pax_global_header00006660000000000000000000000064152434231400014510gustar00rootroot0000000000000052 comment=3b6a3a714d86fc1d8d97efe52e7082bb26f352f8 bidict-0.24.1/000077500000000000000000000000001524342314000130325ustar00rootroot00000000000000bidict-0.24.1/.coveragerc000066400000000000000000000006231524342314000151540ustar00rootroot00000000000000[run] branch = True core = sysmon # Uncomment out the following once it's supported by the sysmon core (https://github.com/coveragepy/coveragepy/issues/2150): # dynamic_context = test_function parallel = True patch = subprocess source = bidict tests [report] precision = 1 show_missing = True # Don't show files in the report that are 100% covered: skip_covered = True exclude_also = @.*overload bidict-0.24.1/.editorconfig000066400000000000000000000002631524342314000155100ustar00rootroot00000000000000# http://EditorConfig.org # top-most EditorConfig file root = true [*] end_of_line = lf insert_final_newline = true indent_style = space indent_size = 2 [*.py] indent_size = 4 bidict-0.24.1/.envrc000066400000000000000000000000121524342314000141410ustar00rootroot00000000000000use flake bidict-0.24.1/.github/000077500000000000000000000000001524342314000143725ustar00rootroot00000000000000bidict-0.24.1/.github/FUNDING.yml000066400000000000000000000010401524342314000162020ustar00rootroot00000000000000# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository github: jab tidelift: pypi/bidict polar: jab ko_fi: joshbronson custom: - http://paypal.me/js3 - https://thanks.dev - https://gumroad.com/l/bidict community_bridge: # PROJECT-NAME issuehunt: # USERNAME liberapay: # Replace with a single Liberapay username open_collective: # Replace with a single Open Collective username patreon: # Replace with a single Patreon username bidict-0.24.1/.github/workflows/000077500000000000000000000000001524342314000164275ustar00rootroot00000000000000bidict-0.24.1/.github/workflows/benchmark.yml000066400000000000000000000256241524342314000211150ustar00rootroot00000000000000name: benchmark "on": push: branches: - main - dev - deps pull_request: branches: - main workflow_dispatch: inputs: ref: description: (optional) ref to benchmark env: FORCE_COLOR: "1" PYTHONHASHSEED: "42" BASELINE_RELEASE_TAG: microbenchmarks # Cachegrind counts instructions rather than measuring time, so comparing them is # reproducible and can be held to a tight bound. A change of more than this much in # either direction is called out. # # There is deliberately no wall-clock threshold. The timings pytest-benchmark reports # here are measured *under* Cachegrind, and vary far more between runs of identical code # than any change worth catching: revisions whose bidict/ was byte-identical have been # seen to differ by tens of percent, in both directions. They are still compared in the # run output, which is archived below for eyeballing, but nothing keys off them. INSTRUCTION_CHANGE_PCT: "1.0" jobs: benchmark: runs-on: ubuntu-24.04 steps: - name: install valgrind uses: awalsh128/cache-apt-pkgs-action@553a35bb8ebd9fcabcb1c9451aa4c98e1b4ca8a9 with: packages: valgrind - name: check out source uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 with: fetch-depth: 0 - name: install Nix uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 - name: resolve benchmark metadata id: metadata run: | mapfile -t python_info < <(nix develop .#benchmark --command bash -c "python - <<'PY' import platform print(platform.python_version()) print(platform.python_implementation()) PY") python_version=${python_info[0]} python_impl=${python_info[1]} python_series=${python_version%.*} arch=$(uname -m) baseline_asset_name="GHA-linux-cachegrind-${arch}-${python_impl}-${python_series}-baseline.json" baseline_url="https://github.com/${GITHUB_REPOSITORY}/releases/download/${BASELINE_RELEASE_TAG}/${baseline_asset_name}" instr_asset_name="GHA-linux-cachegrind-${arch}-${python_impl}-${python_series}-instructions.txt" instr_url="https://github.com/${GITHUB_REPOSITORY}/releases/download/${BASELINE_RELEASE_TAG}/${instr_asset_name}" { echo "python_version=$python_version" echo "python_series=$python_series" echo "baseline_asset_name=$baseline_asset_name" echo "baseline_url=$baseline_url" echo "instr_asset_name=$instr_asset_name" echo "instr_url=$instr_url" } >> "$GITHUB_OUTPUT" - name: benchmark and compare to baseline id: benchmark run: | set +e nix develop .#benchmark --command bash -c ' set -euo pipefail git checkout ${{ github.event.inputs.ref || github.sha }} # install a non-editable version of bidict at the revision under test uv pip install --python "$VIRTUAL_ENV/bin/python" --no-deps . # restore the current revision so we use its version of tests/microbenchmarks.py git checkout ${{ github.sha }} # move aside the '"'"'bidict'"'"' subdirectory to make sure we always import the installed version mv -v bidict src curl -L -s -o baseline.json "${{ steps.metadata.outputs.baseline_url }}" line1=$(head -n1 baseline.json) [ "$line1" = "{" ] ./cachegrind.py pytest -c /dev/null -n0 \ --benchmark-autosave \ --benchmark-columns=min,rounds,iterations \ --benchmark-disable-gc \ --benchmark-group-by=name \ --benchmark-compare=baseline.json \ microbenchmarks.py ' 2>&1 | tee benchmark-output.txt benchmark_status=${PIPESTATUS[0]} # Nothing here is allowed to fail the job except the run itself failing, which # means pytest could not benchmark the revision at all. if [ "$benchmark_status" -eq 0 ]; then result_state=ok result_message='benchmarks ran' else result_state=failed result_message='benchmark execution failed' fi { echo "exit_code=$benchmark_status" echo "result_state=$result_state" echo "result_message=$result_message" } >> "$GITHUB_OUTPUT" exit "$benchmark_status" env: CACHEGRIND_ESTIMATE_OUT: ${{ github.workspace }}/instructions.txt - name: compare instruction estimate to baseline id: instructions if: always() env: INSTR_URL: ${{ steps.metadata.outputs.instr_url }} run: | # This comparison is reproducible where a wall-clock one is not: two runs of the # same revision have been measured 0.13% apart, against swings of tens of percent # for the per-benchmark timings. state=unavailable delta= now= baseline= if [ ! -s instructions.txt ]; then # Distinct from a missing baseline: this means cachegrind.py did not honor # CACHEGRIND_ESTIMATE_OUT, i.e. something here is broken rather than unpublished. summary='cachegrind.py recorded no instruction estimate' elif ! curl -fL -s -o instructions-baseline.txt "$INSTR_URL" || [ ! -s instructions-baseline.txt ]; then summary="no instruction baseline published yet (${INSTR_URL##*/})" else now=$(cat instructions.txt) baseline=$(cat instructions-baseline.txt) delta=$(python -c "print(f'{($now - $baseline) / $baseline * 100:+.2f}')") state=$(python -c "d = $delta; p = $INSTRUCTION_CHANGE_PCT; print('regression' if d > p else 'improved' if d < -p else 'ok')") if [ "$state" = regression ]; then summary="${delta}% vs baseline, over the ${INSTRUCTION_CHANGE_PCT}% threshold" else summary="${delta}% vs baseline" fi fi { echo "state=$state" echo "summary=$summary" echo "delta=$delta" echo "now=$now" echo "baseline=$baseline" } >> "$GITHUB_OUTPUT" # Warn only on pull requests, matching the timing check: on a push the baseline is # whatever was last published, so drift since then is expected rather than notable. if [ "$state" = regression ] && [ "${{ github.event_name }}" = "pull_request" ]; then echo "::warning::Instruction count regressed by ${delta}% vs the baseline (threshold ${INSTRUCTION_CHANGE_PCT}%)." fi - name: summarize benchmark result if: always() run: | { echo '## Benchmark result' echo echo "- Baseline asset: \`${{ steps.metadata.outputs.baseline_asset_name }}\`" echo "- Benchmark run: [${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})" echo "- Instruction threshold: \`${INSTRUCTION_CHANGE_PCT}%\`" echo "- Result: ${{ steps.benchmark.outputs.result_message }}" echo "- Instruction count: ${{ steps.instructions.outputs.summary }}" } >> "$GITHUB_STEP_SUMMARY" - name: prepare PR benchmark comment if: always() && github.event_name == 'pull_request' env: BASELINE_ASSET_NAME: ${{ steps.metadata.outputs.baseline_asset_name }} PR_NUMBER: ${{ github.event.pull_request.number }} RESULT_MESSAGE: ${{ steps.benchmark.outputs.result_message }} RESULT_STATE: ${{ steps.benchmark.outputs.result_state }} INSTR_STATE: ${{ steps.instructions.outputs.state }} INSTR_SUMMARY: ${{ steps.instructions.outputs.summary }} INSTR_DELTA: ${{ steps.instructions.outputs.delta }} run: | mkdir -p benchmark-pr-comment run_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" case "$INSTR_STATE" in improved) headline=":zap: Instruction count improved: ${INSTR_SUMMARY}." ;; regression) headline=":warning: Instruction count regressed: ${INSTR_SUMMARY}." ;; ok) headline=":white_check_mark: Instruction count within threshold: ${INSTR_SUMMARY}." ;; *) headline=":grey_question: Instruction count: ${INSTR_SUMMARY}." ;; esac if [ "$RESULT_STATE" != ok ]; then headline=":x: Benchmark execution failed, so there is nothing to compare." fi cat > benchmark-pr-comment/comment.md < ## Benchmark report ${headline} - Baseline asset: \`${BASELINE_ASSET_NAME}\` - Instruction threshold: \`${INSTRUCTION_CHANGE_PCT}%\` - Run: [benchmark workflow run](${run_url}) _Instruction counts are reported for information and do not block merging. Wall-clock timings are compared in the run output too, but they are measured under Cachegrind and vary too much between runs to report on._ EOF python - <<'PY' import json import os from pathlib import Path payload = { 'pr_number': os.environ['PR_NUMBER'], 'result_state': os.environ['RESULT_STATE'], 'result_message': os.environ['RESULT_MESSAGE'], 'baseline_asset_name': os.environ['BASELINE_ASSET_NAME'], 'instruction_threshold_pct': os.environ['INSTRUCTION_CHANGE_PCT'], 'instruction_state': os.environ['INSTR_STATE'], 'instruction_summary': os.environ['INSTR_SUMMARY'], 'instruction_delta_pct': os.environ['INSTR_DELTA'], 'run_url': f"{os.environ['GITHUB_SERVER_URL']}/{os.environ['GITHUB_REPOSITORY']}/actions/runs/{os.environ['GITHUB_RUN_ID']}", } Path('benchmark-pr-comment/result.json').write_text(json.dumps(payload, indent=2) + '\n') PY - name: archive PR benchmark comment if: always() && github.event_name == 'pull_request' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: benchmark-pr-comment path: benchmark-pr-comment if-no-files-found: error - name: archive benchmark results if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: microbenchmark results (CPython ${{ steps.metadata.outputs.python_version }}) path: | .benchmarks benchmark-output.txt instructions.txt include-hidden-files: true if-no-files-found: error permissions: contents: read bidict-0.24.1/.github/workflows/benchmark_pr_comment.yml000066400000000000000000000067611524342314000233410ustar00rootroot00000000000000name: benchmark PR comment "on": workflow_run: workflows: - benchmark types: - completed jobs: comment: if: github.event.workflow_run.event == 'pull_request' runs-on: ubuntu-24.04 permissions: actions: read contents: read issues: write pull-requests: write steps: - name: download benchmark PR comment artifact env: FALLBACK_PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number || '' }} GH_TOKEN: ${{ github.token }} REPOSITORY: ${{ github.repository }} RUN_ID: ${{ github.event.workflow_run.id }} RUN_URL: ${{ github.event.workflow_run.html_url }} run: | set -euo pipefail mkdir -p artifact gh api "repos/${REPOSITORY}/actions/runs/${RUN_ID}/artifacts" > artifacts.json artifact_url=$( python -c "import json; from pathlib import Path; artifacts = json.loads(Path('artifacts.json').read_text())['artifacts']; print(next((artifact['archive_download_url'] for artifact in artifacts if artifact['name'] == 'benchmark-pr-comment'), ''))" ) if [ -n "$artifact_url" ]; then curl -LfsS \ -H "Authorization: Bearer ${GH_TOKEN}" \ "$artifact_url" > artifact.zip python -c "from zipfile import ZipFile; ZipFile('artifact.zip').extractall('artifact')" else python -c "import json, os; from pathlib import Path; Path('artifact/comment.md').write_text('\\n## Benchmark report\\n\\n:warning: Benchmark comment artifact not found.\\n\\n- Run: [benchmark workflow run]({})\\n- Result: the benchmark workflow completed, but it did not upload the PR comment artifact.\\n\\n_This benchmark check is informational and does not block merging._\\n'.format(os.environ['RUN_URL'])); Path('artifact/result.json').write_text(json.dumps({'pr_number': os.environ['FALLBACK_PR_NUMBER']}) + '\\n')" fi - name: create or update sticky benchmark comment env: GH_TOKEN: ${{ github.token }} FALLBACK_PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number || '' }} REPOSITORY: ${{ github.repository }} run: | set -euo pipefail PR_NUMBER=$( python -c "import json, os; from pathlib import Path; result_path = Path('artifact/result.json'); pr_number = str(json.loads(result_path.read_text()).get('pr_number', '')) if result_path.exists() else ''; print(pr_number or os.environ.get('FALLBACK_PR_NUMBER', ''))" ) [ -n "$PR_NUMBER" ] gh api "repos/${REPOSITORY}/issues/${PR_NUMBER}/comments?per_page=100" > comments.json comment_id=$( python -c "import json; marker = ''; comments = json.load(open('comments.json')); print(next((str(comment['id']) for comment in comments if marker in comment['body']), ''))" ) python -c "import json; from pathlib import Path; body = Path('artifact/comment.md').read_text(); Path('comment-payload.json').write_text(json.dumps({'body': body}))" if [ -n "$comment_id" ]; then gh api \ --method PATCH \ "repos/${REPOSITORY}/issues/comments/${comment_id}" \ --input comment-payload.json else gh api \ --method POST \ "repos/${REPOSITORY}/issues/${PR_NUMBER}/comments" \ --input comment-payload.json fi bidict-0.24.1/.github/workflows/lint.yml000066400000000000000000000041571524342314000201270ustar00rootroot00000000000000name: lint "on": workflow_dispatch: push: branches: - main - dev - deps pull_request: branches: - main env: PREK_HOME: ~/.cache/prek jobs: main: name: lint runs-on: ubuntu-24.04 steps: - name: check out code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 with: fetch-depth: 0 - name: install Nix uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 - name: cache prek hook environments uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with: path: ${{ env.PREK_HOME }} key: prek|${{ runner.os }}|${{ hashFiles('.pre-commit-config.yaml') }} - name: lint changed files run: | if [[ "$GITHUB_EVENT_NAME" == 'pull_request' ]]; then from_ref='${{ github.event.pull_request.base.sha }}' to_ref='${{ github.event.pull_request.head.sha }}' elif [[ "$GITHUB_EVENT_NAME" == 'push' ]]; then from_ref='${{ github.event.before }}' to_ref='${{ github.sha }}' if [[ "$from_ref" == '0000000000000000000000000000000000000000' ]] || ! git cat-file -e "$from_ref^{commit}" 2>/dev/null; then # New branch, or from_ref no longer reachable (e.g. after a force-push): from_ref="$(git merge-base "origin/${{ github.event.repository.default_branch }}" "$to_ref")" fi else to_ref='${{ github.sha }}' from_ref="$(git merge-base "origin/${{ github.event.repository.default_branch }}" "$to_ref")" if [[ -z "$(git diff --name-only "$from_ref" "$to_ref")" ]]; then # No files changed between from_ref and to_ref -> run on all files: nix develop .#lint --command prek run --all-files --show-diff-on-failure --verbose exit 0 fi fi nix develop .#lint --command prek run \ --from-ref "$from_ref" \ --to-ref "$to_ref" \ --show-diff-on-failure \ --verbose permissions: contents: read bidict-0.24.1/.github/workflows/release-to-pypi.yml000066400000000000000000000021521524342314000221710ustar00rootroot00000000000000name: release to pypi.org "on": push: tags: - "v[0-9]+.[0-9]+.[0-9]+" workflow_dispatch: jobs: main: runs-on: ubuntu-24.04 steps: - name: check out source uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - name: install Nix uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 - name: build distributions # This uv is the flake's, which is also the build backend: uv build uses its own # built-in uv_build whenever that uv satisfies pyproject.toml's [build-system] # requires, and only fetches uv_build from PyPI otherwise. Either way, that floor # is what keeps a too-old backend from writing the wheel's RECORD (#406). run: nix develop .#build --command uv build - name: check distributions run: nix develop .#build --command ./check_dist - name: Publish uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b with: user: __token__ password: ${{ secrets.PYPI_API_TOKEN }} permissions: contents: read bidict-0.24.1/.github/workflows/release-to-test-pypi.yml000066400000000000000000000033111524342314000231440ustar00rootroot00000000000000name: release to test.pypi.org "on": push: tags: # To publish a test release to test.pypi.org, # create and push a tag as follows: # git tag -a 0.21.3.rc1 -m "Tag 0.21.3.rc1 for release to test.pypi.org" # git push --tags # Go to https://github.com/jab/bidict/actions?query=workflow%3A%22Release+to+Test+PyPI%22 # and watch for a new run of this workflow to publish to test.pypi.org. # IMPORTANT: Run the following to clean up after: # git tag -d 0.21.3.rc1 # git push origin :0.21.3.rc1 - "[0-9]+.[0-9]+.[0-9]+.rc[0-9]+" workflow_dispatch: jobs: main: runs-on: ubuntu-24.04 steps: - name: check out source uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - name: install Nix uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 - name: build distributions # This uv is the flake's, which is also the build backend: uv build uses its own # built-in uv_build whenever that uv satisfies pyproject.toml's [build-system] # requires, and only fetches uv_build from PyPI otherwise. Either way, that floor # is what keeps a too-old backend from writing the wheel's RECORD (#406). run: nix develop .#build --command uv build - name: check distributions run: nix develop .#build --command ./check_dist - name: Publish uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b with: user: __token__ password: ${{ secrets.TEST_PYPI_API_TOKEN }} repository_url: https://test.pypi.org/legacy/ verbose: true permissions: contents: read bidict-0.24.1/.github/workflows/test.yml000066400000000000000000000075251524342314000201420ustar00rootroot00000000000000# This name appears as the text in the build badge: https://github.com/jab/bidict/actions/workflows/test.yml/badge.svg name: tests "on": workflow_dispatch: inputs: hypothesis_profile: type: choice description: (optional) options: - less-examples - more-examples schedule: - cron: "15 16 * * *" push: branches: - main - dev - deps pull_request: branches: - main env: FORCE_COLOR: "1" jobs: test-all: name: ${{ matrix.python }} runs-on: ubuntu-24.04 continue-on-error: ${{ matrix.allow_failure || false }} strategy: fail-fast: false matrix: include: - python: "3.15" shell: test315 # TODO: Drop allow_failure once 3.15 is stable: allow_failure: true - python: "3.14" shell: test314 enable_coverage: true - python: "3.13" shell: test313 - python: "3.12" shell: test312 - python: "3.11" shell: test311 # bidict/_typing.py's `typing`/`typing_extensions` imports branch on python<3.12 enable_coverage: true - python: "pypy-3.11" shell: testPyPy311 steps: - name: check out source uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - name: install Nix uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 - name: cache the Nix store uses: DeterminateSystems/magic-nix-cache-action@908b263ff629f4cc17666315b7fd3ec127c6244d with: # Use only the GitHub Actions cache; we don't authenticate to FlakeHub, and leaving it # enabled makes the action log a noisy (non-fatal) "Cannot find netrc credentials for # https://api.flakehub.com/" error before falling back to the GHA cache. use-flakehub: false use-gha-cache: true - name: set hypothesis profile # Both choices are profiles bidict registers in tests/conftest.py, so no run lands on # hypothesis's built-in `default`, whose wall-clock deadline fails tests for being slow # on their first call. Using less-examples here also stops CI, which gates merges, from # generating fewer examples than a plain local `pytest` does. run: | hypothesis_profile=${{ github.event.inputs.hypothesis_profile || (github.event_name == 'schedule' && 'more-examples' || 'less-examples') }} echo PYTEST_ADDOPTS="$PYTEST_ADDOPTS --hypothesis-profile=$hypothesis_profile" >> "$GITHUB_ENV" - name: cache .hypothesis dir uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with: path: .hypothesis key: hypothesis|${{ runner.os }}|${{ matrix.python }} - name: maybe enable coverage if: matrix.enable_coverage run: | echo RUN_PYTEST_CMD="coverage run -m pytest" >> "$GITHUB_ENV" - name: run ty and pytest run: | nix develop .#${{ matrix.shell }} --command bash -c " set -euo pipefail ty check \${RUN_PYTEST_CMD:-pytest} " - name: combine and show any collected coverage if: matrix.enable_coverage run: | nix develop .#${{ matrix.shell }} --command bash -c ' coverage combine coverage debug data coverage report ' - name: maybe upload to Codecov # https://github.com/codecov/codecov-action if: matrix.enable_coverage uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: verbose: true fail_ci_if_error: false # https://github.com/codecov/codecov-action/issues/557 permissions: contents: read bidict-0.24.1/.github/workflows/update_actions.yml000066400000000000000000000014121524342314000221520ustar00rootroot00000000000000# https://github.com/marketplace/actions/github-actions-version-updater name: update GitHub Actions "on": workflow_dispatch: schedule: # Second day of every third month at noon - cron: "0 12 2 */3 *" jobs: main: runs-on: ubuntu-24.04 steps: - name: check out code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 with: token: ${{ secrets.ACTIONS_VERSION_UPDATER_TOKEN }} - name: update GitHub Actions uses: saadmk11/github-actions-version-updater@v0.9.0 with: token: ${{ secrets.ACTIONS_VERSION_UPDATER_TOKEN }} update_version_with: release-commit-sha pull_request_labels: "automated, dependencies" permissions: contents: write pull-requests: write bidict-0.24.1/.github/workflows/update_benchmark_baselines.yml000066400000000000000000000141271524342314000245000ustar00rootroot00000000000000name: update benchmark baselines "on": push: branches: - main paths: - flake.lock - flake.nix workflow_dispatch: inputs: ref: description: (optional) ref to benchmark for the new baseline required: false env: FORCE_COLOR: "1" PYTHONHASHSEED: "42" BASELINE_RELEASE_TAG: microbenchmarks jobs: update-baselines: runs-on: ubuntu-24.04 steps: - name: install valgrind uses: awalsh128/cache-apt-pkgs-action@553a35bb8ebd9fcabcb1c9451aa4c98e1b4ca8a9 with: packages: valgrind - name: check out source uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 with: fetch-depth: 0 ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.ref || github.ref }} - name: install Nix uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 - name: resolve benchmark metadata id: metadata run: | mapfile -t python_info < <(nix develop .#benchmark --command bash -c "python - <<'PY' import platform print(platform.python_version()) print(platform.python_implementation()) PY") python_version=${python_info[0]} python_impl=${python_info[1]} python_series=${python_version%.*} arch=$(uname -m) versioned_asset_name="GHA-linux-cachegrind-${arch}-${python_impl}-${python_version}-baseline.json" series_asset_name="GHA-linux-cachegrind-${arch}-${python_impl}-${python_series}-baseline.json" versioned_instr_name="GHA-linux-cachegrind-${arch}-${python_impl}-${python_version}-instructions.txt" series_instr_name="GHA-linux-cachegrind-${arch}-${python_impl}-${python_series}-instructions.txt" { echo "python_version=$python_version" echo "python_series=$python_series" echo "versioned_asset_name=$versioned_asset_name" echo "series_asset_name=$series_asset_name" echo "versioned_instr_name=$versioned_instr_name" echo "series_instr_name=$series_instr_name" } >> "$GITHUB_OUTPUT" - name: benchmark env: # Have cachegrind.py record its instruction estimate, which unlike the wall-clock # figures is reproducible, so PR runs can compare against it without a noise allowance. CACHEGRIND_ESTIMATE_OUT: ${{ github.workspace }}/instructions.txt run: | nix develop .#benchmark --command bash -c ' uv pip install --python "$VIRTUAL_ENV/bin/python" --no-deps . # Move aside the working tree package so we always import the installed version. mv -v bidict src ./cachegrind.py pytest -c /dev/null -n0 \ --benchmark-autosave \ --benchmark-columns=min,rounds,iterations \ --benchmark-disable-gc \ --benchmark-group-by=name \ microbenchmarks.py ' - name: prepare baseline assets id: assets run: | benchmark_json=$(find .benchmarks -type f -name '*.json' | sort | tail -n1) [ -n "$benchmark_json" ] cp "$benchmark_json" '${{ steps.metadata.outputs.versioned_asset_name }}' cp "$benchmark_json" '${{ steps.metadata.outputs.series_asset_name }}' [ -s instructions.txt ] cp instructions.txt '${{ steps.metadata.outputs.versioned_instr_name }}' cp instructions.txt '${{ steps.metadata.outputs.series_instr_name }}' { echo "benchmark_json=$benchmark_json" echo "versioned_asset_path=${{ github.workspace }}/${{ steps.metadata.outputs.versioned_asset_name }}" echo "series_asset_path=${{ github.workspace }}/${{ steps.metadata.outputs.series_asset_name }}" echo "versioned_instr_path=${{ github.workspace }}/${{ steps.metadata.outputs.versioned_instr_name }}" echo "series_instr_path=${{ github.workspace }}/${{ steps.metadata.outputs.series_instr_name }}" } >> "$GITHUB_OUTPUT" - name: ensure baseline release exists env: GH_TOKEN: ${{ github.token }} run: | if gh release view "$BASELINE_RELEASE_TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then exit 0 fi gh release create "$BASELINE_RELEASE_TAG" \ --repo "$GITHUB_REPOSITORY" \ --title 'baseline microbenchmarks' \ --notes 'This tag exists merely so we have somewhere we can store the attached baseline benchmark data.' - name: upload baseline assets env: GH_TOKEN: ${{ github.token }} run: | gh release upload "$BASELINE_RELEASE_TAG" \ '${{ steps.assets.outputs.versioned_asset_path }}' \ '${{ steps.assets.outputs.series_asset_path }}' \ '${{ steps.assets.outputs.versioned_instr_path }}' \ '${{ steps.assets.outputs.series_instr_path }}' \ --repo "$GITHUB_REPOSITORY" \ --clobber - name: write summary run: | { echo '### Uploaded benchmark baselines' echo echo '- Python: `${{ steps.metadata.outputs.python_version }}`' echo '- Versioned asset: `${{ steps.metadata.outputs.versioned_asset_name }}`' echo '- Series alias: `${{ steps.metadata.outputs.series_asset_name }}`' echo '- Source benchmark file: `${{ steps.assets.outputs.benchmark_json }}`' echo "- Instruction estimate: \`$(cat instructions.txt)\`" } >> "$GITHUB_STEP_SUMMARY" - name: archive benchmark results uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: microbenchmark baseline results (CPython ${{ steps.metadata.outputs.python_version }}) path: | .benchmarks ${{ steps.metadata.outputs.versioned_asset_name }} ${{ steps.metadata.outputs.series_asset_name }} include-hidden-files: true if-no-files-found: error permissions: contents: write bidict-0.24.1/.github/workflows/update_dev_deps.yml000066400000000000000000000017671524342314000223200ustar00rootroot00000000000000name: update dev deps "on": schedule: # First day of every third month at noon - cron: "0 12 1 */3 *" workflow_dispatch: jobs: main: runs-on: ubuntu-24.04 steps: - name: check out code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - name: install Nix uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 # - name: set up upterm session # uses: lhotari/action-upterm@v1 - name: update development dependencies run: nix develop .#update_deps --command bash -c './update_dev_dependencies' - name: create PR uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 with: token: ${{ secrets.DEV_DEPS_UPDATE_TOKEN }} title: Update development dependencies labels: automated,dependencies commit-message: Update dev dependencies. branch: deps permissions: contents: read pull-requests: write bidict-0.24.1/.github/workflows/update_flake_lock.yml000066400000000000000000000014071524342314000226100ustar00rootroot00000000000000name: update flake.lock "on": workflow_dispatch: schedule: # Third day of every third month at noon - cron: "0 12 3 */3 *" jobs: main: runs-on: ubuntu-24.04 steps: - name: check out code uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 - name: install Nix uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 - name: update flake.lock uses: DeterminateSystems/update-flake-lock@834c491b2ece4de0bbd00d85214bb5e83b4da5c6 with: token: ${{ secrets.FLAKE_LOCK_UPDATE_ACTION_TOKEN }} pr-title: "Update flake.lock" pr-labels: | automated dependencies permissions: contents: read pull-requests: write bidict-0.24.1/.gitignore000066400000000000000000000003201524342314000150150ustar00rootroot00000000000000*.pyc *.so __pycache__ .DS_Store .benchmarks .cache .coverage* .direnv .eggs .hypothesis .idea .mypy_cache .tox .venv .venv-benchmark bidict.egg-info build _build coverage.xml dist htmlcov pip-wheel-metadata bidict-0.24.1/.pre-commit-config.yaml000066400000000000000000000025151524342314000173160ustar00rootroot00000000000000exclude: ^\.benchmarks repos: - repo: builtin hooks: - id: check-added-large-files - id: check-case-conflict - id: check-merge-conflict - id: check-symlinks - id: check-toml - id: check-yaml - id: end-of-file-fixer - id: mixed-line-ending - id: trailing-whitespace - repo: https://gitlab.com/bmares/check-json5 rev: v1.0.1 hooks: - id: check-json5 - repo: https://github.com/Lucas-C/pre-commit-hooks rev: v1.5.6 hooks: - id: forbid-crlf - id: remove-crlf - id: forbid-tabs - id: remove-tabs - repo: https://github.com/codespell-project/codespell rev: v2.4.3 hooks: - id: codespell args: ["--uri-ignore-words-list", "*"] # https://github.com/codespell-project/codespell/issues/2473 - repo: https://github.com/adhtruong/mirrors-typos rev: v1.49.0 hooks: - id: typos args: [--write-changes] - repo: https://github.com/astral-sh/ty-pre-commit rev: v0.0.74 hooks: - id: ty - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.16.4 hooks: - id: ruff-check args: [--fix, --unsafe-fixes] - id: ruff-format - repo: https://github.com/shellcheck-py/shellcheck-py rev: v0.11.0.1-1 hooks: - id: shellcheck exclude: ^.envrc$ bidict-0.24.1/.readthedocs.yml000066400000000000000000000004571524342314000161260ustar00rootroot00000000000000--- # https://docs.readthedocs.io/en/stable/config-file/v2.html version: 2 formats: - htmlzip sphinx: configuration: docs/conf.py fail_on_warning: true build: os: "ubuntu-24.04" tools: python: "3.12" python: install: - method: uv command: sync groups: - docs bidict-0.24.1/.vscode/000077500000000000000000000000001524342314000143735ustar00rootroot00000000000000bidict-0.24.1/.vscode/extensions.json000066400000000000000000000005421524342314000174660ustar00rootroot00000000000000// vim: set ft=json5 { // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. "recommendations": [ "astral-sh.ty", "charliermarsh.ruff", // "lextudio.restructuredtext", // "tamasfe.even-better-toml", // "trond-snekvik.simple-rst", ], "unwantedRecommendations": [], } bidict-0.24.1/.vscode/settings.json000066400000000000000000000004541524342314000171310ustar00rootroot00000000000000// vim: set ft=json5 { "editor.formatOnSaveMode": "modificationsIfAvailable", "files.insertFinalNewline": true, "files.trimFinalNewlines": true, "files.trimTrailingWhitespace": true, "python.defaultInterpreterPath": ".venv/bin/python", "python.testing.pytestEnabled": true, } bidict-0.24.1/.vscode/tasks.json000066400000000000000000000046761524342314000164300ustar00rootroot00000000000000{ "version": "2.0.0", "tasks": [ { "label": "Run tox (all targets)", "type": "process", "command": "tox", "group": "test", "presentation": { "echo": true, "reveal": "always", "focus": false, "panel": "dedicated", "showReuseMessage": false, "clear": false } }, { "label": "Lint", "type": "process", "command": "tox", "args": [ "-e", "lint" ], "group": "test", "presentation": { "echo": true, "reveal": "always", "focus": false, "panel": "dedicated", "showReuseMessage": false, "clear": false } }, { "label": "Run tests", "type": "process", "command": "pytest", "isTestCommand": true, "presentation": { "echo": true, "reveal": "always", "focus": false, "panel": "dedicated", "showReuseMessage": false, "clear": false } }, { "label": "Build docs", "type": "process", "command": "tox", "args": [ "-e", "docs" ], "group": "build", "presentation": { "echo": true, "reveal": "silent", "focus": false, "panel": "dedicated", "showReuseMessage": false, "clear": true } }, { "label": "Host docs", "type": "process", "command": "python", "args": [ "-m", "http.server" ], "isBackground": true, "options": { "cwd": "${workspaceFolder}/docs/_build/html" }, "dependsOn": "Build docs", "presentation": { "echo": true, "reveal": "silent", "focus": false, "panel": "dedicated", "showReuseMessage": false, "clear": true }, "problemMatcher": [] } ] } bidict-0.24.1/CHANGELOG.rst000066400000000000000000001044011524342314000150530ustar00rootroot00000000000000.. 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 ========= .. image:: https://img.shields.io/badge/GitHub-sponsor-ff69b4 :target: https://github.com/sponsors/jab :alt: Sponsor :sup:`If you or your organization depends on bidict, please consider sponsoring bidict on GitHub.` .. tip:: Watch `bidict releases on GitHub `__ to be notified when new versions of bidict are published. Click the "Watch" dropdown, choose "Custom", and then choose "Releases". 0.24.1 (2026-08-25) ------------------- - Fix the ``RECORD`` file in the published 0.24.0 wheel by upgrading to a fixed version of ``uv_build``. :issue:`406` - Fix a test failure on Python 3.15 caused by changes to :class:`~collections.UserDict`. :issue:`407` 0.24.0 (2026-08-24) ------------------- - Remove ``bidict.metadata`` and associated metadata from the :mod:`bidict` module (e.g. ``bidict.__version__``). Use e.g. :func:`importlib.metadata.metadata("bidict")["Version"] ` instead. - Fix a bug where pickling or :func:`~copy.deepcopy`\ing an instance of a dynamically-generated inverse class (see :ref:`extending:Dynamic Inverse Class Generation`) could change the order of its items. :issue:`398` Pickles written by bidict 0.23.1 and earlier can no longer be read. They call the private ``BidictBase._from_other()`` with an argument it no longer accepts, which was retained for no other purpose. Pickle compatibility across versions `has never been guaranteed `__, and dropping it here keeps :meth:`~bidict.BidictBase.__reduce__` free of special cases. - Fix a bug where a non-ordered bidict's :meth:`~bidict.BidictBase.values` view could yield its values in a different order than :meth:`~bidict.BidictBase.keys` yields the corresponding keys, so that e.g. ``zip(b.keys(), b.values())`` silently paired up the wrong keys and values. - Fix a bug where :meth:`~bidict.MutableBidict.putall` and :meth:`~bidict.MutableBidict.update` could leave earlier items inserted when a later item in a bulk update raised a non-duplication exception, rather than failing clean. :issue:`389` - Fix a bug where a bulk update did not fail clean at all when the :class:`~bidict.OnDup` in effect contained no :attr:`~bidict.RAISE` action – as with :meth:`~bidict.MutableBidict.forceupdate`, :meth:`~bidict.MutableBidict.putall` passed :attr:`~bidict.ON_DUP_DROP_OLD`, or :meth:`~bidict.MutableBidict.update` on a subclass that overrides :attr:`~bidict.BidictBase.on_dup` (e.g. the ``YoloBidict`` recipe in :doc:`extending`). Rollback was previously enabled only when a duplication error was possible, but a bulk update can also fail while unpacking an item, hashing a key or value, or writing to a backing mapping. Rollback is now always enabled for these methods. :issue:`392` - Fix a bug where a write or removal that a custom backing mapping refused could leave a custom bidict's two backing mappings out of sync, breaking the bidirectional invariant, rather than failing clean. :issue:`401` :issue:`403` - Fix a bug where mutating an :class:`~bidict.OrderedBidict` while iterating over it produced incorrect behavior rather than raising an error. :issue:`393` - A bidict and its inverse now always refer to the same object for each contained key and value, rather than possibly to equivalent but distinct ones, so that e.g. ``b.inverse[b[key]] is key`` always holds. Writing an item whose key or value is equal to a contained one now keeps the object already contained, as :class:`dict` does when a key is overwritten, instead of keeping one object in each direction. *See also* :ref:`addendum:Equivalent but distinct \:class\:\`~collections.abc.Hashable\`\\s` :issue:`396` - Fix a bug where setting an already-contained (key, value) pair spuriously raised :class:`~bidict.KeyAndValueDuplicationError` or ``AssertionError`` (rather than being a no-op, as documented) when the key or value has non-reflexive equality (e.g. *nan*) or asymmetric equality. :issue:`377` - Fix a bug where set operations between an :class:`~bidict.OrderedBidict`'s keys view and its items view (or vice versa) raised :class:`TypeError` (or, for ``==``, returned the wrong result) rather than behaving like the equivalent plain :class:`dict` views. :issue:`376` - Single-item writes such as :meth:`~bidict.MutableBidict.__setitem__`, :meth:`~bidict.MutableBidict.put`, and :meth:`~bidict.MutableBidict.forceput` are now ~6x faster: most of what they cost was never the write itself, but typing machinery being re-evaluated on every call. Iterating an :class:`~bidict.OrderedBidict` is also ~1.2x faster. Everything else is within a couple of percent of 0.23.1. - A bidict backed by a :class:`dict` *subclass* now gets that mapping's own views from :meth:`~bidict.BidictBase.keys` and :meth:`~bidict.BidictBase.items`, as a bidict backed by an exact :class:`dict` already did. Previously only an exact :class:`dict` qualified, so such a bidict got generic views instead, which were not :class:`~collections.abc.Reversible` (even when the bidict itself was), had no ``.mapping`` attribute, and performed their set operations in Python rather than in C. This affects every backing mapping used in the recipes in :doc:`extending`, since :class:`collections.OrderedDict`, :class:`collections.defaultdict`, and ``sortedcontainers.SortedDict`` are all :class:`dict` subclasses. - Fix a bug where a subclass of a bidict class whose backing mappings are not :class:`~collections.abc.Reversible` could not itself be reversible, even when it specified backing mappings that are. - Fix a bug where an :class:`~bidict.OrderedBidictBase` that is not an :class:`~bidict.OrderedBidict` could yield its items in the wrong order from :meth:`~bidict.OrderedBidictBase.keys`, :meth:`~bidict.OrderedBidictBase.items`, :meth:`~bidict.BidictBase.values`, :func:`repr`, and :meth:`~bidict.BidictBase.equals_order_sensitive`. 0.23.1 (2024-02-18) ------------------- Fix a regression in 0.23.0 that could defeat type inference of a bidict's key type and value type when running in Python 3.8 or 3.9. :issue:`310` 0.23.0 (2024-02-14) ------------------- Primarily, this release simplifies bidict by removing minor features that are no longer necessary or that have little to no apparent usage, and it also includes some performance optimizations. Specifically, initializing or updating a bidict is now up to 70% faster in microbenchmarks. The changes in this release will also make it easier to maintain and improve bidict in the future, including further potential performance optimizations. It also contains several other improvements. - Drop support for Python 3.7, which reached end of life on 2023-06-27, and take advantage of features available in Python 3.8+. - Remove ``FrozenOrderedBidict`` now that Python 3.7 is no longer supported. :class:`~bidict.frozenbidict` now provides everything that ``FrozenOrderedBidict`` provided (including :class:`reversibility `) on all supported Python versions, but with less space overhead. - Remove ``namedbidict`` due to low usage. - Remove the ``kv`` field of :class:`~bidict.OnDup` which specified the :class:`~bidict.OnDupAction` to take in the case of :ref:`basic-usage:key and value duplication`. The :attr:`~bidict.OnDup.val` field now specifies the action to take in the case of :ref:`basic-usage:key and value duplication` as well as :ref:`just value duplication `. - Improve type hints for the :attr:`~bidict.BidictBase.inv` shortcut alias for :attr:`~bidict.BidictBase.inverse`. - Fix a bug where calls like ``bidict(None)``, ``bi.update(False)``, etc. would fail to raise a :class:`TypeError`. - All :meth:`~bidict.BidictBase.__init__`, :meth:`~bidict.MutableBidict.update`, and related methods now handle `SupportsKeysAndGetItem `__ objects that are not :class:`~collections.abc.Mapping`\s the same way that `MutableMapping.update() `__ does, before falling back to handling the provided object as an iterable of pairs. - The :func:`repr` of ordered bidicts now matches that of regular bidicts, e.g. ``OrderedBidict({1: 1})`` rather than ``OrderedBidict([(1, 1)])``. (Accordingly, the ``bidict.__repr_delegate__`` field has been removed now that it's no longer needed.) This tracks with the change to :class:`collections.OrderedDict`\'s :func:`repr` `in Python 3.12 `__. - Test with Python 3.12 in CI. Note: Older versions of bidict also support Python 3.12, even though they don't explicitly declare support for it. - Drop use of `Trove classifiers `__ that declare support for specific Python versions in package metadata. 0.22.1 (2022-12-31) ------------------- - Only include the source code in the source distribution. This reduces the size of the source distribution from ~200kB to ~30kB. - Fix the return type hint of :func:`bidict.inverted` to return an :class:`~collections.abc.Iterator`, rather than an :class:`~collections.abc.Iterable`. 0.22.0 (2022-03-23) ------------------- - Drop support for Python 3.6, which reached end of life on 2021-12-23 and is no longer supported by pip as of pip version 22. Take advantage of this to reduce bidict's maintenance costs. - Use mypy-appeasing explicit re-exports in ``__init__.py`` (e.g. ``import x as x``) so that mypy no longer gives you an implicit re-export error if you run it with ``--no-implicit-reexport`` (or ``--strict``) against code that imports from :mod:`bidict`. - Update the implementations and type annotations of :meth:`bidict.BidictBase.keys` and :meth:`bidict.BidictBase.values` to make use of the new :class:`~bidict.BidictKeysView` type, which works a bit better with type checkers. - Inverse bidict instances are now computed lazily the first time the :attr:`~bidict.BidictBase.inverse` attribute is accessed rather than being computed eagerly during initialization. (A bidict's backing, inverse, one-way mapping is still kept in sync eagerly as any mutations are made, to preserve key- and value-uniqueness.) - Optimize initializing a bidict with another bidict. In a microbenchmark on Python 3.10, this now performs over **2x faster**. - Optimize updating an empty bidict with another bidict. In a microbenchmark on Python 3.10, this now performs **60-75% faster**. - Optimize :meth:`~bidict.BidictBase.copy`. In a microbenchmark on Python 3.10, this now performs **10-20x faster**. - Optimize rolling back :ref:`failed updates to a bidict ` in the case that the number of items passed to the update call can be determined to be larger than the bidict being updated. Previously this rollback was O(n) in the number of items passed. Now it is O(1), i.e. **unboundedly faster**. - Optimize :meth:`bidict.BidictBase.__contains__` (the method called when you run ``key in mybidict``). In a microbenchmark on Python 3.10, this now performs over **3-10x faster** in the False case, and at least **50% faster** in the True case. - Optimize :meth:`bidict.BidictBase.__eq__` (the method called when you run ``mybidict == other``). In a microbenchmark on Python 3.10, this now performs **15-25x faster** for ordered bidicts, and **7-12x faster** for unordered bidicts. - Optimize :meth:`~bidict.BidictBase.equals_order_sensitive`. In a microbenchmark on Python 3.10, this now performs **2x faster** for ordered bidicts and **60-90% faster** for unordered bidicts. - Optimize the :class:`~collections.abc.MappingView` objects returned by :meth:`bidict.OrderedBidict.keys `, :meth:`bidict.OrderedBidict.values `, and :meth:`bidict.OrderedBidict.items ` to delegate to backing ``dict_keys`` and ``dict_items`` objects if available, which are much faster in CPython. For example, in a microbenchmark on Python 3.10, ``orderedbi.items() == d.items()`` now performs **30-50x faster**. - Fix a bug where :meth:`bidict.BidictBase.__eq__` was always returning False rather than :obj:`NotImplemented` in the case that the argument was not a :class:`~collections.abc.Mapping`, defeating the argument's own ``__eq__()`` if implemented. As a notable example, bidicts now correctly compare equal to :obj:`unittest.mock.ANY`. - :class:`bidict.BidictBase` now adds a ``__reversed__`` implementation to subclasses that don't have an overridden implementation depending on whether both their backing mappings are :class:`~collections.abc.Reversible`. Previously, a ``__reversed__`` implementation was only added to :class:`~bidict.BidictBase` when ``BidictBase._fwdm_cls`` was :class:`~collections.abc.Reversible`. So if a :class:`~bidict.BidictBase` subclass set its ``_fwdm_cls`` to a non-reversible mutable mapping, it would also have to manually set its ``__reversed__`` attribute to None to override the implementation inherited from :class:`~bidict.BidictBase`. This is no longer necessary thanks to bidict's new :meth:`object.__init_subclass__` logic. - The :class:`~collections.abc.MappingView` objects returned by :meth:`bidict.OrderedBidict.keys `, :meth:`bidict.OrderedBidict.values `, and :meth:`bidict.OrderedBidict.items ` are now :class:`~collections.abc.Reversible`. (This was already the case for unordered bidicts when running on Python 3.8+.) - Add support for Python 3.9-style dict merge operators (`PEP 584 `__). See `the tests `__ for examples. - Update docstrings for :meth:`bidict.BidictBase.keys`, :meth:`bidict.BidictBase.values`, and :meth:`bidict.BidictBase.items` to include more details. - ``namedbidict`` now exposes the passed-in *keyname* and *valname* in the corresponding properties on the generated class. - ``namedbidict`` now requires *base_type* to be a subclass of :class:`~bidict.BidictBase`, but no longer requires *base_type* to provide an ``_isinv`` attribute, which :class:`~bidict.BidictBase` subclasses no longer provide. - When attempting to pickle a bidict's inverse whose class was :ref:`dynamically generated `, and no reference to the dynamically-generated class has been stored anywhere in :data:`sys.modules` where :mod:`pickle` can find it, the pickle call is now more likely to succeed rather than failing with a :class:`~pickle.PicklingError`. - Remove the use of slots from (non-ABC) bidict types. This better matches the mapping implementations in Python's standard library, and significantly reduces code complexity and maintenance burden. The memory savings conferred by using slots are not noticeable unless you're creating millions of bidict instances anyway, which is an extremely unusual usage pattern. Of course, bidicts can still contain millions (or more) items (which is not an unusual usage pattern) without using any more memory than before these changes. Notably, slots are still used in the internal linked list nodes of ordered bidicts to save memory, since as many node instances are created as there are items inserted. 0.21.4 (2021-10-23) ------------------- Explicitly declare support for Python 3.10 as well as some minor internal improvements. 0.21.3 (2021-09-05) ------------------- - All bidicts now provide the :meth:`~bidict.BidictBase.equals_order_sensitive` method, not just :class:`~bidict.OrderedBidict`\s. Since support for Python < 3.6 was dropped in v0.21.0, :class:`dict`\s provide a deterministic ordering on all supported Python versions, and as a result, all bidicts do too. So now even non-:class:`Ordered ` bidicts might as well provide :meth:`~bidict.BidictBase.equals_order_sensitive`. See the updated :ref:`other-bidict-types:What about order-preserving dicts?` docs for more info. - Take better advantage of the fact that dicts became :class:`reversible ` in Python 3.8. Specifically, now even non-:class:`Ordered ` bidicts provide a :meth:`~bidict.BidictBase.__reversed__` implementation on Python 3.8+ that calls :func:`reversed` on the backing ``_fwdm`` mapping. As a result, if you are using Python 3.8+, :class:`~bidict.frozenbidict` now gives you everything that ``FrozenOrderedBidict`` gives you, but with less space overhead. - Drop `setuptools_scm `__ as a ``setup_requires`` dependency. - Remove the ``bidict.__version_info__`` attribute. 0.21.2 (2020-09-07) ------------------- - Include `py.typed `__ file to mark :mod:`bidict` as type hinted. 0.21.1 (2020-09-07) ------------------- This release was yanked and replaced with the 0.21.2 release, which actually provides the intended changes. 0.21.0 (2020-08-22) ------------------- - :mod:`bidict` now provides `type hints `__! ⌨ï¸� ✅ Adding type hints to :mod:`bidict` poses particularly interesting challenges due to the combination of generic types, dynamically-generated types (such as :ref:`inverse bidict classes ` and ``namedbidict``\s), and complicating optimizations such as the use of slots and weakrefs. It didn't take long to hit bugs and missing features in the state of the art for type hinting in Python today, e.g. missing higher-kinded types support (`python/typing#548 `__), too-narrow type hints for :class:`collections.abc.Mapping` (`python/typeshed#4435 `__), a :class:`typing.Generic` bug in Python 3.6 (`BPO-41451 `__), etc. That said, this release should provide a solid foundation for code using :mod:`bidict` that enables static type checking. As always, if you spot any opportunities to improve :mod:`bidict` (including its new type hints), please don't hesitate to submit a PR! - Add :class:`bidict.MutableBidirectionalMapping` ABC. The :ref:`other-bidict-types:Bidict Types Diagram` has been updated accordingly. - Drop support for Python 3.5, which reaches end of life on 2020-09-13, represents a tiny percentage of bidict downloads on `PyPI Stats `__, and lacks support for `variable type hint syntax `__, `ordered dicts `__, and :attr:`object.__init_subclass__`. - Remove the no-longer-needed ``bidict.compat`` module. - Move :ref:`inverse bidict class access ` from a property to an attribute set in :attr:`~bidict.BidictBase.__init_subclass__`, to save function call overhead on repeated access. - :meth:`bidict.OrderedBidictBase.__iter__` no longer accepts a ``reverse`` keyword argument so that it matches the signature of :meth:`container.__iter__`. - Set the ``__module__`` attribute of various :mod:`bidict` types (using :func:`sys._getframe` when necessary) so that private, internal modules are not exposed e.g. in classes' repr strings. - ``namedbidict`` now immediately raises :class:`TypeError` if the provided ``base_type`` does not provide ``_isinv`` or :meth:`~object.__getstate__`, rather than succeeding with a class whose instances may raise :class:`AttributeError` when these attributes are accessed. 0.20.0 (2020-07-23) ------------------- The following breaking changes are expected to affect few if any users. Remove APIs deprecated in the previous release: - ``bidict.OVERWRITE`` and ``bidict.IGNORE``. - The ``on_dup_key``, ``on_dup_val``, and ``on_dup_kv`` arguments of :meth:`~bidict.MutableBidict.put` and :meth:`~bidict.MutableBidict.putall`. - The ``on_dup_key``, ``on_dup_val``, and ``on_dup_kv`` :class:`~bidict.bidict` class attributes. - Remove ``bidict.BidirectionalMapping.__subclasshook__`` due to lack of use and maintenance cost. Fixes a bug introduced in 0.15.0 that caused any class with an ``inverse`` attribute to be incorrectly considered a subclass of :class:`collections.abc.Mapping`. :issue:`111` 0.19.0 (2020-01-09) ------------------- - Drop support for Python 2 :ref:`as promised in v0.18.2 `. The ``bidict.compat`` module has been pruned accordingly. This makes bidict more efficient on Python 3 and enables further improvement to bidict in the future. - Deprecate ``bidict.OVERWRITE`` and ``bidict.IGNORE``. A :class:`UserWarning` will now be emitted if these are used. :attr:`bidict.DROP_OLD` and :attr:`bidict.DROP_NEW` should be used instead. - Rename ``DuplicationPolicy`` to :class:`~bidict.OnDupAction` (and implement it via an :class:`~enum.Enum`). An :class:`~bidict.OnDupAction` may be one of :attr:`~bidict.RAISE`, :attr:`~bidict.DROP_OLD`, or :attr:`~bidict.DROP_NEW`. - Expose the new :class:`~bidict.OnDup` class to contain the three :class:`~bidict.OnDupAction`\s that should be taken upon encountering the three kinds of duplication that can occur (*key*, *val*, *kv*). - Provide the :attr:`~bidict.ON_DUP_DEFAULT`, :attr:`~bidict.ON_DUP_RAISE`, and :attr:`~bidict.ON_DUP_DROP_OLD` :class:`~bidict.OnDup` convenience instances. - Deprecate the ``on_dup_key``, ``on_dup_val``, and ``on_dup_kv`` arguments of :meth:`~bidict.MutableBidict.put` and :meth:`~bidict.MutableBidict.putall`. A :class:`UserWarning` will now be emitted if these are used. These have been subsumed by the new *on_dup* argument, which takes an :class:`~bidict.OnDup` instance. Use it like this: ``bi.put(1, 2, OnDup(key=RAISE, val=...))``. Or pass one of the instances already provided, such as :attr:`~bidict.ON_DUP_DROP_OLD`. Or just don't pass an *on_dup* argument to use the default value of :attr:`~bidict.ON_DUP_RAISE`. The :ref:`basic-usage:Values Must Be Unique` docs have been updated accordingly. - Deprecate the ``on_dup_key``, ``on_dup_val``, and ``on_dup_kv`` :class:`~bidict.bidict` class attributes. A :class:`UserWarning` will now be emitted if these are used. These have been subsumed by the new :attr:`~bidict.BidictBase.on_dup` class attribute, which takes an :class:`~bidict.OnDup` instance. See the updated :doc:`extending` docs for example usage. - Improve the more efficient implementations of ``bidict.BidirectionalMapping.keys``, ``bidict.BidirectionalMapping.values``, and ``bidict.BidirectionalMapping.items``, and now also provide a more efficient implementation of ``bidict.BidirectionalMapping.__iter__`` by delegating to backing :class:`dict`\s in the bidict types for which this is possible. - Move :meth:`bidict.BidictBase.values` to ``bidict.BidirectionalMapping.values``, since the implementation is generic. - No longer use ``__all__`` in :mod:`bidict`'s ``__init__.py``. 0.18.4 (2020-11-02) ------------------- - Backport fix from v0.20.0 that removes ``bidict.BidirectionalMapping.__subclasshook__`` due to lack of use and maintenance cost. 0.18.3 (2019-09-22) ------------------- - Improve validation of names passed to ``namedbidict``: Use :meth:`str.isidentifier` on Python 3, and a better regex on Python 2. - On Python 3, set :attr:`~definition.__qualname__` on ``namedbidict`` classes based on the provided ``typename`` argument. 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. :issue:`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`. :issue:`86` - ``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 ``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 ``_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:\`\`SortedBidict\`\` 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:\`\`SortedBidict\`\` 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.BidictBase.keys`, :meth:`~bidict.BidictBase.values`, and :meth:`~bidict.BidictBase.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 ``bidict.__version_info__`` attribute to complement ``bidict.__version__``. 0.16.0 (2018-04-06) ------------------- Minor code and efficiency improvements to :func:`~bidict.inverted` and ``bidict._iter._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()`` → ``bidict._iter._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. :issue:`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** - ``namedbidict`` now verifies that the provided ``keyname`` and ``valname`` are distinct, raising :class:`ValueError` if they are equal. - ``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:\`\`SortedBidict\`\` 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. **Misc** - 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 ``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`, ``OVERWRITE``, and ``IGNORE`` duplication policies are no longer available as attributes of ``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, :obj:`pickle.DEFAULT_PROTOCOL` is 3 anyway, so this will not affect you. However if you are using in Python 2, :obj:`~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)``. bidict-0.24.1/CLAUDE.md000066400000000000000000000066051524342314000143200ustar00rootroot00000000000000# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Orientation `bidict` is a mature, dependency-free bidirectional mapping library for Python (>=3.11, CPython + PyPy). The public API is small; the value is in the carefully-factored, fully type-hinted implementation. Optimize for correctness, API stability, and long-term maintainability over cleverness. There are **zero runtime dependencies** (standard library only) — do not add any. ## Canonical docs (imported so their content is in-session) These human-facing docs are the single source of truth. When the underlying facts change, update *them* rather than duplicating anything here: - Contributor workflow — dev environment, running tests and checks, single-test invocation, the property-based (Hypothesis) testing approach, code style and lint, commit conventions, the Semantic Line Breaks prose convention, and the fact that doctests in modules and `docs/*.rst` run as tests: @CONTRIBUTING.rst - Architecture, code structure, and the guided "code review nav" reading order through the source: @docs/learning-from-bidict.rst - Extending bidict — custom subclasses, `on_dup` policies, dynamic inverse-class generation: @docs/extending.rst ## Working in this codebase (Claude-specific notes) - Run dev tooling through the Nix dev shell, not the bare `.venv`: prefix commands with `nix develop --command bash -c '...'` (or work from within a `nix develop` shell). `prek`, `tox`, and the docs build are provided only by the Nix shell, so invoking them outside it fails with "command not found" — even though `pytest` and `ty` happen to also be in `.venv`, which makes it easy to forget. The committed `.envrc` (`use flake`) does not help here, because direnv has no hook in the non-interactive subshells spawned for these tool calls. - SemBr ([Semantic Line Breaks](https://sembr.org), see CONTRIBUTING.rst) applies to prose in Markdown and reStructuredText documents only (this file, `CONTRIBUTING.rst`, `docs/*.rst`): one sentence per line, breaking at clause boundaries, don't reflow paragraphs to fill columns. It does *not* apply to code, code comments, docstrings, or commit messages. - Follow the "Code review nav" banner comments at the top and bottom of each key file (start in `bidict/__init__.py`); they define the author's intended reading order. `_base.py`'s `BidictBase` is the heart of the library. - `_base.py` holds the subtle machinery, each piece explained in inline comments — **read those comments before editing** the relevant code. The landmarks to be careful around: - a bidict and its `.inverse` **share** the same two backing dicts (`_fwdm`/`_invm`, swapped), so mutations through either are visible in both; - the `inverse` property's strong-ref/weakref pair, which exposes the inverse without creating a reference cycle; - `_ensure_inv_cls`/`_make_inv_cls`, which synthesize a distinct inverse class when the forward and inverse backing types differ (intentionally corecursive with `__init_subclass__`); - the `_dedup` → `_write` mutation path, which records "unwrites" so a failing bulk `_update` rolls back atomically. - Every source file carries the MPL-2.0 header — include it on new files. Public API changes must be reflected in `CHANGELOG.rst` and the relevant `docs/*.rst`. bidict-0.24.1/CODE_OF_CONDUCT.md000066400000000000000000000002501524342314000156260ustar00rootroot00000000000000Please see [CODE_OF_CONDUCT.rst](CODE_OF_CONDUCT.rst) This file is here to work around the GitHub bug discussed in https://github.com/github/feedback/discussions/9442 bidict-0.24.1/CODE_OF_CONDUCT.rst000066400000000000000000000004301524342314000160360ustar00rootroot00000000000000Code of Conduct =============== All interaction in the bidict community should adhere to the `Python Community Code of Conduct `__. You can report any Code of Conduct issues via email to `jabronson@gmail.com `__. bidict-0.24.1/CONTRIBUTING.rst000066400000000000000000000232561524342314000155030ustar00rootroot00000000000000.. 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 `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 post in the `GitHub Discussions forum `__, 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 -------------- - To set up a development environment: - If you have `Nix `__, run ``nix develop`` from within your clone to start a shell where all supported Python versions as well as ``prek`` are installed and added to your PATH. This also pins ``uv`` to the flake-provided default Python when initializing ``.venv``. - Otherwise, manually ensure you have `uv `__, `prek `__, and at least the latest `stable Python version `__ installed and on your PATH. - Run ``./init_dev_env`` This installs the ``prek``-based pre-commit hook in your clone, and creates a virtualenv with all the development dependencies installed. - Note that `prek `__ is used to help achieve uniform code style and quality standards at commit time. - Create a topic branch off of ``main`` for your changes: ``git checkout -b main`` - 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 `GitHub Actions `__ build, which should run the tests for all supported Python versions. Testing your changes with GitHub Actions will require approval from a project admin the first time you submit a PR. - 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. Running Tests and Checks ------------------------ The commands below assume you have an active development environment, set up per the steps above. Commands that run against the ``./init_dev_env`` virtualenv (such as ``pytest``) can be prefixed with ``uv run`` or run after activating ``.venv``. Note, however, that ``prek`` — used by the lint, format, and style hooks, including via ``tox -e lint`` — is provided by the ``nix develop`` shell (or your own PATH, if you installed it manually per the setup steps above), not by the ``./init_dev_env`` virtualenv, so run those from within ``nix develop`` (or otherwise ensure ``prek`` is on your PATH). - Run the test suite on your current Python: ``pytest`` - Run a single test: ``pytest tests/test_bidict.py::test_frozenbidicts_hashable`` - Run the tests for every supported Python version: ``tox`` (see ``envlist`` in ``tox.ini`` for the list). - Type-check the code: ``ty check`` - Run all the lint, format, and style hooks: ``prek run --all-files`` (equivalently, ``tox -e lint``). - Build the docs: ``tox -e docs``. Note that the test suite (configured under ``[tool.pytest]`` in ``pyproject.toml``) executes the doctests in every module's docstrings **as well as** the code blocks in ``docs/*.rst`` files. In other words, example code in docstrings and docs is run as part of the tests, so be sure to keep it correct and up to date. Most of bidict's tests are property-based, written using `Hypothesis `__. The bulk of the suite lives in ``tests/test_bidict.py``, centered on ``BidictStateMachine`` (a `stateful `__ ``RuleBasedStateMachine``) that checks bidict's invariants against a simpler reference model, with user-defined bidict subclass fixtures in ``tests/bidict_test_fixtures.py``. When adding behavior, prefer extending these properties and invariants (and adding doctests where they help document usage) over adding one-off, example-based tests. Documentation and Prose Style ----------------------------- Prose in bidict's Markdown and reStructuredText documents (this file, the ``*.rst`` files under ``docs/``, etc.) follows `Semantic Line Breaks `__ (SemBr): start a new line after each sentence, and optionally at other natural boundaries between clauses or phrases, rather than hard-wrapping at a fixed column width or placing an entire paragraph on a single line. Because both Markdown and reStructuredText collapse a single line break within a paragraph into a space, this keeps the rendered output unchanged while making diffs smaller and easier to review. This convention applies to these prose documents only, not to code, code comments, docstrings, or commit messages. 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. Sponsoring ---------- .. Some of the following badges are duplicated on other pages. Would use `.. include::` but GitHub's renderer doesn't support it. .. image:: https://img.shields.io/badge/GitHub-sponsor-ff69b4 :target: https://github.com/sponsors/jab :alt: Sponsor through GitHub .. image:: https://img.shields.io/badge/PayPal-sponsor-blue.svg :target: https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=jabronson%40gmail%2ecom&lc=US&item_name=Sponsor%20bidict :alt: Sponsor through PayPal Bidict is the product of thousands of hours of my unpaid work over the 20 years that I've been the sole maintainer. If bidict has helped you or your company accomplish your work, please sponsor my work through one of the following, and/or ask your company to do the same: - `GitHub `__ - `PayPal `__ - `Tidelift `__ - `thanks.dev `__ - `Gumroad `__ - `a support engagement with my LLC `__ If you're not sure which to use, GitHub is an easy option, especially if you already have a GitHub account. Just choose a monthly or one-time amount, and GitHub handles everything else. Your bidict sponsorship on GitHub will automatically go on the same regular bill as any other GitHub charges you pay for. PayPal is another easy option for one-time contributions. See the following for rationale and examples of companies supporting the open source projects they depend on in this manner: - ``__ - ``__ - ``__ .. - ``__ .. - ``__ .. - ``__ 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-coc] ``__ | ``__ bidict-0.24.1/LICENSE000066400000000000000000000406201524342314000140410ustar00rootroot00000000000000Mozilla Public License Version 2.0 ================================== Copyright 2009-2026 Joshua Bronson. All rights reserved. 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.24.1/PYPI_DOWNLOAD_STATS.rst000066400000000000000000000003341524342314000166120ustar00rootroot00000000000000Retrieving PyPI Download Stats ------------------------------ * https://pepy.tech/project/bidict * https://pypi.org/project/pypistats/ * https://packaging.python.org/en/latest/guides/analyzing-pypi-package-downloads/ bidict-0.24.1/README.rst000066400000000000000000000172401524342314000145250ustar00rootroot00000000000000.. role:: doc .. (Forward declaration for the "doc" role that Sphinx defines for interop with renderers that are often used to show this doc and that are unaware of Sphinx (GitHub.com, PyPI.org, etc.). Use :doc: rather than :ref: here for better interop as well.) bidict ====== *The bidirectional mapping library for Python.* 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/main.svg :target: https://bidict.readthedocs.io/en/main/ :alt: Documentation .. image:: https://github.com/jab/bidict/actions/workflows/test.yml/badge.svg :target: https://github.com/jab/bidict/actions/workflows/test.yml?query=branch%3Amain :alt: GitHub Actions CI status .. image:: https://img.shields.io/pypi/l/bidict.svg :target: https://raw.githubusercontent.com/jab/bidict/main/LICENSE :alt: License .. image:: https://static.pepy.tech/badge/bidict :target: https://pepy.tech/project/bidict :alt: PyPI Downloads .. image:: https://img.shields.io/badge/GitHub-sponsor-ff69b4 :target: https://github.com/sponsors/jab :alt: Sponsor Features -------- - Mature: Depended on by Google, Venmo, CERN, Baidu, Tencent, and teams across the world since 2009 - Familiar, Pythonic APIs that are carefully designed for safety, simplicity, flexibility, and ergonomics - Lightweight, with no runtime dependencies outside Python's standard library - Implemented in concise, well-factored, fully type-hinted Python code that is optimized for running efficiently as well as for long-term maintenance and stability (as well as `joy <#learning-from-bidict>`__) - Extensively `documented `__ - 100% test coverage running continuously across all supported Python versions (including property-based tests and benchmarks) 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. Enterprise Support ------------------ Enterprise-level support for bidict can be obtained via the `Tidelift subscription `__ or by `contacting me directly `__. I have a US-based LLC set up for invoicing, and I have over 20 years of professional experience delivering software and support to companies successfully. You can also sponsor my work through several platforms, including GitHub Sponsors. See the `Sponsoring <#sponsoring>`__ section below for details, including rationale and examples of companies supporting the open source projects they depend on. Voluntary Community Support --------------------------- Please search through already-asked questions and answers in `GitHub Discussions `__ and the `issue tracker `__ in case your question has already been addressed. Otherwise, please feel free to `start a new discussion `__ or `create a new issue `__ on GitHub for voluntary community support. Notice of Usage --------------- If you use bidict, and especially if your usage or your organization is significant in some way, please let me know in any of the following ways: - `star bidict on GitHub `__ - post in `GitHub Discussions `__ - `email me `__ Changelog --------- For bidict release notes, see the :doc:`changelog`. [#fn-changelog]_ Release Notifications --------------------- .. duplicated in CHANGELOG.rst: (Would use `.. include::` but GitHub's renderer doesn't support it.) Watch `bidict releases on GitHub `__ to be notified when new versions of bidict are published. Click the "Watch" dropdown, choose "Custom", and then choose "Releases". Learning from bidict -------------------- One of the best things about bidict is that it touches a surprising number of interesting Python corners, especially given its small size and scope. Check out :doc:`learning-from-bidict` [#fn-learning]_ if you're interested in learning more. Contributing ------------ I have been bidict's sole maintainer and `active contributor `__ since I started the project ~15 years ago. Your help would be most welcome! See the :doc:`contributors-guide` [#fn-contributing]_ for more information. Sponsoring ---------- .. duplicated in CONTRIBUTING.rst (Would use `.. include::` but GitHub's renderer doesn't support it.) .. image:: https://img.shields.io/badge/GitHub-sponsor-ff69b4 :target: https://github.com/sponsors/jab :alt: Sponsor through GitHub Bidict is the product of thousands of hours of my unpaid work over the 15+ years that I've been the sole maintainer. If bidict has helped you or your company accomplish your work, please sponsor my work through one of the following, and/or ask your company to do the same: - `GitHub `__ - `PayPal `__ - `Tidelift `__ - `thanks.dev `__ - `Gumroad `__ - `a support engagement with my LLC <#enterprise-support>`__ If you're not sure which to use, GitHub is an easy option, especially if you already have a GitHub account. Just choose a monthly or one-time amount, and GitHub handles everything else. Your bidict sponsorship on GitHub will automatically go on the same regular bill as any other GitHub charges you pay for. PayPal is another easy option for one-time contributions. See the following for rationale and examples of companies supporting the open source projects they depend on in this manner: - ``__ - ``__ - ``__ .. - ``__ .. - ``__ .. - ``__ 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] ``__ | ``__ .. [#fn-contributing] ``__ | ``__ bidict-0.24.1/SECURITY.rst000066400000000000000000000002061524342314000150310ustar00rootroot00000000000000Security ======== Please see `tidelift.com/security `__ for how to report a security issue in bidict. bidict-0.24.1/_typos.toml000066400000000000000000000001311524342314000152370ustar00rootroot00000000000000[default] locale = "en-us" [default.extend-words] bimap = "bimap" slicings = "slicings" bidict-0.24.1/bidict/000077500000000000000000000000001524342314000142705ustar00rootroot00000000000000bidict-0.24.1/bidict/__init__.py000066400000000000000000000100061524342314000163760ustar00rootroot00000000000000# Copyright 2009-2026 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 * # ============================================================================ # Reading through the code? You'll find a "Code review nav" comment like the one # below at the top and bottom of the key source files. Follow these cues to take # a path through the code that's optimized for familiarizing yourself with it. # # If you're not reading this on https://github.com/jab/bidict already, go there # to ensure you have the latest version of the code. While there, you can also # star the project, watch it for updates, fork the code, and submit an issue or # pull request with any proposed changes. More information can be found linked # from README.rst, which is also shown on https://github.com/jab/bidict. # * Code review nav * # ============================================================================ # Current: __init__.py Next: _abc.py → # ============================================================================ """The bidirectional mapping library for Python. ---- bidict by example: .. code-block:: python >>> 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) 2009-2026 Joshua Bronson. .. :license: MPLv2. See LICENSE for details. """ # Use private aliases to not re-export these publicly (for Sphinx automodule with imported-members). from __future__ import annotations as _annotations from contextlib import suppress as _suppress from ._abc import BidirectionalMapping as BidirectionalMapping from ._abc import MutableBidirectionalMapping as MutableBidirectionalMapping from ._base import BidictBase as BidictBase from ._base import BidictKeysView as BidictKeysView from ._base import GeneratedBidictInverse as GeneratedBidictInverse from ._bidict import MutableBidict as MutableBidict from ._bidict import bidict as bidict from ._dup import DROP_NEW as DROP_NEW from ._dup import DROP_OLD as DROP_OLD from ._dup import ON_DUP_DEFAULT as ON_DUP_DEFAULT from ._dup import ON_DUP_DROP_OLD as ON_DUP_DROP_OLD from ._dup import ON_DUP_RAISE as ON_DUP_RAISE from ._dup import RAISE as RAISE from ._dup import OnDup as OnDup from ._dup import OnDupAction as OnDupAction from ._exc import BidictException as BidictException from ._exc import DuplicationError as DuplicationError from ._exc import KeyAndValueDuplicationError as KeyAndValueDuplicationError from ._exc import KeyDuplicationError as KeyDuplicationError from ._exc import ValueDuplicationError as ValueDuplicationError from ._frozen import frozenbidict as frozenbidict from ._iter import inverted as inverted from ._orderedbase import OrderedBidictBase as OrderedBidictBase from ._orderedbidict import OrderedBidict as OrderedBidict # Set __module__ of re-exported classes to the 'bidict' top-level module, so that e.g. # 'bidict.bidict' shows up as 'bidict.bidict` rather than 'bidict._bidict.bidict'. for _obj in tuple(locals().values()): # pragma: no cover if not getattr(_obj, '__module__', '').startswith('bidict.'): continue with _suppress(AttributeError): _obj.__module__ = 'bidict' # * Code review nav * # ============================================================================ # Current: __init__.py Next: _abc.py → # ============================================================================ bidict-0.24.1/bidict/_abc.py000066400000000000000000000062771524342314000155420ustar00rootroot00000000000000# Copyright 2009-2026 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/. # * Code review nav * # (see comments in __init__.py) # ============================================================================ # â†� Prev: __init__.py Current: _abc.py Next: _base.py → # ============================================================================ """Provide the :class:`BidirectionalMapping` abstract base class.""" from __future__ import annotations from abc import abstractmethod from collections.abc import Iterator from collections.abc import Mapping from collections.abc import MutableMapping from ._typing import KT from ._typing import VT class BidirectionalMapping(Mapping[KT, VT]): """Abstract base class for bidirectional mapping types. Extends :class:`collections.abc.Mapping` primarily by adding the (abstract) :attr:`inverse` property, which implementers of :class:`BidirectionalMapping` should override to return a reference to the inverse :class:`BidirectionalMapping` instance. """ __slots__ = () @property @abstractmethod def inverse(self) -> BidirectionalMapping[VT, KT]: """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 @abstractmethod decorator prevents subclasses from being instantiated unless they # override this method. But an overriding implementation may merely return super().inverse, # in which case this implementation is used. Raise NotImplementedError to indicate that # subclasses must actually provide their own implementation. raise NotImplementedError def __inverted__(self) -> Iterator[tuple[VT, KT]]: """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 iter(self.inverse.items()) class MutableBidirectionalMapping(BidirectionalMapping[KT, VT], MutableMapping[KT, VT]): """Abstract base class for mutable bidirectional mapping types.""" __slots__ = () # * Code review nav * # ============================================================================ # â†� Prev: __init__.py Current: _abc.py Next: _base.py → # ============================================================================ bidict-0.24.1/bidict/_base.py000066400000000000000000000761721524342314000157300ustar00rootroot00000000000000# Copyright 2009-2026 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/. # * Code review nav * # (see comments in __init__.py) # ============================================================================ # â†� Prev: _abc.py Current: _base.py Next: _frozen.py → # ============================================================================ """Provide :class:`BidictBase`.""" from __future__ import annotations import typing as t import weakref from collections.abc import ItemsView from collections.abc import Iterable from collections.abc import Iterator from collections.abc import KeysView from collections.abc import Mapping from collections.abc import MutableMapping from collections.abc import Reversible from collections.abc import Set from collections.abc import Sized from collections.abc import ValuesView from operator import eq from types import MappingProxyType from ._abc import BidirectionalMapping from ._dup import DROP_NEW from ._dup import DROP_OLD from ._dup import ON_DUP_DEFAULT from ._dup import RAISE from ._dup import OnDup from ._exc import KeyAndValueDuplicationError from ._exc import KeyDuplicationError from ._exc import ValueDuplicationError from ._iter import inverted from ._iter import iteritems from ._typing import KT from ._typing import MISSING from ._typing import OKT from ._typing import OVT from ._typing import VT from ._typing import Maplike from ._typing import MapOrItems from ._typing import override OldKV: t.TypeAlias = tuple[OKT[KT], OVT[VT]] DedupResult: t.TypeAlias = OldKV[KT, VT] | None Unwrites: t.TypeAlias = list[tuple[t.Any, ...]] ReversedIter: t.TypeAlias = t.Callable[['BidictBase[KT, t.Any]'], Iterator[KT]] class BidictKeysView(KeysView[KT], ValuesView[KT]): """Since the keys of a bidict are the values of its inverse (and vice versa), the :class:`~collections.abc.ValuesView` result of calling *bi.values()* is also a :class:`~collections.abc.KeysView` of *bi.inverse*. """ class ProxiedSetView: """Mixin for bidict views whose :class:`~collections.abc.Set` methods delegate to a backing dict view. See :func:`_override_set_methods_to_use_backing_dict`. *_viewname* names the view of *_mapping._fwdm* with the same elements as this view. """ _mapping: BidictBase[t.Any, t.Any] _viewname: t.ClassVar[str] __slots__ = () class BidictValuesView(ProxiedSetView, BidictKeysView[VT]): """The set-like view returned by *bi.values()* for a non-ordered bidict. A bidict's values are the keys of its inverse, so the fast, set-like operations are all provided by viewing the inverse's keys, which this does by taking the *inverse* as its *_mapping*: the inherited __contains__ and __len__ then already do the right thing, and _mapping._fwdm is the backing mapping whose keys are our elements, so the set-method proxy below works unmodified. Iteration is the exception. The inverse's key order is its own backing mapping's, which diverges from this bidict's key order as soon as an item is overwritten. So iterate *this* bidict's backing mapping instead (i.e. the inverse's _invm), to keep b.values() corresponding elementwise to b.keys(), as it does for a plain dict. """ _viewname: t.ClassVar[str] = 'keys' __slots__ = () @override def __iter__(self) -> Iterator[VT]: return iter(self._mapping._invm.values()) def __reversed__(self) -> Iterator[VT]: return reversed(t.cast('Reversible[VT]', self._mapping._invm.values())) class _NonReversibleBidictValuesView(BidictValuesView[VT]): """The values view of a bidict whose backing mappings are not reversible. Setting __reversed__ to None keeps issubclass(cls, Reversible) false, the same way BidictBase._set_reversed() does for the bidict itself, so that this view does not advertise support for reversed() that the backing mappings cannot deliver. """ __reversed__: t.ClassVar[None] = None # type: ignore[assignment] __slots__ = () class BidictBase(BidirectionalMapping[KT, VT]): """Base class implementing :class:`BidirectionalMapping`.""" #: The default :class:`~bidict.OnDup` #: that governs behavior when a provided item #: duplicates the key or value of other item(s). #: #: *See also* #: :ref:`basic-usage:Values Must Be Unique` (https://bidict.rtfd.io/basic-usage.html#values-must-be-unique), #: :doc:`extending` (https://bidict.rtfd.io/extending.html) on_dup = ON_DUP_DEFAULT _fwdm: MutableMapping[KT, VT] #: the backing forward mapping (*key* → *val*) _invm: MutableMapping[VT, KT] #: the backing inverse mapping (*val* → *key*) _fwdm_cls: t.ClassVar[type[MutableMapping[t.Any, t.Any]]] = dict #: class of the backing forward mapping _invm_cls: t.ClassVar[type[MutableMapping[t.Any, t.Any]]] = dict #: class of the backing inverse mapping _fwdm_is_dict: t.ClassVar[bool] = True # When a bidict's `.inverse` property is accessed for the first time, the inverse instance is computed on demand # and stored for subsequent use. A reference back to itself is also stored on the inverse instance at the same time. # A weakref is used in the inverse direction to avoid creating a reference cycle. See :meth:`inverse` _inv: BidictBase[VT, KT] | None _invweak: weakref.ReferenceType[BidictBase[VT, KT]] | None _inv_cls: t.ClassVar[type[BidictBase[t.Any, t.Any]]] # the inverse bidict's class, see :meth:`_ensure_inv_cls` _values_view_cls: t.ClassVar[type[BidictValuesView[t.Any]]] # see :meth:`_set_reversed` def __init_subclass__(cls) -> None: super().__init_subclass__() cls._init_class() @classmethod def _init_class(cls) -> None: cls._fwdm_is_dict = issubclass(cls._fwdm_cls, dict) cls._ensure_inv_cls() cls._set_reversed() __reversed__: t.ClassVar[ReversedIter[t.Any] | None] #: Whether __reversed__ was provided by a user rather than by :meth:`_set_reversed`. #: Inherited, so that a subclass of e.g. :class:`~bidict.OrderedBidictBase` keeps #: the implementation it inherits rather than computing one of its own. _reversed_is_user_provided: t.ClassVar[bool] = False @classmethod def _set_reversed(cls) -> None: """Set __reversed__ for subclasses that do not set it explicitly according to whether backing mappings are reversible. """ backing_reversible = all(issubclass(i, Reversible) for i in (cls._fwdm_cls, cls._invm_cls)) # Leave a user-provided __reversed__ alone, whether it is defined in this class's own # body (e.g. OrderedBidictBase's) or inherited from a base class that defined one # (e.g. OrderedBidict's). Crucially, a value *this* method assigned must not count as # user-provided: a subclass of a bidict whose backing mappings were not reversible # inherits the None assigned below, and must stay free to compute its own answer from # its own backing types, which may well be reversible. resolved = getattr(cls, '__reversed__', None) # Note Mapping.__reversed__ is None, which is what resolves here for BidictBase itself. user_impl = resolved is not None and resolved is not _fwdm_reversed # A user's explicit `__reversed__ = None` opt-out is indistinguishable by value from # the None assigned below, so look for it in the class's own namespace instead. Match # only that exact value: a bare membership test would also match a value assigned by a # previous call of this method, which would then be inherited as if a user had provided it. opted_out = getattr(cls, '__dict__', {}).get('__reversed__', MISSING) is None if user_impl or opted_out: cls._reversed_is_user_provided = True if not cls._reversed_is_user_provided: cls.__reversed__ = _fwdm_reversed if backing_reversible else None # values() iterates a backing mapping (see :meth:`values`), so its view can only # support reversed() if that mapping does, and should not offer it if this bidict # declines to offer reversed() itself. values_reversible = backing_reversible and cls.__reversed__ is not None cls._values_view_cls = BidictValuesView if values_reversible else _NonReversibleBidictValuesView @classmethod def _ensure_inv_cls(cls) -> None: """Ensure :attr:`_inv_cls` is set, computing it dynamically if necessary. All subclasses provided in :mod:`bidict` are their own inverse classes, i.e., their backing forward and inverse mappings are both the same type, but users may define subclasses where this is not the case. This method ensures that the inverse class is computed correctly regardless. See: :ref:`extending:Dynamic Inverse Class Generation` (https://bidict.rtfd.io/extending.html#dynamic-inverse-class-generation) """ # This _ensure_inv_cls() method is (indirectly) corecursive with _make_inv_cls() below # in the case that we need to dynamically generate the inverse class: # 1. _ensure_inv_cls() calls cls._make_inv_cls() # 2. cls._make_inv_cls() calls type(..., (cls, ...), ...) to dynamically generate inv_cls # 3. Our __init_subclass__ hook (see above) is automatically called on inv_cls # 4. inv_cls.__init_subclass__() calls inv_cls._ensure_inv_cls() # 5. inv_cls._ensure_inv_cls() resolves to this implementation # (inv_cls deliberately does not override this), so we're back where we started. # But since the _make_inv_cls() call will have set inv_cls.__dict__._inv_cls, # just check if it's already set before calling _make_inv_cls() to prevent infinite recursion. if getattr(cls, '__dict__', {}).get('_inv_cls'): # Don't assume cls.__dict__ return cls._inv_cls = cls._make_inv_cls() @classmethod def _make_inv_cls(cls) -> type[t.Self]: diff = cls._inv_cls_dict_diff() cls_is_own_inv = all(getattr(cls, k, MISSING) == v for (k, v) in diff.items()) if cls_is_own_inv: return cls # Suppress auto-calculation of _inv_cls's _inv_cls since we know it already. # Works with the guard in BidictBase._ensure_inv_cls() to prevent infinite recursion. diff['_inv_cls'] = cls inv_cls = type(f'{cls.__name__}Inv', (cls, GeneratedBidictInverse), diff) inv_cls.__module__ = cls.__module__ # Point __qualname__ at where this class actually lives, namely cls's _inv_cls attribute, # so that pickle can find it by reference like any other class. Without this it could not # be pickled at all, since nothing else refers to it by name. __name__ is left alone, so # repr() is unaffected. inv_cls.__qualname__ = f'{cls.__qualname__}._inv_cls' return t.cast('type[t.Self]', inv_cls) @classmethod def _inv_cls_dict_diff(cls) -> dict[str, t.Any]: return { '_fwdm_cls': cls._invm_cls, '_invm_cls': cls._fwdm_cls, } def __init__(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None: """Make a new bidirectional mapping. The signature behaves like that of :class:`dict`. ktems passed via positional arg are processed first, followed by any items passed via keyword argument. Any duplication encountered along the way is handled as per :attr:`on_dup`. """ self._fwdm = self._fwdm_cls() self._invm = self._invm_cls() self._update(arg, kw, rollback=False) @property @override def inverse(self) -> BidictBase[VT, KT]: """The inverse of this bidirectional mapping instance.""" # First check if a strong reference is already stored. inv: BidictBase[VT, KT] | None = getattr(self, '_inv', None) if inv is not None: return inv # Next check if a weak reference is already stored. invweak = getattr(self, '_invweak', None) if invweak is not None: inv = invweak() # Try to resolve a strong reference and return it. if inv is not None: return inv # No luck. Compute the inverse reference and store it for subsequent use. inv = self._make_inverse() self._inv = inv self._invweak = None # Also store a weak reference back to `instance` on its inverse instance, so that # the second `.inverse` access in `bi.inverse.inverse` hits the cached weakref. inv._inv = None inv._invweak = weakref.ref(self) # In e.g. `bidict().inverse.inverse`, this design ensures that a strong reference # back to the original instance is retained before its refcount drops to zero, # avoiding an unintended potential deallocation. return inv def _make_inverse(self) -> BidictBase[VT, KT]: inv: BidictBase[VT, KT] = self._inv_cls() inv._fwdm = self._invm inv._invm = self._fwdm return inv @property def inv(self) -> BidictBase[VT, KT]: """Alias for :attr:`inverse`.""" return self.inverse @override def __repr__(self) -> str: """See :func:`repr`.""" clsname = self.__class__.__name__ items = dict(self.items()) if self else '' return f'{clsname}({items})' @override def values(self) -> BidictKeysView[VT]: """A set-like object providing a view on the contained values. Since the values of a bidict are equivalent to the keys of its inverse, this method returns a set-like object for this bidict's values rather than just a collections.abc.ValuesView. This object supports set operations like union and difference, and constant- rather than linear-time containment checks, and is no more expensive to provide than the less capable collections.abc.ValuesView would be. Like :class:`dict`, and unlike the inverse's :meth:`keys` view, it also yields this bidict's values in the same order as its keys, so that *zip(b.keys(), b.values())* corresponds elementwise to *b.items()*. See :meth:`keys` for more information. """ return self._values_view_cls(self.inverse) @override def keys(self) -> KeysView[KT]: """A set-like object providing a view on the contained keys. When *b._fwdm* is a :class:`dict`, *b.keys()* returns its *dict_keys*, which behaves exactly the same as *collections.abc.KeysView(b)*, except for - offering better performance - being reversible - having a .mapping attribute in Python 3.10+ that exposes a mappingproxy to *b._fwdm*. A :class:`dict` subclass gets the same treatment, via whatever view its own *keys()* returns. Only a backing mapping that is not a :class:`dict` at all falls back to a generic view over this bidict. """ return self._fwdm.keys() if self._fwdm_is_dict else BidictKeysView(self) @override def items(self) -> ItemsView[KT, VT]: """A set-like object providing a view on the contained items. When *b._fwdm* is a :class:`dict`, *b.items()* returns its *dict_items*, which behaves exactly the same as *collections.abc.ItemsView(b)*, except for: - offering better performance - being reversible - having a .mapping attribute in Python 3.10+ that exposes a mappingproxy to *b._fwdm*. See :meth:`keys` for how backing mappings that are not exactly dicts are handled. """ return self._fwdm.items() if self._fwdm_is_dict else super().items() # The inherited collections.abc.Mapping.__contains__() method is implemented by doing a `try` # `except KeyError` around `self[key]`. The following implementation is much faster, # especially in the missing case. @override def __contains__(self, key: t.Any) -> bool: """True if the mapping contains the specified key, else False.""" return key in self._fwdm # The inherited collections.abc.Mapping.__eq__() method is implemented in terms of an inefficient # `dict(self.items()) == dict(other.items())` comparison, so override it with a # more efficient implementation. @override def __eq__(self, other: object) -> bool: """*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 ` (https://bidict.rtfd.io/other-bidict-types.html#eq-is-order-insensitive). *See also* :meth:`equals_order_sensitive` """ if isinstance(other, Mapping): return self._fwdm.items() == other.items() # Ref: https://docs.python.org/3/library/constants.html#NotImplemented return NotImplemented def equals_order_sensitive(self, other: object) -> bool: """Order-sensitive equality check. *See also* :ref:`eq-order-insensitive` (https://bidict.rtfd.io/other-bidict-types.html#eq-is-order-insensitive) """ if not isinstance(other, Mapping) or len(self) != len(other): return False return all(map(eq, self.items(), other.items())) def _dedup(self, key: KT, val: VT, on_dup: OnDup) -> DedupResult[KT, VT]: """Check *key* and *val* for any duplication in self. Handle any duplication as per the passed in *on_dup*. If (key, val) is already present, return None since writing (key, val) would be a no-op. If duplication is found and the corresponding :class:`~bidict.OnDupAction` is :attr:`~bidict.DROP_NEW`, return None. If duplication is found and the corresponding :class:`~bidict.OnDupAction` is :attr:`~bidict.RAISE`, raise the appropriate exception. If duplication is found and the corresponding :class:`~bidict.OnDupAction` is :attr:`~bidict.DROP_OLD`, or if no duplication is found, return *(oldkey, oldval)*. """ fwdm, invm = self._fwdm, self._invm oldval: OVT[VT] = fwdm.get(key, MISSING) oldkey: OKT[KT] = invm.get(val, MISSING) isdupkey = oldval is not MISSING isdupval = oldkey is not MISSING if isdupkey and isdupval: if fwdm[oldkey] is oldval: return None # (key, val) duplicates an existing item -> no-op # key and val each duplicate a different existing item. if on_dup.val is RAISE: raise KeyAndValueDuplicationError(key, val) if on_dup.val is DROP_NEW: return None assert on_dup.val is DROP_OLD # Fall through to the return statement on the last line. elif isdupkey: if on_dup.key is RAISE: raise KeyDuplicationError(key) if on_dup.key is DROP_NEW: return None assert on_dup.key is DROP_OLD # Fall through to the return statement on the last line. elif isdupval: if on_dup.val is RAISE: raise ValueDuplicationError(val) if on_dup.val is DROP_NEW: return None assert on_dup.val is DROP_OLD # Fall through to the return statement on the last line. # else no key or value duplication. return oldkey, oldval def _write(self, newkey: KT, newval: VT, oldkey: OKT[KT], oldval: OVT[VT], unwrites: Unwrites | None) -> None: """Insert (newkey, newval), extending *unwrites* with associated inverse operations if provided. *oldkey* and *oldval* are as returned by :meth:`_dedup`. If *unwrites* is not None, it is extended with the inverse operations necessary to undo the write. This design allows :meth:`_update` to roll back a partially applied update that fails part-way through when necessary. This design also allows subclasses that require additional operations to easily extend this implementation. For example, :class:`bidict.OrderedBidictBase` calls this inherited implementation, and then extends *unwrites* with additional operations needed to keep its internal linked list nodes consistent with its items' order as changes are made. """ fwdm, invm = self._fwdm, self._invm fwdm_set, invm_set = fwdm.__setitem__, invm.__setitem__ fwdm_del, invm_del = fwdm.__delitem__, invm.__delitem__ # When newkey or newval duplicates one already contained, adopt the object already # contained rather than the one passed in. Otherwise the two backing mappings would end # up referring to equal but distinct objects for the same item, since a dict keeps the # key object it already has when a key is overwritten but takes the new value object. # invm[oldval] is the contained key equal to newkey; fwdm[oldkey] the contained value # equal to newval. This also matches what a plain dict does on overwrite. if oldval is not MISSING: # newkey duplicates a contained key newkey = invm[oldval] if oldkey is not MISSING: # newval duplicates a contained value newval = fwdm[oldkey] # Record each unwrite as soon as its write succeeds, rather than all of them at the end: # a backing mapping is user-supplied (see _fwdm_cls/_invm_cls) and may reject a write, and # if it does, everything written before it still has to be undone. Note that the four # writes below touch four distinct slots, so the order they are undone in does not matter. fwdm_set(newkey, newval) if unwrites is not None: # {0: 1} | {2: 3} => del fwdm[2]; {0: 1} | {0: 3} => fwdm[0] = 1 unwrites.append((fwdm_del, newkey) if oldval is MISSING else (fwdm_set, newkey, oldval)) invm_set(newval, newkey) if unwrites is not None: # {0: 1} | {2: 3} => del invm[3]; {0: 1} | {2: 1} => invm[1] = 0 unwrites.append((invm_del, newval) if oldkey is MISSING else (invm_set, newval, oldkey)) if oldkey is not MISSING: # newval duplicates the value of the item keyed by oldkey # {0: 1, 2: 3} | {4: 3} => {0: 1, 4: 3} fwdm_del(oldkey) if unwrites is not None: unwrites.append((fwdm_set, oldkey, newval)) if oldval is not MISSING: # newkey duplicates the key of the item valued by oldval # {0: 1, 2: 3} | {2: 4} => {0: 1, 2: 4} invm_del(oldval) if unwrites is not None: unwrites.append((invm_set, oldval, newkey)) def _update( self, arg: MapOrItems[KT, VT], kw: Mapping[str, VT] = MappingProxyType({}), *, rollback: bool = True, on_dup: OnDup | None = None, ) -> None: """Update with the items from *arg* and *kw*, failing clean as per *rollback*. When *rollback* is true (the default), a failure part-way through leaves self exactly as it was before the update was attempted. Callers pass rollback=False only when self is a throwaway instance that is discarded if the update fails, and so has nothing to roll back to. """ # Note: We must process input in a single pass, since arg may be a generator. if not isinstance(arg, (Iterable, Maplike)): raise TypeError(f"'{arg.__class__.__name__}' object is not iterable") if not arg and not kw: return if on_dup is None: on_dup = self.on_dup # Fast path when we're empty and updating only from another bidict (i.e. no dup vals in new items). if not self and not kw and isinstance(arg, BidictBase): self._init_from(arg) return # Fast path when we're adding more items than we contain already and rollback is enabled: # Update a copy of self with rollback disabled. Fail if that fails, otherwise become the copy. if rollback and isinstance(arg, Sized) and len(arg) + len(kw) > len(self): tmp = self.copy() tmp._update(arg, kw, rollback=False, on_dup=on_dup) self._init_from(tmp) return # In all other cases, benchmarking has indicated that the update is best implemented as follows: # For each new item, perform a dup check (raising if necessary), and apply the associated writes we need to # perform on our backing _fwdm and _invm mappings. If rollback is enabled, also compute the associated unwrites # as we go. If item unpacking, duplication checking, or writing raises while rollback is enabled, apply the # accumulated unwrites before re-raising, to ensure that we fail clean. write = self._write unwrites: Unwrites | None = [] if rollback else None try: for key, val in iteritems(arg, **kw): dedup_result = self._dedup(key, val, on_dup) if dedup_result is not None: write(key, val, *dedup_result, unwrites=unwrites) except Exception: if unwrites is not None: for fn, *args in reversed(unwrites): fn(*args) raise def __copy__(self) -> t.Self: """Used for the copy protocol. See the :mod:`copy` module.""" return self.copy() def copy(self) -> t.Self: """Make a (shallow) copy of this bidict.""" # Could just `return self.__class__(self)` here, but the below is faster. The former # would copy this bidict's items into a new instance one at a time (checking for duplication # for each item), whereas the below copies from the backing mappings all at once, and foregoes # item-by-item duplication checking since the backing mappings have been checked already. return self._from_other(self) @classmethod def _from_other(cls, other: MapOrItems[KT, VT]) -> t.Self: """Fast, private constructor based on :meth:`_init_from`.""" inst = cls() inst._init_from(other) return inst def _init_from(self, other: MapOrItems[KT, VT]) -> None: """Fast init from *other*, bypassing item-by-item duplication checking.""" self._fwdm.clear() self._invm.clear() self._fwdm.update(other) # If other is a bidict, use its existing backing inverse mapping, otherwise # other could be a generator that's now exhausted, so invert self._fwdm on the fly. if isinstance(other, BidictBase): self._invm.update(t.cast('BidictBase[KT, VT]', other).inverse) else: self._invm.update(inverted(self._fwdm)) # other's type is Mapping rather than Maplike since bidict() | SupportsKeysAndGetItem({}) # raises a TypeError, just like dict() | SupportsKeysAndGetItem({}) does. def __or__(self, other: Mapping[KT, VT]) -> t.Self: """Return self|other.""" if not isinstance(other, Mapping): return NotImplemented new = self.copy() new._update(other, rollback=False) return new def __ror__(self, other: Mapping[KT, VT]) -> t.Self: """Return other|self.""" if not isinstance(other, Mapping): return NotImplemented # False positive in ty: https://github.com/astral-sh/ty/issues/4278 new = self.__class__(other) # ty: ignore[invalid-argument-type] new._update(self, rollback=False) return new @override def __len__(self) -> int: """The number of contained items.""" return len(self._fwdm) @override def __iter__(self) -> Iterator[KT]: """Iterator over the contained keys.""" return iter(self._fwdm) @override def __getitem__(self, key: KT) -> VT: """*x.__getitem__(key) ⟺ x[key]*""" return self._fwdm[key] @override def __reduce__(self) -> tuple[t.Any, ...]: """Return state information for pickling.""" return self.__class__._from_other, (dict(self),) # See BidictBase._set_reversed() above. def _fwdm_reversed(self: BidictBase[KT, t.Any]) -> Iterator[KT]: """Iterator over the contained keys in reverse order.""" return reversed(t.cast('Reversible[KT]', self._fwdm)) BidictBase._init_class() # For better performance, make ProxiedSetView subclasses delegate to backing dicts for the # methods they inherit from collections.abc.Set. (Cannot delegate for __iter__ and # __reversed__ since they are order-sensitive.) See also: https://bugs.python.org/issue46713 _setmethodnames: Iterable[str] = ( '__lt__', '__le__', '__gt__', '__ge__', '__eq__', '__ne__', '__sub__', '__rsub__', '__or__', '__ror__', '__xor__', '__rxor__', '__and__', '__rand__', 'isdisjoint', ) # fmt: skip def _override_set_methods_to_use_backing_dict(cls: type[ProxiedSetView]) -> None: def make_proxy_method(methodname: str) -> t.Any: def method(self: ProxiedSetView, *args: t.Any) -> t.Any: fwdm = self._mapping._fwdm if not isinstance(fwdm, dict): # dict view speedup not available, fall back to Set's implementation. return getattr(Set, methodname)(self, *args) fwdm_dict_view = getattr(fwdm, self._viewname)() fwdm_dict_view_method = getattr(fwdm_dict_view, methodname) # When the (single) arg is another ProxiedSetView backed by a dict, forward its # backing dict_keys/dict_items to the C-level method rather than the arg itself. C-level dict views # only interoperate with other C-level dict views, not with arbitrary Set subclasses, so e.g. # `dict_keys(ob1).__lt__(ob2.keys())` returns NotImplemented. With both sides returning # NotImplemented, Python either raises TypeError (for `<`, `<=`, `>`, `>=`) or falls back to the # wrong answer (e.g. identity-based `==`). Note arg's view may differ from self's (keys vs items), # so use arg._viewname; this also subsumes the same-type case, where it equals self._viewname. if len(args) == 1 and isinstance((arg := args[0]), ProxiedSetView) and isinstance(arg._mapping._fwdm, dict): arg_dict_view = getattr(arg._mapping._fwdm, arg._viewname)() return fwdm_dict_view_method(arg_dict_view) return fwdm_dict_view_method(*args) method.__name__ = methodname method.__qualname__ = f'{cls.__qualname__}.{methodname}' return method for name in _setmethodnames: setattr(cls, name, make_proxy_method(name)) _override_set_methods_to_use_backing_dict(BidictValuesView) class GeneratedBidictInverse: """Base class for dynamically-generated inverse bidict classes.""" # * Code review nav * # ============================================================================ # â†� Prev: _abc.py Current: _base.py Next: _frozen.py → # ============================================================================ bidict-0.24.1/bidict/_bidict.py000066400000000000000000000202141524342314000162360ustar00rootroot00000000000000# Copyright 2009-2026 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/. # * Code review nav * # (see comments in __init__.py) # ============================================================================ # â†� Prev: _frozen.py Current: _bidict.py Next: _orderedbase.py → # ============================================================================ """Provide :class:`MutableBidict` and :class:`bidict`.""" from __future__ import annotations import typing as t from collections.abc import Mapping from ._abc import MutableBidirectionalMapping from ._base import BidictBase from ._base import Unwrites from ._dup import ON_DUP_DROP_OLD from ._dup import ON_DUP_RAISE from ._dup import OnDup from ._typing import DT from ._typing import KT from ._typing import MISSING from ._typing import ODT from ._typing import VT from ._typing import MapOrItems from ._typing import override class MutableBidict(BidictBase[KT, VT], MutableBidirectionalMapping[KT, VT]): """Base class for mutable bidirectional mappings.""" if t.TYPE_CHECKING: @property @override def inverse(self) -> MutableBidict[VT, KT]: ... @property @override def inv(self) -> MutableBidict[VT, KT]: ... def _pop(self, key: KT) -> VT: return self._pop_invm(key, self._fwdm.pop(key)) def _pop_invm(self, key: KT, val: VT) -> VT: """Remove *val* from _invm, *key* having already been removed from _fwdm. Puts (key, val) back if _invm refuses the removal, so that a backing mapping rejecting one half of a removal cannot leave the two disagreeing. This is the removing counterpart of the unwrites that :meth:`BidictBase._write` records. """ try: del self._invm[val] except Exception: self._fwdm[key] = val raise return val @override def __delitem__(self, key: KT) -> None: """*x.__delitem__(y) ⟺ del x[y]*""" self._pop(key) @override def __setitem__(self, key: KT, val: VT) -> None: """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 behavior 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. """ self.put(key, val, on_dup=self.on_dup) def put(self, key: KT, val: VT, on_dup: OnDup = ON_DUP_RAISE) -> None: """Associate *key* with *val*, honoring the :class:`OnDup` given in *on_dup*. For example, if *on_dup* is :attr:`~bidict.ON_DUP_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.val* is :attr:`~bidict.RAISE`. """ # Rather than self._update(((key, val),), on_dup=on_dup): a single item needs none of # the argument-type dispatch, iteration, or bulk fast paths that _update() provides, and # they cost several times what writing the item does. Rollback is still required, since # OrderedBidictBase._write() can fail after the write it delegates to has succeeded. dedup_result = self._dedup(key, val, on_dup) if dedup_result is None: return unwrites: Unwrites = [] try: self._write(key, val, *dedup_result, unwrites=unwrites) except Exception: for fn, *args in reversed(unwrites): fn(*args) raise def forceput(self, key: KT, val: VT) -> None: """Associate *key* with *val* unconditionally. Replace any existing mappings containing key *key* or value *val* as necessary to preserve uniqueness. """ self.put(key, val, on_dup=ON_DUP_DROP_OLD) @override def clear(self) -> None: """Remove all items.""" self._fwdm.clear() self._invm.clear() @t.overload def pop(self, key: KT, /) -> VT: ... @t.overload def pop(self, key: KT, default: DT = ..., /) -> VT | DT: ... @override def pop(self, key: KT, default: ODT[DT] = MISSING, /) -> VT | DT: """*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 MISSING: raise return default @override def popitem(self) -> tuple[KT, VT]: """*x.popitem() → (k, v)* Remove and return some item as a (key, value) pair. :raises KeyError: if *x* is empty. """ key, val = self._fwdm.popitem() return key, self._pop_invm(key, val) @override def update(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None: """Like calling :meth:`putall` with *self.on_dup* passed for *on_dup*.""" self._update(arg, kw=kw) def forceupdate(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None: """Like a bulk :meth:`forceput`.""" self._update(arg, kw=kw, on_dup=ON_DUP_DROP_OLD) def putall(self, items: MapOrItems[KT, VT], on_dup: OnDup = ON_DUP_RAISE) -> None: """Like a bulk :meth:`put`. If one of the given items causes an exception to be raised, none of the items is inserted. """ self._update(items, on_dup=on_dup) # other's type is Mapping rather than Maplike since bidict() |= SupportsKeysAndGetItem({}) # raises a TypeError, just like dict() |= SupportsKeysAndGetItem({}) does. def __ior__(self, other: Mapping[KT, VT]) -> t.Self: """Return self|=other.""" self.update(other) return self class bidict(MutableBidict[KT, VT]): """The main bidirectional mapping type. See :ref:`intro:Introduction` and :ref:`basic-usage:Basic Usage` to get started (also available at https://bidict.rtfd.io). """ if t.TYPE_CHECKING: @property @override def inverse(self) -> bidict[VT, KT]: ... @property @override def inv(self) -> bidict[VT, KT]: ... # * Code review nav * # ============================================================================ # â†� Prev: _frozen.py Current: _bidict.py Next: _orderedbase.py → # ============================================================================ bidict-0.24.1/bidict/_dup.py000066400000000000000000000041141524342314000155710ustar00rootroot00000000000000# Copyright 2009-2026 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/. """Provide :class:`OnDup` and related functionality.""" from __future__ import annotations import typing as t from enum import Enum from ._typing import override class OnDupAction(Enum): """An action to take to prevent duplication from occurring.""" #: Raise a :class:`~bidict.DuplicationError`. RAISE = 'RAISE' #: Overwrite existing items with new items. DROP_OLD = 'DROP_OLD' #: Keep existing items and drop new items. DROP_NEW = 'DROP_NEW' @override def __repr__(self) -> str: return f'{self.__class__.__name__}.{self.name}' RAISE: t.Final[OnDupAction] = OnDupAction.RAISE DROP_OLD: t.Final[OnDupAction] = OnDupAction.DROP_OLD DROP_NEW: t.Final[OnDupAction] = OnDupAction.DROP_NEW class OnDup(t.NamedTuple): r"""A combination of :class:`~bidict.OnDupAction`\s specifying how to handle various types of duplication. The :attr:`~OnDup.key` field specifies what action to take when a duplicate key is encountered. The :attr:`~OnDup.val` field specifies what action to take when a duplicate value is encountered. In the case of both key and value duplication across two different items, only :attr:`~OnDup.val` is used. *See also* :ref:`basic-usage:Values Must Be Unique` (https://bidict.rtfd.io/basic-usage.html#values-must-be-unique) """ key: OnDupAction = DROP_OLD val: OnDupAction = RAISE #: Default :class:`OnDup` used for the #: :meth:`~bidict.bidict.__init__`, #: :meth:`~bidict.bidict.__setitem__`, and #: :meth:`~bidict.bidict.update` methods. ON_DUP_DEFAULT: t.Final[OnDup] = OnDup(key=DROP_OLD, val=RAISE) #: An :class:`OnDup` whose members are all :obj:`RAISE`. ON_DUP_RAISE: t.Final[OnDup] = OnDup(key=RAISE, val=RAISE) #: An :class:`OnDup` whose members are all :obj:`DROP_OLD`. ON_DUP_DROP_OLD: t.Final[OnDup] = OnDup(key=DROP_OLD, val=DROP_OLD) bidict-0.24.1/bidict/_exc.py000066400000000000000000000020521524342314000155570ustar00rootroot00000000000000# Copyright 2009-2026 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/. """Provide all bidict exceptions.""" from __future__ import annotations class BidictException(Exception): """Base class for bidict exceptions.""" class DuplicationError(BidictException): """Base class for exceptions raised when uniqueness is violated as per the :attr:`~bidict.RAISE` :class:`~bidict.OnDupAction`. """ 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.24.1/bidict/_frozen.py000066400000000000000000000035371524342314000163140ustar00rootroot00000000000000# Copyright 2009-2026 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/. # * Code review nav * # (see comments in __init__.py) # ============================================================================ # â†� Prev: _base.py Current: _frozen.py Next: _bidict.py → # ============================================================================ """Provide :class:`frozenbidict`, an immutable, hashable bidirectional mapping type.""" from __future__ import annotations import typing as t from collections.abc import ItemsView from ._base import BidictBase from ._typing import KT from ._typing import VT from ._typing import override class frozenbidict(BidictBase[KT, VT]): """Immutable, hashable bidict type.""" _hash: int if t.TYPE_CHECKING: @property @override def inverse(self) -> frozenbidict[VT, KT]: ... @property @override def inv(self) -> frozenbidict[VT, KT]: ... @override def __hash__(self) -> int: """The hash of this bidict as determined by its items.""" if getattr(self, '_hash', None) is None: # The following is like hash(frozenset(self.items())) # but more memory efficient. See also: https://bugs.python.org/issue46684 self._hash = ItemsView(self)._hash() return self._hash # * Code review nav * # ============================================================================ # â†� Prev: _base.py Current: _frozen.py Next: _bidict.py → # ============================================================================ bidict-0.24.1/bidict/_iter.py000066400000000000000000000037021524342314000157460ustar00rootroot00000000000000# Copyright 2009-2026 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/. """Functions for iterating over items in a mapping.""" from __future__ import annotations import typing as t from collections.abc import Mapping from operator import itemgetter from ._typing import KT from ._typing import VT from ._typing import ItemsIter from ._typing import Maplike from ._typing import MapOrItems def iteritems(arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> ItemsIter[KT, VT]: """Yield the items from *arg* and *kw* in the order given.""" if isinstance(arg, Mapping): yield from t.cast('Mapping[KT, VT]', arg).items() # isinstance() against a runtime-checkable Protocol is cheap when it succeeds but expensive # when it fails: it falls back to inspect.getattr_static() per member and caches nothing. # It fails for an iterable of items, which is what every single-item write passes, so screen # that case out first -- a Maplike has a keys attribute by definition. elif hasattr(arg, 'keys') and isinstance(arg, Maplike): yield from ((key, arg[key]) for key in arg.keys()) else: yield from arg yield from t.cast('ItemsIter[KT, VT]', kw.items()) swap: t.Final = itemgetter(1, 0) def inverted(arg: MapOrItems[KT, VT]) -> ItemsIter[VT, KT]: """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__` """ invattr = getattr(arg, '__inverted__', None) if callable(invattr): inv: ItemsIter[VT, KT] = invattr() return inv return map(swap, iteritems(arg)) bidict-0.24.1/bidict/_orderedbase.py000066400000000000000000000346471524342314000172760ustar00rootroot00000000000000# Copyright 2009-2026 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/. # * Code review nav * # (see comments in __init__.py) # ============================================================================ # â†� Prev: _bidict.py Current: _orderedbase.py Next: _orderedbidict.py → # ============================================================================ """Provide :class:`OrderedBidictBase`.""" from __future__ import annotations import typing as t from collections.abc import ItemsView from collections.abc import Iterator from collections.abc import KeysView from weakref import ref as weakref from ._base import BidictBase from ._base import BidictKeysView from ._base import ProxiedSetView from ._base import Unwrites from ._base import _override_set_methods_to_use_backing_dict from ._bidict import bidict from ._iter import iteritems from ._typing import KT from ._typing import MISSING from ._typing import OKT from ._typing import OVT from ._typing import VT from ._typing import MapOrItems from ._typing import override AT = t.TypeVar('AT') # attr type _MUTATED_DURING_ITERATION: t.Final = 'ordered bidict mutated during iteration' class WeakAttr(t.Generic[AT]): """Descriptor to automatically manage (de)referencing the given slot as a weakref. See https://docs.python.org/3/howto/descriptor.html#managed-attributes for an intro to using descriptors like this for managed attributes. """ def __init__(self, *, slot: str) -> None: self.slot = slot def __set__(self, instance: t.Any, value: AT) -> None: setattr(instance, self.slot, weakref(value)) @t.overload def __get__(self, instance: None, owner: type) -> t.Self: ... @t.overload def __get__(self, instance: object, owner: type) -> AT: ... def __get__(self, instance: object | None, owner: type) -> t.Self | AT: if instance is None: return self return getattr(instance, self.slot)() # deref the weakref stored in the slot; typed via the overloads above class Node: """A node in a circular doubly-linked list used to encode the order of items in an ordered bidict. A weak reference to the previous node is stored to avoid creating strong reference cycles. Referencing/dereferencing the weakref is handled automatically by :class:`WeakAttr`. """ prv: WeakAttr[Node] = WeakAttr(slot='_prv_weak') # nxt is a plain (strong-ref) slot on the base Node; SentinelNode overrides it # below with a WeakAttr to break the otherwise-strong cycle around the circular list. nxt: Node __slots__ = ('__weakref__', '_prv_weak', 'nxt') def __init__(self, prv: Node, nxt: Node) -> None: self.prv = prv self.nxt = nxt def unlink(self) -> None: """Remove self from in between prv and nxt. Self's references to prv and nxt are retained so it can be relinked (see below). """ self.prv.nxt = self.nxt self.nxt.prv = self.prv def relink(self) -> None: """Restore self between prv and nxt after unlinking (see above).""" self.prv.nxt = self.nxt.prv = self class SentinelNode(Node): """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. """ nxt: WeakAttr[Node] = WeakAttr(slot='_nxt_weak') # override base's plain slot with a weakref #: Snapshot token, bumped by :meth:`mutated` on every structural change to the list, so #: that iterators can detect one. Compared for equality only; its magnitude means nothing. #: Lives here rather than on the owning bidict because a bidict and its inverse share this #: sentinel, and so must invalidate each other's iterators. version: int __slots__ = ('_nxt_weak', 'version') def __init__(self) -> None: self.version = 0 super().__init__(self, self) def mutated(self) -> None: """Record a structural change to the list, invalidating any iterators over it.""" self.version += 1 def reset(self) -> None: """Empty the list.""" self.nxt = self.prv = self self.mutated() def iternodes(self, *, reverse: bool = False) -> Iterator[Node]: """Iterator yielding nodes in the requested order. Raises :class:`RuntimeError` if the list is structurally modified while iterating, as :class:`dict` and :class:`collections.OrderedDict` do. """ # Not a generator: the version is captured when the iterator is created rather than when it # is first advanced, so mutating in between is detected too, as OrderedDict does. return self._iternodes(self.version, reverse=reverse) def _iternodes(self, initial_version: int, *, reverse: bool) -> Iterator[Node]: # Advance via a literal attr name rather than getattr(node, 'prv' if reverse else 'nxt'): # the dynamic lookup the latter needs costs more per node than everything else in # this loop put together, since only a literal gets CPython's specialized LOAD_ATTR. # (operator.attrgetter does not help: it is a call, not a load.) node = self.prv if reverse else self.nxt while node is not self: if self.version != initial_version: raise RuntimeError(_MUTATED_DURING_ITERATION) yield node node = node.prv if reverse else node.nxt # Check on the step that finds the end too, so that a mutation which happens to leave the # iterator pointing at the sentinel is caught as well -- e.g. move_to_end() of the item # just yielded, which relinks it to exactly where iteration is about to stop. if self.version != initial_version: raise RuntimeError(_MUTATED_DURING_ITERATION) def new_last_node(self) -> Node: """Create and return a new terminal node.""" old_last = self.prv new_last = Node(old_last, self) old_last.nxt = self.prv = new_last self.mutated() return new_last class OrderedBidictBase(BidictBase[KT, VT]): """Base class implementing an ordered :class:`BidirectionalMapping`.""" _node_by_korv: bidict[t.Any, Node] _bykey: bool def __init__(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None: """Make a new ordered bidirectional mapping. The signature behaves like that of :class:`dict`. Items passed in are added in the order they are passed, respecting the :attr:`~bidict.BidictBase.on_dup` class attribute in the process. The order in which items are inserted is remembered, similar to :class:`collections.OrderedDict`. """ self._sntl = SentinelNode() self._node_by_korv = bidict() self._bykey = True super().__init__(arg, **kw) if t.TYPE_CHECKING: @property @override def inverse(self) -> OrderedBidictBase[VT, KT]: ... @property @override def inv(self) -> OrderedBidictBase[VT, KT]: ... @override def _make_inverse(self) -> OrderedBidictBase[VT, KT]: inv = t.cast('OrderedBidictBase[VT, KT]', super()._make_inverse()) inv._sntl = self._sntl inv._node_by_korv = self._node_by_korv inv._bykey = not self._bykey return inv def _assoc_node(self, node: Node, key: KT, val: VT) -> None: korv = key if self._bykey else val self._node_by_korv.forceput(korv, node) def _dissoc_node(self, node: Node) -> None: del self._node_by_korv.inverse[node] node.unlink() self._sntl.mutated() def _relink_node(self, node: Node) -> None: """Undo a :meth:`_dissoc_node` (the linked list half of it). See :meth:`_write`.""" node.relink() self._sntl.mutated() @override def _init_from(self, other: MapOrItems[KT, VT]) -> None: """See :meth:`BidictBase._init_from`.""" super()._init_from(other) bykey = self._bykey korv_by_node = self._node_by_korv.inverse korv_by_node.clear() korv_by_node_set = korv_by_node.__setitem__ self._sntl.reset() new_node = self._sntl.new_last_node for k, v in iteritems(other): korv_by_node_set(new_node(), k if bykey else v) @override def _write(self, newkey: KT, newval: VT, oldkey: OKT[KT], oldval: OVT[VT], unwrites: Unwrites | None) -> None: super()._write(newkey, newval, oldkey, oldval, unwrites) assoc, dissoc, relink = self._assoc_node, self._dissoc_node, self._relink_node node_by_korv, bykey = self._node_by_korv, self._bykey if oldval is MISSING and oldkey is MISSING: # no key or value duplication # {0: 1, 2: 3} | {4: 5} => {0: 1, 2: 3, 4: 5} newnode = self._sntl.new_last_node() assoc(newnode, newkey, newval) if unwrites is not None: unwrites.append((dissoc, newnode)) elif oldval is not MISSING and oldkey is not MISSING: # key and value duplication across two different items # {0: 1, 2: 3} | {0: 3} => {0: 3} # n1, n2 => n1 (collapse n1 and n2 into n1) # oldkey: 2, oldval: 1, oldnode: n2, newkey: 0, newval: 3, newnode: n1 if bykey: oldnode = node_by_korv[oldkey] newnode = node_by_korv[newkey] else: oldnode = node_by_korv[newval] newnode = node_by_korv[oldval] dissoc(oldnode) assoc(newnode, newkey, newval) if unwrites is not None: unwrites.extend(( (assoc, newnode, newkey, oldval), (assoc, oldnode, oldkey, newval), (relink, oldnode), )) elif oldval is not MISSING: # just key duplication # {0: 1, 2: 3} | {2: 4} => {0: 1, 2: 4} # oldkey: MISSING, oldval: 3, newkey: 2, newval: 4 node = node_by_korv[newkey if bykey else oldval] assoc(node, newkey, newval) if unwrites is not None: unwrites.append((assoc, node, newkey, oldval)) else: assert oldkey is not MISSING # just value duplication # {0: 1, 2: 3} | {4: 3} => {0: 1, 4: 3} # oldkey: 2, oldval: MISSING, newkey: 4, newval: 3 node = node_by_korv[oldkey if bykey else newval] assoc(node, newkey, newval) if unwrites is not None: unwrites.append((assoc, node, oldkey, newval)) @override def __iter__(self) -> Iterator[KT]: """Iterator over the contained keys in insertion order.""" return self._iter(reverse=False) @override def __reversed__(self) -> Iterator[KT]: """Iterator over the contained keys in reverse insertion order.""" return self._iter(reverse=True) def _iter(self, *, reverse: bool = False) -> Iterator[KT]: # Not a generator, so that the version is captured now rather than on the first # next() call, and an iterator created before a mutation still detects it. Calls # _iternodes() directly rather than iternodes(), to skip a call on this hot path. sntl = self._sntl nodes = sntl._iternodes(sntl.version, reverse=reverse) korv_by_node = self._node_by_korv.inverse if self._bykey: return (korv_by_node[node] for node in nodes) key_by_val = self._invm return (key_by_val[korv_by_node[node]] for node in nodes) # Override the keys() and items() implementations inherited from BidictBase, which may # delegate to the backing _fwdm dict: an ordered bidict's order is encoded in its linked # list, not in _fwdm, and the two can disagree. That happens after any mutation that # changes an existing item, but also during __init__ itself, since a value-duplication # overwrite reuses the existing item's node (keeping its position) while _fwdm gets the # new key appended and the old one deleted. So these must be overridden here rather than # in OrderedBidict, to cover immutable ordered bidicts too. @override def keys(self) -> KeysView[KT]: """A set-like object providing a view on the contained keys.""" return _OrderedBidictKeysView(self) @override def items(self) -> ItemsView[KT, VT]: """A set-like object providing a view on the contained items.""" return _OrderedBidictItemsView(self) @override def values(self) -> BidictKeysView[VT]: """A set-like object providing a view on the contained values.""" # Unlike a non-ordered bidict, whose BidictValuesView has to iterate the backing # _fwdm to yield values in key order (see BidictBase.values()), an ordered bidict # gets that for free: the inverse shares this bidict's linked list, so its keys # view already yields the values in this bidict's order. return t.cast('BidictKeysView[VT]', self.inverse.keys()) # The following MappingView implementations use the __iter__ implementations # inherited from their superclass counterparts in collections.abc, so they # continue to yield items in the correct order even after an ordered bidict # is mutated. They also provide a __reversed__ implementation, which is not # provided by the collections.abc superclasses. class _OrderedBidictKeysView(ProxiedSetView, BidictKeysView[KT]): _mapping: OrderedBidictBase[KT, t.Any] _viewname: t.ClassVar[str] = 'keys' __slots__ = () def __reversed__(self) -> Iterator[KT]: return reversed(self._mapping) class _OrderedBidictItemsView(ProxiedSetView, ItemsView[KT, VT]): _mapping: OrderedBidictBase[KT, VT] _viewname: t.ClassVar[str] = 'items' __slots__ = () def __reversed__(self) -> Iterator[tuple[KT, VT]]: ob = self._mapping for key in reversed(ob): yield key, ob[key] _override_set_methods_to_use_backing_dict(_OrderedBidictKeysView) _override_set_methods_to_use_backing_dict(_OrderedBidictItemsView) # * Code review nav * # ============================================================================ # â†� Prev: _bidict.py Current: _orderedbase.py Next: _orderedbidict.py → # ============================================================================ bidict-0.24.1/bidict/_orderedbidict.py000066400000000000000000000062321524342314000176070ustar00rootroot00000000000000# Copyright 2009-2026 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/. # * Code review nav * # (see comments in __init__.py) # ============================================================================ # â†� Prev: _orderedbase.py Current: _orderedbidict.py # ============================================================================ """Provide :class:`OrderedBidict`.""" from __future__ import annotations import typing as t from ._bidict import MutableBidict from ._orderedbase import OrderedBidictBase from ._typing import KT from ._typing import VT from ._typing import override class OrderedBidict(OrderedBidictBase[KT, VT], MutableBidict[KT, VT]): """Mutable bidict type that maintains items in insertion order.""" if t.TYPE_CHECKING: @property @override def inverse(self) -> OrderedBidict[VT, KT]: ... @property @override def inv(self) -> OrderedBidict[VT, KT]: ... @override def clear(self) -> None: """Remove all items.""" super().clear() self._node_by_korv.clear() self._sntl.reset() @override def _pop(self, key: KT) -> VT: val = super()._pop(key) node = self._node_by_korv[key if self._bykey else val] self._dissoc_node(node) return val @override def popitem(self, last: bool = True) -> tuple[KT, VT]: """*b.popitem() → (k, v)* If *last* is true, remove and return the most recently added item as a (key, value) pair. Otherwise, remove and return the least recently added item. :raises KeyError: if *b* is empty. """ if not self: raise KeyError('OrderedBidict is empty') node = getattr(self._sntl, 'prv' if last else 'nxt') korv = self._node_by_korv.inverse[node] if self._bykey: return korv, self._pop(korv) return self.inverse._pop(korv), korv def move_to_end(self, key: KT, last: bool = True) -> None: """Move the item with the given key to the end if *last* is true, else to the beginning. :raises KeyError: if *key* is missing """ korv = key if self._bykey else self._fwdm[key] node = self._node_by_korv[korv] node.prv.nxt = node.nxt node.nxt.prv = node.prv sntl = self._sntl sntl.mutated() if last: lastnode = sntl.prv node.prv = lastnode node.nxt = sntl sntl.prv = lastnode.nxt = node else: firstnode = sntl.nxt node.prv = sntl node.nxt = firstnode sntl.nxt = firstnode.prv = node # * Code review nav * # ============================================================================ # â†� Prev: _orderedbase.py Current: _orderedbidict.py # ============================================================================ bidict-0.24.1/bidict/_typing.py000066400000000000000000000026021524342314000163130ustar00rootroot00000000000000# Copyright 2009-2026 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/. """Provide typing-related objects.""" from __future__ import annotations import sys import typing as t from collections.abc import Iterable from collections.abc import Iterator from enum import Enum if sys.version_info >= (3, 12): from typing import override as override else: from typing_extensions import override as override KT = t.TypeVar('KT') VT = t.TypeVar('VT') VT_co = t.TypeVar('VT_co', covariant=True) MissingT = Enum('MissingT', {'MISSING': 'MISSING'}) MISSING: t.Final[t.Literal[MissingT.MISSING]] = MissingT.MISSING OKT: t.TypeAlias = KT | MissingT #: optional key type OVT: t.TypeAlias = VT | MissingT #: optional value type DT = t.TypeVar('DT') #: for default arguments ODT: t.TypeAlias = DT | MissingT #: optional default arg type Items: t.TypeAlias = Iterable[tuple[KT, VT]] ItemsIter: t.TypeAlias = Iterator[tuple[KT, VT]] @t.runtime_checkable class Maplike(t.Protocol[KT, VT_co]): """Like typeshed's SupportsKeysAndGetItem, but usable at runtime.""" def keys(self) -> Iterable[KT]: ... def __getitem__(self, key: KT, /) -> VT_co: ... MapOrItems: t.TypeAlias = Maplike[KT, VT] | Items[KT, VT] bidict-0.24.1/bidict/py.typed000066400000000000000000000000201524342314000157570ustar00rootroot00000000000000PEP-561 marker. bidict-0.24.1/cachegrind.py000077500000000000000000000125061524342314000155020ustar00rootroot00000000000000#!/usr/bin/env python3 # Based on https://github.com/pythonspeed/cachegrind-benchmarking/blob/main/cachegrind.py """ Run a program under Cachegrind, combining various metrics into one single performance metric. License: https://opensource.org/licenses/MIT ## Features * Disables ASLR. * Sets consistent cache sizes. * Calculates a combined performance metric. For more information see the detailed write up at: https://pythonspeed.com/articles/consistent-benchmarking-in-ci/ ## Usage $ python3 cachegrind.py ./yourprogram --yourparam=yourvalues If you're benchmarking Python, make sure to set PYTHONHASHSEED to a fixed value (e.g. `export PYTHONHASHSEED=1234`). Other languages may have similar requirements to reduce variability. The last line printed will be a combined performance metric, but you can tweak the script to extract more info, or use it as a library. Copyright © 2020, Hyphenated Enterprises LLC. """ from __future__ import annotations import os import subprocess as sp import sys import typing as t from pathlib import Path from tempfile import NamedTemporaryFile try: sp.check_call(['setarch', '-h'], stdout=sp.DEVNULL, stderr=sp.DEVNULL) sp.check_call(['valgrind', '-h'], stdout=sp.DEVNULL, stderr=sp.DEVNULL) except FileNotFoundError as exc: # e.g. macOS raise SystemExit(f'Command not found: {exc.filename}') from None ARCH = sp.check_output(['uname', '-m'], text=True).strip() DISABLE_ASLR_CMD = ['setarch', ARCH, '-R'] def run_with_cachegrind(args_list: list[str]) -> tuple[int, dict[str, int]]: """ Run the the given program and arguments under Cachegrind, parse the Cachegrind specs. Return the program's exit status along with the parsed results. For now we just ignore program output, and in general this is not robust. """ # Deliberately not a context manager: this stays open across the run below, which writes to # it, and is read afterwards. temp_file = NamedTemporaryFile('r+', encoding='utf-8') # ruff: ignore[open-file-with-context-handler] # Don't raise if the program fails (to support e.g. `pytest --benchmark-compare-fail=...`), # but do return its status so that main() can exit with it. Callers such as the benchmark # workflow rely on it to tell a benchmark regression from a clean run. returncode = sp.call([ *DISABLE_ASLR_CMD, 'valgrind', '--tool=cachegrind', '--cache-sim=yes', # Set some reasonable L1 and LL values, based on Haswell. # Feel free to update, important part is that they are consistent across runs, # instead of the default of copying from the current machine. '--I1=32768,8,64', '--D1=32768,8,64', '--LL=8388608,16,64', '--cachegrind-out-file=' + temp_file.name, *args_list, ]) return returncode, parse_cachegrind_output(temp_file) def parse_cachegrind_output(temp_file: t.IO[str]) -> dict[str, int]: header = summary = '' for line in temp_file: if line.startswith('events: '): header = line[len('events: ') :].strip() elif line.startswith('summary: '): summary = line[len('summary:') :].strip() assert header assert summary return dict(zip(header.split(), (int(i) for i in summary.split()), strict=False)) def get_counts(cg_results: dict[str, int]) -> dict[str, int]: """ Given the result of run_with_cachegrind(), figure out the parameters we will use for final estimate. We pretend there's no L2 since Cachegrind doesn't currently support it. Caveats: we're not including time to process instructions, only time to access instruction cache(s), so we're assuming time to fetch and run_with_cachegrind instruction is the same as time to retrieve data if they're both to L1 cache. """ result = {} d = cg_results ram_hits = d['DLmr'] + d['DLmw'] + d['ILmr'] l3_hits = d['I1mr'] + d['D1mw'] + d['D1mr'] - ram_hits total_memory_rw = d['Ir'] + d['Dr'] + d['Dw'] l1_hits = total_memory_rw - l3_hits - ram_hits assert total_memory_rw == l1_hits + l3_hits + ram_hits result['l1'] = l1_hits result['l3'] = l3_hits result['ram'] = ram_hits return result def combined_instruction_estimate(counts: dict[str, int]) -> int: """ Given the result of run_with_cachegrind(), return estimate of total time to run_with_cachegrind. Multipliers were determined empirically, but some research suggests they're a reasonable approximation for cache time ratios. L3 is probably too low, but then we're not simulating L2... """ return counts['l1'] + (5 * counts['l3']) + (35 * counts['ram']) def main() -> None: returncode, results = run_with_cachegrind(sys.argv[1:]) counts = get_counts(results) estimate = combined_instruction_estimate(counts) print(f'{"*" * 80}\nCombined instruction estimate: {estimate:,}') # Unlike the wall-clock figures pytest-benchmark records, which vary with whatever else is # running on the machine, this estimate counts instructions and so is reproducible. Write it # out when asked, so a caller can compare it between revisions without a noise allowance. estimate_out = os.environ.get('CACHEGRIND_ESTIMATE_OUT') if estimate_out: Path(estimate_out).write_text(f'{estimate}\n', encoding='utf-8') sys.exit(returncode) if __name__ == '__main__': main() bidict-0.24.1/check_dist000077500000000000000000000051031524342314000150570ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright 2009-2026 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/. # # Inspect built distributions before they are published. Nothing else does: the tests import # from a wheel but never look inside one, and the release workflows went straight from `uv build` # to publishing. That is how 0.24.0 shipped a wheel whose RECORD listed hex-encoded hashes # instead of the urlsafe-base64 the spec requires (#406) with every check still green. # # Usage: ./check_dist [dist_dir] (dist_dir defaults to ./dist, where `uv build` writes) set -euo pipefail log() { >&2 printf "> %s\n" "$@" } main() { local dist_dir=${1:-dist} declare -r hint="Hint: Use 'nix develop' to bootstrap a development environment" if ! command -v uv >/dev/null 2>&1; then log "Error: No 'uv' on PATH. $hint" exit 1 fi shopt -s nullglob local -a wheels=("$dist_dir"/*.whl) local -a sdists=("$dist_dir"/*.tar.gz) # Guard against a false pass: with no artifacts to check, everything below trivially succeeds. if [[ ${#wheels[@]} -eq 0 || ${#sdists[@]} -eq 0 ]]; then log "Error: expected at least one wheel and one sdist in '$dist_dir'," \ " but found ${#wheels[@]} and ${#sdists[@]}. Run 'uv build' first?" exit 1 fi # The check that #406 needed. installer recomputes the hash and size of every file in the # wheel and compares them to what RECORD claims, so a RECORD that is malformed (not just # stale) fails here on every entry. log "Validating each wheel's RECORD..." uv run --no-project --with installer python - "${wheels[@]}" <<'PY' import sys from installer.sources import WheelFile for path in sys.argv[1:]: try: with WheelFile.open(path) as wheel: wheel.validate_record() except Exception as exc: # noqa: BLE001 (report the issues, not a traceback) print(f'RECORD INVALID: {path}', file=sys.stderr) for issue in getattr(exc, 'issues', None) or [exc]: print(f' {issue}', file=sys.stderr) sys.exit(1) print(f'RECORD ok: {path}') PY # Orthogonal to the above: catches metadata that PyPI would reject or render wrong, e.g. a # README that no longer parses as reStructuredText. log "Checking metadata renders..." uv run --no-project --with twine twine check "${wheels[@]}" "${sdists[@]}" log "Distributions OK: ${#wheels[@]} wheel(s), ${#sdists[@]} sdist(s) in '$dist_dir'" } main "$@" bidict-0.24.1/codecov.yml000066400000000000000000000001321524342314000151730ustar00rootroot00000000000000coverage: status: project: default: target: 99% threshold: 1% bidict-0.24.1/docs/000077500000000000000000000000001524342314000137625ustar00rootroot00000000000000bidict-0.24.1/docs/Makefile000066400000000000000000000151521524342314000154260ustar00rootroot00000000000000# 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.24.1/docs/__init__.py000066400000000000000000000000001524342314000160610ustar00rootroot00000000000000bidict-0.24.1/docs/_static/000077500000000000000000000000001524342314000154105ustar00rootroot00000000000000bidict-0.24.1/docs/_static/android-chrome-192x192.png000066400000000000000000001115061524342314000217520ustar00rootroot00000000000000‰PNG  IHDRÀÀݾûP cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYsÃÃÇo¨dtIMEè ;w»bß.nzTXtRaw profile type app11xœ­�Gb\9–EçXE-Þ,vÜûõ¹RdÐIÊÌ®ÎJ‰Œøæ½k€”éÿ÷Ιÿýï.XLìÉžeŸþ/øUr/)¯ì?qûåï1‡à‹ÍŽŸé[ïï{7|­¶Qœ oyßžÚçL {û¹³~gWBá±Å—HKOÞúÞËX=Ò¼÷öŽìó)þ»W¸÷¯¨zI®†?êK•·½¾Ãºz?ȯûŠÛfÛúZÕÎdG§Íì÷Žg/×½dŽƒy¼»{ZáòÌ%g=€aõŒXÎéí5uu:—é&­Öß�5žÈ¤Ð¢GÃRõ¶¸”CçÍ49Ú²×æÝ‡�gÎ|�cÆ­'OËzi~¤½º›£0–ÍV£o«·9Fûé�1ÒŤы¯cµ¯¾a~}Å%›l°o_Q+{£ÛæÏÙݵQ‡Måô\g‹«OÛŽu3�˜Ê2›æÒÓÚ>í>ߌ®ÿØÊÇ+Ýó+MvÏšN­ÛžÉër¯aŽxÜäu«‚;1-šÂèºåcoáÌ9mW <^i¾xgˆ1¹Ÿß8íí®¸XËJÍmÏ[®9Î>¡&3˜_‡ïq2•Óù8‡‹‘ia â?tòé…æõ�¶ofvÔ{ÜÕ�äZëí„BXûø>b 1ÄhÉÖ•ö>�D­‘YûaXo¸å�3ɳšwt§�<¾ègiÝ¢Ë�F`¹§;nåã3óÌ´œSÚeOþ+ýotÒÄúqXë(kÛØ³grºe¤r§ÏΞ±bu+Ñ�U]Z ·W¥°ç0ä]y�òe¼¾½ñó }Ï@A ´ÑÇ\Í}m.7O@µ^lg•=NfØÇZÉ1ä±T%`øú…æû7ž� “s|£G+¯ÆÔ–V¬ß³�X«]³„Lä.™^NÒ« ]`ÜžÛÅìËFJ #²§�9wŽôõË޶Gí¶KÇœM‹Ì±�&Îå{Êq?¿Ð|*ðìé�…Vù§Ùãz:¡×±{êÌ]6ÎÚCO³žÍW€Óígu¼r0­¨?v1½"ãë €·Hú]êNѵµ{‰Ã<1¬Ö{-yÔ™3Nœbz׿¦}}Ò¼³_ÂÆè��ÿ›h:ì¿aóÆ\<ù#gýŸ˜ÇÔï>qdöÓC«ë1ç÷?ƒmÞx šf�‘È¿"@øH.‘túUÔb~â£ç;Ó7ž×o„�GðÀñÕúø \‡ˆ ùùoDCŠúsèüC tBê$gÔüÝÖëj©¹Í÷ÑE2 Þ6ˆáï{héû6Mzž·K<èy¦�RÝŒ‹_krÏk|5ê¸òê†)¿÷<&¥sgü˜ÇÓK|ÿôÏçg I†�8÷LÂ+Tß/5ïßêí×o%šqö.®“½ßÌ/³�zž‹~PüýªréuúW"´zðéSÀ˜1}=KMëŸL½fÞüS¯×˜ïuôãÏ"ø½þ ´ŠoÉÍÊ£¼]c3ð›±r{EºÚ€ÖyFˆ{�Ùà6¾BCl­³GßJ›ýu¼Ì§ {¯þ7ãeþκ|?^æý€ýáx=ñëH™ÇPÍy±Þ&@( Ä[ÍÇ�=qû†[˜½Âíí¾,玵gưÑw)_¿æÇúh¡ê“… â ÌWYÿò¸Ñë+·,uinw:>®;3–%£,±m»W”ýLaVÄx“&´°üj8Ê™ênv;”ªYŠu ñ ­ù5škªP^ÖVKé§ŒPÎ&g1#ŽcGê8ã6R»úÙ@uX€¯9 n8¡Ì°™Wï ÿs\�¼àÕˆw·î<ór~¶ÊÈØÈ˹«vU ‘RÅ¥x$Ý1gŒY00·jñ7LP°#°;ô;Ó$õâÔQ=tßï£�²ŒE«ŠãëÞœ²f+ÃãáãŒÐÀ '«ài¶­9dD/‰: Z iÚÌ¡K8ŽÚÀ … ì|9;†�°œS"° †$a’ãŠe�Gkä‚¡¶Sè ˆ¹yFÑ"Ââ›èd¤ßnµ4#*ä4¯q Æ´rt^…žL…~v¨@q_ÇÓ 8ßžƒéê>b…ÌËOBî0vW;[ƒ ¢u£’sÊ­Äpáô»Í3¥86@&þ°æuaPÇ©¾š¶k©µaÃüðôl9kB1nœ9«ñE`µÏÝV™É¹Ñ�[ç`Vp� ?ÖùP1“‘ÉŽÇ­¼‰oòi1-„Ñqô?üøªCÚ¦‚zIF¡n¿ Ã@ßt‰ðsûHR·@Ž!‘N웾ÛBoL!,}§Wq»>á(bZ8ZØÞdF‰<ȽA+Ù’8^à�—x‡±<2ÿ4Œ_äŠ&Ô½`ª�¶(‘<¾L¤Ÿ´;±;|SH~à8)ój¥þܽ. !VL«°B†ò —Ûø±%hqþLò@,ù ph±Qì(,B~Pð|AŸ|ùÛ÷N΢ðrešÎBÈmdÍ]°ZÚT.sFu%�è~¸ _NŽ´µZ¤È®9�7»c¾÷;çäÌG¯óŽg_ÌÌ/®ýdt~qnÓ>ˆ7½ð¨þño&¯´¯L]tjÍ¿~o>˜¼õ'&ï«N›¿3yßwÜüÜóï;^â3›ï-0#ZP T²m§—tðAHƒ."~tÙÍĬ��öG�‚‚@P;‰H>¥ñaa<Óª2Š7¨4N=�ÓÖŠXT�Tu`fÎ.#†qqu2X�—# ÝáK ;�jV»êÅD3ãëð�Zu‰n¬˜`fo *e °sv4ZÀ—µÈN†*jyQζñöÆ÷%‡ßÁü¹Bæy@‹ÎRÁE«– ÜF4/­¢Wœ®— ¦p ® ‘2è‚…sm00 šðŒ&qYJ¶­sOu“rá¡´¡2y+®Ç*àiA…*;´äFQ…†ˆÉTŠ�àý. J€9�o‰éÁ˜m\Å'˜÷ÁÀhì-:I[ñkó‰Ðd%‚«¦ã,KXƒ¹la8Ú‡8/²Ùaã6a9 !qpøØ$æ&ÆÓ0r®"–hËÄTßfÆ�3"d]ƒeg\Æîk=˜6,a ‚øØk9-âÒ œïÄí ³SüB£®ŠŒÅ 3t8jr²1àäqÄd�+¤»WqwòQ+Ãè5W›iå abq‰v‘ƒæ#a®Aéd“±ém-UW10£i³{”㇧EˆTäܪ#É£B j^€ÙVæÀª O`÷�ýÄåâ L„AÄ#{7á1³PôM8Ãa€CèWx…ãµ·�œ9¤�¬‡|¶ÒÝB…Ÿ¯…Ø—f£™¦iW 2BZ¶®ÕV°ß{E…"Jd8>¯„_U¶e� F^Þ2P�^«ÌÇ0‹áœÑqp§Ã¨ö2KVTt´[Ì^³3añhéåXØýþÓþêð̵x–0­+ÅY6ìØý <ƒ„tZ§é·ûKÚ‚þol�ùs÷“·3cî~ðvî± õfîÊÓ¯ým]»æî7×üíÑwƒ`þ|~óyþÆî½¹=óf÷@AYÜÉQEmdjÃÿâÊ`uË ùF£�‹´Ó ‚© [¬m$ �.ÒÇX$DùÑb!’Ý-õ-Ã$-Ô…þ`|äv�àrĸÌ"(Áèy„1ô"Ç�(ÚPâ9AɲH§ƒ`OuoU.UDõé ­Ò;èŠö5‰”`ÝLf!âñøÍt> j]ªZ¸Sñ)°Ÿ‘€8[Qo�9¸õŒÍ,çÚî0Z%ƒÚè:¡ÕDô¯‰@I=ó'Pq“ë9ìpá. ä ž´’m©ÖÝ»p%ж´­Ô«C¡Úº'³† = ^3ü¨ÛBŸüPÑŽL˜ D¨€FƒÐwf®«Ø °yåÉ@“ ¢ßÉ•sâ­E^€iýèMR×R} g¯>D²×¸_¿5J€{–ÖšáFÕ·d°»1 {dm¸ðø˜Ìoǃ¬Jhˆö‡€kZ4A4�k>ǘɧÄ)Ÿe:ʘ� ¯E[; ìqÖ&ÔH%,oDƒ÷+µ‰ýÊG}w~Ã>SÐ�óM8aÍ öô>‡š´ÉòZ‘ÍÐqirºr0²¯H×+F±®[¾©@dÔ^XæҭÑ&©­ý0gÛí`Ë�dˆ¶o‰t¨˜¤žò]2UµZûvˆrdX¸ØtèˆFáZ®è(¦®Qð)½"oGH‰vª¬d§ÒœÚ<+£˜�ÍŒ t€!±*Z È/ ÚZS£R>Âi5B%#¦Q±tÚ¨0-Š ÿЗªwÃX.8íšÆ¢=‚~Æ!¿T�ü´—–U ˜>o†½¹<ó°yöüÖ%}±]öÞ!Y¤ïÒùH÷µÏNð£ü³m;±G,|®Y©øú¬Ê“Ž€þìzúB0vWÒÏB�hì«C¨mÙîØi…�ìé Æ†Br¯ O“Ú*êê%…Í#]fY 5æ�·%Lª�ÕÞ<éëœAì¢ B•N/‘=ƒ…¼h*eÝ¡/XÔîmÁáWbº*1ÉÐY}nÉôv c,¯Tg'€‚�4^…Ð0Ûž´ñ{A¼iÝ€¬l‚]«�•&YTD@dóP9³-]ƒà,9k1l5d°ìV Ó¬K´s£Nµµœ¥ÍÐ�5j©Då�S#=jMŒ¥ª_éǸµñnÒQT&-kE\›AD®%ùQY¶r™ØÃe»Ž¨#´‡.\Õ^FŠÚD÷ˆuFdÖŠvŸ™•ü¢¸á¸Wº å)ˆ�šs>7è×I '@@¤‘”/v€`[Eã¥ð…ÀWsëMÕÍŸÆ÷'ÓU7�>J Ï^å PÅ5\I5¹@l.¤ð&)ú"&Á“Ya®Èyæ³;ˆeb 3F.Gú ù´ áÁ¿yj·z#Xñeg,D MBpÕÐ ¼¦þB³Ø@_•’1€´Ý1!˜‰Üp0;^Œš't[VÅéa:˜—4'*ȵ³ê-cŲ„�Ä>pd– nJ·.Œ Ù !9" �õ*F™……á器Šñ«ªØ·«Þ¡ î�ÁD½à©˜n!ÙJLíV„RÞjÌK“Cœ·ìÁˆ¸}rª_€9œ‡öøL‹ÞC°®ÓÙB<@+¡ZrZ!ç´‘†Äf4Q!øÒbPð:Æ6DæG ™¾XðÈX‘û§¤š£që�U‹¬’8U#3l`ñ-3üÁûSÕ“àõ ’ »¿uíñ)—îw�¢ªW0àÊÚ×g°²ÎžÄû�«èK½å Ï�l·6pÁ|Çš_̶îý£ø8h£U™[¼lzˆt¨ y݆ÄɥDŽÎH øBëq›xP0­ÞLÌa2*ŒUÃZ-8ùܵêä ,Oë´ÃK’¡|¢ÄºÒž×"ëÛ2wëÊÜ-®¾ÿŽW°/5yS QÚëÏbÖ¦ûѪ/N)#5pƒél ÂåϤ`^Xa<W…°?Ö¥÷>�¾Ým‘ÜTq �VZƒÝ Ÿ¬Á�yï�Pa/_ùõ šÍ¿Ó­MNæV…—_MÁ“†J×ÞP�/•¤úÒÝ¢e·¤yi#ò¥®ýn™_¶I…z Îx}ÑË^\Sà§�p÷“ªH×ëc0Ìß�Æ×ƒa®äxr‹ÊûÏ£ñèXùÕ±_6èa—½ù{ôfƒäš#™ïˆnü ´ñN)à›Ót FßEJÓ–S+ˆŽd^›YÛÞ‘BI:ƒÇ_*VÈb·¾¡T_ ˜¬€NŸÚþø¡U´ˆ8N;c]g�xèÁOa%‰£ÍXÑ@@Õ�áfJƒA»,„;~ž9lé:È©Wma÷3ËQ D‹=’*hƒ¦„|Ø];ó˜>H÷@)»«œ±Ž6ÉödViÃ(K˜£!M‡÷žÈ¦' ¢whpÂHÕ Óx:Y‹¬ŠÚ.³“>E«Zô]KÏ:6‰§Å¸}Üö/Û^å'?$~+û2O~è¥ìËå/ê'¿ëŸvI‚ü ®åQèý°5‚X+¾G–TY÷òøñ­¿nR™�»T˜b W^‘!AÆÃÁàL×)j'ñ—“'}tpæaáÐì¨wvÙ]>µwO ‘c(R…é'xÄ+OÕŠAîhÉ1ÝF,0ÂÓvÏËþQÐä>Èàu7çm»ç�&ÌãWï9Së`ú]¾'˯©ÒHƼ/R${í×;X*ðÔï5é>~üŒ ÷´ÿÿÜ-u,èÌãwÝblêû‡™·-1ðåÃéƯ=®ßŒ”yϨÿf¤Ì«ªøPïø5÷Žgo�„ï <ì¶730¨®ŒY,~é@§òqS R8o™8ù$Äë17³N¯c«] X²´Þ0È ¿V}íhüsËp‘ïK®{F“€xDê Kņ„ÚÐâ{Z¿‡fj¼,:XÓ;ÆR'»’ `¦j©BK º©|0ƒATh[:øÃ”Ò*ÊòÎUõ!ˆYt0ÝÊÇׂÝIyàMhލ)'ŸU€8U¡jð‹IfDäÊ{©Û”DÇ'êô`B6HOEm� €*‹µJ²U?É0&-_by@ÿ:¦«üqªlȵ¡šú|¼ªÊp¥{�Ç>ëþ¯h·DÃWáhx:éà"Æ’! bK–YCsLo˜q2þrPÉ׊î Ìýž“ 10æxÍ�^p".™³ Nyg&^6ª.�ÌÉVI…ªM9Dú>À=mô˜æƒX, é}Ú°0‘¢ïâ§Á Â?ÈÖÞå qÿÅ“ XÅ¢JE&S- ùüÞ–ªîJêLj½ Pwt>™ úÕ…˜¾kAàÓ¬N÷»…£²}U½hÕGë“è=|ˆuNgÜÑA’�ãŒÎK—&—‚oÇöN†¨±€h-¢mãqyDY¨�¤R€ºræ½@�.áOu愆„‰V¸þ,gNm]N»êž ¯%Z­ û©sV‚u*µ�#x�e´#‘0Éc`†à‰¬'u@Dû‘ ºˆ*´Œïá›Z,Bm*ì�Õhëdôä²@j3Z ¡ƒi Ò'quœžg9ü ,‰´¤[ëh jeÇ1ˬ©ŒDæ­?ÊJà€ÞíœÅ ¯H£Xˆßj�=ü}ã«wó?z7Õ⇧2F;?{�‡Yáã—}}|àT쯪„'è5ïàÜùwübpêÏv/Ç×MS^Œß‡ ¯ðâà>;·òò[ÿìÜÌ¿ñ±ï�›ù7>ö½�5ÿÆÇ¾ß÷újúkø š ˜";ÒhNB¬™D6Ï‚2 3/ÀBÙí/ÀX^òM{9f'À¦êáÚ“¡4§û9"¼¥ŠvsxÕË:¡Mðo”£R…¶á„àNRÐÁ”—êÌzE殳´¯]£àð0à (¬ ëÞÃm7‚²ÂY”rúp0FØà#¤Qñ?Ȫu´Ln`Æ/>”T”­0]µ$A¢�³ZSÍG&ÝÀ>åyÅßâ?zÒA.@Q±_oÌ®5f¤90Žaˆå4¾j­k$£6½Û�(pcÄ{Ï·#Ã1÷!!ˆÀàsuÂŽi“p6d‹+@3fŒGÕ)‚¢{ ðåá4 ëä`†¨`ØV©@" ¶ÏÐ6˜ {%°VG{#ñ{0ï­˜c@Âe’“ÎÂajT$ŠÆ�7® Z5¨<ÀI*þTÁu—šEÕÿ'·Mè�4Ð"nm&ƒ¦âTmÝBF°Þ˜ãîKÀm0܉¾5bIæWE4C+`Um1àê”åt+ 8· Æ®£oÊ‘\M;º>`&«3ëæ¶åîÃÔÁâ5µýZŽÓÎ-ÀHpâsiâÄJêDí£–dˆ¦u/l6pÜð©¸#ýÄ$÷ÃßðÃ[”ÖLªÏo:«+M ‹‰Å[0h²`ƒ ?§åE^1£„CPÃÖ…Uû…5ÒÆee§UYÕMÌãW»aÔ˜bŸe2UÛÚEÛ Xµu»ˆÎ”2š÷Û\a±>•š‡KÛ^�ëö…v!ÖawØ…Ûe "ûvÌE<ß[Só«"3¼³Ÿ?Om}}6ëÖì}åxþÆð˜gÇÝ×½Bú�á1¿÷†_ž×’ŠKF×Á ×ÞûÔÀø�ý„3ê÷*`ZägSÍ¿o‹|§·¿ŠOÿ¹óX2ó;O¦{œ��VUã S�ÕreÃO;æh˜dåß:YæQéäÜÃu0pIûËž,²°!Z™ëHðv`iSBŒ;ÛYW5vh?�…ÿ¿d¢¬ügp�7 ¨ñàlԢꢳµÒ ‡åмׇ‘´è€4Iw‚M®s=b�¹R®ÒÏÒ×PK Z˜ÒrïÜÉà‚Ÿ º5[±ÓYuêМfä:tTU‡â¡MCÕ×x†N  J¯�õƒ¥‚|Ú±¤ìھ˗0ÐÚ…&/î@%™Œ-ó 2sító“ïºê”rºK¢CFÛÄªŠ‰I˲jëvËcŽ£M:$K?*Ò`xuñ›[Àºƒ¾0¼QÞbêXºÆèTY×êeÓMÚB…9-ÆÜwâPS“ Q”ÂBk4�n€�[éK °IE.¾/uTÚ‚‰$H1ZšËÑÂèܨR�âTؾ &ø¿¢Úìeˆ˜Ykì�Ù1è<ݰ*éá¡a] 4û"š´“Že·ºA)¼sT�ÈÌÐé¨yyQÍ mµëqª,Bh :½��¬¶�«ºbdEÌp2¤÷da ($œ°Æ;53{±R:ƒð'mÑ�a÷D“NG0¾N'Ü–NÖ+óæm€ òÄQî§/ô£Š݈HXÑvšÃ¼hýy@Þè ¬…·ÌˆÄ™ì¨½qƒ$]I» mYÕôêþ£±ñV]rHEtžy7ÚpÀÁ coí9rÛàÚŽ×ÑCEÝØ†BÄL¡R¥LP÷Œãwç²Ã‘'ãÃI¾ó8>�H|X2\òsõ¡ÝMå(û6tiío ݧEÜ>Ú#ú¹úPwûü…'ûÉ’™¿ñdO–Lw¢øç+0Æo¹· ¼\tßãÇšÄgcf^6)¿rfîþGvçÞÚW&Õü³ù< æGä·&Õ|ïRßLêŸÔ#šŸ|Ù8ª×½8â¡×ÅÃz(öœ °µ'¼&·ƒ˜F[µ 3ù¦*ë$u�Èš‹@Z±ø¥pK‘€Ý¨»ÔPƒyêÀ&0Ò‡?á'J|yÞ �ŠÜmLމ¶K˜¡­}"Ù —SÓ2ÞOõ$vz]º€Înºæ5€œv%ºÆ£ñµ{bK�wÉtàf�%•I: Êó4ú¾Ð$Òu¦mP}<™oºìšîÒqžœôËẎ3ÏF®ª†C�Årø›¼w):¶ÝUé^TLfRL$«Z8  ƒ„¯ø €‡"Ö©$”[ÀœT¾6E°üõ ¬Vx|há°@Þ–6ƒ®y8H&‹Æ!ªn½ˆæ¨%¦²pºi« A×jQö~³†‚$ÛЧ+ÞP™øì’d[‚7кB W}—õ Þñ×ÈLçÞº5¹¬Åû _U¡·Ê;]ªKêá̈ÝÓ)ȱUØ\K°A;Œ˜ ½×&)Nƒ«êü±Täò‡ a[œjÒö-G‘›ÖñG�©ÜnSƒVÌkct:óŒT(Û ¡°ÆËkɤ­¬„Å£ÃÀ»–ãfKSeˆ2ÇÄŒ¶™(–¨�ˆä)Ûл.ßÔ.œíAÙ¬KNn¥†Yå-•ù`È/Ö=PX|UF¸H"pæÜáE(¸}5¯ PÓj‡NŠíÑçÐM„Ä £èC$ê�Nk8ݤœÝ¨�‰˜!Φ;‘Iå:›÷$”h€<ƒhœ*ª*¢czìJJGžë(»ˆ^ƨžE�¹ ±ˆYuS0¥W­UëRªëü´ë…ºhùGu‡ŸÝ”ùÎN}w¸+&lìçÄæç ÊÝ=8L/ 'dÒÇþàÈ^ Ù×§£ÌÛñ¨ÿÖf…olVùÏlÖ3eŠ0Ù›»Yd^w‹bz²Zõ‡Ýê/v‹VÅŸ¬–ùoÚó¸Eo~w’ðoêG¼æ®¡²:zu°S Zu’¯Cšn™]Ê‹ÒTÙ¿VÅ;©¡‹1t�oÚ½hx@-‡Ð'}!­+ê*¦¡«PãÑÒ)áÆ¸�ÿ:¶JĂ֣áwÜ)(W´™Ñ�k°X€�ÓXÓq)Ù§ÓøBé: –VÞäk IKIX…¼Ûƒ¡ô]7錈òm‰A4NÏ ÑÕ*£nyJ*§Ëžÿ°—·&#„BG»W-NE$ÜU•N·t¡owرQ\)¬­Zv5B €¤;±U3Õ•% ÝÏ"¯[u¦†i©Ês…”uZC]ÕÝ Zu$Ši›áq­ÑA¶>µ[F:&ã‹}±x¤6aé²ïIX¼CPÄ:¡DÙÚ›‘×1L4öJ: ¬ò]*­Äò:Ó…eàhÚ^ûW�tªƒ„vî9žò�8º�¬ü´oþY!ÕçÕxó7Ëñ?­Æ›Ÿ—ãÿ¼ÊÎ|WYØm}Àxÿ"¿Ú­‚\ïKÍs�ãËQ�Ï_L*Ÿ|wùܧ2B#~ñ«òIo'S!tàS‡ä|øŽLð|žP˜¹{¯U–u^ MUbóèóe» ¯«¹6§µœ4öU�“�~7¸ g«{Yº´O®¨?¯:+TœWY™Ÿ€ºÄ±|ÝzüºS—ûXŸÅ$×óD-òbö`˜½x–Ÿ , ©�p˜5ë2¯[Ç2mF>›~�³ÀÄÒgÕ¬³‹WÌ[Œx€X^Ä Â­5¦¿èö5L´emE’ŽåIÑåÞU¯­.t_ûª*™B-xŒ4Êb©N�é×-Å…‚ÕQ�1†nç ¸aˆÀëxD îÈj7æ,Hùn4Ï�«­ Ý×sEO"3u n©LQ÷àɉĦãp�U™|7¼Ù¯f¾Òèí¦G�Ahhø±t€‚,ô:¹¬"Iqž©PB’O^^‡ÕEJ©i´F–Ich\ÀÁdxCKšD"�Ò •£¹­Um^O¸ÁëpUYŒlÑÞfŠÒW÷Ô‰ö\v':*^¯0NgÒ@'ËZ- ßÖY�ƒ!! ´Â¬áöŽ{ÜÊpPö*þÇÉÔe'Rˆ“êÛlµºþ$‰²Ï™A|ë¡�:xX$3åT¨Õ7¬é ]¡41¸N×FèÖÖýü˶¤ó¸ªæÒ½�žlÏNW#ƒwƵñ(ö­œ `q™S]î”TÖ /ò«¾DGf´QÌ$íþl)’šÕµCÅ=a H꺞ڑÌ;3C/c>:ÁM'TºWÔå&ë Déºí} ÖG¹Û¾ùVµ«Æpâ</|%,Ô™{¼™nawMÛc:ݸÜÿ ½Y8È£}¥/¢/TU±:ý¯2x¨�Rt©šŠ ‘º"‚§cb[•»Í*%�#š%¼4cpï2!¤sÄ“âÌlT`Ãl³–]÷άºUGˆzF0e]� ‘Z胢?cÒ#ÝÅ�7¯k´M_Ö¨S$}ìM(Ne ï�¿ZvÓºÓ=ÞŽÙÏYA!Æ'h�®ê6±Þïu(8sžË�*NŠrZ•»M·¼á—±ònâU·ŸAž÷øÁ Ó±7Ž$ÈÉËÿëØ¿Š§òè–@\Q …c�ȤƒN×M]ZàµÑÞudZwv3UÕËQ)Zš#2'²-Õ°­Áê¼`ë»¶]�•Úu 5#´á0�nN Û€8Ä¡#vªq± $ú.¨÷úžVc†‚îsSޏkè~€5·»'g”è1{àªk½¢Ç{¹®-[„%MÖAMˆBARêâš®#3¬¨ ­³WŽþޏº&ëÞD§öf`$: T—Í«�ènþ€kÁþ›å¢Ð_zTXtRaw profile type exif™ãJ­ÈLãRS3.Ss 3K33 0I1I100J4€ 6654± ¡b†0PÄ2�‰sA #d 4À”C�÷b¡IDATxÚí½w¼]Õu'þ]kŸ[^OOU Ó1Åôblp�qì¸ÅIfÒf~“ùý’ùef’IsÆç—^DZãÄÛ‰Mܰ1`šé��@]zO¯ÞrÎ^ë÷ÇÞûœsÛkØN´?t߽瞳÷Úk¯^½—à^ ª86æ4$¼áöL^¿•(` T5"à†PDäpˆÚÞŠÈýtO§ì�?l@ÙÈÖN€R€Ð­†5jËçÔ®.4_Ø.`/:ýœ¨Ý}(L/¬ hA@²án¬ðw!"Ì$ �sÓwCü'够Ö[ÏŠm/k½ }ÿc�Lþ¤5/6%í4—ťР�B)Çþ:¼ÓÒw ƒjÓ}´- #¥™h'¢™ `+gœ�»Í:iuçµó gGãR»oÛßjF9,%mŸ<Ã�Iwp�ÐpQî׳âP[øÏ÷ˆR;X¥Ç#û†`¬ª­O�@‚¦E4ß7éYÔ�9¡5Îk–G¶û¾…/ÌãVí7 Õ2<.A›·$¿´æmÖ”—µì߬3lÃ#¡Ósù¹¶Àß!‡ÿ!uü¹JJ>ý¯XU|€Ò‡§S?¢û´¹ñëÍ�Xœ›Œ†ñÚaë›>YÈ”ÂÒŸsz®| €}t�©M«z½ùƒÐæ0´�̇ò#?‡N¦ñ¸èœ Q» .”ê¾nJúügØðëV’ÙrÃ…íD[ò@ÙSyæØS�Ö£ç~=5vàü$ÝåMŸ( t„;Ñ2©£y³ƒf÷?Â'Ì.stxÆ]%¥vºEë¬:ÎS�ª žh�pœ}¼f�óÑ#|DGKÊl"më·3ˆ’GWÊô¬:oœÿˆúÖÙp؉ð8�¿AÒjÕÛê‡Mk=òÎ"~±±j^¨0¿å·<¢€MÏ�u óÂÅ´töß¿F#5B͸œYsä\,ú£®-…™7p�y/–:uæzý€—´HLGu8›û‘ßç9ÚðZhæs¿•Îó'sYÑ<ÎIgÏAÛ ò#‚2èhàP*�§F¹œ„NGŒC:‹íÑ?T…šµžŽ@k¦óóB�¶n�¹üªÓOŽ.â¦òÍœn{„ˆ^ý{6ùºÍ7˜ÃyÒœÖp�êëW³ ]Ö93ˆ:IK˜�ÀÌw’¯[$Ô\§•×Ô(7æðËù>Ê?b‹Y˜‘ó¨Û#ŒC�àÐéÊfžÓÂÚ±ž-k®?×b  &êHéìØÓÊ ÛÒù¨ßó]òF+~´jp3ˆw˜ ªs×ÓñCˆÅl;ÅVQ[©¶³±ðùüˆ8(f�6v~âÿŒ1^�¶f†û5;ÐlÓnCNç~Êó¾âÎÂÍBÌE?‚ˆÒqt^]«�-A�‡³ÎÓh3+|Ú!PÛ�ÞæèøžÚÁ„渇³_5gK`”,ÆÌ–ÃN_Í´ÀÎ˼Àòš³°¹lüQ1îÍ‹’/Ü©òCsE‹9ÝëhNŒ�â-g�cæ²ø£‚C?^h1ßåáG�j†ˆDÒ|Ê ­òÿT¾cãÈÇÆ+ð‚ÐQ ĘÅ–©µ0ˆû;?ëæÍ8Ž–rÖˆa"—+2— �ÎÊ¡ìÇ™ûoÿÝŽ9úgæ~ŸÙ.K3Þf¹þH ‰?{Ú±1ß1?æÐˆ 33ÍYb¢_Ïȇc£Ó8BòÓöçGë ÏNlf�,9†d¯é8ºØÓ6ÿHƉâ ËÆ8†p G!¥³e´Ç!eÿšÃ˜ý¢™ŒžajóZFk>À‘Àåßü8ÂH·#”[¸/l^¹þsLêî”l?—|Þ·¢÷.ü5B7:øÂ|nÙlƒ#žÐâŽ�£8޼îE 4·Ô¼kwÁÒ9º®ŽTÇFË8*G·£ ´€›£%?FãhmÖ‘Æ5ñ £á©96^�ñzØ�|4Òl>‘×ÂL�eèÖÛv)Þ´|KDĶεռ‘¯hr©ÍÔ‘¢.ÀÊLD)‰(¬W{P¡¢€5¬¦€B±ØÝÛ].]u9e_À–r•²|„“'[šX©UâÊT­V©'‰˜œ÷&dzâêLCxL�ˆ”D¡b‘(B" *pOO¡»§P*&([¹†•“f•1UEQ­%ÓÓ•Z-ŽëV\µ'03 Ò&úN¯S‹üý�dh¨Ôî—×lCb5‰ˆªJ´h¸oÍ +N>_[ÝÙ>:ÉÿG£�Û­R‰€dh¨{ãi+Ï>ë„M§¯]»nÙ¢EÝ]¥¢aWî"c÷A$LHU¡ª•JeäÐÄèÈäÞý£/½rhëó»·oßóꮑ‰‰X-ˆ ¤ôÚ¯šÐw…ç53P ™Y Å=3C=Ö+TÅyÙªeg^´é¼KÎ:õŒ‡V-CoO�� `‘ÕÇK©°RC²²†{©҈У(Ŷ~xìŧž»ó÷ÜuûC{v�2EiÛîph†U¼öPA‰HE8ÒS6÷–κþêÓ7žrÜPŸ‰Ø•·R :MZi—Òý›‹ x‚ 0ÀªÖâC‡§¶m?øàÃÛï¾wËO¼tð@U­!6Ž€¹-JùH)�+q'º@Ê í¦Ÿ„„@ V,DÊ]§ž·ñ’/;ýâ³ú×,OŠÅ)`ZÕêèMxHFÁÒ «{Lÿ¯ E0:X�mÙöõÏ~í¶¯Ü71Yg†8 äH¤ �-ôDR%² ]sÜâ}øâŸ¼éÂu+û &VµDššJ4XM(;MÍx“}BêH8´S"36¥[¶í¿ýŽÍ߾屧7ï®U™˜‰4�†z„ÙG‚@žM7ÝPýw �íéïÙxùÙ—þäõëßx†ôöM*ê ¡|·—ì¨IÀ—Vi+…(†„¨ª*áѤ’¢eq}û-÷|æ÷>÷êó{˜(6¹ZGŠ@aóæqW6XX l¯¼âøÿ÷WßsÁ™« Q�Tˆ@,à|)ø@((ñÏÊàœ¯dÝ*,çê�;ñŠ"ÕòžCÕÛïÜþù¼ÿ�·U+ÄeI­õRŽ�ШãÅ v¨aÕtÑI—lºü#ï\}ÉyõÞžšŠÄƒšºÛ¸uØ6Å5šÊ¶Á(Œ¡Bbm’DňêcY@†t™AõáÍŸý¯²ó©íÂFXƒ¢7×ðËö1'¬ž”Í ÐÞŽ¯b¤õëÞ²á?~Óº•‹ˆ¦˜9Q²DN,BT�E,•J!QÄþã¬fxF[j²¤‚“’’* ƒA¥ƒcÉ-·>õ—u÷£�-A•44Ù9b꿬�&´E ŠÍäö�`ñÒŽ»ä§ßuò;¯”%CUU rM‘jƒ&•#¤U4w„<à•Sr}„yøé¾rÇá�û–œ¼zãû®ï?m½¬%–`Z2ŠC“÷=ùÕŸÿ�‘WF` žÀµ¬«ÕŸZ4Bܺ=aNÀœ_é’‹–üÙŸ¼÷”5Ë )ª ˜  ° ŸþòWž¿íÖW¦¦ë_´òC?uæš5]@Bjn&ÊÍEõÓ÷¡º>‘3©§L bBá¥]ÓúW÷}þó��Œ(Vµ%ì¹`R@ ƒÒº¶˜ÑŠ]Â?°á†‹®ù�ÿ2pýÅã=]5¥:(&ªƒj@T#ÔA1¨Nƒê@Ë ¨5¢º¢$ º¢ÎØsçîûå?ݼ½ëŽï=öʃ� Ÿ{ /[\!šO©5˜ Y»¬ÓîûS±3¬¬Ãß ° ü3T±Ÿ{n"–,ãOüÞÛÎ{òˆjU‰ªDU ªR­U÷ã÷ýÖÇŸ9Pé�.ÝrË–ç¶í¸òÒÕ}½P$@B°@Òø²¹—ûS ¯“@ü'éK㡹ìM'l8uŶ­{÷í�$¦ÎsÐ6ÈK¤�æˆC­ÃW8S- •Îù…›Îþþc}íq¢\©uP�¨Fbòèƒê¹ËâÆ÷uBLˆAVQjS•Í¿ýµ—w½ÿ÷ÿ¯·þÚ ½½O}í.e _~AL\WX Q²þ&˜&-®\6rÏc•½‡À�ø¦{|÷ÛO¬[×Þ¹CPK­èB�´WÈ*ä„GÞ‚%¸›$$b¸zꆞK.Y»g÷ØöçGLŽ1µ©Ì0'³¡†Q¤Òµ¬÷¬_ÿÙU¿ô¡‰�þŠ"Vªƒ*÷š&T 5 ­Ak@J*jžØ j…Pu/hZ%­`rdâðö]=‹ûÎÚX[>¸öò³Ê½]‡ž{irºZê¤5Ò:©ûa °Vâå‹.9[‰L`d¯ ûÝ‹„ ÄD«N\~ÝM—¬:q”‰r}k@Ì8ã Kß~éK‡ ©5ê$~QµP…(D¡ê  ‚’J±,W^¸ª·P!žMãÐ èP�Ä@íù‰�?aÉÐê%=+‡6]pj=‰žÜ²ÏÆI  ´îÁ¦5hCch’nE]©®î2©CjPƒš¢®¨©‡t•´ ™>ýþË?½ú#ÜX0 &"rv6'78JFsâÔQ�é\ʹ=1‘&åçþæÏ ßpUÕˆÔi“(TB©øœ)è’Z}MAr¥æTP.•zúoßöƒoÞ¹öŠó·Ý|Wmrz°¿7Ž Dã`~“ ³ƒ`#S>íDŠ’$ ›»W*yٜȮ‹W/~ÿïþüšsÏîÿîã7ÿÊ'¤:¸DuÕqæ/>qî™§,ùû¯¬øõߺ}b¢Ô²|8‹ b‡«[£=]8q�%T8»F(H ªª$vñ¢žrÑ<ùÀ“ß»ãþ�Å}wÞz?õ 1 Ñ`P�i'¼z’ž ʽiPJHUÅ._š|âãçvwÛOýÝsõ„8øA0�©¹ŽYmqH5S Õâðàñ¿þ³7^mÉX�u&3GX‰”œìœ™v(Å2”" êY&_ço¸caû×ÞxÅÓ°õ¾O~öŸþ§êèd¡¿gõ�—I¡˜(êêíÿÀÇJ*öô‹O½þÿ‘%&²†8�@ÁeàZ ŠzO\¿eõ)ÿ°» ZFÅ* Àï/U—ñ¿D‡öðíïX¾ü§^ÙU¯(‘„NsìN¤`(ÔvwÕN^[Æ D}ƒQuJE‚¸pÞY‹¯¸|Õ7o}þO~íÏ Oš>ñÄþw¼e�±ue€ljÉãJÃ1ÎÞrf„mý2üžÐÚP?ÿæÿ<³ÛÏ|ö‘å·i¾”Ç¢œÅ¶åŽª>R†P_qÝ/½oàm×XRe¨ó::Hp t^çrÚBÞ%“)Ÿ>þöF(©Zª�\·X&¶Þ|GmªrÜy§÷¾ë»®¾¸j%!#ðº¢%°‚IZ¯èH4|Ü�o'UI¼í6°}ÁY�@bK÷Oãéý+øÞGdb"8Q<ص;yôá±u—�õ‹o¿ðbŠ6*@LàÌJ®)ökD¨%µmbO ¨‹¨dŽQ@‡è¿sEïàà÷|Q!ž¿á—~fãy#H�ÀmbÚàOJfl®L[mz@F3I1Ô'ÿë×Ï8x vó7vÃÂB¢I ý—¡):?m*ÖÙÜ´(+?tÃq¿ö èîaRe‚cX9„¦L£Q±IïÃéu©$쮦ʅ  ºJkKäéÊá¡Eûzû+!#Æx•ÎP)`©Öpà194ÅvIAb’ðœíWU%µ\ «%2ÅÉ*ßwoí ŸKF÷G”ªoâ§WMÿÞ/�\yþX¹{Š&ŠRºo ó¾O‡v •šAÿ™¼è"5ÆKNñfp÷dmñ+»Øª]±<,�²ÆäœbìXµëj’šsÆÙì4ÚS"beELÆ<·=ùèÇîð‰)2Æ‹sq¸æí@m¨£¹Ùy*`û.Þtüýz´j+¬iÀžÀà [(šƒ¡³ fàpì-sÛxl"UR%+dIHK£RS¨v›Ì%"baˆbrDö=žŒ½¢åúËÄcP‚U«.©zF$ U¶*qÕ<€gžŽ·>-ÕñÜÊÅ�Ç€,ìÒÞúgOžÿ†ñ%C1ˆ(Ê;ÏÉ!0sjݰZ:å¸ÚÆõ´è”hà<†h„|‘žàÔ¢TUÕ4ÝRÈ4¶Ó öhÀФ36Ö€«98“‚D¼4f¢Ûï˜øÈÏ=¸oÄIÒ:R�rScEyéÐê?úÕžËÞ¨ä¿PRqü«‰iËjÜTYa ¯ñhƶ@AÒfQç€fë„0w‘·ù+@Ä0�µ˜<¬_‘Ñ—(�Š/?“|í“:¾Ï×��ôWyè;$!` +ˆ´ÑÊF¾×+©ll(1F„R\Ð$›�`"¨¹ð¤ø3¿»oÕª”–˜¾Ó¸|<¢Eà‚G0H°jˆÊ÷dM·½u/}àc#igÓŽ÷äðO½¾A„æ·?¾óÿ|r«¥¢eiÃÆZ»Q{Oy«!1çeh[ÑÜ(ؘ%?ucßû®6¤ø ñvg�AþŸnºC1£`€I™È(X*$bDY•ÕeU¨¨ûªQ÷—Ã6µ Õ«:=¦‡vê«[°g &w©LuJïø¬¼ü„ZU±«j¡µH߈{oI°ìAžè°ŸUÙ ¢EÑ’hA´Þ§¯H´(Z`)ì)ö颳*¤£¨ìÄôN­€LƒêH±Ç{F½ú7Ÿü›T3ñ’¤* ‘)ÁæZ¼jÛ—zš—n‰•C1œœtâÐ÷ïß÷êÞ:1·ëØjqõrAsLtKT[Γ’O^Ó÷ÞëaÊ¢¢ì”gç^ɦ EèÿTR"!09¼Q’ºVÇmõ0ê“WÕ:KX>Œ#Ei'zòêm-ªjc²u­×WIêD–àL>R3Üo»ßÓkÏefЄ›oÃÅš î6œ ɕ߯›«�”d5þô×zO:aù{¯}TW»Ÿkû0¾Y£.1½jº‰ Ä”5“oò 6(9}™Ëõ¢8@Å!ŽúA=h´Å4œ{'ØçÑŒR•X ºjeòó?»òé_Ù:ó¼rç”–É.�Ìð[¯ãµ«ED˜ P"eØ ã�0Iêþƒªºü vn¾xZ_ÑÊh”Ô½ææjÊ這:Ö¼×áå4‰ .æÌÔ&ù¾›ãûþYëU!xµòš_üñ×wR~ù­°}vÔ´©MwT@yÏDéüyŸTW¿ûÍ{J¥ T•„’1JÆÐx‹¦{åU©¦è(u³å‚roRZÌÝëÑs<™!ráU~âÞzf•¬Ç½#O¿õú%_øâ®Ûî­’i1ßtÆ�V_µ²° ë¥ã×,ùÏ¢áÁÔÁnAž :ƪOɱœt kcÝ!»ŸLF_B<^´6ÃwÒìAA¯ gìöošNº‚•Äf‘Âîm¸ãsöá[4žÒ¦“Ôù\ÑŒ×P ®íè�ÌýV™01U¸÷q/Ÿ¼R†ë4[°`ºêüã(Û 8ý�TÈÖ8>„Ê˶¶�¨Œh0·›�%PÊSU'å’°*¶»G!…ïܵ?‘¨Uxiù[Û#QvT›ˆI™†n¼ªû-— ±�sßA@ÎG¤©)ßñîTîQ8 Wdÿ;ú¼&£Î‚Îä…hÊyÈI¹¬6Zì_îç¾bf‚Q1Չ®çðÐ7’ï}A^~B\À,@˜5– ¹Ý ‡ÖM2]/>üLùžÇŠ¥¾.îîÖbI™A†È¯�r¯P¨�[_wü}�A ¶£Z}UU¹4¬ˆ2�P&c…]¡ W÷YY²˜ïøÞ¡=ûZmȨMZOå+ÀÏô÷÷]t¡rÑŠHjÈpR¥¼Ú©0*NöØ¡q¶ÆÕÝ€1äì;€�š(‰iì0Ækm:ÏBˆÔËD“`'W¯‚Šr\¥ÉìÝ-»ž�n×êTöÂióü;*¥Úæ]ºèŽÈ¦3y‹Bâ›:Jì0šà‘ú7?_þ‹/÷œv¢=ãäêI«kˆâRQØd“Q‚*—Ó®D¨@<0ÀË—$Cý±‰¥X)Á&uò!«uôŸKlXmv· �î!µP³|©¹öʡǞ>H(�Ä™ZS‡RÛÑl‰ža� kÕJsҺت2D½Jà¦'4c/ TAê±vôETD†Y)Yc�D Ê4¶>‰Ç´¯<‹‰QغÍSƒ<ãVM…DÏëT�$b¶¢Àª#Qª³P‡ ï©1q½¯Œt½ôû퇤@¶`ÀD’�•†Mo`•ªˆX»»dÍòäʳ*ï¸*ÞtúaSªÁFŽT3 Ó[À]Ô{Èe‚dÂi†4*ž.*]BÌW]6ø×·|’\LѬ–éÅ=9NSÞx Xqž JH¡’�‘0ÑtÆD“¨zP C�%0ƒÈH׋[+·~E6?*õ1‘a'–§jt£6› ÃûȈÂD*J&Ðçá¡^!&£€ˆ�p’ƒ]~©-oDA£UÚ5’<øLïçn¯}ðÍ¿ô�‰å+&5�]RÑéíZ âÊ @h#0ó(åŒwPØè´“‹Ç¯‰žÜ<POp\:=ÞízÜ�¡•½í-ØtŠ…Ø°Ï6‹b />«�H�8ýžâšNíÅjÌd˜"‚Ùúdåó‘<û˜H͉;JŽ[SÞV$@—ÓÃJÎÓí¥¦¾[ Q-´ÇËR¹îuG¨ã+S\S(ý65t�’�ÎÄ'È JÊ41=ô¿´£pÞ¦žEƒ‰R�Pd" *.U"… R³æ”Ã$'©…j¹Xxð¡‰ÍÏÕ‰#Å% ßÉ…l:WE‹…q†öªÝ]¼fu¬jba­Z«bÕZµ"� D VŦïQÄJ¦ˆ8b*2ïÞ‘üã_Ù]ÛÀh‹OnËÌjÙŽª;# ÕiBy;k‘¶?[}üþàéjž¥Î§Öøï{´6áÊÁÓÿ;Ÿ¹æÒYî¶Û7KDÐÄ¿ô�ø=7 ¯_“øà9RÕ˜m “kî® fÒŒ{¦"ƒÈÊ妧‹ÅygaÇ1K´:'"LOE+NÿRç÷ÎÂ0µÞq î½""~æÜËúøcvj⨵ùw<¼>ª ‘>ÿŠ|ÿYBD‚qWuB)G©•²D´Ôõa}l.”ƒƒÔÛ-‡Æuvô™µÕA:SR \6jIª¤BjI,‰%RñoDœ_Þ]0ƒYÉq}ºöò¶övšcc# )Ub<±Y4î3qD´®jUEœ²êe çZaùî“Þ>éí¹Àãy4[é8\ØŒ¥¨¨ @%˜ÄI)u3¤z»O„„TÕEö3¨>%ccDÔÄbȹ~GàAóâ¶�yj äó»Sc¨îÜckI¹«XºUÈÐÈDsµ=ÿ •(âR !šÍ.2Ÿ"› qÆ{ò Ú4bƒ�@I‰]´pHŽ#&‘Øjj<6Žt8椞ªØD ¨è£l|ñ«>Z(˜i¼µÞ‰­Öy2ÉYRòNÄÙм%œ£³EÑZ«bÔÛ „èÌuF¡ŒA(4R×(›ˆ"ó£#ìñø‘Xˆ—vYKÝG��Ñ"ræd›xææ�3øªËýgr´Ö&6” Y´±6¨c>F5F"ˆÀªÖ 9’f’PP«¨…:9š­4P•î^^4¤;ÐÉSÞ:Ûœ­¹>Fî-1ÙÔ[ó—;¦hóë6s»Ð|1:]¬sP¾:_“ÿ›[®aw–X»6*– Õ�H)¢&öãÌ?â£Ä݆Yת¶RÑô 3‡ ´oyÙ(V;�tr‚« ,IÀo')Kîÿî�‰’Ur©¢>ÔUUIW©tÂ)D ©OM!`Ýÿy´yàŒ•hÛ~;à_³FP¹$ç�ÕW`"Œ‹ejc²` 'D'!DÓIÓ¤ããfjŠÈ%ÖÎdçTÊÚ&À«‚(µÓˆ–àÃH\h¨ªu’Ÿ‰X²BVÈ*B)¨éÙgšž¾Ô¯ÂEÓ29m7&SêÏNÞ;ÑàDȰ-Ÿ�Ü"ãp1½ În×pqúìYUÇÙ âóm±¶anäË Êq«pÞŠ(j€¦`û&?†À›§}½:¥Œì¾vr:Í.¡™g‘+ã¨èœÊêo’LŒë¡Q,YRNU²:ˆPv”0G sw�P·��`ÃúòI§UŸ¸Ÿˆ„HÙ0ŒjêÍ—4¬ÓG’KÒñ‘¼0Ž%’Š0)B©¥éÿKñN¡*Ä¡’Zj?K�²Á¨) ˆ0»X. ‘ΫÍ*"@š²’#(|ªéÿƒÛRóÉY͸�îM`»š…ë7þ#Š’a à"CíÕoê?aYA%!ŽœÃ#ø }Ô1²0O œ Þ3!o’æ;’é“e…´#kVB4W}ˆÈV¦u÷nœ´Îy™?i>= ÍòŽÎ€]ÒÝW|ó[ëÏ=¥µIÀ˜¨X<õZ;¼^��JpÆ+˜”ˆY IŒ—ž®½ú‰À§¼°¨ë’eƒÏ<ù´3O^¾dq¡PÈ]œ¶¡¢>ÅQT¡¬.™ŸÔá�ˆ¨N׫Ïo}ùž[Ù?FLêÜ 1°ö„�«¯Ú´våpW¹@¬PC$’\‘.öY@nø)h㿹ß4`UÃ�0Uqé1êšTãúè×¾¾ýñg3©Â¬Z�¾c d\Ì�Mï‚_èVú(2ƒ �H\zzk564'·Oh5žáC;œŠëñË;8¾¬Á#ì�¹BÅ»5Æ7XÌI\d@À.µöü3K—\Qùî·ˆ�$Ž'Fpþ{íÀr#ØÅE["ˆ¥Ûë[nçƒ[H„”P�‰xõÆ•—Üø¦ó¯»dxýÚ¤«”* Æ—Ì3¾4j�ƒàQÚæö�àL+r†Ô7\pÆŸÿê_L�O¤ÜKTÖŸØýç|ÕÅç¯ê*°!D^‚L]¢�¤…#4¬§IŸ €j‚¾K ÂôÂÞ«²B'íøÓ7íå}3Ù¼søÌ�e�uQ6 §-,!ET§ºkæ[Ÿˆ7o�Å|ÀGGªâµ°Ù°G½š(õ_(UkÚeH=S¿+�PE´)rɽ€•ÈzRŠÅw½[¶¿Pq«�”_z„îûœ¹ô#ܵ š±’-Ü)[îL¶_'vAc0�€#Z¹qíE?qÍIo½4^±|‹áºÔ4rÙx@¤–VBhš²³yZX!(HȨ’ªf…ˆU�?Ø�OqeÕùCî­ŠPhE'öØý[¾qÛôÿø³hß�.CáKßýìû–—áB­­?JYLu¦ˆi =”ÏR�%èK;kÛ_²LªÄgò¶?}›ÎÙ�¨DJvî,Ü'«V‰J6Â};m£5Pà³þ,YÑe+ËüˆþÅ_ê¡�ÄU,=KÍØ.°÷ÅÊúÕ¡¼«wªZ0ŒDèø5õ�ÿ·Î:5b­�ã<[nwÒæ´0Ñ¡6­k69Š;þUë‘!@æù�¤!‚Þª¦Ú]¯ Iâø‘D]’tÃÝFQjÙ̧é¤Ë_”ÒoQ�2Ä\pNÏèG'þå‹2ñ²¢š¼ð}}ñ~À±QIiéð²k.\ñžë£“NØIÅzM ¤ÆÅÛùâïò€w¥U¬g`±R‘ñ}¨ìÒúHR�¢Pã*©³›{l �ŒàÞ›ã};B¬’ó=�ëŸiàÃ7V‡{&ˆ'|%cÈUûq®ŽV1¥îb¹¯À…DÝ0p\&S$SD¡dL�r´?ø•|q±`’å*t\ÇvñÁ#»ðµ»ûÿú›=O½Ü¥1C,NñßW^÷F6RCm\R³jfx™)#Ð4ÕU5%ĵ-OzJ•‹M(8CJ]¶ºÍ™hRÐc¯n¬ï¹í´i4!Oºœ¢¹�M à _%Óã›ÃÖH™êZ=˜Ti .ÅäNøIJJ$BÃל;ôîë gœ~¸E‰©0 A) äØ{QÄ1‡ÎJì E”¤g¥..Mcß¶Wn¤òê>1–½ðá…ªDu±‡_µã{Ãy Ôn4Yãÿý¥â¿Ü³lÙâicÜ&‡xBRh¤Z°àe˺Þ~Õ’+ÞÔß·$rUr‚°+cÒ$à|^³wUÀ'w �ÓÔ^Œì™Þ[¹óŸúfÿ½[Ê•¤lœ—œ’ /2¿û_Ž»ðô#fƒFìIí©è“㘬x#YPªÚñêÍ·ò¾1f×–bnNš™›­4x5j”“Éñúß+œ°¡^4L>µ;õv5¤ùþì Ÿ@jˆ¢z”ŒØÚËì3?ÀÓ·ËèK¾QT‘˜þÁž Ï|çõ…³7J©§& š ‘öÙgp¥«B)ƒDpÉ A°|“�¤ÓËûúÞù†ÓŽïyî;öØ“–`©ÕË¡F™Ú”VWÀÔã¾'v v 4�D&b2lpÅ¥?ÿ±õç�i‹Å˜œé”Ôµ;Ê¢¤¡’¡7|RR¯D Di µ|hwí@õO÷}ê[÷>R�.ET4l­hoüþw÷ÿç�,>a¸’Ž5ϧ(%?”±ÂŒt(`5MÞ£ D›˜leËãøÆ÷ i$luN±@)u�—q €B @•§èã•ö”�"šÜj5iÓ!±*‘%� ˜E0ÊÕW'ÏÞ¯ÏÜ)û·ÁÖARR‰ºúºÎ>­ïo.œÿéé‹•“²+U±ª.Øz`¹"Яñ’Pj;ðÆI@ uzÃÉ+?úÓ•]P=°†ü)Éù•l3êäg/2”_.*$ç�Áô+Øpê!DIìQ.².ÍôVE’3óÀp.p¬õÝ“ŒNlÞVþÜ7—ß|oyïx"ŽŒ&j#–óÞý§�-½á²�Þ¨ŠÁIZØ‚šS/r;’Ù�©VˆÔ›žYTª•}õÏ|¹kÇÞ²W]|zƹ:ÛÌ©_Xàe�ï�ÿõ;ÅUë«åÈKõ ø6þàñD`’HÕXÕINvVdËCö™ÛôÀØ)•ÊåÓ6ö¼íÚò…çËÀ`bbÿs¥`E"¨7Tû K0Óåܵv,Þ D¡~޲F =¯µ±µ´ríÛã,Ü-”¦3šN¼²l ¤öês¦�ïÞaëLy ¼7[!Yö¥—ýäAŽ£)ƒ¨ªñ8Þƒ‘ñç^ìùüw鮾—€Q=~môá÷öð}k—(Ùi"rþòé/¶�K:à�«h®J>„ÞBdÁ‰åš9<~çw»¾|O?´ dCï„9�9^šò2DY+OßÓÿÈYtáĉ˼ »JN+rþ�•Á<Ù]É¶ÍØ|›îyTãi1̱X-J'oèóu…Kßh‡b°XbgH°i1!õŒ99KÓ–[“‹W/¹³/¦Öjm?&·«T ‘5Ê3ðîy "aPÒ_¨™d#[Q¬S48_¦ÍQWì̇ƒ³rB\§ú¤ŽÐÃc¯î*ÿó]Ëþm»Š¢f² «ñŠ¥úÎ?öîáÓד¡˜%QNË@keÒÚyù3 á¹V³¦ñ8Á(–˜£RtÒ ]×^]¼äR]¶4v.AR±DÊL¹™C¹©rOfI Š ¥ænñ~BN¤~XíA®ŒJ}œa¹0uÐÚÉš™Ô§Ó´ä6­U²Òti{M/³ªóô \*ÕöÚ]#(H©W }¦4À¦$I_”Vɪë’–‰;¸·ø�ûöÛ]�ìè�ÁL†(±Ö Ê›¯îÿ¹÷-¾ð4*E‰jXu%îUüâ)øì2ÇdøG%HˆNç²á�€ÁÆÆÇ^”?øüðÃÛzÓœé0‡’õmêÏâLYLb÷>_»åË?ñóÕÁAiò (L\sÌö`=yîyÝ|;^ù¾Ö&A‰QXD¦´ê¤Ò5—/¿BV¬¨S�­+ÎÂÂÁì-á�wzc\Þ`E)Z¥Köz? �¨P2¦´oÚT­Mëãwbß6™Sâålƒ�1„o>PØ´nø—™ˆm©˜ ,›àÞZöG/Ì^YÀ1¤‚‰ƒtððÔsÛ£ƒý��‡žíªØ†"aéꢋ..ÿ‡,¾æ¼¨·d! Ô¥sºà/EûžžWª—{¬?[Ndöf-!ŠU+8t ú ÿé—}ñ®EŠ¢Ì­0t3\‰;8 äkž¥zWVD&àM*ýY¥Òù×è�µ]¢6DHhd5:�ÄÛw$[ï’—�Ê~£V K(ñò½W\]}�¬\¥Lþ\ºB.LIh‘åâe¡ÁLTf�¥T�7jhZ@ʇÐ)‘ºfšJ‚‚(W4zîÕ©[¾=ýôÃ4¶_¤æB>ÃBSèÏ…¥àIHÔtq¼jIý²óðs?ÙwÚÆš)1Sd”˜Éº\Š)�¡Ã‡*‡ø¾§†>ukïO–'k%f£°"(E8çìâO¿é[.íZÚWƒÖ ±AŠÒàóŠÔ�F” $Ä5A S“¼oòÀîò'ÿiðonë·ejT¤ç5YXÐþµµd‡\¤ —ÙZüð7£Útéš÷si±}eWüÌý¼ín™ØAš0ü„† ¼©ëêëõÄãk…’Š�õ¾>WdM} Ý@xRp¥&­œ?DI4DÚ¨:|‚ë»àÂÉ�ÑEq�ˆk ©®ŽÞðÚ±]ë•£ùå-ñªC‹ê¿òî‰ ‹&‰ ÊS'­éÄ4K¦âç^êýÇÛ†¿ø@q×h™(b#*‘J²v-Þÿ®%~{Ïñ+Æ$Ä‚“̨ßdÌWœ aä9¼•Ùç†Ö\ÓúFÇu¿<øìÀ'¾Üwë“‹b-À+' Á¯a¢9ì,"¤vÊ4‰Ÿü®Ž�á“ñÒcöðVqå�ȈBû»Ï½0ºúZl8©^ì(Y 6ê”-QšÕÚâ ô¡f�a¹¡¤„“þŒ„ˆ(fA|P1 €Ð£<@¦Ÿ¨H è~$/‘È:*õS}úhH@)<\ÿi¬ˆO^4¢ãÓÔgÐÕ« $ULN`tŒ¦âWö |áÞ¥ÿpGqÛ¾>a±ˆ -_V{×õ½~÷Ð'"¢  @¤šfä 9IEƒ¬ãí�ae%¤Ã’ Fë�Ú˯vÿã]ýGïŽ=Ì%B옰6Y€ç�@$>\ ¡îÐL…˜‚ÏC)%vÇ#ôÒ£%%"ôÏ:7ºúÍØpZRêb$ÖW3dΜz”³Å"õ�æ8Wpèˆ{!Y‚••]$‘Á8ê/©¨QݪF b̦ QŸ©­³Æ¢6f;k•¹Yñ&gLpÚÛ6ž¶{j4ØÃš®P½>:Ö󭇆?uÛÀã;ºc³’²•dhQrýU½{ïð¥lb(©ÆÄq 3ù¨� iR8…’i¡ðªzi HàRºL¢Z¡Ãc©î~¥ëæû†þáÎòS;ûb1 b�ß„:3“lƒ@ÞÓF~Ïæ‰†)åò>0bU˜®RaÓYÅkÞ,›Î¶å.…!‚c/Ü”%—²n‚hÈÇ9G‰ˆy›«>XFDbyç�êƒ[’m[ut7’*LÙô¯(,Û KOÓò=\°,`5*v÷£Z=<{pó|‘ Ĥ;o{làc׌ Z3ûę̂T»¾÷Øò?¿­ÿûÏ•&¤qd„ckzzj—_Üõsï_~ù9è)NÃEbÁ$纂—òRÍÜÇèÀ3ëNÚRœ¡NÍ4KÓã8Üe¾ýÐàßÞ9ôÈ åØFÊ „&çèXøpv °ûó¸_.pÕG’Aa©P.n8¥píu8óÜZÏ‹H¢iÔ¨K3L£Š3åÉOîî£päÒÚÖ®r1˜fÏnûÀ÷'¸Gö¼h“ª*DÁŠçJÜ¿®¸ê\Zu~¡lEw>œ<óu•Xg3¾/…@Ó–ÿðŸ{{ +¯zÃÁˆñÌ+=ÿpgÏ7é©” ™ˆ5±ÔU”7žÍ?óþ%×]Ò5Ü]%IÈ:1Åu�ËBc�Œay9&ïãš½qª$¡EUM+£84=¾;ºëÑ�OßÞ{ßÖât\fvvoéîæÉiQ˜\MóbRS¥úÙšÓºR^„¡°ÍªdMT(®;Ñ\u�ûÆúÐ ‘œÓâeB©¼ÄÛ€')2å¤÷ÇÂAˆ$Àˆ2”ÁæÀ{ß½ñ½ß�÷¼$X}x¬’‚R�FèZRè–¤’Lî!;JNµÁà¹v{lúÀÙô\]LMú µõ˪Eƒ—ôª�r2¢Ö»éÔâGnZü®«ÌqC1I=H*IH 'H[l<)&ù`E%ѵH¤"F|›¿x’F+•òýͽŸýFßm›{'ª3„ÔªY¹¨vÓÅS—n´7¿ð•û{'mÄ ’H v�#é•1+…BÊÁÙe ÄDkV/¿Jßx• -µê|ïYÅ`ºÏ°$µ¡¶ÑƒBè…èrVeO%DDÊãcxèÞú÷nK^~R÷!¬¢ RŽ„ ¬ lì"ÿ}ñX8µ�µ]rÎQB Rç9†X( Sd‰È*3éñ'ðO½³ï'oè9aYb4V{*¡œ[@/ôøŒÊh�b‘Ú”)‚‘²U“ ™¤ñ){°öä3ÝŸ¿uøŸî:0Q,œ( uÇ×�;ñ±«Ÿ·f¢Õ«Õî/Ü7øÉ¯ îÜ×ï*ºf†�4Ðr!qaD¾³‘—? àþ�®‹ß„ko¨¯Xíd\Re%nÏ•Ò$•T §ŸÖè³¼pÀ…ðÃ(K45UxüñÊ¿~§úâSOH5Zì1‹NäÅ'£wJšÔtr¯}IFvèÔ!P�ÈÁH•Ñ —£‚@ÀÌ QRQ�’¬^�›nìùÀÛ{NY›D®8—8Ó2ÉyßgjæI“›4XçüiÜD-Êu B“SöPåÅí=Ÿ»sðËß+½4R6(ºhîR$o<}üg®¿jÃØ@±*ªÌ¤j̽ۗ}üúïyfQ̆Àªâ$soí“Ù¨¹ÙJc{ì4"1 r%eõÅ%Äë7”ßþ®øÌó’¨Gà*qPNbIñƒ;ZR“OíÕ%h¹8|�ëíY¯ÑsOÙ;¿UæI©M°�ç* šeçDë.²KO‹‹ƒP…Qe²œT`^6Ó›ëOÞ[ßõ2Ù‘X6­¥,ç‡@m~m •9R‰ ,tù~Ç[{>üž®7¬×2ÅŠzÖ8Ñ÷Ùsñí™u+w„@WîßGü(‘*Y%KTÅôFk¯¼Z¸ùÎÞÏßÞ÷ÌîkˆA¢ÂFN[[ûØ•‡o}K×÷¶tM× d`1xqåmN}ôʱ3VŒQe8DZ*Ô7Š1‘ô÷Òâ%Ô5@T@dNü÷�'ŸûJœ¸^ Îýy"PÓPU YÖ†H ¥ ®à÷üt<0,¡Œ¦™©¾åIã³R]­1æËÉÕ¤¾Í’?id )™‘½üà]õï�ý¯ Ť†E@ƒ'Ö]!«ß—W¨�2#5`-(+Ö)-"2–UÌÞLBdØÄS|ï÷¦ÿå+öÐ^ëO&;¯:WÁƒGDB°¢¬}ä¦þ_xÿàÚ¥VQÕ)õ€¶0Îü‘õ×49 ½(Aàð ®Cª˜�÷™Ç6÷~úÖÒ·í;4Õe •Ú]N®8cú£×N]|Ò�Aª²º¾™Á»è]w/£þA2RIܘ]#C¿ð«õoÝmÕ„ †pÀR)6µ$Ï� .ćœøcN>3úð/%CË vFdעɓ࠴kNÀA T�!€j kÚ|Ä“ãúøýrï·e×VˆUbW猻WÒÚ+±ö Ûsœ%¡Ä(“(•a‹•Œ¥�’²°‘ 0†@!"³[|ê©ú>WÛù¼ä¼kóE òÀŒD±nåÄoþç�Ÿ¸¦T.Z@É«ûÎiy'M£þ©)n¥4”Ÿ�ˆ±J›”ƒñömåÏ}wèËßïÙ5Úåâ@ÕFQ¡~ÖIÕ�^;vÃcÃ¥IQRÖ$LTˆ´X¤ÁE:¼ˆŠeÎv'øh#óä³ý?ùËñ³/إƇ$¡#C ÇÛ‰0ëø#ÿ99q“Jj³"—÷¬î¡ro†?Ž LCMuF �ÞØÔ§±õ ¹ûvûSˆ+@ÎZ^­ºk.�ŽD¤–”Ô()i$ÜK´’°\¥KÄ^L +J�è¤FUˆ$ÒòöíõÏ}ºþÒæàIJ àœ(p.\Ü›lX_ùƒ_¼ú.@4²ìQLJ,©æ|æ¹pÜ�Ò” ë­û¤àT—z…Uö¼ÐõÕ{ú?óÝ®göu)ÊMtªڇ¯{ç…ãÇ÷ŽI|PYvuÌÖéïãE‹¨»‡¨• ŸhˆêTÀPd>ÿÕÞÿôñT­‚ͤé#C v¾òb©ë†Ÿ®]ycxã•$œB™=£ÁΜ3 †r„GKPCÌVù•çôîo%O=¨•1%5‚â@´ø|^wm2|ŠP7‰*¬¬QL=àå$ËYz²†ä”’�ÔHI 4‘�U-H÷ó/Ô>óçÉ«[…#™‹ -¨HáìúÎ�P=ùøúÿFß•g«�²P JZh[Hw­>=ê©�#Tù÷¨c5™æ‘úøsëƒ=óí¾·÷Õ42¤ª°‚‹§ßyIí×�n\6Z²µTÍOÖž2†©·\dGûh‘®„˜ˆ*ÕÞ_üŸæ¾ž€£ÓmˆMÍ#Ðc¢)Rá gÛó®„�@5¥H45¥à OI³éÓ¢wîš d ‚¢©{ß-É}ߑѽ1T„ÅtG‹Nção°KΨ™^¨%M\ê))qWMV°®`ÛÍÖH^ÀHEv÷¦ÁàíS4”k˜>~}÷»?jÿþ�1¾‡Àóö %á¥Ë¦ï¿–¯8»)ȤåßmŽ£YùÊüçÙds— HÔÔTcŸNvÓ�üÕwú¿ûxßx ¦ˆ­Mú»+Wž;õ®;íd/UE,2Nà�€” ¤�~D˜Y‚9ßGdû«…rwyü—>tÕøÛÎ[Ö3¡n$« à0Q ´§Lƒ¦«ô©,,/gõK º9Ä%7]ßýůë { ³úÚÀ;R( {¢MW¢ ¾uMA“‰Ìéyoyˆ4|âmn0å[ê_ù ÚýŒ’2cðsò»“%ç«ö@c©OjŒèh‰±C„ȵuñ»ÏNö}^ôÉ=*"4o¿«õî�®«ßnv>c'v‘FYÓ®¬Òúµµ_ù -*'ÄNèÉ‹ÉySEþÉ9ãa�ŠÔ‘ra¡¸"j�<Øû‡ÿ/=ñ”mY›s"^ SU�‰¦Ï9£Pø—b"2C_¹ŽDÞ›ÆfpyRQP(SÙ—ÎM¥¼�”Eé+'F)zqsíÕç„ äM" ÃÖ³ÝwÂKUSåÄÝ_œ05¾G^}Vž¹¿táM…s®¬t•ýD‡dXP³Þ¡õI¡$+×ÐðÚ»¥3r§YEpÆ)ذº �&R¨õÑ.¤z‚˧¥D’Dy÷³§ž,ýêô=þ‒ ͯÝM¢ñJA©H¹s‘Û 94UÚ±¯çîÇ“oÜYûí_¬^tÖ” !Ÿz�9RK�ÃY‚¼šª~…Xcµ¤€•�'ÕõÙýcÎúê8o3&uNÀ† .U.¹Þj Í/ Í‡KH€°DVÉ* `™’¶>*õéÆ2 -ÑÉ‹áJBü²i›t„Ω�ï«Üõ7æ�o—«Ê"ipŸo"$­CãË]毡DÐÝÏ«7ÌÜÂÑÁ>b{ÑY¶·g\QS­«� ³.qš@ßúÊçdeÍ%= ­"Àñ¡ƒÑïþÙÀƒÛ]ƒëüáshâKxꑽÈõ11•¿÷Tÿ/ünï� ²pèì”ïni³ÎN’@ˆ%õ¯ô}¨¹`¤ñŠeÕ‹ë"¦}ŠàÌäy±ö +"h‹Æ¡ó‹„Èùò# �Nv¿Ð®=q#ú"í‡Úò•º1Òz­úÀ¿DÏ=NR$÷8ñ³¢6H“ý™^CÖ×XdËEYu ¸0ó¼ÜÓ¥gŸ’Dˆ5Õ8”áw$­Âªošo! ªVÕª&¾}©«ím _ývïwê2ñ}Úç>‚_H…‰6ïìúíOwïéŪîqiƒ\›Kiy¹ÎÙôÿF’þžúò%‰zÇ\ûÌ ©:'XyЗé†f+lˆ ÕηpÌž]Ï1%ÂÈ>ßïj4bÌì^ÌœŠ,.›-©¨?úÝhÝ&ÛÕ 1¶`3/Y˜•z‘Œ, "^¼ŠKZÙ/Üuƒ½M Ðñ+HL>^G�ø•‹·öIA,ònœÔN¯J„ýûºþñ›åɤ̜257f‡FÊ�Õ7q¦{Ÿ(ÞrwßÇÞ3*’´4³É]žg–(�Ô•›V(å¸ÅŽå#ñ4°UFOªx¢ˆJÝ9¾^é'9än~¥$Êå8r>~õéYÍSs.9Ÿ±ë)³o'ÄÀ,CÚ¾©£ûÐŽœ�&,VmÏ ºûC/’ "84XºÈ÷ÕI3�püËóˆ$ð! |ÁQM›<ê“ÏšÍ/Á²O\nb.k�*1n½›'*EÒjI'æ^MN€$ÇÔ’t¶üqÆÔ)‘í¸_êuðÆ«²QS å‹ò½6gÃ�Ù©(å"ÇH«SªÉcOŠDœÔ§yß«XyúÜËúåf¨Î;« b!ëŽtkáÑПtÉ`ÜSªˆ& qùý¹0ô¦ù!gÎh€Ÿ(™§¶ÒD¥@|„ÇÉ¡6”ùé—̾ƒÅ¾ã|e4Íîœs|çýÛi¼T¶gî�@•`ûº\Á“°M‹Í¶â�¯óB_¦(D[S®‘I»�Ñl�«$Qkí Ùl;ÞÔÕ‹”„Ä¢2Fiºæ\q(-máò@Ö¹ÐM`²,ˆ,¬È¿葈Ò$ GÈìÏXêÂm™NàS@ÌþƒÎû–vàk gʫɌk¾`¾�ž(Œ.`\C‡Ì¡×`C®Ð’f³ôʘØ`-cÍ-2sÊ;v, ñ…pWTÈ«�©‹´ãÖPÎ=DgÆD]PnŠ®ZÈHía®·¯Õ㥿„µPײuY^Ör‰ …¢™„ 8§­·¸4Ø/ÜyœkMÃÆ.t¸ç K¬q½náËærY‹åPÚ›=Óä3ÎûìÚŸN�QˆvÑb‚8ñ©JÔ&̪ù–”û"‹‘pXÍLÝZ(!‰ÃH½SŠ)¦,]C.—é“f@“Í[ £ä¢¥ZÅXOU +i’ÕVj…n&©åx—Ev¨-5†D.x¥îRÒ×m=ÿrEP2ômÕ Fk²;K|W‘¸Í\s3ÊÖÙøÆ¯J-U')ö8Þ¦�]¦àe~ Š)h]¸�Z ®àže26é,VùŠQáWs*MýÊ\î¡Á•jÓLê¶�MY½6bXʧ\¾½º:C3£`’@Õ `ÔúºF¾28 Ï"ƒ²Mi¹"_”†4Ù¸>î*Æ[@ ¡Û L`X+æ„UvÅ’º 8öÍfÃÌfAOƒ[A„É)ÉKR­c¶2¿’ðôIºÕmu´ÿ*ï.SŸÎšô.5«ß £;aÀÌjšyé Š–ž «aµÓ!nq~åf°Å%®‘M(©ÎFÀxjº`mÄ<­é­T›=É™`šúáÃyJy„ÆgžV=~Uýée¦# @Áec õ«/® õNçüH�ÆÚ”F·Æp5]šØhï)¹Ö¸9Qh M0 ¨èä!¶ ‰’¨ï†š{Á¦Æ_oEK_Ù5.—Ò b:å*Ó»Úi¶ U?BÃr?N}s\ì'kÃsÑlƒn°M§ÝÕÕævÞLghà$!gbè°›ÆÆ(®3§‡ÛÑ­|%ÙÜH?iÐÂÜ)·ºnÙøn¬£ÍÁ 9Ù¶ V6m!ƒ ª§®­¿ý²ªÑj{cX†Óí°'oòe?0=Uܹ߸RC�v¢¿pÕ/Ô5’TÛKqÍöqEBU4ߥ5Û å6,\£�hB6A¼x½9óFŽz È�ÑPꉼùŸZÄ÷'R&†!sòeÉÊs‚­U‚É;ÀÀ½DsŸwxæ÷ð C)ž–ê8«"W¾ƒ4u—yOË�Qž¬’Òã”퇊ošZÉœU’MÃÛ;"ŒÊGnœ¸áâi£‘2ˆ L.¶5-ø’¾ÜŸéÔ•H‰”M‘ö÷Vþ¦øä£ª®¹‚68vüžrpàä¾òäßû‡F¢—÷F”¥dÐHÇLB4ÀÖÑ]<=†¾nh’qé4½#½¼´ã}ÞiÁà 8¡Nˆ’�—GÕ1»ùŸ5™"R_ìhj”×IÉZ…nºÉrY%•q¨MXRÛ¥eò¬?[ÄSãqeÌ·áépæˆhßXtp´´l§EĽ¦©Ï9ý ÑF˜�£©ÈòþýÿES­â»w)º‚+£ -¦¥ð&€Z5î鱿øþé›®Ø[°S¾¾¹ú:9iÕƒ™Áªb†ÀRo}¥´ÿ`WhRÐ ¥uh#Vb•¤¸|“ GbUMFiÒ¦²õ½¦æìû‘5�tó=¼œ@„å'Q×°ŽBm "õÌÔâ&2P£ytú[ôŒ÷Õº«¹*¯Ê¹§Ìú"Ÿ™ >–‘a£WŸH¶ß­ÚÁÄb)Á•o¨�ºnÝø¦HQ÷= 9»}.6»=¥'¥…,l|ÂâýŸüÅú —õýîÒæ­…c¦nI}î5øØ¼Ñ€zÊX³:¹ôœÊ›/¨o\r(”ÀRNq˹åróȪ Pó|øžì¹ÿñbHcK £3#PfD-œ¨`÷´ñíZLû%RŽÊgöúŽ#Yª`÷žD×ÒÉ1Õ«*.­)«·LþÎBGĤQQ ½‘*“¶4¬m27M�ÒMÎ}BRe‰¦§ìþgµ½¨á&¢zÿå‘ñ®EýÓ^:p<4DÕ¥†ÔfþÓX:9oS±ÝÑÈ[Î:|õ™å‰‰îñJ1–H”ÅyfCÝ %ì©ô›*Q�¬UòušîžŸy5=«Î”†L¥IÞÞJúä }�mïÃìxF}¹�š' );òr´g ­}“:éLá½°yµ°#‡Íms¶�F �5]@‰ ýÄÍf¥�ÓáÍ) ÄY‡Á™Lý�Ë Ùò.÷þÐ 2úÒ,:< ´yGé©­‹®¸à°Šd•Y\<ÐVÝM·?ƒo€žªÇAX-¢2Ü;5ÜOà(²@Õòw "¹’sÉ4í™R¿H͈ W�d“®¯ß=t`‚Ù5ÔòÓm³ªvBt@èi¬M&éÅ»xÅYÖô4ÄñéH‚(]¼÷ͨ„ÿ…€ÀM°mC.S–šŠéMðí<Ú˜ƒçÌ)l¼ü¨ÔÇAÍAÑù zW#�@‡¦qË÷{/9³7âÉ|‹“Ò>£°er¹©»è3R•PZ*?ßF(·ÄÍ6¤²Qóåá“F[AÆn)G¨ô…Wn½· („Ù¥ìœ#`ȉìy2Ú³B¡­¢zµÙëðsyÁë�ÜŒ^ÓN-# Óš,!ê;¨äzœ§¯4Ôd¦ð s–œÂïÍTÑá—°óÁ|æõ À¬eúÎCÅ^YJ¤Ö)ïnäRðfFšŽ²àMG^-jcj.îܤņ˳›¡‰`P@(PðЖþùîþç÷C†ÇL`iÒÂ¥A3cR ©!N°ü,墯Ñô r µ(;Rdõ�ƒÑ§‰ý9dƒµ´”CÕÜ_á¹J’Y2H};A#±Ùömûê}¹ÒŸù�jø—ƒ·úð– u¿ñŒ Öj¾*@Svšê<ˆQ–Ά‚3ø¸æ2¨E£z&?·kío|ºïÀh„Ö– -ÓV�Ï‘ä|qR9PèY��õðþ?‡ÁæÖaAùmxù‚ƾœÛfž+B éÅ3ó¯tpšâèH7Á‚8:ü\òÄ—%ѼšÙŒŒ'¸¸sÐÁCzÍ9C‹ûAm¦þ¦(à‹my3�˵!å`ãÈ ÙÚ³E9Ù 3I¤K_Y¹�…眹$œœ–_¥¯´¯%yC9Ki¢KþðË+nù~dÈØl÷ý³4}hHæjF Ê ¹L="‚Ôyú@´ø I¹iËäí.™ªÖôUî$½ž¯ÆD*Q2ާÿÙxLI}�ÁÈ¿'aä°r´èò³È`”|žŸi`i¼OÞB©-ߤf×J†‚:ÍosC©�ã_LaGŽ=™Yr¿j>MB°Ñλ“羦R š ¹šmª _�~ÉkÖ¯šÐdÒ#�Ÿ[ºçMú@{pŽà‡Ûgsö´¤=ö´Ž&±ºIÇH%qOÕ�öYƒQiçøi¿òÿõlÙ™“¦Mp; �Cºv,LóW;SI&àÑä..-ÒÁõê\¡ê7ΰ$_·±TÊ@ž Sþ(¢�­9±×6(y›ûdÒ’6¡‘O�F·ÈŸ×ʾ¼+.Ìš‘1”@´)¨�— Z©È«»ê—¼qÕP÷HÚ§¥‰\½Œà¶rN¿”¿¤sný$}hËW /·ðÎ|ªù>Èæ“Eò=�yBNýŸüæ= Ȥ­7T×|R£B3¥êm#ª§J/ 1ƶz–i÷:!Kjаó­ç¤ 8¹$øï¼µ#+Ï@ª¹5¤Ç‡š.ËŸ¶@ÂqkÀGuð¸<¹Ó>ñÙ"¬mNXR”i¹L€»ë@<1]záÒ’8 ËÓàÀ#r7Íû:Œ¶=ÛZ}[Ýe�¸Ë²6áf …©–Nþ“¯.ûë/ÆuWö¿Ó­í„hí„@á*¢dc;Mß-¯ðåÄsy×ÍDÏsm˜‚<’J$šÚ‚﬩cM~H‹à•ê ^CÌýJ4ˆñ!"N)ªïÁSŸ³{åÊWÏ�ü'Ê´mÇtÁ �{ö¢‚Ýï eR¨D’�!¥ýsîó¢�Î6Ú"ÍåŽYgíÜi%@QHÊ'}æÖ~ÿS“Sun¬Ó5"jÓ!¡ÉQ¡`ŠGõðNÓ»Z»CE]¨R^ƒ5¡™ ¦wmU¯ò�餈å1GŠü›œÉ-ç� T‹¶P߇§?o_½[`CMÙ yÏj ä(S‰„Xè‰g¦ú»†ÎØ4lìA–ÔxžÑ?jX—ûÄ#~vì4'¥Ï줴l¬vÂzÍòñ³Š¿dH ˆâî?ךßüóÇ&M¨\Ü¬Ûæz3J̃…åCMõ�Œ½`ÊCÚs\p—hÕ´·kÖô¦éšT7i1 äl‘þ=rœK} ‘–¦_Ö§ÿN_ýžï›ÑtÔ(õ†Î€@ »æhÛ´5ož(•‡Î|âHFTë€RÞñžÓ§Â'!x!€È.óAH­ˆ’r°}…òH–¾—”ëçÈJ•¦Š§üÍ7—þ¯¿®gd‘«³›ÆÂòŸ�S}#Ï.pÏjá‚�À•p´ÚªBÒ¸Èìd„Ò"¹7�¿ eÁ?̸¡�¢?=Q·åDqáðSxúïdï£.³µ�r€1grΆV-~°y¢÷o:}Ew±¢Ét®Ð]îIi)äT˜Ev´ZéM3èSU`V}S3ÔI?I'Dåå{ë›~ïóýøù©ÃS&—¶Ô]æ�@ÞS뱺“:d "N&õð3Z;lº‡µ¸ˆ”H@\'æ ‘hÃNû ´š[_MsöŸ§ôÔwPO¿M{ß®DÂB‘ Ëx´ûNÙò÷2ö¼P¾ÖIÓƒ¸=ùi¾>…FΪFT·xô©êŽW¢õ'¿lq„dj e 1Rîpå$ÄVóD Ü¡Ò)ØËš©†Õ‘›r§4gÏ$˜’íÙðƒ§ÿêÇ_º}²’üsÔUaÊÈON©msœ¨½�¬Ò xçP©nÆ·áð³et-V.)„„¼×*çôÈ �®�v'¬ÍhÕHŽ¿Dð{©Ê¢,`Mxj¶A^üUF¥Áo;ûQ›adnHde à¹ñ=�L—úŽ[ÒªR©.É4Û,:3pjÆP3iý³ J$„vŸ à½KÊi{ËÒÿö'£?k¥Æ}§¦v ¥X١иk‘‘KVtA ùR£ÎÌ!¬J`�€{±ä Zy• œ¥Ü u¥¤Y`‚¾,¬B›ê�oµ‡ž’CÏDS¯ÄÌB³!‡c§³’¿Ù9Û•®•… õÞ9sc× —÷\~6Ÿ´|²ÇŒp}”둺jLêòžòÆ¢š“óGÎõ.!¢2qŲ'¤Ûž®;(~ãžê“ÏÖ¦ê6hþ›áɯ}AÄ�—µŠ*YmöÆe!D(öSÿJî;•z�§®a*HÔ“PÑ‹ÂYº]›}m vßxy�Xc’iÄ\Õ‰Wíø;ñ"*4©Y%Vš•/:F̺ š �¼‚ÆJ®x¥¨�X–/â3N-^pFñÌ“Š'®Œ†‡mw÷t‰Ή*ÈdRÉ3w_õñ*!ÖÓ+œØBeº¼ïp´}/?¾Í>ôDeóÖÚþƒ’ Hd|–„C’lÒ­”2�#D ôŽ .�eÝ4Û鮓²’… ÈØô 0@¥!)ö‚ŠDW7¹¤ÞÖúº¾ŒrŽ�…4x%;­µÃZ•xBm®b¥,©A:˜ÓÁZؘ šÓö}-TBÜUÆp¿9n-Ò¾�¨\ŽØgyå©LdS¼É…Z‡ÏÜ5!®µR×Ñ1Ý?¢»&£‡Q­Ö¹ Éè¬E ç Ÿ¹#�æF*Ï�Ú=T}²�x[g®|�¦’d®O^Nídl‚Mmo³>ý‡�@¹åP#qr©†JœÓ̯›=³ínJìB³}ãÁ ¥?;Ê4K¥ú|EÜPOwîΜ֧ª„…eÆ·FÐJ]­-õDÛLui¬²à9½n#8”1gZ,m\§iÙ¹ÖMM[0ô%×tÅPVa�CºàD¼9�ޤYyÞÜÞ¸`øƒDºŒN£‚Õ7ã´™�&ü´±,Lƒè3#j¸Ò¿mNL[àQ'<���£Ii«¶üºÒŸ`þiüuî2ÓðkÊ“åÈ�­ùDŽ&Ã^GU+³!ûN­ó;Š3§6¿ãˆlw¯×$_£Ñhìñ£“\Òr1åþ?§;Ïiø²Ÿ^¿ž7<;Ê…ó©cãÇkhª×-dÌ”–+�æ®Ï¥üìÜD°ÆgÍ0ÿ6­»Zí ­_½VLn£3S›S*ÕÌús§kh)EG> š=Äé1:6: ¦¹ aN—ÿþF¤BžµÀFôÑç4æ¥Ípñk§Xõq´¦ú#�9>r!†þcãßÃh±ë´ǰçØè4RÓuRm`\:6þýŒŽÍVü8F|Ž�Ç\beŽ�c£ãÈ;˜¡ÈÇ[#EÇF›1WÅï\ðÇÆ¿å1SOù¦q ‡Ž�Ö¹,�¹ÄƒãbÇFë` Cõ™¦q yŽ�vÃÎ!ô톯ª1³eæuL0úw>f§@3K>G#}lüØ�ÙÔø¹Åcá‡Ãmù¬–èÙ¾OC²ÙÕ 8‚„ÇÆ�ÏHKA:_ØLWÎã¦4�ë_¢uŒ.¾ã(‡ ÍqËB±Å×pƒ_‡Gȳ�²¡&ËL7háYZk.Ù/¤|·þ\ç®lüŽp½ÁJfåÍ,D«º²žm�c.§Ÿ^3 ¥S�YÏ_ë 5 Ø0‡ H{–ù1?®A¡xÖk0ŽaÏë0\ßxm"çç´-¬'”ÀÎÒè›îÓ€/:Sºå±ñ#;\ÅdRÇÂ|búQ;±)Mj{Çcdá߯p¬*M ž57]þWù;Û¯Dè£9§Ç,l>sB;þá;-Ìã¡éŹÂSÍw&´©‘˜¿H¼nֆͥø#r×¼nÄöh?+[éœäŦ2Ûº) Ÿ 2×¼ÝôÿÆ•úêK¦7ˆ%tEXtdate:create2024-01-25T21:10:59+00:00 ´±$%tEXtdate:modify2024-01-25T21:10:59+00:00xé ˜tEXtexif:PixelPerUnitX08‹*µtEXtexif:PixelPerUnitY09I@‚tEXtexif:PixelUnit1e–ÿÉWzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚bidict-0.24.1/docs/_static/android-chrome-512x512.png000066400000000000000000003633431524342314000217520ustar00rootroot00000000000000‰PNG  IHDR{C­ cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYsÃÃÇo¨dtIMEè ;w»bß.nzTXtRaw profile type app11xœ­�Gb\9–EçXE-Þ,vÜûõ¹RdÐIÊÌ®ÎJ‰Œøæ½k€”éÿ÷Ιÿýï.XLìÉžeŸþ/øUr/)¯ì?qûåï1‡à‹ÍŽŸé[ïï{7|­¶Qœ oyßžÚçL {û¹³~gWBá±Å—HKOÞúÞËX=Ò¼÷öŽìó)þ»W¸÷¯¨zI®†?êK•·½¾Ãºz?ȯûŠÛfÛúZÕÎdG§Íì÷Žg/×½dŽƒy¼»{ZáòÌ%g=€aõŒXÎéí5uu:—é&­Öß�5žÈ¤Ð¢GÃRõ¶¸”CçÍ49Ú²×æÝ‡�gÎ|�cÆ­'OËzi~¤½º›£0–ÍV£o«·9Fûé�1ÒŤы¯cµ¯¾a~}Å%›l°o_Q+{£ÛæÏÙݵQ‡Måô\g‹«OÛŽu3�˜Ê2›æÒÓÚ>í>ߌ®ÿØÊÇ+Ýó+MvÏšN­ÛžÉër¯aŽxÜäu«‚;1-šÂèºåcoáÌ9mW <^i¾xgˆ1¹Ÿß8íí®¸XËJÍmÏ[®9Î>¡&3˜_‡ïq2•Óù8‡‹‘ia â?tòé…æõ�¶ofvÔ{ÜÕ�äZëí„BXûø>b 1ÄhÉÖ•ö>�D­‘YûaXo¸å�3ɳšwt§�<¾ègiÝ¢Ë�F`¹§;nåã3óÌ´œSÚeOþ+ýotÒÄúqXë(kÛØ³grºe¤r§ÏΞ±bu+Ñ�U]Z ·W¥°ç0ä]y�òe¼¾½ñó }Ï@A ´ÑÇ\Í}m.7O@µ^lg•=NfØÇZÉ1ä±T%`øú…æû7ž� “s|£G+¯ÆÔ–V¬ß³�X«]³„Lä.™^NÒ« ]`ÜžÛÅìËFJ #²§�9wŽôõË޶Gí¶KÇœM‹Ì±�&Îå{Êq?¿Ð|*ðìé�…Vù§Ùãz:¡×±{êÌ]6ÎÚCO³žÍW€Óígu¼r0­¨?v1½"ãë €·Hú]êNѵµ{‰Ã<1¬Ö{-yÔ™3Nœbz׿¦}}Ò¼³_ÂÆè��ÿ›h:ì¿aóÆ\<ù#gýŸ˜ÇÔï>qdöÓC«ë1ç÷?ƒmÞx šf�‘È¿"@øH.‘túUÔb~â£ç;Ó7ž×o„�GðÀñÕúø \‡ˆ ùùoDCŠúsèüC tBê$gÔüÝÖëj©¹Í÷ÑE2 Þ6ˆáï{héû6Mzž·K<èy¦�RÝŒ‹_krÏk|5ê¸òê†)¿÷<&¥sgü˜ÇÓK|ÿôÏçg I†�8÷LÂ+Tß/5ïßêí×o%šqö.®“½ßÌ/³�zž‹~PüýªréuúW"´zðéSÀ˜1}=KMëŸL½fÞüS¯×˜ïuôãÏ"ø½þ ´ŠoÉÍÊ£¼]c3ð›±r{EºÚ€ÖyFˆ{�Ùà6¾BCl­³GßJ›ýu¼Ì§ {¯þ7ãeþκ|?^æý€ýáx=ñëH™ÇPÍy±Þ&@( Ä[ÍÇ�=qû†[˜½Âíí¾,玵gưÑw)_¿æÇúh¡ê“… â ÌWYÿò¸Ñë+·,uinw:>®;3–%£,±m»W”ýLaVÄx“&´°üj8Ê™ênv;”ªYŠu ñ ­ù5škªP^ÖVKé§ŒPÎ&g1#ŽcGê8ã6R»úÙ@uX€¯9 n8¡Ì°™Wï ÿs\�¼àÕˆw·î<ór~¶ÊÈØÈ˹«vU ‘RÅ¥x$Ý1gŒY00·jñ7LP°#°;ô;Ó$õâÔQ=tßï£�²ŒE«ŠãëÞœ²f+ÃãáãŒÐÀ '«ài¶­9dD/‰: Z iÚÌ¡K8ŽÚÀ … ì|9;†�°œS"° †$a’ãŠe�Gkä‚¡¶Sè ˆ¹yFÑ"Ââ›èd¤ßnµ4#*ä4¯q Æ´rt^…žL…~v¨@q_ÇÓ 8ßžƒéê>b…ÌËOBî0vW;[ƒ ¢u£’sÊ­Äpáô»Í3¥86@&þ°æuaPÇ©¾š¶k©µaÃüðôl9kB1nœ9«ñE`µÏÝV™É¹Ñ�[ç`Vp� ?ÖùP1“‘ÉŽÇ­¼‰oòi1-„Ñqô?üøªCÚ¦‚zIF¡n¿ Ã@ßt‰ðsûHR·@Ž!‘N웾ÛBoL!,}§Wq»>á(bZ8ZØÞdF‰<ȽA+Ù’8^à�—x‡±<2ÿ4Œ_äŠ&Ô½`ª�¶(‘<¾L¤Ÿ´;±;|SH~à8)ój¥þܽ. !VL«°B†ò —Ûø±%hqþLò@,ù ph±Qì(,B~Pð|AŸ|ùÛ÷N΢ðrešÎBÈmdÍ]°ZÚT.sFu%�è~¸ _NŽ´µZ¤È®9�7»c¾÷;çäÌG¯óŽg_ÌÌ/®ýdt~qnÓ>ˆ7½ð¨þño&¯´¯L]tjÍ¿~o>˜¼õ'&ï«N›¿3yßwÜüÜóï;^â3›ï-0#ZP T²m§—tðAHƒ."~tÙÍĬ��öG�‚‚@P;‰H>¥ñaa<Óª2Š7¨4N=�ÓÖŠXT�Tu`fÎ.#†qqu2X�—# ÝáK ;�jV»êÅD3ãëð�Zu‰n¬˜`fo *e °sv4ZÀ—µÈN†*jyQζñöÆ÷%‡ßÁü¹Bæy@‹ÎRÁE«– ÜF4/­¢Wœ®— ¦p ® ‘2è‚…sm00 šðŒ&qYJ¶­sOu“rá¡´¡2y+®Ç*àiA…*;´äFQ…†ˆÉTŠ�àý. J€9�o‰éÁ˜m\Å'˜÷ÁÀhì-:I[ñkó‰Ðd%‚«¦ã,KXƒ¹la8Ú‡8/²Ùaã6a9 !qpøØ$æ&ÆÓ0r®"–hËÄTßfÆ�3"d]ƒeg\Æîk=˜6,a ‚øØk9-âÒ œïÄí ³SüB£®ŠŒÅ 3t8jr²1àäqÄd�+¤»WqwòQ+Ãè5W›iå abq‰v‘ƒæ#a®Aéd“±ém-UW10£i³{”㇧EˆTäܪ#É£B j^€ÙVæÀª O`÷�ýÄåâ L„AÄ#{7á1³PôM8Ãa€CèWx…ãµ·�œ9¤�¬‡|¶ÒÝB…Ÿ¯…Ø—f£™¦iW 2BZ¶®ÕV°ß{E…"Jd8>¯„_U¶e� F^Þ2P�^«ÌÇ0‹áœÑqp§Ã¨ö2KVTt´[Ì^³3añhéåXØýþÓþêð̵x–0­+ÅY6ìØý <ƒ„tZ§é·ûKÚ‚þol�ùs÷“·3cî~ðvî± õfîÊÓ¯ým]»æî7×üíÑwƒ`þ|~óyþÆî½¹=óf÷@AYÜÉQEmdjÃÿâÊ`uË ùF£�‹´Ó ‚© [¬m$ �.ÒÇX$DùÑb!’Ý-õ-Ã$-Ô…þ`|äv�àrĸÌ"(Áèy„1ô"Ç�(ÚPâ9AɲH§ƒ`OuoU.UDõé ­Ò;èŠö5‰”`ÝLf!âñøÍt> j]ªZ¸Sñ)°Ÿ‘€8[Qo�9¸õŒÍ,çÚî0Z%ƒÚè:¡ÕDô¯‰@I=ó'Pq“ë9ìpá. ä ž´’m©ÖÝ»p%ж´­Ô«C¡Úº'³† = ^3ü¨ÛBŸüPÑŽL˜ D¨€FƒÐwf®«Ø °yåÉ@“ ¢ßÉ•sâ­E^€iýèMR×R} g¯>D²×¸_¿5J€{–ÖšáFÕ·d°»1 {dm¸ðø˜Ìoǃ¬Jhˆö‡€kZ4A4�k>ǘɧÄ)Ÿe:ʘ� ¯E[; ìqÖ&ÔH%,oDƒ÷+µ‰ýÊG}w~Ã>SÐ�óM8aÍ öô>‡š´ÉòZ‘ÍÐqirºr0²¯H×+F±®[¾©@dÔ^XæҭÑ&©­ý0gÛí`Ë�dˆ¶o‰t¨˜¤žò]2UµZûvˆrdX¸ØtèˆFáZ®è(¦®Qð)½"oGH‰vª¬d§ÒœÚ<+£˜�ÍŒ t€!±*Z È/ ÚZS£R>Âi5B%#¦Q±tÚ¨0-Š ÿЗªwÃX.8íšÆ¢=‚~Æ!¿T�ü´—–U ˜>o†½¹<ó°yöüÖ%}±]öÞ!Y¤ïÒùH÷µÏNð£ü³m;±G,|®Y©øú¬Ê“Ž€þìzúB0vWÒÏB�hì«C¨mÙîØi…�ìé Æ†Br¯ O“Ú*êê%…Í#]fY 5æ�·%Lª�ÕÞ<éëœAì¢ B•N/‘=ƒ…¼h*eÝ¡/XÔîmÁáWbº*1ÉÐY}nÉôv c,¯Tg'€‚�4^…Ð0Ûž´ñ{A¼iÝ€¬l‚]«�•&YTD@dóP9³-]ƒà,9k1l5d°ìV Ó¬K´s£Nµµœ¥ÍÐ�5j©Då�S#=jMŒ¥ª_éǸµñnÒQT&-kE\›AD®%ùQY¶r™ØÃe»Ž¨#´‡.\Õ^FŠÚD÷ˆuFdÖŠvŸ™•ü¢¸á¸Wº å)ˆ�šs>7è×I '@@¤‘”/v€`[Eã¥ð…ÀWsëMÕÍŸÆ÷'ÓU7�>J Ï^å PÅ5\I5¹@l.¤ð&)ú"&Á“Ya®Èyæ³;ˆeb 3F.Gú ù´ áÁ¿yj·z#Xñeg,D MBpÕÐ ¼¦þB³Ø@_•’1€´Ý1!˜‰Üp0;^Œš't[VÅéa:˜—4'*ȵ³ê-cŲ„�Ä>pd– nJ·.Œ Ù !9" �õ*F™……á器Šñ«ªØ·«Þ¡ î�ÁD½à©˜n!ÙJLíV„RÞjÌK“Cœ·ìÁˆ¸}rª_€9œ‡öøL‹ÞC°®ÓÙB<@+¡ZrZ!ç´‘†Äf4Q!øÒbPð:Æ6DæG ™¾XðÈX‘û§¤š£që�U‹¬’8U#3l`ñ-3üÁûSÕ“àõ ’ »¿uíñ)—îw�¢ªW0àÊÚ×g°²ÎžÄû�«èK½å Ï�l·6pÁ|Çš_̶îý£ø8h£U™[¼lzˆt¨ y݆ÄɥDŽÎH øBëq›xP0­ÞLÌa2*ŒUÃZ-8ùܵêä ,Oë´ÃK’¡|¢ÄºÒž×"ëÛ2wëÊÜ-®¾ÿŽW°/5yS QÚëÏbÖ¦ûѪ/N)#5pƒél ÂåϤ`^Xa<W…°?Ö¥÷>�¾Ým‘ÜTq �VZƒÝ Ÿ¬Á�yï�Pa/_ùõ šÍ¿Ó­MNæV…—_MÁ“†J×ÞP�/•¤úÒÝ¢e·¤yi#ò¥®ýn™_¶I…z Îx}ÑË^\Sà§�p÷“ªH×ëc0Ìß�Æ×ƒa®äxr‹ÊûÏ£ñèXùÕ±_6èa—½ù{ôfƒäš#™ïˆnü ´ñN)à›Ót FßEJÓ–S+ˆŽd^›YÛÞ‘BI:ƒÇ_*VÈb·¾¡T_ ˜¬€NŸÚþø¡U´ˆ8N;c]g�xèÁOa%‰£ÍXÑ@@Õ�áfJƒA»,„;~ž9lé:È©Wma÷3ËQ D‹=’*hƒ¦„|Ø];ó˜>H÷@)»«œ±Ž6ÉödViÃ(K˜£!M‡÷žÈ¦' ¢whpÂHÕ Óx:Y‹¬ŠÚ.³“>E«Zô]KÏ:6‰§Å¸}Üö/Û^å'?$~+û2O~è¥ìËå/ê'¿ëŸvI‚ü ®åQèý°5‚X+¾G–TY÷òøñ­¿nR™�»T˜b W^‘!AÆÃÁàL×)j'ñ—“'}tpæaáÐì¨wvÙ]>µwO ‘c(R…é'xÄ+OÕŠAîhÉ1ÝF,0ÂÓvÏËþQÐä>Èàu7çm»ç�&ÌãWï9Së`ú]¾'˯©ÒHƼ/R${í×;X*ðÔï5é>~üŒ ÷´ÿÿÜ-u,èÌãwÝblêû‡™·-1ðåÃéƯ=®ßŒ”yϨÿf¤Ì«ªøPïø5÷Žgo�„ï <ì¶730¨®ŒY,~é@§òqS R8o™8ù$Äë17³N¯c«] X²´Þ0È ¿V}íhüsËp‘ïK®{F“€xDê Kņ„ÚÐâ{Z¿‡fj¼,:XÓ;ÆR'»’ `¦j©BK º©|0ƒATh[:øÃ”Ò*ÊòÎUõ!ˆYt0ÝÊÇׂÝIyàMhލ)'ŸU€8U¡jð‹IfDäÊ{©Û”DÇ'êô`B6HOEm� €*‹µJ²U?É0&-_by@ÿ:¦«üqªlȵ¡šú|¼ªÊp¥{�Ç>ëþ¯h·DÃWáhx:éà"Æ’! bK–YCsLo˜q2þrPÉ׊î Ìýž“ 10æxÍ�^p".™³ Nyg&^6ª.�ÌÉVI…ªM9Dú>À=mô˜æƒX, é}Ú°0‘¢ïâ§Á Â?ÈÖÞå qÿÅ“ XÅ¢JE&S- ùüÞ–ªîJêLj½ Pwt>™ úÕ…˜¾kAàÓ¬N÷»…£²}U½hÕGë“è=|ˆuNgÜÑA’�ãŒÎK—&—‚oÇöN†¨±€h-¢mãqyDY¨�¤R€ºræ½@�.áOu愆„‰V¸þ,gNm]N»êž ¯%Z­ û©sV‚u*µ�#x�e´#‘0Éc`†à‰¬'u@Dû‘ ºˆ*´Œïá›Z,Bm*ì�Õhëdôä²@j3Z ¡ƒi Ò'quœžg9ü ,‰´¤[ëh jeÇ1ˬ©ŒDæ­?ÊJà€ÞíœÅ ¯H£Xˆßj�=ü}ã«wó?z7Õ⇧2F;?{�‡Yáã—}}|àT쯪„'è5ïàÜùwübpêÏv/Ç×MS^Œß‡ ¯ðâà>;·òò[ÿìÜÌ¿ñ±ï�›ù7>ö½�5ÿÆÇ¾ß÷újúkø š ˜";ÒhNB¬™D6Ï‚2 3/ÀBÙí/ÀX^òM{9f'À¦êáÚ“¡4§û9"¼¥ŠvsxÕË:¡Mðo”£R…¶á„àNRÐÁ”—êÌzE殳´¯]£àð0à (¬ ëÞÃm7‚²ÂY”rúp0FØà#¤Qñ?Ȫu´Ln`Æ/>”T”­0]µ$A¢�³ZSÍG&ÝÀ>åyÅßâ?zÒA.@Q±_oÌ®5f¤90Žaˆå4¾j­k$£6½Û�(pcÄ{Ï·#Ã1÷!!ˆÀàsuÂŽi“p6d‹+@3fŒGÕ)‚¢{ ðåá4 ëä`†¨`ØV©@" ¶ÏÐ6˜ {%°VG{#ñ{0ï­˜c@Âe’“ÎÂajT$ŠÆ�7® Z5¨<ÀI*þTÁu—šEÕÿ'·Mè�4Ð"nm&ƒ¦âTmÝBF°Þ˜ãîKÀm0܉¾5bIæWE4C+`Um1àê”åt+ 8· Æ®£oÊ‘\M;º>`&«3ëæ¶åîÃÔÁâ5µýZŽÓÎ-ÀHpâsiâÄJêDí£–dˆ¦u/l6pÜð©¸#ýÄ$÷ÃßðÃ[”ÖLªÏo:«+M ‹‰Å[0h²`ƒ ?§åE^1£„CPÃÖ…Uû…5ÒÆee§UYÕMÌãW»aÔ˜bŸe2UÛÚEÛ Xµu»ˆÎ”2š÷Û\a±>•š‡KÛ^�ëö…v!ÖawØ…Ûe "ûvÌE<ß[Só«"3¼³Ÿ?Om}}6ëÖì}åxþÆð˜gÇÝ×½Bú�á1¿÷†_ž×’ŠKF×Á ×ÞûÔÀø�ý„3ê÷*`ZägSÍ¿o‹|§·¿ŠOÿ¹óX2ó;O¦{œ��VUã S�ÕreÃO;æh˜dåß:YæQéäÜÃu0pIûËž,²°!Z™ëHðv`iSBŒ;ÛYW5vh?�…ÿ¿d¢¬ügp�7 ¨ñàlԢꢳµÒ ‡åмׇ‘´è€4Iw‚M®s=b�¹R®ÒÏÒ×PK Z˜ÒrïÜÉà‚Ÿ º5[±ÓYuêМfä:tTU‡â¡MCÕ×x†N  J¯�õƒ¥‚|Ú±¤ìھ˗0ÐÚ…&/î@%™Œ-ó 2sító“ïºê”rºK¢CFÛÄªŠ‰I˲jëvËcŽ£M:$K?*Ò`xuñ›[Àºƒ¾0¼QÞbêXºÆèTY×êeÓMÚB…9-ÆÜwâPS“ Q”ÂBk4�n€�[éK °IE.¾/uTÚ‚‰$H1ZšËÑÂèܨR�âTؾ &ø¿¢Úìeˆ˜Ykì�Ù1è<ݰ*éá¡a] 4û"š´“Že·ºA)¼sT�ÈÌÐé¨yyQÍ mµëqª,Bh :½��¬¶�«ºbdEÌp2¤÷da ($œ°Æ;53{±R:ƒð'mÑ�a÷D“NG0¾N'Ü–NÖ+óæm€ òÄQî§/ô£Š݈HXÑvšÃ¼hýy@Þè ¬…·ÌˆÄ™ì¨½qƒ$]I» mYÕôêþ£±ñV]rHEtžy7ÚpÀÁ coí9rÛàÚŽ×ÑCEÝØ†BÄL¡R¥LP÷Œãwç²Ã‘'ãÃI¾ó8>�H|X2\òsõ¡ÝMå(û6tiío ݧEÜ>Ú#ú¹úPwûü…'ûÉ’™¿ñdO–Lw¢øç+0Æo¹· ¼\tßãÇšÄgcf^6)¿rfîþGvçÞÚW&Õü³ù< æGä·&Õ|ïRßLêŸÔ#šŸ|Ù8ª×½8â¡×ÅÃz(öœ °µ'¼&·ƒ˜F[µ 3ù¦*ë$u�Èš‹@Z±ø¥pK‘€Ý¨»ÔPƒyêÀ&0Ò‡?á'J|yÞ �ŠÜmLމ¶K˜¡­}"Ù —SÓ2ÞOõ$vz]º€Înºæ5€œv%ºÆ£ñµ{bK�wÉtàf�%•I: Êó4ú¾Ð$Òu¦mP}<™oºìšîÒqžœôËẎ3ÏF®ª†C�Årø›¼w):¶ÝUé^TLfRL$«Z8  ƒ„¯ø €‡"Ö©$”[ÀœT¾6E°üõ ¬Vx|há°@Þ–6ƒ®y8H&‹Æ!ªn½ˆæ¨%¦²pºi« A×jQö~³†‚$ÛЧ+ÞP™øì’d[‚7кB W}—õ Þñ×ÈLçÞº5¹¬Åû _U¡·Ê;]ªKêá̈ÝÓ)ȱUØ\K°A;Œ˜ ½×&)Nƒ«êü±Täò‡ a[œjÒö-G‘›ÖñG�©ÜnSƒVÌkct:óŒT(Û ¡°ÆËkɤ­¬„Å£ÃÀ»–ãfKSeˆ2ÇÄŒ¶™(–¨�ˆä)Ûл.ßÔ.œíAÙ¬KNn¥†Yå-•ù`È/Ö=PX|UF¸H"pæÜáE(¸}5¯ PÓj‡NŠíÑçÐM„Ä £èC$ê�Nk8ݤœÝ¨�‰˜!Φ;‘Iå:›÷$”h€<ƒhœ*ª*¢czìJJGžë(»ˆ^ƨžE�¹ ±ˆYuS0¥W­UëRªëü´ë…ºhùGu‡ŸÝ”ùÎN}w¸+&lìçÄæç ÊÝ=8L/ 'dÒÇþàÈ^ Ù×§£ÌÛñ¨ÿÖf…olVùÏlÖ3eŠ0Ù›»Yd^w‹bz²Zõ‡Ýê/v‹VÅŸ¬–ùoÚó¸Eo~w’ðoêG¼æ®¡²:zu°S Zu’¯Cšn™]Ê‹ÒTÙ¿VÅ;©¡‹1t�oÚ½hx@-‡Ð'}!­+ê*¦¡«PãÑÒ)áÆ¸�ÿ:¶JĂ֣áwÜ)(W´™Ñ�k°X€�ÓXÓq)Ù§ÓøBé: –VÞäk IKIX…¼Ûƒ¡ô]7錈òm‰A4NÏ ÑÕ*£nyJ*§Ëžÿ°—·&#„BG»W-NE$ÜU•N·t¡owرQ\)¬­Zv5B €¤;±U3Õ•% ÝÏ"¯[u¦†i©Ês…”uZC]ÕÝ Zu$Ši›áq­ÑA¶>µ[F:&ã‹}±x¤6aé²ïIX¼CPÄ:¡DÙÚ›‘×1L4öJ: ¬ò]*­Äò:Ó…eàhÚ^ûW�tªƒ„vî9žò�8º�¬ü´oþY!ÕçÕxó7Ëñ?­Æ›Ÿ—ãÿ¼ÊÎ|WYØm}Àxÿ"¿Ú­‚\ïKÍs�ãËQ�Ï_L*Ÿ|wùܧ2B#~ñ«òIo'S!tàS‡ä|øŽLð|žP˜¹{¯U–u^ MUbóèóe» ¯«¹6§µœ4öU�“�~7¸ g«{Yº´O®¨?¯:+TœWY™Ÿ€ºÄ±|ÝzüºS—ûXŸÅ$×óD-òbö`˜½x–Ÿ , ©�p˜5ë2¯[Ç2mF>›~�³ÀÄÒgÕ¬³‹WÌ[Œx€X^Ä Â­5¦¿èö5L´emE’ŽåIÑåÞU¯­.t_ûª*™B-xŒ4Êb©N�é×-Å…‚ÕQ�1†nç ¸aˆÀëxD îÈj7æ,Hùn4Ï�«­ Ý×sEO"3u n©LQ÷àɉĦãp�U™|7¼Ù¯f¾Òèí¦G�Ahhø±t€‚,ô:¹¬"Iqž©PB’O^^‡ÕEJ©i´F–Ich\ÀÁdxCKšD"�Ò •£¹­Um^O¸ÁëpUYŒlÑÞfŠÒW÷Ô‰ö\v':*^¯0NgÒ@'ËZ- ßÖY�ƒ!! ´Â¬áöŽ{ÜÊpPö*þÇÉÔe'Rˆ“êÛlµºþ$‰²Ï™A|ë¡�:xX$3åT¨Õ7¬é ]¡41¸N×FèÖÖýü˶¤ó¸ªæÒ½�žlÏNW#ƒwƵñ(ö­œ `q™S]î”TÖ /ò«¾DGf´QÌ$íþl)’šÕµCÅ=a H꺞ڑÌ;3C/c>:ÁM'TºWÔå&ë Déºí} ÖG¹Û¾ùVµ«Æpâ</|%,Ô™{¼™nawMÛc:ݸÜÿ ½Y8È£}¥/¢/TU±:ý¯2x¨�Rt©šŠ ‘º"‚§cb[•»Í*%�#š%¼4cpï2!¤sÄ“âÌlT`Ãl³–]÷άºUGˆzF0e]� ‘Z胢?cÒ#ÝÅ�7¯k´M_Ö¨S$}ìM(Ne ï�¿ZvÓºÓ=ÞŽÙÏYA!Æ'h�®ê6±Þïu(8sžË�*NŠrZ•»M·¼á—±ònâU·ŸAž÷øÁ Ó±7Ž$ÈÉËÿëØ¿Š§òè–@\Q …c�ȤƒN×M]ZàµÑÞudZwv3UÕËQ)Zš#2'²-Õ°­Áê¼`ë»¶]�•Úu 5#´á0�nN Û€8Ä¡#vªq± $ú.¨÷úžVc†‚îsSޏkè~€5·»'g”è1{àªk½¢Ç{¹®-[„%MÖAMˆBARêâš®#3¬¨ ­³WŽþޏº&ëÞD§öf`$: T—Í«�ènþ€kÁþ›å¢Ð_zTXtRaw profile type exif™ãJ­ÈLãRS3.Ss 3K33 0I1I100J4€ 6654± ¡b†0PÄ2�‰sA #d 4À”C�÷€IDATxÚìýwœ%Éuˆ~߉Ì{o¹öÝ3=¶Ç`à=@C€A‘ (R4dHŠ+‰Z‰¢(­V¢ÌÓ{z?R¿•áîJ¢É•è- H€ÀÀ3ÀÀ 0ÞwÏ´ï2×eÆ9ï�H{ëfuUwUwõt~“¿šÛyófFDFœsâXbî�@ ‰ ¦ÁÌТE‹IhÃy¹Ø kñ‚ÄÙç[…žOA äàÀÕ¯õË-Z´hñ@$}Š_îÙJú-Z´hñD¡È‰ ÔŸ •ÀêÜ E‹-Z¼@@2SªŸ å>ó]ÁÄWkë•Z´¸\Á žoÑâ|pîó-Pÿð7šnL`;o[´hÑâ…‰rú©´Þ -Z´hñÂFÔêú[´hÑâ²Bi6pµf¿î´½ÿyÅT{±l Míom-Ö5?eúõRQ±rykÃ;lJÃü´é÷1óå³Ö3…mºÿ¸i¥ýÛamnçõØÔÎói?§ûû7Ûbæ‰VÞiÞ’Qøp‘Uþ•άÇȼQf³®{^Ìþ·ØÞØð¢åÔŸ¬\h[=áˆâY5‚Þ°v×È$¸Mm¸dÖfÛÎí�.v2�´‹Ê…¦6  {nÖóúçC¾þ'6ÒaŽ™Ù–Ït‚F;úÝä%x!Q¬Íí¿§’‘íÜþmÁÂ$cåóÚØ’À´EYØÊ[\Î(æÏ:çC5¥J]æIlù´ªøq¯cP]‚Ó¯¹k¡q�¯Ím¾›èØvnDÙoŸõl3khЋ�Ïo›®9ŸAoÔ‡Ö/ÚXÛšú²YØŠçnÖ=›Æê|ú¸YÏ]�*rz^kºþ"a=q÷bÙÖµH68>›Õ—-Ñ�ž‡Ž~£}Ä:tåõû\|p>Øj]öù–^4›Á×xS›××γúsp+qç¬÷_§^rÓí ë´lè¹›ÛÈ Ýj�sw³ú²†ntÃÝœ6æ›xýYúh†iJœ|�üvÖe_àvnÊ»>Û¤·>!ÛEc5¥ãyÜdí­Ð¦¯È³Ú ÎÁž±™,jÕsÏg«ØtÏsë輄 wsÚ˜Ÿÿõ딪²Ëšïy©x€¬[­Ë>IöbÙ ßõf©°²+¸Ø¦�[õ'‘Á3/°y/u=M8wºwþDms±Q=ÝV£F˜ýÇ76V›Õ—M›cµ~�ÕÞSstnjÃù0‰æ~M·±‰”zØõ ÜʼnÌßê9|>÷ßëë|®_×:Ýè=µaÞ®úíÅWµhq¡°ij¶m®ýh±Í‘éq‘½ªé [´hѢŅÂv’!ZТÅÐîZœ¶GZ‹šP¡zÁ»1\BØnvŽKÍã³1£Ùfé¦Û÷µ66+Fg³î¹åhj³Ú^ÿSû¾1Òô§^$ËR‹-Z´¨àB3­ÀjZТE‹ÛvÙ@xRËZ´hÑ⢃¸eYmտ“6nÞZ#Ùý×e‚mð¾ÖÕÌ�Ú<6دí6U´)¯Ô:Ú¿.Ý÷:HÉFíÛm ·C{6/øK˜§ð^!³à἞&ZÜ•EÞ'ÓKƒ:´hÑ¢ aaojØb3°^®|Î9,ÿ=Z7Ð-.iXSÏ/tlJRñ–´hq)c{ø•·¸ðØ”=ß%ɪ5-/d®’íàÓ½ÝÚs±ú^ņr £ˆÅ¿àmÞ¬ÔǶID£m;Ïd›~Ÿí†³§¤]cî™ÙFZyÙùMæÖÐârÁåÆ/[l¬“Ë]xfØ2€-Z´ØZ¬·¢ÆoXËZ\.x!iZ\ZذbçBá’´TÑ”~=¨ 7Yá…ç“/þ|®¿°Y¹ÔÏý·ïEœÁ“³è‘7©m[=W7+ÏÕæ`97lŒ¬qq¥Êá…´iµ;€€V6l±ÝÑÎÑUl Ÿn@‹—Ú-d‹MGËZ´¸4ÐÚ0Zl:.yÀù ¶‡Ú‚ŵåºTU�ÛߺpÖëîÏ-¥ ¸Ômçsÿ­ˆKØD{ÀÔQ¿8¯µÝ´hÑ¢ÅeŠ–´hѢť‡MÙz´ à’G«0iÑâ2Ä9댪?ŒêyÕ·»6y šòÂS7vý¥ˆ ú¯ïžÓÇÍ´¼ÿ¦ÕbmȲQ]íÅb�Û­&ífé¸_H"E“]á|ÆŠ•uw±úV Ésl�e7yQà ç™�þ…ClZ´¸d�-»ËÚ ¨ÅùãüóÑ_‚»Î-.u0¬Ú–´8?´ùè[´¸dÑ2€‹Œ û/WjÉR¶VƒWo[qßb¢©äŽßÎm»q>1åÏëyrÎË�ßêŒm\G6Š�Ö”nB”õmë©I‹ÍA+e·hq6lQ©¨ít¹Q´;€K …Ýÿ…6[´hqÁÑJý—x¨ÿ>°Už´hq±Ð¼¸Ôýè/`;·"ÉEÛlVÆ­Ö‚­hÎÆs —Í<�Üú›År¶ëÚníiÂFkiœ›Þœä:õ¥ëZ�/P ù ³W-Z´hÑâ¬h@‹-Z\¦h@‹-Z\¦h½€6€&ýãzôË[Q w;Ô;½�hóÛ´8ûÙùÄlVí�ó¹ÃVÌávТE‹—)ZТE‹—²ÍDËZ´hÑb]x)3MÔÆmÜ`ŠK$n`+j{VóölE ‡‹5·â¹MúÙÐ’»¬±QßÿóÁ–Ô�hŠYÙ¤x© =Ï ̬5o%¶™µE‹-¬Öyiˆç—(B,âvó¥iÑ¢E‹€–l-íoy@‹-¶!^P* �æ ¹�z·õä+ßnx!ÙZ\\´6ží‰vpqÐî Z´hqÑÑ2€-Z´¸L!YvyÂΫ²w‹�¡Ýù¶hÑâ¢#4÷ ªë£ÏÿNÝή—o¢†Û-oFá|žçÊß¶Š —7.y{À%çÔ„K»õ-Z´hÑâœÑ2€-Z´¸LÑ2€-Z´¸ŒPÕ;G…+úy:&jñ5yç“›øM}Üh{.Iýf‹›„�Úÿ¶¶šþ\è¸%Ë*¦{-Z´hÑbÛ MÝ¢E‹—)2‰?c—ÊF¬E‹-Zl¢ÍÊs]°�óô‘oÂvcQÛ­=-Z´8\4eø:èíVÄL´* -Z´¸LÑ2€-Z´¸LÑ2€-Z´¸L±%õ¶BWuÉç iÑâ2Ã¥âû¿Yí¼�éÛ@‹-Z\¦h@‹-Z\¦h@‹-Z\¦ØÞ5�7)OÑf¡µC´hÑ¢ ç•»ì"Õ¸vÛ„ú·hѢŠ—hÑ¢E‹[�K€´Ê–-Z´Ø lš `KÈtCž¢ ©‹_׳Öa«ØŠv¶6‰— ¶óü¼œÛv ì.´¶Š-ª(ˆ×v¦°—9¶·P‹-.e´¤›£e›†s¨٢ŠUêß.�m‰�3€JÞê {g½Ôð&aĬK„©Ø*ê§ÛIßâ2Æe6ÿ/t]ßÍÀfÙ¶°W-mÑ¢E‹­@knÑ¢E‹Ë—Øn›¦-Z´xa༌Àu?ô-h]S½âÆ6l/V±ÕíÙnýmÑârÃ¥® ¾v-Z´hÑb+Ð2€-Z´¸LÑ2€-Z´¸LqÉ‚­'×öv¶´hÑâ…‡K�δ;€-Z´¸LÑ2€-Z´¸LÑ2€-Z´¸L±i6€í�ã‚êãšžu‰û·hÑâòÁ%cÞvh }‹-.q´ àܱzÓs©»´hÑâ²Bk8GLUy]êqá-Z´¸¬°y;€J�€¬ä1Môñ|çMº›Úßøà鼓˜~k]€M/¥À©Ý¢¶¥É·›d[Çûm±ýÑ4?7íöÙ”ž8}Ñæ-6¶/»ùܪ€.. l°'7——¿ØmnÑ¢ 4 /í¼ÝŽhÀE‡N_0Ó×ËÖT^kÑbÓ Óæn;o·²wÔ2€‹ kX0Më…0w±ÛÜ¢E¬A içívÙÙ àBæði´Ó®Ã>Qý-+ZUÏv›-¶Õù)R9mS¯1œ=§ÖvF}¸»rQAÀ`f�Í�êìi±!Ôg߆™þ“FP‹¬‡ò5.[Ñ@¦Ù´Îë¡-uß\Xå}l‹À¥’fòœê¢ÉÍc­1­E $kkºá¢Üó…ت­v“¹9�cXeYóZ~sΈʉsÖ9ôB†Uþf Áj¢kcUhÑ"bf-,µÚÏh°f¿³) €Èüƒ¦ É³ruX¡í•-ýES-\Êê=¸º1Vþ¼]gÛ™t¼z®dt‘å5än ,H-ù;¥IöŠ3a›˜~÷5Ð ÐlÔÍ:·$„”§óK3ÒHT–XõïêA)o´‰oáÒBu* `Â�wÃ/l:.¤N=Ïšêm ~î†@‘-•’ÓÈì›ÀBÓB°‚ˆ@) ši6/s-ã\ÕβUý¬Ë_F…þ†ŸVŒiå5BžWRl’F˜˜)¦¦Qx’™Äf3XøW¶ö¬h8mÒ4Ìix/—™ŸõV 6çÖ©dW}¶º³A˨g&®�NÍ“F…Šõ¹‰ 9aRÄ(šW¾w«ÏžÂLœ³ää<¿…™£Ñ -T‡ÁŒ4˜Yþ�ùB5Ñ‹ùÒ‘lý1Íï+f̾òó«Æö2‰ÈdDFe|Æ WѶ>}UÊ(g(¡ùÄ2 ΰœ$ˆÐâæI3SÂC¼W s̈pæaaÙä3eÊÜ2 ­Hg•¶M¬C–÷ä*ú\.{’ Q\$"‘y‹}X*4!LC薆߂‘ ‚—æD¿,A�& ‚�©�>$$ÒÜ@„‚jTƒWx3o–ï§î�§JÓf¨6Ö'äZÒ ÒJg B"P„Î�F‚PU2�uB"f°@ü3á,ÿ<²iœ¯£°IÆv¹£u­€@¬*™0ûLSri©`•sA¡)�˜zÕô GˆØ‰ãN·w:�^÷Š+¯¸êàsÝH’” G2'¥nÆ´X% ?!üHEÌq )œ0?ÌÔTU½��ÆKKK§O�9³¸µxüÄ©S§NŸ8~êø‰ÅÃGŽ>õô‘ã'—–G‹Ë+£D¡ŽèˆÄÈt5FAšith¹®²�Æ5 wOwÝ,€n›]�®=îb�¹PLª“ÁDfŠÔ�¦švf¢ùý½k]}û·ºõ†›n¹ášëÎí˜[˜�™w3±£fðª hL¦Õ,×w†Æ Vã^ôË“²“E·h…!"»¬üŸLö=·ü™Á !Âþ#Õt¹¿²|zå±GŸúò—¿vÿç¿ø•¯|íùçNõ�X,tdt¦aç­�i}œ§�§VVZíÝmÒ|h ÂZYFÁ"XD ¦©™WIo†×]·ÿå/¿õ¥/½õ®»n¹ñ¦köíš�ŸíŠƒZª:½AaÊ©:Ê œ¿(œÂP¤Z…Ѻ`$t„#àHg†±OÇc¿¼2\ì��9ñàÃO<ôÈã_à¡GŸ8|òÄâ™3ƒ4u`�ì1M iaóhÐ| 6è{w©Û*ô<ÏÌvˆ-ÈÎ×u—¤š hޤ�J‡»æºæE/¾ýEwÝüâß|õuçw.D±Œ #ÕTS¯š˜XæBÍmez– ¦ª­ñœ>5˜òæ�©²ëK™@ôÔKÐøÒœH¸Ð™ÍÒ:ÂQ,NŒãþèÄÑc_üâWÿìÏïû̧î{úÉgÇ7C‹ÔCÚ°cnÀÅ„4$Þ§ê!Ò‰ð:Jý°Û¡k÷¼îõ/ÿÆ7¿æÕ¯ºãê«võzJ ÍÆÎ§´Ç«`Pª‘ÊxC4NštRÙAf-2#–[_ÂèHgˆ Žˆ¼rq¥r±ÿä“Gî½ï�{ïûÚ×xòÈ‘3‹‹cSPĤ‰Á™Æ  ßhÀ9âRaRùLY¦ª›±Wíñ]w¼ä•/yù+^|ãMWíÞµÐéF¦–¤6† ¼&ÄH‘˜y‘! ¹*ØÃ2SB…Tewåô¹eDm‚Z¡.mìØÄ@ †Ž*­XF™ƒ‡3›UtÀ˜ì:D×¹%¦ãäégŸûÔÇÿâïûðï{pñ䊠ÄÚ¸Zp1Ñ$ŸSŒ†Úß¹·ûªWÝñÎo}ó7¼îޝ¿²Ó³!u, R@KÁ¢æMF“hªC²5·gú£'&ï”ê]¬Pê@L¨™gŒ ‘Ygy ÇOöøúcŸýì?õ©{¿þÐ3'O.z¢GtÍbXd 6d'mšæ-8Gl7z 8dú˜0 .s&S…šyF²oÿ¾—¾æ¥¯üÆ—¾âµ/»æº«çºFxó^“¡ùS��ZJIÀ„’PŒ¢ŠØòÐÞÌe4{¬L(ésÓªT=Žj6ˆú0NÝT/hð{Öj��iØ\‹� gŒ`â}ˆà{ÎÍ8î@Ò£ÄõO÷¿ðù¯üÞo¿ÿž{>{ìèiøalÊ Êà×iÀ3òSø!™ù}–šï_uí®w¼ãµßñÝo½ë¥×ïÚá"= ÓLÒ 7âà3&…×29%�›5Dn ùòs%‚ÅÌ!ï¤Á`š¹„0�±kpd/UœZ|ý±ÓŸøÔ½þ‘O~å+�ž89HÇŽ2‹hQÅ9»ì“Už•Z“ «ekc£ ž²1Ý\ÓÎÒXy…”‡_%èLD oéœÁ<¢Êt~ÏÜí/¾ù5w¿îÕoxõ ·êî襰‘ÚÈt¤Cµlèà™Ù¶òôW$7pUäÿJ›7múT'.«;èéOÐ<è'¸&›aºn¯¹]ÆYÁr¿ï—¿ük¿þ›÷|ðó‹GŽó¦(…©É˜¢jQ¾þP¸ñMï\’qÛ®þA¡a…¡U8S3§DÔ ‘“ôäWÎ~ÇwÝýýïyûKﺦ�կС‘!*$só̓=ªqWelЄÿd{&Æ yÍ”ß4z_4œ,@eåp•÷NᢪEˆc¼Fbµ]Þ:§û_ùúcùó¿øó�~æë=}æÔÈÒYçf€^`–²eòRÆ�„‰e)ß°cØœ:"[ŽË˜@ ¹Ï³©x 'ßjbˆÒƒ×_ýêo|Ý›¾ùMw¾âÎù½ó#Õ¡O†°TmlS‘TœR”ô…‹N%B–,Ý4�:¥'šWEý.(®œº¹?Ëxgò_¶Ã%+�cÕæ¯¥êYDè#ÕY³ãN`§só”deåóŸþ¯ü·_ÿôGï"çf 4¡jÜ ']G'ÛÔ2€ó‡^a1[&c“Œfœ¦ýnox÷Ý/ú‰¿ýïzõm�hh~YtŽ4Ñ,v8‹ .øAí>­»l(|Ô8m�}aÃÅÓÎOÿ�U” ×OÞÊL¼uƒ3cí=Ù¿ÿþ‡>ð�?ûÄǾôÄÏ�†æ8G΀‘e"“·Êª´|³Ñì<Ø2€µû{1€Uä™@î‘ 3� ¾¨¨Š*S׋o¸ãÆ7¾ó¾ñíw_}èZt£¾ê@“‘ú6B¤#=©„'5ýN—ôë C«Mªe-.¾šSîÓ´„DÖO3fSŒ! ÛƒÕ¼ŒXI8‘7-lÌa,ªšÎx¿×Ü~s{]4aùäé÷ÿæûåÿüµ§=Êh§·ŽA" Ô2,�µœlSËο=¹e)È«PZhLŒhÑ ­+~Ôn¾iáÇ~âÛ¿ã]¯Þ¹£ã}¿ãLÄœ…ÈBÒ,²ª”±†—o06¦$Ù¨ƒM3˜iXÓïãURœšStÁÐ�ùÄS'ÿäßøÃ÷ýéï{d¹ódÏ,ì°ÂÀd»Š@Kt:ãiÀYû{Q@аKøN 2-qš0‰f寗Üö¶ï~çßú »®Ù7¢ ¼½ ¼&" Ì(*±æ9R¬rçhê|#šž›ÒJlë…™Rv�ñfÑ�MÜÜøl¡ `}è œa6EBëÇ95õ]µyã‚q¿ó{¢xGʇï{à¿ü»çÏî cº—Ž„YçŒð„Z—([°) �SŒ@gèAú-AÇ=×ùÎï|û�ÿä÷Ü~ëÎXSÒHR( >0Ô ÿ >ÅyvˆÚ#êâîT/£4xÑp£}C ƒëÞ[ ï‹7SªFÆf“‘g/ÕαãÃ�âË¿ù[öÉO~åÌ¢7ô€8sš ]¡Ò€60ž–œ­¿ë`5š¶ÁçV©XqÔ@P Á�@ip …jJus�›_~û›¿ó¯yÛæìC-IMS“‘Ñ‹ótJ*Œ•ÙOâ¬fæzw+Þ>�ÔdM[ת`¥×’yOÉ0SòúÕq9fÁůvÀÌhˆUB/”æÍŒf„ƒ-¨îޏßE éó§~å?þòoüòïõÏŒg 0¯Ž¢4O¨@'Ô´— ¨ "«ý޹A6K‰#(j]ç̧'öíÃOÿô¿û=ßÔë�Å’‹„ñÂb™©÷‹°Ø<ÅÉg› j5«Ë8ƒ†\:M° y41ŒØš‹m"Qc“’ÆÔJl1-2RűaÞ°ãÄi|êSüÏÿù¾�~ìs‹§R¸X,ŒU�eŽ­Ñib>lP`mÀ´¶m6@ða&T¼˜ŠÂ™Ä8ô¢Ûßñžï|å[ßÔÝ·sIu`>�¦N”TˆB|ÅÛ¬x¿epJî¾9u®7É3~�HÈ©;‰ìf@éÖ?9TÕ^3׿‡T/’eà Y`ò[†Ý¾™™ù<¯‘eóÁB§FÂÈÐMÑõO¤B/€Y Ýé°ßñ8ß}à×ÿàÿúÿüâécޡ㌖¦•ðåEc›U\h»1Xp†Éœv$3Øœƒ®¿fîçþÅ_Ç·Ü¡z´;€³õ÷"1€ 093ˆšhê¼ñê·|×Û¿á]ß²pðŠ%è¢bH¤ÂNc9!õ]9¬ô+Õ°\K:™:ÍýZ½é6Ó.Yuf^ÿ–3HÉVß? pNk+4�05-cì{І¸<²�jÏünÚAçö¤ö‰?üÈù¹ÿrô飑DôJ…-�¬zdù�–œK_�{àÙ?Ó‘)Wì×÷ïþ—oyÛ‹áÏt]ä¤ã$2Ñl#uT0$G3+òáL0¬ÁŠÆ¦@!5ºb7غÐhìmv(-.©e�hò ·ŒöcQ ƒ`ÁYˆ13ÇOû�üù½¿ôK¿÷™O=Ô͸h§Y ʪæ[>v—:Øqw‘N²ž±õÒ`y—È"ç1 †à½Ešõ’Î]¹ûMé­ïxÏ·ï¾õšeØŠiH\œÐ©Ðr;A1§3¥àCöŸì\MŒor÷œ2k0€Uª˜Ê�*Ÿr1~âö™CSÂÄHĆÂ1ÛÍKTaP0 ÖìŒX8hû°Fo),Þ…©Ðžú=à•‘Û¥¸÷>ýþóŸ?ó܉X©©jžM¸jU¼  @˜›·ÍôŲ ³¤#iFQ¯ý;Çÿâ_½÷{¾ëå‘-ι…ÈL!Óx PZD‹Ü ð`ž�»ŸiÎ Â…ˆˆ(,Ÿ)LM=ÌS4˳VîS-ßœäc?UÒ_M¤+Ó¾;ëUnßt}æ=eY®8Qˆ˜sž€‚i(Œ¡)jÎ8ë1{ü¨þÏßøÈ/ýÿÞÿðÃ'LÈZÈêY0§ÓÕKŸ¼¹2ž›¤s^A[Õ뛌½bé�S!i^<,íz�Ó»ÝÛÞðòoþ«ß{ãk^2ˆ£S¦^˜yõdþ’$Ëé–ß™hœo‚³òüÑÓ[Y›·õ®7¸ÙÕ=uMÔ¢Àrã­TBw`€¥±§éwÌ æVÒñáãÇž|öø³ÇÆšt÷î¼ú†k¯¼úŠÙ¹¹62š™0OþiF¸H™í‡ªô³’¢)f"Ùc_Š{íC¿ö¿ÿ|rrÅ%3'&�¤nt8×ù³ÑH‰F“ÊÙj}N6Ô×Ýè‚?Týñ¡ ºIA'Bl–O.ìXúgÿìû¾ÿû¾…~4ÛéĈ„NÄL<Ý(×{(¥p_³€+€´cðäÐtDÆHdv0ÂÓ‡úÚñÇ>¾2LæÜ�w\wÛÍW]yåNǰ$2†t0A $h]XLWiEˆFa~ ÐzÆÙ ¹¨¦ªªŽ[Õ ºâX–Û(庂¡˜Itþ¾ûŸûÿéwß÷G÷öWzänHB�H}ƒL̬ÆzʽбՌáÉò/$l`E„P³„bS‡«n=ôÍ?ø=/ç›±wá„�ÇQ' \*‚Á3ŸìdîŒá3gèôóÕMÄÆÇ§îTö¸N�s f~ÙxhÑh½‘_~àñ¯þøØç†Ï�¯¤•^ÜÝ=åKn}é÷¼óÊo|ÅxG¯« RQH}fðJø�ºèdöÓÊ]Î~°‡<0L?üïùÿùWe 0JRœ1)ÖpËÎ 5Ÿb£QIÂ☑sçžÿ_ÿá»üo½Õ§Ë=×›‰ºŽdÐöˆŠ¤y hÍ3$ ,‡à ¬‹ cpŬo6Ÿú}ŸúÌ£¿þ[öñ�}íøsè¯Ä)ÔÅ£ù9½ñ†=ßý�wÏw¿ùêkœp1Š€ÌCÔ ­D€Ÿ\«kEXåïÎC²®ºbWÝ7+’”ÖmÈYí¦,ìM0vö‹¿ø�<<ˆ¸+"†4ˆ^¦˜Ø~œ¸H À¡{¨6  f '; Û1DA‹)½Û3óÚï|û_þ™Ÿ¼ñͯ9=㎦ÉȹԉŠË•™s€æ’¾ÂIoÙ· x˨räJ•Õ‡¯]iáƒ_}‡³™Ê6»‰•_YaÒªœô´‘°/ÖY>ù+üø?ý�‡?òùÑɬ¤�!â±`%MO¬œyäéÇ>óùþâÒ¡ë¯w ½±³”â b0 ŒR<×gúx˜·z/HO$f+ªiºå¦gyòØ£OuUxúuz1�ë›?‡»œ½=äêu¼›Õ¯u´¹ÊB/)"ž8ñö·ßõÓ?ý#ÝN?ë8‰# U˜‚â%8ÿ0Ÿ¿Ù~σ ˜È¬EHÁ¡qhäòòÜù¯ÿ™ô+÷ÜsòÔÉ}£ñ•Ww«. GÝ#‡Ÿ¸ç‹_øÂW®9tÍU׈eà�>d ͽ&=WFÃÁ©×oð&… O+È[Íg)»¦<*Ñ^Õ‡Â,2�ôà˜6îvÓ—¿ôÆ×¼öö¥•¥Ç}v4ìgŒ)8Ì2$Ö3wÖž¡[;™*‚fÖqàÀÂÜ‹€ªFšÊx÷-×}ûßûo{ï÷§÷<Ëôd„Q7NÄ©¸Pâ.£q¤!Ð*QPs½PÜóªBá³Üɽ‰pûfr¿!à¥øÀ�r3¬f‰}X#ý¹NÐù¥ñWÿ¯ßùÜÏÿŠ{nÉ™¤}ì LÕQ$rj\ýâ×Ó£'¾â[˜I„Þ²D'#ÁȆǜxd÷Wн&”LaÞ�ú—¨n¾wpÿ�|æ‹ã“KBø,ZnsfÊ&Ýå’fFh–YTdùà•öÏþÙ_»ùÆZ¿IDsâ�x0…x“i.½sÄ)0<²!F$†ÀÁp×øú·ÿö�Nž¾ÊÜõ*»¬ÓU¡9é€3ÂÕÞÓÏ>÷Ù¿øü�7ßxËõ»Ganf›Czcš—õSWFcÈ³Š®´ õS/žzezÄ̧Os»•žLc`,ƒ«îúƻ߰{ÏÂÃ>|úÔ¢0fÈEš—{ÅY< Ö7C·v2M0€ìq5Ð0ùÎï¹ 8Ÿá >Ñ ÔÈ ©FD‚ ñßò�ßû³çЛ_"Â1øåŽÆ.ñ Ùñ‘zÍ6ÌT°.ð–¤ÜS”ÌŽìJz° îB¦þù§ŸôsríK^4Ž]Ô ÆDlìh&µ]Q¾1 æóFBI¦äÐÉ0’�aïîý8½üÄ—€7a%ìø¼gÐYçÕÄÕÅ�šzm]sõ¬ÏmJ%¿EÂsï}BI¡D£È�øÛû]ßõ®×ˆ?Õ‰à`±˜“H(aÂz AàHÍÂçÈDW˜À‚'Oª>õ:÷ûðøÏýËß[\­<¨Ò±Î ;¿¼ç*·°§uÓQ20ˆš¢ã'Ï<úðÃo|íû÷Î3°€ŒX!M+yVA^ÏEØŸv„&dæà*o¨ì ¬q‡QþÓèI/æQTÑ0À|·‹W½â¦—½üÐÓO?þìÓ'4í ƒñ#¯ó”ý]O¸ÐºçùæÍ¤:Žƒf[Î6­ý«Ú–y-E™Z:ß½r×[ßûoû;C¯½ò¨OWœÇ. Ѱ̇ÁrNU–÷UJ Ôè{E/_Ù Lw[uT‰û‡¯í08M.ª¬›¼0áʑßø7ÿÉ?q"2$±ºÙø†;oþþŸü‘ïú»?üæïyç¡Ûo:uìÔ™ã'=LÌ’“O?sÍ‹nŸ»öª±Ë\áR2ÉêÜ×–…–uhhEk-pPx±HÍ ÜàÀãŸûÂàø©Ø3¤…Øì7?}~®!dT>Ÿû ~OÛ�f½�Ïz – ÅCN¿æ5Wýô?ø�ÝsãX’ˆ¨0e øôoÌwaz"ÏcO¦¹ËœGHaŽîsGÒô�û‰§#È>ï:œÝp箟ü‡?ðã÷ÞýßúMo{�pðÄã�&£±s�8ê}îh¯«oxÓ+\4 †™·q˜ÂYöœ¼\ûºÈ÷jpnƒeexóô@ù P ØWçÉÒÃpiîÔä€PB ªË‘,^ýŽ7½éUý•á£?ž¤#RC�äTµü»ñÖoÑ*gâa\€À¦µUó²s¦Œ%�ýü-W¿ó§þÖKßý®“½ø”`G©ˆ‘£XØß™YF[-§þƺØN›Ó5>–×õ=ýúæû”ôݲ)¬uEfuò"hÿYÛt‰gÿàOû£?ëŽÐIÕG¸êE7ü­Ÿû©ÛßòªtGöÍ]û¢›ïxÙKž|èñcÏ>y8�ñr?ší]ýºWôcgѼGšE=Ze·],¥¼%VHS4…Zj6‚uÆÇO?wïW;C5Á“€¬óÍŸe~ëtî�ÅÊçÍQei6²d¹Ä·e7ÒÁA7Šzg~ü'¾ýµ¯¾vÖ�#o$‚êŸÌ PÚB Äb燱ÙáÂûÞwï/ý?ŸO¹×ÓY<>xÝüÿö¯þÎÝo{ýÂŽî쬼rÇÞðŠÑhåK÷}Á¼9:¨=zä-ßôÚ½ûà\Ÿ¦Áfn!>ÒÖCô×ÞäÁ ë=òP°BꟾK¨1€ªI 04c"yy•Ę8z±l°cGüú7¼t~Gï«_y ß÷@—Eº€B·²½m¨0€K#.?¼¬Ì3»ð€�9³®*à¯zå�ßñ/ÿáõïú¦ÃΈ$%ÂHÏHá4}.¼g냥Þ&­Rsƒ7x+?L J?íÐü¶kù.=ûœäGJ¤¹°ï )²6¤ªÞLXžùó/c%2GÞz|íw¿cþö›O�Së÷½.ºdîEW½ùG¿«»0ã<æF˜Iä©{¿2<³d€ÒàÚm5ƒshv%��FÍ(mµÈ«˜�»îê»ß0så¾bzÕ§ÜÚǹOm2T­’��µEœ¹HELÄÄ™°1‰Xóœ+›îŠ„õ"y>Ù<—rPL;xö»O›ì“g :Õñõ×íùÆ7½´#c±Ä‰:ªPYÎ�‡YúҚà ?0äó11KÇc|îs��Æ4z•¡Ç™·ë›^ò²úÉhè}šxí÷æð—ð]7Þt6²4uœyê™þ§?óU²“zÍ ,d'Õ³­†úQ¨`kÇÆìÀ¶ÖÅ�âÖt9-c(AÑ›GàèSÇ4@äÔîÝÇþÖ�¿áçáÇo¹qÁü û •c«wž4ïÂ`]Eá7Ë•s=¨2ªâ¹b訙º��'¥dΛƒŽÝðÖ×½îïÿ�ø–žõ �ŠxÉÛ‰g^ +(ù,�kE!S×}Þ­òA+Ã_U�ÿµé‰¶fêˆÉû¬ó| Kå]ö[Â`ÉrÿØ#ÏÂ;ãØ`;ºs7ÝzûÉ$`ÁÇšÚ(JTÜu/¾yvߎ¥“KcgiLœ\<~ôDïª�‘À;L+ÙF ¹Á¬ɲRñ¥Ÿ5 Î|pýN”½›¯ÙùªÛŽ?þ ˜åmg=;^5–¢> $±)!½2ËÒRV²¢Ð“Cï:H:Q g–ÄFHìÝØ©�Pí'GAãÜ6¡@»æF›ñé:t�S/N�FŠŽ 3¸�DµèAyObjšâÂ¥vÊù\�]ä~ÊhP Žê_vÇ ‡öÍ÷’q‰FCATˆRPaÁZ„l¢”Ä™CCptÉò†÷O,/ñ�c ð.?Ós·¿ä¶ÓýEçAŒ„%Éî}{Ýtã׿ò¬s=3×»'žzÆü]κf4ñ„�²ìúaÓ^o³ý¨±bWÍm·å‰AŸzýä5™e7Lýà+-F^ÑT‡³Ñ©ï|çuvþåüOßwߟ‡,x:C""P‹�ãéãМؘRb‹ÝC×Å. BCÀ„iï)º)Í0ì YˆnýæoxËO¾wåÚ}Çà;Òé˜ä™Î­ØF¢ÌX£ûåK†œ¨x¬^¿†ú»-Hò½¥­º¼Ñ«y]úÎzµïüYÂÌT5J5�‹ó&«Z’XìÒÈ™3¥ù4õÞÇ>BššÓQròıƒ¸C�47Ûj¥¦ŸY5$ L·b«ØVPI%×ëxñíϽïn왵Ûjõ–§“ÜÂ{oõ˜F' 0É«ðd¿¢ ;è #ì¾a÷-7^ã"ÿðãO}j‰‹š!;K¢1´ t�¸xiï®îu×ìëvF‡Ÿ:yäð™¡v!=UR5¢˜˜Ç_»¬ýMVîH>åÑé)-PQ©ÃàÖ[ö-ôŽÆ°0gÓ<Ò*øë‡†Šî»°ZÓ�kî Hƒ.+MõÔé±!öžd$f:ÖÑx,=B%«ï:‰…�™€)Ep³Ç�Ÿ'i‹™™)Q¤Î߀}֙ɗ?í¬N½²YHÕf!=ŸrYWŠõ6½FPl9ýÆ7^÷ïÿ�ý'ÿä¿âžçœì¡sб™’Ø,'ˆ­Å¶f”‹WNÑñH"Ê®î-ï~ÇËøÝ'÷íYv„D‘fª~…æ”J½9ªV!¬dVÏèQTÁ³Æf ³GW__°œ©›ƒF‰¦Î�2=gÙNËÉ«ÂRB�ƒM XZZ|äÁ¯ßqÇ #X?Žè4öÖñròð±ñâ …‹�c5S3؈Lç ÕŠñ¶žü%{ÞDO2�z¡9îºýöή�þت……PîÙà^#S@dSj•3IHˆC5 ú1nvî/½û›¿ã¯¼ãæC{LÒÇŸ;ý«ÿñ÷?öŸÔaº� G38º3ÇßðúkþÞOþøí·ŒÜàØ‘Ñû¿ßÿë¿û‘åÌ:T’Aü'Ø)w¯yƒi›’ÜhS rv'f ÐŒ„‹ ‘Úha‡Þ|Ë^Êi‘-¢!Së°ª>2§ÀY-§þ0˜33HË­ÏÛ Ûš”é�iê̱glu%ÝÛ½ó‡¿ãE?ú½+;ú œ‹ Fz�§%ÌâÿJA¨¤õ+2ûÛ¤ ¨â} h…7Õì­ì�®àhBXÛ\u²zŸºÌôù&4¡uc™Ÿ§gltÄ Ñû>üÑk_õò™k¯w"'=ˆž|ú?Ü?¾è4K‡èz��»÷ª1! ˆ ‰Á³dJµ8D(š‡ŠlšÉ,^*±pÕñ®�鱚¢(ÄP‰kÞÐH§«ÎH‚bj�ÕFŒ%½ëî;¾ë'ßsž…ÈÒ(š½æÐþø»?väÉñW?ú)YQ*›(ÆôæöýÜÏþÄ+^|›ž&Ý�®úÙôWWFË¿ùŸQsÆN2(…ÜRKX¨ip6E aÔ«Ì šÐL­´Ñ#Õ†³=wὦ§ 芽脾»B/­º.jHˆæL9Û‰®¾r÷_ÜÿŒs³ðæ$ú³|ø%o|É�¯º£ï!EÍS>ø‡òȃ�‹E¢!ôÞÏïœët"õYU¸Œ…g6€u4§î ®PˆoXCjŸ¦*YÍ]JœUµbµ‰žíP=`"àà ƒ_ºí–}ÿïÿ×÷u:ÿóýø:m¯1ZÿÛ˜ ;w?ý þ¤)Âjo’6ë�ÍwâÁþÞ-í»oûáï^Yè%Ò‰;pP ž;¦.×)?/3?aý©º�–¿œâ|Yuè¬x dÑÂÓ<Š×pßœb¢â”ŸO^V Y±2?cîjIÎ2áá“<ÚóhJœ9uòô±ìõæ°<=yøž_ù�ûÞ÷ç²’FÞ4uœ¹õºÛÞómãÙNê"±ÇØY–¨®>ÈaîfQ ¸ L ¥E‰™Ä?óÑOŽž9NŠ Õ ¬ÈLV5‘N˜�YÑ ¹ž¦ØŒiÁC[BBG³˜jéÁ›~ßßûÞù›®>aÝŸK\ÂC¾s²7w|qðä§ïŸf&ZñÈésž0 ’å¿òý/ÿ¾o¿Qû_ãø!矉¤?»+ºá–ïûò×>EF�P‘WC[Êž‘ŽMÅ›¤&¾~˜Q2g’f„D†( Ek£Øù+¤õ‡^·w~9„¹T‚ób-”Eó�è´§„ÁdD€Á,Žw<òhÿSŸ{˜ìP9.¯œ~ì©Çö]qÅüüNŽqúðñþæýöýõÑ‹ÒÈ™9—ƽ3?üW^÷ò»vŠ !-ëSR'ÞaV¤hÚ±~KïÄR8ïû7|U]Ö•ŸOL%5äM&½Ð‰õˆþî}þµ¯½ëȳ'üÚÓ™B ‡°ð‰µum<Ö÷Å ô*k£—Ä 8_‹QÕ¬ vvýà·_ÿCßuzaÆ1Š!N–Œ RA*P’y¦{ ¤žÙçi6b·�ÆðŠNv¤á½[ýâ³k Y³)†üEêÍ:ÑµßøêÇÿä=³‚4…_NüàÇŸýòû®¿v”öWžnpt‘+§€™�™öxã7¾:Ú³Ë JˆÂ c¡Òù× Ôm¾%ÎŒf4õf2ãìXŠGš©€|n ÍǸ¢c*;VÛô”¦•J5«îÍÄŒ€I ;.Н=tý_ùÛ?zç]/yJzqtüÈi;e�TèG;÷I¯‡ñp­¼dõމh'êÜ»´rúC¶òµŽ'“NïæØ½ù®Û_ü�þ×wÿÓÿí¿?òÈ ïÒIR;¬¡;£RÆÓ2èÔr–Uõ–é ¥Ì‘®–÷ÍÏîêi„!RÀ»ɲÝBÇQœ±ÊÛËÍA›abAFN–ßöÖÿßÿããGŽœq²�ª0ŽþòÃ?ÿ³ÿæêC‡8}üØâóÇ"ß�’8è§¼-ßqëìÝo¾ÕÙ²˜Šu f≤®ƒªéæ²ó«ŸTÇçr½å¯)|0z7ž¸úê?÷sïNÓßþ£÷?�Ú û³m�mÍPøA�"íÆé|tý{¾å¶üîþÜ,%ê02˜Âÿo/Yù§å :ý+ï°"Ð\°¥I‘g S®I×߸sµÕ¿_Ó:UÂso‚û_ÿ²«ßôÊg>øq¡(5NAuý'ž[~ü0"3§´HÒXA‹ÄG~Ïm×ßô-oY¦Á¨>¨ˆmD£[mÆn0ieÌÈHƒƒÂ@±™þÒ{ÞÑ}õ�q¡3En€'"º¢®B-Zx•€’=‚YG®ò* ˉœ@L\wÇÂ-/yѾë®{<厎?FO÷v¬@0ò{Æ&gÔt[TB¨±�,Y:9>}bÏ Ž8Q«·^ç€{ç[^qðÿé¿ðäÒÒ²"Il\00¢ZZƒJ7u:Jb6¡sÌÅÆLf4ó¼)t|Ó ˜ëôi ›IFH3i.Ø_™óíÀ�Љ_0�³�·ˆ�}àôK_zç÷}ÏÝÿñ?þ®¹È¬'JA<8­�Üû¨ âH"í1!á”@lq'ý¡zçÕWÉig=dÉ×Ç™x2u®lVf�µÈꆡ¼An4®¥�O!‹0Šï9¯¾fé_þ›ï¥ý}èIÓÝE~IæË\7Îv¶ÛŽ„:N!8z‚°H)âÆ=¹êÛßrûO²g§¸(†3µÔ g¦dȘî Tú<©šÑ3,Òêö¯°Ð6%¯iš·M©æmmÚ=y÷ê÷•Ùa�7)¬Áö3 l´gîMïý¾<öØ©&@o’jGbê“Ô4“&½£wåÞ×üµ�«$hfFoÔRÇ4ñ\ÓrY³ÅÜ;øÑ€Ø5Óý¦·¿éúÔÇ4çD¦EæiÄR�r¥Í¤)|2ª¼5-j"{Ži&&I #Ê’ù§Wüg�ù/�±�e*³´(Å®e=óø1Œ“r`Ï.�*94MŽ>Tt.öI]ÅXe +&§»ñî¯~ÙK_ý’;€H‘¨x�(f]vž¦]›¿õê»ÿî_ßõÖ7œv€‹RËœOR!ê.+–CŸŠ ²òØ!öIÂèÆt*.cï8½¢ë@ûfµ¾Ú åÀcèÙ÷\ñÈ[ñè+úŠ�·¾×•ÔúÞúÞÞV¼ ½% †© Òìd?ÅŠçJŠ¥„Ë©[Jä´—£^žNùÀ²}âðÊgO'ËãØ%5›öR?ôÄÑ}È~,dÍ0kå+y`¬ø ÑÈÌÏ¿õìvýxÜ�™ï¬¤²”¤§ÕŸ&ÔÄ|bé~äÓø>ÒÒ�%¤C¤ú¡¦}KW,í‡CÓ¾¥}$+H—Ë“Iy�ù�ú�÷Ÿ‡ê‡HÆH—DžÕäQçÆ”Y%5Kl1Él°!| iÝŒ…|׊">[,$ýͶ{Ç‹_|çc�?õäSÇSΘDæ¼ÊH8¦D^z %åÊìŽ3ïyÏ«~æ|çUóÏź"æ(²åÛ™›×ÆÕý 6LÕû7«õ§?×j½â›]äC�UÌ…s¤AFä˜0÷íŒï¼ãªÏßûèñccʌь0‚2°,hq•�õ"Ù6\ ©Â7X¹�NšÐŒ�šFL"ÀQv¼öE¯þ?>¼íÐÒL·#QW)€wyDKμ­”è§Ý�e}hgÏWV¿¾:|\CÔoº×4TÛÙTkº®'1å¶ŠèhX„tw’ÞÕíè—þøûõ/~øžþé¾@ ̘:ñÂUû½õ w}×Ûgn;ô”©�;*Eé<Ä2ã]î8Xß�xjnÏ… ë„^Ìb|*i"$êرÅÜ·Û§±e"mP1Á`‚ñ¾ŽóUlEU×â½XV‘-·Ó˜y -A–àË +©œãøÈN'š žDZFÃÇ]¿{e…ºçèÿøm,=R•™W½�Ê|pÎfEwöžü™?øÞïö’‡i]s=缺qÝ}®{ƒÈ!â XÏ»Š,ê·“Ôª»g%®¥aÂZöâzs¢=p…Ýc+'踸³ã‹vyç\¦’ì†D–U¤2kjýõuƒ{�Ä¥ØíqÕãϸÿãÿø·ÿSÇOéœ8%T•ª˜_è¼øÎ+ÿê½åÛÞ~çŽÞ™8}Ú1ͤÂÜ*Š"»îz§ÿ9@²™v�gñ'[ÃÊÖÿ\›YZ¥ Bxм™]ÓH±ëzú§þþ/~¦«2§…Ðo¾Z¹^[¸éQ›V�\ ÍÑPÌf;1:f$’ÈÒT9çEçn¸êEÿøï̾ê®ÅÙØw:³êº€yQˆCÅœ[|ö ]©É×u0¥E aˆ\V˜â°\]x?ª]BLÞ¼QñSù¢(l´öaj¡âg|z0Mo�ãƒ)žùÜ}_þøçžùÚCËgNÍôz{¯½nÿ‹n»î5/w7]˜éñ4I\/5‚.0€à£œ^ Ñ2Á1›‹áÚ”FøØKb’FÖ�Æ£œXY¶îþ½Æ±„ꌦj…¶¿nL¨Î͉ š÷0“Jr¯Ò¥Q#Ôyu ƒx餌àœcËXô\:˜{ø‘£¿ô?í+*–T|hÆz€ ã¢e§ý[®8ý¯fï›^õtìOEÉB'˜z1ïèÑSë@"G‘Ô…dýÌÄ’Á¡³|É•çŠY´šÐ ŽŠµÊlol@l˜‡)‡i_Å/ôöÞ";n5ìA<´¬¾£ÑB£1�ºÆX¬ß°ZÂfˆTDÆ]]»2Ú÷÷þП|îË_zäèñ“c¤{÷ï¾ã¶Co|Ý�oxÕõWíM\zXÒ“t ³LHyòËŒ¤6õ¹›•5 VøeôŠ# kŽ­ž'„Å€†Ä«a‹LÄjÝ¡íûÕ_½÷çþÙN/îó‹fKrKÉÄ}Z�##3ïlÜQÉó/ÿûï�ûÖw,v;Ö�`Öõ+TL�±ðUùÛy;Íë¦j>OløuÕT.å9«Ô�Ÿ`,vp¥}jŒà{é`/ô ã 3³ûL¤ß�ÒÔœv»§;ñÓ£ñÓÃñiX""©šQ(â)¡¬Ž”)>:r·‰e[`B=mì\â(©ÄÇåù/.?œØî~oWc/¡B•j%…rµît‘Q´ÏvVú¼)¹­3“maJMEUHH:SŠgÚ�‰Í{~ìÄïÿáÊ>/£%cjS1¦/lÂQ)^Àxœ¼øú3ÿôοñ•Ç»i_8‚ŒžŽ´1�ùŽ2÷*‚›$p°i�Š‚�å¨Ôf.%]0ñP 6œ×d–ݹèÀK8û"ÈŒQ�Þè Ò„æ`0I§‹4åúÍ[*¹¨‰tUvxî9 ¶{e‰Ã‘¥bQGçg­-úñ—�°âllâ�å_Bɲ6Ýl\ï6`JñàL‚.ç~±ß9¦¯HãôõÎ&Àt¹‘¢1``ªšRœÔèÑ]Ìÿ»û±_üO÷�u��Gž‘ú�Ä(ÄÌ`{0€õÚ*-®SÐ23óÀÔÎ>bàªÔÙÎ ïùÖ½ï~çJw–q'2Fž¨ qô!(wç·êßZš×òК>½¢&œb×Xó¨eNï×9çP*l£Å|/}гÜùÂ`æ”qêD� i‹ê�‡G“䔸Ó"Ϙ>2?<>çm™qv©Á$$5Ë:^c%©b‘$$Û_QÕ¼Yh4>Égï,=‹ÍÛBäg ܧscèF^œ UÄÓ©8gΙˆŠ(i”P`Yfí,‚ -ƒõÁ„*NC‰Üœzšê€^Š®Og——ãû¿ròwß7ºÿ‹Î÷µR xõ¤«¾—ÂÒ¥â Ć…“'£xvÏ®}W¼ªÛqÁÜJ�È¢ÈÄ©˜º(ñ"J§.ôLTœ:ç�ÓÕGï êLTLÅB–ò/âE "Þf>"f�ÍN˜_b§G·‡ŒC�S˲UûfŸ†ªƒz™×48ðž}ÓÓb§º�•…™þŽÎ™Ùè˜èÓðÏNd GÆ”b%©eiG-p­J.þ�ír¡!¿OíeÙêû׫}•¶œZjÒJS'cÊe­õçæ7›¢SÉjJ*M €Ôngüâ»nìác?x˜UOˆÃt¥òE³lŒLiP©Ç=_À`OÖM8îEû_ÿ²[ì‡NØå\¯FQ(ÃÊÉ^‘VëúäB”6Zs­K¸¸ºe`åoN©³/«\eÕ°YIÁ³©7!Û0Ïê¬' �’|¶eœŠ(”’Ò% L–§½OýQÅIÈ2ãco‘y'YÞ¥Ê"wLœ²T �=RáT�X4?rçӧ?¿¼ôŒ£Íh‡\H¤74‹²ì‰V))`T�J­ÊM~˜Ji•L­M+G¹ÎQà]¤ˆ„Äí¡�Μî>üèøO?zæ�?˜<õ(|ŠuØljIî í©¤Ú?…Ï}úÌSOöwìÐ;{½'’Ä‘ •æ$:b±C$ˆc‡Ø! ‡ rˆ¢üŸ‘ƒ‹(òƒáp±HD«°æD}”x{öRUÚŠ“$Iú6K<ÃX@e–‘4ØMÓ)³ÆÕ+Í!¸iL+ÐEè)§'ÄN:œ, SLà$“°êþ¥ÜU¶¡d;ç‚5ê4¬ƒÎLgõ,Ш¬ì:}9¢ª!0˜"Æ¥tº äpf6ºåæÛ>ÿ_þ¹¾‹çÔR6ÑÉíl&‹<0VÛ’˜UÀÆB©ªí™ˆ1GŒcvn¼òeÿûßë^2èF±Hl…^ Næ{Åðk(?O×T5¾Ç ˜pŠm\ÃõM7ª“몞ê0WˆJ“5{)TD^,+)cYª©³�0.¤t JÒ„€03‡R²®�´PÍqÚ{Q:ƒ�j„½RDtˆå‡’Ã__/;ÃŒF"�tÿ~t:ý�‹L\�-”�13"‘,c˜!¯*^LesYêjÀX…åÂÌõÖ†HÕÌÔÔ4E2ò+ýÑ©SãgŸM~Ð?þ$ŽŸÀ¸¯’R©Ð5²7M�‡‚È 5Jâ�Æ+ô3�QgÖŸÚ¿pæÎ;øú×wn¿mpíAÎÏZ'¦D*‡÷})yVãºð9‰dYK*ÿ]ÕDGQêw:‹»<6Ççœ_‘Jd½½Ý�×¹7Cö›Í)@¤o5O§Ê¼ª¨¡*kYÊ¥‰!l$¬’["d6%è’&)†!s@šX´æ•±pà `=hÅ}ˆ5(ýÔsy b•†ÒAìqÆ+ÿ÷žý©ŸúÍã§vxœWòÁÚ* M`ÙÏ�dÊÃL J³Žš:¤1ÓݽÛò‡¼ç]‹�ŽD‘¹�ÈÀ Yfé¿|¨ëSÄÜwzz_l#  ¢ihÙ‰ìƒT\î&&P•ºWçt©û–†Ë%Ä[!“W²9dYÚµloo�ì�çªYzNmĂۛd®‘LàŊ𪻤±X31ÅÊ’?üЙ¥G:wœš‰Jd<ý\çñ/ŋϙšYP(™W¨AÕÔÔ{Ë÷P¥eX¥‹Ïühòì§%È8S5ïS'Žt0Ô•¾ V ZJ¤¤7ª†%£YÓüœÆh¤F¾#–$.MÙƒÄâ-òÎÛ8Óáé]3鎞ÍÍZ¯›º8ed $ÌÊ̪; næ†Îümˆ¯†ÌYVÕvb²æBQuWšQ.¦P«…ZÆ�½Ã�þ:%*¶f“ðSúKX^9k}˜²ð2Zce¥J¡·•w£á»)'­P¿ÖIEƒiÀhi} ‡–zĘÔåÁÿú_}â?ÿçϧØoÁi¥œÈ9ã½€  P›ÚÆê„ «G%O�·ˆ¯&/Ç £X{êRï~Ûão»»ï¢9ï–ã�9ŎúŠò“Ô]„¾&YO _¯3’‰dpUÑ=Ÿ®&Y_˜©s‘«š³¸�ªiÕ–0‘U7W³å>1y*¸|K­k…H’ %žù…Ù3­‡,á˜ZΈÍB½ ®å3ŠE"FÂá=ùôøøÓ£á’À$R˜:Oéõ—ÓÏ|jé/>€Ñs™¢§Úá|Ú5Lˆi[ªÒÖR]ç–YÊo˜o ’æd+×±Ù‰Q—¸K³»S(fš@SÀ¼„`³‰ÎïÛñå ¼Q=ÓÕ–KÀ0Q *÷¬‰‰\â̓ rÚKâ¡HïÓ_w:K?ý·znIlÎ¥€0ùšŸ“™9{³u¨ô‚�ÚýPw% Ö¤V–!”È5ÙEþí|RÔäZÜ\œÒáúHW/Ùh�¸ÜRZÖx ïCh¹¸iå#ŠÚ<µù3õŸk Î£Xak¹ˆä1hç’ ©ÈhaîÄßü±×ÿŽO~ú“ËQ4PÍ�¯a#ßh´Ù¤:SÙ//^$°VÖx„A%i�¨wëõ7}ß·¥;T˜¢�Á°˜¶…Ò¿ÒÁœî_�TÜ\õ!oFá�W3™ÂÜt.ßh›äôË,ŸkY.ÀÜËÞÊYX’|ãTd(üý‰Œ…Ó,äÁÏt.4|`ÐÎÇéXNŸNO-�Î8±Y§TMÕTz~$O>2zà^®œŠDÓ9üôû“g¿éÐ¥¢z²®yµQ'›6ž•mÖZï®éŠuµ3s©nÁU‡lì`ÑÚ\a—UÅ‹iä#’ÃáÎ3§W^ÿÚ™ùî)s#ˆSÄjFQOsx£i:"F”42":jXŒÒ÷%(óÕDA#\]5TJ¥/4sÓnŒ%sž 1d„* ùN[´çX‰}Víº×yý|°‘dœÒLyݵ‡?{ä¾ûŸSÌ##àÔ¨€ÀdãÍߨ¼^/j. ‚lç‚bØgº=ozÕŽ·¾ve¶ë‚Ó`N‹ê …†§Z¬QQ‘ýyîLý˜ þÙ¿,sŒ¶Š'^¨M\иJñÀæåŠ�[ƒYf¦³¬þRxn©ÉŸbÅF¤ *¥ŽÛ‚ƒ}é€Î%%ÌYÂÑ@—Oɉcºxt8^¢y'²“æhÁpœMA$Éà‘ûG�~�Éq3‚3@zÎÒSSªðúaÚý/ÀkohMã–|#M¢­– ë¢F¾ã4J#ô£¹{¾tæO>ýð»®wò(,z�ºâDé/jÿ!�žqÝÝÒÝËî^¸ÎÍçIÓ‹;‹ÁÁ¢Lã·ÚU4`ýjº~C* SÚ=fÎ&Á‰©hgU“�çó]×ûXOSkÛóâ5³±)¹å³Ïý­¿þú{>ýÜ×\·Ó ™û�9˜Ò­ßLÁv¹ÏÆ&íš9H ? cä4ŠÜ•nþÉÞv�Å‘ºØ c`–m'ýÚP8îV¾ õ¼öY°Ñ„Tm5ƒXÑyƒMª&ƒ•Ô�v=øØ;ÀeµR‚QT+©GLÌœ™˜‰óáóÔfåö†üoÙzäþj¨^åê FàÜ"1G‹Q8 ¼¨gÒwK§ìÄáÑ‘GO?4:ö¤®s~Ð¥vÄbª Ù—`õÄÄT˜ÊñLJŸú�?L¬(¨Y%çÕº¼5¤–rê¬u)¸´º�ÎYÚpöv¤gË–÷Ï�ðàà"�%˜|mHK©J•ÀÑ�B)”ëƒB„¯­v~/ŽÕΦjYz­ì`qÏÉ+³ƒDen+ 1?D…dñtBŠ™³¬ú\ÕcºÔIm”þ¬õ†×‹íA(@^:1{“ƒ}ûvö‡³ŸýÌýf]CÇ$¨X…Ù'›ÑÐÍÚlš„ÅÊ4Wq”:XŒkßö÷’[–¢hÖ\ ¡‚^S±¦då‹/“}–ó›OØ›ªnû¬(k§i®n*±*�L™ÓOj5 …„ZDçà‚²JXl!}›A‹ÝUù¼®õiÊ6šÙáª)EP©÷W7F1ÛHÔje/óDýÞC½�†£áPýd<ðÃ¥N2PUšFP!A³ˆrýšip*#Ùõ~féèÒ}Öç¾FAbg–V ôÙs.­ïš:ΫÊò¹âì0¸ú35‹Ôb/CO¥-Sº_}<ú¿úÔ¿þéëvÎ<aÑ1%`ÆTR¥wÞ Hœ |réQŒ"e'‰vÒ͹h–nŽ2G™¥ëAbP‹´juCèÆÞc}‘ÔµÓiVÍ<˜®H } :0£<åNÈv—f%'é`Zn\6è…¸y¯«AU›éösM; GîÔ{¾ïŽ}ðÏ?óÙÂ^^úçb»h* , hîå`•:wý•ûßu÷`¦ç$†ºNï�ºì¥ÈLKóŒ›æÒhBÒÏÊ Ý .:V=_#,èïrŸÄU³Ÿ˜¤þÁ{°#„¥LÇ0bÔO’aš é=|jªÁóyë§$'"‘3V=²¼ÊX÷)¶ÌhU3~2s¸/üEƒû¤¥žšB=à©*jbê 1ÐÍÌiÈ7œ•—ÒÊvÈ &€aÝÁéäs±û?%'Su^�†@|y1¶'j¯^:e~“V}ï90¡�½Ó4ÓNº ~¦/ƒ?øÔÑkÿ‡üØ�¼t!ºÆŸŒ5Q§^Ô3cæ(gFSú”Ñ�Î)"e Fƈt +²TVRSÔS7­‡T8HÍDUéNíúj×Y� õ÷(]Fs]F3”.]® öBH9L×5ÁÖ#X40¹óÊ_ˆC<¹#õÆ•«žü‘zí×¾ò§‹}¯çÝE¨¼^P&óÚ$dŒ;„N“æ 3�kÞö�éÍW{:QzXÇÓ`C‡(dÏ3N”Irª£]PÿúWXk��·©Ú×ð3M{µ¼�,&-ß¿ AE:ÆèŒ,�LûgÒ•3>雦‘zg>‚ÕÕdÅxž‹àRXC*rvæëXäE(ºœÙ"jù< 0“,€"ÿ1Àæ©8˜8“¬ UiÌüMsSrÒ_üâ§xïÇg–�'6ðÑNøX41ç•åÔZÇ¢²&â²iIÄÎVx³êiªM¢YeºAebLi)“øžÎô—yÅÿ­£�ÎÊ{àÖn÷~³‘X7B &©³ˆñ`ñ%à8÷ÒRej°¼Æò´1?wÂTg «ßl sõ�#elÒ¥ëI§7�îÕQg‡D]0»`D � Q*$ «ýo½=!ÑŸÓÛˈT©±ÎÊ»�©ðØ;ßqÛû~ÿÑ?úàIéìT^{á‘‹8·¨éµ5Æ@ŠTN:QÚ‰®½9zÇ[ú�މ‘3%œ2sQ(ò†åÈBÀrýÏT] &¤Œ&·ÚjT^®ðažó3lÖB8£„‡$˜ÅNÅÆ¶tJÏœHÎMFgb?ó× •æ[”F[«è�Ó;œþÏÂ^˜|4h¹½UÔMfAÕVIûSø´J£!6 ºšÄ£¥3÷R?ý;Òn5v c UQC CáÊ}>ä¤Qêl:] ¦Øàò]‡Å¡‘QMWqœý˜’œNáÓ B¤=BöÓx¤jLgýÕÿíœéÈÞyÏ»z_s6/b‘Å Q#T@Ñ,ß«•÷.ÜY³•4MzZϰU{Ù”ß|=¨È-Yyƒ¡b)1¦Á™<’HGºsÒÝ#ÝŒ@öº&©‘°tfS¨®QçizæD_X’›-MCN¹Òäár;J\p€í¹bñ/ÿÈ]ŸüÌûO¯ˆh¬Ú¡sZ)}º‘¡:?�wÝ ˜ 'I¡@LÕ�pˆf®ûÞoë½å•Úqa#ZJúE8d1°Vቂ_ù�öÆÈÕ–{ÆÌå;-<©Å"ñ‘�yêpòÌÃý#�ŽŸÓd%Öq»oIú+/MòšÕªÛç ƒwbË ì˜2¤qð0�Eˆ}·ÿœÿì‡ý'?ÄåÃfIžô­(šÑ<‘¶ÚVw÷?ŸÝ†ãXÃø“)L�âƒ|¢Féè«_<Ù?µãö;ÌÌ�4K�v`!b b›Qt½óæÒ­è;�—IÚ$‡væk? ¢0xJª˜º4?BÒ÷Ã3éà´-Ò/ Gtš7!€ÔæÑD°š8ÆÔ£™ Ôváù^+£äÊ+}åËÇ~è„bF¥žƒÓy� Ùâ"1ƒÍ!R˜÷n¼îÚ÷~Oº7"¡”„ËrKAÍ� ÐfLl²K[h6Ú“u¼2ÏŸ³´³ÜÙ‘i`J* >UQÇ9ýœæÁ•cO‡§ÅF]ú.5:«^’¥?UøçÙ®I…²NÃi¹Ë“êf~ìy�’•eˆeµ¦Ä¢`öíZ}jü‰÷%÷~¨»øŒ‡×U ;Kÿ7Û�lšTaRù6wI ¨ÄJKuæÁ¯�Ÿ}Ro¸éŠÝ{Æb‰¤3TJ(¨#Þ$1Q¢›ØÔií\ŸhÚ˜ð¹¸`ªÁØ@� ó¢#ZÉ)Œ�Úð¸OSGÁDB¼¼h�Æç¦a�j´ÌYÔR„NV`žô’¢ipØèõº‘ÛýÑ?{x”ÎxÍ Fnl¤7xõé�0‹ü2‚!î|×7ußñ:ítŒ¡X¤Ô`­dÌÿÖ£A*¯£ßÿèúÿÂ%'�¡†$8ëGË΂õ0€²V˜h×,Ò(C{œ_øâ©…=»®¸f~F†Î†Oû4М4?â|P8í®gší•k¦2€l? ÉġީØ~e4^ÒÑ5×�‹A§ Qh¢Lsù¬Õ´0`šû, ¦1[Ù¿ÿàî=þУ'5Ž q޹þ!ßÈÅ�n çPø|Iˆ�ÇŽd_uàª÷~÷àšý⢂ÊW³ú(B®J"Ëf[ÖÅ]#”ªN(‹³Mô$‡Ì{›dEI¼�ÆgðÜÃã�GgÄÒQE ÔM OY)©âTQwšx/å+¨î ëZN??]óP}wµB�zYfÂQ!PR�,-³�b±-Ï?ÿ¸ÿÔW>óGþäCŠó4íè:ý✰Y `=1°[X( •´àaÞÄ»D;úüÉ™O|öÌÉ%Üpu´cgIO#ÌQEŒ”é+f£ã0=\ƒ\Ï`rÚ••ÁkÿžBÕÄWÜïR)Úr:\FšˆD”.N*‰zj»ç‰¼ÿÕ’¿X#ô¡°œ”"V]ߺZ!]«m^¹27Û >vÏ—ÇzØÎ  †MaÄ"0zçö¿åµóßq÷¸Óu&Á3EÃ’ù> ·UeMȆ\×7Y«6ìêPTÁVép3áÚDÆf ÅL£3GÒ#öûG�t&TÇ ‹‘•©`«¢²6`å ibH3}_�Ô_üsÊJ-¡ü"�4uPGƒ9jŒ¤«£èÌQ|éS+÷üQÿñÏct„X‚¬ôšJ6bû1€­mφÑ4˜y*¶J„�‘šÀ«ŒMR¥K1Ûïýò—ôþÏ/yîÙuå¾î¼#ÅÔѼÑ×ëMžû84 ‹ç³»hª¬T•"B’† ÂÔ1�Ôt< ™¸.Å5?l:•o† Y±¦|˜zõTÎa žïÞsàcŸøê‘£^97Íñ,ƒµ±¡Ý^ T:‹°kþªüv»ý$ŠUTX-™3‘î­úaýÙ«µmW«€ yVÌz���AÕGH¢cOŒŽ=2ðƒŽK#ñµ2-E8#òä-«™lP|×ÈìlFÔÆNfÃ]øû¯ú®úRè²@�ué…cÕyóóÃ3sÇžH¿ü‰þ§ÿ8ùÒ=¶xX´xx8 Þ¾¨o·^´ à,hdÅ·å.‘hTpL�™î&iÁí:|*þøç–î»?�w/ìZ˜Ÿ7�P;�t*™»$@ERÂU‚dz,`N¼ÃÈt9-CS‰#H/+.8¥tÁÔ&4Òî)¶¢/³U[È‚•*HåÏÃK Õ¬8œ�çsÏë§?}Ì0o£þ¸ÄsNRéÞyÓÕßÿmãóBçŒ^òìZd^Ô‚yŽÚì3I-¥Ýæ,EÖ«Ì[ˆ� >ˇ_ºCˆ¡Î�ܱ'†§Ÿ[Òc" –]f®-e¬˜ípò$È…f´bИ®žªΜó�Ê é¥�pÙ¨HØ+i±ÙÜ8�ëfN÷yxïÇ—?ýáäëŸçÉÇÍŸˆÓQ7¡ÓŽgìÅLFb£µ´® qN¸Ü@­XPQ>#„ñQÍÏ‹ßáL͆dâeyÜí =óÜ賟>õ™{O?Ñ57͹n·ë⮑Æ4Ï·†šÇÙä^XJ¥Œ•Ú€«7©ÅnwmµdÃøI%.>³ÿå[öÌ/�°P(”ùΛ40�Ö5 uDU8¦�|Ò§ŽÙY Ä@dt5hP¶ÔtUY G ë²b”Ÿ*÷añgú{Ì5Qæ 18 Å�ƒþÓÇ—;&Y‘¾úX­Ñ˜ÍaŽÞhñ÷¦ñ3jd’ÎÎ\ùªWÚîýô±À%!2¢Èaœ×å¬zé׋§7Û‹2‘Éjž?>+|Q|— d¨Ô“åö)Ò¼ý O<5X<’`Ü•TŒ–Pé¥b/¦4¨Ñhæ] £¨ËÒ�„r¯Pz±Ô„"¤úü±ÌãE w¦MÈfW›Ã•JèÅcÂÀ*ˆ:úÈ�ãd(Ã!Nžè<óxÿ™ÇGŸòKG1Z¢ŽI<á<Ìœ™%a¿Dsf²aÒ·I.lÃ_4\¾®ëÏÞGÛ´TÓǧB[QTÔAö²�ѼŒ”t€˜Åð4ëyŸö{>÷ÔàK‡ûÿýOû×´×Þ1óò—ÌÜqgtÅ‹»ç³QY* Ík¹T•˜êÕ°jÇ<íÔÕ�uûüæy~1Xœi~5�£J¨h(è&p’Õ3 3á8%UâÅ�i°<6^dD;ªÃE[D wB®VÆ^<™ LÌÑŠ"tUGB¯®èTíTÖìò ©|U–0nYŽÊ’V)ÌH"¾sçí3¯yuïÙ÷-[4ïML�€ ”$ÔÒC1ZÓšs>¸8© ˆ, ’Û9¿÷¥/N\ìá¸sNý³¿¥¦mJ�3®mÓŸjQ2+¤ôÉF2ÿ}‘² l ‰Ì(&𨱧úK‡‡¢=z òÒµ0“Œ‘yˆ²Y.åÜ…28cÄ�‹éÌ82M©©ùÔLÍ¢)Ìj^:Õ¾çq�IŸ) 2P‹¢œ[Æ Õhùeø±WdyQNžÔ£'úÇO¤§OúäÒeh_˜PÇ€)Ä b42ã\y�¨‹2yZ(iS6yB¸F±­¨bp&†ŽŒØõÓS%}]ë�Ò� ƒk®°›o˜?t-¯¼btõA½bg2Óc'vâL2G š!)ä±Ú.¤hÂQ â¹Ô« °a[ É!¶Òƒ*ŽB$Ý:]F°HÅ($Ï"%UC,À$¸ZÐ"Z¡¶š%X½ &©bã´ÔüL´Kg¿™¢,�\­®wµµÔ,õNÚ$WC ,BS½U¾L³Ç±¬{jôT±°`o¹ûÖ~øó˾Gta’s¸�Î ‡ˆAÔ¥Žs×_={ÍÁãb^ ¼Á±ÐÉW K7‘›*û®�ÏYn¬ü«™F)«�‘›ÿCª)sðކO–ަä <�DÔÌ.((ƒc¼‰�&TÒŒ‘�ðÍ:©Î(:áœ:28þ|râhzúdºrÉÉ:n,R®kq•.V¤�Éø€œÅIªÌó,¨…J›ú4ñ#ó#ø>Í"'… §ŒBÛ !„ܺʫ¶Ø`Qí€�BA‡(DèN¯à©‡õÓ$1µwg»Ú�ûÝ®u:‡(’ÌELT¡EŒR5‡k{’FúàOƲÒ+€2k‰ÕòœÕ�?ÖéÌŒíÝ;¿oßÜÁý|ÙÍvýµîÀþ´-‹ŽàS!!©Fc/¦B@DÅ)�9˜Ýjý.!N“tø¬ÑÇ»|$W˜v�)8^÷PNXW3 ›NªË>j^l-¿jYEe Þø†›¯¹æ‹>‘ÐfòU/yZÖ-çšäᵌ”ãÙhï‹oõ»çSOŠ™ä¥NòÁf©š6kyNéÔÁˤábu°`ëYj)ÔÔEƇӥçM´Ÿ{ß)Ÿ¡Ü¡ÒŒêœ’�”¦b$¥ÒèÒˆIg0è>wTzbñ±GÒ£_÷+'08Ÿˆ&ÎR�7Ñ!£i† Vþ®½˜÷>›RÍtÙàì޶bËŠèP̨ PÙ1UZ*òG3¬Zê Á�§0¡Â9À«Š8¼ŠŠG<�8E#ßéÛ̉�Ãа¤–S¨"ˆÉ[¬øSe@ã¾pºÆˆf@!OŽÍFÀ°ù=3ñþ=K¯|‰Üýú¹×ÞµëÚ=I¤‹°TÄ«˜Ò”cƒT`(«M2bBŒÒñÈ/GÑìÙ…ÐD›Ħ«z*‰êݵJ·Õɾè¾Öó‘)à³|¼\sõ®—½d߃�Ì›Ñ ÈLžþ‚[‚Ø´Lx ÈìPŒfäÂ\ïÖCÃNxyPdq–{Óçs¨+ú˼flvŸmÊùÊ“°Åe1™�¤3MOø3ϧHºð&&$Bˆ�æž„ˆ‰•[n5x#|W:æ{ýE}ú±þ—î<ø€ž8ÆÑ ¸¤R$Óµw)@‡¶Ž5SíØºÅË�“V± µh*Cp¢šS8%�i¦-‹§A¥•WÖݸ£ÂYÛפ#nq.¨äì*’¥Ž%—åSQ˜Îæ°±J‚h,Ú©¼—yÎmÃY]§ùí�éÔÖ$% &„#gɹà G†ÑóϤ_|éý8sÇ¡þ;ïÞñöoºöæF3þlI0r¢Æ$ø­Á«…�ªÁ4Tá8‚OûG„ûe¦Gs9M™Ö"© [S»VÎÛf´dZ!Rá¯5W�fû¯}ÍU¿ûþg“d,ìh©( ¯tkÓ\_œ€*®{`ÏÜ­7ö Q*à¹^"PºuÚ‚icš&æÎ–¹f<4 ^s47èëÉ£CŒc§(Trfy¹/ ¹;HQ’êEý <‘c{ê©þ§?3þÒýÑÉç;ÖO9TQB`1L<œ22 ÕbÌi_¦enÞü­µí™¼”HeŠÕ^ ½¡Ðœ'U dJ¤apj´ÌIеEÊÈ–èo epJLc¹O›§Ef�¬ø3GÀŠ1UÆVD +™èFÒÔX59«_w¡ „‚IÌœ�³xçiÛù™GF÷=~ú—þøÔ·~ÓÕõ�n:Ô;Lw2r)OQŠ+üz‚u¢|T :�8¦ýg⸋Î. ³ÖNeJy™Ê¢›TøT¿ªztäÔ¿Mj®’ƒŽpÐ�ðôë^}ý�½_<òüèÐâl�¾® ºóÅű„‰{n¾!ݽ`â¢æ�Fæsןª­v¢ØKí>k©€mV0û`ŠWjj'ŽŽÓ!; à5Tç*­ÍÁ#�μ’^$5ˆj ?k)N[üÜŸ¯Üûy=ú]M<Ç蘊H9 ŠB5l&4¬¯ngid«ö¶2Ç× Ñ©)¨ÈCÕ q¶ ÃF'ŽÌ¡”¦[T·:6\ ¦ÅÚ K7€j°,LcÐÀ>¬o3�1Ò;…LS'r@X§a~6ù‰§¹Fµb)c� Iƒ‹ÍuÇ2ÿàÑ¥ÇãÙO~jð£ßwë_zÛ‹öïx’v.�„â0¡©ôG5¥Àb±H¯Ç“¡ëto†í]Ë�lŠN�A°U¿ ÐÚ,8�" Ç‹¡UJÿº«¯¹ù¦+Ÿ9|8r]ŠT{2Åì¼(îx¡@È6Ò:�7Ò™5:5JþÝ´q]}“⚦ Øjß \Ð(ç¥/Í`>UBú‹6Z¡S¡‚r§M ¾É¤!TÒV�wpÀì(µg?þ‘?±û> �^#¬Xè˜ÀCEM<òìÌ*:÷ÑUºKCð2ZÕ�UŽ«®˜Ð¶fUµëð‚T*ãªF€yõD¶ÓÉ2Ï·éúÈâmO«·Óâü`YKfv¥×E—0`d’d© L"MóŒÐUNÈʵ�§6o¦n#™ cTƒšu¤9&MBÍt¥9¯‘�]_xjÇÿðõÏ©÷wÿÚ¡;uèŸwTBd1^„ƈÖ�EÂÔÉ(ŸH»£î<¤—o MætcMisíEPT˜jŸŠAXh Õï˜ÇKïºæžO<*DÐ –‘Ûœe7q›¢üIÔè—]éÃùØ‚þœ¦Ážkƒ(£hçÂÌõ×§«¹Ô©Q#�ÔI0Ñj!éæ‘yÚ8¤Uï—ZŠ/‚Ú�]±@ÐÃGófBÚƒã*ÃÈy="£Ñ�ÕÙËàYé¥P³Tü¬ÅÝä÷Ç?ó¨$}5˜ªeº ›…ö‰Y³YDõëêq^“ëOy•÷R#¦¬È6aL.Æ¡|" b5&\l:6øÞ›üÙ_¨jŸMŠoh*mؤêl2 åq ¡ vá-G „qˆók=¨  °Uî~1MÓS�‘ª^œý …Œ*Ò.„„ÖY8˜Z콉tÇ3¿ýÇ'ž9üÈÏþÔ­¯|±ë¤Ç"!$XVáê ò& w–Ôh×1`åسîÕ`/+wÊĨ†æ$ ]=Ðyj~‡SÞÄbÒüMób % Ôõ⥻n‘Ýq?‰@GŽ`âà< BcÜI#=¯P0+ÿ:to˜~}Ó„Û(È¢ƒÌ|ÜŠë\uåµßñ-+ —8L iVoª¨`XN�ìd^ÜÐPDq51€J›Ë0läROÐl{ Î=Ã3:Z2ñN@BA#E %?BµwAs¢ ÉÀÝÿó¿÷;é³�‹ï#D…!,„Z~Ä©)ã7-u£¡ü•£úO›ü2oçÆ[´)í¼ì°Aš»–Øôk+Þ,«ãN‰ó>¦�%²¥3å(ñĺÈ~ÉÚ �8×�ÍyvôÀWŸ½éú›®¾rFâ3Ì÷§‘ 布q8óvs€ƒ™ˆcg7ÃBV�4—¸…!b5ñC‘'®<*'×9þ´êà³<™ù}&ÉÎüñ×û êb“&`j�ÔÜiÏþâ%…©W\ÐXžyÏðk_‹ü u‰Šæ6´Vÿ³^TxpË ZœÆTÝcÊtFtŠT8v{þì³'å·ží'·zì3×5$85Ò²d¦1Aj?h�Êê:P†Âk‘õB¿ª¥ ®¢þõè0 ·c*˜ÄÑòõ‡vv{ x°È·!ÜsÁ…Íç•Ç;só³ûŒHËJO…q `º`jÖ$ÀbGó}rÀx¨H‘) 3Õf(�Á†-Ò£õúúò=ŸàòbÊ$%]â\ê<Ýú«´Àoo[\Ê�Õ‡�)Í`â%"i¤�ef{~ýwŸþüd¬s”˜ˆŒ “ó!"X @¨#KV ãJa‘Õ¾&ë@ ôTP >? µƒ/Äü²0@†ŠtOO7¸ùæƒsó�´bLßò¥±õ €È“‰Õa”…ÌÎ4ŸE+JY†€0/E^Hî� ¢Âª[Ö0�tde‘,"OÈAsª¢ îIJCdÝ•åù¨y6Fš:(¤›¸ÈS/,?½äQ3¦µØ\¼ %§6«#‡¡ƒÑ:ª�óGŽïüÕ_ûêâÒ^ÃC×*…Å@0â9# ¡Ð, 6["ü%n[÷·U—êªW}n½ÄøÊ+fæ‚ÚŸÆ ÒÞò—…ǹç ΋óâhÃÈØIcìÞÝïÅâ½Pƨ„Ô F3ͳ÷3w¨Íˆüô6ÄÉe®¢e„ÜõUÂ.„YÒ9ª8ˆ%È3¾™IÍUK�4JÄ3ŠÍ�áEÆî�¯ô¿úEêÊÞ„Œ„µàF†h»%U¶ �>?´.¡«±Áx‚Æ×5%”87ÏþMéÖãêþõ5_U%,+ ã $”д3÷‰Ï-~þ ö-o»Â¨&crDˆø(÷Ë+»N ©©Ø˜š�< ³'\éÅ7Xv–Ð8›k™àX¹^a!û?L¹cGÿà><ú¸h×¥nèµG‹7Γ6ÉGd ŸQÄ“š) #çöíEQƒN¶IÒ\PxïT�¦ÖÐöT\BCÍ›¢ç™†`6…O –éþËÊ�YmVŽLI#:‚™áðô}_Ðå3oY>i*CúÑV’m±ðÂ嬴°uÏ¥-3óõæN/;ï.÷÷¦:cè̺Ȭz²ŽYfÓ3ššŸ³$½ØènµŒ«¤¤bº BV��Á•Wì¢æqÂ@TQmÕŒ zÈÍÌ�õ“˜Ýµ3ÔkVÍ¡ø”ò¥Û~öy @©²SÍTú–çµÍ¿¦™�ó Ešú,TD²ÂÍÌ"Gà€(Kù`>²ŽúÙç�¯<üpÑž­G-Z´˜‚|=ÃÔ nǧ>ûüªr—ÑŒ±ÇU„n– 'C*õ™ˆ}ö,[…a ÙØXÅÔH]\ÚÕL‹Ï0TD÷ØmþlI_6 Qѹ­ Ñ lšEI3¡›ë••¼òŒžÁ%_³�ÙOó1°õ˜+ªä8TÞeÉŠk² ³Šcj*¥ ÏÍB«DdyéÌêà ³‰¦_{(9qœ[ï¡Õ¢E‹³"$Põ)»GNv>ù¹ã/}ÙopÆØ,ue&GSó_¿@§²�ŠÇÚêòêy+¥~Û‹Ld´üžÌ# Pù={ºäÈ‚jÈ@lAö:Jöh9Äæ%ç¢åŒ“YÔ³�†^‡.Ê”C–mz2-¡`ò‰ŠÛ6¾€ ÐJ½,ËT€VÞÍ4³ˆO5¼ÔZ Z�S*I¡Á:ÉhéÁ1Z¦…|šm2Ë-¶5Á.T¨¨SHï™ 1÷Ùûžûᕽ3{-ä·NIyI@…bPX ú²LxS,XÍ ±Y¹L^VƒDÅÇ4ÿ*÷:1¨sé®Ýw’15³q@«¶œ­ 3[n� É/Ãͼ[�ønœóÀU?(¢À²Ààâs©ñ¯èýË£¬ø˜Ç÷NEæøŸ%ÀÌä‡2%Îë!T „ÎŒT,­<ý$uˆM+Þ¢E‹õcªÏéé9´(~ð‘ÅS'DüœXdH34yI†‚ç�Ï3l.…­ÊþºŠú×@šp¼ÿÀ\Üñ µQ,X‰·v4·–d^7E$X ¾‘X¯£�-„sE¸¯åÕ€Q1 dŸs—M+™Á„)Ø´Â3,¿sõæyª�\ûŸ›a2gÕ°²â0±Ô„±™£õO÷gNA’­®ÔÓ¢E‹fL8è8§=ƒO)'Oóé'ÆL÷ÂÏJ¾]X�\Õ«fð|P¶¤…ugPZ5t �SB)~ç®^§ÃÌ;(ûíq€ì¶[¿¨2ÛPŒEœët,WˆMŽz]̯ü­ZÏÝ�Š¿,²ž†fän ˪xf�¥î±ëÚ¯¨›¨¹Õ9›™ þ(¨T�]çò(ÂÁ¦ÆT6€úõBÉâ{ÕŒ ÅL`¹¤_½™͹D*çëþÂùPÖF2ßR…}ƒ1‹ÈË‹gc ñ+‰2C9u WÓ-Z\X”¾ß"ªfFÊ*-MîZo$… LË+Ö‘‹©NršÕGG± @Iý­HÀ£…*[5O0@»©à6¼°s’|«˜™÷>×ãÓ‹e’>©*ž[‰s¢]W»}½5q†\Û_ª€‚&'Oß“)ƒò�Â:!Ιz Ðz�¶h±}�åù1Àân‡¡v‡! ?-6–… K 7±ôm} {bß°¶$Xu„¯Þ‹¿¹M¡Ð¾°´©RgÂ$£™™-KšÑ¢E‹s Pˆ‚jôó sâ ©þ¥Tþ„ä0(ds–ÊÝ’Lotq¯M¬«IÿuÕùjé`‚�Æêuãm8w\”í�Î/+ÓÔ³HëG˜ºþÜÃvUBÖÆýPaW^u¶ØXî¡DÅÈ[0™l2íÞ,�Ð4šçf¹Pª³�hQA«¼0hX« šÜˆ’ìÝ×ëôt ™9ã[M‡�ÕùËP%9S×õ9¼_-ïÌUàÊ ƒ‰Œ†cÅ&M›:‚6PýꬢpˆzS1ÓŒÈÇJŸš ÓJ^~XÈÀ,ÔTÉc²ñ³L9?-IÓªÀ€|p Ç"øü¬˜Iî ”Ó î¨ÕKž>\Åç» Ì"Àõ#é\±Wº™)¸‘)qöìEçyŸ¦Ô :Íæ77ý>¶aÁhƒqM­±á~5ÜfƒÏm~é{“Ϧç6çÙßà@l°�¿ÓÞcS‘ñ¤)B½/oŠ_èÄ'®½qà¢eó±ª8I+�Fe(‘…2S�¨gm+0µAÓÿQkg•†‚.ÙÓXá/…!ZsôபPß_–4¥¡ Ž`¨ƒhAœ6SÄM#/ÀÀŠa Ý„÷ލa\ÊeæûiEO^@k)ê¹þUŸ‚©�²lwÂâvZ0³Ñ�v²çŠ+–gfGCi%¾u´óá‚ sí/Wkpàó Ò 1;ão¿í ³Tè(œˆìÉAËË.–ž9V8¨Opåc®�˜¨^ž¯zžL a²ÚG Æ€ÎÒÒxœ½ÛRCÖ€õ2€sžÝ�”fj �©™Oe¥/et.Xøçg£Xd—­)ð5ƒ­þ÷jÉÂr µW–eiu J$¨Æ ÑÞý£ãÏr‹+õ´hÑbÝ 0V8ÚÊ�ý¸þšýÇÍ”´¢ L%ã?× ]'JšnÓÎçŸJ?ŸüoFé4ãA&…"D­{üÄR’¨9dqIØ:_ÃL“¶Þ}ú¹2£LÝꬄ¼¨ô)û}ñ&FhÃÎ*&,d²y¬­#cC]éÚσˆî£ÌÓ„WÒÐIÞv/¦çvÜxdfã:‘-Zl&¶ñ0‡Hõä]/Úsž5øyjECPù`‚f­ò:ÞPfâ|Iý­’ ´j“@vÕ„>í�>%ÞGÈrç» Pl];€Às¬i0OQK M‡‹gæÒ£’ç÷,F±øiÅñ³f—¨¨ëª„˜ÕÁtoªÉ³Ì~fY&R(Qx‡†…{ BŽ;Ýø–›ññè™—©î1UµÒÊéÓkZWÎÍÏš~MÝ¡Ö~Ûq7ýõa�úÜ §™Úàý«_¬ç]¬o Û­ÞÅD-6¿L`…ª…€Q)Öí¬¼öu7ÍuS—:ÕÌ›ž«©p»þÕ×8*ù…&캆šìÏÌu$¯�¥¹ÅUmœtNO �ÀÏĤ’Dh«°µ6€ ø!LŒa[cNmñèѹ±‡@œx£UÜ9 ]Pf )‡–õÑ-.®-þR‹3Ý;¨4O€¦…ºIKÝB½ßP¶Æ©[¡ÌÞ~S|àŠô‰ã_¬Ýgƒ„f;�–:�n8ßh‚iòÎÚ¤ö4]´Žû·þº/ Ôk5±à´¼’ƒx´^ýêý—œIá¾cVàØð´ö�U�ÏŠ[jœL�:GŽ,Râ (A(º°eØú•,w¨3ªÐF'NøÁ0«wfeýÞB φʲ: yèìšH¬¡ f:Ln"ªE—Ïvì¸|Eáƒ'=ASQ“ÔÆ±ë_¹oöæ›Q&¯wwúéiÃrIP§P˜ˆÌÓzOk4W›×·ðäê±þ�{Ö~±±ÅyƒÅô«íøsŸ e”Æw¾hï5×’¶,ÆIâ–ž•Í&z9‘š<VSÿâC¡B¨j<Ú‘#‹@”{À\O“­g¥ ¸ð¶4 u¥/Á È  …Bt­v{¨ô¶–9ñ”º¶¢„p^lÓŠª¿9OX×3ø,j»üN†·'jKLdz3ó/}1çæCþèà:`ÙSÐá µ dbé€F1Y{ :�Øjð… uëatWgœÓn4Épе…+Z°‰T‰­�RDÃtxÕŽ§f³ÉŽ\‡6¥M\ kÑ€IDAT87›•t>«#ÁrõgÜ`­Q«ëM×ä¶Ž–­Ò Fr3 ?l8^˜ÈÜuê$÷"˜¶:úàÜI ¡°Rà%K㈬™Å�þ›ÞxóB/¥&¹0(õ±Í­†Dóh7ÏÏÆ3kÃê¦ÞA,žñ'O%”(o˜NÎæ-@Ä1ÑTÔü² ÜÆk“p Æâ� Š‚&Ë‹xþ8®¾ÊC¢ÔRzï,ö‘Á™+m+šëx –•e)ô“j™Ï€Â¢È²�ù¨½sJîÖˆæ”-•3µf ªvqé0>€5ýþ¹q.+óQ¼Hõî%ñ* HZLsY24úÌ1†‰Ah=¨Š$bBë¤.��æqªF°ëS½áÆÁÛ¿aow|Z¼¨ '¾G&¹”+¹ØSô�yïʉ‘›&‚Mt¯’ç§QZ¤ ¶iŠ0"3@ /ˆž||trQR¡j,P21ë‚Z>ºªÙpÀËê.vA"�Qq ¯Xûýô¹çÅ+²dLÙ«É6e”VÙ몣hµWMÿÚùÏIFÕ2_ÜgbØMáwïØõšW}èáhe¤QjNã1œ"ç<”N…& 1�:˜S¡Š¡,N¾LHÐÁp6±Ær�EÂ1h:gh>¶$²±‘ Ý(Š)‘a4ÍÀa_ æO•J>T'Œ`¦D"ãʄٗäÕFÀ Û jD�tù ¯Q.d9™V ’¹ÅÁ`.*Ì|¬Ij…ú§¶ã /΂+·9aÁÌ}–8›_V›ºà6e¦Ðh™Ö˜„ÎlC ¾sÊ‚¢+ÏßÑê™È‰GMŒU^Á.$Ç•ªŠ¸*¯–<+Ou(*Í.ž&M‚Z`EˆR¥†b´kÁžy“-ŸQ�ªß)~™$—YÉ•ÜRò³t¢®òœ¢J¢©v�î"È22ŠglP˜„Yö^1 "Œyêío9tÃU½È-ÊlŽp@Zi­Ut…°ÊßÕç±îóiƒÅg­¤&-Ć™G=±Ò÷‹©£ásÅMØL¥þà…M “ ¼×'z>Šœ™P³ôš!h±ã°<{‡Â΄è±)6ÈjÖŠB"¬{æ¢d!ŒÅízõ«»ÿœ>°DKhcQBé‰F*Ä«øÔb`–œ#Š­®åyö~�U×±¼ZpúøQEÇŠô–,¶#[Ô<àר<^—�ží¯¸Uƒ)Å¿ÊeÌíá5;JéxckFJ4ÎéÕÍ)NæK0M¬Ê›á1$àðŠ+ö¼åÍÏ=ùhÔÆ2¶ˆFGu>ˆëª0O‰{û®—…ëG¶CÌ`^Í[A– JôyšºÛ’„çQŒEÕbÀH¬ãÌlxÊŸyÂ�;xëYU›—)e¯I ø\ÁGš8kBÁÜüÌÎ];^uå•»wÍÎÎv»]qND2SˆÖ$öºWFW\Œ¦ÙUBc¡ªfêË,¼”PO$OÑ›q%c©z*_=C¦ßìŽÞÔTUUÍFI²Üï?qòØó'NžXôcsÒeæ÷HÙºD*ɬ"*bªCõý»:;wÌîœ��›��™éE]$¥þÚ„”ÐþšP^y”ˆ”]©˜ 3µ¶ˆP„QnqÏ»šàË·j¹8”ªª_…±�žÜ0WVeãŒUïÔLW‡ÎæÑ0ª‹¨ØzÕš�Ë%­3Xš½ÕÌÀ§¦ ç;^}jÃÔF©&êÕ§0ó&‰CÒqn°2óØ£Aâ42Ð ƒšQ$rNˆTxêÛßqÝ‹nv⡉3…ͬYÇjÙÂåŸYœyàë‡•Ý Ñ$·Žl 9(ÚPnŸM‚Á0<ülg°Â¹Cž ÂLÅg Ì�ÈO Mk’QE‹i f’ª|4ÑÇ©+£H;]±GVþY×™aEdïë^ѽÿÞñg?§~ØIé¢xdÃÌ"µÈ"õ¢Ù{^u÷ÊŽkDx#JÓ��Ô› /W\k§3Йs&ó¤:}»æfƉ?òô©‡îŸ~&V'jÆÊü*y¤À;Ѝ…F3(ƒîÇRcçž…;î¼é¥¯¾ë®W¼èÐÍ×ïÞ5¿#îEt"ÖTÊÂ)’i°Eç¯bb µrª¢Ä,dzìoØÌ×Ü;òG'ÂÂÐ_Øêtå-ÒRèh<Ž’çŸ;óÉ�~ó¡GxÚ’ðê3[ ÉÂO¬a I´±ë¤æ—¯¹ná[ÿÒ·½ù-¯¹ñú«vÍ÷:±Dq¨u^Ö•†�rR½Ó°¾¬”hÊ] óôæÙ=Jæ=iX(~Ô*Åë(-IUYj² …JÉ* x͵_¼ÄÊ-'vuÙ'©ðªêªaæÙQ6Ì2¹JªT²á«Q�–‡ 'Ôz¿ÿ;�ýóöc…ÚXÕ“QþúE b ìø 7軿뮹Î)— …  £äо¦7\ëÝ4CÐúШj+_mXÅëÖ�g$ nѱ�gޤ†ù(³rû-ãa[^¸³S§Òã'dï>,I#ƒ­$3„ô‚\Ýrª<Ö˜iuô'´ 6õ|õ'V£þ¥l“Y/²Ÿ‡¯0ÓÅý»v~ë7}ôÑôØ(Ôý¡dœÌ"£y.>tøèC½—_3ˆw§âàh…0ˆ*�Ágf²]„Š)©™ïš©èXDDË'å±ûG|ÚŽ?é@­› ÒÊþ¾´âŠF0¼Ò4�¤ÛëÞ|ÃMw¿õMoxËën¸í†ÙÝsÙÈ�¼¥gL-w»*—;Q‰».’«FË�óå7F_ö¥�U±õb>`�Â*†Œ¼!`œÅaT¸ZÕŒ‡ê}"³Žè\wïÞ«¿ç¶w¿é›¿á¿þÂ/ÿÙ~DÇ’%÷¨ÿ¶K$Ktú o¼ñ§þþ�¼æ•·EQê˜ÒN‘ºÊIªÚÔê¢m*XDNh'rëL“ÌZqʨŽÛ´i¾6X™m¥h]²_M 5åY™FsU{h“™Õs¨qd¤Ilt„ §Cêr:zzixôþ–í7pÞÙXL™±ÒD éÇîø}ÿ7Ýzã<ô8™û~Ó“ s¸8°’úS’?6€P^ñžÄ¨B£€"Žt–TLjc S¿>u©Sk¶yÔ;"wùÝ©‰myë jú˜ç»ý·ÃLŸÿ9~uüˆŒ0‹»Ѻ²)ïu÷*Q©yÓœ 9tXÕòÙrûÄöêÖ±§óÿõ_ßsï[U÷bµJÔhŒ& Õ{š„Í›oÞÿ¡\)\&œS10:(­üÙO|ìºûOtIÓrP€j|èáÓý�×Nf¨89ôyÄ/?îHæ'kê•€!å‰ Qµ)ïÐÆ×n¥Û}v «mÜKàÜ·ú|²~ ý«�¢Ö†7¢™j, %C4lfþðO½kô£‡Ê{ïÊ=Jj¦¾"‚³Hs,3ÝÔͪ¼ïë²p¤óª7 Ø�dT%©N,Å8‰Ð_óÍk •"Df¹VÝrSWŽŽÝg�‹['<†ŒÛ¤Â‰Øˆœ¼�i3ª‘cCP„ÈjéðÒ­ïzç{î}7¼áÆ|©·î⃱”a¨Á—ðA: xÓñþ?Þ+ø1¿“�ƒ02Lï£06ä˜(Å4M¬•h!„¥@§h‚œõz° ßZ]üØà× 2�ˆNGÉ`ÜwñÁ_ù­�=úƒgÏŸÛ9¿K˜¨Šl÷õÞB½>"¢E+Wè¶z¼Oy?íÿžf)ìðÂvù|z‚h ‘:�°nd ¸…“\Y8n\r䂟ÿ…ã'–ãé§è Ów̉eÞD�°yʾû§ì…ìÊ·„ØéD C‘iqÅ~,£¤²È`ð¢>xúñò‘;ªcßóÛ'J ` 3±,]‡ qJ÷Ê©eLÍ ^rèÍï¹õ]¿ô3W¼îÕ¡ã�åú`xÜùB¼Â7¬ABAÂ[Ó¡]IapM¬5½*�m�¨ñÃ0Ž÷Öôo;…ßôåÔ±N–¥y�Ôy²fE™ÉîuFƱTš9O¦/FzWá©�òÒŽ[¼ö¦W½ãÝkOÿ�‹Ã‚]F'RQÑŽÖe;VŠª7Ývðö›»sk?ðù“}O•+÷�%Äš=3YžD×´\åævئ=yíƇÇ«qÌAÕ �µ…5­Ï »T¾ž…ôìXÿÖ랟˜$´áØìx®%’œŠ#ÐÃ(€ÄÔ®ÑhjÇm”Ǫ�‡uc]ú¾¿¶ÿ_rå³_Ûê ÏbE¨3çÌ“%‘A2úBøì'>ñÆw¿õp¯zœD*Ý@ê+ª!)´ï:á£3öô™\{Î[{K¢Š��æ�lL­¾Á4Z08c¤fŒ]ʦŽŸÌ~\;DåT Q ˜…»‘,&w·«œõ 'HC�©@ò3äů nM�AË“§uyÕöï¯ÒaS¹&ÃÁéšÛf² '„rB±vÖ¥ùØmóçÔ?mO¿ÉÔ©¤Ö‡$àŒ.’Š!¹ðÚWïû™wŸþôŸv·7HS¦fŒ UÐmóÄà;_š‡sW¾®�…žæ�JK’ µ�"&YðŽê4‹å|5ÈWNl?t÷ðØlór¨6‚Ejf¤&zjÂ�£'è¡£J¥ÔýG¾í?ýîàèõW »Ùãeµ²5ì+Ä÷ŧr+ÖM’c ߨ� .Шç!¹»˜î¿#îîaMÜ|KZµïgJµqþ/Q¹Sà¥ÙCÇ)b`ÂÅ<{ø1uVuòÆy˜sY¤Êü‰õѱ‡—÷°¸t~qîÚ×ûÞ_`P”ºàg7­}nÑ,Û~ókÏáNŒž�ž ê{ûáÝ C]DÇñî #ÏUToÍ‘lm÷ãsÇ:m àé5ʱ0@ª<šnçô·Ë]/¦ c¹c[Ü £™u’)Ù\“øm ›¦m1UóšOd‡ºXÑ¡&jŒ§âÖcÕò“nUqñÄÚÑÿõß=ùç]Žôp@×êù H]…'ÄN¼û�û~íW¯ïek®4çj�OJ¬ó® C‡�cWœñ°ÎëóGîÎRHk>JV‘C³}>Ø?½\Y]ð,Êd4ÜyV³ž×¨/ï%¢�BÖ7‡O=)¯º¼ïý\ �¬¤)«÷kåHØ�Y1©6LìïIrúøYŸ·²¾6^Àã›VÄ;’À˜¨Ö5‚Ó]·øþÛöœ:Y|éÛ™n{Tf©* ¾6˜¸åÔ£ÃïüYî†Ùoa7ø=ª¥)h–ËŒ°¨Î´+!Ûxºzäîí‡ïàòcóq«d¬|O�Ï‚ÑTøÂq—M>!°Š2H¹÷âýo~ï[ßó‘Ÿ;rã«ûb–åêv±Aßg§È�buÍNÛ¥kÔwì@Ž.ì|·ñx®U¦w|`k­ÎÔ¥ì Q“ûZ\`«5^Î~÷ ˆläBÆ�ÁÌT”мªäé3xjk¯Uî±ÕµÅ".¨†›0‹F�ÂÏbÚÍ9\³Om펪X5ôsEÖÙÃy[]K2CêÚÝP�Ù>iAO̧ÉkcÊ À²´èÆ0ÙøÉ4ž¾MÌÝ®“ß!3ŸÉÄ‹Ÿœ¿�ž3<åI`L„M¦%Õñ¦Ùˆ`cz\UD J¤•……mÝZ+×N`ûd^öCØ÷ä©£ÿÏß?ñçߊª—¨u�QAb“Úµà2G˱zãuòßÿó·Ú{Òª¾0¢Hbc d±Ç$|lW˜·'§ùw<“RÕŸ¹¡ºÑ ?w×�ëƒ$U˜�K_^ÄÀ8jô@Ã2³çN޽�CÍ…¢<öx§ºe#멉SJtVC½ æS£¨ÓµDS1éøªgEu³v¨Ÿ�ÑÿqÐŽ ¤•ÕxC7Ê–ó{÷ùÐWO ?¼[”^K°RFM¾if!JVž~ë¯{1ãÕ7—n©SæÝ‘C)bÔ垪ßÝXÛ~òá­‡îˆ+�‰®d²n,œ9¨S'2˜¼Ð U„Ä¥ –Þôþ·¾ãã:|ãµ›™|¯ªÖå‰+%«èÓ†š©�“¹"-¼ÇX‹ÞL¿2öëlbˆTŠ: Z¿q6ä€s… M‰Z:� ñ{`  e;wÙX�¬t\¦VïcfPÆàF™bN³í•jë™a¶åé*Ù ZGé ¡�h”Ý׌J®‹ Ežm¯«® \·4òŒdG-Ï` j�¤º³ÑîÒÖà:“c8~ßš#Úîrxýüï>tÓÕNâI/žšQŒ‰I6‘ý¤ÌÀÙ¬›¶S�)°¦' ‚ÚÉÓ½;ï~–2)…ÕUl/ZÀxœwðÂÔ P`ê·ôÂ�ußí¨Š‹4_—©ð>ùœ�?´;xß.ë™É xÎËiî¥Þý­Î�#ƒ¤-MJÏ€@¨33ëV¶ ÒϲþEG÷}øçÊÁÆè±G3M-D1ó¦Ñ�*Î[ð8½2üÛ/Ï#t.Û Ë£y#ÄÂsÃÓñ‰ûVº»:yÌëŽA¥ª$ôbæ4z•MNÏ™9U+î}Ó»nçÇ~þ¢×_:“»GƒÕQÜ–n�ù*eSS’¹jòÄÍ�gbòŸm# €°É�ÚØ$´6³éç3†n¦OMQ¢Ò0±®™j�¡: 0¶Ûþ4X¨‚‘bMnóE4_ØBT ÛòÄ£kƒÕ*‹^4æÂ`CL7§°™�¾æ ¹ÀFØ8T¹cé4÷ÂÆ©ØyÚ}f˜«!·sõ &-›D ¶ªã¦¯�±¶§ãÀÓ€1™e*Ö|4Eëi"Ûµr{êÏítv}1°{IÙt:·Åám'êa%��Q‘G,ÖÂÚ³ºvJ†Ã¬t…È&�~它¿ý¿¯ÜÿÔRèõ Á JW) È,zƒ:g£}K›ÿ⟾ãö[÷eÕ³ÞºB@J‘Fç'þ˜[ÿlÂȬÏÛ¸¿µÊ_Îöýu eÓ­àb1\xøGòØ“Qd©(xâ;¥ã_\ðRA@„øh¡:ù¬=òøÂ¾ƒ%r…J¢šŒC¥”Ùl©;†aGb­ýÍù kÙ€: =¶>M^rjGL¾¸ÂÔ,+ÑUÙØuWùå_~æ�?];Ö5¸²75+)b™S¥àÊ£oþåB‘ûW½5°›•Åb±ÁgÜzøŽÑñ¤:C˜3˜ÍD{TB%%^ÔÄ�‘F ™!töοþ·¿÷c¿xù^·êä®Qufd[tÁw+øhuŽÔÁÑY4h 3“ôÂÚ¸üjf‰äQïâ5ld¦&ý—[Ø8Þ_=ƒh‹� ¨ÌÔN?¥Ãuo!B£Ôp gº·q¶~ôôb…C{Ü£0FÈ`¸|¿”«ÝŽ®ÓƒdW[FpŠm–�tH"{5J+›¦w¡É…×䳤~ ƒ±VÀl¬Â”…>'ü6KHò|^ ³výÁYçi¼ì‰Ó=6<ëÀ*"ˆqót¹zJ·6óh Y”C§¶.û£/ÇóO_Y´|^Õ¼:2˜ ÞÔ =� rÿ¯~ýMýÅ«�=-fN»t2‚ u=Óz?‰Ñòý'Ñ@;к¤äÙ³ÒÀQÿÂ;îì¯n;õn æ ÖÝ"_äñÒ€ÔÆœÊ`{pßC{nºùTn °” ASüy<¯™àÙ_>ï11v&�Ÿw|1Ò¤ŽÐafbp‘9ý¶£íMUvü>Ž?)Ô(%Íq¡˜¹m"f!r9n~ë3½áò¡+_[®œÙúÑ÷GOþ�ýSGÑ š8QŠ™¤MÊ,Ò¥J3Ë�¥D,u¯xÓënûèÏ_ö–7ö³ì›Å`]8òY@sM ´!×b HÚýQ¯ÆvÕt»ÃQ{~&H1Ve#–¼SA€�ë3FÊÓá"ž©ñg#4 V¨ E,Ëj4 ÕHG…‹b [R–øþµçž–¥ÙTsS B9§Ì Š–,ýc÷ûášC É"…IæÁ‚µ©0ã‹§à«ß=ý‘Ÿ½æš½ bkU&ÁJWmm«ÚÊ*ñâsúÜà’ÖžÅ)žTÒy "G Ä©Ï(^è)ÌÀ t©BÒ‘ô<²i š0¾&ìÜQ¢½ýO[ �m3v{‰,ÎürÌ&©�;Q¦€š°"#´`5´íåbõ¸m­K‰]p¡âÞïÛ÷¯å/¿#[rD{%uÈØíQL-6�…¬œëçîÔ¯ÿòeÿÅ'®Ïy6 ˆ‘””rˆMÊ/õóùÍÏøß©ŠßÝvÿÚ›5ªÀ–¡âò©¥o~ó¡(¾ó89i%½¸°üK–6b>ÆÍt᩵ì’ù@«ÕR1V×jÆ98 /P¦¤þOøïÖbê¯ê �0QäÑ"1ÌÍ(sʼbW2ôu¯»bsxìÏþ¤\y„‰¹(Ý*¹Re�©9õ�#Ù~ººãÏ7¾{ÔßÐÁ ­/R©È�:3£º ¨¥‰�Žê”Á £™våÂ^ýÆ_ùÙËÞuË`¡wÉ�ªd®ôÎè$ZCf+R"½‚‘©A†F›Úš§ö¾9 :NW4Õùy³Äž‘±Û€víŠ;׺©H>pT+¢CnUÅv,ú CV#†2ÆX©™© •.'v£MÓYÆ"ÃŒK(Z/¡NJh¤ä4zÓ¬,¬?|ä�ꩇz:4¸Œ¡éL))Â\ïû?Úþò7Ö¯þÙ+ÌÊh¥�(Â�ES€Îp±±¤íØ‘£UV5ÙíI ´BJ—�^LOz‘™‹xˆ£8—Áåt¹ø.ÄC)0Õ¸d%³±hÐ$^—Š5ÎJë%ÑÙ{ãn‘t‹†8õ›æã¼Õ¨´€Ô¬‚�,‰¡ÐÁ†®žÔ�UWŒ$ ÝáÓ›>ÿµõßùôŸpUçeõDi¦¡Q4�u=¹æ¾ O}ì#×ýwÿì†ý §B5pž�Vµs2qlïþ­ zê6Ïç9×Îñ\¶¯Aɤ�l´P Ý¿¿õèã#uóª 8ö“±\ÍðS!ÞóÁô[ØâÔµRÇÍ7žG�YÖëլąXðéG†w}Ý6Nb@�µ¤3D¹{'#‚—QÌÿß<|ýe×½ýæ£ê(»Ñ�5oòî­qÿlìð�ãÉ Y³pP/äT ¡€*� ÕÁjbâÄ ˆt G…˜edtæ*ˆ‘ŠÑQœ8Oñê(ÅC¼¸œâAçà|R—CÍ&ä$½ë{4Jåx?�hWPe)ªƒº´L¢1LTDe踉bÝV7tmËF›.Ëq{¶«}ûÃÞ¿ù³Õ¯Ü7u¿u:fF•WŠ£g &t%z�ÿÚ/_ú?ü‹×ì®°,=�‹IÒN!M7‹É6Óv v‡°¨»o³RáSI…]s*Ó»aíJY‚ö¬áBGsEéàcæ·­X[ü›¯ŸZ.ÆÕÈ´åLE‰ÙX/òçÕ¢õ<íÇK$Va”hÕöúýß¿à­oXó ±Ç×±6(Æ.¶»ƒ2ã‹™3q+­×TvÊ’Ö;MÃä0@µcêÌŽ¦Â[«¢“ÍKoy«Çüé/~YN<áGÁMÀ¼4?&·YJ2«™‰&Nn‘J£ˆÑ©£y/�KÜø¾w^ùÞwØ%GŽ{lCº\àXW¥¢~È@¤¢€´mÖ¹§æ¾"ZžÐx ï`õ·Ð55³qßL­ãÉ´Ô±„Ž''½/Ê”¥�a8ŒýMõ �r>«˜)¢YT$Tˆú±!Ä&lÈ”c›d›§ÞëIe¸šW’.–yÄÜÖŽÝ¿v×Wõ釩E]hf�é;×[D‰™…î“Ïøÿé_=ÿùåo½ùFuOy³TC I¼Ô`±fÐËØíH<ü±£sN¼ˆsη€£/À¹Èœ ©+Ç�($uï `0+(êPJµ®[§Ã꺭[;�<ЇÞÑû[úÔçV?÷µ•“ý…‘Ì©ëB3š€jl"™î ¸,"÷g~íc—ýŸþ›[÷ͯrTHªä˜tˆk‰-ïxýŒTð¹rÏ5ìl«S÷KÁÃLÌœUaË?õôÜßÞû¬úË-Œ‹2vy ç߆ë<ÆKc<:‹Åöã\ðØãó¯¾q½+¢ÒÒ˜î?ÓfïB…¶ 2Ã.Lè'Í1ï*cü?E%ÉB7)b­3§JBu–#tJÙþ‡ÿé�þÔÞ÷¿ûòK�övÖrŸf`¬â”zò¾Çúg¶lżD“ ¦M>.,UC&ºÿ¦µvÜ­ÀLr-Fq°¦ƒ3V¬C‡À(xC­œñ¼Fâ¦ÙÒ¬*™=¶yð·ÿxãÏþÓú¡½ºÿ ÎÍyç3B'ÇEH”Ôq¨ž¾ Œ ƒ‰c@Šm™Ó¹ (à4T%ÊÑbæo¸æ¢Ûß~àuoØsàÂýY×Q󉵺JºwÁÄìÔMöŒšØBé²]p°CQ{÷u8+ÄnþoÒCÚ@B=“ R‘¬ •…ŽÖÃÚºllq4tªÝÊ:±¾ôWßîüÑgŸ¸÷X¶å.©ºf(|èJ5O”& ä€KMÛÌ©ÙÖ5Wmÿ·ÿä5?ÿþ‹º\Á¨¬›©¦­¿–/ð}ØŸëa?7»éyŽiè‰ZOykóo²j(¥…�òÄ™¹ÏíØÐ/i,¡sôÎvý/žû�ÖìŠUͤ‰Q•†Êépý�ì¹õøÜW®ÞqR€=f„·÷ÿ¶HYl6‚�3u~9€Ô÷kŠoÞÞ*—šmFwâè DŽ"Qlâ‰Áú†•\„ ]ùØð™ïÆGïÅöò®ñ‹©#�†óC1˜ÐÄk×sq~ÿë^sñ»ß¶çõ×oìÉ7:90u¤y*ë>-NS]Õ„´Tcc)–oúmS9Ž�uÆÚ1õ@ÛyßÚÑäd—sh8nqJŒYŒÍŸ¶ B+±p0që»ß¶wqþ 'DË£9'ÊD•…J#k-¾dfu™Å$…Zg˜Çtæö\MH2ÓÍèLJì—�+=Ž’'k0J b#X�b;n¬‡Í + § !Û;ˆGïþaöÉ?;õÕ;Ž/÷ö{ pâ+ÍB.–› º¡J‰¦HÍ|œZ˜[ýÀû/ûÿü­—Þv£2«8”�$’ÐPjåÔ Fغññ^<+Ax޽çþ|ºÎ8IÞΔŒõšÐZ|*¡Ù¨Œ[îÌÊá?ûòã#;$Á;‹š•j?9)¶öxÉ €2äÁQ³"× …ÅáÚýß»ø¦7gG/ lª@I¥¢©æY P-t^ϱ=vžoZ'=Vi¯+Ÿ™�ŒÞ©³‘m­ «£8T/¹Æ <ûù�{â>)N† K ß�E;uÎ4 àM(¾ò¾Êöä‹×]}ѻ߽ÿ曆ûç×z®pâ™u³(!%[Ç’ �*£µ°°IØbc­üdo&PÚ¤åð΀g—iOlJåÆìþQE ùŸ%­ýÚ|§vW}`›Õ)+„]¶tõ?ýp÷Õßñ¯¿ìiDº*fIØßÕÍaÏÍw˜¢‰Ò¢«"¨t)aJ4ÛåùùO©h:wê @‚º‘¹¨€‘³ÏU·Œße}¥ö?©§[¿ …pñà¾ø�åõ¿þ‘ëŽ^°‘»ûi%¢ÔUæj�ð:¿Ü 05ÖÑ¢f¦Thz=´…Ô�Ÿ-ëŒÏŒý}<—32lôõé˜zˆÆTˆ Q Tø¶jkk6z�ÑïáðƒOîýý?_ùüW×O®ïG§º#²°ØU˃÷di¬@#r¡¨5]Ì‘å+¯,ÿËß|Û/¾÷’¥¹uVÑ®0‰/ÌA×$ªb‹)/»íþ:}�—±Ã`´óg >6™ôi~  ‘bÐ7GqtáWÿ6Üý0é÷äC»£±õà½îÈBIŒ“äø×=¡Z“ÚÚ¹ZÉ�v§¤çœµ÷ä±ë;öpkoW'Ý7°ÌÍ¡’þF1ZV›Ee.X±|">y�»§·þxn›‡Êw ôœ4«Û–GBiNÕ�J‰NžîÜ5—]òS·ï»åõG.8‘$¢ŸIv†#"HLÈoÓI²F¯Ð0W'^¿My¦“Ý߀qrøì9™šçÉχj¢“:©ž›2“Huõ§t{B4Ó£ðqÙÇÊU…“Ë?pË;z�oüo¿»õУªZÅ…1uOSÙ}kš÷Q}*s IvQb-¨«r{A‚¯"æ,£`1jdÆwÙëÛÂÈS'Ò¦P8µå!œÐW/=²ù?ü×?ÿ�w]¼”ϹNDCðÄPõ »Òþbi6šÂíÄ£œ8B�ûß$è[[Û?=‡S<¾ÿñËÆÐ?MÁ`Œ”a-ö·ÃÊšlo»ªB ±§ràÑã‡>÷׃O}ñÑ-/ùáÐ% ³JÍ\ *7€/Àè¢cÌ�]X&¢ÐA×o½ëí‡ÿÙ¿¸í¦ëãÂè <²!²- z 'ŸZÈÏøvkðô�i—VpG•2†P“hV ú£¸-ÇOÍýÑçžèÁ¤]¤(ú/øE>Ïñ€õ»«mÌP¹²’h£wÎéhmýž¯ìyíëzûÅ }�Ñw*Yù„M8+õÿ$�m|Ú¦¹"[Çì­ë‰>KbÛš$ÁÚÚ­1%jÀñï*úuÛX F�Øí©Ê™ÇË'﫞¾_V�ù04„‚9@‹B êT„s‹YTŠŒE$�yp¾˜ïu¯¼üè{n_zËÂ…N梖ÓD�hâ…qîŠÚ‚°La‰ÂIª¯æíL'6šiœÆ&r©»#§»(×0y¥“ó[‹d•„ü›†î5!)Ò‚h¥Wy7`9¤­T䨼üí7ß”áîÿÛ¿’¯ÄGÕµUÒ1»wkËBkºõq»’$sAÎÜýws»R¿‘pÇz3–ö™g]Ñ®?S�‡ ŸY×?ú³¯yß›÷aýšI6PÙ%!´jVòjºdmÇšßõÙÄݤ)Ú©ÞÆظŒðdrNU!%eȸmÛº¾6‡®,EBtd~àôÖ%_úÿä³'î}ÈÖt¯ù^Íá22µqdp¬ŒÑ@³\5'½± ¢Û‹ «ïïÁÿê·ÞyÓµÝLOKU |ªldÆ »jubùvÎÉÎÅp^Ÿ?÷ÁS’¶#Р@,�®Ñˆ(Yú°±£|ÿ‘îgÿú© —Zìzƒ!¨T³—¦wåK'wÖkMŠÁß:tÝkpáeN½G¨|0³(ªg«þpú<Ó�iÇ_0kˆž“2HéIÖ®rJÙ§Ø[—¥8X^öÑ?]T+šÅ¬k…­?]<ñÝê‰;ÝÚ±¹¸ «ÔP8WC�¦ÉáRª˜ùX…ºjRˆÌ|§tY~Ñûßñ¦Ã·Ý"—^´Þ͆ND¼WˆÖ<˜ 1@MÝ]ûh\í•n½õNìvpK`ÊýŸ=fVwk}6@=ÁRóDÛ¶!5ѵ¤óêL 1¸XºÁ†{ðÉõ�+ÜÑoë\þ�­=˜Å:Ÿnóò©äWÅÔ¨5R·vé…ß{ßEÝá÷«þ‰lïAb.Õ~ÓPÜ9é˜õØþ|—¿ ê¬ÇÚ2 ãµE·–¤cBØi ”"PÆÑzØ\áêv¾�NôU7 ù…Å‘¯|køGŸ;uÇ}؉\R˜¥Þz~|…2�J–‚Ôø‡TXìäÃ7\‹ßúÍw¼ç§ö,Î�’rè,wÌuÃXNdç�î‚õ¿@cVíØ˨-þÜ JÆ"XG%½EW2žÄ!ת¥û™ãOœÞå1: ÉŠ“8ï%/Y0z×üYz 8þèêw¾9÷Á£Ý,N͈*Õ»œ½ Í¦_˜fç› Ÿí‘ö¥vÈ<æÐÕèê¤gƒ0ëZ€eå0Û^‰aµô#ëFríÙøÔ·FOÿkOfåj†‘šEß© Š’iÚ"ª‰Î.ñ†Ì$w‡î¿í {ß}k¼æÊõ¬cF2s 5”Ñb®ÐrªÕˆK-×?¹û©Ù3sžcMÙ$åQOÿsŽYÇØ¤içø4;Ü)¢G ¤2Â*o�èÊmÝ^sìyâØ¨Üßí^qýöcÇ\¨Ô%úáKön¼0ƒP Va‚yl½æÚî‘¥gÝè ÏQ™Ú^“¹(V£µ"ðÎinC4“¨w²9žuüŒm±ñíÇgh�$xcêbÁTLÚQ¡Àh…[§msèN ˜vÝ:.»ãÎù?üôê7¾—‹ý¡“kÇ•¤SeÃßJ*$ –)ÄàA!Fާ®º¿úÑ7|ìƒG�® Ë¾(½å„# È$£­-•·×ü"ìþç š  ¶úQ·/C'ÉêÌ•Q˜U†�5n—Æ+¾üu|ùž­¾?R/¦¤�•ÑÁ<í¥qtü˜Ïü"ñLg÷˜$vk‚a.nm|ÿÎïy£»æU¥g':…¯¹’õ£Pm~qz5·Ÿ×YA]Ðk6¾Ûñ>š¾&ɆÚO¥ƒ0Y¹©ƒ•èú²¯r~ûÙÁ‰û¶¿ËŸ¾/¯ š-ØQÂLsfb&©SŠ "qf†Œì»ùÆ}ï| ¯¿r°Ð ì8äLúÀ@MU(65øËúÿ[;í�¢M…'f§ ±�3Ô¦eLšxcZñdÆ«Á6Õ~¢qÜO‡Kzi4Q‘A-ºRºQÖ—C8�N¨ôÔFÙ]8 Ò!¶´ÎfÛ+Ψj£@ Q QA…ÃèšKôüI„-³Ë´ê³·¤%\]4œ^ˆv=�M3ÚÍZf·ý®Íš·q[çL@Ô D¤U� Z us«Ë2ìçQA_e ¼èÇðÉ¿Øú«¯?{fópå.¬º¦2 •Ðø‰éO™jUƒó‰ê,qóÈ�чîU¿öñ˯»ºÈâÃ.ä^÷ˆu‰AtÍ-+êrÂqâ  Sþøùbâ»cýMéÖÙóYÛ†›´yL@¢ Ö²ÂæÅ £m—ØÜRë;¾øï>ub¥|³\~òög¼Oà3%è×žÙøö_8zh}n47àµèÊôSitvŒ`Æhêj^ì<iª4Š9o’Ãi…ÁVl(‡˜+ÐÝXÖ§¸õÄ·Êå»óxF¢(³J2…U¬Êl(ˆ† 1ƒA�*b>3x"çÒÂÞ›_sè]oë½úêþžÞªS¿·ôGGŽ xcèÌ‚£NÝÙò1ÎfsLq¡S-˜ÍÀóŸ¼=�°¦9Û¤ Í»žl*•<ÍÍIø;ë’±Äé1+£�âœur•°n[Otè*ÐÔk•Å$:¥¾D¾Ñßy˜�MJŘƒxp!W ÛšÀÅ0¬¶Nwæçç�¢PItkQÛÒäÚŒüóîb)3’™DÃiÓ&¨뉫ŠÔ´=VV bk´µÆÑ «‘*àR)?xüà|yó3³üÌrÇÜE±×�ZªeŒsÎ*"DŽ»±ÞO•â1[Þ¿´úÎÛÿã�¿ãÖ×ííùã.œ�E1/æ‰�Öƒv!Û¨»�ÚÔâ÷ÇÝ4gÈ)9ô�¢oí®S9çÚÜ&â?c*Èpe4 «ýjèûvôwÿôä}ÇöVù‚bD`½oRš‘Ñ'Œð'?^:¨^&;�…À¶û{ïw¯Ø÷ÆŸ9“åÑÑ—C Oø §Œa7HœÓ Jê—aœB=«�“© �ƒdæ¤Äp³¬–:Ô®A†«úì#k�~WO=ä‹“]Ûc!Y$�(HªkZ7¤MÍLÕçê¼Ì홿úÕGÞ{{ö¦¶æúp„xš £3³¨€ZʧšÁô¬×}¼]kÙjWG�o˜ÍîŒ+(Κ|kT6Z篃×&ÌJ�‡Y£Eµ»1Ñq/«û¦±y,hžp�HÛ�)$Ó˜y•b-œyx«Zó;êƒò ®Œ° .ÂÑ1ðùp½¼FÐ6/¬5Š™@�0""Ë .ŒlëDpšºy&@§ÉŸ´Ûr¶ðå³å×Ïw²[YãTDX Dh´²ÐÍõ°±nÅ(Suš™ï•½Ožºè?~±üã/�xl¹7äQÉ‹*Hâ%2£3iü¹ºG·:G°ßÉŸyë[üã_}×Ûß´´·Ówq…À= ~”@YkÄpÔÁíØýÇãï¶ûŸê±NÍ.¿ØJüZËõJÀÔàK K,o` …^þç_™ûã¿:Þ÷«fNK"¼Š‡Œ$ªØ˜nð“µøI7ž‚nˆ†Bh5¬œþÚ_=p]÷U7p¹ú*IPÚ¸í[«ðéì‘¶úÉþÏ1a�쳘 i%hõÌ$ør[GË}]/sËd4ðÇÐâ»áôRÏtaÁyµŒ:ôVPŠ�ÌK΃",D#E"�fÞzs W]uñÛnã[Þ\î]\§D—kRs×è‚õ3ƒÁĩ¢b¥ÀH™b}pÜï^§Š�u×S ÷iZgNQóÓ‹Â0ÙëÍšúèe®u9Ù Œ% › �Œ6ëä_ÕW#,Ÿ�ã†Iå „3WŬÙÖ4⥩‹|�F#“™’ÌUMCtý¾B�À;-2h(7NWfÙ¾ýÌ:�EÐ7ÓØ¨^êF–<ûYÌHÏú°.ªiÀŠa°ªR·úåú:†}£7Â:A.;¾rø [|ò Çï{Z¶G³.Ì«’–Q…Ñm+a6o6GëQ³Ã¬$úÞ7ܰÿ×?ñú¼÷šƒ½*›>T4FV&Bvȑɀ¦¦Þ æ†`aêÙj.6}_¶Û;0ûg›á3¶¨œx4m÷ß��§ñî�DˆB«­p&f[‘Ö}à‰ùßþÃ3«åÑR Ñ�™AÍ pV·N{i¼?+£8Ó̲º30¸¶nãnõJ‚i­dé‚÷ÆòÌ3+ßþì¡ Ëýõýœ`è5²H„J¥™©÷�PŠ3P(Rûò*˜1&E1ª¡åB·yú“ÝßZe?g=2™Ô_M?ÉÝçgêžE–ÚUŠÄfœ§®VM6·ý¦šKW¤æŒ. âa[«Õ`#ÚÔ. sÁ¨¢^lÈÑÊ`í#ò*§iå"vWì?~ôy®Û™:ò³ÖyŽk¶i3�*F?RW–¡ûÄñAý,#@¨x£ [®d]¯ó‡™/Ðç�ðÆ ð ±¦nY-IÕ´Ih%‡§.µXmzău/{€j’%­*âæÖ†¨¯FâTÑQøLÿÀîéýáŸûÁ#Ü,÷WYWE �9…ƒDc!4Aõ’ÞvjÁ2“̤rnõºkø«½éCï»êŠëN�K©©…fêQ Ø›¾r‘ÐÔ1eÂbšòyj^t;ãÔF’Ï~0;žwù°µà¥.*N1ð˜4˜Þ¼ñß�áG¯SP*½láôÈ­,˜.œˆþ_râ¾Õƒ&K�8*QF&E� ˆÞ AÂLgöE.~ Y@»74ˆš K1cµñÈ;ßùÆþ÷|hÈ9ЧZ£zo1Å׺Ã#nŸ¾.‘ož¸•N9§‚ʇ*¯„–G.©GŸÃµl´^fe5_ ¸úDÿ‰»FÏÜcÃÓ>Œ$ijjÝ¡<ýñŠY4¨™7ffª¬*2ºŽ-ôò«¯8tûm‹¯}�8Ü—Ì�›ÅLÓä²NõÚ8Q�úÍ6î¶åÖ}qw ùÏ íþñÄö¶Ý­G´ã‚Ø\·É™z‘|ªu®,,ú¶´ØÖ²ba¢§z°FÅÚ² UÜÜ(—�S e)¥6ª¯¸$ÀÀWsÁ¢ˆf¢Q錽{î{ö±“õ®®ªj˜ÁFͶè,C_¬_*¼äž�²Ô̲Çe‡qtÑ<ƒYÏwÜÕš´¦NÐàÔ"i À€aåhcÛ†ky0½£3^°/ùæÝþ“þÄ·ïÛÚ*öV¸ ¸ƒ%Mi0Í!%¤Ô,§¹´ç£ñÄÑ «_ü¹WÿÚG^{ù…£§³0¨…K9f$Ø$Ögä¬Ûõìžóø;;ûãpwwèÌšÎn â?.¼›Fœ0]a@I‚ÛÖêt%}ƒôõÚßþýíoÞ5'ЎɸkÒ$w}>:…/ðx À.CÌœ¢U¯ÔÊ�¶—ïøÖ…>øº›×݂‘ˆ>šCê—ÄX�‰rÜU,-}œy$í?F:E^ú¸R�N2ìì)‡X?6|òžòÄ÷±ýTŽ Z-W:«¨�#6åø4AM¨ôzÙ¥Wºí–…Ûn\xð¤ËÌ|'ú<2º¦ÃÃÔ¨CLöÕVæo,ê55’¦ÿ¸È© ÍDðf¬­¶ÖûèÝ܃ñì*ŒÄÛÒ‰8ö¸¶€ †Õh£ ›¦ƒÜú¹TÄœÒ*LÏ[ëbp�ŽŠÇ·�3�~åpê ™½ …hP�…ê¼³\T©Ö{fyéßæÔÿù¿Þ»Ï‹ÌL£Z4FçÍSF55-É`ž¾+�ô„¤dYÍ09—ÐÈ'šQ�õ¿5:A_Ü&«-Û.ÃZûÁÉÈ ÝÞvyô{ïûwŸ9õ•{†Ëƒ9ǃƵ®B U¢]ˆ¬„VMÄêa…t!êé ü™+?þK×ßx•ïÉqW EƒÔª€hÑÞÇ[-ž¯Žÿ�³v�IëäǤwçYÉÞ�¿;†R &�ˆDM4pô½šPž*±ÁˆlÔYüÃ/ ?ùôêÜ[,ÈO¸áãs�——0¤^y*j>Ú¨Ú:}úÿéâ½ó —½aÛ¹DÓUÔ�Ø1ž[ƒ RI•PÖ� ËQ§ºNìȨ7CÿôÀšW¡³öÈðéû‡Ï|Ÿ›Oeºå5YDf®2ÄÊXX�f,œˆ€P�,+ærwÑþ½o}óÒ­ï�ÃGú¹Щ $+!QàÒ 6 bÓešä8£¦­½)·91ÓEÐçBÎ8|f^m—Ïë2S¯Ë„MÄ,ËÝBn‚Ѝ¢‹4fÚ�°h¢t)mæbg¸¦�þ ¼ÿ{~´eE‰°Üé¢|%Ž&-âaÞ¥š`‰Ûó_]¾òpç7?|ãbïI ' s‹ T&â( á$¿ �½ÒY`· �!2A›5‚³6E›t „‘P…u�ƒSquë"Cç¤vdÛÞsÌÿ‡¿\þÒ·×O­ìq%hêK�Hkä¹ÝT"ƒuM�x�º1×Ûzçí½ßú�w¾éƽ‹Ù©,¬¹h°ež‚¡ÙýÀ³lw|µÛ¤þØ�c ¤ÎŽf_^»“,´Ó’"ãöVµRø�H˜¸‹¾ø ù_~ÿô™x•a…9¯•Õ9¯ñ¼ Àl.{4}ËÆBéç?Œ¨œ!¯Œ+)•}=þ£“õ…}º`î𑾋éXW+Âéî�t–§f0%Ì)2xÂÌU Þ¶mpzd›E7”Ö_)Ÿ}pôÄ·âúã™måØ�Ñ:�ó‘ΰA¡¤èµ¼7 .ŽèÂÍg=øæ×e︹¸òèš[ ‰‡Ë*z0ŠD!f2véN !´V²zB©ßÑœ½%ZW××Oåys5‡OÏ�¶HægÉi<ÏõÀi¶áØ£J¯\—Yƹ9ê^×ËþJá¶ó>šh¨j¨JÛ^µÇî.ïýÛlùÉŽ §Ñ办™·$AüÊ„˜åfy” (i•9«¨kå�óÉ3ë§Võ/½âè|'*¨T�/± h£N®ë]Þ3?锩^’ ’d-À13Wg€Š�H  Â*‹kº±eë�Ü%i ›/1ÿðñßùRñ§ÓÿÑÊÁQÞA×| 4¯Xª¯Œ�ÍÑ<ÕEMêþíØÈ;+7¿iï¯üÚ;ßwËžCó¥”Ofeß!‚™z‹‘©±t{c�,¼:þvÞý̲篿ík± 1ÙYçI �Úù•æÚ¨uX�!¨ "8ÝÔ¸Zù‘IåTö}ûÞ¹õ;Ï>»u´Ì…eåÍG«âl>ÅK5ˆÅwìþE»ñó1Öt)z~`W‘8#LÔGÍ£PzÅ 2È|÷¦Ûÿô×öíÝÎz°\"#ME]l:HN_™AU `E—�\½�´~ÜX•Ãà«2®†gï/žøž®<ÉbÃa”a$6T³ y`Ï舑³(*b]DjZNg!öºîèE‹o¼õà›nu—\²ÞíÝ 26KýKAF1s"YÏdb ìšÏl'{§…Ìvï‹0›+ɦAÕÔ.ß–Yžþj÷óÈ”Ø_k=´’umÁ¸´=9‹NM¢¹HQJßÂOnÞÿ¨mm95Ä2Vƒr´WNóÌ3~¸ÙÕÂâ rZŠSéBIV»G/YxÆi¦’ÀíÒt¡vÉ!¥Oä&Ñ\Ë:ó¶|ùáþkoì9Úíäæc§êGÁèèÅù›oY¸êš=â·£”êD\ž«'„dE$%%Ý 7Y%Š(4ÔåT±D9 ƒMÝZå g9gˆê5ºC'–/ú‹¿Yý÷_9~ì©E‹Wëżü¶"3í ㈠4'6GÍÓ (:`Elt³õ®Ÿÿµ_{Ý»ßwÁÁ}[{†Ã,F%#T4:UXV‹»Z‹Ï:½ËO×÷ò|mÀ 7kàìÄúg|µz ›�Õ‡(p@ú*"©–j&\�ÅÊÐÖ¶³JcÙE~ù·~ÿåÿïÌ}Ï\¸•Ï«S)s§!º2pv–wwîÛz¡øp­õÜØßdŽ^@0î�÷ã„Zã܈Rà@‰ôæ÷î¹å¶Þ{~z}ñHÄœW(ª(æÇûã¤SXr2DM‚£åæ;1G_G+EX‹FRž©N?T3ÂåFïMê¾D 2Q4‡Ý„4“ˆÔ­Pu{3ö·ãpä*Oíæ‚ì95Üû¥»ô“Ÿ]ýÁc½M.ÂgŒê(°¤”¨hF–D e¢ó0)ÀÂq+7¼Êÿò‡oøà{¯¹øPð8å±�#§Œ 6ÿ* L­ï€)¿)9[Ýá¼vI`–HmåvÛèg€$•<ýtyMˆú¦Ì* Òýa¹º¥Û£¬R„¹B®ýê‹ÿò·ï{èøEÑï¥j °TҬǒvÏy[/²xAs€š øD3Æ. `i¶{³Šë‹Ÿ^:Ï1~Ü-Ævüú®l·V`ünÔi.‚ŒÁLa�Ðjs[N�dXyS�T<ø7w–ÿ×ß{àûg.E¶ºá,7õÊ È¡9ëÖ�/£õL,¼5`ÁYžþ,%ȳ£�çµ-|»Ç/MÇèGêùlhÞ`~¡ê˜{ó»ßöÞí…C¥æÎD$T¢Q° p05SJtšùÐ�ë¡XÞvýa'”Å©'ⱯUgŽ¡è‹J2*¢Ñ ª¤1u>ÒAÁ¼ª«/èv°÷Àž×\¿÷Ö7w¯Õ`ïRIIdæäË'(D¦;j#DoS÷>þ°éôWÏÞø@’»C.¶³5ìs9þc©¶*� ðŒ›+®óec›•B�Z±$u(ôiÊVü¡‰\aðIÌÌÌD¤.P&Ì4+É*ìŸGuï]OüîïéS'D "ÔH3¥‘ºBvWÇ|ÑuÒgŽóŒ XK F€ŒY-û fä6m�Ì:sOüÖÇ®þg½òðÂ-[oyæ(( 3ˆJlÀ¼TpΚүUê1Ó“³ÅVˆ[q¸]llØ`ä+ó•2Jo=\p×CÝ?øâÖ—ïgÊ}Ñ÷‘3g©•BQ¸H‰âL¢hðitº~h©úù¾ú7>|Á ×íƒmg‰•©¯`�jÚÙdÓÑìl(ïi+›Ò>š™Q=³Ç»�¿›Æô1ÍznêYjþl’.42ÔMДð•ú�º Jª®ôuµÏà F×Ý]ø¹¿áÿç“«�l\ÒÏÍ"¬bRùO*”à4‡ãy�ŸPÀ—‡Qs"Ç¢OÍëœX›Ñ›ƒï|ÑßöS *—u´$L)€@!jŽ&_åÕPú+}Ý,ºå0[}bôÄÝųXÿ”PaQR7RŒ÷ï”ÚR¯š"bÌi^²0]–÷\ý¡ÛoË®õÖâžïU…˜&Õj’­ ÚØ^lÓzãâ»)6æø``‡ç~®dïîu|Ss:Ú�Èg߆^'G&*5ƒµU' Œ»%§›Ôí…ÍR  M©¤!Ï3/~µ?¼ôÆ7.þJõýßù]]^fƒn5f­.‡{s@Ó$ÕmàêÈ fÌy;îä¯þ¡ÿã'.ž:®ºÌ(Žt0ifÛˆ8&j¬›E€µ—d(AXÂFúq0Œë%!/�hHå– ä�”ÿñóÛõ­õãƒÃ}°ÊÌ0ò�.:c¡ Í2*ij*U &ŒÕÞîà=ï<úŸ¸þ 7u°*á´ÐæRPe‡ µ5j³´ŒfîÜ»ܦåìünÆIÚÚA­ßm*Ú˜Oë©©¥D" •f#3Aô.íjykôå‚ÑBεâÂßûLõ{:<9¸¸Ê;ºúê[/{ÏñÇ>ýI /Ç×ãÅT0*3Zÿ�o™û¿váRõ•L¢tæÅy$ohV§¤«¤Ùji ¢¤Ù$DT…ö×b# ‚/é«C>¯òù‡Î,ýÁ—«ÏþõÆñå½Á.�nAa1…榹H$£Acr�Ü(ê3áúBgõmo:ø�~éö·ßzpaþYÁS¢¡§˜˜J‘NjPç§Ï3s9?/�ò©¡Ïã[«'@ã©Lý߸ãZÒŒ‘h‚`K§N5©-tµÀÞ~=òìÉ}ÿï?9ó©¯ê¦]:^µÍ’¿dS�â^Žã…4ϧ ï�7’‡ÅÌ�|,Ü ôïøj(¶{o}×èàµQ\¦UÏb/:-¸¾5 ‚ ó�x懣'ïáÆ™mF J#J6­Æ¢–€ƒ“@Z¤�ìZ¾�_rù¾·¿{é ¯­.žÌÝÈ á³Ê;Eœêà6vŠ1‘[œƒ]WÁD iâh?�ÄûîŸÛ¬FRã_0}Ì.Í`@JÀî8? Zªôds(˜*bƉem„µ!¹hÖ‡ £SV¢¥waà6žÕûWÊ«o¸µw×7‡Çk,Óß9•ôJPâââʯüâk.ôøíG±p ÊœL¢°fÕâ…u fŒ`¬Åúi¤2+Øzß6·m8’è;&fTdš/=uzï¾9ú£¿:uÿ©¥¾\b3�Ä€¨œ•0c$€y³hŒ¢„МF͸òÚÜù�oÿ;öœ[sñAj€‚¢”ÊL åD öí΂nÎË5>oü¼íÚ·wL)Í5[�ŒÐ š&ÀH3_ ûýxfS6¢+sá\…0rsß¾·û¿ý‡ãßy´·ÑÙ_åjÑ÷À`VY»Fæå:þN`÷ÿücö³dWÇgjå€È¨.˜hVÆÎåÝß±þhñv/‡/-|·Š®Ü¬âÚº+úÝíåxâ¡áÓØÊ“Ýjµ££H-˜+V&§5‰\¦UŪ¬",ƒ÷ȪlÞ]vÅÂmoÉßðúxáŧ��€A$ÀÃIsQNÍT373Œw9‹99¤†DjÊ|}çm:Íl™’ÜKYO)×Bf´”³I/Ùé†zØÅ¨$éžI09¥™E’¦ ;„uc𱫦03¥Ð,‚’XaNœZׇˆY®y)7¢ë÷ŠíêÔ¾Îܵ7 Ÿ|¡¬…—]½ä�?ZÅG�‰î!žØzÕUÅ�W­ûíg;±,UŠhÓÿ“�'.F31sf�‘ÎB’’²Òí�®m±?B11z£/ò=§6÷åùƒ?[ÿá±=ÛvUÈ�nVÏh4‚™Šš¯Ô«iêÍ<ÚÜ‚­_}ÕÜÇùª膋»z2+„™ˆy'hfÐFøn¼™Î‚bfìþöÜÃd=L«‘L¯“6«ãŸ«ÔÞýu|PKuüdˆ"TÐ 0FÕ¢°õmÛº"2B½rðøÖ‘?ùòòï~~åäêþà*ƒÂ2D3C#ùÀ)ÃørS¶}e@@‹ŒF É,‹e§ØŒ÷ßµ=X;xÛÏè‘׬ng6ˆs›Ëîø½Å“wÅõ‡F„¯È躰ˆ¨žÁ$é`I$…0A¯^}Vuz¸ðÒƒoºuþM7¯_røÌB7 ™�£S, JgF8LÄzÚ½µ#‘^}Ž>?;Íéžçœ2 ¾•¦G ¼SA2!±àjYÐÑL¼: æ0n4Û¤‡™p …ƒt5�,×­WyFÛ\¥Ûs…tæ«—v™ýÄFê>êÂè ×ìÛ›Ÿt[%ãb™ms¡gJâ÷kcFµ5ŠJâw#qs¨ý¾A ®’<æû×Ë…¯ßÿä/–¿}ïžÕêêØu� g…‹ŽÕ"-'¼ALÔl �#s%¥Ç˜{DÑ•£õîg¯ûå_¼áúË7]|$·àŒ‚ŽÑ¬€0‘¦­m@ËÑÞí¦gGç3uö|γÛÏíÝêj§3Ìh�a0•qkP­¤¯ŽfªÛÛŽ—|ëûK¿÷é•oÿ�§äbËæ}ÑËeh~Y%ªÎÛ+$�}…Z� f®£—ࢳ�GU>õƒÅV级zó«çÂ釲êm=R y '¡Î‚Ô-$Hª„ A¿è/¾dÏ-oÊÞx³]xÑJžo�>Z­m#‘Ä.£åiœóÔ.ˆ�Š Ìr€0 o�gÂê›kƒQóŒ�5­sg¥A#ƒÔœËl—óbbyÒ–=uõôK^9”(·u¸^…�éHYE(��뉟׃Ÿw¾ë%gÌ¢BMÍ¥Îð©-Œ „îfk�ŽÜ¶ÓXuTµèÁ.×3¬[ûÏþýUTy´‹æ]ǶÕU!ëÅØÇö€s@r˜B\ódh0Æà¨tD¨PÝîÛÆ– SïTËÕÚÆß}P~ÿ³�åî¸>XR·ÏºAe‚èP:f=&Œf$2à™›ƒa òìE‡ãûÞqÙÇ~ñö×^?—s9+6½d03PØ`>ÉFMçéÏ›¿ž7V�Ÿæ­Xë_첄¦vL»^cœÍ%bj@oU¶q­Ï~å£HÌ5ï�²#÷=ÑûƒÏ¯~ñ›ÏœÜØý,4J€T`„ Íφ¼^&£¾¶¦ìeBÚ6Â$²b^‰’#˜åÎb(̈ÓÇtë¤d¹ G,F¤UˆQz€ŠÆÜ"ÍŒb"QœšOjV„Î<ÑÉýþ{n¾mï­o)/»t£7WQrÕnU‰†à$8«*F˜Wt¢(�›tÃ=ä™úŸtÌî¡ýùYúl»Áô­é±öŸ™v¿&nÃs³1*�ëo¨Æ�cÿÕ—ÒDäwV º®V±o(CæÕ;M {P"lë@*óËz.[ðn ù¼—ÌA ¨ÛƒÀX¬ýh›'|'äœ1dó¤'Ï_¾Ó�;š[‹±ýY'«`ÑäHe±á:Kû! DaˆP¢b¬Pªöûa³Ï¢t¥y£!˜1`±’‹xbï§¾´þ¹on<»¹XæKê)ˆ1-�Ì£xÇh2R"5w¡—éœ(B¹ºÿ`ÿ=ï¾ð}üº×_Ÿ-úuŽ»HaêUBjU, F@0úq{áÆï�w÷¯ÿØ„Ã@>Ÿ•bÉMJìB l�¬Õ Á „¥š}(¢ê`XnlÆÍ�+ᫌȋÞÁÇOìÿìßTÿñ¯–tºWf‡ªÜhe^åF«ÜJôA9ÇpÐ)ˆ±koç—Ϩ§ÎC‡ò,0{÷Ÿ_ žõ ~«MžS{s4ÐDÉQÖ|\Yƒ”Wˆ•m U4=è(£ Ô1F5“ZHÅ$÷]¸póëçn¾Y¯¸v«Ó+ISø$A@/ÎA…·TÚJ$~2©M>tç¼N¹ñuaÎŽðYcg `<»Œ–•�6Ž?m§Ï«cëÞ£i¤ŠÁL �‰œ™H„ĨÆL»Rd£5,GlƒÁ{Í( ZÈbªp#ÍkåP6´‚ÂÑœæ{‘-Òõ(I„­*>Û-Ó¡KŠS*48*ƒ¢‚¡$)ÙHÄ¿œ_¢Ö˜u�<ë™`ô&.Ƨ\5—�ò\\4'ÈD ][GlÏ{ŸF�Ð`aþmY”>˜Ð™(üÁ'Ö�~ú+ŧþòÉGO. siÈSyŠª¦QšAiÁ©Z$3ñ˜/Kl/-ï{“ûÄÇn{ë-,vÎ0>ëC%ì˜ó©³˜H%CÃõ$¡[êIÿ·éèòùär¦pÏöKÒæ­Û41aü+-ÜÌãŸÐ.*Q„9˜k*Œ„ŠHFpnÀE°gÁa°­k¥nFE¯ÞÐUÁ3«‹Ÿþšÿ�_|òѧò�^òù¥šq˜åTo Œu‰Ï îŸ]×ò.ÒöºL¸±½Ü  Ù&=•Ó´Ëš&ÕI˜v Ä�Zó„æ(Fñ¦y«Ì™·‡öÜôú}·½-^~Åöü|e¾Ù*XÒªYa©{3hÍyÞý‰ÍJ`Î~Žlýð|^˜ö�­„yÓ»bŒð4ë°FФö„R—HÆÄ"4SZjìg GÎE‡,�¢Ûnp2„e“Â+ I2”–ê£AcêâÃD#,5³7Qxc,t°�E:KÍoPZ^øŽdÁ*#MLM} a°­UÙÔtÛßï¬Êý§Ö¥Ê Z¡"Iç*_n´Ê|Æ\ 2+¢BÔŒBz(ÀÉ<½}ÁWî¨þðóÏ|ïñΆ]„|ÎÒ®ÏH(IÀ á,˜*Ì™fqÂ[(æV_{‹ûØÇoxÿ­—Ü£.œð¶%ˆBgt€$<„©„Äf›Ÿrö¹ë�ç;ÚßL}ª�gšCWÿâø_* JKºØõF‘¤) ´g�gK,+Œúºµ6†2TrÓ¹˜í?1<øåï†?úü³÷=KÝ[É�À^Ló�ú~§ 8˜«Ér/{—¥ ¿Ü À 5hp 5°"ÅàÔ\„SAÜ·oñ�¯›ëÛxÅ5›sKÛâ"%Ws ÀBr¢�c©ý”w�dbŸ{—ja4­½zêˆ)m·³ñ÷³O¹û7ídoêd´ãÍH¿©°³˜j4ÍœS'k*ಲ×QqåZÜ:]ØVÌ+çM³8d¬+h4ƒ‰@¼I™‹pÁ«+å“—æLÅ,"U͈Vœ@å2Â’¹Ýg£þé'­a÷þ΢êߺù—Ë…‹zð:ŒÌòž9¢BY+Eꬤ¨PÍkfÌÔh*ûåÑo|½ø·_Ú¸çGa«ÜWå{Mœiôæ 4AŽ&uë 3ƒª� `U‡«7¼&ÿG¿ö†÷¼wï�ý¾z¡r0¡‰HÍr€Ze³�É©1+{ŽãÛ¯@šLSÖÎ>Ï4³sJ5Åß'­u©C!ÀF˜1Ò¬?4õq؋˥ÛX—Ñ0ÓÌбÞÒ™Á�¯·÷{Ÿ[¹óQöõ¯b.DgBc+aM}ßË~Ç?ÇøûiTXˆ‚Ó�«B$ˆWtla±÷ÚW¾í-rÝõ›{ö�Cé¢du‡ô"¯;¡O@qÇhÏ¥R8´ šÖ!;tKÛ¿=ùÍ™dŠûg§ŒsSo;îd×.¥µ6«Ç(• iY8•N¡„,TÌJ-íLakˆ­­°±V¬œ¬ÖŸ�ýM ¡ÑÐIÞq½=nÏQ¿÷ðüÒë-¿PÊ\ey4–&&Œp 5��B²ŽÒ)Œ>JÇK¥Û'G'~€8j.ó哎z±�´2Üó(¿zgçc︠c'¨0tÅ+"æ¨bˆÑÂBB)ºo4ºäúÿ—+ߺ/®ŽŽÄ\ªÎ¾cÇIn ”ÒÁ23ÕD ©ÔKÑwX¿ò |ìïþù\yÅEef§¥ì%)™©CÊǰÇžøÙ|ùdìØý[øþs³‰Ì’rç„q±CÁ?ý M?œh.Až‘�‚(]«ÕA¹¶.ÛÁ‡’ê�G6lé[÷ÆßÿÒæ×îí¯ öÓís!©TJRÙ df¯ì~x…€ç§TJšóš $·Å¥…W]·ï–[ôÆ›‹{û’«fÞ$3+•™�Ó)]YŸœ­¢VÚda¶E¦¯®um“O§4Ùډ߿ÛÓrµS´µ©Õ8h«pÔ&Mâa³±bê4BË�ÎÔYÅÄLGƒÁ™ ;±‚ÇŸ;N>¥[Ë(·- h�HU0“H ðtsÈæ8·”¸8¿àʹÃWaîPåæ’™:3§ …F5jÅ�D˜«2hÏEßÁööñ”ëeºÓ¿÷»z, >®Œþä³·]{í5û†ÎÖ» ÐD4Ë` s•A�Þ¬Sâà#�-}ê‹[ŸùÎð‰ê‚Q¾Çg(¡NËŒì©IÉ‘£fªPzc¦eAWP·.=þg_õ‘�\vÍe1¯NuʘY f¤‡: eã+cIFÀaìrL5g?ÇÝŒ©×t÷÷Ôô¹ Ħ"ã‰Aj„±¡ÀÄwkªtŒ é" Í€lè6°ln3øJÕœæG6ãÜ÷޹?þüÆ_Ýé��.(òœ9%F§Z¹˜ôŽM*h…¤…e¹ÉD³èùè§½ÜÆ+Ò´Ç.òÔ„¤Ü>³à::7ß½úŠ Þþ6¹ñºþžÅ‘Û˜Áà¹*J§Á™Äq“½©B’¦eo#’–YÝþü<žñLšþŒo¦Rä;=ý³pÏúâÆ(m|k¾÷ãKYÝ܆PdjYÐ,¨mnê“?ÚºïÅ£�êòIô7$L•’Dl¨D4ˆXåã†)®\lôÌ}²çÂΡ+æ/¼viÿµÈöV&>˜Å )5ÒÓ¸hÃÁ3w»ƒårRÒûI¯ž—h˜™9ÀÈN÷ž‡V~çÿýoÞxhþ>©FðRˆÆÊ$F¢@™Y¸ð䙋?ÿµêS_:ñ𲌲 Šl5§n‹uÀމ©ƒ¨.©ff[‰æBW8×–÷í/ßyûU¿ù‘×¼þ†=™;éãzÇ‚7!äÍú©5ËP^s˜Ù†×'7ñc5�Õ�k—CžÛÀÔ‚HíÊÞúÉ1 „o4�j¨‚Ëjºü@�ªºÞ@.½ÿéýŸúÒS~×é3«‹.u¶Ô [æVŒŒ2)#-E×8£ðü¤/^vcªÀ,­ÿé†!/î[ú|˜d³®3IûP€Ú›ó—_¹çַ̽öµ£úyè]ì4FoÑ”,œa9ÑØm5ôP¶vÿVMÕ4眣ɹìÒS}Æk”p ×Ü�+:5´¾þ¦ð mȪ¦éM ”¢ Wë•Åž­­ê±Ç–ï¹{ðÀuc•a :J¥©ÐÄAs(šºÿ”!w€y-Ñ`FQffsóÒÛç÷_½pÑ«º‡¯ªæ.¹…H¯jÞ1J‹=-;ÃåÑ3?Xèk²ýÊÕ"ÍõÛ„tžëí%R�yx›Í2Fãh&"ê<Ík1Ï3{ïŸ}ôÀ¥ §Ÿ%¶Å *>r)úý§7ò¯Þ#ŸúÜê=�ö6åpèÀ8bð.Î�S²”RY¼é´ç¤O§`4[Y˜_yçÛŽ|âc¯{Óë÷ïÉÏ8-$*r–„(Rëø&6`Z˜Zg}[w3=».ÅÝèYÞRÍܘ¨ñœ=o3rc6Nð¶y6ÚªV6=�õôh( 5Ú°Ð�AÜ,1Ê…®äàã§÷üé×úŸþ«ÕÇOÏ—~ È}êJO*$2K"Â,`¨æ°Œ3æá|#€]ݶ½n­®ù7³WŒG¡éBQomdê`Ú(îá,óîâ ö¾ñ�{n¹eû£›ùBD–)3KòNQ%Š©W¡ey$%5M=k´)�ƒ?Vr~ó0ëënn/[;8v}ÆG¶ü¡v…ÀØ„´”ãIƒØXnÕA-·˜mo”?zhðÝ;F= «Ë •Ó2Cå¬PÂUìkPÑäJ \N‹D%L½šé „Ë´³$‹—dG¯÷‡¯é,Ê\×Ó$„ÑpíÉá±;ɸÁ‰L+3” ÿwìmÚßcsAéL£˜øÑ\±rès߬>ó•õûžÎ‡nŸdóÝàƒ�J_E/†ŒÑ¹àœ™YFŦ“b¡Û ãHçH'F3§€‰¥Jµ© g¬– � óþƒ3m}jÊ8©)S¾os€ÁÕ4P«‹8j’^ Ž•Y¬„šÏûýî{ýñÖ·úK.)¼::�¸t’æÖˆ•'U­Ý==‹ŠÞÊì:o»Ì��ãϘçYš'mm¶ý}¥©M&Rk�Ô÷ÑRÅ—#„§*4˜:ssým}èÁõocø£±µ¦±¨…Æ 4¯cI†¶Þô“QêlgTñ0mQD Û¼©Ò)sssÒÙ›/ìÍ/9'± 6×Êí5«6¡AAM@”kóÈŸÓ}z¹õ˜yø´ÖMZ*¤(i–zΉEú‹�þ¥¶¯¾láСùªÓ+Ã=1:µÒÄÅ"ËA’¢ê‰ÌLL,8uF‰”ïÕ q1踭_½ð±¿ê§ßyá…ûF™m:zª@R—`ÀHШ`àNMÖ1ªÌxϹÑ?¿ã›µÝfõXkš[!B*à€VñÍ$ù;±y£�f?+-lÅþzÜÆ>]èŠæäžãG¾ô·ƒO}iå{Où¾[ŠÒ“Ø͉}¿òC¥£ö$tóè�™!DfÁª,;}äÀÊO½ùÈÛ®¿ø‘‡Nüþ7†'—™Ùž2.T.WD*š!ˆÕ™Gf3)MJ¨ì®ÆòÙˆH-o&p»ž¨34…ÁêNƒbBç£e‘ð�pðà­·tÞzKuÑÅE¾ŒæDaf&dÝÕÝ8ãìò¹5Bg�öç;’Ï»_ÿó˜’™5;Äòïž“÷­t‚p–ºZ˜ À3¡�ˆ0õe!<¼uçÅ÷Ùê™L Ñ2PUj_ÊR?ÇëL3¯HZ>4%" ÉÞ´5ß“apê§H�ODi°Qí?jÝ5°¼Lð|1µæ&wÿâaRÀV+l’*�¨C±Ò ”y”=—":^êâÒÔ­<¹.¬y^•Je ƒ'*ïW\ÚýÈ/\óózÕ%‡·º8žÅMHj/c±Vóy„ÝéîÓù¼DÜžÏñ“¶‹ò~úßô€[µ�z56¦ í¨DHwaÉ’¬€¡Ô­ «ŽÛžaeTdKëåUß¼3~ês§¿÷ m„‹F~)d�ù@Ñ,HLen ªæj“ÂòÂâ¼èð‚Þéw½Þÿâ»ößxIµä65ú¯<<÷{¾|Ïcó›Õ03óf®btͤz"K†Öê‹Ümþ³À9 @ò¸eÜt‚)§I!ƒË¸tpþ5¯ß{ëm¼úÚ•^o輋&�&’¤dâïz53 ÷ìy€é‰;·ØÚ¹ÆNx§Eƒh3Au $E¿R÷1rJ±q²×¼Å (¼)­§º0,홓«wÜYÜù-[_¦Žr-½³X¥Â!õuH—@ƒF Æ}šÊ UAc( 5Œ¦µÆœ‘–ÊH“³iTéÊ~’5hï ©½r @’L2AQ˜A"3•\�œ#0åZT  ¤6¥F1l;7Ì̹ —ÁÏýÂ¥?ÿs—_{±ë¸µÌV<†>U*Õ`iÈû×:ó¾Z–Óó|žZ73�›qd0E3m]ŽNM{ý|“-0¨$�ì©Ú™‘,‡6ب6GØ å.öàölcßDzßýâÊ—ïêoDÛ«0È–p jéˆè”b™JUùAt>šõò“·\‡_}çÁw_çɲ ëðAitY½øw¿¸ý™¯o­öçT:ÞØ! ¦–D è¡ÎT`Öf MÍÃ6¨! Ý0ñÔbP%š4[Š”¸wiîºënG|Õ ÃÞÞ y^Ñ+FY]딑$ÞKJbž=ý†ZÖv—{Ÿñ`b›³ÿ<¸Àç´+¦*~Õvâ?͉ѩ¤â”™$tFs„ùb(Ï>]Þsïæ]÷ÚñãYØ€–&µ¬¼ZÓŠS|2=©9W]qM#T…K)6š‰@®uqñ¸:;]pÙ4�lÝ�™Js9Ý…ø�@ÃSÙihAÔ Î¬¬‹ŒtêMS{©†Oå©b¨E¤]èZÚþé÷þ�týõ×"—µ<Žœ�‚à@5Ö–5�üçn³93 }!#€±H‚€ZÀDÊ�õóMÔ~Ä´6Àp¬ öú¶¹¥ETØ ñÈCÇö~æ¯ú­íÇû EwÞ|ÅÊ9ë:3¢$Õ4WË5y–fÉf:”âÖ®¼¤ú•wçï{s~aïä¢mfy‘Á\5ƒêâ†^ýgß¶ßùâ3?î#×ÊÔ3‹Ýrç:ÕÌÊÞÑ& 5=bÓk¡�55ÍEb† c¶P„½§OwÞ¹|ç·Â3�º¸MFg¦@HMJé`"*4¨$·% ŒªÎÔ \¤Å’b”)M�£ÖñSì!ši É%qò¬~’¢R³Öë—9�oçK)|…€ñÇÁn º 5sF³H &%¨ÔÜà•NÍ‘B…!b¥[K{Gïyûá�äê7¿Î/õÖ¤Ür"0<�)iRËTÉÚÂÖ§z¡ì:¡»ÞÊ™=/Æ‹Ú9½ „l�߆“�1ÝhÂoH+ÕÅ1yý`…X¡(ãúÛ¥Œ ¥@ò-¿çGÇ÷}ñ«ñ³ÝìÌž¡ì ®cTuÛbš©ˆE3�ðQzÑý¥3÷?ÝÝö‡BæaÈCLJžRˆ(D0±Ò,ˆ�Sº¬ˆqíÀžá»ÞØûØ{n¼pmQ—組„à`t½…Œ¥bÞ ` hŽOo_÷;_¨þàËË›=`©‹Ñ1º�± :Æ\ewÙôrÏÞ�ÿ¡Ö½§¡’ ÈÞ ¯{þÛß1¼äò�¼kp¤¨™ Ç~f¢?ŠÖ#•Iö²YH;¸&‰!Ùiª‘–)RÎTYÀÔMvö¬›Úí<ÍÄZjÓN#Ìrÿ‘šXÖoŸK.ƒ�fU$+:€½¨‹U9·½5xø¡­¯}ëÉi¹°‚` 52Ä(ãÛh˜£QETz†.²E×ÛË…}~ñ ëî—îBÖé‰óMCU±ØÆhe´µ¢Ûk6Xµjq@‰F˜kt�­…#›ÔNÞ8І—új=ÈÝ @ªb¬ \©.š$�bQ½1sÎËó½Ó¯¿iéW?ú†wßÖ;°8DÜÈœy�+"Ð20’Xd_Vš¬)šÍŒ˜4?='f–�·IìÝÎ÷ÚôÛØ–÷  Z¢Ð`ŠXÅÁ(¬1¹½u+^ôìðâ¿þ~ñ>óøƒ�, u©Ê}éÔ$Š2 »‘��6 Uˆ#¤$Ö–²Ñ-¯æ/¿¿ó¦WmÌ6²¢òPñ f]då-:³,:˜+bÚ}‚_XÅ5_¼Cÿ÷Ïøñ¬ÒKKY®RVÔ 13‰SÝçëæ"öŸ t&MË n&§ôæ‹ù®¿îнï~»»þÆ~w߈óQrEªSeŒBgHÿGCEÔh‰‘ID“pån—c”±}+Þœ‰æìº¥¤ì®Ç?gÀÖ)ÒçÞúÝ´Ý×ZB*œÂÑi¤Q­£:¿ÝçcÇ6ïünÿ�rã˜CIªje0…< ÞêLc2‹TŠAhýzò ®É/¸Êï¿T»û,›WÎEˆÖë4¥T ¢ÃЗۺy²Z}*¬=­'m¸ƒ!±éjKSH¬½¹È4¢Úç­ûüÊ7lRI™¾I†3U ƒ˜y˜'Dh&CqfVt:[×_ë?ö‘×üÌû.;¼wÐ-ÎdV$OVhF* J–`,ƒùñŸ"[ésõR?ÇýÎ6“5¬ãÐîŸÁÆ¢žcKÔ:’¦íL b¤fE°PH "5 ¨âÆ l 9R‰moxøoÈþí_.ù·RÌ!£uL…40¤MJBE;ç2õÔ¡wk×^¾ýK?}à§ß¨G³“óå– žêT�v¨,éJDúˆŽIéU½©‰OqðÁíÿúWþöï?ý�»ÝV¼x$.J„zÆ�ã<ð¤èEÍÆx÷Ô ½ ±þfú€Yý, �¶Ç7þ\ ¹²ÈÄ\¥£ —ãÀ%‹·¼yÏÛÞ28|¸ï»‘,yÕš*/d|âdÞ8öÑ�‡‰/±ëæ=ƒï6 £g{Çn ¢ÏJÏ|�µ�y³Ñ[Ó?Eˆ:ßW7öJ²Ð™Ä‚M:3•~fÄ¥Á&�=²~Ç·?¼_Ö6|UF)Í¢ ‰c@S¬#b*´2·Òk©** ‘ Á-pñH÷È•ó¿ ‹—~_ŹhÞàÌ ÔºvS5±Ìch„ÒÓ ÕÈ—è/Wgž(Oÿ nŸDµ&"Â2ƒ(ÕL�™XLQ]Âür«œ|aÆTv©U ¬æ-“ØqšX Qëôpa¬”¦è@»¢¹˜Òi”QžŸyÕÕñ£¾âƒ?uÉ¥‡!a+³˜[€2õêTL$kÑríYërÊ¡˜&ÌHÒÎ0œéõ+'îÓøäSž”Y»[z{÷ãWÇ fYP°xX'5/17Td`U„Ímn”Ü‚Ä\}w+¾÷‘¥?ø‹“sOyª¿¯ÊöªËT†4š$<2‘ÇU¢Ê€E»y•ÏéÆÅ‡V~æ]‹~«^v¨`XéZ™Ã$IbÔ}“l†Ršj$còÆ P1B fÙþk—ÿΕŸüb\ TŠHË� @€1EÉ&Á›m`—4ce�ï:?k²4xA ¸T§eTëT.ós[½Œ×]yø]?�_uíæÜ|?ëFæÎ(¦Û•Õs–fg æØNÿ–ÊÉ9ÎP€Q¡F1˜L^K¦b;¢²·Ò›,Àí—ù‹æ�¾*?r-n®ô{*æJ±ä¨*Æ{Š©¥¢ &!bž&`¥Ò7Ùvù°;·á×OlßwÏð©GÙß`,I(TÍs]j* E¡Fœ� x…3á$:� ƒ1hÒîˆ*AE`Γ¶qù¥Õ/øõ¿ð³×^~ÑvnÏfº�™P%5çA]š«­‚Œ —¦6âß4 ±Ö`òTÎ!É Äq¾í<]ý"«±ׇTáÈcÓâú0#…2ë¶ïÁ'.þÌ_ÿOß\}zmqÄ‹”󀂕¹ wÈ,@"RŽ0v”½Hݼpiùgnu}ïžk¯ïÑ3Q`DLÝ’¤‘?i\;ð¾­CYÎGßeKgâµð…øoþðÌ©õ¥(%£’¢d ‰©«¼Ù¡Ø µÎÏ~¾VS3^NÀhš©¨æÑ¼yÓn˜ßß¹õ� ï{{…Ý›iŽ˜ ízÌîàýxs?ËrÓPϘ|9}Þ±¡Rj™c”@h+·v&~ïÛw~'ž:™•} µ*8—>æLEMo€Ã пdÙÎÍ.|õüÅ×ÉÜÁ‹�Y弊ӺH ©hÖ$ÕS'I&(˜+…ü¨šúCè^Ô“}2¯¡·²º}ï½Ëwß9zòQ 6%–Y,�Z—SR©M ç­¼Â �`-è&UÃ9†nRs¥˜s…påÐáòg?tÝÇ?tÉ«¯Ú#q%“õ Ñ ’›ŽWn{÷Ç9€ÎŒv¿~›Þïþ¼l&äÕ¾Ÿ£'³ÂÈÈLICp:7DèFÀ*Ü&QFÍ;£î…?Z?øé/­üéÚ~æ´ noÀ¢¢CUg#¢2ÉŒÒP?Òí¡™£[è ßr³þÂûôÍ×®Ôµ^PJÕ‘4MUÆhøƒiöHNd«‰à „Ó†¬äh@t®èìѹw`_á/þ‹/uþçÿû±§NÌW^#²$Ž^o&Œ/v}À.þeE�êMœuÊý‡{ï|מÛß9Ú³o�IåÄÌ»(y§¦£˜ÊîxGD5Þém7�ͺÈljfÆŸÏ»3ã}™Íriɬ¨IlФÞi¡©Þ­¡]D0 ’kj±^ä›gìþû7¿ó·úø¨úÊ«„šˆ™VNuZ9‹Ž\¬©¢^ý"æŽú£7ú£¯Áž‹ƒÌ©d`'!R[LZ(ÌÑDTÄ„� ‹J¡1X'¸}Ö¹Ðe‡}Ù •D‚¹r® �3gúß»g펿­žyªÛ_7V…7õS(\gx~Ð+Ã0mˆg±: YŒôãú&CjÖ%nØ[¼ÿ}üW¯¿þ:]äÓ™ÅbjotuЬñ¬�G�5m»GçÖßße¨í¾aɄ׿ó<6®mœú~ÌК´\_�f c ¤ZÅþ–”Ñ«�ØwzûÈçïÀ¿ûÂæýOÏõ¹hÞCœªêœUbªì(�¥„z껉œºþé¯Úþćßu“í—å, Õ¹Š0¨ -„Mo M»{ÞŒP‡§%È ´nîçlÏæŒ1f:ÂÕ_üòüÿüÿøÞ£O1ð`To„±QXDt¦ÎÄ~Âà<"€©_›�eÏäõÏíŠßñߥ!3²Ž¹péï7¿q�ïÏ´§´(€Ñ«dj4­œUÎÙ¢™µ¢u&Ýs:^øqÇÌi˜š7›þ¹)˜ð;!cjN¢& �(ÌrÓ¹ˆGša€IDATa?üèþ­¿ýZõÈe°á´4h¤¦M¼~1Ò1" �¨Ñ¢Ë"�ʼÍ]Ñ9üªîÑëmßå…ßW¢K:ÐŒ`­¦3gX¤ÁÄ™KUULèÌÑ‚�Øë²#ÞðìE•‚L4ÂEæb~>ØÞ¢�S§V¾w׿]ß(OG¬$–.F³h¤:²ó™ö—³˜rhv—X ÑA‚±x†®°càȲØØÓY×[.þõ�¼ù-oØ;ß}ÚË)oCÅ&iy'^ms·†ZmìÝÏ€bfð÷gÙßç˜N@ÍÍ:~¦YbÃþL}‰‹`T™²†¾•}lE¬‹ŽºQ$º…�òà7îÒ?ú‹Õ»Ì×Ã��õª$´@5±§h€R�Ü‚zÏÊsKlãò‹ø‹ïžÿÀíîÒ¥'˵N‘Ñæ£¯b6p¥yÓsj.r‚µžrãL$8g s~ÿ^ÎÏAº„Â:fs¥cé|ù«ò/ÿå÷{z)Úb´\Í Á’Š”Ûu®u–a~A žŸôÔ¯½˜$‘¹¿âÊÅpxÃuÛèŠ,HdG©@ˆÂ Î*Ù�¨c 6·Û„þ ÀÔϳÎ_O蔘s]T×-ÓÌ+sTÍŹáÐ=ñäÚw¾5|äØ<íÀZT¹3…Dx%S·'|¥ Œ¾¥Ë¹ý� ¯öÝâ�V²'¸…ÈŽÁ •*šO½¨RöÌ`•DšÔìlÑàJu%|̺Ö9Ôó‡»Õ‚–Y$«ÌÔ!F‰„sÖõ é2ÑUþô±­ïܹñ�ïòÔ™nUD–eÕ)#©ç1ó¯p‚� ¢°už ‘ ñ[â7nxu÷7ãµïסýÝõNÜvq$P#Ø ÍfŒ1õ:ÔVÙú»3�øüýÙ@wœ }jкùú4¦ïv°Ö&ëÒMƒ‘XêNj¬2¨n­êpf9pp—~÷�ü�?ú¯¿»½\ô�ÍÃzÿÿìýi°$Ùu~ß¹×c{kî{í¨½P…})H‚)’â’¦­ÕSO÷´¤Vké1M÷h¬§{LÓfÌ4=jYGÙER"Ä]   P…*Ô^™•ûÛ_„û½çÌ�ëá/üå‹Ì—UYcº•Ï×ëw=Ëw¾ãŒ‘%s5�N-S´·MóNÛ-äm{õäáËýžå�}ðàÃK«m»$²é�‹©7ç*[ÿ”6H]Yú˜2ŽÞÌI0X·ë––dqí–2#Ú‚Í`½èóÂÇÀ»÷÷â?ü¿~ñÅ—ÛÊc¹eÑ Ûb eMëÒMÚ†]ë$„I6e¤Õ¾ûÞƒ?úç×ï½o‹ÝVÈ-HPsJFh˜RŒ‰½Á¦ÆÓJ�Þ|/¸Îë_ÿÇ®�$q›~Uã2¥{R’+U™)ºWÍ«e¡Àù§6¿øÇ[_ý*W.}“¨Po"ÑÌ ‰(5 S ôà4•>²g­ÃþȽ½»Þî޾閕maKÕA)HP—Z•¥Bb%ìÔÄ•Ñ`š™úÈNÌ·[ÇÚ2'9 uÍÙŠ@Š… PXp,œmŠëÞqïò±Û—ßòð…O~rë©oÈ@ sQG®´7K.¥(IþÇúœÛ†¼zòøà/üÈÃ?õãŸ:µéñ|·„’iÊßSZ5qyº”äyl0�Å’ìæŒ�ò×:¹†Ôª²Nï¼Þ}Mhº*ùLÞQP ¦Ø.ŠË¶®ÌÊ,¸¥àïüæóÙÏÿöÅÿð™•Ë'ûîxho“Û �ÖV—@ä‰ìWŒ¡Î»ÜÛù#óW¿ç]½Ÿüþ{8³2‡gzƒà%(B4-yÂJXá˜/pTó—VÖ%�¶¼,.¸Å%væèÚ¥UZ hpp«�¾Óqö£>^Äü·ÿð·/^¦êµ!³×ë-µ =o˜�òJI#£¡øÈvç®—~ü‡Vßò–>:E;SY,¤ðê‚0óJŸx Rx×TI¿�Ù¤ÔÖúàz— ÖmýÍÏô¦Cäh•Àެ2³@½ƒA¤&ˆ$�ž±;Èã…‹_ûrþ¥?ˆ—_¦nzëÓ"ÌEk‰ùVÌ�Vx�3Uše1 4ˆD¶T–ÜÒ�ó·½Ã�|tÐ==p=LU´dÐ5&~m&FîDá`É©'@Ô4F•`í��¹ã-,Êúœ‚ÚÒèU(¥p™AÚjD4L‚j!fžNÍ®›©.ÄAgåüÊn峟•sç;ƒ"¸PÐ4‰WVî…Ö No mk 4F£–¡e,à ÅÁ\çʇ¾ûð_ÿkïú®C†+D"¾D±È bÕê_.L‚Ä19Â]ÖžÛØ µE|èœ(�ÛÎsÇ$GÁ�uç Ë4 YFiéÊóÊÁŸ2vI0DÒµ�ëëve[Êè@ŸûÃß9ôW7ÿõ?Xÿöe|ÇØQ뙵…„m‹/ !ÞÌ«ÂÔÄTH2 EÛ_xì¡ðS?tò=÷ó¨\œË/·­=hÈÔ3 aæ‚ú`4<�É¥k£(e˜$(«¦£‰À;]ìÉâ{=ËÚ/êh!"Ë�à!kê6Œ- ÅÒº=ø‹¿röÿþ?}ñòúéBºÊ˜ð©M>€FÎeÚKW-eß0 hæ4+|Û²ÀB}nÎG™—Û˜ÿ±Ÿá]wö½Û‘H3šK«i¹" WÒ±%·>$µ’ß¼´×lF“èˆ ƒ³‡}!Á‚'øÚšˆ& P±VÔVÔ(6È B ©-�ß –]8¿ýÕ'6¿ò‡8÷"9¤P—ƒALE)š% Ad•Á� ªƒ:ú—¹pºsâ‘ìÔcº|gß-ð ¥&;jÅ4�ѡ̩ÕGYðêbÑÙ–ƒ–o·´ÔE‹Î*XcI—nçÊdLfeú†2dcàÅž¡ûúôÓ«¿õ{Å׿Õ\ɥȅâœ2AÌ,r�lVJ�ý* \Öƒlˆ¬Š�:¯Ú2æt}aKÑQÚk÷œÙþÏþʃ?þwšß½ÂD–r/3V‡Ëtš6R€ghŸÆn ê‚ÌP ,vÀÝRº Ð %j[á ÎŒæ¢�}dEÁØÖxeÃÖ¾Oc7oy~}ñwžØü¥ßX}ö…ãƒx"¶ÖÔ呌æ…m1Ò GÒ!¤…Æ.osímÇ7~ìcG¿ë½v¤w±6Û1f(„… # %ú¢ÌEç†ÍQ!¦^9æ• Tõ™õæüÒ..Àû„”æÓg‰Õ’’rR&fu ÒÚ ÷ü¿ÿé•ÿç?yn3ŒtAÑ(5�üØúÙÌiÚá›@:·À�è \¢æÑŽ™F Y£CÇÝ~ÿ¡û©�ÛïÏ][œK!Kš&Ö¿2:6å6/¿ëôU^gf—™®pVß@5O‡«?›u<ˆ"ZbáÅEz… óVlƒ¥«+ƒ'¿²þ'O„Wže±æ,¸hJ‹©9` ™“Ì5bÁY ©"‹ÙB”žô޶�=:ú~,�Þöú2ÍC�fµ�bÂÒÇeÔ˜ïÔ;s‰óGÅŒQ]!óhŸðrØkÏr“DA1–#ïÙPºäð°Ñ‚‹™Ò™ ^ÍÅÅ8X¢¤£íCîȽ󷿃GïøC¹õ b!¡D%¬jYÒo¥á,¶UT�EÔG´-;Ðmðá nû ¢)|�ð¥ˆ^“Gy¹ËV˜üÁh‰€DÔ$RÄÂ+‚í…¥üÐñ¥#ó7òžuŠ–…ª ‘voΒ¹*�|fr 8lÜuzýoÿ�÷þàGææýs­H‡¶¹¨n€h0_ Í6 1Â5a�{*¶Ë×t_óäš=Î2MBEU¤ ŒÑP½\„•-·E±´�~ûÕÅ÷»¯üêpv5Cv[hwc‚èm0£l–ºµYS44àZEÇÛJ×½üî·éOýÀ‘÷ÜãÛ�¸)ˆÂ šœÄÍ$š˜ì’ÿ¦ö‡š‰ú ݶ?¸„ùž¶2£ÐÍfŸd„ $ÎS/ß~<ÿ»ÿÕ=Ï¿ô�§_Ë4S ïV­q³Z1f/7Å4ö€ìž¼ÑGô[„Ëæßÿ!ùá¼Ú;ÐÁ\ÐBKF@Œ磻ŽL푌#Zùk½�l¥ÃÕ vÞ^L:{B§±NX~šœq oã£pËŸ}1>ñ¥âË_q—_úQ�hw¹)lØÌ)œ™P)TªBT£?èŽÜëo{‡?z_h h«93�æ�™˜K¸æ”[ÐHÐTà2u*6ðƒØËÝaç�´1OÍ4¸�rD¦°Sšsæ8Ü?v´Èô¡DS§Né•€Dap©„9ÕZ¸gž¾ø«ŸÐ§ŸÎÛEpeĽ�·×Ó4îìÕ�¿â”p!ˆªµ2ÏuÚ o}ÈýƒÿúѼóp[Ï·âzKhÌ¢—”Opä’-ã{“z:|sVr:ÁÔñ?¶ �ˆM—@›pý¥IµOª¡À$ª0ˆ µ�A¸´Á ˆ*Åvè;¯-ÿêgû¿òéÕç.Íxؤmð‰´¼¤nf¡˜9XK­Eñ`TQ°˜³«�Ý—ÿÄ÷Ï}è­8–­tŠÕ67E"5%$Ú`ªJZkSu >[¾vÊ.–„iw¸¸( èv¢ˆQÄ()rY¦FÚÔ~1¨IëBÅü À]?ûó­ÿËÿôôÕAÖ™²ÔÐM dnaÀø+LFü&Lè\”è;î‘·/þðO\=tÒÚ=Q¨Å’OƒÆÊÇ*{ÔŽ €M’þ8®¶*7% kâW²)´eGSVï[Þ‡•‰qsP½i¥§Hlaà.½:øÊòEÿê«Y¾>è®E�±'¡ëÌӔ̕:pÔitˆ„S¶�ÍEÎÉÂÝ3�¸“oÝîžpÎ@*œX•�¦”‘ K>f–ág4'b!5‹\BvÜñ€äÝPpob>µ�hÂê_›>¦�%£™(§)g½$°jA D±‹ùç_ºü‰ßØþú“·£m£Lê¼çø€[i8Ñ–ÊVô}Ò·Á¶½òø»Zÿï¾÷‘û6|\m›¹(ŽD¢æŠÊ§R·üØJ¿¾@×ôƒ=Z,Æì »ˆMßà­)¾¡LÈ>T\Jª"+¹ê"4Ú †•~\`�–®l�ø­Ïöñw®~ù¥ÞFv²ðmAžL›4 ‰H¨™E$ï˜{¬x^=sªøá�ùxüÀm�•ù¥n¾í êE"Êì^0Q“"-Í @š´)äH‚2ï:½li½®:¯$%£&¾†9Rw6ÄÔ]FÄ€±•_ܸÿÿôŸÿåO\Èq…ßÙ¤ŠxS7€×ßPîÂgvüD÷Ãß³rôt`×E ’“&¥Å„ ¤XbEÇ=²³”½¬ÿÓµl©c{¼•s•µŸ¦ f 5cÞZ½lO=¹ù¹OÇŸÍŠ-¢È[1Š7%A‹Œ*FxÂH�s *‡Ù;Ý=ýHûÄCÚ;´‰N¡íD1NS@•±Êö•DÒ,�KÜÄT@”h+ÃrlídK.v4f!RI‡È’³®J÷b‰¾†àÔHì’�uGïWp�@S KÀW@QS¸Un»ûàOüäÅÌõ¿öeŸfÅP$¾nxîë_J~ªIßh„wì;¾ö½�/ýŸÿî{ï>³*ÅU� \bB‚($…2 ±çS¥†ÉÇÌ\j’ÔD@bÃÙS­=f5*N¸àÊp³8Ô`ŒfŒ„a�ëz?\`›Ì½øå=þÄ7ôçíâç¿Î«ñ¶Ð^PQAAÍD‚ RÍ™yͲ(Ùvöʇ®þ¹Ç~ìƒGî8y®‹:yÑŽ…sŒ`&pd¨2–ª0´L;IHW†\‚‘¨Ä¡×Í–]·‡ÌG…¢"�åÙ’”„F<ò´ 5m†.A[4®Xzîoþg÷<ûgW¾øí-¸¹Úµ¨L´7wÌ¿€•Nt–„B¡Åå ‹‹ßýÁpÛ�ß&,°ô÷VXaúb`ã ÀhµnÜñêè�ÚqN=>ôÕNÔ}—ùgS¿V°­ŠÁ¹<˜|¡BMP1¥iæ¶6ã³__ÿò—â·¾ÑÚ¸ÙÎ}4!U:ý. Q4ø¾J-‘õûT²(=ôδ�¿­wê�ºpÛç•B3• ÍBÂè .aÆiaa4gm‚‘ 1­p&én',vµ`gf&QœeP¨TL() ´rÎ4 @Ó'ƒ”)1§¥ÎSR 1…_sÈO�8ôçhUÃöW¾B5cª(`²Kðß[¬ÎZ5j.6ct\ÆËýÞƒÿíß~ß]Ç/dzÎÓ›-=¸>²5“mjÚ¥ €P¿/0ôÓLpÍMÑ‚ÞåZ›vþ5Ê�*ÁF@U  ¦Ì-QCÜÊmek} œ†Å�~óùù?üÖVÎo´æB;'.ú ^{‘Þ@XË�ÕÁ´%.»¼Ô½ò¡w´þÒGßò¶3——ðT¶!â ȼE$qgP¦»0TJpåP4—†q-G“% —¢ívkiIæzèt*I N�˜tšd0UcR€'lòåç×þø ƒ¯ÿ6V�ªŠ–¹ 1S€Wz#¡‘¢Ž4U³¸ˆÎ™ìðíS�f‡ïÎe.GfpeÊ¿ôŸ7¦0ML  Ø©@"‰öª­]mi¹Yl©¶¬ÄíD”±/±„:-¸*oö”5Ù>:¥_†¾-‰†‘yjŠi°¸Ùwú¶?üÓ!,Ä?ý#Ãe“~�ÖË¥¥Œ´¼qmj¤/žÑ4Ôp™¦BhÈ’Tg¢&fPUL-ߢïê«?úýsïoÞ{ÇÉs(®‚TsÂ(²‰0alö�0E¯'U›À@4iEà 3˜ð{ÕƒŒ=¢¶fM¢à*tܰbkG³Æ˜Vü¤ ¦“%cÐ~V·¹i²ê|.Ÿ¾|ð×>]|âV¿sõ@�;à;k…”»/E“„*¼Ä.ÂÌ+\D(ý•÷ܧ?ó}Ëï‡Û/eaÍkÑrJFC€ÍV››µáHMëX G…±à3?·�-,°Ó6qšLBVÅm—ÌÛD¢½+GñÔñV#¬µ8M %a¡ëÅ‘¯þ¹��úìýÂ'. d!ªdÚXá·#3ÚtJƒæ k³•×Å”b@`ª*HËZþÄ™#ïzÿÕÎ’2-¼šè(Z ½M¢(ó†crȦ{KC¨ÄŒ›gShiSê¯q°C÷LûvÊ–e‰ß°4š«D‡ ±­ýÎų[_~bó+_ÂÅW]ØÓXÁfœ"-Œ1Eú+½sµhê]kk¸kîÌ£îà½ÛÙÁu´ ¢ˆbŽË,�*ªÀœ˜£&DF‡ØRu‘mmle‡3›ç@b©ZâoË¥ßJ�L+Fš•š2ÑûÎõ¿‘²Âq�䮲«Dé#¼©y Æ ¢}òø‰úÁ×6¯äÏý©‹�Æ"xõ‰¦½9Fø *Œ¤ŠEƒE ( Ð\‹>“W>òáìü½÷�X>oýõLZ¤I‰H$À¥‘ZÁ€›ïŒÅ¸}vQž¦jV[ýG ŒÄ¥2ÿj‰Xe€¦™ÒS‚ læzÑc­Ý@µ}èÕ­“¿ùùø‹¿sñ/»¾;[mX õS#˜ö,i«Ò‚© ¶ Î;Bé¸úÐí›ÿèíßû޹íç{v6À@µ‚‡Wyv¨7õm°|³¤“AEü|¯3¿ Ý.$1îqäÌÛá(Ùi®Ýžõ:åø@�2Xœ¿ú¿û«w}åk—ž|NÄ;Å:,†;Üð`Ø­Üì €I_r()é£8efÝÅïþ`~ôô€žJŠA�…™¡,/gG¥L5F6-5³Õ´‰ «q§-—Eþ (Õ\ƒS:�ò™¡r·u9úkWžø¬¾ü\«¿é‹Að’òSÓ´J€‘&™72AáŒK&GüÒ=ÙéǺÇî ÙÒz[ê Z4ìð×%"¼ª7Òœ9šË )´»Ý:ØêèrÎAÔÕb]W£>k(¢¢‚I½5)—®ûÉ&'O^ãÁ,šW*E£ÈU¯¸íØ‘ý±³ÿz ¯<m]]liN¥úaPà­Qh�@ ÞbbPUfêÔYì„+x\þ�ÿ¾#‡^Ä Ï�‰�F)�¢w–^×£§¯56¹T�ΟV>±ôWŸtL¢RM ŒVÆ.qAL‘aeS/¿Ñ’Bèmâħ¾ˆÿÏ¿õ‹ÏpC�Ð-Â5$qéè¦$;a²èBáƒzqQ;¶rÇá�úð‘~ÿ�36Zñùy]q@†ˆsÉP˜”8\©ÛG"Ù붤×�”¾çÒ/¶ 6¦�qlb£»Á�ÆCÓõ4gvõ¡û;?õã§_øÇ—Wb³M�sˆ býÛô¾•×Ap@‹P3× lõî}DxÛJ{!JMTLi&$ƒõp çp°íˆ·Øƒwöæ• ¸çíSÂc<Ì�‚ö]̰îŸyfûsŸ+žú—ˆ>cpd‘<f0uå{ (¦^c4qêdîÞÞñtŽ=Ö_8¸§ÖR:¡IªŸN}DPbæ Þ@‹æCÈ4dê´ÚÇæÜœ+QÌœEª¢4 �Ý ¡T®nT9›&~Nèé�W5O"’¥‹.@ Êeg‡î¾÷ØGäü¯þ¢]yAÜvaŒ.ú×!8j¦áP@h¢š™¥ ^zû}Å?ü{ïºóÄ‹YÜlaÁKHçR´Ê²–VŒÖÖJÓù7xŸ�³�íé•©F5 &À5(EàÚV¼:°uCÑ ìnûÅ?yùð¿þµ+Ÿü#»48£7�0`˜£,F‰��IBÕ¨HUÆ®`ÉÜ@eåàÂ¥|Wû/}ßá‡Oltõ¢/ú1‰Ffi›S6.© É„•ÞDme~aÁÍÍ[+SX„«öhTùðÊÕixù”öš]Àñ'§#fªB�EmÛó?ù#oýìçÖç�6͵Œ™˜w¶?úà.å¦kHf‹„‰¸[îèéï|üê⑾kÓè`ЬRƒ&ØoÍÇ[Á=ë8ÐQ#³ T× ö²MTwßsH1kçW{�Ð p0§‰ûâC![Wúéõ?ü¬?÷Ú\±¥.ï;ÍE •4$% OŒ$ÉýÅ\ÑU’Ή¹ã÷uÎ<çîÞ�yʪž(2ªÐ2"jɪÔ V4q19”Š�Ú)xÀµweÑ…–æ(jü%u•f†Ò ÐÃt8&-GÓ¢úAiÑ•ï$W˜EªPÁç?òÈ�‹®üî¯iqA[‘­AFa¯'è� ˜¤ªV~qB}Z T[t­ÄÅ;N®þ7ç÷ݾêŠ-W´<…²M �D^?é•âW‡Wî –Ý´5HúM´ÌÜm/)ŸbVRŦ=Ì4$h�ZÊC!0µb]¯¹·é:[ÙÉg..ÿÒï_ü…?<ûÚå9Úqó ˆ¶¡n ²ŠH553k‹±EóvŸõê»¶ŸüèÑ>²}ßêè¶qdòhÑS5Œ…Œ×ï¤Ä•Ø�j.T¢ ˜9×ëù…¶ÛæœR@‘ bNÕ–´co¾f¿ØhfÔ,£~±ˆ2ËDµª§�Ÿû«ùØW¿ùÍ×6ލôH˜3’lÎZnòPzZh5(�µççyWqû}}é˜Q,&ïb„ÚûwþµÕ¯~TXQCß2…FÂ\à2Jl¹«KÝs÷¿xÿ{ß%\ôè9k³Ìz˜Ò k5n&^DgYh0£€¸G�¡þ}Ke2’(=Ô58È­XÝ,6¶80Wt}ëäùõ#¿öéÁÏÿæË_¥»éÏ�ÎÁÄ6¾`;:Pò,¬:ÆÑ8Ïà dØfh¯=t{ø+ß»ôoÍŽµV%¿jY½ £jB´ÑW¢|Åe5íÅF^¦Äwk�ˆŽlwü‚t;ð^«1È æàªáÅ¡›·.NÒ¼OkÒá4âøùå†-c÷ÑLlöÚ‡?°üÑï^úÅ_ßÞ¶Ž2xˆÎÈõ4k¹¹‡ RÒ:G—>Ñ}ä—;K Ÿi-@Dq‘>ÙÁëpÏñ%y:+À®ëÀðÙ{œ$;ŒJ¶«@\�"‡Þ 3SÓH*àæÂF|æk—ÿà·ô¥owòUC‘;Çç"½*Ì‚ce÷¸L¥mè°³àßÕ;õN·ðà�Ò 4B]I*h† %aF�Hõªb-Œ¡h÷ÑCv8ã!¯S�)û«Ê�6 ꬄ{j²k·ÿhƒ±Z/ZÍÇ@…S(M‰ø„ÁIô».nÃ]]^^þð÷n_~¥øÎ“Z¸©úàWÊ€ �&ÖòyË�ûOú®?ÿ½m§/ 2Z&>‚ììO«¼LÜ‹f³+ÿ¾5œ?U˜òä·ÓÐTã¹5D³"vt5×+l™f…;xg~ÿKñçýÅ?}ÆmÇ¢[ð̪‰:5Ù2‚Ú¡vië%(€s±%›´çÏœÜúÁÿÁÌݽüÒ�b¥S8²¬`>†D+–òq � Ãaˆc ëf¾Ûu½¶Úp‰n2á…*’Äd�ö†q~íIdÿ”ÆÂ(Ê-a‡lˆ}«RV¥£ftˆq¡ûò_øø�Ÿýão>1S2šßKÒu”×-! ¢P£*¼ºÞÁÞŸÈ�sÑœ*M# %šÜ¥ÐÔZ5±d»÷WÝåú5€Æg)f¢e”¦b„1 �±…ØÝººòåÏ÷?÷{Ùù;a½ß6F¶‚‹`‘I´4ffje®£˜´¢Ìû§çO?½�*Ä›S`*¾hyõ!…d‰“Ù'½]RͪIL3˜ Ù�;Âìp;ö$÷QEÅèÔQ©ÐáÐâ�Åmd‰Þ‡®ß¡& »tøoyÍ2E$ƒ”\‘iöE¨ÑDm‹’�>qè»>|áµóníµÂ ŒCã`B*Y% ¾Î%i:êÌ’EÄËï}÷�¿ôñ»æÜ 0sèªÜ'Ð Ô§Sæhi˜ñéÓš¾QÒß5÷oåð¡ð† [†Â0oOT謿�_ÝÖË!ۯݾ;úµç~ö7/þÆWãÅü [ B‘š¸Â©0z5‚¨S·-7)ÄÏœ¿ð=ßÕûÑï?þ®C—ÛñòáóNÑ’u_¨ï‹Ð—ŠRÊöRH^¤�í!I¨Ba–9×ëÈ|í6|Î'bÿä‚a 9¯®,a�Ñ”Ô~Ú.[dÇÛÓj.ôщIB†�PÄ6ßþ(¿çƒËÿòW.GYŽ 0»fw_GÊ^û¶Ô%ñQŽ_ÐÓ Ø�R¨Íù#Ê�_ÉzÐõ.í«4q6Ú 'îV3³O)ÍÎÿ½`ÿkE›ž0 ?N@(A»…ªÄí•d �ÁÌú×Ïo|öwü‡í�+jƒmï¶¾p4ˆ©Tú Q³H:u]í�lŸz‡œxûv÷LÔE5�‰�4‰‘*€‰I4ž£� XxS¡9‰A‚µÕ츃]`îL©PzõÉ‚dHP‹iiíë¡úÂÝ´´6’jí+™tX˜‡�V’+Fª»í�ƒµ¶Ÿ{äÝÙ WŠÏüF;?[d˜Pcb€D:ØÔdØŒœ9M¥¢:HLÂÃR[¦fm¥x¬Þuôêßùëo;}äûâ™ s:�BdŒ©OÇ‚êþ�6Ç Çc½�¯×<î�F0UiÐT!$€Ë50ÀT±Í W¶l#¢¿{i¥÷¯žà/ÿÞ¹—.è»#p‚äã#2S—lU•A mŠ«K�ËïÐÿÌGN¼ï-ýe÷† ŠŠPª”áÂRŽQÚðï’= 2˜˜"ñHZò–°×iÍϳ݅8$½7âkf- QnUëОâ'šÛvÊùŒ€Ê¾Dg¸M³ÅnûòOýðÁÏþþùV$zƒ ucÙ¡¥E®QóÛ%0yZ%oz ÄHŠxegážõà±@Ϩ¦f”š–YyÁvÜáž<ýum·§ïµyªÓ¹·£ ffG£K1S¦ˆ´žóW/®}êw¶þä³.¿ Ô›˜–sËÒ0B˜E7ÚGü¡ûçO¿Íæïà Å…Ò:ž†z º7eRP!V.t¬äwAof1øà–|çpW]á ’¨µG{jZ÷‡\c‰z*…u–.n žMsÒ&a´ú¤wN$x�ƒöü¡÷¼ïò ß*¾sElà, hUka)¾Î¦¡2ÀÚ žÒ“Kågμí!µÁ† Ch)L&”0äÓØ¯§Ïv| Zß᥺ª>Ví™1W‰&Ñ,w,AcЫ9ÏG·áasWpüS_ëý‹wöK/Ä Çƒ?Í(%¢cƒ�1#:‰IÜI½<'—Þ~??þÑSï}€G»WÛaÅ…hΑ1�<#“ü–§úRSP5­ÐÄ¢Hke�…žÌu‘µè2ÄÊå>Ux¬oÌû.°†?#Xæ[ô�#ï~lùå?È�¹êål|­»N³ÈÄ‹ÚÍ6-°€cÇ/ž¿÷ÞËÞ™9¯‰{¾\lv ¦Æ^qO–œ±›Ìr¾í¢hLCK-ˆäž0¸H¡PA¾tõ¥Õßýíí¯5Û^‚D‰æ•Á ©°´`‘b€7¸è0wº{Ç{åø;úî¸i7S/…õ}¨#Êè\ÒàdZau\ÊG4P§nÞg‡0ïúÞÔ«I™1pˆ5)Çk™+ëA.û¸xÖœÀ»5åÄ/)è¾´‡�fÔ˜;Q¢1?ºüøÎ_~‰kg½å UZ$MÍ;¥Î dÚ‡w%¤HѶ+y¼ûñ]ÎðªÓ9�q¹£xÛ§VžñxSkÕ�C‚Lt²j b9­ÐA¿¸2ˆWÍ÷ÛÁŽ<óÊ‘ÿïo¯ÿò_»—2¿¨Ú‰ð&ÌÉ�vf3§RDCG¬'0ÁJÆóÞ¹ýñ�Üþïê�ê<ߊgYæ;Ñeb…Xåã®ÔÖ˜êrhs@Úp$‰Îô½n6?�Ì›ó�³þÎÚþûåŒ�¾«´G¨×­¥î•ïûÞƒ¿ýÄË[a£på}ö§›Þd €,÷lëÎÝõ@8v¢ï<"D¬ ν‘;åf�íæiÿJÙXÔà4vµèn\^ýÝOl|ãËn°éâDL…¥Å׬$'Qfm•wðÁ…»ß—ïÙ”c‘óTš!“8!A­ôFƒ@ÅÔœEÑ(üÚË=.dyÁÅ›“Ü5[;Q ÌÍM¹_�<³€[Éo£=À`p¦ê:Qgä/|°û�·÷ÿx1�ŒÊÌèœÑ´É(xsJz”š˜k;®Þ~âÊÿþ?yìèÜ«’ά€„*Œ½2¦—néÊ.;ð`°·@°¦GŒY•lxÙȬDE6H:§˜Š*sÅ6ô²ùU´{>œüÍÏùŸûÄåož�Ï[‡ V §t)+»T£š‹ÈÔF%[.ƶ�?ràÅ?÷ÑùŸøÐÉ»óƒgzùE��y+lSS¨ô¨&•eg76H¦T`êéÚ­¬Û•n™‡ ­Í3h_c´Øû3¨Æµ<‘`œsØ$‚“³ï{ßÜ›}îÉ-¸^mJî?"è¦lC¬4’…�-öŽôî}ëFg>šÐÕÆ30N˜ü§jf2õüš,;q\ú¹)iuSRø)pR¥Î\Ô,Hš‹ÀÖÂÖÚúg>¹õõ/1¬©äÁ‡ŽAŒÛ‚�WàÔ(]D'Ê¢¹åÎñû³»¾?ï�l 3³h Œ@]ßášA£* ŒJU5‹~Þû.0d(œªSˆQ£�& W.9•;}÷ÚzHYí¹»Yôwž_Ü“§óš72‹¥Î/)ƒ ”dò*œÛ\8Ð{Çãù³ÏÄËÏ9Ë“ÔHÞ1¡Ê9GÒtDQNŠ!–‘°¶[ÿé;ñ¶7}|X§pQ\Yo“uˆ ô©Ðdºm‘;ê6íäº�Øê+~ƒ18aü“ÚUº7`T�"@dØJ?® nv4zúÕC?ûëŸxbóR\¶n+‹’…ÖÀ™ºÜP®þΔF3i™WçÃærëüß>þ#ÇyËÖrü¶Ïƒƒg ' gšbGiðpôí\‚«ŒÖ,yE-:"ó­^Gzzq%KÑ(öût‚ȉ�M;'�œðñìØ€š£¤$À¶O_úȇåÏÎn#Ó’ˆÈê÷zq'ŽÏZn–�ª•t·—�¸ÃNß½å»)¼'J³˜f ;ôÐJ1á °¡ÙØ&�³áî.bë6‘‰GpÊWTT"½¦WÛKauóKŸÚøò§Û[«ÁçÁk$c K‘„en\d;ȶOÍÝñ¶ÎéGW³»¢µ¼‚c”(^A7U#¡ƒŠF �(]vuüR«ð8UI^0£¦xZŠ•*¯±úiè¬Ñ»•v¹ª 'Ì�»tz£‰óše¸ëW¨óDim¦0DŒj `Û|÷Ž{}ß•Ï]’|[bJ$ šÖ�›‚››b¨ 'jvé±ûôÇðX ϊ̓]¸u‘¬b9i5iÝ ÍôVlnßiEà�Ó‘*M0Ð:ÑkZ…¢ÇB¼ŠBW·ò ‹ÛË›ÅÉßübü¹_yõ›/Þjb¶iè+3 ƒ° µE´L�™Š+2äž±‡+ß¿õSnî»ßÙ^’‹íAÞ‰Û�¨Î "^‘©s*ZFªà»ñV¨†¥Q¨ŽÑ‰Ÿëú^‡™GJXWbü“ò=ñ2fRŸòõFŠ™ÕP S:zš95 °rŽ—¾÷ƒ÷ýò¿íë\_Ù¯\U•{Ç·7—›g*å"g.¶çºwß·¾¸é[9€˜»`MìŒ%ùÒÎåÄ͇ Úd5j`‹Ùa�MNR› [;¹>��¤:�‹Åv|òKë_ü½öök°œ ¼‘¹˜˜:ƒ+`PPÀLe^º'æî|vû{Ö°éhª@ÄMÂ×›dhá40F8çÜb«µì­�-PHˆhEU aÊ#N$É9½\¹;jœ?£–6ÊóG³ Çú;'Ó5õ�1—ÑÀHø‚Jª@h>¨Š¬e�Ã�¾×ûkñìUr@"iÕrCv“6€�%MrR„y¯uî/þä[Ïí»Âè¢ú-'E™!}á`ͼÞh¢™}RÛÄÿw•ìB¬ù~«Jš)´ph¡ôêZ¾©}=ùÊÕ3ÿòW^ý7ŸÍWú=dN•¾˜‹.WZ£‰S˜©ƒ:’Èrr-+Îß}¢øñ�ù�tO-ŸëÄU)Äi‡"”H¨£IâÔ¦˜°.‘ U®r€L]Á »�Ö|OÚ¼ Wß¡¡¼¤|Í„Àu˜_¬qcÞé0‰fèRBæ˜ß{×öûÞ¶ðÔÙm°3²ÈÍJj{­²À¸�˜4&&²°Üºãž ׆‰S5Ñj/ŸŒÝUÒ´¡ °Á:æÌœÈ2Â��£`Xû·RAš‰"x¨h'ÏùÜ·WþðS²zÞÅõ�ób¾U �Hë*ZÑ΢k)çÙ9¾p÷»Ü‰‡×p `Çëe7 ƒ7d1‚±�ÊYU3,¥UêXo©#‹¾è0Ï¢2B”g¬ô¹@h^‡!í#qcÒ¢9ÞXίz„ëYT§u‚6èw6uß§�) @¤šE‰ªŠÜÉàБÞ#ï^»ø‚䚨ÒdÖŽŸímJ…ˆˆÕ!$mó½okøó¼êÐ…Ëá·cýú ±cªéÆf^h¦ KSÙ+Ó/SP^i•Œ ´JT¦¤Gð²…í®†b#Ûw~þÉöÏþÛgŸøf¶ÆÓ1É,f‹½äõElC2 “ßI0»°8wñcïìüôÝ}ï™Õùp¶³e-,ÑoD¿¦0gÌT\@â�WÑHˆÖVPðÄ¢\Φ)dËûli^zmxgŽÉéœpA4Ô’a±šJä~¯¤;º`Ò�7µ¿Ì¬ôòÈ\Ñ2‚ð.tV¾ë=G~åSçWú…Ò#å+@¢‡N|ìMÃh†²o@Ê)Ž2�§ÁL ŽˆwúLÿðq³6T¾0!c“R_Yš©}ª…ÙªÓª¶­ÒÆ•CL_€¦­d–]1¼j´Jy´lýÄ…/Þ|ðôϽ|ùS¿©ç¿ÃØ�æL$ ª(aÎLa9E=H¨[Š�û:w} œ|hÓ-£³ æi`â4 Ä:õ LT�ª ÆÀ³…–ð±-ÑA¡P:ó€cMÈ1@£¦¤�’2þÚˆp”UøŠ–ÊF²U žl¼=®þÖ ŒÙ.›|–°2âH (UžÄDø8 �jÐÕ®Ì?ø÷ä7±ñù® hÍ8LÉ3^Më{2Å�È�*Øë[Ño™y–çVþò�:>¿"y1I‹§XIúhÓ6�uéÆ(Në‹~Œ£^¨ÝT&=ŠÂÄ&R¸ D¦ÑYƒÁ䪋+Ûƒ~÷âÚŸø¤ÿ矸ôüÚ‘íÖ‚©¤Ë�[¡ <Ì)£I$Íç[ ¸øØ}ë?ý#>øÚ/S7ZˆÞ‘PšúD‡j2²¬jš~ê0Àt¥ò˜Œ�i2%´å¥×“^�=Ÿ¢ 3((ÑÃ1])¡VÛ›ë ÔÌ,Ðä#l花^�ðÁTSuÆÆ$½PË<ïytî¾#ƒ¯>·žg‡£µ�å‚<ˆôýñ½Óû¸¤ú¨T+&€;‹‹·ßÓoõÌ@…:³2?"Gëm㹇ãc­½‡Æ°†Ó¦HF“˜$R€F Áæ·76¿ô…â•gÀ¾B)Yé_’r9$\QfŽ‹èÞ¾tçãvì‘-,u485g¾†ÐÇpK3‰‹>F­cn±íç3´|(9¶K€•ˆÎ@•”}Ï"ie\utc 1ÓìàXFmݘnçÞE°ÞC|†Õ2lZý§Þ´�8L1iiIU3Ïß÷Èö«_É‚w %Æ]97£J‘ß� /qýí�->þž“ˆ—¼êßÊ\ 5›ûž&ë ¼Áô$ï»kEiÐÑ0G+Zq`¢FFƒSç¶òüB¿ß?ùÌk§þ×_:÷ÛŸÛÚˆÇMz>ÄP¹‰Ky‘HÏuˆÂزÍ{î¸ücq}ÿáÓ‹Û]\t–‹PD¡Ñ†k4“x+WzÐpQÒ^®LÕ&ç­äIы˜ŸïH¯£N@­BböH5k;_ÜXM¯œUðì˜QHÆ�Ÿ8î¹oñëÏn$GÍ7RöÙ Iá*çª È¸p<;q׆´P`Å €Ý&M4ã §ïâdÛ¡ŒñC I͈è0_­oëÒ7¾DÛ0 H˜™¨%#)j0zÀ«ÌY÷ž¹»Ç‘6ÝR�hf,±î�@ÌUEL³�J@×¹…ŒK­Ø‘�‹†H‹¬¬ó,I�QO$—C¤ËpÓ”8eKŠYId•‹Ä’iqèOÛ7͘Ap„x›±_†>邾Lär‡¹Þ²ùµùù�V ê4Š"AHnZ!´Œ¦Ð2O7ß½ú?úÈ\¯ÏPˆD2BR:Ü›Äã2QÆMFÃfnTµêÎöÄs FO)!= Îú:867nû£oøýë _x¦•·ŽÐ£]°�{Í“¶?z°ÒœÓ¶×þÁîùïyøéž{äŽ~¯¸ØR‹¥e£Œddâ~… É|ê¯@¤ÄìT1%LHF+ă˜9ö2×kG/Ñ …G{ËþõùYnxjìR»,�ô’h–S²V»ÿÎwúÕÿ°QPÕm#ÎÁÚÄö>âA÷o0$‚&”ˆвÕ:rW\:!¥4—’¼ï’Îc�<¦0Øôã�ÕÜMØ&+Õ¤ªºQD,ï^½°ñÄgüÆyÓõÂ`f„”ç%foðïÚK­»Þ#ÇÙ’å(-RÉ@S)í\Yÿ¡„èͬµÐÍæ[š±3Q ÌK¶ª²Î%]¹T)ŧfZ2F›¢P¤ø™„C2� ,™€†[íZðÐFxÜžǵ:§QJ¥ ý�#ù‹�äbÙÑ#Ù}�„Ë{ý«™ä}‹y¾Å 3É …X&ÅæÃ�ø÷¼=c<çXPHÁ_Ðq$Â�jë�Õý5U·G�Ž—«?0ÒõaB±p2…®]ÂÆÚ™_û½ö?ûÕŸ¹xx�*\A Œ­Ìæ [Õj•n"Äâb¼å¶�Ÿþ±åïÿ®Í£½ í�¹è¤“2å%ê,�&3¶X,sË��ZL]‘ìhLy§µ¿]ƬåçÚìf1ƒ2 ’`Ó4,kÎê=ë(ÑÑ(¼¡~WÎj÷¯À é—X}ôáå‡üú•>³mżXlûæ ÞG ùÇLÌ@SN+ßi�¼{Ð^4HÂ&*›C]óUë ”!º}âxcëOu�Mû{ÇCÓŸexJÑl¾ñåðÒÓ­°–3§2岡ž˜„t¡8·¸|Àe._=ŸqSà …C.¦bTº¡KCDì²½4:>¶®TÍL3š�8%™@ïµ CU7€#]ˤ­Y7f�(™Ò)F5À ’�ÄÌT}ʾ”è(†ò�ÁFDÍ“í3Ŧ<~NÃn¼éi¶UBEídÕÅAoÎßûXþäŸÅþ†GN²‘òÊ„OƒŠˆƒµÝå�}øÔ±Å•VÑ÷TaÆ2÷7 &äÈ7Þ> µ&ó¦kë’~ýtmÈ+P×XåεèB´¢§ØÅÆÖåÖÅ+÷ü¿ßþgÿþêÕ­cÑÏ` Y{ ¾ÈÔ’TŒufýG~ìÄ=÷öϾbçó#´`>7[I ¥™ œ',Mò”4¸Ï­™!2ë{§Ý–ïµ°Ô•ŽË‰PX׹Šæ !Nb&1±åÄÉVå˜dÑ„Íß[©©°c]qíuìÚqK4ržK£`óöSý»nã³W6L ,ó‹n¿Æøþš€Ê\îe³‹c{žÇnH¦¦¾„i˜ŽBw¶ó´—ÛÑÐSwQì}ösb4)UkÀ2‹ —_»üä—\XUAÍÄ\,-2#^³HÓ�K/ØÕ³†®¡ è 0Wó˜ A÷Üôb-Ãd«VÎÖä1JÖüÑÆGÀ œ‡kÁw9·ìdÍ9aGÎpn¹OWX(–uUÙS“µj|Åô“zTä6ïY·÷]r›W94†.b šƒíSoq'ï)V^õØ‚Ê ºQ÷TUF“@fÐüä©í=¾Ð‰ç3‹2däB¾xBµ]ÑnM¦›Ù4æI ` âfõ§¤z ‹ž:§2€¶×ìÊ•ÿü—6ÿå¯õ”yq¥@Ëæ³~”U†¬â‹czG33ÊK—íùWÏg10§í(^£‹f�¥ŒH!Ë]ÃÊ€º´…$÷'š÷v$“Øël>пãï»sþ±OÜvÆ[ÞjwúÐMÇÂÐ6´ x“œ%oóލ.^³‰ö2fö 5TSQw–²N9ÈÉ|y~íá;ŸüÓ ´# ó"¹×Øœk•ýÔR§–¾ñ qí¹Ö�#[` ôƒf©PBe˜:è£ì›vïÁJµo³4Ää2ähånà‹zBž2ˆÐà‹bëk_Ñ /yn¼ªfYh �gZqDšÀH¥Y †�Ó”–¨`NDš‡ùä´M5ÖGMÍc ¯¨ä3“á+Ô`r¦^ g z"FErç6çÝ‘Ûz§ïž¿ý>wüÎíöÒ¦øÂe¥m‚)n´ ZR—LHI¬ÈCëÇëg4IC{ãµo†éX=!Ÿ•à1A€¶Šörç-¯ç øØè´O…É\«´lýíï8pÇé¢U¨£câ0-ŸžÂ�Ä8íÍlÉqfÓDó}ê{@Uý1Àð4'DîCÜ\]8wñøÿúóW~á7ŠÕxÄÓ¦LC Ma)kƒ«‘S€Yí/¯o·iÛ2J´žåö}ŒbCû¾ S>¥ÌXe=,%p„Ñ×RSl/o»gÖÛŸÝXì]½ûööG>Øú¾Çï¸ïv.¶ÎW5JbéšD•O•ú÷êy¼f™Q“°ä3ý—ª¶f‰õËHÍÜúC,õ:a»˜hÒI“ýÂ;ïÛ •jDE ¦�öácÚéE#L¡1ÅsbBøŸˆ¦;ÉmbÝ©ÿ6[E'³óÔ­ÿÓ¢% bŒ¥9 rõÒæ·žd±�ÇL€ŒæYR}%gG)A� 1ª Ê9C`° æ'é|…0"‹JC’û­$…ѤvzýU%ÒÑŒhÌ$š®®èÕsë/üÙÆ7Ntïz´÷ð{O¾eM}î20ÑPÇ´š–ðj#¥Qíw£¶‚×n†1ûZ½&uqÉ@i¤Zp®}Û�rðh|í¢Ó}"}Þ­&LDªu[ýÇß{´ëÖ%Wq¥ð2ÚÌ €îX!v÷´Lø·®i¾hZÈ}ÊĪ‘L@ipÔ›Ä"®·V^»óŸýok¿ð[zUO+Å38%¢‹ŠmšHôÐÞˆ½µ62`Ž6¯,È�!Œ² pÁ•’_ ¤ÅÉЛ…’éÍ fÎú¢A€ÐÎuqe#üÉ×·¾þõµ_þ7kßÿ�¥ŸùóG¼¯ãý9ažú¥ôy1 ÐR$›’:Y³f°³¯Û¯‘eÿÇкYJa©A´Ìc€þ½÷?tÀ_:ç! Hû#è8´ïÕãz'6 ¢¦Rˆ8³Ì} ‘ó½‡/îz$gF8KKµNº~_ÊX=9ÛgÈb Ö‰ oމU¤ö“¾_¸`­"Szsa¹Xw_ýÜÖS_€n+ óI’Ž‚ò^e“P“ ³ìU©òÀ¥¸tWE=ØØ8Ž ãÐöÓh ®›€Xâ�f’È8¢å5¸ÍËÅkÏ^{± ô–GéDˈ(n ( ™YÇ Vûì©/ƪ9üì¥_J²Œ2Iq%ø�ifuû¸ÑHí¸8ˆ.×Ö‚½rçŸó”Íu†‘ÜP(C">hbÎAÔaë-'6ÿÖ_;q¸½šÉ*$‡¤ 5e6‹H¹m<5õº”¼5,ƒüª—½yò×hj¹ªÿ 4Ö´Jç–¬%)âÛvù b�ÈÅ‹©Ä&>Л‡mÉM wöêáú¯×þ›ëz:H¦@4Ä2•%kÍEòèUí#@U#è80é bp e¼k’“¦ †º¯ºÛ¢ðÆ,²½ºyøËß*þèÉ—Ûæo;³0ñ/>åi(”E3:Q©æVÙä2e†¬õÃŽÊ/å RþÉé·ÉvIrê9´ÚÄ~†# F(+öÇŒŸ}âêsg„® ¾d®‚ Ùä§aä7͇}Ú1¨D¡˜y£yXÈd½¯8qW0)sŽ`@»T©é ûõÁ0ÛèO+× °öS'*•T…bÅÂÆÅ�/ü~¼òGƒ•C|€í¨sÙBµ­EÒ@�r[×—¿a®‹Ñáú|¯ßyxEeÆâ¨YnB42d‚¶·6_;oÛ[‡—¸Ö\D4‡h„e¥èEÉìi¥œÙÚßp˜ §Ô¤ÝRK.7TšwVDQ°Ó¹ryðÂ7€ÁÌREã0Eú& ’"e-³í�|WïG?6׎+™ÛNÁ‹ÎÐÎ;÷L)1@ŠÀ‰jL—L'Á,#¢™$ÓäBti :“Ìè�)Õ4´._9þó¿Òÿç¿tuµ8]°ÒÔbéä­ æjUÛÑŽ#?CmÐJe°Þõµ~ŠàUᚌXn"ô*Τ}åªÿò·®ú{ï:5·°I·BÍ m@MxÈ•LQËݺ»DS_LkÒ¦¬¶ÍÓ�7>YÇê0L€ ðíî“Ow¾ø¤Áµ|€¹¤g‰'qÊ@™mØ¿@°ÚÿH�Û·¸\ئô�CjúÊ�»÷ÛïÉï¤�À†,m'ÑJìe$ÔÁhÝXèk¯æ—Î&0È~€æG ôþ›V¨@Tjé¶mœÛþê'¯®œ=øø�¸#·_a™§ªGžì�î�¦7UìOÏXÃwT UJ&oUdXZŸ øß=yrkáP¼º.RÜDaˆfêè»ÎÞóžy﯊•§¾ªý.î¥zW7ä¡d«±§yÑ”Át÷ê›yDA„Ðà æ�KŠÞVqàw~_þÙÏm_Ùºo�õ"‚7ˆ*yóZó:гØ6é›3Áé«k§þå¿yöÊÊKó¿”2F“FR½mÙ`sû™Õ‹†#úøÜá»7艺J2L5 ö¦ºÍTgÛõN;ËjžéÊa F 0@08˜=WÎí×Äh®£Á)�v?LÚåRê/¹þw¼À˜ëb ¿9¥UväãÎ�=4i½#mxÆ „q 2@hi<ñÕo,þÓùÔùõ{ûÙÁ[BoAb¸µ6š¹¨-:ˬ�mÚ±ûÉ—VúWþû¿uÿ�ÇζüEš1fôQ+ØØŽFœõÁûRÿ]|6µ?jË&R‘�{îX^ì]½¸Y3³Öþù°÷“ .­š–Ú;ÀIwÎÚóe”Srâ�p?˜ñ ÆÍÁMjÎ^p¾ušôá͇—Jí+5P”òœÒ ê4v76.¾ò‚³¾ZÄ~”Ã&O/ÃûÈ,SHLÙ¡´àXPóíž¼üÅ#‹�/ëÂáà—LBk\M–\aŠDmzF2vi>Xua æ0¼’ÅÂBvòÎþóßD±µOm8"¡"ÐH‚âÄ\ìßsgvâð¶³-ÂŒÄ8‰ë˜Ñ|x×á«×a…c6âÚ íS×ê—é9c™¦H0I\«}“meçâ•åÿ埿òíW–ŠV'¸5H°ØIÔ-Uèî-Q W�fˆæò‚�ýâÌofëäüæßÿ[§.žk‹ÒZDT˜ZWPq”LøÚ¥É¤v#¦NN;X‡0ŠAˆ9íŸ9!KsñâfA'aö+xŸ¹€†n~¥°·�ûVé²J×2bP+ Ð,m:‚×£©3ö”ü}¨ ¤M¸|¨Š*hJm©âÒå¸rŬØþAƒoZ1šUY$’¸s¤„��oý±ï8øîï¹Ú�ß–L!ÉM?­åØhš½N ýØ$ja5%2•%†„΂!ƒyEØÊÚþÄÈæ­¸´OµÊ“W?DÀ‹.\}äÁCK½" £QY¦šey•I­æ×]»œSOhJ>e#7s„$ä±() ‹pì×>¹ñ™?–�)¸. f–)Äf�¤7½¨2/ã†ML]„£“>ü/ý‡K·ßÃÿäãw9žÍ$9àÍĨ¤Î²‡5I:7"œME�£¹8š‚~Àby¾hÏ^(pD%z½±²?ÀøœN[�´çƒËÔJaÚJîÈf<“rYE L6⬅ڴ̌ïÄ;Œb‘ÑhÚ?ûšö7!*·”n<ý¥ˆ0t'4ˆh‘„æ™^ÞøÚ§çñ÷¿;d=|ŒQlºü3¬ÆMÍ&¦à"e­J,HBK>2"wÎ:&ÝEÛº© –€-Øv¯—?ð@Ö²àµÅ’žLË<ƳDZÃt¥7Óö¦/Üc¦Ž�ù)Ó˜Üs*­t‚b@áE³Øo:Ï¿xðç~ù;ëz{‘B+ò–£Wæ*-kzðU Fj‹ð%LZÔ¼]Ñ…ŸýųßóÖ¼ƒÎ=mÈaÈa£Ѭµg“²¹ë³÷ÞÜ¡¥UBoåͬ¢-Óé%6rì%�œb±×?Ò³§ “82Tܨ7ZöW†MBº0úVwR™«†à•›JÕ2Ž=œ­êãP°R!K\jP$Bú[ƒ ¯Zè!·R™^eTf9,w½šWº(8ÝÄÆ¹+O>áÖWD‘Ò†q˜5fòc;?6í`Ãgx“é÷´Ý.d…°Hª R:ãÉÞRëà1PJU ±½^1¼„qìHS,Îóî»[…˜+OK$«åØá2«Dð;?MÏÕѧv¾ÙئH_1µ˜1(•¨“Ø�ű_ÿ­Õ§_ZÒ‰P�™×E»D4FãÍeÖ»Öxžò1Ë{Œ=ªaNƒ™Ï3>vá~iíêÆ‰�Ùfä¶!¢Zhë£lê ß�(L›æEÓd©];ô4Z5ÖS8þD=&fDª�’D§¥'�Í%»V w8CÙ)_¥û£”é<ØŠQ‰\Ô+Z¡·Ds”¡.:�­S«9åÅløOíºÖ9Mž}K)>jàŠ¦W ¤2“ˆVÿòÆ•oŠm˜v ³™áìæÚ‹†�ÕÉRÙtÒ:ÅXîÐQsC^~nî©'—ß}ðj»á`#ïüxÄo£àÚ¥.ÉN˜}F÷iJ 4‚ÅT~ÌXD¶}afR¨w»»ÿÜç$ŒTÆèÍD©ž*µ™D† š I†ÀHå‰#íCK[V}31¤tœUÙÎxâ‘:/üBÖêZ¸b0â £MK 9>jk‘ªµ uˆPñß~±ó+¿yqÝî Ef"Š`0³–´!Ò|ZÝÌÒlàP•�ô-ÕÀŽ€igîwÿxëž<ô±éÙ%gfP­å¯ûÆÆC &Ð8³”&ã’ SlŽ¿W=R½nÞ3&@N€™4àŒTf™Ã™C…ƒìˆ0º)qš»V~¸Ô3¿í› Š)¤ÁzkwJò±ôs„ƒkPi÷fjØPîÚ‡mǪ4rOZ™^QKúag7×bU`ÑÞ@Éhj¹¦žN žôÌÊô‘X¬m>ûõå‡q’¶XÞJ¥ f…�°òuÍ�ŒŠu΂o[ØvqU^¯¶¶£QËd±¸ûŽCs0À¡ña2ŽNª½øtéòF|ŠuIvlƒ�WpÓù¤‰˜AÕ$¿|µ÷ûŸzµªhÚÃö-Äë\Ht43ýòW6¾ñ�£|ï¢ÙUZÚ*¦øów´iºM3¾r&L ®£ƒ§mö‰»)Ž9Øi­n VäÛûRöO�«¥$L€kµË¤£OåÏ&ëè V¶ýýL©m¨Ä§ÚRÍ©bcƒ¡0 ·”[ì:JrÒ$‹1³-ö//=ÝηYý¶ós#ÍË=|𝕤S…$R£@EKû;Ì�˜›ggÁÀh¡tÖ˜ýbˆ£ZY8~$¶X˜ªUUlŸk”ønü³Ë*3ŒÁ•d ¯8z94g;yî%÷Ôwº*K@͆æé[¸44'"Œ±�âÊÚܱ_Ä•$& ôͨ�5ÝØ=ëN€¦Ï.Úù)�4;?)EÓÎOÍ—S» ¢dòåÅv–�(ÆD�.ûkB2H�ó®ÕQRªùÍdP­d6ìªo¼suÈŒi% ¢æb@±Z°ýìƒ7ê%%‘Ž0ÛÛ¯½ØÛ\w„1%l^roKJ“¤lÕ¯¥aԌɣ’°îjF-ÝÖé¹îRp™ÅmBa�”B p³½Ž MÅcaºöZñô±èâ–@‘F1è«ËUu~ÿúkζÎNV}(nM¿ßصTÁf%ã¦FíþÉŸn^\Y YXË[p —¡�x,Ñ4”V¨„ a`ó_úÓ«+›‹‡—£G!¨¸R8¡Ð6ák–û™·E›éš‘¿g$ Uc Ý®´¼�2“Ç~”}5•“ 4A¼VÀ3 ãñh5>Œ7@ÖØÕXV¿"4#’ø«h1¶‘–þ:…ᛱИŒ1®\Áê·x&HÂýz.Sà¡”l" fFÐRÜ‚ÄD&�vkî`¡4,–y‘Å€0»Þ¦È(º;~$8íC,帨XꆦùéÎó: qæÁs-BÀ)m8Å9œ°%„[ƒÞ“ß\+x:ÀÁü›bõ¯5Æd¿$.Þ RxÿÜËý —�Zöf}B’3;½Ž ¸¹kžQöêµ@£˜rÒ.ŽÉ!æÀƒ)«@Ô„+ëdÒòiÈ»D ¿/ Ðþi£w¡�N<Å×á–BÀR4?ÇD—�wz½ÆâNZ]Žw­Õ()M‹|;åû¾¥³"Š9E«©Û›ÅÕËîTdSÚéõÆ‚sÚ‘Òœ2–‰ŠÑL"5Qd[Hßš[Þdi©+@J²_oÐicy!-(–èþY¦AÔkÖjmCS:ooÅ&]|õýeªsÓÐàl4u”èIÝÜZxúÙóÑG@%z»µ(öÐ&ツ Á™µ£·Ëká™gòûîì9JZVVžêzîxXY3vÏo±k{Me5AóeuÜhÝg_7,vZ¾Ó¨QÌM¸+®»ïö› ®tf'¾K7ž‘³ª±í.‡ßÜÅf<ÀN�ðø¿£r33-  ”:ßä¥ôy(©pb Û\£*¦‚½Îoܘø!‰ö0“$#¥å’†‡08¶æ!.) Upº\—¯«Êî6qPãüœtÚ‘VTÇLSj��íe•gµŠa.…½Ñøz7¶�5ÑÝOíFE™·Ú­¬ðêŠ7)¨ÑÌWIÉoý²'8áS·¶ ùF_^yÕÔæ¡›¤VQäÖûÿŽv®;c›<;{i(k>>õ§B¯ÌÚSŽp¡Ñ|f™Oâ§7›¤ œ).xˆ‹ è “¥0g$Öo*½Ò8´ ÕZ¿1ÙÅ~Iÿ»Eü6·UÙ²IÂOP5‹P šµÌ†)J“‰ƒSÿ2PW-£Š1/òuZrÒLoÐ7ìÍÆþ’t(Jš$‚”c0X¤´—<"#Ï29»@»˜ŽÓlo¬"ÁÆÏ¤Ó°¼éDa&j”¾™çX¶×Ú}Ø`R˜ ëÄøâ2ž‹xê÷æq8eœ‹ Õ÷�.¯\éoΌԨÒjž³õû~Í߆÷J™^R;Õ– #`Þ‚EóÁ–^»"Q;ÔP™ 1–r}Òì_oóú«7Dkï­%FíYïÇú=kÇkFýŠæ9銢¢Ùfæ @ zÙ±VW4¹»mSš”ûœ¸Þ“0¦KœUoeU’�Z°ÚñÌn²°‡;�¸v“¸\b`$„e’¡[l˜­Ð †0š#�iè "+¤i�ö:¼òpÕ礕]1dh+ÝóɵÇQœ'³Î(l Z&½¬fªÇ´b°Øm;/4Ä*ÕO¥ŽIšS¯nXÜwf©»¾rm<» €l{+„À§¸€}ã[¿éeZ !‘8hjpye½ؤùÕFÔŽ_j½ØÔ×jª‰¥¸lÜYQ¶IÑ’½ÆE'Æ”/höÞâÔÝç¤ð•æh:¦ð}TË:Ç,]µÚUÉ´­Ú n¼4h˜�ë†G‡b‚ Ñåf& %¡Ž’•é›nu¬Ü^K²¡M-0æ¢��oöú¼q9vjUJ# R„pšÃLn{` f­ä³Wh…k¹¶Ãn– j§Ór®RzS¡ô”1±aÆ·ž*ö4zã¯yÿ&g£�Ôå9c¦�x3‹4¨T*AÚÆæfKæ�Ù°5ênkŽœÚ‹¬s­–šîýݹ_»Å«da*•Q³by’Õi¸í·¸š«¥óz¨™Œ‹öIš³HpòNûU£ñÒ˜û·ú]*ê1ŒVMù»¼sí`’6à×ÓW}sÊÈ(0ÕX⑵)bòu|Û A¶’¬'æ GÚB¥wÄ· ’€)J@ö4¥÷Üj´VæÈPenK�æx¢�é‚g#T´æT¼¶¶yƒ©SGpª S7¦?œv‡ý\O­öá.«¢±@(„iΖ�`ûPÆ6€¦�pêñ1²xJ„ˆ†j>è–ÛZu&1V©àkÛCuhÊm›ÞË8•Ï‹M1>�xä1tPÍõ\ß�‡7’¤O-¢Ä¸xHæïÔõKæ×¡Ju¶Szš6xç›øßí&畬‡' M¤BÌÚŽ*ˆÑÑÏ”¹C £ÁMëÛ …}Ùh»Îi<°Óƒ�XKêb“»îÐØ’D%4ª šˆA-:Jp_Ä[tyASRr 3t æR_aªù²Ë¢"cûEÝxZß1*<Ѩõ×;¥²LPúÞ&[>sÙ_êõ93÷µ?Þ§‘K©<ŽcS{ÆÚ§%´ñ¹•ÁÄ¡& c”ˆB»êÌcpp~ðÀ=pØ2k9¨z(GAص `ÜR·/õßS³ÕÚyŒ^x„˜'�3 �Áövlg)”Ï®9Çö\öMAU”*·š:ØLIÊ!É�"Ò¬ïÐì™­® Öõ�€&ˇD‰p¡»Ø>z:œ’Ñvĉ¾¹|ÂLvD��EZ‡ŽÅö*@Cíu1°Ý6ò™‡ã¢[ÝË9\ø¬†G0ƒ†j�— •À„ò݇)c0cž›™3³ Õ0¾šL4¦üÒ±SM•Ò¤e;Žï¼Ñ°­kŠêbg듎`ìt·x ÝýÔj�-³6K®=˜ÞÚÃØÆ¶IÕtQƒ(Ìï¸�§Næä€Ž¦VåÏšŠ-»Å‹U0PnmÅ"Ó¨ì[Í÷7¬BÎ,Fô7�)àjцAa¶g³òð´�š÷¹/­â›L¤ [f"æ9hÏe§OãÙ9¿åL’h(I-ø›¢P Q!�V÷èéà»±‚šM…17Cê¦5äÔØ“éeµ~œö㔺[mT6þ” ´`0R0ìÃ}¹Ó ÛÛ£SNÚ8dz�´ãš½¾*tY“hj+O¿ÿT¬  %iÇdå­o;và`¾¾Òz£¸ò7°#žmWßýîÅ¥åZ®VÔ˜&Ûgú½öâ˜õœ½\ÛôjªâD‘­¬Û ÆäèŽfhs›¡ì£ý¡þ– l‰ÆZf×*Ýå�ûzÄ¿ûÇÆÿµ†Ÿöø1è´Ïè×ÒEQFû&KI•[8yÆ:ë¥\t“�ioN]`So ïçgGnË¥e­a'óÚ´ã»}¦¤÷�~æ.7¢ Æ?£zV+]ÙƒJ-¨µÀíjp^G a§?–³~ßB‘Z �HÓ™ %»”á'ݳ:Ü÷UTf³0bëî»pßÝcÒü&H€‰€£aK0Òƒ&º}âpüàûz¹ì¬Ê<õf%D¤™šY÷Â¥¸BJƒIì[J’}ÖJk¥l°)q@çmjÜÀ¬¥6Çš¼ç{­ac S%Š–ù§0¨*…LB¤Ó…C�;Þ<û ô- ˆ””rf|S¬ÿɤ,Î)³…¹Ó ' ´w¥i�QriºËÌC`Ì‹::Zj%VRMC Ræ7a-`Æ§Ž€£ÄÐonmç¹·vF—‰ bLà›ôï¬ó®mg{=nÊÐÔV«% 0§ùƒ½ÁG>pì‹_\‰ÔZµÇÑD·Ú€.5¤ñ䱄9/ÁÛå÷¾mþÞ;ÄëT@ÇÊÜf{CRÝòçFŽO r´ªõ¥ÐÞÅË­�" !”5Äv-åýÌ!lû£T~¸rõ ÍAû›+N£-ý[Úì�Ëž3YJÏ^¹ ««�UÐê &åæûc|*%z%ƒ‹´È`¹µ³;‘£÷’s@x�#'ðÞܤoTFÍ ¡�ÀÏ´ïyçfv Ò—ÁMÓ gú@§š/i*SÕNžQÅ`;¥2/9I6!5¯£hn}­ÈûÎÔ#¡l‚´Ýz%%œ£XlÛÚ÷}°÷н}okRÛŸX+ot}' 9^=–ÕJÆâÐÂÕùرC�õ,Dšo}�fz©ØÈ Æh.½W_+3Cf&ûª¹o& *^¹J„Vl¬±ÈQNÑò½®ËžPµ‡Mæfº®yÿºm�Túà3Ÿƒ¶*4+Oµî{ü4CÊÌÀĦ÷/õàÍ*£ymfÍæ:·?Ý5�9£ù˜ÓÞñ ãöÀzlQc™É­–ÌaßÐôý¾noG˜'Pz‚¨@1.­ŒÅÚËì¡4�ßXÑ)æMÀÍ*ËfîâÕÛO^ø™ŸYZè­�V_ñ“Cø–ÜÔ8þG)qzN7ßÒÛÉ3½ìÍÈ\¥¸Eh{g5{‡F·Ýw/¼pÕÄÌËþéeûe*�m5¶FC1�b‹%�˜îS¹~Uk‡åFû¸¤««*»*©%tU`.F¥ë³»pçCÙ‹oY~U˜§˜o£ÐL 7Q¡*˜à ™L4 ˜Ž³å’Í͹Ãwvï|t�sF¡*-Òš´þyw“xÔÜåþ;F -åXA‰Oè:UÉ7aš¢ªû³ONE ‘e»¯WW ž”±‚ÖBuË­ŸF¨X™¢/±Åsß÷¡û>ý…¥÷{ÛŠ"—²-ˆ%ÊSµ‰á\Ýk?*4s øäÍ©P À¸qä@ÿ'~øÞ¥Þ·|ܤ™1°Ì~ð÷ÃÈ­³g‹ZeTLu¿µ!ç.Ì-'�—íÀø^·u}ö `n�P±¥mpbA,lbã¼,œ‰0±`f`fth±)eÑ.à)ßÐLÑh‚«Ûgk8;ÚNÅJa…¨@È‚Y˜©ýîòüCß»¹zWŸt( õ&mÇØÒ¾ÂG:¥%ŒM%ùàÊÌvº«âÁ#cM2´YÓ˜™©˜y¨˜©0P(æT‹¹cÙß»qèþÂZ"€‚�†x‹ñ'߈üaM;y²‚µ×+ÛJÌœZh9£ø"8+N�­¬Èmã\P3g�fÔÐ÷MÊÙÔÝÈ@†5bAŽb}ÐzõB›„Y,$#sÑH#k\;°ÈFõÙf¼Vçúñ½G+�’Vá*ŽêOu®þ�¿pðÉï¬?ûüºãRÀB!Á$d³à>…UìœûÄ×D=8mŒÑè`K)*Ûp³\ØÉ˜µxþ/üùÛß}Þ‰«„F@œFšÖ^»ÉgŽ ¾v#ŒeOÖärXF¹ÃL½vÏ�åÙu—»ž‹[bY!c\Ã)EÎlìÜ/Ðм_Ê›Ðþ†®\˜bteè©U3jÚg/Hžº/çìåüFç @*abé ¸Á‰ûçý°.œ„ëyƒ³h�  ÉD¯¨•I©ŠD}Ý�yë;ËIQi’E£Xá`¡}¨{Ï;Z§îhFXZ. 2n»>C¨wÍ8±çG…A`&1äWMIY1)îW4“H·™óüå`ô†¨µ�ЩóÔäÈzýKk«¾ưþØ[Šÿê/¿m±/j ºèÛÁ ûÑÀaJ5Öv5«}Ù9‘{øXJÛ9Sí©Ek;ºur³…ÐRzóp.píñ÷´>þ#GæÜ‹-lÁ¢�0ÏknÃol©Cæ&Ìzµ!«ÒyöùÁê¦ÑÚT’Å>†åï— ˆ—˜ë Å (¶uõ¢ÓiÇ!y¦ qÓ»J|Sž0Ѻ—¶møa즣£ VºÒ†Xâ‚P/¸žÍÍßóÎÎöåþ×þCkðš�ƒB|!­HNÈTgTö¬þhšYn`1—�bE$°Ýºí=s÷¼Ý/Â@ 5Jµ:L­+¾Ï\©é}ÑØ§6ö3«½Ô’ÕÎ 3¤D‡y?no¢äJ¬vüýly²hÙ…+E@Ïbæ’8_b¨†$Ã%¦lüø¾4á¬öúCKŸ…!Áõtà� xí'?0·zöÐ?þ¹•K½!ÐÂe¹�‰] V™¹®s°Yl²ÖÜ9Mš™Š"Ûö%ﺸ,Þ wî®»ÖÿË¿~׉¥ï´íœØÀIŠ@}30œÚ0gèÄûÆÀÚßüÎ „.¤¥‘`^F6îGÙ À€2we‰¨qË·.¿âóM—,Ši*M™Ö®ûÙÓ%Ç™ ›W½Êx^ÚdJ™Â\ÜôsÙ}ßݹ÷{ŠÖ EËYËÍ4E¯–”a¥FðFlFFfFÉP´¬/š›´ w(;óÎîCÝìÞ6@•·tŒfa÷�î᜙´·=Þ°Ž/ån¥Ñàa"¦º¹bù6,’¥GªJ»?+3§ì<ÿÊÚf¿gšR]™t ‰ #’a«/‡·ľҴSg›º•¹Í¹ìÙ¿ð£î¯~|ñ`ç5b=ø"0S,šy@v¤ycÞ…p.Ì12J>3é"¬ßyòüó7N=|ûùn|¡�­ `¹ÉEÜà¦2Jš5¦ ”¿¥sÔde»÷§O­‚sˆÞ´eR`ÿPgûÀäi43¥(ºúšß¼œeËÊv²h‰i D›îåÎ}»ôœ4ìx×�7/™6ÆxWÊy:åf#�¦¤˜7€ˆŽ[‘ÙvïÈü£ß‘þÓ¿ïû¯ø8PiC<,*„šX^K¤˜”›–Olgž…‹®ëQ8ÝfØ¢_°ÖRûÌc ~pséž~ê‹”œS¶K›Ž¼Þ7h¾®i@kíºŠàÀ�E¤jIiÌt «´ØÒ �,v�'ÏÖʈ’½p¶XÛ\\j· ­p@Såï½2MVà‰�×O?~ý÷ä0ؘ£½·ð>?<ïÿñ-tƒŸýw¯]X_0Hç�¹¡`ÉJ©£›45Ï ÅèÔîSW–ª{б%èBŽ9uNøÒý·_ú»ÿÅßõð•^~®ƒ�WhB@“×MõáTÉXN»`tzMšmêë¦ç^£yÊuª÷ÊŹÎg@Ï©O¦h‰¢û”�Ä¡}Ç5_`â훓&PFQ `jl¹Û/Ï¥m ˜z <šºw¬>É1ÀÊÛ;é3hð% éŸvú8åž»ì0R1”|c4ÐÔé¶€�™¶ç:GŽÃgÅúª…<"3¸ ~>”¶föÎÌQÆÚÀjs3 \×ÄE3ó�;Þ½û½½‡>²1G_ºÚ|èŒ.ñ¹6µ[SûßüOj¾’Ñ¡ªa‰ÎÔFs@>¯kúìWòsß ó*ÅhՊןW÷Ó×¼º˜ˆ�ë}üÈÉCÈ>áEŠÆÙxí5䦗qËÓpÒŒŒö¨§Ó|.Û|øÑ#�Ýgž¿´µ3 PªZ2åû'Z³Á±³ÇHѳ/ô0óþ•w¿måü­Sx`u.¼ÚBp01BD…%¢ìÍôz †;”ÅýÔþÄl=Ds9D;À¾�[íã““�(�Á¥ØÙláTûè�ÛÒ5�z+”bôi%m˜òSŸÙ°>ïÒv»ÿ4ýžÓ¶˜:º£¢6Ëhæ‘"Ïæ[‡NûÞ�°•[Û$j³Ñ;ÎØ[7²”ÿ2ùï"(ÖZÄá{º|wûÞÇ7;'s™¤Ø‚.±GJEç×ä¡ÝKÝÙ`˜éPQAá�žRÌ.mýÙtí" bŒ¼®¶Ÿ|×Ú Æ@ß¶Áæûj=tךp“p"»q)OJVQñíxÏ�MÜt|�mÇš…aØZIhRVÄ̉äÄVÛ­?tÏ�{o¿íü¹KV^éÇ6Ås„ «6â}Úš6€DZ4ì@!…BǘôW/¾òÓ?Øú¯ÿêÑ·ž¹Ø-η`p‘…fbJƒ˜K¡¦{0rï²î%á}ç û˜¼|Z}†�a�ý«_‹ô”ƒ.9cô›'±S†ÑÞp¹Ž S$KQÙ”Rb=¡Ì-ôÎ<¸�-Ä£p#œÑA›0ÓëÐX·ÙOhx³¨«£æ&àŒm˜yÛVjd»�ž[<:èDfE `€Eš&Vº­\Fnʇ�$ùpÄ0TÄ9�Þ¡î�oŸ{ô#zê±-8H‡ !‘0Ð¡ÄæBL­1#Û*%�X|“X/T�˜ RMIÇ¢»vvóŸÇà¡£á×]õ逑JñáÞãùûÞVd²z²ØéhH7°]ÆgõÓMà»vì>••�#ä!i””^T´è„ü®S�w¼û6óîÜù|{«OÌ©90q;ê0ÊŽÚ혶Qߟ®D¢Ú Y)lÓA10˜Š3qÁ0Èz+�=<øÛýÔ_þÁömÝW»a5#é̲œŒ¤™˜‰IÇÀ½$ƒØ‹éf/kÅuûæÇF… RŒ‹9@.®œø'?åÕ•eÓiQú°¶˜7îOVÈëÈ <½Q`Tº²GS4)�VèÊsƒõ+Ö»S4¶â@)æªà´p6Ã^Í�׬sSëÔ;×:§^ŸÒ \ÉAf†¬À¢ªB#t8xG÷í‹sw¼2xù›ÅkO‡õ×X¬{-Ä4¦ám“u¨¡nvŒ+k¬×Ž"G€Z8 F¯®Ã¹Cñô£Ùm÷gÇîÚr‹9»†Œ¦e.08+[JSo)åu X+eÓ=ŸŒ*.«J,j&f!fATÝ–Ñœ1\Y‘�K€i™Å톲ŽIW•HsΜZ®Òþê3[—ûs'¥-ð”J&& µ„”MoÙ˜¸(Ħ]óxýJ–>-«=6a–rZj;R¶:öì#GÏý÷ÿé±�½÷Ô¿û­>ûĹW.Ï ì�J "Q¢ÀDM` ãP²<Ž‹u ûÈ�\{wÖíV1É$õU)F ãšd+ sƒ‡ïkÿȳïyï‰cs›=½ÐƆ“‚ŽJ•¨åþaC�¢är!Èý1Óÿ`Ã9»°‰Mí_L�Ãú C¹SvÉ>ÜŽ®0¡k>ûò Ë/¾r®Û}„àÔ¬Gó*Û·/ž}u×VÇê�Zÿj~ñe9ò˜Â¼¦ ¢Íéf<þÍ-³‘7•;C„ƒ)ý4m@_´·ŽÏÍ9&«o çŸß¾øJ±rYûkÒ¿L+�lHu]¢žþmB’š6ÌÆ™j2ù碾³9öºƒgZÇîè¹M�ÒÙd'XÛ,¦bÊè^f5g÷Zú†l¦µuqO›}½Yªü®@2^D!Ts1ä—ÏkØ‚«¦ýÍ(¤Ô¢÷ì‹«¯œ;pê-Áæ˜\ò”UnÛ'ÀÞþÆ¥º$»•awJäòyn|à±ÍG>ôgÏüÌ­é«—Ÿ{>¬¯ùí�l£áÒ2TeÐ ØR6Vm°r^\_dk§±<"T¯ƒ ÚjéâbƒDk™y$<’Ðӌ߬VŸù$câwT‰rŽ–y‹­Áúæ•— ùŒêÅÌ%ÁâÕpe­xòIyû=óÎ]âNBhÛÿEÈÆcg 7Ë{iI´‹—œœ{ϽsïxàðêÆ©óç:Ï?Óé•âåu®nçÛÛƒ‡¼{¢®B:ç‡JFt7NäÇ4¡�N¸Øë:Ð:qBï¹³}úˆînõ°&v>j!2Ë=r±0jâJéº×üñÆÅ´Õ&�ÒׂêÁˆL®\<ü…/½6À²Â…JóDk¿|07wà—ž›[y1îåÒ1@,2©?ã­R}m´ÝÜÜŠ6-‡ 1 ´¡™€%qt‚xª@Z,ës™qÙq™¢@ðW—PêÔ ŸßS_xh×Óëaiæ™)ÀhT×Šæ ’³s‡*ÙKIV§ÇÙ«$~ã}a»üu­§—~Ì”®Ç¨@€f´V·üú…¸òŠ0Ÿä Þ×’ò‹Ã,hè‡î—¾ÊÿÁƒÙü‹Î*[ZÕœSZ¦Ýjf›þ�\?xö€ÊZoCà9PÝ áB¯Ó>qG÷]w.z[ÚR8µyM�\Zò;M¬K%] ÓI­-M£·joä¶CÁxÁÛ­b�™1J$£Ð …Ètÿ[ÎSoÝi…))dJ@etŒnîkO»g^ôшeÚ’0˜«¥J½¡rCÀ.Y�ª—¥�¶uÑΫ{ðŽÚ"îsˆÑÃÒJͰÕÀÛS7^ÁpP3”ìx_"êXÕ�’¢@é•.$‰>1†Vƒ»æÿJöÀYD‰/!Ÿ|ð°è¤P5htÞJ¸·Vš…šÁÌU©gÇHÎÌ™Žš!3vZi›€ +î{@¡)MMᵟŸV·.jÕÆ|³¤cÓd?‹²ðÕo ^8»´xÏœ³mLÝÈË ÿê5¦›ú'ºt¶¶�ýü¦çëe€X®Ózdæ"Åb´5@,=àWÞ(î Ô{@Õ>6!Ëp3¬´R3 (%iÎ+]²œ”#W� ʵçÑ�Åß\;× wœSùµ ^,Æ 8þÉϯ¯n-‡¬m¦‰Ø%ÍLVÒiØ� 7WPHtNŠõÁÙo.ÜþN×[Px”b6¾zWÞ«/HÍ^Úý®é„Ø8æ(¦M=®#Lh•›U ^�€ !C6±tšNTš)¢ I$ØéFÊ…Õt~L\£²8Ú\“C¾Î»¢FBkîº=�íhóš£ûºÔôáâTé&€!¹U\±¶qîiÆMnÈ󻇚HiÃÕÈÞ+WÖ¾ød|àΓ^LÖ·òLwN`@ßxcÜD© +¨À<´EŒ`“¦Õߥ)[:�§�Ïšj`µÿ•ÚÃHž«¶{Éb 4Cž°ÉJ@<Ì9&Ã*ůæ„7c1ZH¢ �zðù³§>õ¥gUލCNëÒ2pj¡îË+ßÜ À(…ù6£^|>¿ðbvûmÁœ–dí¨˜êy¨Ç§Æ5‘™ûVS6i3c‰cUèâЀ¤èj)¬ b PÍïX Ò%;SKV6ìi¯o“7(k/ZPˆA,î§_ãË.ËÛLa3ËõyX ýH R Å£`4ß<¯¾ì-�&CÒ©›R{31£R E»�ìóO¬üè÷m÷^£Ï+ˆÚr×äÉ®~·|QøÒ7ÅD%�&ÖÇÒik>×`Ãå||�.vøÛ„Z4:½ lÁŒpˆ1Ô�0„1¡rgUO{So(ÌШAÝ‘OA¿s¾câ� ZAíÁ2¸ÂX6¾ ô›í 13 6XÝxñë�ãÇîÑRe™.úr/\RõÅzÿº}„Ñ÷³N…ë #¼†•H«9ÃÌ\ê¤ £™XœP2*¬à”u¸&Mþ Óª:10+u„*¾ŸšLB)(¯DÙ Aíµ6Ü“Çòú[zC=ë²§UÅ*Ï9*�ËRÜO¿áí_Í5[oÞZ@¢¨ÍHmù¯}kã;Ï>þÈ2t«‚Ã�V³ø5Õ¥ ï�ý”k&Ëõ4L,ù£;$楴û²¤Þ„¥Wf£‰r* ÔÐ@?I€bJæ�œ>)ùäÂP>àÚšÀÔ»VÑL,E˜ V×»¿óɳ} E2Œ0¢•Œû¤7îO>&Ó¼¥Z^Ð ;ÿeé�Á™©tZ¤É0”‚Ù8ÓȺ­0|Èä ké"Ç©,ûSkcÃUK�9›Dp\£æÖüÃXíÆtµ¸ž2d¡š"qLý®’díÁJ9:¸_)ö´¼�icRñP¦1�~R07¶}àüöù•W¾ ]SF›=—”Q —»¢ç‹vðE&¯¬õ>ó%}ì¾Ûçìªeëð@Ñ¢z Æ>›±û�EFî˜×qkÐnÇÛagÈkÄ(…°ÚÈ¥S?Ú”i®áuÝн}XQ,aÎŒ»gþèKøÆ·ûâ[6gD�<óqhBË Ì°o)!0:ä&P�å+ý—¾ÞÎW ‰[Êç+C‘sJ=Ù|MÉÏR\I!W{N�¼ëMíVgÙ,JÕ¿S™ÍÙñIé—¯ç³ãÂè�jÍ)[W5³"œQ/½"ˆq·0æ}#øóh8ÿé'^9{iA㜃Ð@jé8Ú]˜OŒZ¾ˆ)KÛ-RlÂÄRz,oj¦ ¯j®ÞÛ8»ߥz#‘-¥.3M¡+ý¿úÛë›ù¼i,1?)N»Œ‚äDÜH¹ÙqæXDf GÓâÜ·ç.?›^Ì]6Û;Ìn:ØÇÒh¤¹V�oîØÜóý÷^ 6žÏH°=3jhÂÄWÔ“ÄT�Í»8h .m¼üu+V©…™…¶Ÿ\ã;Z‡PD•h¢FÒÏ?õüÙ/|uóŽï?’éaN ªtä)3Æôö|£—®ÿX^¯ÒL‘¼+I‰a"£ë~ñ)ùôŸJðËŒŠ›,ÓÜ\ 0A`òŒZäöùü¹/öò•šg¯Zå߬}n¾Ä”d4Ùñ¹õ”•¦2½þMŸæt`×�à’”ýžÔ+ rÔoâmÛ®÷v—¡X5Óñ•˜©ÆãÇßøåbÂÎÞ‘P+Å$ª€9®¼Ü?÷¬Ó¾8Æ€H–áW¯Ž’0U sµ¥s~­û«¿óô»î?‘ù×ÄV$qœÍÞô¶I|ÜÓ ‘]³i÷fz#Ê›eõ¿ž¡f‚š'çuih’ùµüÔ¿øåW.l- }ÑóqÿïL”ŠTeoÀ(Íì.ÐõéSJ(�–ØÕi°u»ð§|åþÞßµáçMs. Ä¢ë«f˜ m �kþŒ¢ÈaÁ6íÐŽ¸«vê•lá¸7ÑŽÓfzÓܯo-†éà¾Î~ì!$š)zÙX5m€#œW­fJË�Îà ‹‚F?¸\<÷Y¬¾Ao.¶ö™,·¬[�(¤ÁQ @¤’Þ ¦íîïýñÙŸzæþP¬ Ø(Óìþ´Ñ6‘È¥)bpº†Ñä ™>èÇ봇͠ 3kºxtÚìIQ§­¯3µ§ÎjÇ Ë‹é¹õ™4ÀMø#43a�N�±-Æè4vú�Oê§¾|>vŽº¯m…SškÙ�Õ„ë©™¬«ÄpÀÞM@x7=`ê�†ó�xr4�s‡Ï(² © ĬÊN>ùi¨\7ÂdÌ:=[ÇïèàkªjMXø=b乇#;ÝÅàþƈyM–³’"l¢_FNÝ2R;Ø çþlðÌgQ¬‚¢-ÓÅÐí½&»7Ã.3aت† ¥G1¸°½�ÁÆw¿ïA§kŽJT µ�;–]´á“Ò4–aµxŠk׿¢ç°¹ªï;ë?5®eÚ§!ôø®ý™]à�éwš4¯3¾d“7µæô΢&@›$¢˜:Ç^\yìø<ùâ¥EåœDs&*.4¿Ý-S^¸~ÆuøfÝÆÏJü°-¶DÚ­¥;¢-(a~Û¨Ðv+ç5—³ÙË0wîžøƒ ˜dÍd‰ã�Ò”W~òZÃh]›rœ»];qã½T»aJ¾‘{@è·z²ÚÒÊ_ëÐ(bêL bôƒÎúKýo~ÆV_�PÒ/™Üõ¼ÑŒ@MÂÀC ÍeäٗϾåÎûî¾ç$pÁÅ59>‘–òëÇÜÃ{ˆÈÝ7q`V¸íì îµkt#`�}úcM^_d9õdsfT‰"EÆ Z$y6IDATµ³¥~ëÑòs«¿þÉ+9O1f"ƒ³è�’wÎò7wàžpÍ ÀŒV„Áz{þH6w&‡‡ `¤íb’ºž¦YMF#‘cV�³éڽܳI »RºÌ\Æ5›þCÝDF‹¢¤A»ºŸ"¼ôEèjŠœ)÷¤hI™y¥¹¡  ¬iJbh°¢È^{mó}ïëâ•̮2ÀD•#Ã~ÚÓ8¾>ŒÃk›ô›~hJ-¹·÷�­!fÖf.o¾ `üð” P! ¢Dðf¦YGçùÜ“‡þoÿóŸ­åÇ s¢ê‘C1fÍŽ¤×} Yq]ã“/½ãþ4øh¦EØî.ßaþP„€‘e½i�¸ 6ë±Å÷fKÃf£ÏÍ@û4¾dM•nÄ}7ø!f…žìáüæ…¬ù]b "Z¶å®<³ý­?�ÍÌ£T 嘑kÜg– ]ëm­lÚòd¨æzçί,.ºw¾ý¤ÓUä�Y0DÖt1P`ºé`’âc|¿7Û-cÃÌ&¬ÙšÿÍ'bì­Üè ¬fñx7�þ´é ·˜¶ ¥)42ÎÝ}~ëÿÝ?úÓ'_öÑuLU, £JŒl™u� gxƒ›mšq¨Ÿ=Ú(4’E¬ƒÙÜò™œ=£EBM˜ýÒÐh�¼îÏ�Âf<¿4Úèì½> ›SîÙT¬VÏÉ: áøÔ;ÞvV\ÞxdÔH�mÌ*ŒJzQ½ðTÿ©ßó/y„£°Â¤±\ý˲ÿ�`�Í:ThA—<b@l¡÷ÚK—.÷ÞúØé–»bq[5'ƒ41Œç/Ü«-»©ªÓ€(» Ž&É}ïÝÍ̶—àÇë~Õ=_|mÕÖú×ÊX:ƒ©Çk7«ìw•\MUØ9ÌùûŸzùÔ÷�žxæÜ|psˆ"Q뚈I!Q¯lÊý»?Àþ‚Y¯\=ésU h�<2 ¸ð-mÿ~yû.@À‚ˆ¤ƒŠ@À` Ž’g�Ùš¯Íg×4ÁFõ!ÐMl6Ž6ظ§ ²S–úšábê}™&8ú÷ZklÊ9ýu–ÁIn“áñ‰[Mh&ÔáÑùMt*”F�©3%Ôè#Ršo+¤›ÅµùÕg7ŸúYÉ!–l„C’¹t+©›Ù§=U®Y�ñ¦›Þcl£µ¼ *1Q;S;Á¬ÏÞÏþÒŸ<ðÖŸúðÛßfJ ÏÑúPšv‚3sÛYü®Ãå…~zÒ€fSöh6/^õérƒ’þNœ‹Õ�²áä¡Á|Zå†RóÔË'�ïA°øÿµwæO’×}ÿ~_Võ13»;» ,€A\$A˜¤H�!ù’#–ììŸþgt„¥ùƒ®ì°²#vØ’aÙ¢NK2�¤H� ‚&q,€½wfg¦»«ò=ÿ�UÝU=U³];=ØÙíü`b1S]]•™••/ó½—ïf²X»|µŽ³�jW¯ç-ŸM LÀ™ýŸpðF¥e=NêÚ‡Þ?ý«¿ûì7_Üi—{O¯H˜d0Чj0™XëÐÔ¹^ós7¶Ä@ l]r„FÔ©íŒòd==ó�GŸ&+²�ÒˆšZÛ@¿ØÌbտ׉lñ;n�í4ŸÏ¶ƒmö‹Ö¿ètßÖ´ÎvÊö,FüƒÊ�Ê_D>®¿­Ï¤ºfFí•"ÈL�‘ðB/ôŽãáäâøÅg&žOí,󤑀ßw“Šhlìq�`{¿�þÎéK? !4£ùÝÝÝ·Þzûg~êã'O —,ßvÖ'sã&bõT'�%mÛñÞZ­;¥Ü;ŒjqÍä"ÞMGM[„ú¨ìs…¾¯0^Ò¼©’ [{l/ý±ßù�/þ�Ͼ9±sÆÆ2aß̆PnmïÜž�Gkå·²çÞ@ƒ@� i„Èv¶Ò~šnÜç}è�j2‚äÐ>´†T{·ÕË©WëJ¢›?ÝA ï.×?àmèX÷唿møïݳ¹¾æ‚\èUDÍ$|{'ò ãמ½ñ-É.'ºcæ=i"A¥Þ±Kh76«n(H3z£7˜PÄ%Þ¹4Þ�üôO?ÕïOàUlLÛ…XRWÕnÐ0VÍÛó†Å¹òÍ­Þº¸œÙÃMÓuŠh¾�Žó6¯¹ÿœ†Êw¬ï‚mÂr÷™í[4é|Š w¡‘FUófÖë뉇uø¿÷¿¶þõï~wgò�gO1¢ËÍÚT—G"¦'Ý!x£3 @š'rä7ó�Kɉƒµû4R…ä0¡¦í3Ùõ§s«Ë}¥U´}ÝJÓQ%ËŽ‚çÀŠ7ý´¸lv{lÁc• „ ˆ"…%0K‘mèßúêÍ—¿b£÷¿%˜Õ‹¥{û±°PH*…PQ$�Á+¯¼yòÌÚÇ>ñ¡~OM¯"ß% ­©QÅÔ.R—EÞëŽ6›®®Ã Å_nùîaÊyêê�EŠS ªïB kÞˆþºÛxx¼þãùüúo|íâ�ó¹Ûðœ€ÅãO'S�sºÞêÆ$„0Ò<>ÍYž`lùõl|cmã¾^z>Ë{& ÄÃ22ÈÒù¼ˆ zÃÆ'³`”ÓF'yªïR¨n;¿ÛX aÛ¬¿[µÞg`¥Lù¿°¦]³Ï+ì}¯`'Pšqó©¹5Y?oÃ�¿öÞc¿ü™/üÍ·&ŠûÌR£‚JlF¿Z+€ ÆuP†øxt Å$ɩȳÉ�,ß럺OÜI¯C"%@* F!€’ÅŸ‹ëèË*,¨Öï¾7§só4}�S€æ‡ìàò7]¹ñtk7Á éƒú1ÖTÁÂQ›ù‚ä}êF²÷ÖÎKŸóo£—_ÕÄ�RŽþ¥ƒ]À 1†Ì–Ài�Œ¢æû4Gº·ß¸rñ�ë?õ“:y:sIŠñØtTxÝN±ˆOÛ¦N? mãÕ"e8L§£­£ÕµÈ­…˜zú×�¶¬g–2Y—“aø¡7¯<ük¿ù¥¿|fËËý^Egg‡•m~ÀÔ«k«´³ñøB€–æj=¹ �R>Ò\ýD·oÈh|âÔY/'rôh L”c£ƒö`N�“cX sa¤ã?-ÒBnk¨m4®¶üt½~±"™»Ž´^¿ù¦¬Z ih)¼µ¬Ú*[õZ¯.x‚*/<‹_A51Bú°tïíñËáßúJ/¿šf™ç^ÆB …GÝöȪ-M©ê£—%ÚŒêòXd¯a ½(5S·öú›W¯]¾ñŸzzc½/ÉÙ‰ÞPÞ ƒB�3£‰†öw0Wln˜¼É6üO÷ÿ´*Èj‚¤Ñ ]CÕ¦!¬ê=¶õ½žun»õO닱ˆÖ¶%àÂÙ²ÏT«b6Ýa2·ZÝ„ºY»ÎŠ�'êOXÚéS~ý©^}úW~ó›øùËwn¢ô4(µT:„6“NYë8d-o°$Py õË‹Šxoše;;>óƒS›–¦9{F¼3u€JX2½H]ÓжT¿;B#”�sør.KÙßu¦Ö|¾PÅ´Æ-ìà-æCCŽú;¯í½ð—þío0¿ff*©o‹†»€m£sY  ™~ÎB±$•B¼‰y¤ƒ×^~}çÆö'?õw»‚õ|2‚íˆ9A Ób'ÑÌ—µ•—5—f>©üAáÍåE¿Èø°´wéý|) · ¶ÛÔç¼°ª¿�–ÐRZÐúÔf©&k<{Ÿ­}àíkúµßúöýŸ«^Îä˜(ÂTõd�ÎA�°�Ž­ØwuzÇÜYËÕò|o“íÁFšO™%ôÎ�ÂLé = …T˜íóSYNÃÕ¿zlEÅA…^Òé-n­®~��Àœe-&ˆE‚,OÓǽ›/ï¾øÇz᫃ì¼z×ó‰ƒuôޏc`6ç «jC<»žù´ÿÂKo_¾¶÷#Ÿxd}­Ÿ¸¾æcjFïÄ„ÎÏ&ÏÕ´Ríó™ÎÕêøSŸß:ã²èZÎî?ÝB»7 ‚°D,¡9˜Â¼¦)û'¹yÚ§�_¸òÑ_úÌ7þø¯®åxÀ˜´´ÓrT=íg߀$¡*¦Ž¨Ú$ß¹¬{×’ázšl˜­y¦êÔèE�xW æ r‘zû½tùáHßߎ~¸Ÿ™r¥úHë/Rµ±šÜ T&F1�ôÙÀF½k/ï¼ôçþÒ³=)ñÞ¬ç…pÊÖ�fw‡�Ê–4'×4çðÅ—/m]âÇžžÈûÉÀÔ c"|¡EÃL³<«�ÍKÛr÷q³}þ–/^õuYÌcóxM€ºn9¸åul³¿§·U0W@édý>¬?à‡O¼ðú#¿ô™çÿô‹£Qr&çFúaýëÍ]Œ÷Q,}À§޿Ąa£0ŒÈüî5î]ö×dp&cßGhÏû¾ÂúÖšPuPo¾�Ýþ€¸ˆN³ÝÛgÚtÖñø"Xû­»¦Òlóª¹Ä5¾m£z²‘J$ ˆ<±�nâú«{ßû3é9òº™zx¤à„ÜkŸY_0{„FAJè¢FUQOæ–¾òÒÅËWw?ùnäi/ɰ£~– };ËV½{�~볨.ª)'§?í1@Útú­±c3· Ü‹<­…úa-&us½Zú¶Eoõ)Ô˜&ðI�køÁ£>ýÈß<¿ùËŸþÊž�d郙ó*cS¡ïC´cp·jßéìãåÔz:Ã6ŸÂ$"IL¸wm¼u5é÷em])ðHÌh)F'›ë£ÍŸunèåPó{iIwë”ríXç�Q­Wºåñ6ãÛb× ËƒMú¸¹a—õò÷v^ü‚\~.åMTúž h¹ 7t\2P$Þ.<—@’d`®T!é /^yûÂÍO|ê£'Ny/¦úÜ-¼-hS—©ƒª»`µÊ9FýZv‹:UÏZ¬ÐE”ùÔ€r„-"Af�~p9•”�7;À/§<¿pËÎ’ >ì‡'Ÿø‹/�ñ׿ñ�—4OOx�šAMØÚóVmzèóïÒ#xô@Œb4¥ÞåÍ·ÇÛï8ËÖ§œœÈ,ÍÄiÅqºV2Û?-¨þ~(kXgÊÔ±À\O¿åñEÊY‰U2¯5˜ ¾ÄVù·òUV?-^ÛâHmq07²Ô/Fä0%&=ì ó÷ò ߨyésróeÇmSƒõA‚c lØ>nß €x„# 뷢μôðòÖ+/½÷ä�=tßC IšÃ�LÕ,l¤˜¿ªµ#)OK¡�4¬z÷k·®–ò‚Ú�výzÓçÊžÚ�ÉYY{,O?²å?ößþ÷;¿öÛϼqñL.'ÌAÕC…š,½Ø—Òv‡‡§7`”"Ë«‘À^ö('7V¬Jé� ¤¦)m`Ú{õµËÏ~ý�áÉsç{ é;‘AÚz?VŒƒ½Tc�³¤óW‹«Ê›¹Z£5WïèÕs$…o“�UQÕ¼jBHÇßhŶneX8CŠô´l<–÷›¤�ç­Ÿù7_üÿõ;·ÊÝy/“±qMÈé.ášö¥r³(öo P¬ÈDúIª£Äßô£+Ù�‹Ì³A:H\ RIO§è‡cá�ƒ1”6¶ 4ÝÜ%IÎ4>¨>;n ZšªÇNmñYtôJ¨…ÐVôMÐw [Ú�bæ4à%ñŽâÆýü{ûkãWþÊ.ý­ø«)sg¦JOªX´ú–5èZã÷³�ö†"8ݱ¦#0ƒœ11IUN\ºš>óÕï¿{yû±'?uúIozŸ+rJˆ2Ñ�ŒÓ°UT~xˆŸn ¸Ú9UPw °ÝèîžuíH˜Øélƒ‘œNÙ“Þ)Yƒ‡}ÿÉ«ùù?üü»¿ø™¯>óìögr*M }ÀM_·{JÔíµV=i�zup7$�È ª3G•TÙSIÌTF–mù«ïbçê@|:ìçiß3ežÒN:ƒ˜Ñ´Œ=FqT4ÄÝŒÃlÍ1k¨O¹5]ÏïxÍ*õGÖÍ8_µ÷TÍ£)’�Ui¦BžØíãšl½4~ýK“׿̛¯G%3Ñà _DQnXîv0U˜Lgë£XF‹ÓÄÄ+¼§æ.gkßûÞ•o?÷æÆÉ³ðƒ½áII7�ë™÷Þ&fæLèÉâ¡4Ô×ncAÛ­ ­óËbÎÔÒµ&s[5 ZŒþËR*]ÖßHNžÅÚß?7JÿÖË¿õo¿ó»ÿé•·Þ{@å¬RŒ` õô µ7�hÎ�“¥ Ž‹Î¶�›h§j<¬V¸Y`tŒ¾p�Å‚I 1:s^tÒÓ‘î^Ýx7ß`®')Ÿ�‚ Œ OŸ<–ºªrî ùNÓ ¢ª åþÂO‚;z¹ï³Ñ}sºõh>J\Óì‰E0g 3OdOzoYßnlŒ_µ7ŸýàÿêÅç©Û€W&ÆT‘¨QIÀJ?wï ÌdÀ4ÈkÐÁ1¬SЃj0ŠóšK2|÷|éKï¼ñÃñ¹G>ýàfÏmºôÓDáÔ÷̈gˆ'\íÂÓÙ)hàA� èÒuÀ²m– ÍèZ©XËïsô2îbNªôÙ;ŵÓrò¤ï=èûóêÿå.|úw¾öå¯ùLõì5)³?:éµÕC«kCtþ µA›¾¹<Ð"ÖZ=‹º €ú�x›hNäB_ôW/.ó~Kwß³k¯ºìbÒ·¤g Ô�ÂHø2æ(*¢ß¦;.»U÷.±´–¿5­Qãñ}û¦„ðe¦€äœÈz2YÏ.è¥çv~ðùì�o¤£·»F…æBÐܦöÌÖ|Ïw»�ú €¥¢-'H„H2Bæ=j�Î{ËŒÙäô ¯\ýÜ—¾ye;{ä¡§76ï·~*ý¡$'€Ær Ô‚¤™3Az2Y{À­=ÄÁCžO^ÝùÈŸ~‘¿úÛßü½Ï¾}ikÓܦQ¼ŒÀÆàðVx@‹—ÔŸ�X'vöGGPß¹ê�‹LÂT«ç·Åx™­Ê¦å þœ0äb9`žb"€£¦ÁœTÀDս槟v÷?�œyZ�åÜôÖ‡!„�3Ч¢°¤A)MoËÔk¦æ.ŠO6DkÁœu©ùÌ>ÝßÞ�t!Í ›ÏŸ»zyý�°Åjc†afÞ·�ΪGƒùWÍvê ¼³I‚‘³ú�ÉÕ7ðöW'×S¸+›ù"®‡§&¦R)«�M«ñЃÐ»Sû#ò²ei&¦¤UÆmÕe‘o±å÷º9âÚA]¸Ó}ç¾[®ŒµT¦Å?@Ùësí$ú÷ÁÝÞwýúÆ3Ϧ¿÷Ùç?ÿÍ WÇ'¬·¬’š{­P'£HrnSíQûs[­c?¯¤+Cç„ Â!ÀBbó‹]ìj¨o»[›MO°2îË�)x[YØ? ˆÉÀ܆ Î=�ž}Ú�¸û¼ i š§GˆE¦BM¬ìáŸ`-Õõ4 ‡—¢š*ÚülLšÇu©hÛì%­‰50¢í‘šîÛÒø0¸ò°Q­°b×WȆ2:Šºb[@š˜dó²EÂ|àwÒÑÛùÕÿ·ûÞsùö1¹QzñÏb4Wtß•ÕTƒ;3зҜϯm&k ‡�Ù E›ä ˜Ì�°;ÂQ�ä“Azåãu¿ð/>òóÿèÑÇαo7¨7™ßð£+ùø²ä[âGPƒöÎYf!žDEÀsÿÎ=”#Vsùg%«÷[™?©vŃ�wå ÕMq¥«›Ùü©Ø4�ÿb (0gT2+$sØlç…3— é»õS–žðÉ™\º|ý¾¯=»õûÿó;ý\vcœÒõ3#DŠñËæú!÷ý»p—5зqç@ó‹Ñ"˜IµÑt~o™˜ôÕ��µå쇓³�»õóãôA/ð‰!¥A0IlDøŒ³$ì\eHPC?WÌr/G)ß›«­¤:ãhñ¡^ ³R«èØþ®<<õø Ã@5VÕÔU”Prd„"5¤0G£Àò; nÚî;Ùå—³K/øoŠß‚ŽLòŠjz�òwä.@[?¯y©i¸‘‘Û‘‰mˆê‰Á?ÿ§�ÿÜ?>ÿøc\ëÝàdÄ,Çh‹ãKêßõº%Ð$7x ‘˜ôd^<ÒÙTdV8mÊ»ÀB!RmöJÅj¦‡RÈ4ïf·®±ª*¥© ž²SÎ/¾C»±2Q„À„JP-á ¡HTCÜ1z&KO`°É´¯½éý�\¸zòósá÷ÿðùo?¿½½{r’œ4qØïLÑ:@ß¡™~+%8 ƒZP õ,r°é6ÆÙO¥'žtÉyo›Þú*9¸Gƒ,…¥ )Æ£)ó⥙Ø Ì5–¦š8iúb”ßïмÒmœ yŒÊêÏîkmþþ2åk9Gœe,wºYeåAdåêŒ4M…Buùnïæv/~o|å{¶û:u[¼š¦DªœÜâØ�x«�ÃŒn‡Ö“|=Õ~«—\zðAÿöü?û¹Ó?ú±nö}'ùuç/ûìr>¹Îɶù � Ì,$¬18­äž­”MÃŽp·Y´3°¥ÓVÃ*Öm¼û§ýlô¶©œÏýWg]ì¼£€l.§nØ7áŠDvA”E ¢ìSqCöO"ÝÐÞ0OúLÖ÷ìÜ›úŸûâ¥?ø“Ÿ{yk'_ÓäÐ7˜™ßçJÀ- zGVA£y¡W¨QÔĤ�ô~Y¸¿ùTºù]dœžÊ\ª‘ÓPÆ®Š4Í?(2–—-YIËk™ÍùT,²fž¿ð�ç˜U§,äîI+ŸM±b-‚UɈÓBZy9sâûï°—p;±˜\Þ»q!»öŽ]ySG�^Iõº³ŒÉ`bk¹%ÕýQ4¡·ºTU�–Ffdîhæ hvöÔî'?vêçþÉ£ï§6{ØN$É2f¹Ë¶áoøüŠÏ¯™îÒç4s†ÄÍ霯6qÚ´¶X÷ìj3X¤ ,â±Óx)+%’9ÞƒåŽ Š°O7¤ ,°—Z¿çݺ—ÍçnÜ>÷ýkŸýÜ¥g¾òöß´±ß´¤o–˜LÙÑ.À¾·�_Z²6Z …TQs¦‚™úÞ̼$>=ÁÁýrêqwæ#\{˜ƒûswÖ›Li…d`8™œs65SÎb¹4yÚ5:ÝVÝMm1+kó5+i0Ré ÐD€"ØIÓ�æ€^î�îr|Éo¿‘]5»ñ†î]D¾k˜ˆjê}ªž°‰“LD¥ëÛÒ½MÐÒîK¡~ÕLG€øa`fÌÀࣛÀx/Øö¶}˜?ó“gÿÁß=ÿÉOl>t–'ݳUáÇÌw5Û²lºG?†ÏÁ0ŸõE´,¨N`U EÌ{ÌNnÝýÛæÑÖœáÌÒõ»ñ›Vq—0«–…<ã(’Å:Eq&"II_dMzë–¬y×3ï’íÉðÕ7Ü_?³õ…Ï_ùî÷wßÉ\Ž¡`hfä˜Ìa0¸�¿¨¡œ­¸«óB›ZxÅÀrV„QP)A0Õ‡£ñ†Ì äÀä´ë�KN|Ào>‘n>Ôžõ¶–c]e¨–@$µ‰YÌGF– E°³}w®t›=Öî-ÛY´Øfop-ÎÒL `Æà ESÃAGŸ ËL,ùÉõüæ‹Ùµ7ý�K¶w“-Ñ‘C¦:Ö48ç{´TA/Þ» âi²ÐD¯[“¬‚˜Žj3@C¢  €$,x:�Ï0Øä£”£õÞøƒçOüÔ�}àgÿ>?öô¹În¬õ2ço:ì9«ŽE=,7�˜MÔÆfÓ 4KÌÓ4l¬©úCIÊF‡¶Àh3wÞ¹šW.[ùneëÂì92xËšÕr*få)B$�9ÓÇ�çzd�ì=â$\OgBu=MúæzÞW·6/¼›ã[>ÿÌkÏ=ãâE§vZ¹6êû`+ eb§¤`½,É´é/MÄ@qzá¡Å…ßê€B�ø*™ö@:SѪ€D]¢ý�ôO¹õ¤ktƒGdøÓÓpŸä&�11ˆç*.­õy~S‡FÇîPè¢néù3ÿ�döEf*)3§»·”!<­gšXŽì&F7òÝË“›—Æ7.éèªÏߢîR=4§*�ÂDáÉ …W‘wªb/å²:n­mWAÈìÓ™.ˆ¢PÐe„TÀL² ˆª&:¡�N¬�¸Ÿ?þã~ì£ÃO}|óч›ën­— �7f� dŽ�1Í HUXÕ`k�“Þ¢P�Õ­Æ^­Ø�f®�6÷ek|_ w%3+}—‹ÿj+ìàwÌua+`Ø“ž)! *¤c[Ûžô/mÙ÷_~÷Ûß¹øÍ¿Ýzùå�«×ÓÑøÜ:$'w•#�6€õƒeb€¥°ÄWlZõÆXŽË±c®3¯š�ê zQÕGó�ƒ§ G3QƒŠ*4ëÑR‚ž¹¹‰1K4’œã{'Ùß�ᆞÖÞ£2<“ ÖátCHߘ@zhˆ;MþTT@k}¼6©éÒœuuMÅÐæÔ|Álâ&åæœy�'rbBLh“|¼—ï]Ovßö;W²í«:¾®ÙuäÛ¢{Ž03ï‚…P!&‰“ ÷âUr0çÂ(Ô5Ь’ÀÔ¨xYi,Ô>!,®/%·SB §A•0UhF½9HöÎløsgÓ§ž¸ÿ©Ÿ{ú yüÑ3››ý“'“ᚦ½‰¸ ‘‹¹}ÌLCܧéB¤gÁ°ª&hÅÙ¡Zݪ;òÜHV9©ªÓ±ÊûRU„hù\-Ü·uá 0˜y’")�=Ó^–ñ掿¾“\¸¸óâ+W^ycï»/^{íÍìò5ÙÞM”‚ÄŠD )c:š§ C£(Æàâa„¦Mcú4ËÈÏq1¤eÅ×€ªÆÞÚõ;‡»¿`å§A¬¢êé±×–Tš˜YØÏQ8ÈŸO¡ôàúLÖ!®w*œ¡[KÖN�gUÒt,~èE«O¯(f®6µò6¿Eå—æþ ë"™z;Tº‰UúúW©‡Šòÿ‚<�\·lG'ÛȶòÉõltMG[æG–� 9ÌÂNˆ°8€Š�~¥Pˆ7ÃŒ “ qÊŠ˜Åm�åÈ—ºÇ�Ûê·*ê ba8›SÏvëNÕêkÎ�Õ,'rÓÌ“¥Vºë¾œfÝzG7aý¦~l`:2ÜF˜��D é%¨U·Ôº,�þÝNb!\J_"-=.PnÆ)lª¥k´LuýÅÒå·™£y§nÇѼ5ŽkÏfxCXÎù ?‡8öß3°§’f4u“Ù<ܦ¶A1¤SO°’Æ: …ì5É v$léŠ ¹=ö·Ò©¯tð›-Ê«©«0»÷‰à heV[ÉÜŠX*®Í™w VêúY· •á­æºumKëÆ"¡ñÝhÕ5­™3NÂ’E ±r#Ê�nõH'U((ýÐ Ô©¶¦P׆ӤŒù7 (´Ê¤§i…ÚŠ:h(Rç•«•QQ÷[ôÁƒÊHô‚>À4v{Y‹éùS[H)Þ€ú]¬òïJp(оaa�']Û¶ÈÍš—líŠò%H{ã4§F4˪Tæ»Ë¾Á¹ª¬oŸ¢w[´mÁ<¨MW˜n cYŠÛé÷�#ûß«îžëÛÚÖ­n£í9¨[>¨Ûˆ¦5û ¹¡7;›;<ëÎ ?ã©È˜;ÌÛ˜Ve^˜"¶+�¸ÁW.ÐènŸ®µCŸ®Û¶+vMi~^´r wèÄÍK!®nA‹÷rýœÚ_·ñPïÈŒãÎw¾È2è¤ûcûirð7¦aɹÔþÝä3�#Þ´hÑy§HÃbÞµïQD"‘ÈrXÈ¡‘ÇHÉ´bëñH$9tg?¡«Jµ¨Ç¬¿ÓU‰D"‘;ÇB#{5 Ç1 ®"‘HdE‰ ‰DV”("‘HdEénhñGnÓhY5zß×YGž4|�D7sZN½ØqC×D=]¯m?ËeIûŽ|nw‰Juý®ýyYõ½Ëûÿû°¸Ë[(‰DîQ¢ (‰DV”("‘HdEIŽ:}¯@TE"‘Èq!®"‘HdE‰ ‰DV”("‘HdEİTИ�³ÚÕ¯vÞ{Ép§âÚ/뾫—ÿ^ånޱ?ßQÊVëœ×#‰D"w7¥ˆã$‰¬…ˆš‘H$²j$Ó >fv{¢h‰D"‘ãI´œD"‘ÈŠ@$‰¬(QD"‘ÈŠÒžàqäëzÿè`‰D"Ç‘¸ˆD"‘% €H$YQ¢ˆD"‘% €H$YQÌp4»À"‘H$rl‰+€H$YQ¢ˆD"‘¥}@×|Õ¯Ö´I1'p$‰Gâ ‰DV”("‘HdE‰ ‰DV”äð—Xœªm Ú"‘HäÎW‘H$²¢D‰D"+Š€?†¨“‰D"‘"´ôÔ7q4ˆ¨÷�D"‘ãCTE"‘ÈŠ@$‰¬(QD"‘ÈŠ@$‰¬(QD"‘ÈŠ@$‰¬(QD"‘ÈŠ’Àª2 ²àùª,Ë÷?ÆŠD"‘åW‘H$²¢D‰D"+J‘H$²¢I>€ºŽ~9ñ…ª×Œö€H$9ò‘H$rWÑ]Ä�>‰Dî nC4„ZŽr"‘H䮣³ °?þþ‚é#‘ÈíR�u­Â»Ö¦iX…º/Bc;tVÏ$ìÜž¾ñ¨°ÑžLÓŽvæ–ý¬taC²kþ€¨ÚÐ7'Ø1YJzƒÃLŽ"Ë›µôçê~—£Î.Wm“¶{-+×ôQäÖ> ÚÊÓZ÷¶}K°æþÜÖ™­ù£;Õn-}Ã@í&ö�R|ÝF4Ðn��ì˜GŒ·–üGÑè�Ëyob šÚáX´ÌѼkô7.÷¾íƒÈ"u´Î9D+‹'Ü\ß…ÊÉ[?ǹ/,¥”ïo»•mBkl‹ÖËBJ0.-t{ëwX—Ò¢Ý/B‹«Ëvnã96_‡¼ÝffíË‚Í×4Ð ‡·¥Ý×*ÿΗ¢~¶ý�…iiÿ£iÛÃÑÖKØý¸-|rÛ8p§ÚmvßÙ?·hŸE/®p ›j…ÝV¶­Î¬¶$Ç­½ë*Ù:–ó^…€4ˆP@oãŠó2»í÷…·/=Z/i­¡M ¥ÖqY÷5kSo²þ»5}w9+à¶ö?‚¶=U.­ãFÇѹuf}§Úmz_ηI[¿]h|&-¤y_ZB˜¶jÍIÛoq±[Ýë6®¹Hù�Ñ pG±–ƒw¸}Á²î»ÈÀ½È½Ž¢î'Ž˹”*tëçïg»íWŽ/ª²Âqg!P¿qÛ ´rÎ4º„u ªëv…ƒ.uÐÙ·y—{ øÑ½Ø>­�$ö‡»ŠÛ7¿r7<÷ªj€fÃm‡K�àQ¥„œ Fë:p4ëà:?•`åX¼I:—sÕ¸W£†´Ìøb¸Ëè8n´�wËs¯»oÎ]$äb ž*²©� YjûÎgÇm_u^iuüÂ’Üï~Úý÷¤8 ¿ÅþpqãÆ]ýÜ�µ@gã0É ¤ùÿÅ®ç¼Áï?%tEXtdate:create2024-01-25T21:10:59+00:00 ´±$%tEXtdate:modify2024-01-25T21:10:59+00:00xé ˜tEXtexif:PixelPerUnitX08‹*µtEXtexif:PixelPerUnitY09I@‚tEXtexif:PixelUnit1e–ÿÉWzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚bidict-0.24.1/docs/_static/apple-touch-icon.png000066400000000000000000001052341524342314000212720ustar00rootroot00000000000000‰PNG  IHDR´´²¯‘e cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYsÃÃÇo¨dtIMEè :¼RI.nzTXtRaw profile type app11xœ­�Gb\9–EçXE-Þ,vÜûõ¹RdÐIÊÌ®ÎJ‰Œøæ½k€”éÿ÷Ιÿýï.XLìÉžeŸþ/øUr/)¯ì?qûåï1‡à‹ÍŽŸé[ïï{7|­¶Qœ oyßžÚçL {û¹³~gWBá±Å—HKOÞúÞËX=Ò¼÷öŽìó)þ»W¸÷¯¨zI®†?êK•·½¾Ãºz?ȯûŠÛfÛúZÕÎdG§Íì÷Žg/×½dŽƒy¼»{ZáòÌ%g=€aõŒXÎéí5uu:—é&­Öß�5žÈ¤Ð¢GÃRõ¶¸”CçÍ49Ú²×æÝ‡�gÎ|�cÆ­'OËzi~¤½º›£0–ÍV£o«·9Fûé�1ÒŤы¯cµ¯¾a~}Å%›l°o_Q+{£ÛæÏÙݵQ‡Måô\g‹«OÛŽu3�˜Ê2›æÒÓÚ>í>ߌ®ÿØÊÇ+Ýó+MvÏšN­ÛžÉër¯aŽxÜäu«‚;1-šÂèºåcoáÌ9mW <^i¾xgˆ1¹Ÿß8íí®¸XËJÍmÏ[®9Î>¡&3˜_‡ïq2•Óù8‡‹‘ia â?tòé…æõ�¶ofvÔ{ÜÕ�äZëí„BXûø>b 1ÄhÉÖ•ö>�D­‘YûaXo¸å�3ɳšwt§�<¾ègiÝ¢Ë�F`¹§;nåã3óÌ´œSÚeOþ+ýotÒÄúqXë(kÛØ³grºe¤r§ÏΞ±bu+Ñ�U]Z ·W¥°ç0ä]y�òe¼¾½ñó }Ï@A ´ÑÇ\Í}m.7O@µ^lg•=NfØÇZÉ1ä±T%`øú…æû7ž� “s|£G+¯ÆÔ–V¬ß³�X«]³„Lä.™^NÒ« ]`ÜžÛÅìËFJ #²§�9wŽôõË޶Gí¶KÇœM‹Ì±�&Îå{Êq?¿Ð|*ðìé�…Vù§Ùãz:¡×±{êÌ]6ÎÚCO³žÍW€Óígu¼r0­¨?v1½"ãë €·Hú]êNѵµ{‰Ã<1¬Ö{-yÔ™3Nœbz׿¦}}Ò¼³_ÂÆè��ÿ›h:ì¿aóÆ\<ù#gýŸ˜ÇÔï>qdöÓC«ë1ç÷?ƒmÞx šf�‘È¿"@øH.‘túUÔb~â£ç;Ó7ž×o„�GðÀñÕúø \‡ˆ ùùoDCŠúsèüC tBê$gÔüÝÖëj©¹Í÷ÑE2 Þ6ˆáï{héû6Mzž·K<èy¦�RÝŒ‹_krÏk|5ê¸òê†)¿÷<&¥sgü˜ÇÓK|ÿôÏçg I†�8÷LÂ+Tß/5ïßêí×o%šqö.®“½ßÌ/³�zž‹~PüýªréuúW"´zðéSÀ˜1}=KMëŸL½fÞüS¯×˜ïuôãÏ"ø½þ ´ŠoÉÍÊ£¼]c3ð›±r{EºÚ€ÖyFˆ{�Ùà6¾BCl­³GßJ›ýu¼Ì§ {¯þ7ãeþκ|?^æý€ýáx=ñëH™ÇPÍy±Þ&@( Ä[ÍÇ�=qû†[˜½Âíí¾,玵gưÑw)_¿æÇúh¡ê“… â ÌWYÿò¸Ñë+·,uinw:>®;3–%£,±m»W”ýLaVÄx“&´°üj8Ê™ênv;”ªYŠu ñ ­ù5škªP^ÖVKé§ŒPÎ&g1#ŽcGê8ã6R»úÙ@uX€¯9 n8¡Ì°™Wï ÿs\�¼àÕˆw·î<ór~¶ÊÈØÈ˹«vU ‘RÅ¥x$Ý1gŒY00·jñ7LP°#°;ô;Ó$õâÔQ=tßï£�²ŒE«ŠãëÞœ²f+ÃãáãŒÐÀ '«ài¶­9dD/‰: Z iÚÌ¡K8ŽÚÀ … ì|9;†�°œS"° †$a’ãŠe�Gkä‚¡¶Sè ˆ¹yFÑ"Ââ›èd¤ßnµ4#*ä4¯q Æ´rt^…žL…~v¨@q_ÇÓ 8ßžƒéê>b…ÌËOBî0vW;[ƒ ¢u£’sÊ­Äpáô»Í3¥86@&þ°æuaPÇ©¾š¶k©µaÃüðôl9kB1nœ9«ñE`µÏÝV™É¹Ñ�[ç`Vp� ?ÖùP1“‘ÉŽÇ­¼‰oòi1-„Ñqô?üøªCÚ¦‚zIF¡n¿ Ã@ßt‰ðsûHR·@Ž!‘N웾ÛBoL!,}§Wq»>á(bZ8ZØÞdF‰<ȽA+Ù’8^à�—x‡±<2ÿ4Œ_äŠ&Ô½`ª�¶(‘<¾L¤Ÿ´;±;|SH~à8)ój¥þܽ. !VL«°B†ò —Ûø±%hqþLò@,ù ph±Qì(,B~Pð|AŸ|ùÛ÷N΢ðrešÎBÈmdÍ]°ZÚT.sFu%�è~¸ _NŽ´µZ¤È®9�7»c¾÷;çäÌG¯óŽg_ÌÌ/®ýdt~qnÓ>ˆ7½ð¨þño&¯´¯L]tjÍ¿~o>˜¼õ'&ï«N›¿3yßwÜüÜóï;^â3›ï-0#ZP T²m§—tðAHƒ."~tÙÍĬ��öG�‚‚@P;‰H>¥ñaa<Óª2Š7¨4N=�ÓÖŠXT�Tu`fÎ.#†qqu2X�—# ÝáK ;�jV»êÅD3ãëð�Zu‰n¬˜`fo *e °sv4ZÀ—µÈN†*jyQζñöÆ÷%‡ßÁü¹Bæy@‹ÎRÁE«– ÜF4/­¢Wœ®— ¦p ® ‘2è‚…sm00 šðŒ&qYJ¶­sOu“rá¡´¡2y+®Ç*àiA…*;´äFQ…†ˆÉTŠ�àý. J€9�o‰éÁ˜m\Å'˜÷ÁÀhì-:I[ñkó‰Ðd%‚«¦ã,KXƒ¹la8Ú‡8/²Ùaã6a9 !qpøØ$æ&ÆÓ0r®"–hËÄTßfÆ�3"d]ƒeg\Æîk=˜6,a ‚øØk9-âÒ œïÄí ³SüB£®ŠŒÅ 3t8jr²1àäqÄd�+¤»WqwòQ+Ãè5W›iå abq‰v‘ƒæ#a®Aéd“±ém-UW10£i³{”㇧EˆTäܪ#É£B j^€ÙVæÀª O`÷�ýÄåâ L„AÄ#{7á1³PôM8Ãa€CèWx…ãµ·�œ9¤�¬‡|¶ÒÝB…Ÿ¯…Ø—f£™¦iW 2BZ¶®ÕV°ß{E…"Jd8>¯„_U¶e� F^Þ2P�^«ÌÇ0‹áœÑqp§Ã¨ö2KVTt´[Ì^³3añhéåXØýþÓþêð̵x–0­+ÅY6ìØý <ƒ„tZ§é·ûKÚ‚þol�ùs÷“·3cî~ðvî± õfîÊÓ¯ým]»æî7×üíÑwƒ`þ|~óyþÆî½¹=óf÷@AYÜÉQEmdjÃÿâÊ`uË ùF£�‹´Ó ‚© [¬m$ �.ÒÇX$DùÑb!’Ý-õ-Ã$-Ô…þ`|äv�àrĸÌ"(Áèy„1ô"Ç�(ÚPâ9AɲH§ƒ`OuoU.UDõé ­Ò;èŠö5‰”`ÝLf!âñøÍt> j]ªZ¸Sñ)°Ÿ‘€8[Qo�9¸õŒÍ,çÚî0Z%ƒÚè:¡ÕDô¯‰@I=ó'Pq“ë9ìpá. ä ž´’m©ÖÝ»p%ж´­Ô«C¡Úº'³† = ^3ü¨ÛBŸüPÑŽL˜ D¨€FƒÐwf®«Ø °yåÉ@“ ¢ßÉ•sâ­E^€iýèMR×R} g¯>D²×¸_¿5J€{–ÖšáFÕ·d°»1 {dm¸ðø˜Ìoǃ¬Jhˆö‡€kZ4A4�k>ǘɧÄ)Ÿe:ʘ� ¯E[; ìqÖ&ÔH%,oDƒ÷+µ‰ýÊG}w~Ã>SÐ�óM8aÍ öô>‡š´ÉòZ‘ÍÐqirºr0²¯H×+F±®[¾©@dÔ^XæҭÑ&©­ý0gÛí`Ë�dˆ¶o‰t¨˜¤žò]2UµZûvˆrdX¸ØtèˆFáZ®è(¦®Qð)½"oGH‰vª¬d§ÒœÚ<+£˜�ÍŒ t€!±*Z È/ ÚZS£R>Âi5B%#¦Q±tÚ¨0-Š ÿЗªwÃX.8íšÆ¢=‚~Æ!¿T�ü´—–U ˜>o†½¹<ó°yöüÖ%}±]öÞ!Y¤ïÒùH÷µÏNð£ü³m;±G,|®Y©øú¬Ê“Ž€þìzúB0vWÒÏB�hì«C¨mÙîØi…�ìé Æ†Br¯ O“Ú*êê%…Í#]fY 5æ�·%Lª�ÕÞ<éëœAì¢ B•N/‘=ƒ…¼h*eÝ¡/XÔîmÁáWbº*1ÉÐY}nÉôv c,¯Tg'€‚�4^…Ð0Ûž´ñ{A¼iÝ€¬l‚]«�•&YTD@dóP9³-]ƒà,9k1l5d°ìV Ó¬K´s£Nµµœ¥ÍÐ�5j©Då�S#=jMŒ¥ª_éǸµñnÒQT&-kE\›AD®%ùQY¶r™ØÃe»Ž¨#´‡.\Õ^FŠÚD÷ˆuFdÖŠvŸ™•ü¢¸á¸Wº å)ˆ�šs>7è×I '@@¤‘”/v€`[Eã¥ð…ÀWsëMÕÍŸÆ÷'ÓU7�>J Ï^å PÅ5\I5¹@l.¤ð&)ú"&Á“Ya®Èyæ³;ˆeb 3F.Gú ù´ áÁ¿yj·z#Xñeg,D MBpÕÐ ¼¦þB³Ø@_•’1€´Ý1!˜‰Üp0;^Œš't[VÅéa:˜—4'*ȵ³ê-cŲ„�Ä>pd– nJ·.Œ Ù !9" �õ*F™……á器Šñ«ªØ·«Þ¡ î�ÁD½à©˜n!ÙJLíV„RÞjÌK“Cœ·ìÁˆ¸}rª_€9œ‡öøL‹ÞC°®ÓÙB<@+¡ZrZ!ç´‘†Äf4Q!øÒbPð:Æ6DæG ™¾XðÈX‘û§¤š£që�U‹¬’8U#3l`ñ-3üÁûSÕ“àõ ’ »¿uíñ)—îw�¢ªW0àÊÚ×g°²ÎžÄû�«èK½å Ï�l·6pÁ|Çš_̶îý£ø8h£U™[¼lzˆt¨ y݆ÄɥDŽÎH øBëq›xP0­ÞLÌa2*ŒUÃZ-8ùܵêä ,Oë´ÃK’¡|¢ÄºÒž×"ëÛ2wëÊÜ-®¾ÿŽW°/5yS QÚëÏbÖ¦ûѪ/N)#5pƒél ÂåϤ`^Xa<W…°?Ö¥÷>�¾Ým‘ÜTq �VZƒÝ Ÿ¬Á�yï�Pa/_ùõ šÍ¿Ó­MNæV…—_MÁ“†J×ÞP�/•¤úÒÝ¢e·¤yi#ò¥®ýn™_¶I…z Îx}ÑË^\Sà§�p÷“ªH×ëc0Ìß�Æ×ƒa®äxr‹ÊûÏ£ñèXùÕ±_6èa—½ù{ôfƒäš#™ïˆnü ´ñN)à›Ót FßEJÓ–S+ˆŽd^›YÛÞ‘BI:ƒÇ_*VÈb·¾¡T_ ˜¬€NŸÚþø¡U´ˆ8N;c]g�xèÁOa%‰£ÍXÑ@@Õ�áfJƒA»,„;~ž9lé:È©Wma÷3ËQ D‹=’*hƒ¦„|Ø];ó˜>H÷@)»«œ±Ž6ÉödViÃ(K˜£!M‡÷žÈ¦' ¢whpÂHÕ Óx:Y‹¬ŠÚ.³“>E«Zô]KÏ:6‰§Å¸}Üö/Û^å'?$~+û2O~è¥ìËå/ê'¿ëŸvI‚ü ®åQèý°5‚X+¾G–TY÷òøñ­¿nR™�»T˜b W^‘!AÆÃÁàL×)j'ñ—“'}tpæaáÐì¨wvÙ]>µwO ‘c(R…é'xÄ+OÕŠAîhÉ1ÝF,0ÂÓvÏËþQÐä>Èàu7çm»ç�&ÌãWï9Së`ú]¾'˯©ÒHƼ/R${í×;X*ðÔï5é>~üŒ ÷´ÿÿÜ-u,èÌãwÝblêû‡™·-1ðåÃéƯ=®ßŒ”yϨÿf¤Ì«ªøPïø5÷Žgo�„ï <ì¶730¨®ŒY,~é@§òqS R8o™8ù$Äë17³N¯c«] X²´Þ0È ¿V}íhüsËp‘ïK®{F“€xDê Kņ„ÚÐâ{Z¿‡fj¼,:XÓ;ÆR'»’ `¦j©BK º©|0ƒATh[:øÃ”Ò*ÊòÎUõ!ˆYt0ÝÊÇׂÝIyàMhލ)'ŸU€8U¡jð‹IfDäÊ{©Û”DÇ'êô`B6HOEm� €*‹µJ²U?É0&-_by@ÿ:¦«üqªlȵ¡šú|¼ªÊp¥{�Ç>ëþ¯h·DÃWáhx:éà"Æ’! bK–YCsLo˜q2þrPÉ׊î Ìýž“ 10æxÍ�^p".™³ Nyg&^6ª.�ÌÉVI…ªM9Dú>À=mô˜æƒX, é}Ú°0‘¢ïâ§Á Â?ÈÖÞå qÿÅ“ XÅ¢JE&S- ùüÞ–ªîJêLj½ Pwt>™ úÕ…˜¾kAàÓ¬N÷»…£²}U½hÕGë“è=|ˆuNgÜÑA’�ãŒÎK—&—‚oÇöN†¨±€h-¢mãqyDY¨�¤R€ºræ½@�.áOu愆„‰V¸þ,gNm]N»êž ¯%Z­ û©sV‚u*µ�#x�e´#‘0Éc`†à‰¬'u@Dû‘ ºˆ*´Œïá›Z,Bm*ì�Õhëdôä²@j3Z ¡ƒi Ò'quœžg9ü ,‰´¤[ëh jeÇ1ˬ©ŒDæ­?ÊJà€ÞíœÅ ¯H£Xˆßj�=ü}ã«wó?z7Õ⇧2F;?{�‡Yáã—}}|àT쯪„'è5ïàÜùwübpêÏv/Ç×MS^Œß‡ ¯ðâà>;·òò[ÿìÜÌ¿ñ±ï�›ù7>ö½�5ÿÆÇ¾ß÷újúkø š ˜";ÒhNB¬™D6Ï‚2 3/ÀBÙí/ÀX^òM{9f'À¦êáÚ“¡4§û9"¼¥ŠvsxÕË:¡Mðo”£R…¶á„àNRÐÁ”—êÌzE殳´¯]£àð0à (¬ ëÞÃm7‚²ÂY”rúp0FØà#¤Qñ?Ȫu´Ln`Æ/>”T”­0]µ$A¢�³ZSÍG&ÝÀ>åyÅßâ?zÒA.@Q±_oÌ®5f¤90Žaˆå4¾j­k$£6½Û�(pcÄ{Ï·#Ã1÷!!ˆÀàsuÂŽi“p6d‹+@3fŒGÕ)‚¢{ ðåá4 ëä`†¨`ØV©@" ¶ÏÐ6˜ {%°VG{#ñ{0ï­˜c@Âe’“ÎÂajT$ŠÆ�7® Z5¨<ÀI*þTÁu—šEÕÿ'·Mè�4Ð"nm&ƒ¦âTmÝBF°Þ˜ãîKÀm0܉¾5bIæWE4C+`Um1àê”åt+ 8· Æ®£oÊ‘\M;º>`&«3ëæ¶åîÃÔÁâ5µýZŽÓÎ-ÀHpâsiâÄJêDí£–dˆ¦u/l6pÜð©¸#ýÄ$÷ÃßðÃ[”ÖLªÏo:«+M ‹‰Å[0h²`ƒ ?§åE^1£„CPÃÖ…Uû…5ÒÆee§UYÕMÌãW»aÔ˜bŸe2UÛÚEÛ Xµu»ˆÎ”2š÷Û\a±>•š‡KÛ^�ëö…v!ÖawØ…Ûe "ûvÌE<ß[Só«"3¼³Ÿ?Om}}6ëÖì}åxþÆð˜gÇÝ×½Bú�á1¿÷†_ž×’ŠKF×Á ×ÞûÔÀø�ý„3ê÷*`ZägSÍ¿o‹|§·¿ŠOÿ¹óX2ó;O¦{œ��VUã S�ÕreÃO;æh˜dåß:YæQéäÜÃu0pIûËž,²°!Z™ëHðv`iSBŒ;ÛYW5vh?�…ÿ¿d¢¬ügp�7 ¨ñàlԢꢳµÒ ‡åмׇ‘´è€4Iw‚M®s=b�¹R®ÒÏÒ×PK Z˜ÒrïÜÉà‚Ÿ º5[±ÓYuêМfä:tTU‡â¡MCÕ×x†N  J¯�õƒ¥‚|Ú±¤ìھ˗0ÐÚ…&/î@%™Œ-ó 2sító“ïºê”rºK¢CFÛÄªŠ‰I˲jëvËcŽ£M:$K?*Ò`xuñ›[Àºƒ¾0¼QÞbêXºÆèTY×êeÓMÚB…9-ÆÜwâPS“ Q”ÂBk4�n€�[éK °IE.¾/uTÚ‚‰$H1ZšËÑÂèܨR�âTؾ &ø¿¢Úìeˆ˜Ykì�Ù1è<ݰ*éá¡a] 4û"š´“Že·ºA)¼sT�ÈÌÐé¨yyQÍ mµëqª,Bh :½��¬¶�«ºbdEÌp2¤÷da ($œ°Æ;53{±R:ƒð'mÑ�a÷D“NG0¾N'Ü–NÖ+óæm€ òÄQî§/ô£Š݈HXÑvšÃ¼hýy@Þè ¬…·ÌˆÄ™ì¨½qƒ$]I» mYÕôêþ£±ñV]rHEtžy7ÚpÀÁ coí9rÛàÚŽ×ÑCEÝØ†BÄL¡R¥LP÷Œãwç²Ã‘'ãÃI¾ó8>�H|X2\òsõ¡ÝMå(û6tiío ݧEÜ>Ú#ú¹úPwûü…'ûÉ’™¿ñdO–Lw¢øç+0Æo¹· ¼\tßãÇšÄgcf^6)¿rfîþGvçÞÚW&Õü³ù< æGä·&Õ|ïRßLêŸÔ#šŸ|Ù8ª×½8â¡×ÅÃz(öœ °µ'¼&·ƒ˜F[µ 3ù¦*ë$u�Èš‹@Z±ø¥pK‘€Ý¨»ÔPƒyêÀ&0Ò‡?á'J|yÞ �ŠÜmLމ¶K˜¡­}"Ù —SÓ2ÞOõ$vz]º€Înºæ5€œv%ºÆ£ñµ{bK�wÉtàf�%•I: Êó4ú¾Ð$Òu¦mP}<™oºìšîÒqžœôËẎ3ÏF®ª†C�Årø›¼w):¶ÝUé^TLfRL$«Z8  ƒ„¯ø €‡"Ö©$”[ÀœT¾6E°üõ ¬Vx|há°@Þ–6ƒ®y8H&‹Æ!ªn½ˆæ¨%¦²pºi« A×jQö~³†‚$ÛЧ+ÞP™øì’d[‚7кB W}—õ Þñ×ÈLçÞº5¹¬Åû _U¡·Ê;]ªKêá̈ÝÓ)ȱUØ\K°A;Œ˜ ½×&)Nƒ«êü±Täò‡ a[œjÒö-G‘›ÖñG�©ÜnSƒVÌkct:óŒT(Û ¡°ÆËkɤ­¬„Å£ÃÀ»–ãfKSeˆ2ÇÄŒ¶™(–¨�ˆä)Ûл.ßÔ.œíAÙ¬KNn¥†Yå-•ù`È/Ö=PX|UF¸H"pæÜáE(¸}5¯ PÓj‡NŠíÑçÐM„Ä £èC$ê�Nk8ݤœÝ¨�‰˜!Φ;‘Iå:›÷$”h€<ƒhœ*ª*¢czìJJGžë(»ˆ^ƨžE�¹ ±ˆYuS0¥W­UëRªëü´ë…ºhùGu‡ŸÝ”ùÎN}w¸+&lìçÄæç ÊÝ=8L/ 'dÒÇþàÈ^ Ù×§£ÌÛñ¨ÿÖf…olVùÏlÖ3eŠ0Ù›»Yd^w‹bz²Zõ‡Ýê/v‹VÅŸ¬–ùoÚó¸Eo~w’ðoêG¼æ®¡²:zu°S Zu’¯Cšn™]Ê‹ÒTÙ¿VÅ;©¡‹1t�oÚ½hx@-‡Ð'}!­+ê*¦¡«PãÑÒ)áÆ¸�ÿ:¶JĂ֣áwÜ)(W´™Ñ�k°X€�ÓXÓq)Ù§ÓøBé: –VÞäk IKIX…¼Ûƒ¡ô]7錈òm‰A4NÏ ÑÕ*£nyJ*§Ëžÿ°—·&#„BG»W-NE$ÜU•N·t¡owرQ\)¬­Zv5B €¤;±U3Õ•% ÝÏ"¯[u¦†i©Ês…”uZC]ÕÝ Zu$Ši›áq­ÑA¶>µ[F:&ã‹}±x¤6aé²ïIX¼CPÄ:¡DÙÚ›‘×1L4öJ: ¬ò]*­Äò:Ó…eàhÚ^ûW�tªƒ„vî9žò�8º�¬ü´oþY!ÕçÕxó7Ëñ?­Æ›Ÿ—ãÿ¼ÊÎ|WYØm}Àxÿ"¿Ú­‚\ïKÍs�ãËQ�Ï_L*Ÿ|wùܧ2B#~ñ«òIo'S!tàS‡ä|øŽLð|žP˜¹{¯U–u^ MUbóèóe» ¯«¹6§µœ4öU�“�~7¸ g«{Yº´O®¨?¯:+TœWY™Ÿ€ºÄ±|ÝzüºS—ûXŸÅ$×óD-òbö`˜½x–Ÿ , ©�p˜5ë2¯[Ç2mF>›~�³ÀÄÒgÕ¬³‹WÌ[Œx€X^Ä Â­5¦¿èö5L´emE’ŽåIÑåÞU¯­.t_ûª*™B-xŒ4Êb©N�é×-Å…‚ÕQ�1†nç ¸aˆÀëxD îÈj7æ,Hùn4Ï�«­ Ý×sEO"3u n©LQ÷àɉĦãp�U™|7¼Ù¯f¾Òèí¦G�Ahhø±t€‚,ô:¹¬"Iqž©PB’O^^‡ÕEJ©i´F–Ich\ÀÁdxCKšD"�Ò •£¹­Um^O¸ÁëpUYŒlÑÞfŠÒW÷Ô‰ö\v':*^¯0NgÒ@'ËZ- ßÖY�ƒ!! ´Â¬áöŽ{ÜÊpPö*þÇÉÔe'Rˆ“êÛlµºþ$‰²Ï™A|ë¡�:xX$3åT¨Õ7¬é ]¡41¸N×FèÖÖýü˶¤ó¸ªæÒ½�žlÏNW#ƒwƵñ(ö­œ `q™S]î”TÖ /ò«¾DGf´QÌ$íþl)’šÕµCÅ=a H꺞ڑÌ;3C/c>:ÁM'TºWÔå&ë Déºí} ÖG¹Û¾ùVµ«Æpâ</|%,Ô™{¼™nawMÛc:ݸÜÿ ½Y8È£}¥/¢/TU±:ý¯2x¨�Rt©šŠ ‘º"‚§cb[•»Í*%�#š%¼4cpï2!¤sÄ“âÌlT`Ãl³–]÷άºUGˆzF0e]� ‘Z胢?cÒ#ÝÅ�7¯k´M_Ö¨S$}ìM(Ne ï�¿ZvÓºÓ=ÞŽÙÏYA!Æ'h�®ê6±Þïu(8sžË�*NŠrZ•»M·¼á—±ònâU·ŸAž÷øÁ Ó±7Ž$ÈÉËÿëØ¿Š§òè–@\Q …c�ȤƒN×M]ZàµÑÞudZwv3UÕËQ)Zš#2'²-Õ°­Áê¼`ë»¶]�•Úu 5#´á0�nN Û€8Ä¡#vªq± $ú.¨÷úžVc†‚îsSޏkè~€5·»'g”è1{àªk½¢Ç{¹®-[„%MÖAMˆBARêâš®#3¬¨ ­³WŽþޏº&ëÞD§öf`$: T—Í«�ènþ€kÁþ›å¢Ð_zTXtRaw profile type exif™ãJ­ÈLãRS3.Ss 3K33 0I1I100J4€ 6654± ¡b†0PÄ2�‰sA #d 4À”C�÷Y÷IDATxÚí½w¸\Çq'ú«ê337�fREJ¤s’(ZÉT°W–lÙ’ýl9­×^ï{ï³w÷{ÞõÚëô­´–V¶iK–¬@R")æœsA� 2.n3sNW½?ºû„ 7 •М�˜{æœ>ÝÕÕ•«šÐó"¸ÿCUq´56X(Ô�K+L- T5"DPJ…H>ÚrMNüø!GÚ S#"Y�É�í”�Lk€Î‰ë� n³ô‘JâˆF6­öÌ…æ¼�ÖÉ�Zó»ŠHAªªPjø�H@Óý'€‚R �– Œ‡D¿¸-úP�f÷fâÿˆÚ1‘–�:ð,vdGbŽojk7ìD%¢¶³¡”ƒScošõ³häF³(ægÑj5 +¯ªÍ˜9ìÆS;¶@‹ü<çVò’Î!‰5aþ§©ᇞ›~ÃØÒ æ®û=ÒL4ºš ¤Íí`8oÿ­_ÚHñ @iø)ò´¥Í…Ë­º] f,dæó=BJ··9�17̨y�§ o×â×Å lqôãðZáEÜæ¥êèDØ6ªÑ¡îã7|oÂ¨Š„•4·Ø-—íMƒUË·/œlÌÛùgµzzqRÅ›„þ‹ßšyp �/4 Y[³È=B‘ÿ§Õ¨;‹C»¹Àý™Lw"s&G#ü¡ÍÈñC«Ç;†~:„Þæ¹^ä9 ›õ*ž÷†6ÉI¤ª (/ª×CnGú‡?× ÐX0³h~6ßÉcn~ã¼Rçá7 -ÿö…6Zà}sŽ^åi†£`n4ͬî�fáÍPh'IfÏím �O-d¾í¤®¥úЖEµ#A9<#Ò§• çGÈÔ±¨vhó:Lh,Ðpp8­(›Zkóø¼Ã›w‡¾üþ{TŒ7Bºœ—÷cZ84"(ƒÓx´ ²�¾)R-‰{—êü„½ù†…/ç!è�íÈþ‘¢�©þuD´Å� ž­ñ…<”ç�õæz*%\ížm°jû�ðÄ…ˆ± ™5Ûò0µ7I[Y(׿{ª€Ö÷éáýÀ[³«¥àF9r/Êi+ŽJƒ�Å,Œ›hÓVÖCÛÜÊsÙ˜Ú´ÖÅ9¹Ò›¬‡7¸ýZ˜ó›`TxÝ‘°Ž€*»Ø9ç9ÜÜÚæ%‰Eµ7TxãZËý“êÆ‡¬ÙÎýTK¶RTJ߀¶(£Ó¿ó‡¹>dr×cùhE9´UÐÓa95ÚAa!V£Ãr;ì‡�þ² �+Óqˆ¾:rl¥¥t�°8ä5û1£+?lHÌÁ ©P*|à¿4 s^ŒÎÿÿh[lkM²øŽÂ †ú $ˆ %€TEƒü¸@ühùÓ¯ÿd¶#iÌ=lSäBÙJÃ)?ŠùvDÂyæ]”I6HÁÎÑZ~™£½¡á*GÛ¢Ú"6jn¡çV òª¬¶PU޶ÃVXè9°j¶2o�ôQbp¤Ú!ó”9ÕÒ|®>tNétQ<ò Ò„�¶¹Ûa¦£¶f+¹ÌÚ�àЖùúV޶æö†¿�žGÛ�D;,Ç[ÞÙö%üH´Ã_Ž¶È‘¯¶pRÅÑöcÐÚSÊŠÌKÚÿÚ˜h—Å?6ý4ß³-‡˜¿ó‡V¼]ìDíÎ#?ý9ØJ°°#¼¿º( Qtø»Â'®ò•ÈÒÅ¿)M÷�¶¡V@ú–#Q�áˆ7šÉ%ç_@a¶…¿s_´Ì±¸pņhGmO„~?ŒË|d¡ÔðÄ}94xS' .ÌyýCU°Öw.ÒÆåÐX¡ŸýÂ� U (c˜ÓJJpQ$Y­ÍUlTŪX "&öÑH¡Wx*·UßtBBD€*!_Ò€”EUU DF�…ßrãôÓÏ#‰*¬@E  8A QÕ”Ò ÊÑûÜNB{Y@Þ‹‚â®€Šª ³tvw,_9¸zí²Õk–-[¾lhÅÐ’%ý†™ ì+]* Ð#"„°¹8±S“ÓöxuÛ®­/½þÚ«û&Æfb6¹š©�¹�üÊ0�Eb2´|Y߯�+Ob€ ¡ì™ªVõ:¹¸H;"RVU²å¨üÎóŽÿÅ_¼øÝçnXÒo˜,©õè@œ‹ ’5móKlÈd6a÷±ì=Xøñß½é‰ÛnyöÕí£b#6¾{õ=6àÙbrÕH�ÕE#QKÄ ˆXjË�å�gŸô®�^~Êo3Ë–Nƒj KY1²´.™´ÇðÀ¡@¤Æ‰ Ië))HÕ°® Ò—_ýöÿý-ß¹GbkÙWÑ·KlDÄágm”�"rx·jyähw§ã•*ÂF�Ýrü{>yõ¦Kß-KúëÐX!�L¤û0}Þfµ)ð“œó`À0•T´sɰ1u�, PO„¡‰ÉÛþäÚ¿x]\·Ö¤È± ßa q›@©÷qÈá†ÎPVYº,úÿþ˯ù©³J˜b¦º²C±*Wk–ÉT*ZWX@ ìñCU³ýßøvÊCPRR…a¡ÊŽ]Ó_ÿæƒ_þÊýÛ¶Ï2GPR’FKÒ©`†}ï)P÷ÈÑVª `|"°ªí[Ñÿö�¿ï´ŸyotìÊYÀ@ TŠ@ô\ÏÔ«ùžáŸ- À˜Ú¾kÛWoØ÷äÖž•KOýèeËÎ=CÀÖ‚%`VÔ73{çïýù£_½I˜‘‘˜†ñ6ÍÓ׎ÈmVïutÃXPÒX rÔÛEð}úãçvFE5âA@ `A²{÷ÄW®}îî»öutâWŸôá�ÐÝí˜rÔ jä¶_9'(�5a:(‘Q�{vø¿ýÉí×ÿÛ¶j�ÁÚ¦ÞÐ= ‡A帖 ŸŸy;¿«§#¤†ì±ï8ùâÿüùÕ½brI_U©Љê *PÕuPT'ª5 Ô�P#Ô1ù‹5¢(ÅŠcr×þûí�wÝüÀ’þ¾½�m}馻NÛPZ·z–h†¨ª)êÀ¬b´³Ô¿ñ¸}w=6{`¤Íô³­“ñ¬°†•?.H®óÙ}hóï|þÂÞJÂf–y–¨ Ì€ª€Œ�OÿÆoßö¿¯ÝSZ³sŸ|ëŸììˆÏ={9S¢T'µ $M[üˆ’,H›»!�Ö�YQºä¢ÍK—v=ýԞɉ:·Iªž9|ER�sãG»œlÊ´ñ#žû¿Á§Ÿ8Kd�8‡îK�(&Ô uÀ!M ŠÝOî‹C&¢: QÔ v~ëûÛ¿ú/—þg?ò_?·ò”ãŸøÎ­µéée—œ³qD9QJ@u .öÊØÔð½�kÐ…›ÌŽ~‹{BB$JÄ…Bà~f hj]ÈuÕd­'�Ò’¥ü‡ÿï…'×Å4C< ®î“€ëwÝùúþñ“~ð¢?ü³_ºè’S¸ëÉ'yå½ï]?8¨%1ƒ �Z@òÈ¡$ ñ˜A �,4"I*•ÚÙg-9í´UÏ>½wï¾*q;V2çZ“׊ ªìB U%ŒIKÑúO¿oÓ¯~²Ú?(ªD¤€% äi¢f²E*K0dŒ&¿ƒKã;ö«µ¥UËFz»;7¬ªôtNìÜ75[ãR)!/WHèK :ÏÛbú¿)c“ ÒT€ñ=-@L R’•ë—¿÷š‹^{eÏí×ÝŸ$³¯*°d0úØOŸe«ñ×¾õÐÔ„*‘¢ Çdlˆ¡Y·®÷Ô Ðqâ¨AÅ-­jD$¯ïž˜�Ñ��ÎZ¹T^1Ð?4ðÒ»öíŸÜ°®L%›_°Þå_¦©Y0•œÈ (`²—]4¸ü_úùß¾ýÞ÷—ÓÕ 7µhZ¶¨%6´¬{×à iT.û¹­û•OØ®ÞYòj‚8¨�C޼å•ò<¼a÷©¢ÙGŒ®µÇ’å{þö['¦ö>úÌ侃kÞuº­”ј½°"êì’¤³vhÙ ÇV_ÝEFS³Z*§õÊÔÙßuÅo|bàâ‹FwŒw<ôÚÔö—Áá +ç�Ýõ‡¿&åÒÒþ%o½ö«O[ Ò!ÇˉÔ8$#€!ÖÊ)›z{FeÐÄÔ‚°ñ¸Á¾ºõ_n¡^ž¿GÜr�B(ÍÖ;ÿãyá _y´žX-íþýß;ë³]n˜)²Á$6ÇV&dÜ­ù:rôL=O4üÔ³³Ÿùì}�<>ÉÆ’¼60å qÁ¢�È…j€hñÙĆT�]ñ¾wûŸ³´t)“*SÀ Àá„æ€œ¼G|)Á«è켞ž‡y‘ª3k” ÇîÝ[ûîíÛ^+¯=Ö\ðöêº55.YŽ”UU• k½ª#/Ž�•²�ŠJ¨AàÔ>׿ *Ó–Ö#ž­Ó×¾6ý�¯‹Ô‰(¨9¼´wöO~}ôšKšNAå8¢^"C0�í8+'�‘È„¢×,=¦�Áv§ *�Í,ýö c<üzÏ@åòóW¾g WJUb;33£76¼º›Ã‰T4pS†ê,Íd‰£;î™ú…_º÷•]1‘Sâ94X°[»‚ã"‚í:cÃññŸ*›Ž‡ª!�ia-ÒE ´�ŠÄ‘ÙOé ¬B¢“!]ÆI¯MÆÉŒI$¢Ê¬Lêí=$ %­Nê®Çìô0d…¨!¿Ê�”Y‚ªQ�&ˆ«Ñž½öÎ;ëw_ª“a â5¥UK¦ñýSWž?ºzùtTâˆ`ÒóGÔûA<¬TD=QÌK·˜Á·Ât6Û¨ÊP20=6é&Ô@�„�ðëË)™F¬ðöŸà¶ôj¿’æ0‰RfM uC!%RYåÒµÿ°ïó¿óøD•)HiG9ÜEV- ö¬ýo¿Ù÷Þ @ "0 TéI`AÅÎèE°‚9G�*ç _þ½î�â-欪"N<‡:˸…óŽ˜ÄXgŠ®Ö0º[ö?/µ½ˆž¼‘^¹×I""â][9?‰’B­ÊÌŒŽę̈’j>,‚ˆT–L¯XR/Uï FR "‡ó(›ŽRô>>~þ;Rϱ¦ï,ª¬u€5µðM—‘ÂÞðþ͋ـåóhµ¢T "HÅ =¤³qô[ÿá…/ýÍkà²eÉ›»³íYh⌃sû4Ž@YÁÄK¯¾¨ëÂwX1)‘W¤ òäü�Ȥx§¼»ÎÐ 6dË—“JÔKç$�ï°*”-”ÕÂÖxvcûdt—ÌŽ²&¥�Ï'·~CFö¤¥äüX 8@™”@’¦ @Á®,ñž±îÝ£Ý9-ªA°S·éÁÊ–#1§ž4½Œ¶ÙÚë\^G]б¥.�(O1§Z©AÁ9^D ¿ ¢XÕ´ÑQåg­ªPí,×?ÿ+ï¹çÀ³[ëĔ۷áÍ ¾³ð[Ôâ5mšó•6®éÿÄû¥Ò©°N÷s+'qKKåT,öv  ±Ä3’LsRU›¨ª²£¾;¡zõ"ü‘P\×ê´T§¨6I¶Ê¤%E“ôî¯Ú‰½ˆšö_³Û(>Óι¯ž6°/îîo7M72ŒHïy¦ó‹ßXþ;?ŸtT&µþ"MmEÔ#åA”–¨é#Žˆ8¸�³PŠtÁý¼]ÓÓC¥n˜NBd°PÛÓ‹¸Ý|ǰUS´7²*ʈd92ñ·9ˆÀÔÕÅÝï=ß‚„œG�œ‰GéGœ«Í:ãÄê kjCq¹¬dÄÙò/ðh.©p‰yp€V ÅýÝ L] @Dd 5�}B´JçÂt±ÚTÍȘjNrä×BxÍ1Ñ%ç<óÒ(¡äTƒ4F e‹ÐÆXÞˆ3‚Î5k̦õ±¨*l*j ç>x €‚VRV;+#[%žŒ"akTH�&uÝö<=|¯Ýþ4ÆÂÖ,4ã`šÉ´ùõôB‡ØDbNœÊkÕ‰x-ô1̳áß�–É®¶Ôµã`çöû’½OËœ”"bªS†ž-"&±öt˦5õ+Þ>ûþ‹«ë7Œ�T%ò$ªúŠNT¸ïl0CÉY&�õȸ·ÀX¨U¾øüþ/ÿýÈL••l>d¢-r 3¶´ž¯Ûš'�@}}Ö:{¨×`Ýüòhax UKã»ÕN”D‰"5Ê\>°·~ã·’îÔ©a%…e&HÓvNy¹6;E×ET ƒT•æ?/†æù}aM‰i §#ƒ5P×R=I‡Ó<"Êý€(hd;$w<Ùó77Ö~ý£¿z¼ÒQ ñ‚ê.)¿b:7::D”z9s ”ÃÇÕˆ9íÄŽuÇÐóÛbÀÌëo1(oð$J•‹F00)EåÁ÷_�Ó6[çH&µP+©’\=Ä ¨N¥Ú”V÷¨2“abc*÷Ô¾ú×µû¾/õ)ïX'uvÉ¢¼Ï ‰@¬™v—qžÔ ۼ휌â-˜G¦Ðµýdê\J ž[OO‹îÕ9_n#%†ï�îy˜Év¾íŒR©$JF#"�ÔQõ.ðKSþ# •Žré®û&žß–GNEò¶=ÊÁ’‚2‡ésS0�¼öØDaba­Jˆ�XXqß!Vm± I� (1•˜ÊÄv&¹î«ÉãwlnÍœK[˜ª j±µ=]%ÿè$}÷$Úv·9U]M3wüñWùoÿe©p/VÁ”IgQß MHU«Z Ê}¬Âmj[©$›7••,TægÞŽv·Hazz±d)�%Ô’ ©%÷Ö+Mêõ�Ô 52†¨ *Á”ØU… ÆPP¤UF4;[½÷ޤ:æfêz(5.µáßPkr_YÉO“<¾,;#ëS\‡–DÛvê¿ÜdN:±—µO?-K&*p­4¤É_ò16ªJ"Ǭ0eLWçOv´gÛ&ªPî(#*{~!$BÖzVâé„%±�ZÇw`­2�d”K„á½ñö—Á‹G‚Ÿì–òQ¨ZÁíÕ&§:Àeâq‰Š ŠDa‰º(C !¨êŠªû3DW§³?γ ÊxSU”ÊBìi†:;)i�Ç(õĪBÅç5’Qob7°Ã{íôxS"ÚÂ÷Õ�ZSïÓÊ;cç{Dó.ø¬Ž °�wìNFvôÆÄÐDÅ"—Vœ‚š`Sjw7:ÊN×l� ¸#5æÆ õ^i£Jb!¬êý´Ø=õªJB gæÖ@f¦‘4&1ýXWL¦Å2¾Ì!šz§ŸOùxjFÇgT¹!ã•‘&÷Q9Tr¨3´m4GÖ�`í b¢j­KøöA_A“T¢L˜"!¨ˆ…Òh\»4À£å«)©2)E ([@ü™ßHBÒ=Â?™‘Uqk—µ/ Z‡l¥5~Ô$ª¢PõÈã9lW¨ `4D`eÑKŒ�~*Ejã¼XžùM›†ôýbJuA¦^ïFCG³Ë¤‘^µó®(µ£l�–«v/ÉúnCç½!?®|)·´ýýÜ¿¤]ÉJ†’à:„)Cò¦R…*‘…r­šÔã Ì‘‹¯ `+~·ÏÎp5Ag0’ ¤ùôʆBVeUQ-­Z Õ÷ìX'¡©m2wÍÜ6w¶ó»5Ý™ º@æ@mLs-ºœK)<­A¯¥ÍÇ——/í€ÎÂeŽÃ„8‰€›¤ñf$ °L¿¥ñq®Vá²SÛRò`ç˜o¶PÅ“ãvbBÖB-iBjƒ†â•”ðÝR¢”¨c‰^V±vÙ�Ù|yS[:ÿÖœ��ß2”&5œ8ÛdÈb&r¯HmÀ¹™;ãiË3|³àйð¡Ù8àH1΂�ÃxL”¼ë¼Žžl깊Äp†…`ûòÚŠ…&€Ý·Oªµù”F€ˆÀ>œ¼í¼±Ú0H ÉÔ”Å1«TUBª.uIÓ¸?YÐð,«Z ¶bÊçž—Ü�ÔgAj9b…¦:(d·º.ˆÙût¬B€Âþ�ŠKZGcàY®/üâø[Fu|¡!ò)Ëܼ Q0ƒ\TêßñÛΪxËVŽrlÊá›ï4ïM›ã8«tGhFoµE¯P¢  Î+=v5]òŽ>Q”ܨ²“ÚCYÐ5—/ð«e¡æ•WãZÂD”U™hÀú³(gËk�óDR�•];qÒ)Ty XÐÉÜ”þ >VQ:ó-åÓÞZ}äPÙåõoÓ5gY²¤ fr&–ÒøH}ë=vz'‰y±,]>pò™›N:mÓÐÒAEP% Ηü¦ÈÙUUÙ‡nSÂn1|6\Ý&{ö ßsãC;¶íN‹%áÌ·®=ïí',èŽJŽå¢ Xù0$”Aa¶(Xû3Qð‘¦Z]@&y�PUUTTT±Ö!3c#¿þÍ—÷�V‰Ø°~è½='¯+C-q=uë¨f›³àÿTñ2‡3¨“’¸Vyæ…º¨1¤!o½­Þ-Ä_I¿ºÝάJÎê_…Tr¹`@Á I­óªIwgô¡šmÏÛ±ƒJ&Ghõf»úd#žf&š�ÐW®o{€ªc *d ¯9qõ¹W½óm—¿kéÆu¶³’ò ¹”¡¦–§_âuCµäÍ06#†®öNFýÌ+ßõ?åì~egÈiRÑä⋎ùÓ?ºàøcK†˜"_+µûûIú÷†�æm͹Ì:MÙ[+»‚feÓ2â¡p�“22½ÿéÿñW¯NÎLEDVéÔMæ“YEVIH3¢SÜ�i×)ÎeÛ’ŒŒÆÏ¿l‰*ó2@j©­4¦Fº¿XêÛ_©ÌTµ»äX‰%¤OοŠ,\W]䨋âR(H„N:©óýœý‡¿O´JÃÛéÎ/™‹‘—žUbB2ï>&O}/Ùó Åìb˜VŸ¸æœ_²éªóë«�yÖPÝ U5‚C#—Ê’ IAB°$"qQÁRP¨Urlµ˜÷›�ݧŸg¶}=ØhP*ÉG.­nèúg“œB4°+y�[‡Üy%šF#+ù’—WB.I¡ «G Ù�²+DY S˜Ø1õúKñ÷É_~­³V�XÍÒAù­_^sâê´NÞªÈWËËi’‘ÀàUQU—ÂüâËÕ×vZ"UŠÖßYtˆ{)cª,q²óõò¾Ý²~ƒŠud¼à•Im¤�:_ˆ ô aºäŠŽÝgn¹TÇžgåÖÿS:ÿtp=ïyÆ>ý½äµG¨>ÂÌPÉÐÆcÞò¡ËÖ\}áÔšc�©Å„Ä‚\J;€3”äòœ( ª#ý¢¤"âc   ëýQšX~Uvl¥òT˜•ÄÅ'³PÏÔ®Ò¾W4Ç’ã•+9ÉÝ ( oàð™'Uð)e!(ìóŒò.”‹4«<£3{Í�m;·ÖÿçµýsK÷TRVÖr„_ûÌŠ\Øe¨FƶŒÃÈE³9ÃÓJ«iɆ$¹ëþÊĤ!“¯’Ô†nHcÙ�@ª›ÉQ<1J�?CÇnHi¤z™ˆs’dÎ(˜‰¹š’UµˆºK×|¢{¶6uÿÍ$B»ŸJnú3Zº&yý)�A)‚J÷1K×]}Áq¼<9nÍóˆ’feØeázdt)( ;3 +8��¥ÚŒÖ¦P›B­jãY¶‰Š¨¦AJ›ÔKÑÁ}µ—óqŠPµÄÞr?ÞwvÔ™<ŠÑguhZ£Áɵd¬)3uu*�:(ê—ˆJà2L™("&pž†„e·—ÈY 8Qª£¶Ÿîˆ÷ŽÞñpÏÿÆ’»žë&)1iTN>÷ïú>û±�JT'“íø‘-pAæp/!�Û—l8¸·Ý)&•yZÔ¢Ü�q5]¡’Ô½?z÷ùq_WÈ2t"µäÊ%6h€™½disš ËaÃxÎËÚ1$ýè­ÌîýÇ[vßq?âYKöª“×Í„LmF“™q�€±ýÙ·¿òÝ®r9ñº¬«eHÎ!•»ùÊ W}ê§—t[Š:| ù€]AZC"´R¥˜ÈB'il§~m;}íÆ¾koéyuo/ˆ™ÅŠnXÿö¯ ýÌe½]¥F‰ -ÞV2ûžr ¢ŸKJp ž�Ý_ûú ÑÄ,�Ñ¢ÞEkÊÑ5¬} ¨Tgj÷ÝR:ñÔZW»xM¹lÞ®žÚ¬`0C ÀÕ¨¾¿¿ø’}êÞv¯­�ÄβÛÓÙ}ö–¾^VÞr¦vuÕ'Ô]a§&)Áæ¬)òäRc„ñÌ-RËÑì–õ+×]ÃåúÎo^Ÿ@´¡T4A”‹i\©£«¬dGª%Ìä5"˜¸§¿þ3ËégVõÖ¡u’°`jC˜ujüÈU%tâ*,Ð)�ÙC#{÷¿¦×ÝÞ÷åïõ>õz§…áˆTl¥$W¾»ãßÿòÊ·�È%Љ”±†å/®SJ@ƒVCh�ga1âÙ»ï ï?PbDIѸ‘‹õj4ç ÁÝÌQý¹G;ž~ZÎ:'V+¤9å™o�ü‡a b¡nì�$~ñeûÌ÷ñÊ�:} ñ^±�]]§ŸÖõåÑ9[¤¯»&Du“º¿JPVo @@” Ôdi §â±ÛßJDlk²c²§´åýÑ]ÏÙ½/+CóÔX4ø Â\H|uËœ#ˆˆ@bEÎ?ËþÂ%¯õV,¤pF>Ÿtj¶@3¬p ­êÌ~Ù?ºË~ïÁÞ/_ßóÐ �U[fC¬¢„“N,öý?}eײn@mª›hV+)‡ ÙŸÒ€DVa•²3¶&õõ¾ƒ�06Õ¼æM·_@<‡Ëù÷’¹êìØìí×uwBmIy€½—…$^e"�¢R½$#b_Ù…Ço³Ûn¶S\͈H¥³cóI½ï»Ì¼ó­\Z#Ãq’jÒ‚YNž˜¦[Ó%Nóü†ôQ1ÆWܳ˜Ð‰´>º„»–©¾|$R4ªöÄc¦ºe·LÅÔ±Žµä‘Á• ¦R"ñ*‘²[ ®Ó#?0»¿zÇÃ_ø^×]OtMÅb(³j²f ôê%?÷áÞMkÔX«âD‘`[¹}”†+'ïÑ=#®Cgìþñk¿ÙëÓ½b\pZ‹H¼¶ÈѨ»Ý‹Žo¤·qíå'Ê··ô¾ŸN YÇÁ‚'„½w^˜`„hÉË»ìSwØ­·éÄR%¬¤åréø Ý—^Vy÷y2´ÌÄ*`]dÈþÕ|)ŠFÃ|j­V8!'d`BTµ®˜BmLgö"ãÒìŒN�s®ÔBv°Gº®PЄÒ;(3­¬èè‹b¢s™–º‰+Ì¥P(åvâ fµ:FcÃõáÚÃÏt}é†c®¤st¦Ã0 ÁZZ:$¸¢ÿ3× œ¹)Š(†X¥:‚ v¤ÈðgJ®$M€ »)�á#·ßÖýÿÜW‹+*å …¶&Ð4oE3_Vj± K�/$õ™{ÿ­sÕZl9ª6˜ÞI¶ �ÄèŒÒöýòÔ½úâÍ:¾R7`‘)—�[ÛqéE¥óß� S'�U"ò•kDq4=o•ôä)�X@Χ¡*ªP%«ñ°Ö_çúÁD[—g‘‘W¶¥¤ÜQœà“×ò`T ÒòÍ—ny¬÷Â-1ö$3fz;¨g%u ÂDi9we€­rñ�ì³ëOmíüòM+ÿõÞ®½ã5¦D°Öv÷òÅçw}öKÏ;½ÔÕ�Y¸¢+!H8ø0Ã'"»2vž­X/…Á‚$£4<öä£=ÿÏ——ì=ØãÎ((JWóXÆ }ïñß‚ËÍc‰6Äóe5ìJfÙúò5Ÿ«oÜâê+¹Äö<ÅvçHüÂCö…Ûtøycg,RÊfõª®K..�¡³ L™¥�É“£xX°¹g©oiÔdâyм¤IHÏDVÍ4è¹ÝÓ·ß]Ûþ,í~I«# sÁèÿI‘#]RשäwF(¤ãŠT'Dvu_í-›gß²™>rUïÆbªT —”Œ;7DJuĘÖÑ™m¯ô\{kï?ÞÑýÚp‡rŽÕF�9÷œÎŸÿø²KÎ-/鬉ÆÁ†›å¸6’Ëë잊5‹ªu™éJU­NÒþñçžîý�/Þö\(j¬ÏÖ²donîd5Ê`$ÌFW\š'Nã?°½þí¿)ÿT9Ùp²e[VÒØ;]{æ‘ø™[éÀó$SJP”bV­é|÷¥ .еkc\¥�¿N¤j…\ [j(iP¶Ô™d�5ÃO!µ©(AI˜À¢J""¤�¾j �2òÅÛgjcÊØVÕ5ŠX’]ñ "sê!p KyçHyÍlÿe—ÐÆ�Ó%SR5ÞÑEªT×d “£�Þ½;úöí˾rëÀs»*¢Lq¬Ì|Æ™¥_øxÿUõ-ï�Y¦T,ƒ‚u«èHÓ¢¾ê@ñAWêÜäª.🫂*�MоÚOöüÞ——Þ½­¯]öó¼�Ð{Aå@ª•7¦;‘7»ÒË6Dïý4oÜÂgj[ŸÆÓ·ÊÞG%ž2ÊBP¶ÑÒ¥¥wœßyÉ¥vÃqÖ”!â UåÊÔÙœRdþ(ÊɤàPä‡$pº¥‘Ì8/þtøŠ/)ÝyýØõ_R[2{#åhÛÒ"OÙ~s«Ðßoÿþ?M]qî, ô�"–ÈבT1>IcÃÃæ»÷,ûë[ºÝÞK™\¦+Ç'l(ýÜ5ƒ»¢sõPBš⬶L†âq1ý“ü•œõÑæ¢xD9Qª¡6I'¦v•¾}WïÿÖÒô8½¹Õ$B9Zƒ¤¥‘$U�” ¬b‡_Öþ+>é|9p@vÝ�Úƒ@Fè<çÜèâK±ñøj©C¡d5Ë{T(S*ûJ™ B?«—HC}AoL"(«%bš¥dvT‡V”û”û˜;A ŒJu3oâJ·ÌÔyÊbZeïUNêi«õfeØÁn3‹²ìøzðëY%QÓ×[zÛ9ÑE—cÓII¥bD(±`WÕƒR �".S‘.‚�‹ ç.TÜe¨0)©ÑýZ¥®ãU$J¨Ø¨#!cQ·p�5Z·jRæC@‹<~¸1;ªfkœÄjkSvw�û:©nyv¶^åÇ^øë›ú®¤´jØ ‹$Ë—ËÕWô|êCƒoÙ˜”8† (N=«ø³EfÚ¢TÞôB¨ã‰sŽ©‰ÕNóøD2\ê…žk¿ßsÝýÝ;Ç:Ž˜¢ É£bËÅv–ày…Ö†–É"©˜æþQ5¦«£tæ–ÒÅWÈ)g&•ŠŠRâÃ)|ÍÚ¼ŸB•ŠPO™¶äÎŒÅûXœJm%ž�Õg·Õî{ÜîØŠéƒªÊ•~^z\阷`É&Lö[‚°‰l=yýA­M,âøõ4&Ý>\ºþÁ�Ï]9ÍÎrµja^z­ÿË7 |ã�ÞÝ“¦âÄô Ä—�ßý‹ë;÷TíˆfTX)&í4ç'ÏôD'Tûm ÔÚUÊ ²'«š:ÛYLNÈ~ûÒÖÒWoúÚ=ý;†K ŽÕv.àÈ×yW:Wjr�'Œ¾\£Zêè,Ÿxré²ËôŒ·&�ý$âüLŽ,YŠCiô¢¯¹ˆHvÕECž¨‚¡F”\Q¾Z/<_¿ó–ÚScb�+Jè¢wÊýѲÍfÝ;̲M¤õäÕê/]ï�ÃRSæç‚eŽlîn͈¼¦æ7®½ðŒÑZÝúD××îì~q_�¢D„D¥»“ÞùöÊ/~¼÷·•û:ªëË}³ UËRãzªƒ„¢ žZ(…0~U§†Aˆ­KuD‡gw½\ù§;û®½£ç¥=%KeR¨Ú¡ÁX“òþ±Ègž å‹ÏbÒy�ƒ$„ݺUwóK¨\ªl8!ºèJÙrvÒßOÜZ¾œ²-€à�CQ0ôo÷|QçbuLà$旷ŷܘ<~_25{íæMv€%Up—ûTc['�›•”Å ¤ÍÈ"¨”©¾¬§.b†g:„YE©TÛ�ŸþØ’«ÞÍC½uHâ÷=%~U²Ò¤ šª¤;îœgÕ#%…²¨Iuª�cdæàë•oß×ý·ßëyâµ+®"§öõÆï;kæSçÏıþéuý·>Û‘h™ÔE¼ØÂÜ�,r¤¯C” E»6ºäb9ç=ÉÀ ˆºòh¹:×ù²ÎW�êɹ· 7ü8ÎÎJBd"ì|ÝÞqSýÁ[íØ°³�+”)âr·–{@ŒxFëSÖÖàÂ�!êcM¨™§&r¸H&eˆ(‘‚Lbµ9i³ùÙkz?rIçš%uv:ò ‰9&âõUÉ‘ý¸yryl$p¦=#™á±‰É=|Ë_þÞÀ]/öV“¨[WS©Äï:yö3�^pÒXw¹‘˜èý³—}å{ƒ#³� '°‰›´³”êa!…U#ø`� »²(u÷vœ÷NºüýõÕëêJ?4“:¥ˆœ7²\CÎøä%2§¯z²£DAyÿ.¾û®Ú½·ÆÃ;„,+±¨–yùf^sŽ�rOcb�x^†Ÿ±ã¯ÁÖ µÂ-ô“#š�#Ø!È•€³ I´Ä¤ÇoÄÇ?Øõñ+{6¬¬1bõõR˜(u²XPê!C0tæWU…«È�U,*Ó4=9»7yø‘î/ܸä¦'+³eÃd¡%ÒÓ×ÍþÜ¥cW¿etyç4)ü2ÆVÑyÝCCÿõV<¿·‹™·2pj¸hBŽ£Ð9R:‘šMI]5ûä ]_º±ï_ïëÜ?ÞÁ µëWÔ?vÁäÇÎ=¸~pÊH°Ì‚D@dì’å÷îXÿ;ÿ=zäY"C*™^ÔŽ¿øHÛE�šÀ®–¨´þþø'eÓ™Ž,b/ò±©B)r�÷�Ck�Iƒfì`U%âòÔ”>ýh|× vÛ3×A†T‰K´âZ‰¬8K*ýJʾ@.Ã$¼41ë ­ªH$ÆìßW¿÷öÚmßOîjNí:4ä "O"V3Ø[¿êÊÊg?6ø–Íq…fU�ÜãÈbÞ´…`œð«�´6§*‡Ã‰²:ߘ¨bzF'¦·½Ü÷7õüãÛ‡»ˆUaD±¢¯~õ¹“Ÿ¼`üôcV4q%<Â…•Iº»hÙrê[B¥Î‡žïþÕß�}øY"#é©¶YµÆ…"G¶©î P+ž bÖŸTúÙÏ&ëNt¶˜¬~¸O­TJý¥êƒŸò,Å©.ªNÐP‘�À&®FÏ=“ÜõÝø¥‡µ6Å)T6}ëxÃevíù¶¼Ä×C†2XX¸Wy�ÐJ¢Š#ÅÄdÁ`PôòóµïüSíéGU¬÷»&ºPäðamn“P¬Ê†’·œÎ¿ý™¥—¿³ÔÝ9-Zgv•#†…Wi ªÞƒê)®ZRJ¨a,¨†x k{_�¾yW÷ßÝ<øÌ®²¢LdEÑÓŸÆì§/}÷†ñž&�7VÁTËXºŒ– RÔéúG)ºû‘�_üíé—^g˜ àË3‚7mÈ‘Ÿ“*�ÙUò#ÐòÕ•Oþjrüi¾¾´³Fîå-â P ¦Œ\x´c»ÄAq�äd•^ݪwý›<}—ÌL�ŒB¡uƒõ—`ݶ{HlI•˜Ô@”D{À«kTz`¬’;d‚ˆDK&š8 ß¹®vû÷âd¶9™o¡È‚ü˜TˆËÑô5W™ßýì’Mk”½E+ÎY¾Œ½)~ÅUÓø×t @XÔÔ¸>�ñÙ‰�zó}Kÿú{]¼Ü5 cA¤É™›§>séÔe§�/«L�(!&¤{€)iŸ._F•öôÛ‡ÎiTù§ë»~ù?ÕG§Jáí6lÕ9(�óû¸¤9çÐçŽ~sùÇjëO×DÁÊäKfÆ_è/8育ýåK¿¨Pˆš0ªfßN¹÷{òðí2~€4¨šÎU¼ú]zÜEIßz(Q]@ �hx9éZµ}Ž� —½ß%ølL]ëÝC|ÍÏTzä†oÚÚÄ!؄ȇAø³»:fÿ¯Ÿ©ü槺‡zbKœ¤‘›¡èwjƼ×Ëã�³ô†ô§;Ij4>]Û­>Öó…ºo|¦wªÖ"M²yíôÇ/™üÈÙcÇuO „”-I0o¶Ýݼt)õö•Ø�:„Ô;¥HfêR<òdùϾ’‘ÒÜã€Vö! ¢³Ï�·¼Ó ‡?J؆ ž°ç(”g-ššBÝ%_§•„@MÄ÷Ç÷Þ¨û_%DQÂuŠ£åçÐúËeð$¡2g4Æ$(+ Ç;¨0î4/ÏÔò “I µÜ)ェKh憯j½j9gŸnŒúIçœúÈÛQTI:+ño|ºü›Ÿìè¯ÄJJT÷[3p…ܖȧ²eR™—.ÒÚ ¬JÓÌ´ Ûçž+å»ýߺ¿ïT‰ °"+—W?|^í“ï>iÙDIkA*ô^'eHgý¦Q™@’eRK«WÌÌç®tÿÃòÀ“uDYFk¡lîâ�ƒÈ¨ðêÍx÷U ²u%#âÝa™Ù÷ßL¥ó¶ñÔÃ)F¢²Mô…ì­ß–WžQ3‰(«é*-;�Ž»Ê.;ÅšnÀºâ2Q,Ë@« &) ÜQ'áÅ™žœ«íbI�Šår|Ù{;FÇfﺎÕE�•µ|gJ¤‘*Jò™kè×?iúÊuŸJç³H2ÔGÈiÎjGPzF3çK©(ÇbêWi¸öúÖμuÉßÞÚ·í@¤T“ؤ¯{ö’·MýÒ¥g;ÙÉ3¢6ǧ¡¬Z6:Ї�ª”@†50‹FºûY–׬œøµOõ>ýŸìÔLÔî€úE )¡T‰Î½²¶l ¬2!s:5p…tPo=L¥éþÔàEaïî�Ìì$ÝùÏõ»¾£S£ €PE—lŽÖ^�¡·'å>¡² !CÜϲ†t)lD¡Ä'2ç‘83Є=ë¾Çs=ê¬\ù�hÏkñ‹�g£k…Ö�»ˆÕ$$W¿gö·>ÕÑ_J˜-¸nµy4 º(Òr_3Uó=³w™Ä³|pvüuú·{—ýõ�}¿ÒeµVhRf¼ã´ÑO_:uùI“=“n‡˜ÀÝ„U™´»“¹«®¢<Ô³’¼xç6€Àg�ˆ½ò|¾ôÜÎoÝœ�1s:ßæDrñ]dyõÉö¤wˆÔ $ºe;¥Ì!¡Ì<¬€ F!Ä¥ñƒzõµGnR©)3+йŒÖ^B«/M:Wªsù”…Œr—b%Ékw~Ÿ b–ìU¹/Ì÷¹Ê&a%Õúà’Êe•]¯Ù©ýDêÃuïý(Ž_Wÿ�_(¯ê³D¡2ó:y+¤8‹�J‡ï ªlÕ$TŸ±»ã‡ìýËë»á©�©„˜Œ€#MNßPûw�¿ÿmcË»'#©G6x DVí(c°—»{É6èXVÂk#�¨;- ÒÓ%Ÿü©Žïß«Õ2¹QüBàqè£-r¤©Tà(:åÜZ×µ¼[Ém¹HÍ6löŽ,—ÊÃK•§Æô_¿’p¡|úƒ3Ç®¨+gO"¦�6‰ rW™IåbUÕ¾î©3N*Ýúˆ�³¶2CÌ‘H­ 2]Ú3$þŒVVŒx—³úø€'Öòô„<{¿µ6HÅ©³É#¿§ŽÞ3œÎN­*ÕcÙ»U¼ZÚ±µëÒOͳ^`ÕõãÓ)4˜¸57²·ð²Š‚”„”#³á4<{;¤ÖnþîŸ�¼ë­1ñ¤?‡Àcål}Z|BsfÛe$qô·ÿØõ?¿>8U¯„p(òy`  Œ¯ÎAW&k�O½ÜõüvûÐå?úÍ™Ó6M 'ì¢f2Ût^ É!K0D:H[‚…‘ÓN¬wDI¥ñ+,e{qÌÎ{µÜM–`–�ä>Ö}8|É}ü¯ +°ÂD{_·û¶£ ~!à‰†·ED¡”(ª¯ÜŸÜôw]GH Y"ë‚%˜¤Õ0ÒRX–HüÖUtPY³ ]KÚÈbAŠVlX�l>nZ1+¨¥9¨êm_§Šh°x†�€Bªd’‡Ÿ(ÿéµ=ãõÒbÂÀ=7d£–Í��vÿΟöïÚ×M°â�%Iø„©ª…$�„Ē䪊¿AÕ×χÖ6¬©vuZmKüç•Õ;û…+BU5QMTÕD5q˱ª¾ÐJu²ëK_ïÛ>ÜmÔ))hÎ�sM²€ Ldn}¼ôwÿºD”¡±ªUIAP¸’eÏz´p%ôE\íØKl_·‹]*œgD·¹�ƒD�J`ÒJÕ†cx|‰ëâÉ@¹ƒ‚T¾r»(ÞIÖ6(âéòë<`r‘K®ŠKlŸ¿3†·o ‡åÓôE¸-ø %*j¡¥,=&œ»Õ$Ã:‘=~ •£j˜°Øé GàØìƒÜÿÕŸuFŠ—¶E·à‚ÜÜ”V/!U[Ñ™ o9¼Æjdlw´o'zW¦!©óÇÍØ dYHÀ†{—'¤9×bŸÆÚ3DuˆUrq¾Á�ZÔQ(sD{Øæœ±úø³fïHåð›#Ò­{èÙmѱ+Å‹4”a[VÔÙ A¯™òàÔk‚Tʶ§#T#mçxk}îŸóžpI”‰ÞCÙzìaP9™ÁWöS+×éŽÎ<þI��¤¡w àâ™bŸ!!ŒŽr Ý©vÞæƒÈè’Þ:i¬°î0­p8#2,/VŸÍɧ!c‹éµÝ[‚I c4™JÚ@4³^¨ˆUg«åí;+©§FŽ )(²lUš^ª ")•ÊÁZÐp0ŸoE]u2ovE“æÈÊ-È6yÇH ¨”…z,®åaÀ’&dkpÇP.¨,ÜÁ¾Juhª84½R�ˆµ³BPKâ«7QÚåb šA ŠtU¸V5ÅŽ‹ƒ[!vÿV™˜¶þ€x„Ãc5¦| ñ ñÄ®JKš_ž…<h�#OB¼+*±„ Ì™™©õ гÔôU.×¾³_[�n]$£q~´Š–{a•$ØgÜœU›\9#L$ÒÄ+UUAD¬‘ Ü�|Α/Ú¡Íï Üã…]ßÓ#aK/\Ui9 f®õv9[‘Öz/Ì®bY~¼Ãmñ¦e±d“hèEùÇòœEAAmЇ›T,xÞ""'gæ¤ÊLË6�);½ËyB�çO³ËÕOaêìEï*µÜ Eï_Ã5_EVTÀÄ!,¥‚ªÂZ�ªªõg%yÑB)Ïð<2¿‰j¶•’Ž‹;JqU¢�°Up{„É\UCH©·[7¯�ÝY�>­²Ð]aEŠüÏïW_,‹(®£:;—Ùö¼?à™qŠc˜RþZ̵ÍÃn$†Z–cOážÕ2ù*|2KZ ý &DË�—¾UÇÚŽ¼Å5 ûÎ/(ˆ«soåÄòÌL ùb¿¡ª&iÓû¼ã[ä¯MÎ<¥zÜšús¯V˜ôPHG€�…ž¾¹vòñÓ*ု,¨'�¦¹ñúɇáëäL42­DâÏ�lzíYÂì×gI”DI$|ñW!"œj›·s„œ�U‹¾c¢ÍÊ ›–H.øMç‘«.Ô9 ']‘D=d-¬¸êÍ…O¦Û£hŒñç2;E�D¨6EÚ²z…¿bË%ª«’(iÊÎA•¼®8¬®_9ññ÷UKQ ÊC\ÛFC ÒžJüñ+ëË{¦[§ÖbÇÍ?Ÿ¶‹ÊÚw <2…#9ZÝhU#+è6DЩƒ43Žr”á=7Ev’%òƒË�[¼yS)†)�|±Ùÿ¼ì¸‡‰J çi?Š\8WÞ ND¬6ˆØœxarÌ™š¨6ðµfvÒ d¨ÏÑ4Äb15âŠÉ¤Ò@Î=Ë J¬î:ÀV‰TX[ñ./‹r—êZ¼*Ê\ýù÷O<þtå_ïìq‘ü.4»�èä“S´�H™,«}ÿEիσÔ}„Ÿä†P0¥P¼ ,¾6ä¶ÑÄŒIÃ_�kÏáèïì¸ÙIýë uÑ\x¯v¤nP{Oÿñ† w qÒÕWzÇÏIì®G±�;Ì ¡äjaJ”r="ŽJtârê5B—2˜Šñ˜§å�JîÌÍ$Öñ=¡�6JÍË»*I½\¦8=ÿ7÷¾…°HEVöíÿ£_åXì÷îëQ-Sƻʃ€ƒá–+Õ÷½«þûŸ>0T9 ê‹Y‡Ê~ÁÄRà…"‘évÍ<š6zôÅŽz­ÂQÛiTŽkÈx sR‚ŠJ©w%V�¨hä…uñ\;Ë`\Gª^ir_ÄWj׎n¬>Í Ò™qªÏ¨ØŒe�B­êm„Q…–®7où œüSq¹_]IJÿŠôE ø8Ûˆ2CJSûõ©•ÚXkõ:„Hu•åïïê˜Í1w_Z¨é‘€¬ “‚è’þéwo¡¨L;ö&Ó$�ízЬÁ•-¹�¢R¼~íì/}xú÷>q`Ý’ƒà$£íéH³÷¥tWS�6IwDD£“Ýþµ%;öWˆM»ÝÕB•…�4qÉS±Ýû,ÍÎh¥;{·/ð´Õ>J� ÎrX”FRYjÎúXiÓÙº÷EÝ£q-;²It'fîèÖ¡0´9î:F4JOcjZ˜æ¦�7ºåS2Ù-ÓÃhGk‰é•ݺmGçÐ€Ãø�ãgÖ’n7nÖÔF +«†ÿàS³º°çîÇ»^ØV™a«ÎÁ æ¼ü§ 5Lƒý8}Sõ¼ÓfOX9Ù‰ � ­ê×8€t›RcrÃðk &bzö•ž^-GëÖ¦&˜%À:²Ý oÓU[H­:£‡Ë]Ìqüd:ÐŒÝ0�TKõÞÓµïtÏy)«M”=õÆXW™Nws¢u³#¤hGwøÓ"œ€ˆXYLëî§$žšÛ(GÐá s×cýgŸº¨®˜ \”ë�évV�”0qÖº©³Ö—D¢DËJÆ×ELoÏð™Ø$ªîÔE¸8£<j­ú4Ù‚… vY[ºá¾ÁýS`Wç¡uŽBKäÈs¶6E¯ÜÅC§X*f*qÌ^eP*Äú°SÍŠT‰‹ j¶ùV[ ˜ðÊÓÏÔ´Ó“,ø+²À+˜g‡íî'æ]W‚[ºùÁŽO_588°–B�KSçÃŽâÌJ"ŒjÉP:Ñ$ž»eLmo>!DáÜû¹$ö°?‰hçîþïÞÛ)€QwQƒuÄ7nÑgÈ–wEÀ‰Ýõ�9¸-¤ƒSVíÐepµvŠÂ“@!HÈ'W_×Sá\†,ÊA= >gõUW�÷,z‘…|¤DžC»Þ¦OšÅú…ïZ”Dy×Ó:òª6‘�T†Iÿ$cÛfxrÐh䪨8á‰ü‡(ûÞæ“JYt‚¦‡‡“+©áÐ Nm•´’d&ƒ´ k(ô R"¥ôØðtiþ·{^|­Ä)B„X+ºI †äô`�¢>cP–ågx#©Ÿj0c ›ËO=5¢z&µÌkÕ¢†·ºèŠ‘7H†¡DÕqzêtìUiæ;”ƒ‚‹øâd¶*—œS‹JS,…}¸ ³ÛÍi.v†Q$Õ)Øò€i‚e¨ñ®hd;"Ú9¼ò÷¿<øúþrØ­¥¶Bù,¤Œ°ÂƯß­97Y±êJµ¤,¬­õ—rªŒ$ì w4PA¼ŸJ­Ô÷¶ £Hë‘‘'ãZ¤á]�$ûŸ“ù2!`1"–ï?F=·ú·L³!·Ì½(Ò %â©�àSáŸô YúU† Íâ–ϛ²²©6ƒ£!(?=xK¡@ß?Þ¶ò©—J†Ø6=—Öõrß(GÎlà� Áç’Ls}Ї¶ØRÉë¥ó(�-Îô�K XñþâwJuæT©+¸`Z[œŠzÊ�š!ff¿}òZ™zÝû+šÇØ03ULO÷\|Ng§v¢RÎaáGž·YSn¦Š”tÎ,HÓßó´­&ÞNkVŸÛíL¤h—æ§kéñÿuŽŽ1é� �#ùïncI[¡âÿÒצ÷›¨[—œWöG•Ü ^mø_ºä£­~-|×ÀåìÚêñ–V�tRÊ Ra­™¾“ì¸Sa[ž&ä@°Ú¾º·¾vùŠ36Õ!ã¬!ãO‰2'\n­äÔFnŽáºÏ‚”4L-§å»ö�¹ai4^ßø»_ºû阙%cy[bð†*H[Èh¸5·E“¯›Þ Ò½’`=íi%èRFú8 cÚ‰ÛýȰµ^Èœ‘{I¡J{z@žP‡A‘2³ë>}öëÖÎän[3jú®¬L&Qlñꫵs¶¬Y5x¶æ2Òü›ˆRªÃtTÙ,Òþ³‘kx9)?q.!�¬Ïðl&H§}úðPWþ1¯ýÓ^ó®KDÊ&YàK”ÂW›Ò‚UËm›tUIÏ`j{iàÛ±D¦Æû�$¿rÍ€ò¿¦7d$.Ü€’zÈ@ÌnyÒâTg(�+#OÛ'þ¦_—ÌÜ”‚†Gd*Ï]ÁàdxÜî> ï9wUo´¶žgs�ŒmÍš‡_Í+ ã©ñ»ÀCóÔ"?©6×L�+ú‚¤²úëwÿ_¾OÖS+5õ“!‡û»€¡h#ð‹áŠMV÷ÓÌ~8QKý®¨WÎêP¤"n^©¡mT2 7 (É üE!œã,),ðzpfˆôZ‰ Bqr;•¦_ÖÇ¿$£/h!’-OQ¥…éûâTfûîêìL×Ûß¶¢ƒ@¸Z4Èh{F‘®ÈhÓû³©4¬ÂœÝh�[ *ŒÑŽcnxüÔßý“ê¾1¢lú‹DÊNkjFŽ´1fvÓô0÷/å(  å@ëE ›>o4ð3h¥‘Î{CÁ�’'¡E&’Ö3ôu!–6šÞ†'¿l<¡‚ZÝê.Éœ[…Ý#Gᘠ¢ôÌÖYµÝ[Þ²¼Œƒ, PNq:¶rã„ñæ¶öÒRóB4!RpÁ¥é#LjHI;WßøÌ‰¿õÇ3¯ì1+4G’Ó WZ#GóÜÈåéÝ:µÃô«ƒlI\òfAéhÔe‚‰fÞOƒ�›ea†¥ïüOšÝS�m“”Ǟѧþ·x"gWÈ n‹ë|”Ã\ Ã<öÜt5î9kËP�©Öœõ_›¦éê$ƒTiNÔA>¤µ6ò h£ÑdÇ÷¸>ƒI”ˆL½s÷ï;î·ÿ¤þ桂 ´#¹¿ÍV cWÍì¡ÑLy]+|p¨‹*B¨iÓâÓj‹(ÂÑÅÍ *X±2;k ¼ÙUðy®òl´ÿn}ú+2ºUH¦8ZËü>-¨/¤.G5V<öÂ̾ƒ]§�¶f »®Étj¡¦ýPd…MsO‹Z§kŸ»mnë¢]Q‹öÃ( ŽÓéõÏCÿÏfw$€ƒÒ¸¾º@ä ¢ÔX”ƒP*Bfºs‰pmÄŽ>ÃÉw­‚é‡&J ÀAÁkI¹‘4~ŠMÓ·§,15)2äÀ²GŠÔšúóêuúü×íì^)ršåó– ½0*ÊïØ[ÁS/ÕŸzNV­;níêNÖIÕ˜|,AÀÔ–,#c‹9‰ÇæF¢¢­¶…•Él6dJÚµö©gþþÿŠþúÛÓãU1\Ñ¡TphÚüÔ=³k¡ÊRËIϾ�€L2ÃãÏctGÚ±D¹$œU<€§ ”?t}1¶Šº(ùí".s ¾Œš�J¤6J¦iäa}ñï’�w"© 糄硨í5}%5Bxm¯½í�éi»|æãúz[%‰)53äQ¡€Ú@<‚²S„ Z„Zþ …‰Ðµt„Núû[VýîŸVo¬*’žfêv>µšU+äð–°VEj]mZ€B4‘ µÏ�ÈY3\´� EÝ4t­ºDûN•¨ÇY…ñÿºšY`žZçP O°Z0}@ÕWSOù°ç±D€I¦¢ñgìî{ì�G�Œ©qg5¶XåÔ¼±À–J,n:®ˆ*ƒDa ÅgžPúÔ‡úÞ{n²º{ÏìÓÚÙpTò©ÿÅL‚âº4ï… <„aÈäÝäóš¢ ºú&kodðËÿR¿ëñjµf\<¢6š¿sïÊ‚;�ßñÖ¾‚qZ< ªJº° î�½¬ R/7ÓŠó¨ÿ­ÚÑ/ ê«Håõ¨â˜r!nYY>×¹–Òד‚2¬6K�â{{O'É4¨pža3̃á‰T³ð-_Ú\TâÎÈž±±rÕ¥]—¿£rŠƒ]²µ1�gÙ&!<ÊÏ-=5-�ß̽%~ø¡ŸàP�+E¨tÇÑÐëãC·>VþÆ�Õž®OW 8/H5 ™RÒ‡€H7mk䈌(b*Ôu ž‚%'S÷q(wG’ú€ÜØÂI¡Å‘5/ª7˜ l<‚%Û:ÕFtj—Ž<'#ÏÊÌ.Ï“å¹>„/ò€«9�pgP°ªÕ˜IW/§wœÑyÑÛ+g�Œc—L”k†gASdã`é)J2YŠKžµ ¨Çyß+ED�V{¦¥kïdçÓÛÌíÖî| yq'’X‰�x]%o"9âÈáû-bR#UT¹Œa"§9(XHÉ"*Syˆ»†¨s9u¬ÐÊ2uJ`O9}AV�+íYR’�pÐ8™AmXf÷êÔ^™Ý¯µ1HU€A¢E½4X=¨8¥E”ÈÈC5ÿhNܦ úcw ‘R¤CƒºaMtÒq]×™ÕËí@/—ˆ9eƒÙ„SZ1"X=?wpW�­NNëþa³ugò«ñÖ×tÏ�¸ZS€ˆËa�\0ŠÐ(,ëa!¸ ¥oѤæxÞ˜ÀF=£i˜@6Ì\�M²ˆG›b¡*�œzÖêÍY§óæK.¸µ !éØÄERWA5"”Tnôæmæ J ]+'‰U+P5@ÜkiÕ%:Иû\ÙÜÀÓy*B³¦›æ~yyD¢@�(Îw�ö‘mò9;T%¡y#2~ -•”.‰¨šIæX|Æ—Àæ‚ Áƒ#|ŸÓG ev1ö¥v�ÎÙæ 0ÎÒSýU.Nª�TPø»±‰+¬F(`…æeiÍuŒÝn±Ô ýyèœy°‡Øšr®o-°‰Üý®ða0ö·vå¸ … æA‘k¬0ÙʈŠä‚pÝéñy móÖ>§EþÚzEµ5ç¢y\D£]:­��zßy\™c<�q¶½¥‘ñÎ=ª®æ”žE¤5r¸ó#„or[䮸qo©ˆ›Ù �¹reƒTì´ó 2Ú^ÊÝ’ê&EU¨éÎV§l;Ù H7žÉ-€%ã±™à0'4´Ý 9¢æóÊGÐ9‹ à(füð6W¡Û—± YÜG¤ç܉QG‰ü�vKÙŠf áèž>Úíš¡ÈÑv´õÊm­›@Ôª‰«µOát©VD@V¾;»š/ã”üy£š+_ÚÞkØb4iÌU• …9#󆽹†1ï«[´Bé<I‹×¨©èƒ/Á5ï.÷Ü�Áœv•Vn¢9ÎxÓÔ..MÀÈ|¹s �€7ÒáBiUÐbIÎ&ÐBŸi5•vPuwS‹ç�Ä0æè _־ᎄÅ$ëæëÚäÈJ†µÊ²O«:úG¹Qe-½kq=ƒâ›�ºxD+´´MooÑ~ÚX³—•P˯Å!!Ëek´dþÿpw¸|µî¼%tEXtdate:create2024-01-25T21:10:58+00:00¯Ãº�%tEXtdate:modify2024-01-25T21:10:58+00:00Þž,tEXtexif:PixelPerUnitX08‹*µtEXtexif:PixelPerUnitY09I@‚tEXtexif:PixelUnit1e–ÿÉWzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚bidict-0.24.1/docs/_static/bidict-types-diagram.dot000066400000000000000000000030521524342314000221220ustar00rootroot00000000000000// Copyright 2009-2026 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-bidict-types-diagram for how to generate a PNG from this file. digraph G { dpi=300 node [fontsize="12", shape="box"] subgraph bidicts { node [fontname="Operator Mono SSm Lig Book"] bidict [label="bidict.bidict"] frozenbidict [label="bidict.frozenbidict"] OrderedBidict [label="bidict.OrderedBidict"] { rank=same bidict frozenbidict OrderedBidict } } subgraph ABCs { node [fillcolor="#EFEFEF", color="#666666", fontcolor="#333333", style="filled,rounded", fontname="Operator Mono SSm Lig Book Italic", fontsize="10"] 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.BidirectionalMapping"] MutableBidirectionalMapping [label="bidict.MutableBidirectionalMapping"] { rank=same BidirectionalMapping MutableBidirectionalMapping } BidirectionalMapping -> Mapping MutableBidirectionalMapping -> BidirectionalMapping MutableBidirectionalMapping -> MutableMapping } bidict -> { MutableBidirectionalMapping } OrderedBidict -> { MutableBidirectionalMapping } frozenbidict -> { BidirectionalMapping, Hashable } } bidict-0.24.1/docs/_static/bidict-types-diagram.png000066400000000000000000001154541524342314000221320ustar00rootroot00000000000000‰PNG  IHDR¬×ù€œbKGDÿ‡�Ì¿šåIDATxÚì�g€ÔÔÚ€{½ö.ÖïZîUÁ‚�k÷ZQ¯J/" ˆˆ«€ "R‘ÞD¥ˆt¤ˆH‘¾HgYØ) »ß9'Ó'Édf23™Ùçù¡ì”LÎ{Λæ>Œþ½D§7‘²âøž/1²âôž@V’"+ñv{:2ðH/ÍTïf¦¬8=É�•è}¸[}æÖ˜û0ú÷ }�íÑé�p¤¬¤�ÞGÊJJƒGÇûØÒ­NÍÊÔöWFÊÊÁÍ‹¾Öÿ³O{ŽøaÉßÚÈJRd%ÞnOy¯>#à*®2SVœždÈJô>\¡>ó¿˜û0ú÷ô¨)¿d¿¬8½Ž”•”-ŽŽ×XzGiïFò¸æg ¬¸ƒ6óG¹/ÊÄž@V’"+ñv{Š3°¸x祾|âe7Vk—™²âô$CV¢÷Ⴈ§öôûpA\§“$+No„#e%¥A‹sSYôvÙ �ý«2[V$·-˼ž@V’"+ñv{J3PÒTýÞµ�çîqh§dÃæY‰Þ‡;†K~�¹£/…²âôF8RVR´87•�B÷ô—lÍxYq�ü}Æõ²’Y‰·ÛSš�‚mÇȯ¾|Ĺ�’ ›;dÅÂ])ÝÚ'IVœÞgÞºœÊ Å·©lëÝÁû®¹ªd¾¬¸NØ–i=�¬$EV¿éõÒO~óø¿Ü)Ù°¹CV�d%seeùQò[Ǿ9ëÀÜÖÞ)~#2RVΛ4cþO½žö¶¡²‚¬d�¬<#¿ùO'w ²’M²²ªß»ïö_óÏ-ÚåÍq÷á¾­+æ´OV2·i”‡-®Måê÷‡«ÏUç¢]—6ùËæXoÄ‘9ýß}ç³i‡£„1b™¦ßÓû=%+Wz§�f¹ ÓzYI@VÒ“€6e ¢’üf�èMŽH–_»¿þBÓŽsc¿~dž�…3>Ïùhâ¦,ÛÜ!+ZÎÓ6’¥jl ¼7ùÜ`è}}ö“Aw¬åXÿž `â{�]¦Ž‹ýs"¿–ŸW{œ²þ¯/-.�H›¬8!hñv|ñ\õó­¼ ÑÖf®÷/ÿ¢.(”[· ÿ)ãr½ùÍÏÓ^>ëµ½�W£/Sÿ{¦¿,+Å{ÏU½±/ÃzY‰[VìLÀÔg Æò›O†½5Y÷ô•‘;§[aàåeçêPl!;ûÝò¯‹O}¦¸xw³³´w_Ü�U›;dEÒ®¹ÿ’ÿy?ûßërý©È/ÿ|kÈ'Þ¶ú=a¾ß>z´ÿó}¯vpE²°¸d4"M²âŒ ÅÛñÅ Ô†Ç?Ãã_ê›M´?Ú–µ±¸xáõÚFª(j#}N ¼qYàfâ¨Ë4øžéï…ÈŠvFݵ%ÃzY‰SVìMÀ”÷ûÞ+eäçOºÒË^kɲøßA?ö¯Íþ×'é¬KèÞÍ Ëräß·O»ÈÿæÅ¹Ù´¹CVTu‡ ¨÷­ï½VQú¢çÑ.Ý>lµG�ü‰‰!»ž¸e%³‘&YqFÐâíøCêp§|˜K\£ýñB`YóŽ´*ãý羨���¡·�½Á÷F”e~Ïô÷Be¥§êŠ¢ ë d%NY±7SÞï+ôÄâ/KÉ2å¤�/]ì¿h3(ЬfYGùçEMK½ùd6mî�•.8à}ïYó¾hþÅ6Ö¾W¼¥fè÷†ûÞ¨™�¬dv#Ò$+ÎZ¼?_}òÿß µ-’ÖŒ;ËX±Q!x1ì­J¾7¢,Óð{¦¿*+oÉ¿n,ΰž@Vâ”{0åýþ½‰¬˜'Ë�^8Þ÷Ƴ!Îa"+†YÖ#òk¥~ɢͲ¢Ùé‡sw/ëýOí�O|§ø¶¬úeÖ„‘ý?9F¯/>Ñ:¼aÿ}TéCóïo¹<¬Ÿzú¯ÊÛÕo�/•îcWqÉhDºdÅA‹·ã{«¥ª’�£^ÐN ÿ¹öçï¿èuŠjdà'×GmDqq_µ™k4%oë·�ißúÎûŽù2�¿gú{¡²rŸüëóâ ë d%^Y±5SÞï}MdÅ4Yv]¨®õZU¼qø5šW,ö.³Yé²ÇÒ©ÿ8óœó/¼ä²3Õ›Ç[ÈÎþ¾ªŠo9£Ï�Ú¿dÑæY‘<­í% nÑ®æûЉ:}±@�Ö»_‹±vG×[žW¼óÿ´ž»üž³VD®QÜwev#Ò$+ Z_7ü DÝ•àô‘Àõër÷4ê6aÍ‘è�Xœ¬­>[ù{£5J¸ÎJf6"ÍuV´8:¾ŠZbnà…ûÕ ýƒ>r™÷Šx«e–Q'ø£b5 ð˜�g,Óì{f¿$+[»É“ãç¯+¶´óqPO +qÊJ’0Uýîå\æɲ^ÍåýkÏ©ê33"¿ý§6 ÷3KYö•úìï[+KdÃæY ©•£™êÑûb²|©Ìêâà>lm¥«!ôì¡â¤ÉJf6"ÝEáÒ´8:^;�ûgà…çÔ ]ƒ>¢oÊÿV{Ŭ›å³†Nñ/t¨zó‡â¨Ë4ûžiД¬œùQ§¶ +©¹�•W[’'õ²’ ¬Øœ€©ê÷è²¢Ÿ,jŽìÅþ*)Ú´�–_þ[;òžµ,z«ƒ:ÍzLQölî�•�>Ì?Vþùxô¾¨ò$ð}!å.Lûðeõ“‡ã&.+ÙˆtËJúƒGÇ«¹öe‚¶ƒ¯j7(}ä:Ý¢š5âÓÐW¨7‡G]¦Ù÷LƒVn¿–n…,‡÷²’¨¬Ø›€©ê÷è²¢Ÿ,êâлþ?W•Òî:£P›ŠúŠÅ,›¨þç{ï¿Áh²as‡¬„V!¾!ä^þ8¢¦=}á`}1ÖéÃ"5¬ß,N¦¬dd#Ò^n?íA‹£ãÕÍ�eƒ^h¯V§sÐ+ªºÃ3aß3mÄò�¦�ϪÙs‹£-Óì{æA 6ÐU=ŽX‘Gõ²’¨¬Ø›€©ê÷è²¢›,«ÔZx¡œüûaŸ*R¦àz¦ÈZ–OUÿÚ÷^3YÉÈͲڇj,œµ/~V_ûÉ÷çõçkúp¹úä äÊJ&6"í²’ö ÅÑñZ토§Òk�5ìô‘òò…ÿ†}Ï´jóÔdüWC?ÿ¤S»ÖÍžr{Žá2;g´ÈÞ¿ÛÂÎÇQ=�¬$,+¶&`ªú=º¬è&‹VJeNà…ªjmص"íâн‡,fYñ,í6ißGsÌd%7wÈJh6TŠÖ#ÕÇò}T6³Ð‡“C˽&GV2±i—•´-ŽŽ?9|‚mÓð#6íÂõÃaß3kDa)½»1{G[¦Ù÷̃¦dåôœ·Û¼õÒuÞÒYU-ì|ÕÈJ²bk¦ªß£ËŠn²|è«këã õ‚'äCÚiÒÊû¬fYñœÐŠW¦²’‰›;d%´Û[ÎOBÏ¿ºBOÎ÷á��ÂI’•LlDÚe%íA‹£ã/PË ÔÍöN° ž «Ùj†}Ϭ[ô¶†®îÅÑ–iö=ó ߺ¼÷mmküEqfõ²’°¬Øš€©ê÷è²¢›,Ú·^Ð.Ù„œPÔŠÙ_S`9˼5"[’•LÜÜ!+¡}Ø<¤@•a_¼*ÂEÁÏd±Ð‡¿$WV2±i—•´-ŽŽ¿Z-sRØ2\Û‚>R]¾pWØ÷̱ɻ,}Ü©g_tŵå«Ü~ïCO<7¹8Ú2;g´Ð¢p£Ô›7gVO + ËŠ­ ˜ª~�.+ºÉÒ8|UÔÌø£ƒ?ò¥º›æâÍÖ³¬x�zk€%YÉÄͲڇ�ë=ë;²/´G1ýêÿ[6´Ð‡B'l'GV2±i—•´-ŽŽ¿/ü�ª0yNðGTÍïÛþgÖm]ƒC&?«»L³ï™-TV´[œN.άž@V–[0Uý]Vt“åmµ*߇6þü O|¯ªñŸ¹*†,+þ%tÆš©¬dâæY íCUK°cÔ¾ÐÿÆûÿ–7¿»êZèCmÂRãhûù’•LlDÚe%íA‹£ãßp…žcþ[V·tÝü‘»ä+Õ¾gÚµŒóŽ˜ü¬î2;g´0Yy*âìPô²’°¬Øš€©ê÷è²¢›,]Õªô;ʸ/ð÷¼T5þÈ'æ˜eçbµÔ>–d%7wÈJHîUu“‹Ú‹Ô×Ú‡¡-ôám°í5^£ÿèÝÄ–ý�H·¬¤?hqt¼V_ûXÿ2¿Sw‰8ùR9ì{¦�PÙ]S£�Ð _¦Ù÷̃&+u#/ß;¿'�•DeÅÞLU¿G—Ýd™úèBïC½>öÿýÛ?Ôe¡)‘‹3ËÎ_CO´šÉJFnî�•�>üXþu]ô¾Ø­=[Á6NÝ–QËBßQæ' íÞúu ÈJF6"ݲ’þ ÅÓñ¥C++ÔSEâ¶El*„}Ï´Zq˪GQÑðeš}ÏÜžî…6�¾8ËR*ëtùדVúÐû˜Îæ‡�ÖH+BZ¿H÷͹®Ðçefd#œ(+Z_|«zñßÞã—ÍgDNæ{X¾t}øâ̱\3 jk C§¿L³ï™-TV¶ªËâ·9¶'�•¤ÈŠÍ ˜² Œ*+úÉ¢=º°ƒïÏ»Cd˜wEøU"kY¶6qÆŠ�7¿ò~÷«Ln„“dÅAA‹£ã‹]¥½|ï ¼-ýµËÙþ]æZõÛj~ß%ÞÙé{ϬÅ;/ðÕo8¾Rý‡L]¼zË_–iö=ÓßS²rÞ”ŸWm_1¸±:ts•wnO +¶Êн ˜ò <°J¡êÊÖÔþ½*ßJ²Ü­­G�m"oºB.®hçÊÞrsE÷¿¯ý¿+.½èü³Ï8µ«…,û=ª¬dÊæY1Θ Ž Ô@®£[€Ç5W½ÙÆ÷çq¾>ñßfú½ââ¡¥ÃÞx t•Ú†¼ùDÈ{¼¯~ŸÉ�p’¬8)h±w¼¶cPø*[^°Õ÷VÍÈ lhM!¼®ÿâCV–iò=Óß‹,·_n½s{Y±UVìMÀ”gàB�ûÀJ²üê[“Ë/ÑþÿϽ¦mèo!ËV„ίב•LÙÜ!+V2æÂ r }¡ 韗¿v¶üO+ߌ:;ô�°û»=üfèS¼? ÙgÊJúƒ{ÇG¤¼ëŒÀŠÎ¶2PýÚ¤‚¼ÿ†Uõnbe™&ß3ý½Y¹n³ƒ{YI’¬Ø‘€)Ï@=Yn)Y^ }çšMæ�g!Ë4YùØ’¬8{s‡¬DϘR�çGëÃÒ…Ú»ž{=8þ�à›ÆÍ¿'ØóÆqÁït [§¢Ž§Þü,ä­÷½¯.ËäF8QV´˜;^í&ƒ�_þô¾Î¶2°A4i„â—û˱³¥eÏô÷Âdå¢þ‡�ÜÈJRdÅžLyêÉÊ�Ö’¥Mð5=Q?ÏB–­ Í9YqúæYÑcÿÕËúâuâã‹CÞÓï }Ð#ojß,ýèyްÌ?jXûždï¸zåü;™‘kõw¿§.ô¾ùCÈ­¼¯®ÏäF8CV´;^1û_þmIûàÊ–‘ÛÊÒÁSò ᳋/_¸Ô¿Iem™†ß3ý½ Y)uu³É�ÝÈŠM²’ŒLyêÉÊ&‹É2ç&ßë7NŒÚø5²l•‰¬dÖæY1`÷ø>í?ßâ£Ð­¤vöý…×zËI{·ì�y… 7ýôõˆ1§ÍÝ£û¶gù#† 軫¸d4"å²âØ ÅÖñ’¥9ÏÜVý©×~8lw# ×Nîóa»ÖÍ­�±�ºß3ú½þn`¿~ýO]s 8C{Y‰YVÒ˜€¶g`œ¬øð¥û¨×ym|ߎ5;3~s‡¬€#H‡¬Ø²�¬Ä²È ²‚¬²‚¬²È ²€¬ +È ²È ²È ²È ²‚¬²‚¬ +È +È ²È ²‚¬²‚¬²È ²€¬ +È ²È ²È ²È ²‚¬²‚¬ +È +È ²È ²‚¬²‚¬²È ²€¬ +È ²È ²È ²È ²‚¬²‚¬²È ²€¬²€¬ +€¬ +€¬²È +È ²‚¬²‚¬²‚¬²€¬ +€¬ +€¬²‚¬ +È ²€¬ +€¬ +€¬ +È +È ²‚¬²‚¬²‚¬²€¬ +€¬ +€¬²‚¬ +È ²‚¬²‚¬²‚¬²€¬ +€¬ +È ²È ²€¬²€¬ +€¬ +€¬²‚¬ +È ²‚¬²‚¬²‚¬²€¬ +€¬ +È ²È ²€¬²€¬ +€¬ +€¬²‚¬ +È ²‚¬²‚¬²‚¬²€¬ +€¬ +€¬²‚¬ +€¬ +È +È +€¬²È ²‚¬ +€¬ +€¬ +€¬ +È +È +€¬ +È ²‚¬ +È +È +È ²È ²‚¬ +€¬ +€¬ +€¬ +È +È +€¬ +È ²‚¬ +€¬ +€¬ +€¬ +È +È ²‚¬²‚¬ +€¬ +È +È +€¬ +È ²‚¬ +€¬ +€¬d¬¬\Ñ2…v¶ÊÊRÉ=ÈJˆ¬üƒ!vÓ4›e2 Ûd å +YH È +È ²È ²È +È ²Ä7Õ!ç‰Î¿ÐI+tÀŽ�к$uaÕSEþ“¡ìÚã)ŠùYÔ§Õ.ùuÔM)ÿÝ*WŸ]æ"R*’‡²QV *?–’ªÚ¤ˆHd,ež±›HØÏæ*êpþ¥”ÿp+ñ«WÿlY‰™¡GÉL¬}„Hd(y×Ë<í'"`?3ÎQ®òì¾”ÿòù»+èd¼ŒP¶òt!‘ÈH¶]+»ïì¥DÀvŠºªÍã1]ÓñÛòòÓûô²>F–•éø¶’‰l¸\vÞ…«ˆ€íì~D�V¹(=ç-‹Ÿ®@' +àç»ceB>vˆHd¹åd×]²–HØÎ¢K•«Ô,HÏÏO¿]jÝ€¬€Ÿ ÇÉ”¼?‘È0Vœ/;îªMDÀv©íb™œtMè;|†øùîô²fœ(³òž¿‰Dfø�)»íê­DÀnö¿¬õ˜œ¾UxAüþmô²AÌ:Iæeõ¿ˆDñóé²ÓÜùDÀnVÿK¹JÕ-i\‡±òÄù�¬@0?ž,3ó–=D"sSuYUê«ØÎ7²Ò¢«T“´ÎäÛ/�!ÐÈ ³P¦—ßE$2„iêÒ]uôÀn [ªb™'�Lóz<*VâºY�ËÙ\®w‰Œà[u ×}L3°oÑÚþžî*ÖâXŽG�å÷se‚^Ï%ÒLà Uç�DÀfÒW´6œ?�ë1ŠAV ”•êFØn!ŽG{HÂSò°™t­�ànžä�¬€Z‰±«6 ‡Ó«4tHé-ZNo±*§¤W�ã�ËTAÔ\"áh>T³ÿð¨l›IsÑÚp¶ËÃ’It ²ál¼BfêÅ”ow2Ôæ´%�°™t­�àf±:uéd"Øv�z0Þj"áXÚ(Wy‡@Ø‹ŠÖ†ÓI>S�ë½È D’w�L׳— gRôŠ*Võ1‘°'­ 'W®ÑúY�H *Èô8k)‘p"‡_T®ò ‘°G­�@<¶ s�ÐÁs“ÌÙÓ ºÊsê’ú"`+N)ZNŽX©rt²zü)'u¹N�G$œÆAu[åÑT‰°Ç­ g‰\-Îs#+ ËÞÛe‚œ8�H8‹¨jUcˆ€­øŠÖîuÞª]Êtzd Ùw§Ìܦ G9d Ù+ÇO&v⨢µá4köoúY³cxö‹NB»:wâ4"`'Î*ZÎl¹nëè%dô9ø°:ÔK$œBAEfØ�ÊֆsD^¡êL7!+`ÀágÔ\ÎÑDÂlWõoÎZB$ìÄqEké-k¿ÐOÈ ÚŠv—ì"á´ç œC­>;q`ÑÚp&ˆõ+½�®BVÀÐVTý±2‰DúY¯ž0yñ"`#N,ZÎ!Y¬®}…¬€!E�d—îG$ÒÍÊ dO\¹‘H؈3‹Ö†ó”XÇ{è,dLl¥©JåîD"½,?WÕ«ÚB$ìéEkÃ)V²¬‡þBVÀ„·”­t!édáé²nÈ'öáØ¢µáüu¬XÍát²fä¨|nG ÒÇì“eTØE$ìÃÁEké)Öóqz YS:¨ŒnI ÒÅôeTÛC$lÃÑEkÃé'«Aî§Ó�0¥¶’NÆËSÀ®{þ&¶á좵áì”bõ-½†¬€9ŸªYh-D:{Œ*®ÉQ€}8¼hmÕÅʾH·!+…ÏJËÄ®WD$RÎ0u®úÉCDÀ6_´6œ®buO/¤ã�ˆÂÐ22·k!)¦�ÒÄgÙJØF­ g“<»=�®CV #ÔþÓì4SKu®’`™P´6·Xã&ô²QYVæ÷ØJ*ÑnÄz�@ØÆXU´ÖU'³.­¶«|⑈Îwꦔǘ<‘:r¸ À^2¥hm8ËåZ/¤ÿ�ˆÎ5'í~nKIE¯ªâÁ »ð­]žqk~•XíÖt ²˜q"?Rè*ê!’¥º Û¶a™S´6œ–b½¯¦‘°Â¬“d¢Wÿ‹H$ŸÃÏ«{+yà5€m™T´6œùrÕWÐ‰È XáGõ�š[(üžt>¦\e0‘°‰Ì*ZaZŠuÿ€^DVÀÚãy¤^²9ð ŒóÑ_ ›ð­½¿ C׿¡XùŠt#²ÖX|†Ì÷w‰d²ïNåã¿'6‘qEkÙ"ç°m¤#‘°ÆïçÊ”¿>ŸH$�?Õ 'L%ö��EkÃ)”Š=èJd,²ò|uëß"‘, n’>u.‘°‡Œ,ZÎs¢wÐ—È X%·œLû«6‰ä�§¶«ÿX@$ì!3‹Ö†3F4á(Îi#+`™?.“‰I.‘HÛ®‘Ñ=çW"` ™Z´6œ¿O­D"+`™�WÈÜ¿x-‘H‚ ^®î®\M$l!s‹Ö†ó°hÆCt(²±ý_ÈÕvV]¨ÎZ­#¶�ÁEkÃ,ÚqÜ^ºYëä]'óÿìeDÂ^~?OÆõÿ˜` ]´6ÏÑ¢)£éTdb  ‚Üœµ”HØÉ/ªŠÍõ;ˆ€dvÑÚdý¥géUdb’|uíiܳb# þ!cê¦â€-dzÑÚp>•5 Ò¯È ÄŸ7«j óˆ„]ÌTω¼e7‘°ƒŒ/ZζҢ=“éXdbbïírKpât"aÔ–õVži `YP´6‚J¢AõéZdbC{‚Í Sˆ„Œ;V�°ÞO$l +ŠÖ†ÓQÖ`:Bç"+PÏÛã´¤ Œ(+cùßCDÀ²£hm8kd›x²±rðau[àX"‘(}åÅh×Ó…D q²¥hm׊V½Fÿ"++‡Ÿ‘›„£¹õ?A>U®R—ó»6�=EkÃi#šu9Œ¬@ì¶òœšo?„H$BGµimXD$'‹ŠÖ†³H6ŒbœÈ Äa+ÿS¶2�HÄOµimI '«ŠÖF Ÿyß–NFV ŽMC#¹e(Ý�HÄÀæÊUÞ%‰“eEkÃi*Úv½Œ¬@<;[™>®R݉D|ák¢Â×…H$ޝhí®,mßLÙº\úY�xhÍî6n´Ëh¥?'‰“uEkÃ9"çã°­EV >rÔÁL;3…Ï2åÀ&²±hm8/‰V£«‘ˆ¦ˆÆ‡V¨æè¯ˆ@ÂdeÑÚp¾“gb·ÑÙÈ ÄG'l%öÝEQ=›È΢µá8Y´±/½�¬@œ|ª*F¶ 1 = ò„ˆ@¢dmÑÚpž­¼�þFV ^>SEXëQØÌ2ùU×)sˆ@¢doÑÚp¾�gcwÓãÈ ÄËÐ2rcQ›’ñÉ»^Æë´Ÿˆ@¢dqÑÚpþ’Ïgÿ‚.GV nFÅÃø¬³M>’ÌuöR"� Ù]´6œûDSŸ Ó‘ˆŸ‘eåãIlÅ.—±:w9‘H�,/ZN_ÑÖ÷ÓíÈ ÄÏwò¥ë±CD"¹ò®KÖ €Éö¢µáäË îßÑïÈ $Àe+÷cýQXq¾ŒÓU›ˆ@‚d}ÑÚª‰ö¾DÇ#+�ÓO”Ž{þ&¦‡‚gÊ(]½•H$FI(ZNÑà3¸Úެ@BÌ:In:ªÿE$Œùùt#w>‘HŒQ´6œ?dE™™t>² ñ£,°èºe‘0ô9¡*TJH�’Q´6‚D››ÒûÈ $ÆBuÞ Â."¡Ï4u¥¬:6�%¦hm8mE«/¦þ&² ²ø ¹¹q'‘ÐC»cê^fõ$FÉ)ZÎ2ÙîEŒdä÷se.]Ïœ ¾Tµhþs€H$D *ZÁ•¢ámÈ $ÊJugî?¹Û%‚¡ªÒæSÌäHˆ¢®eKPÑÚp^M¿–A€¬@Âh5Ï®ÚL$Bé]šç'$N +ZÎ<Ùø• dæ�ËT…Ö\"L'5°3㢤­ §èÑúŽŒdgãrcr1õäƒè 6°- @B”¼¢µáÔí¯Ä@@VÀ¶]#·'®&>Úà*‰S‹Ö†3Y �ë@VÀò®“[”³— EQSŽR�‰@"”È¢µá:M„àS²vPPAnSÎZJ$‡_R®Ò�H$B -Zγ"w2�°ÏMr«rÚ"Q|ø9u‘}‘H€[´6œÑ" e È ØÂŸ7Ë Ë©óJ| ª-ËŽbH$@É-ZξD3"�°‡½·ËMˉÓKx< êW�a@$@I.ZÎC"dìòÿ;åÆå„)%[ÙjÈ ?™á?%»hm8ƒä6kCVÀ.´“ %zG­] ;qƒ ~|Ekç ‰Gš'k‘°�ƒ«£¡±%6™¸�(%½hmwˆhꢃߺC—ž²0òÕ…§ËFß�OïÄKÞí­5àjžâެ€ýä¨MN»ð—'ãr}–ñ�ëír�±1�}²lqnµˆŠÖš^A�°™j£Ó2ÒU\—dúµèƒ‰Vœ6‹vú‰²½ÕöÐóqBÑZ3ÊØpÆ Y»éi+STñWß oYOÕŠ‹7¿6þXùÚ=ÓïqBÑZsʉà´' È ØÍ§j¢\‹À sÔɱ›ÏìY+û/КqùÖÀkcå)#WÍýô:@œP´6 MDtÜ„YÛéSZn{êùî¶›w’ËËçݬn¾f\µÝ÷Ò°£äßOr¯%€vè½HÑÚhL—¢0²ö3´ŒÌ®ÚÚÖççS|;yW¹LÞ«ÿ}®¿7x´—>SVöl!=� —{"^£hmtŸ)"Ä|d’ÀuÆái¹_zº+@&ŸZéÔŽ›Ô|ÚžêzW=Ž,°û"׋›Q´Ö /ŠU' È $�‘jvÿ“…Å+ÏÚÇgò¬•½! ¹y¯ï¾§×èl+ÔéòaèK­µÄ·ò:Ù‬@øNÝ%óØïçºBÈÜRüCRcŽÞ=Ú Ï y"ò¨™A¯P´Ö"NÊèm'²Žf‚²•cCwñ™{jeïYa-Q�.,ՉްÂßêÁä®s·ù_¡h­e—÷d’Âô]:dêáÁ{z�)Ť7k4÷&Muß|ôçR´Ö*ÃeÉ< O"+�féÙÊ¥™yëÌ_gê´¥ 'f¬ñS_ÚhWN)Z {d='®–!+�¶_¢w6"3¾ü®^Snã¹í–8xmà|äèbŠÖÆÊ="XOd’ÁŽkôvð®Ë2ñÔÊŸ§é¶åzÀ m‚ÒæÔµ­�•>r"2…²‘Hž]ú ÈÀƼmЖú :K�N›õ¥hmŒäÉ«hˆ²öŸ‹(o°ÏÄS+žS�ó= �B½­Ekc¡ª¬ N�°›Ý]† ȸִ6nÌGô5@:èdEkcBÐ>ë0q@VÀ^öU3Þ½gÞ©•�'7¦TzÀ”UÇE&Ekcc½ Úl‬€­ü}›ËŒ�Öœ–f�)=”þ0áÈ-‘isΟÄ%6þ-¢ÖŒ0 +`'ï3u•L;µ’’ikÊ|I�Ó]/mþÃ}ÿ±ñŽÚ%„Y;]å~W2ëÔJó(­9šIú†ü¡/û<©"6–Ê -!È ØÆ¡‡¢¹ŠëòL:µ²íøhÍ9n½`ÀÝúYòHCˆÎ•ÔJ@VÀNÿ×�AÔ W¢7çĹô;€.ýŒ²ælnЉ"f×dìâ¯ögEß»_‘9§V6½9¥_â<€[O3L›ê…„'æÈ˜­"È ØÆ�AWeÑ©•†QÛr|ƒµt:€.›dNKÂGÎe¦²v§Õ¸›²eÖÊÆc¢´äÌ–[ép}F˜åŽz¤!X¥®ÙÍ„Y{™]³”é>~pm L¸´ë>úÀ€�æ×„Oåœd L’Wœ94BVÀn–Ô:*óO­l8Úl[ëDýkcžŠr^ò_¸¾uÉé?½‰²¶“ÛÄä®ß!Ñ„—MfÕÖü�.0Ứ¾^"HÖyZìn€¬@Ø‘ó�Œ¾!h½á‰•cjýN÷˜ñçùÑï¤ëO˜,3JÄ«lq@V üÕõ >µò‚ÁºŸÒ„Q¨m¡äÒqeµÌ>y¦šg‘!+�$ º&SO­¬ÑŸuS®ë^º SKY�×å<ÒÐ2ˆx=J�HEãªèm¥œˆð¬Þjß0ˆZVQÙ{©WqÝÈÔ/Ë �e�˜“Œ¬@YX«Læ�ZYyb¥T�qt&€šX0•«s(É;åi,q@V ™¬irl¦�Zy2âùʵ~£#¬0¯LtSYM˜bã6¶²Ée[Ωa§Vœ]¥ä·Ò¡«{r“Mt"€%\ÍTÖ¤˜é."w:—¡‘H6a9æèµ},d]/îò`‘VfþtçPº6.6Ë9ËÓˆ²É?Þ yÈ¡£O­, >±òïA‡è<«,)kh*Uºn&>ñRAD°1a@V „<äp¸ƒWô¡ÀjVWDÇX¦Ðmh*T(J„÷EÏgk„¬@j˜\÷íú§sO­üâ+qôs¿Òe±ÐÎÀTx _‚¬’�\@�Hþ‡:÷ÔJMmOj²‘wþ¹ÊTéº�À$Îÿ‰X¶" È ¤ŒµõŽS§VŽ8tý¨+tÚMWÄÆ‘Êa¦Rö®¾ù„ÅäÄå+ ²)D{Èᇮݽòùõ}öÓM±òqø9•ôŽ?þòû;2¡(Õî-k—ýD¥ƒ™åýWnn1.sÖ{î’UwqüÈn$[@Vìfû¼¯º¾VLx܉+õÒÓtŒ1õr>›°ôoÇ&Ýæ¿üøUz)mTó^ý¹äö2oå¾7hÊ*GÛøTùˆ² 8²b#…¿ù[.ÈRêwž¼ÝyIwpéЖôMZyæh±7=ªÜíÿËÜ&4éõ£s'Ö>CÄ·;€¬ØÆú�MØnAvÓfÒG]Î_õYC:%Ý\â:ê¢[ÿ—é­¨ÛqžSkV¿ då6Y±éøîÇ÷BFþ+-s>è�ñ´«yˆ4èç˜ÇÑ훚²·yå�w:Ða)ç¹>Ù>3×¼í›Í� WG9ó&¦±òw‚#+¶¨ÊÄÀóÝGÎZ[àÈvüúýÀ�Íúû¿;BUÆ4ö¯Ñ=GÏÍ¥ŸÒCfoì¶üòÝçïÖõ o/'VÜÝ’°•H²’ø%ÅY¯û†zÛá‹ñÈJò ò�ó:W¥ýø`RSßäß÷Æ,£w !c™Ùûß6¼Ïçíb²ò€¬$Ê/­|‡wc6’ö�Í,ýÌw~¥çδÎU™Ý»o�ßJ·@âìšó‘÷üJƒ/Wr¨�•c÷`ÈJBüÙË+ä]æsN²ÿtܛڀo<%}*ò:{ïOêù =v±n¸÷l]ËeNÛËÈû­¾Â�•DŽðæy'«tú�\‡AÁLï©Ävizàã‘)Úd•º=VÓ`'yc¼Wƒú8ì4ÆÝBVžÁ�•øù«›6´;,!Ï¡Ä�?¾™v¾|J:’n×ZÒuù�žÛÏÓ.t6_î¨=Mo!+§D�•xÙ �o>•‡ÅŽáõ´™+©¯j»R›­Òò'z’A®v�±îh'=(l{ia+“Ðd%Næiõ'zl&Á¡¤±D«ÕÜfKН»NR–T·_]Ib¦vm¿û^íln²R @Vâ»r>H+«Â”È“+#ÔÍ�MeÒì¡’®õRâÉc£vyÿM=]¢“�•³�àÈJöVãùƒM¤6”L~V3Wêý˜º¤Û÷¡Jº®Ü­ ÉeR}UÑv�cö7¹òI‘sðd%vtQg£í$¯¡¤òG{•ß§*év·Sv4†�l5Wç �3Íö:!+-ðd%fö¨ÍfÃIj(Áä¦Ît|“š¤ËWóÙ›."î�|6*o°È)»œ·…¬”Ã�•XÙ¯ò+‹Ii(ÑŒT¶òm*’Σ\¥97,CJÈûHÕtJ}¸Åò:ÐRDY‰�C�ä0nÆfJ<ߪi¶)(¸òw[õH‹µ„RtÞ°§:}Œ_*dåDY‰‰#ê–„7Ö‘Î?È{‰ëþœôIbdÒ½Ë|vHÝyÃþêºãgìvš Yù7"€¬ÄÄ@uË2® ˜¨®í¯Hò‚º™´5%� •¶¢æd½¾Ë»�Ùò:Ð:LY‰�©r7YN*HF«»<ó“štê7^Ë%Ø�Jv}"ÇÝû…Ž8¡Ž�•Θ²b�\ù숆‹Id�¡ê±†‡’˜tKå̘WWjH-ùêêãPGìyj Y©Š +–ÙÓR^¢ŸCøÎ–’ä-z^Sy¥‰²µ�r¶µ–c{žv=„¬”Þ† +)RÅྠ‰ülW[ôùÉJºCêF ‰ÄRÏÊFbì5rÂ$ÛC§ [éƒ +™.7›î"‡¬n,ëy’”tcdÒ}J”!ÌP9�ðXž§„¬Üƒ +ÖðÈóѯqÿ$@ä½Gr’n“|NËÛ;2¤u÷ç÷ØûŒ²RÖƒ +–�Vê.$BQÏõü%9wä=9ae%!†ô�ßF^Ú‘þ½Ï_Ç [Ž +VX ·ÈýH_€0¶È¿½¶/ I7Y&ÝH" éBÝ‹öqQú÷?5…¬<Ž +Vf8É;�šó|z€Ô… ¯’p8ÙDVƒË'À�6˱í€Gö²râ~dY‰Î÷rÌÎ&w"é.ëØ¡^^y]Bx!}ìh%a›ôϱÝy”°•o‘d%*û›‰!Û™ÔÐAUK´½ØJAC±Ô¾DÒÉ,y˜:7ý» êBV^D�•¨Œ“Çx¿’¹zÈ»&êm·9é†ÈÙµ<‡ ÒJA;1 [¥¿ê~W!+§bÈJþ–Ï?!qtÙ$Ëgõ·ùÄ·|¦ó b ée¾<µ23íû M¥„­LÇ�•(L“Ž<žÀ€ò,È[“N>À°ÑFB i¦£ˆmÓ¿t Yi‚ +QÈ‘e¯ÈZ¶4°»zV¡¼!z0‘…t£ªV¬MûN¨½�• ŠÐdÅ”UªêY `„¬ ×ÚÎMéOršØj 馠µý×8ã`¹�×BtY1å31Xß* kŒX*…þw“îC±¼NÄÒÏXû¯qÆÃUBVZ£ÈŠä-”ß’³Æ¼cïáçN)?³+¤u�3ýSl[ Y¹@VÌX"Åšâµ&L�%ží+ž%ŸqÞŒGœƒø4y�êŒ�ùò:ÐJ|Y1a0'¤¢ð‡|ŠÊ:Û’NÅýŒ¨‚�Ï“hx0ÝûÁ¢ „¬|€ +&cäu®DCÞ2÷�]Iw¨!W�À)l«/Fã¯iß6²R@VŒÙ ¯ž¯!cÌag9 9_·þ6‚ Ž ƒŽÃÒ¾#œ"d¥ÔF„Y1½zÞš|0ENíª{À¦¤#Ö‘˜‚3øF Çvißž!l¥B€¬"QÒ‡|0%_ž+ϵ)é>ËALÁ,’÷XNûžð9!+w ÈŠ!òàXòÀœ6rš‰MI×R,k!g°MÎß’ö=á!+GåcÈŠÑüÚÆbœ. _Ì‘7xް'éöÉ�ã§ åyAÚ÷„Ÿ leF€¬�/ç×n"]Ì‘óL>²'éVËÓîTY§ÐU È1éß>,då!ŒY1`­¦�ÉV€(Ì™ò¶=I·�Iíà$†Šé€Sƒ…¬·%@VôY&†iK² ?‹LiaOÒÍ‹z�ˆ‚S-d¯ôï =G [� +úÈ„ç�­QøM^»±'龋êLDÁ)Œòcì ï²ò,J€¬è#K-@¶Da�œÝUhKÒɺ=‰(8…ib@¶wÀ¾ðS!+§Ä �]&‰aÚ…lˆÂf)+{lIº/ä#œ‰(8…¹b@¾å€}á¶ÒÂV&ãÈŠ.òi²ÝÈV€(l•²â±%醋% ¢àæ‹ÙÊ ;ÃJBVêãÈ ²€¬8UV: Y9çR€¬ +È €Cee��×<¤YAV�‡ÊJñ5BV^G �dYpª¬´²r9R€¬ +È €See‘¼´ +@V�dÀ¡²R\NÈJ[¬YAVì—•Ã��Þ�¬²’8M…¬Ü€ +‰ÉÊÖó'ÏÔkõ[Íë¿P[ÿ½-ËçMžkñ³Û=7Øã)X>vèœøŸœë؈%ñÇ Yša"+….×)µÆJ†¬Ø“t©Í¹8¶S7´“ÒÉÊLy(-@V’•ÇÝnw[ý·Fˆ·Üoè¿w—x«»ÅÏ: “{&="›ñüšx—íØˆ%ïÇ Yša.+‚ÓëÌ.²]VìIºÔæ\ÉÛ)ÚIi„ƒdåÈ9"•º ÈJ"²²£¢H’úïµ– 4N÷­\ùÖDkŸu& ÞRß­Q?Þ…;6bÉú±ÄC–æFD•A¹Ö¿Ù++6%]js®¤�í”í¤4ÂA²Rü’È£jh²’ˆ¬Ì—I²Pÿ½Å[•·ê¾5Y~m­µÏ†1¶[»¤\Ù·¸\ãçþ×íãWóeìÚ�».wWÊ"fC’óc1„Ì’Ñ+²"¸:g��²bSÒÅëIÇØNÇÐNJ#œ$+߉$*½ /@V�•¡2Iò��—êé­§x«†ÅφeP…Ð3ÆF;‘ÚÏ"heËr�¼ñÙ†›Ôæi¼Ù&ó¹ûÔ‡*ÞßhÈúTD,¦í“~’óc‘!‹¹×bÚ}$£eÅå*U¥Gž]²bOÒÅ«ÉÁØNÏÐNN#œ$+N9Ô/@V�•‘$Oé¿5Î]¾J�/ôßk–[fŸ =p{J|sJôÏÍ–Ùû_ï Ý&óLb[®aƒ äY߇çäsŸ¢W¼îPµç®¤G,Œ¢�”Ó Y¬½Ii„eY”©Òg·-²bOÒY�‡åä`l§gh'§N’•â'D݇ + Èʳ"ëÞ6¸²¾½Àðk÷‹¯u¶øÙú‹/–ßýsäæàníßKÊGëË5l°<:|\ž‡½[üc²ÉvóFA²# FQHÊ�é„,Ö^‹‰¤4"Y[sоÄeÅž¤³ËÉÁØNÏÐNN#%+_ˆì9f7b€¬Ä-+;+‹¬ûIR™¬ßÆ‘?ko_|ÄÂß”¿PYûw+µéüÙ–å5ø×ŠnwµÕò_ψ¬0^À¶ òë­œ·ѶèßÙ±‚Ü·N–£` :!‹±×@Œ²â2¹�Ù²¬86é’7¶Ú©ÛY1´�%++rç ÄY‰[Vˬ›'·&Ë'¯´–›™:ï+ùµèŸ/È�÷ã†�WšÉ/¾eáW´émyòŸkÔ•ãJ;Ì>n²ÜíË×íˆÞàWÄËýÕÙf±'y(øûyË~˜¾:pÜ3G.àKù¯ò¼´»‘]Û’s«ûÙõúï…­CÂÑÕΫÿ>cªÁ>dýœ_òÍã¨2Ó^‹X€¯á ¶Z~ÕòênX°PÄrý7km—ÃÛ™-ËŠc“.Yc;æ¡�î±ëÐvæØv”¬ß'ç ÄY‰[VFÉÙt;<;‡>$þñlPzoŸÖ½þ‹/¾8?ìóË>ºÇw’øÖhŸ�“s›ü\�/}/|òf õͧßTt2Y¯ þðïrf|�÷>ëð¢ÚÈ|möÙ‘*Ïjå´T[¨�µmÓ#�<"·ÐÕÑøÁdÅÞ•‡œn÷X�gG ÷#ra?z<+Õ!M3íòöÏ—Í–»UÞsQ±vëzwø73 öx>ÿ|Eý«…Û}×ïJ|®ÎE7øþýª1Ú´}Ùö6Úû?‹޼ʞˆ Û/2YëÑ5ø±uëå]l+WÐý¸v6ù;ùoyÔï.ï=6Ž£~Èt{M«å?sä„ÎÊAG溯4Â`uçW“çð» l¿ö•fÉ”•�Û™­ÊJ¢IgôÑ„“.Ic;¦¡í„±m}h;{l;LVºˆt9£5@Vâ“•åÚ ÿïÄÏd¹Í¹Y¾Ø½s¿¯§þ²ZšÁÔàYa2Cj«Ô�*¿´Ìä³3dN>¼DN«2QOn�zZX1y渽ºebˆØbɤG:µƒÁä4ýŽ&ËÝ%�_�«P ž»±Ñ¸ÁZýHu�üë ûF©Ñê¬xKùQÿElíò»ç×¾c"–[9dƒ^Ël¬G×àÇFË¥6‘—rÕ‰øáêÕ^ÚO?4jÓŠ†¾ƒe£8ê‡L·×ôðƒ÷ȈÍùê¦Ð;Œ_5h„þên—�©y]NIÜ5V½?6¹²t;³UYI4é >šxÒ%ilÇ2´1¶-m‡�m‡ÉÊ¥D²ÌD �•ødå5æsòü÷ãfàËIf•ƒ§½ÉSoöÝ4ƒ?ü³¹rSWk£ÿ0å%ß+åoL·0™ÿf¹™�[§]ºï—Û�=ž9ÔÚþ¨]˜®ä;œ3XnoY×j©uï7kð*ßü—E7û¯“{~«¨¥ ÏCWÕ®PË�ÊÌ®ë,ŽŠÊ÷òxl‰˜Ç³XN!¬òtëϧÜïÛV¬CÌÑ ÿ±<9á±Þÿ´ûM�o—áv¿¶Ý·a`GÝ�éöšÁú«k©¦/Ôößg¡ÿª~ÄôW·»<á¦}l‚*m–UV»¥K=z¹,sêÿ~8lYVìIºˆ�&œtIÛÖ‡¶#ƶõ¡íð±í0Y)¾AdJSÔY‰OV>’·à� :$Yä«›ÿ2‹÷Êsy‘¿réAï…V>•ë!o&� \lÑU*X¸mo©øÜ=¿¸ÝxÄ!Ä@qDãn!¯ØÊ+¼7iË]òÐŽÈåþV)P5ÿ ÿi]ƒ�‘¯Š#»MÿíÚ4³ �'0AF»¦ÜVTÍøòÃrù†”åO$bq¸V[]Εç»óLÖ!æè†ÿ˜ÜÄÞº-èV-ÿÍ™?c�7‰£nÈt{Í`mä÷‡]Xnüª~ÄtWw]¼M�é¢îw¢ßº\Ùe§×ɱ(+ö$]D<Nºä�mËCÛcÛòÐvúØvš¬´irqn€¬Ä%+rÚ{SOàð&(�j…�vm”²fÔûam‚>û[Å ³ëF~õµÿfÅvÁ·ü™ ·á ָݭ :×+Ïæú6UzŸ½×c_ÛeF�´°Ý|Y`Uvת箺Qü”õ/wÞØ,>/þÙÎx¹ýdŠçeö:³ËÝGû�b{ø�;÷‡Ü€ü&723ß“SöŸÛØŒÔîðþ{µÕ=·Í÷Ø1u?¤ö(¸�òÚw�É:ÄÝð“O«{Òÿ—¬pUÝwöÛ÷œ�f¾¹�qÔ ™n¯,`YÐm¥žÎò(ÛøUýˆé®®¼žðDеÿ½Kf²rçù·ÖÐãŽLåµ§±8gÅž¤‹ˆGâI—¬±m}h;cl[ÚŽÛŽ“•×D¦\‹ +ñÈÊ„àÝÏ;!�NÍ «¶ýrгÊ&ïë}v±a&Íôß7…[Õöïnwyâó ßľ¾«j HŠÞrÉRA™]ôÁ²*ÓG�ºÝµSå½ ÷ý0øƒÆ·«©l=v.�kóö·ö,¸32Áˆy<“+¸k¬ñ_®îb²±G7üÇä]¯úÿjâ›,(§Rܤ"½Mâ¨2Ý^3X€:¹í½ oÕîÂÔU?bº«ûªw2�DÞlú¢Ç‚¬$z7�ëØš#Z¿Èž¤ ÿ¨ I—¤±m}h;dl[ÚŽÛŽ“•¹2[V"ÈJ²Ò=x÷óLàĬà?A'-ù•ƒ3Ú&èD�Ï~¼5¡WPš±B«¤)ë7VZ£Î û�-¼e½— ƒë-·@n\>ñþñv`‡ ßà-ªJ¤ÛÝ8/ô¬º�Gzú.]«Y3¾;å Ú ç3'1ϲêîª?nEXh²±G7üÇnöß éÛƒ4÷M¥¨˜N¨=¼Æ Žº!Óë5£t º±È#çM2~U·º««¦Oøv¢Ï®9$SVÊÔ´Gû¼EY±'éÂã‘xÒ%ilÇ0´�1¶­mç�mÇÉJÑ"a:"ÈJ²Ò8h÷#ïó+�æw™#‹ŸTšYÞ?ž .CùÙÏ�' £‘º�oµÙt/jSÒžõÞlX]5c§áråÆÅýUÐêv6kð ­Zæ'ÁË_Ñ6¤•žh=è· —kmrÖÊô±#b[vWœ8N½ËlbŽnø�m©ºÁÿà;…©äJTÛeGÝ�éõšÑ…M2­¸ÆøU½F诮çŽ@µÏ�Õ‚vÉ’•ÒUºæù?oQVlIºˆx$žtÉÛ± mgŒm«CÛùcÛq²R\_äL%äY‰CVî Úý´9!rÊßã}4†w«š_)è¸Jç³� ŸZ!Oiv·°Ùì" x7hRŸoMVìIºˆx$žtIÛ1 mGŒmËCÛùcÛy²rè4‘9ŸbÈJ̲2%0é|ó#AÓ·w…ÕNXèß’í�WgÝó�?;Örá8ì|ÇÄÈ×GÝ/ºÄ<ž^÷Ý7W»ñVÿ‡*ÂðÅM�ÂàºËUé®6Œԃƪ7ø+íùU·‡¬S{݃¼oƒ.åçÊ3¿Õ¶Ú±°;2¦˜­CÌÑ�ø1¹åõ=XZþÄ­}‡¡·[Î5‰£~ÈôzÍ`Ó“TG䘼ªßÝÕõÔ•ÿ|vÒäU‡B»$²r^“Ù‘Å­¬ÉŠ=I�Ä“.Ùc;úÐvÂØ¶>´�?¶�'+ÅÏŠä¹;@Vb–•Þþ1¿C^¯®±!ôHF+@T°|ŽïÀ Ær‘tO¨T¹ÛcüÙ\©Çø¯Zÿ¢Ÿ{_�˜¿öŽZäüÐÓ ¹Áï¾ìßbµôxÖ´Ö.xO6^®š–öÈFÏÎÑêifîGMÜÕ}¯z \Oµ­ÉÛôgÿ=M|%°óföá;¬î¢öä}¯&ÖÍ–ˆ…Y–¯aºëkt#L�lo¥®ƒw |§YàŠ„ºqá�quC¦Ûk èë?ó�_G>H{‹É«ú�Ð]]O�À´MyCKŤÈÊ©µÆé>ŽÍ𬨒t‘ñH8é’>¶£m'ŒmëCÛùcÛ�²2ZäOÙôY‰UVäõÐ O0t\/ù@�ê ï,QÇK­{vnU«š»¦ï‚¶ûæçïß�õ+ôêY{„Ñg«Œz²ÃÀÁŸ¿ßôÁòþgß©;oj?êËÞo>Q!P+_«œYaGÈfíÿ_Oû.C«‚®äv«gk4éUo¸Ár·ª�ÞöÂmb�e±Í›º½ÿߥ Îë¹} úø³_êñZUï„‚]jtû;}‡ÞùÕGnòV “n›·z»m=íéö wÙ1?Cå[uýmBoÃuˆ1º‘?¶¾º*¨1jþ×*Œ�îðŸeît+ÈGÝjÍ7Š£nÈt{Í`²BûMµ{~7sˆ¼/âo•ýWõ¡»ºž­·{7畆©øo¶]V¼·)Ç/+¶$�ÎJ4é’>¶- mŒmëCÛùcÛ�²²ïx‘CCÐd%VYy0¸bå­AYžuÁï”ßæ»¯QRyüHï¿Þ5ú쯷„>ÞW i{Èëþ§’TU‡(¡§A_¹Mr´ÿ¢·¢­÷Áµî·�–[Ç÷W�ù£¼ÿmÜà ·½^E;û¶|h#^ð�± â�í6E,t²�úR�Ñ:Ä]�ëüÒ#Úãæò�'Ìúî+hGÝ�é÷šþ ^ƒ¾[Ðõ_Õm„Áêz&UÓö4K´ÎþÕ^Y ܦ¿¬Ø’t:�šhÒ%}l[ÚÎÛV‡¶ãǶe¥ø!‘F� ÈJŒ²²5x{Ñ$ôrà1!·µS«½¦ðøbßV瑌>ë™T¸»B½qù!³ýµW[6Óšy]»o|wAà)µµïVì­�‡(£Œ–;Õûwý\ßê>6ߤÁüïTnï{ýó �Wl1Ç}ÊÏ‹Sì‹XÈ0uf}‹Á:Ä]�ÛùV`¯¬ÜMé^4gR¬øLƒ8ê‡L¿×t�Ô,÷«ë}t_Õo„Áêz<+:¾ôâ;ê®ÚçÄk3l”•ÒÕ{ï4M:K²bSÒ錠“.écÛÊÐvÆØ¶8´?¶�(+ƒD&¿?@Vb“•M?ïÝæT~urØ{‹VoÜÿÖ8߉âÙòÔc�ÞâÏòľÞeüYÏÊ&Ú’+ÿ¯ÛÊà; s¼9ýQð«êºlPi,5¥DðÙco�ÌÜÔ1˜œo&ŸÕqoÏ­ÆË$·�È |é8OŽÜeÚàꀷb­!A'W~QÛhUmðÙZí•ÇFõ»-³5b>¨½Í&ï2Z‡X£«ûc“µ«ìîçÇ߈á-¸çY-o³|껣8ê‡Ì ×ô0ÏÇÊÍ~ð¯”þ«ú�0ZÝ ÜYŸ¬ÜøQÔ;.-ÉŠMI§×©‰%]òǶ•¡íŒ±mqh;}l;QV?†¯ +�­cÛ¡²ÒZÈʲ‚¬ +N••…ò:ÐrYAV�‡ÊJq9!+íQdY@Vœ*+M„¬¸Qd% +]ÉV+²ò§-I7Y'1O È7¸oœ.¯åâÈŠb𦒭QX/eå€-I÷µXRo" Na†�m¸o<|¦�•n8²¢�NÝ–lˆÂï"SêÙS¢j"§3ÁIL²“wŽ/ Y¹G@VKä @² ‹D¦4³'éä�l" NaŒ�=�¸süVÈJ™H²"Y-†é«d+@æˆLimOÒ-‹Ê!¢àäŒïþNÜ98IØJ?$Y‘l‘'·w�®ÑO•¿oOÒý&Õ”ˆ‚Sè-äŽÜ;>.d¥&’€¬H ë‰qú+é `N?ûŽ>wʹº)8„1g:rï8\ÈÊ1{°dE"Çé÷¤+€9ïÉD±'犚ŠeÍ'¤à v6ãq­#÷Ž{޶2K@V$}Å8H¾˜RÐX$Š]¥¿;‰e�!¦à ä�nu÷;s÷x��•§°dE"«Â½O¾˜²Æ¾špZ ۞ĜÁ‡Ö„“ô²rÒ4YñNö«·•„0c¼È“×ìJºå Û]AOY¤Ð¡»Çíe„­L@�Á¡Fb¤Î aÌøH¤É »’ÎSW,m1A'°KN¡úÑ©ûǪBVj£ ÈŠ¤µ¿¢�'ç .²-éÚ‰¥ 'ªà~‘SV²óÚ!Ý �[ÿCNÞC¶²ò/DY‘l“n=Š´Ðeç›"A:Ø›t+¤ÿL"¶�^rå=ù£½‡œ#¯­Â�‰|Bx£M$.€¥X,µ9é:ˆe¶È'¸�V來ŽÞC9WÈJ'LY‘l—÷: #qtØñš|~V‘ÍI·ZÐ8¢ édµÜôåð]d]!+7c ÈŠb ,yµ–Ôˆd´Ô ûOCw‘“6^H#òV &{¾‹œ$d¥ôVTY‘ì”.;�»Ÿ29ºÙŸtÈ©b½ˆ/¤5sü[§ï"�&l¥7ª€¬(FÊAû=É FÁûò¹ä“�tŸÉ¤›O„!]ln&Fàëû¿�|ZÈÊݨ²¢8ØZžÜ@ú„2A*Åèd$Ý_jWAÍHŸÊ±½ØùûÈQBVÊà ÈŠb¹¶�¹ÂêÆ"1ÞJN Y;ºN_b éa–}2`¹ïxa+CqdECÖªó Dþ;òa+’”t]eÒM&Ê�Ö4‘S¼wgÂNò!+�â ÈŠÆÞòÒüR @/©C’•tùò´Mƒå„RO^9¶çfÄNr€�•ã÷! ÈŠÆZù´’¦¹$1€ù¼Á:m&-éË;‚Zn!Ð�rd)Ð:ý2c'¹ó(a+c‘dÅË÷rðæl%‹4~R¿#‰I'ŸËUçC ÙBªùJ޼v‡2d/y›�•�dÅK‘¬¼\§}y ùµ‘œ°²(™Iw¤“Lº®<ÑR‹z„DR=ÜVº Y9½[@V¼ì[à.l8+›Ê|ø&¹IçyMÝÄ}x�JfÊ2ûu—fÌ^rs)a+Ó°dÅeðu¹áì…­xÖÊ)çuú%9é6)%âÉ\�B~’U™ëÌÈ Ýdy!+�±dÅÏÖWÕIi.¡çU”«ô8’ô¤['o ªó‡�*f+WŸI»É÷„¬œ_„. +~Ö« gªjB gQ• R�tKå4Þ:ÝvtH ä=hu†gÔnr•�×tY °¼¡ºYs# %™9êØó½Ô”v˜/'ÔéÄ!¤€õ ¸:2ì4Åÿ Yi…. +Aäª+A-–�ÔPr·çcÔ±çG©zÄÛRuˆÐz%‘‡d³½‡r•™vI¥•�•+Ñd%˜-j–m½1¤5”P¶|¤¶ç=SW„bõ+òÍ ö�\V¿U'iOæL* äu ø²L~kmSÍYi(‘üÚR%Àà#)Lº�j:o�AL\�d2­‘:�™yûÉ¢ …¬¼�/ +!ìí¦6œÍg“ÛPâÈ©æ»Ö›”ÚóäTÒ½¹�€d±é5È^ý-w”�„¬TÀ�•0‰�¤.Ù×鱉ü†’Åbí¼bó”Ÿp.üBýpÝ~œÑ„¤P0U•ô©Ó>?#w”S…¬”Úˆ0 +á3þ´aýêJ®@ b}MÓ;íNCÒÍUÓlë¼>•r¶`?Kµswu†fhÕúÃg[éŽ0 +áìÔ.Õyc*Ū „°q�ºa¹Nà GÒ’t[¼»“6?¢+`/+»iÞâ—ŒÝS¾ då6„Y‰dÞ«Ú–ó­©Lúƒ@îðFÚˆï´=]9wdJcmÚÍæìcY/MUêÜ›¹{ʱBVÊäc ÈJ${újÎ:M‡­!Ý!«)˜×¥ž6Ú›LOg ßÍ:-FþA¯€ì˜ÜÎ;¨Þü=“÷”ûO¶2c@VôXû‘w�×í0n5IYJþÏCZzGzÑ{ÒœtËÚ{W¥ÞGréHŒí³>{Å; šO)Ìì]å£BVÀ�}~{¯Ž�7ÏXɹiÈ2¶-šðIc߯7¸ ý9W´°�?éÞ>s5Iñ±qþ˜ëû†Ò+ãdú®r¨�•c÷  ÈŠÁ–s‰wb–¢Á;Ÿô6zÂ$€ŒgÜÈA}>nÜuš~‘猤;òÓ‡A«Õ°]Ï~ÿžH‡�e¾1 ×‡¯ ¢Vöfþ®òÏ£…­|…2 +†ìݼ@–óÞ,'yný*]öP·ËÂ#Y±¯¼KÈÊ3(²bBáÒ¡-IyÈÞ­y‡ñ›�–tà ¦a÷éÙ²¯ì%d唃8²bÎÆñ=Z‘ù©áåçŸþÂ�´0ס×Á‹rÇv{�’Ü~ës!fšt¾$›öíÛK [™„3 +Ñù{ÍŒoGìÕ’K=yA’L·Ï†Œž¸`‹ÓO�ï]9mÜ—>-á�uŽ«Ô%�³Vùäóác&/ɾš$7‹-c]œY§0Y¤äù„ÀË:‘®ùÄ¡¤ÓI ƒ³�d�ÒUdÄYì¤J<¹RZçd�RCdÄ‹„®¡a@VYp»e��¯‰¼-B9€¬²à…r2S‬²�v(_ <'†Æ„Yd íP¾ #†ÆQùÄYd ÍP¾Œøû16d�€4CùZ0äa18" È +i†òµ`È`18ŽÛK�@VÒ åkÁ�¼F8š8 +€¬¤Êׂ wŠÑñ,a@VYH+”¯>ÃãÔƒÄYd �P¾LØVZŒ�ÉÄYd �P¾L©$ÆG}€¬²�F(_ ¦tä²È @¡|-˜²Fžz›G�@VÒåk! ׈ò:a@VYH”¯…(´Cär€¬²�6(_ QX$¯-#È +i‚òµ•rbŒ´% È +i‚òµ•¦bŒÜ@�@VÒåk!*3¥Ñæd�€ô@ùZˆÊ‘sÄ(éB�@VÒåkÁ/‰QR�0 +€¬¤Êׂ¾äô6‬²�(_ 8p²'}‰²È @ |-Xâ 1Nî# È +i€òµ`‰/ä@ÙM�@VRåkÁ+FÊÄYd åP¾,rŸ)Od�€”CùZ°H_1RNÜO�@VR åkÁ"ùeÄXO�@VR åkÁ*·ˆ±ò2a@VYH1”¯Ë|,ÆÊ…ÄYd µP¾,óG)1Zfd�€ÔBùZ°Î b´4% È +)…òµmÅh¹¸ˆ8 +€¬¤Ê×B ,“3œd�€TBùZˆ…+ÅxiC�@VRåk!&^ãåZ€¬²�B(_ 11W˜UÄYd uP¾b¢è1b:d�€ÔAùZˆ�úbÄT" È +)ƒòµÇö²Ô&‬²�*(_ 1rè41f>%È +©‚òµ+ÏŠ1s'a@VYH”¯…˜-ÆLÙ‬²�(_ 1³ïx1j†d�€Ô@ùZˆ�Ũy„0 +€¬¤Ê×B £æø½ÄYd P¾âÀSV ›1ÄYd P¾âá1nž# È +©€òµ=ĸ9õq@VYH>”¯…¸Ø\J œ)ÄYd ùP¾⣢9 ²È @ò¡|-ÄÇr›YD�@V’ åk!NVË ˆ?d�€dCùZˆ95û €¬²�l(_ ñÒZŒ�+²È @’¡|-ÄÍByh9q@VYH.”¯…ø)'O{€¬²�\(_ ñÓDŒ7a@VYH.”¯…ø™.ÏËåd�€dBùZH€ÃgŠáÓ�8 +€¬$Ê×B"üOŒŸ[ ²È @2¡|-$Â81~Êì È +Ƀòµ�N¨q@VYH”¯…Äx\Œ š„Yd yP¾c8º‹¬²`'k”òåk!Aö#†ÐÈ�— §6jH`�@Vâã—«´;ga‘ÿÊ×B¢Ü#†ÐS�?÷�«s¶ËõqAVYˆ��.E¹&“j/P¾¥�C'Ðþíúè jˆ=G\�°�Ï¡šH±ãB_z|-Q‚,b¿ËÇñ5ûl-¦|-$Îö2bMÿÈTóhßøªK\�°�ñ®hœ{˜(A6qTÐè.SåƒI”¯…„©*Q�5Þ\:hp5&,È ØÆ¡3¢ÉÊ+ ²ŠS"ù™”¯…„è,FÑQa£ê5‚¬€}Ô�&+?#È*΋äGi„ââÈÂWt6�odìcVW¹¬ˆAVq¥î@—wˆ�ÂÙMÎÕRïdì£èsYiCˆ »¸Áp°_RgÜâ1°o\­SŒ†ÓG„YyÝ\V~#B�]Üb6Þ�ç‚Xeç ÇO0K=ˆ²6²ØÔU®'@�eÜåÊçñ#ˆÎ„êeÌR_b„¬€�\c–o‰d�E‘•n„,°áô(i1BVÀNÚš¤[©õIJŒÌw15™R–ø¶”ùHIˆ�°“µ&)w á�l£‘éæ¼D¬ñš¹¬Œ#BÈ ØJEãtû”è@¶ÑÒlSú)¬b*+“‰²¶ÒÅ0ÛŽÊ#:�m˜]÷t½I|À2›L €Ï$@È ØÊVÃIí÷È::›ì_*">`�ñ¥(þ�¬@ê¸�éìPrèc¼{9q5á�X0›¶²”ð +`/} ’íØÝIJŽaÆ»—¡DbÂlÚÊJƒ¬€½xŽÑO¶' dßî]þGp FL¦­P\Y»yP?Ù¾!2�}L1Ú¹\¾‡à@¬O[ÙNp�°™/tsíTêYÈ<ƒ}KY&DBN[ñdlfÿÉz¹ö��,d™Á¾åcBq`8me?±AVÀnžÕ˵)IJ�õú»–{(³qa4må¡AVÀnÆë¤Ú¹‡‰ d!;t÷,gm#2çæSwÚÊ1YÛ)<+2ךÈFþÖ-³OmtˆÝi+'dì§>õ¡„P¤W±¹%q�øöô¦­œE\�°ŸY©v—ð!;Ñ™N^þ a�øÑ›¶raAV G›—„§Z‚Ùɹ‘eöWH�i+Wd’Àëá©ö1�ìä ‚v9må:‚‚¬@X–i×ÈR®ß­@<`V€5<ƒu'@"0Sõ‰2áâP[IE8`V€5¬ •Ùï0—¸—Eá”ÿ‹eö�@ÔÃVF!0+Àü¿UÊì ¸—¬ÐçÉ¿»†h‘¨†­LB4`V€E¼¢”ÙNĸ—�¡Ï“õËÞа•Ì °ˆ-Á*û‡Ÿ à^ Ѓ,#4le>b³,âþ¿—«ìC„¸˜’à§É¿`hNhØÊRÄfXÅ»r•}‰Hs<¸˜Ðq„ˆG¶² ¡€YVQÄŠìŸ!ÀÅ\B7=°ò1*[ù‘€YVñ˦"‰@7S-ï3‡eö�5È«æ!0+À2R¨È° -p5�¤òÿT‡@‹¾ôõÜJ˜`-G¤û_íˆp3÷i™ý"ÄXEÍ?IƒÂ`V€u´ÿÏ=Òàn•ÿË‹KÙ÷«=" 0+]â«­¼Xvtƒ·zôÈAºÃéòê»÷P?6T—ŸIð\ý¾Ç¿|éÆû:y©ªîÛø—à/M·®žýÚÝ{»G�OñPT(»XYëƒY‰¤­úÈÆi^Ð]õø'¡ûLZYpÚ¿&þtÁÊIH’×û÷¿yý77jÑ–cµñú*÷Ç‹ûVOON‰ýíŸ{ B¡E�¶`ã‘›m0+Œû§³GC&ùÇÇ“Ì*ø&þ&š´Ý(˜�ÔùýÝ~‡ãs/Äß2Ôw¿Xœ’0{çw¯£Ð:3:ûôý„7+mç—%C æéùb  $·Þ�«êhØ ¯y"ÜäЬ«ñÔ¿r¯xjb‰ì…7Qhš$/¿Ð–ÈfåÛ½"Â1râ¬�‚n��t‹¹ÓÆ WK0iñéxY[ïÑÙ%Iê¦ 7mnb'˥φ3'ŽˆÈtzÉq¢Áªµ©FjÌT~äâ¼Ã×Z‘(7sóÄÎÌÉaW°ýû8Ð`ùÜPƒRçç|q© iJ\;ˆ[n/“?)ì~ti$»îbô9‚¦|ÖÁ‘´ÃÞ©i r¿âä3ÈФu�ÜÝ�ýÐåfåžüÍ1£ 9ñÌWl¶ZÒ[«c/ëû~áWäùëËì\�ÿ"ëTLÚŒï’@—JybÐÜ{®6+-rù­C)€8§JžBºÉ¾ù£íùìŠS®#ø€Ñ,¿‘™sÏ6 –±u:GžDìA´Î•<¹û­ÉÅf¥ž­Ê9ì0² ➦5¬ W=´©8Ú䡵Ÿ6"ô@¡˜½ šÖj“¿b]{3±¸肯YÏó¸Zך•j¶¦ù$|sŽ`øþ‰=½ð—³)rE;Pq‘­S8ÁžWv1»¼ýÞ K®³FU»Ô¬Üa£Óo#ÑÀ”²ïµKìXìâÑ 6î�Ž ’lÇ ñ-6hpó*9>tM-‰=¢Æ•f¥iZ[‡4§p– 7\eý|ŒvöhXB:~(°ÁSS¿³\ƒ‡ÙÐÚD¢~Û8ªÁ…få[ö a1º�ƒ¸ÌÞ\æY^lBÿÈK8èD›{1ç�Å„½£™mÝr+ÙE! t)§þ½áÖíU•K\�y@€×FÓß”*™•ïh"P¦:Gò)›ÑiYul¤Óg"Ì _²Åá¬Zòç)‰� 7'i\ö¸{î1+ŸQ-lGb�#id›D\´¨8*’ðAºdi0ߢ™šôõxØ5ð³�-$è³r‘ng!6½¥ŠÖ–žhÍÜÑŸé­ï0¬ê ¢Ó<›z§¿±Dƒ«è�í3Awð± Ìç]bV~OëòÖ"­À©”P=n¶¤:Øî…Å1èÊ1Ó°•™V¬¦|–$ø" ºE-­E5þGw˜öNþ+$8÷ÛÃB«¾ÖVÓÐóÙº¤À¢î�¥…H±²8è&_‘07ºÂ¬Ü¡wò‹‘Rà`ª‡Ñ"¢íâ«c>íT…ƒ.i¥E-†ú¬éÛ;Šø‚îò }•«qƒYYI“în!£ÀÉÒ]üÒpè´»^`¶ÈìFÑô•κÑÝæ6�éËt�Yù†ÇH(pö×Ú©´³è ÛiŠ)z A»]¦4Z°ÄJ*–À&ØIò7œoVh¬ðèFä8›£T�ÇG�K×cÔÒËÈub%ØHÝ59ˆ-0A#­Á½Ðñfå=Ž‹�Nàp|4b`²Ø®•vê®™�ѵÀ ›ip€Øul³iæ<¦jS°U¾¯9ݬÐþ ÍÈ&p:¬ä’Ðâ¸Âv|Ah�Aêiõ¶-"%ø=�XÙŒÈS4O”d”åp³â§™™û�Là|hU®B«#“:VX`˜-´ÇšÈE÷‹iÄ ¦-“ì£áTß:Û¬ì¡NF,%\­ —Ô"°8|ää¿@`�an‘d¾ü"r5â LÒ0œ†{8Ú¬´M�n!©. ™úàw ¬Ž]ÒùÒ0öp°TÒÌ\Á/"/!¬À,4öiB›“ÍÊUª…«È$ph‡ �Õ1Y:ßz„pÀFNÝ&Áux „PN¬p²YÙ*ÝÀl$¸6³­VXqÔÁÉ^|ã$ÑÖóMÛºìGT�yfkí î$³BoDw"�ÀPWÈ>¡cÇ#¨€ ên_$J‚U4 «‹l—´”î`³Ò€ïŽÀEäЦƒÂªc!ÞnNHªI¾/H‚;ñ‚½jt®Y¡ùã°æp 'éƒâAÅqŸ&v”!¨€‹æTI6§i�:Ü‚˜øhóî/�kV>£Õ¡‘Fà– Zîü²ÀÁçC±\"àd‰¤›­b$øS’t® ) Ö^í\³’.5¿Ynaž$èbAÅñ…t®9)à„Æ,#AÚd6~ဤ¦iŽ5+©£û2²ÜÂç7’ËF·#襴3¬ ¡�Dá2½$èT³r“Zã\Mà™)p¼6¢¼TÓ@Æo…H0O:Ó*D¡™ú&n9Õ¬|-5~ ’\ÃEê7$f‰ (y!œøÒ$á” ›�V€ˆ1L‘äTêT³B›-E�k`ë¸}'¤8î±æRÀ uÉ�6¦ð Ä@[AìwªYÙ!5þ3丆Ö$a‹�7’YÁ;RÀ õ‡¢Á1ҙΠ @ Y´¬SÍJ®Ôø È!p´·è !Åq‹f.# €›’röÑ ½‰,G@�hÍÌ�N5+«i·ä¸ڙ劰eVÆ  €›5Z›°tk¶&uîÝ@@�h'À5N5+Ë¥ÆïF�{H¶|è9Œ>Ý‚:¬s„ ›ºƒ€1ì–ä´Ü©fåê¯D�{˜!Iú¤�â8Cû~! €šp¼^„ýdVêP †=’œ>�Yf˜³³Ì €Yf˜˜³`V`V€Y0+0+ffÀ¬À¬˜`V€YfÀ¬À¬ ƬÌ_X³`VÌ ÌJ$¾òÝK[�5IåÔ1)ï}+ ÔW”8�âŒÞ0K2ë¤E1+Czüú‰OãŬØW(›ƒã³’(Œ Ö\>^|NHsMäfE�âA‰!UFŽše3�tb¬„øºtñYñø$ŽÚ0k2ë¤E5+70ç^<˜«ÅaspbVF‚q ÁÆ^R¶Æú± ³¢M]ŠG&¥ë£æ™Bç,Œ‘›zK߇âh ³*±NZWfEâïßÜýsŒÍŠ­Õ�â°98Ž0+‰#ÁxÐàq À9óÍ5—˜Mªßð(\êê(»—Íþ\ãð+ÒûÆêånÝ�­¹ëD�£aæ3aK’fÀ¬HüÃàÂ_bhV,ªG|ˆÐ fÅÞtL%Ü µ O‹éæšÌÌŠ5/S<cQ-êâ(—ìzy<Ë5rHgLŽ•7R%6›8AýGï¼úü°à?¾$1©;Qàh˜ÁLð6ŒïqiIÒŒ™‰ÿ:êT¬ÌŠEÕ�âˆ:À¬Øû€Ž­ÍkÐ+©N‘`I°Œ÷ Ó¤&¼mº¹fó³¢��:«þ\ڼɣîÐÒ>ÊCë[Ò_~Ùùx¡§ç·Äª¦K�zËÌ ŽQ@Þþc¨§«¬zQ0Þ0£™àlÖ$ͰY‘ø*baV,ªG¼ˆ0þÍŠÍèØJдïô”N0Vu2O ï)(.ÓÍ6×t~`V4È”‚ù:ÙóÒ¢å![úÞ[¦75øbØÅ÷®ÔªifNð9‰ïyùç =»T¢^Œ7Ìh&8Ƈ5Iã1+ÿ:ý†ífÅ¢ê@qÄ‹ã߬Øü€Ž­Mkð©n•êd/𞡹¯ôW¹f›k:?0+�¹ÔÛãyª’~zGŠjEÔ£<|ó¤ô‡ƒ¬tÅÕîþe �5™LÅÐWþyëã;-" º 3œ ¾†Åœf¥‡þtf«ÌŠEÕaeqt¿:ì.ޏ îÍ Ð\¬õ„û‹Zédi¼Í=Cg(3Ù\óùI(³â«>ñõíŽ=W¬Ž<4BŠe¶’ÙW£%/—ªôu}±Ñ”ò©†»$;7LáféÙˆw‚­kŸñx^¾iôÌ å7šÂÿ:O­:A .?pÍHÄ:!�šj¤«Ø É>MQ~;J 6Ìp&¢7,òjaêNÕ<è7–‰Û§ÎHé¹¹ëáfEw:3¯Y1XbªÃÆâ0UV—yDhFƒ13+¶JЬí’ y N¤Ü vîÑÏËýÑ%Ø©¹[¤?êÍ~«º³®L?¶µÓ“Øf¥túŠã@õtñËsÒ±gǨd÷µtàåVÅP.�zTŠü¾ìôlvSÔ‹­˜<–=¶ÞžÌXNõWËS>øàƒ¾U£a³‡¾÷Æ¿¿9ïMé<©šH×êegþØHw$=K¿ÜÿÃ…_ÉG¶ÉBlÙøªôûÕ]ELã”òˆ)6s~ž'ôŠþÚ°!ƒžûBþ�¥,�ކ΄Nô¯–=üƒ¿Î—*lßàžž^£¢ÔIšnzü¥éýéZZøŠÇ3²U¼Y‘øÝó6eVŒ‡�ê°³8ÌU‡UÅÁ¡AŠÑ`ŒÌŠ­4®ÁXKм_“~åÿùÃ'óì׿˜vsgKÿü‹ßß²ù펷fú±­“žÄ6+×ÓB³¦æ„z¬2û*Çž.ýf²âiz}Ÿê¨Gýçß�Öë‹r±Æ>ž†Ê|ï¼wä§Y¯ˆ7¥Z k¦éëþS¯ËÇ« ýöùH–�(l~:Ü„qò¡¹LˆçÞ”¾Ò5bZœ”‡&«Õôc?N!_ýýtƒý›ÌV¡Ά΄vÃt®F—Yæ¿þ¡|p°Oÿ vÒtÓS=2â–«-1+Ó™yÌŠñâPö‡¹ê°¨8x4È!BAŒ‰Y±U‚F54­ÁFj˜2hnÈ:k_L»¹C¤N …Ruk¦ÛÚéIp³RüD8ª½‚ÉjLQ«SY ¸ª—Çó«°ËÒOQ�úsÕ_åbG"KÁó ]ÿÕð¿ß‰�—VÃ.±÷†›z+‡ÃZ((í2µç]-|Ÿ„¸3T|[¢EL“Mòï�±Î”\O‘ñ„GrÑÏOëE�·aÆ3¡Ý0í«ùèn ö?©ݧwP/izé9> ⎟ñ[eVh:sÚ±öî˜ãÅ! :l.sÕaQqph�G„‚4 ³b« j0>$hZƒ'<Ìí†O60ÊÅ4›ÛJ6;{Wߎ·fþ±­�ž7+ùLCƒ§Oøýw‰ü` Ÿûxý,�ìy=Ø9ú©ôóöÓXéÿÖù£eC—ŽY?÷%vú(Ë4h%°ÿ ™:¨²¥‹Ôï!5¶—~fƘÍ)ðÌT~ýª|†®×¨§qÚ½?š’ülè*]Œž‚–NùäŸä^Ð(7¡ÍL2ÐÏn¿¿i gýÙ×~ÿ5ö5r´ü4™íoºQàl˜ñLh6Lçj•ôãtZTZ.³�tê$M'=eOQïçÒõ/É2ÚJ³1�Ù¸Yá(óÕasq˜«‹ŠƒGƒ<"¤Á˜[%hXƒñ AóÌ _¿ï©PC4/¦Ý\æÃÆöêxkæÛÚéIp³r˜ýç 4Êì�¡>± 4ꦪf}Qyòᄁ산Sú!tvÍ£ìà¶°ßé§Ç[õ/F�ª2ÕÍZ¾xÝ΃g+ésý ê°vÃVÉzu[mÅЈWŠu½Xít¹ÛB+yÞ—©]¾ÍáÉöåòiߨïó ›û¸?úMtf°ôÿ3Øp©,¨ ±§ô|úHí•iô÷Ý(ð5Œ#š Ó¹ZI°×ró�f6ÙôY݃:IÓNOÃsÒ�ãiHZënöÿw[lVÂÓ™ ›žâ0]v‡¹ê°¨8x4È#BA´ß¬Ø*A㌠š× [Y¥ReDé_L»¹A æ×¨oÍüc[;= nVª©ckpMÈá}Èúò^$û(�ê9MQ›,¿TÆWœ{\õ*Póè•~áU¨±ŸþÅØˆS:ǡέ£‘G}U£‹t6A~1Ø <¿>�@åÙØe²¨‰CŽö%ùè.vÚéìÕ"›Zy;êMh”Øã¤>ªòÖW’Å«ý“Çó~‹Ú[v:JÎ2]Õ×öŽþÅKÙK£t—)/ITšÕhÍ�ì½Ö¯ §¯W¼‹½»|±®‹ \éþ£‰¡>9ÿ"º³|ÕW†sQo¢3i¬ùY�gUÂúŒàb‰Çé}ïcòΩ÷‚讆qdB»a:WK§ÓnTuN–ëÔNšvznH©é_+ÿÂT::ÃoÀ¬ü¾‡yþnàÌ÷�™žâ0]¶‡¹ê°¨8x4È#BA´Ý¬Ø*An ÆV‚¦5Ⱦ*ö ¾Ü¨HçbÚÍ%�ÜkC‡[3ÿØÖNO‚›•+½UßìoäoßI«çݦ·w¡ùiS•! ~z ¼*Ùg)A¯…»Æ´Ž’Žý!øh}W1‰šcÌVÏ[ìÐS¬ê|Ôi[ÍgaX�ž‹Á+|«:ÑÀA©¹¿H?¯ ÒéÛ[Yʺ7ÑRdj�Ûólã`e±ÄáE—·’knÕ�OÃx2¡Ý0�«½£š§±K™1¡yP3i:顚yÁ_¨JšõfEâ7ÿû½tÁÅa¶:ì.³ÕaQqðh�C„¢4h·Y±U‚üŒ­Mkð\‡‘Þ§|úÓnî€ðÝð­™~lk§'ÑÍÊ,Õq^TáJµ{ö´(φ½äú^QÍðÓ:úQxã*2‰4ë^,Ô§±¿Âzcr¼Ë†]RíRNÞ~€|� ºr2{é²)jn÷e3ëlïâðÐoE©Etšº¨7Ñ™ùô´ÑãzX:ëöfã#ß ï‚BB¢®†ñdB³a:Wcÿ{]ðtÔ[ß³Eç vÒ´ÓS!ýV¯àR�eá!“¶˜•ß>ùôûFzV¸ŠÃluØ\¦«ÃšâàÑ �EiÐn³b«¹5c šÖàÖŽfåý(Ól.{…s4<,ŠÝšùǶvzݬ¼š0¨b¼tðÍпh½¦þ¡`gÔHº}U5Q^ëè-Êèzœ™CÃÆÿ­Vÿblœe4_#´ÎNk— +ð„×(Q•ÛÏã¸GÜÕ7êzÈëHe�ª‡–¼JýøEðwÖ(/uoBƒ¿1�ß×38ÙÓ¯†-_HK¶Ð3v›ü4K¶n¸Æ“ ͆é\í²zräb²üzµ“¦�êÛü«ªŸS5ä>šYyr &ÿ…ã%Ð3k}Ǭp‡Ùê°·8LW‡EÅÁ£AŠÒ ÝfÅV rk0¶4¯Á9t‚!ï3Þb3–ô/¦Ýܽʸp‰QÊ­™~lë¤'ÁÍÊyÍ¥!Ô£BÿJS†¾ùi  E¯y<ƒ#1Ö8JC™_,Ù0oø3lÔÚÊÖ( õ‰]î||z‡±Ü: £w�T•IsÝë“è%ø­`©× êÌ0¶®Oø¡œl¿O¥TÿŒàŒµóÆj2$´ þç=OPoóe×¶3á»e³ô·èF�§a<™Ðn˜ÎÕXï¦R-cƒÓ;5j'M3=¬²•ÝNië~CfÅäl ÿ:¿Îðl ¾â0Y¶‡€ê°¨8x4È#BQ´Ù¬Ø*A~ ÆV‚æ5ø^ØçÉÓ«·é^L§¹KiÖ�ü£ïYåÖL?¶užÚ nVvªãâñˆÙe4:j ýPÇ–èóx†GèJëè,UÏÚ Ìš¨ u iÿ“ª›7JÃè]`RxÔÛ}¡u�ç-yÂMÓ;ê•4ðÑcsEðÓÂ"ZÖ™ÜW·*êMt¦‚|5¨Ÿ®ö‡ðÊDh”3¢û6+~´ŠÄÓ盨�MÏöà?Þ ?À†«–ÿ¡yx=/E½ íŽú7üþäa€ï*ËÒN Ÿ— oÑ‹WÃx2¡Ù0½« ë0,¬w•ÞAͤé¤çÙðj�-OEN´Æ¬ü·´cœ+Ør‡Ùê°·8ÌW‡5ÅÁ¥AŠÒ ÍfÅV rk0Æ4­AöUqžêû¶ê_L»¹Ï…—ä(·fþ±­�žD7+‹µ¶Ãhî¥^¨Œfª÷© åöéZïp”¾¦ =sËÈÅB}ƒË;ÎU[Qý†U«ÆoQgððŽçÙîÑ~ëïW½V . Ì6WÛ~_¬|ñ ŒÅ6Q > ~ÿH¦K6Mno‡/t³Ô3ë:E�«a<™ÐlX´«)ÃÂF+_$4j&M'=}C«=6 ótØ V¼YùÇÁ%mÜ{q‡ÙêˆYqt³:¬). rˆP˜m6+¶J�[ƒ1– i xƒýÏ'ë]L³¹ìÖ‚¡£ÜšùǶvzг¢óâeÕ7––ç÷)ïø5¥ÃïjM“w¢4t1OäÑžœ52b??݆ ?¿®ªuÏÓ: ¼n’_„Åå[A?_ ·*Xc×ú(+5êÞ„©Ò¯~ÆÞì¦GªP+}�) úwöR ²ï®†ñdB³a:W«ñ„‡³—÷Žþ×<¨“4íôPò@Z‘á�ví|j…Yùýë…?wg×ežâ0]1+ŽîU‡EÅÁ£A Ó` zVl“ ·c+Aó\èaæ7=ÁG±ÎÅ´›{@™4¡¾5ó�míô$ºYÙ­¹=7=G”½iníÓôÖl»¼D¿†H“©y4CÓÝîÖÛ ¼,boî0ÏÇgGo³ðϨ\êñN'¢¾Œ´Ð¿¶½DìŽ|’±Éh·ÙîSýä¹/ÃcØï ÅÛ­¿¡yÇó²ö—øý«^|ñ¸<­ïé�gëla»–nÐ�WÃx2¡Ù0�«}~Ì®6]÷ NÒ´ÓCãÕ<ï˜.o Öß*³òÛ?æ|ßé×�™Žâ0_±+ŽnU‡EÅÁ£A Ó ÍfÅV rk0¶äÖ`' &ßülùÙ\ý‹i7÷SeÒDp~öq1�í ŽÊÄ1+ÕôqÙ»@ùgÝ×áîÀI­!ó¹V€ôÛ~)“…¾q÷ÈÓúGÙ¸ç4eæÆ#™›õ/¦dwmðè�Æ?/ið•—ê6Œõ»ÔØü€ŽÝgwØ„ÿðÚE3˜<Âs娠¯A5þ–ló-Ïkòá¬Ð󫉦½¼í�z�Ï[!¹ÊBA¬ò'øýUSä7“t£ÀÕ0ŽLh7LçjkB}½Í^Ú,ºN÷ NÒ´Ó³2<„,³§QKÌʯŸø¤Ië×�™Žâ0_±*ŽnV‡EÅÁ£A Ó ÍfÅV òj0ÆäÖ`ÇÓúi®Í»ÁŸW)ÿOçbÚÍî[ ßšùǶvzݬ°A?Ï›ó×oX;wä+=å—nög+$m+ÛÉ6Üx�E­1³a=ûåw·æ¬×/øúMûh+ËÒ33Öä­]/¯î=%sñ¤ÁOyþ¨Û0Ö›»8,Ï¢eƒËXÿÚ”ŒùÏ™ü>Ûäx@äâ–ž^á-êY³¼7ÀãyœFw?¶lîå׫½Þž·±pmxÑÿT´ˆiž÷@hÃ5âmå}îqv‚?¿ÝGº&ÊUÉyÚQàjG&´¦s5Ú×ã±�2÷É¥ùÏʽ¦šu’¦�žúg‚}6±I¬wÄ›yšr÷Í Gq¨{‹ÃluXT<ä¡0 ڽΊ­äÔ`Œ%È­Áާ­ò¨ºãèd½õ/¦ÝÜ?)“&Ô·fþ±­“žD7+—žŒ\ÂO^b)[}hPHE·¨?±6ÊÑ==#Oû^”‹ùý ÇCÛeÝPíyW¯awz†÷ªTæ|­Wºú‡§%² kžAª x•ßX¶-øÓy/ÌO—E�˜Öy?UoœÑÜW>«$Ï>ÊŸÎ nÃ陦®†Ï„Nô¯6Hý×φûA;ÔNš^zŠŸ’kô‚|C—›•Ð4ef…«8ÌV‡½Åa¶:¬* rˆPœí6+¶J�Sƒ1– ¯;�vŸ'4�J>ÙëQ.¦Ù\vk{;ÝšùǶvzݬø÷?I¯äByYß–©áƒ#nªÒŠaߌê¨G×ö Ÿ¡÷ØÒhSºå£cUY:<`ö)݆±‹®‡Ç§“êŽ(Æ?Ø‚1ªM½e‡0VƒƒÁ_K©–Gy<‘ü±Z/iÕ]DLë¼£Õ¯tO…÷Äø(ب,yˆ ô¥p›Nøf8: Ó¼Z£êÏ=£‚!×<¨“4½ôø+|øÁ ¶Rõ¿IÇ‹4+ÿ}Üù¨Åat×e®â0[¶‡Éê°¬8Œk�G„â4hûF†¶J�Sƒ1• ÷ºÓi—©Þ ±“MÒ¿˜vs«†«nMÀc[;=‰nVü×Òäoú}ß_vM5¶S~ÝæRñˇ™=ì=8÷NWGO g _êêoºº˜¿yz0§‹ÔGýçÿÌŽ¾4µ°)JÃÖ†×XóWÒô°·ö²÷§ƒ¹~~äÚi°—‹Êäx™’Æ òÏÍä$Þ̧=0— v�ôuÀ@Ä:Ÿ÷eõú�Ò?—sU¿ÌÌ2 Æ¢ýQ^Ȭ×�_ÃŒfB¯aZW;ª™¾£K”¿Ñ<¨“4½ô¨flü¾A³òS޶wQFÍ _q˜­;‹ÃduXW†5È#Bq´Ý¬Ø+A> ÆT‚ÜìtZJyï`Ë�ÑÿËÖ¿˜vsõnMÀc[;=‰nV¤¯(·l+8Ùy°µ|ofÖΊN¿|¡°ðX£¡£wænÛ[Öjäb~ÿ¥œ¥k¶Wu<ÚTº)ÿ@…±†ÿbçAåÕì.ÜSt䲑‚ÿê– Çå ªÏÍ;¯m8¹oêmGj�EÌ8õVæž–ܹ¡´5Z8Æ“ ca`Ëíæ¯•®¦ZHQó`´¤i¤GEZ¸3Õ¬Yé$¸…Ã’¢' ªúZûB 8©#Ã|Wˆi¨îçˆ(‚o}ýrªY¹GeU…,·°YôJAÕAã$óRÀ ÍyÚ&D‚ÅÒ©æ"¢@•ôqÏ©f%0Vjý1d¸…%’  Çné\‹RÀÉ^I7sÄH�¦ÏG×7ÂQZŒ!àX³BKØnA�[+lM8y ÛÑø¤œ¬µ&\p [t}!lî¼&œ“ÌÊN©ù³�Eà*èáÞ ¨8šèdå*àÂG†ù+�]ßEˆ)Á,�ng™š<‘tiî€Ì÷daÕ1U:Ûpq™…´g²ÆkÉèZÕÛOdÚÅÇ;¿Ý ^§Lé�2àç ½ELè³`kTŒÁ~YÀ‘|AŸ3±¨8ÍF/<èŠkÃh£¸»i0—$˜…(nn�¦žˆª€kÌŠüí1“€)§5Ãë-+ŽÆ´êþèÒHoj¼¥–-Ý™à ºCË\RÌJûJº¥ÕqGõ8Zfö¬…ÕÁÖp[�P½�ÚzÅ›k�iuÂTì8 øðe‘03ÛÝdV÷i¡hïzd8Œ;L¹Û-­Žt‰Iµ6ÐþHøŒ2û¡…¼H†y(º÷´i·wªþŽiŽ4+�ša˜œGÃ,Òí¢6K‹£m ]dF ´`�Æ´X?es$–Ã0Ñ ¯ ¸Ì¬.ÓRIØ1 8‰¦�ÙàÚûÇ�l�í|ÌǰB‡ß´øM}6]eÜ770J1uÇ¥\ ¸Î¬NÑ�%å#ÅÀ1Ô³ác“¿µ¼8Žþ;9è€oI#õŠÕl[ÅúoÊq`Œ=ìýxÀ…f%pˆŠÁ›ƒQ¶À!ÔLgÏïŠÃ7�½ý½… ƒZÙ"?I§­—àCZLÙ;âb ›hï—Wšy³wu  œ@%3£kl)Ž;cèb*v ¢q1ó*Çl™1‡õáGÔA—´°y@Þ¢€KÍJàõyçbu8àŽ�`oñïØTÍlÚÑð£<Q5�ù‡SöHð§O˜3ÊCç7è‚ÛÌØ&¸Ö¬N¦°ïªXyÄ;­ùÌYOkµ­8¾e�’rÐó‚”2¿<üŠ]ü…Í‘ö.®CèA4ÎѺµÞä.W)t²Y \f3˜“ àÝA\S˦yç~ocqü0Ÿ]s~ Â$š71¿<ªÚ> ¶m`œx Ѻø ’™‰¾pµY Ô°Îno&ôƒ8æÈ(&Óu?ÙZå�Š´bxyà/ŸÉÔ0«ÉV e�ßÉ9˜Ft¨’¿TM40™ÞÙf%ð€Í�ó¦äa§ §T³ÕͽÉŶWlj¡ìÊó0Î6á»Uò’e¿ü³Í¬'�F€­©L +Œ,>åp³h/’«pZâ�Æì]¥wBu ªãæ$ví¡Û°œm"ã;<‘é õˆýü–Maö&­¾‰<€Ž”¥Ë_äŠÚ `V�Jù~½s1¥ÄÝ7Ú=£eu®û!&ÅñC¶|ùÑ…MHF¢rb†,‚ŒšXH°­HîßKÍÁvU ‚ssea¦W“’óÍJàáN¹sÅ»ø4Þ΃8¢aßxY™/Ǭ:®È�+ÞqEw‘�¤µtŽ,€¡Åm1’à]yx¹wXzW@¨»ïôbYÉF÷Ôt�Y j2äÛöN)Ä49'”¯“_y“6?ˆaqü´5è凭½‚¤$5;‚vÙ»¸1†ïê¥?—––áû$�¨+œæãý}®0+�ö²ÉÁ[O]ù%zAÌ¿6”ï˜TdÒ§u1®ŽúUIÁ¶ÌÜ~ íýKS”Ä_ˆ­ïå ¶dBîiL†HpjKV¤*Ý eí�3+�À£ÃÊWoRƶÒPˆÍWJÖ�UÄè]RÕqsi¨=cו\Áøכ媣y3B9çúD°߆d¥9ÃWì;‡w’ Ê�Òü 廓wü‘G<r‹Y šé “67s]^Áþbl£hûÆ5ËÓ“Ã*Lɺ/ÃÐW§†›•¹Ç¬HÜÊU)1eü_ÇwÅ“‘’„#-·&޾OžYŠŒy¼ÆgW¹»û\eV�J³Ò {¦æW´ÅYq´Wä§#1 Äèu§Ä™k‹æ%!1 o¡?;Þ�¥\fVhôJÅö%£ 3’¦f•4Äiu4–d¥ãÓ"÷É®oÚâR‚÷Ž>; JX½d{E7ßKºÏ¬0üWJvmÎ^¹ÉÊÙVtìæOq^?ß #da532c bidict-0.24.1/docs/_static/build-bidict-types-diagram000077500000000000000000000024101524342314000224320ustar00rootroot00000000000000#!/bin/bash # # Copyright 2009-2026 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. main() { 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 } main bidict-0.24.1/docs/_static/custom.js000066400000000000000000000015111524342314000172560ustar00rootroot00000000000000'use strict'; document.addEventListener('DOMContentLoaded', function() { var sidebarUl = document.querySelector('.sidebar-tree > ul'); sidebarUl.insertAdjacentHTML('beforeend', '
  • GitHub Repository
  • '); }); document.head.insertAdjacentHTML('beforeend', ` `); bidict-0.24.1/docs/_static/favicon-16x16.png000066400000000000000000000316561524342314000203410ustar00rootroot00000000000000‰PNG  IHDR(-S cHRMz&€„ú€èu0ê`:˜pœºQ< PLTEA A A@B @ > > A ? ? @1]4hˆGo8ÕâBñÿ?×ï8»ÚZ† ._'/BXYJÊÄoçàzÿú…ßÝ„HOR ?B˜»áÿ u­A~3oHB@ =<=5SO2‹�6ýð_±­Z@D � ÅüM‰ *` [&aˆ;j5C€†Ï �¼³ßÍó“È'[!(?­ŸBÑÂKµ«JâÑHëÕ=^[9 ?;v‘Ø­óŽØoÈT�D@sk9ÔÁ;ðÙ9˲.¶•!XR5 @R}ךüV¤=—â”ò5yAA6ìÒ*âÊ(ka/”w úÔÖ½!!'9 ^qéz÷0}QW½‚ÿCžmb&ÿݵœ9OJ.ôÍ êÆ 463HH»fÿ]îWâcùañ%u<80é¼úÈÛ¯ ç¸ÿͲ‘<?U5£CÈDË?¾'~C@QG/­ˆ¿•½“‘t $&9EF ? A@@ A@ÿÿÿ9­bKGD­ b pHYsÃÃÇo¨dtIMEè ;w»bß.nzTXtRaw profile type app11xœ­�Gb\9–EçXE-Þ,vÜûõ¹RdÐIÊÌ®ÎJ‰Œøæ½k€”éÿ÷Ιÿýï.XLìÉžeŸþ/øUr/)¯ì?qûåï1‡à‹ÍŽŸé[ïï{7|­¶Qœ oyßžÚçL {û¹³~gWBá±Å—HKOÞúÞËX=Ò¼÷öŽìó)þ»W¸÷¯¨zI®†?êK•·½¾Ãºz?ȯûŠÛfÛúZÕÎdG§Íì÷Žg/×½dŽƒy¼»{ZáòÌ%g=€aõŒXÎéí5uu:—é&­Öß�5žÈ¤Ð¢GÃRõ¶¸”CçÍ49Ú²×æÝ‡�gÎ|�cÆ­'OËzi~¤½º›£0–ÍV£o«·9Fûé�1ÒŤы¯cµ¯¾a~}Å%›l°o_Q+{£ÛæÏÙݵQ‡Måô\g‹«OÛŽu3�˜Ê2›æÒÓÚ>í>ߌ®ÿØÊÇ+Ýó+MvÏšN­ÛžÉër¯aŽxÜäu«‚;1-šÂèºåcoáÌ9mW <^i¾xgˆ1¹Ÿß8íí®¸XËJÍmÏ[®9Î>¡&3˜_‡ïq2•Óù8‡‹‘ia â?tòé…æõ�¶ofvÔ{ÜÕ�äZëí„BXûø>b 1ÄhÉÖ•ö>�D­‘YûaXo¸å�3ɳšwt§�<¾ègiÝ¢Ë�F`¹§;nåã3óÌ´œSÚeOþ+ýotÒÄúqXë(kÛØ³grºe¤r§ÏΞ±bu+Ñ�U]Z ·W¥°ç0ä]y�òe¼¾½ñó }Ï@A ´ÑÇ\Í}m.7O@µ^lg•=NfØÇZÉ1ä±T%`øú…æû7ž� “s|£G+¯ÆÔ–V¬ß³�X«]³„Lä.™^NÒ« ]`ÜžÛÅìËFJ #²§�9wŽôõË޶Gí¶KÇœM‹Ì±�&Îå{Êq?¿Ð|*ðìé�…Vù§Ùãz:¡×±{êÌ]6ÎÚCO³žÍW€Óígu¼r0­¨?v1½"ãë €·Hú]êNѵµ{‰Ã<1¬Ö{-yÔ™3Nœbz׿¦}}Ò¼³_ÂÆè��ÿ›h:ì¿aóÆ\<ù#gýŸ˜ÇÔï>qdöÓC«ë1ç÷?ƒmÞx šf�‘È¿"@øH.‘túUÔb~â£ç;Ó7ž×o„�GðÀñÕúø \‡ˆ ùùoDCŠúsèüC tBê$gÔüÝÖëj©¹Í÷ÑE2 Þ6ˆáï{héû6Mzž·K<èy¦�RÝŒ‹_krÏk|5ê¸òê†)¿÷<&¥sgü˜ÇÓK|ÿôÏçg I†�8÷LÂ+Tß/5ïßêí×o%šqö.®“½ßÌ/³�zž‹~PüýªréuúW"´zðéSÀ˜1}=KMëŸL½fÞüS¯×˜ïuôãÏ"ø½þ ´ŠoÉÍÊ£¼]c3ð›±r{EºÚ€ÖyFˆ{�Ùà6¾BCl­³GßJ›ýu¼Ì§ {¯þ7ãeþκ|?^æý€ýáx=ñëH™ÇPÍy±Þ&@( Ä[ÍÇ�=qû†[˜½Âíí¾,玵gưÑw)_¿æÇúh¡ê“… â ÌWYÿò¸Ñë+·,uinw:>®;3–%£,±m»W”ýLaVÄx“&´°üj8Ê™ênv;”ªYŠu ñ ­ù5škªP^ÖVKé§ŒPÎ&g1#ŽcGê8ã6R»úÙ@uX€¯9 n8¡Ì°™Wï ÿs\�¼àÕˆw·î<ór~¶ÊÈØÈ˹«vU ‘RÅ¥x$Ý1gŒY00·jñ7LP°#°;ô;Ó$õâÔQ=tßï£�²ŒE«ŠãëÞœ²f+ÃãáãŒÐÀ '«ài¶­9dD/‰: Z iÚÌ¡K8ŽÚÀ … ì|9;†�°œS"° †$a’ãŠe�Gkä‚¡¶Sè ˆ¹yFÑ"Ââ›èd¤ßnµ4#*ä4¯q Æ´rt^…žL…~v¨@q_ÇÓ 8ßžƒéê>b…ÌËOBî0vW;[ƒ ¢u£’sÊ­Äpáô»Í3¥86@&þ°æuaPÇ©¾š¶k©µaÃüðôl9kB1nœ9«ñE`µÏÝV™É¹Ñ�[ç`Vp� ?ÖùP1“‘ÉŽÇ­¼‰oòi1-„Ñqô?üøªCÚ¦‚zIF¡n¿ Ã@ßt‰ðsûHR·@Ž!‘N웾ÛBoL!,}§Wq»>á(bZ8ZØÞdF‰<ȽA+Ù’8^à�—x‡±<2ÿ4Œ_äŠ&Ô½`ª�¶(‘<¾L¤Ÿ´;±;|SH~à8)ój¥þܽ. !VL«°B†ò —Ûø±%hqþLò@,ù ph±Qì(,B~Pð|AŸ|ùÛ÷N΢ðrešÎBÈmdÍ]°ZÚT.sFu%�è~¸ _NŽ´µZ¤È®9�7»c¾÷;çäÌG¯óŽg_ÌÌ/®ýdt~qnÓ>ˆ7½ð¨þño&¯´¯L]tjÍ¿~o>˜¼õ'&ï«N›¿3yßwÜüÜóï;^â3›ï-0#ZP T²m§—tðAHƒ."~tÙÍĬ��öG�‚‚@P;‰H>¥ñaa<Óª2Š7¨4N=�ÓÖŠXT�Tu`fÎ.#†qqu2X�—# ÝáK ;�jV»êÅD3ãëð�Zu‰n¬˜`fo *e °sv4ZÀ—µÈN†*jyQζñöÆ÷%‡ßÁü¹Bæy@‹ÎRÁE«– ÜF4/­¢Wœ®— ¦p ® ‘2è‚…sm00 šðŒ&qYJ¶­sOu“rá¡´¡2y+®Ç*àiA…*;´äFQ…†ˆÉTŠ�àý. J€9�o‰éÁ˜m\Å'˜÷ÁÀhì-:I[ñkó‰Ðd%‚«¦ã,KXƒ¹la8Ú‡8/²Ùaã6a9 !qpøØ$æ&ÆÓ0r®"–hËÄTßfÆ�3"d]ƒeg\Æîk=˜6,a ‚øØk9-âÒ œïÄí ³SüB£®ŠŒÅ 3t8jr²1àäqÄd�+¤»WqwòQ+Ãè5W›iå abq‰v‘ƒæ#a®Aéd“±ém-UW10£i³{”㇧EˆTäܪ#É£B j^€ÙVæÀª O`÷�ýÄåâ L„AÄ#{7á1³PôM8Ãa€CèWx…ãµ·�œ9¤�¬‡|¶ÒÝB…Ÿ¯…Ø—f£™¦iW 2BZ¶®ÕV°ß{E…"Jd8>¯„_U¶e� F^Þ2P�^«ÌÇ0‹áœÑqp§Ã¨ö2KVTt´[Ì^³3añhéåXØýþÓþêð̵x–0­+ÅY6ìØý <ƒ„tZ§é·ûKÚ‚þol�ùs÷“·3cî~ðvî± õfîÊÓ¯ým]»æî7×üíÑwƒ`þ|~óyþÆî½¹=óf÷@AYÜÉQEmdjÃÿâÊ`uË ùF£�‹´Ó ‚© [¬m$ �.ÒÇX$DùÑb!’Ý-õ-Ã$-Ô…þ`|äv�àrĸÌ"(Áèy„1ô"Ç�(ÚPâ9AɲH§ƒ`OuoU.UDõé ­Ò;èŠö5‰”`ÝLf!âñøÍt> j]ªZ¸Sñ)°Ÿ‘€8[Qo�9¸õŒÍ,çÚî0Z%ƒÚè:¡ÕDô¯‰@I=ó'Pq“ë9ìpá. ä ž´’m©ÖÝ»p%ж´­Ô«C¡Úº'³† = ^3ü¨ÛBŸüPÑŽL˜ D¨€FƒÐwf®«Ø °yåÉ@“ ¢ßÉ•sâ­E^€iýèMR×R} g¯>D²×¸_¿5J€{–ÖšáFÕ·d°»1 {dm¸ðø˜Ìoǃ¬Jhˆö‡€kZ4A4�k>ǘɧÄ)Ÿe:ʘ� ¯E[; ìqÖ&ÔH%,oDƒ÷+µ‰ýÊG}w~Ã>SÐ�óM8aÍ öô>‡š´ÉòZ‘ÍÐqirºr0²¯H×+F±®[¾©@dÔ^XæҭÑ&©­ý0gÛí`Ë�dˆ¶o‰t¨˜¤žò]2UµZûvˆrdX¸ØtèˆFáZ®è(¦®Qð)½"oGH‰vª¬d§ÒœÚ<+£˜�ÍŒ t€!±*Z È/ ÚZS£R>Âi5B%#¦Q±tÚ¨0-Š ÿЗªwÃX.8íšÆ¢=‚~Æ!¿T�ü´—–U ˜>o†½¹<ó°yöüÖ%}±]öÞ!Y¤ïÒùH÷µÏNð£ü³m;±G,|®Y©øú¬Ê“Ž€þìzúB0vWÒÏB�hì«C¨mÙîØi…�ìé Æ†Br¯ O“Ú*êê%…Í#]fY 5æ�·%Lª�ÕÞ<éëœAì¢ B•N/‘=ƒ…¼h*eÝ¡/XÔîmÁáWbº*1ÉÐY}nÉôv c,¯Tg'€‚�4^…Ð0Ûž´ñ{A¼iÝ€¬l‚]«�•&YTD@dóP9³-]ƒà,9k1l5d°ìV Ó¬K´s£Nµµœ¥ÍÐ�5j©Då�S#=jMŒ¥ª_éǸµñnÒQT&-kE\›AD®%ùQY¶r™ØÃe»Ž¨#´‡.\Õ^FŠÚD÷ˆuFdÖŠvŸ™•ü¢¸á¸Wº å)ˆ�šs>7è×I '@@¤‘”/v€`[Eã¥ð…ÀWsëMÕÍŸÆ÷'ÓU7�>J Ï^å PÅ5\I5¹@l.¤ð&)ú"&Á“Ya®Èyæ³;ˆeb 3F.Gú ù´ áÁ¿yj·z#Xñeg,D MBpÕÐ ¼¦þB³Ø@_•’1€´Ý1!˜‰Üp0;^Œš't[VÅéa:˜—4'*ȵ³ê-cŲ„�Ä>pd– nJ·.Œ Ù !9" �õ*F™……á器Šñ«ªØ·«Þ¡ î�ÁD½à©˜n!ÙJLíV„RÞjÌK“Cœ·ìÁˆ¸}rª_€9œ‡öøL‹ÞC°®ÓÙB<@+¡ZrZ!ç´‘†Äf4Q!øÒbPð:Æ6DæG ™¾XðÈX‘û§¤š£që�U‹¬’8U#3l`ñ-3üÁûSÕ“àõ ’ »¿uíñ)—îw�¢ªW0àÊÚ×g°²ÎžÄû�«èK½å Ï�l·6pÁ|Çš_̶îý£ø8h£U™[¼lzˆt¨ y݆ÄɥDŽÎH øBëq›xP0­ÞLÌa2*ŒUÃZ-8ùܵêä ,Oë´ÃK’¡|¢ÄºÒž×"ëÛ2wëÊÜ-®¾ÿŽW°/5yS QÚëÏbÖ¦ûѪ/N)#5pƒél ÂåϤ`^Xa<W…°?Ö¥÷>�¾Ým‘ÜTq �VZƒÝ Ÿ¬Á�yï�Pa/_ùõ šÍ¿Ó­MNæV…—_MÁ“†J×ÞP�/•¤úÒÝ¢e·¤yi#ò¥®ýn™_¶I…z Îx}ÑË^\Sà§�p÷“ªH×ëc0Ìß�Æ×ƒa®äxr‹ÊûÏ£ñèXùÕ±_6èa—½ù{ôfƒäš#™ïˆnü ´ñN)à›Ót FßEJÓ–S+ˆŽd^›YÛÞ‘BI:ƒÇ_*VÈb·¾¡T_ ˜¬€NŸÚþø¡U´ˆ8N;c]g�xèÁOa%‰£ÍXÑ@@Õ�áfJƒA»,„;~ž9lé:È©Wma÷3ËQ D‹=’*hƒ¦„|Ø];ó˜>H÷@)»«œ±Ž6ÉödViÃ(K˜£!M‡÷žÈ¦' ¢whpÂHÕ Óx:Y‹¬ŠÚ.³“>E«Zô]KÏ:6‰§Å¸}Üö/Û^å'?$~+û2O~è¥ìËå/ê'¿ëŸvI‚ü ®åQèý°5‚X+¾G–TY÷òøñ­¿nR™�»T˜b W^‘!AÆÃÁàL×)j'ñ—“'}tpæaáÐì¨wvÙ]>µwO ‘c(R…é'xÄ+OÕŠAîhÉ1ÝF,0ÂÓvÏËþQÐä>Èàu7çm»ç�&ÌãWï9Së`ú]¾'˯©ÒHƼ/R${í×;X*ðÔï5é>~üŒ ÷´ÿÿÜ-u,èÌãwÝblêû‡™·-1ðåÃéƯ=®ßŒ”yϨÿf¤Ì«ªøPïø5÷Žgo�„ï <ì¶730¨®ŒY,~é@§òqS R8o™8ù$Äë17³N¯c«] X²´Þ0È ¿V}íhüsËp‘ïK®{F“€xDê Kņ„ÚÐâ{Z¿‡fj¼,:XÓ;ÆR'»’ `¦j©BK º©|0ƒATh[:øÃ”Ò*ÊòÎUõ!ˆYt0ÝÊÇׂÝIyàMhލ)'ŸU€8U¡jð‹IfDäÊ{©Û”DÇ'êô`B6HOEm� €*‹µJ²U?É0&-_by@ÿ:¦«üqªlȵ¡šú|¼ªÊp¥{�Ç>ëþ¯h·DÃWáhx:éà"Æ’! bK–YCsLo˜q2þrPÉ׊î Ìýž“ 10æxÍ�^p".™³ Nyg&^6ª.�ÌÉVI…ªM9Dú>À=mô˜æƒX, é}Ú°0‘¢ïâ§Á Â?ÈÖÞå qÿÅ“ XÅ¢JE&S- ùüÞ–ªîJêLj½ Pwt>™ úÕ…˜¾kAàÓ¬N÷»…£²}U½hÕGë“è=|ˆuNgÜÑA’�ãŒÎK—&—‚oÇöN†¨±€h-¢mãqyDY¨�¤R€ºræ½@�.áOu愆„‰V¸þ,gNm]N»êž ¯%Z­ û©sV‚u*µ�#x�e´#‘0Éc`†à‰¬'u@Dû‘ ºˆ*´Œïá›Z,Bm*ì�Õhëdôä²@j3Z ¡ƒi Ò'quœžg9ü ,‰´¤[ëh jeÇ1ˬ©ŒDæ­?ÊJà€ÞíœÅ ¯H£Xˆßj�=ü}ã«wó?z7Õ⇧2F;?{�‡Yáã—}}|àT쯪„'è5ïàÜùwübpêÏv/Ç×MS^Œß‡ ¯ðâà>;·òò[ÿìÜÌ¿ñ±ï�›ù7>ö½�5ÿÆÇ¾ß÷újúkø š ˜";ÒhNB¬™D6Ï‚2 3/ÀBÙí/ÀX^òM{9f'À¦êáÚ“¡4§û9"¼¥ŠvsxÕË:¡Mðo”£R…¶á„àNRÐÁ”—êÌzE殳´¯]£àð0à (¬ ëÞÃm7‚²ÂY”rúp0FØà#¤Qñ?Ȫu´Ln`Æ/>”T”­0]µ$A¢�³ZSÍG&ÝÀ>åyÅßâ?zÒA.@Q±_oÌ®5f¤90Žaˆå4¾j­k$£6½Û�(pcÄ{Ï·#Ã1÷!!ˆÀàsuÂŽi“p6d‹+@3fŒGÕ)‚¢{ ðåá4 ëä`†¨`ØV©@" ¶ÏÐ6˜ {%°VG{#ñ{0ï­˜c@Âe’“ÎÂajT$ŠÆ�7® Z5¨<ÀI*þTÁu—šEÕÿ'·Mè�4Ð"nm&ƒ¦âTmÝBF°Þ˜ãîKÀm0܉¾5bIæWE4C+`Um1àê”åt+ 8· Æ®£oÊ‘\M;º>`&«3ëæ¶åîÃÔÁâ5µýZŽÓÎ-ÀHpâsiâÄJêDí£–dˆ¦u/l6pÜð©¸#ýÄ$÷ÃßðÃ[”ÖLªÏo:«+M ‹‰Å[0h²`ƒ ?§åE^1£„CPÃÖ…Uû…5ÒÆee§UYÕMÌãW»aÔ˜bŸe2UÛÚEÛ Xµu»ˆÎ”2š÷Û\a±>•š‡KÛ^�ëö…v!ÖawØ…Ûe "ûvÌE<ß[Só«"3¼³Ÿ?Om}}6ëÖì}åxþÆð˜gÇÝ×½Bú�á1¿÷†_ž×’ŠKF×Á ×ÞûÔÀø�ý„3ê÷*`ZägSÍ¿o‹|§·¿ŠOÿ¹óX2ó;O¦{œ��VUã S�ÕreÃO;æh˜dåß:YæQéäÜÃu0pIûËž,²°!Z™ëHðv`iSBŒ;ÛYW5vh?�…ÿ¿d¢¬ügp�7 ¨ñàlԢꢳµÒ ‡åмׇ‘´è€4Iw‚M®s=b�¹R®ÒÏÒ×PK Z˜ÒrïÜÉà‚Ÿ º5[±ÓYuêМfä:tTU‡â¡MCÕ×x†N  J¯�õƒ¥‚|Ú±¤ìھ˗0ÐÚ…&/î@%™Œ-ó 2sító“ïºê”rºK¢CFÛÄªŠ‰I˲jëvËcŽ£M:$K?*Ò`xuñ›[Àºƒ¾0¼QÞbêXºÆèTY×êeÓMÚB…9-ÆÜwâPS“ Q”ÂBk4�n€�[éK °IE.¾/uTÚ‚‰$H1ZšËÑÂèܨR�âTؾ &ø¿¢Úìeˆ˜Ykì�Ù1è<ݰ*éá¡a] 4û"š´“Že·ºA)¼sT�ÈÌÐé¨yyQÍ mµëqª,Bh :½��¬¶�«ºbdEÌp2¤÷da ($œ°Æ;53{±R:ƒð'mÑ�a÷D“NG0¾N'Ü–NÖ+óæm€ òÄQî§/ô£Š݈HXÑvšÃ¼hýy@Þè ¬…·ÌˆÄ™ì¨½qƒ$]I» mYÕôêþ£±ñV]rHEtžy7ÚpÀÁ coí9rÛàÚŽ×ÑCEÝØ†BÄL¡R¥LP÷Œãwç²Ã‘'ãÃI¾ó8>�H|X2\òsõ¡ÝMå(û6tiío ݧEÜ>Ú#ú¹úPwûü…'ûÉ’™¿ñdO–Lw¢øç+0Æo¹· ¼\tßãÇšÄgcf^6)¿rfîþGvçÞÚW&Õü³ù< æGä·&Õ|ïRßLêŸÔ#šŸ|Ù8ª×½8â¡×ÅÃz(öœ °µ'¼&·ƒ˜F[µ 3ù¦*ë$u�Èš‹@Z±ø¥pK‘€Ý¨»ÔPƒyêÀ&0Ò‡?á'J|yÞ �ŠÜmLމ¶K˜¡­}"Ù —SÓ2ÞOõ$vz]º€Înºæ5€œv%ºÆ£ñµ{bK�wÉtàf�%•I: Êó4ú¾Ð$Òu¦mP}<™oºìšîÒqžœôËẎ3ÏF®ª†C�Årø›¼w):¶ÝUé^TLfRL$«Z8  ƒ„¯ø €‡"Ö©$”[ÀœT¾6E°üõ ¬Vx|há°@Þ–6ƒ®y8H&‹Æ!ªn½ˆæ¨%¦²pºi« A×jQö~³†‚$ÛЧ+ÞP™øì’d[‚7кB W}—õ Þñ×ÈLçÞº5¹¬Åû _U¡·Ê;]ªKêá̈ÝÓ)ȱUØ\K°A;Œ˜ ½×&)Nƒ«êü±Täò‡ a[œjÒö-G‘›ÖñG�©ÜnSƒVÌkct:óŒT(Û ¡°ÆËkɤ­¬„Å£ÃÀ»–ãfKSeˆ2ÇÄŒ¶™(–¨�ˆä)Ûл.ßÔ.œíAÙ¬KNn¥†Yå-•ù`È/Ö=PX|UF¸H"pæÜáE(¸}5¯ PÓj‡NŠíÑçÐM„Ä £èC$ê�Nk8ݤœÝ¨�‰˜!Φ;‘Iå:›÷$”h€<ƒhœ*ª*¢czìJJGžë(»ˆ^ƨžE�¹ ±ˆYuS0¥W­UëRªëü´ë…ºhùGu‡ŸÝ”ùÎN}w¸+&lìçÄæç ÊÝ=8L/ 'dÒÇþàÈ^ Ù×§£ÌÛñ¨ÿÖf…olVùÏlÖ3eŠ0Ù›»Yd^w‹bz²Zõ‡Ýê/v‹VÅŸ¬–ùoÚó¸Eo~w’ðoêG¼æ®¡²:zu°S Zu’¯Cšn™]Ê‹ÒTÙ¿VÅ;©¡‹1t�oÚ½hx@-‡Ð'}!­+ê*¦¡«PãÑÒ)áÆ¸�ÿ:¶JĂ֣áwÜ)(W´™Ñ�k°X€�ÓXÓq)Ù§ÓøBé: –VÞäk IKIX…¼Ûƒ¡ô]7錈òm‰A4NÏ ÑÕ*£nyJ*§Ëžÿ°—·&#„BG»W-NE$ÜU•N·t¡owرQ\)¬­Zv5B €¤;±U3Õ•% ÝÏ"¯[u¦†i©Ês…”uZC]ÕÝ Zu$Ši›áq­ÑA¶>µ[F:&ã‹}±x¤6aé²ïIX¼CPÄ:¡DÙÚ›‘×1L4öJ: ¬ò]*­Äò:Ó…eàhÚ^ûW�tªƒ„vî9žò�8º�¬ü´oþY!ÕçÕxó7Ëñ?­Æ›Ÿ—ãÿ¼ÊÎ|WYØm}Àxÿ"¿Ú­‚\ïKÍs�ãËQ�Ï_L*Ÿ|wùܧ2B#~ñ«òIo'S!tàS‡ä|øŽLð|žP˜¹{¯U–u^ MUbóèóe» ¯«¹6§µœ4öU�“�~7¸ g«{Yº´O®¨?¯:+TœWY™Ÿ€ºÄ±|ÝzüºS—ûXŸÅ$×óD-òbö`˜½x–Ÿ , ©�p˜5ë2¯[Ç2mF>›~�³ÀÄÒgÕ¬³‹WÌ[Œx€X^Ä Â­5¦¿èö5L´emE’ŽåIÑåÞU¯­.t_ûª*™B-xŒ4Êb©N�é×-Å…‚ÕQ�1†nç ¸aˆÀëxD îÈj7æ,Hùn4Ï�«­ Ý×sEO"3u n©LQ÷àɉĦãp�U™|7¼Ù¯f¾Òèí¦G�Ahhø±t€‚,ô:¹¬"Iqž©PB’O^^‡ÕEJ©i´F–Ich\ÀÁdxCKšD"�Ò •£¹­Um^O¸ÁëpUYŒlÑÞfŠÒW÷Ô‰ö\v':*^¯0NgÒ@'ËZ- ßÖY�ƒ!! ´Â¬áöŽ{ÜÊpPö*þÇÉÔe'Rˆ“êÛlµºþ$‰²Ï™A|ë¡�:xX$3åT¨Õ7¬é ]¡41¸N×FèÖÖýü˶¤ó¸ªæÒ½�žlÏNW#ƒwƵñ(ö­œ `q™S]î”TÖ /ò«¾DGf´QÌ$íþl)’šÕµCÅ=a H꺞ڑÌ;3C/c>:ÁM'TºWÔå&ë Déºí} ÖG¹Û¾ùVµ«Æpâ</|%,Ô™{¼™nawMÛc:ݸÜÿ ½Y8È£}¥/¢/TU±:ý¯2x¨�Rt©šŠ ‘º"‚§cb[•»Í*%�#š%¼4cpï2!¤sÄ“âÌlT`Ãl³–]÷άºUGˆzF0e]� ‘Z胢?cÒ#ÝÅ�7¯k´M_Ö¨S$}ìM(Ne ï�¿ZvÓºÓ=ÞŽÙÏYA!Æ'h�®ê6±Þïu(8sžË�*NŠrZ•»M·¼á—±ònâU·ŸAž÷øÁ Ó±7Ž$ÈÉËÿëØ¿Š§òè–@\Q …c�ȤƒN×M]ZàµÑÞudZwv3UÕËQ)Zš#2'²-Õ°­Áê¼`ë»¶]�•Úu 5#´á0�nN Û€8Ä¡#vªq± $ú.¨÷úžVc†‚îsSޏkè~€5·»'g”è1{àªk½¢Ç{¹®-[„%MÖAMˆBARêâš®#3¬¨ ­³WŽþޏº&ëÞD§öf`$: T—Í«�ènþ€kÁþ›å¢Ð_zTXtRaw profile type exif™ãJ­ÈLãRS3.Ss 3K33 0I1I100J4€ 6654± ¡b†0PÄ2�‰sA #d 4À”C�÷øIDATÓc````dd`dbbbb&f€L&V66v ‡“‹‹(ÀÌÍÃËÇ/À"($,"*ÆÈÄ .!)%-#+'¯ ¨¤¬¢ªÆ ®¡©¥­£«§o`hdlbjÆ`naiemckgïàèäìâêÆàîáéåíãëçÊÊŸ�˜”œ’Ê�–ž‘™•�“›—_PXT\RÊPV^QYU]S[WßÐØÔÜÒÊÐÖÞÑÙÕÝÓÛ×?aâ¤ÉS¦2L›>cæ¬ÙsæÎ›¿`á¢ÅK8RS—.›»œ‰iÅÊU«Vs�΄ Ö01"óS_À=Cº€Þ%tEXtdate:create2024-01-25T21:10:59+00:00 ´±$%tEXtdate:modify2024-01-25T21:10:59+00:00xé ˜tEXtexif:PixelPerUnitX08‹*µtEXtexif:PixelPerUnitY09I@‚tEXtexif:PixelUnit1e–ÿÉWzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚bidict-0.24.1/docs/_static/favicon-32x32.png000066400000000000000000000335571524342314000203370ustar00rootroot00000000000000‰PNG  IHDR üí£ cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ pHYsÃÃÇo¨dtIMEè ;w»bß.nzTXtRaw profile type app11xœ­�Gb\9–EçXE-Þ,vÜûõ¹RdÐIÊÌ®ÎJ‰Œøæ½k€”éÿ÷Ιÿýï.XLìÉžeŸþ/øUr/)¯ì?qûåï1‡à‹ÍŽŸé[ïï{7|­¶Qœ oyßžÚçL {û¹³~gWBá±Å—HKOÞúÞËX=Ò¼÷öŽìó)þ»W¸÷¯¨zI®†?êK•·½¾Ãºz?ȯûŠÛfÛúZÕÎdG§Íì÷Žg/×½dŽƒy¼»{ZáòÌ%g=€aõŒXÎéí5uu:—é&­Öß�5žÈ¤Ð¢GÃRõ¶¸”CçÍ49Ú²×æÝ‡�gÎ|�cÆ­'OËzi~¤½º›£0–ÍV£o«·9Fûé�1ÒŤы¯cµ¯¾a~}Å%›l°o_Q+{£ÛæÏÙݵQ‡Måô\g‹«OÛŽu3�˜Ê2›æÒÓÚ>í>ߌ®ÿØÊÇ+Ýó+MvÏšN­ÛžÉër¯aŽxÜäu«‚;1-šÂèºåcoáÌ9mW <^i¾xgˆ1¹Ÿß8íí®¸XËJÍmÏ[®9Î>¡&3˜_‡ïq2•Óù8‡‹‘ia â?tòé…æõ�¶ofvÔ{ÜÕ�äZëí„BXûø>b 1ÄhÉÖ•ö>�D­‘YûaXo¸å�3ɳšwt§�<¾ègiÝ¢Ë�F`¹§;nåã3óÌ´œSÚeOþ+ýotÒÄúqXë(kÛØ³grºe¤r§ÏΞ±bu+Ñ�U]Z ·W¥°ç0ä]y�òe¼¾½ñó }Ï@A ´ÑÇ\Í}m.7O@µ^lg•=NfØÇZÉ1ä±T%`øú…æû7ž� “s|£G+¯ÆÔ–V¬ß³�X«]³„Lä.™^NÒ« ]`ÜžÛÅìËFJ #²§�9wŽôõË޶Gí¶KÇœM‹Ì±�&Îå{Êq?¿Ð|*ðìé�…Vù§Ùãz:¡×±{êÌ]6ÎÚCO³žÍW€Óígu¼r0­¨?v1½"ãë €·Hú]êNѵµ{‰Ã<1¬Ö{-yÔ™3Nœbz׿¦}}Ò¼³_ÂÆè��ÿ›h:ì¿aóÆ\<ù#gýŸ˜ÇÔï>qdöÓC«ë1ç÷?ƒmÞx šf�‘È¿"@øH.‘túUÔb~â£ç;Ó7ž×o„�GðÀñÕúø \‡ˆ ùùoDCŠúsèüC tBê$gÔüÝÖëj©¹Í÷ÑE2 Þ6ˆáï{héû6Mzž·K<èy¦�RÝŒ‹_krÏk|5ê¸òê†)¿÷<&¥sgü˜ÇÓK|ÿôÏçg I†�8÷LÂ+Tß/5ïßêí×o%šqö.®“½ßÌ/³�zž‹~PüýªréuúW"´zðéSÀ˜1}=KMëŸL½fÞüS¯×˜ïuôãÏ"ø½þ ´ŠoÉÍÊ£¼]c3ð›±r{EºÚ€ÖyFˆ{�Ùà6¾BCl­³GßJ›ýu¼Ì§ {¯þ7ãeþκ|?^æý€ýáx=ñëH™ÇPÍy±Þ&@( Ä[ÍÇ�=qû†[˜½Âíí¾,玵gưÑw)_¿æÇúh¡ê“… â ÌWYÿò¸Ñë+·,uinw:>®;3–%£,±m»W”ýLaVÄx“&´°üj8Ê™ênv;”ªYŠu ñ ­ù5škªP^ÖVKé§ŒPÎ&g1#ŽcGê8ã6R»úÙ@uX€¯9 n8¡Ì°™Wï ÿs\�¼àÕˆw·î<ór~¶ÊÈØÈ˹«vU ‘RÅ¥x$Ý1gŒY00·jñ7LP°#°;ô;Ó$õâÔQ=tßï£�²ŒE«ŠãëÞœ²f+ÃãáãŒÐÀ '«ài¶­9dD/‰: Z iÚÌ¡K8ŽÚÀ … ì|9;†�°œS"° †$a’ãŠe�Gkä‚¡¶Sè ˆ¹yFÑ"Ââ›èd¤ßnµ4#*ä4¯q Æ´rt^…žL…~v¨@q_ÇÓ 8ßžƒéê>b…ÌËOBî0vW;[ƒ ¢u£’sÊ­Äpáô»Í3¥86@&þ°æuaPÇ©¾š¶k©µaÃüðôl9kB1nœ9«ñE`µÏÝV™É¹Ñ�[ç`Vp� ?ÖùP1“‘ÉŽÇ­¼‰oòi1-„Ñqô?üøªCÚ¦‚zIF¡n¿ Ã@ßt‰ðsûHR·@Ž!‘N웾ÛBoL!,}§Wq»>á(bZ8ZØÞdF‰<ȽA+Ù’8^à�—x‡±<2ÿ4Œ_äŠ&Ô½`ª�¶(‘<¾L¤Ÿ´;±;|SH~à8)ój¥þܽ. !VL«°B†ò —Ûø±%hqþLò@,ù ph±Qì(,B~Pð|AŸ|ùÛ÷N΢ðrešÎBÈmdÍ]°ZÚT.sFu%�è~¸ _NŽ´µZ¤È®9�7»c¾÷;çäÌG¯óŽg_ÌÌ/®ýdt~qnÓ>ˆ7½ð¨þño&¯´¯L]tjÍ¿~o>˜¼õ'&ï«N›¿3yßwÜüÜóï;^â3›ï-0#ZP T²m§—tðAHƒ."~tÙÍĬ��öG�‚‚@P;‰H>¥ñaa<Óª2Š7¨4N=�ÓÖŠXT�Tu`fÎ.#†qqu2X�—# ÝáK ;�jV»êÅD3ãëð�Zu‰n¬˜`fo *e °sv4ZÀ—µÈN†*jyQζñöÆ÷%‡ßÁü¹Bæy@‹ÎRÁE«– ÜF4/­¢Wœ®— ¦p ® ‘2è‚…sm00 šðŒ&qYJ¶­sOu“rá¡´¡2y+®Ç*àiA…*;´äFQ…†ˆÉTŠ�àý. J€9�o‰éÁ˜m\Å'˜÷ÁÀhì-:I[ñkó‰Ðd%‚«¦ã,KXƒ¹la8Ú‡8/²Ùaã6a9 !qpøØ$æ&ÆÓ0r®"–hËÄTßfÆ�3"d]ƒeg\Æîk=˜6,a ‚øØk9-âÒ œïÄí ³SüB£®ŠŒÅ 3t8jr²1àäqÄd�+¤»WqwòQ+Ãè5W›iå abq‰v‘ƒæ#a®Aéd“±ém-UW10£i³{”㇧EˆTäܪ#É£B j^€ÙVæÀª O`÷�ýÄåâ L„AÄ#{7á1³PôM8Ãa€CèWx…ãµ·�œ9¤�¬‡|¶ÒÝB…Ÿ¯…Ø—f£™¦iW 2BZ¶®ÕV°ß{E…"Jd8>¯„_U¶e� F^Þ2P�^«ÌÇ0‹áœÑqp§Ã¨ö2KVTt´[Ì^³3añhéåXØýþÓþêð̵x–0­+ÅY6ìØý <ƒ„tZ§é·ûKÚ‚þol�ùs÷“·3cî~ðvî± õfîÊÓ¯ým]»æî7×üíÑwƒ`þ|~óyþÆî½¹=óf÷@AYÜÉQEmdjÃÿâÊ`uË ùF£�‹´Ó ‚© [¬m$ �.ÒÇX$DùÑb!’Ý-õ-Ã$-Ô…þ`|äv�àrĸÌ"(Áèy„1ô"Ç�(ÚPâ9AɲH§ƒ`OuoU.UDõé ­Ò;èŠö5‰”`ÝLf!âñøÍt> j]ªZ¸Sñ)°Ÿ‘€8[Qo�9¸õŒÍ,çÚî0Z%ƒÚè:¡ÕDô¯‰@I=ó'Pq“ë9ìpá. ä ž´’m©ÖÝ»p%ж´­Ô«C¡Úº'³† = ^3ü¨ÛBŸüPÑŽL˜ D¨€FƒÐwf®«Ø °yåÉ@“ ¢ßÉ•sâ­E^€iýèMR×R} g¯>D²×¸_¿5J€{–ÖšáFÕ·d°»1 {dm¸ðø˜Ìoǃ¬Jhˆö‡€kZ4A4�k>ǘɧÄ)Ÿe:ʘ� ¯E[; ìqÖ&ÔH%,oDƒ÷+µ‰ýÊG}w~Ã>SÐ�óM8aÍ öô>‡š´ÉòZ‘ÍÐqirºr0²¯H×+F±®[¾©@dÔ^XæҭÑ&©­ý0gÛí`Ë�dˆ¶o‰t¨˜¤žò]2UµZûvˆrdX¸ØtèˆFáZ®è(¦®Qð)½"oGH‰vª¬d§ÒœÚ<+£˜�ÍŒ t€!±*Z È/ ÚZS£R>Âi5B%#¦Q±tÚ¨0-Š ÿЗªwÃX.8íšÆ¢=‚~Æ!¿T�ü´—–U ˜>o†½¹<ó°yöüÖ%}±]öÞ!Y¤ïÒùH÷µÏNð£ü³m;±G,|®Y©øú¬Ê“Ž€þìzúB0vWÒÏB�hì«C¨mÙîØi…�ìé Æ†Br¯ O“Ú*êê%…Í#]fY 5æ�·%Lª�ÕÞ<éëœAì¢ B•N/‘=ƒ…¼h*eÝ¡/XÔîmÁáWbº*1ÉÐY}nÉôv c,¯Tg'€‚�4^…Ð0Ûž´ñ{A¼iÝ€¬l‚]«�•&YTD@dóP9³-]ƒà,9k1l5d°ìV Ó¬K´s£Nµµœ¥ÍÐ�5j©Då�S#=jMŒ¥ª_éǸµñnÒQT&-kE\›AD®%ùQY¶r™ØÃe»Ž¨#´‡.\Õ^FŠÚD÷ˆuFdÖŠvŸ™•ü¢¸á¸Wº å)ˆ�šs>7è×I '@@¤‘”/v€`[Eã¥ð…ÀWsëMÕÍŸÆ÷'ÓU7�>J Ï^å PÅ5\I5¹@l.¤ð&)ú"&Á“Ya®Èyæ³;ˆeb 3F.Gú ù´ áÁ¿yj·z#Xñeg,D MBpÕÐ ¼¦þB³Ø@_•’1€´Ý1!˜‰Üp0;^Œš't[VÅéa:˜—4'*ȵ³ê-cŲ„�Ä>pd– nJ·.Œ Ù !9" �õ*F™……á器Šñ«ªØ·«Þ¡ î�ÁD½à©˜n!ÙJLíV„RÞjÌK“Cœ·ìÁˆ¸}rª_€9œ‡öøL‹ÞC°®ÓÙB<@+¡ZrZ!ç´‘†Äf4Q!øÒbPð:Æ6DæG ™¾XðÈX‘û§¤š£që�U‹¬’8U#3l`ñ-3üÁûSÕ“àõ ’ »¿uíñ)—îw�¢ªW0àÊÚ×g°²ÎžÄû�«èK½å Ï�l·6pÁ|Çš_̶îý£ø8h£U™[¼lzˆt¨ y݆ÄɥDŽÎH øBëq›xP0­ÞLÌa2*ŒUÃZ-8ùܵêä ,Oë´ÃK’¡|¢ÄºÒž×"ëÛ2wëÊÜ-®¾ÿŽW°/5yS QÚëÏbÖ¦ûѪ/N)#5pƒél ÂåϤ`^Xa<W…°?Ö¥÷>�¾Ým‘ÜTq �VZƒÝ Ÿ¬Á�yï�Pa/_ùõ šÍ¿Ó­MNæV…—_MÁ“†J×ÞP�/•¤úÒÝ¢e·¤yi#ò¥®ýn™_¶I…z Îx}ÑË^\Sà§�p÷“ªH×ëc0Ìß�Æ×ƒa®äxr‹ÊûÏ£ñèXùÕ±_6èa—½ù{ôfƒäš#™ïˆnü ´ñN)à›Ót FßEJÓ–S+ˆŽd^›YÛÞ‘BI:ƒÇ_*VÈb·¾¡T_ ˜¬€NŸÚþø¡U´ˆ8N;c]g�xèÁOa%‰£ÍXÑ@@Õ�áfJƒA»,„;~ž9lé:È©Wma÷3ËQ D‹=’*hƒ¦„|Ø];ó˜>H÷@)»«œ±Ž6ÉödViÃ(K˜£!M‡÷žÈ¦' ¢whpÂHÕ Óx:Y‹¬ŠÚ.³“>E«Zô]KÏ:6‰§Å¸}Üö/Û^å'?$~+û2O~è¥ìËå/ê'¿ëŸvI‚ü ®åQèý°5‚X+¾G–TY÷òøñ­¿nR™�»T˜b W^‘!AÆÃÁàL×)j'ñ—“'}tpæaáÐì¨wvÙ]>µwO ‘c(R…é'xÄ+OÕŠAîhÉ1ÝF,0ÂÓvÏËþQÐä>Èàu7çm»ç�&ÌãWï9Së`ú]¾'˯©ÒHƼ/R${í×;X*ðÔï5é>~üŒ ÷´ÿÿÜ-u,èÌãwÝblêû‡™·-1ðåÃéƯ=®ßŒ”yϨÿf¤Ì«ªøPïø5÷Žgo�„ï <ì¶730¨®ŒY,~é@§òqS R8o™8ù$Äë17³N¯c«] X²´Þ0È ¿V}íhüsËp‘ïK®{F“€xDê Kņ„ÚÐâ{Z¿‡fj¼,:XÓ;ÆR'»’ `¦j©BK º©|0ƒATh[:øÃ”Ò*ÊòÎUõ!ˆYt0ÝÊÇׂÝIyàMhލ)'ŸU€8U¡jð‹IfDäÊ{©Û”DÇ'êô`B6HOEm� €*‹µJ²U?É0&-_by@ÿ:¦«üqªlȵ¡šú|¼ªÊp¥{�Ç>ëþ¯h·DÃWáhx:éà"Æ’! bK–YCsLo˜q2þrPÉ׊î Ìýž“ 10æxÍ�^p".™³ Nyg&^6ª.�ÌÉVI…ªM9Dú>À=mô˜æƒX, é}Ú°0‘¢ïâ§Á Â?ÈÖÞå qÿÅ“ XÅ¢JE&S- ùüÞ–ªîJêLj½ Pwt>™ úÕ…˜¾kAàÓ¬N÷»…£²}U½hÕGë“è=|ˆuNgÜÑA’�ãŒÎK—&—‚oÇöN†¨±€h-¢mãqyDY¨�¤R€ºræ½@�.áOu愆„‰V¸þ,gNm]N»êž ¯%Z­ û©sV‚u*µ�#x�e´#‘0Éc`†à‰¬'u@Dû‘ ºˆ*´Œïá›Z,Bm*ì�Õhëdôä²@j3Z ¡ƒi Ò'quœžg9ü ,‰´¤[ëh jeÇ1ˬ©ŒDæ­?ÊJà€ÞíœÅ ¯H£Xˆßj�=ü}ã«wó?z7Õ⇧2F;?{�‡Yáã—}}|àT쯪„'è5ïàÜùwübpêÏv/Ç×MS^Œß‡ ¯ðâà>;·òò[ÿìÜÌ¿ñ±ï�›ù7>ö½�5ÿÆÇ¾ß÷újúkø š ˜";ÒhNB¬™D6Ï‚2 3/ÀBÙí/ÀX^òM{9f'À¦êáÚ“¡4§û9"¼¥ŠvsxÕË:¡Mðo”£R…¶á„àNRÐÁ”—êÌzE殳´¯]£àð0à (¬ ëÞÃm7‚²ÂY”rúp0FØà#¤Qñ?Ȫu´Ln`Æ/>”T”­0]µ$A¢�³ZSÍG&ÝÀ>åyÅßâ?zÒA.@Q±_oÌ®5f¤90Žaˆå4¾j­k$£6½Û�(pcÄ{Ï·#Ã1÷!!ˆÀàsuÂŽi“p6d‹+@3fŒGÕ)‚¢{ ðåá4 ëä`†¨`ØV©@" ¶ÏÐ6˜ {%°VG{#ñ{0ï­˜c@Âe’“ÎÂajT$ŠÆ�7® Z5¨<ÀI*þTÁu—šEÕÿ'·Mè�4Ð"nm&ƒ¦âTmÝBF°Þ˜ãîKÀm0܉¾5bIæWE4C+`Um1àê”åt+ 8· Æ®£oÊ‘\M;º>`&«3ëæ¶åîÃÔÁâ5µýZŽÓÎ-ÀHpâsiâÄJêDí£–dˆ¦u/l6pÜð©¸#ýÄ$÷ÃßðÃ[”ÖLªÏo:«+M ‹‰Å[0h²`ƒ ?§åE^1£„CPÃÖ…Uû…5ÒÆee§UYÕMÌãW»aÔ˜bŸe2UÛÚEÛ Xµu»ˆÎ”2š÷Û\a±>•š‡KÛ^�ëö…v!ÖawØ…Ûe "ûvÌE<ß[Só«"3¼³Ÿ?Om}}6ëÖì}åxþÆð˜gÇÝ×½Bú�á1¿÷†_ž×’ŠKF×Á ×ÞûÔÀø�ý„3ê÷*`ZägSÍ¿o‹|§·¿ŠOÿ¹óX2ó;O¦{œ��VUã S�ÕreÃO;æh˜dåß:YæQéäÜÃu0pIûËž,²°!Z™ëHðv`iSBŒ;ÛYW5vh?�…ÿ¿d¢¬ügp�7 ¨ñàlԢꢳµÒ ‡åмׇ‘´è€4Iw‚M®s=b�¹R®ÒÏÒ×PK Z˜ÒrïÜÉà‚Ÿ º5[±ÓYuêМfä:tTU‡â¡MCÕ×x†N  J¯�õƒ¥‚|Ú±¤ìھ˗0ÐÚ…&/î@%™Œ-ó 2sító“ïºê”rºK¢CFÛÄªŠ‰I˲jëvËcŽ£M:$K?*Ò`xuñ›[Àºƒ¾0¼QÞbêXºÆèTY×êeÓMÚB…9-ÆÜwâPS“ Q”ÂBk4�n€�[éK °IE.¾/uTÚ‚‰$H1ZšËÑÂèܨR�âTؾ &ø¿¢Úìeˆ˜Ykì�Ù1è<ݰ*éá¡a] 4û"š´“Že·ºA)¼sT�ÈÌÐé¨yyQÍ mµëqª,Bh :½��¬¶�«ºbdEÌp2¤÷da ($œ°Æ;53{±R:ƒð'mÑ�a÷D“NG0¾N'Ü–NÖ+óæm€ òÄQî§/ô£Š݈HXÑvšÃ¼hýy@Þè ¬…·ÌˆÄ™ì¨½qƒ$]I» mYÕôêþ£±ñV]rHEtžy7ÚpÀÁ coí9rÛàÚŽ×ÑCEÝØ†BÄL¡R¥LP÷Œãwç²Ã‘'ãÃI¾ó8>�H|X2\òsõ¡ÝMå(û6tiío ݧEÜ>Ú#ú¹úPwûü…'ûÉ’™¿ñdO–Lw¢øç+0Æo¹· ¼\tßãÇšÄgcf^6)¿rfîþGvçÞÚW&Õü³ù< æGä·&Õ|ïRßLêŸÔ#šŸ|Ù8ª×½8â¡×ÅÃz(öœ °µ'¼&·ƒ˜F[µ 3ù¦*ë$u�Èš‹@Z±ø¥pK‘€Ý¨»ÔPƒyêÀ&0Ò‡?á'J|yÞ �ŠÜmLމ¶K˜¡­}"Ù —SÓ2ÞOõ$vz]º€Înºæ5€œv%ºÆ£ñµ{bK�wÉtàf�%•I: Êó4ú¾Ð$Òu¦mP}<™oºìšîÒqžœôËẎ3ÏF®ª†C�Årø›¼w):¶ÝUé^TLfRL$«Z8  ƒ„¯ø €‡"Ö©$”[ÀœT¾6E°üõ ¬Vx|há°@Þ–6ƒ®y8H&‹Æ!ªn½ˆæ¨%¦²pºi« A×jQö~³†‚$ÛЧ+ÞP™øì’d[‚7кB W}—õ Þñ×ÈLçÞº5¹¬Åû _U¡·Ê;]ªKêá̈ÝÓ)ȱUØ\K°A;Œ˜ ½×&)Nƒ«êü±Täò‡ a[œjÒö-G‘›ÖñG�©ÜnSƒVÌkct:óŒT(Û ¡°ÆËkɤ­¬„Å£ÃÀ»–ãfKSeˆ2ÇÄŒ¶™(–¨�ˆä)Ûл.ßÔ.œíAÙ¬KNn¥†Yå-•ù`È/Ö=PX|UF¸H"pæÜáE(¸}5¯ PÓj‡NŠíÑçÐM„Ä £èC$ê�Nk8ݤœÝ¨�‰˜!Φ;‘Iå:›÷$”h€<ƒhœ*ª*¢czìJJGžë(»ˆ^ƨžE�¹ ±ˆYuS0¥W­UëRªëü´ë…ºhùGu‡ŸÝ”ùÎN}w¸+&lìçÄæç ÊÝ=8L/ 'dÒÇþàÈ^ Ù×§£ÌÛñ¨ÿÖf…olVùÏlÖ3eŠ0Ù›»Yd^w‹bz²Zõ‡Ýê/v‹VÅŸ¬–ùoÚó¸Eo~w’ðoêG¼æ®¡²:zu°S Zu’¯Cšn™]Ê‹ÒTÙ¿VÅ;©¡‹1t�oÚ½hx@-‡Ð'}!­+ê*¦¡«PãÑÒ)áÆ¸�ÿ:¶JĂ֣áwÜ)(W´™Ñ�k°X€�ÓXÓq)Ù§ÓøBé: –VÞäk IKIX…¼Ûƒ¡ô]7錈òm‰A4NÏ ÑÕ*£nyJ*§Ëžÿ°—·&#„BG»W-NE$ÜU•N·t¡owرQ\)¬­Zv5B €¤;±U3Õ•% ÝÏ"¯[u¦†i©Ês…”uZC]ÕÝ Zu$Ši›áq­ÑA¶>µ[F:&ã‹}±x¤6aé²ïIX¼CPÄ:¡DÙÚ›‘×1L4öJ: ¬ò]*­Äò:Ó…eàhÚ^ûW�tªƒ„vî9žò�8º�¬ü´oþY!ÕçÕxó7Ëñ?­Æ›Ÿ—ãÿ¼ÊÎ|WYØm}Àxÿ"¿Ú­‚\ïKÍs�ãËQ�Ï_L*Ÿ|wùܧ2B#~ñ«òIo'S!tàS‡ä|øŽLð|žP˜¹{¯U–u^ MUbóèóe» ¯«¹6§µœ4öU�“�~7¸ g«{Yº´O®¨?¯:+TœWY™Ÿ€ºÄ±|ÝzüºS—ûXŸÅ$×óD-òbö`˜½x–Ÿ , ©�p˜5ë2¯[Ç2mF>›~�³ÀÄÒgÕ¬³‹WÌ[Œx€X^Ä Â­5¦¿èö5L´emE’ŽåIÑåÞU¯­.t_ûª*™B-xŒ4Êb©N�é×-Å…‚ÕQ�1†nç ¸aˆÀëxD îÈj7æ,Hùn4Ï�«­ Ý×sEO"3u n©LQ÷àɉĦãp�U™|7¼Ù¯f¾Òèí¦G�Ahhø±t€‚,ô:¹¬"Iqž©PB’O^^‡ÕEJ©i´F–Ich\ÀÁdxCKšD"�Ò •£¹­Um^O¸ÁëpUYŒlÑÞfŠÒW÷Ô‰ö\v':*^¯0NgÒ@'ËZ- ßÖY�ƒ!! ´Â¬áöŽ{ÜÊpPö*þÇÉÔe'Rˆ“êÛlµºþ$‰²Ï™A|ë¡�:xX$3åT¨Õ7¬é ]¡41¸N×FèÖÖýü˶¤ó¸ªæÒ½�žlÏNW#ƒwƵñ(ö­œ `q™S]î”TÖ /ò«¾DGf´QÌ$íþl)’šÕµCÅ=a H꺞ڑÌ;3C/c>:ÁM'TºWÔå&ë Déºí} ÖG¹Û¾ùVµ«Æpâ</|%,Ô™{¼™nawMÛc:ݸÜÿ ½Y8È£}¥/¢/TU±:ý¯2x¨�Rt©šŠ ‘º"‚§cb[•»Í*%�#š%¼4cpï2!¤sÄ“âÌlT`Ãl³–]÷άºUGˆzF0e]� ‘Z胢?cÒ#ÝÅ�7¯k´M_Ö¨S$}ìM(Ne ï�¿ZvÓºÓ=ÞŽÙÏYA!Æ'h�®ê6±Þïu(8sžË�*NŠrZ•»M·¼á—±ònâU·ŸAž÷øÁ Ó±7Ž$ÈÉËÿëØ¿Š§òè–@\Q …c�ȤƒN×M]ZàµÑÞudZwv3UÕËQ)Zš#2'²-Õ°­Áê¼`ë»¶]�•Úu 5#´á0�nN Û€8Ä¡#vªq± $ú.¨÷úžVc†‚îsSޏkè~€5·»'g”è1{àªk½¢Ç{¹®-[„%MÖAMˆBARêâš®#3¬¨ ­³WŽþޏº&ëÞD§öf`$: T—Í«�ènþ€kÁþ›å¢Ð_zTXtRaw profile type exif™ãJ­ÈLãRS3.Ss 3K33 0I1I100J4€ 6654± ¡b†0PÄ2�‰sA #d 4À”C�÷ÊIDATHǵVklTÇþÎÌ}¬×ëך5Æà8$àS84Mò€¤�‡UÚªUÒ¦$?ª*Iÿ¦‘ª¨RU•ò§RT%Q‹ª¤ÏD -J¢† Uy¦`Ü�ãõÚ°»ÞõÞÝ»÷ÎÌé�]lU%z¤{¥™{îùÎcæœ�¨þ^0 |ñ}}¡êæKËKU�ƒa� šÕŸóž+̘Eæ¹:s""ˆÁ˜.ÓœñÌLD— _=¾Òêl8Õ�¬¹ÞTsSÑ»–ÝkÉô+K Ä`šûí³{}±®íÏL¶þ«ç39ºÊ®TŠAÕM£-Ûr"Ž@…º\*3èjP†Ýˆí8’6\.‡*Ðty¬jþ 0¦¦!¶lCß­ÖÍkŸ/-ÉåÀÏ÷|ràÍÊ…@ p\ùøÖÞG6õÄ›¢Ñ¨ÔJ��OíÚszÇÎáÉÉ"„¨HŠt›XׂÕ?{¾ë¹o†«nÎv´fÚ[ÆÎ&³å nÛÖ0ë‰éRÝ¢ÂuçG½ž›#��öƒ÷µüâçkÎOLJù‡îs:ÛÍŠwóÆÖ5«�¤'&üJÐ’Ü.fX±hûOŸµ·¬¿@2SæLŽ2yxº¦iN^”ùOÏ‘eq}c15UéÛo ÚZTGK¾oùù…‰éöD:æ&¡Æ¡=�Òâ%´¬Û}ÿ£´W4 J ŒŽ®]Éwßy±Sâü1¯¸w€³Y!Ôæä15°*¢ódýæ=Ø’úØñÓ_ýJ!â²1hªç{w¬ƒjìï3�l¨}ãÍ)H²@ "¹ô–Bèê,›—þ¼3xëuV b0k�„�³…°b±coóŽ¿Ç‰˜A–4?|Â{ù……´ô«ù�ßÍž"h¶‹9Ã"dN�BiØ„¾d; ÒJ†š™m{¬z^ˆzèó&e\Gåu|!`Lå1‡#ãœVJ a÷õÛ§²p뢩îGïJt/šƒ¼ Ê<ôö_»ýýÏ>ÝaÙ5‘šI‹H©2²oý)¹e£p\ ãCù§>ó�’°0‰pà¨81ftÈÂ4R{ž]ßSÿà÷.´&R°÷‡�§Þy/LŽ”^}íø×7;O§•j¬²ìûGî_GÔã›c["";—Ûù‘SI�Å tjŒ~ÿkë¶~™KæYÏ=.\0I  ¦œ/Š¢¼È?vÒJÁNMZ ãÞ·7Ÿ9v’þ²GÖÇžúFýM]šà±.�=Yøñ+Ö'CN¥TÖLcâÏ�‹›:ðØ&µ¨=‚3$§2âÐA}ä ÁÑŸ† Q)Üþãò¥W‚hsÓ×�ô.7RNéñÒÎÃá—‡N7®–Í"ØÈ¶ùäózyo@9¿$óáOC±·=f%rdORú kw×lz8úåUÚq¦ÁA>|¸[<¤×¶g_üVðÌÎwÙwXB@R¤“¤%Þ¦Vôkð!.f­w‹aÅK6šu+MWL7%°ôKb"Éɳ`ºûv½ýåRï²¢ä"kïÀAÿÕí°½ü¶&î¸S¸mMñVn�«»Ý $In§hl5ýOC@ì~›ÿù `ú(9Æ4t²Ãrc<¸ORðÒ÷³ýk§–À¥�»ÄS/6�¦„R”èp–.3@í7×{ï¿`[`†ã0Š\åF„9¥½Š“0Z¦“H¬A$0;‹m¬SùžÎ‹<R ÛßY<2æBºƒ§ëƽé{ÖGkÀ1 -ñ\k�ˆý2M\K`,´®£F+"�Ä ”" š�!å ÜדûÛ‘Ú@‘”Ôדw©„À€¸ìYùiQ9¦„Â$�F{  2›©¡—”OÂ2 í\´«—õü3ÓÚ:t¼nݲ @øÁ–ÑVg‹eéÚæ–vO  ž¬;1RÁ’ÜÅlBòÒÔ´ŠQ‡ÐÛÍp糓€vŠDá"}�óç"•ŽÜß[Œ×úÉ&^÷;¥¶&ß%†"ds5?z½ûð‰(UæÁ›¹rÛ@�PŠ!(d C1ušiR™ˆR9 = < = = < < < < > ? @ A A A A A A A A @ ? > > ? ? @ @ @ @ ? ? ? ? @@A A A ? @@@A@? < D\u"%€&€%&~&|%lR? > @ A A A A A @ ? > = ; 8>B6Q[7T^6T^6T^6S^5S^6NW;77=? ? ? @ A A ? @@AA> Ar"º<äLóQöR÷R÷R÷RöRõRïPÙH¢3Y= ? A A A A @ > ;".l€£Ò ·ô¼ý½þ¾þ¿ý¿ý¾ý½üµï˜Â3Ub>> ? @ A ? @@A ? GŸ5ïTýYýXýXýXýXýXýYýXþXýXýYûYØMr#= ? A A @ > 933�ÄÂþÁÿÀÿÀÿÁÿÁÿÁþÁÿÁÿÁÿÁÿÃÿ¿ù&„£= ? ? A ? @@@ B¡8ø]ü^ü^ý_þ_þ_þ_þ_ý_þ_þ_þ_þ_ü^þ_ãVi!< @ @ > ;%"ŸÇÇÿÄÿÆÿÆÿÆÿÆÿÆÿÆÿÆÿÆÿÆÿÆÿÆÿÅÿÆÿ#‰¨=? @ ? @@> w'ò`þdþdþdþeþeþfÿgÿgÿgÿgþfþeþeþeþeÿfÆNI> ? >&t‹ÊÿÊÿÊÿËÿËÿËÿÎÿÏÿÏÿÏÿÌÿÊþÊþÊÿÊÿÉÿÈü(_p> ? ? @?FÁOÿmþkþlþlýlülçbÉSÆQÆQÎUðgþmþmþmþmýmóks)< ? 9%" ²ÛÏÿÐþÐÿÐÿÐÿÉö¤Ç—´˜´™¶±ØÍýÎÿÎÿÎÿÍþÏÿ©Î9? ? @?\çiýtýtýtütýuÞdk%EEEH‚1îmþvþuýuýuüwšA= @ 1EIÍ÷ÓÿÔÿÔÿÔÿÏù%k{:;;=8)$™µÒÿÑÿÒÿÑÿÑÿÊõ/AE@ ? ?= l'ówý}ý}ý}ü|ü}žE< ? A A @ EÁZÿ€ü~ü~ü~þ€©M= ? -U[Õý×þ×ÿ×ÿÚÿµÕ:> ? ? ? @ .MSÐúÕÿÕÿÕÿÕÿÕÿ(Zc@ ? @= m*ó€ü†ý†ý†ü…û†‘A< ? @ ? > CÂaÿ‰üˆüˆû‡ü‰ M= ? 1OR×úÛÿÜÿÜÿÞÿ¹×9> ? ? ? ?/QX Ôû Øÿ Øÿ ØÿÙÿÙþ)\c@ ? @>`#ë‚û�û�ü�û�ý�µ^AMTST‰Bîˆü‘û’û’û’ö�~9< ? 93.!ËçßÿßÿàÿßÿÚú+jv= ;6 5279!¨ÂÝÿÜÿÜÿÜÿÝÿ×÷0GJ? ? @?JÍuýšü˜ü™ü™ü˜ì�t5s"ÐIáaâzó“ûšüšü›ûœýžÕ€Q> ? >4•¤*äÿ(âÿ(âÿ&âÿ#âÿÕð'p�5''%^q•ɱîÐþÜþßÿßÿßÿáÿ!ÁÚ:% ? ? @@> ŠGöžû¢ü¢ü¢û¡ý¡ãŒ†Cy'ÂCõcü�ú›ú¥ú¥û¨îž@> @ @ @ >50:ÀÔ6çÿ3åÿ0äþ.äÿ+äÿ$àü#¥¿/NW,FR‡´³÷ ÄÿÖþ)áþ)âÿ(äÿ4}ˆ> ? ? @@?J²lùªü¬û¬ü«üªýªõ¢¾vy9„,ÍLøoü‘ú© à› ‡KA@ A A A @ ?>:C±À?åû;èÿ9æþ7åÿ3åÿ.çÿ'Öò'�£0BH(Qb“ȸüËÿ+áÿ7²Â>%> @ ? @@A? Nžaæ£ü¶ýµü´üµý´þ´ï¦°p t4Š/±C›Jb+> ? @ A A A @ > >"ClmGÂÐEèý@éÿ>èÿ;çþ9çÿ1èÿ(Ìç)|�0>E"^y œØ�¸>0,@ @ A ? @@A A ? @h2¬t ë® ýÀ üÀüÀýÀýÀþ¾ç¨ ªl ƒ:šC¶R X= @ A A @? <"t’%i�9??Gz|KÌÝHëÿDêÿBéÿ?çÿ;èÿ2çþ(ÀÛ*l}09A;? ?A A ? AAA A > y8»f�:r= ³�ï¼þÌýÌ ýÌ ýË ýÊ ýÇù¸ü¶ëœg'= @A A @ ? :+­Ì/ãÿ*¶Ò-`m=B?K‰ŒO×çMìÿHêÿDéÿAèÿ;éÿ/äý%²Î0DO? ? A A ? @@A > e+â�ý¥ó›Áo z8wE ¾‘óÌþÙýØýØý×üÖûÓõ¸’L : = ? @ ? ?5DJ6ÍêIêÿIîÿ=æú1®Ã2W]AIEPšŸRàñKìÿGêÿEéÿ@éþ7êÿ(Êå3?D? @ A ? @@@C´q ü±ú¯û°ü±ñ£ «b T|OĤ õÜ-þè'ýæ!üå üã"ôÑ#ªl~=x8L< /BG-OU2lwLÒåWíÿZïþ\òÿZõÿKè÷6¥µ4NQC\[RÊØOìÿJêÿHêÿDéÿ;ìÿ/¨¹<> @ ? A@> [&å¥ ü½ü½ü½û½ô¶ ’V �:­Ml/ €]#Ê·DíâXðå^ïãaîÛ^íÐUîÎRå¾Hp9<'"YÁÎoâísàêzâë‚èï†êðˆëðˆëð‡ìñ~îóg×âKosFNKUÔåOìÿMëÿJêÿEëÿ;ßò;B?> @ ? @@= t? ö¾üÇ ýÈýÈþÉ Æ� Ja l'[? J c;%hB+hA+hA*hB)iB)e<%HAT5*[A6\A6\A6[A7ZA6Z@6Z@6Z@6Z@6YA8P80?KˆŽOíÿPìÿOìÿLëÿEíÿ?ln? @ ? @@= ‚O ûÍýÒ þÒ üÏþË£o < > ? ? A @ ? > > ? > > ? A @ ? > > > > > > > > > = > > AZ[EçýSíÿVîÿUîÿOñÿC�„> @? @@= }MúÕþÜþÜüØþÈ» B= ? ? ? ? @ @ A A A A A A A A A A A A @ ? ? ? ? ? ? = 8v7æÿ[îþ`ñÿ_ñÿZóÿIyz> @? @@> f7 ðÓÿçÿæþäüÐ𥠗SYRRRRH> ? A A A A A A A @ @ @? > : 76665#*W`Åã?çÿkòÿjóÿhóÿbïúIWT? @ ? @@@I˰ ÿò'ÿñ#þð#ýì$ûÌù§ ç�á…á„á„ß‚ÏrŒ@D< = = > ?@@ @ ? ? = *IOšµ¶Ö¸Ø·Ù·Ù¼ÞÓö5åþlòþvõÿuöÿsøÿgÐÖC'? A ? @@@> |Xõê1ÿù/ÿø,þ÷,þ÷.ýì.þã+þà+þÞ,ùÙ/øÕ/þÓ(õ´œZ p;p<p;`+A>7'#3??3@?3?=/\c3ÏæQðÿ`ïüaîü_òÿ`ñÿaòÿlôþ}÷ÿ€øÿ€øÿ€úÿ~÷ûZvt? @ A ? @@@@C …$úóDÿûAÿú<ÿú:ÿú:ÿû;ÿú:ý÷9·£5¨‘5õì=ÿ÷:ßÃ3¬†5¬…5¬„5¶‹._- =E‰“Q�•T‹‘TŠ�_ºÃƒùÿ†õûxœ•v•�Šò÷ŒûÿŒûÿŒûÿ�ûÿŽûÿ�ýÿ�üþp£¡C? A A ? @@@@?F—z/ìâ[ÿü`ÿüZÿúVÿúTÿúSý÷R´žA¥ŒAõîUüøV’s'? @AN GAH!BBA _RJ§îï¡ùú…•ŠƒŽƒ�óõ¢þÿ¡þÿ¡ÿÿ¤ÿÿ¨ÿÿ¢òñw”�F? @ A A ? A@@A A@Af?­–SßÔxóí†ùôŠùõŠúö‹óî‰ìçˆáÙ}›€II ? A A @ @ A @ A A A Ctib­Ðͺèç¾íìÂùøÁùø¿ù÷ºòñ®ÞÛ‘¨¢bQHB? @ A A A ? @@@AA A A ? @R%gA,tP9uR;tR;uS @ A A A A A ? @@AA A A A A A @ > = = = = > ? A A A A A A A A A A A A A A @ > > > > > > @ @ A A A A A A A ? @@A A A BA A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A BBA A A ? @ABA A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A BBAAA ? @AAA A BA A A A BA A A A A A A A A A A A A A A A A A A A A A A A BA A A A A BBBAA A ? AAABBBBBA BBA A A A A A A A A A A A A A A A A A A A A A A A A A A A A A AABB A A ? AABBBBBBBA BBA A BBAAA A BA A A A A A A A A A A A A A A A BBBA ABBBBA ? @ABBBBAAAA BBBA BBBBBA A A A A A A A A A A A A A A A A A BA A A A BA BBA ? @AABBBABBBBBBA BBBBBBBBAA A A A BA A A ABBA A A A A A A A BA AAA @ AAAABBA BBBBBBA AABBBBBAAA A A A AA AA@ABA A BBBA A A BA A@@A A A A A A A A A A A A A A A A A A A A A A A A A A A @ @ A A A @ A A A A A A A A A A A A A @ @ A ( @ ? @ A A A A A A A A A A A A A A A A A A A A A A A A A A A A A @ @A A A AA A A A A A A A A A A A A A A A A A A A A A A A A A @ @@A A AA A A A A A A A A A A A A A A A A A A A A A A A A A @ @@A A A A A A A A A A A A A A A A A A A A A A A A A A A A A @ AAA A A A A A A A A A A A A A A A A A A A A A A A A A A A A @ @AA A ? = > > > > = = ? A A A A A A @ ? ? @ A A @ @ @ @ A A @ @@@> P~%�1¤3£3£3ž1�'S> @ A A @ ? ; 0O[(n‡(tŽ(tŽ'sŽ(pŠ/Ve;&"? @ A @ @@? t#ÓHøUþWÿXÿXÿXþWùVØKz&? @ A ? 5@FŸË¾ûÂÿÂÿÃÿÃÿÃÿÀý¨Ù0Q]?@ @ @> m"çWÿ`þ`þaÿbÿbÿbÿaþ`ÿaëZq%= @ 701®ÛÉÿÇÿÈÿÊÿËÿÊÿÈÿÇÿÈÿ ¼î0KU? @ ?GÂNÿkþjþj÷hÚYÒUÖWófþkþkÿlÂPE? {’ÐÿÎÿÏÿÈö©Î¢Ä§ËÄòÎÿÍÿÏÿ¢Æ:? >]élþwývüv¬JMIK“;ùuþxþxälW;¨Ç×ÿÕÿÕÿ wŠ:; <%ixÐüÒÿÓÿÈò1:;@ = d%ï|ý„ý„ø�{2; = : g&ñ~ý†ý†æxX:°Ë ÝÿÛÿ×û/MT?? @3?B ÏõØÿØÿÓù/GI@ >Xå�ý“ü’ü’ QS}*�9½iû“ü”þ—ÊrH>,‘¡ ãÿàÿáÿ$Ÿ³8#3+,(J[š¶ÝÿÝÿÞÿÏí553? ?C´gþ¢ü üŸë’—L¨<åcý�ü ý¥ñ�?> @ =?=5Ìâ1çÿ-äÿ(ãþ&¯Ç*dsr“ ®çÐÿ#Þÿ&åÿ-¤µ= ? @? ]&Í…û®ý¯ý®õ¦Áz—F¸HäsÕˆ …KB@ A @ @IFA²À>ãù:éÿ4èÿ.Øñ+—ª(bt©¹ñ+¼Û=?<@ @ @A ? Sžcß¡ ü½þ¿ÿ¾í®·y •F›Fd#= A A @ 7&%.fv?y€G¿ÎEèü@ëÿ:éÿ1Ðç,‰œ%^u5/3@ A @ @A @ €?¾l•R ©t åµþÐþÑ þÎö¿øµ˜R ; ? @ ?4S]2×õ3±Æ6qzEƒˆMËÚJëþCëÿ:èþ.ÄÝ2S\? A @ @? [%à–þ¯ñ£½u F ±†êÍ#ÿå#ÿæ þà#ÁŠr8U;6AB<Œ™TìþXõÿRêøC¯¼?sxK�¥NåøHêÿBìÿ3Ïä964@ @ @= ‹S û¾üÀþÂÉ� z2‡9oC«‘8Ç´MƱO£IÁœC|IDA=c¦«l«¯t´·x·¸z¸¹v»»e¦©KROM˜ PìÿLëÿDíÿ ¤rÿÑýÏ üÊ‹WA H@ AEFFFCBEEEDDDDABMLKåùTíÿQñÿF�¤?@ @> ŸsÿàþÞýϨjD@ @ @ = @ A A A A A @ @ ? > = > <1muDçýcñÿ`õÿN—š? @ @= xNøå$ÿï!þæó·Åx´gµh²cƒ=D> > ? @ ? > <,IN „—‹Ÿ‰�—®+ÓícñÿsõÿnóüOec? @ @@ I¾¨%ÿû5ÿù0þô0ÿê.ÿæ-îÏ.êÇ.õÉ$§t‡W‡V[(<"\^?v}PÜíaßêcÝçgõÿjöÿz÷ÿ„ùÿ…þÿp½¾D @ @ @@> W, Á­<úõVÿþTÿþQÿÿP̾FÀ°GúôO•t&`2h:[* C%I=8I3,\d`šðò�¸±‹²ªŸÿÿŸÿÿ ÿÿ ûü„¿½N7.? A @ @@A? K �`1¹¥\ÐÂpÓÆsÍ¿rÁ±j�q>G> ? @ A @ @ Cqd\›®©¥¿»¨ÉŤÅ”¬§pldI!? A A @ @@A A A > BH I I F? @ A A A A A A A @ EH H G B? @ A A A @ @AA A A A A A A A A A A A A A A A A A A A A A A A A A BAA @ @AA A A A A A A A A A A A A A A A A A A A A A A A A A BBA @ AABBBABA A A A A A A A A A A A A A A A A A A A A BBA @ ABBBAABBA BBBA A A A A A A A A A A A A BA A BBB@ @ABBBBBBBBBBBBAAA A A A AAA A A A A A B AA@ AA A A A A A A A A A A A A A A A A A A AAA A A A A A A A @@ ( HQu%UØ‘¼� 364wog_ðý£5…úÿv;A ÿá•¿ËD„ÝßROH!•¶I]1G``9ÙðÿñB> ? j;> ? A žCB['EFE �T w”J<5âÕ8¤Véq2OSHÑâØŽ08<> �o<÷z†ZKÂÑH`* ~A×}üÅ ÝÿF±ºˆ­ï×?ÈC@@oGD Íô!½Ö»˜.JO_. ˆa&ß³T5+R(Êâ‰MÈovS*? @ A @9[^“½C= Mçùÿ‚JYX€Cña9ks ¯Û9&$?(!—=~'?}0@A ÆêB5=<\idÍÿ@œµ</GQÈ“üšˆh4¾?Z­±y5[ AÈúB@φò”9J«µeOEâùco35RXÔúó­»H¼é&bmÿfWd`> Ú»8? âW@ ^ A @½WBŸ­DÂ� 6AA.²Ë­u î] t‘TUO=ÕëóÍ9'!qkc¸ç;ÁÔ‘²B/'? @ *Òì/akA 6�‹@oÄÊzàç? Q�§�������������c���������������d��!"T��P>xx �a <q`T�m:S™]3„‡˜ŒZ-…v\Ÿi¡lŽ)0b‘W†8k{DAeI6o(_~zs•¥J¦%‚B�£ ƒ,L$“©[ –��.YyGœn ^’2|+›RO@”7K4tF&ˆhšV9¬wC —5€=Ug*¨rj?';Š1E¢Xª« Nc¤p/Mfu#}žH§�d�O‰���‹Of�dfdf�d��������f�ddd§§d§���d����cbidict-0.24.1/docs/_static/mstile-150x150.png000066400000000000000000000406071524342314000203430ustar00rootroot00000000000000‰PNG  IHDRx±ù¥gAMA±� üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEè ;w»bß@(IDATxÚí½y´eUyèûûæÚ{Ÿ¾«†ª¢(úF@¥!JcPŒTc4&w¤ÏËð%ã¦ñÝû’{G¼÷¥ÑxÕt&:bLA$ˆŠŠ ‚ôHSPP@õ}ÕéöÞkÍïý1W»ÏÞ§©F¾ß«êœ½W3×:k~óëæ7Á0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ãxv‘g»Ïudø2-?%U}¶›ôÀ^�çÃëãÓÿ"éý¨¢“·<nîˆQ{¶ðœ'}}DU-^®4ÒãçŸ4´{ûío¼ &8ƒšþŸÑMó�ö©U~ruîÕi¸G­v4qi‡T!tN ¿ª"àz>ÃÊyÂC[Ô¾=Ï!ÒýYKhWu Pð&4ƒ Ž…è1ú¤ïcñû<û†¯dÎ ²OÊ�¢s¿^FDP”nÒ§—€êÙ‰æ½ýÂN‚PšØB')ŸKò6gZÜbžýbŸK×ýÓg�#Ù© ¡dšäÒ0Á±â{U¬Ü<ûÍÿRÊRNçõ%ñ¥çN2ßï¥{Ìû¢Vµ¦¼ �Ò2½g‘ŽŽ<ϳèvGÚoTÌÚõQiªiHåA½0Á±‹�ŽühudGÅL{(_¯zí#Õžù„F/SïPMw¯†iKÅÇRyFÓìs:ë|šÆ"ÎWDªçYj›;÷ÏÚ™®½MŽC¹Îb÷-·ErßK�¶‹îc^ß Œƒc�~òl‡wUõ Û0¯ÿ¥Çwó:Œ3"’ûuŠë/êÎŽX›ž/˜ÆqDÑ`Sw¾ˆ àzkó�ñL„nšÁBû,õœ‹Ñ²Ê÷°$''sµ¥ù„W~ÌA=-c>LãX�CÉY�%~~ä(w¸#9ʬ9q8¯³g³y7 ¡üêæä+,îøòq鹎Ôë* âÉ‚¦™¢U½Ã¿Qú|1y©‚§×¾‹ó™6‡ÅAka؃ÂÇ�…ƒ7-:5…;J˨g«“És¤YÈ/²Øpw·ýžmÓO*æãX,Y>Ç¢*‘çqÈ/qYŠ<èæ“XŠssÁ&JÆ'½#J½„…é?Lp,™rG8¼¡ÅÃÑa—ªEéáf1æM%ÄÚáíö›i‡3U–ŠhióuŠƒuì-åÜ‹I¬z®wœÅ&‡uÝ/û17’t(!h#`‚cQd#WycÑÎÒ_ò5ò±˜k¼0:Îóeêÿs3UB|:£SÆfªòÜœ„á¿0:öä`"`Æ¢1�cÑôWô yvþÜóÌ‹HÌ2Ç–l3Ár(˜Æ±X² až‰ýŸ¯l„iÑ‚ ôwüqÌÌ}¾b‚ã˜ïų—òÇÇ|Âf®@1Mãp`¦Šñœãˆjk*æÿ8 ˜Æ±d²PæÂ{ŒÖ±˜É[ÏgMæpÏÔ=Ü×1&8–Šh*4ŽÌ¨µ˜™¥Æâèœ×b>ÌT9–šÒmÏ7Lã8X²Þ=°¸Ï>¦e9Lp$Rúg)u3KßTΖW<Ÿ#�¤Ç1=[UÚï¹&¸–Úþ¥ìó\»×ç7&8–Ž|XÂJiwüš ÎDG¨çŸï—×à.G¤ûÉ5;ÿôÅ,�po•O*²3»×ê=J�{ÌΩ9ò\¹×ç?&8$›ï0Ÿæ°¸6ï¹Ð �GðÅEB½QC\á~ »w.âŽ‹Û q;AÕƒDˆ“êN”–øq†!¥ò_¸×$ÜCT‹¨7—¶UÓ¶IDZÞ+íØ“Ä øôY;×C ž™ËÆÂ˜àXˆ¬x�Ò×ÚÙ©;I‹åŠ”4 êÁ9a|Ù0Çž°†“N?Žu'ÍŠÕ+X¶b�F=÷\kšîžVÛHs¦ÁÇ S&ÙúÔ½ÿqîûá£l|r;­¶¦¤ÐXôÇÜ‘r‘ áNL òâ¯ã¼—�À‹^´–£VŽÐרg7Xº·b™Uh·ÛìÚµ�íÛ÷ñä3»yø‘ͬl[·î£5›€séZ1Zü¹ò?‰ �#… ŽÃ�TëA” zK’00<ÀÉg�ÌË_w!/þ©sXyÒZdl„$ª•:›÷Jøãõ«�—7ÛüìÖí<øõïsýg¾ÊƒwmÀ«ËWKõ™¢ŠªgÅòÞò–syÇÏžÇÙ/^Íøh�ÈAè¹.×ÑŽkfŸ9¼Âôl“M[ösÇ]OñÕ›ä;ß^Ϧ§öãUpQx0ZVsÊÍ8lØÓ\ˆ‘ËTDzÖÞPßa�wh&’Ž|ê†û8ýUçpÑ»¯à„‹Î†ñ1Z"´5õ�d¾º/Ó˜-3)@-—Vþ�ÍÉ (õ­;øöÇþ�>u=ÓÓ³ø(uàlõ²Ìÿ°¨ã' >á¼óŽæ¿~ø-\þÊèSTcp™ö•Ö^ÕHª×IŸÂÜŽ/•Ÿ›mX¿a/ÿqíƒ|ö_ÀúGw¡¤Â·³Çbï]<â�ü¶õ�y°‡³£—ª,hªdj6tszŠSŽ;çT^ñ+?Ëñ¯¹ˆdt˜¶W¥E­ ¡ÑyµìwGP˧Ÿx†]w?ÂØºU¬8çtâZD¢ŠjðŒ·ZÜû7Ÿçkþ�4ãßUcs׳ͲRþ,=¢´ôêÜç�~."à•sÏYÎÇÿ¿«yÙKÖ‚Ì Òi£xÖ?¾—ü`;G¯á®a` J¹+)[¨ºË3ÏÕ‰TðH ¯�?¹‡�}òûüãgîgÏž‰:#T²8óÅÇ¢°‡³£—h� K{TaÀSFûxÉϽ‘—|àÔÖ®"Q%!ŒÐTh„-óGPq€–Ö Ã ì»÷îûð_1R«³g÷>NûÐ[8þÝW1+Š×§â¦f¸óWÿŒÇ¯»%Ø�vš éÅÂjóé}¤µH¼÷•Ïçcùò:ŸþØ[¸ê5'ƒ´7 4ÁÁÝwoåC¿}'¾o5ûwnæßu4¿÷›ç"N�J{z•1p©0s¥ ^AÄÑjÃWnz’?ùÈw¹÷�]Häæên i&8Eôl7à9Oßñ KÈÍ}êZ=Î9øËœô�wÑšcF•YfD˜Í7ò­‰0Kúyé禳¢´šÀcŸüwwïåç>ýÇ4'§yà+ßbÅU—Òl4h)´Thª2Ó_‡¾>¶Ýð]|;©6Ò _�uÆ£ÖŒ366ÌÔ�Ù|¡°Î±ÇL0==K§µGRÁX’z¯\~ùZ~÷CgÓWŸDÜ~` dhññOÜǃ›Gø³Oÿ.õšðŸ½…·\µŽÑa@Û@ç–™21J §ŸûmБkqúiƒ¼òâµ<±a?�oØ⊺m•X¯Eº5ì×Úø'Ïö«÷\Æœ£‹`n…/èõâ…—T\»œ3>òk,»âRö»Uð"$¢$)i’ºš(Z²û�Æ;6næ»_½•'ïyiÔ™VÁ+xUNÿšUœø;ï%îï§•hzî´;yOc|œ·ýï3Ôn†3‹ iîˆ x”„„}õan«­æ™ÛÀ'ÕȆÌ<ÍÑz'úkçñÁk^I¢ ÀåÍÊ\¢Š¨²bÙ4Ù†D I~|�wþì‰Üzç>÷ÑÏpÔ²A~ÿ7^Êêq ™IË4¦¥[ýá,]z&™7¦ø{($pì1Âÿúó³˜<só·v"Nèîr6» 1z‰VfY¦Q”N{_RÁQëŽùÝŸgõ¯\õê ‘B›è²€{)�¡”ì•k9¥ KUœ÷Ô=¬Ü»›þM[˜Z¾œËWЖ¥ù"à<“;=[ð$Cœ…¾0-BÒ™dª I«‰nxŠä³ÿDë�V½£ƒm~ë�»¸æª�¬Xሢ:"µ¢æÅ•C»Å{úÆNÃ-?\ƒÔŒ¨€4صo„ –MxŽ[Ó¦æ’ThøÔQÜíµL} •\J›|E…D‘$ŒìNBfe¦Õ(33 »6);$Ä·YÿuPÅû¬6ªæ9m¢ øé)tû3øÉ½¥Ž[LÔ«‰çøÕS¬Y1‹«¥R¢–l? Ñ‘cWÀŸ|hkOY�Œœƒ4Vƒë+½l!û Ép’ÝdèòtæwhjZdO«xjû”lʲìjÂg?¿“ýúLΆ¿åãç˜,>ä ˜à˜3U–Â<š®SOcÍJ–ðj’±Q¼×`¢øt`O�ÏBpÔ…,IGðR;U|Ë£-!I<øL¸Ž õ©óΧáQ|/q[˜�&wÂþmBsªN´ùIôæ&Ùú8¸¨*‰ÊacͲQ;•ùÂÐÖˆG7 óè3Ã¥CËiðicD¨ ¬[åùð§1ý$Ô�†�µhß ˆ†¢JF¼¯\±´…€Š×@\"õð¤æ\¿äãÈ YÏ[Þ0Î�7.ã3_ØžCEŒWåƒI‹Åa‚c hùÍLÉ<õ"ÂØ_Mý%§“Ä $^‚ÐHG±†S2ç�•;=ûŸ†©]B<£hð æ dáúùUÉ„I°4 >¼àÄíx nü8~û…à™VB²Òys©™Ðq•üR .íµ[§Ë’Ɖ(û÷e¬šˆùÅ7of°=~ú1�uu‚—vîüŸ| OÚ– ‰84êGëHÿZdðd¨/:œjéºÅm„Öd~Ï@¿çCï_Í×¾µ›­»ªþ)óz&8–@1#¢ãs…úꌼñrbW &…ЀRDÆgsV rÊÌÞ„]{&7ƒŸ­Î>ŸîÛãÍL°ç� .ŒãÈÌ~Üú;ð·~ždó#ÅLÙùÐòåÙ·å\ùbŸÞ9-š{¦"þðoWðÐ5~åmÛ8í„)ê�4„ÚmÀ/}VnrHÓ߇ÎnƒÉõøÆ}0úrÜÈéÁÏ¢¾rš"g,[ë×Cì9ï¬?}ùÿð¯û š_¯0a²0&8–‚ÐUt¨zÏ=‹è„ã‰c%qAPdþÇ,ƒTUqêÓD.aj·gç Í=Ôp Éädïn´Ù #½ºbèÏÚ¡„N¡ŠKbÜä^Øô8þÉ»ˆ7?жfÐÎÐO�d7Ë#üÚ}hVéÕµ¤"ì›mðñkWðÕÛ¸äì\pÖ4'¯�et(AœŸsÁ²›Bj"LŒÃêmým<—ìA÷Ý‚Oö!£/GÄ¥ÚG§·¹ìŽ©×o}ã(Ÿ¿n/3M—géš”88Lp,‚J5¯.}/Šê žwq£�$¾�Ì<ñYx1½B„Ðnzv?ꉧµ~%R`çümßÀß;º{;êÛé^v’h©]áÜêâv â6Jü]ó –hÁk¯cçÕ82*Ž'¶�ñÄWGøç›úë õ:H—u]¡”3D¢LŒz.p­p/ÍMPÌŸ„HI;Ë?MMˆêpÆ‹jˆó•�óü÷dtêœ/„hªV÷øˆ–/Gû‡Ð6ø8lƒÆ‚Æ!jâÅ'á»d:­Fѧ¸:èwo¦ùè!·¡ã캄-[lhÎç%ŽèHªRÙÂõ]êkYü¦yJ)�\à@³Æß|®� ›—#õApCà§‘dÑ6¢Iéá'ù&šæ»´9ḈZLP¦q,ˆÂ|Ü¢á!¼DÄ1xQ'©…£¥lÑ4aA=>–�V! S“Ä÷Þ‰WŸ†)+§æ'ëïÖÖ,YlÉʙɢª¨(âà±§¾{W�“OBHÂìbm"4 Ý¡°Ërç¨jŒ8eå èo(íøÙ~V?Ù˜à8D Þ9qH/O¥©˜¥œ Ÿ¦B+¸šâ� 3ûIvmïNò(4zQ„”+7¤ZŸ"tÚmáÑ Ú®„­Æàk…V1W BçiàeCp‘„ŒOçS^$aâ•z4Iº\ìù 4æ^:<8å™È©Órº% ý€CÄ¡x4Ë¡˜"X”DŠQ|š†žp„ ¶&8–@–t5giÁÙ8ø2TôyG*`2­Có}]æÄÌrB‡�¡aؾµ:ׂî¯wÖ%ŠÊéXÙ|�ŽëwFA*¡Ðâû9NÕ®eç†Q»ž¾ôy×B^¥›”®ß¦¡¥ m"J)kŽn@­”ˆ,�×ÊVÉ‚Ö!’€*³3I0SÄÄÇ¡`‚c Ì]ð9�’ìß3 :�΃H§Ò—ò!Œyé{­84${�ŒP;éTâ'«†]3ÙPNäLÿÍ|�¹C4 ?æزsäçêLñ.ÿ_ú~N.ª³§¹fÅ1T͉òy;£½ E«ß—Ï•Þq)Œ<6ªœwÖ`ø^¢0c¶õÊ'ñeùøi8–àÔØµKh6-&p¨˜àX€9/fÇ·*B{×.tß¾^/L$ŒØRì[FÓœ©EÔ.º˜Ú­ß·¦Ñ¨�4FÃñÙ,¶¬%Npí>žÄãq™Uï•þþCCCDQT$oR ýªAƒPM—YÈÊïe-ShÇžÉSÁQ‹/„B_Ä@=õßj1-7É Û¬2㥭RžS^;FUÓ>МM˜mǨW^vV�sNëK ÕÉêhZðX2Á¡y& Y 6zZm)ŠõЖŒù1Á±Á­ÑËpDHöìF·ï„ñ <¾2™,‘îA—M'Gá¥gS?ïš·~××Oôòw’w6ÎûT!TjÛ…»¯§½sÈ ÇŠuËyÙå/ãœËÏgõ±k¨×jyŠ{!t‚½¯*„ef@Ü‘¢Òj5ùá ·ó¥O|‰æÌ xUÎ>{¿ý¯ääã–Ss5BÚe&R‚ç²,HÊ%‰²ù4“ª¤Thž®¹i¡šµw’-O=ÌýÙƒÜÿHÌèˆã—Þ9ÎÄHDÐ $¿FÑã}úwËΙjÒ&i ÷ÿÈã½ •Ø�ƒÆÇé¬=ªNH¦Ð~r#zò)¨*i¯ÎU™ëò¡\õh_�·½¿á Z[ž‚G¾‰{&²úLD=º{#úÀ�´×Ù¿ AYqì*^úæK9å­¯¡vêñì®ÕÙå³)ú!…=ÊGÝ %‰^¢ŠÙá³6'Êt²–‘ÿ|ˆæƒw�sD‘òËïhóî×=B4|P§(‚´–ŠÃ œñ6Ç‘�™éëšòAAÚ -˜ÝƶGÖó©/íåÑ Žš‹x÷›GyÃ%£„ÔÓP¹½Ðª *hUEDEI‰Ù¹C¹ï!éËÍ;É+‰¥§9¨°ñ K¤[`E“˜øÁûá§. Ú�¤fA‘�ŽÊþʲ ŽÂ1'Òÿs¿Œ~ò¯I¶>Œ~í¯qç_ ;7’õDŒêÄq‚&¾ä,ÕP(5Qœ†És>†v ZÍ„v|´�ÄC¢ž™IeǃJ2S2±<È®�DÏü? êÃ…$ÔquÔ5x©…Ú’j%©fRÔØ(õȬ~GÖÁÅ£®…$Ûð;Ÿäžïíã#ŸåÆ;Gh©råeƒ|øCËhá2gF^9ŠRi±c‰¹û^x|cJt- `, !Z‚4›÷Qve íï£ï™­è1k‚Ö‘~£Y¹»J¿)*…k&EðÔÎ~9}W½�éû$ºíaÚ7þ97S›câòó9úê70pæé<]«‘´ ‰Ò cB^oT ÂBÓ™v.QÚ<3O´™|d³û[¨waoŸúZMä�[‰7=&Ê¡$>ý¥ÇLÀ‰Gß .d‚j:»ÔûˆvRcldˆµÇÓ…Ú âàú‘Z©õá¤Vy^Áñš¤~ t/²÷i6?´‡Ï^Wç“_YÎcÛú©EÂ/oð??<Áº£b�V! ÐRÎGILçšV’&‰µˆggùÊö±oºž®øVÌ«I7–€ Ž)¼ûå�Êɉ"ïØDã·­|kè iÊuY;)¨Ã "N•HÌ6ÈáS ê ¯‚ÿúÁkNõÍTHÒ;¡‘*>ïç¡Ú¸™E¦·3¹i_ÿ6|â‹|û�¦ZŽzCxÅËêüÖûÆxÃ+hd«ÀÅH— ®�ìzžbYÉ ¡4wOñ©îçé­�ô–¤¨U¢…87� ŽC$óy¨8âÍ�Ѹ嫸ŸyOxADké‘P|JÔš<½‡ö�·áïý ÉîÇßÂ5ú¨ŸyCoº’úÅç¡c´4�–‡Hòiú¡–i6),í ©3RSýÛ©ùt­¾éÙ¿Q™jž CË¡¹þy8T&û¥’ã‚Svs”¢‹‘ )çÑ–ýèÝß'¾ç+øíAÜÆõÕiœñbú®¼‚úE#Ë'ˆEÑv¹O¡`í,œ©’;ZE3"&®­4·*3›”æ>G´i3:µkN†g‘Òê«_¤;JMÉk'ƒ�Gìß½—áøøþqdxQÿ8¸ZnVñ¨kãš{hïÜÅ=w+Ÿ¾nŒ/Þ>Êöý Ϻcj\ýæQÞ÷ÖaN;Vi£>DOD_ºûLƒ *WašÄ„º êš0»›ûoõü?ŸZÃÎÉFu¡i‡„ Ž%PätT³ó1PÀOî¤uí§© �à×½Ñ'‚SOmÇ4ñƒwÓºûFØrO!Qƒè”S¸â j¯z%ºbEHej+ZZÌIEò…Ί:¢’†Óħb¡Y²Iuh˜ÒÕa`jú�o�Ü÷tv_ê-#=~ïžü&‘rý÷†˜ýïÇrÕ%1oz}�‰1!h>ÕP¤½ݾ“GPþþ†Q>÷í1žÙÕ‡G9j™ð¦ŸçýW�ð²)5×B}L B d™s)óed~ ­ú4`Ù¿‡‡ïHøí¿\Í=Ou©øeBãP0Á±å…{´wB˜¦U˽8ØòüëÇ©½ùCpÜ©¸Óø‡¤yç è3÷@{?DBí¸éíë‰.¹]µšXÒú©ž-å˜^zŽUOš¶.éBKA€HHgOÓ"UH þ’Œ<6ÊžïnÊ£>];PçbEì.Í5Rß…25Óà©=ãœsVÌò£‘(ø"¤ ­)tÿ.žYŸð¹¯ ó7Oðè–~/Œ�8^wÉx÷ŸSc ÞL6iÒV>Ÿ¦ìhÍ¢&‚BÃä5•�ZH¼¿}’Ûo­óá¿;š[Y°8±±tLp,šêdµnd{'ðÌè¿ý/jgý4í§Å?ù}hîq¸µÇиôr¢Ë^�®]GKM4õ•Hî£PŸ¯�~§ÈôtY.U¶ÎІå'� pøÝ4÷A�aAÐÚ]'é{2þؾ~Ný�ÅÞq¿!ßãMìæìU»AW ZG[“¸{ÙýTÂ|{„OÞ¸Œ{6ÑŠƒž‹_Þàïåõ7l�ÎP¬‘IÊR1ãlŽø’v¡¹YBÔBtöìeÓ£1ÿrÿaOï§–Ôu0Á±â«FÏJáaTNñâH¶?N|óßg¡x¢•«¨¿ê2Üe¯ƒcŽ ¦H¢é2 ¥yøR 0æ3?ò˜«¤+ iº@SX‚ѵ”äá�Äï@§šHcœdt28L­tÚÃþmµÂ伃ˆË®¦ñ�}¸äQ=bf·çæ;Gøø�Gñ�‡F™N#%žñþ«Gù™K¬Wð3 -*úT¹VhiÞ‰¤ÿFšûá<0 “Øñø,_üÆwÓ(wm ×òÕö:ÒpŠgi4&8–DÕ>§¤•¤“¢ n|‚Æ+.½æ ô¸SH¢ZZăàóΪW’"¥)wi䉩ö®àpDq‚lx‚ö-_§y×øý»À'H}·ìxܺ‹ÑÕg#NI¾`Ó’¢)ó"ðù[GyùÉ˹ðÔ½<¾¥�¿»i×Ý=Ξ™µšãŒÓj¼÷ƒ\}EëV¶C¤$O3/¶ųËü5™ÀPòå´%çiÃì^ömœåÆoñɯ®á¶õÃÌ´„‘Á„Z[˜iIêg™g®‘qP˜ñ·¥µcC¶g¯ÅŠ5Ko‚3”‘Aç^€{ÍÐS^µ¾P¸'«š•ç$h媆£q‘›áˆ|‚{z#É7n"þþ-Ä»·§£q”j@q˜§á¸Á•€’LoOUýR�|^ÀtÉ�”Ù-û´�Ž2ÞßdÍx›�ê윪¡qì:áÝ?3Ì{ßÜÇ©ëDÛL Ó¤³@ž>^öa¤¦JÔBZ˜Ý:Å·¿ÛÏÇ¿<Æ7ïfÿL�¡AÏ%/™äý—ícë®:ñå Û:ˆKÛü4 Ü«-:½(Lã8dáÉtz¸¸ˆÆé/Á]õ’3Ï¥Ý@¼GcŸç^ø\L¤¯´ÚŒT¥FÉñ’¹j(ѶÍè­ß`öÖI¶?Ì•þe¸§!ãÇCÔ3»Hv?�ß·1Õ2 X~ñð�­ûr`¶ÁÞÍ V­qüìýüâÛúyéÉžº›I}1s3=KƘVIH¦O£+.�¢½}’»ï¨ñ‰kWpÝ£ìœlÐyÎÑxí.®:{7Ë›ˆÀ¹'ïå�?»–›ï#!Ê[\*8`$&U¢¢q�Ï™ýœåxHZ£Ö?HýµWÁëßD2¾¯>¡Udzªäó¼¾¾wY¸!Âí݃Þq É-7oz"¤s÷/CÖ^„;ár’e§B4ˆK©ÅDcûˆê��|ïë´îûIs*ÕFª— ?,ÅYªi§Ù $žñq¸ê5ƒ¼ÿ] ^~†ÒWk£š òâ:Rý‹•³óZ¹©â’PW”itÿ4�ÞŸ¾n”Ïk”göô!NZÓä½—íá]¯ØÁ±ãS8Ÿºý56qô™cøÌ—„Øþ¢^÷,i[Lã˜Ó8–€d}½<ÿD2ÓÜÈ8µ·þÉ«^��Р뫨+º•×8™sþ,R’kîYʺMOÝûÚߺ¿áGh»…Ô‡qk/FOy#ºüÅ´k}ä++N$ÈñÀš1´ÿ|缄Ú}wÓºî ´(랇ð,$÷½Ôœç’WÔù�÷ rÙùÊ`cÕ$䑚B“ÐôIxŸ¶C³àsîåÀ%ˆÌ “S<³>æs_çoáÑ­}xŽZóö‹÷ñ¾Kwræê}Ôh§˜†e&FGñ+V±vdŒ?ÿƒP»äþ=Æ‹ëŒ Ñ9~š6²0&U¢¤qÌAÃD/' }4Þò^ü¥o$‰B ÁlQ&�tD0¤t|uÒUæÃ&H«…<|ÜòE’GîÁ·¦‘¨·üLää7âWŸG�¥‰f†AŽQ8\ª±@ðÁÔnçü>Gó¶o'­ŽÛYœÆá$›ßªŒ�´ø/?ßǯ¾g˜ÕËTg(RÃ;|"ÙMçZFyýØtj½(ꚸÙIöllñå›FùÄWG¸ëÉ!Úq�Ñá6¯=÷|ín.’ð¦ öñÁ×ìâìc÷Ð'ÍP¸Y'$õƆ�±1\½‘>ÓlMÇŽvkÑr|Ìê•ÊÕo¨qÇ�j!Ê•ùYr_‡‰‘Å`‚ã`Éò6θˆvÿû´ÓJ©÷f!’ríÀ4ûÓg;<8!Úø(þ‹�ßùR«ãV_Šžñ hß1!,yVd•C— Z�QE]šM¡i}Ïr•.)®[LÅW4C|ÒKˆ^z)zÛCÁ�>ŽÌ±91–ðëïŽY½¬Ò"ƒí¤sÄÏ’º2¿‡KZ<õ€òÑO/ã3ßœ`Os�¾F«^º—½a7¯9c7#õY$ñ©`•�¢?2#¸¾zÚªVžÛµ³§�_²ZI¯tüåg"žØÜWT$2–„ ŽƒF‘¡eøÎF“Ðiç:ÜJóO*óM(iލ9 _ûg’m�ÆÄ™è‰?ƒú7½�`ŽŒ…œ ·¤^#@ê�0;V m‚’oCóëÏ­î¥êI¢ˆèe¯&º÷[$3»™S§£X&áÕz^uN˜.õ·’PìxFytEÉg±¢mnÿN�?øßÜú£Qb‰jóž×ïáêWífõÐ4{÷*ûéCDì÷ŒOnYF¢ÒuT43Eò‰lRjx© ¦á‹¶9a­ãÂ3Ú<ñL¢Ã›÷BÁÇAâ¼ÇM¬Ã�­�8M‰®Ø"2÷},e‚¢¡•s÷£à½M ú&“OÃ=ÿ“Ô3‚ÔÓÒaéùEiôãVGí¬WÓ>élâZNM#�B¡øHeô/ç�êâ£O :î¥ÈC·ôšÃ�¾„·\Þfd`Õ™dÊäÊÓî+Y¡…ßA$á[ßéã¿|d%>•ÖÉPO+öüçmýüçm«Bû%«O ãCm.8«Å{ßÚâÜÓ›ˆo—´»3°üÐËr,¯¦Ô3\pö4Ÿ¿¹Ÿd‘!h£Š ŽC@&Öâ£AH|G‡“£dS?þ›ˆ“OhrÚ‰{Ó ÔÿŠï8k.<3"3k�šet8aßl¡1‹ÇÄìA¢ô�¢Þ¡ é&hâº� kHmˆ;4N÷Ù½�ÞWõƒd³g{lÙêiÁ¤’É]è=7ãš1Ä®(ò�­µœ^3l®XJ5ýLÛ #+�¡e€Ïgí÷þ=e]Ì@­ê‹hÑñm ڠ1ªmð1êÃÿâã>&aýc ¾rë`)í»$T{n%BœS~ôd�k¿1L�$ «Ôç[LñLjÓ-´KÒv…*Ï ã#1ã# ˆ«ÔoU“!‹Â4ŽƒD�ƒÚ’�Wì*´ŒÎ�K?ä¶~:ìÏL¦ (/áÚ#mæ M¶? “SèÐ8�©Þs)% e¹n SÊ£j© à”µ+fBI@Ÿj5i¡Ê(_¹ýR(V„‡slÛ]Ÿ-ÞÚ�xøþ š³Ž¾Úlêf‘¼¬AvÝ\$•JH–Ëâ=�ZÌ@_áXµ¸ÊÒ0Á±*UÎ)”M+qáË/`¯y-Ù›š¢ˆ:4‰â­- ü‚J‚´g‘v ]Âù²)ý‚úRïgÌ| ¥[q#ƒéš%Þ"·J¡˜Jv}mÙ?éH|Y¸vL7ëò芴´(»÷ ÍY¡o()œ³³‹Sežâ’‰&Ê,FYBšä¢ÆJ .K ,@DZí ö'åõQ»“k¥ÉTD h­ÚÙz¨åNµ½9�Ðhÿ(*}a ¢";Ïa!ü"™ •ˆ >Ds®!N‰$5 Rj¶ÆKg³¥â Ì:¤0>S‹”ÖB QÏgÎ6>Ò¦ÅéìÛt9ˆž=¾ì Å›Å)I I»ÖëcLp,‚\XT�<2½/LÑÈùŽW®<gŸU~Wtüܲð[ïE]¦3—Ó眓‘D¸Õ§×FB�â%ä%( NqI‚KâžÇzšÍ(8¬K�-´�P½½î<Ÿ;M£U$uå*«‚ké9¦m’Tó˜žq˜>Ø7Â0çè’I5 9°׎‘$Q$±ŽÉD+›d?{�¶àûF‰N¿© –¦À—.ÕcüËösꑱ5øS^ƒzÉ–ž/œ£]·¬=’¶�`æ´¦è*¨¼wìÞ¥*¿†e  ÉgÙ¨®i!aïÖ™žÉÉÇà]WNQsž"íª”$VÙ ÁÁTRU^rJ“7½ò@pzEíÅŽÍwþÚœ)Ûw6ØuÀ…ulËëÑ‹Â4Ž¥’ͪġ{6!ͨ9©�Ÿ›&¹i“~�;%CíÑD€“/¢¶÷Iüý_$ñ3S!ËK(L�΄Ãã†W"/»†xü$´]Þ£üÏ› ö¾nv?½·âÝ,2H¼ãÉ­ â¶£FŽ-kHåsæInTFÿˆ¿ñö­<õt�ýú±�—M­/ç©@ºâmš(ª '¬mò‡ïßÁÉGí BÍÅòkUX«÷ŸŸß =ÑϾÉzžC6�Œ6º`‚cɹ ÉÞgˆönE—Ÿœ~ÕI"éÿ•Ã(\q…²ç¥Ÿøœwâ†W=z~ï&¼oU�Ó"cADp�AÜQ§Â™WÑ^ór¼ÏÎç¨^¸{ûóŸÓ¹4ÑîMøéÝÕ¥%KgRQÙØ`ê@ƒÑáfå42×V)ίÅ(/ŽÝËGÛsòñ«øìMClÚ^§§ÎÞÊiÒv9a|ÔsÁYÓüú[wñÊï XR!xQò'S*œ›Ž�2Mß®ñýûiljl®ÊÁ`‚c ä…c�ÿŸÝ�ly&NÎUó�àÅœA¿óýÍÓÇ5ÕdNyѺóqû¶!­Y�¬¬¥“)â20†=†¤>š—ž(Î>ŸÐèˆd¸Ô…¹õ´5Õ3œ,ÙñØSƒ¼ìŒYövh£tø²º"ZD0Vïç®™åš× ±á™AöÍ4B”‰bR^vžZ Ö5Ë©GO1Ö˜F³êbÙó›#™ËÁêâú’:‘‰„gv ñíû†Q'E9HLp,)�fÿÄw‘ã/‡úpÖ“JÓËeÞóTBᵆ¯¯…k) ’޽ó¬ÌtH»,(2QJçÌü)ÎáâýøMw¥&Cw·—ˆ²co�¯ÿ`çž¶;$v¥¦”º,u¼zLEhT~ôÔ˜å¤U-NZ³'¤ÚgUíÜ?ó •BÞÚãÝ/Vú?¤–ýËxøé\.ØÁ2rÌ9ºT²´ÊtÆd烸g~˜¯¬¤>¬®†§ä¤ÔŽ��]ê%_ÑPSM¥ÈBU4ñùæÓÿ‰Ã2 Z>OÅñ)‹pŠ–œµ¢Í Û™#è:3Hc”/Ý:¶�cAKIý¡a]hI×±í±•—Ų°éýÅ1Ämˆc4Û’°'A›Ë}'Ù"Û½¶´¼€$)Ú” �=ûø—›Æhµ²ìÕrÝSc±˜à8�x ÿÈõD“»ŠˆI¢yÇßáÈ^äôsI’-I–¥'/‹®ólžTH$®´I×M²-�ôHº¢µ›=€®¿ mO2èœ8îÞPç†ï­Eè+-Â"š Ââ^ÓûÈÚáK[å~¨, [Ù>!ÙNòktn”þfTÚ&%£RçºÛŽáöúS§H£+kc¦{,Œ Ž% ¥WJÓ°¤Gð;略á¦P 3É´�Tkˆ»„cË/¸Oó©²Î•Í-©Ì3é²U:bv>í¹i*¨´"À÷ôíÄ[îÄ/°uæÝ™mÃÿùò·�ˆàª!ݤÔ.툰�¼âé8ž9‚6”¹ÖR� é„óIéYd?‹ÏD‚cÖµüÕ&˜mº’v¾-¯®g,Œ Ž¥PI¥.V•Ç·IÖ‘hÛý¡&f’¤ù¾Ã,HÎò<*�›\àä&ûnޙӹ_DZ=LM¸N}(²¼wú£/ ñ4Uu=[0*ëTÙ=­ã‡ëc>þk˜MÖæË¹f‚’.Â"ϵð]¶²Ð즙d‚ 3ATè’î17$ÑЮta«ÉÖ*þì³ë¸ëQæõÊô5«eQ˜àXU?\ñâ)àg¶Áÿ‡ú¾'ÉV%Ë—ŸË“ù¨ IJ‰6GvhT%¿L.D:Í7Ÿ™ŠÅslq}í üË� •dC�Ðó³ý¢ýú)žçôÿÇÕz Õ—-›n&ÌìÀMmÅ���ÖGÒlèÂŽÏÕì,ß#WÙé½e+9UÔt:„ •ÑW4í�B+¬;:œkïFø;’§¿• „’ �.#q–Zžý*ÂL îyØó¢SVsâšI$™I;2y{Ë´²n)€’_µ[²{–Rþ¾»–‚#¥‚Ééß$®Å'ozù”0Ù¤t…©¢ÿFz‚ÖÆ?ùñ½d?y˜àXˆE Ž€"¸©MÈ�§‘‘c¡±,i5!!”"§äÌ×9¢%Ðj´  ¶~!P2AQ>oÑKk³›q~ÿÔ7ñù‚Ii}�,C{ Ž¢Ó‰ÀžI厕O\ÅÉGÏ"ÉT¡ùPvpf÷%•öHÇý– £çSLtîy:7õ]®åjLËZ>ö•ø“O {&I ™WkŒjÇï&8‡ Ž…è2燊Ó˜ÞŒÛó®1Ž®B¨¥!E*�»ºÑ±Iéó­Ãk©ÃeBÂÏ9wèïQˆ4!Ús?òà'H¶|O–eY}Ê)ß«ص?áÖ{<Ãc«9íÄ:}r¼O}©™•¥xÌÑ®:RÄ{j]ÕßóôðR&×:i ñô�3øÓϬ棟õìŸNë†thSU=ªøTÀǘy!:ÖŽÕ\Cè²Ê9”fŒz¢Æ0¬y-þØ7� ®­CÚaË)çBðò/Õ¶®v-Ú—¯'Dx\klý:þÉëÑém¥ul;V­_¤Ë+»×0-_QŸ0Ò¯¼ýµýüÆ;[œ¾ê j³;CnF×ܪ² Õü£¥Ü×¹%�3n7ß·Žÿñ™ß»?N—ÀÌŽ(=±<átîªuâmµú…°‡³Ý�ÎLÈuì|¢TZ8FJ‰2´Ys¬¼<•zÚI³7_J‚£ûŸdΔ—Rc$Óé³k:·kîÂíø>Éæ[Ð}�à}\dhVÎ:ÿµç6Æ—| ¾h›Æœt \seo»dŠSVl£ÑÞíÔ‡cò+ç¶Hõ²=¬¤J“Ãí¦IxQõ!&uß{ì(þñ†A®ÿn›½ûÁ¹rYÀ¡¡s?ÏïÍÇ‚ØÃYˆ^«Õg#U¶6iªv£1”³#q0p²ì\Xq:r"RŸ@]Þ¹¹#s¹Í‘…Î^ìåqÚFÚûaòØ}ºãn˜|‚Xcè™§‘ ­% ÷Ùš°Åµ³Ô'ÔHX·Æqù…}\yaÂ9'N²jh?Ñ,"3E¦—Be=˜J5 ò­–'Ôð~ˆÉd€§÷ŒpÛƒ\û�·ÝÓfÏÂú¹½´ª^šFéÞLp,Œ=œ…è%8:uë,1U%ó1ŽEMý D ¤%2x4n`Ú¿ !®––,§ER’–r§3U]ç[ÐÜ�NmÅOmAgw¹’E ²sPJÂÒM¤üÆ;Úš}'€ú0]~ Ö­N?¾Æ‹Ž«±vUÌÈ à¢Ô[’O»'�>XÔàÈ+‡–ÖNi'ÊžýŽ'6 = �>™°mg›8Ž•Ì’N­Š"‚¤ÕÏ«V‹ÁÎBôY@ÒA;}¹3œQ¹óà ò™¶â�ÜW­…RÑDª'Ë»Fšç­Y u·�*‹m—JÏ{,­¯’/8-ªD®K�P- ÍüUeK4O=÷ù³wA€UœÖ‡pï&8…ÍŽ=´ÓîÎ<ú•ÅUŠä0©ìœ’šŨZ´É�¥¤ô°'§®ë0 ½ÌŸÃò :î,ïø™B�¡L`æyÉnn¾¬Íní¬:HDÊôÖ0*¹–ÙuØ0Áq«Dæ~ª�{ª55º�m>þmŸÛ7÷ :7”|–eÇã\Gì¡ßs·ï«çÔŠ¬Ðçe€ Ž¥“•Ì Îèü6sØ{áî/Zíé]Péø¢¼J|7ÍâÇ=ÂvÑ@æ>ézÌ¢žIå¼ó·Á´‹#‹ Ž˜ëߨf‘ŠdÂc¡Qt¾ï‹\†ùÏÓc¤íšÔðl˜è鵸¶ôºgéqü¢Jv™{âHc‚c!²—ºó…-*ùß�,Bk¡ËudþÏŸU›ÑÕ£­½ò,I@‡  –é(Ûêù7é÷‡ëE]ìyä�ÿqrêO̽¾°0Á±XºhKJš2Œçæj^4Y4 sV–a¼ð0�c±HY`¤eK˜ü0^`˜Æ±hzIAÄlnã……i ‘Wˆé�šÊa¼À0�cAL(F'&8Bݼ¹½´ 3_Œç3&8Å<³c{ ª&<Œç-&8‰Þ’#²‰ñÜÁþT‹ÃÇ!±ˆYž²¸<Ç#¡�ˆXÄç`0Ù±0UYˆ�!K1ï:¯¬r\©„`VèG«)ê��Z„P“#[{Å0ž£˜àX�R)žrX×ù+¥£JÉ+W—8â-·0±q„0Á±X´:ÛsÁNY*S©S•:M{oÖã³IV<ÝDîü˜àX¡fæ!j ¥—Ñ4ã'Þ‹xs¹FŠ Ž%1w¢›a¼1Seº—þ/‡9{UßZ¨”ß�_éœ5PJŽÛžû—Zßå´äÁ™7ò›ï»À~ ÒíùŽêì绯Âl,/P›Ž¡‡»üóK&]Ö «Ÿ¢Çº†áˆ~?|m[Šf¤ôòJç^ œRY^`±û-D·ú¦¥°9‹õp ù ö¦L†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†a†aðÿˆG|�2Q¶%tEXtdate:create2024-01-25T21:10:59+00:00 ´±$%tEXtdate:modify2024-01-25T21:10:59+00:00xé ˜WzTXtRaw profile type iptcxœãò qV((ÊOËÌIåR# .c #K“ D€4Ãd#³T ËØÔÈÄÌÄÄË€H J.êtòB5•IEND®B`‚bidict-0.24.1/docs/_static/safari-pinned-tab.svg000066400000000000000000000215321524342314000214200ustar00rootroot00000000000000 Created by potrace 1.14, written by Peter Selinger 2001-2017 bidict-0.24.1/docs/_static/site.webmanifest000066400000000000000000000006521524342314000206050ustar00rootroot00000000000000{ "name": "", "short_name": "", "icons": [ { "src": "/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" } ], "theme_color": "#ffffff", "background_color": "#ffffff", "display": "standalone" } bidict-0.24.1/docs/addendum.rst000066400000000000000000000207361524342314000163050ustar00rootroot00000000000000Addendum ======== Performance ----------- Bidict is written to be as performant as possible without sacrificing other important goals, such as safety, portability, and maintainability. In general, using a bidict to maintain a bidirectional mapping should exhibit about the same performance as keeping two mutually-inverse one-directional mappings in sync manually. The test suite includes benchmarks so that bidict's performance can be continuously measured and improved. If you spot an opportunity to improve bidict's performance further, please don't hesitate to :doc:`file an issue or submit a pull request `. ``bidict`` Avoids Reference Cycles ---------------------------------- A careful reader might notice the following... .. doctest:: >>> fwd = bidict(one=1) >>> inv = fwd.inverse >>> inv.inverse is fwd True ...and worry that a :class:`~bidict.bidict` and its inverse create a reference cycle. If this were true, in CPython this would mean that the memory for a :class:`~bidict.bidict` could not be immediately reclaimed when you retained no more references to it, but rather would have to wait for the next garbage collection to kick in before it could be reclaimed. However, :class:`~bidict.bidict`\s use 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 :class:`~bidict.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 does not occur, 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. :mod:`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 :class:`~bidict.bidict`\s to return a set-like (*dict_keys*) object for :meth:`~bidict.BidictBase.values`, rather than a non-set-like *dict_values* object. Missing ``bidict``\s in the Standard Library -------------------------------------------- The Python standard library actually contains some examples where :class:`~bidict.bidict`\s 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. - The :mod:`html.entities` 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 :class:`~bidict.bidict` are not atomic. If you need to mutate the same :class:`~bidict.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:: >>> {1: int, 1.0: float, 1+0j: complex, True: bool} {1: } >>> 1+0j 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 a :class:`~bidict.bidict`, since values function as keys in the inverse mapping, this behavior occurs in the inverse direction too. That puts a :class:`~bidict.bidict` between two of :class:`dict`'s conventions, which conflict once a value is also a key: overwriting a :class:`dict` key keeps the key object already contained, but replaces the value object with the one passed in. A :class:`~bidict.bidict` resolves this by keeping the object already contained in both directions, so that a single item is never represented by two equivalent but distinct objects: .. doctest:: >>> b = bidict({'false': 0}) >>> b.forceput('FALSE', False) >>> b # the contained 0 is kept, rather than the equivalent False passed in bidict({'FALSE': 0}) >>> b.inverse bidict({0: 'FALSE'}) >>> b.inverse[b['FALSE']] is next(iter(b)) # one object per item, in both directions True *nan* as a 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 :class:`~bidict.bidict`\s too. :mod:`bidict` contains no special-case logic for dealing with *nan* as a key, so bidict's behavior will match :class:`dict`'s on whatever runtime you're using. Note that even though *nan* is not equal to itself, re-inserting an already-contained item using the same *nan* object is still construed as a no-op (see :ref:`basic-usage:Key and Value Duplication`): .. doctest:: >>> b = bidict() >>> nan = float('nan') >>> b[nan] = 'nan' >>> b[nan] = 'nan' # no-op >>> b bidict({nan: 'nan'}) See e.g. `these docs `__ for more info (search the page for "nan"). Simultaneous Assignment ^^^^^^^^^^^^^^^^^^^^^^^ :class:`~bidict.bidict`\s may behave differently from dicts with respect to so-called "simultaneous assignment". Consider the following: .. doctest:: >>> m = {'a': 'a', 'b': 'b'} >>> m['a'], m['b'] = m['b'], m['a'] # swap two values >>> m {'a': 'b', 'b': 'a'} With a :class:`~bidict.bidict`, simultaneous assignment cannot be used to swap two values in this way: .. doctest:: >>> m = bidict({'a': 'a', 'b': 'b'}) >>> m['a'], m['b'] = m['b'], m['a'] Traceback (most recent call last): ... bidict.KeyAndValueDuplicationError: ('a', 'b') This is because "simultaneous" assignments like the above are `by definition `__ just syntax sugar for: .. code-block:: python # desugaring: m['a'], m['b'] = m['b'], m['a'] tmp = (m['b'], m['a']) m['a'] = tmp[0] m['b'] = tmp[1] and so the intermediate ``m['a'] = tmp[0]`` assignment raises :class:`~bidict.KeyAndValueDuplicationError` before the second half of the swap assignment has a chance to run. For a working alternative, you can write: .. doctest:: >>> m.forceupdate({m['a']: m['b'], m['b']: m['a']}) >>> m bidict({'a': 'b', 'b': 'a'}) ---- For more in this vein, check out :doc:`learning-from-bidict`. bidict-0.24.1/docs/api.rst000066400000000000000000000010331524342314000152620ustar00rootroot00000000000000API === This page contains auto-generated documentation from the bidict source code. bidict ------ .. automodule:: bidict :members: :imported-members: :member-order: bysource :special-members: :show-inheritance: :undoc-members: .. autoattribute:: bidict.BidictBase._fwdm_cls .. autoattribute:: bidict.BidictBase._invm_cls .. autodata:: bidict.RAISE .. autodata:: bidict.DROP_OLD .. autodata:: bidict.DROP_NEW .. autodata:: bidict.ON_DUP_DEFAULT .. autodata:: bidict.ON_DUP_RAISE .. autodata:: bidict.ON_DUP_DROP_OLD bidict-0.24.1/docs/basic-usage.rst000066400000000000000000000312471524342314000167060ustar00rootroot00000000000000Basic Usage ----------- Let's return to the example from the :doc:`intro`: .. 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 bidict({'hydrogen': 'H'}) >>> element_by_symbol.inverse['helium'] = 'He' >>> element_by_symbol bidict({'H': 'hydrogen', 'He': 'helium'}) >>> del element_by_symbol.inverse['hydrogen'] >>> element_by_symbol bidict({'He': 'helium'}) Note you can also use :attr:`~bidict.BidictBase.inv` as a shortcut for :attr:`~bidict.BidictBase.inverse`: .. doctest:: >>> element_by_symbol.inv bidict({'helium': 'He'}) Both a :class:`bidict.bidict` and its inverse support the entire :class:`collections.abc.MutableMapping` interface: .. doctest:: >>> 'C' in element_by_symbol False >>> element_by_symbol.get('C', 'missing') 'missing' >>> 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' The inverse is automatically kept up-to-date. Referencing a :class:`~bidict.bidict`'s inverse is always a constant-time operation; the inverse is not computed on demand. 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 :mod:`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): ... bidict.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 explicitly: .. doctest:: >>> b.forceput('two', 1) >>> b bidict({'two': 1}) Similarly, initializations and :meth:`~bidict.MutableBidict.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): ... bidict.ValueDuplicationError: 1 >>> b = bidict({'one': 1}) >>> b.update({'uno': 1}) Traceback (most recent call last): ... bidict.ValueDuplicationError: 1 >>> 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}) In summary, when attempting to insert an item whose key duplicates an existing item's, :class:`~bidict.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, :class:`~bidict.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 :meth:`~bidict.MutableBidict.forceput` (mentioned above) and :meth:`~bidict.MutableBidict.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 :meth:`~bidict.MutableBidict.put` and :meth:`~bidict.MutableBidict.putall`. These variants allow you to pass an :class:`~bidict.OnDup` instance to specify custom :class:`~bidict.OnDupAction`\s for each type of duplication that can occur. .. doctest:: >>> b = bidict({1: 'one'}) >>> b.put(1, 'uno', OnDup(key=RAISE)) Traceback (most recent call last): ... bidict.KeyDuplicationError: 1 >>> b bidict({1: 'one'}) :mod:`bidict` provides the :attr:`~bidict.ON_DUP_DEFAULT`, :attr:`~bidict.ON_DUP_RAISE`, and :attr:`~bidict.ON_DUP_DROP_OLD` :class:`~bidict.OnDup` instances for convenience. If no *on_dup* argument is passed, :meth:`~bidict.MutableBidict.put` and :meth:`~bidict.MutableBidict.putall` will use :attr:`~bidict.ON_DUP_RAISE`, providing stricter-by-default alternatives to :meth:`~bidict.MutableBidict.__setitem__` and :meth:`~bidict.MutableBidict.update`. (These defaults complement the looser alternatives provided by :meth:`~bidict.MutableBidict.forceput` and :meth:`~bidict.MutableBidict.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. For example: .. code-block:: python b.putall([(1, -1), (2, -2), (1, -2)], on_dup=OnDup(...)) Here, the third item we're trying to insert, (1, -2), duplicates the key of the first item we're passing, (1, -1), and the value of the second item we're passing, (2, -2). Keep in mind, the :class:`~bidict.OnDup` may specify one :class:`~bidict.OnDupAction` for :attr:`key duplication ` and a different :class:`~bidict.OnDupAction` for :attr:`value duplication `. In the case of a key and value duplication, the :class:`~bidict.OnDupAction` for :attr:`value duplication ` takes precedence: .. doctest:: >>> on_dup = OnDup(key=DROP_OLD, val=RAISE) >>> b.putall([(1, -1), (2, -2), (1, -2)], on_dup=on_dup) Traceback (most recent call last): ... bidict.KeyAndValueDuplicationError: (1, -2) Note that repeated insertions of the same item are construed as a no-op and will not raise, no matter what :class:`~bidict.OnDup` is: .. doctest:: >>> b = bidict({1: 'one'}) >>> b.put(1, 'one') # no-op, not a DuplicationError >>> b.putall([(2, 'two'), (2, 'two')]) # The repeat (2, 'two') is also a no-op. >>> b bidict({1: 'one', 2: 'two'}) See the :ref:`extending:\`\`YoloBidict\`\` Recipe` for another way to customize this behavior. Collapsing Overwrites +++++++++++++++++++++ When setting an item 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:: >>> b = bidict({1: -1, 2: -2, 3: -3, 4: -4}) >>> b.forceput(2, -4) # item with duplicated value, namely (4, -4), is dropped >>> b # and the item with duplicated key, (2, -2), is updated in place: bidict({1: -1, 2: -4, 3: -3}) >>> # (2, -4) took the place of (2, -2), not (4, -4) >>> # Another example: >>> b = bidict({1: -1, 2: -2, 3: -3, 4: -4}) # as before >>> b.forceput(3, -1) >>> b bidict({2: -2, 3: -1, 4: -4}) >>> # (3, -1) took the place of (3, -3), not (1, -1) Updates Fail Clean ++++++++++++++++++ If an update to a :class:`~bidict.bidict` fails, you can be sure that it fails clean. In other words, a :class:`~bidict.bidict` will never apply only part of an update that ultimately fails, without restoring itself to the state it was in before processing the update: .. doctest:: >>> b = bidict({1: 'one', 2: 'two'}) >>> b.putall({3: 'three', 1: 'uno'}) Traceback (most recent call last): ... bidict.KeyDuplicationError: 1 >>> # (1, 'uno') was the problem... >>> b # ...but (3, 'three') was not added either: bidict({1: 'one', 2: 'two'}) This holds no matter why the update failed – not just for a :class:`~bidict.DuplicationError`, but also for e.g. an unhashable key or a malformed item. What is restored is the bidict's *contents*. For an :class:`~bidict.OrderedBidict`, the order of its items is restored as well. For other bidict types, it may not be: rolling back an overwrite reinserts the overwritten item, which puts it back at the end of the backing mapping rather than in its original position. So a failed update can leave a non-ordered bidict holding exactly the items it held before, but iterating them in a different order: .. doctest:: >>> b = bidict({1: 'one', 2: 'two'}) >>> b.update({1: 'uno', 3: 'two'}) # (1, 'uno') is applied, then (3, 'two') fails Traceback (most recent call last): ... bidict.ValueDuplicationError: two >>> b # the contents are restored... bidict({1: 'one', 2: 'two'}) >>> b.inverse # ...but the inverse is no longer in its original order: bidict({'two': 2, 'one': 1}) This is the same caveat described in :ref:`other-bidict-types:Order consistency between bidicts and their inverses`, applied to updates that fail rather than updates that succeed: if you need a bidict whose order is meaningful, use an :class:`~bidict.OrderedBidict`. Order Matters +++++++++++++ Performing a bulk insert operation – i.e. passing multiple items to :meth:`~bidict.BidictBase.__init__`, :meth:`~bidict.MutableBidict.update`, :meth:`~bidict.MutableBidict.forceupdate`, or :meth:`~bidict.MutableBidict.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 is significant to the result. For example, let's try calling `~bidict.MutableBidict.forceupdate` with a list of three items that duplicate some keys and values already in an initial bidict: .. doctest:: >>> b = bidict({0: 0, 1: 2}) >>> b.forceupdate({ ... 2: 0, # (2, 0) overwrites (0, 0) -> bidict({2: 0, 1: 2}) ... 0: 1, # (0, 1) is added -> bidict({2: 0, 1: 2, 0: 1}) ... 0: 0, # (0, 0) overwrites (0, 1) and (2, 0) -> bidict({1: 2, 0: 0}) ... }) >>> b bidict({1: 2, 0: 0}) Now let's do the exact same thing, but with a different order of the items that we pass to :meth:`~bidict.MutableBidict.forceupdate`: .. doctest:: >>> b = bidict({0: 0, 1: 2}) # as above >>> b.forceupdate({ ... # same items as above, different order: ... 0: 1, # (0, 1) overwrites (0, 0) -> bidict({0: 1, 1: 2}) ... 0: 0, # (0, 0) overwrites (0, 1) -> bidict({0: 0, 1: 2}) ... 2: 0, # (2, 0) overwrites (0, 0) -> bidict({1: 2, 2: 0}) ... }) >>> b # different items! bidict({1: 2, 2: 0}) Of course, if you try to initialize or update a bidict with an iterable that yields items in a nondeterministic order, the results will vary accordingly. .. [#fn-fail-clean] Albeit with the extremely important advantage of :ref:`failing clean `. Interop +++++++ :class:`~bidict.bidict`\s 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: .. doctest:: >>> dict(bidict(a=1)) {'a': 1} >>> bidict(dict(a=1)) bidict({'a': 1}) (Just remember that if there were any :ref:`duplicate values ` in the dict passed to :class:`~bidict.bidict`, it would trigger a :class:`~bidict.ValueDuplicationError`.) See the :ref:`other-bidict-types:Polymorphism` section for more interoperability documentation. ---- Proceed to :doc:`other-bidict-types` for documentation on the remaining bidict variants. bidict-0.24.1/docs/changelog.rst000077700000000000000000000000001524342314000206722../CHANGELOG.rstustar00rootroot00000000000000bidict-0.24.1/docs/code-of-conduct.rst000077700000000000000000000000001524342314000227022../CODE_OF_CONDUCT.rstustar00rootroot00000000000000bidict-0.24.1/docs/conf.py000066400000000000000000000210731524342314000152640ustar00rootroot00000000000000# Copyright 2009-2026 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 importlib.util from importlib.metadata import metadata # -- General configuration ------------------------------------------------ # suppress_warnings = [ # ] # 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 custom ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.autosectionlabel', 'sphinx.ext.coverage', 'sphinx.ext.doctest', 'sphinx.ext.extlinks', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode', ] if importlib.util.find_spec('sphinx_copybutton'): extensions.append('sphinx_copybutton') intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} # 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' bidict_metadata = metadata('bidict') # bidict must be on PYTHONPATH (e.g. installed) project = bidict_metadata['Name'] # Extract author name from "Name " format author_email = bidict_metadata['Author-email'] author = author_email.split('<')[0].strip() if author_email else 'Joshua Bronson' copyright = f'2009-2026 {author}' # ruff: ignore[builtin-variable-shadowing] # Sphinx requires this name # 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_metadata['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 = 'colorful' # 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 = 'furo' # 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. # https://pradyunsg.me/furo/customisation/#theme-options # html_theme_options = dict( # ) # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = 'bidict' # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = 'bidict' # 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 = [] # https://docs.readthedocs.io/en/stable/guides/adding-custom-css.html#adding-custom-css-or-javascript-to-sphinx-documentation # html_css_files = ['custom.css'] html_js_files = ['custom.js'] # 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. # https://pradyunsg.me/furo/customisation/sidebar/#using-html-sidebars html_sidebars = { '**': [ 'sidebar/brand.html', 'sidebar/search.html', 'sidebar/scroll-start.html', 'sidebar/navigation.html', 'sidebar/scroll-end.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' # https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html extlinks = { 'issue': ('https://github.com/jab/bidict/issues/%s', '#%s'), } # Ignore urls matching these regex strings when doing "make linkcheck" linkcheck_ignore = [ r'https://codecov\.io/.*', # gives 405 for HEAD requests r'https://pypistats\.org/.*', # unreliable # alternative links for readers on GitHub (which don't work on readthedocs.io): r'docs/learning-from-bidict\.rst', r'CHANGELOG\.rst', r'docs/intro\.rst', r'CONTRIBUTING\.rst', r'CODE_OF_CONDUCT\.rst', ] linkcheck_timeout = 10 # 5s default too low nitpicky = True nitpick_ignore_regex = [ # work around https://github.com/sphinx-doc/sphinx/issues/10974 ('py:(class|obj)', r'(bidict\._typing\.)?(KT|VT|DT|Maplike|MapOrItems|MissingT)'), ('py:class', r'(bidict\._base\.)?BT'), ('py:class', r't\.(Any|ClassVar|MutableMapping)'), ] # http://www.sphinx-doc.org/en/stable/ext/autosectionlabel.html#configuration autosectionlabel_prefix_document = True # https://www.sphinx-doc.org/en/3.x/usage/extensions/autodoc.html#confval-autodoc_typehints autodoc_typehints = 'description' # pytest-sphinx does not support doctest_global_setup. We use conftest.py instead. # Ref: https://github.com/thisch/pytest-sphinx/issues/5#issuecomment-618072237 # doctest_global_setup = """""" # https://sphinx-copybutton.readthedocs.io/en/latest/#strip-and-configure-input-prompts-for-code-cells copybutton_prompt_text = '>>> ' bidict-0.24.1/docs/conftest.py000066400000000000000000000016221524342314000161620ustar00rootroot00000000000000# Copyright 2009-2026 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/. from __future__ import annotations import sys import typing as t from collections.abc import Mapping from collections.abc import MutableMapping import pytest import bidict # https://github.com/thisch/pytest-sphinx/issues/5#issuecomment-618072237 @pytest.fixture(autouse=True) def _add_doctest_globals(doctest_namespace: MutableMapping[str, t.Any]) -> None: doctest_namespace['Mapping'] = Mapping doctest_namespace['MutableMapping'] = MutableMapping doctest_namespace['pypy'] = sys.implementation.name == 'pypy' doctest_namespace['sys'] = sys doctest_namespace.update(i for i in vars(bidict).items() if not i[0].startswith('_')) bidict-0.24.1/docs/contributors-guide.rst000077700000000000000000000000001524342314000232132../CONTRIBUTING.rstustar00rootroot00000000000000bidict-0.24.1/docs/extending.rst000066400000000000000000000213741524342314000165100ustar00rootroot00000000000000Extending ``bidict`` -------------------- Bidict was written with extensibility in mind. Let's look at some examples. ``YoloBidict`` Recipe ##################### If you'd like :attr:`~bidict.ON_DUP_DROP_OLD` to be the default :class:`~bidict.BidictBase.on_dup` behavior (for :meth:`~bidict.BidictBase.__init__`, :meth:`~bidict.MutableBidict.__setitem__`, and :meth:`~bidict.MutableBidict.update`), you can use the following recipe: .. doctest:: >>> from bidict import bidict, ON_DUP_DROP_OLD >>> class YoloBidict(bidict): ... on_dup = ON_DUP_DROP_OLD >>> b = YoloBidict({'one': 1}) >>> b['two'] = 1 # succeeds, no ValueDuplicationError >>> b YoloBidict({'two': 1}) >>> b.update({'three': 1}) # ditto >>> b YoloBidict({'three': 1}) Of course, ``YoloBidict``'s inherited :meth:`~bidict.MutableBidict.put` and :meth:`~bidict.MutableBidict.putall` methods still allow specifying a custom :class:`~bidict.OnDup` per call via the *on_dup* argument, and will both still default to raising for all duplication types. Further demonstrating :mod:`bidict`'s extensibility, to make an ``OrderedYoloBidict``, the class above can simply inherit from :class:`bidict.OrderedBidict` rather than :class:`bidict.bidict`. Beware of ``ON_DUP_DROP_OLD`` ::::::::::::::::::::::::::::: There's a good reason that :mod:`bidict` does not provide a ``YoloBidict`` out of the box. Before you decide to use a ``YoloBidict`` in your own code, beware of the following potentially unexpected, dangerous behavior: .. doctest:: >>> b = YoloBidict({'one': 1, 'two': 2}) # b contains two items >>> b['one'] = 2 # update one of the items >>> b # now b only has one item! YoloBidict({'one': 2}) As covered in :ref:`basic-usage:collapsing overwrites`, setting an existing key to the value of a different existing item causes both existing items to quietly collapse into a single new item. The opposite customization would look something like: .. doctest:: >>> from bidict import ON_DUP_RAISE >>> class YodoBidict(bidict): # yodo: you only die once! ... on_dup = ON_DUP_RAISE >>> b = YodoBidict({'one': 1}) >>> b['one'] = 2 # Unlike a regular bidict, YodoBidict won't allow this. Traceback (most recent call last): ... bidict.KeyDuplicationError: one >>> b YodoBidict({'one': 1}) >>> b.forceput('one', 2) # Any type of overwrite requires more force. >>> b YodoBidict({'one': 2}) ``WeakrefBidict`` Recipe ######################## Suppose you need to store some objects in a bidict without incrementing their refcounts. With :class:`~bidict.BidictBase`\'s :attr:`~bidict.BidictBase._fwdm_cls` (forward mapping class) and :attr:`~bidict.BidictBase._invm_cls` (inverse mapping class) attributes, accomplishing this is as simple as: .. doctest:: >>> from bidict import MutableBidict >>> from weakref import WeakKeyDictionary, WeakValueDictionary >>> class WeakrefBidict(MutableBidict): ... _fwdm_cls = WeakKeyDictionary ... _invm_cls = WeakValueDictionary Now you can insert items into *WeakrefBidict* without incrementing their refcounts: .. doctest:: >>> b = WeakrefBidict() >>> o1, o2 = frozenset({1}), frozenset({2}) >>> b[o1] = o2 Since o1 and o2 are the only strong references to these objects, if you delete these references, the refcounts will go to zero and the objects will immediately be deallocated on CPython, since the *WeakrefBidict* isn't holding on to them: .. use `:skipif: pypy` for the test below once https://github.com/thisch/pytest-sphinx/issues/9 is fixed .. doctest:: >>> del o1, o2 # after this, b immediately becomes empty on CPython: >>> if sys.implementation.name == 'cpython': ... assert not b ``SortedBidict`` 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. Using these, along with :class:`~bidict.BidictBase`'s :attr:`~bidict.BidictBase._fwdm_cls` (forward mapping class) and :attr:`~bidict.BidictBase._invm_cls` (inverse mapping class) attributes, creating a sorted bidict is simple: .. doctest:: >>> from sortedcontainers import SortedDict >>> 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 = SortedDict ... _invm_cls = SortedDict >>> b = SortedBidict({'Tokyo': 'Japan', 'Cairo': 'Egypt'}) >>> b SortedBidict({'Cairo': 'Egypt', 'Tokyo': 'Japan'}) >>> b['Lima'] = 'Peru' >>> list(b.items()) # stays sorted by key [('Cairo', 'Egypt'), ('Lima', 'Peru'), ('Tokyo', 'Japan')] >>> list(b.inverse.items()) # .inverse stays sorted by *its* keys (b's values) [('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:: >>> from sortedcollections import ValueSortedDict >>> class KeySortedBidict(MutableBidict): ... _fwdm_cls = SortedDict ... _invm_cls = ValueSortedDict >>> elem_by_atomicnum = KeySortedBidict({ ... 6: 'carbon', 1: 'hydrogen', 2: 'helium'}) >>> list(elem_by_atomicnum.items()) # stays sorted by key [(1, 'hydrogen'), (2, 'helium'), (6, 'carbon')] >>> list(elem_by_atomicnum.inverse.items()) # .inverse stays sorted by value [('hydrogen', 1), ('helium', 2), ('carbon', 6)] >>> elem_by_atomicnum[4] = 'beryllium' >>> list(elem_by_atomicnum.inverse.items()) [('hydrogen', 1), ('helium', 2), ('beryllium', 4), ('carbon', 6)] Automatic "Get Attribute" Pass-Through ###################################### Python makes it easy to customize a class's "get attribute" behavior. You can take advantage of this to pass attribute access through to the backing ``_fwdm`` mapping when an attribute is not provided by the bidict class itself: >>> def __getattribute__(self, name): ... try: ... return object.__getattribute__(self, name) ... except AttributeError: ... return getattr(self._fwdm, name) >>> KeySortedBidict.__getattribute__ = __getattribute__ Now, even though this ``KeySortedBidict`` itself provides no ``peekitem`` attribute, you can still call ``peekitem`` on it and it will return the result of calling ``peekitem`` on the backing ``SortedDict``: >>> elem_by_atomicnum.peekitem() (6, 'carbon') Dynamic Inverse Class Generation ################################ When a bidict class's :attr:`~bidict.BidictBase._fwdm_cls` and :attr:`~bidict.BidictBase._invm_cls` are the same, the bidict class is its own inverse class. (This is the case for all the :ref:`bidict classes ` that come with :mod:`bidict`.) However, when a bidict's :attr:`~bidict.BidictBase._fwdm_cls` and :attr:`~bidict.BidictBase._invm_cls` differ, as in the ``KeySortedBidict`` and ``WeakrefBidict`` recipes above, the inverse class of the bidict needs to have its :attr:`~bidict.BidictBase._fwdm_cls` and :attr:`~bidict.BidictBase._invm_cls` swapped. :class:`~bidict.BidictBase` detects this and dynamically computes the correct inverse class for you automatically. You can see this if you inspect ``KeySortedBidict``'s inverse bidict: >>> elem_by_atomicnum.inverse.__class__.__name__ 'KeySortedBidictInv' Notice that :class:`~bidict.BidictBase` automatically created a ``KeySortedBidictInv`` class and used it for the inverse bidict. As expected, ``KeySortedBidictInv``'s :attr:`~bidict.BidictBase._fwdm_cls` and :attr:`~bidict.BidictBase._invm_cls` are the opposite of ``KeySortedBidict``'s: >>> elem_by_atomicnum.inverse._fwdm_cls.__name__ 'ValueSortedDict' >>> elem_by_atomicnum.inverse._invm_cls.__name__ 'SortedDict' :class:`~bidict.BidictBase` also ensures that round trips work as expected: >>> KeySortedBidictInv = elem_by_atomicnum.inverse.__class__ # i.e. a value-sorted bidict >>> atomicnum_by_elem = KeySortedBidictInv(elem_by_atomicnum.inverse) >>> atomicnum_by_elem KeySortedBidictInv({'hydrogen': 1, 'helium': 2, 'beryllium': 4, 'carbon': 6}) >>> KeySortedBidict(atomicnum_by_elem.inverse) == elem_by_atomicnum True ----- This all goes to show how simple it can be to compose your own bidirectional mapping types out of the building blocks that :mod:`bidict` provides. bidict-0.24.1/docs/index.rst000066400000000000000000000003631524342314000156250ustar00rootroot00000000000000.. toctree:: :hidden: intro basic-usage other-bidict-types extending other-functionality addendum changelog api learning-from-bidict contributors-guide thanks code-of-conduct .. include:: ../README.rst bidict-0.24.1/docs/intro.rst000066400000000000000000000123131524342314000156470ustar00rootroot00000000000000Introduction ============ The :mod:`bidict` library provides several friendly, efficient data structures for working with `bidirectional mappings `__ in Python. bidict.bidict ------------- :class:`bidict.bidict` is the main bidirectional mapping data structure provided. It allows looking up the value associated with a key, just like a :class:`dict`: .. doctest:: >>> element_by_symbol = bidict({'H': 'hydrogen'}) >>> element_by_symbol['H'] 'hydrogen' But it also allows looking up the key associated with a value, via the special :attr:`~bidict.BidictBase.inverse` attribute: .. doctest:: >>> element_by_symbol.inverse['hydrogen'] 'H' The :attr:`~bidict.BidictBase.inverse` attribute actually references the entire inverse bidirectional mapping: .. doctest:: >>> element_by_symbol bidict({'H': 'hydrogen'}) >>> element_by_symbol.inverse bidict({'hydrogen': 'H'}) ...which is automatically kept in sync as the original mapping is updated: .. doctest:: >>> element_by_symbol['H'] = 'hydrogène' >>> element_by_symbol.inverse bidict({'hydrogène': 'H'}) If you're used to working with :class:`dict`\s, you'll feel right at home using :mod:`bidict`: >>> dir(element_by_symbol) [..., '__getitem__', ..., '__setitem__', ..., 'items', 'keys', ...] Familiar, concise, 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 :mod:`bidict`? One answer is better ergonomics for maintaining a correct representation. For example, to get the correct length, you'd have to take the number reported by :func:`len` and cut it in half. But now consider what happens when we need to store a new association, and we try to do so naively: .. code-block:: python el_by_sym = {'H': 'hydrogen', 'hydrogen': 'H'} # Later we need to associate 'H' with a different value el_by_sym.update({'H': 'hydrogène', 'hydrogène': 'H'} # Too naive Here is what we're left with: .. code-block:: python # el_by_sym: {'H': 'hydrogène', 'hydrogène': 'H', 'hydrogen': 'H'} Oops. We forgot to look up whether the key and value we wanted to set already had any previous associations and remove them as necessary. In general, if we want to store the association *k* ⟷ *v*, but we may have already stored the associations *k* ⟷ *v′* or *k′* ⟷ *v*, a correct implementation using the single-dict approach would require code like this: .. doctest:: >>> d = {'H': 'hydrogen', 'hydrogen': 'H'} >>> def update(d, key, val): ... oldval = d.pop(key, object()) ... d.pop(oldval, None) ... oldkey = d.pop(val, object()) ... d.pop(oldkey, None) ... d.update({key: val, val: key}) >>> update(d, 'H', 'hydrogène') >>> d == {'H': 'hydrogène', 'hydrogène': 'H'} True With :mod:`bidict`, we can instead just write: .. doctest:: >>> b = bidict({'H': 'hydrogen'}) >>> b['H'] = 'hydrogène' And :mod:`bidict` takes care of all the fussy details, leaving us with just what we wanted: .. doctest:: >>> b bidict({'H': 'hydrogène'}) >>> b.inverse bidict({'hydrogène': 'H'}) 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 the single-dict approach: >>> set(d.keys()) == {'H', 'hydrogène'} # .keys() also gives values True >>> set(d.values()) == {'H', 'hydrogène'} # .values() also gives keys True >>> # ...to using a bidict: >>> b.keys() == {'H'} # just the keys True >>> b.values() == {'hydrogène'} # just the values True In short, to model a bidirectional mapping correctly and unambiguously, 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 :mod:`bidict` does under the hood, abstracting it into a clean and ergonomic interface. :mod:`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` and :class:`~bidict.OrderedBidict`. These and :mod:`bidict`'s other functionality will be covered in later sections. But first, let's look at a few more details of :doc:`basic-usage`. bidict-0.24.1/docs/learning-from-bidict.rst000066400000000000000000000447031524342314000205200ustar00rootroot00000000000000Learning from ``bidict`` ------------------------ Working on bidict has taken me to some of the most interesting and unexpected places I've gotten to visit in many years of programming. (When I started this project 20 years ago, I'd never heard of things like higher-kinded types. Thanks to bidict, I not only learned about them, I got to `share a practical example with Guido `__ where they would be beneficial for Python.) The problem space that bidict inhabits is abundant with beautiful symmetries, delightful surprises, and rich opportunities to come up with elegant solutions. You can check out bidict's source to see for yourself. I've sought to optimize the code not just for correctness and performance, but also for clarity, maintainability, and to make for an enjoyable read. See below for more, and feel free to let me know what you think. I hope reading bidict's code brings you some of the `joy `__ that bidict has brought me. Code structure ============== :class:`~bidict.bidict`\s come in mutable, immutable, and ordered variants, 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 specialized optimizations) has been one of the most fun parts of working on bidict. To see how this is done, check out the code starting with `__init__.py `__, and then follow the path suggested in the "code review nav" comments at the top of the file: - `_base.py `__ - `_frozen.py `__ - `_bidict.py `__ - `_orderedbase.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 real-world usage, with practical concerns at top of mind. ``OrderedBidict``\'s design =========================== A regular :class:`~bidict.bidict` encapsulates two regular dicts, keeping them in sync to preserve the bidirectional mapping invariants. How should we extend this to implement :class:`~bidict.OrderedBidict`? From :class:`~bidict.BidictBase`, :class:`~bidict.OrderedBidictBase` inherits the use of two regular dicts to store the contents of the forward and inverse items. To store the *ordering* of the items, we use a doubly-linked list (much like :class:`~collections.OrderedDict`), allowing us to e.g. move any item to the front of the bidict in constant time. Interestingly, the nodes of the linked list encode only the ordering of the items; the nodes themselves contain no key or value data. An additional backing mapping associates the key/value data with the nodes, providing the final piece of the puzzle. And since the implementation needs to not only look up nodes by key/value, but also key/value by node, we use a :class:`~bidict.bidict` for this internally. Bidicts all the way down! Python syntax hacks =================== bidict :issue:`used to <19>` support 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') # [normal] syntax for the forward mapping lookup: element_by_symbol['H'] # ==> 'hydrogen' # [:slice] syntax for the inverse lookup (no longer supported): element_by_symbol[:'hydrogen'] # ==> 'H' See `this code `__ for how this was implemented. It's super cool when you find a way to bend Python's syntax to support new use cases like this that still feel like they fit well into the language, especially given that Python (wisely) limits how much you can customize its syntax. Property-based testing is incredible ==================================== When your automated tests run, are they only checking the test cases that you happened to think of when writing your tests? How do you know you aren't missing some important edge cases? With property-based testing, you describe the _types_ of the test case inputs that your APIs accept, along with the properties that should hold for all valid inputs. Rather than having to think of your test case inputs manually and hard-code them into your test suite, they get generated for you dynamically, in much greater quantity and diversity than you would typically come up with by hand. This dramatically increases test coverage and confidence that your code is correct with much less actual test code. 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. Check out `bidict's property-based tests `__ to see this in action. Python surprises ================ - What should happen when checking equality of several ordered mappings that contain the same items but in a different order? First let's see how :class:`collections.OrderedDict` works. The results may surprise you: .. doctest:: >>> from collections import OrderedDict >>> x = OrderedDict({1: 1, 2: 2}) >>> y = {1: 1, 2: 2} >>> z = OrderedDict({2: 2, 1: 1}) >>> x == y True >>> y == z True >>> x == z # !!! False So :class:`collections.OrderedDict` violates the `transitive property of equality `__. This can lead to some even more unusual behavior than the above. As an example, let's see what would happen if ``bidict.frozenbidict.__eq__()`` behaved this way: .. doctest:: >>> class BadFrozenBidict(BidictBase): ... __hash__ = frozenbidict.__hash__ ... ... def __eq__(self, other): # (deliberately simplified) ... # Override to be order-sensitive, like collections.OrderedDict: ... return all(i == j for (i, j) in zip(self.items(), other.items())) >>> x = BadFrozenBidict({1: 1, 2: 2}) >>> y = frozenbidict({1: 1, 2: 2}) >>> z = BadFrozenBidict({2: 2, 1: 1}) >>> x == y True >>> y == z True >>> x == z # !!! False >>> set1 = {x, y, z} >>> len(set1) 2 >>> set2 = {y, x, z} >>> len(set2) # !!! 1 According to Raymond Hettinger, the Python core developer who built Python's collections foundation, :class:`collections.OrderedDict`\'s ``__eq__()`` implementation should have been order-insensitive. Making it order-sensitive violates the transitive property of equality as well as the `Liskov substitution principle `__. It's too late now to change this for :class:`collections.OrderedDict`. But at least it's not too late to learn from this. Hence :ref:`eq-order-insensitive`, even for ordered bidicts. For an order-sensitive equality check, bidict provides the separate :meth:`~bidict.BidictBase.equals_order_sensitive` method, thanks to Raymond's advice. - See :ref:`addendum:\*nan\* as a Key`. - See :ref:`addendum:Equivalent but distinct \:class\:\`~collections.abc.Hashable\`\\s`. Better memory usage through ``__slots__`` ========================================= Using :ref:`slots` speeds up attribute access, and can dramatically reduce memory usage in CPython when creating many instances of the same class. As an example, the ``Node`` class used internally (in the linked list that backs :class:`~bidict.OrderedBidictBase`) uses slots for better performance at scale, since there are as many node instances kept in memory as there are items in every ordered bidict in memory. *See:* `_orderedbase.py `__ Note that extra care must be taken when using slots with pickling and weakrefs; see the code for more. Better memory usage through ``weakref`` ======================================= A :class:`~bidict.bidict` and its inverse use :mod:`weakref` to :ref:`avoid creating a reference cycle `. As a result, when you drop your last reference to a bidict, its memory is reclaimed immediately in CPython rather than having to wait for the next garbage collection. *See:* `_base.py `__ As another example, the ``Node`` class used internally by :class:`~bidict.OrderedBidictBase` uses weakrefs to avoid creating reference cycles in the doubly-linked lists used to encode the ordering of inserted items. *See:* `_orderedbase.py `__ Using descriptors for managed attributes ======================================== To abstract the details of creating and dereferencing the weakrefs that :class:`~bidict.OrderedBidictBase`\'s aforementioned doubly-linked list nodes use to refer to their neighbor nodes, a ``WeakAttr`` descriptor is used to `manage access to these attributes automatically `__. *See:* `_orderedbase.py `__ The implicit ``__class__`` reference ==================================== Anytime you have to reference the exact class of an instance (and not a potential subclass) from within a method body, you can use the implicit, lexically-scoped ``__class__`` reference rather than hard-coding the current class's name. *See:* https://docs.python.org/3/reference/datamodel.html#executing-the-class-body Subclassing ``namedtuple`` classes ================================== To get the performance benefits, intrinsic sortability, etc. of :class:`~typing.NamedTuple` (or :func:`~collections.namedtuple`) while customizing behavior, API, etc., you can subclass. See the *OnDup* class in `_dup.py `__ for an example. Here's another example: .. 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().__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 ``namedtuple``-style dynamic class generation ============================================= See the `implementation `__ of ``namedbidict`` (it was since removed due to low usage). 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. ``setdefault()``, ``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, ``__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`? - Override :meth:`~abc.ABCMeta.__subclasshook__` to check for the interface you require. - 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 you needed to derive from a second metaclass? 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 you must either explicitly subclass them (in which case you inherit their concrete method implementations) or use :meth:`abc.ABCMeta.register` (to register as a virtual subclass without inheriting any of the implementation). - Notice that Python provides :class:`collections.abc.Reversible` but no ``collections.abc.Ordered`` or ``collections.abc.OrderedMapping``. *See:* ``__ - See the `Zen of Python `__ for how to make APIs Pythonic. The following Zen of Python guidelines have been particularly influential for bidict: - "Errors should never pass silently. Unless explicitly silenced. - "In the face of ambiguity, refuse the temptation to guess." - "Readability counts." - "There should be one – and preferably only one – obvious way to do it." 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. - 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.frozenbidict`: its ``__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()``.) - See also ``__ - 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. 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. - Overriding :meth:`object.__getattribute__` for custom attribute lookup. See :ref:`extending:\`\`SortedBidict\`\` 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 =========== - CPython vs. PyPy (and other Python implementations) - See https://doc.pypy.org/en/latest/cpython_differences.html - gc / weakref - Hence ``test_bidicts_freed_on_zero_refcount()`` in `test_properties.py `__ is skipped outside CPython. - primitives' identities, nan, etc. - Python 2 vs. Python 3 - As affects bidict, mostly :class:`dict` API changes, but also functions like :func:`zip`, :func:`map`, :func:`filter`, etc. - :meth:`~object.__ne__` fixed in Python 3 - 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`` 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` - See :ref:`addendum:Missing \`\`bidict\`\`\\s in the Standard Library` Tools ===== See the :ref:`Thanks ` page for some of the fantastic tools for software verification, performance, code quality, etc. that bidict has provided a great opportunity to learn and use. bidict-0.24.1/docs/other-bidict-types.rst000066400000000000000000000243521524342314000202410ustar00rootroot00000000000000Other ``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. 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`. As you can see above, :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: 'frozenbidict' object does not support item assignment :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 :class:`~bidict.OrderedBidict` ------------------------------ :class:`bidict.OrderedBidict` is a :class:`~bidict.MutableBidirectionalMapping` that preserves the insertion order of its items, and offers some additional ordering-related APIs not offered by the plain bidict type. 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 = element_by_symbol.items() >>> last_item ('Be', 'beryllium') .. _extra-order-sensitive-apis: Extra order-sensitive APIs ++++++++++++++++++++++++++ Additional, efficiently-implemented, order-sensitive APIs are provided as well, following the example of :class:`~collections.OrderedDict`. Namely, :class:`~bidict.OrderedBidict` provides constant-time implementations of :meth:`popitem(last: bool) ` and :meth:`move_to_end(last: bool) `, which make ordered bidicts suitable to use for things like FIFO queues and LRU caches. .. 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'}) .. _eq-order-insensitive: :meth:`~bidict.OrderedBidict`\'s ``__eq__()`` is order-insensitive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ To ensure that ``==`` comparison for any bidict always upholds the `transitive property of equality `__ and the `Liskov substitution principle `__, equality tests between a bidict and another mapping are always order-insensitive, even for ordered bidicts: .. doctest:: >>> o1 = OrderedBidict({1: 1, 2: 2}) >>> o2 = OrderedBidict({2: 2, 1: 1}) >>> o1 == o2 True For order-sensitive equality tests, use :meth:`~bidict.BidictBase.equals_order_sensitive`: .. doctest:: >>> o1.equals_order_sensitive(o2) False (Note that this improves on the behavior of ``collections.OrderedDict.__eq__()``. For more about this, see :ref:`learning-from-bidict:Python surprises`.) What about order-preserving dicts? ++++++++++++++++++++++++++++++++++ In CPython 3.6+ and all versions of PyPy, :class:`dict` preserves insertion order. Since bidicts are built on top of dicts, can we get away with using a plain bidict in places where you need an order-preserving bidirectional mapping? (Assuming we don't need the :ref:`extra-order-sensitive-apis`.) Let's look at some examples. Order consistency between bidicts and their inverses ++++++++++++++++++++++++++++++++++++++++++++++++++++ Consider the following: .. doctest:: >>> b = bidict({1: -1, 2: -2, 3: -3}) >>> b[2] = 'UPDATED' >>> b bidict({1: -1, 2: 'UPDATED', 3: -3}) So far so good, but look what happens to the inverse: .. doctest:: >>> b.inverse bidict({-1: 1, -3: 3, 'UPDATED': 2}) After the mutation, the ordering of the items in the plain bidict is no longer consistent with its inverse. To ensure that ordering is kept consistent between a bidict and its inverse, no matter how it's mutated, you have to use an ordered bidict: .. doctest:: >>> ob = OrderedBidict({1: -1, 2: -2, 3: -3}) >>> ob[2] = 'UPDATED' >>> ob OrderedBidict({1: -1, 2: 'UPDATED', 3: -3}) >>> ob.inverse # better: OrderedBidict({-1: 1, 'UPDATED': 2, -3: 3}) Preserving insertion order of items even after key changes ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Another way that ordered bidicts differ from plain bidicts is that you can change the *key* of an existing item, and its order will still be preserved. Let's look at an example: .. doctest:: >>> bi = bidict({1: -1}) >>> ob = OrderedBidict({1: -1}) >>> bi.forceupdate({2: -2, 3: -1}) >>> ob.forceupdate({2: -2, 3: -1}) This update changes the key of the existing item with value -1. In the ordered bidict, this change is performed in-place, preserving the insertion order. The item with value -1 was the first item inserted, and it remains the first item even after the update: >>> ob OrderedBidict({3: -1, 2: -2}) In the plain bidict, however, the changed item has now been moved to the end: >>> bi bidict({2: -2, 3: -1}) Note that if you insert an item that changes the key of one existing item and the value of another existing item, the behavior described in :ref:`basic-usage:collapsing overwrites` still applies. Trade-offs ++++++++++ Like plain bidicts (and plain dicts too, for that matter), ordered bidicts take *O(n)* space. But to preserve insertion order, as well as implement the :ref:`extra-order-sensitive-apis` in constant time, it costs :class:`~bidict.OrderedBidict` a higher constant factor in its *O(n)* space complexity. If you depend on preserving insertion order, an unordered bidict may be sufficient if: * you'll never mutate it (in which case, use a :class:`~bidict.frozenbidict`), or: * you only mutate by removing and/or adding whole new items, never changing just the key or value of an existing item, or: * you are okay with inconsistent ordering between a bidict and its inverse after changing the key or value of an existing item, as well as with items moving to the end when you change their key rather than being changed in place. That said, if your code depends on the ordering, using an :class:`~bidict.OrderedBidict` makes for clearer code, and ensures that insertion order will be preserved no matter what mutations you perform. The :ref:`extra-order-sensitive-apis` that :class:`~bidict.OrderedBidict` gives you also expand the range of use cases where your bidict would be suitable, as mentioned above. Reversing a bidict ------------------ All provided bidict types are reversible (since they are backed by dicts, which are themselves reversible on all supported Python versions as of CPython 3.8+). .. doctest:: >>> b = bidict({1: 'one', 2: 'two', 3: 'three'}) >>> list(reversed(b)) [3, 2, 1] >>> list(reversed(b.items())) # keys/values/items views are reversible too [(3, 'three'), (2, 'two'), (1, 'one')] Polymorphism ------------ Code that needs to check only whether an object is *dict-like* should not use ``isinstance(obj, dict)``. This check is too specific, because dict-like objects need not actually be instances of dict or a dict subclass. You can see this for many dict-like objects in the standard library: .. doctest:: >>> from collections import ChainMap >>> chainmap = ChainMap() >>> isinstance(chainmap, dict) False The same is true for all the bidict types: .. doctest:: >>> bi = bidict() >>> isinstance(bi, dict) False A better way to check whether an object is dict-like is to use the :class:`~collections.abc.Mapping` abstract base class (ABC) from the :mod:`collections.abc` module, which provides a number of ABCs intended for this purpose: .. doctest:: >>> isinstance(chainmap, Mapping) True >>> isinstance(bi, Mapping) True Also note that the proper way to check whether an object is a mutable mapping is to use the :class:`~collections.abc.MutableMapping` ABC: .. doctest:: >>> isinstance(chainmap, MutableMapping) True >>> isinstance(bi, MutableMapping) True To illustrate this, here's an example of how you can combine the above with bidict's own :class:`~bidict.BidirectionalMapping` ABC to implement your own check for whether an object is an immutable bidirectional mapping: .. doctest:: >>> def is_immutable_bimap(obj): ... return ( ... isinstance(obj, BidirectionalMapping) ... and not isinstance(obj, MutableMapping)) >>> is_immutable_bimap(bidict()) False >>> is_immutable_bimap(frozenbidict()) True For more you can do with :mod:`bidict`, check out :doc:`extending` next. bidict-0.24.1/docs/other-functionality.rst000066400000000000000000000016071524342314000205270ustar00rootroot00000000000000Other 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: .. doctest:: >>> dict(inverted(bidict({1: 'one'}))) {'one': 1} >>> list(inverted(OrderedBidict({2: 4, 3: 9}))) [(4, 2), (9, 3)] bidict-0.24.1/docs/thanks.rst000066400000000000000000000037571524342314000160200ustar00rootroot00000000000000Thanks ------ Bidict has benefited from the assistance of many people and projects. People ====== - Gregory Ewing for the name. - Terry Reedy for suggesting the slice syntax (it was fun while it lasted). - Raymond Hettinger for providing feedback on the design and implementation, and (most of all) for the amazing work on Python's built-in collections that made bidict possible. - 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. - Zac Hatfield-Dodds for the amazing work (as well as soliciting feedback) on `Hypothesis `__, `Hypofuzz `__, and `Pytest `__. - Harrison Goldstein for building `Tyche `__ and showing me how to use it. - Daniel Pope, Leif Walsh, David Turner, Itamar Turner-Trauring, and Michael Arntzenius for suggestions, code reviews, and design discussion. - Jozef Knaperek for the bugfix. - Igor Nehoroshev for contributing the py.typed marker. - Bernát Gábor for pyproject.toml support. - Richard Sanger, Zeyi Wang, Brian Maissy, and Amol Sahsrabudhe for reporting bugs. Projects ======== - `Python `__ - `GitHub `__ - `Tidelift `__ - `Pytest `__ - `Hypothesis `__ - `Tyche `__ - `Pytest-Benchmark `__ - `Coverage `__ - `Codecov `__ - `Sphinx `__ - `Readthedocs `__ - `ty `__ - `ruff `__ - `prek `__ bidict-0.24.1/flake.lock000066400000000000000000000026701524342314000147730ustar00rootroot00000000000000{ "nodes": { "flake-utils": { "inputs": { "systems": "systems" }, "locked": { "lastModified": 1731533236, "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { "owner": "numtide", "repo": "flake-utils", "type": "github" } }, "nixpkgs": { "locked": { "lastModified": 1783081925, "narHash": "sha256-CtXGh9RHsbGiXDljN3C8hOA18phgOJx3ZIQqmPSMHIE=", "owner": "NixOS", "repo": "nixpkgs", "rev": "d1143607239da8ffdee02379643f74cd3e4733c5", "type": "github" }, "original": { "owner": "NixOS", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { "flake-utils": "flake-utils", "nixpkgs": "nixpkgs" } }, "systems": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", "owner": "nix-systems", "repo": "default", "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", "type": "github" }, "original": { "owner": "nix-systems", "repo": "default", "type": "github" } } }, "root": "root", "version": 7 } bidict-0.24.1/flake.nix000066400000000000000000000075631524342314000146470ustar00rootroot00000000000000{ description = "bidict"; inputs = { flake-utils.url = "github:numtide/flake-utils"; nixpkgs.url = "github:NixOS/nixpkgs"; }; outputs = { self, flake-utils, nixpkgs }: flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; }; lib = pkgs.lib; # TODO: Change to pkgs.python315 once we pick up a stable release: latestPython = pkgs.python314; commonTools = with pkgs; [prek uv]; supportedPythons = with pkgs; [ python315 python314 python313 python312 python311 pypy3 ]; mkPathPrefix = packages: ''export PATH="${lib.makeBinPath packages}:$PATH"''; mkUvShellHook = { packages, python ? null, projectEnv ? null, syncArgs ? null, activate ? false, extraShellHook ? "", }: lib.concatStringsSep "\n" ( lib.filter (line: line != "") [ (mkPathPrefix packages) (if projectEnv != null then ''export UV_PROJECT_ENVIRONMENT="${projectEnv}"'' else "") (if python != null then ''export UV_PYTHON="${python.interpreter}"'' else "") (if python != null then ''export UV_PYTHON_DOWNLOADS=never'' else "") (if syncArgs != null then "uv sync ${syncArgs}" else "") extraShellHook (if activate && projectEnv != null then ''source "$UV_PROJECT_ENVIRONMENT/bin/activate"'' else "") ] ); mkUvShell = { python, projectEnv ? null, syncArgs ? null, activate ? false, extraPackages ? [], extraShellHook ? "", }: let packages = commonTools ++ [python] ++ extraPackages; in pkgs.mkShell { inherit packages; shellHook = mkUvShellHook { inherit packages python projectEnv syncArgs activate extraShellHook; }; }; mkTestShell = { python, projectEnv }: mkUvShell { inherit python projectEnv; syncArgs = "--only-group=test"; activate = true; extraShellHook = '' uv pip install --python "$UV_PROJECT_ENVIRONMENT/bin/python" --no-deps -e . ''; }; in { devShells = { default = let packages = commonTools ++ supportedPythons; in pkgs.mkShell { inherit packages; shellHook = mkUvShellHook { inherit packages; python = latestPython; projectEnv = ".venv"; activate = true; extraShellHook = '' ./init_dev_env ''; }; }; benchmark = mkUvShell { python = latestPython; projectEnv = ".venv-benchmark"; syncArgs = "--only-group=test"; activate = true; }; build = mkUvShell { python = pkgs.python313; }; lint = pkgs.mkShell { packages = with pkgs; [prek]; shellHook = mkPathPrefix [pkgs.prek]; }; test311 = mkTestShell { python = pkgs.python311; projectEnv = ".venv-test-3.11"; }; test312 = mkTestShell { python = pkgs.python312; projectEnv = ".venv-test-3.12"; }; test313 = mkTestShell { python = pkgs.python313; projectEnv = ".venv-test-3.13"; }; test314 = mkTestShell { python = pkgs.python314; projectEnv = ".venv-test-3.14"; }; test315 = mkTestShell { python = pkgs.python315; projectEnv = ".venv-test-3.15"; }; testPyPy311 = mkTestShell { python = pkgs.pypy3; projectEnv = ".venv-test-pypy3.11"; }; update_deps = mkUvShell { python = latestPython; }; }; }); } bidict-0.24.1/init_dev_env000077500000000000000000000011671524342314000154360ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright 2009-2026 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/. # shellcheck disable=SC1091 set -euo pipefail declare -r hint="Hint: Use 'nix develop' to bootstrap a development environment" for cmd in uv prek; do if ! command -v "$cmd" >/dev/null 2>&1; then >&2 echo "Error: No '$cmd' on PATH. $hint" exit 1 fi done prek install -f uv sync --all-groups echo "Development virtualenv initialized" bidict-0.24.1/microbenchmarks.py000066400000000000000000000403771524342314000165660ustar00rootroot00000000000000# Copyright 2009-2026 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/. """Microbenchmarks. Uses https://pytest-benchmark.readthedocs.io/en/v4.0.0/pedantic.html which pairs well with ../cachegrind.py (as used by ../.github/workflows/benchmark.yml). """ from __future__ import annotations import pickle import typing as t from collections import deque from functools import partial import pytest import bidict consume: t.Any = partial(deque, maxlen=0) #: Rounds per benchmark. The reported figure is the min over these, so that one unlucky #: sample cannot dominate a result. pedantic() defaults to a single round, i.e. no filtering. ROUNDS = 5 #: Iterations per round for an operation too cheap to time on its own. Running this suite #: under Cachegrind puts a fixed floor of roughly 25us on a single timed call -- three orders #: of magnitude more than e.g. a lookup costs -- so unless the operation is repeated within #: the round, the result is nearly all floor and carries no signal. Only valid for operations #: that can be repeated without fresh setup. CHEAP_ITERATIONS = 1000 #: Roughly how many items a single round should process, for operations whose cost scales #: with the number of items. See :func:`scaled_iterations`. TARGET_ITEMS_PER_ROUND = 20_000 def scaled_iterations(n: int) -> int: """Iterations per round for an operation whose cost scales with *n*. Keeps the work done per round roughly constant across sizes, so that the smallest sizes clear the measurement floor described above without making the largest ones slow. """ return max(1, TARGET_ITEMS_PER_ROUND // n) #: Writes performed per timed call by the single-item write benchmarks below. #: #: Those benchmarks cannot use `iterations`: each needs a bidict in a known state, setup runs #: once per round rather than once per iteration, and repeating a write would not exercise the #: same path the second time. That left one write per timed call, which at roughly a microsecond #: is far under the floor above, so the reported figure was nearly all floor. Batching this many #: writes into a single timed call lifts them clear of it, at a fraction of what raising `rounds` #: to the same effect would cost, since the per-round setup copies the whole bidict. #: #: They therefore measure the cost of a run of writes rather than of one in isolation. For the #: smaller sizes the batch consumes most of the contained items, so the bidict grows or shrinks #: appreciably during it -- which is representative, and identical across the revisions being #: compared, so it does not affect what the comparison means. WRITES_PER_ROUND = 1_000 def scaled_writes(n: int) -> int: """How many writes the single-item write benchmarks perform per timed call, for size *n*. Capped by *n*, since some of them consume a distinct contained item per write. """ return min(n, WRITES_PER_ROUND) LENS = (100, 1_000, 10_000) DATASET_NAMES = ('int', 'str') INT_DICTS_BY_LEN: dict[int, dict[int, int]] = {n: {i: i for i in range(n)} for n in LENS} STR_DICTS_BY_LEN: dict[int, dict[str, str]] = {n: {f'key{i}': f'value{i}' for i in range(n)} for n in LENS} DICTS_BY_KIND_AND_LEN: dict[str, dict[int, dict[t.Any, t.Any]]] = { 'int': INT_DICTS_BY_LEN, 'str': STR_DICTS_BY_LEN, } BIDICTS_BY_KIND_AND_LEN: dict[str, dict[int, bidict.bidict[t.Any, t.Any]]] = { kind: {n: bidict.bidict(other) for n, other in dicts_by_len.items()} for kind, dicts_by_len in DICTS_BY_KIND_AND_LEN.items() } LOOKUP_ITEMS_BY_KIND_AND_LEN: dict[str, dict[int, tuple[t.Any, t.Any]]] = { kind: {n: next(iter(other.items())) for n, other in dicts_by_len.items()} for kind, dicts_by_len in DICTS_BY_KIND_AND_LEN.items() } INT_BIDICTS_BY_LEN: dict[int, bidict.bidict[int, int]] = t.cast( 'dict[int, bidict.bidict[int, int]]', BIDICTS_BY_KIND_AND_LEN['int'], ) ORDERED_BIDICTS_BY_LEN: dict[int, bidict.OrderedBidict[int, int]] = { n: bidict.OrderedBidict(INT_DICTS_BY_LEN[n]) for n in LENS } INT_DICTS_BY_LEN_DUPVAL_EARLY: dict[int, dict[int, int]] = { n: dict([(0, 0), (1, 0), *((i, i) for i in range(2, n))]) for n in LENS } INT_DICTS_BY_LEN_DUPVAL_LATE: dict[int, dict[int, int]] = {n: {**INT_DICTS_BY_LEN[n], n - 1: 0} for n in LENS} # One batch of items per single-item write benchmark, sized by scaled_writes(). Every item in # a batch takes the same path through the code as the others, so the batch measures that path. #: New keys and new values: no duplication. SETITEM_NEW_ITEMS_BY_LEN: dict[int, list[tuple[int, int]]] = { n: [(-i, -i) for i in range(1, scaled_writes(n) + 1)] for n in LENS } SETITEM_NEW_RESULTS_BY_LEN: dict[int, dict[int, int]] = { n: INT_DICTS_BY_LEN[n] | dict(SETITEM_NEW_ITEMS_BY_LEN[n]) for n in LENS } #: Contained keys paired with new values: key duplication. SETITEM_REPLACE_ITEMS_BY_LEN: dict[int, list[tuple[int, int]]] = { n: [(n - i, -i) for i in range(1, scaled_writes(n) + 1)] for n in LENS } SETITEM_REPLACE_RESULTS_BY_LEN: dict[int, dict[int, int]] = { n: INT_DICTS_BY_LEN[n] | dict(SETITEM_REPLACE_ITEMS_BY_LEN[n]) for n in LENS } #: New keys paired with contained values: value duplication, collapsing an item each time. FORCEPUT_ITEMS_BY_LEN: dict[int, list[tuple[int, int]]] = { n: [(-i, i - 1) for i in range(1, scaled_writes(n) + 1)] for n in LENS } FORCEPUT_RESULTS_BY_LEN: dict[int, dict[int, int]] = { n: {k: v for k, v in INT_DICTS_BY_LEN[n].items() if k >= scaled_writes(n)} | dict(FORCEPUT_ITEMS_BY_LEN[n]) for n in LENS } POP_KEYS_BY_LEN: dict[int, list[int]] = {n: [n - i for i in range(1, scaled_writes(n) + 1)] for n in LENS} POP_RESULTS_BY_LEN: dict[int, dict[int, int]] = { n: {k: v for k, v in INT_DICTS_BY_LEN[n].items() if k not in set(POP_KEYS_BY_LEN[n])} for n in LENS } PARTIAL_OVERLAP_UPDATES_BY_LEN: dict[int, dict[int, int]] = { n: {i: i for i in range(n // 2, n + (n // 2))} for n in LENS } PARTIAL_OVERLAP_RESULTS_BY_LEN: dict[int, dict[int, int]] = { n: (INT_DICTS_BY_LEN[n] | PARTIAL_OVERLAP_UPDATES_BY_LEN[n]) for n in LENS } BIDICT_AND_DICT_LAST_TWO_ITEMS_DIFFERENT_ORDER: dict[int, tuple[bidict.bidict[int, int], dict[int, int]]] = {} ORDERED_BIDICT_AND_DICT_LAST_TWO_ITEMS_DIFFERENT_ORDER: dict[ int, tuple[bidict.OrderedBidict[int, int], dict[int, int]] ] = {} for _i in LENS: _bi = INT_BIDICTS_BY_LEN[_i] _d = dict(_bi) _last, _secondlast = _d.popitem(), _d.popitem() _d[_last[0]] = _last[1] # new second-last _d[_secondlast[0]] = _secondlast[1] # new last BIDICT_AND_DICT_LAST_TWO_ITEMS_DIFFERENT_ORDER[_i] = (_bi, _d) ORDERED_BIDICT_AND_DICT_LAST_TWO_ITEMS_DIFFERENT_ORDER[_i] = ( bidict.OrderedBidict(_bi), _d, ) def _setitem(bi: bidict.bidict[int, int], items: list[tuple[int, int]], _expected: dict[int, int]) -> None: for key, val in items: bi[key] = val def _forceput(bi: bidict.bidict[int, int], items: list[tuple[int, int]], _expected: dict[int, int]) -> None: for key, val in items: bi.forceput(key, val) def _update(bi: bidict.bidict[int, int], other: dict[int, int], _expected: dict[int, int]) -> None: bi.update(other) def _failing_update(bi: bidict.bidict[int, int], other: dict[int, int], _expected: dict[int, int]) -> None: with pytest.raises(bidict.DuplicationError): bi.update(other) def _pop(bi: bidict.bidict[int, int], keys: list[int], _expected: dict[int, int]) -> None: for key in keys: bi.pop(key) def _assert_mapping_matches(*args: t.Any) -> None: assert dict(args[0]) == args[-1] def _setup_setitem_new(n: int) -> tuple[tuple[t.Any, ...], dict[str, t.Any]]: return ((INT_BIDICTS_BY_LEN[n].copy(), SETITEM_NEW_ITEMS_BY_LEN[n], SETITEM_NEW_RESULTS_BY_LEN[n]), {}) def _setup_setitem_replace_existing_key(n: int) -> tuple[tuple[t.Any, ...], dict[str, t.Any]]: return ((INT_BIDICTS_BY_LEN[n].copy(), SETITEM_REPLACE_ITEMS_BY_LEN[n], SETITEM_REPLACE_RESULTS_BY_LEN[n]), {}) def _setup_forceput_existing_value(n: int) -> tuple[tuple[t.Any, ...], dict[str, t.Any]]: return ((INT_BIDICTS_BY_LEN[n].copy(), FORCEPUT_ITEMS_BY_LEN[n], FORCEPUT_RESULTS_BY_LEN[n]), {}) def _setup_pop(n: int) -> tuple[tuple[t.Any, ...], dict[str, t.Any]]: return ((INT_BIDICTS_BY_LEN[n].copy(), POP_KEYS_BY_LEN[n], POP_RESULTS_BY_LEN[n]), {}) def _setup_update_partial_overlap(n: int) -> tuple[tuple[t.Any, ...], dict[str, t.Any]]: return ( ( INT_BIDICTS_BY_LEN[n].copy(), PARTIAL_OVERLAP_UPDATES_BY_LEN[n], PARTIAL_OVERLAP_RESULTS_BY_LEN[n], ), {}, ) def _setup_failing_update_early(n: int) -> tuple[tuple[t.Any, ...], dict[str, t.Any]]: return ( ( INT_BIDICTS_BY_LEN[n].copy(), INT_DICTS_BY_LEN_DUPVAL_EARLY[n], INT_DICTS_BY_LEN[n], ), {}, ) def _setup_failing_update_late(n: int) -> tuple[tuple[t.Any, ...], dict[str, t.Any]]: return ( ( INT_BIDICTS_BY_LEN[n].copy(), INT_DICTS_BY_LEN_DUPVAL_LATE[n], INT_DICTS_BY_LEN[n], ), {}, ) @pytest.mark.parametrize('kind', DATASET_NAMES) @pytest.mark.parametrize('n', LENS) def test_bi_init_from_dict(kind: str, n: int, benchmark: t.Any) -> None: """Benchmark initializing a new bidict from a dict.""" other = DICTS_BY_KIND_AND_LEN[kind][n] benchmark.pedantic(bidict.bidict, args=(other,), rounds=ROUNDS, iterations=scaled_iterations(n)) @pytest.mark.parametrize('n', LENS) def test_bi_init_from_bi(n: int, benchmark: t.Any) -> None: """Benchmark initializing a bidict from another bidict.""" other = INT_BIDICTS_BY_LEN[n] benchmark.pedantic(bidict.bidict, args=(other,), rounds=ROUNDS, iterations=scaled_iterations(n)) @pytest.mark.parametrize('n', LENS) def test_bi_init_fail_early_dupval(n: int, benchmark: t.Any) -> None: """Benchmark failing initialization when a duplicate value appears near the start.""" other = INT_DICTS_BY_LEN_DUPVAL_EARLY[n] def failing_init() -> None: with pytest.raises(bidict.DuplicationError): bidict.bidict(other) benchmark.pedantic(failing_init, rounds=ROUNDS, iterations=scaled_iterations(n)) @pytest.mark.parametrize('n', LENS) def test_bi_init_fail_late_dupval(n: int, benchmark: t.Any) -> None: """Benchmark failing initialization when a duplicate value appears at the end.""" other = INT_DICTS_BY_LEN_DUPVAL_LATE[n] def failing_init() -> None: with pytest.raises(bidict.DuplicationError): bidict.bidict(other) benchmark.pedantic(failing_init, rounds=ROUNDS, iterations=scaled_iterations(n)) @pytest.mark.parametrize('kind', DATASET_NAMES) @pytest.mark.parametrize('n', LENS) def test_bi_getitem_present(kind: str, n: int, benchmark: t.Any) -> None: """Benchmark forward lookup of an existing key.""" bi = BIDICTS_BY_KIND_AND_LEN[kind][n] key, val = LOOKUP_ITEMS_BY_KIND_AND_LEN[kind][n] result = benchmark.pedantic(bi.__getitem__, args=(key,), rounds=ROUNDS, iterations=CHEAP_ITERATIONS) assert result == val @pytest.mark.parametrize('kind', DATASET_NAMES) @pytest.mark.parametrize('n', LENS) def test_bi_inverse_getitem_present(kind: str, n: int, benchmark: t.Any) -> None: """Benchmark inverse lookup of an existing value.""" bi = BIDICTS_BY_KIND_AND_LEN[kind][n] key, val = LOOKUP_ITEMS_BY_KIND_AND_LEN[kind][n] result = benchmark.pedantic(bi.inverse.__getitem__, args=(val,), rounds=ROUNDS, iterations=CHEAP_ITERATIONS) assert result == key @pytest.mark.parametrize('n', LENS) def test_bi_setitem_new_item(n: int, benchmark: t.Any) -> None: """Benchmark inserting new items into an existing bidict.""" benchmark.pedantic( _setitem, setup=lambda n=n: _setup_setitem_new(n), teardown=_assert_mapping_matches, rounds=ROUNDS, ) @pytest.mark.parametrize('n', LENS) def test_bi_setitem_replace_existing_key(n: int, benchmark: t.Any) -> None: """Benchmark replacing the values of existing keys with new unique values.""" benchmark.pedantic( _setitem, setup=lambda n=n: _setup_setitem_replace_existing_key(n), teardown=_assert_mapping_matches, rounds=ROUNDS, ) @pytest.mark.parametrize('n', LENS) def test_bi_forceput_existing_value(n: int, benchmark: t.Any) -> None: """Benchmark forceput when each provided value is already associated with another key.""" benchmark.pedantic( _forceput, setup=lambda n=n: _setup_forceput_existing_value(n), teardown=_assert_mapping_matches, rounds=ROUNDS, ) @pytest.mark.parametrize('n', LENS) def test_bi_pop_existing_key(n: int, benchmark: t.Any) -> None: """Benchmark popping existing keys.""" benchmark.pedantic( _pop, setup=lambda n=n: _setup_pop(n), teardown=_assert_mapping_matches, rounds=ROUNDS, ) @pytest.mark.parametrize('n', LENS) def test_bi_update_partial_overlap(n: int, benchmark: t.Any) -> None: """Benchmark updating from a mapping with a mix of overlapping and new items.""" benchmark.pedantic( _update, setup=lambda n=n: _setup_update_partial_overlap(n), teardown=_assert_mapping_matches, rounds=ROUNDS, ) @pytest.mark.parametrize('n', LENS) def test_bi_update_fail_early_dupval(n: int, benchmark: t.Any) -> None: """Benchmark a bulk update that fails near the start and rolls back.""" benchmark.pedantic( _failing_update, setup=lambda n=n: _setup_failing_update_early(n), teardown=_assert_mapping_matches, rounds=ROUNDS, ) @pytest.mark.parametrize('n', LENS) def test_bi_update_fail_late_dupval(n: int, benchmark: t.Any) -> None: """Benchmark a bulk update that fails at the end and rolls back.""" benchmark.pedantic( _failing_update, setup=lambda n=n: _setup_failing_update_late(n), teardown=_assert_mapping_matches, rounds=ROUNDS, ) @pytest.mark.parametrize('n', LENS) def test_bi_iter(n: int, benchmark: t.Any) -> None: """Benchmark iterating over a bidict.""" bi = INT_BIDICTS_BY_LEN[n] # Build the iterator inside the timed callable: one pre-built and passed via args # would already be exhausted by the second of the repeated calls below. benchmark.pedantic(lambda: consume(iter(bi)), rounds=ROUNDS, iterations=scaled_iterations(n)) @pytest.mark.parametrize('n', LENS) def test_orderedbi_iter(n: int, benchmark: t.Any) -> None: """Benchmark iterating over an OrderedBidict.""" ob = ORDERED_BIDICTS_BY_LEN[n] # Build the iterator inside the timed callable: one pre-built and passed via args # would already be exhausted by the second of the repeated calls below. benchmark.pedantic(lambda: consume(iter(ob)), rounds=ROUNDS, iterations=scaled_iterations(n)) @pytest.mark.parametrize('n', LENS) def test_bi_equals_with_equal_dict(n: int, benchmark: t.Any) -> None: """Benchmark bidict.__eq__ with an equivalent dict.""" bi, d = BIDICT_AND_DICT_LAST_TWO_ITEMS_DIFFERENT_ORDER[n] result = benchmark.pedantic(bi.__eq__, args=(d,), rounds=ROUNDS, iterations=scaled_iterations(n)) assert result @pytest.mark.parametrize('n', LENS) def test_orderedbi_items_equals_with_equal_dict_items(n: int, benchmark: t.Any) -> None: """Benchmark OrderedBidict.items().__eq__ with equivalent dict_items.""" ob, d = ORDERED_BIDICT_AND_DICT_LAST_TWO_ITEMS_DIFFERENT_ORDER[n] result = benchmark.pedantic(ob.items().__eq__, args=(d.items(),), rounds=ROUNDS, iterations=scaled_iterations(n)) assert result @pytest.mark.parametrize('n', LENS) def test_copy(n: int, benchmark: t.Any) -> None: """Benchmark creating a copy of a bidict.""" bi = INT_BIDICTS_BY_LEN[n] benchmark.pedantic(bi.copy, rounds=ROUNDS, iterations=scaled_iterations(n)) @pytest.mark.parametrize('n', LENS) def test_pickle(n: int, benchmark: t.Any) -> None: """Benchmark pickling a bidict.""" bi = INT_BIDICTS_BY_LEN[n] benchmark.pedantic(pickle.dumps, args=(bi,), rounds=ROUNDS, iterations=scaled_iterations(n)) @pytest.mark.parametrize('n', LENS) def test_unpickle(n: int, benchmark: t.Any) -> None: """Benchmark unpickling a bidict.""" bp = pickle.dumps(INT_BIDICTS_BY_LEN[n]) benchmark.pedantic(pickle.loads, args=(bp,), rounds=ROUNDS, iterations=scaled_iterations(n)) bidict-0.24.1/pyproject.toml000066400000000000000000000134051524342314000157510ustar00rootroot00000000000000[project] name = "bidict" version = "0.24.1" description = "The bidirectional mapping library for Python." authors = [{ name = "Joshua Bronson", email = "jabronson@gmail.com" }] license = "MPL-2.0" license-files = ["LICENSE"] dependencies = [ # bidict/_typing.py's `typing`/`typing_extensions` imports branch on python<3.12 "typing_extensions>=4.0; python_version<'3.12'", ] requires-python = ">=3.11" readme = "README.rst" keywords = [ "bidict", "bimap", "bidirectional", "dict", "dictionary", "mapping", "collections", ] classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Typing :: Typed", ] [project.urls] # https://github.com/pypi/warehouse/blob/main/warehouse/templates/packaging/detail.html#L20-L62 Changelog = "https://bidict.readthedocs.io/changelog.html" Documentation = "https://bidict.readthedocs.io" Sponsor = "https://bidict.readthedocs.io/#sponsoring" Repository = "https://github.com/jab/bidict" [dependency-groups] test = [ "coverage", "hypothesis", "pytest", "pytest-benchmark", "pytest-sphinx", "pytest-xdist", "sortedcollections", "sortedcontainers", "ty>=0.0.72", "typing_extensions", ] dev = [ "pytest-clarity", "pytest-icdiff", "pytest-sugar", "tox", "tox-uv", ] docs = [ "sphinx", "sphinx-copybutton", "furo", ] [tool.uv] default-groups = ["test", "dev", "docs"] [tool.uv.build-backend] module-root = "" source-exclude = [".mypy_cache"] [build-system] # uv_build, not the uv on PATH, is what writes the wheel's RECORD, and it comes from this pin. # The floor is load-bearing: 0.24.0 shipped hex-encoded RECORD hashes (#406) because the pin # read >=0.7.13,<0.8.0, so it kept resolving uv_build to 0.7.22 long after 0.8.13 fixed them to # be urlsafe-base64 as the spec requires, and 0.7.x got no backport. Keeping the floor at that # fix, rather than raising it in lockstep with the ceiling, means every version this admits # writes a valid RECORD even if the ceiling goes stale again, and leaves distro packagers a # wide range to build the sdist against whatever uv_build they ship. # The ceiling is only change control, and is what uv recommends (it warns without one). Keep it # covering the uv in uv.lock, so `uv build` keeps using that uv's built-in uv_build rather than # downloading one; update_dev_dependencies checks this. requires = ["uv_build>=0.8.13,<0.12"] build-backend = "uv_build" [tool.ty.src] include = ["bidict", "tests"] [tool.ty.terminal] error-on-warning = true [tool.ty.rules] # ty has no `strict`-mode bundle like mypy's; instead, ratchet up the rules that # default to `warn`/`ignore` but that we want enforced as errors. `error-on-warning` # above already makes the `warn`-level rules fatal; the following promote rules that # default to `ignore` (so are otherwise silent even under `error-on-warning`). missing-type-argument = "error" # analogous to mypy's disallow_any_generics missing-override-decorator = "error" # require @override on overriding methods [tool.ruff] preview = true line-length = 121 # Ruff's default rule set grows between minor versions, so an older ruff than the one pinned in # .pre-commit-config.yaml lints with fewer rules and passes code that CI rejects. Fail on that # rather than let it be discovered in CI. ./update_dev_dependencies checks these two stay in step. required-version = ">=0.16.4" [tool.ruff.lint] # https://docs.astral.sh/ruff/rules/ # Whole linters, selected by prefix. Individual rules are selected by name below, since # a name says what it checks where a code does not. extend-select = [ "A", "ARG", "B", "BLE", "E", "F", "FA", "FLY", "FURB", "G", "I", "ICN", "PERF", "PGH", "PIE", "PT", "PTH", "RET", "RSE", "RUF", "SLOT", "T20", "TID", "UP", "W", "YTT", # Individual rules, from linters whose other rules do not suit this codebase: "debugger", "runtime-cast-value", # keeps cast()'s type expression from being evaluated at runtime "unspecified-encoding", # text I/O should not depend on the machine's locale ] ignore = [ "in-dict-keys", # https://github.com/astral-sh/ruff/issues/4481 "non-empty-init-module", # Allow __init__.py to set __module__ on re-exported classes "unaliased-collections-abc-set-import", # Prefer `Set` over `AbstractSet` for readability "useless-import-alias", # Allow explicit re-exports (import X as X) ] # Rules that know about typing should treat what bidict._typing re-exports the same way. typing-modules = ["bidict._typing"] [tool.ruff.lint.per-file-ignores] "cachegrind.py" = ["print"] # printing its results is what this script is for [tool.ruff.lint.isort] force-single-line = true lines-after-imports = 2 [tool.ruff.format] docstring-code-format = true docstring-code-line-length = "dynamic" preview = true quote-style = "single" # Keep the code (especially in the docs' doctests) matching Python's output [tool.pytest] addopts = [ "-vv", "--doctest-modules", "--doctest-glob=docs/*.rst", "--durations=5", "--hypothesis-profile=less-examples", "--numprocesses=auto", # Benchmarks are run separately (see the benchmark tox env and workflow, which # invoke pytest with `-c /dev/null` to bypass this config), so unload # pytest-benchmark here. Otherwise, being installed, it loads on every run and # warns under xdist (which addopts enables above) that it is auto-disabling itself. "-p", "no:benchmark", ] doctest_optionflags = ["ELLIPSIS"] # Treat warnings as errors so deprecations etc. fail the suite instead of going # unnoticed. (The benchmark plugin is unloaded above so its xdist warning # doesn't trip this.) filterwarnings = ["error"] strict = true testpaths = ["bidict", "tests", "docs"] bidict-0.24.1/tests/000077500000000000000000000000001524342314000141745ustar00rootroot00000000000000bidict-0.24.1/tests/bidict_test_fixtures.py000066400000000000000000000272261524342314000210050ustar00rootroot00000000000000# Copyright 2009-2026 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/. from __future__ import annotations import operator import pickle import typing as t from collections import OrderedDict from collections import UserDict from collections.abc import Iterable from collections.abc import KeysView from collections.abc import Mapping from collections.abc import MutableMapping from collections.abc import Reversible from dataclasses import dataclass from itertools import chain from itertools import combinations from bidict import DROP_NEW from bidict import DROP_OLD from bidict import ON_DUP_DROP_OLD from bidict import RAISE from bidict import BidictBase from bidict import DuplicationError from bidict import KeyAndValueDuplicationError from bidict import KeyDuplicationError from bidict import MutableBidirectionalMapping from bidict import OnDup from bidict import OrderedBidict from bidict import OrderedBidictBase from bidict import ValueDuplicationError from bidict import bidict from bidict import frozenbidict from bidict._typing import Maplike from bidict._typing import MapOrItems from bidict._typing import override KT = t.TypeVar('KT') VT = t.TypeVar('VT') class SupportsKeysAndGetItem(t.Generic[KT, VT]): def __init__(self, *args: t.Any, **kw: t.Any) -> None: # This fixture trusts its *args/**kw (typed Any); dict(**kw) yields str keys, so cast to the declared type. self._mapping = t.cast('Mapping[KT, VT]', dict(*args, **kw)) def keys(self) -> KeysView[KT]: return self._mapping.keys() def __getitem__(self, key: KT) -> VT: return self._mapping[key] BB = BidictBase[KT, VT] BT = type[BidictBase[KT, VT]] user_bidict_types: list[BT[t.Any, t.Any]] = [] _B = t.TypeVar('_B', bound=BidictBase[t.Any, t.Any]) _BT = t.TypeVar('_BT', bound=type[BidictBase[t.Any, t.Any]]) def pickle_copy(b: _B, protocol: int | None = None) -> _B: return pickle.loads(pickle.dumps(b, protocol)) def user_bidict(cls: _BT) -> _BT: # Preserve the exact decorated class type (a plain `BT[KT, VT]` return would widen it to BidictBase). user_bidict_types.append(cls) return cls @user_bidict class UserBi(bidict[KT, VT]): _fwdm_cls = UserDict _invm_cls = UserDict @user_bidict class UserOrderedBi(OrderedBidict[KT, VT]): _fwdm_cls = UserDict _invm_cls = UserDict @user_bidict class UserBiNotOwnInv(bidict[KT, VT]): """A custom bidict whose inverse class is not itself.""" _fwdm_cls = dict _invm_cls = UserDict @user_bidict class UserBiBackedByDictSub(bidict[KT, VT]): """A bidict backed by a dict *subclass*, which gets the same native views as a dict.""" _fwdm_cls = OrderedDict _invm_cls = OrderedDict @user_bidict class UserOrderedBiBase(OrderedBidictBase[KT, VT]): """An immutable ordered bidict, i.e. an OrderedBidictBase that is not an OrderedBidict. Uses a permissive on_dup so that even a bulk __init__ can overwrite an existing item. That is what makes the backing mappings' order diverge from the bidict's own order, which is otherwise only reachable by mutating an OrderedBidict. """ on_dup = ON_DUP_DROP_OLD UserBiNotOwnInvInv = UserBiNotOwnInv._inv_cls assert UserBiNotOwnInvInv is not UserBiNotOwnInv BTs = tuple[BT[t.Any, t.Any], ...] builtin_bidict_types: BTs = (bidict, frozenbidict, OrderedBidict) bidict_types: BTs = (*builtin_bidict_types, *user_bidict_types) update_arg_types = (*bidict_types, list, dict, iter, SupportsKeysAndGetItem) mutable_bidict_types: BTs = tuple(t for t in bidict_types if issubclass(t, MutableBidirectionalMapping)) assert frozenbidict not in mutable_bidict_types MBT = type[bidict[KT, VT]] | type[OrderedBidict[KT, VT]] def should_be_reversible(bi_t: BT[KT, VT]) -> bool: # Every ordered bidict is reversible regardless of its backing mappings, since it # iterates its linked list rather than them. Any other bidict is reversible exactly # when both its backing mappings are. if bi_t in builtin_bidict_types or issubclass(bi_t, OrderedBidictBase): return True return all(issubclass(i, Reversible) for i in (bi_t._fwdm_cls, bi_t._invm_cls)) assert all(not should_be_reversible(bi_t) or issubclass(bi_t, Reversible) for bi_t in bidict_types) def powerset(iterable: Iterable[t.Any]) -> Iterable[tuple[t.Any, ...]]: iterable = tuple(iterable) return chain.from_iterable(combinations(iterable, r) for r in range(len(iterable) + 1)) SET_OPS: t.Any = ( operator.le, operator.lt, operator.gt, operator.ge, operator.eq, operator.ne, operator.and_, operator.or_, operator.sub, operator.xor, (lambda x, y: x.isdisjoint(y)), ) DEFAULT_ON_DUP = OnDup(DROP_OLD, RAISE) @dataclass class Oracle(t.Generic[KT, VT]): data: dict[KT, VT] ordered: bool @property def data_inv(self) -> dict[VT, KT]: return {v: k for (k, v) in self.data.items()} def assert_match(self, bi: BidictBase[KT, VT]) -> None: assert dict(bi) == self.data assert dict(bi.inv) == self.data_inv self.assert_items_match(bi) def assert_items_match(self, bi: BidictBase[KT, VT]) -> None: if self.ordered: assert zip_equal(bi.items(), self.data.items()) else: assert bi.items() == self.data.items() def clear(self) -> None: self.data.clear() def pop(self, key: KT) -> VT: return self.data.pop(key) def popitem(self, last: bool = True) -> tuple[KT, VT]: if last: return self.data.popitem() key = next(iter(self.data)) return key, self.data.pop(key) def put(self, key: KT, val: VT, on_dup: OnDup = DEFAULT_ON_DUP) -> None: oldval = self.data.get(key) oldkey = self.data_inv.get(val) isdupkey = oldval is not None isdupval = oldkey is not None if isdupkey and isdupval: if key == oldkey: # (key, val) duplicates an existing item -> no-op assert val == oldval return # key and val each duplicate a different existing item. if on_dup.val is RAISE: raise KeyAndValueDuplicationError(key, val) if on_dup.val is DROP_NEW: return assert on_dup.val is DROP_OLD elif isdupkey: if on_dup.key is RAISE: raise KeyDuplicationError(key) if on_dup.key is DROP_NEW: return assert on_dup.key is DROP_OLD elif isdupval: if on_dup.val is RAISE: raise ValueDuplicationError(val) if on_dup.val is DROP_NEW: return assert on_dup.val is DROP_OLD if not self.ordered: self.data[key] = val self.data.pop(oldkey, None) return # Ensure insertion order is preserved in the case of a sequence of overwriting updates. updated = {} for k, v in self.data.items(): if k == oldkey or v == oldval: if k == oldkey and isdupkey and isdupval: continue updated[key] = val else: updated[k] = v updated[key] = val self.data = updated def putall(self, updates: MapOrItems[KT, VT], on_dup: OnDup = DEFAULT_ON_DUP) -> None: # https://bidict.readthedocs.io/en/main/basic-usage.html#order-matters tmp = self.data.copy() items: Iterable[tuple[KT, VT]] if isinstance(updates, Mapping): items = t.cast('Mapping[KT, VT]', updates).items() elif isinstance(updates, Maplike): items = [(key, updates[key]) for key in updates.keys()] else: items = updates try: for key, val in items: self.put(key, val, on_dup) except DuplicationError: self.data = tmp # fail clean (no partially-applied updates) raise def __ior__(self, other: Mapping[KT, VT]) -> dict[KT, VT]: self.putall(other) return self.data def __or__(self, other: Mapping[KT, VT]) -> dict[KT, VT]: before = self.data.copy() self.putall(other) after = self.data self.data = before return after def __ror__(self, other: Mapping[KT, VT]) -> dict[KT, VT]: before = self.data.copy() self.data = {} try: self.putall(other) self.putall(before) except DuplicationError: self.data = before raise after = self.data self.data = before return after def move_to_end(self, key: KT, last: bool = True) -> None: val = self.pop(key) if last: self.put(key, val) else: self.data = {key: val, **self.data} def zip_equal(i1: Iterable[t.Any], i2: Iterable[t.Any]) -> bool: return all(map(operator.eq, i1, i2)) def invdict(d: dict[KT, VT]) -> dict[VT, KT]: return {v: k for (k, v) in d.items()} def dedup(x: MapOrItems[KT, VT]) -> dict[KT, VT]: return invdict(invdict(dict(x))) @dataclass(frozen=True) class Tagged: """Equal whenever *n* is equal, but each instance is distinguishable by its *tag*. Stands in for the realistic case of value-equal objects that carry distinct state, e.g. a dataclass whose __eq__ covers only some of its fields. """ n: int tag: str = '' @override def __eq__(self, other: object) -> bool: return isinstance(other, Tagged) and self.n == other.n @override def __hash__(self) -> int: return hash(self.n) class HashRaises: @override def __hash__(self) -> int: raise RuntimeError('boom!') bomb = HashRaises() BAD_ITEMS = ( (RuntimeError, (bomb, 0)), # hashing the key raises (RuntimeError, (0, bomb)), # hashing the value raises (TypeError, (['unhashable'], 0)), (ValueError, (1, 2, 'bad len')), ) class WriteRefused(Exception): """Raised by the backing mappings that :func:`bidict_refusing_nth_write` provides.""" def bidict_refusing_nth_write(bi_t: BT[t.Any, t.Any], init: Mapping[t.Any, t.Any], n: int) -> BB[t.Any, t.Any]: """Return a *bi_t* containing *init* whose nth write from now on raises :class:`WriteRefused`. Stands in for a custom bidict's backing mapping that may raise on a write it will not accept, e.g. SortedDict's TypeError when a key is not orderable with the keys already contained. Both backing mappings are given the same class, so the count spans them the way a single _write() does. """ counting = False counter = iter(range(1, 1000)) def tick() -> None: if counting and next(counter) == n: raise WriteRefused class RefusingDict(UserDict[t.Any, t.Any]): @override def __setitem__(self, key: t.Any, item: t.Any) -> None: tick() super().__setitem__(key, item) @override def __delitem__(self, key: t.Any) -> None: tick() super().__delitem__(key) @override def popitem(self) -> tuple[t.Any, t.Any]: # Python 3.15 gave UserDict a popitem() of its own that goes straight to self.data, # bypassing __delitem__ and so escaping the count above. Take MutableMapping's # implementation, which removes via __delitem__ on every supported Python. return MutableMapping.popitem(self) bi_t_refusing = type(f'Refusing{bi_t.__name__}', (bi_t,), {'_fwdm_cls': RefusingDict, '_invm_cls': RefusingDict}) bi = bi_t_refusing(init) counting = True # writing init above must not count return bi bidict-0.24.1/tests/conftest.py000066400000000000000000000013221524342314000163710ustar00rootroot00000000000000# Copyright 2009-2026 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/. from hypothesis import settings # deadline=None because hypothesis times each call in wall-clock, and the first call of any test # can spend a few hundred ms on warm-up that later calls do not, which can trip the 200ms default # when the machine is loaded. settings.register_profile('less-examples', deadline=None, max_examples=200, stateful_step_count=100) settings.register_profile('more-examples', deadline=None, max_examples=500, stateful_step_count=200) bidict-0.24.1/tests/test_bidict.py000066400000000000000000001452071524342314000170540ustar00rootroot00000000000000# Copyright 2009-2026 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/. """Tests for :mod:`bidict`. Mainly these are property-based tests implemented via https://hypothesis.works. """ from __future__ import annotations import gc import pickle import sys import typing as t import weakref from collections import UserDict from collections.abc import Callable from collections.abc import Mapping from collections.abc import Reversible from collections.abc import Sequence from copy import copy from copy import deepcopy from functools import partial from functools import reduce from itertools import product from itertools import starmap from random import Random from typing import assert_type from unittest.mock import ANY import pytest from bidict_test_fixtures import BAD_ITEMS from bidict_test_fixtures import BB from bidict_test_fixtures import BT from bidict_test_fixtures import KT from bidict_test_fixtures import MBT from bidict_test_fixtures import SET_OPS from bidict_test_fixtures import VT from bidict_test_fixtures import Oracle from bidict_test_fixtures import SupportsKeysAndGetItem from bidict_test_fixtures import Tagged from bidict_test_fixtures import UserBi from bidict_test_fixtures import UserBiBackedByDictSub from bidict_test_fixtures import UserBiNotOwnInv from bidict_test_fixtures import UserOrderedBi from bidict_test_fixtures import UserOrderedBiBase from bidict_test_fixtures import WriteRefused from bidict_test_fixtures import bidict_refusing_nth_write from bidict_test_fixtures import bidict_types from bidict_test_fixtures import bomb from bidict_test_fixtures import dedup from bidict_test_fixtures import invdict from bidict_test_fixtures import mutable_bidict_types from bidict_test_fixtures import pickle_copy from bidict_test_fixtures import powerset from bidict_test_fixtures import should_be_reversible from bidict_test_fixtures import update_arg_types from bidict_test_fixtures import zip_equal from hypothesis import assume from hypothesis import example from hypothesis import given from hypothesis import note from hypothesis.stateful import RuleBasedStateMachine from hypothesis.stateful import initialize from hypothesis.stateful import invariant from hypothesis.stateful import precondition from hypothesis.stateful import rule from hypothesis.strategies import booleans from hypothesis.strategies import randoms from hypothesis.strategies import sampled_from from typing_extensions import TypeIs from bidict import BidictKeysView from bidict import BidirectionalMapping from bidict import DuplicationError from bidict import KeyAndValueDuplicationError from bidict import MutableBidict from bidict import MutableBidirectionalMapping from bidict import OnDup from bidict import OnDupAction from bidict import OrderedBidict from bidict import OrderedBidictBase from bidict import ValueDuplicationError from bidict import bidict from bidict import frozenbidict from bidict import inverted from bidict._orderedbase import Node as OrderedBidictNode from bidict._orderedbase import WeakAttr from bidict._typing import MapOrItems from bidict._typing import override Items = Sequence[tuple[int, int]] Items121 = dict[t.Any, t.Any] ks = tuple(range(1, 5)) vs = tuple(range(-1, -5, -1)) keys = sampled_from(ks) vals = sampled_from(vs) items = sampled_from(list(powerset(product(ks, vs)))) items121 = items.map(dedup) # Items that can never duplicate anything in a bidict under test: their keys and values are # disjoint from ks and vs, and they are 1:1 among themselves. fresh_items = sampled_from(list(powerset((k, -k) for k in range(5, 9)))) bidict_t = sampled_from(bidict_types) mut_bidict_t = sampled_from(mutable_bidict_types) updates_t = sampled_from(update_arg_types) on_dups = tuple(starmap(OnDup, product(OnDupAction, repeat=2))) on_dup = sampled_from(on_dups) def is_ordered(bi: BidirectionalMapping[int, int]) -> TypeIs[OrderedBidict[int, int]]: return isinstance(bi, OrderedBidict) class BidictStateMachine(RuleBasedStateMachine): bi: MutableBidict[int, int] oracle: Oracle[int, int] @initialize(mut_bidict_t=mut_bidict_t, items121=items121) def init(self, mut_bidict_t: type[MutableBidict[int, int]], items121: Items121) -> None: self.bi = mut_bidict_t(items121) self.oracle = Oracle(items121, ordered=self.is_ordered()) def is_ordered(self) -> bool: return is_ordered(self.bi) @invariant() def assert_match_oracle(self) -> None: note(f'> {self.bi=}\n> {self.oracle.data=}') self.oracle.assert_match(self.bi) viewnames = sampled_from(('keys', 'values', 'items')) # TODO: Try @invariant rather than @rule now that hypothesis is faster / it might not slow down the tests too much. @rule(rand=randoms(), viewname=viewnames, set_op=sampled_from(SET_OPS), other_set=items.map(frozenset)) def assert_views_match_oracle(self, rand: Random, viewname: str, set_op: t.Any, other_set: t.Any) -> None: check = getattr(self.bi, viewname)() expect = getattr(self.oracle.data, viewname)() if viewname != 'values' else self.oracle.data_inv.keys() assert len(check) == len(expect) if self.is_ordered(): assert zip_equal(check, expect) else: assert check == frozenset(expect) missing = ('foo', 'bar') if viewname == 'items' else 'foo' assert missing not in check if self.oracle.data: contained = rand.choice(tuple(expect)) assert contained in check if viewname != 'items': other_set = {k for (k, _) in other_set} assert_calls_match( partial(set_op, check, other_set), partial(set_op, expect, other_set), ) if viewname == 'items': other_set = self.bi.__class__(dedup(other_set)).items() assert_calls_match( partial(set_op, check, other_set), partial(set_op, expect, other_set), ) @invariant() def assert_bi_and_inv_are_inverse(self) -> None: assert_bi_and_inv_are_inverse(self.bi) @invariant() def assert_values_correspond_to_keys(self) -> None: """values() must correspond elementwise to keys(), as a plain dict's does. Overwriting an item reorders a non-ordered bidict's backing _invm relative to its _fwdm, so a values() view sourced from _invm's keys would silently mispair here. Only reachable by mutating: a bulk __init__ that would cause it raises instead. """ for b in (self.bi, self.bi.inv): assert list(b.values()) == [b[k] for k in b] @precondition(lambda self: should_be_reversible(self.bi.__class__)) @invariant() def assert_reversed_works(self) -> None: assert list(reversed(self.bi)) == list(self.bi)[::-1] items = self.bi.items() assert isinstance(items, Reversible) assert list(reversed(items)) == list(items)[::-1] if self.is_ordered(): assert zip_equal(reversed(self.bi), reversed(self.oracle.data)) assert zip_equal(reversed(items), reversed(self.oracle.data.items())) values = self.bi.values() assert isinstance(values, Reversible) assert zip_equal(reversed(values), reversed(self.oracle.data.values())) @rule() def copy(self) -> None: for cp in (copy(self.bi), deepcopy(self.bi)): assert_bi_and_inv_are_inverse(cp) assert_bidicts_equal(cp, self.bi) @rule() def pickle(self) -> None: for b in (self.bi, self.bi.inv): roundtripped = pickle_copy(b) assert_bi_and_inv_are_inverse(roundtripped) assert_bidicts_equal(roundtripped, b) @rule() def clear(self) -> None: self.bi.clear() self.oracle.clear() @rule(key=keys, val=vals, on_dup=on_dup) def put(self, key: int, val: int, on_dup: OnDup) -> None: assert_calls_match( partial(self.bi.put, key, val, on_dup), partial(self.oracle.put, key, val, on_dup), ) @rule(updates=items, updates_t=updates_t, on_dup=on_dup) def putall(self, updates: MapOrItems[int, int], updates_t: t.Any, on_dup: OnDup) -> None: # Don't let the updates_t(updates) calls below raise a DuplicationError. if isinstance(updates_t, type) and issubclass(updates_t, BidirectionalMapping): updates = dedup(updates) # Since updates_t can be iter, can't extract the two updates_t(updates) calls below into a single value. assert_calls_match( partial(self.bi.putall, updates_t(updates), on_dup), partial(self.oracle.putall, updates_t(updates), on_dup), ) @rule(new=fresh_items, on_dup=on_dup) def putall_with_bad_item(self, new: Items, on_dup: OnDup) -> None: """A bulk update whose last item raises must apply none of it, whatever the on_dup. The preceding items are fresh, so the only thing that can fail is the bad item. Pass an iterator so this always takes the incremental rollback path. """ assert_update_fails_clean(self.bi, iter([*new, (bomb, 0)]), RuntimeError, on_dup) @precondition(is_ordered) @rule(updates=items, on_dup=on_dup) def putall_with_bad_item_after_overwrites(self, updates: Items, on_dup: OnDup) -> None: """An ordered bidict must restore its *order* too, not just its contents. Unlike the rule above this lets the preceding items overwrite existing ones, which is what makes the linked list's order diverge from the backing mappings'. Only ordered bidicts guarantee this: rolling back an overwrite reinserts the overwritten item at the end of a backing mapping rather than in its original position, so a non-ordered bidict is restored contents-only. See "Updates Fail Clean" in the docs. """ arg = iter([*updates, (bomb, 0)]) assert_update_fails_clean(self.bi, arg, (RuntimeError, DuplicationError), on_dup) @rule(other=items121) def __ior__(self, other: Mapping[int, int]) -> None: assert_calls_match( partial(self.bi.__ior__, other), partial(self.oracle.__ior__, other), ) @rule(other=items121) def __or__(self, other: Mapping[int, int]) -> None: assert_calls_match( partial(self.bi.__or__, other), partial(self.oracle.__or__, other), ) # https://bidict.rtfd.io/basic-usage.html#order-matters @precondition(lambda self: zip_equal(self.bi, self.oracle.data)) @rule(other=items121) def __ror__(self, other: Mapping[int, int]) -> None: assert_calls_match( partial(self.bi.__ror__, other), partial(self.oracle.__ror__, other), ) @precondition(lambda self: len(self.bi) >= 2) @rule(random=randoms()) def update_with_dup(self, random: Random) -> None: # Covered nondeterministically by the more general "putall" rule above, but this ensures that basic duplication # scenarios are deterministically covered. # Choose two existing items at random. (k1, v1), (k2, v2) = random.sample(tuple(self.oracle.data.items()), 2) # Inserting (new_key, dup_val) should raise ValueDuplicationError. assert_update_fails_clean(self.bi, [('foo', 'foo'), ('bar', v1)], ValueDuplicationError) # key and value duplication across two different items should raise KeyAndValueDuplicationError. for key, val in ((k1, v2), (k2, v1)): assert_update_fails_clean(self.bi, [('foo', 'foo'), (key, val)], KeyAndValueDuplicationError) # Inserting already-present items should be a no-op. before = self.bi.copy() self.bi.update([(k1, v1), (k2, v2)]) assert self.bi.equals_order_sensitive(before) assert self.bi.inv.equals_order_sensitive(before.inv) def is_empty(self) -> bool: return not self.bi @precondition(is_empty) @rule() def popitem_empty(self) -> None: with pytest.raises(KeyError): self.bi.popitem() def is_nonempty(self) -> bool: return bool(self.bi) @precondition(is_nonempty) @rule(last=booleans(), flip=booleans(), inv=booleans()) def popitem(self, last: bool, inv: bool, flip: bool) -> None: bi, oracle = self.bi, self.oracle if is_ordered(bi): if not inv: expect = oracle.popitem(last=last) check = bi.popitem(last=last) else: expect = oracle.popitem(last=last)[::-1] check = bi.inv.popitem(last=last) assert check == expect assert check not in bi.items() else: fst, snd = (bi, oracle) if flip else (oracle, bi) k, v = fst.popitem() assert snd.pop(k) == v assert (k, v) not in bi.items() @precondition(is_nonempty) @rule(random=randoms()) def pop_randkey(self, random: Random) -> None: key = random.choice(tuple(self.oracle.data)) expect = self.oracle.pop(key) check = self.bi.pop(key) assert check == expect @precondition(is_ordered) @precondition(is_nonempty) @rule(random=randoms(), last=booleans()) def move_to_end_randkey(self, random: Random, last: bool) -> None: assert is_ordered(self.bi) key, val = random.choice(tuple(self.oracle.data.items())) self.bi.move_to_end(key, last=last) self.oracle.move_to_end(key, last=last) it: t.Any = reversed if last else iter assert (key, val) == next(it(self.bi.items())) assert (val, key) == next(it(self.bi.inv.items())) assert (key, val) == next(it(self.oracle.data.items())) assert (val, key) == next(it(self.oracle.data_inv.items())) BidictStateMachineTest = BidictStateMachine.TestCase @pytest.mark.parametrize('bi_t', bidict_types) def test_init_and_update_with_bad_args(bi_t: BT[KT, VT]) -> None: bad_args: t.Any for bad_args in ((None,), (0,), (False,), (True,), ({}, {})): # ty raises on unpacking an `Any`/unknown-length arg into a call; see # https://github.com/astral-sh/ty/issues/3649 with pytest.raises(TypeError): bi_t(*bad_args) # ty: ignore[invalid-argument-type, too-many-positional-arguments] if not issubclass(bi_t, MutableBidict): continue bi = bi_t() with pytest.raises(TypeError): bi.update(*bad_args) # ty: ignore[invalid-argument-type, too-many-positional-arguments] # https://github.com/astral-sh/ty/issues/3649 @pytest.mark.parametrize('bi_t', bidict_types) def test_inv_attrs_readonly(bi_t: BT[KT, VT]) -> None: """Attempting to set .inverse or .inv should raise AttributeError.""" bi: t.Any = bi_t() with pytest.raises(AttributeError): bi.inverse = 'foo' with pytest.raises(AttributeError): bi.inv = 'foo' @pytest.mark.parametrize('bi_t', mutable_bidict_types) def test_pop_missing_key(bi_t: MBT[t.Any, t.Any]) -> None: bi = bi_t() with pytest.raises(KeyError): bi.pop('foo') assert bi.pop('foo', 'bar') == 'bar' @pytest.mark.parametrize('bi_t', [OrderedBidict, UserOrderedBi]) def test_move_to_end_missing_key(bi_t: type[OrderedBidict[KT, VT]]) -> None: bi = bi_t() with pytest.raises(KeyError): bi.move_to_end('foo') # ty: ignore[invalid-argument-type] @pytest.mark.parametrize('bi_t', bidict_types) def test_eq_defers_to_other_eq(bi_t: BT[KT, VT]) -> None: """bidict.__eq__(other) should defer to other.__eq__ when other is not a mapping.""" # ANY.__eq__ always returns true, so this test will fail if bi_t.__eq__ fails to defer. assert bi_t() == ANY @pytest.mark.parametrize(('bi_t', 'non_mapping'), list(product(bidict_types, (None, 1, [], SupportsKeysAndGetItem({}))))) def test_eq_and_or_with_non_mapping(bi_t: BT[KT, VT], non_mapping: t.Any) -> None: bi = bi_t() assert bi != non_mapping assert not bi.equals_order_sensitive(non_mapping) with pytest.raises(TypeError): bi | non_mapping with pytest.raises(TypeError): non_mapping | bi @given(items121=items121, bidict_t=bidict_t, rand=randoms()) def test_equals_order_sensitive(items121: Items121, bidict_t: BT[KT, VT], rand: Random) -> None: # Ensure there are at least 3 items in items121. items121.update({5: -5, 6: -6, 7: -7}) bi = bidict_t(items121) items_shuf = list(items121.items()) rand.shuffle(items_shuf) assume(not zip_equal(items_shuf, items121.items())) map_shuf = dict(items_shuf) assert bi == map_shuf assert not bi.equals_order_sensitive(map_shuf) @given(items=items, bidict_t=bidict_t) def test_inverted(items: Items, bidict_t: BT[int, int]) -> None: check = tuple(inverted(inverted(items))) expect = items assert check == expect items_nodup = dedup(items) check_bi = bidict_t(inverted(bidict_t(items_nodup))) expect_bi = bidict_t({v: k for (k, v) in items_nodup.items()}) assert_bidicts_equal(check_bi, expect_bi) @given(items=items, bidict_t=bidict_t) # Pin the case that actually exercises the divergence, rather than relying on it being # generated: (3, -1) overwrites (1, -1) in place, so an ordered bidict keeps the item's # original position while its backing mappings append the new key and drop the old one. @example(items=((1, -1), (2, -2), (3, -1)), bidict_t=UserOrderedBiBase) def test_views_agree_with_iteration_order(items: Items, bidict_t: BT[int, int]) -> None: """Every order-sensitive API must agree with the bidict's own iteration order. For ordered bidicts the order lives in the linked list, not in the backing mappings, and the two diverge as soon as an item is overwritten -- including during __init__, for a type whose on_dup permits it. So the views must not delegate to _fwdm. """ try: bi = bidict_t(items) except DuplicationError: # this type's on_dup rejects these items; settle for a 1:1 init bi = bidict_t(dedup(items)) expect = [(k, bi[k]) for k in bi] # the items in iteration order, without using items() assert list(bi.keys()) == list(bi) assert list(bi.items()) == expect assert list(dict(bi)) == list(bi) # dict(mapping) goes through keys() assert bi.equals_order_sensitive(bidict_t(expect)) assert list(bi.values()) == [v for (_, v) in expect] assert list(bi.items()) == list(zip(bi.keys(), bi.values(), strict=True)) if should_be_reversible(bidict_t): keysview, itemsview = bi.keys(), bi.items() assert isinstance(keysview, Reversible) assert isinstance(itemsview, Reversible) assert list(reversed(keysview)) == list(bi)[::-1] assert list(reversed(itemsview)) == expect[::-1] @given(items121=items121) def test_frozenbidicts_hashable(items121: Items121) -> None: """Frozen bidicts can be hashed (and therefore inserted into sets and mappings).""" bi = frozenbidict(items121) h1 = hash(bi) h2 = hash(bi) assert h1 == h2 assert {bi} assert {bi: bi} bi2 = frozenbidict(items121) assert bi2 == bi assert hash(bi2) == h1 # These test cases ensure coverage of all branches in [Ordered]BidictBase._undo_write. # (Hypothesis doesn't always generate examples that cover all the branches otherwise.) @pytest.mark.parametrize(('bi_t', 'on_dup'), list(product(mutable_bidict_types, on_dups))) def test_putall_matches_bulk_put(bi_t: type[MutableBidict[int, int]], on_dup: OnDup) -> None: bi = bi_t({0: 0, 1: 1}) for k1, v1, k2, v2 in product(range(4), repeat=4): for b in bi, bi.inv: assert_putall_matches_bulk_put(b, [(k1, v1), (k2, v2)], on_dup) def assert_putall_matches_bulk_put(bi: MutableBidict[int, int], new_items: Items, on_dup: OnDup) -> None: tmp = bi.copy() checkexc = None expectexc = None try: for key, val in new_items: tmp.put(key, val, on_dup) except DuplicationError as exc: expectexc = type(exc) tmp = bi # Since bulk updates fail clean, expect no changes (i.e. revert to bi). try: bi.putall(new_items, on_dup) except DuplicationError as exc: checkexc = type(exc) assert checkexc == expectexc assert bi == tmp assert bi.inv == tmp.inv def assert_update_fails_clean( bi: MutableBidict[t.Any, t.Any], updates: t.Any, exc_t: type[Exception] | tuple[type[Exception], ...], on_dup: OnDup | None = None, ) -> None: """Check that a bulk update that raises *exc_t* leaves *bi* exactly as it was. Exercises update() (i.e. bi's own on_dup) when *on_dup* is None, else putall(). """ before = bi.copy() do_update = partial(bi.update, updates) if on_dup is None else partial(bi.putall, updates, on_dup) with pytest.raises(exc_t): do_update() assert bi.equals_order_sensitive(before) assert bi.inv.equals_order_sensitive(before.inv) # A RAISE-free on_dup must fail clean too: a bulk update can raise for reasons that have # nothing to do with duplication, so rollback cannot be conditioned on on_dup. @pytest.mark.parametrize(('bi_t', 'on_dup'), list(product(mutable_bidict_types, (None, *on_dups)))) def test_update_with_bad_last_item_fails_clean(bi_t: MBT[t.Any, t.Any], on_dup: OnDup | None) -> None: # Keep self at least as large as updates so this sized arg takes the # in-place rollback path rather than the copy fast path. bi = bi_t({ 0: 0, 1: 1, 2: 2, }) for b in (bi, bi.inv): for exc, bad in BAD_ITEMS: # The items before the bad one are all new, so the update fails for the # bad item's reason regardless of the on_dup. updates = [(3, 3), (4, 4), bad] assert_update_fails_clean(b, updates, exc, on_dup) @pytest.mark.parametrize('bi_t', [bidict, OrderedBidict]) @pytest.mark.parametrize( ('init', 'write', 'nwrites'), [ # One case per kind of duplication BidictBase._write() handles, with the number of writes # to the backing mappings it performs: two to insert the new item, plus one to remove each # item that the new one displaces. ({1: 'a'}, lambda b: b.__setitem__(2, 'b'), 2), ({1: 'a'}, lambda b: b.__setitem__(1, 'z'), 3), ({1: 'a'}, lambda b: b.forceput(9, 'a'), 3), ({1: 'a', 2: 'b'}, lambda b: b.forceput(1, 'b'), 4), ], ids=['no-dup', 'dup-key', 'dup-val', 'dup-key-and-val'], ) def test_write_fails_clean_when_a_backing_mapping_refuses( bi_t: MBT[t.Any, t.Any], init: dict[t.Any, t.Any], write: t.Any, nwrites: int ) -> None: """Writing one item must fail clean when a backing mapping refuses part-way through. _write() sets both backing mappings, and for some kinds of duplication deletes from them too. Backing mappings are user-supplied (see _fwdm_cls and _invm_cls), so any one of those writes can be refused, and everything already written must then be undone. """ unchanged = dict(init), invdict(init) refused = 0 for n in range(1, nwrites + 2): # one past the last, which must find nothing left to refuse bi = bidict_refusing_nth_write(bi_t, init, n) try: write(bi) except WriteRefused: refused += 1 assert (dict(bi._fwdm), dict(bi._invm)) == unchanged, f'refusing write #{n} left bi changed' else: break assert refused == nwrites @pytest.mark.parametrize('bi_t', [bidict, OrderedBidict]) @pytest.mark.parametrize( ('remove', 'nwrites'), [ # Removing an item takes two writes whichever way it is asked for: one to each # backing mapping. (lambda b: b.__delitem__(1), 2), (lambda b: b.pop(1), 2), (lambda b: b.popitem(), 2), ], ids=['delitem', 'pop', 'popitem'], ) def test_remove_fails_clean_when_a_backing_mapping_refuses(bi_t: MBT[t.Any, t.Any], remove: t.Any, nwrites: int) -> None: """Removing an item must fail clean when a backing mapping refuses part-way through. The removing counterpart of test_write_fails_clean_when_a_backing_mapping_refuses: removing from one backing mapping and then being refused by the other must not leave the two disagreeing. """ init = {1: 'a', 2: 'b'} unchanged = dict(init), invdict(init) refused = 0 for n in range(1, nwrites + 2): # one past the last, which must find nothing left to refuse bi = bidict_refusing_nth_write(bi_t, init, n) try: remove(bi) except WriteRefused: refused += 1 assert (dict(bi._fwdm), dict(bi._invm)) == unchanged, f'refusing write #{n} left bi changed' else: break assert refused == nwrites @pytest.mark.parametrize('bi_t', mutable_bidict_types) @pytest.mark.parametrize('roundtrip', [copy, deepcopy, pickle_copy], ids=['copy', 'deepcopy', 'pickle']) def test_roundtrip_preserves_iteration_order(bi_t: MBT[t.Any, t.Any], roundtrip: t.Any) -> None: """Duplicating a bidict must preserve its own iteration order. An ordered bidict preserves its inverse's order too, since both read the same linked list. A non-ordered one does not: its inverse gets rebuilt by inverting the forward mapping, which leaves it in the forward mapping's order -- the same thing that happens whenever a bidict is built from items, and the reason to reach for an OrderedBidict when order matters. """ bi = bi_t({1: -1, 2: -2, 3: -3}) bi.forceput(4, -2) # a value-duplicating overwrite, which skews the inverse's order cp = roundtrip(bi) assert cp.equals_order_sensitive(bi) if isinstance(bi, OrderedBidictBase): assert cp.inv.equals_order_sensitive(bi.inv) def test_pickle_preserves_order_of_generated_inverse_class() -> None: """An instance of a dynamically-generated inverse class keeps its own order. Such a class used to have no name pickle could reference it by, so __reduce__ pickled an instance of the class it was generated from and reconstructed this one by inverting, which left the order of the object being pickled derived rather than recorded. It is now pickled by reference like any other class (see _make_inv_cls), so the items are this object's own. """ b: MutableBidict[t.Any, t.Any] = UserBiNotOwnInv() b.forceupdate([(1, 'a'), (2, 'b'), (3, 'a')]) # the last item skews the inverse's order inv = b.inverse assert list(inv.items()) == [('a', 3), ('b', 2)] roundtripped = pickle_copy(inv) assert type(roundtripped) is type(inv) assert roundtripped.equals_order_sensitive(inv) def test_pickling_costs_no_extra_space() -> None: """Preserving the order must not have made pickles bigger. Recording the inverse's key order alongside the forward mapping would: measured at up to 150% more space, or ~10% more time once conditioned on actually being needed. Making the generated class referenceable instead costs neither, since only the forward items are ever written. """ bi = bidict({i: -i for i in range(1000)}) assert len(pickle.dumps(bi)) < len(pickle.dumps(dict(bi))) * 1.1 def test_pickle_orderedbi_whose_order_disagrees_with_fwdm() -> None: """An OrderedBidict whose order does not match its _fwdm's should pickle with the correct order.""" ob = OrderedBidict({0: 1, 2: 3}) # First get ob._fwdm's order to disagree with ob's: ob.inv[1] = 4 assert list(ob.items()) == [(4, 1), (2, 3)] assert list(ob._fwdm.items()) == [(2, 3), (4, 1)] # Now check that its order is preserved after pickling and unpickling: roundtripped = pickle_copy(ob) assert list(roundtripped.items()) == [(4, 1), (2, 3)] assert roundtripped.equals_order_sensitive(ob) def test_pickle_dynamically_generated_inverse_bidict() -> None: """Instances of dynamically-generated inverse bidict classes should be pickleable.""" ub: MutableBidict[str, int] = UserBiNotOwnInv(one=1, two=2) roundtripped = pickle_copy(ub) assert roundtripped == ub == UserBiNotOwnInv({'one': 1, 'two': 2}) assert dict(roundtripped) == dict(ub) # Now for the inverse: assert repr(ub.inverse) == "UserBiNotOwnInvInv({1: 'one', 2: 'two'})" # We can still pickle the inverse, even though its class, UserBiNotOwnInvInv, was # dynamically generated, and we didn't save a reference to it named "UserBiNotOwnInvInv" # anywhere that pickle could find it in sys.modules: for protocol in range(2, pickle.HIGHEST_PROTOCOL + 1): ubinv = pickle_copy(ub.inverse, protocol) assert repr(ubinv) == "UserBiNotOwnInvInv({1: 'one', 2: 'two'})" assert ub._inv_cls.__name__ not in (name for m in sys.modules for name in dir(m)) # What pickle finds it by instead is its __qualname__, which spells out the attribute of # UserBiNotOwnInv that it is reachable through. Check that that lookup resolves back to it. assert ub._inv_cls.__qualname__ == 'UserBiNotOwnInv._inv_cls' module = sys.modules[ub._inv_cls.__module__] assert reduce(getattr, ub._inv_cls.__qualname__.split('.'), module) is ub._inv_cls def test_abstract_bimap_init_fails() -> None: class AbstractBimap(BidirectionalMapping[t.Any, t.Any]): """Does not override `inverse` and therefore should not be instantiable.""" for bi_t in (BidirectionalMapping, MutableBidirectionalMapping, AbstractBimap): with pytest.raises(TypeError, match="Can't instantiate abstract class"): bi_t() def test_bimap_bad_inverse() -> None: # Overrides `inverse`, but merely calls the abstract superclass implementation. class BimapBadInverse(BidirectionalMapping[t.Any, t.Any]): __getitem__ = __iter__ = __len__ = ... @property @override def inverse(self) -> t.Any: return super().inverse bi = BimapBadInverse() with pytest.raises(NotImplementedError): bi.inverse # ruff: ignore[useless-expression] # evaluating it is the point: it must raise skip_if_pypy = pytest.mark.skipif( sys.implementation.name == 'pypy', reason='Requires CPython refcounting behavior', ) @skip_if_pypy @given(bidict_t=bidict_t) def test_bidicts_freed_on_zero_refcount(bidict_t: BT[KT, VT]) -> None: """On CPython, the moment you have no more (strong) references to a bidict, there are no remaining (internal) strong references to it (i.e. no reference cycle was created between it and its inverse), allowing the memory to be reclaimed immediately, even with GC disabled. """ gc.disable() try: bi = bidict_t() weak = weakref.ref(bi) assert weak() is not None del bi assert weak() is None finally: gc.enable() @skip_if_pypy @given(items121=items121) def test_orderedbidict_nodes_freed_on_zero_refcount(items121: Items121) -> None: """On CPython, the moment you have no more references to an ordered bidict, the refcount of each of its internal nodes drops to 0 (i.e. the linked list of nodes does not create a reference cycle), allowing the memory to be reclaimed immediately. """ gc.disable() try: ob = OrderedBidict(items121) nodes = weakref.WeakSet(ob._sntl.iternodes()) assert len(nodes) == len(ob) del ob assert len(nodes) == 0 finally: gc.enable() @given(items121=items121) def test_orderedbidict_nodes_consistent(items121: Items121) -> None: """The nodes in an ordered bidict's backing linked list should be the same as those in its backing mapping.""" ob = OrderedBidict(items121) mapnodes = set(ob._node_by_korv.inverse) linkedlistnodes = set(ob._sntl.iternodes()) assert mapnodes == linkedlistnodes def test_dict_subclass_backing_gets_native_views() -> None: """A backing mapping that is a dict subclass should get the same views a dict would. keys()/items() dispatch on isinstance(fwdm, dict) rather than `fwdm_cls is dict`, so a dict subclass -- which is what every backing in the docs' recipes actually is, e.g. sortedcontainers.SortedDict -- gets its own native views. Those are reversible, carry a .mapping attribute, and implement their set operations in C, none of which a generic view over the bidict provides. """ b = UserBiBackedByDictSub({1: 'one', 2: 'two'}) # backed by OrderedDict keysview, itemsview = b.keys(), b.items() assert not isinstance(keysview, BidictKeysView) # the backing's own view, not a fallback assert isinstance(keysview, Reversible) assert isinstance(itemsview, Reversible) assert hasattr(keysview, 'mapping') assert hasattr(itemsview, 'mapping') assert list(reversed(keysview)) == [2, 1] assert list(reversed(itemsview)) == [(2, 'two'), (1, 'one')] # ...and the views still agree with the bidict itself. assert list(keysview) == list(b) == [1, 2] assert list(itemsview) == [(1, 'one'), (2, 'two')] assert keysview == {1, 2} assert list(b.values()) == ['one', 'two'] def test_non_dict_backing_falls_back_to_generic_views() -> None: """A backing mapping that is not a dict at all still gets a view over the bidict.""" b = UserBi({1: 'one', 2: 'two'}) # backed by UserDict assert isinstance(b.keys(), BidictKeysView) assert list(b.keys()) == [1, 2] assert b.keys() == {1, 2} assert list(b.items()) == [(1, 'one'), (2, 'two')] def test_subclass_can_regain_reversibility() -> None: """A subclass whose backing mappings are reversible must be reversible. Regression test: _set_reversed() decided whether __reversed__ had been overridden by comparing the resolved value to BidictBase's. A class whose backing mappings are not reversible has __reversed__ set to None by _set_reversed() itself, and a subclass of it inherits that None, which compared unequal to BidictBase's and so was misread as a deliberate override -- leaving the subclass non-reversible no matter its own backings. """ class NotReversible(bidict[t.Any, t.Any]): _fwdm_cls = UserDict _invm_cls = UserDict class ReversibleAgain(NotReversible): _fwdm_cls = dict _invm_cls = dict assert not issubclass(NotReversible, Reversible) # UserDict is not reversible assert issubclass(ReversibleAgain, Reversible) # but dict is bi = ReversibleAgain({1: 'one', 2: 'two'}) assert list(reversed(bi)) == [2, 1] assert list(reversed(bi.keys())) == [2, 1] assert list(reversed(bi.values())) == ['two', 'one'] def test_user_provided_reversed_is_honored_and_inherited() -> None: """_set_reversed() must never clobber a __reversed__ that a user provided. This is what keeps OrderedBidict, which does not define __reversed__ itself, from computing one from its backing mappings and losing OrderedBidictBase's. """ class CustomReversed(bidict[t.Any, t.Any]): @override def __reversed__(self) -> t.Any: return iter(['custom']) class SubCustom(CustomReversed): # even with backings that are not reversible _fwdm_cls = UserDict _invm_cls = UserDict for bi_t in (CustomReversed, SubCustom): assert issubclass(bi_t, Reversible) assert list(reversed(bi_t())) == ['custom'], bi_t def test_set_reversed_is_idempotent() -> None: """Running _set_reversed() again must not make a computed __reversed__ look user-provided. It only runs once per class today, but were a repeat ever to mark the class as having a user-provided __reversed__, subclasses would inherit that and stop computing their own, which is exactly the bug that test_subclass_can_regain_reversibility covers. """ class Computed(bidict[t.Any, t.Any]): pass Computed._set_reversed() assert not Computed._reversed_is_user_provided class SubComputed(Computed): _fwdm_cls = UserDict _invm_cls = UserDict assert not issubclass(SubComputed, Reversible) # still free to compute its own answer def test_reversed_opt_out_is_honored_and_inherited() -> None: """Setting __reversed__ to None opts out of reversed(), for subclasses too. Unnecessary as of v0.22 for the usual case of non-reversible backing mappings, which _set_reversed() now detects, but still the way to opt out deliberately. """ class OptedOut(bidict[t.Any, t.Any]): __reversed__ = None class SubOptedOut(OptedOut): pass for bi_t in (OptedOut, SubOptedOut): bi: t.Any = bi_t({1: 'one'}) assert not isinstance(bi, Reversible), bi_t with pytest.raises(TypeError): reversed(bi) # The values view must not offer what the bidict itself declines to. assert not isinstance(bi.values(), Reversible), bi_t #: Ways to mutate an ordered bidict, keyed by name. Each takes the bidict and the key #: just yielded by the iteration in progress. _MUTATIONS_DURING_ITERATION: t.Any = { 'insert': lambda ob, key: ob.__setitem__(f'new{key}', f'new{key}'), 'delete': lambda ob, key: ob.pop(next(k for k in ob if k != key), None), 'clear': lambda ob, _key: ob.clear(), 'move_to_end': lambda ob, key: ob.move_to_end(key), 'collapse_to_fewer_items': lambda ob, key: ob.forceput(key, next(iter(ob.inv))), 'insert_via_the_inverse': lambda ob, key: ob.inv.__setitem__(f'new{key}', f'new{key}'), } def _iterate_while_mutating(ob: OrderedBidict[t.Any, t.Any], iterate: t.Any, mutate: t.Any) -> None: """Iterate *ob* via *iterate*, applying *mutate* to it on each step. Bounded, so that a failure to detect the mutation fails the test rather than hanging it: inserting during iteration used to grow the linked list ahead of the iterator forever. """ for i, key in enumerate(iterate(ob)): assert i < 100, 'iteration did not terminate after mutation' mutate(ob, key) @pytest.mark.parametrize('mutate', _MUTATIONS_DURING_ITERATION.values(), ids=list(_MUTATIONS_DURING_ITERATION)) @pytest.mark.parametrize('iterate', [iter, reversed], ids=['forward', 'reverse']) def test_orderedbidict_mutation_during_iteration_raises(mutate: t.Any, iterate: t.Any) -> None: """Mutating an ordered bidict while iterating it must raise RuntimeError. dict and OrderedDict both do this. Without it, inserting during iteration looped forever, clear() raised a KeyError naming an internal Node, and deleting silently skipped items. Note the last mutation goes through the inverse, which shares the linked list, so it must invalidate this iterator too. """ ob: OrderedBidict[t.Any, t.Any] = OrderedBidict({1: 'one', 2: 'two', 3: 'three'}) with pytest.raises(RuntimeError): _iterate_while_mutating(ob, iterate, mutate) def test_orderedbidict_mutation_on_final_item_raises() -> None: """Mutating while the last item is being visited raises, unlike OrderedDict. dict raises here and OrderedDict does not, so the two disagree and we cannot match both. Raising is the safer of the two, keeps OrderedBidict consistent with plain bidict (which is backed by a dict and so already raises), and avoids code that works or not depending on which iteration the mutating branch happens to be taken on. """ ob = OrderedBidict({1: 'one', 2: 'two'}) with pytest.raises(RuntimeError): _iterate_while_mutating(ob, iter, lambda o, key: o.__setitem__(3, 'three') if key == 2 else None) def test_orderedbidict_iteration_allows_value_only_update() -> None: """Updating an existing key's value does not restructure the list, so it must not raise. dict and OrderedDict both permit this, and an ordered bidict's iteration order is unaffected by it: the item keeps its node, and so its position. """ ob = OrderedBidict({1: 'one', 2: 'two'}) for key in ob: ob[key] = f'updated{key}' assert list(ob.items()) == [(1, 'updated1'), (2, 'updated2')] def test_orderedbidict_iterator_created_before_mutation_raises() -> None: """The check must catch a mutation made after the iterator was created but before it ran. OrderedDict does this too, which is why iternodes() captures the version eagerly rather than on the first next() call. """ ob = OrderedBidict({1: 'one', 2: 'two'}) it = iter(ob) ob[3] = 'three' with pytest.raises(RuntimeError): list(it) def test_orderedbidict_iteration_unaffected_by_unrelated_bidict() -> None: """Only mutations to *this* bidict's linked list invalidate its iterators.""" ob, other = OrderedBidict({1: 'one', 2: 'two'}), OrderedBidict({3: 'three'}) keys = [] for key in ob: other[key] = f'x{key}' # a different bidict, so a different linked list keys.append(key) assert keys == [1, 2] #: (label, mutation) pairs, each writing an item that duplicates a contained key, a contained #: value, or both, using an object that is equal to the contained one but not identical to it. _DUPLICATING_WRITES: t.Any = { 'key_duplication': lambda b: b.__setitem__(Tagged(1, 'new'), 'other'), 'value_duplication': lambda b: b.forceput(Tagged(9, 'new'), Tagged(2, 'new')), 'collapse': lambda b: b.forceput(Tagged(1, 'new'), Tagged(2, 'new')), } @pytest.mark.parametrize('mutate', _DUPLICATING_WRITES.values(), ids=list(_DUPLICATING_WRITES)) @pytest.mark.parametrize('bi_t', mutable_bidict_types) def test_one_object_per_item_in_both_directions(bi_t: MBT[t.Any, t.Any], mutate: t.Any) -> None: """A bidict and its inverse must hold the same object for each item, not equal copies. dict keeps the key object it already has when a key is overwritten, but takes the new value object. In a bidict a value is also a key of the inverse, so those two conventions conflict; applying each to its own backing mapping left the two holding equal but distinct objects for one item, and so left b.inverse[b[key]] not identical to key. """ bi = bi_t({Tagged(1, 'orig'): Tagged(2, 'orig')}) mutate(bi) for key in bi: val = bi[key] assert bi.inverse[val] is key, 'key differs between a bidict and its inverse' inv_key = next(k for k in bi.inverse if k == val) assert inv_key is val, 'value differs between a bidict and its inverse' @pytest.mark.parametrize('bi_t', mutable_bidict_types) def test_duplicating_write_keeps_the_contained_object(bi_t: MBT[t.Any, t.Any]) -> None: """Of two equal objects, the one already contained is the one kept. That is what a dict does for keys, and it is the only self-consistent choice here: adopting the incoming key object instead would mean deleting and reinserting it, which would move the item to the end and so silently reorder the bidict. """ bi = bi_t({Tagged(1, 'orig'): Tagged(2, 'orig')}) bi[Tagged(1, 'new')] = Tagged(3, 'new') # key duplicates the contained Tagged(1) (key,) = bi assert key.tag == 'orig' assert bi.inverse[bi[key]].tag == 'orig' @pytest.mark.parametrize('bi_t', mutable_bidict_types) def test_duplicating_write_does_not_reorder(bi_t: MBT[t.Any, t.Any]) -> None: """Keeping the contained key object also keeps the item in place.""" bi = bi_t({Tagged(1): 'one', Tagged(2): 'two'}) bi[Tagged(1, 'new')] = 'uno' assert [k.n for k in bi] == [1, 2] def test_orderedbidict_weakattr_class_access() -> None: """Accessing a WeakAttr descriptor from the Node class should return the descriptor itself.""" descriptor = OrderedBidictNode.prv assert isinstance(descriptor, WeakAttr) def test_orderedbidictbase_order_diverges_from_backing_mappings() -> None: """Spell out the scenario behind test_views_agree_with_iteration_order's @example. That test checks the views against the bidict's own iteration order, so on its own it could not tell you whether the two orders ever actually differ. This pins that they do, with absolute expectations, and covers repr() (which goes through items()) besides. Regression test: the keys()/items() overrides used to live on OrderedBidict, justified by a *mutable* ordered bidict getting out of sync with its backing mappings after mutation. But an overwrite during __init__ suffices, so OrderedBidictBase needs them too. """ ob = UserOrderedBiBase([(1, 'a'), (2, 'b'), (3, 'a')]) # (3, 'a') overwrites (1, 'a') in place assert list(ob) == [3, 2] # the item formerly keyed 1 is now keyed 3, in its original position assert list(ob._fwdm) == [2, 3] # whereas the backing dict appended 3 and dropped 1 assert repr(ob) == "UserOrderedBiBase({3: 'a', 2: 'b'})" def test_orderedbidict_cross_view_set_operations() -> None: """Set operations between an OrderedBidict keys view and an items view (or vice versa) should behave like the equivalent plain dict views rather than raising TypeError or giving a wrong result. Regression test: the set-operation proxy methods in _OrderedBidictKeysView and _OrderedBidictItemsView previously passed the opposing custom view type directly to the C-level dict_keys/dict_items methods, which returned NotImplemented (they only recognize dict_keys and dict_items). With both sides returning NotImplemented, Python raised TypeError (for the ordering comparisons) or fell back to the wrong answer (e.g. identity-based __eq__). The fix extracts the backing dict view from a cross-type _OView arg before forwarding. """ ob1 = OrderedBidict({'a': 1, 'b': 2}) ob2 = OrderedBidict({'a': 1}) d1 = {'a': 1, 'b': 2} d2 = {'a': 1} # The comparison operators return bools; the set-algebra operators return sets/bools. In every # case the OrderedBidict view result must match the equivalent plain dict view result exactly. # fmt: off ops = ( '__lt__', '__le__', '__gt__', '__ge__', '__eq__', '__ne__', # comparisons '__sub__', '__or__', '__xor__', '__and__', 'isdisjoint', # set algebra ) # fmt: on for op in ops: assert getattr(ob1.keys(), op)(ob2.items()) == getattr(d1.keys(), op)(d2.items()), op assert getattr(ob1.items(), op)(ob2.keys()) == getattr(d1.items(), op)(d2.keys()), op def test_abc_slots() -> None: """Bidict ABCs should define __slots__. Ref: https://docs.python.org/3/reference/datamodel.html#notes-on-using-slots Note: non-abstract bidict types do not define __slots__ as of v0.22.0. """ assert BidirectionalMapping.__dict__['__slots__'] == () assert MutableBidirectionalMapping.__dict__['__slots__'] == () @pytest.mark.parametrize('bi_t', bidict_types) def test_values_view_reversibility_matches_bidict(bi_t: BT[t.Any, t.Any]) -> None: """values() iterates the backing forward mapping, so it must be reversible exactly when the bidict itself is -- never advertising a reversed() that raises. """ bi = bi_t({1: -1, 2: -2}) values = bi.values() if isinstance(bi, Reversible): assert isinstance(values, Reversible) assert list(reversed(values)) == list(bi.values())[::-1] else: assert not isinstance(values, Reversible) with pytest.raises(TypeError): # and the claim is not a lie reversed(t.cast('t.Any', values)) @pytest.mark.parametrize('bi_t', bidict_types) def test_inv_aliases_inverse(bi_t: BT[KT, VT]) -> None: """bi.inv should alias bi.inverse.""" bi = bi_t() assert bi.inverse is bi.inv assert bi.inv.inverse is bi.inverse.inv def test_static_types() -> None: d = {'1': 1} fb = frozenbidict(d) assert_type(fb, frozenbidict[str, int]) assert_type(fb.inv, frozenbidict[int, str]) @pytest.mark.parametrize('bi_t', mutable_bidict_types) def test_setitem_existing_is_noop_with_nonreflexive_eq(bi_t: MBT[t.Any, t.Any]) -> None: """Setting an existing (key, val) pair should be a no-op even when key == key is False. Float NaN has non-reflexive equality (nan != nan), so it exercises the identity-based same-item check in _dedup. (Previously, _dedup used an equality-based same-item check that caused spurious KeyAndValueDuplicationErrors and AssertionErrors. See #377.) """ nan = float('nan') # NaN as key: b[nan] = 'a' again must not raise b1 = bi_t() b1[nan] = 'a' b1[nan] = 'a' assert len(b1) == 1 assert b1[nan] == 'a' # NaN as value: b['x'] = nan again must not raise b2 = bi_t() b2['x'] = nan b2['x'] = nan assert len(b2) == 1 assert b2['x'] is nan # A key or value that duplicates an existing item's key and an existing # *different* item's value must still raise, even when it's the same NaN object: b3 = bi_t() b3[nan] = 'a' b3['x'] = nan with pytest.raises(KeyAndValueDuplicationError): b3[nan] = nan class _AsymStored: """Pathological type equal to _AsymLookup instances, but only when on the left-hand side.""" @override def __hash__(self) -> int: return 1 @override def __eq__(self, other: object) -> bool: return isinstance(other, _AsymLookup) class _AsymLookup: """Pathological type that is never equal to anything, even when an _AsymStored equals it.""" @override def __hash__(self) -> int: return 1 @override def __eq__(self, other: object) -> bool: return False @pytest.mark.parametrize('bi_t', mutable_bidict_types) def test_setitem_existing_is_noop_with_asymmetric_eq(bi_t: MBT[t.Any, t.Any]) -> None: """Setting an existing (key, val) pair should be a no-op even when __eq__ is asymmetric. dict lookup compares stored == lookup, so a lookup key that a stored key compares equal to hits the stored key's item even when lookup == stored is False. _dedup must agree with the dict lookups rather than re-checking equality itself (with operands in the opposite order) and wrongly concluding the items differ. See #382. """ stored, lookup = _AsymStored(), _AsymLookup() probe: dict[t.Any, str] = {stored: 'hit'} if probe.get(lookup) != 'hit': pytest.skip('dict lookup on this runtime does not compare stored == lookup') # Asymmetric key: dict considers *lookup* the same key as *stored* -> no-op b1 = bi_t() b1[stored] = 'v' b1[lookup] = 'v' assert len(b1) == 1 assert next(iter(b1)) is stored # Asymmetric value -> no-op b2 = bi_t() b2['x'] = stored b2['x'] = lookup assert len(b2) == 1 assert b2['x'] is stored def assert_calls_match(call1: Callable[..., t.Any], call2: Callable[..., t.Any]) -> None: results: dict[t.Any, t.Any] = {call1: None, call2: None} for call in results: try: results[call] = call() except Exception as exc: # ruff: ignore[blind-except] results[call] = exc.__class__ assert results[call1] == results[call2] def assert_mappings_are_inverse(m1: Mapping[KT, VT], m2: Mapping[VT, KT]) -> None: assert len(m1) == len(m2) assert all(k == m2[v] for (k, v) in m1.items()) assert m1.keys() == frozenset(m2.values()) assert frozenset(m1.values()) == m2.keys() def assert_bi_and_inv_are_inverse(bi: BB[KT, VT]) -> None: assert_mappings_are_inverse(bi, bi.inv) assert bi is bi.inv.inv assert bi.inv is bi.inv.inv.inv def assert_bidicts_equal(b1: BB[KT, VT], b2: BB[KT, VT]) -> None: assert b1 == b2 assert b1.inv == b2.inv assert_mappings_are_inverse(b1, b2.inv) assert_mappings_are_inverse(b1.inv, b2) bidict-0.24.1/tox.ini000066400000000000000000000023431524342314000143470ustar00rootroot00000000000000[tox] download = true envlist = py3{15,14,13,12,11} pypy3.11 # Do not include the following so they only run when explicitly requested: # benchmark # coverage # docs # lint skip_missing_interpreters = true # https://hynek.me/articles/turbo-charge-tox/ package = wheel wheel_build_env = .pkg [testenv] runner = uv-venv-lock-runner passenv = # https://docs.pytest.org/en/stable/example/simple.html PYTEST_ADDOPTS # https://docs.pytest.org/en/7.1.x/reference/reference.html#envvar-FORCE_COLOR FORCE_COLOR # https://hypothesis.readthedocs.io/en/latest/settings.html#hypothesis.settings.print_blob # https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables CI allowlist_externals = bash commands = ty check pytest [testenv:benchmark] commands = pytest -c /dev/null -n0 --benchmark-autosave microbenchmarks.py [testenv:coverage] commands = coverage run -m pytest coverage combine coverage report [testenv:docs] dependency_groups = docs commands = sphinx-build -TWn --keep-going -b html -d {envtmpdir}/doctrees docs {envtmpdir}/html [testenv:lint] deps = skip_install = true allowlist_externals = prek commands = prek --all-files --verbose --show-diff-on-failure bidict-0.24.1/update_dev_dependencies000077500000000000000000000107031524342314000176070ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright 2009-2026 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() { >&2 printf "> %s\n" "$@" } # prek auto-update moves the ruff pin in .pre-commit-config.yaml but knows nothing about # pyproject.toml's required-version, which exists to reject a local ruff older than that pin. # Left to drift, the floor keeps passing versions that lint with fewer rules than CI uses. check_ruff_required_version() { local pinned required pinned=$(grep -A1 'astral-sh/ruff-pre-commit' .pre-commit-config.yaml | sed -n 's/^ *rev: v//p') required=$(sed -n 's/^required-version = ">=\(.*\)"$/\1/p' pyproject.toml) if [[ -z $pinned || -z $required ]]; then log "Warning: could not compare ruff's pinned version to pyproject.toml's required-version." log " Check by hand that they agree, and fix this check if its parsing has gone stale." return fi if [[ $pinned != "$required" ]]; then log "Action needed: ruff is pinned to v$pinned, but required-version says >=$required." log " Set required-version = \">=$pinned\" in pyproject.toml, so that a ruff" log " older than the pinned one fails instead of linting with fewer rules." log fi } # Zero-pad a version into a fixed-width string, so that two of them compare correctly with the # lexicographic [[ < ]], which is available everywhere `sort -V` is not (e.g. BSD/macOS sort). version_key() { local major minor patch IFS=. read -r major minor patch <<<"$1" printf '%05d%05d%05d' "${major:-0}" "${minor:-0}" "${patch:-0}" } # The wheel's RECORD is written by uv_build, whose version comes from pyproject.toml's # [build-system] requires -- not from the uv on PATH, and not from uv.lock. Nothing else here # touches that pin, and left to drift it is what shipped 0.24.0 with hex RECORD hashes (#406). # The pin's floor guards correctness on its own; what needs watching is its ceiling, which # should keep covering the uv in uv.lock, so that building a release goes on using that uv's # built-in uv_build rather than quietly downloading a different version to build with. check_uv_build_pin() { local locked floor ceiling locked=$(sed -n '/^name = "uv"$/{n;s/^version = "\(.*\)"$/\1/p;}' uv.lock) floor=$(sed -n 's/^requires = \["uv_build>=\([^,"]*\),.*$/\1/p' pyproject.toml) ceiling=$(sed -n 's/^requires = \["uv_build>=[^,]*,<\([^"]*\)"\].*$/\1/p' pyproject.toml) if [[ -z $locked || -z $floor || -z $ceiling ]]; then log "Warning: could not compare uv.lock's uv version to pyproject.toml's uv_build pin." log " Check by hand that they agree, and fix this check if its parsing has gone stale." return fi if [[ ! $(version_key "$locked") < $(version_key "$ceiling") ]]; then log "Action needed: uv.lock has uv $locked, past uv_build>=$floor,<$ceiling's ceiling." log " Raise that ceiling in pyproject.toml to cover $locked, so that building a" log " release keeps using uv's own uv_build instead of downloading another." log " Leave the floor alone: it is what keeps #406 from recurring." log elif [[ $(version_key "$locked") < $(version_key "$floor") ]]; then log "Action needed: uv.lock has uv $locked, below uv_build>=$floor,<$ceiling's floor, so a" log " release would be built by a downloaded uv_build rather than this uv's own." log " Upgrade uv rather than lowering the floor, which guards against #406." log fi } main() { declare -r hint="Hint: Use 'nix develop' to bootstrap a development environment" for cmd in uv prek; do if ! command -v "$cmd" >/dev/null 2>&1; then log "Error: No '$cmd' on PATH. $hint" exit 1 fi done log "Upgrading PyPI dependencies..." uv lock --upgrade && uv sync log "Upgrading PyPI dependencies: Done" log log "Upgrading pre-commit hooks..." prek auto-update log "Upgrading pre-commit hooks: Done" log check_ruff_required_version check_uv_build_pin log "Reminders:" log " - Check release notes of upgraded packages for anything that affects bidict." log " - Ensure tests pass for all supported Python versions." log " - Check output for any new warnings, not just test failures." log " - Ensure 'prek run --all-files' still succeeds." } main bidict-0.24.1/uv.lock000066400000000000000000004526611524342314000143540ustar00rootroot00000000000000version = 1 revision = 3 requires-python = ">=3.11" resolution-markers = [ "python_full_version >= '3.15'", "python_full_version >= '3.12' and python_full_version < '3.15'", "python_full_version < '3.12'", ] [[package]] name = "accessible-pygments" version = "0.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pygments" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899, upload-time = "2024-05-10T11:23:10.216Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903, upload-time = "2024-05-10T11:23:08.421Z" }, ] [[package]] name = "alabaster" version = "1.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, ] [[package]] name = "babel" version = "2.18.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, ] [[package]] name = "beautifulsoup4" version = "4.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "soupsieve" }, { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/43/65/318323f98dbee45d42dff61d8f047181bc6f2268a9068cfad035a46be5af/beautifulsoup4-4.15.0.tar.gz", hash = "sha256:288e3ca7d54b06f2ac191970bc275c1939cb46d450b255bf6718b04aa37ab4f7", size = 632571, upload-time = "2026-06-07T16:44:20.453Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/88/c6/92fcd42f1ba33e1184263f25bfabf3d27c383410470f169e4b8163bf9c17/beautifulsoup4-4.15.0-py3-none-any.whl", hash = "sha256:d6f88de62e1d4e38ecb1077eb9724cd0eff29d2a08ca16a401e9b9e93f117cf9", size = 109924, upload-time = "2026-06-07T16:44:21.566Z" }, ] [[package]] name = "bidict" version = "0.24.1" source = { editable = "." } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] [package.dev-dependencies] dev = [ { name = "pytest-clarity" }, { name = "pytest-icdiff" }, { name = "pytest-sugar" }, { name = "tox" }, { name = "tox-uv" }, ] docs = [ { name = "furo" }, { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "sphinx-copybutton" }, ] test = [ { name = "coverage" }, { name = "hypothesis" }, { name = "pytest" }, { name = "pytest-benchmark" }, { name = "pytest-sphinx" }, { name = "pytest-xdist" }, { name = "sortedcollections" }, { name = "sortedcontainers" }, { name = "ty" }, { name = "typing-extensions" }, ] [package.metadata] requires-dist = [{ name = "typing-extensions", marker = "python_full_version < '3.12'", specifier = ">=4.0" }] [package.metadata.requires-dev] dev = [ { name = "pytest-clarity" }, { name = "pytest-icdiff" }, { name = "pytest-sugar" }, { name = "tox" }, { name = "tox-uv" }, ] docs = [ { name = "furo" }, { name = "sphinx" }, { name = "sphinx-copybutton" }, ] test = [ { name = "coverage" }, { name = "hypothesis" }, { name = "pytest" }, { name = "pytest-benchmark" }, { name = "pytest-sphinx" }, { name = "pytest-xdist" }, { name = "sortedcollections" }, { name = "sortedcontainers" }, { name = "ty", specifier = ">=0.0.72" }, { name = "typing-extensions" }, ] [[package]] name = "cachetools" version = "7.1.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f4/8b/0d3945a13955303b81272f759a0331e54c5c793da455e6f5706b89d2639c/cachetools-7.1.4.tar.gz", hash = "sha256:437f55a4e0c1b01a4f3077cc470e6991d47430970e36fbcb77e2be0df4fc1cd6", size = 40085, upload-time = "2026-05-21T22:40:43.376Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8c/7b/1fc1c09cc0756cf25861a3be10565915953876da48bb228fb9a672b20a42/cachetools-7.1.4-py3-none-any.whl", hash = "sha256:323dc4127934744db5b54eb4924482d7edafbf9554e820d1531c2e08c0e4ef54", size = 16761, upload-time = "2026-05-21T22:40:41.845Z" }, ] [[package]] name = "certifi" version = "2026.6.17" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" }, ] [[package]] name = "charset-normalizer" version = "3.4.8" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/20/56/10a88e00039537d74bd420f0457c52ab8f58a1af56126e3b9f1b1c8c4724/charset_normalizer-3.4.8.tar.gz", hash = "sha256:d9bf144d6faf12c70d58e47f7512992ae2882b820031d6cef68152deb645bf2d", size = 151790, upload-time = "2026-07-06T15:27:58.477Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/94/b5/7f10929c45e2d0d0dc78bead98458c271af3e028e66b16441de88829a8b7/charset_normalizer-3.4.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ca832d525a2a52542048111cb44e0dea595b9ad53ad542020aa770f308427b92", size = 316812, upload-time = "2026-07-06T15:25:58.71Z" }, { url = "https://files.pythonhosted.org/packages/2a/b4/8e936a5e19d7e7b19db29aeed0988b481dc745eed3437829780f6ec98ce9/charset_normalizer-3.4.8-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab07eb7b564635602734c3ef0e8d2db9d59cbbce54f5dc42b8f11aa1f56ce364", size = 213580, upload-time = "2026-07-06T15:26:00.121Z" }, { url = "https://files.pythonhosted.org/packages/27/b8/dbc3b3c4796e4e29e193c5d7e100bb8ebfa66267994c01ba1eaaa3ebc474/charset_normalizer-3.4.8-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6e88da593ea098194ea08f58924b716a9ae0c39058edad8c5c9b0bafa39fbd56", size = 235244, upload-time = "2026-07-06T15:26:01.402Z" }, { url = "https://files.pythonhosted.org/packages/93/22/808ff7eb8d344a174b89a388a4540fb86e486f608c16b9a2a023ddf6c9c6/charset_normalizer-3.4.8-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8ca83574f63f71b485da1c50d4e17bcef7375a56b459a861562554f1fbaac1a4", size = 229678, upload-time = "2026-07-06T15:26:02.62Z" }, { url = "https://files.pythonhosted.org/packages/c2/35/525d3e86af55a66073c02dbf9b6a720c74601489e4b4cb391cad0a4cb620/charset_normalizer-3.4.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9840cca6969a7e35498f1ce6fc32b7842500783d303b5ab254679a0f591093c4", size = 221015, upload-time = "2026-07-06T15:26:03.888Z" }, { url = "https://files.pythonhosted.org/packages/e1/63/10f18541380f2d1c40ffda42835661aa9f88a1333e586d7b0f1d29869113/charset_normalizer-3.4.8-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:ca8776b012d464136c239f51133120db94397bc69f3faee404ff8c99827f8192", size = 205002, upload-time = "2026-07-06T15:26:05.32Z" }, { url = "https://files.pythonhosted.org/packages/1e/0b/28168f20737bb7d7d40d29cb82d2084cb3a8c19a4e1fef18f07069a24338/charset_normalizer-3.4.8-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:23c40d25fe581d34ff0ef7ff1ca1527f5c51c5c6edf0b8384eeafac4a0438469", size = 217527, upload-time = "2026-07-06T15:26:06.47Z" }, { url = "https://files.pythonhosted.org/packages/8a/41/bc39417675dcca7151be665ec20f4b1b25ff3486d8eb2f3d7662ebc56082/charset_normalizer-3.4.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6809e40a8876eb4742676fbbb57056c0344ef2555e5597d4343f0b365953afdd", size = 216538, upload-time = "2026-07-06T15:26:07.836Z" }, { url = "https://files.pythonhosted.org/packages/76/7f/e322a4f060a32aa9510d3c76689be7d58c62653b09fe156912471e17a7bc/charset_normalizer-3.4.8-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1bfd4bf262d6f26805cc6a32dae2554db66ef7533e6c62cc12644d3882be05e5", size = 206170, upload-time = "2026-07-06T15:26:09.269Z" }, { url = "https://files.pythonhosted.org/packages/5d/64/07d0a02c401433ba18d57f55a96ffe7c701a11eac57c74bae0e1506cfa40/charset_normalizer-3.4.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9421549d803f0f712aa6e1496d15ff5ac510fc4c7104e7e299ea1d498d582d59", size = 222807, upload-time = "2026-07-06T15:26:10.476Z" }, { url = "https://files.pythonhosted.org/packages/e1/84/2d132bdad9cadc3251bbad2813d29642c068855ad0394234f76845672100/charset_normalizer-3.4.8-cp311-cp311-win32.whl", hash = "sha256:9a2748f7588b0c1e5166db3a9448fe86e392479aded89b0c86382d41cade91a2", size = 150195, upload-time = "2026-07-06T15:26:11.654Z" }, { url = "https://files.pythonhosted.org/packages/8d/5f/c46567479049f46929d8ed9e628990c2419f369c5ea5797add417808d37b/charset_normalizer-3.4.8-cp311-cp311-win_amd64.whl", hash = "sha256:2e9f0db12ea28a3349e514443fc56d4b1fb3c81d0f9c0e33dacfdfc2ac63f774", size = 161151, upload-time = "2026-07-06T15:26:13.111Z" }, { url = "https://files.pythonhosted.org/packages/d1/ac/39a8bc03f7550f86f8c43205f2c97bc3a4cea775e5a0c0317917679cdef5/charset_normalizer-3.4.8-cp311-cp311-win_arm64.whl", hash = "sha256:4b1f25c6e376033f31463d66f8bb01ae77a128ca11c6677c69ed8e9ce913bbf9", size = 152392, upload-time = "2026-07-06T15:26:14.335Z" }, { url = "https://files.pythonhosted.org/packages/59/c2/39de60ef5687662f467bed3d1e6944c67a4f0d057141d0404002b8f405ae/charset_normalizer-3.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:faac37c4904598daa00cb4c9b32f3b4cc814fb5f145d7a531ceb4a70f2114132", size = 319040, upload-time = "2026-07-06T15:26:15.854Z" }, { url = "https://files.pythonhosted.org/packages/a7/57/a9474c3aeaa337c8a330c0dc5df266527d56da3b189c029529f6b08af2a4/charset_normalizer-3.4.8-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f191c19a32dc6cec0fb8079789d786254653a9ce906fcab04ccd2eed07bba233", size = 215541, upload-time = "2026-07-06T15:26:17.265Z" }, { url = "https://files.pythonhosted.org/packages/13/a9/be1ff7e81f6e086dced2a7a7a28b789be351d9796084ccaf6136a4ffafb3/charset_normalizer-3.4.8-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05811b76943d477bb90822dedb5c4565cef70148847a59d574e2b35043aeb563", size = 236913, upload-time = "2026-07-06T15:26:18.482Z" }, { url = "https://files.pythonhosted.org/packages/8f/75/d8c5eae93da26d463f9ebe46a4937ca44434dc2937a565b92437befb3d94/charset_normalizer-3.4.8-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3868a3e4ec1e40b419e060d063f93eac6f046fa21426c4816421223ae7dc8ab8", size = 232815, upload-time = "2026-07-06T15:26:19.734Z" }, { url = "https://files.pythonhosted.org/packages/27/0d/98e301ca944bcca5e6bc312406b579c8a6d81546c1b494afb3a9478495d6/charset_normalizer-3.4.8-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25f93d194eb6264c64416cabff46a91f6d99b97e7525a1b4f35c77a99e75cc68", size = 223995, upload-time = "2026-07-06T15:26:20.931Z" }, { url = "https://files.pythonhosted.org/packages/fa/df/f5222366b76dcb31453a9bd922610c893540d0e729fd390439b0d3e972ee/charset_normalizer-3.4.8-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:ee6a62492f18d432cca031fabd158f400a8c25bf7b9458f50953393a2a23d97a", size = 208522, upload-time = "2026-07-06T15:26:22.214Z" }, { url = "https://files.pythonhosted.org/packages/74/52/293220d59d8ddfb8aa56836b33bd6df58e70795d8a102a858c2984480f00/charset_normalizer-3.4.8-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1c16cb4fc35e4b064f5ee78d849f15a550ada1729c3372916672e38f1f01d1d4", size = 219660, upload-time = "2026-07-06T15:26:23.493Z" }, { url = "https://files.pythonhosted.org/packages/c3/2c/81a298e66f3d01e61bfc6f7064bbb553b067a9f1d979e5962bf00733069b/charset_normalizer-3.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2fbd0edb0426ab28e70fac9d1d4ef549eb5a64a2521f0428c441d75e4387e6c2", size = 218230, upload-time = "2026-07-06T15:26:24.629Z" }, { url = "https://files.pythonhosted.org/packages/0d/45/f1dd2328cbc3340705f82072c09bd4c68d6e079191cde05810c1eac77eee/charset_normalizer-3.4.8-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccb9052771216170015f810b88065fd9e13b1e0b391f92abb9b47e0919a42aad", size = 210006, upload-time = "2026-07-06T15:26:25.837Z" }, { url = "https://files.pythonhosted.org/packages/38/63/28697000620e117eb413424caaf60b6f98ddb1b09b2c11f7c0038d9936a7/charset_normalizer-3.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3809ba5d3cd02aca0894597f2669a825bdfe2229061515c128b0f4e5533b4ab5", size = 225771, upload-time = "2026-07-06T15:26:27.079Z" }, { url = "https://files.pythonhosted.org/packages/12/a7/d5844e315f5f35e7938c415f07a1df144eed1cf993f1b43cc16c980c5b46/charset_normalizer-3.4.8-cp312-cp312-win32.whl", hash = "sha256:de63c31666a049f653ada24e800192e3c019e96bc7d70fb449a000bccf26a36f", size = 150922, upload-time = "2026-07-06T15:26:28.514Z" }, { url = "https://files.pythonhosted.org/packages/9b/82/eb8b72f184b1e4986dd9daec15d7f6d9285a6728d2b07b7f04656829f473/charset_normalizer-3.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:14a4bbe066f3fb05c6ba70e9cf9d34614b57a2fd70ea8c27cc30f34155e16a58", size = 162294, upload-time = "2026-07-06T15:26:29.745Z" }, { url = "https://files.pythonhosted.org/packages/09/5a/ab810134aa41034a08ffe94c058102016e6ad9bce62f3cdba547b4723385/charset_normalizer-3.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:2b5b0c0dca0a02c3f816f89abf18af3d20416dedbc3d3aa5f3981045f88ae7b0", size = 152409, upload-time = "2026-07-06T15:26:31.034Z" }, { url = "https://files.pythonhosted.org/packages/11/49/fe5a8572a70cd9cba79f80af9388ac8c5c914ed4459b956f940244e499a5/charset_normalizer-3.4.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:057f8609f7341618c98e5aa9a6109fa116acff2a658497d47ab3325b5e8f2b08", size = 317424, upload-time = "2026-07-06T15:26:32.23Z" }, { url = "https://files.pythonhosted.org/packages/e5/59/d71c96616b6825425a876f79f38fa440db30b32cc1166179a839f6259150/charset_normalizer-3.4.8-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c591f9a82adc5b89a039b90df74e43de2b9177fb46771172bed7b80722a70db0", size = 214723, upload-time = "2026-07-06T15:26:33.635Z" }, { url = "https://files.pythonhosted.org/packages/c6/35/dc9eeb297f19b7b6ada39709ccb74937e6c51f0947958ae601a977cedd5d/charset_normalizer-3.4.8-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5b56f449132d9adefe55b87635d05177a914ed5d070438a74725e1d77a280002", size = 236200, upload-time = "2026-07-06T15:26:34.99Z" }, { url = "https://files.pythonhosted.org/packages/0a/37/6775fe852b4acad8bf7e0575fbe8aa9f41b546e33251acbded3c04a6b0d9/charset_normalizer-3.4.8-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1004c3b5831a301dadfb9e916f38e78e2ff3e08db24a1ad7c354db8ee3dea9c3", size = 231740, upload-time = "2026-07-06T15:26:36.498Z" }, { url = "https://files.pythonhosted.org/packages/e4/28/1bcc3f5f3bac81532384adcfcdd9362c7f46a188a19deacc1ddaf7bdaa00/charset_normalizer-3.4.8-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:60883e22821d17c9e5b4f3ca1ef8074f766e3db28791f851b665929c515635c0", size = 222888, upload-time = "2026-07-06T15:26:38.161Z" }, { url = "https://files.pythonhosted.org/packages/47/81/9f3993ca62ef090c58059da641e49e3129e74700a6a3beb58436cdb8d4b9/charset_normalizer-3.4.8-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:21e4dbb942c8a6342e2685f232dd2a7bc73465697bd26ead4f118271d28be383", size = 207649, upload-time = "2026-07-06T15:26:39.628Z" }, { url = "https://files.pythonhosted.org/packages/11/f4/679f636bcbdc2d53d06b1f4039be310450dca95a9f76bbf22f09985556e8/charset_normalizer-3.4.8-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:84bcae14c65e645ca66b661339183d32b8c846a17c96e3e81ab3d346e1c498d4", size = 218908, upload-time = "2026-07-06T15:26:40.911Z" }, { url = "https://files.pythonhosted.org/packages/7e/44/96e8c81867ba8a45ff893c8e7474c2d6b9633f7aa663da7901d040214d3e/charset_normalizer-3.4.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b4e4d44b8287aa13a25e16e29393d494b0643b24894f7c8266c6f6788dd36337", size = 217096, upload-time = "2026-07-06T15:26:42.148Z" }, { url = "https://files.pythonhosted.org/packages/a5/bf/4d53f04f29bdb22601701f4f9f4d038edfb27976c296fcb7400c02736a6e/charset_normalizer-3.4.8-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f68545d1b267dbfafd5d253b6d1cb161562c4e61ab25b5c4cdb7d9e5923e441e", size = 209355, upload-time = "2026-07-06T15:26:43.557Z" }, { url = "https://files.pythonhosted.org/packages/ad/60/92b3f630798d777fa880ad289a3f9f2fc663e4b4beb24783c53318820254/charset_normalizer-3.4.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1936e48214adea74922a20c8ab41b1393ae27cc9e329eb1f0b937d3416824f36", size = 224732, upload-time = "2026-07-06T15:26:44.892Z" }, { url = "https://files.pythonhosted.org/packages/bd/85/eafa0a3c7bb6fe9f02f4c7901f02071933cac85ee634197e17280818c6de/charset_normalizer-3.4.8-cp313-cp313-win32.whl", hash = "sha256:1f8e3521860187d597f3867d8466da225b9179ea2833bb26de1bb026144d07c3", size = 150358, upload-time = "2026-07-06T15:26:46.153Z" }, { url = "https://files.pythonhosted.org/packages/f5/8c/879fafff7b47bb1166d289f2d2472cb31b9922f9f4ca1f392edf85ec16be/charset_normalizer-3.4.8-cp313-cp313-win_amd64.whl", hash = "sha256:8b654b6f52a0a9a6be38e88f3e1dc68f1093ebeb2abbadafc7c82da0786a34be", size = 161685, upload-time = "2026-07-06T15:26:47.423Z" }, { url = "https://files.pythonhosted.org/packages/c3/46/b57c7e778a7b578f28d35fd38544687d4f8d9c019585eebc5ad936073fad/charset_normalizer-3.4.8-cp313-cp313-win_arm64.whl", hash = "sha256:d2d5a250ee26e29468b7607d97479221b069fa8aaf6f929ac84ec0e962e15154", size = 152333, upload-time = "2026-07-06T15:26:48.689Z" }, { url = "https://files.pythonhosted.org/packages/1c/bc/0a8540b8cd494951cca1428606373942803f5ffcec40fe798f819c5a8adb/charset_normalizer-3.4.8-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:77e993ecf65f21ab1f82266ff5e84a7de2c879e7d9b8bc006009df83f22a1d5e", size = 316993, upload-time = "2026-07-06T15:26:49.962Z" }, { url = "https://files.pythonhosted.org/packages/0e/99/a0868f0a1f0a045fd374d1f2cf7042d8ad5d7fb4dd1f4ac7365e319f7e32/charset_normalizer-3.4.8-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:524939917f17f6de502dfda30b472550965740d7f126659d4c4f8dd1569cce22", size = 215638, upload-time = "2026-07-06T15:26:51.338Z" }, { url = "https://files.pythonhosted.org/packages/e8/e9/43c4d09a09b5557cc5fe1d87c9d96f86a3942aec0517d2b5408cef87ca75/charset_normalizer-3.4.8-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a4508989ba8e2ce43ef989453d18188b261546e8188cbdd4ef451fb9e4c3b467", size = 236456, upload-time = "2026-07-06T15:26:52.531Z" }, { url = "https://files.pythonhosted.org/packages/e2/67/492ca98b3ab785b736b5da10c1bc233e1c8fec6c0cdb29b482c38bfc52a2/charset_normalizer-3.4.8-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9e44127f7d11eee4548ad2cdf1f4e1b6eaaddd5cb92d15ad65f6ecc9bcf403ab", size = 232253, upload-time = "2026-07-06T15:26:53.838Z" }, { url = "https://files.pythonhosted.org/packages/2d/fd/1e6eff58c14f1aace1e26d80defbeaea2d35e075dbe4b611111ee4b47fa8/charset_normalizer-3.4.8-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bb90317359f7e67bb6df615999a95e0980877468e617ddce8b6c2f8e7fe60d95", size = 222886, upload-time = "2026-07-06T15:26:55.009Z" }, { url = "https://files.pythonhosted.org/packages/40/7a/90056a5326b0c4b9a3f924d337729c344c11542e5bc7191e50410db61587/charset_normalizer-3.4.8-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:35d9e7a9c960520ae89d1f4e305d1c047a74dea2e0f73a0e84f879356c2e8776", size = 206482, upload-time = "2026-07-06T15:26:56.306Z" }, { url = "https://files.pythonhosted.org/packages/18/ff/94761d31a33878dbb5008ddbd918615061fcf5c0a612aa3075450e60f628/charset_normalizer-3.4.8-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:92e322b054c7ff886f78feab7360736bb45de2e18cf4a0ee84e8fc5a08d53a19", size = 218929, upload-time = "2026-07-06T15:26:57.422Z" }, { url = "https://files.pythonhosted.org/packages/2b/dc/00b9675acd7c4b926b9102ee3f0d1a570ce943901be73b87485001393fe1/charset_normalizer-3.4.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:3c0086d97094363556206dc3bcf43f7edcfc043ea7a568a46f45efea74858bd1", size = 218069, upload-time = "2026-07-06T15:26:58.719Z" }, { url = "https://files.pythonhosted.org/packages/04/11/94ada5a0482ee4bf688d04be4c7d6fd945d37370d04a95671040dfe2b416/charset_normalizer-3.4.8-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:0752c849b51198267df2aba013c4de3a2955bd014a4fd70828809946c1acbc0c", size = 207146, upload-time = "2026-07-06T15:27:00.058Z" }, { url = "https://files.pythonhosted.org/packages/7c/f7/246bd36762207ab4752cd436b64e5d81a1668b15ddea7b5b2d0e8545e727/charset_normalizer-3.4.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2a4707e09eca11e81ece4fced600c5a0a801f568b962244f6f517bc274745fc9", size = 224896, upload-time = "2026-07-06T15:27:01.599Z" }, { url = "https://files.pythonhosted.org/packages/6f/f7/3510622d1fbe13b0ebf827c475e40a27e2be427140d792878b63ab6425cc/charset_normalizer-3.4.8-cp314-cp314-win32.whl", hash = "sha256:8ea67f427c073ae3da0923aa55f3715131fa613a61a7f2f8d762bde75eaf00ae", size = 150851, upload-time = "2026-07-06T15:27:02.964Z" }, { url = "https://files.pythonhosted.org/packages/32/2b/9ce65dd21672b55cf800cca5f4433afa1586fda1d78731067ec9ec544c62/charset_normalizer-3.4.8-cp314-cp314-win_amd64.whl", hash = "sha256:ff71018850863362e5c7533769d0a9f77715c31af1502d523630ce822922f5c9", size = 162549, upload-time = "2026-07-06T15:27:04.249Z" }, { url = "https://files.pythonhosted.org/packages/2f/34/9a5967eed666a88f31a0866884606d9ec3c2cd6091e2ccd7e0b4c4176c35/charset_normalizer-3.4.8-cp314-cp314-win_arm64.whl", hash = "sha256:44464e66f4da2f21dea7145c7693f9f60717ca4794a954dea5bf8c2c932678bd", size = 153079, upload-time = "2026-07-06T15:27:05.608Z" }, { url = "https://files.pythonhosted.org/packages/02/4f/aa44cc81d8987f105352c74c0bf919007f8b80e9880d28bcf0393c1a816e/charset_normalizer-3.4.8-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:50a0c2e58ad2c203adb616fef28941b7e13716adbc25e0dfaeec29f5afe6382f", size = 338586, upload-time = "2026-07-06T15:27:06.86Z" }, { url = "https://files.pythonhosted.org/packages/1d/2b/b0392e2b235c08ff0623d905c2ee8ac820620544043c1ce92ce0b3d64c55/charset_normalizer-3.4.8-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1e589fdb95c76f08288bbb346230cdd8994db74903db6637b380f7b5fc9336", size = 222764, upload-time = "2026-07-06T15:27:08.23Z" }, { url = "https://files.pythonhosted.org/packages/a2/a1/7d466879190731f5559662c22232646f2ae2dace2323c3e5aefcf78d458a/charset_normalizer-3.4.8-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b3d7c887444c5a7ef0d68d358d81e758a850bc626f8e639e2ca5667153272b20", size = 241331, upload-time = "2026-07-06T15:27:09.512Z" }, { url = "https://files.pythonhosted.org/packages/70/17/8b89e797137aa28c8fb0bafbafc243246a7afe21620a13b00e37624ece1d/charset_normalizer-3.4.8-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:65c389b96c0cfff3a3f0458fa1c7ce554a30e23101a88a49f03997afce6a929f", size = 239323, upload-time = "2026-07-06T15:27:10.86Z" }, { url = "https://files.pythonhosted.org/packages/d7/98/1c1940730ed22d50983be4e243c722c89d5136d6f073bd840d1128bfddcb/charset_normalizer-3.4.8-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:593403fc47dcdf55e2987b2e3cc2e064127e2b908929f1f18b2e4a4652cbd780", size = 229964, upload-time = "2026-07-06T15:27:12.113Z" }, { url = "https://files.pythonhosted.org/packages/53/2d/bb8e81b7ff603d3f77e9a8a5d1ad34fcabbf3c54d300c29d99fba581fa23/charset_normalizer-3.4.8-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:606088e9fa2b7469ab9c42d4da8e05a415622a07714edd2fcd8fed48dda4c853", size = 212405, upload-time = "2026-07-06T15:27:13.447Z" }, { url = "https://files.pythonhosted.org/packages/ce/1f/e52a3a53b13da591bb8f21d29e63877268eadf20686b7762351d4b89062c/charset_normalizer-3.4.8-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0317406326fed512f42a1632ad91a96228a7616c06547666a6dd79967f1bd6ca", size = 226918, upload-time = "2026-07-06T15:27:14.89Z" }, { url = "https://files.pythonhosted.org/packages/e8/f9/32996d79c57189af9722fe618f46d8a86b7be035ca98887b8d0c3821f141/charset_normalizer-3.4.8-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:b67d50ee47e5c57a0064a9cb575b963a7125819dfd1fd094d44d378fff94659b", size = 225113, upload-time = "2026-07-06T15:27:16.125Z" }, { url = "https://files.pythonhosted.org/packages/d6/d2/9248c18e695696513774523a794cfb8b677521ce9ad7554d301cb10a9b20/charset_normalizer-3.4.8-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:79e402b869f270140afa5e2b0e2ac100585358d812fe3dd093d424f7a72964e0", size = 214966, upload-time = "2026-07-06T15:27:17.418Z" }, { url = "https://files.pythonhosted.org/packages/1e/9d/4b19432d406179a40f924691906ee5b15ac664b408971c973295192444ea/charset_normalizer-3.4.8-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2970b9f7ab69ec3a0423ec6b6ac718e79fbf4a282c0bc103ef88c1ef50dfa15a", size = 231699, upload-time = "2026-07-06T15:27:19.131Z" }, { url = "https://files.pythonhosted.org/packages/be/41/bdbdf71e8c3ccff10ef3cc2bb9467a7fdb3dc94b9a406d1a3c44afd39632/charset_normalizer-3.4.8-cp314-cp314t-win32.whl", hash = "sha256:458c2972a78043b7261c9726670029f15f722e70669bcbe961153a01968f589f", size = 155333, upload-time = "2026-07-06T15:27:20.681Z" }, { url = "https://files.pythonhosted.org/packages/bd/f8/e05c69323bd50091ec39f5f885385b884624b0131a6885a0c83a6217ba7a/charset_normalizer-3.4.8-cp314-cp314t-win_amd64.whl", hash = "sha256:0c926329a1df7cd56d7d8349fe354460d20aefd2e394c9e159e479d018b2b359", size = 167378, upload-time = "2026-07-06T15:27:22.042Z" }, { url = "https://files.pythonhosted.org/packages/c2/04/cbaf1a2f5e2bbf70760e774380cbf052b10849fc35e770905df31af5cf00/charset_normalizer-3.4.8-cp314-cp314t-win_arm64.whl", hash = "sha256:2232baea80a2b01783679fed4e625ccdb19a974f44c9cf0fba21a777a4c8179c", size = 157782, upload-time = "2026-07-06T15:27:23.312Z" }, { url = "https://files.pythonhosted.org/packages/23/52/d5bee5b6ea81882d549b566d2545b044bbcbc33fe5fbe001008a7e745a21/charset_normalizer-3.4.8-py3-none-any.whl", hash = "sha256:b7c1fb310df524e01fbe84d43b7f95aa4f808f8eaa0dafc185f64ba395e37d54", size = 64279, upload-time = "2026-07-06T15:27:57.043Z" }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] name = "coverage" version = "7.15.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/cc/8b/adeb62ea8951f13c4c7fef2e7a85e1a06b499c8d8237ea589d496029e53f/coverage-7.15.0.tar.gz", hash = "sha256:9ac3fe7a1435986463eaa8ee253ae2f2a268709ba4ae5c7dd1f52a05391ad78f", size = 925362, upload-time = "2026-07-02T13:10:50.535Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ae/23/82e910835ef4b8391047025e1d53aa48d66029f444eb8b25373c849bf503/coverage-7.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:003fff99412ea848c0aaebcc78ed2b6ce7d8a1227ed17e68470672770b78a02a", size = 220662, upload-time = "2026-07-02T13:08:39.205Z" }, { url = "https://files.pythonhosted.org/packages/6d/0d/c7b213dde2f1579de5231062b386d8413f79c11667eb58c39319b25991da/coverage-7.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5cbd804bf2784ce7b45114516050f346ecd50f960c4bb630a7ee9e1d78fa2118", size = 221168, upload-time = "2026-07-02T13:08:40.471Z" }, { url = "https://files.pythonhosted.org/packages/33/77/d000aeedfac085088337b3c7becdad328474b1f8a9e4c9368a0c99605d68/coverage-7.15.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8773e15c23305b58882a4611fb9b2755977eae0dc2e515366a1b6c98866cc4c2", size = 251587, upload-time = "2026-07-02T13:08:42.033Z" }, { url = "https://files.pythonhosted.org/packages/cc/e0/86787c56b9df17afd370d5e293515dd4d9a107a561d13054873eefad8ecc/coverage-7.15.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f50e40081494c1dc4239ebb202014cbcc3306ea96fb6302a34c8cc0967fc5ae8", size = 253497, upload-time = "2026-07-02T13:08:43.387Z" }, { url = "https://files.pythonhosted.org/packages/3f/02/181bc917359299c07dead6270f94e411151c8b60cec905c33499da69afe6/coverage-7.15.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daf96f37f5fc3a7b6c6da862eb4aee61c426bd63da236ed4a73ef0e503b4bca5", size = 255607, upload-time = "2026-07-02T13:08:44.897Z" }, { url = "https://files.pythonhosted.org/packages/b9/35/ca5e7427699913da6788c4f910e73ab16c5f4b59ec5d3a999dce2a45112f/coverage-7.15.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:51aa20f6ae2788fd197747766edf4cd8234fd9423309b934257fa6b21a592723", size = 257563, upload-time = "2026-07-02T13:08:46.334Z" }, { url = "https://files.pythonhosted.org/packages/0b/4d/b8220bacc2fc3c4e9078e27c32e99fb411479a4718a72bdd00036a9891c8/coverage-7.15.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:03d1f922757662eb7af586e77834792274cff776bc7b1d1a0b66a49ea9d84735", size = 251726, upload-time = "2026-07-02T13:08:47.941Z" }, { url = "https://files.pythonhosted.org/packages/c4/e4/2e145da1991d72189b9c3cf7eca05c716ee7080d099aaea6757cfc7df008/coverage-7.15.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a6d6acc9a7666245e6133dd15144ca038a85a9cd5026bb06d6bbae9e77440dc9", size = 253301, upload-time = "2026-07-02T13:08:49.5Z" }, { url = "https://files.pythonhosted.org/packages/72/28/d2c841d698bf762e481f08bd4839d370246b6d9b61dab085a7b20b201a08/coverage-7.15.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1ac2c4c27c7df851dc9a017c2d7de00b69147e84ba3d96f37a530b0b6fb51035", size = 251361, upload-time = "2026-07-02T13:08:51.304Z" }, { url = "https://files.pythonhosted.org/packages/9d/ed/55d9ffde994fba3897c0c783f77a7d053b0c18787f6892ed5b0aed73f469/coverage-7.15.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b761a1d504fd4bd1f20f418753964dca9f5862a511fc854dac58296b3b223671", size = 255129, upload-time = "2026-07-02T13:08:52.661Z" }, { url = "https://files.pythonhosted.org/packages/1d/c0/ecbf33b8c460ea2718aeb813e2df8140d0370e5f67261c31524ceb0a2a8d/coverage-7.15.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:e43b045e11c16e897895758ae90e4a90cf99e93d58549e2f90c0e2272e155695", size = 251081, upload-time = "2026-07-02T13:08:54.188Z" }, { url = "https://files.pythonhosted.org/packages/a9/de/fb87b4261f54448dd2b9504ef19a58be42cef0d9520595fbfe1219b15234/coverage-7.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:589b54513e901739f4b4582c705ce96b80c96f57641b1464607e2367a270e540", size = 251988, upload-time = "2026-07-02T13:08:55.726Z" }, { url = "https://files.pythonhosted.org/packages/df/27/3494d5f291b9a4cb868f73c11221a8bd2d5bd761a8f9acea61ff57128dd1/coverage-7.15.0-cp311-cp311-win32.whl", hash = "sha256:106781b8482749162d0b47056937ba0933508e5d9447f65a5e7d5c422f0d6bb4", size = 222754, upload-time = "2026-07-02T13:08:57.091Z" }, { url = "https://files.pythonhosted.org/packages/2a/ee/cd4847ebc9be6a9c0123d763645a6f1f3be6b8c58c962706368b79cbac07/coverage-7.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:821e92b3631d762a339695824cadbbc73020354eba2a23a551a99ad34938fbe6", size = 223225, upload-time = "2026-07-02T13:08:58.594Z" }, { url = "https://files.pythonhosted.org/packages/57/37/5011581aa7f2be498b97dcc7c9902192442a42f4f9a748aeadb3d6506b42/coverage-7.15.0-cp311-cp311-win_arm64.whl", hash = "sha256:309990eb5fb8014b9f67cb211f7fd41876ec8a88a88d3ae76de0ed1d611e3640", size = 222774, upload-time = "2026-07-02T13:09:00.074Z" }, { url = "https://files.pythonhosted.org/packages/2a/74/fd4c0901137c4f8d81a76ada99e43c65163b4c94a02ece107a4ec0c6b615/coverage-7.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b75ee5e8cb7575636ac598719b4307ac529ec8fcd79608a35c3cd4d4dada812d", size = 220838, upload-time = "2026-07-02T13:09:02.084Z" }, { url = "https://files.pythonhosted.org/packages/0f/2e/2347583467bd7f0402635101a916961915cc68fce652cd0db5f173ea04fc/coverage-7.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffb31267816b93b075302248cc1737506081b4f163df4401e9df1a6424aafabe", size = 221197, upload-time = "2026-07-02T13:09:03.617Z" }, { url = "https://files.pythonhosted.org/packages/f0/17/99fa688541ae1d6e84543a0e544f83de0c944815b63e9e7b1ed411d15036/coverage-7.15.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e4d0bb73455bf97ab243a8f12c37c686ccf1c13bb614b7b85f1d062f06f42b2c", size = 252705, upload-time = "2026-07-02T13:09:05.059Z" }, { url = "https://files.pythonhosted.org/packages/fb/02/6a95a5cd83b74839017ef9cf48d2d8c9ae60af919e17a3f336e6f9f1b7bd/coverage-7.15.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:20d9ccc4ebd0edc434d86dfd2a1dd2a8efa6b6b3073d0485a394fee86459ebb4", size = 255441, upload-time = "2026-07-02T13:09:06.559Z" }, { url = "https://files.pythonhosted.org/packages/67/f2/406f6c57d600f68185942422c4c00f1a3255d60aee6e5fd961425cd9987e/coverage-7.15.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:20c8a976c365c8cb12f0cbd099508772ea41fb5fa80657a8506df0e11bd278c5", size = 256556, upload-time = "2026-07-02T13:09:08.197Z" }, { url = "https://files.pythonhosted.org/packages/74/8e/d3fa48489c15ecdec1ba48fd61f68798555dddd2f6716f9ad42adeb1a2a9/coverage-7.15.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f948fd5ba1b9cbca91f0ae08b4c1ce2b139509149a435e2585d056d57d70bf01", size = 258815, upload-time = "2026-07-02T13:09:09.691Z" }, { url = "https://files.pythonhosted.org/packages/47/2e/2d40ddd110462c6a2769677cf7f1c119a52b45f568978fc6c98e4cc0dd0f/coverage-7.15.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f58185f06edf6ad68ec9fb155d63ef650c82f3fbd7e1770e2867751fb13158f4", size = 253117, upload-time = "2026-07-02T13:09:11.212Z" }, { url = "https://files.pythonhosted.org/packages/51/c0/310782f0d7c3cb2b5ac05ba8d205fe91f24a36f6bf3256098f1782181c38/coverage-7.15.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02adc79a920c73c647c5d117f55747df7f2de94571884758ce8bc58e04f0a796", size = 254475, upload-time = "2026-07-02T13:09:13.029Z" }, { url = "https://files.pythonhosted.org/packages/86/f7/702da6c275f8ae6ade423d2877243122932c9b27f5403003b9ef8c927d12/coverage-7.15.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6eb7c300fbed667fd6e3588eba71c1904cdb06110ca6fdf908c26bdd88b8e382", size = 252619, upload-time = "2026-07-02T13:09:14.699Z" }, { url = "https://files.pythonhosted.org/packages/fb/84/c5b15a7e5ecba4e56218d772d99fe80a63e63f8d11f12783723a6005ab45/coverage-7.15.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b5fb23fa2de9dce1f5c36c09066d8fcda16cd96e8e26686caa2d7cb9b567d65c", size = 256689, upload-time = "2026-07-02T13:09:16.103Z" }, { url = "https://files.pythonhosted.org/packages/95/2f/c8b07559b57701230c61b23a953858c052890c12ef568d81780c6c46e92e/coverage-7.15.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:cec79341dbe6281484024979976d0c7f22beae08b4a254655decd25d42cbe766", size = 252189, upload-time = "2026-07-02T13:09:17.828Z" }, { url = "https://files.pythonhosted.org/packages/6b/80/6d2f049dd3fd3dbfd60b62ba6b2162a04009e2c002ce70b24cf3878dec7a/coverage-7.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c664c5444b1d970b1b2a450e21fb19ee5c9cfdf151ded2dda37260031cca0da", size = 254059, upload-time = "2026-07-02T13:09:19.304Z" }, { url = "https://files.pythonhosted.org/packages/ce/92/b0287a2c42031d25c628f815f89a3cd9f8268ee78bb1252c9356cda1c689/coverage-7.15.0-cp312-cp312-win32.whl", hash = "sha256:5f764a3fa339bde6b3aa97657f5a6a3a9451e4a5b4ea98a2892c773a43525f77", size = 222893, upload-time = "2026-07-02T13:09:20.812Z" }, { url = "https://files.pythonhosted.org/packages/a9/69/e34c481915fecb499b3146975061dac528752e37706edc1804f32c822469/coverage-7.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:52f9a4d2c4c56c8848bc2f524916698354b0211488b38c49ad9ae54f6cafbff6", size = 223429, upload-time = "2026-07-02T13:09:22.315Z" }, { url = "https://files.pythonhosted.org/packages/fe/98/6e878f0b571d32684ef3f38d7c03db241ca5b82a5da8a5391596a8f209c4/coverage-7.15.0-cp312-cp312-win_arm64.whl", hash = "sha256:31e5c3e70c85307ea35a12964e2e40f56ca2ee4b1c8c721ccf4609d17071080b", size = 222810, upload-time = "2026-07-02T13:09:23.812Z" }, { url = "https://files.pythonhosted.org/packages/76/04/145a3748098bcc86b631a85408d2c3dc5c104e0bd86d605468239b25b6c4/coverage-7.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5be4caf3b28836f078abe700f8944dac4a65d78f16d6c600c89cb624e5535782", size = 220863, upload-time = "2026-07-02T13:09:25.371Z" }, { url = "https://files.pythonhosted.org/packages/a4/5c/4ed55708fed2c64b63c9bc5715daef670872202101938869b7fe5d5fbb8f/coverage-7.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dd58ad1404704303ca8d4f4b8a1095e7cbc7040ef17a66df1e6619aa10176430", size = 221230, upload-time = "2026-07-02T13:09:26.897Z" }, { url = "https://files.pythonhosted.org/packages/7b/19/3a80b97d3b2a5c77a01ae359c6bed20c13738fe3d9380f08616d4fec0281/coverage-7.15.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bbcbb317c2e5ded5b21104af81c29f391be2af98d065693ffbe8d23949b948e5", size = 252227, upload-time = "2026-07-02T13:09:28.543Z" }, { url = "https://files.pythonhosted.org/packages/a1/fa/b70062750686bd7da454da27927622f48bbac6990ac7a4c4a4653e7b0036/coverage-7.15.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:27f31ecb458da3f859aab3f15ada871eb7a7768807d88df4a9f186bb17737970", size = 254823, upload-time = "2026-07-02T13:09:30.177Z" }, { url = "https://files.pythonhosted.org/packages/a9/09/dad6a75a2e561b9dc5086a8c5257a7591d584246f67e23e70d2995b89ab6/coverage-7.15.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13fb759be317fdc62e0f56bffdf61cfcb45c7761ad6b71e3e583e71a67ae753c", size = 256059, upload-time = "2026-07-02T13:09:31.979Z" }, { url = "https://files.pythonhosted.org/packages/e6/e7/b5d2941fa9564573d44b693a871ff3156f0c42cbefe977a09fa7fdc59971/coverage-7.15.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d5cf007add5ab4bb8fa9f4c77e3732127c9e6cad501d7db43355fbfafca0be84", size = 258190, upload-time = "2026-07-02T13:09:34.035Z" }, { url = "https://files.pythonhosted.org/packages/7c/1d/8e895bcde3c57ccd46d896dda5f2b3d5df761a1b0c6c9d450d175dedc632/coverage-7.15.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cc78d9843bd576fbe2118248258d485e968dc535f95ed504a7b0867ba9b51389", size = 252456, upload-time = "2026-07-02T13:09:35.765Z" }, { url = "https://files.pythonhosted.org/packages/14/4c/f6997da343ddeb959be82c3b05322793f92c071ad45f7cb8a96336e2dd5f/coverage-7.15.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a263060f1de0b4b74b4e089c2a70b8003b3781c733329a9c8fd54995328f9950", size = 254192, upload-time = "2026-07-02T13:09:37.445Z" }, { url = "https://files.pythonhosted.org/packages/17/27/a0bc09d032267b9da89d95a2d874cfbef2a5aebbf0e87cf7aba221d79a99/coverage-7.15.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c48decf16e0dfd5b049c7d5e82200c23c08126719142998d4f172444e3d0529e", size = 252153, upload-time = "2026-07-02T13:09:39.422Z" }, { url = "https://files.pythonhosted.org/packages/54/c0/77fc233d9fba07b244c40948c53fe27308b8f21732fb3417f87fbd6fd992/coverage-7.15.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:08fb028000ed0aaa0a4cbdfbb98be7cb42f370db973fbbb469733505ab20e13e", size = 256310, upload-time = "2026-07-02T13:09:41.006Z" }, { url = "https://files.pythonhosted.org/packages/d5/24/601cecfb5825becacb8d45219a018a3b55b9dbaec624efdb0ea249d08be2/coverage-7.15.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb7dc0c3b7d8a1077abea0b8546ebc5e26d6ef6ecefc2f0f5ad2b8a53bdad837", size = 251974, upload-time = "2026-07-02T13:09:42.733Z" }, { url = "https://files.pythonhosted.org/packages/47/1e/6f45e5a5b3d5484318d368702af6716b5ab8913b0428bec981a562fcf296/coverage-7.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6cb3602054ccbe9f0d8c2dc04bbeba90d5719236e2cd06e042ddd6d3fc7b6e37", size = 253745, upload-time = "2026-07-02T13:09:44.376Z" }, { url = "https://files.pythonhosted.org/packages/8e/db/4df027a77bd11d0e527f44c53557c76e54ad027413d0304252ea3a78d67e/coverage-7.15.0-cp313-cp313-win32.whl", hash = "sha256:0bf781da64326b677be344df505171435b6f58716108606621d5d27d964fff8b", size = 222902, upload-time = "2026-07-02T13:09:46.122Z" }, { url = "https://files.pythonhosted.org/packages/a0/10/0355894d34e231f2c5449e71287e81a50793a325df2e2b027b7bcd9dfd19/coverage-7.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:2c57a275078ee3fa185f83e400f765bc764a549de66d99b47881645cbd4ea629", size = 223444, upload-time = "2026-07-02T13:09:47.687Z" }, { url = "https://files.pythonhosted.org/packages/06/ef/bb725f263befaaff851203ab338e68af15e195d7f7b5f323162532d9b6a8/coverage-7.15.0-cp313-cp313-win_arm64.whl", hash = "sha256:3812c61afc6685c7999b39320779ab8f43b7a3081fdb0def39976e56fbdb9a21", size = 222839, upload-time = "2026-07-02T13:09:49.717Z" }, { url = "https://files.pythonhosted.org/packages/4f/9c/1e3ca54f72a3185ece06c58d871099898c48f0ed6430d17b6ab75f0d180a/coverage-7.15.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:41cb79af843222e11da87127ad0ecbfa878abadd0f770a4a99391a27d3887324", size = 220906, upload-time = "2026-07-02T13:09:51.339Z" }, { url = "https://files.pythonhosted.org/packages/09/37/f718613d83b274880382f6b67e78f3802549ae39b0b3e65ae5b5974df56e/coverage-7.15.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7d2008989ef8fe54188d3f3bfa2e3099b025af11e90a6a1b9e7dc433d04263d8", size = 221239, upload-time = "2026-07-02T13:09:53.138Z" }, { url = "https://files.pythonhosted.org/packages/a7/ce/22bae91e0b75445f68d365c7643ed0aa4880bbf77450ee74ca65bdae53a7/coverage-7.15.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:769e8ece11a596315ebf5aa7ec383aeeed016c091d2bf6363ffb996d41529092", size = 252286, upload-time = "2026-07-02T13:09:54.996Z" }, { url = "https://files.pythonhosted.org/packages/dd/1e/bec5e32aa508615d9d7a2790effb25fb4dc28606e995816afe400b25ece3/coverage-7.15.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:65a6b6164ee5c39e2f3803f314292d6c61a607ba7fee253d1e03c42dc3903502", size = 254789, upload-time = "2026-07-02T13:09:56.678Z" }, { url = "https://files.pythonhosted.org/packages/17/29/0e865435b4354e4a7c03b1b7920046d31d0a273d55decefea27e011cb9bf/coverage-7.15.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75128817f95a5c45bb01d65fd2d8b9cb54bbe03d81608fb70e3e14b437ad56c2", size = 256135, upload-time = "2026-07-02T13:09:58.343Z" }, { url = "https://files.pythonhosted.org/packages/84/ff/33a870b58a13325d62fc0a6c8f01fa0ff667cef60c7498e2382a147dfa18/coverage-7.15.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9887bb428fe2d4cd4bee89bac1a6c9932f484afd5b36fbd4ff6ea5f825bb1f5e", size = 258449, upload-time = "2026-07-02T13:10:00.057Z" }, { url = "https://files.pythonhosted.org/packages/18/7b/6fffe596bf3ddba8462758d02c5dad730fd91055a6634aa2e4226229181a/coverage-7.15.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0bfc0be1f702042207a93a00523b1065ee1fe951e96edf311581c0bbc2e34888", size = 252313, upload-time = "2026-07-02T13:10:01.946Z" }, { url = "https://files.pythonhosted.org/packages/58/1b/11468dd6c1676ab831a70cb9a8d4e198e8607fa0b7220ab918b73fe9bfbd/coverage-7.15.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f64627d55def5a43282d70e08396672692f77e4da610a5bb8bb4060b432b6859", size = 254142, upload-time = "2026-07-02T13:10:04.065Z" }, { url = "https://files.pythonhosted.org/packages/79/41/29328e21d16b1b95092c30dd700e08cf915bd3734f836df8f3bdb0e8fa9f/coverage-7.15.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2c6f0fa473003905c6d5bac328ee4eba9fbea654f15bc24b8a3274b23363fa99", size = 252108, upload-time = "2026-07-02T13:10:06.11Z" }, { url = "https://files.pythonhosted.org/packages/9b/de/05ccfb990439655b35afbfd8e0d13fe66677565a7d4eb38c3f5ef2635e1c/coverage-7.15.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2bcf9afaf064172c6ec3c58a325a9957ad1178c05dd934e25f253321776e0676", size = 256385, upload-time = "2026-07-02T13:10:08.141Z" }, { url = "https://files.pythonhosted.org/packages/51/0e/486828a3d2695ea7a2609f17ff572f6b01905e608379440a11da4b8dffbe/coverage-7.15.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:baf06bc987115d6fb938d403f7eab684a057766c490367999a2b71a6883110c6", size = 251923, upload-time = "2026-07-02T13:10:10.179Z" }, { url = "https://files.pythonhosted.org/packages/18/c7/03582b6715f078e5e558354c87616d945b9894cda2dace8e4009b17035e4/coverage-7.15.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f0405f2ff97b1c4c0e782cb32e02f32369bcf2e6b618b591d67e1ea754575dfe", size = 253580, upload-time = "2026-07-02T13:10:12.052Z" }, { url = "https://files.pythonhosted.org/packages/db/dc/9e578bbaf2ecb4959a81b7e7601ad8cca772cba2892e8d144cb749b4a71a/coverage-7.15.0-cp314-cp314-win32.whl", hash = "sha256:ab282853ed5fbd64bbb162f19cb8fcb7087187508a6374b4f9c34ec1577c4e8f", size = 223107, upload-time = "2026-07-02T13:10:13.994Z" }, { url = "https://files.pythonhosted.org/packages/ae/3e/c8c3b75d8dbe0e35f7b0cc3ff5e949fc59500f70b21d0398813f66740664/coverage-7.15.0-cp314-cp314-win_amd64.whl", hash = "sha256:3bb3040e9f4bbe26fcb0cd7cc85ac63e630d3f3a9c74f027abf4caa27e706663", size = 223597, upload-time = "2026-07-02T13:10:15.906Z" }, { url = "https://files.pythonhosted.org/packages/cd/bc/3cbc9fb036eb388519bccd521f783499c39b64256013fbc362782f196fe1/coverage-7.15.0-cp314-cp314-win_arm64.whl", hash = "sha256:346771144d34f7fa84ec28386f78e0f31653f33cf35e19d253d5b35f9e8201da", size = 223020, upload-time = "2026-07-02T13:10:17.844Z" }, { url = "https://files.pythonhosted.org/packages/28/00/199c4a8d656dff63102577a056c0fce2ff6a79e40adac092fc986c49cbf1/coverage-7.15.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d34a010905fb6401324ba016b5da03d574967f7b21ce48ea41e66f0f1f95f641", size = 221638, upload-time = "2026-07-02T13:10:19.703Z" }, { url = "https://files.pythonhosted.org/packages/ba/8e/9d0092c96a3d3a26951ecc7020826aa57bcb1b119ca81acbba996884ab13/coverage-7.15.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:bb25d825d885ca8036795dacfc3924d33091fc76d71ebc99420c6b79e77d96fa", size = 221903, upload-time = "2026-07-02T13:10:21.514Z" }, { url = "https://files.pythonhosted.org/packages/6d/b4/c0ca3028f42c9a08e51feb4561ef1192e5de99797cd1db5b04590c215bda/coverage-7.15.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:94c9686bfe8a9a6810297aecbd99beaa3445f9e8dc2f80b1382cca0d86b64461", size = 263267, upload-time = "2026-07-02T13:10:23.261Z" }, { url = "https://files.pythonhosted.org/packages/5f/aa/a375e3846e5d3c013dc600b2a3231089055c73d77f5393dd2192a8d64da6/coverage-7.15.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9bd671c25f9d85f09d7ec481d0e43d5139f486c06a37139847a7ce569788af72", size = 265390, upload-time = "2026-07-02T13:10:25.152Z" }, { url = "https://files.pythonhosted.org/packages/92/e1/5783cdabb797305e1c9e4809fea496d31834c51fa772514f73dc148bcfc9/coverage-7.15.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:110cbdf8d2e216577312cf06ccf85539c0e5a5420ef747e4a4719b5e483c88cd", size = 267811, upload-time = "2026-07-02T13:10:27.249Z" }, { url = "https://files.pythonhosted.org/packages/85/31/96d8bbf58b8e9193bc8389574a91a0db48355ee98feb66aa6bf8d1b32eea/coverage-7.15.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2c5d4619214f1d9993e7b00a8600d14614b7e9d84e89507460b126aa5e6559e5", size = 268928, upload-time = "2026-07-02T13:10:29.242Z" }, { url = "https://files.pythonhosted.org/packages/5e/7a/5294567e811a1cb7eda93140c628fa050d66189da28da320f93d1d815c73/coverage-7.15.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:781a704516e2d8346fbbd5be6c6f3412dd824785146528b3a01816f26c081007", size = 262378, upload-time = "2026-07-02T13:10:31.107Z" }, { url = "https://files.pythonhosted.org/packages/69/3f/3f48538421f899f28946f90a3d272136a4686e1abf461cc9249a783ee0f3/coverage-7.15.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd4a1b44bcb65ee29e947ac92bbee04956df3a6bfc6143641bb6cae7ede00fc9", size = 265263, upload-time = "2026-07-02T13:10:32.942Z" }, { url = "https://files.pythonhosted.org/packages/ce/d3/092df15efcab8a9c1467ee960eb8019bbad3f9300d115d89ea6195f369ff/coverage-7.15.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:0e4950c9d6d3e39c64c991814ff315e2d0b9cb8152363594212c9e55208c0a8f", size = 262866, upload-time = "2026-07-02T13:10:35.104Z" }, { url = "https://files.pythonhosted.org/packages/e5/ab/0254d2b88665efb2c57ad368cc77ab5de3435bd8d5add4729c1b0e79431e/coverage-7.15.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:fe9c87ff42e5472d80d21704972e1f96e104a0a599d77c5e35db5a3c562e2571", size = 266599, upload-time = "2026-07-02T13:10:37.05Z" }, { url = "https://files.pythonhosted.org/packages/a8/79/1cfa4023e489ce6fbc7be4a5d442dbc375edb4f4fda39a352cedb53263c2/coverage-7.15.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f00d5ae1dd2fe13fb8186e3e7d37bcbd8b25c0d764ff7d1b32cef9be058510a8", size = 261714, upload-time = "2026-07-02T13:10:38.966Z" }, { url = "https://files.pythonhosted.org/packages/b7/eb/fee5c8665656be63f497418d410484637c438172568688e8ac92e06574e7/coverage-7.15.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:363ab38cc78b615f11c9cac3cf1d7eef950c18b9fdedfb9066f59461dcf84d68", size = 264025, upload-time = "2026-07-02T13:10:40.789Z" }, { url = "https://files.pythonhosted.org/packages/ab/99/63005db722f91edc81abc16302f9cc2f6228c1679e46e15be9ae144b14d0/coverage-7.15.0-cp314-cp314t-win32.whl", hash = "sha256:54fd9c53a5fafff509195f1b6a3f9be615d8e8362a3629ff1de23d270c03c86b", size = 223413, upload-time = "2026-07-02T13:10:42.597Z" }, { url = "https://files.pythonhosted.org/packages/c1/e8/2bc6181c4fb06f1a6b981eb85330cc57bfad7e3f710fc9c9d350013ba228/coverage-7.15.0-cp314-cp314t-win_amd64.whl", hash = "sha256:87b47553097ba185ed964866078e7e63adea9f5f51b5f39691c34f30afd21080", size = 224245, upload-time = "2026-07-02T13:10:44.47Z" }, { url = "https://files.pythonhosted.org/packages/79/b8/4d959bf9cc45d0cfed2f4d35cafcab978cdb6ea02eb5100009cd740632a3/coverage-7.15.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aeefb2dd178fe7eee79f0ad25d75855cb35ee9ed472db2c5ea06f5b4fd00cec5", size = 223558, upload-time = "2026-07-02T13:10:46.368Z" }, { url = "https://files.pythonhosted.org/packages/52/30/21b2ad45959cd50e909e02ebac1e30b4ceb7162e91c11d4c570223a458b7/coverage-7.15.0-py3-none-any.whl", hash = "sha256:56da6a4cbe8f7e9e80bd072ca9cefe67d7106a440a7ec06519ec6507ac94ad19", size = 212632, upload-time = "2026-07-02T13:10:48.641Z" }, ] [[package]] name = "distlib" version = "0.4.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c9/02/bd72be9134d25ed783ecbbc38a539ffaefbf90c78418c7fb7229600dbac7/distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed", size = 615141, upload-time = "2026-06-12T08:04:52.847Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/02/08/9c41fb51ab5b43eb21674aff13df270e8ba6c4b29c8624e328dc7a9482af/distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b", size = 470628, upload-time = "2026-06-12T08:04:50.506Z" }, ] [[package]] name = "docutils" version = "0.22.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968", size = 2291750, upload-time = "2025-12-18T19:00:26.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" }, ] [[package]] name = "execnet" version = "2.1.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, ] [[package]] name = "filelock" version = "3.29.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e0/c8/35bdf04fb30755e2ed758f877edf3eb4a243c2463d3a258cc28b18b7a6e2/filelock-3.29.6.tar.gz", hash = "sha256:895c532ef3f4ef04972b9446a8c4e2931a5c399ff3c4be4c9369f2639b80f793", size = 70301, upload-time = "2026-07-06T23:08:08.577Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/bb/49/7467c2946ccd9617f7da38187071bdc45bb9a95df51f4d63d6622432ce4e/filelock-3.29.6-py3-none-any.whl", hash = "sha256:14d5f5597d2e0c4dbd774cfb6d8132da1db44da83732aab679d54f7dcf97ab65", size = 45478, upload-time = "2026-07-06T23:08:07.197Z" }, ] [[package]] name = "furo" version = "2025.12.19" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "accessible-pygments" }, { name = "beautifulsoup4" }, { name = "pygments" }, { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, { name = "sphinx-basic-ng" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ec/20/5f5ad4da6a5a27c80f2ed2ee9aee3f9e36c66e56e21c00fde467b2f8f88f/furo-2025.12.19.tar.gz", hash = "sha256:188d1f942037d8b37cd3985b955839fea62baa1730087dc29d157677c857e2a7", size = 1661473, upload-time = "2025-12-19T17:34:40.889Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f4/b2/50e9b292b5cac13e9e81272c7171301abc753a60460d21505b606e15cf21/furo-2025.12.19-py3-none-any.whl", hash = "sha256:bb0ead5309f9500130665a26bee87693c41ce4dbdff864dbfb6b0dae4673d24f", size = 339262, upload-time = "2025-12-19T17:34:38.905Z" }, ] [[package]] name = "hypothesis" version = "6.165.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sortedcontainers" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5c/e2/0fad246d2b6330e1f78479bfc566b5c22be82aee8a865cde9a08f648487d/hypothesis-6.165.10.tar.gz", hash = "sha256:68b45e09834cd80523cb1eb274463073c7a9af4e4ef7cff34d9615f355572d32", size = 503703, upload-time = "2026-08-16T22:56:15.404Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/05/c1/9a9538e6d185baf5cc7f15bc3b76e08efbb3de4b3c782f234356449c0dd7/hypothesis-6.165.10-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f839d29d0cc12048cf073d88ca4fdf94d420bc2b8afd69641ff6d496422ccd4f", size = 783243, upload-time = "2026-08-16T22:55:44.058Z" }, { url = "https://files.pythonhosted.org/packages/a1/30/b70d9d79e871a75cbdeccd9067f20ecdb9eb2a1dfa03c630be3ad13b8b30/hypothesis-6.165.10-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:e10858f57ed0e74baa04393845f469fe8ad502c16ece4499bef7700c575611bd", size = 778815, upload-time = "2026-08-16T22:55:46.948Z" }, { url = "https://files.pythonhosted.org/packages/db/52/6f0a9b7aab24b0635e2238f3fbddea5b54b17879ac813df42a3cc3384c5c/hypothesis-6.165.10-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76a7be86d986223b9f1bdb7e7cbcdb048649901fdb956c598ef73bdab1786cd5", size = 1108009, upload-time = "2026-08-16T22:54:53.082Z" }, { url = "https://files.pythonhosted.org/packages/f6/06/8d0d4e11ff02350d09ec9f9e90af354158e59e16a8907ba5199a4ff2d7e8/hypothesis-6.165.10-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:717aea574e0e5edba2868aa66b1caae335d8f1ad3fb29f01dd6502953fa823a1", size = 1136596, upload-time = "2026-08-16T22:54:54.443Z" }, { url = "https://files.pythonhosted.org/packages/59/dd/01a1e440f2e38dc1ccf5d597af5b8a0bee5f21b674c99c123b5554de9690/hypothesis-6.165.10-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4334058033e0214475f019e15492a50f3854fe8728cf51fe25c6191a2c3f8e52", size = 1135234, upload-time = "2026-08-16T22:55:08.911Z" }, { url = "https://files.pythonhosted.org/packages/7d/18/8a26c24d3d9db20265f39df341ab265858c094e209571e3179cf237935f4/hypothesis-6.165.10-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2abb50cf1cf77d721de0a24c3f99d9c4ffdeb2cbd1e12aebb5a7a93e2b6b6d1f", size = 1157528, upload-time = "2026-08-16T22:56:02.159Z" }, { url = "https://files.pythonhosted.org/packages/ea/8e/ce3c829b1937402d7944420ca26a05a0c8563e894dcff03d34ffa279d306/hypothesis-6.165.10-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:3de69aa8b924b400291a3cc42aaf78e6ab65c905a3e7e1a5dc39d95ef1b428cb", size = 1112870, upload-time = "2026-08-16T22:54:55.919Z" }, { url = "https://files.pythonhosted.org/packages/f2/1b/4c4926d6c9a2b5d7cc090cc1e91219d6796102aa2a2c4b8f961c939e60b5/hypothesis-6.165.10-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5841331c504e02d7c334591681cb8587cdd59dee7e149db6d3db8e3f9e9f02eb", size = 1149683, upload-time = "2026-08-16T22:55:30.567Z" }, { url = "https://files.pythonhosted.org/packages/cb/f9/df24eb28412f82465e2b7707f0ff1ec274d580bce389d4d9156617dc7bba/hypothesis-6.165.10-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2d0e0f8263d34dd8fa3b39eaa9a50bba56a8470b3dd9ebf6672d10840abe063e", size = 1283402, upload-time = "2026-08-16T22:54:18.054Z" }, { url = "https://files.pythonhosted.org/packages/4d/07/c2b2a761300cf60b90ccebba4328175331e67d34f4fbd39429a7ddcdce49/hypothesis-6.165.10-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:0c4e6869817c3cfdf5a2b4d348497b95159bdecb3365be732c9b8570e36a4eef", size = 1409948, upload-time = "2026-08-16T22:54:22.343Z" }, { url = "https://files.pythonhosted.org/packages/f4/ec/1c2bf1acdd0e273d81f833f85caf0ae5423db68a783554992fca36e6c541/hypothesis-6.165.10-cp310-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:9f07ae36c3b093e13687a894e79fe69e98a94c0b67fef656c575247682218143", size = 1265023, upload-time = "2026-08-16T22:54:41.402Z" }, { url = "https://files.pythonhosted.org/packages/3d/a8/7f984908b7391160c7801b84e51ca8e4ba88c89e8d8811aa1aa7c03de73c/hypothesis-6.165.10-cp310-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:aff1f584c9538e8979cd180b1d70bf99bc16be19d4666414f49e5942b21a4f2c", size = 1282698, upload-time = "2026-08-16T22:56:06.998Z" }, { url = "https://files.pythonhosted.org/packages/48/78/3a5d91c2d0250521736c42dfa2402b75049bc5fe2fb716c10bc84bb91ed1/hypothesis-6.165.10-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1f2c4db25fb8ec1a16a8dba580666337b8ffb1887c4cf1750cc954313897cef7", size = 1324816, upload-time = "2026-08-16T22:54:46.675Z" }, { url = "https://files.pythonhosted.org/packages/6f/99/27450763853a034bca1574d3e0a315164b33ff49c3862df6872dda45e25e/hypothesis-6.165.10-cp310-abi3-win32.whl", hash = "sha256:b33dc30170a7402e03c180f2c5ef69dc077152f35b91621e9cebcde9c7d71746", size = 669039, upload-time = "2026-08-16T22:55:11.962Z" }, { url = "https://files.pythonhosted.org/packages/2c/fc/ff2988b72b5705ad9ca500444bf3f43e3c2f41edfa034bbfeb23b215791a/hypothesis-6.165.10-cp310-abi3-win_amd64.whl", hash = "sha256:e9f924aa610c0618445e1e8738c822c3190ce2a2699a0cb48ec3a351a96761f2", size = 675213, upload-time = "2026-08-16T22:55:01.697Z" }, { url = "https://files.pythonhosted.org/packages/c5/8b/821810d36f78d9d9421cd2c5d9d36983b45bb3575c3086276cc5c76f9f73/hypothesis-6.165.10-cp310-abi3-win_arm64.whl", hash = "sha256:1d305448e9bd8e2f4f3cea0eafd809efdaab4e998a0019bc615650c8463e42f1", size = 673537, upload-time = "2026-08-16T22:54:47.898Z" }, { url = "https://files.pythonhosted.org/packages/ed/c2/b9546ace11f241c9c02d389f258cb80c14447a8c885771c9f1f0bc1d85ca/hypothesis-6.165.10-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:592107a0faf6c9c3a63a8dbf13dfb1cbda1cf599b0bc11c953221b00204b9ce1", size = 783716, upload-time = "2026-08-16T22:55:36.624Z" }, { url = "https://files.pythonhosted.org/packages/37/10/27c2fdd574fd798caf5e91eb51f7834b098f5d840ce733efb3fba79ef86e/hypothesis-6.165.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9180c362bde06fd05380298ded4e234fbc0d6ede0a864835bfd91c1e24283d5", size = 779507, upload-time = "2026-08-16T22:55:07.633Z" }, { url = "https://files.pythonhosted.org/packages/5e/b6/70bc23695f3783c4b0486b6cad47b08a20f791db4a3c1b25250add9659fa/hypothesis-6.165.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d623801ae3dcd97b77b983400ef3d48bf976648e4efff19929175322eaae074d", size = 1108406, upload-time = "2026-08-16T22:55:39.653Z" }, { url = "https://files.pythonhosted.org/packages/71/4c/32e200bd7a352af4b7f4e3729aaa4cd002cb5fe8c4c6aef5599d0019f152/hypothesis-6.165.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20f6236cfb90b7817bb1a6a087589ca4aa46d73170f0dd62963952ed5dadc589", size = 1157850, upload-time = "2026-08-16T22:55:24.394Z" }, { url = "https://files.pythonhosted.org/packages/03/a5/8efc2a9a484822efc0d0da466f50094e0f2c068187faaf33831fc905873e/hypothesis-6.165.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad0764730e8e3421601c2cc7e1f054a9206c60ea0917165d8d9193dc453f34f1", size = 1283704, upload-time = "2026-08-16T22:54:27.279Z" }, { url = "https://files.pythonhosted.org/packages/46/2a/90cc8d7463929c04786f29600de45f3227c12fa9bed1d5b7ce319b05e1c9/hypothesis-6.165.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:10d9a650a4666b0914831f769703d36140ed8039fd19bf9b71f615b8541eccf2", size = 1325077, upload-time = "2026-08-16T22:55:16.561Z" }, { url = "https://files.pythonhosted.org/packages/82/ac/bc16faba4b42883e3d290bfaceff51e258b63fbbdf789bf9fe88df1ce537/hypothesis-6.165.10-cp311-cp311-win_amd64.whl", hash = "sha256:5671d2b2bf83bd4b6f02e55b32d432506eff5358c82f39b460a849ce19a2666e", size = 674920, upload-time = "2026-08-16T22:55:42.613Z" }, { url = "https://files.pythonhosted.org/packages/e9/45/cde4f78afe2b9e29caecf38319eedc1deb76aebcacbdd128e03cbb2511c3/hypothesis-6.165.10-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:637445c1593a2a9d1024fda50082f07bb56baedda78d90a25f64b8111727ef94", size = 784835, upload-time = "2026-08-16T22:54:45.429Z" }, { url = "https://files.pythonhosted.org/packages/7f/81/847f30b81cbfd07607296b3ce43067cf4f80799bd9244167f587de9c8081/hypothesis-6.165.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:713f4ce4e82c26b53031f139de959bc9e8b54d3995aa824b89bbdf8229df2a45", size = 776419, upload-time = "2026-08-16T22:55:33.633Z" }, { url = "https://files.pythonhosted.org/packages/04/66/4c71c5be7a49d84b8c3a9278c1807c4c81181ab5474beb27df9d4c40dc0e/hypothesis-6.165.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9ff356e97e3ab09db07c8b675efa67340103874a0bae7465acb83dad7a35f7f", size = 1106830, upload-time = "2026-08-16T22:55:10.389Z" }, { url = "https://files.pythonhosted.org/packages/e3/c4/e2cbd2810e79f7a452a8ea9f6c6438ee718ce938d8cc12252cf0b36a81d3/hypothesis-6.165.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a380bc99aa3b035e6a95a2201bf792d4082a04ca75babcc21849c2d0914bb28", size = 1156952, upload-time = "2026-08-16T22:55:53.35Z" }, { url = "https://files.pythonhosted.org/packages/a8/8b/794ced36864825492ac3712d5acab5a257b4601e6a9dc2ccdd3937198f87/hypothesis-6.165.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e9acb2c4d9cb532c3fedea74159f7b923c8c036328c9239b4049e7aa073bdd81", size = 1280780, upload-time = "2026-08-16T22:54:34.983Z" }, { url = "https://files.pythonhosted.org/packages/5d/2d/550525442cdbcc2daf1f9bdd8ba35bcbde63db7c7a22f2ef137fbb49df2f/hypothesis-6.165.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8660572b2d424bf5369ea8990985225f70bd1615b76ecd9c25588a3b9307009f", size = 1324130, upload-time = "2026-08-16T22:55:48.659Z" }, { url = "https://files.pythonhosted.org/packages/74/59/6caf69dd5fe03499ada94c9cec016bffcc164511c6b93fe680f01209b9ff/hypothesis-6.165.10-cp312-cp312-win_amd64.whl", hash = "sha256:3376f2594763aef14faa519b0fb27cae7ce9eeaab4c69efa07777499110306c9", size = 672337, upload-time = "2026-08-16T22:54:49.11Z" }, { url = "https://files.pythonhosted.org/packages/b1/fb/c82c5bd92864ffcf319772fedc8c9bf2dbe4ca14baa0fee6e49e67b5ba1c/hypothesis-6.165.10-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:9d77c3be7b429875036ad0f0597c6e5cc6bb17894a4da005e3807de64d2673ad", size = 784726, upload-time = "2026-08-16T22:54:32.371Z" }, { url = "https://files.pythonhosted.org/packages/0e/b9/3d7acd08506da85557e65147b7f3fca8c47684e33be90bee0acb523920db/hypothesis-6.165.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:490c56b830772b0eca3b4b2cecb3741a1ed26b1d7206a279e1525dbf0aa95ee4", size = 776375, upload-time = "2026-08-16T22:55:13.303Z" }, { url = "https://files.pythonhosted.org/packages/38/6b/922e8b3f9a706dd89d440b9545d2c6231c65e74da1c1fee3ff36c251b9c4/hypothesis-6.165.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed68e27b8a61e57a3ccdc7c5a14499e00b54dfe223087204d5d40b3b5ef58b6d", size = 1106763, upload-time = "2026-08-16T22:55:06.129Z" }, { url = "https://files.pythonhosted.org/packages/01/39/f5b9a5d390d4edd1ad472334493ac442963ebeb4daaa74ff4bdac6ef292f/hypothesis-6.165.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6caadcd1afb62630ff5c5ff353626eaa616553a5971295ad6dc2b19ca8a39620", size = 1156778, upload-time = "2026-08-16T22:54:33.824Z" }, { url = "https://files.pythonhosted.org/packages/b5/5f/5fbe1be4326337fd6acefe2d18ed44007ee1dc1f98fe5b3c0eb22942364d/hypothesis-6.165.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9145fe43ebb22e66672967c3fab411793b226ed776e4fe282271bca6ad3c0bb", size = 1280756, upload-time = "2026-08-16T22:55:54.834Z" }, { url = "https://files.pythonhosted.org/packages/25/c0/cf6f9e1ef632a1a75694eed0db3a02e6fc75c367a363e94acee52f043c64/hypothesis-6.165.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79900a9920a0b1d3a626c03a90ac6bf7042e78d46906a565b86a0dbe926f1d96", size = 1323889, upload-time = "2026-08-16T22:55:56.567Z" }, { url = "https://files.pythonhosted.org/packages/cc/cc/662b94880f260b0a88de1fdcf60fc9984f6e2a796da549542adc10a7bc83/hypothesis-6.165.10-cp313-cp313-win_amd64.whl", hash = "sha256:c01dd04044c472e47193b54f68e84e08d6ebf4f29551885aa959b015f7cd9747", size = 672346, upload-time = "2026-08-16T22:56:03.792Z" }, { url = "https://files.pythonhosted.org/packages/3f/77/55e020c9c576532ff7d20bf8b1dfa052ecbd5ada1949b02f76c44c966f7e/hypothesis-6.165.10-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9ccac776b2ca93b324806facd526ccb45da0fd035001c899a35b02c44431e209", size = 784833, upload-time = "2026-08-16T22:55:21.255Z" }, { url = "https://files.pythonhosted.org/packages/4f/f2/01da2adf829cf549eaddcabb8e8072077fb3d26da4275f4c1e89b2c0af74/hypothesis-6.165.10-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e5f95f7b622e4171096d92175dda0a560f0955ade9b8a3a07bdcf151f7359611", size = 776545, upload-time = "2026-08-16T22:56:10.159Z" }, { url = "https://files.pythonhosted.org/packages/cf/8e/58d4f842895220b793c53fc94a6489705b3665bb4d0ae4d338ce03fdf9fb/hypothesis-6.165.10-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f76d1562643693b8a40066f1f96af795b93fd9bcfc9690a1af2ff4c5867ee29e", size = 1107271, upload-time = "2026-08-16T22:54:50.266Z" }, { url = "https://files.pythonhosted.org/packages/8f/b8/206468912d2153306bb8a41afdfc59e45b7a73a0495bbe4b9cb4f0e79c1d/hypothesis-6.165.10-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60cab3ab4ea468d31a33739ffd7e94ec3e37dea891d65a6582ecc8a477175191", size = 1156915, upload-time = "2026-08-16T22:54:25.89Z" }, { url = "https://files.pythonhosted.org/packages/fb/d3/bf5a22929b70a4cfd3edf69c5642b029b27ddb5cfda48fa295d384b01abb/hypothesis-6.165.10-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:22cf19388f0ff6ced8eb3e49c903d14938e4ed909d93bf28383eef451511e424", size = 1281205, upload-time = "2026-08-16T22:54:44.083Z" }, { url = "https://files.pythonhosted.org/packages/07/a2/d7b2ba444d36fc84d4779f4431e74dd9b023dc63bcf282199f6e48ad39f4/hypothesis-6.165.10-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:057d0232f1224dcd0b7698902551a4341a7399f90670b036db6c4376715fe889", size = 1324243, upload-time = "2026-08-16T22:55:41.123Z" }, { url = "https://files.pythonhosted.org/packages/d1/95/afe6b531fd01928c6f63d394ee413fa2338d088b2b44efcc23596b54477e/hypothesis-6.165.10-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:ab0f2e9d7d7d4db257f7cf53de3706c2baf124269571f20ffc2bcd6781f03063", size = 616382, upload-time = "2026-08-16T22:55:18.449Z" }, { url = "https://files.pythonhosted.org/packages/48/86/9b4fb75f520a028edec50ffc904a94d724180395d71feb6d7a0ce7bb6f00/hypothesis-6.165.10-cp314-cp314-win_amd64.whl", hash = "sha256:d1ea02fa8ab3d33eb1125eade81f7136341eb429152c6dbe2ae6f8bc33b3fbdd", size = 672145, upload-time = "2026-08-16T22:54:24.831Z" }, { url = "https://files.pythonhosted.org/packages/f9/ba/f7bbaae0c789bab7ddb764d2056ee1a463cc95a8acbccc90d4184e48b242/hypothesis-6.165.10-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ed1a5891e59472884a03cb9875483e8fc131c80a275c60967f8afc5458a0c8ff", size = 783287, upload-time = "2026-08-16T22:54:23.751Z" }, { url = "https://files.pythonhosted.org/packages/3a/83/01ef80772b4abd335c49405576dc503cede94fb5da30ba2643a119013aea/hypothesis-6.165.10-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:09772e328a26e50486ac572be34f9887f9aa185efe7ebb16bde4e8f6038db1f4", size = 774991, upload-time = "2026-08-16T22:55:25.987Z" }, { url = "https://files.pythonhosted.org/packages/a3/0b/f47506241f9d5a5a2efe4c65b6bf4830e9d9576e5d3779007a260699e608/hypothesis-6.165.10-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cf3b612542ba174c9da4000b59a4f4c81e8d66f87509be85d3a1b71b5c36413", size = 1105499, upload-time = "2026-08-16T22:54:51.864Z" }, { url = "https://files.pythonhosted.org/packages/84/fe/abb3909b7089835112fbe75bf00d817d733b3a8032759783db0a24ff1e56/hypothesis-6.165.10-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f69ec5be85ef508e206153bed8eafd03f7995dc464356c8bbb279a1e2b7d56f3", size = 1155685, upload-time = "2026-08-16T22:54:30.94Z" }, { url = "https://files.pythonhosted.org/packages/73/2f/1964738921640184067121ae77414522fc3f0463fc26c6e25a4f3b8e42ca/hypothesis-6.165.10-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:dd207497bb985918409a1bb5db85d1875f74e1269487332113b73d1ee7c77647", size = 1279177, upload-time = "2026-08-16T22:54:40.179Z" }, { url = "https://files.pythonhosted.org/packages/34/c5/312af8ae038d3af9cf3f7f1021c1abfe31c0d9035e4cf63519e0a7dc983e/hypothesis-6.165.10-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:00de0abdcf8c05c9d0eab735a3c49a276376b55151e6fcb903c2b39a90e5e5c3", size = 1322921, upload-time = "2026-08-16T22:54:42.7Z" }, { url = "https://files.pythonhosted.org/packages/9e/e7/b0a2fde7570c090a1b914026266a421c751ef10138fffe37fe0ef9e675c0/hypothesis-6.165.10-cp314-cp314t-win_amd64.whl", hash = "sha256:cc2da5aa4edf14743fa9257e5ba3513963999f01211635702479d8e92b8207c8", size = 672147, upload-time = "2026-08-16T22:55:27.527Z" }, { url = "https://files.pythonhosted.org/packages/47/fd/985aa564d6ffd06483d45a62b40d319df0a703cd8bc1d041de17d102fbaa/hypothesis-6.165.10-cp315-abi3.abi3t-macosx_10_12_x86_64.whl", hash = "sha256:eeab73050ea58c13dd56e329f594c1dfe32ebd7bb169bbdf4f8ceefbc31ec6b5", size = 782882, upload-time = "2026-08-16T22:55:37.93Z" }, { url = "https://files.pythonhosted.org/packages/f8/2c/6cc11151e450f72353a490940cd0db704680d07b78dc75dcc9f480e0d0e1/hypothesis-6.165.10-cp315-abi3.abi3t-macosx_11_0_arm64.whl", hash = "sha256:4c68e983d0007d014bb01ad4bcbba78bc432c73a1755ff36d5102ceefa18299a", size = 774584, upload-time = "2026-08-16T22:55:51.822Z" }, { url = "https://files.pythonhosted.org/packages/10/39/ef26fa79c1738dfe9cdb1a3584fb6717d26429ca6c9d011cc4fdf08130c2/hypothesis-6.165.10-cp315-abi3.abi3t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7730d8197086f65d8969a991d6728a1d420a51b19fea06535c896cb43a1e05d0", size = 1104876, upload-time = "2026-08-16T22:54:58.937Z" }, { url = "https://files.pythonhosted.org/packages/4e/f4/3fcc84e7637f42bf00d987093b9418083ac8db81b87392608a60f4b7c5fd/hypothesis-6.165.10-cp315-abi3.abi3t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7a7980a898a3e6ebe4de1896a0507e3d519edb53fb9b4bda478c9fbeb6514558", size = 1133353, upload-time = "2026-08-16T22:54:28.635Z" }, { url = "https://files.pythonhosted.org/packages/35/59/21c5c14179c38f8d0de3560e7f1825c083311b3013b63f817d7dc78dfcbd/hypothesis-6.165.10-cp315-abi3.abi3t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5820d009aedb7ae9cfd32f98b1ab0c0bbd6268379c4fab042218b6b655c63f8", size = 1132300, upload-time = "2026-08-16T22:56:08.539Z" }, { url = "https://files.pythonhosted.org/packages/14/af/fbb56059961e416b2de7b9dc5352db2e8572bd5ea46892957e4c1e5548ab/hypothesis-6.165.10-cp315-abi3.abi3t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37a7ac3d34220800e1107871cc391bca1b00439875925d7d821878b8b791f245", size = 1155175, upload-time = "2026-08-16T22:55:19.824Z" }, { url = "https://files.pythonhosted.org/packages/0f/53/77fb0c2dad445858555429c4e06cf94a59ae8d2407dd6426b5af97c84828/hypothesis-6.165.10-cp315-abi3.abi3t-manylinux_2_31_riscv64.whl", hash = "sha256:dafa7c9dbe3d802f9bcdf261b29c8a70700fb22839947f06e471f62c46b6257f", size = 1109881, upload-time = "2026-08-16T22:55:32.029Z" }, { url = "https://files.pythonhosted.org/packages/a8/7b/d187f673ff30e6ada640953636f978ffe64a6332f756b64163c2277f8d0c/hypothesis-6.165.10-cp315-abi3.abi3t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:90915635b9648071129b0f72c0673cf8eac9eb84cfd445c5bedef30c714b1ec2", size = 1144963, upload-time = "2026-08-16T22:56:13.428Z" }, { url = "https://files.pythonhosted.org/packages/e0/60/31d504e364134d60af23e5f6365db0da3cf4a51b3ed3d4836e5a2cff12cf/hypothesis-6.165.10-cp315-abi3.abi3t-musllinux_1_2_aarch64.whl", hash = "sha256:e1bbeb7c506b07ee0422cf9b2f7212fefa4240957f03526d38d27bc6743a0a48", size = 1278684, upload-time = "2026-08-16T22:55:22.971Z" }, { url = "https://files.pythonhosted.org/packages/ef/e6/89d26834a08c02f8da149e541dd40d7a96f68d9722f43146e69a77436ed7/hypothesis-6.165.10-cp315-abi3.abi3t-musllinux_1_2_armv7l.whl", hash = "sha256:2b36aaffc88625a44f91074c5bbedfdefb9b376c38d1b3c342edcd2e4c8ed16c", size = 1407202, upload-time = "2026-08-16T22:55:14.949Z" }, { url = "https://files.pythonhosted.org/packages/dc/61/20d1e72246867ea195440092e8bb422c7ddc2f271b87b5b65679d5532719/hypothesis-6.165.10-cp315-abi3.abi3t-musllinux_1_2_ppc64le.whl", hash = "sha256:18a3ea838ddea183388f8788750afa8494d79abb5358823be9782585f34445d3", size = 1261395, upload-time = "2026-08-16T22:56:05.448Z" }, { url = "https://files.pythonhosted.org/packages/2a/9b/ebab6c3c2b90a16abb4119198178652d12aff83cc8ec2cfde5276c69fb1e/hypothesis-6.165.10-cp315-abi3.abi3t-musllinux_1_2_riscv64.whl", hash = "sha256:2a2567b3a03a4a5a7c575c191cfcce321a967df3727803817e75bffbbeaecabe", size = 1279213, upload-time = "2026-08-16T22:55:35.066Z" }, { url = "https://files.pythonhosted.org/packages/23/78/69b219b524231d36eb20c792e1f01e7cb037e02bd0af1c29f77ed9a969c0/hypothesis-6.165.10-cp315-abi3.abi3t-musllinux_1_2_x86_64.whl", hash = "sha256:8001925fa3dde51cb574e4c9de4c7efe77c4e4d64bd2fd2ef61d5651f9d04f3d", size = 1322367, upload-time = "2026-08-16T22:54:21.279Z" }, { url = "https://files.pythonhosted.org/packages/55/63/ad5cc153dcc72ae5e7905fb9b3585f3e48ce892a2d6366f90163e867a69d/hypothesis-6.165.10-cp315-abi3.abi3t-win32.whl", hash = "sha256:c6559380469295c4009215fe1cab561301591a3bee2e2fb3f4f96d2273a3affc", size = 666038, upload-time = "2026-08-16T22:56:11.797Z" }, { url = "https://files.pythonhosted.org/packages/80/32/b62307b73fbc99f0a4381d6f9456df76fbcbb7a27ef7256e26f0376f48ea/hypothesis-6.165.10-cp315-abi3.abi3t-win_amd64.whl", hash = "sha256:30797f20ca45e57f526d2df872f63ba453cb4e1091ad542184a7a951af8da79d", size = 671941, upload-time = "2026-08-16T22:55:00.235Z" }, { url = "https://files.pythonhosted.org/packages/c2/dd/e0f98add0548ef73ea7afac45da1fb8efc854d7f9931db568754d0f963f3/hypothesis-6.165.10-cp315-abi3.abi3t-win_arm64.whl", hash = "sha256:c53e9b1c36350df9965ec44d6c0d4e0bbbb38f720dd2b0e1256dc6524d411015", size = 669931, upload-time = "2026-08-16T22:55:50.205Z" }, { url = "https://files.pythonhosted.org/packages/0b/6a/880d6eeed5c451fb40a66733dadec4a5d498628a4a7f6a8a5f633f4c6dcb/hypothesis-6.165.10-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:34ee6402df6f31274d89119f1561b5f7489c97866afc5b7a3ed3a13d7e762802", size = 784644, upload-time = "2026-08-16T22:54:20.127Z" }, { url = "https://files.pythonhosted.org/packages/27/e0/9e942bd3c3cf5ea0d5c0fd0905893bbfb6cefb7284c70fcc8033f8fdec38/hypothesis-6.165.10-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:277f41801e88dad2eba082f91a75632b7584ff64044ba2cf9dadf511b0d19cd0", size = 780515, upload-time = "2026-08-16T22:55:04.676Z" }, { url = "https://files.pythonhosted.org/packages/19/32/f11a618415dc5fa9cdde41fea56c489f0814759527ae1ecd11a75a4558b9/hypothesis-6.165.10-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72df95fb1db41755b155c5f02106e0036a339250555c8d351d488704fd112cf9", size = 1109374, upload-time = "2026-08-16T22:56:00.241Z" }, { url = "https://files.pythonhosted.org/packages/5e/6f/db49b719842297c2b71e0d81e5b8967d31215fb7389421abcb465ce7ed3f/hypothesis-6.165.10-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e20a02775eb3cf0ffb4f0219b6d7c1f240336663d4e5d7028675ec247c790c4", size = 1159092, upload-time = "2026-08-16T22:55:58.57Z" }, { url = "https://files.pythonhosted.org/packages/b2/2a/bf0bae84ba1cb3923d295973f1fe38ee867eaf90119e0d559116083be300/hypothesis-6.165.10-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:1ec53f08732e3cfd0342cbbd75dbd1b193c8f19390660466e536a748bb81f757", size = 676045, upload-time = "2026-08-16T22:55:45.514Z" }, ] [[package]] name = "icdiff" version = "2.0.10" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/5b/6d/41c8ff13b67c30ceb9325398ff6bb9fc4b77208c6c1d79db8d5913840bc6/icdiff-2.0.10.tar.gz", hash = "sha256:75a3de5c9af35ab45fb0504df59770c514a12c0d2b2c99e5f9c5c2429957e133", size = 16378, upload-time = "2026-02-08T15:03:26.76Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/85/4b/bb94514476624bfff977599e5ef3ac9aea603abb693639ed305b22ed1b35/icdiff-2.0.10-py3-none-any.whl", hash = "sha256:fd8ce592d94261c435e2a410f668a41ec3be4527878f8df01100797021d8edb0", size = 17103, upload-time = "2026-02-08T15:03:25.723Z" }, ] [[package]] name = "idna" version = "3.18" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, ] [[package]] name = "imagesize" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6c/e6/7bf14eeb8f8b7251141944835abd42eb20a658d89084b7e1f3e5fe394090/imagesize-2.0.0.tar.gz", hash = "sha256:8e8358c4a05c304f1fccf7ff96f036e7243a189e9e42e90851993c558cfe9ee3", size = 1773045, upload-time = "2026-03-03T14:18:29.941Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5f/53/fb7122b71361a0d121b669dcf3d31244ef75badbbb724af388948de543e2/imagesize-2.0.0-py2.py3-none-any.whl", hash = "sha256:5667c5bbb57ab3f1fa4bc366f4fbc971db3d5ed011fd2715fd8001f782718d96", size = 9441, upload-time = "2026-03-03T14:18:27.892Z" }, ] [[package]] name = "iniconfig" version = "2.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] [[package]] name = "jinja2" version = "3.1.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] [[package]] name = "markdown-it-py" version = "4.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, ] [[package]] name = "markupsafe" version = "3.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] [[package]] name = "mdurl" version = "0.1.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] [[package]] name = "packaging" version = "26.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, ] [[package]] name = "platformdirs" version = "4.10.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743, upload-time = "2026-05-28T03:32:52.175Z" }, ] [[package]] name = "pluggy" version = "1.6.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] [[package]] name = "pprintpp" version = "0.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/06/1a/7737e7a0774da3c3824d654993cf57adc915cb04660212f03406334d8c0b/pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403", size = 17995, upload-time = "2018-07-01T01:42:34.87Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4e/d1/e4ed95fdd3ef13b78630280d9e9e240aeb65cc7c544ec57106149c3942fb/pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d", size = 16952, upload-time = "2018-07-01T01:42:36.496Z" }, ] [[package]] name = "py-cpuinfo" version = "9.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/37/a8/d832f7293ebb21690860d2e01d8115e5ff6f2ae8bbdc953f0eb0fa4bd2c7/py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690", size = 104716, upload-time = "2022-10-25T20:38:06.303Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e0/a9/023730ba63db1e494a271cb018dcd361bd2c917ba7004c3e49d5daf795a2/py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5", size = 22335, upload-time = "2022-10-25T20:38:27.636Z" }, ] [[package]] name = "pygments" version = "2.20.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] [[package]] name = "pyproject-api" version = "1.10.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, ] sdist = { url = "https://files.pythonhosted.org/packages/62/62/0fe346fe380b1aafaf819c8cb195d3241bb4f355f908e6339814131a830b/pyproject_api-1.10.1.tar.gz", hash = "sha256:c2b2726bd7aa9217b6c50b621fef5b2ae5def4d55b779c9e0694c15e0a8517ba", size = 23477, upload-time = "2026-05-28T14:22:14.049Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/79/d7/29e1e5e882f79133631f7bcace42d23db493f616463c157a1ab614bf69dd/pyproject_api-1.10.1-py3-none-any.whl", hash = "sha256:fa9e6f66c35b5017e909825d8f2b5d5482ea699d7be809d21c03bd1f7317f36a", size = 12992, upload-time = "2026-05-28T14:22:12.711Z" }, ] [[package]] name = "pytest" version = "9.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, { name = "pygments" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, ] [[package]] name = "pytest-benchmark" version = "5.2.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "py-cpuinfo" }, { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/24/34/9f732b76456d64faffbef6232f1f9dbec7a7c4999ff46282fa418bd1af66/pytest_benchmark-5.2.3.tar.gz", hash = "sha256:deb7317998a23c650fd4ff76e1230066a76cb45dcece0aca5607143c619e7779", size = 341340, upload-time = "2025-11-09T18:48:43.215Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/33/29/e756e715a48959f1c0045342088d7ca9762a2f509b945f362a316e9412b7/pytest_benchmark-5.2.3-py3-none-any.whl", hash = "sha256:bc839726ad20e99aaa0d11a127445457b4219bdb9e80a1afc4b51da7f96b0803", size = 45255, upload-time = "2025-11-09T18:48:39.765Z" }, ] [[package]] name = "pytest-clarity" version = "1.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pprintpp" }, { name = "pytest" }, { name = "rich" }, ] sdist = { url = "https://files.pythonhosted.org/packages/52/5c/cafa97944de55738a6a2c5a7cee00d073cb80495032d2b112c4546525eca/pytest-clarity-1.0.1.tar.gz", hash = "sha256:505fe345fad4fe11c6a4187fe683f2c7c52c077caa1e135f3e483fe112db7772", size = 4891, upload-time = "2021-06-11T18:16:18.372Z" } [[package]] name = "pytest-icdiff" version = "0.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "icdiff" }, { name = "pprintpp" }, { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5a/0c/66e1e2590e98f4428e374a3b6448dc086a908d15b1e24b914539d13b7ac4/pytest-icdiff-0.9.tar.gz", hash = "sha256:13aede616202e57fcc882568b64589002ef85438046f012ac30a8d959dac8b75", size = 7110, upload-time = "2023-12-05T11:18:30.192Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e2/e1/cafe1edf7a30be6fa1bbbf43f7af12b34682eadcf19eb6e9f7352062c422/pytest_icdiff-0.9-py3-none-any.whl", hash = "sha256:efee0da3bd1b24ef2d923751c5c547fbb8df0a46795553fba08ef57c3ca03d82", size = 4994, upload-time = "2023-12-05T11:18:28.572Z" }, ] [[package]] name = "pytest-sphinx" version = "0.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3c7e79f46228bbabdc836b3d2ef4adaa32559501055fdb02d40e4a6e7452/pytest_sphinx-0.7.1.tar.gz", hash = "sha256:bdf45d96458e6aa1f3618c4845e60924eaa91244247c527eb88f58d6685dece6", size = 13940, upload-time = "2026-01-21T19:08:28.655Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/df/ee/fc942ac27ad00ac71a5f5b1c8929bd49ff632d2c3dd30f07b552280bd4c8/pytest_sphinx-0.7.1-py3-none-any.whl", hash = "sha256:fa943bb22c15569db02367b5b2b13ef3fbb9e534931ec193d480c05d956979fb", size = 10066, upload-time = "2026-01-21T19:08:26.612Z" }, ] [[package]] name = "pytest-sugar" version = "1.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, { name = "termcolor" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0b/4e/60fed105549297ba1a700e1ea7b828044842ea27d72c898990510b79b0e2/pytest-sugar-1.1.1.tar.gz", hash = "sha256:73b8b65163ebf10f9f671efab9eed3d56f20d2ca68bda83fa64740a92c08f65d", size = 16533, upload-time = "2025-08-23T12:19:35.737Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/87/d5/81d38a91c1fdafb6711f053f5a9b92ff788013b19821257c2c38c1e132df/pytest_sugar-1.1.1-py3-none-any.whl", hash = "sha256:2f8319b907548d5b9d03a171515c1d43d2e38e32bd8182a1781eb20b43344cc8", size = 11440, upload-time = "2025-08-23T12:19:34.894Z" }, ] [[package]] name = "pytest-xdist" version = "3.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "execnet" }, { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" }, ] [[package]] name = "python-discovery" version = "1.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "platformdirs" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/26/8b004cc36f430345136f6f00fa1aa9ed596c8ed1e8504625fa79522ff39c/python_discovery-1.4.3.tar.gz", hash = "sha256:ad57d7045a862460d4a235986c33f13ed707d3aeb9153fa47eb7dfd0d4673289", size = 70438, upload-time = "2026-07-03T13:21:51.621Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/28/78/9b77ecb4644d1bbea94d29abf78f21c47eca6eb79e9745b702ec0bed2e19/python_discovery-1.4.3-py3-none-any.whl", hash = "sha256:b6e1e4a7d9e3f6948c39746ffe8218225162d738ba39d05ab1d2f6c1cac4878c", size = 33885, upload-time = "2026-07-03T13:21:50.174Z" }, ] [[package]] name = "requests" version = "2.34.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, { name = "idna" }, { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, ] [[package]] name = "rich" version = "15.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, ] [[package]] name = "roman-numerals" version = "4.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ae/f9/41dc953bbeb056c17d5f7a519f50fdf010bd0553be2d630bc69d1e022703/roman_numerals-4.1.0.tar.gz", hash = "sha256:1af8b147eb1405d5839e78aeb93131690495fe9da5c91856cb33ad55a7f1e5b2", size = 9077, upload-time = "2025-12-17T18:25:34.381Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/04/54/6f679c435d28e0a568d8e8a7c0a93a09010818634c3c3907fc98d8983770/roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7", size = 7676, upload-time = "2025-12-17T18:25:33.098Z" }, ] [[package]] name = "snowballstemmer" version = "3.1.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/f8/0a71edf031f03c40db17503cb8ca78a69a171254e568e7db241b0ab57ea1/snowballstemmer-3.1.1.tar.gz", hash = "sha256:e07bbc54a0d798fe6010a12398422e62a8bfbba95c394fd0956ef58cb4d3e260", size = 123314, upload-time = "2026-06-03T00:56:40.194Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4c/07/2ebca9b11fb9be7340a818d8d6f63feaebb146be2c4afbd6061701d6df6e/snowballstemmer-3.1.1-py3-none-any.whl", hash = "sha256:7e207fa178741da09cdee59d3ecec3827ad5f92b1fc5c9ff3755b639f71f5752", size = 104164, upload-time = "2026-06-03T00:56:38.614Z" }, ] [[package]] name = "sortedcollections" version = "2.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sortedcontainers" }, ] sdist = { url = "https://files.pythonhosted.org/packages/01/00/6d749cc1f88e7f95f5442a8abb195fa607094deba9e0475affbfb7fa8c04/sortedcollections-2.1.0.tar.gz", hash = "sha256:d8e9609d6c580a16a1224a3dc8965789e03ebc4c3e5ffd05ada54a2fed5dcacd", size = 9287, upload-time = "2021-01-18T22:15:16.623Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6e/39/c993a7d0c9dbf3aeca5008bdd00e4436ad9b7170527cef0a14634b47001f/sortedcollections-2.1.0-py3-none-any.whl", hash = "sha256:b07abbc73472cc459da9dd6e2607d73d1f3b9309a32dd9a57fa2c6fa882f4c6c", size = 9531, upload-time = "2021-01-18T22:15:15.36Z" }, ] [[package]] name = "sortedcontainers" version = "2.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, ] [[package]] name = "soupsieve" version = "2.8.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/47/2c/0a5f6f8ee0d5589e48c7640213ed5175d52cf540a06725b628cc1a45d6ce/soupsieve-2.8.4.tar.gz", hash = "sha256:e121fd02e975c695e4e9e8774a5ee35d74714b59307868dcc5319ad2d9e3328e", size = 121110, upload-time = "2026-05-24T13:55:57.154Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5e/f5/0c41cb68dcae6b7de4fac4188a3a9589e21fb31df21ea3a2e888db95e6c9/soupsieve-2.8.4-py3-none-any.whl", hash = "sha256:e7e6b0769c8f51ed59acab6e994b00621096cfb1c640a7509295987388fbaf65", size = 37304, upload-time = "2026-05-24T13:55:55.406Z" }, ] [[package]] name = "sphinx" version = "9.0.4" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version < '3.12'", ] dependencies = [ { name = "alabaster" }, { name = "babel" }, { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "docutils" }, { name = "imagesize" }, { name = "jinja2" }, { name = "packaging" }, { name = "pygments" }, { name = "requests" }, { name = "roman-numerals" }, { name = "snowballstemmer" }, { name = "sphinxcontrib-applehelp" }, { name = "sphinxcontrib-devhelp" }, { name = "sphinxcontrib-htmlhelp" }, { name = "sphinxcontrib-jsmath" }, { name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-serializinghtml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/50/a8c6ccc36d5eacdfd7913ddccd15a9cee03ecafc5ee2bc40e1f168d85022/sphinx-9.0.4.tar.gz", hash = "sha256:594ef59d042972abbc581d8baa577404abe4e6c3b04ef61bd7fc2acbd51f3fa3", size = 8710502, upload-time = "2025-12-04T07:45:27.343Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c6/3f/4bbd76424c393caead2e1eb89777f575dee5c8653e2d4b6afd7a564f5974/sphinx-9.0.4-py3-none-any.whl", hash = "sha256:5bebc595a5e943ea248b99c13814c1c5e10b3ece718976824ffa7959ff95fffb", size = 3917713, upload-time = "2025-12-04T07:45:24.944Z" }, ] [[package]] name = "sphinx" version = "9.1.0" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.15'", "python_full_version >= '3.12' and python_full_version < '3.15'", ] dependencies = [ { name = "alabaster" }, { name = "babel" }, { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "docutils" }, { name = "imagesize" }, { name = "jinja2" }, { name = "packaging" }, { name = "pygments" }, { name = "requests" }, { name = "roman-numerals" }, { name = "snowballstemmer" }, { name = "sphinxcontrib-applehelp" }, { name = "sphinxcontrib-devhelp" }, { name = "sphinxcontrib-htmlhelp" }, { name = "sphinxcontrib-jsmath" }, { name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-serializinghtml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cd/bd/f08eb0f4eed5c83f1ba2a3bd18f7745a2b1525fad70660a1c00224ec468a/sphinx-9.1.0.tar.gz", hash = "sha256:7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb", size = 8718324, upload-time = "2025-12-31T15:09:27.646Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/73/f7/b1884cb3188ab181fc81fa00c266699dab600f927a964df02ec3d5d1916a/sphinx-9.1.0-py3-none-any.whl", hash = "sha256:c84fdd4e782504495fe4f2c0b3413d6c2bf388589bb352d439b2a3bb99991978", size = 3921742, upload-time = "2025-12-31T15:09:25.561Z" }, ] [[package]] name = "sphinx-basic-ng" version = "1.0.0b2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/0b/a866924ded68efec7a1759587a4e478aec7559d8165fac8b2ad1c0e774d6/sphinx_basic_ng-1.0.0b2.tar.gz", hash = "sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9", size = 20736, upload-time = "2023-07-08T18:40:54.166Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3c/dd/018ce05c532a22007ac58d4f45232514cd9d6dd0ee1dc374e309db830983/sphinx_basic_ng-1.0.0b2-py3-none-any.whl", hash = "sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b", size = 22496, upload-time = "2023-07-08T18:40:52.659Z" }, ] [[package]] name = "sphinx-copybutton" version = "0.5.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd", size = 23039, upload-time = "2023-04-14T08:10:22.998Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e", size = 13343, upload-time = "2023-04-14T08:10:20.844Z" }, ] [[package]] name = "sphinxcontrib-applehelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, ] [[package]] name = "sphinxcontrib-devhelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, ] [[package]] name = "sphinxcontrib-htmlhelp" version = "2.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, ] [[package]] name = "sphinxcontrib-jsmath" version = "1.0.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, ] [[package]] name = "sphinxcontrib-qthelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, ] [[package]] name = "sphinxcontrib-serializinghtml" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, ] [[package]] name = "termcolor" version = "3.3.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, ] [[package]] name = "tomli-w" version = "1.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" }, ] [[package]] name = "tox" version = "4.56.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cachetools" }, { name = "colorama" }, { name = "filelock" }, { name = "packaging" }, { name = "platformdirs" }, { name = "pluggy" }, { name = "pyproject-api" }, { name = "python-discovery" }, { name = "tomli-w" }, { name = "virtualenv" }, ] sdist = { url = "https://files.pythonhosted.org/packages/60/6a/d20d405fc6661902ff803a9fa048d8aae27597c3b5dc750369ded82d08f7/tox-4.56.1.tar.gz", hash = "sha256:db1c2610802553189cf40de251661d066a635ee0ed9bf2a60093b5f1a7f36ef8", size = 283155, upload-time = "2026-06-25T06:18:36.802Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d8/97/560a5dfde154619d9643b1e208119dddc29bbb35a38a4ce4d095c16cf8f0/tox-4.56.1-py3-none-any.whl", hash = "sha256:4d06b925c4dd67872099b39c5a46fba79a2169c5f6e32060f95a8b1181f0ef55", size = 216469, upload-time = "2026-06-25T06:18:35.229Z" }, ] [[package]] name = "tox-uv" version = "1.35.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tox-uv-bare" }, { name = "uv" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/ca/dc/6e9994c799bdbb309f829dd6b8d98764dd0757302f3433c380438a3a127b/tox_uv-1.35.2-py3-none-any.whl", hash = "sha256:2d99b0e3c782ba49e7cbe521c8d344758595961b17a3633738d67096641c1bde", size = 6565, upload-time = "2026-05-05T01:34:16.07Z" }, ] [[package]] name = "tox-uv-bare" version = "1.35.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, { name = "tox" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0a/cb/168dc1ccf24e4065a9a0a33df55709ed2b5eb73bd2b13ddd53187e5dffb8/tox_uv_bare-1.35.2.tar.gz", hash = "sha256:49e28a804c97f23ea17e25859960c0fa78f35bccb7e14344cfd840e89a9aade9", size = 32333, upload-time = "2026-05-05T01:34:18.916Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5f/53/4a33dc81da39db7b31e5622333df361e8fe055b7ec636bd5fea762c9182d/tox_uv_bare-1.35.2-py3-none-any.whl", hash = "sha256:c0d590a41d1054a1ad0874e9e5943ff52402786e3d4599d8f8d37a65b566ef53", size = 22307, upload-time = "2026-05-05T01:34:17.681Z" }, ] [[package]] name = "ty" version = "0.0.72" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d5/df/656e684bafb13c1d146e7d5b5f3e7978ca177232acc84998ff36427e9462/ty-0.0.72.tar.gz", hash = "sha256:ec2b8066b618df18cab4cb8e992f8da45d360332acb23fa34df7fa29cd1b9d3a", size = 6654939, upload-time = "2026-08-14T21:35:42.612Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e2/3b/f51461239a4e66565d4b362f97a3b55fe7fdba2e944068341f87c62f6743/ty-0.0.72-py3-none-linux_armv6l.whl", hash = "sha256:fda86db153ffd85ee52000cf175d6a3f1c0223772cf7c5b6f726200bf92c7b44", size = 12621989, upload-time = "2026-08-14T21:35:01.676Z" }, { url = "https://files.pythonhosted.org/packages/ca/fb/79ddf683affc679ca856f3510b5640ec3a88a842ba5f654f5d4bc78f1786/ty-0.0.72-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ceb944c612529b9023acfdc9cf4c0dcbb722549f9d17d46baecd1141baf01d7f", size = 12233910, upload-time = "2026-08-14T21:35:04.334Z" }, { url = "https://files.pythonhosted.org/packages/5d/45/10562a0d84802158db8fa4ec46de54aa9fdcecdeeaabbfe3639ae7042b66/ty-0.0.72-py3-none-macosx_11_0_arm64.whl", hash = "sha256:108d76218333d6c092e5f1cebf8e9b06f25738613a0236a28e2dd47c936ee52c", size = 12084108, upload-time = "2026-08-14T21:35:06.686Z" }, { url = "https://files.pythonhosted.org/packages/a1/dc/1fe1aef8d697e3509face271a5331700c7aa1d1e44a4b622707bdfa41d4b/ty-0.0.72-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f3943f186f741a2499a31053872169250c9264a9a49684920e48d8fcf4ef4f5", size = 12132640, upload-time = "2026-08-14T21:35:09.305Z" }, { url = "https://files.pythonhosted.org/packages/14/46/41ceb265e96969487311a2014bd0e53abb4fbc1395efb2ebe411fcb4db62/ty-0.0.72-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf283c07dc3cc52ca48a3ad8ab100fb5aec3aebbd03ef6a12d5f910b8e596fc5", size = 12402489, upload-time = "2026-08-14T21:35:11.555Z" }, { url = "https://files.pythonhosted.org/packages/2b/45/30bf43cb4fd505c5c2dd30fda27dde5f05208686cd21217adec77c954204/ty-0.0.72-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95f3b6462c38f9f115d10cee21f47fedf715fcf2040daf36eef210359300bc7c", size = 13130835, upload-time = "2026-08-14T21:35:13.746Z" }, { url = "https://files.pythonhosted.org/packages/31/2f/03bba754d2613f640df168335c41f83f41db150bb515839c60d80e3a7880/ty-0.0.72-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30caf658feb8ffb250d9e9e47107657a78f5f3425c227df1664d8df2ebe38880", size = 13590392, upload-time = "2026-08-14T21:35:16.839Z" }, { url = "https://files.pythonhosted.org/packages/04/c7/03c67f00e63005ec41585653dc3096064570b1e6273742baae2798cd242f/ty-0.0.72-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27bdc012ddfbeec8948e4a6036c0dc39ac7cf2c8ec7c7d48dc7d2fd56d57b399", size = 13309629, upload-time = "2026-08-14T21:35:19.169Z" }, { url = "https://files.pythonhosted.org/packages/c1/df/102d3b264eb7f2a58dd11952f229bb5150bb5668d176a6154976a6675981/ty-0.0.72-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:802c5970a77d7739e6f499921fbb6984fb7ad8a31d95e1ff42fd46f3642e4f3b", size = 12734028, upload-time = "2026-08-14T21:35:22.099Z" }, { url = "https://files.pythonhosted.org/packages/61/85/d0737c8c54d0ba67366ddfb9f31d88edf0b02299e65923e6945ae60ebcb5/ty-0.0.72-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:47dce65114fdc615c68ca0edb393b433df0956447e4267df0e264137a789598d", size = 13174832, upload-time = "2026-08-14T21:35:24.71Z" }, { url = "https://files.pythonhosted.org/packages/1e/31/497f5a96c36d9b586ab6afe0574986835c6fd5b835a89773d2bec4711b49/ty-0.0.72-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:325144fa07e2675d0faa337fcc864213c272a499eb0cfe5bde2fdc62282d27bc", size = 12215005, upload-time = "2026-08-14T21:35:26.892Z" }, { url = "https://files.pythonhosted.org/packages/df/7d/46e65b17b4966c7cd0140f134380d33d8e84fe6efccd761533ce793dc502/ty-0.0.72-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a5c9f15d0f58e43707d8848274be1821a0ef408eccb8aa7dda28a4a9eddf7640", size = 12421298, upload-time = "2026-08-14T21:35:29.301Z" }, { url = "https://files.pythonhosted.org/packages/08/2a/12ada4ec17700b3cb1d4fd3bc3e5b1852df9e6885288429318cade87b3c1/ty-0.0.72-py3-none-musllinux_1_2_i686.whl", hash = "sha256:8ee508d64b381871529cc22c412b41071bf5e908b7aa5d66a38f3f6b2573a806", size = 12669242, upload-time = "2026-08-14T21:35:31.444Z" }, { url = "https://files.pythonhosted.org/packages/1c/1a/4692536880790fb550ed6d44a6096778dc71bb112f2c6d615cebb01a57e5/ty-0.0.72-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3699e2ec7921d44da79d6b089f7bf239b2cc53c4e45a5a38430adc34ee9e9a55", size = 12988199, upload-time = "2026-08-14T21:35:33.749Z" }, { url = "https://files.pythonhosted.org/packages/9a/0d/f5e5a50322e9c45865e7b7a428ba6cd6527387cf0f2472492ac3cf746243/ty-0.0.72-py3-none-win32.whl", hash = "sha256:f25f72a67bd36cd247707c4784e52fad0b6b4f42a1b7dd14804110fa95c486ed", size = 11939708, upload-time = "2026-08-14T21:35:36.006Z" }, { url = "https://files.pythonhosted.org/packages/3f/4e/8af3534b2e4214e6184a5a59c34101e94a68d578f081f97b995866bab1bf/ty-0.0.72-py3-none-win_amd64.whl", hash = "sha256:cdeee869341717e1736cea2e2d7856738c6957c320f584ed2f68c8f90100d2f5", size = 12643876, upload-time = "2026-08-14T21:35:38.141Z" }, { url = "https://files.pythonhosted.org/packages/ff/ea/a2606e654c7276bd08586391a2525b0af3f3bf60228a8c57b2d248f273f9/ty-0.0.72-py3-none-win_arm64.whl", hash = "sha256:1bd3ac3ed4424a6d6990a85dc388556aea012bd752de21349a84b685951de0d8", size = 12394857, upload-time = "2026-08-14T21:35:40.277Z" }, ] [[package]] name = "typing-extensions" version = "4.16.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, ] [[package]] name = "urllib3" version = "2.7.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, ] [[package]] name = "uv" version = "0.11.27" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8f/ed/b8bb8bf2044561e3349ebe75be0d8abdeb19577886753b49200ec6caea0d/uv-0.11.27.tar.gz", hash = "sha256:3469204521869f0e6bdea17b02c1d86db2d0150820895653a6152cab206fb00b", size = 5978029, upload-time = "2026-07-06T21:00:29.995Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b2/fe/8a080fb603f276ceb2d960454b2b5998cc6e5c0c6d5dbbbeb48b141de4f2/uv-0.11.27-py3-none-linux_armv6l.whl", hash = "sha256:6cedad2185b16bd5da77096d4813159c9c3c572897537256eecdb4092941adc0", size = 25490659, upload-time = "2026-07-06T20:59:29.003Z" }, { url = "https://files.pythonhosted.org/packages/d1/15/886a2ef7b00c1a4fcf706e7a6b946b3f7485a55f42d0aa9b5572caed58b6/uv-0.11.27-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:42b273459864c67f3736ae2a63929df463975d885bbc1afd8f53f7e0fb1f2269", size = 24498434, upload-time = "2026-07-06T20:59:33.042Z" }, { url = "https://files.pythonhosted.org/packages/2d/6e/45335717c4372bf955c87bc05c6462dd4c0c6087ed12c3991b14cbba77cd/uv-0.11.27-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b316464a1028a43478b74424b4b78925c463758baec93cb754fb2392ba175138", size = 23248727, upload-time = "2026-07-06T20:59:36.201Z" }, { url = "https://files.pythonhosted.org/packages/0a/fa/41dde1e350c5a277b797371faf96fb013c2c13ed18df6efc51ed8ec9bb5b/uv-0.11.27-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:3ca478883d78270ceed57f229d1b480dbcadf5d79b2ce9624574807d6ec48554", size = 25208126, upload-time = "2026-07-06T20:59:39.984Z" }, { url = "https://files.pythonhosted.org/packages/00/e3/bc6d4af24ab533db4c741cebade3a58b91fc0563059d39e838161dd210c8/uv-0.11.27-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:232dfb7549c8a4217ab1970dea0de731926b8ca21769ed89951ad8f8c3bce8b6", size = 25030974, upload-time = "2026-07-06T20:59:43.378Z" }, { url = "https://files.pythonhosted.org/packages/c3/0c/82e736930d3f78ca6c3286ef31627d7155e20191af88afc40ec29486f400/uv-0.11.27-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4c0cf7c7960587a231252cbe4d7a032b5a02c29cfab3fcc4e75a915b1c5cacee", size = 25015115, upload-time = "2026-07-06T20:59:46.694Z" }, { url = "https://files.pythonhosted.org/packages/a0/5b/512ebf3b24b708ea2adda4ec4d4bd23b2404d7a7ea3bd24d2b92210ab680/uv-0.11.27-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47b5863ef715ffe4c29e792c9884a4e8b8016b0628d3613ac84c696acc128a78", size = 26487914, upload-time = "2026-07-06T20:59:50.414Z" }, { url = "https://files.pythonhosted.org/packages/98/d5/3871185331266156fbd09ab0ad7ddc69ca759b3a28ece5488bdb64f152d9/uv-0.11.27-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5764155d2a578a41d2827f464d4ce5b7788632e732cb304e2025fb3d043b46f", size = 27393306, upload-time = "2026-07-06T20:59:53.852Z" }, { url = "https://files.pythonhosted.org/packages/24/0f/9fe3cc9b8d498f2e426b3cda90d337b076d64f19c2d55cb0b7d091c4bfe9/uv-0.11.27-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d806e1067c8eb9f8ba5dbdca46484512d224070e8473442319d4c1fbc3246f4d", size = 26563495, upload-time = "2026-07-06T20:59:56.945Z" }, { url = "https://files.pythonhosted.org/packages/e7/be/18393c15ac0c982fefa34944135ead3adc565da5023d973eff5081a95a62/uv-0.11.27-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cb783b9db3868e51e8da1956aaa7e800262ad1af03dfc8b024f3b04ecb447c2", size = 26652374, upload-time = "2026-07-06T21:00:00.256Z" }, { url = "https://files.pythonhosted.org/packages/b8/93/1bb8bee2b0bcc6e9655518ecaa9a792b1952dd99ae7366fe4f6c82754361/uv-0.11.27-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:8e2b86d3dee515eeba6ea001d8b3eac20b204db07d39b04187c755a490a4fba6", size = 25341573, upload-time = "2026-07-06T21:00:03.789Z" }, { url = "https://files.pythonhosted.org/packages/e6/e0/fae0d1c972b25ac192ac807c1b1baf0f12070c40c8af2eb8e22310ea8846/uv-0.11.27-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:d325b8bd2665ce3ac58d33f977683cfb2cb8eb951effab06fad8518426bc0a90", size = 26051363, upload-time = "2026-07-06T21:00:07.281Z" }, { url = "https://files.pythonhosted.org/packages/e5/a2/4c0c103ea431f5d70cd33f10c754b5b1de9687fea982ca1a20a4eee0a4a7/uv-0.11.27-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:3d5c9036b558a323f254e3d16038183c22c55e0d06b921f1ed9706953311e52f", size = 26148896, upload-time = "2026-07-06T21:00:10.56Z" }, { url = "https://files.pythonhosted.org/packages/bb/b7/a514307a90ca9f1cb59efd0898958dea6c1092ad5e4e6b6f2eb4d55109db/uv-0.11.27-py3-none-musllinux_1_1_i686.whl", hash = "sha256:4cc04e625e7bfac6975fd384d6598169cea0030995ff3b557950ec3077974a4d", size = 25701138, upload-time = "2026-07-06T21:00:13.772Z" }, { url = "https://files.pythonhosted.org/packages/bf/46/c6cfa675d727a199cfce32f7a30350ce6e47f699c3cd7f0433a619c671d4/uv-0.11.27-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:109d8e145b390d0e14f2aefd9708a7522a4236d6bee20361a7558e77a14c0531", size = 26913232, upload-time = "2026-07-06T21:00:17.233Z" }, { url = "https://files.pythonhosted.org/packages/a4/04/0070ecdea37baa9d38187abedc78eed9a52a2e6cb1d4f175c580640f3456/uv-0.11.27-py3-none-win32.whl", hash = "sha256:b330d2ab6af0f79396fb350a9fed8ed1aa92516310f7533de9a8dfebc4e147cd", size = 24374672, upload-time = "2026-07-06T21:00:20.399Z" }, { url = "https://files.pythonhosted.org/packages/d0/b9/f3df522d2e609fe511e5bee24b34c91ce281ce472594121fa1d5fa159d9d/uv-0.11.27-py3-none-win_amd64.whl", hash = "sha256:e20f25921ed4c46d32ac18a9b2e610c0384439fd367f647f2b68e0e1d90e9885", size = 27275452, upload-time = "2026-07-06T21:00:23.903Z" }, { url = "https://files.pythonhosted.org/packages/8d/2e/4ea9c3bbf95a21c627a3dfa359f5a3266e648cd103c5ade374a6e4265c5f/uv-0.11.27-py3-none-win_arm64.whl", hash = "sha256:a41da27667e95c0df939e99e77a4d9169fb895df0f6788b2ab65ed5efdc1395f", size = 25561477, upload-time = "2026-07-06T21:00:27.333Z" }, ] [[package]] name = "virtualenv" version = "21.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, { name = "python-discovery" }, ] sdist = { url = "https://files.pythonhosted.org/packages/74/65/ec1d92091671e6407d3e7c1f5801413bb7b2b57630a50cae7750456ba0ed/virtualenv-21.6.0.tar.gz", hash = "sha256:e18a4d750f2b64dea73e72ffde3922f3c52365fabdc8157ebd3da20d031c4734", size = 5526111, upload-time = "2026-07-06T22:49:56.972Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b8/e7/2fbd0cc1653c53eed8f10670538bb547de2b3e37aacad283faa82a71094b/virtualenv-21.6.0-py3-none-any.whl", hash = "sha256:bce9d097950fef9d81129b333babfb7767072850c2f1acce0ec536708401bfd1", size = 5506216, upload-time = "2026-07-06T22:49:54.941Z" }, ]