dill-0.3.1.1/000755 000765 000024 00000000000 13543677347 013603 5ustar00mmckernsstaff000000 000000 dill-0.3.1.1/.coveragerc000644 000765 000024 00000000555 13543677215 015723 0ustar00mmckernsstaff000000 000000 [run] # source = dill include = */dill/* omit = */tests/* */info.py # timid = true # parallel = true # and need to 'combine' data files # concurrency = multiprocessing # thread # data_file = $TRAVIS_BUILD_DIR/.coverage # debug = trace [report] exclude_lines = pragma: no cover if __name__ == .__main__.: # show_missing = true ignore_errors = true dill-0.3.1.1/.eggs/000755 000765 000024 00000000000 13543677347 014606 5ustar00mmckernsstaff000000 000000 dill-0.3.1.1/.gitignore000644 000765 000024 00000000040 13543677215 015557 0ustar00mmckernsstaff000000 000000 .tox/ .cache/ *.egg-info/ *.pyc dill-0.3.1.1/.travis.yml000644 000765 000024 00000004367 13543677215 015720 0ustar00mmckernsstaff000000 000000 language: python sudo: false matrix: include: - python: '2.5' dist: trusty sudo: false env: - python: '2.6' dist: trusty sudo: false env: - python: '2.7' dist: trusty sudo: false env: - COVERAGE="true" - NUMPY="true" - python: '3.1' dist: trusty sudo: false env: - python: '3.2' dist: trusty sudo: false env: - python: '3.3' dist: trusty sudo: false env: - python: '3.4' dist: trusty sudo: false env: - python: '3.5' dist: trusty sudo: false env: - COVERAGE="true" - python: '3.6' dist: trusty sudo: false env: - python: '3.7' dist: xenial sudo: true env: - python: '3.8-dev' dist: xenial sudo: true env: - python: 'nightly' dist: xenial sudo: true env: - python: 'pypy' dist: trusty sudo: false env: - python: 'pypy3' dist: trusty sudo: false env: allow_failures: - python: '2.5' - python: '2.6' - python: '3.1' - python: '3.2' - python: '3.3' - python: '3.8-dev' - python: 'nightly' - python: 'pypy3' fast_finish: true cache: pip: true before_install: - set -e # fail on any error - if [[ $COVERAGE == "true" ]]; then pip install coverage; fi - if [[ $NUMPY == "true" ]]; then pip install numpy; fi install: - python setup.py build && python setup.py install script: - for test in tests/__init__.py; do echo $test ; if [[ $COVERAGE == "true" ]]; then coverage run -a $test > /dev/null; else python $test > /dev/null; fi ; done - for test in tests/test_*.py; do echo $test ; if [[ $COVERAGE == "true" ]]; then coverage run -a $test > /dev/null; else python $test > /dev/null; fi ; done after_success: - if [[ $COVERAGE == "true" ]]; then bash <(curl -s https://codecov.io/bash); else echo ''; fi dill-0.3.1.1/DEV_NOTES000644 000765 000024 00000004441 13543677215 015111 0ustar00mmckernsstaff000000 000000 create a weakref: >>> import dill >>> import weakref >>> class Object: ... pass ... >>> o = Object() >>> r = weakref.ref(o) #XXX: type: weakref.ReferenceType >>> r >>> o <__main__.Object instance at 0xb23080> >>> r() <__main__.Object instance at 0xb23080> >>> r.__call__() <__main__.Object instance at 0xb23080> >>> r.__hash__() 11677824 >>> id(o) 11677824 >>> o2 = Object() >>> r2 = weakref.ref(o2) >>> del o2 >>> r2 >>> r2() >>> r2.__call__() >>> r2.__hash__() Traceback (most recent call last): File "", line 1, in TypeError: weak object has gone away >>> o3 = Object() >>> r3 = weakref.proxy(o3) #XXX: type: weakref.ProxyType >>> r3 >>> o3 <__main__.Object instance at 0x8d530> >>> r3.__class__ >>> o3.__class__ >>> del o3 >>> r3 >>> r3.__class__ Traceback (most recent call last): File "", line 1, in ReferenceError: weakly-referenced object no longer exists >>> class Object2: ... def __call__(self): ... pass ... >>> oo = Object2() >>> oo <__main__.Object instance at 0x8ca30> >>> oo() >>> rr = weakref.proxy(oo) #XXX: type: weakref.CallableProxyType >>> rr >>> rr() >>> rr.__call__ > >>> rr.__call__() >>> ######################################## approach to pickling weakrefs: *) register the weakref types ? (see line ~228 of dill.py) *) use hash to create hard copy of ref object then upon unpickle, create new weakref *) propose that pickling a weakref will always provide a dead reference unless the reference object is pickled along with the weakref ######################################## pickling generators: *) need to avoid the "new" method for FrameTypes... don't see how to do that, without going into C to get the GID Thread. *) currently inspecting: Objects/object.c Objects/dictobject.c Objects/genobject.c Objects/frameobject.c Python/pystate.c Python/thread.c Python/pythonrun.c *) the package "generator_tools" may have the answer. ######################################## dill-0.3.1.1/dill/000755 000765 000024 00000000000 13543677347 014527 5ustar00mmckernsstaff000000 000000 dill-0.3.1.1/dill.egg-info/000755 000765 000024 00000000000 13543677347 016221 5ustar00mmckernsstaff000000 000000 dill-0.3.1.1/docs/000755 000765 000024 00000000000 13543677215 014525 5ustar00mmckernsstaff000000 000000 dill-0.3.1.1/LICENSE000644 000765 000024 00000003415 13543677215 014605 0ustar00mmckernsstaff000000 000000 Copyright (c) 2004-2016 California Institute of Technology. Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. All rights reserved. This software is available subject to the conditions and terms laid out below. By downloading and using this software you are agreeing to the following conditions. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:: - Redistribution of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistribution in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentations and/or other materials provided with the distribution. - Neither the name of the California Institute of Technology 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. dill-0.3.1.1/MANIFEST.in000644 000765 000024 00000000123 13543677215 015327 0ustar00mmckernsstaff000000 000000 include LICENSE include README include tox.ini include scripts/* include tests/*py dill-0.3.1.1/README000644 000765 000024 00000012630 13543677347 014465 0ustar00mmckernsstaff000000 000000 ----------------------------- dill: serialize all of python ----------------------------- About Dill ========== ``dill`` extends python's ``pickle`` module for serializing and de-serializing python objects to the majority of the built-in python types. Serialization is the process of converting an object to a byte stream, and the inverse of which is converting a byte stream back to on python object hierarchy. ``dill`` provides the user the same interface as the ``pickle`` module, and also includes some additional features. In addition to pickling python objects, ``dill`` provides the ability to save the state of an interpreter session in a single command. Hence, it would be feasable to save a interpreter session, close the interpreter, ship the pickled file to another computer, open a new interpreter, unpickle the session and thus continue from the 'saved' state of the original interpreter session. ``dill`` can be used to store python objects to a file, but the primary usage is to send python objects across the network as a byte stream. ``dill`` is quite flexible, and allows arbitrary user defined classes and functions to be serialized. Thus ``dill`` is not intended to be secure against erroneously or maliciously constructed data. It is left to the user to decide whether the data they unpickle is from a trustworthy source. ``dill`` is part of ``pathos``, a python framework for heterogeneous computing. ``dill`` is in active development, so any user feedback, bug reports, comments, or suggestions are highly appreciated. A list of known issues is maintained at http://trac.mystic.cacr.caltech.edu/project/pathos/query.html, with a public ticket list at https://github.com/uqfoundation/dill/issues. Major Features ============== ``dill`` can pickle the following standard types: - none, type, bool, int, long, float, complex, str, unicode, - tuple, list, dict, file, buffer, builtin, - both old and new style classes, - instances of old and new style classes, - set, frozenset, array, functions, exceptions ``dill`` can also pickle more 'exotic' standard types: - functions with yields, nested functions, lambdas, - cell, method, unboundmethod, module, code, methodwrapper, - dictproxy, methoddescriptor, getsetdescriptor, memberdescriptor, - wrapperdescriptor, xrange, slice, - notimplemented, ellipsis, quit ``dill`` cannot yet pickle these standard types: - frame, generator, traceback ``dill`` also provides the capability to: - save and load python interpreter sessions - save and extract the source code from functions and classes - interactively diagnose pickling errors Current Release =============== This documentation is for version ``dill-0.3.1.1``. The latest released version of ``dill`` is available from: https://pypi.org/project/dill ``dill`` is distributed under a 3-clause BSD license. >>> import dill >>> print (dill.license()) Development Version =================== You can get the latest development version with all the shiny new features at: https://github.com/uqfoundation If you have a new contribution, please submit a pull request. Installation ============ ``dill`` is packaged to install from source, so you must download the tarball, unzip, and run the installer:: [download] $ tar -xvzf dill-0.3.1.1.tar.gz $ cd dill-0.3.1.1 $ python setup py build $ python setup py install You will be warned of any missing dependencies and/or settings after you run the "build" step above. Alternately, ``dill`` can be installed with ``pip`` or ``easy_install``:: $ pip install dill Requirements ============ ``dill`` requires: - ``python``, **version >= 2.6** or **version >= 3.1**, or ``pypy`` Optional requirements: - ``setuptools``, **version >= 0.6** - ``pyreadline``, **version >= 1.7.1** (on windows) - ``objgraph``, **version >= 1.7.2** More Information ================ Probably the best way to get started is to look at the documentation at http://dill.rtfd.io. Also see ``dill.tests`` for a set of scripts that demonstrate how ``dill`` can serialize different python objects. You can run the test suite with ``python -m dill.tests``. The contents of any pickle file can be examined with ``undill``. As ``dill`` conforms to the ``pickle`` interface, the examples and documentation found at http://docs.python.org/library/pickle.html also apply to ``dill`` if one will ``import dill as pickle``. The source code is also generally well documented, so further questions may be resolved by inspecting the code itself. Please feel free to submit a ticket on github, or ask a question on stackoverflow (**@Mike McKerns**). If you would like to share how you use ``dill`` in your work, please send an email (to **mmckerns at uqfoundation dot org**). Citation ======== If you use ``dill`` to do research that leads to publication, we ask that you acknowledge use of ``dill`` by citing the following in your publication:: M.M. McKerns, L. Strand, T. Sullivan, A. Fang, M.A.G. Aivazis, "Building a framework for predictive science", Proceedings of the 10th Python in Science Conference, 2011; http://arxiv.org/pdf/1202.1056 Michael McKerns and Michael Aivazis, "pathos: a framework for heterogeneous computing", 2010- ; http://trac.mystic.cacr.caltech.edu/project/pathos Please see http://trac.mystic.cacr.caltech.edu/project/pathos or http://arxiv.org/pdf/1202.1056 for further information. dill-0.3.1.1/README.md000644 000765 000024 00000011546 13543677215 015063 0ustar00mmckernsstaff000000 000000 dill ==== serialize all of python About Dill ---------- ``dill`` extends python's ``pickle`` module for serializing and de-serializing python objects to the majority of the built-in python types. Serialization is the process of converting an object to a byte stream, and the inverse of which is converting a byte stream back to on python object hierarchy. ``dill`` provides the user the same interface as the ``pickle`` module, and also includes some additional features. In addition to pickling python objects, ``dill`` provides the ability to save the state of an interpreter session in a single command. Hence, it would be feasable to save a interpreter session, close the interpreter, ship the pickled file to another computer, open a new interpreter, unpickle the session and thus continue from the 'saved' state of the original interpreter session. ``dill`` can be used to store python objects to a file, but the primary usage is to send python objects across the network as a byte stream. ``dill`` is quite flexible, and allows arbitrary user defined classes and functions to be serialized. Thus ``dill`` is not intended to be secure against erroneously or maliciously constructed data. It is left to the user to decide whether the data they unpickle is from a trustworthy source. ``dill`` is part of ``pathos``, a python framework for heterogeneous computing. ``dill`` is in active development, so any user feedback, bug reports, comments, or suggestions are highly appreciated. A list of known issues is maintained at http://trac.mystic.cacr.caltech.edu/project/pathos/query.html, with a public ticket list at https://github.com/uqfoundation/dill/issues. Major Features -------------- ``dill`` can pickle the following standard types: * none, type, bool, int, long, float, complex, str, unicode, * tuple, list, dict, file, buffer, builtin, * both old and new style classes, * instances of old and new style classes, * set, frozenset, array, functions, exceptions ``dill`` can also pickle more 'exotic' standard types: * functions with yields, nested functions, lambdas * cell, method, unboundmethod, module, code, methodwrapper, * dictproxy, methoddescriptor, getsetdescriptor, memberdescriptor, * wrapperdescriptor, xrange, slice, * notimplemented, ellipsis, quit ``dill`` cannot yet pickle these standard types: * frame, generator, traceback ``dill`` also provides the capability to: * save and load python interpreter sessions * save and extract the source code from functions and classes * interactively diagnose pickling errors Current Release --------------- The latest released version of ``dill`` is available from: https://pypi.org/project/dill ``dill`` is distributed under a 3-clause BSD license. Development Version [![Documentation Status](https://readthedocs.org/projects/dill/badge/?version=latest)](https://dill.readthedocs.io/en/latest/?badge=latest) [![Travis Build Status](https://img.shields.io/travis/uqfoundation/dill.svg?label=build&logo=travis&branch=master)](https://travis-ci.org/uqfoundation/dill) [![codecov](https://codecov.io/gh/uqfoundation/dill/branch/master/graph/badge.svg)](https://codecov.io/gh/uqfoundation/dill) ------------------- You can get the latest development version with all the shiny new features at: https://github.com/uqfoundation If you have a new contribution, please submit a pull request. More Information ---------------- Probably the best way to get started is to look at the documentation at http://dill.rtfd.io. Also see ``dill.tests`` for a set of scripts that demonstrate how ``dill`` can serialize different python objects. You can run the test suite with ``python -m dill.tests``. The contents of any pickle file can be examined with ``undill``. As ``dill`` conforms to the ``pickle`` interface, the examples and documentation found at http://docs.python.org/library/pickle.html also apply to ``dill`` if one will ``import dill as pickle``. The source code is also generally well documented, so further questions may be resolved by inspecting the code itself. Please feel free to submit a ticket on github, or ask a question on stackoverflow (**@Mike McKerns**). If you would like to share how you use ``dill`` in your work, please send an email (to **mmckerns at uqfoundation dot org**). Citation -------- If you use ``dill`` to do research that leads to publication, we ask that you acknowledge use of ``dill`` by citing the following in your publication:: M.M. McKerns, L. Strand, T. Sullivan, A. Fang, M.A.G. Aivazis, "Building a framework for predictive science", Proceedings of the 10th Python in Science Conference, 2011; http://arxiv.org/pdf/1202.1056 Michael McKerns and Michael Aivazis, "pathos: a framework for heterogeneous computing", 2010- ; http://trac.mystic.cacr.caltech.edu/project/pathos Please see http://trac.mystic.cacr.caltech.edu/project/pathos or http://arxiv.org/pdf/1202.1056 for further information. dill-0.3.1.1/scripts/000755 000765 000024 00000000000 13543677215 015264 5ustar00mmckernsstaff000000 000000 dill-0.3.1.1/setup.cfg000644 000765 000024 00000000106 13543677215 015413 0ustar00mmckernsstaff000000 000000 [egg_info] #tag_build = .dev0 #tag_svn_revision = yes #tag_date = yes dill-0.3.1.1/setup.py000644 000765 000024 00000025336 13543677243 015321 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import os # set version numbers stable_version = '0.3.1.1' target_version = '0.3.1.1' is_release = stable_version == target_version # check if easy_install is available try: # import __force_distutils__ #XXX: uncomment to force use of distutills from setuptools import setup has_setuptools = True except ImportError: from distutils.core import setup has_setuptools = False # generate version number if os.path.exists('dill/info.py'): # is a source distribution, so use existing version os.chdir('dill') with open('info.py','r') as f: f.readline() # header this_version = f.readline().split()[-1].strip("'") os.chdir('..') elif stable_version == target_version: # we are building a stable release this_version = target_version else: # we are building a distribution this_version = target_version + '.dev0' if is_release: from datetime import date today = "".join(date.isoformat(date.today()).split('-')) this_version += "-" + today # get the license info with open('LICENSE') as file: license_text = file.read() # generate the readme text long_description = \ """----------------------------- dill: serialize all of python ----------------------------- About Dill ========== ``dill`` extends python's ``pickle`` module for serializing and de-serializing python objects to the majority of the built-in python types. Serialization is the process of converting an object to a byte stream, and the inverse of which is converting a byte stream back to on python object hierarchy. ``dill`` provides the user the same interface as the ``pickle`` module, and also includes some additional features. In addition to pickling python objects, ``dill`` provides the ability to save the state of an interpreter session in a single command. Hence, it would be feasable to save a interpreter session, close the interpreter, ship the pickled file to another computer, open a new interpreter, unpickle the session and thus continue from the 'saved' state of the original interpreter session. ``dill`` can be used to store python objects to a file, but the primary usage is to send python objects across the network as a byte stream. ``dill`` is quite flexible, and allows arbitrary user defined classes and functions to be serialized. Thus ``dill`` is not intended to be secure against erroneously or maliciously constructed data. It is left to the user to decide whether the data they unpickle is from a trustworthy source. ``dill`` is part of ``pathos``, a python framework for heterogeneous computing. ``dill`` is in active development, so any user feedback, bug reports, comments, or suggestions are highly appreciated. A list of known issues is maintained at http://trac.mystic.cacr.caltech.edu/project/pathos/query.html, with a public ticket list at https://github.com/uqfoundation/dill/issues. Major Features ============== ``dill`` can pickle the following standard types: - none, type, bool, int, long, float, complex, str, unicode, - tuple, list, dict, file, buffer, builtin, - both old and new style classes, - instances of old and new style classes, - set, frozenset, array, functions, exceptions ``dill`` can also pickle more 'exotic' standard types: - functions with yields, nested functions, lambdas, - cell, method, unboundmethod, module, code, methodwrapper, - dictproxy, methoddescriptor, getsetdescriptor, memberdescriptor, - wrapperdescriptor, xrange, slice, - notimplemented, ellipsis, quit ``dill`` cannot yet pickle these standard types: - frame, generator, traceback ``dill`` also provides the capability to: - save and load python interpreter sessions - save and extract the source code from functions and classes - interactively diagnose pickling errors Current Release =============== This documentation is for version ``dill-%(thisver)s``. The latest released version of ``dill`` is available from: https://pypi.org/project/dill ``dill`` is distributed under a 3-clause BSD license. >>> import dill >>> print (dill.license()) Development Version =================== You can get the latest development version with all the shiny new features at: https://github.com/uqfoundation If you have a new contribution, please submit a pull request. Installation ============ ``dill`` is packaged to install from source, so you must download the tarball, unzip, and run the installer:: [download] $ tar -xvzf dill-%(relver)s.tar.gz $ cd dill-%(relver)s $ python setup py build $ python setup py install You will be warned of any missing dependencies and/or settings after you run the "build" step above. Alternately, ``dill`` can be installed with ``pip`` or ``easy_install``:: $ pip install dill Requirements ============ ``dill`` requires: - ``python``, **version >= 2.6** or **version >= 3.1**, or ``pypy`` Optional requirements: - ``setuptools``, **version >= 0.6** - ``pyreadline``, **version >= 1.7.1** (on windows) - ``objgraph``, **version >= 1.7.2** More Information ================ Probably the best way to get started is to look at the documentation at http://dill.rtfd.io. Also see ``dill.tests`` for a set of scripts that demonstrate how ``dill`` can serialize different python objects. You can run the test suite with ``python -m dill.tests``. The contents of any pickle file can be examined with ``undill``. As ``dill`` conforms to the ``pickle`` interface, the examples and documentation found at http://docs.python.org/library/pickle.html also apply to ``dill`` if one will ``import dill as pickle``. The source code is also generally well documented, so further questions may be resolved by inspecting the code itself. Please feel free to submit a ticket on github, or ask a question on stackoverflow (**@Mike McKerns**). If you would like to share how you use ``dill`` in your work, please send an email (to **mmckerns at uqfoundation dot org**). Citation ======== If you use ``dill`` to do research that leads to publication, we ask that you acknowledge use of ``dill`` by citing the following in your publication:: M.M. McKerns, L. Strand, T. Sullivan, A. Fang, M.A.G. Aivazis, "Building a framework for predictive science", Proceedings of the 10th Python in Science Conference, 2011; http://arxiv.org/pdf/1202.1056 Michael McKerns and Michael Aivazis, "pathos: a framework for heterogeneous computing", 2010- ; http://trac.mystic.cacr.caltech.edu/project/pathos Please see http://trac.mystic.cacr.caltech.edu/project/pathos or http://arxiv.org/pdf/1202.1056 for further information. """ % {'relver' : stable_version, 'thisver' : this_version} # write readme file with open('README', 'w') as file: file.write(long_description) # generate 'info' file contents def write_info_py(filename='dill/info.py'): contents = """# THIS FILE GENERATED FROM SETUP.PY this_version = '%(this_version)s' stable_version = '%(stable_version)s' readme = '''%(long_description)s''' license = '''%(license_text)s''' """ with open(filename, 'w') as file: file.write(contents % {'this_version' : this_version, 'stable_version' : stable_version, 'long_description' : long_description, 'license_text' : license_text }) return # write info file write_info_py() # build the 'setup' call setup_code = """ setup(name='dill', version='%s', description='serialize all of python', long_description = '''%s''', author = 'Mike McKerns', maintainer = 'Mike McKerns', license = '3-clause BSD', platforms = ['Linux', 'Windows', 'Mac'], url = 'https://pypi.org/project/dill', download_url = 'https://github.com/uqfoundation/dill/releases/download/dill-%s/dill-%s.tar.gz', python_requires='>=2.6, !=3.0.*', classifiers = ['Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: BSD License', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Topic :: Scientific/Engineering', 'Topic :: Software Development'], packages = ['dill','dill.tests'], package_dir = {'dill':'dill', 'dill.tests':'tests'}, """ % (target_version, long_description, stable_version, stable_version) # add dependencies ctypes_version = '>=1.0.1' objgraph_version = '>=1.7.2' pyreadline_version = '>=1.7.1' import sys if has_setuptools: setup_code += """ zip_safe=False, """ if sys.platform[:3] == 'win': setup_code += """ extras_require = {'readline': ['pyreadline%s'], 'graph': ['objgraph%s']}, """ % (pyreadline_version, objgraph_version) # verrrry unlikely that this is still relevant elif hex(sys.hexversion) < '0x20500f0': setup_code += """ install_requires = ['ctypes%s'], extras_require = {'readline': [], 'graph': ['objgraph%s']}, """ % (ctypes_version, objgraph_version) else: setup_code += """ extras_require = {'readline': [], 'graph': ['objgraph%s']}, """ % (objgraph_version) # add the scripts, and close 'setup' call setup_code += """ scripts=['scripts/undill','scripts/get_objgraph']) """ # exec the 'setup' code exec(setup_code) # if dependencies are missing, print a warning try: import ctypes import readline except ImportError: print ("\n***********************************************************") print ("WARNING: One of the following dependencies is unresolved:") print (" ctypes %s" % ctypes_version) if sys.platform[:3] == 'win': print (" readline %s" % pyreadline_version) print ("***********************************************************\n") if __name__=='__main__': pass # end of file dill-0.3.1.1/tests/000755 000765 000024 00000000000 13543677215 014737 5ustar00mmckernsstaff000000 000000 dill-0.3.1.1/tox.ini000644 000765 000024 00000000634 13543677215 015113 0ustar00mmckernsstaff000000 000000 [tox] skip_missing_interpreters= True envlist = py26 py27 py33 py34 py35 py36 py37 py38 pypy # pypy3 [testenv] deps = # numpy whitelist_externals = bash commands = {envpython} setup.py build {envpython} setup.py install bash -c "failed=0; for test in tests/__main__.py; do echo $test; \ {envpython} $test || failed=1; done; exit $failed" dill-0.3.1.1/tests/__init__.py000644 000765 000024 00000000765 13543677215 017060 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2018-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ to run this test suite, first build and install `dill`. $ python setup.py build $ python setup.py install then run the tests with: $ python -m dill.tests or, if `nose` is installed: $ nosetests """ dill-0.3.1.1/tests/__main__.py000644 000765 000024 00000001327 13543677215 017034 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2018-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE from __future__ import print_function import glob import os try: import pox python = pox.which_python(version=True, fullpath=False) or 'python' except ImportError: python = 'python' suite = os.path.dirname(__file__) or os.path.curdir tests = glob.glob(suite + os.path.sep + 'test_*.py') if __name__ == '__main__': for test in tests: print('.', end='') os.system('{0} {1}'.format(python, test)) print('') dill-0.3.1.1/tests/test_check.py000644 000765 000024 00000002376 13543677215 017435 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE from dill import check import sys from dill.temp import capture from dill._dill import PY3 #FIXME: this doesn't catch output... it's from the internal call def raise_check(func, **kwds): try: with capture('stdout') as out: check(func, **kwds) except Exception: e = sys.exc_info()[1] raise AssertionError(str(e)) else: assert 'Traceback' not in out.getvalue() finally: out.close() f = lambda x:x**2 def test_simple(): raise_check(f) def test_recurse(): raise_check(f, recurse=True) def test_byref(): raise_check(f, byref=True) def test_protocol(): raise_check(f, protocol=True) def test_python(): raise_check(f, python=None) #TODO: test incompatible versions #TODO: test dump failure #TODO: test load failure if __name__ == '__main__': test_simple() test_recurse() test_byref() test_protocol() test_python() dill-0.3.1.1/tests/test_classdef.py000644 000765 000024 00000011145 13543677215 020136 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import dill import sys dill.settings['recurse'] = True # test classdefs class _class: def _method(self): pass def ok(self): return True class _class2: def __call__(self): pass def ok(self): return True class _newclass(object): def _method(self): pass def ok(self): return True class _newclass2(object): def __call__(self): pass def ok(self): return True class _meta(type): pass def __call__(self): pass def ok(self): return True _mclass = _meta("_mclass", (object,), {"__call__": __call__, "ok": ok}) del __call__ del ok o = _class() oc = _class2() n = _newclass() nc = _newclass2() m = _mclass() # test pickles for class instances def test_class_instances(): assert dill.pickles(o) assert dill.pickles(oc) assert dill.pickles(n) assert dill.pickles(nc) assert dill.pickles(m) def test_class_objects(): clslist = [_class,_class2,_newclass,_newclass2,_mclass] objlist = [o,oc,n,nc,m] _clslist = [dill.dumps(obj) for obj in clslist] _objlist = [dill.dumps(obj) for obj in objlist] for obj in clslist: globals().pop(obj.__name__) del clslist for obj in ['o','oc','n','nc']: globals().pop(obj) del objlist del obj for obj,cls in zip(_objlist,_clslist): _cls = dill.loads(cls) _obj = dill.loads(obj) assert _obj.ok() assert _cls.ok(_cls()) if _cls.__name__ == "_mclass": assert type(_cls).__name__ == "_meta" # test NoneType def test_none(): assert dill.pickles(type(None)) if hex(sys.hexversion) >= '0x20600f0': from collections import namedtuple Z = namedtuple("Z", ['a','b']) Zi = Z(0,1) X = namedtuple("Y", ['a','b']) X.__name__ = "X" if hex(sys.hexversion) >= '0x30300f0': X.__qualname__ = "X" #XXX: name must 'match' or fails to pickle Xi = X(0,1) Bad = namedtuple("FakeName", ['a','b']) Badi = Bad(0,1) else: Z = Zi = X = Xi = Bad = Badi = None # test namedtuple def test_namedtuple(): assert Z is dill.loads(dill.dumps(Z)) assert Zi == dill.loads(dill.dumps(Zi)) assert X is dill.loads(dill.dumps(X)) assert Xi == dill.loads(dill.dumps(Xi)) assert Bad is not dill.loads(dill.dumps(Bad)) assert Bad._fields == dill.loads(dill.dumps(Bad))._fields assert tuple(Badi) == tuple(dill.loads(dill.dumps(Badi))) def test_array_nested(): try: import numpy as np x = np.array([1]) y = (x,) dill.dumps(x) assert y == dill.loads(dill.dumps(y)) except ImportError: pass def test_array_subclass(): try: import numpy as np class TestArray(np.ndarray): def __new__(cls, input_array, color): obj = np.asarray(input_array).view(cls) obj.color = color return obj def __array_finalize__(self, obj): if obj is None: return if isinstance(obj, type(self)): self.color = obj.color def __getnewargs__(self): return np.asarray(self), self.color a1 = TestArray(np.zeros(100), color='green') assert dill.pickles(a1) assert a1.__dict__ == dill.copy(a1).__dict__ a2 = a1[0:9] assert dill.pickles(a2) assert a2.__dict__ == dill.copy(a2).__dict__ class TestArray2(np.ndarray): color = 'blue' a3 = TestArray2([1,2,3,4,5]) a3.color = 'green' assert dill.pickles(a3) assert a3.__dict__ == dill.copy(a3).__dict__ except ImportError: pass def test_method_decorator(): class A(object): @classmethod def test(cls): pass a = A() res = dill.dumps(a) new_obj = dill.loads(res) new_obj.__class__.test() # test slots class Y(object): __slots__ = ['y'] def __init__(self, y): self.y = y value = 123 y = Y(value) def test_slots(): assert dill.pickles(Y) assert dill.pickles(y) assert dill.pickles(Y.y) assert dill.copy(y).y == value if __name__ == '__main__': test_class_instances() test_class_objects() test_none() test_namedtuple() test_array_nested() test_array_subclass() test_method_decorator() test_slots() dill-0.3.1.1/tests/test_detect.py000644 000765 000024 00000007723 13543677215 017631 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE from dill.detect import baditems, badobjects, badtypes, errors, parent, at, globalvars from dill import settings from dill._dill import IS_PYPY from pickle import PicklingError import inspect def test_bad_things(): f = inspect.currentframe() assert baditems(f) == [f] #assert baditems(globals()) == [f] #XXX assert badobjects(f) is f assert badtypes(f) == type(f) assert type(errors(f)) is PicklingError if IS_PYPY else TypeError d = badtypes(f, 1) assert isinstance(d, dict) assert list(badobjects(f, 1).keys()) == list(d.keys()) assert list(errors(f, 1).keys()) == list(d.keys()) s = set([(err.__class__.__name__,err.args[0]) for err in list(errors(f, 1).values())]) a = dict(s) assert len(s) is len(a) # TypeError (and possibly PicklingError) n = 1 if IS_PYPY else 2 assert len(a) is n if 'PicklingError' in a.keys() else n-1 def test_parent(): x = [4,5,6,7] listiter = iter(x) obj = parent(listiter, list) assert obj is x if IS_PYPY: assert parent(obj, int) is None else: assert parent(obj, int) is x[-1] # python oddly? finds last int assert at(id(at)) is at a, b, c = 1, 2, 3 def squared(x): return a+x**2 def foo(x): def bar(y): return squared(x)+y return bar class _class: def _method(self): pass def ok(self): return True def test_globals(): def f(): a def g(): b def h(): c assert globalvars(f) == dict(a=1, b=2, c=3) res = globalvars(foo, recurse=True) assert set(res) == set(['squared', 'a']) res = globalvars(foo, recurse=False) assert res == {} zap = foo(2) res = globalvars(zap, recurse=True) assert set(res) == set(['squared', 'a']) res = globalvars(zap, recurse=False) assert set(res) == set(['squared']) del zap res = globalvars(squared) assert set(res) == set(['a']) # FIXME: should find referenced __builtins__ #res = globalvars(_class, recurse=True) #assert set(res) == set(['True']) #res = globalvars(_class, recurse=False) #assert res == {} #res = globalvars(_class.ok, recurse=True) #assert set(res) == set(['True']) #res = globalvars(_class.ok, recurse=False) #assert set(res) == set(['True']) #98 dill ignores __getstate__ in interactive lambdas bar = [0] class Foo(object): def __init__(self): pass def __getstate__(self): bar[0] = bar[0]+1 return {} def __setstate__(self, data): pass f = Foo() def test_getstate(): from dill import dumps, loads dumps(f) b = bar[0] dumps(lambda: f, recurse=False) # doesn't call __getstate__ assert bar[0] == b dumps(lambda: f, recurse=True) # calls __getstate__ assert bar[0] == b + 1 #97 serialize lambdas in test files def test_deleted(): from dill import dumps, loads from math import sin, pi global sin def sinc(x): return sin(x)/x settings['recurse'] = True _sinc = dumps(sinc) sin = globals().pop('sin') sin = 1 del sin sinc_ = loads(_sinc) # no NameError... pickling preserves 'sin' res = sinc_(1) from math import sin assert sinc(1) == res def test_lambdify(): try: from sympy import symbols, lambdify except ImportError: return settings['recurse'] = True x = symbols("x") y = x**2 f = lambdify([x], y) z = min d = globals() globalvars(f, recurse=True, builtin=True) assert z is min assert d is globals() if __name__ == '__main__': test_bad_things() test_parent() test_globals() test_getstate() test_deleted() test_lambdify() dill-0.3.1.1/tests/test_diff.py000644 000765 000024 00000005311 13543677215 017260 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE from dill import __diff as diff import sys IS_PYPY = not hasattr(sys, 'getrefcount') class A: pass def test_diff(): a = A() b = A() c = A() a.a = b b.a = c diff.memorise(a) assert not diff.has_changed(a) c.a = 1 assert diff.has_changed(a) diff.memorise(c, force=True) assert not diff.has_changed(a) c.a = 2 assert diff.has_changed(a) changed = diff.whats_changed(a) assert list(changed[0].keys()) == ["a"] assert not changed[1] a2 = [] b2 = [a2] c2 = [b2] diff.memorise(c2) assert not diff.has_changed(c2) a2.append(1) assert diff.has_changed(c2) changed = diff.whats_changed(c2) assert changed[0] == {} assert changed[1] a3 = {} b3 = {1: a3} c3 = {1: b3} diff.memorise(c3) assert not diff.has_changed(c3) a3[1] = 1 assert diff.has_changed(c3) changed = diff.whats_changed(c3) assert changed[0] == {} assert changed[1] if not IS_PYPY: try: import abc # make sure the "_abc_invaldation_counter" doesn't make test fail diff.memorise(abc.ABCMeta, force=True) assert not diff.has_changed(abc) abc.ABCMeta.zzz = 1 assert diff.has_changed(abc) changed = diff.whats_changed(abc) assert list(changed[0].keys()) == ["ABCMeta"] assert not changed[1] except ImportError: pass ''' import Queue diff.memorise(Queue, force=True) assert not diff.has_changed(Queue) Queue.Queue.zzz = 1 assert diff.has_changed(Queue) changed = diff.whats_changed(Queue) assert list(changed[0].keys()) == ["Queue"] assert not changed[1] import math diff.memorise(math, force=True) assert not diff.has_changed(math) math.zzz = 1 assert diff.has_changed(math) changed = diff.whats_changed(math) assert list(changed[0].keys()) == ["zzz"] assert not changed[1] ''' a = A() b = A() c = A() a.a = b b.a = c diff.memorise(a) assert not diff.has_changed(a) c.a = 1 assert diff.has_changed(a) diff.memorise(c, force=True) assert not diff.has_changed(a) del c.a assert diff.has_changed(a) changed = diff.whats_changed(a) assert list(changed[0].keys()) == ["a"] assert not changed[1] if __name__ == '__main__': test_diff() dill-0.3.1.1/tests/test_extendpickle.py000644 000765 000024 00000001541 13543677215 021030 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import dill as pickle try: from StringIO import StringIO except ImportError: from io import BytesIO as StringIO def my_fn(x): return x * 17 def test_extend(): obj = lambda : my_fn(34) assert obj() == 578 obj_io = StringIO() pickler = pickle.Pickler(obj_io) pickler.dump(obj) obj_str = obj_io.getvalue() obj2_io = StringIO(obj_str) unpickler = pickle.Unpickler(obj2_io) obj2 = unpickler.load() assert obj2() == 578 if __name__ == '__main__': test_extend() dill-0.3.1.1/tests/test_file.py000644 000765 000024 00000032512 13543677215 017272 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import os import sys import string import random import dill dill.settings['recurse'] = True fname = "_test_file.txt" rand_chars = list(string.ascii_letters) + ["\n"] * 40 # bias newline if sys.hexversion < 0x03030000: FileNotFoundError = IOError buffer_error = ValueError("invalid buffer size") dne_error = FileNotFoundError("[Errno 2] No such file or directory: '%s'" % fname) def write_randomness(number=200): f = open(fname, "w") for i in range(number): f.write(random.choice(rand_chars)) f.close() f = open(fname, "r") contents = f.read() f.close() return contents def trunc_file(): open(fname, "w").close() def throws(op, args, exc): try: op(*args) except type(exc): return sys.exc_info()[1].args == exc.args else: return False def teardown_module(): if os.path.exists(fname): os.remove(fname) def bench(strictio, fmode, skippypy): import platform if skippypy and platform.python_implementation() == 'PyPy': # Skip for PyPy... return # file exists, with same contents # read write_randomness() f = open(fname, "r") _f = dill.loads(dill.dumps(f, fmode=fmode))#, strictio=strictio)) assert _f.mode == f.mode assert _f.tell() == f.tell() assert _f.read() == f.read() f.close() _f.close() # write f = open(fname, "w") f.write("hello") f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio) f1mode = f.mode ftell = f.tell() f.close() f2 = dill.loads(f_dumped) #FIXME: fails due to pypy/issues/1233 # TypeError: expected py_object instance instead of str f2mode = f2.mode f2tell = f2.tell() f2name = f2.name f2.write(" world!") f2.close() if fmode == dill.HANDLE_FMODE: assert open(fname).read() == " world!" assert f2mode == f1mode assert f2tell == 0 elif fmode == dill.CONTENTS_FMODE: assert open(fname).read() == "hello world!" assert f2mode == f1mode assert f2tell == ftell assert f2name == fname elif fmode == dill.FILE_FMODE: assert open(fname).read() == "hello world!" assert f2mode == f1mode assert f2tell == ftell else: raise RuntimeError("Unknown file mode '%s'" % fmode) # append trunc_file() f = open(fname, "a") f.write("hello") f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio) f1mode = f.mode ftell = f.tell() f.close() f2 = dill.loads(f_dumped) f2mode = f2.mode f2tell = f2.tell() f2.write(" world!") f2.close() assert f2mode == f1mode if fmode == dill.CONTENTS_FMODE: assert open(fname).read() == "hello world!" assert f2tell == ftell elif fmode == dill.HANDLE_FMODE: assert open(fname).read() == "hello world!" assert f2tell == ftell elif fmode == dill.FILE_FMODE: assert open(fname).read() == "hello world!" assert f2tell == ftell else: raise RuntimeError("Unknown file mode '%s'" % fmode) # file exists, with different contents (smaller size) # read write_randomness() f = open(fname, "r") fstr = f.read() f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio) f1mode = f.mode ftell = f.tell() f.close() _flen = 150 _fstr = write_randomness(number=_flen) if strictio: # throw error if ftell > EOF assert throws(dill.loads, (f_dumped,), buffer_error) else: f2 = dill.loads(f_dumped) assert f2.mode == f1mode if fmode == dill.CONTENTS_FMODE: assert f2.tell() == _flen assert f2.read() == "" f2.seek(0) assert f2.read() == _fstr assert f2.tell() == _flen # 150 elif fmode == dill.HANDLE_FMODE: assert f2.tell() == 0 assert f2.read() == _fstr assert f2.tell() == _flen # 150 elif fmode == dill.FILE_FMODE: assert f2.tell() == ftell # 200 assert f2.read() == "" f2.seek(0) assert f2.read() == fstr assert f2.tell() == ftell # 200 else: raise RuntimeError("Unknown file mode '%s'" % fmode) f2.close() # write write_randomness() f = open(fname, "w") f.write("hello") f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio) f1mode = f.mode ftell = f.tell() f.close() fstr = open(fname).read() f = open(fname, "w") f.write("h") _ftell = f.tell() f.close() if strictio: # throw error if ftell > EOF assert throws(dill.loads, (f_dumped,), buffer_error) else: f2 = dill.loads(f_dumped) f2mode = f2.mode f2tell = f2.tell() f2.write(" world!") f2.close() if fmode == dill.CONTENTS_FMODE: assert open(fname).read() == "h world!" assert f2mode == f1mode assert f2tell == _ftell elif fmode == dill.HANDLE_FMODE: assert open(fname).read() == " world!" assert f2mode == f1mode assert f2tell == 0 elif fmode == dill.FILE_FMODE: assert open(fname).read() == "hello world!" assert f2mode == f1mode assert f2tell == ftell else: raise RuntimeError("Unknown file mode '%s'" % fmode) f2.close() # append trunc_file() f = open(fname, "a") f.write("hello") f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio) f1mode = f.mode ftell = f.tell() f.close() fstr = open(fname).read() f = open(fname, "w") f.write("h") _ftell = f.tell() f.close() if strictio: # throw error if ftell > EOF assert throws(dill.loads, (f_dumped,), buffer_error) else: f2 = dill.loads(f_dumped) f2mode = f2.mode f2tell = f2.tell() f2.write(" world!") f2.close() assert f2mode == f1mode if fmode == dill.CONTENTS_FMODE: # position of writes cannot be changed on some OSs assert open(fname).read() == "h world!" assert f2tell == _ftell elif fmode == dill.HANDLE_FMODE: assert open(fname).read() == "h world!" assert f2tell == _ftell elif fmode == dill.FILE_FMODE: assert open(fname).read() == "hello world!" assert f2tell == ftell else: raise RuntimeError("Unknown file mode '%s'" % fmode) f2.close() # file does not exist # read write_randomness() f = open(fname, "r") fstr = f.read() f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio) f1mode = f.mode ftell = f.tell() f.close() os.remove(fname) if strictio: # throw error if file DNE assert throws(dill.loads, (f_dumped,), dne_error) else: f2 = dill.loads(f_dumped) assert f2.mode == f1mode if fmode == dill.CONTENTS_FMODE: # FIXME: this fails on systems where f2.tell() always returns 0 # assert f2.tell() == ftell # 200 assert f2.read() == "" f2.seek(0) assert f2.read() == "" assert f2.tell() == 0 elif fmode == dill.FILE_FMODE: assert f2.tell() == ftell # 200 assert f2.read() == "" f2.seek(0) assert f2.read() == fstr assert f2.tell() == ftell # 200 elif fmode == dill.HANDLE_FMODE: assert f2.tell() == 0 assert f2.read() == "" assert f2.tell() == 0 else: raise RuntimeError("Unknown file mode '%s'" % fmode) f2.close() # write write_randomness() f = open(fname, "w+") f.write("hello") f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio) ftell = f.tell() f1mode = f.mode f.close() os.remove(fname) if strictio: # throw error if file DNE assert throws(dill.loads, (f_dumped,), dne_error) else: f2 = dill.loads(f_dumped) f2mode = f2.mode f2tell = f2.tell() f2.write(" world!") f2.close() if fmode == dill.CONTENTS_FMODE: assert open(fname).read() == " world!" assert f2mode == 'w+' assert f2tell == 0 elif fmode == dill.HANDLE_FMODE: assert open(fname).read() == " world!" assert f2mode == f1mode assert f2tell == 0 elif fmode == dill.FILE_FMODE: assert open(fname).read() == "hello world!" assert f2mode == f1mode assert f2tell == ftell else: raise RuntimeError("Unknown file mode '%s'" % fmode) # append trunc_file() f = open(fname, "a") f.write("hello") f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio) ftell = f.tell() f1mode = f.mode f.close() os.remove(fname) if strictio: # throw error if file DNE assert throws(dill.loads, (f_dumped,), dne_error) else: f2 = dill.loads(f_dumped) f2mode = f2.mode f2tell = f2.tell() f2.write(" world!") f2.close() assert f2mode == f1mode if fmode == dill.CONTENTS_FMODE: assert open(fname).read() == " world!" assert f2tell == 0 elif fmode == dill.HANDLE_FMODE: assert open(fname).read() == " world!" assert f2tell == 0 elif fmode == dill.FILE_FMODE: assert open(fname).read() == "hello world!" assert f2tell == ftell else: raise RuntimeError("Unknown file mode '%s'" % fmode) # file exists, with different contents (larger size) # read write_randomness() f = open(fname, "r") fstr = f.read() f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio) f1mode = f.mode ftell = f.tell() f.close() _flen = 250 _fstr = write_randomness(number=_flen) # XXX: no safe_file: no way to be 'safe'? f2 = dill.loads(f_dumped) assert f2.mode == f1mode if fmode == dill.CONTENTS_FMODE: assert f2.tell() == ftell # 200 assert f2.read() == _fstr[ftell:] f2.seek(0) assert f2.read() == _fstr assert f2.tell() == _flen # 250 elif fmode == dill.HANDLE_FMODE: assert f2.tell() == 0 assert f2.read() == _fstr assert f2.tell() == _flen # 250 elif fmode == dill.FILE_FMODE: assert f2.tell() == ftell # 200 assert f2.read() == "" f2.seek(0) assert f2.read() == fstr assert f2.tell() == ftell # 200 else: raise RuntimeError("Unknown file mode '%s'" % fmode) f2.close() # XXX: other alternatives? # write f = open(fname, "w") f.write("hello") f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio) f1mode = f.mode ftell = f.tell() fstr = open(fname).read() f.write(" and goodbye!") _ftell = f.tell() f.close() # XXX: no safe_file: no way to be 'safe'? f2 = dill.loads(f_dumped) f2mode = f2.mode f2tell = f2.tell() f2.write(" world!") f2.close() if fmode == dill.CONTENTS_FMODE: assert open(fname).read() == "hello world!odbye!" assert f2mode == f1mode assert f2tell == ftell elif fmode == dill.HANDLE_FMODE: assert open(fname).read() == " world!" assert f2mode == f1mode assert f2tell == 0 elif fmode == dill.FILE_FMODE: assert open(fname).read() == "hello world!" assert f2mode == f1mode assert f2tell == ftell else: raise RuntimeError("Unknown file mode '%s'" % fmode) f2.close() # append trunc_file() f = open(fname, "a") f.write("hello") f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio) f1mode = f.mode ftell = f.tell() fstr = open(fname).read() f.write(" and goodbye!") _ftell = f.tell() f.close() # XXX: no safe_file: no way to be 'safe'? f2 = dill.loads(f_dumped) f2mode = f2.mode f2tell = f2.tell() f2.write(" world!") f2.close() assert f2mode == f1mode if fmode == dill.CONTENTS_FMODE: assert open(fname).read() == "hello and goodbye! world!" assert f2tell == ftell elif fmode == dill.HANDLE_FMODE: assert open(fname).read() == "hello and goodbye! world!" assert f2tell == _ftell elif fmode == dill.FILE_FMODE: assert open(fname).read() == "hello world!" assert f2tell == ftell else: raise RuntimeError("Unknown file mode '%s'" % fmode) f2.close() def test_nostrictio_handlefmode(): bench(False, dill.HANDLE_FMODE, False) teardown_module() def test_nostrictio_filefmode(): bench(False, dill.FILE_FMODE, False) teardown_module() def test_nostrictio_contentsfmode(): bench(False, dill.CONTENTS_FMODE, True) teardown_module() #bench(True, dill.HANDLE_FMODE, False) #bench(True, dill.FILE_FMODE, False) #bench(True, dill.CONTENTS_FMODE, True) if __name__ == '__main__': test_nostrictio_handlefmode() test_nostrictio_filefmode() test_nostrictio_contentsfmode() dill-0.3.1.1/tests/test_functions.py000644 000765 000024 00000002563 13543677215 020366 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python import dill import sys dill.settings['recurse'] = True def is_py3(): return hex(sys.hexversion) >= '0x30000f0' def function_a(a): return a def function_b(b, b1): return b + b1 def function_c(c, c1=1): return c + c1 def function_d(d, d1, d2=1): return d + d1 + d2 if is_py3(): exec(''' def function_e(e, *e1, e2=1, e3=2): return e + sum(e1) + e2 + e3''') def test_functions(): dumped_func_a = dill.dumps(function_a) assert dill.loads(dumped_func_a)(0) == 0 dumped_func_b = dill.dumps(function_b) assert dill.loads(dumped_func_b)(1,2) == 3 dumped_func_c = dill.dumps(function_c) assert dill.loads(dumped_func_c)(1) == 2 assert dill.loads(dumped_func_c)(1, 2) == 3 dumped_func_d = dill.dumps(function_d) assert dill.loads(dumped_func_d)(1, 2) == 4 assert dill.loads(dumped_func_d)(1, 2, 3) == 6 assert dill.loads(dumped_func_d)(1, 2, d2=3) == 6 if is_py3(): exec(''' dumped_func_e = dill.dumps(function_e) assert dill.loads(dumped_func_e)(1, 2) == 6 assert dill.loads(dumped_func_e)(1, 2, 3) == 9 assert dill.loads(dumped_func_e)(1, 2, e2=3) == 8 assert dill.loads(dumped_func_e)(1, 2, e2=3, e3=4) == 10 assert dill.loads(dumped_func_e)(1, 2, 3, e2=4) == 12 assert dill.loads(dumped_func_e)(1, 2, 3, e2=4, e3=5) == 15''') if __name__ == '__main__': test_functions() dill-0.3.1.1/tests/test_functors.py000644 000765 000024 00000001642 13543677215 020216 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import functools import dill dill.settings['recurse'] = True def f(a, b, c): # without keywords pass def g(a, b, c=2): # with keywords pass def h(a=1, b=2, c=3): # without args pass def test_functools(): fp = functools.partial(f, 1, 2) gp = functools.partial(g, 1, c=2) hp = functools.partial(h, 1, c=2) bp = functools.partial(int, base=2) assert dill.pickles(fp, safe=True) assert dill.pickles(gp, safe=True) assert dill.pickles(hp, safe=True) assert dill.pickles(bp, safe=True) if __name__ == '__main__': test_functools() dill-0.3.1.1/tests/test_mixins.py000644 000765 000024 00000007647 13543677215 017675 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import dill dill.settings['recurse'] = True def wtf(x,y,z): def zzz(): return x def yyy(): return y def xxx(): return z return zzz,yyy def quad(a=1, b=1, c=0): inverted = [False] def invert(): inverted[0] = not inverted[0] def dec(f): def func(*args, **kwds): x = f(*args, **kwds) if inverted[0]: x = -x return a*x**2 + b*x + c func.__wrapped__ = f func.invert = invert func.inverted = inverted return func return dec @quad(a=0,b=2) def double_add(*args): return sum(args) fx = sum([1,2,3]) ### to make it interesting... def quad_factory(a=1,b=1,c=0): def dec(f): def func(*args,**kwds): fx = f(*args,**kwds) return a*fx**2 + b*fx + c return func return dec @quad_factory(a=0,b=4,c=0) def quadish(x): return x+1 quadratic = quad_factory() def doubler(f): def inner(*args, **kwds): fx = f(*args, **kwds) return 2*fx return inner @doubler def quadruple(x): return 2*x def test_mixins(): # test mixins assert double_add(1,2,3) == 2*fx double_add.invert() assert double_add(1,2,3) == -2*fx _d = dill.copy(double_add) assert _d(1,2,3) == -2*fx #_d.invert() #FIXME: fails seemingly randomly #assert _d(1,2,3) == 2*fx assert _d.__wrapped__(1,2,3) == fx # XXX: issue or feature? in python3.4, inverted is linked through copy if not double_add.inverted[0]: double_add.invert() # test some stuff from source and pointers ds = dill.source dd = dill.detect assert ds.getsource(dd.freevars(quadish)['f']) == '@quad_factory(a=0,b=4,c=0)\ndef quadish(x):\n return x+1\n' assert ds.getsource(dd.freevars(quadruple)['f']) == '@doubler\ndef quadruple(x):\n return 2*x\n' assert ds.importable(quadish, source=False) == 'from %s import quadish\n' % __name__ assert ds.importable(quadruple, source=False) == 'from %s import quadruple\n' % __name__ assert ds.importable(quadratic, source=False) == 'from %s import quadratic\n' % __name__ assert ds.importable(double_add, source=False) == 'from %s import double_add\n' % __name__ assert ds.importable(quadruple, source=True) == 'def doubler(f):\n def inner(*args, **kwds):\n fx = f(*args, **kwds)\n return 2*fx\n return inner\n\n@doubler\ndef quadruple(x):\n return 2*x\n' #***** #FIXME: this needs work result = ds.importable(quadish, source=True) a,b,c,_,result = result.split('\n',4) assert result == 'def quad_factory(a=1,b=1,c=0):\n def dec(f):\n def func(*args,**kwds):\n fx = f(*args,**kwds)\n return a*fx**2 + b*fx + c\n return func\n return dec\n\n@quad_factory(a=0,b=4,c=0)\ndef quadish(x):\n return x+1\n' assert set([a,b,c]) == set(['a = 0', 'c = 0', 'b = 4']) result = ds.importable(quadratic, source=True) a,b,c,result = result.split('\n',3) assert result == '\ndef dec(f):\n def func(*args,**kwds):\n fx = f(*args,**kwds)\n return a*fx**2 + b*fx + c\n return func\n' assert set([a,b,c]) == set(['a = 1', 'c = 0', 'b = 1']) result = ds.importable(double_add, source=True) a,b,c,d,_,result = result.split('\n',5) assert result == 'def quad(a=1, b=1, c=0):\n inverted = [False]\n def invert():\n inverted[0] = not inverted[0]\n def dec(f):\n def func(*args, **kwds):\n x = f(*args, **kwds)\n if inverted[0]: x = -x\n return a*x**2 + b*x + c\n func.__wrapped__ = f\n func.invert = invert\n func.inverted = inverted\n return func\n return dec\n\n@quad(a=0,b=2)\ndef double_add(*args):\n return sum(args)\n' assert set([a,b,c,d]) == set(['a = 0', 'c = 0', 'b = 2', 'inverted = [True]']) #***** if __name__ == '__main__': test_mixins() dill-0.3.1.1/tests/test_module.py000644 000765 000024 00000003657 13543677215 017650 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import sys import dill import test_mixins as module try: from imp import reload except ImportError: pass dill.settings['recurse'] = True cached = (module.__cached__ if hasattr(module, "__cached__") else module.__file__.split(".", 1)[0] + ".pyc") module.a = 1234 pik_mod = dill.dumps(module) module.a = 0 # remove module del sys.modules[module.__name__] del module module = dill.loads(pik_mod) def test_attributes(): #assert hasattr(module, "a") and module.a == 1234 #FIXME: -m dill.tests assert module.double_add(1, 2, 3) == 2 * module.fx # Restart, and test use_diff reload(module) try: dill.use_diff() module.a = 1234 pik_mod = dill.dumps(module) module.a = 0 # remove module del sys.modules[module.__name__] del module module = dill.loads(pik_mod) def test_diff_attributes(): assert hasattr(module, "a") and module.a == 1234 assert module.double_add(1, 2, 3) == 2 * module.fx except AttributeError: def test_diff_attributes(): pass # clean up import os if os.path.exists(cached): os.remove(cached) pycache = os.path.join(os.path.dirname(module.__file__), "__pycache__") if os.path.exists(pycache) and not os.listdir(pycache): os.removedirs(pycache) # test when module is None import math def get_lambda(str, **kwarg): return eval(str, kwarg, None) obj = get_lambda('lambda x: math.exp(x)', math=math) def test_module_is_none(): assert obj.__module__ is None assert dill.copy(obj)(3) == obj(3) if __name__ == '__main__': test_attributes() test_diff_attributes() test_module_is_none() dill-0.3.1.1/tests/test_moduledict.py000644 000765 000024 00000002236 13543677215 020504 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import dill dill.settings['recurse'] = True def f(func): def w(*args): return f(*args) return w @f def f2(): pass # check when __main__ and on import def test_decorated(): assert dill.pickles(f2) import doctest import logging logging.basicConfig(level=logging.DEBUG) class SomeUnreferencedUnpicklableClass(object): def __reduce__(self): raise Exception unpicklable = SomeUnreferencedUnpicklableClass() # This works fine outside of Doctest: def test_normal(): serialized = dill.dumps(lambda x: x) # should not try to pickle unpicklable object in __globals__ def tests(): """ >>> serialized = dill.dumps(lambda x: x) """ return #print("\n\nRunning Doctest:") def test_doctest(): doctest.testmod() if __name__ == '__main__': test_decorated() test_normal() test_doctest() dill-0.3.1.1/tests/test_nested.py000644 000765 000024 00000006076 13543677215 017643 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ test dill's ability to handle nested functions """ import os import math import dill as pickle pickle.settings['recurse'] = True # the nested function: pickle should fail here, but dill is ok. def adder(augend): zero = [0] def inner(addend): return addend + augend + zero[0] return inner # rewrite the nested function using a class: standard pickle should work here. class cadder(object): def __init__(self, augend): self.augend = augend self.zero = [0] def __call__(self, addend): return addend + self.augend + self.zero[0] # rewrite again, but as an old-style class class c2adder: def __init__(self, augend): self.augend = augend self.zero = [0] def __call__(self, addend): return addend + self.augend + self.zero[0] # some basic class stuff class basic(object): pass class basic2: pass x = 5 y = 1 def test_basic(): a = [0, 1, 2] pa = pickle.dumps(a) pmath = pickle.dumps(math) #XXX: FAILS in pickle pmap = pickle.dumps(map) # ... la = pickle.loads(pa) lmath = pickle.loads(pmath) lmap = pickle.loads(pmap) assert list(map(math.sin, a)) == list(lmap(lmath.sin, la)) def test_basic_class(): pbasic2 = pickle.dumps(basic2) _pbasic2 = pickle.loads(pbasic2)() pbasic = pickle.dumps(basic) _pbasic = pickle.loads(pbasic)() def test_c2adder(): pc2adder = pickle.dumps(c2adder) pc2add5 = pickle.loads(pc2adder)(x) assert pc2add5(y) == x+y def test_pickled_cadder(): pcadder = pickle.dumps(cadder) pcadd5 = pickle.loads(pcadder)(x) assert pcadd5(y) == x+y def test_raw_adder_and_inner(): add5 = adder(x) assert add5(y) == x+y def test_pickled_adder(): padder = pickle.dumps(adder) padd5 = pickle.loads(padder)(x) assert padd5(y) == x+y def test_pickled_inner(): add5 = adder(x) pinner = pickle.dumps(add5) #XXX: FAILS in pickle p5add = pickle.loads(pinner) assert p5add(y) == x+y def test_moduledict_where_not_main(): try: from . import test_moduledict except: import test_moduledict name = 'test_moduledict.py' if os.path.exists(name) and os.path.exists(name+'c'): os.remove(name+'c') if os.path.exists(name) and hasattr(test_moduledict, "__cached__") \ and os.path.exists(test_moduledict.__cached__): os.remove(getattr(test_moduledict, "__cached__")) if os.path.exists("__pycache__") and not os.listdir("__pycache__"): os.removedirs("__pycache__") if __name__ == '__main__': test_basic() test_basic_class() test_c2adder() test_pickled_cadder() test_raw_adder_and_inner() test_pickled_adder() test_pickled_inner() test_moduledict_where_not_main() dill-0.3.1.1/tests/test_objects.py000644 000765 000024 00000003363 13543677215 020006 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ demonstrate dill's ability to pickle different python types test pickling of all Python Standard Library objects (currently: CH 1-14 @ 2.7) """ import dill as pickle pickle.settings['recurse'] = True #pickle.detect.trace(True) #import pickle # get all objects for testing from dill import load_types, objects, extend load_types(pickleable=True,unpickleable=False) # uncomment the next two lines to test cloudpickle #extend(False) #import cloudpickle as pickle # helper objects class _class: def _method(self): pass # objects that *fail* if imported special = {} special['LambdaType'] = _lambda = lambda x: lambda y: x special['MethodType'] = _method = _class()._method special['UnboundMethodType'] = _class._method objects.update(special) def pickles(name, exact=False): """quick check if object pickles with dill""" obj = objects[name] try: pik = pickle.loads(pickle.dumps(obj)) if exact: try: assert pik == obj except AssertionError: assert type(obj) == type(pik) print ("weak: %s %s" % (name, type(obj))) else: assert type(obj) == type(pik) except Exception: print ("fails: %s %s" % (name, type(obj))) def test_objects(): for member in objects.keys(): #pickles(member, exact=True) pickles(member, exact=False) if __name__ == '__main__': test_objects() dill-0.3.1.1/tests/test_properties.py000644 000765 000024 00000002502 13543677215 020543 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import sys import dill dill.settings['recurse'] = True class Foo(object): def __init__(self): self._data = 1 def _get_data(self): return self._data def _set_data(self, x): self._data = x data = property(_get_data, _set_data) def test_data_not_none(): FooS = dill.copy(Foo) assert FooS.data.fget is not None assert FooS.data.fset is not None assert FooS.data.fdel is None def test_data_unchanged(): FooS = dill.copy(Foo) try: res = FooS().data except Exception: e = sys.exc_info()[1] raise AssertionError(str(e)) else: assert res == 1 def test_data_changed(): FooS = dill.copy(Foo) try: f = FooS() f.data = 1024 res = f.data except Exception: e = sys.exc_info()[1] raise AssertionError(str(e)) else: assert res == 1024 if __name__ == '__main__': test_data_not_none() test_data_unchanged() test_data_changed() dill-0.3.1.1/tests/test_recursive.py000644 000765 000024 00000004175 13543677215 020366 0ustar00mmckernsstaff000000 000000 import dill from functools import partial from dill._dill import PY3, OLDER _super = super class obj1(object): def __init__(self): super(obj1, self).__init__() class obj2(object): def __init__(self): _super(obj2, self).__init__() class obj3(object): super_ = super def __init__(self): obj3.super_(obj3, self).__init__() def test_super(): assert dill.copy(obj1(), byref=True) assert dill.copy(obj1(), byref=True, recurse=True) #assert dill.copy(obj1(), recurse=True) #FIXME: fails __main__.py assert dill.copy(obj1()) assert dill.copy(obj2(), byref=True) assert dill.copy(obj2(), byref=True, recurse=True) #assert dill.copy(obj2(), recurse=True) #FIXME: fails __main__.py assert dill.copy(obj2()) assert dill.copy(obj3(), byref=True) assert dill.copy(obj3(), byref=True, recurse=True) #assert dill.copy(obj3(), recurse=True) #FIXME: fails __main__.py assert dill.copy(obj3()) def get_trigger(model): pass class Machine(object): def __init__(self): self.child = Model() self.trigger = partial(get_trigger, self) self.child.trigger = partial(get_trigger, self.child) class Model(object): pass def test_partial(): assert dill.copy(Machine(), byref=True) assert dill.copy(Machine(), byref=True, recurse=True) if not OLDER: assert dill.copy(Machine(), recurse=True) assert dill.copy(Machine()) class Machine2(object): def __init__(self): self.go = partial(self.member, self) def member(self, model): pass class SubMachine(Machine2): def __init__(self): _super(SubMachine, self).__init__() #super(SubMachine, self).__init__() #XXX: works, except for 3.1-3.3 def test_partials(): assert dill.copy(SubMachine(), byref=True) assert dill.copy(SubMachine(), byref=True, recurse=True) #if not OLDER: #FIXME: fails __main__.py # assert dill.copy(SubMachine(), recurse=True) assert dill.copy(SubMachine()) if __name__ == '__main__': #print(('byref','_super','_recurse','_memo','_stop','OLDER')) test_super() test_partial() test_partials() dill-0.3.1.1/tests/test_restricted.py000644 000765 000024 00000001417 13543677215 020523 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Kirill Makhonin (@kirillmakhonin) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import dill class RestrictedType: def __bool__(*args, **kwargs): raise Exception('Restricted function') __eq__ = __lt__ = __le__ = __ne__ = __gt__ = __ge__ = __hash__ = __bool__ glob_obj = RestrictedType() def restricted_func(): a = glob_obj def test_function_with_restricted_object(): deserialized = dill.loads(dill.dumps(restricted_func, recurse=True)) if __name__ == '__main__': test_function_with_restricted_object() dill-0.3.1.1/tests/test_selected.py000644 000765 000024 00000004772 13543677215 020152 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ testing some selected object types """ import dill dill.settings['recurse'] = True verbose = False def test_dict_contents(): c = type.__dict__ for i,j in c.items(): #try: ok = dill.pickles(j) #except: # print ("FAIL: %s with %s" % (i, dill.detect.errors(j))) if verbose: print ("%s: %s, %s" % (ok, type(j), j)) assert ok if verbose: print ("") def _g(x): yield x; def _f(): try: raise except: from sys import exc_info e, er, tb = exc_info() return er, tb class _d(object): def _method(self): pass from dill import objects from dill import load_types load_types(pickleable=True,unpickleable=False) _newclass = objects['ClassObjectType'] del objects # getset_descriptor for new-style classes (fails on '_method', if not __main__) def test_class_descriptors(): d = _d.__dict__ for i in d.values(): ok = dill.pickles(i) if verbose: print ("%s: %s, %s" % (ok, type(i), i)) assert ok if verbose: print ("") od = _newclass.__dict__ for i in od.values(): ok = dill.pickles(i) if verbose: print ("%s: %s, %s" % (ok, type(i), i)) assert ok if verbose: print ("") # (__main__) class instance for new-style classes def test_class(): o = _d() oo = _newclass() ok = dill.pickles(o) if verbose: print ("%s: %s, %s" % (ok, type(o), o)) assert ok ok = dill.pickles(oo) if verbose: print ("%s: %s, %s" % (ok, type(oo), oo)) assert ok if verbose: print ("") # frames, generators, and tracebacks (all depend on frame) def test_frame_related(): g = _g(1) f = g.gi_frame e,t = _f() _is = lambda ok: not ok if dill._dill.IS_PYPY else ok ok = dill.pickles(f) if verbose: print ("%s: %s, %s" % (ok, type(f), f)) assert _is(not ok) #XXX: dill fails ok = dill.pickles(g) if verbose: print ("%s: %s, %s" % (ok, type(g), g)) assert _is(not ok) #XXX: dill fails ok = dill.pickles(t) if verbose: print ("%s: %s, %s" % (ok, type(t), t)) assert not ok #XXX: dill fails ok = dill.pickles(e) if verbose: print ("%s: %s, %s" % (ok, type(e), e)) assert ok if verbose: print ("") if __name__ == '__main__': test_frame_related() test_dict_contents() test_class() test_class_descriptors() dill-0.3.1.1/tests/test_source.py000644 000765 000024 00000014143 13543677215 017653 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE from dill.source import getsource, getname, _wrap, likely_import from dill.source import getimportable import sys PY3 = sys.version_info[0] >= 3 f = lambda x: x**2 def g(x): return f(x) - x def h(x): def g(x): return x return g(x) - x class Foo(object): def bar(self, x): return x*x+x _foo = Foo() def add(x,y): return x+y # yes, same as 'f', but things are tricky when it comes to pointers squared = lambda x:x**2 class Bar: pass _bar = Bar() # inspect.getsourcelines # dill.source.getblocks def test_getsource(): assert getsource(f) == 'f = lambda x: x**2\n' assert getsource(g) == 'def g(x): return f(x) - x\n' assert getsource(h) == 'def h(x):\n def g(x): return x\n return g(x) - x\n' assert getname(f) == 'f' assert getname(g) == 'g' assert getname(h) == 'h' assert _wrap(f)(4) == 16 assert _wrap(g)(4) == 12 assert _wrap(h)(4) == 0 assert getname(Foo) == 'Foo' assert getname(Bar) == 'Bar' assert getsource(Bar) == 'class Bar:\n pass\n' assert getsource(Foo) == 'class Foo(object):\n def bar(self, x):\n return x*x+x\n' #XXX: add getsource for _foo, _bar # test itself def test_itself(): assert likely_import(likely_import)=='from dill.source import likely_import\n' # builtin functions and objects def test_builtin(): if PY3: builtin = 'builtins' else: builtin = '__builtin__' assert likely_import(pow) == 'pow\n' assert likely_import(100) == '100\n' assert likely_import(True) == 'True\n' assert likely_import(pow, explicit=True) == 'from %s import pow\n' % builtin assert likely_import(100, explicit=True) == '100\n' assert likely_import(True, explicit=True) == 'True\n' if PY3 else 'from %s import True\n' % builtin # this is kinda BS... you can't import a None assert likely_import(None) == 'None\n' assert likely_import(None, explicit=True) == 'None\n' # other imported functions def test_imported(): from math import sin assert likely_import(sin) == 'from math import sin\n' # interactively defined functions def test_dynamic(): assert likely_import(add) == 'from %s import add\n' % __name__ # interactive lambdas assert likely_import(squared) == 'from %s import squared\n' % __name__ # classes and class instances def test_classes(): try: #XXX: should this be a 'special case'? from StringIO import StringIO x = "from StringIO import StringIO\n" y = x except ImportError: from io import BytesIO as StringIO x = "from io import BytesIO\n" y = "from _io import BytesIO\n" s = StringIO() assert likely_import(StringIO) == x assert likely_import(s) == y # interactively defined classes and class instances assert likely_import(Foo) == 'from %s import Foo\n' % __name__ assert likely_import(_foo) == 'from %s import Foo\n' % __name__ # test getimportable def test_importable(): assert getimportable(add) == 'from %s import add\n' % __name__ assert getimportable(squared) == 'from %s import squared\n' % __name__ assert getimportable(Foo) == 'from %s import Foo\n' % __name__ assert getimportable(Foo.bar) == 'from %s import bar\n' % __name__ assert getimportable(_foo.bar) == 'from %s import bar\n' % __name__ assert getimportable(None) == 'None\n' assert getimportable(100) == '100\n' assert getimportable(add, byname=False) == 'def add(x,y):\n return x+y\n' assert getimportable(squared, byname=False) == 'squared = lambda x:x**2\n' assert getimportable(None, byname=False) == 'None\n' assert getimportable(Bar, byname=False) == 'class Bar:\n pass\n' assert getimportable(Foo, byname=False) == 'class Foo(object):\n def bar(self, x):\n return x*x+x\n' assert getimportable(Foo.bar, byname=False) == 'def bar(self, x):\n return x*x+x\n' assert getimportable(Foo.bar, byname=True) == 'from %s import bar\n' % __name__ assert getimportable(Foo.bar, alias='memo', byname=True) == 'from %s import bar as memo\n' % __name__ assert getimportable(Foo, alias='memo', byname=True) == 'from %s import Foo as memo\n' % __name__ assert getimportable(squared, alias='memo', byname=True) == 'from %s import squared as memo\n' % __name__ assert getimportable(squared, alias='memo', byname=False) == 'memo = squared = lambda x:x**2\n' assert getimportable(add, alias='memo', byname=False) == 'def add(x,y):\n return x+y\n\nmemo = add\n' assert getimportable(None, alias='memo', byname=False) == 'memo = None\n' assert getimportable(100, alias='memo', byname=False) == 'memo = 100\n' assert getimportable(add, explicit=True) == 'from %s import add\n' % __name__ assert getimportable(squared, explicit=True) == 'from %s import squared\n' % __name__ assert getimportable(Foo, explicit=True) == 'from %s import Foo\n' % __name__ assert getimportable(Foo.bar, explicit=True) == 'from %s import bar\n' % __name__ assert getimportable(_foo.bar, explicit=True) == 'from %s import bar\n' % __name__ assert getimportable(None, explicit=True) == 'None\n' assert getimportable(100, explicit=True) == '100\n' def test_numpy(): try: from numpy import array x = array([1,2,3]) assert getimportable(x) == 'from numpy import array\narray([1, 2, 3])\n' assert getimportable(array) == 'from %s import array\n' % array.__module__ assert getimportable(x, byname=False) == 'from numpy import array\narray([1, 2, 3])\n' assert getimportable(array, byname=False) == 'from %s import array\n' % array.__module__ except ImportError: pass #NOTE: if before likely_import(pow), will cause pow to throw AssertionError def test_foo(): assert getimportable(_foo, byname=False).startswith("import dill\nclass Foo(object):\n def bar(self, x):\n return x*x+x\ndill.loads(") if __name__ == '__main__': test_getsource() test_itself() test_builtin() test_imported() test_dynamic() test_classes() test_importable() test_numpy() test_foo() dill-0.3.1.1/tests/test_temp.py000644 000765 000024 00000005073 13543677215 017322 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import sys from dill.temp import dump, dump_source, dumpIO, dumpIO_source from dill.temp import load, load_source, loadIO, loadIO_source WINDOWS = sys.platform[:3] == 'win' f = lambda x: x**2 x = [1,2,3,4,5] # source code to tempfile def test_code_to_tempfile(): if not WINDOWS: #see: https://bugs.python.org/issue14243 pyfile = dump_source(f, alias='_f') _f = load_source(pyfile) assert _f(4) == f(4) # source code to stream def test_code_to_stream(): pyfile = dumpIO_source(f, alias='_f') _f = loadIO_source(pyfile) assert _f(4) == f(4) # pickle to tempfile def test_pickle_to_tempfile(): if not WINDOWS: #see: https://bugs.python.org/issue14243 dumpfile = dump(x) _x = load(dumpfile) assert _x == x # pickle to stream def test_pickle_to_stream(): dumpfile = dumpIO(x) _x = loadIO(dumpfile) assert _x == x ### now testing the objects ### f = lambda x: x**2 def g(x): return f(x) - x def h(x): def g(x): return x return g(x) - x class Foo(object): def bar(self, x): return x*x+x _foo = Foo() def add(x,y): return x+y # yes, same as 'f', but things are tricky when it comes to pointers squared = lambda x:x**2 class Bar: pass _bar = Bar() # test function-type objects that take 2 args def test_two_arg_functions(): for obj in [add]: pyfile = dumpIO_source(obj, alias='_obj') _obj = loadIO_source(pyfile) assert _obj(4,2) == obj(4,2) # test function-type objects that take 1 arg def test_one_arg_functions(): for obj in [g, h, squared]: pyfile = dumpIO_source(obj, alias='_obj') _obj = loadIO_source(pyfile) assert _obj(4) == obj(4) # test instance-type objects #for obj in [_bar, _foo]: # pyfile = dumpIO_source(obj, alias='_obj') # _obj = loadIO_source(pyfile) # assert type(_obj) == type(obj) # test the rest of the objects def test_the_rest(): for obj in [Bar, Foo, Foo.bar, _foo.bar]: pyfile = dumpIO_source(obj, alias='_obj') _obj = loadIO_source(pyfile) assert _obj.__name__ == obj.__name__ if __name__ == '__main__': test_code_to_tempfile() test_code_to_stream() test_pickle_to_tempfile() test_pickle_to_stream() test_two_arg_functions() test_one_arg_functions() test_the_rest() dill-0.3.1.1/tests/test_weakref.py000644 000765 000024 00000004010 13543677215 017767 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE import dill dill.settings['recurse'] = True import weakref class _class: def _method(self): pass class _class2: def __call__(self): pass class _newclass(object): def _method(self): pass class _newclass2(object): def __call__(self): pass def _function(): pass def test_weakref(): o = _class() oc = _class2() n = _newclass() nc = _newclass2() f = _function z = _class x = _newclass r = weakref.ref(o) dr = weakref.ref(_class()) p = weakref.proxy(o) dp = weakref.proxy(_class()) c = weakref.proxy(oc) dc = weakref.proxy(_class2()) m = weakref.ref(n) dm = weakref.ref(_newclass()) t = weakref.proxy(n) dt = weakref.proxy(_newclass()) d = weakref.proxy(nc) dd = weakref.proxy(_newclass2()) fr = weakref.ref(f) fp = weakref.proxy(f) #zr = weakref.ref(z) #XXX: weakrefs not allowed for classobj objects #zp = weakref.proxy(z) #XXX: weakrefs not allowed for classobj objects xr = weakref.ref(x) xp = weakref.proxy(x) objlist = [r,dr,m,dm,fr,xr, p,dp,t,dt, c,dc,d,dd, fp,xp] #dill.detect.trace(True) for obj in objlist: res = dill.detect.errors(obj) if res: print ("%s" % res) #print ("%s:\n %s" % (obj, res)) # else: # print ("PASS: %s" % obj) assert not res def test_dictproxy(): from dill._dill import DictProxyType try: m = DictProxyType({"foo": "bar"}) except: m = type.__dict__ mp = dill.copy(m) assert mp.items() == m.items() if __name__ == '__main__': test_weakref() from dill._dill import IS_PYPY if not IS_PYPY: test_dictproxy() dill-0.3.1.1/scripts/get_objgraph000644 000765 000024 00000003166 13543677215 017650 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ display the reference paths for objects in ``dill.types`` or a .pkl file Notes: the generated image is useful in showing the pointer references in objects that are or can be pickled. Any object in ``dill.objects`` listed in ``dill.load_types(picklable=True, unpicklable=True)`` works. Examples:: $ get_objgraph FrameType Image generated as FrameType.png """ import dill as pickle #pickle.debug.trace(True) #import pickle # get all objects for testing from dill import load_types load_types(pickleable=True,unpickleable=True) from dill import objects if __name__ == "__main__": import sys if len(sys.argv) != 2: print ("Please provide exactly one file or type name (e.g. 'IntType')") msg = "\n" for objtype in list(objects.keys())[:40]: msg += objtype + ', ' print (msg + "...") else: objtype = str(sys.argv[-1]) try: obj = objects[objtype] except KeyError: obj = pickle.load(open(objtype,'rb')) import os objtype = os.path.splitext(objtype)[0] try: import objgraph objgraph.show_refs(obj, filename=objtype+'.png') except ImportError: print ("Please install 'objgraph' to view object graphs") # EOF dill-0.3.1.1/scripts/undill000644 000765 000024 00000001116 13543677215 016475 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ unpickle the contents of a pickled object file Examples:: $ undill hello.pkl ['hello', 'world'] """ if __name__ == '__main__': import sys import dill for file in sys.argv[1:]: print (dill.load(open(file,'rb'))) dill-0.3.1.1/docs/Makefile000644 000765 000024 00000001155 13543677215 016167 0ustar00mmckernsstaff000000 000000 # Minimal makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build SPHINXPROJ = dill SOURCEDIR = source BUILDDIR = build # Internal variables ALLSPHINXOPTS = $(SPHINXOPTS) $(SOURCEDIR) # Put it first so that "make" without argument is like "make help". help: @echo "Please use \`make html' to generate standalone HTML files" .PHONY: help clean html Makefile clean: -rm -rf $(BUILDDIR) html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR) -rm -f $(BUILDDIR)/../../scripts/_*py -rm -f $(BUILDDIR)/../../scripts/_*pyc dill-0.3.1.1/docs/source/000755 000765 000024 00000000000 13543677215 016025 5ustar00mmckernsstaff000000 000000 dill-0.3.1.1/docs/source/_static/000755 000765 000024 00000000000 13543677215 017453 5ustar00mmckernsstaff000000 000000 dill-0.3.1.1/docs/source/_templates/000755 000765 000024 00000000000 13543677215 020162 5ustar00mmckernsstaff000000 000000 dill-0.3.1.1/docs/source/conf.py000644 000765 000024 00000016300 13543677215 017324 0ustar00mmckernsstaff000000 000000 # -*- coding: utf-8 -*- # # dill documentation build configuration file, created by # sphinx-quickstart on Sun Aug 6 06:50:58 2017. # # 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. # 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. # import os from datetime import datetime import sys scripts = os.path.abspath('../../scripts') sys.path.insert(0, scripts) try: os.symlink(scripts+os.sep+'undill', scripts+os.sep+'_undill.py') os.symlink(scripts+os.sep+'get_objgraph', scripts+os.sep+'_get_objgraph.py') except: pass # Import the project import dill # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.imgmath', 'sphinx.ext.ifconfig', 'sphinx.ext.napoleon'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. project = u'dill' year = datetime.now().year copyright = u'%d, The Uncertainty Quantification Foundation' % year author = u'Mike McKerns' # extension config github_project_url = "https://github.com/uqfoundation/dill" autoclass_content= 'both' napoleon_include_init_with_doc = True napoleon_include_private_with_doc = False napoleon_include_special_with_doc = True napoleon_use_param = False napoleon_use_ivar = True # 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 = dill.__version__ # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # Configure how the modules, functions, etc names look add_module_names = False modindex_common_prefix = ['dill.'] # -- Options for HTML output ---------------------------------------------- # on_rtd is whether we are on readthedocs.io on_rtd = os.environ.get('READTHEDOCS', None) == 'True' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # if not on_rtd: html_theme = 'alabaster' #'bizstyle' #import sphinx_rtd_theme #html_theme = 'sphinx_rtd_theme' #html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # 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 = { 'github_user': 'uqfoundation', 'github_repo': 'dill', 'github_button': False, 'github_banner': True, 'travis_button': True, 'gratipay_user': False, # username 'extra_nav_links': {'Module Index': 'py-modindex.html'}, # 'show_related': True, 'show_powered_by': False } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars #if html_theme == 'alabaster': html_sidebars = { '**': [ 'about.html', # 'navigation.html', 'localtoc.html', # display the toctree 'relations.html', # needs 'show_related':True option to display 'searchbox.html', 'donate.html', # needs 'gratipay_user': option to display ] } #FIXME: donate / UQFoundation (home/github) # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. htmlhelp_basename = 'dilldoc' # Logo for sidebar html_logo = 'pathos.png' # -- 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': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'dill.tex', u'dill Documentation', u'Mike McKerns', 'manual'), ] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'dill', u'dill Documentation', [author], 1) ] # -- 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 = [ (master_doc, 'dill', u'dill Documentation', author, 'dill', 'Serialize all of python.', 'Miscellaneous'), ] # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'https://docs.python.org/': None} # {'python': {'https://docs.python.org/': None}, # 'mystic': {'https://mystic.readthedocs.io/en/latest/', None}, # 'pathos': {'https://pathos.readthedocs.io/en/latest/', None}, # 'klepto': {'https://klepto.readthedocs.io/en/latest/', None}, # 'pox': {'https://pox.readthedocs.io/en/latest/', None}, # 'multiprocess': {'https://multiprocess.readthedocs.io/en/latest/', None}, # 'ppft': {'https://ppft.readthedocs.io/en/latest/', None}, # 'pyina': {'https://pyina.readthedocs.io/en/latest/', None}, # } dill-0.3.1.1/docs/source/dill.rst000644 000765 000024 00000003055 13543677215 017506 0ustar00mmckernsstaff000000 000000 dill module documentation ========================= dill module ----------- .. automodule:: dill._dill :members: :undoc-members: :private-members: :special-members: :show-inheritance: :imported-members: .. :exclude-members: detect module ------------- .. automodule:: dill.detect :members: :undoc-members: :private-members: :special-members: :show-inheritance: :imported-members: .. :exclude-members: ismethod, isfunction, istraceback, isframe, iscode, parent, reference, at, parents, children objtypes module --------------- .. automodule:: dill.objtypes :members: :undoc-members: :private-members: :special-members: :show-inheritance: :imported-members: .. :exclude-members: pointers module --------------- .. automodule:: dill.pointers :members: :undoc-members: :private-members: :special-members: :show-inheritance: :imported-members: .. :exclude-members: settings module --------------- .. automodule:: dill.settings :members: :undoc-members: :private-members: :special-members: :show-inheritance: :imported-members: .. :exclude-members: source module ------------- .. automodule:: dill.source :members: :undoc-members: :private-members: :special-members: :show-inheritance: :imported-members: .. :exclude-members: temp module ----------- .. automodule:: dill.temp :members: :undoc-members: :private-members: :special-members: :show-inheritance: :imported-members: .. :exclude-members: dill-0.3.1.1/docs/source/index.rst000644 000765 000024 00000000575 13543677215 017675 0ustar00mmckernsstaff000000 000000 .. dill documentation master file dill package documentation ========================== .. automodule:: dill :members: :undoc-members: :private-members: :special-members: :show-inheritance: .. toctree:: :maxdepth: 2 :caption: Contents: dill scripts Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` dill-0.3.1.1/docs/source/pathos.png000644 000765 000024 00000231466 13543677215 020045 0ustar00mmckernsstaff000000 000000 ‰PNG  IHDRI(Õ"WCiCCPICC Profilex­Xy8”Ýß?³ÛØ÷¥LŠ-»0²ïk¶ìfˆÉ0ƒ±'¥EÙ—²D¶„EDòDH¶¥RŠHJ$û’ð»‡zžë÷¾×s½ÿ¼çºæ>Ÿó9ßí>ßsæœsÀ&èA&á?J µ6Æá¸#†ö€À¤—>ˆ¬eii ‰üKYy `Ô®)ª­ú7š9rLàôÞÅG©·‹m¨8”B¦@2>TŒ÷ñð„ð)KÚXë@¸ ÂÌÞ»øãvq;‡à½©ºC Øý= þÐÎ@ë鄇º©~==ƒð~NŽõó#AöY_B¼žé²®Aøu\ *¨i@6Ûÿá\îPIKó?ÜÁ 8hÊù‡[´Þ+woÐ y¹s0´64#ÛÛ‹¢Plil¦noomooÞñ€§D|p`ÈŽ,äÖ ÀÿÕÞ}çß(9P‚aü°.x<©I#‰’ 5¡‹¢Æ(‚Îgb©f³å çläãUç‡ 4í9-$‹™N? /òê ¿Ø–D²$·T† ·lº½ü…U%¼r—êá# j3ÆØBÍU-SílÏz’úþe†£Æ¬&š¦³ó*‹!+zkc¡6wlGì™ÔŸtÌvjqžreuSt·óÅeà«=û½f½‘>\á“2¾*Dm?cs’Ù:À<Ð8H‹¢,"ʺ6þ<"?’xJ%Š6jèô­èè3vgåbXbæÎ ž|¡èb|lØ%ïËvqÆñ Wû’S´SCÓŠÓ{¯¬fðgªfÙdû^‹ÊIÏÍ¿~/¯>¿½`¨ðKÑâ­›t%¥‚enIÞ–¿£zW­\ãžæý£G+±Ô«ŽT+=”«‘­•~$Y'þX¤~ß_üOX +_ž¾mzÞ\Ñ’û,¶•òܵM¿]ºƒ½ã[gcWÒ çn±îùžÚÞ°—Ê/—ú*û û†S_é¿Úx}ÿëÃPå[»·?ß]Vîïûù!gDn¤cÔ}tícú˜ÌXç8áçª ×Ï Ÿ«']¾ ¾Üýjõui*ýÛáo=Ó„øLöwéïͳv³S?bæöÎ5͸ÚÏ,a—‘Ëý+·WãÖ×=~ÚoØü²ßtÝòÙ6ÝÞ†ò‡Ã]|ˆÈzšÛ¨ Ú.º%uÆ+èEfË [+g ·.Ï(_¨«àõ½²B•ûä…Ë`DD—ÅlÅ+ÑKºKݓޒ5;œ"7¨À©h¡” Üªò눔š«z¢F ö½æ––€¶‚Ž®£AŸbpÊ0Ö¨Àø©ÉˆéOs. iK=+'kʱK6Ù¶·íÛ·;¼:>æøÝiÍîŠrCºm»¯{,à¦ñŸ<ßyõhõ®ó)'äŸLö=C òóð·"iWê#ƒ4(JGpRˆ}èþй°'áñN‘‡"7OõFÝ8mtæàY®æstçáç^˜¿8ûéÒð徸¶ø§ µ‰åIÅÉ9)©©ÓΤ‡] ¼JÌÀgºd9d[\ÓÏÑÈ•¿.ž'˜Ïœ¿]ð£p´èÅÚâ›7ÓKRKÓʲoåÞ.¹s÷nuù£{M÷»+^WŽ=˜©ZHSÃY+üHºNý±A½é_ÆOô´UžŠ5q7Û§Z:ŸÝj=ûÜ®M¢m£½³#£Ó½ëP×ê‹–îÄ»^ÁÞ/óûœûyúûâu½ªyM~#ñæËÐÍ·žïDßM W¼ù€AôŽæ|ô“‡÷~*˜ü¬7É7ùãKÓ×Ì)¿o:Ó|Ós3=ßkfoüȜ˜Ï_¨XìZZ^]Å­¯ÏmhÿÊܜۖÚÉ¿)\ Þ…G*"Ò´¡JhÓè.Ó§1”0>G/0‹°àXo°}áPãÌç†ñàyŸòcB»÷ ÄTïÛÜ=)RÍ q7‰ôC’£RË2(Y¾ÃbrJòš Š&JfÊÆ*úªjGäÕ0ê,ê_°½šµG µ´ÃuNèÓÓÓ—52D®M˜4˜–™¥š‡Y¸ZêX‰Ysƒûa3dÛhW`åàpüÐñMǧëÎ']]®/ÝòÜý<4q\¸ølOcÏm¯ÚAÞ Þë>̈́箾²Dñµß-ÿp’!™‹ü1 8Ð5ˆ;¨‡r!X-øGHq¨SKXs8%B,â]dÂ)쩹¨ÂÓÖÑtÑmgRϺÇHÇlë=ŸwxQ=;|©ì2%îh¿1cEimbãΖ5ÿ»{uO@)p“ »ÌïP@@4 v–Lبxp3€£_X ð{ÿ€ö&°È#€à (í`ü‚ñÀäa0_Ø%ØMX3ì#l.ÇÂÝàgàEðVø‚¡€pFœG”#Þ ÈÃH7d²¹@#JãH“JÓB °¨T-j…V™6Œ¶žv‹N.‘î ½0}}# ƒ;C5#=£;ã#4š„îa’aJcZgÆ1÷°h°ÜcfÍbcgKb§cf_æ q|ãôæœäòášæ&s/óœæeàÍâ;ÈWÇoÎ?!%È+X½ÇzÏÒÞ!¡eLÉ>'aVáŽý±ôEDD¯$‰éРНJ z"Y"U(}_¦Y¶ÿð„Ü¢L­Ä£¼WEDõ4Ç•ÕÕ5´±:šbš3Gi]жÕÓÙÒ}§÷H?Ëà´!ÁÈÎØÈDËk¦b®a¡eiheeíp gC²¶K·/uxrüã‚3«‹¬«[”{©Ç î©àå{¢Ð{˜À{ÒÖ7ØïÏA²'ç| R¥¤O…†•F0GFúvÚ1ºã¬vLÃyÕ ý±¡—ÅãFŠ’RÌÒ¯g`²®íÏ=œ§[à_TyQê}ëó]ÿûðÊ‚jšÞ:|ý÷›§Zö¶&·£;³»5zgû+^]òv‘û8þ)øóüWëo™3M³s= —2W|Öd ÿòMoêüÀö5`H ”€0 eŸ¦³ƒîÀª`ƒ°e8üÜ/…÷À—{F ¢Ñ‹ØFÊ"ñÈLd Šæ(M$MÍ:ê* ÕDKGkE{ö3Ýyº×ôôgé‡ä¦Mï¡ÙÑáèOLLÌrÌe,Â,y¬{X ØDÙî³Ë±?àPà¨ã<ÊÙÁeËõ‰;ˆÁ“É+ÃÛ·ç‡ó è |LÝ£ºgro–éÜ/l¶Ÿcÿð‘`Q½ƒ|çÅ:ÅoHœ;„—4’R‘6•!ɦ®”{-¿¦È«¤ªì¬­Z|¤CmVƒ«­érÔC ¯}BÇO7Lï‚~ŠAža¥Q›ñ°É‚“¹˜…ž¥—Õ%ëÒc6Óv¬öGÜ_v|ä4å"àjévɽ ‡Â›x¦x {KúDº|QD-¿ÿJÒdÀ¾@Ç Ê›¶P˰¤ðîHô)³¨ÄÓÝgØÏ:Ä䛾 {±äýerÜç\âx²*]ZÉû –ÌÞìÌÂuí|¾‚ù¢¾âÇ%wË*n7Þ}uo®’«Já¡CmhÝÕúò'ͽM£-ß[7Úi:Y_ôˆ¼”è—”­0„}§ýÞhÄú£ã¸Í„ò$û—‘©«ÓÚ3c³”ËóA K–Ë5«\käõŽ Ì¯Í®üÃà‡Ö¿9ð‰à>èËЙRæK€UÃÞÃiárPæcáUðКÇ"Ȉ"hÅ3!õÑÈzä: M8Íhµ£ÒQ#´’´‘´/è„èBééé¯Ño3ø0 0j3V¡ÅÐL‚L9Ìæ›,ò,ͬ¶¬Ólمٟr¸rlqré@k;G“g†÷:Ÿ?Š¿Zר=ð=í{ã…L1œ˜ûª„“÷“8ЉjTSW’P=¤!‰•Òv•É–})‡—V°Q Uºªü@¥_uAM@ÝP#[s”YËOû¥î½Û|†iÐ96ÙŒÛ<ßRÚªé˜Í=;f{ŠÃ+Gu§2×·ÜwO²×ºwÿd)Qίš¤L® ”ª– )ã‹øuŠ5mq¦=Fý\ñù¥‹º±—¦âTãÆ“T’“S~¤Ù¦?»ª˜ñ0K%»3—»—W [Øpæx¶$¾LæÖÛ;çË%ï V„>`«*{¨XSÿ[WW/ùWaƒDcW±…ùÙýçfm_;¢»ø^<èÑíî  ,{­õfüí¹áƒï[FìFÇÆ<ÇßL`?_Ÿüúõà”ã·Èé”™ëß³fãÍÙÎË,Ð,ô-æ.9/ .­\Y5^]]»¹nµþëgé†ÙÆâ¯¬MµÍ‘­jþwïK;w ‘ˆ1ÕÑÝiþÿ=üˆÁÐl§°CO´?Îܪ©ø+™biÕÜÐïgPÈ1=¨f…Nµ¬'úF¿1ÆÓCׂ/á£ca4„MOê[C²s8éal afŸôò·=ö›#wî¸T™82E›*Ï á\¯ ½?2Õ>6ö¿uŸ[ÛBø$3èK2¡ÊS}­yzéþŽ Žô'š›B<3œ“@1¢ÆÏ a  <@ ð^@ ˜ ûû‰x Ô&A½^ ’›Ø‘û#e·Ó&ü-)pbÇ^ÈŽŽ/˜„tüÜ1­]ëqÀÿ#{GvJöן֎GâŽ×?&Pë¿™]K»Ñíö€'$õ‡ÇÿÑ zö{p"$‹~ÄÎ)Š”ƒÎœÚH $© 0Hn$?B* UZHM¤Ô§Ú3S;ów,»cƒûûM 8¼@ðΈøÿÍþ/¯€}ÃØ¹»C£ PÐÜÈ-§¢Vbµú¯Bñ £P 9<àíCÁhA_.¼$1FþxiIŒœìayðja™BÁžà pHYs  šœ IDATxì`G•ïz³%Kî–›,—¸¤@B„$°„À.»°»”PviË6jXxð¨BÛö-KKBHoîÝr·,[½ëýg¾¹úts]¤HvlklݯM=sæ?çœiyr6îÆ)0Nq ŒS 'òs¾9Nq ŒS`œNqg„q ŒS`œ‡¡À8H†8ãŸOþþþ!ÒÏܧŸ‡x<ÄÑü󽯯ÏCÉï!’=NaS`$‡M²ñý=Ý6Ð?`ùùCÙ'ýÌ}ú9‚[¤^ö3ïñÁïPß <Š\qǰ1ñë8Fƒyã7£AÆS+² H‘´Ž†_Ú? Æ¸a|Çs6øåååù»ì°¹Ò#_ÄQXÛt|¹ÂŒ¿§À‘(0’G¢Ðø÷ÃR Øð Xáòòóü Àåå Ékÿ6œŸ£ÊáÄ7îwœGC¡úÒÑ„÷3N„€V.8öõ÷ú'@Ô%EIž€c6@G®xÒïâ}ž°70ñ¦¸Ì_oÖû´Ÿñûq Œ„ã’äH¨vЇéíí±Â¢ ±¨2ó2$­¿/øк»º »eÏÌË+°Þîß××ë*7juOþ mÀò¬°(ßß XeßÔw¾—›ž$™ò$ÕLFüp.újüiœO‚ã ù$ˆwª`ÙÝÝm=Æs—€®·³C6Á>ëî鵸ßÁq÷îݶ½a›õôJõ¶h:`ÝÝ]NB—Sx‡]±ººÆŠ‹‹Ï€ÕΚeÓgÎt ^qæYV"à €Yb…ùVTTl%ϲb=k`§¨´ôT¯šñò"ÆAr‰yªDÕÒÒl]Änkok·ûî½×}è!Û³w¯u (% ¼ ­¼¬Ü***¬K ˆõ 4»$QV”— (ó­C`Ú×Û«ZÏ`ýiëh÷Áš’’—.{å§´¤T@Üa­m­>(Ó-I´@Òdqq±Mªždg <Ÿqî3=î²²½/±ReI™þãnœ#¡ÀqI¤‡¨.qߣ†U\€8!õ«¿@ßú¤¶±aáQÕ}“ù-tÕ.­uÉË0#!ʉ&× J,Kö·ìçlñ;R"ÀÔÕ´Øa¿¼ógöð#Xkk«ƒTUuµM²¸IK!ê1àW(©®G¶Éî®n­^©Ö]]ÏRÆ!’¢‚q퀤ÄÍÒÒ2I£ÝŠ·×Jr€­Ç+I²GqæPå;ùí‘ßÎÎN)ëy6aB…­X~º]|é¥V9a‚ÀºÜJ•nYY™••W¸Ä‰ÔËéP<ìÈ—C2•<‰¿²M¹â8ùß©>Ôvq¿ >¸S§˜'“ õ>¿ŠOdZáY~¢¯êµ`($‘ÓËqÉÞ>‘&!Ì CC¿0R؈È7gº{ûó­0_“”U¢H)('XI©Ôt™ °y2Ç’2aÀ!¡z:â»CÍ¿"m=Ð)ø¡ñ~h…3};ÖÙ¾;oµÖ‡±ñZçžV>wº™ìÉe ê¬æÂZÙòsE­Ø~u·z‹`"Úü±tÇ$!b~^ŠN³¶•¶®†Ö½iå«ñΜeEÓj­¨z†•/}šÓÅ¥$=J’Ž“úP†QÐcI¾3-TR$¬¶ÖvûÑoµG¥>wŠqkgÏv)^_( GeÉe°Ñ;¤„lw(D,).u‰ûr@Rñ#1dÙ®],à†jÌàN¯ÒÂ>™‘$³@²OƒA€bë Õ’IGì ¨›ð¤øØé_¿:\FÔé &UUÙÒ%§Ùe¯¼Ü*«*õWm+<¯Ä›½ÏÎ/ÏãRdŠ*½+,I½p–ÑœñÜ–¶ï†ëìÀ°Î†v¯u½Þá–.ª²ª αɯúK+«ºk›¶Ü AòÛüÆðḀd(T»^Ù®¶Q"6ÔÆ’IÅVº|–U,_b“_ù«˜_oýy%CF{ ½ÍàÄå1¤Ýq:ª5¹2’ý ÀhïÐÀGK‹ÝqûŒ9@Í’4`zƒ D4t)ÑfpéaÆ¢¤@RØ‘OȪpŸj¸‚ZŒ:Õçàæ ™±IŒêv¬çXŽ!êvÉ”MÒÕmIx7i¸uNÏäÐUpT"VBä^‰£<ñ‰7_ª ô™\3ÙV,[n—]þJ«žTíCÅl$àbtÚ¥ÁÑÕKåPRf:ÜÉ|û½~Ù£¶çåíQÇ嫡΋¬õ7·ÙÖ¯ÝÚîßåÝVž:U”_”gÕ¯|†Í}÷%$ÍMHE}JºW½bŽ;–î8d¯õ´´Ú¶k®¶ÆïþÆú»Chxîô_’oUçÍ·‰ç>ÝŠWœcENì…4†êÉV2©´ðò á2q§ººãDÐ ¸Gji«$ÆU«VÚÏîø‘í×Ô›úúzFTJ¸ÒmzºAÄ¡H NÇ„¦ ¤>À>Ôç êÞ]‚s`RzÔd$±eö„mfà ª:{(I’øè¶Ò2psI2Ú$y1Ë®¥òQ¾` ëäŸr Ê–)?” p¥¼Hª¨Ó.µ&#÷sç̱½èE>zÎ(z¹Tò‰ú+V~‘OÏ%ŽS E`§e¤õ?à|p6O6G™ÎúÂNíúÞWm×—¾c=û1«.„íʧ—ÚœO|Àª.|™^' ™¥zÄcüs\@fZû¶+­ù—ëT<581*dtRŠ‘ó+ mê߿Ȧ¿îmV2µV_Òªyê^½ "xo/¢y¨”1¦ÝS6ú.#ƒ.m²½}óÚ¯ÛvÙ§MŸîƒ.€L€Qj¤°@]u9L•º"ÚQo°é©† °n€wþ-tlÑîÇûC©ÛHªÅE$ÝNܸù$ÄšùÍH’šºÃ”"ÔiæLÆÑm·IJM"IЧP‹Ù(IÆN3‚{ȰQbÛÄ`W™Éc§@2_ü÷ðL'AGÂÔ%q^íû»7¿Å&M™lÕRÏ++eÃT‘0³%wüýJ ³Û‘ø58ÆØƒ<¤ü˜µ¬¹ßÖ_õÖ³­]ß‚ì߯ú,)γھɦ^ùÊ0ó%tæÇмÇ$7~èm¶÷†{ŒA­~•¦ÄÂEÑ‹kËlé7¾f¥‹V¨qjtt ÏŠ4˜ˆzˆÕê4@ò>û™w§Š±çÝ|ÓMöèÃ[¹F‘'O™ªŒ½6J‚¢·T¤:ˆÐi9hJŠƒt^¼GŒ|À"EH@ÁÌÙ5‰;‚$PÔ_­¢ÈŒZ¡Ãˆ4Ót¢ôÅ<É ÝqÂøŠ”¼äKfž#÷äÉ û!j< F\iôü% É  íÞä@H’PüЃ8qt}zÇô&èás3U6¤_ÔzÂP$#:“™,&it|ÅŠöÊ+^£ÿjŸøÎ|Pò%(|ü''º¥‰D›v2(O’ÿŽÍöØÛÞl«š„ ÔZ蘋 ólÞÇßj5—_•†rF@KF¼¡÷Þ© ‹¥JwîÜj+/«ÞPÐ…(±à@iž-¾ö6éÙ—8/‚+Ìp ³`BF½ž¸#*Ѥ&÷„ÞÂE‘b'F·zëuW¼ØÚ×5ÁÕQa\ˆ¥Â-¹öÃ6á9¯ÈŒj¨D'Q Õ`coè™FŒT„…4uà`³]÷Ÿ_·R©ëë I´Eâì—ªÝ;˜¨é/’€€†‘^æ>ª.<•ŠH„Á%€( ‹Õ.ØÊ›6M6os ‹!¦ø°‘cÀ§—ú÷FX­ÁAK‘†žXa”G^p4(†29€¢IÔðÙ;YQS”+ï)¯ ÓÝSÓsª3yRÞ9ˆ¦.E*3Ä]oÍV²ä%t"àI›z@õ4D ï±ùsçÙUo‡ÍYcòä7m0ÉœòBw÷ oºnã}ìÌÒuN¹O6— ’”?Ÿ/)^iüùlû>-̈%WGN=Ì(³3n»Ù &OÓu$ÂJ_Ôhž«æSç D­3†}ò×1ɈèÙÄØñõZÃÿù¡çZ ‹Å8*&rÚ‹WXÝ¿óäKtÅ@£ñÆš*S¿$¸NöÆk¿þUk8.嗆Ȁ “¸œcƒ£!‛ M&*Pð‡ÿ=$ϨÊ€+YºŒåˆÍÍúÓp»€‘Iç¨÷n³£6àÇŸ£"×ð4øèïÿ£,¸®Á…PÝúÉ«<¤¨Î%j:L!Be“ŒR ’"°OD—ô m;¤^î¡ß¡¤H€“ïH‘ø¡nÈ #àeÊíêëØ›ßúV›5k¦MÖàâĉUV\¦Éч ©hFú±Žb%?)/ÂBï,ÔÃdV91¯_S±LlÛ>ùÛñ?w‹ÄB½ë­ó¦úågXýçþ'„eúãji&GZ-5RBŽ Hbsˆ¨ÅêžÝ[ì‘]a½- ?R¿°Vnθ㿬xáÓô^#\ÉŒ{÷p þÄN&»è4ΖæV»Nƒ1[6o¶E‹»äƒ´‚ú HÐrQ5‘¤¸âht4@éŠÆ‘lx¯O#Eýîèu¸ŠÜ©´šmßþý~mnmH¶0¥.#F0L€Ìtü¤©¿ô3ùŽNøP$Š‚0á)ÊMXÒ–%šÚ CÏ€(!ÚT^ÊÂ;‰˜ PXÔÝ E³D´“"}SÖ*# [Ð?š)ôZ¸`]uÕÛlÖìY6IÓˆ*4ÐP§ë6ÒÇ©Ž”5:€‡d ]pHùyBÖƒöÈ¥/¶î}L ”æ£ÚB§aåòâoF3^ž—H’A}3µ)-A´Ï/Ýuúc’Î õ ìº5±´HCþÿíMÖxË}õ‹I±ø™xî,[öŸ a >ªúù¿DÂ@c#‰_þâÿÙ/~~§Õ/Yb½.ý¨1;HA)ú\M\@}Ë)Mú'udF¢Mq£:8pÐöíÝ#þ KŒMØ©§Û%OEùå:Öîpé¨  €)¾3—nh`&­pc‰b…Öv³iÏ&I.-ªƒq&é0ˆÃ{Tm$JÀè¡m¤3þ¡›''~É ^`/¿ìå6sÆ DCªep(:ê–¬˜§Xf€RôBÄ1úÍ(øÎk>d[¯ù‘ЏÎu®ªäÙÄóçÚiÿ÷‡Ò˜^$ó‡T8ÑpT=RøÉ_Ç$©p¦™ô¨°L¾íػݿø¥6Ð8º”Zö"øV÷sß…MÓmOÎàO¾p'j a=k˜¦Cmni³/~öÓnçb5:—\`ý‰ÜêdèEQÛfúƒa¼±ºª¦¾Äi=¨œ¬Ïnko³]ÚÆl¯vðij>hûƒt¤H¬PcŽ>Æ¢=áz8à|‚ç/È?œØùŸhÃ?$ȉ­.0Å«(.Ðr¨ =PÏ1GŽHæq Z3ƒÿÐØ¡L©©±w¿ç½6oþ\›>mºM”TÉ€Qå÷“Ÿ–éw'Û= &re\ö3 u÷ÞmöÈů°þ.ñ5u¿+,ãUÏ»\š”¦ü U$LÊa‡æ:ºnL@’B3ò¤‰ó>tÏ5°í_ù‰ç<–‡¤c°¥?¼Ö*–œ£^]½‰ °cÑŒ.ÙÆ66ì\¨omR­ÿû›×ÙæÍ›¬Nê ˆNã ]壃øò“‘Hä7J“LìîðA–vÛ/5zï¾}®NïH7*îÌôÌ£UÊ' p£•t<˜Ü¤—OËBÂTT)ÀD² AÅ’%I øéXP»i¤½Éè>qº)º¡fÓ†yæš2(Yàû Øâúz{ËÛÞnµµµ6}ÆL©þš3ZžÎÖ`½ y{ò=dw°mtT&;VìlyÇ_Ù_­óOŽb&$ÆŠ§Ï²¥ß¿]U¡ ØôÉhYÿº¥$˜Kb|Oö:& ‰m W…T¶5²×ºä"ëÞçĉ)UmècÚ§BCûùvÖ}¿·B­í¥°'ûô‡£©0Hî¹ûn»ýöÛm¾eÔ >Z`¾Œ2HŠ<âhŒeÀ$¯!!©™zoL F¢YÅ0îÞ½Ëö5€d‹"sp$ž´{*[:£qË%Ë –kô\O©æ˜NÐNA€%j9Ž'»ˆ?(E2mJb Õ#20ä£ç"g¨L* 鈥—¿ô%öüK.µÚ9³­rb¥46ÔSœ‹±†¼O±Ÿ\e…FIaQH¿í¼öS¶íÓ7¹Ö‰°_GSÝü/¾ß¦¿ø¯¼S8ãøÇhsŒ@r0›»o»Î¶þÓ—U4øHRF;›¹šÍJ›Â¥vöÝ¿KHpÖhÕh^ssüï2^*+0 Ž©5í,ùÂç?ë ]i\ºÓ·0}‡f…k˜É¥KIAÄ HÀ ;&;ÞìÖî>;vítɱYöF±«äYÀHœÑE‰ÏñJ{?L°è-sñd_3Æøf¸é:«›-A+FÇY†ˆt Àa»d;v*\Q¹0"ýp¤^Nfà|ZþõZt±!p £ª+Ü®»îšÒ³Èç9#S`˜ÅÕCEÂh4çŸýLžøFãdÞb³æOî0nß±ÃvíÜå#·nTÞp!6¿Íù|…´ÉC|¦‡ãb8®”<>Ç8ÒïÒ÷ñû“½*Ý\ñzúPyy¢­·Kôò_„tÉ€O‰ïÀH?¼ë )’º€DtVÑy=ëÙ'ðCÕÑ®={ìŸÿí_ìïßð·öìóÏ·)ÊÉZîXQ¢Í?d¯Ló á%^2&’$³˜Êë—zÀIwu™V¶ýa³u4¬·²Ù õ¨¹’}Aݱm%¥ÆiìE™¶2FØ}˜,ö§€GŠ·ÇçvÚW¾ü%­ši¶)ZFHCsiF.ö¢1.ÚÕ¦.ÇU¦=ôˬÁœEF¤wîÜiÛvlHî6æU2g2J¤1Ž£¹Ž6h…|‚%°Žd œä-vúþpù>Zé8ކ<“G¯$=Ý#U² °Ì\²U'}¢5ª8®PR$ìlÂD$Éßë‰SØDUŸ'µûÝïz·-¨_`•š.TYYéj>qDÛ]¼òîdwPS˜íÀ‚{Ï:Û¬UÚ‘zkH½…wÎÚ·½Ðf¿÷Sxöí¡øhiÀ#£ï€ìؼÊzwb‹Te+:Ð3̓÷y’$[Wý‰¢…|ˆÉN—–(S=‚ s¹ïÔ •ý[ìß?𯾔mÊäÉz+ʨáÑ |›HL(äê4L¤Æ%6Q#ÒR®®vÛ!iqåêÕöçûïÓßý:tk»vº¸É€LÏp.é‰C1ï•ugz$)Öd+ó>ªΞ)ñ)1N©VÎpåDDhÀôè肃⠞Ã9ò{h?¢kŽðG*#}9ê4Xµ©Þ­Q6^V¡&Ó0>ü¤ÔÎç¦êe§ãŒ;A¼mÙ¶ÍÞÿ/ÿl÷Ýÿ€íP½57)^i¾™´Ô{1â @Nv‡å“Ä–úÅÃÚ%ŒÉä^Jø!`‰ÙÞ_ü^t׳~Æ5F—Bc"²Åž cýã^gÿQ9U:zì‘à"*ø¾ŸÜlN??Ts*OF óôŒ4–V ÎüñO÷Ú­7ÿÀêæ×ƒ¿Þ3‘™†æ.ih¼PõëúA6ÝË/s™Ó¸CRãFM.ß¹c§7BâÏVhbGÒŒþâ•wGržM5â"5h¦¶0f℉®šN6ÍÍØö‰ø|íµ@ž0™`à˜Ým¦’ŽY¦Hj”‰ò2Ϥöƒ¢_{{‡Ïˆƒ%Ð-C»¬Lg:½?:¤ƒGsCžnÜd¡Žþe³ Å8lŒíߊ˜„. íU&"q”…©AhêPAùÅlÂ& W_}µ]~Ù+ì…/~‘Í«›oUýU’X'¤j¢Avç뉜d?Ð,?Ùó¡eóZè …L„ÞTf€{ÖµXë†G¬|Á ñ-dô!môcT6iÀ ]÷7p ¤P ÏÓ°F[æ/ …æ¯ù—÷Zß?…UÁ«—'°‹ •m“Œ*ÓÍöµ/Ñ'lÏÓš_6€ ­<)¿ÞñÏ{PÑp„CX.ˆºS€±~Ý:ÛÒÐàv3q%²,_Ñq@Òé<™d¨yf0‚Q_Ž<˜.d“Úb#àȶa\™wÈÁ[ì ÉI‰ø$™]¨H¸2/¹TœÒ  àƒIÉýHÊ¥8Ö†3*ïWLšX2»vî°­ Û|³ùáœHŽx¥|Ãu1L,¿×ŠØW ¯S`ÍÈ7e.×”êi5ZŒ Ü0Eˆû_¨[L%Ü~ðÇ-·ÿÐxð{ç?üƒ-Z¸È&O›¢Ò+½s$ß'Cû8ý9v…6m¿û™s=ªv¾À¼À–ÐÇŽûî¶ÊùKĸÚãS1£êÆ$Ùé{Ë€ŒÐ4jrÝ«žÀûS˜Ë  1:6µØ¾ïɦ¿þ=‰¸<&ÙUÂ.²to™?4”MÚÞmû臭¾®ÞŠ'kj‰*Ô%]‘.KW­D#aM ‘çSyPó¶lÚd›·nµý²ArÜá²]»øIQf@#Ûoú9‚‚‡§úÔ€ºjíp³°¾^@Pá°'Ê.7Qö3¤–ýùvaR™9\ Uš©-€ k¨FRL«Ñ€$ÀO¾ OtŒ¼Çކ+¼€”˜-8Û›.FïY)Äñ¶AªÓÎëÍoÕ†Î>x%ióû½[å™8UÝH—xéî³—¦%¼Ý¯uÆ}2 èC{Ÿ6øPÞ°YrZ£Ï ð±KöŠÄkI~‰'3Ã@Ð@ë-Ûd‚ù€ýû¿@@¹Ð—6b«ŒË—ϓᛃãšî¶ÿÇ?ñà›4ŸWÊ€¶V“ƪã"@Žþ˜Æ˜ QP™4×lμPg0ÿTXý½bäPo¶ý«×[Í‹_gE53NøzÚ›±³Ž¤ ­‡¾ç·¿³[n’z]·@]•©JF•ƒ)  )^i0±§¤a¡jÔŠ˜ÚÐbr—g8ÔåÒ_œÜDt”ŽÆZ!©ˆåt³k5ŸO`X=©JGÔHr¬Ñ0U6ó˜eÊ]µF:,c×qu’€$£ð\€ôR¼Ce!JÚñšË_¯@‘‰ÜHÓ,t©R´4ÙͧCe§ìyÃÐÒÚfgéòa{Õ寴—½äe6gîlI•ÓeŽ‘½6$}RÿB›¶‡þd-îöv©ò½D+•ÜR7lˆÑ£y¿`íi,܈F·Ó"8*ŽÁÖ¦R›R ýøÅj¸õªR9T† v3W2Øu(V\…3E:ÔU IDATùUg[ýÿºÎÁAʇ>„òC?`úð{ ]ì¥3- .ïqñ]\SÞý~â[ñEÇw·EIŠÂÞÔÖÖa7ßø}{ìÑGmÊÔiIc S„2a¼Á„¤Úv?䙼s ÓxÖmØàF~T;ÒtwŒ`®¤˜±ëö­Ÿ$Éqª“¦L›j5F–ª&MÒž‰U¾DÕ’Aì­l 6hw…ÌŒ Š88†Í’ÓÙ¼¢M@Ù¬Îå @²i“V5ÚI–¿¹ë._ŽÉ ŒKyY饓¶—TOÆWîö°*OBêÎB@Igf ŒÁ”àR­"…æ4n´:EÏ‹ÞS¿Qò}Ö¹çÚÞðFí]¹Ðª§Ô¨Cš¨0’<åOr¬o#†ú.hQƒ£â™ à&òuì´âó¢Êd°…6„‹ä¾«ÍVýõåÖö€fh¨2q  "U/´%ÿySðàChƒ2Ù¨-•ˆ$¡=œJ<õeD’$ öIÅ`Ù¡OW5ybšõ¨ ÔÒBeA‚…v~¾íúÊ5‰\Õ;ü‡7JœB»1Vß÷ß|¿U¬ø¢Í|ý»å3:0€âf©RØ¥üðå‹•}¡òáb%G@ȳïOƒ?Pâ'ÆEø_Œ‹6RÌXëû_߸V›Gp°i„IÇAXÞÓhøCëÓüI&oظQÒãFkRìuc¨òC9Eñ„†í7R8_ƒ'“´a,§"!:0NjÓ$¹L@V 'IŠœ0Qkœ±9JzÄÆøTsØ6QÍ«%í⪑6EG¦Fu´ë¯Öf;¨zØ/ÉrÉâŶwÏ>M´ßm¿úõ¯\%§¾UîÒR&ï gtý,ßtW­ÖÛq CÜX­äU† ç@þI«ÛJ5H‘Ê@(|Ÿí¾ý;Úæè:ëÙÔš¡óŠš’áüU*êwÉB„R«g(²ù×ü‡Õœÿ"¢•«^‡SÖŽÆEÂoú>2DŒ#ýŒ?TœÓ2ñ”ÃÇw:,SÀXm­-öõk®±K´i0Á÷wT:ŒÐ¡^¹$¡¨\’-G\-²©mݲÅÖ¬]ã#ØýÚé„Fôd%#A¥$ÂË—û¨ô 5¶©Óg„­¼´£vµ§ú„fæ.ªQG—¦W|w¢^±ñvh$y<`¤Šïf7$­„ázûwøÎHL?ÂÑPqª¦Ì}xs¸ßˆú¥¾±I²›z˜x–pâ¤ÖŠ—ÊŒ¹ƒ>³gÏQ‡VaL§:óôÓí4ý±A†žÂ­‡ò©Ó§LHúØgÙ<£Ye«T<ìàÚíT;Æ3O'Î Û¿ñ\¡‘YÌPˆ y¸Òü›@XR]ÔäX§Í'\Ó]7ÙÆü¤õw&íDô X¨ï~ÃKEè()Åv†Nµª©Ê³vòˆ+œŽ€¶ëšªÞ¤ÛµÚ$ %՜墦IÍ[6ØÆŸuü©Á¤×+“ôd›gÔP*@’—´}À1J˜z«—ÒÊB[pÍÇ­úY/ ¯œÑTtGÊÎÅÆœ¾:£&á"³GôÃ=ƒ"ÓgÕZÖMÚ|`®F7ÚMÃØ¼qƒÍ_PoÛ\sæÍ³½jD“¥Ž¢ºUËV‡Z–²"x·K­äY=|xßoÛ¶îLv—Ñh·Ô=Y•y÷®]¾ãøêµëì÷ø½5bGSƒG(ËA/¾É~Žï¹²iC¤ÅeK—jùÛâL5¾Ù6C;h£RWiô´Zàèj¡À1­ŠÅòO”V¸?Q ôÊ<†²­Zíä+–DóÝ¥–snÝÖ`?ùé¶M|áÇ>(LË£/;œ/§€Ø)Ùên’LóæÎõ êøúðeê´fΜiO;ûò,Ún½ÕV­\i§vš­\µÊ–ž¶Tו~]½z•-–=y®§-[n«W>.ðÐÌ€½ L|hyHÙ±ß2U €õbÅ»aÝZ[¶l™½êÊ+=ûñ'Ý^â»á_ÑŠ¤‹çãäo@sß¿e›?|M²º†XÊ3òTdwtöxz,’–ÊÔ*‰¤V~V­Mºø"›ùºwX¯F»N„N.j¤¾[ÚÂp܈@ÒAF›êööI„-P¥þ¶¯ú£mxó»¬s; SõIE •WÅtÕC¿ ̃QÖËŽÝã [%*Fʪg^"b2‚ê  ÏÅF>XÁV•ç#žôªë׬1¶#[£+ôÐ[·mñÁ‰ƒÚ„v^]mÕDí9͆íÛl¶®;5¯N Ù Ð<¶n±ºúz«UP3g×z£Ã–‡ÚÆàqš˜|ã>ù_hÛ·mµ¹óët§êl”Øë§A<æý®_ýÒ¶KlضÍ6Jýn—Ä@ãÅïnmy†cú tK;$‚éš0üTû¬ÚÙ6§v–Ž˜e3fÎÒ€LµOãA Lw$ÄÍ wvéØŸxóûÄ/O7±,ÙZÏâ‡Vzd ÞÞÀº÷:’w‡ÝzÛ-ÖÀŒ‚D²<\iPïË%M‡Þ3gØœÙsítI/xá‹rœÏ\“¦rÑÉÂ_ù»A¦A‚ÚU¯Ôÿ]’8‹µP`‡óçÔ³lËÆõÎcëׯ·Ç~˜J¸¯mܲYËçˆw·Z­:zÂͯíÒ®OtxÔ-Ž+|³ˆLÔV\·izÙ9çœc‹µûýs.¸À–,=-é8á¯(y”#ú!}$¼I‘:9q÷—ÿCÛ)ÞNÿ <Š÷+PäH$Ç€ ¼¡$¶ô+8h€ä t(™Sa ®þ›xÁËõ–ª´yioâeXÿrt?#É5%z~óc÷؆¿ýGë=ˆ½0T†X’< ௕Y åâ¯7f}§pTbi¼ã™÷…’(ë$QNzö‹Bá0z'£ÞIœ—ØXcƒˆW<7Øo?¹ýGêWùjŽý>ò©c 20À‚TÁ¼?â‰y¡¸§çeÞ sïÊå§Eª5ªÑ$Q›Te$Ÿ\,u‡2À„¨­€dUe•ötlµúE‹¼qpÚÞ¦m‘zÿÍ›6½øBçÛ4Þü:¡­T¼LÐf¤¼ZöÂvÙ̪¥Æ8Ðä U‹†I^Iïúï~OÀ~mÖh5Z ηB©{ŒR#1ÖΚ!•ZG h~#’M68B£4½xŽôŒWÞårGúž+ÌñxÇÌ ¦Ód—“¼ -wiFKJ]Ý!°d¥-³Ûn»Í¶ 8Ef«”z:S*ðìÚZužsÜ„qùkÿR|ªSüDsê Rõ½W@…J]’8 ”îFÒÞœùóm:ç2©Ó¨ü8ê¹U<…jÎÔ%ý˜˜O‡Ký2µU£öÓÂŒäÇ%n[ï²!³$yÎQ§ÈZþùJ‡ó×ÔÕ¹‡ƒË¶i>æ™gœa«”~­:M:¦y5Éѥξ˜¬Žžóz/Zb—¾äÅÒ¹ô(AjåW@„y§Åâµé…-R^½]È43Kæ€Ód®yÝë_O6Gì ³WÓ>[óο·Ö?7¨ŽM±c‡ü¹v©+í4N¤½ðLÀ4y¦öÀLw½Ò< „œSÿú9V÷‘/¥òéð¥àC‚¤W‡K êð!oð :HJd›5¯{©µ=¶OY … 8 ¼#»¨Á¤Of¼'Ð5‚_ÄØP¾Ñ[ÐKÇ{@’9–V^`õ_ø«¹ø5xÍH6ÚÛ]>Ø~% ä5Ž¢Á?¸ñ[%¦…©Ô²/Ž!íR/V©¼nþ|ŸŒÌîÓ8zäØ`üÅ!~ze4%œÁhP¬*ɘ&ƒt:YÌ»SRÄ M¥A BÝm°2A›ódHg‚¤9쎀ë‘'IòØ.Uk¦T%Àpf… ñã_˜IaŸÔlâÚ.ÉfÁü:›®0H²< u ¦^ýJ6¯5*ÿê .y¾¹Åí«H¡ä—ÁŒþa?‘nhÒAÓñ§ßä>÷€\=Ø@£™´ÄÄ…¼À”£Žÿþ4ô'ð~˜áÀ—¨ŽrÝÞ°M Wf¿ùÕÿs~¢“Z³j¥@IƒZ»½g÷[#óÍ,©¼{T÷55€‘N‘|PßÌÙœ:uŠ×ûdÙYlÀ\X–¨böA]f0 턲ŃÉÈ ùŽ.]ÆÌ»Ô÷ìwžÚ# )Ô1¤Á7Êßs¼0Hª¸¥e:F¤ÕÎzÚÓ|PoÙÒevù«¯´Q–T4wµ³ùëѳNRüœ8 ÙÉ€MËšû5@ónëÔj;ðl;6(ž¨}ê•Z×à/K³Á ’òÖ®@„ šiHßãÂOü¦×Óþîb«û·Ï»„;Y†3ù%ƒü~ì±…ßœ éüÕ'ÕY§ŽybÚF‘åAB„ˆ¶~ôm¶ç{HŠ ªDKFq>ñ“@d$¼r¿¢˜P^•ãD¿â]ˆãõNŸ\ŠD쎯 4+tþgþÉj.}*‡Cc "p…Š #n˜ÕËЫ |¥ÚÜtýõÞ»ßõÛßø&È¡ôÔóæÎQ:a % Z<;HRk9\š1a(F±¢òøœ5J¨ÿ±aÁ|8®‘Á3‚W…EBôozöF!p8™Ô½EvHÔ²Öª'ß©IåL×yó ÄË®ã¥dò4ê?Ò*I×Y’Œ·K­ZPWo6¬wc?`Ú"ÉcÑâ%>@±xéi:yq‘«t¨‰¨ùMRÕ±Y¢€PBß¡E鿯ìA6^“ ^/‘⻑^³ãŽñxÝó ºRi7Ø(‚„O¹"(â/ b‹¤ük¥Š2 ÖÕÙm›Uk5ã€Iô»¤~¯•D?Wy[·luúPwS%ýc™:e²KˆH¢¨¼ ;¤}Ì÷:_¨oŸ@®)*.% $òHÌg/Ôuxž4²] Ãû4ò ¯¥ß‘}cñ/SŽà—Èû˜“Øô©KÊ+z‡„¢ Ò¬Z%9?ï‹léÒ%öš¿¼Rô/ˆg1S08EšQkA£Éó‘M Ô=ûƸû'¶ñý·¾F¡rûÀ®®_Æ)ô!K”] ¥Pzƒp‚xã–Ç€“ÀÂã ±Êÿ¼¿Õf\ùÑ"UO:S@1L= ´p³ùó ÉÖLJ=t¾Þ3{n’ˆÞøÓïÚÆ÷|Ö+; 8—U—^H瀩 (¿á™wúsuÜï Í`1QËuEtv$ÕÕoKò­þÿh“/{£W ~úï×N!ùE4ˆœ}b>Fð%m}åË_±_ÿúW~(i,^PçÒ“§$ ÕP"¬ÆK3Ÿ¿ä}¦†0qäÃ¥%á¡Mt™ç¤¨<ô0> K¢})ħrÉ`àyIâ#t¨iì®ÓÙÕ)¦ÔHºâeÉóçÛšõë]=B-’ý4?_þÅäH6œmƒJ†5‘]²d¢¡ }VOª‘½µ]vÒÓ|Pj©¤Ñg<óYj ¼¡ÖLÆæ*ULi³¼Ï¤7Hýhü¸lfó—£ð“ Ž8 QÌI*6Ö˜l¬??‘OåSh˜`ÎÑLÕz\›¯•4ÈH?¦ˆËô .-/E²š¢©Rh%}2á°Éá—j¾%&€($ƒ/pНSWTQÜ(¿Áé^~ÂÀ/÷"ïp¥´â;Â…à!çÙ! ›ïso³:yè@RK=$h$<ã:dƒ‡~ÝJ˜e¡<ç{Ó›Þ¤N 6 #<DAb˜Õ!+H’y¶ûÖoض}US|TFŠ»ÐìHRâ5ÂWßCÒ!|@h ¨wr<;XŠŽ!¤ÞëN¢‚hQE¡-¹ñ›6¡þ4½ä¸eÑ‚AI €ýH¹Š×%RÂÄ|é—$AG×Ee‰Èƒ‚8ÚÓÔh]v™uk¹¡ƒ˜"ŠË…¼dÊÏŽWb$ÓôŠÔ3åÌôä"@nñÌwÀopZîù–P•s•jÿõ/mÖ_¿W+y8“„†ªFŠô+Æç˜IÒ’ WKÚ´y‹Oï™PQfõuuª°Ð›¥²£ô`Ð޼ Lš‹ñb#Ãa:qÄ’p0£bQ¾©Œ ø»¤!ð-J›Äéñ„Ìxƒ N—0•†ìåÇÄ[hAzJ=T.ôÒK§üÀèx‡É™ÚdY©uÖ€#¶OÖ4wkà‚¦M’‚0°å È0€…DÉ\IÖ=׉f,I¤¡#Í,xnÜ€TºÌ.~Á%Ú(v’VuŠT¦µ(afƒ™`”~ÒqÇ{ê#ÖÉðÞ¥5z{ÕIÜõž÷ ˆüòç?—Ê¼Òæ-Xdë5ˆž‘e6ÁfŒÝ23EˆÑcÎ!gÎ"ƒs ¨°’Û–eÿóê#a¥•æØ–)X^ÿäCuGýëV•ü§ƒóÀHEF`ËæÇìgÂåzÇ{ñĸx’dàáØ&àø ‚+’$qúÄvˆÆ›[4NËkU¦%²½.]¾Ô®¸òÕòÇbâ|_ô!–vÞýÐxÀ”-Ÿûí¹ö§*©¦cý¢1§Ðb–€!j7ÐG.¨Ñð;Oƒï==ÓÚ¢¤™4†À fÏ„§Ï°7üLÄ'œkò©¤W¶À‘l—$CÀ †rb™ó„†>€„Yh›?ðÛ}ãŸ=c ¹âá3ªu1‹ª¬lÉ\MŸ`…¨Ž]{­gë.ëÙ¯Ñ3 F朘D §GR(â‚XÂô4þB?ò䤔¿oºDÇÑþoù "2Œ Q!-vÍ>gwk¾a·$¨Eóçk¤N+G`P¸9ºä60µR!ô̓{r‘ùIÇ¥¿H"…ÅïÁOú9M(‡ò‹$é£aÑâŶNƒ^쿹fÝŸ3Ê [¹ìn­Ê’¬Q-¡ÔWxèI Þ’Xâ(OŒ—WnÆlèéÃÆç\×´Ÿtœø Ãñ@„/ÑPbN¾ˆé¹°°ØZ5àˆ½ü‚gŸ¯)NËíò+_Ú4ù§œŠšNIè>ônkûõº >°wÀ9’»J¹ ,êt¢3õ »zuÈÐÎ=êÈš/Oh°P“à8•4xŽ÷sÞý ›õ¶¸È ð­ÂW%•æOšŠ¼‘ó‘Qïª(ÉP#xÛ}¿ÐÂóVÃ Ò ‹VæÙ”Wœmµoz§.8K”BÙ àEì‚0ˆ¸sƒíýÉMÖt÷ï­å¾íÚæF…¦$Ê(¢¯”G_ŠÍ½ã{Rhâˆ=ˤç.°¹ÿüa+©?‹×òË´¤~ûê—¾j÷ÞwŸF·Z‰z²¥2°Sƒ=Õ›P¾8#(Èÿ<@ò(ñ† L#ÆÑ=«::…•kʨûlTh¨A v‘ñð¯hý]A¾A?9q»:,ÉŽ&æ;õ€} ”?+: ´ˆËëOrÄI0Ð9œ—|‹i„CÊdÀ)#>ê/{(»î ¢ïÝטÉ“›ëëê5u@€¹ÌΗ:6»/ÿhܨäŠ/–Ï|?é¸"]([žŸ!~@¶Õ 6hFÀz[§yˆ=ö¨ò¤9¯â Ö¦Ô4¤óy½ `ó-½þÅ'Ð%•g¯hMeAdxAôôç”$oîôà|¡0± a @'xÔ/~à/… ¼Ò!©µ±Eö“ÿØîÐ<ÈÕ’fHzœ))Àí¤ £: „¬;8ƒëYŸÅˆ"r¼0HšÉH/ z4„P @¿ŒKV’ <. j™û¤L|B<Fùá= I… [&Æ}l›[|)\¾À©—ýüaÏi’ÚN?óL;ïYÏÿ©Ñ©±Çü{¢#ü6”/ms„§pL½ùÓÿèƒ.¯Àò»»v¸ të™U*š†SªÝ‹°BÊðç4 ì4DÕÕc]yB¤§<à™oÁQið ï©?LS¼†xà/B…kŒ"¦Ã—Ø¡°Cã%Ù¤ÀÄ0$„ .í‡xãïÉ@ñgTm`Pµ=wî—g[¦wÄ H&ÉäÀrÖ žó{ýßhÝ kmÝ»Þn­îø…¶ ^@M˜¸K²Î…7\÷éYàl‘|ЙBKµóÑ™ µõbUœñ41j±•<ý"+Ö€PÇš¬W‹3š~ýsk¾ûAëÒh¹ã’ÒQq0Àð½ŽY¸óû¶ñŸRxe€ï^B[ϓΟk ¾ø-+˜P™Q…`Z¤BÒ÷Ä@8\]ò“ü&ˆK4oØl{®ÿ†¼ëÖ¶æ Ž„`Ö(­ŸBû;îqµïºÌf¾ãvËõ7k5Â*»÷Þ?Ë6’ïóƒØ`RH1¶(k4€%8Å©ÛÈŒ0RšÉð“ ’IÀ óE  é@¦{I¼ç}Æéà6úï´‹ß“ê¥ü_¤ ¾yžñŒ#¿PBïS@Šˆ‚¿ žú•Bqî @H⨯‡Þá ß# "¤ Ý\ ’vOŸÛ';]“NjdÒ< Ž)KL´f©Üùç?Û–¯8Ýãퟛ¥J¯ÔT§Z­nÁ^ p³ÃO±€¯S€>[«Œ(= œé7P z 5A/h‹ t€WèpBùW¼#¥†žúÞãQÌÌx&´¤“qúê>Ò7ÐQ9Qšÿhf¤ IDAT‘ÏHãÈ'߉“kˆãð ésü„ô‡˜®¼Oƒ$yA‰ª6›Çòs…G™¤Î{±&·¦¥É>ÛÖÞáuËŒŒ¥šnvîžÇm×—nózÌ[äJ CKTÅCHAØ}¦‹¾)J+¬-·êó—[ù3tŠä…2ßLšÚ•|!¯c‹DH¸ »ƒÉÖü»;mË|Úº7j3ê=€NU½ôÛŸ±‰ç¾ÀÛdlt­×í§Á[üÍ ’|Œ`ÆùÂV¾êbkWï§¹‰9ô[ñ¼z[úÅÿ‘DWáá"PÏHéw¬üƒíúÁ÷ìà/î³Î}áÄÅ(BSÞ(jOzÁ[òÕïj4±Ïþ×Ç?a¿½û·ºï´óÎ>;a² @p‘鏿rQ­‘ÒL†ßHîažèBœ<â;®iÿé÷éûÀŒ!®„‰wOƒdš¾1þ˜×Èìiÿé´¸é9HR‡bÖtº!®¡ ©J§º½±;hÌ PêÌ`Ãk”Ë Q‡Ô¶ƒb‚üâ…‹í—¾Ð.¸ðÚùå ƒ…鲑×C¹°†šÚßù®=¦©:wÿînט?Ê@µ =ê4ÿÖÇ=ÍTµªÇ'‚N¤iFpÃtÄÃ÷´K‡Mó~"oà'íbÙqá‡w‘?Cø'æ7W¸tü1žø.æƒ+aჴ] Ä z­º¡Ó$š~”»D«š*ÅŲÖvÕ5÷?÷¹ö¡«¯¶õï|­íÿÙjIv\£S Äâ Êó­ìì9VuöÓlò¥/·ÒEOYÑu £Å¶~ë[w)|¨ñŒt*&Úmû~ö-]ºUÆßõJEß•8M„ëÌ×½Þ·¥ºþûßרd£î{mìN0sp!ÏGœ—0¸‡Î0bâñ”ºÄFH¡Ó÷9‰ Úဌ; Þóž ÄGåÙ&jEQ•¤ÉFI˜«W¯´æV1ð–öú7¼Ñ“‰ èS2Tç°ôáœKgAš´ÍÙ-7þÀ·{àü ²6MÈ?kÅ ÙÉZ|•€2ÒÐù­3ÂáR AÔ¦‡8Âf¿âá~ܨOï@u¥ógÒ!†N•Ž5غñÇ"æè²A ]ƒd—¼áÍÖøó÷¹¤29@Ц˜æJg”YÕsÏ´ çžoÕ—^a…ÅåN=%û¤Ý@éD›ó¯Ÿ·‚ª«mû—´\ŽÅ,ǽ‹´¶{ìàŸeUç^©îCs09 ù¨2à¨v«¹å{ºGƒa4H³ð“WKžæ"¸¤åÚêÁ,<ñU_ER¦‚ä!O‡N]üZ›òÂW[óý°-WÔZW79ˆ×\qŽ•Ÿÿm>Ñ`ë4·U5å©eã/‡Žò@\ºÒ=¶<Å~"èM±“=Ñg|A’ÝêA#hîKèº;dËóòUÚ˜‰ï>üˆ-?}…wt¬Îp~Ðäh¨ƒêëÐgÔV¾oÔ`ÌÍ7Ý,à]cÛ¶iªSÍÑfLkâ òŠò°ŠÈóF^7j" ó‹,3ÀnV9Ý`g0ø™ü¥¹gðˉt:¹¡åŽuméˆâDò`£LI¢£Ÿ'.𢉏}R ‰ÉªYz½Û¶ù^‚{Õk^k“_÷lkú®Ž}ÕsÁÄ|«~éy6õ¥¯²òsž#ó™V¸Ñqùj9QÜIxàÉГ(0©Í|ûG´ëK‹mÿ¯_;PÓã0Û1HÔø£[Hª, cB‰³AÒéê©·ôîž ›•B[ËC:lG‘‘$…>몗JL¾Èý0`Á¨õÑl>‘J*ç-#¡1îAÀ[R,UE`Y)â.¿é›úЧûŒú™¯ýÛùó_ø}ZeÃäÖ@ŽAu{E±‘µ‰†sâ3~NB>É—‘.Ћ¿Ðqe™AZ"‰ Ò›÷0u­—)%úúA6Ã?H5¦Äåkƒ%£íCÓˆÏ4^â»YKL¿ó?ßöÙ Û¶ØTuˆgh—#æ,z£óQëýŸµj™ãÜ–ìù’ðå঩o«Ö«Üƒm?𑼰©Ÿ¡Ü˜|ˆQ¹Q¡Ù1¥kµ¶ãJâ£W(žUfµoû ¢Þ@§ÄQX>•f*™aÞjt‰<—‹ÀhuÏ»^í—_¢­þ÷µ¶èšµÒ3/´uZ*Æ6g›¶n±É’$ØÌÁ+ž00€_•]ôÌ™¡ÑèÅrF<—ôø‡ª¸FyTÁhDÐèî€PètÔ_‹| 6¶ ª)^5@v'zè‘GìΟÞ1„Iñ çrŒb)²OÚÂc‰i»$—³´Y­$ÈÀ÷AVpÀUÚÁó äѺÜzôá6ãí:]‚TpuðÓ WÔ ¡|ÁwꪛQnÝ–¶ °çïúõ]’òW[Ïô¹¶ø[ß°ºO\kE3æ%EÅ,'tftkeF݇öúä a„À ƒ<õWÖ 'kæ‚d8Tg_þ¬kwS{OÝû`LävI]R.'G:êöv% —o= k¬·#HbØA›iW¾D+0¤®@™-q‹)§"2·Q’$ßýšˆCd©a¿&µ÷Êà:ù’+(=ôà#¾¦ ž®¹oqêà1TªÞÇsl8Tü A<2Ä“É÷ÉšÉEÅ ºòçÏú[,G”_uÏRÊ~5®šŒ¾Fª2Kݨk:Aæ+Rg8_Úy½+þ‡xÐw¼!ι³k·æßF|H>`s}ºüÓ°aQ}r—\ü>7ñ÷hhýžˆWïE'>ÑÜ¥Cê:óúüh'† J±ùzÐáÑ&q|÷«j€å˜ìV4GõS¢õýå — '¨Ï€´ghuŽÌaÜ#%yL#ÿqì¨ûÊEÓW3Û¦^þ<ÜmX–´Sð…?ÔlÊ뛕tÎÖÀ(”fG{ï€tس³Á%0™]lL®ºª pâ5»ì ¹Ò‘ ÈvTmMñPè­? ã™'ÞiÓÆl߯ŽéyŠ‹qrvÍáÎlÚµ>9˜LNÇŽ<»„#f¤.]ZuPja,~iü§@Rî\ÞwÉOu˜…ÈÐÅú 摤}(’(KZm¨[<(á9:™z¦}ñ­ää0!?t ÇÂÁ#Ža¾)´$¹d[´N幎rÔ^õ_zH ÌhÂ92˜$ÝŸG,㪘Ãê„es„²'¨Ä%ÓµÖ÷™T¡¤}nwÀtΑʼb>–«Uà ڠ€Ígq±Êã•©ÆÀ2ôˆ±Q Æ (O©(³eEèÄ_lPÁ)€lÓy0H΃ñ‰Æ4Ù¡‚éC”„£át¨qê…Ž¡Ð” ûp: EòðE‡¹„Á9ù¯Xƒ5ІÍÙåY…'„#Òxƒý óKH3Æ5~ €FHlÄŒÍ5Ù;ïÈ;µ§]•(9BOÀ®»;Œp;@êz»Àáõz.BmG³÷ä¡x)ähô~äô’_:gð©wÏ~ØÍª.^lÕϵc¨‰:Îwǰ8ž$ªªp5ŒG#T=ïbï(J¾l aD*ôæ¾Ã/T<†ŽãhŒœÿÁAî& ‹ÊÓMÔCˆ"Q*Jg-¾Ïn¸.Ũ‡¥RÇ]n D…FÐZ³mšÛ  € ’ Ì ˜ŠO¸&Qb×÷l¨Ð-;ãn-UÜâ_QuG·c.vhïGŽ`EMÆQOHÿ§+Žýià(½N%ÙœÊuš'èÀŸ×›À‘54—ѬUBè\DP÷€Ä‚H@U’¡¤G·U Q·½ÝAûäFÅf¤{6É®S¯°1øñ3îÅØ±(²¼ºïà>ëx|¼›ÿ‘Oë#ëÌ5èL™å»$`µçt¶r‚$„òW‹u&.÷5/û+¨é¾§q¯Çá£Bº# òäJ§6Š÷qÚ©Ú_ÍÀ+)4À2üQ–8XÁ1؈‘*Zoü®® J=øO3Z:üÉrŸ DUfhæ)i€ìPgÕªilKæö-P¢ry#‘(&Ôâ!i¬˜Jö7î÷U8Œ®:ߥˆJ:œ,Ø ån¬ÇF’ô:uà#šÐ ƒ• ^ vg—„äÇ%ñ€×¯üž .».ÓÏÜSGlÇ™HØ#PrÐÛé_ô£Óé–}ÑOtDòtJˆc¿I@2šQ\¡µ×‰êFí©GaØV3ÆÃœÖcQð8ÂŵMi½»¿«U¦yŸ¹ÚŠ§Ï“VÎìòÅ0dIy,s¹¬¡—à%ô¤cOy”ø9 ©4:]pÆ•Ûö¯ý̺vnÒ¡¶ÚßM#U8"¨È÷ÙŒîžFñ‡Jܧ³[¥Ò+µ 6¢>ŽoÑI#GuãšþKg…÷ìèãÜß–x}!ñŒtMùN%mÒ ,–#}ÐpXaá{6j›Ææg¢è{®p„w Boý—/o@œM}PuÉôž…Úí<½>|µòñÇ|wp™*ÑüÈ·àÑ㡞2ÒjR×øq Ôµ€ r §§wë!?¡ŒÜ<Ž2årЀ´°6éHŠIÿØ&¡eÜ—{é‘ºŽ’¡/]„æ(ž@øå–*Å‘4©Gsy¬ëfAÀ±p®å*!ÒC@’ ÈöÝt§Õ~ä-6IK"}£ eÒ±Šv­Å)aηàNåÍiÏ ’…E¥JBêª8+Oâ2 àµoúgíÄs—µ?x_f÷ À£WCà Ÿ3Êì`%ÆkG/A%ú´õhçêN™¥'‹ŽJ†i"ãpàßÇFÃÄk: ÷> ÄzS8á$vttÙt BØs@lko ÒˆVÍDÛTô˜&¡q9½’zÑ…¸ùŠÁÀݧ©=Ö­³Å‹µƒ<+ÕpQ}è˜Pµ9ƒš1bÝyø¤h¼Äìuªîñ“)¶&±H¨s¨Üu˜ŽWžNhË 1?Pg^ÆîIMÚmž³Žº$õÓŽœ€BR?üNW¦ÿñÌ'Æ(†º(¼e*Ä V+²-«±O¢m+‡f€’(fÛ¿}jþʦ^ùvϵM|¦Cr$ ìÀ»l€$@Nd®c·ôù"IVêGDŸþiùB¯ÿðûl÷O~äb¹Oؘr˜¹3¶È£Ž¹Saš[Û]’¡À¤é¢¾Wã`êA •J{Jƒ›7I 0BdoØ NÏés+uÛ #çÅ Qì)‘`âý`ʹïH'ª…¹}ŒÞ[X5.¿"VŸÛ¨HËúÑ‹@‡*©S=û5ÿP¶£|^·ê\†y_P®I¿¨+Lç5XOeuPÕÔ;³Ñ®«ØR¹±í„c#BüNuŸþ“X¸øÛHf§;_‘F÷ëÖ]:.—N—³±ó5–•oÃúõ¾Þ{–6Ë$Óõ@9Ä„ÎA!æõ8Hg@êånß³Õz5ªž×ÜFs¶Ù¢xóKTVþtÐW¡v´Ï›2SghJ›Ó 5”YÐ Éup`‰¸ÇÚ¹¤|„DÀ¯¤ßpÚQVhÈ4,Tk¤Çý²ërG«$HlŠGˆ÷ Ÿ¡¨"ýpÚ“nòúà? ò$*<}¬œ«úÑaÈÖµê+«oÕ/ù+O^Í=Ô!)Çñ4Ñű˜ø¯ƒ>â®ÙÎg‰!½q±£†ð´·¿Ð*/¾Ìš¸W*Œœ¯Íþ!xŽ÷$‘`é8GñžyPœM‚ê`Ñ[eŽòÌ='TW’p¨KÕfR©É&âÖU ì1zˆöÌ–L\ QõØ<£WW€&àLZjκ¹sˆŒ5Ф8dTÀR>j¦ò2€~þ‡ÊGYyݺu³õìÞc-Z?-.§®a:+¹ZÒÒ\gE5› a¿•èØÞîJ˜UXâ ÒíX‰4uó7¥Ã½×Cr¯G²ê…rž-ûnݺUê_»Ž‚ÐDqÕôÝ´q£ÔNçÔq±èÓRùuy¯•œþ‚á ˆ•ûÄÍ›6Xw£v»×&)ÔV±üBÊí²¨:‡þíb³¯Íz7Ëîž·ZvxM}Ó¹çsëÜ4ô‚ÅÑ5³w5™);üÌ ªc•ÃéMÇ/"ލÖŠì¥GT`êgÄÎIÂŽD¿]üÅDs˱¼t¾8§ö3ÖÎ1HékbõLšn“^ütï|‘½³_ ÇåI;éÉUx/4L¯zÛþb«}ßǬ[’\q•“!ÕÜÏјKÅJ@NÆç—Ä”Îð ×½Ûu Õbˆß"O„s)…^޲éÏí.€$÷>â…4b¢L˜8o™?V”$.a 0–\îxÛ2S'(É# °ÿá­mO³UH*rõÈ¿÷*”˜Ÿ{Êæ” o^ÝØn ;l•6þÜ!ðrÚBwèê¹êÆÿ‡kƒû@]ébÇ2Åý’tÖ­[ëÇ>2?À‹cm9ã;HðdB.^ˆCÎ z®z§en2ÉÛÖÖ©S: ”9Ó\J#uÙ:ø ë:Žwÿ&›ÒÓnÛrôÄа„mËr¤xñ¿<‡ùa¶ÁAÙ÷Kµ>¨9¨‹4‡Æ5ª.S½ºñ:Ñ'O€ÁY3´+eLu”ïƨ¦}ˆÈ¼ÓSFkª˜]ïí¯>m‘Õ1Ãt9A2-v¢ÛÃl2¡TT~Ô¥rV)hbçé•6œ?{ã,kC©Î•Ææ½É§:q瀨J‚yx…½4Šºª@PéÜP-¿4ngÒ$hAGð$-€²D ‡TéH8ÒÊ8.5Ó}Â+4ÞÑfÊP´£ü¥Ô&@ZÊ—ÄÛÛ°Ù ÷µZµÊ…”HOÿ“w®g*¨Þà@TR.¼H¥žÞƒº-ÚªPÒ9ʼnÈcãš8ƒ®‰WWÔêFè´yÃF;ã̳2tãèÚXÕ„ ¡¹hL#Æ««¿Ožýüo¥}ðᇭ³©ÕJȳ¾acÃAîhPä[Ÿý_’o¼™.ô™Ú¼eÒš&ë­Ùa Õ³x=¦Îù&á¿C%”ö0BO$Ñh5ƒ$MêpHzd@ŒlÀ8Td£õ^tŒõ¯®¶X‡Á-_ÆRæcäÔFóuä-»…åõˆÏâ éIfÇÊp\NŒÀ@²ãÃЈ$rlyTà½4=ÇÅ “Q¡ö–¸Ã„HEr' í^•L@¡²èìT«Ð=;:uÀÖÊk¶$LÞ‘Ì¡ÆÓe~Y¨ÅNž !, Ì@§Ù™e…öŸíÚ¾Ž)äƒpe¸‹T ñHس¹Bc|0›ÙNýUí–IoRÁ±¡Íž6ÕAºc„9iL§V¨óâóµgeMs—óëT½£¬tñÚú×Z”W:@:$Š͇ é£éËÔ°ªéIä–mÞfÛ«kõ)õñ¬_x'Íw´ujP¦ÍiبN¥¹¥Uª¶ìŽâùãéʵC<æ“3ubæ1sÒìM|ÃsΣ¥rˆ–ÀfN /'‡I¤ ¦ù [¡ùN<Š¿[/8á¬ó"•8†R¶ꓱ–‹c­nà suh|¥–"2XÀ»)@†š$BMÝUpD üÁîb6'bŠŠ„xhÁ4b ?‚/!à»Àœƒi#aF©Õ©ÒÁ2DqŒ†1óIÊžÅ@{³ÈΨf.™Ÿ‚Ën£+g3BãǦÝAí…²7WIJ¬8w®åéØU6×PÓ§8$Ç;M|tPá^¢:ذz»ýtó§YÊ~˜¦¡Ó tMHëñPOÍuå ç;wxD‡Ó ›)RdŸF`]òTnÉ1õë઴cGF1cøgîÛn+šeI/-·üieVT*ˆ:‘©¯GØÁ`U§õ´J3Pfvª ÷X©_йóB-W›Ú¨øŠ'jÑ‚Ê>±·Íšµêñt”“?x°³‹UNšk*»_Óf; Õše¡ðãñv´:,–‘Öή=fÙqí þXúEÚ¸zuúÖ‘`Ó¡ARDfúi&í•8…J[œ¯ÑñöÉà!iÊKІi q ãð™T]me’àtî3 ŒFå¥òê@(¦wfý`@26&W?iÅüWeêâåŒYQ0ZÿUܼ®RâQÏ0"q!‘² ù`¥ÊÏñËÐÐ)Ѐ—Kõ‡XGA6)ïÀ(²aâçÙy%6O÷Sþb‰66‘äX]¥“ì 8Í2yRWݯ:€çþóO«íÎu›í ¦“…Øãî£ fÐ34ôø½_¶Nh‹ ­©±ÉfÍže[¶l– ÞèfØ€‰ƒ’«çG¹òœ‰ŸÄUÖ‡§Í±ÍµuvFaÕ§ÁùEëé–ÿ"ý ¨|ežÐu†$Ùú?mÓúã~kTF*ŽÅj[¥3Jm`b‰©Ã€&S5ó£¥sºö88ÊÁ‘é2Ëñ°¡q1€–Ûžãôô]‰ÖiŠÞßvØÃEåv^a¯Ö/Õ[ñzý“%Ë$_¡zšôùU¹5š<þµw[a “’Ãñ$Ú±”¬SÊ´ft¸Z- »IÓy|ÄZëå1ÿ<•õT­ÝšæêÌõgŸÿ@: h“tâšv“Ÿ¯Y>gC8¥«óÛ0 •$#`äŒKö©˜P eÄ_!BøOΠ£õÒ{$I¹‹/²Ù³gÛ¶m[Ý>èƒ74n¹ŽšIa„7€Ámm.=©xæ)ðF2‚ ÏÛ²Ç~â¼@¢W½ê0èɱSvê†.P–i€Ç핉þDàHEoC–âÓ°¯.ýsÎÕI¼Ž$-·É2ç …JN Í^¦C™ª/]j…Sj4ûKJx‚®Äý™NB¿Š'Ïþ´³É¾ð»‡l·ÀŒ°Ï£‡8ò—+}ÎéÚq‘žž5=°Ä‘9“lÄ˼¾-›7kw ›R]©ÊS*JŒŽ.†Ï9é“'÷.ØÍh[¿ŸõÚ£š¾tQ~·M“ê5Oê*ûJs²»bãØJëÌ9Ï ¢ò à%9òðäçJB9Ȧø#1üÍà»ø ¾Š+eöi'àÈyæ¬zŠ4O‚>%.œVйlÙR›7ž×Ç1˘°aØâ]Ä©áç"Æ0üÇ1=Eçœ{®ýôŽŸˆ§‹­]R‰˜†á/Žb;ñN<ÿDp …ˆaР].pôïòCC¤ÑºwÝ3MŠo¤ÍºVæ2í¢S YVЦ1•%{y)’ØÅæäfÄ.¶qÅÉ?W÷lHJ3gz„íY²»Õœ1Íò$-±ôKßüå«|\w¶÷Ø'ïºßÛ©y•ä[ŒÞÀ“wÙÝ=úOèd<[ú¡|Ñyl Ïätæ£Òq5è8Žf1+EJ”/\Hß!ýC¥E½Dy)@8üîXÞ a©¢;_Ã8Ú3[¶t·° Å|Ijt»g™æ ûÎÚ=RѧþÊb…HÉ”Ç?²hðD€ŒåŠ|I§Ëˆu£Ví•ù álhŒ™ç©èæéÜûŋمÏ}žg‘Ž åÂÓ‰ñ{B‚$¤eÎ&#ÕK—žæ«5þøÇ?ÊV#¡*#ªÖ]-ÄG*a¾´” {ÃÓ WÔ0\°NÎ3?1¾A$>‡p$îÓŽPÕ”,þg7 ×Úæ2ŽÍ2#YªÇ‹RIÅÆá1’¹Qt¢„r)ÉP4+ˆ¾J×:IDE3j¬D+LPØ|m•$P~<Œ®ÿ}¿TëGÖh › Z (œ®ŠÃs©wNÛø<$߃àè~ôÍãöò)€Ú9MÔØ<á´%,K4Û¶y«ƒB±¦o0/•z .s_<ኙ콌”t…z^Ÿt+»lC^™=[Õr©àt`uAçË öŽ˜ëøzœ¢8$I:©Çðr„¿ä1tðo°»²"†å|-©Þ«éQ{÷79X"=>U4™>mšÍœ9ÓN?ý ›:}𗇲¡‚³c؉æNXdG‘ü‚"»âµ¯µ•+Wú`I§ÖÃ`ι‘{Å|¨áÙjµ7v¼þ"8RyÔtÊ ‚¢^†´ìtIµÿŽ¿,é=Ù|–}ûJ%š¨á4~ì•HÆ.•јGÉ‘½ ô8L(§!ƒЃ{]Ÿ%(¨¹ N#·åY£ÖI0#ŸÇö´ÏþöAÛ®ALYõÞãÍd5È„€æ QˆAp$­è|!¥9éÚSU|g•OýÂ…º3í¹Û%˲âR¯?÷£x<×,ç@˜¼ £ßzˆÞ¼Îb¨<ëR~Ý]l«Õp/Îï´Ép@’é]¨ýÒÃÝЯ8ú¥¦³m  Kvù±iäi€ô@Ùg˜A‚ŒÒc«lðÒSÙ•kIgÝüù¶bÅéöâ—¿\|”Ûdruöë§ðó ’ØýˆQ1R¿&.]¾ÜÔ=÷Üc²eˆ´#Ž£«î35…„GkvsÕ8Hš9ÀQÞOoüøOÂ誷ÖX³ '¤"†—?&^ûÈ»À&ÏH—ÉdtÔoÀ2ô´éHbüÿ:$dEÅ»"M™ó8ú”h·'l~tìr¬T¡ÜŸúí#öÛu[$YÅFId¡ðÐ Já!ÁW &y§]Ú ¨ûä]$£kzx泟¥±¥V­´Yësþ*´W(i1Ȇ”îgz«Ôà¡\ž€Oí>tü†d 'ÇŽ â :Ô}v}_™UÒoÏìïxú&: ˆ30—¯<ø)¡*¦Éމsz(“t Léñ áéo”í‘ób|íó¡‹<&yn¤ÔÑLI‘s4XsÞyçe2½³N¦)7òãèÿ„Ézy’$‘z^}啲I¶ùÙÛ«W=îI…q£ÿîh$.eŠñ£Ú¬¶æ ?*ò”_¨.EÆ÷ˆA¡™…‹Çíù0Ô%¯Óñ’>vJ®~X–ì•¥²-!QúÔ¡D²dŽe„†ÆzÔO4ª„ Â8!µêýÙšQ}aVMfÈ·^J¦µ{w4Úgî~ÐöJÅsé†@Q·Î¤.ÿŠ/æÑý%ßb’Л{œ€ß„ÈŸ{ÎÓŽãå’$ùzm¦uѱTiIˆ+¨ NO§­~—Nß_yÞ9š{^ª ÐÄçª^ýªoù*wì÷våÛú‚ »$¯Í¦K¤Æì „t 2¯¨ÀФ&öéÀ±n·5$ ç¸êRÒŽÜF)F£]:ÓÈô‘ïÄð¨ åŸâCÉäE¦ª“–GîbZÑChÌH@! °GÃïÑ #–>¿’Qp5’Íûdp÷o !@‹ Bï—²RNJã=¸2‘W\hÓ†åjwJ§˜Ý} zþ´æ<Þµf£lƒÉ¤jON”pb¤ÓV¼zÇÚ\ÿ–”-ãCé†0! ?F¿x ¯ïD°éÚå·_»!M1‰³DfD›zÐI¹Ü³~¼Œ$’qøa5˜Êέ®^øñä0ªÚ0} ›#y8 qñF«´s zíýZ±!;šìÆ€T¾€ÓíàÐÓÓJ§—I8G^¿eßù¦¶‰Ý±Yk«™Îúu_JØ8F)>;äSï¹X³"Õ×Û¢…‹í‚‹.ÒÄý"ñ®Úœ*Àw ‡†âçÑ é ^ÌʲCìH¸¹ófÛ’eËl÷ž=vÿý÷¹ZOÚs¦c;[«Ñ nz£ÑopúÆwý¥{í$DÒ¨³…Â&Ái·Ñy¼’ù¯àÄŸ`t¸ÌaLLF—ÔH ŒèÂx¨àü9¢ÇDŽæªô¸•€O¡4…0³à£Zç|VOòIáì>h_úýöSê‡9¹µbù’¢;д -ý™¼¤¾“– ùÝ…“'ý_ºd‰ûݰv­4ƒö`~P<ž âô(=!q†/‚ŸÔ8½R’°1ƒz·€“t´Ø`¬qþ iIGª\+©òÒ‚V›%IÓ%mØ ˆž¾¹š?.„óÛaý8™ÒçFVˈö$EújÕÁ‰ä¨–™3fØŒY³ì<Í8™­¶˜§òÑÁüöÞ¾®ã:÷€h$A°€½줺d«Ø²ÕÜ«,«Z¶“8vîužã”çÔû’—vï/N|Sü’Ü”ßÙV±)–mÉE½Z’UI±÷ÞH ¼ïÿÍžs6ÑH‘t‡ÄÙ{Ïž=u­oÖ̬YC=CO•Ú‘×!)ܼ[N…S^Ë$®Ò+<² W®»á†°rÙ’°´~XØ'û„2RcæKmâÅ3Üß ¶"p©!!^ÿƒ»¸Rø½ù0 gvôlæ%8}n…v&c0ü"³èVœ‘*m5Z«™µbž!¨ I±›•pÒ%ZfOü`8Æá•e•Eu#4òAbÚ§,ušÍ}ÖêžMÿmƒ‡†ÿõÜòðÐÒÕ>”«]Vs jƒ…3H È\8ê'&ž³~›±WÆ,#ò1pCu¹s”YE]qåU>·hÉ’eÞž8DF,e1‚´, Å›ÕA+®Ñ/~å7¼ïƒïQ+™Ð˜üÊ i²I2%…H÷ø/\x–$²¶ðèc² .°a5Òí¥w‘ â/TìKw <#ÆÈº9Ò>ö3ì2þÔc«<G˜ÞŒš} ƒD+ß =ô)ó€ºI#UVjØ Xb<…ô#ÏÐ[qÐ(¿à'Å­„â”,LŠnZœmÕœ—Ö'$EÎ ¯ê„·ÿùÝŸ†Z¹öy4ªqDl?ÕÿX:1+iJƒ—¸Âs|ä9¾Š/P¹Iu–…Ðcz§#xª–´üñëoÔ³ÛUþ…èô¡_q8¬öVÐß4øgiwWÉ/]IÓ –ïÇCÈ•tl/¶Th®rHx_Å¡0Y•¹G+7 ƒ‘ÒÓð1‚`,7õÍŸ÷µ#*¯äM«ÖØwÜ¡"wH)é‘öŽ5ÒÌaAT&Œššf†w_q…rW–Òk­–m‰ò@i A¢ˆüÑO^/‹2GÃæ­[Ã’Å‹EœØy¡c˘:#G|<¬E{ÅÛþºÖرä 2²k^r,¤B¼ú#o–Xt.†@°)æÕƒ"ö,#øG€‹ŠéCUFÀ’£*±¸C׬ÿ|Ÿwä©Á°­]‡>iqè€æ¼öîß6JRý£ýÍá™õ[¤gª]?5C[âV$07–pÄñ]סhúÐÏ¹Ô ÏÜðW’€ƒ¦w1O¬ŠR'O>ú˜çD9{#Ç|Ï"—…aw%„Ž.„øðÌŸë‘RÐÒ0Ù§Ç\º†3´;ëå^-lÝÝ>8,T}ïR/xD 8DÇbS:éÛÔÄi´à’Óþx¤x”å™w,H²ÉZNóŽÇTš<ÆK²Is‘óçÏ Î:æÐºËÌ)ò+[¤>"3DF4Q¯(¯zÏ5a݆ ¶ ³QG•¢'™@ Æeñ¤(=F&pø—œÃ'ª·§ÞZ(2çyèà/̉é+F«qxÉÜ&qˆÇäJ‚ç"@Æ n”79`» ó­$ à,ò$³lù!8e†Y“30fL‰TÊ7¨ìÓJ)Ë~1i«¤ìÞ“:M£/{™iîµæäX©¤Èük+å »kw¡\J")|Ð4cº%³Å‹…—^~Ñ‹$΋êGGFQW©:¿-þ$ÀJ><§¿ä××IW:…Ü!Á’æ«)¿¬¸«Î;4Ç­y) $_Ño$G:¯t¶LRgþq¯:)¤ÇrwõÒF¦CøØ]só­·ªÔŸ›´Ü‹WÈYƒdbˆ–iŽr´¤’‹.º(lظ!ìÒY&d|´F«º¢^³W»EõI3@‚€8…‰àÜbF²‰g=[ÚŠ_ø7I‹Šçž8Â8]'Æïpú)$ÁØHKWœ•! ÇœCp¶9"Q¢_É*8`ÉwÔáÚG"6±PS"ѯ£Ž0¡&®7H1_çô”f”8KŠ×¯¨¾ã7ºyÙ¢ B„ú¡²>¤+i9¤¼¤4ÓwÝ]S]t÷®?~‚cO9pEÉUkÜ΃ 0¶ õ¨|bDa,ba%?¯¶Åè%µWRëÙµ[çËh˜ÍP~q°?ù9ÃÐ9×bÍù\`)Ò6fÏÄŒž„<•5HÂ@¸Ž©>èů¼æê°zÕ*+$/_ºÄR& â^.„óDè…¡¥Ó;—ôÞ²R&i Ÿd(X=ŽpwzŽñ“¹J(Ù@’–ÒáüxGŒ4ÆGœHw‘ùdqH«àµ5‡uFU<Ò J`Éw0çˆp z†€ãaìu² ¯FÀ”d'Ц>,UúóNI×Ѹ~äc¾ò¬¢$eÙRàý«/ GáÒÕ}üP¯¸Tǽ}£/$¦¥p±UCfU±Ú¸¨-°u‘é®8O‘h£F:86½Ö´Ç™f©Ç™=ÁŸQ#µX3#œÞyáú›nq,‰ÊO0Ê3ö³²É´XÃ;’…gIT×¼ÿ½ÚÞ¶E ºûÂz »a’(ÈöEÏI2„1 â_Õ\ ’„É$< ¤_7¤‡µ  >D"äÊwÄ£ÿwÀ.?=¤Â˜y3É IÍ Ð%Rº•J€ýê(c‘E©j1'`É”Âí­fÞkóíZ‘ù,ÕÁ©rJÊŒ„ Õ{HNýH¶Ô\uGdÀÔ[úÔa«5÷¸àœ³µÚ»Ï+¿H̨@ R½ûŸÊ™U®£K —®xæï{K3ewßGÎ+gªol£25ÑÆÜ-Ïښخ}ÝqŽ1B<Ô=CoèøcgÕjI~h¯Y`y"R|oåx3ßÕÉÁ,m=ûì³Âû?ðÁ(€¨¥Ð‡ˆ®lA²')’ù"¥†¡Ó¦M_rIغu›Õ-Øî™Qtcè0 ä1-DOü\PÒK‚qÞ9Íèaèó½Þé_š—ÒÛÌùË,…ч…!¶¾+$éŽÇ'.~îÛÈÀ%^²wýˆ˜Så­’02 H"Á ÍœçlªLä‰¹Ô ¡$ó˜Ô,¿É务0Yᨽ;ºQ€_6ÈÈ.j1Tt­€_•£ÿb<={ BŸ¹ÅäËcþ>¥ÙÓ5Z¡íñܘÿM ˆJTÀ(DwXÕ+áL/Y9ÜAÐ~I:T”&Á>Í=”¾§Û­§Ì”™?ü0iü„0eòd[á=z´y~ g¡0É•-HöÔn+€8D‡Ù_óÞ÷…Õ«×øpûÕkt¤¨†ªH(8†±H¦VóÎsLÈ8yKÃD0FTç d ^E@(œ¢.’w1,UÈøQŸ™Å XâdI”ô¥øÜΙC™ÄÈþ^Lh.€LÙK×8Õ ,À£êÏL“UH¾^¨‡SYæÌšéºYªiæPë•êäô%µ'iS_ª(wêI“úÃÑùûR¿ôLûáÜŽ2€K;,®@Padüzï°’&¹z.›•ºw;8º0¤õ ÕQas $¥Ýب]5³5Ì>?\uõÕn7üa)Vú¢p ™i¯v0üË?ücø¿~ë·ÂG?ú±°UV®·lÝb)¡iAðÁ°Hq42’Œh¦ƒ ÅzÁ$bøC¼šsÙCv‰lËkîºÈȨ€ „°é÷Ÿ‹ž1¯ ¹ó¦€HdzòÖ¢y°£bú7ÛL,Ú¥B}¦º4‹.ÞãuÙeï°ô±tÉ’°ióÆP§9VÞ2Ô¥-¤ãv ¾({Þw ¹'LÞg?À¹A€ÃÇØaß!! 3I‘6')ê™ïF§ìk1´#ëRú”‰ÊsÁoVg•¯Ÿ“yÏ0€œ;wNxß>äzc^šúKDþþd¦ýfÆ5 A’†Z©E›Ÿ>òp8ûõxW]m;…Ûe°ôµW^ ûµÊsBüúï!ͼŒOÀ’ŸÇÒ£™¦ÈETë®ùÌÕ@dc¤3[?ÒQ:º#}oÉ…üò§x`Jü Ýa»’¡a>‡ŽæMú!€ùöô…çëTk–â#°Åz὚×Âê +Â6F¬oãwð(‚k”ÆâÞe¦ƒˆõ‘1IZ„ˆ`l“¤¹:?ÞE@ÏYÕmEÌrÔu¼ã©‹‹µ./‰‹þ¥á:mšHþ˜$‘“&M —½óaÜø±¶‘0„6u„É%°LÏá: A’¹î¹û.“÷ÝwÞ®¾æšpýÍ7‡Ã¬8jÎÞàæì¬—$éx> æ̓?˜ ‹C­È80çá E.*Ò@ä^ê/2¯¥U3LØO€,ÄCÔY<Ä‘Ý'€t~H- oi)¾s¦Ö8ùïˆÚḧÑë™ÆP=¸Î]ézŒ’bEÊšî>£$j€C¾è$¶ÈPmGTª´îq» ³—~̵‰ÁÑÏÑ3½LSYI_Ê;Úsüçhí—¿KíS6nÜfÌhÒöYŽ“‹Ž²4 ˜ )ÆXµzµaÎmþïö§áwÿÂûßÿ¾°MG–bVmÍÚ5¶dž&š“4Â\”‡×â†^À“ n€Q*%ªèr%Pd–ÈB\Y<¤n€dÁ ÅJþR8ªçýô’÷€ú딿£RaH‹4‰d£Ö©—˜$k–Ng G¡j_ó0ŒË:„£Ä§Tò¬ xÏ_’­›ˆ'IU(²°âÍc=†©'ÚˆøëØî´kÖ´T}ιÉy™œÌ3&pÜ©6ÅšÎvýí÷00–šÒ%uâúS]XêV§Év:ë¿dúã’œ½Üªñß§—ºÆ÷±ÝÓtµ!²Îü' ›û¸ o±mŠ¥ø+¯¸BRäí#xØ£ŽiÙò¥Ú¤q Ð&8Úˆöh®,A2Ql ŽHÅ¥¬Y«¤?{áy=kÞÉ Œðþhøù /„o}ëÛÖƒ\0^¸ì’KÃXñœt…¦ÖsŒÌ¥ƒ<@Z?ŽÄ`,3—ðáËÞ’Rðcèˆú>åWWî j(NA?EV±ç"c¹°t®ÏËÎa+³ª²Zûëe2lÏn­pïÃâ|d*íÊA‹¦PØj‰%íš2ArÜ©ïØúp2Ìöªµ™5V#¸m°€Lj$ìÒý©oþ%©]Z¡X¤`ßö í 8ÕpM”ac”PÂÁD­fs®ýåï¼ÜG¤|õÏÿ<¼ôê"…씽ϭ2 £ÝDÚÝuXðᨛ¶hC¹ÊvN•ˆ’aLDá‹YvÊü?ï3&ìt¥qï¹ç;á]š—¼î¦›ÃP-ì‚Éhlͱ ¿yxm<‹ˆfý8ˆ¾@ø‘Y2~°·nÕ|0 ±aÂÝÑÇ4ÈW!îù£S ¥ëP"Z¤ —Y>£w–¸$a•£+Åd:¼ :c{¯Ž- œÔw’ô ©á5 1!»‰hËaÍ?ЬœÓ!º}2ýA ´[‚ÛM‘}j7h‡DÉÑ#ÍEd)ÃR¹×V¾!Øä*™«¢±,P&‚œX„‹Œöwó7"xUøð‡Ã¹:xŠæ'iܰ ±3\ƒ ,3 Œ¢Z3fRü)œ{H“pü§ºgUxsþDRp)߆;§,Z‚tÞ؉(.%ÈvK3¤ÒF¹šWž·„@•~µ¤šy:#§œÜì¦Îî:í«G:¬—qá¼ .hÏÞñžùF†ÕÌCÒ0³x ’©¾¨ê ÈJ2J€´ õ™µ¶„ IDAT ãù)½Â_æÍ;èÌíH{p£äȾù4ß Cg,‘§Iš¯É:m°Ì~† FH6Í Ÿøäu"¯Žðñ}PÙ¾BIPÂçÐ2ÔíÐÁ D€¤\e ’:zŒÉAÄôà»l6!“ˆâG ÀI/k%õëýךŸ<>ú‰OhÁ,K•Äã0úÆs“\FxPQjˆñˆ+"ðŠ€ ¦º‚¤°[ I9 Î;;ž“¹QZ(ê1*+4×UEúúgÙ˜o”>érDÅ {ýà†ð‹ÕõY"åq¹\«£HÌ;vl÷q¨šà(W\˜9ìó_Vo×|§vQ!Ez1‰ pÔލˆÆJbyÞ±D‚´.HÿŽGÕc†—Ã@ë¶, «Œ€£¶Lú 6†Ø¦=Ùî”.æÁle}ΠšpÓÐáám‹¬°å䨻‰Ú›}þùçkgÍÜШé¨?û£? /¿öZ×bˆþ˜ú@²gd HÐ] ŸÊ«s%ÈÏ}Ð@0ÁQ$xìáGLÀF7… Kô ˜£á›wÞ¡ù¯áá3Ÿû¥°`Á<[ÎyþùçµgoT@MŒÃ@*I'$oPs¤¸‚¢üá`B1 s†Üó½Á11 _ØŽ‡:˜_9¾—+ ±õlç¿Sçf £ÔQŒRlj¯ë¬ ¯Î‹ÛýÝ™þCé¾ð¥_ÓAXÃÆ ë=·5\’0R9Ù,Ü+; Ì{Œ,ÄDUž¬¡€D‚xN]щˆDƒì®pY½òirxùƒ›ÙÓCÓ1à0ò-@™Muø™¶å[ÚCtÄÜ(ªFXýaË#ŽzD9a¤¾÷Qfz˜®C×6,_’ÔÕ–£Op†ü4 «³gÏÖ^ç„ët–=î¦>iC®³\>yÞ¶}›%IN¶Dá6u’Fd¹àe}K[–­Kê SçŽ`gq»Ž”M¢¿Ï·ˆÔpÉÏW–_vé ¦I¥¡£³*ÜxË-ᜳÎSdо&¶eÆŠ @2ÿØ®¸â) OÐ>ÔùóæZ¢äÀ­®q¾°8Åe†‹;zªª#¨Á|ŒšÉSLG‘+\ü‘Ÿþ•¤£ËBxh(¦4ðÆŠGÃÌÖ£a°â”å1gƒ(G >¤Á\ùcBemµâ!ì+I’aë§?û ¡½õ`X¼tYظy“‡ÔÞ1#IÒfƺc:0¥>o/аPW“-¨X_Q éá³ÂPaJ· ©wzï:\Cß8:ME¥ÆB“ÅAäá^@"­ÌµÐ¨rHuúvR§Ž]•ÄX™ÁOæ;ÂEÕá÷†Ž CeîÍv£FŒ¬d_ yÈ[t WûÑÊð¿÷;]vqQ¢¬ ÙEšfÇ i¨®,A"‡¸‘&q0Cjæ"!d3ˆü"CÅ÷]üÔâ ›8D Û¿úÚ_ÚÒÌÍŸút¸øÒKÂü¹óÂpI”Ìü™äE!€œâfxcyˆ-ÆÃ‘$CvÞ˜  ?4»H}à äÍô”4µ Q«¸f 9+[¬íü%bE"ÁPnôˆè¯E´gº£3›:uJ¨¤&ÃhªGW¬‡«»t|»eJA‡2ÅöSøì¤íj·Ž¯Ð\&ÃÅ(Íg©h©~5•® «U¯©ê  º)ò%Àªº×têF€D‚lÑb½b‰$5ø6p<ÅFÝŽXÉ¢¸˜&'ÉŠûŸê”÷7Ë18VçÍ=+¼ûª«]î_ÿÒ—ÂÊÕkœ%ÊŸ´—þÐ3«ú­švÀxqû3—ÊúæµNÊÁ \MÀ¹ï p(ó°Ê»‚T'Oî!v† E” aÍú ᣚŸüÏüPÝvï #ˆ“­WEݨƒ¥ `4H3'¥ÿqØí/b6äWö+}ÂëBf/cÀ¸8Òéý -.Õ©(@ÁÁ"EÞXQ†^2YÆ!Šý\Ë‘®åv9¢ ³Z:W[ù†Njê‡ÚŸÒVªZ4Wv&;$ó©]MŸ25\üŽw€nÒ‚Ù>¨`ŸðmK5²ÑmÊœà^=/Y²DG–η.%{µ9Cœ!uµÚžsq¸2² ÎiOw4Œžãœ$í•2=Ëp¤ø¯0¸ø)¿¢µô…‚¸%Hi?duZÃKÚ³'צwއ º©W:ûÕîÓ+´z/?t[ë@ ^ÒQÆk¡d«:äÓé0S7K{³ßvÑ…ZÍŽ'ÞvÛ7ºd!ÖjòŠõŸbáØqƒFÓÔó@te ’4HjD}޵™1L¾ÁhRœ%: K“ÌUJëwjnò¬sÎ Ÿý¥_ ÏZh)rÑâEa³æÍ`Ä´J|,,`f‚xgÆ­Ø €“InôĶûe%ÌÕäfi¦ë$ïÆ4da˜ü§&…63Wt µM”aÑÙ‹¸ÛÊÃꨛ1£G{ÞkÞ‚ùaøˆ‘¶ÎCÙ¾ðÅ_Õ9D«ÂÖM›Ãô¦&ÕJU†§žz*L7NÃÁqaÅŠåᥗ_²në.m;¥YFr§¤xÌ¢´‘ýòÀ˜Ý,‹àè m–Õñ¤¸h·£Úl€-ÊZÁÅ(°æ}iŸÞœwa)RŸ© l@’”l&êiš‰tjFׄê1Cà íp™¿¼SGŒœ>¬£0Z1O •ïEÃC´ü[¿õaé²å®ÛT¾ŒRÓcîkí¤­ª#t[áA:®æÊ$½Â-FÁ1'²iãƒfw$L“â³`è wŽù‹¿úËð ¿üËR¦½! Z/¸x¨S³¶aá’„a)R‘ÁfX€‰’ ïù«ûO@=ü‚4M^½$ß’´4S\£ÉpQ@:Ù!ð¸Fë¤ÃÎÒÔ¿k<¬Sº8Å]ÏT7B‹}K}~ìÚk½¸Åê1°B™?ð§CǶV©\×gºz„ùÎQùöy×­¯ ¨ôÔ½ëSíÚ8Lq¾Ð=Žß<8âG»²ÈèýGl“&ËBî„ Ô‹kWh·ä¸e0RCëa3BÍÍ#–*hFCTÞÒâßér¬ØOÒ"変ÃW]%‹ã“ÿýëÿ=ü°kÓõqLfÈ%u]èââ æf™Ù~§$îÿ’ÇTÜ›ëÁpɺ@›„›¶l6ÁEòï9o–è+A9ZŽÈã€ôóÞ{Õ•áÇ=>øÑjgÁz`X×¶ÆŠæUJ7îÕŽ –BÊ -A¿îH>­žRaHò´W…˜fRiȃþ¾¡4jÆŽò*º_ • 9é[[ê¹Øoê›jS7¨ÛÔiû!œ{”QòÏf€¸cƒk•Ô¹hWKßă$µHð?ÿÇŸÛªü¸±clGÒ ÷®Of2)Ñ# ‰Y”‰ Ó¯þôD|ï‹ôG@ ’¡äa=#)ÑõÇyzEiGbçÊßPý ÖÀé’ å…÷D»zÔ3Ôã©uJp¼Î§™9³)œîyá"YÂBOø¶¿-˯êFùb>•¼EáŽ?ž£¯t&úÉÌñsôî@te+IÂd€$Î’ž™¯Â¿è+´ø£ ±Ã3ݹח- ¿ú…/„¿ÿç ×~òZ©9pmeX.vYà`°tüÏ0tuï|˜¯Š¤&®-0/«Ø8Þ He†Ú¬¡žÖÎ=…sXU¼Ð_À«x`1@¦’4te˜w&:˜n$ó_³çh è ÀX!@Dú&×Ì/ã¸Zç0k@G'P¯…²Ý)Þ´ichyåeÏ…ÙT™À÷˜EÅí)€0‹ÇPEr<ãÈ z÷8báœE;$Êd~Íûñã&W8ržZÄéê¡Bª@jéXz–pé¶Û$ËÓáè¬æÍ[ yȋ R÷©ÑÜï/ʾ*;œâtQì\ØŸ‘•K8F)ÒÙUâ3 7 ³á»üN·ÓQ–Ó•F¤ÀÓ•ÚILǪ7"~èß 8jTæFL™PgwòŒsˆÇf&1ðÔ÷øaø«¯~-Œ?)|XVPfÍl S¦I¾a%€„ùÀ,¤D®V:'qÒ'=ýšU1=»A¼J+OÞ²è“$HžÉ_³@r—¬N V¹ØŒ*ô$qí‡YÊÕ4/§ô­ñ©wG¿N‡S¾)à—@ˆkþw–pUfìFÒy4ÍhÒÁu*´¤CâXQnW`.ßþNut`y•ââ@·ÿö‡ÿ-\tÁ’†fÉ_«ÜÒ5d¥;©dAy%pçEq8 Ÿþ ¶®÷0ÕŠ•+Âkšÿ‚aoþÌg<ŸÃP tBÙ'HU"±B† 1-C?¤› Ê­âê )¿Å+B³˜õá!Ž+Jbe¸Íµ}µNyT^PÚE ì4¡HfìB§þ&m¿Œà­œ©®ø3“iåVãJ—c"HMt8èBRy@du?ÀvÄ¥÷øÑ^ ,S©Ð«D:‚I«$Mzÿ<@™˳øøžº7€â—ý‘Ç<@bê “gX‡J£Bç•íåJ»¨à&‡¸pC‹")ŠÞäÏ_J›N#H;¡²¦*üËⵡEõr*]½ŽÄX0A8ÿ¼óÂǯû¤“úÍ/9l‘°AÌ+Éõ$)Ú‹6K»Ý’÷@º4sI"£±`\7Zj¼c®±y!Ž.×C« Ùnƒ¬gÊÎòøÌç>š¦ÏƒµJ;X§ûA^ /}ð0“7þ>dÌW24‡ÍŒIZᥜI5#XbÐĸ%2½óž@ø Ã|$Cq†…±<¼<½.Öw”ÊHÃH°¥8—½2´ ‘ôKÏpŸ çâÜfª ŠãÉ¥Œ÷É¡!Àsz‡?Ûé8â´iÆ ßŽÄãùIf ó”Ù³Uèž«ãU]ö#Aî—Ù"éœ]5QŽ”vm’òÑÛµXø2dçiõx¸vGU(Ï•u:xŽ¢¿$Êï­–*Ó)tÔ»œ¦i+èÕïyo@ëŸÿéŸÂ“O=©¶BÒ†–˜ Šm掼ˆ—}æÌåôh¨Ï e ¬A2I\Y-búCØ–ú „ôš+R î TƒH‹ ï³¥h~Å»¯ Ó§G&58H@|ÞÛ-ÆNÖDG–ÛÔšâ°Õù‘ßþ4F _—MºGscÿ:DöoíÐA¡fB]¨®¯ mZ¼ˆ-eêãé?O“Ó“æ¨O€ß Vû(A2?Èê)¨Ð xüÊ+¯:]@ †Lm˜2“À1IŽ\js¥×®YùéCÞÔ4ÓCnâÎj…õ ©¿Ho¬jSEäÉqŸÚs¯þXÍ>"ƒÍ>.Nx¨F]{õþCýëÏÈZ¼Äo彬1, ®“ •¿A’‚;k…ßyü«õù‰¿ü8Ìë¬giƒÄ9áœóÎ /ýüÅðo|£ŠtÞthI3@ý‡HÉ—zèÞ¹ɽŒ#ŠDÅÝSξÅ.¼ KsÀ<0–‡ÚŸR¦+-V$‚R߮Ϧwy¥k"˜Æ=­Þ}ìúÂŒY/…V)šs\í.íD‹XYN´@ïŒ#O]¤G‚)®Dg„Š!³¹J1«v¡?#‰ç2 í/l¨ ƒjÕd²v]¥rKµDé|é>öœä›òÃܬFÓL-(•w†ÂÌ v*¿Û4¼[/epJ¡í²6¤žR›òžû|{®_»6|ó¶oXwñÊk®–T4[[l¯½þ“–’ÿÇŸþqX¼xq”S~©så7«ú8E=¸\}d‚0Ð]ú¾àeùº¬%I˜ À’*ÙFc»âo—Á‹ETP£â,5dAýʾñ'űGI$'¥‚~’’Pιõ³ŸµÞ$çë,_ºÔFc¡L%qƒ#~ú"¥“îcNT½g’´øƒðbÂñ=GüñêMá7æNïk&©¤Úሑ¡}§æýR¹b ÞÜ_TCPÌf(Æ +ÑÒöK—. õÚšØ*éï–OZ™d—F$ÖùœÓ¾¡SƒÂlÛº5lÒÖäCG›NPÜZ¤×6Ôë4…eZ‚:¨qäá¤}ÎæÑÄþ!‹E¥ÎÌÎתÿ~»l´ÿšAGòR­m7^13TÓþlI’Œ&î}}ø d±ãíwJýÈ´Ã$©úL“ŠÔ5ï¹:Œ3NG&ï üèÁGVG…U\ê ú)³#½ÂôpÃÂ&õ/¥i©‚–­wYƒdªuvn0´«ÑQžkÍ 1äR˜8²ˆ¸gÐ*X´÷^1Vœ0+CÈ$½ Ý£à¼kÚb@ÌFíÒ=a-˜áb||c½ÂŒ I‰ÿä¹+@2GDhÅ¡²’€ÍóW—®í=¾z‰vž( Qqe¥—aí©]'%Oýwä™=½íRÿapBÊ{éå—­`Îñ H<ʶ˳Qßh0²¨…s{É@íÝwÝ¥ùLÍᩎß}ÕÕ¡]‹!›µ˜†„:XJÒÌ9òM…¾'-¶¢Î!bšøzHÓH¸ž.-FVߪÍX©¥ï»{Ö7îD…,Åf”Q.ÐQ £šF„A¬Êúá–~ù¾'Âsë6:‰î¢;~ÐÁäI5¹0\xÑáü .4-P'á§·DDL±$úu}ô8¾£¬^DTGK<ߌ߲I€¦L:Õ@0=(*!½¶/„­°w>\iÚb,'I=è`€yi‡{…úÖÏþbd$Ì•+%åìãì—‰$F\!u=w¥2¢™väøC½øÙ–á½÷ï WN~ó|é JІ9êôw¦F9¨#þ*P¦˜/’lgÛ·wOhÐ\kjKÊGgÇ7jY Òà ðܳυçŸ.¬\µ2\÷±…ygîùÎw¢E‹ÃÎ;Ãı£½wŸíƒ€2Z¦Àö# âܬ3é’tJiB)Ó<¤ßg÷7]¿¨U;Ì”H[7kBèÐóÿþÐsááëNý®ÑÛ­dÏœ93œ'+ã×ßÍŸQ¿¨a€Þ’™Ñ`*£·Ff•zç‘L×"¥ Ç\̓bB_Åyþ8&p™z”-HæëÛ+tZÝD*‰ ‰Lm‘€rO™(bŒµË³@ µ+ÍfÒ ¡Ìô[ˆ"¬—*Ðõ7Üä£PÛ4ÿ…: Rމt²nœüýOF”qˆ¾ÂðÌÎ þY"•_Þµj~òÁµ›ÂC¶„I:åîm2zÑ -{$-©Îê(ãÆëØÒqaŽöqO”%vk°zÔI;â|QÝvÊ$ÜÓO=~ò“‡ZðiÒðñ×¾òWåÒ×_O?÷¬†ÙC=TÊžzNWD!pdÕÚaˆ¬þ»­hBÁIwuÝ×7"ËŽ”T{—´ž{øå°qßO7tÇIö=ªQ¦ÏæJòüpƒF78ÔÃ0†úÐ:£¸R¾H~]†Ü) ¿Š?L4E9_ªX,̉÷*«ÄUŠ º²I¾‹"Î/»ƒ¯½¾X+ß¾éà5!òÄ}Žmb˜ K',¤$A8ŽOR"l=*|êÖO{Û ï—/_æÕTÒ28+,q ¯õ$3L‹4BA£3 IDATΧº0Ü5Zw/%\rÅ<ÚÚ½ûýWòêŒx‡i¾°q´/ÄLœÆ7sÆôpÅÕט©1· @Š9Åiqd ç2xü°¬0ýL‹56naÞ]á–ÿúEäÝßþvØ(‰”zR[ci’au‹@òÂm-é_’+s®Ó^jƒ¶r˜¾æâ0 (|w º^¦ÕÖKr<Ž:­Å¡ÙÚäðaY®Âº;&ç8’Lø¥ŒŠè("Fö˜5ÊÓ×|iH"Á.å -˜ÕÖè* z º²ɼd`°T9…³SÌ:½7s(ÐMÑ•>I¢ÈBÀ7Lò³­õ¸<8Û#û!Ö‰Ú{ýM7…Cÿö°]ŒÞѹ++!dH£cQ'I§JIÀiu¡ 0‘ZítÅ ÏÙ×gúf¦aôð††0DÛÅ¡Úñ±P–€†ËÊøŸ!4sÖL©Mír4zŒ3“ôµV;›öê¬í×—, ›eeþõ¥K´o~]¡…óuô»¤ }P ¯KŠdè]/Û6o±µpæ;™‡¤­¼çZ `½Í>*ËÚ*ïw=«iJ$Ï‚HÕG:§òuFã'Œ—é³s¥`??Ìž3'KNóôºƒÖ _eŒdi,þúUü¡ƒVøþ:À8ZaB™¿ÿÚ%ýÿLWÆ )&È@‰Ž•µÙ³gG‰ ·šˆ ï³²ç"ùý‘1ÐÃcN‡!6./Å24Ä¿CéèĤ35”i¦üÐÇ?ný…_ðœ&Gm<ñØ£¶¿W ¹dÉëçÝ’<÷îßç’%¿×Ç-ú÷WŠŒÝj”òûDXˆSö;TÚódãt¡æx.\ …™fVý&¾H ^9¨Fó¸ZØ[³&ö¼ªÿô.eúóñ|®¢R n®¤m@œ_”4º ZÖ^e ’4d)@2s€¸è¸5ÎZ†6‡ç2Q`”µ‚áE¢ô2»&2áŠ*Éa é ”Ë¡ìîèÓ1‡)• IHì,aAçÁ0àr4*ŠÎ‘(ÕcC¡8ò"gð,H—ö:í?t¨5566†áÃGX:ê5jVs4”¾ä—ËxÂø0D‹'5úÛµ}[xæñ‡½¢ÿª†Á”v¢Ã ]:î{Æ®ÅDªIù‰Ç ëuæÐäɓåïx§±š¦Ê|Ý^ »üÁ÷Ã(I¸Hî¨mÜ´ÁJþÛ¶ïÐP}¿Ns|´?UMôå©þXó)µî¯(( Åo¦«S}ÓQÍž5;\§-‡¯  £Ä\`b–o·æy)$a(+íé.]£mF}k¾û’Rä dц¿”f÷_•§oY‚¤%µ|}‹jšÒ› ÑY:ƒ&$ßê(_3ôPCC0}VÏ9ã%åþvT%bcÿ‹ô(µqÅÕW‡µ2Ѐþä‹/¾ètÙKœ5 < M¨H‘pðir =!øQ2¥…ù·j eÉgÊÌš5Ëv jŸúÅï¸L5ŹڢaîsO?!ÐZçyFïtQ=%pLY§ŽqqøÁÒài¤ŠïJÕ’$MêLº/ÓÛ´ÍnÆôé:eqvøˆì$Þü©[Ã!í®Ù§¿¥‹—„WtíÊÕ«%a½îNŠ]Q»õ‡Šo½Hµ;Zû¢ÚG9W‘¾B—–æä=3Ý1EÄ9Ú“½pþ¼®j¹d («_oÍT§µ[*‡êTó€}3 TQý M”Ù}ÞùÞ{åeHyˆÔ€<ßIÎÍ•%H¦F`%š"‹c[¤ŸÑ£F…Ú…Ñ›ƒ)*Ä=…„è"3l/ĆšI=*=+C¹J¶KÊ}æ—>î¹û.å¹Z€¹:,[¾\ ç<7IZH0 ç(Èœ$ÕŸ47 ¶‡Ôñä;u±p2eÊTÍï­—\z™tߪuhÔ¼pÍûd‡PÒ$yÛ¦åþó>‡Y£³²éœ ðpMÎñ(RÏD¦ äÒÐÙ=üŽðÙaJ$È<0áG¼m²I‡óô3Ï„ï)OçH¢zוW…ó/z»Õ/y×åá÷ÝÆ+Éòpxþ…çtlÁ<Õýíen6`b WUõwÍiÖž÷¬ô³“úŒD>U¹páYáòË. ŸÐü,®R'Á¡h%—ï¨Z¥·‰j_o޲Ùx®õ^1Fœ_ÄÜ4J>ÍÞÒ)·wÅZ-£œ§Æ€ùòâ=Dð¶·]ËЮs] Ç÷ž_B:Ð_dÀÒÐE2á=g/szçèôÇ¥É{=0veeµÏ’nšÙî»÷>©¹ì±á‡~³ÐÁ!Ižû“Ðq†á0¨!š_l(Ö"9j8½CúœçHq¨¤p@ðúÑG?q­lAV‡ÍÖ…}4lܸ1¬Ö;òÁBe2zè9—[À‘¨å¸ž•Gê9 ¹ûʲAWb1Ϧöʾߒ~¬4g‹„øèã‡ÇŸxBÃÐYZŸ>þÉëõ×]§t…ïÞq§Ê]¦NŸaC$7m”eîmÒ:ØöH7ó°,Q(.Jê>v¨,z¼yR$s¨S´'È uÃuÒÅ…þEV6¬³×ù^}G­Ã#„M‚h¯Ô6n;—Y'´õ–ç¬z»ÄUú0JÉFµ5ž—$èÊ$M(ÇŠ#$/¬ðÀï{ÿt†ð7ÝV=i÷Ð[Âtivcx‘\|.‚& ‰¬É@DÌÿÄ…ˆÞ‰"à••ÑêL‡ò}áEo Ë¿nIqíºµa°¶ÜmÚ²Å61¡NrNDÂ\µ²†=jÄH`Æjh³;Ð)e—Æì9sU¶Ía®ÞÿX…fB]ç‡÷Þ6nX6H²¤`ªb-Q[‘#˜¹N•`HxÒNÀh£Îs©¾{»&€ì&ÆØ‘·,^žW¬\–kÑ葇çéÈ‚wÈ8òu7ÝhÃu²ÅùÊ+‹Ã‹Ú ¾jÅÊp@ÃṖµÊj:‹@üqæ6m@¼úqst-;ïO£'iNEüK.¾8üò¯üŠÏ©Ó k§.Ô?õÃè`Ù²¥–2“…öKÉwÜGÛmÚ_®‘R?gyØVJ‡;LÇCظŒâ‚¾+552\Y‚$ €žd"ZÔÚ¢|̘<õŽ‘c“žgÈ„ï§H.é!áAŽëú¼/› Ä×sÏm’4é’JªòxÞ"kÌå}÷î»ÁÖÛ}¤€Ã“¡tÌß¡xn"eE&ï”îâ<aݧ]+ì~Çå—‡MMžB`ªâU ]—j5š|mß¾=KÒnÔ·ú)é}¿ãµîù£ì Ä’mv<pH8Èw ŒÝ~Ž(¶ñsª2oãT†lO>ùDxâÉÇÃôiÓ-…}äÚë,5Ÿ«Ý)[6o <ôíèiO<ýdxÛÛ/«Õ9H4 ,ö0·Ù!Cµ¸7KФ£™ªEš:IùÓT†_ùbÜš‰}M„¨z‡~t±K3W:™Ÿ<ø€Û$µ‘©ÎŠFÝrê¡:r2ï(uÚ^2‚ðâžvV1—]ËgrÇÛÆþè ÿ)c„<¢K=WvwÔIjbHÉŠ4.1N Y|¦‘9¥óˆÈ@÷É:O —âNÏÌÔ<ÖáƒQÚ)«{ ä,•ôe×k>üT­Ìþò>îÿÏûà š/{YG4‹±·K/3Lׯ»bÒÜ=ºÖ“èšHšf4Iùz’ê ©nUFÞ£ùEæê‡óŠçweMç QkÈ„1ˆb ¥´b ¬ þYp`ÊQÞ’<[§Þ Xê ~~ß|d˜¨»,SÜg!ÂZ?>òˆ†«†Ë¯¼2¼óŠ+ÃMÚk/óÄ2f­ŒóxžNNP~f4Í”9ׇyåÁ0Õ1yJɽ;gêpD³«×®ë¦Y£àúl• š@±7€tzâæ#‡HÛ[¡:‰¾~à‹òue ’Tyw Uñ¥ÚÇЖ4Ø_ù$zZ 0`‰8â›ô^¡tËÎèâ7,Ú`°•ƒ£8—¼öø~!Ê-ˆ\ËÍÞ14RCbæÕ†K²Ù¬á=' b‹1ïªQÚUG€6zŠÞ#­òîWØIþŒ×ŒÁƒ‡˜¡çig ª:£e® ]¶4$zM*:?òpxö駬"sžLµiÅFÁe“Oö¸ï=W™ÈP¦j=î»ÿÀéè•‘Œ÷’yÂ`¬ä™Ÿ=ž•áŒoÝöp¶$Êw]qU¸ö†]×Q}ï?¾µ‹h´Ža]%É’ÝR[ÜÍR5Úc:ˆJ÷y:¾Ðç$OÃ"Í%—\>ò±ËzÒØ.`Øk:Høƒé¡ƒÒó¥#5 RÿºIÍ©[䢺cý!7÷îêÔCƒµhÃU Xòìý«ò|[Ö Ù]•#úŸîya£æøvYʰDbÑ'ÙU†2‰yã<`”(“´c°ÌÈ©]sžÌW5k¸´7²}”‡øÝå¡¿~i8ÎAY׉Iïúö·L¤Í’‚;4g6uÊ=whg·•¹1,ËJ/GEì—¢ôŒé3ܓϞ5'lg^qÁ‚p®¤¤™M³äÃp”@”a{ÛÁÀ;¿õm AŸ´’÷0MºŸ#&ŒòV2'¶éo)ŠáÒjvªÓtMÒd1ä¿K XÐȤßõïÈn«n¶üèGá'?þ±çh9&ø=š—½éS·X/v°†¸«V,?úXX¹l¹ÔÀZd ý°:0í—ªÓÖ 8Q+u¤(®ô]_ÏC2U#€ ÎÒœê¹ásŸÿÑZ´z%ºé)ž$Ÿ­UéÙzÆ€mãèÑ·n…ÁšèŒVÍ‘"Hã[·ÝÓî”Ú8®q”í3ZNÍ@ÃutL©û],¤NóO(Õ!5P_ÌÅОsÔ£y™ö+¾ƒçŸâ ûá­ô‘<Ö$zMÏË¥ŽµtÙ²ð£ÿÈæÆÞ¦í•–ô6CÐç5»yóæpP€ƒe¢5«Ö„+VXò<‡Y [(Cò¤ql.r™ìåv°ö­OÖˆ€Q*Mÿ勿꼦ÅÂþ|A{#5ßõ­Û=gHá«ÐêïqÔ(gŽ·Êió?çÎk¨×µÁñuǽµl^•5HvWËZhPÃUKr²-Aµº1 =xˆç¼D8ÈËÂ5ï û‰¦0}Ʊ¨X«a‡‰ëq‰Ð!T+O\C4|AÿíºoÔé‚;t|êO¬ú¾âUïy¯T‡‰Ò•K.MÛ%€Äß@o°bˆe ß¾ý›áÍÇ­\µ"L×÷XéM\î¬R(ëq ­j¢ô ÏDª„xîÄŽ7MâH‹3d=‚ ~EÀt¹q!½”>YÉòætW,9þt`K˜/¿újøßÿöo៸.¼[ó—³µÀÕ1a¬:¤&Y:o·£qÚ¯>söܰtÉëa‡¶bœìPÚ/•"4P-4+€¨—n l_u\(îO–®êE^èNÓ‹3šp¬’ú.éwEÁ+ÑÕ!醾,…z¬²£cÉÁht õKÊÊ55¦[\ºïËA¯ŒØ8Ã;Ú­ìin¾¯˜Êãý€Iˆmð:mjEmÑ}Ç3Œ¥_¸ÅÄÓ)‰ËCìø¢Kx?ÀˆúŽ3Rúî“NÊåɉº$Mæ÷»&âN«•ªeèg)ÂÆi9ËgT—$óöIÚ[…cê=Nâß~Û7£ X÷'ûX#rݸ.¨”-7%•–^õóJ]&àxbBýü¸ŸÁƒGæ.¤ÁHé&Pro¡T.8Y˜t•Wü¦SÃÓ·ð-Mü\«þWh‘çu\L¼¡Oz£¬<±U3o{¤ïú“?(¥õqîÀ–K"e·Sà¹oßþ¨~¤ÑÇs»­ð1Ê2DsÈÃ5¯nfÎP‘ð>—?=.ÊÔçžs¶ý:dðBõèD\’&óß'¦@9L²Iv3é*BÖM<(+ëìÓ¶ä¸<:9´„Oå¾yÛmáá‡q¾Èñ’€kL/ hÖˆÒŸ^¿!&FÍG”Ê—÷;‘{â±$$)ÈÖnôœÏ2 ˜ÒJ™ÒIϯïíráýì Š‹êºYª- •ÂcºÃ1g‰=¦ÑRRcmMmX/å{,«s0Üò¥Ë=”Gâ «e÷ñæ´@‹…¦E؇=sæÌðÞ÷½_8KCû¦N”M¸”¶zø¡n(ÿ¢Wtàš†ï´…ç#‘EÃàMz¾…Ú³6õ“é!æè~-º‘ ö:ÏuÆyÒ<-öA™½˜ Y[n¼éäï›ÈiOWÃL Fc^R ø§>Tïâê¶Â‰‚„Ë4‘}ÈJ±r˜9‡9Ο#d1¸™c˜ADTÈ@0ý4ü“=@·Ù»=šä„¾=F1¤ªÖÜ  ä¸ú ^EqŒ;ÂJa}ª³É‚!q)m¤òÒ&©óNæ H¾³§O£5ßEñ3ÙI_¥Æ2;"GV¸;¡$êÜ×’úî„…V8æ:6˜F·1Ýç™›ûR0¤¤y¿R2rÃ=yÎîóöC9°hd¥Î,rUôÙ™áVæ9`½(Õµu`ý`±7Oš¸éM¾tó#5šb³ø}jcRûÇúajw Ì5*Ë䃽êk7nÐÜ¡Ì×euXh]áXÜãçµbu^º²\1YS¤•ÌSò‡ªÚI‘ Ã$IÖùeÊ[1äÀ¹ ‰ö?à Ôè!=Ô $¦(\E003Cîvu# âVŽßü¨ˆj©¤Š:žùž©B´‹qߨDYL¡ï;æ! Ú¸?\sMLÎ)=ÈÕkVÇã´˜@¸¥´<þà$ÿHüy%Yq'Pê2YAºù€¸J€‚?/Îõ†ó¡w]2'-Ï[ñ>ÂEÊW6ÔŠ†–«í™ÇcÊâºUäµ0"½AŽð8].eŽ@Šá´êçgÏ>SP£\žwW^ÓÊ~§€ÐD’$Ž€#jé(+59CmŽfcÂ@w©NT9,&“Y‘L.¼Ÿa`! ÌãURyú=Ÿ9 –9¼LCp®¯Ë€Æöí;Ã^-ât\Ižüt:R"¤“L’ èA>¡4ksšfèh…QF…SÙŒ3øÃSôcprýžlò‚Ù¥²Hé G·¥è ›…wõå¾5@æÞ—FŠt†"?§3®Ôe>úH¸S§6*#HIuÌóɧôó“ú ¸àntò8×…®ø³Àø€lkBÕ”‹²ZàF§åzÉòÉ7˜·cWNÒŽ‘ªâ=qç]ƒttÓ|$s²§S8ÈçãtÞŸl*>yï5-,ÜüÒç>o¦(@ƒˆ¤Žúšù«fÀlrTF¢sÀ_y™ñ"Ò&g¶kŸ5+ݨ{àØK›Õ§ðÇRäQI¾úX0OÅÄüwÄ´(НOÓo¤Vß#0ª FÕÈ$§0kŽÚJå¹çd¥†¥ùHKY»¥ø#d@ Ožq²ä9óã®ñÑ¿ñËÔìY<ú5¶prZ#4î¼ãÛ¢#Ie’4™öp5çâ9U·ÐUËh‹ôjoڼɋ*ä—GÚÔ|5¤è…º9"e¤ÅÕu oû„¦3LW#t–‘wvªžAñÈá6ÀA/×4cºmè„B ý!ŠI˜Wh ˆ Æ3c‰a$M3nI ÇÜãO~š,¥˜?½ï ÓËc®Ää/ oˆyß:­NÓ)!w7KUËsÛzß©vÉÀ õ‘F2 ¹9lîŽÛo #d[‡–¾†‘&¢?»í£Æa‰Ã')’¨¸Ë³ÊMÇËè¤A×·ÂP›z QTk¥µ‹1šÛ*‹6À…ƒìŒ%¦1Y&‰/ ”G¢yË6kd,{„Ûe-f” Äj€$ ˜49¤—íÊÇã:Ö³fä·6M[Ú:ŒðÙ¶K囬—-EqÊ®C<æïN† ˜oóšÊm€TÄ Iƒ2æŸñKŽ\äAÓ÷Ýä­XW¨J©ã˦5ˆ'ÅÁbY]³9ÛEÙkýÉ믷ÞmJïT]é Æ|‡ ÍãØ"ùøãyÁûªÐ#¼P!A½LŽGF/’3›öîÛ«òQ—ÅÜ&p„[À{ÞÑÍ¢;Ê–XŒ»°hùGoWä¶VZtÜF4øÀvˆ‰†NÄŸ=õ’~ï·€§Ù òˆÂ#ò—Ý€?ÌålÑVµàf­rwhòžx àÓézÿPóOœÆ¸Cy™=k¦r‰ÌLÆåTp)–è)‚Jô<µ¿Ô¯ÿ²IºTßo$U-Õ/?`i¤aå ­Wg® ʯ˳ "~›Â§kjrê0ÍY§wÅ+CoéR —-[¢³w÷}÷»Å×§ð@„ÎJ;d´öÊ‚‘•ÂUH‰ì1?¢78@‹=èr"‰2Ônçë…p‰/¸Ïª×¼0RÆXØ@1rä)‘6Pf » ’4=é­Ÿý¥HLjíBau_ÊÌ£'¶3ˆÉy˜š}aI3ë^}ìIØ·gŸˆ±M,U<ëøTÈkZC IDAT£#$H‰áî;îO<õTؤ½Ü ´ßW/Lä>P‡8¾2»y*‚È©Ì#qG°,Ôú 'GY+Ïù ½ºLg$Ú,¹<çÛ—û<äïÓ·]¯)Îcé„p±nU¿º(‘á8ògÏ?^|áç9¥€LeÍwÊGŠ󵿔zÎHÓ>`ŠæsŽHhpwL¨Ñ­ ¦£nè®Å¨¶LŽ’Eûáɡٷ§´¨gDäÝÕÇ‘±7’ $0d°¶”4Y§+ ³@Øf]+è¶0ÇŽùŽ@ Q!9ÚéEÁ„šîwìÚ6ËÚÐ6ý±»¢{–ʾ=—[¶†%Zi_³zµvMò·˜×˜a—OudIiU¹ôĽÊãÂFIi3[+ïBùW*â,?û3½Í„E‡#tr‰‰¹¦ûô®ïkªp¦/â÷´C&2\ddk›©sKñÒöYa•sݪ’(ï=‡È 屘"ñ©«þÄi">Ä{µ†°dŒäG²(´eã&ÓÊá„DwÝEæHŽÿ‡ú¤ü8€4ØÓ}H«Ôëeÿu%€ÐÛ³!7{·‘,ÙYƒ~/fÿ86¤t¨MœÅÚâ):T0‰ÆVYt$ë4ÔÎëp¦pñ: A’aÌ[£7˜rZ óN )È FÇ¥+ž°›ÿeŒç·Y_Œyø=Ì÷ ¬>oÙº%ì‘zk }*]§†Jèc=¤S WYBf2çT#óH(“¤°äÌ\E@C䵸‹Ð8ª?Õž™Ððª-›|ÝÙ©Õ{}Ñ¡´4¥2FpJÌ_ 3ÄžÒɹS.úºfu­`X["ÏÔiRýa¨MƳbt‰Œ°))Ú;–7 iˆº‚ÎmO`ÇUL³K„¹âŠÿb¼îŒ•?ëŠæ6mÙ^{å%JÖÜ|@_j[cÖ‹d—hæ¢=î[èp$}K•Šüˆ¬ýõ×þÊÇoðà( Ëü%£*üYÝfÞ’¹H[‹ÊÑFwIÁP)’ùHxêD»t—Æ™î—êàLÏç ås¯ë‡Õ‡/ù7£D’Å;˜ ùLLDB„©£äbÒOÆ\|—ñPb%¾Ça©gÝú a³¤Ž À•ÎÙó$þ°˜°rù ã²\i¯ 3§Mó1O%¬î’òp5cƒŽî]<»B¢„Uq´-ݺ^ÃH¼õ“!ƒKäÂb[H¼'£Žã189áXC€3•ñFÒ€@S'”ÒHqõ€N£Û76rlºÀeó³Y»Ë;s¡®U‡Éz¥Î™Å ¨¦ºfJ#vB¨×TyÚã)Noüÿph"$0+ó<'tFP/Í2º¼4ÛĆü –IÙ!Í®)<¶Qi¿nŠÚ%[tÐ ¦ÛG‡Ñ’$md·K¨ýðÆ©÷ ®ˆ„ ø£Gxx@VMþú‘pG$˜Á¾úQ͘Ý#ÏÇ{yçÙ‡WmfýD6±\½GÃïÞŽœ…pO†ë”Žäâŋº m„EèBñI0éåïã3ž `œê@Œwt׎Ðñâ²Ð°z‰ü¨(*"×…€QZ©}¬¬À0ÖMŠÏ‘š‰ã݉ÿB hzªÃ|-ݺ}É,gjÛ •ò¥Qîëöí ïÙ¼/Œ•%€cý¥ï]Ǫ'ž=TUb¾+<>nݺµá%™({ò‰'­‰$¿žòîŽ÷GíÂJ5q•™³ù§6ˆ!1‚jÌEr^Í%éö‰A”7žüÀ=Nà¨E‹A»÷‡AÊ 0\õrIgU~ÞØ0ªŸd¥›AŸ#¡)€\añH~í’àÉm»ŽŸ Îv×#Öx`ÃÁ¤É‹ªXé0G‰¤÷F´„ Pîùª¬¨׈‹nj ëZá^åf~2JñêÌ•GŒ cÉb.hrTÚDø5hN«?ãutH£@Ëÿo57 A2¤‡F"VâFjõ÷Lý£?ù·q)8ÂG‰ D`ð9ñ^Ó ÂäÃE?Œ£¶‡|ÿ{:¼kr˜0q‚w&œ*‹Íƒeåˆ2Ât­’dï@GK ά¼“W…1Xfïý%3±ÒT;”¤6BU픨2ì( Ó3³O„i;"]¶1´oØjfN •S›ˆ^õ”…T‡ôYita?¾%ýâ<Ÿ?:ޤ&À0òb ¢ªüðOŽ»ü³W›É‰ÊCÅ| ÒyãÕÇj#¬¬Ú¡Ö¤avÝ`ÕÁȆ0Lï tzKšÄË@©œé "ÀȽ@‡o|îùUª<·IÊc£A;‡Òã¯JÚ’bú'òK05Ò"5ž¿ÿÿþÖ§:425A»×bØWR.eà T¢i:Ÿv)@òŽ”é:Ëfüø±aœþ’êOþ»tOyÝé&t Iû¸Ôpl¡:ï‹|.õA ‰Â•H¦á ˆÌsW0¼ˆK,ž !³¡›¿T]qñÊG’&µ‡Å”ÉÊR—`ÿxJÿdQ¥Œ²²ÂÈPгIR§s ˜9žý§Œr…ÉhПCÒK€9QﱈN íÈ U˜½:)’zPÚw„–×V…Aë6†ª¹3à±STqZ$Px€¨± .Y^¡ãЗÒ*>R88ÛФ DŠ“¸ä+_7¾Ï‹Ó†Ó+$yW`¼õhÐ=§Ï/yª¸"‡^0%JÙUÊ£@ówH‡Ì52ÁQ`™Ii•ÝÀ(Z‹p¬¼8ö"ý‘gΧ1=bþ¾;ùF¹vLĘh(‹Ú`K˜=͇Âë‹k¾°ÑÄK8Ú°¤ŽŽÒnê i»ýHÎgÂZ¹íc¡gܸña¬þÆh¸ÍÁ_´CwôVšÇþÄ_.a,H&ý4ˆ‰¦#ØœñÛ/¶1Z‹Ñ"ÃizLKЉñÔz<›NElúïÞ85j$ßô”®eG¸÷Þ{tÚÝ„0fÌ8ÙݦùÐâžî”—ôŹ2Îáð-:=±N{jqdÄè>¼ìê –Hz&’©þjj…B₆‰Å:e½À<¬JAb¦oÚ÷ ‡Ÿ=T5®Ó‘óBeVÏÝ¥ IÉùÑÕÒ¬$®¥CƒdCÚ}9Úˆ:ƒ1ã< r¤çTF·!?™ qéª-%aÀ±öP[‚l× Ö¥Á•ßWjÃÁ¥SCåÐÁ¦ƒ=Ú9Õ¬¹Eær™od¾ÙyÒb“Ow. ó z1ýdùàBRn¯6gÏýH¾¥~7\K?è‡ôñ;x°%|ý¯¾*ðçú@ºÅøÃ¨.# êŽþ:R¤Èš'z§16R(…ËäÇ#),ÚŒ@¢‰A‹î2Æ6p,H¦& ™ŸÁ >{Nùó_O?ýLh‘Éü‚ƒÞ¡ ø¶Àsôáò‘ELL-ÝD nfLBÛ¶m×µ×MXJ¯Zs\V”ÞHää¸ ãLJa:Êsÿþ½RŠCeg®Í9ÎN×›ìžgçHeð°XÏG4Dщj e”ô§@õ‚˜*…Ù¦³XØæØ¢ï‘X†ê}Û®CáðS?Õc†…Š™3CÕÈ1YådÒqë;ìtÇã¬úÃ| Ji§²¨ž=”¦4‘ê‡2ÀhźBGlÔl Z¶å‹’#a(Ë䕵aô‚Ñ¡S‡ÆQ^¢_º[—ކE‚ôŸŒê$âàDâ ©ÒvìhsÔφIúJ®'),½OW¾í.¬Z™D²Ý(ýØM[6ËÐă6Ö  1¹QZ(cš>Ìúñ]^ŠL­AݤªM~t˜óæÌÕáfãÄ lC¥ô·¢ð =Ó¸ôþ½˜0aœcçèÈÐ×"ØÑê„Øü D±xÑ®’ƒàD€Ôs’ x§p–&ôýýZéž1½É+‚5u5Ò-Ãl™˜TÌ~2zbÊ2Y‡z1\:y á”_1s†~Î3-ùNy·?Ï Å/õã!*…–Û¥—ŠÖP%ÿjýÕ*Rº“‰z­SP4 ×ÐW÷,iy#Të;äÇöíÚa²ýåÐ>V²g“†á#ÆO’j¿%LY®‘tuTÕ_5ò\˜TùR9|%³dYyŒ¥%pÔñ„É‘á=oÛ9=RW: ÊÏyÏŸ£=ΓÆ^Ô6ª>`ýù-Ë¡…1ºAYyAøîx3Ç®WG–Üñ´}>,<4Lœå!é8þµöhcé‘ÜaT)‘ïðCúEšdÅý æ.±J½Sœ¼£NbçC]ó(3u4FGçr`Ù[ÕQGÎ1ïRp’p ê0;/¢ýÍÿû·=tHa R!ü ZI„‘±2 !&‡‰ß&Š”g ”×Ã÷î¿/¬]»Flj°zûó„ŸÒ>Ñë Q££*Ř*x[EM¸dî˜P=m‚ý˜VФ‚:†ÎðÊ–fÓ¡¥º*¤“ìó æè“aZNî<^âÒ5/Á¡^öíoþ»¬ðÈ*8Ò¹òI¥’GªA0å\Üaémr&ó¬”'ÏðH‡ŠH¬%µ£†ú ,5m4A«ÚÃ%­²WÛi9ü[ë'_g¦äÌáhT&9ˆc¡ÆóÑé ŒÉÒB¥ƒÞ‰ü @¡€Vüæa(,9ê‡a)÷ü¥x8âaåšµ>)oŸöuCÀ'‹ÈÈs&N õ~V_ÉÎ@ ÓdŒc ˜ù0J¬üfås˜š5ž^5 Sÿ K3iZArL‹]¨EŽ][³ø‘Ш>·„È7*lÅ΃¡ã…Å¡õ埇Ã;·xî´]+­ž[œ1EzŒSr]†Ú¤¾)‚–â§B²À]+p¬?xÄ M»%p&ˆ ø ×Í*jÃ¥—NµSdž*阶‹> ÚîΕ›­-ÐcÖG\­âå,íFTä,­Sæ~ºD³´aÞµHvßþæðÔ“O¨Î#…bÄ‚¡q¬ŸØî”É’•÷f½Ø¦ãm½À¤Èò¹(½GÅÐÞlK‘“'‡ñ“Dcš2ð”•Òy+º9ÜN‹6Hn#C¶Ô³…oÄÈáá·÷÷4?ù9MЋE0‰™*€Vô PXÍ“a¯Rf´¿‹„Žƒé™RbÓí·ß®c\G[or°rÇ`éÉp0åš$İŶ™~¾Ê²“’‡™-çé0 ëbüýäoŸ”­À…{šC%Ü-ÇI’GuËŒÔH}uEEuxY+µË;eéZŸÑIðàbs¤®T÷øջÛCÍîuaÃä!áÕÑcCsíÐ8$DDÕÇ;Ýå>+# ÀJNü'ÿª#-a¤Vj‡ìóÊjEþS0¹T®€#SÊÓ Z¤sÕIß²#u¾©­Ò*¶vÊÕÜÂ+6ðùvƒ¥K8T’'TB‹d+P#OClÂSÔSëá¶ðçü‡š2’Qe$sûkE›EOJˆ‹‚ú¸ãýš[e˜mÈFT½¥hÐ ,´É)ìVËëü’æÉõ–Ÿ3åÝ€I*þähôÔ3§kCC}˜¨Éèysæ„E‹uð¼ÂrÉñŒ3kBq">ˆœÞ˜ ñôþ ü,aH÷Ì ž¢Ú-F¾ÿ{÷Ê:úHI~CMlµ'ç»q‰HgΚ-%ùÑaíš5ýsþb~‰·#Ô(BÈ)_’g1³¿ a“†ÖËFiâ~—TIÛœ ;¬Z‹J6 × ¯ ×HwR“¡VRöê8'ç©Ò9€ÖŠjýñ¬úÛÛÒvïÒªñÑC>ŲS T¡a/ÜP*Y±YˆàÝ-̳¡ØM|ïúÓòLü*÷Q5€¼]÷)ÏnS=TëfÈ< §5RŽîTGY)õÂwjXÊ¢Ò¯­ {4w2\-xˬ˜”¯;´V\ììtê€mH{:Ôî¹ë×-=7íe:  jÓú ê?JÝØŠÜ­Å›CS<ýu#dq|Œæ"§I?rÜ„ñš÷YàŸ·"@Ro$!šž\µ¤™ÆQ#ÂoåwÂç¾ðy«{ÀX€Œ-ÁÜñÙ`¨ ’U]ëéñÄGrþ&ÞFiR÷€&þ/¾òZ¸tù óÑÕD­¢¢RÇjˆÌáQÉÁ€¸øÝŸü{»ÎÓ¼ÑäI“¢E‹”Xdâ±ËòÆ}Ç®þH8Å@…!¸Qu÷k¸8cÐþP+ e¤¾ª1 +õõú;" Ò*xõ-Îú®åÝ +IÃ{¹é2‘äŽðo‹×…ŸmØ®oªC€31¿ÁQa(7yá9®ZkWÒŒ~HÀ…Bv‹Ts"PF°ü­>_0axøÊìñ¡ðÔ·šì´TÓ&?HØ”ß6eÁ†"W!…I×´SÖäq{ZŽ„}y™ïOÆ»RFjQmš¬3”Ï£ºè¯ƒB2Ü"´}üQï|A²†¾ø£ã&,WK–òce~ŸvÖl’ ?ôèTRK«J\ÝåÃs‘ êœðI’$'…Qš.¨R;'—:çôüV¹kà­Rb•³JŒ„úÌxI“sgÍ ¯-ÁâMtEàaÁx¦.¢–Õnƒ™üa<^ ³kð`¼€Ìýã?ý/¹‡j¸t¡ÿäòC«äן+RÚXéÉaçoû¶­:J +&p¤ .Fi‘e¢Às–²|P!¾;¡>ܲ¡YCSéaJ’¬Ò¡.ƒ¤OX)Æ© uh¼Z©a·%G@Zñx>X’M‡êxÃþ–ð÷/®;¤ÓÇËΑzHPö‚’®ÌaÒ_”HèÞ`vN¥Ü§½ÆÍ‡ $G)u#YŠñ„Ÿê¤Êg´èÏš.˜ØèŒ)wb&ÍÔ¹ ¾ì¤ÑwHòÀšf©V9Žªøâ½k±†ùw(åûl%µË©Ï¤ÑËqŒê“ºiëáïÿîoëhŽY^Ù&—Xg×+IìaU=U­Q? ³·l‘!h­Ò»ÓÉŠePå#9ßÇÛÂ3' Ži£í©žï&zMÓT¹ o¹[êê-ç`°Iu#.¿ó{¿ïs? $"´h!¦-J’T½qF¸Ü‹ã¿‹÷é™ïqÐ$»5þáÿ>,]º$lÖB’Là•&%@ ¶oç¹Q›=g¶vEŒó*0_‘ÇôçX?yÓ?üU„ÂÏÆ©¬<¼Ãc©Æ°65„ª¡5EI’Ã4»§© rØ©³¦ÅÃv’ÿÜ™0µ£¢ï.ßþì©EaG³†°NLy@²ÈÔ&©ݽC2¸Àg­’R|¼?h=ÅZ‘Ý.EðmúÛ¹{¯ýÐÀÌ&`èhi ¿óóeáÏ^\%ðSÚμ’d’Nˆr©á¸žU¶A¼×j¾UÇ©µ|éûÏ„ {ã±À±4oì—UgæñÆKõ¸1—tWÔ}þß?ü·ñaí«§ƒèY°ŠªjÕXj+è‘ô¶wËìÛf™îCºÌªãP,¥2¦GÎɤHÔ~FjȬýä²õ–¼}KJ’ÜqãþØðÎK/ ?úXF A Ñ_¼dA"P†¸Uy§ÞfŒû™³OÄ®ä®]{Â=ßýŽ%XpСc© E0ÿ{of×UÝù®T’5ZóP%©ͳåÙ€ ÛÐæK óBèt¦æõׯéN^:$„Énšä=ºÓ™ÈGh é$ØÁ8CÒ†´lc0Ø–-k´fk²f©4—jxÿßÚgß{êêÖ$«®$×ÞRÝsÎ>{:ëìý?kíµöÚïþ´™pp×jѳO?cë7nÏòA‰¸@A1„‡ÈÆSaàpßÁ±˜0»§6g£èÙ3R”Œ¬µY§A¨6WkE%³4æ‘9E2ñ܈ÜnßgoÚeÇ„¼ü—÷q Ñ›ËüXÙFÀä.’½Í ¼Ìz p¤Oțϳ¯´÷ȬçÿYÞ$®RåÑ>±ÿ€'½KœhMÇp¹Z!‘ø·¿ó¤½ Nôb†QRz]-“™ 3/¸X>œê ¢K›ýý7Ùdj%NÚ9nù!`_´×z2™ö ã8‘ýãqH•Ý»ö8§ gCñ,¼súB>¸—q¾³]Ô;ûØ«ó)‡ÞùI:!ÁjM°OÒ’«ßüÈ¿µ—e\Ϊ„0©ŽTÒ‰£8Eêñy!æ»8:Ð(1€’cà°èÃÜyQ;Þ¼q£›XŒ“Љ,õðÄÐ_ÎÃE~Ígª€ &M“ôåß»g— Ëul8Çâ ˆGšéB|–¾-”ðÔ)‰ÔuWÙ/ŒR[Uâ‹ÙˆÕµÌù™ýh_«=´q§„sÔsÇU.¢‚î ôz‚XØ­túX’ H®™Oc1bv2>Gv üî–öèÎ×ísfÙ¯.œé³€¼7DW·Uå½Õ°ÿíØÏ^ÛÏ~QÎGJB™¬¹Ïææ&?ýy§¼Ç|ºjM7ð‰9¦ÄSO>áë§«˜¦PŸm—ë5-vt…Ü$kús¸Ç4ý°[þ|vx¡eŸ©ôìE ÚLq8´`›<¥œ¡ šC$½çh@U©“1ïR/[°ßú­ß¶{î½Gã9 èx€ðVèÀWÌOÂÍRêõ’³Ÿi¹+±/}ùHëÚn9gGI(,Yæ‡Î У ]´l©½°j•ï»= ŽLÏZYxœB)Ž;@z*o›ÎJGŽâRF—=uì´½*¿‹wMgS57yºµÍÈçÕÖS¶vßa;ÙÆÚa…Œ\à ױlWÔx}*S·-DÂj™ qÁÈ®“'ñœ-‘º/’êÊ…SŒ¿^·ÅîÛ¸Ýæh#¸eÇYÓ8íÁ>ö”m<±Ó¾¹úUku''år_x@7JsÝ“'OqNÒMsúQ\ IŽMÁ -BøÄ|Üæ´ÌÑÇ┯{Ç™/bñY™^ CäÖy—¦  /ôbmö$Ó‘æ}UÏ;^¨h34šš›mš È™SÍbþ¼¯òÞŒ÷‡$H¢Œêll „PŸg‘ÁNÙuƒT‰ÀàX«k¸¦/}é¯ìw~ç?ù¦ñˆ7L¾3A^:XzëpîÌUy$H.]¶ÜfÍj´uë×ù†P¥xG9c™A›]•€Ç@¤# íLáÆöj~ìk[ƒ™L¬ÃI¤?R8™½2N(Ÿüá¾ç‰Gàž°ÑÏEß+ZÚÜðá!þ¢ûMsðW‰€a?Ëù0/cî¸k—ë9LŒú 4<ÿÉ“§í³÷~FÀUï›vy¿ÐÇ‹>̈*l‹ùý¥ÓƒÚkiçkþ¡ ï¶ûÓ’âÉ IDAT's¯ÇIYƒ&»¹©I ÙäÞ«X]Cp‰%'™dY‡ÜaHN:Ðéè0àóz£eÃ8IëSï÷ÿÀm]¬Öðu Tº8È @@7•ÓbATùH1C¶‹–.öwR-'åÏ™ÿ(F0b뇿ÿÆ7eútTôaõ‚2úyÐÔWk]xÀ’{ç$M–¢†m"Xz˜:ýK*-ýÜÄëziàghmvcS£Ì~fºG!@=…î’ ;e$×øfœ8i²ýÊoü¦:úä1AvdŒ;è•ôDuP –PFh P†8~ýL?ϯzÉî×ÒÅ-[¶ØA¹ù?«¹§¨üɪôÁ‘?/m;÷èØMsçH3ÙäN/|¤„êÈõã@UºXPøB† <¢¥NâãvǬQ!]ÏØN?ÆÝ"Ë\ÄzEqç$ŵ—á†Ê伬¢PØàsq¦l ±Áí l@ÀOC°GÎw¾õ-í²ø¢ÑVV0áÀoú ØF¢á&… ïýš‡DYãk·ã‹êe0UZ°`LÍê7Í6AÊšÁò¤ßæ\ÖI†$Hæ¹1Þbà3F“ü¬‡þô=ÿÙ·|ˆXÂÑÏ‹?Š  âšSÅ{ÿÔO•&Ò ÎLeÇ‚ÆÜï„O¥ô?~î§öw÷ßo›7mÖæQlîuÊÎ=¨]±½å’tüÁ 7jNiªŒ˜ÛtM{°¥ a¨Ó›¯Ó —<²Š =Ÿ~@†|¤Ïç ±Ù3Ç‹x ī޹Bi[P䈋ÌÀ£÷Ì—×Ý1ZîÈFY}6,.KƒMÛþ顇ì§ÏýÄ·bà~X‹O/“„":Žz«aBïƒi‰C‡´Ù˜æ!ãö±<?/m½bÙ2›-1›>Ó03ìËTš.] ôFË7-€%¾ú\ ڤɭ©i–½ãÖÛüv– ³,âåÂeÍOjp£q¦SÃ=”áʆ¬'Ÿú¡}ëÛß²7I|Ÿa06§ÀËæW¤‹c*‡´+W^çšúšLdÔy³ã<•ÛÙõPئpÌDkš—5±[®²8X6²[¶âE®àÂ)ôRþWLyÅœ1—7E[®.^¶¤Ï6gä•V_ÞÞeHÿè#ØO<¡üÓ¼ï@t€2ö%M9–¤Lñ –ïÕ’Ã-Û¶É-ßq} C_Žb4 ÈŸ—6h†LÆpÚÜ¢<ÌENð½´ëº‰Ò¨ÒgY<ŸçuÈ Q^¢GtÌ'è~Ó-.ÔŸ$-ìV~·¤—íEµgÍÔ¦Yê;}áŸ÷“³ê/?ü°}ÿûßÓF[ÓC6½G§=?‘ëä½!‚Ãeã¸b›ÆqL”Ë7”ã†,HòÒé¬z!DtÀ†¹ kï½÷?kÉ¢&²}äªÓª2†óžÙãB¬‹¸*CßM!=çñ< ˆƒÃƒë|ìÛ_ÿ¯ÿeëå‹r¿¶8©y*Œ ó—6GÐŒâ7mŽçË–/“ƒ‚ªP ô2çX:ØÎ®²ÅÒû8R`VhiÙçl±É}zù܆‹d£¬Yò߯ ß9­”yà¾ûì™§ž” NC¯É¬÷í†øzwþOôàݲä²·Ê?ä.m_Œ=$Âü»ÉŸ—kšñk®YîãsÄEÖ«ŸŒ• P,¿\žçߪ¡K:^ Qm±›(_€ ³ìsŸý/¾ ¼Ø cØQÞ,¯½—®Œ’<1]<2|â( ”ôÌd_ýÊ—mݺuöúëû´VYÎk‚105Mâ#@’n銕n€Ì>̯‡*Ö-ŽÜoT%M µîÇ41îüˆÂóOÊÜ­<]þe7 ô=¿´Ë2ú²7õtä’åK °žË;:®¥–+°µk_ÑŠ/9ÁPâTÙÓCýÁEò/¾_Ö¸ïÚµÓ6oÙìîéHÓß@×ÊxfÃ,WØ´Ìi‘¹ÒßÑ3Ï ô·¼¡”®ˆC驳gl"WFçI¸A¶ƒ¥Uó´á2 ê6xéÄBÅ0ß s (³q§â(™[*pRJîl¢ødÁç2uýÒË«í ñç¶A@¹g·ÖA·séòÇØ~Ž „êªv›—úúŒÓ‰yI$€OÏG(ƒaÏØ+;þÊFz–î?ÅGŠ]¼ŸîfEÞ"ÕïNbÄå1r„æô&ÚL)Aêµ^»¯Ã%!¾#>ÂØ2~é/ÿÂöïß/ÏP¸0þWÒäñ,”ô)\Æí”’fý«¯ºÒÆÊc¢ìØÛ`ž!ßx½Z¸p‘ƒä4‰÷¬ø"Äî@@7«rHz£ë @ì ñkÍC&xæ9z¬¾¼ ök¿ö뮹t‚d@áó‰9 Ñ­Ñt#6{1¸£ãá72ˆÔˆÕcÈ\vKÒ”·nÛføÿþ‘½² ÜãÊ—aœŸ;« h:ÔÕYcoyÛ->¯Šn*Ãô‡6ñçí„Cá$²û¤ébÆóntK.üÁ¼" Ù²r -p]6”¶©l¢Ë+rœ–µ"j7Ξ™5Œ ¹çß}ŒwÇ6°ÿßç>2H¿Î1Ì@«Åéòc …ÅÃŽ×vØÙÔb*Ë/¥DQÞè~‡yÈó"öüùsµdRb¶œëF¦ ¦Žc!^§c ÀÉrÀDcÈ|%[v6hÜsï½6\F¼qx†åBO `’"G6p|õ™tÇa¯ãHÆAF`ÀD®X>†ÁûÄmüÑ}N@¹Fë²wY«ŒŒÏj°EFnŒ§ãËÑj3Ḛ̈ÙCì°åxy^“3ì*û9u.\¹zÊ  ÜêûúÕ€‘›;'¨‘=#ƒ‹@š\¬Ò@A<·ø²‘'˜Ï|æ3¶êÅUöڎ׬U›Š‘èÅÀcI%GÒE‘.–·òÚk%v‹»Ñ ëÖÖ\³sÕÇla°–½QLR8ÓsÄyÝ쑼Ý~Ÿ2ôçÏ/ŠŸ´»Ç“¤í± Ü`›É2ûñ­´¤÷Ê{àãÇÇ’§Æ•ï‡ìSrš;£¾¡ðž€@¸D=xëþžxrÌÈà&«õžÏØÖíÛlýú Á³²Ü«é‰ƒ¤×®¼ÆÛ7Á|kžÓlãµ²Œ©¤úOš{úŸ|¥¤¿ÒÑõ‡ï¾áúc~±]k£×ãɼ\oÍÈCÖ|ð¢ôà Âè['…üÄùŸ208¼Rýøž¸ÁzöG?@×úÆ_#¤q6LÞÂuòÈÆ€0Ù¬Œ:U¶p¨ï•óU”?±dÒ–mzÙÈüSäÎ)„?…ìP¼™•@”Ò¡˜Hùò:çÃÀšmߦAÇ+!L–‰Ø|‰±o¿í6›ÕØèï€vól¬ŠácöãÿľðçbMZÙ‚-†g.AèÛU$cF)?(·hÁ~Ù¬ÇFwD{%Ï>”Þ¿@Ù-MM®Ä[¶d©-[¾Ü—Ž–’‰Ò¿RèHö@§^€wfuÇiÉâۮλ[NòÝ,Î v‹ÌÊŽéÀú&ÆÁ‘#I¬+r–€%i3ø[T¼¤õòlþÚöV/ÀDü'/í+”¡‰,(áä‰ã>Ÿ¹[ÞÐßTÃÃï…Õà3ÕÛ)ex9…C1uŽDô8çXLÎru@RÞmðä~¹Œ»§K²dÑûÅ~ÐWh±¼Gêì’ã ™ê|ýoÿÖžýá“NØÑVó§ŸÐx¯¹ 7èD8ï“r:¼iËf[«q±säÍå*ÊÛŸ2uŠ-]²Ä–耜¥)#¸Hú]š{,O·žbÃhêéîއ+#4ÁâØFɦlvS£ý»÷Q›­ÉoŸ—Œ {qnà{”¡?ŸÓ`/dŸ¯Þø€Q~.d=Ï£6pŒ  ׸FœÅ§?õ){饗m‡ó„æ©:,±½pž1¼õíï§3ßw¼‹àæÍ£­þSöqäãsfÅÇÇ å¾‘Ö^@ækïâù;—×9¶‘Ó5 ƒQöp¹0ƒþˆÌçÄÅ8tØîÑ;B“ÆÑ¤¿à Œ6ž*|ÀÔGd;‰³aœž¬“ˆ @†ôÅgïÏ€eŸì¥‹—øž8óÄéÎÔ†dx'*g>V,9õDÄI–¡ ÀH'&QVGÉF‘‰p8ʹsæÙOdÓxƒo¥sðñçÿp¯[! ÿ¨Ã¿ê~ 9Hê8cô”EÏ<ó´¼íÇ0UÓìy6¨¯ÅCŒÚTÊÞ/qNr¿Vg¸8_@7OÖûOÏK˜•žä¼»=Gô@(ç$0gá$%n÷¬çr+|‰b±ÜŒÝ~û;m†8{ÞÓ±c'ÜIÅýó7¾ ‚¸x‡´M?až’o¹É“ÝÒTC‡‘©×&™ø¼²v­7YÎ]\9ºÐSc<^Ư_¹Rý³Å–ÈÏèBí¨ÉÖ Ä§paH YŽnêqt`L0ÜÑ€-J8€aÚ‡ª#%~Ï;ßž”{}ö #¡{atÜ0 rñŠŒ6–˜æ|ü9ªNòàènŸHoÅ( à‡ø¶SÛ5<§¹JwÜ«,lÿY ×Âü©\j!þMÑÜäF‰m;äN+ &jè#ÄF«.ýïT/ÿàø"×Xš¤{†ìªjIÀd'DÙ‚.}dÖøCó›n¸É~îýïó§Ïÿág݆'Îþqñp_ç4ÒO°~m™‹=¨Ï6lب9ÈõNØìQÏ{9ðNé-úÅõRصˆ»].m;â6b7œ%}¹·r¨/‚v(-ýF $Œ”Ècg)t*@LfêØ5Rš`4\ûP/\¸Ø~(LÊû@È—£s°Á†à%7PçsU*‡ª„ ¥ÉÜ"u¢W.ÿCœsš˜˜IO=õ”½òÊj47*½î`0uRð`0ŒåA¹ÔÂÙo€aJ£AÔ˜ <°?4e—܈"ç®ry{:ígB@’MÁÎ$ñps9‡‰Úes¾\{ݵZl°Àžxüöm\¯Õ,ÐÕlD õ\NKŽþ™ÊúDö€ì‰©×†lƒ¸HßV³ŸòR }åFdSS³›ü,@² sê'Moá¼÷Ý[â!v/ä½ð.ßzåɈº¾*çégŸqñ(öÅ<68y‡Ö!(z4p¹†È!’ÂÐ2ãBÈ£¿Ô°»$±nà¨õ‰'~`­Úe¼übÖjT`ê÷;NœÄÖmÛµbc‡ê£”Ì\ùÉFQÙÁ¤<cÞ>ÅjúLJ·¯„f¸Ó[&'Çïùw»2ä§?yÎÛ¡7ïÂ’–“RÜ㜮bÅÚaâÃ:ì5k×H“½Ãç«I“ŸûC<údSc£ÚµÌ ™ ek[$ŠÞx) ÎÝi L?Q_ëé¶|ù ûÌ'>íó‚åÀãƒDÅA)$£#ø–Ôðx”†A…±9{–´É¯ œ ¯ùVÇÇ@œaF êe^‘„ÀÁÊü~Ø-ð{ÿçûR|ÒV¿²FËeª¤f‹»hœÝ(£çé.š1xãÀõ£§¢ÚŽYã¼}ˆÕ1:»[þ@¢øW>Eϱ<îÆçí9᥽3jôH¹4›"ÛÃFklj²íÛ¶É3øŽðND<èÉG¯@1¿Ö•îžq ^¼ÂûŒñ|Üx÷̵îڻמñE[¥=Ø9ÒÍÄptŒÕ‘sŽñÚ#ýà»Nï´±±ÉEÿ¥KÈÙ6YÖy€,æHgJ’J9åÃþ ­!òjywnjœeËÔY?õÉOk³&eÖã‹GeŠ£€Ð€bð‘H–ÒnãÈठw1ÍARi5Am!¹WÉ_Yö>ao”ª|»Ñ¯j [ël³¹óZl¦¸ hû òvÿeYûsPÖ <{™àmd.´Ü2e^̨«³uÚìL ½Ÿ“ ØQqí(ihrE^qx@öÈÖ•¿ÏVÙ<¾ºy“ýìÅÜ“ÏÙ3ì+.^1÷¬ F®Ke¼ŽG¤†ë%b755¹’f‘L‘š[æÚ$íSã–ó¡SYç½D’P‰*ºÎ'ÛDÙÎa²\bϽŸ¹×&h^ˆ8HôŸÀSwH…øŽlž²MéÔ‰“ÎUÂÅDŽ$€s!‡—æÜ%e©lÀ´ºq½Ë^кo«®³wÜö›«ÍŸÆÈ(Þ2mÑâ¾!NbDÉ‘ûñ¯äV—Ù£óøþW&¡ÓCåÒžË1@¯ñ㯖W¨™¶òÚëœÖ¯‹+ €(zgÿh{|ÿØI*x]æA(g^Xõ¢+jØ&ο4ĘxŒ È5]…ãUW°o¸ALÐb¯0´Ølæ5fìhÿXשŸ¤pq)ßÃÅ-õM^ZäÚxÌ8ß7 H—#ÓÆÆF[¢mE?®}¼Ù¨>@Pàƒ¨Ë RÈFÓy¸ x¸D ØÛ4uVZPö½!¹s•1p¾’nÖÓfеÁ˃ËT ÞcÇ[íOþëç}ûÙùÈœ&í,S¤s@%¡.¼Mþ£ëÒà‰K#ûqÝSy1«Ê…³u$®¯ô1_…£G²©z—¼Û¹óæiyè6Ûºu«¿Œ÷(àïOÇÅ=nWºç_xÞÅë£ÇZÝÙIѾ!‚%éÈ3Fó¯[y­Í×|èJ‰ÚË4½C{&LšTð°ßS™ôÙ.Œé³stóùÁòEÑ»Fâöžìc³¯|YžÆ5Á@®2dÀžr`õÁ¤Î ·rZ@‰Ñ1ö™ –ê.!£”eÀf4ãp¤Ì öánpÛm·Ú+rê»Y j0«½ *Äüxž¼çf·Kt³ò圗PEûf7ú‘¥´ˆJ^_q‘ .ôj7®ß¨#æ%0%¦< ßé3§}5*vÈQî1yr ¢µSØóôgŠ€p‰Äê9--®$œ§vÔkê¿ñCÝ[™½õÙÞò¥{…¡•Hq1)PŽ9Ê÷šákÿï?úìz(?+IvÝ¢p(JÖð¢ùÆùÁa̓áb˜là0BÎ<$Ê/N×” OÃ2E`ðU*ÿó÷¿/Nw¼8¡ùÖÔØ¨ý­³:c“B¦ÐÎc|·6õ~áó¥4ÂR&-efœcéݘ%Kï_ªëáÃëlŠlOçÊãÍo{«¼*ñ½Ò¡2Š2è žÕû9¨åŸôAüé /Øj-/ăOØ‹¦gbö&ÎéûhõòW¹\N*.\ ܵÚ&b¹{B/ç8÷RÑèÍ\oâ$áíb—Çw1ƒ¹A‚|äßÊ®òïíÑÇwÐ+T›­§aäñ€% &²MJsç°«ltnp›¾z'r‘”âp”ž¹Ìjq¶ÿôÿhwÞu—ÝüÖ[ìU™ lÛ¶ÕªÔV{Ãí©…÷pÒ²eevãUL7®3+–çð)‰ mGÍ{#ÑãÆó(™:!üäGÏډǮ|L{Μ:m{dÎÃþ3¯íÜé列{3@/Ï@S^© ì=„šJi–sŠóø‚ŒÄçJÔ®o¨·á#†“5… P ä ™PÂQ¢$AãŒÿǺ_þ°-—]ÛŸþéŸJë|®[Í`8±!ð'‘! "1¿Ì}uu ô4ÒNvžörp^€îAñ>âp¨—ù28|b®góøcÙwÞé®ü7mÛf;””¥"U?-`è+‹¨c Щ[(¹ìvï]À»m¤¶Š½þ¦›¼û¥ˆá=¹bFFá‡òí¶¿¶Óˬ÷v¥Š¸EÀ° ½À’ø{Ì¿°lH½@ʶ¹òæ4oÞmP7Éwó,É’.‘ $¸6ðb2hâ*ÅíM•ÈT+ D;ùñ?ø„ýå_þ¹ö×Ö€ÊSHšÏÃýxî:»Õv.¬yÆðH)ð–MÀÞ²J6œ@b÷÷´Ï3 yí 7j­ð&Û©Õ"ŽMÌ_4ôj<{!WgoÅå’Uô—hh´çÌcÓ´Òfë–-N³S2Ï:¦% líº]Ë=÷î}ݧDÎr¡|l˜ï*½Ç>Þ+Ô»pÑBä"klžm㯟²q9.ä Ø÷´@¹±¹8L…XG=Qua?‰(þ¿÷q{àoتկøœ"Í(Bañ,r”¥ÍtÞÒGW‡u±«<+g xÃ,GHcB`Dqã"·DÿW­²§Ÿ|ÒÞrÛÛe:Ò$ môAÜÏÄîR¯´òžÐ,kö@Áñ¼âõðç+½Qék=çD­^iÔJ¥%2ëÂõ%‚ïÙ÷º\Ðís¥Ì®={ýƒT*ZGα·&—¦áM×Çt¡8ÇYÚ}q‘Múì¦Fm[;V.ú’ˆÝ=ë^ÉA ,Ë qs.|;"z”Ãä™eÊq”xhÙ  ž¾øÅ/fâ7(ˆ_®"\ÆëxÔ-¿ëiôÃr·ªªN)N¹¿I¼ÿÀU"Šcc X2™'ýþ÷ÿÙA3’Í›6i/ç]Êç•N¥¡\\iÚ0@α´ˆ î ™ åÁ.q€~øëljÒª­Ïß©¹ÆøÎw ³ž=²‘d JµrÏ]ÊÆG‰À1qÄ멪/ìj¸ÀZæÌÑõ'¯CHh¨©/iª#Õ*sL 9tF̆æa¤íÈã|ìØQËF%Žo´8„OHüþ‚öb>tøp¡5¥ÅîÒø!ð]`›ŽU«'µ¯Íi)漢‰~À™mnŸþg¶nÍjÙr.³Ÿ=ÿ¼/_Ü«ý½}å…ä9ɾRÉËDáA®à“ñWãñ&iµÙOûËr‡ö¬”6í²ì ûz\À³ GŽ”x-ÿˆ×ó¥Áž7w®5ÊX|üøqšk«ô"²@”Ð@âC4~¤=CúyÃH®ÒÞ0 Ï/ b _þaMuv.ÓDîQ£FÛh 6gZ(¿„G5Gɦõ¾ûüb{Éc—Âíàq¦ÍgƒsœÆž={Æn}ûÛU¦œ÷jý1skay¤¢h3M-\ûí¢ñê÷.28Òf¶¶ÀŒÆ•ZÔs 4jyã7Ú?ôKjIµ}ô£§vªÌ7 Ð+mn¹¸˜'¦e:¤AK¯½f¥¸GÙ?ÊÍ{ÒÀINТ> ¤ ËcîÞL ¤pq)8É‹K쥮 ™$ešï«FŒ‡9Î6Iüýúý_w®PÉ IDAT°Œh^ÅÕSX^ÚÅ%ód”;à‰ág5o‰÷ò1£ÇØc2EúÀ~ÉVh€®zþEß™oÿþ}bE» Š>H³Jcù€{jK_ñb­CJ®ý¿?d_OÚWéçþq‘3´2i欰Öý7í_ÛQ­ Éàj•ã»S1Ÿ+p’£õ–jUÖtiÍ›Ƙö467ʼ§ÁP!qúâ»—œ®ƒ $ƒªý,3¬”¨ÑœÓÕV'qx䨑râ:^À9Ù{ô{F[3 )…RÐŒ\dÆ´:XF@}º$bs;JL“àÔð@óÇüß4úWÆžÌëׯ³}RHÎ˧RNbYK¬ŽË$©Îÿbe^ó¥ùÁ0Ÿ6 ¬›o¾Å9û—åŸ3=‹1½b1•, 4åÑ$ÛÇææWᙩ¹¥É÷äž(#ê4-’d>_:¿tH yéh_¨™A1fŒöÒÖq¬”9ˆZhU¯¿î{à›ß‰É΂œLyÐS°yl‰N¡ò8É~lÇ.²Êž–{¿öVy«öfÙä)$Žè[LÊ$øºj¹Ê"ÀqïÒ¡1{˜˜o¤Ì‹•‡µ3gÎr±wò”©öeyQÚ+ÛÈ|ˆôÎÓ>žOË9J³ RÀ N×ký<ÚkÄêYLœ!³ Jµ¥”»ô× $/Á;Èk(áìGiÒx_åÛB Ó–ˆÞ“´^—œ¶hÇ<`sŠÒfGPC1ÜWÃà`×eÇå4ã?~ôÿ¶ø¦‹|õÓëíð@P èåsª:gUÎ ±LG ËŠÌ—çpßh]šŸe•ìOÏÈ›n¹Ef?UnªUîÃ@‘ÖëÓ¡¯HF²óªF1ƒ ½©ÜYß––fq-®¹f«W”jlëûÁy¤ˆKJ’—€üÌ3E³ F(Ù•‘A5\ÛÖbÆ3Q\å4™…L™2Mk¯¶çeçÈrÄòƒ³Ü@ŽéòÇ|ž—_‘¦ê|çwÚ–M›m·ö\9|è@’‚³ Á"6c3ó…öq^Ê9æ“{ijÔÀKÍ—rqÎÙ1»¹±ÉäÄö¯Ý6nÞR¶ð@™æè. ¥¡V ºÓ§Ù­–™©2›±e› 9AÓ*س"~óØÒúÒõàP äàе×Rã’Ř(’ÂØÕ%ƒê«%ž1p–Á<å”É“ím·ÞfßøÆ7´—ö_nàEÐ냌uqŒÀÇùñã'ìÿô»OÜ䜹-¶fM½$uØ*ÅBYoàHýx† dHÏỷ©ï¨vLœ0Ñfk˜r$Èýí}_ ØC­ñÃßÉØ¹ÅÏ’E‹ý‡Ñ–æf›¥ã4‹c;\ö«|,yç„ü‡Ò#zøIŠœ3ˆÑ $‘¸=A±ô~~07ÅbûüŽ=ʵÒS–S§N“sŠmöÐCÿàFÍx !äjiÙ½]¿¸zµØÛïx§m~nr—¸I‰Ý*w  ëé/8Æô#0Æcþ^%Îñ9]mæ —,_f?”À+ëÖ—¾ˆà?L|xxWËuÙ’ÅK|›‡™3¬±±I›†Í²é õâ'¸tÀ» ñÇ>Ápô<_‰gNuôM’}Óè’¥`6ÇŽ“\þ)á,q²Êòµí«¼s×köÐ?üØý>(S”ùž„›<³”ÃŒb9ð¤­OÑÒ‰c+ 1¹³rJÓ æ5MBY†A÷ùj´þâÏÿÌW2•«7‚#÷ à(Î3ˆ3%Rc>4M8wJ¡÷Æœs ãu<&€Œ”¸|Ž $/ŸwQ¶%ùÁÄCŒœq†gši3¦Yý®é>°wÈÍÃÿ“s–mçXbB~0Óþ¬ÒÜ$«‚Þùîwkn³ŒËá&‰› ¶–Yq:”ƒGÊq튊geÀ±xóÒžÐ<06‹xܹù­oÕRÍÝö²¼&Eú•ûØà©MøbÀQbz}ƒì*²ÌiN“‘ø„‰û¢5OØ_±úÒR#Õž§@É<5®€s¸Ö€3ðà*ñ 3Cî´Ø’¡QŠÖa?òèÿÑ:ã]¾‘XO }ä,1”þµÈç&á&×¾7yHéÙ.8:JcùO•½í ¼§Iâ"·–9MþømiýÏÈÃx|þ–Ðk„¬°g] çp‰3ˆx ¯o˜îïíø(‹_•Í;æ››ÿèåãÓùåK’—ï»)۲ȉ–£äCÀDÀÀ<".Ƶ¨MÚFv·mÛ±Ý~øôí°–;âS2â —"`¾¨mN w¼ûmï°UÊ¡ÝZ*y¨ \¹À.xÉ‹Ž^¡~˜ÅûzG—ÚYa€Äcbñ¢…‹¤å¿Ë›´f½¶ÛÈ} ð+ɼ0ëªñR>I8Ÿ¨×”Ç4ÍOW?Qœ#KM݉‰æSxsP äöK9À Z“†O¶Ñ 'O²ú#õÖØ¤¥nò¸LÆËxÌ~ìñGÝçá)­ãv®-{n8£h¾ÂFUÿꃴû¾y¿Ûò͘Q/Ÿ—p“!Dp”Izˆè Ìzg>cq ©_ À1Óí纃y1ñàM?ÁêgÈì§©Qíh³ð—­õøq)ªl¸¦7ÐTÏ“ÏqíÓ¦Mu±|²rªÎ'k~xœâùP±>?ƒÞ{ºT%'¼T”¿Hõ2á*á0Q ‚³jg¼æÈX{|ìè-7<  ¤šuܧ¿ýö´¸Ë}øæb0K¸Jæ&;»jíÎ÷¼Ç½íÉq“¾±˜Ò€eqP‘¤`©€<£¥’g´….N.*Fè3]+`Ø?æ®»ïöÆV9"ÆÁî|‰Ó¬£fnq²®§Ë^ušì9gšcÌX‰Ô2Ïbž¸·P0íê-QºwÙR äeûjznXt‡Eïh˜mîðÉÀf£(Äð)fÍWxØ7ªZ @`êZ]ó“ç~ìKîp«²qÕ¯Ènòþo>hsšmÄIòyÙ2ž¹ˆ ÷Üv¿Ê*ppRþ6ÈsÉg÷*ÙöTWå(@²r´”šâX~ÀF[»|€P'®ÎrRÛ9ä=i'´=íqíÓrìØQæ;¦¿ë¯»^Üä{ø»ßµ»þçm¾4ÝëÖjM·ì&µï¢Dr™æÞbˆ Ù+YŽäÅg&‰G¢3gÅEŠ›¬t@£í®ÊÄEÖ iÛ´F~nK“‰+3ü|öGœ®t»S}•¥@ÉÊÒû²¨ÍS  —Ô6¹Í·|@Ü=uò„µJysLœ¦äkoëïy·mÙ¶Õö½¾ÇEôŽLŽsypŒq…‡,G.Ã(ŠšN£æ"ÅAF‡À…|8a/m4Ó,¼ó=w{Ðc¢´ÖÌíæçó\zš–ª¸Ì(@ò2{!•nNLêmoŸ yÁsîÉüŒ<—Ô*œÏÓöëeX}@"wPÍ0u0#¹‰ÉP1Žñ4*ˆH‡6“$Dl¸ÈööÊ*khmœoÄáÄp9"&0÷X:˜ÒI3¤Hé×ßýáÝù»J\fgÍD—ªQØÜ~Ç»d7¹É<ûöæ&,ƒ™ø1WlÑdsÌ}¢˜]y€ÄÈ›%K´]ÂϽï}|dԤɄ2 –ü”Eî±Òé¢@R» ¡—Ý×£Fí¸2[Ž(©[™ˆgÿV• ØÀ“FkÔýü9u€•† b¸"šH7oC›-1»§}ªC†‹ÿ œO–-)«kÍ›ïó¢þ¼€·ÄÿJ)@²”"Cø:ÏIU ÝÔHGïfi|—.]"mp½8Ìš åÎ8Çèæ Ò±Eép†º "¶VÔ´·µ[›öGaSi›HÚdz´ö5Ú"öö;ïp 5ÆôpŒi-(”B)H–R$]»A5dpS#i¡£È¹BÀ‚ Qµ¥ ësB”Ì3ŽÝ8G®å\¥æ Ûµ¢æì¹6;­¿sÌCfy)¦ùS\Íá„b¡<ýpM€Sfî1ZT¢-©Ž+‡ $¯œwuQ[Z­U*‘XøDÀÈÉŠk®±ùZžÇJVúÀ5†?„òÈ=†’"÷ˆDæ Ïeéöâ&+-fÓª±ãÆÈ¡îl[´x±½Eûúà"kå$ι·ò4ë-mº÷æ¢@ï=ãÍõ¬éirȋ֑SÌÝ.œ–¬“Îò¦›nômj4o‰Ó‡Rv0pŽ{Ħ‘š9ȳímn47*©À 8Y+fšššíºk¯uÀóvŸ ØmúQ\e¹ò4+—&Ž9)@òÍù^/êS¡ñ( ‹—.“ÏÅ…¾¡•P£€‘ްe:Á£9íR„`ÞÃü#Jšd»À(ˆåµ‰}ÆrÂYr%7þ<[&ŽÀ‹àOæø¡H@Ø')‡\‚’Cî•ì#8æòwÜn‹-’ƒ‡qG‰Hí“*.±;Èsúƒ‹tï>:Gdí’y¥C­ì ™‹œÓ<Çn¹ùæ@òL„øŒ•nWªïÊ @É+ã=U¼•qþ ‰s–(g̘jóçÎõ-$Ü$H­ó¹É áÌEvˆ£ìl—r$ÓyWúaðÿØÒÜ¢=¯Û\)lx¶´%žÇç¬tûR}—7H^Þïç’´‰b'爢‘ÛP:;«íýÚgÅŠ•ò04Õjµ-ª‹×JëŽsŠœ»¸ ©xÄl×’Tø‰FÉ䇽®‘ˆý ò• ÓŸ->SlR¹ãu:& @’©œG"ÞA\9Sä¶bà‰ÝäL˜Wa¤ØU¡¬AÜætüù\åy5 nD­ÚU/MÓ Ôé–{Ð/X93C‰cŽ[Þz‹}àCr1»NJ&Bþ™âs¦ŠS Ä¥(@2õ^)½ ÅÆ%|–¿÷½wÛ)¹Wcy¢þÛ>yò8šd?œJšüÔÕ @ÎÐv-vë­·ÚûÞÿ~o¶o+ñ›Pö™üNï÷²$é0Ä(P¥L¿N!Q`@@L\bìº5kíÿáÛ¶vÝ:mk»Ó=• ´ÞŽœ*}à‰i ûѰ›aƒ@ò†[n¶Ÿ—‡Ÿ«å@7òíÎǧóDž(@²'ʤøQ­ñ–Í[ì{ÿô][µj•m—èÇóýÚ»{0— «©•óàqÖ0³A&IÓÅAα•׬°;ï~oÞº?KȽҔ8£@ÉÔ.˜ù¹=¨ªºÆNž:!Žò!mù°F@¹ÃvïÞížÎ?a¥ÛÙ^hňú#äYœ]!¤¹ž®Íºhgæ¦Fq·¸")–ÛˆR†9Ç”‘2éØ_ $ì/¥Rºnˆà“xν5¯¬¶U/¼h[·lµ×vî´#GÛQq–§´¯Î©S§ì„þH-eo¡ZŽ4ð:T'[ÌaÆ1£FÙxí“ ÷X?½ÞZ´Ï̆{×»ßíÀYS]ëÎ9bûbÙ$ãu:& ô— $ûK©”®,"0Æ›\ÃQªcyÔÖ­[ló¦Í¶ëµ×l·¼š¿þú>í~ÔEqÖuãˆIK€Ó•=± å­]Ùw¸<¥ãr̘±6A›w±ÍëTm+‘ø%Ë KÁ±´}±øtLè/Hö—R)Ýy(åÎ" aöƒ‡æ) pNžêN¦ï²Æ–¦nëª#øÅ2áê*ù¦ÔIuu÷ùÆP.(]´ró}½…ÿÈúK’ý¥TJwÑ(àœ¦VçtÔÈÞ’ ¸ªjëðº:ÙFA>,;¥høÚÎZMÝð‹Vw*(Q` (~fš3¥O¸@ °õƒpѪ;‡9 ®ÿõ÷ÙÙ=‡­j˜8<‰æðy]Js¦Í–<ò¤®à@cWÍŸ+:…DA¦@ìyƒ\M*>Q H”:rVfm:ŽVfm[[}nÒQRIY½3îÖ&yªµÚ.9ÊÀ‹‹ÊÅrÒY¢@%(&g*AåTG7 N3g9…N§üMŠcdö°ZÜ#Gß°V(Y;m²ÕÕ R«Yà¨;ÇSH¨$HV’Ú©.§@Ôz#vwV‰—¨ôš»ì@7;#Cõš‚Ç£ÒO¢À S ä “8UPJ n·»èÜúÜ8-w1›tÎErHžÞºW|;5/‰â¦ËêÄY¦(Pi $¬4ÅS}R¾z²Ô ™/­FãT ̤æ"AMý?ýêA«Ö~ݤõ5ÜŽs/…D R d‰ª +gdú£7Ǻ]Ü#ðˆÂFs‘ì&6(ì:ÛeÇ_|Ò¹KWò,£³_Ï~*@’ rª¢„rlQÕ%·j/êXo-@’Ò¥ËÄ êÆ¡‡¿ æ"ÕžtÄÒür Ó…ôìÖãvbçÖPŽ·Nß@)íÓª¶ÊrÓ÷Û©b‚4…DH我Njk«­ëœœÜŽ.2׸­b¿¹8äeÒw€@ 5ˆÞZ³}â°µþðUGB@Ìs·J$ÃEº¸í¹HŒÊ?þ¿ÌhÏE bp±¿¬øƒû´­Klm¾¥þTÈC’WÌ«ªdCÛíÔ–Wœ» \% Rãsxøì+Èos¢pl5B¼‰;ø˜öýÝ­ó´„h‰¹Ì7Š@±¯ßÖ5l$s”üósýšG}\e\€¤-€v‡øTWuòLµî†-ÍIöõv‡Þý’Cï÷ã‰kíÄ«¯Xû¡Ýrd¨–"ÇNs•}O'Ðq07$fmçÎØ¿{ØEmDéNmÍ@p^S=‘yIæ(‹6“Áù.)N>¿ÛN¬~F©/†ö {‡{:GAeÙ3ÑÎjëû#àN?C† $‡Ì«ØƒŽœ¿Üö~õO\C% wV XJM¾°wPº¼þ÷ZÛž3^Ž+iˆp“@¥¥P $À]r'Šßr+i{¾ø…Läö$oà'ã"1N—'">púˆ~ø7PnÊúf¤@É7ã[}ƒÏÄ4âè¹+ìøVÙ‰õ/ èy££L÷¸ºp—èZìA‡|pl„ÖÇ´}÷=!ô ]I£"8‚–;K]×-}nRi‚§ËŽ>¾Ñ|û+ž>üh1y+÷¦äb9mà<›‡¶rÍ_-…Ë8ÀAvÙoë~õ—¬¦yAIIér¨S äPïežŸyGæ¯ZÚb;ÿ÷ìLëA›Lv&bé¢Aw{{Ðx:h‡ pž(A\äV9øŽ<ö³'mÓï~ÞÚÏ`v#îPéKž¾ 7››„‹@9:xªw’Ž”‘ßÜù‡_µò1ÙÙ¡6j®³FÞ1|^Qi:»ª9ìí:¨ñlP½}â ]s/mvÛÎ ¶î—Áj§L´q‹V*>…D"Hi‘Î2 tb.­ïÄ_ü;±áˆíø¿a]­ìh(¯†.ŒÄQÊÀÉDGº®\ –öÎZ;øø·lóoRûØHääEΑsDit5ÑÔ@ðœƒT-vTJPZö¾é8Ña>ò1ÙZ~ÛA»½3táÎv”A(—2€V–ŽܬRÀœ•3º>ôÝ¿¶µü×vJ›‘5ýÖ’·ô4$œHé§@õIºi ‰Ý)Ðy®Íª‡UÛKï}—ÝxÔFÍg³ÿÛçmŒ8-·w„åSˆ\\&!ØWšÜ±Á^ÿ¯Ÿ³#lPzu1)=M3€žNP¨s€88EÅ‹…„‹d¾Ò½ŒüW"ç2ÉŠ¸Î}•7ñçVXýü¸]5kµË6³V«rØç"àmrð­†GĽõ™ïÙž¯~ÙŽ>»Ý¹Þi¿q»5|ìTùˆÀ«ª @ÉÔÊP r­ÏÑïümùý/8HÕŠ‹ýŽy6íC¶Ñ·¼×¸†“t%l >õ¿íÐãÙñ¬µv™ú8Ç(tµÐ€sÀsàËâ©3G_…šf€ .:°f×ÞXaI°¯$ç¨k¦ÙÕ·Þd“Þÿa«›>7€£î9pRvWP:]óŒ~ì{vìéŸÙ±µdÌ@xÔ ¶ø>hu#…ü^WúòH 9ä»@OÐJ‰ž]šÎ[÷Á;íôꃕåëÑ' .‰³Íc¬ªN$3ŸÎÓçìÜŽ.:lÃôCzDdç …h)ù£’¦S7¨”pû¶f;þÃ-ÂGPPuè/j·½•T*pÕ]n»èŽ`OÊp¬S+ eUcFÙ°éã­sïk?qÒÎ:mƒyy3Æ×FÎk þæïlØäiŠ¥´ðÐI ‰N’©#œGÀ¬CU­æ÷=[Ÿýg[ÿ‘Oɹ#ZçN G#ðŽÅ Œtàâ:xW¹ œÃœãžgØØZ[øíûìõ¯ü©øæsïšðŒƒ¤\Ô/”SN•EœsšY™àÐÒ:²çÕóè.®•¶\2Á~ékV5µQ‘°¶š7­éÛTÅ¥0„(ïÓCè±Ó£öFæòjk:%®"ÐÖÚ˜›ï¶Y¿ûËŽm‚?:'â8çÑTMt,¹Ü9^~`áHH‘¦VçÕuUÖpïGíªÆ6ûsÿæþ_wa¾è%+‰—§dÎý¡W‘~FaMRú6´Dƒu’zhY˜Ç$Sum•MùÕÛláýYÍ´FÝ8â¯RFåhÍSHÈS q’yj¤s§šâj±](:WP‚ÈhÛ½¿£3O»¸se€žððŠ –KƒsÐKIìGæÒ^Õ8Úê?ñ»6ñïsq<*€Z×ÿÌöñ¿ÛÑÇ6JävŽx”«¶yÃT¤ÇSc(>\“\ðöôZ݃%PÝÒñ6ç3h#W\§ç§#=RH(C’eˆ2Ô£ÚÑgŽ‚v8ó®5Îû¾õUÛóÇ_³ö£×¤\üõ«NÎÉdS€ „œôt«–±6å=o³é2çé¬+1G¡LìÞqyqæàkýÁwìè“OÙ©WwɦñTVB A@ôœ[*¤ì¾Ì…tÆ,cÕ¸Z{C‹Mù—¿`ãnÿEü6¡zIePÎóR£kóÜé()@2R"»Q€yI¸:8,>k?!-IDATŒ´‹Î%´?Íέ¶÷?+ó™õÖy `S:N‘Ó ÀH(²îˆIÃmÄœi6¼¥É&¼ó.sÓ]M‰Á™f?•Ø5ˆÇV%¤ª¡POë8gGúˆÝ°Ñ:ϲ¶Ö£Zê¸Ï9J5WÀиväU6zN³æ¯·Q7¼Kå Ä…çb…Pn;ˆðœ’¸io ‰9 $Ì# °ªÆÕ08ÞU¡±Ñ9æ>p˜EŽ«ÝNþô ÙDn¶¶ƒ2©JÉ…²ÚÆ-^$²9”·‘ó|î€Bl—J\àëT]¾^G^†¬’Áge¬ðУ Ê¶Žš,>˧j"pÓ^å‡u¨ã~ ioÔX °•ŽçðgRªJéÂ3á®û³ysÒO¢ý!(…DR àl—e„õuƒ8AÍé9È^2Ü–¥¹$ñNá‘&³–,æÅVÖV‡Õ8RøHýÇ]Y4îîì:ãuÀ…zbÁ "<ð˨ÒG`¹!:á‚k}é¡G~²¤^/Î7ò€Y-î’6ÛYÈ–N†0Š=|!=zw $Ai3Bâk— GŒÍ–vàO’•-Jã)N0E+Œ¨[ä2X±¶DŒŽ.H ì2Îî¼p|žWå…2Šë°8Nð‹[,ÁQõŠ# Ë åRuVÓ&U pç Æ9W8ÈÐ&¥E^O!Q „‰“,!Hº ×ÇP! džÓ‹iIA«^'EnÖ1ˆ»°Jä¬"@q€½\äèŠç±Þ|žx9Â8%˜¶éæˆÌ¹E·v¸:'Ôíù°$ó£äç˜B¢@¤@ÉH‰t,P0 Jæÿâ^×EåÍÉp8Àlc7`·©>l‘û£ð Æ ôXÉã@ çÙ¡yÈêL4.blLÆxÄÇzJ/[ë´óârñ9B®žÊ"?!ˆþ\0™B¢@ @ÉÔz¡@š“ì…8éV¢@¢@¢@ÉÔz¡@É^ˆ“n% $ $ $L} Q Q Q  üÿµ ØÒ¾eIEND®B`‚dill-0.3.1.1/docs/source/scripts.rst000644 000765 000024 00000000327 13543677215 020250 0ustar00mmckernsstaff000000 000000 dill scripts documentation ========================== get_objgraph script ------------------- .. automodule:: _get_objgraph :members: undill script -------------------- .. automodule:: _undill :members: dill-0.3.1.1/dill.egg-info/dependency_links.txt000644 000765 000024 00000000001 13543677347 022267 0ustar00mmckernsstaff000000 000000 dill-0.3.1.1/dill.egg-info/not-zip-safe000644 000765 000024 00000000001 13543677347 020447 0ustar00mmckernsstaff000000 000000 dill-0.3.1.1/dill.egg-info/PKG-INFO000644 000765 000024 00000017542 13543677347 017327 0ustar00mmckernsstaff000000 000000 Metadata-Version: 1.2 Name: dill Version: 0.3.1.1 Summary: serialize all of python Home-page: https://pypi.org/project/dill Author: Mike McKerns Author-email: UNKNOWN License: 3-clause BSD Download-URL: https://github.com/uqfoundation/dill/releases/download/dill-0.3.1.1/dill-0.3.1.1.tar.gz Description: ----------------------------- dill: serialize all of python ----------------------------- About Dill ========== ``dill`` extends python's ``pickle`` module for serializing and de-serializing python objects to the majority of the built-in python types. Serialization is the process of converting an object to a byte stream, and the inverse of which is converting a byte stream back to on python object hierarchy. ``dill`` provides the user the same interface as the ``pickle`` module, and also includes some additional features. In addition to pickling python objects, ``dill`` provides the ability to save the state of an interpreter session in a single command. Hence, it would be feasable to save a interpreter session, close the interpreter, ship the pickled file to another computer, open a new interpreter, unpickle the session and thus continue from the 'saved' state of the original interpreter session. ``dill`` can be used to store python objects to a file, but the primary usage is to send python objects across the network as a byte stream. ``dill`` is quite flexible, and allows arbitrary user defined classes and functions to be serialized. Thus ``dill`` is not intended to be secure against erroneously or maliciously constructed data. It is left to the user to decide whether the data they unpickle is from a trustworthy source. ``dill`` is part of ``pathos``, a python framework for heterogeneous computing. ``dill`` is in active development, so any user feedback, bug reports, comments, or suggestions are highly appreciated. A list of known issues is maintained at http://trac.mystic.cacr.caltech.edu/project/pathos/query.html, with a public ticket list at https://github.com/uqfoundation/dill/issues. Major Features ============== ``dill`` can pickle the following standard types: - none, type, bool, int, long, float, complex, str, unicode, - tuple, list, dict, file, buffer, builtin, - both old and new style classes, - instances of old and new style classes, - set, frozenset, array, functions, exceptions ``dill`` can also pickle more 'exotic' standard types: - functions with yields, nested functions, lambdas, - cell, method, unboundmethod, module, code, methodwrapper, - dictproxy, methoddescriptor, getsetdescriptor, memberdescriptor, - wrapperdescriptor, xrange, slice, - notimplemented, ellipsis, quit ``dill`` cannot yet pickle these standard types: - frame, generator, traceback ``dill`` also provides the capability to: - save and load python interpreter sessions - save and extract the source code from functions and classes - interactively diagnose pickling errors Current Release =============== This documentation is for version ``dill-0.3.1.1``. The latest released version of ``dill`` is available from: https://pypi.org/project/dill ``dill`` is distributed under a 3-clause BSD license. >>> import dill >>> print (dill.license()) Development Version =================== You can get the latest development version with all the shiny new features at: https://github.com/uqfoundation If you have a new contribution, please submit a pull request. Installation ============ ``dill`` is packaged to install from source, so you must download the tarball, unzip, and run the installer:: [download] $ tar -xvzf dill-0.3.1.1.tar.gz $ cd dill-0.3.1.1 $ python setup py build $ python setup py install You will be warned of any missing dependencies and/or settings after you run the "build" step above. Alternately, ``dill`` can be installed with ``pip`` or ``easy_install``:: $ pip install dill Requirements ============ ``dill`` requires: - ``python``, **version >= 2.6** or **version >= 3.1**, or ``pypy`` Optional requirements: - ``setuptools``, **version >= 0.6** - ``pyreadline``, **version >= 1.7.1** (on windows) - ``objgraph``, **version >= 1.7.2** More Information ================ Probably the best way to get started is to look at the documentation at http://dill.rtfd.io. Also see ``dill.tests`` for a set of scripts that demonstrate how ``dill`` can serialize different python objects. You can run the test suite with ``python -m dill.tests``. The contents of any pickle file can be examined with ``undill``. As ``dill`` conforms to the ``pickle`` interface, the examples and documentation found at http://docs.python.org/library/pickle.html also apply to ``dill`` if one will ``import dill as pickle``. The source code is also generally well documented, so further questions may be resolved by inspecting the code itself. Please feel free to submit a ticket on github, or ask a question on stackoverflow (**@Mike McKerns**). If you would like to share how you use ``dill`` in your work, please send an email (to **mmckerns at uqfoundation dot org**). Citation ======== If you use ``dill`` to do research that leads to publication, we ask that you acknowledge use of ``dill`` by citing the following in your publication:: M.M. McKerns, L. Strand, T. Sullivan, A. Fang, M.A.G. Aivazis, "Building a framework for predictive science", Proceedings of the 10th Python in Science Conference, 2011; http://arxiv.org/pdf/1202.1056 Michael McKerns and Michael Aivazis, "pathos: a framework for heterogeneous computing", 2010- ; http://trac.mystic.cacr.caltech.edu/project/pathos Please see http://trac.mystic.cacr.caltech.edu/project/pathos or http://arxiv.org/pdf/1202.1056 for further information. Platform: Linux Platform: Windows Platform: Mac Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Science/Research Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.1 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Scientific/Engineering Classifier: Topic :: Software Development Requires-Python: >=2.6, !=3.0.* dill-0.3.1.1/dill.egg-info/requires.txt000644 000765 000024 00000000045 13543677347 020620 0ustar00mmckernsstaff000000 000000 [graph] objgraph>=1.7.2 [readline] dill-0.3.1.1/dill.egg-info/SOURCES.txt000644 000765 000024 00000001612 13543677347 020105 0ustar00mmckernsstaff000000 000000 LICENSE MANIFEST.in README setup.cfg setup.py tox.ini dill/__diff.py dill/__init__.py dill/_dill.py dill/_objects.py dill/detect.py dill/info.py dill/objtypes.py dill/pointers.py dill/settings.py dill/source.py dill/temp.py dill.egg-info/PKG-INFO dill.egg-info/SOURCES.txt dill.egg-info/dependency_links.txt dill.egg-info/not-zip-safe dill.egg-info/requires.txt dill.egg-info/top_level.txt scripts/get_objgraph scripts/undill tests/__init__.py tests/__main__.py tests/test_check.py tests/test_classdef.py tests/test_detect.py tests/test_diff.py tests/test_extendpickle.py tests/test_file.py tests/test_functions.py tests/test_functors.py tests/test_mixins.py tests/test_module.py tests/test_moduledict.py tests/test_nested.py tests/test_objects.py tests/test_properties.py tests/test_recursive.py tests/test_restricted.py tests/test_selected.py tests/test_source.py tests/test_temp.py tests/test_weakref.pydill-0.3.1.1/dill.egg-info/top_level.txt000644 000765 000024 00000000005 13543677347 020746 0ustar00mmckernsstaff000000 000000 dill dill-0.3.1.1/dill/__diff.py000644 000765 000024 00000016053 13543677215 016306 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ Module to show if an object has changed since it was memorised """ import os import sys import types try: import numpy HAS_NUMPY = True except: HAS_NUMPY = False try: import builtins except ImportError: import __builtin__ as builtins # pypy doesn't use reference counting getrefcount = getattr(sys, 'getrefcount', lambda x:0) # memo of objects indexed by id to a tuple (attributes, sequence items) # attributes is a dict indexed by attribute name to attribute id # sequence items is either a list of ids, of a dictionary of keys to ids memo = {} id_to_obj = {} # types that cannot have changing attributes builtins_types = set((str, list, dict, set, frozenset, int)) dont_memo = set(id(i) for i in (memo, sys.modules, sys.path_importer_cache, os.environ, id_to_obj)) def get_attrs(obj): """ Gets all the attributes of an object though its __dict__ or return None """ if type(obj) in builtins_types \ or type(obj) is type and obj in builtins_types: return try: return obj.__dict__ except: return def get_seq(obj, cache={str: False, frozenset: False, list: True, set: True, dict: True, tuple: True, type: False, types.ModuleType: False, types.FunctionType: False, types.BuiltinFunctionType: False}): """ Gets all the items in a sequence or return None """ try: o_type = obj.__class__ except AttributeError: o_type = type(obj) hsattr = hasattr if o_type in cache: if cache[o_type]: if hsattr(obj, "copy"): return obj.copy() return obj elif HAS_NUMPY and o_type in (numpy.ndarray, numpy.ma.core.MaskedConstant): if obj.shape and obj.size: return obj else: return [] elif hsattr(obj, "__contains__") and hsattr(obj, "__iter__") \ and hsattr(obj, "__len__") and hsattr(o_type, "__contains__") \ and hsattr(o_type, "__iter__") and hsattr(o_type, "__len__"): cache[o_type] = True if hsattr(obj, "copy"): return obj.copy() return obj else: cache[o_type] = False return None def memorise(obj, force=False): """ Adds an object to the memo, and recursively adds all the objects attributes, and if it is a container, its items. Use force=True to update an object already in the memo. Updating is not recursively done. """ obj_id = id(obj) if obj_id in memo and not force or obj_id in dont_memo: return id_ = id g = get_attrs(obj) if g is None: attrs_id = None else: attrs_id = dict((key,id_(value)) for key, value in g.items()) s = get_seq(obj) if s is None: seq_id = None elif hasattr(s, "items"): seq_id = dict((id_(key),id_(value)) for key, value in s.items()) elif not hasattr(s, "__len__"): #XXX: avoid TypeError from unexpected case seq_id = None else: seq_id = [id_(i) for i in s] memo[obj_id] = attrs_id, seq_id id_to_obj[obj_id] = obj mem = memorise if g is not None: [mem(value) for key, value in g.items()] if s is not None: if hasattr(s, "items"): [(mem(key), mem(item)) for key, item in s.items()] else: if hasattr(s, '__len__'): [mem(item) for item in s] else: mem(s) def release_gone(): itop, mp, src = id_to_obj.pop, memo.pop, getrefcount [(itop(id_), mp(id_)) for id_, obj in list(id_to_obj.items()) if src(obj) < 4] #XXX: correct for pypy? def whats_changed(obj, seen=None, simple=False, first=True): """ Check an object against the memo. Returns a list in the form (attribute changes, container changed). Attribute changes is a dict of attribute name to attribute value. container changed is a boolean. If simple is true, just returns a boolean. None for either item means that it has not been checked yet """ # Special cases if first: # ignore the _ variable, which only appears in interactive sessions if "_" in builtins.__dict__: del builtins._ if seen is None: seen = {} obj_id = id(obj) if obj_id in seen: if simple: return any(seen[obj_id]) return seen[obj_id] # Safety checks if obj_id in dont_memo: seen[obj_id] = [{}, False] if simple: return False return seen[obj_id] elif obj_id not in memo: if simple: return True else: raise RuntimeError("Object not memorised " + str(obj)) seen[obj_id] = ({}, False) chngd = whats_changed id_ = id # compare attributes attrs = get_attrs(obj) if attrs is None: changed = {} else: obj_attrs = memo[obj_id][0] obj_get = obj_attrs.get changed = dict((key,None) for key in obj_attrs if key not in attrs) for key, o in attrs.items(): if id_(o) != obj_get(key, None) or chngd(o, seen, True, False): changed[key] = o # compare sequence items = get_seq(obj) seq_diff = False if (items is not None) and (hasattr(items, '__len__')): obj_seq = memo[obj_id][1] if (len(items) != len(obj_seq)): seq_diff = True elif hasattr(obj, "items"): # dict type obj obj_get = obj_seq.get for key, item in items.items(): if id_(item) != obj_get(id_(key)) \ or chngd(key, seen, True, False) \ or chngd(item, seen, True, False): seq_diff = True break else: for i, j in zip(items, obj_seq): # list type obj if id_(i) != j or chngd(i, seen, True, False): seq_diff = True break seen[obj_id] = changed, seq_diff if simple: return changed or seq_diff return changed, seq_diff def has_changed(*args, **kwds): kwds['simple'] = True # ignore simple if passed in return whats_changed(*args, **kwds) __import__ = __import__ def _imp(*args, **kwds): """ Replaces the default __import__, to allow a module to be memorised before the user can change it """ before = set(sys.modules.keys()) mod = __import__(*args, **kwds) after = set(sys.modules.keys()).difference(before) for m in after: memorise(sys.modules[m]) return mod builtins.__import__ = _imp if hasattr(builtins, "_"): del builtins._ # memorise all already imported modules. This implies that this must be # imported first for any changes to be recorded for mod in sys.modules.values(): memorise(mod) release_gone() dill-0.3.1.1/dill/__init__.py000644 000765 000024 00000007062 13543677215 016637 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE # get version numbers, license, and long description try: from .info import this_version as __version__ from .info import readme as __doc__, license as __license__ except ImportError: msg = """First run 'python setup.py build' to build dill.""" raise ImportError(msg) __author__ = 'Mike McKerns' __doc__ = """ """ + __doc__ __license__ = """ """ + __license__ from ._dill import dump, dumps, load, loads, dump_session, load_session, \ Pickler, Unpickler, register, copy, pickle, pickles, check, \ HIGHEST_PROTOCOL, DEFAULT_PROTOCOL, PicklingError, UnpicklingError, \ HANDLE_FMODE, CONTENTS_FMODE, FILE_FMODE from . import source, temp, detect # get global settings from .settings import settings # make sure "trace" is turned off detect.trace(False) try: from importlib import reload except ImportError: try: from imp import reload except ImportError: pass # put the objects in order, if possible try: from collections import OrderedDict as odict except ImportError: try: from ordereddict import OrderedDict as odict except ImportError: odict = dict objects = odict() # local import of dill._objects #from . import _objects #objects.update(_objects.succeeds) #del _objects # local import of dill.objtypes from . import objtypes as types def load_types(pickleable=True, unpickleable=True): """load pickleable and/or unpickleable types to ``dill.types`` ``dill.types`` is meant to mimic the ``types`` module, providing a registry of object types. By default, the module is empty (for import speed purposes). Use the ``load_types`` function to load selected object types to the ``dill.types`` module. Args: pickleable (bool, default=True): if True, load pickleable types. unpickleable (bool, default=True): if True, load unpickleable types. Returns: None """ # local import of dill.objects from . import _objects if pickleable: objects.update(_objects.succeeds) else: [objects.pop(obj,None) for obj in _objects.succeeds] if unpickleable: objects.update(_objects.failures) else: [objects.pop(obj,None) for obj in _objects.failures] objects.update(_objects.registered) del _objects # reset contents of types to 'empty' [types.__dict__.pop(obj) for obj in list(types.__dict__.keys()) \ if obj.find('Type') != -1] # add corresponding types from objects to types reload(types) def extend(use_dill=True): '''add (or remove) dill types to/from the pickle registry by default, ``dill`` populates its types to ``pickle.Pickler.dispatch``. Thus, all ``dill`` types are available upon calling ``'import pickle'``. To drop all ``dill`` types from the ``pickle`` dispatch, *use_dill=False*. Args: use_dill (bool, default=True): if True, extend the dispatch table. Returns: None ''' from ._dill import _revert_extension, _extend if use_dill: _extend() else: _revert_extension() return extend() def license(): """print license""" print (__license__) return def citation(): """print citation""" print (__doc__[-501:-123]) return del odict # end of file dill-0.3.1.1/dill/_dill.py000644 000765 000024 00000155634 13543677215 016174 0ustar00mmckernsstaff000000 000000 # -*- coding: utf-8 -*- # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2015 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ dill: a utility for serialization of python objects Based on code written by Oren Tirosh and Armin Ronacher. Extended to a (near) full set of the builtin types (in types module), and coded to the pickle interface, by . Initial port to python3 by Jonathan Dobson, continued by mmckerns. Test against "all" python types (Std. Lib. CH 1-15 @ 2.7) by mmckerns. Test against CH16+ Std. Lib. ... TBD. """ __all__ = ['dump','dumps','load','loads','dump_session','load_session', 'Pickler','Unpickler','register','copy','pickle','pickles', 'check','HIGHEST_PROTOCOL','DEFAULT_PROTOCOL','PicklingError', 'UnpicklingError','HANDLE_FMODE','CONTENTS_FMODE','FILE_FMODE'] import logging log = logging.getLogger("dill") log.addHandler(logging.StreamHandler()) def _trace(boolean): """print a trace through the stack when pickling; useful for debugging""" if boolean: log.setLevel(logging.INFO) else: log.setLevel(logging.WARN) return stack = dict() # record of 'recursion-sensitive' pickled objects import os import sys diff = None _use_diff = False PY3 = (sys.hexversion >= 0x3000000) # OLDER: 3.0 <= x < 3.4 *OR* x < 2.7.10 #NOTE: guessing relevant versions OLDER = (PY3 and sys.hexversion < 0x3040000) or (sys.hexversion < 0x2070ab1) OLD33 = (sys.hexversion < 0x3030000) PY34 = (0x3040000 <= sys.hexversion < 0x3050000) if PY3: #XXX: get types from .objtypes ? import builtins as __builtin__ from pickle import _Pickler as StockPickler, Unpickler as StockUnpickler from _thread import LockType if (sys.hexversion >= 0x30200f0): from _thread import RLock as RLockType else: from threading import _RLock as RLockType #from io import IOBase from types import CodeType, FunctionType, MethodType, GeneratorType, \ TracebackType, FrameType, ModuleType, BuiltinMethodType BufferType = memoryview #XXX: unregistered ClassType = type # no 'old-style' classes EllipsisType = type(Ellipsis) #FileType = IOBase NotImplementedType = type(NotImplemented) SliceType = slice TypeType = type # 'new-style' classes #XXX: unregistered XRangeType = range if OLD33: DictProxyType = type(object.__dict__) else: from types import MappingProxyType as DictProxyType else: import __builtin__ from pickle import Pickler as StockPickler, Unpickler as StockUnpickler from thread import LockType from threading import _RLock as RLockType from types import CodeType, FunctionType, ClassType, MethodType, \ GeneratorType, DictProxyType, XRangeType, SliceType, TracebackType, \ NotImplementedType, EllipsisType, FrameType, ModuleType, \ BufferType, BuiltinMethodType, TypeType from pickle import HIGHEST_PROTOCOL, PicklingError, UnpicklingError try: from pickle import DEFAULT_PROTOCOL except ImportError: DEFAULT_PROTOCOL = HIGHEST_PROTOCOL import __main__ as _main_module import marshal import gc # import zlib from weakref import ReferenceType, ProxyType, CallableProxyType from functools import partial from operator import itemgetter, attrgetter # new in python3.3 if sys.hexversion < 0x03030000: FileNotFoundError = IOError if PY3 and sys.hexversion < 0x03040000: GENERATOR_FAIL = True else: GENERATOR_FAIL = False try: import ctypes HAS_CTYPES = True # if using `pypy`, pythonapi is not found IS_PYPY = not hasattr(ctypes, 'pythonapi') except ImportError: HAS_CTYPES = False IS_PYPY = False NumpyUfuncType = None NumpyArrayType = None try: if OLDER: raise AttributeError('find_spec not found') import importlib if not importlib.machinery.PathFinder().find_spec('numpy'): raise ImportError("No module named 'numpy'") NumpyUfuncType = True NumpyArrayType = True except AttributeError: try: import imp imp.find_module('numpy') NumpyUfuncType = True NumpyArrayType = True except ImportError: pass except ImportError: pass def __hook__(): global NumpyArrayType, NumpyUfuncType from numpy import ufunc as NumpyUfuncType from numpy import ndarray as NumpyArrayType return True if NumpyArrayType: # then has numpy def ndarraysubclassinstance(obj): if type(obj) in (TypeType, ClassType): return False # all classes return False try: # check if is ndarray, and elif is subclass of ndarray cls = getattr(obj, '__class__', None) if cls is None: return False elif cls is TypeType: return False elif 'numpy.ndarray' not in str(getattr(cls, 'mro', int.mro)()): return False except ReferenceError: return False # handle 'R3' weakref in 3.x except TypeError: return False # anything below here is a numpy array (or subclass) instance __hook__() # import numpy (so the following works!!!) # verify that __reduce__ has not been overridden NumpyInstance = NumpyArrayType((0,),'int8') if id(obj.__reduce_ex__) == id(NumpyInstance.__reduce_ex__) and \ id(obj.__reduce__) == id(NumpyInstance.__reduce__): return True return False def numpyufunc(obj): if type(obj) in (TypeType, ClassType): return False # all classes return False try: # check if is ufunc cls = getattr(obj, '__class__', None) if cls is None: return False elif cls is TypeType: return False if 'numpy.ufunc' not in str(getattr(cls, 'mro', int.mro)()): return False except ReferenceError: return False # handle 'R3' weakref in 3.x except TypeError: return False # anything below here is a numpy ufunc return True else: def ndarraysubclassinstance(obj): return False def numpyufunc(obj): return False # make sure to add these 'hand-built' types to _typemap if PY3: CellType = type((lambda x: lambda y: x)(0).__closure__[0]) else: CellType = type((lambda x: lambda y: x)(0).func_closure[0]) # new in python2.5 if sys.hexversion >= 0x20500f0: from types import GetSetDescriptorType if not IS_PYPY: from types import MemberDescriptorType else: # oddly, MemberDescriptorType is GetSetDescriptorType # while, member_descriptor does exist otherwise... is this a pypy bug? class _member(object): __slots__ = ['descriptor'] MemberDescriptorType = type(_member.descriptor) if IS_PYPY: WrapperDescriptorType = MethodType MethodDescriptorType = FunctionType ClassMethodDescriptorType = FunctionType else: WrapperDescriptorType = type(type.__repr__) MethodDescriptorType = type(type.__dict__['mro']) ClassMethodDescriptorType = type(type.__dict__['__prepare__' if PY3 else 'mro']) MethodWrapperType = type([].__repr__) PartialType = type(partial(int,base=2)) SuperType = type(super(Exception, TypeError())) ItemGetterType = type(itemgetter(0)) AttrGetterType = type(attrgetter('__repr__')) def get_file_type(*args, **kwargs): open = kwargs.pop("open", __builtin__.open) f = open(os.devnull, *args, **kwargs) t = type(f) f.close() return t FileType = get_file_type('rb', buffering=0) TextWrapperType = get_file_type('r', buffering=-1) BufferedRandomType = get_file_type('r+b', buffering=-1) BufferedReaderType = get_file_type('rb', buffering=-1) BufferedWriterType = get_file_type('wb', buffering=-1) try: from _pyio import open as _open PyTextWrapperType = get_file_type('r', buffering=-1, open=_open) PyBufferedRandomType = get_file_type('r+b', buffering=-1, open=_open) PyBufferedReaderType = get_file_type('rb', buffering=-1, open=_open) PyBufferedWriterType = get_file_type('wb', buffering=-1, open=_open) except ImportError: PyTextWrapperType = PyBufferedRandomType = PyBufferedReaderType = PyBufferedWriterType = None try: from cStringIO import StringIO, InputType, OutputType except ImportError: if PY3: from io import BytesIO as StringIO else: from StringIO import StringIO InputType = OutputType = None if not IS_PYPY: from socket import socket as SocketType try: #FIXME: additionally calls ForkingPickler.register several times from multiprocessing.reduction import _reduce_socket as reduce_socket except ImportError: from multiprocessing.reduction import reduce_socket try: __IPYTHON__ is True # is ipython ExitType = None # IPython.core.autocall.ExitAutocall singletontypes = ['exit', 'quit', 'get_ipython'] except NameError: try: ExitType = type(exit) # apparently 'exit' can be removed except NameError: ExitType = None singletontypes = [] ### File modes # Pickles the file handle, preserving mode. The position of the unpickled # object is as for a new file handle. HANDLE_FMODE = 0 # Pickles the file contents, creating a new file if on load the file does # not exist. The position = min(pickled position, EOF) and mode is chosen # as such that "best" preserves behavior of the original file. CONTENTS_FMODE = 1 # Pickles the entire file (handle and contents), preserving mode and position. FILE_FMODE = 2 ### Shorthands (modified from python2.5/lib/pickle.py) def copy(obj, *args, **kwds): """use pickling to 'copy' an object""" ignore = kwds.pop('ignore', Unpickler.settings['ignore']) return loads(dumps(obj, *args, **kwds), ignore=ignore) def dump(obj, file, protocol=None, byref=None, fmode=None, recurse=None, **kwds):#, strictio=None): """pickle an object to a file""" from .settings import settings protocol = settings['protocol'] if protocol is None else int(protocol) _kwds = kwds.copy() _kwds.update(dict(byref=byref, fmode=fmode, recurse=recurse)) Pickler(file, protocol, **_kwds).dump(obj) return def dumps(obj, protocol=None, byref=None, fmode=None, recurse=None, **kwds):#, strictio=None): """pickle an object to a string""" file = StringIO() dump(obj, file, protocol, byref, fmode, recurse, **kwds)#, strictio) return file.getvalue() def load(file, ignore=None, **kwds): """unpickle an object from a file""" return Unpickler(file, ignore=ignore, **kwds).load() def loads(str, ignore=None, **kwds): """unpickle an object from a string""" file = StringIO(str) return load(file, ignore, **kwds) # def dumpzs(obj, protocol=None): # """pickle an object to a compressed string""" # return zlib.compress(dumps(obj, protocol)) # def loadzs(str): # """unpickle an object from a compressed string""" # return loads(zlib.decompress(str)) ### End: Shorthands ### ### Pickle the Interpreter Session def _module_map(): """get map of imported modules""" from collections import defaultdict modmap = defaultdict(list) items = 'items' if PY3 else 'iteritems' for name, module in getattr(sys.modules, items)(): if module is None: continue for objname, obj in module.__dict__.items(): modmap[objname].append((obj, name)) return modmap def _lookup_module(modmap, name, obj, main_module): #FIXME: needs work """lookup name if module is imported""" for modobj, modname in modmap[name]: if modobj is obj and modname != main_module.__name__: return modname def _stash_modules(main_module): modmap = _module_map() imported = [] original = {} items = 'items' if PY3 else 'iteritems' for name, obj in getattr(main_module.__dict__, items)(): source_module = _lookup_module(modmap, name, obj, main_module) if source_module: imported.append((source_module, name)) else: original[name] = obj if len(imported): import types newmod = types.ModuleType(main_module.__name__) newmod.__dict__.update(original) newmod.__dill_imported = imported return newmod else: return original def _restore_modules(main_module): if '__dill_imported' not in main_module.__dict__: return imports = main_module.__dict__.pop('__dill_imported') for module, name in imports: exec("from %s import %s" % (module, name), main_module.__dict__) #NOTE: 06/03/15 renamed main_module to main def dump_session(filename='/tmp/session.pkl', main=None, byref=False, **kwds): """pickle the current state of __main__ to a file""" from .settings import settings protocol = settings['protocol'] if main is None: main = _main_module if hasattr(filename, 'write'): f = filename else: f = open(filename, 'wb') try: if byref: main = _stash_modules(main) pickler = Pickler(f, protocol, **kwds) pickler._main = main #FIXME: dill.settings are disabled pickler._byref = False # disable pickling by name reference pickler._recurse = False # disable pickling recursion for globals pickler._session = True # is best indicator of when pickling a session pickler.dump(main) finally: if f is not filename: # If newly opened file f.close() return def load_session(filename='/tmp/session.pkl', main=None, **kwds): """update the __main__ module with the state from the session file""" if main is None: main = _main_module if hasattr(filename, 'read'): f = filename else: f = open(filename, 'rb') try: #FIXME: dill.settings are disabled unpickler = Unpickler(f, **kwds) unpickler._main = main unpickler._session = True module = unpickler.load() unpickler._session = False main.__dict__.update(module.__dict__) _restore_modules(main) finally: if f is not filename: # If newly opened file f.close() return ### End: Pickle the Interpreter class MetaCatchingDict(dict): def get(self, key, default=None): try: return self[key] except KeyError: return default def __missing__(self, key): if issubclass(key, type): return save_type else: raise KeyError() ### Extend the Picklers class Pickler(StockPickler): """python's Pickler extended to interpreter sessions""" dispatch = MetaCatchingDict(StockPickler.dispatch.copy()) _session = False from .settings import settings def __init__(self, *args, **kwds): settings = Pickler.settings _byref = kwds.pop('byref', None) #_strictio = kwds.pop('strictio', None) _fmode = kwds.pop('fmode', None) _recurse = kwds.pop('recurse', None) StockPickler.__init__(self, *args, **kwds) self._main = _main_module self._diff_cache = {} self._byref = settings['byref'] if _byref is None else _byref self._strictio = False #_strictio self._fmode = settings['fmode'] if _fmode is None else _fmode self._recurse = settings['recurse'] if _recurse is None else _recurse def dump(self, obj): #NOTE: if settings change, need to update attributes stack.clear() # clear record of 'recursion-sensitive' pickled objects # register if the object is a numpy ufunc # thanks to Paul Kienzle for pointing out ufuncs didn't pickle if NumpyUfuncType and numpyufunc(obj): @register(type(obj)) def save_numpy_ufunc(pickler, obj): log.info("Nu: %s" % obj) StockPickler.save_global(pickler, obj) log.info("# Nu") return # NOTE: the above 'save' performs like: # import copy_reg # def udump(f): return f.__name__ # def uload(name): return getattr(numpy, name) # copy_reg.pickle(NumpyUfuncType, udump, uload) # register if the object is a subclassed numpy array instance if NumpyArrayType and ndarraysubclassinstance(obj): @register(type(obj)) def save_numpy_array(pickler, obj): log.info("Nu: (%s, %s)" % (obj.shape,obj.dtype)) npdict = getattr(obj, '__dict__', None) f, args, state = obj.__reduce__() pickler.save_reduce(_create_array, (f,args,state,npdict), obj=obj) log.info("# Nu") return # end hack if GENERATOR_FAIL and type(obj) == GeneratorType: msg = "Can't pickle %s: attribute lookup builtins.generator failed" % GeneratorType raise PicklingError(msg) else: StockPickler.dump(self, obj) stack.clear() # clear record of 'recursion-sensitive' pickled objects return dump.__doc__ = StockPickler.dump.__doc__ pass class Unpickler(StockUnpickler): """python's Unpickler extended to interpreter sessions and more types""" from .settings import settings _session = False def find_class(self, module, name): if (module, name) == ('__builtin__', '__main__'): return self._main.__dict__ #XXX: above set w/save_module_dict elif (module, name) == ('__builtin__', 'NoneType'): return type(None) #XXX: special case: NoneType missing if module == 'dill.dill': module = 'dill._dill' return StockUnpickler.find_class(self, module, name) def __init__(self, *args, **kwds): settings = Pickler.settings _ignore = kwds.pop('ignore', None) StockUnpickler.__init__(self, *args, **kwds) self._main = _main_module self._ignore = settings['ignore'] if _ignore is None else _ignore def load(self): #NOTE: if settings change, need to update attributes obj = StockUnpickler.load(self) if type(obj).__module__ == getattr(_main_module, '__name__', '__main__'): if not self._ignore: # point obj class to main try: obj.__class__ = getattr(self._main, type(obj).__name__) except (AttributeError,TypeError): pass # defined in a file #_main_module.__dict__.update(obj.__dict__) #XXX: should update globals ? return obj load.__doc__ = StockUnpickler.load.__doc__ pass ''' def dispatch_table(): """get the dispatch table of registered types""" return Pickler.dispatch ''' pickle_dispatch_copy = StockPickler.dispatch.copy() def pickle(t, func): """expose dispatch table for user-created extensions""" Pickler.dispatch[t] = func return def register(t): def proxy(func): Pickler.dispatch[t] = func return func return proxy def _revert_extension(): for type, func in list(StockPickler.dispatch.items()): if func.__module__ == __name__: del StockPickler.dispatch[type] if type in pickle_dispatch_copy: StockPickler.dispatch[type] = pickle_dispatch_copy[type] def use_diff(on=True): """ reduces size of pickles by only including object which have changed. Decreases pickle size but increases CPU time needed. Also helps avoid some unpicklable objects. MUST be called at start of script, otherwise changes will not be recorded. """ global _use_diff, diff _use_diff = on if _use_diff and diff is None: try: from . import diff as d except: import diff as d diff = d def _create_typemap(): import types if PY3: d = dict(list(__builtin__.__dict__.items()) + \ list(types.__dict__.items())).items() builtin = 'builtins' else: d = types.__dict__.iteritems() builtin = '__builtin__' for key, value in d: if getattr(value, '__module__', None) == builtin \ and type(value) is type: yield key, value return _reverse_typemap = dict(_create_typemap()) _reverse_typemap.update({ 'CellType': CellType, 'MethodWrapperType': MethodWrapperType, 'PartialType': PartialType, 'SuperType': SuperType, 'ItemGetterType': ItemGetterType, 'AttrGetterType': AttrGetterType, 'FileType': FileType, 'BufferedRandomType': BufferedRandomType, 'BufferedReaderType': BufferedReaderType, 'BufferedWriterType': BufferedWriterType, 'TextWrapperType': TextWrapperType, 'PyBufferedRandomType': PyBufferedRandomType, 'PyBufferedReaderType': PyBufferedReaderType, 'PyBufferedWriterType': PyBufferedWriterType, 'PyTextWrapperType': PyTextWrapperType, }) if ExitType: _reverse_typemap['ExitType'] = ExitType if InputType: _reverse_typemap['InputType'] = InputType _reverse_typemap['OutputType'] = OutputType if not IS_PYPY: _reverse_typemap['WrapperDescriptorType'] = WrapperDescriptorType _reverse_typemap['MethodDescriptorType'] = MethodDescriptorType _reverse_typemap['ClassMethodDescriptorType'] = ClassMethodDescriptorType else: _reverse_typemap['MemberDescriptorType'] = MemberDescriptorType if PY3: _typemap = dict((v, k) for k, v in _reverse_typemap.items()) else: _typemap = dict((v, k) for k, v in _reverse_typemap.iteritems()) def _unmarshal(string): return marshal.loads(string) def _load_type(name): return _reverse_typemap[name] def _create_type(typeobj, *args): return typeobj(*args) def _create_function(fcode, fglobals, fname=None, fdefaults=None, fclosure=None, fdict=None, fkwdefaults=None): # same as FunctionType, but enable passing __dict__ to new function, # __dict__ is the storehouse for attributes added after function creation if fdict is None: fdict = dict() func = FunctionType(fcode, fglobals or dict(), fname, fdefaults, fclosure) func.__dict__.update(fdict) #XXX: better copy? option to copy? if fkwdefaults is not None: func.__kwdefaults__ = fkwdefaults return func def _create_ftype(ftypeobj, func, args, kwds): if kwds is None: kwds = {} if args is None: args = () return ftypeobj(func, *args, **kwds) def _create_lock(locked, *args): #XXX: ignores 'blocking' from threading import Lock lock = Lock() if locked: if not lock.acquire(False): raise UnpicklingError("Cannot acquire lock") return lock def _create_rlock(count, owner, *args): #XXX: ignores 'blocking' lock = RLockType() if owner is not None: lock._acquire_restore((count, owner)) if owner and not lock._is_owned(): raise UnpicklingError("Cannot acquire lock") return lock # thanks to matsjoyce for adding all the different file modes def _create_filehandle(name, mode, position, closed, open, strictio, fmode, fdata): # buffering=0 # only pickles the handle, not the file contents... good? or StringIO(data)? # (for file contents see: http://effbot.org/librarybook/copy-reg.htm) # NOTE: handle special cases first (are there more special cases?) names = {'':sys.__stdin__, '':sys.__stdout__, '':sys.__stderr__} #XXX: better fileno=(0,1,2) ? if name in list(names.keys()): f = names[name] #XXX: safer "f=sys.stdin" elif name == '': f = os.tmpfile() elif name == '': import tempfile f = tempfile.TemporaryFile(mode) else: # treat x mode as w mode if "x" in mode and sys.hexversion < 0x03030000: raise ValueError("invalid mode: '%s'" % mode) try: exists = os.path.exists(name) except: exists = False if not exists: if strictio: raise FileNotFoundError("[Errno 2] No such file or directory: '%s'" % name) elif "r" in mode and fmode != FILE_FMODE: name = '' # or os.devnull? current_size = 0 # or maintain position? else: current_size = os.path.getsize(name) if position > current_size: if strictio: raise ValueError("invalid buffer size") elif fmode == CONTENTS_FMODE: position = current_size # try to open the file by name # NOTE: has different fileno try: #FIXME: missing: *buffering*, encoding, softspace if fmode == FILE_FMODE: f = open(name, mode if "w" in mode else "w") f.write(fdata) if "w" not in mode: f.close() f = open(name, mode) elif name == '': # file did not exist import tempfile f = tempfile.TemporaryFile(mode) elif fmode == CONTENTS_FMODE \ and ("w" in mode or "x" in mode): # stop truncation when opening flags = os.O_CREAT if "+" in mode: flags |= os.O_RDWR else: flags |= os.O_WRONLY f = os.fdopen(os.open(name, flags), mode) # set name to the correct value if PY3: r = getattr(f, "buffer", f) r = getattr(r, "raw", r) r.name = name else: if not HAS_CTYPES: raise ImportError("No module named 'ctypes'") class FILE(ctypes.Structure): _fields_ = [("refcount", ctypes.c_long), ("type_obj", ctypes.py_object), ("file_pointer", ctypes.c_voidp), ("name", ctypes.py_object)] class PyObject(ctypes.Structure): _fields_ = [ ("ob_refcnt", ctypes.c_int), ("ob_type", ctypes.py_object) ] #FIXME: CONTENTS_FMODE fails for pypy due to issue #1233 # https://bitbucket.org/pypy/pypy/issues/1233 ctypes.cast(id(f), ctypes.POINTER(FILE)).contents.name = name ctypes.cast(id(name), ctypes.POINTER(PyObject)).contents.ob_refcnt += 1 assert f.name == name else: f = open(name, mode) except (IOError, FileNotFoundError): err = sys.exc_info()[1] raise UnpicklingError(err) if closed: f.close() elif position >= 0 and fmode != HANDLE_FMODE: f.seek(position) return f def _create_stringi(value, position, closed): f = StringIO(value) if closed: f.close() else: f.seek(position) return f def _create_stringo(value, position, closed): f = StringIO() if closed: f.close() else: f.write(value) f.seek(position) return f class _itemgetter_helper(object): def __init__(self): self.items = [] def __getitem__(self, item): self.items.append(item) return class _attrgetter_helper(object): def __init__(self, attrs, index=None): self.attrs = attrs self.index = index def __getattribute__(self, attr): attrs = object.__getattribute__(self, "attrs") index = object.__getattribute__(self, "index") if index is None: index = len(attrs) attrs.append(attr) else: attrs[index] = ".".join([attrs[index], attr]) return type(self)(attrs, index) if PY3: def _create_cell(contents): return (lambda y: contents).__closure__[0] else: def _create_cell(contents): return (lambda y: contents).func_closure[0] def _create_weakref(obj, *args): from weakref import ref if obj is None: # it's dead if PY3: from collections import UserDict else: from UserDict import UserDict return ref(UserDict(), *args) return ref(obj, *args) def _create_weakproxy(obj, callable=False, *args): from weakref import proxy if obj is None: # it's dead if callable: return proxy(lambda x:x, *args) if PY3: from collections import UserDict else: from UserDict import UserDict return proxy(UserDict(), *args) return proxy(obj, *args) def _eval_repr(repr_str): return eval(repr_str) def _create_array(f, args, state, npdict=None): #array = numpy.core.multiarray._reconstruct(*args) array = f(*args) array.__setstate__(state) if npdict is not None: # we also have saved state in __dict__ array.__dict__.update(npdict) return array def _create_namedtuple(name, fieldnames, modulename): class_ = _import_module(modulename + '.' + name, safe=True) if class_ is not None: return class_ import collections t = collections.namedtuple(name, fieldnames) t.__module__ = modulename return t def _getattr(objclass, name, repr_str): # hack to grab the reference directly try: #XXX: works only for __builtin__ ? attr = repr_str.split("'")[3] return eval(attr+'.__dict__["'+name+'"]') except: try: attr = objclass.__dict__ if type(attr) is DictProxyType: attr = attr[name] else: attr = getattr(objclass,name) except: attr = getattr(objclass,name) return attr def _get_attr(self, name): # stop recursive pickling return getattr(self, name, None) or getattr(__builtin__, name) def _dict_from_dictproxy(dictproxy): _dict = dictproxy.copy() # convert dictproxy to dict _dict.pop('__dict__', None) _dict.pop('__weakref__', None) _dict.pop('__prepare__', None) return _dict def _import_module(import_name, safe=False): try: if '.' in import_name: items = import_name.split('.') module = '.'.join(items[:-1]) obj = items[-1] else: return __import__(import_name) return getattr(__import__(module, None, None, [obj]), obj) except (ImportError, AttributeError): if safe: return None raise def _locate_function(obj, session=False): if obj.__module__ in ['__main__', None]: # and session: return False found = _import_module(obj.__module__ + '.' + obj.__name__, safe=True) return found is obj #@register(CodeType) #def save_code(pickler, obj): # log.info("Co: %s" % obj) # pickler.save_reduce(_unmarshal, (marshal.dumps(obj),), obj=obj) # log.info("# Co") # return # The following function is based on 'save_codeobject' from 'cloudpickle' # Copyright (c) 2012, Regents of the University of California. # Copyright (c) 2009 `PiCloud, Inc. `_. # License: https://github.com/cloudpipe/cloudpickle/blob/master/LICENSE @register(CodeType) def save_code(pickler, obj): log.info("Co: %s" % obj) if PY3: if hasattr(obj, "co_posonlyargcount"): args = ( obj.co_argcount, obj.co_posonlyargcount, obj.co_kwonlyargcount, obj.co_nlocals, obj.co_stacksize, obj.co_flags, obj.co_code, obj.co_consts, obj.co_names, obj.co_varnames, obj.co_filename, obj.co_name, obj.co_firstlineno, obj.co_lnotab, obj.co_freevars, obj.co_cellvars ) else: args = ( obj.co_argcount, obj.co_kwonlyargcount, obj.co_nlocals, obj.co_stacksize, obj.co_flags, obj.co_code, obj.co_consts, obj.co_names, obj.co_varnames, obj.co_filename, obj.co_name, obj.co_firstlineno, obj.co_lnotab, obj.co_freevars, obj.co_cellvars ) else: args = ( obj.co_argcount, obj.co_nlocals, obj.co_stacksize, obj.co_flags, obj.co_code, obj.co_consts, obj.co_names, obj.co_varnames, obj.co_filename, obj.co_name, obj.co_firstlineno, obj.co_lnotab, obj.co_freevars, obj.co_cellvars ) pickler.save_reduce(CodeType, args, obj=obj) log.info("# Co") return @register(dict) def save_module_dict(pickler, obj): if is_dill(pickler) and obj == pickler._main.__dict__ and not pickler._session: log.info("D1: ')) owner = int(r.split('owner=')[1].split()[0]) if PY3 else getattr(obj, '_RLock__owner') pickler.save_reduce(_create_rlock, (count,owner,), obj=obj) log.info("# RL") return if not IS_PYPY: #@register(SocketType) #FIXME: causes multiprocess test_pickling FAIL def save_socket(pickler, obj): log.info("So: %s" % obj) pickler.save_reduce(*reduce_socket(obj)) log.info("# So") return @register(ItemGetterType) def save_itemgetter(pickler, obj): log.info("Ig: %s" % obj) helper = _itemgetter_helper() obj(helper) pickler.save_reduce(type(obj), tuple(helper.items), obj=obj) log.info("# Ig") return @register(AttrGetterType) def save_attrgetter(pickler, obj): log.info("Ag: %s" % obj) attrs = [] helper = _attrgetter_helper(attrs) obj(helper) pickler.save_reduce(type(obj), tuple(attrs), obj=obj) log.info("# Ag") return def _save_file(pickler, obj, open_): if obj.closed: position = 0 else: obj.flush() if obj in (sys.__stdout__, sys.__stderr__, sys.__stdin__): position = -1 else: position = obj.tell() if is_dill(pickler) and pickler._fmode == FILE_FMODE: f = open_(obj.name, "r") fdata = f.read() f.close() else: fdata = "" if is_dill(pickler): strictio = pickler._strictio fmode = pickler._fmode else: strictio = False fmode = 0 # HANDLE_FMODE pickler.save_reduce(_create_filehandle, (obj.name, obj.mode, position, obj.closed, open_, strictio, fmode, fdata), obj=obj) return @register(FileType) #XXX: in 3.x has buffer=0, needs different _create? @register(BufferedRandomType) @register(BufferedReaderType) @register(BufferedWriterType) @register(TextWrapperType) def save_file(pickler, obj): log.info("Fi: %s" % obj) f = _save_file(pickler, obj, open) log.info("# Fi") return f if PyTextWrapperType: @register(PyBufferedRandomType) @register(PyBufferedReaderType) @register(PyBufferedWriterType) @register(PyTextWrapperType) def save_file(pickler, obj): log.info("Fi: %s" % obj) f = _save_file(pickler, obj, _open) log.info("# Fi") return f # The following two functions are based on 'saveCStringIoInput' # and 'saveCStringIoOutput' from spickle # Copyright (c) 2011 by science+computing ag # License: http://www.apache.org/licenses/LICENSE-2.0 if InputType: @register(InputType) def save_stringi(pickler, obj): log.info("Io: %s" % obj) if obj.closed: value = ''; position = 0 else: value = obj.getvalue(); position = obj.tell() pickler.save_reduce(_create_stringi, (value, position, \ obj.closed), obj=obj) log.info("# Io") return @register(OutputType) def save_stringo(pickler, obj): log.info("Io: %s" % obj) if obj.closed: value = ''; position = 0 else: value = obj.getvalue(); position = obj.tell() pickler.save_reduce(_create_stringo, (value, position, \ obj.closed), obj=obj) log.info("# Io") return @register(PartialType) def save_functor(pickler, obj): log.info("Fu: %s" % obj) pickler.save_reduce(_create_ftype, (type(obj), obj.func, obj.args, obj.keywords), obj=obj) log.info("# Fu") return @register(SuperType) def save_super(pickler, obj): log.info("Su: %s" % obj) pickler.save_reduce(super, (obj.__thisclass__, obj.__self__), obj=obj) log.info("# Su") return @register(BuiltinMethodType) def save_builtin_method(pickler, obj): if obj.__self__ is not None: if obj.__self__ is __builtin__: module = 'builtins' if PY3 else '__builtin__' _t = "B1" log.info("%s: %s" % (_t, obj)) else: module = obj.__self__ _t = "B3" log.info("%s: %s" % (_t, obj)) if is_dill(pickler): _recurse = pickler._recurse pickler._recurse = False pickler.save_reduce(_get_attr, (module, obj.__name__), obj=obj) if is_dill(pickler): pickler._recurse = _recurse log.info("# %s" % _t) else: log.info("B2: %s" % obj) StockPickler.save_global(pickler, obj) log.info("# B2") return @register(MethodType) #FIXME: fails for 'hidden' or 'name-mangled' classes def save_instancemethod0(pickler, obj):# example: cStringIO.StringI log.info("Me: %s" % obj) #XXX: obj.__dict__ handled elsewhere? if PY3: pickler.save_reduce(MethodType, (obj.__func__, obj.__self__), obj=obj) else: pickler.save_reduce(MethodType, (obj.im_func, obj.im_self, obj.im_class), obj=obj) log.info("# Me") return if sys.hexversion >= 0x20500f0: if not IS_PYPY: @register(MemberDescriptorType) @register(GetSetDescriptorType) @register(MethodDescriptorType) @register(WrapperDescriptorType) @register(ClassMethodDescriptorType) def save_wrapper_descriptor(pickler, obj): log.info("Wr: %s" % obj) pickler.save_reduce(_getattr, (obj.__objclass__, obj.__name__, obj.__repr__()), obj=obj) log.info("# Wr") return else: @register(MemberDescriptorType) @register(GetSetDescriptorType) def save_wrapper_descriptor(pickler, obj): log.info("Wr: %s" % obj) pickler.save_reduce(_getattr, (obj.__objclass__, obj.__name__, obj.__repr__()), obj=obj) log.info("# Wr") return @register(MethodWrapperType) def save_instancemethod(pickler, obj): log.info("Mw: %s" % obj) pickler.save_reduce(getattr, (obj.__self__, obj.__name__), obj=obj) log.info("# Mw") return elif not IS_PYPY: @register(MethodDescriptorType) @register(WrapperDescriptorType) def save_wrapper_descriptor(pickler, obj): log.info("Wr: %s" % obj) pickler.save_reduce(_getattr, (obj.__objclass__, obj.__name__, obj.__repr__()), obj=obj) log.info("# Wr") return @register(CellType) def save_cell(pickler, obj): log.info("Ce: %s" % obj) f = obj.cell_contents pickler.save_reduce(_create_cell, (f,), obj=obj) log.info("# Ce") return if not IS_PYPY: if not OLD33: @register(DictProxyType) def save_dictproxy(pickler, obj): log.info("Mp: %s" % obj) pickler.save_reduce(DictProxyType, (obj.copy(),), obj=obj) log.info("# Mp") return else: # The following function is based on 'saveDictProxy' from spickle # Copyright (c) 2011 by science+computing ag # License: http://www.apache.org/licenses/LICENSE-2.0 @register(DictProxyType) def save_dictproxy(pickler, obj): log.info("Dp: %s" % obj) attr = obj.get('__dict__') #pickler.save_reduce(_create_dictproxy, (attr,'nested'), obj=obj) if type(attr) == GetSetDescriptorType and attr.__name__ == "__dict__" \ and getattr(attr.__objclass__, "__dict__", None) == obj: pickler.save_reduce(getattr, (attr.__objclass__,"__dict__"),obj=obj) log.info("# Dp") return # all bad below... so throw ReferenceError or TypeError raise ReferenceError("%s does not reference a class __dict__" % obj) @register(SliceType) def save_slice(pickler, obj): log.info("Sl: %s" % obj) pickler.save_reduce(slice, (obj.start, obj.stop, obj.step), obj=obj) log.info("# Sl") return @register(XRangeType) @register(EllipsisType) @register(NotImplementedType) def save_singleton(pickler, obj): log.info("Si: %s" % obj) pickler.save_reduce(_eval_repr, (obj.__repr__(),), obj=obj) log.info("# Si") return def _proxy_helper(obj): # a dead proxy returns a reference to None """get memory address of proxy's reference object""" _repr = repr(obj) try: _str = str(obj) except ReferenceError: # it's a dead proxy return id(None) if _str == _repr: return id(obj) # it's a repr try: # either way, it's a proxy from here address = int(_str.rstrip('>').split(' at ')[-1], base=16) except ValueError: # special case: proxy of a 'type' if not IS_PYPY: address = int(_repr.rstrip('>').split(' at ')[-1], base=16) else: objects = iter(gc.get_objects()) for _obj in objects: if repr(_obj) == _str: return id(_obj) # all bad below... nothing found so throw ReferenceError msg = "Cannot reference object for proxy at '%s'" % id(obj) raise ReferenceError(msg) return address def _locate_object(address, module=None): """get object located at the given memory address (inverse of id(obj))""" special = [None, True, False] #XXX: more...? for obj in special: if address == id(obj): return obj if module: if PY3: objects = iter(module.__dict__.values()) else: objects = module.__dict__.itervalues() else: objects = iter(gc.get_objects()) for obj in objects: if address == id(obj): return obj # all bad below... nothing found so throw ReferenceError or TypeError try: address = hex(address) except TypeError: raise TypeError("'%s' is not a valid memory address" % str(address)) raise ReferenceError("Cannot reference object at '%s'" % address) @register(ReferenceType) def save_weakref(pickler, obj): refobj = obj() log.info("R1: %s" % obj) #refobj = ctypes.pythonapi.PyWeakref_GetObject(obj) # dead returns "None" pickler.save_reduce(_create_weakref, (refobj,), obj=obj) log.info("# R1") return @register(ProxyType) @register(CallableProxyType) def save_weakproxy(pickler, obj): refobj = _locate_object(_proxy_helper(obj)) try: _t = "R2" log.info("%s: %s" % (_t, obj)) except ReferenceError: _t = "R3" log.info("%s: %s" % (_t, sys.exc_info()[1])) #callable = bool(getattr(refobj, '__call__', None)) if type(obj) is CallableProxyType: callable = True else: callable = False pickler.save_reduce(_create_weakproxy, (refobj, callable), obj=obj) log.info("# %s" % _t) return @register(ModuleType) def save_module(pickler, obj): if False: #_use_diff: if obj.__name__ != "dill": try: changed = diff.whats_changed(obj, seen=pickler._diff_cache)[0] except RuntimeError: # not memorised module, probably part of dill pass else: log.info("M1: %s with diff" % obj) log.info("Diff: %s", changed.keys()) pickler.save_reduce(_import_module, (obj.__name__,), obj=obj, state=changed) log.info("# M1") return log.info("M2: %s" % obj) pickler.save_reduce(_import_module, (obj.__name__,), obj=obj) log.info("# M2") else: # if a module file name starts with prefix, it should be a builtin # module, so should be pickled as a reference if hasattr(obj, "__file__"): names = ["base_prefix", "base_exec_prefix", "exec_prefix", "prefix", "real_prefix"] builtin_mod = any([obj.__file__.startswith(os.path.normpath(getattr(sys, name))) for name in names if hasattr(sys, name)]) builtin_mod = builtin_mod or 'site-packages' in obj.__file__ else: builtin_mod = True if obj.__name__ not in ("builtins", "dill") \ and not builtin_mod or is_dill(pickler) and obj is pickler._main: log.info("M1: %s" % obj) _main_dict = obj.__dict__.copy() #XXX: better no copy? option to copy? [_main_dict.pop(item, None) for item in singletontypes + ["__builtins__", "__loader__"]] pickler.save_reduce(_import_module, (obj.__name__,), obj=obj, state=_main_dict) log.info("# M1") else: log.info("M2: %s" % obj) pickler.save_reduce(_import_module, (obj.__name__,), obj=obj) log.info("# M2") return return @register(TypeType) def save_type(pickler, obj): #stack[id(obj)] = len(stack), obj #XXX: probably don't obj in all cases below if obj in _typemap: log.info("T1: %s" % obj) pickler.save_reduce(_load_type, (_typemap[obj],), obj=obj) log.info("# T1") elif issubclass(obj, tuple) and all([hasattr(obj, attr) for attr in ('_fields','_asdict','_make','_replace')]): # special case: namedtuples log.info("T6: %s" % obj) pickler.save_reduce(_create_namedtuple, (getattr(obj, "__qualname__", obj.__name__), obj._fields, obj.__module__), obj=obj) log.info("# T6") return elif obj.__module__ == '__main__': if issubclass(type(obj), type): # try: # used when pickling the class as code (or the interpreter) if is_dill(pickler) and not pickler._byref: # thanks to Tom Stepleton pointing out pickler._session unneeded _t = 'T2' log.info("%s: %s" % (_t, obj)) _dict = _dict_from_dictproxy(obj.__dict__) # except: # punt to StockPickler (pickle by class reference) else: log.info("T5: %s" % obj) StockPickler.save_global(pickler, obj) log.info("# T5") return else: _t = 'T3' log.info("%s: %s" % (_t, obj)) _dict = obj.__dict__ #print (_dict) #print ("%s\n%s" % (type(obj), obj.__name__)) #print ("%s\n%s" % (obj.__bases__, obj.__dict__)) for name in _dict.get("__slots__", []): del _dict[name] pickler.save_reduce(_create_type, (type(obj), obj.__name__, obj.__bases__, _dict), obj=obj) log.info("# %s" % _t) # special cases: NoneType elif obj is type(None): log.info("T7: %s" % obj) if PY3: pickler.write(bytes('c__builtin__\nNoneType\n', 'UTF-8')) else: pickler.write('c__builtin__\nNoneType\n') log.info("# T7") else: log.info("T4: %s" % obj) #print (obj.__dict__) #print ("%s\n%s" % (type(obj), obj.__name__)) #print ("%s\n%s" % (obj.__bases__, obj.__dict__)) StockPickler.save_global(pickler, obj) log.info("# T4") return @register(property) def save_property(pickler, obj): log.info("Pr: %s" % obj) pickler.save_reduce(property, (obj.fget, obj.fset, obj.fdel, obj.__doc__), obj=obj) log.info("# Pr") @register(staticmethod) @register(classmethod) def save_classmethod(pickler, obj): log.info("Cm: %s" % obj) im_func = '__func__' if PY3 else 'im_func' try: orig_func = getattr(obj, im_func) except AttributeError: # Python 2.6 orig_func = obj.__get__(None, object) if isinstance(obj, classmethod): orig_func = getattr(orig_func, im_func) # Unbind pickler.save_reduce(type(obj), (orig_func,), obj=obj) log.info("# Cm") @register(FunctionType) def save_function(pickler, obj): if not _locate_function(obj): #, pickler._session): log.info("F1: %s" % obj) if getattr(pickler, '_recurse', False): # recurse to get all globals referred to by obj from .detect import globalvars globs = globalvars(obj, recurse=True, builtin=True) # remove objects that have already been serialized #stacktypes = (ClassType, TypeType, FunctionType) #for key,value in list(globs.items()): # if isinstance(value, stacktypes) and id(value) in stack: # del globs[key] # ABORT: if self-references, use _recurse=False if id(obj) in stack: # or obj in globs.values(): globs = obj.__globals__ if PY3 else obj.func_globals else: globs = obj.__globals__ if PY3 else obj.func_globals _byref = getattr(pickler, '_byref', None) _recurse = getattr(pickler, '_recurse', None) _memo = (id(obj) in stack) and (_recurse is not None) #print("stack: %s + '%s'" % (set(hex(i) for i in stack),hex(id(obj)))) stack[id(obj)] = len(stack), obj if PY3: #NOTE: workaround for 'super' (see issue #75) _super = ('super' in getattr(obj.__code__,'co_names',())) and (_byref is not None) if _super: pickler._byref = True if _memo: pickler._recurse = False fkwdefaults = getattr(obj, '__kwdefaults__', None) pickler.save_reduce(_create_function, (obj.__code__, globs, obj.__name__, obj.__defaults__, obj.__closure__, obj.__dict__, fkwdefaults), obj=obj) else: _super = ('super' in getattr(obj.func_code,'co_names',())) and (_byref is not None) and getattr(pickler, '_recurse', False) if _super: pickler._byref = True if _memo: pickler._recurse = False pickler.save_reduce(_create_function, (obj.func_code, globs, obj.func_name, obj.func_defaults, obj.func_closure, obj.__dict__), obj=obj) if _super: pickler._byref = _byref if _memo: pickler._recurse = _recurse #clear = (_byref, _super, _recurse, _memo) #print(clear + (OLDER,)) #NOTE: workaround for #234; "partial" still is problematic for recurse if OLDER and not _byref and (_super or (not _super and _memo) or (not _super and not _memo and _recurse)): pickler.clear_memo() #if _memo: # stack.remove(id(obj)) # #pickler.clear_memo() # #StockPickler.clear_memo(pickler) log.info("# F1") else: log.info("F2: %s" % obj) StockPickler.save_global(pickler, obj) #NOTE: also takes name=... log.info("# F2") return # quick sanity checking def pickles(obj,exact=False,safe=False,**kwds): """quick check if object pickles with dill""" if safe: exceptions = (Exception,) # RuntimeError, ValueError else: exceptions = (TypeError, AssertionError, PicklingError, UnpicklingError) try: pik = copy(obj, **kwds) try: result = bool(pik.all() == obj.all()) except AttributeError: result = pik == obj if result: return True if not exact: result = type(pik) == type(obj) if result: return result # class instances might have been dumped with byref=False return repr(type(pik)) == repr(type(obj)) #XXX: InstanceType? return False except exceptions: return False def check(obj, *args, **kwds): """check pickling of an object across another process""" # == undocumented == # python -- the string path or executable name of the selected python # verbose -- if True, be verbose about printing warning messages # all other args and kwds are passed to dill.dumps #FIXME: ignore on load verbose = kwds.pop('verbose', False) python = kwds.pop('python', None) if python is None: import sys python = sys.executable # type check isinstance(python, str) import subprocess fail = True try: _obj = dumps(obj, *args, **kwds) fail = False finally: if fail and verbose: print("DUMP FAILED") msg = "%s -c import dill; print(dill.loads(%s))" % (python, repr(_obj)) msg = "SUCCESS" if not subprocess.call(msg.split(None,2)) else "LOAD FAILED" if verbose: print(msg) return # use to protect against missing attributes def is_dill(pickler, child=None): "check the dill-ness of your pickler" if (child is False) or PY34 or (not hasattr(pickler.__class__, 'mro')): return 'dill' in pickler.__module__ return Pickler in pickler.__class__.mro() def _extend(): """extend pickle with all of dill's registered types""" # need to have pickle not choke on _main_module? use is_dill(pickler) for t,func in Pickler.dispatch.items(): try: StockPickler.dispatch[t] = func except: #TypeError, PicklingError, UnpicklingError log.info("skip: %s" % t) else: pass return del diff, _use_diff, use_diff # EOF dill-0.3.1.1/dill/_objects.py000644 000765 000024 00000047714 13543677215 016700 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ all Python Standard Library objects (currently: CH 1-15 @ 2.7) and some other common objects (i.e. numpy.ndarray) """ __all__ = ['registered','failures','succeeds'] # helper imports import warnings; warnings.filterwarnings("ignore", category=DeprecationWarning) import sys PY3 = (hex(sys.hexversion) >= '0x30000f0') if PY3: import queue as Queue import dbm as anydbm else: import Queue import anydbm import sets # deprecated/removed import mutex # removed try: from cStringIO import StringIO # has StringI and StringO types except ImportError: # only has StringIO type if PY3: from io import BytesIO as StringIO else: from StringIO import StringIO import re import array import collections import codecs import struct import datetime import calendar import weakref import pprint import decimal import functools import itertools import operator import tempfile import shelve import zlib import gzip import zipfile import tarfile import xdrlib import csv import hashlib import hmac import os import logging import optparse #import __hello__ import threading import socket import contextlib try: import bz2 import sqlite3 if PY3: import dbm.ndbm as dbm else: import dbm HAS_ALL = True except ImportError: # Ubuntu HAS_ALL = False try: #import curses #from curses import textpad, panel HAS_CURSES = True except ImportError: # Windows HAS_CURSES = False try: import ctypes HAS_CTYPES = True # if using `pypy`, pythonapi is not found IS_PYPY = not hasattr(ctypes, 'pythonapi') except ImportError: # MacPorts HAS_CTYPES = False IS_PYPY = False # helper objects class _class: def _method(self): pass # @classmethod # def _clsmethod(cls): #XXX: test me # pass # @staticmethod # def _static(self): #XXX: test me # pass class _class2: def __call__(self): pass _instance2 = _class2() class _newclass(object): def _method(self): pass # @classmethod # def _clsmethod(cls): #XXX: test me # pass # @staticmethod # def _static(self): #XXX: test me # pass class _newclass2(object): __slots__ = ['descriptor'] def _function(x): yield x def _function2(): try: raise except: from sys import exc_info e, er, tb = exc_info() return er, tb if HAS_CTYPES: class _Struct(ctypes.Structure): pass _Struct._fields_ = [("_field", ctypes.c_int),("next", ctypes.POINTER(_Struct))] _filedescrip, _tempfile = tempfile.mkstemp('r') # deleted in cleanup _tmpf = tempfile.TemporaryFile('w') # put the objects in order, if possible try: from collections import OrderedDict as odict except ImportError: try: from ordereddict import OrderedDict as odict except ImportError: odict = dict # objects used by dill for type declaration registered = d = odict() # objects dill fails to pickle failures = x = odict() # all other type objects succeeds = a = odict() # types module (part of CH 8) a['BooleanType'] = bool(1) a['BuiltinFunctionType'] = len a['BuiltinMethodType'] = a['BuiltinFunctionType'] a['BytesType'] = _bytes = codecs.latin_1_encode('\x00')[0] # bytes(1) a['ClassType'] = _class a['ComplexType'] = complex(1) a['DictType'] = _dict = {} a['DictionaryType'] = a['DictType'] a['FloatType'] = float(1) a['FunctionType'] = _function a['InstanceType'] = _instance = _class() a['IntType'] = _int = int(1) a['ListType'] = _list = [] a['NoneType'] = None a['ObjectType'] = object() a['StringType'] = _str = str(1) a['TupleType'] = _tuple = () a['TypeType'] = type if PY3: a['LongType'] = _int a['UnicodeType'] = _str else: a['LongType'] = long(1) a['UnicodeType'] = unicode(1) # built-in constants (CH 4) a['CopyrightType'] = copyright # built-in types (CH 5) a['ClassObjectType'] = _newclass # a['ClassInstanceType'] = _newclass() # a['SetType'] = _set = set() a['FrozenSetType'] = frozenset() # built-in exceptions (CH 6) a['ExceptionType'] = _exception = _function2()[0] # string services (CH 7) a['SREPatternType'] = _srepattern = re.compile('') # data types (CH 8) a['ArrayType'] = array.array("f") a['DequeType'] = collections.deque([0]) a['DefaultDictType'] = collections.defaultdict(_function, _dict) a['TZInfoType'] = datetime.tzinfo() a['DateTimeType'] = datetime.datetime.today() a['CalendarType'] = calendar.Calendar() if not PY3: a['SetsType'] = sets.Set() a['ImmutableSetType'] = sets.ImmutableSet() a['MutexType'] = mutex.mutex() # numeric and mathematical types (CH 9) a['DecimalType'] = decimal.Decimal(1) a['CountType'] = itertools.count(0) # data compression and archiving (CH 12) a['TarInfoType'] = tarfile.TarInfo() # generic operating system services (CH 15) a['LoggerType'] = logging.getLogger() a['FormatterType'] = logging.Formatter() # pickle ok a['FilterType'] = logging.Filter() # pickle ok a['LogRecordType'] = logging.makeLogRecord(_dict) # pickle ok a['OptionParserType'] = _oparser = optparse.OptionParser() # pickle ok a['OptionGroupType'] = optparse.OptionGroup(_oparser,"foo") # pickle ok a['OptionType'] = optparse.Option('--foo') # pickle ok if HAS_CTYPES: a['CCharType'] = _cchar = ctypes.c_char() a['CWCharType'] = ctypes.c_wchar() # fail == 2.6 a['CByteType'] = ctypes.c_byte() a['CUByteType'] = ctypes.c_ubyte() a['CShortType'] = ctypes.c_short() a['CUShortType'] = ctypes.c_ushort() a['CIntType'] = ctypes.c_int() a['CUIntType'] = ctypes.c_uint() a['CLongType'] = ctypes.c_long() a['CULongType'] = ctypes.c_ulong() a['CLongLongType'] = ctypes.c_longlong() a['CULongLongType'] = ctypes.c_ulonglong() a['CFloatType'] = ctypes.c_float() a['CDoubleType'] = ctypes.c_double() a['CSizeTType'] = ctypes.c_size_t() a['CLibraryLoaderType'] = ctypes.cdll a['StructureType'] = _Struct if not IS_PYPY: a['BigEndianStructureType'] = ctypes.BigEndianStructure() #NOTE: also LittleEndianStructureType and UnionType... abstract classes #NOTE: remember for ctypesobj.contents creates a new python object #NOTE: ctypes.c_int._objects is memberdescriptor for object's __dict__ #NOTE: base class of all ctypes data types is non-public _CData try: # python 2.6 import fractions import number import io from io import StringIO as TextIO # built-in functions (CH 2) a['ByteArrayType'] = bytearray([1]) # numeric and mathematical types (CH 9) a['FractionType'] = fractions.Fraction() a['NumberType'] = numbers.Number() # generic operating system services (CH 15) a['IOBaseType'] = io.IOBase() a['RawIOBaseType'] = io.RawIOBase() a['TextIOBaseType'] = io.TextIOBase() a['BufferedIOBaseType'] = io.BufferedIOBase() a['UnicodeIOType'] = TextIO() # the new StringIO a['LoggingAdapterType'] = logging.LoggingAdapter(_logger,_dict) # pickle ok if HAS_CTYPES: a['CBoolType'] = ctypes.c_bool(1) a['CLongDoubleType'] = ctypes.c_longdouble() except ImportError: pass try: # python 2.7 import argparse # data types (CH 8) a['OrderedDictType'] = collections.OrderedDict(_dict) a['CounterType'] = collections.Counter(_dict) if HAS_CTYPES: a['CSSizeTType'] = ctypes.c_ssize_t() # generic operating system services (CH 15) a['NullHandlerType'] = logging.NullHandler() # pickle ok # new 2.7 a['ArgParseFileType'] = argparse.FileType() # pickle ok except (AttributeError, ImportError): pass # -- pickle fails on all below here ----------------------------------------- # types module (part of CH 8) a['CodeType'] = compile('','','exec') a['DictProxyType'] = type.__dict__ a['DictProxyType2'] = _newclass.__dict__ a['EllipsisType'] = Ellipsis a['ClosedFileType'] = open(os.devnull, 'wb', buffering=0).close() a['GetSetDescriptorType'] = array.array.typecode a['LambdaType'] = _lambda = lambda x: lambda y: x #XXX: works when not imported! a['MemberDescriptorType'] = _newclass2.descriptor if not IS_PYPY: a['MemberDescriptorType2'] = datetime.timedelta.days a['MethodType'] = _method = _class()._method #XXX: works when not imported! a['ModuleType'] = datetime a['NotImplementedType'] = NotImplemented a['SliceType'] = slice(1) a['UnboundMethodType'] = _class._method #XXX: works when not imported! a['TextWrapperType'] = open(os.devnull, 'r') # same as mode='w','w+','r+' a['BufferedRandomType'] = open(os.devnull, 'r+b') # same as mode='w+b' a['BufferedReaderType'] = open(os.devnull, 'rb') # (default: buffering=-1) a['BufferedWriterType'] = open(os.devnull, 'wb') try: # oddities: deprecated from _pyio import open as _open a['PyTextWrapperType'] = _open(os.devnull, 'r', buffering=-1) a['PyBufferedRandomType'] = _open(os.devnull, 'r+b', buffering=-1) a['PyBufferedReaderType'] = _open(os.devnull, 'rb', buffering=-1) a['PyBufferedWriterType'] = _open(os.devnull, 'wb', buffering=-1) except ImportError: pass # other (concrete) object types if PY3: d['CellType'] = (_lambda)(0).__closure__[0] a['XRangeType'] = _xrange = range(1) else: d['CellType'] = (_lambda)(0).func_closure[0] a['XRangeType'] = _xrange = xrange(1) if not IS_PYPY: d['MethodDescriptorType'] = type.__dict__['mro'] d['WrapperDescriptorType'] = type.__repr__ a['WrapperDescriptorType2'] = type.__dict__['__module__'] d['ClassMethodDescriptorType'] = type.__dict__['__prepare__' if PY3 else 'mro'] # built-in functions (CH 2) if PY3 or IS_PYPY: _methodwrap = (1).__lt__ else: _methodwrap = (1).__cmp__ d['MethodWrapperType'] = _methodwrap a['StaticMethodType'] = staticmethod(_method) a['ClassMethodType'] = classmethod(_method) a['PropertyType'] = property() d['SuperType'] = super(Exception, _exception) # string services (CH 7) if PY3: _in = _bytes else: _in = _str a['InputType'] = _cstrI = StringIO(_in) a['OutputType'] = _cstrO = StringIO() # data types (CH 8) a['WeakKeyDictionaryType'] = weakref.WeakKeyDictionary() a['WeakValueDictionaryType'] = weakref.WeakValueDictionary() a['ReferenceType'] = weakref.ref(_instance) a['DeadReferenceType'] = weakref.ref(_class()) a['ProxyType'] = weakref.proxy(_instance) a['DeadProxyType'] = weakref.proxy(_class()) a['CallableProxyType'] = weakref.proxy(_instance2) a['DeadCallableProxyType'] = weakref.proxy(_class2()) a['QueueType'] = Queue.Queue() # numeric and mathematical types (CH 9) d['PartialType'] = functools.partial(int,base=2) if PY3: a['IzipType'] = zip('0','1') else: a['IzipType'] = itertools.izip('0','1') a['ChainType'] = itertools.chain('0','1') d['ItemGetterType'] = operator.itemgetter(0) d['AttrGetterType'] = operator.attrgetter('__repr__') # file and directory access (CH 10) if PY3: _fileW = _cstrO else: _fileW = _tmpf # data persistence (CH 11) if HAS_ALL: a['ConnectionType'] = _conn = sqlite3.connect(':memory:') a['CursorType'] = _conn.cursor() a['ShelveType'] = shelve.Shelf({}) # data compression and archiving (CH 12) if HAS_ALL: if (hex(sys.hexversion) < '0x2070ef0') or PY3: a['BZ2FileType'] = bz2.BZ2File(os.devnull) #FIXME: fail >= 3.3, 2.7.14 a['BZ2CompressorType'] = bz2.BZ2Compressor() a['BZ2DecompressorType'] = bz2.BZ2Decompressor() #a['ZipFileType'] = _zip = zipfile.ZipFile(os.devnull,'w') #FIXME: fail >= 3.2 #_zip.write(_tempfile,'x') [causes annoying warning/error printed on import] #a['ZipInfoType'] = _zip.getinfo('x') a['TarFileType'] = tarfile.open(fileobj=_fileW,mode='w') # file formats (CH 13) a['DialectType'] = csv.get_dialect('excel') a['PackerType'] = xdrlib.Packer() # optional operating system services (CH 16) a['LockType'] = threading.Lock() a['RLockType'] = threading.RLock() # generic operating system services (CH 15) # also closed/open and r/w/etc... a['NamedLoggerType'] = _logger = logging.getLogger(__name__) #FIXME: fail >= 3.2 and <= 2.6 #a['FrozenModuleType'] = __hello__ #FIXME: prints "Hello world..." # interprocess communication (CH 17) if PY3: a['SocketType'] = _socket = socket.socket() #FIXME: fail >= 3.3 a['SocketPairType'] = socket.socketpair()[0] #FIXME: fail >= 3.3 else: a['SocketType'] = _socket = socket.socket() a['SocketPairType'] = _socket._sock # python runtime services (CH 27) if PY3: a['GeneratorContextManagerType'] = contextlib.contextmanager(max)([1]) else: a['GeneratorContextManagerType'] = contextlib.GeneratorContextManager(max) try: # ipython __IPYTHON__ is True # is ipython except NameError: # built-in constants (CH 4) a['QuitterType'] = quit d['ExitType'] = a['QuitterType'] try: # numpy #FIXME: slow... 0.05 to 0.1 sec to import numpy from numpy import ufunc as _numpy_ufunc from numpy import array as _numpy_array from numpy import int32 as _numpy_int32 a['NumpyUfuncType'] = _numpy_ufunc a['NumpyArrayType'] = _numpy_array a['NumpyInt32Type'] = _numpy_int32 except ImportError: pass try: # python 2.6 # numeric and mathematical types (CH 9) a['ProductType'] = itertools.product('0','1') # generic operating system services (CH 15) a['FileHandlerType'] = logging.FileHandler(os.devnull) #FIXME: fail >= 3.2 and <= 2.6 a['RotatingFileHandlerType'] = logging.handlers.RotatingFileHandler(os.devnull) a['SocketHandlerType'] = logging.handlers.SocketHandler('localhost',514) a['MemoryHandlerType'] = logging.handlers.MemoryHandler(1) except AttributeError: pass try: # python 2.7 # data types (CH 8) a['WeakSetType'] = weakref.WeakSet() # 2.7 # # generic operating system services (CH 15) [errors when dill is imported] # a['ArgumentParserType'] = _parser = argparse.ArgumentParser('PROG') # a['NamespaceType'] = _parser.parse_args() # pickle ok # a['SubParsersActionType'] = _parser.add_subparsers() # a['MutuallyExclusiveGroupType'] = _parser.add_mutually_exclusive_group() # a['ArgumentGroupType'] = _parser.add_argument_group() except AttributeError: pass # -- dill fails in some versions below here --------------------------------- # types module (part of CH 8) a['FileType'] = open(os.devnull, 'rb', buffering=0) # same 'wb','wb+','rb+' # FIXME: FileType fails >= 3.1 # built-in functions (CH 2) a['ListIteratorType'] = iter(_list) # empty vs non-empty FIXME: fail < 3.2 a['TupleIteratorType']= iter(_tuple) # empty vs non-empty FIXME: fail < 3.2 a['XRangeIteratorType'] = iter(_xrange) # empty vs non-empty FIXME: fail < 3.2 # data types (CH 8) a['PrettyPrinterType'] = pprint.PrettyPrinter() #FIXME: fail >= 3.2 and == 2.5 # numeric and mathematical types (CH 9) a['CycleType'] = itertools.cycle('0') #FIXME: fail < 3.2 # file and directory access (CH 10) a['TemporaryFileType'] = _tmpf #FIXME: fail >= 3.2 and == 2.5 # data compression and archiving (CH 12) a['GzipFileType'] = gzip.GzipFile(fileobj=_fileW) #FIXME: fail > 3.2 and <= 2.6 # generic operating system services (CH 15) a['StreamHandlerType'] = logging.StreamHandler() #FIXME: fail >= 3.2 and == 2.5 try: # python 2.6 # numeric and mathematical types (CH 9) a['PermutationsType'] = itertools.permutations('0') #FIXME: fail < 3.2 a['CombinationsType'] = itertools.combinations('0',1) #FIXME: fail < 3.2 except AttributeError: pass try: # python 2.7 # numeric and mathematical types (CH 9) a['RepeatType'] = itertools.repeat(0) #FIXME: fail < 3.2 a['CompressType'] = itertools.compress('0',[1]) #FIXME: fail < 3.2 #XXX: ...and etc except AttributeError: pass # -- dill fails on all below here ------------------------------------------- # types module (part of CH 8) x['GeneratorType'] = _generator = _function(1) #XXX: priority x['FrameType'] = _generator.gi_frame #XXX: inspect.currentframe() x['TracebackType'] = _function2()[1] #(see: inspect.getouterframes,getframeinfo) # other (concrete) object types # (also: Capsule / CObject ?) # built-in functions (CH 2) x['SetIteratorType'] = iter(_set) #XXX: empty vs non-empty # built-in types (CH 5) if PY3: x['DictionaryItemIteratorType'] = iter(type.__dict__.items()) x['DictionaryKeyIteratorType'] = iter(type.__dict__.keys()) x['DictionaryValueIteratorType'] = iter(type.__dict__.values()) else: x['DictionaryItemIteratorType'] = type.__dict__.iteritems() x['DictionaryKeyIteratorType'] = type.__dict__.iterkeys() x['DictionaryValueIteratorType'] = type.__dict__.itervalues() # string services (CH 7) x['StructType'] = struct.Struct('c') x['CallableIteratorType'] = _srepattern.finditer('') x['SREMatchType'] = _srepattern.match('') x['SREScannerType'] = _srepattern.scanner('') x['StreamReader'] = codecs.StreamReader(_cstrI) #XXX: ... and etc # python object persistence (CH 11) # x['DbShelveType'] = shelve.open('foo','n')#,protocol=2) #XXX: delete foo if HAS_ALL: x['DbmType'] = dbm.open(_tempfile,'n') # x['DbCursorType'] = _dbcursor = anydbm.open('foo','n') #XXX: delete foo # x['DbType'] = _dbcursor.db # data compression and archiving (CH 12) x['ZlibCompressType'] = zlib.compressobj() x['ZlibDecompressType'] = zlib.decompressobj() # file formats (CH 13) x['CSVReaderType'] = csv.reader(_cstrI) x['CSVWriterType'] = csv.writer(_cstrO) x['CSVDictReaderType'] = csv.DictReader(_cstrI) x['CSVDictWriterType'] = csv.DictWriter(_cstrO,{}) # cryptographic services (CH 14) x['HashType'] = hashlib.md5() if (hex(sys.hexversion) < '0x30800a1'): x['HMACType'] = hmac.new(_in) else: x['HMACType'] = hmac.new(_in, digestmod='md5') # generic operating system services (CH 15) if HAS_CURSES: pass #x['CursesWindowType'] = _curwin = curses.initscr() #FIXME: messes up tty #x['CursesTextPadType'] = textpad.Textbox(_curwin) #x['CursesPanelType'] = panel.new_panel(_curwin) if HAS_CTYPES: x['CCharPType'] = ctypes.c_char_p() x['CWCharPType'] = ctypes.c_wchar_p() x['CVoidPType'] = ctypes.c_void_p() if sys.platform[:3] == 'win': x['CDLLType'] = _cdll = ctypes.cdll.msvcrt else: x['CDLLType'] = _cdll = ctypes.CDLL(None) if not IS_PYPY: x['PyDLLType'] = _pydll = ctypes.pythonapi x['FuncPtrType'] = _cdll._FuncPtr() x['CCharArrayType'] = ctypes.create_string_buffer(1) x['CWCharArrayType'] = ctypes.create_unicode_buffer(1) x['CParamType'] = ctypes.byref(_cchar) x['LPCCharType'] = ctypes.pointer(_cchar) x['LPCCharObjType'] = _lpchar = ctypes.POINTER(ctypes.c_char) x['NullPtrType'] = _lpchar() x['NullPyObjectType'] = ctypes.py_object() x['PyObjectType'] = ctypes.py_object(lambda :None) x['FieldType'] = _field = _Struct._field x['CFUNCTYPEType'] = _cfunc = ctypes.CFUNCTYPE(ctypes.c_char) x['CFunctionType'] = _cfunc(str) try: # python 2.6 # numeric and mathematical types (CH 9) x['MethodCallerType'] = operator.methodcaller('mro') # 2.6 except AttributeError: pass try: # python 2.7 # built-in types (CH 5) x['MemoryType'] = memoryview(_in) # 2.7 x['MemoryType2'] = memoryview(bytearray(_in)) # 2.7 if PY3: x['DictItemsType'] = _dict.items() # 2.7 x['DictKeysType'] = _dict.keys() # 2.7 x['DictValuesType'] = _dict.values() # 2.7 else: x['DictItemsType'] = _dict.viewitems() # 2.7 x['DictKeysType'] = _dict.viewkeys() # 2.7 x['DictValuesType'] = _dict.viewvalues() # 2.7 # generic operating system services (CH 15) x['RawTextHelpFormatterType'] = argparse.RawTextHelpFormatter('PROG') x['RawDescriptionHelpFormatterType'] = argparse.RawDescriptionHelpFormatter('PROG') x['ArgDefaultsHelpFormatterType'] = argparse.ArgumentDefaultsHelpFormatter('PROG') except NameError: pass try: # python 2.7 (and not 3.1) x['CmpKeyType'] = _cmpkey = functools.cmp_to_key(_methodwrap) # 2.7, >=3.2 x['CmpKeyObjType'] = _cmpkey('0') #2.7, >=3.2 except AttributeError: pass if PY3: # oddities: removed, etc x['BufferType'] = x['MemoryType'] else: x['BufferType'] = buffer('') # -- cleanup ---------------------------------------------------------------- a.update(d) # registered also succeed if sys.platform[:3] == 'win': os.close(_filedescrip) # required on win32 os.remove(_tempfile) # EOF dill-0.3.1.1/dill/detect.py000644 000765 000024 00000027056 13543677215 016355 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ Methods for detecting objects leading to pickling failures. """ import dis from inspect import ismethod, isfunction, istraceback, isframe, iscode from .pointers import parent, reference, at, parents, children from ._dill import _trace as trace from ._dill import PY3 __all__ = ['baditems','badobjects','badtypes','code','errors','freevars', 'getmodule','globalvars','nestedcode','nestedglobals','outermost', 'referredglobals','referrednested','trace','varnames'] def getmodule(object, _filename=None, force=False): """get the module of the object""" from inspect import getmodule as getmod module = getmod(object, _filename) if module or not force: return module if PY3: builtins = 'builtins' else: builtins = '__builtin__' builtins = __import__(builtins) from .source import getname name = getname(object, force=True) return builtins if name in vars(builtins).keys() else None def outermost(func): # is analogous to getsource(func,enclosing=True) """get outermost enclosing object (i.e. the outer function in a closure) NOTE: this is the object-equivalent of getsource(func, enclosing=True) """ if PY3: if ismethod(func): _globals = func.__func__.__globals__ or {} elif isfunction(func): _globals = func.__globals__ or {} else: return #XXX: or raise? no matches _globals = _globals.items() else: if ismethod(func): _globals = func.im_func.func_globals or {} elif isfunction(func): _globals = func.func_globals or {} else: return #XXX: or raise? no matches _globals = _globals.iteritems() # get the enclosing source from .source import getsourcelines try: lines,lnum = getsourcelines(func, enclosing=True) except: #TypeError, IOError lines,lnum = [],None code = ''.join(lines) # get all possible names,objects that are named in the enclosing source _locals = ((name,obj) for (name,obj) in _globals if name in code) # now only save the objects that generate the enclosing block for name,obj in _locals: #XXX: don't really need 'name' try: if getsourcelines(obj) == (lines,lnum): return obj except: #TypeError, IOError pass return #XXX: or raise? no matches def nestedcode(func, recurse=True): #XXX: or return dict of {co_name: co} ? """get the code objects for any nested functions (e.g. in a closure)""" func = code(func) if not iscode(func): return [] #XXX: or raise? no matches nested = set() for co in func.co_consts: if co is None: continue co = code(co) if co: nested.add(co) if recurse: nested |= set(nestedcode(co, recurse=True)) return list(nested) def code(func): '''get the code object for the given function or method NOTE: use dill.source.getsource(CODEOBJ) to get the source code ''' if PY3: im_func = '__func__' func_code = '__code__' else: im_func = 'im_func' func_code = 'func_code' if ismethod(func): func = getattr(func, im_func) if isfunction(func): func = getattr(func, func_code) if istraceback(func): func = func.tb_frame if isframe(func): func = func.f_code if iscode(func): return func return #XXX: ugly: parse dis.dis for name after " len(referrednested(func)), try calling func(). If possible, python builds code objects, but delays building functions until func() is called. """ if PY3: att1 = '__code__' att0 = '__func__' else: att1 = 'func_code' # functions att0 = 'im_func' # methods import gc funcs = set() # get the code objects, and try to track down by referrence for co in nestedcode(func, recurse): # look for function objects that refer to the code object for obj in gc.get_referrers(co): # get methods _ = getattr(obj, att0, None) # ismethod if getattr(_, att1, None) is co: funcs.add(obj) # get functions elif getattr(obj, att1, None) is co: funcs.add(obj) # get frame objects elif getattr(obj, 'f_code', None) is co: funcs.add(obj) # get code objects elif hasattr(obj, 'co_code') and obj is co: funcs.add(obj) # frameobjs => func.func_code.co_varnames not in func.func_code.co_cellvars # funcobjs => func.func_code.co_cellvars not in func.func_code.co_varnames # frameobjs are not found, however funcobjs are... # (see: test_mixins.quad ... and test_mixins.wtf) # after execution, code objects get compiled, and then may be found by gc return list(funcs) def freevars(func): """get objects defined in enclosing code that are referred to by func returns a dict of {name:object}""" if PY3: im_func = '__func__' func_code = '__code__' func_closure = '__closure__' else: im_func = 'im_func' func_code = 'func_code' func_closure = 'func_closure' if ismethod(func): func = getattr(func, im_func) if isfunction(func): closures = getattr(func, func_closure) or () func = getattr(func, func_code).co_freevars # get freevars else: return {} return dict((name,c.cell_contents) for (name,c) in zip(func,closures)) # thanks to Davies Liu for recursion of globals def nestedglobals(func, recurse=True): """get the names of any globals found within func""" func = code(func) if func is None: return list() from .temp import capture names = set() with capture('stdout') as out: dis.dis(func) #XXX: dis.dis(None) disassembles last traceback for line in out.getvalue().splitlines(): if '_GLOBAL' in line: name = line.split('(')[-1].split(')')[0] names.add(name) for co in getattr(func, 'co_consts', tuple()): if co and recurse and iscode(co): names.update(nestedglobals(co, recurse=True)) return list(names) def referredglobals(func, recurse=True, builtin=False): """get the names of objects in the global scope referred to by func""" return globalvars(func, recurse, builtin).keys() def globalvars(func, recurse=True, builtin=False): """get objects defined in global scope that are referred to by func return a dict of {name:object}""" if PY3: im_func = '__func__' func_code = '__code__' func_globals = '__globals__' func_closure = '__closure__' else: im_func = 'im_func' func_code = 'func_code' func_globals = 'func_globals' func_closure = 'func_closure' if ismethod(func): func = getattr(func, im_func) if isfunction(func): globs = vars(getmodule(sum)).copy() if builtin else {} # get references from within closure orig_func, func = func, set() for obj in getattr(orig_func, func_closure) or {}: _vars = globalvars(obj.cell_contents, recurse, builtin) or {} func.update(_vars) #XXX: (above) be wary of infinte recursion? globs.update(_vars) # get globals globs.update(getattr(orig_func, func_globals) or {}) # get names of references if not recurse: func.update(getattr(orig_func, func_code).co_names) else: func.update(nestedglobals(getattr(orig_func, func_code))) # find globals for all entries of func for key in func.copy(): #XXX: unnecessary...? nested_func = globs.get(key) if nested_func is orig_func: #func.remove(key) if key in func else None continue #XXX: globalvars(func, False)? func.update(globalvars(nested_func, True, builtin)) elif iscode(func): globs = vars(getmodule(sum)).copy() if builtin else {} #globs.update(globals()) if not recurse: func = func.co_names # get names else: orig_func = func.co_name # to stop infinite recursion func = set(nestedglobals(func)) # find globals for all entries of func for key in func.copy(): #XXX: unnecessary...? if key is orig_func: #func.remove(key) if key in func else None continue #XXX: globalvars(func, False)? nested_func = globs.get(key) func.update(globalvars(nested_func, True, builtin)) else: return {} #NOTE: if name not in func_globals, then we skip it... return dict((name,globs[name]) for name in func if name in globs) def varnames(func): """get names of variables defined by func returns a tuple (local vars, local vars referrenced by nested functions)""" func = code(func) if not iscode(func): return () #XXX: better ((),())? or None? return func.co_varnames, func.co_cellvars def baditems(obj, exact=False, safe=False): #XXX: obj=globals() ? """get items in object that fail to pickle""" if not hasattr(obj,'__iter__'): # is not iterable return [j for j in (badobjects(obj,0,exact,safe),) if j is not None] obj = obj.values() if getattr(obj,'values',None) else obj _obj = [] # can't use a set, as items may be unhashable [_obj.append(badobjects(i,0,exact,safe)) for i in obj if i not in _obj] return [j for j in _obj if j is not None] def badobjects(obj, depth=0, exact=False, safe=False): """get objects that fail to pickle""" from dill import pickles if not depth: if pickles(obj,exact,safe): return None return obj return dict(((attr, badobjects(getattr(obj,attr),depth-1,exact,safe)) \ for attr in dir(obj) if not pickles(getattr(obj,attr),exact,safe))) def badtypes(obj, depth=0, exact=False, safe=False): """get types for objects that fail to pickle""" from dill import pickles if not depth: if pickles(obj,exact,safe): return None return type(obj) return dict(((attr, badtypes(getattr(obj,attr),depth-1,exact,safe)) \ for attr in dir(obj) if not pickles(getattr(obj,attr),exact,safe))) def errors(obj, depth=0, exact=False, safe=False): """get errors for objects that fail to pickle""" from dill import pickles, copy if not depth: try: pik = copy(obj) if exact: assert pik == obj, \ "Unpickling produces %s instead of %s" % (pik,obj) assert type(pik) == type(obj), \ "Unpickling produces %s instead of %s" % (type(pik),type(obj)) return None except Exception: import sys return sys.exc_info()[1] _dict = {} for attr in dir(obj): try: _attr = getattr(obj,attr) except Exception: import sys _dict[attr] = sys.exc_info()[1] continue if not pickles(_attr,exact,safe): _dict[attr] = errors(_attr,depth-1,exact,safe) return _dict # EOF dill-0.3.1.1/dill/info.py000644 000765 000024 00000016436 13543677347 016046 0ustar00mmckernsstaff000000 000000 # THIS FILE GENERATED FROM SETUP.PY this_version = '0.3.1.1' stable_version = '0.3.1.1' readme = '''----------------------------- dill: serialize all of python ----------------------------- About Dill ========== ``dill`` extends python's ``pickle`` module for serializing and de-serializing python objects to the majority of the built-in python types. Serialization is the process of converting an object to a byte stream, and the inverse of which is converting a byte stream back to on python object hierarchy. ``dill`` provides the user the same interface as the ``pickle`` module, and also includes some additional features. In addition to pickling python objects, ``dill`` provides the ability to save the state of an interpreter session in a single command. Hence, it would be feasable to save a interpreter session, close the interpreter, ship the pickled file to another computer, open a new interpreter, unpickle the session and thus continue from the 'saved' state of the original interpreter session. ``dill`` can be used to store python objects to a file, but the primary usage is to send python objects across the network as a byte stream. ``dill`` is quite flexible, and allows arbitrary user defined classes and functions to be serialized. Thus ``dill`` is not intended to be secure against erroneously or maliciously constructed data. It is left to the user to decide whether the data they unpickle is from a trustworthy source. ``dill`` is part of ``pathos``, a python framework for heterogeneous computing. ``dill`` is in active development, so any user feedback, bug reports, comments, or suggestions are highly appreciated. A list of known issues is maintained at http://trac.mystic.cacr.caltech.edu/project/pathos/query.html, with a public ticket list at https://github.com/uqfoundation/dill/issues. Major Features ============== ``dill`` can pickle the following standard types: - none, type, bool, int, long, float, complex, str, unicode, - tuple, list, dict, file, buffer, builtin, - both old and new style classes, - instances of old and new style classes, - set, frozenset, array, functions, exceptions ``dill`` can also pickle more 'exotic' standard types: - functions with yields, nested functions, lambdas, - cell, method, unboundmethod, module, code, methodwrapper, - dictproxy, methoddescriptor, getsetdescriptor, memberdescriptor, - wrapperdescriptor, xrange, slice, - notimplemented, ellipsis, quit ``dill`` cannot yet pickle these standard types: - frame, generator, traceback ``dill`` also provides the capability to: - save and load python interpreter sessions - save and extract the source code from functions and classes - interactively diagnose pickling errors Current Release =============== This documentation is for version ``dill-0.3.1.1``. The latest released version of ``dill`` is available from: https://pypi.org/project/dill ``dill`` is distributed under a 3-clause BSD license. >>> import dill >>> print (dill.license()) Development Version =================== You can get the latest development version with all the shiny new features at: https://github.com/uqfoundation If you have a new contribution, please submit a pull request. Installation ============ ``dill`` is packaged to install from source, so you must download the tarball, unzip, and run the installer:: [download] $ tar -xvzf dill-0.3.1.1.tar.gz $ cd dill-0.3.1.1 $ python setup py build $ python setup py install You will be warned of any missing dependencies and/or settings after you run the "build" step above. Alternately, ``dill`` can be installed with ``pip`` or ``easy_install``:: $ pip install dill Requirements ============ ``dill`` requires: - ``python``, **version >= 2.6** or **version >= 3.1**, or ``pypy`` Optional requirements: - ``setuptools``, **version >= 0.6** - ``pyreadline``, **version >= 1.7.1** (on windows) - ``objgraph``, **version >= 1.7.2** More Information ================ Probably the best way to get started is to look at the documentation at http://dill.rtfd.io. Also see ``dill.tests`` for a set of scripts that demonstrate how ``dill`` can serialize different python objects. You can run the test suite with ``python -m dill.tests``. The contents of any pickle file can be examined with ``undill``. As ``dill`` conforms to the ``pickle`` interface, the examples and documentation found at http://docs.python.org/library/pickle.html also apply to ``dill`` if one will ``import dill as pickle``. The source code is also generally well documented, so further questions may be resolved by inspecting the code itself. Please feel free to submit a ticket on github, or ask a question on stackoverflow (**@Mike McKerns**). If you would like to share how you use ``dill`` in your work, please send an email (to **mmckerns at uqfoundation dot org**). Citation ======== If you use ``dill`` to do research that leads to publication, we ask that you acknowledge use of ``dill`` by citing the following in your publication:: M.M. McKerns, L. Strand, T. Sullivan, A. Fang, M.A.G. Aivazis, "Building a framework for predictive science", Proceedings of the 10th Python in Science Conference, 2011; http://arxiv.org/pdf/1202.1056 Michael McKerns and Michael Aivazis, "pathos: a framework for heterogeneous computing", 2010- ; http://trac.mystic.cacr.caltech.edu/project/pathos Please see http://trac.mystic.cacr.caltech.edu/project/pathos or http://arxiv.org/pdf/1202.1056 for further information. ''' license = '''Copyright (c) 2004-2016 California Institute of Technology. Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. All rights reserved. This software is available subject to the conditions and terms laid out below. By downloading and using this software you are agreeing to the following conditions. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:: - Redistribution of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistribution in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentations and/or other materials provided with the distribution. - Neither the name of the California Institute of Technology 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. ''' dill-0.3.1.1/dill/objtypes.py000644 000765 000024 00000001340 13543677215 016730 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ all Python Standard Library object types (currently: CH 1-15 @ 2.7) and some other common object types (i.e. numpy.ndarray) to load more objects and types, use dill.load_types() """ # non-local import of dill.objects from dill import objects for _type in objects.keys(): exec("%s = type(objects['%s'])" % (_type,_type)) del objects try: del _type except NameError: pass dill-0.3.1.1/dill/pointers.py000644 000765 000024 00000010563 13543677215 016743 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE __all__ = ['parent', 'reference', 'at', 'parents', 'children'] import gc import sys from ._dill import _proxy_helper as reference from ._dill import _locate_object as at def parent(obj, objtype, ignore=()): """ >>> listiter = iter([4,5,6,7]) >>> obj = parent(listiter, list) >>> obj == [4,5,6,7] # actually 'is', but don't have handle any longer True NOTE: objtype can be a single type (e.g. int or list) or a tuple of types. WARNING: if obj is a sequence (e.g. list), may produce unexpected results. Parent finds *one* parent (e.g. the last member of the sequence). """ depth = 1 #XXX: always looking for the parent (only, right?) chain = parents(obj, objtype, depth, ignore) parent = chain.pop() if parent is obj: return None return parent def parents(obj, objtype, depth=1, ignore=()): #XXX: objtype=object ? """Find the chain of referents for obj. Chain will end with obj. objtype: an object type or tuple of types to search for depth: search depth (e.g. depth=2 is 'grandparents') ignore: an object or tuple of objects to ignore in the search """ edge_func = gc.get_referents # looking for refs, not back_refs predicate = lambda x: isinstance(x, objtype) # looking for parent type #if objtype is None: predicate = lambda x: True #XXX: in obj.mro() ? ignore = (ignore,) if not hasattr(ignore, '__len__') else ignore ignore = (id(obj) for obj in ignore) chain = find_chain(obj, predicate, edge_func, depth)[::-1] #XXX: should pop off obj... ? return chain def children(obj, objtype, depth=1, ignore=()): #XXX: objtype=object ? """Find the chain of referrers for obj. Chain will start with obj. objtype: an object type or tuple of types to search for depth: search depth (e.g. depth=2 is 'grandchildren') ignore: an object or tuple of objects to ignore in the search NOTE: a common thing to ignore is all globals, 'ignore=(globals(),)' NOTE: repeated calls may yield different results, as python stores the last value in the special variable '_'; thus, it is often good to execute something to replace '_' (e.g. >>> 1+1). """ edge_func = gc.get_referrers # looking for back_refs, not refs predicate = lambda x: isinstance(x, objtype) # looking for child type #if objtype is None: predicate = lambda x: True #XXX: in obj.mro() ? ignore = (ignore,) if not hasattr(ignore, '__len__') else ignore ignore = (id(obj) for obj in ignore) chain = find_chain(obj, predicate, edge_func, depth, ignore) #XXX: should pop off obj... ? return chain # more generic helper function (cut-n-paste from objgraph) # Source at http://mg.pov.lt/objgraph/ # Copyright (c) 2008-2010 Marius Gedminas # Copyright (c) 2010 Stefano Rivera # Released under the MIT licence (see objgraph/objgrah.py) def find_chain(obj, predicate, edge_func, max_depth=20, extra_ignore=()): queue = [obj] depth = {id(obj): 0} parent = {id(obj): None} ignore = set(extra_ignore) ignore.add(id(extra_ignore)) ignore.add(id(queue)) ignore.add(id(depth)) ignore.add(id(parent)) ignore.add(id(ignore)) ignore.add(id(sys._getframe())) # this function ignore.add(id(sys._getframe(1))) # find_chain/find_backref_chain, likely gc.collect() while queue: target = queue.pop(0) if predicate(target): chain = [target] while parent[id(target)] is not None: target = parent[id(target)] chain.append(target) return chain tdepth = depth[id(target)] if tdepth < max_depth: referrers = edge_func(target) ignore.add(id(referrers)) for source in referrers: if id(source) in ignore: continue if id(source) not in depth: depth[id(source)] = tdepth + 1 parent[id(source)] = target queue.append(source) return [obj] # not found # backward compatability refobject = at # EOF dill-0.3.1.1/dill/settings.py000644 000765 000024 00000001317 13543677215 016735 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ global settings for Pickler """ try: from pickle import DEFAULT_PROTOCOL except ImportError: from pickle import HIGHEST_PROTOCOL as DEFAULT_PROTOCOL settings = { #'main' : None, 'protocol' : DEFAULT_PROTOCOL, 'byref' : False, #'strictio' : False, 'fmode' : 0, #HANDLE_FMODE 'recurse' : False, 'ignore' : False, } del DEFAULT_PROTOCOL dill-0.3.1.1/dill/source.py000644 000765 000024 00000127552 13543677215 016407 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE # # inspired by inspect.py from Python-2.7.6 # inspect.py author: 'Ka-Ping Yee ' # inspect.py merged into original dill.source by Mike McKerns 4/13/14 """ Extensions to python's 'inspect' module, which can be used to retrieve information from live python objects. The methods defined in this module are augmented to facilitate access to source code of interactively defined functions and classes, as well as provide access to source code for objects defined in a file. """ __all__ = ['findsource', 'getsourcelines', 'getsource', 'indent', 'outdent', \ '_wrap', 'dumpsource', 'getname', '_namespace', 'getimport', \ '_importable', 'importable','isdynamic', 'isfrommain'] import linecache import re from inspect import (getblock, getfile, getmodule, getsourcefile, indentsize, isbuiltin, isclass, iscode, isframe, isfunction, ismethod, ismodule, istraceback) from tokenize import TokenError from ._dill import PY3 def isfrommain(obj): "check if object was built in __main__" module = getmodule(obj) if module and module.__name__ == '__main__': return True return False def isdynamic(obj): "check if object was built in the interpreter" try: file = getfile(obj) except TypeError: file = None if file == '' and isfrommain(obj): return True return False def _matchlambda(func, line): """check if lambda object 'func' matches raw line of code 'line'""" from .detect import code as getcode from .detect import freevars, globalvars, varnames dummy = lambda : '__this_is_a_big_dummy_function__' # process the line (removing leading whitespace, etc) lhs,rhs = line.split('lambda ',1)[-1].split(":", 1) #FIXME: if !1 inputs try: #FIXME: unsafe _ = eval("lambda %s : %s" % (lhs,rhs), globals(),locals()) except: _ = dummy # get code objects, for comparison _, code = getcode(_).co_code, getcode(func).co_code # check if func is in closure _f = [line.count(i) for i in freevars(func).keys()] if not _f: # not in closure # check if code matches if _ == code: return True return False # weak check on freevars if not all(_f): return False #XXX: VERY WEAK # weak check on varnames and globalvars _f = varnames(func) _f = [line.count(i) for i in _f[0]+_f[1]] if _f and not all(_f): return False #XXX: VERY WEAK _f = [line.count(i) for i in globalvars(func).keys()] if _f and not all(_f): return False #XXX: VERY WEAK # check if func is a double lambda if (line.count('lambda ') > 1) and (lhs in freevars(func).keys()): _lhs,_rhs = rhs.split('lambda ',1)[-1].split(":",1) #FIXME: if !1 inputs try: #FIXME: unsafe _f = eval("lambda %s : %s" % (_lhs,_rhs), globals(),locals()) except: _f = dummy # get code objects, for comparison _, code = getcode(_f).co_code, getcode(func).co_code if len(_) != len(code): return False #NOTE: should be same code same order, but except for 't' and '\x88' _ = set((i,j) for (i,j) in zip(_,code) if i != j) if len(_) != 1: return False #('t','\x88') return True # check indentsize if not indentsize(line): return False #FIXME: is this a good check??? # check if code 'pattern' matches #XXX: or pattern match against dis.dis(code)? (or use uncompyle2?) _ = _.split(_[0]) # 't' #XXX: remove matching values if starts the same? _f = code.split(code[0]) # '\x88' #NOTE: should be same code different order, with different first element _ = dict(re.match(r'([\W\D\S])(.*)', _[i]).groups() for i in range(1,len(_))) _f = dict(re.match(r'([\W\D\S])(.*)', _f[i]).groups() for i in range(1,len(_f))) if (_.keys() == _f.keys()) and (sorted(_.values()) == sorted(_f.values())): return True return False def findsource(object): """Return the entire source file and starting line number for an object. For interactively-defined objects, the 'file' is the interpreter's history. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a list of all the lines in the file and the line number indexes a line in that list. An IOError is raised if the source code cannot be retrieved, while a TypeError is raised for objects where the source code is unavailable (e.g. builtins).""" module = getmodule(object) try: file = getfile(module) except TypeError: file = None # use readline when working in interpreter (i.e. __main__ and not file) if module and module.__name__ == '__main__' and not file: try: import readline err = '' except: import sys err = sys.exc_info()[1].args[0] if sys.platform[:3] == 'win': err += ", please install 'pyreadline'" if err: raise IOError(err) lbuf = readline.get_current_history_length() lines = [readline.get_history_item(i)+'\n' for i in range(1,lbuf)] else: try: # special handling for class instances if not isclass(object) and isclass(type(object)): # __class__ file = getfile(module) sourcefile = getsourcefile(module) else: # builtins fail with a TypeError file = getfile(object) sourcefile = getsourcefile(object) except (TypeError, AttributeError): # fail with better error file = getfile(object) sourcefile = getsourcefile(object) if not sourcefile and file[:1] + file[-1:] != '<>': raise IOError('source code not available') file = sourcefile if sourcefile else file module = getmodule(object, file) if module: lines = linecache.getlines(file, module.__dict__) else: lines = linecache.getlines(file) if not lines: raise IOError('could not extract source code') #FIXME: all below may fail if exec used (i.e. exec('f = lambda x:x') ) if ismodule(object): return lines, 0 #NOTE: beneficial if search goes from end to start of buffer history name = pat1 = obj = '' pat2 = r'^(\s*@)' # pat1b = r'^(\s*%s\W*=)' % name #FIXME: finds 'f = decorate(f)', not exec if ismethod(object): name = object.__name__ if name == '': pat1 = r'(.*(?': pat1 = r'(.*(?' if stdin: lnum = len(lines) - 1 # can't get lnum easily, so leverage pat if not pat1: pat1 = r'^(\s*def\s)|(.*(? 0: #XXX: won't find decorators in ? line = lines[lnum] if pat1.match(line): if not stdin: break # co_firstlineno does the job if name == '': # hackery needed to confirm a match if _matchlambda(obj, line): break else: # not a lambda, just look for the name if name in line: # need to check for decorator... hats = 0 for _lnum in range(lnum-1,-1,-1): if pat2.match(lines[_lnum]): hats += 1 else: break lnum = lnum - hats break lnum = lnum - 1 return lines, lnum try: # turn instances into classes if not isclass(object) and isclass(type(object)): # __class__ object = object.__class__ #XXX: sometimes type(class) is better? #XXX: we don't find how the instance was built except AttributeError: pass if isclass(object): name = object.__name__ pat = re.compile(r'^(\s*)class\s*' + name + r'\b') # make some effort to find the best matching class definition: # use the one with the least indentation, which is the one # that's most probably not inside a function definition. candidates = [] for i in range(len(lines)-1,-1,-1): match = pat.match(lines[i]) if match: # if it's at toplevel, it's already the best one if lines[i][0] == 'c': return lines, i # else add whitespace to candidate list candidates.append((match.group(1), i)) if candidates: # this will sort by whitespace, and by line number, # less whitespace first #XXX: should sort high lnum before low candidates.sort() return lines, candidates[0][1] else: raise IOError('could not find class definition') raise IOError('could not find code object') def getblocks(object, lstrip=False, enclosing=False, locate=False): """Return a list of source lines and starting line number for an object. Interactively-defined objects refer to lines in the interpreter's history. If enclosing=True, then also return any enclosing code. If lstrip=True, ensure there is no indentation in the first line of code. If locate=True, then also return the line number for the block of code. DEPRECATED: use 'getsourcelines' instead """ lines, lnum = findsource(object) if ismodule(object): if lstrip: lines = _outdent(lines) return ([lines], [0]) if locate is True else [lines] #XXX: 'enclosing' means: closures only? or classes and files? indent = indentsize(lines[lnum]) block = getblock(lines[lnum:]) #XXX: catch any TokenError here? if not enclosing or not indent: if lstrip: block = _outdent(block) return ([block], [lnum]) if locate is True else [block] pat1 = r'^(\s*def\s)|(.*(? indent: #XXX: should be >= ? line += len(code) - skip elif target in ''.join(code): blocks.append(code) # save code block as the potential winner _lnum.append(line - skip) # save the line number for the match line += len(code) - skip else: line += 1 skip = 0 # find skip: the number of consecutive decorators elif pat2.match(lines[line]): try: code = getblock(lines[line:]) except TokenError: code = [lines[line]] skip = 1 for _line in code[1:]: # skip lines that are decorators if not pat2.match(_line): break skip += 1 line += skip # no match: reset skip and go to the next line else: line +=1 skip = 0 if not blocks: blocks = [block] _lnum = [lnum] if lstrip: blocks = [_outdent(block) for block in blocks] # return last match return (blocks, _lnum) if locate is True else blocks def getsourcelines(object, lstrip=False, enclosing=False): """Return a list of source lines and starting line number for an object. Interactively-defined objects refer to lines in the interpreter's history. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a list of the lines corresponding to the object and the line number indicates where in the original source file the first line of code was found. An IOError is raised if the source code cannot be retrieved, while a TypeError is raised for objects where the source code is unavailable (e.g. builtins). If lstrip=True, ensure there is no indentation in the first line of code. If enclosing=True, then also return any enclosing code.""" code, n = getblocks(object, lstrip=lstrip, enclosing=enclosing, locate=True) return code[-1], n[-1] #NOTE: broke backward compatibility 4/16/14 (was lstrip=True, force=True) def getsource(object, alias='', lstrip=False, enclosing=False, \ force=False, builtin=False): """Return the text of the source code for an object. The source code for interactively-defined objects are extracted from the interpreter's history. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a single string. An IOError is raised if the source code cannot be retrieved, while a TypeError is raised for objects where the source code is unavailable (e.g. builtins). If alias is provided, then add a line of code that renames the object. If lstrip=True, ensure there is no indentation in the first line of code. If enclosing=True, then also return any enclosing code. If force=True, catch (TypeError,IOError) and try to use import hooks. If builtin=True, force an import for any builtins """ # hascode denotes a callable hascode = _hascode(object) # is a class instance type (and not in builtins) instance = _isinstance(object) # get source lines; if fail, try to 'force' an import try: # fails for builtins, and other assorted object types lines, lnum = getsourcelines(object, enclosing=enclosing) except (TypeError, IOError): # failed to get source, resort to import hooks if not force: # don't try to get types that findsource can't get raise if not getmodule(object): # get things like 'None' and '1' if not instance: return getimport(object, alias, builtin=builtin) # special handling (numpy arrays, ...) _import = getimport(object, builtin=builtin) name = getname(object, force=True) _alias = "%s = " % alias if alias else "" if alias == name: _alias = "" return _import+_alias+"%s\n" % name else: #FIXME: could use a good bit of cleanup, since using getimport... if not instance: return getimport(object, alias, builtin=builtin) # now we are dealing with an instance... name = object.__class__.__name__ module = object.__module__ if module in ['builtins','__builtin__']: return getimport(object, alias, builtin=builtin) else: #FIXME: leverage getimport? use 'from module import name'? lines, lnum = ["%s = __import__('%s', fromlist=['%s']).%s\n" % (name,module,name,name)], 0 obj = eval(lines[0].lstrip(name + ' = ')) lines, lnum = getsourcelines(obj, enclosing=enclosing) # strip leading indent (helps ensure can be imported) if lstrip or alias: lines = _outdent(lines) # instantiate, if there's a nice repr #XXX: BAD IDEA??? if instance: #and force: #XXX: move into findsource or getsourcelines ? if '(' in repr(object): lines.append('%r\n' % object) #else: #XXX: better to somehow to leverage __reduce__ ? # reconstructor,args = object.__reduce__() # _ = reconstructor(*args) else: # fall back to serialization #XXX: bad idea? #XXX: better not duplicate work? #XXX: better new/enclose=True? lines = dumpsource(object, alias='', new=force, enclose=False) lines, lnum = [line+'\n' for line in lines.split('\n')][:-1], 0 #else: object.__code__ # raise AttributeError # add an alias to the source code if alias: if hascode: skip = 0 for line in lines: # skip lines that are decorators if not line.startswith('@'): break skip += 1 #XXX: use regex from findsource / getsourcelines ? if lines[skip].lstrip().startswith('def '): # we have a function if alias != object.__name__: lines.append('\n%s = %s\n' % (alias, object.__name__)) elif 'lambda ' in lines[skip]: # we have a lambda if alias != lines[skip].split('=')[0].strip(): lines[skip] = '%s = %s' % (alias, lines[skip]) else: # ...try to use the object's name if alias != object.__name__: lines.append('\n%s = %s\n' % (alias, object.__name__)) else: # class or class instance if instance: if alias != lines[-1].split('=')[0].strip(): lines[-1] = ('%s = ' % alias) + lines[-1] else: name = getname(object, force=True) or object.__name__ if alias != name: lines.append('\n%s = %s\n' % (alias, name)) return ''.join(lines) def _hascode(object): '''True if object has an attribute that stores it's __code__''' return getattr(object,'__code__',None) or getattr(object,'func_code',None) def _isinstance(object): '''True if object is a class instance type (and is not a builtin)''' if _hascode(object) or isclass(object) or ismodule(object): return False if istraceback(object) or isframe(object) or iscode(object): return False # special handling (numpy arrays, ...) if not getmodule(object) and getmodule(type(object)).__name__ in ['numpy']: return True # # check if is instance of a builtin # if not getmodule(object) and getmodule(type(object)).__name__ in ['__builtin__','builtins']: # return False _types = ('") if not repr(type(object)).startswith(_types): #FIXME: weak hack return False if not getmodule(object) or object.__module__ in ['builtins','__builtin__'] or getname(object, force=True) in ['array']: return False return True # by process of elimination... it's what we want def _intypes(object): '''check if object is in the 'types' module''' import types # allow user to pass in object or object.__name__ if type(object) is not type(''): object = getname(object, force=True) if object == 'ellipsis': object = 'EllipsisType' return True if hasattr(types, object) else False def _isstring(object): #XXX: isstringlike better? '''check if object is a string-like type''' if PY3: return isinstance(object, (str, bytes)) return isinstance(object, basestring) def indent(code, spaces=4): '''indent a block of code with whitespace (default is 4 spaces)''' indent = indentsize(code) if type(spaces) is int: spaces = ' '*spaces # if '\t' is provided, will indent with a tab nspaces = indentsize(spaces) # blank lines (etc) need to be ignored lines = code.split('\n') ## stq = "'''"; dtq = '"""' ## in_stq = in_dtq = False for i in range(len(lines)): #FIXME: works... but shouldn't indent 2nd+ lines of multiline doc _indent = indentsize(lines[i]) if indent > _indent: continue lines[i] = spaces+lines[i] ## #FIXME: may fail when stq and dtq in same line (depends on ordering) ## nstq, ndtq = lines[i].count(stq), lines[i].count(dtq) ## if not in_dtq and not in_stq: ## lines[i] = spaces+lines[i] # we indent ## # entering a comment block ## if nstq%2: in_stq = not in_stq ## if ndtq%2: in_dtq = not in_dtq ## # leaving a comment block ## elif in_dtq and ndtq%2: in_dtq = not in_dtq ## elif in_stq and nstq%2: in_stq = not in_stq ## else: pass if lines[-1].strip() == '': lines[-1] = '' return '\n'.join(lines) def _outdent(lines, spaces=None, all=True): '''outdent lines of code, accounting for docs and line continuations''' indent = indentsize(lines[0]) if spaces is None or spaces > indent or spaces < 0: spaces = indent for i in range(len(lines) if all else 1): #FIXME: works... but shouldn't outdent 2nd+ lines of multiline doc _indent = indentsize(lines[i]) if spaces > _indent: _spaces = _indent else: _spaces = spaces lines[i] = lines[i][_spaces:] return lines def outdent(code, spaces=None, all=True): '''outdent a block of code (default is to strip all leading whitespace)''' indent = indentsize(code) if spaces is None or spaces > indent or spaces < 0: spaces = indent #XXX: will this delete '\n' in some cases? if not all: return code[spaces:] return '\n'.join(_outdent(code.split('\n'), spaces=spaces, all=all)) #XXX: not sure what the point of _wrap is... #exec_ = lambda s, *a: eval(compile(s, '', 'exec'), *a) __globals__ = globals() __locals__ = locals() wrap2 = ''' def _wrap(f): """ encapsulate a function and it's __import__ """ def func(*args, **kwds): try: # _ = eval(getsource(f, force=True)) #XXX: safer but less robust exec getimportable(f, alias='_') in %s, %s except: raise ImportError('cannot import name ' + f.__name__) return _(*args, **kwds) func.__name__ = f.__name__ func.__doc__ = f.__doc__ return func ''' % ('__globals__', '__locals__') wrap3 = ''' def _wrap(f): """ encapsulate a function and it's __import__ """ def func(*args, **kwds): try: # _ = eval(getsource(f, force=True)) #XXX: safer but less robust exec(getimportable(f, alias='_'), %s, %s) except: raise ImportError('cannot import name ' + f.__name__) return _(*args, **kwds) func.__name__ = f.__name__ func.__doc__ = f.__doc__ return func ''' % ('__globals__', '__locals__') if PY3: exec(wrap3) else: exec(wrap2) del wrap2, wrap3 def _enclose(object, alias=''): #FIXME: needs alias to hold returned object """create a function enclosure around the source of some object""" #XXX: dummy and stub should append a random string dummy = '__this_is_a_big_dummy_enclosing_function__' stub = '__this_is_a_stub_variable__' code = 'def %s():\n' % dummy code += indent(getsource(object, alias=stub, lstrip=True, force=True)) code += indent('return %s\n' % stub) if alias: code += '%s = ' % alias code += '%s(); del %s\n' % (dummy, dummy) #code += "globals().pop('%s',lambda :None)()\n" % dummy return code def dumpsource(object, alias='', new=False, enclose=True): """'dump to source', where the code includes a pickled object. If new=True and object is a class instance, then create a new instance using the unpacked class source code. If enclose, then create the object inside a function enclosure (thus minimizing any global namespace pollution). """ from dill import dumps pik = repr(dumps(object)) code = 'import dill\n' if enclose: stub = '__this_is_a_stub_variable__' #XXX: *must* be same _enclose.stub pre = '%s = ' % stub new = False #FIXME: new=True doesn't work with enclose=True else: stub = alias pre = '%s = ' % stub if alias else alias # if a 'new' instance is not needed, then just dump and load if not new or not _isinstance(object): code += pre + 'dill.loads(%s)\n' % pik else: #XXX: other cases where source code is needed??? code += getsource(object.__class__, alias='', lstrip=True, force=True) mod = repr(object.__module__) # should have a module (no builtins here) if PY3: code += pre + 'dill.loads(%s.replace(b%s,bytes(__name__,"UTF-8")))\n' % (pik,mod) else: code += pre + 'dill.loads(%s.replace(%s,__name__))\n' % (pik,mod) #code += 'del %s' % object.__class__.__name__ #NOTE: kills any existing! if enclose: # generation of the 'enclosure' dummy = '__this_is_a_big_dummy_object__' dummy = _enclose(dummy, alias=alias) # hack to replace the 'dummy' with the 'real' code dummy = dummy.split('\n') code = dummy[0]+'\n' + indent(code) + '\n'.join(dummy[-3:]) return code #XXX: better 'dumpsourcelines', returning list of lines? def getname(obj, force=False, fqn=False): #XXX: throw(?) to raise error on fail? """get the name of the object. for lambdas, get the name of the pointer """ if fqn: return '.'.join(_namespace(obj)) module = getmodule(obj) if not module: # things like "None" and "1" if not force: return None return repr(obj) try: #XXX: 'wrong' for decorators and curried functions ? # if obj.func_closure: ...use logic from getimportable, etc ? name = obj.__name__ if name == '': return getsource(obj).split('=',1)[0].strip() # handle some special cases if module.__name__ in ['builtins','__builtin__']: if name == 'ellipsis': name = 'EllipsisType' return name except AttributeError: #XXX: better to just throw AttributeError ? if not force: return None name = repr(obj) if name.startswith('<'): # or name.split('('): return None return name def _namespace(obj): """_namespace(obj); return namespace hierarchy (as a list of names) for the given object. For an instance, find the class hierarchy. For example: >>> from functools import partial >>> p = partial(int, base=2) >>> _namespace(p) [\'functools\', \'partial\'] """ # mostly for functions and modules and such #FIXME: 'wrong' for decorators and curried functions try: #XXX: needs some work and testing on different types module = qual = str(getmodule(obj)).split()[1].strip('"').strip("'") qual = qual.split('.') if ismodule(obj): return qual # get name of a lambda, function, etc name = getname(obj) or obj.__name__ # failing, raise AttributeError # check special cases (NoneType, ...) if module in ['builtins','__builtin__']: # BuiltinFunctionType if _intypes(name): return ['types'] + [name] return qual + [name] #XXX: can be wrong for some aliased objects except: pass # special case: numpy.inf and numpy.nan (we don't want them as floats) if str(obj) in ['inf','nan','Inf','NaN']: # is more, but are they needed? return ['numpy'] + [str(obj)] # mostly for classes and class instances and such module = getattr(obj.__class__, '__module__', None) qual = str(obj.__class__) try: qual = qual[qual.index("'")+1:-2] except ValueError: pass # str(obj.__class__) made the 'try' unnecessary qual = qual.split(".") if module in ['builtins','__builtin__']: # check special cases (NoneType, Ellipsis, ...) if qual[-1] == 'ellipsis': qual[-1] = 'EllipsisType' if _intypes(qual[-1]): module = 'types' #XXX: BuiltinFunctionType qual = [module] + qual return qual #NOTE: 05/25/14 broke backward compatability: added 'alias' as 3rd argument def _getimport(head, tail, alias='', verify=True, builtin=False): """helper to build a likely import string from head and tail of namespace. ('head','tail') are used in the following context: "from head import tail" If verify=True, then test the import string before returning it. If builtin=True, then force an import for builtins where possible. If alias is provided, then rename the object on import. """ # special handling for a few common types if tail in ['Ellipsis', 'NotImplemented'] and head in ['types']: head = len.__module__ elif tail in ['None'] and head in ['types']: _alias = '%s = ' % alias if alias else '' if alias == tail: _alias = '' return _alias+'%s\n' % tail # we don't need to import from builtins, so return '' # elif tail in ['NoneType','int','float','long','complex']: return '' #XXX: ? if head in ['builtins','__builtin__']: # special cases (NoneType, Ellipsis, ...) #XXX: BuiltinFunctionType if tail == 'ellipsis': tail = 'EllipsisType' if _intypes(tail): head = 'types' elif not builtin: _alias = '%s = ' % alias if alias else '' if alias == tail: _alias = '' return _alias+'%s\n' % tail else: pass # handle builtins below # get likely import string if not head: _str = "import %s" % tail else: _str = "from %s import %s" % (head, tail) _alias = " as %s\n" % alias if alias else "\n" if alias == tail: _alias = "\n" _str += _alias # FIXME: fails on most decorators, currying, and such... # (could look for magic __wrapped__ or __func__ attr) # (could fix in 'namespace' to check obj for closure) if verify and not head.startswith('dill.'):# weird behavior for dill #print(_str) try: exec(_str) #XXX: check if == obj? (name collision) except ImportError: #XXX: better top-down or bottom-up recursion? _head = head.rsplit(".",1)[0] #(or get all, then compare == obj?) if not _head: raise if _head != head: _str = _getimport(_head, tail, alias, verify) return _str #XXX: rename builtin to force? vice versa? verify to force? (as in getsource) #NOTE: 05/25/14 broke backward compatability: added 'alias' as 2nd argument def getimport(obj, alias='', verify=True, builtin=False, enclosing=False): """get the likely import string for the given object obj is the object to inspect If verify=True, then test the import string before returning it. If builtin=True, then force an import for builtins where possible. If enclosing=True, get the import for the outermost enclosing callable. If alias is provided, then rename the object on import. """ if enclosing: from .detect import outermost _obj = outermost(obj) obj = _obj if _obj else obj # get the namespace qual = _namespace(obj) head = '.'.join(qual[:-1]) tail = qual[-1] # for named things... with a nice repr #XXX: move into _namespace? try: # look for '<...>' and be mindful it might be in lists, dicts, etc... name = repr(obj).split('<',1)[1].split('>',1)[1] name = None # we have a 'object'-style repr except: # it's probably something 'importable' if head in ['builtins','__builtin__']: name = repr(obj) #XXX: catch [1,2], (1,2), set([1,2])... others? else: name = repr(obj).split('(')[0] #if not repr(obj).startswith('<'): name = repr(obj).split('(')[0] #else: name = None if name: # try using name instead of tail try: return _getimport(head, name, alias, verify, builtin) except ImportError: pass except SyntaxError: if head in ['builtins','__builtin__']: _alias = '%s = ' % alias if alias else '' if alias == name: _alias = '' return _alias+'%s\n' % name else: pass try: #if type(obj) is type(abs): _builtin = builtin # BuiltinFunctionType #else: _builtin = False return _getimport(head, tail, alias, verify, builtin) except ImportError: raise # could do some checking against obj except SyntaxError: if head in ['builtins','__builtin__']: _alias = '%s = ' % alias if alias else '' if alias == tail: _alias = '' return _alias+'%s\n' % tail raise # could do some checking against obj def _importable(obj, alias='', source=None, enclosing=False, force=True, \ builtin=True, lstrip=True): """get an import string (or the source code) for the given object This function will attempt to discover the name of the object, or the repr of the object, or the source code for the object. To attempt to force discovery of the source code, use source=True, to attempt to force the use of an import, use source=False; otherwise an import will be sought for objects not defined in __main__. The intent is to build a string that can be imported from a python file. obj is the object to inspect. If alias is provided, then rename the object with the given alias. If source=True, use these options: If enclosing=True, then also return any enclosing code. If force=True, catch (TypeError,IOError) and try to use import hooks. If lstrip=True, ensure there is no indentation in the first line of code. If source=False, use these options: If enclosing=True, get the import for the outermost enclosing callable. If force=True, then don't test the import string before returning it. If builtin=True, then force an import for builtins where possible. """ if source is None: source = True if isfrommain(obj) else False if source: # first try to get the source try: return getsource(obj, alias, enclosing=enclosing, \ force=force, lstrip=lstrip, builtin=builtin) except: pass try: if not _isinstance(obj): return getimport(obj, alias, enclosing=enclosing, \ verify=(not force), builtin=builtin) # first 'get the import', then 'get the instance' _import = getimport(obj, enclosing=enclosing, \ verify=(not force), builtin=builtin) name = getname(obj, force=True) if not name: raise AttributeError("object has no atribute '__name__'") _alias = "%s = " % alias if alias else "" if alias == name: _alias = "" return _import+_alias+"%s\n" % name except: pass if not source: # try getsource, only if it hasn't been tried yet try: return getsource(obj, alias, enclosing=enclosing, \ force=force, lstrip=lstrip, builtin=builtin) except: pass # get the name (of functions, lambdas, and classes) # or hope that obj can be built from the __repr__ #XXX: what to do about class instances and such? obj = getname(obj, force=force) # we either have __repr__ or __name__ (or None) if not obj or obj.startswith('<'): raise AttributeError("object has no atribute '__name__'") _alias = '%s = ' % alias if alias else '' if alias == obj: _alias = '' return _alias+'%s\n' % obj #XXX: possible failsafe... (for example, for instances when source=False) # "import dill; result = dill.loads(); # repr()" def _closuredimport(func, alias='', builtin=False): """get import for closured objects; return a dict of 'name' and 'import'""" import re from .detect import freevars, outermost free_vars = freevars(func) func_vars = {} # split into 'funcs' and 'non-funcs' for name,obj in list(free_vars.items()): if not isfunction(obj): continue # get import for 'funcs' fobj = free_vars.pop(name) src = getsource(fobj) if src.lstrip().startswith('@'): # we have a decorator src = getimport(fobj, alias=alias, builtin=builtin) else: # we have to "hack" a bit... and maybe be lucky encl = outermost(func) # pattern: 'func = enclosing(fobj' pat = r'.*[\w\s]=\s*'+getname(encl)+r'\('+getname(fobj) mod = getname(getmodule(encl)) #HACK: get file containing 'outer' function; is func there? lines,_ = findsource(encl) candidate = [line for line in lines if getname(encl) in line and \ re.match(pat, line)] if not candidate: mod = getname(getmodule(fobj)) #HACK: get file containing 'inner' function; is func there? lines,_ = findsource(fobj) candidate = [line for line in lines \ if getname(fobj) in line and re.match(pat, line)] if not len(candidate): raise TypeError('import could not be found') candidate = candidate[-1] name = candidate.split('=',1)[0].split()[-1].strip() src = _getimport(mod, name, alias=alias, builtin=builtin) func_vars[name] = src if not func_vars: name = outermost(func) mod = getname(getmodule(name)) if not mod or name is func: # then it can be handled by getimport name = getname(func, force=True) #XXX: better key? src = getimport(func, alias=alias, builtin=builtin) else: lines,_ = findsource(name) # pattern: 'func = enclosing(' candidate = [line for line in lines if getname(name) in line and \ re.match(r'.*[\w\s]=\s*'+getname(name)+r'\(', line)] if not len(candidate): raise TypeError('import could not be found') candidate = candidate[-1] name = candidate.split('=',1)[0].split()[-1].strip() src = _getimport(mod, name, alias=alias, builtin=builtin) func_vars[name] = src return func_vars #XXX: should be able to use __qualname__ def _closuredsource(func, alias=''): """get source code for closured objects; return a dict of 'name' and 'code blocks'""" #FIXME: this entire function is a messy messy HACK # - pollutes global namespace # - fails if name of freevars are reused # - can unnecessarily duplicate function code from .detect import freevars free_vars = freevars(func) func_vars = {} # split into 'funcs' and 'non-funcs' for name,obj in list(free_vars.items()): if not isfunction(obj): # get source for 'non-funcs' free_vars[name] = getsource(obj, force=True, alias=name) continue # get source for 'funcs' fobj = free_vars.pop(name) src = getsource(fobj, alias) # DO NOT include dependencies # if source doesn't start with '@', use name as the alias if not src.lstrip().startswith('@'): #FIXME: 'enclose' in dummy; src = importable(fobj,alias=name)# wrong ref 'name' org = getsource(func, alias, enclosing=False, lstrip=True) src = (src, org) # undecorated first, then target else: #NOTE: reproduces the code! org = getsource(func, enclosing=True, lstrip=False) src = importable(fobj, alias, source=True) # include dependencies src = (org, src) # target first, then decorated func_vars[name] = src src = ''.join(free_vars.values()) if not func_vars: #FIXME: 'enclose' in dummy; wrong ref 'name' org = getsource(func, alias, force=True, enclosing=False, lstrip=True) src = (src, org) # variables first, then target else: src = (src, None) # just variables (better '' instead of None?) func_vars[None] = src # FIXME: remove duplicates (however, order is important...) return func_vars def importable(obj, alias='', source=None, builtin=True): """get an importable string (i.e. source code or the import string) for the given object, including any required objects from the enclosing and global scope This function will attempt to discover the name of the object, or the repr of the object, or the source code for the object. To attempt to force discovery of the source code, use source=True, to attempt to force the use of an import, use source=False; otherwise an import will be sought for objects not defined in __main__. The intent is to build a string that can be imported from a python file. obj is the object to inspect. If alias is provided, then rename the object with the given alias. If builtin=True, then force an import for builtins where possible. """ #NOTE: we always 'force', and 'lstrip' as necessary #NOTE: for 'enclosing', use importable(outermost(obj)) if source is None: source = True if isfrommain(obj) else False elif builtin and isbuiltin(obj): source = False tried_source = tried_import = False while True: if not source: # we want an import try: if _isinstance(obj): # for instances, punt to _importable return _importable(obj, alias, source=False, builtin=builtin) src = _closuredimport(obj, alias=alias, builtin=builtin) if len(src) == 0: raise NotImplementedError('not implemented') if len(src) > 1: raise NotImplementedError('not implemented') return list(src.values())[0] except: if tried_source: raise tried_import = True # we want the source try: src = _closuredsource(obj, alias=alias) if len(src) == 0: raise NotImplementedError('not implemented') # groan... an inline code stitcher def _code_stitcher(block): "stitch together the strings in tuple 'block'" if block[0] and block[-1]: block = '\n'.join(block) elif block[0]: block = block[0] elif block[-1]: block = block[-1] else: block = '' return block # get free_vars first _src = _code_stitcher(src.pop(None)) _src = [_src] if _src else [] # get func_vars for xxx in src.values(): xxx = _code_stitcher(xxx) if xxx: _src.append(xxx) # make a single source string if not len(_src): src = '' elif len(_src) == 1: src = _src[0] else: src = '\n'.join(_src) # get source code of objects referred to by obj in global scope from .detect import globalvars obj = globalvars(obj) #XXX: don't worry about alias? recurse? etc? obj = list(getsource(_obj,name,force=True) for (name,_obj) in obj.items() if not isbuiltin(_obj)) obj = '\n'.join(obj) if obj else '' # combine all referred-to source (global then enclosing) if not obj: return src if not src: return obj return obj + src except: if tried_import: raise tried_source = True source = not source # should never get here return # backward compatability def getimportable(obj, alias='', byname=True, explicit=False): return importable(obj,alias,source=(not byname),builtin=explicit) #return outdent(_importable(obj,alias,source=(not byname),builtin=explicit)) def likely_import(obj, passive=False, explicit=False): return getimport(obj, verify=(not passive), builtin=explicit) def _likely_import(first, last, passive=False, explicit=True): return _getimport(first, last, verify=(not passive), builtin=explicit) _get_name = getname getblocks_from_history = getblocks # EOF dill-0.3.1.1/dill/temp.py000644 000765 000024 00000020056 13543677215 016043 0ustar00mmckernsstaff000000 000000 #!/usr/bin/env python # # Author: Mike McKerns (mmckerns @caltech and @uqfoundation) # Copyright (c) 2008-2016 California Institute of Technology. # Copyright (c) 2016-2019 The Uncertainty Quantification Foundation. # License: 3-clause BSD. The full license text is available at: # - https://github.com/uqfoundation/dill/blob/master/LICENSE """ Methods for serialized objects (or source code) stored in temporary files and file-like objects. """ #XXX: better instead to have functions write to any given file-like object ? #XXX: currently, all file-like objects are created by the function... __all__ = ['dump_source', 'dump', 'dumpIO_source', 'dumpIO',\ 'load_source', 'load', 'loadIO_source', 'loadIO',\ 'capture'] import contextlib from ._dill import PY3 @contextlib.contextmanager def capture(stream='stdout'): """builds a context that temporarily replaces the given stream name >>> with capture('stdout') as out: ... print "foo!" ... >>> print out.getvalue() foo! """ import sys if PY3: from io import StringIO else: from StringIO import StringIO orig = getattr(sys, stream) setattr(sys, stream, StringIO()) try: yield getattr(sys, stream) finally: setattr(sys, stream, orig) def b(x): # deal with b'foo' versus 'foo' import codecs return codecs.latin_1_encode(x)[0] def load_source(file, **kwds): """load an object that was stored with dill.temp.dump_source file: filehandle alias: string name of stored object mode: mode to open the file, one of: {'r', 'rb'} >>> f = lambda x: x**2 >>> pyfile = dill.temp.dump_source(f, alias='_f') >>> _f = dill.temp.load_source(pyfile) >>> _f(4) 16 """ alias = kwds.pop('alias', None) mode = kwds.pop('mode', 'r') fname = getattr(file, 'name', file) # fname=file.name or fname=file (if str) source = open(fname, mode=mode, **kwds).read() if not alias: tag = source.strip().splitlines()[-1].split() if tag[0] != '#NAME:': stub = source.splitlines()[0] raise IOError("unknown name for code: %s" % stub) alias = tag[-1] local = {} exec(source, local) _ = eval("%s" % alias, local) return _ def dump_source(object, **kwds): """write object source to a NamedTemporaryFile (instead of dill.dump) Loads with "import" or "dill.temp.load_source". Returns the filehandle. >>> f = lambda x: x**2 >>> pyfile = dill.temp.dump_source(f, alias='_f') >>> _f = dill.temp.load_source(pyfile) >>> _f(4) 16 >>> f = lambda x: x**2 >>> pyfile = dill.temp.dump_source(f, dir='.') >>> modulename = os.path.basename(pyfile.name).split('.py')[0] >>> exec('from %s import f as _f' % modulename) >>> _f(4) 16 Optional kwds: If 'alias' is specified, the object will be renamed to the given string. If 'prefix' is specified, the file name will begin with that prefix, otherwise a default prefix is used. If 'dir' is specified, the file will be created in that directory, otherwise a default directory is used. If 'text' is specified and true, the file is opened in text mode. Else (the default) the file is opened in binary mode. On some operating systems, this makes no difference. NOTE: Keep the return value for as long as you want your file to exist ! """ #XXX: write a "load_source"? from .source import importable, getname import tempfile kwds.pop('suffix', '') # this is *always* '.py' alias = kwds.pop('alias', '') #XXX: include an alias so a name is known name = str(alias) or getname(object) name = "\n#NAME: %s\n" % name #XXX: assumes kwds['dir'] is writable and on $PYTHONPATH file = tempfile.NamedTemporaryFile(suffix='.py', **kwds) file.write(b(''.join([importable(object, alias=alias),name]))) file.flush() return file def load(file, **kwds): """load an object that was stored with dill.temp.dump file: filehandle mode: mode to open the file, one of: {'r', 'rb'} >>> dumpfile = dill.temp.dump([1, 2, 3, 4, 5]) >>> dill.temp.load(dumpfile) [1, 2, 3, 4, 5] """ import dill as pickle mode = kwds.pop('mode', 'rb') name = getattr(file, 'name', file) # name=file.name or name=file (if str) return pickle.load(open(name, mode=mode, **kwds)) def dump(object, **kwds): """dill.dump of object to a NamedTemporaryFile. Loads with "dill.temp.load". Returns the filehandle. >>> dumpfile = dill.temp.dump([1, 2, 3, 4, 5]) >>> dill.temp.load(dumpfile) [1, 2, 3, 4, 5] Optional kwds: If 'suffix' is specified, the file name will end with that suffix, otherwise there will be no suffix. If 'prefix' is specified, the file name will begin with that prefix, otherwise a default prefix is used. If 'dir' is specified, the file will be created in that directory, otherwise a default directory is used. If 'text' is specified and true, the file is opened in text mode. Else (the default) the file is opened in binary mode. On some operating systems, this makes no difference. NOTE: Keep the return value for as long as you want your file to exist ! """ import dill as pickle import tempfile file = tempfile.NamedTemporaryFile(**kwds) pickle.dump(object, file) file.flush() return file def loadIO(buffer, **kwds): """load an object that was stored with dill.temp.dumpIO buffer: buffer object >>> dumpfile = dill.temp.dumpIO([1, 2, 3, 4, 5]) >>> dill.temp.loadIO(dumpfile) [1, 2, 3, 4, 5] """ import dill as pickle if PY3: from io import BytesIO as StringIO else: from StringIO import StringIO value = getattr(buffer, 'getvalue', buffer) # value or buffer.getvalue if value != buffer: value = value() # buffer.getvalue() return pickle.load(StringIO(value)) def dumpIO(object, **kwds): """dill.dump of object to a buffer. Loads with "dill.temp.loadIO". Returns the buffer object. >>> dumpfile = dill.temp.dumpIO([1, 2, 3, 4, 5]) >>> dill.temp.loadIO(dumpfile) [1, 2, 3, 4, 5] """ import dill as pickle if PY3: from io import BytesIO as StringIO else: from StringIO import StringIO file = StringIO() pickle.dump(object, file) file.flush() return file def loadIO_source(buffer, **kwds): """load an object that was stored with dill.temp.dumpIO_source buffer: buffer object alias: string name of stored object >>> f = lambda x:x**2 >>> pyfile = dill.temp.dumpIO_source(f, alias='_f') >>> _f = dill.temp.loadIO_source(pyfile) >>> _f(4) 16 """ alias = kwds.pop('alias', None) source = getattr(buffer, 'getvalue', buffer) # source or buffer.getvalue if source != buffer: source = source() # buffer.getvalue() if PY3: source = source.decode() # buffer to string if not alias: tag = source.strip().splitlines()[-1].split() if tag[0] != '#NAME:': stub = source.splitlines()[0] raise IOError("unknown name for code: %s" % stub) alias = tag[-1] local = {} exec(source, local) _ = eval("%s" % alias, local) return _ def dumpIO_source(object, **kwds): """write object source to a buffer (instead of dill.dump) Loads by with dill.temp.loadIO_source. Returns the buffer object. >>> f = lambda x:x**2 >>> pyfile = dill.temp.dumpIO_source(f, alias='_f') >>> _f = dill.temp.loadIO_source(pyfile) >>> _f(4) 16 Optional kwds: If 'alias' is specified, the object will be renamed to the given string. """ from .source import importable, getname if PY3: from io import BytesIO as StringIO else: from StringIO import StringIO alias = kwds.pop('alias', '') #XXX: include an alias so a name is known name = str(alias) or getname(object) name = "\n#NAME: %s\n" % name #XXX: assumes kwds['dir'] is writable and on $PYTHONPATH file = StringIO() file.write(b(''.join([importable(object, alias=alias),name]))) file.flush() return file del contextlib # EOF dill-0.3.1.1/.eggs/README.txt000644 000765 000024 00000000323 13543677215 016274 0ustar00mmckernsstaff000000 000000 This directory contains eggs that were downloaded by setuptools to build, test, and run plug-ins. This directory caches those eggs to prevent repeated downloads. However, it is safe to delete this directory.