bidict-0.18.2/0000775000372000037200000000000013535200730013700 5ustar travistravis00000000000000bidict-0.18.2/.LICENSE_HEADER0000664000372000037200000000037313535200701015774 0ustar travistravis00000000000000Copyright 2009-2019 Joshua Bronson. All Rights Reserved. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. bidict-0.18.2/.appveyor.yml0000664000372000037200000000054013535200701016343 0ustar travistravis00000000000000skip_tags: true os: "Visual Studio 2017" environment: matrix: - PYTHON: "C:\\Python27-x64" - PYTHON: "C:\\Python36-x64" build_script: - "git --no-pager log -n2" - "echo %APPVEYOR_REPO_COMMIT%" - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;;%PATH%" - "python --version" - "pip install -e .[test]" test_script: - "python run_tests.py" bidict-0.18.2/.coveragerc0000664000372000037200000000020413535200701016013 0ustar travistravis00000000000000[run] branch=True source=bidict omit= setup.py [report] precision = 1 exclude_lines = pragma: no cover return NotImplemented bidict-0.18.2/.editorconfig0000664000372000037200000000035313535200701016354 0ustar travistravis00000000000000# http://EditorConfig.org # top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true indent_style = space indent_size = 4 [*.yml] indent_size = 2 bidict-0.18.2/.github/0000775000372000037200000000000013535200730015240 5ustar travistravis00000000000000bidict-0.18.2/.github/FUNDING.yml0000664000372000037200000000140613535200701017054 0ustar travistravis00000000000000github: "jab" tidelift: "pypi/bidict" custom: - https://gumroad.com/l/bidict - https://www.bountysource.com/teams/bidict - https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=jab%40math%2ebrown%2eedu&lc=US&item_name=Support%20bidict&button_subtype=services¤cy_code=USD&bn=PP%2dBuyNowBF%3aPaypal%2dBuy%2520a%2520Drink%2dblue%2esvg%3aNonHosted patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username bidict-0.18.2/.gitignore0000664000372000037200000000026613535200701015672 0ustar travistravis00000000000000*.pyc .DS_Store .benchmarks .cache .coverage .eggs .hypothesis .mypy_cache .tox .vscode __pycache__ _build bidict.egg-info bidict/_version.py coverage.xml htmlcov pip-wheel-metadata bidict-0.18.2/.lgtm.yml0000664000372000037200000000022413535200701015440 0ustar travistravis00000000000000queries: - exclude: py/missing-equals - exclude: py/conflicting-attributes - exclude: py/unused-import - exclude: py/import-and-import-from bidict-0.18.2/.pre-commit-config.yaml0000664000372000037200000000352413535200701020163 0ustar travistravis00000000000000repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v2.1.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: mixed-line-ending - id: double-quote-string-fixer # This stopped working so comment out for now (started applying to files that didn't need it): # - id: fix-encoding-pragma - id: check-yaml # Keep in sync with flake8 version in setup.py -- # check https://github.com/pre-commit/pre-commit-hooks/blob/master/setup.py # for the version of flake8 that is included with this pre-commit repo. - id: flake8 - repo: https://github.com/chewse/pre-commit-mirrors-pydocstyle # Keep in sync with pydocstyle version in setup.py rev: v2.1.1 hooks: - id: pydocstyle exclude: bidict/_version.py - repo: https://github.com/Lucas-C/pre-commit-hooks rev: v1.1.6 hooks: - id: forbid-crlf - id: remove-crlf - id: forbid-tabs - id: remove-tabs # This stopped working so comment out for now (started applying to files that didn't need it): # - id: insert-license # files: \.py$ # args: # # Renamed LICENSE_HEADER -> .LICENSE_HEADER to avoid confusing licensee # # (https://github.com/benbalter/licensee - what GitHub uses to detect license) # - --license-filepath=.LICENSE_HEADER - repo: https://github.com/pre-commit/mirrors-pylint # Keep in sync with pylint version in setup.py rev: v2.2.2 hooks: - id: pylint # Needed to avoid ImportErrors when linting tests (keep in sync with versions in setup.py): additional_dependencies: ["hypothesis<4","pytest<5", "Sphinx<2"] args: # http://pylint.pycqa.org/en/latest/user_guide/run.html#parallel-execution # "If the provided number is 0, then the total number of CPUs will be used." - --jobs=0 - repo: https://github.com/jumanjihouse/pre-commit-hooks rev: 1.10.2 hooks: - id: shellcheck - id: shfmt bidict-0.18.2/.pylintrc0000664000372000037200000000121613535200701015543 0ustar travistravis00000000000000# https://docs.pylint.org/en/latest/technical_reference/features.html [MESSAGES CONTROL] disable = # Must inherit from object for Python 2 compatibility. useless-object-inheritance, # repeated-keyword check is buggy: # https://github.com/PyCQA/pylint/issues/1843#issuecomment-419746286 repeated-keyword, # bidict/_version.py is generated by setuptools_scm ignore = _version.py # Maximum number of parents for a class. # The default of 7 results in "too-many-ancestors" for all bidict classes. max-parents = 13 # Maximum number of arguments for a function. # The default of 5 only leaves room for 4 args besides self for methods. max-args=6 bidict-0.18.2/.readthedocs.yml0000664000372000037200000000034213535200701016763 0ustar travistravis00000000000000# http://docs.readthedocs.io/en/latest/yaml-config.html#requirements-file # Don't build any extra formats formats: - none build: image: latest python: version: 3.6 pip_install: true extra_requirements: - docs bidict-0.18.2/.travis.yml0000664000372000037200000001421413535200701016011 0ustar travistravis00000000000000language: 'python' # Default version used for jobs that don't override it. python: '3.7' # TODO: Update to 'bionic' once available. # https://travis-ci.community/t/ubuntu-18-04-1-lts-bionic-beaver/1270 dist: 'xenial' # https://docs.travis-ci.com/user/customizing-the-build/ # "Without the top-level env, no job will be allowed to fail." env: global: - 'INSTALL_EXTRAS=test' before_install: # Ensure we have the required versions of Python and Pip. - 'echo "TRAVIS_PULL_REQUEST_SHA: $TRAVIS_PULL_REQUEST_SHA"' - 'echo "TRAVIS_COMMIT: $TRAVIS_COMMIT"' - 'git --no-pager log -n2' # Travis does a shallow (--depth=50) clone by default. # Clone the full history as requested by setuptools_scm. - 'travis_retry git fetch --unshallow' # Install Python on macOS since https://github.com/travis-ci/travis-ci/issues/2312 is WONTFIXed. - | if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then declare -r pyver="${TASK##*-}" # strip all chars up to and including the last - declare -r python="python$pyver" echo "TASK=$TASK -> pyver=$pyver python=$python" if ! type "$python"; then export HOMEBREW_NO_AUTO_UPDATE=1 brew tap minrk/homebrew-python-frameworks brew cask install "python-framework-${pyver/./}" type "$python" || exit 1 fi type python "$python" --version travis_retry curl https://bootstrap.pypa.io/get-pip.py | "$python" "$python" -m pip install virtualenv "$python" -m virtualenv ~/travis-env source ~/travis-env/bin/activate type python fi - 'python --version' # https://github.com/python-trio/trio/issues/487#issuecomment-377931587 - 'echo "Installing latest pip..."' - 'travis_retry curl https://bootstrap.pypa.io/get-pip.py | python' - 'pip --version' install: # Install our test dependencies. - | [[ "$COVERAGE" ]] && INSTALL_EXTRAS+=",coverage" install_cmd="pip install -U --upgrade-strategy=eager ." [[ "$INSTALL_EXTRAS" ]] && install_cmd+="[$INSTALL_EXTRAS]" echo "install_cmd: $install_cmd" travis_retry $install_cmd before_script: - 'pip list' - | if [[ "$TASK" == lint-* ]]; then shopt -s globstar export LINT_SRC=**/*.py echo "LINT_SRC:" $LINT_SRC fi script: # Run the test suite. - | if [[ "$TRAVIS_EVENT_TYPE" == "cron" ]]; then export HYPOTHESIS_PROFILE="more-examples" # See tests/hypothesis/_setup_hypothesis.py else export HYPOTHESIS_PROFILE="default" fi export PYTEST_ADDOPTS="--hypothesis-profile=${HYPOTHESIS_PROFILE}" if [[ "$COVERAGE" ]]; then export PYTEST_ADDOPTS="${PYTEST_ADDOPTS} --cov=bidict --cov-config=.coveragerc" fi ./run_tests.py after_script: - | if [[ "$COVERAGE" ]]; then echo "Installing codecov..." travis_retry pip install codecov || exit 1 echo echo "Uploading coverage report to codecov..." travis_retry codecov fi matrix: allow_failures: - env: 'TASK=docs-linkcheck INSTALL_EXTRAS=docs' - env: 'TASK=test-linux-cpython-3.8-dev' - env: 'TASK=deploy-if-tag' ## fast_finish causes Travis to sned a useless daily "build pending" email; not worth the noise. # fast_finish: true include: # Each job below performs a single task. Setting a per-job "TASK" env var # causes Travis to clearly show each job's task in the web UI. # "test*" tasks run the test suite with various Python versions. # Travis runs jobs in the order defined below -> order jobs by priority. ## Test suite on Linux with latest CPython and PyPy 2 and 3 -> enable coverage. - python: '3.7' env: 'TASK=test-linux-cpython-3.7 COVERAGE=1' - python: '2.7' env: 'TASK=test-linux-cpython-2.7 COVERAGE=1' - python: 'pypy3.5-6.0' env: 'TASK=test-linux-pypy-3.5-6.0 COVERAGE=1' - python: 'pypy2.7-6.0' env: 'TASK=test-linux-pypy-2.7-6.0 COVERAGE=1' ## Test suite on Mac with latest CPython 2 and 3. - python: '2.7' env: 'TASK=test-mac-cpython-2.7' os: 'osx' language: 'generic' - python: '3.7' env: 'TASK=test-mac-cpython-3.7' os: 'osx' language: 'generic' ## Make sure there are no relied-on side effects in assert statements. - env: 'TASK=test-with-optimization-flag' before_install: 'skip' install: 'skip' script: 'python -O -m doctest -o IGNORE_EXCEPTION_DETAIL -o ELLIPSIS tests/*.txt' ## Linting, static analysis, code style. - env: 'TASK=lint-flake8 INSTALL_EXTRAS=flake8' before_install: 'skip' script: 'flake8 $LINT_SRC' - env: 'TASK=lint-pylint INSTALL_EXTRAS=pylint,test' before_install: 'skip' script: 'pylint --jobs=0 $LINT_SRC' - env: 'TASK=lint-pydocstyle INSTALL_EXTRAS=pydocstyle' before_install: 'skip' script: 'pydocstyle $LINT_SRC' ## Misc. - env: 'TASK=docs-build INSTALL_EXTRAS=docs' before_install: 'skip' script: './build-docs.sh' - env: 'TASK=docs-linkcheck INSTALL_EXTRAS=docs' before_install: 'skip' script: '(cd docs && travis_retry make linkcheck)' ## Remaining CPython versions on Linux. - python: '3.6' env: 'TASK=test-linux-cpython-3.6' - python: '3.5' env: 'TASK=test-linux-cpython-3.5' - python: '3.8-dev' env: 'TASK=test-linux-cpython-3.8-dev' - stage: 'deploy-if-tag' env: 'TASK=deploy-if-tag' before_install: 'skip' install: 'skip' script: 'skip' deploy: - provider: 'pypi' user: 'jab' password: secure: 'B9LLgXkTbtjeC/IbH4wh9PEBzvKEAuYo3EBNW5f1xuLqVqtsysIyxJa5ar/FQ4qwUCBwZPFAXFurN3lLzRhb2Tc04YQ0GYVv6f8lkzwrjoWau4iB9Qt/nnvdRa7KryEJvtenHCAnwoEUaADCjkZjwo6fIA0hEOLB6/AYfhfgXYA=' on: tags: true # Does this deploy all tags to PyPI, not just release tags? # https://docs.travis-ci.com/user/deployment/pypi/ doesn't say. distributions: 'sdist bdist_wheel' before_cache: - 'rm -rf "$HOME"/.cache/pip/log' cache: directories: - '"$HOME"/.cache/pip' - '"$HOME"/.hypothesis' notifications: webhooks: urls: - 'https://webhooks.gitter.im/e/bf64fb45a633c0935b9b' email: recipients: 'jab@math.brown.edu' bidict-0.18.2/CHANGELOG.rst0000664000372000037200000006725513535200701015736 0ustar travistravis00000000000000.. Forward declarations for all the custom interpreted text roles that Sphinx defines and that are used below. This helps Sphinx-unaware tools (e.g. rst2html, PyPI's and GitHub's renderers, etc.). .. role:: doc .. role:: ref Changelog ========= Release Notifications --------------------- .. duplicated in README.rst (would use `.. include::` but GitHub doesn't understand it) .. image:: https://img.shields.io/badge/libraries.io-subscribe-5BC0DF.svg :target: https://libraries.io/pypi/bidict :alt: Follow on libraries.io Tip: `Subscribe to bidict releases `__ on libraries.io to be notified when new versions of bidict are released. Alternatively, `on GitHub `__, click "`Watch `__" and choose "Releases". 0.18.2 (2019-09-08) ------------------- - Warn that Python 2 support will be dropped in a future release when Python 2 is detected. 0.18.1 (2019-09-03) ------------------- - Fix a regression introduced by the memory optimizations added in 0.15.0 which caused :func:`deepcopied ` and :func:`unpickled ` bidicts to have their inverses set incorrectly. `#94 `__ 0.18.0 (2019-02-14) ------------------- - Rename ``bidict.BidirectionalMapping.inv`` to :attr:`~bidict.BidirectionalMapping.inverse` and make :attr:`bidict.BidictBase.inv` an alias for :attr:`~bidict.BidictBase.inverse`. `#86 `__ - :meth:`bidict.BidirectionalMapping.__subclasshook__` now requires an ``inverse`` attribute rather than an ``inv`` attribute for a class to qualify as a virtual subclass. This breaking change is expected to affect few if any users. - Add Python 2/3-compatible :attr:`bidict.compat.collections_abc` alias. - Stop testing Python 3.4 on CI, and warn when Python 3 < 3.5 is detected rather than Python 3 < 3.3. Python 3.4 reaches `end of life `__ on 2019-03-18. As of January 2019, 3.4 represents only about 3% of bidict downloads on `PyPI Stats `__. 0.17.5 (2018-11-19) ------------------- Improvements to performance and delegation logic, with minor breaking changes to semi-private APIs. - Remove the ``__delegate__`` instance attribute added in the previous release. It was overly general and not worth the cost. Instead of checking ``self.__delegate__`` and delegating accordingly each time a possibly-delegating method is called, revert back to using "delegated-to-fwdm" mixin classes (now found in ``bidict._delegating_mixins``), and resurrect a mutable bidict parent class that omits the mixins as :class:`bidict.MutableBidict`. - Rename ``__repr_delegate__`` to :class:`~bidict.BidictBase._repr_delegate`. 0.17.4 (2018-11-14) ------------------- Minor code, interop, and (semi-)private API improvements. - :class:`~bidict.OrderedBidict` optimizations and code improvements. Use ``bidict``\s for the backing ``_fwdm`` and ``_invm`` mappings, obviating the need to store key and value data in linked list nodes. - Refactor proxied- (i.e. delegated-) to-``_fwdm`` logic for better composability and interoperability. Drop the ``_Proxied*`` mixin classes and instead move their methods into :class:`~bidict.BidictBase`, which now checks for an object defined by the ``BidictBase.__delegate__`` attribute. The ``BidictBase.__delegate__`` object will be delegated to if the method is available on it, otherwise a default implementation (e.g. inherited from :class:`~collections.abc.Mapping`) will be used otherwise. Subclasses may set ``__delegate__ = None`` to opt out. Consolidate ``_MutableBidict`` into :class:`bidict.bidict` now that the dropped mixin classes make it unnecessary. - Change ``__repr_delegate__`` to simply take a type like :class:`dict` or :class:`list`. - Upgrade to latest major `sortedcontainers `__ version (from v1 to v2) for the :ref:`extending:Sorted Bidict Recipes`. - ``bidict.compat.{view,iter}{keys,values,items}`` on Python 2 no longer assumes the target object implements these methods, as they're not actually part of the :class:`~collections.abc.Mapping` interface, and provides fallback implementations when the methods are unavailable. This allows the :ref:`extending:Sorted Bidict Recipes` to continue to work with sortedcontainers v2 on Python 2. 0.17.3 (2018-09-18) ------------------- - Improve packaging by adding a pyproject.toml and by including more supporting files in the distribution. `#81 `__ - Drop pytest-runner and support for running tests via ``python setup.py test`` in preference to ``pytest`` or ``python -m pytest``. 0.17.2 (2018-04-30) ------------------- Memory usage improvements +++++++++++++++++++++++++ - Use less memory in the linked lists that back :class:`~bidict.OrderedBidict`\s by storing node data unpacked rather than in (key, value) tuple objects. 0.17.1 (2018-04-28) ------------------- Bugfix Release ++++++++++++++ Fix a regression in 0.17.0 that could cause erroneous behavior when updating items of an :class:`~bidict.Orderedbidict`'s inverse, e.g. ``some_ordered_bidict.inv[foo] = bar``. 0.17.0 (2018-04-25) ------------------- Speedups and memory usage improvements ++++++++++++++++++++++++++++++++++++++ - Pass :meth:`~bidict.bidict.keys`, :meth:`~bidict.bidict.values`, and :meth:`~bidict.bidict.items` calls (as well as their ``iter*`` and ``view*`` counterparts on Python 2) through to the backing ``_fwdm`` and ``_invm`` dicts so that they run as fast as possible (i.e. at C speed on CPython), rather than using the slower implementations inherited from :class:`collections.abc.Mapping`. - Use weakrefs in the linked lists that back :class:`~bidict.OrderedBidict`\s to avoid creating strong reference cycles. Memory for an ordered bidict that you create can now be reclaimed in CPython as soon as you no longer hold any references to it, rather than having to wait until the next garbage collection. `#71 `__ Misc ++++ - Add :attr:`bidict.__version_info__` attribute to complement :attr:`bidict.__version__`. 0.16.0 (2018-04-06) ------------------- Minor code and efficiency improvements to :func:`~bidict.inverted` and :func:`~bidict._util._iteritems_args_kw` (formerly ``bidict.pairs()``). Minor Breaking API Changes ++++++++++++++++++++++++++ The following breaking changes are expected to affect few if any users. - Rename ``bidict.pairs()`` → :func:`bidict._util._iteritems_args_kw`. 0.15.0 (2018-03-29) ------------------- Speedups and memory usage improvements ++++++++++++++++++++++++++++++++++++++ - Use :ref:`slots` to speed up bidict attribute access and reduce memory usage. On Python 3, instantiating a large number of bidicts now uses ~57% the amount of memory that it used before, and on Python 2 only ~33% the amount of memory that it used before, in a simple but representative `benchmark `__. - Use weakrefs to refer to a bidict's inverse internally, no longer creating a strong reference cycle. Memory for a bidict that you create can now be reclaimed in CPython as soon as you no longer hold any references to it, rather than having to wait for the next garbage collection. See the new :ref:`addendum:Bidict Avoids Reference Cycles` documentation. `#24 `__ - Make :func:`bidict.BidictBase.__eq__` significantly more speed- and memory-efficient when comparing to a non-:class:`dict` :class:`~collections.abc.Mapping`. (``Mapping.__eq__()``\'s inefficient implementation will now never be used.) The implementation is now more reusable as well. - Make :func:`bidict.OrderedBidictBase.__iter__` as well as equality comparison slightly faster for ordered bidicts. Minor Bugfixes ++++++++++++++ - :func:`~bidict.namedbidict` now verifies that the provided ``keyname`` and ``valname`` are distinct, raising :class:`ValueError` if they are equal. - :func:`~bidict.namedbidict` now raises :class:`TypeError` if the provided ``base_type`` is not a :class:`~bidict.BidirectionalMapping`. - If you create a custom bidict subclass whose ``_fwdm_cls`` differs from its ``_invm_cls`` (as in the ``FwdKeySortedBidict`` example from the :ref:`extending:Sorted Bidict Recipes`), the inverse bidirectional mapping type (with ``_fwdm_cls`` and ``_invm_cls`` swapped) is now correctly computed and used automatically for your custom bidict's :attr:`~bidict.BidictBase.inverse` bidict. Miscellaneous +++++++++++++ - Classes no longer have to provide an ``__inverted__`` attribute to be considered virtual subclasses of :class:`~bidict.BidirectionalMapping`. - If :func:`bidict.inverted` is passed an object with an ``__inverted__`` attribute, it now ensures it is :func:`callable` before returning the result of calling it. - :func:`~bidict.BidictBase.__repr__` no longer checks for a ``__reversed__`` method to determine whether to use an ordered or unordered-style repr. It now calls the new ``__repr_delegate__`` instead (which may be overridden if needed), for better composability. Minor Breaking API Changes ++++++++++++++++++++++++++ The following breaking changes are expected to affect few if any users. - Split back out the :class:`~bidict.BidictBase` class from :class:`~bidict.frozenbidict` and :class:`~bidict.OrderedBidictBase` from :class:`~bidict.FrozenOrderedBidict`, reverting the merging of these in 0.14.0. Having e.g. ``issubclass(bidict, frozenbidict) == True`` was confusing, so this change restores ``issubclass(bidict, frozenbidict) == False``. See the updated :ref:`other-bidict-types:Bidict Types Diagram` and :ref:`other-bidict-types:Polymorphism` documentation. - Rename: - ``bidict.BidictBase.fwdm`` → ``._fwdm`` - ``bidict.BidictBase.invm`` → ``._invm`` - ``bidict.BidictBase.fwd_cls`` → ``._fwdm_cls`` - ``bidict.BidictBase.inv_cls`` → ``._invm_cls`` - ``bidict.BidictBase.isinv`` → ``._isinv`` Though overriding ``_fwdm_cls`` and ``_invm_cls`` remains supported (see :doc:`extending`), this is not a common enough use case to warrant public names. Most users do not need to know or care about any of these. - The :attr:`~bidict.RAISE`, :attr:`~bidict.OVERWRITE`, and :attr:`~bidict.IGNORE` duplication policies are no longer available as attributes of :class:`bidict.DuplicationPolicy`, and can now only be accessed as attributes of the :mod:`bidict` module namespace, which was the canonical way to refer to them anyway. It is now no longer possible to create an infinite chain like ``DuplicationPolicy.RAISE.RAISE.RAISE...`` - Make ``bidict.pairs()`` and :func:`bidict.inverted` no longer importable from ``bidict.util``, and now only importable from the top-level :mod:`bidict` module. (``bidict.util`` was renamed ``bidict._util``.) - Pickling ordered bidicts now requires at least version 2 of the pickle protocol. If you are using Python 3, :attr:`pickle.DEFAULT_PROTOCOL` is 3 anyway, so this will not affect you. However if you are using in Python 2, :attr:`~pickle.DEFAULT_PROTOCOL` is 0, so you must now explicitly specify the version in your :func:`pickle.dumps` calls, e.g. ``pickle.dumps(ob, 2)``. 0.14.2 (2017-12-06) ------------------- - Make initializing (or updating an empty bidict) from only another :class:`~bidict.BidirectionalMapping` more efficient by skipping unnecessary duplication checking. - Fix accidental ignoring of specified ``base_type`` argument when (un)pickling a :func:`~bidict.namedbidict`. - Fix incorrect inversion of ``some_named_bidict.inv._for`` and ``some_named_bidict.inv._for``. - Only warn when an unsupported Python version is detected (e.g. Python < 2.7) rather than raising :class:`AssertionError`. 0.14.1 (2017-11-28) ------------------- - Fix a bug introduced in 0.14.0 where hashing a :class:`~bidict.frozenbidict`\’s inverse (e.g. ``f = frozenbidict(); {f.inv: '...'}``) would cause an ``AttributeError``. - Fix a bug introduced in 0.14.0 for Python 2 users where attempting to call ``viewitems()`` would cause a ``TypeError``. `#48 `__ 0.14.0 (2017-11-20) ------------------- - Fix a bug where :class:`~bidict.bidict`\’s default *on_dup_kv* policy was set to :attr:`~bidict.RAISE`, rather than matching whatever *on_dup_val* policy was in effect as was :ref:`documented `. - Fix a bug that could happen when using Python's optimization (``-O``) flag that could leave an ordered bidict in an inconsistent state when dealing with duplicated, overwritten keys or values. If you do not use optimizations (specifically, skipping ``assert`` statements), this would not have affected you. - Fix a bug introduced by the optimizations in 0.13.0 that could cause a frozen bidict that compared equal to another mapping to have a different hash value from the other mapping, violating Python's object model. This would only have affected you if you were inserting a frozen bidict and some other immutable mapping that it compared equal to into the same set or mapping. - Add :meth:`~bidict.OrderedBidictBase.equals_order_sensitive`. - Reduce the memory usage of ordered bidicts. - Make copying of ordered bidicts faster. - Improvements to tests and CI, including: - Test on Windows - Test with PyPy3 - Test with CPython 3.7-dev - Test with optimization flags - Require pylint to pass Breaking API Changes ++++++++++++++++++++ This release includes multiple API simplifications and improvements. - Rename: - ``orderedbidict`` → :class:`~bidict.OrderedBidict` - ``frozenorderedbidict`` → :class:`~bidict.FrozenOrderedBidict` so that these now match the case of :class:`collections.OrderedDict`. The names of the :class:`~bidict.bidict`, :func:`~bidict.namedbidict`, and :class:`~bidict.frozenbidict` classes have been retained as all-lowercase so that they continue to match the case of :class:`dict`, :func:`~collections.namedtuple`, and :class:`frozenset`, respectively. - The ``ON_DUP_VAL`` duplication policy value for *on_dup_kv* has been removed. Use ``None`` instead. - Merge :class:`~bidict.frozenbidict` and ``BidictBase`` together and remove ``BidictBase``. :class:`~bidict.frozenbidict` is now the concrete base class that all other bidict types derive from. See the updated :ref:`other-bidict-types:Bidict Types Diagram`. - Merge :class:`~bidict.frozenbidict` and ``FrozenBidictBase`` together and remove ``FrozenBidictBase``. See the updated :ref:`other-bidict-types:Bidict Types Diagram`. - Merge ``frozenorderedbidict`` and ``OrderedBidictBase`` together into a single :class:`~bidict.FrozenOrderedBidict` class and remove ``OrderedBidictBase``. :class:`~bidict.OrderedBidict` now extends :class:`~bidict.FrozenOrderedBidict` to add mutable behavior. See the updated :ref:`other-bidict-types:Bidict Types Diagram`. - Make :meth:`~bidict.OrderedBidictBase.__eq__` always perform an order-insensitive equality test, even if the other mapping is ordered. Previously, :meth:`~bidict.OrderedBidictBase.__eq__` was only order-sensitive for other ``OrderedBidictBase`` subclasses, and order-insensitive otherwise. Use the new :meth:`~bidict.OrderedBidictBase.equals_order_sensitive` method for order-sensitive equality comparison. - ``orderedbidict._should_compare_order_sensitive()`` has been removed. - ``frozenorderedbidict._HASH_NITEMS_MAX`` has been removed. Since its hash value must be computed from all contained items (so that hash results are consistent with equality comparisons against unordered mappings), the number of items that influence the hash value should not be limitable. - ``frozenbidict._USE_ITEMSVIEW_HASH`` has been removed, and ``frozenbidict.compute_hash()`` now uses ``collections.ItemsView._hash()`` to compute the hash always, not just when running on PyPy. Override ``frozenbidict.compute_hash()`` to return ``hash(frozenset(iteritems(self)))`` if you prefer the old default behavior on CPython, which takes linear rather than constant space, but which uses the ``frozenset_hash`` routine (implemented in ``setobject.c``) rather than the pure Python ``ItemsView._hash()`` routine. - ``loosebidict`` and ``looseorderedbidict`` have been removed. A simple recipe to implement equivalents yourself is now given in :ref:`extending:OverwritingBidict Recipe`. - Rename ``FrozenBidictBase._compute_hash()`` → ``frozenbidict.compute_hash()``. - Rename ``DuplicationBehavior`` → :class:`~bidict.DuplicationPolicy`. - Rename: - ``bidict.BidictBase._fwd_class`` → ``.fwd_cls`` - ``bidict.BidictBase._inv_class`` → ``.inv_cls`` - ``bidict.BidictBase._on_dup_key`` → :attr:`~bidict.BidictBase.on_dup_key` - ``bidict.BidictBase._on_dup_val`` → :attr:`~bidict.BidictBase.on_dup_val` - ``bidict.BidictBase._on_dup_kv`` → :attr:`~bidict.BidictBase.on_dup_kv` 0.13.1 (2017-03-15) ------------------- - Fix regression introduced by the new :meth:`~bidict.BidirectionalMapping.__subclasshook__` functionality in 0.13.0 so that ``issubclass(OldStyleClass, BidirectionalMapping)`` once again works with old-style classes, returning ``False`` rather than raising :class:`AttributeError` `#41 `__ 0.13.0 (2017-01-19) ------------------- - Support Python 3.6. (Earlier versions of bidict should work fine on 3.6, but it is officially supported starting in this version.) - :class:`~bidict.BidirectionalMapping` has been refactored into an abstract base class, following the way :class:`collections.abc.Mapping` works. The concrete method implementations it used to provide have been moved into a new ``BidictBase`` subclass. :class:`~bidict.BidirectionalMapping` now also implements :meth:`~bidict.BidirectionalMapping.__subclasshook__`, so any class that provides a conforming set of attributes (enumerated in :attr:`~bidict.BidirectionalMapping._subclsattrs`) will be considered a :class:`~bidict.BidirectionalMapping` subclass automatically. - ``OrderedBidirectionalMapping`` has been renamed to ``OrderedBidictBase``, to better reflect its function. (It is not an ABC.) - A new ``FrozenBidictBase`` class has been factored out of :class:`~bidict.frozenbidict` and :class:`frozenorderedbidict `. This implements common behavior such as caching the result of ``__hash__`` after the first call. - The hash implementations of :class:`~bidict.frozenbidict` and :class:`frozenorderedbidict `. have been reworked to improve performance and flexibility. :class:`frozenorderedbidict `\’s hash implementation is now order-sensitive. See ``frozenbidict._compute_hash()`` and ``frozenorderedbidict._compute_hash`` for more documentation of the changes, including the new ``frozenbidict._USE_ITEMSVIEW_HASH`` and ``frozenorderedbidict._HASH_NITEMS_MAX`` attributes. If you have an interesting use case that requires overriding these, or suggestions for an alternative implementation, please `share your feedback `__. - Add ``_fwd_class`` and ``_inv_class`` attributes representing the backing :class:`~collections.abc.Mapping` types used internally to store the forward and inverse dictionaries, respectively. This allows creating custom bidict types with extended functionality simply by overriding these attributes in a subclass. See the new :doc:`extending` documentation for examples. - Pass any parameters passed to :meth:`~bidict.bidict.popitem` through to ``_fwd.popitem`` for greater extensibility. - More concise repr strings for empty bidicts. e.g. ``bidict()`` rather than ``bidict({})`` and ``orderedbidict()`` rather than ``orderedbidict([])``. - Add :attr:`bidict.compat.PYPY` and remove unused ``bidict.compat.izip_longest``. 0.12.0 (2016-07-03) ------------------- - New/renamed exceptions: - :class:`~bidict.KeyDuplicationError` - :class:`~bidict.ValueDuplicationError` - :class:`~bidict.KeyAndValueDuplicationError` - :class:`~bidict.DuplicationError` (base class for the above) - :func:`~bidict.bidict.put` now accepts ``on_dup_key``, ``on_dup_val``, and ``on_dup_kv`` keyword args which allow you to override the default policy when the key or value of a given item duplicates any existing item's. These can take the following values: - :attr:`~bidict.RAISE` - :attr:`~bidict.OVERWRITE` - :attr:`~bidict.IGNORE` ``on_dup_kv`` can also take ``ON_DUP_VAL``. If not provided, :func:`~bidict.bidict.put` uses the :attr:`~bidict.RAISE` policy by default. - New :func:`~bidict.bidict.putall` method provides a bulk :func:`~bidict.bidict.put` API, allowing you to override the default duplication handling policy that :func:`~bidict.bidict.update` uses. - :func:`~bidict.bidict.update` now fails clean, so if an :func:`~bidict.bidict.update` call raises a :class:`~bidict.DuplicationError`, you can now be sure that none of the given items was inserted. Previously, all of the given items that were processed before the one causing the failure would have been inserted, and no facility was provided to recover which items were inserted and which weren't, nor to revert any changes made by the failed :func:`~bidict.bidict.update` call. The new behavior makes it easier to reason about and control the effects of failed :func:`~bidict.bidict.update` calls. The new :func:`~bidict.bidict.putall` method also fails clean. Internally, this is implemented by storing a log of changes made while an update is being processed, and rolling back the changes when one of them is found to cause an error. This required reimplementing :class:`orderedbidict ` on top of two dicts and a linked list, rather than two OrderedDicts, since :class:`~collections.OrderedDict` does not expose its backing linked list. - :func:`orderedbidict.move_to_end() ` now works on Python < 3.2 as a result of the new :class:`orderedbidict ` implementation. - Add - :func:`bidict.compat.viewkeys` - :func:`bidict.compat.viewvalues` - :func:`bidict.compat.iterkeys` - :func:`bidict.compat.itervalues` - ``bidict.compat.izip`` - ``bidict.compat.izip_longest`` to complement the existing :func:`~bidict.compat.iteritems` and :func:`~bidict.compat.viewitems` compatibility helpers. - More efficient implementations of ``bidict.pairs()``, :func:`~bidict.inverted`, and :func:`~bidict.BidictBase.copy`. - Implement :func:`~bidict.BidictBase.__copy__` for use with the :mod:`copy` module. - Fix issue preventing a client class from inheriting from ``loosebidict``. `#34 `__ - Add benchmarking to tests. - Drop official support for CPython 3.3. (It may continue to work, but is no longer being tested.) Breaking API Changes ++++++++++++++++++++ - Rename ``KeyExistsException`` → :class:`~bidict.KeyDuplicationError` and ``ValueExistsException`` → :class:`~bidict.ValueDuplicationError`. - When overwriting the key of an existing value in an :class:`orderedbidict `, the position of the existing item is now preserved, overwriting the key of the existing item in place, rather than moving the item to the end. This now matches the behavior of overwriting the value of an existing key, which has always preserved the position of the existing item. (If inserting an item whose key duplicates that of one existing item and whose value duplicates that of another, the existing item whose value is duplicated is still dropped, and the existing item whose key is duplicated still gets its value overwritten in place, as before.) For example: .. code:: python >>> from bidict import orderedbidict # doctest: +SKIP >>> o = orderedbidict([(0, 1), (2, 3)]) # doctest: +SKIP >>> o.forceput(4, 1) # doctest: +SKIP previously would have resulted in: .. code:: python >>> o # doctest: +SKIP orderedbidict([(2, 3), (4, 1)]) but now results in: .. code:: python >>> o # doctest: +SKIP orderedbidict([(4, 1), (2, 3)]) 0.11.0 (2016-02-05) ------------------- - Add :class:`orderedbidict `, ``looseorderedbidict``, and :class:`frozenorderedbidict `. - Add :doc:`code-of-conduct`. - Drop official support for pypy3. (It still may work but is no longer being tested. Support may be added back once pypy3 has made more progress.) 0.10.0.post1 (2015-12-23) ------------------------- - Minor documentation fixes and improvements. 0.10.0 (2015-12-23) ------------------- - Remove several features in favor of keeping the API simpler and the code more maintainable. - In the interest of protecting data safety more proactively, by default bidict now raises an error on attempting to insert a non-unique value, rather than allowing its associated key to be silently overwritten. See discussion in `#21 `__. - New :meth:`~bidict.bidict.forceupdate` method provides a bulk :meth:`~bidict.bidict.forceput` operation. - Fix bugs in :attr:`~bidict.bidict.pop` and :attr:`~bidict.bidict.setdefault` which could leave a bidict in an inconsistent state. Breaking API Changes ++++++++++++++++++++ - Remove ``bidict.__invert__``, and with it, support for the ``~b`` syntax. Use :attr:`~bidict.BidictBase.inv` instead. `#19 `__ - Remove support for the slice syntax. Use ``b.inv[val]`` rather than ``b[:val]``. `#19 `__ - Remove ``bidict.invert``. Use :attr:`~bidict.BidictBase.inv` rather than inverting a bidict in place. `#20 `__ - Raise ``ValueExistsException`` when attempting to insert a mapping with a non-unique key. `#21 `__ - Rename ``collapsingbidict`` → ``loosebidict`` now that it suppresses ``ValueExistsException`` rather than the less general ``CollapseException``. `#21 `__ - ``CollapseException`` has been subsumed by ``ValueExistsException``. `#21 `__ - :meth:`~bidict.bidict.put` now raises ``KeyExistsException`` when attempting to insert an already-existing key, and ``ValueExistsException`` when attempting to insert an already-existing value. 0.9.0.post1 (2015-06-06) ------------------------ - Fix metadata missing in the 0.9.0rc0 release. 0.9.0rc0 (2015-05-30) --------------------- - Add this changelog, `Contributors' Guide `__, `Gitter chat room `__, and other community-oriented improvements. - Adopt Pytest. - Add property-based tests via `hypothesis `__. - Other code, tests, and docs improvements. Breaking API Changes ++++++++++++++++++++ - Move ``bidict.iteritems()`` and ``bidict.viewitems()`` to new :mod:`bidict.compat` module. - Move :class:`bidict.inverted` to new ``bidict.util`` module (still available from top-level :mod:`bidict` module as well). - Move ``bidict.fancy_iteritems()`` → ``bidict.util.pairs()`` (also available from top level as ``bidict.pairs()``). - Rename :func:`bidict.namedbidict`\'s ``bidict_type`` argument → ``base_type``. bidict-0.18.2/CODE_OF_CONDUCT.rst0000664000372000037200000000631613535200701016713 0ustar travistravis00000000000000Code of Conduct =============== Our Pledge ---------- In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. Our Standards ------------- Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting Our Responsibilities -------------------- Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. Scope ----- This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. Enforcement ----------- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. Attribution ----------- This Code of Conduct is adapted from the `Contributor Covenant `__, version 1.4, available at `https://www.contributor-covenant.org/version/1/4 `__. bidict-0.18.2/CONTRIBUTING.rst0000664000372000037200000001472313535200701016346 0ustar travistravis00000000000000.. Forward declarations for all the custom interpreted text roles that Sphinx defines and that are used below. This helps Sphinx-unaware tools (e.g. rst2html, PyPI's and GitHub's renderers, etc.). .. role:: doc .. role:: ref Contributors' Guide =================== Bug reports, feature requests, patches, and other contributions are warmly welcomed. Contribution should be as easy and friendly as possible. Below are a few guidelines contributors should follow to facilitate the process. Getting Started --------------- - `Create a GitHub account `__ if you don't have one already. - Search through the `issue tracker `__ to see if an issue or pull request has already been created for what you're interested in. If so, feel free to add comments to it or just hit the "subscribe" button to follow progress. If not, you can `join the chat room `__ to discuss there, or go ahead and `create a new issue `__: - Clearly describe the issue giving as much relevant context as possible. - If it is a bug, include reproduction steps, all known environments in which the bug is exhibited, and ideally a failing test case. - If you would like to contribute a patch, make sure you've `created your own fork `__ and have cloned it to your computer. Making Changes -------------- - Before making changes, please install the extra packages required for development: ``pip install -e .[dev]`` We use `EditorConfig `__ and `pre-commit `__ to help achieve uniform style and quality standards across a diversity of development environments. pre-commit gets installed when you run ``pip install -e .[dev]`` and ensures that various code checks are run before every commit (look in ``.pre-commit-config.yaml`` to see which hooks are run). EditorConfig allows us to provide a single ``.editorconfig`` file to configure settings like indentation consistently across a variety of suppored editors. See https://editorconfig.org/#download to install the plugin for your editor. - Create a topic branch off of master for your changes: ``git checkout -b master`` - Make commits of logical units. - Match the existing code style and quality standards. If you're adding a feature, include accompanying tests and documentation demonstrating its correctness and usage. - Run the tests locally with `tox `__ to make sure they pass for all supported Python versions (see ``envlist`` in ``tox.ini`` for the complete list). If you do not have all the referenced Python versions available locally, you can also push the changes on your branch to GitHub to automatically trigger a new `Travis-CI `__ build, which should run the tests for all supported Python versions. You should be able to see the results at ``travis-ci.org//bidict``, where ```` is the GitHub username you used to fork bidict. - Create a concise but comprehensive commit message in the following style:: Include an example commit message in CONTRIBUTING guide #9999 Without this patch the CONTRIBUTING guide would contain no examples of a model commit message. This is a problem because the contributor is left to imagine what the commit message should look like and may not get it right. This patch fixes the problem by providing a concrete example. The first line is an imperative statement summarizing the changes with an issue number from the tracker. The body describes the behavior without the patch, why it's a problem, and how the patch fixes the problem. Submitting Changes ------------------ - Push your changes to a topic branch in your fork of the repository: ``git push --set-upstream origin `` - Submit a pull request providing any additional relevant details necessary. - Acknowledgment should typically be fast but please allow 1-2 weeks for a full response / code review. - The code review process often involves some back-and-forth to get everything right before merging. This is typical of quality software projects that accept patches. - All communication should be supportive and appreciative of good faith efforts to contribute, creating a welcoming and inclusive community. Expect nothing less of any project. Other Ways to Contribute ------------------------ .. image:: https://img.shields.io/badge/Gumroad-Chip%20in-orange.svg :target: https://gumroad.com/l/bidict :alt: Chip in via Gumroad .. image:: https://img.shields.io/badge/Bountysource-Chip%20in-brightgreen.svg :target: https://www.bountysource.com/teams/bidict :alt: Chip in via Bountysource .. image:: https://img.shields.io/badge/PayPal-Chip%20in-blue.svg :target: https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=jab%40math%2ebrown%2eedu&lc=US&item_name=Support%20bidict&button_subtype=services¤cy_code=USD&bn=PP%2dBuyNowBF%3aPaypal%2dBuy%2520a%2520Drink%2dblue%2esvg%3aNonHosted :alt: Chip in via PayPal .. duplicated in README.rst (would use `.. include::` but GitHub doesn't understand it) Bidict is the product of hundreds of hours of unpaid, voluntary work. If bidict has helped you accomplish your work, especially work you've been paid for, please consider chipping in toward the costs of bidict's maintenance and development and/or ask your organization to do the same. Any amount contributed is gratefully received. Besides chipping in financially, filing issues, and submitting pull requests, there are other ways to contribute. - If you read the code and learned something new, please :ref:`let me know ` [#fn-let-me-know]_. - If you're using bidict in a project you work on, please post about your experience and send me a link. - If you come across other people who could find bidict useful, please spread the word. **Please support bidict:** .. image:: https://raw.githubusercontent.com/jab/bidict/master/assets/support-on-gumroad.png :target: https://gumroad.com/l/bidict :alt: Support bidict Code of Conduct --------------- All participation in this project should respect the :doc:`code-of-conduct`. [#fn-coc]_ By participating, you are expected to honor this code. .. [#fn-let-me-know] ``__ .. [#fn-coc] ``_ | ``__ bidict-0.18.2/LICENSE0000664000372000037200000004052513535200701014711 0ustar travistravis00000000000000Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. bidict-0.18.2/MANIFEST.in0000664000372000037200000000102613535200701015433 0ustar travistravis00000000000000# Tip: pip install check-manifest && check-manifest -uv include LICENSE include pyproject.toml include *.rst include *.sh include *.yaml include *.yml include .editorconfig include .pylintrc include .LICENSE_HEADER include .coveragerc include pytest.ini include tox.ini include docs/_static/custom.css include docs/_static/bidict-types-diagram.dot recursive-include docs *.py recursive-include docs *.rst recursive-include docs Makefile recursive-include docs/_static *.png recursive-include tests *.py recursive-include tests *.txt bidict-0.18.2/PKG-INFO0000664000372000037200000003031613535200730015000 0ustar travistravis00000000000000Metadata-Version: 2.1 Name: bidict Version: 0.18.2 Summary: Efficient, Pythonic bidirectional map implementation and related functionality Home-page: https://bidict.readthedocs.io Author: Joshua Bronson Author-email: jab@math.brown.edu License: MPL 2.0 Description: .. Forward declarations for all the custom interpreted text roles that Sphinx defines and that are used below. This helps Sphinx-unaware tools (e.g. rst2html, PyPI's and GitHub's renderers, etc.). .. role:: doc bidict ====== Efficient, Pythonic bidirectional map implementation and related functionality. .. image:: https://raw.githubusercontent.com/jab/bidict/master/assets/logo-sm.png :target: https://bidict.readthedocs.io/ :alt: bidict logo Status ------ .. image:: https://img.shields.io/pypi/v/bidict.svg :target: https://pypi.org/project/bidict :alt: Latest release .. image:: https://img.shields.io/readthedocs/bidict/master.svg :target: https://bidict.readthedocs.io/en/master/ :alt: Documentation .. image:: https://api.travis-ci.org/jab/bidict.svg?branch=master :target: https://travis-ci.org/jab/bidict :alt: Travis-CI build status .. image:: https://codecov.io/gh/jab/bidict/branch/master/graph/badge.svg :target: https://codecov.io/gh/jab/bidict :alt: Test coverage .. image:: https://img.shields.io/lgtm/alerts/github/jab/bidict.svg :target: https://lgtm.com/projects/g/jab/bidict/ :alt: LGTM alerts .. image:: https://api.codacy.com/project/badge/Grade/6628756a73254cd895656348236833b8 :target: https://www.codacy.com/app/jab/bidict :alt: Codacy grade .. image:: https://bestpractices.coreinfrastructure.org/projects/2354/badge :target: https://bestpractices.coreinfrastructure.org/en/projects/2354 :alt: CII best practices badge .. image:: https://img.shields.io/badge/tidelift-pro%20support-EF914C.svg :target: https://tidelift.com/subscription/pkg/pypi-bidict?utm_source=pypi-bidict&utm_medium=referral&utm_campaign=docs :alt: Paid support available via Tidelift .. Hide to reduce clutter .. image:: https://ci.appveyor.com/api/projects/status/gk133415udncwto3/branch/master?svg=true :target: https://ci.appveyor.com/project/jab/bidict :alt: AppVeyor (Windows) build status .. image:: https://img.shields.io/pypi/pyversions/bidict.svg :target: https://pypi.org/project/bidict :alt: Supported Python versions .. image:: https://img.shields.io/pypi/implementation/bidict.svg :target: https://pypi.org/project/bidict :alt: Supported Python implementations .. image:: https://img.shields.io/pypi/l/bidict.svg :target: https://raw.githubusercontent.com/jab/bidict/master/LICENSE :alt: License .. image:: https://img.shields.io/badge/dynamic/json.svg?label=downloads&url=https%3A%2F%2Fpypistats.org%2Fapi%2Fpackages%2Fbidict%2Frecent%3Fperiod%3Dmonth&query=%24.data.last_month&colorB=blue&suffix=%2fmonth :target: https://pypistats.org/packages/bidict :alt: Downloads past month Bidict: ^^^^^^^ - is in use by several teams at Google, Venmo, CERN, Bank of America Merrill Lynch, Bloomberg, Two Sigma, and others - has carefully designed APIs for safety, simplicity, flexibility, and ergonomics - is CPython-, PyPy-, Python 2-, and Python 3-compatible - has extensive test coverage (including property-based tests and benchmarks) run continuously on all supported Python versions and OSes - integrates natively with Python’s collections interfaces - is implemented in concise, well-factored, well-documented pure Python that leverages a number of advanced language features [#fn-learning]_ ⚠️ Python 2 EOL ⚠️ ++++++++++++++++++ Python 2 support will be dropped in a future release. See `python3statement.org `__ for more info. Installation ------------ ``pip install bidict`` Quick Start ----------- .. code:: python >>> from bidict import bidict >>> element_by_symbol = bidict({'H': 'hydrogen'}) >>> element_by_symbol['H'] 'hydrogen' >>> element_by_symbol.inverse['hydrogen'] 'H' For more usage documentation, head to the :doc:`intro` [#fn-intro]_ and proceed from there. Community Support ----------------- .. image:: https://img.shields.io/badge/chat-on%20gitter-5AB999.svg?logo=gitter-white :target: https://gitter.im/jab/bidict :alt: Chat If you are thinking of using bidict in your work, or if you have any questions, comments, or suggestions, I'd love to know about your use case and provide as much voluntary support for it as possible. Please feel free to leave a message in the `chatroom `__ or open a new issue on GitHub. You can search through `existing issues `__ before creating a new one in case your questions or concerns have been adressed there already. Paid Support via Tidelift ------------------------- .. image:: https://img.shields.io/badge/tidelift-pro%20support-EF914C.svg :target: https://tidelift.com/subscription/pkg/pypi-bidict?utm_source=pypi-bidict&utm_medium=referral&utm_campaign=readme :alt: Paid support available via Tidelift If your use case requires a greater level of support, contractual support for bidict can be obtained through the `Tidelift subscription `__. Notice of Usage --------------- If you use bidict, and especially if your usage or your organization is significant in some way, please let me know. You can: - `star bidict on GitHub `__ (the "star" button is at the top-right) - `create an issue `__ (preferred) - leave a message in the `chat room `__ - `email me `__ Changelog --------- See the :doc:`changelog` [#fn-changelog]_ for a history of notable changes to bidict. Release Notifications --------------------- .. duplicated in CHANGELOG.rst: (would use `.. include::` but GitHub doesn't understand it) .. image:: https://img.shields.io/badge/libraries.io-subscribe-5BC0DF.svg :target: https://libraries.io/pypi/bidict :alt: Follow on libraries.io `Subscribe to bidict releases `__ on libraries.io to be notified when new versions of bidict are released. Alternatively, on `GitHub `__, click "`Watch `__" and choose "Releases". Learning from bidict -------------------- One of the most rewarding things about bidict is the outsized amount of advanced Python it covers in light of its small codebase. Check out :doc:`learning-from-bidict` [#fn-learning]_ if you're interested in learning more. Contributing ------------ Bidict is currently a one-person operation maintained on a voluntary basis with no other sponsorship. Your help would be most welcome! Reviewers Wanted! ^^^^^^^^^^^^^^^^^ One of the most valuable ways to contribute to bidict and to explore some advanced Python [#fn-learning]_ while you're at it is to review bidict's relatively small codebase. Please create an issue or pull request with any improvements you'd propose or any other results you found. (Submitting a "Nothing-to-merge" PR with feedback in inline code comments or a `Review results `__ issue both work well.) You can also +1 `this issue `__ to sign up to give feedback on future proposed changes that are in need of a reviewer. Giving Back ^^^^^^^^^^^ .. duplicated in CONTRIBUTING.rst (would use `.. include::` but GitHub doesn't understand it) Bidict is the product of hundreds of hours of unpaid, voluntary work. If bidict has helped you accomplish your work, especially work you've been paid for, please consider chipping in toward the costs of bidict's maintenance and development and/or ask your organization to do the same. .. image:: https://raw.githubusercontent.com/jab/bidict/master/assets/support-on-gumroad.png :target: https://gumroad.com/l/bidict :alt: Support bidict Finding Documentation --------------------- If you're viewing this on ``__, note that multiple versions of the documentation are available, and you can choose a different version using the popup menu at the bottom-right. Please make sure you're viewing the version of the documentation that corresponds to the version of bidict you'd like to use. If you're viewing this on GitHub, PyPI, or some other place that can't render and link this documentation properly and are seeing broken links, try these alternate links instead: .. [#fn-intro] ``__ | ``__ .. [#fn-changelog] ``__ | ``__ .. [#fn-learning] ``__ | ``__ ---- Next: :doc:`intro` [#fn-intro]_ Keywords: dict dictionary mapping datastructure bimap bijection bijective injective inverse reverse bidirectional two-way 2-way Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Software Development :: Libraries :: Python Modules Provides-Extra: test Provides-Extra: coverage Provides-Extra: sphinx Provides-Extra: flake8 Provides-Extra: lint Provides-Extra: docs Provides-Extra: pylint Provides-Extra: pydocstyle Provides-Extra: dev bidict-0.18.2/PYPI_DOWNLOAD_STATS.rst0000664000372000037200000000125013535200701017454 0ustar travistravis00000000000000Retrieving PyPI Download Stats ------------------------------ As of May 2016, PyPI download stats are now available from BigQuery at: https://bigquery.cloud.google.com/table/the-psf:pypi.downloads Here is an example query for number of downloads in the last 30 days: .. code:: sql SELECT DATE(timestamp) as day, file.project, file.version, COUNT(*) as total_downloads, FROM TABLE_DATE_RANGE( [the-psf:pypi.downloads], DATE_ADD(CURRENT_TIMESTAMP(), -1, 'month'), CURRENT_TIMESTAMP() ) WHERE file.project = 'bidict' GROUP BY day, file.project, file.version ORDER BY day asc LIMIT 99999999 bidict-0.18.2/README.rst0000664000372000037200000002144513535200701015373 0ustar travistravis00000000000000.. Forward declarations for all the custom interpreted text roles that Sphinx defines and that are used below. This helps Sphinx-unaware tools (e.g. rst2html, PyPI's and GitHub's renderers, etc.). .. role:: doc bidict ====== Efficient, Pythonic bidirectional map implementation and related functionality. .. image:: https://raw.githubusercontent.com/jab/bidict/master/assets/logo-sm.png :target: https://bidict.readthedocs.io/ :alt: bidict logo Status ------ .. image:: https://img.shields.io/pypi/v/bidict.svg :target: https://pypi.org/project/bidict :alt: Latest release .. image:: https://img.shields.io/readthedocs/bidict/master.svg :target: https://bidict.readthedocs.io/en/master/ :alt: Documentation .. image:: https://api.travis-ci.org/jab/bidict.svg?branch=master :target: https://travis-ci.org/jab/bidict :alt: Travis-CI build status .. image:: https://codecov.io/gh/jab/bidict/branch/master/graph/badge.svg :target: https://codecov.io/gh/jab/bidict :alt: Test coverage .. image:: https://img.shields.io/lgtm/alerts/github/jab/bidict.svg :target: https://lgtm.com/projects/g/jab/bidict/ :alt: LGTM alerts .. image:: https://api.codacy.com/project/badge/Grade/6628756a73254cd895656348236833b8 :target: https://www.codacy.com/app/jab/bidict :alt: Codacy grade .. image:: https://bestpractices.coreinfrastructure.org/projects/2354/badge :target: https://bestpractices.coreinfrastructure.org/en/projects/2354 :alt: CII best practices badge .. image:: https://img.shields.io/badge/tidelift-pro%20support-EF914C.svg :target: https://tidelift.com/subscription/pkg/pypi-bidict?utm_source=pypi-bidict&utm_medium=referral&utm_campaign=docs :alt: Paid support available via Tidelift .. Hide to reduce clutter .. image:: https://ci.appveyor.com/api/projects/status/gk133415udncwto3/branch/master?svg=true :target: https://ci.appveyor.com/project/jab/bidict :alt: AppVeyor (Windows) build status .. image:: https://img.shields.io/pypi/pyversions/bidict.svg :target: https://pypi.org/project/bidict :alt: Supported Python versions .. image:: https://img.shields.io/pypi/implementation/bidict.svg :target: https://pypi.org/project/bidict :alt: Supported Python implementations .. image:: https://img.shields.io/pypi/l/bidict.svg :target: https://raw.githubusercontent.com/jab/bidict/master/LICENSE :alt: License .. image:: https://img.shields.io/badge/dynamic/json.svg?label=downloads&url=https%3A%2F%2Fpypistats.org%2Fapi%2Fpackages%2Fbidict%2Frecent%3Fperiod%3Dmonth&query=%24.data.last_month&colorB=blue&suffix=%2fmonth :target: https://pypistats.org/packages/bidict :alt: Downloads past month Bidict: ^^^^^^^ - is in use by several teams at Google, Venmo, CERN, Bank of America Merrill Lynch, Bloomberg, Two Sigma, and others - has carefully designed APIs for safety, simplicity, flexibility, and ergonomics - is CPython-, PyPy-, Python 2-, and Python 3-compatible - has extensive test coverage (including property-based tests and benchmarks) run continuously on all supported Python versions and OSes - integrates natively with Python’s collections interfaces - is implemented in concise, well-factored, well-documented pure Python that leverages a number of advanced language features [#fn-learning]_ ⚠️ Python 2 EOL ⚠️ ++++++++++++++++++ Python 2 support will be dropped in a future release. See `python3statement.org `__ for more info. Installation ------------ ``pip install bidict`` Quick Start ----------- .. code:: python >>> from bidict import bidict >>> element_by_symbol = bidict({'H': 'hydrogen'}) >>> element_by_symbol['H'] 'hydrogen' >>> element_by_symbol.inverse['hydrogen'] 'H' For more usage documentation, head to the :doc:`intro` [#fn-intro]_ and proceed from there. Community Support ----------------- .. image:: https://img.shields.io/badge/chat-on%20gitter-5AB999.svg?logo=gitter-white :target: https://gitter.im/jab/bidict :alt: Chat If you are thinking of using bidict in your work, or if you have any questions, comments, or suggestions, I'd love to know about your use case and provide as much voluntary support for it as possible. Please feel free to leave a message in the `chatroom `__ or open a new issue on GitHub. You can search through `existing issues `__ before creating a new one in case your questions or concerns have been adressed there already. Paid Support via Tidelift ------------------------- .. image:: https://img.shields.io/badge/tidelift-pro%20support-EF914C.svg :target: https://tidelift.com/subscription/pkg/pypi-bidict?utm_source=pypi-bidict&utm_medium=referral&utm_campaign=readme :alt: Paid support available via Tidelift If your use case requires a greater level of support, contractual support for bidict can be obtained through the `Tidelift subscription `__. Notice of Usage --------------- If you use bidict, and especially if your usage or your organization is significant in some way, please let me know. You can: - `star bidict on GitHub `__ (the "star" button is at the top-right) - `create an issue `__ (preferred) - leave a message in the `chat room `__ - `email me `__ Changelog --------- See the :doc:`changelog` [#fn-changelog]_ for a history of notable changes to bidict. Release Notifications --------------------- .. duplicated in CHANGELOG.rst: (would use `.. include::` but GitHub doesn't understand it) .. image:: https://img.shields.io/badge/libraries.io-subscribe-5BC0DF.svg :target: https://libraries.io/pypi/bidict :alt: Follow on libraries.io `Subscribe to bidict releases `__ on libraries.io to be notified when new versions of bidict are released. Alternatively, on `GitHub `__, click "`Watch `__" and choose "Releases". Learning from bidict -------------------- One of the most rewarding things about bidict is the outsized amount of advanced Python it covers in light of its small codebase. Check out :doc:`learning-from-bidict` [#fn-learning]_ if you're interested in learning more. Contributing ------------ Bidict is currently a one-person operation maintained on a voluntary basis with no other sponsorship. Your help would be most welcome! Reviewers Wanted! ^^^^^^^^^^^^^^^^^ One of the most valuable ways to contribute to bidict and to explore some advanced Python [#fn-learning]_ while you're at it is to review bidict's relatively small codebase. Please create an issue or pull request with any improvements you'd propose or any other results you found. (Submitting a "Nothing-to-merge" PR with feedback in inline code comments or a `Review results `__ issue both work well.) You can also +1 `this issue `__ to sign up to give feedback on future proposed changes that are in need of a reviewer. Giving Back ^^^^^^^^^^^ .. duplicated in CONTRIBUTING.rst (would use `.. include::` but GitHub doesn't understand it) Bidict is the product of hundreds of hours of unpaid, voluntary work. If bidict has helped you accomplish your work, especially work you've been paid for, please consider chipping in toward the costs of bidict's maintenance and development and/or ask your organization to do the same. .. image:: https://raw.githubusercontent.com/jab/bidict/master/assets/support-on-gumroad.png :target: https://gumroad.com/l/bidict :alt: Support bidict Finding Documentation --------------------- If you're viewing this on ``__, note that multiple versions of the documentation are available, and you can choose a different version using the popup menu at the bottom-right. Please make sure you're viewing the version of the documentation that corresponds to the version of bidict you'd like to use. If you're viewing this on GitHub, PyPI, or some other place that can't render and link this documentation properly and are seeing broken links, try these alternate links instead: .. [#fn-intro] ``__ | ``__ .. [#fn-changelog] ``__ | ``__ .. [#fn-learning] ``__ | ``__ ---- Next: :doc:`intro` [#fn-intro]_ bidict-0.18.2/assets/0000775000372000037200000000000013535200730015202 5ustar travistravis00000000000000bidict-0.18.2/assets/bidict-types-diagram.dot0000664000372000037200000000265313535200701021720 0ustar travistravis00000000000000// Copyright 2009-2019 Joshua Bronson. All Rights Reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // See ../build-docs.sh for how to generate an image from this file. digraph G { rankdir=BT dpi=300 node [fontsize="12", shape="box"] subgraph ABCs { node [fillcolor="#EFEFEF", color="#666666", fontcolor="#333333", style="filled", fontname="Script12 BT"] Mapping [label="collections.abc.Mapping"] MutableMapping [label="collections.abc.MutableMapping"] Hashable [label="collections.abc.Hashable"] MutableMapping -> Mapping { rank=same Mapping MutableMapping Hashable } BidirectionalMapping [label="bidict._abc.BidirectionalMapping", style="filled, bold", fontcolor="black", fontname="Cousine Bold Italic"] BidirectionalMapping -> Mapping } subgraph { node [style="bold", fontname="Fira Mono Bold"] bidict [label="bidict.bidict"] frozenbidict [label="bidict.frozenbidict"] OrderedBidict [label="bidict.OrderedBidict"] FrozenOrderedBidict [label="bidict.FrozenOrderedBidict"] bidict -> { BidirectionalMapping, MutableMapping } OrderedBidict -> { BidirectionalMapping, MutableMapping } FrozenOrderedBidict -> { BidirectionalMapping, Hashable } frozenbidict -> { BidirectionalMapping, Hashable } } } bidict-0.18.2/assets/bidict-types-diagram.png0000664000372000037200000013166113535200701021720 0ustar travistravis00000000000000PNG  IHDR 0sRGBkIDATxwSUڇCNJuuWݵg}:QET"*}{AQ Ał( * RavE$3LnL7y`rS{{*a@fa@ffa@W@Z,̾w;L2?f/s<<{Ihh$a2 Dfa@fa@f9<H33+(4s)̓7f9]a@J ͬ0&PΥ0/#;^@fa@fa@faFfaFfa@faFa@faFaFaFfaaaFaaaaafa@fa@faFfaFfa@faFa@faFaFaFfaaaFaaaFaaaaaaFfa@fa@fa@faFfaFfaaFfaaaFfffaffaFf@f@f@faFfa@fa@fa@faFfaFfaaFfaaaFaaaFaaaaafa@fa@faFfaFfa@faFa@faFaFaFfaaaFaaaFffff?0qȄh.Œ03f(d#3/aȓn8 f 35k?30$U} 3^p\1(3oŒ0J_y2#frи졌5w| csܴ2$f{b3#=K#s_gǚ@Œ0B_nKuCynˡ03k8=q{.>qs`nG""̌tf?;֪?ik}Zҷ]̬KY"yM/gf礶n~֋gòfv7>9}jfv~&J:TyٙUzM+hnd7f={>y"̌,tyUM3u-e33֏LaF}$ϙέffn7q6\jft_O03ْ?wknZGs'90o`afgiYfV a\עF=~d*3#a>d}҆:EfyQ o8̎HI=cr}`f77Vi67 ֽ'D|m003ҳ4݃f63bu-,X?2Za0Ql69T6ԍqffor#Ù(b3v[bN5Vi57 ֣u 9O&̏n~f={~!̌,t.3k[ufZRE{K~f9<ɬr 5oP7ze;u6Y`f3rl{gfeCٳf6,#%=af|䯅ffS3M+uon0YR +{fFzF[캪&[u-I3O3֏aF#̇QLmC:/xG_pʌ,ueG [2F禉n}$KPF67 ֽfQ{*P|!̌ t=Qf%ڏQfvX"oyYι /Kis˦{ϴtYk}۳ӕEYzrفyԙ6on*Nt||&9q?unmzd;N$Je0YskWrOYtCݙqЁCL",i_ af ʾKafeZQd{3{-cKjf9¼଒ѢxJMSUrW뻥׆EHcS|HAJǖ?}U~4wWE7F_['d343["|3{Թ8oڬnm kgYvŧ'<iɬ$Xܴ2\ʇ&4[mff'$}HKɂ0K){7}(̌tߌtN3UϩWg?Yih7Y>=0# Ot:h;vK%]Z>HMuac?6f>,3+ ʏ43k`M6u٫5_s,tDk3+33;:Y٘ffVaQkN5O+no~ԢwR5& 3;8fa Jeл^م9t$..M; Sɰ$9=}a#{A7'̌ttzU {m3;=dk<Œ0^6c?̬$Ң JGOpO3{2jKly_ 9\ƫ_`=8km8oP3[sϵ33GNsCiVlf~hfvDf]lf*,N%qycXJC[n2ёͺfUy_ Y=7xS{Y5I*yly֧aι0?of ^shϝsQ+3nك5ݰȳϷث+wι%^Ϧ:ո'gX}4c03k:#ٷǘ];oDA4xnQc͢Iڌ3ݰ=ķeoT񠨇*t;߬clϳ? s.f:[s@{eo0Yw_up]ƚ؇g%9^ZueZ_={j2deYOu1NGpWͬda̵pC'Yũu65nlr6Ŭ{m̎>Hݓq7kc@T*Gp?|Rj4;9w~\qTov>ȸC",: fv[jMo&u+d9+fvs]Jigг?bfqwXI0 7x;6k^sЋ.̱Kͥ&{8}&̌t?IVUُf½_bW<Œ0XߴAYߪs/Ѻf \o70Y5)T_O0xgs7fO;̮ؒR3RV=jISZG_xsue%{PFfNdJigлnf-*  7:{v|'ٽKs!̒6:Sf{fFFн{pK9&$ܳmve}_Yls0 s˗F|on7zVߩ]\ +Km1ĕ뛪KlcvԷy6eny7;9=8j7;)3ީj~eYÎKAq0Jn}r~bf|]8繘~f9v[Q6_t1f)fafS`n.;wvF4b~sϠgs+F즄#[Nf%I pY]hȨw\M|:xTgqUl`c~sϠgsTnCfW&sv5;ʃDDu6on˛d7d `035ҝ,f]UُfUgzaFs,S옸[GM:^rYZذ/Sܽص(F߻͊Gj{zU.eft'da~)6I:蝏sT!A>6T7ǜZGGUͭS77A寘QXr⨅13HQ3Jƶg²r{9$̌t#Yn$u]"%ܫ̪/Ϗy.aα0cfn`~TsnF5:KuzO#>w+k/u}kE\wUzXi9fR}ؕsnR zqk-ѡ+EsY^Jgг *:W3瞩]jQ q7֩E?#j+Rzp ^@@f? 3#_#ݹ͢Z)QF *tv ι̬WEʕ}ٕeιQ+8V]mv}t*uGnU3Њ,55vs->І /^"3g n.Zu,;rvX3[G /3V7.lnGӗ8{1Oq7$yԆ/$v s'yk*Oc ƾeΝtE. _u@kcvih:˫=$Om97p9=nyՏL3j^e}gcܲJ:G9q៣V]QzQ.'/v=/tX/{+Vmgjdл *?TwYssXHm(;2ACnfvk^u)Ϙu˾0u,ꭩ3^0@f_ 3#O#9wLιffzWA~\ifkL?3œsaKԋCs_gf3 =hrhSCefpιG`Gym\űf_`_݆{T^vTwݢ졞6Q_#Lgwx5ׅ r44Q-xH)9bNc.`-i33?cl[3Wᖎh}o7٘ 7{HV`_ \[W;d}V7kZw=i7wLnn{]\unuQ'jm SsvI}_T}/^ تn<*?1A?NZ#z`A gffo<o>}ťf8NfvdU Z?zؐژYK6\l ˝s ~cBw~ǭ|75˜[5sf 6+w[ǘjnQGA_\jv3k?tҘw~,têR3;xP;Ss[GpEӞ xu=O}~3plX]vsWAzWmmnH"?߰"At{c3vȢI]._뭩3^0@f_ 3#O#9%{WY7 *?9A?2gL?3œ{avg[ :PK>Q2tN 7ppl1o&9f֦Q%fffjH$Qs~hih{udOP]z%QC̮Y㜛g{c 'ݸuvιCneI=xoMIq0K>ιcto$ܫZٟ~fٽ~l6R5&m2h^]GY/%9ܔ mոFgL܊;zjffW`hH_ŔzY9ѯ:lG ^-utמ^btqwgkySBQ眛VjVzXթie0As=+sf%'FsWΓw_^] 3^ f 3#?#97GpMJGw=0# !M<uX'K͏\چշ ϽT*w9d':꥕̟pS.}`Az^[[|'~}=Zw9lֽCh?z豪ϷSF=8>Óvtbd?MXթg0>upܘ-zۻuY!aNܠaaFf.3imHαfȗ0Œ0#3fݗ!}n-2֧}fȗ0Œ0#3͞MoCX0£_ 4>0C ffaF!̛ir 2f@fa@faFfaFfa@fa@fa@f@fa@f@f@faFaFaFf@aFaFa@aFaF  0 3Œ0 3Œ0#3 0#3 0 3 0Q@fa@f@fa@f@f@ff@f@ff@f@f@f@f@aFfaFfa@fa@fa@faFffaFfffa@f@f@ff@f@fa@aFaFa@faFfaFfa@fa@fa@faFffaFfffa@f@f@ff@f@f@f@f@aFfaFfa@fa@fa@faFffaFfffa@f@f@ff@f@ff@f@f@3V[/N)/'s~3!|3Œ0 'saK^Qo Cf9Vs3VؚL!sraGujm0"s5,DPs)DhbQ;s)9X_OT3aJ\0# 3Eҟ3X6R5dP @G΄RTҡux+őD1Ufa'%I{gĝ%5>"̅NNDa7IR=w[IMfa*&I?E+I{[Xj<8 EFԿ^_$Ia0_9᩿KtE)rb 3U /FlM'P\=w&xF_OYƖ5 >5}Y+3[5o(QBa.3ơ|N} ;Fa_@׸.|y W[Q ?Bܡ8+zԟE< <֨Ƒ|y}JFaE0 cG-_Adۚ54~C޳n,fZ_S܍no˻[e]ZԪcD k7Wyך@aD8Iu4zC38vOD |Y*B׉3 KFe-t=Ʃyͯb|_ }WJ4δ >dquYfZU>RCg@PYScxz:޴fߗ.U=Fcj]t$1`RgC*s]xenŒ=|YfWTtiFZ"?{?~nп|Ma?1^2^*ƑW&,4 AWԯؽ◺2"36eZx]r9@Y}sQ9 nnˍ|}zUVtɀIq{W:3JYgmEGn78y__x3Kꗅ*%2yHxqq|wɝ!0CFeUx39㛸*@+{Qz@tľP= k@q}>@xQ#w=I|.Ѭ34(olė%}} %8n7g%'0CC-_QgI$} bPGl 0 a{z8p*EG$jwo%"0Cέ0J ?^Dp3[죵=h m$cS;Eߙ_49*6 RyIܗA_{ ^2_]IDfIҋ^W~^٪Q ΙI7і67Tc-5-4;(*b 3W={堢1jX^Ѕ*+/dIr^#ޮzaW%i 3}k}_ [ ;o*23"c^z/b fgK ڄ$mTN*a3HfJһDf 5ԧa۰ @L_In/H"3$X8NR @W%]FKj51|I[1dfrMM]DYf]ҟlv)i ~a]s $]Ha"IC|դ$i2_̔{r_iZ@ac}[Ik^$#70 P$%0C1QnYH ~ⓢޒ"i}֪u|O H򧆨-nK`I_^%=0%]0uԚ _( ?$ic0u?.I 36.Iz 7tAUn'I@!.IgemS3*JjmC~dfhoJm7K,r3?X7t2ir8IݟmOz#@咚,j/Ԃf9m%i/.l9JR3_+I+ID <_%@IEK23ϛJ]-g f-$i&|*Iw @!+M%'O04<#}pA\ EI-LR O[I:$=C2aM\I IЭGR)rMt8LR% fm$lfLI ̐3l&ׂ}R$ f&Izv3$m,I-V-@_, 4dƋH ̐#>m,H m~9ƒ&!0C*ioɒ6,#_04m//2TF 9a$]~D%$ f.I,n"i$)r;K 4uM83@o:1GK$f#%iR y @!O/I1$iIʍ%u Hc$ fᏝ%uMs:Iڛ xIfq DI<'I/@!|P$ip`[?6@?v?Y ̐m:H4w$%m04%y5h$}Bba$ P{H$fܳvI~j/[KHfav-@-~Gn's0~;\Yyf+H ̐Mg䮒ʲ0w̕e-%]Dna,nj4 k!Nُ$fGKj<7`(i?H |sI Y-I:=h&I=@rmKҎEzyyZ ׿Hv͐ ̐%Kk3 $I3|ذ݊3IkHڗ C~Ưw?*Io!@!+\۝S1Iz  ;HL?%"C0C6XLҡlH*!0t?vF_#@! ,$%r3@)Im?t 92+t~@Β#0﷐ӯHR23d\9{$i:i 7~mf$K0CUl!x@!|m@I[BaR nnwI$ rIEs۾O$iy2˙~]>U~ϗ ̐_tcIGHڝG e^I}݅J҇fs—XfW݅oR 3@Y\ qoIH ̐AI*K2a6'Hj,$r3dwOIG6a27tg?K:d c$=n Ԙg eJ[r&ߐ-@!CDRL\' Y"In#ICI ̐!NT~tbIMP@6soْ6| Fhl 2 3@!I#E%"a0CF(ъPI͗R@GGI6񾒶 1I6?) YyI-M}_ e0C寒v5Ozs* Ybv i$Kas$=/ * Yb$M HcWHL,PR 6*'0dJui$DfB8IO6΃|Œ0_'IOwJ\҆0ԏwm!$ 6i[@+@ެ/Ԫ,4f,0R^ Pl%CI_}:RҖ?[@2ΚVjj!20ԃ,yEƐ\@2PIEC$mI\"I/[/df cEn!w3@y׭f,OREkvZGfoIM_of2HҹAktIz!uuI{SƑ`@2J7IdbIm P7#iK],if $]vO P';kHR 3@XxGԛ"uử$G~vs c$ĖK20ԁZvyIDa i@aSIB }4tDv_ZOap6XCf!y۽$i2i 3Tl&K@I" ./H%ۿ{J2 3@f8_RѬ?JfXm>Oa%҈0ؼ_wmnړi@2AI; nIڃ[f(k%$KҫfA܁%y0)>17Œ0OҦeAL 3@i,|坒a? to~L %5LaHOI0I& >m-cFX Hҳo[J:aN\(I˔py oZJ:|+f@ϛ-$ +Ia}^,`v9@Ar_ϔIͿfD̐3 'Kڰ,x|R tNK @_(^/j"tc;5NO =tku{M s&IՌ0Hm Ia9=7O=%%@8_^.#if@TIg3J0xe3I I0œ7ttM &=N0xpf %m<f\*iy7#<,I 3@\^ %i, sLoFXc3@#I+ sI f8"I hi$a0_&IqF~SIg3@m7dNWIa95n!{~Kڰ3@jq$Y#8'f[R9#,m*a&y8PtK G%|o PZ.)Lf@S`._g$^aIcZf@3VCf~E?v'f@>$i*z0D3J. GҾ3 I/hf>'+z0D*DRc sfHKG P f|CR sb%ժ~Fq PF'HK3 $ݚ3IM23":Jx%qcgI!0'bƒGḦ0$I#Cee=4a9H*z'g%m=3# PYYYYv@TVVn3 ޼.IFXHf+%i2qMEa< `F8Bkfʥd5n+' $BfJ#̌3@eee?I?!a+I"0 QdL3@eےt*qV@aa_3“:3# XfkDI*0%ap$D~3If@]J*aBm%{.3 ̵9_* %Ĉ0Cs$H GOa rf(lj.P[DE3 5X^R/ hB˙f(lzKj9qeNAa8IfaBUI:8df@cO'l.i_ jBWT(iA~s3)F#{4LE$Yby9Wȭ0U$[IE JD$M 0_JΡ}M]Bo.{&ȥΤ:&Q_=_8*dIy9ћN@:ۇ_x(WU4r*̿.i2Ւ.cbDp/!%i/V0&Ij<:{aߴ$i|6$\_HŖ,IE$Yp 7pCsIR-ˊ±=H2>Ur Œ߂l BE zxJ&ZbLsC!SsK9LF#G}%)(EVu;V˶]Gɥ0j,:&$8 P o#i"`)-a82sCNԜ$mXCd4b80L9`IJI(\,2*&!u=%5|Pe#Ic tqHG$ sX!}a;34/P22Xze>sВWqѯ'IM$isι=$5Ss$]lPYY[ 3?EnXABZl&Ce)?ɹLF#B%3f̘g=b3|%)(E$Ru䣒;:aI\lPYYO48jyV,vnGnϣ,zVtu82_BgMפY*^ګݎ?1żѣo)I) ČC<ӉF6'䫰 qxﻳB;uwa[<Nv;w|$ovTyoD(wsnm1U_Q6޺$(I8\{II%Y\ǵ~~#5q4ROSg8}G=zO%5em%& 3ZH:8%u 0B;9w>3 6>C䮩_rB+NnEI.`81SեrgHL}b!׿q6_Qo7pOjM4oݴz!Voxj⹽ۻWצKRѩXc|$(k'9N{3ŭ_o~RY*LL!a&ԹK 0OM}5Uy^ҫz&3 >o" uC dȗgm[G#a2ɕ0T>\fN#3?%lmsisx4z:߾~x^ i{SJueGZ00#35mjHĄ?xJ*sg?npFت%L7샑mg^4q)WzOM]I$ Np{8H1=9 ~DIE  yx_I[TtIfUO MHjoթOU=7^ڄx#~{PdöFw@:3Ax!^FNj491;]uoQ57kqv~k7~%[[fYT]}[- o = o7){J)wz[K҉JxN<$,𒃒6fV=H6:eDm㏛.˙q3c0C!0Nn'i$ 0WJrW9 ־"iӦM6-|Xg6rJ5U+ܮJ峮otng7~1mڴM 3=3'KB̹KךmNȒ#zwٹv_6j,56|zЋG|sdo$#IJԬYaɥ-2Z-$(uɻo)VSz״ ]2^K^O}lZV&F~kV>*RO_M$Q\"2@!n+I{dT䫛SiCW: Ko3'I£V9\ELnbխOsT͟ϫOf3?]s_4h$o'/3t]1)8;NDܹovRhE? hYޙZ1asז{/RY",RD,)DHʾCV$$ڷJ{99,s=̜O9gygy:4kpmcnlTaK۾I}}W̼k+>\uit5b>}>qˣ` d +r1AYxNL|60p_냦&etSn]:svSƟ賱T531cʁ@qWh8ƟGFW5Gv㻹74j?K>WB袎3RIa/,~N֫~żATa9cY+Z[8wNG#n^UCsDv>F.7Y-wog6~5T.Zfn-5l\sD> z/b:puEs\*)ejlXlfa`N["WaQoxf~4 42,#7e[Rul|u3W7dGQ/AYx H2q5 !/}SfalgRo3{>{u"cd'C'\`G ;3Aꪫôc9u %~٘J wYw-b%7#U:$^1ɴ-mϞSiJ^޾xtk捍?K\ ,IZ8HƪJ0B;o 95̴bkvUzcTk8ۄa#snȠ1':|>e"ndGů]V/ce^Ӄ]œcZEٍ#eZmi1EGc?^I?0 8I08r ҡ\T\:|UhoUn,cku[my_5aݝ_mUkVk (l^Ə 2 W;a~0~5>/rjkmTaœGp|iq+mcm|O}Ka~u. ktadA0@:ecB ^V J5#sK%O+ڰ_/{}/? LqM, R5GdmLJΖqDŽ,sq; eE*)eY;0C-]>fQ<輵nMg}]Bsl|-\,LRhU{WHfIzE@ZfӺ, X@"80s5Xn_3+ތa6טc-5l\sDkDMΖ#l:ym%޺S3mv0-. <9'>bFH^Oîc|53iwѧW0 > ,<4ҡ,wa9tus O|P"0wwo_}}=C'2-].|?j vk}u &8:|>陋]g/:.٭ЉqWa,“^`q?|D?Utcˣ<LH !dؾx(Uҥ`0Y &V=tjJt)9hX3Xq/o+q .Bt5l\sD.* \yEBu.Q2=hW>._%ՙ!=D_Zo ]*,0~?=|8d԰F `yO~n!yg' #ExN:0 r/t(g5]|"A9*fz`)_k&3'-l` (ڄiO4a^qs{jľWhVр ws`~0 Yu1~760X?eyA ]Nqp6.k??!8ý1_C_it57PB >YSJf |pht 2k 2cAcF5 4|vͶ[X.xq>ze®la_s|ߴ-Z\G~7f0G[TO Xk{jľW5I&MtS`}>߄H}E,L,cEVI.Vp>ggNr=_f||ǘm}U6}BorIJ '@()d&8_:@\d̈́ U g'3k.grV9VCzd0l[ԙ;<)eߚ_>䮉ctPd X+\>}fmjziV5G";n[u΋v4/ Fcعl8b%Ÿ)y׾W4Kxbk^UoK#8oT3=yfw{OEJL>Jü"~T = G{[]dQ4$g+ b*ZUۚ,־_KPr {[K=aG箠#Vx€ iS ;.EsQ y_H(ako*:6cWa 3 q6Ts5D4϶9T3V?Jf%^K:^@}'i/5{$>WZL} L/̐ k~=լhﶠQհu͑pRTnEt^W1Bzit4PI1/k}O*r~Fwt#U}ìRxIa~tX؇P#zyg#yշoP.zhXl#db(?_< J+7mQH e~c6580K޾>Kͬ{ŝcꐏGgzϷuoT5]s^R3I_FJlL#nU.]WR犠nזϕȕGH.^60y['Z3o`q?[٭K͊CG41&V~sc0\p@ ,!8 =ü,+l-r'=?EoG5]w!Vfp: N)2U^~% D=3[q}>UcYca_ՏT{%I"grɕR8|%٩o{ i^-9U dĨUKxWr)3dn~"ՈY^湕>uӫRgw}lVFIf#'Oٚޡ`g?]W:[;{m~WF[s,+Sq\dkwBєu߿FXלʩs }_jY+wy OHƷqev>Bn?+SgXo@-AYx@O!>tZvaBD J>+yj Ǚ@[- kE ,<KC0YY/qk蚈,[5LcRfrWGn ,<%D hωFk>Qve+˧a'W*$$i` sa/m2U ,-[ Ϛ;^(g% (Ü|?OeDEZa{ ߟ.Uy^jyۼ 0[:0 p Y ,guYəeXt.%_[)AoPA>} p?'Ix^0 ?Ǘr2 tpQTK 7 ,\O W7s|y` ^l>&.׻o/UyP*6WSjf>)}2Bx[,wFotk)a^XTt*2n?ο"LTYĉ'NTO&^?t/Vj8LS|/%sAYOJxqa"͉a0LԜ&dP8`H̓W2Bخ^j~xB:0 7sg!laBx0X {8h^dY >d^0̛[^f:!5a|tHNaBx0\lt 2µ(@O2BG:P`/|#dKhH d7V/Q\/m}ta.!Q dn Ef!dc74^f p'inذ0XYn\K+–_>0\:0 Wr1W:$%2BW]v)+6JfBΑ dMe` ͆L $ K:0 r$P*,aB0UT|2u ptH(+*W0 !\kpy9 ,ƶ&@"\TZ-,patEr(dtH0Kskd.5̓lR4/7>2],Ks>^YJU by)l/d8 Ț/Y)[}\Yr (ǃ~2M||gihR_f! #F(DžRa`Z ~0 !g/[<>rWJf_:$3Z[dn3̓Sk*Kf6Z+zr!#E9Lea.aPE1E:0 p=!I MY*ü>K ! ,\ŸCKjB 2e7ON2*FOf! c4/| 0U:0 W0 `tHaB0\AAY=|"taB0 U6ϥ p<&ɇ0 !\bV2R7} p>k4,-NDf!dfpbw]:0 3`tH.LaB0:`BwTD:0 kptH62BoSN5RY8^@?Cy` >+²`ta]C)8PYxV&Piv8]:0 ' PoH>/'9rf!dKo2^UN?L2ܟfi.,pa^6q otaem5`ݦ)YdN6u8W!;tae(tH e6{N8jBv"/ٿBYYʬB#,parvBy[ ,Jw otH;0 !k'M:AY8n)c@S50 !\*F&u [:0 GDK7u>2Bg/*`p6# p-Hr1_YD[-[e@ p +!l aB80`"u23 G:0 rtH)_d3[[:)4%d㘛\ Rƪ2B'Eq:9|ta0jbn0 !fhRQ:Yt 2iL[:uIwa黿sHa/ IcAY8-iMRM Sn} ~xL 7T<zIf,nxK:Ua5*DFMS2E!J{':nZ`/byJ߈P:0 'ptp3N0`^D$J&m:sQνU0C}\.wlתi:*然X\֚AY8~@d?U2Qh-k7j#{s 3Cjjy&S{lKk`@zDzn'vPOŜTAY8HG-!"6_K>g@]:jdQ&k'{vcWc4 ,p7 $!E/vXSSNon}\lԎm,ZBt "N \,dEyH :/V1b."a/rm 촮On'ZՇcWiu x*0L:0Tp8@!k26'nZis>vqb-I<ź1,VNJ7e$^:03 `tp? yRy4O.q+<ѸbK #rUI1JfZ~KhdB Xʸ^(w֛ha1eVkf [)S@`o-(,R˱@0Y:XlۏdLjVMy,[s]>SEH{_!c)v@+ <{oa)g:H:J|D~Rg^^SHD[3oSw3@ =NN20Hc8iftzjA3̺bb{ 4fWx#׏$,;=18?kbu#x@eE +š)[~AxGs_θ1r\D4Ok6mn(zHf2VU"NU4`St^6Wi1y2ek_9-l~W="{px+˦ʽsލCx { ,R@02"&D<_MWFI{pm?wsW("ii}"oSZ5,AYZy4%dE:.btXUf:چ^Zk8ꂆM>D-sŝ]RJ'Nt߫]r^Su_,dEd(}yt#"^-cTD͝9asb')XoJUl? w98P20d9W8͓E#"Ǿ%&rpeF 4o}khcUxf[ʹ@w H.$k*]:HLw:lw5=]_ VEv7-zu]:tsPQיdy3yMՁ^*Qt36AjcV-nh&9WxޱkU(玑04{]"Cs_u$ȵT\Aש< d"dE2\hf 7eHin8gm{гAE^k7z֯QT,{@kr _ B ,(+ذGV0>0\ìFɚϚzR=:w׈j䝢+R+:_Cϊf4PqtacqDW-W: wLwu} GG.x5`^;nW bUYUQ:0Y$\šP0˂(^lE9kC'X͵9YU?wjٜ*dE`tp W\St.`jSg~2,^,ꈉZӭk忂檜ts^·  ,@5\vd]󱒝O ͢/_Ewn yeA7}N2S9^@KaIk gq P]S=6\twႲm3Vx7˵m25ܠWR~_NU`taɉ׵zDuKsk\s?M1k0yQ,<{_=WꮍLc;+T daI O8wôHsƯFYo{yfgcӭ_\!;ǨJd HdKwG+ G: 4s6:{WP0Y{66;g"Z3_/̇U.aW# ,@%eTW60=(iEw%^ar!tcý/dڌ8#j5d)dEy`tp?gzuaaL\-(Lkכy z,mKX͝t OKfhv+{8ĊKtA,:(p һmb- :ʚnJ/kЈXW1 dEy>~qELqtIi_搵6o.'~FqnRsZ'˞=%JMl6 ,˚!FNItV 5l@Jԭj͝-okc"Op&@'etzz aeou%9b0FpeOV k}CS2>2e`gXoFWpfi6xF:0DC&ptp'=VHtf Xăh2xÂ@RLvts=\l 2"tKw2KI4 NK-t{,xuS>o9Q"Jm",k895W h4tA|ՐJdn-%D|X\je\s`o.f]e ,j3I1sk:Knh&9Wvhy9@M"^k M(ШFz5\TSZKf }0.KtVv?Tݐ8-#l[Ixޕ-f.5wII{&pta {yd:#Y 1OW,{xEBėmkfC>i?Gޔ/ttaqgK¹ނOwtXz!Gޭ%F锫 TGBĝ_nI77|a+{Γ9 gN yX0"mq椗 ߩsrk|)R{Fp{% 7K*K=U:Lmbhq([ɴ=hi I8OAYęӁ쟥x`N&[%OGwLllj@X[Cތnn{#9pta+0~/ 6 W:(.7?f 1g@=%ݟ]ѱ^Kj>#P&('uVIdG[u~Ѫbe.0F:01"QDJ\W];n7:/Qn%ĦϯgM77dܨb1M:0x(+8 K4I1Sa)haHNqC(vܡ7UxIf/zKﰱ*pviTpa MP{|XWPB$/;mD@YĉFI/qm(\:0Hc h搵#^:eQ,7~1&QŇӥ {kX\`sag1G|+1ȕ#CY4x`F+fl*bH ,g;oaR՟,-@'W{Xg/y)^+dEXW8H6c (qFigYPh^B$]W~zZQQOAs& f%Kq9P1Hd(/ϽU N]bğN|< %޸%,8s:i~HfQndX (]0ʌ6`ߓ'"i|a c%\a㾓N.g^AY@e X yyJ8O0l9#1kix8“M>%H? M w5Á|02 `t fta8GMC5>)l=}{u[os-ewHfQ>4UOr.PWP:RCC_IDr!M! ,6 G)DIJ)ȉj3haM7wcK:29 ,ʽ. ThtcPcTUJ4d6PevtsFV9qA200ԂedSYKx)FPuC~IVA!9vv%ovaK - . fJfQveIQ2`( 5SZ$=]^ d~4;}YtsVCatae`U[(FXz9vVMwJU+eӝzu/i+{]cg?JfQV^K:xt@mLlk>wLb$a4]ϯh-9G߫Jfus (#5Z^!L:'4eajCƎERptH_66F)!=yJ%4}=;@ ,r>a(g!dGיd66r"s"/ r63li6Oztu6k+ (WgS2")iTJ|S&mIgv&F߬O1,A) T"dEYd$MtAݺ-8Ty!f7͒I .q#'{搆SϯNeQ&0A:020RblØ0YbdUivu(q\mGX2s&}f;a@z VBau}Ruom4t:xG|3/ {T@f@Y$L:/"0Ucf)I^!n|a|钠 {}5\{nq "dEiٴ7&i00>Z?Q٢jEj9a'?{[6@5 ' {WūJ),J53s GL#Lj< oN^GTPi+6R$&< px+kޏEs #dE#8I:0"-p822ǘ4dH=32ZW)S+Ӛn5!L22̢Tru㸦gN:ȼ0S2FYsXJ Gp%HP^v Ⱥ%y+l~Q#k~ϭV=8ՀAYSlÈJh=P29 &/'I'{ۻXe| |yC'׼Fڎ eIpta18_!RGaDf8PAqjC]@; ^ ~?+%(V9iK z*ay6"Lpt38joE46z,]&@݉3\mWpOwiM7wИ5&AxA:0hlk4ӰTt:kw5l є[z3z{25ܠW|D(dE4.Mt'b\=O2 pt!Fz;ٸ3C ,",.J aD| }V睌h@BDfF2]_UϜn-ǒVAYD, ktHI?wY:4Fo]oy@MĶZ%1{׬{Oqy @K0|bI$0?3UKǕwܞoTii'zI|c'R9oF]Ε#C 웽pΖwY]Pjrktaa$È\*N=ĨH]@[5>MvgXlo)\9 h-2" 9J& 4Lګ3:*ڬvTųIwFf]nOJfQYåCY3e3aDf6P9;bIzNfkꡘ:UijNY88T20PD 4e q7yA}Om+xZB~QӮ[߹uܩV=)KfcI0ܒC^CwC!!;o2|wKN7|bwtal t-!gܑ#2z#V9-8Tmo$i}\kZgAw}25\MY3`tIwx^jhNbƅ7G:}y7lM7Gl*ptaV~N%L:/\ h_zQ?u.T[ZY=r1P/t_H쫩2dm5` 0",Gުmcͧ3zZh-QƿS[gSHfa0R:ϤÈȮf@wOij:V<LBy ϪĤ[ɴL>6M ~!aeg~0P:S0"8fgңzll~Ve^pZo3?ATPV:0 =<#2;{4ˍYôWz0;h5} Fc`nU~)ٵ }@+Hf73"l Hqd//<`'ZFuS怴a4iS܏ZK_GOkyL+6 o ,ۛMItZㅒdTZWՒӇ]Ҥu ˚[͝޺lFHf @>"*N/FUUm9-* JZK.g%_=ښn(~2^\0!"O5~./Ď;/4I^//GM0 8*/^?%:gptaN{2a ヴd{FݵH98arT{TA;]ӁF4dӜ!LOCÈƪ..ʫ6A>YWeKn;n}5\ mNg9xQB99 ![:d/vCHcDbkըӓ@GVaNgkT"5Fdr]sYji@GdN;|*:a h։,y}' U2=0t#2*\x+ڬ,4XmqT1MK,;&9in c sptP:(\TtV1*$r<p5R'o\PߚnnnkM| +FdomU4J {w߿繁n`8A/’ʺgְ^?MiRdӔ=ҶJa%-V"=7Єw!Tsts=Kts5S0'O"XP: Tq ́Rʼn,=\MUlXDk}.~&Sh'+RE,B4,yzUf9ruGzPڼ9i~"v'\4DY1g\h .T9_z-=.o>V,̍h d?ALBĝ8nԖ"̒a2BYYf!d 2B0 ffff!daBY0 !, 2BYff!, aBYYx0#|tu10WB7̽H.W7jA,MaYyU܉:a aaaaBYf!,,,, 2BYYYYf!da2B0 !, aBYY0 !,daa2B0 f!de 2BY!,de aB0 ff!,deaBY0000 !, aaaaBYf!,,daBYf!, aBY0 !,,da2B00 f!d BY0 !,d2BYY0 f! aa2222B0 !,deeeaBY0000 !, 2BYf!da2B00 f!d 22BYf!, aBY0 !d 2BY!,de aaBYf!,,,, 2BYYYYf!d aBYf!d 22BYf!, aBY0 !,,da2Bf!, aB0 ff!,d2BYY0000 !,C s7N1 Ց Z;J\ì'8V;0T;vaH>^90{D5̊{"cs LcZG;0 ֑c Z[JTì':V;0T;Na͝Ш|.ڗ hzeF=4m :%ry]SG0k*Q PaWeS/7'Nx/>K')ڷ7tsu&K󺦎Ra=Uf=X;syz"N!̍I??6f̣~O :ravC+To܈bCە fG k!醹|Z酱oxǁveg1qvȱUS%ravYܛtfX68-+V;]90ϑC2G9T-$0h72~[[շ/:zU8c{ȱUS%ravYB8rv;/+V;]90ΑCTfB e Y Gqp ^*Ws  qk90{DN5.{ s gej'+f9?EdԨf7N_Ɛegp0Wycɠuǂ0:ravS+Tk枎ˊՎnW53~h }'NSÜUBׂ0\ZG6.j*s ^|bەs Leuxdo݀<.Qx- st|e0f=,Ü>*s~?=BE~偹?0000XYejt1C͝g0{0׿+휋݋{Uef/>»ǩy[mdH*.^pX%ڳlG3R#G7y*6ug0{{D)6hņL[:sңS?TmDŕ3yiW)6^3w'n3U 1{3[Ɉ *j-!L}~AY쯋#Fde6[%~U]fȑzސ \T ]YG5i*QJ WZDtl#:~pJiXMay0\g_AX-*;wf4;[üoрū<ws}v!p"aǁu.߾?~sFmn3WN%eoZP#G7yCpAHUQJ WZJJ0ǎN5GlAۉ8W\K.iW43fGޙުD[\>km M0/̃!V/0C4-qp [~ $?7yo;vJ/nIƘ’ ?AxfHݺRi=Vf9Btz&7c,GlG,in)9Qke;(+c%JaNkFYaN娑-]ѮRhsg779X-$0w{a^[jժUa 7#/!L}hһs>@Eܪzիg~Z|N $o9x֮{i@)Q`YvsvWk7hfg~F=oP.P;(ņc%JaHnG큛2r?l5YtqEb}XvZ;3a;c\e_U\| }A߇Uࡠ/)i%447L`nC~mIŧ|F=ov;Rj==VTfϴi"GQ~_4bznۉE:g<\kb+U* gyLB" s C bnsN_Q*a (+!kRyktA MDŽ4OD<pl_~p[oKQ* WZJBQlY8t1㋏6-ׁK vb@̧bxjWfܙK 2dHYlwZHa?r#@׸0B\bnn1!vNotp@ %2a`5Go XG4^i+Q wZDYNKq|ӻ)VS,<(lxs>ΪbU LIw?3=V \;0eX/0;j#/^cË7 բy7g%)hƦknx~pGoXGNXc%ro1!)7O17L9úׇނb[o~jǷ+,;ӾavƝZHa~>tY07>ZaodtYK4ώ;ͳ=kU4ͪEQ} ?d;A؁uV90E0FBdž Kň!:iXv;ӶavȝZHaL<4v:Ew̭{3̸-:yxмq}\v}mG{Q \Q^= ?"jkr43[qoXpop~R|f˽-Ws̢˕Y0`/ ߳΅_\3~) IQ[ {tNZ̭laW>֑7>+ݖя Wf`ʬYd0ߕ}|p;黟̯3'xxfF'ߣovKme~5,(`.(E}1Ϳl<[؟=lesu*`•9`ҕYNKƱwM~ĿmmKևcB˒ ]g]>zɶ?mقeeߣ#`/2,"[`S3rk/3[m\\ӻdw0ʬe~$~F oyrx=gON)gonX^ssXw{7fG6y[& IIx(`.(/}׳cﶤ^ {o W渃yXWf/ #s˲ρqP{ 5 L]afDEقe݇gmc{ޖIxeXQ\Q^=2?"pk}_"gH^[9]^4M-_V4Qљm\\=`ҕ9`ڕY 9u2}g^bŊ+->tkw{g'&&w4 &9K${_ ?o/_:r򛆯ldMl/ZYRmpltttmh[h䔇6os&'G6yvmץџ؂:{W0WgDspxĹrgw&oas̼`ʬe $cdhW?$IKˊlo]F;ozKe^]We+j^9:Sj˦OqG6y;MmE̕ݣȂ:^n0wR?FYdf˿-㞫29+RAsssڮ-x`FZ6|g~Zچ?s{m 壭;b3jޔՅ9w0 &sc0Wcw {3Zsoٺ:z\+`ҕY=S뿀 b=.~o&]#7|qW7Q۴CwΖ3?ԲC+6 mm'.9,+4˻GQs>9-?ߖ/4u fsusRWf<+R]{v<0m^.ָGߘҰ~vC k|s[xxQո+|ms$|Хϥ8GqsFy(`ԼO0l\tߖPhf!s`ΕYtGMuG <}"ti&vcOu_wyn/$I2UGվ;9^ginCw=⏜mO»x /@D} 2QD\y`NwRo)4u fsusjE2`ʕYDs͛+ /u{O?E?}u3Ws=i־v##Nj]E]x}/:g΂]}r駏>3/w}8Q\Q^= <"g|'uxC:ҹzʌʬe0 3j013L`̂Y0``̂Y0``̂Y0`  3f3f``,  33f`F0,f 3Y0 f 3Y0 f 3Y0#A0``,  33`F0`F0  f`F0#`f,3ff,3ff,3f  A0`F0`ff̂  Y0#A0#``3Y0#̂3f`̂3f`̂3f`F0`  Y0#A0#A0 f3f3f``33f`F0,̂Y0 f ̂Y0 f ̂Y0 f A0#A0``,  33`F0`F0  f`F0#3ff,3ff,3ff` 3`F0`F0`ff̂  f3f3 ̂`3Y0#` `̳5*v `ÂX@A(Mz~redww\.߼gg>mfA"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$D"H$Mt+& qjw¨qn`v R=!~b6'R)Mhzs WQ /we/ùvnQB'9lV]#_,Fzf3dGg?mr48I2> E;MH7+)R&N}pHZRNK Gr&c^1c/!Is3?Qv34bP !pߘqԪ]W7\CrbBwL #lw.+eSîZ`JJ+]ߚٻ ݞ[NJI)986+38^NJa< #'4q]WCT \+>J,!m F @d4W⿜ҢJ 9-c:'tAv$1ӏi8m8=ZMmkoct+Cvy'_3o!j b>6u2>~ 홗#C"fk>kBc6~cR"WKf$ K_a ߍ|&p>c sZI G2i$D,IP )lTSԋd0[9[uXYLQB;\eӃ[Fp]wl. I!vt+dA:X0aˆQ nܸpJP!r8!ʩ82"1e~9_q5I-v=37+(\h9A3Зo+jA˒Dw.A>7QqY7QMYlXxķvl>u}!_sCyO [X)\b;nq<Z4Vq7SuOXݢC9<@[c(=d+t)dZ<ȧr*bÆ .\#&̘`!DH& hK: ē Ua`bcƳ[gߟa_#CA572FŤtI2gXN[^~&2D20Mt4.e4[PPV&z,;59]h-Gw>T:x.be\1$j `O)f1KFRDۨЃlJ"Dsx=;x^-mٯ&%d3C#hD 2\^3iB[a.q-r f3]bq) FfI/[Nbxb+DЙ1,$) { w^_-y1 !kj$g-FL/95s0U(my7ptmFR" f%{[) h/FSIR Lf.5([4~5+HFFx:M; uи*v(_dfenDLHg̷ё{9+#2 /b.׆#}lg#kY~0k_KH7P#g,b8H@ \ȊF:w"2 ub8A$r K4SR.387D2l:-e~9f& 5 {CI!5}ewDl!HA=y yLoK$U)7F{FBcbWdj|.c С"yΙ(kZe&d9D=8fmi*\([3E- ilb rFD (&糀Ku~T7T?qy0'x~ 2.(@7&Ac>'OM/ [}WDŽXD3T}νa-?経MA0ǯAw٨kKFVf9E~]l|3/렊"R3.R9^a;_| ìݸQpyMN{ 'TKhߊ"=oX43k@- ۜ$W1\|r U;w=^Q=&.Y̗((x=572qM^LO#l]-exb:*Mک#RDGm8tOל8gpjQx~ƅYz]"_bN*UXA \)Oj2YBWANf2-1rYr^rN:nHmb^!8zd~c/E^3N@wvўSSo}F99D &l䳖Oxq<{'7$M!41tF!3y}kzj]tfHjJNo1UMXQX>&,'j?F ϣW Y'Y5Ȕ-75;FܽМ0ۏ66Z, 9f_ۘ@:Ё~7Y/(CYN?|:AB0ج X֬5?jFTZ=>nr6:A]H6~Q9jFH0} ЖPPX^sBs59';y<" ;Xýa: 2oexP^vCt N?{a~/md_謰=Q/4:IRYd2kmoPOcC7z"J[~_d?a_3Xw_Qa|c'^;s[يk?UiDҦb`=)mmRO*QPXgձwPǰ৊qW( x{ySXe!]6& f GiN={7W'¾Ub_O5bnPKAydoiFr>qad& %j]݆2'|ߌ ~O@Oi&`GP/@"sb0s+1/I>K0TJ4:\ @gf1FVKҀAǼ3}%v5t>S]|. jZx1ўK .!7y,{S6>1媟wٙ+rHǚOe8+tWy-৊VswolFғ`gfrJ/@Wm7 <IG>fUoqJli$~~R ϑ8z2%JoÉ|߸3je:?vZpOoco4j(=5^ldjd27'|^g_rCÐL} uR!y)"ϝJWTf1t#>7i7*Z0뜿ii:N>D:w+5VN c><xTd+#H&i4PoJ5N MߢI ډ~k:ikA3F8Qp1^TcW% ˆl(6~JCofUq?(vf8+3FitJJf.$K jQ퉍x#㏀L#oOT\dâyǝ-(Lܡyd 4.F0fb((l+PP!v(ѼNYrҁ׹YGקW y>C6* on͔T͸%rϲݥvxb/™TZu y&ྼu,gNӘ~`(Gsɧ#wD0 Y2`f>-=Yu a U()-4hfײ&xc7o\Y.ӑh -g6h{6{*nfAB7"ŃG&#p\C52gG,I |UpS5nV1gU7M%o]|DK $Ha> \'O\yTm5'?q]/@U',zd r 2C^`1K IsU8GRy j!O<҆tRI"8,1 #W;p`N V(/xF ԅq`3PLp^u Zj Ou0[u zOXuc;Ct5䫀@mk|&,I&t$t,Da"*$K 'N)B)J! K1Gf'1$ŕaVB/S1ГWS|K-?sNS5a!ol@m*|qt\F߳jٴiŅrvLzNmPͨfN/u&v`΅5yΑ61ɕ:Ac~ { zďL`Q@wHnoF33 x8EةjQxY(Ċ?Fc&G'0K,b` BoFs-m'F_*Ь_H;[/2A:y"C8߸4,f=#Cȿu_17ZSf2hMtdЃY:wR+r( *Rn̨2` O"BmȢ-I'xMNS,Q66R~!s09TMdOrͣ+-E7T8 ~Vg0O5,cݐaXl܏tȵZ*-1߬G(x(q8Bb> !n0U=/4g12B, F` Io!Ƅ߉:gϫ+2J)jjXL )1~J7"RN' oFZMLL㐷Rg۹IgYxB*O7r1@gmty-Lܗx'g:rpW̡,g(Ҩ1ēD:ґv-h_pR@y"䲅Ogp&}*"m/9} `TBY@Z}y/`bY5P2O٧V!K F?%okxM^J y4Sϭ<,V07iJfr'8\Q &'[, EP>nS']i^U?:).ְ"[4+9x5F:cYM׊xLn2Tf~G6Q ɤ+'r"=N*q70aF`,qU@ ј9 tL |K sBcIjU͢Ǝ*zbV38Gɑʭ\g&a/;7q.`R)(bIB4QDItQ8|jVoDqIr*rjNXIӝK][= դ/hYtEp qưA^'kx(?) 0xCylMqb(TEvՅn\-:رc"(" )J؁8RɜĉGz wbSL8>}-.Ss\ gޥ[w в|Hyd9bjmf=&o>3r3/p8u7f's!BbDo/Q}̘5ذQC "pK2s:ғL+wa0RqEPKdVYFOr6q '+>A$Vʨ*Tclذ }ߩntQB7K,,ĉxH$^LJ5䰗 eDvJYEjxs*9\i! oPRF뾆.ėz.z11ۓSx4)QGȭX}Av'_8f (+b7hjT"tOL'tq؀h/4'UTNvR#>ۂY3摤݀n=ԓʕOb'S9k7F*1Mtⅲ(37.v+߭QόY[${9\[pɱD"_Pb:GNّ6x"@G5?3e!>Uky' cR3I$")R( l8#"n& c $HI$J2)$}#v(e[nvQF+Puw& p ͠K(KY&]Gd5p*7o)tPرb*J\bŊ] 0c! q$ImiG&dAQ"MlgZ}dfÍ*b[9r ˹~plALgN^5j7f TñZuEOTR-&_I$dҙ.tiE5\q:M" O p @&CSt3> ^ب<2y~3\ލ2Fu7ifhkC1hÆ)"DdQ)A7;]Dof wk`[D~5|-]b yuV3Y<()2)2ʨ*ljO&a[S={`O`LJNjj*EL"a!B&]EOӕtQa^^ENnJt^\HQ9u7aLCPRH!@"1BBM") |(Jh dҝxٺxFshڑff3Q\v*tRH#Fj5tS+}baBiۆa $HEIC.rC.c,m]d{ WN`?z\fsͅcսX`qPCPɼÎrϣPidA&,EG(bsTS];sMiğYX$(WeRvs"<'i{iDNR]1aE[hKP"%^vXIĀ+bMÕlA4<Í`-( cр9\B@D>~A* AP;# Y%`.lDNBBR$TM|~_R%Q2ܘX+ 2 0 144 1 144 253 1 124 2018:10:17 10:10:23 Pixelmator 3.7.5 fF!QIDATxw|߱gU3VjVQF{Kj֨MզVƪQZY[Q{XiB$Bܑ{cѾ:|/%.qK\%.q۔ԧ.E'@7NaD8W()]aG&M 4KI\I3#L*P$/+⻌X1,,.\~KAsO67AOƳ`5ǟGɼln3TL4D~POR3)KO}ݟ) M{H_]BF3d )O_+ϙDz0[)zЬSU =eaʺ&9R+NxJ$ <,02,eD jS4!:"x%kQ:"IXb&qZ|R%dюOq)ϥ)o1%|Og99 9LPh~Z Z#Xb L}DE:3=\S(B{[$\`3h0IASv-f17|j]?)Rx:N/1}Q+-4 HNb'>1SUzua>~N:+3 =*r15sJSԢ1P~d)9B4SGیxЕxƯTp3Kp.xdؔQ5Sy\ 7FӖx&!(HU:3Y =YE*^DI'?3=,jԳH9&LL,u?) ǞXA?*ݡ4RMjs0LkCMa?5Z{e|>Gv0$'99/&S_'ӞW11Aڊ3F=Z%C%;D*:+KZms3HvDYvbtE^KP]<ڪ~ :Q1 ͪ oe1*f3&F(PAj(Lq@=,󥽁n"h$V~8*Ρs ˊ*g9~v5Fm8衯 46ݓ2~Lkèl9Mho% %jG޾Hr'Ƈ?GZ9UKKcX3D0\aZU,_|ۅ:yMDrKF 0H\.z=d/F4669Jm9$%`a~jԞqQi$Go)FWq6*wi;*j??]8UTL`Pi]I3<g'gl{N5!uB>fEx30[fv%[T};<./-׊TfhUTbsT(_axk luP#`~ /Jyiϱ;fIngO B)GI7 f+0F2 WqSM SCLu0N[472R# lDۭGF"L%c;NJ@6Y@]Q ,j:+Yy8]J]D~ޥP$}O0<)9@2T(Kv#I V'K7Yk;,ELse Ɨn*{5P \0!tR@#z\s`y2VcB>taX8鄰JbFJrI8e~mFy>աxaM13;sFi[Z|Ϙ}Ҡxн,0#׺+?d#iM_~W- f8Q 9?UT9[{ӓP4r.ۡ/;+0a-X0 bⓑNxիme`NtWMkdiJy\!5uQ {v/aVo.H&9'5:+`pӗLNKxD>s%|*CZ.N[ }wݰ;p2*\XVPB-`ӆ^TƮOUOO7vIM%5w7Iȩ 17G׉~=yi,fMؕN5]j,07Khp]_y|ZV9Ib=wetֶks=fgaU!*mHk vZY޻v&)3:q%dazcxmHe.YoÚVWKvz]s[)e FEk#~»o :RW,<5QRі2#VQ;F< C4Is -%Q®w}g&{re4o~k49] ?,[t"΢n4IMi[7z|YF=PNwu _fKHaBVKIOC'64.Yt+j 4*(؂W툯]>L$Ĵ@_1eбY6:g/+ǀ8xȼH&ZHi89I`ۚW[F-5z4[j@-&tcwPe5{;E)sNqsu˱d H;gfM<&2x/\p~Ҽq߰$Yen^}\!эmݛQAde_1NV'[*,_8h{q6_43U,Q\b)ԧ̔Ye/Ct2ΙE3]$rŌњNRdM|Ӗ3A =~c%gV}k;l;&D٣UY4^IzbHSRt/1tf:?R D21\J/=#؆Tl J1E3x,Gol;>ƫ/1AaDifY+d{AJ`'+یq|Dx:&LLnQ'Wate4xS]EdFCI9~eɰ`9MI]ZA|O#֘agkaG3K.;>r*^fc!R,i@:i&[4?1qHb[8{%,00^'`"L柖PK tL-7Y5,B>w*!J~ F$+':Bge&!;qH^eH\v[U|Ci3l, r#Fx+x9VdsIb2_"0}2 [i"G=|I[n>Ή@%JZ " 3jNL`kKRKԑ#Y(8}eF^,U%?s͆p^;uF O ݚ812봱'$a8,W.;*:G!DUMC<:9uK+!vHӔt}p@f&ޒTѐx]C-Sʲ HI5*)§98N @&\\xai';_8٧{{b=I]by660 c᫡ t^UI'x+*1 v;$ 9\RE&n^; 5uib xSXStf*8] hݻ)Ÿ"iIJڰBm,PYX}^zC%]VL{&lLVY4D&a(WD2rt*rQ81 0B &"P[&B #VQ\gHYӜ\54$..OEɜm |޲$.3/·2zGb=  ߨ.2Fbg$=Y1 _I%lf!?_R2%LzRd$#I;Jn)Nyj?0l7+U;0FR@88RDȢ ^^W B Oc஧9饸Ѐ@*J2߹fъ6' t1(BVIOz2 OIf2;Hn+HAvJPa%G""Y'Hk7A23a:q99M0FG5Ll{3B@Zfк(n5,f&B~a8qq@}GdMv36AN SftcXzs\6)z/#y]ple5@oZQ o>R43P|%@5>Y#= =ZnI6Rf4)d 3i$7iP沎ݜ&mDa?*"FK9r`T:.)&!6W@eHZlԕ^ٰJ=ZW,kB+j~fg sW 0I-'<%犋miϸVmLV!yF7~0gQAt9eEiwHJڬV|:*fuřH786vsU0PVDWАj&?yɃ^!/ET 5GѝoLAYIa5#G~٥:w۫$ =(3#Yp*Պ>_G ./ֳ0|EC*S 3i,-p';(OY(Wo"9FɀٲS\{(IiaPe6X~Lw1'+Hӂ/+ NK^ѐ>f; #1O@O߇J+J:t4:^ÂovqG< O(xHO~eN `;҈"'uDRH;&-x.[D>=O{^%RbwieiI}jRr8E(HWj('9HUjQ5}xf5l '9uS/2GJ26T(ɤޗ`k8& Ux%7U?ToJ>ӟ#pA6)NCa%[ 6/ׄr"-ya4;apL(=/$8-܃.H22"-e-85yj@+R4O QU(_IҺō/5uw2=X'iFm$E&$=yc$O'1,<݋c+vm[1—9~y+}MC{SZO .8ǿnee#O/g&?JFҒܡy֜ >3Y!s ,b;/A-bcԤ Yq'9m)B8Q?Y"fES$Yl2Md~縫 =EÄL8Shnru X>Pr{z3)b ]iK#SL%E<ϒdUi ȴ+4mJ}7ӹnq3 ,fBo:ҒT4)D^rŦ D0IG84 xöo"q $lVTF-15(O)-XE{L3 !\նҞ{DWlP1Md沔le 2 5 72 1 72 507 1 507 2017-11-16T12:11:95 Pixelmator 3.7 P(BwIDATxwWǟ=DIQ"⧥)JPNCT)DQJ٣%JDFVPZG=3>?=s>?=A!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!?rP5 BdQ!TG iXH`jӾf.N. KQ[?a҄0!JqOl8_'Dqo(cg8גY)DrPUaOrB$2h(+Eq FZU|WR3]< Y73Rh!tW}ꖿI4w08ƒ\!"7?qR 5̻0㬦3gi=ﮧj٨Vdk"Va!+I#hJumg|?87\|1M4#^bfpEb"xg al%Wx3r3EJ/Jpz}Q]iڳd+"j򞫘nŬ7a ԫY*^[hrL7яޡCtJ&X}HCRì4-?&!-]i97%H_3caJ%9NW1zj zUg LkyTHWekCգIY ekƻ(OQ syohe}D\Opat=(=\՜BqOpEH1srҝ\jn:FD4Ϲ04_v{G%soȓO._SO(\k殝tKG9Ϻ Dz&My#`/#éZص1ELoc{ ro/|d#53IXZ*+[zDrq.E2bI\!懕F SA r01aǝB +_ϗ9z6ڞ|: hCO1u_??oW~k>g3y<Fя49O1 r /OR-,yτ5/#lkT3#Q47Xu vV0 %rBMB׬r?i\w]ʰ>F  w2y|( I;·,Yъ*ITE!]62, 2,hXϙ)ȏs"䗗d,-RhxY p KjuM[?ϩKF7<JВGXMĶYShG9ɫ4r-ADWWmk>L*Ӌ5-̨";:4O'06rI6!;35sf"vҭHtAy˱5p(v?OB9g}+ְa=hO rWR\Lq R\qPk#}df: {}%+&,J?e7^mvX̩)YB9Va=y͸*J6 p];E8gen8l.K,}@_.BS3fJ͚rw>pfj0}A61aA8V*DZҟ,Y2پmI9keLۆEfRfMvJjY͵ _TX(ZP6!} s8wf/Dm~K2&"1M B]eN͞rُFr9cC=F ᝵q':`:y# ?scVRL.~fPd<{(tᲤ1t]Ƌi30qmҨMx=qO&$gws{GLT8g=+}|j`gq13ur/'U8 ~^{nwpI؂\Mpt q}_1EW5 j۸"N~Llx%yht%K=\ XqG:0b㜦c?br.b{fsB[-"k Q;5\ߥID|2'\^FŠb6/$Մ{]ݏL܈y,lRFnVGw/S6bwI*Uëa^?V6T8Ud4qzИX/41,>#J{rڲ(bȄ8[׸Ndlք˃POlp,;kt?nh{UYVϗ)E>'Oƨ2^nI'oq!P}tD٘+ƣcn Ja\rgb&i̋M^B=l8nvqEk'b<tNKuBx#,p'Bd0OS˜N%\@ϟ/ Dwp`1W1x'WƸO-QG';$B&'#f7\-H"vQWM|m~:+(07ǼW߸VO&&)ͽR)+nHüa' MKVm|ۣ˿K^.1E;w;UPs]t͟ݍ+-CW! U=6"a.F,,wv 4LK'"|fļCoK,η} wr1O|=).J8Z'jU,Ȇ"_r0߶3#&ҏ %{FXR-׮HzQV fFuJu]ӅRPnMQi eZYKs)oޠe6qu&ǂW\|7;ްQ/НdrQ2 :&ëH׵}bS(6&9 o YI>1|E5s5s&[Fn@Iɶ ^SpJRn$M4if6&T tϞykpqՋpWy~jnmAc@weE_`7 +KTq gR0a>\Fʼn3 MƱμ3l4 "0\Eeүd"yQegHGVPs^2xݑҰ70\ROkA'H|뾍<zUX lrw Wz>gzX&\gm1;j|&֘'/)iA5o)"fdΛڍQ=Wm)y|99?x7W374H'Caw/zٰ_BO}t1qi;*3tY, aWnvbcΪ,c/_pـK҈$>w3C!'Z;{CJ6J'wƞWѢ)83TWjڋKۨ51ϻV7iD]f1LV'}zN/$75C.7U2З1CZne 1V|Zw8Xge,fhmvIFUnSg! >~etzӇBE2 FEϫr bmaCQ=j1M;#Rpz Ȉl1W1e t9 >-z#eq|ƈ:<(3)Ms#'J'LV:;=Q+:xO3fb,ĝ賞{1/\d|Vk( z"eV5H{[iNZķ;87{ڻT 3nw~M5GXzЍ.fhZ Uƚp$ĴU5ʐc1.]]ì/sDjp (f~E7|ʋ q |g߯<7%܎#iX#5nXʉL/;(&}ڛVR:1gC4{Yh"_²J@[]gtrmѴg"NpcfULrE4Xv,SٹڵUz?D.~{'ʲ5.zx\s? :Vuf&BϞE!h1'CF)k'k-{Ar:|F.O-t=mDegGKQmOU1> !/ΰ[=hI*r|J7Ϲ }CQ8gnrG 7h)K 6w,mfQb * fBO"a_lXCni9?~{eYp𗌲:?EP2~9e^*B@#&$rRILJwk5, -ΗG ׿!g6Bs_zu\@$_Y4H`4;A9Yx\$uϠ>sK? :(6G.tTRyhA[ۮ)7Lɇi_R%hHO=J +gόb a0ax'm '.t&bvrXY "klRL ?7*tݽ`QN~yh}R}w,@Qsn{uXmpYq)1cY ?XB g} 7Ex2 ĚߏNjkjNuyx?r$'LwFn|BS,;~%.'S'|ЇZ*ɿJIR5\tUpϱ[Vv -XꏇjǿҨ85YFYyKyRvBod)2=m'm -i_ƒ٨nJn+mw ?S-bs2tn FSxv8_j}gNI%g'G&;6?NWu]> ! !໸54G+sؘ )1k>#G;m*fåAYIg'#[B^[Od|h|n_Ge ?CSOeP3Y 5tDU 7CAF۪M* }~p>_}2E7eH-a=,K mwbFq^4jBu-u?(mtSG 5>┟?{{6όEXlPQn%뎓By͋\iɮ}!',{Qg&a^ϵڈ|*G(}kbQuT=a7.kCKc`tHopŜ\`9Ygas48h魄_ֽB8G;fd `Iݢ#Л`~UlsNnlz\z^ی-쇝@ HWBq%1֛fFWg7 og9BomȄٷ"^ nr垌>ҽjye $ËG]Փ)\86{N~c_P>U疸Rҷ2@%^x;)ڦh/)+B8U[fshiD|May}oPҊ|K4M, y(LI* 6vE_a"B9*%dx`D p>jS<ڙaESL!_&i̶n'[OD4L0-^-G^_۟Kԇ/“>SsE\dQ8g`}<'zTO;{2'pPK?۟_CЧ!^KyC _`IrVy9Ş,`)@v(7Qђv+a^\zop>4\N/k O(&~,`-2Q7Ͷ*۪D-\Չ{cbtj&6~-r|+f7f똻!Y#3B =- ha^u)@g˶ܥ ?gTP9}y3jtd?2,fl ?LC>Ssɐa˺) )VT/GkᎽ В~ Lzv_~ !%]{۟Ka)DvŬ;ސo</$g ~F7%\)Mynn9-iF ҐԢ(M1Ύr ^l[blsT}l돟IK0goBX;N{zl]Tĭgٹ4#l`gw;; ѝۨe!y}D6QXkЛa똛M*׽!.d˵ޤ(gx_Rqư/HSg2kkxGTଘ=K;,+u1K ;*8zN40= nnvhY!\>VPY_\TKigoi_lbhG(:Zgh:R-ZZRлIj2Ʒ3ON$^HA.ab<BɯhS#ђ(%8z `ģa 3MmFt,nD<h`e=rTuݤrp?{|c !Mbiců4$7φ܃J1a!\94d8oxx\BI@צeKh. -r3ΰV pgD.Wˣ;"Bez07J9'hG9UR,lHne*){1wbk}#b["2Z<8;dZa2?*lf-+xY+,d>BxldOW+s_IUWYR*/{evTuuMBPښ5.YzG1Ƒ϶F\FǙWv [>C,gDgq#)|r5>GQ1; j~b7{EWA.K̚>y|J9rj8.cuG>͌gъY%B|,Fp77S6I:S(DyӉQb?CshJxtOƃdpGޱC[^\KW ,׋+2~R5ҏFf1\P&l27.L[xڶ X~4 RfxH[Fw x% ͇9n`ߥ, ByWtm Lc.J\#XSAޠ%[?Kcqe9E)1"BƤOg2§0j;f餸3b66<{Vѐ?!J'd/'ᭌJ(.;Sg@{q%r-N8&+xd"E [QZWGk,[[kTrEDԙ-E39kz/be?+O~ +lհdXr ĵ?s 42"Ԣ;O23~4)<Ʃ=B/K. sӵދBLyEQEW1P<7"P`050W5 "׹YH'fKƂ~=s\ΰS L.=s;*v8v#!ᱝPMAP'>s%4ua Z1u>MVџ*SM--Z\CE.b.< S;΢PUAn:ҋ!<Ӽ[+7s52W2mlg"NR+36ǚL{8*::nПj6{漿wlI}l6 ^}J 6<%xJo73iG=*S[Q#?/bópG̣>';E$}/Ac*ZcI tc,/>bJfø_n*G#Ieg؞2Y? VqG^*g9V*Q>\pE}RﱟpQ}T$<_μ1^Sy6 rNі{CaӘoXˇlc>ekZ§|f6bo0xpГN)uN.H49 %>ЁF;G޷ASD{q/KL ǐ yQ#Ԧ?Q^N~r;3}؞+qNӁ~9^e59ʩܞOv)0z҆\KY 183i]Ar[ jEy~nϤjHjkm:J6 ;W{?Sv,"8Q/Z8{,iFҝԠ){(5te:By/eng;s&ș@YxfIqW=AIZ3mA5gIYQ>#<頌 sk8׳Mm΍k1|j_f*ӈlSiB(Ӷk\ W7ڇyL vÙjTWwr%r"%F7b+x6\zF`v8sKa:݄;K+uJi G(!TNRt3,~ZD݄y %WCQЫ+OKAK'nrXi((֥;Ws B gp!Mkg,3y3$ќ2d[qpQvt̕> vU@M5Z]*m~%.5PH6O -J$~*(ԡ=b6KGVI#8:jY; .^ 7J[G3z6̠/ )z&P\JEQzJ+ѓC c$3L౴(xqa4# ~34f (ɹ@jʅTR>Zn. %.G`Occ'da`'[Y[c:LwZs (K!VQFd"5bW(8j 3ŧ![ 0(#_f̄]Sqn Y3됲Gƾ9Ԧ54O1f+ְ錢QKBSk!bл1WVq1|oZ˞MM. 9J _ ,+?<a{GLuZ.nq7xf7|\͹Ϣ*<> a\;#DVr+|~2#95Glm\oXFK0VOvXLrsR3%`T9E 8:j[m5BIwF 6/^'yYQ6avYctf.4ϧ}&w^EcQ!3ZصT1COea[FaV0i\K2J4y(<-jt 1?VI71WV~ͼJXີlxF#JPvf>'L\Q+9Y2d1ͳLc F1< j1ьQ&3\^ug5Ʒ޸9K2fin98 w#ZMV(r6|f?̔SgFAj&F,k`ypБVz*R䏙n p!q5)c&YV~)N7vRsq̕>\,}<ګ۞$e|f2 p+.ˢqI7cx.I7c|lzqTT,3o9dz}i5CK:ђi!=̹T]L竈 #A-se7Sv:~hk,lWY~iOla%xG@gZp05R(LӇ'x/"4 =S. Q.ǔn8s]*%Nˊm~ /v,`#ɝԡFI啉b@ = c[TRi+}N/߮Kl.צ!qnj|SseF@䓻Rp: q^vLei5b(lQpM&}( {LhQ~f#Kyat!9/:҄QbM1ǝYwMRb\CipMhGO2,f3X̓ =)g v Kq'N W\Yfj8Qf)=ih\U62x ~Kvٌ;M¹ǃ\ǃ,q,+}P7l4pa'SKkz2i,d{}a'0GpMn љ96+}B$уA?-A(ȥԠ]g%_'n(:RKKY,1WVSBe_[xΥ<7Ӛ>S~dY$zӄE27\YҶ!XJVz}.-]1x3wҘ)A8'\I]џvD,If 'W!-u5{/J`2 >ӂzԠe(JǞ3)M n7y|xl+mqCV!0C"!Mwc+yŖ=ĭkp&wZxX"}#}PrAŦ( `.b3=9T] ϗ>OXs?>yo1"Y}T+8b`'!ї.Cd-\A=:2G8+eO&>D_N#W6^qsͨC ǠdogC< !'CP4;:~v %'-g.I</2 =\DCd"jҎdߦ&I5XJjd燠J~Fx惀=DO:po&1wG.>t6-!*$z;!]-{3<dOFβEy_mqtU};?=0tzZV KVKֳwx,MVrSˈj/}Rm{eMxY퓙|g޳l.*siA{ #yyWyl[vGtQm|Y퓝x7a#Bo&PkAGz31L9+ȟ H֒dO\aSx>l(euԥwэbx5|?/D9woQWV$&2+,'\B. Q˨J-Њ` 3e)6$͠϶eOod Xj%4]!qB^Υ45]3Y[||slڧ+q 0woivŌ~+&Ꞩp U=Hc:/*ﳞ|ڧs_& B?YV{!RZO*r=uiF[ÙSfﰖO_Li)1y)GUjѐVt'da. |QfzB$YyթMЅ> e+vPZn`"N4VZ~iB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!vIIENDB`bidict-0.18.2/assets/logo.png0000664000372000037200000004170613535200701016656 0ustar travistravis00000000000000PNG  IHDR75sRGB pHYs  $iTXtXML:com.adobe.xmp 2 5 72 1 72 507 1 247 2017-11-16T12:11:52 Pixelmator 3.7 ?;IDATxuEǿ^QCZ^RBiDRAJAIi)D@*}? g=u{<3<{@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!\AA! -SE\c/x$QâU'B zSxjG"b{AЀj'"~b&T B<_Zc0WSnDvT@F( 9^dVëhA+NwI@10kY0j̯BB9oBI f=- KF5 D|zsA OXK1+Tf([#-OCg^R{$a O#}Xcw1kPPR>7By9duDc6g%cɦ^B6I]ҟoy,C#bdg>"HӞܓG8((( ? #/.rD: 2J JAa;x=.1m"ڳW *M(fI,&%=$bJ\6u~Id. Q4X}G]BØ4KP= rՖSBqAkfƚ2BQx)(n >ǦLv!$P/WA %!* lK\ox\2}B L)~!H!8 Bad I»xIjTPBF>@Hn2ATqZe,:F(:r4|AEg>]#&B mO XtOgZj"(DsݢPhk\rYבNMliFČ2Aw(WW]isߡ)(x a4Ik` f!7`3)W"b&g"AL)=mCA)B+xxG迎`왒thTF߾GUpLAT;дj(#1saiɫkZ_u5 i-e!V{ԛ%TRdaa<2- .Qǣ+W.G!UmO$uhMOF0 vp_unpUw~g/Y"f1t1U(DZ)X+{$ R+޼=b͋(JvF'$8 tֲ߄ [8N34ҫeYeU"}]$HLT.ث3S#MĔ%XQn{IeC~c BsJVuc@t ̰PJ0?+5ţIt{ra)c$Vw̧/^;@uv $;o,N)G6# ДI'qtpyuz2 plb1(N/֚6| ZrB84{O<R'eof1n(EWATOcӑ_sÉqd WDм7[ϰcCA{P!?Nfғ$#)IC”UҜe3X|ǯܰՋKKQ"蟲Tak#C\5C?,"6I4I rbYTzш^!%K'F2ExnG'$ `0|Aߤ}yŎr!FEfa3c%)m.ڜS0V7\Pm0s1#>{x%`w̶aM 2F!%\z2:|: ՞Llp1?a`!DXD숐 8I[`c5]n dcA^cHE;zoY6Az!8os(J/h \> fp&--p:`Ubk? c6QKK^hQ&`P4 %AP#425>{h1hIz2^P_`o|Bsz*!v|J IoqR=pC& NJCW kKcxlDC=>\&=ՐPSnz8*1F#%/5r/i6Omeٻ~½vko#1akEj. ÄjCUo Ïd "j,#OQ*gbLr;vD\O9Av5X"0c@/ypLT7d}vQP䓱Exn?񙉾 _D>>S%5#,!m&W&gNҴY\]ΤU'3~c7I  O=$7F:u EOzJ=ʄW#i6[2=4n|l[1#^|$ACm|r1'Dpс s8oFr@XۄO}r+Ud'ܗuN`˷uɹ!'Du/1G+M>3|LJ~lI^ mq'mn?!l̒pN0}G(a Hv6L8%wW IZ1a3x;&ALsFص^I1xJ?ݘKfdGdiEes?^\}N:In9Aâ^F>6E[ߛ<2zP|(7x-[A=|vDl<ؐ}ͦnKD(- ff*S,7EZKS~7qU$>ɢn6T le7 ATpIYY&Aw(@ӒI" n龜4R|>24yj?9('eɮHHͿ4wrY7arE iQE:*oPb'Y|dK5W-?=NkoSgu|~B:f 01 vmYZ;]/,2]|ܧ/?/߻6!ૐXbw@3Boh.7u ?;>[alrԋ-lxy'.,M$CzcvΔ8,Y'Jo8Bu0t95ȣK5eۍr}esPJ=O ^JH"VJQPLOԨsSE٩:ipNAe35;Lk—>nw\a|·,; ģ"Z3 N:ew+ֲ,loA߿:%e$#8kL@!o>V9.YD22 aC>Q/`J)*?: !}79u3jfmu:M&ݾ>;WA}H *lPq ǘA}t5q BK<5 brPORU$Sހgm$ yKW L wCbW&1g:xY2$$v4B"(Jh0FcQR{k|>n 41}Vlg* oфOD_>@9c,nJv, l̓k1-!t0P.I:bÃĦ6 U1=5 ~6PR:\5{.&ϫvLJl > -H=zs?XbާX"1L$̆L~3o:% *.1^v|ĪS'd6yьM 9<|ıuz&n&9r6p z!0 ˏ`/fkػYPIHIOS*s ZxWm[>-X$^dҿg|5}W'`{_,esk?G"6=7ObTf0\Wn\CLbB1\Ղ>b(fH2.;w,Q_FBG[|'Z%8Oڦ* t*ʄHx,ț!~0&X ;>s,ȷ_H*0~_K\aInPz]A; Fm0Ov\Ӄ9ՙR׾UT˭šk7}ײ<)JeR4$RυRR#k% 7Rʠ׾Aa( >8Z IziHH%Rqc%#: Kj:൏Pɘz'c6P,a!UV7w|ZHj%n4RZ&o+M'o1nr8쇧K9¾BT9^u79o⒓iWBb2X-6%S#ilIHm feL]t 5[d kܱh)$j0$eoͣk1!nġ] InXM"refϼa<䑋_ޒ'CFk'^ix7rԾn*MCcegCp^fAe9tP?#ŘvKqtZ-#TpKとk`;|}y[eO+J\?#c->a) -;~ 0?$~ 2JK;bn 1SR/7LO+?u7V.grr_DC[A_H]qhuq}N6\L !}bk2#Π L$;ج䮛ud4 s]pǞ[~Ӂ,-rXkaGԃNڻ;X QmDrzcT#>CmO f'fDX{TH3e=w܄_ x%op#q%~YRkzР9qX'=21R1^R?NjkťjEp u \Sx3{| ~=PjO*s.KNz?:GJ>iF_HN*o ׆ko/ Jw{P -ݜrQIԷ[$a;w9? 4O#% ,Ҥne z{tG/8$s9ZKzhjV$IMqwepnP\t\٫# Y̓nJ}ctȼԐyFrw:]J]'n?Z`daHBAWh+9isY>63IG;m)>C^7VFW62H-u5{ ŤRe2I2 0&71]_ӬRF.›)%И]{R-wϚ%oAo^{3U>)U>@2 HV?],& }6D[)"EN$]8gH_tյ$u7m&h_Q¥/+tasy[CǁF\vb> xWjKA ,zRw8n07#E^~vXo޳M랛ޑHcNy9 z5Y|^ڋBKKQv/4C$LD1ҧt5QVsGW#瞅I ikBu5jk^MoYlzHKy*,L$fDya䖅㺩:7灮GI./ެ){,Ӑ>FM%9&knMIg4ZJLD;'=Qs3 )?ۛ`e0W KscL 3ng {wlAoҳ23Ŧ%ҋ46MI€fRDK'w7I0#Zo$JkQ?) ^Ao.od@ oamOMU±CY~) kg=CRє6xD4хm]>Bs<]`༪|gSSҝ+8lW *썹cAu 9/Ƞw@@zI!4,{U1M <Oa)F 8enAf"-%4}hB[XodЛK)7!^RLY8Uki33[MQaRȇX0$$%(N?A/˾fSi 734dxBFXpz86Flx/H\tV |z @oMTAJͻhhi@}T|hZ })&5{p=z*MQh+?-vE3\'3@=kmٟiäh5ZI,]&jVYM|p 6]>qʭ64n evTuFLzeBCf&L튶|Bއ+T҄D/C\Wc(0o-Z(tRَ1ID¥$ _o4 ztspRbm")l%#Yvɇ/% */tz 5OcP]YPRFehk`x I-ܤ!䲔KУBXF@D]>ݗT^nUZPҵ|B K2I4Ыb6Rx]~5c2V}^ MIN$%=9)Di*Qx49oЂ7hFRT,I^r ^HQɛ@ xX&~ЍǏN,,`y-al˩wߢW,\"h&GG3lf?d3{;L8|ӌ*4d٣ Z9WР7_707"MS& t,xSSqM/I(JC0iA8^V2Na^S]O٩3hРŠsPT7q2Xki!]UV@W}jh環s|XX~.Ro8*Ўr^ \u"4YM5 ^3<>APZێHZS񞅒_FQ^"HK-lZlѮ:j 4 PsC#B@p{B 49NJK|X]5|GzULzb`8qhG~*!Z#ٿ5v4Q% z" ! mRs]tK3"Fr ѪebBvWWe'9>v5_XjVc_ {8 P+XoMm<|*)WAn`nzPBk-knUo1H[@(ۈ509SߡkP~|i3}y<3!tR,=a$!(O=яq,sY|'K ɂZc]~s4~x-6A=*JflʚcԎRSڋWkvU bߏl_9KtKʷ |F&CRPtb K6uHc<0u5 5!j"hJV44=vko \nfXoxEAN[YKΠl8KLC )9Lg g=b?$rA|dbU 4jNA/nb]~.y6I; Vr]O8>̼JXgq5̙2d x9XG%.馡ax:U5If"7r{6r8ɏ`'[Xbf3!C[^2d<>\ri1O꫈F(kI^lh u6ep-N8j }gfZg3SQXd,h汑buq"GLgERJ-!-jpdڧWh. %Рw*W@4C}a.*0j`,Dz:LSTAқq۬-gC5l^ β匧+DNGVX007<7jQAoA`nڛ:"R2NzB#<}LVKDU4X0^g^`65,՗IJiZ32И]a?KAkʒ`/@vy?Q8떏7>Qko~"Q^:__'}+?w '|.H@)Kom"U·8z2:%ӐPuϳmW 07J{͐6=0Ħb'CKwyH9u6 ц)lQ):?t2B)8|]7eՇjld /oz:l'IsX8`50]טCyt#  KmLybq:ka@Рn\A BD(.i֡"bgm H44C6P,4gm&D8n6Ye oӖ&FP|d'#iII2y{&MaJQN :ҋaL#V%8UM{NKra2'84vXb>b& z҉V4(LvRy4f(rԡ@Mtܖh7CF\eh2Ay[TK\<:5XYc:_iRl ciI}:0 |p ^=uqobf02 c glkw1VFk 'o I)Kj{U~1]zП/`RЎu)785F=o'\4{XG;MHw+H@2cF`& ؠ7007{–UێozWtb vs ;}EwV0ek@Z%9&5/#0U嵷omnb2n)mxycҐ^~aѯq0!2Y%P 51 䆁k/X76|d{]Nz?r &6*z=,eLf  7k/|6 P:!Qy16|h`gEҘιqtMF ]]P5+fӇzӥ҄dg G"|'A3C_y-"-l48acBuR;4Nid;~˜0;|L3miNCPTe)E S,$)K9*QԡMi[M1|"V8)_?Z,pm|@jŭJCR^!f@6* 0[ x[W\P zQG`~r:A7Vl?Uu[PR$C9Vm8 IKJQtb35lGZFނwU)!滩kogT'4ۍ=u3+I96{.=ΰOMR > u D1ӊ>g!9E|$)0" h A`KiPTݣD\:WO+a|Ⱊl#ޥ)H$VJJ R a69%/r: Z "G0 U^{ζ36SzEx ㏹EǤ퀴&.VCIHJ2 x-ѓ =F0D&35Ma282 ]iOKSjTF8Pbr4gQ}v6 s=fYD7͋;8Hx6#IB۵egc>=x qHMRftbcBֱ9drKV1 ;x&qI(D=z2 w,7L %lc rC"'HM#OvwC=8b2{IAnXؤ(iE/05(|:gz142y,VIIZ2%y0A5A`;쬲˾Le|*p׸sa,ѹ{Gg"`DM0+߲I1I']0%JъQ⨅EpРV$;mN󴕜$0 tk:@*4/X~~w2|e' N*^ʨJjч3Y* z00Wyk|;&M-vҽvz4kAȰY w= ^LY3sdXuY>)YgS3t9@Qr> ׍C22'ØBֳ\+G7J62e*ב%6⛼'|tw^>#ng9b3Y,3^E3jS"d'̻ςt{3O"t'<$KEyy`oV^{b|DgApp -l8QeKM㻨0P:ta4 38|ޢQ` Uq;ECÉWVRmX&14*E!lCM1$sާ ę]vVh/bfckhzҒ#L^dg"tC" 0Wy}QJd f*iV;lfG[jQXJOԢ7AY~Abڤz|ϴdmb Zf3ԧ Y1,:}XWAHզ~B:۴}[45coyv9aMf)!әĸtց }џ a#8&1c0?ǧvεa7 Q¤"yy ln%Iylwq&YeW87`yVԡB2\ION Sԥ9oыg Y's= !6#D]r]L4` _[8N~G؜TC-+"{YXP⤳CGjrR4=4ȹ{Eg=2T'&x)AKfrPNa` cD!dd$iFW2Elb/' Rӝ xFae6a`bUX E_a˯DRQ'cZv3C-˙;4uvCGg^C 0Wy nXJ1=i!5h^C(KEѕa|jvqk~=|od1cHumlGT6H] xwC/KC!ъLd1_s~Y No/*}@"nJVMJsHpleK$ӗδ>U)MO -Q~"Ԥ*%1L9 k(n͋[`C4u\4fVeО&Ԣ"E:HDN*ҌLd;8mxs^U^+C:k" F 7g9^C(t''iA}wu!H*}$܊M-AR"g8noҔJBIM1ѕ,N ~v AyI5N[.y:yY.U1~tTԗ)H-:2F>&k.l`&yFԠaRf3y"=IB RL``;Kv܍kLhyd;x˘dQ :"YL;oxhI5hJ)}#6QL6bM/HsG|!*QC 9"zk>XW|-2mb[5: 6i@5>!Q50w>W>ذTq~@tKߺ=@3^{A؜q x|g0pcDYU k#OWDp 4g3WQ48PP|ߞpKCbCI>8@jJlb[1͙N~kT~ni{~h3QyYm3i2Cq*Q&;2|ħl`8o\qtQͷm,>QOC$|P UO :қc'*6 ZSW^|A1E>p")EQSFd氄u|^ ^Mq*}#2ևd&BӁ f,lb9y)?)}TC(%& }6RvA ӀVt/Øl/8n30G)d53r+c=ʮ%##y(A%jӔtg <>ep㜍FFK嵏P5^0Zq+(xdLO.R4-H&3kq_+k#+>)L~JQ4=Xf1+gs^Fu((b0NZӅ g"YZd?p6SPPJ-3$jнMIENDB`bidict-0.18.2/assets/logo.pxm0000664000372000037200000076433513535200701016710 0ustar travistravis00000000000000PXMDMETAbplist00X$versionX$objectsY$archiverT$top1/0123456789:;<=>?@ABCDGNOVZ^adghijxyz{|}U$null .WNS.keysZNS.objectsV$class   !"!$%&!!)*!,- !"#0_3PTImageIOFormatBasicMetaBitsPerComponentInfoInfoKey_+PTImageIOFormatBasicMetaDocumentSizeInfoKey_.PTImageIOFormatBasicMetaResolutionUnitsInfoKey_/PTImageIOFormatBasicMetaGroupLayersCountInfoKey_-PTImageIOFormatBasicMetaColorspaceNameInfoKey_0PTImageIOFormatBasicMetaBitmapLayersCountInfoKey_'PTImageIOFormatBasicMetaKeywordsInfoKey_)PTImageIOFormatBasicMetaDataAmountInfoKey_)PTImageIOFormatBasicMetaLayerNamesInfoKey_0PTImageIOFormatBasicMetaVectorLayersCountInfoKey_.PTImageIOFormatBasicMetaTextLayersCountInfoKey_.PTImageIOFormatBasicMetaLayerMasksCountInfoKey_1PTImageIOFormatBasicMetaNumberOfComponentsInfoKey_.PTImageIOFormatBasicMetaColorspaceModelInfoKey_)PTImageIOFormatBasicMetaResolutionInfoKey_&PTImageIOFormatBasicMetaVersionInfoKeyZ{507, 247}_sRGB IEC61966-2.1 EFHIJKZ$classnameX$classes^NSMutableArrayJLMWNSArrayXNSObject PFQRST WXYYNS.stringUGroupHI[\_NSMutableString[]MXNSString WX`Qd WXcQb WXfULayer#@R kq.lmnop$%&'(rsluv)-$./0_PTImageIOPlatformMacOS_%PTImageIOFormatDocumentVersionInfoKey_-PTImageIOFormatDocumentSavedOnPlatformInfoKey_1PTImageIOFormatDocumentSavedWithAppVersionInfoKey_5PTImageIOFormatDocumentMinimumSupportedVersionInfoKey ~*+,_7PTImageIOFormatDocumentRequiresMinimumAppVersionInfoKeyU3.1.1HI\NSDictionaryMU1.5.1S3.7S1.5HI_NSMutableDictionaryM_NSKeyedArchiverѐTroot#-27kqx0^$Nz ;o "'2;JNV_dinprtvx}!Iy06;HKQUY^txPK\~O document/infoSQLite format 3@ -.@  ? {!!ktablelayer_infolayer_infoCREATE TABLE layer_info (layer_uuid TEXT, name TEXT, value BLOB, UNIQUE (layer_uuid, name) ON CONFLICT REPLACE)3G!indexsqlite_autoindex_layer_info_1layer_info ))Stabledocument_layerdocument_layerCREATE TABLE document_layer (layer_uuid TEXT, parent_uuid TEXT, index_at_parent INTEGER, type TEXT)|''7tabledocument_infodocument_infoCREATE TABLE document_info (name TEXT, value BLOB, UNIQUE (name) ON CONFLICT REPLACE)9M'indexsqlite_autoindex_document_info_1document_info 2iPTImageIOFormatDocumentBitsPerComponentInfoKey8YdPTImageIOFormatDocumentKeywordsInfoKeybplist00X$versionX$objectsY$archiverT$top U$null ZNS.objectsV$classZ$classnameX$classes^NSMutableArrayWNSArrayXNSObject_NSKeyedArchiverTroot#-27;AFQXY[`kt_MPTImageIOFormatDocumentIDInfoKeyBB259585-A926-448C-9FE7-9E4FF89D4617-64145-00016D990CA70147`elPTImageIOFormatDocumentSelectedLayersInfoKeybplist00X$versionX$objectsY$archiverT$topU$null ZNS.objectsV$class _;4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9Z$classnameX$classes^NSMutableArrayWNSArrayXNSObject_NSKeyedArchiverTroot#-27AF!H_clPTImageIOFormatDocumentLayersLinkingInfoKeybplist0023X$versionX$objectsY$archiverT$top%(+.U$null WNS.keysZNS.objectsV$class  _;E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83D_;DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BB_;4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9_;BAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9  !"Z$classnameX$classes^NSMutableArray!#$WNSArrayXNSObject & ) , /0_NSMutableDictionary/1$\NSDictionary_NSKeyedArchiver45Troot#-27DJQYdkprtvx}A"6    (  2 Du [W2iPTImageIOFormatDocumentColorsyncProfileInfoKey4mPTImageIOFormatDocumentNumberOfComponentsInfoKey2iPTImageIOFormatDocumentBitmapDataFormatInfoKey*YPTImageIOFormatDocumentSaveDateInfoKey4mPTImageIOFormatDocumentFileVersionSupportInfoKey (UPTImageIOFormatDocumentGuidesInfoKey 8uPTImageIOFormatDocumentOriginalExifDictionaryInfoKey &QPTImageIOFormatDocumentSizeInfoKey 0ePTImageIOFormatDocumentResolutionSizeInfoKey 1gPTImageIOFormatDocumentResolutionUnitsInfoKey,]PTImageIOFormatDocumentCustomDataInfoKey2iPTImageIOFormatDocumentBitsPerComponentInfoKey*YPTImageIOFormatDocumentKeywordsInfoKey$MPTImageIOFormatDocumentIDInfoKey0ePTImageIOFormatDocumentSelectedLayersInfoKeyHPTImageIOFormatDocumentViewingOptionsInfoKey_PTImageIOPlatformMacOS.c PTImageIOFormatDocumentLayersLinkingInfoKey ''aBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC94A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9com.pixelmatorteam.pixelmator.layer.vectorj_4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9com.pixelmatorteam.pixelmator.layer.grouplaDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBcom.pixelmatorteam.pixelmator.layer.bitmapi ]E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83Dcom.pixelmatorteam.pixelmator.layer.texta"Tp0hUDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerBlendModeInfoKeynormpmDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerPreservesTransparencyInfoKeybQ DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerOptionsInfoKeyh ] DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerHasBitmapDataInfoKeyd KDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerNameInfoKeyLayer| uDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerBitmapDataChangeTimestampInfoKeyAhh UE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerBlendModeInfoKeynormb Q E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOptionsInfoKeyh]E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerHasBitmapDataInfoKeyjOE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOriginInfoKey{146, 43}gKE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerSizeInfoKey{92, 88}i_E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerIsClippingMaskInfoKey`KE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerNameInfoKeybdU E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerIsVisibleInfoKeyc[E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerSpecificDataInfoKeybplist00X$versionX$objectsY$archiverT$top !"#$%=>?@ABCDEFGHNOUV^_`abeuvwxy}M!"%156;CFNQRbefgU$null WNS.keysZNS.objectsV$class  jk>*_$PTLayerMarkedAsTemplateCustomInfoKey_PTLayerStyleSnapshotKey__IS_STYLE_LAYER__PXTextLayerInfoDict]LAYER_OPTIONS\_STATE_DATA__PTLayerIsLockedCustomInfoKey &1'()*+,-./0 23456789:; +QSfg*_PTLayerStyleOpacityKey_PTLayerStyleDocumentSizeKey_PTLayerStyleBlendModeKey_PTLayerStyleReflectionKey_PTLayerStyleShadowKey_PTLayerStyleStrokeKey_PTLayerStyleLayerRectKey_PTLayerStyleFillKey_PTLayerStyleVersionKey_PTLayerStyleInnerShadowKey#@YI JKLMZNS.sizevalZNS.specialZ{507, 247}PQRSZ$classnameX$classesWNSValueRTXNSObjectnorm WZ]XY\_PTLayerStyleIsEnabledKey_PTLayerStyleStrengthKeydPQcd\NSDictionarycT fmgXijk'!"#$ npqps%'(')*_PTLayerStyleColorKey_PTLayerStyleShadowBlurKey_PTLayerStyleShadowAngleKey_PTLayerStyleShadowOffsetKeyz {|WNS.dataO>PTCGC??appl mntrGRAYXYZ  acspAPPLnone-appldescodscm0fcprt8wtptkTRCdescGeneric Gray ProfileGeneric Gray Profilemluc skSK*enUS(caES,viVN,ptBR*.ukUA,XfrFU*huHU.zhTWnbNO,koKR cQE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOpaci -*Z-^3cg S  3 e  $ m p > 4`KBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerSizeInfoKey'j_BAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerIsClippingMaskInfoKey&`KBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerNameInfoKey%eUBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerIsVisibleInfoKey$h[BAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerSpecificDataInfoKey#cQBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerOpacityInfoKey"eU4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerBlendModeInfoKey!cQ4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerOptionsInfoKey i]4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerHasBitmapDataInfoKeybO4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerOriginInfoKey`K4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerSizeInfoKeyj_4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerIsClippingMaskInfoKey`K4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerNameInfoKeyeU4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerIsVisibleInfoKeyh[4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerSpecificDataInfoKeycQ4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerOpacityInfoKey`KDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerSizeInfoKeyeUDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerIsVisibleInfoKeybODEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerOriginInfoKeyj_DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerIsClippingMaskInfoKeylcDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerBitmapDataFormatInfoKeycQDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerOpacityInfoKeyh[DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerSpecificDataInfoKeyeUDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerBlendModeInfoKeyqmDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerPreservesTransparencyInfoKeycQDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerOptionsInfoKeyi]DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerHasBitmapDataInfoKey `KDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerNameInfoKey uuDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerBitmapDataChangeTimestampInfoKey eUE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerBlendModeInfoKey cQE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOptionsInfoKey i]E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerHasBitmapDataInfoKeybOE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOriginInfoKey`KE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerSizeInfoKeyj_E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerIsClippingMaskInfoKey`KE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerNameInfoKeyeUE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerIsVisibleInfoKeyh[E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerSpecificD,i]DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerHasBitmapDataInfoKey   ) eL2iPTImageIOFormatDocumentBitsPerComponentInfoKey8YdPTImageIOFormatDocumentKeywordsInfoKeybplist00X$versionX$objectsY$archiverT$top U$null ZNS.objectsV$classZ$classnameX$classes^NSMutableArrayWNSArrayXNSObject_NSKeyedArchiverTroot#-27;AFQXY[`kt_MPTImageIOFormatDocumentIDInfoKeyBB259585-A926-448C-9FE7-9E4FF89D4617-64145-00016D990CA70147`elPTImageIOFormatDocumentSelectedLayersInfoKeybplist00X$versionX$objectsY$archiverT$topU$null ZNS.objectsV$class _;4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9Z$classnameX$classes^NSMutableArrayWNSArrayXNSObject_NSKeyedArchiverTroot#-27AF!H_clPTImageIOFormatDocumentLayersLinkingInfoKeybplist0023X$versionX$objectsY$archiverT$top%(+.U$null WNS.keysZNS.objectsV$class  _;E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83D_;DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BB_;4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9_;BAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9  !"Z$classnameX$classes^NSMutableArray!#$WNSArrayXNSObject & ) , /0_NSMutableDictionary/1$\NSDictionary_NSKeyedArchiver45Troot#-27DJQYdkprtvx}A"6$ r9/ Q!PTImageIOFormatDocumentSizeInfoKey{507, 247}7 ePTImageIOFormatDocumentResolutionSizeInfoKey{72, 72}0g PTImageIOFormatDocumentResolutionUnitsInfoKeyY]fPTImageIOFormatDocumentCustomDataInfoKeybplist00X$versionX$objectsY$archiverT$top.!"#$%&'()*19:;<=DLMUV^_cdgopqrz{|}~U$null  WNS.keysZNS.objectsV$class   %&)+__LAYERGROUPS_EXPANSION_STATES___LAYERS_VISIBLE_RECT___DOCUMENT_SLICES___DOCUMENT_SLICES_INFO___DOCUMENT_LAST_SLICE_INFO___DOCUMENT_WINDOW_RECT__PXRulersMetadataKey\_PRINT_INFO__PXDocumentOriginalImportURL +0,-./  25 34 67W_STATE_T_ID__;4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9>?@AZ$classnameX$classes_NSMutableDictionary@BC\NSDictionaryXNSObject EH 34 6J_;BAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9 NQ 34 6S_;E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83D WZ 34 6\_;DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BB>?`a^NSMutableArray`bCWNSArray_{{0, 0}, {240, 208}} e0 hk ijll_PXSlicesPreviewEnabledKey_PXSlicesVisibleKey svytu !wx"#$Wquality_PXSliceFormatKeyd_PXSliceFormatJPEG>?BBC_{{361, 0}, {678, 746}} ij'll(_PXRulersMeasurementUnitKeyҎ WNS.dataObplist00;Troot#-27LRW^kmov~  7CRSXZ\afqz?*>?]NSMutableDataCVNSDataӖ WNS.base[NS.relative-,_2file:///Users/_pants/Downloads/noun_1330481_cc.png>?UNSURLC_NSKeyedArchiverѡTroot#-27hnu}/Le{"-6LP]fmprtwy{}!#%'ejy} !5:=V]acegkmoqs').<@GNVbdfh  p}G4mPTImageIOFormatDocumentNumberOfComponentsInfoKey44iPTImageIOFormatDocumentBitmapDataFormatInfoKey1YPTImageIOFormatDocumentSaveDateInfoKeyAփq { mPTImageIOFormatDocumentFileVersionSupportInfoKeybplist0023X$versionX$objectsY$archiverT$top$%&,-./U$null WNS.keysZNS.objectsV$class    _PTImageIOPlatformMacOS_%PTImageIOFormatDocumentVersionInfoKey_-PTImageIOFormatDocumentSavedOnPlatformInfoKey_1PTImageIOFormatDocumentSavedWithAppVersionInfoKey_5PTImageIOFormatDocumentMinimumSupportedVersionInfoKey !# " _7PTImageIOFormatDocumentRequiresMinimumAppVersionInfoKeyU3.1.1'()*Z$classnameX$classes\NSDictionary)+XNSObjectU1.5.1S3.7S1.5'(01_NSMutableDictionary0)+_NSKeyedArchiver45Troot#-27IOV^ipvxz|~7ovxz|~1496;? U:PTImageIOFormatDocumentGuidesInfoKeybplist00BCX$versionX$objectsY$archiverT$top%&'()*+,-./0125<=>U$null $WNS.keysZNS.objectsV$class  !   ZsnapToGrid\snapToLayers[guidesArray]rulersVisible\guidesLocked\guidesHidden_rulersMeasurementUnits\snapToGuides\rulersOffset\snapToBounds[gridVisible 346789Z$classnameX$classes^NSMutableArray8:;WNSArrayXNSObjectV{0, 0}67?@_NSMutableDictionary?A;\NSDictionary_NSKeyedArchiverDETroot#-27NT[cnu -:GSTUZ[]bmvF u6PTImageIOFormatDocumentOriginalExifDictionaryInfoKeybplist00X$versionX$objectsY$archiverT$topC-./0123456789:;?@ABCDFGHI&*&^ResolutionUnitXSoftware[CompressionXDateTime[XResolution[Orientation[YResolution^Pixelmator 3.7_2017:11:16 12:11:81"B\]^_Z$classnameX$classes_NSMutableDictionary^`a\NSDictionaryXNSObject cg,def!"#hi*$%_PixelXDimension_PixelYDimensionZColorSpace"?"Cw ty,uvwx)*+,z*|}-/1XKeywords_ImageOrientation_OriginatingProgram^ProgramVersion .\]^NSMutableArrayaWNSArrayҋ WNS.dataJPixelmator0\]]NSMutableDataaVNSDataҋ C3.70 ,4567&&*8XYDensity]IsProgressiveXXDensity[DensityUnit"C_sRGB IEC61966-2.1 ,<=>?@@]InterlaceType_XPixelsPerMeter_YPixelsPerMeter SRGB_NSKeyedArchiverѼTroot#-27} AMT]do{ +79HJ`eglw $&(*,.7J_nstv{)*/CJNPRTXZ\^`n ziPTImageIOFormatDocumentColorsyncProfileInfoKey HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km csCZ$0heIL TroRO$tdeDE:itIT.svSE.zhCN.jaJP>elGR$TptPO8xnlNL*esES(thTH$trTR"&fiFI,HhrHR:tplPL6ruRU&arEG( daDK42Vaeobecn siv profilGeneric Gray ProfilePerfil de gris genricCu hnh Mu xm ChungPerfil Cinza Genrico030;L=89 ?@>D09; GrayProfil gnrique grisltalnos szrke profilu(ppr_icϏGenerisk grtoneprofil| Gray \ |Obecn aed profil Gray Profil gri genericAllgemeines Graustufen-ProfilProfilo grigio genericoGenerisk grskaleprofilfnpp^cϏeNN,000000000  Perfil genrico de cinzentosAlgemeen grijsprofielPerfil gris genricoB#D%L*5@21H'DGenel Gri ProfiliYleinen harmaaprofiiliGeneri ki profil sivih tonovaUniwersalny profil szaro[ci1I89 A5@K9 ?@>D8;LEDA *91JA Gray 'D9'EGenerel grtonebeskrivelsetextCopyright 2007 Apple Inc., all rights reserved.XYZ Qcurv&PQ~]NSMutableData~TVNSData#@|3!#@RPQ_NSMutableDictionarycT gXY,-.!/01234579:4<>4?*_PTLayerStyleStrokePositionKey_(PTLayerStyleGradientRadialAndAnglePoint2_ PTLayerStyleGradientLinearPoint1_ PTLayerStyleGradientLinearPoint2_PTLayerStyleStrokeStyleKey_(PTLayerStyleGradientRadialAndAnglePoint1_PTLayerStyleStrokeModeKey_PTLayerStyleGradientKey JL[NS.pointval6_){-1.5869565217391304, 2.3181818181818183} JL8_){-1.5869565217391304, 2.3181818181818183}z |O>PTCGC??appl mntrGRAYXYZ  acspAPPLnone-appldescodscm0fcprt8wtptkTRCdescGeneric Gray ProfileGeneric Gray Profilemluc skSK*enUS(caES,viVN,ptBR*.ukUA,XfrFU*huHU.zhTWnbNO,koKRcsCZ$0heIL TroRO$tdeDE:itIT.svSE.zhCN.jaJP>elGR$TptPO8xnlNL*esES(thTH$trTR"&fiFI,HhrHR:tplPL6ruRU&arEG( daDK42Vaeobecn siv profilGeneric Gray ProfilePerfil de gris genricCu hnh Mu xm ChungPerfil Cinza Genrico030;L=89 ?@>D09; GrayProfil gnrique grisltalnos szrke profilu(ppr_icϏGenerisk grtoneprofil| Gray \ |Obecn aed profil Gray Profil gri genericAllgemeines Graustufen-ProfilProfilo grigio genericoGenerisk grskaleprofilfnpp^cϏeNN,000000000  Perfil genrico de cinzentosAlgemeen grijsprofielPerfil gris genricoB#D%L*5@21H'DGenel Gri ProfiliYleinen harmaaprofiiliGeneri ki profil sivih tonovaUniwersalny profil szaro [ci1I89 A5@K9 ?@>D8;LEDA *91JA Gray 'D9'EGenerel grtonebeskrivelsetextCopyright 2007 Apple Inc., all rights reserved.XYZ Qcurv& JL;_){-1.5869565217391304, 2.3181818181818183} JL=_){-1.5869565217391304, 2.3181818181818183} À@ABCȀ4DGH*_PTGradientTypeKey_PTGradientMidpointListKey_PTGradientSnapshotVersionKey_PTGradientColorStopListKey ѡЀEF">RPQ^NSMutableArrayTWNSArray#@ ѢۀINF ]JKLM_PTGradientColorStopColorKey_PTGradientColorStopPositionKeyz |O PTCGC????m ?????m ?H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km&" ]JKOPz |O PTCGC?M?ĥg?P??M?ĥg?P?H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km&"? JLZNS.rectvalR_{{146, 43}, {92, 88}} gX-T./1!3    U>WY[]^*_PTLayerStyleFillModeKey JLV_){-1.5869565217391304, 2.3181818181818183} JLX_){-1.5869565217391304, 2.3181818181818183} JLZ_){-1.5869565217391304, 2.3181818181818183} JL\_){-1.5869565217391304, 2.3181818181818183}z #|O PTCGC?3]$D????3]$D???H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km& &+À@ABC-/4_Ga* 2ѡ3`F"? 7Ѣ89bdF <?]JK@cMz D|O PTCGC?3]$D????3]$D???H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km& GJ]JKKePz O|O PTCGC?I {????I {???H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km&#? SZgXijk'!"#$ [p^psh'i')*z c|O>PTCGC??????appl mntrGRAYXYZ  acspAPPLnone-appldescodscm0fcprt8wtptkTRCdescGeneric Gray ProfileGeneric Gray Profilemluc skSK*enUS(caES,viVN,ptBR*.ukUA,XfrFU*huHU.zhTWnbNO,koKRcsCZ$0heIL TroRO$tdeDE:itIT.svSE.zhCN.jaJP>elGR$TptPO8xnlNL*esES(thTH$trTR"&fiFI,HhrHR:tplPL6ruRU&arEG( daDK42Vaeobecn siv profilGeneric Gray ProfilePerfil de gris genricCu hnh Mu xm ChungPerfil Cinza Genrico030;L=89 ?@>D09; GrayProfil gnrique grisltalnos szrke profilu(ppr_icϏGenerisk grtoneprofil| Gray \ |Obecn aed profil Gray Profil gri genericAllgemeines Graustufen-ProfilProfilo grigio genericoGenerisk grskaleprofilfnpp^cϏeNN,000000000  Perfil genrico de cinzentosAlgemeen grijsprofielPerfil gris genricoB#D%L*5@21H'DGenel Gri ProfiliYleinen harmaaprofiiliGeneri ki profil sivih tonovaUniwersalny profil szaro[ci1I89 A5@K9 ?@>D8;LEDA *91JA Gray 'D9'EGenerel grtonebeskrivelsetextCopyright 2007 Apple Inc., all rights reserved.XYZ Qcurv&#?!TD-SYES hyijklmnopqrstuvwxlmnopqrstuvwxyz{z|}~|>~>*_PXTextLayerTextSize_PXTextLayerVerticalAlignment]PXTextLayerID_PXTextLayerName_PXTextLayerCenterPoint_PXTextLayerTextContainerSize_PXTextLayerRTFData_PXTextLayerRenderOffsetSize_PXTextLayerAcceptsDynamicName_PXTextLayerTextDrawOffset_PXTextLayerEncodedStringData_PXTextLayerUsedFontNamesInfo_PXTextLayerRotationAngle_PXTextLayerClassName_PXTextLayerType_PXTextLayerAllTextIsVisibleI JLM}Z{153, 262}_;E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83D YNS.stringQbPQ_NSMutableStringTXNSString JL_({202.18737082507323, 87.290252138017649}I JLMZ{153, 262}z |O{\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf830 {\fonttbl\f0\fnil\fcharset0 Lobster-Regular;} {\colortbl;\red255\green255\blue255;\red0\green0\blue0;\red255\green255\blue255;} {\*\expandedcolortbl;;\cssrgb\c0\c0\c0;\csgenericrgb\c100000\c99997\c99999;} \pard\sl336\slmult1\pardirnatural\qc \f0\fs292\fsmilli146166 \cf2 \expnd0\expndtw0\kerning0 \up0 \nosupersub \ulnone \outl0\strokewidth0 \strokec3 b}&I JLMX{50, 53} JLW{0, 40}z |Obplist00X$versionX$objectsY$archiverT$top.&RSTUVWXYZ[\]^_`abcdefnorxv{|}U$null WNS.keysZNS.objectsV$class +-YATTSTRINGXRTFFONTS XNSString\NSAttributes* YNS.stringQb !"#Z$classnameX$classes_NSMutableString"$%XNSStringXNSObject '?@?B?@EF@F=?@BB@@F!"!#!"$("(!"##""()_PXTextDisplayFontAttributeWNSColor_PXTextDisplayLigatureAttribute_&PXTextEncodedDisplayFontIndexAttribute_0PXTextToolGlobalTypingVerticalAlignmentAttribute_$PXTextDisplayKernPercentageAttributeZNSLigature_NSStrikethrough_NSParagraphStyle]NSStrokeColor]NSSuperScript_NSUnderlineColorVNSFont_PXTextEncodedFontIndexAttribute]NSStrokeWidthVNSKern_NSBaselineOffset_PXTextSuperscriptAttribute[NSUnderline_NSStrikethroughColorghi jklmVNSSizeXNSfFlagsVNSName#@bEO;dZ_Lobster-Regular !pqVNSFontp%st uvwUNSRGB\NSColorSpaceF0 0 0 !yzWNSColory%"~ [NSAlignmentZNSTabStops\NSTextBlocks_NSTighteningFactorForTruncation_NSLineHeightMultiple%'%#?#?ff` & !WNSArray% !_NSMutableParagraphStyle%_NSParagraphStylest vwO'0.9999992847 0.9999744296 0.9999912977 !\NSDictionary% !_NSMutableAttributedString%_NSMutableAttributedString_NSAttributedStringҟ WNS.dataO:{\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf830 {\fonttbl\f0\fnil\fcharset0 Lobster-Regular;} {\colortbl;\red255\green255\blue255;} {\*\expandedcolortbl;;} \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 \f0\fs292\fsmilli146166 \cf0 FF}, !]NSMutableData%VNSData !_NSMutableDictionary%_NSKeyedArchiverѫTroot#-27hnu} )0GIKMOQSUWY[]_acegikmoRy)FRiry&H_acegpy~ 04Pejr  & €ŀ*_PXTextLayerUsedActualFontNames_PXTextLayerUsedDisplayFontNames ѡˀF_Lobster-Regular ѡˀF"B(s^PXTextBoxLayerz |O|bplist00 X$versionX$objectsY$archiverT$topU$null_NSKeyedArchiver#-279?Q R&_NSKeyedArchiverTroot"+5:?lr)?MZy{.Jbz '2;CHQVchjlqsuw  ">[y $+8OQSUWY[]_ace|~%Bm-6xz  !#%9Ut  )JS&&'' '''''''!'*333333334 44+4-4/41434547494;4L4N4P4R4T4V4X4Z4\4^4x444444444555/5<5>5@5l5uBBB*B3B5B7B9B;BDBFBHBJBLBNBWBZB\B^BcBlBqBsBuBwBBBBBBBBBOGOIOVO[O]O_OdOfOhOjOs\\\$\1\>\@\B\D\F\H\J\W\Y\[\]\_\a\c\e\nddddddddddddddeeeee e e ee2e4e6e8e:ee@eBeDeFeHeJeLeNePeReTejeeeeeeff4fPfofffffffgg gJgSg]g_gagjg|gggggggggggiiiiiiiiiiiirPrRr_rdrfrhrmrorqrsrrrrrrrrrrrrrssssssstBR*.ukUA,XfrFU*huHU.zhTWnbNO,koKRcsCZ$0heIL TroRO$tdeDE:itIT.svSE.zhCN.jaJP>elGR$TptPO8xnlNL*esES(thTH$trTR"&fiFI,HhrHR:tplPL6ruRU&arEG( daDK42Vaeobecn siv profilGeneric Gray ProfilePerfil de gris genricCu hnh Mu xm ChungPerfil Cinza Genrico030;L=89 ?@>D09; GrayProfil gnrique grisltalnos szrke profilu(ppr_icϏGenerisk grtoneprofil| Gray \ |Obecn aed profil Gray Profil gri genericAllgemeines Graustufen-ProfilProfilo grigio genericoGenerisk grskaleprofilfnpp^cϏeNN,000000000  Perfil genrico de cinzentosAlgemeen grijsprofielPerfil gris genricoB#D%L*5@21H'DGenel Gri ProfiliYleinen harmaaprofiiliGeneri ki profil sivih tonovaUniwersalny profil szaro[ci1I89 A5@K9 ?@>D8;LEDA *91JA Gray 'D9'EGenerel grtonebeskrivelsetextCopyright 2007 Apple Inc., all rights reserved.XYZ Qcurv #@|3!#@R'(_NSMutableDictionaryj, n`a./0$123 45679;<6> 6@,_PTLayerStyleStrokePositionKey_(PTLayerStyleGradientRadialAndAnglePoint2_ PTLayerStyleGradientLinearPoint1_ PTLayerStyleGradientLinearPoint2_PTLayerStyleStrokeStyleKey_(PTLayerStyleGradientRadialAndAnglePoint1_PTLayerStyleStrokeModeKey_PTLayerStyleGradientKey UW.[NS.pointval8_{-0.024793388429752067, 1} UW.:_{-0.024793388429752067, 1}# %O>PTCGC??appl mntrGRAYXYZ  acspAPPLnone-appldescodscm0fcprt8wtptkTRCdescGeneric Gray ProfileGeneric Gray Profilemluc skSK*enUS(caES,viVN,ptBR*.ukUA,XfrFU*huHU.zhTWnbNO,koKRcsCZ$0heIL TroRO$tdeDE:itIT.svSE.zhCN.jaJP>elGR$TptPO8xnlNL*esES(thTH$trTR"&fiFI,HhrHR:tplPL6ruRU&arEG( daDK42Vaeobecn siv profilGeneric Gray ProfilePerfil de gris genricCu hnh Mu xm ChungPerfil Cinza Genrico030;L=89 ?@>D09; GrayProfil gnrique grisltalnos szrke profilu(ppr_icϏGenerisk grtoneprofil| Gray \ |Obecn aed profil Gray Profil gri genericAllgemeines Graustufen-ProfilProfilo grigio genericoGenerisk grskaleprofilfnpp^cϏeNN,000000000  Perfil genrico de cinzentosAlgemeen grijsprofielPerfil gris genricoB#D%L*5@21H'DGenel Gri ProfiliYleinen harmaaprofiiliGeneri ki profil sivih tonovaUniwersalny profil szaro[ci1I89 A5@K9 ?@>D8;LEDA *91JA Gray 'D9'EGenerel grtonebeskrivelsetextCopyright 2007 Apple Inc., all rights reserved.XYZ Qcurv UW.=_{-0.024793388429752067, 1} UW.?_{-0.024793388429752067, 1} ĀABCDɀ6EHI,_PTGradientTypeKey_PTGradientMidpointListKey_PTGradientSnapshotVersionKey_PTGradientColorStopListKey ҡрFG">R'(^NSMutableArray,WNSArray#@ Ң܀JOG eKLMN"_PTGradientColorStopColorKey_PTGradientColorStopPositionKey# %O PTCGC??@?m ???@?m ?H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km " eKLPQ"# %O PTCGC?M?ĥ???M?ĥ??H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km "? UWZNS.rectvalS_{{12, 12}, {484, 235}} n`/U013$5    V XZ\^_,_PTLayerStyleFillModeKey UW.W_{-0.024793388429752067, 1} UW.Y_{-0.024793388429752067, 1} UW.[_{-0.024793388429752067, 1} U W.]_{-0.024793388429752067, 1}# $%O PTCGC?3]$D????3]$D???H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km ',ĀABCD.06`Hb, 3ҡ4aG"? 8Ң9:ceG =@eKLAdN"# E%O PTCGC?3]$D????3]$D???H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km HKeKLLfQ"# P%O PTCGC?I {????I {???H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km #? T[n`pqr2$%&'\w_wzi)j)+,# d%O>PTCGC??????appl mntrGRAYXYZ  acspAPPLnone-appldescodscm0fcprt8wtptkTRCdescGeneric Gray ProfileGeneric Gray Profilemluc skSK*enUS(caES,viVN,ptBR*.ukUA,XfrFU*huHU.zhTWnbNO,koKRcsCZ$0heIL TroRO$tdeDE:itIT.svSE.zhCN.jaJP>elGR$TptPO8xnlNL*esES(thTH$trTR"&fiFI,HhrHR:tplPL6ruRU&arEG( daDK42Vaeobecn siv profilGeneric Gray ProfilePerfil de gris genricCu hnh Mu xm ChungPerfil Cinza Genrico030;L=89 ?@>D09; GrayProfil gnrique grisltalnos szrke profilu(ppr_icϏGenerisk grtoneprofil| Gray \ |Obecn aed profil Gray Profil gri genericAllgemeines Graustufen-ProfilProfilo grigio genericoGenerisk grskaleprofilfnpp^cϏeNN,000000000  Perfil genrico de cinzentosAlgemeen grijsprofielPerfil gris genricoB#D%L*5@21H'DGenel Gri ProfiliYleinen harmaaprofiiliGeneri ki profil sivih tonovaUniwersalny profil szaro[ci1I89 A5@K9 ?@>D8;LEDA *91JA Gray 'D9'EGenerel grtonebeskrivelsetextCopyright 2007 Apple Inc., all rights reserved.XYZ Qcurv #?!TD-_NSKeyedArchiverijTroot"+5:?+3>ERTVXZ\^kmoqsuwy  /13579;=?ACE^|-JS`kvxz|"/13579;HJLNPRTVm#,BIVmoqsuwy{} C`  +4vx5Tqz} *3&&&&&&&&&&'' 33333333334 444444444-4/41434547494;4=4?4Y4f4h4j44444444444455AAAAAAAAAAAAAAAABBBBBBBBB)B.B0B2B7B9B;B=BFNNNOOOO O O OO[[[[[[[[[[[[[\\\\\\ \dUdWd`drdwd|kd~ .a"Tp0hUDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerBlendModeInfoKeynormpmDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerPreservesTransparencyInfoKeybQ DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerOptionsInfoKeyh ] DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerHasBitmapDataInfoKeyd KDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerNameInfoKeyLayer| uDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerBitmapDataChangeTimestampInfoKeyAhh UE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerBlendModeInfoKeynormb Q E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOptionsInfoKeyh]E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerHasBitmapDataInfoKeyjOE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOriginInfoKey{146, 43}gKE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerSizeInfoKey{92, 88}i_E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerIsClippingMaskInfoKey`KE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerNameInfoKeybdU E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerIsVisibleInfoKeyc[E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerSpecificDataInfoKeybplist00X$versionX$objectsY$archiverT$top !"#$%=>?@ABCDEFGHNOUV^_`abeuvwxy}M!"%156;CFNQRbefgU$null WNS.keysZNS.objectsV$class  jk>*_$PTLayerMarkedAsTemplateCustomInfoKey_PTLayerStyleSnapshotKey__IS_STYLE_LAYER__PXTextLayerInfoDict]LAYER_OPTIONS\_STATE_DATA__PTLayerIsLockedCustomInfoKey &1'()*+,-./0 23456789:; +QSfg*_PTLayerStyleOpacityKey_PTLayerStyleDocumentSizeKey_PTLayerStyleBlendModeKey_PTLayerStyleReflectionKey_PTLayerStyleShadowKey_PTLayerStyleStrokeKey_PTLayerStyleLayerRectKey_PTLayerStyleFillKey_PTLayerStyleVersionKey_PTLayerStyleInnerShadowKey#@YI JKLMZNS.sizevalZNS.specialZ{507, 247}PQRSZ$classnameX$classesWNSValueRTXNSObjectnorm WZ]XY\_PTLayerStyleIsEnabledKey_PTLayerStyleStrengthKeydPQcd\NSDictionarycT fmgXijk'!"#$ npqps%'(')*_PTLayerStyleColorKey_PTLayerStyleShadowBlurKey_PTLayerStyleShadowAngleKey_PTLayerStyleShadowOffsetKeyz {|WNS.dataO>PTCGC??appl mntrGRAYXYZ  acspAPPLnone-appldescodscm0fcprt8wtptkTRCdescGeneric Gray ProfileGeneric Gray Profilemluc skSK*enUS(caES,viVN,ptBR*.ukUA,XfrFU*huHU.zhTWnbNO,koKR cQE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOpacityInfoKeyd 5.X"Co5b Q 4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerOptionsInfoKeyh]4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerHasBitmapDataInfoKeyjO4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerOriginInfoKey{333, 69}gK4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerSizeInfoKey{75, 79}i_4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerIsClippingMaskInfoKeydK4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerNameInfoKeyGroupdU 4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerIsVisibleInfoKey[\4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerSpecificDataInfoKeybplist00"#X$versionX$objectsY$archiverT$topU$null WNS.keysZNS.objectsV$class _$PTLayerMarkedAsTemplateCustomInfoKey]LAYER_OPTIONS_PTLayerIsLockedCustomInfoKeyZ$classnameX$classes_NSMutableDictionary !\NSDictionaryXNSObject_NSKeyedArchiver$%Troot#-27AGNVahlnprvxz|~  25:&?@ABCDEF#-RTgh,_PTLayerStyleOpacityKey_PTLayerStyleDocumentSizeKey_PTLayerStyleBlendModeKey_PTLayerStyleReflectionKey_PTLayerStyleShadowKey_PTLayerStyleStrokeKey_PTLayerStyleLayerRectKey_PTLayerStyleFillKey_PTLayerStyleVersionKey_PTLayerStyleInnerShadowKey#@YT UVWXZNS.sizevalZNS.specialZ{507, 247}'([\WNSValue[,norm _be`a d!"_PTLayerStyleIsEnabledKey_PTLayerStyleStrengthKeyd'(jk\NSDictionaryj, mtn`pqr2$%&'uwxwz()*)+,_PTLayerStyleColorKey_PTLayerStyleShadowBlurKey_PTLayerStyleShadowAngleKey_PTLayerStyleShadowOffsetKey# %O>PTCGC??appl mntrGRAYXYZ  acspAPPLnone-appldescodscm0fcprt8wtptkTRCdescGeneric Gray ProfileGeneric Gray Profilemluc skSK*enUS(caES,viVN,p 1 @ x 8 j h+UBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerBlendModeInfoKeynormb*QBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerOptionsInfoKeyh)]BAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerHasBitmapDataInfoKeyj(OBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerOriginInfoKey{333, 69}g'KBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerSizeInfoKey{75, 79}i&_BAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerIsClippingMaskInfoKey`%KBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerNameInfoKeydd$U BAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerIsVisibleInfoKey#[ZBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerSpecificDataInfoKeybplist00klX$versionX$objectsY$archiverT$topm !"#$%=>?@ABCDEFGHNOUV^_`abeuvwxy}M!"%&267<DGORScfghU$null WNS.keysZNS.objectsV$class  k4lc"QBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerOpacityInfoKeydh!U4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerBlendModeInfoKeypassk*_$PTLayerMarkedAsTemplateCustomInfoKey_PTLayerStyleSnapshotKey__IS_STYLE_LAYER_]LAYER_OPTIONS\_STATE_DATA___IS_VECTOR_LAYER__PTLayerIsLockedCustomInfoKey &1'()*+,-./0 23456789:; +QSgh*_PTLayerStyleOpacityKey_PTLayerStyleDocumentSizeKey_PTLayerStyleBlendModeKey_PTLayerStyleReflectionKey_PTLayerStyleShadowKey_PTLayerStyleStrokeKey_PTLayerStyleLayerRectKey_PTLayerStyleFillKey_PTLayerStyleVersionKey_PTLayerStyleInnerShadowKey#@YI JKLMZNS.sizevalZNS.specialZ{507, 247}PQRSZ$classnameX$classesWNSValueRTXNSObjectnorm WZ]XY\_PTLayerStyleIsEnabledKey_PTLayerStyleStrengthKeydPQcd\NSDictionarycT fmgXijk'!"#$ npqps%'(')*_PTLayerStyleColorKey_PTLayerStyleShadowBlurKey_PTLayerStyleShadowAngleKey_PTLayerStyleShadowOffsetKeyz {|WNS.dataO>PTCGC??appl mntrGRAYXYZ  acspAPPLnone-appldescodscm0fcprt8wtptkTRCdescGeneric Gray ProfileGeneric Gray Profilemluc skSK*enUS(caES,viVN,ptBR*.ukUA,XfrFU*huHU.zhTWnbNO,koKRcsCZ$0heIL TroRO$tdeDE:itIT.svSE.zhCN.jaJP>elGR$TptPO8xnlNL*esES(thTH$trTR"&fiFI,HhrHR:tplPL6ruRU&arEG( daDK42Vaeobecn siv profilGeneric Gray ProfilePerfil de gris genricCu hnh Mu xm ChungPerfil Cinza Genrico030;L=89 ?@>D09; GrayProfil gnrique grisltalnos szrke profilu(ppr_icϏGenerisk grtoneprofil| Gray \ |Obecn aed profil Gray Profil gri genericAllgemeines Graustufen-ProfilProfilo grigio genericoGenerisk grskaleprofilfnpp^cϏeNN,000000000  Perfil genrico de cinzentosAlgemeen grijsprofielPerfil gris genricoB#D%L*5@21H'DGenel Gri ProfiliYleinen harmaaprofiiliGeneri ki profil sivih tonovaUniwersalny profil szaro[ci1I89 A5@K9 ?@>D8;LEDA *91JA Gray 'D9'EGenerel grtonebeskrivelsetextCopyright 2007 Apple Inc., all rights reserved.XYZ Qcurv&PQ~]NSMutableData~TVNSData#@|3!#@RPQ_NSMutableDictionarycT gXY,-.!/01234579:4<>4?*_PTLayerStyleStrokePositionKey_(PTLayerStyleGradientRadialAndAnglePoint2_ PTLayerStyleGradientLinearPoint1_ PTLayerStyleGradientLinearPoint2_PTLayerStyleStrokeStyleKey_(PTLayerStyleGradientRadialAndAnglePoint1_PTLayerStyleStrokeModeKey_PTLayerStyleGradientKey JL[NS.pointval6_){-5.7199999999999998, 5.2911392405063289} JL8_){-5.7199999999999998, 5.2911392405063289}z |O PTCGC??H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km& JL;_){-5.7199999999999998, 5.2911392405063289} JL=_){-5.7199999999999998, 5.2911392405063289} À@ABCȀ4DGH*_PTGradientTypeKey_PTGradientMidpointListKey_PTGradientSnapshotVersionKey_PTGradientColorStopListKey ѡЀEF">RPQ^NSMutableArrayTWNSArray#@ ѢۀINF ]JKLM_PTGradientColorStopColorKey_PTGradientColorStopPositionKeyz |O PTCGC????m ?????m ?H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km&" ]JKOPz |O PTCGC?M?ĥg?P??M?ĥg?P?H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km&"? JLZNS.rectvalR_{{333, 69}, {75, 79}} gX-T./1!3    U4WY[]^_*_PTLayerStyleFillModeKey JLV_){-5.7199999999999998, 5.2911392405063289} JLX_){-5.7199999999999998, 5.2911392405063289} JLZ_){-5.7199999999999998, 5.2911392405063289} JL\_){-5.7199999999999998, 5.2911392405063289}z #|O PTCGC??H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8# f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km& ',À@ABC.04`Gb* 3ѡ4aF"? 8Ѣ9:ceF =@]JKAdMz E|O PTCGC?3]$D????3]$D???H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3!dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km& HK]JKLfPz P|O PTCGC?I {????I {???H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km&#? T[gXijk'!"#$ \p_psi'j')*z d|O>PTCGC??????appl mntrGRAYXYZ  acspAPPLnone-appldescodscm0"fcprt8wtptkTRCdescGeneric Gray ProfileGeneric Gray Profilemluc skSK*enUS(caES,viVN,ptBR*.ukUA,XfrFU*huHU.zhTWnbNO,koKRcsCZ$0heIL TroRO$tdeDE:itIT.svSE.zhCN.jaJP>elGR$TptPO8xnlNL*esES(thTH$trTR"&fiFI,HhrHR:tplPL6ruRU&arEG( daDK42Vaeobecn siv profilGeneric Gray ProfilePerfil de gris genricCu hnh Mu xm ChungPerfil Cinza Genrico030;L=89 ?@>D09; GrayProfil gnrique grisltalnos szrke profilu(ppr_icϏGenerisk grtoneprofil| Gray \ |Obecn aed profil Gray Profil gri genericAllgemeines Graustufen-ProfilProfilo grigio genericoGenerisk grskaleprofilfnpp^cϏeNN,000000000  Perfil genrico de cinzentosAlgemeen grijsprofielPerfil gris genricoB#D%L*5@21H'DGenel Gri ProfiliYleinen harmaaprofiiliGeneri ki profil sivih tonovaUniwersalny profil szaro[ci1I89 A5@K9 ?@>D8;LEDA *91JA Gray 'D9'EGenerel grtonebeskrivelsetextCopyright 2007 Apple Inc., all rights reserved.XYZ Qcurv&#?!TD-SYESz i|Obplist00X$versionX$objectsY$archiverT$topY !"#+/r{  #),0ABCDEFGHIJKLMQ[\`Xeijnpuxyz{|}U$null ZNS.objectsV$class  ZbezierPath_isUnderConstructionXuniqueID_transformControlsRotation_isFakeSmarthShapeXselected_composingOperation\pathMetaData"_;3EBCE249-C166-4144-BCCD-0F3B1F97AB4B-64145-00016ED0C0974B0AO 3.1.0MD[x@RUc!f@L!zty@9ˈ@f@Lݙx@ s?]@C]k7x@IpX_@K+~w@1q\@ņ?~w@;QH\@CTJx@ :_@eBw@Hd\@w@[@C+4w@d\Ik[@;WGx@qp&^@ew@@[@C5lw@ZbdZ@ffw@IJYܟY@w@Z@C#QLw@4m\@*s0w@`;bgX@0w@@Y@Cw@PrX@)Nw@5l$=Y@w@Y@C.Uv@ ʓ X@*[/$w@}X@v@Y@C,jsxVv@@TY@nsKv@ +MY@_0v@X@CJv@ӲX@ .FƸu@|šʀY@ع{ܫu@$PY@C<ˋu@aQY@zmu@rY@΍BQu@u$Z@C B5u@0yEOZ@u@E⩤Z@QX u@>[@Cct@ [@Et@rn\@Kt@I/Q\@CLQt@x23L]@:t@JD ^@è>t@[J ^@C't@[N_@x,t@|C!`@?d= u@ ݿ`@C,u@3`@0u@X b:a@JM$u@(Hgb@CSJu@^Իtb@5zu@`W)c@Tv@`)5bc@Cg_w@b@G=c$w@R>:b@o; w@h*b@C:\v@~ڎb@9v@ b@7FҾv@P8[bb@CXlv@۠0b@}v@tža@D#zv@WTa@C>aev@F9 ra@}}Rv@zJ,a@bAv@ϭ`@C*H00v@# œ`@fXl"v@TT U`@v@Vĉ! `@CJ#N) v@hvn_@v@+: _@4PUu@@#֠^@C[u@<*'^@-ϡu@>Ǘ]@Eu@XgE]@CwK fu@O\@݁v@Ĭt\@ v@ !\@CCZ[@v@j2G]\@cv@U0 @\@jmZ&v@Nik1\@C a!0v@Gx"\@H:?w:v@W7\@Q}Bv@XF\@CaxŤOv@eP \@37p]v@еG \@qY+Tlv@`g\@C!7{v@0'\@!nCv@PL@\@&ܠ wv@).`td\@Cv@ <\@<.Ev@di\@?gFv@Wem\@C&CJHv@ a-]@^wv@omu]@:lv@{]@Ln)+v@, <^@EO3.1.0         , $%&'Z$classnameX$classes\PXBezierPath()*\PXBezierPathWPXShapeXNSObject$%,-^NSMutableArray,.*WNSArray&0123456789:;<=>?@A BCDEFGHIJKLMNOPQRSTUVWXYZ[\X\]^_abcade\fgikilZm\nXoq_fillLinearGradientPoints_p1_copiedLayerBounds_strokeLinearGradientPoints_p2[strokeStyle_fillRadialGradientPoints_p2[strokeWidthYfillColorZshadowBlur_rightPathEndPoint_innerShadowBlur_reflectionOpacity\fillGradientXfillType]strokeEnabled_innerShadowOpacity[fillEnabled[shadowColor]shadowOpacity_fillRadialGradientPoints_p1\shadowOffset_fillLinearGradientPoints_p2^strokeGradient]shadowEnabled_innerShadowAngle_reflectionEnabled[strokeColor[shadowAngle_copiedLayerAngle^strokePosition_strokeRadialGradientPoints_p1ZstrokeType_innerShadowOffset_strokeRadialGradientPoints_p2_leftPathEndPoint_strokeLinearGradientPoints_p1_innerShadowEnabled_innerShadowColor OL# dK PR"!%Z$"+b_MNKQstuv wxZyz\NSComponentsUNSRGB\NSColorSpace_NSCustomColorSpaceG0 0 0 1F0 0 0 |} ~TNSIDUNSICC WNS.dataO H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQ$QR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km $%]NSMutableData*VNSData$%\NSColorSpace*\NSColorSpace$%WNSColor* bYthumbnail]gradientAngle\gradientType]gradientStops[tracksAngleXblendingTUUID_gradientMidStops]interpolation^extension_data  YNS.string_$D56486CD-E83E-49C5-965D-734D39E37DE2$%_NSMutableString*XNSString  b_midPointPositionWICCData_isMidPointColorXpositionUcolor"? "?׀ O H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@%iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km tuv ZzO0.1206132 0.7484115 1| _ $%[GCColorStop*[GCColorStop ʀ "? O H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km tuv ZzO0.22813 0.843386 1 "?"? O H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech&0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km tuv ZzO0.0130964 0.653437 1$%ZGCGradient*ZGCGradient[{-96, -240}[{-96, -240}[{-96, -240}[{-96, -240}stuv ZyzG0 0 0 1F0 0 0  b@+ &'2 _$4134734E-F552-47F0-9EF3-C7EEF259044B  ( b "?) ">R*  O H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC'61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km tuv ZzO'0.2461415445 0.8543331325 0.8500828445  ,/ ">R-. O H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&(Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km tuv  ZzO&0.4705045223 0.9346615076 0.919639647 $%("?01 *O H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]st)tptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km tuv -ZzO'0.02177856676 0.7740047574 0.7805260421 29@WNS.keys345678345678:;<=>?9:;<=>?_radialendingpoint.y_radialendingradius_radialendingpoint.x_radialstartingpoint.x_radialstartingpoint.y_radialstartingradius#?#?#?#?#?#$%NO_NSMutableDictionaryNP*\NSDictionaryR STUVWXYZVNSSize\NSImageFlagsVNSRepsWNSColorAJ BIX{40, 40} ] ^C adbcDEHf gh_NSTIFFRepresentationFGO&MM*###$$#################((#(#'('##((('####(#((#####'###(#''+,+''''+',#+'##''''##'#'#'++''',''#+'''+'++'''''+++++''+'''+'++''''+//+++'+'''////++/////+++/+//+++/+++++//+++/+///+//2/22.+///+2++//////++/22//2.//22/+///22/22552222.2..55222.225222.25225222....22225522252555588525525822555255285252522525558558555885558888588888885855585888822588885888885888;;8885888;8;8858885888;588;8:;8;:;8;;;;8;=:;::;:8;;;;8;8:;;88=8;::=:::=::::::===:88:=:==:=::=:====:::=:87=:===:=@:=:@@:==*::=::=::@@=@:==::@:====:=@===@==:::@:@==:=@=@@==:==:==@==::=@@====@@@@@=@=?@?@==@@@B@=@@@@@@@@@?@=B@B@B@???@BD??B@B??B?BB@@@BBBBBBB??B?B???B?DBBBGDDDDGGGDBBBDDDGDDGGDDBDDGGDBGBDGBDDBGBIFIKIIFIKFGIIKIIIFIGGGIFIIIFIIIGGGIFGGGIKKKKMKKMMKKKKKMMMMMKMKMMMKKKMKMMKMKKKKKKQOOOMOOOQQOQOOQQOOQQQQOOQOOOQOQOOOQQQOQOTSSTRTTTSQTSQSRTSSQTSSSSSRSQRTRSSSSTSQRSTXTXVXVTTVXVVVTTVVXXTXXTTVXXVVXVXTVVTTXX[[[[[[[YY[Y[YYY[YYYZZ[[YX[ZYYY[[[YY[[[XZ]^]^^]^]]^]^^]^]]^^]^^]]]]]^^]^]^^]]^^]^caaa``ac``aaaaa``aaac``a````aa``aa`aa`a`ccffdddcdddcddfddfcdcdcdfddfffddfffdddddggggfigigggigiiggfffggfgiggigfgigggifgigkjjijjjjjjijkjjjkijijjjjkjiijkjkkjjjjjkkmnknknkmmnmnmnmnknmnnnnnmmmmmmnnnmmnkmmnnnpoonoonoppooppopqoooooopoopooonnoonnonprrrrrsrprrrrrprprsrrrrrpprrrrprrrrppsrptssrttsssrsssssttttsssstrssrttssttsttstsuutuuwuuwttttuttuuttwuuutuwuutttuuwuutttxwuwwwxwwuwuuwuxuuwwuuwuxxuuxxwuwuwwwuuw(((RSs H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1+XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km$%kl_NSBitmapImageRepkm*ZNSImageRep$%.o.*qu rszWNSWhiteD0 0$%vwWNSImagev*[{-96, -240}[{-96, -240}[{-96, -240}[{-96, -240}_T{{337.35746699081346, 97.817201750418931}, {63.052777174092228, 84.236204214349627}}qu ~szG0 0.75qu szG1 0.75$%\PXLayerStyle*\PXLayerStyle  TO3.1.0MD[x@RUc!f@L!zty@9ˈ@f@Lݙx@ s?]@C]k7x@IpX_@K+~w@1q\@ņ?~w@;QH\@CTJx@ :_@eBw@Hd\@w@[@C+4w@d\Ik[@;WGx@qp&^@ew@@[@C5lw@ZbdZ@ffw@IJYܟY@w@Z@C#QLw@4m\@*s0w@`;bgX@0w@@Y@Cw@PrX@)Nw@5l$=Y@w@Y@C.Uv@ ʓ X@*[/$w@}X@v@Y@C,jsxVv@@TY@nsKv@ +MY@_0v@X@CJv@ӲX@ .FƸu@|šʀY@ع{ܫu@$PY@C<ˋu@aQY@zmu@rY@΍BQu@u$Z@C B5u@0yEOZ@u@E⩤Z@QX u@>[@Cct@ [@Et@rn\@Kt@I/Q\@CLQt@x23L]@:t@JD ^@è>t@[J ^@C't@[N_@x,t@|C!`@?d= u@ ݿ`@C,u@3`@0u@X b:a@JM$u@(Hgb@CSJu@^Իtb@5zu@`W)c@Tv@`)5bc@Cg_w@b@G=c$w@R>:b@o; w@h*b@C:\v@~ڎb@9v@ b@7FҾv@P8[bb@CXlv@۠0b@}v@tža@D#zv@WTa@C>aev@F9 ra@}}Rv@zJ,a@bAv@ϭ`@C*H00v@# œ`@fXl"v@TT U`@v@Vĉ! `@CJ#N) v@hvn_@v@+: _@4PUu@@֠^@C[u@<*'^@-ϡu@>Ǘ]@Eu@XgE]@CwK fu@O\@݁v@Ĭt\@ v@ !\@CCZ[@v@j2G]\@cv@U0 @\@jmZ&v@Nik1\@C a!0v@Gx"\@H:?w:v@W7\@Q}Bv@XF\@CaxŤOv@eP \@37p]v@еG \@qY+Tlv@`g\@C!7{v@0'\@!nCv@PL@\@&ܠ wv@).`td\@Cv@ <\@<.Ev@di\@?gFv@Wem\@C&CJHv@ a-]@^wv@omu]@:lv@{]@Ln)+v@, <^@EMn)+v@, <^@  V  bDA_NSKeyedArchiverVshapesUstyle_bezierPathDataVersion]legacyShadows_bezierPathTypes_bezierPathPointData_layerRotationAngle_bezierPathComposingDataXWS"+b_U"+5:?ALbk %   " + 4 C J R  ? K i u   # A N l {  )I\|&.579FKQSUW`h FP^ky '.7@CEG`s{****.*0*2*;*=*F*R*W*c*l*q*s*u*w*******667777777<7>7@7A7F7H7QCCCCCCCCCCCDDD D5D=DDDFDHDuDwDyDzD|D~DDDDDDDDDDDDDDDDDQCQEQVQQQQQQQQQQQQQQQ^^^%^N^P^R^k^p^r^t^u^w^jjjk k k kk"k/k1k3k5k7k9k;kHkJkLkNkPkRkTkVklkkkkkkkkll lll3l:lGl\lclplwllllllllllllllllllllݒ &+8@EGIRZ_kw */@Bb7QS`lnpr "$-/1357Kg ;\e+ + +++$+&+(+-+/+1+3+<7777888888,8=8?8A8C8E8G8I8K8M8^8`8b8d8f8h8j8l8n8p8888888899999A9N9P9R9~9F-F/F0F=FFFHFJFLFNFWFYF[F]F_FaFjFmFoFqFvFFFFFFFFFFFFFFSZS\SiSnSpSrSwSyS{S}S`,`.`7`D`Q`S`U`W`Y`[`]`j`l`n`p`r`t`v`x`hhhhh     o g*Z-^ '3c"g S  e  $ m p > 4`KBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerSizeInfoKey'j_BAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerIsClippingMaskInfoKey&`KBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerNameInfoKey%eUBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerIsVisibleInfoKey$h[BAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerSpecificDataInfoKey#cQBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerOpacityInfoKey"eU4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerBlendModeInfoKey!cQ4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerOptionsInfoKey i]4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerHasBitmapDataInfoKeybO4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerOriginInfoKey`K4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerSizeInfoKeyj_4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerIsClippingMaskInfoKey`K4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerNameInfoKeyeU4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerIsVisibleInfoKeyh[4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerSpecificDataInfoKeycQ4A3010A7-EC8B-413C-A981-143B9D824F58-64145-00016F7318EF9DB9PTImageIOFormatLayerOpacityInfoKeydKDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerSizeInfoKeycQBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerOptionsInfoKey*i]BAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerHasBitmapDataInfoKey)bOBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerOriginInfoKey(lcDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerBitmapDataFormatInfoKey gQDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerOpacityInfoKeyheUBAC473F0-ED6F-4ED9-9BE7-C56EE461E304-64145-00016ED0C0651DC9PTImageIOFormatLayerBlendModeInfoKey+eUDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerBlendModeInfoKey mDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerPreservesTransparencyInfoKey/QDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerOptionsInfoKey]DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerHasBitmapDataInfoKey `KDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerNameInfoKey uuDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerBitmapDataChangeTimestampInfoKey UE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerBlendModeInfoKey cQE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOptionsInfoKey j]E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerHasBitmapDataInfoKeybOE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOriginInfoKey`KE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerSizeInfoKey2_E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerIsClippingMaskInfoKey`KE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerNameInfoKeyeUE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerIsVisibleInfoKeyh[E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerSpecificDataInfoKeycQ E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOpacityInfoKey q/j 1 g  , e  ;qh[E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerSpecificDataInfoKey`KE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerSizeInfoKeybOE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOriginInfoKeycQE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOptionsInfoKey bQ E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerOpacityInfoKey`KE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerNameInfoKeyeUE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerIsVisibleInfoKeyj_E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerIsClippingMaskInfoKeyi]E4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerHasBitmapDataInfoKeyeUE4E66D51-EC0A-42DE-AC81-CE7F67DC87D1-64145-00016E66AA7EB83DPTImageIOFormatLayerBlendModeInfoKey h[DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerSpecificDataInfoKey`KDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerSizeInfoKeyqmDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerPreservesTransparencyInfoKeybODEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerOriginInfoKeycQDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerOptionsInfoKeycQDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerOpacityInfoKey`KDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerNameInfoKey eUDEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerIsVisibleInfoKeyj_DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BBPTImageIOFormatLayerIsClippingMaskInfoKeyPKшkNkNGlayers/DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BB.dataPT_IMAGEDATAAh@;N@x }9$D:QQA Df䐒DR)ՔRJ 䘘aƜvNp_{w{|}]+Jǭ\=(JRt qr>gJRT:>"9nwP*JRiy}L9.X)T*J|?9. \-(JRԮ[/ r|]7!- JRT*9ȟeP>RT*ޥ+w^yȿ2ÃRT*.-xcc+ '+{ uw7 JRT:g]%[yqO(k|y}AT*J~kc^ 3 JRt r7WJһF88{./c8c(i%N5JZlYlo+Vo,g(o>?(JqKSW޿[Q?zw|&KPrT*J%RCV~/зEq˾)[mguǕJcSz>kpQ,iކEOHR*J:Y{r+k/s~1v;JʹJ!d>܊?Z:?z=\%TwT:;O0/,+ ߇< q;BT:^yJ?.yQo.m3,T*Jyomn.=scjJRi֣aJ)gy A]{JRi>"xB ~pTڥ[!sJdO|U-?<7xQ_w{Z)h\1"ڻYoo Kw ^TK -ԍ7{f (Hqu0t~ J1frrܠm'>%Ξ o{E>O&bO +k{T뤋-y},j+

:g٠W@8y{e^:_}Npi@+1WZ~ 8a]R5f/c zbaL Q:q5A~ƭi=Uo@!coKO/y<rcEޗN[%7b-yA`_,∏ ʃyhA J'EgيkQOt(ɉˏ`8nPT=2s n{2 #?)Ṕ׭75ɭO oo|x oyׯa#:EفywԬu^c5iZz]yĭx3lR$cs||{{)0/'{:juckU"fy7 N<{j!ZZ(oiH/Zׂ|lP*<1K#w\*Wyxwr+_x4^<XCi¨!@}W9&P;߷b ~| žP<ұ˘"ϪW;k:Wҕ|`:[L` ߙ>fjHĴŰ}ƥϷD]Jǩk??yRd|1;q\\=Sf_6X[~jM? mO,CJ\|!uE~N-X~2JS_﷍ߗW]+]1Pל~@'yC+¯Fgc{ʏ_R|k6M__WgrCj[x͛]ZNr !5rx@{9LU6o\1\/o 7,?}xK|[:JA>>龹.rAm bͮ>kadI+ J|[z .YO;yqcsݾ7CzV཭vǡ? iE]A}I=\uEMsRo$㿚 J#swiқ@K~bR]2cĘ@jj, +M/k, z–ڥݿ x lž.NIƚ5d ̖[-ǥ){/yHMc0 tzCK%砯 ﯽ~JSqu1DO}=O-gӑM~E=(S<=9hq~` ]bnSNOkr*ݲ?fg-x|`?R4Nj_u >*u`"WnȞS~S9n`_O]o+^Ri-oݪ'mcc%NjWtz_{. }þ< ,旘[޶!e{h1MQ疯9NEӚp=HPsZJ7 9f ?5Bz'c{{Ҋo$:}Ip\ۗ:g˥+c>SZ=4Xs.}(^olTZW2r ֒5= wE kV&z&K\'PͿךP՛T:\˹݂%%iutq`Za ?%<'k7@(NE_u q -?w yp PR;ϳ1'Pc(uZ%)htynZAbIMckpTKSA=\ϾT*7 y̡wսeNMEK|P*NKYy-⋃)k]A\/֒!<"8%篂|-xjP{J-}ۃ Zu@|![FAb^UyNl"u1S:mhpT*x~/k|rc-v~[%ҏ3ύ.擭cאSk{,M-JK/}ZVފamR)8Ϗ. gNɯ EIbfCoQ>OT*ymo_}k /jK ϑmitO1pL@\]OU5RtZ2kzmo?֭Ky҅z_m}1Zߋԋ66'\'(J!뾺j i-S:.;\=Gxe߆ck^^ט' g^=J׾"s2z5do$/>T O=PI}VЭ>oX(JzX1.`A"<[Yg/KẶ6y؀n<% v zWTZ_OZ܇oJ-c둦&|:Z8QWREy =LĄ)`-鑔P1ϑ}!8<)qP*G Ri\bύx(|ję3ǀ^rUy[_όA^qRi9ɋ%koKSԷ׷1<E>}.ښ߷  d&>. f |jRi}v!gqA4Vy>m~"P]}{b\u3cnA՜JK5TK4E O]|܂dT֬~unZUFrO ԡϴ9ոgT*W}ɭ{ex(⹏ T֪ؕF6`ߓ]y! j=^*J%}^O xP^]ҵ%c7@(mÞꞫT*JGwዼA[W\5,Ym=N OϘ?;s+JJӼ7wCWe>nA6Rb" k> OeorzHOKp瀾CCmC_JRi]%}$Ǜdž@6Oeo`/*|z_36_SaAT*W_Pc\i>n޵%j^sﲞԢի=80+J2r}~y 5޵%j:?$zM c5nq}u+J!mBԗyJ,Q/|c\JZ5^s:cuqjC1kT*=)>{+cCA>j8qLxJy=S1An\RT&uS}k<~&ӻߟ7^^z[ xxIJwjҽ?L:?4SGA~o(kJx']V3Z`Nomq=7o м5!{ڣ_SW:zRTYk=v`N\xm`>M6uyS~AB W*J? ^;==%7:lSk/{풚(w̏?/xr0Ƨ0*ߋ\zk? >7(J~}*s0۾\0g^'q?_{ 1DC|7}\Z~.T*J(]Eǃ<?ua>ǐ=4~߉#!i`wO=`7 >8D\{fZ̃KR]=˿ H?<]ڐ1w"߬ Ńe7UQ ?A~o-bߚkWCRT*]}{"pǭ;x׆qSk߉~bZ6ϼ0XG'b1uS )ӿT:\;zZX|AP*Ja0FrKK"_as''`VTZRbGm7[*)+b}䜼yZяŻWL&|%p?.2Z//j`_s=h,o(AtmQ*K<}#X |Z-!eN&|%?l{}~fxr sq5r#_Tau\*%7:ίy@8Gjx4D~1ķ/3SSd}jMd?}Z 4/ "2s^;(ȜY|ݷ~VK53`sNPcx$x׌o .OW>d)zuA>أM>;[[o!A4F>O m߻nFYX*))<7+Xa|=Żf_1[zv󯁞bs躁}Ğw;ii >7ܫ{kEc,+ؽ+n~eS*-i_zTǺe߅XowMos֘(t[}f x:f`*o~}&j>"(W9/nwSiJm<8_Ij{x88TKҽ6ޅ52&W\s8{ngN_}S ͛s۟jK}ⳕr7vQ!T*J |"Kmj qא5Ƥļj\һ֞9{D 1IW+`9Cm}[[rJM yqoJe_9HOgַYkߵxs~H | Kco(s={DOXLn˃^z1GW[Ybv@Gg?+c}W\*Nb0 6j}c|ct zce5$Ƕ!_w1[} G*{."Nus݆_K;6ᩳ?T˜~|ǥ|Cn+J8muN X;˃V^"s]́˳}z>)-1o0t`q͠tCi7dS˛^*s'G.Q}}[>'hxX{\<KysÛ[b|szy/Fݣ9:@9quiՍkͱ۸m "睥1/'vw\zxx.*׺~72Kk> Kӊ+k7nK|a_:/}B`6vaW}J$U=U3ȿc | t^~pN0t`O1iJKc<允9j>dLcy?>uz<߷4#%o9&q܏͞}G'-xpt0_mjnJcs"._xo XzL},Q#uh CBĺ6sK/=Ty; w9Er<|~ GP:N? ]o'Jc<_8߳$o&A_׳ջfc*%Ak˃-=S㕬eͦv<.S3^JcV_r#Sy o{-5q֡S*s RRG7._ Y f. oqH~~.Cp)_g4s{7&Ξ؏Zks웟8)߿zS>+o<7:}臂[]w˯qj`:] sK~qs[믖[\ȗ֑О]6KS> &9wW5| VZ>(]Ρ{̡9}Yu YKGy\}wO]^bRri<+NEz幻{=5q? Żf}'Q=.|og|g ٗ^wV~ >H,jзq抹JE<21ux8喙EKAGkě _+?$u5yPW{2p+NI" wtPwMuA>kJ۾<\,5NGkoOuθJazu_D |^;zI}io~z|&M>)O 8=u5R?b>ԝt)\ z(ʉ@o~Ϙ.{eNY!?HJ3'ZkOME 듂_=]שs1{3W νkck˚M-}oQj"Y`~-3&nj4&{>ŽkS.ֽxX!7U=g\{)?]__]-~5#EJe>k|ZyBpcvacΚySõl#N̋59]ISm .b\]Wɯ~4g13E{!1P?(iF Ow }j允uĩH~8-M=.]g\:HOW96V}ix[+Z樭\z`oſ]ϚK~|k>^wҟPdd)k{_4Pgfpr8b}zLA5oJ?^G uŠz_[pr AS5y9e'5[~/s#ȓ|♝zϵ\ZDk)sVşQb꽝{U]bj:st=Y+&<^y |]mlƚAk|=yAׇ湊+ֱt!s=RW :ߒZ!'G˥yĿe.v"^!Wo!i.ڻi(bxz55c9*ss[kl 냏Y\ĻX?ϕGs;5{!/rR'Oa_-}xӉ_2k.7.r:cC9㗘T~fk`ܔu!AN̳%Ԃ='^kBc4~7l#"q|޹pWse]^{s[<ʮ#[15{P9B8:3՜[jN-eg +~ _љ)7gR3UfM' bi}7/ϥ^b|=z. u/9?o[+7֧gH>uߩn!jOGzh-5BR\sr:8DSA`(cׯ{XƢR&0k']\{O밾7N[Ky1㬗{s̓=ʽ^+sa/MMf{#o Wۇ{^KxU}zrl 搵xkzyl.NMjR7寃1U>0>9֒ؗ>kHd*v~ }rb y{ux/QXkޔY~:$Ǻ|e̠o*4%6?r 9Wއ˜1=ZTd>,zD1T bskr}jm2F<6[@txαZy2ƹ?Wρ!t?.?k}Ɵ9$,(`Lb}ā"_rQe 8}~1}7eۆ. ]sKT̵*Vcg4<Ʈ)rއ>/|<*s1{m>a=1h\va7fR0Ujy)Ͻ'KUc^m׎@]yiA19HY~a.w$<id<6H|׀g;x!ϻ9}Sc: 'V6x}Č]gK-%p1oT`Z]xq]^!k]}7ţCK7uq/1uӺ^7g-8ƥ".Z{&k9ʖ1Y5O8ٽ)y뛂&]9&9GHx15WJOWN_Kc*y=HlMw[7YgvOۛsC-1}V&?[ᑒU{aN}bij[š=sM뗚"Gy;2uQ@8ُyţ5:ľzb>c% } !TŐ\^DٯƼwRƽRggg gqZrz3Cs'q:;^:$zE7Cx%Wo4oY9u5y]S+){tI֭5nٖ%k/ňF\[XŊs~2M)Xqۺqʸ~܆߻O 9|pcR,'*v4^r1U'>@,?C`~!7W~x@Η<ϵx`n-PS5^&nAz/せr_7vZYnCֱ b~ḿ|bzCs/%X[ŏ:<7|<)=xyrOs}Xψ㡜BlĈXk"Zgb>.%߾!{P{|7%{CqVc04>YۻX/76OpuʣQ߸lNA5+q|<.m<)1Je;%<#bgCbjyKws >$n^?Ws`sWFF-O^Pd.6 "n06/O@Xϙ!}B!TwOu4byά9W3s,8\Af߅8^> yQu3?Zݙ?Skcw"ޣ~E=Kr:cn 9߾Y^yϵxVիSU_kAŞo gxHN,&ρ1]b<8f#ģx_'6\}Jy/{W>:>^q{0ɓ[nhsͫOԦ+ϙϋZk}SDtLjz<=kx5O'#}(r9~e!1SB^|x澭.GZo1UnFOUYͿ]55Q;ԟÈ]tO?s}`D>6opZy7U]"kq<@枴Oj+Է] 3-Rg~k9Yu[?+R#֞xT`+?ש]<`z%q^;)]Ƹ̳{?E-kJ$\<=jKsHy^ 1 .]C_ycAczmꍌ ѬJ!ix5bz:'?v̟n^%G؄^~|'>)~9uXӋy@8yI6sy]>ޅuЦ߆}Yk7c#IN֋|v޿9e}~7zMsųfs5_؍طX Oqaf$edμc;sk]52yηz̍M5*ε)sx ܃{s;TwMMr+ZR*FZӝޠG|m#G7'r$fǎcXC{bX/.ke!!Os.'v^ܜu'#6eMxxw? jK<׀:7PK_BRgCanEFy891O-oy3PszSKbu<9mia>:Żfn,_wlcY"3{OUr&iFKJl[*@k!yyG>GQ1qst1rهc"<>^r溼)Owkm͗' JCJ<غ/5xNyݍxcre>s&/^qD1ns)5JHYvO_ Zy}eS1O{?{|~]ʺ32yb)m=ki-4j=*uޢ8&ėT&K z;˧@[5vc[Иҩ˵iLzi3.%y4ur<3F}~j<zQo,˲[9Zͽ.^UoMwt~o r= ,E5qb/ zՌɻ+[ý Ơ=u^QO5#;׎4sJROEIkzwIO]^_}>D['X-syޔAz)a,QflNj[op֝ $< )8o<ߣ B^˼vI)0WL5΍yĘd֝J$c<_%OfsJw=O|=čYgNKm>`L!3oҏ<@_srSϸ9wb>b4zΈ$7UKQs-&g Z{%U]:g鑸k5r}iP10 K+&g`jަJ}C/5)Gσ/#vMy951{q5)ZwO>njK+ykyBK\˼T:z5.FăՑE=X7rl#桿Ͻ|Rb(}3{G| .0;1bhmwtL?wVWe%͙xKAbZbwn[߫'vu|+Qz[E73/ME~.5d ǻ1~ˡROo> @X{x_[){HɉOm|Kz TC&+n-G{Lj7C>F:ڿT25 =SKb)B@ |{ {C}|rxyycT̽4?p_.7^=kXkT5W1o뛺|һ$.־7e\o:x챥\͞bw 읪GW Je1&@xoɏi5<.6T\ymtʞ׸Ԡ1xAuZ{9Z7;X=b>k bCV$mf#WaRV<>~%R.l ꍃZ'K+҃A_^*VּrpՍob.U]*&V^#ЛښٽsVncE1]|_} bm>E?yT_Tm.R%A^#}ÓsEq l ~-;'+@/z Ĭ/<wRi:ZXc0uTy| f&( co vM+-@bz$o"FDJRl#)L[b]3V_ZP}Ք =+ޗU]*}]gԗ)p!"z/V@\|uϱ ~RTky݌A,Xnm@}:wܺ/Uŀo]ߥ0WS^f}JQ%K~Jm^kxM=wK꺁u>?!Qۮ}Z؛Yb1}լ뜥(}^qyRԮ[kP6R}awуB?*G;i|}~|r^_4뀗((.Gͽy>Rߥ4MZ<-8}gDQ=*͏Gy@^`ü3˗K7gc/rx҃h.D9 ڻ.=Ω E? OA'ry\g7tz]>Wv{]wߩ bz}^g݆gH mZifh gLj c/`2No fbeChtEđ,MZWpc(f0 Eޖ.́xұOUѴ[^ٶD{ @Ib$TLg\_<* 0yvծ F>ou d$w_Y~L <.Rh3A`bocϚ^6}^x cUH$;e|pvf߼ CM iC@.AT@|*L~N@ n@q9% Hv@J. "$E&@O*!,@ǜHA#HC71k$eѝ b,#B6`6&r쉰 q,8 $=%$@Xl<:_Yp9(J"y 7'0c󒲞TJ n S̪QD:H%E4̡H M-d͙5K XZ#@\V%'oRpIzxOZ^ |Հew&ܕbm9)ND%) @Vnh ,W@qZ E3F" Q`!y<@4iF*uR:uNT!&6TOd YSҴ@ qt @' +HV/H_ cVX%x$ @ .T Uld][ MBM  b؛bP51LCP4UAVfBrUV@ Tel" &Rd[B/)K%Tȳ$,gĈg8@  AT. CN)@0 #(R4 `9|i@P7 ~Oo oH֓y07 Tj7]jWeYUm[T ,n0t #Iկ8 `d$ 'g ;)@ϐ3lix@6WIiV7@ 9v,y07D s@ܼ@߻ޗOu! (@9N LS{>W1[0(vNApdOh% aYCpZ~9l9Ec-븁4DE?CA/Rv/* ܀j1r1LmBn^\ځ$9!*m flOHsAPt"$Fx( IRl06h Oht e @:`UCWUskZaWXWuY t׶%c, ).3M? D*W'=k!nN `-H`mB2Tƪ쁚vy+ɂ QH[y1^x RWɨR>+^%"4צr.fzd)r:Z:c97" bWY{jǟhz#u;a L](WsZWx4@G'U|(ʏ ,[m HSHXjH0qHq| 4̈́@R$ tF$(oEAHv:9`)%p FWsGbF]X ydEab" !^_ڵz o^?@'+ %@nMKB|{ƨ7{ \<:$T5 +=X d Q1VA  @!G@B8!dS& |N@wQF@g א%d#qTdTkN6b(D !c:lCG3qEM3B"8e$$@Y1=xLP h7l@h&W/.")2V9 L6bZe o8̩e\,UὲfHw\$ @$wCb{"nj@"ԛ*6  0q* 28E `qu6:@P!*@y\8tE*a&?C r.H.0C5 EdAKM JZMK A聅daYX bPƪ^KT1nR}ǙL^ =T @d6>W&j-ZrO݆/rz;_j{k M!%gܠio0/0OK !oB̛6EDPD P8$ BaPd6DbQ8V- g17hJeRd]/LfS89,3%3 54 UI8@0]v%(.j\nW;I@ͷ[ #w`pX<$Lhpdkkh#}tzPg =uu \w߭jm ]j+G J TB(nwf# z>* y$$e C Z"d 2ΰ#8 `|R/ |l2K@ %aBy G B* P; n@@a}0.\F!T Cb[uLl;h\XR /MPQ6$w`)aDB#ih)!_& @)}0%LjŘ`D/>pACH%$6f)t0HkjU"9K$MYW-мv lV &Bre&@YDI$fYy`ģ8e iNpK@ޱI /`br"uю )ւ0Zf/nOJ '1 A*K@ZF`uQb4<'*@SP:HK‘9t$iH2= &~]) _TwQ *$ f +R GiF%@4;"RaDy$~ J+0Au^L )\[_u l "1Jz 1A mch4 1&1FYbXW /fB ?b :2b ,Z-( p l $ ,pu* O Ɯ7M$ k)+̪3jCPrāHD3R:H &/1MT$RYF c{A dPh1,( .ԘTy/:bp-5ճm+j,ڴs ]M(Ap{"~Âx.q >02m@2H}N)]% c_ m= 1^q=3ʁs $Q]E@L ƖI]:~0ƒU@5` ƾI0cYb H0" پnhaF d4* y V x\3Ӟ(26nh4TW([ep#ؙ fb P52ӊ fY=j,k}Xr-gIlh0@`. gR A1X[ dOvn &u(0 ¿5U=12A;逎0K+DD/H5쨁 \/ X;bU+p 0R8`$qlxh0{ 3rRChTf}`Hp"qDrQj.W\@ʯZ'Fr&dtHD8K:K b(bOz"N " Pc_5gE^@8b ! ˺B+d@չ*q6KNg3'DrȄ.Hj+D2}"zhql[nϦ%42fUrl=P>sl.A 9$ 5!RY8Y s*y<9+jkHAc繊=`F օ#@ xi- @ ꇫwk.V^&0:]I D$T `!H R bi/2P`%NJ4H5S:SYHp ހǟ FgS=jMPCƟؤ͑&qi[ vXk oH]r &|D~xۣ0BkJy+ L\Y]J^VAL #H4j QtY3Wrb:Y@xGuU"2TV*i{dd߆ tYH$"41~UֳKpX5ƹ 1 +/HM&[;tƸSm hcz"aK`H >pT(30I.%im7q@ l $1́l/|W/Ja?'ٙpg2[fE|gڔxg`q^%Si V_my!g#D` ٬@}@?UKfajD9@AgC@=^>Klb+ZW!& q6I;j;ȰL&@e*#+þI`EHWCbT¼; m?(6iE>Fqx;$*+p;r /B FVA 9&C)7*.ƀd]Hځsx Q}uPc>QA6^2 ;_,vz2A>WK.LL <cGd1OHOE LJh=3h RBJ:۬d&`GyF_T9=-7 ^&J@ϧO~mљ^{{P-H[` O "#ĒjBtB=b 0@9){H8D=[0* nԺKđ++4.2C+ҧA*R-6 97+x߀M Lý DlckA"8hػ.F8$ԡȔ%5@PAQ}8 ?@5mB"`[ 3-~i4<l 8ސchs!  DIĈI©:Ɉ30;Hj8HG*TtPCZx1B 9 l"NyPPd JQk #kU+!\ =&G?1K*:I)iΨY;nQh(́9liMRʝt.pF+k0 4[^n 9 ㆵ@YQP!誤OX$ޥG8ipJR=\շ*s 曛Q0BLOчzU_(M5}9sD;ՃSּ~ԷBHo LNq}֘@p DJ6 xI&i37C;0/ ~H "Zy##J6h6iS(tAw%( BW (J7Tfk^KzM> CDzt'ةn^8%Ok5Keg a[Ϳ45U>2ޙO͙TJXעkn6I(8́ⱇ8K\ OyqaRfgP6Mv ,`,se:^+wu #^s HF*-̵TքÛ֣!45j8 Iښ{ǖFA:s ۊ{HK)9^+A>v_ȓܣͣ+)e쉜(s3 9T BJ̶ UYYJUi*C'D{=Uxv<ފ6JM^ ҿD:3j 4.ȏ{+{8TF=3x-d<|isT\ K0K 8 "t|%[Fd%3C#PF(r`TBp%|Wj?!ߥVnٴ~vݔ%n3%fC-M I== / JR`^FW x P8$ BaPHfahdV-Fc}R9$X{70]/gngX2a?I3T 4PaTjR@| 8U:qX05 ]ZmVe2,n'4<&J 0 ዂ`L(!$R˙|w=kJ%9H_"m<#"8 c\>'3qI70 @̐0w:Ԭ@א0 һu M@–l ~x"@ſ(cjb f JeZ L K*BQ}D|`4N 􁐱 fTEƉ,H8h D-JJ*eb*Ʋ ʁҢBƐb1?1!%9 fdd98$:<ˠOh$ ΁dH7ET-LҨ^_ !'/ e%O]R@2 @,BL rUyg-(RkH*W$6 Ja AJHyhKA2C b(h69BRÂu+ȁ1h{g; `p*tJ.(YH*IQ gr[dye>e \PiXh6YCy2-Z nA|C ]g+΁9ʁI|W vJT rtz6 m7 LEKAXԇDU:@`dZkN+(tEр X&Օ`v'( Q ;BW~89k;j_@\Ok@DAo_uRg  Pd(HcHTn2ZDo@o@ `:ZH7H{D0x$Z@$h]D 4AlAk$@Il1@. &[Ӓ--CnN N9G bhGnXVb `‘<{ qP "S@W^BHY Bࣁ `v 2y Y!$ayO܁"& : '0*R^B1KQlx ah@IŰCZ=B !tnm4]2t E$LD| sT)wdZ(E C-I=âuN(!?F0mX>[ pF>܀)t6^zHY,W@y./0ʡ *qɥQ4fz O :7"؁jZ@J3S)&b)s]j2o-rMKYLI >Za?#]N*"=ZhS=֢<WΒ62$Ik )NEk9j ,sFqBp+| . J g dr.|BƖƷ8^5V7'dӵ@ݼdqPR#.Q? BD$r{8L}[ -KmԬYX7W7B6_A65=-^5ArYi|p!'UQۇp$ K 3( N%"´LTUb |\dFl&).z5a􀁂ߓmT%s@2  h6@QV*Օi،Y3 @}c8376ɪh$L]P4.[2F[  b@+dD_ I mNh쾌L2d{h@9+RNMQ fdh$J#!-]^eݨ$3Td -_*Te D@sě},ˠr Ehtԅ<iuA=9|њq0rX',ER}@ׅW VԒLAvd[sz>bzjWc j&NLa .:` m]xxՀ? XWΙlO*D@j->2X{]OkHe SĦ&J$xkI|A@u-ٓq%IN0%sySK0H/%6Jir b֏IL'qfo.EoRϢevFx9̄'Bϴ{JoFC -r0J{ L$%v$v" 00(LB^ьBL-I%,t+$exL(#>lm . r$K2-2^&BH  $%-T '-fz @㰶.TL o.32l| "Q| a0T$:4SU5dh"`& Q$% p-+~-n5G58x଄JPc؁09 $' 8,3=s>KUFQ-2J$,$X SL-AzL 7u=jgjş {63$xn ,T$2 QtKE`0BF JsjHAI.t)Լ"~"tb rt~tHTd- # {Ex} "H!M*Inb# C %_E`:H'ʣ N wN(BL|xW01Cςxl>@Ik+MGf3TaV"FQ$fxF5%Tf$n /Q-qCVHm$~m t,K0Tq2Kb9M zt.^ʻYE.{!&]!*Fb 4}BH7-6xr$-L?u2G2@):T(291fK?ai;9C.ssP3J$&JVJđR<6sn↭<I{sf#Q"F @$n;Cj?IabbMant Kn6FheFN~hC{*Pod!m;cc^'HX60Wd5Vvg*LD/GtI{ssq70{v7%)֨1Ppjws`w~.j S99 _KG QP$d^%-N2I-S|j{N]BhLOϗw &Re9M k`-:( r+w"bGYFxuj(2d%XLW-o_jVKjvXK'gjRltf.9• T3lߑ~'OF@mwK$hS .ςH0kl][`-͏I73KsDt S$d9P{y "4{Fdch"M 86ħM`Uk"״&&ۢBo)Xn$&"ΑD$lQBHp{LP ټJHlGBN B-I^K"BH5;oɉʰ丵AάgO(+)@F~H/BFш44#8-F*-ULەn8зQ+ Ou]E{<'c8+ZF!{I֊H.2 ٶp RH gf 2Y~%Ӕ? K$R\a-E-6ɩB]D1{Fox0=B-Bb38a$3yn~1BT&{K7"GuQ ;iHBK +Lʿk/r (S1t$E8$q$~0P%uBX0G+WyH r-hyWw\\͸Ӑ>3bk L{J؊ڻjGw/4Dnf}~wjoڢg v;Z9-_ r^ E"G̮Ȥ%қ2YY8"Ѓɳ"y\$o=+-i$%(cÒ,ɣ Ń1pg.al] + m mH2 +" 3ʡ &`jv dg`m<` n0׉|_SC|a҃(164 .0:xS I - ﱤ1 .|4 f Rdn0&H0!(HJ `R( j2Ҭr4tL2"i*@4\Sk23 |N1˔jϨI?NJ x } pɠy%ы]Sz& TʩFjƃ0/\4•0KW5w^Wvh4%_+$FHk ;H؁(G Ýn(Ka͌1(Ёrl:(1xT]KHȁh5H0,S/Wڃh2 gB g=͍u aDB=_& b0+*h1 d 6:5^lb&Yj(H0Oi:; 'p"0` ĭ^HخWBa ā՘,Y= w[ p",]i2#;-w(ʈ0& ԁbApF0&Vp -p0a kIⅧu Tϲ蓤*;(z< VSD J8?)iW"4"L3͆PrUZ.o"H eΌԺSH-+B6(@4IFAkd'4ÀK 2 Ԋ3"A+bt|3ʚcj]U4 9ȊX@S uYbZ@"P5r8-*Ph N)j\;60&I @&6$6YT1 OH"W R Z41f}8:$)ao-Q*B(#b@Ն3Ќ޸suEF]_EO j9GVN 1[`Hj/TdlDN PE[%9PA)S"'b~Hc5f.P28v$=`ÐD'nN]Z瀁ZE uʸGҵ:bcT a,PAXy(N@̵$QLH$kck SN*[;!|UbEX5 +bzvIoł 3e.,g@u - e͸׻h2 |@"/}2卣k ]30 `ZlQc"crBH9BhN{@˅7 |GX8pXe۸Jfo⩽"SȁҜB4/mB*rZ"5!=azb6xgRMv͖vq<mVU H7J^MޗK ̎tf' UPko1:>fc{xq `=vHbxg"DD?E@?3nfeeʟ7A-fliZl FZ?(3/*2DAr 3i @h@8?2 9;D|0i<؁(-ޒϠ3⺫yp84|ص$z`Ƣ.A&qkF= 0;Ԁf(ǖG"0<"y&&;"3Ql3r8 1<V>ц=D*1ByK#:(0;a;"+KfDjZn+"<45'P-R.y jlD|^^,?R53%,­3>?b/#p 1ȮPPͫ i؉Ro&!X[JL_ǀT!+dzTѐGiH"ty:n pƿnj ؁-2WBA%M+ hT +-BH F̏T5KJS53QJ2'".:zz.HCa4.+ћ*=\KKpB!ҀqFxƟbtA=CG LLx;TY:L͐L@(LCꄪ?-2'4"PZ(Ƚ;;3|Nፒ)C:k1O4;\r ٽTs|<-%Od 4>GFH)k<F{<`B (K̾\74P Z7wLI~SܷCS, d B+sBPn>!C H{.RF{QD4t:mřrXǺ1?}2A-.q }4ɵj !+Ƌ# 2 rĜ>۰H4 89HTU`Y/@[G?]4=&`ƕI݉X\KLPcs;I )P(W?V74,X3qBPBeZԇ ڂ+ ̊XHMK,<<#?[\o@L#:l#<ڠ$)IbLE[mܠ@;z;׼U%C(.:X\B @=nVܭ߈oL⟩}yە}B|[$3?[S>S5AM^2[@_7 ۤNfM 6|-@8F;XT[CYtG8<\`Z`r,[tRlZmQ@P N*LA"uK_§CVaaɤ(JZ \| r P8$ BaPd6DbQ8V-FcQv=D3 eR K>@QIc"eq 3|+<1WH^6 ^@ڰ7=f@ W Bn̢0 χbjϸ`O(R wh n A![{gjwVz Á5 wtz]>WY3 vlRi0) e8"fhHFH0YdP |Pm g,,+ `[@ @F)GǑ|0#Iԁhҁв l~;hFr a, Q, 80dkPV b;=ϓ1 OB*O6$hb‹(T fVb6 M OPbV@ n2Mc% 5(1R Xh*Xguiږ5FK* G*r vp Gs[h[c?j [*nf3הEiZ6{[KtMHRH1*n@DO*swHo9Ɍ# N05d@) ]c B聋2 Yk.l( 1Fl@$k(t@ށj@ ' T8B!M aQ`S\hr"vTe*; O5l@O /pW`2H mH,@51}9:@G$%C{r:! slmD9m r\˷ʾߪ 3@dqA'6&y_ SH)Ҵ+%KفL*rNY9ʏB 5(Ճ6}'D xV hLN07|T]0Plchan"G2dɜ$1@$I(B04"@t$ ՀKKrO) S؁8zrcЬ`e)@AH ڝSkn-B٘NOҤJ $UPIHIJ:+uD WZ]+~o΁WӅ@skLaE ec=.d28 vhg+.8"Ra}$eO%\f5٩Oڑ:5VYX (‡ۧuJIt2h֢k?Z$!@$ \E&$@>j9%:$wF L&0KTuR̩D{"l_b45`xt =7o [N-4  H.uqYG*\&xWO'!Hb 3 W-g\e->$j4~eva-i .d7UE r۫7;=CvH8$8VA- ܙ٨5ƹjS6k@͛b% /Zc e0cUʅsru[lG:@DLz.? \$ ŶPl 2N o>w[#Mu ]xG0ML][ϊq^,AZk7 ʵy)i2Z&/tlV%$P](4!426FeqmStZњ+Kޜ'pKX̾:<_O=RJl=*CGD܍\ A>jg\]9mKrx\u8l"H-wJ_-|"й}=1f/J`.jT4ԩ͒^Ch} fܨ @Җ-l:ߟ ,< 9? ؓ>wl s.-δF\U-_?Z`5漡漡\J M}dv |cO0M*PJk (b'\> g3cj`L ]ngrTX; (k &c|F5(v `t pCR_/+ lK;ʱv/$.P 0!\ ` o-; b>k"4 Ojb:vrʆ5kfBN BJ I,G q#9\,QdY K'r^!Fkck  "E"t KV Z(jO (aH h Ko"W jX EEKڻqlb .`5-!"(Ȑ8b@@ e"Oܵ"(( r4$(k/rg B#biC;S:ӧ:%$ AQC@t>fʮ-=q"CT]EA "*a^9Fl{R䪯))eF :djB)Bԙ,SH̅ϚGDTCJyJ%".)DԥMt:` a8#j@d TMVt#I3OIA:TZLxmOaGў "i("4ӕSu8%gG#1 j\ ;UAIBVV`#iG l >-!wYu" H%UV H koT-YvTP'WV;  "b G"/)^u!Xb@uUdfb1 5`+VS=O3aT$j"N10 c5>° B 5u5ScVQSnWOԗ\V]V]S!.b/76Sgv ]cPu-xNJgi(u4eaF]2&Z"iV[`2 :G-,(k{`GQk6ml5g-Enu: (uno 8qMM13pShJ"J@ڭoQOKw(,043sw=r;rq7Me_3&"3t]Sڸ5D:$cfsGs?t7At{wW9t׈_y- "L*/YWz5 "`by W3θwxEwy|w}xx7v1{zWO mQ)^W~_`S)#x|W}7}Wx|7woCR5c#5`m| R+4Gh}]}xeisqgXuyJomƱ Gi>Blo̲X ϋ8o8}aX`sXم׍InX厸"8x9EdaMX9Z\%x-Yy9<[Y)M%g?a9exIEQt (d g9y9y9y9y9Ŝyɜ͜ѝ9՝yٝݝB_` @_=RS`C#K+#NPK"`"`QuickLook/Thumbnail.tiffMM*_D P8$ BaPd6DbQ8V-FcQv=HdR9$M'JeRd]/LfS9m7NgS}?PhT:%GRiTe6OTjU:VWVkUv_XlV;%gZmVeo\nW;w^oW`pX<& bqXf7drY'ry\g7tz]>Wv{]wߩ bz}^g݆gH mZifh gLj c/`2No fbeChtEđ,MZWpc(f0 Eޖ.́xұOUѴ[^ٶD{ @Ib$TLg\_<* 0yvծ F>ou d$w_Y~L <.Rh3A`bocϚ^6}^x cUH$;e|pvf߼ CM iC@.AT@|*L~N@ n@q9% Hv@J. "$E&@O*!,@ǜHA#HC71k$eѝ b,#B6`6&r쉰 q,8 $=%$@Xl<:_Yp9(J"y 7'0c󒲞TJ n S̪QD:H%E4̡H M-d͙5K XZ#@\V%'oRpIzxOZ^ |Հew&ܕbm9)ND%) @Vnh ,W@qZ E3F" Q`!y<@4iF*uR:uNT!&6TOd YSҴ@ qt @' +HV/H_ cVX%x$ @ .T Uld][ MBM  b؛bP51LCP4UAVfBrUV@ Tel" &Rd[B/)K%Tȳ$,gĈg8@  AT. CN)@0 #(R4 `9|i@P7 ~Oo oH֓y07 Tj7]jWeYUm[T ,n0t #Iկ8 `d$ 'g ;)@ϐ3lix@6WIiV7@ 9v,y07D s@ܼ@߻ޗOu! (@9N LS{>W1[0(vNApdOh% aYCpZ~9l9Ec-븁4DE?CA/Rv/* ܀j1r1LmBn^\ځ$9!*m flOHsAPt"$Fx( IRl06h Oht e @:`UCWUskZaWXWuY t׶%c, ).3M? D*W'=k!nN `-H`mB2Tƪ쁚vy+ɂ QH[y1^x RWɨR>+^%"4צr.fzd)r:Z:c97" bWY{jǟhz#u;a L](WsZWx4@G'U|(ʏ ,[m HSHXjH0qHq| 4̈́@R$ tF$(oEAHv:9`)%p FWsGbF]X ydEab" !^_ڵz o^?@'+ %@nMKB|{ƨ7{ \<:$T5 +=X d Q1VA  @!G@B8!dS& |N@wQF@g א%d#qTdTkN6b(D !c:lCG3qEM3B"8e$$@Y1=xLP h7l@h&W/.")2V9 L6bZe o8̩e\,UὲfHw\$ @$wCb{"nj@"ԛ*6  0q* 28E `qu6:@P!*@y\8tE*a&?C r.H.0C5 EdAKM JZMK A聅daYX bPƪ^KT1nR}ǙL^ =T @d6>W&j-ZrO݆/rz;_j{k M!%gܠio0/0OK !oB̛6EDPD P8$ BaPd6DbQ8V- g17hJeRd]/LfS89,3%3 54 UI8@0]v%(.j\nW;I@ͷ[ #w`pX<$Lhpdkkh#}tzPg =uu \w߭jm ]j+G J TB(nwf# z>* y$$e C Z"d 2ΰ#8 `|R/ |l2K@ %aBy G B* P; n@@a}0.\F!T Cb[uLl;h\XR /MPQ6$w`)aDB#ih)!_& @)}0%LjŘ`D/>pACH%$6f)t0HkjU"9K$MYW-мv lV &Bre&@YDI$fYy`ģ8e iNpK@ޱI /`br"uю )ւ0Zf/nOJ '1 A*K@ZF`uQb4<'*@SP:HK‘9t$iH2= &~]) _TwQ *$ f +R GiF%@4;"RaDy$~ J+0Au^L )\[_u l "1Jz 1A mch4 1&1FYbXW /fB ?b :2b ,Z-( p l $ ,pu* O Ɯ7M$ k)+̪3jCPrāHD3R:H &/1MT$RYF c{A dPh1,( .ԘTy/:bp-5ճm+j,ڴs ]M(Ap{"~Âx.q >02m@2H}N)]% c_ m= 1^q=3ʁs $Q]E@L ƖI]:~0ƒU@5` ƾI0cYb H0" پnhaF d4* y V x\3Ӟ(26nh4TW([ep#ؙ fb P52ӊ fY=j,k}Xr-gIlh0@`. gR A1X[ dOvn &u(0 ¿5U=12A;逎0K+DD/H5쨁 \/ X;bU+p 0R8`$qlxh0{ 3rRChTf}`Hp"qDrQj.W\@ʯZ'Fr&dtHD8K:K b(bOz"N " Pc_5gE^@8b ! ˺B+d@չ*q6KNg3'DrȄ.Hj+D2}"zhql[nϦ%42fUrl=P>sl.A 9$ 5!RY8Y s*y<9+jkHAc繊=`F օ#@ xi- @ ꇫwk.V^&0:]I D$T `!H R bi/2P`%NJ4H5S:SYHp ހǟ FgS=jMPCƟؤ͑&qi[ vXk oH]r &|D~xۣ0BkJy+ L\Y]J^VAL #H4j QtY3Wrb:Y@xGuU"2TV*i{dd߆ tYH$"41~UֳKpX5ƹ 1 +/HM&[;tƸSm hcz"aK`H >pT(30I.%im7q@ l $1́l/|W/Ja?'ٙpg2[fE|gڔxg`q^%Si V_my!g#D` ٬@}@?UKfajD9@AgC@=^>Klb+ZW!& q6I;j;ȰL&@e*#+þI`EHWCbT¼; m?(6iE>Fqx;$*+p;r /B FVA 9&C)7*.ƀd]Hځsx Q}uPc>QA6^2 ;_,vz2A>WK.LL <cGd1OHOE LJh=3h RBJ:۬d&`GyF_T9=-7 ^&J@ϧO~mљ^{{P-H[` O "#ĒjBtB=b 0@9){H8D=[0* nԺKđ++4.2C+ҧA*R-6 97+x߀M Lý DlckA"8hػ.F8$ԡȔ%5@PAQ}8 ?@5mB"`[ 3-~i4<l 8ސchs!  DIĈI©:Ɉ30;Hj8HG*TtPCZx1B 9 l"NyPPd JQk #kU+!\ =&G?1K*:I)iΨY;nQh(́9liMRʝt.pF+k0 4[^n 9 ㆵ@YQP!誤OX$ޥG8ipJR=\շ*s 曛Q0BLOчzU_(M5}9sD;ՃSּ~ԷBHo LNq}֘@p DJ6 xI&i37C;0/ ~H "Zy##J6h6iS(tAw%( BW (J7Tfk^KzM> CDzt'ةn^8%Ok5Keg a[Ϳ45U>2ޙO͙TJXעkn6I(8́ⱇ8K\ OyqaRfgP6Mv ,`,se:^+wu #^s HF*-̵TքÛ֣!45j8 Iښ{ǖFA:s ۊ{HK)9^+A>v_ȓܣͣ+)e쉜(s3 9T BJ̶ UYYJUi*C'D{=Uxv<ފ6JM^ ҿD:3j 4.ȏ{+{8TF=3x-d<|isT\ K0K 8 "t|%[Fd%3C#PF(r`TBp%|Wj?!ߥVnٴ~vݔ%n3%fC-M I== / JR`^FW x P8$ BaPHfahdV-Fc}R9$X{70]/gngX2a?I3T 4PaTjR@| 8U:qX05 ]ZmVe2,n'4<&J 0 ዂ`L(!$R˙|w=kJ%9H_"m<#"8 c\>'3qI70 @̐0w:Ԭ@א0 һu M@–l ~x"@ſ(cjb f JeZ L K*BQ}D|`4N 􁐱 fTEƉ,H8h D-JJ*eb*Ʋ ʁҢBƐb1?1!%9 fdd98$:<ˠOh$ ΁dH7ET-LҨ^_ !'/ e%O]R@2 @,BL rUyg-(RkH*W$6 Ja AJHyhKA2C b(h69BRÂu+ȁ1h{g; `p*tJ.(YH*IQ gr[dye>e \PiXh6YCy2-Z nA|C ]g+΁9ʁI|W vJT rtz6 m7 LEKAXԇDU:@`dZkN+(tEр X&Օ`v'( Q ;BW~89k;j_@\Ok@DAo_uRg  Pd(HcHTn2ZDo@o@ `:ZH7H{D0x$Z@$h]D 4AlAk$@Il1@. &[Ӓ--CnN N9G bhGnXVb `‘<{ qP "S@W^BHY Bࣁ `v 2y Y!$ayO܁"& : '0*R^B1KQlx ah@IŰCZ=B !tnm4]2t E$LD| sT)wdZ(E C-I=âuN(!?F0mX>[ pF>܀)t6^zHY,W@y./0ʡ *qɥQ4fz O :7"؁jZ@J3S)&b)s]j2o-rMKYLI >Za?#]N*"=ZhS=֢<WΒ62$Ik )NEk9j ,sFqBp+| . J g dr.|BƖƷ8^5V7'dӵ@ݼdqPR#.Q? BD$r{8L}[ -KmԬYX7W7B6_A65=-^5ArYi|p!'UQۇp$ K 3( N%"´LTUb |\dFl&).z5a􀁂ߓmT%s@2  h6@QV*Օi،Y3 @}c8376ɪh$L]P4.[2F[  b@+dD_ I mNh쾌L2d{h@9+RNMQ fdh$J#!-]^eݨ$3Td -_*Te D@sě},ˠr Ehtԅ<iuA=9|њq0rX',ER}@ׅW VԒLAvd[sz>bzjWc j&NLa .:` m]xxՀ? XWΙlO*D@j->2X{]OkHe SĦ&J$xkI|A@u-ٓq%IN0%sySK0H/%6Jir b֏IL'qfo.EoRϢevFx9̄'Bϴ{JoFC -r0J{ L$%v$v" 00(LB^ьBL-I%,t+$exL(#>lm . r$K2-2^&BH  $%-T '-fz @㰶.TL o.32l| "Q| a0T$:4SU5dh"`& Q$% p-+~-n5G58x଄JPc؁09 $' 8,3=s>KUFQ-2J$,$X SL-AzL 7u=jgjş {63$xn ,T$2 QtKE`0BF JsjHAI.t)Լ"~"tb rt~tHTd- # {Ex} "H!M*Inb# C %_E`:H'ʣ N wN(BL|xW01Cςxl>@Ik+MGf3TaV"FQ$fxF5%Tf$n /Q-qCVHm$~m t,K0Tq2Kb9M zt.^ʻYE.{!&]!*Fb 4}BH7-6xr$-L?u2G2@):T(291fK?ai;9C.ssP3J$&JVJđR<6sn↭<I{sf#Q"F @$n;Cj?IabbMant Kn6FheFN~hC{*Pod!m;cc^'HX60Wd5Vvg*LD/GtI{ssq70{v7%)֨1Ppjws`w~.j S99 _KG QP$d^%-N2I-S|j{N]BhLOϗw &Re9M k`-:( r+w"bGYFxuj(2d%XLW-o_jVKjvXK'gjRltf.9• T3lߑ~'OF@mwK$hS .ςH0kl][`-͏I73KsDt S$d9P{y "4{Fdch"M 86ħM`Uk"״&&ۢBo)Xn$&"ΑD$lQBHp{LP ټJHlGBN B-I^K"BH5;oɉʰ丵AάgO(+)@F~H/BFш44#8-F*-ULەn8зQ+ Ou]E{<'c8+ZF!{I֊H.2 ٶp RH gf 2Y~%Ӕ? K$R\a-E-6ɩB]D1{Fox0=B-Bb38a$3yn~1BT&{K7"GuQ ;iHBK +Lʿk/r (S1t$E8$q$~0P%uBX0G+WyH r-hyWw\\͸Ӑ>3bk L{J؊ڻjGw/4Dnf}~wjoڢg v;Z9-_ r^ E"G̮Ȥ%қ2YY8"Ѓɳ"y\$o=+-i$%(cÒ,ɣ Ń1pg.al] + m mH2 +" 3ʡ &`jv dg`m<` n0׉|_SC|a҃(164 .0:xS I - ﱤ1 .|4 f Rdn0&H0!(HJ `R( j2Ҭr4tL2"i*@4\Sk23 |N1˔jϨI?NJ x } pɠy%ы]Sz& TʩFjƃ0/\4•0KW5w^Wvh4%_+$FHk ;H؁(G Ýn(Ka͌1(Ёrl:(1xT]KHȁh5H0,S/Wڃh2 gB g=͍u aDB=_& b0+*h1 d 6:5^lb&Yj(H0Oi:; 'p"0` ĭ^HخWBa ā՘,Y= w[ p",]i2#;-w(ʈ0& ԁbApF0&Vp -p0a kIⅧu Tϲ蓤*;(z< VSD J8?)iW"4"L3͆PrUZ.o"H eΌԺSH-+B6(@4IFAkd'4ÀK 2 Ԋ3"A+bt|3ʚcj]U4 9ȊX@S uYbZ@"P5r8-*Ph N)j\;60&I @&6$6YT1 OH"W R Z41f}8:$)ao-Q*B(#b@Ն3Ќ޸suEF]_EO j9GVN 1[`Hj/TdlDN PE[%9PA)S"'b~Hc5f.P28v$=`ÐD'nN]Z瀁ZE uʸGҵ:bcT a,PAXy(N@̵$QLH$kck SN*[;!|UbEX5 +bzvIoł 3e.,g@u - e͸׻h2 |@"/}2卣k ]30 `ZlQc"crBH9BhN{@˅7 |GX8pXe۸Jfo⩽"SȁҜB4/mB*rZ"5!=azb6xgRMv͖vq<mVU H7J^MޗK ̎tf' UPko1:>fc{xq `=vHbxg"DD?E@?3nfeeʟ7A-fliZl FZ?(3/*2DAr 3i @h@8?2 9;D|0i<؁(-ޒϠ3⺫yp84|ص$z`Ƣ.A&qkF= 0;Ԁf(ǖG"0<"y&&;"3Ql3r8 1<V>ц=D*1ByK#:(0;a;"+KfDjZn+"<45'P-R.y jlD|^^,?R53%,­3>?b/#p 1ȮPPͫ i؉Ro&!X[JL_ǀT!+dzTѐGiH"ty:n pƿnj ؁-2WBA%M+ hT +-BH F̏T5KJS53QJ2'".:zz.HCa4.+ћ*=\KKpB!ҀqFxƟbtA=CG LLx;TY:L͐L@(LCꄪ?-2'4"PZ(Ƚ;;3|Nፒ)C:k1O4;\r ٽTs|<-%Od 4>GFH)k<F{<`B (K̾\74P Z7wLI~SܷCS, d B+sBPn>!C H{.RF{QD4t:mřrXǺ1?}2A-.q }4ɵj !+Ƌ# 2 rĜ>۰H4 89HTU`Y/@[G?]4=&`ƕI݉X\KLPcs;I )P(W?V74,X3qBPBeZԇ ڂ+ ̊XHMK,<<#?[\o@L#:l#<ڠ$)IbLE[mܠ@;z;׼U%C(.:X\B @=nVܭ߈oL⟩}yە}B|[$3?[S>S5AM^2[@_7 ۤNfM 6|-@8F;XT[CYtG8<\`Z`r,[tRlZmQ@P N*LA"uK_§CVaaɤ(JZ \| r P8$ BaPd6DbQ8V-FcQv=D3 eR K>@QIc"eq 3|+<1WH^6 ^@ڰ7=f@ W Bn̢0 χbjϸ`O(R wh n A![{gjwVz Á5 wtz]>WY3 vlRi0) e8"fhHFH0YdP |Pm g,,+ `[@ @F)GǑ|0#Iԁhҁв l~;hFr a, Q, 80dkPV b;=ϓ1 OB*O6$hb‹(T fVb6 M OPbV@ n2Mc% 5(1R Xh*Xguiږ5FK* G*r vp Gs[h[c?j [*nf3הEiZ6{[KtMHRH1*n@DO*swHo9Ɍ# N05d@) ]c B聋2 Yk.l( 1Fl@$k(t@ށj@ ' T8B!M aQ`S\hr"vTe*; O5l@O /pW`2H mH,@51}9:@G$%C{r:! slmD9m r\˷ʾߪ 3@dqA'6&y_ SH)Ҵ+%KفL*rNY9ʏB 5(Ճ6}'D xV hLN07|T]0Plchan"G2dɜ$1@$I(B04"@t$ ՀKKrO) S؁8zrcЬ`e)@AH ڝSkn-B٘NOҤJ $UPIHIJ:+uD WZ]+~o΁WӅ@skLaE ec=.d28 vhg+.8"Ra}$eO%\f5٩Oڑ:5VYX (‡ۧuJIt2h֢k?Z$!@$ \E&$@>j9%:$wF L&0KTuR̩D{"l_b45`xt =7o [N-4  H.uqYG*\&xWO'!Hb 3 W-g\e->$j4~eva-i .d7UE r۫7;=CvH8$8VA- ܙ٨5ƹjS6k@͛b% /Zc e0cUʅsru[lG:@DLz.? \$ ŶPl 2N o>w[#Mu ]xG0ML][ϊq^,AZk7 ʵy)i2Z&/tlV%$P](4!426FeqmStZњ+Kޜ'pKX̾:<_O=RJl=*CGD܍\ A>jg\]9mKrx\u8l"H-wJ_-|"й}=1f/J`.jT4ԩ͒^Ch} fܨ @Җ-l:ߟ ,< 9? ؓ>wl s.-δF\U-_?Z`5漡漡\J M}dv |cO0M*PJk (b'\> g3cj`L ]ngrTX; (k &c|F5(v `t pCR_/+ lK;ʱv/$.P 0!\ ` o-; b>k"4 Ojb:vrʆ5kfBN BJ I,G q#9\,QdY K'r^!Fkck  "E"t KV Z(jO (aH h Ko"W jX EEKڻqlb .`5-!"(Ȑ8b@@ e"Oܵ"(( r4$(k/rg B#biC;S:ӧ:%$ AQC@t>fʮ-=q"CT]EA "*a^9Fl{R䪯))eF :djB)Bԙ,SH̅ϚGDTCJyJ%".)DԥMt:` a8#j@d TMVt#I3OIA:TZLxmOaGў "i("4ӕSu8%gG#1 j\ ;UAIBVV`#iG l >-!wYu" H%UV H koT-YvTP'WV;  "b G"/)^u!Xb@uUdfb1 5`+VS=O3aT$j"N10 c5>° B 5u5ScVQSnWOԗ\V]V]S!.b/76Sgv ]cPu-xNJgi(u4eaF]2&Z"iV[`2 :G-,(k{`GQk6ml5g-Enu: (uno 8qMM13pShJ"J@ڭoQOKw(,043sw=r;rq7Me_3&"3t]Sڸ5D:$cfsGs?t7At{wW9t׈_y- "L*/YWz5 "`by W3θwxEwy|w}xx7v1{zWO mQ)^W~_`S)#x|W}7}Wx|7woCR5c#5`m| R+4Gh}]}xeisqgXuyJomƱ Gi>Blo̲X ϋ8o8}aX`sXم׍InX厸"8x9EdaMX9Z\%x-Yy9<[Y)M%g?a9exIEQt (d g9y9y9y9y9Ŝyɜ͜ѝ9՝yٝݝB_` @_=RS`C#K+#NPK document/infoPK"`"`&QuickLook/Preview.tiffPK"`"`5QuickLook/Thumbnail.tiffPKkNkNGlayers/DEC08EFE-CC42-4C78-88F2-C81310E63F05-64145-00016DF2C8F7B3BB.dataPK:bidict-0.18.2/assets/support-on-gumroad.png0000664000372000037200000002212113535200701021466 0ustar travistravis00000000000000PNG  IHDR7.-viCCPICC ProfileXyXUͷOqVnKnED QI6 ADEDEVnB̜YkwfMul@6%@-`D @ղ4cY# _{z{Y3#ō`8O>I$xk,H?N^# 2^@r[~'mA"/N{ D_[$ڴoQcvcLVr;>?Otq8}_(@c}}}Na #o6lwK!90SQ?:a"FGcX0@D M'ȿ,?oq[N#N/Zs~[9\Cn҆4>iA w%\ f-GG̬{:iy3 +&bcC脄ƒ||#ً(Cj'"hynC,u qYH v3X8Iڒa6,zgТ; I(@c`l#؏κ/BYGpL NbP *p\͠ t.`]3#+'Axb!^H H҃L!+r|`(JAPT C+P+ ݁BOW,L3ܰ0, Z l}08NBn.< Oe  H"*b8!IB2|Cn~L!ÇDק! $a0Ř &-#+7˅a>hl6{{ۇ cѽpgp.C4ndz%jx < Ok ;K#B>A!#EaAIKCQEq O"=QF! u>s"%%JUʽ~( )((_Qbҡrʦ:OEjZZډ::"u/ 44R4F444%4M4#4_h)hhh^}@NNDDWBJn^ނ>>{<0'C*C%C/4#(xq $dϔt>3s s s; "bȒreeUՋ5u'&[[=(*;{qfI 8^h}88wszpfp^|ssYqsUr q-spprqra93ȫ{3_ _!-9~.~CHr?wݑ~ǤQ@E[@ `%gBB*BBBB߄E텏7 a1$\ZTC4LBNLE,@ذ8,(+^"@P8#p'v;HRIjIFI^|%"e*",EZPItoE@* YYc rrr%r[$*+2*)QQDVSUTvS>DIR%Ke@ڦcҮ]Ww}-;`w{Dx3CV6Χ^>AҨx)yN󝖘Vmmuo:tut] z zzz/w_ҟ3P4727|bmathX8 IkSqS 3ss!`f `adqbR2^^˽%{ZZ%X[3ZZXhL؊Fڹ]fkg? pבϱ dtiY󌋢K>}1ݕ֕z fVF UݍOyxx|<9[; Y_ |O~:~~,܂ZoĄ< M v*llB> o`B_u"E#GR*m}->&8f(V<6=]~\u<&#'?`«D$(='Y 95y KIKY:dF*w/ѤӞ}(E3<33e23ײ<+<}?G)l..78w yyqy'N4;qr; ĂȂB–"ܢb\O;yfٺR2r J\eT*j8eu> .*_XUs yi֥v:ɺzە&W{\kj<}zF4<ոoJdjsϢ8~)3_D4~:4073O__Zd_<Գlb%h緌/Pѿjg~دM~?_Z_%IZaoo@#i@ivP:at8A<-GNeCESD^!qY%)u.N^ɿ ($,J'V"!YJ[zD[nQ!UCFUu{) o͏A:szAo ]6[d[.XNin/X4Bا5ϭ4)esȷ[`xЛ0<1+3)!qlK\Q|TEpϤUb:ڑOrx,H􌌤Lr1l]?O䵟(=y_Er!_he37^.--*pԬQ W>uBEKFUd]ڧ';ZZ-o(kh[j1}l[&`Xx݂{n s>=\yqh˜qd|i3 扻c&&_D}fվלǧX{NYC?65|o{r~lxeq%eWJpYMWf`Ybpx75јҘj/Mm7wF_Jwlq콜\ܝ., #* \TUFRXF!YqNU==5t ƍčcLL')-T,[Y?jGm/RimQiW MCKDL C~ _(rVaYkMIHMfL^90q;ԘiGгUzg,c?s&s;W>pab!pht:eز򱊁UUpb|M%Zjub k o<ځWr3[2[ȻYV^Qy+{_Y->bbwY߳`ϰCG4NjoF_ZDsI/_>*uشڙ/o=ߟ}B6O_0\-v.[[ZrܷgWگݹvD葫g,ۊ# E.ѓRJZQɌruP#@ OEw <$yJt̠g_Jʢ*ʪz,vcfn)ůMT^~hҸ$Lgڢ$+7km[^RG'ygjw.] q͑܋<:~~iAbAk!a.rBR|DMGgHtFfJlm)5AD_I7cX=ؖtH+I=| M5m壾BYbYsZX~>~]C'YO8US V𡰦ȯX]әgBZ*1-WT^9w|v5{/_֨SoBrŵ뇛BcZ[n|)Х{VCwlGA?_y5i2ԗo ߞ|9nvd@d 3XR` W>r84h6,\8f 8 y $h(.P8UA8 Kv9p#r9E0̘=hyae& & x| N"T(x)(*(fb`b %҉ rjK&f֙4] =}<Fwi&hƒ*f6͞5ʝcϻ7_#[ RMH]Gk/H酞 \2X9 O([\=j?4vh/Ewҙ̯["{5oڬ?0r{k>'7o1 ,s_L<$3+n4!'rPaGde);ptjoE[I֙2 5qomnںfSrj̠܃ #F^qv|gX=u_%Y6}*0j?Y =` | AhF>o^A24ahc0>kM6`_ 7{K gK A ?Db6qR2=SC440Wttj WԘY"Yljlc9xpqNQCFJ5" 1'q# ՝w|Ro5?8~tY&VKWolYۼ> *m/ϊ_hv6:N/lAUpٴ8XiTXtXML:com.adobe.xmp 232 729 1 &L, IDATxS[Kn~LftNIϤLt6i6ۀxƲyـ!< x@+!Aȋ,Hc {掳w޽|Wr%j-Xs{愯?SЏo/|WG>C<>Lg <>xzƿ22~b!]E)X|-ބ9ǐ:4S`AO9<(v8~Z<6a0ӹ5r h4az`vN8[puB9N' p8NNNN@bwǂ]_`b1mZ͖NX3Z>iLR?sI׹jSEˤ(XۂO\Wl|nh4jZ¾XJ8kx:k?kՓ bL_>/P8_&ۭ=z%J}###1f5""={rcc#{O]GJ@B)R{ي>k PG666I$BhŋSlp7CMZ=z/XR= \[ccc?~ѪjveYY&ueSNq ʹ#" ih\AulqO߅\8;/5\ͅ.>*pUTT,=_gJNV+N ؂r t }ݾ}`eeEV^v+=* 8CQ ݻwhvj"F-pNt<- _`T<` lS<ÇXdd$@DG+o믦n5O$PWX08 9a0XuZz`]b, I$¾XWWzS,}ӉSEKz@Y=::ʺ% ]]]Gb:50-p:%@.X N1ԀВ1H½(ח&j֦>x˧Ѥ$,§a`*#Pؗ8Fj233NWX+`U+J )Y 2Ԡ_e[@hR3 oAos[M ޠfvݦgݜNI?s.pLJJ JN}LM,--U~6L j/HGPw "#L0[<+ߘ"lc+MX Is$nؗkލ:GP:rz?k5N'n(5_{ D@!ͨ%Ff$ pN CrJ9! B~{<5?ڜ5;蜽U$H.m[Y񡎌"!˨INNfdǗ,z#ƳM:EϺ%?L:(G̦&łSfE ?XMvv6jo3)(IyIIu8?vJ_Nˠ ]ӭfBV\#LjB6@b 3ؙ p\3ݑNI_P"1M-kGh@;--a;S=Vz9FR?S LRaT$@v1&EShB5-Q渞`\΋;X~l;CLRQQ p~@ؓXO:mhh Rbwʺ] fhjj;0F )uSot50Ӟ҅oA`f#P,߷4<<{=wuNh( ! Qv< ;+8UWAnSh }ƀ]H0Eho+t}_bb[j]+ߋhNhkLoϑTח>yV߁|Uy즩8}?5MiQugz<#>yͧwJJ~Tm*)Tgh+DB[6 F|LUD;)8\8\8\8\8\8\8\8\8\8\8\8\iq\tP^]X~˻.JrlllyyyV J4>> from bidict import bidict >>> element_by_symbol = bidict({'H': 'hydrogen'}) >>> element_by_symbol['H'] 'hydrogen' >>> element_by_symbol.inverse['hydrogen'] 'H' Please see https://github.com/jab/bidict for the most up-to-date code and https://bidict.readthedocs.io for the most up-to-date documentation if you are reading this elsewhere. .. :copyright: (c) 2019 Joshua Bronson. .. :license: MPLv2. See LICENSE for details. """ # This __init__.py only collects functionality implemented in the rest of the # source and exports it under the `bidict` module namespace (via `__all__`). from ._abc import BidirectionalMapping from ._base import BidictBase from ._mut import MutableBidict from ._bidict import bidict from ._dup import DuplicationPolicy, IGNORE, OVERWRITE, RAISE from ._exc import ( BidictException, DuplicationError, KeyDuplicationError, ValueDuplicationError, KeyAndValueDuplicationError) from ._util import inverted from ._frozenbidict import frozenbidict from ._frozenordered import FrozenOrderedBidict from ._named import namedbidict from ._orderedbase import OrderedBidictBase from ._orderedbidict import OrderedBidict from .metadata import ( __author__, __maintainer__, __copyright__, __email__, __credits__, __url__, __license__, __status__, __description__, __keywords__, __version__, __version_info__) __all__ = ( '__author__', '__maintainer__', '__copyright__', '__email__', '__credits__', '__license__', '__status__', '__description__', '__keywords__', '__url__', '__version__', '__version_info__', 'BidirectionalMapping', 'BidictException', 'DuplicationPolicy', 'IGNORE', 'OVERWRITE', 'RAISE', 'DuplicationError', 'KeyDuplicationError', 'ValueDuplicationError', 'KeyAndValueDuplicationError', 'BidictBase', 'MutableBidict', 'frozenbidict', 'bidict', 'namedbidict', 'FrozenOrderedBidict', 'OrderedBidictBase', 'OrderedBidict', 'inverted', ) # * Code review nav * #============================================================================== # Current: __init__.py Next: _abc.py → #============================================================================== bidict-0.18.2/bidict/_abc.py0000664000372000037200000001122513535200701016373 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. #============================================================================== # * Welcome to the bidict source code * #============================================================================== # Doing a code review? You'll find a "Code review nav" comment like the one # below at the top and bottom of the most important source files. This provides # a suggested initial path through the source when reviewing. # # Note: If you aren't reading this on https://github.com/jab/bidict, you may be # viewing an outdated version of the code. Please head to GitHub to review the # latest version, which contains important improvements over older versions. # # Thank you for reading and for any feedback you provide. # * Code review nav * #============================================================================== # ← Prev: __init__.py Current: _abc.py Next: _base.py → #============================================================================== """Provides the :class:`BidirectionalMapping` abstract base class.""" from .compat import Mapping, abstractproperty, iteritems class BidirectionalMapping(Mapping): # pylint: disable=abstract-method,no-init """Abstract base class (ABC) for bidirectional mapping types. Extends :class:`collections.abc.Mapping` primarily by adding the (abstract) :attr:`inverse` property, which implementors of :class:`BidirectionalMapping` should override to return a reference to the inverse :class:`BidirectionalMapping` instance. Implements :attr:`__subclasshook__` such that any :class:`~collections.abc.Mapping` that also provides :attr:`~BidirectionalMapping.inverse` will be considered a (virtual) subclass of this ABC. """ __slots__ = () @abstractproperty def inverse(self): """The inverse of this bidirectional mapping instance. *See also* :attr:`bidict.BidictBase.inverse`, :attr:`bidict.BidictBase.inv` :raises NotImplementedError: Meant to be overridden in subclasses. """ # The @abstractproperty decorator prevents BidirectionalMapping subclasses from being # instantiated unless they override this method. So users shouldn't be able to get to the # point where they can unintentionally call this implementation of .inverse on something # anyway. Could leave the method body empty, but raise NotImplementedError so it's extra # clear there's no reason to call this implementation (e.g. via super() after overriding). raise NotImplementedError def __inverted__(self): """Get an iterator over the items in :attr:`inverse`. This is functionally equivalent to iterating over the items in the forward mapping and inverting each one on the fly, but this provides a more efficient implementation: Assuming the already-inverted items are stored in :attr:`inverse`, just return an iterator over them directly. Providing this default implementation enables external functions, particularly :func:`~bidict.inverted`, to use this optimized implementation when available, instead of having to invert on the fly. *See also* :func:`bidict.inverted` """ return iteritems(self.inverse) @classmethod def __subclasshook__(cls, C): # noqa: N803 (argument name should be lowercase) """Check if *C* is a :class:`~collections.abc.Mapping` that also provides an ``inverse`` attribute, thus conforming to the :class:`BidirectionalMapping` interface, in which case it will be considered a (virtual) C even if it doesn't explicitly extend it. """ if cls is not BidirectionalMapping: # lgtm [py/comparison-using-is] return NotImplemented if not Mapping.__subclasshook__(C): return NotImplemented mro = getattr(C, '__mro__', None) if mro is None: # Python 2 old-style class return NotImplemented if not any(B.__dict__.get('inverse') for B in mro): return NotImplemented return True # * Code review nav * #============================================================================== # ← Prev: __init__.py Current: _abc.py Next: _base.py → #============================================================================== bidict-0.18.2/bidict/_base.py0000664000372000037200000004601213535200701016562 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. #============================================================================== # * Welcome to the bidict source code * #============================================================================== # Doing a code review? You'll find a "Code review nav" comment like the one # below at the top and bottom of the most important source files. This provides # a suggested initial path through the source when reviewing. # # Note: If you aren't reading this on https://github.com/jab/bidict, you may be # viewing an outdated version of the code. Please head to GitHub to review the # latest version, which contains important improvements over older versions. # # Thank you for reading and for any feedback you provide. # * Code review nav * #============================================================================== # ← Prev: _abc.py Current: _base.py Next: _delegating_mixins.py → #============================================================================== """Provides :class:`BidictBase`.""" from collections import namedtuple from weakref import ref from ._abc import BidirectionalMapping from ._dup import RAISE, OVERWRITE, IGNORE, _OnDup from ._exc import ( DuplicationError, KeyDuplicationError, ValueDuplicationError, KeyAndValueDuplicationError) from ._miss import _MISS from ._noop import _NOOP from ._util import _iteritems_args_kw from .compat import PY2, KeysView, ItemsView, Mapping, iteritems _DedupResult = namedtuple('_DedupResult', 'isdupkey isdupval invbyval fwdbykey') _WriteResult = namedtuple('_WriteResult', 'key val oldkey oldval') _NODUP = _DedupResult(False, False, _MISS, _MISS) # Since BidirectionalMapping implements __subclasshook__, and BidictBase # provides all the required attributes that the __subclasshook__ checks for, # BidictBase would be a (virtual) subclass of BidirectionalMapping even if # it didn't subclass it explicitly. But subclassing BidirectionalMapping # explicitly allows BidictBase to inherit any useful implementations that # BidirectionalMapping provides that aren't part of the required interface, # such as its `__inverted__` implementation and `inverse` alias. class BidictBase(BidirectionalMapping): """Base class implementing :class:`BidirectionalMapping`.""" __slots__ = ('_fwdm', '_invm', '_inv', '_invweak', '_hash') + (() if PY2 else ('__weakref__',)) #: The default :class:`DuplicationPolicy` #: (in effect during e.g. :meth:`~bidict.bidict.__init__` calls) #: that governs behavior when a provided item #: duplicates only the key of another item. #: #: Defaults to :attr:`~bidict.OVERWRITE` #: to match :class:`dict`'s behavior. #: #: *See also* :ref:`basic-usage:Values Must Be Unique`, :doc:`extending` on_dup_key = OVERWRITE #: The default :class:`DuplicationPolicy` #: (in effect during e.g. :meth:`~bidict.bidict.__init__` calls) #: that governs behavior when a provided item #: duplicates only the value of another item. #: #: Defaults to :attr:`~bidict.RAISE` #: to prevent unintended overwrite of another item. #: #: *See also* :ref:`basic-usage:Values Must Be Unique`, :doc:`extending` on_dup_val = RAISE #: The default :class:`DuplicationPolicy` #: (in effect during e.g. :meth:`~bidict.bidict.__init__` calls) #: that governs behavior when a provided item #: duplicates the key of another item and the value of a third item. #: #: Defaults to ``None``, which causes the *on_dup_kv* policy to match #: whatever *on_dup_val* policy is in effect. #: #: *See also* :ref:`basic-usage:Values Must Be Unique`, :doc:`extending` on_dup_kv = None _fwdm_cls = dict _invm_cls = dict #: The object used by :meth:`__repr__` for printing the contained items. _repr_delegate = dict def __init__(self, *args, **kw): # pylint: disable=super-init-not-called """Make a new bidirectional dictionary. The signature is the same as that of regular dictionaries. Items passed in are added in the order they are passed, respecting the current duplication policies in the process. *See also* :attr:`on_dup_key`, :attr:`on_dup_val`, :attr:`on_dup_kv` """ #: The backing :class:`~collections.abc.Mapping` #: storing the forward mapping data (*key* → *value*). self._fwdm = self._fwdm_cls() #: The backing :class:`~collections.abc.Mapping` #: storing the inverse mapping data (*value* → *key*). self._invm = self._invm_cls() self._init_inv() # lgtm [py/init-calls-subclass] if args or kw: self._update(True, None, *args, **kw) def _init_inv(self): # Compute the type for this bidict's inverse bidict (will be different from this # bidict's type if _fwdm_cls and _invm_cls are different). inv_cls = self._inv_cls() # Create the inverse bidict instance via __new__, bypassing its __init__ so that its # _fwdm and _invm can be assigned to this bidict's _invm and _fwdm. Store it in self._inv, # which holds a strong reference to a bidict's inverse, if one is available. self._inv = inv = inv_cls.__new__(inv_cls) inv._fwdm = self._invm # pylint: disable=protected-access inv._invm = self._fwdm # pylint: disable=protected-access # Only give the inverse a weak reference to this bidict to avoid creating a reference cycle, # stored in the _invweak attribute. See also the docs in # :ref:`addendum:Bidict Avoids Reference Cycles` inv._inv = None # pylint: disable=protected-access inv._invweak = ref(self) # pylint: disable=protected-access # Since this bidict has a strong reference to its inverse already, set its _invweak to None. self._invweak = None @classmethod def _inv_cls(cls): """The inverse of this bidict type, i.e. one with *_fwdm_cls* and *_invm_cls* swapped.""" if cls._fwdm_cls is cls._invm_cls: return cls if not getattr(cls, '_inv_cls_', None): class _Inv(cls): _fwdm_cls = cls._invm_cls _invm_cls = cls._fwdm_cls _inv_cls_ = cls _Inv.__name__ = cls.__name__ + 'Inv' cls._inv_cls_ = _Inv return cls._inv_cls_ @property def _isinv(self): return self._inv is None @property def inverse(self): """The inverse of this bidict. *See also* :attr:`inv` """ # Resolve and return a strong reference to the inverse bidict. # One may be stored in self._inv already. if self._inv is not None: return self._inv # Otherwise a weakref is stored in self._invweak. Try to get a strong ref from it. inv = self._invweak() if inv is not None: return inv # Refcount of referent must have dropped to zero, as in `bidict().inv.inv`. Init a new one. self._init_inv() # Now this bidict will retain a strong ref to its inverse. return self._inv @property def inv(self): """Alias for :attr:`inverse`.""" return self.inverse def __getstate__(self): """Needed to enable pickling due to use of :attr:`__slots__` and weakrefs. *See also* :meth:`object.__getstate__` """ state = {} for cls in self.__class__.__mro__: slots = getattr(cls, '__slots__', ()) for slot in slots: if hasattr(self, slot): state[slot] = getattr(self, slot) # weakrefs can't be pickled. state.pop('_invweak', None) # Added back in __setstate__ via _init_inv call. state.pop('__weakref__', None) # Not added back in __setstate__. Python manages this one. return state def __setstate__(self, state): """Implemented because use of :attr:`__slots__` would prevent unpickling otherwise. *See also* :meth:`object.__setstate__` """ for slot, value in iteritems(state): setattr(self, slot, value) self._init_inv() def __repr__(self): """See :func:`repr`.""" clsname = self.__class__.__name__ if not self: return '%s()' % clsname return '%s(%r)' % (clsname, self._repr_delegate(iteritems(self))) # The inherited Mapping.__eq__ implementation would work, but it's implemented in terms of an # inefficient ``dict(self.items()) == dict(other.items())`` comparison, so override it with a # more efficient implementation. def __eq__(self, other): u"""*x.__eq__(other) ⟺ x == other* Equivalent to *dict(x.items()) == dict(other.items())* but more efficient. Note that :meth:`bidict's __eq__() ` implementation is inherited by subclasses, in particular by the ordered bidict subclasses, so even with ordered bidicts, :ref:`== comparison is order-insensitive `. *See also* :meth:`bidict.FrozenOrderedBidict.equals_order_sensitive` """ if not isinstance(other, Mapping) or len(self) != len(other): return False selfget = self.get return all(selfget(k, _MISS) == v for (k, v) in iteritems(other)) # The following methods are mutating and so are not public. But they are implemented in this # non-mutable base class (rather than the mutable `bidict` subclass) because they are used here # during initialization (starting with the `_update` method). (Why is this? Because `__init__` # and `update` share a lot of the same behavior (inserting the provided items while respecting # the active duplication policies), so it makes sense for them to share implementation too.) def _pop(self, key): val = self._fwdm.pop(key) del self._invm[val] return val def _put(self, key, val, on_dup): dedup_result = self._dedup_item(key, val, on_dup) if dedup_result is not _NOOP: self._write_item(key, val, dedup_result) def _dedup_item(self, key, val, on_dup): """ Check *key* and *val* for any duplication in self. Handle any duplication as per the duplication policies given in *on_dup*. (key, val) already present is construed as a no-op, not a duplication. If duplication is found and the corresponding duplication policy is :attr:`~bidict.RAISE`, raise the appropriate error. If duplication is found and the corresponding duplication policy is :attr:`~bidict.IGNORE`, return *None*. If duplication is found and the corresponding duplication policy is :attr:`~bidict.OVERWRITE`, or if no duplication is found, return the _DedupResult *(isdupkey, isdupval, oldkey, oldval)*. """ fwdm = self._fwdm invm = self._invm oldval = fwdm.get(key, _MISS) oldkey = invm.get(val, _MISS) isdupkey = oldval is not _MISS isdupval = oldkey is not _MISS dedup_result = _DedupResult(isdupkey, isdupval, oldkey, oldval) if isdupkey and isdupval: if self._isdupitem(key, val, dedup_result): # (key, val) duplicates an existing item -> no-op. return _NOOP # key and val each duplicate a different existing item. if on_dup.kv is RAISE: raise KeyAndValueDuplicationError(key, val) elif on_dup.kv is IGNORE: return _NOOP assert on_dup.kv is OVERWRITE, 'invalid on_dup_kv: %r' % on_dup.kv # Fall through to the return statement on the last line. elif isdupkey: if on_dup.key is RAISE: raise KeyDuplicationError(key) elif on_dup.key is IGNORE: return _NOOP assert on_dup.key is OVERWRITE, 'invalid on_dup.key: %r' % on_dup.key # Fall through to the return statement on the last line. elif isdupval: if on_dup.val is RAISE: raise ValueDuplicationError(val) elif on_dup.val is IGNORE: return _NOOP assert on_dup.val is OVERWRITE, 'invalid on_dup.val: %r' % on_dup.val # Fall through to the return statement on the last line. # else neither isdupkey nor isdupval. return dedup_result @staticmethod def _isdupitem(key, val, dedup_result): isdupkey, isdupval, oldkey, oldval = dedup_result isdupitem = oldkey == key assert isdupitem == (oldval == val), '%r %r %r' % (key, val, dedup_result) if isdupitem: assert isdupkey assert isdupval return isdupitem @classmethod def _get_on_dup(cls, on_dup=None): if on_dup is None: on_dup = _OnDup(cls.on_dup_key, cls.on_dup_val, cls.on_dup_kv) elif not isinstance(on_dup, _OnDup): on_dup = _OnDup(*on_dup) if on_dup.kv is None: on_dup = on_dup._replace(kv=on_dup.val) return on_dup def _write_item(self, key, val, dedup_result): isdupkey, isdupval, oldkey, oldval = dedup_result fwdm = self._fwdm invm = self._invm fwdm[key] = val invm[val] = key if isdupkey: del invm[oldval] if isdupval: del fwdm[oldkey] return _WriteResult(key, val, oldkey, oldval) def _update(self, init, on_dup, *args, **kw): # args[0] may be a generator that yields many items, so process input in a single pass. if not args and not kw: return can_skip_dup_check = not self and not kw and isinstance(args[0], BidirectionalMapping) if can_skip_dup_check: self._update_no_dup_check(args[0]) return on_dup = self._get_on_dup(on_dup) can_skip_rollback = init or RAISE not in on_dup if can_skip_rollback: self._update_no_rollback(on_dup, *args, **kw) else: self._update_with_rollback(on_dup, *args, **kw) def _update_no_dup_check(self, other, _nodup=_NODUP): write_item = self._write_item for (key, val) in iteritems(other): write_item(key, val, _nodup) def _update_no_rollback(self, on_dup, *args, **kw): put = self._put for (key, val) in _iteritems_args_kw(*args, **kw): put(key, val, on_dup) def _update_with_rollback(self, on_dup, *args, **kw): """Update, rolling back on failure.""" writelog = [] appendlog = writelog.append dedup_item = self._dedup_item write_item = self._write_item for (key, val) in _iteritems_args_kw(*args, **kw): try: dedup_result = dedup_item(key, val, on_dup) except DuplicationError: undo_write = self._undo_write for dedup_result, write_result in reversed(writelog): undo_write(dedup_result, write_result) raise if dedup_result is not _NOOP: write_result = write_item(key, val, dedup_result) appendlog((dedup_result, write_result)) def _undo_write(self, dedup_result, write_result): isdupkey, isdupval, _, _ = dedup_result key, val, oldkey, oldval = write_result if not isdupkey and not isdupval: self._pop(key) return fwdm = self._fwdm invm = self._invm if isdupkey: fwdm[key] = oldval invm[oldval] = key if not isdupval: del invm[val] if isdupval: invm[val] = oldkey fwdm[oldkey] = val if not isdupkey: del fwdm[key] def copy(self): """A shallow copy.""" # Could just ``return self.__class__(self)`` here instead, but the below is faster. It uses # __new__ to create a copy instance while bypassing its __init__, which would result # in copying this bidict's items into the copy instance one at a time. Instead, make whole # copies of each of the backing mappings, and make them the backing mappings of the copy, # avoiding copying items one at a time. copy = self.__class__.__new__(self.__class__) copy._fwdm = self._fwdm.copy() # pylint: disable=protected-access copy._invm = self._invm.copy() # pylint: disable=protected-access copy._init_inv() # pylint: disable=protected-access return copy def __copy__(self): """Used for the copy protocol. *See also* the :mod:`copy` module """ return self.copy() def __len__(self): """The number of contained items.""" return len(self._fwdm) def __iter__(self): # lgtm [py/inheritance/incorrect-overridden-signature] """Iterator over the contained items.""" # No default implementation for __iter__ inherited from Mapping -> # always delegate to _fwdm. return iter(self._fwdm) def __getitem__(self, key): u"""*x.__getitem__(key) ⟺ x[key]*""" return self._fwdm[key] def values(self): """A set-like object providing a view on the contained values. Note that because the values of a :class:`~bidict.BidirectionalMapping` are the keys of its inverse, this returns a :class:`~collections.abc.KeysView` rather than a :class:`~collections.abc.ValuesView`, which has the advantages of constant-time containment checks and supporting set operations. """ return self.inverse.keys() if PY2: # For iterkeys and iteritems, inheriting from Mapping already provides # the best default implementations so no need to define here. def itervalues(self): """An iterator over the contained values.""" return self.inverse.iterkeys() def viewkeys(self): # noqa: D102; pylint: disable=missing-docstring return KeysView(self) def viewvalues(self): # noqa: D102; pylint: disable=missing-docstring return self.inverse.viewkeys() viewvalues.__doc__ = values.__doc__ values.__doc__ = 'A list of the contained values.' def viewitems(self): # noqa: D102; pylint: disable=missing-docstring return ItemsView(self) # __ne__ added automatically in Python 3 when you implement __eq__, but not in Python 2. def __ne__(self, other): # noqa: N802 u"""*x.__ne__(other) ⟺ x != other*""" return not self == other # Implement __ne__ in terms of __eq__. # * Code review nav * #============================================================================== # ← Prev: _abc.py Current: _base.py Next: _delegating_mixins.py → #============================================================================== bidict-0.18.2/bidict/_bidict.py0000664000372000037200000000371413535200701017110 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. #============================================================================== # * Welcome to the bidict source code * #============================================================================== # Doing a code review? You'll find a "Code review nav" comment like the one # below at the top and bottom of the most important source files. This provides # a suggested initial path through the source when reviewing. # # Note: If you aren't reading this on https://github.com/jab/bidict, you may be # viewing an outdated version of the code. Please head to GitHub to review the # latest version, which contains important improvements over older versions. # # Thank you for reading and for any feedback you provide. # * Code review nav * #============================================================================== # ← Prev: _mut.py Current: _bidict.py Next: _orderedbase.py → #============================================================================== """Provides :class:`bidict`.""" from ._mut import MutableBidict from ._delegating_mixins import _DelegateKeysAndItemsToFwdm class bidict(_DelegateKeysAndItemsToFwdm, MutableBidict): # noqa: N801,E501; pylint: disable=invalid-name """Base class for mutable bidirectional mappings.""" __slots__ = () __hash__ = None # since this class is mutable; explicit > implicit. # * Code review nav * #============================================================================== # ← Prev: _mut.py Current: _bidict.py Next: _orderedbase.py → #============================================================================== bidict-0.18.2/bidict/_delegating_mixins.py0000664000372000037200000001002713535200701021337 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. #============================================================================== # * Welcome to the bidict source code * #============================================================================== # Doing a code review? You'll find a "Code review nav" comment like the one # below at the top and bottom of the most important source files. This provides # a suggested initial path through the source when reviewing. # # Note: If you aren't reading this on https://github.com/jab/bidict, you may be # viewing an outdated version of the code. Please head to GitHub to review the # latest version, which contains important improvements over older versions. # # Thank you for reading and for any feedback you provide. # * Code review nav * #============================================================================== # ← Prev: _base.py Current: _delegating_mixins.py Next: _frozenbidict.py → #============================================================================== r"""Provides mixin classes that delegate to ``self._fwdm`` for various operations. This allows methods such as :meth:`bidict.bidict.items` to be implemented in terms of a ``self._fwdm.items()`` call, which is potentially much more efficient (e.g. in CPython 2) compared to the implementation inherited from :class:`~collections.abc.Mapping` (which returns ``[(key, self[key]) for key in self]`` in Python 2). Because this depends on implementation details that aren't necessarily true (such as the bidict's values being the same as its ``self._fwdm.values()``, which is not true for e.g. ordered bidicts where ``_fwdm``\'s values are nodes), these should always be mixed in at a layer below a more general layer, as they are in e.g. :class:`~bidict.frozenbidict` which extends :class:`~bidict.BidictBase`. See the :ref:`extending:Sorted Bidict Recipes` for another example of where this comes into play. ``SortedBidict`` extends :class:`bidict.MutableBidict` rather than :class:`bidict.bidict` to avoid inheriting these mixins, which are incompatible with the backing :class:`sortedcontainers.SortedDict`s. """ from .compat import PY2 _KEYS_METHODS = ('keys',) + (('viewkeys', 'iterkeys') if PY2 else ()) _ITEMS_METHODS = ('items',) + (('viewitems', 'iteritems') if PY2 else ()) _DOCSTRING_BY_METHOD = { 'keys': 'A set-like object providing a view on the contained keys.', 'items': 'A set-like object providing a view on the contained items.', } if PY2: _DOCSTRING_BY_METHOD['viewkeys'] = _DOCSTRING_BY_METHOD['keys'] _DOCSTRING_BY_METHOD['viewitems'] = _DOCSTRING_BY_METHOD['items'] _DOCSTRING_BY_METHOD['keys'] = 'A list of the contained keys.' _DOCSTRING_BY_METHOD['items'] = 'A list of the contained items.' def _make_method(methodname): def method(self): return getattr(self._fwdm, methodname)() # pylint: disable=protected-access method.__name__ = methodname method.__doc__ = _DOCSTRING_BY_METHOD.get(methodname, '') return method def _make_fwdm_delegating_mixin(clsname, methodnames): clsdict = dict({name: _make_method(name) for name in methodnames}, __slots__=()) return type(clsname, (object,), clsdict) _DelegateKeysToFwdm = _make_fwdm_delegating_mixin('_DelegateKeysToFwdm', _KEYS_METHODS) _DelegateItemsToFwdm = _make_fwdm_delegating_mixin('_DelegateItemsToFwdm', _ITEMS_METHODS) _DelegateKeysAndItemsToFwdm = type( '_DelegateKeysAndItemsToFwdm', (_DelegateKeysToFwdm, _DelegateItemsToFwdm), {'__slots__': ()}) # * Code review nav * #============================================================================== # ← Prev: _base.py Current: _delegating_mixins.py Next: _frozenbidict.py → #============================================================================== bidict-0.18.2/bidict/_dup.py0000664000372000037200000000175613535200701016446 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Provides bidict duplication policies and the :class:`_OnDup` class.""" from collections import namedtuple from ._marker import _Marker _OnDup = namedtuple('_OnDup', 'key val kv') class DuplicationPolicy(_Marker): """Base class for bidict's duplication policies. *See also* :ref:`basic-usage:Values Must Be Unique` """ __slots__ = () #: Raise an exception when a duplication is encountered. RAISE = DuplicationPolicy('DUP_POLICY.RAISE') #: Overwrite an existing item when a duplication is encountered. OVERWRITE = DuplicationPolicy('DUP_POLICY.OVERWRITE') #: Keep the existing item and ignore the new item when a duplication is encountered. IGNORE = DuplicationPolicy('DUP_POLICY.IGNORE') bidict-0.18.2/bidict/_exc.py0000664000372000037200000000200513535200701016421 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Provides all bidict exceptions.""" class BidictException(Exception): """Base class for bidict exceptions.""" class DuplicationError(BidictException): """Base class for exceptions raised when uniqueness is violated as per the RAISE duplication policy. """ class KeyDuplicationError(DuplicationError): """Raised when a given key is not unique.""" class ValueDuplicationError(DuplicationError): """Raised when a given value is not unique.""" class KeyAndValueDuplicationError(KeyDuplicationError, ValueDuplicationError): """Raised when a given item's key and value are not unique. That is, its key duplicates that of another item, and its value duplicates that of a different other item. """ bidict-0.18.2/bidict/_frozenbidict.py0000664000372000037200000000442613535200701020335 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. #============================================================================== # * Welcome to the bidict source code * #============================================================================== # Doing a code review? You'll find a "Code review nav" comment like the one # below at the top and bottom of the most important source files. This provides # a suggested initial path through the source when reviewing. # # Note: If you aren't reading this on https://github.com/jab/bidict, you may be # viewing an outdated version of the code. Please head to GitHub to review the # latest version, which contains important improvements over older versions. # # Thank you for reading and for any feedback you provide. # * Code review nav * #============================================================================== # ← Prev: _delegating_mixins.py Current: _frozenbidict.py Next: _mut.py → #============================================================================== """Provides :class:`frozenbidict`, an immutable, hashable bidirectional mapping type.""" from ._base import BidictBase from ._delegating_mixins import _DelegateKeysAndItemsToFwdm from .compat import ItemsView class frozenbidict(_DelegateKeysAndItemsToFwdm, BidictBase): # noqa: N801,E501; pylint: disable=invalid-name """Immutable, hashable bidict type.""" __slots__ = () def __hash__(self): # lgtm [py/equals-hash-mismatch] """The hash of this bidict as determined by its items.""" if getattr(self, '_hash', None) is None: # pylint: disable=protected-access,attribute-defined-outside-init self._hash = ItemsView(self)._hash() return self._hash # * Code review nav * #============================================================================== # ← Prev: _delegating_mixins.py Current: _frozenbidict.py Next: _mut.py → #============================================================================== bidict-0.18.2/bidict/_frozenordered.py0000664000372000037200000000657313535200701020530 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. #============================================================================== # * Welcome to the bidict source code * #============================================================================== # Doing a code review? You'll find a "Code review nav" comment like the one # below at the top and bottom of the most important source files. This provides # a suggested initial path through the source when reviewing. # # Note: If you aren't reading this on https://github.com/jab/bidict, you may be # viewing an outdated version of the code. Please head to GitHub to review the # latest version, which contains important improvements over older versions. # # Thank you for reading and for any feedback you provide. # * Code review nav * #============================================================================== #← Prev: _orderedbase.py Current: _frozenordered.py Next: _orderedbidict.py → #============================================================================== """Provides :class:`FrozenOrderedBidict`, an immutable, hashable, ordered bidict.""" from ._delegating_mixins import _DelegateKeysToFwdm from ._frozenbidict import frozenbidict from ._orderedbase import OrderedBidictBase from .compat import DICTS_ORDERED, PY2, izip # If the Python implementation's dict type is ordered (e.g. PyPy or CPython >= 3.6), then # `FrozenOrderedBidict` can delegate to `_fwdm` for keys: Both `_fwdm` and `_invm` will always # be initialized with the provided items in the correct order, and since `FrozenOrderedBidict` # is immutable, their respective orders can't get out of sync after a mutation. (Can't delegate # to `_fwdm` for items though because values in `_fwdm` are nodes.) _BASES = ((_DelegateKeysToFwdm,) if DICTS_ORDERED else ()) + (OrderedBidictBase,) _CLSDICT = dict( __slots__=(), # Must set __hash__ explicitly, Python prevents inheriting it. # frozenbidict.__hash__ can be reused for FrozenOrderedBidict: # FrozenOrderedBidict inherits BidictBase.__eq__ which is order-insensitive, # and frozenbidict.__hash__ is consistent with BidictBase.__eq__. __hash__=frozenbidict.__hash__.__func__ if PY2 else frozenbidict.__hash__, __doc__='Hashable, immutable, ordered bidict type.', __module__=__name__, # Otherwise unpickling fails in Python 2. ) # When PY2 (so we provide iteritems) and DICTS_ORDERED, e.g. on PyPy, the following implementation # of iteritems may be more efficient than that inherited from `Mapping`. This exploits the property # that the keys in `_fwdm` and `_invm` are already in the right order: if PY2 and DICTS_ORDERED: _CLSDICT['iteritems'] = lambda self: izip(self._fwdm, self._invm) # noqa: E501; pylint: disable=protected-access FrozenOrderedBidict = type('FrozenOrderedBidict', _BASES, _CLSDICT) # pylint: disable=invalid-name # * Code review nav * #============================================================================== #← Prev: _orderedbase.py Current: _frozenordered.py Next: _orderedbidict.py → #============================================================================== bidict-0.18.2/bidict/_marker.py0000664000372000037200000000104413535200701017125 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Provides :class:`_Marker`, an internal type for representing singletons.""" from collections import namedtuple class _Marker(namedtuple('_Marker', 'name')): __slots__ = () def __repr__(self): return '<%s>' % self.name # pragma: no cover bidict-0.18.2/bidict/_miss.py0000664000372000037200000000066113535200701016623 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Provides the :obj:`_MISS` sentinel, for internally signaling "missing/not found".""" from ._marker import _Marker _MISS = _Marker('MISSING') bidict-0.18.2/bidict/_mut.py0000664000372000037200000001517013535200701016456 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. #============================================================================== # * Welcome to the bidict source code * #============================================================================== # Doing a code review? You'll find a "Code review nav" comment like the one # below at the top and bottom of the most important source files. This provides # a suggested initial path through the source when reviewing. # # Note: If you aren't reading this on https://github.com/jab/bidict, you may be # viewing an outdated version of the code. Please head to GitHub to review the # latest version, which contains important improvements over older versions. # # Thank you for reading and for any feedback you provide. # * Code review nav * #============================================================================== # ← Prev: _frozenbidict.py Current: _mut.py Next: _bidict.py → #============================================================================== """Provides :class:`bidict`.""" from ._base import BidictBase from ._dup import OVERWRITE, RAISE, _OnDup from ._miss import _MISS from .compat import MutableMapping # Extend MutableMapping explicitly because it doesn't implement __subclasshook__, as well as to # inherit method implementations it provides that we can reuse (namely `setdefault`). class MutableBidict(BidictBase, MutableMapping): """Base class for mutable bidirectional mappings.""" __slots__ = () __hash__ = None # since this class is mutable; explicit > implicit. _ON_DUP_OVERWRITE = _OnDup(key=OVERWRITE, val=OVERWRITE, kv=OVERWRITE) def __delitem__(self, key): u"""*x.__delitem__(y) ⟺ del x[y]*""" self._pop(key) def __setitem__(self, key, val): """ Set the value for *key* to *val*. If *key* is already associated with *val*, this is a no-op. If *key* is already associated with a different value, the old value will be replaced with *val*, as with dict's :meth:`__setitem__`. If *val* is already associated with a different key, an exception is raised to protect against accidental removal of the key that's currently associated with *val*. Use :meth:`put` instead if you want to specify different policy in the case that the provided key or value duplicates an existing one. Or use :meth:`forceput` to unconditionally associate *key* with *val*, replacing any existing items as necessary to preserve uniqueness. :raises bidict.ValueDuplicationError: if *val* duplicates that of an existing item. :raises bidict.KeyAndValueDuplicationError: if *key* duplicates the key of an existing item and *val* duplicates the value of a different existing item. """ on_dup = self._get_on_dup() self._put(key, val, on_dup) def put(self, key, val, on_dup_key=RAISE, on_dup_val=RAISE, on_dup_kv=None): """ Associate *key* with *val* with the specified duplication policies. If *on_dup_kv* is ``None``, the *on_dup_val* policy will be used for it. For example, if all given duplication policies are :attr:`~bidict.RAISE`, then *key* will be associated with *val* if and only if *key* is not already associated with an existing value and *val* is not already associated with an existing key, otherwise an exception will be raised. If *key* is already associated with *val*, this is a no-op. :raises bidict.KeyDuplicationError: if attempting to insert an item whose key only duplicates an existing item's, and *on_dup_key* is :attr:`~bidict.RAISE`. :raises bidict.ValueDuplicationError: if attempting to insert an item whose value only duplicates an existing item's, and *on_dup_val* is :attr:`~bidict.RAISE`. :raises bidict.KeyAndValueDuplicationError: if attempting to insert an item whose key duplicates one existing item's, and whose value duplicates another existing item's, and *on_dup_kv* is :attr:`~bidict.RAISE`. """ on_dup = self._get_on_dup((on_dup_key, on_dup_val, on_dup_kv)) self._put(key, val, on_dup) def forceput(self, key, val): """ Associate *key* with *val* unconditionally. Replace any existing mappings containing key *key* or value *val* as necessary to preserve uniqueness. """ self._put(key, val, self._ON_DUP_OVERWRITE) def clear(self): """Remove all items.""" self._fwdm.clear() self._invm.clear() def pop(self, key, default=_MISS): u"""*x.pop(k[, d]) → v* Remove specified key and return the corresponding value. :raises KeyError: if *key* is not found and no *default* is provided. """ try: return self._pop(key) except KeyError: if default is _MISS: raise return default def popitem(self): u"""*x.popitem() → (k, v)* Remove and return some item as a (key, value) pair. :raises KeyError: if *x* is empty. """ if not self: raise KeyError('mapping is empty') key, val = self._fwdm.popitem() del self._invm[val] return key, val def update(self, *args, **kw): """Like :meth:`putall` with default duplication policies.""" if args or kw: self._update(False, None, *args, **kw) def forceupdate(self, *args, **kw): """Like a bulk :meth:`forceput`.""" self._update(False, self._ON_DUP_OVERWRITE, *args, **kw) def putall(self, items, on_dup_key=RAISE, on_dup_val=RAISE, on_dup_kv=None): """ Like a bulk :meth:`put`. If one of the given items causes an exception to be raised, none of the items is inserted. """ if items: on_dup = self._get_on_dup((on_dup_key, on_dup_val, on_dup_kv)) self._update(False, on_dup, items) # * Code review nav * #============================================================================== # ← Prev: _frozenbidict.py Current: _mut.py Next: _bidict.py → #============================================================================== bidict-0.18.2/bidict/_named.py0000664000372000037200000000742613535200701016742 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Provides :func:`bidict.namedbidict`.""" import re from ._abc import BidirectionalMapping from ._bidict import bidict _VALID_NAME = re.compile('[A-z][A-z0-9_]*$') def namedbidict(typename, keyname, valname, base_type=bidict): r"""Create a new subclass of *base_type* with custom accessors. Analagous to :func:`collections.namedtuple`. The new class's ``__name__`` will be set to *typename*. Instances of it will provide access to their :attr:`inverse `\s via the custom *keyname*\_for property, and access to themselves via the custom *valname*\_for property. *See also* the :ref:`namedbidict usage documentation ` :raises ValueError: if any of the *typename*, *keyname*, or *valname* strings does not match ``%s``, or if *keyname == valname*. :raises TypeError: if *base_type* is not a subclass of :class:`BidirectionalMapping`. (This function requires slightly more of *base_type*, e.g. the availability of an ``_isinv`` attribute, but all the :ref:`concrete bidict types ` that the :mod:`bidict` module provides can be passed in. Check out the code if you actually need to pass in something else.) """ # Re the `base_type` docs above: # The additional requirements (providing _isinv and __getstate__) do not belong in the # BidirectionalMapping interface, and it's overkill to create additional interface(s) for this. # On the other hand, it's overkill to require that base_type be a subclass of BidictBase, since # that's too specific. The BidirectionalMapping check along with the docs above should suffice. if not issubclass(base_type, BidirectionalMapping): raise TypeError(base_type) names = (typename, keyname, valname) if not all(map(_VALID_NAME.match, names)) or keyname == valname: raise ValueError(names) class _Named(base_type): # pylint: disable=too-many-ancestors __slots__ = () def _getfwd(self): return self.inverse if self._isinv else self def _getinv(self): return self if self._isinv else self.inverse @property def _keyname(self): return valname if self._isinv else keyname @property def _valname(self): return keyname if self._isinv else valname def __reduce__(self): return (_make_empty, (typename, keyname, valname, base_type), self.__getstate__()) bname = base_type.__name__ fname = valname + '_for' iname = keyname + '_for' names = dict(typename=typename, bname=bname, keyname=keyname, valname=valname) fdoc = u'{typename} forward {bname}: {keyname} → {valname}'.format(**names) idoc = u'{typename} inverse {bname}: {valname} → {keyname}'.format(**names) setattr(_Named, fname, property(_Named._getfwd, doc=fdoc)) # pylint: disable=protected-access setattr(_Named, iname, property(_Named._getinv, doc=idoc)) # pylint: disable=protected-access _Named.__name__ = typename return _Named namedbidict.__doc__ %= _VALID_NAME.pattern # pylint: disable=no-member def _make_empty(typename, keyname, valname, base_type): """Create a named bidict with the indicated arguments and return an empty instance. Used to make :func:`bidict.namedbidict` instances picklable. """ cls = namedbidict(typename, keyname, valname, base_type=base_type) return cls() bidict-0.18.2/bidict/_noop.py0000664000372000037200000000064313535200701016623 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Provides the :obj:`_NOOP` sentinel, for internally signaling "no-op".""" from ._marker import _Marker _NOOP = _Marker('NO-OP') bidict-0.18.2/bidict/_orderedbase.py0000664000372000037200000002651613535200701020136 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. #============================================================================== # * Welcome to the bidict source code * #============================================================================== # Doing a code review? You'll find a "Code review nav" comment like the one # below at the top and bottom of the most important source files. This provides # a suggested initial path through the source when reviewing. # # Note: If you aren't reading this on https://github.com/jab/bidict, you may be # viewing an outdated version of the code. Please head to GitHub to review the # latest version, which contains important improvements over older versions. # # Thank you for reading and for any feedback you provide. # * Code review nav * #============================================================================== # ← Prev: _bidict.py Current: _orderedbase.py Next: _frozenordered.py → #============================================================================== """Provides :class:`OrderedBidictBase`.""" from weakref import ref from ._base import _WriteResult, BidictBase from ._bidict import bidict from ._miss import _MISS from .compat import Mapping, PY2, iteritems, izip class _Node(object): # pylint: disable=too-few-public-methods """A node in a circular doubly-linked list used to encode the order of items in an ordered bidict. Only weak references to the next and previous nodes are held to avoid creating strong reference cycles. Because an ordered bidict retains two strong references to each node instance (one from its backing `_fwdm` mapping and one from its `_invm` mapping), a node's refcount will not drop to zero (and so will not be garbage collected) as long as the ordered bidict that contains it is still alive. Because nodes don't have strong reference cycles, once their containing bidict is freed, they too are immediately freed. """ __slots__ = ('_prv', '_nxt', '__weakref__') def __init__(self, prv=None, nxt=None): self._setprv(prv) self._setnxt(nxt) def __repr__(self): # pragma: no cover clsname = self.__class__.__name__ prv = id(self.prv) nxt = id(self.nxt) return '%s(prv=%s, self=%s, nxt=%s)' % (clsname, prv, id(self), nxt) def _getprv(self): return self._prv() if isinstance(self._prv, ref) else self._prv def _setprv(self, prv): self._prv = prv and ref(prv) prv = property(_getprv, _setprv) def _getnxt(self): return self._nxt() if isinstance(self._nxt, ref) else self._nxt def _setnxt(self, nxt): self._nxt = nxt and ref(nxt) nxt = property(_getnxt, _setnxt) def __getstate__(self): """Return the instance state dictionary but with weakrefs converted to strong refs so that it can be pickled. *See also* :meth:`object.__getstate__` """ return dict(_prv=self.prv, _nxt=self.nxt) def __setstate__(self, state): """Set the instance state from *state*.""" self._setprv(state['_prv']) self._setnxt(state['_nxt']) class _Sentinel(_Node): # pylint: disable=too-few-public-methods """Special node in a circular doubly-linked list that links the first node with the last node. When its next and previous references point back to itself it represents an empty list. """ __slots__ = () def __init__(self, prv=None, nxt=None): super(_Sentinel, self).__init__(prv or self, nxt or self) def __repr__(self): # pragma: no cover return '' def __bool__(self): return False if PY2: __nonzero__ = __bool__ def __iter__(self, reverse=False): """Iterator yielding nodes in the requested order, i.e. traverse the linked list via :attr:`nxt` (or :attr:`prv` if *reverse* is truthy) until reaching a falsy (i.e. sentinel) node. """ attr = 'prv' if reverse else 'nxt' node = getattr(self, attr) while node: yield node node = getattr(node, attr) class OrderedBidictBase(BidictBase): """Base class implementing an ordered :class:`BidirectionalMapping`.""" __slots__ = ('_sntl',) _fwdm_cls = bidict _invm_cls = bidict #: The object used by :meth:`__repr__` for printing the contained items. _repr_delegate = list def __init__(self, *args, **kw): """Make a new ordered bidirectional mapping. The signature is the same as that of regular dictionaries. Items passed in are added in the order they are passed, respecting this bidict type's duplication policies along the way. The order in which items are inserted is remembered, similar to :class:`collections.OrderedDict`. """ self._sntl = _Sentinel() # Like unordered bidicts, ordered bidicts also store two backing one-directional mappings # `_fwdm` and `_invm`. But rather than mapping `key` to `val` and `val` to `key` # (respectively), they map `key` to `nodefwd` and `val` to `nodeinv` (respectively), where # `nodefwd` is `nodeinv` when `key` and `val` are associated with one another. # To effect this difference, `_write_item` and `_undo_write` are overridden. But much of the # rest of BidictBase's implementation, including BidictBase.__init__ and BidictBase._update, # are inherited and are able to be reused without modification. super(OrderedBidictBase, self).__init__(*args, **kw) def _init_inv(self): super(OrderedBidictBase, self)._init_inv() self.inverse._sntl = self._sntl # pylint: disable=protected-access # Can't reuse BidictBase.copy since ordered bidicts have different internal structure. def copy(self): """A shallow copy of this ordered bidict.""" # Fast copy implementation bypassing __init__. See comments in :meth:`BidictBase.copy`. copy = self.__class__.__new__(self.__class__) sntl = _Sentinel() fwdm = self._fwdm.copy() invm = self._invm.copy() cur = sntl nxt = sntl.nxt for (key, val) in iteritems(self): nxt = _Node(cur, sntl) cur.nxt = fwdm[key] = invm[val] = nxt cur = nxt sntl.prv = nxt copy._sntl = sntl # pylint: disable=protected-access copy._fwdm = fwdm # pylint: disable=protected-access copy._invm = invm # pylint: disable=protected-access copy._init_inv() # pylint: disable=protected-access return copy def __getitem__(self, key): nodefwd = self._fwdm[key] val = self._invm.inverse[nodefwd] return val def _pop(self, key): nodefwd = self._fwdm.pop(key) val = self._invm.inverse.pop(nodefwd) nodefwd.prv.nxt = nodefwd.nxt nodefwd.nxt.prv = nodefwd.prv return val def _isdupitem(self, key, val, dedup_result): """Return whether (key, val) duplicates an existing item.""" isdupkey, isdupval, nodeinv, nodefwd = dedup_result isdupitem = nodeinv is nodefwd if isdupitem: assert isdupkey assert isdupval return isdupitem def _write_item(self, key, val, dedup_result): # pylint: disable=too-many-locals fwdm = self._fwdm # bidict mapping keys to nodes invm = self._invm # bidict mapping vals to nodes isdupkey, isdupval, nodeinv, nodefwd = dedup_result if not isdupkey and not isdupval: # No key or value duplication -> create and append a new node. sntl = self._sntl last = sntl.prv node = _Node(last, sntl) last.nxt = sntl.prv = fwdm[key] = invm[val] = node oldkey = oldval = _MISS elif isdupkey and isdupval: # Key and value duplication across two different nodes. assert nodefwd is not nodeinv oldval = invm.inverse[nodefwd] oldkey = fwdm.inverse[nodeinv] assert oldkey != key assert oldval != val # We have to collapse nodefwd and nodeinv into a single node, i.e. drop one of them. # Drop nodeinv, so that the item with the same key is the one overwritten in place. nodeinv.prv.nxt = nodeinv.nxt nodeinv.nxt.prv = nodeinv.prv # Don't remove nodeinv's references to its neighbors since # if the update fails, we'll need them to undo this write. # Update fwdm and invm. tmp = fwdm.pop(oldkey) assert tmp is nodeinv tmp = invm.pop(oldval) assert tmp is nodefwd fwdm[key] = invm[val] = nodefwd elif isdupkey: oldval = invm.inverse[nodefwd] oldkey = _MISS oldnodeinv = invm.pop(oldval) assert oldnodeinv is nodefwd invm[val] = nodefwd else: # isdupval oldkey = fwdm.inverse[nodeinv] oldval = _MISS oldnodefwd = fwdm.pop(oldkey) assert oldnodefwd is nodeinv fwdm[key] = nodeinv return _WriteResult(key, val, oldkey, oldval) def _undo_write(self, dedup_result, write_result): # pylint: disable=too-many-locals fwdm = self._fwdm invm = self._invm isdupkey, isdupval, nodeinv, nodefwd = dedup_result key, val, oldkey, oldval = write_result if not isdupkey and not isdupval: self._pop(key) elif isdupkey and isdupval: # Restore original items. nodeinv.prv.nxt = nodeinv.nxt.prv = nodeinv fwdm[oldkey] = invm[val] = nodeinv invm[oldval] = fwdm[key] = nodefwd elif isdupkey: tmp = invm.pop(val) assert tmp is nodefwd invm[oldval] = nodefwd assert fwdm[key] is nodefwd else: # isdupval tmp = fwdm.pop(key) assert tmp is nodeinv fwdm[oldkey] = nodeinv assert invm[val] is nodeinv def __iter__(self, reverse=False): """An iterator over this bidict's items in order.""" fwdm_inv = self._fwdm.inverse for node in self._sntl.__iter__(reverse=reverse): yield fwdm_inv[node] def __reversed__(self): """An iterator over this bidict's items in reverse order.""" for key in self.__iter__(reverse=True): yield key def equals_order_sensitive(self, other): """Order-sensitive equality check. *See also* :ref:`eq-order-insensitive` """ # Same short-circuit as BidictBase.__eq__. Factoring out not worth function call overhead. if not isinstance(other, Mapping) or len(self) != len(other): return False return all(i == j for (i, j) in izip(iteritems(self), iteritems(other))) # * Code review nav * #============================================================================== # ← Prev: _bidict.py Current: _orderedbase.py Next: _frozenordered.py → #============================================================================== bidict-0.18.2/bidict/_orderedbidict.py0000664000372000037200000000627113535200701020456 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. #============================================================================== # * Welcome to the bidict source code * #============================================================================== # Doing a code review? You'll find a "Code review nav" comment like the one # below at the top and bottom of the most important source files. This provides # a suggested initial path through the source when reviewing. # # Note: If you aren't reading this on https://github.com/jab/bidict, you may be # viewing an outdated version of the code. Please head to GitHub to review the # latest version, which contains important improvements over older versions. # # Thank you for reading and for any feedback you provide. # * Code review nav * #============================================================================== # ← Prev: _frozenordered.py Current: _orderedbidict.py #============================================================================== """Provides :class:`OrderedBidict`.""" from ._mut import MutableBidict from ._orderedbase import OrderedBidictBase class OrderedBidict(OrderedBidictBase, MutableBidict): """Mutable bidict type that maintains items in insertion order.""" __slots__ = () __hash__ = None # since this class is mutable; explicit > implicit. def clear(self): """Remove all items.""" self._fwdm.clear() self._invm.clear() self._sntl.nxt = self._sntl.prv = self._sntl def popitem(self, last=True): # pylint: disable=arguments-differ u"""*x.popitem() → (k, v)* Remove and return the most recently added item as a (key, value) pair if *last* is True, else the least recently added item. :raises KeyError: if *x* is empty. """ if not self: raise KeyError('mapping is empty') key = next((reversed if last else iter)(self)) val = self._pop(key) return key, val def move_to_end(self, key, last=True): """Move an existing key to the beginning or end of this ordered bidict. The item is moved to the end if *last* is True, else to the beginning. :raises KeyError: if the key does not exist """ node = self._fwdm[key] node.prv.nxt = node.nxt node.nxt.prv = node.prv sntl = self._sntl if last: last = sntl.prv node.prv = last node.nxt = sntl sntl.prv = last.nxt = node else: first = sntl.nxt node.prv = sntl node.nxt = first sntl.nxt = first.prv = node # * Code review nav * #============================================================================== # ← Prev: _frozenordered.py Current: _orderedbidict.py #============================================================================== bidict-0.18.2/bidict/_util.py0000664000372000037200000000363513535200701016631 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Useful functions for working with bidirectional mappings and related data.""" from itertools import chain, repeat from .compat import iteritems, Mapping _NULL_IT = repeat(None, 0) # repeat 0 times -> raise StopIteration from the start def _iteritems_mapping_or_iterable(arg): """Yield the items in *arg*. If *arg* is a :class:`~collections.abc.Mapping`, return an iterator over its items. Otherwise return an iterator over *arg* itself. """ return iteritems(arg) if isinstance(arg, Mapping) else iter(arg) def _iteritems_args_kw(*args, **kw): """Yield the items from the positional argument (if given) and then any from *kw*. :raises TypeError: if more than one positional argument is given. """ args_len = len(args) if args_len > 1: raise TypeError('Expected at most 1 positional argument, got %d' % args_len) itemchain = None if args: arg = args[0] if arg: itemchain = _iteritems_mapping_or_iterable(arg) if kw: iterkw = iteritems(kw) itemchain = chain(itemchain, iterkw) if itemchain else iterkw return itemchain or _NULL_IT def inverted(arg): """Yield the inverse items of the provided object. If *arg* has a :func:`callable` ``__inverted__`` attribute, return the result of calling it. Otherwise, return an iterator over the items in `arg`, inverting each item on the fly. *See also* :attr:`bidict.BidirectionalMapping.__inverted__` """ inv = getattr(arg, '__inverted__', None) if callable(inv): return inv() return ((val, key) for (key, val) in _iteritems_mapping_or_iterable(arg)) bidict-0.18.2/bidict/_version.py0000664000372000037200000000016513535200730017336 0ustar travistravis00000000000000# coding: utf-8 # file generated by setuptools_scm # don't change, don't track in version control version = '0.18.2' bidict-0.18.2/bidict/compat.py0000664000372000037200000000630513535200701016775 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Compatibility helpers.""" from operator import methodcaller from platform import python_implementation from sys import version_info from warnings import warn # Use #: (before or) at the end of each line with a member we want to show up in the docs, # otherwise Sphinx won't include (even though we configure automodule with undoc-members). PYMAJOR, PYMINOR = version_info[:2] #: PY2 = PYMAJOR == 2 #: PYIMPL = python_implementation() #: CPY = PYIMPL == 'CPython' #: PYPY = PYIMPL == 'PyPy' #: DICTS_ORDERED = PYPY or (CPY and (PYMAJOR, PYMINOR) >= (3, 6)) #: # Without the following, pylint gives lots of false positives. # pylint: disable=invalid-name,unused-import,ungrouped-imports,no-name-in-module if PY2: if PYMINOR < 7: # pragma: no cover raise ImportError('Python 2.7 or 3.5+ is required.') warn('Python 2 support will be dropped in a future release.') # abstractproperty deprecated in Python 3.3 in favor of using @property with @abstractmethod. # Before 3.3, this silently fails to detect when an abstract property has not been overridden. from abc import abstractproperty #: from itertools import izip #: # In Python 3, the collections ABCs were moved into collections.abc, which does not exist in # Python 2. Support for importing them directly from collections is dropped in Python 3.8. import collections as collections_abc # noqa: F401 (imported but unused) from collections import ( # noqa: F401 (imported but unused) Mapping, MutableMapping, KeysView, ValuesView, ItemsView) viewkeys = lambda m: m.viewkeys() if hasattr(m, 'viewkeys') else KeysView(m) #: viewvalues = lambda m: m.viewvalues() if hasattr(m, 'viewvalues') else ValuesView(m) #: viewitems = lambda m: m.viewitems() if hasattr(m, 'viewitems') else ItemsView(m) #: iterkeys = lambda m: m.iterkeys() if hasattr(m, 'iterkeys') else iter(m.keys()) #: itervalues = lambda m: m.itervalues() if hasattr(m, 'itervalues') else iter(m.values()) #: iteritems = lambda m: m.iteritems() if hasattr(m, 'iteritems') else iter(m.items()) #: else: # Assume Python 3 when not PY2, but explicitly check before showing this warning. if PYMAJOR == 3 and PYMINOR < 5: # pragma: no cover warn('Python 3.4 and below are not supported.') import collections.abc as collections_abc # noqa: F401 (imported but unused) from collections.abc import ( # noqa: F401 (imported but unused) Mapping, MutableMapping, KeysView, ValuesView, ItemsView) viewkeys = methodcaller('keys') #: viewvalues = methodcaller('values') #: viewitems = methodcaller('items') #: def _compose(f, g): return lambda x: f(g(x)) iterkeys = _compose(iter, viewkeys) #: itervalues = _compose(iter, viewvalues) #: iteritems = _compose(iter, viewitems) #: from abc import abstractmethod abstractproperty = _compose(property, abstractmethod) #: izip = zip #: bidict-0.18.2/bidict/metadata.py0000664000372000037200000000350213535200701017266 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Define bidict package metadata.""" __version__ = '0.0.0.VERSION_NOT_FOUND' # _version.py is generated by setuptools_scm (via its `write_to` param, see setup.py) try: from ._version import version as __version__ # pylint: disable=unused-import except (ImportError, ValueError, SystemError): # pragma: no cover try: import pkg_resources except ImportError: pass else: try: __version__ = pkg_resources.get_distribution('bidict').version except pkg_resources.DistributionNotFound: pass try: __version_info__ = tuple(int(p) if i < 3 else p for (i, p) in enumerate(__version__.split('.'))) except Exception: # noqa: E722; pragma: no cover; pylint: disable=broad-except __vesion_info__ = (0, 0, 0, 'PARSE FAILURE: __version__=%s' % __version__) __author__ = u'Joshua Bronson' __maintainer__ = u'Joshua Bronson' __copyright__ = u'Copyright 2019 Joshua Bronson' __email__ = u'jab@math.brown.edu' # See: ../docs/thanks.rst __credits__ = [i.strip() for i in u""" Joshua Bronson, Michael Arntzenius, Francis Carr, Gregory Ewing, Raymond Hettinger, Jozef Knaperek, Daniel Pope, Terry Reedy, David Turner, Tom Viner, Richard Sanger, Zeyi Wang """.split(u',')] __description__ = u'Efficient, Pythonic bidirectional map implementation and related functionality' __keywords__ = 'dict dictionary mapping datastructure bimap bijection bijective ' \ 'injective inverse reverse bidirectional two-way 2-way' __license__ = u'MPL 2.0' __status__ = u'Beta' __url__ = u'https://bidict.readthedocs.io' bidict-0.18.2/bidict.egg-info/0000775000372000037200000000000013535200730016630 5ustar travistravis00000000000000bidict-0.18.2/bidict.egg-info/PKG-INFO0000664000372000037200000003031613535200730017730 0ustar travistravis00000000000000Metadata-Version: 2.1 Name: bidict Version: 0.18.2 Summary: Efficient, Pythonic bidirectional map implementation and related functionality Home-page: https://bidict.readthedocs.io Author: Joshua Bronson Author-email: jab@math.brown.edu License: MPL 2.0 Description: .. Forward declarations for all the custom interpreted text roles that Sphinx defines and that are used below. This helps Sphinx-unaware tools (e.g. rst2html, PyPI's and GitHub's renderers, etc.). .. role:: doc bidict ====== Efficient, Pythonic bidirectional map implementation and related functionality. .. image:: https://raw.githubusercontent.com/jab/bidict/master/assets/logo-sm.png :target: https://bidict.readthedocs.io/ :alt: bidict logo Status ------ .. image:: https://img.shields.io/pypi/v/bidict.svg :target: https://pypi.org/project/bidict :alt: Latest release .. image:: https://img.shields.io/readthedocs/bidict/master.svg :target: https://bidict.readthedocs.io/en/master/ :alt: Documentation .. image:: https://api.travis-ci.org/jab/bidict.svg?branch=master :target: https://travis-ci.org/jab/bidict :alt: Travis-CI build status .. image:: https://codecov.io/gh/jab/bidict/branch/master/graph/badge.svg :target: https://codecov.io/gh/jab/bidict :alt: Test coverage .. image:: https://img.shields.io/lgtm/alerts/github/jab/bidict.svg :target: https://lgtm.com/projects/g/jab/bidict/ :alt: LGTM alerts .. image:: https://api.codacy.com/project/badge/Grade/6628756a73254cd895656348236833b8 :target: https://www.codacy.com/app/jab/bidict :alt: Codacy grade .. image:: https://bestpractices.coreinfrastructure.org/projects/2354/badge :target: https://bestpractices.coreinfrastructure.org/en/projects/2354 :alt: CII best practices badge .. image:: https://img.shields.io/badge/tidelift-pro%20support-EF914C.svg :target: https://tidelift.com/subscription/pkg/pypi-bidict?utm_source=pypi-bidict&utm_medium=referral&utm_campaign=docs :alt: Paid support available via Tidelift .. Hide to reduce clutter .. image:: https://ci.appveyor.com/api/projects/status/gk133415udncwto3/branch/master?svg=true :target: https://ci.appveyor.com/project/jab/bidict :alt: AppVeyor (Windows) build status .. image:: https://img.shields.io/pypi/pyversions/bidict.svg :target: https://pypi.org/project/bidict :alt: Supported Python versions .. image:: https://img.shields.io/pypi/implementation/bidict.svg :target: https://pypi.org/project/bidict :alt: Supported Python implementations .. image:: https://img.shields.io/pypi/l/bidict.svg :target: https://raw.githubusercontent.com/jab/bidict/master/LICENSE :alt: License .. image:: https://img.shields.io/badge/dynamic/json.svg?label=downloads&url=https%3A%2F%2Fpypistats.org%2Fapi%2Fpackages%2Fbidict%2Frecent%3Fperiod%3Dmonth&query=%24.data.last_month&colorB=blue&suffix=%2fmonth :target: https://pypistats.org/packages/bidict :alt: Downloads past month Bidict: ^^^^^^^ - is in use by several teams at Google, Venmo, CERN, Bank of America Merrill Lynch, Bloomberg, Two Sigma, and others - has carefully designed APIs for safety, simplicity, flexibility, and ergonomics - is CPython-, PyPy-, Python 2-, and Python 3-compatible - has extensive test coverage (including property-based tests and benchmarks) run continuously on all supported Python versions and OSes - integrates natively with Python’s collections interfaces - is implemented in concise, well-factored, well-documented pure Python that leverages a number of advanced language features [#fn-learning]_ ⚠️ Python 2 EOL ⚠️ ++++++++++++++++++ Python 2 support will be dropped in a future release. See `python3statement.org `__ for more info. Installation ------------ ``pip install bidict`` Quick Start ----------- .. code:: python >>> from bidict import bidict >>> element_by_symbol = bidict({'H': 'hydrogen'}) >>> element_by_symbol['H'] 'hydrogen' >>> element_by_symbol.inverse['hydrogen'] 'H' For more usage documentation, head to the :doc:`intro` [#fn-intro]_ and proceed from there. Community Support ----------------- .. image:: https://img.shields.io/badge/chat-on%20gitter-5AB999.svg?logo=gitter-white :target: https://gitter.im/jab/bidict :alt: Chat If you are thinking of using bidict in your work, or if you have any questions, comments, or suggestions, I'd love to know about your use case and provide as much voluntary support for it as possible. Please feel free to leave a message in the `chatroom `__ or open a new issue on GitHub. You can search through `existing issues `__ before creating a new one in case your questions or concerns have been adressed there already. Paid Support via Tidelift ------------------------- .. image:: https://img.shields.io/badge/tidelift-pro%20support-EF914C.svg :target: https://tidelift.com/subscription/pkg/pypi-bidict?utm_source=pypi-bidict&utm_medium=referral&utm_campaign=readme :alt: Paid support available via Tidelift If your use case requires a greater level of support, contractual support for bidict can be obtained through the `Tidelift subscription `__. Notice of Usage --------------- If you use bidict, and especially if your usage or your organization is significant in some way, please let me know. You can: - `star bidict on GitHub `__ (the "star" button is at the top-right) - `create an issue `__ (preferred) - leave a message in the `chat room `__ - `email me `__ Changelog --------- See the :doc:`changelog` [#fn-changelog]_ for a history of notable changes to bidict. Release Notifications --------------------- .. duplicated in CHANGELOG.rst: (would use `.. include::` but GitHub doesn't understand it) .. image:: https://img.shields.io/badge/libraries.io-subscribe-5BC0DF.svg :target: https://libraries.io/pypi/bidict :alt: Follow on libraries.io `Subscribe to bidict releases `__ on libraries.io to be notified when new versions of bidict are released. Alternatively, on `GitHub `__, click "`Watch `__" and choose "Releases". Learning from bidict -------------------- One of the most rewarding things about bidict is the outsized amount of advanced Python it covers in light of its small codebase. Check out :doc:`learning-from-bidict` [#fn-learning]_ if you're interested in learning more. Contributing ------------ Bidict is currently a one-person operation maintained on a voluntary basis with no other sponsorship. Your help would be most welcome! Reviewers Wanted! ^^^^^^^^^^^^^^^^^ One of the most valuable ways to contribute to bidict and to explore some advanced Python [#fn-learning]_ while you're at it is to review bidict's relatively small codebase. Please create an issue or pull request with any improvements you'd propose or any other results you found. (Submitting a "Nothing-to-merge" PR with feedback in inline code comments or a `Review results `__ issue both work well.) You can also +1 `this issue `__ to sign up to give feedback on future proposed changes that are in need of a reviewer. Giving Back ^^^^^^^^^^^ .. duplicated in CONTRIBUTING.rst (would use `.. include::` but GitHub doesn't understand it) Bidict is the product of hundreds of hours of unpaid, voluntary work. If bidict has helped you accomplish your work, especially work you've been paid for, please consider chipping in toward the costs of bidict's maintenance and development and/or ask your organization to do the same. .. image:: https://raw.githubusercontent.com/jab/bidict/master/assets/support-on-gumroad.png :target: https://gumroad.com/l/bidict :alt: Support bidict Finding Documentation --------------------- If you're viewing this on ``__, note that multiple versions of the documentation are available, and you can choose a different version using the popup menu at the bottom-right. Please make sure you're viewing the version of the documentation that corresponds to the version of bidict you'd like to use. If you're viewing this on GitHub, PyPI, or some other place that can't render and link this documentation properly and are seeing broken links, try these alternate links instead: .. [#fn-intro] ``__ | ``__ .. [#fn-changelog] ``__ | ``__ .. [#fn-learning] ``__ | ``__ ---- Next: :doc:`intro` [#fn-intro]_ Keywords: dict dictionary mapping datastructure bimap bijection bijective injective inverse reverse bidirectional two-way 2-way Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Software Development :: Libraries :: Python Modules Provides-Extra: test Provides-Extra: coverage Provides-Extra: sphinx Provides-Extra: flake8 Provides-Extra: lint Provides-Extra: docs Provides-Extra: pylint Provides-Extra: pydocstyle Provides-Extra: dev bidict-0.18.2/bidict.egg-info/SOURCES.txt0000664000372000037200000000364413535200730020523 0ustar travistravis00000000000000.LICENSE_HEADER .appveyor.yml .coveragerc .editorconfig .gitignore .lgtm.yml .pre-commit-config.yaml .pylintrc .readthedocs.yml .travis.yml CHANGELOG.rst CODE_OF_CONDUCT.rst CONTRIBUTING.rst LICENSE MANIFEST.in PYPI_DOWNLOAD_STATS.rst README.rst build-docs.sh pyproject.toml pytest.ini run_tests.py setup.cfg setup.py tox.ini .github/FUNDING.yml assets/bidict-types-diagram.dot assets/bidict-types-diagram.png assets/custom.css assets/custom.js assets/favicon.ico assets/logo-sm.png assets/logo-square.png assets/logo.png assets/logo.pxm assets/support-on-gumroad.png bidict/__init__.py bidict/_abc.py bidict/_base.py bidict/_bidict.py bidict/_delegating_mixins.py bidict/_dup.py bidict/_exc.py bidict/_frozenbidict.py bidict/_frozenordered.py bidict/_marker.py bidict/_miss.py bidict/_mut.py bidict/_named.py bidict/_noop.py bidict/_orderedbase.py bidict/_orderedbidict.py bidict/_util.py bidict/_version.py bidict/compat.py bidict/metadata.py bidict.egg-info/PKG-INFO bidict.egg-info/SOURCES.txt bidict.egg-info/dependency_links.txt bidict.egg-info/not-zip-safe bidict.egg-info/requires.txt bidict.egg-info/top_level.txt docs/Makefile docs/_static docs/addendum.rst docs/api.rst docs/basic-usage.rst docs/changelog.rst docs/code-of-conduct.rst docs/conf.py docs/contributors-guide.rst docs/extending.rst docs/home.rst docs/index.rst docs/intro.rst docs/learning-from-bidict.rst docs/other-bidict-types.rst docs/other-functionality.rst docs/thanks.rst docs/_static/bidict-types-diagram.dot docs/_static/bidict-types-diagram.png docs/_static/custom.css docs/_static/logo-sm.png docs/_static/logo-square.png docs/_static/logo.png docs/_static/support-on-gumroad.png tests/__init__.py tests/conftest.py tests/test_benchmark.py tests/test_bidict.txt tests/test_class_relationships.py tests/test_metadata.py tests/test_orderedbidict.txt tests/properties/__init__.py tests/properties/_strategies.py tests/properties/_types.py tests/properties/test_properties.pybidict-0.18.2/bidict.egg-info/dependency_links.txt0000664000372000037200000000000113535200730022676 0ustar travistravis00000000000000 bidict-0.18.2/bidict.egg-info/not-zip-safe0000664000372000037200000000000113535200730021056 0ustar travistravis00000000000000 bidict-0.18.2/bidict.egg-info/requires.txt0000664000372000037200000000121413535200730021226 0ustar travistravis00000000000000 [coverage] coverage<5 pytest-cov<3 [dev] setuptools_scm<4 Sphinx<3 docutils==0.15.2 hypothesis<5 py<2 pytest<6 pytest-benchmark<4,>=3.2.0 sortedcollections<2 sortedcontainers<3 Sphinx<3 docutils==0.15.2 coverage<5 pytest-cov<3 flake8<3.8 pydocstyle<3.1 pylint==2.2.3 astroid==2.1.0 pre-commit<2 tox<4 [docs] Sphinx<3 docutils==0.15.2 [flake8] flake8<3.8 [lint] flake8<3.8 pydocstyle<3.1 pylint==2.2.3 astroid==2.1.0 [pydocstyle] pydocstyle<3.1 [pylint] pylint==2.2.3 astroid==2.1.0 [sphinx] Sphinx<3 docutils==0.15.2 [test] hypothesis<5 py<2 pytest<6 pytest-benchmark<4,>=3.2.0 sortedcollections<2 sortedcontainers<3 Sphinx<3 docutils==0.15.2 bidict-0.18.2/bidict.egg-info/top_level.txt0000664000372000037200000000000713535200730021357 0ustar travistravis00000000000000bidict bidict-0.18.2/build-docs.sh0000775000372000037200000000270313535200701016264 0ustar travistravis00000000000000#!/bin/bash # # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. set -euo pipefail log() { echo >&2 " *" "$@" } # Generate a new graph image from its source file if it's been modified. update_graph() { local -r graph_src="bidict-types-diagram.dot" local -r graph_dst="${graph_src%.*}.png" if [[ ! "$(git diff --name-only -- "$graph_src")" ]] && [[ ! "$(git diff --name-only --cached -- "$graph_src")" ]]; then log "$graph_src not modified -> skipping graph update." return 0 fi if ! command -v dot &>/dev/null; then log "'dot' not found -> skipping graph update. Hint: brew install graphviz" return 1 fi if ! dot -v -Tpng -o "$graph_dst" <"$graph_src"; then log "dot exited nonzero." return 1 fi # return 0 if any of the below fail because running dot succeeded, which is the main thing. if ! command -v optipng &>/dev/null; then log "'optipng' not found -> skipping png optimization. Hint: brew install optipng" return 0 fi if ! optipng "$graph_dst"; then log "optipng exited nonzero." return 0 fi } # Use parentheses instead of braces around body so it runs in a subshell -> cd doesn't leak. build_docs() ( cd docs make clean html ) main() { update_graph build_docs } main bidict-0.18.2/docs/0000775000372000037200000000000013535200730014630 5ustar travistravis00000000000000bidict-0.18.2/docs/Makefile0000664000372000037200000001515213535200701016272 0ustar travistravis00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/bidict.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/bidict.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/bidict" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/bidict" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." bidict-0.18.2/docs/_static/0000775000372000037200000000000013535200730016256 5ustar travistravis00000000000000bidict-0.18.2/docs/_static/bidict-types-diagram.dot0000664000372000037200000000265313535200701022774 0ustar travistravis00000000000000// Copyright 2009-2019 Joshua Bronson. All Rights Reserved. // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // See ../build-docs.sh for how to generate an image from this file. digraph G { rankdir=BT dpi=300 node [fontsize="12", shape="box"] subgraph ABCs { node [fillcolor="#EFEFEF", color="#666666", fontcolor="#333333", style="filled", fontname="Script12 BT"] Mapping [label="collections.abc.Mapping"] MutableMapping [label="collections.abc.MutableMapping"] Hashable [label="collections.abc.Hashable"] MutableMapping -> Mapping { rank=same Mapping MutableMapping Hashable } BidirectionalMapping [label="bidict._abc.BidirectionalMapping", style="filled, bold", fontcolor="black", fontname="Cousine Bold Italic"] BidirectionalMapping -> Mapping } subgraph { node [style="bold", fontname="Fira Mono Bold"] bidict [label="bidict.bidict"] frozenbidict [label="bidict.frozenbidict"] OrderedBidict [label="bidict.OrderedBidict"] FrozenOrderedBidict [label="bidict.FrozenOrderedBidict"] bidict -> { BidirectionalMapping, MutableMapping } OrderedBidict -> { BidirectionalMapping, MutableMapping } FrozenOrderedBidict -> { BidirectionalMapping, Hashable } frozenbidict -> { BidirectionalMapping, Hashable } } } bidict-0.18.2/docs/_static/bidict-types-diagram.png0000664000372000037200000013166113535200701022774 0ustar travistravis00000000000000PNG  IHDR 0sRGBkIDATxwSUڇCNJuuWݵg}:QET"*}{AQ Ał( * RavE$3LnL7y`rS{{*a@fa@ffa@W@Z,̾w;L2?f/s<<{Ihh$a2 Dfa@fa@f9<H33+(4s)̓7f9]a@J ͬ0&PΥ0/#;^@fa@fa@faFfaFfa@faFa@faFaFaFfaaaFaaaaafa@fa@faFfaFfa@faFa@faFaFaFfaaaFaaaFaaaaaaFfa@fa@fa@faFfaFfaaFfaaaFfffaffaFf@f@f@faFfa@fa@fa@faFfaFfaaFfaaaFaaaFaaaaafa@fa@faFfaFfa@faFa@faFaFaFfaaaFaaaFffff?0qȄh.Œ03f(d#3/aȓn8 f 35k?30$U} 3^p\1(3oŒ0J_y2#frи졌5w| csܴ2$f{b3#=K#s_gǚ@Œ0B_nKuCynˡ03k8=q{.>qs`nG""̌tf?;֪?ik}Zҷ]̬KY"yM/gf礶n~֋gòfv7>9}jfv~&J:TyٙUzM+hnd7f={>y"̌,tyUM3u-e33֏LaF}$ϙέffn7q6\jft_O03ْ?wknZGs'90o`afgiYfV a\עF=~d*3#a>d}҆:EfyQ o8̎HI=cr}`f77Vi67 ֽ'D|m003ҳ4݃f63bu-,X?2Za0Ql69T6ԍqffor#Ù(b3v[bN5Vi57 ֣u 9O&̏n~f={~!̌,t.3k[ufZRE{K~f9<ɬr 5oP7ze;u6Y`f3rl{gfeCٳf6,#%=af|䯅ffS3M+uon0YR +{fFzF[캪&[u-I3O3֏aF#̇QLmC:/xG_pʌ,ueG [2F禉n}$KPF67 ֽfQ{*P|!̌ t=Qf%ڏQfvX"oyYι /Kis˦{ϴtYk}۳ӕEYzrفyԙ6on*Nt||&9q?unmzd;N$Je0YskWrOYtCݙqЁCL",i_ af ʾKafeZQd{3{-cKjf9¼଒ѢxJMSUrW뻥׆EHcS|HAJǖ?}U~4wWE7F_['d343["|3{Թ8oڬnm kgYvŧ'<iɬ$Xܴ2\ʇ&4[mff'$}HKɂ0K){7}(̌tߌtN3UϩWg?Yih7Y>=0# Ot:h;vK%]Z>HMuac?6f>,3+ ʏ43k`M6u٫5_s,tDk3+33;:Y٘ffVaQkN5O+no~ԢwR5& 3;8fa Jeл^م9t$..M; Sɰ$9=}a#{A7'̌ttzU {m3;=dk<Œ0^6c?̬$Ң JGOpO3{2jKly_ 9\ƫ_`=8km8oP3[sϵ33GNsCiVlf~hfvDf]lf*,N%qycXJC[n2ёͺfUy_ Y=7xS{Y5I*yly֧aι0?of ^shϝsQ+3nك5ݰȳϷث+wι%^Ϧ:ո'gX}4c03k:#ٷǘ];oDA4xnQc͢Iڌ3ݰ=ķeoT񠨇*t;߬clϳ? s.f:[s@{eo0Yw_up]ƚ؇g%9^ZueZ_={j2deYOu1NGpWͬda̵pC'Yũu65nlr6Ŭ{m̎>Hݓq7kc@T*Gp?|Rj4;9w~\qTov>ȸC",: fv[jMo&u+d9+fvs]Jigг?bfqwXI0 7x;6k^sЋ.̱Kͥ&{8}&̌t?IVUُf½_bW<Œ0XߴAYߪs/Ѻf \o70Y5)T_O0xgs7fO;̮ؒR3RV=jISZG_xsue%{PFfNdJigлnf-*  7:{v|'ٽKs!̒6:Sf{fFFн{pK9&$ܳmve}_Yls0 s˗F|on7zVߩ]\ +Km1ĕ뛪KlcvԷy6eny7;9=8j7;)3ީj~eYÎKAq0Jn}r~bf|]8繘~f9v[Q6_t1f)fafS`n.;wvF4b~sϠgs+F즄#[Nf%I pY]hȨw\M|:xTgqUl`c~sϠgsTnCfW&sv5;ʃDDu6on˛d7d `035ҝ,f]UُfUgzaFs,S옸[GM:^rYZذ/Sܽص(F߻͊Gj{zU.eft'da~)6I:蝏sT!A>6T7ǜZGGUͭS77A寘QXr⨅13HQ3Jƶg²r{9$̌t#Yn$u]"%ܫ̪/Ϗy.aα0cfn`~TsnF5:KuzO#>w+k/u}kE\wUzXi9fR}ؕsnR zqk-ѡ+EsY^Jgг *:W3瞩]jQ q7֩E?#j+Rzp ^@@f? 3#_#ݹ͢Z)QF *tv ι̬WEʕ}ٕeιQ+8V]mv}t*uGnU3Њ,55vs->І /^"3g n.Zu,;rvX3[G /3V7.lnGӗ8{1Oq7$yԆ/$v s'yk*Oc ƾeΝtE. _u@kcvih:˫=$Om97p9=nyՏL3j^e}gcܲJ:G9q៣V]QzQ.'/v=/tX/{+Vmgjdл *?TwYssXHm(;2ACnfvk^u)Ϙu˾0u,ꭩ3^0@f_ 3#O#9wLιffzWA~\ifkL?3œsaKԋCs_gf3 =hrhSCefpιG`Gym\űf_`_݆{T^vTwݢ졞6Q_#Lgwx5ׅ r44Q-xH)9bNc.`-i33?cl[3Wᖎh}o7٘ 7{HV`_ \[W;d}V7kZw=i7wLnn{]\unuQ'jm SsvI}_T}/^ تn<*?1A?NZ#z`A gffo<o>}ťf8NfvdU Z?zؐژYK6\l ˝s ~cBw~ǭ|75˜[5sf 6+w[ǘjnQGA_\jv3k?tҘw~,têR3;xP;Ss[GpEӞ xu=O}~3plX]vsWAzWmmnH"?߰"At{c3vȢI]._뭩3^0@f_ 3#O#9%{WY7 *?9A?2gL?3œ{avg[ :PK>Q2tN 7ppl1o&9f֦Q%fffjH$Qs~hih{udOP]z%QC̮Y㜛g{c 'ݸuvιCneI=xoMIq0K>ιcto$ܫZٟ~fٽ~l6R5&m2h^]GY/%9ܔ mոFgL܊;zjffW`hH_ŔzY9ѯ:lG ^-utמ^btqwgkySBQ眛VjVzXթie0As=+sf%'FsWΓw_^] 3^ f 3#?#97GpMJGw=0# !M<uX'K͏\چշ ϽT*w9d':꥕̟pS.}`Az^[[|'~}=Zw9lֽCh?z豪ϷSF=8>Óvtbd?MXթg0>upܘ-zۻuY!aNܠaaFf.3imHαfȗ0Œ0#3fݗ!}n-2֧}fȗ0Œ0#3͞MoCX0£_ 4>0C ffaF!̛ir 2f@fa@faFfaFfa@fa@fa@f@fa@f@f@faFaFaFf@aFaFa@aFaF  0 3Œ0 3Œ0#3 0#3 0 3 0Q@fa@f@fa@f@f@ff@f@ff@f@f@f@f@aFfaFfa@fa@fa@faFffaFfffa@f@f@ff@f@fa@aFaFa@faFfaFfa@fa@fa@faFffaFfffa@f@f@ff@f@f@f@f@aFfaFfa@fa@fa@faFffaFfffa@f@f@ff@f@ff@f@f@3V[/N)/'s~3!|3Œ0 'saK^Qo Cf9Vs3VؚL!sraGujm0"s5,DPs)DhbQ;s)9X_OT3aJ\0# 3Eҟ3X6R5dP @G΄RTҡux+őD1Ufa'%I{gĝ%5>"̅NNDa7IR=w[IMfa*&I?E+I{[Xj<8 EFԿ^_$Ia0_9᩿KtE)rb 3U /FlM'P\=w&xF_OYƖ5 >5}Y+3[5o(QBa.3ơ|N} ;Fa_@׸.|y W[Q ?Bܡ8+zԟE< <֨Ƒ|y}JFaE0 cG-_Adۚ54~C޳n,fZ_S܍no˻[e]ZԪcD k7Wyך@aD8Iu4zC38vOD |Y*B׉3 KFe-t=Ʃyͯb|_ }WJ4δ >dquYfZU>RCg@PYScxz:޴fߗ.U=Fcj]t$1`RgC*s]xenŒ=|YfWTtiFZ"?{?~nп|Ma?1^2^*ƑW&,4 AWԯؽ◺2"36eZx]r9@Y}sQ9 nnˍ|}zUVtɀIq{W:3JYgmEGn78y__x3Kꗅ*%2yHxqq|wɝ!0CFeUx39㛸*@+{Qz@tľP= k@q}>@xQ#w=I|.Ѭ34(olė%}} %8n7g%'0CC-_QgI$} bPGl 0 a{z8p*EG$jwo%"0Cέ0J ?^Dp3[죵=h m$cS;Eߙ_49*6 RyIܗA_{ ^2_]IDfIҋ^W~^٪Q ΙI7і67Tc-5-4;(*b 3W={堢1jX^Ѕ*+/dIr^#ޮzaW%i 3}k}_ [ ;o*23"c^z/b fgK ڄ$mTN*a3HfJһDf 5ԧa۰ @L_In/H"3$X8NR @W%]FKj51|I[1dfrMM]DYf]ҟlv)i ~a]s $]Ha"IC|դ$i2_̔{r_iZ@ac}[Ik^$#70 P$%0C1QnYH ~ⓢޒ"i}֪u|O H򧆨-nK`I_^%=0%]0uԚ _( ?$ic0u?.I 36.Iz 7tAUn'I@!.IgemS3*JjmC~dfhoJm7K,r3?X7t2ir8IݟmOz#@咚,j/Ԃf9m%i/.l9JR3_+I+ID <_%@IEK23ϛJ]-g f-$i&|*Iw @!+M%'O04<#}pA\ EI-LR O[I:$=C2aM\I IЭGR)rMt8LR% fm$lfLI ̐3l&ׂ}R$ f&Izv3$m,I-V-@_, 4dƋH ̐#>m,H m~9ƒ&!0C*ioɒ6,#_04m//2TF 9a$]~D%$ f.I,n"i$)r;K 4uM83@o:1GK$f#%iR y @!O/I1$iIʍ%u Hc$ fᏝ%uMs:Iڛ xIfq DI<'I/@!|P$ip`[?6@?v?Y ̐m:H4w$%m04%y5h$}Bba$ P{H$fܳvI~j/[KHfav-@-~Gn's0~;\Yyf+H ̐Mg䮒ʲ0w̕e-%]Dna,nj4 k!Nُ$fGKj<7`(i?H |sI Y-I:=h&I=@rmKҎEzyyZ ׿Hv͐ ̐%Kk3 $I3|ذ݊3IkHڗ C~Ưw?*Io!@!+\۝S1Iz  ;HL?%"C0C6XLҡlH*!0t?vF_#@! ,$%r3@)Im?t 92+t~@Β#0﷐ӯHR23d\9{$i:i 7~mf$K0CUl!x@!|m@I[BaR nnwI$ rIEs۾O$iy2˙~]>U~ϗ ̐_tcIGHڝG e^I}݅J҇fs—XfW݅oR 3@Y\ qoIH ̐AI*K2a6'Hj,$r3dwOIG6a27tg?K:d c$=n Ԙg eJ[r&ߐ-@!CDRL\' Y"In#ICI ̐!NT~tbIMP@6soْ6| Fhl 2 3@!I#E%"a0CF(ъPI͗R@GGI6񾒶 1I6?) YyI-M}_ e0C寒v5Ozs* Ybv i$Kas$=/ * Yb$M HcWHL,PR 6*'0dJui$DfB8IO6΃|Œ0_'IOwJ\҆0ԏwm!$ 6i[@+@ެ/Ԫ,4f,0R^ Pl%CI_}:RҖ?[@2ΚVjj!20ԃ,yEƐ\@2PIEC$mI\"I/[/df cEn!w3@y׭f,OREkvZGfoIM_of2HҹAktIz!uuI{SƑ`@2J7IdbIm P7#iK],if $]vO P';kHR 3@XxGԛ"uử$G~vs c$ĖK20ԁZvyIDa i@aSIB }4tDv_ZOap6XCf!y۽$i2i 3Tl&K@I" ./H%ۿ{J2 3@f8_RѬ?JfXm>Oa%҈0ؼ_wmnړi@2AI; nIڃ[f(k%$KҫfA܁%y0)>17Œ0OҦeAL 3@i,|坒a? to~L %5LaHOI0I& >m-cFX Hҳo[J:aN\(I˔py oZJ:|+f@ϛ-$ +Ia}^,`v9@Ar_ϔIͿfD̐3 'Kڰ,x|R tNK @_(^/j"tc;5NO =tku{M s&IՌ0Hm Ia9=7O=%%@8_^.#if@TIg3J0xe3I I0œ7ttM &=N0xpf %m<f\*iy7#<,I 3@\^ %i, sLoFXc3@#I+ sI f8"I hi$a0_&IqF~SIg3@m7dNWIa95n!{~Kڰ3@jq$Y#8'f[R9#,m*a&y8PtK G%|o PZ.)Lf@S`._g$^aIcZf@3VCf~E?v'f@>$i*z0D3J. GҾ3 I/hf>'+z0D*DRc sfHKG P f|CR sb%ժ~Fq PF'HK3 $ݚ3IM23":Jx%qcgI!0'bƒGḦ0$I#Cee=4a9H*z'g%m=3# PYYYYv@TVVn3 ޼.IFXHf+%i2qMEa< `F8Bkfʥd5n+' $BfJ#̌3@eee?I?!a+I"0 QdL3@eےt*qV@aa_3“:3# XfkDI*0%ap$D~3If@]J*aBm%{.3 ̵9_* %Ĉ0Cs$H GOa rf(lj.P[DE3 5X^R/ hB˙f(lzKj9qeNAa8IfaBUI:8df@cO'l.i_ jBWT(iA~s3)F#{4LE$Yby9Wȭ0U$[IE JD$M 0_JΡ}M]Bo.{&ȥΤ:&Q_=_8*dIy9ћN@:ۇ_x(WU4r*̿.i2Ւ.cbDp/!%i/V0&Ij<:{aߴ$i|6$\_HŖ,IE$Yp 7pCsIR-ˊ±=H2>Ur Œ߂l BE zxJ&ZbLsC!SsK9LF#G}%)(EVu;V˶]Gɥ0j,:&$8 P o#i"`)-a82sCNԜ$mXCd4b80L9`IJI(\,2*&!u=%5|Pe#Ic tqHG$ sX!}a;34/P22Xze>sВWqѯ'IM$isι=$5Ss$]lPYY[ 3?EnXABZl&Ce)?ɹLF#B%3f̘g=b3|%)(E$Ru䣒;:aI\lPYYO48jyV,vnGnϣ,zVtu82_BgMפY*^ګݎ?1żѣo)I) ČC<ӉF6'䫰 qxﻳB;uwa[<Nv;w|$ovTyoD(wsnm1U_Q6޺$(I8\{II%Y\ǵ~~#5q4ROSg8}G=zO%5em%& 3ZH:8%u 0B;9w>3 6>C䮩_rB+NnEI.`81SեrgHL}b!׿q6_Qo7pOjM4oݴz!Voxj⹽ۻWצKRѩXc|$(k'9N{3ŭ_o~RY*LL!a&ԹK 0OM}5Uy^ҫz&3 >o" uC dȗgm[G#a2ɕ0T>\fN#3?%lmsisx4z:߾~x^ i{SJueGZ00#35mjHĄ?xJ*sg?npFت%L7샑mg^4q)WzOM]I$ Np{8H1=9 ~DIE  yx_I[TtIfUO MHjoթOU=7^ڄx#~{PdöFw@:3Ax!^FNj491;]uoQ57kqv~k7~%[[fYT]}[- o = o7){J)wz[K҉JxN<$,𒃒6fV=H6:eDm㏛.˙q3c0C!0Nn'i$ 0WJrW9 ־"iӦM6-|Xg6rJ5U+ܮJ峮otng7~1mڴM 3=3'KB̹KךmNȒ#zwٹv_6j,56|zЋG|sdo$#IJԬYaɥ-2Z-$(uɻo)VSz״ ]2^K^O}lZV&F~kV>*RO_M$Q\"2@!n+I{dT䫛SiCW: Ko3'I£V9\ELnbխOsT͟ϫOf3?]s_4h$o'/3t]1)8;NDܹovRhE? hYޙZ1asז{/RY",RD,)DHʾCV$$ڷJ{99,s=̜O9gygy:4kpmcnlTaK۾I}}W̼k+>\uit5b>}>qˣ` d +r1AYxNL|60p_냦&etSn]:svSƟ賱T531cʁ@qWh8ƟGFW5Gv㻹74j?K>WB袎3RIa/,~N֫~żATa9cY+Z[8wNG#n^UCsDv>F.7Y-wog6~5T.Zfn-5l\sD> z/b:puEs\*)ejlXlfa`N["WaQoxf~4 42,#7e[Rul|u3W7dGQ/AYx H2q5 !/}SfalgRo3{>{u"cd'C'\`G ;3Aꪫôc9u %~٘J wYw-b%7#U:$^1ɴ-mϞSiJ^޾xtk捍?K\ ,IZ8HƪJ0B;o 95̴bkvUzcTk8ۄa#snȠ1':|>e"ndGů]V/ce^Ӄ]œcZEٍ#eZmi1EGc?^I?0 8I08r ҡ\T\:|UhoUn,cku[my_5aݝ_mUkVk (l^Ə 2 W;a~0~5>/rjkmTaœGp|iq+mcm|O}Ka~u. ktadA0@:ecB ^V J5#sK%O+ڰ_/{}/? LqM, R5GdmLJΖqDŽ,sq; eE*)eY;0C-]>fQ<輵nMg}]Bsl|-\,LRhU{WHfIzE@ZfӺ, X@"80s5Xn_3+ތa6טc-5l\sDkDMΖ#l:ym%޺S3mv0-. <9'>bFH^Oîc|53iwѧW0 > ,<4ҡ,wa9tus O|P"0wwo_}}=C'2-].|?j vk}u &8:|>陋]g/:.٭ЉqWa,“^`q?|D?Utcˣ<LH !dؾx(Uҥ`0Y &V=tjJt)9hX3Xq/o+q .Bt5l\sD.* \yEBu.Q2=hW>._%ՙ!=D_Zo ]*,0~?=|8d԰F `yO~n!yg' #ExN:0 r/t(g5]|"A9*fz`)_k&3'-l` (ڄiO4a^qs{jľWhVр ws`~0 Yu1~760X?eyA ]Nqp6.k??!8ý1_C_it57PB >YSJf |pht 2k 2cAcF5 4|vͶ[X.xq>ze®la_s|ߴ-Z\G~7f0G[TO Xk{jľW5I&MtS`}>߄H}E,L,cEVI.Vp>ggNr=_f||ǘm}U6}BorIJ '@()d&8_:@\d̈́ U g'3k.grV9VCzd0l[ԙ;<)eߚ_>䮉ctPd X+\>}fmjziV5G";n[u΋v4/ Fcعl8b%Ÿ)y׾W4Kxbk^UoK#8oT3=yfw{OEJL>Jü"~T = G{[]dQ4$g+ b*ZUۚ,־_KPr {[K=aG箠#Vx€ iS ;.EsQ y_H(ako*:6cWa 3 q6Ts5D4϶9T3V?Jf%^K:^@}'i/5{$>WZL} L/̐ k~=լhﶠQհu͑pRTnEt^W1Bzit4PI1/k}O*r~Fwt#U}ìRxIa~tX؇P#zyg#yշoP.zhXl#db(?_< J+7mQH e~c6580K޾>Kͬ{ŝcꐏGgzϷuoT5]s^R3I_FJlL#nU.]WR犠nזϕȕGH.^60y['Z3o`q?[٭K͊CG41&V~sc0\p@ ,!8 =ü,+l-r'=?EoG5]w!Vfp: N)2U^~% D=3[q}>UcYca_ՏT{%I"grɕR8|%٩o{ i^-9U dĨUKxWr)3dn~"ՈY^湕>uӫRgw}lVFIf#'Oٚޡ`g?]W:[;{m~WF[s,+Sq\dkwBєu߿FXלʩs }_jY+wy OHƷqev>Bn?+SgXo@-AYx@O!>tZvaBD J>+yj Ǚ@[- kE ,<KC0YY/qk蚈,[5LcRfrWGn ,<%D hωFk>Qve+˧a'W*$$i` sa/m2U ,-[ Ϛ;^(g% (Ü|?OeDEZa{ ߟ.Uy^jyۼ 0[:0 p Y ,guYəeXt.%_[)AoPA>} p?'Ix^0 ?Ǘr2 tpQTK 7 ,\O W7s|y` ^l>&.׻o/UyP*6WSjf>)}2Bx[,wFotk)a^XTt*2n?ο"LTYĉ'NTO&^?t/Vj8LS|/%sAYOJxqa"͉a0LԜ&dP8`H̓W2Bخ^j~xB:0 7sg!laBx0X {8h^dY >d^0̛[^f:!5a|tHNaBx0\lt 2µ(@O2BG:P`/|#dKhH d7V/Q\/m}ta.!Q dn Ef!dc74^f p'inذ0XYn\K+–_>0\:0 Wr1W:$%2BW]v)+6JfBΑ dMe` ͆L $ K:0 r$P*,aB0UT|2u ptH(+*W0 !\kpy9 ,ƶ&@"\TZ-,patEr(dtH0Kskd.5̓lR4/7>2],Ks>^YJU by)l/d8 Ț/Y)[}\Yr (ǃ~2M||gihR_f! #F(DžRa`Z ~0 !g/[<>rWJf_:$3Z[dn3̓Sk*Kf6Z+zr!#E9Lea.aPE1E:0 p=!I MY*ü>K ! ,\ŸCKjB 2e7ON2*FOf! c4/| 0U:0 W0 `tHaB0\AAY=|"taB0 U6ϥ p<&ɇ0 !\bV2R7} p>k4,-NDf!dfpbw]:0 3`tH.LaB0:`BwTD:0 kptH62BoSN5RY8^@?Cy` >+²`ta]C)8PYxV&Piv8]:0 ' PoH>/'9rf!dKo2^UN?L2ܟfi.,pa^6q otaem5`ݦ)YdN6u8W!;tae(tH e6{N8jBv"/ٿBYYʬB#,parvBy[ ,Jw otH;0 !k'M:AY8n)c@S50 !\*F&u [:0 GDK7u>2Bg/*`p6# p-Hr1_YD[-[e@ p +!l aB80`"u23 G:0 rtH)_d3[[:)4%d㘛\ Rƪ2B'Eq:9|ta0jbn0 !fhRQ:Yt 2iL[:uIwa黿sHa/ IcAY8-iMRM Sn} ~xL 7T<zIf,nxK:Ua5*DFMS2E!J{':nZ`/byJ߈P:0 'ptp3N0`^D$J&m:sQνU0C}\.wlתi:*然X\֚AY8~@d?U2Qh-k7j#{s 3Cjjy&S{lKk`@zDzn'vPOŜTAY8HG-!"6_K>g@]:jdQ&k'{vcWc4 ,p7 $!E/vXSSNon}\lԎm,ZBt "N \,dEyH :/V1b."a/rm 촮On'ZՇcWiu x*0L:0Tp8@!k26'nZis>vqb-I<ź1,VNJ7e$^:03 `tp? yRy4O.q+<ѸbK #rUI1JfZ~KhdB Xʸ^(w֛ha1eVkf [)S@`o-(,R˱@0Y:XlۏdLjVMy,[s]>SEH{_!c)v@+ <{oa)g:H:J|D~Rg^^SHD[3oSw3@ =NN20Hc8iftzjA3̺bb{ 4fWx#׏$,;=18?kbu#x@eE +š)[~AxGs_θ1r\D4Ok6mn(zHf2VU"NU4`St^6Wi1y2ek_9-l~W="{px+˦ʽsލCx { ,R@02"&D<_MWFI{pm?wsW("ii}"oSZ5,AYZy4%dE:.btXUf:چ^Zk8ꂆM>D-sŝ]RJ'Nt߫]r^Su_,dEd(}yt#"^-cTD͝9asb')XoJUl? w98P20d9W8͓E#"Ǿ%&rpeF 4o}khcUxf[ʹ@w H.$k*]:HLw:lw5=]_ VEv7-zu]:tsPQיdy3yMՁ^*Qt36AjcV-nh&9WxޱkU(玑04{]"Cs_u$ȵT\Aש< d"dE2\hf 7eHin8gm{гAE^k7z֯QT,{@kr _ B ,(+ذGV0>0\ìFɚϚzR=:w׈j䝢+R+:_Cϊf4PqtacqDW-W: wLwu} GG.x5`^;nW bUYUQ:0Y$\šP0˂(^lE9kC'X͵9YU?wjٜ*dE`tp W\St.`jSg~2,^,ꈉZӭk忂檜ts^·  ,@5\vd]󱒝O ͢/_Ewn yeA7}N2S9^@KaIk gq P]S=6\twႲm3Vx7˵m25ܠWR~_NU`taɉ׵zDuKsk\s?M1k0yQ,<{_=WꮍLc;+T daI O8wôHsƯFYo{yfgcӭ_\!;ǨJd HdKwG+ G: 4s6:{WP0Y{66;g"Z3_/̇U.aW# ,@%eTW60=(iEw%^ar!tcý/dڌ8#j5d)dEy`tp?gzuaaL\-(Lkכy z,mKX͝t OKfhv+{8ĊKtA,:(p һmb- :ʚnJ/kЈXW1 dEy>~qELqtIi_搵6o.'~FqnRsZ'˞=%JMl6 ,˚!FNItV 5l@Jԭj͝-okc"Op&@'etzz aeou%9b0FpeOV k}CS2>2e`gXoFWpfi6xF:0DC&ptp'=VHtf Xăh2xÂ@RLvts=\l 2"tKw2KI4 NK-t{,xuS>o9Q"Jm",k895W h4tA|ՐJdn-%D|X\je\s`o.f]e ,j3I1sk:Knh&9Wvhy9@M"^k M(ШFz5\TSZKf }0.KtVv?Tݐ8-#l[Ixޕ-f.5wII{&pta {yd:#Y 1OW,{xEBėmkfC>i?Gޔ/ttaqgK¹ނOwtXz!Gޭ%F锫 TGBĝ_nI77|a+{Γ9 gN yX0"mq椗 ߩsrk|)R{Fp{% 7K*K=U:Lmbhq([ɴ=hi I8OAYęӁ쟥x`N&[%OGwLllj@X[Cތnn{#9pta+0~/ 6 W:(.7?f 1g@=%ݟ]ѱ^Kj>#P&('uVIdG[u~Ѫbe.0F:01"QDJ\W];n7:/Qn%ĦϯgM77dܨb1M:0x(+8 K4I1Sa)haHNqC(vܡ7UxIf/zKﰱ*pviTpa MP{|XWPB$/;mD@YĉFI/qm(\:0Hc h搵#^:eQ,7~1&QŇӥ {kX\`sag1G|+1ȕ#CY4x`F+fl*bH ,g;oaR՟,-@'W{Xg/y)^+dEXW8H6c (qFigYPh^B$]W~zZQQOAs& f%Kq9P1Hd(/ϽU N]bğN|< %޸%,8s:i~HfQndX (]0ʌ6`ߓ'"i|a c%\a㾓N.g^AY@e X yyJ8O0l9#1kix8“M>%H? M w5Á|02 `t fta8GMC5>)l=}{u[os-ewHfQ>4UOr.PWP:RCC_IDr!M! ,6 G)DIJ)ȉj3haM7wcK:29 ,ʽ. ThtcPcTUJ4d6PevtsFV9qA200ԂedSYKx)FPuC~IVA!9vv%ovaK - . fJfQveIQ2`( 5SZ$=]^ d~4;}YtsVCatae`U[(FXz9vVMwJU+eӝzu/i+{]cg?JfQV^K:xt@mLlk>wLb$a4]ϯh-9G߫Jfus (#5Z^!L:'4eajCƎERptH_66F)!=yJ%4}=;@ ,r>a(g!dGיd66r"s"/ r63li6Oztu6k+ (WgS2")iTJ|S&mIgv&F߬O1,A) T"dEYd$MtAݺ-8Ty!f7͒I .q#'{搆SϯNeQ&0A:020RblØ0YbdUivu(q\mGX2s&}f;a@z VBau}Ruom4t:xG|3/ {T@f@Y$L:/"0Ucf)I^!n|a|钠 {}5\{nq "dEiٴ7&i00>Z?Q٢jEj9a'?{[6@5 ' {WūJ),J53s GL#Lj< oN^GTPi+6R$&< px+kޏEs #dE#8I:0"-p822ǘ4dH=32ZW)S+Ӛn5!L22̢Tru㸦gN:ȼ0S2FYsXJ Gp%HP^v Ⱥ%y+l~Q#k~ϭV=8ՀAYSlÈJh=P29 &/'I'{ۻXe| |yC'׼Fڎ eIpta18_!RGaDf8PAqjC]@; ^ ~?+%(V9iK z*ay6"Lpt38joE46z,]&@݉3\mWpOwiM7wИ5&AxA:0hlk4ӰTt:kw5l є[z3z{25ܠW|D(dE4.Mt'b\=O2 pt!Fz;ٸ3C ,",.J aD| }V睌h@BDfF2]_UϜn-ǒVAYD, ktHI?wY:4Fo]oy@MĶZ%1{׬{Oqy @K0|bI$0?3UKǕwܞoTii'zI|c'R9oF]Ε#C 웽pΖwY]Pjrktaa$È\*N=ĨH]@[5>MvgXlo)\9 h-2" 9J& 4Lګ3:*ڬvTųIwFf]nOJfQYåCY3e3aDf6P9;bIzNfkꡘ:UijNY88T20PD 4e q7yA}Om+xZB~QӮ[߹uܩV=)KfcI0ܒC^CwC!!;o2|wKN7|bwtal t-!gܑ#2z#V9-8Tmo$i}\kZgAw}25\MY3`tIwx^jhNbƅ7G:}y7lM7Gl*ptaV~N%L:/\ h_zQ?u.T[ZY=r1P/t_H쫩2dm5` 0",Gުmcͧ3zZh-QƿS[gSHfa0R:ϤÈȮf@wOij:V<LBy ϪĤ[ɴL>6M ~!aeg~0P:S0"8fgңzll~Ve^pZo3?ATPV:0 =<#2;{4ˍYôWz0;h5} Fc`nU~)ٵ }@+Hf73"l Hqd//<`'ZFuS怴a4iS܏ZK_GOkyL+6 o ,ۛMItZㅒdTZWՒӇ]Ҥu ˚[͝޺lFHf @>"*N/FUUm9-* JZK.g%_=ښn(~2^\0!"O5~./Ď;/4I^//GM0 8*/^?%:gptaN{2a ヴd{FݵH98arT{TA;]ӁF4dӜ!LOCÈƪ..ʫ6A>YWeKn;n}5\ mNg9xQB99 ![:d/vCHcDbkըӓ@GVaNgkT"5Fdr]sYji@GdN;|*:a h։,y}' U2=0t#2*\x+ڬ,4XmqT1MK,;&9in c sptP:(\TtV1*$r<p5R'o\PߚnnnkM| +FdomU4J {w߿繁n`8A/’ʺgְ^?MiRdӔ=ҶJa%-V"=7Єw!Tsts=Kts5S0'O"XP: Tq ́Rʼn,=\MUlXDk}.~&Sh'+RE,B4,yzUf9ruGzPڼ9i~"v'\4DY1g\h .T9_z-=.o>V,̍h d?ALBĝ8nԖ"̒a2BYYf!d 2B0 ffff!daBY0 !, 2BYff!, aBYYx0#|tu10WB7̽H.W7jA,MaYyU܉:a aaaaBYf!,,,, 2BYYYYf!da2B0 !, aBYY0 !,daa2B0 f!de 2BY!,de aB0 ff!,deaBY0000 !, aaaaBYf!,,daBYf!, aBY0 !,,da2B00 f!d BY0 !,d2BYY0 f! aa2222B0 !,deeeaBY0000 !, 2BYf!da2B00 f!d 22BYf!, aBY0 !d 2BY!,de aaBYf!,,,, 2BYYYYf!d aBYf!d 22BYf!, aBY0 !,,da2Bf!, aB0 ff!,d2BYY0000 !,C s7N1 Ց Z;J\ì'8V;0T;vaH>^90{D5̊{"cs LcZG;0 ֑c Z[JTì':V;0T;Na͝Ш|.ڗ hzeF=4m :%ry]SG0k*Q PaWeS/7'Nx/>K')ڷ7tsu&K󺦎Ra=Uf=X;syz"N!̍I??6f̣~O :ravC+To܈bCە fG k!醹|Z酱oxǁveg1qvȱUS%ravYܛtfX68-+V;]90ϑC2G9T-$0h72~[[շ/:zU8c{ȱUS%ravYB8rv;/+V;]90ΑCTfB e Y Gqp ^*Ws  qk90{DN5.{ s gej'+f9?EdԨf7N_Ɛegp0Wycɠuǂ0:ravS+Tk枎ˊՎnW53~h }'NSÜUBׂ0\ZG6.j*s ^|bەs Leuxdo݀<.Qx- st|e0f=,Ü>*s~?=BE~偹?0000XYejt1C͝g0{0׿+휋݋{Uef/>»ǩy[mdH*.^pX%ڳlG3R#G7y*6ug0{{D)6hņL[:sңS?TmDŕ3yiW)6^3w'n3U 1{3[Ɉ *j-!L}~AY쯋#Fde6[%~U]fȑzސ \T ]YG5i*QJ WZDtl#:~pJiXMay0\g_AX-*;wf4;[üoрū<ws}v!p"aǁu.߾?~sFmn3WN%eoZP#G7yCpAHUQJ WZJJ0ǎN5GlAۉ8W\K.iW43fGޙުD[\>km M0/̃!V/0C4-qp [~ $?7yo;vJ/nIƘ’ ?AxfHݺRi=Vf9Btz&7c,GlG,in)9Qke;(+c%JaNkFYaN娑-]ѮRhsg779X-$0w{a^[jժUa 7#/!L}hһs>@Eܪzիg~Z|N $o9x֮{i@)Q`YvsvWk7hfg~F=oP.P;(ņc%JaHnG큛2r?l5YtqEb}XvZ;3a;c\e_U\| }A߇Uࡠ/)i%447L`nC~mIŧ|F=ov;Rj==VTfϴi"GQ~_4bznۉE:g<\kb+U* gyLB" s C bnsN_Q*a (+!kRyktA MDŽ4OD<pl_~p[oKQ* WZJBQlY8t1㋏6-ׁK vb@̧bxjWfܙK 2dHYlwZHa?r#@׸0B\bnn1!vNotp@ %2a`5Go XG4^i+Q wZDYNKq|ӻ)VS,<(lxs>ΪbU LIw?3=V \;0eX/0;j#/^cË7 բy7g%)hƦknx~pGoXGNXc%ro1!)7O17L9úׇނb[o~jǷ+,;ӾavƝZHa~>tY07>ZaodtYK4ώ;ͳ=kU4ͪEQ} ?d;A؁uV90E0FBdž Kň!:iXv;ӶavȝZHaL<4v:Ew̭{3̸-:yxмq}\v}mG{Q \Q^= ?"jkr43[qoXpop~R|f˽-Ws̢˕Y0`/ ߳΅_\3~) IQ[ {tNZ̭laW>֑7>+ݖя Wf`ʬYd0ߕ}|p;黟̯3'xxfF'ߣovKme~5,(`.(E}1Ϳl<[؟=lesu*`•9`ҕYNKƱwM~ĿmmKևcB˒ ]g]>zɶ?mقeeߣ#`/2,"[`S3rk/3[m\\ӻdw0ʬe~$~F oyrx=gON)gonX^ssXw{7fG6y[& IIx(`.(/}׳cﶤ^ {o W渃yXWf/ #s˲ρqP{ 5 L]afDEقe݇gmc{ޖIxeXQ\Q^=2?"pk}_"gH^[9]^4M-_V4Qљm\\=`ҕ9`ڕY 9u2}g^bŊ+->tkw{g'&&w4 &9K${_ ?o/_:r򛆯ldMl/ZYRmpltttmh[h䔇6os&'G6yvmץџ؂:{W0WgDspxĹrgw&oas̼`ʬe $cdhW?$IKˊlo]F;ozKe^]We+j^9:Sj˦OqG6y;MmE̕ݣȂ:^n0wR?FYdf˿-㞫29+RAsssڮ-x`FZ6|g~Zچ?s{m 壭;b3jޔՅ9w0 &sc0Wcw {3Zsoٺ:z\+`ҕY=S뿀 b=.~o&]#7|qW7Q۴CwΖ3?ԲC+6 mm'.9,+4˻GQs>9-?ߖ/4u fsusRWf<+R]{v<0m^.ָGߘҰ~vC k|s[xxQո+|ms$|Хϥ8GqsFy(`ԼO0l\tߖPhf!s`ΕYtGMuG <}"ti&vcOu_wyn/$I2UGվ;9^ginCw=⏜mO»x /@D} 2QD\y`NwRo)4u fsusjE2`ʕYDs͛+ /u{O?E?}u3Ws=i־v##Nj]E]x}/:g΂]}r駏>3/w}8Q\Q^= <"g|'uxC:ҹzʌʬe0 3j013L`̂Y0``̂Y0``̂Y0`  3f3f``,  33f`F0,f 3Y0 f 3Y0 f 3Y0#A0``,  33`F0`F0  f`F0#`f,3ff,3ff,3f  A0`F0`ff̂  Y0#A0#``3Y0#̂3f`̂3f`̂3f`F0`  Y0#A0#A0 f3f3f``33f`F0,̂Y0 f ̂Y0 f ̂Y0 f A0#A0``,  33`F0`F0  f`F0#3ff,3ff,3ff` 3`F0`F0`ff̂  f3f3 ̂`3Y0#` `̳5 2 0 144 1 144 253 1 124 2018:10:17 10:10:23 Pixelmator 3.7.5 fF!QIDATxw|߱gU3VjVQF{Kj֨MզVƪQZY[Q{XiB$Bܑ{cѾ:|/%.qK\%.q۔ԧ.E'@7NaD8W()]aG&M 4KI\I3#L*P$/+⻌X1,,.\~KAsO67AOƳ`5ǟGɼln3TL4D~POR3)KO}ݟ) M{H_]BF3d )O_+ϙDz0[)zЬSU =eaʺ&9R+NxJ$ <,02,eD jS4!:"x%kQ:"IXb&qZ|R%dюOq)ϥ)o1%|Og99 9LPh~Z Z#Xb L}DE:3=\S(B{[$\`3h0IASv-f17|j]?)Rx:N/1}Q+-4 HNb'>1SUzua>~N:+3 =*r15sJSԢ1P~d)9B4SGیxЕxƯTp3Kp.xdؔQ5Sy\ 7FӖx&!(HU:3Y =YE*^DI'?3=,jԳH9&LL,u?) ǞXA?*ݡ4RMjs0LkCMa?5Z{e|>Gv0$'99/&S_'ӞW11Aڊ3F=Z%C%;D*:+KZms3HvDYvbtE^KP]<ڪ~ :Q1 ͪ oe1*f3&F(PAj(Lq@=,󥽁n"h$V~8*Ρs ˊ*g9~v5Fm8衯 46ݓ2~Lkèl9Mho% %jG޾Hr'Ƈ?GZ9UKKcX3D0\aZU,_|ۅ:yMDrKF 0H\.z=d/F4669Jm9$%`a~jԞqQi$Go)FWq6*wi;*j??]8UTL`Pi]I3<g'gl{N5!uB>fEx30[fv%[T};<./-׊TfhUTbsT(_axk luP#`~ /Jyiϱ;fIngO B)GI7 f+0F2 WqSM SCLu0N[472R# lDۭGF"L%c;NJ@6Y@]Q ,j:+Yy8]J]D~ޥP$}O0<)9@2T(Kv#I V'K7Yk;,ELse Ɨn*{5P \0!tR@#z\s`y2VcB>taX8鄰JbFJrI8e~mFy>աxaM13;sFi[Z|Ϙ}Ҡxн,0#׺+?d#iM_~W- f8Q 9?UT9[{ӓP4r.ۡ/;+0a-X0 bⓑNxիme`NtWMkdiJy\!5uQ {v/aVo.H&9'5:+`pӗLNKxD>s%|*CZ.N[ }wݰ;p2*\XVPB-`ӆ^TƮOUOO7vIM%5w7Iȩ 17G׉~=yi,fMؕN5]j,07Khp]_y|ZV9Ib=wetֶks=fgaU!*mHk vZY޻v&)3:q%dazcxmHe.YoÚVWKvz]s[)e FEk#~»o :RW,<5QRі2#VQ;F< C4Is -%Q®w}g&{re4o~k49] ?,[t"΢n4IMi[7z|YF=PNwu _fKHaBVKIOC'64.Yt+j 4*(؂W툯]>L$Ĵ@_1eбY6:g/+ǀ8xȼH&ZHi89I`ۚW[F-5z4[j@-&tcwPe5{;E)sNqsu˱d H;gfM<&2x/\p~Ҽq߰$Yen^}\!эmݛQAde_1NV'[*,_8h{q6_43U,Q\b)ԧ̔Ye/Ct2ΙE3]$rŌњNRdM|Ӗ3A =~c%gV}k;l;&D٣UY4^IzbHSRt/1tf:?R D21\J/=#؆Tl J1E3x,Gol;>ƫ/1AaDifY+d{AJ`'+یq|Dx:&LLnQ'Wate4xS]EdFCI9~eɰ`9MI]ZA|O#֘agkaG3K.;>r*^fc!R,i@:i&[4?1qHb[8{%,00^'`"L柖PK tL-7Y5,B>w*!J~ F$+':Bge&!;qH^eH\v[U|Ci3l, r#Fx+x9VdsIb2_"0}2 [i"G=|I[n>Ή@%JZ " 3jNL`kKRKԑ#Y(8}eF^,U%?s͆p^;uF O ݚ812봱'$a8,W.;*:G!DUMC<:9uK+!vHӔt}p@f&ޒTѐx]C-Sʲ HI5*)§98N @&\\xai';_8٧{{b=I]by660 c᫡ t^UI'x+*1 v;$ 9\RE&n^; 5uib xSXStf*8] hݻ)Ÿ"iIJڰBm,PYX}^zC%]VL{&lLVY4D&a(WD2rt*rQ81 0B &"P[&B #VQ\gHYӜ\54$..OEɜm |޲$.3/·2zGb=  ߨ.2Fbg$=Y1 _I%lf!?_R2%LzRd$#I;Jn)Nyj?0l7+U;0FR@88RDȢ ^^W B Oc஧9饸Ѐ@*J2߹fъ6' t1(BVIOz2 OIf2;Hn+HAvJPa%G""Y'Hk7A23a:q99M0FG5Ll{3B@Zfк(n5,f&B~a8qq@}GdMv36AN SftcXzs\6)z/#y]ple5@oZQ o>R43P|%@5>Y#= =ZnI6Rf4)d 3i$7iP沎ݜ&mDa?*"FK9r`T:.)&!6W@eHZlԕ^ٰJ=ZW,kB+j~fg sW 0I-'<%犋miϸVmLV!yF7~0gQAt9eEiwHJڬV|:*fuřH786vsU0PVDWАj&?yɃ^!/ET 5GѝoLAYIa5#G~٥:w۫$ =(3#Yp*Պ>_G ./ֳ0|EC*S 3i,-p';(OY(Wo"9FɀٲS\{(IiaPe6X~Lw1'+Hӂ/+ NK^ѐ>f; #1O@O߇J+J:t4:^ÂovqG< O(xHO~eN `;҈"'uDRH;&-x.[D>=O{^%RbwieiI}jRr8E(HWj('9HUjQ5}xf5l '9uS/2GJ26T(ɤޗ`k8& Ux%7U?ToJ>ӟ#pA6)NCa%[ 6/ׄr"-ya4;apL(=/$8-܃.H22"-e-85yj@+R4O QU(_IҺō/5uw2=X'iFm$E&$=yc$O'1,<݋c+vm[1—9~y+}MC{SZO .8ǿnee#O/g&?JFҒܡy֜ >3Y!s ,b;/A-bcԤ Yq'9m)B8Q?Y"fES$Yl2Md~縫 =EÄL8Shnru X>Pr{z3)b ]iK#SL%E<ϒdUi ȴ+4mJ}7ӹnq3 ,fBo:ҒT4)D^rŦ D0IG84 xöo"q $lVTF-15(O)-XE{L3 !\նҞ{DWlP1Md沔le 2 5 72 1 72 507 1 507 2017-11-16T12:11:95 Pixelmator 3.7 P(BwIDATxwWǟ=DIQ"⧥)JPNCT)DQJ٣%JDFVPZG=3>?=s>?=A!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!?rP5 BdQ!TG iXH`jӾf.N. KQ[?a҄0!JqOl8_'Dqo(cg8גY)DrPUaOrB$2h(+Eq FZU|WR3]< Y73Rh!tW}ꖿI4w08ƒ\!"7?qR 5̻0㬦3gi=ﮧj٨Vdk"Va!+I#hJumg|?87\|1M4#^bfpEb"xg al%Wx3r3EJ/Jpz}Q]iڳd+"j򞫘nŬ7a ԫY*^[hrL7яޡCtJ&X}HCRì4-?&!-]i97%H_3caJ%9NW1zj zUg LkyTHWekCգIY ekƻ(OQ syohe}D\Opat=(=\՜BqOpEH1srҝ\jn:FD4Ϲ04_v{G%soȓO._SO(\k殝tKG9Ϻ Dz&My#`/#éZص1ELoc{ ro/|d#53IXZ*+[zDrq.E2bI\!懕F SA r01aǝB +_ϗ9z6ڞ|: hCO1u_??oW~k>g3y<Fя49O1 r /OR-,yτ5/#lkT3#Q47Xu vV0 %rBMB׬r?i\w]ʰ>F  w2y|( I;·,Yъ*ITE!]62, 2,hXϙ)ȏs"䗗d,-RhxY p KjuM[?ϩKF7<JВGXMĶYShG9ɫ4r-ADWWmk>L*Ӌ5-̨";:4O'06rI6!;35sf"vҭHtAy˱5p(v?OB9g}+ְa=hO rWR\Lq R\qPk#}df: {}%+&,J?e7^mvX̩)YB9Va=y͸*J6 p];E8gen8l.K,}@_.BS3fJ͚rw>pfj0}A61aA8V*DZҟ,Y2پmI9keLۆEfRfMvJjY͵ _TX(ZP6!} s8wf/Dm~K2&"1M B]eN͞rُFr9cC=F ᝵q':`:y# ?scVRL.~fPd<{(tᲤ1t]Ƌi30qmҨMx=qO&$gws{GLT8g=+}|j`gq13ur/'U8 ~^{nwpI؂\Mpt q}_1EW5 j۸"N~Llx%yht%K=\ XqG:0b㜦c?br.b{fsB[-"k Q;5\ߥID|2'\^FŠb6/$Մ{]ݏL܈y,lRFnVGw/S6bwI*Uëa^?V6T8Ud4qzИX/41,>#J{rڲ(bȄ8[׸Ndlք˃POlp,;kt?nh{UYVϗ)E>'Oƨ2^nI'oq!P}tD٘+ƣcn Ja\rgb&i̋M^B=l8nvqEk'b<tNKuBx#,p'Bd0OS˜N%\@ϟ/ Dwp`1W1x'WƸO-QG';$B&'#f7\-H"vQWM|m~:+(07ǼW߸VO&&)ͽR)+nHüa' MKVm|ۣ˿K^.1E;w;UPs]t͟ݍ+-CW! U=6"a.F,,wv 4LK'"|fļCoK,η} wr1O|=).J8Z'jU,Ȇ"_r0߶3#&ҏ %{FXR-׮HzQV fFuJu]ӅRPnMQi eZYKs)oޠe6qu&ǂW\|7;ްQ/НdrQ2 :&ëH׵}bS(6&9 o YI>1|E5s5s&[Fn@Iɶ ^SpJRn$M4if6&T tϞykpqՋpWy~jnmAc@weE_`7 +KTq gR0a>\Fʼn3 MƱμ3l4 "0\Eeүd"yQegHGVPs^2xݑҰ70\ROkA'H|뾍<zUX lrw Wz>gzX&\gm1;j|&֘'/)iA5o)"fdΛڍQ=Wm)y|99?x7W374H'Caw/zٰ_BO}t1qi;*3tY, aWnvbcΪ,c/_pـK҈$>w3C!'Z;{CJ6J'wƞWѢ)83TWjڋKۨ51ϻV7iD]f1LV'}zN/$75C.7U2З1CZne 1V|Zw8Xge,fhmvIFUnSg! >~etzӇBE2 FEϫr bmaCQ=j1M;#Rpz Ȉl1W1e t9 >-z#eq|ƈ:<(3)Ms#'J'LV:;=Q+:xO3fb,ĝ賞{1/\d|Vk( z"eV5H{[iNZķ;87{ڻT 3nw~M5GXzЍ.fhZ Uƚp$ĴU5ʐc1.]]ì/sDjp (f~E7|ʋ q |g߯<7%܎#iX#5nXʉL/;(&}ڛVR:1gC4{Yh"_²J@[]gtrmѴg"NpcfULrE4Xv,SٹڵUz?D.~{'ʲ5.zx\s? :Vuf&BϞE!h1'CF)k'k-{Ar:|F.O-t=mDegGKQmOU1> !/ΰ[=hI*r|J7Ϲ }CQ8gnrG 7h)K 6w,mfQb * fBO"a_lXCni9?~{eYp𗌲:?EP2~9e^*B@#&$rRILJwk5, -ΗG ׿!g6Bs_zu\@$_Y4H`4;A9Yx\$uϠ>sK? :(6G.tTRyhA[ۮ)7Lɇi_R%hHO=J +gόb a0ax'm '.t&bvrXY "klRL ?7*tݽ`QN~yh}R}w,@Qsn{uXmpYq)1cY ?XB g} 7Ex2 ĚߏNjkjNuyx?r$'LwFn|BS,;~%.'S'|ЇZ*ɿJIR5\tUpϱ[Vv -XꏇjǿҨ85YFYyKyRvBod)2=m'm -i_ƒ٨nJn+mw ?S-bs2tn FSxv8_j}gNI%g'G&;6?NWu]> ! !໸54G+sؘ )1k>#G;m*fåAYIg'#[B^[Od|h|n_Ge ?CSOeP3Y 5tDU 7CAF۪M* }~p>_}2E7eH-a=,K mwbFq^4jBu-u?(mtSG 5>┟?{{6όEXlPQn%뎓By͋\iɮ}!',{Qg&a^ϵڈ|*G(}kbQuT=a7.kCKc`tHopŜ\`9Ygas48h魄_ֽB8G;fd `Iݢ#Л`~UlsNnlz\z^ی-쇝@ HWBq%1֛fFWg7 og9BomȄٷ"^ nr垌>ҽjye $ËG]Փ)\86{N~c_P>U疸Rҷ2@%^x;)ڦh/)+B8U[fshiD|May}oPҊ|K4M, y(LI* 6vE_a"B9*%dx`D p>jS<ڙaESL!_&i̶n'[OD4L0-^-G^_۟Kԇ/“>SsE\dQ8g`}<'zTO;{2'pPK?۟_CЧ!^KyC _`IrVy9Ş,`)@v(7Qђv+a^\zop>4\N/k O(&~,`-2Q7Ͷ*۪D-\Չ{cbtj&6~-r|+f7f똻!Y#3B =- ha^u)@g˶ܥ ?gTP9}y3jtd?2,fl ?LC>Ssɐa˺) )VT/GkᎽ В~ Lzv_~ !%]{۟Ka)DvŬ;ސo</$g ~F7%\)Mynn9-iF ҐԢ(M1Ύr ^l[blsT}l돟IK0goBX;N{zl]Tĭgٹ4#l`gw;; ѝۨe!y}D6QXkЛa똛M*׽!.d˵ޤ(gx_Rqư/HSg2kkxGTଘ=K;,+u1K ;*8zN40= nnvhY!\>VPY_\TKigoi_lbhG(:Zgh:R-ZZRлIj2Ʒ3ON$^HA.ab<BɯhS#ђ(%8z `ģa 3MmFt,nD<h`e=rTuݤrp?{|c !Mbiců4$7φ܃J1a!\94d8oxx\BI@צeKh. -r3ΰV pgD.Wˣ;"Bez07J9'hG9UR,lHne*){1wbk}#b["2Z<8;dZa2?*lf-+xY+,d>BxldOW+s_IUWYR*/{evTuuMBPښ5.YzG1Ƒ϶F\FǙWv [>C,gDgq#)|r5>GQ1; j~b7{EWA.K̚>y|J9rj8.cuG>͌gъY%B|,Fp77S6I:S(DyӉQb?CshJxtOƃdpGޱC[^\KW ,׋+2~R5ҏFf1\P&l27.L[xڶ X~4 RfxH[Fw x% ͇9n`ߥ, ByWtm Lc.J\#XSAޠ%[?Kcqe9E)1"BƤOg2§0j;f餸3b66<{Vѐ?!J'd/'ᭌJ(.;Sg@{q%r-N8&+xd"E [QZWGk,[[kTrEDԙ-E39kz/be?+O~ +lհdXr ĵ?s 42"Ԣ;O23~4)<Ʃ=B/K. sӵދBLyEQEW1P<7"P`050W5 "׹YH'fKƂ~=s\ΰS L.=s;*v8v#!ᱝPMAP'>s%4ua Z1u>MVџ*SM--Z\CE.b.< S;΢PUAn:ҋ!<Ӽ[+7s52W2mlg"NR+36ǚL{8*::nПj6{漿wlI}l6 ^}J 6<%xJo73iG=*S[Q#?/bópG̣>';E$}/Ac*ZcI tc,/>bJfø_n*G#Ieg؞2Y? VqG^*g9V*Q>\pE}RﱟpQ}T$<_μ1^Sy6 rNі{CaӘoXˇlc>ekZ§|f6bo0xpГN)uN.H49 %>ЁF;G޷ASD{q/KL ǐ yQ#Ԧ?Q^N~r;3}؞+qNӁ~9^e59ʩܞOv)0z҆\KY 183i]Ar[ jEy~nϤjHjkm:J6 ;W{?Sv,"8Q/Z8{,iFҝԠ){(5te:By/eng;s&ș@YxfIqW=AIZ3mA5gIYQ>#<頌 sk8׳Mm΍k1|j_f*ӈlSiB(Ӷk\ W7ڇyL vÙjTWwr%r"%F7b+x6\zF`v8sKa:݄;K+uJi G(!TNRt3,~ZD݄y %WCQЫ+OKAK'nrXi((֥;Ws B gp!Mkg,3y3$ќ2d[qpQvt̕> vU@M5Z]*m~%.5PH6O -J$~*(ԡ=b6KGVI#8:jY; .^ 7J[G3z6̠/ )z&P\JEQzJ+ѓC c$3L౴(xqa4# ~34f (ɹ@jʅTR>Zn. %.G`Occ'da`'[Y[c:LwZs (K!VQFd"5bW(8j 3ŧ![ 0(#_f̄]Sqn Y3됲Gƾ9Ԧ54O1f+ְ錢QKBSk!bл1WVq1|oZ˞MM. 9J _ ,+?<a{GLuZ.nq7xf7|\͹Ϣ*<> a\;#DVr+|~2#95Glm\oXFK0VOvXLrsR3%`T9E 8:j[m5BIwF 6/^'yYQ6avYctf.4ϧ}&w^EcQ!3ZصT1COea[FaV0i\K2J4y(<-jt 1?VI71WV~ͼJXີlxF#JPvf>'L\Q+9Y2d1ͳLc F1< j1ьQ&3\^ug5Ʒ޸9K2fin98 w#ZMV(r6|f?̔SgFAj&F,k`ypБVz*R䏙n p!q5)c&YV~)N7vRsq̕>\,}<ګ۞$e|f2 p+.ˢqI7cx.I7c|lzqTT,3o9dz}i5CK:ђi!=̹T]L竈 #A-se7Sv:~hk,lWY~iOla%xG@gZp05R(LӇ'x/"4 =S. Q.ǔn8s]*%Nˊm~ /v,`#ɝԡFI啉b@ = c[TRi+}N/߮Kl.צ!qnj|SseF@䓻Rp: q^vLei5b(lQpM&}( {LhQ~f#Kyat!9/:҄QbM1ǝYwMRb\CipMhGO2,f3X̓ =)g v Kq'N W\Yfj8Qf)=ih\U62x ~Kvٌ;M¹ǃ\ǃ,q,+}P7l4pa'SKkz2i,d{}a'0GpMn љ96+}B$уA?-A(ȥԠ]g%_'n(:RKKY,1WVSBe_[xΥ<7Ӛ>S~dY$zӄE27\YҶ!XJVz}.-]1x3wҘ)A8'\I]џvD,If 'W!-u5{/J`2 >ӂzԠe(JǞ3)M n7y|xl+mqCV!0C"!Mwc+yŖ=ĭkp&wZxX"}#}PrAŦ( `.b3=9T] ϗ>OXs?>yo1"Y}T+8b`'!ї.Cd-\A=:2G8+eO&>D_N#W6^qsͨC ǠdogC< !'CP4;:~v %'-g.I</2 =\DCd"jҎdߦ&I5XJjd燠J~Fx惀=DO:po&1wG.>t6-!*$z;!]-{3<dOFβEy_mqtU};?=0tzZV KVKֳwx,MVrSˈj/}Rm{eMxY퓙|g޳l.*siA{ #yyWyl[vGtQm|Y퓝x7a#Bo&PkAGz31L9+ȟ H֒dO\aSx>l(euԥwэbx5|?/D9woQWV$&2+,'\B. Q˨J-Њ` 3e)6$͠϶eOod Xj%4]!qB^Υ45]3Y[||slڧ+q 0woivŌ~+&Ꞩp U=Hc:/*ﳞ|ڧs_& B?YV{!RZO*r=uiF[ÙSfﰖO_Li)1y)GUjѐVt'da. |QfzB$YyթMЅ> e+vPZn`"N4VZ~iB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!vIIENDB`bidict-0.18.2/docs/_static/logo.png0000664000372000037200000004170613535200701017732 0ustar travistravis00000000000000PNG  IHDR75sRGB pHYs  $iTXtXML:com.adobe.xmp 2 5 72 1 72 507 1 247 2017-11-16T12:11:52 Pixelmator 3.7 ?;IDATxuEǿ^QCZ^RBiDRAJAIi)D@*}? g=u{<3<{@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!\AA! -SE\c/x$QâU'B zSxjG"b{AЀj'"~b&T B<_Zc0WSnDvT@F( 9^dVëhA+NwI@10kY0j̯BB9oBI f=- KF5 D|zsA OXK1+Tf([#-OCg^R{$a O#}Xcw1kPPR>7By9duDc6g%cɦ^B6I]ҟoy,C#bdg>"HӞܓG8((( ? #/.rD: 2J JAa;x=.1m"ڳW *M(fI,&%=$bJ\6u~Id. Q4X}G]BØ4KP= rՖSBqAkfƚ2BQx)(n >ǦLv!$P/WA %!* lK\ox\2}B L)~!H!8 Bad I»xIjTPBF>@Hn2ATqZe,:F(:r4|AEg>]#&B mO XtOgZj"(DsݢPhk\rYבNMliFČ2Aw(WW]isߡ)(x a4Ik` f!7`3)W"b&g"AL)=mCA)B+xxG迎`왒thTF߾GUpLAT;дj(#1saiɫkZ_u5 i-e!V{ԛ%TRdaa<2- .Qǣ+W.G!UmO$uhMOF0 vp_unpUw~g/Y"f1t1U(DZ)X+{$ R+޼=b͋(JvF'$8 tֲ߄ [8N34ҫeYeU"}]$HLT.ث3S#MĔ%XQn{IeC~c BsJVuc@t ̰PJ0?+5ţIt{ra)c$Vw̧/^;@uv $;o,N)G6# ДI'qtpyuz2 plb1(N/֚6| ZrB84{O<R'eof1n(EWATOcӑ_sÉqd WDм7[ϰcCA{P!?Nfғ$#)IC”UҜe3X|ǯܰՋKKQ"蟲Tak#C\5C?,"6I4I rbYTzш^!%K'F2ExnG'$ `0|Aߤ}yŎr!FEfa3c%)m.ڜS0V7\Pm0s1#>{x%`w̶aM 2F!%\z2:|: ՞Llp1?a`!DXD숐 8I[`c5]n dcA^cHE;zoY6Az!8os(J/h \> fp&--p:`Ubk? c6QKK^hQ&`P4 %AP#425>{h1hIz2^P_`o|Bsz*!v|J IoqR=pC& NJCW kKcxlDC=>\&=ՐPSnz8*1F#%/5r/i6Omeٻ~½vko#1akEj. ÄjCUo Ïd "j,#OQ*gbLr;vD\O9Av5X"0c@/ypLT7d}vQP䓱Exn?񙉾 _D>>S%5#,!m&W&gNҴY\]ΤU'3~c7I  O=$7F:u EOzJ=ʄW#i6[2=4n|l[1#^|$ACm|r1'Dpс s8oFr@XۄO}r+Ud'ܗuN`˷uɹ!'Du/1G+M>3|LJ~lI^ mq'mn?!l̒pN0}G(a Hv6L8%wW IZ1a3x;&ALsFص^I1xJ?ݘKfdGdiEes?^\}N:In9Aâ^F>6E[ߛ<2zP|(7x-[A=|vDl<ؐ}ͦnKD(- ff*S,7EZKS~7qU$>ɢn6T le7 ATpIYY&Aw(@ӒI" n龜4R|>24yj?9('eɮHHͿ4wrY7arE iQE:*oPb'Y|dK5W-?=NkoSgu|~B:f 01 vmYZ;]/,2]|ܧ/?/߻6!ૐXbw@3Boh.7u ?;>[alrԋ-lxy'.,M$CzcvΔ8,Y'Jo8Bu0t95ȣK5eۍr}esPJ=O ^JH"VJQPLOԨsSE٩:ipNAe35;Lk—>nw\a|·,; ģ"Z3 N:ew+ֲ,loA߿:%e$#8kL@!o>V9.YD22 aC>Q/`J)*?: !}79u3jfmu:M&ݾ>;WA}H *lPq ǘA}t5q BK<5 brPORU$Sހgm$ yKW L wCbW&1g:xY2$$v4B"(Jh0FcQR{k|>n 41}Vlg* oфOD_>@9c,nJv, l̓k1-!t0P.I:bÃĦ6 U1=5 ~6PR:\5{.&ϫvLJl > -H=zs?XbާX"1L$̆L~3o:% *.1^v|ĪS'd6yьM 9<|ıuz&n&9r6p z!0 ˏ`/fkػYPIHIOS*s ZxWm[>-X$^dҿg|5}W'`{_,esk?G"6=7ObTf0\Wn\CLbB1\Ղ>b(fH2.;w,Q_FBG[|'Z%8Oڦ* t*ʄHx,ț!~0&X ;>s,ȷ_H*0~_K\aInPz]A; Fm0Ov\Ӄ9ՙR׾UT˭šk7}ײ<)JeR4$RυRR#k% 7Rʠ׾Aa( >8Z IziHH%Rqc%#: Kj:൏Pɘz'c6P,a!UV7w|ZHj%n4RZ&o+M'o1nr8쇧K9¾BT9^u79o⒓iWBb2X-6%S#ilIHm feL]t 5[d kܱh)$j0$eoͣk1!nġ] InXM"refϼa<䑋_ޒ'CFk'^ix7rԾn*MCcegCp^fAe9tP?#ŘvKqtZ-#TpKとk`;|}y[eO+J\?#c->a) -;~ 0?$~ 2JK;bn 1SR/7LO+?u7V.grr_DC[A_H]qhuq}N6\L !}bk2#Π L$;ج䮛ud4 s]pǞ[~Ӂ,-rXkaGԃNڻ;X QmDrzcT#>CmO f'fDX{TH3e=w܄_ x%op#q%~YRkzР9qX'=21R1^R?NjkťjEp u \Sx3{| ~=PjO*s.KNz?:GJ>iF_HN*o ׆ko/ Jw{P -ݜrQIԷ[$a;w9? 4O#% ,Ҥne z{tG/8$s9ZKzhjV$IMqwepnP\t\٫# Y̓nJ}ctȼԐyFrw:]J]'n?Z`daHBAWh+9isY>63IG;m)>C^7VFW62H-u5{ ŤRe2I2 0&71]_ӬRF.›)%И]{R-wϚ%oAo^{3U>)U>@2 HV?],& }6D[)"EN$]8gH_tյ$u7m&h_Q¥/+tasy[CǁF\vb> xWjKA ,zRw8n07#E^~vXo޳M랛ޑHcNy9 z5Y|^ڋBKKQv/4C$LD1ҧt5QVsGW#瞅I ikBu5jk^MoYlzHKy*,L$fDya䖅㺩:7灮GI./ެ){,Ӑ>FM%9&knMIg4ZJLD;'=Qs3 )?ۛ`e0W KscL 3ng {wlAoҳ23Ŧ%ҋ46MI€fRDK'w7I0#Zo$JkQ?) ^Ao.od@ oamOMU±CY~) kg=CRє6xD4хm]>Bs<]`༪|gSSҝ+8lW *썹cAu 9/Ƞw@@zI!4,{U1M <Oa)F 8enAf"-%4}hB[XodЛK)7!^RLY8Uki33[MQaRȇX0$$%(N?A/˾fSi 734dxBFXpz86Flx/H\tV |z @oMTAJͻhhi@}T|hZ })&5{p=z*MQh+?-vE3\'3@=kmٟiäh5ZI,]&jVYM|p 6]>qʭ64n evTuFLzeBCf&L튶|Bއ+T҄D/C\Wc(0o-Z(tRَ1ID¥$ _o4 ztspRbm")l%#Yvɇ/% */tz 5OcP]YPRFehk`x I-ܤ!䲔KУBXF@D]>ݗT^nUZPҵ|B K2I4Ыb6Rx]~5c2V}^ MIN$%=9)Di*Qx49oЂ7hFRT,I^r ^HQɛ@ xX&~ЍǏN,,`y-al˩wߢW,\"h&GG3lf?d3{;L8|ӌ*4d٣ Z9WР7_707"MS& t,xSSqM/I(JC0iA8^V2Na^S]O٩3hРŠsPT7q2Xki!]UV@W}jh環s|XX~.Ro8*Ўr^ \u"4YM5 ^3<>APZێHZS񞅒_FQ^"HK-lZlѮ:j 4 PsC#B@p{B 49NJK|X]5|GzULzb`8qhG~*!Z#ٿ5v4Q% z" ! mRs]tK3"Fr ѪebBvWWe'9>v5_XjVc_ {8 P+XoMm<|*)WAn`nzPBk-knUo1H[@(ۈ509SߡkP~|i3}y<3!tR,=a$!(O=яq,sY|'K ɂZc]~s4~x-6A=*JflʚcԎRSڋWkvU bߏl_9KtKʷ |F&CRPtb K6uHc<0u5 5!j"hJV44=vko \nfXoxEAN[YKΠl8KLC )9Lg g=b?$rA|dbU 4jNA/nb]~.y6I; Vr]O8>̼JXgq5̙2d x9XG%.馡ax:U5If"7r{6r8ɏ`'[Xbf3!C[^2d<>\ri1O꫈F(kI^lh u6ep-N8j }gfZg3SQXd,h汑buq"GLgERJ-!-jpdڧWh. %Рw*W@4C}a.*0j`,Dz:LSTAқq۬-gC5l^ β匧+DNGVX007<7jQAoA`nڛ:"R2NzB#<}LVKDU4X0^g^`65,՗IJiZ32И]a?KAkʒ`/@vy?Q8떏7>Qko~"Q^:__'}+?w '|.H@)Kom"U·8z2:%ӐPuϳmW 07J{͐6=0Ħb'CKwyH9u6 ц)lQ):?t2B)8|]7eՇjld /oz:l'IsX8`50]טCyt#  KmLybq:ka@Рn\A BD(.i֡"bgm H44C6P,4gm&D8n6Ye oӖ&FP|d'#iII2y{&MaJQN :ҋaL#V%8UM{NKra2'84vXb>b& z҉V4(LvRy4f(rԡ@Mtܖh7CF\eh2Ay[TK\<:5XYc:_iRl ciI}:0 |p ^=uqobf02 c glkw1VFk 'o I)Kj{U~1]zП/`RЎu)785F=o'\4{XG;MHw+H@2cF`& ؠ7007{–UێozWtb vs ;}EwV0ek@Z%9&5/#0U嵷omnb2n)mxycҐ^~aѯq0!2Y%P 51 䆁k/X76|d{]Nz?r &6*z=,eLf  7k/|6 P:!Qy16|h`gEҘιqtMF ]]P5+fӇzӥ҄dg G"|'A3C_y-"-l48acBuR;4Nid;~˜0;|L3miNCPTe)E S,$)K9*QԡMi[M1|"V8)_?Z,pm|@jŭJCR^!f@6* 0[ x[W\P zQG`~r:A7Vl?Uu[PR$C9Vm8 IKJQtb35lGZFނwU)!滩kogT'4ۍ=u3+I96{.=ΰOMR > u D1ӊ>g!9E|$)0" h A`KiPTݣD\:WO+a|Ⱊl#ޥ)H$VJJ R a69%/r: Z "G0 U^{ζ36SzEx ㏹EǤ퀴&.VCIHJ2 x-ѓ =F0D&35Ma282 ]iOKSjTF8Pbr4gQ}v6 s=fYD7͋;8Hx6#IB۵egc>=x qHMRftbcBֱ9drKV1 ;x&qI(D=z2 w,7L %lc rC"'HM#OvwC=8b2{IAnXؤ(iE/05(|:gz142y,VIIZ2%y0A5A`;쬲˾Le|*p׸sa,ѹ{Gg"`DM0+߲I1I']0%JъQ⨅EpРV$;mN󴕜$0 tk:@*4/X~~w2|e' N*^ʨJjч3Y* z00Wyk|;&M-vҽvz4kAȰY w= ^LY3sdXuY>)YgS3t9@Qr> ׍C22'ØBֳ\+G7J62e*ב%6⛼'|tw^>#ng9b3Y,3^E3jS"d'̻ςt{3O"t'<$KEyy`oV^{b|DgApp -l8QeKM㻨0P:ta4 38|ޢQ` Uq;ECÉWVRmX&14*E!lCM1$sާ ę]vVh/bfckhzҒ#L^dg"tC" 0Wy}QJd f*iV;lfG[jQXJOԢ7AY~Abڤz|ϴdmb Zf3ԧ Y1,:}XWAHզ~B:۴}[45coyv9aMf)!әĸtց }џ a#8&1c0?ǧvεa7 Q¤"yy ln%Iylwq&YeW87`yVԡB2\ION Sԥ9oыg Y's= !6#D]r]L4` _[8N~G؜TC-+"{YXP⤳CGjrR4=4ȹ{Eg=2T'&x)AKfrPNa` cD!dd$iFW2Elb/' Rӝ xFae6a`bUX E_a˯DRQ'cZv3C-˙;4uvCGg^C 0Wy nXJ1=i!5h^C(KEѕa|jvqk~=|od1cHumlGT6H] xwC/KC!ъLd1_s~Y No/*}@"nJVMJsHpleK$ӗδ>U)MO -Q~"Ԥ*%1L9 k(n͋[`C4u\4fVeО&Ԣ"E:HDN*ҌLd;8mxs^U^+C:k" F 7g9^C(t''iA}wu!H*}$܊M-AR"g8noҔJBIM1ѕ,N ~v AyI5N[.y:yY.U1~tTԗ)H-:2F>&k.l`&yFԠaRf3y"=IB RL``;Kv܍kLhyd;x˘dQ :"YL;oxhI5hJ)}#6QL6bM/HsG|!*QC 9"zk>XW|-2mb[5: 6i@5>!Q50w>W>ذTq~@tKߺ=@3^{A؜q x|g0pcDYU k#OWDp 4g3WQ48PP|ߞpKCbCI>8@jJlb[1͙N~kT~ni{~h3QyYm3i2Cq*Q&;2|ħl`8o\qtQͷm,>QOC$|P UO :қc'*6 ZSW^|A1E>p")EQSFd氄u|^ ^Mq*}#2ևd&BӁ f,lb9y)?)}TC(%& }6RvA ӀVt/Øl/8n30G)d53r+c=ʮ%##y(A%jӔtg <>ep㜍FFK嵏P5^0Zq+(xdLO.R4-H&3kq_+k#+>)L~JQ4=Xf1+gs^Fu((b0NZӅ g"YZd?p6SPPJ-3$jнMIENDB`bidict-0.18.2/docs/_static/support-on-gumroad.png0000664000372000037200000002212113535200701022542 0ustar travistravis00000000000000PNG  IHDR7.-viCCPICC ProfileXyXUͷOqVnKnED QI6 ADEDEVnB̜YkwfMul@6%@-`D @ղ4cY# _{z{Y3#ō`8O>I$xk,H?N^# 2^@r[~'mA"/N{ D_[$ڴoQcvcLVr;>?Otq8}_(@c}}}Na #o6lwK!90SQ?:a"FGcX0@D M'ȿ,?oq[N#N/Zs~[9\Cn҆4>iA w%\ f-GG̬{:iy3 +&bcC脄ƒ||#ً(Cj'"hynC,u qYH v3X8Iڒa6,zgТ; I(@c`l#؏κ/BYGpL NbP *p\͠ t.`]3#+'Axb!^H H҃L!+r|`(JAPT C+P+ ݁BOW,L3ܰ0, Z l}08NBn.< Oe  H"*b8!IB2|Cn~L!ÇDק! $a0Ř &-#+7˅a>hl6{{ۇ cѽpgp.C4ndz%jx < Ok ;K#B>A!#EaAIKCQEq O"=QF! u>s"%%JUʽ~( )((_Qbҡrʦ:OEjZZډ::"u/ 44R4F444%4M4#4_h)hhh^}@NNDDWBJn^ނ>>{<0'C*C%C/4#(xq $dϔt>3s s s; "bȒreeUՋ5u'&[[=(*;{qfI 8^h}88wszpfp^|ssYqsUr q-spprqra93ȫ{3_ _!-9~.~CHr?wݑ~ǤQ@E[@ `%gBB*BBBB߄E텏7 a1$\ZTC4LBNLE,@ذ8,(+^"@P8#p'v;HRIjIFI^|%"e*",EZPItoE@* YYc rrr%r[$*+2*)QQDVSUTvS>DIR%Ke@ڦcҮ]Ww}-;`w{Dx3CV6Χ^>AҨx)yN󝖘Vmmuo:tut] z zzz/w_ҟ3P4727|bmathX8 IkSqS 3ss!`f `adqbR2^^˽%{ZZ%X[3ZZXhL؊Fڹ]fkg? pבϱ dtiY󌋢K>}1ݕ֕z fVF UݍOyxx|<9[; Y_ |O~:~~,܂ZoĄ< M v*llB> o`B_u"E#GR*m}->&8f(V<6=]~\u<&#'?`«D$(='Y 95y KIKY:dF*w/ѤӞ}(E3<33e23ײ<+<}?G)l..78w yyqy'N4;qr; ĂȂB–"ܢb\O;yfٺR2r J\eT*j8eu> .*_XUs yi֥v:ɺzە&W{\kj<}zF4<ոoJdjsϢ8~)3_D4~:4073O__Zd_<Գlb%h緌/Pѿjg~دM~?_Z_%IZaoo@#i@ivP:at8A<-GNeCESD^!qY%)u.N^ɿ ($,J'V"!YJ[zD[nQ!UCFUu{) o͏A:szAo ]6[d[.XNin/X4Bا5ϭ4)esȷ[`xЛ0<1+3)!qlK\Q|TEpϤUb:ڑOrx,H􌌤Lr1l]?O䵟(=y_Er!_he37^.--*pԬQ W>uBEKFUd]ڧ';ZZ-o(kh[j1}l[&`Xx݂{n s>=\yqh˜qd|i3 扻c&&_D}fվלǧX{NYC?65|o{r~lxeq%eWJpYMWf`Ybpx75јҘj/Mm7wF_Jwlq콜\ܝ., #* \TUFRXF!YqNU==5t ƍčcLL')-T,[Y?jGm/RimQiW MCKDL C~ _(rVaYkMIHMfL^90q;ԘiGгUzg,c?s&s;W>pab!pht:eز򱊁UUpb|M%Zjub k o<ځWr3[2[ȻYV^Qy+{_Y->bbwY߳`ϰCG4NjoF_ZDsI/_>*uشڙ/o=ߟ}B6O_0\-v.[[ZrܷgWگݹvD葫g,ۊ# E.ѓRJZQɌruP#@ OEw <$yJt̠g_Jʢ*ʪz,vcfn)ůMT^~hҸ$Lgڢ$+7km[^RG'ygjw.] q͑܋<:~~iAbAk!a.rBR|DMGgHtFfJlm)5AD_I7cX=ؖtH+I=| M5m壾BYbYsZX~>~]C'YO8US V𡰦ȯX]әgBZ*1-WT^9w|v5{/_֨SoBrŵ뇛BcZ[n|)Х{VCwlGA?_y5i2ԗo ߞ|9nvd@d 3XR` W>r84h6,\8f 8 y $h(.P8UA8 Kv9p#r9E0̘=hyae& & x| N"T(x)(*(fb`b %҉ rjK&f֙4] =}<Fwi&hƒ*f6͞5ʝcϻ7_#[ RMH]Gk/H酞 \2X9 O([\=j?4vh/Ewҙ̯["{5oڬ?0r{k>'7o1 ,s_L<$3+n4!'rPaGde);ptjoE[I֙2 5qomnںfSrj̠܃ #F^qv|gX=u_%Y6}*0j?Y =` | AhF>o^A24ahc0>kM6`_ 7{K gK A ?Db6qR2=SC440Wttj WԘY"Yljlc9xpqNQCFJ5" 1'q# ՝w|Ro5?8~tY&VKWolYۼ> *m/ϊ_hv6:N/lAUpٴ8XiTXtXML:com.adobe.xmp 232 729 1 &L, IDATxS[Kn~LftNIϤLt6i6ۀxƲyـ!< x@+!Aȋ,Hc {掳w޽|Wr%j-Xs{愯?SЏo/|WG>C<>Lg <>xzƿ22~b!]E)X|-ބ9ǐ:4S`AO9<(v8~Z<6a0ӹ5r h4az`vN8[puB9N' p8NNNN@bwǂ]_`b1mZ͖NX3Z>iLR?sI׹jSEˤ(XۂO\Wl|nh4jZ¾XJ8kx:k?kՓ bL_>/P8_&ۭ=z%J}###1f5""={rcc#{O]GJ@B)R{ي>k PG666I$BhŋSlp7CMZ=z/XR= \[ccc?~ѪjveYY&ueSNq ʹ#" ih\AulqO߅\8;/5\ͅ.>*pUTT,=_gJNV+N ؂r t }ݾ}`eeEV^v+=* 8CQ ݻwhvj"F-pNt<- _`T<` lS<ÇXdd$@DG+o믦n5O$PWX08 9a0XuZz`]b, I$¾XWWzS,}ӉSEKz@Y=::ʺ% ]]]Gb:50-p:%@.X N1ԀВ1H½(ח&j֦>x˧Ѥ$,§a`*#Pؗ8Fj233NWX+`U+J )Y 2Ԡ_e[@hR3 oAos[M ޠfvݦgݜNI?s.pLJJ JN}LM,--U~6L j/HGPw "#L0[<+ߘ"lc+MX Is$nؗkލ:GP:rz?k5N'n(5_{ D@!ͨ%Ff$ pN CrJ9! B~{<5?ڜ5;蜽U$H.m[Y񡎌"!˨INNfdǗ,z#ƳM:EϺ%?L:(G̦&łSfE ?XMvv6jo3)(IyIIu8?vJ_Nˠ ]ӭfBV\#LjB6@b 3ؙ p\3ݑNI_P"1M-kGh@;--a;S=Vz9FR?S LRaT$@v1&EShB5-Q渞`\΋;X~l;CLRQQ p~@ؓXO:mhh Rbwʺ] fhjj;0F )uSot50Ӟ҅oA`f#P,߷4<<{=wuNh( ! Qv< ;+8UWAnSh }ƀ]H0Eho+t}_bb[j]+ߋhNhkLoϑTח>yV߁|Uy즩8}?5MiQugz<#>yͧwJJ~Tm*)Tgh+DB[6 F|LUD;)8\8\8\8\8\8\8\8\8\8\8\8\iq\tP^]X~˻.JrlllyyyV J4`. Bidict Avoids Reference Cycles ------------------------------ A careful reader might notice the following... .. testsetup:: from bidict import bidict .. doctest:: >>> fwd = bidict(one=1) >>> inv = fwd.inverse >>> inv.inverse is fwd True ...and become concerned that a bidict and its inverse create a reference cycle. If this were true, in CPython this would mean that the memory for a bidict could not be immediately reclaimed when you retained no more references to it, but rather would have to wait for the next gargage collection to kick in before it could be reclaimed. However, under the hood bidict uses a :class:`weakref.ref` to store the inverse reference in one direction, avoiding the strong reference cycle. As a result, when you no longer retain any references to a bidict you create, you can be sure that its refcount in CPython drops to zero, and that its memory will therefore be reclaimed immediately. .. note:: In PyPy this is not an issue, as PyPy doesn't use reference counts. The memory for unreferenced objects in PyPy is only reclaimed when GC kicks in, which is unpredictable. Terminology ----------- - It's intentional that the term "inverse" is used rather than "reverse". Consider a collection of *(k, v)* pairs. Taking the reverse of the collection can only be done if it is ordered, and (as you'd expect) reverses the order of the pairs in the collection. But each original *(k, v)* pair remains in the resulting collection. By contrast, taking the inverse of such a collection neither requires the collection to be ordered nor guarantees any ordering in the result, but rather just replaces every *(k, v)* pair with the inverse pair *(v, k)*. - "keys" and "values" could perhaps more properly be called "primary keys" and "secondary keys" (as in a database), or even "forward keys" and "inverse keys", respectively. bidict sticks with the terms "keys" and "values" for the sake of familiarity and to avoid potential confusion, but technically values are also keys themselves. Concretely, this allows bidict to return a set-like (*dict_keys*) object for :meth:`~bidict.BidictBase.values` (Python 3) / ``viewvalues()`` (Python 2.7), rather than a non-set-like *dict_values* object. Missing bidicts in Stdlib! -------------------------- The Python standard library actually contains some examples where bidicts could be used for fun and profit (depending on your ideas of fun and profit): - The :mod:`logging` module contains a private ``_levelToName`` dict which maps integer levels like *10* to their string names like *DEBUG*. If I had a nickel for every time I wanted that exposed in a bidirectional map (and as a public attribute, no less), I bet I could afford some better turns of phrase. - The :mod:`dis` module maintains a mapping from opnames to opcodes ``dis.opmap`` and a separate list of opnames indexed by opcode ``dis.opnames``. These could be combined into a single bidict. - Python 3's :mod:`html.entities` module / Python 2's ``htmlentitydefs`` module maintains separate ``html.entities.name2codepoint`` and ``html.entities.codepoint2name`` dicts. These could be combined into a single bidict. Caveats ------- Non-atomic Mutation ^^^^^^^^^^^^^^^^^^^ As with built-in dicts, mutating operations on a bidict are not atomic. If you need to mutate the same bidict from different threads, use a `synchronization primitive `__ to coordinate access. [#]_ .. [#] *See also:* [`2 `__], [`3 `__] Equivalent but distinct :class:`~collections.abc.Hashable`\s ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Consider the following: .. doctest:: >>> d = {1: int, 1.0: float} How many items do you expect *d* to contain? The actual result might surprise you: .. doctest:: >>> len(d) 1 And similarly, .. doctest:: >>> dict([(1, int), (1.0, float), (1+0j, complex), (True, bool)]) {1: <... 'bool'>} >>> 1.0 in {True} True (Note that ``1 == 1.0 == 1+0j == True``.) This illustrates that a mapping cannot contain two items with equivalent but distinct keys (and likewise a set cannot contain two equivalent but distinct elements). If an object that is being looked up in a set or mapping is equal to a contained object, the contained object will be found, even if it is distinct. With bidict, since values function as keys in the inverse mapping, this behavior occurs in the inverse direction too, and means that a bidict can end up with a different but equivalent key from the corresponding value in its own inverse: .. doctest:: >>> b = bidict({'false': 0}) >>> b.forceput('FALSE', False) >>> b bidict({'FALSE': False}) >>> b.inverse bidict({0: 'FALSE'}) nan as key ^^^^^^^^^^ In CPython, nan is especially tricky when used as a dictionary key: .. doctest:: >>> d = {float('nan'): 'nan'} >>> d {nan: 'nan'} >>> d[float('nan')] # doctest: +SKIP Traceback (most recent call last): ... KeyError: nan >>> d[float('nan')] = 'not overwritten' >>> d # doctest: +SKIP {nan: 'nan', nan: 'not overwritten'} In other Python implementations such as PyPy, nan behaves just like any other dictionary key. But in CPython, beware of this unexpected behavior, which applies to bidicts too. bidict contains no special-case logic for dealing with nan as a key, so the behavior will match dict's in the host environment. See e.g. `these docs `__ for more info (search the page for "nan"). ---- For more info in this vein, check out :doc:`learning-from-bidict`. bidict-0.18.2/docs/api.rst0000664000372000037200000000144713535200701016137 0ustar travistravis00000000000000API === This page contains auto-generated documentation from the bidict source code. bidict ------ .. automodule:: bidict :members: :member-order: bysource :special-members: :show-inheritance: :undoc-members: :exclude-members: __abstractmethods__,__dict__,__module__,__weakref__ :inherited-members: .. autodata:: bidict.RAISE .. autodata:: bidict.OVERWRITE .. autodata:: bidict.IGNORE .. autofunction:: bidict._util._iteritems_mapping_or_iterable .. autofunction:: bidict._util._iteritems_args_kw .. attribute:: __version__ The version of bidict represented as a string. .. attribute:: __version_info__ The version of bidict represented as a tuple. bidict.compat ------------- .. automodule:: bidict.compat :members: :member-order: bysource :undoc-members: bidict-0.18.2/docs/basic-usage.rst0000664000372000037200000002323113535200701017544 0ustar travistravis00000000000000Basic Usage ----------- Let's return to the example from the :doc:`intro`: .. testsetup:: from bidict import bidict .. doctest:: >>> element_by_symbol = bidict(H='hydrogen') As we saw, this behaves just like a dict, but maintains a special :attr:`~bidict.BidictBase.inverse` attribute giving access to inverse items: .. doctest:: >>> element_by_symbol.inverse['helium'] = 'He' >>> del element_by_symbol.inverse['hydrogen'] >>> element_by_symbol bidict({'He': 'helium'}) :class:`bidict.bidict` supports the rest of the :class:`collections.abc.MutableMapping` interface as well: .. doctest:: >>> 'C' in element_by_symbol False >>> element_by_symbol.get('C', 'carbon') 'carbon' >>> element_by_symbol.pop('He') 'helium' >>> element_by_symbol bidict() >>> element_by_symbol.update(Hg='mercury') >>> element_by_symbol bidict({'Hg': 'mercury'}) >>> 'mercury' in element_by_symbol.inverse True >>> element_by_symbol.inverse.pop('mercury') 'Hg' Because inverse items are maintained alongside forward items, referencing a bidict's inverse is always a constant-time operation. Values Must Be Hashable +++++++++++++++++++++++ Because you must be able to look up keys by value as well as values by key, values must also be hashable. Attempting to insert an unhashable value will result in an error: .. doctest:: >>> anagrams_by_alphagram = dict(opt=['opt', 'pot', 'top']) >>> bidict(anagrams_by_alphagram) Traceback (most recent call last): ... TypeError: ... So in this example, using a tuple or a frozenset instead of a list would do the trick: .. doctest:: >>> bidict(opt=('opt', 'pot', 'top')) bidict({'opt': ('opt', 'pot', 'top')}) Values Must Be Unique +++++++++++++++++++++ As we know, in a bidirectional map, not only must keys be unique, but values must be unique as well. This has immediate implications for bidict's API. Consider the following: .. doctest:: >>> b = bidict({'one': 1}) >>> b['two'] = 1 # doctest: +SKIP What should happen next? If the bidict allowed this to succeed, because of the uniqueness-of-values constraint, it would silently clobber the existing item, resulting in: .. doctest:: >>> b # doctest: +SKIP bidict({'two': 1}) This could result in surprises or problems down the line. Instead, bidict raises a :class:`~bidict.ValueDuplicationError` so you have an opportunity to catch this early and resolve the conflict before it causes problems later on: .. doctest:: >>> b['two'] = 1 Traceback (most recent call last): ... ValueDuplicationError: 1 The purpose of this is to be more in line with the `Zen of Python `__, which advises, | *Errors should never pass silently.* | *Unless explicitly silenced.* So if you really just want to clobber any existing items, all you have to do is say so: .. doctest:: >>> b.forceput('two', 1) >>> b bidict({'two': 1}) Similarly, initializations and :func:`~bidict.bidict.update` calls that would overwrite the key of an existing value raise an exception too: .. doctest:: >>> bidict({'one': 1, 'uno': 1}) Traceback (most recent call last): ... ValueDuplicationError: 1 >>> b = bidict({'one': 1}) >>> b.update([('two', 2), ('uno', 1)]) Traceback (most recent call last): ... ValueDuplicationError: 1 If an :func:`~bidict.bidict.update` call raises, you can be sure that none of the supplied items were inserted: .. doctest:: >>> b bidict({'one': 1}) Setting an existing key to a new value does *not* cause an error, and is considered an intentional overwrite of the value associated with the existing key, in keeping with dict's behavior: .. doctest:: >>> b = bidict({'one': 1}) >>> b['one'] = 2 # succeeds >>> b bidict({'one': 2}) >>> b.update([('one', 3), ('one', 4), ('one', 5)]) >>> b bidict({'one': 5}) >>> bidict([('one', 1), ('one', 2)]) bidict({'one': 2}) In summary, when attempting to insert an item whose key duplicates an existing item's, bidict's default behavior is to allow the insertion, overwriting the existing item with the new one. When attempting to insert an item whose value duplicates an existing item's, bidict's default behavior is to raise. This design naturally falls out of the behavior of Python's built-in dict, and protects against unexpected data loss. One set of alternatives to this behavior is provided by :func:`~bidict.bidict.forceput` (mentioned above) and :func:`~bidict.bidict.forceupdate`, which allow you to explicitly overwrite existing keys and values: .. doctest:: >>> b = bidict({'one': 1}) >>> b.forceput('two', 1) >>> b bidict({'two': 1}) >>> b.forceupdate([('three', 1), ('four', 1)]) >>> b bidict({'four': 1}) For even more control, you can use :func:`~bidict.bidict.put` instead of :func:`~bidict.bidict.forceput` or :func:`~bidict.bidict.__setitem__`, and :func:`~bidict.bidict.putall` instead of :func:`~bidict.bidict.update` or :func:`~bidict.bidict.forceupdate`. These methods allow you to specify different strategies for handling key and value duplication via the *on_dup_key*, *on_dup_val*, and *on_dup_kv* arguments. Three possible options are :attr:`~bidict.RAISE`, :attr:`~bidict.OVERWRITE`, and :attr:`~bidict.IGNORE`: .. doctest:: >>> from bidict import RAISE, OVERWRITE, IGNORE >>> b = bidict({2: 4}) >>> b.put(2, 8, on_dup_key=RAISE) Traceback (most recent call last): ... KeyDuplicationError: 2 >>> b bidict({2: 4}) >>> b.putall([(3, 9), (2, 8)], on_dup_key=RAISE) Traceback (most recent call last): ... KeyDuplicationError: 2 >>> # (2, 8) was the duplicative item, but note that >>> # (3, 9) was not added either because the whole call failed: >>> b bidict({2: 4}) >>> b.putall([(3, 9), (1, 4)], on_dup_val=IGNORE) >>> sorted(b.items()) # Note (1, 4) was ignored as requested: [(2, 4), (3, 9)] If not specified, the *on_dup_key* and *on_dup_val* keyword arguments of :func:`~bidict.bidict.put` and :func:`~bidict.bidict.putall` default to :attr:`~bidict.RAISE`, providing stricter-by-default alternatives to :func:`~bidict.bidict.__setitem__` and :func:`~bidict.bidict.update`. (These defaults complement the looser alternatives provided by :func:`~bidict.bidict.forceput` and :func:`~bidict.bidict.forceupdate`.) Key and Value Duplication ~~~~~~~~~~~~~~~~~~~~~~~~~ Note that it's possible for a given item to duplicate the key of one existing item, and the value of another existing item, as in: .. doctest:: :skipif: True >>> b.putall([(4, 16), (5, 25), (4, 25)]) Because the *on_dup_key* and *on_dup_val* policies that are in effect may differ, *on_dup_kv* allows you to indicate how you want to handle this case without ambiguity: .. doctest:: >>> b.putall([(4, 16), (5, 25), (4, 25)], ... on_dup_key=IGNORE, on_dup_val=IGNORE, on_dup_kv=RAISE) Traceback (most recent call last): ... KeyAndValueDuplicationError: (4, 25) If not specified, *on_dup_kv* defaults to ``None``, which causes *on_dup_kv* to match whatever *on_dup_val* policy is in effect. Note that if an entire *(k, v)* item is duplicated exactly, the duplicate item will just be ignored, no matter what the duplication policies are set to. The insertion of an entire duplicate item is construed as a no-op: .. doctest:: >>> sorted(b.items()) [(2, 4), (3, 9)] >>> b.put(2, 4) # no-op, not a DuplicationError >>> b.putall([(4, 16), (4, 16)]) # ditto >>> sorted(b.items()) [(2, 4), (3, 9), (4, 16)] See the :ref:`extending:OverwritingBidict Recipe` for another way to customize this behavior. Order Matters +++++++++++++ Performing a bulk insert operation – i.e. passing multiple items to :meth:`~bidict.BidictBase.__init__`, :func:`~bidict.bidict.update`, :func:`~bidict.bidict.forceupdate`, or :func:`~bidict.bidict.putall` – is like inserting each of those items individually in sequence. [#fn-fail-clean]_ Therefore, the order of the items provided to the bulk insert operation may affect the result: .. doctest:: >>> b = bidict({0: 0, 1: 2}) >>> b.forceupdate([(2, 0), (0, 1), (0, 0)]) >>> # 1. (2, 0) overwrites (0, 0) -> bidict({2: 0, 1: 2}) >>> # 2. (0, 1) is added -> bidict({2: 0, 1: 2, 0: 1}) >>> # 3. (0, 0) overwrites (0, 1) and (2, 0) -> bidict({0: 0, 1: 2}) >>> sorted(b.items()) [(0, 0), (1, 2)] >>> b = bidict({0: 0, 1: 2}) # as before >>> # Give the same items to forceupdate() but in a different order: >>> b.forceupdate([(0, 1), (0, 0), (2, 0)]) >>> # 1. (0, 1) overwrites (0, 0) -> bidict({0: 1, 1: 2}) >>> # 2. (0, 0) overwrites (0, 1) -> bidict({0: 0, 1: 2}) >>> # 3. (2, 0) overwrites (0, 0) -> bidict({1: 2, 2: 0}) >>> sorted(b.items()) # different items! [(1, 2), (2, 0)] .. [#fn-fail-clean] Albeit with an extremely important advantage: bulk insertion *fails clean*. i.e. If a bulk insertion fails, it will leave the bidict in the same state it was before, with none of the provided items inserted. Interop +++++++ bidicts interoperate well with other types of mappings. For example, they support (efficient) polymorphic equality testing: .. doctest:: >>> bidict(a=1) == dict(a=1) True And converting back and forth works as expected (modulo any value duplication, as discussed above): .. doctest:: >>> dict(bidict(a=1)) {'a': 1} >>> bidict(dict(a=1)) bidict({'a': 1}) See the :ref:`other-bidict-types:Polymorphism` section for more interoperability documentation. Hopefully bidict feels right at home among the Python built-ins you already know. Proceed to :doc:`other-bidict-types` for documentation on the remaining bidict variants. bidict-0.18.2/docs/changelog.rst0000664000372000037200000006725513535200701017326 0ustar travistravis00000000000000.. Forward declarations for all the custom interpreted text roles that Sphinx defines and that are used below. This helps Sphinx-unaware tools (e.g. rst2html, PyPI's and GitHub's renderers, etc.). .. role:: doc .. role:: ref Changelog ========= Release Notifications --------------------- .. duplicated in README.rst (would use `.. include::` but GitHub doesn't understand it) .. image:: https://img.shields.io/badge/libraries.io-subscribe-5BC0DF.svg :target: https://libraries.io/pypi/bidict :alt: Follow on libraries.io Tip: `Subscribe to bidict releases `__ on libraries.io to be notified when new versions of bidict are released. Alternatively, `on GitHub `__, click "`Watch `__" and choose "Releases". 0.18.2 (2019-09-08) ------------------- - Warn that Python 2 support will be dropped in a future release when Python 2 is detected. 0.18.1 (2019-09-03) ------------------- - Fix a regression introduced by the memory optimizations added in 0.15.0 which caused :func:`deepcopied ` and :func:`unpickled ` bidicts to have their inverses set incorrectly. `#94 `__ 0.18.0 (2019-02-14) ------------------- - Rename ``bidict.BidirectionalMapping.inv`` to :attr:`~bidict.BidirectionalMapping.inverse` and make :attr:`bidict.BidictBase.inv` an alias for :attr:`~bidict.BidictBase.inverse`. `#86 `__ - :meth:`bidict.BidirectionalMapping.__subclasshook__` now requires an ``inverse`` attribute rather than an ``inv`` attribute for a class to qualify as a virtual subclass. This breaking change is expected to affect few if any users. - Add Python 2/3-compatible :attr:`bidict.compat.collections_abc` alias. - Stop testing Python 3.4 on CI, and warn when Python 3 < 3.5 is detected rather than Python 3 < 3.3. Python 3.4 reaches `end of life `__ on 2019-03-18. As of January 2019, 3.4 represents only about 3% of bidict downloads on `PyPI Stats `__. 0.17.5 (2018-11-19) ------------------- Improvements to performance and delegation logic, with minor breaking changes to semi-private APIs. - Remove the ``__delegate__`` instance attribute added in the previous release. It was overly general and not worth the cost. Instead of checking ``self.__delegate__`` and delegating accordingly each time a possibly-delegating method is called, revert back to using "delegated-to-fwdm" mixin classes (now found in ``bidict._delegating_mixins``), and resurrect a mutable bidict parent class that omits the mixins as :class:`bidict.MutableBidict`. - Rename ``__repr_delegate__`` to :class:`~bidict.BidictBase._repr_delegate`. 0.17.4 (2018-11-14) ------------------- Minor code, interop, and (semi-)private API improvements. - :class:`~bidict.OrderedBidict` optimizations and code improvements. Use ``bidict``\s for the backing ``_fwdm`` and ``_invm`` mappings, obviating the need to store key and value data in linked list nodes. - Refactor proxied- (i.e. delegated-) to-``_fwdm`` logic for better composability and interoperability. Drop the ``_Proxied*`` mixin classes and instead move their methods into :class:`~bidict.BidictBase`, which now checks for an object defined by the ``BidictBase.__delegate__`` attribute. The ``BidictBase.__delegate__`` object will be delegated to if the method is available on it, otherwise a default implementation (e.g. inherited from :class:`~collections.abc.Mapping`) will be used otherwise. Subclasses may set ``__delegate__ = None`` to opt out. Consolidate ``_MutableBidict`` into :class:`bidict.bidict` now that the dropped mixin classes make it unnecessary. - Change ``__repr_delegate__`` to simply take a type like :class:`dict` or :class:`list`. - Upgrade to latest major `sortedcontainers `__ version (from v1 to v2) for the :ref:`extending:Sorted Bidict Recipes`. - ``bidict.compat.{view,iter}{keys,values,items}`` on Python 2 no longer assumes the target object implements these methods, as they're not actually part of the :class:`~collections.abc.Mapping` interface, and provides fallback implementations when the methods are unavailable. This allows the :ref:`extending:Sorted Bidict Recipes` to continue to work with sortedcontainers v2 on Python 2. 0.17.3 (2018-09-18) ------------------- - Improve packaging by adding a pyproject.toml and by including more supporting files in the distribution. `#81 `__ - Drop pytest-runner and support for running tests via ``python setup.py test`` in preference to ``pytest`` or ``python -m pytest``. 0.17.2 (2018-04-30) ------------------- Memory usage improvements +++++++++++++++++++++++++ - Use less memory in the linked lists that back :class:`~bidict.OrderedBidict`\s by storing node data unpacked rather than in (key, value) tuple objects. 0.17.1 (2018-04-28) ------------------- Bugfix Release ++++++++++++++ Fix a regression in 0.17.0 that could cause erroneous behavior when updating items of an :class:`~bidict.Orderedbidict`'s inverse, e.g. ``some_ordered_bidict.inv[foo] = bar``. 0.17.0 (2018-04-25) ------------------- Speedups and memory usage improvements ++++++++++++++++++++++++++++++++++++++ - Pass :meth:`~bidict.bidict.keys`, :meth:`~bidict.bidict.values`, and :meth:`~bidict.bidict.items` calls (as well as their ``iter*`` and ``view*`` counterparts on Python 2) through to the backing ``_fwdm`` and ``_invm`` dicts so that they run as fast as possible (i.e. at C speed on CPython), rather than using the slower implementations inherited from :class:`collections.abc.Mapping`. - Use weakrefs in the linked lists that back :class:`~bidict.OrderedBidict`\s to avoid creating strong reference cycles. Memory for an ordered bidict that you create can now be reclaimed in CPython as soon as you no longer hold any references to it, rather than having to wait until the next garbage collection. `#71 `__ Misc ++++ - Add :attr:`bidict.__version_info__` attribute to complement :attr:`bidict.__version__`. 0.16.0 (2018-04-06) ------------------- Minor code and efficiency improvements to :func:`~bidict.inverted` and :func:`~bidict._util._iteritems_args_kw` (formerly ``bidict.pairs()``). Minor Breaking API Changes ++++++++++++++++++++++++++ The following breaking changes are expected to affect few if any users. - Rename ``bidict.pairs()`` → :func:`bidict._util._iteritems_args_kw`. 0.15.0 (2018-03-29) ------------------- Speedups and memory usage improvements ++++++++++++++++++++++++++++++++++++++ - Use :ref:`slots` to speed up bidict attribute access and reduce memory usage. On Python 3, instantiating a large number of bidicts now uses ~57% the amount of memory that it used before, and on Python 2 only ~33% the amount of memory that it used before, in a simple but representative `benchmark `__. - Use weakrefs to refer to a bidict's inverse internally, no longer creating a strong reference cycle. Memory for a bidict that you create can now be reclaimed in CPython as soon as you no longer hold any references to it, rather than having to wait for the next garbage collection. See the new :ref:`addendum:Bidict Avoids Reference Cycles` documentation. `#24 `__ - Make :func:`bidict.BidictBase.__eq__` significantly more speed- and memory-efficient when comparing to a non-:class:`dict` :class:`~collections.abc.Mapping`. (``Mapping.__eq__()``\'s inefficient implementation will now never be used.) The implementation is now more reusable as well. - Make :func:`bidict.OrderedBidictBase.__iter__` as well as equality comparison slightly faster for ordered bidicts. Minor Bugfixes ++++++++++++++ - :func:`~bidict.namedbidict` now verifies that the provided ``keyname`` and ``valname`` are distinct, raising :class:`ValueError` if they are equal. - :func:`~bidict.namedbidict` now raises :class:`TypeError` if the provided ``base_type`` is not a :class:`~bidict.BidirectionalMapping`. - If you create a custom bidict subclass whose ``_fwdm_cls`` differs from its ``_invm_cls`` (as in the ``FwdKeySortedBidict`` example from the :ref:`extending:Sorted Bidict Recipes`), the inverse bidirectional mapping type (with ``_fwdm_cls`` and ``_invm_cls`` swapped) is now correctly computed and used automatically for your custom bidict's :attr:`~bidict.BidictBase.inverse` bidict. Miscellaneous +++++++++++++ - Classes no longer have to provide an ``__inverted__`` attribute to be considered virtual subclasses of :class:`~bidict.BidirectionalMapping`. - If :func:`bidict.inverted` is passed an object with an ``__inverted__`` attribute, it now ensures it is :func:`callable` before returning the result of calling it. - :func:`~bidict.BidictBase.__repr__` no longer checks for a ``__reversed__`` method to determine whether to use an ordered or unordered-style repr. It now calls the new ``__repr_delegate__`` instead (which may be overridden if needed), for better composability. Minor Breaking API Changes ++++++++++++++++++++++++++ The following breaking changes are expected to affect few if any users. - Split back out the :class:`~bidict.BidictBase` class from :class:`~bidict.frozenbidict` and :class:`~bidict.OrderedBidictBase` from :class:`~bidict.FrozenOrderedBidict`, reverting the merging of these in 0.14.0. Having e.g. ``issubclass(bidict, frozenbidict) == True`` was confusing, so this change restores ``issubclass(bidict, frozenbidict) == False``. See the updated :ref:`other-bidict-types:Bidict Types Diagram` and :ref:`other-bidict-types:Polymorphism` documentation. - Rename: - ``bidict.BidictBase.fwdm`` → ``._fwdm`` - ``bidict.BidictBase.invm`` → ``._invm`` - ``bidict.BidictBase.fwd_cls`` → ``._fwdm_cls`` - ``bidict.BidictBase.inv_cls`` → ``._invm_cls`` - ``bidict.BidictBase.isinv`` → ``._isinv`` Though overriding ``_fwdm_cls`` and ``_invm_cls`` remains supported (see :doc:`extending`), this is not a common enough use case to warrant public names. Most users do not need to know or care about any of these. - The :attr:`~bidict.RAISE`, :attr:`~bidict.OVERWRITE`, and :attr:`~bidict.IGNORE` duplication policies are no longer available as attributes of :class:`bidict.DuplicationPolicy`, and can now only be accessed as attributes of the :mod:`bidict` module namespace, which was the canonical way to refer to them anyway. It is now no longer possible to create an infinite chain like ``DuplicationPolicy.RAISE.RAISE.RAISE...`` - Make ``bidict.pairs()`` and :func:`bidict.inverted` no longer importable from ``bidict.util``, and now only importable from the top-level :mod:`bidict` module. (``bidict.util`` was renamed ``bidict._util``.) - Pickling ordered bidicts now requires at least version 2 of the pickle protocol. If you are using Python 3, :attr:`pickle.DEFAULT_PROTOCOL` is 3 anyway, so this will not affect you. However if you are using in Python 2, :attr:`~pickle.DEFAULT_PROTOCOL` is 0, so you must now explicitly specify the version in your :func:`pickle.dumps` calls, e.g. ``pickle.dumps(ob, 2)``. 0.14.2 (2017-12-06) ------------------- - Make initializing (or updating an empty bidict) from only another :class:`~bidict.BidirectionalMapping` more efficient by skipping unnecessary duplication checking. - Fix accidental ignoring of specified ``base_type`` argument when (un)pickling a :func:`~bidict.namedbidict`. - Fix incorrect inversion of ``some_named_bidict.inv._for`` and ``some_named_bidict.inv._for``. - Only warn when an unsupported Python version is detected (e.g. Python < 2.7) rather than raising :class:`AssertionError`. 0.14.1 (2017-11-28) ------------------- - Fix a bug introduced in 0.14.0 where hashing a :class:`~bidict.frozenbidict`\’s inverse (e.g. ``f = frozenbidict(); {f.inv: '...'}``) would cause an ``AttributeError``. - Fix a bug introduced in 0.14.0 for Python 2 users where attempting to call ``viewitems()`` would cause a ``TypeError``. `#48 `__ 0.14.0 (2017-11-20) ------------------- - Fix a bug where :class:`~bidict.bidict`\’s default *on_dup_kv* policy was set to :attr:`~bidict.RAISE`, rather than matching whatever *on_dup_val* policy was in effect as was :ref:`documented `. - Fix a bug that could happen when using Python's optimization (``-O``) flag that could leave an ordered bidict in an inconsistent state when dealing with duplicated, overwritten keys or values. If you do not use optimizations (specifically, skipping ``assert`` statements), this would not have affected you. - Fix a bug introduced by the optimizations in 0.13.0 that could cause a frozen bidict that compared equal to another mapping to have a different hash value from the other mapping, violating Python's object model. This would only have affected you if you were inserting a frozen bidict and some other immutable mapping that it compared equal to into the same set or mapping. - Add :meth:`~bidict.OrderedBidictBase.equals_order_sensitive`. - Reduce the memory usage of ordered bidicts. - Make copying of ordered bidicts faster. - Improvements to tests and CI, including: - Test on Windows - Test with PyPy3 - Test with CPython 3.7-dev - Test with optimization flags - Require pylint to pass Breaking API Changes ++++++++++++++++++++ This release includes multiple API simplifications and improvements. - Rename: - ``orderedbidict`` → :class:`~bidict.OrderedBidict` - ``frozenorderedbidict`` → :class:`~bidict.FrozenOrderedBidict` so that these now match the case of :class:`collections.OrderedDict`. The names of the :class:`~bidict.bidict`, :func:`~bidict.namedbidict`, and :class:`~bidict.frozenbidict` classes have been retained as all-lowercase so that they continue to match the case of :class:`dict`, :func:`~collections.namedtuple`, and :class:`frozenset`, respectively. - The ``ON_DUP_VAL`` duplication policy value for *on_dup_kv* has been removed. Use ``None`` instead. - Merge :class:`~bidict.frozenbidict` and ``BidictBase`` together and remove ``BidictBase``. :class:`~bidict.frozenbidict` is now the concrete base class that all other bidict types derive from. See the updated :ref:`other-bidict-types:Bidict Types Diagram`. - Merge :class:`~bidict.frozenbidict` and ``FrozenBidictBase`` together and remove ``FrozenBidictBase``. See the updated :ref:`other-bidict-types:Bidict Types Diagram`. - Merge ``frozenorderedbidict`` and ``OrderedBidictBase`` together into a single :class:`~bidict.FrozenOrderedBidict` class and remove ``OrderedBidictBase``. :class:`~bidict.OrderedBidict` now extends :class:`~bidict.FrozenOrderedBidict` to add mutable behavior. See the updated :ref:`other-bidict-types:Bidict Types Diagram`. - Make :meth:`~bidict.OrderedBidictBase.__eq__` always perform an order-insensitive equality test, even if the other mapping is ordered. Previously, :meth:`~bidict.OrderedBidictBase.__eq__` was only order-sensitive for other ``OrderedBidictBase`` subclasses, and order-insensitive otherwise. Use the new :meth:`~bidict.OrderedBidictBase.equals_order_sensitive` method for order-sensitive equality comparison. - ``orderedbidict._should_compare_order_sensitive()`` has been removed. - ``frozenorderedbidict._HASH_NITEMS_MAX`` has been removed. Since its hash value must be computed from all contained items (so that hash results are consistent with equality comparisons against unordered mappings), the number of items that influence the hash value should not be limitable. - ``frozenbidict._USE_ITEMSVIEW_HASH`` has been removed, and ``frozenbidict.compute_hash()`` now uses ``collections.ItemsView._hash()`` to compute the hash always, not just when running on PyPy. Override ``frozenbidict.compute_hash()`` to return ``hash(frozenset(iteritems(self)))`` if you prefer the old default behavior on CPython, which takes linear rather than constant space, but which uses the ``frozenset_hash`` routine (implemented in ``setobject.c``) rather than the pure Python ``ItemsView._hash()`` routine. - ``loosebidict`` and ``looseorderedbidict`` have been removed. A simple recipe to implement equivalents yourself is now given in :ref:`extending:OverwritingBidict Recipe`. - Rename ``FrozenBidictBase._compute_hash()`` → ``frozenbidict.compute_hash()``. - Rename ``DuplicationBehavior`` → :class:`~bidict.DuplicationPolicy`. - Rename: - ``bidict.BidictBase._fwd_class`` → ``.fwd_cls`` - ``bidict.BidictBase._inv_class`` → ``.inv_cls`` - ``bidict.BidictBase._on_dup_key`` → :attr:`~bidict.BidictBase.on_dup_key` - ``bidict.BidictBase._on_dup_val`` → :attr:`~bidict.BidictBase.on_dup_val` - ``bidict.BidictBase._on_dup_kv`` → :attr:`~bidict.BidictBase.on_dup_kv` 0.13.1 (2017-03-15) ------------------- - Fix regression introduced by the new :meth:`~bidict.BidirectionalMapping.__subclasshook__` functionality in 0.13.0 so that ``issubclass(OldStyleClass, BidirectionalMapping)`` once again works with old-style classes, returning ``False`` rather than raising :class:`AttributeError` `#41 `__ 0.13.0 (2017-01-19) ------------------- - Support Python 3.6. (Earlier versions of bidict should work fine on 3.6, but it is officially supported starting in this version.) - :class:`~bidict.BidirectionalMapping` has been refactored into an abstract base class, following the way :class:`collections.abc.Mapping` works. The concrete method implementations it used to provide have been moved into a new ``BidictBase`` subclass. :class:`~bidict.BidirectionalMapping` now also implements :meth:`~bidict.BidirectionalMapping.__subclasshook__`, so any class that provides a conforming set of attributes (enumerated in :attr:`~bidict.BidirectionalMapping._subclsattrs`) will be considered a :class:`~bidict.BidirectionalMapping` subclass automatically. - ``OrderedBidirectionalMapping`` has been renamed to ``OrderedBidictBase``, to better reflect its function. (It is not an ABC.) - A new ``FrozenBidictBase`` class has been factored out of :class:`~bidict.frozenbidict` and :class:`frozenorderedbidict `. This implements common behavior such as caching the result of ``__hash__`` after the first call. - The hash implementations of :class:`~bidict.frozenbidict` and :class:`frozenorderedbidict `. have been reworked to improve performance and flexibility. :class:`frozenorderedbidict `\’s hash implementation is now order-sensitive. See ``frozenbidict._compute_hash()`` and ``frozenorderedbidict._compute_hash`` for more documentation of the changes, including the new ``frozenbidict._USE_ITEMSVIEW_HASH`` and ``frozenorderedbidict._HASH_NITEMS_MAX`` attributes. If you have an interesting use case that requires overriding these, or suggestions for an alternative implementation, please `share your feedback `__. - Add ``_fwd_class`` and ``_inv_class`` attributes representing the backing :class:`~collections.abc.Mapping` types used internally to store the forward and inverse dictionaries, respectively. This allows creating custom bidict types with extended functionality simply by overriding these attributes in a subclass. See the new :doc:`extending` documentation for examples. - Pass any parameters passed to :meth:`~bidict.bidict.popitem` through to ``_fwd.popitem`` for greater extensibility. - More concise repr strings for empty bidicts. e.g. ``bidict()`` rather than ``bidict({})`` and ``orderedbidict()`` rather than ``orderedbidict([])``. - Add :attr:`bidict.compat.PYPY` and remove unused ``bidict.compat.izip_longest``. 0.12.0 (2016-07-03) ------------------- - New/renamed exceptions: - :class:`~bidict.KeyDuplicationError` - :class:`~bidict.ValueDuplicationError` - :class:`~bidict.KeyAndValueDuplicationError` - :class:`~bidict.DuplicationError` (base class for the above) - :func:`~bidict.bidict.put` now accepts ``on_dup_key``, ``on_dup_val``, and ``on_dup_kv`` keyword args which allow you to override the default policy when the key or value of a given item duplicates any existing item's. These can take the following values: - :attr:`~bidict.RAISE` - :attr:`~bidict.OVERWRITE` - :attr:`~bidict.IGNORE` ``on_dup_kv`` can also take ``ON_DUP_VAL``. If not provided, :func:`~bidict.bidict.put` uses the :attr:`~bidict.RAISE` policy by default. - New :func:`~bidict.bidict.putall` method provides a bulk :func:`~bidict.bidict.put` API, allowing you to override the default duplication handling policy that :func:`~bidict.bidict.update` uses. - :func:`~bidict.bidict.update` now fails clean, so if an :func:`~bidict.bidict.update` call raises a :class:`~bidict.DuplicationError`, you can now be sure that none of the given items was inserted. Previously, all of the given items that were processed before the one causing the failure would have been inserted, and no facility was provided to recover which items were inserted and which weren't, nor to revert any changes made by the failed :func:`~bidict.bidict.update` call. The new behavior makes it easier to reason about and control the effects of failed :func:`~bidict.bidict.update` calls. The new :func:`~bidict.bidict.putall` method also fails clean. Internally, this is implemented by storing a log of changes made while an update is being processed, and rolling back the changes when one of them is found to cause an error. This required reimplementing :class:`orderedbidict ` on top of two dicts and a linked list, rather than two OrderedDicts, since :class:`~collections.OrderedDict` does not expose its backing linked list. - :func:`orderedbidict.move_to_end() ` now works on Python < 3.2 as a result of the new :class:`orderedbidict ` implementation. - Add - :func:`bidict.compat.viewkeys` - :func:`bidict.compat.viewvalues` - :func:`bidict.compat.iterkeys` - :func:`bidict.compat.itervalues` - ``bidict.compat.izip`` - ``bidict.compat.izip_longest`` to complement the existing :func:`~bidict.compat.iteritems` and :func:`~bidict.compat.viewitems` compatibility helpers. - More efficient implementations of ``bidict.pairs()``, :func:`~bidict.inverted`, and :func:`~bidict.BidictBase.copy`. - Implement :func:`~bidict.BidictBase.__copy__` for use with the :mod:`copy` module. - Fix issue preventing a client class from inheriting from ``loosebidict``. `#34 `__ - Add benchmarking to tests. - Drop official support for CPython 3.3. (It may continue to work, but is no longer being tested.) Breaking API Changes ++++++++++++++++++++ - Rename ``KeyExistsException`` → :class:`~bidict.KeyDuplicationError` and ``ValueExistsException`` → :class:`~bidict.ValueDuplicationError`. - When overwriting the key of an existing value in an :class:`orderedbidict `, the position of the existing item is now preserved, overwriting the key of the existing item in place, rather than moving the item to the end. This now matches the behavior of overwriting the value of an existing key, which has always preserved the position of the existing item. (If inserting an item whose key duplicates that of one existing item and whose value duplicates that of another, the existing item whose value is duplicated is still dropped, and the existing item whose key is duplicated still gets its value overwritten in place, as before.) For example: .. code:: python >>> from bidict import orderedbidict # doctest: +SKIP >>> o = orderedbidict([(0, 1), (2, 3)]) # doctest: +SKIP >>> o.forceput(4, 1) # doctest: +SKIP previously would have resulted in: .. code:: python >>> o # doctest: +SKIP orderedbidict([(2, 3), (4, 1)]) but now results in: .. code:: python >>> o # doctest: +SKIP orderedbidict([(4, 1), (2, 3)]) 0.11.0 (2016-02-05) ------------------- - Add :class:`orderedbidict `, ``looseorderedbidict``, and :class:`frozenorderedbidict `. - Add :doc:`code-of-conduct`. - Drop official support for pypy3. (It still may work but is no longer being tested. Support may be added back once pypy3 has made more progress.) 0.10.0.post1 (2015-12-23) ------------------------- - Minor documentation fixes and improvements. 0.10.0 (2015-12-23) ------------------- - Remove several features in favor of keeping the API simpler and the code more maintainable. - In the interest of protecting data safety more proactively, by default bidict now raises an error on attempting to insert a non-unique value, rather than allowing its associated key to be silently overwritten. See discussion in `#21 `__. - New :meth:`~bidict.bidict.forceupdate` method provides a bulk :meth:`~bidict.bidict.forceput` operation. - Fix bugs in :attr:`~bidict.bidict.pop` and :attr:`~bidict.bidict.setdefault` which could leave a bidict in an inconsistent state. Breaking API Changes ++++++++++++++++++++ - Remove ``bidict.__invert__``, and with it, support for the ``~b`` syntax. Use :attr:`~bidict.BidictBase.inv` instead. `#19 `__ - Remove support for the slice syntax. Use ``b.inv[val]`` rather than ``b[:val]``. `#19 `__ - Remove ``bidict.invert``. Use :attr:`~bidict.BidictBase.inv` rather than inverting a bidict in place. `#20 `__ - Raise ``ValueExistsException`` when attempting to insert a mapping with a non-unique key. `#21 `__ - Rename ``collapsingbidict`` → ``loosebidict`` now that it suppresses ``ValueExistsException`` rather than the less general ``CollapseException``. `#21 `__ - ``CollapseException`` has been subsumed by ``ValueExistsException``. `#21 `__ - :meth:`~bidict.bidict.put` now raises ``KeyExistsException`` when attempting to insert an already-existing key, and ``ValueExistsException`` when attempting to insert an already-existing value. 0.9.0.post1 (2015-06-06) ------------------------ - Fix metadata missing in the 0.9.0rc0 release. 0.9.0rc0 (2015-05-30) --------------------- - Add this changelog, `Contributors' Guide `__, `Gitter chat room `__, and other community-oriented improvements. - Adopt Pytest. - Add property-based tests via `hypothesis `__. - Other code, tests, and docs improvements. Breaking API Changes ++++++++++++++++++++ - Move ``bidict.iteritems()`` and ``bidict.viewitems()`` to new :mod:`bidict.compat` module. - Move :class:`bidict.inverted` to new ``bidict.util`` module (still available from top-level :mod:`bidict` module as well). - Move ``bidict.fancy_iteritems()`` → ``bidict.util.pairs()`` (also available from top level as ``bidict.pairs()``). - Rename :func:`bidict.namedbidict`\'s ``bidict_type`` argument → ``base_type``. bidict-0.18.2/docs/code-of-conduct.rst0000664000372000037200000000631613535200701020337 0ustar travistravis00000000000000Code of Conduct =============== Our Pledge ---------- In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. Our Standards ------------- Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting Our Responsibilities -------------------- Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. Scope ----- This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. Enforcement ----------- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. Attribution ----------- This Code of Conduct is adapted from the `Contributor Covenant `__, version 1.4, available at `https://www.contributor-covenant.org/version/1/4 `__. bidict-0.18.2/docs/conf.py0000664000372000037200000002412213535200701016126 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # bidict documentation build configuration file, created by # sphinx-quickstart on Fri Aug 29 11:38:22 2014. # # 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. """Sphinx configuration.""" import sys import os # pylint: disable=invalid-name # 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. sys.path.insert(0, os.path.abspath('..')) import bidict # noqa: E402; pylint: disable=wrong-import-position # -- General configuration ------------------------------------------------ suppress_warnings = ['image.nonlocal_uri'] # 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 = [ 'alabaster', 'sphinx.ext.autodoc', 'sphinx.ext.autosectionlabel', 'sphinx.ext.coverage', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode', 'sphinx.ext.todo', ] intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} #todo_include_todos = True # Add any paths that contain templates here, relative to this directory. #templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'bidict' author = bidict.__author__ copyright = bidict.__copyright__ # pylint: disable=redefined-builtin # 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 full version, including alpha/beta/rc tags. release = bidict.__version__ # The short X.Y version. version = '.'.join(release.split('.')[:2]) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. modindex_common_prefix = ['bidict.'] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'alabaster' #html_theme = 'sphinx_rtd_theme' #html_theme = 'nature' # 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 = dict( analytics_id='UA-10116163-3', description=bidict.__description__, link_hover='#247BA1', github_banner=True, github_repo='bidict', github_type='star', github_user='jab', page_width='1000px', show_powered_by=False, show_relbar_bottom=True, donate_url='https://gumroad.com/l/bidict', tidelift_url='https://tidelift.com/subscription/pkg/pypi-bidict?utm_source=pypi-bidict&utm_medium=referral&utm_campaign=docs', # noqa: E501; pylint: disable=line-too-long ) # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [alabaster.get_path()] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = '_static/logo-256.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. html_favicon = '_static/favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. html_sidebars = { '**': [ 'about.html', 'navigation.html', 'relations.html', 'searchbox.html', 'donate.html', ] } # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. html_split_index = True # If true, links to the reST sources are added to the pages. html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. html_show_sphinx = False # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'bidictdoc' # -- Options for LaTeX output --------------------------------------------- #latex_elements = { ## The paper size ('letterpaper' or 'a4paper'). ##'papersize': 'letterpaper', # ## The font size ('10pt', '11pt' or '12pt'). ##'pointsize': '10pt', # ## Additional stuff for the LaTeX preamble. ##'preamble': '', #} # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). #latex_documents = [ # ('index', 'bidict.tex', u'bidict Documentation', # author, 'manual'), #] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). #man_pages = [ # ('index', 'bidict', u'bidict Documentation', # [author], 1) #] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) #texinfo_documents = [ # ('index', 'bidict', u'bidict Documentation', # author, 'bidict', 'One line description of project.', # 'Miscellaneous'), #] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False # Ignore urls matching these regex strings when doing "make linkcheck" linkcheck_ignore = [ ] linkcheck_timeout = 30 # 5s default too low # http://www.sphinx-doc.org/en/stable/ext/autosectionlabel.html#configuration autosectionlabel_prefix_document = True # http://www.sphinx-doc.org/en/master/usage/extensions/doctest.html doctest_global_setup = """ """ def setup(app): """https://docs.readthedocs.io/en/latest/guides/adding-custom-css.html#adding-custom-css-or-javascript-to-a-sphinx-project""" # noqa: E501; pylint: disable=line-too-long app.add_javascript('custom.js') bidict-0.18.2/docs/contributors-guide.rst0000664000372000037200000001472313535200701021217 0ustar travistravis00000000000000.. Forward declarations for all the custom interpreted text roles that Sphinx defines and that are used below. This helps Sphinx-unaware tools (e.g. rst2html, PyPI's and GitHub's renderers, etc.). .. role:: doc .. role:: ref Contributors' Guide =================== Bug reports, feature requests, patches, and other contributions are warmly welcomed. Contribution should be as easy and friendly as possible. Below are a few guidelines contributors should follow to facilitate the process. Getting Started --------------- - `Create a GitHub account `__ if you don't have one already. - Search through the `issue tracker `__ to see if an issue or pull request has already been created for what you're interested in. If so, feel free to add comments to it or just hit the "subscribe" button to follow progress. If not, you can `join the chat room `__ to discuss there, or go ahead and `create a new issue `__: - Clearly describe the issue giving as much relevant context as possible. - If it is a bug, include reproduction steps, all known environments in which the bug is exhibited, and ideally a failing test case. - If you would like to contribute a patch, make sure you've `created your own fork `__ and have cloned it to your computer. Making Changes -------------- - Before making changes, please install the extra packages required for development: ``pip install -e .[dev]`` We use `EditorConfig `__ and `pre-commit `__ to help achieve uniform style and quality standards across a diversity of development environments. pre-commit gets installed when you run ``pip install -e .[dev]`` and ensures that various code checks are run before every commit (look in ``.pre-commit-config.yaml`` to see which hooks are run). EditorConfig allows us to provide a single ``.editorconfig`` file to configure settings like indentation consistently across a variety of suppored editors. See https://editorconfig.org/#download to install the plugin for your editor. - Create a topic branch off of master for your changes: ``git checkout -b master`` - Make commits of logical units. - Match the existing code style and quality standards. If you're adding a feature, include accompanying tests and documentation demonstrating its correctness and usage. - Run the tests locally with `tox `__ to make sure they pass for all supported Python versions (see ``envlist`` in ``tox.ini`` for the complete list). If you do not have all the referenced Python versions available locally, you can also push the changes on your branch to GitHub to automatically trigger a new `Travis-CI `__ build, which should run the tests for all supported Python versions. You should be able to see the results at ``travis-ci.org//bidict``, where ```` is the GitHub username you used to fork bidict. - Create a concise but comprehensive commit message in the following style:: Include an example commit message in CONTRIBUTING guide #9999 Without this patch the CONTRIBUTING guide would contain no examples of a model commit message. This is a problem because the contributor is left to imagine what the commit message should look like and may not get it right. This patch fixes the problem by providing a concrete example. The first line is an imperative statement summarizing the changes with an issue number from the tracker. The body describes the behavior without the patch, why it's a problem, and how the patch fixes the problem. Submitting Changes ------------------ - Push your changes to a topic branch in your fork of the repository: ``git push --set-upstream origin `` - Submit a pull request providing any additional relevant details necessary. - Acknowledgment should typically be fast but please allow 1-2 weeks for a full response / code review. - The code review process often involves some back-and-forth to get everything right before merging. This is typical of quality software projects that accept patches. - All communication should be supportive and appreciative of good faith efforts to contribute, creating a welcoming and inclusive community. Expect nothing less of any project. Other Ways to Contribute ------------------------ .. image:: https://img.shields.io/badge/Gumroad-Chip%20in-orange.svg :target: https://gumroad.com/l/bidict :alt: Chip in via Gumroad .. image:: https://img.shields.io/badge/Bountysource-Chip%20in-brightgreen.svg :target: https://www.bountysource.com/teams/bidict :alt: Chip in via Bountysource .. image:: https://img.shields.io/badge/PayPal-Chip%20in-blue.svg :target: https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=jab%40math%2ebrown%2eedu&lc=US&item_name=Support%20bidict&button_subtype=services¤cy_code=USD&bn=PP%2dBuyNowBF%3aPaypal%2dBuy%2520a%2520Drink%2dblue%2esvg%3aNonHosted :alt: Chip in via PayPal .. duplicated in README.rst (would use `.. include::` but GitHub doesn't understand it) Bidict is the product of hundreds of hours of unpaid, voluntary work. If bidict has helped you accomplish your work, especially work you've been paid for, please consider chipping in toward the costs of bidict's maintenance and development and/or ask your organization to do the same. Any amount contributed is gratefully received. Besides chipping in financially, filing issues, and submitting pull requests, there are other ways to contribute. - If you read the code and learned something new, please :ref:`let me know ` [#fn-let-me-know]_. - If you're using bidict in a project you work on, please post about your experience and send me a link. - If you come across other people who could find bidict useful, please spread the word. **Please support bidict:** .. image:: https://raw.githubusercontent.com/jab/bidict/master/assets/support-on-gumroad.png :target: https://gumroad.com/l/bidict :alt: Support bidict Code of Conduct --------------- All participation in this project should respect the :doc:`code-of-conduct`. [#fn-coc]_ By participating, you are expected to honor this code. .. [#fn-let-me-know] ``__ .. [#fn-coc] ``_ | ``__ bidict-0.18.2/docs/extending.rst0000664000372000037200000001437613535200701017360 0ustar travistravis00000000000000Extending ``bidict`` -------------------- Although bidict ships with all the bidict types we just covered, it's always possible users might need something more than what's provided. For this reason, bidict was written with extensibility in mind. Let's look at some examples. OverwritingBidict Recipe ######################## If you'd like :attr:`~bidict.OVERWRITE` to be the default duplication policy for :func:`~bidict.bidict.__setitem__` and :func:`~bidict.bidict.update`, rather than always having to use :func:`~bidict.bidict.forceput` and :func:`~bidict.bidict.forceupdate`, you can use the following recipe: .. doctest:: >>> from bidict import bidict, OVERWRITE >>> class OverwritingBidict(bidict): ... on_dup_val = OVERWRITE >>> b = OverwritingBidict({'one': 1}) >>> b['two'] = 1 # succeeds, no ValueDuplicationError >>> b OverwritingBidict({'two': 1}) >>> b.update({'three': 1}) # ditto >>> b OverwritingBidict({'three': 1}) As with :class:`bidict.bidict`, ``OverwritingBidict.put()`` and ``OverwritingBidict.putall()`` will still provide per-call overrides for duplication policies, and will both still default to raising for all duplication types unless you override those methods too. To make an overwriting *ordered* bidict, simply adapt this recipe to have the class inherit from :class:`bidict.OrderedBidict`. Beware of ``OVERWRITE`` ::::::::::::::::::::::: With a default :attr:`~bidict.OVERWRITE` policy as in the ``OverwritingBidict`` recipe above, beware of the following potentially surprising behavior: .. doctest:: >>> b = OverwritingBidict({'one': 1, 'two': 2}) >>> b['one'] = 2 >>> b OverwritingBidict({'one': 2}) That is, setting an existing key to the value of a different existing item causes both existing items to be collapsed into a single item. Sorted Bidict Recipes ##################### Suppose you need a bidict that maintains its items in sorted order. The Python standard library does not include any sorted dict types, but the excellent `sortedcontainers `__ and `sortedcollections `__ libraries do. Armed with these along with bidict's :attr:`~bidict.BidictBase._fwdm_cls` and :attr:`~bidict.BidictBase._invm_cls` attributes, creating a sorted bidict type is dead simple: .. doctest:: >>> # As an optimization, bidict.bidict includes a mixin class that >>> # we can't use here (namely bidict._delegating_mixins._DelegateKeysAndItemsToFwdm), >>> # so extend the parent class, bidict.MutableBidict, instead. >>> from bidict import MutableBidict >>> import sortedcontainers >>> class SortedBidict(MutableBidict): ... """A sorted bidict whose forward items stay sorted by their keys, ... and whose inverse items stay sorted by *their* keys. ... Note: As a result, an instance and its inverse yield their items ... in different orders. ... """ ... ... _fwdm_cls = sortedcontainers.SortedDict ... _invm_cls = sortedcontainers.SortedDict ... _repr_delegate = list >>> b = SortedBidict({'Tokyo': 'Japan', 'Cairo': 'Egypt'}) >>> b SortedBidict([('Cairo', 'Egypt'), ('Tokyo', 'Japan')]) >>> b['Lima'] = 'Peru' >>> # b stays sorted by its keys: >>> list(b.items()) [('Cairo', 'Egypt'), ('Lima', 'Peru'), ('Tokyo', 'Japan')] >>> # b.inverse stays sorted by *its* keys (b's values) >>> list(b.inverse.items()) [('Egypt', 'Cairo'), ('Japan', 'Tokyo'), ('Peru', 'Lima')] Here's a recipe for a sorted bidict whose forward items stay sorted by their keys, and whose inverse items stay sorted by their values. i.e. An instance and its inverse will yield their items in *the same* order: .. doctest:: >>> import sortedcollections >>> class KeySortedBidict(MutableBidict): ... _fwdm_cls = sortedcontainers.SortedDict ... _invm_cls = sortedcollections.ValueSortedDict ... _repr_delegate = list >>> element_by_atomic_number = KeySortedBidict({ ... 3: 'lithium', 1: 'hydrogen', 2: 'helium'}) >>> # stays sorted by key: >>> element_by_atomic_number KeySortedBidict([(1, 'hydrogen'), (2, 'helium'), (3, 'lithium')]) >>> # .inverse stays sorted by value: >>> list(element_by_atomic_number.inverse.items()) [('hydrogen', 1), ('helium', 2), ('lithium', 3)] >>> element_by_atomic_number[4] = 'beryllium' >>> list(element_by_atomic_number.inverse.items()) [('hydrogen', 1), ('helium', 2), ('lithium', 3), ('beryllium', 4)] >>> # This works because a bidict whose _fwdm_cls differs from its _invm_cls computes >>> # its inverse class -- which (note) is not actually the same class as the original, >>> # as it needs to have its _fwdm_cls and _invm_cls swapped -- automatically. >>> # You can see this if you inspect the inverse bidict: >>> element_by_atomic_number.inverse # Note the different class, which was auto-generated: KeySortedBidictInv([('hydrogen', 1), ('helium', 2), ('lithium', 3), ('beryllium', 4)]) >>> ValueSortedBidict = element_by_atomic_number.inverse.__class__ >>> ValueSortedBidict._fwdm_cls >>> ValueSortedBidict._invm_cls >>> # Round trips work as expected: >>> atomic_number_by_element = ValueSortedBidict(element_by_atomic_number.inverse) >>> atomic_number_by_element KeySortedBidictInv([('hydrogen', 1), ('helium', 2), ('lithium', 3), ('beryllium', 4)]) >>> KeySortedBidict(atomic_number_by_element.inverse) == element_by_atomic_number True >>> # One other useful trick: >>> # To pass method calls through to the _fwdm SortedDict when not present >>> # on the bidict instance, provide a custom __getattribute__ method: >>> def __getattribute__(self, name): ... try: ... return object.__getattribute__(self, name) ... except AttributeError as e: ... return getattr(self._fwdm, name) >>> KeySortedBidict.__getattribute__ = __getattribute__ >>> # bidict has no .peekitem attr, so the call is passed through to _fwdm: >>> element_by_atomic_number.peekitem() (4, 'beryllium') >>> element_by_atomic_number.inverse.peekitem() ('beryllium', 4) Next proceed to :doc:`other-functionality`. bidict-0.18.2/docs/home.rst0000664000372000037200000002144513535200701016316 0ustar travistravis00000000000000.. Forward declarations for all the custom interpreted text roles that Sphinx defines and that are used below. This helps Sphinx-unaware tools (e.g. rst2html, PyPI's and GitHub's renderers, etc.). .. role:: doc bidict ====== Efficient, Pythonic bidirectional map implementation and related functionality. .. image:: https://raw.githubusercontent.com/jab/bidict/master/assets/logo-sm.png :target: https://bidict.readthedocs.io/ :alt: bidict logo Status ------ .. image:: https://img.shields.io/pypi/v/bidict.svg :target: https://pypi.org/project/bidict :alt: Latest release .. image:: https://img.shields.io/readthedocs/bidict/master.svg :target: https://bidict.readthedocs.io/en/master/ :alt: Documentation .. image:: https://api.travis-ci.org/jab/bidict.svg?branch=master :target: https://travis-ci.org/jab/bidict :alt: Travis-CI build status .. image:: https://codecov.io/gh/jab/bidict/branch/master/graph/badge.svg :target: https://codecov.io/gh/jab/bidict :alt: Test coverage .. image:: https://img.shields.io/lgtm/alerts/github/jab/bidict.svg :target: https://lgtm.com/projects/g/jab/bidict/ :alt: LGTM alerts .. image:: https://api.codacy.com/project/badge/Grade/6628756a73254cd895656348236833b8 :target: https://www.codacy.com/app/jab/bidict :alt: Codacy grade .. image:: https://bestpractices.coreinfrastructure.org/projects/2354/badge :target: https://bestpractices.coreinfrastructure.org/en/projects/2354 :alt: CII best practices badge .. image:: https://img.shields.io/badge/tidelift-pro%20support-EF914C.svg :target: https://tidelift.com/subscription/pkg/pypi-bidict?utm_source=pypi-bidict&utm_medium=referral&utm_campaign=docs :alt: Paid support available via Tidelift .. Hide to reduce clutter .. image:: https://ci.appveyor.com/api/projects/status/gk133415udncwto3/branch/master?svg=true :target: https://ci.appveyor.com/project/jab/bidict :alt: AppVeyor (Windows) build status .. image:: https://img.shields.io/pypi/pyversions/bidict.svg :target: https://pypi.org/project/bidict :alt: Supported Python versions .. image:: https://img.shields.io/pypi/implementation/bidict.svg :target: https://pypi.org/project/bidict :alt: Supported Python implementations .. image:: https://img.shields.io/pypi/l/bidict.svg :target: https://raw.githubusercontent.com/jab/bidict/master/LICENSE :alt: License .. image:: https://img.shields.io/badge/dynamic/json.svg?label=downloads&url=https%3A%2F%2Fpypistats.org%2Fapi%2Fpackages%2Fbidict%2Frecent%3Fperiod%3Dmonth&query=%24.data.last_month&colorB=blue&suffix=%2fmonth :target: https://pypistats.org/packages/bidict :alt: Downloads past month Bidict: ^^^^^^^ - is in use by several teams at Google, Venmo, CERN, Bank of America Merrill Lynch, Bloomberg, Two Sigma, and others - has carefully designed APIs for safety, simplicity, flexibility, and ergonomics - is CPython-, PyPy-, Python 2-, and Python 3-compatible - has extensive test coverage (including property-based tests and benchmarks) run continuously on all supported Python versions and OSes - integrates natively with Python’s collections interfaces - is implemented in concise, well-factored, well-documented pure Python that leverages a number of advanced language features [#fn-learning]_ ⚠️ Python 2 EOL ⚠️ ++++++++++++++++++ Python 2 support will be dropped in a future release. See `python3statement.org `__ for more info. Installation ------------ ``pip install bidict`` Quick Start ----------- .. code:: python >>> from bidict import bidict >>> element_by_symbol = bidict({'H': 'hydrogen'}) >>> element_by_symbol['H'] 'hydrogen' >>> element_by_symbol.inverse['hydrogen'] 'H' For more usage documentation, head to the :doc:`intro` [#fn-intro]_ and proceed from there. Community Support ----------------- .. image:: https://img.shields.io/badge/chat-on%20gitter-5AB999.svg?logo=gitter-white :target: https://gitter.im/jab/bidict :alt: Chat If you are thinking of using bidict in your work, or if you have any questions, comments, or suggestions, I'd love to know about your use case and provide as much voluntary support for it as possible. Please feel free to leave a message in the `chatroom `__ or open a new issue on GitHub. You can search through `existing issues `__ before creating a new one in case your questions or concerns have been adressed there already. Paid Support via Tidelift ------------------------- .. image:: https://img.shields.io/badge/tidelift-pro%20support-EF914C.svg :target: https://tidelift.com/subscription/pkg/pypi-bidict?utm_source=pypi-bidict&utm_medium=referral&utm_campaign=readme :alt: Paid support available via Tidelift If your use case requires a greater level of support, contractual support for bidict can be obtained through the `Tidelift subscription `__. Notice of Usage --------------- If you use bidict, and especially if your usage or your organization is significant in some way, please let me know. You can: - `star bidict on GitHub `__ (the "star" button is at the top-right) - `create an issue `__ (preferred) - leave a message in the `chat room `__ - `email me `__ Changelog --------- See the :doc:`changelog` [#fn-changelog]_ for a history of notable changes to bidict. Release Notifications --------------------- .. duplicated in CHANGELOG.rst: (would use `.. include::` but GitHub doesn't understand it) .. image:: https://img.shields.io/badge/libraries.io-subscribe-5BC0DF.svg :target: https://libraries.io/pypi/bidict :alt: Follow on libraries.io `Subscribe to bidict releases `__ on libraries.io to be notified when new versions of bidict are released. Alternatively, on `GitHub `__, click "`Watch `__" and choose "Releases". Learning from bidict -------------------- One of the most rewarding things about bidict is the outsized amount of advanced Python it covers in light of its small codebase. Check out :doc:`learning-from-bidict` [#fn-learning]_ if you're interested in learning more. Contributing ------------ Bidict is currently a one-person operation maintained on a voluntary basis with no other sponsorship. Your help would be most welcome! Reviewers Wanted! ^^^^^^^^^^^^^^^^^ One of the most valuable ways to contribute to bidict and to explore some advanced Python [#fn-learning]_ while you're at it is to review bidict's relatively small codebase. Please create an issue or pull request with any improvements you'd propose or any other results you found. (Submitting a "Nothing-to-merge" PR with feedback in inline code comments or a `Review results `__ issue both work well.) You can also +1 `this issue `__ to sign up to give feedback on future proposed changes that are in need of a reviewer. Giving Back ^^^^^^^^^^^ .. duplicated in CONTRIBUTING.rst (would use `.. include::` but GitHub doesn't understand it) Bidict is the product of hundreds of hours of unpaid, voluntary work. If bidict has helped you accomplish your work, especially work you've been paid for, please consider chipping in toward the costs of bidict's maintenance and development and/or ask your organization to do the same. .. image:: https://raw.githubusercontent.com/jab/bidict/master/assets/support-on-gumroad.png :target: https://gumroad.com/l/bidict :alt: Support bidict Finding Documentation --------------------- If you're viewing this on ``__, note that multiple versions of the documentation are available, and you can choose a different version using the popup menu at the bottom-right. Please make sure you're viewing the version of the documentation that corresponds to the version of bidict you'd like to use. If you're viewing this on GitHub, PyPI, or some other place that can't render and link this documentation properly and are seeing broken links, try these alternate links instead: .. [#fn-intro] ``__ | ``__ .. [#fn-changelog] ``__ | ``__ .. [#fn-learning] ``__ | ``__ ---- Next: :doc:`intro` [#fn-intro]_ bidict-0.18.2/docs/index.rst0000664000372000037200000000037513535200701016474 0ustar travistravis00000000000000.. toctree:: :hidden: Home intro basic-usage other-bidict-types extending other-functionality addendum changelog api learning-from-bidict contributors-guide code-of-conduct thanks .. include:: home.rst bidict-0.18.2/docs/intro.rst0000664000372000037200000001042313535200701016513 0ustar travistravis00000000000000Introduction ============ The :mod:`bidict` package provides a Pythonic `bidirectional map `__ implementation and related functionality to work with one-to-one mappings in Python. bidict.bidict ------------- :class:`bidict.bidict` is the main bidirectional map data structure provided. It implements the familiar API you're used to from dict: .. testsetup:: from bidict import bidict .. doctest:: >>> element_by_symbol = bidict({'H': 'hydrogen'}) >>> element_by_symbol bidict({'H': 'hydrogen'}) >>> element_by_symbol['H'] 'hydrogen' But it also maintains the inverse bidict via the :attr:`~bidict.BidictBase.inverse` attribute: .. doctest:: >>> element_by_symbol.inverse bidict({'hydrogen': 'H'}) >>> element_by_symbol.inverse['hydrogen'] 'H' Concise, efficient, Pythonic. Why can't I just use a dict? ---------------------------- A skeptic writes: If I want a mapping associating *a* → *b* and *b* → *a*, I can just create the dict ``{a: b, b: a}``. Why bother using bidict? One answer is better ergonomics for maintaining a correct representation. For example, consider what happens when we need to change an existing association: If we want to create the assocation *a* ⟷ *b*, but might have already created the association *a* ⟷ *c*, with the skeptic's approach we would have to write: .. doctest:: >>> # To represent an existing association a ⟷ c in a single dict d: >>> d = {'a': 'c', 'c': 'a'} >>> # Here is what we'd have to do to make sure a ⟷ b gets associated >>> # regardless of what associations may be in d already: >>> newkey = 'a' >>> newval = 'b' >>> _sentinel = object() >>> oldval = d.pop(newkey, _sentinel) >>> if oldval is not _sentinel: ... del d[oldval] >>> oldkey = d.pop(newval, _sentinel) >>> if oldkey is not _sentinel: ... del d[oldkey] >>> d[newkey] = newval >>> d[newval] = newkey >>> d == {'a': 'b', 'b': 'a'} True With bidict, we can instead just write: .. doctest:: >>> m = bidict({'a': 'c'}) # (match the previous initial setup) >>> # Here is all we need to make sure a ⟷ b: >>> m['a'] = 'b' and voilà, bidict takes care of all the fussy details, leaving us with just what we wanted: .. doctest:: >>> m bidict({'a': 'b'}) >>> m.inverse bidict({'b': 'a'}) Even more important... ++++++++++++++++++++++ Beyond this, consider what would happen if we needed to work with just the keys, values, or items that we have associated. Since the single-dict approach inserts values as keys into the same dict that it inserts keys into, we'd never be able to tell our keys and values apart. So iterating over the keys would also yield the values (and vice versa), with no way to tell which was which. Iterating over the items would yield twice as many as we wanted, with a *(v, k)* item that we'd have to ignore for each *(k, v)* item that we expect, and no way to tell which was which. .. doctest:: >>> # Compare: >>> sorted(d.keys()) # gives both keys and values ['a', 'b'] >>> sorted(d.values()) # gives both keys and values ['a', 'b'] >>> # vs. >>> sorted(m.keys()) # just the keys ['a'] >>> sorted(m.values()) # just the values ['b'] In short, to model a bidirectional mapping, we need two separate one-directional mappings, one for the forward associations and one for the inverse, that are kept in sync as the associations change. This is exactly what bidict does under the hood, abstracting it into a clean, simple, Pythonic interface. bidict's APIs also provide power, flexibility, and safety, making sure the one-to-one invariant is maintained and inverse mappings are kept consistent, while also helping make sure you don't accidentally :ref:`shoot yourself in the foot `. Additional Functionality ------------------------ Besides the standard :class:`bidict.bidict` type, the :mod:`bidict` module provides other bidirectional mapping variants: - :class:`~bidict.frozenbidict` - :class:`~bidict.OrderedBidict` - :class:`~bidict.FrozenOrderedBidict` - :func:`~bidict.namedbidict` – custom bidict type factory function Additional functionality is covered in later sections. But first let's proceed to :doc:`basic-usage`. bidict-0.18.2/docs/learning-from-bidict.rst0000664000372000037200000004641413535200701021365 0ustar travistravis00000000000000Learning from bidict -------------------- Below is an outline of some of the more fascinating and lesser-known Python corners I got to explore further thanks to working on bidict. If you are interested in learning more about any of the following, I highly encourage you to `read bidict's code `__. I've sought to optimize the code not just for correctness and performance, but also to make for a clear and enjoyable read, illuminating anything that could otherwise be obscure or subtle. I hope it brings you some of the `joy `__ it's brought me. 😊 Python syntax hacks =================== Bidict used to support (ab)using a specialized form of Python's :ref:`slice ` syntax for getting and setting keys by value: .. code-block:: python >>> element_by_symbol = bidict(H='hydrogen') >>> element_by_symbol['H'] # [normal] syntax for the forward mapping 'hydrogen' >>> element_by_symbol[:'hydrogen'] # [:slice] syntax for the inverse (no longer supported) 'H' See `this code `__ for how this was implemented, and `#19 `__ for why this was dropped. Code structure ============== Bidicts come in every combination of mutable, immutable, ordered, and unordered types, implementing Python's various :class:`relevant ` :class:`collections ` :class:`interfaces ` as appropriate. Factoring the code to maximize reuse, modularity, and adherence to `SOLID `__ design principles (while not missing any chances for special-case optimizations) has been one of the most fun parts of working on bidict. To see how this is done, check out this code: - `_base.py `__ - `_delegating_mixins.py `__ - `_frozenbidict.py `__ - `_mut.py `__ - `_bidict.py `__ - `_orderedbase.py `__ - `_frozenordered.py `__ - `_orderedbidict.py `__ Data structures are amazing =========================== Data structures are one of the most fascinating and important building blocks of programming and computer science. It's all too easy to lose sight of the magic when having to implement them for computer science courses or job interview questions. Part of this is because many of the most interesting real-world details get left out, and you miss all the value that comes from ongoing, direct practical application. Bidict shows how fundamental data structures can be implemented in Python for important real-world usage, with practical concerns at top of mind. Come to catch sight of a real, live, industrial-strength linked list in the wild. Stay for the rare, exotic bidirectional mapping breeds you'll rarely see at home. [#fn-data-struct]_ .. [#fn-data-struct] To give you a taste: A regular :class:`~bidict.bidict` encapsulates two regular dicts, keeping them in sync to preserve the bidirectional mapping invariants. Since dicts are unordered, regular bidicts are unordered too. How should we extend this to implement an ordered bidict? We'll still need two backing mappings to store the forward and inverse associations. To store the ordering, we use a (circular, doubly-) linked list. This allows us to e.g. delete an item in any position in O(1) time. Interestingly, the nodes of the linked list encode only the ordering of the items; the nodes themselves contain no key or value data. The two backing mappings associate the key and value data with the nodes, providing the final pieces of the puzzle. Can we use dicts for the backing mappings, as we did for the unordered bidict? It turns out that dicts aren't enough—the backing mappings must actually be (unordered) bidicts themselves! Check out `_orderedbase.py `__ to see this in action. Property-based testing is revolutionary ======================================= When your automated tests run, are they only checking the test cases you happened to hard-code into your test suite? How do you know these test cases aren't missing some important edge cases? With property-based testing, you describe the types of test case inputs your functions accept, along with the properties that should hold for all inputs. Rather than having to think up your test case inputs manually and hard-code them into your test suite, they get generated for you dynamically, in much greater quantity and edge case-exercising diversity than you could come up with by hand. This dramatically increases test coverage and confidence that your code is correct. Bidict never would have survived so many refactorings with so few bugs if it weren't for property-based testing, enabled by the amazing `Hypothesis `__ library. It's game-changing. Check out `bidict's property-based tests `__ to see this in action. Python surprises, gotchas, regrets ================================== - See :ref:`addendum:nan as key`. - See :ref:`addendum:Equivalent but distinct \:class\:\`~collections.abc.Hashable\`\\s`. - What should happen when checking equality of several ordered mappings that contain the same items but in a different order? What about when comparing with an unordered mapping? Check out what Python's :class:`~collections.OrderedDict` does, and the surprising results: .. code-block:: python >>> from collections import OrderedDict >>> d = dict([(0, 1), (2, 3)]) >>> od = OrderedDict([(0, 1), (2, 3)]) >>> od2 = OrderedDict([(2, 3), (0, 1)]) >>> d == od True >>> d == od2 True >>> od == od2 False >>> class MyDict(dict): ... __hash__ = lambda self: 0 ... >>> class MyOrderedDict(OrderedDict): ... __hash__ = lambda self: 0 ... >>> d = MyDict([(0, 1), (2, 3)]) >>> od = MyOrderedDict([(0, 1), (2, 3)]) >>> od2 = MyOrderedDict([(2, 3), (0, 1)]) >>> len({d, od, od2}) 1 >>> len({od, od2, d}) 2 According to Raymond Hettinger (Python core developer responsible for much of Python's collections), this design was a mistake (e.g. it violates the `Liskov substitution principle `__ and the `transitive property of equality `__), but it's too late now to fix. Fortunately, it wasn't too late for bidict to learn from this. Hence :ref:`eq-order-insensitive` for ordered bidicts, and their separate :meth:`~bidict.FrozenOrderedBidict.equals_order_sensitive` method. - If you define a custom :meth:`~object.__eq__` on a class, it will *not* be used for ``!=`` comparisons on Python 2 automatically; you must explicitly add an :meth:`~object.__ne__` implementation that calls your :meth:`~object.__eq__` implementation. If you don't, :meth:`object.__ne__` will be used instead, which behaves like ``is not``. Python 3 thankfully fixes this. Better memory usage through ``__slots__`` ========================================= Using :ref:`slots` dramatically reduces memory usage in CPython and speeds up attribute access to boot. Must be careful with pickling and weakrefs though! See `BidictBase.__getstate__() `__. Better memory usage through :mod:`weakref` ========================================== A bidict and its inverse use :mod:`weakref` to avoid creating a strong reference cycle, so that when you release your last reference to a bidict, its memory is reclaimed immediately in CPython rather than having to wait for the next garbage collection. See :ref:`addendum:Bidict Avoids Reference Cycles`. The (doubly) linked lists that back ordered bidicts also use weakrefs to avoid creating strong reference cycles. Subclassing :func:`~collections.namedtuple` classes =================================================== To get the performance benefits, intrinsic sortability, etc. of :func:`~collections.namedtuple` while customizing behavior, state, API, etc., you can subclass a :func:`~collections.namedtuple` class. Just make sure to include ``__slots__ = ()``, or you'll lose a lot of the performance benefits. ``_marker.py`` contains a small example. Here's a larger one: .. doctest:: >>> from collections import namedtuple >>> from itertools import count >>> class Node(namedtuple('_Node', 'cost tiebreaker data parent depth')): ... """Represent nodes in a graph traversal. Suitable for use with e.g. heapq.""" ... ... __slots__ = () ... _counter = count() # break ties between equal-cost nodes, avoid comparing data ... ... # Give call sites a cleaner API for creating new Nodes ... def __new__(cls, cost, data, parent=None): ... tiebreaker = next(cls._counter) ... depth = parent.depth + 1 if parent else 0 ... return super(Node, cls).__new__(cls, cost, tiebreaker, data, parent, depth) ... ... def __repr__(self): ... return 'Node(cost={cost}, data={data!r})'.format(**self._asdict()) >>> start = Node(cost=0, data='foo') >>> child = Node(cost=5, data='bar', parent=start) >>> child Node(cost=5, data='bar') >>> child.parent Node(cost=0, data='foo') >>> child.depth 1 :func:`~collections.namedtuple`-style dynamic class generation ============================================================== See the `implementation `__ of :func:`~bidict.namedbidict`. API Design ========== How to deeply integrate with Python's :mod:`collections` and other built-in APIs? - Beyond implementing :class:`collections.abc.Mapping`, bidicts implement additional APIs that :class:`dict` and :class:`~collections.OrderedDict` implement (e.g. :func:`setdefault`, :func:`popitem`, etc.). - When creating a new API, making it familiar, memorable, and intuitive is hugely important to a good user experience. - Thanks to :class:`~collections.abc.Hashable`'s implementing :meth:`abc.ABCMeta.__subclasshook__`, any class that implements the required methods of the :class:`~collections.abc.Hashable` interface (namely, :meth:`~collections.abc.Hashable.__hash__`) makes it a virtual subclass already, no need to explicitly extend. I.e. As long as ``Foo`` implements a ``__hash__()`` method, ``issubclass(Foo, Hashable)`` will always be True, no need to explicitly subclass via ``class Foo(Hashable): ...`` - How to make your own open ABC like :class:`~collections.abc.Hashable`, i.e. how does :class:`~bidict.BidirectionalMapping` work? - Override :meth:`~abc.ABCMeta.__subclasshook__` to check for the interface you require. See the `implementation `__ of :class:`~bidict.BidirectionalMapping`. - Interesting consequence of the ``__subclasshook__()`` design: the "subclass" relation becomes intransitive. e.g. :class:`object` is a subclass of :class:`~collections.abc.Hashable`, :class:`list` is a subclass of :class:`object`, but :class:`list` is not a subclass of :class:`~collections.abc.Hashable`. - What if we needed to add a second metaclass in addition to :class:`~bidict.BidirectionalMapping` (e.g. to conditionally implement an optimized version of some methods based on the type of ``_fwmd_cls``, as ``_delegating_mixins.py`` currently does without a metaclass)? Would have to be careful to avoid "TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases". See the great write-up in https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/. - :class:`collections.abc.Mapping` and :class:`collections.abc.MutableMapping` don't implement :meth:`~abc.ABCMeta.__subclasshook__`, so must either explicitly subclass (if you want to inherit any of their implementations) or use :meth:`abc.ABCMeta.register` (to register as a virtual subclass without inheriting any implementation) - Notice we have :class:`collections.abc.Reversible` but no ``collections.abc.Ordered`` or ``collections.abc.OrderedMapping``. Proposed in `bpo-28912 `__ but rejected. Would have been useful for bidict's ``__repr__()`` implementation (see ``_base.py``), and potentially for interop with other ordered mapping implementations such as `SortedDict `__. How to make APIs Pythonic? - See the `Zen of Python `__. - "Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess." Manifested in bidict's default duplication policies. - "Readability counts." "There should be one – and preferably only one – obvious way to do it." An early version of bidict allowed using the ``~`` operator to access ``.inverse`` and a special slice syntax like ``b[:val]`` to look up a key by value, but these were removed in preference to the more obvious and readable ``.inverse``-based spellings. Python's data model =================== - What happens when you implement a custom :meth:`~object.__eq__`? e.g. What's the difference between ``a == b`` and ``b == a`` when only ``a`` is an instance of your class? See the great write-up in https://eev.ee/blog/2012/03/24/python-faq-equality/ for the answer. - If an instance of your special mapping type is being compared against a mapping of some foreign mapping type that contains the same items, should your ``__eq__()`` method return true? Bidict says yes, again based on the `Liskov substitution principle `__. Only returning true when the types matched exactly would violate this. And returning :obj:`NotImplemented` would cause Python to fall back on using identity comparison, which is not what is being asked for. (Just for fun, suppose you did only return true when the types matched exactly, and suppose your special mapping type were also hashable. Would it be worth having your ``__hash__()`` method include your type as well as your items? The only point would be to reduce collisions when multiple instances of different types contained the same items and were going to be inserted into the same :class:`dict` or :class:`set`, since they'd now be unequal but would hash to the same value otherwise.) - Making an immutable type hashable (so it can be inserted into :class:`dict`\s and :class:`set`\s): Must implement :meth:`~object.__hash__` such that ``a == b ⇒ hash(a) == hash(b)``. See the :meth:`object.__hash__` and :meth:`object.__eq__` docs, and the `implementation `__ of :class:`~bidict.frozenbidict`. - Consider :class:`~bidict.FrozenOrderedBidict`: its :meth:`~bidict.FrozenOrderedBidict.__eq__` is :ref:`order-insensitive `. So all contained items must participate in the hash order-insensitively. - Can use `collections.abc.Set._hash `__ which provides a pure Python implementation of the same hash algorithm used to hash :class:`frozenset`\s. (Since :class:`~collections.abc.ItemsView` extends :class:`~collections.abc.Set`, :meth:`bidict.frozenbidict.__hash__` just calls ``ItemsView(self)._hash()``.) - Does this argue for making :meth:`collections.abc.Set._hash` non-private? - Why isn't the C implementation of this algorithm directly exposed in CPython? The only way to use it is to call ``hash(frozenset(self.items()))``, which wastes memory allocating the ephemeral frozenset, and time copying all the items into it before they're hashed. - Unlike other attributes, if a class implements ``__hash__()``, any subclasses of that class will not inherit it. It's like Python implicitly adds ``__hash__ = None`` to the body of every class that doesn't explicitly define ``__hash__``. So if you do want a subclass to inherit a base class's ``__hash__()`` implementation, you have to set that manually, e.g. by adding ``__hash__ = BaseClass.__hash__`` in the class body. See :class:`~bidict.FrozenOrderedBidict`. This is consistent with the fact that :class:`object` implements ``__hash__()``, but subclasses of :class:`object` that override :meth:`~object.__eq__` are not hashable by default. - Using :meth:`~object.__new__` to bypass default object initialization, e.g. for better :meth:`~bidict.bidict.copy` performance. See `_base.py `__. - Overriding :meth:`object.__getattribute__` for custom attribute lookup. See :ref:`extending:Sorted Bidict Recipes`. - Using :meth:`object.__getstate__`, :meth:`object.__setstate__`, and :meth:`object.__reduce__` to make an object pickleable that otherwise wouldn't be, due to e.g. using weakrefs, as bidicts do (covered further below). Portability =========== - Python 2 vs. Python 3 - As affects bidict, mostly :class:`dict` API changes, but also functions like :func:`zip`, :func:`map`, :func:`filter`, etc. - See the :meth:`~object.__ne__` gotcha for Python 2 above. - Borrowing methods from other classes: In Python 2, must grab the ``.im_func`` / ``__func__`` attribute off the borrowed method to avoid getting ``TypeError: unbound method ...() must be called with ... instance as first argument`` See the `implementation `__ of :class:`~bidict.FrozenOrderedBidict`. - CPython vs. PyPy - gc / weakref - primitives' identities, nan, etc. - https://bitbucket.org/pypy/pypy/src/dafacc4/pypy/doc/cpython_differences.rst?mode=view - Hence ``test_no_reference_cycles()`` in `test_properties.py `__ is skipped on PyPy. Other interesting stuff in the standard library =============================================== - :mod:`reprlib` and :func:`reprlib.recursive_repr` (but not needed for bidict because there's no way to insert a bidict into itself) - :func:`operator.methodcaller` - :attr:`platform.python_implementation` - See :ref:`addendum:Missing bidicts in Stdlib!` Tools ===== See the :ref:`Thanks ` page for some of the fantastic tools for software verification, performance, code quality, etc. that bidict has provided an excuse to play with and learn. bidict-0.18.2/docs/other-bidict-types.rst0000664000372000037200000003011413535200701021076 0ustar travistravis00000000000000Other ``bidict`` Types ====================== Now that we've covered :doc:`basic-usage` with the :class:`bidict.bidict` type, let's look at some other bidirectional mapping types. .. testsetup:: from bidict import bidict from bidict.compat import Mapping, MutableMapping Bidict Types Diagram -------------------- .. image:: _static/bidict-types-diagram.png :target: _static/bidict-types-diagram.png :alt: bidict types diagram All bidirectional mapping types that :mod:`bidict` provides are subclasses of :class:`bidict.BidirectionalMapping`. This abstract base class extends :class:`collections.abc.Mapping` by adding the ":attr:`~bidict.BidirectionalMapping.inverse`" :obj:`~abc.abstractproperty`. [#fn-subclasshook]_ .. [#fn-subclasshook] In fact, any :class:`collections.abc.Mapping` that provides an ``inverse`` attribute will be considered a virtual subclass of :class:`bidict.BidirectionalMapping` :meth:`automatically `, enabling interoperability with external implementations. As you may have noticed, :class:`bidict.bidict` is also a :class:`collections.abc.MutableMapping`. But :mod:`bidict` provides immutable bidirectional mapping types as well. :class:`~bidict.frozenbidict` ----------------------------- :class:`~bidict.frozenbidict` is an immutable, hashable bidirectional mapping type. As you would expect, attempting to mutate a :class:`~bidict.frozenbidict` causes an error: .. doctest:: >>> from bidict import frozenbidict >>> f = frozenbidict({'H': 'hydrogen'}) >>> f['C'] = 'carbon' Traceback (most recent call last): ... TypeError: ... :class:`~bidict.frozenbidict` also implements :class:`collections.abc.Hashable`, so it's suitable for insertion into sets or other mappings: .. doctest:: >>> my_set = {f} # not an error >>> my_dict = {f: 1} # also not an error See the :class:`~bidict.frozenbidict` API documentation for more information. :class:`~bidict.OrderedBidict` ------------------------------ :class:`bidict.OrderedBidict` is a mutable :class:`~bidict.BidirectionalMapping` that preserves the order in which its items are inserted. It's like a bidirectional version of :class:`collections.OrderedDict`. .. doctest:: >>> from bidict import OrderedBidict >>> element_by_symbol = OrderedBidict([ ... ('H', 'hydrogen'), ('He', 'helium'), ('Li', 'lithium')]) >>> element_by_symbol.inverse OrderedBidict([('hydrogen', 'H'), ('helium', 'He'), ('lithium', 'Li')]) >>> first, second, third = element_by_symbol.values() >>> first, second, third ('hydrogen', 'helium', 'lithium') >>> # Insert an additional item and verify it now comes last: >>> element_by_symbol['Be'] = 'beryllium' >>> last_item = list(element_by_symbol.items())[-1] >>> last_item ('Be', 'beryllium') Additional functionality modeled after :class:`~collections.OrderedDict` is provided as well: .. doctest:: >>> element_by_symbol.popitem(last=True) # Remove the last item ('Be', 'beryllium') >>> element_by_symbol.popitem(last=False) # Remove the first item ('H', 'hydrogen') >>> # Re-adding hydrogen after it's been removed moves it to the end: >>> element_by_symbol['H'] = 'hydrogen' >>> element_by_symbol OrderedBidict([('He', 'helium'), ('Li', 'lithium'), ('H', 'hydrogen')]) >>> # But there's also a `move_to_end` method just for this purpose: >>> element_by_symbol.move_to_end('Li') >>> element_by_symbol OrderedBidict([('He', 'helium'), ('H', 'hydrogen'), ('Li', 'lithium')]) >>> element_by_symbol.move_to_end('H', last=False) # move to front >>> element_by_symbol OrderedBidict([('H', 'hydrogen'), ('He', 'helium'), ('Li', 'lithium')]) As with :class:`~collections.OrderedDict`, updating an existing item preserves its position in the order: .. doctest:: >>> element_by_symbol['He'] = 'updated in place!' >>> element_by_symbol OrderedBidict([('H', 'hydrogen'), ('He', 'updated in place!'), ('Li', 'lithium')]) Collapsing overwrites ##################### When setting an item in an ordered bidict whose key duplicates that of an existing item, and whose value duplicates that of a *different* existing item, the existing item whose *value* is duplicated will be dropped, and the existing item whose *key* is duplicated will have its value overwritten in place: .. doctest:: >>> o = OrderedBidict([(1, 2), (3, 4), (5, 6), (7, 8)]) >>> o.forceput(3, 8) # item with duplicated value (7, 8) is dropped... >>> o # and the item with duplicated key (3, 4) is updated in place: OrderedBidict([(1, 2), (3, 8), (5, 6)]) >>> # (3, 8) took the place of (3, 4), not (7, 8) >>> o = OrderedBidict([(1, 2), (3, 4), (5, 6), (7, 8)]) # as before >>> o.forceput(5, 2) # another example >>> o OrderedBidict([(3, 4), (5, 2), (7, 8)]) >>> # (5, 2) took the place of (5, 6), not (1, 2) .. _eq-order-insensitive: :meth:`~bidict.OrderedBidict.__eq__` is order-insensitive ######################################################### To ensure that equality of bidicts is transitive (and to uphold the `Liskov substitution principle `__), equality tests between an ordered bidict and other mappings are always order-insensitive: .. doctest:: >>> b = bidict([('one', 1), ('two', 2)]) >>> o1 = OrderedBidict([('one', 1), ('two', 2)]) >>> o2 = OrderedBidict([('two', 2), ('one', 1)]) >>> b == o1 True >>> b == o2 True >>> o1 == o2 True For order-sensitive equality tests, use :meth:`~bidict.FrozenOrderedBidict.equals_order_sensitive`: .. doctest:: >>> o1.equals_order_sensitive(o2) False >>> from collections import OrderedDict >>> od = OrderedDict(o2) >>> o1.equals_order_sensitive(od) False Note that this differs from the behavior of :class:`collections.OrderedDict`\'s ``__eq__()``, by recommendation of Raymond Hettinger (the author) himself. He later said that making OrderedDict's ``__eq__()`` intransitive was a mistake. What if my Python version has order-preserving dicts? ##################################################### In PyPy as well as CPython ≥ 3.6, :class:`dict` preserves insertion order. If you are using one of these versions of Python, you may wonder whether you can get away with using a regular :class:`bidict.bidict` in places where you need an insertion order-preserving bidirectional mapping. In general the answer is no, particularly if you need to be able to change existing associations in the bidirectional mapping while preserving order correctly. Consider this example using a regular :class:`~bidict.bidict` with an order-preserving :class:`dict` version of Python: .. doctest:: :pyversion: >= 3.6 >>> b = bidict([(1, -1), (2, -2), (3, -3)]) >>> b[2] = 'UPDATED' >>> b bidict({1: -1, 2: 'UPDATED', 3: -3}) >>> b.inverse # oops: bidict({-1: 1, -3: 3, 'UPDATED': 2}) When the value associated with the key ``2`` was changed, the corresponding item stays in place in the forward mapping, but moves to the end of the inverse mapping. Since regular :class:`~bidict.bidict`\s provide no guarantees about order preservation (which allows for a more efficient implementation), non-order-preserving behavior (as in the example above) is exactly what you get. If you never mutate a bidict (or are even using a :class:`~bidict.frozenbidict`) and you're running a version of Python with order-preserving :class:`dict`\s, then you'll find that the order of the items in your bidict and its inverse happens to be preserved. However, you won't get the additional order-specific APIs (such as :meth:`~bidict.OrderedBidict.move_to_end`, :meth:`~bidict.OrderedBidict.equals_order_sensitive`, and :meth:`~bidict.OrderedBidict.__reversed__` – indeed the lack of a ``dict.__reversed__`` API is what stops us from making :class:`~bidict.FrozenOrderedBidict` an alias of :class:`~bidict.frozenbidict` on dict-order-preserving Pythons, as this would mean :meth:`FrozenOrderedBidict.__reversed__() ` would have to be O(n) in space complexity). If you need order-preserving behavior guaranteed, then :class:`~bidict.OrderedBidict` is your best choice. :class:`~bidict.FrozenOrderedBidict` ------------------------------------ :class:`~bidict.FrozenOrderedBidict` is an immutable ordered bidict type. It's like an :class:`~bidict.OrderedBidict` without the mutating APIs, or equivalently like an order-preserving :class:`~bidict.frozenbidict`. :func:`~bidict.namedbidict` --------------------------- :func:`bidict.namedbidict`, inspired by :func:`collections.namedtuple`, allows you to easily generate a new bidirectional mapping type with custom attribute-based access to forward and inverse mappings: .. doctest:: >>> from bidict import namedbidict >>> ElementMap = namedbidict('ElementMap', 'symbol', 'name') >>> noble_gases = ElementMap(He='helium') >>> noble_gases.name_for['He'] 'helium' >>> noble_gases.symbol_for['helium'] 'He' >>> noble_gases.name_for['Ne'] = 'neon' >>> del noble_gases.symbol_for['helium'] >>> noble_gases ElementMap({'Ne': 'neon'}) Using the *base_type* keyword arg – whose default value is :class:`bidict.bidict` – you can override the bidict type used as the base class, allowing the creation of e.g. a named frozenbidict type: .. doctest:: >>> ElMap = namedbidict('ElMap', 'symbol', 'name', base_type=frozenbidict) >>> noble = ElMap(He='helium') >>> noble.symbol_for['helium'] 'He' >>> hash(noble) is not 'an error' True >>> noble['C'] = 'carbon' # mutation fails Traceback (most recent call last): ... TypeError: ... Polymorphism ------------ (Or: ABCs ftw!) You may be tempted to write something like ``isinstance(obj, dict)`` to check whether ``obj`` is a :class:`~collections.abc.Mapping`. However, this check is too specific, and will fail for many types that implement the :class:`~collections.abc.Mapping` interface: .. doctest:: :pyversion: >= 3.3 >>> from collections import ChainMap >>> issubclass(ChainMap, dict) False The same is true for all the bidict types: .. doctest:: >>> issubclass(bidict, dict) False The proper way to check whether an object is a :class:`~collections.abc.Mapping` is to use the abstract base classes (ABCs) from the :mod:`collections` module that are provided for this purpose: .. doctest:: :pyversion: >= 3.3 >>> issubclass(ChainMap, Mapping) True >>> isinstance(bidict(), Mapping) True Also note that the proper way to check whether an object is an (im)mutable mapping is to use the :class:`~collections.abc.MutableMapping` ABC: .. doctest:: >>> from bidict import BidirectionalMapping >>> def is_immutable_bimap(obj): ... return (isinstance(obj, BidirectionalMapping) ... and not isinstance(obj, MutableMapping)) >>> is_immutable_bimap(bidict()) False >>> is_immutable_bimap(frozenbidict()) True Checking for ``isinstance(obj, frozenbidict)`` is too specific and could fail in some cases. For example, :class:`~bidict.FrozenOrderedBidict` is an immutable mapping but it does not subclass :class:`~bidict.frozenbidict`: .. doctest:: >>> from bidict import FrozenOrderedBidict >>> obj = FrozenOrderedBidict() >>> is_immutable_bimap(obj) True >>> isinstance(obj, frozenbidict) False Besides the above, there are several other collections ABCs whose interfaces are implemented by various bidict types. Have a look through the :mod:`collections.abc` documentation if you're interested. One thing you might notice is that there is no ``Ordered`` or ``OrderedMapping`` ABC. However, Python 3.6 introduced the :class:`collections.abc.Reversible` ABC. Since being reversible implies having an ordering, you could check for reversibility instead. For example: .. doctest:: :pyversion: >= 3.6 >>> from collections.abc import Reversible >>> def is_reversible_mapping(cls): ... return issubclass(cls, Reversible) and issubclass(cls, Mapping) ... >>> is_reversible_mapping(OrderedBidict) True >>> is_reversible_mapping(OrderedDict) True For more you can do with :mod:`bidict`, check out :doc:`extending` next. bidict-0.18.2/docs/other-functionality.rst0000664000372000037200000000202413535200701021365 0ustar travistravis00000000000000Other Functionality =================== :func:`bidict.inverted` ----------------------- bidict provides the :class:`~bidict.inverted` iterator to help you get inverse items from various types of objects. Pass in a mapping to get the inverse mapping: .. doctest:: >>> from bidict import inverted >>> it = inverted({1: 'one'}) >>> {k: v for (k, v) in it} {'one': 1} ...an iterable of pairs to get the pairs' inverses: .. doctest:: >>> list(inverted([(1, 'one'), (2, 'two')])) [('one', 1), ('two', 2)] >>> list(inverted((i*i, i) for i in range(2, 5))) [(2, 4), (3, 9), (4, 16)] ...or any object implementing an ``__inverted__`` method, which objects that already know their own inverses (such as bidicts) can implement themselves: .. testsetup:: from bidict import bidict, OrderedBidict .. doctest:: >>> dict(inverted(bidict({1: 'one'}))) {'one': 1} >>> list(inverted(OrderedBidict([(2, 4), (3, 9)]))) [(4, 2), (9, 3)] Perhaps you'd be interested in taking a look at the :doc:`addendum` next. bidict-0.18.2/docs/thanks.rst0000664000372000037200000000336213535200701016654 0ustar travistravis00000000000000Thanks ------ Bidict has benefited from the assistance of many people and projects. People ====== .. Remember to update "__credits__" in ../bidict/metadata.py when this is updated - Gregory Ewing for the name. - Terry Reedy for suggesting the slice syntax (it was fun while it lasted). - Raymond Hettinger for suggesting namedbidict and pointing out various caveats. - Francis Carr for the idea of storing the inverse bidict. - Adopt Pytest Month 2015 for choosing bidict, Tom Viner for being bidict's Adopt Pytest helper for the month, and Brianna Laugher for coordinating. - Daniel Pope for suggestions, code reviews, and design discussion. - David Turner for code reviews and design discussion. - Michael Arntzenius for design discussion. - Jozef Knaperek for the bugfix. - Bernát Gábor for pyproject.toml support. - Muhammad Faisal for the `CC BY 3.0 `__ `icon `__ that bidict's logo was derived from. - Richard Sanger and Zeyi Wang for reporting bugs. Projects ======== - `Tidelift `__ - `Pytest `__ - `Coverage `__ - `hypothesis `__ - `pytest-benchmark `__ - `Sphinx `__ - `Travis `__ - `Readthedocs `__ - `Codecov `__ - `lgtm `__ - `Pylint `__ - `Flake8 `__ - `Alabaster `__ - `setuptools_scm `__ bidict-0.18.2/pyproject.toml0000664000372000037200000000017313535200701016613 0ustar travistravis00000000000000[build-system] requires = [ "setuptools", "wheel", "setuptools_scm", ] build-backend = "setuptools.build_meta" bidict-0.18.2/pytest.ini0000664000372000037200000000136513535200701015734 0ustar travistravis00000000000000[pytest] testpaths = bidict tests docs addopts = --ignore=docs/conf.py --verbose --doctest-modules --doctest-glob=tests/*.txt # pytest's doctest support doesn't support Sphinx extensions # (see https://www.sphinx-doc.org/en/latest/usage/extensions/doctest.html) # so †est the code in the Sphinx docs using Sphinx rather than pytest # (i.e. leave the next line commented out): # --doctest-glob=docs/*.rst # Only add the following from the docs for the sake of pytest's coverage report: --doctest-glob=docs/extending.rst --benchmark-columns=mean,stddev,outliers --benchmark-group-by=func --benchmark-save-data # --benchmark-autosave # --benchmark-compare # --hypothesis-show-statistics doctest_optionflags = IGNORE_EXCEPTION_DETAIL ELLIPSIS bidict-0.18.2/run_tests.py0000775000372000037200000000162713535200701016307 0ustar travistravis00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. # First run all tests that pytest discovers. """Run all tests.""" from functools import reduce from operator import or_ from pytest import main as pytest_main from sphinx.cmd.build import main as sphinx_main TEST_FUNCS = [ pytest_main, # pytest's doctest support doesn't support Sphinx extensions # (see https://www.sphinx-doc.org/en/latest/usage/extensions/doctest.html) # so †est the code in the Sphinx docs using Sphinx's own doctest support. lambda: sphinx_main('-b doctest -d docs/_build/doctrees docs docs/_build/doctest'.split()), ] exit(reduce(or_, (f() for f in TEST_FUNCS))) bidict-0.18.2/setup.cfg0000664000372000037200000000027613535200730015526 0ustar travistravis00000000000000[bdist_wheel] universal = 1 [flake8] ignore = E126,E128,E266,E265,E731,W504 max-line-length = 100 [pydocstyle] add_ignore = D105,D205,D400,D401,D402 [egg_info] tag_build = tag_date = 0 bidict-0.18.2/setup.py0000664000372000037200000001130013535200701015403 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """A setuptools-based setup module. Ref: https://github.com/pypa/sampleproject/blob/master/setup.py """ from codecs import open as c_open from os.path import abspath, dirname, join from setuptools import setup CWD = abspath(dirname(__file__)) # Get bidict's package metadata from ./bidict/metadata.py. METADATA_PATH = join(CWD, 'bidict', 'metadata.py') try: from importlib.util import module_from_spec, spec_from_file_location except ImportError: # Python < 3.5 try: from importlib.machinery import SourceFileLoader except ImportError: # Python < 3.3 - treat as Python 2 (otherwise unsupported). from imp import load_source METADATA = load_source('metadata', METADATA_PATH) else: # Python 3.3 or 3.4 LOADER = SourceFileLoader('metadata', METADATA_PATH) METADATA = LOADER.load_module('metadata') # pylint: disable=deprecated-method else: SPEC = spec_from_file_location('metadata', METADATA_PATH) METADATA = module_from_spec(SPEC) SPEC.loader.exec_module(METADATA) with c_open(join(CWD, 'README.rst'), encoding='utf-8') as f: LONG_DESCRIPTION = f.read() # Manually keep these version pins in sync with those in .travis.yml and .pre-commit-config.yaml. SETUP_REQS = [ 'setuptools_scm < 4', ] SPHINX_REQS = [ 'Sphinx < 3', # Sphinx's docutils pin has no upper bound. Pin to 0.15.2 pending sphinx-doc/sphinx#6594. # (Pulling 0.15 previously broke "make doctest" with SyntaxError under Python 2.7.) 'docutils == 0.15.2', ] DOCS_REQS = SPHINX_REQS TEST_REQS = [ 'hypothesis < 5', 'py < 2', 'pytest < 6', 'pytest-benchmark >= 3.2.0, < 4', 'sortedcollections < 2', 'sortedcontainers < 3', # pytest's doctest support doesn't support Sphinx extensions # (https://www.sphinx-doc.org/en/latest/usage/extensions/doctest.html) # so †est the code in the Sphinx docs using Sphinx's own doctest support. DOCS_REQS, ] # Split out coverage from test requirements since it slows down the tests. COVERAGE_REQS = [ 'coverage < 5', 'pytest-cov < 3', ] # The following dependencies have a higher chance of suddenly causing CI to fail after updating # even between minor versions, so pin to currently-working minor versions. Upgrade to newer # minor versions manually to have a chance to fix any resulting breakage before it hits CI. FLAKE8_REQ = 'flake8 < 3.8' PYDOCSTYLE_REQ = 'pydocstyle < 3.1' PYLINT_REQS = [ # Pin to exact versions of Pylint and Astroid, which don't follow semver. # See https://github.com/PyCQA/astroid/issues/651#issuecomment-469021040 'pylint == 2.2.3', 'astroid == 2.1.0', ] LINT_REQS = [ FLAKE8_REQ, PYDOCSTYLE_REQ, ] + PYLINT_REQS DEV_REQS = SETUP_REQS + DOCS_REQS + TEST_REQS + COVERAGE_REQS + LINT_REQS + [ 'pre-commit < 2', 'tox < 4', ] EXTRAS_REQS = dict( docs=DOCS_REQS, test=TEST_REQS, coverage=COVERAGE_REQS, lint=LINT_REQS, dev=DEV_REQS, sphinx=SPHINX_REQS, flake8=[FLAKE8_REQ], pydocstyle=[PYDOCSTYLE_REQ], pylint=PYLINT_REQS, ) setup( name='bidict', use_scm_version={ 'version_scheme': 'guess-next-dev', 'local_scheme': 'dirty-tag', 'write_to': 'bidict/_version.py', }, author=METADATA.__author__, author_email=METADATA.__email__, description=METADATA.__description__, long_description=LONG_DESCRIPTION, keywords=METADATA.__keywords__, url=METADATA.__url__, license=METADATA.__license__, packages=['bidict'], zip_safe=False, # Don't zip. (We're zip-safe but prefer not to.) classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules', ], setup_requires=SETUP_REQS, # required so pip < 10 install works (no PEP-517/518 support) # for more details see https://www.python.org/dev/peps/pep-0518/#rationale tests_require=TEST_REQS, extras_require=EXTRAS_REQS, ) bidict-0.18.2/tests/0000775000372000037200000000000013535200730015042 5ustar travistravis00000000000000bidict-0.18.2/tests/__init__.py0000664000372000037200000000052713535200701017155 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """See http://doc.pytest.org/en/latest/pythonpath.html""" bidict-0.18.2/tests/conftest.py0000664000372000037200000000211313535200701017234 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Set up hypothesis.""" from os import getenv from hypothesis import HealthCheck, settings, unlimited MAX_EXAMPLES_DEFAULT = 200 NOCHECK_SLOW = (HealthCheck.too_slow,) PROFILE_DEFAULT = { 'max_examples': int(getenv('HYPOTHESIS_MAX_EXAMPLES') or MAX_EXAMPLES_DEFAULT), 'deadline': None, 'timeout': unlimited, # Enabling coverage slows down hypothesis. 'suppress_health_check': NOCHECK_SLOW if getenv('COVERAGE') else (), } PROFILE_MORE_EXAMPLES = dict( PROFILE_DEFAULT, max_examples=int(getenv('HYPOTHESIS_MAX_EXAMPLES') or MAX_EXAMPLES_DEFAULT * 10), suppress_health_check=NOCHECK_SLOW, ) settings.register_profile('default', **PROFILE_DEFAULT) settings.register_profile('more-examples', **PROFILE_MORE_EXAMPLES) settings.load_profile(getenv('HYPOTHESIS_PROFILE') or 'default') bidict-0.18.2/tests/properties/0000775000372000037200000000000013535200730017236 5ustar travistravis00000000000000bidict-0.18.2/tests/properties/__init__.py0000664000372000037200000000052713535200701021351 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """See http://doc.pytest.org/en/latest/pythonpath.html""" bidict-0.18.2/tests/properties/_strategies.py0000664000372000037200000002035313535200701022122 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Strategies for Hypothesis tests.""" import re from collections import OrderedDict from hypothesis import assume, strategies as st from bidict import IGNORE, OVERWRITE, RAISE, OrderedBidictBase, namedbidict from bidict.compat import ItemsView, PY2, izip from . import _types as t # pylint: disable=invalid-name DATA = st.data() RAND = st.randoms() BIDICT_TYPES = st.sampled_from(t.BIDICT_TYPES) MUTABLE_BIDICT_TYPES = st.sampled_from(t.MUTABLE_BIDICT_TYPES) FROZEN_BIDICT_TYPES = st.sampled_from(t.FROZEN_BIDICT_TYPES) ORDERED_BIDICT_TYPES = st.sampled_from(t.ORDERED_BIDICT_TYPES) MAPPING_TYPES = st.sampled_from(t.MAPPING_TYPES) NON_BIDICT_MAPPING_TYPES = st.sampled_from(t.NON_BIDICT_MAPPING_TYPES) ORDERED_MAPPING_TYPES = st.sampled_from(t.ORDERED_MAPPING_TYPES) HASHABLE_MAPPING_TYPES = st.sampled_from(t.HASHABLE_MAPPING_TYPES) DUP_POLICIES = st.sampled_from((IGNORE, OVERWRITE, RAISE)) DUP_POLICIES_DICT = st.fixed_dictionaries(dict( on_dup_key=DUP_POLICIES, on_dup_val=DUP_POLICIES, on_dup_kv=DUP_POLICIES, )) BOOLEANS = st.booleans() FLOATS = st.floats(allow_nan=False) INTS = st.integers() TEXT = st.text() NONE = st.none() IMMUTABLES = BOOLEANS | TEXT | NONE | INTS | FLOATS LISTS_MAX_SIZE = 10 LISTS_PAIRS = st.lists(st.tuples(IMMUTABLES, IMMUTABLES), max_size=LISTS_MAX_SIZE) NON_MAPPINGS = IMMUTABLES | LISTS_PAIRS IDENTIFIER_TYPE = TEXT if PY2: IDENTIFIER_TYPE = IDENTIFIER_TYPE.map(lambda x: x.encode('utf-8')) @st.composite def _lists_pairs_with_duplication(draw): # pylint: disable=too-many-locals n = draw(st.integers(min_value=3, max_value=LISTS_MAX_SIZE)) indexes = st.integers(min_value=0, max_value=n - 1) keys = draw(st.lists(IMMUTABLES, min_size=n, max_size=n)) vals = draw(st.lists(IMMUTABLES, min_size=n, max_size=n)) fwd = OrderedDict(izip(keys, vals)) inv = OrderedDict(izip(vals, keys)) which_to_dup = draw(RAND).choice((1, 2, 3)) should_dup_key = which_to_dup in (1, 3) should_dup_val = which_to_dup in (2, 3) should_add_dup_key = should_dup_key and len(fwd) < n should_add_dup_val = should_dup_val and len(inv) < n if not should_add_dup_key and not should_add_dup_val: return list(izip(keys, vals)) if should_add_dup_key: dup_key_idx = draw(indexes) added_key = keys[dup_key_idx] else: added_key = draw(IMMUTABLES) assume(added_key not in fwd) if should_add_dup_val: dup_val_idx = draw(indexes) if should_add_dup_key: assume(dup_val_idx != dup_key_idx) added_val = vals[dup_val_idx] else: added_val = draw(IMMUTABLES) assume(added_val not in inv) insert_idx = draw(indexes) keys.insert(insert_idx, added_key) vals.insert(insert_idx, added_val) return list(izip(keys, vals)) # pylint: disable=no-value-for-parameter LISTS_PAIRS_DUP = _lists_pairs_with_duplication() @st.composite def lists_pairs_nodup(draw, elements=IMMUTABLES, min_size=0, max_size=LISTS_MAX_SIZE): """Generate a list of pairs from the given elements with no duplication.""" n = draw(st.integers(min_value=min_size, max_value=max_size)) size_n_sets = st.sets(elements, min_size=n, max_size=n) keys = draw(size_n_sets) vals = draw(size_n_sets) return list(izip(keys, vals)) LISTS_PAIRS_NODUP = lists_pairs_nodup() LISTS_TEXT_PAIRS_NODUP = lists_pairs_nodup(elements=TEXT) # pylint: disable=dangerous-default-value @st.composite def bidicts(draw, bi_types=BIDICT_TYPES, init_items=LISTS_PAIRS_NODUP): """Generate bidicts.""" bi_cls = draw(bi_types) items = draw(init_items) bi = bi_cls(items) # Return the inverse bidict with 50% probability to increase coverage. return bi if draw(RAND).choice((True, False)) else bi.inv BIDICTS = bidicts() FROZEN_BIDICTS = bidicts(bi_types=FROZEN_BIDICT_TYPES) MUTABLE_BIDICTS = bidicts(bi_types=MUTABLE_BIDICT_TYPES) ORDERED_BIDICTS = bidicts(bi_types=ORDERED_BIDICT_TYPES) NAMEDBIDICT_VALID_NAME_PAT = re.compile('[A-z][A-z0-9_]*$') NAMEDBIDICT_NAMES = st.from_regex(NAMEDBIDICT_VALID_NAME_PAT, fullmatch=True) NAMEDBIDICT_3_NAMES = st.tuples( NAMEDBIDICT_NAMES, NAMEDBIDICT_NAMES, NAMEDBIDICT_NAMES, ) @st.composite def _namedbidict_types(draw, names=NAMEDBIDICT_3_NAMES, base_types=BIDICT_TYPES): typename, keyname, valname = draw(names) assume(keyname != valname) base_type = draw(base_types) return namedbidict(typename, keyname, valname, base_type=base_type) NAMEDBIDICT_TYPES = _namedbidict_types() @st.composite def _namedbidicts(draw, nb_types=NAMEDBIDICT_TYPES, init_items=LISTS_PAIRS_NODUP): nb_cls = draw(nb_types) items = draw(init_items) nb = nb_cls(items) # Return the inverse namedbidict with 50% probability to increase coverage. return nb if draw(RAND).choice((True, False)) else nb.inv NAMEDBIDICTS = _namedbidicts() _COMPARE_DICT_TYPE = object() _SAME_AS_BI_ITEMS = object() _SAME_AS_BI_ITEMS_DIFF_ORDER = object() @st.composite def _bidict_and_mapping_from_items( draw, bi_types=BIDICT_TYPES, map_types=MAPPING_TYPES, bi_items=LISTS_PAIRS_NODUP, map_items=_SAME_AS_BI_ITEMS, ): bi_cls = draw(bi_types) if map_types is _COMPARE_DICT_TYPE: map_cls = OrderedDict if issubclass(bi_cls, OrderedBidictBase) else dict else: map_cls = draw(map_types) bi_items_ = draw(bi_items) same_items = map_items in (_SAME_AS_BI_ITEMS, _SAME_AS_BI_ITEMS_DIFF_ORDER) if same_items: map_items_ = bi_items_[:] if map_items is _SAME_AS_BI_ITEMS_DIFF_ORDER: draw(RAND).shuffle(map_items_) assume(map_items_ != bi_items_) else: map_items_ = draw(map_items) b = bi_cls(bi_items_) m = map_cls(map_items_) if not same_items: assume(ItemsView(m) != ItemsView(b)) return b, m BIDICT_AND_MAPPING_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items() BIDICT_AND_MAPPING_FROM_DIFFERENT_ITEMS = _bidict_and_mapping_from_items( map_items=LISTS_PAIRS_NODUP, ) BIDICT_AND_COMPARE_DICT_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items( map_types=_COMPARE_DICT_TYPE, ) ORDERED_BIDICT_AND_ORDERED_DICT_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items( bi_types=ORDERED_BIDICT_TYPES, map_types=_COMPARE_DICT_TYPE, ) ORDERED_BIDICT_AND_ORDERED_MAPPING_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items( bi_types=ORDERED_BIDICT_TYPES, map_types=ORDERED_MAPPING_TYPES, ) HASHABLE_BIDICT_AND_MAPPING_FROM_SAME_ITEMS_NODUP = _bidict_and_mapping_from_items( bi_types=FROZEN_BIDICT_TYPES, map_types=HASHABLE_MAPPING_TYPES, ) ORDERED_BIDICT_AND_ORDERED_MAPPING_FROM_SAME_ITEMS_DIFF_ORDER = _bidict_and_mapping_from_items( bi_types=ORDERED_BIDICT_TYPES, map_types=ORDERED_MAPPING_TYPES, map_items=_SAME_AS_BI_ITEMS_DIFF_ORDER, ) NO_ARGS = st.just(()) IM_ARG = st.tuples(IMMUTABLES) LP_ARG = st.tuples(LISTS_PAIRS) TWO_IM_ARGS = st.tuples(IMMUTABLES, IMMUTABLES) ARGS_BY_METHOD = st.fixed_dictionaries({ # mutating # 0-arity (0, 'clear'): NO_ARGS, (0, 'popitem'): NO_ARGS, # 1-arity, an immutable atom (1, '__delitem__'): IM_ARG, (1, 'pop'): IM_ARG, (1, 'setdefault'): IM_ARG, (1, 'move_to_end'): IM_ARG, # 1-arity, a list of pairs (1, 'update'): LP_ARG, (1, 'forceupdate'): LP_ARG, # 2-arity (2, 'pop'): TWO_IM_ARGS, (2, 'setdefault'): TWO_IM_ARGS, (2, '__setitem__'): TWO_IM_ARGS, (2, 'put'): TWO_IM_ARGS, (2, 'forceput'): TWO_IM_ARGS, (2, 'move_to_end'): st.tuples(IMMUTABLES, BOOLEANS), # non-mutating # 0-arity (0, '__copy__'): NO_ARGS, (0, '__iter__'): NO_ARGS, (0, '__len__'): NO_ARGS, (0, 'copy'): NO_ARGS, (0, 'keys'): NO_ARGS, (0, 'items'): NO_ARGS, (0, 'values'): NO_ARGS, (0, 'iterkeys'): NO_ARGS, (0, 'iteritems'): NO_ARGS, (0, 'itervalues'): NO_ARGS, (0, 'viewkeys'): NO_ARGS, (0, 'viewitems'): NO_ARGS, (0, 'viewvalues'): NO_ARGS, # 1-arity (1, '__contains__'): IM_ARG, (1, '__getitem__'): IM_ARG, (1, 'get'): IM_ARG, }) bidict-0.18.2/tests/properties/_types.py0000664000372000037200000000316213535200701021113 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Types for Hypothoses tests.""" from collections import OrderedDict from bidict import bidict, OrderedBidict, frozenbidict, FrozenOrderedBidict, namedbidict from bidict.compat import ItemsView, KeysView, Mapping MyNamedBidict = namedbidict('MyNamedBidict', 'key', 'val') MyNamedFrozenBidict = namedbidict('MyNamedFrozenBidict', 'key', 'val', base_type=frozenbidict) MyNamedOrderedBidict = namedbidict('MyNamedOrderedBidict', 'key', 'val', base_type=OrderedBidict) MUTABLE_BIDICT_TYPES = (bidict, OrderedBidict, MyNamedBidict) FROZEN_BIDICT_TYPES = (frozenbidict, FrozenOrderedBidict, MyNamedFrozenBidict) ORDERED_BIDICT_TYPES = (OrderedBidict, FrozenOrderedBidict, MyNamedOrderedBidict) BIDICT_TYPES = tuple(set(MUTABLE_BIDICT_TYPES + FROZEN_BIDICT_TYPES + ORDERED_BIDICT_TYPES)) class _FrozenDict(KeysView, Mapping): def __init__(self, *args, **kw): # pylint: disable=super-init-not-called self._mapping = dict(*args, **kw) def __getitem__(self, key): return self._mapping[key] def __hash__(self): return ItemsView(self._mapping)._hash() # pylint: disable=protected-access NON_BIDICT_MAPPING_TYPES = (dict, OrderedDict, _FrozenDict) MAPPING_TYPES = BIDICT_TYPES + NON_BIDICT_MAPPING_TYPES ORDERED_MAPPING_TYPES = ORDERED_BIDICT_TYPES + (OrderedDict,) HASHABLE_MAPPING_TYPES = FROZEN_BIDICT_TYPES + (_FrozenDict,) bidict-0.18.2/tests/properties/test_properties.py0000664000372000037200000004103413535200701023043 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Property-based tests using https://hypothesis.readthedocs.io.""" import gc import pickle from functools import reduce from copy import deepcopy from collections import OrderedDict from weakref import ref import pytest from hypothesis import HealthCheck, given, settings from bidict import BidictException, OrderedBidictBase, namedbidict, inverted from bidict.compat import ( PY2, PYPY, collections_abc as c, iteritems, izip, viewkeys, viewitems, ) from bidict._util import _iteritems_args_kw # pylint: disable=protected-access from . import _strategies as st # pylint: disable=invalid-name @given(st.BIDICTS, st.NON_MAPPINGS) def test_unequal_to_non_mapping(bi, not_a_mapping): """Bidicts and their inverses should be unequal to non-mappings.""" assert bi != not_a_mapping assert bi.inv != not_a_mapping assert not bi == not_a_mapping assert not bi.inv == not_a_mapping @given(st.BIDICT_AND_MAPPING_FROM_DIFFERENT_ITEMS) @settings(suppress_health_check=[HealthCheck.too_slow]) def test_unequal_to_mapping_with_different_items(bidict_and_mapping_from_different_items): """Bidicts should be unequal to mappings containing different items.""" bi, mapping = bidict_and_mapping_from_different_items assert bi != mapping assert not bi == mapping @given(st.BIDICT_AND_MAPPING_FROM_SAME_ITEMS_NODUP) def test_equal_to_mapping_with_same_items(bidict_and_mapping_from_same_items_nodup): """Bidicts should be equal to mappings created from the same non-duplicating items. The bidict's inverse and the mapping's inverse should also be equal. """ bi, mapping = bidict_and_mapping_from_same_items_nodup assert bi == mapping assert not bi != mapping mapping_inv = OrderedDict((v, k) for (k, v) in iteritems(mapping)) assert bi.inv == mapping_inv assert not bi.inv != mapping_inv @given(st.HASHABLE_BIDICT_AND_MAPPING_FROM_SAME_ITEMS_NODUP) def test_equal_hashables_have_same_hash(hashable_bidict_and_mapping): """Hashable bidicts and hashable mappings that are equal should hash to the same value.""" bi, mapping = hashable_bidict_and_mapping assert bi == mapping assert hash(bi) == hash(mapping) @given(st.ORDERED_BIDICT_AND_ORDERED_MAPPING_FROM_SAME_ITEMS_NODUP) def test_equals_order_sensitive(ob_and_om): """Ordered bidicts should be order-sensitive-equal to ordered mappings with same nondup items. The bidict's inverse and the ordered mapping's inverse should also be order-sensitive-equal. """ ob, om = ob_and_om assert ob.equals_order_sensitive(om) om_inv = OrderedDict((v, k) for (k, v) in iteritems(om)) assert ob.inv.equals_order_sensitive(om_inv) @given(st.ORDERED_BIDICT_AND_ORDERED_MAPPING_FROM_SAME_ITEMS_DIFF_ORDER) def test_unequal_order_sensitive_same_items_different_order(ob_and_om): """Ordered bidicts should be order-sensitive-unequal to ordered mappings of diff-ordered items. Where both were created from the same items where no key or value was duplicated, but the items were ordered differently. The bidict's inverse and the ordered mapping's inverse should also be order-sensitive-unequal. """ ob, om = ob_and_om assert not ob.equals_order_sensitive(om) om_inv = OrderedDict((v, k) for (k, v) in iteritems(om)) assert not ob.inv.equals_order_sensitive(om_inv) @given(st.ORDERED_BIDICTS, st.NON_MAPPINGS) def test_unequal_order_sensitive_non_mapping(ob, not_a_mapping): """Ordered bidicts should be order-sensitive-unequal to ordered mappings of diff-ordered items. Where both were created from the same items where no key or value was duplicated, but the items were ordered differently. The bidict's inverse and the ordered mapping's inverse should also be order-sensitive-unequal. """ assert not ob.equals_order_sensitive(not_a_mapping) assert not ob.inv.equals_order_sensitive(not_a_mapping) @given(st.BIDICTS) def test_bijectivity(bi): """b[k] == v <==> b.inv[v] == k""" for b in (bi, bi.inv): assert all(b.inv[v] == k for (k, v) in iteritems(b)) @given(st.BIDICT_AND_COMPARE_DICT_FROM_SAME_ITEMS_NODUP, st.ARGS_BY_METHOD) def test_consistency_after_method_call(bi_and_cmp_dict, args_by_method): """A bidict should be left in a consistent state after calling any method, even if it raises.""" # pylint: disable=too-many-locals bi_orig, cmp_dict_orig = bi_and_cmp_dict for (_, methodname), args in iteritems(args_by_method): if not hasattr(bi_orig, methodname): continue bi = bi_orig.copy() method = getattr(bi, methodname) try: result = method(*args) except (KeyError, BidictException) as exc: # Call should fail clean, i.e. bi should be in the same state it was before the call. assertmsg = '%r did not fail clean: %r' % (method, exc) assert bi == bi_orig, assertmsg assert bi.inv == bi_orig.inv, assertmsg else: # Should get the same result as calling the same method on the compare-to dict. cmp_dict = cmp_dict_orig.copy() cmp_dict_meth = getattr(cmp_dict, methodname, None) if cmp_dict_meth: cmp_result = cmp_dict_meth(*args) if isinstance(cmp_result, c.Iterable): coll = list if isinstance(bi, OrderedBidictBase) else set result = coll(result) cmp_result = coll(cmp_result) assert result == cmp_result, 'methodname=%s, args=%r' % (methodname, args) # Whether the call failed or succeeded, bi should pass consistency checks. assert len(bi) == sum(1 for _ in iteritems(bi)) assert len(bi.inv) == sum(1 for _ in iteritems(bi.inv)) assert bi == dict(bi) assert bi.inv == dict(bi.inv) assert bi == OrderedDict((k, v) for (v, k) in iteritems(bi.inv)) assert bi.inv == OrderedDict((v, k) for (k, v) in iteritems(bi)) @given(st.MUTABLE_BIDICTS, st.LISTS_PAIRS_DUP, st.DUP_POLICIES_DICT) def test_putall_same_as_put_for_each_item(bi, items, dup_policies): """*bi.putall(items) <==> for i in items: bi.put(i)* for all duplication policies.""" check = bi.copy() expect = bi.copy() checkexc = None expectexc = None for (key, val) in items: try: expect.put(key, val, **dup_policies) except BidictException as exc: expectexc = type(exc) expect = bi # Bulk updates fail clean -> roll back to original state. break try: check.putall(items, **dup_policies) except BidictException as exc: checkexc = type(exc) assert checkexc == expectexc assert check == expect assert check.inv == expect.inv @given(st.BIDICT_AND_COMPARE_DICT_FROM_SAME_ITEMS_NODUP) def test_iter(bi_and_cmp_dict): """:meth:`bidict.BidictBase.__iter__` should yield all the keys in a bidict.""" bi, cmp_dict = bi_and_cmp_dict assert set(bi) == viewkeys(cmp_dict) @given(st.ORDERED_BIDICT_AND_ORDERED_DICT_FROM_SAME_ITEMS_NODUP) def test_orderedbidict_iter(ob_and_od): """Ordered bidict __iter__ should yield all the keys in an ordered bidict in the right order.""" ob, od = ob_and_od assert all(i == j for (i, j) in izip(ob, od)) @given(st.ORDERED_BIDICT_AND_ORDERED_DICT_FROM_SAME_ITEMS_NODUP) def test_orderedbidict_reversed(ob_and_od): """:meth:`bidict.OrderedBidictBase.__reversed__` should yield all the keys in an ordered bidict in the reverse-order they were inserted. """ ob, od = ob_and_od assert all(i == j for (i, j) in izip(reversed(ob), reversed(od))) @given(st.FROZEN_BIDICTS) def test_frozenbidicts_hashable(bi): """Frozen bidicts can be hashed and inserted into sets and mappings.""" # Nothing to assert; making sure these calls don't raise is sufficient. # pylint: disable=pointless-statement hash(bi) {bi} {bi: bi} @pytest.mark.skipif(not PY2, reason='iter* methods only defined on Python 2') @given(st.BIDICTS) def test_iterkeys_itervals_iteritems(bi): """Bidicts' iter* methods should work as expected.""" assert set(bi.iterkeys()) == bi.viewkeys() assert set(bi.itervalues()) == bi.viewvalues() assert set(bi.iteritems()) == bi.viewitems() @pytest.mark.skipif(not PY2, reason='iter* methods only defined on Python 2') @given(st.ORDERED_BIDICTS) def test_orderedbidict_iterkeys_itervals_iteritems(ob): """Ordered bidicts' iter* methods should work as expected.""" assert list(ob.iterkeys()) == ob.keys() assert list(ob.itervalues()) == ob.values() assert list(ob.iteritems()) == ob.items() @given(st.st.tuples(st.IDENTIFIER_TYPE, st.IDENTIFIER_TYPE, st.IDENTIFIER_TYPE)) def test_namedbidict_raises_on_invalid_name(names): """:func:`bidict.namedbidict` should raise if given invalid names.""" typename, keyname, valname = names try: namedbidict(typename, keyname, valname) except ValueError: # Either one of the names was invalid, or the keyname and valname were not distinct. assert not all(map(st.NAMEDBIDICT_VALID_NAME_PAT.match, names)) or keyname == valname @given(st.NAMEDBIDICT_3_NAMES, st.NON_BIDICT_MAPPING_TYPES) def test_namedbidict_raises_on_invalid_base_type(names, invalid_base_type): """:func:`bidict.namedbidict` should raise if given a non-bidict base_type.""" with pytest.raises(TypeError): namedbidict(*names, base_type=invalid_base_type) @given(st.NAMEDBIDICTS) def test_namedbidict(nb): """Test :func:`bidict.namedbidict` custom accessors.""" valfor = getattr(nb, nb._valname + '_for') # pylint: disable=protected-access keyfor = getattr(nb, nb._keyname + '_for') # pylint: disable=protected-access assert all(valfor[key] == val for (key, val) in iteritems(nb)) assert all(keyfor[val] == key for (key, val) in iteritems(nb)) # The same custom accessors should work on the inverse. inv = nb.inv valfor = getattr(inv, nb._valname + '_for') # pylint: disable=protected-access keyfor = getattr(inv, nb._keyname + '_for') # pylint: disable=protected-access assert all(valfor[key] == val for (key, val) in iteritems(nb)) assert all(keyfor[val] == key for (key, val) in iteritems(nb)) @given(st.BIDICTS) def test_bidict_isinv_getstate(bi): """All bidicts should provide ``_isinv`` and ``__getstate__`` (or else they won't fully work as a *base_type* for :func:`namedbidict`). """ # Nothing to assert; making sure these calls don't raise is sufficient. # pylint: disable=pointless-statement bi._isinv # pylint: disable=pointless-statement,protected-access bi.__getstate__() # pylint: disable=pointless-statement # Skip this test on PyPy where reference counting isn't used to free objects immediately. See: # https://bitbucket.org/pypy/pypy/src/dafacc4/pypy/doc/cpython_differences.rst?mode=view # "It also means that weak references may stay alive for a bit longer than expected." @pytest.mark.skipif(PYPY, reason='objects with 0 refcount are not freed immediately on PyPy') @given(bi_cls=st.BIDICT_TYPES) def test_refcycle_bidict_inverse(bi_cls): """When you release your last strong reference to a bidict, there are no remaining strong references to it (e.g. no reference cycle was created between it and its inverse) allowing the memory to be reclaimed immediately. """ gc.disable() try: bi = bi_cls() weak = ref(bi) assert weak() is not None del bi assert weak() is None finally: gc.enable() # See comment about skipping `test_refcycle_bidict_inverse` above. @pytest.mark.skipif(PYPY, reason='objects with 0 refcount are not freed immediately on PyPy') @given(ob_cls=st.ORDERED_BIDICT_TYPES, init_items=st.LISTS_PAIRS_NODUP) def test_refcycle_orderedbidict_nodes(ob_cls, init_items): """When you release your last strong reference to an ordered bidict, the refcount of each of its internal nodes drops to 0 allowing the memory to be reclaimed immediately. """ gc.disable() try: some_ordered_bidict = ob_cls(init_items) # On Python 2, list comprehension references leak to enclosing scope -> use reduce instead: node_weakrefs = reduce( lambda acc, node: acc + [node], map(ref, some_ordered_bidict._fwdm.values()), # pylint: disable=protected-access [] ) assert all(r() is not None for r in node_weakrefs) del some_ordered_bidict assert all(r() is None for r in node_weakrefs) finally: gc.enable() @given(bi_cls=st.BIDICT_TYPES) def test_slots(bi_cls): """See https://docs.python.org/3/reference/datamodel.html#notes-on-using-slots.""" stop_at = {object} if PY2: stop_at.update({c.Mapping, c.MutableMapping}) # These don't define __slots__ in Python 2. cls_by_slot = {} for cls in bi_cls.__mro__: if cls in stop_at: break slots = cls.__dict__.get('__slots__') assert slots is not None, 'Expected %r to define __slots__' % cls for slot in slots: seen_at = cls_by_slot.get(slot) assert not seen_at, '%r repeats slot %r declared first by %r' % (seen_at, slot, cls) cls_by_slot[slot] = cls @given(st.BIDICTS) def test_inv_aliases_inverse(bi): """bi.inv should alias bi.inverse.""" assert bi.inverse is bi.inv assert bi.inv.inverse is bi.inverse.inv @given(st.BIDICTS) def test_pickle_roundtrips(bi): """A bidict should equal the result of unpickling its pickle.""" dumps_args = {} # Pickling ordered bidicts in Python 2 requires a higher (non-default) protocol version. if PY2 and isinstance(bi, OrderedBidictBase): dumps_args['protocol'] = 2 pickled = pickle.dumps(bi, **dumps_args) roundtripped = pickle.loads(pickled) assert roundtripped is roundtripped.inv.inv assert roundtripped == bi assert roundtripped.inv == bi.inv assert roundtripped.inv.inv == bi.inv.inv @given(st.BIDICTS) def test_deepcopy(bi): """A bidict should equal its deepcopy.""" cp = deepcopy(bi) assert cp is not bi assert cp.inv.inv is cp assert cp.inv.inv is not bi assert bi == cp assert bi.inv == cp.inv def test_iteritems_args_kw_raises_on_too_many_args(): """:func:`bidict._iteritems_args_kw` should raise if given too many arguments.""" with pytest.raises(TypeError): _iteritems_args_kw('too', 'many', 'args') @given(st.LISTS_PAIRS, st.lists_pairs_nodup(elements=st.TEXT, min_size=0)) # pylint: disable=E1120 def test_iteritems_args_kw(arg0_pairs, kw_pairs): """:func:`bidict._iteritems_args_kw` should work correctly.""" assert list(_iteritems_args_kw(arg0_pairs)) == list(arg0_pairs) assert list(_iteritems_args_kw(OrderedDict(kw_pairs))) == list(kw_pairs) kwdict = dict(kw_pairs) # Create an iterator over both arg0_pairs and kw_pairs. arg0_kw_items = _iteritems_args_kw(arg0_pairs, **kwdict) # Consume the initial (arg0) pairs of the iterator, checking they match arg0. assert all(check == expect for (check, expect) in izip(arg0_kw_items, arg0_pairs)) # Consume the remaining (kw) pairs of the iterator, checking they match kw. assert all(kwdict[k] == v for (k, v) in arg0_kw_items) with pytest.raises(StopIteration): next(arg0_kw_items) @given(st.LISTS_PAIRS) def test_inverted_pairs(pairs): """:func:`bidict.inverted` should yield the inverses of a list of pairs.""" inv = [(v, k) for (k, v) in pairs] assert list(inverted(pairs)) == inv assert list(inverted(inverted(pairs))) == pairs @given(st.BIDICT_AND_COMPARE_DICT_FROM_SAME_ITEMS_NODUP) def test_inverted_bidict(bi_and_cmp_dict): """:func:`bidict.inverted` should yield the inverse items of a bidict.""" bi, cmp_dict = bi_and_cmp_dict cmp_dict_inv = OrderedDict((v, k) for (k, v) in iteritems(cmp_dict)) assert set(inverted(bi)) == viewitems(cmp_dict_inv) == viewitems(bi.inv) assert set(inverted(inverted(bi))) == viewitems(cmp_dict) == viewitems(bi.inv.inv) @given(st.ORDERED_BIDICT_AND_ORDERED_DICT_FROM_SAME_ITEMS_NODUP) def test_inverted_orderedbidict(ob_and_od): """:func:`bidict.inverted` should yield the inverse items of an ordered bidict.""" ob, od = ob_and_od od_inv = OrderedDict((v, k) for (k, v) in iteritems(od)) assert all(i == j for (i, j) in izip(inverted(ob), iteritems(od_inv))) assert all(i == j for (i, j) in izip(inverted(inverted(ob)), iteritems(od))) bidict-0.18.2/tests/test_benchmark.py0000664000372000037200000001046013535200701020404 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Benchmarks.""" import pytest from bidict import OrderedBidict, ValueDuplicationError, bidict BIDICT_TYPES = (bidict, OrderedBidict) ELEMENTS = OrderedBidict(( ('H', 'hydrogen'), ('He', 'helium'), ('Li', 'lithium'), ('Be', 'beryllium'), ('B', 'boron'), ('C', 'carbon'), ('N', 'nitrogen'), ('O', 'oxygen'), ('F', 'fluorine'), ('Ne', 'neon'), ('Na', 'sodium'), ('Mg', 'magnesium'), ('Al', 'aluminum'), ('Si', 'silicon'), ('P', 'phosphorus'), ('S', 'sulfur'), ('Cl', 'chlorine'), ('Ar', 'argon'), )) UPDATE_NODUP = OrderedBidict(( ('K', 'potassium'), ('Ca', 'calcium'), ('Sc', 'Scandium'), ('Ti', 'titanium'), ('V', 'vanadium'), ('Cr', 'chromium'), ('Mn', 'manganese'), ('Fe', 'iron'), ('Co', 'cobalt'), ('Ni', 'nickel'), ('Cu', 'copper'), ('Zn', 'zinc'), ('Ga', 'gallium'), ('Ge', 'germanium'), ('As', 'arsenic'), ('Se', 'selenium'), ('Br', 'bromine'), ('Kr', 'krypton'), ('Rb', 'rubidium'), ('Sr', 'strontium'), ('Y', 'yttrium'), ('Zr', 'zirconium'), ('Nb', 'niobium'), ('Mo', 'molybdenum'), ('Tc', 'technetium'), ('Ru', 'ruthenium'), ('Rh', 'rhodium'), ('Pd', 'palladium'), ('Ag', 'silver'), ('Cd', 'cadmium'), ('In', 'indium'), ('Sn', 'tin'), ('Sb', 'antimony'), ('Te', 'tellurium'), ('I', 'iodine'), ('Xe', 'xenon'), ('Cs', 'cesium'), ('Ba', 'barium'), ('La', 'lanthanum'), ('Ce', 'cerium'), ('Pr', 'praseodymium'), ('Nd', 'neodymium'), ('Pm', 'promethium'), ('Sm', 'samarium'), ('Eu', 'europium'), ('Gd', 'gadolinium'), ('Tb', 'terbium'), ('Dy', 'dysprosium'), ('Ho', 'holmium'), ('Er', 'erbium'), ('Tm', 'thulium'), ('Yb', 'ytterbium'), ('Lu', 'lutetium'), ('Hf', 'hafnium'), ('Ta', 'tantalum'), ('W', 'tungsten'), ('Re', 'rhenium'), ('Os', 'osmium'), ('Ir', 'iridium'), ('Pt', 'platinum'), ('Au', 'gold'), ('Hg', 'mercury'), ('Tl', 'thallium'), ('Pb', 'lead'), ('Bi', 'bismuth'), ('Po', 'polonium'), ('At', 'astatine'), ('Rn', 'radon'), ('Fr', 'francium'), ('Ra', 'radium'), ('Ac', 'actinium'), ('Th', 'thorium'), ('Pa', 'protactinium'), ('U', 'uranium'), ('Np', 'neptunium'), ('Pu', 'plutonium'), ('Am', 'americium'), ('Cm', 'curium'), ('Bk', 'berkelium'), ('Cf', 'californium'), ('Es', 'einsteinium'), ('Fm', 'fermium'), ('Md', 'mendelevium'), ('No', 'nobelium'), ('Lr', 'lawrencium'), ('Rf', 'rutherfordium'), ('Db', 'dubnium'), ('Sg', 'seaborgium'), ('Bh', 'bohrium'), ('Hs', 'hassium'), ('Mt', 'meitnerium'), ('Ds', 'darmstadtium'), ('Rg', 'roentgenium'), ('Cn', 'copernicium'), )) UPDATE_WITHDUPVAL = OrderedBidict(UPDATE_NODUP, key_with_dup_val='hydrogen') @pytest.mark.parametrize('bi_cls', BIDICT_TYPES) def test_put_nodup(bi_cls, benchmark): """Test inserting a new item with no key or value duplication using put.""" some_bidict = bi_cls(ELEMENTS) benchmark(some_bidict.put, 'K', 'potassium') @pytest.mark.parametrize('bi_cls', BIDICT_TYPES) def test_put_withdup(bi_cls, benchmark): """Test inserting a new item with a duplicate value using put.""" some_bidict = bi_cls(ELEMENTS) def _runner(): with pytest.raises(ValueDuplicationError): some_bidict.put('key_with_dup_val', 'hydrogen') benchmark(_runner) @pytest.mark.parametrize('bi_cls', BIDICT_TYPES) def test_update_nodup(bi_cls, benchmark): """Test inserting new items with no duplication using update.""" some_bidict = bi_cls(ELEMENTS) benchmark(some_bidict.update, UPDATE_NODUP) @pytest.mark.parametrize('bi_cls', BIDICT_TYPES) def test_update_withdup(bi_cls, benchmark): """Test inserting new items with value duplication using update.""" some_bidict = bi_cls(ELEMENTS) def _runner(): with pytest.raises(ValueDuplicationError): some_bidict.update(UPDATE_WITHDUPVAL) benchmark(_runner) @pytest.mark.parametrize('bi_cls', BIDICT_TYPES) def test_forceupdate_withdup(bi_cls, benchmark): """Test inserting new items with value duplication using forceupdate.""" some_bidict = bi_cls(ELEMENTS) benchmark(some_bidict.forceupdate, UPDATE_WITHDUPVAL) assert some_bidict.inv['hydrogen'] == 'key_with_dup_val' bidict-0.18.2/tests/test_bidict.txt0000664000372000037200000001646313535200701020110 0ustar travistravis00000000000000# Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. Test script for bidict.bidict:: >>> from bidict import bidict >>> keys = (1, 2, 3) >>> vals = ('one', 'two', 'three') >>> bi = bidict(zip(keys, vals)) >>> bi == bidict({1: 'one', 2: 'two', 3: 'three'}) True Works like dict for getting and changing forward mappings:: >>> bi[2] 'two' >>> bi[2] = 'twain' >>> bi[2] 'twain' >>> bi[4] Traceback (most recent call last): ... KeyError: 4 >>> del bi[2] >>> bi.pop(3) 'three' >>> bi bidict({1: 'one'}) ``put`` can also be used to insert a mapping as long as its key and value don't already exist:: >>> bi.put(0, 'zero') >>> bi[0] 'zero' >>> bi.put(1, 'aught') Traceback (most recent call last): ... KeyDuplicationError: 1 >>> del bi[1] >>> bi.put(1, 'aught') >>> bi[1] 'aught' >>> del bi[0] >>> bi bidict({1: 'aught'}) bidicts maintain references to their inverses via the ``inv`` property, which can also be used to access or modify them:: >>> bi.inv bidict({'aught': 1}) >>> bi.inv['aught'] 1 >>> bi.inv['aught'] = 'one' >>> bi bidict({'one': 'aught'}) >>> bi.inv.pop('aught') 'one' >>> bi == bi.inv == bidict() True >>> bi.inv.update(one=1) >>> bi bidict({1: 'one'}) >>> bi is bi.inv.inv True >>> bi.inv is bi.inv.inv.inv True bidicts work with ``inverted`` as expected:: >>> from bidict import inverted >>> biinv = bidict(inverted(bi)) >>> biinv bidict({'one': 1}) This created a new object (equivalent but not identical):: >>> biinv == bi.inv True >>> biinv is bi.inv False Inverting the inverse should round-trip:: >>> bi == bidict(inverted(inverted(bi))) True >>> bi = bi.inv >>> bi == bidict(inverted(inverted(bi))) True The rest of the ``MutableMapping`` interface is supported:: >>> bi.get('one') 1 >>> bi.get('zero') >>> bi.get('zero', 'default') 'default' >>> list(bi.keys()) ['one'] >>> list(bi.values()) [1] >>> list(bi.items()) [('one', 1)] >>> bi.setdefault('one', 2) 1 >>> bi.setdefault('two', 2) 2 >>> bi.pop('one') 1 >>> bi bidict({'two': 2}) >>> bi.inv bidict({2: 'two'}) >>> bi.pop('wrong', 'number', 'of', 'args') Traceback (most recent call last): ... TypeError: pop expected at most 2 arguments (got 4) >>> bi.popitem() ('two', 2) >>> bi.popitem() Traceback (most recent call last): ... KeyError: 'popitem(): bidict is empty' >>> bi.inv.setdefault(3, 'three') 'three' >>> bi bidict({'three': 3}) >>> len(bi) # calls __len__ 1 >>> [key for key in bi] # calls __iter__, returns keys like dict ['three'] >>> 'three' in bi # calls __contains__ True >>> list(bi.keys()) ['three'] >>> list(bi.values()) [3] >>> bi.update([('four', 4)]) >>> bi.update({'five': 5}, six=6, seven=7) >>> sorted(bi.items(), key=lambda x: x[1]) [('three', 3), ('four', 4), ('five', 5), ('six', 6), ('seven', 7)] >>> bi.clear() >>> bi bidict() Empty update is a no-op:: >>> bi.update() >>> bi bidict() Not part of the public API, but test this anyway for the coverage:: >>> bi._update(False, None) >>> bi bidict() Initializing with different keys mapping to the same value fails:: >>> bidict([(1, 1), (2, 1)]) Traceback (most recent call last): ... ValueDuplicationError: 1 Adding a new key associated with an existing value fails:: >>> b = bidict({1: 1}) >>> b[2] = 1 Traceback (most recent call last): ... ValueDuplicationError: 1 >>> b.update({2: 1}) Traceback (most recent call last): ... ValueDuplicationError: 1 ``forceput`` and ``forceupdate`` can be used instead:: >>> b.forceput(2, 1) >>> b bidict({2: 1}) >>> b.forceupdate({1: 1}) >>> b bidict({1: 1}) Trying to insert an existing mapping does not raise, and is a no-op:: >>> b = bidict({1: 'one'}) >>> b[1] = 'one' >>> b[1] 'one' >>> b.inv['one'] = 1 >>> b.inv['one'] 1 The following case does not half-succeed, i.e. the bidict is not in an inconsistent state after:: >>> b = bidict(one=1, two=2) >>> b['one'] = 2 Traceback (most recent call last): ... KeyAndValueDuplicationError: ('one', 2) >>> len(b) == len(b.inv) True ``put`` and ``putall`` allow you to have per-call control over duplication behavior (see doctests in ``../docs/unique-values.rst.inc``). Even with RAISE duplication behavior, inserting existing items is a no-op (i.e. it doesn't raise):: >>> from bidict import RAISE >>> b.putall([('three', 3), ('one', 1)], ... on_dup_key=RAISE, on_dup_val=RAISE) is not 'an error' True >>> b0 = b.copy() >>> b.putall([]) # no-op >>> b == b0 True Python 2 dict "view*" APIs are supported:: >>> from bidict.compat import PY2 >>> sorted(b.viewkeys()) == sorted(b.keys()) if PY2 else True True >>> sorted(b.viewvalues()) == sorted(b.values()) if PY2 else True True >>> sorted(b.viewitems()) == sorted(b.items()) if PY2 else True True >>> from bidict import OrderedBidict >>> ob = OrderedBidict(b) >>> sorted(ob.viewkeys()) == sorted(ob.keys()) if PY2 else True True >>> sorted(ob.viewvalues()) == sorted(ob.values()) if PY2 else True True >>> sorted(ob.viewitems()) == sorted(ob.items()) if PY2 else True True On Python 2, bidict.compat.{iter,view}* functions should still work even if passed a Mapping that does not provide corresponding methods (e.g. a sortedcontainers.SortedDict, see https://github.com/grantjenks/python-sortedcontainers/pull/106#issuecomment-435631649):: >>> class MissingViewMethodsDict(dict): ... def __getattribute__(self, attr): ... if attr in ( ... 'iterkeys', 'itervalues', 'iteritems', ... 'viewkeys', 'viewvalues', 'viewitems'): ... raise AttributeError(attr) ... return object.__getattribute__(self, attr) >>> mvmdict = MissingViewMethodsDict({'a': 'A', 'b': 'B'}) >>> from bidict.compat import ( ... iterkeys, itervalues, iteritems, ... viewkeys, viewvalues, viewitems, KeysView, ValuesView, ItemsView) >>> set(iterkeys(mvmdict)) == set(mvmdict.keys()) True >>> set(itervalues(mvmdict)) == set(mvmdict.values()) True >>> set(iteritems(mvmdict)) == set(mvmdict.items()) True >>> viewkeys(mvmdict) == KeysView(mvmdict) True >>> set(viewvalues(mvmdict)) == set(ValuesView(mvmdict)) # ValuesView is not a Set, must wrap True >>> viewitems(mvmdict) == ItemsView(mvmdict) True Make sure copy.copy and copy.deepcopy create shallow and deep copies, respectively:: >>> from copy import copy, deepcopy >>> from bidict import frozenbidict >>> b = frozenbidict({1: frozenbidict()}) >>> c = copy(b) >>> d = deepcopy(b) >>> b == c == d True >>> b[1] is c[1] True >>> b[1] is d[1] False bidict-0.18.2/tests/test_class_relationships.py0000664000372000037200000001274513535200701022533 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Test various issubclass checks.""" try: from collections.abc import Hashable except ImportError: # Python < 3 from collections import Hashable import pytest from bidict import bidict, frozenbidict, FrozenOrderedBidict, OrderedBidict, BidirectionalMapping from bidict.compat import Mapping, MutableMapping, PY2 class OldStyleClass: # pylint: disable=no-init,too-few-public-methods """In Python 2 this is an old-style class (not derived from object).""" class VirtualBimapSubclass(Mapping): # pylint: disable=abstract-method """Dummy type that implements the BidirectionalMapping interface without explicitly extending it, and so should still be considered a (virtual) subclass if the BidirectionalMapping ABC is working correctly. (See :meth:`BidirectionalMapping.__subclasshook__`.) (Not actually a *working* BidirectionalMapping implementation, but doesn't need to be for the purposes of this test.) """ inverse = NotImplemented class AbstractBimap(BidirectionalMapping): # pylint: disable=abstract-method """Dummy type that explicitly extends BidirectionalMapping but fails to provide a concrete implementation for the :attr:`BidirectionalMapping.inverse` :func:`abc.abstractproperty`. As a result, attempting to create an instance of this class should result in ``TypeError: Can't instantiate abstract class AbstractBimap with abstract methods inverse`` """ __getitem__ = NotImplemented __iter__ = NotImplemented __len__ = NotImplemented BIDICT_TYPES = (bidict, frozenbidict, FrozenOrderedBidict, OrderedBidict) BIMAP_TYPES = BIDICT_TYPES + (VirtualBimapSubclass, AbstractBimap) NOT_BIMAP_TYPES = (dict, object, OldStyleClass) MUTABLE_BIDICT_TYPES = (bidict, OrderedBidict) HASHABLE_BIDICT_TYPES = (frozenbidict, FrozenOrderedBidict) ORDERED_BIDICT_TYPES = (OrderedBidict, FrozenOrderedBidict) @pytest.mark.parametrize('bi_cls', BIMAP_TYPES) def test_issubclass_bimap(bi_cls): """All bidict types should subclass :class:`BidirectionalMapping`, and any class conforming to the interface (e.g. VirtualBimapSubclass) should be considered a (virtual) subclass too. """ assert issubclass(bi_cls, BidirectionalMapping) @pytest.mark.parametrize('not_bi_cls', NOT_BIMAP_TYPES) def test_not_issubclass_not_bimap(not_bi_cls): """Classes that do not conform to :class:`BidirectionalMapping` should not be considered subclasses. """ assert not issubclass(not_bi_cls, BidirectionalMapping) # Make sure one of the types tested is an old-style class on Python 2, # i.e. that BidirectionalMapping.__subclasshook__ doesn't break for them. if PY2: # testing the tests ¯\_(ツ)_/¯ assert any(not issubclass(cls, object) for cls in NOT_BIMAP_TYPES) @pytest.mark.parametrize('bi_cls', BIDICT_TYPES) def test_issubclass_mapping(bi_cls): """All bidict types should be :class:`collections.abc.Mapping`s.""" assert issubclass(bi_cls, Mapping) @pytest.mark.parametrize('bi_cls', MUTABLE_BIDICT_TYPES) def test_issubclass_mutablemapping(bi_cls): """All mutable bidict types should be :class:`collections.abc.MutableMapping`s.""" assert issubclass(bi_cls, MutableMapping) @pytest.mark.parametrize('bi_cls', HASHABLE_BIDICT_TYPES) def test_issubclass_hashable(bi_cls): """All hashable bidict types should implement :class:`collections.abc.Hashable`.""" assert issubclass(bi_cls, Hashable) @pytest.mark.parametrize('bi_cls', ORDERED_BIDICT_TYPES) def test_ordered_reversible(bi_cls): """All ordered bidict types should be reversible.""" assert callable(bi_cls.__reversed__) def test_issubclass_internal(): """The docs specifically recommend using ABCs over concrete classes when checking whether an interface is provided (see :ref:`polymorphism`). The relationships tested here are not guaranteed to hold in the future, but are still tested so that any unintentional changes won't go unnoticed. """ assert not issubclass(bidict, FrozenOrderedBidict) assert not issubclass(bidict, OrderedBidict) assert not issubclass(bidict, frozenbidict) assert not issubclass(FrozenOrderedBidict, OrderedBidict) assert not issubclass(FrozenOrderedBidict, bidict) assert not issubclass(FrozenOrderedBidict, frozenbidict) assert not issubclass(OrderedBidict, FrozenOrderedBidict) assert not issubclass(OrderedBidict, bidict) assert not issubclass(OrderedBidict, frozenbidict) assert not issubclass(frozenbidict, FrozenOrderedBidict) assert not issubclass(frozenbidict, OrderedBidict) assert not issubclass(frozenbidict, bidict) def test_abstract_bimap_init_fails(): """See the :class:`AbstractBimap` docstring above.""" with pytest.raises(TypeError): AbstractBimap() # pylint: disable=abstract-class-instantiated def test_bimap_inverse_notimplemented(): """Calling .inverse on a BidirectionalMapping should raise :class:`NotImplementedError`.""" with pytest.raises(NotImplementedError): # Can't instantiate a BidirectionalMapping that hasn't overridden the abstract methods of # the interface, so only way to call this implementation is on the class. BidirectionalMapping.inverse.fget(bidict()) # pylint: disable=no-member bidict-0.18.2/tests/test_metadata.py0000664000372000037200000000122213535200701020226 0ustar travistravis00000000000000# -*- coding: utf-8 -*- # Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. """Test bidict metadata.""" import bidict METADATA_ATTRS = """ __author__ __maintainer__ __copyright__ __email__ __credits__ __description__ __keywords__ __license__ __status__ __url__ __version__ __version_info__ """.split() def test_metadata(): """Ensure bidict has expected metadata attributes.""" for i in METADATA_ATTRS: assert getattr(bidict, i) bidict-0.18.2/tests/test_orderedbidict.txt0000664000372000037200000000564113535200701021451 0ustar travistravis00000000000000# Copyright 2009-2019 Joshua Bronson. All Rights Reserved. # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. Test for consistency in ordered bidicts after handling duplicate keys/values (when passing python's -O flag, this would previously fail due to reliance on side effects in assert statements):: >>> from bidict import OrderedBidict, DuplicationError, RAISE, OVERWRITE >>> b = OrderedBidict([(0, 1)]) >>> exc = None >>> try: ... b.update([(0, 2), (3, 4), (5, 4)]) ... except DuplicationError as e: ... exc = e >>> exc is not None True >>> len(b.inv) 1 >>> exc = None >>> try: ... b.putall([(2, 1), (2, 3)], on_dup_key=RAISE, on_dup_val=OVERWRITE) ... except DuplicationError as e: ... exc = e >>> exc is not None True >>> len(b) 1 >>> b.forceupdate([(0, 1), (2, 3), (0, 3)]) >>> b OrderedBidict([(0, 3)]) Test for consistency updating an ordered bidict's inverse: >>> b.inv[3] = 'UPDATED KEY' >>> b OrderedBidict([('UPDATED KEY', 3)]) >>> b.inv OrderedBidict([(3, 'UPDATED KEY')]) >>> b.inv.forceput('UPDATED VAL', 'UPDATED KEY') >>> b OrderedBidict([('UPDATED KEY', 'UPDATED VAL')]) >>> b.inv OrderedBidict([('UPDATED VAL', 'UPDATED KEY')]) >>> b.inv['NEW VAL'] = 'NEW KEY' >>> b OrderedBidict([('UPDATED KEY', 'UPDATED VAL'), ('NEW KEY', 'NEW VAL')]) >>> b.inv OrderedBidict([('UPDATED VAL', 'UPDATED KEY'), ('NEW VAL', 'NEW KEY')]) >>> b.inv.forceput('NEW VAL', 'UPDATED KEY') >>> b OrderedBidict([('UPDATED KEY', 'NEW VAL')]) >>> b.inv OrderedBidict([('NEW VAL', 'UPDATED KEY')]) >>> b.inv.update([('NEWER VAL', 'NEWER KEY'), ('NEW VAL', 'NEW KEY'), ('FAIL!', 'NEW KEY')]) Traceback (most recent call last): ... ValueDuplicationError: NEW KEY >>> b OrderedBidict([('UPDATED KEY', 'NEW VAL')]) >>> b.inv OrderedBidict([('NEW VAL', 'UPDATED KEY')]) >>> b.inv.forceupdate([('NEWER VAL', 'NEWER KEY'), ('NEW VAL', 'NEW KEY'), ('SUCCESS!', 'NEW KEY')]) >>> b OrderedBidict([('NEW KEY', 'SUCCESS!'), ('NEWER KEY', 'NEWER VAL')]) >>> b.inv OrderedBidict([('SUCCESS!', 'NEW KEY'), ('NEWER VAL', 'NEWER KEY')]) Test move_to_end here so it shows up in pytest's coverage report (its hypothesis tests may not always hit all code paths, and the doctests in the Sphinx docs don't get counted in the coverage report):: >>> b.move_to_end('NEW KEY') >>> b OrderedBidict([('NEWER KEY', 'NEWER VAL'), ('NEW KEY', 'SUCCESS!')]) >>> b.move_to_end('NEW KEY', last=False) >>> b OrderedBidict([('NEW KEY', 'SUCCESS!'), ('NEWER KEY', 'NEWER VAL')]) >>> b.move_to_end('NOT FOUND') Traceback (most recent call last): ... KeyError: 'NOT FOUND' bidict-0.18.2/tox.ini0000664000372000037200000000017613535200701015215 0ustar travistravis00000000000000[tox] envlist = py27, py34, py35, py36, py37, pypy, pypy3 [testenv] commands = pip install -e .[test] ./run_tests.py