magic-wormhole-0.7.6/.cargo/config.toml000064400000000000000000000001041046102023000160560ustar 00000000000000[target.wasm32-unknown-unknown] runner = 'wasm-bindgen-test-runner' magic-wormhole-0.7.6/.cargo_vcs_info.json0000644000000001360000000000100137600ustar { "git": { "sha1": "786ae6838ea1f2e2beada9fd95f44849e34a409e" }, "path_in_vcs": "" }magic-wormhole-0.7.6/.codecov.yml000064400000000000000000000000641046102023000147730ustar 00000000000000coverage: status: project: off patch: off magic-wormhole-0.7.6/.github/workflows/audit.yml000064400000000000000000000014361046102023000200020ustar 00000000000000name: Security Audit on: push: branches: [main] paths: - "**/Cargo.toml" - "**/Cargo.lock" pull_request: branches: [main] paths: - "**/Cargo.toml" - "**/Cargo.lock" schedule: - cron: "32 10 * * *" jobs: audit: name: Audit Rust Dependencies runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Cache ~/.cargo uses: actions/cache@v4 with: # we specifically want ~/.cargo/bin/cargo-audit # and ~/.cargo/.crates.toml and .crates2.json # which cargo-install uses to remember that it's # already installed path: ~/.cargo key: ${{ runner.os }}-audit-dotcargo - uses: actions-rust-lang/audit@v1 name: Audit Rust Dependencies magic-wormhole-0.7.6/.github/workflows/push.yml000064400000000000000000000226351046102023000176570ustar 00000000000000name: Rust on: push: branches: [main, "v*"] tags: ["[0-9]+.[0-9]+.[0-9]+"] pull_request: branches: [main, "v*"] jobs: read_msrv: name: Read MSRV runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Rust (stable) uses: actions-rust-lang/setup-rust-toolchain@v1 - name: Read MSRV from workspace manifest id: read_msrv run: | cargo metadata --no-deps --format-version=1 \ | jq -r 'first(.packages[]).rust_version' \ | sed -E 's/^1\.([0-9]{2})$/1\.\1\.0/' \ | xargs -0 printf "msrv=%s" \ | tee /dev/stderr \ >> "$GITHUB_OUTPUT" outputs: msrv: ${{ steps.read_msrv.outputs.msrv }} formatting: name: Cargo Format runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # Ensure rustfmt is installed and setup problem matcher - uses: actions-rust-lang/setup-rust-toolchain@v1 with: components: rustfmt toolchain: nightly - name: Rustfmt Check uses: actions-rust-lang/rustfmt@v1 clippy: name: Clippy runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Cache ~/.cargo uses: actions/cache@v4 with: path: ~/.cargo key: ${{ runner.os }}-clippy-dotcargo - name: Cache cargo build uses: actions/cache@v4 with: path: target key: ${{ runner.os }}-clippy-cargo-build-target - uses: dtolnay/rust-toolchain@stable with: toolchain: stable components: clippy - name: cargo clippy run: cargo clippy --all-features test: name: "Test (${{ matrix.os }} ${{ matrix.channel }})" needs: - read_msrv runs-on: ${{ matrix.image }} strategy: fail-fast: false matrix: channel: - MSRV - stable os: - Linux - Windows - macOS - WASM include: - os: Linux image: ubuntu-latest target: x86_64-unknown-linux-gnu features: all,native-tls,experimental - os: Windows image: windows-latest target: x86_64-pc-windows-msvc features: all,native-tls,experimental - os: macOS image: macos-latest target: aarch64-apple-darwin features: all,native-tls,experimental - os: WASM image: ubuntu-latest target: wasm32-unknown-unknown features: transit,transfer - channel: msrv rust: ${{ needs.read_msrv.outputs.msrv }} - channel: stable rust: stable steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ matrix.rust }} target: wasm32-unknown-unknown - name: Cache ~/.cargo uses: actions/cache@v4 with: path: ~/.cargo key: ${{ runner.os }}-test-dotcargo-${{ matrix.rust }} - name: Cache cargo build uses: actions/cache@v4 with: path: target key: ${{ runner.os }}-test-build-target-${{ matrix.rust }} - name: build library (no default features) run: cargo build -p magic-wormhole --target ${{ matrix.target }} --no-default-features - name: build library (features=transit) run: cargo build -p magic-wormhole --target ${{ matrix.target }} --no-default-features --features=transit - name: build library (features=transfer) run: cargo build -p magic-wormhole --target ${{ matrix.target }} --no-default-features --features=transfer - name: build library (features=forwarding) if: ${{ matrix.os != 'WASM' }} run: cargo build -p magic-wormhole --target ${{ matrix.target }} --no-default-features --features=forwarding - name: build CLI if: ${{ matrix.os != 'WASM' }} run: cargo build -p magic-wormhole-cli --target ${{ matrix.target }} --features=all - name: build WASM if: ${{ matrix.os == 'WASM' }} run: cargo build -p magic-wormhole --target wasm32-unknown-unknown --no-default-features --features ${{ matrix.features }} - name: test uses: nick-fields/retry@v3 with: max_attempts: 3 polling_interval_seconds: 30 timeout_minutes: 30 retry_on_exit_code: 101 command: cargo test --verbose --workspace --features ${{ matrix.features }} dist: name: "Dist (${{ matrix.os }})" runs-on: ${{ matrix.image }} strategy: fail-fast: false matrix: os: - Linux - Windows - macOS include: - os: Linux image: ubuntu-latest target: x86_64-unknown-linux-gnu ext: "" - os: Windows image: windows-latest target: x86_64-pc-windows-gnu ext: ".exe" - os: macOS image: macos-latest target: aarch64-apple-darwin ext: "" steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: toolchain: stable target: ${{ matrix.target }} - name: Cache ~/.cargo uses: actions/cache@v4 with: path: ~/.cargo key: ${{ runner.os }}-test-dotcargo-stable - name: Cache cargo build uses: actions/cache@v4 with: path: target key: ${{ runner.os }}-test-build-target-stable - name: Build run: cargo build -p magic-wormhole-cli --target ${{ matrix.target }} --bins --locked --release - name: Tar binaries run: | pushd "target/${{ matrix.target }}/release/" tar -cvzf "magic-wormhole-cli-${{ matrix.target }}.tgz" "wormhole-rs${{ matrix.ext }}" popd - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: magic-wormhole-cli-${{ matrix.target }} path: target/${{ matrix.target }}/release/magic-wormhole-cli-${{ matrix.target }}.tgz if-no-files-found: error coverage: name: Coverage runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: toolchain: nightly - uses: taiki-e/cache-cargo-install-action@v2 with: tool: cargo-tarpaulin - name: Cache ~/.cargo uses: actions/cache@v4 with: path: ~/.cargo key: ${{ runner.os }}-coverage-dotcargo - name: Cache cargo build uses: actions/cache@v4 with: path: target key: ${{ runner.os }}-coverage-cargo-build-target - name: Run tarpaulin run: cargo tarpaulin --workspace --out Xml - name: upload coverage uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} cargo-deny: name: Cargo deny runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: toolchain: nightly - name: Checkout Rust toolcnain uses: actions/checkout@v4 - uses: EmbarkStudios/cargo-deny-action@v1 semver: name: SemVer runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: toolchain: nightly - name: Check semver uses: obi1kenobi/cargo-semver-checks-action@v2 with: feature-group: default-features features: "all" - name: Extract Changelog uses: release-flow/keep-a-changelog-action@v3 with: command: query version: unreleased release: name: Release runs-on: ubuntu-latest needs: - dist steps: - uses: actions/checkout@v4 - name: Get Cargo Version id: query-version run: | cargo metadata --no-deps --format-version=1 \ | jq -r 'first(.packages[]).version' \ | xargs -0 printf "version=%s" \ >> "$GITHUB_OUTPUT" - name: Check Tag id: check-tag run: | if git show-ref --tags --verify --quiet "refs/tags/${{ steps.query-version.outputs.version }}"; then echo "tag=1" >> "$GITHUB_OUTPUT" else echo "tag=0" >> "$GITHUB_OUTPUT" fi - name: Extract Changelog for ${{ steps.query-version.outputs.version }} id: query-changelog uses: release-flow/keep-a-changelog-action@v3 with: command: query version: ${{ steps.query-version.outputs.version }} - uses: actions/download-artifact@v4 with: path: "./dist" pattern: "magic-wormhole-cli-*" - name: Update Release uses: softprops/action-gh-release@v2 if: ${{ startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/heads/main') }} with: name: "Version ${{ steps.query-version.outputs.version }}" body: ${{ steps.query-changelog.outputs.release-notes }} files: "./dist/**/magic-wormhole-cli-*" fail_on_unmatched_files: true prerelease: ${{ contains(steps.query-version.outputs.version, '-') }} draft: ${{ steps.check-tag.outputs.tag == 0 && !startsWith(github.ref, 'refs/tags/') }} make_latest: ${{ !contains(steps.query-version.outputs.version, '-') && startsWith(github.ref, 'refs/tags/') }} magic-wormhole-0.7.6/.gitignore000064400000000000000000000002241046102023000145360ustar 00000000000000# Generated by Cargo # will have compiled files and executables /target/ # These are backup files generated by rustfmt **/*.rs.bk .idea/ .vscode/ magic-wormhole-0.7.6/.rustfmt.toml000064400000000000000000000002401046102023000152230ustar 00000000000000unstable_features = true edition = "2018" # max_width = 80 match_block_trailing_comma = true imports_granularity = "Crate" format_code_in_doc_comments = true magic-wormhole-0.7.6/CHANGELOG.md000064400000000000000000000217541046102023000143720ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [0.7.6] - 2025-04-05 ### Security - Fixed [RUSTSEC-2025-0004](https://rustsec.org/advisories/RUSTSEC-2025-0004.html) - Fixed [RUSTSEC-2025-0009](https://rustsec.org/advisories/RUSTSEC-2025-0009.html) - Fixed [RUSTSEC-2025-0022](https://rustsec.org/advisories/RUSTSEC-2025-0022.html) ## [0.7.5] - 2025-01-12 ### Fixed - cli: Command line arguments completion would generate completions for magic-wormhole-cli, not wormhole-rs ## [0.7.4] - 2024-11-23 ### Fixed - cli: autocomplete would use the wrong wordlist exactly 100% of the time 🙈 - cli: Remove unmaintained instant dependency ## [0.7.3] - 2024-10-25 ### Added - cli: Add clipboard auto completion support ## [0.7.2] - 2024-10-11 ### Changed - \[all\]\[\breaking\] Code words with a secret password section shorter than 4 bytes are no longer accepted. This only breaks completely invalid uses of the code. - \[all\] Code words with a weak password section or a non-integer nameplate will throw an error in the long. This error can be upgraded to a hard error by enabling the "entropy" feature. This feature will become the default in the next major release. - \[lib\] Implemented FromStr for `Code` and `Nameplate` - \[lib\] Added new checked type for the `Password` section of a wormhole code - \[lib\] Added new `entropy` feature. When enabled, the entropy of the passed password will be checked on creation. This will change the signature of `MailboxConnection::create_with_password` to require the password to be passed via the new `Password` wrapper type. - \[lib\]\[deprecated\] Deprecated the `Code` and `Nameplate` `From>` implementations and `new()` methods. They are unchecked and will print a warning for now. These will be removed in the next breaking release. ## [0.7.1] - 2024-07-25 ### Changed - Bump dependencies ### Fixed - [openssl's `MemBio::get_buf` has undefined behavior with empty buffers](https://github.com/advisories/GHSA-q445-7m23-qrmw) ## [0.7.0] - 2024-07-17 ### Changed - \[all\]\[breaking\] By default websocket TLS support is now disabled in the library crate. TLS is required for secure websocket connections to the mailbox server (`wss://`). As the handshake protocol itself is encrypted, this extra layer of encryption is superfluous. Most WASM targets however refuse to connect to non-TLS websockets. For maximum compatibility with all mailbox servers, or for web browser support, select a TLS implementation by specifying the feature flag `tls` for a statically linked implementation via the `ring` crate, or `native-tls` for dynamically linking with the system-native TLS implementation. - \[all\] For experimental (unstable) `transfer-v2` protocol support, enable feature flag `experimental-transfer-v2`. The protocol is not yet finalized. - \[all\] Added compilation support for WASM targets. - \[lib\]\[breaking\] replaced `transit::TransitInfo` with a struct containing the address and a `conn_type` field which contains the old enum as `transit::ConnectionType` - \[lib\]\[breaking\] changed the signature of the `transit_handler` function to take just the newly combined `transit::TransitInfo` - \[lib\]\[breaking\] changed the signature of the `file_name` argument to `transfer::send_*` to take `Into` instead of `Into` - \[lib\]\[breaking\] replaced `transfer::AppVersion` with a struct with private fields that implements `std::default::Default` - \[lib\]\[deprecated\] split `Wormhole` in `MailboxConnection` and `Wormhole` - \[lib\]\[deprecated\] `Wormhole::connect_with(out)_code`, `WormholeWelcome`, use `MailboxConnection::create()` and then `Wormhole::connect()` instead - \[lib\]\[deprecated\] `Wormhole` public struct fields. Use the provided accessor methods instead. - \[lib\]\[deprecated\] `ReceiveRequest.filename` is deprecated and replaced by `ReceiveRequest.file_name(..)` - \[lib\]\[deprecated\] `ReceiveRequest.filesize` is deprecated and replaced by `ReceiveRequest.file_size(..)` - \[lib\]\[deprecated\] `GenericKey`, implement `KeyPurpose` on a custom struct instead - \[lib\]\[deprecated\] `rendezvous::RendezvousServer` will be removed in the future with no planned public replacement. - \[lib\]\[deprecated\] `transfer::PeerMessage` will be removed in the future with no planned public replacement. - \[lib\]\[deprecated\] `transit::TransitConnector` will be removed in the future with no planned public replacement. - \[lib\]\[deprecated\] `transit::log_transit_connection` and implemented `Display` on `TransitInfo` instead. - \[lib\]\[deprecated\] `transit::init()` will be removed in the future with no planned public replacement. ## [0.6.1] - 2023-12-03 ### Fixed - RUSTSEC-2023-0065: Update tungstenite - RUSTSEC-2023-0037: Replace xsalsa20poly1305 with crypto_secretbox - RUSTSEC-2023-0052: Update webpki ### Changed - Update crate dependencies ## [0.6.0] - 2022-12-21 ### Added - Add shell completion support for the CLI - Add support for [wormhole URIs](https://github.com/magic-wormhole/magic-wormhole-protocols/pull/21) - \[cli\] The CLI will show a QR code (even if no app can probably read it currently) and a link - \[lib\] See `magic_wormhole::uri::WormholeTransferUri` ### Fixed - Fix broken port forwarding - Fix directory transfer - Smaller bugfixes ### Changed - \[lib\]\[breaking\] File transfer functions do not take a `url::Url` for the relay server anymore, but a `Vec` - For migration, look at `magic_wormhole::transit::RelayHint::from_urls` ## [0.5.0] - 2022-05-24 ### Changed - \[lib\]\[breaking\] Removed `relay-v2` ability again. - This fixed some relay signalling issues, where no connection could be made with `--force-relay` under some circumstances. - \[lib\]\[breaking\] Exposed the state of the established transit connection - The `transit` module now returns whether the established connection is direct or not and the peer/relay's IP address - The `transfer` and `forwarding` modules now take a `transit_handler` argument. Use `&transit::log_transit_connection` as default value ### Fixed - Various bugfixes ## [0.4.0] - 2022-03-23 ### Added - Added `--force-relay` and `--force-direct` CLI flags that control the transit connection - The feature is also exposed in the API ### Changed - When sending, the code will now aumatically be copied into clipboard. So you don't have to select it in the terminal anymore before pasting! - Updated a lot of dependencies - Split the project into a workspace and feature gated some higher level protocols. This should now work way better on crates.io (and generally for library usage) ## [0.3.1] - 2022-03-22 ### Changed - yanked, changes moved to 0.4.0 ## [0.3.0] - 2022-03-06 ### Added - Added experimental port forwarding feature ### Fixed - Fixed `send-many` subcommand ### Changed - Improved user experience with better logging and messages - Improved error and cancellation handling - Cleaned up CLI args and implemented previous placeholders - Many internal refactorings to accomodate the changes. The public API did not change that much though. ## [0.2.0] - 2021-04-12 ### Added - Implemented version and verifier in the API - Added API documentation \o/ (still a long way to go though) - New features for file transfer - File acks are not sent automatically anymore, the receiver has to accept an offer now. - Existing files are not overwritten without permission ### Changed - Reworked Key API. It now uses type-level programming to distinguish key purposes, in the hope you'll never ever confuse them. - Internal improvements in Transit implementation. Little API changed except for the Keys. - Internal rewrite of the `core`. This resulted in no public API changes except that the receiver is now `TryStream` instead of `Stream` (error handling, yay). - Progress reporting support during transfers - `send-many` got improved ## [0.1.0] - 2020-11-03 ### Added - Merged Transit/Transfer implementation from @vu3rdd and made it work. ### Changed - Rewrote Wormhole API (and parts of Transit/Transfer as well) - Everything is async now (using `async_std`), there are no other (i.e. blocking) implementations. - The API exposed from `core` got flipped on its head too in the process. - Moved IO layer into core; ported it from `ws` to `async-tungstenite`. Removed all `tokio` dependencies. - Many other refactorings, thrown stuff around, in the hope of improving things. - Together with the changes noted above, the `io::*` modules got removed, as well as their Cargo feature flags (and dependencies). - There is only one feature flag left, it's for the binary. - A bit of progress on the CLI side - Added an experimental `send-many` command. It will create a code and then simply send the file over and over again in a loop. Might be useful. ## [0.0.2] - 2019-09-01 ### Changed - No change log provided ## [0.0.1] - 2018-12-21 ### Changed - Initial release magic-wormhole-0.7.6/Cargo.lock0000644000002263630000000000100117470ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aead" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", "generic-array", ] [[package]] name = "aes" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", "cpufeatures", ] [[package]] name = "aes-gcm" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", "aes", "cipher", "ctr", "ghash", "subtle", ] [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "android-tzdata" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "anstream" version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", "once_cell", "windows-sys 0.59.0", ] [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-attributes" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ "quote", "syn 1.0.109", ] [[package]] name = "async-channel" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", "event-listener 2.5.3", "futures-core", ] [[package]] name = "async-channel" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-executor" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", "fastrand", "futures-lite", "slab", ] [[package]] name = "async-global-executor" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.3.1", "async-executor", "async-io", "async-lock", "blocking", "futures-lite", "once_cell", ] [[package]] name = "async-io" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ "async-lock", "cfg-if", "concurrent-queue", "futures-io", "futures-lite", "parking", "polling", "rustix 0.38.44", "slab", "tracing", "windows-sys 0.59.0", ] [[package]] name = "async-lock" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener 5.4.0", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-native-tls" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9343dc5acf07e79ff82d0c37899f079db3534d99f189a1837c8e549c99405bec" dependencies = [ "futures-util", "native-tls", "thiserror 1.0.69", "url", ] [[package]] name = "async-process" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ "async-channel 2.3.1", "async-io", "async-lock", "async-signal", "async-task", "blocking", "cfg-if", "event-listener 5.4.0", "futures-lite", "rustix 0.38.44", "tracing", ] [[package]] name = "async-signal" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ "async-io", "async-lock", "atomic-waker", "cfg-if", "futures-core", "futures-io", "rustix 0.38.44", "signal-hook-registry", "slab", "windows-sys 0.59.0", ] [[package]] name = "async-std" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "730294c1c08c2e0f85759590518f6333f0d5a0a766a27d519c1b244c3dfd8a24" dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", "async-io", "async-lock", "async-process", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", "futures-lite", "gloo-timers", "kv-log-macro", "log", "memchr", "once_cell", "pin-project-lite", "pin-utils", "slab", "wasm-bindgen-futures", ] [[package]] name = "async-task" version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-tls" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ae3c9eba89d472a0e4fe1dea433df78fbbe63d2b764addaf2ba3a6bde89a5e" dependencies = [ "futures-core", "futures-io", "rustls", "rustls-pemfile", "webpki-roots", ] [[package]] name = "async-trait" version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "async-tungstenite" version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef0f7efedeac57d9b26170f72965ecfd31473ca52ca7a64e925b0b6f5f079886" dependencies = [ "async-native-tls", "async-std", "async-tls", "atomic-waker", "futures-core", "futures-io", "futures-task", "futures-util", "log", "pin-project-lite", "tungstenite", ] [[package]] name = "async_io_stream" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ "futures", "pharos", "rustc_version", ] [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "base64" version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bit-set" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "blake2" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ "digest", ] [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "blocking" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", "futures-lite", "piper", ] [[package]] name = "bumpalo" version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytecodec" version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adf4c9d0bbf32eea58d7c0f812058138ee8edaf0f2802b6d03561b504729a325" dependencies = [ "byteorder", "trackable 0.2.24", ] [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" version = "1.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" dependencies = [ "shlex", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chacha20" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", "cipher", "cpufeatures", ] [[package]] name = "chacha20poly1305" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ "aead", "chacha20", "cipher", "poly1305", "zeroize", ] [[package]] name = "chrono" version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", "windows-link", ] [[package]] name = "cipher" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", "zeroize", ] [[package]] name = "colorchoice" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "concurrent-queue" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] [[package]] name = "core-foundation" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crc" version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "rand_core 0.6.4", "typenum", ] [[package]] name = "crypto_secretbox" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d6cf87adf719ddf43a805e92c6870a531aedda35ff640442cbaf8674e141e1" dependencies = [ "aead", "cipher", "generic-array", "poly1305", "salsa20", "subtle", "zeroize", ] [[package]] name = "ctr" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ "cipher", ] [[package]] name = "curve25519-dalek" version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", "fiat-crypto", "rand_core 0.6.4", "rustc_version", "subtle", "zeroize", ] [[package]] name = "curve25519-dalek-derive" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "darling" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ "darling_core", "darling_macro", ] [[package]] name = "darling_core" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", "syn 2.0.100", ] [[package]] name = "darling_macro" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", "syn 2.0.100", ] [[package]] name = "data-encoding" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" [[package]] name = "deranged" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", ] [[package]] name = "derive_builder" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ "darling", "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "derive_builder_macro" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", "syn 2.0.100", ] [[package]] name = "derive_more" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", "unicode-xid", ] [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", "subtle", ] [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "env_filter" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", ] [[package]] name = "env_logger" version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", "env_filter", "log", ] [[package]] name = "errno" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", ] [[package]] name = "event-listener" version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] [[package]] name = "event-listener-strategy" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ "event-listener 5.4.0", "pin-project-lite", ] [[package]] name = "eyre" version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" dependencies = [ "indenter", "once_cell", ] [[package]] name = "fancy-regex" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" dependencies = [ "bit-set", "regex-automata 0.4.9", "regex-syntax 0.8.5", ] [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fiat-crypto" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "filetime" version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", "libredox", "windows-sys 0.59.0", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ "foreign-types-shared", ] [[package]] name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", "futures-executor", "futures-io", "futures-sink", "futures-task", "futures-util", ] [[package]] name = "futures-channel" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", ] [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-io" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" dependencies = [ "fastrand", "futures-core", "futures-io", "parking", "pin-project-lite", ] [[package]] name = "futures-macro" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "futures-sink" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-macro", "futures-sink", "futures-task", "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "fuzzt" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a15f3d0fa42283a765e5fb609683ddab4ee4ff245d8db66a24d926c05e518c6" [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", "zeroize", ] [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] [[package]] name = "getrandom" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", "libc", "r-efi", "wasi 0.14.2+wasi-0.2.4", ] [[package]] name = "ghash" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ "opaque-debug", "polyval", ] [[package]] name = "gloo-timers" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", "js-sys", "wasm-bindgen", ] [[package]] name = "hermit-abi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" dependencies = [ "serde", ] [[package]] name = "hkdf" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] [[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ "digest", ] [[package]] name = "http" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", "itoa", ] [[package]] name = "httparse" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "iana-time-zone" version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "log", "wasm-bindgen", "windows-core", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "icu_collections" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ "displaydoc", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locid" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_locid_transform" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ "displaydoc", "icu_locid", "icu_locid_transform_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_locid_transform_data" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] name = "icu_normalizer" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "utf16_iter", "utf8_iter", "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" [[package]] name = "icu_properties" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" dependencies = [ "displaydoc", "icu_collections", "icu_locid_transform", "icu_properties_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_properties_data" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" [[package]] name = "icu_provider" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", "icu_locid", "icu_provider_macros", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_provider_macros" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "if-addrs" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69b2eeee38fef3aa9b4cc5f1beea8a2444fc00e7377cafae396de3f5c2065e24" dependencies = [ "libc", "windows-sys 0.59.0", ] [[package]] name = "indenter" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "inout" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "generic-array", ] [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "kv-log-macro" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" dependencies = [ "log", ] [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags", "libc", "redox_syscall", ] [[package]] name = "linux-raw-sys" version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "litemap" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" [[package]] name = "log" version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" dependencies = [ "value-bag", ] [[package]] name = "magic-wormhole" version = "0.7.6" dependencies = [ "async-io", "async-std", "async-trait", "async-tungstenite", "base64 0.22.1", "bytecodec", "crypto_secretbox", "derive_more", "eyre", "futures", "fuzzt", "getrandom 0.2.15", "hex", "hkdf", "if-addrs", "libc", "noise-protocol", "noise-rust-crypto", "percent-encoding", "rand 0.8.5", "rmp-serde", "serde", "serde_derive", "serde_json", "sha-1", "sha2", "socket2", "spake2", "stun_codec", "tar", "test-log", "thiserror 1.0.69", "time", "tracing", "url", "wasm-bindgen-test", "ws_stream_wasm", "zxcvbn", ] [[package]] name = "matchers" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ "regex-automata 0.1.10", ] [[package]] name = "md5" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "minicov" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" dependencies = [ "cc", "walkdir", ] [[package]] name = "native-tls" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ "libc", "log", "openssl", "openssl-probe", "openssl-sys", "schannel", "security-framework", "security-framework-sys", "tempfile", ] [[package]] name = "noise-protocol" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2473d39689a839f5a363aaef7d99f76d5611bf352286682b25a6644fec18b1d3" dependencies = [ "arrayvec", ] [[package]] name = "noise-rust-crypto" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c6159f60beb3bbbcdc266bc789bfc6c37fdad7d7ca7152d3e049ef5af633f0" dependencies = [ "aes-gcm", "blake2", "chacha20poly1305", "noise-protocol", "sha2", "x25519-dalek", "zeroize", ] [[package]] name = "nu-ansi-term" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ "overload", "winapi", ] [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "opaque-debug" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" version = "0.10.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" dependencies = [ "bitflags", "cfg-if", "foreign-types", "libc", "once_cell", "openssl-macros", "openssl-sys", ] [[package]] name = "openssl-macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "openssl-probe" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" version = "0.9.107" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" dependencies = [ "cc", "libc", "pkg-config", "vcpkg", ] [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parking" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pharos" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ "futures", "rustc_version", ] [[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", "fastrand", "futures-io", ] [[package]] name = "pkg-config" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "polling" version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", "rustix 0.38.44", "tracing", "windows-sys 0.59.0", ] [[package]] name = "poly1305" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", "opaque-debug", "universal-hash", ] [[package]] name = "polyval" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", "opaque-debug", "universal-hash", ] [[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] [[package]] name = "proc-macro2" version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", ] [[package]] name = "rand" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", "zerocopy", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core 0.6.4", ] [[package]] name = "rand_chacha" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core 0.9.3", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom 0.2.15", ] [[package]] name = "rand_core" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom 0.3.2", ] [[package]] name = "redox_syscall" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ "bitflags", ] [[package]] name = "regex" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.9", "regex-syntax 0.8.5", ] [[package]] name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ "regex-syntax 0.6.29", ] [[package]] name = "regex-automata" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", "regex-syntax 0.8.5", ] [[package]] name = "regex-syntax" version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ring" version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", "getrandom 0.2.15", "libc", "untrusted", "windows-sys 0.52.0", ] [[package]] name = "rmp" version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" dependencies = [ "byteorder", "num-traits", "paste", ] [[package]] name = "rmp-serde" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" dependencies = [ "byteorder", "rmp", "serde", ] [[package]] name = "rustc_version" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] name = "rustix" version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys 0.4.15", "windows-sys 0.59.0", ] [[package]] name = "rustix" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys 0.9.3", "windows-sys 0.59.0", ] [[package]] name = "rustls" version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", "rustls-webpki", "sct", ] [[package]] name = "rustls-pemfile" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ "base64 0.21.7", ] [[package]] name = "rustls-webpki" version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ "ring", "untrusted", ] [[package]] name = "rustversion" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "ryu" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa20" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" dependencies = [ "cipher", ] [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "schannel" version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "sct" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", ] [[package]] name = "security-framework" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags", "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", ] [[package]] name = "security-framework-sys" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "semver" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "send_wrapper" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "serde_json" version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "sha-1" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "sha1" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "sharded-slab" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "socket2" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "spake2" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5482afe85a0b6ce956c945401598dbc527593c77ba51d0a87a586938b1b893a" dependencies = [ "curve25519-dalek", "hkdf", "rand_core 0.6.4", "sha2", ] [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "stun_codec" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feed9dafe0bda84f2b6ca3ce726b0a1f1ac2e8b63c6ecfb89b08b32313247b5b" dependencies = [ "bytecodec", "byteorder", "crc", "hmac", "md5", "sha1", "trackable 1.3.0", ] [[package]] name = "subtle" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "tar" version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" dependencies = [ "filetime", "libc", "xattr", ] [[package]] name = "tempfile" version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ "fastrand", "getrandom 0.3.2", "once_cell", "rustix 1.0.5", "windows-sys 0.59.0", ] [[package]] name = "test-log" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f46083d221181166e5b6f6b1e5f1d499f3a76888826e6cb1d057554157cd0f" dependencies = [ "env_logger", "test-log-macros", "tracing-subscriber", ] [[package]] name = "test-log-macros" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "888d0c3c6db53c0fdab160d2ed5e12ba745383d3e85813f2ea0f2b1475ab553f" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "thiserror" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl 1.0.69", ] [[package]] name = "thiserror" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ "thiserror-impl 2.0.12", ] [[package]] name = "thiserror-impl" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "thiserror-impl" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "thread_local" version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", ] [[package]] name = "time" version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", "serde", "time-core", "time-macros", ] [[package]] name = "time-core" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", ] [[package]] name = "tinystr" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "tracing" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "tracing-core" version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", ] [[package]] name = "tracing-log" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ "log", "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", "once_cell", "regex", "sharded-slab", "thread_local", "tracing", "tracing-core", "tracing-log", ] [[package]] name = "trackable" version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98abb9e7300b9ac902cc04920945a874c1973e08c310627cc4458c04b70dd32" dependencies = [ "trackable 1.3.0", "trackable_derive", ] [[package]] name = "trackable" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15bd114abb99ef8cee977e517c8f37aee63f184f2d08e3e6ceca092373369ae" dependencies = [ "trackable_derive", ] [[package]] name = "trackable_derive" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebeb235c5847e2f82cfe0f07eb971d1e5f6804b18dac2ae16349cc604380f82f" dependencies = [ "quote", "syn 1.0.109", ] [[package]] name = "tungstenite" version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" dependencies = [ "bytes", "data-encoding", "http", "httparse", "log", "native-tls", "rand 0.9.0", "sha1", "thiserror 2.0.12", "utf-8", ] [[package]] name = "typenum" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-xid" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", "subtle", ] [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", ] [[package]] name = "utf-8" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "utf16_iter" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "value-bag" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] [[package]] name = "wasm-bindgen" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", "syn 2.0.100", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-bindgen-test" version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" dependencies = [ "js-sys", "minicov", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test-macro", ] [[package]] name = "wasm-bindgen-test-macro" version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "web-sys" version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "webpki" version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ "ring", "untrusted", ] [[package]] name = "webpki-roots" version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ "webpki", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ "windows-implement", "windows-interface", "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-implement" version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "windows-interface" version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "windows-link" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] name = "windows-result" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" dependencies = [ "windows-link", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "wit-bindgen-rt" version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags", ] [[package]] name = "write16" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "ws_stream_wasm" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" dependencies = [ "async_io_stream", "futures", "js-sys", "log", "pharos", "rustc_version", "send_wrapper", "thiserror 1.0.69", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", ] [[package]] name = "x25519-dalek" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek", "rand_core 0.6.4", "zeroize", ] [[package]] name = "xattr" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" dependencies = [ "libc", "rustix 1.0.5", ] [[package]] name = "yoke" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", "synstructure", ] [[package]] name = "zerocopy" version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "zerofrom" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", "synstructure", ] [[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "zerovec" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", "syn 2.0.100", ] [[package]] name = "zxcvbn" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad76e35b00ad53688d6b90c431cabe3cbf51f7a4a154739e04b63004ab1c736c" dependencies = [ "chrono", "derive_builder", "fancy-regex", "itertools", "lazy_static", "regex", "time", "wasm-bindgen", "web-sys", ] magic-wormhole-0.7.6/Cargo.toml0000644000000106570000000000100117670ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.81" name = "magic-wormhole" version = "0.7.6" authors = [ "Fina Wilke ", "piegames ", "Brian Warner ", ] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Get things from one computer to another, safely" homepage = "http://magic-wormhole.io/" documentation = "https://docs.rs/magic-wormhole/latest/" readme = "README.md" keywords = [ "magic-wormhole", "wormhole", "file-transfer", "transfer", ] categories = [ "network-programming", "asynchronous", ] license = "EUPL-1.2" repository = "https://github.com/magic-wormhole/magic-wormhole.rs/tree/main/cli" [package.metadata.docs.rs] features = ["all"] [features] all = [ "default", "forwarding", "fuzzy-complete", ] default = [ "transit", "transfer", ] entropy = ["zxcvbn"] experimental = ["experimental-transfer-v2"] experimental-transfer-v2 = [] forwarding = [ "transit", "dep:rmp-serde", ] fuzzy-complete = ["fuzzt"] native-tls = ["async-tungstenite/async-native-tls"] tls = ["async-tungstenite/async-tls"] transfer = [ "transit", "dep:tar", "dep:rmp-serde", ] transit = [ "dep:noise-rust-crypto", "dep:noise-protocol", "dep:socket2", "dep:stun_codec", "dep:if-addrs", "dep:bytecodec", "dep:async-trait", ] [lib] name = "magic_wormhole" path = "src/lib.rs" [dependencies.async-std] version = "1.12.0" features = [ "attributes", "unstable", ] [dependencies.async-trait] version = "0.1.57" optional = true [dependencies.base64] version = "0.22.0" [dependencies.bytecodec] version = "0.4.15" optional = true [dependencies.crypto_secretbox] version = "0.1.1" [dependencies.derive_more] version = "1.0" features = [ "display", "deref", "from", ] default-features = false [dependencies.futures] version = "0.3.12" [dependencies.fuzzt] version = "0.3.1" optional = true [dependencies.hex] version = "0.4.2" features = ["serde"] [dependencies.hkdf] version = "0.12.2" [dependencies.noise-protocol] version = "0.2" optional = true [dependencies.noise-rust-crypto] version = "0.6.0-rc.1" optional = true [dependencies.percent-encoding] version = "2.1.0" [dependencies.rand] version = "0.8.3" [dependencies.rmp-serde] version = "1.0.0" optional = true [dependencies.serde] version = "1.0.120" features = ["rc"] [dependencies.serde_derive] version = "1.0.120" [dependencies.serde_json] version = "1.0.61" [dependencies.sha-1] version = "0.10.0" [dependencies.sha2] version = "0.10.0" [dependencies.spake2] version = "0.4.0" [dependencies.stun_codec] version = "0.3.0" optional = true [dependencies.tar] version = "0.4.33" optional = true [dependencies.thiserror] version = "1.0.24" [dependencies.time] version = "0.3.7" features = ["formatting"] [dependencies.tracing] version = "0.1" features = [ "log", "log-always", ] [dependencies.url] version = "2.2.2" features = ["serde"] [dependencies.zxcvbn] version = "3.1.0" optional = true [dev-dependencies.eyre] version = "0.6.5" [dev-dependencies.test-log] version = "0.2" [target.'cfg(not(target_family = "wasm"))'.dependencies.async-io] version = "2.2.0" [target.'cfg(not(target_family = "wasm"))'.dependencies.async-tungstenite] version = "0.29" features = ["async-std-runtime"] [target.'cfg(not(target_family = "wasm"))'.dependencies.if-addrs] version = "0.13" optional = true [target.'cfg(not(target_family = "wasm"))'.dependencies.libc] version = "0.2.101" [target.'cfg(not(target_family = "wasm"))'.dependencies.socket2] version = "0.5.0" features = ["all"] optional = true [target.'cfg(target_family = "wasm")'.dependencies.getrandom] version = "0.2.5" features = ["js"] [target.'cfg(target_family = "wasm")'.dependencies.ws_stream_wasm] version = "0.7.3" [target.'cfg(target_family = "wasm")'.dev-dependencies.wasm-bindgen-test] version = "0.3" [profile.release] lto = "thin" overflow-checks = true strip = "debuginfo" magic-wormhole-0.7.6/Cargo.toml.orig000064400000000000000000000114571046102023000154470ustar 00000000000000[workspace] members = [".", "cli"] default-members = ["cli"] [workspace.package] version = "0.7.6" authors = [ "Fina Wilke ", "piegames ", "Brian Warner ", ] description = "Get things from one computer to another, safely" keywords = ["magic-wormhole", "wormhole", "file-transfer", "transfer"] homepage = "http://magic-wormhole.io/" repository = "https://github.com/magic-wormhole/magic-wormhole.rs/tree/main/cli" license = "EUPL-1.2" rust-version = "1.81" edition = "2021" [workspace.dependencies] arboard = "3.2.0" async-std = "1.12.0" async-trait = "0.1.57" base64 = "0.22.0" bytecodec = "0.4.15" clap = "4" clap_complete = "4" color-eyre = "0.6.0" console = "0.15.0" crypto_secretbox = "0.1.1" ctrlc = "3.2.1" derive_more = { version = "1.0", default-features = false } dialoguer = "0.11" env_logger = "0.11" eyre = "0.6.5" futures = "0.3.12" hex = "0.4.2" hkdf = "0.12.2" indicatif = "0.17.0" noise-protocol = "0.2" noise-rust-crypto = "0.6.0-rc.1" number_prefix = "0.4.0" percent-encoding = "2.1.0" qr2term = "0.3.0" rand = "0.8.3" rmp-serde = "1.0.0" serde = "1.0.120" serde_derive = "1.0.120" serde_json = "1.0.61" sha-1 = "0.10.0" sha2 = "0.10.0" spake2 = "0.4.0" stun_codec = "0.3.0" tar = "0.4.33" thiserror = "1.0.24" time = "0.3.7" trycmd = "0.15" url = "2.2.2" tracing = "0.1" tracing-subscriber = "0.3" test-log = "0.2" zxcvbn = "3.1.0" [package] name = "magic-wormhole" categories = ["network-programming", "asynchronous"] documentation = "https://docs.rs/magic-wormhole/latest/" readme = "README.md" version.workspace = true authors.workspace = true description.workspace = true keywords.workspace = true homepage.workspace = true repository.workspace = true license.workspace = true rust-version.workspace = true edition.workspace = true [package.metadata.docs.rs] features = ["all"] [dependencies] serde = { workspace = true, features = ["rc"] } serde_json = { workspace = true } serde_derive = { workspace = true } crypto_secretbox = { workspace = true } spake2 = { workspace = true } sha-1 = { workspace = true } sha2 = { workspace = true } hkdf = { workspace = true } hex = { workspace = true, features = ["serde"] } rand = { workspace = true } base64 = { workspace = true } time = { workspace = true, features = ["formatting"] } derive_more = { workspace = true, features = ["display", "deref", "from"] } thiserror = { workspace = true } futures = { workspace = true } url = { workspace = true, features = ["serde"] } percent-encoding = { workspace = true } zxcvbn = { workspace = true, optional = true } tracing = { workspace = true, features = ["log", "log-always"] } fuzzt = { version = "0.3.1", optional = true } # Transit dependencies stun_codec = { workspace = true, optional = true } bytecodec = { workspace = true, optional = true } noise-rust-crypto = { workspace = true, optional = true } async-std = { version = "1.12.0", features = ["attributes", "unstable"] } async-trait = { workspace = true, optional = true } noise-protocol = { workspace = true, optional = true } # Transfer dependencies rmp-serde = { workspace = true, optional = true } tar = { workspace = true, optional = true } # Forwarding dependencies # rmp-serde = … # defined above [target.'cfg(not(target_family = "wasm"))'.dependencies] libc = "0.2.101" async-tungstenite = { version = "0.29", features = ["async-std-runtime"] } async-io = "2.2.0" # Transit socket2 = { version = "0.5.0", optional = true, features = ["all"] } if-addrs = { version = "0.13", optional = true } # Transfer [target.'cfg(target_family = "wasm")'.dependencies] ws_stream_wasm = "0.7.3" getrandom = { version = "0.2.5", features = ["js"] } # for some tests [dev-dependencies] test-log = { workspace = true } eyre = { workspace = true } [target.'cfg(target_family = "wasm")'.dev-dependencies] wasm-bindgen-test = "0.3" [features] # Check the entropy of custom codes. Will fail for any weak passwords. entropy = ["zxcvbn"] transfer = ["transit", "dep:tar", "dep:rmp-serde"] transit = [ "dep:noise-rust-crypto", "dep:noise-protocol", "dep:socket2", "dep:stun_codec", "dep:if-addrs", "dep:bytecodec", "dep:async-trait", ] forwarding = ["transit", "dep:rmp-serde"] default = ["transit", "transfer"] all = ["default", "forwarding", "fuzzy-complete"] # TLS implementations for websocket connections via async-tungstenite # required for optional wss connection to the mailbox server tls = ["async-tungstenite/async-tls"] native-tls = ["async-tungstenite/async-native-tls"] # Enable experimental transfer-v2 support. The protocol is not yet finalized and is subject to change. # By enabling this option you are opting out of semver stability. experimental-transfer-v2 = [] experimental = ["experimental-transfer-v2"] fuzzy-complete = ["fuzzt"] [profile.release] overflow-checks = true strip = "debuginfo" lto = "thin" magic-wormhole-0.7.6/LICENSE000064400000000000000000000330031046102023000135540ustar 00000000000000 EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016 This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined below) which is provided under the terms of this Licence. Any use of the Work, other than as authorised under this Licence is prohibited (to the extent such use is covered by a right of the copyright holder of the Work). The Work is provided under the terms of this Licence when the Licensor (as defined below) has placed the following notice immediately following the copyright notice for the Work: Licensed under the EUPL or has expressed by any other means his willingness to license under the EUPL. 1. Definitions In this Licence, the following terms have the following meaning: - ‘The Licence’: this Licence. - ‘The Original Work’: the work or software distributed or communicated by the Licensor under this Licence, available as Source Code and also as Executable Code as the case may be. - ‘Derivative Works’: the works or software that could be created by the Licensee, based upon the Original Work or modifications thereof. This Licence does not define the extent of modification or dependence on the Original Work required in order to classify a work as a Derivative Work; this extent is determined by copyright law applicable in the country mentioned in Article 15. - ‘The Work’: the Original Work or its Derivative Works. - ‘The Source Code’: the human-readable form of the Work which is the most convenient for people to study and modify. - ‘The Executable Code’: any code which has generally been compiled and which is meant to be interpreted by a computer as a program. - ‘The Licensor’: the natural or legal person that distributes or communicates the Work under the Licence. - ‘Contributor(s)’: any natural or legal person who modifies the Work under the Licence, or otherwise contributes to the creation of a Derivative Work. - ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of the Work under the terms of the Licence. - ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, renting, distributing, communicating, transmitting, or otherwise making available, online or offline, copies of the Work or providing access to its essential functionalities at the disposal of any other natural or legal person. 2. Scope of the rights granted by the Licence The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, sublicensable licence to do the following, for the duration of copyright vested in the Original Work: - use the Work in any circumstance and for all usage, - reproduce the Work, - modify the Work, and make Derivative Works based upon the Work, - communicate to the public, including the right to make available or display the Work or copies thereof to the public and perform publicly, as the case may be, the Work, - distribute the Work or copies thereof, - lend and rent the Work or copies thereof, - sublicense rights in the Work or copies thereof. Those rights can be exercised on any media, supports and formats, whether now known or later invented, as far as the applicable law permits so. In the countries where moral rights apply, the Licensor waives his right to exercise his moral right to the extent allowed by law in order to make effective the licence of the economic rights here above listed. The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to any patents held by the Licensor, to the extent necessary to make use of the rights granted on the Work under this Licence. 3. Communication of the Source Code The Licensor may provide the Work either in its Source Code form, or as Executable Code. If the Work is provided as Executable Code, the Licensor provides in addition a machine-readable copy of the Source Code of the Work along with each copy of the Work that the Licensor distributes or indicates, in a notice following the copyright notice attached to the Work, a repository where the Source Code is easily and freely accessible for as long as the Licensor continues to distribute or communicate the Work. 4. Limitations on copyright Nothing in this Licence is intended to deprive the Licensee of the benefits from any exception or limitation to the exclusive rights of the rights owners in the Work, of the exhaustion of those rights or of other applicable limitations thereto. 5. Obligations of the Licensee The grant of the rights mentioned above is subject to some restrictions and obligations imposed on the Licensee. Those obligations are the following: Attribution right: The Licensee shall keep intact all copyright, patent or trademarks notices and all notices that refer to the Licence and to the disclaimer of warranties. The Licensee must include a copy of such notices and a copy of the Licence with every copy of the Work he/she distributes or communicates. The Licensee must cause any Derivative Work to carry prominent notices stating that the Work has been modified and the date of modification. Copyleft clause: If the Licensee distributes or communicates copies of the Original Works or Derivative Works, this Distribution or Communication will be done under the terms of this Licence or of a later version of this Licence unless the Original Work is expressly distributed only under this version of the Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee (becoming Licensor) cannot offer or impose any additional terms or conditions on the Work or Derivative Work that alter or restrict the terms of the Licence. Compatibility clause: If the Licensee Distributes or Communicates Derivative Works or copies thereof based upon both the Work and another work licensed under a Compatible Licence, this Distribution or Communication can be done under the terms of this Compatible Licence. For the sake of this clause, ‘Compatible Licence’ refers to the licences listed in the appendix attached to this Licence. Should the Licensee's obligations under the Compatible Licence conflict with his/her obligations under this Licence, the obligations of the Compatible Licence shall prevail. Provision of Source Code: When distributing or communicating copies of the Work, the Licensee will provide a machine-readable copy of the Source Code or indicate a repository where this Source will be easily and freely available for as long as the Licensee continues to distribute or communicate the Work. Legal Protection: This Licence does not grant permission to use the trade names, trademarks, service marks, or names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the copyright notice. 6. Chain of Authorship The original Licensor warrants that the copyright in the Original Work granted hereunder is owned by him/her or licensed to him/her and that he/she has the power and authority to grant the Licence. Each Contributor warrants that the copyright in the modifications he/she brings to the Work are owned by him/her or licensed to him/her and that he/she has the power and authority to grant the Licence. Each time You accept the Licence, the original Licensor and subsequent Contributors grant You a licence to their contributions to the Work, under the terms of this Licence. 7. Disclaimer of Warranty The Work is a work in progress, which is continuously improved by numerous Contributors. It is not a finished work and may therefore contain defects or ‘bugs’ inherent to this type of development. For the above reason, the Work is provided under the Licence on an ‘as is’ basis and without warranties of any kind concerning the Work, including without limitation merchantability, fitness for a particular purpose, absence of defects or errors, accuracy, non-infringement of intellectual property rights other than copyright as stated in Article 6 of this Licence. This disclaimer of warranty is an essential part of the Licence and a condition for the grant of any rights to the Work. 8. Disclaimer of Liability Except in the cases of wilful misconduct or damages directly caused to natural persons, the Licensor will in no event be liable for any direct or indirect, material or moral, damages of any kind, arising out of the Licence or of the use of the Work, including without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, loss of data or any commercial damage, even if the Licensor has been advised of the possibility of such damage. However, the Licensor will be liable under statutory product liability laws as far such laws apply to the Work. 9. Additional agreements While distributing the Work, You may choose to conclude an additional agreement, defining obligations or services consistent with this Licence. However, if accepting obligations, You may act only on your own behalf and on your sole responsibility, not on behalf of the original Licensor or any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against such Contributor by the fact You have accepted any warranty or additional liability. 10. Acceptance of the Licence The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ placed under the bottom of a window displaying the text of this Licence or by affirming consent in any other similar way, in accordance with the rules of applicable law. Clicking on that icon indicates your clear and irrevocable acceptance of this Licence and all of its terms and conditions. Similarly, you irrevocably accept this Licence and all of its terms and conditions by exercising any rights granted to You by Article 2 of this Licence, such as the use of the Work, the creation by You of a Derivative Work or the Distribution or Communication by You of the Work or copies thereof. 11. Information to the public In case of any Distribution or Communication of the Work by means of electronic communication by You (for example, by offering to download the Work from a remote location) the distribution channel or media (for example, a website) must at least provide to the public the information requested by the applicable law regarding the Licensor, the Licence and the way it may be accessible, concluded, stored and reproduced by the Licensee. 12. Termination of the Licence The Licence and the rights granted hereunder will terminate automatically upon any breach by the Licensee of the terms of the Licence. Such a termination will not terminate the licences of any person who has received the Work from the Licensee under the Licence, provided such persons remain in full compliance with the Licence. 13. Miscellaneous Without prejudice of Article 9 above, the Licence represents the complete agreement between the Parties as to the Work. If any provision of the Licence is invalid or unenforceable under applicable law, this will not affect the validity or enforceability of the Licence as a whole. Such provision will be construed or reformed so as necessary to make it valid and enforceable. The European Commission may publish other linguistic versions or new versions of this Licence or updated versions of the Appendix, so far this is required and reasonable, without reducing the scope of the rights granted by the Licence. New versions of the Licence will be published with a unique version number. All linguistic versions of this Licence, approved by the European Commission, have identical value. Parties can take advantage of the linguistic version of their choice. 14. Jurisdiction Without prejudice to specific agreement between parties, - any litigation resulting from the interpretation of this License, arising between the European Union institutions, bodies, offices or agencies, as a Licensor, and any Licensee, will be subject to the jurisdiction of the Court of Justice of the European Union, as laid down in article 272 of the Treaty on the Functioning of the European Union, - any litigation arising between other parties and resulting from the interpretation of this License, will be subject to the exclusive jurisdiction of the competent court where the Licensor resides or conducts its primary business. 15. Applicable Law Without prejudice to specific agreement between parties, - this Licence shall be governed by the law of the European Union Member State where the Licensor has his seat, resides or has his registered office, - this licence shall be governed by Belgian law if the Licensor has no seat, residence or registered office inside a European Union Member State. Appendix ‘Compatible Licences’ according to Article 5 EUPL are: - GNU General Public License (GPL) v. 2, v. 3 - GNU Affero General Public License (AGPL) v. 3 - Open Software License (OSL) v. 2.1, v. 3.0 - Eclipse Public License (EPL) v. 1.0 - CeCILL v. 2.0, v. 2.1 - Mozilla Public Licence (MPL) v. 2 - GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 - Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for works other than software - European Union Public Licence (EUPL) v. 1.1, v. 1.2 - Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong Reciprocity (LiLiQ-R+). The European Commission may update this Appendix to later versions of the above licences without producing a new version of the EUPL, as long as they provide the rights granted in Article 2 of this Licence and protect the covered Source Code from exclusive appropriation. All other changes or additions to this Appendix require the production of a new EUPL version. magic-wormhole-0.7.6/MAINTENANCE.md000064400000000000000000000006661046102023000146240ustar 00000000000000# Maintenance documentation ## Release To create a new release, follow these steps: - Update version number in the workspace Cargo.toml - Update CHANGELOG.md with release version and date - Update Cargo.lock - Commit & push the changes - Tag the commit: `git tag -as a.b.c` - Push the tag: `git push origin a.b.c` - Verify GitHub release was created by CI - Push a new crate version to crates.io with `cargo publish -p magic-wormhole` magic-wormhole-0.7.6/README.md000064400000000000000000000062611046102023000140340ustar 00000000000000# Rusty Wormhole Get things from one computer to another, safely. This is a Rust port of the Python version at . ## Comparison with the Python implementation Features that are missing: - Text message sending - Folder sending (we can send folders, but it will send a tar ball which the other side will have to manually unpack) - Tor support New features that exceed the other implementations: - Can do direct connections across the internet (NATs) and firewalls - Automatically copies your code to the clipboard - Port forwarding in addition to file transfer (experimental) - Send a file to multiple people (experimental) - Fuzzy wormhole code completion ## Getting started If you want to toy with the CLI, `cargo run -- --help` will get you started. The code sits in `./cli/src`. For more instructions see [cli/README.md](cli/README.md). If you'd like to use Wormhole in your application, `cargo doc --open` will tell you how to use it. There aren't any hosted docs at the moment. If you don't fear touching code and want to contribute, `./src/lib.rs`, `./src/transfer.rs` and `./src/transit.rs` are rather easy to get into. The [protocol specification](https://github.com/magic-wormhole/magic-wormhole-protocols) will probably be useful to you. ## Applications using Wormhole Rust as library - [Warp](https://gitlab.gnome.org/World/warp), a GUI client using Gtk - [Wormhole File Transfer](https://gitlab.com/lukas-heiligenbrunner/wormhole), a Android client using Flutter (feel free to add yours) ## License This work is licensed under the EUPL v1.2 or later. Contact the owner(s) for use in proprietary software. ---------- [![Matrix][matrix-room-image]][matrix-room-url] [![Irc][irc-room-image]][irc-room-url] ![Build Status][build-status-image] [![Deps][deps-status-image]][deps-status-url] [![Codecov][codecov-image]][codecov-url] [![Is-It-Maintained-Resolution-Time][iim-resolution-image]][iim-resolution-url] [![Crates.io][crates-io-image]][crates-io-url] [![Docs.rs][docs-image]][docs-url] [matrix-room-image]: https://img.shields.io/badge/matrix.org-%23magic--wormhole-brightgreen [matrix-room-url]: https://matrix.to/#/#magic-wormhole:matrix.org [irc-room-image]: https://img.shields.io/badge/irc.libera.chat-%23magic--wormhole-brightgreen [irc-room-url]: https://web.libera.chat/ [build-status-image]: https://github.com/magic-wormhole/magic-wormhole.rs/workflows/Rust/badge.svg [deps-status-image]: https://deps.rs/repo/github/magic-wormhole/magic-wormhole.rs/status.svg [deps-status-url]: https://deps.rs/repo/github/magic-wormhole/magic-wormhole.rs [codecov-image]: https://codecov.io/gh/magic-wormhole/magic-wormhole.rs/branch/main/graph/badge.svg [codecov-url]: https://codecov.io/gh/magic-wormhole/magic-wormhole.rs [crates-io-image]: https://img.shields.io/crates/v/magic-wormhole.svg [crates-io-url]: https://crates.io/crates/magic-wormhole [docs-image]: https://docs.rs/magic-wormhole/badge.svg [docs-url]: https://docs.rs/magic-wormhole [iim-resolution-image]: http://isitmaintained.com/badge/resolution/magic-wormhole/magic-wormhole.rs.svg [iim-resolution-url]: http://isitmaintained.com/project/magic-wormhole/magic-wormhole.rs magic-wormhole-0.7.6/deny.toml000064400000000000000000000014441046102023000144070ustar 00000000000000[advisories] db-urls = ["https://github.com/rustsec/advisory-db"] yanked = "warn" ignore = [] [licenses] allow = [ "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC", "MIT", "MPL-2.0", "OpenSSL", "Unicode-3.0", "Unlicense", ] [licenses.private] ignore = false registries = [] [[licenses.exceptions]] allow = ["EUPL-1.2"] name = "magic-wormhole" version = "*" [[licenses.clarify]] name = "ring" version = "*" expression = "MIT AND ISC AND OpenSSL" license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }] [bans] multiple-versions = "warn" wildcards = "allow" highlight = "all" allow = [] deny = [] skip = [] skip-tree = [] [sources] unknown-registry = "warn" unknown-git = "warn" allow-registry = ["https://github.com/rust-lang/crates.io-index"] allow-git = [] magic-wormhole-0.7.6/src/core/key.rs000064400000000000000000000324561046102023000154370ustar 00000000000000use crate::core::*; use crypto_secretbox as secretbox; use crypto_secretbox::{ aead::{generic_array::GenericArray, Aead, AeadCore}, KeyInit, XSalsa20Poly1305, }; use hkdf::Hkdf; use serde_derive::{Deserialize, Serialize}; use sha2::{digest::FixedOutput, Digest, Sha256}; use spake2::{Ed25519Group, Identity, Password, Spake2}; /// Marker trait to give encryption keys a "purpose", to not confuse them /// /// See [`Key`]. pub trait KeyPurpose: std::fmt::Debug {} /// The type of main key of the Wormhole #[derive(Debug)] pub struct WormholeKey; impl KeyPurpose for WormholeKey {} /// A generic key purpose for ad-hoc subkeys or if you don't care. #[derive(Debug)] #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] pub struct GenericKey; impl KeyPurpose for GenericKey {} /** * The symmetric encryption key used to communicate with the other side. * * You don't need to do any crypto, but you might need it to derive subkeys for sub-protocols. */ #[derive(Debug, Clone, derive_more::Display, derive_more::Deref)] #[display("{:?}", _0)] #[deref(forward)] pub struct Key( #[deref] #[deprecated( since = "0.7.0", note = "Use the AsRef implementation to get access to the secretbox key" )] pub Box, #[deref(ignore)] std::marker::PhantomData

, ); impl Key { /** * Derive the sub-key used for transit * * This one's a bit special, since the Wormhole's AppID is included in the purpose. Different kinds of applications * can't talk to each other, not even accidentally, by design. * * The new key is derived with the `"{appid}/transit-key"` purpose. */ #[cfg(feature = "transit")] #[deprecated( since = "0.7.0", note = "This will be a private method in the future. Open an issue if you require access to protocol intrinsics in the future" )] pub fn derive_transit_key(&self, appid: &AppID) -> Key { let transit_purpose = format!("{}/transit-key", appid); let derived_key = self.derive_subkey_from_purpose(&transit_purpose); tracing::trace!( "Input key: {}, Transit key: {}, Transit purpose: '{}'", self.to_hex(), derived_key.to_hex(), &transit_purpose ); derived_key } } impl Key

{ /// Create a new key pub fn new(key: Box) -> Self { Self(key, std::marker::PhantomData) } /// Encode a key as a hex string pub fn to_hex(&self) -> String { hex::encode(**self) } /** * Derive a new sub-key from this one */ pub fn derive_subkey_from_purpose(&self, purpose: &str) -> Key { Key( Box::new(derive_key(self, purpose.as_bytes())), std::marker::PhantomData, ) } } #[derive(Serialize, Deserialize, Debug)] struct PhaseMessage { #[serde(with = "hex::serde")] pake_v1: Vec, } /// TODO doc /// /// The "password" usually is the code, but it needs not to. The only requirement /// is that both sides use the same value, and agree on that. pub fn make_pake(password: &str, appid: &AppID) -> (Spake2, Vec) { let (pake_state, msg1) = Spake2::::start_symmetric( &Password::new(password.as_bytes()), &Identity::new(appid.0.as_bytes()), ); let pake_msg = PhaseMessage { pake_v1: msg1 }; let pake_msg_ser = serde_json::to_vec(&pake_msg).unwrap(); (pake_state, pake_msg_ser) } #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct VersionsMessage { #[serde(default)] pub abilities: Vec, #[serde(default)] pub app_versions: serde_json::Value, // resume: Option, } impl VersionsMessage { pub fn new() -> Self { Default::default() } pub fn set_app_versions(&mut self, versions: serde_json::Value) { self.app_versions = versions; } // pub fn add_resume_ability(&mut self, _resume: ()) { // self.abilities.push("resume-v1".into()) // } } pub fn build_version_msg( side: &MySide, key: &secretbox::Key, versions: &VersionsMessage, ) -> (Phase, Vec) { let phase = Phase::VERSION; let data_key = derive_phase_key(side, key, &phase); let plaintext = serde_json::to_vec(versions).unwrap(); let (_nonce, encrypted) = encrypt_data(&data_key, &plaintext); (phase, encrypted) } pub fn extract_pake_msg(body: &[u8]) -> Result, WormholeError> { serde_json::from_slice(body) .map(|res: PhaseMessage| res.pake_v1) .map_err(WormholeError::ProtocolJson) } fn encrypt_data_with_nonce( key: &secretbox::Key, plaintext: &[u8], nonce: &secretbox::Nonce, ) -> Vec { let cipher = XSalsa20Poly1305::new(GenericArray::from_slice(key)); let mut ciphertext = cipher.encrypt(nonce, plaintext).unwrap(); let mut nonce_and_ciphertext = vec![]; nonce_and_ciphertext.extend_from_slice(nonce); nonce_and_ciphertext.append(&mut ciphertext); nonce_and_ciphertext } pub fn encrypt_data(key: &secretbox::Key, plaintext: &[u8]) -> (secretbox::Nonce, Vec) { let nonce = secretbox::SecretBox::::generate_nonce( &mut rand::thread_rng(), ); let nonce_and_ciphertext = encrypt_data_with_nonce(key, plaintext, &nonce); (nonce, nonce_and_ciphertext) } // TODO: return a Result with a proper error type pub fn decrypt_data(key: &secretbox::Key, encrypted: &[u8]) -> Option> { use secretbox::aead::generic_array::typenum::marker_traits::Unsigned; let nonce_size = ::NonceSize::to_usize(); let (nonce, ciphertext) = encrypted.split_at(nonce_size); assert_eq!(nonce.len(), nonce_size); let cipher = XSalsa20Poly1305::new(GenericArray::from_slice(key)); cipher .decrypt(GenericArray::from_slice(nonce), ciphertext) .ok() } fn sha256_digest(input: &[u8]) -> Vec { let mut hasher = Sha256::default(); hasher.update(input); hasher.finalize_fixed().to_vec() } pub fn derive_key(key: &secretbox::Key, purpose: &[u8]) -> secretbox::Key { let hk = Hkdf::::new(None, key); let mut key = secretbox::Key::default(); hk.expand(purpose, &mut key).unwrap(); key } pub fn derive_phase_key(side: &EitherSide, key: &secretbox::Key, phase: &Phase) -> secretbox::Key { let side_digest: Vec = sha256_digest(side.0.as_bytes()); let phase_digest: Vec = sha256_digest(phase.0.as_bytes()); let mut purpose_vec: Vec = b"wormhole:phase:".to_vec(); purpose_vec.extend(side_digest); purpose_vec.extend(phase_digest); derive_key(key, &purpose_vec) } pub fn derive_verifier(key: &crypto_secretbox::Key) -> crypto_secretbox::Key { derive_key(key, b"wormhole:verifier") } #[cfg(test)] mod test { use super::*; use crate::core::EitherSide; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_extract_pake_msg() { // let _key = super::KeyMachine::new( // &AppID::new("appid"), // &MySide::unchecked_from_string(String::from("side1")), // json!({}), // ); let s1 = "7b2270616b655f7631223a22353337363331646366643064336164386130346234663531643935336131343563386538626663373830646461393834373934656634666136656536306339663665227d"; let pake_msg = super::extract_pake_msg(&hex::decode(s1).unwrap()); assert_eq!( pake_msg.ok(), Some( hex::decode("537631dcfd0d3ad8a04b4f51d953a145c8e8bfc780dda984794ef4fa6ee60c9f6e") .unwrap() ) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_derive_key() { let main = secretbox::Key::from_exact_iter( hex::decode("588ba9eef353778b074413a0140205d90d7479e36e0dd4ee35bb729d26131ef1") .unwrap(), ) .unwrap(); let dk1 = derive_key(&main, b"purpose1"); assert_eq!( hex::encode(dk1), "835b5df80ce9ca46908e8524fb308649122cfbcefbeaa7e65061c6ef08ee1b2a" ); /* The API doesn't support non-standard length keys anymore. * But we may want to add that back in in the future. */ // let dk2 = derive_key(&main, b"purpose2", 10); // assert_eq!(hex::encode(dk2), "f2238e84315b47eb6279"); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_derive_phase_key() { let main = secretbox::Key::from_exact_iter( hex::decode("588ba9eef353778b074413a0140205d90d7479e36e0dd4ee35bb729d26131ef1") .unwrap(), ) .unwrap(); let dk11 = derive_phase_key(&EitherSide::from("side1"), &main, &Phase("phase1".into())); assert_eq!( hex::encode(&*dk11), "3af6a61d1a111225cc8968c6ca6265efe892065c3ab46de79dda21306b062990" ); let dk12 = derive_phase_key(&EitherSide::from("side1"), &main, &Phase("phase2".into())); assert_eq!( hex::encode(&*dk12), "88a1dd12182d989ff498022a9656d1e2806f17328d8bf5d8d0c9753e4381a752" ); let dk21 = derive_phase_key(&EitherSide::from("side2"), &main, &Phase("phase1".into())); assert_eq!( hex::encode(&*dk21), "a306627b436ec23bdae3af8fa90c9ac927780d86be1831003e7f617c518ea689" ); let dk22 = derive_phase_key(&EitherSide::from("side2"), &main, &Phase("phase2".into())); assert_eq!( hex::encode(&*dk22), "bf99e3e16420f2dad33f9b1ccb0be1462b253d639dacdb50ed9496fa528d8758" ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_derive_phase_key2() { // feed python's derive_phase_key with these inputs: // key = b"key" // side = u"side" // phase = u"phase1" // output of derive_phase_key is: // "\xfe\x93\x15r\x96h\xa6'\x8a\x97D\x9d\xc9\x9a_L!\x02\xa6h\xc6\x8538\x15)\x06\xbbuRj\x96" // hexlified output: fe9315729668a6278a97449dc99a5f4c2102a668c6853338152906bb75526a96 // let _k = KeyMachine::new( // &AppID::new("appid1"), // &MySide::unchecked_from_string(String::from("side")), // json!({}), // ); /* This test is disabled for now because the used key length is not compatible with our API */ // let key = Key(b"key".to_vec()); // let side = "side"; // let phase = Phase(String::from("phase1")); // let phase1_key = derive_phase_key(&EitherSide::from(side), &key, &phase); // assert_eq!( // hex::encode(&*phase1_key), // "fe9315729668a6278a97449dc99a5f4c2102a668c6853338152906bb75526a96" // ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_encrypt_data() { let k = secretbox::Key::from_exact_iter( hex::decode("ddc543ef8e4629a603d39dd0307a51bb1e7adb9cb259f6b085c91d0842a18679") .unwrap(), ) .unwrap(); let plaintext = hex::decode("edc089a518219ec1cee184e89d2d37af").unwrap(); assert_eq!(plaintext.len(), 16); let nonce = secretbox::Nonce::from_exact_iter( hex::decode("2d5e43eb465aa42e750f991e425bee485f06abad7e04af80").unwrap(), ) .unwrap(); assert_eq!(nonce.len(), 24); let msg = encrypt_data_with_nonce(&k, &plaintext, &nonce); assert_eq!(hex::encode(msg), "2d5e43eb465aa42e750f991e425bee485f06abad7e04af80fe318e39d0e4ce932d2b54b300c56d2cda55ee5f0488d63eb1d5f76f7919a49a"); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_decrypt_data() { let k = secretbox::Key::from_exact_iter( hex::decode("ddc543ef8e4629a603d39dd0307a51bb1e7adb9cb259f6b085c91d0842a18679") .unwrap(), ) .unwrap(); let encrypted = hex::decode("2d5e43eb465aa42e750f991e425bee485f06abad7e04af80fe318e39d0e4ce932d2b54b300c56d2cda55ee5f0488d63eb1d5f76f7919a49a").unwrap(); match decrypt_data(&k, &encrypted) { Some(plaintext) => { assert_eq!(hex::encode(plaintext), "edc089a518219ec1cee184e89d2d37af"); }, None => { panic!("failed to decrypt"); }, }; } /* This test is disabled for now because the used key length is not compatible with our API */ // #[test] // fn test_encrypt_data_decrypt_data_roundtrip() { // let key = Key(b"key".to_vec()); // let side = "side"; // let phase = Phase(String::from("phase")); // let data_key = derive_phase_key(&EitherSide::from(side), &key, &phase); // let plaintext = "hello world"; // let (_nonce, encrypted) = encrypt_data(&data_key, &plaintext.as_bytes()); // let maybe_plaintext = decrypt_data(&data_key, &encrypted); // match maybe_plaintext { // Some(plaintext_decrypted) => { // assert_eq!(plaintext.as_bytes().to_vec(), plaintext_decrypted); // }, // None => panic!(), // } // } } magic-wormhole-0.7.6/src/core/pgpwords.json000064400000000000000000000175221046102023000170360ustar 00000000000000{ "00": ["aardvark", "adroitness"], "01": ["absurd", "adviser"], "02": ["accrue", "aftermath"], "03": ["acme", "aggregate"], "04": ["adrift", "alkali"], "05": ["adult", "almighty"], "06": ["afflict", "amulet"], "07": ["ahead", "amusement"], "08": ["aimless", "antenna"], "09": ["Algol", "applicant"], "0A": ["allow", "Apollo"], "0B": ["alone", "armistice"], "0C": ["ammo", "article"], "0D": ["ancient", "asteroid"], "0E": ["apple", "Atlantic"], "0F": ["artist", "atmosphere"], "10": ["assume", "autopsy"], "11": ["Athens", "Babylon"], "12": ["atlas", "backwater"], "13": ["Aztec", "barbecue"], "14": ["baboon", "belowground"], "15": ["backfield", "bifocals"], "16": ["backward", "bodyguard"], "17": ["banjo", "bookseller"], "18": ["beaming", "borderline"], "19": ["bedlamp", "bottomless"], "1A": ["beehive", "Bradbury"], "1B": ["beeswax", "bravado"], "1C": ["befriend", "Brazilian"], "1D": ["Belfast", "breakaway"], "1E": ["berserk", "Burlington"], "1F": ["billiard", "businessman"], "20": ["bison", "butterfat"], "21": ["blackjack", "Camelot"], "22": ["blockade", "candidate"], "23": ["blowtorch", "cannonball"], "24": ["bluebird", "Capricorn"], "25": ["bombast", "caravan"], "26": ["bookshelf", "caretaker"], "27": ["brackish", "celebrate"], "28": ["breadline", "cellulose"], "29": ["breakup", "certify"], "2A": ["brickyard", "chambermaid"], "2B": ["briefcase", "Cherokee"], "2C": ["Burbank", "Chicago"], "2D": ["button", "clergyman"], "2E": ["buzzard", "coherence"], "2F": ["cement", "combustion"], "30": ["chairlift", "commando"], "31": ["chatter", "company"], "32": ["checkup", "component"], "33": ["chisel", "concurrent"], "34": ["choking", "confidence"], "35": ["chopper", "conformist"], "36": ["Christmas", "congregate"], "37": ["clamshell", "consensus"], "38": ["classic", "consulting"], "39": ["classroom", "corporate"], "3A": ["cleanup", "corrosion"], "3B": ["clockwork", "councilman"], "3C": ["cobra", "crossover"], "3D": ["commence", "crucifix"], "3E": ["concert", "cumbersome"], "3F": ["cowbell", "customer"], "40": ["crackdown", "Dakota"], "41": ["cranky", "decadence"], "42": ["crowfoot", "December"], "43": ["crucial", "decimal"], "44": ["crumpled", "designing"], "45": ["crusade", "detector"], "46": ["cubic", "detergent"], "47": ["dashboard", "determine"], "48": ["deadbolt", "dictator"], "49": ["deckhand", "dinosaur"], "4A": ["dogsled", "direction"], "4B": ["dragnet", "disable"], "4C": ["drainage", "disbelief"], "4D": ["dreadful", "disruptive"], "4E": ["drifter", "distortion"], "4F": ["dropper", "document"], "50": ["drumbeat", "embezzle"], "51": ["drunken", "enchanting"], "52": ["Dupont", "enrollment"], "53": ["dwelling", "enterprise"], "54": ["eating", "equation"], "55": ["edict", "equipment"], "56": ["egghead", "escapade"], "57": ["eightball", "Eskimo"], "58": ["endorse", "everyday"], "59": ["endow", "examine"], "5A": ["enlist", "existence"], "5B": ["erase", "exodus"], "5C": ["escape", "fascinate"], "5D": ["exceed", "filament"], "5E": ["eyeglass", "finicky"], "5F": ["eyetooth", "forever"], "60": ["facial", "fortitude"], "61": ["fallout", "frequency"], "62": ["flagpole", "gadgetry"], "63": ["flatfoot", "Galveston"], "64": ["flytrap", "getaway"], "65": ["fracture", "glossary"], "66": ["framework", "gossamer"], "67": ["freedom", "graduate"], "68": ["frighten", "gravity"], "69": ["gazelle", "guitarist"], "6A": ["Geiger", "hamburger"], "6B": ["glitter", "Hamilton"], "6C": ["glucose", "handiwork"], "6D": ["goggles", "hazardous"], "6E": ["goldfish", "headwaters"], "6F": ["gremlin", "hemisphere"], "70": ["guidance", "hesitate"], "71": ["hamlet", "hideaway"], "72": ["highchair", "holiness"], "73": ["hockey", "hurricane"], "74": ["indoors", "hydraulic"], "75": ["indulge", "impartial"], "76": ["inverse", "impetus"], "77": ["involve", "inception"], "78": ["island", "indigo"], "79": ["jawbone", "inertia"], "7A": ["keyboard", "infancy"], "7B": ["kickoff", "inferno"], "7C": ["kiwi", "informant"], "7D": ["klaxon", "insincere"], "7E": ["locale", "insurgent"], "7F": ["lockup", "integrate"], "80": ["merit", "intention"], "81": ["minnow", "inventive"], "82": ["miser", "Istanbul"], "83": ["Mohawk", "Jamaica"], "84": ["mural", "Jupiter"], "85": ["music", "leprosy"], "86": ["necklace", "letterhead"], "87": ["Neptune", "liberty"], "88": ["newborn", "maritime"], "89": ["nightbird", "matchmaker"], "8A": ["Oakland", "maverick"], "8B": ["obtuse", "Medusa"], "8C": ["offload", "megaton"], "8D": ["optic", "microscope"], "8E": ["orca", "microwave"], "8F": ["payday", "midsummer"], "90": ["peachy", "millionaire"], "91": ["pheasant", "miracle"], "92": ["physique", "misnomer"], "93": ["playhouse", "molasses"], "94": ["Pluto", "molecule"], "95": ["preclude", "Montana"], "96": ["prefer", "monument"], "97": ["preshrunk", "mosquito"], "98": ["printer", "narrative"], "99": ["prowler", "nebula"], "9A": ["pupil", "newsletter"], "9B": ["puppy", "Norwegian"], "9C": ["python", "October"], "9D": ["quadrant", "Ohio"], "9E": ["quiver", "onlooker"], "9F": ["quota", "opulent"], "A0": ["ragtime", "Orlando"], "A1": ["ratchet", "outfielder"], "A2": ["rebirth", "Pacific"], "A3": ["reform", "pandemic"], "A4": ["regain", "Pandora"], "A5": ["reindeer", "paperweight"], "A6": ["rematch", "paragon"], "A7": ["repay", "paragraph"], "A8": ["retouch", "paramount"], "A9": ["revenge", "passenger"], "AA": ["reward", "pedigree"], "AB": ["rhythm", "Pegasus"], "AC": ["ribcage", "penetrate"], "AD": ["ringbolt", "perceptive"], "AE": ["robust", "performance"], "AF": ["rocker", "pharmacy"], "B0": ["ruffled", "phonetic"], "B1": ["sailboat", "photograph"], "B2": ["sawdust", "pioneer"], "B3": ["scallion", "pocketful"], "B4": ["scenic", "politeness"], "B5": ["scorecard", "positive"], "B6": ["Scotland", "potato"], "B7": ["seabird", "processor"], "B8": ["select", "provincial"], "B9": ["sentence", "proximate"], "BA": ["shadow", "puberty"], "BB": ["shamrock", "publisher"], "BC": ["showgirl", "pyramid"], "BD": ["skullcap", "quantity"], "BE": ["skydive", "racketeer"], "BF": ["slingshot", "rebellion"], "C0": ["slowdown", "recipe"], "C1": ["snapline", "recover"], "C2": ["snapshot", "repellent"], "C3": ["snowcap", "replica"], "C4": ["snowslide", "reproduce"], "C5": ["solo", "resistor"], "C6": ["southward", "responsive"], "C7": ["soybean", "retraction"], "C8": ["spaniel", "retrieval"], "C9": ["spearhead", "retrospect"], "CA": ["spellbind", "revenue"], "CB": ["spheroid", "revival"], "CC": ["spigot", "revolver"], "CD": ["spindle", "sandalwood"], "CE": ["spyglass", "sardonic"], "CF": ["stagehand", "Saturday"], "D0": ["stagnate", "savagery"], "D1": ["stairway", "scavenger"], "D2": ["standard", "sensation"], "D3": ["stapler", "sociable"], "D4": ["steamship", "souvenir"], "D5": ["sterling", "specialist"], "D6": ["stockman", "speculate"], "D7": ["stopwatch", "stethoscope"], "D8": ["stormy", "stupendous"], "D9": ["sugar", "supportive"], "DA": ["surmount", "surrender"], "DB": ["suspense", "suspicious"], "DC": ["sweatband", "sympathy"], "DD": ["swelter", "tambourine"], "DE": ["tactics", "telephone"], "DF": ["talon", "therapist"], "E0": ["tapeworm", "tobacco"], "E1": ["tempest", "tolerance"], "E2": ["tiger", "tomorrow"], "E3": ["tissue", "torpedo"], "E4": ["tonic", "tradition"], "E5": ["topmost", "travesty"], "E6": ["tracker", "trombonist"], "E7": ["transit", "truncated"], "E8": ["trauma", "typewriter"], "E9": ["treadmill", "ultimate"], "EA": ["Trojan", "undaunted"], "EB": ["trouble", "underfoot"], "EC": ["tumor", "unicorn"], "ED": ["tunnel", "unify"], "EE": ["tycoon", "universe"], "EF": ["uncut", "unravel"], "F0": ["unearth", "upcoming"], "F1": ["unwind", "vacancy"], "F2": ["uproot", "vagabond"], "F3": ["upset", "vertigo"], "F4": ["upshot", "Virginia"], "F5": ["vapor", "visitor"], "F6": ["village", "vocalist"], "F7": ["virus", "voyager"], "F8": ["Vulcan", "warranty"], "F9": ["waffle", "Waterloo"], "FA": ["wallet", "whimsical"], "FB": ["watchword", "Wichita"], "FC": ["wayside", "Wilmington"], "FD": ["willow", "Wyoming"], "FE": ["woodlark", "yesteryear"], "FF": ["Zulu", "Yucatan"] } magic-wormhole-0.7.6/src/core/rendezvous.rs000064400000000000000000000520441046102023000170460ustar 00000000000000//! Implementation of the Client-to-Server part //! //! Wormhole builds upon this, so you usually don't need to bother. #[cfg(not(target_family = "wasm"))] use async_tungstenite::tungstenite as ws2; use futures::prelude::*; use std::collections::VecDeque; use crate::core::{ server_messages::{InboundMessage, OutboundMessage, PermissionRequired, SubmitPermission}, AppID, EncryptedMessage, Mailbox, Mood, MySide, Nameplate, Phase, }; /// Some rendezvous server you might use. /// /// Two applications that want to communicate with each other *must* use the same rendezvous server. pub const DEFAULT_RENDEZVOUS_SERVER: &str = "ws://relay.magic-wormhole.io:4000/v1"; /// An error occurred when connecting to the rendezvous server #[derive(Debug, thiserror::Error)] #[non_exhaustive] pub enum RendezvousError { /// Some deserialization went wrong, we probably got some garbage #[error("Corrupt message received")] ProtocolJson( #[from] #[source] serde_json::Error, ), /// A generic string message for "something went wrong", i.e. /// the server sent some bullshit message order #[error("Protocol error: {}", _0)] Protocol(Box), /// The server sent us an error message #[error("Received error message from server: {}", _0)] Server(Box), /// Server wants a login permission, but we don't suppport any of these #[error( "Server wants one of {:?} for permissions, but we don't suppport any of these", _0 )] Login(Vec), #[cfg(not(target_family = "wasm"))] /// Websocket I/O error #[error("Websocket I/O error")] IO( #[from] #[source] ws2::Error, ), /// Websocket I/O error #[cfg(target_family = "wasm")] #[error("Websocket IO error")] IO( #[from] #[source] ws_stream_wasm::WsErr, ), } impl RendezvousError { pub(self) fn protocol(error: impl Into>) -> Self { Self::Protocol(error.into()) } pub(self) fn invalid_message(expected: &str, got: impl std::fmt::Debug) -> Self { Self::protocol(format!( "Unexpected message (protocol error): Expected '{}', but got: {:?}", expected, got )) } pub(self) fn server(error: impl Into>) -> Self { Self::Server(error.into()) } } type MessageQueue = VecDeque; #[derive(Clone, Debug, derive_more::Display)] #[display("{:?}", _0)] struct NameplateList(Vec); #[cfg(not(target_family = "wasm"))] struct WsConnection { connection: async_tungstenite::WebSocketStream, } #[cfg(target_family = "wasm")] struct WsConnection { connection: ws_stream_wasm::WsStream, meta: ws_stream_wasm::WsMeta, } impl WsConnection { #[cfg(not(target_family = "wasm"))] async fn send_message( &mut self, message: &OutboundMessage, queue: Option<&mut MessageQueue>, ) -> Result<(), RendezvousError> { tracing::debug!("Sending {}", message); self.connection .send(ws2::Message::text(serde_json::to_string(message).unwrap())) .await?; self.receive_ack(queue).await?; Ok(()) } #[cfg(target_family = "wasm")] async fn send_message( &mut self, message: &OutboundMessage, queue: Option<&mut MessageQueue>, ) -> Result<(), RendezvousError> { tracing::debug!("Sending {:?}", message); self.connection .send(ws_stream_wasm::WsMessage::Text( serde_json::to_string(message).unwrap(), )) .await?; self.receive_ack(queue).await?; Ok(()) } async fn receive_ack( &mut self, mut queue: Option<&mut MessageQueue>, ) -> Result<(), RendezvousError> { loop { let message = self.receive_message().await?; match message { Some(InboundMessage::Ack) => break, Some(InboundMessage::Message(message)) => match &mut queue { Some(queue) => { queue.push_back(message); }, None => { return Err(RendezvousError::protocol( "Received peer message, but haven't opened the mailbox yet", )); }, }, Some(other) => { return Err(RendezvousError::protocol(format!( "Got unexpected message type from server '{}'", other ))) }, None => continue, } } Ok(()) } async fn receive_reply( &mut self, mut queue: Option<&mut MessageQueue>, ) -> Result { loop { let message = self.receive_message().await?; match message { Some(InboundMessage::Allocated { nameplate }) => { break Ok(RendezvousReply::Allocated(nameplate)) }, Some(InboundMessage::Released) => break Ok(RendezvousReply::Released), Some(InboundMessage::Claimed { mailbox }) => { break Ok(RendezvousReply::Claimed(mailbox)) }, Some(InboundMessage::Closed) => break Ok(RendezvousReply::Closed), Some(InboundMessage::Message(message)) => match &mut queue { Some(queue) => { queue.push_back(message); }, None => { break Err(RendezvousError::protocol( "Received peer message, but haven't opened the mailbox yet", )) }, }, Some(InboundMessage::Error { error, orig: _ }) => { break Err(RendezvousError::Server(error.into())); }, Some(InboundMessage::Nameplates { nameplates }) => { break Ok(RendezvousReply::Nameplates(NameplateList(nameplates))) }, Some(other) => { break Err(RendezvousError::protocol(format!( "Got unexpected message type from server '{}'", other ))) }, None => (/*continue*/), } } } async fn receive_message_some(&mut self) -> Result { loop { if let Some(message) = self.receive_message().await? { break Ok(message); } } } #[cfg(not(target_family = "wasm"))] async fn receive_message(&mut self) -> Result, RendezvousError> { let message = self .connection .next() .await .expect("TODO this should always be Some")?; match message { ws2::Message::Text(message_plain) => { let message = serde_json::from_str(&message_plain)?; tracing::debug!("Received {}", message); match message { InboundMessage::Unknown => { tracing::warn!("Got unknown message, ignoring: '{}'", message_plain); Ok(None) }, InboundMessage::Error { error, orig: _ } => Err(RendezvousError::server(error)), message => Ok(Some(message)), } }, ws2::Message::Binary(_) => Err(RendezvousError::protocol( "WebSocket messages must be UTF-8 encoded text", )), /* Ignore ping pong for now */ ws2::Message::Ping(_) => Ok(None), ws2::Message::Pong(_) => Ok(None), ws2::Message::Close(_) => { tracing::debug!("Received connection close"); Err(ws2::Error::ConnectionClosed.into()) }, ws2::Message::Frame(_) => { tracing::warn!("Received a WebSocket 'Frame' message and don't know what to do with it, please open a bug report"); Ok(None) }, } } #[cfg(target_family = "wasm")] async fn receive_message(&mut self) -> Result, RendezvousError> { let message = self .connection .next() .await .expect("TODO this should always be Some"); match message { ws_stream_wasm::WsMessage::Text(message_plain) => { let message = serde_json::from_str(&message_plain)?; tracing::debug!("Received {:?}", message); match message { InboundMessage::Unknown => { tracing::warn!("Got unknown message, ignoring: '{}'", message_plain); Ok(None) }, InboundMessage::Error { error, orig: _ } => Err(RendezvousError::server(error)), message => Ok(Some(message)), } }, ws_stream_wasm::WsMessage::Binary(_) => Err(RendezvousError::protocol( "WebSocket messages must be UTF-8 encoded text", )), } } #[cfg(not(target_family = "wasm"))] async fn close(&mut self) -> Result<(), ws2::Error> { self.connection.close(None).await } #[cfg(target_family = "wasm")] async fn close(&mut self) -> Result { self.meta.close().await } } #[derive(Clone, Debug, derive_more::Display)] enum RendezvousReply { Allocated(Nameplate), Released, Claimed(Mailbox), Closed, Nameplates(NameplateList), } #[derive(Clone, Debug, derive_more::Display)] #[display( "MailboxMachine {{ mailbox: {}, processed: [{}] }}", mailbox, "processed.iter().map(|p| format!(\"{}\", p)).collect::>().join(\", \")" )] struct MailboxMachine { nameplate: Option, mailbox: Mailbox, queue: MessageQueue, processed: std::collections::HashSet, } impl MailboxMachine { fn receive_message(&mut self, message: &EncryptedMessage, side: &MySide) -> bool { if *message.side != **side { // Got a message from them. Check if duplicate if !self.processed.contains(&message.phase) { self.processed.insert(message.phase.clone()); true } else { false } } else { // Echo of ours. Ignore false } } } /// The rendezvous server is a central server used for connection establishment #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] pub struct RendezvousServer { connection: WsConnection, state: Option, side: MySide, } #[allow(deprecated)] impl std::fmt::Debug for RendezvousServer { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fmt.debug_struct("RendezvousServer") .field("state", &self.state) .field("side", &self.side) .finish() } } #[allow(deprecated)] #[allow(missing_docs)] impl RendezvousServer { /** * Connect to the rendezvous server * * This does the permission negotiation part if required and binds the * connection to the given `appid`. */ pub async fn connect( appid: &AppID, relay_url: &str, ) -> Result<(Self, Option), RendezvousError> { let side = MySide::generate(); let mut connection; #[cfg(not(target_arch = "wasm32"))] { let (stream, _) = async_tungstenite::async_std::connect_async(relay_url).await?; connection = WsConnection { connection: stream }; } #[cfg(target_arch = "wasm32")] { let (meta, stream) = ws_stream_wasm::WsMeta::connect(relay_url, None).await?; connection = WsConnection { meta, connection: stream, }; } let welcome = match connection.receive_message_some().await? { InboundMessage::Welcome { welcome } => welcome, other => { return Err(RendezvousError::protocol(format!( "First message server sends must be 'welcome', but was '{}'", other ))) }, }; match welcome.permission_required { Some(PermissionRequired { hashcash: Some(hashcash), .. }) => { let token = crate::util::hashcash(hashcash.resource, hashcash.bits); connection .send_message( &OutboundMessage::SubmitPermission(SubmitPermission::Hashcash { stamp: token.to_string(), }), None, ) .await?; }, Some(PermissionRequired { none: true, .. }) => (), Some(PermissionRequired { other, .. }) => { /* We can't actually log in :/ */ return Err(RendezvousError::Login( // TODO use `into_keys` once stable and remove the `cloned` other.keys().cloned().collect(), )); }, None => (), } connection .send_message(&OutboundMessage::bind(appid.clone(), side.clone()), None) .await?; tracing::info!("Connected to rendezvous server."); Ok(( Self { connection, state: None, side, }, welcome.motd, )) } /** A random unique string for this session */ pub(crate) fn side(&self) -> &MySide { &self.side } async fn send_message(&mut self, message: &OutboundMessage) -> Result<(), RendezvousError> { self.connection .send_message(message, self.state.as_mut().map(|state| &mut state.queue)) .await } async fn receive_reply(&mut self) -> Result { self.connection .receive_reply(self.state.as_mut().map(|state| &mut state.queue)) .await } pub(crate) async fn send_peer_message( &mut self, phase: Phase, body: Vec, ) -> Result<(), RendezvousError> { self.send_message(&OutboundMessage::Add { body, phase }) .await } pub(crate) async fn next_peer_message_some( &mut self, ) -> Result { loop { if let Some(message) = self.next_peer_message().await? { return Ok(message); } } } pub(crate) async fn next_peer_message( &mut self, ) -> Result, RendezvousError> { let machine = &mut self .state .as_mut() .expect("Can only receive messages when having a claimed+open mailbox"); if let Some(message) = machine.queue.pop_front() { if machine.receive_message(&message, &self.side) { return Ok(Some(message)); } else { return Ok(None); } } match self.connection.receive_message().await? { Some(InboundMessage::Message(message)) => { if machine.receive_message(&message, &self.side) { Ok(Some(message)) } else { Ok(None) } }, Some(other) => Err(RendezvousError::protocol(format!( "Expected message from peer, got '{}' instead", other ))), None => Ok(None), } } /** Allocate a nameplate, claim the mailbox and open it */ pub async fn allocate_claim_open(&mut self) -> Result<(Nameplate, Mailbox), RendezvousError> { assert!( self.state.is_none(), "Can only call in initial state, and only once" ); self.send_message(&OutboundMessage::Allocate).await?; let nameplate = match self.receive_reply().await? { RendezvousReply::Allocated(nameplate) => nameplate, other => return Err(RendezvousError::invalid_message("allocated", other)), }; self.send_message(&OutboundMessage::claim(nameplate.clone())) .await?; let mailbox = match self.receive_reply().await? { RendezvousReply::Claimed(mailbox) => mailbox, other => return Err(RendezvousError::invalid_message("claimed", other)), }; self.send_message(&OutboundMessage::open(mailbox.clone())) .await?; self.state = Some(MailboxMachine { nameplate: Some(nameplate.clone()), mailbox: mailbox.clone(), queue: Default::default(), processed: Default::default(), }); Ok((nameplate, mailbox)) } /** Claim a nameplate+mailbox and open it */ pub async fn claim_open(&mut self, nameplate: Nameplate) -> Result { assert!( self.state.is_none(), "Can only call in initial state, and only once" ); self.send_message(&OutboundMessage::claim(nameplate.clone())) .await?; let mailbox = match self.receive_reply().await? { RendezvousReply::Claimed(mailbox) => mailbox, other => return Err(RendezvousError::invalid_message("claimed", other)), }; self.send_message(&OutboundMessage::open(mailbox.clone())) .await?; self.state = Some(MailboxMachine { nameplate: Some(nameplate.clone()), mailbox: mailbox.clone(), queue: Default::default(), processed: Default::default(), }); Ok(mailbox) } pub fn needs_nameplate_release(&self) -> bool { self.state .as_ref() .and_then(|state| state.nameplate.as_ref()) .is_some() } /** * Gets the list of currently claimed nameplates. * This can be called at any time. */ pub async fn list_nameplates(&mut self) -> Result, RendezvousError> { self.send_message(&OutboundMessage::List).await?; let nameplate_reply = self.receive_reply().await?; match nameplate_reply { RendezvousReply::Nameplates(x) => Ok(x.0), other => Err(RendezvousError::invalid_message("nameplates", other)), } } pub async fn release_nameplate(&mut self) -> Result<(), RendezvousError> { let nameplate = &mut self .state .as_mut() .and_then(|state| state.nameplate.clone()) .expect("Can only release an allocated nameplate, and only once"); self.send_message(&OutboundMessage::release(nameplate.as_ref())) .await?; match self.receive_reply().await? { RendezvousReply::Released => (), other => return Err(RendezvousError::invalid_message("released", other)), }; self.state.as_mut().unwrap().nameplate = None; Ok(()) } /** * Open a mailbox while skipping the nameplate part. * * This is the base functionality for seeds. */ pub async fn open_directly(&mut self, mailbox: Mailbox) -> Result<(), RendezvousError> { assert!( self.state.is_none(), "Can only call in initial state, and only once" ); self.send_message(&OutboundMessage::open(mailbox.clone())) .await?; self.state = Some(MailboxMachine { nameplate: None, mailbox, queue: Default::default(), processed: Default::default(), }); Ok(()) } pub async fn shutdown(mut self, mood: Mood) -> Result<(), RendezvousError> { if let Some(MailboxMachine { nameplate, mailbox, mut queue, .. }) = self.state { if let Some(nameplate) = nameplate { self.connection .send_message(&OutboundMessage::release(nameplate), Some(&mut queue)) .await?; match self.connection.receive_reply(Some(&mut queue)).await? { RendezvousReply::Released => (), other => return Err(RendezvousError::invalid_message("released", other)), }; } self.connection .send_message(&OutboundMessage::close(mailbox, mood), Some(&mut queue)) .await?; match self.connection.receive_reply(Some(&mut queue)).await? { RendezvousReply::Closed => (), other => return Err(RendezvousError::invalid_message("closed", other)), }; } self.connection.close().await?; Ok(()) } } magic-wormhole-0.7.6/src/core/server_messages.rs000064400000000000000000000365671046102023000200530ustar 00000000000000use super::{AppID, Mailbox, Mood, MySide, Nameplate, Phase, TheirSide}; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; /// Special encoding for the `nameplates` message #[derive(Serialize, Deserialize, Debug, PartialEq)] struct Nameplate_ { pub id: String, } impl Nameplate_ { fn deserialize<'de, D>(de: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { let value: Vec = serde::Deserialize::deserialize(de)?; Ok(value.into_iter().map(|value| Nameplate(value.id)).collect()) } #[allow(clippy::all, dead_code)] fn serialize(value: &Vec, ser: S) -> Result where S: serde::Serializer, { ser.collect_seq(value.iter().map(|value| Self { id: value.to_string(), })) } } #[derive(Serialize, Debug, PartialEq, Eq, derive_more::Display)] #[serde(rename_all = "kebab-case")] #[serde(tag = "method")] pub enum SubmitPermission { #[display("Hashcash {{ stamp: '{}' }}", stamp)] Hashcash { stamp: String }, } #[derive(Deserialize, Debug, PartialEq, Eq, Default)] pub struct WelcomeMessage { #[deprecated(note = "This is for the Python client")] pub current_cli_version: Option, pub motd: Option, #[deprecated(note = "Servers should send a proper error message instead")] pub error: Option, #[serde(rename = "permission-required")] pub permission_required: Option, } impl std::fmt::Display for WelcomeMessage { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "WelcomeMessage {{ ")?; if let Some(motd) = &self.motd { write!(f, "motd: '{}', ", motd)?; } if let Some(permission_required) = &self.permission_required { write!(f, "permission_required: '{}', ", permission_required)?; } write!(f, ".. }}")?; Ok(()) } } #[derive(Deserialize, Debug, PartialEq, Eq)] pub struct PermissionRequired { #[serde(deserialize_with = "PermissionRequired::deserialize_none")] pub none: bool, pub hashcash: Option, #[serde(flatten)] pub other: HashMap, } impl PermissionRequired { fn deserialize_none<'de, D>(de: D) -> Result where D: serde::Deserializer<'de>, { let value: Option> = serde::Deserialize::deserialize(de)?; Ok(value.is_some()) } } impl std::fmt::Display for PermissionRequired { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let none_iter = std::iter::once("none").filter(|_| self.none); let hashcash_iter = std::iter::once("hashcash").filter(|_| self.hashcash.is_some()); let other_iter = self.other.keys().map(String::as_str); write!( f, "PermissionRequired {{ one of: {:?}}}", none_iter.chain(hashcash_iter).chain(other_iter) ) } } #[derive(Deserialize, Debug, PartialEq, Eq, derive_more::Display)] #[display("HashcashPermission {{ bits: {}, resource: '{}' }}", bits, resource)] #[serde(deny_unknown_fields)] pub struct HashcashPermission { pub bits: u32, pub resource: String, } #[derive(Debug, PartialEq, Clone, Deserialize, derive_more::Display)] #[display( "EncryptedMessage {{ side: {}, phase: {}, body: {}", side, phase, "crate::util::DisplayBytes(body)" )] pub(crate) struct EncryptedMessage { pub side: TheirSide, pub phase: Phase, #[serde(deserialize_with = "hex::serde::deserialize")] pub body: Vec, } impl EncryptedMessage { pub fn decrypt(&self, key: &crypto_secretbox::Key) -> Option> { use super::key; let data_key = key::derive_phase_key(&self.side, key, &self.phase); key::decrypt_data(&data_key, &self.body) } } // Client sends only these #[derive(Serialize, Debug, PartialEq, derive_more::Display)] #[serde(rename_all = "kebab-case")] #[serde(tag = "type")] #[allow(dead_code)] pub enum OutboundMessage { #[display("SubmitPermission({})", _0)] SubmitPermission(SubmitPermission), #[display("Bind {{ appid: {}, side: {} }}", appid, side)] Bind { appid: AppID, side: MySide, }, List, Allocate, #[display("Claim({})", nameplate)] Claim { nameplate: String, }, #[display("Release({})", nameplate)] Release { nameplate: String, }, // TODO: nominally optional #[display("Open({})", mailbox)] Open { mailbox: Mailbox, }, #[display( "Add {{ phase: {}, body: {} }}", phase, "crate::util::DisplayBytes(body)" )] Add { phase: Phase, #[serde(serialize_with = "hex::serde::serialize")] body: Vec, }, #[display("Close {{ mailbox: {}, mood: {} }}", mailbox, mood)] Close { mailbox: Mailbox, mood: Mood, }, #[display("Ping({})", ping)] Ping { ping: u64, }, } impl OutboundMessage { pub fn bind(appid: AppID, side: MySide) -> Self { OutboundMessage::Bind { appid, side } } pub fn claim(nameplate: impl Into) -> Self { OutboundMessage::Claim { nameplate: nameplate.into(), } } pub fn release(nameplate: impl Into) -> Self { OutboundMessage::Release { nameplate: nameplate.into(), } } pub fn open(mailbox: Mailbox) -> Self { OutboundMessage::Open { mailbox } } #[allow(dead_code)] pub fn add(phase: Phase, body: Vec) -> Self { OutboundMessage::Add { body, phase } } pub fn close(mailbox: Mailbox, mood: Mood) -> Self { OutboundMessage::Close { mailbox, mood } } } // Server sends only these #[derive(Deserialize, Debug, PartialEq, derive_more::Display)] #[serde(rename_all = "kebab-case")] #[serde(tag = "type")] pub enum InboundMessage { #[display("Welcome({})", welcome)] Welcome { welcome: WelcomeMessage, }, #[display("Nameplates({:?})", nameplates)] Nameplates { #[serde(with = "Nameplate_")] nameplates: Vec, }, #[display("Allocated({})", nameplate)] Allocated { nameplate: Nameplate, }, #[display("Claimed({})", mailbox)] Claimed { mailbox: Mailbox, }, Released, #[display( "Message {{ side: {}, phase: {:?}, body: {} }}", _0.side, _0.phase, "crate::util::DisplayBytes(_0.body.as_bytes())" )] Message(EncryptedMessage), Closed, Ack, #[display("Pong({})", pong)] Pong { pong: u64, }, #[display("Error {{ error: {:?}, .. }}", error)] Error { error: String, /// A copy of the original message that caused the error. orig: Box, }, #[serde(other)] Unknown, } #[cfg(test)] mod test { use super::*; use serde_json::{from_str, json, Value}; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_bind() { let m1 = OutboundMessage::bind( AppID::new("appid"), MySide::unchecked_from_string(String::from("side1")), ); let s = serde_json::to_string(&m1).unwrap(); let m2: Value = from_str(&s).unwrap(); assert_eq!( m2, json!({"type": "bind", "appid": "appid", "side": "side1"}) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_list() { let m1 = OutboundMessage::List; let s = serde_json::to_string(&m1).unwrap(); let m2: Value = from_str(&s).unwrap(); assert_eq!(m2, json!({"type": "list"})); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_allocate() { let m1 = OutboundMessage::Allocate; let s = serde_json::to_string(&m1).unwrap(); let m2: Value = from_str(&s).unwrap(); assert_eq!(m2, json!({"type": "allocate"})); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_claim() { let m1 = OutboundMessage::claim("nameplate1"); let s = serde_json::to_string(&m1).unwrap(); let m2: Value = from_str(&s).unwrap(); assert_eq!(m2, json!({"type": "claim", "nameplate": "nameplate1"})); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_release() { let m1 = OutboundMessage::release("nameplate1"); let s = serde_json::to_string(&m1).unwrap(); let m2: Value = from_str(&s).unwrap(); assert_eq!(m2, json!({"type": "release", "nameplate": "nameplate1"})); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_open() { let m1 = OutboundMessage::open(Mailbox(String::from("mailbox1"))); let s = serde_json::to_string(&m1).unwrap(); let m2: Value = from_str(&s).unwrap(); assert_eq!(m2, json!({"type": "open", "mailbox": "mailbox1"})); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_add() { let m1 = OutboundMessage::add(Phase("phase1".into()), b"body".to_vec()); let s = serde_json::to_string(&m1).unwrap(); let m2: Value = from_str(&s).unwrap(); assert_eq!( m2, json!({"type": "add", "phase": "phase1", "body": "626f6479"}) ); // body is hex-encoded } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_close() { let m1 = OutboundMessage::close(Mailbox(String::from("mailbox1")), Mood::Happy); let s = serde_json::to_string(&m1).unwrap(); let m2: Value = from_str(&s).unwrap(); assert_eq!( m2, json!({"type": "close", "mailbox": "mailbox1", "mood": "happy"}) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_close_errory() { let m1 = OutboundMessage::close(Mailbox(String::from("mailbox1")), Mood::Errory); let s = serde_json::to_string(&m1).unwrap(); let m2: Value = from_str(&s).unwrap(); assert_eq!( m2, json!({"type": "close", "mailbox": "mailbox1", "mood": "errory"}) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_close_scared() { let m1 = OutboundMessage::close(Mailbox(String::from("mailbox1")), Mood::Scared); let s = serde_json::to_string(&m1).unwrap(); let m2: Value = from_str(&s).unwrap(); assert_eq!( m2, json!({"type": "close", "mailbox": "mailbox1", "mood": "scary"}) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[allow(deprecated)] fn test_welcome3() { let s = r#"{"type": "welcome", "welcome": {}, "server_tx": 1234.56}"#; let m = serde_json::from_str(s).unwrap(); assert!(matches!( m, InboundMessage::Welcome { welcome: WelcomeMessage { current_cli_version: None, motd: None, error: None, permission_required: None } } )); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[allow(deprecated)] fn test_welcome4() { let s = r#"{"type": "welcome", "welcome": {} }"#; let m = serde_json::from_str(s).unwrap(); assert!(matches!( m, InboundMessage::Welcome { welcome: WelcomeMessage { current_cli_version: None, motd: None, error: None, permission_required: None } } )); } // TODO: when "error_on_line_overflow=false" lands on rustfmt(stable), // let's replace this cfg_attr with a change to our .rustfmt.toml #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[rustfmt::skip] #[allow(deprecated)] fn test_welcome5() { let s = r#"{"type": "welcome", "welcome": { "motd": "hello world" }, "server_tx": 1234.56 }"#; let m = serde_json::from_str(s).unwrap(); assert!(matches!(m, InboundMessage::Welcome { welcome: WelcomeMessage { current_cli_version: None, motd: Some(_), error: None, permission_required: None } })); } /// Test permission_required field deserialization #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[allow(deprecated)] fn test_welcome6() { let s = r#"{"type": "welcome", "welcome": { "motd": "hello world", "permission-required": { "none": {}, "hashcash": { "bits": 6, "resource": "resource-string" }, "dark-ritual": { "hocrux": true } } } }"#; let m: InboundMessage = serde_json::from_str(s).unwrap(); assert_eq!( m, InboundMessage::Welcome { welcome: WelcomeMessage { motd: Some("hello world".into()), permission_required: Some(PermissionRequired { none: true, hashcash: Some(HashcashPermission { bits: 6, resource: "resource-string".into(), }), other: [("dark-ritual".to_string(), json!({ "hocrux": true }))] .into_iter() .collect() }), current_cli_version: None, error: None, } } ) } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_submit_permissions() { let m = OutboundMessage::SubmitPermission(SubmitPermission::Hashcash { stamp: "stamp".into(), }); let s = serde_json::to_string(&m).unwrap(); assert_eq!( s, r#"{"type":"submit-permission","method":"hashcash","stamp":"stamp"}"# ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_ack() { let s = r#"{"type": "ack", "id": null, "server_tx": 1234.56}"#; let m = serde_json::from_str(s).unwrap(); match m { InboundMessage::Ack {} => (), _ => panic!(), } } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_message() { let s = r#"{"body": "7b2270616b655f7631223a22353361346566366234363434303364376534633439343832663964373236646538396462366631336632613832313537613335646562393562366237633536353533227d", "server_rx": 1523468188.293486, "id": null, "phase": "pake", "server_tx": 1523498654.753594, "type": "message", "side": "side1"}"#; let m = serde_json::from_str(s).unwrap(); match m { InboundMessage::Message(EncryptedMessage { side: _s, phase: _p, body: _b, //id: i }) => (), _ => panic!(), } } } magic-wormhole-0.7.6/src/core/test.rs000064400000000000000000000541271046102023000156250ustar 00000000000000#![allow(irrefutable_let_patterns)] use super::{Mood, Phase}; use rand::Rng; use std::{borrow::Cow, str::FromStr, time::Duration}; #[cfg(feature = "transfer")] use crate::transfer; use crate::{ self as magic_wormhole, core::MailboxConnection, transit, AppConfig, AppID, Code, WormholeError, }; use test_log::test; pub const TEST_APPID: AppID = AppID(std::borrow::Cow::Borrowed( "piegames.de/wormhole/rusty-wormhole-test", )); pub const APP_CONFIG: AppConfig<()> = AppConfig::<()> { id: TEST_APPID, rendezvous_url: Cow::Borrowed(crate::rendezvous::DEFAULT_RENDEZVOUS_SERVER), app_version: (), }; const TIMEOUT: Duration = Duration::from_secs(60); /// Utility method that logs information of the transit result /// /// Example usage: /// /// ```no_run /// use magic_wormhole as mw; /// # #[async_std::main] async fn main() -> Result<(), mw::transit::TransitConnectError> { /// # let derived_key = unimplemented!(); /// # let their_abilities = unimplemented!(); /// # let their_hints = unimplemented!(); /// let connector: mw::transit::TransitConnector = unimplemented!("transit::init(…).await?"); /// let (mut transit, info) = connector /// .leader_connect(derived_key, their_abilities, their_hints) /// .await?; /// mw::log_transit_connection(info); /// # Ok(()) /// # } /// ``` #[cfg(not(target_family = "wasm"))] pub(crate) fn log_transit_connection(info: crate::transit::TransitInfo) { tracing::info!("{info}") } fn default_relay_hints() -> Vec { vec![ transit::RelayHint::from_urls(None, [transit::DEFAULT_RELAY_SERVER.parse().unwrap()]) .unwrap(), ] } #[test(async_std::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] pub async fn test_connect_with_unknown_code_and_allocate_passes() { let code = generate_random_code(); let mailbox_connection = MailboxConnection::connect(transfer::APP_CONFIG.id(TEST_APPID).clone(), code, true).await; assert!(mailbox_connection.is_ok()); mailbox_connection .unwrap() .shutdown(Mood::Happy) .await .unwrap() } #[test(async_std::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] pub async fn test_connect_with_unknown_code_and_no_allocate_fails() { tracing::info!("hola!"); let code = generate_random_code(); let mailbox_connection = MailboxConnection::connect( transfer::APP_CONFIG.id(TEST_APPID).clone(), code.clone(), false, ) .await; assert!(mailbox_connection.is_err()); let error = mailbox_connection.err().unwrap(); match error { WormholeError::UnclaimedNameplate(nameplate) => { assert_eq!(nameplate, code.nameplate()); }, _ => { assert!(false); }, } } /** Generate common offers for testing, together with a pre-made answer that checks the received content */ #[cfg(not(target_family = "wasm"))] async fn file_offers( ) -> eyre::Result> { async fn offer( name: &str, ) -> eyre::Result<(transfer::offer::OfferSend, transfer::offer::OfferAccept)> { let path = format!("tests/{name}"); let offer = transfer::offer::OfferSend::new_file_or_folder(name.into(), &path).await?; let answer = transfer::offer::OfferSend::new_file_or_folder(name.into(), &path) .await? .set_content(|_path| { use std::{ io, pin::Pin, task::{Context, Poll}, }; let path = path.clone(); let content = transfer::offer::new_accept_content(move |_append| { struct Writer { closed: bool, send_bytes: Vec, receive_bytes: Vec, } impl futures::io::AsyncWrite for Writer { fn poll_write( mut self: Pin<&mut Self>, _: &mut Context<'_>, buf: &[u8], ) -> Poll> { self.receive_bytes.extend_from_slice(buf); Poll::Ready(Ok(buf.len())) } fn poll_close( mut self: Pin<&mut Self>, _: &mut Context<'_>, ) -> Poll> { self.closed = true; if self.send_bytes == self.receive_bytes { Poll::Ready(Ok(())) } else { Poll::Ready(Err(io::Error::new( io::ErrorKind::Other, "Send and receive are not the same", ))) } } fn poll_flush( self: Pin<&mut Self>, _: &mut Context<'_>, ) -> Poll> { Poll::Ready(Ok(())) } } impl Drop for Writer { fn drop(&mut self) { assert!(self.closed, "Implementation forgot to close Writer"); } } let path = path.clone(); async move { Ok(Writer { closed: false, send_bytes: async_std::fs::read(&path).await?, receive_bytes: Vec::new(), }) } }); transfer::offer::AcceptInner { content, offset: 0, sha256: None, } }); Ok((offer, answer)) } Ok(vec![ offer("example-file.bin").await?, /* Empty file: https://github.com/magic-wormhole/magic-wormhole.rs/issues/160 */ offer("example-file-empty").await?, /* 4k file: https://github.com/magic-wormhole/magic-wormhole.rs/issues/152 */ offer("example-file-4096.bin").await?, ]) } /** Send a file using the Rust implementation (using deprecated API). This does not guarantee compatibility with Python! ;) */ #[cfg(feature = "transfer")] #[cfg(not(target_family = "wasm"))] #[test(async_std::test)] #[allow(deprecated)] pub async fn test_file_rust2rust_deprecated() -> eyre::Result<()> { for (offer, answer) in file_offers().await? { let (code_tx, code_rx) = futures::channel::oneshot::channel(); let sender_task = async_std::task::Builder::new() .name("sender".to_owned()) .spawn(async { let (welcome, wormhole_future) = crate::Wormhole::connect_without_code( transfer::APP_CONFIG.id(TEST_APPID).clone(), 2, ) .await?; if let Some(welcome) = &welcome.welcome { tracing::info!("Got welcome: {}", welcome); } tracing::info!("This wormhole's code is: {}", &welcome.code); code_tx.send(welcome.code.clone()).unwrap(); let wormhole = wormhole_future.await?; eyre::Result::<_>::Ok( transfer::send( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, offer, &log_transit_connection, |_sent, _total| {}, futures::future::pending(), ) .await?, ) })?; let receiver_task = async_std::task::Builder::new() .name("receiver".to_owned()) .spawn(async { let code = code_rx.await?; let config = transfer::APP_CONFIG.id(TEST_APPID); tracing::info!("Got code over local: {}", &code); let (welcome, wormhole) = crate::Wormhole::connect_with_code(config.clone(), code).await?; if let Some(welcome) = &welcome.welcome { tracing::info!("Got welcome: {}", welcome); } // Hacky v1-compat conversion for now let mut answer = (answer.into_iter_files().next().unwrap().1.content)(false).await?; /*let transfer::ReceiveRequest::V1(req) = transfer::request( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, futures::future::pending(), ) .await? .unwrap() else { panic!("v2 should be disabled for now") };*/ let req = transfer::request_file( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, futures::future::pending(), ) .await? .unwrap(); req.accept( &log_transit_connection, |_received, _total| {}, &mut answer, futures::future::pending(), ) .await?; eyre::Result::<_>::Ok(()) })?; sender_task.await?; receiver_task.await?; } Ok(()) } /** Send a file using the Rust implementation. This does not guarantee compatibility with Python! ;) */ #[cfg(feature = "transfer")] #[cfg(not(target_family = "wasm"))] #[test(async_std::test)] pub async fn test_file_rust2rust() -> eyre::Result<()> { for (offer, answer) in file_offers().await? { let (code_tx, code_rx) = futures::channel::oneshot::channel(); let sender_task = async_std::task::Builder::new() .name("sender".to_owned()) .spawn(async { let mailbox_connection = MailboxConnection::create(transfer::APP_CONFIG.id(TEST_APPID).clone(), 2) .await?; if let Some(welcome) = &mailbox_connection.welcome { tracing::info!("Got welcome: {}", welcome); } tracing::info!("This wormhole's code is: {}", &mailbox_connection.code); code_tx.send(mailbox_connection.code.clone()).unwrap(); let wormhole = crate::Wormhole::connect(mailbox_connection).await?; eyre::Result::<_>::Ok( #[allow(deprecated)] transfer::send( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, offer, &log_transit_connection, |_sent, _total| {}, futures::future::pending(), ) .await?, ) })?; let receiver_task = async_std::task::Builder::new() .name("receiver".to_owned()) .spawn(async { let code = code_rx.await?; let config = transfer::APP_CONFIG.id(TEST_APPID); let mailbox = MailboxConnection::connect(config, code.clone(), false).await?; if let Some(welcome) = mailbox.welcome.clone() { tracing::info!("Got welcome: {}", welcome); } let wormhole = crate::Wormhole::connect(mailbox).await?; // Hacky v1-compat conversion for now let mut answer = (answer.into_iter_files().next().unwrap().1.content)(false).await?; /*let transfer::ReceiveRequest::V1(req) = transfer::request( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, futures::future::pending(), ) .await? .unwrap() else { panic!("v2 should be disabled for now") };*/ let req = transfer::request_file( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, futures::future::pending(), ) .await? .unwrap(); req.accept( &log_transit_connection, |_received, _total| {}, &mut answer, futures::future::pending(), ) .await?; eyre::Result::<_>::Ok(()) })?; sender_task.await?; receiver_task.await?; } Ok(()) } /** Test the functionality used by the `send-many` subcommand. */ #[cfg(feature = "transfer")] #[cfg(not(target_family = "wasm"))] #[test(async_std::test)] pub async fn test_send_many() -> eyre::Result<()> { let mailbox = MailboxConnection::create(transfer::APP_CONFIG.id(TEST_APPID), 2).await?; let code = mailbox.code.clone(); tracing::info!("The code is {:?}", code); async fn gen_offer() -> eyre::Result { file_offers().await.map(|mut vec| vec.remove(0).0) } async fn gen_accept() -> eyre::Result { file_offers().await.map(|mut vec| vec.remove(0).1) } /* Send many */ let sender_code = code.clone(); let senders = async_std::task::spawn(async move { // let mut senders = Vec::, eyre::Error>>>::new(); let mut senders: Vec>> = Vec::new(); /* The first time, we reuse the current session for sending */ { tracing::info!("Sending file #{}", 0); let wormhole = crate::Wormhole::connect(mailbox).await?; senders.push(async_std::task::spawn(async move { eyre::Result::Ok( #[allow(deprecated)] crate::transfer::send( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, gen_offer().await?, &log_transit_connection, |_, _| {}, futures::future::pending(), ) .await?, ) })); } for i in 1..5usize { tracing::info!("Sending file #{}", i); let wormhole = crate::Wormhole::connect( MailboxConnection::connect( transfer::APP_CONFIG.id(TEST_APPID), sender_code.clone(), true, ) .await?, ) .await?; let gen_offer = gen_offer.clone(); senders.push(async_std::task::spawn(async move { eyre::Result::Ok( #[allow(deprecated)] crate::transfer::send( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, gen_offer().await?, &log_transit_connection, |_, _| {}, futures::future::pending(), ) .await?, ) })); } eyre::Result::<_>::Ok(senders) }); async_std::task::sleep(std::time::Duration::from_secs(1)).await; /* Receive many */ for i in 0..5usize { tracing::info!("Receiving file #{}", i); let wormhole = crate::Wormhole::connect( MailboxConnection::connect(transfer::APP_CONFIG.id(TEST_APPID), code.clone(), true) .await?, ) .await?; tracing::info!("Got key: {}", &wormhole.key); /*let transfer::ReceiveRequest::V1(req) = crate::transfer::request( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, futures::future::pending(), ) .await? .unwrap() else { panic!("v2 should be disabled for now") };*/ let req = transfer::request_file( wormhole, default_relay_hints(), magic_wormhole::transit::Abilities::ALL_ABILITIES, futures::future::pending(), ) .await? .unwrap(); // Hacky v1-compat conversion for now let mut answer = (gen_accept() .await? .into_iter_files() .next() .unwrap() .1 .content)(false) .await?; req.accept( &log_transit_connection, |_, _| {}, &mut answer, futures::future::pending(), ) .await?; } for sender in senders.await? { sender.await?; } Ok(()) } /// Try to send a file, but use a bad code, and see how it's handled #[cfg(not(target_family = "wasm"))] #[test(async_std::test)] pub async fn test_wrong_code() -> eyre::Result<()> { let (code_tx, code_rx) = futures::channel::oneshot::channel(); let sender_task = async_std::task::Builder::new() .name("sender".to_owned()) .spawn(async { let mailbox = MailboxConnection::create(APP_CONFIG, 2).await?; if let Some(welcome) = &mailbox.welcome { tracing::info!("Got welcome: {}", welcome); } let code = mailbox.code.clone(); tracing::info!("This wormhole's code is: {}", &code); code_tx.send(code.nameplate()).unwrap(); let result = crate::Wormhole::connect(mailbox).await; /* This should have failed, due to the wrong code */ assert!(result.is_err()); eyre::Result::<_>::Ok(()) })?; let receiver_task = async_std::task::Builder::new() .name("receiver".to_owned()) .spawn(async { let nameplate = code_rx.await?; tracing::info!("Got nameplate over local: {}", &nameplate); let result = crate::Wormhole::connect( MailboxConnection::connect( APP_CONFIG, /* Making a wrong code here by appending nonsense */ Code::from_components(nameplate, "foo-bar".parse().unwrap()), true, ) .await?, ) .await; /* This should have failed, due to the wrong code */ assert!(result.is_err()); eyre::Result::<_>::Ok(()) })?; async_std::future::timeout(TIMEOUT, sender_task).await??; async_std::future::timeout(TIMEOUT, receiver_task).await??; Ok(()) } /** Connect three people to the party and watch it explode … gracefully */ #[test(async_std::test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] pub async fn test_crowded() { let initial_mailbox_connection = MailboxConnection::create(APP_CONFIG, 2).await.unwrap(); tracing::info!("This test's code is: {}", &initial_mailbox_connection.code); let code = initial_mailbox_connection.code.clone(); let mailbox_connection_1 = MailboxConnection::connect(APP_CONFIG.clone(), code.clone(), false); let mailbox_connection_2 = MailboxConnection::connect(APP_CONFIG.clone(), code.clone(), false); match futures::try_join!(mailbox_connection_1, mailbox_connection_2) .err() .unwrap() { magic_wormhole::WormholeError::ServerError( magic_wormhole::rendezvous::RendezvousError::Server(error), ) => { assert_eq!(&*error, "crowded") }, other => panic!("Got wrong error message: {}, wanted 'crowded'", other), } } #[async_std::test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] pub async fn test_connect_with_code_expecting_nameplate() { let code = generate_random_code(); let result = MailboxConnection::connect(APP_CONFIG, code.clone(), false).await; let error = result.err().unwrap(); match error { magic_wormhole::WormholeError::UnclaimedNameplate(x) => { assert_eq!(x, code.nameplate()); }, other => panic!( "Got wrong error type {:?}. Expected `NameplateNotFound`", other ), } } fn generate_random_code() -> Code { let mut rng = rand::thread_rng(); let nameplate_string = format!("{}-guitarist-revenge", rng.gen_range(1000..10000)); Code::from_str(&nameplate_string).unwrap() } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_phase() { let p = Phase::PAKE; assert!(p.is_pake()); assert!(!p.is_version()); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_mood() { // The serialized forms of these variants are part of the wire protocol, // so they must be spelled exactly as shown (they must match the strings // used in the Python version in src/wormhole/_boss.py , in calls to // self._T.close()) assert_eq!( String::from(r#""happy""#), serde_json::to_string(&Mood::Happy).unwrap() ); assert_eq!( String::from(r#""lonely""#), serde_json::to_string(&Mood::Lonely).unwrap() ); assert_eq!( String::from(r#""errory""#), serde_json::to_string(&Mood::Errory).unwrap() ); assert_eq!( String::from(r#""scary""#), serde_json::to_string(&Mood::Scared).unwrap() ); assert_eq!( String::from(r#""unwelcome""#), serde_json::to_string(&Mood::Unwelcome).unwrap() ); } magic-wormhole-0.7.6/src/core/wordlist.rs000064400000000000000000000254101046102023000165060ustar 00000000000000//! Wordlist generation and wormhole code utilities use rand::{rngs::OsRng, seq::SliceRandom}; use serde_json::{self, Value}; use std::fmt; use super::Password; /// Represents a list of words used to generate and complete wormhole codes. /// A wormhole code is a sequence of words used for secure communication or identification. #[derive(PartialEq)] pub struct Wordlist { /// Number of words in a wormhole code num_words: usize, /// Odd and even wordlist words: Vec>, } impl fmt::Debug for Wordlist { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Wordlist ( {}, lots of words...)", self.num_words) } } impl Wordlist { #[cfg(test)] #[doc(hidden)] pub fn new(num_words: usize, words: Vec>) -> Wordlist { Wordlist { num_words, words } } /// Completes a wormhole code /// /// Completion can be done either with fuzzy search (approximate string matching) /// or simple `starts_with` matching. pub fn get_completions(&self, prefix: &str) -> Vec { let words = self.get_wordlist(prefix); let (prefix_without_last, last_partial) = prefix.rsplit_once('-').unwrap_or(("", prefix)); #[cfg(feature = "fuzzy-complete")] let matches = self.fuzzy_complete(last_partial, words); #[cfg(not(feature = "fuzzy-complete"))] let matches = self.normal_complete(last_partial, words); matches .into_iter() .map(|word| { let mut completion = String::new(); completion.push_str(prefix_without_last); if !prefix_without_last.is_empty() { completion.push('-'); } completion.push_str(&word); completion }) .collect() } fn get_wordlist(&self, prefix: &str) -> &Vec { let count_dashes = prefix.matches('-').count(); let index = 1 - (count_dashes % 2); &self.words[index] } #[cfg(feature = "fuzzy-complete")] fn fuzzy_complete(&self, partial: &str, words: &[String]) -> Vec { // We use Jaro-Winkler algorithm because it emphasizes the beginning of a word use fuzzt::algorithms::JaroWinkler; let words = words.iter().map(|w| w.as_str()).collect::>(); fuzzt::get_top_n(partial, &words, None, None, None, Some(&JaroWinkler)) .into_iter() .map(|s| s.to_string()) .collect() } #[allow(unused)] fn normal_complete(&self, partial: &str, words: &[String]) -> Vec { words .iter() .filter(|word| !partial.is_empty() && word.starts_with(partial)) .cloned() .collect() } /// Choose wormhole code word pub fn choose_words(&self) -> Password { let mut rng = OsRng; let components: Vec = self .words .iter() .cycle() .take(self.num_words) .map(|words| words.choose(&mut rng).unwrap().to_string()) .collect(); #[allow(unsafe_code)] unsafe { Password::new_unchecked(components.join("-")) } } #[cfg(feature = "entropy")] pub(crate) fn into_words(self) -> impl Iterator { self.words.into_iter().flatten() } /// Construct Wordlist struct with given number of words in a wormhole code pub fn default_wordlist(num_words: usize) -> Wordlist { Wordlist { num_words, words: load_pgpwords(), } } } fn load_pgpwords() -> Vec> { let raw_words_value: Value = serde_json::from_str(include_str!("pgpwords.json")).unwrap(); let raw_words = raw_words_value.as_object().unwrap(); let mut even_words: Vec = Vec::with_capacity(256); even_words.resize(256, String::from("")); let mut odd_words: Vec = Vec::with_capacity(256); odd_words.resize(256, String::from("")); for (index_str, values) in raw_words.iter() { let index = u8::from_str_radix(index_str, 16).unwrap() as usize; even_words[index] = values .get(1) .unwrap() .as_str() .unwrap() .to_lowercase() .to_string(); odd_words[index] = values .get(0) .unwrap() .as_str() .unwrap() .to_lowercase() .to_string(); } vec![even_words, odd_words] } #[cfg(test)] mod test { use super::*; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_load_words() { let w = load_pgpwords(); assert_eq!(w.len(), 2); assert_eq!(w[0][0], "adroitness"); assert_eq!(w[1][0], "aardvark"); assert_eq!(w[0][255], "yucatan"); assert_eq!(w[1][255], "zulu"); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_default_wordlist() { let d = Wordlist::default_wordlist(2); assert_eq!(d.words.len(), 2); assert_eq!(d.words[0][0], "adroitness"); assert_eq!(d.words[1][0], "aardvark"); assert_eq!(d.words[0][255], "yucatan"); assert_eq!(d.words[1][255], "zulu"); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_get_wordlist() { let list = Wordlist::default_wordlist(2); assert_eq!(list.words.len(), 2); assert_eq!(list.get_wordlist("22-"), &list.words[0]); assert_eq!(list.get_wordlist("22-dictator-"), &list.words[1]); } fn vec_strs(all: &str) -> Vec<&str> { all.split_whitespace() .map(|s| if s == "." { "" } else { s }) .collect() } fn vec_strings(all: &str) -> Vec { vec_strs(all).iter().map(|s| (*s).to_owned()).collect() } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_completion() { let words: Vec> = vec![ vec_strings("purple green yellow"), vec_strings("sausages seltzer snobol"), ]; let w = Wordlist::new(2, words); assert_eq!(w.get_completions(""), Vec::::new()); assert_eq!(w.get_completions("9"), Vec::::new()); assert_eq!(w.get_completions("seltz"), vec!["seltzer"]); assert_eq!(w.get_completions("sausages-yello"), vec!["sausages-yellow"]); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_choose_words() { let few_words: Vec> = vec![vec_strings("purple"), vec_strings("sausages")]; let w = Wordlist::new(2, few_words.clone()); assert_eq!(w.choose_words().as_ref(), "purple-sausages"); let w = Wordlist::new(3, few_words.clone()); assert_eq!(w.choose_words().as_ref(), "purple-sausages-purple"); let w = Wordlist::new(4, few_words); assert_eq!(w.choose_words().as_ref(), "purple-sausages-purple-sausages"); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_choose_words_matches_completion() { let few_words: Vec> = vec![vec_strings("purple"), vec_strings("sausages")]; let w = Wordlist::new(2, few_words.clone()); assert_eq!(w.choose_words().as_ref(), "purple-sausages"); // Check if odd and even wordlist are correctly selected assert_eq!( w.get_completions("1-purple-sausages").first().unwrap(), &format!("1-{}", w.choose_words().as_ref()) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_choose_more_words() { let more_words = vec![vec_strings("purple yellow"), vec_strings("sausages")]; let expected2 = vec_strs("purple-sausages yellow-sausages"); let expected3 = vec![ "purple-sausages-purple", "yellow-sausages-purple", "purple-sausages-yellow", "yellow-sausages-yellow", ]; let w = Wordlist::new(2, more_words.clone()); for _ in 0..20 { assert!(expected2.contains(&w.choose_words().as_ref())); } let w = Wordlist::new(3, more_words); for _ in 0..20 { assert!(expected3.contains(&w.choose_words().as_ref())); } } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg(feature = "fuzzy-complete")] fn test_completion_fuzzy() { let wl = Wordlist::default_wordlist(2); let list = wl.get_wordlist("22-"); assert_eq!( wl.fuzzy_complete("bzili", list).first().unwrap(), "brazilian" ); assert_eq!( wl.fuzzy_complete("carvan", list).first().unwrap(), "caravan" ); assert_ne!( wl.fuzzy_complete("choking", list).first().unwrap(), "choking" ) } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_completion_normal() { let wl = Wordlist::default_wordlist(2); let list = wl.get_wordlist("22-"); assert_eq!( wl.normal_complete("braz", list).first().unwrap(), "brazilian" ); assert_eq!(wl.normal_complete("cara", list).first().unwrap(), "caravan"); assert!(wl.normal_complete("cravan", list).is_empty()); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_wormhole_code_normal_completions() { let list = Wordlist::default_wordlist(2); assert_eq!( list.get_completions("22-compo").first().unwrap(), "22-component" ); assert_eq!( list.get_completions("22-component-check").first().unwrap(), "22-component-checkup" ); assert_ne!(list.get_completions("22-troj"), ["trojan"]); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg(feature = "fuzzy-complete")] fn test_wormhole_code_fuzzy_completions() { let list = Wordlist::default_wordlist(2); assert_eq!(list.get_completions("22"), Vec::::new()); assert_eq!(list.get_completions("22-"), Vec::::new()); assert_ne!(list.get_completions("22-trj"), ["trojan"]); assert_eq!( list.get_completions("22-udau").first().unwrap(), "22-undaunted" ); assert_eq!( list.get_completions("22-undua").first().unwrap(), "22-undaunted" ); assert_eq!( list.get_completions("22-undaunted-usht").first().unwrap(), "22-undaunted-upshot" ); } } magic-wormhole-0.7.6/src/core.rs000064400000000000000000001154531046102023000146460ustar 00000000000000#![allow(deprecated)] pub(super) mod key; pub mod rendezvous; mod server_messages; #[cfg(test)] mod test; /// Module for wormhole code generation and completion. pub mod wordlist; use serde_derive::{Deserialize, Serialize}; use std::{borrow::Cow, str::FromStr}; use thiserror::Error; use crate::Wordlist; use self::{rendezvous::*, server_messages::EncryptedMessage}; use crypto_secretbox as secretbox; /// An error occurred in the wormhole connection #[derive(Debug, thiserror::Error)] #[non_exhaustive] pub enum WormholeError { /// Corrupt message received from peer. Some deserialization went wrong, we probably got some garbage #[error("Corrupt message received from peer")] ProtocolJson( #[from] #[source] serde_json::Error, ), /// Error with the rendezvous server connection. Some deserialization went wrong, we probably got some garbage #[error("Error with the rendezvous server connection")] ServerError( #[from] #[source] rendezvous::RendezvousError, ), /// A generic string message for "something went wrong", i.e. /// the server sent some bullshit message order #[error("Protocol error: {}", _0)] Protocol(Box), /// Key confirmation failed. If you didn't mistype the code, /// this is a sign of an attacker guessing passwords. Please try /// again some time later. #[error( "Key confirmation failed. If you didn't mistype the code, \ this is a sign of an attacker guessing passwords. Please try \ again some time later." )] PakeFailed, /// Cannot decrypt a received message #[error("Cannot decrypt a received message")] Crypto, /// Nameplate is unclaimed #[error("Nameplate is unclaimed: {}", _0)] UnclaimedNameplate(Nameplate), /// The provided code is invalid #[error("The provided code is invalid: {_0}")] CodeInvalid(#[from] ParseCodeError), } impl WormholeError { /** Should we tell the server that we are "errory" or "scared"? */ pub fn is_scared(&self) -> bool { matches!(self, Self::PakeFailed) } } impl From for WormholeError { fn from(_: std::convert::Infallible) -> Self { unreachable!() } } /** * The result of the client-server handshake */ #[derive(Clone, Debug, PartialEq, Eq)] #[deprecated( since = "0.7.0", note = "part of the response of `Wormhole::connect_without_code(...)` and `Wormhole::connect_with_code(...) please use 'MailboxConnection::create(...)`/`MailboxConnection::connect(..)` and `Wormhole::connect(mailbox_connection)' instead" )] pub struct WormholeWelcome { /** A welcome message from the server (think of "message of the day"). Should be displayed to the user if present. */ pub welcome: Option, /// The wormhole code used in the exchange pub code: Code, } /** * Establishing Wormhole connection * * You can send and receive arbitrary messages in form of byte slices over it, using [`Wormhole::send`] and [`Wormhole::receive`]. * Everything else (including encryption) will be handled for you. * * To create a wormhole, use the mailbox connection created via [`MailboxConnection::create`] or [`MailboxConnection::connect`] with the [`Wormhole::connect`] method. * Typically, the sender side connects without a code (which will create one), and the receiver side has one (the user entered it, who got it from the sender). * * # Clean shutdown * * TODO */ /* TODO * Maybe a better way to handle application level protocols is to create a trait for them and then * to paramterize over them. */ /// A `MailboxConnection` contains a `RendezvousServer` which is connected to the mailbox pub struct MailboxConnection { /// A copy of `AppConfig`, config: AppConfig, /// The `RendezvousServer` with an open mailbox connection server: RendezvousServer, /// The welcome message received from the mailbox server welcome: Option, /// The mailbox id of the created mailbox mailbox: Mailbox, /// The Code which is required to connect to the mailbox. code: Code, } impl MailboxConnection { /// Create a connection to a mailbox which is configured with a `Code` starting with the nameplate and by a given number of wordlist based random words. /// /// # Arguments /// /// * `config`: Application configuration /// * `code_length`: number of words used for the password. The words are taken from the default wordlist. /// /// # Examples /// /// ```no_run /// # fn main() -> eyre::Result<()> { async_std::task::block_on(async { /// use magic_wormhole::{transfer::APP_CONFIG, AppConfig, MailboxConnection}; /// let config = APP_CONFIG; /// let mailbox_connection = MailboxConnection::create(config, 2).await?; /// # Ok(()) })} /// ``` pub async fn create(config: AppConfig, code_length: usize) -> Result { Self::create_with_validated_password( config, Wordlist::default_wordlist(code_length).choose_words(), ) .await } /// Create a connection to a mailbox which is configured with a `Code` containing the nameplate and the given password. /// /// # Arguments /// /// * `config`: Application configuration /// * `password`: Free text password which will be appended to the nameplate number to form the `Code` /// /// # Examples /// /// ```no_run /// # #[cfg(feature = "entropy")] /// # { /// # fn main() -> eyre::Result<()> { async_std::task::block_on(async { /// use magic_wormhole::{transfer::APP_CONFIG, MailboxConnection}; /// let config = APP_CONFIG; /// let mailbox_connection = /// MailboxConnection::create_with_password(config, "secret".parse()?).await?; /// # Ok(()) })} /// # } /// ``` /// /// TODO: Replace this with create_with_validated_password pub async fn create_with_password( config: AppConfig, #[cfg(not(feature = "entropy"))] password: &str, #[cfg(feature = "entropy")] password: Password, ) -> Result { #[cfg(not(feature = "entropy"))] let password = password.parse().map_err(ParseCodeError::from)?; Self::create_with_validated_password(config, password).await } /// Create a connection to a mailbox which is configured with a `Code` containing the nameplate and the given password. /// /// # Arguments /// /// * `config`: Application configuration /// * `password`: Free text password which will be appended to the nameplate number to form the `Code` async fn create_with_validated_password( config: AppConfig, password: Password, ) -> Result { let (mut server, welcome) = RendezvousServer::connect(&config.id, &config.rendezvous_url).await?; let (nameplate, mailbox) = server.allocate_claim_open().await?; let code = Code::from_components(nameplate, password); Ok(MailboxConnection { config, server, mailbox, code, welcome, }) } /// Create a connection to a mailbox defined by a `Code` which contains the `Nameplate` and the password to authorize the access. /// /// # Arguments /// /// * `config`: Application configuration /// * `code`: The `Code` required to authorize to connect to an existing mailbox. /// * `allocate`: /// - `true`: Allocates a `Nameplate` if it does not exist. /// - `false`: The call fails with a `WormholeError::UnclaimedNameplate` when the `Nameplate` does not exist. /// /// # Examples /// /// ```no_run /// # fn main() -> eyre::Result<()> { async_std::task::block_on(async { /// use magic_wormhole::{transfer::APP_CONFIG, Code, MailboxConnection, Nameplate}; /// let config = APP_CONFIG; /// let code = "5-password".parse()?; /// let mailbox_connection = MailboxConnection::connect(config, code, false).await?; /// # Ok(()) })} /// ``` pub async fn connect( config: AppConfig, code: Code, allocate: bool, ) -> Result { let (mut server, welcome) = RendezvousServer::connect(&config.id, &config.rendezvous_url).await?; let nameplate = code.nameplate(); // Ensure the code has enough entropy without the nameplate [#193](https://github.com/magic-wormhole/magic-wormhole.rs/issues/193) if !allocate { let nameplates = server.list_nameplates().await?; if !nameplates.contains(&nameplate) { server.shutdown(Mood::Errory).await?; return Err(WormholeError::UnclaimedNameplate(nameplate)); } } let mailbox = server.claim_open(nameplate).await?; Ok(MailboxConnection { config, server, mailbox, code, welcome, }) } /// Shut down the connection to the mailbox /// /// # Arguments /// /// * `mood`: `Mood` should give a hint of the reason of the shutdown /// /// # Examples /// /// ``` /// # fn main() -> eyre::Result<()> { use magic_wormhole::WormholeError; /// # #[cfg(feature = "entropy")] /// return async_std::task::block_on(async { /// use magic_wormhole::{transfer::APP_CONFIG, MailboxConnection, Mood}; /// let config = APP_CONFIG; /// let mailbox_connection = MailboxConnection::create_with_password(config, "secret-code-password".parse()?) /// .await?; /// mailbox_connection.shutdown(Mood::Happy).await?; /// # Ok(())}); /// # #[cfg(not(feature = "entropy"))] /// # return Ok(()); /// # } /// ``` pub async fn shutdown(self, mood: Mood) -> Result<(), WormholeError> { self.server .shutdown(mood) .await .map_err(WormholeError::ServerError) } /// The welcome message received from the mailbox server pub fn welcome(&self) -> Option<&str> { self.welcome.as_deref() } /// The mailbox id of the created mailbox pub fn mailbox(&self) -> &Mailbox { &self.mailbox } /// The Code that was used to connect to the mailbox. pub fn code(&self) -> &Code { &self.code } } /// A wormhole is an open connection to a peer via the rendezvous server. /// /// This establishes the client-client part of the connection setup. #[derive(Debug)] pub struct Wormhole { #[allow(deprecated)] server: RendezvousServer, phase: u64, key: key::Key, appid: AppID, /// The cryptographic verifier code for the connection #[deprecated(since = "0.7.0", note = "Use the verifier() method")] pub verifier: Box, /// Our app version #[deprecated(since = "0.7.0", note = "Use the our_version() method")] pub our_version: Box, /// The app version of the peer #[deprecated(since = "0.7.0", note = "Use the peer_version() method")] pub peer_version: serde_json::Value, } impl Wormhole { /** * Generate a code and connect to the rendezvous server. * * # Returns * * A tuple with a [`WormholeWelcome`] and a [`std::future::Future`] that will * do the rest of the client-client handshake and yield the [`Wormhole`] object * on success. */ #[deprecated( since = "0.7.0", note = "please use 'MailboxConnection::create(..) and Wormhole::connect(mailbox_connection)' instead" )] #[allow(deprecated)] pub async fn connect_without_code( config: AppConfig, code_length: usize, ) -> Result< ( WormholeWelcome, impl std::future::Future>, ), WormholeError, > { let mailbox_connection = MailboxConnection::create(config, code_length).await?; Ok(( WormholeWelcome { welcome: mailbox_connection.welcome.clone(), code: mailbox_connection.code.clone(), }, Self::connect(mailbox_connection), )) } /** * Connect to a peer with a code. */ #[deprecated( since = "0.7.0", note = "please use 'MailboxConnection::connect(..) and Wormhole::connect(mailbox_connection)' instead" )] #[allow(deprecated)] pub async fn connect_with_code( config: AppConfig, code: Code, ) -> Result<(WormholeWelcome, Self), WormholeError> { let mailbox_connection = MailboxConnection::connect(config, code.clone(), true).await?; Ok(( WormholeWelcome { welcome: mailbox_connection.welcome.clone(), code, }, Self::connect(mailbox_connection).await?, )) } /// Set up a Wormhole which is the client-client part of the connection setup /// /// The MailboxConnection already contains a rendezvous server with an opened mailbox. pub async fn connect( mailbox_connection: MailboxConnection, ) -> Result { let MailboxConnection { config, mut server, mailbox: _mailbox, code, welcome: _welcome, } = mailbox_connection; /* Send PAKE */ let (pake_state, pake_msg_ser) = key::make_pake(code.as_ref(), &config.id); server.send_peer_message(Phase::PAKE, pake_msg_ser).await?; /* Receive PAKE */ let peer_pake = key::extract_pake_msg(&server.next_peer_message_some().await?.body)?; let key = pake_state .finish(&peer_pake) .map_err(|_| WormholeError::PakeFailed) .map(|key| *secretbox::Key::from_slice(&key))?; /* Send versions message */ let mut versions = key::VersionsMessage::new(); versions.set_app_versions(serde_json::to_value(&config.app_version).unwrap()); let (version_phase, version_msg) = key::build_version_msg(server.side(), &key, &versions); server.send_peer_message(version_phase, version_msg).await?; let peer_version = server.next_peer_message_some().await?; /* Handle received message */ let versions: key::VersionsMessage = peer_version .decrypt(&key) .ok_or(WormholeError::PakeFailed) .and_then(|plaintext| { serde_json::from_slice(&plaintext).map_err(WormholeError::ProtocolJson) })?; let peer_version = versions.app_versions; if server.needs_nameplate_release() { server.release_nameplate().await?; } tracing::info!("Found peer on the rendezvous server."); /* We are now fully initialized! Up and running! :tada: */ #[allow(deprecated)] Ok(Self { server, appid: config.id, phase: 0, key: key::Key::new(key.into()), verifier: Box::new(key::derive_verifier(&key)), our_version: Box::new(config.app_version), peer_version, }) } /** Send an encrypted message to peer */ pub async fn send(&mut self, plaintext: Vec) -> Result<(), WormholeError> { let phase_string = Phase::numeric(self.phase); self.phase += 1; let data_key = key::derive_phase_key(self.server.side(), &self.key, &phase_string); let (_nonce, encrypted) = key::encrypt_data(&data_key, &plaintext); self.server .send_peer_message(phase_string, encrypted) .await?; Ok(()) } /** * Serialize and send an encrypted message to peer * * This will serialize the message as `json` string, which is most commonly * used by upper layer protocols. The serialization may not fail * * ## Panics * * If the serialization fails */ pub async fn send_json( &mut self, message: &T, ) -> Result<(), WormholeError> { self.send(serde_json::to_vec(message).unwrap()).await } /** Receive an encrypted message from peer */ pub async fn receive(&mut self) -> Result, WormholeError> { loop { let peer_message = match self.server.next_peer_message().await? { Some(peer_message) => peer_message, None => continue, }; if peer_message.phase.to_num().is_none() { // TODO: log and ignore, for future expansion todo!("log and ignore, for future expansion"); } // TODO maybe reorder incoming messages by phase numeral? let decrypted_message = peer_message .decrypt(&self.key) .ok_or(WormholeError::Crypto)?; // Send to client return Ok(decrypted_message); } } /** * Receive an encrypted message from peer * * This will deserialize the message as `json` string, which is most commonly * used by upper layer protocols. We distinguish between the different layers * on which a serialization error happened, hence the double `Result`. */ pub async fn receive_json(&mut self) -> Result, WormholeError> where T: for<'a> serde::Deserialize<'a>, { self.receive().await.map(|data: Vec| { serde_json::from_slice(&data).inspect_err(|_| { tracing::error!( "Received invalid data from peer: '{}'", String::from_utf8_lossy(&data) ); }) }) } /// Close the wormhole pub async fn close(self) -> Result<(), WormholeError> { tracing::debug!("Closing Wormhole…"); self.server.shutdown(Mood::Happy).await.map_err(Into::into) } /** * The `AppID` this wormhole is bound to. * This determines the upper-layer protocol. Only wormholes with the same value can talk to each other. */ pub fn appid(&self) -> &AppID { &self.appid } /** * The symmetric encryption key used by this connection. * Can be used to derive sub-keys for different purposes. */ pub fn key(&self) -> &key::Key { &self.key } /** * If you're paranoid, let both sides check that they calculated the same verifier. * * PAKE hardens a standard key exchange with a password ("password authenticated") in order * to mitigate potential man in the middle attacks that would otherwise be possible. Since * the passwords usually are not of hight entropy, there is a low-probability possible of * an attacker guessing the password correctly, enabling them to MitM the connection. * * Not only is that probability low, but they also have only one try per connection and a failed * attempts will be noticed by both sides. Nevertheless, comparing the verifier mitigates that * attack vector. */ pub fn verifier(&self) -> &secretbox::Key { #[allow(deprecated)] &self.verifier } /** * Our "app version" information that we sent. See the [`peer_version`](Self::peer_version()) for more information. */ pub fn our_version(&self) -> &(dyn std::any::Any + Send + Sync) { #[allow(deprecated)] &*self.our_version } /** * Protocol version information from the other side. * This is bound by the [`AppID`]'s protocol and thus shall be handled on a higher level * (e.g. by the file transfer API). */ pub fn peer_version(&self) -> &serde_json::Value { #[allow(deprecated)] &self.peer_version } } /// The close command accepts an optional "mood" string: this allows clients to tell the server /// (in general terms) about their experiences with the wormhole interaction. The server records /// the mood in its "usage" record, so the server operator can get a sense of how many connections /// are succeeding and failing. The moods currently recognized by the Mailbox server are: #[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize, derive_more::Display)] pub enum Mood { /// The PAKE key-establishment worked, and the client saw at least one valid encrypted message from its peer #[serde(rename = "happy")] Happy, /// The client gave up without hearing anything from its peer #[serde(rename = "lonely")] Lonely, /// The client encountered some other error: protocol problem or internal error #[serde(rename = "errory")] Errory, /// The client saw an invalid encrypted message from its peer, /// indicating that either the wormhole code was typed in wrong, /// or an attacker tried (and failed) to guess the code #[serde(rename = "scary")] Scared, /// Clients are not welcome on the server right now #[serde(rename = "unwelcome")] Unwelcome, } /** * Wormhole configuration corresponding to an uppler layer protocol * * There are multiple different protocols built on top of the core * Wormhole protocol. They are identified by a unique URI-like ID string * (`AppID`), an URL to find the rendezvous server (might be shared among * multiple protocols), and client implementations also have a "version" * data to do protocol negotiation. * * See [`crate::transfer::APP_CONFIG`]. */ #[derive(PartialEq, Eq, Clone, Debug)] pub struct AppConfig { /// The ID of the used application pub id: AppID, /// The URL of the rendezvous server pub rendezvous_url: Cow<'static, str>, /// The client application version pub app_version: V, } impl AppConfig { /// Set the app id pub fn id(mut self, id: AppID) -> Self { self.id = id; self } /// Set the rendezvous URL pub fn rendezvous_url(mut self, rendezvous_url: Cow<'static, str>) -> Self { self.rendezvous_url = rendezvous_url; self } } impl AppConfig { /// Set the app version pub fn app_version(mut self, app_version: V) -> Self { self.app_version = app_version; self } } /// Newtype wrapper for application IDs /// /// The application ID is a string that scopes all commands /// to that name, effectively separating different protocols /// on the same rendezvous server. #[derive( PartialEq, Eq, Clone, Debug, Deserialize, Serialize, derive_more::Display, derive_more::Deref, )] #[deref(forward)] pub struct AppID( #[deref] #[deprecated(since = "0.7.0", note = "use the AsRef implementation")] pub Cow<'static, str>, ); impl AppID { /// Create a new app ID from an ID string pub fn new(id: impl Into>) -> Self { AppID(id.into()) } } impl From for AppID { fn from(s: String) -> Self { Self::new(s) } } impl AsRef for AppID { fn as_ref(&self) -> &str { &self.0 } } // MySide is used for the String that we send in all our outbound messages #[derive( PartialEq, Eq, Clone, Debug, Deserialize, Serialize, derive_more::Display, derive_more::Deref, )] #[serde(transparent)] #[display("MySide({})", "&*_0")] #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] pub struct MySide(EitherSide); impl MySide { pub fn generate() -> MySide { use rand::{rngs::OsRng, RngCore}; let mut bytes: [u8; 5] = [0; 5]; OsRng.fill_bytes(&mut bytes); MySide(EitherSide(hex::encode(bytes))) } // It's a minor type system feature that converting an arbitrary string into MySide is hard. // This prevents it from getting swapped around with TheirSide. #[cfg(test)] pub fn unchecked_from_string(s: String) -> MySide { MySide(EitherSide(s)) } } // TheirSide is used for the string that arrives inside inbound messages #[derive( PartialEq, Eq, Clone, Debug, Deserialize, Serialize, derive_more::Display, derive_more::Deref, )] #[serde(transparent)] #[display("TheirSide({})", "&*_0")] #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] pub struct TheirSide(EitherSide); impl> From for TheirSide { fn from(s: S) -> TheirSide { TheirSide(EitherSide(s.into())) } } #[derive( PartialEq, Eq, Clone, Debug, Deserialize, Serialize, derive_more::Display, derive_more::Deref, )] #[serde(transparent)] #[deref(forward)] #[display("{}", "&*_0")] #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] pub struct EitherSide(pub String); impl> From for EitherSide { fn from(s: S) -> EitherSide { EitherSide(s.into()) } } #[derive(PartialEq, Eq, Clone, Debug, Hash, Deserialize, Serialize, derive_more::Display)] #[serde(transparent)] #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] pub struct Phase(Cow<'static, str>); impl Phase { pub const VERSION: Self = Phase(Cow::Borrowed("version")); pub const PAKE: Self = Phase(Cow::Borrowed("pake")); pub fn numeric(phase: u64) -> Self { Phase(phase.to_string().into()) } #[allow(dead_code)] pub fn is_version(&self) -> bool { self == &Self::VERSION } #[allow(dead_code)] pub fn is_pake(&self) -> bool { self == &Self::PAKE } pub fn to_num(&self) -> Option { self.0.parse().ok() } } impl AsRef for Phase { fn as_ref(&self) -> &str { &self.0 } } #[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize, derive_more::Display)] #[serde(transparent)] #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] pub struct Mailbox(pub String); /// An error occurred when parsing a nameplate: Nameplate is not a number. #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Copy, derive_more::Display, Error)] #[display("Nameplate is not a number. Nameplates must be a number >= 1.")] #[non_exhaustive] pub struct ParseNameplateError {} /// Wormhole codes look like 4-purple-sausages, consisting of a number followed by some random words. /// This number is called a "Nameplate". #[derive( PartialEq, Eq, Clone, Debug, Deserialize, Serialize, derive_more::Display, derive_more::Deref, )] #[serde(transparent)] #[deref(forward)] #[display("{}", _0)] #[cfg(not(feature = "entropy"))] pub struct Nameplate( #[deprecated(since = "0.7.0", note = "use the AsRef implementation")] pub String, ); /// Wormhole codes look like 4-purple-sausages, consisting of a number followed by some random words. /// This number is called a "Nameplate". #[derive(PartialEq, Eq, Clone, Debug, Deserialize, Serialize, derive_more::Display)] #[serde(transparent)] #[display("{}", _0)] #[cfg(feature = "entropy")] pub struct Nameplate(String); #[allow(deprecated)] impl Nameplate { /// Create a new nameplate from a string. /// /// Nameplate will be [required to be numbers](https://github.com/magic-wormhole/magic-wormhole-mailbox-server/issues/45) soon. #[deprecated( since = "0.7.2", note = "Nameplates will be required to be numbers soon. Use the [std::str::FromStr] implementation" )] #[cfg(not(feature = "entropy"))] pub fn new(n: impl Into) -> Self { let nameplate = n.into(); if let Err(err) = Nameplate::from_str(&nameplate) { tracing::error!("{err}"); } #[allow(unsafe_code)] unsafe { Self::new_unchecked(&nameplate) } } /// Create a new nameplate from a string. /// /// Safety: Nameplate will be [required to be numbers](https://github.com/magic-wormhole/magic-wormhole-mailbox-server/issues/45) soon. #[allow(unsafe_code)] #[doc(hidden)] pub unsafe fn new_unchecked(n: &str) -> Self { Nameplate(n.into()) } } impl FromStr for Nameplate { type Err = ParseNameplateError; fn from_str(s: &str) -> Result { if !s.chars().all(|c| c.is_ascii_digit()) || u128::from_str(s) == Ok(0) { Err(ParseNameplateError {}) } else { Ok(Self(s.to_string())) } } } /// Deprecated: Use the [`std::fmt::Display`] implementation #[allow(deprecated)] impl From for String { fn from(value: Nameplate) -> Self { value.0 } } /// Deprecated: Use the [`std::str::FromStr`] implementation /// /// Does not check if the nameplate is a number. This may be incompatible. #[allow(deprecated)] #[cfg(not(feature = "entropy"))] impl From for Nameplate { fn from(value: String) -> Self { tracing::debug!( "Implementation of From for Nameplate is deprecated. Use the FromStr implementation instead" ); if let Err(err) = Nameplate::from_str(&value) { tracing::error!("{err} This will be a hard error in the future."); } Self(value) } } /// Deprecated: Use the [`std::fmt::Display`] implementation #[allow(deprecated)] impl AsRef for Nameplate { fn as_ref(&self) -> &str { &self.0 } } /// This is a compromise. Generally we want to be wordlist-agnostic here. But /// we can't ignore that the PGP wordlist is the most common wordlist in use. /// /// - The shortest word in the PGP wordlist is 4 characters long. The longest /// word is 9 characters. This means we can't limit to more than 9 bytes here, /// 'solo-orca' is 9 bytes, and we want to allow 2-word codes. /// - A 9 character random password is very strong. If it is only comprised of /// uniformly distributed lowercase ASCII characters, we have an entropy of /// 26^9 >= 40 bits. This is much more than the default 16 bits we get from two /// words from the PGP wordlist. /// - An emoji contains at least 2 bytes of data. So two emoji are actually /// about the same security as two words from the PGP wordlist. /// /// We ultimately can't protect people from making bad choices, as entropy is a /// very difficult thing. What we can do instead is offer guidance, by printing /// warnings in case of rather short passwords, and making people choose for /// themselves whether their privacy is worth it to them choosing longer codes. #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Copy, derive_more::Display, Error)] #[non_exhaustive] pub enum ParsePasswordError { /// Password too short #[display("Password too short. It is only {value} bytes, but must be at least {required}")] TooShort { /// The calculated value value: usize, /// The value that is required required: usize, }, /// Password does not have enough entropy #[display( "Password too weak. It can be guessed with an average of {value} tries, but must be at least {required}" )] LittleEntropy { /// The calculated value value: u64, /// The value that is required required: u64, }, } /// Wormhole codes look like 4-purple-sausages, consisting of a number followed by some random words. /// This number is called a "Nameplate", the rest is called the `Password` #[derive(Clone, Debug, Serialize, derive_more::Display)] #[serde(transparent)] #[display("{password}")] pub struct Password { password: String, #[serde(skip)] #[cfg(feature = "entropy")] entropy: zxcvbn::Entropy, } impl PartialEq for Password { fn eq(&self, other: &Self) -> bool { self.password == other.password } } impl Eq for Password {} impl Password { /// Create a new password from a string. Does not check the entropy of the password. /// /// You should use [`Password::from_str`] / [`String::parse`] instead. /// /// Safety: Does not check the entropy of the password, or if one exists at all. This can be a security risk. #[allow(unsafe_code)] #[doc(hidden)] pub unsafe fn new_unchecked(n: impl Into) -> Self { let password = n.into(); #[cfg(feature = "entropy")] let entropy = Self::calculate_entropy(&password); Password { password, #[cfg(feature = "entropy")] entropy, } } #[cfg(feature = "entropy")] fn calculate_entropy(password: &str) -> zxcvbn::Entropy { static PGP_WORDLIST: std::sync::OnceLock> = std::sync::OnceLock::new(); let words = PGP_WORDLIST.get_or_init(|| { // TODO: We leak the str: https://github.com/shssoichiro/zxcvbn-rs/issues/87 Wordlist::default_wordlist(2) .into_words() .map(|s| &*s.leak()) .collect::>() }); zxcvbn::zxcvbn(password, &words[..]) } } impl From for String { fn from(value: Password) -> Self { value.password } } impl AsRef for Password { fn as_ref(&self) -> &str { &self.password } } impl FromStr for Password { type Err = ParsePasswordError; fn from_str(password: &str) -> Result { let password = password.to_string(); if password.len() < 4 { Err(ParsePasswordError::TooShort { value: password.len(), required: 4, }) } else { #[cfg(feature = "entropy")] return { let entropy = Self::calculate_entropy(&password); if entropy.guesses() < 2_u64.pow(16) { return Err(ParsePasswordError::LittleEntropy { value: entropy.guesses(), required: 2_u64.pow(16), }); } Ok(Self { password, entropy }) }; #[cfg(not(feature = "entropy"))] Ok(Self { password }) } } } /// An error occurred parsing the string as a valid wormhole mailbox code #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Copy, derive_more::Display, Error)] #[non_exhaustive] pub enum ParseCodeError { /// The code is empty #[display("The code is empty")] Empty, /// A code must contain at least one '-' to separate nameplate from password #[display("A code must contain at least one '-' to separate nameplate from password")] SeparatorMissing, /// An error occurred when parsing the nameplate #[display("{_0}")] Nameplate(#[from] ParseNameplateError), /// An error occurred when parsing the code #[display("{_0}")] Password(#[from] ParsePasswordError), } /** A wormhole code à la 15-foo-bar * * The part until the first dash is called the "nameplate" and is purely numeric. * The rest is the password and may be arbitrary, although dash-joining words from * a wordlist is a common convention. */ #[derive(PartialEq, Eq, Clone, Debug, derive_more::Display, derive_more::Deref)] #[display("{}", _0)] #[cfg(not(feature = "entropy"))] pub struct Code( #[deprecated(since = "0.7.0", note = "use the std::fmt::Display implementation")] pub String, ); /** A wormhole code à la 15-foo-bar * * The part until the first dash is called the "nameplate" and is purely numeric. * The rest is the password and may be arbitrary, although dash-joining words from * a wordlist is a common convention. */ #[derive(PartialEq, Eq, Clone, Debug, derive_more::Display)] #[display("{}", _0)] #[cfg(feature = "entropy")] pub struct Code(String); #[allow(deprecated)] impl Code { /// Create a new code, comprised of a [`Nameplate`] and a password. /// /// Safety: Does not check the entropy of the password, or if one exists at all. This can be a security risk. #[deprecated( since = "0.7.2", note = "Use [`from_components`] or the [std::str::FromStr] implementation" )] #[cfg(not(feature = "entropy"))] pub fn new(nameplate: &Nameplate, password: &str) -> Self { if let Err(err) = Password::from_str(password) { tracing::error!("{err}"); } #[allow(unsafe_code)] unsafe { Self::from_components(nameplate.clone(), Password::new_unchecked(password)) } } /// Create a new code, comprised of a [`Nameplate`] and a [`Password`]. pub fn from_components(nameplate: Nameplate, password: Password) -> Self { Self(format!("{nameplate}-{password}")) } /// Split the code into nameplate and password #[deprecated(since = "0.7.2", note = "Use [Self::nameplate] and [Self::password]")] pub fn split(&self) -> (Nameplate, String) { let mut iter = self.0.splitn(2, '-'); #[allow(unsafe_code)] let nameplate = unsafe { Nameplate::new_unchecked(iter.next().unwrap()) }; let password = iter.next().unwrap(); (nameplate, password.to_string()) } /// Retrieve only the nameplate pub fn nameplate(&self) -> Nameplate { // Safety: We checked the validity of the nameplate before #[allow(unsafe_code)] unsafe { Nameplate::new_unchecked(self.0.split('-').next().unwrap()) } } /// Retrieve only the password pub fn password(&self) -> Password { // Safety: We checked the validity of the password before #[allow(unsafe_code)] unsafe { Password::new_unchecked(self.0.splitn(2, '-').last().unwrap()) } } } /// Deprecated: Use the [`std::fmt::Display`] implementation #[allow(deprecated)] impl From for String { fn from(value: Code) -> Self { value.0 } } /// Deprecated: Use the [`std::str::FromStr`] implementation /// /// Safety: Does not check the entropy of the password, or if one exists at all. This can be a security risk. #[cfg(not(feature = "entropy"))] impl From for Code { fn from(value: String) -> Self { tracing::debug!( "Implementation of From for Code is deprecated. Use the FromStr implementation instead" ); if let Err(err) = Code::from_str(&value) { tracing::error!("{err} This will be a hard error in the future."); } Self(value) } } impl FromStr for Code { type Err = ParseCodeError; fn from_str(s: &str) -> Result { match s.split_once('-') { Some((n, p)) => { let password: Password = p.parse()?; let nameplate: Nameplate = n.parse()?; Ok(Self(format!("{}-{}", nameplate, password))) }, None if s.is_empty() => Err(ParseCodeError::Empty), None => Err(ParseCodeError::SeparatorMissing), } } } /// Deprecated: Use the [`std::fmt::Display`] implementation #[allow(deprecated)] impl AsRef for Code { fn as_ref(&self) -> &str { &self.0 } } magic-wormhole-0.7.6/src/forwarding.rs000064400000000000000000001111371046102023000160530ustar 00000000000000//! Client-to-Client protocol to forward TCP connections //! //! This is a new (and still slightly experimental feature) that allows you to forward TCP connections over a wormhole //! `transit` connection. //! //! It is bound to an [`APPID`], which is distinct to the one used for file transfer. Therefore, the codes used //! for port forwarding are in an independent namespace than those for sending files. //! //! At its core, "peer messages" are exchanged over an established wormhole connection with the other side. //! They are used to set up a [`transit`] portal that will be used instead of the wormhole connection, which will be closed. //! Connections are tracked via an identifier, and multiplexed over the transit channel. The forwarding is //! "logical" and not "raw"; because "TCP in TCP" tunneling is known to be problematic. Packages are sent //! and received as they come in, no additional buffering is applied. (Under the assumption that those applications //! that need buffering already do it on their side, and those who don't, don't.) #![allow(deprecated)] use super::*; use async_std::net::{TcpListener, TcpStream}; use futures::{AsyncReadExt, AsyncWriteExt, Future, SinkExt, StreamExt, TryStreamExt}; use serde::{Deserialize, Serialize}; use std::{ borrow::Cow, collections::{HashMap, HashSet}, rc::Rc, sync::Arc, }; use transit::{TransitConnectError, TransitError}; const APPID_RAW: &str = "piegames.de/wormhole/port-forwarding"; /// The App ID associated with this protocol. pub const APPID: AppID = AppID(Cow::Borrowed(APPID_RAW)); /// An [`crate::AppConfig`] with sane defaults for this protocol. /// /// You **must not** change `id` and `rendezvous_url` to be interoperable. /// The `app_version` can be adjusted if you want to disable some features. pub const APP_CONFIG: crate::AppConfig = crate::AppConfig:: { id: AppID(Cow::Borrowed(APPID_RAW)), rendezvous_url: Cow::Borrowed(crate::rendezvous::DEFAULT_RENDEZVOUS_SERVER), app_version: AppVersion { transit_abilities: transit::Abilities::ALL_ABILITIES, other: serde_json::Value::Null, }, }; /** * The application specific version information for this protocol. */ #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct AppVersion { /// Our transit abilities pub transit_abilities: transit::Abilities, #[serde(flatten)] other: serde_json::Value, } #[derive(Debug, thiserror::Error)] #[non_exhaustive] /// An error occurred when establishing a port forwarding session pub enum ForwardingError { /// Transfer was not acknowledged by peer #[error("Transfer was not acknowledged by peer")] AckError, /// Something went wrong on the other side #[error("Something went wrong on the other side: {}", _0)] PeerError(String), /// Some deserialization went wrong, we probably got some garbage #[error("Corrupt JSON message received")] ProtocolJson( #[from] #[source] serde_json::Error, ), /// Some deserialization went wrong, we probably got some garbage #[error("Corrupt Msgpack message received")] ProtocolMsgpack( #[from] #[source] rmp_serde::decode::Error, ), /// A generic string message for "something went wrong", i.e. /// the server sent some bullshit message order #[error("Protocol error: {}", _0)] Protocol(Box), /// Unexpected message (protocol error) #[error( "Unexpected message (protocol error): Expected '{}', but got: {:?}", _0, _1 )] ProtocolUnexpectedMessage(Box, Box), /// Wormhole connection error #[error("Wormhole connection error")] Wormhole( #[from] #[source] WormholeError, ), /// Error while establishing transit connection #[error("Error while establishing transit connection")] TransitConnect( #[from] #[source] TransitConnectError, ), /// Transit error #[error("Transit error")] Transit( #[from] #[source] TransitError, ), /// I/O error #[error("I/O error")] IO( #[from] #[source] std::io::Error, ), } impl ForwardingError { fn protocol(message: impl Into>) -> Self { Self::Protocol(message.into()) } pub(self) fn unexpected_message( expected: impl Into>, got: impl std::fmt::Debug + Send + Sync + 'static, ) -> Self { Self::ProtocolUnexpectedMessage(expected.into(), Box::new(got)) } } /// Offer to forward some ports /// /// `targets` is a mapping of (host, port) pairs. If no target host is provided, then /// a local port will be forwarded (`localhost`). Forwarding remote ports only works well /// when the protocol being forwarded is not host-aware. HTTP, for example, is host aware. /// /// The port forwarding will run until an error occurs, the peer terminates the connection /// or `cancel` resolves. The last one can be used to provide timeouts or to inject CTRL-C /// handling. If you want the forward to never (successfully) stop, pass [`futures::future::pending()`] /// as the value. pub async fn serve( mut wormhole: Wormhole, transit_handler: impl FnOnce(transit::TransitInfo), relay_hints: Vec, targets: Vec<(Option, u16)>, cancel: impl Future, ) -> Result<(), ForwardingError> { assert!( !targets.is_empty(), "The list of target ports must not be empty" ); let our_version: &AppVersion = wormhole .our_version() .downcast_ref() .expect("You may only use a Wormhole instance with the correct AppVersion type!"); let peer_version: AppVersion = serde_json::from_value(wormhole.peer_version().clone())?; let connector = transit::init( our_version.transit_abilities, Some(peer_version.transit_abilities), relay_hints, ) .await?; /* Send our transit hints */ wormhole .send_json(&PeerMessage::Transit { hints: (**connector.our_hints()).clone(), }) .await?; let targets: HashMap, u16)> = targets .into_iter() .map(|(host, port)| match host { Some(host) => { if port == 80 || port == 443 || port == 8000 || port == 8080 { tracing::warn!("It seems like you are trying to forward a remote HTTP target ('{}'). Due to HTTP being host-aware this will very likely fail!", host); } (format!("{}:{}", host, port), (Some(host), port)) }, None => (port.to_string(), (host, port)), }) .collect(); /* Receive their transit hints */ let their_hints: transit::Hints = match wormhole.receive_json().await?? { PeerMessage::Transit { hints } => { tracing::debug!("Received transit message: {:?}", hints); hints }, PeerMessage::Error(err) => { bail!(ForwardingError::PeerError(err)); }, other => { let error = ForwardingError::unexpected_message("transit", other); let _ = wormhole .send_json(&PeerMessage::Error(format!("{}", error))) .await; bail!(error) }, }; let (mut transit, info) = match connector .leader_connect( wormhole.key().derive_transit_key(wormhole.appid()), peer_version.transit_abilities, Arc::new(their_hints), ) .await { Ok(transit) => transit, Err(error) => { let error = ForwardingError::TransitConnect(error); let _ = wormhole .send_json(&PeerMessage::Error(format!("{}", error))) .await; return Err(error); }, }; transit_handler(info); /* We got a transit, now close the Wormhole */ wormhole.close().await?; transit .send_record( &PeerMessage::Offer { addresses: targets.keys().cloned().collect(), } .ser_msgpack(), ) .await?; let (backchannel_tx, backchannel_rx) = futures::channel::mpsc::channel::<(u64, Option>)>(20); let (transit_tx, transit_rx) = transit.split(); let transit_rx = transit_rx.fuse(); use futures::future::FutureExt; let cancel = cancel.fuse(); futures::pin_mut!(transit_tx); futures::pin_mut!(transit_rx); futures::pin_mut!(cancel); /* Main processing loop. Catch errors */ let result = ForwardingServe { targets, connections: HashMap::new(), historic_connections: HashSet::new(), backchannel_tx, backchannel_rx, } .run(&mut transit_tx, &mut transit_rx, &mut cancel) .await; /* If the error is not a PeerError (i.e. coming from the other side), try notifying the other side before quitting. */ match result { Ok(()) => Ok(()), Err(error @ ForwardingError::PeerError(_)) => Err(error), Err(error) => { let _ = transit_tx .send( PeerMessage::Error(format!("{}", error)) .ser_msgpack() .into_boxed_slice(), ) .await; Err(error) }, } } struct ForwardingServe { targets: HashMap, u16)>, /* self => remote */ connections: HashMap< u64, ( async_std::task::JoinHandle<()>, futures::io::WriteHalf, ), >, /* Track old connection IDs that won't be reused again. This is to distinguish race hazards where * one side closes a connection while the other one accesses it simultaneously. Despite the name, the * set also includes connections that are currently live. */ historic_connections: HashSet, /* remote => self. (connection_id, Some=payload or None=close) */ backchannel_tx: futures::channel::mpsc::Sender<(u64, Option>)>, backchannel_rx: futures::channel::mpsc::Receiver<(u64, Option>)>, } //futures::pin_mut!(backchannel_rx); impl ForwardingServe { async fn forward( &mut self, transit_tx: &mut (impl futures::sink::Sink, Error = TransitError> + Unpin), connection_id: u64, payload: &[u8], ) -> Result<(), ForwardingError> { tracing::debug!("Forwarding {} bytes from #{}", payload.len(), connection_id); match self.connections.get_mut(&connection_id) { Some((_worker, connection)) => { /* On an error, log for the user and then terminate that connection */ if let Err(e) = connection.write_all(payload).await { tracing::warn!("Forwarding to #{} failed: {}", connection_id, e); self.remove_connection(transit_tx, connection_id, true) .await?; } }, None if !self.historic_connections.contains(&connection_id) => { bail!(ForwardingError::protocol(format!( "Connection '{}' not found", connection_id ))); }, None => { /* Race hazard. Do nothing. */ }, } Ok(()) } async fn remove_connection( &mut self, transit_tx: &mut (impl futures::sink::Sink, Error = TransitError> + Unpin), connection_id: u64, tell_peer: bool, ) -> Result<(), ForwardingError> { tracing::debug!("Removing connection: #{}", connection_id); if tell_peer { transit_tx .send( PeerMessage::Disconnect { connection_id } .ser_msgpack() .into_boxed_slice(), ) .await?; } match self.connections.remove(&connection_id) { Some((worker, _connection)) => { worker.cancel().await; }, None if !self.historic_connections.contains(&connection_id) => { bail!(ForwardingError::protocol(format!( "Connection '{}' not found", connection_id ))); }, None => { /* Race hazard. Do nothing. */ }, } Ok(()) } async fn spawn_connection( &mut self, transit_tx: &mut (impl futures::sink::Sink, Error = TransitError> + Unpin), mut target: String, connection_id: u64, ) -> Result<(), ForwardingError> { tracing::debug!("Creating new connection: #{} -> {}", connection_id, target); use std::collections::hash_map::Entry; let entry = match self.connections.entry(connection_id) { Entry::Vacant(entry) => entry, Entry::Occupied(_) => { bail!(ForwardingError::protocol(format!( "Connection '{}' already exists", connection_id ))); }, }; let (host, port) = self.targets.get(&target).unwrap(); if host.is_none() { target = format!("[::1]:{}", port); } let stream = match TcpStream::connect(&target).await { Ok(stream) => stream, Err(err) => { tracing::warn!( "Cannot open connection to {}: {}. The forwarded service might be down.", target, err ); transit_tx .send( PeerMessage::Disconnect { connection_id } .ser_msgpack() .into_boxed_slice(), ) .await?; return Ok(()); }, }; let (mut connection_rd, connection_wr) = stream.split(); let mut backchannel_tx = self.backchannel_tx.clone(); let worker = async_std::task::spawn_local(async move { let mut buffer = vec![0; 4096]; /* Ignore errors */ macro_rules! break_on_err { ($expr:expr) => { match $expr { Ok(val) => val, Err(_) => break, } }; } #[allow(clippy::while_let_loop)] loop { let read = break_on_err!(connection_rd.read(&mut buffer).await); if read == 0 { break; } let buffer = &buffer[..read]; break_on_err!( backchannel_tx .send((connection_id, Some(buffer.to_vec()))) .await ); } /* Close connection (maybe or not because of error) */ let _ = backchannel_tx.send((connection_id, None)).await; backchannel_tx.disconnect(); }); entry.insert((worker, connection_wr)); Ok(()) } async fn shutdown(self) { tracing::debug!("Shutting down everything"); for (worker, _connection) in self.connections.into_values() { worker.cancel().await; } } async fn run( mut self, transit_tx: &mut (impl futures::sink::Sink, Error = TransitError> + Unpin), transit_rx: &mut (impl futures::stream::FusedStream, TransitError>> + Unpin), cancel: &mut (impl futures::future::FusedFuture + Unpin), ) -> Result<(), ForwardingError> { /* Event processing loop */ tracing::debug!("Entered processing loop"); let ret = loop { futures::select! { message = transit_rx.next() => { match PeerMessage::de_msgpack(&message.unwrap()?)? { PeerMessage::Forward { connection_id, payload } => { self.forward(transit_tx, connection_id, &payload).await? }, PeerMessage::Connect { target, connection_id } => { /* No matter what happens, as soon as we receive the "connect" command that ID is burned. */ self.historic_connections.insert(connection_id); ensure!( self.targets.contains_key(&target), ForwardingError::protocol(format!("We don't know forwarding target '{}'", target)), ); self.spawn_connection(transit_tx, target, connection_id).await?; }, PeerMessage::Disconnect { connection_id } => { self.remove_connection(transit_tx, connection_id, false).await?; }, PeerMessage::Close => { tracing::info!("Peer gracefully closed connection"); self.shutdown().await; break Ok(()); }, PeerMessage::Error(err) => { self.shutdown().await; bail!(ForwardingError::PeerError(err)); }, other => { self.shutdown().await; bail!(ForwardingError::unexpected_message("connect' or 'disconnect' or 'forward' or 'close", other)); }, } }, message = self.backchannel_rx.next() => { /* This channel will never run dry, since we always have at least one sender active */ match message.unwrap() { (connection_id, Some(payload)) => { transit_tx.send( PeerMessage::Forward { connection_id, payload } .ser_msgpack() .into_boxed_slice() ).await?; }, (connection_id, None) => { self.remove_connection(transit_tx, connection_id, true).await?; }, } }, /* We are done */ () = &mut *cancel => { tracing::info!("Closing connection"); transit_tx.send( PeerMessage::Close.ser_msgpack() .into_boxed_slice() ) .await?; transit_tx.close().await?; self.shutdown().await; break Ok(()); }, } }; tracing::debug!("Exited processing loop"); ret } } /// Request a port forwarding offer from the other side /// /// You can optionally specify a `bind_address` where the port forwarding /// will be made available. You can also specify a list of `custom_ports` that /// will be used for the forwarding. The mapping between custom ports and forwarded /// targets is 1:1 and order preserving. If more ports are forwarded than custom /// ports were specified, then the remaining ports will be arbitrary. /// /// The method returns a [`ConnectOffer`] from which the resulting port mapping can /// be queried. That struct also has an `accept` and `reject` method, of which one /// must be used. /// /// This method already binds to all the necessary ports up-front. To limit abuse potential /// no more than 1024 ports may be forwarded at once. pub async fn connect( mut wormhole: Wormhole, transit_handler: impl FnOnce(transit::TransitInfo), relay_hints: Vec, bind_address: Option, custom_ports: &[u16], ) -> Result { let our_version: &AppVersion = wormhole .our_version() .downcast_ref() .expect("You may only use a Wormhole instance with the correct AppVersion type!"); let peer_version: AppVersion = serde_json::from_value(wormhole.peer_version().clone())?; let connector = transit::init( our_version.transit_abilities, Some(peer_version.transit_abilities), relay_hints, ) .await?; let bind_address = bind_address.unwrap_or_else(|| std::net::IpAddr::V6("::".parse().unwrap())); /* Send our transit hints */ wormhole .send_json(&PeerMessage::Transit { hints: (**connector.our_hints()).clone(), }) .await?; /* Receive their transit hints */ let their_hints: transit::Hints = match wormhole.receive_json().await?? { PeerMessage::Transit { hints } => { tracing::debug!("Received transit message: {:?}", hints); hints }, PeerMessage::Error(err) => { bail!(ForwardingError::PeerError(err)); }, other => { let error = ForwardingError::unexpected_message("transit", other); let _ = wormhole .send_json(&PeerMessage::Error(format!("{}", error))) .await; bail!(error) }, }; let (mut transit, info) = match connector .follower_connect( wormhole.key().derive_transit_key(wormhole.appid()), peer_version.transit_abilities, Arc::new(their_hints), ) .await { Ok(transit) => transit, Err(error) => { let error = ForwardingError::TransitConnect(error); let _ = wormhole .send_json(&PeerMessage::Error(format!("{}", error))) .await; return Err(error); }, }; transit_handler(info); /* We got a transit, now close the Wormhole */ wormhole.close().await?; let run = async { /* Receive offer and ask user */ let addresses = match PeerMessage::de_msgpack(&transit.receive_record().await?)? { PeerMessage::Offer { addresses } => addresses, PeerMessage::Error(err) => { bail!(ForwardingError::PeerError(err)); }, other => { bail!(ForwardingError::unexpected_message("offer", other)) }, }; /* Sanity check on untrusted input */ if addresses.len() > 1024 { return Err(ForwardingError::protocol("Too many forwarded ports")); } /* self => remote * (address, connection) * Vec> */ let listeners: Vec<( async_std::net::TcpListener, u16, std::rc::Rc, )> = futures::stream::iter( addresses .into_iter() .map(Rc::new) .zip(custom_ports.iter().copied().chain(std::iter::repeat(0))), ) .then(|(address, port)| async move { let connection = TcpListener::bind((bind_address, port)).await?; let port = connection.local_addr()?.port(); Result::<_, std::io::Error>::Ok((connection, port, address)) }) .try_collect() .await?; Ok(listeners) }; match run.await { Ok(listeners) => Ok(ConnectOffer { transit, mapping: listeners.iter().map(|(_, b, c)| (*b, c.clone())).collect(), listeners, }), Err(error @ ForwardingError::PeerError(_)) => Err(error), Err(error) => { let _ = transit .send_record(&PeerMessage::Error(format!("{}", error)).ser_msgpack()) .await; Err(error) }, } } /// A pending forwarding offer from the other side /// /// You *should* consume this object, either by calling [`accept`](ConnectOffer::accept) or [`reject`](ConnectOffer::reject). #[must_use] pub struct ConnectOffer { /// The offered port mapping pub mapping: Vec<(u16, Rc)>, transit: transit::Transit, listeners: Vec<( async_std::net::TcpListener, u16, std::rc::Rc, )>, } impl ConnectOffer { /// Accept the offer and start the forwarding /// /// The method will run until an error occurs, the peer terminates the connection /// or `cancel` resolves. The last one can be used to provide timeouts or to inject CTRL-C /// handling. If you want the forward to never (successfully) stop, pass [`futures::future::pending()`] /// as the value. pub async fn accept(self, cancel: impl Future) -> Result<(), ForwardingError> { let (transit_tx, transit_rx) = self.transit.split(); let transit_rx = transit_rx.fuse(); use futures::FutureExt; let cancel = cancel.fuse(); futures::pin_mut!(transit_tx); futures::pin_mut!(transit_rx); futures::pin_mut!(cancel); /* Error handling catcher (see below) */ let run = async { let (backchannel_tx, backchannel_rx) = futures::channel::mpsc::channel::<(u64, Option>)>(20); ForwardConnect { incoming: futures::stream::select_all(self.listeners.into_iter().map( |(connection, _, address)| { connection .into_incoming() .map_ok(move |stream| (address.clone(), stream)) .boxed_local() }, )), connection_counter: 0, connections: HashMap::new(), backchannel_tx, backchannel_rx, } .run(&mut transit_tx, &mut transit_rx, &mut cancel) .await }; match run.await { Ok(()) => Ok(()), Err(error @ ForwardingError::PeerError(_)) => Err(error), Err(error) => { let _ = transit_tx .send( PeerMessage::Error(format!("{}", error)) .ser_msgpack() .into_boxed_slice(), ) .await; Err(error) }, } } /// Reject the offer /// /// This will send an error message to the other side so that it knows the transfer failed. pub async fn reject(mut self) -> Result<(), ForwardingError> { self.transit .send_record(&PeerMessage::Error("transfer rejected".into()).ser_msgpack()) .await?; Ok(()) } } #[allow(clippy::type_complexity)] struct ForwardConnect { //transit: &'a mut transit::Transit, /* when can I finally store an `impl Trait` in a struct? */ incoming: futures::stream::SelectAll< futures::stream::LocalBoxStream< 'static, Result<(Rc, async_std::net::TcpStream), std::io::Error>, >, >, /* Our next unique connection_id */ connection_counter: u64, connections: HashMap< u64, ( async_std::task::JoinHandle<()>, futures::io::WriteHalf, ), >, /* application => self. (connection_id, Some=payload or None=close) */ backchannel_tx: futures::channel::mpsc::Sender<(u64, Option>)>, backchannel_rx: futures::channel::mpsc::Receiver<(u64, Option>)>, } impl ForwardConnect { async fn forward( &mut self, transit_tx: &mut (impl futures::sink::Sink, Error = TransitError> + Unpin), connection_id: u64, payload: &[u8], ) -> Result<(), ForwardingError> { tracing::debug!("Forwarding {} bytes from #{}", payload.len(), connection_id); match self.connections.get_mut(&connection_id) { Some((_worker, connection)) => { /* On an error, log for the user and then terminate that connection */ if let Err(e) = connection.write_all(payload).await { tracing::warn!("Forwarding to #{} failed: {}", connection_id, e); self.remove_connection(transit_tx, connection_id, true) .await?; } }, None if self.connection_counter <= connection_id => { bail!(ForwardingError::protocol(format!( "Connection '{}' not found", connection_id ))); }, None => { /* Race hazard. Do nothing. */ }, } Ok(()) } async fn remove_connection( &mut self, transit_tx: &mut (impl futures::sink::Sink, Error = TransitError> + Unpin), connection_id: u64, tell_peer: bool, ) -> Result<(), ForwardingError> { tracing::debug!("Removing connection: #{}", connection_id); if tell_peer { transit_tx .send( PeerMessage::Disconnect { connection_id } .ser_msgpack() .into_boxed_slice(), ) .await?; } match self.connections.remove(&connection_id) { Some((worker, _connection)) => { worker.cancel().await; }, None if connection_id >= self.connection_counter => { bail!(ForwardingError::protocol(format!( "Connection '{}' not found", connection_id ))); }, None => { /* Race hazard. Do nothing. */ }, } Ok(()) } async fn spawn_connection( &mut self, transit_tx: &mut (impl futures::sink::Sink, Error = TransitError> + Unpin), target: Rc, connection: TcpStream, ) -> Result<(), ForwardingError> { let connection_id = self.connection_counter; self.connection_counter += 1; let (mut connection_rd, connection_wr) = connection.split(); let mut backchannel_tx = self.backchannel_tx.clone(); tracing::debug!("Creating new connection: #{} -> {}", connection_id, target); transit_tx .send( PeerMessage::Connect { target: (*target).clone(), connection_id, } .ser_msgpack() .into_boxed_slice(), ) .await?; let worker = async_std::task::spawn_local(async move { let mut buffer = vec![0; 4096]; /* Ignore errors */ macro_rules! break_on_err { ($expr:expr) => { match $expr { Ok(val) => val, Err(_) => break, } }; } #[allow(clippy::while_let_loop)] loop { let read = break_on_err!(connection_rd.read(&mut buffer).await); if read == 0 { break; } let buffer = &buffer[..read]; break_on_err!( backchannel_tx .send((connection_id, Some(buffer.to_vec()))) .await ); } /* Close connection (maybe or not because of error) */ let _ = backchannel_tx.send((connection_id, None)).await; backchannel_tx.disconnect(); }); self.connections .insert(connection_id, (worker, connection_wr)); Ok(()) } async fn shutdown(self) { tracing::debug!("Shutting down everything"); for (worker, _connection) in self.connections.into_values() { worker.cancel().await; } } async fn run( mut self, transit_tx: &mut (impl futures::sink::Sink, Error = TransitError> + Unpin), transit_rx: &mut (impl futures::stream::FusedStream, TransitError>> + Unpin), cancel: &mut (impl futures::future::FusedFuture + Unpin), ) -> Result<(), ForwardingError> { /* Event processing loop */ tracing::debug!("Entered processing loop"); let ret = loop { futures::select! { message = transit_rx.next() => { match PeerMessage::de_msgpack(&message.unwrap()?)? { PeerMessage::Forward { connection_id, payload } => { self.forward(transit_tx, connection_id, &payload).await?; }, PeerMessage::Disconnect { connection_id } => { self.remove_connection(transit_tx, connection_id, false).await?; }, PeerMessage::Close => { tracing::info!("Peer gracefully closed connection"); self.shutdown().await; break Ok(()) }, PeerMessage::Error(err) => { for (worker, _connection) in self.connections.into_values() { worker.cancel().await; } bail!(ForwardingError::PeerError(err)); }, other => { self.shutdown().await; bail!(ForwardingError::unexpected_message("connect' or 'disconnect' or 'forward' or 'close", other)); }, } }, message = self.backchannel_rx.next() => { /* This channel will never run dry, since we always have at least one sender active */ match message.unwrap() { (connection_id, Some(payload)) => { transit_tx.send( PeerMessage::Forward { connection_id, payload }.ser_msgpack() .into_boxed_slice() ) .await?; }, (connection_id, None) => { self.remove_connection(transit_tx, connection_id, true).await?; }, } }, connection = self.incoming.next() => { let (target, connection): (Rc, TcpStream) = connection.unwrap()?; self.spawn_connection(transit_tx, target, connection).await?; }, /* We are done */ () = &mut *cancel => { tracing::info!("Closing connection"); transit_tx.send( PeerMessage::Close.ser_msgpack() .into_boxed_slice() ) .await?; transit_tx.close().await?; self.shutdown().await; break Ok(()); }, } }; tracing::debug!("Exited processing loop"); ret } } /** Serialization struct for this protocol */ #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "kebab-case")] #[non_exhaustive] enum PeerMessage { /** Offer some destinations to be forwarded to. * forwarder -> forwardee only */ Offer { addresses: Vec }, /** Forward a new connection. * forwardee -> forwarder only */ Connect { target: String, connection_id: u64 }, /** End a forwarded connection. * Any direction. Errors or the reason why the connection is closed * are not forwarded. */ Disconnect { connection_id: u64 }, /** Forward some bytes for a connection. */ Forward { connection_id: u64, payload: Vec, }, /** Close the whole session */ Close, /** Tell the other side you got an error */ Error(String), /** Used to set up a transit channel */ Transit { hints: transit::Hints }, #[serde(other)] Unknown, } impl PeerMessage { #[allow(dead_code)] pub fn ser_msgpack(&self) -> Vec { let mut writer = Vec::with_capacity(128); let mut ser = rmp_serde::encode::Serializer::new(&mut writer) .with_struct_map() .with_human_readable(); serde::Serialize::serialize(self, &mut ser).unwrap(); writer } #[allow(dead_code)] pub fn de_msgpack(data: &[u8]) -> Result { rmp_serde::from_read(&mut &*data) } } magic-wormhole-0.7.6/src/lib.rs000064400000000000000000000045521046102023000144610ustar 00000000000000//! In reality, there is no one "Magic Wormhole" protocol. What makes Wormhole work is a handful of different protocols //! and handshakes, layered on another and weaved together. This allows other applications to build upon the parts they want //! and then add new ones special to their needs. //! //! At the core, there is a rendezvous server with a message box that allows clients to connect to and perform a PAKE. //! Protocol wise, this is split into the "client-server" part (connect to a server, allocate nameplates, send and receive messages) //! and a "client-client" part (do a key exchange). //! //! Two clients that are connected to each other need to know beforehand how to communicate with each other once the connection is established. //! This why they have an [`AppID`]. The protocol they use to talk to each other is bound to the AppID. Clients with different AppIDs cannot communicate. //! //! Magic Wormhole is known for its ability to transfer files. This is implemented in the [`transfer`] module, which builds upon the wormhole //! protocol and thus requires a [`Wormhole`]. //! //! As an alternative to file transfer, there is the [`forwarding`] module, which allows to forward arbitrary TCP connections over the Wormhole/Transit tunnel. //! //! Transferring large amounts of data should not be done over the rendezvous server. Instead, you have to set up a [`transit`] //! connection. A transit is little more than an encrypted TcpConnection. If a direct connection between both clients is not possible, //! a relay server will transparently connect them together. Transit is used by the file transfer for example, but any other AppID protocol //! might make use of it as well. #![deny(unsafe_code)] #![allow(clippy::upper_case_acronyms)] #![allow(clippy::too_many_arguments)] #![allow(unused_macros)] #![warn(missing_docs)] #[macro_use] mod util; mod core; #[cfg(feature = "forwarding")] pub mod forwarding; #[cfg(feature = "transfer")] pub mod transfer; #[cfg(feature = "transit")] pub mod transit; #[cfg(feature = "transfer")] pub mod uri; #[allow(deprecated)] pub use crate::core::{ key::{GenericKey, Key, KeyPurpose, WormholeKey}, rendezvous, AppConfig, AppID, Code, MailboxConnection, Mood, Nameplate, ParseCodeError, ParseNameplateError, ParsePasswordError, Password, Wormhole, WormholeError, WormholeWelcome, }; #[doc(hidden)] pub use core::wordlist::Wordlist; magic-wormhole-0.7.6/src/transfer/cancel.rs000064400000000000000000000272261046102023000167670ustar 00000000000000/// Various helpers to deal with closing connections and cancellation use super::*; /// A weird mixture of [`futures::future::Abortable`], [`async_std::sync::Condvar`] and [`futures::future::Select`] tailored to our Ctrl+C handling. /// /// At it's core, it is an `Abortable` but instead of having an `AbortHandle`, we use a future that resolves as trigger. /// Under the hood, it is implementing the same functionality as a `select`, but mapping one of the outcomes to an error type. pub async fn cancellable( future: impl Future + Unpin, cancel: impl Future, ) -> Result { use futures::future::Either; futures::pin_mut!(cancel); match futures::future::select(cancel, future).await { Either::Left(((), _)) => Err(Cancelled), Either::Right((val, _)) => Ok(val), } } /** Like `cancellable`, but you'll get back the cancellation future in case the code terminates for future use */ pub async fn cancellable_2 + Unpin>( future: impl Future + Unpin, cancel: C, ) -> Result<(T, C), Cancelled> { use futures::future::Either; match futures::future::select(cancel, future).await { Either::Left(((), _)) => Err(Cancelled), Either::Right((val, cancel)) => Ok((val, cancel)), } } /// Indicator that the [`Cancellable`] task was cancelled. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Cancelled; impl std::fmt::Display for Cancelled { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Task has been cancelled") } } /// Maximum duration that we are willing to wait for cleanup tasks to finish const SHUTDOWN_TIME: std::time::Duration = std::time::Duration::from_secs(5); // TODO make function once possible (Rust language limitations etc.) macro_rules! with_cancel_wormhole { ($wormhole:ident, run = $run:expr, $cancel:expr, ret_cancel = $ret_cancel:expr $(,)?) => {{ let run = Box::pin($run); let result = cancel::cancellable_2(run, $cancel).await; let Some((transit, wormhole, cancel)) = cancel::handle_run_result_noclose($wormhole, result).await? else { return Ok($ret_cancel); }; (transit, wormhole, cancel) }}; } // Make macro public #[cfg(feature = "experimental-transfer-v2")] pub(super) use with_cancel_wormhole; // Rustfmt has a bug where it will indent a few lines again and again and again and again and again anda #[rustfmt::skip] macro_rules! with_cancel_transit { ($transit:ident, run = $run:expr, $cancel:expr, $make_error_message:expr, $parse_message:expr, ret_cancel = $ret_cancel:expr $(,)?) => {{ let run = Box::pin($run); let result = cancel::cancellable_2(run, $cancel).await; let Some((value, transit)) = cancel::handle_run_result_transit( $transit, result, $make_error_message, $parse_message, ).await? else { return Ok($ret_cancel); }; (value, transit) }}; } // Make macro public #[cfg(feature = "experimental-transfer-v2")] pub(super) use with_cancel_transit; /// Run a future with timeout and cancellation, ignore errors async fn wrap_timeout(run: impl Future, cancel: impl Future) { let run = async_std::future::timeout(SHUTDOWN_TIME, run); futures::pin_mut!(run); match cancellable(run, cancel).await { Ok(Ok(())) => {}, Ok(Err(_timeout)) => tracing::debug!("Post-transfer timed out"), Err(_cancelled) => tracing::debug!("Post-transfer got cancelled by user"), }; } /// Ignore an error but at least debug print it fn debug_err(result: Result<(), impl std::fmt::Display>, operation: &str) { if let Err(error) = result { tracing::debug!("Failed to {} after transfer: {}", operation, error); } } /** Handle the post-{transfer, failure, cancellation} logic, then close the Wormhole */ pub async fn handle_run_result( wormhole: Wormhole, result: Result<(Result<(), TransferError>, impl Future), Cancelled>, ) -> Result<(), TransferError> { match handle_run_result_noclose(wormhole, result).await { Ok(Some(((), wormhole, cancel))) => { /* Happy case: everything went okay. Now close the wormholhe */ tracing::debug!("Transfer done, doing cleanup logic"); wrap_timeout( async { debug_err(wormhole.close().await, "close Wormhole"); }, cancel, ) .await; Ok(()) }, Ok(None) => Ok(()), Err(e) => Err(e), } } /** Handle the post-{transfer, failure, cancellation} logic */ pub async fn handle_run_result_noclose>( mut wormhole: Wormhole, result: Result<(Result, C), Cancelled>, ) -> Result, TransferError> { match result { /* Happy case: everything went okay */ Ok((Ok(val), cancel)) => Ok(Some((val, wormhole, cancel))), /* Got peer error: stop everything immediately */ Ok((Err(error @ TransferError::PeerError(_)), cancel)) => { tracing::debug!( "Transfer encountered an error ({}), doing cleanup logic", error ); wrap_timeout( async { debug_err(wormhole.close().await, "close Wormhole"); }, cancel, ) .await; Err(error) }, /* Got transit error: try to receive peer error for better error message */ Ok((Err(mut error @ TransferError::Transit(_)), cancel)) => { tracing::debug!( "Transfer encountered an error ({}), doing cleanup logic", error ); wrap_timeout(async { /* If transit failed, ask for a proper error and potentially use that instead */ // TODO this should be replaced with some try_receive that only polls already available messages, // and we should not only look for the next one but all have been received // and we should not interrupt a receive operation without making sure it leaves the connection // in a consistent state, otherwise the shutdown may cause protocol errors if let Ok(Ok(Ok(PeerMessage::Error(e)))) = async_std::future::timeout(SHUTDOWN_TIME / 3, wormhole.receive_json()).await { error = TransferError::PeerError(e); } else { tracing::debug!("Failed to retrieve more specific error message from peer. Maybe it crashed?"); } debug_err(wormhole.close().await, "close Wormhole"); }, cancel).await; Err(error) }, /* Other error: try to notify peer */ Ok((Err(error), cancel)) => { tracing::debug!( "Transfer encountered an error ({}), doing cleanup logic", error ); wrap_timeout( async { debug_err( wormhole .send_json(&PeerMessage::Error(format!("{}", error))) .await, "notify peer about the error", ); debug_err(wormhole.close().await, "close Wormhole"); }, cancel, ) .await; Err(error) }, /* Cancelled: try to notify peer */ Err(cancelled) => { tracing::debug!("Transfer got cancelled, doing cleanup logic"); /* Replace cancel with ever-pending future, as we have already been cancelled */ wrap_timeout( async { debug_err( wormhole .send_json(&PeerMessage::Error(format!("{}", cancelled))) .await, "notify peer about our cancellation", ); debug_err(wormhole.close().await, "close Wormhole"); }, futures::future::pending(), ) .await; Ok(None) }, } } /** * Handle the post-{transfer, failure, cancellation} logic where the error signaling is done over the transit channel */ #[cfg(feature = "experimental-transfer-v2")] pub async fn handle_run_result_transit( mut transit: transit::Transit, result: Result<(Result, impl Future), Cancelled>, make_error_message: impl FnOnce(&(dyn std::string::ToString + Sync)) -> Vec, parse_message: impl Fn(&[u8]) -> Result, TransferError>, ) -> Result, TransferError> { match result { /* Happy case: everything went okay */ Ok((Ok(val), _cancel)) => Ok(Some((val, transit))), /* Got peer error: stop everything immediately */ Ok((Err(error @ TransferError::PeerError(_)), _cancel)) => { tracing::debug!( "Transfer encountered an error ({}), doing cleanup logic", error ); Err(error) }, /* Got transit error: try to receive peer error for better error message */ Ok((Err(mut error @ TransferError::Transit(_)), cancel)) => { tracing::debug!( "Transfer encountered an error ({}), doing cleanup logic", error ); wrap_timeout( async { /* Receive one peer message to see if they sent some error prior to closing * (Note that this will only happen if we noticed the closed connection while trying to send, * otherwise receiving will already yield the error message). */ loop { let Ok(msg) = transit.receive_record().await else { break; }; match parse_message(&msg) { Ok(None) => continue, Ok(Some(err)) => { error = TransferError::PeerError(err); break; }, Err(_) => break, } } }, cancel, ) .await; Err(error) }, /* Other error: try to notify peer */ Ok((Err(error), cancel)) => { tracing::debug!( "Transfer encountered an error ({}), doing cleanup logic", error ); wrap_timeout( async { debug_err( transit.send_record(&make_error_message(&error)).await, "notify peer about the error", ); }, cancel, ) .await; Err(error) }, /* Cancelled: try to notify peer */ Err(cancelled) => { tracing::debug!("Transfer got cancelled, doing cleanup logic"); /* Replace cancel with ever-pending future, as we have already been cancelled */ wrap_timeout( async { debug_err( transit.send_record(&make_error_message(&cancelled)).await, "notify peer about our cancellation", ); }, futures::future::pending(), ) .await; Ok(None) }, } } magic-wormhole-0.7.6/src/transfer/new_api.rs000064400000000000000000000000001046102023000171410ustar 00000000000000magic-wormhole-0.7.6/src/transfer/offer.rs000064400000000000000000000435141046102023000166410ustar 00000000000000use std::collections::BTreeMap; #[cfg(not(target_family = "wasm"))] use std::path::{Path, PathBuf}; use futures::{AsyncRead, AsyncSeek, AsyncWrite, Future}; use serde::{Deserialize, Serialize}; pub type OfferSend = Offer; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(bound(deserialize = "T: Default"))] pub struct Offer { pub(super) content: BTreeMap>, } impl OfferSend { /// Offer a single path (file or folder) #[cfg(not(target_family = "wasm"))] pub async fn new_file_or_folder( offer_name: String, path: impl AsRef, ) -> std::io::Result { let path = path.as_ref(); tracing::trace!( "OfferSend::new_file_or_folder: {offer_name}, {}", path.display() ); let mut content = BTreeMap::new(); content.insert(offer_name, OfferSendEntry::new(path).await?); Ok(Self { content }) } /// Offer list of paths (files and folders) /// Panics if any of the paths does not have a name (like `/`). /// Panics if any two or more of the paths have the same name. #[cfg(not(target_family = "wasm"))] pub async fn new_paths(paths: impl IntoIterator) -> std::io::Result { let mut content = BTreeMap::new(); for path in paths { let offer_name = path.file_name().expect("Path must have a name"); let offer_name = offer_name .to_str() .ok_or_else(|| { std::io::Error::new( std::io::ErrorKind::Other, format!( "{} is not UTF-8 encoded", (offer_name.as_ref() as &Path).display() ), ) })? .to_owned(); let old = content.insert(offer_name, OfferSendEntry::new(path).await?); assert!(old.is_none(), "Duplicate names found"); } Ok(Self { content }) } /// Offer a single file with custom content /// /// You must ensure that the Reader contains exactly as many bytes /// as advertized in file_size. pub fn new_file_custom(offer_name: String, size: u64, content: OfferContent) -> Self { let mut content_ = BTreeMap::new(); content_.insert(offer_name, OfferSendEntry::RegularFile { size, content }); Self { content: content_ } } } impl Offer { pub fn top_level_paths(&self) -> impl Iterator + '_ { self.content.keys() } pub fn get(&self, path: &[String]) -> Option<&OfferEntry> { match path { [] => None, [start, rest @ ..] => self.content.get(start).and_then(|inner| inner.get(rest)), } } pub fn get_file(&self, path: &[String]) -> Option<(&T, u64)> { match path { [] => None, [start, rest @ ..] => self .content .get(start) .and_then(|inner| inner.get_file(rest)), } } /** Recursively list all file paths, without directory names or symlinks. */ pub fn iter_file_paths(&self) -> impl Iterator> + '_ { self.iter_files().map(|val| val.0) } /** Recursively list all files, without directory names or symlinks. */ pub fn iter_files(&self) -> impl Iterator, &T, u64)> + '_ { self.content.iter().flat_map(|(name, offer)| { let name = name.clone(); offer.iter_files().map(move |mut val| { val.0.insert(0, name.clone()); val }) }) } pub fn total_size(&self) -> u64 { self.iter_files().map(|v| v.2).sum() } #[cfg(not(target_family = "wasm"))] pub fn accept_all(&self, target_dir: &Path) -> OfferAccept { self.set_content(|path| { let full_path: PathBuf = target_dir.join(path.join("/")); let content = new_accept_content(move |append| { let full_path = full_path.clone(); async_std::fs::OpenOptions::new() .write(true) .create(true) .append(append) .truncate(!append) .open(full_path) }); AcceptInner { content: Box::new(content) as _, offset: 0, sha256: None, } }) } #[cfg(not(target_family = "wasm"))] pub async fn create_directories(&self, target_path: &Path) -> std::io::Result<()> { // TODO this could be made more efficient by passing around just one buffer for (name, file) in &self.content { file.create_directories(&target_path.join(name)).await?; } Ok(()) } // #[cfg(not(target_family = "wasm"))] // pub async fn create_symlinks(&self, target_path: &Path) -> std::io::Result<()> { // // TODO this could be made more efficient by passing around just one buffer // for (name, file) in &self.content { // file.create_symlinks(&target_path.join(name)).await?; // } // Ok(()) // } pub fn offer_name(&self) -> String { let (name, entry) = self.content.iter().next().unwrap(); if self.is_multiple() { format!( "{name} and {} other files or directories", self.content.len() - 1 ) } else if self.is_directory() { let count = entry.iter_files().count(); format!("{name} with {count} files inside") } else { name.clone() } } pub fn is_multiple(&self) -> bool { self.content.len() > 1 } pub fn is_directory(&self) -> bool { self.is_multiple() || self .content .values() .any(|f| matches!(f, OfferEntry::Directory { .. })) } pub fn set_content(&self, mut f: impl FnMut(&[String]) -> U) -> Offer { Offer { content: self .content .iter() .map(|(k, v)| (k.clone(), v.set_content(&mut vec![k.clone()], &mut f))) .collect(), } } } impl Offer { /** Recursively list all files, without directory names or symlinks. */ pub fn into_iter_files(self) -> impl Iterator, T, u64)> + Send { self.content.into_iter().flat_map(|(name, offer)| { offer.into_iter_files().map(move |mut val| { val.0.insert(0, name.clone()); val }) }) } } impl From<&Offer> for Offer { fn from(from: &Offer) -> Self { from.set_content(|_| ()) } } pub trait AsyncReadSeek: AsyncRead + AsyncSeek {} impl AsyncReadSeek for T where T: AsyncRead + AsyncSeek {} /// The signature is basically just `() -> io::Result`, but in async /// /// This may be called multiple times during the send process, an imlementations that generate their /// output dynamically must ensure all invocations produce the same result — independently of each other /// (things may be concurrent). pub type OfferContent = Box< dyn Fn() -> futures::future::BoxFuture< 'static, std::io::Result>, > + Send, >; pub fn new_offer_content(content_provider: F) -> OfferContent where F: Fn() -> G + Send + 'static, G: Future> + Send + 'static, H: AsyncReadSeek + Unpin + Send + 'static, { let wrap_fun = move || { use futures::TryFutureExt; let fut = content_provider(); let wrap_fut = fut.map_ok(|read| Box::new(read) as Box); Box::pin(wrap_fut) as futures::future::BoxFuture<'static, _> }; Box::new(wrap_fun) as _ } pub type OfferSendEntry = OfferEntry; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] #[serde(tag = "type")] #[serde(bound(deserialize = "T: Default"))] pub enum OfferEntry { RegularFile { size: u64, #[serde(skip)] content: T, }, Directory { content: BTreeMap, }, // Symlink { // target: String, // }, } impl OfferSendEntry { #[cfg(not(target_family = "wasm"))] pub(super) async fn new(path: impl AsRef) -> std::io::Result { // Workaround for https://github.com/rust-lang/rust/issues/78649 #[inline(always)] fn new_recurse<'a>( path: impl AsRef + 'a + Send, ) -> futures::future::BoxFuture<'a, std::io::Result> { Box::pin(OfferSendEntry::new(path)) } let path = path.as_ref(); // let metadata = async_std::fs::symlink_metadata(path).await?; let metadata = async_std::fs::metadata(path).await?; // let mtime = metadata.modified()? // .duration_since(std::time::SystemTime::UNIX_EPOCH) // .unwrap_or_default() // .as_secs(); if metadata.is_file() { tracing::trace!("OfferSendEntry::new {path:?} is file"); let path = path.to_owned(); Ok(Self::RegularFile { size: metadata.len(), content: new_offer_content(move || { let path = path.clone(); async_std::fs::File::open(path) }), }) // } else if metadata.is_symlink() { // tracing::trace!("OfferSendEntry::new {path:?} is symlink"); // let target = async_std::fs::read_link(path).await?; // Ok(Self::Symlink { // target: target // .to_str() // .ok_or_else(|| { // std::io::Error::new( // std::io::ErrorKind::Other, // format!("{} is not UTF-8 encoded", target.display()), // ) // })? // .to_string(), // }) } else if metadata.is_dir() { use futures::TryStreamExt; tracing::trace!("OfferSendEntry::new {path:?} is directory"); let content: BTreeMap = async_std::fs::read_dir(path) .await? .and_then(|file| async move { let path = file.path(); let name = path .file_name() .expect("Internal error: non-root paths should always have a name") .to_str() .ok_or_else(|| { std::io::Error::new( std::io::ErrorKind::Other, format!("{} is not UTF-8 encoded", path.display()), ) })? .to_owned(); let offer = new_recurse(path).await?; Ok((name, offer)) }) .try_collect() .await?; Ok(Self::Directory { content }) } else { unreachable!() } } } impl OfferEntry { /** Recursively list all files, without directory names or symlinks. */ fn iter_files(&self) -> impl Iterator, &T, u64)> + '_ { // TODO I couldn't think up a less efficient way to do this ^^ match self { Self::Directory { content, .. } => { let iter = content.iter().flat_map(|(name, offer)| { let name = name.clone(); offer.iter_files().map(move |mut val| { val.0.insert(0, name.clone()); val }) }); Box::new(iter) as Box> }, Self::RegularFile { content, size } => { Box::new(std::iter::once((vec![], content, *size))) as Box> }, // Self::Symlink { .. } => Box::new(std::iter::empty()) as Box>, } } fn get(&self, path: &[String]) -> Option<&Self> { match path { [] => Some(self), [start, rest @ ..] => match self { Self::Directory { content, .. } => { content.get(start).and_then(|inner| inner.get(rest)) }, _ => None, }, } } fn get_file(&self, path: &[String]) -> Option<(&T, u64)> { match path { [] => match self { Self::RegularFile { content, size } => Some((content, *size)), _ => None, }, [start, rest @ ..] => match self { Self::Directory { content, .. } => { content.get(start).and_then(|inner| inner.get_file(rest)) }, _ => None, }, } } #[cfg(not(target_family = "wasm"))] async fn create_directories(&self, target_path: &Path) -> std::io::Result<()> { #[inline(always)] fn recurse<'a, T>( this: &'a OfferEntry, path: &'a Path, ) -> futures::future::LocalBoxFuture<'a, std::io::Result<()>> { Box::pin(OfferEntry::create_directories(this, path)) } match self { Self::Directory { content, .. } => { async_std::fs::create_dir(target_path).await?; for (name, file) in content { recurse(file, &target_path.join(name)).await?; } Ok(()) }, _ => Ok(()), } } // #[cfg(not(target_family = "wasm"))] // async fn create_symlinks(&self, target_path: &Path) -> std::io::Result<()> { // #[inline(always)] // fn recurse<'a, T>( // this: &'a OfferEntry, // path: &'a Path, // ) -> futures::future::LocalBoxFuture<'a, std::io::Result<()>> { // Box::pin(OfferEntry::create_symlinks(this, path)) // } // match self { // Self::Symlink { target } => { // todo!() // }, // Self::Directory { content, .. } => { // for (name, file) in content { // recurse(file, &target_path.join(name)).await?; // } // Ok(()) // }, // _ => Ok(()), // } // } fn set_content( &self, base_path: &mut Vec, f: &mut impl FnMut(&[String]) -> U, ) -> OfferEntry { match self { OfferEntry::RegularFile { size, .. } => OfferEntry::RegularFile { size: *size, content: f(base_path), }, OfferEntry::Directory { content } => OfferEntry::Directory { content: content .iter() .map(|(k, v)| { base_path.push(k.clone()); let v = v.set_content(base_path, f); base_path.pop(); (k.clone(), v) }) .collect(), }, // OfferEntry::Symlink { target } => OfferEntry::Symlink { // target: target.clone(), // }, } } } impl OfferEntry { /** Recursively list all files, without directory names or symlinks. */ fn into_iter_files(self) -> impl Iterator, T, u64)> + Send { // TODO I couldn't think up a less efficient way to do this ^^ match self { Self::Directory { content, .. } => { let iter = content.into_iter().flat_map(|(name, offer)| { offer.into_iter_files().map(move |mut val| { val.0.insert(0, name.clone()); val }) }); Box::new(iter) as Box + Send> }, Self::RegularFile { content, size } => { Box::new(std::iter::once((vec![], content, size))) as Box + Send> }, // Self::Symlink { .. } => { // Box::new(std::iter::empty()) as Box + Send> // }, } } } impl From<&OfferEntry> for OfferEntry { fn from(from: &OfferEntry) -> Self { /* Note: this violates some invariants and only works because our mapper discards the path argument */ from.set_content(&mut vec![], &mut |_| ()) } } /// The signature is basically just `bool -> io::Result`, but in async /// /// The boolean parameter dictates whether we start from scratch or not: /// true: Append to existing files /// false: Truncate if necessary pub type AcceptContent = Box< dyn FnOnce( bool, ) -> futures::future::BoxFuture< 'static, std::io::Result>, > + Send, >; pub fn new_accept_content(content_handler: F) -> AcceptContent where F: Fn(bool) -> G + Send + 'static, G: Future> + Send + 'static, H: AsyncWrite + Unpin + Send + 'static, { let wrap_fun = move |append| { use futures::TryFutureExt; let fut = content_handler(append); let wrap_fut = fut.map_ok(|write| Box::new(write) as Box); Box::pin(wrap_fut) as futures::future::BoxFuture<'static, _> }; Box::new(wrap_fun) as _ } pub type OfferAccept = Offer; pub struct AcceptInner { pub offset: u64, pub sha256: Option<[u8; 32]>, pub content: AcceptContent, } magic-wormhole-0.7.6/src/transfer/v1.rs000064400000000000000000000711051046102023000160630ustar 00000000000000use futures::{ io::{AsyncReadExt, AsyncWriteExt}, StreamExt, TryFutureExt, }; use sha2::{digest::FixedOutput, Digest, Sha256}; use super::{offer::*, *}; #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] #[serde(rename_all = "kebab-case")] pub enum OfferMessage { Message(String), File { filename: String, filesize: u64, }, Directory { dirname: String, mode: String, zipsize: u64, numbytes: u64, numfiles: u64, }, #[serde(other)] Unknown, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(rename_all = "snake_case")] pub enum AnswerMessage { MessageAck(String), FileAck(String), } /** * A set of hints for both sides to find each other */ #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "kebab-case")] pub struct TransitV1 { pub abilities_v1: TransitAbilities, pub hints_v1: transit::Hints, } #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all = "kebab-case")] struct TransitAck { pub ack: String, pub sha256: String, } impl TransitAck { pub(crate) fn new(msg: impl Into, sha256: impl Into) -> Self { TransitAck { ack: msg.into(), sha256: sha256.into(), } } #[cfg(test)] pub(crate) fn serialize(&self) -> String { json!(self).to_string() } pub(crate) fn serialize_vec(&self) -> Vec { serde_json::to_vec(self).unwrap() } } pub(crate) async fn send( wormhole: Wormhole, relay_hints: Vec, transit_abilities: transit::Abilities, offer: OfferSend, progress_handler: impl FnMut(u64, u64) + 'static, transit_handler: impl FnOnce(transit::TransitInfo), _peer_version: AppVersion, cancel: impl Future, ) -> Result<(), TransferError> { if offer.is_multiple() { let folder = OfferSendEntry::Directory { content: offer.content, }; send_folder( wormhole, relay_hints, "".into(), folder, transit_abilities, transit_handler, progress_handler, cancel, ) .await } else if offer.is_directory() { let (folder_name, folder) = offer.content.into_iter().next().unwrap(); send_folder( wormhole, relay_hints, folder_name, folder, transit_abilities, transit_handler, progress_handler, cancel, ) .await } else { let (file_name, file) = offer.content.into_iter().next().unwrap(); let (mut file, file_size) = match file { OfferSendEntry::RegularFile { content, size } => { /* This must be split into two statements to appease the borrow checker (unfortunate side effect of borrow-through) */ let content = content(); let content = content.await?; (content, size) }, _ => unreachable!(), }; send_file( wormhole, relay_hints, &mut file, file_name, file_size, transit_abilities, transit_handler, progress_handler, cancel, ) .await } } pub(crate) async fn send_file( mut wormhole: Wormhole, relay_hints: Vec, file: &mut F, file_name: impl Into, file_size: u64, transit_abilities: transit::Abilities, transit_handler: G, progress_handler: H, cancel: impl Future, ) -> Result<(), TransferError> where F: AsyncRead + Unpin + Send, G: FnOnce(transit::TransitInfo), H: FnMut(u64, u64) + 'static, { let run = Box::pin(async { let connector = transit::init(transit_abilities, None, relay_hints).await?; // We want to do some transit tracing::debug!("Sending transit message '{:?}", connector.our_hints()); wormhole .send_json(&PeerMessage::transit_v1( *connector.our_abilities(), (**connector.our_hints()).clone(), )) .await?; // Send file offer message. tracing::debug!("Sending file offer"); wormhole .send_json(&PeerMessage::offer_file_v1(file_name, file_size)) .await?; // Wait for their transit response let (their_abilities, their_hints): (transit::Abilities, transit::Hints) = match wormhole.receive_json::().await??.check_err()? { PeerMessage::Transit(transit) => { tracing::debug!("Received transit message: {:?}", transit); (transit.abilities_v1, transit.hints_v1) }, other => { bail!(TransferError::unexpected_message("transit", other)) }, }; { // Wait for file_ack let fileack_msg = wormhole.receive_json::().await??; tracing::debug!("Received file ack message: {:?}", fileack_msg); match fileack_msg.check_err()? { PeerMessage::Answer(AnswerMessage::FileAck(msg)) => { ensure!(msg == "ok", TransferError::AckError); }, _ => { bail!(TransferError::unexpected_message( "answer/file_ack", fileack_msg )); }, } } let (mut transit, info) = connector .leader_connect( wormhole.key().derive_transit_key(wormhole.appid()), their_abilities, Arc::new(their_hints), ) .await?; transit_handler(info); tracing::debug!("Beginning file transfer"); // 11. send the file as encrypted records. let file = futures::stream::once(futures::future::ready(std::io::Result::Ok( Box::new(file) as Box, ))); let checksum = v1::send_records(&mut transit, file, file_size, progress_handler).await?; // 13. wait for the transit ack with sha256 sum from the peer. tracing::debug!("sent file. Waiting for ack"); let transit_ack = transit.receive_record().await?; let transit_ack_msg = serde_json::from_slice::(&transit_ack)?; ensure!( transit_ack_msg.sha256 == hex::encode(checksum), TransferError::Checksum ); tracing::debug!("Transfer complete!"); Ok(()) }); futures::pin_mut!(cancel); let result = cancel::cancellable_2(run, cancel).await; cancel::handle_run_result(wormhole, result).await } pub(crate) async fn send_folder( mut wormhole: Wormhole, relay_hints: Vec, mut folder_name: String, folder: OfferSendEntry, transit_abilities: transit::Abilities, transit_handler: impl FnOnce(transit::TransitInfo), progress_handler: impl FnMut(u64, u64) + 'static, cancel: impl Future, ) -> Result<(), TransferError> { let run = Box::pin(async { let connector = transit::init(transit_abilities, None, relay_hints).await?; // We want to do some transit tracing::debug!("Sending transit message '{:?}", connector.our_hints()); wormhole .send_json(&PeerMessage::transit_v1( *connector.our_abilities(), (**connector.our_hints()).clone(), )) .await?; /* We need to know the length of what we are going to send in advance. So we already build * all the headers of our file now but without the contents. We know that a file is * header + contents + padding */ tracing::debug!("Estimating the file size"); // TODO try again but without pinning use futures::{ future::{ready, BoxFuture}, io::Cursor, }; use std::io::Result as IoResult; type WrappedDataFut = BoxFuture<'static, IoResult>>; /* Type tetris :) */ fn wrap(buffer: impl AsRef<[u8]> + Unpin + Send + 'static) -> WrappedDataFut { Box::pin(ready(IoResult::Ok( Box::new(Cursor::new(buffer)) as Box ))) as _ } /* Walk our offer recursively, concatenate all our readers into a stream that will build the tar file */ fn create_offer( mut total_content: Vec, total_size: &mut u64, offer: OfferSendEntry, path: &mut Vec, ) -> IoResult> { match offer { OfferSendEntry::Directory { content } => { tracing::debug!("Adding directory {path:?}"); let header = tar_helper::create_header_directory(path)?; *total_size += header.len() as u64; total_content.push(wrap(header)); for (name, file) in content { path.push(name); total_content = create_offer(total_content, total_size, file, path)?; path.pop(); } }, OfferSendEntry::RegularFile { size, content } => { tracing::debug!("Adding file {path:?}; {size} bytes"); let header = tar_helper::create_header_file(path, size)?; let padding = tar_helper::padding(size); *total_size += header.len() as u64; *total_size += padding.len() as u64; *total_size += size; total_content.push(wrap(header)); let content = content().map_ok( /* Re-box because we can't upcast trait objects */ |read| Box::new(read) as Box, ); total_content.push(Box::pin(content) as _); total_content.push(wrap(padding)); }, // OfferSendEntry::Symlink { .. } => todo!(), } Ok(total_content) } let mut total_size = 0; let mut content = create_offer( Vec::new(), &mut total_size, folder, &mut vec![folder_name.clone()], )?; /* Finish tar file */ total_size += 1024; content.push(wrap([0; 1024])); let content = futures::stream::iter(content).then(|content| content); /* Convert to stream */ // Send file offer message. tracing::debug!("Sending file offer ({total_size} bytes)"); folder_name.push_str(".tar"); wormhole .send_json(&PeerMessage::offer_file_v1(folder_name, total_size)) .await?; // Wait for their transit response let (their_abilities, their_hints): (transit::Abilities, transit::Hints) = match wormhole.receive_json::().await??.check_err()? { PeerMessage::Transit(transit) => { tracing::debug!("received transit message: {:?}", transit); (transit.abilities_v1, transit.hints_v1) }, other => { bail!(TransferError::unexpected_message("transit", other)); }, }; // Wait for file_ack match wormhole.receive_json::().await??.check_err()? { PeerMessage::Answer(AnswerMessage::FileAck(msg)) => { ensure!(msg == "ok", TransferError::AckError); }, other => { bail!(TransferError::unexpected_message("answer/file_ack", other)); }, } let (mut transit, info) = connector .leader_connect( wormhole.key().derive_transit_key(wormhole.appid()), their_abilities, Arc::new(their_hints), ) .await?; transit_handler(info); tracing::debug!("Beginning file transfer"); // 11. send the file as encrypted records. let checksum = v1::send_records(&mut transit, content, total_size, progress_handler).await?; // 13. wait for the transit ack with sha256 sum from the peer. tracing::debug!("sent file. Waiting for ack"); let transit_ack = transit.receive_record().await?; let transit_ack_msg = serde_json::from_slice::(&transit_ack)?; ensure!( transit_ack_msg.sha256 == hex::encode(checksum), TransferError::Checksum ); tracing::debug!("Transfer complete!"); Ok(()) }); futures::pin_mut!(cancel); let result = cancel::cancellable_2(run, cancel).await; cancel::handle_run_result(wormhole, result).await } /** * Wait for a file offer from the other side * * This method waits for an offer message and builds up a [`ReceiveRequest`](ReceiveRequest). * It will also start building a TCP connection to the other side using the transit protocol. * * Returns `None` if the task got cancelled. */ pub async fn request( mut wormhole: Wormhole, relay_hints: Vec, transit_abilities: transit::Abilities, cancel: impl Future, ) -> Result, TransferError> { // Error handling let run = Box::pin(async { let connector = transit::init(transit_abilities, None, relay_hints).await?; // send the transit message tracing::debug!("Sending transit message '{:?}", connector.our_hints()); wormhole .send_json(&PeerMessage::transit_v1( *connector.our_abilities(), (**connector.our_hints()).clone(), )) .await?; // receive transit message let (their_abilities, their_hints): (transit::Abilities, transit::Hints) = match wormhole.receive_json::().await??.check_err()? { PeerMessage::Transit(transit) => { tracing::debug!("received transit message: {:?}", transit); (transit.abilities_v1, transit.hints_v1) }, other => { bail!(TransferError::unexpected_message("transit", other)); }, }; // 3. receive file offer message from peer let (filename, filesize) = match wormhole.receive_json::().await??.check_err()? { PeerMessage::Offer(offer_type) => match offer_type { v1::OfferMessage::File { filename, filesize } => (filename, filesize), v1::OfferMessage::Directory { mut dirname, zipsize, .. } => { dirname.push_str(".zip"); (dirname, zipsize) }, _ => bail!(TransferError::UnsupportedOffer), }, other => { bail!(TransferError::unexpected_message("offer", other)); }, }; Ok((filename, filesize, connector, their_abilities, their_hints)) }); futures::pin_mut!(cancel); let result = cancel::cancellable_2(run, cancel).await; cancel::handle_run_result_noclose(wormhole, result) .await .map(|inner: Option<_>| { inner.map( |((filename, filesize, connector, their_abilities, their_hints), wormhole, _)| { ReceiveRequest::new( filename, filesize, connector, their_abilities, their_hints, wormhole, ) }, ) }) } /** * A pending files send offer from the other side * * You *should* consume this object, either by calling [`accept`](ReceiveRequest::accept) or [`reject`](ReceiveRequest::reject). */ #[must_use] pub struct ReceiveRequest { wormhole: Wormhole, connector: TransitConnector, /// **Security warning:** this is untrusted and unverified input #[deprecated(since = "0.7.0", note = "use ReceiveRequest::file_name(..) instead")] #[cfg(not(target_family = "wasm"))] pub filename: PathBuf, file_name: String, /// The expected size of the file #[deprecated(since = "0.7.0", note = "use ReceiveRequest::file_size(..) instead")] pub filesize: u64, #[allow(dead_code)] offer: Arc, their_abilities: transit::Abilities, their_hints: Arc, } #[allow(deprecated)] impl ReceiveRequest { fn new( file_name: String, filesize: u64, connector: TransitConnector, their_abilities: transit::Abilities, their_hints: transit::Hints, wormhole: Wormhole, ) -> Self { let their_hints = Arc::new(their_hints); let mut content = BTreeMap::new(); // Synthesize an offer to make transfer v1 more similar to transfer v2 content.insert( file_name.clone(), OfferEntry::RegularFile { size: filesize, content: (), }, ); let offer = Arc::new(Offer { content }); #[allow(deprecated)] Self { wormhole, connector, #[cfg(not(target_family = "wasm"))] filename: PathBuf::from(file_name.clone()), file_name, filesize, offer, their_abilities, their_hints, } } /** * Accept the file offer * * This will transfer the file and save it on disk. */ pub async fn accept( mut self, transit_handler: G, progress_handler: F, content_handler: &mut W, cancel: impl Future, ) -> Result<(), TransferError> where F: FnMut(u64, u64) + 'static, G: FnOnce(transit::TransitInfo), W: AsyncWrite + Unpin, { let run = Box::pin(async { // send file ack. tracing::debug!("Sending ack"); self.wormhole .send_json(&PeerMessage::file_ack_v1("ok")) .await?; let (mut transit, info) = self .connector .follower_connect( self.wormhole .key() .derive_transit_key(self.wormhole.appid()), self.their_abilities, self.their_hints.clone(), ) .await?; transit_handler(info); tracing::debug!("Beginning file transfer"); tcp_file_receive( &mut transit, self.filesize, progress_handler, content_handler, ) .await?; Ok(()) }); futures::pin_mut!(cancel); let result = cancel::cancellable_2(run, cancel).await; cancel::handle_run_result(self.wormhole, result).await } /** * Reject the file offer * * This will send an error message to the other side so that it knows the transfer failed. */ pub async fn reject(mut self) -> Result<(), TransferError> { self.wormhole .send_json(&PeerMessage::error_message("transfer rejected")) .await?; self.wormhole.close().await?; Ok(()) } #[cfg(feature = "experimental-transfer-v2")] #[allow(missing_docs)] pub fn offer(&self) -> Arc { self.offer.clone() } /// The name of the offered file. /// /// This is untrusted and unverified input. pub fn file_name(&self) -> String { self.file_name.clone() } /// The expected file size pub fn file_size(&self) -> u64 { self.filesize } } // encrypt and send the file to tcp stream and return the sha256 sum // of the file before encryption. pub(crate) async fn send_records<'a>( transit: &mut Transit, files: impl futures::Stream>>, file_size: u64, mut progress_handler: impl FnMut(u64, u64) + 'static, ) -> Result, TransferError> { // rough plan: // 1. Open the file // 2. read a block of N bytes // 3. calculate a rolling sha256sum. // 4. AEAD with skey and with nonce as a counter from 0. // 5. send the encrypted buffer to the socket. // 6. go to step #2 till eof. // 7. if eof, return sha256 sum. // Report at 0 to allow clients to configure as necessary. progress_handler(0, file_size); let mut hasher = Sha256::default(); let mut plaintext = vec![0u8; 16 * 1024].into_boxed_slice(); let mut sent_size = 0; futures::pin_mut!(files); while let Some(mut file) = files.next().await.transpose()? { loop { // read a block of up to 4096 bytes let n = file.read(&mut plaintext[..]).await?; if n == 0 { // EOF break; } // send the encrypted record transit.send_record(&plaintext[0..n]).await?; sent_size += n as u64; progress_handler(sent_size, file_size); // sha256 of the input hasher.update(&plaintext[..n]); /* Don't do this. The EOF check above is sufficient */ // if n < 4096 { // break; // } } } transit.flush().await?; ensure!( sent_size == file_size, TransferError::FileSize { sent_size, file_size } ); Ok(hasher.finalize_fixed().to_vec()) } pub(crate) async fn receive_records( filesize: u64, transit: &mut Transit, mut progress_handler: F, mut content_handler: W, ) -> Result, TransferError> where F: FnMut(u64, u64) + 'static, W: AsyncWrite + Unpin, { let mut hasher = Sha256::default(); let total = filesize; let mut remaining_size = filesize as usize; // Might not need to do this here, since `accept()` is where they'd know the filesize // already... progress_handler(0, total); while remaining_size > 0 { // 3. decrypt the vector 'enc_packet' with the key. let plaintext = transit.receive_record().await?; content_handler.write_all(&plaintext).await?; // 4. calculate a rolling sha256 sum of the decrypted output. hasher.update(&plaintext); remaining_size -= plaintext.len(); let remaining = remaining_size as u64; progress_handler(total - remaining, total); } content_handler.close().await?; tracing::debug!("done"); // TODO: 5. write the buffer into a file. Ok(hasher.finalize_fixed().to_vec()) } pub(crate) async fn tcp_file_receive( transit: &mut Transit, filesize: u64, progress_handler: F, content_handler: &mut W, ) -> Result<(), TransferError> where F: FnMut(u64, u64) + 'static, W: AsyncWrite + Unpin, { // 5. receive encrypted records // now skey and rkey can be used. skey is used by the tx side, rkey is used // by the rx side for symmetric encryption. let checksum = receive_records(filesize, transit, progress_handler, content_handler).await?; let sha256sum = hex::encode(checksum.as_slice()); tracing::debug!("sha256 sum: {:?}", sha256sum); // 6. verify sha256 sum by sending an ack message to peer along with checksum. transit .send_record(&TransitAck::new("ok", &sha256sum).serialize_vec()) .await?; // 7. close socket. // well, no need, it gets dropped when it goes out of scope. tracing::debug!("Transfer complete"); Ok(()) } /// Custom functions from the `tar` crate to access internals mod tar_helper { /* Imports may depend on target platform */ #[allow(unused_imports)] use std::{ borrow::Cow, io::{self, Read, Write}, path::Path, str, }; pub(crate) fn create_header_file(path: &[String], size: u64) -> std::io::Result> { let mut header = tar::Header::new_gnu(); header.set_size(size); let mut data = Vec::with_capacity(1024); prepare_header_path(&mut data, &mut header, path.join("/").as_ref())?; header.set_mode(0o644); header.set_cksum(); data.write_all(header.as_bytes())?; Ok(data) } pub(crate) fn create_header_directory(path: &[String]) -> std::io::Result> { let mut header = tar::Header::new_gnu(); header.set_entry_type(tar::EntryType::Directory); let mut data = Vec::with_capacity(1024); prepare_header_path(&mut data, &mut header, path.join("/").as_ref())?; header.set_mode(0o755); header.set_cksum(); data.write_all(header.as_bytes())?; // append(&mut data, header, data)?; Ok(data) } pub(crate) fn padding(size: u64) -> &'static [u8] { const BLOCK: [u8; 512] = [0; 512]; if size % 512 != 0 { &BLOCK[size as usize % 512..] } else { &[] } } fn append( mut dst: &mut dyn std::io::Write, header: &tar::Header, mut data: &mut dyn std::io::Read, ) -> std::io::Result<()> { dst.write_all(header.as_bytes())?; let len = std::io::copy(&mut data, &mut dst)?; dst.write_all(padding(len))?; Ok(()) } fn prepare_header(size: u64, entry_type: u8) -> tar::Header { let mut header = tar::Header::new_gnu(); let name = b"././@LongLink"; header.as_gnu_mut().unwrap().name[..name.len()].clone_from_slice(&name[..]); header.set_mode(0o644); header.set_uid(0); header.set_gid(0); header.set_mtime(0); // + 1 to be compliant with GNU tar header.set_size(size + 1); header.set_entry_type(tar::EntryType::new(entry_type)); header.set_cksum(); header } fn prepare_header_path( dst: &mut dyn std::io::Write, header: &mut tar::Header, path: &str, ) -> std::io::Result<()> { // Try to encode the path directly in the header, but if it ends up not // working (probably because it's too long) then try to use the GNU-specific // long name extension by emitting an entry which indicates that it's the // filename. if let Err(e) = header.set_path(path) { let data = path2bytes(path); let max = header.as_old().name.len(); // Since `e` isn't specific enough to let us know the path is indeed too // long, verify it first before using the extension. if data.len() < max { return Err(e); } let header2 = prepare_header(data.len() as u64, b'L'); // null-terminated string let mut data2 = data.chain(io::repeat(0).take(1)); append(dst, &header2, &mut data2)?; // Truncate the path to store in the header we're about to emit to // ensure we've got something at least mentioned. Note that we use // `str`-encoding to be compatible with Windows, but in general the // entry in the header itself shouldn't matter too much since extraction // doesn't look at it. let truncated = match std::str::from_utf8(&data[..max]) { Ok(s) => s, Err(e) => std::str::from_utf8(&data[..e.valid_up_to()]).unwrap(), }; header.set_path(truncated)?; } Ok(()) } #[cfg(any(windows, target_arch = "wasm32"))] pub(crate) fn path2bytes(p: &str) -> Cow<[u8]> { let bytes = p.as_bytes(); if bytes.contains(&b'\\') { // Normalize to Unix-style path separators let mut bytes = bytes.to_owned(); for b in &mut bytes { if *b == b'\\' { *b = b'/'; } } Cow::Owned(bytes) } else { Cow::Borrowed(bytes) } } #[cfg(unix)] pub(crate) fn path2bytes(p: &str) -> Cow<[u8]> { Cow::Borrowed(p.as_bytes()) } } #[cfg(test)] mod test { use super::*; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_transit_ack() { let f1 = TransitAck::new("ok", "deadbeaf"); assert_eq!(f1.serialize(), "{\"ack\":\"ok\",\"sha256\":\"deadbeaf\"}"); } } magic-wormhole-0.7.6/src/transfer/v2.rs000064400000000000000000000460351046102023000160700ustar 00000000000000use futures::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; use serde_derive::{Deserialize, Serialize}; use sha2::{digest::FixedOutput, Sha256}; use super::{offer::*, *}; /** * A set of hints for both sides to find each other */ #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "kebab-case")] pub struct TransitV2 { pub hints_v2: transit::Hints, } /** * The type of message exchanged over the transit connection, serialized with msgpack */ #[derive(Deserialize, Serialize, derive_more::Display, Debug, Clone)] #[serde(rename_all = "kebab-case")] #[non_exhaustive] pub enum PeerMessageV2 { #[display("offer")] Offer(Offer), #[display("answer")] Answer(AnswerMessage), #[display("file-start")] FileStart(FileStart), #[display("payload")] Payload(Payload), #[display("file-end")] FileEnd(FileEnd), #[display("transfer-ack")] TransferAck(TransferAck), #[display("error")] Error(String), #[display("unknown")] #[serde(other)] Unknown, } impl PeerMessageV2 { pub fn ser_msgpack(&self) -> Vec { let mut writer = Vec::with_capacity(128); let mut ser = rmp_serde::encode::Serializer::new(&mut writer) .with_struct_map() .with_human_readable(); serde::Serialize::serialize(self, &mut ser).unwrap(); writer } pub fn de_msgpack(data: &[u8]) -> Result { rmp_serde::from_read(&mut &*data) } pub fn check_err(self) -> Result { match self { Self::Error(err) => Err(TransferError::PeerError(err)), other => Ok(other), } } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(rename_all = "kebab-case")] pub struct AnswerMessage { pub(self) files: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[serde(rename_all = "kebab-case")] struct AnswerMessageInner { pub file: Vec, pub offset: u64, pub sha256: Option<[u8; 32]>, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "kebab-case")] pub struct FileStart { pub file: Vec, pub start_at_offset: bool, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "kebab-case")] pub struct Payload { payload: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "kebab-case")] pub struct FileEnd {} #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "kebab-case")] pub struct TransferAck {} /** The code to establish a transit connection is essentially the same on both sides. */ async fn make_transit( wormhole: &mut Wormhole, is_leader: bool, relay_hints: Vec, transit_abilities: transit::Abilities, peer_abilities: transit::Abilities, ) -> Result<(transit::Transit, transit::TransitInfo), TransferError> { let connector = transit::init(transit_abilities, Some(peer_abilities), relay_hints).await?; /* Send our transit hints */ wormhole .send_json(&PeerMessage::transit_v2((**connector.our_hints()).clone())) .await?; /* Receive their transit hints */ let their_hints: transit::Hints = match wormhole.receive_json::().await??.check_err()? { PeerMessage::TransitV2(transit) => { tracing::debug!("received transit message: {:?}", transit); transit.hints_v2 }, other => { let error = TransferError::unexpected_message("transit-v2", other); let _ = wormhole .send_json(&PeerMessage::Error(format!("{}", error))) .await; bail!(error) }, }; /* Get a transit connection */ let (transit, info) = match connector .connect( is_leader, wormhole.key().derive_transit_key(wormhole.appid()), peer_abilities, Arc::new(their_hints), ) .await { Ok(transit) => transit, Err(error) => { let error = TransferError::TransitConnect(error); let _ = wormhole .send_json(&PeerMessage::Error(format!("{}", error))) .await; return Err(error); }, }; Ok((transit, info)) } pub async fn send( mut wormhole: Wormhole, relay_hints: Vec, transit_abilities: transit::Abilities, offer: OfferSend, progress_handler: impl FnMut(u64, u64) + 'static, peer_version: AppVersion, cancel: impl Future, ) -> Result<(), TransferError> { let peer_abilities = peer_version.transfer_v2.unwrap(); futures::pin_mut!(cancel); /* Establish transit connection, close the Wormhole and switch to using the transit connection (msgpack instead of json) */ let (mut transit, wormhole, cancel) = cancel::with_cancel_wormhole!( wormhole, run = async { Ok(make_transit( &mut wormhole, true, relay_hints, transit_abilities, peer_abilities.transit_abilities, ) .await? .0) }, cancel, ret_cancel = (), ); cancel::with_cancel_transit!( transit, run = async { /* Close the wormhole only here so that the operation may be cancelled */ wormhole.close().await?; send_inner(&mut transit, offer, progress_handler).await }, cancel, |err| PeerMessageV2::Error(err.to_string()).ser_msgpack(), |msg| match PeerMessageV2::de_msgpack(msg)? { PeerMessageV2::Error(err) => Ok(Some(err)), _ => Ok(None), }, ret_cancel = (), ); Ok(()) } /** We've established the transit connection and closed the Wormhole */ async fn send_inner( transit: &mut transit::Transit, offer: OfferSend, mut progress_handler: impl FnMut(u64, u64) + 'static, ) -> Result<(), TransferError> { transit.send_record(&{ /* This must be split into two statements to appease the borrow checker (unfortunate side effect of borrow-through) */ PeerMessageV2::Offer((&offer).into()).ser_msgpack() }).await?; let files = match PeerMessageV2::de_msgpack(&transit.receive_record().await?)?.check_err()? { PeerMessageV2::Answer(answer) => answer.files, other => { bail!(TransferError::unexpected_message("answer", other)) }, }; let mut total_size = 0; for file in &files { if let Some((_, size)) = offer.get_file(&file.file) { total_size += size; } else { bail!(TransferError::Protocol( format!("Invalid file request: {}", file.file.join("/")).into() )); } } let mut total_sent = 0; const BUFFER_LEN: usize = 16 * 1024; let mut buffer = vec![0u8; BUFFER_LEN].into_boxed_slice(); for AnswerMessageInner { file, offset, sha256, } in &files { let offset = *offset; /* This must be split into two statements to appease the borrow checker (unfortunate side effect of borrow-through) */ let content = (offer.get_file(file).unwrap().0)(); let mut content = content.await?; let file = file.clone(); /* If they specified a hash, check our local file's contents */ if let Some(sha256) = sha256 { content.seek(std::io::SeekFrom::Start(offset)).await?; let mut hasher = Sha256::default(); futures::io::copy( (&mut content).take(offset), &mut futures::io::AllowStdIo::new(&mut hasher), ) .await?; let our_hash = hasher.finalize_fixed(); /* If it doesn't match, start at 0 instead of the originally requested offset */ if *our_hash == sha256[..] { transit .send_record( &PeerMessageV2::FileStart(FileStart { file, start_at_offset: true, }) .ser_msgpack(), ) .await?; } else { transit .send_record( &PeerMessageV2::FileStart(FileStart { file, start_at_offset: false, }) .ser_msgpack(), ) .await?; content.seek(std::io::SeekFrom::Start(0)).await?; // offset = 0; TODO } } else { content.seek(std::io::SeekFrom::Start(offset)).await?; transit .send_record( &PeerMessageV2::FileStart(FileStart { file, start_at_offset: true, }) .ser_msgpack(), ) .await?; } progress_handler(total_sent, total_size); loop { let n = content.read(&mut buffer[..]).await?; let buffer = &buffer[..n]; if n == 0 { // EOF break; } transit .send_record( &PeerMessageV2::Payload(Payload { payload: buffer.into(), }) .ser_msgpack(), ) .await?; total_sent += n as u64; progress_handler(total_sent, total_size); if n < BUFFER_LEN { break; } } transit .send_record(&PeerMessageV2::FileEnd(FileEnd {}).ser_msgpack()) .await?; } transit .send_record(&PeerMessageV2::TransferAck(TransferAck {}).ser_msgpack()) .await?; Ok(()) } pub async fn request( mut wormhole: Wormhole, relay_hints: Vec, peer_version: AppVersion, transit_abilities: transit::Abilities, cancel: impl Future, ) -> Result, TransferError> { let peer_abilities = peer_version.transfer_v2.unwrap(); futures::pin_mut!(cancel); /* Establish transit connection, close the Wormhole and switch to using the transit connection (msgpack instead of json) */ let ((mut transit, info), wormhole, cancel) = cancel::with_cancel_wormhole!( wormhole, run = async { make_transit( &mut wormhole, false, relay_hints, transit_abilities, peer_abilities.transit_abilities, ) .await }, cancel, ret_cancel = None, ); let (offer, transit) = cancel::with_cancel_transit!( transit, run = async { /* Close the wormhole only here so that the `.await` is scoped within cancellation */ wormhole.close().await?; let offer = match PeerMessageV2::de_msgpack(&transit.receive_record().await?)?.check_err()? { PeerMessageV2::Offer(offer) => offer, other => { bail!(TransferError::unexpected_message("offer", other)) }, }; Ok(offer) }, cancel, |err| PeerMessageV2::Error(err.to_string()).ser_msgpack(), |msg| match PeerMessageV2::de_msgpack(msg)? { PeerMessageV2::Error(err) => Ok(Some(err)), _ => Ok(None), }, ret_cancel = None, ); Ok(Some(ReceiveRequest::new(transit, offer, info))) } /** * A pending files send offer from the other side * * You *should* consume this object, either by calling [`accept`](ReceiveRequest::accept) or [`reject`](ReceiveRequest::reject). */ #[must_use] pub struct ReceiveRequest { transit: Transit, offer: Arc, info: transit::TransitInfo, } impl ReceiveRequest { pub fn new(transit: Transit, offer: Offer, info: transit::TransitInfo) -> Self { Self { transit, offer: Arc::new(offer), info, } } /** The offer we got */ pub fn offer(&self) -> Arc { self.offer.clone() } /** * Accept the file offer * * This will transfer the file and save it on disk. */ pub async fn accept( self, transit_handler: impl FnOnce(transit::TransitInfo), answer: OfferAccept, progress_handler: impl FnMut(u64, u64) + 'static, cancel: impl Future, ) -> Result<(), TransferError> { transit_handler(self.info); futures::pin_mut!(cancel); let mut transit = self.transit; cancel::with_cancel_transit!( transit, run = async { transit.send_record(&{ /* This must be split into two statements to appease the borrow checker (unfortunate side effect of borrow-through) */ let msg = PeerMessageV2::Answer(AnswerMessage { files: answer.iter_files() .map(|(path, inner, _size)| AnswerMessageInner { file: path, offset: inner.offset, sha256: inner.sha256, }) .collect(), }).ser_msgpack(); msg }).await?; receive_inner(&mut transit, &self.offer, answer, progress_handler).await }, cancel, |err| PeerMessageV2::Error(err.to_string()).ser_msgpack(), |msg| match PeerMessageV2::de_msgpack(msg)? { PeerMessageV2::Error(err) => Ok(Some(err)), _ => Ok(None), }, ret_cancel = (), ); Ok(()) } /** * Reject the file offer * * This will send an error message to the other side so that it knows the transfer failed. */ pub async fn reject(mut self) -> Result<(), TransferError> { self.transit .send_record(&PeerMessageV2::Error("transfer rejected".into()).ser_msgpack()) .await?; self.transit.flush().await?; Ok(()) } } /** We've established the transit connection and closed the Wormhole */ async fn receive_inner( transit: &mut transit::Transit, offer: &Arc, our_answer: OfferAccept, mut progress_handler: impl FnMut(u64, u64) + 'static, ) -> Result<(), TransferError> { /* This does not check for file sizes, but should be good enough * (failures will eventually lead to protocol errors later on anyways) */ assert!( our_answer .iter_file_paths() .all(|path| offer.get_file(&path).is_some()), "Mismatch between offer and accept: accept must be a true subset of offer" ); let n_accepted = our_answer.iter_file_paths().count(); let total_size = our_answer .iter_files() .map(|(_path, _inner, size)| size) .sum::(); let mut total_received = 0; /* The receive loop */ for (i, (file, answer, size)) in our_answer.into_iter_files().enumerate() { let file_start = match PeerMessageV2::de_msgpack(&transit.receive_record().await?)? .check_err()? { PeerMessageV2::FileStart(file_start) => file_start, PeerMessageV2::TransferAck(_) => { bail!(TransferError::Protocol(format!("Unexpected message: got 'transfer-ack' but expected {} more 'file-start' messages", n_accepted - i).into_boxed_str())) }, other => { bail!(TransferError::unexpected_message("file-start", other)) }, }; ensure!( file_start.file == file, TransferError::Protocol( format!( "Unexpected file: got file {} but expected {}", file_start.file.join("/"), file.join("/"), ) .into_boxed_str() ) ); let mut content; let mut received_size = 0; if file_start.start_at_offset { content = (answer.content)(true).await?; let offset = answer.offset; received_size = offset; } else { content = (answer.content)(false).await?; } progress_handler(total_received, total_size); loop { let payload = match PeerMessageV2::de_msgpack(&transit.receive_record().await?)?.check_err()? { PeerMessageV2::Payload(payload) => payload.payload, PeerMessageV2::FileEnd(_) => { bail!(TransferError::Protocol( format!( "Unexpected message: got 'file-end' but expected {} more payload bytes", size - received_size, ) .into_boxed_str() )) }, other => { bail!(TransferError::unexpected_message("payload", other)) }, }; content.write_all(&payload).await?; received_size += payload.len() as u64; total_received += payload.len() as u64; progress_handler(total_received, total_size); if received_size == size { break; } else if received_size >= size { /* `received_size` must never become greater than `size` or we might panic on an integer underflow in the next iteration * (only on an unhappy path, but still). Also, the progress bar might not appreciate. */ bail!(TransferError::Protocol( format!( "File too large: expected only {size} bytes, got at least {} more", size - received_size ) .into_boxed_str() )) } } content.close().await?; let _end = match PeerMessageV2::de_msgpack(&transit.receive_record().await?)?.check_err()? { PeerMessageV2::FileEnd(end) => end, other => { bail!(TransferError::unexpected_message("file-end", other)) }, }; } let _transfer_ack = match PeerMessageV2::de_msgpack(&transit.receive_record().await?)?.check_err()? { PeerMessageV2::TransferAck(transfer_ack) => transfer_ack, PeerMessageV2::FileStart(_) => { bail!(TransferError::Protocol( "Unexpected message: got 'file-start' but did not expect any more files" .to_string() .into_boxed_str() )) }, other => { bail!(TransferError::unexpected_message("transfer-ack", other)) }, }; Ok(()) } magic-wormhole-0.7.6/src/transfer.rs000064400000000000000000000541661046102023000155450ustar 00000000000000//! Client-to-Client protocol to organize file transfers //! //! This gives you the actual capability to transfer files, that feature that Magic Wormhole got known and loved for. //! //! It is bound to an [`AppID`]. Only applications using that APPID (and thus this protocol) can interoperate with //! the original Python implementation (and other compliant implementations). //! //! At its core, "peer messages" are exchanged over an established wormhole connection with the other side. //! They are used to set up a [transit] portal and to exchange a file offer/accept. Then, the file is transmitted over the transit relay. #![allow(deprecated)] use futures::{AsyncRead, AsyncWrite}; use serde_derive::{Deserialize, Serialize}; #[cfg(test)] use serde_json::json; use std::sync::Arc; use super::{core::WormholeError, transit, AppID, Wormhole}; use futures::Future; use std::{borrow::Cow, collections::BTreeMap}; #[cfg(not(target_family = "wasm"))] use std::path::{Path, PathBuf}; use transit::{ Abilities as TransitAbilities, Transit, TransitConnectError, TransitConnector, TransitError, }; mod cancel; #[doc(hidden)] pub mod offer; mod v1; #[cfg(feature = "experimental-transfer-v2")] #[allow(missing_docs)] mod v2; #[doc(hidden)] pub use v1::ReceiveRequest as ReceiveRequestV1; #[cfg(not(feature = "experimental-transfer-v2"))] pub use v1::ReceiveRequest; #[cfg(feature = "experimental-transfer-v2")] pub use v2::ReceiveRequest as ReceiveRequestV2; const APPID_RAW: &str = "lothar.com/wormhole/text-or-file-xfer"; /// The App ID associated with this protocol. pub const APPID: AppID = AppID(Cow::Borrowed(APPID_RAW)); /// An [`crate::AppConfig`] with default parameters for the file transfer protocol. /// /// You **must not** change `id` and `rendezvous_url` to be interoperable. /// The `app_version` can be adjusted if you want to disable some features. pub const APP_CONFIG: crate::AppConfig = crate::AppConfig:: { id: AppID(Cow::Borrowed(APPID_RAW)), rendezvous_url: Cow::Borrowed(crate::rendezvous::DEFAULT_RENDEZVOUS_SERVER), app_version: AppVersion::new(), }; // TODO be more extensible on the JSON enum types (i.e. recognize unknown variants) #[derive(Debug, thiserror::Error)] #[non_exhaustive] /// An error occurred during file transfer pub enum TransferError { /// Transfer was not acknowledged by peer #[error("Transfer was not acknowledged by peer")] AckError, /// Receive checksum error #[error("Receive checksum error")] Checksum, /// The file contained a different amount of bytes than advertized #[error("The file contained a different amount of bytes than advertized! Sent {} bytes, but should have been {}", sent_size, file_size)] FileSize { /// The amount of bytes that were sent sent_size: u64, /// The expected amount of bytes file_size: u64, }, /// The file(s) to send got modified during the transfer, and thus corrupted #[error("The file(s) to send got modified during the transfer, and thus corrupted")] FilesystemSkew, // TODO be more specific /// Unsupported offer type #[error("Unsupported offer type")] UnsupportedOffer, /// Something went wrong on the other side #[error("Something went wrong on the other side: {}", _0)] PeerError(String), /// Corrupt JSON message received. Some deserialization went wrong, we probably got some garbage #[error("Corrupt JSON message received")] ProtocolJson( #[from] #[source] serde_json::Error, ), /// Corrupt Msgpack message received. Some deserialization went wrong, we probably got some garbage #[error("Corrupt Msgpack message received")] ProtocolMsgpack( #[from] #[source] rmp_serde::decode::Error, ), /// A generic string message for "something went wrong", i.e. /// the server sent some bullshit message order #[error("Protocol error: {}", _0)] Protocol(Box), /// Unexpected message (protocol error) #[error( "Unexpected message (protocol error): Expected '{}', but got: '{}'", _0, _1 )] ProtocolUnexpectedMessage(Box, Box), /// Wormhole connection error #[error("Wormhole connection error")] Wormhole( #[from] #[source] WormholeError, ), /// Error while establishing transit connection #[error("Error while establishing transit connection")] TransitConnect( #[from] #[source] TransitConnectError, ), /// Transit error #[error("Transit error")] Transit( #[from] #[source] TransitError, ), /// I/O error #[error("I/O error")] IO( #[from] #[source] std::io::Error, ), } impl TransferError { pub(self) fn unexpected_message( expected: impl Into>, got: impl std::fmt::Display, ) -> Self { Self::ProtocolUnexpectedMessage(expected.into(), got.to_string().into()) } } /** * The application specific version information for this protocol. */ #[derive(Clone, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub struct AppVersion { #[serde(default)] abilities: Cow<'static, [Cow<'static, str>]>, #[serde(default)] #[cfg(feature = "experimental-transfer-v2")] transfer_v2: Option, } // TODO check invariants during deserialization impl AppVersion { const fn new() -> Self { Self { // Dont advertize v2 for now abilities: Cow::Borrowed(&[ Cow::Borrowed("transfer-v1"), /* Cow::Borrowed("experimental-transfer-v2") */ ]), #[cfg(feature = "experimental-transfer-v2")] transfer_v2: Some(AppVersionTransferV2Hint::new()), } } #[allow(dead_code)] fn supports_v2(&self) -> bool { self.abilities.contains(&"transfer-v2".into()) } } impl Default for AppVersion { fn default() -> Self { Self::new() } } /// A hint used in transfer v2 to determine the app version #[cfg(feature = "experimental-transfer-v2")] #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub struct AppVersionTransferV2Hint { supported_formats: Cow<'static, [Cow<'static, str>]>, transit_abilities: transit::Abilities, } #[cfg(feature = "experimental-transfer-v2")] impl AppVersionTransferV2Hint { const fn new() -> Self { Self { supported_formats: Cow::Borrowed(&[Cow::Borrowed("plain"), Cow::Borrowed("tar")]), transit_abilities: transit::Abilities::ALL_ABILITIES, } } } #[cfg(feature = "experimental-transfer-v2")] impl Default for AppVersionTransferV2Hint { fn default() -> Self { Self::new() } } /** * The type of message exchanged over the wormhole for this protocol */ #[derive(Deserialize, Serialize, derive_more::Display, Debug, Clone)] #[serde(rename_all = "kebab-case")] #[non_exhaustive] #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] pub enum PeerMessage { /* V1 */ /// A transit message #[display("transit")] Transit(v1::TransitV1), /// An offer message #[display("offer")] Offer(v1::OfferMessage), /// An answer message #[display("answer")] Answer(v1::AnswerMessage), /* V2 */ /// A transit v2 message #[cfg(feature = "experimental-transfer-v2")] #[display("transit-v2")] TransitV2(v2::TransitV2), /// Tell the other side you got an error #[display("error")] Error(String), /// An unknown message #[display("unknown")] #[serde(other)] Unknown, } impl PeerMessage { #[allow(unused)] fn offer_message_v1(msg: impl Into) -> Self { PeerMessage::Offer(v1::OfferMessage::Message(msg.into())) } fn offer_file_v1(name: impl Into, size: u64) -> Self { PeerMessage::Offer(v1::OfferMessage::File { filename: name.into(), filesize: size, }) } #[allow(dead_code)] fn offer_directory_v1( name: impl Into, mode: impl Into, compressed_size: u64, numbytes: u64, numfiles: u64, ) -> Self { PeerMessage::Offer(v1::OfferMessage::Directory { dirname: name.into(), mode: mode.into(), zipsize: compressed_size, numbytes, numfiles, }) } #[allow(dead_code)] fn message_ack_v1(msg: impl Into) -> Self { PeerMessage::Answer(v1::AnswerMessage::MessageAck(msg.into())) } fn file_ack_v1(msg: impl Into) -> Self { PeerMessage::Answer(v1::AnswerMessage::FileAck(msg.into())) } fn error_message(msg: impl Into) -> Self { PeerMessage::Error(msg.into()) } fn transit_v1(abilities: TransitAbilities, hints: transit::Hints) -> Self { PeerMessage::Transit(v1::TransitV1 { abilities_v1: abilities, hints_v1: hints, }) } #[cfg(feature = "experimental-transfer-v2")] fn transit_v2(hints_v2: transit::Hints) -> Self { PeerMessage::TransitV2(v2::TransitV2 { hints_v2 }) } fn check_err(&self) -> Result { match self { Self::Error(err) => Err(TransferError::PeerError(err.clone())), other => Ok(other.clone()), } } #[allow(dead_code)] fn ser_json(&self) -> Vec { serde_json::to_vec(self).unwrap() } } /// Send a previously constructed offer. /// /// Part of the experimental and unstable transfer-v2 API. /// Expect some amount of API breakage in the future to adapt to protocol changes and API ergonomics. #[cfg_attr(not(feature = "experimental-transfer-v2"), doc(hidden))] pub async fn send( wormhole: Wormhole, relay_hints: Vec, transit_abilities: transit::Abilities, offer: offer::OfferSend, transit_handler: impl FnOnce(transit::TransitInfo), progress_handler: impl FnMut(u64, u64) + 'static, cancel: impl Future, ) -> Result<(), TransferError> { let peer_version: AppVersion = serde_json::from_value(wormhole.peer_version().clone())?; #[cfg(feature = "experimental-transfer-v2")] { if peer_version.supports_v2() { return v2::send( wormhole, relay_hints, transit_abilities, offer, progress_handler, peer_version, cancel, ) .await; } } v1::send( wormhole, relay_hints, transit_abilities, offer, progress_handler, transit_handler, peer_version, cancel, ) .await } /** * Wait for a file offer from the other side * * This method waits for an offer message and builds up a [`ReceiveRequest`]. * It will also start building a TCP connection to the other side using the transit protocol. * * Returns `None` if the task got cancelled. * * Part of the experimental and unstable transfer-v2 API. * Expect some amount of API breakage in the future to adapt to protocol changes and API ergonomics. */ #[cfg(feature = "experimental-transfer-v2")] pub async fn request( wormhole: Wormhole, relay_hints: Vec, transit_abilities: transit::Abilities, cancel: impl Future, ) -> Result, TransferError> { #[cfg(feature = "experimental-transfer-v2")] { let peer_version: AppVersion = serde_json::from_value(wormhole.peer_version().clone())?; if peer_version.supports_v2() { v2::request( wormhole, relay_hints, peer_version, transit_abilities, cancel, ) .await .map(|req| req.map(ReceiveRequest::V2)) } else { v1::request(wormhole, relay_hints, transit_abilities, cancel) .await .map(|req| req.map(ReceiveRequest::V1)) } } } /// Wait for a file offer from the other side /// /// This method waits for an offer message and builds up a ReceiveRequest. It will also start building a TCP connection to the other side using the transit protocol. /// /// Returns None if the task got cancelled. #[cfg_attr( feature = "experimental-transfer-v2", deprecated( since = "0.7.0", note = "transfer::request_file does not support file transfer protocol version 2. To continue only supporting version 1, use transfer::v1::request. To support both protocol versions, use transfer::request" ) )] pub async fn request_file( wormhole: Wormhole, relay_hints: Vec, transit_abilities: transit::Abilities, cancel: impl Future, ) -> Result, TransferError> { v1::request(wormhole, relay_hints, transit_abilities, cancel).await } /// Send a file to the other side /// /// You must ensure that the Reader contains exactly as many bytes as advertized in file_size. #[cfg_attr( feature = "experimental-transfer-v2", deprecated( since = "0.7.0", note = "transfer::send_file does not support file transfer protocol version 2, use transfer::send" ) )] pub async fn send_file( wormhole: Wormhole, relay_hints: Vec, file: &mut F, file_name: N, file_size: u64, transit_abilities: transit::Abilities, transit_handler: G, progress_handler: H, cancel: impl Future, ) -> Result<(), TransferError> where F: AsyncRead + Unpin + Send, N: Into, G: FnOnce(transit::TransitInfo), H: FnMut(u64, u64) + 'static, { v1::send_file( wormhole, relay_hints, file, file_name, file_size, transit_abilities, transit_handler, progress_handler, cancel, ) .await } /// Send a file or folder #[cfg_attr( feature = "experimental-transfer-v2", deprecated( since = "0.7.0", note = "transfer::send_file_or_folder does not support file transfer protocol version 2, use transfer::send" ) )] #[allow(deprecated)] #[cfg(not(target_family = "wasm"))] pub async fn send_file_or_folder( wormhole: Wormhole, relay_hints: Vec, file_path: N, file_name: M, transit_abilities: transit::Abilities, transit_handler: G, progress_handler: H, cancel: impl Future, ) -> Result<(), TransferError> where N: AsRef, M: Into, G: FnOnce(transit::TransitInfo), H: FnMut(u64, u64) + 'static, { use async_std::fs::File; let file_path = file_path.as_ref(); let file_name = file_name.into(); let mut file = File::open(file_path).await?; let metadata = file.metadata().await?; if metadata.is_dir() { send_folder( wormhole, relay_hints, file_path, file_name, transit_abilities, transit_handler, progress_handler, cancel, ) .await?; } else { let file_size = metadata.len(); send_file( wormhole, relay_hints, &mut file, file_name, file_size, transit_abilities, transit_handler, progress_handler, cancel, ) .await?; } Ok(()) } /// Send a folder to the other side /// This isn’t a proper folder transfer as per the Wormhole protocol because it sends it in a way so /// that the receiver still has to manually unpack it. But it’s better than nothing #[cfg_attr( feature = "experimental-transfer-v2", deprecated( since = "0.7.0", note = "transfer::send_folder does not support file transfer protocol version 2, use transfer::send" ) )] #[cfg(not(target_family = "wasm"))] pub async fn send_folder( wormhole: Wormhole, relay_hints: Vec, folder_path: N, folder_name: M, transit_abilities: transit::Abilities, transit_handler: G, progress_handler: H, cancel: impl Future, ) -> Result<(), TransferError> where N: Into, M: Into, G: FnOnce(transit::TransitInfo), H: FnMut(u64, u64) + 'static, { let offer = offer::OfferSendEntry::new(folder_path.into()).await?; v1::send_folder( wormhole, relay_hints, folder_name.into(), offer, transit_abilities, transit_handler, progress_handler, cancel, ) .await } /** * A pending files send offer from the other side * * You *should* consume this object, by matching on the protocol version and then calling either `accept` or `reject`. */ #[must_use] #[cfg(feature = "experimental-transfer-v2")] pub enum ReceiveRequest { /// A protocol version 1 receive request V1(ReceiveRequestV1), /// A protocol version 2 receive request V2(ReceiveRequestV2), } #[cfg(feature = "experimental-transfer-v2")] impl ReceiveRequest { /// Accept this receive request pub async fn accept( self, transit_handler: G, progress_handler: F, mut answer: offer::OfferAccept, cancel: impl Future, ) -> Result<(), TransferError> where F: FnMut(u64, u64) + 'static, G: FnOnce(transit::TransitInfo), W: AsyncWrite + Unpin, { match self { ReceiveRequest::V1(request) => { // Desynthesize the previously synthesized offer to make transfer v1 more similar to transfer v2 let (_name, entry) = answer.content.pop_first().expect( "must call accept(..) with an offer that contains at least one element", ); let mut acceptor = match entry { offer::OfferEntry::RegularFile { content, .. } => { (content.content)(true).await? }, _ => panic!( "when using transfer v1 you must call accept(..) with file offers only", ), }; request .accept(transit_handler, progress_handler, &mut acceptor, cancel) .await }, ReceiveRequest::V2(request) => { request .accept(transit_handler, answer, progress_handler, cancel) .await }, } } /** * Reject the file offer * * This will send an error message to the other side so that it knows the transfer failed. */ pub async fn reject(self) -> Result<(), TransferError> { match self { ReceiveRequest::V1(request) => request.reject().await, ReceiveRequest::V2(request) => request.reject().await, } } /// The file offer for this receive request pub fn offer(&self) -> Arc { match self { ReceiveRequest::V1(req) => req.offer(), ReceiveRequest::V2(req) => req.offer(), } } } #[cfg(test)] mod test { use super::*; use transit::{Abilities, DirectHint, RelayHint}; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_transit() { let abilities = Abilities::ALL_ABILITIES; let hints = transit::Hints::new( [DirectHint::new("192.168.1.8", 46295)], [RelayHint::new( None, [DirectHint::new("magic-wormhole-transit.debian.net", 4001)], [], )], ); assert_eq!( serde_json::json!(crate::transfer::PeerMessage::transit_v1(abilities, hints)), serde_json::json!({ "transit": { "abilities-v1": [{"type":"direct-tcp-v1"},{"type":"relay-v1"}], "hints-v1": [ {"hostname":"192.168.1.8","port":46295,"type":"direct-tcp-v1"}, { "type": "relay-v1", "hints": [ {"type": "direct-tcp-v1", "hostname": "magic-wormhole-transit.debian.net", "port": 4001} ], "name": null } ], } }) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_message() { let m1 = PeerMessage::offer_message_v1("hello from rust"); assert_eq!( serde_json::json!(m1).to_string(), "{\"offer\":{\"message\":\"hello from rust\"}}" ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_offer_file() { let f1 = PeerMessage::offer_file_v1("somefile.txt", 34556); assert_eq!( serde_json::json!(f1).to_string(), "{\"offer\":{\"file\":{\"filename\":\"somefile.txt\",\"filesize\":34556}}}" ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_offer_directory() { let d1 = PeerMessage::offer_directory_v1("somedirectory", "zipped", 45, 1234, 10); assert_eq!( serde_json::json!(d1).to_string(), "{\"offer\":{\"directory\":{\"dirname\":\"somedirectory\",\"mode\":\"zipped\",\"numbytes\":1234,\"numfiles\":10,\"zipsize\":45}}}" ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_message_ack() { let m1 = PeerMessage::message_ack_v1("ok"); assert_eq!( serde_json::json!(m1).to_string(), "{\"answer\":{\"message_ack\":\"ok\"}}" ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_file_ack() { let f1 = PeerMessage::file_ack_v1("ok"); assert_eq!( serde_json::json!(f1).to_string(), "{\"answer\":{\"file_ack\":\"ok\"}}" ); } } magic-wormhole-0.7.6/src/transit/crypto.rs000064400000000000000000000410021046102023000167060ustar 00000000000000//! Cryptographic backbone of the Transit protocol //! //! This handles the encrypted handshakes during connection setup, then provides //! a simple "encrypt/decrypt" abstraction that will be used for all messages. #![allow(deprecated)] use super::{ TransitError, TransitKey, TransitRxKey, TransitTransport, TransitTransportRx, TransitTransportTx, TransitTxKey, }; use crate::Key; use async_trait::async_trait; use crypto_secretbox as secretbox; use crypto_secretbox::{aead::Aead, KeyInit}; use futures::{future::BoxFuture, io::AsyncWriteExt}; use std::sync::Arc; /// Private, because we try multiple handshakes and only /// one needs to succeed #[derive(Debug, thiserror::Error)] #[non_exhaustive] pub(super) enum TransitHandshakeError { #[error("Handshake failed")] HandshakeFailed, #[error("Relay handshake failed")] RelayHandshakeFailed, #[error("Malformed peer address")] BadAddress( #[from] #[source] std::net::AddrParseError, ), #[error("Noise cryptography error")] NoiseCrypto( #[from] #[source] noise_protocol::Error, ), #[error("Decryption error")] Decryption, #[error("IO error")] IO( #[from] #[source] std::io::Error, ), #[cfg(target_family = "wasm")] #[error("WASM error")] WASM( #[from] #[source] ws_stream_wasm::WsErr, ), } impl From<()> for TransitHandshakeError { fn from(_: ()) -> Self { Self::Decryption } } /// The Transit protocol has the property that the last message of the handshake is from the leader /// and confirms the usage of that specific connection. This trait represents that specific type state. pub(super) trait TransitCryptoInitFinalizer: Send { fn handshake_finalize( self: Box, socket: &mut dyn TransitTransport, ) -> BoxFuture>; } /// Due to poorly chosen abstractions elsewhere, the [`TransitCryptoInitFinalizer`] trait is also /// used by the follower side. Since it is a no-op there, simply implement the trait for the result. impl TransitCryptoInitFinalizer for DynTransitCrypto { fn handshake_finalize( self: Box, _socket: &mut dyn TransitTransport, ) -> BoxFuture> { Box::pin(futures::future::ready(Ok(*self))) } } /// Do a handshake. Multiple handshakes can be started from one instance on multiple streams. #[async_trait] pub(super) trait TransitCryptoInit: Send + Sync { // Yes, this method returns a nested future. TODO explain async fn handshake_leader( &self, socket: &mut dyn TransitTransport, ) -> Result, TransitHandshakeError>; async fn handshake_follower( &self, socket: &mut dyn TransitTransport, ) -> Result, TransitHandshakeError>; } /// The classic Transit cryptography backend, powered by libsodium's "Secretbox" API. /// /// The handshake looks like this (leader perspective): /// ```text /// -> transit sender ${transit_key.derive("transit_sender)")} ready\n\n /// <- transit receiver ${transit_key.derive("transit_receiver")} ready\n\n /// -> go\n /// ``` pub struct SecretboxInit { pub key: Arc>, } #[async_trait] impl TransitCryptoInit for SecretboxInit { async fn handshake_leader( &self, socket: &mut dyn TransitTransport, ) -> Result, TransitHandshakeError> { // 9. create record keys let rkey = self .key .derive_subkey_from_purpose("transit_record_receiver_key"); let skey = self .key .derive_subkey_from_purpose("transit_record_sender_key"); // for transmit mode, send send_handshake_msg and compare. // the received message with send_handshake_msg socket .write_all( format!( "transit sender {} ready\n\n", self.key .derive_subkey_from_purpose::("transit_sender") .to_hex() ) .as_bytes(), ) .await?; let expected_rx_handshake = format!( "transit receiver {} ready\n\n", self.key .derive_subkey_from_purpose::("transit_receiver") .to_hex() ); assert_eq!(expected_rx_handshake.len(), 89); socket.read_expect(expected_rx_handshake.as_bytes()).await?; struct Finalizer { skey: Key, rkey: Key, } impl TransitCryptoInitFinalizer for Finalizer { fn handshake_finalize( self: Box, socket: &mut dyn TransitTransport, ) -> BoxFuture> { Box::pin(async move { socket.write_all(b"go\n").await?; Ok::<_, TransitHandshakeError>(( Box::new(SecretboxCryptoEncrypt { skey: self.skey, snonce: Default::default(), }) as Box, Box::new(SecretboxCryptoDecrypt { rkey: self.rkey, rnonce: Default::default(), }) as Box, )) }) } } Ok(Box::new(Finalizer { skey, rkey })) } async fn handshake_follower( &self, socket: &mut dyn TransitTransport, ) -> Result, TransitHandshakeError> { // 9. create record keys /* The order here is correct. The "sender" and "receiver" side are a misnomer and should be called * "leader" and "follower" instead. As a follower, we use the leader key for receiving and our * key for sending. */ let rkey = self .key .derive_subkey_from_purpose("transit_record_sender_key"); let skey = self .key .derive_subkey_from_purpose("transit_record_receiver_key"); // for receive mode, send receive_handshake_msg and compare. // the received message with send_handshake_msg socket .write_all( format!( "transit receiver {} ready\n\n", self.key .derive_subkey_from_purpose::("transit_receiver") .to_hex(), ) .as_bytes(), ) .await?; let expected_tx_handshake = format!( "transit sender {} ready\n\ngo\n", self.key .derive_subkey_from_purpose::("transit_sender") .to_hex(), ); assert_eq!(expected_tx_handshake.len(), 90); socket.read_expect(expected_tx_handshake.as_bytes()).await?; Ok(Box::new(( Box::new(SecretboxCryptoEncrypt { skey, snonce: Default::default(), }) as Box, Box::new(SecretboxCryptoDecrypt { rkey, rnonce: Default::default(), }) as Box, )) as Box) } } type NoiseHandshakeState = noise_protocol::HandshakeState< noise_rust_crypto::X25519, noise_rust_crypto::ChaCha20Poly1305, noise_rust_crypto::Blake2s, >; type NoiseCipherState = noise_protocol::CipherState; /// Cryptography based on the [noise protocol](noiseprotocol.org). /// → "Magic-Wormhole Dilation Handshake v1 Leader\n\n" /// ← "Magic-Wormhole Dilation Handshake v1 Follower\n\n" /// → psk, e // Handshake /// ← e, ee /// ← "" // First real message /// → "" // Not in this method, to confirm the connection /// /// The noise protocol pattern used is "Noise_NNpsk0_25519_ChaChaPoly_BLAKE2s" pub struct NoiseInit { pub key: Arc>, } #[async_trait] impl TransitCryptoInit for NoiseInit { async fn handshake_leader( &self, socket: &mut dyn TransitTransport, ) -> Result, TransitHandshakeError> { socket .write_all(b"Magic-Wormhole Dilation Handshake v1 Leader\n\n") .await?; socket .read_expect(b"Magic-Wormhole Dilation Handshake v1 Follower\n\n") .await?; let mut handshake: NoiseHandshakeState = { let mut builder = noise_protocol::HandshakeStateBuilder::new(); builder.set_pattern(noise_protocol::patterns::noise_nn_psk0()); builder.set_prologue(&[]); builder.set_is_initiator(true); builder.build_handshake_state() }; handshake.push_psk(&self.key); // → psk, e socket .write_transit_message(&handshake.write_message_vec(&[])?) .await?; // ← e, ee handshake.read_message(&socket.read_transit_message().await?, &mut [])?; assert!(handshake.completed()); let (tx, mut rx) = handshake.get_ciphers(); // ← "" let peer_confirmation_message = rx.decrypt_vec(&socket.read_transit_message().await?)?; ensure!( peer_confirmation_message.is_empty(), TransitHandshakeError::HandshakeFailed ); struct Finalizer { tx: NoiseCipherState, rx: NoiseCipherState, } impl TransitCryptoInitFinalizer for Finalizer { fn handshake_finalize( mut self: Box, socket: &mut dyn TransitTransport, ) -> BoxFuture> { Box::pin(async move { // → "" socket .write_transit_message(&self.tx.encrypt_vec(&[])) .await?; Ok::<_, TransitHandshakeError>(( Box::new(NoiseCryptoEncrypt { tx: self.tx }) as Box, Box::new(NoiseCryptoDecrypt { rx: self.rx }) as Box, )) }) } } Ok(Box::new(Finalizer { tx, rx })) } async fn handshake_follower( &self, socket: &mut dyn TransitTransport, ) -> Result, TransitHandshakeError> { socket .write_all(b"Magic-Wormhole Dilation Handshake v1 Follower\n\n") .await?; socket .read_expect(b"Magic-Wormhole Dilation Handshake v1 Leader\n\n") .await?; let mut handshake: NoiseHandshakeState = { let mut builder = noise_protocol::HandshakeStateBuilder::new(); builder.set_pattern(noise_protocol::patterns::noise_nn_psk0()); builder.set_prologue(&[]); builder.set_is_initiator(false); builder.build_handshake_state() }; handshake.push_psk(&self.key); // ← psk, e handshake.read_message(&socket.read_transit_message().await?, &mut [])?; // → e, ee socket .write_transit_message(&handshake.write_message_vec(&[])?) .await?; assert!(handshake.completed()); // Warning: rx and tx are swapped here (read the `get_ciphers` doc carefully) let (mut rx, mut tx) = handshake.get_ciphers(); // → "" socket.write_transit_message(&tx.encrypt_vec(&[])).await?; // ← "" let peer_confirmation_message = rx.decrypt_vec(&socket.read_transit_message().await?)?; ensure!( peer_confirmation_message.is_empty(), TransitHandshakeError::HandshakeFailed ); Ok(Box::new(( Box::new(NoiseCryptoEncrypt { tx }) as Box, Box::new(NoiseCryptoDecrypt { rx }) as Box, )) as Box) } } type DynTransitCrypto = (Box, Box); #[async_trait] pub(super) trait TransitCryptoEncrypt: Send { async fn encrypt( &mut self, socket: &mut dyn TransitTransportTx, plaintext: &[u8], ) -> Result<(), TransitError>; } #[async_trait] pub(super) trait TransitCryptoDecrypt: Send { async fn decrypt( &mut self, socket: &mut dyn TransitTransportRx, ) -> Result, TransitError>; } struct SecretboxCryptoEncrypt { /** Our key, used for sending */ pub skey: Key, /** Nonce for sending */ pub snonce: secretbox::Nonce, } struct SecretboxCryptoDecrypt { /** Their key, used for receiving */ pub rkey: Key, /** * Nonce for receiving * * We'll count as receiver and track if messages come in in order */ pub rnonce: secretbox::Nonce, } #[async_trait] impl TransitCryptoEncrypt for SecretboxCryptoEncrypt { async fn encrypt( &mut self, socket: &mut dyn TransitTransportTx, plaintext: &[u8], ) -> Result<(), TransitError> { let nonce = &mut self.snonce; let sodium_key = secretbox::Key::from_slice(&self.skey); let ciphertext = { let nonce_le = secretbox::Nonce::from_slice(nonce); let cipher = secretbox::XSalsa20Poly1305::new(sodium_key); cipher .encrypt(nonce_le, plaintext) /* TODO replace with (TransitError::Crypto) after the next xsalsa20poly1305 update */ .map_err(|_| TransitError::Crypto)? }; // send the encrypted record socket .write_all(&((ciphertext.len() + nonce.len()) as u32).to_be_bytes()) .await?; socket.write_all(nonce).await?; socket.write_all(&ciphertext).await?; crate::util::sodium_increment_be(nonce); Ok(()) } } #[async_trait] impl TransitCryptoDecrypt for SecretboxCryptoDecrypt { async fn decrypt( &mut self, socket: &mut dyn TransitTransportRx, ) -> Result, TransitError> { let nonce = &mut self.rnonce; let enc_packet = socket.read_transit_message().await?; use std::io::{Error, ErrorKind}; ensure!( enc_packet.len() >= secretbox::SecretBox::::NONCE_SIZE, Error::new( ErrorKind::InvalidData, "Message must be long enough to contain at least the nonce" ) ); // 3. decrypt the vector 'enc_packet' with the key. let plaintext = { let (received_nonce, ciphertext) = enc_packet .split_at(secretbox::SecretBox::::NONCE_SIZE); { // Nonce check ensure!( nonce.as_slice() == received_nonce, TransitError::Nonce(received_nonce.into(), nonce.as_slice().into()), ); crate::util::sodium_increment_be(nonce); } let cipher = secretbox::XSalsa20Poly1305::new(secretbox::Key::from_slice(&self.rkey)); cipher .decrypt(secretbox::Nonce::from_slice(received_nonce), ciphertext) /* TODO replace with (TransitError::Crypto) after the next xsalsa20poly1305 update */ .map_err(|_| TransitError::Crypto)? }; Ok(plaintext.into_boxed_slice()) } } struct NoiseCryptoEncrypt { tx: NoiseCipherState, } struct NoiseCryptoDecrypt { rx: NoiseCipherState, } #[async_trait] impl TransitCryptoEncrypt for NoiseCryptoEncrypt { async fn encrypt( &mut self, socket: &mut dyn TransitTransportTx, plaintext: &[u8], ) -> Result<(), TransitError> { socket .write_transit_message(&self.tx.encrypt_vec(plaintext)) .await?; Ok(()) } } #[async_trait] impl TransitCryptoDecrypt for NoiseCryptoDecrypt { async fn decrypt( &mut self, socket: &mut dyn TransitTransportRx, ) -> Result, TransitError> { let plaintext = self.rx.decrypt_vec(&socket.read_transit_message().await?)?; Ok(plaintext.into_boxed_slice()) } } magic-wormhole-0.7.6/src/transit/transport.rs000064400000000000000000000260741046102023000174360ustar 00000000000000//! Helper functions abstracting away different transport protocols for Transit use super::{ConnectionType, TransitConnection, TransitHandshakeError, TransitInfo}; #[cfg(not(target_family = "wasm"))] use super::{DirectHint, StunError}; #[cfg(not(target_family = "wasm"))] use async_std::net::TcpStream; use async_trait::async_trait; use futures::{ future::TryFutureExt, io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, }; #[cfg(not(target_family = "wasm"))] use std::{ net::{IpAddr, SocketAddr, ToSocketAddrs}, sync::Arc, }; #[async_trait] pub(super) trait TransitTransportRx: AsyncRead + std::any::Any + Unpin + Send { /// Helper method for handshake: read a fixed number of bytes and make sure they are as expected async fn read_expect(&mut self, expected: &[u8]) -> Result<(), TransitHandshakeError> { let mut buffer = vec![0u8; expected.len()]; self.read_exact(&mut buffer).await?; ensure!(buffer == expected, TransitHandshakeError::HandshakeFailed); Ok(()) } /// Helper method: read a four bytes length prefix then the appropriate number of bytes async fn read_transit_message(&mut self) -> Result, std::io::Error> { // 1. read 4 bytes from the stream. This represents the length of the encrypted packet. let length = { let mut length_arr: [u8; 4] = [0; 4]; self.read_exact(&mut length_arr[..]).await?; u32::from_be_bytes(length_arr) as usize }; // 2. read that many bytes into an array (or a vector?) let mut buffer = Vec::with_capacity(length); let len = self.take(length as u64).read_to_end(&mut buffer).await?; use std::io::{Error, ErrorKind}; ensure!( len == length, Error::new(ErrorKind::UnexpectedEof, "failed to read whole message") ); Ok(buffer) } } #[async_trait] pub(super) trait TransitTransportTx: AsyncWrite + std::any::Any + Unpin + Send { /// Helper method: write the message length then the message async fn write_transit_message(&mut self, message: &[u8]) -> Result<(), std::io::Error> { // send the encrypted record self.write_all(&(message.len() as u32).to_be_bytes()) .await?; self.write_all(message).await } } /// Trait abstracting our socket used for communicating over the wire. /// /// Will be primarily instantiated by either a TCP or web socket. Custom methods /// will be added in the future. pub(super) trait TransitTransport: TransitTransportRx + TransitTransportTx {} impl TransitTransportRx for T where T: AsyncRead + std::any::Any + Unpin + Send {} impl TransitTransportTx for T where T: AsyncWrite + std::any::Any + Unpin + Send {} impl TransitTransport for T where T: AsyncRead + AsyncWrite + std::any::Any + Unpin + Send {} #[cfg(not(target_family = "wasm"))] pub(super) fn set_socket_opts(socket: &socket2::Socket) -> std::io::Result<()> { socket.set_nonblocking(true)?; /* Explicitly make the socket dual-stack, otherwise IPv4 won't work on some platforms * where IPV6_V6ONLY is enabled by default (e.g. Windows) or by system configuration. */ socket.set_only_v6(false)?; /* See https://stackoverflow.com/a/14388707/6094756. * On most BSD and Linux systems, we need both REUSEADDR and REUSEPORT; * and if they don't support the latter we won't compile. * On Windows, there is only REUSEADDR but it does what we want. */ socket.set_reuse_address(true)?; #[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))] { socket.set_reuse_port(true)?; } #[cfg(not(any( all(unix, not(any(target_os = "solaris", target_os = "illumos"))), target_os = "windows" )))] { compile_error!("Your system is not supported yet, please raise an error"); } Ok(()) } /** Perform a STUN query to get the external IP address */ #[cfg(not(target_family = "wasm"))] pub(super) async fn tcp_get_external_ip() -> Result<(SocketAddr, TcpStream), StunError> { let mut socket = tcp_connect_custom( &"[::]:0".parse::().unwrap().into(), &super::PUBLIC_STUN_SERVER .to_socket_addrs()? /* If you find yourself behind a NAT66, open an issue */ .find(|x| x.is_ipv4()) /* TODO add a helper method to stdlib for this */ .map(|addr| match addr { SocketAddr::V4(v4) => { SocketAddr::new(IpAddr::V6(v4.ip().to_ipv6_mapped()), v4.port()) }, SocketAddr::V6(_) => unreachable!(), }) .ok_or(StunError::ServerIsV6Only)? .into(), ) .await?; use bytecodec::{DecodeExt, EncodeExt}; use stun_codec::{ rfc5389::{ self, attributes::{MappedAddress, Software, XorMappedAddress}, Attribute, }, Message, MessageClass, MessageDecoder, MessageEncoder, TransactionId, }; fn get_binding_request() -> Result, bytecodec::Error> { use rand::Rng; let random_bytes = rand::thread_rng().gen::<[u8; 12]>(); let mut message: Message = Message::new( MessageClass::Request, rfc5389::methods::BINDING, TransactionId::new(random_bytes), ); message.add_attribute(Attribute::Software(Software::new( "magic-wormhole-rust".to_owned(), )?)); // Encodes the message let mut encoder = MessageEncoder::new(); let bytes = encoder.encode_into_bytes(message.clone())?; Ok(bytes) } fn decode_address(buf: &[u8]) -> Result, bytecodec::Error> { let mut decoder = MessageDecoder::::new(); let decoded = decoder.decode_from_bytes(buf)??; let external_addr1 = decoded .get_attribute::() .map(|x| x.address()); //let external_addr2 = decoded.get_attribute::().map(|x|x.address()); let external_addr3 = decoded .get_attribute::() .map(|x| x.address()); let external_addr = external_addr1 // .or(external_addr2) .or(external_addr3); Ok(external_addr) } /* Connect the plugs */ socket.write_all(get_binding_request()?.as_ref()).await?; let mut buf = [0u8; 256]; /* Read header first */ socket.read_exact(&mut buf[..20]).await?; let len: u16 = u16::from_be_bytes([buf[2], buf[3]]); /* Read the rest of the message */ socket.read_exact(&mut buf[20..][..len as usize]).await?; let external_addr = decode_address(&buf[..20 + len as usize])?.ok_or(StunError::ServerNoResponse)?; Ok((external_addr, socket)) } /** * Bind to a port with SO_REUSEADDR, connect to the destination and then hide the blood behind a pretty [`async_std::net::TcpStream`] * * We want an `async_std::net::TcpStream`, but with SO_REUSEADDR set. * The former is just a wrapper around `async_io::Async`, of which we * copy the `connect` method to add a statement that will set the socket flag. * See https://github.com/smol-rs/async-net/issues/20. */ #[cfg(not(target_family = "wasm"))] async fn tcp_connect_custom( local_addr: &socket2::SockAddr, dest_addr: &socket2::SockAddr, ) -> std::io::Result { tracing::debug!("Binding to {}", local_addr.as_socket().unwrap()); let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::STREAM, None)?; /* Set our custum options */ set_socket_opts(&socket)?; socket.bind(local_addr)?; /* Initiate connect */ match socket.connect(dest_addr) { Ok(_) => {}, #[cfg(unix)] Err(err) if err.raw_os_error() == Some(libc::EINPROGRESS) => {}, Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => {}, Err(err) => return Err(err), } let stream = async_io::Async::new(std::net::TcpStream::from(socket))?; /* The stream becomes writable when connected. */ stream.writable().await?; /* Check if there was an error while connecting. */ stream .get_ref() .take_error() .and_then(|maybe_err| maybe_err.map_or(Ok(()), Result::Err))?; /* Convert our mess to `async_std::net::TcpStream */ Ok(stream.into_inner()?.into()) } #[cfg(not(target_family = "wasm"))] pub(super) async fn connect_tcp_direct( local_addr: Option>, hint: DirectHint, ) -> Result { let dest_addr = SocketAddr::try_from(&hint)?; tracing::debug!("Connecting directly to {}", dest_addr); let socket; if let Some(local_addr) = local_addr { socket = tcp_connect_custom(&local_addr, &dest_addr.into()).await?; tracing::debug!("Connected to {}!", dest_addr); } else { socket = async_std::net::TcpStream::connect(&dest_addr).await?; tracing::debug!("Connected to {}!", dest_addr); } wrap_tcp_connection(socket, ConnectionType::Direct) } /* Take a relay hint and try to connect to it */ #[cfg(not(target_family = "wasm"))] pub(super) async fn connect_tcp_relay( host: DirectHint, name: Option, ) -> Result { tracing::debug!("Connecting to relay {}", host); let socket = TcpStream::connect((host.hostname.as_str(), host.port)) .err_into::() .await?; tracing::debug!("Connected to {}!", host); wrap_tcp_connection(socket, ConnectionType::Relay { name }) } #[cfg(target_family = "wasm")] pub(super) async fn connect_ws_relay( url: url::Url, name: Option, ) -> Result { tracing::debug!("Connecting to relay {}", url); let (_meta, transit) = ws_stream_wasm::WsMeta::connect(&url, None) .err_into::() .await?; tracing::debug!("Connected to {}!", url); let transit = Box::new(transit.into_io()) as Box; Ok(( transit, TransitInfo { conn_type: ConnectionType::Relay { name }, }, )) } /* Take a tcp connection and transform it into a `TransitConnection` (mainly set timeouts) */ #[cfg(not(target_family = "wasm"))] pub(super) fn wrap_tcp_connection( socket: TcpStream, conn_type: ConnectionType, ) -> Result { /* Set proper read and write timeouts. This will temporarily set the socket into blocking mode :/ */ // https://github.com/async-rs/async-std/issues/499 let socket = std::net::TcpStream::try_from(socket) .expect("Internal error: this should not fail because we never cloned the socket"); socket.set_write_timeout(Some(std::time::Duration::from_secs(120)))?; socket.set_read_timeout(Some(std::time::Duration::from_secs(120)))?; let socket: TcpStream = socket.into(); let info = TransitInfo { conn_type, peer_addr: socket .peer_addr() .expect("Internal error: socket must be IP"), }; Ok((Box::new(socket), info)) } magic-wormhole-0.7.6/src/transit.rs000064400000000000000000001554461046102023000154100ustar 00000000000000//! Connect two sides via TCP, no matter where they are //! //! This protocol is the second part where the Wormhole magic happens. It does not strictly require a Wormhole connection, //! but it depends on some kind of secure communication channel to talk to the other side. Conveniently, Wormhole provides //! exactly such a thing :) //! //! Both clients exchange messages containing hints on how to find each other. These may be local IP addresses for in case they //! are in the same network, or the URL to a relay server. In case a direct connection fails, both will connect to the relay server //! which will transparently glue the connections together. //! //! Each side might implement (or use/enable) some [abilities](Abilities). //! //! **Notice:** while the resulting TCP connection is naturally bi-directional, the handshake is not symmetric. There *must* be one //! "leader" side and one "follower" side (formerly called "sender" and "receiver"). #[allow(deprecated)] use crate::{Key, KeyPurpose}; use serde_derive::{Deserialize, Serialize}; #[cfg(not(target_family = "wasm"))] use async_std::net::{TcpListener, TcpStream}; #[allow(unused_imports)] /* We need them for the docs */ use futures::{ future::FutureExt, future::TryFutureExt, io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, Sink, SinkExt, Stream, StreamExt, TryStreamExt, }; use std::{ collections::HashSet, net::{IpAddr, SocketAddr}, sync::Arc, time::Instant, }; mod crypto; mod transport; use crypto::TransitHandshakeError; use transport::{TransitTransport, TransitTransportRx, TransitTransportTx}; /// ULR to a default hosted relay server. Please don't abuse or DOS. pub const DEFAULT_RELAY_SERVER: &str = "tcp://transit.magic-wormhole.io:4001"; // No need to make public, it's hard-coded anyways (: // Open an issue if you want an API for this // Use for non-production testing #[cfg(not(target_family = "wasm"))] const PUBLIC_STUN_SERVER: &str = "stun.piegames.de:3478"; /// Deprecated: This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] #[derive(Debug)] pub struct TransitKey; #[allow(deprecated)] impl KeyPurpose for TransitKey {} /// Deprecated: This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] #[derive(Debug)] pub struct TransitRxKey; #[allow(deprecated)] impl KeyPurpose for TransitRxKey {} /// Deprecated: This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] #[derive(Debug)] pub struct TransitTxKey; #[allow(deprecated)] impl KeyPurpose for TransitTxKey {} /// An error occurred when connecting to the peer. #[derive(Debug, thiserror::Error)] #[non_exhaustive] pub enum TransitConnectError { /// Incompatible abilities, or wrong hints #[error("{}", _0)] Protocol(Box), /// All (relay) handshakes failed or timed out; could not establish a connection with the peer #[error("All (relay) handshakes failed or timed out; could not establish a connection with the peer")] Handshake, /// I/O error #[error("I/O error")] IO( #[from] #[source] std::io::Error, ), /// WASM error #[cfg(target_family = "wasm")] #[error("WASM error")] WASM( #[from] #[source] ws_stream_wasm::WsErr, ), } /// An error occurred during transit #[derive(Debug, thiserror::Error)] #[non_exhaustive] pub enum TransitError { /// Cryptography error. This is probably an implementation bug, but may also be caused by an attack #[error("Cryptography error. This is probably an implementation bug, but may also be caused by an attack.")] Crypto, /// Wrong nonce received, got {:x?} but expected {:x?}. This is probably an implementation bug, but may also be caused by an attack #[error("Wrong nonce received, got {:x?} but expected {:x?}. This is probably an implementation bug, but may also be caused by an attack.", _0, _1)] Nonce(Box<[u8]>, Box<[u8]>), /// I/O error #[error("I/O error")] IO( #[from] #[source] std::io::Error, ), /// WASM error #[cfg(target_family = "wasm")] #[error("WASM error")] WASM( #[from] #[source] ws_stream_wasm::WsErr, ), } impl From<()> for TransitError { fn from(_: ()) -> Self { Self::Crypto } } /** * Defines a way to find the other side. * * Each ability comes with a set of [`Hints`] to encode how to meet up. */ #[derive(Copy, Clone, Debug, Default)] pub struct Abilities { /** Direct connection to the peer */ pub direct_tcp_v1: bool, /** Connection over a relay */ pub relay_v1: bool, #[cfg(any())] /** **Experimental** Use the [noise protocol](https://noiseprotocol.org) for the encryption. */ pub noise_v1: bool, } impl Abilities { /// The abilities preset that contains all abilities pub const ALL: Self = Self { direct_tcp_v1: true, relay_v1: true, #[cfg(any())] noise_v1: false, }; /// The abilities preset that contains all abilities #[deprecated(since = "0.7.0", note = "use Abilities::ALL")] pub const ALL_ABILITIES: Self = Self::ALL; /** * If you absolutely don't want to use any relay servers. * * If the other side forces relay usage or doesn't support any of your connection modes * the attempt will fail. */ pub const FORCE_DIRECT: Self = Self { direct_tcp_v1: true, relay_v1: false, #[cfg(any())] noise_v1: false, }; /** * If you don't want to disclose your IP address to your peer * * If the other side forces a the usage of a direct connection the attempt will fail. * Note that the other side might control the relay server being used, if you really * don't want your IP to potentially be disclosed use TOR instead (not supported by * the Rust implementation yet). */ pub const FORCE_RELAY: Self = Self { direct_tcp_v1: false, relay_v1: true, #[cfg(any())] noise_v1: false, }; /// Whether direct transfer is allowed pub fn can_direct(&self) -> bool { self.direct_tcp_v1 } /// Whether relay transfer is allowed pub fn can_relay(&self) -> bool { self.relay_v1 } #[cfg(any())] pub fn can_noise_crypto(&self) -> bool { self.noise_v1 } /// Whether noise cryptography is supported #[deprecated(since = "0.7.0", note = "Noise cryptography is not standardized")] pub fn can_noise_crypto(&self) -> bool { false } /// Keep only abilities that both sides support pub fn intersect(mut self, other: &Self) -> Self { self.direct_tcp_v1 &= other.direct_tcp_v1; self.relay_v1 &= other.relay_v1; #[cfg(any())] { self.noise_v1 &= other.noise_v1; } self } } impl serde::Serialize for Abilities { fn serialize(&self, ser: S) -> Result where S: serde::Serializer, { let mut hints = Vec::new(); if self.direct_tcp_v1 { hints.push(serde_json::json!({ "type": "direct-tcp-v1", })); } if self.relay_v1 { hints.push(serde_json::json!({ "type": "relay-v1", })); } #[cfg(any())] if self.noise_v1 { hints.push(serde_json::json!({ "type": "noise-crypto-v1", })); } serde_json::Value::Array(hints).serialize(ser) } } impl<'de> serde::Deserialize<'de> for Abilities { fn deserialize(de: D) -> Result where D: serde::Deserializer<'de>, { #[derive(Deserialize)] #[serde(rename_all = "kebab-case", tag = "type")] enum Ability { DirectTcpV1, RelayV1, RelayV2, #[cfg(any())] NoiseCryptoV1, #[serde(other)] Other, } let mut abilities = Self::default(); /* Specifying a hint multiple times is undefined behavior. Here, we simply merge all features. */ for ability in as serde::Deserialize>::deserialize(de)? { match ability { Ability::DirectTcpV1 => { abilities.direct_tcp_v1 = true; }, Ability::RelayV1 => { abilities.relay_v1 = true; }, #[cfg(any())] Ability::NoiseCryptoV1 => { abilities.noise_v1 = true; }, _ => (), } } Ok(abilities) } } /* Wire representation of a single hint */ #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all = "kebab-case", tag = "type")] #[non_exhaustive] enum HintSerde { DirectTcpV1(DirectHint), RelayV1(RelayHint), #[serde(other)] Unknown, } /** Information about how to find a peer */ #[derive(Clone, Debug, Default)] pub struct Hints { /** Hints for direct connection */ pub direct_tcp: HashSet, /** List of relay servers */ pub relay: Vec, } impl Hints { /// Create new hints pub fn new( direct_tcp: impl IntoIterator, relay: impl IntoIterator, ) -> Self { Self { direct_tcp: direct_tcp.into_iter().collect(), relay: relay.into_iter().collect(), } } } impl<'de> serde::Deserialize<'de> for Hints { fn deserialize(de: D) -> Result where D: serde::Deserializer<'de>, { let hints: Vec = serde::Deserialize::deserialize(de)?; let mut direct_tcp = HashSet::new(); let mut relay = Vec::::new(); let mut relay_v2 = Vec::::new(); for hint in hints { match hint { HintSerde::DirectTcpV1(hint) => { direct_tcp.insert(hint); }, HintSerde::RelayV1(hint) => { relay_v2.push(hint); }, /* Ignore unknown hints */ _ => {}, } } /* If there are any relay-v2 hints, there relay-v1 are redundant */ if !relay_v2.is_empty() { relay.clear(); } relay.extend(relay_v2); Ok(Hints { direct_tcp, relay }) } } impl serde::Serialize for Hints { fn serialize(&self, ser: S) -> Result where S: serde::Serializer, { let direct = self.direct_tcp.iter().cloned().map(HintSerde::DirectTcpV1); let relay = self.relay.iter().cloned().map(HintSerde::RelayV1); ser.collect_seq(direct.chain(relay)) } } /** hostname and port for direct connection */ #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Hash, derive_more::Display)] #[display("tcp://{}:{}", hostname, port)] pub struct DirectHint { // DirectHint also contains a `priority` field, but it is underspecified // and we won't use it // pub priority: f32, /// The hostname via which to reach this peer pub hostname: String, /// The port to use pub port: u16, } impl DirectHint { /// Create a new direct hint pub fn new(hostname: impl Into, port: u16) -> Self { Self { hostname: hostname.into(), port, } } } /* Wire representation of a single relay hint (Helper struct for serialization) */ #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all = "kebab-case", tag = "type")] #[non_exhaustive] struct RelayHintSerde { name: Option, #[serde(rename = "hints")] endpoints: Vec, } /* Wire representation of a single relay endpoint (Helper struct for serialization) */ #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all = "kebab-case", tag = "type")] #[non_exhaustive] enum RelayHintSerdeInner { #[serde(rename = "direct-tcp-v1")] Tcp(DirectHint), Websocket { url: url::Url, }, #[serde(other)] Unknown, } #[derive(Debug, thiserror::Error)] #[non_exhaustive] /// An error occurred while parsing a relay hint pub enum RelayHintParseError { #[error( "Invalid TCP hint endpoint: '{}' (Does it have hostname and port?)", _0 )] /// Invalid TCP hint endpoint InvalidTcp(url::Url), #[error( "Unknown schema: '{}'. Currently known values are 'tcp', 'ws' and 'wss'.", _0 )] /// Unknown schema. Currently known values are 'tcp', 'ws' and 'wss'. UnknownSchema(Box), #[error("'{}' is not an absolute URL (must start with a '/')", _0)] /// The provided URL is not absolute UrlNotAbsolute(url::Url), } /** * Hint describing a relay server * * A server may be reachable at multiple locations. Any two must be relayable * over that server, therefore a client may pick only one of these per hint. * * All locations are URLs, but here they are already deconstructed and grouped * by schema out of convenience. */ /* RelayHint::default() gives the empty server (cannot be reached), and is only there for struct update syntax */ #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct RelayHint { /** Human readable name. The expectation is that when a server has multiple endpoints, the * expectation is that the domain name is used as name */ pub name: Option, /** TCP endpoints of that relay */ pub tcp: HashSet, /** WebSockets endpoints of that relay */ pub ws: HashSet, } impl RelayHint { /// Create a new relay hint pub fn new( name: Option, tcp: impl IntoIterator, ws: impl IntoIterator, ) -> Self { Self { name, tcp: tcp.into_iter().collect(), ws: ws.into_iter().collect(), } } /// Construct a relay hint from a list of multiple endpoints, and optionally a name. /// /// Not all URLs are acceptable, therefore this method is fallible. Especially, TCP endpoints /// must be encoded as `tcp://hostname:port`. All URLs must be absolute, i.e. start with a `/`. /// /// Basic usage (default server): /// /// ``` /// use magic_wormhole::transit; /// let hint = /// transit::RelayHint::from_urls(None, [transit::DEFAULT_RELAY_SERVER.parse().unwrap()]) /// .unwrap(); /// ``` /// /// Custom relay server from url with name: /// /// ``` /// use magic_wormhole::transit; /// # let url: url::Url = transit::DEFAULT_RELAY_SERVER.parse().unwrap(); /// let hint = transit::RelayHint::from_urls(url.host_str().map(str::to_owned), [url]).unwrap(); /// ``` pub fn from_urls( name: Option, urls: impl IntoIterator, ) -> Result { let mut this = Self { name, ..Self::default() }; for url in urls.into_iter() { ensure!( !url.cannot_be_a_base(), RelayHintParseError::UrlNotAbsolute(url) ); match url.scheme() { "tcp" => { /* Using match */ let (hostname, port) = match (url.host_str(), url.port()) { (Some(hostname), Some(port)) => (hostname.into(), port), _ => bail!(RelayHintParseError::InvalidTcp(url)), }; this.tcp.insert(DirectHint { hostname, port }); }, "ws" | "wss" => { this.ws.insert(url); }, other => bail!(RelayHintParseError::UnknownSchema(other.into())), } } assert!( !this.tcp.is_empty() || !this.ws.is_empty(), "No URLs provided" ); Ok(this) } #[deprecated( since = "0.7.0", note = "This will be a private method in the future. Open an issue if you require access to protocol intrinsics in the future" )] /// Whether the relay server is probably the same pub fn can_merge(&self, other: &Self) -> bool { !self.tcp.is_disjoint(&other.tcp) || !self.ws.is_disjoint(&other.ws) } #[deprecated( since = "0.7.0", note = "This will be a private method in the future. Open an issue if you require access to protocol intrinsics in the future" )] /// Extend this server with additional endpoints pub fn merge(mut self, other: Self) -> Self { #[allow(deprecated)] self.merge_mut(other); self } #[deprecated( since = "0.7.0", note = "This will be a private method in the future. Open an issue if you require access to protocol intrinsics in the future" )] /// Extend this server with additional endpoints pub fn merge_mut(&mut self, other: Self) { self.tcp.extend(other.tcp); self.ws.extend(other.ws); } #[deprecated( since = "0.7.0", note = "This will be a private method in the future. Open an issue if you require access to protocol intrinsics in the future" )] #[allow(deprecated)] /// Deduplicate and merge the hints us into theirs pub fn merge_into(self, collection: &mut Vec) { for item in collection.iter_mut() { if item.can_merge(&self) { item.merge_mut(self); return; } } collection.push(self); } } impl serde::Serialize for RelayHint { fn serialize(&self, ser: S) -> Result where S: serde::Serializer, { let mut hints = Vec::new(); hints.extend(self.tcp.iter().cloned().map(RelayHintSerdeInner::Tcp)); hints.extend( self.ws .iter() .cloned() .map(|h| RelayHintSerdeInner::Websocket { url: h }), ); serde_json::json!({ "name": self.name, "hints": hints, }) .serialize(ser) } } impl<'de> serde::Deserialize<'de> for RelayHint { fn deserialize(de: D) -> Result where D: serde::Deserializer<'de>, { let raw = RelayHintSerde::deserialize(de)?; let mut hint = RelayHint { name: raw.name, tcp: HashSet::new(), ws: HashSet::new(), }; for e in raw.endpoints { match e { RelayHintSerdeInner::Tcp(tcp) => { hint.tcp.insert(tcp); }, RelayHintSerdeInner::Websocket { url } => { hint.ws.insert(url); }, /* Ignore unknown hints */ _ => {}, } } Ok(hint) } } impl TryFrom<&DirectHint> for IpAddr { type Error = std::net::AddrParseError; fn try_from(hint: &DirectHint) -> Result { hint.hostname.parse() } } impl TryFrom<&DirectHint> for SocketAddr { type Error = std::net::AddrParseError; /** This does not do the obvious thing and also implicitly maps all V4 addresses into V6 */ fn try_from(hint: &DirectHint) -> Result { let addr = hint.try_into()?; let addr = match addr { IpAddr::V4(v4) => IpAddr::V6(v4.to_ipv6_mapped()), IpAddr::V6(_) => addr, }; Ok(SocketAddr::new(addr, hint.port)) } } /// Direct or relay #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum ConnectionType { /// We are directly connected to our peer Direct, /// We are connected to a relay server, and may even know its name Relay { /// The name of the relay server name: Option, }, } /// Metadata for the established transit connection #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub struct TransitInfo { /// Whether we are connected directly or via a relay server pub conn_type: ConnectionType, /// Target address of our connection. This may be our peer, or the relay server. /// This says nothing about the actual transport protocol used. #[cfg(not(target_family = "wasm"))] pub peer_addr: SocketAddr, } type TransitConnection = (Box, TransitInfo); #[cfg(not(target_family = "wasm"))] #[derive(Debug, thiserror::Error)] enum StunError { #[error("No IPv4 addresses were found for the selected STUN server")] ServerIsV6Only, #[error("Server did not tell us our IP address")] ServerNoResponse, #[error("Connection timed out")] Timeout, #[error("IO error")] IO( #[from] #[source] std::io::Error, ), #[error("Malformed STUN packet")] Codec( #[from] #[source] bytecodec::Error, ), } #[cfg(not(target_family = "wasm"))] impl std::fmt::Display for TransitInfo { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.conn_type { ConnectionType::Direct => { write!( f, "Established direct transit connection to '{}'", self.peer_addr, ) }, ConnectionType::Relay { name: Some(name) } => { write!( f, "Established transit connection via relay '{}' ({})", name, self.peer_addr, ) }, ConnectionType::Relay { name: None } => { write!( f, "Established transit connection via relay ({})", self.peer_addr, ) }, } } } #[cfg(target_family = "wasm")] impl std::fmt::Display for TransitInfo { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.conn_type { ConnectionType::Direct => { write!(f, "Established direct transit connection",) }, ConnectionType::Relay { name: Some(name) } => { write!(f, "Established transit connection via relay '{}'", name) }, ConnectionType::Relay { name: None } => { write!(f, "Established transit connection via relay",) }, } } } #[deprecated( since = "0.7.0", note = "use the `Display` implementation of `TransitInfo` instead" )] /// Deprecated: use the `Display` implementation of `TransitInfo` instead pub fn log_transit_connection( conn_type: ConnectionType, #[cfg(not(target_family = "wasm"))] peer_addr: SocketAddr, ) { let info = TransitInfo { conn_type, #[cfg(not(target_family = "wasm"))] peer_addr, }; tracing::info!("{info}"); } /** * Initialize a relay handshake * * Bind a port and generate our [`Hints`]. This does not do any communication yet. */ #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] #[allow(deprecated)] pub async fn init( mut abilities: Abilities, peer_abilities: Option, relay_hints: Vec, ) -> Result { let mut our_hints = Hints::default(); #[cfg(not(target_family = "wasm"))] let mut sockets = None; if let Some(peer_abilities) = peer_abilities { abilities = abilities.intersect(&peer_abilities); } /* Detect our IP addresses if the ability is enabled */ #[cfg(not(target_family = "wasm"))] if abilities.can_direct() { let create_sockets = async { /* Do a STUN query to get our public IP. If it works, we must reuse the same socket (port) * so that we will be NATted to the same port again. If it doesn't, simply bind a new socket * and use that instead. */ let socket: MaybeConnectedSocket = match async_std::future::timeout( std::time::Duration::from_secs(4), transport::tcp_get_external_ip(), ) .await .map_err(|_| StunError::Timeout) { Ok(Ok((external_ip, stream))) => { tracing::debug!("Our external IP address is {}", external_ip); our_hints.direct_tcp.insert(DirectHint { hostname: external_ip.ip().to_string(), port: external_ip.port(), }); tracing::debug!( "Our socket for connecting is bound to {} and connected to {}", stream.local_addr()?, stream.peer_addr()?, ); stream.into() }, // TODO replace with .flatten() once stable // https://github.com/rust-lang/rust/issues/70142 Err(err) | Ok(Err(err)) => { tracing::warn!("Failed to get external address via STUN, {}", err); let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::STREAM, None)?; transport::set_socket_opts(&socket)?; socket.bind(&"[::]:0".parse::().unwrap().into())?; tracing::debug!( "Our socket for connecting is bound to {}", socket.local_addr()?.as_socket().unwrap(), ); socket.into() }, }; /* Get a second socket, but this time open a listener on that port. * This sadly doubles the number of hints, but the method above doesn't work * for systems which don't have any firewalls. Also, this time we can't reuse * the port. In theory, we could, but it really confused the kernel to the point * of `accept` calls never returning again. */ let listener = TcpListener::bind("[::]:0").await?; /* Find our ports, iterate all our local addresses, combine them with the ports and that's our hints */ let port = socket.local_addr()?.as_socket().unwrap().port(); let port2 = listener.local_addr()?.port(); our_hints.direct_tcp.extend( if_addrs::get_if_addrs()? .iter() .filter(|iface| !iface.is_loopback()) .flat_map(|ip| { [ DirectHint { hostname: ip.ip().to_string(), port, }, DirectHint { hostname: ip.ip().to_string(), port: port2, }, ] .into_iter() }), ); tracing::debug!("Our socket for listening is {}", listener.local_addr()?); Ok::<_, std::io::Error>((socket, listener)) }; sockets = create_sockets .await // TODO replace with inspect_err once stable .map_err(|err| { tracing::error!("Failed to create direct hints for our side: {}", err); err }) .ok(); } if abilities.can_relay() { our_hints.relay.extend(relay_hints); } Ok(TransitConnector { #[cfg(not(target_family = "wasm"))] sockets, our_abilities: abilities, our_hints: Arc::new(our_hints), }) } /// Bound socket, maybe also connected. Guaranteed to have SO_REUSEADDR. #[cfg(not(target_family = "wasm"))] #[derive(derive_more::From)] enum MaybeConnectedSocket { #[from] Socket(socket2::Socket), #[from] Stream(TcpStream), } #[cfg(not(target_family = "wasm"))] impl MaybeConnectedSocket { fn local_addr(&self) -> std::io::Result { match &self { Self::Socket(socket) => socket.local_addr(), Self::Stream(stream) => Ok(stream.local_addr()?.into()), } } } /** * A partially set up [`Transit`] connection. * * For the transit handshake, each side generates a [`Hints`] with all the information to find the other. You need * to exchange it (as in: send yours, receive theirs) with them. This is outside of the transit protocol, because we * are protocol agnostic. */ #[deprecated( since = "0.7.0", note = "This will be a private type in the future. Open an issue if you require access to protocol intrinsics in the future" )] pub struct TransitConnector { /* Only `Some` if direct-tcp-v1 ability has been enabled. * The first socket is the port from which we will start connection attempts. * For in case the user is behind no firewalls, we must also listen to the second socket. */ #[cfg(not(target_family = "wasm"))] sockets: Option<(MaybeConnectedSocket, TcpListener)>, our_abilities: Abilities, our_hints: Arc, } #[allow(deprecated)] impl TransitConnector { /// The abilities that we've sent to the other side pub fn our_abilities(&self) -> &Abilities { &self.our_abilities } /** Send this one to the other side */ pub fn our_hints(&self) -> &Arc { &self.our_hints } /** * Forwards to either [`leader_connect`](Self::leader_connect) or [`follower_connect`](Self::follower_connect). * * It usually is better to call the respective functions directly by their name, as it makes * them less easy to confuse (confusion may still happen though). Nevertheless, sometimes it * is desirable to use the same code for both sides and only track the side with a boolean. */ pub async fn connect( self, is_leader: bool, transit_key: Key, their_abilities: Abilities, their_hints: Arc, ) -> Result<(Transit, TransitInfo), TransitConnectError> { if is_leader { self.leader_connect(transit_key, their_abilities, their_hints) .await } else { self.follower_connect(transit_key, their_abilities, their_hints) .await } } /** * Connect to the other side, as sender. */ pub async fn leader_connect( self, transit_key: Key, their_abilities: Abilities, their_hints: Arc, ) -> Result<(Transit, TransitInfo), TransitConnectError> { let Self { #[cfg(not(target_family = "wasm"))] sockets, our_abilities, our_hints, } = self; let transit_key = Arc::new(transit_key); let start = Instant::now(); let mut connection_stream = Box::pin( Self::connect_inner( true, transit_key, our_abilities, our_hints, their_abilities, their_hints, #[cfg(not(target_family = "wasm"))] sockets, ) .filter_map(|result| async { match result { Ok(val) => Some(val), Err(err) => { tracing::debug!("Some leader handshake failed: {:?}", err); None }, } }), ); let (mut transit, mut finalizer, mut conn_info) = async_std::future::timeout( std::time::Duration::from_secs(60), connection_stream.next(), ) .await .map_err(|_| { tracing::debug!("`leader_connect` timed out"); TransitConnectError::Handshake })? .ok_or(TransitConnectError::Handshake)?; if conn_info.conn_type != ConnectionType::Direct && our_abilities.can_direct() { tracing::debug!( "Established transit connection over relay. Trying to find a direct connection …" ); /* Measure the time it took us to get a response. Based on this, wait some more for more responses * in case we like one better. */ let elapsed = start.elapsed(); let to_wait = if elapsed.as_secs() > 5 { /* If our RTT was *that* long, let's just be happy we even got one connection */ std::time::Duration::from_secs(1) } else { elapsed.mul_f32(0.3) }; let _ = async_std::future::timeout(to_wait, async { while let Some((new_transit, new_finalizer, new_conn_info)) = connection_stream.next().await { /* We already got a connection, so we're only interested in direct ones */ if new_conn_info.conn_type == ConnectionType::Direct { transit = new_transit; finalizer = new_finalizer; conn_info = new_conn_info; tracing::debug!("Found direct connection; using that instead."); break; } } }) .await; tracing::debug!("Did not manage to establish a better connection in time."); } else { tracing::debug!("Established direct transit connection"); } /* Cancel all remaining non-finished handshakes. We could send "nevermind" to explicitly tell * the other side (probably, this is mostly for relay server statistics), but eeh, nevermind :) */ std::mem::drop(connection_stream); let (tx, rx) = finalizer .handshake_finalize(&mut transit) .await .map_err(|e| { tracing::debug!("`handshake_finalize` failed: {e}"); TransitConnectError::Handshake })?; Ok(( Transit { socket: transit, tx, rx, }, conn_info, )) } /** * Connect to the other side, as receiver */ pub async fn follower_connect( self, transit_key: Key, their_abilities: Abilities, their_hints: Arc, ) -> Result<(Transit, TransitInfo), TransitConnectError> { let Self { #[cfg(not(target_family = "wasm"))] sockets, our_abilities, our_hints, } = self; let transit_key = Arc::new(transit_key); let mut connection_stream = Box::pin( Self::connect_inner( false, transit_key, our_abilities, our_hints, their_abilities, their_hints, #[cfg(not(target_family = "wasm"))] sockets, ) .filter_map(|result| async { match result { Ok(val) => Some(val), Err(err) => { tracing::debug!("Some follower handshake failed: {:?}", err); None }, } }), ); let transit = match async_std::future::timeout( std::time::Duration::from_secs(60), &mut connection_stream.next(), ) .await { Ok(Some((mut socket, finalizer, conn_info))) => { let (tx, rx) = finalizer .handshake_finalize(&mut socket) .await .map_err(|e| { tracing::debug!("`handshake_finalize` failed: {e}"); TransitConnectError::Handshake })?; Ok((Transit { socket, tx, rx }, conn_info)) }, Ok(None) | Err(_) => { tracing::debug!("`follower_connect` timed out"); Err(TransitConnectError::Handshake) }, }; /* Cancel all remaining non-finished handshakes. We could send "nevermind" to explicitly tell * the other side (probably, this is mostly for relay server statistics), but eeh, nevermind :) */ std::mem::drop(connection_stream); transit } /** Try to establish a connection with the peer. * * This encapsulates code that is common to both the leader and the follower. * * ## Panics * * If the receiving end of the channel for the results is closed before all futures in the return * value are cancelled/dropped. */ fn connect_inner( is_leader: bool, transit_key: Arc>, our_abilities: Abilities, our_hints: Arc, their_abilities: Abilities, their_hints: Arc, #[cfg(not(target_family = "wasm"))] sockets: Option<(MaybeConnectedSocket, TcpListener)>, ) -> impl Stream> + 'static { /* Have Some(sockets) → Can direct */ #[cfg(not(target_family = "wasm"))] assert!(sockets.is_none() || our_abilities.can_direct()); let cryptor = if our_abilities.can_noise_crypto() && their_abilities.can_noise_crypto() { tracing::debug!("Using noise protocol for encryption"); Arc::new(crypto::NoiseInit { key: transit_key.clone(), }) as Arc } else { tracing::debug!("Using secretbox for encryption"); Arc::new(crypto::SecretboxInit { key: transit_key.clone(), }) as Arc }; // 8. listen for connections on the port and simultaneously try connecting to the peer port. let tside = Arc::new(hex::encode(rand::random::<[u8; 8]>())); /* Iterator of futures yielding a connection. They'll be then mapped with the handshake, collected into * a Vec and polled concurrently. */ #[cfg(not(target_family = "wasm"))] use futures::future::BoxFuture; #[cfg(target_family = "wasm")] use futures::future::LocalBoxFuture as BoxFuture; type BoxIterator = Box>; type ConnectorFuture = BoxFuture<'static, Result>; let mut connectors: BoxIterator = Box::new(std::iter::empty()); #[cfg(not(target_family = "wasm"))] let (socket, listener) = sockets.unzip(); #[cfg(not(target_family = "wasm"))] if our_abilities.can_direct() && their_abilities.can_direct() { let local_addr = socket.map(|socket| { Arc::new( socket .local_addr() .expect("This is guaranteed to be an IP socket"), ) }); /* Connect to each hint of the peer */ connectors = Box::new( connectors.chain( their_hints .direct_tcp .clone() .into_iter() /* Nobody should have that many IP addresses, even with NATing */ .take(50) .map(move |hint| transport::connect_tcp_direct(local_addr.clone(), hint)) .map(|fut| Box::pin(fut) as ConnectorFuture), ), ) as BoxIterator; } /* Relay hints. Make sure that both sides advertise it, since it is fine to support it without providing own hints. */ if our_abilities.can_relay() && their_abilities.can_relay() { /* Collect intermediate into HashSet for deduplication */ let mut relay_hints = Vec::::new(); relay_hints.extend(our_hints.relay.iter().take(2).cloned()); for hint in their_hints.relay.iter().take(2).cloned() { hint.merge_into(&mut relay_hints); } #[cfg(not(target_family = "wasm"))] { connectors = Box::new( connectors.chain( relay_hints .into_iter() /* A hint may have multiple addresses pointing towards the server. This may be multiple * domain aliases or different ports or an IPv6 or IPv4 address. We only need * to connect to one of them, since they are considered equivalent. However, we * also want to be prepared for the rare case of one failing, thus we try to reach * up to three different addresses. To not flood the system with requests, we * start them in a 5 seconds interval spread. If one of them succeeds, the remaining ones * will be cancelled anyways. Note that a hint might not necessarily be reachable via TCP. */ .flat_map(|hint| { /* If the hint has no name, take the first domain name as fallback */ let name = hint.name .or_else(|| { /* Try to parse as IP address. We are only interested in human readable names (the IP address will be printed anyways) */ hint.tcp.iter() .filter_map(|hint| match url::Host::parse(&hint.hostname) { Ok(url::Host::Domain(_)) => Some(hint.hostname.clone()), _ => None, }) .next() }); hint.tcp .into_iter() .take(3) .enumerate() .map(move |(i, h)| (i, h, name.clone())) }) .map(|(index, host, name)| async move { async_std::task::sleep(std::time::Duration::from_secs( index as u64 * 5, )) .await; transport::connect_tcp_relay(host, name).await }) .map(|fut| Box::pin(fut) as ConnectorFuture), ), ) as BoxIterator; } #[cfg(target_family = "wasm")] { connectors = Box::new( connectors.chain( relay_hints .into_iter() /* A hint may have multiple addresses pointing towards the server. This may be multiple * domain aliases or different ports or an IPv6 or IPv4 address. We only need * to connect to one of them, since they are considered equivalent. However, we * also want to be prepared for the rare case of one failing, thus we try to reach * up to three different addresses. To not flood the system with requests, we * start them in a 5 seconds interval spread. If one of them succeeds, the remaining ones * will be cancelled anyways. Note that a hint might not necessarily be reachable via TCP. */ .flat_map(|hint| { /* If the hint has no name, take the first domain name as fallback */ let name = hint.name .or_else(|| { /* Try to parse as IP address. We are only interested in human readable names (the IP address will be printed anyways) */ hint.tcp.iter() .filter_map(|hint| match url::Host::parse(&hint.hostname) { Ok(url::Host::Domain(_)) => Some(hint.hostname.clone()), _ => None, }) .next() }); hint.ws .into_iter() .take(3) .enumerate() .map(move |(i, u)| (i, u, name.clone())) }) .map(|(index, url, name)| async move { async_std::task::sleep(std::time::Duration::from_secs( index as u64 * 5, )) .await; transport::connect_ws_relay(url, name).await }) .map(|fut| Box::pin(fut) as ConnectorFuture), ), ) as BoxIterator; } } /* Do a handshake on all our found connections */ let transit_key2 = transit_key.clone(); let tside2 = tside.clone(); let cryptor2 = cryptor.clone(); #[allow(unused_mut)] // For WASM targets let mut connectors = Box::new( connectors .map(move |fut| { let transit_key = transit_key2.clone(); let tside = tside2.clone(); let cryptor = cryptor2.clone(); async move { let (socket, conn_info) = fut.await?; let (transit, finalizer) = handshake_exchange( is_leader, tside, socket, &conn_info.conn_type, &*cryptor, transit_key, ) .await?; Ok((transit, finalizer, conn_info)) } }) .map(|fut| { Box::pin(fut) as BoxFuture> }), ) as BoxIterator>>; /* Also listen on some port just in case. */ #[cfg(not(target_family = "wasm"))] if let Some(listener) = listener { connectors = Box::new( connectors.chain( std::iter::once(async move { let transit_key = transit_key.clone(); let tside = tside.clone(); let cryptor = cryptor.clone(); let connect = || async { let (socket, peer) = listener.accept().await?; let (socket, info) = transport::wrap_tcp_connection(socket, ConnectionType::Direct)?; tracing::debug!("Got connection from {}!", peer); let (transit, finalizer) = handshake_exchange( is_leader, tside.clone(), socket, &ConnectionType::Direct, &*cryptor, transit_key.clone(), ) .await?; Result::<_, TransitHandshakeError>::Ok((transit, finalizer, info)) }; loop { match connect().await { Ok(success) => break Ok(success), Err(err) => { tracing::debug!( "Some handshake failed on the listening port: {:?}", err ); continue; }, } } }) .map(|fut| { Box::pin(fut) as BoxFuture> }), ), ) as BoxIterator>>; } connectors.collect::>() } } /** * An established Transit connection. * * While you can manually send and receive bytes over the TCP stream, this is not recommended as the transit protocol * also specifies an encrypted record pipe that does all the hard work for you. See the provided methods. */ pub struct Transit { /** Raw transit connection */ socket: Box, tx: Box, rx: Box, } impl Transit { /** Receive and decrypt one message from the other side. */ pub async fn receive_record(&mut self) -> Result, TransitError> { self.rx.decrypt(&mut self.socket).await } /** Send an encrypted message to the other side */ pub async fn send_record(&mut self, plaintext: &[u8]) -> Result<(), TransitError> { assert!(!plaintext.is_empty()); self.tx.encrypt(&mut self.socket, plaintext).await } /// Flush the socket pub async fn flush(&mut self) -> Result<(), TransitError> { tracing::debug!("Flush"); self.socket.flush().await.map_err(Into::into) } /** Convert the transit connection to a [`Stream`]/[`Sink`] pair */ #[cfg(not(target_family = "wasm"))] #[allow(clippy::type_complexity)] pub fn split( self, ) -> ( impl futures::sink::Sink, Error = TransitError>, impl futures::stream::Stream, TransitError>>, ) { let (reader, writer) = self.socket.split(); ( futures::sink::unfold( (writer, self.tx), |(mut writer, mut tx), plaintext: Box<[u8]>| async move { tx.encrypt(&mut writer, &plaintext) .await .map(|()| (writer, tx)) }, ), futures::stream::try_unfold((reader, self.rx), |(mut reader, mut rx)| async move { rx.decrypt(&mut reader) .await .map(|record| Some((record, (reader, rx)))) }), ) } } type HandshakeResult = ( Box, Box, TransitInfo, ); /** * Do a transit handshake exchange, to establish a direct connection. * * This automatically does the relay handshake first if necessary. On the follower * side, the future will successfully run to completion if a connection could be * established. On the leader side, the handshake is not 100% completed: the caller * must write `Ok\n` into the stream that should be used (and optionally `Nevermind\n` * into all others). */ #[allow(deprecated)] async fn handshake_exchange( is_leader: bool, tside: Arc, mut socket: Box, host_type: &ConnectionType, cryptor: &dyn crypto::TransitCryptoInit, key: Arc>, ) -> Result< ( Box, Box, ), TransitHandshakeError, > { if host_type != &ConnectionType::Direct { tracing::trace!("initiating relay handshake"); let sub_key = key.derive_subkey_from_purpose::("transit_relay_token"); socket .write_all(format!("please relay {} for side {}\n", sub_key.to_hex(), tside).as_bytes()) .await?; let mut rx = [0u8; 3]; socket.read_exact(&mut rx).await?; let ok_msg: [u8; 3] = *b"ok\n"; ensure!(ok_msg == rx, TransitHandshakeError::RelayHandshakeFailed); } let finalizer = if is_leader { cryptor.handshake_leader(&mut socket).await? } else { cryptor.handshake_follower(&mut socket).await? }; Ok((socket, finalizer)) } #[cfg(test)] mod test { use super::*; use serde_json::json; #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] pub fn test_abilities_encoding() { assert_eq!( serde_json::to_value(Abilities::ALL).unwrap(), json!([{"type": "direct-tcp-v1"}, {"type": "relay-v1"}]) ); assert_eq!( serde_json::to_value(Abilities::FORCE_DIRECT).unwrap(), json!([{"type": "direct-tcp-v1"}]) ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] pub fn test_hints_encoding() { assert_eq!( serde_json::to_value(Hints::new( [DirectHint { hostname: "localhost".into(), port: 1234 }], [RelayHint::new( Some("default".into()), [DirectHint::new("transit.magic-wormhole.io", 4001)], ["ws://transit.magic-wormhole.io/relay".parse().unwrap(),], )] )) .unwrap(), json!([ { "type": "direct-tcp-v1", "hostname": "localhost", "port": 1234 }, { "type": "relay-v1", "name": "default", "hints": [ { "type": "direct-tcp-v1", "hostname": "transit.magic-wormhole.io", "port": 4001, }, { "type": "websocket", "url": "ws://transit.magic-wormhole.io/relay", }, ] } ]) ) } } magic-wormhole-0.7.6/src/uri.rs000064400000000000000000000162661046102023000145170ustar 00000000000000//! Custom magic wormhole URI scheme //! //! At the moment, only `wormhole-transfer:` is specified as scheme //! and therefore URLs can only be used for file transfer applications. //! This, however, might change in the future. use super::*; /// An error occurred during parsing an URI #[derive(Debug, thiserror::Error, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum ParseError { /// Wrong URI scheme, must be `wormhole-transfer`` #[error("Wrong URI scheme, must be 'wormhole-transfer' but was '{_0}'")] SchemeError(String), /// Wormhole URIs start with `wormhole-transfer:${{code}}`, they do not have a host #[error("Wormhole URIs start with 'wormhole-transfer:${{code}}', they do not have a host")] HasHost, /// Code is missing or empty #[error("Code is missing or empty")] MissingCode, /// Unsupported scheme version #[error("Unsupported scheme version {_0}")] UnsupportedVersion(String), /// Invalid 'role' parameter #[error("Invalid 'role' parameter: '{_0}'")] InvalidRole(String), /// Some deserialization went wrong, we probably got some garbage #[error("String does not parse as URL")] UrlParseError( #[from] #[source] url::ParseError, ), /// Invalid UTF-8 encoding #[error("Invalid UTF-8 encoding: {_0}")] Utf8Error( #[from] #[source] std::str::Utf8Error, ), /// Error parsing the mailbox code #[error("Error parsing the mailbox code")] ParseCodeError(#[from] ParseCodeError), } /// The wormhole-transfer URI Scheme is used to encode a wormhole code for file transfer as a URI. /// This can then be used to generate QR codes, or be opened by the platform URI handler to open a supporting client. #[derive(Debug, Clone, Eq, PartialEq)] pub struct WormholeTransferUri { /// The wormhole code pub code: Code, /// If `Some`, a custom non-default rendezvous-server is being requested pub rendezvous_server: Option, /// By default, the "leader" (e.g. the file sender) generates the code (and thus the link), /// while the "follower" (receiver) parses the code. However, since not all devices can /// parse QR images equally well, this dynamic can be inversed. /// /// For example, when sending a file from a smart phone to a computer, one would initiate the /// transfer from the computer side (and thus set `is_leader` to `true`), because only the phone /// has a camera. pub is_leader: bool, } impl WormholeTransferUri { /// Create a new URI from the given code with the default settings pub fn new(code: Code) -> Self { Self { code, rendezvous_server: None, is_leader: false, } } } impl TryFrom<&url::Url> for WormholeTransferUri { type Error = ParseError; fn try_from(url: &url::Url) -> Result { use std::ops::Deref; match url.scheme() { "wormhole-transfer" => {}, other => return Err(ParseError::SchemeError(other.into())), } if url.has_host() { return Err(ParseError::HasHost); } let queries = url .query_pairs() .collect::>(); match queries.get("version").map(Deref::deref).unwrap_or("0") { "0" => {}, unsupported => return Err(ParseError::UnsupportedVersion(unsupported.into())), } let rendezvous_server = queries .get("rendezvous") .map(Deref::deref) .map(url::Url::parse) .transpose()?; let is_leader = match queries.get("role").map(Deref::deref).unwrap_or("follower") { "leader" => true, "follower" => false, invalid => return Err(ParseError::InvalidRole(invalid.into())), }; let code: Code = percent_encoding::percent_decode_str(url.path()) .decode_utf8()? .parse() .map_err(|e| { // TODO: Remove for 0.8 if matches!(e, ParseCodeError::Empty) { ParseError::MissingCode } else { e.into() } })?; Ok(WormholeTransferUri { code, rendezvous_server, is_leader, }) } } impl TryFrom for WormholeTransferUri { type Error = ParseError; fn try_from(url: url::Url) -> Result { (&url).try_into() } } impl std::str::FromStr for WormholeTransferUri { type Err = ParseError; fn from_str(s: &str) -> Result { url::Url::parse(s)?.try_into() } } impl From<&WormholeTransferUri> for url::Url { fn from(val: &WormholeTransferUri) -> Self { let mut url = url::Url::parse("wormhole-transfer:").unwrap(); url.set_path(val.code.as_ref()); /* Only do this if there are any query parameteres at all, otherwise the URL will have an ugly trailing '?'. */ if val.rendezvous_server.is_some() || val.is_leader { let mut query = url.query_pairs_mut(); query.clear(); if let Some(rendezvous_server) = val.rendezvous_server.as_ref() { query.append_pair("rendezvous", rendezvous_server.as_ref()); } if val.is_leader { query.append_pair("role", "leader"); } } url } } impl std::fmt::Display for WormholeTransferUri { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { url::Url::from(self).fmt(f) } } #[cfg(test)] mod test { use super::*; fn test_eq(parsed: WormholeTransferUri, string: &str) { assert_eq!(parsed.to_string(), string); assert_eq!(string.parse::().unwrap(), parsed); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_uri() { test_eq( WormholeTransferUri::new("4-hurricane-equipment".parse().unwrap()), "wormhole-transfer:4-hurricane-equipment", ); test_eq( WormholeTransferUri::new("8-🙈-🙉-🙊".parse().unwrap()), "wormhole-transfer:8-%F0%9F%99%88-%F0%9F%99%89-%F0%9F%99%8A", ); test_eq( WormholeTransferUri { code: "8-🙈-🙉-🙊".parse().unwrap(), rendezvous_server: Some(url::Url::parse("ws://localhost:4000").unwrap()), is_leader: true, }, "wormhole-transfer:8-%F0%9F%99%88-%F0%9F%99%89-%F0%9F%99%8A?rendezvous=ws%3A%2F%2Flocalhost%3A4000%2F&role=leader" ); } #[test] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] fn test_uri_err() { assert_eq!( "wormhole-transfer:8-%F0%9F%99%88-%F0%9F%99%89-%F0%9F%99%8A?version=42&rendezvous=ws%3A%2F%2Flocalhost%3A4000%2F&role=leader".parse::(), Err(ParseError::UnsupportedVersion("42".into())) ); assert_eq!( "wormhole-transfer:?rendezvous=ws%3A%2F%2Flocalhost%3A4000%2F&role=leader" .parse::(), Err(ParseError::MissingCode) ); } } magic-wormhole-0.7.6/src/util.rs000064400000000000000000000122761046102023000146720ustar 00000000000000use base64::Engine; macro_rules! ensure { ($cond:expr, $err:expr $(,)?) => { if !$cond { return std::result::Result::Err($err.into()); } }; } macro_rules! bail { ($err:expr $(,)?) => {{ return std::result::Result::Err($err.into()); }}; } /// A warpper around `&[u8]` that implements [`std::fmt::Display`] in a more intelligent+ way. pub struct DisplayBytes<'a>(pub &'a [u8]); impl std::fmt::Display for DisplayBytes<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let hex_decode = hex::decode(self.0); let (string, hex_param) = match hex_decode.as_ref().map(Vec::as_slice) { Ok(decoded_hex) => (decoded_hex, "hex-encoded "), Err(_) => (self.0, ""), }; let string = match std::str::from_utf8(string) { Ok(string) => string, Err(_) => { return f.write_fmt(format_args!("<{} {}bytes>", string.len(), hex_param)); }, }; match string.parse::() { Ok(serde_json::Value::Object(map)) => { if map.len() == 1 { return f.write_fmt(format_args!( "<{}JSON dict with key '{}'>", hex_param, map.keys().next().unwrap() )); } else if map.contains_key("type") { return f.write_fmt(format_args!( "<{}JSON dict of type '{}'>", hex_param, map.get("type").unwrap() )); } else { return f.write_fmt(format_args!( "<{}JSON dict with {} keys>", hex_param, map.len() )); } }, Ok(serde_json::Value::Array(list)) => { return f.write_fmt(format_args!( "<{}JSON array with {} entry/ies>", hex_param, list.len() )); }, _ => (), } if string.len() > 20 { f.write_fmt(format_args!("\"{:.15}…\"", string.replace('"', "\\\"")))?; } else { f.write_fmt(format_args!("\"{}\"", string.replace('"', "\\\"")))?; } Ok(()) } } /** * Native reimplementation of [`sodiumoxide::utils::increment_le](https://docs.rs/sodiumoxide/0.2.6/sodiumoxide/utils/fn.increment_le.html). * TODO remove after https://github.com/quininer/memsec/issues/11 is resolved. * Original implementation: https://github.com/jedisct1/libsodium/blob/6d566070b48efd2fa099bbe9822914455150aba9/src/libsodium/sodium/utils.c#L262-L307 */ #[allow(unused)] pub fn sodium_increment_le(n: &mut [u8]) { let mut c = 1u16; for b in n { c += *b as u16; *b = c as u8; c >>= 8; } } pub fn sodium_increment_be(n: &mut [u8]) { let mut c = 1u16; for b in n.iter_mut().rev() { c += *b as u16; *b = c as u8; c >>= 8; } } /** Mint a new hashcash token with a given difficulty and resource string. */ pub fn hashcash(resource: String, bits: u32) -> String { use rand::{distributions::Standard, Rng}; use sha1::{Digest, Sha1}; if bits > 32 { tracing::warn!( "Minting a hashcash token with {} bits. If the application is frozen, you'll know why", bits ); } /* This is the `[year][month][day]` format, but without activating the parser */ use time::format_description::{Component, FormatItem}; let format = [ FormatItem::Component(Component::Year( time::format_description::modifier::Year::default(), )), FormatItem::Component(Component::Month( time::format_description::modifier::Month::default(), )), FormatItem::Component(Component::Day( time::format_description::modifier::Day::default(), )), ]; let base64_engine = base64::engine::general_purpose::STANDARD; /* I'm pretty sure HashCash should work with any time zone */ let date = base64_engine.encode( time::OffsetDateTime::now_utc() .date() .format(&format[..]) .unwrap(), ); let rand: String = base64_engine.encode( rand::thread_rng() .sample_iter(&Standard) .take(16) .collect::>(), ); /* 64 bit counter should suffice */ let mut counter = [0; 8]; let mut hasher = Sha1::new(); loop { sodium_increment_be(&mut counter); let stamp = format!( "1:{}:{}:{}::{}:{}", bits, date, resource, rand, base64_engine.encode(counter) ); hasher.update(&stamp); let result = hasher.finalize_reset(); let mut leading_zeros = 0; for byte in result { let front_zeros = byte.leading_zeros(); leading_zeros += front_zeros; if front_zeros < 8 { break; } } if leading_zeros >= bits { return stamp; } } } magic-wormhole-0.7.6/tests/example-file-4096.bin000064400000000000000000000200001046102023000173440ustar 00000000000000magic-wormhole-0.7.6/tests/example-file-empty000064400000000000000000000000001046102023000173270ustar 00000000000000magic-wormhole-0.7.6/tests/example-file.bin000064400000000000000000041777131046102023000170000ustar 00000000000000FEҞBP}1# Gv:Z5Y"^{YCjzUөIӐ`—۠]CEݓ KU=v"S0Hkr.1͹ƦhyBmNvTxCN mtf*1HZ"R1rG9]b|U*OnbFgGʛQcY~ + sb3N)MY0fyJ:B_tˠ>Vnؖo ݗ;3( o,u* 3(Rd9$*6qUgN)}!>ܝߎx}O~~|Obd3r>9:ZU:*+TjYёdzR3PDGFXʴ3<FfZsJwrdʓ| OBWI7 o6"/ّ~|dL&lwfMO˚J6vw}&lq"lžed!Y;`<%<:9.){۟I =}&}4e*2F/  :p'H7J@s08c ] Uk }.809Vr봑$[d(>O$喇Q6loslB-5cy"ifJk*h6QE"{\:RaTqeHx#$Ƿ IKs⾷8E[\qBi ˂&f7a\A*03}@k-t3{-ɌȾ(i7,_i_ T}$yt;.BֿEb8$RTtTn2_064O]z# >:SXNU]40ɞWKT=Vό}~+-D%o^E.WB'CnA **Y]O夞~Xh/>%I@.  %LO4w=E +츾^D 2n7*ث 蓶B& n:lBfO\`?s&KZxJ= 3",ecN9gAqGE_#7PІp[U j 6\yG'70hLrZ_"~BskC'UFJnZ zEO>6垀^FrK@?pM+ݡJ^!b3>Ws8b=w$~ppO5QeAve6x@2>g6=N}L%͛$ywQYSu=˗gxЇNp A^+D6_O-7@fG܇ WtTKL,֦Ć*ԅ6jGr XU+cߺqz%M0:*hFS;92~KD;ȁeS?=HV35JԳ{v$`2v4RpRxvthጚ@ѡ6Gx젉<(_F/6Ku:}wj\Yibe|sa}FfI }L%^gXV6~3.&ژ-]v{˺)@ޱA a>Vꂒyb9doNgWee҃~yc[YAwٚh4K%yp_2E[eo{BvI* ;DJ%8[oUٔ>9k tE#̧T\JKx~ܬwvh C^["/x`̜;;k[s.QϦBoA1ZdXDOl!]]-O5mn-I!J~Of:nHIjD3]bs57(5Z"Ѫ!b򍨆;g9nё_g+Z؈p)K5O`/ꭠ,' Are}[ AgLFvh'#](d2NjR]!*+q# 00.SEs:E:gDr|[tϭrݾZ‡:c Z&\4T>7 ;wMn2~Jb׃qB3!?h1tej)3^ÁԝKE^2h*'] p+2R2DǍ բO`%$\8d{ TXU5?Cn2@ .j&':<_?"hq18^##ZHP3wj$ɍlc]] pYl/Z/3J' օ`w{Xh?ͪ{Cy˭, Qy }2<*ghmcQ)ǘ$b߱' V&̂ΈY;- Bss 1By}7RVݙ`j)"{#=O\#werAy hmmZ]캒ETnA΃ f{Ye4O!_ (*~'޹4Q^Jj>~j$İR;S- {1.s)ւ 'YNoA볱?%r!*kZv4.aa܂NVȵ(6\ e@%aM,Cg:NW#VTz,^ c&.wڄu lm f aW4I/` ;z""tO~??#~8ImCbd#CdS3T4I$WSRE'8e˖t iFE+AɭS*d,)S_rAXٹD* ;IWlfGBK6呃kG8ݾ,dttr^`01K]آlP/|1""ÃgKe@Ylx͡9Sֹg}ۯ{\d8b$T':KX4-ޯBF3i TBU(D2ڻ a5?pݎֿlcNԎ ()N z֪g[`[Fe #>6uJ뷥1ar#θPAWJ'A6;ס7_:|cGW{}f(E4ɃQt9ɌL>M k [ TkM Xby*t*l J^ԙ} |ޏlsB__לOY,ͥ?vNrfML7xSm) "τF,J:X~= C^'r 0q87 P7˾1.LmH3G4&j$kNqxkAENPF,3\S(Ffa~vnpXKrmVԕP1"aFV U%ɨo&a-B)P 47[/UH ~9ƼML0 U; {Ae;= 4m &%dl/*vx fTgs8 ^vK9;=oT~5A:JmtA#\ٕq/ւ+Y G+X/l|c#*hvIV316`qp dyӂ`/@B#rS5R'rחZqT6)nUs-󸡑$.{sſWdEA2< W=#j52?!QGڈP5i"93$J"@OaB\/wm|%&:MJ&.f aY5FcV_kD\8ɕhޮNRk \0y&VmwܦN< c#eoȇ!heŠLDW? .\(qؠR+J^bcd sf2&}T?@{ ˨T>t'YpE꩛4F C;y;Ό5ϻv϶G%@h6҆K._Nٔ  $$5o o7yئjrgw 7Dy3BBW1A-6.SpkL)9ES}Bv6\\[3w`M=2mQx[ b3 dj^Ry_I,]v(|-0LoaU4 =׫5[˖hD֎h>z Pshq1It+q&N_wh'#"J=Iw.vw|6IWPI.:;{M;O^S١STzSAszk>}ܝ(vy-OswD_qDI;W>{*"'y`ňkIY|]=FI'^ $ @>%N 9aUp3#*څr\baq=eܕmc=S9l (#֨cauW }qL,Ր*ھS:ֱ.ڝnA%/RLZ梴g|a ՗:P(P \t(K8y_Ҏa ᦦdC֟/Lry{Mۛ+(,{r.̓xH؁+uٜo=g?@)$2gyڟyE)W?ͷ370y8JywkĬх^D beΓڏpHXlr>ٱbQ2Ox?BexȫǂNk Hd:bCIUIos۩Hڢx-W soڜt-*IFIOzXNNBx q;{nqcX[Te&oAڡ;y*|;ySIaz.hUzEΟHpU3: iJs9o?F&cxFgo{ͿE'Q4&CLPzH2ݹJ,%(<$'v'kn| Bo3"p]n-@t`[hl7Hu#Jg_d+jDwJ"x82NAP]*#=b;POjP`W6xԇc")MLhk\JqpIrHLWu˕a]Po>C8-n}avv]}z,^{9||.mJ x9}[{>2 =&FnORk݄%W |;utt)_ Qj'+z`iQ⦐acn7{۩+Wϩsu/˒8Ejr[kBnUq3\E5p>S@}[q 'ǑLS΀ǫ&UUUoSnr$ܑ%<К/ {U3D}7\z$BRs`3sSu+FLZw :@6̴!(C=}` k$d7d_EʬR+ e:Q8?I3KwR *@]!>Z!\!|m#_?-i$ZgZ\cMSЪ|m\t[)L$=+^$S9'*@tk,TĞh gL).:Zet<-E&wؾ ,7rn/ONd'`}'>2A8BE_cY9 Q ]49ɞ6n^|*ҁ lk*eVbm `&vl=oc6=~h4,z$?=/J`Gz&\TUtlsQXl^Q{F ͜ A]PM͆0loJ GƏNA{/DfyhqP HAoThEy ?6Ofz x_Z)1`пZTܸt g}>53Vo`#o?pʹld-TNtm xqJd={[67 GWVwn}n(g ,1 μI!ҧvtfw8&Y^5ENgcOf)(nhbƅ.GF6wD!NJ^JWCc&sM|? \=޵tdܡc}q^m$tg'O5-s.Ҋ{Z Z!䆖H*aQQLRb1Cy"`%AQvwQ,(;d A&iFRSP `/H{5Цzp>*`%܎dxFS5 x~T+)>2y렯j=oѩ ʴ3bcmoa .i./(r/wwb&=ِL@EذXh]mVh 䊻fŷf\Yayrm.df/Wn71dm&.) VM1#K&N;_]9ܓ} h?m6R`~tמ*Zwl j({qGmV2]غ+,~/c</MW>9ݩ>tFe~%@B7DTxnՙN aOٮ)L_Ywu# [RgxE:ir*(I\0q#4zD1 \0GVL&dc.?iK^$Z\HahxhxodrR iO Iۉ2َAXNZjXm 颞;+bW߁j2>}ʚeyK8$r=b 0JoW0fɕ&J+r;P,IqGI"~]mw״9:ff i9iELD*=*`,O!aj.- ݜ?O7Z[]U.9|}/(}RXD(oYx2+i o |Xi0S_Jg'[wfthIbHm9s:ˌE9NNV63߅RX3DfNhNO{Ba Qc8L󙰏UV$)A6L NwL={biܲASB8չCUHkY AjIvJwm>(VvxQN{j3>DWF|R& !fsFnYaD"ecX l's[&Ls Dk{F`PDj؜Q 5ވgqc&g $ D1ׅ&GZdEƅ{?_~ߌDJ~(ʣuZORU NV?s'EnK!NPr#f:|/ +,9pǡD0VELvEW9#[89ƍ𷎉{Ҋz~ Xt|Uj.nfmͧYBd=NWۺ)Y>x$qYD~:bC Kn:eo)_3qHD`+DɁ<}PYoM>|<3i$]݉h d:H]F3qf)ܫ:`3j¿H|L%TncF8ȃiE,P)"Ȣ|I[#wTrP @f!-*Arp;5_7V8OG^pyiqRD)g鞹J`~SR=$&ݥ#p0VB|`޷UN!iE4qƼbcS d4e[@[M_(=lU΅%5:. "bnӘo r.PFI .e` ,`1TF9GFkf"EIS 7YBs'cmUbRMݑ]Ne Z(C Q_)UQ۫NÌݎlE"֫ 5\L)+hit_t'5EYt]?n.ݣqSsz^ܐW[I>-0OT#sR#%^|IracrnR )]Y8 gs.O?Z? 6"X.Ea⯺ҞnBAcު<1=oN= E:}"cŢܿ^ I5>z% ;8m9uXIn؝LnCZIa[A|\mvUl m HpP ?H5Gq"yt]OIgnm|0nM[9@ #sUq,+gYliځثv GI1)$pYc=ѡ~j4IF/6 st=ao`N~Nof1Aŷ7teob&I]gKHO5C&?<уflI-z67R*%t1 Fi%\CV\cNlyoj) 0@QPtK.U]Y>/5i>5"s@ޮʄtgBl:&G4)Vf#|8k߯h2S2A97O},3VMQZ:%Aq 4}唐@!aϯ ^%O5*@E3~V+yQ1D @^fd!!"ݩR4z/> N髣4z3IBK$tsUooLY|XlK|XW}K ?Q$eJN{U_3έ6 o=.ʌx'֐\5w]m<m$d[ l֚.Ъ (PmA*LGwɲ57LP[? _;5i`_DOB^sZM3ܘ9pBjUc]E ȋ$Ï*cnp\:.9[{% MwFn&rtQpxNPd1 nqA\*wAk^p8kH)3l>Ë0Qa="!?MA+i(G34%\I9ژIX JR VN`JV%=c\Hbm 0Q Ye:nyG`#Z'Tr ZgF]X[kQ&ɑEPh':ɽn#Jh,uw ]יx `zfzߙ[C H6/!PcL16qCn6 ]В :9.2z$OS{| )inHx1\& o9#۹EBԻZ pݲuA=_[m|v* M/h;]G $a vg9eƬFVi(k|"Bo2f Jv].f,z9H tG~v2h:w$:◑j1&}YvWXCc>4k ۬|-,'ĔKo1FxSC/ӟ_T֟DG Z5|Kу3qba GOReMN6,oRG+p+_ 6P$* e`;"ƛa4stW hOI!K2*/v=1bIv^XZkؑ|Ih .V=n0z&*ƾXEF6摠Gd ?B݇,.^}RRG3Md&Vy$jh= ' 0YJ5_=+#´!l\f"f5pR 56!wN/#d`kҮjw4Ek2=h^Yߟ+f4{Hf!TDԖV8gT[ҧ!CTg\3&B*p]DsM=*fʓ*ΐ}zo =<Ԥ] &ro͏arOU-GP'$Jɒ/Y(IѺ ֲjUH:}Vw]4`[3\?جHƯ~f}虯޿aVKup*CP7JcvpyAX!> hH3J(tf\srasnZ-.b' S7fkd0\ ^Axꌐ-DZkfl ƶ(P̵!ck7<Cͧ #3(.6y_@ ^AeBGSɭ]I*[y=خi#UXvvf8+g)/feà!_c.XJե4Ԭ4Tl_ A*d j^2/ 88:QL,@P>/k5؋7yvz:Vr,-:x`įG#GPMzmnf&L猷n($h >=.U /䓩|L\f%ko!e,Uu'2P)i}EOUp\x=f{mKb~蚇]sVVYosY@uv 4Ὁ1 ]cpd*r({m$#5l8f[W/w;XN0WɮR;;{j͌};s(>T().{Ю~+(,WE(zP(t346L@H n@?Y0ٕ*yw~DP gdy!\bj(C ώz H Utr;V N KvTk94FRt0~GpuΛwKJ%M%wB۸#7q;DmgEv}־_zXa=.߯uX_wMkGAp@sU@ЬhUꯐy`#|RާXQ/#cLi?E"9 ? ;6Ϛܐl >NGKi`>"TxL/b<-o=FwZRr3 $~g= dDrkp68)M{$"uu;2,؏7ͥ¥K61O9BT-5+cU_Bpal8T+Q-)يcC|<ؙD)3?3_L?@\DV=B " JԥC"eܠ2sq/X/8Y. r \Y+R eC: c򑱒7w7.1^0O^fY6p졋+-&a T8tD2 c8c#Tm6uFcrv  ݢ]M*ZfW/AAiҬuyiws.y4̇-%$,YeiNFH^OXX{Ȗ6 gJՙ1oۄ5Zf9U%PÿVGS_%7Q+pCG&SUȹPˡEscQ53 2 <}Q:&E+T uVC%8AV+ef{B`%s!kE6gs0gov՛ q{ "n#EaF 3wV|4Jw鹣O @7N)N+^'?Avj΁b%2 2/LW-wv=:P'ɬpێV嘻K`xn.ѶN_,8!/LD$V'oaI[χtkKߝ-BS"{[007CqY<<2gjv X%@.ߴRFQe렲 G`@`}AP# ?*1ZAG-aWhLnT<ˤHP`KTFٽ̎,?_s{&~ D0u,옝=l4e vKQpCQw% ]Ǚy΢7XOE?>t%lO7 Ru>]xBڒ{Aɳi&{aic`1Lҭdb# д8~ݴ܇ގ]X~R8P9ͽǤmqz!@;$ JcLx_f7WoȢቒKEtPvDʴ"NҝtkI'҈xUDuf[8m!]{ ]6/{k積p Y-;!]\G"(@tuFaby&"veM*zlHFQiP/J{WBXΖD䚗w9 %cޞ$||Hv~hJ* 6kBH(aCoߏRVxwauPس|79h@|Ae8Gt\![M $m+g ,짓G/é ݟOkǷ9whBL2y]1GmƠM(E12TC~;gëL嵰3Mdurot! C#QcTΙD D{LCQvr_:,辣"$v(Wsy=v۶Aanca%b!t  2y^ĿL͞!Y9Q(1G`wMj'*+37RFtLHp(]h/.l%hgUA,>^o?9a| CkO2Ƃ@F (7v8eRq ItQ KZlBy-hӓbytdwxSL~E;Z:4/A`4,PQTYJu$o ֛ߑPZhXCОXoſ'Md #B9A7.{(oޅ{NBH To] ;*+V#@QZj9WgѼocUt9TІ^%.ؤ~0.&w5i1 0S pe|!&8zI;zu6;Z8cGv @~.VssqJ3FzoH&Em,^:G&Gu)s5fB;P}'伙Xw_p$Cn1i@M;5Z׿l%yYmxqiŴzH2:S'(GsB]g@ζU &wRDh*%B<ة[UE`Ҩ2oLQ[.g8kRWzMOZ̐Q Iǐ˓!ԪD7:%1smK 4lV=۱Ŷ hL1?k8w5w GoE~\8 _*c:n%bI9CB?>5{CҌs_sr7>8P.]ʹK%GE#K9|2MNL9w/R$X g Cjda F n07ciŻ6Gxe^quE&21N؂+S5i+n#\O&^KAn|B&ZՌC,iN1.!2֜y6Q)<H Lا|aA-|ً)O - i>桬oZ# qڡ~_2!YtS6=7yatS R>!wwǘpiFLx\9뤿CVȼ ]GLO/z5a }dd,X\ vb؜`:kE{i[Qk:[ +Lytߧeզ·U(y3 P/o5dtvX[0Zx1ڮ;??W??d亶S*}J_!]O$D*Gz/ [JBiGJgK3ߘuF7]#Fwq,; Llꅡ^C ۓ5$fL΢T!VS9Y `78e&s[v'B3&)Kp;D>mjȥ':N~Rt%=6?Qa/[|~R& fܯ yUOԴ6otƁ5j4 U7B?`sZr(¶'>ى^SJ}jsjZ`D3XVbQCb%&@ײ7SG63y f#_1Ad̶͜W7Cq̶k@B"G*&ݜ $G7Zc7oўp{ykb)oE{^=N HOhhbGE R$dgĜQHIpHʅ]^?Ml}rgߍ]rY: A~Q-DVGқXbӀ)]G&*D7CTM97f*!QAUBWDvVj8rB!LSla}z"Vq;kX{ ͵:(?P9ܵ9V€o2c^xSQpP (;NQ^Y)'#FtmyK"Jt&m9&c y+ZUPs!s4ݸtlyho4!@'HCiS3"x/,U"B$ڒxs$5q*x3 b ay){74`(/Iiل| L˴-"\mRY%e=3 Д4.gM"'> 0Yș#\QMV3k7ռD0  FY'0Rv!=O;9DT9s2^J5fX,3^!eb094P|-agΕ޷c:hLWj׮Tfꑲ: MXlYDyPhu`ہR;@jcĵpo~ArsmaUzk;Z.5~S"$ 9keʧZ2=uQEf`{o~~0лV/@;v=(|~ 4N0J?̅wB=T!}A[SDN6/M @cmx 459QȰ-#{;3]4XuzHșKq'!FqJTLoTпJ1"}-F85;w o ˿@Yܡ)XPu ' H<"!k,B&2\U%ūT'0xjN^F&I :rYzQa {4>!)wmoQ=֚5P4/A`VM46IEr X,19E]T>ƊCX 2l'0Vק݃Y[<Ar}7ZvV~iq2gZF?pɓ@_FZ?_Vz$!*KD&W>1̡,Kߥ(#J{I:Oj^4|՘\*c}Q:nf@)TtGwcw؇1ګ"/R;taIӵ%>Qvbi;G@ҙfb%:B5+@u%v?UB)kCAb/Sc<{kYÝP !N J 3akosF=y;M]KtJ~ܷ5fAiz09%yhR ~ "eW] ɡT%0D'#3\pC"6Cy@(*KF_{F/2=o5~ N00ՃaO:q= Vb8I[no-;3V0Vy'ϠU XMPQHlsa(du W&?1 LځX %5vB 뗗8ϧ5glyBmVM:s=:{FKȮ  `ܭ9K8"H] đSAdqgċ_''U7b nڤgˮjb:$pÍSH m<ƣmZQ |/ViW4;Ӥy~m\=k7[ ΄Lu Qƫ9x9tf ZL.JᕝES9Vw*7Wi2]brTx%e#r-MI?.А^}2s$]лbyQ5!gSܘ8g*y`ѩ:|7=6D|^S#.(Ove}KuX !r/mᐥtW)b<W*;7 Y¢TQ;qGcDA m/wŢIUiⱟ3jhg;BjTZ*RX Q#U>MGH/=4xR-Dr.a U5N7v8eDE%XMZU_bsEx(T+ܗX!JmGbJ !Cl_ dx5sW}R y]@^q-Yg]lZco6̊P]~䵫4]pQVf?7sU Ƙ tLR5ҩ#v2qg׼nΤ/j`m)!S`\8{$"cޗ@>v|r/g*SZs3O AprC->f~2_J_.zXFg`͘lxZ/ v= j&X{-B'i5_TMr&;~;-7wLW]PXT&۩$ȅf1QX)Zc>Eg?%Mr ܾ,`!x-?0eF%1y` ϥ71f+ %>' ?qi{Xхk[>,dS/<1Vy@J(e@`8ҝ O9M/KPfBwmy(4s8- w _s P;2'>g2 >tñXx>" U9Ck>)x8I.)/ECԴ[A±pn%>Yv5NPjPagᨀEKx vMUeiH,Nf'ﱛ(rwVhMcB]b$Z>bK V`kR8Ŧ Fܽ ?۽,[jXnGa^}&td喰6j\?L0i3DDRfi3|D+i*@@XUyNJ.Hasu64|R(,f5kI8h/=<*pkSJX6fP9Hc!=J)`lD$vi/D/#ځ,=V@"ƕ6_bb U4o #kZ pw=iɬ ^ĵrbgO5!rܨ }][r_bj ?[rNR98lj.RTq62ڦ0(ܧ&$@r>zU@Q0ؾBHi:S(jל2< "i$qTᯤ2A?$lH-.T-151p8fT5:`bfF…-餂<\Q *r>Jes▰v,Hj:j2>|{t~aL0[spݎ3όJq&iL<%ƅ Rex`\BP+J&{Μ_)!d6BɔLzbtt|i|K5SMzOG z67iJ\,hR,sxh$ }@ǙNj1BlYm\ٓBєG&@L/cAc٢ZqSN81Fh5&H|$HYfW.qӅ@P`m &)OBkæ:x:a^`F[j$]ǐI_Y C^2-5tğ&O2p4֜s!o|[`)z. 秞!D=eK5'Bb53D Pۊ*$oXd^ *Ӵ `>Go= h;5(llJ?tToYZTBhLxMW\XҞLp`2ƈ)6kl͜iHxH5wzA԰50B[|.|,ڎyk ?Ni^BGKi.|bIsbR%ɖ.ƎveZU; +XDuẽCI{`,5>'΀"[Z{_# d&x)r2=%lj@htP'"Lr(NEBf*f@{+gFZ(4z'et{+@:Ij3{ܖpEB}]QkϽL Fc #E-A߽b썱QUئW)6PC,wXbw2>R޷EDchY(KRʎ -Iltl?~zO.vRg=TF;GpO ~bχwǀ8#q9 zvG =S YձM2s$BO-O=6r('0֛chȓ񝣳0l7z3XN bZy6Ɂ[d+ <\.tv~MQN:cM?([}&{&˚bQ +2vH˅^{J3?> .%S5eF*#?k ]۞5]ǀj}ɬangFx"e*Wezpe;rgvҙE'όm1P+W5FMݪ̜N} +x=镵֡(\)hh4e\t6Y`IZI FCFQݏI.F <>Pg5J3<ت!3.a͕+v#=!} ɽ PUFcLHr\zu7CN.6HHW21i"Վۥ ;`?qT|*S Xz{7oLOjC/O<) ~MӇW" υR>ϔEwikA&Ox,GtL#U%vYypj^/ m gեފ$v5EJ)KaEI2E*[Vq MlC:r83/v&ħg),Bij؜4h)f%xYn5hz5ܰO3voWR3ƿ< |WD/o"#U:ޔ a}T44e_bP( ~-.zJꝵ|Ykyw]t6kBp*K׹lv>p&6Xtv?QWc:֓(R鰃W*[Xv7!?}Pr@|V8MCTυ,)"fGYzc@i0T4΁H"^T0!+rJߠ>up_ UfQ`8'm]scz482SwJy35kiC!<n޽>8PQV\H%W4PxVoW&ש,-t&ȑ%Nak I)k.DlΜ3lk0ֽwK7.5w8OXH:>b2,蠽| DY%1B+@:]FDhڨfڕ?]C%kja7#2ȼpGcqBRa R* QuoJ]p/oMq;Ҭ@QU[{|y=167.Ey~DH((P-xѼ4TL-as5esjXly>f۴+'JR^@4TTϢ=i{"l dV*E4LS F@Q z=B Lx+1(Z==څ5呻4`ke }ՀۨLoR\(c%_'u!e۽PE5FN B; cZ2v7l]<4_dVV˱q^Ԟ~']q?*״+=`Z{mfctg?%+^\գ>G8y?brQ1;bnҜpSd3ȏ]7b*㽅ky{gmD!+P%Kf)(8X:/mX=\H|׻Tj6ҷړl>YDp+1i%F#T0x ̄vݗ;v6I`<(`EV׼Fg䰈=͋5&/@U[|_eZXaVGyW bwC^;3s#hİ? qkC3魸ͅm9ƕ<OX=}28\6\eVM4':-25I֋\@9N)Xq;ӳ|Z\]aybuǘZX(J4ڴ߳LEOW Kz Z/^Vi_#i>= \~̿;knD :V\Q֍Y_&m`ԤE D+K`z7LzviTeg$;sW\G gLdS?AN91&yzZ۴!h iClX(I%:L ;|:m ty$2=헑ב) <`쏞M}%ȇp0L̠,Inȥl!,s҇y1QK{c+M3QiiW{YQǶ6鉛O)!·Xugs]s^M=[1Y&9<yoh@S@"Y_?jSHe;Ɗ@SV2 |YOf6:$b/A`5PA&Ä2F,q_>UO}(S8M4;OJlO,y8bTHVC,;Zm 7䟸B8;EzkgL[H>?p:gݳ! <땓ldȬ_W[뎪q;Z2;:2;PۑoqC ?(nޞ&Ag=Raɐ^gi+o p9>|q:zFwfAL'%\A3*lY]$^c%I*x˧llrO}~$nmY_83 `ej:y{@\XjQ5Y l{gZGs73VW(vѡX"rg'&牝lB'a[dAZB3bh lsA%1c%+s\A ΚV_֩XA_.1}AɏcTȍ(5vo@&@Xl#豎a]$+\S3/J;wWş!~0p#W\oS)QPW*HRg`Dv¶76PJ,܏?*N0KUؐt2moe,`7GJL@so@fk1F[o b+@F^ZCjJ#G|ELR-5#[ ~7cZ^dBѠV~$ Awb؛d %D>a0h'~,~w `k42#5`Uqq)>i|R3xB߹l: 4ѝvHӇ Un{tR=ڃEr"`ٙ2+ţ#b">`$'*zk:OB%.2_ k͏Ԯh!Ĺ.tFr1TY@$XT1%pN1``#p)V$xm1B"hh.  # LvmHχ/Z'Y/Rq/Dg[%_BsƣK,* F"Z /[hd!Ua"O5HX);7Zb!>0Nnnq׹9 ~7W`DSȠm[)*O{I~-j9W@xSN;|pTv7*6돾#]7~e{C"F2%፶Ǟj,ZyOhpҲj&'Q~{e;LIm:ozүOFILWBaAA\df{$ᝊe1,B`~-otNJ;QFv^S eIbnN)ذ3ײ GdEūMsmR$ċ!Px#b&amii5< :>:L*ǎgS_umVDul=m@ ^Q}7Hi\5[B|uC[V M*.[$L١^q4:zhFieI8ǴQlvna0`y oÝ_ێJNsF3sBS |BZ9<_x OW6DA+!O 'YnU!mJiJ즱08a #"Ow]F0)H5yYԦⲖyJ c FTb(E`6dUi͏BȂ7◒쐐-.fW=VT~nȸIcoc:e,fBaSi8 _Ulܒ|aʻGێBtk2e 5p7~@oMD㠴+EI6፷2 q |䵣M:%EU!crq>HN](5NF #wsuѧrʲ/"UTgs#jW؛قi|]zRJv$_q|R t獡I8 #ETD_?8.zJ76WJz/Ydӟ^M.w `| |a-L٧k*ѫ:K~kX(J'Nհ(>E%Z>T nˎEadRf̈t׷ыܤaWݴHiFV,Wv{1#u22JSꡇpͯj Ȧ`Nw0sSAk42*n~:f:𸆗wVײ2 bcWi?ݩRt:MQʛ,o(M+`JOO|TXja ,:7=0WQ*Xb92aiG`VI<ș k%O5z_/ E<Rz)mB]i`蒤 _o|@tХy'yt=9ǯ _)ӐPDh'/&B5<%kplyrԌrԸo}落Ю>:Ϡ `ֺ}Y7'ײ?vɇw|Ѓ}UQ"鑲w;w@ Xm 5| dXÒfiJ7mx2rfDCj05_qtKVT]A5GqA]^.f5ړ o</ t7M3"o$5t0g!k֤)+e=IV&+1Ybpj/Tf' \3͋:W1ϣ݈>Jtv,Dzf,Y;A4?~OzΙi?bۗWs`Om ^a;ERH~t:F ͂fH薛{uMIʍ3zuɈ_$ cl+|!7FWa[# MzAh΢9I"- .YۂVڒgC{ ԛ| lӠ{rL{Rq]j׆oH h>HVW ry5 N ɻ alUD ϲ -f8sqH}cZ0QjPB|VcU60SܷGi@tw< vpm|^plfnI:@һlH1d?xVÐuK ??>}^iD??K1΀Ӥc֚&SCPNK"#zt"x\’uvbUіx@Q-A!٪f i;aQΊK*Ykj0o$(Z=%KK~XYhnDLR&:&t#Ŷڄ8m:qѤT 61Dh/!xyLc#vF8,d?Z] Toz2pޘ"GDDyrg_5rzŨS`1 wRe$t+ E_#ΟC&cgxgF1 av%21;'FZ.hYۛ${Wܗm1cvdF?w @B&dxJMD9oR)-uO<\'l8j(?R hGKL53(ݝS*724UQ<z'Qw9Q[!懌$o=y3"F=<7w:RK\֧!P2(M my4[rNqK#:Jƾc*f)P:SS,:jL*;65P|Ž_0-'r x {o'$ VeM.)L=q˷Q$q"$y[my,>+,[nĿ"͗KB8jS>vL@"%Tga!T#CgHlgoBJe KqQQ1Nл{-vPOn:&6|Ȑ [VgSDd:%k#C)hp;>[BSۓf<%=N]HŚCH$|)4p_?8n/~B<#)5@Z 5֖1Kv碡3p5bE6J?䘙ڝ}{~afyNDLG39oH$cXN1X:6ak@mo,ؓ^K_/>LhV#{G z)E_͏,퀇7TYf㧜}sD@\%Cڀ|$*!My?eڕh YT?ay ayQz^>bqY[Z8PAMPT%De!濾Ac-޹&Gu7<N?m{]͘AQfW|5!g5*]rf OUu2],\)K`wDZd;۰NDv247sZNdG@'iۤ(<9%XO;ardmMI(,pT`D[]j\\HEk+;r i@ Xa QayJ?Hߝ>G>.tMSp/M4l, -b)F;.pB_S*P!T^k8Į^$"A,ν Gt4Kr`o87sJ8(zpP`xJ9<%)[j .bÑ6JJ+фNeS5,`!2>U,3Jg4]f|kN}7Z;"JTC0K!¶;QyMP9*k3D7n,Ry/O#i>P(ǗIڗ") ̾nhDQ0mˑyb4ULp[I U$TvݩbYEo;qRqf!_O_}צو p'𡫝|؆ cFLoz" ؝n\{rՍWJUl㗎QNdIB|@@,J;:6^٢΀Aw%z;n֔HT8ov!=] B]HGWjhAC2tJǵ>0",qY"# xұ5Jw/1μ>&YCBnE`jP!:~PN"tl%6AћG"`)؞Iwmwi'Os*c|xX ޮڛ9q䍕;v:PJ ,2С :ĕ7,NJaܯQHOi+E~x_ ڰʱkQΧa 5Sq]37cY UK:U&r,Ѕq ֗b._4 +/`pD}-w>tVlc'pRx(1*?fl0ݽJ.ee']% al+)xawW ܘ0ZBcJx¬|Xy-lsMq$λ:U:eçиYT=׷&Wn /bH?|>wLџI)S1puOH[|V k F}58)UwjVlqN9aȐDEBm"-q5.*]= \ѣ_n}إ*36)I-SH1ə2[Їg~~ry^aX)f[ qRY ~-9 f6'-xiJhjLK$6ŭLaI/u ,wBqB :)c$>T]&@&9 =+`~~Ѡȏ{ҵ^_<><4ؾbTÎn~kEk@fQ<>7t ZW 0'}7rtD;xgk@}*ȪiaY@\> ж|QO_~C/\({OIxވ~L.1yDޭխ+9JUU\$s2/PHYo2bsa1")y)e5| f:8c1oT ~y~)-ɚ}1j mΎG0.G?@q՛"d)&+07NX|9s΅ҚsD1ձJ1IRhrjaXe xQLzd%z2xwT@kMAUp%\Aq&2]F5 jf>:s܏KY!yw:Ux06ӹ U1DEVD]!Il/3 i?W 5b#qM(eb|Qj AA;TS%WT~).xοn폽=t F:r#<+;0@ ~)MnA{$ x=`QWuAM/n9;f=$8%^3V1z|F2,Zu,go(-W ~-\9/b9: ѽ܆ *\^?l򪉣 JÅ 6@_7񩔬߉Q-50.b\g۾`%LޔMuɵ?<"UܽQ(7F TAؠCtkˣY&R#[Qa}YIPS]OND;*Y3{ѽ\?`sQU;1Qz JY$cv _T:i\9laҽGK{(A{R? l";e:('; ˠjZ)\OEEs[@ضtg->?9Ixf"=%d=5;=]f=L8b~}9q( {w浮K >A1Τ6o}:ç#63>WG% "ί؏eR"϶0k6Ǫ3gU5ޭZ&"BD}:_خOt,ɳgչs*BwuT处4YvifȹHg jULCK(.RŅ3,SV$ :~^MMͱ, aE^;I'B35|wgi_р-8:'xFdQ2AVTW-jZ9]8A/7h7ok9õ0Cq̂*&ϲ\kֺL{:uֈra ků+MρNN eWN<⩁fxFDz뮦<uV31#pwG-A9F@2Tz tzo,ftщU-݂> :A@2}P BXZ9xQm@KZx؇nh$t筢42h)K?~8tH_M,cj#?w-/_dҒ!ךO͇H(#Nki;-ľ_ G'P䌳 M~ذqꕚUuMA>XWb&4T~5q,`j. ۟RW:M'*6?G ZNCTK` _5AW9=g٢թF!$HפtO1`@a_H,.;nDꗯ>'B>HͦI M6`ϕt6t*H=U/R唖?H+@χjIwXq`۫>O=PX[;4˝\7|gs~'QUc#Nړq^ݽtJL+CR ^)):S@DJFױPH#4iG[i7T;:8o O;glwĉZuR w$,qY۬c P nȒڏ2\@&WLC$GO-rYxcp#u:J{HV ~*n3:o|3Ad:c`fN0q LsTN}(Y m,_UjSKiL#%'뙬-Sɸ6T?xǮ]d b+A*W{ ƿY2y]tZtM3Yc$?O&Mg*1h?`5Ѕ>Y_b[Pe7g#R;/z\ % ݕRPߏ]ÝAJ տ@Pb'1.gRBS[+x5ߑ!z}xS+}qgwmz~9j߇C#P(_|.} %Tq/,P_V5:I y5=yX,L&@ )h`Tw_ϱ}g-$&/ӫeG qlb@6?Q 6r G??c5]n3@h)6: W-nI}J6vjtuꇺ^EΖfE2 ";t3ɜ4w1C˜jκ/%HŪO˘Xpdz@ S- [U]a##AڦFzU!,/=@/vLօ cx(oD~Pwja-$!(Ib5X` |[Ž2.<k0{ߔc9IfAUjVb@Z8#_CeMmxwvL|;'uJXB/XO"P 4 ݞBKз$p@^+F hc6eܖ"ۥQVChGV~@/*4]3ƶE]y)$84** 4Hja~ ;v%qw(& ma`[XM}쨌;6 "CI9g;Pp?-H{5aXYTanf<d.@[{5&k/' jd;b'̈́N{K¥ Pz0n-%LPȖ ;fxE~b?1Dׄ@S| _94Dn&h?)+4'Y~ˍBGnZ3f~QıKFf 6FIW v~COD癒~ED]VՁTUώn 5$CrAD:J!.]{%!ا4h~֞DrXŷ WXу;>5MyÆg^]tՠgK^u{nWT..JLv(8Oa66*&"A\y+pCAQ /"ډ5 EjR YˁU79Ez*ܰ&_-ښq;p{J5.+̌!Qo#f~Fgx)u51PA"Vn4|)mox5SV6PɴHN :VJ7&Q3E5 m=;͑ bEe' 2saѹk~Dn Jז=|nr6eFW"RKUս#!W_b4Orl=5 e%f|4HCԟL;Q1\0?X@r,UP6fT {39 /'1!9c5=%b4 dT p fru5GGBGNR>RntZBZG] XJg+G>7`)Ǽ'st_)l+mHyM dmҪB'Z&wHw=C.^özP9 6卮9d:VX B!B \D.XWr1pdKpzp<@R4Q d< V^wl6"jɟus}ޫZUNLƴnQ#f1bۋm<|ѿF<؏#a,K!iC\#8.`6[e &I 3-x{{4??)M}˃3jH\WeEQ~jC` xY_I\{P6}cd 5qK@16f Je`/j j%r.9b[d[{!M٪1F<WC|oF)߁rSPD|}&Z3~*$d89dGP wFeӝqfɱyhj*ڱhF #o@)a'&CӞo2;$.QQKnA??L0\N`n.gށm`\ٝkYɘeX[+`J#BMuH{FxplV[PD?ڂ< I* s ige'm|^5>s !agr%cn/(FlZ*~K,9Kub )~g#DFٗiVpU-/$GtҺ<$jpv <|q7``݋TA3}kLSqlh _2euE,Cw"/gbvjiYt(I8_*Ŝ-Ty;6/@ u%3y(,l)@ 9Q@Q&ݳjC7 H@,dhf:=79 <*`GxEء1Pxn`V<'q>N)opc2r9}jM?ʢ f[Lݭ}8VO`bXR.cS3٤Ò$>:XN#Ҩaƕ ?VLױ8KOu(qAρ6=crۃDy/d])(C{sH2q䨪V m*V^Eixva1XrMnjوaDF>usYc8j TYSo 卾n$`DɁ lg3av'M]8^(W6$H4dT hԠ'xK 8J.R?IJ_zɖW5eԞ04G\y 2zHdeR:A5ΎޓNcy>5W`R&>ɸ1{LAϞn(+Gn̊X \UTK1pZ"U-eppǝ,꟫61ApԺ穀N3X.KUs~:"u2.V{9}/FAirz f0%ﳳa:9[l`Ag =< _TYڧ8q+[`6{C)4XޮkIn`F6M H߉5}@y- nol}Du.4P moCꎳ“.lAk¾S'>-h ګ.@I,֮JGII#pUzEM/0i)%(10KRT[Qmv؂yVdWe|Xi =ф#w.)V_e:6;;;|Z %=e\?_Ό.JEL>|V}n L,#2g ' ^2 1x5G Q 5ǻM^>4"(pjj[~ZI?cqA `>@>:GқэП3woR3larD+X'~"%aבUg!!\bVNuEe`ZRz\UE]*Ec#_%P`.׵ш<@Ql$63)oW˸UAJܕ(<7<~wH@:=? M!zV0FQ|^xnWzm؛./ۜ%T^靆CV07b5\oOKlmt_Yd`89ޙawb/Jvt Hu~ +͝t'mkjŷ`dk~Y~I5e)di=*q }vu^A& ,QE5iW]_8t`^hmb #{]LNr![S* Ku!5r"vkPrj8WTP9Kcɤ-R!.SqbNMZ&]_HCvenfP,,w]ت2tJ\(h">(wJI`jcDm g1Ezo iv8 jt܋t 7av6Xh3>!rkeP%;ҥVK.v=pf\HxRטsx#ߊ>a:?dW(S|U?&t%= kDZbt̀/7 p.&| 1ɅQ /TbzCqgXa50gwTyσ% lϚcĿOL2ʴUjIA@6'S j\զ)a|'k|d NŰ?~)G]őÈa!E/Zֺ_0#{v; UVrzl~Cxž/7sMU 9̀fO&} KCАC]k@q&C87lM>=/\N 3q|ykTsC5<t:TK$8%|FdQ7:gӓ\ 7K (v'>ĕ]Tt j'Cϻ}oA{zk7p =Ru0bRʌkl=23S5i6T.In(Z_fig#$AS[sY,ʹhpaZKrZXfrB!hz?BUZmti_~|]~˫eQ0{G~Rح1[ذ~,^?.z%:8Y7j A0d%a3oD f2 YWSk<Aay |}̓sP*JYGW\@8:6Vbol˨ ts'gw \Z@x 5C {=T(l62CHs) Ƌ|x;WgJ y}v&Z%|ďcqR$?ЈPYTZ9Is^Hi7ai!$k-V @a&fC}Fo4v>?Fݟzf~9Uϧ/ZM6^:gTj5SGR0MXPZAx%-Mc& rl7 ] @zьn-O5*ÛejW(zקd^V1 !Q Ү#Lha)hJv2 xꇸ٣9& I_?Gi[]`pT*H9 0uvQ='$apr,GPJgAcvU_kQ;|Ƭ|T5SVlɷU!|Rc}v+f!jWĢyKL՝]Ȓ4nTƩM6z$L"Eq<F C3"{C(Ei4уmktҹw.7zzD@^Wo rcj;$ǣkmAh!wb$,(?OUKZNs ERcI3G"pE+BqZe%4VxjOL9NooJ __!G 2MYݗ:y[/wV ]7몼 |m0襟9_HA}e6tMsi"M+ӿEc IaYJ|2iof,"ۜ7Xs+ū*__jzZ%('vBeյ U>Upt X澘 k?p"6\T{LiKV8Y INOo+Kd3D\{ĭ\)tpvQi,-V/QYDirK {NaI&L%K^&#]$gz85⮯$Ow(u>-f 'OzNVpGI| <4"c‡OPͮ:T;#wG kQ:f)we;!$#0ܝtuAfnzYЬ{SJ&CK_+=Ҏ } z;8\e6F* cw\e 2\:ra/_)$u3?K%'F̎$`J֣DFmqUtJp|v0?p]O0;{xD+iktǁ%i0 ]."hZ_` O$=hCre0Jv+J@Z_a 8F^`:RpW5<~0@!2ugmJvޥΨ3iSlmwM0y{6<ܚukqmvD8}Ƃ0*3"qFe%-x~b3>2PRY-c^qt?/Zik*4 3gd@=$<;p` 8-@7̦?Q/눪}HӇ HOaⵣU _,8y0h; =*s)P7{:pF)KTw%!b:7Uq3c/ b @?1ⱑݥYTfDy!`4iΐ֖ԥ\K&?% `b~;24P6%MvԴ |j=Âߢ_-y0m3ꈥ' vdXW⩲}Şjj(=MP# ߟҕDxskɹV"ncf+7ZU]GU˱dw޶KM&$_vGd/:{Y\6HzXWcqGF$|XQYmTG%֥UūAE\xU:;kO۟5`uή.Y!nvVj[JઅLPslp5g=`>=OBcN'eD&3 '6|cаKzsAz }d,aSr"ɏK lgEyFHPCdeFa4 `xQk/#PeRy7ŭCɖ5,cŃY%}[6VTxZı ݓ,ÆJţXsNUU-]t@0\=u'tYd\)ĵ !OG3vz;ǗwFoVFpm5 P?6HDNV5ޕz[%QOgQyAaef:öى4@̩MԳ o4Αr2D+sJ8)܎^NYu/1!!X0&`uUci [ZlA/سd1bץGxu/QD9.tkL'.M2Ym?'d-2uqUۊKA'/q]BIż򢒂>?n>=E[ێ&NyZ_Am ei _cgX`lCh9$$b&y{\t0_h9U(B 2 tRH:x%l9of-⭗>?jDwJ?vd{ Exhq:Wx{"o᧧0a4+™Ӷ:e> g.MtW}ڣwJ_RĂ,-=5Aη*~Ti{X^~Z GOP7Ao 洎8Ƒb(_t(Ms̜Rj8>#.7v#Z9<2,iƮ*Rj& ߯MAl ` O3L7$hۤն0Zp0b(W}|X^4c6\S ~.v2P߲$9NL?>e-rtZ+9@H/aL6T!oK׺aFT!0UMOc؇P @/|܍{үQ40s< mYF!9hdZ;A+^]4)-(?m_9]ot.:Ccʼny\g&@z|5t ?D'.y 6.w4)rL :\IPͦbEsO%Ψ"F]%lsj87P/PH}sӆ3j>t6jb{W&ʗE_,(){^` by 8w,ɍ n w63}O|RfS_ DEӽBh!F:2SoH 5=iGTOoO۴ n1:پ&|U<^V~&m79"{%K&,IQcg=so>"o ;'+2-xۺjbGA*A^f#h_ve"o*sP>_T:6J*3LLX6v'1&2TnN07e^)y^l3&.(It^k~,. $s%[G$RHXd{2!-|yQ< _eMg\?oC/ĝ'vCsc/a}q{AH[^i?695E+J¤%reF^C?Vg-T}1k\@k7|[lD]6:`!n6ZlwE1JdA>uy}];+NG( ܅\"wkj vADuvz#D!VU'_K {QrѶfǴeafKH >fת-pD Uu'tct_ SnI|5q;+Gg Tv%/t utA>DE( o^zt.ͭtnSht  -Ꜵ M =7iѕdNy#5h;oWݭ2H>CCgW ޛqZ[M>xq;n$S2Qx MC><ۚ׷V{}uC+x1u:3fz*h";D}Ӷ[p <.0[[wIut$> iw8)w G_{o8NGӣ>\nvOyuTUzqOb({T 1ׇ =tYS>|g|t/*ohs:<,u86?BV1PxYK*K#Ÿh47SK$PcK1?B5n#WGt?ѳwhe*_D܁M[,8HIM !Wg2D[ w`AfyڦAd!*T ow]#lX^rv^_T5R QUKH=N#' MIa 1H&zT3tÙ/ٻuxW}{.1!miªi͡$3DY*uf)Ʉ4sK1+&m*-<9ـ,rw1:HE yLbOJf QM N[{T'{BdHa`w/<2'jUomzrQ KK\QiyTe؞|gṮ/(0?GqFy!QI tXf9PpB́c4PCk^Inm %â%\V )6+L cuNY9rƖ6ߛM{ #%rවA١y^~y$f!4ѧe{Â#)K AUM:&[ѫm:tPѵU!)er 4 !V֮Ň.a9$N-!nh2yC Pa I9Jӊ8OcYRS̽=|B6({lUc3jnDo}%Uh?J3LYc>Z->2 ㌮_%!VDַ~$aC2)̨38X:*X5 q^=)Պ^d[C*|eC:}įs"mΓFRrA:VgKbv'M`e"1.ޞ7֒roK kk }٬ aZel{WhnQ(u!&a²ӉEh Qi|#98' RA0#n4 ϴ׍1 ̣Sʺ꨸zmv񃄄8n e_}$RzwIﬓYȐSv W+c.5a򉌩k[CmĀVxn RfV|HbQ<;e? TKuu~ѣ _oPţ+0,7F JuBP'P >N)fk'1sJYc/)mV,V!_Je+߭X'zm@&-.g#,Swlz> nO~>TXC_ݮ,Mۛޢ_d}%)g;M`2fW ;B~쯏l_߲0L0CxE!|DKW[#i3c=nnOިYMRk{ ?ཋ;`k\m4w*}eA8,yhP.5mu6C6j!yI%=;TLcxu҅?wa 2>qHP4*b~ wWN?&4iZޯ>\FMBQ:Bl?,H~;[!(rd]fk.\.1dC/Fnl4@WI2\Is,Sl89F+јv툝۞6{ߚ|--d{:׸dp|J}Y*.Ȣ/9nͳ3.[eKYY`[K r)/" s.gmՌq!0nԟADwm$b _ucdCGڲMHBN""UW&YH-}xb$l|ko{KYcs䒭#Y"4j&)&7OY˦o0|SXJR -2ךӥW@ĪQ0]=AHțe2ahMnQz ~ƵR$<FoX°0GTN4A~r x.ցԨ:'qOJH`b jFʭ3T6@M/,)S @~ȍTCH?SI'yQihNPu-3e֨AYhGɄ|j-[r;XLWwEM7NO#-14GhF kѱ`Yģ3sK]sSڀOIOZwt%cX2?@fojx5tEKǍ>ղD)? bsTZc$ ʏt!Y7"nhvqt 5'{{*q=+cN=]r ѢXK݆VZ^ !lUԢ}+b03Wˈ rEV7cDvd&0T61 Mz5IfۚI$?E.0U:Iӯbrpq0QmkuTcOݮa5[G/f ڔk8aӼC7 [9K1K@ c 1-HpbZ! mǓֈZix!OdyIJ9l&U?UhN;`|6u,Fs#=.(<+)˯y{BzG4`F mޫ_yi/A'Z&i/љ7Ӳ3h^uaX(E'9{/?Ƀ]J 9OA7o^hyiNP=_ނ`1PTlb4%g/ a Y m2H 8/=V୘e)*pku_!0Oh{YRCX%S@p/ By!A˜KI`㚒f!~0{lʚ2YsdI"Ery6unijRE\63%3ŸnnW$aP' A*)qUB8hT2|6HfVB Is0Ndؠ2 f" Q{FOVНxBЙM+}>bpzMA_M' mG [,7/t嫪xF(V޿rjG$Iy3&PD╌\x  wo&q VvB0}&pXt9)ыG2.s;V:qE#) [1(v,ރ=! ңw-SF'P-G 4aL9 ;O$k? /*y^qFn5wKTו|T/?"=ɏVi_xF2+_Fy JAa!┰E7EeDu /org_A?ǽ7B#?rOM\'CoWE:+MqM9/{N9`I,J+a3GI~WjBR۽qz +Ҏ}L)^9/i4{'r<"4a -nHMp! 7ڋ^KIfMMm_b(6y: f;uLŒ#\(/K},pMj2IL;YH@5`L69 !<…'Ǐm/90aHڭj6/১еJy.O1v ] >ގT2+Kfj=zj`06#zS9EvxZ&I&1L"(kh d`FӦ0?AXR@Xn:Pic!f5oЬ|L&/;!Ǫ"$L4po?cy&te_'UUn={XBsS9 t;6mD3lQ~$=8[$9mTēm0>kb:RO1{.<ė5Yg;?a#"'||0n6Y!+%N[B< G>!Y#zBr]b韷Ar0',*eƷ]eD gmЀWF Rh@MfAN#iADCw7`[~3Mzp/]-CܙĘmyT':Ymh&d9$۽d w+0|YdvwL2|?b Ncus <AaOi􄿩U0ZYg@pBhHF'4fƧN3_xߕU b`N S$GG8}H)ҧIdT*lwΎP2h#.k~Z:[n>7ISu④>K[W%Mia9sꞆ특 K&Eo»9[2bPwG1Ap E.͸Y Fh_֚³ЇpC V:`4nw~1Ry8Q*̜{2.|An7; [XynFx$3x#{5 MꊑO@Eޢ`>xbN}c%ʳ*!${Zlԅ՚eXaU݈dࠪ|('HrFG0o͗naCB! 8,{xeV}rVJ]! {9Wy{,H@*|NT8mr3.؏`Őϑ,$R{p ǂ恝Oļ 7^Kn1~38E t ͲXF RgΆM]3/Kq:vj)xc_ܜ˪hO=I48mU"3rսPuxçhÁYwjRsvb-R5VvZx g w5Nx¯#ZNkOн>s꽘 |62#l Z#whB,[D&E>)N(xחG˽K=!Ni;y$^9Vd ;ԟLޅQ?=o"/J-e qx9.7(З3Ћ1ZKr9e4O%a_`2<^*YU>cߖyNM+L2Cd)2 э98?4bg ߸ ov;%#sR: @*l+%W_Шq:ϱXPPͬB|NvmN񘠫> sq-@OoH2j) ;𮷕ލ-K~4dy QSa}pv<|@vG}0bQ| Zhf"/Dޮ0fAR!B g@Db# .IE‘}xJQ%6}P 2*F[ ,ȥt<і*ݏhMo{hQgwegɴogW@S5#~Y,_ܘH,T=ƴQֶ2;Ĭm(W r CjƓZ<=WmXU @^xb y6y*q=[B.4܅VLư7`8AK?|E(̵_D%g r A+"K=57j0/QohH01 }b} y5a03-/mf!F~KQ ^_hO>L_1w=.6ijB[pۄc.1tծ9 }oے=0*sGub&м6GYI\ F0|W\e2bHDēC asN[^S1kCa>Df+4_ 'IPO>p! 8~$d(gXë$6ZL/\PI!Ɖ.L)4a V '⡬"^C f_98Te%e3Fjͪyτzk F+Lq @Ϩ.3Y2HuqO$1:6OۍQ*Śmݎڝj?ZL삳K0_V8lrcY4?F|hlD;yh& `O'NĤ+x3ۈ֠B?i a..l%> iNMf$SwY.kn_XChF/; A,hx{T \IV[>`n%!Me b~z7]Sk@d֔ ic&b}vU='2f:ײޅ>y2L nc=ĪzTV7a'SآMׯ * QU f-T >_SYs@FPe $e$R{ ~ɇVx6VVd}i {#?[ Q?`qBiiU[ c:;=m8c2׈d[G>$8I6^ݣr  "P4*'˥L|լ>*BwP+|0ƤC'E~FY([%*jX 4}!}Yj%%ARP2 0+UD>: ;o&F.*p=N,oI#nTTܨOi;v m<'C . M$sL[{~ ӨQ+ GEewL %fs)ƙKGW^YPݓ }nCHP0|%`.aQ6Y/ m&{9H[x1lB븧e@(}D3SNM`ˤ赑3 Э5G-$L8` m]'(kg##*qG9B[qVCZ)2W(2Ie' d/*n|t 40ڣ n5 {oc0tϗ\On5`,6o7UӹO^P^i'5g8b*e>WT N,Њ(-'E z^ɸWG`Al1ӘMVԲK`6Zj|W%*GhE-C#:o+sN(yv.6v S dV>J$ =xDBpd4b򟶲@u$8E `[X.U:L$YrpMLU wy_/Mtr2K#.tqaS|]| "ncdb˚tL:qi{%" ۽# N8p5!dKM euNگ2]\&;Tr1@DG wV)[Q8Qwo%p*/K{E$XX,{n9~/s9zN5l39SNuػjNTZuvrTnj/f,T?n86u.q,7XOtg˓қyĤ 8iϻNv|LBQ~'SbZ ѱq.{) :5v6C#5qJݮ;k!y˶A'h%9'Ri=[5!m7"ZBNDJ.F"Gf7M1BkYl^ {nǘ4cjO (Oi$z򮥝 A OL̛~H:5?f,L yJ5N陗0qnfA&@倱b^~}Gҗ\rk4p3ò׿@s٩eET#gj|7`"qXn~̴{W-" tnpRxM{vHY"K%$P7.pFoEI֭k'ܿU=AfoE-8kh [a;Av{(QڇG5LByK d`z bO@3L._4fNt)(UN4>ӻ`M#lHG|s8Ɉ;z9Hy=z1?-ԋ@-* JoW$UYmǜ4i2/_=1e)j[t wm2ESV X <뮛7^?10H X Ԕh{E1 #gj )=be:]~\s~TU|{ƎUUl0_W3,J\#`5P_9n4cvO0FDEIH:?"=_F*'{Ơ/sfM@T݉QcDoG]VD0c (Ԉ+q5 Y @p5w JjLx0Ƽ&m=a"w>y7qyEp>\[$#F%l;ʯ/25Qh šB2TXO<8j[D`ŸJmPb]Ծ;>o#Fl&/}`#M .ɠtQ}5`0tj pw/+6Ǜxa߈]Ե [@۷fGkIh份U'ބIV_0xԲBuoE^N$mNe+GbӍu𞉬3FvƱLs;{K %NRV5$0k ]CE ,e' pg X곋sAGcI[?jRzM !(*:eܰ.^13v]pB޻6⣻Bh${rMS wA 9as/|a(ds?rDFn7"0@sZ|HmީaxaLTHڪ+K L^lީ 钊b.S#^Kwİ1A7ier&u)lŞYE'cS9/WbA~D~$MgH7j<·~=NAcj>帜L={vs,/VeXrL63 f2. M(_NXPVgAHn-7P%]xi>y*|NJE:d錏 ebȞbI; wri+OFx`BP6X.]-zla߬̆8h}s6 W huuI71Bd]!QL;_d{PmmH^FOcWչPrC8hHAIh ߰2ݪ߷1(JB$ jzGKx4g\,OB4p tZXb^DSlIʉBo`Y36j_ q`#Sp׮w6 ˆyxuDZ/XĻxè˸]`C~_Xs26Fa'?7q6{Eܘ5u>@t)pSos:,odAsQ0~]`k4Awc$3YfVFTX(cٍ7irƆֆ'Д$3_GY4>!ĩ KJQ"SuOX\h3U^T Myl]Cc^s+sjLxmoIOA1„yS pf^~7]}dy"!f LP}a1Ie$hϪ}P޵S7vMʭr㞧,|ϡf rJ[zeQX#IKqjF #cMҐx3>p6[;SMQE~4{ѵdΦB!SFI ?PAwarSO{Lه](] qMsmMLpB _|ĺGws?,1g~z@`],l#[2? >E;\*ʳ`H0?.YvkeG650֒jeK:Bʨ+D>8 λ?g1J;" FRƛ#IOc7[ϐ*J)@F&J>ehhE>)gC|m8o|t_-i}^JA<݌y;GQcZS M;1JӅc3ؔ7!=3LѢIO>oP} 7{%G&G΍l:OYLvgi֕.XOhc[^=fBm Y:S tLDo楴STzQD\ﻖ$wtng, ? .JH[EDU__( "ZFwvI3+?M)9=!Z7:a[C%i5tUdxEYQ>tj9F!9alܚ5914a* `ɇPHL.Ӈ$ڇ+JuwE*ql , .Pm( T  xwL *.nVI&Hom I4WS͟&q 3Qn* % Xr(ƝLJ8o6yԦҞΗOamw`RM6]Ilv%au ;Z(UV1{姅ɷJex¤fh|WQf9NHaEɄ7HfrVR}\B2 g]]?ˠ+/f"8*YGJo| MgiVOõK2bDZqcAjሃY⍛t1՜38kKi __x{OZO,2tX9qgoMo [t`2OԌ+=[?D덺w,u߉` *rie[S Yבlf00H-5m,[P4%}si:|Ef V>^ߍBc1虑9AϵTM*)o[pnWןA#.FYt{f݈ߋ܋lpppz:OnV֥mӪ]?Ȓ,oK@x#Yb!VؑWrF$4 ؛ Mn+ Mz~ǒy5[Wczd)̼=mJYc!^ػep'zΰCUAw+ F/Ϻm?q6kHv#~Y|݆]n-sV>]Ƈo*qOӐ@nFLi[.Gj[̙6pfv4mM4Ĥq4}FGZD 5(aL{%rcޔ*tCi[N ?O+h\6HtlnM'!^㲬ɯ)bTfesJΓ)Ŋ|B7xQo9 eme+}+ +mϿ(CT^+o^(IS$ox?c5M6E$xskh`7샯E*xR EHE%8([E%X $\w-rƲ6LA'=ҽzLiz_эx&*VS!YĹA?4)\h%ܱQp"(vX {6muF؈5K~4=I-تa*k&e`7Bsh0ɦi,1z5w WUEB#MV, z9rjG{[-585 vY(X w.g0,&@b?DgEeJf*Z&vܿ? ڣ{MNTO NR*_1PfC5WK=RvvS @9bi곪${FHt/k;U|EB$2L/%djgrgӯ3w@"7}K6al!֒QV;Ntܔ@Rӆȍ-[W6fnMd :s3؍3G)U؇N `vvA1Vϯ"ke k-VswiuΊ+|֛?~v$zVS8<1W9pWa-o,p$ss%z1aE,il3*ڬ$eJH3*0;yj7:B;q@`7tOa =lMLYbp<CQ~ăg$HSx` ŝU*-|<}]y9qsfW"7 V0~Om7S¡M gMOÌQn25 KKzMU%J/M QX;X N >VqiT`3` _>(4{91N&b=GFeK0(B,N,CIh9j,ZXBgwP4g' }UX,؄'[YR@siEVŒ9:J'`GP ekWJ^kUJ^sBO28`(皦2QA l@-D54_q1}3f0H+y4eHc$L]"SyfQ|8 `ugXBߨ,rOjF#DJCiA3B4_3j:qp˸і d@q"X|{!\\?99DБ#|ƦRd 15"uVއ" mnpCOmy&"LlPҫZc.S,&*e!GwJ=\ƺ_耞g:m;aK(; &:a̜u>إ %U'uyZ`K|cAQ`3M7J^HcCg!fEO=ѵ n Q׸pt#!|~%وCՈLT2^m8Cˤn?TU5$ u>㎌ۆޓPwJyUYHax21H>S1B2M?A{GYFmXJdQ4M=)َ2AhFtUB}~);bE`eט.Izy5j$D /?7,`swaE^됓=k,#׍׊b&ɒJ]Cm ;-ArWB%;`#&Pc9eh$jBtR{¿2S0 矍XIʠeec,-@0τau6gMh49+51>Jcpeu[]`~lYza=t7.iӹ!/zBظja d tn[}:jx\Ke8q#mKra(mܘ$~c+E=~ ɧ|0lZC7n(dؐf[)p+_l*vg:bns5[ϲNg(k$QΉg'^ea x @(y8;[~d,e='k/VhAA4 -\v"?P?3E9Mڸd=J]QXJ n f a4HN݆Dm)պY3~ G/\'_Xj'^OQ3LSֱ(pCs؀L#:-^!lZv(LUm7S)[%2ߋ=vjiwͭ퍊'U'iOx|zc "vS(rNJ%Cɲ^nhYa.@.bS:Ib̝hf8< S sZ1% q.tno>(=+Fp虹+0&@#ݰpǶe V_jXSo6B9VLwVг?ߨ4+dL~6^w4?|~ /al K2L Q5"M.*]x*oJ EV&8Jb:A>M6w Ώ*lUGI!/š2tӽ@!1X7/:cib߫ G)r5>JP<"4(v4#OEk*$=#;raS/.V q5L 4XˉTyD+fQ7GƏt4.tZJ7ѩxER3-R)+v^28j壔^uYIPV:t; 7#fu'nez_z(y4 kG?DށBT$ԃ=֫YsUFK"w5ψ} dfubX?n no2{Bxt&Ϥ#CW 6ILFƘ&;3pQ}@HeA:f[M >q)O1jߘc0P?JPi=f3vb&d% ;0cQDBoT$g@:"cɽ U _ :qNڗb=Lc}'-f:5EQTH},G6&~Yws:3|J=}4*+1`^@*pi@|&Aq_*rQ8b" E2ORqT[ƾ>6 HtRy̗MjK=i C7j>1ӽv, )F,LoEڥ~~e|~CE>OWi(!~^%I1$70aCB2a!m&Z,10d]#wݘCes=<="P"aQb"r\1k( #]URk?Qk1R{ q0IQVH j2,sW, `:c$ nŞ9_T>ݝգMj 7#) talTQ=OԈ,n)̛uyR()"c3p厇fF~ vYpX+d?hj\W?.TuƆeuO"&X #2P9O)uv,z_ןYv1WdY̑ 6HzM$,5DI¤a5_0dDc`G|h#,tf{zmH7\y],h{$]cYy N)w"v?gVoRwa|e2F@yc"1ݭ2ft.0"&kA >/ /~28Xl0zKUҝM 4޵lm1<^DT?FmѕKDq^pHL& Ip;)mIVA%¾NPDМ1OB.*ػe˦1[fE?d |>ʛW8ʏEQpo?Q|Q*QNہtGY4}H+D4(LJIpJדJzyw1 Jl/7 Vf?Z2۪?0Tt":wJ-z愚s9ʝb j qp>Jf7$yHGdCOΚ=X*l@>Tpڗ;R5UHܐN]i뱧 .aB],ש?^HŖPͷXq"E_16#EJLuzB˾c~SǥHJR-80|YH`֕=#:$PjVҖX$]!>ѻ%VCc6JYhҌ.Vr FLPWAkc´w8Qkј9 זӓaQ?}X^7scAbzl]|6h|! z*dTDMG$3kFzk8nH4F_$y𽆛^8@*b L78;k$"/"bl鈾nX]o YݠlrʈВTٙ$ WsȱjCI_=ઉ@>@/}) L[œ¨*~F.7Ujuҽl 5JKX0BNCD+Q , (2ICNRhws~YVj$o:#K-B&m@Rؠh+>QU%`r =I,U8Gi}IxӵJ,J5dW5q6E>*r5$!Dž;!KC5hO(]b`BŠKW޻e.n]ۑ7"5_([ȤI$spov>\]m!3ObxZO 1Y|)Y&qo QZDp%C.#qM&IAbC_}r XR, {Uu͌L+0ʑ;ɵ,3TmMׂ>!G:Եm)=oϺd St=BX@Zy\lժ1!Tܑdm`o~?2?Ygkת$Vos$i|J| ?⺡jShzJ:͒o%:]7r6&;Ʈ纄P|Lq0 E@LP.j\kir+YTyHj=0Q nxE{ְ\z ݷc.5R(RE.d5M!eaa/cAgW ?J:O \a:%o/)Ehr xshcrleK.7(R,Vz*ÞA%1*Ikj>Y5:]t;±&mԻOy85ϠLz.g@Kwvrh\$"EM*7;1jWr+d.ydiU ]#اVTXx#hN:} Ԥ%deb@PE\ B?!l.(?f /ONYI{D/;[:i}$mR>1I.JOpB8H>Tʸ鯅L5PJLL!6:ԷAz3T3i4&Ztߝs*8-L a]/[f) )L"|零֯Xp2eVrt /kQkW;ABJNbmOc5T R+jysҿ6%ݶrt|p^ThG7?xh :z a| e[۲IRo*6҈~Ĵg-d!0f#OK>MU+f@t O'S۠U/2%KF,{6Ϯj1yO?[8opvƇ4geϚp)|PA[f Np70o$gLP 55^tri1wU͓i]@tՊb?- Q=Š_kO*Ň #|PT]|E:R_k(n~kgyv}}"6`mZk Ó%C%l8UHi63"IN7IkUqZnV$_LB^͂u[?Enl~vɫ~͇E#OIQ(ˀyZKu3vSRJ.Gx0|j]͆j~#]v$`>m yUA.i!6ZRfPZXwsPTa[r1! >)A>J *V=M#\4ƃ47ҮwG op:XEe_~u7 ^Y0]'syvv"\nLH Y@( 3Ǻ-wz,A$B-W+I'׺*.# g/K0/RZu!TmԮD\Iyjsۼ;YB1Z|u2At pѬb?>kǝ{9녉AYIQ40&e AC4ڔqFPLçR1g v_\G&&:Ց]ꊴ[: SG60V=,KQtB#+( hw1B3<< uP;cZ"x{wZ"hD¦?B"!LnI*p 7g2]hjqb'[;y)øB#On; .9b&3Iov1R] mZǧe9?Acq]'A$%o C uFAMߕޞ 03_(mPq 6-|űU5"Ce[LBZ^/Smkc`'RC# ;a^w=V!vn\Imj.R[R Ʃ\Ƨ2+NҞJl G-P306GP@RE*ib D lG|R';i,evzl}TT`,`Z%Fp@sKjakn}l}3ܡ5TD < F:9B a U%7yi<)H\mO}=HGl_IIj{ B<f=ϒJ50mԻA1:[Ӷͦm?0?c(Bmba ${<`_kM (~-ECP jRA`@D0v`dߋFd}HH韵Yj#fz_>iY1Qv&l( rrݬo`,=Z6w iNZ*h`+~M1ٖzYr;|Җ Rqx1,%8%Lױp UV^IC*`7 TG5IdeNH{M'IתL&q;VFrFUjJ..o^ yw kMhN@Xk6i*` Z?K,mئoX{9q MuE1sr9D?>DXGV|гLCmķ$pŢ2yҌ-jGXhYؾ8J&Le) Md|.yVOMEA*K!B\O)`TljECR[uY>cT |Υ/TxY9L=S+7_F6ed-w|b?ن\ 8*IuD\q=WeJ#'^[kf;-T- *84JͱA>HG^m4]j1s˜:6 g.WI 5K7oOt‘B]ۂ>O b@p'3~DwugkJ.wx*[&AYBpsC!Hy f-&3UC hj34HppW?U5;!4 xr?fn^;ܦ.\$ct*aA=aa"KG29>a^#\F't sJ~ڏE8|ayʵ Üe$-3SKӞ\UF7 QޮgGx'8"H%u:WK%$?N B%^N;bڪ"Qgr6qe76(Dk}FFDW l,'355N"+کrJKp> Ʌto|M@p}LKQ^DɝW\$KPoe /Q `ЙjʬZ@_frG:7G&I˹R!luV[ $3g畺̃ ^od%Brm. /g&h~9)qJBۼ忱/JA)B.,}X@Wr\oz"K5 ˼Oq.JB@rY贂_S yJ_@i#:c/ݢ1A:[u!FmzbіG>1IӍbg{J9ŏY|r7F٦9=\ƷEKfHYEf{ h`EA뭪H5@ggwZĕ>D>jXK;dz-S//dذmȽQiG)W$Vp(@e~@rl&˕׳b{(Pd>Fw:.ne(\bX0Y[a{tk& vʎd\ý"dO+Wea`h,Lxd*#A՚WFIeދk5c|\y:G">שۼ';PA _C  W ?Ĺ$IKJϥa}!)O_ WJ+Nڹ}0!^0CAJ"Q" vC<>K/Uh6(^;7 FTqcΘuƗ Vl\Oh?e>D.sT+ƈJiHˏ/HMF]8oMA,ۅJ)2զ:ϕn!*7xH;x /'u{ʱIKj*֡.R0FC&psLF93uPŹnIf#"қp,#(f, @7: S[3-DG; 0zWdYJX9a'?`>D>/ҝ 'o7Eˏߋ_Ծ3yYkP9Y=JIMGxxQQnUmtMՇGkpZ`NVsE<@>YN@Ny:^Ȧ3g 8G>&UY[ΰ-qR_sCJȀgY$ʬ0cA声o!l߸uJc-OwB% CT=~+Tu0I!p^}Ҍ (Y*s:͏aKnGP#:gc]؇*ᯄD^Mވ$Z fr}=wC(dѡt5Vf6rf>60|؝xQ.pV@`-͆%7s $o[ xRS dEMxԍK&^ƹOH[ hTi_g*Pᔅ8  Y(-4nds{;-ar,NZj!9wό\cO|AYߙO GF'|x i'ԪǡdLrehNH &Bl3E Vެ-An5@&09벲~CWQv?A=ѕzjmo똆Erka![8^]ŭ8+[Ql3,GB:!mv'$+;n6 V$d]CIAPD gzpÙA ̎Q'}1f c}t eƍOݡkFF'l @/wkIxYnh9ʝg+"Lɸ1:->zM/ Ӧڪ815x$~ Ob9.\[vUW2`A~Y} ܌쟆>?"$C'n><=j蕛B)֌z{?=l >6"Х1R85WyC"෭EkIhZ ZwLcǂcu3QIEtHEfWBp^ E)ͥȡ4:o_w*'VaW׳3Z 3rxCyXzK⥃%<ɋ*Lj )M̸jAokiZwk\IPb5ߣY! \[OV\tU{浲aa :T9 [ M{Kw=~ہN*7-h-ܦ$OeN-vB39:|`"q? {,ÔE`._'ÑIKqYBww@1DTl=|RNkɨ { +>^Mpw;y\b]Z/|9FJ I\[1TIBcy_3 ҇IH2Sִ8I!nMPq$d>3QZ ɿThی\ydA}MiYaU A˅$=3[06zTgK .Ln!Bb4g,l 9;AՆrt!r6}Ӈt풫:֝f~gn։rN1T\xR|x| hpuETkɫG @r:̨=XQ}s-:g ԟ䏉7ddϙ>uI42:uܥ'dXU9 :2_A5vdKʮq_K j"l ,qܟ8`NCL3m(Dzqdq_-! <*|ĆhJR)5WW5N3&u8ApAG Cgny^5?[#((J5;{+XDgI/+%-V2@PV0 8EN懛^jE5_! oI6hډ|'zo_:$鄕CTc&Qj/.$,/:(=}agc,o1Ptlc:7/Iʡo{,;SvfDcށaN 2+\稜Q*WAO8@Yk[V1F%i nw叡__x-yٝXo$~< ^$D /'+>J7Jvk>/U ؊TAFB"1O\b+#3 + ǜ Xݡ&ԒXk&p$ }98c!XrӇ(_v3DFt"(+K '$ѺÉc=.<|nCfc|҄|ȏa1OM:>#ՒLGvjb" 6[-AkU I3^)~ *4#S4.V1'R WQdȦcBh"c>VXdU:<z@wh\l2Z됲8g.Pi:{1yJ xjqXs>!VF!q^(ߋvd,ΦF\PMo:uaUKO9h?CE&m/W5a* -WWG. }\SARk!@aMDO6K|8#b ۙë+iύQT 9SwA&K {Is8ܳ da:7~?OY[7^E[lC%Pmv]D涱ie0t=('l)\qbSr@sCAOrCBkqa#C)g = KvO dFsLN !覤ރn&}m:u_oL Ow"_Yz15 ܌y*g3smE:X;$L,km\N\օ*6d:q2SC aVG0,C[I ܵ誐ǜd = ?(/浍7;*bjm,a_ULfZ{y_(k'虋4ؘ6+OfLllegEm{Sʦwg9YSZ֝7GCv82M8Ϳ1xX$H~,KU7&0/tf⛜]-HQoG:Q KēM\qd̋5vqR3E0(Ǿ-34רΫisT-"0kRLb[c"dTᛍęl+KCw5NbQ v#? xކW~DO.LnϺX%''GezW['6OSz~*&A93dTac%u'={k.ÅmuyH8D߰OB!B! 7qO[1=x'A>_/DyZxRT lAwK\['ċK-Jc!)9nEMChxmyP?ߤ'( $L^)ǫ: |O}HA|}Q>kf &z@ҫÀTozcàMDa OZ9H!4wǡɋ? yFw|J.~g,bx>H= % ,P·\/>=6B3%: `5$.g1F)T[ף&4sBRT]%P 6ZV%a;AhO<,X^BǤG#S^ytt hk˖'W]:[~1CL"7 uhvĐeצh'ȂM!=TGdTn@䄼p^9\/^`p CDiI}<!|?{^-]v-y[|9=p*H䯕OA3&j 0:;a ST5{)b;v3? IsY)鬄4`FhLNXCruHÈVVe⾹$'E\ #SH!0me>t@ޡ,3z9~Q.|*isނ87hnY،FG㻴^(g-n0<WD5 an>7=PR)CH./k!yR vCsbfW]- (@&REE'}'欄\@ce!->u $3U ]7_h樟dM)*3J|D֍C%L05ög;Y*,&Pq/|rſQ?0` 31[@uswb YI5CIq'`kl&,YjpS);o ☲~O̭v~ tƟ oM#4!dcאp=}W߲+b!4 R'1Cd^aB݈HS%`Ht¸pJR6u f w~De" h=a")p^"zf1鳈7`YU'mRpX s$eV hnUV$@x53k/uսHˎsT!eomB`BqXJS}PQWlzO/3~ыà_Ln#Cc"~ĨB₉Q`XϮo OM x1?kTi>N ٪~\Nt_-X}CH,aPze+Yl%@R%-3"?wޕ'PѴOkX}&Q7Rv .mRqƘ{m2F[w E"k)_FamK$%qb~NSC7{~= Գma.a:]ŢQܦ廊k`VlhZ#}ALDB9KӴ+(q{s 1KSOpF.CMN41 ;qS^{jru;*4YGx r*r913ڴ```a?#睓/o[xBi˝k7qS R0|ͻ u3gxN|6(3ROb`|;6|EEŐ8Z.T; qzksN)~<~tnaN;3ѱ4kvf0MI w )G'\kz͊1z^I[t. =Fw^&ɦ۳(j1/|c yᴐR.P|htgĀqP<Pe|ƥ*IXnEVd#[M,ժiO܄܉> Ŋ;Ezz\g =;p|i_L* zHFaf负s@i/M j ƮGZP^2%X$쎺JG}A,TJse`a$\E-Rf'mI7yd%4%1IKxCuC5p@[v+ˢqźɟoE-AhNP8ϐ*о%Oݠ`HXxǚLN"5M_CG~^OS30Xzi0<"K߆ڧ"eTjte$.cՒћ[w+gbkвk.Hh-t]L^m2\mP9Uj~v1bhQRz1I5bK s4gĀ4BuN^9S}[!j\_ujYB[Q"X#njqf9}m4Kv=EnVg{\_6Dxg``H:A ^@q"n  |':YTQZ &PL-l$Cls5@&6ԅf} ]Uͼ=\("G}VཌP iwNWӉ0O'K̼?夠V*A[9[%0^#  ʹZ>ӜNT/Lz>DUGȃI#lD(#ס34)I?, r Po Q͋KVԼȯ@0IVW%E ,\A BCJȉ51/9C`JM8 "A\E6B!Ue46Ow6ƗؘSZ"[9m a Ix. #E0Xw2x_jIDَVx&t 9sa.ʥq]AR[Ccha(6eHwm{5kf#x^RsE3m,3znmG!Zrӛ`aQZIK%ӱ) fS.+Y"mG+j`>Ȣtk>QPJb& }14'×9noy?f=UPa}.u lg8Hn](&\*U*v=G$zߑg+yA7 Wt=J:Gц6V bkrd6.o5lŗ!- S)QU'V|| 3{"^5ez4ø waC^m2̰Y5:/z)+9} 坃o>p,y3f>Y!Ex͒ZvX=3 Cx*KiPw𸜪Ŏd)C,cdi3񟷨r׀U~kn! fґ4X-[ϧњ9nAwAXf7AZJgk7aJQ$砶'k5^-e \b,df"v,v/TIȳfHpM& Ҫak?l*!BCLQL<2zpKzבj`̔ݰ9F[vwاN8fLj˴G`s{3.n`qɟq  nw@hc$wW j} : 2ʝw7莐1m5l*j`}LݫYzt'6tڪqȠ_6:rŨh[ T3W͈;ƝQĺdLr Z%"иGv`8[y H*  ;,JQ^7lzC4qVĠ*(B΅,RFVϖ/AZht` S* cWP",d:e>W'/:uVWYi㒂¾0V6?#-tˆ7fsc}V* {'Sݗqazd M\!-*J(Gͮ+Dg`B [MguY TBX.#gU.NQ1i \xNC׌عn$" QNO^;pӮK)Jla߻.t@u2' yVp-f);[lPQf2!/r,E-*Fz3<ᕓ.ҾPzC^_OvO=Wf>AIhQ0s-_`h8lɊ.PZL1ЉΨmgHA-̲#}t %&N9O1ZA1' ųe& A) +|-~~y2KLH4"m 0:U,Vr~4K7Vvm|D#LwKni$4t7 Lz9YB bkz]&UEl%0ꁃ܎g$YE<' ̟Ñ64zP3a{!pxۨb Ġ^;1QUf(Y`an }%mpH70Kx<Ż>P y"}EڜCKmgjsQ Jq=AHTؘ4sMϏ7_ o@qmP8 ?y#V'>jĜX0B02\81;'`Շ~k6PҎ|J6ih?76|۞aNUECT ٜ)5hӆ2FRU0.v<β#fZKoN9^ʄP|R='eTWO2nK&\ +DE^Hg*ǑOZvj0jF 4*=!0+I2X.|~ ؇܁7Ev^zX3vfj\7MDfjN>jY}?E^P:wl D!Fc T)*XkQX~t#x-|̝A6BMV;/G)6$iҎ%ob%~A8I˅YcTdV͡Bb(~SwVs>A gOz@( <$i goK<.lB3,WdRCzRRm1AEʊX';+1# %\6 i$gcA&sBg7[&VbDC7krҥ_)z0DZ"LVP̓mj Q[9dMN؈yWl;gE ;Wo0- Oviܰ$3T\C`K +]>9- bYΛ*ѭAr@]b[9NlG]q%2\NVf})5`[5>I3zC(hM]k y0?fsRMؽ!S1?k(mtFn&*>rUnn5ae^?9FgjDm7@@+SWyY !0˂2DA_չNT]Fji_cw67_Y!tuN+px+i< 8 O P=b֮'&5駦;b,}7Z0)_[wўH*YR w/+P{=rNLۨ< ̇8FT-ZX߽M7ⴠWk*/MD'"SŎKQdlhd7+g&K+6%bjW{y"es? dފx3O݆/yoBx5l=mRuҽ1qEKHSe){(o I^Ш@ @Ta[ގ\|N6;47xD| =K*doÏ̈́>}%][׈]?m%{Cը{ܥ4tiSF:;n:LA Ѿ,si k[Rf% hyL-@, |2#@_Ӏ2Vx !Yʛ)8l3p;q^gF":4BA*Չ*[k[\"#\ߥ-[>ɥB%,"IoI;-jJM#xE77&oIw:"ki6qI3)2lv XN[qjD]i+zܢx$%`I[`#sKeX'B?.|<1V]YjáQ>g ߻pWζ ?:Y-GF@ٓkkKW2JcC:ʸeg+ug&Mos+^Gxy(?qV,?m5 { |I_VZ54&9[雝&^~$=-6*.(7S5E@bϭ({^?t,;}2SiB=M$a!gx{C33̟q8N2é+uܫQ!}u~Y*`k yٚDcqMOqW[s6?UPwNFzX?l9܍TU@# Vsl*uI=f8_5 >Wٳ_6 !}DuB)ND$P]>R~kk ;:ž|҂kѬm UӷœwC9 TPTsoIv`XVĢsyz4>5N*/ɐU9PAɖo Z#z3I0bp<&#"8goW]"e:Hy눎+( TY'dV eJA\G NOYFjvkѦҤ =5EJˆa6X|2݌<)mMAE \ϟa`.$`Kl19i?3r:rCJTm# \`>os)}஋D"Z^/ n$P( m(4XSaâET!B\ߊU洞G87>x.7BYݯ ]KҐʴ>MJc\o՞oK0E]OJKõ%ZtvEȇ+tggT;}w_'~b̉f"97Pl?oui]&e3֋ۺ9\#'U0 vO%<+>k $@',b)d)TY5Z2(&lC/=#f=E?^zX€^jt -dX$j& r`H;3 W6:$D[65d0ԛ0ߓ Bnp5q ̀@"Y oGl$G:z9d5M 5r=3 U+}YےxG9e BN!`me5͉("͎&*臭Z_B#@pĢw..2ĦݵTf ֩M* \>^ݚWV#4/QNvN}x]SUZjrtˆl8EY|~w2 5]/m.9't^)mK3TLN듉R #kC$[eo׸%HR{$h<0`Hwh/\PjՀ:#jTpuVvA@Pd585Y7 mpTKmvAg׼m)سuC}r'S7;9o`Y2FT1.R/K:x>Ѵ K-;\ޝN:`Ҁ=Oa% װ\iZo^fb s "&U!JmP^$]w5Fc-ȷrIg#~{bɸܪ:BG@9{w >Jo7%:-$e$<}n`GV [x1SŝX: }+ -j*~/!>d(mRS&p瘑mIKêW/}zzDk锎 WsF;lP1lg߂%.0Ҏ9Xb/3%t ^"3*M(^jH, +h֚ 7"4]j :?!7j^9/5G 6Wx4 }tsV sT&mhWޥ4,T,!D98 IwqwEFb@KC#.TW@) ބ!2+=J gcokQJ߮'>,.ș>Zåu&UaZQ?qMU_Ҧh+Aҙ9='4ƳzIm]o*^[C_.WqA3`ۢ8;>&q֍6IM&ѿ?p@lu 7}Dkߟ',^7x.`ͷƦiXIzQxjü~d@yjkÊS@eKUxCx݊620$1"zcy}=l0fgs!TkjF[Ω":^AN("ӔVgy,Fq4;I0ni-ȱ^v+ NKL̝c97Ӆ5O9+ h[%WΕG5< - 6(Cf'k$tPV6+ڶe.H#/58 Uceucx@~1R0ʱ:OF8j^w=DetGt9#(p6:bQ?T %8  e%AmYK[s[.?8}i^;@l4!B$}h6Zz{tO!~LgAr'(mr?:<`Yc?]#3ik+սI E"  6OOf4Ύ-ꈠ^{(Y-YB{:*98;yNe+s#y4lՠ, cyfI"־#7jD#=,4wO4 ~`z$Q:PO} è\'#/bR[0aZ1Ma %A}h U7h\RԤSm opkDvXKϴuNHPz[|"'$B3w* C3A^^A9>ˎ BaT)k50 +^sZE} !NĂ,Ϊ$3mE]V[lL[i)PDrpv2:q츏C@ oBW.Oݦ+>7%;/25;((ⶬlN!D~/o pc+ȬbŶ(G~O?WZ.3iFņ×Ѣ)UZZ!Os@dAzا6l_FabWsrg:-+y2fE}8a:GTDx$F$GPmwղ)qQ<!v {~xZA[bDʵ1Nq}; {_ feO6 bkLwX9(}{uj-3)a@W;.Gd>ą!+hng{ێbf$ ̼ך I UŤG ,;*FnJ_?s-'P![#@?֒gPWBWIj)kCV4(5W(P%x)&w=ju^r|~륷0']"~>2"CzJ;KݓYx3G"]d.H%<ԀMi E6WߵB{ z8Yo#} B%L0M]@ǘȝUrsew8Jl-f,5r%_=?SK?ܻ` =P)0gâE?9Jyh˫@*"@#@%ojU@V|an=vC*"~O BWG Ncq&K 8@TS"zq~.AW˃ߝĐP eUrT|.\rD䆠#m&XD΀gB+,u?t^72R ^־61L{Y*tF`@ʃG/ \Efљ.ڈvS\ -Hq4!R+*T3Ę |l:G[T8Yq#7;Crz;M`T.P WYW%T *IJ% a Kr<^JY{НO[ Jǫ".h,S3 =7ON@c9:& V]enXR>^͓9 J\0M.~q=[kފ5$hΥx8PY2_2e ™Ȋݛ($$y+PNC$F?}>m#/c8WN9 ʾ0B/m9< uR-8xifZeXa7VlZ<ϴb.X%fNMrȻ*,Nɂ0V "4J @C<([{&UNiF^L'`h>z$_/IC qC}BBwu@h<3ۥ(~ݩGlN-zӢ:rS>utԩtzw[pX-Y[)64W9<޴kiޫ2&d$CC9BX+uhFY@jgG{:ŶΘ0!}mmgHw D^3~ 1EO"xt\ k'w *q߁7kc}qC<9ݍdqvS,zLKu*=TOb;ԍնC0{7_t䒖_|O_Z@m5uٌE?d>V,fJLukb cJK3T6|UY] _V,l؛'jʅ <6)4_o-J-adۍ H+Rx*?) z{F>X@]^+ >[) G]x} kC[Կ`]B|e/_ Lzwu󱭺 FڶUM`DEPPZW| z#`ㇲ~ &)Rr VP=&*窷>iy 2¹S2s E) h9%.Ȣ:X&xYstĒh3 ![Nвu,0œbB _Z\䙢Meorߗ9O]*&_X,=Oypia {`*Xތ3QFRO"ɏE`пH| *7w(Z[Ғ ,#TC:,NHC 'cԩC?Ej&;u|C\=8tf&Ng`?:Xryf'ux^j>bH, vC>={2\xU”tB, sH} 1[w~ʮt;Bꋎ,]NkH5xn"?] a`pmfM]oDAMst8oIk5M̞}$F rS'(؄v:d~" jL3fJxv:A r NjbH쥝Hr%c hBe5SBW~u'-֪NR\/ZA<>KXƃYGYtV 4x:~}U[)JQXlދRI"(pX7?Pp)Vo}#Jj9[e f$H 5PGd<OA< .'nT8WNvţeŝbLq*:ȗ|E}VhAF'9g}%8Yĉ1۝DC^QN@ d FsTP6@26qB,SL)\U8ͦft\i0) .-B\dS${@' ŮgPJ j'&D!W>qf[i#@xRq|U4OFf?ϨSb?nyo-@NX˟F(P 1V&L\j-f-#F#*aINUnf, Wcax>ba1SyZ±rzE)wy|\w:bzFsR!HG\0̃h8OpC"XRgM0MN0Rf,\eWnP2Hꗭ!TYa'ˊ9 n4\{gf/Vi #R#n"W[qޟda}.EDi/eљo* k\7^b F!d<ҽ:0JrЇ~$h ɲz Xbws-i8 밈.IcgɴV٤b4*ÓcMۗBܺ&$vD}8 r:Ξ&L_+Z(6\g1LLML dNLӻMJ蟱/`d>l,>Qă!w_|ᅡôX{TdZn6'^R7e52W: [H&R L4y9uyZ-5ǰZ&iR 'ĤvX<"pUǴV^65 >,7VgI~DckHγ h?\;kA.!<dMY2> !:]3 ;\jV/l*Z6ӆrwynTбLM?A(3[ņ͸[}Dz8di\!lmƣT\G/qV4y9Yt I?lp'<}n3doMT[TeL{蔐n^ہJ=;hOp&O^UN̫#@uHВ fqγbY 7![ 3eqQLZȍ 3VSB7هeYp&+2FSȼ>!Imwp#p9iTm,j&aNi}U?4.$i~lL|m+C"wd8XpTaA)g FW&ŰFB iZQgrz{1ח$Oޝe<~p;31rfyD5ҞA3=wiZCW"䴚$zDuhAWsB̯+O٘ivH#Uy9aB5o:;Bb=u|p5Qt`ANr w1YdPh"LIvJW23;=i3>gF%*#Nߞ焨GgHR;TkO{{b٥Ak_8 G 4E3AdQŒ2\݉αފXcXE9e;nH13]uAͷ&50*1\T>s< SuAj_($laFwľֳ Nc(IF(H_=뺕m3vڜ~ 'Y?xq=ED%Z‼ώ5OV{Q+Ԡ?IA=^\օW{6;`JUsC*pXYA* lQxeUVK)U ̈ܓ`4/~Dic)ך?i <6~_ؔ C.yiO\Ω3wKfR:ݯ^\Tx4Bo/x:0_My>:Zs`rF} / {C%o 6o$g)~b:gT+:'_Ѫ{9_e힇fsvj5(!7DFo~H?27]q B܍& [NLv' aU! i7ކkDx* ;` Mc~yeTv$^(>09c{!ڋx osfT \WE?. #JECzШ~:26G }R'px־ :+WG߆ k4/7JGUDrYLɎEk,D3AI, O~ڱbV@[SަNPElA:;{)FD jX|vΧ c T# "O25bAQȘABRĪG9sZ6u%"p2 Ql2#,t ?2vȒ:ąMF2r:ۨOT)KB_xe>R]cbp"z"ouD D~L°붡y NyT QL+V(S:>!4!BhAȁV`P {IsD-)8?daeOYH'ԋDfUwc!= 1|C#JH9{B R3z^dd>|/ohF59nM § Xa7HV>F[&7ÅZؽ?$[NʹV i\Rɢ]$P{D`AKK6&l,ql띣?B^EÆ<Q|b&v(WL d/7Ha,>4aCm[--\G~1ҀI΃='È6H.+ti<›e&Ӝ1s5Q_s ܮxq!0̦d4F8}$SI.Bu(q7zd2+?6qSGG~S!s`OPr q#@%[9ёJjs\ǖ2.X!KwӆLH@3fBgm>bx?ezU=S$"B&lQq׌;v)lHL-,mn1] ++3\+YQMB !(?_/rl(Ж>X?&(dj/X=|n!/ \4t:wz8W+nYkd*f#U:ny2G//bX!QY#z=* }d(ԀBR=i% S!hl7KJӪ'djI~fw`de'`oU"kEx&Fӹ[PrU kæM'2}㼤N$L@3B?y(6MרoƮd:ɒS,vV"<"1#Ojs.Tvr%D˵$bkf1 DFy2]?;+Mn"h`Fn2"X*U\0f2і]J %jmg̾O=3b(QuxzɀALAJG_OjC?,{]PpV D Fokl{!OmeL[AsRy%^Ǫg7qR]LN7 X!'w}o#1M}+&UR8k܉Ӗj׽){2Wk7`K:p|p.Q^'w0vhQ*mpSC`?m`_  m.\3GB0Ɇ޼ͪKΉgjQ3eX?Ҳh"!8CM\ys9׹j]{>6߲QXzU!dI~|?A9{\el/5^ j#^.wvCeA]"YTo%]lѸ]Xz Tג3Lʉgc^5Ki@pB_[svIE.0R)+1%pr&= |hhZw`-ebVɺ>\W5/}co+9IsU XZYcA?3To2+CV,M- }HPi0hMN^@UvK2Aټ|$&IJ {aЅSBӘR;=K*LV]5 U:LFĠFu5'C[dC ΋g^T55ͿῊ+d{TN~~`Yǖkeӻ;X//~;/8r(p<8^ 12Hw@RQ0nd% ?a&g/Tt.,݈ТsEdz ZlP|fu&cu/% dTՐ!${D:RkCw(%M6H9]] W.jr\Y"fٚ.G~'8lR!ad ߭eB~PE_Qo:.OŸ_JȠ)64$ Aʫs,yt j׸)+;-w3Gݲq6z7kEzm5; roҤ&\qwI7mSiصSf RxYQ^쏸9JK۾Op?\}g9; u\կlQD|[MXV-ӲApޓ$G,,ս-ۅ [ZhO?b.lK?٣}UfzfGw$"Ya`d8U"7ԶJJ~:IK.3DXsڒ$}z|ڽl\q~EAf))hڮ*eܽ/r?S|T@mы `mկ.im$r iZpfI(Zvg$N7XQ|;T,:mo*j[5IK"t蒪5xheAr{8HO/J"-EԔ =&})^f0dg1r2r^rW^myølQ$Dߜ0kVmk\ɎɴmlhCߦ SqIzbb;6R4"kvhO{߯c)stmkeLHoJ7Ūlvr4LT iaaՎ]Wcq3'+YGS} o] q[\q19dxe/$t_L,[xNVc!V+Fmb 54):5E-GN3 n[;:vչ0#4 vۓuҚ[n-<-F̪~S͹ɏQ~6*^Fcs^qf QNtLWhxro\q%bT.߮މ-?(|1ng*tw~J̓L) >jv>{q4@bam8a_5m?=iC57-퀲ڇRfS`y pVwS-]Db&)`ifs/-\POz3%$l_ \:j4 8 Ƚ]_ҳB jSZCkQIPbdy] ]?ddT)gu^ A\I1ǢGw2",/;LE4?eslG$iL7q˩vl9'ls} pI3( )rͩyB6rKq"QoqhchͥZۖ.? 7?̝;Nd2N o[*nFW dD e TQp72 NSO71Oh*`HݨAɶםQZu[A`CFKx?*OB |io a-*!sc!2(t8|Γox,<;ߍ"eD7l`RIIGC|-4Gef3wҸD`DjuVXyeh?q dzҞi<GZSU&pڪp\Օ] 9%dB'J|ltbK`&&n׫%FxtES1$v_#U8?<G-V^W^99yMR' 9AC9%R5;LX*6rsLQ9?oq\) x}y}#T Pe٭@DԂFYg:==MεѴ8¨j2';ա::,l,;֏7Eu &+0 ΗW9G#dǶsl-DN¿(* V DcGD{YGRxFdpߍNpڰh`%tj9Q|,!(γf)+ܶuИv3 vNu3zşä:1c1xt`]\ Ur4vnQ(.gNiHl>*LTH>TȖŗGݖ cvGBZgtOSrE*9\#7x  B) уuIA(N>k*3ۄ[~'om򛻹_S=&(}tv~],so ~c+rV8o`t|I[؃FBX:VѸA* wvMlXԺ ًA)q.j1ɨ<ĩUR%N@NҨGC8u;Ϥ%'H|gfu||Sv%${ܡ(ŧj 9*kMko F,3T xeJ V vǫJ8$?Ct%I0HA:Cb'K?o!R 7溫-{en"}?ZR#,I2@|t%tb' : +?bqQ!_ U%Ƽ[S~ >.BSX`d*^\8P0>ѫha~c/jyjc-dJ٨s+?>Ʌ Byff`TQj@%YQpi>Lj@h!΀t(OȞ4P j<_. IP'9{ȰXa -#%@DZ)%>lIy7DQOֳ\g 01i)mWo+n 4,j1Q='3)VB+O ɽϰJ:0ÈLlZ/T2_dwÛN"ckD@)~6^Rp(Iȫ1K\nP^s,8#\йg}-GR%UH>TBanxaSB⳸{c3( aNZSuҽkP5ܲv!]*wk%(mw efaCay{*H!s ?C 2Gѩ˲ψ_ė,' OXCL)FʲKISSc|t_( q)FbC[|h[JlV!d|tD)zv42B}u::OZfqi,L7,o<DJv =Kdl^0+Roɘ>D`-E#=geU\☟fh5#</uCE|Y?&Bd"Fk*j"}ǤjĎk<Ůz6ݷ qZU\Uz;tBv)CBhѯa侨R1IȼX[\,CP1Uhє^0_]dAN "A#Y+Ά"]$)B"/+uۊJhJe_¦Jc9^%!Xh'C{" b:N خ*w6$iFUBw|G[G7%OS_ a=I2.ZSRH6qI3_]a`ۢ \º6qdb#-av[8(Ƣ8sY (&.cT滢P9"pK,J(6!dQn+v-e(L Fut 桹kq{\#Bag/O+ LX_!4]^,t v.Wޚev#N>9E'6oc"yl:3p<C\ʶI^.7VE#@F?xOBaD)Jh^uZ$D,]uݥ+SQWM\xPB=a9mn˥#p(Ț(]z3%$>GpEmrPD|$2, >ĝ_ b n sS@ Xݸ\EKR4^bc@0.=!ybQW>23lAg e)ljCwBVAy!)|k[4\ۉC eX-(e8[Ƅ_PM;sSך*'5ɠU90zblDKOuPH?1g"ËCZ[a ݴ> ϣhamJ E<)/. /MGH2+Hp sR84V=QS3__9C0UډS k<3ǨㄽRpX$x4;u^RjIl#&aѷ:faA9:k¬*Pa177YU.ߑG\^}8щ1 p,:JV%%jPp?]DHq)eb<>DhySFK@rn5%l|Xֈ^YQ,\|].v/ }ǛW)4&aD>8#3)M0qX2Яr$SGMg?RDruC(ĻnB̯-&t*mu%\S\&_o{|mzҧx b4p`!jnoq!n^샬> .Dz|űVkV F YpJsԞ)'%SHF]22"oSxYD,fϟV]P(ڢT?sE/PPudS[lsw\C4#dȞg-WΕ:<2k;S9N|=J~5淶bvg{ؼЇ@Ӂ5=.P0wԆ4x2E wʋ!eXCA HZn Us&gCԢ8=~"-^?ʬϑhՇDPGxnfv;v&qD\ :PM`^)?8j, LR`P w!ī4A9CGFPxh>UsfnN DAy7HRx>hzVV2zDMүE3㰇kN^ROBS-y,ǢPkƠlBݼtCǜ~ 6D9W0#ݿDaAdAg`-R,8:H^XӰemnF0>dvX]o!\.)U7iClSbIʸpORH_=Z0R$ /O}18vL ,q;[:嶑잵8q[6/SJ\;)lqۋ.%a[k՚t=~"1uH#}ɰx;8J}u-U?m Y[OҖxY%YҀCqhZ/ Mu na|B[%tk\s%ݷ$ۤУ_dI > *y9qkK/"\gEpyyٸ>髪b =qmEɸ\.+<%S<ݿOɉY]lTT˧wy]vM~%m hq41oqr8>Q/T{%[@oKږHR^o7=>?单?zb"QlNIb}2f6&6 h򃖿H*zJ캞jîz_ֹT{ D:e%\fdĤyM{T{p)Yɚj=3)_ ʂ+'ʬ꣩;xGƊsfۺk6hיU*Wu?Ğ֫X<НAw%y])fY/&p:Lݘvts/6$CCUuά).ӰBqg9B%g5r"j.F^~ NB I^7 mvNJQ?۲Wf;Kuűi* Po65 pf8`%FK=jn*ZsWt;l!q nӓ غo4 ݿ&Az%(m(5 J ]F<0}x2>#cܴTQN{go _jC\ʃC ڋw);$38Am ]l bU7e?cͨݧT!fj}<@1!h}[l Is #i\E0ԾSy(45X` ܋d5`RMV$6~b.Ij@OSp-Uƹ)b zWk}%XVq1a\s:8 z"!aY 5BYGJ09(aƊuyLcXDȥVd1~q !uM@G=5o <4d7vb"g,>l d%TA;ܒ?Bf57 W E %gpshcFu><&ez]g0 UX;wKb~_ZԨ{@wؕ["^]/썙ƪ/{AX"] La0!~;- s ^wA/*lI%|Ҭ~ ^CJ_l|Y[8{cJփKXxH+0꬇BAf5~O o/&FT 1GoQ>Os}6IgXHewIP$Isibn9dt`$EH)LuNyYyIb8Std.=RRÉ\ §tUpo藊ߥ'H} /<\< WLZ:`lTrԮܤ`y~|HeRv /[%Ҵӆ p3Ό oa~I/jV$~'懷bO\;A0ZlZ5D*AN͟l/#A1JEM3' ftQ!qKI|c_ObPC9kx ~UZ+:ul埓dO)m=aMeȏ ֳq۱0ͶQWp`:qUoEUkxx _'B=3:3<´y]|.:÷<ܔ66|/75$אO£wak#7L2@zXEy[(Gsܜ%r# !f.JBf:p49_يW}fݑKsY}͏N_0jWʃ hwtd/[{% 8SZ.5f$m-^pDt15Rl:CtU0JF} j_Uh3@u4+DrdRr-'g~ RmWlkBX.~[u#fdT"V[mĒɧ7['0 iGuBN8e%ei‹|Shw&RrbÞF5[#W{sߖ~MԾ@{&pe" y^W1 ol112器"=04$]?=̍k7T dzWesG24gBi&quۛX1E<'gwImqWY]7"Wd\X2+1}u6#<;W5:ވGʍoXD.He/M7&"._E0EGKk)/FxZ;HJXP֜Cu kHp7 ':&rroyH]a2mH]$,&X)X^.Ib[I$ӌ39`*9)"MZqk)>6MjP fW^ororhiInzP>`UqFX{DШNsh7,4bnm}W&=Z9ux>vF PJ(_.&8a 95?<<6Fv3o8NW7&TDg=JTaKR>߈[D]Js`7a2O`wA'q7Hʰ;/\MCnq:jCٿŬ&V-hKl'*"&c] _34$&ׂDiL/p{?aŌA ~kM񺮻Q>#%JRc(Bnܜz-s?{ t7Ϻ?)(5hatT(@8nDɉODrHW`M陳Pދxdu (N6g_{kˡNO /f{5w<6$ ބyc4>h,, H2p ⥒D}xXa ~_ ÝIXZLH1ab xЭ.ڵ$0Hu8U 9|| t]k4 ˩3c5Lz;eid"yu$*ol.Mr G#UP%8:H42 {ut|nOr?Pvri5kou;2ᢎOXV~_2F0GE;aa`rfQE[tXay8A0O:MYh0ӱE|w[Tf:5aБH!V'8 n5Zn(@&ENK' O҉MIbAWC$l% ai>v:=E.v}$T~m -b$hGʮ2'33n4%0NNT Nx.Q=;oRS{H@+ MŴjzc3!Mv (W TP<c%pfk7{9.a;EXQDX\Ly2F$#8rzSDb'0j;TRlm[E05Hmsptӕ%'rcp}3ܢps j<6 >֘{Kۂܑ'H1 ,S{.VQ[/mz X\k[!Ln&/FϪeP-V%`![1KwcѐdL^tXpQ+C+3GpW#JEf$GW”ԇ 8"74> &fqw(cS4Ǫp 倵B-Aۑqg@f.h'}絲{EL&tjc4S\ C/UAkZܮ8;wВtmD `QXH*;†p-GL6;A/,THC/%C.3LTKz,RAyǚn>.)Lp;{DEq~3j'탍Y8HǯnE9OV rn|+̯JyKnC0ų5XAeJtsXzHf})>jDʗˉ"&w= byo]?-y' CTe9rZ5r$Ys!8ub}8Њ¨#ˆ=7ҨHJfktƂaV`Oh.'=YGyCn,k?PӼzЪÿYó}[^ e~1ªL%-HMgJ4ԛ~YBܠ-uä́VL^`s\>"hr^d̎>ӸR<"˂34 <6&PtQrZ$s\wlbKC@|N"$ٶ#>O?7.=<*>mJX8 ik`pϚeUmipɼ؈Op!Vi,%CUur䝯n{MM:8hrk!B *Dtc*Ls2NQɹg[ +ХB!H\r n */4Ξ{}xE'q] q٢bLe3g 1//P祬TmY7mY}iyF'҆%Sp`f.K6e6`1I{lȟ*1If?_c/rm; 1Gwu& \22Hg*I?s0eT#+݄^CM'Dؕ!S,Q*#|RK]PoЙj"gBl[a:gϷL7 @KGh 7(:twC1> ,Es&Qijz 4YKO Gd糌%XE"*݃뵯inZ`柜0bg3OjC`ߩ kj(Y?*Gc0ԬG0?x#3 fղՈ=Ŀ0JnH_lA{?E@5p|m:^]y ݌.b;P]1][Է1^f\Wؓ=hŕ2L[w.A? 6LQds5\&`mQ+P%U;j:X ћY$j})F3lbYtNJ BNI>܊U3lsƜn6s&-)vt7ZڕT߄ec!;*"vv5ʱ6;52K\c{T@X}o307N:sɐ^,lcEeaTLE$:f++wR] c2"#sPg!U{+hYXavŚQeqs5,9Wѭjc%s3EI'}V> V"B&4RH 02RMgl &= C΀o=DP섔̥#kb*0X`p>#qF˦7tTY@>Uz K Xp /IJ 혿w.ô0s,,ǂzS#ln*XV, }$Cs?|͎sWuѦ^kXvlQr3M7/Mɍq{Q[~0.&XAp N~ǖ?"P9/V(qcmXR's ZsX{]GUQkyzW*T޸(Xgyr gC@r؞B_EeFs5KQgI9,0xa qi]SdYrSXsht<-Ml cwp>Y9Y`_u~ZVXEzfH*T2qaޛ\Jʘ}!KtɤiQ*zX09_2{[clϒTaLl:v_T+ʬ66Gd$5G2t"+jeb䒵 /v2EFH }$ "̃^ ,] ܗ1gj3ղU}!SԬ ttJg ]lWMN(N!jPGs\ZP1޾NР>!Òl PO^ Biyu1/=)f$KeX 3ܫcQFGM[ne9PuVE J^0]2#FV=DH/S(r)ۯWvUʆueb#Džt%KR1J,KuU}]7} GH2ƞ-r DlMk?drlP[d'McT*Z?@淆NH8"G5# j&ƑSY{X%gH(WmFY"J`[CApilEz`o$GR-P<%|߽Ͱ޿bװ(xpڋ%tZi3Ԣ['6B UkuZok\}/(Ukޏ|axB/'JL:qEz J eb Siuh,^@Z>Tݤ+]b|÷;o1x';^źoogDhh{XytBM`Nߌ˭y`Ev4dc #d?S8ٛH x %;gq34/,H4be@Äi}jC$Gc_ -pᐦ hkfC^KY,B+1䘈a4Y*q[i@ !} PzҰHH˕]0iB=@pJx^Bo5$|ln]|]ɉs#"~845&w4y$sۓ q'^㊢mw5p'v|Cz0zH#JPF/0D׶as8w +Fٵo RjU͸\ʮbJvT=2-.tORۇ2!) q9·7_0:_ԪjCNSy qAj T*i"DAQ]d Oh] "Iw0x;UM;Oo'BK{wb-nd6?C!l+Bc2A3^Qē_q6H8)mq l)m?27挊{藤0%O ˤ~Y# 1Sz$ ֶ;<̏Eg=T? )k4k@K?"OMy=P"-+Fb[xʽW}|v%Ziac%[C4D Yz: c<3D^Ut'd{ M`X[O4T :rz3O٢̱|GNǺK{*GgRIp+ZCL/{_:s\+] ^‘B"0C STGA 2%`Yo~lZK\0aú6Է2;k`&~!(OGhGgKYb.*y2,kл3UD8+>O;!"7&XJjBx,Xsz! |eI$YSk#jmuB9i?\)Ǟ}J$ GZ햓67W3XI-{^aPDT< QAbFPdY+5w[كnjؠ Nwk.f#?7BiVk&$'6U;YėZ-{M\L5Gv0燲gwi&LjK3 MWNtE6~-gEW7pP[leԧYH= !r:B&iŎ9$apzDl?8sPI 7`h `* ؁u 'AZpp3UX?+X\Mdq"]T`(M &=zѣ])چ*'kV;Crj+lQ Tj[Cc{늻yw{rTb2Wkh!$^sD(uCA}[Զ7bݍ tz|DUEQ0_FG"'dR~vG9+H՚*,d?8e(]9 ۚrq+c3}-GV8?N;1W!GF8,a%hTp K̂;}#&AE-wdP sgp>y4wۑ##UwB{jsmZk?tcW^ t}*I G1X1zFBw ljkJQ$o 6S,iG n<{ɣd0cwF$s49iK$jex37|N{"4s[a>?X׋s4gg$4zyk#"|Яtѭt&d(!H `mqxW萠]'MX&\&;tV z(j)3;Md%us2FFјϞ;.#jל%= B*t]Di/_=~FHMDYCDb[Gp{2f)$1m%>8gZ>hƬ?9dk4vyٙ&9["8wĬ?6:>iq 61JEALX7ZBZnE2Y$ ]0XVگiɢ %gzmOΞtWEZ^8އ!uTɗm5dݫ o aO K(G!e->X43M) /Ll &;˝"g%;=)Bˆ-o~q~-Teq hXdO6{FkBo[Z843*ᨄO4exagm)Z7A3q&ڋߚ+>4ʠDiru;G[zFHKZY]̆& @'B BSg|76z{E;G!͇ŚLvoh[S:OҲ3 bJS0aG).13Ĥ଴!ၣ)-&\8oLvQö(0C6l ;[egwelt<W)#0`F[b14*r)@EUF5_ rbi1X3@U4ec[ۈE4['%VD/Ic P/=D)mᒃ$5le82!-QLADn\EσrwZཿ"dDCq*#] a˷<@V$K&_ep`eiAO)}^1b2 DC S-X3_{H6`9>4)lL>c8O_(Hڵp"6/"7TX6 {_W)>; # Fh KZr;Xdj6Ga*)[-/~"iAL~YiH]D ~!X!M`sB*;91(is/W ֚bElgX7Ct.No+7 r<֩sd k3&yiCi]ZO9W3-׌KeF>91uV!'ĝT5ҦYKlJnLe21[K߈0yrKiˏ5H|6Ebe ,z̧_vVX$/2(saud&8f>u;PɢaZL,-H5A}T( -imb޽ESt@B8%Lx>YaEMJ>x0"wHǕ+hcB-˛Xs*H0d Ι]BIrϰ f1 'br]8YCqWډ`wčsj|tY9m6rɧ3Ma6b{}#p72xta#*IRZ;#6yV}h}-$Ay8m}c!OJvCiLJzәȦ篮>Ib]?MrkUbK<[5\]V?tHϲiRtkRn?Y\/PPK$Ti'?2(w~0yᄫ(v@/Kv<k2w)ҍZRĊI^_,YFg.:®-Vb*,3/^}$6ncFYQX,ےO]A2]p"O?KQlj᏶ֽۚt ;~fch~6 ͷr.-Xת>"ig73AC#Hǡ:%^3E,*/ xkj^K?R{v@74?$P2艜?͠;/R*^L=v %Q5&UN= ,r {$oеr ":';V,8&IێVdP 1MVl//;4@ccZ$k򟻑1&J]w"l9f0ȓfoX~(%RdĬb[M9 e9D0Ղ}.,:if/Æa mzjˣíώ J2Ho>GV*#gNW .R\w7^$1iV_Gm!M)bx&x)+aƜ~ l% A{_+p2 ji?Zhx#Q|{w['* qIU)C#@_7s56*g^h>O8Dv++H!)`~SW+FI!zE,o~(}4Vk*&@*&e:ڌsm (ѤWs_gƾھȠjʜ4K.tl݇B; 9IݹF1d k1ZRWYlO N92}CeYg\pʣr'k8D9n.W _DZd/㿤 ƐۃU lz a)k HDqĩ(N1}`my&mh+PV1j~!p_$8U$8j;{,h%J8Ò7"oh|9`פ^6ʹnm͖š{]"t'DXtv=vK;:ڢ!h ځ\)խ{WN]i'6(EzYո*!t'/mgEఏm`Zk-A.4Ρ~A)bTn!tA._yNlBdm3s؝E.—}v&[tdlD_V`@)J%.f?WsKڸgMxv{.MkY_7(8Tj'c%+WCG4R0eA<.9Ji~bi;g܏U&/OdښgZwu'd<!)GJFݯ[*q$ݑbfv4$ 1DaңNCa ahRX ]Q׆1/'!U蕭bGPDϋl~$ߡ$Oxǩ5=!y)?,;D]7@wj xAk|;;8zy\в ؤ$qEtZ7m#gЛ+} u|y-醄Ajjb "aY̥G=NK0AB{\EqN)wxS2\<'ncOe ȧQ Wa0]wV`|62Q'hž{wT.ZC[vׂ%~^!Q5խnnTtQ$WQY$R?7l&4!Ѝ1뼞,2̇#Z>KyStG]vm##i 57=Փ8e7EʮVQrMϣ##NJvK#v Sѫ fA^1e;U#?]`kT8 lPV72>59QKt|Kp>@T}' THc̥pȚ} R[z!TPH2QcWLB-x4P.΃An`(x07qt+ڑV p^XBڜ$ԷmI5$(<–LKNlj$T5vFS'6ʉ bDz}RrBX⽙^ v^#R V."#|U>/C%#c+2ǔD gPӢ~RY آ71 J{EOKF^ ՉWAX9$b9QX!k|TtW݅`HSB%C0aNG Ɨ#O)H`1+)0?S:"?Y]{тf lc6#М,Ԗp6;N(@O Z{jݩ*3~0~E0i&pm=|􌧿j qfu%HjFp.̽-S܎hvT CT"{捯;uʹ7,<f2rJk8Y0ŕѼsj.-asztŧ8YpJb u)Z:YpIjZ TξǯSN5t?«fX&$ bHgif4=`bV8ƬnVL<&jjo ;/\:Կ.vH:s?}x#q/mRe2 *ՔD2l3|T\Pse/;fR@<5fM| i={oM"*-pPuJZ 檱cbCdTm1}o;9f4CY84/;{G7h$v1o1MFڲ0U |'C{qÅFHpqR!u3ٵ^JU-+_DžZim;0$/P~2]hKPd,^4,$uBt(Gӕ߯bۺ&'DB;o ƺVsPoV3Dg\E?[OD=rʛIxT0,HWޕdtdiZbW͒b&GMpt]65UP*밼WDg+S@Gu?úK;wsΟ 63^,}vӗpaTM+N)wN\&;),sp5^^7"Mi_r"<ɇ-몯R0E\";R]ⵑΪ`0IA **rsZǷ%DxoNQ:0K5t*L"+(+7(WYX '=U2Q9 opI%nJ=R?}<_mؗ,bw@lj0 e 񋪑;~N,G SUbVW+[O(0>KͯqNEJۯoqV7"GfGK;ӝZl.I[ⱆhON&y|̀v%z2&ٜC`Oyrhlul@& ޮEEch#MO{+2(ޡ̨44 Y:hH2^4Ņ@K~<֓9can/0z=KsKPѲ%Qt@ 6r C7\rhpԝGKHZpV U`q=Ž0߳4f1 8=46xQ(ˣ O7Ԉ\pUlJXm\$sIM…̒MƏZ΢ 'pwU7xDrEF:>`)n5)mvB*@vpzbL3Rضƨv`f/Ys!^ d8"S\+kmA'w ߏ<1=EI4FʟS)P&oO߹_uc݊hPz C}H[EBtbtHJ>_t+CK5V}F{{7b͟*Gi&+JR>/j[׭m8."pyІ+qiH*zqOcow^7O8ֶEN:c^L$B6GUe )'f x0f)1lj$56P)P(:qPNm3"XكBJ"Kn]џeJn}&zg|d/}}N󳽮s} ye):Vdft\ϧz/)yh-fNvG︘*. f)YiXq י F jwX 3gngr5)R% gea{U!Єx$y_wsC}  )c-isa;pqwDXS̯b c]'un**n,u098MZo6@gئ"i@7; )o{j{(>w5d/f#m71i'ӬEd@G@0ObN&=(yO3K"lT@Br-81qKOWT?\OF3k$^ߜi ( &+J1~ Q~Wʧ6m4Y"|rhZ0RQSKK/7qFda,Z (hZO8*@3ںj)R?2c%VePwxj j#h'38 PuV}1Sq P[OӜ;3}qg p'58GQAb6[^I)?]Sg,ܶrp{G/Ȝj@ 6> P &n%n_sz'mY1iNQct !_M_n2Ua0QX)Ł[DM F6 ݃#MU+c(3ThO eNM8>*B0@2LtOUㅫD ewB!}q$c|cJGC ߲[tAJPd ߡ0X /1!1a-U+ޠ}D59e{ø FC=aE0 Z r :{fQw1yݷ\oe+r6M;FcV5̅ 2RL8uvJYVgQJą}-"̦ \z9p}K>;b99thb լ)K{jj/-X3;)wr :Y29% ϐALs#8ׁo0Bᕊl SX` BŋUjB$ݦ7x3mOfq'4q{s[UuY])T-й po#ܺ}“S>za. Sk ^uc'Ȗ.^>IƮSwR/߁셞j&xЅ!M𭷯f"ScPLv,IXM_mk=/׋.>w}=uUgPlB8ٰ@6ȃ(lSxe94Va_8>t+/j;W4e@}[Z'DQoגS 8s`<ީ'^Ԥk^6xaR s4Ě w@27@~=v50>bN~Zgolnul"}qP*z0^G,(Rqp?0VR'YSI%U E`zif;-|{~, >%#O6R% Nt V`UMm  yoU H8H#FHMVD_HP%"0MsYSn$PV+W<=;>Jʣw̍;?b-%Yg&Orأ<;2 D&cto9ǟh™?PkӟVuk-żH U<"NI=_a L0fm9IQ9s 1 9+ "2ӿD}k*&!\&(#}}LJFyBMH' ЪEW調15ZMF%ƲcS1ҡfk0PMqC"X%ao@O#k J~x; B3AC}#֕MGՔ65FC9bLTW_8&TQj[0/z{ h5)٦#ӝ@Bzp|qSl̵@_5.8+hbRL a*,X(75HY)Jt`T1/4IĜ7 sPÃJ%`ўģ`>1dr=\?/n/+RZrɉ=_:TԁyttOJbeF8 *H?xzrTPkglD19(͟ S(_Z.)L-{x/+ؘ1|qڕWŊ6<ɻEm"]'dMAl]E-ĩ[m9C 1+4@*5|X LR1sT68N$R3C,ߞˬrU!Ai[`g)J0\\MU1"*Qt|'ϨJpb Yn$+<lӷ.JW&+~:q<+?f\EpY: m̧OBKt!!gO6ൗ-w6fr .b Zw͠Bh.‡j L0/ 7K1'J"顪OЮ b,!e3>hX\yKpX9c^);^/&@ן$(4$ N,p;|w;'&>Z,(e(>Qk٬Di#D~B*?KSdͩFMeU.*E>aZKWְCr!YìvƄ&\?BK95ի_ב_KkacKg aeX<v3g[>}!زX$x +. uV'tH폳Qzob}/0z1%fe :w6ŮHV  x "D'zkj*o3ȳsbfkQO*9YIl,3{BkՈJ-zI#/iZٰO0H)}6yzȶhXY솭~ ٞMC14BF-zPK Je2nvè--챋M SNGV@Zs6 oKﰤ0ÂZyQ@YU{&FL'-!h!óƒE=Yj:7)p7E[b[F[N[a[i56ivM[6/|yP_]LԶ-}|>Nd>uZz@Hw܎;qi'͘nF2+48gџfwLi.:eEjĦ & T;D/ k&PQg`im5 lȇ~@IԓŢ0+6\XX4jCd$oE5:Huƻ{?3]_{k'CvW%pGrv;CcH:j1Ja*\tzRN;exC:X{mb)=2—%ݨP<,B23;Y b9uGS|aRqC37c h)L~b@GS$o> [J:/8~$XC so"C8&IeI6bDcYV)zɟs'"#ѳPakhfL-7RLc}JU'e9a7%;WjBh#OɝtU%<ѓd=tcF{MeDXKtXgh4 Ё?^VƀґAopA pd"6qXt?S0M .Kp( KA(̾=i\>8ff0)^z^ g3|?_t x k5h `xC4ׇ5"ZJSO σ;Pv{Ǟn{^=6e [& @;iJ)'sxaNr{ˀ?Z1^XY|=Ԗj*e;ڇoDV =GjaZsWr%H%>_h^]0%u3< ?֌}W?S!ѫv rƂ; X}+ Oo \f諝œ|/.Y&' 7+JcsuٸN'%Wc 0}W#yut$آs(8 ?1 a٨. X!_MN;JZ9?H:s1.5Ύ V[w&5:+C'OVE> #(f$*y=ALj|9hHVu3,[=eC#fHeGߝlC5ļaĶc(jⳊuչ\v1Y8綾j\qR5aUr<*QW3{ o^5ZЃQ/ LBuroNOb>χkiZŷ˽ YBfu_b["F"J^Z4ᥳ=#YRc(Sk[~dR \KbK]wJ\҆'ӈ(SY sSC`ŠAU5#Mu5 26`k6Cˢ aˌ. >3I5(JĶ5)ɦQǚvptg=Lm̥tE$Pw8َVj*dܐh䖚h7$]3UoC“ﭏvYZ3aN,LP xWkِ9,Pol|tO#!tgcq,i艹olF'I'0Ͱޘ1g6͖ų{Ek]^>'Ժ7*DU`VѵtYnyT&`~m"DiL~AdӮ랱4~6 %Ќ.ܬEgZ(mơR_KB= )/Ԝ9Gw:dƸi6+wc~"χ o|HGY|BG`opP`zPXxйA{qيrD}Uub"}lBV7KA0$Q!04CߚDnΣ/?v +c-8hL ?h. H̜4Rסu-uuz 0KQ6͢#'ۤq |RuuՌMH`3u\H⧎,8?b)8< ff~{&mR,4L{ofMc׽|=c] co ? l!IVNhH)fULnC B-G0E9kId.yU acمt[ p7L-Ə MOU~ @YxA;%<{8i1[{!K>#jQ׬Jf$ŀ] ~:g*DU +^dhx4J-y9 -bf< ^ua @FayMC1'v/I1 z"h M+pɪG!@XBCp{r w EbhC Zm^1~}KѺ_`c:| "$T0QSox\*wNjtw֧=5n%мkHQ`Byҍ AP]f,rxּ}@5*h7qkkGbC㨜d} qدlWocQ 3 ]lj3vmpP?\vk1q^ծȄvu# T AVT7~}C:],9jQpSҒw dB"D2o 3M U{ Jtv")OPw1!)T f}.b/5b4]M<yDĻZmrLLPLcq\3`2'6;w\ݑtzof:eQk_-qPV܈~d[x2E%G"uHڱ1 vyq&l~d>LoL*  c'vњ+{lğu(z"f-50%Gަ;qOGY LrV+'\'\CwQek,Nqr;Hu-cTmoٓB􁵉):N!3_ ni1IhnLO0h=8)A4KMٿyF5ӀF>;)' i_8a W@q6zVydU@f=AC =j=M&:x6;4~n#1_0Q .e=ʮ1|yG],0\ю 6aP*#'Ndѹx]v= M MrM꿑D/Min/]3"vEb%3Fhn#7H2l%Ktz#rgpp͢ӏ|=6nW=J MhNVJc|[hs!ڏ?.\0;}čq\n(H&Gmؾ-' HyZ6>.)F(NCF!(Nj9y)wbd#~@r'zM]L^DW֪L%c3wj;i"-PYNŝ|64 [7^wD]3iӈ+PƙnILO/(f@ede7!y ,lв$O@.Sy]dcR =UgeyϹ䡐n6cFV::2ϾU:q p ^oʭ>+`R9㪉;*ݙ-_  ?ЪjbT2YZ9)= HSv4I pزPZ7Wr>|Z㚲ASh#@5)6Plao`-;` ɧϝ e@vCdNi!Kgxn$tŚTU'Yn){F8 ,<'m,G M@cv8fxKOň, +<;$}Ymݍ'@_#koDQH l+)섂 <&BvDhXҜWҁWW&rl=3\S;kr 3+[Nl蓁dyH ̌A8Sr15vK{-4K[C-oRz4.o&Ɓ{E> {{5䠇Z?m }OABePiĄ%C=,x@7"}SsIL'I-d<ţpI)dY`] CR|PB9Z6(qAÀxdDP쌊y+gJSvgA# SзfB>*zOW'Ӑ3*yX+o]Z`p91qQZ|CcB¼MfPAĒ])5Pu T|J9(5f"Ԟ]46bJI 2TڠRj2~A SmeyiKF9C~ے۶ca`8 TiAnQG7 v#eFM?:f+"nB~::IQ@ɼbYG7в[źnũ<e6$W9o l~+"5])^7kp-0?xzy4R%|?q#6li"!6[%0@Ul*{oL.9˜qcL# #[E;⮋2ˋ6Z@ciêd{gWIT´3zc=r Er9KtX-9e-ƞE}3`<{X>7n>//w!B|x]Eˀ._<"gUi Mu0BVPyEc(z[pr8%{ktæL')9ű.{@(J;q$'y+V4>4QǍPU0ajMV+lF%;xUbh{Ҿ%@ङ ]5^Ӵ˹VvJaKCQIo EKzHs0_@ R-ow>0|!Z`Lnicc0-ɽ)OVe 59 թH2+K~0_Y}*K6S0仪Tk~X^6t݁axi_I+H=rC̵Ŵ. ݣ`8@9r}M'Nߊ֨{Y5cҙ}?!90v -Tz$%?Me\ԁ&J?4Qn/8`BT:ȖΨpxj*jo2~T,KJ!۠Ϧ_| W/[$ âXfӈy4%^*ѵje8Ey'=_(G=>&^wYD"Pc m"Y)T\l2- FE  mxpRh&BB8+ꋜ` ^BQPv?a`NnZM!BT E^>6ßgh9u$1nJm調P8?)a[hh繓[!eLb9o@ou0 M=IZnF?]ʭUU`=ݦZWAɂ_b)uYY[-y_+I#+<)s:NJ(vm+%N>F /ZuG΀.i "pDbKg3qmuvc F9/.A TF3;bAhdEO Ams^N:@qQ>s W>*NT4Eh>Bcw;h0;6 u7uXT%@a61v!xZK*."/.F.W,{= s$̓W`o[׌_;znXI !M%2E.+bb0\9F5 ŷ7+bg,]DDRM>Q.#c6.l %5 QSo2IOYrLMLD5,ds4@}BcdC\4]|p`0wlBR]EX#&@v\,C*~媕+c+,2c1>QʆF)`ۡ[#ÇVye>5qb¦Hpb1tޱ*#CdmfeaڈͬUE> .C‰wiy;RxN=v&rՍ6JIC%zKM`e\/hbk3@hi*+pD?qN6= ?tĂ:W~(5;{'sA&VZ{yPRvJH|w߈tܿ S+-iW$xtYTL 5K|3SWry ={! WEF$];a Q>z._(AVN'h$8JBOA dX[#۽$#D61(:;'c*^+ga i\*.7RS\JC3F7nfL*)a0\.8x:7ky[|HΰMp"QRґ2>sÀ)}+ *XYe^""\SN+<1_}Oh p_|ٍ#,^A|'†ŸK-=|"࿥]7A@ncO\g"J |V >UЦqq3Fq`1б`egX,{э]ˆdZl+xEsVb [S&m[fc=b b2Nĕv<+@vDWߋ:$,MrI;wGskfP+)5s4ԳFz=u:ncY(徊 A:t1 [|1p`Rw|رuT<쾢6$x~1OU4>"ױqnɒ :^ )GsL5-uj1Ф; 7=(d vQ66P+!%hɞk_Wl$,tx2,CW׍QXasіESwHrRk?rJ C/c&]oGәu|!@B7\Us]E4|5I..>#KX AN ?;Og4cq -21v.E uOXh9rGQ%.sG` to?@Ri 9lثPqK֊{ᨇ\]#z;mcsd7#) )s\Z S U٠Z@;!]gIy3_WDi0éq=ˍSKEP"O;WA6uc,F _䵑q>? %yڪ?Q︀Svi$v#ٳ[_w\($b[ڢ)njȩJkocC%CIu ͕C«dvR̲ 3Փ"e`ɲ>(D!!ia~D]? K1f5‚Ax9l /}`Y sUeĎ XL2;hEFzAM=\\Ux#ZO:Nuզ:;=*nl 1Fr)aCW= E^o Unm:*8-^:3ԞHДTWF?18pJ֬2ڲ#̖m x=~7%Vj3Ѭw^$R~0}H1{菰#2Y# )iRo<nh#G/1feƪng@c׭ujB~U򦞩*vDg;[20[m`vmRUw\e%Qف}W D Mk'rwM)&!< '<.s &'(wcOs3qw,yV~#( 1_#> AU/ZP\qPƊ@28>-xi S G)8!*(A l^nDAIbϦ҈E`G&վGRnLBյhݸ}=<8E}D}[,\= վT;. H Dv %e#'wX `--)U(GL Mߏ1,nH3;-E.YDjd5P7$U9sӪVw$x1C@XF|xBץ "1H%*J 䗹ңM֫$.!N Կ1m]8+'N'jKZWT0PQ _^ZK xpMt1mg('Έ)^'!!TTʞ"%7d_0e$WmG|Q'LB4d#"x+,$ w5OF1'bh9`Ke:ֆsA/+VYGW$M*4GLgyDFLV6O-H 3aa)iYAQZrǶKW]"Ø8o^!$>ї(Q˖Z#sbU˩x{CPYݢ~7 R^KmlB y)MV=a5I F-YI}k; dhCqٻD7(ܣ;%1;ع gobꌬdmRTdܽunV/e0wc9x<|q*&ٌ_P( 2p}[BˏONQD8 o y큌'A%rO4?~&!~X(z38j+}OLVYDf}0wl6C0ՓEm2[Mγg%yhzҽG?~|*ab:Rng\PMMտ߆$Nv 49޷ \ZVbxXɷ xp/hf+L;&LFT5 (-޷M,jw^xń\OTz* {ǙV7UPD߼n gZpe%g9^ #Z"nbE#t W+럐>?0BR5?GVƉ3- (.yR Q =!h39xXH|yˈi_E#/*' I}> 7w4K> t7Hl*^»ib.fB G,9"[vPb_YV1-–_i&OzM1"x`ӓLm*:P;|j4B>Ɍ}Ymp]i|S!^=״n ꬟ܱ`>jIF@`ˮMa;79G8=n)U5VGGK^S]t}_k{;sdj_綟(pekP*Gg2^}Z8ElJyA6wFarZiq6(U(W/T}1BF+rY0xFv Ba<8$)Dc j|HO`<~~.; )ǒ\v(='j"aQ)if{0>~M<#y ,՘}inX$*Bf~[yVW0L0$ڰ>w_ef6YQV\X܀e+ ,%yM?U fY:k4{wa:+6VXè:4x͎x"N\{,1J%;ۖ [C ō#`,'`-h,XFf~@n^'zT]M^MZw=xÂu;)u@ K-^M.+~<2|x7n]bh6~{AYRsS[u?l܍ᚵ-߹~ k:gcRkؐ ݌j,.KiGC)Tod|y[*HIVS|Z(q;1KR&,)?,|U:s?q.["c-KZhmt74@9FztEq{K=D--|W3(NNcrꊭ;*3G#ޝ+;IG_^4m9bmkt ,ͨ#JM.hAͼ]g._I,07 .~A*@kP.!jT19*_"Ɛ&A-gץ:lǾٹY1y%'pNWfY,V5!} sR898^zZ~f7Kr]ߋmWqТ;K'O\~^ ɣvqJS{00yI*g )j6/wPlq2U͔rsK}=}j<&BLb+(g<߁.]E9XtYWU&fnI w|dSsSO'@гaqWu#,C {% h gS;iet73 wn8р5zpJ)_ٗ`xCABe18N3*ڇ\AgX88(j&#c$\yD\ٌ`M[T~[р$Qf1)l0+v'g 9h;(U5{dħ;@w4TJ'ES"jWiM{Է \7<*?$;TA_NuMiX]m2ݱgzʺM vnT^(,"; kzP -=mO T "(luX-RTuJE0GЧH"[8Pz(xm3h ' *Fk}ESm"Er[c֔0eP#t>o]_v2 ṿRk ~/Kӛ[Ra%-"u&i+\Ycvݤ{\oEFj("H{o*PS,X-Fkw7?4gvOs.l6t(xJR?%sm1z~TL|SSRrla=()T6|Y%.#ue.pZ2]Ezk2~ yFL8x) [VHד+E󲁍W"GH"u5ё\}/ܒ=,1=!$r{8|**š+8Z杫5E1+7eG[U pJHڽ_N< ]N0o-z1}!p _]-wjHvvT'+43}>a\΃)WP }'4 W%`C `:t($VIYU=Iutq'O6m(A:0M>8Ҝk-`pY@qyFرAq/ W$ƅN-ާ"zuq\94y8"bۘ 3 h{D= ;R(TMKQ FAzdoخ:a (6H!UK@T䎻䧑Axؠj*q^Kw]O?ZvJ8(d*w?ՅF 3(Uj)K׏:&ЦkI=ʆJ=Ѹ3E~3qc%6gJaLd ү&_V |o\T2C6Σf$Թɞ7*wjKe >ɓ&H. r=@{L(Cej1pN iGw-T-ljg"F "ۓ~'~G<hSahz}[:iC;$닕O#Wrz^*KyK /΍6?r2"RKt:hI"QV $W-CQvcqީmD"r wC茔w}IrCG/ITQ~ŅJ3)9:L9@:MpO< l-D'@#lgT$ˮSܞ[6:I oJ|?<. [y[4c6x($,6VZM3(*C;gݏ$w*au<- Ё"T<$8%bXc].7W&+~%J3or(OQ+ S8F[zEhԴ弩ޔkQy^lcXpJOZxaU]1z?֜ct &/C@/)uKSa{rnUWv)k(q \LTMkaafVj q?b/* iҨb*żعŏ&YfH.}ڸ)KGq}6ss׾8I0Amd Q"Y3xkS?WJhR2~d&IMDcY2_ ?&^kzW N!!&It|1+b)Mzt3K$3p2W)?u,* &N|h찹묬M@:K-9~"tk-Mܚ_I˒nX2ޒBMDpu! 2/J/^pvqښBn~-6D1uGZ*ޜu룉Wjd>SZWOhmoLu|OhCje6[rCfit& 7L &1t 68R!Eӽ~ɏ[<Ĕ6Ey@ @ll0fY3Mg;weVuy!uIf{G6$FBf@Iz{c*(\4ݾ'N$&R&3KǑ"8$ӚPȿϹ;iqS![t153s ?D!i6{ U̇fd\RJ^>I(o!`t0yoG3ymRW!ze_R~i붗ug#Îe/[V焦\_RV]7rv:8eq qsH N; .x_1ŵf25΢Kb|8fU%et9w,=>_y%-"]ke uߞ↎rR۶[*@oܑ~xף Bc5qr4:BxKo(k\ND=o^D(ǮNWdlW ՜ r\芩Eݖ;t!ĩfSa [/`r21ɓ֣*{3;c.'bRI8͍\ JBv̱B+fZ-$GL ?ɚsM RY cN>Z257^MjϾtz U*Ȁ1Ձ}1  (C{GnU*$f8PIa.j'(󩾱=h tK4s@7(9+7eF ,k/EW, t[BSU64x{YUj`l epfq )0^;8X:6$;T6C羭5+*җ |=p; lcq₅ M #wSa䚳zVn-܅޴\ z0+9+[I,}aC{w=m#Z絯HwOHhlu,RyTPxU"$o rSLTz"v#/{_+lW,=I;'s7醷#5xwJz޼6OFa)9_̿T@rm?'ҖJg:qh`EX2"^Du52CGR~^DU5':69=;Oͷ \-a9̶" w5m?jɝ9m3v_VB418撩K@i a?>d?Y7_xVV߁U136^JoVk Ayj)6zYT_L)&{N,R#W>1A8/lL`@½0q:LfŸᐡ};MB"UJ'uʖϢK `ZwW;ϞP4Hr͝}g45]>U3mk'i# /yj d0pぉQ.J~6@YѲ P*\Ub8aJNX~63#A+7xj잮}pkcj΢Ӕ$R[M$p}-[GOi؄^TB7__u+]7KoQtڽ2ۡBrtPԤfn)[3؆H`![d>r=fB w'內Xڰ$ Kcqez,´L6d9v=+`kx"0sgfC_#`HE"Yϗ+As}5Ee}"AJ #}3eY_II#m`D;>Qo-i ]C8rVhE(@X:ցK#)LJ-Me/pI)Yz?jdP}_'Gm!#Ai:vo;)6ìjWڏjEeY<%ӱ.In;R+gҀ 6,vg֗;YҲ\}2'׋2L}{4!JW+Eg a9f\'͌ hN !u=Ur[G|Wofe=Kf;D 0bd81 i?~! ucUaRmF38eY3˂+I|#ͮ?wbbh6M'\.V:'l~Y/,18g}ˆ2׃ ̨ز0$1kh Y0ۭE(faַ'R=վn˖7P1TB0M|GKZz'>o{.Y&&1!K7p1X16Tfko[rs">0{ dv]0Ӫ_k,T8#LǤ2~>*}5R(f_k*\g&\!8 S/3PIQ7doћ8+dNN Ml},RVT3ʁ`1[ '3\V`_eŞUIiV<RZ)Mi.I a5ȵ!ƍg  ;\4Iy7`{l X>N&7﵋<N Z?+|6F (Vaµuq_ 2}^]Kkjй*mҦՕ/5.D㌆K~ol :@t5AJ!ӛ>w_/(NQd{R\,(4}̱7]+;Pf1|j,6eg42b0ڭȄ Bi;J:M^ok*`XNKgh91|gzgt㎫4L"9F>F#f̔7Ob7l#(ꦜR>&((Wcί!N h+p47 r oXm-a}t&RW k!F T *J??qI=2gH<ü3 OΗܰ-B͂49k؆w@j@zaN*{yeZ)"<H|'WcC mz*CZqY*;~ҊH˩HcXYSwa2x +<Ϋ =\ +-/^S]Vld1paLl@gzu{C;C!= WFq"> AL)7ĄҐ׎E\ «K2`P`"+Ln gW-QMeU<1(v&_DZpiz(%7-?R}*Y(Id ҁ ]/`%Kb{5ť(ƃB` +,L*sǤ@[aHo)w1d]sgOl,~n8qg4C>Uk\u %%h.㬢+EoϲM+ 5e=q]XGlt!AM Zs 9䟏XE^2sQ.6fF(G'7F<2umk5?u}Vْ5OG._ixehͿ&\X_FʫRjv`~d"Pp鎵g/BKJL- dxҫTR"-/1N}aIw=@lϓ*1a绷Xvp?Jt V97n=I~j+Ʋ @f; iϝK<)gPyPo:,[LKDr2$Y VZ6b|HADM~ծ!Z޵ͧzoregXst J' 8sF@btʓULu?%.{}rӟa(s~Ҋ|uPHeVԫڋLHv@KB[QT I*pbnDS(!GE˂{ԋۓIۦ)XlBW씿v[ Z+[isͤHS\hcAr;UY$BeHZY?C 5A⇳*l9hWbx k:u ncNJ)>chCcK.̀r4Y>d#4}ed51B L6|J m8 ]vE@Dd kTͪP|w gƃ1d@cOuRlJHU.̪bAb(]}N;wݡ g&[r CτNwC_V[jǯgmE+|0}+ HJ"̧ζ^fYVej* JSwh5e8:A*ޕ2dES5h/ IL{VKj= ?622|R8Ɉ͸ؿ)>"Fv=ny,JpqI,jBӝ*p86ԷJt'|I?qO~ `s-Z%3-ȃ¬*x؇:BhhQfOL::L pc#W.3a *zfp S!SdB *qFQvtjʞ@RSh8n|fJhJLa[_9x]hMzصZBA~C?1 -Ԯ^J&䃴6ae)Z=!6N-ŧ~] :QxMBdODK9nKm;-%ل(ݦ\ޫB6q%H\fܟߢf3E-L#WE]k1rS]}& t-a |Q9Tf'S_.L!WUTm9r'J~b00 ZUKllO4J|l[4:Iٷ$zw}.F˚j"r\80l !{e&>)S?6r/"yk,U0DXM窤֞)N``iS5YW@F4H%J ' b)!)֜ȎoEAyA}_HLFܞE Plo:|H/y(ko=v2Hxh ܫmb(2)%ޣ Lۥ*Ţ^ bv $6EwųofϺWpm5g^ 2aEvULA7n.qA]?\Щzbyހ2z4i͖oP9{8rq!/6ЮÀs?}drS2'{|LVqQ/ONݒٛ-ܔn#h8҆_'4#-,T.zvص0`W#~9ktǻ'!h 1|pRd2lX}8lSi4:⊙0Sn$9v`UH_(  2­x23q>WZ`F)g -ɗ&= !YT'."O>|Uj E%T}ZpmS#!Yl6ިp's7}7ɬv^9;bO%fdN˕`Heᴙ S Rg׻$h c|݃5|1*iTDĮNfdCy'Fqvg+ϠnC C((;V|Xơz;h"_\u_D[fk+5TiO jڸ|Ѩ=u(ux b{ԁ1X9G3ǵ ><vT2T+d,05lPнH 5hqegqad=W=ڳ{8Q{U'* /:zyE+B .X/z,tG仩kYIqUٰ'ͧS"8Ik좉}z7!mkx1E,8+G+uceOV`:^nLI{P]/yklus, 99޽Bf {{k_LdQ3KX5%ˀ YF -6' B瑴>88E ElH 霅)-Ԅad@-`,ww}D+R!~6̩>k9No͵AQSI֒MK2 z5 ,%?/x t8#*R{ h[JvaYق5ĹK %v=WiikB(*2cF71#uMBMά=^]x{q.OT2o'*)EE( )&XZ̒i$֡tC9ïGB| yH<σ9HS&gp~BQ_7&uu,$}MY!YRjƲkYEf n?c֬uֲTOJT^ *frP|3HF k;-#ezh=W8s`SH_k݈ q~X9,.aCqW**_n-1/:(l6NiLj9 v21)>): 囒==|Q+g raCox8pI;Wrhbs 4++N3u&ҥe[Q?a,.?$ovq.WoM A@#| 6艨 "֧ P2v`"F^#?  Ѐ/Y8B.Si|;&l4^VD&iK ~x[CF;)6UiRr+ݼf-2e1Xd$>- U8\s)غ@XmÒtsǛZT!rlB^j%|Qy{X`zSYW2ű}[RCtYÖlp}@՟:ܕculA#veMnuDPF,b 2stV48I͌xiMɚ]]lc)Ǵ6*FP}QumBt0A7Y,FB5#5:L YLV`hH ^>K4 w \8W s7XVeII^ ȓF0-ɁG;\sp/N!hIC{@.ڀd.+"=b[c0&#&ϐ eZsu} 6=aj-|HoN3>yOٵ h ;ȉw2ͷ ?jl YK?9%@$nb֋F"Zb=Rwz*Q +;3#.! i| pam;G2̣Hu6&' B=Nla3uXA& z Z=52&WAfu'F\EQ'M ciZ*قv)ƒ24Nǹ: OZꝦZҍ;qC6i-B܂GX0äOONk,ؼ޴ ZCh+ AG:=ػ~¸vуߤQZ [GqS=r ֆ εɈƊ*ûI_,ث>u]e1sffDEX,TX2R/(ed~:ܪL (G n?)m6F&2Ds'Ym;2qm ywgiO\R߰gbj!Hj$ F {p.^Զb<'U;cS$0\Dj9}zīfF/LԛÞlUi-mrt,$"= せG PQy00K!F:kz LjL0YwFH2PrBdQ@ xh{ڐGwٱZɃC|y~l$$a+y 2e^ՔȤpnuFz!vJ3\H<^֌+wVhO W?8nnW0=4quY^7gŶ kEZ";nW h cQQPX8=j#w72Ý3y|Odu= 5=S*'ewM4~a@ljC1@nd jﮫ%d'i IWxp xK.| 7f9!S1  4{u tp$-cj]S!6|,8_FW,8M ~$'*P+|{$A/] mk ofIWQc$fVʊ|=z"ND !O>DٛߋW 5b$}"kXq1IV^]e\g5iÔ?BK HBmC(\S><ӡnO* "Ϊm\.Kz4Z3;b_;{3_W|CW>krYY}x =;V3VGǿSgsͼ,`k&p[Z M mnBV6_uv *:|W5%h?pMJ /yg+#K^@j:><9Z ]"Cps(A•ṚR~ qd(A+t)W@ɮHo #w) EH)ND>6{;C;LšhM-+[%d=3]|c酽}'3 =ްZd wE$p$wX9q⦉ڂV\QVkS!ڢ3I.~g>I-w޻b(TM*$g!V-29,)k?R)ޕ4ZtH„+79֢СI0Ge#ռ[rSKe:8A Iَ/5_, XX+T.>̼44Bs[oP訔/^O#7jZ/5>#vb-5*n CI2#/O+Gj2O^u,6Ytpq'UG@٬rN3ZXو?У쐤=EU\1#)U8 djEŜ+i9v afl=$ڈG$EؐU·ק:5r&-D.a@l0pav~/,VJ8Y`a([VVK?.q?ˤ4g~KAQzx4^(]evu|q ڽm|rzlaݞ9ѿؓݿx?mOͱ@Ek|SiUΗ S.$7wx8MbI!敏$~ãG%يpf`1eGB2Vo&_ɻ),R'P m˗\eM8fqj.

;Ctt:DZZ4N08fծeQ ySc\: Gxp5c_Bvfa\$6shAn@ki񙭺r]^ǘGsGňͯors[jgf -ҿ/> aItQ6G8{QHovRv+KH+•UwQEN19TG})ťM ;)yx ɲLZU Q 7{w&Zjѩ(k=,9ފ0%CÃxv yXn YlYh bUgݼH$Lꇟ Bx ޲H&=HiTd'TʹռrOqL<͖ ;aezd.6z2N" %OLpJMl+8M1b-?LUXQ@T-@7\R/lýOaq[[⒢͚KDN2cG_;\ 37>`@Sz| Oqx1 ;RxBҫ=w:.׺`Iwu*Hn0ڙW7ڀ44tdEDOz .?l!#H:L׉ru9`D0gu@f7QV<-FzxבD,Ϸ GB(%/ dC'nDv9whh wt0U)]߄Zq#ᄛm޶$|!0Im"XOEN߆Y '܊T֦Gu5/datJh`5Cbl7\*@yH`$]|1cDUvmS3">x4aJ FkC,쀅QwhOɲRU4IY<ނlM/ ŒH1ϳ{gY/?K7LL3D`Z[6Oۧ Pݝ0kë@i`6.,VP8L. 6dS4h?e>G 1Qq֋N%JI*Eޚ0oWǨhGuVU'.3sw( YfX< 9]}H؉}AjVl]Jݔ*yuelQ=#?>kK4ĥ%D 7Fx&=[=2^˲7Vr7́ܺzԮM^ÿ]Fw<_2[n4*WPcLܶt~4M7]γozaJX\{8n#hb1ݶf 8vZG]:)50RY)kМ 6g$3Ǎ`]g@r,oʂ N7 ES/VNV:]r'^w~6 e ʆӱxOB/+D-@/qcsNt q2ާ%^LHd$( pv'];Um ڭy5r9I2ui7.IsG6T{j_u;u V+MÑ.j>SbFU!DN1XUxrBT4{.MQ-0|6CF)'6 zP>^PY&H`t&h㚸,J[ Ibgb!^F޻T59<1uZ  .wZZj>+LWZ;Ǔ` эEMEGQS~j~ϒ^/Q#CFe*[_'e I6?gpN HE1pMȼdiB̆Ll ΤIV;mS>D|uVeF }Źf:Y!Q'P&W/7~$7Ps7)HfYzq;`a;IQS r=G\hA͘{ &ZM7~1\ˆ~Yd.ߙ 3|i\< YCO94~YT}UF?{tFR ">SFHtfK0D{,n^E3}|i|)NK0\eY(_̺y-l F@tԑaK4Yf =Ihm5HpN>>ѬfZU\TM:,(XEMB٬)&fK:*Kb-6eqxF}^g ?H>MaQ&Wˤ ௾儍[F|̰Ww8!*C{'pU"SΌ:t\q2=p4WS@b9VŘL/9BP?ÉyA褏۩+`˔es`kgn0ss$ӭ U$H,Mrksn_Gz@}wb4h]:,fQCVS e1}>:?SRҠl0+-VԄb}W|܃}n'q'gOUP->DD))MhK#Kp)8~ZWV+[ H7-/X]kgCG\jLl+p=*mroFB4v417dNヘ4׼;F{F(U#WZJBs:#ϗ ipE5E{ypNV-t"Zoo{^wl?;ZwnK>ƒ} r۵E462:~%ep/|5;5聱+M@ vޘvД`V,!Vxەed~ Hԅ|+w*cff'4y ⌈@+xX%$H ⩣{BsȖlHc߇tJaoX9 < E KDrk+KqcpSA@ Gk _N\j@Y]P˓z:K٦E04G׎M{ t3}_B8h]^ ~>5&OVZ0,߿HPפ]{$ij\)~徆Ԇ. Y?`E]އv]߆ު:Q̳UGB.y Z3wB~2.9AgV(Uduʄ9tiL>W>Im{;a0~N~nz ~S8# JbVtt xݖ<=nOfTM?|*(qa PG[n_%=9/˵ٚUWD䠘hq;C.=Iʫi.J'i罼NEҠW.`b7(r Ĭa.f(sd0WJ:IS  ^Ѝh#;S[%]wUePZ!ዶg^E°Yinw)B ;U -&~y!G70Y3};S(&9!(*bc eepoUV@%-?i3ƞIlQS&mLX$4|9)=LEty9D~l5Z;dv_f\m#'aDۊ۲&(m鍢En4 䦜8J0d#_0B7Yv&S|8輑-erDQ\fp{Iy5 +{\C:6=JQL#9|Snrnv힩^4zD]UI7O>Z|z7i:7P 3]ڗR9~-YmEuk}ԗrN\iuE0]%CK7!y;^58ӝiX6=h">XTX۪)"*Ӝۡ^w,1jY=ުY[w  T(Y~pӡ@ʆg0fT $D4wh {NO~2gO,)N_JtY,<'r8L 4,!eZ'>R'\*6*ɣ[pˑk4 xChŤ3Sݧ$ݫ62fo\Uv[#H(N+#EvӬd| 8Ցn,cz ŌLzIFπ,3fM,2(007ܸ'd]&@4z0\Li>4k6Z)e \>] =}b&>6 M1zg܅bzc]u.rP1r<+B_ %_5ÌbF]Dq'ܳWFd]>=]Rt&g ?:Dݔ~Thܵ6 !Q2R}➯:dZ˅; q=2tdY˶-=rDvUXY'5$Ek RƘ>,Kmʱ4U%z*h 7e5d, GY'pEuR~:$TQ^ >>d&QKxh?-EtihA,@7>)q}\J+j$873UBL+SƆ-ttf&1ycRT}Q/NL'i2b %p gkeaxZȻ-yw)qpr;ӁP :];_C/5V`/-\jx,4<Bh"#nŁ'B]bqJ?Cj4{AO x"ĉ=%s˚d7िvIrm:K-7-svPt{+]e(W,Rr -A9Ƀ?\2]+ZMl8 䧼[U6v;3~.ͻnc4$/Nn)vΚNIqхy1O@uJg@HC:xju$Rk_2AF";47aw*GML vmrЎ#סY -L"5͆ڒ3]?h"@A ClA_Ag_#ta/,Hx] i^&u;=R݅rؓ~X?E$:zy7y*Рb @2;*E6>S 󠶷&e<1r:O}=41TiہW'vS h]XQC|!ݬc\y)|}E] 2o@8v^=k8拙N6aEX;g!2-r@.#kg3Z4-ACYўjUaL)+- %|ƕȥ0$겍(ur[YϱcD;XrvOM/6ݭK@ 5F^0 c}7i vGDoI{ lqّx؂'ͼ3ޛmp+;gL+o EvAqc`h`>_1 2ɮ͒wǽyxt;Juւ&wXƑ:jUM!&ƀ$Dxy/~Б˳V4([`zAgj~rb Pu0B< 3[he):ghpk: gATQIZĹ%9ť1cK(-k &A jlœ ({ZcTى5Rs4S.Uo?RU-Dex ҃?E 7ԽͦSRxB5\et_QnXcu\ڑIjhCU~j.ko UTR cH8| VyJ>zt'+eEt9u9R_ ag15ݫ3|^z:^^Nx.>g{'])#e7+N/_3ywQl)_Ưp  vr% R=("cnu*K jn<fk@t-Qo}-p"qKq/=DǫDm$YJE>L}<g{jp FYYBJ)`VƓ ܅~$([NE\mv "]ީRbg -$)`ġ(F*) ._d2C"H]=fĝj퍑!=".Δ|qht(ߕ8}5K=R',Np̊Vё=#l˒b>䖤k讏dx SVEFv6Z>iqե1{aII3b(x^,;=]urnҺ?DvӚdtd Յ[.|DҋV}ͫ3k[OSR,z0V-< 9Jv]TOXUT悘 P: !SX~? ^ܗHdXCWQ="x]J@ZQu |&R1 י{ aE uv1>LeL8 b`f)8*˔MDwݳ^@GpЬ[W_?߮g3=MNM˶~8ag-;dTrb2mBv=>>]3Έ[ JSk86$qR Ku!dxd$-R85$X֖qH;lӂi߶`p&yΦJAq wZa7 ̲_M3!PO֔YC)3q)GGZjrچ KO.kyѨW$)~0 [~YT ˰Ila ]6跐R(Z'>Lt4QyQ,ԍV5ͨ?>"J=9*d%a\sOfu-zVn) sc=-\w)Vt+ !7dw`΃ْIٛ[ aCQ$Yg}S-,И+uϝpH 3#,;C¨}lRc ++ N! ƞ/fAِLq0–Hh:/oml hHD⒀ Q)8a5D&pbs櫡qR[qTlˤ_z+!>6Á R(c'0EcXЭ8$ eI9gޯ<[H* jHʪ>߶`jK2)rf[( 7/|^ 0,Z&VKzR]_W9PhFTSDX3 ۤ8coq7ظ͈7"C RGPQsĻ+WJcD9$|6u"f\Gvp@5y"Zk_&6q%98 pW5<Ғ/@[<ŸU!FU)1"8ӗwM,Z'sF=e"СC@B'C;@sx3ZMj`C|\MЋ˖ UwMVgT!- |F[3~9ǿ?ٛOQi>RWx8h{\# s3 fE˸!;FP|(?,b6@iĕ )+ WB^1wn%0c^0gCzpX BS\ |n1K8%\ _ȷ Э^۾Xצ<['MPUjR]D4e(&1 X55"3d*қw sz뗗*h)5"+DՙFOη#Hz9(T[Ze>`Vڰ>`hrsm-eN8ZnoǮVo!~d&1,tAOnivIhqsa9nI;޲*b;|j/B۠n1M;2: Hl3 RtQ*Mi8s,v)->*8.ߍ$ 1"b mŖڲ^iJ}r1-.@kfs O~zaaI_̺|Ad.l)ZA|LEb`vfQE2ikim!m NU5/EHRZ?RbDQeK gN~D? PJ!7{-{1OrW9cW(>VQa{XI¥ކC.یDl@帞bnmK2Ͷ4P?:(ntQüDA7ޒYΛLeH瘺Jl]٪ZD)bЛ԰[0tqetG 7J_Z4)^]á*h"Hy T'O:!;{GM;,؋}2%40P7I.ms. B/5U^@+=]5Qi*unȻm5w} z`w7LnGxC용u}EJynx6R `'v!(b/85}0^&7:f@{T }xumSx԰BЖ.딅L2vA2.y ٝ S^OEt v2C+VR(`Dȋsݪ8M[/<"N]$o#EȽEUYqȎlc| 5QhVz$μ qUv?=tz-Ԧ]ú-m|% P{KVeds/goQ$µ0O7'T@"f.6!?w E.QЀSHDTd5\UD~ Q->JJ#߳Nkrv_[6&i,ʼ7[u8ЬX5 @&8~aOPqC򃕪2:ĭٻ#liijM^iI3綟fS3ML&9DJ9Z>kLYfóU8 [;@:#L߼OTp7Ɏ2zـgGy0e3~ibDnp3S\qM0q,W6nt/޳ L{gw#C}O9A?X;P>,pWo&#h91Tr9ksDIJl>--GmeqȎwuzѲkVU%WtgTh;\lj$rx7i$KEy]ڗQuG CCB2bmJWd׏)W&ް2$p^}y-?x7ՈA$D1t1-gͩj 4 LYE ށ=9ěq@GDN̢iee2NFdo̿!GUp-M*OӳZg:kTNII$ݫ2$1v.9i~M6VVfD+I[0Ͷ =Ð6M_Ψ2VX'zi 'BU[g)Pz-l(8rCQ줴`~vQdiI_`U9!>uTixIPrbi a:փhT4US-wseyꅾTOZ؟v4ځ t{=)@FGג[ĢӒ$l{ Ji FJQ LK۵do2uD%B;u*y4_NG[Cx>{jZ 볬Q`mJ%OvYeu~2`JXU@/,'§-uio ; j|(}]eZ5#6ᢖ(; lɣ4{HM/!`tQD t]ɋU P2>} e)/4Hh 7Ņ}1+ e6!rll\.B8ذi]x~`Jj\4G뚨\p5#n3bȸ&2'Lc tLܭ`3 Pb䑩J_W_YZ03nwԂiau$T& ;Ft4Ǜ.Vt!4&)𨉃^{(4u:B!ŏ@BPB+󆵟v1s C|q}p_(=ʃv|9t+0kDT(Lj#K rnܾ\:|8HC0 H=b9/ 0˞{SMsitu-hQgY4FG pZ Yi;ɾ<S&/&W^v/ %GސQn~\fb2/m >l(ԳY-ݐ?e4Yt.jMɚD*^|Xz4m1d&v 2[ M|쓥"t4AkZGOzDUM} %x}@6ʧQ4oG'@fCG `O^9v{qۣ6YN[;:( /'Mߔ:Ǜ ws Ĉ&}I$OPuɕP!SPlRR nҩ~eb7eF$;y2A%wC+i5yt.@4Q-yZ=?fW5k]CtF&Eh>}x sZ?{La}0cReQي(%B 4sh߁agbxĭ=MmJX4AqMwy!jJR1J7?٨U+2_ڜz<nx; \~jR⪅w/QMC~n~#6A57|2H:Hg(y{Oػ<̢J/I4`S m0cSP2d}={N(VKCe{Y[j9:ۥVXK@ᭁtxsAuEM1X)H^RqGmɇc0Hi)ZzwX& \,(CŌłsT\F?f}>!_uVW=%a 2 Y0m7W\MifRK_&_fFy>F}.\=}7R~"˽q][A=L:̡"ڤ'үW/|8|(drDOW^BRjAT5!nG `7n-WǘRm<m]2U{6Ybm(@QƂm"*O߸;msc҈V_4 CanJ]= e@~ G 61'gLq3(8+#0S{km135nL`}hD8M1:AY_Ri2HCҕn)m)K,JH??*q$\9NY?!2YWNW*ܭPqIofX1 \TR(5v7ȧd홪 v ENPcQ0:p^8 ޵TW4.xy޶I=)W\A3l1L*O࡬s0⥦L2ɚ(fA1!bWhqR\}J̷g ^ <,[Rhr\k9TVlye W%ruK0} 4%4-7bmv *d '(+5h#b\$h)'jw ӌ/Ă5ve\@='"s7i\6ݾ[TnjBmDEJNj)s0X)]t, R}Jb.bm\L2I/ȉx*pmNjvnRU!!DžUM;Y?h;sn;:m0@OW;W xk/"f Gh>wuLqoVoz=]"%JB/@HCB- =$Z `Y 9RHQNL4?{Đ;4"y$[r`w2o'4+M. vq;6&G6>bOPTrϠ%ƍ/_ okE6:9zmu[DUDy<,i8m6NP Zf^ׅ * &ӗya8iݪ%N`smG JBWI-4N'5<7>NaA>Cm|77x:~"!\w<=dNtHpc JLDY^2)G1ɕĽ[" 7 P ͒4JoZ[?ZH'qo>_>>2gұJ~N{ 7nz͒)cZ0) ;yuh+.vhW5J텠4>+oE!f# `~acT?Xjy(f|tAt7{8ڋX#M[Fu#-(zdƐ1 Z`-cDӿ(V6“ {)Og{4]'uًvتIOKB][/򴧫$Ǒ'o Oل1׍ E5κD v-DGz%1d BsS~*%!5BA2j79\/.S-4ҳ7*y cFƯ 3$Ы4ןvt9qsy#Xwi<4V<8YŘ 7T{-vyqp)G`5|ڮu1c5D8wC>cQGN15Qi/ֱ*3ϋX 2Ȅe)ګQ/VI ->_1 /vp\ko y]!U+D9tMufcCL$)DJL@ȿjuDg6;|\^O >0%@ӛ(q!4.R7lhm>da-rZ!zXgEHa}tQh#(ƀ<I< F3Pu)5*2R#аO 0!Sx-}pB̀NmӠ:ݏI$ $"Ԩ}wLZo;~H? (YlHan!<~4\zTw+%\x;LOr0a=]^9Aё)ؘJl Ý:9z~|FyH,5lT4Dg\kˀLUb_웽AB 4ne/*S% ݞq89h7yjObt~n~a٧>Ji",[jS԰9+)p,OD0%_f3d5 ʅyjst{0sӚBe&8丼:c*G|;rSy˓R7b m1R7o2I0OOۮxyə Pk6k\4Uy FX͵cvN"HmX۰1[G{F @߃uSLMmpd }|G(vv x!sii˶^ra'c痠 C6d_{qv5+pE 2*d;YY6wK{aJK_\|6xY?7̕wTSW:K@W<Į|؋h1҂:GiI_rP2҂?:5`-uOo# 9 ؟nrt * PF;띁3艗੗7G;J6o@bh &8Xf'-s$'嬨բG_@7-OIPЌ*.=ou%* ; 0w*u{7Wd63I2a0V1 @NO(f?8{7\h8gOhᩨ6stx3ppՈϩ23e7߸bA]6y`iE}XshR"2Lbi`-T"dë-`pQYH\ك'eR γ 62"`1*)~$?JaZ1kR׽됚@wn_bI`X\Bxlnj: jQR.Op]dу ;[;!%1BI7knn<ik#G@lC4 ! 'KקͺH#N 9wǭ✀RJYg7:(8~4lݨ26bA[;-tER+  $~Em,77z-k6Woa,fJ jQ_-$TڳXUmMp{quJkfr|Y.C%8s:U  (.oILK[;j)'٭˾T_\by_gc/Q- `;T=Ԣ.!kV#HeDst0oݞ򚊋/&Ѽ;l1>sys"CgG-T#>J\R5Sx\* #{MnŸ^S–9hHr.jcвKlI T 2rM-w <(Up)N`]|v1,oY 5tp¹Դvؒ|;E3RիME'qH__s6K׍1Uz kkQdykd8_L/5zwz~ lP˳Z 9_'#->}*DP?zِo-'S}{b_:S,0\#+p-e4CCo4^ ƍ}4ĥ^{)`*=2/tg0i!1{' K̮ާ|9^m׮gzl̎(%*Q VM;Z%ኆg]< UHˢE%"R `qoyL.J_iєm5tF+С$yi$^DQ0*%㣍JN\W[re zFgO3r>䙋(gfw c!e_E8-z뉑'Z)ǙU?~wr߸L;tv='74 KE\fqlŅO}ZNL$NtWw/V,p9Y't׾!xuxx-Z6Xu*~@ kQlM~EEt"%"pZf 6H#$=]1tY{,ޭB(0㷨|FY}L{pd7mӏCsRio: zHƙ K|6#ib`#@翡`JpEߝ pEz?)"*M1fu`Nt70Ua*b Wzʦl?85D"ޭZ*D@3 `SR,^OvKP|m2{5Ŀ y;2ZE@\OY/I2HԴTʶdr [h]PG1D.n4&fM[b\W 46YOF;:.~-WE?Jx=d{9Jڻ}A*,B8N 3@99rLŗiie.)cׁOސX+ g(l긔D9:l\c),F9Of>{a *D9G:~x8+*BŻEzh`(&Z t(G;$UuY#D` +Pl{u$脾ʄWtg7Ljo2єn?:YKz]Vm ~:q֮^%#D]:^J6q~2O^ŗ [K*iYcq|80)=˭`Y*^Q:&=m5.re6,BNeT+: ySbq^zjn FL0*|W(X]co9}kR2:_ ZZfrV\h/z)iX3XAϛ b!@mg<̫J~L7_e-0 9 =?')Sek- G Ȏ9^m`^ShbDzaG4g7E7uzTkʼ=]5]r 1N#Z^h,FgB;݃h٫4$4dɍ >Wh8Ft&I*OY N0(+ pG/}B,4a14`rhi`1j4mGtsaW@0x kY" % 3ƕQ3:Lw2ZVqO 4E އy4nur.ܛtr -Յ9fdXY`{jo!`O=HY0drQ;&. fC!xqvL >[t )ºZ֣DhhnNo ц$I w9Wۡ.'orOZ$ ż %1-Wq1h,wm@xK@^ Ixe3!NkD {7bHtIIbP>j&g$6OXz=8+G2eC2#M۝JvIJ`LG'RƑO4yh2z ܝGý&(9Ņɪdٽ>ƌ0 &&~QUw ܶ~ SR Npp@˙f:RW]L`BXǍJqׄ1{Nl!\Pwʾg(q> %Yj\ o|^np%c2(VT؟ $)pP0 w,C %Tp ,t3\_T*P\! .ҚJeR} t"Cʥ =wnѥ{[KcX񭏫s7MF4kҕB+>uڼ$/F/RBU6;Z-3KB E xi)2ީ&gBT;ZPRil+qpPwV:L2yWi)0PQJߥ3cC۽N%r@.YSXJyN)!`ϧ7 RM!Z0$Ugo>ٸAO⧛ IN ڔ6ꂑӮ;-3TwNnuV)y7}${ z?Vعerܩ}b%H6Loo$KiRX 3vGZ` oP;~'lr7Jz%myH `eON&Xڮ_ ! )j% 90Lue[+U!Α(=+q (u ؂VIȈ#29t@Rm(X;.͔әkVeeIi/ި ej2R܅Lx*,4M૟=^%\j4_E+?x5.[hUcsٱ\]u޳WG8QsU@7 q8Sӻ=jA]|0AjRS B &C QrDG*s~aT=$w/Ҝ*ϔUUN14=m7@SN$-IĶJXvsbx& suK b"y`BL} (|/R̭ äiSڼߦp'?t,_g36Io-fh2u#th=;B{zOjYGi )bjr?$G?AN vq<4:osUa}Z*)_%l=?6X[VO$-K!#b gf#EꡦZ2?7.-o.ti(UG)\7p 1,ks>a]`t#YԬO`(,έڸ13m>a;t L:iѕ,:yLZ[o6鴊z b˥XB9]{%e @4K W1}K<!y}*s s2DKQg,JcāGBaRvぅPeQl5tc`4_]eXӡg P姯kX s@jRt#LHn 8^hP+J`\s8?"ߋaf0+}!T66-ϖֈ",uhcpooEрR K':"@w1ܳA5Lw@iֱr91ig?2Tٞuᣵݔt5 V"F}09L+F oEOb/DI'W";>HKSkB&u LH,Mv%9R=tC!\UQќT@2j zN;)}KMo65g= aڎ"/O/H0>)T>2t(h%4v-ƢvԨ0fSd'pM ;# ][LZ1<=nOT>  Ԧ O'03|sP@qud tHE~K!ڝE8ihUAAIݏqMH&"[ư{zလ֪, q)t>kR?FCe*EeWj떅7A^{s t+f_I%h.qxP`9dX$zEs 1a%*@zI-&:2hĶ9f+NI}@^|?k`T9ѷeeG 1A4+ImKNqt ?Gg.X=կNu FK e]ڹ -E¥A^7B\~jY2(gz P"ړU`r KZ .0qP1Y) Z[SuL/66sno~FJ`lxW$bݠ&S9B 僶Ԏu7KWgDb,r{rއjk=w789K7!0rDyg-$eg@e&OS`!=r5O:46Bێ)?Fg`Jp';!>\B0w<\|ȉIj%X1nHwl4X[D?[j(&N E!\aW#ޯxV+7eϠ6bؑ D&k[ 2}NWыC$+w9"K0:0l~X:DV"#߮_ؚ ۣsPn(L & 0 %/_RU's9sC~.zx~6G#s_.HZO .jv#;jF-Oa%izV{X貶?1bQ;}~ )2 hyqt~E+2Te *46(82PTeK3\Ϯe0Y1,éXXxΟ|N|i#YlП%rJbFU3`V%alaOq ݤ;TB\3Zމ:\z\,<)j`SxT9&͇7~'*m5hnZ:s* 6 lKDTOEe}mz5Ie -4ؘ& `\U "eǞfo݉oޞ/`gn9wg2DsSP:0</@I:YQ~-u!{#diͽ!`/&A@m^DZǓ_6Z!93s zg{s7c"uǁ_:hE>16}&u$oJnЈGGg}Q얫:gjJYc:qw1Ex@gzlŋA-|{Oizewhy !$ׇf[,< ?Y9⍘Q|kpvdSmyѪ3 tTh@fصP׸ q.5d Z| YJȪWj?bPd=nͦIVCm3b i[ DSByI#Qk #ډ& js,ƋHC)z.tvj4j +Q6p+{Ac Ό.IquFHLbC[G1fT^q xh"%k]I˿?5~tm [2/^ C 66d:)J}] }v#~%M-9iC|nxROݾκ"uxƞD*Rn}N)n~W"'Ɗ)VW r B;]ĕ^85DNGyV/㓳 X7ABx"רW!4; 9_1r#sCk||o[kP8at :r=Z% j@ڊ-k7p;a$2tv 2cYP\Kž`9*Rנ4QLUFvwLi0C6= `%xSlE- rꞠXcP,lqw7Φ=<&V낵}`_qc^ 1+ I^A4Wfu9F*WԨ;/<܂b,9wc k&e:Vb4K*R8V1Q­1#uil$ol(zIhiQ;HǷ~梹FAJտ1z +" FKdt\3Ld_0GW$ur+VߩA!kz:/¼ĕmK_ž3 DZRz0"H3X 't RQC>T7y5ʮHQל66FKBfppj U.x[/ َ[hxkP9tV w,^U=nCNKc Zɔtcۈ'E:֬/՜c+RGq@M]_YhIDY.*R1 cWn׏դ/W S Fy ZtټGMxsg#.5;1$A\p۴p"~v-d`7.j-+Iѣٳ -G=uB@ZwNh"~%7'-\ՑAZ(xDEveɥd)$OfՠLs(]O*o7!8vn #zd_&{Wo`.-ݳWh A+ʃHlP Kye>kPVH _eO.`{A_6wqX'#2+-Čų]pՑ/ő?S#~=>Y(6o=<\-N:U78͖DG_)ɚ3j`RtŢ8͖*BK#t2m?޴6V9o07A4ɟ%DIs-45p+18f#rr䅳v إ~X`4y;$64"Œ]ْvٱ<٤q{hrH< rۜW(C,G $+BSeߞ샞OwW9H.@56:;[S! RG3){y>eҷd8>-ٜ7 sdjfJIMB&](&ɓ$Bmj>\ JWo Y=iJi4/jC:=ηmٰ4eJOTK{Dc-6nfm8ƽ9TJh.cuxP)c f U[hâdC 6BnCR~9USw%6ҏGF+e(VABXM|nklwy;5~h>Fe[() rupQtH;ﶎ')M ?XHg18u`AЩ=&xc@ì܇`0|5) x$/vʐNOd 1WPE-MtmV5qӎc~&eE(j* hbn(TۑQN$xQfҫhֲeuʄ$֍lGY+th:Krbm @B_>6$2 @LM߷*W;"~}|%KկNRK1gtm, !:Z{ʙ3cA_C~{_K္7iXD|L'FuٞvϠE*/.eg*dZa7Ut:L_&z [*+L?{]+Ty*3:aeėkz`Dś9LT17_s ݍy|!iWh.r [di'՞H?w=}0(h7:›6M=.m&o,*MVmO:2%OYzVL`QQ( |4?9^Q.BFD+ܘYY.4#Z#/g1ﭯMHF/.@ePyu9QxȲJ5J^²!wrEDEOv[?՞\6ﵡq̲`˴bY aN܊bx‹2,5{*W?i1*)ʴ4+,՜{ 5{Ѻp~mRRy|߾Q"jO |MZL$כ~F@PW}RCЁ8g.}.S]J@%*Wg{f+3"P|FYX>(!|\6$xr@Z!lv n'P;sO4uk׽BV+,INhf@`IݵM$;/C\Z%OxBK`xԐK"'?O;zȟ]\,f *.( (8Ba'CT-:WLԻב"խl3vTHk8@ݍ@ qgא- O%G!*x[3@ DR8Yn~DCǰhl+KJURay:g*1MD0tROrl/c̟'`+KfuģZ]&O H$nĞo^._cQ|@ؼ _"rcI!È,P.b "ܛm8BBF Z(ËKBbAQ7fȧ\-tUܴonh cAIQ0[{><3lk@D{sgz<`aKN_X!4beCmI#Uë"WɌ<~.%l#>ElaU&pHj(ewx SU'VoqmȢۢKQ QV[#K#R]%1Rv7!frۜ='rҥU0Q/^s)D^Ar(F8.*1gF?+,-b8Ę2gTh =ޛ1AtqZG؍h%ծ0>wzEF7#Pf-饿!,$dag$=f";7Q`Y:5nLm~^%39&"RoXUFR9Q8/é܀VOxZ4p/v Xc3“Z,4AM|^ H {̆/dHh!8\h2/CLXjrx7%x&rᮊWvv犆Hb_ mL,a1趥-%aptӿi4bEK̉U|Wc6{Iax_S[p m/u6oXgNzUۘ=.>:PrEhΖ),*QCU 1Җ?@M,p4cC4otRB5Xx"naKcB KeB7-y4;UdvE~ׇJuu7r'GgU*b%:i٦R}onb(^5EJR3;:|U+XX /du~ϮzJy}V h^zBdKO)\0C,V4@rBsJ}6ߙ'}Jij.HO^ں.ᲁن?eAe@e}x&A,*|Bz' s31R8HIpi!̬$ [cBNօEUAQ],ʨFH_CABo{zt%D\xUu3-#,e I›xI.Ț„ JQ$G=QDRCZIՈ~SjnʮFN9MHOȡfHQ&Qx˦N&VV[[O-dY "v86 eUG;ۦ-FA`ipdR6|Q63!P1_e.?tb ,'Ee8@5˙Ļ .c,5nco"U8TLJeV!'5wwtW5~w3ybWh a n8Pt& sf(´KSҁ*?QY#fᠡL+,`Z"5c}# Fp%~bƑ9y(NXX~ԓL}iJ2t=55ŐT=( s^e]9@'+,w9"CLkXNprTI^j |ҟ s"3R0RƘe=hnBi:20k{+aJd `<NXpLZЂ!l9"ms}_,JD^(}lwH8vĥ"JQ;wՃ1oz5Az Gh$^I] @<=DqԒ*XJ% CP@:2H7+(brkdN^5>XwD9ҽPx)zbʼ~R)C p{/'.[]ޖ@߉rm:q%{,(ox;k&@=1_윸>U<JZyP_eSK傾{-}U&.-;V͋<֎e,.{sq.;s8eR 2'`pk5퓰9uL:(\_VaWB'7A^Pt|ERp-AMIq, SҪu'ʹo,[;@t^ Ehu"څ7bƶ d{.E8^8yxedBيK/[^"cWS}ТHPmBu-Uu7+iIn9 ".Wn 0 6R~^_5}ȸp РoqM0Hމ Jb{yP%^La$SlG5]S |RMpB?v"ݫvOhcLgY wȿmXA=9Gridf庯̃XMkU- 5HmFh2kE'zyy aC%][=x5e;Ƽ?Q9UR瓫4IհY ' UvwVx]W>;֙?m?#$',H( gbhs3X0`x@oJRMS;zHh3QF^g(1`[\<c*M${rv'q@ZĜ@Ez־Y7.()20mS#^\\`m"\86C&\?{@"uql^>DO]c|?gZ\?PiRRkS,_uQvt.G4 5ea,=È˥'pH/FgBR~n2F,ok 4 Vןz3:56Ѣq x"$D.1-VE!6#ag>SsynۊpJo0N#'xI?F^[j&^Ė**Rݢ 21/nWieեGŘ5nN^-yĿh7x1yIR:Uv=4~9`Hd"'vMmjquDK73wkWDbTjWD\VdX "$fj_p4Lǹ},-#4~F6\B,Ӈ@v@ƨM^\eUsɳ4=zW`9]vĄX/X8Ng37\p6u "LϲVQ<(h% Cj&SqZ{$yD@|+L)5 triI*N#V#h4.qDK`ȸ0Y%pAN,zm eThb5(Q#S:LJ)C"0h39f:a_\`̒O^m$hμy`uSq! uw)" !Dq3y9׷#C&͎ OͧxƢvɓkW_p^gid9 ݚO.tX=]>d>{k) 0 IS,IS>㱿_D@m~};l^S}atv]N~U[5aI^ EHZL܂}yY3Чy'x|"%l]VE'5ʕ6{q+i5M]dϒV1;'w,䭪5Y x%=QJc̱8.6Pf٥T㭭ypDT d|);h;ʐFY8o/iT¼,sNaz 0VWN+,anP"d+}ɂq3qHccafAi~%cvbw&-NqFröAa.jAf%u9%)֣@g4 ō dxZ -F6pp(5N4 /^b9Q\҇ѲߖC.?,iPXU[M:C{N:B)ĆT=#=Βx=?΃p\ c;_僃'b}*1'X+fp&'B$ qFdb2ozLhAi*gAͤAYLN^H4 ӈ"5-v4N!Yyvu#βLuhRSt mn]^+s?W,1XݛF{< c孎O hݼqqgi75 S9OSq,;njmS)W*kKؐPo?</^84igy{p5 7W8 ۃZxj"tcLnݭx&56vrY _|a?2w#{)#dY0%akkncƵ [mJuI{m 1 {=C~XO$e3L3m35cV_'MM U!@qb1 riZsLznjeuޢs[jMJLqRS.N|Hn"E!dfndClJM`RA#SSYlܐˤT젌eYمS>q{ӯGJY\Pߍi۳!:#)[>|~p\,PwrKKќ|'H񤇈kq[q)8FU1~GTgD5Y*l#0ڟh bxr mT~18A 'y<^.\ɽrZ~H± ꚢ ]xJQzg\.C ˵Hq z h&qUjʝݐ|02 K+ע5wd3>J=Db1?~QHݤ/ۜ>f_bvQCyO[ s_/`u&ږ *  BVE䧢H Py2Ѽw3:6`/V.DS%M\1;zs>鸮 *~ mփ!J153 [ױpjHjK QCέt!,OxuAUJb{Dva.Q(͇e?`?*m!S%G<܃.Ħbg#V|FL4ED6Y8@,[﬷Oc3i~G„NvS׹3Y'H)4:~^HʿNMվ2 fmH>;1ont{XY s6urp: ^cAj~&v]"y;5< U_.;šCT4NMbdw d8P ,҅Fg̞HOO@B*MMO` pd_?'4?;TL&%eu|10LS==<EͪυӮ hH*K88 74p"r6GbƉ6x 83ǒB?Hw׵x6El[G8O(Ϙ9@0AV#tx\+Cڨw_nEJ UAzJ1Uw5.HVj`΋W#TU g}'47fԱ>LEpã[`έ1$[̙UxBPSDOZK m(o&jfOގG+X.P:<+3DD agׁ`%伖tM )7"#Sf`0rD\LMEʸ}Q;,`veai0I<ݷ 2ꛪI#/ˀGؿj6XF?4)Wi-k˶h'r,,%zC{̺_TRx5M&ʢC7/QÜs^VȮ ߝ_zqVw.Ӿ3]r'eM +wyPvY_yxaRQ/Rh-D׫ Aۥy{gG (s9lT{.ހu"ɌKb(0̉ݗ)V!{?Kt_6v.ɤH? Qj:hu,BYʄG"nNhz'X/m kE^)=&Рʨ%-YVEr^htI Мhql^:i`Wuˠ0K)WޣwȒ{=d>ֹbqr#s;GL>x#ūsRtNBQy(v%i\epDm<|5C-6*-⵿7=K/\mnzzjtw^0۴nw4ao`%W+:Jھ^ ЃEhYVf,s'NE&|sLmi*8Ts{P :۳R8rvY*)~_M&}<7`h>$_ᜈ+[2>-'jZAsj34fU87yT9dNk10KWhK̨\ԚƠJ0hEr1&"Y#//ywV`q.eNs"[xPezZ*Kbx pFE3us+/`/:3W6 <^8A,T K=3A4̞L{ Yp[}c3Y̑?sKqXᚋQp'FƉH,B.t>X+i^tmQ58yJoh$bOƞEZo(TZ}N;\q ?_l,-!\6c_Z=[»7 9zC@BJ@3GJ{xLiުEJcPWctZsc3 e,$g ^-0DMa 놕2>&RfLfxmu&9Uonc 0 l,ʕ$% 9E 'r a^*ͧshE5,;cQ\YwZJ?TT|6SK nqKVDIFn3o_Fysu|IyעWϙ-/| .3oG$,1sIg+=TT%̉ hI(euT6}`"`mn-bp) ޔV|77D[|V%GC+~CH-rO,WF+tI{Ǯ@Y?MQ%D I;9hsj +al_CC 1)!ͳ/8WH"t11ٱw.ZJ,UvړjhU֕^.|6ڙ$,lfl:Xmsd<gOz7fv8>޲XX]1Q ZXpy<."yu9rhLcvCQ+'Fz{d ҆tg>UsC' hjup< ?PsL8Hu{4pe|ײJb@:3X^E[ ʵ/B*gsp~q_&hz)h]@ }r` щ.A`o\$HV{spbܚ=8J4Ȋ9 :eT4r4cFSZ0`wTRaяH"I:Ϗ>Z<Ҋcw /Qq2\&3;λP(,Ы`'Ol)mnc,UP; 2 ~˨GnA@iL(<[.1C|:vM[ےp>~ 8ZKϚCcL=.XFL|%ˌZA@jn=-'XojnŚ/8`^?ƱLV-Og Ax&yB5>dR2tG*Ըk XA Wz鞸[تgxӂUBna5U10 8iְ֜C2>i&B).JN;EH.為YɾC%DH; ?N670,CޢsNp1jg1BCzNiCvj#l XzeM e&Og9Ѩg\0Xh~^^iz%>}.(5 P]cX zHrr+JZ` !/طYwǍ'sl[҄A$7A`6pX1d;$c lJ'P"KIoW5$1#!+h41eF38S-_Ҁg9a a24;JYrqJ٩9Ne<RW8Qpv /b83nhLQK8 TTuXU\6/FzRE׸ɫЂ #sU1/+^2!GIS`,&QGALK+ ^E.O嬋-&H{V.v4!00gm[Q qm'UCH*}x@XD`)=35, ːo~߻bv85R^W-ҥMN+_+G}Ks-trѲI<a !UD.|"e] Yu/Aƽq+;r{l[`QZ]5@TJY@9\"KKS̹?pҷ96)zHCwf#-LzWI6=skx Qr%Blt~n<4"E)p|6y.3.I*-C=\MWGGAqf\yR5/.[UNohDZ?nMJcw=;n.;Pa=1An ?XfФEyΰ#noNn7 ·WIOJ7!~pAYe ,i?Ng4z'I$&C]s b2l'{NixqVӆLh 2EW^OX1xh~9H%kVm̬ytOqe)A#TO 1u*ha 0%6b5Rvf^,Ts _+zg3 Ѹq`!0-IuF$zZ%%L'HX=/M5 %!XhC!꟬雭>}[6 V@1{tX]W$a0[<>u2m4Fv!`uQ6 R#Q0?q;*$H+Y M&]Fj8螢3jƲpՀ+Cȑo݁U]:d#vpIV\]G_pW5ӛ;N*i@l?*Zךl>VuB9^eeU8g4NzF8/fvP'fڈ'sppQ2Ǚ٠|dV;I'LS,s'0ƽxM۪me!zYGn #F˵:iKAU!TqJ?24v2HtziBijzCf N/R F-_`FO- UGxs(#VjQ6 F{zt%lFYIs&͜_4O=x(S&CīfԁZvj/)_-&},9eycPQ WuoX#U,粪kŌ&ttODs kCNlr>Kg*| vh_G+1åh,9H&Ҙ7"aC#elt[Fqm$w*)#Z=L{mBl#3Q'$چSk@N`J҈`lKĩ=u J4fzFG*QpcK[9Y4+}˔\gl[#G|D&!u\Fhss[ }ԀE?ncCpнDx,L]z吁>+Ix'\zKMJeHEzt|le,bjh:w}]/zE VS54Cbf Qxo{@J#y k| )&}wo^G-+Ą@pNDMkA,>pxWG.NwL@Yt0İ 2KMp_]fi H^To*g֣TZLa 4TQgB-1ΐoy;FƻEgWG0a<) %drL:(-r>`HͦC%hDV40n:ӿ##`nGS6^6*xOMNcxBGIXv/[A@z!$$Ũ Q{ٷd rZ\7Y~rwdN5.-D.#jtF'!  ܰs n;O.Yg4 I]D 7}鱢eKب:׉q0+fk&*\2 j)-7jO5{ef{E}.۪dسݏFJEϬ{'9ӭx A&MRoYww[i~:ݕAPB/c{vict,-Xp!Y-$/XU_#B}lH9PW۝H54Ȃ+!ʩ,[s' wR>)V }vORq$ A d1VDbiй6}M^RBDZБlxk`Rfz d:Ml*G('C|zA~k^m/"SsQ/LP4>}҉adނ_K,,]4)ރxƺ4ܪW;EAZ[aҁlTjY"@/Ï"W)d\8!9)zG^|0.h#iR>Yi^ؿVN%#՘;PhTl!Tܙ/FZO ~ΰ2/h.gVׂ๟mIW5=#\x lČ}5m(9NKA;0/tJV+|ψٸdK2, fTn!&yX9I4PNHq}^JsFؕh(w$TMcSfhz@g!S';1vJGe!25!PVgAJ'1ߙL)|'<e}ܬ0vLpKz9m&z{Q enf-耬 -@NJ I 8p2 S@lg ι֥#6yI27OIT"3+h9!拕KnbC& 6 #z0zJc 9;aG{ )j{2B.*i Clu|ԙ_b l)/ݡHԦ08yEA{Ι`65 S_f9rKPzHj?WG`V V˼iT"{oI 5EjY5gp<*m>"b1?vl#ý#ys7gok'*xYiQrVYHRs-jbk)1b,s|r)+F>I/N)&‰.wlz1*nMjͨ܊O6|*u 7IԀ8G wc\&yl"+həWalY>@aa%J 8ԛp7ϏQ\9nBbK+t)ŤգVhGjU VV]8P U߉mZUEdxӭ&"RRg3HͲ}>]Rh"ɛm<^HkJEǞ*\"!7Ye(Miq:jLovyAt@еj,@̫E0 \R=58;3󲆼L5[4ґB댴@8tfF#F2A$V#oH`zӻǒG!蕀̜['ꃎyM쌊X@29Ԝ~ZtEYL|JYe 1Z]))e' s19'9ٚ6)׾~QQuxh b`=|2].<-uޮ(1BL;O|~nE#avhUgO4hR+BOWcjdĊ+ڞI6bG<T'o`yte2;,FC{8#jȟG`" LKu$C@o QreWoձ; J.gO|ޯUPG2qo׸xC7fI1RwX SE\Ź UHN6^Ji}%Al |Pu0W*A?SOF^0OsZ^_ #ߨ=tyOoJEOݫ #m<y,ePCv`-lB/pKc7'PNu<)j` /IRG':QO_D$ϼ6JrI9uՊK)_j|dV}Rt0[";9gI&񨡒 W029X״tO21{3ҀO|Y&z=c6`%|I⢖e=&zQꤷB m$ua3 X<i\bWah~ 7CyΔی*nΎPkQFX_Y#Q;[ SY1lU_O\yfW*$l>L*ZSY?:F<ڟ>2W\6UJX- ?Ne0T"V.tu~*uJ+%)@wM._Y"ʔBu^O4](y-<.JIͷ!ȭ"pQCĄ-H> کD'z>] o xֳj8 _h,\cQ nYCŔhrݺ ryUeQ'&)E2I@ A2Dk̨RS . ?ԝƲ>\Sn(2աRE\3yLT`a>U\e,%uDHh_?҈8vRR$T_,TA~ }KmU3:P4AL &Dq2ϔr[ے:yVwSqZ*-PnmǗׄـrZS8)N :Y6qA-Oβў]lUC[[+m\wZfa X.Z[GԱ4Y(NPBV?s$icdM]wVD/̯c""9ϲ G7m-svxLL.עeT/-Ȣ0]0jAEF4n y-ݤ=݅,`z*u>{RYWn->S$JӢЊGVbTJ?nL;~H_:1b &+,:R :jY`@p*,rRńhMcWĔ¤M61h\ȳ^yG[ k8X6rzh\\h+e{_/|/@vwpA&mJpZ:*F !cR7줚!-,7 ꮚ.g܉)$ h# kGqAx+[G5P/ ?,WFs^ 3]]([J׋wɀ^ܬ$AHdp邇5,޸||Gr,ѣ:DMC#uhKC8RRkug%vm,/:I0do&a7lO %-Z8".z[q6$Zos (8Z ᤥ#jEhf9/Yef^$A ^>)&@cOPtrxG!߈;84z֙}[``$~Z*2xjc|r|p(U̔~4ARF3CEwʪ[*фjh1T[ FjnYZ}-4 C5:"ӪS&iOpe`tDZ8|29;QY1ԒHĊlQAD|ɦ{ӡ;o@EgmNűyFHxHć!816zfPF*#ٮ"Jt'/PrJc<$7x ),e:.H[A& 0~?G+̶9HzX톶z%^yG-6DJoٻͭ.|J`YY=^LSk;ӷ"D跗s:A>0cIcUu<[z5DS'خzk6`u kϳ/VǁuӧMaQˊPu:f1ӧ5s%VKLaNEl"I: pT .&5E}f!c9AUc[.3Rf2ye\/ vkngf㊼ 9ǵ<-˛VG* [BCVpsw>3(i:|"X\Ӗ&570{J Y\ɤ*ş۲6 ՐM!Ta*3X:f?Q,xP?!#=+tyS&O<88fg=_qF@֒boUk73K.9Hq-{~Uw Mv0` o_w$w6[q.=¤v Ԍ!ɫu yY'yxV?,F\^""rYVI*e@OPsPv:ׂQxb/=X8(J]C\WjB> $ TșZ}j`a =s~[(d.voOH0٧e+H[U Lܸw#N_Q1WIb1)2#4kMϖ/PF9û+%+Sk Js*ݵ(8jKܮFʀzY^2%kd(R-*HO}NT]eexq'|Տv̒cA&s-Q\Vykh-n>vS$`$˛Y8&i%w7Wi|cD͈?.} zx?V0z} B#p =Fn:\b^ޚhu['p$$& {&Gk%?̷~unvͨYO`(G7Y(fa`5EImVYK|i$pk'_OZq>֬Ҧ#muY 9zh ։G>ТnN.RwxA6aw;o~Ȝr\,]-!FV7lxgΌl9 i BɒpٳVlوcTPyóז܏:M3ܤD "u?UJ uL9k~)wJ}uZdL!y L,7e19eY$Kk[-VJ\="DE zy +(XvΑMɽ#qq}茝4`&6ƙx < w v)0t)6pB?~b3!{,X1BX39ޫ:oxA,P]Wԇ!/_Bm1_b`2_ae18x`t(/՗&^T y*ɮe1eoa vUD3Ԑ}/(0LZtc욓[M#f3|1([uDK@^5 ͩ@|7<5I7&$K_et*3ZZ?{*DBaqZ@Yyn#OR"&&d\«,ז _-#1PJy_ ;2[T±&&Y&=޶ie ٦8_DVg`2;&%@-D6= Hi*V?٦1tt\,FrgQ [|_i|I-ӅDTuzm@0Qo$CiP"}[VNeTȫ} Ԏ~mig6RϮkxI} bRg%Z[[xQ^Ż8~ ^`8}2R^GQ"F"GDAIW眆cWi ߭ƙt0P+wZ~=uGP;O}<}(ĠgMէufSg̬ JP:fc_I߸aٔ(2J؋0Rք3ť/@ocST 8rs( toո"P1O(W;+hViiC]t*,v5hbgJXzI"_bkmlbr֤2cz] n(Wg!Lߩp%ue/",ZhkB2o޹joC eWUcz._KhGo,,xD&wX~x#W#sr _I::QQCGƽ1!f /ߍ#JggZ-6CM\IA]yUj6d|^WsԷQpvl ۩ cfﴅ$x4[)w6CeyN:)^bK(<=^ϯO` e?<z÷5L˳ a;Y,w[uu(;S$T'cSgCzؚN,L Ag9АqTb01(h3%!‰cxԢ0iTM <$+c d@֎O.{;76CS|"|iȝ4ڥXeJ(QDzk)ؕ$Fsom?yO&W@'ϦG6Uq*IF @w1Fp;!G.^YBP((]tc C.w~:{y 6B .4|>'DDz[o#BNbˎَ3i*xwFC&tX~͢7^27+A1 T<bwz--d*ym.PA8m?FwCgu/.MV0z!PB3Wj3 .}_|wzz3LCk|cj&ќ9- Zܿ s<ߩw@T8o9]Y݄c?F~< Ne$Zzd" JZl?48OI&؞LOgگ:y֌g$x :+R=1 `u>cLNw_ 8Ƭh^zuF(hCSچ#@\:9Ps9y]?u prΆ`iKuDžpx2 ~X D(m6K[kF&:Ĕngdsv>b pvԀƈx|٢;Q"mC.Fj[J$=}-r#śI">0\rܾ+YY!OKacL<0oH#(嚎@c,ARxyݝ0]{_3b&NC5]!!bф+)Y@: L㍑}(5+z|F yDC(TRV5Pޓpk3v<"W׶V+x`,l*$ʄ^@S(+vxE[ 8vlA Yk1(?_ŽK8fU?L˜ l4gOʳOIH< $sUN4&ss^`Lぽw[2Qͳ }o/l57[u)Հֲ2ӣpS?JS"<˱'fCȶ6\b@tn,YHhKy"όX!A{!`ksf*=pjƢ?nFҴLj|HpU#U/_U4ߒa=9ԹjJkD .~7%os ߅(xD$N3։m<`";bXf&iАm !f&RS,Cs̾$Z'G1O,/25K-(޶fR+j}^ա@f_:%q&Y1q<3^#4re7Lp_|g>G[\lI25俽*Ύt@-[ͪO(N4336gS G$^7y(̈#G@s8z  :va&:$EJnXO9)qc?Ty4@hDaSJ:{\{BjH~sg';E#(`*,~E C=xD_?OT c-Mοldn##jI|^{a~8 +:sQ2! Bպd _BoknmdlFGf=CD-F pr!YNLZx܃GO܀(@XQ-ޠZrz,=dGʹPͥq-W0Ade׼6]@A6&Y}%5|>Jrȍըm!Wd33U?LLƲ6[|"7\YhTQpCe>pei J5d2h0883/I}TeJC=Qz|"a $7\xKQޔܱ Ttb179YqFO^[/?ĚfIثxx*vԓj d~ _̤&$7|R$YB6{g,(Mm[Vo4؆8~S$((_RAޟWpw M+~œJB"ڝ۷\[L i5 ƽO󼚶p?Wuَ@;t9[~D7Y'S@%<۸ PVeX3VGrW{V5c96u"Τ6^~՜8v"?_.g惇%xyʙo 3Of^bpqa_kܓ$r)l<m{&Dj`CSd[F CS/i;,IXh >J кr32m.C$%E$p2Gbe8ݼ@Q^ė|Tb◌V:#lL dFinN$F9&RtC"r@X<H? wNYG[i}҉~9&4DOֲN p7"!6豟ei/ ^Tx]})pgNʑW6WBK.b $ Z_ZF=AfF>݃V;8x]T:C1Y:kpgGd [mq.F ֎X2rZK?#LS>Of9y(لHt_¡ѹ1Jd J>marI b$LA~J,B9wjR0"Θ.1CU#3u0dɢm\q8gauvǝPg}#Jq-R‡X+6DMb+h,(#iL_?{^}R?Aͅs]mfDr0+6q{F汛Ȍ\L,bkdAԔM Ig;!]ߒfT&=8D1_MkS;fd#\QqC߲AV BO߈՞tǐ19Z8k)Duh>='Ӗ_dEJBƻPZ#p@F(U 1k}S^ngY%^noS"G.$`yŮ؉zD`*.Qws)̩>O2r,@pč58s|`7'#ōR /0AUI%Z.K SRJEk#=docTSzT0A;hV*Nkr{ޜ&,6o#Ȣsg'8UЌ̂ZBˊ(dT fԚw^47Be*An%[M8R phvk5 [tjq:lܺ'2nķݓE=B=dVLldwnnl=nwHZl1TŇգ$y;.EBDPb=ET6s8MR +=;L.VZ7V ʸ8xGy[r0/fHdɹKS$qFչ%z$#:ȁ?1q;gX>+ņ'bRB͐F@f0{Ru|@1&ace{JB|g"J2S. 4JH7Mˑ/pq@#X'KsucaIIoNG*]hA ($%9?VyI+ Itt +pW־ȵ}Dm)6,-(PKgRY>0 yrTZgDUDaV݋@4CxAEe+&q#}ݙU,ׇ2[vl|7ր<{Zw 8sFOA(rs}8oaV ЇnN~8B9#5Ќl)bu^p,*mF.zusA՚k`< ؓr(U3AAݍmuǢeA?E\[#IԢn,D=eI>8Á&\+EMZulϔxA; |)͵AӺ&)o6 .q2a;EOqp@ *( *XD_XqH~rOu*"r38r%ty3įVG0'ۂYx `ld`ȏ(`uK 2|abiRWqN2bL?:#l&:?6닍 V7@Ud#6=R5_;foa`&mI;v/ߊyj`$3TU9Nn@@(ڝMLγ%nG*W0l<A#G*3 g7 o~&MYPH`Ks َ$:8(ך$w4ALu;Z7A$vBwͨm/Hf:Lߡon<MBҸ*~dKdx5Bwqc| \,Cu}O"50FWYp2il3[շڄG)dM \;NJrg=Fצ6n% Fkv$OGAEzY $_|\g#a4c9 3ʾшz5LxjګK^p%kZfphh_™f&Ok,lq6ډy`4 :=k)w+8 5f)z{2 ܡ|3isaTO hVSRI5Nsx GiD 6~RJ3UH@)S@׷H:_:#Qˮe Ds7Ɔ])UlarWosD"hvPW3r=0\+N?e >G b)Nwä7XIfkg$?FE0WMXښ@H[1wzyx[3$$ʺ DD p=Z xןyW4'[Mflc ~UEAe:b*8 .5?n*Wwq(,k`; ( n$]/FDw(1> q_ +&%,˭m8 \DŽ0:f%Y:Wں꛿Wh{@xuLL:_ߠz̳DOaƝ*H^aŃ,'˖Gķ*^‡QBM To `M)&ܥ:t5ő Ŧı>)k`zQT'Ĉ>iJ&f ơ^E^wbܛ&CP21hg,ܤsAG bҵ9UGo=);Oi~L[᭾Ώf13Ql4:CSh`૽N~]_l8dG,)Se9sRܺ_Vt+JYZQi0 %g\H/z-䙗A g=}Z^qs 5žr i8%!FvU3 V9i]tXI~)0],@ 7O|FF\ Yٴ4akuQ>\:J÷s4pjlwGn] m)f0nm)_{"v\OŶvjuRKY;ӵWV (7s>?} X ɾzTһ fXlVeV~"C;Dlf8 !gGǺ-;6!iŶzv`-iHmAU,ƔFO}]LDe6#PqY`,Mo ` 脑BǾDmmFi:y< {8b+{/Pf+]ϢsP|-Ы&ae{[Bj rC +m F=M?Aw{@u" D2+>]/W> IӴugXWU mpu?K a[U,즔P']VWDL8^RcfJ,&{GD!T5%c2nW~|S_|m1)xr.).hg4I2G{xkeAޭ,+[#{ww{ahR$P-u6Xr_ LQ|g0K=AG v`]hT Tgbe6-sTeZϖؤ0R3p0+Yh|r%-F%Ë| P7psbPjϏVkxѵͣ)-(c >27]R(7m{Jܝf?9[ji*QVHszq VU>w\\sy?غ,C*ϔ:=~.+fMn3۱ o{a 1}qN{B8ȡO%"ӟ\1eW,Lq- %.vFw [P4~Sc=2rv\]L[ϬΨBC%9miI7'O]vgЍAR@zQ)Ӥ! sg^ G Mh]-j-f_k:yT,"RjՎ"\CTߘqR,Cfӳ'BŽ?rD7ЩxOҼy=[-aǍ?3} #5ԋ^ӻAK Mr!>ǧ٘Y0(`/5?}S{cX^vB =!|3h1 -a$&i=pWgc5iN3D  &Wi)]"6+#aVH9eOM6iʆEx[Uąf^e1/[@dR mx1yP{-S 4uoMȧS+[Ť `McHűPs  Ӳ%w,04ŵD2qs&LJ ul*DLDO䐼J&ʱ | W1).FJ#Ik?>PRoSW>j|NUyx&NJ@PJ,(̈́ {r>:;;[1^gjmyWH0ЖlwRDh*ېeاZؤE+ 3'1s72$ot2 k_u{ڿ=b"#/DU}8՜ _&V&n'7_z4 IK$> 9Y,las}[8d}%ÝR+:֤#sY<' z.nD~!V>BGeA~h@{66wɶv?{.dMe1wMSRx-X؎뵯~}08 ' AT,+9mV-Tae57PIC=,dv>Gvu'u2# Mth$3b"h&luI LJP(50`ˊyGA# L8id2u Oa`bkrvq!c('E0`Un6EDN6SC9 rT9dήJTGtA ce&E`{)>pEV4](¸ibKGwhXG?D7`{) H7>[;w(wEFM=uPA 'C#A[7DL)Tۏ/;2W) :[B~ q$:'A%9v6,WK꯬#ü#sW h>r ">~4+z 8(5>cpu`ߊo˴bAMzݑ ߍ|dD44܌Fh gm|xgQ} wiV9[ɩa"x5~'N> [&b.x5|Lgƕ,NoA5i38lZTi,`A-G';%D`?fws7jh =4.3܇F5qHXl30#ME¶DNꫴU8-w5H# `ofsmO 6`lCb'plLl?Kd'vt2>^D&.d聝o0, X o";E@X|4\=a/=̕fAӺ^ q4 TB(Hc1%Lg!6Yl8\ǠySR㨙|s&\zёd |yyB}nE8xz?fZjOJ#pPPtXr?Q*r>:wa|Ԯ[j(P|@N^(Ӫ 4$u:n=qN XJ묟zH0q9 m--NGPd\_7R`?÷~G:gNdbbاR`afud`Yqc L/^?6)R-ZsK@'0ui)5CCSp>AM% "ۢjj("J_ zzn/gaK0kpgTqKJU&IIG\a|?-,a@:?ia`STh*d>;\D 䥞HNm$rK\`|aojشv x/MZ?NRAUu\ע. wUR-:{W{lL><8@ѳ8 }HkZ^\yyL'̅`"{*݅ Z*,L_ǡvS?2m //{~'QaL7wCa~wqu5=1e[V)|bcG*`%ǖ ȷDr9jwcύA&cAiPeS%,|a1Q1{tK;`l;V"ޛRڬFX'@(jC7k/Kq fx@e "WZo!ᑰEa H3[|0Ugdvl̷UQeEX6EGйL7[A'EFgdDNhLjlBP2$d1T=]vm_0qZ:+giJZn.ܐ]= O{qyTQ ے)/OB)M 'Ϳ&/T|R/D9cO}[y)ձtC>+`r#1v'HQ@FLM*NYJc8]“?~HjC$3}QqAoc%/}$` 0-͋GqlA++%-+^&9jz7?doEf'ENìsNZұte-6jƌl"kP/ ##|/s%|_>)!Ra\GN1IdGT>DV9zň.`ÅpaYqKm܈MG`.N<7u $ Lv NW!>t]6f^2*Ց׸s*[9Ps*CR ;p4)tc / Liw]M~rsdA4<9L~hCǀxPD /={p!W|W s˷]p{ aҷ;Yw%hQ{E d`&kCi0 dlEj! %X% /t9a? Kg;=Nb<-9m`~{-K9po\HK1 @#vS OnQMRM ?9Xx`ϡWK3bF)Pux0٣~[w{q/}6b͑z5 X ˆBA¸=ƅCjW^6̅ ~ݟ )%/I8K666PWB}'av?h _G|C<wbPiafiGX4IBVs& x 7 ^6<Û 3ض8xF7ÌV~+g)wN)҉Jg 8Y)C4;Nh$aga|ύ)-*?`I2DSƴp`)Ewخ@Mj.&=ŴaDB[pVF`ͮ t땫/e8Gn]0S1XA=}Wܬ@8FDCP= =/bSF>󱦮*pldhŕr?01gf6B؏7x6:9ͽ#O˅`N}L9RLDɟ1AL`̟~#c1YEov?W;l ?oGa-_i",lJ^VӦ-{ּ-G;yD '12I,] 6ڟE}u.&3 -(jI x Q^ '_}ǹQ\C}PC' ҚB^vQv-c #<!鶴B214_DO@CFa+>`&.nlDSiG oЄ X$ FRK$XT=}nG*rwŭ52o<$5Ʋտ c}KQj04R:V/ת*m"1!B]2sNy`e(oI!"{3VV-5GJh|&Pr"EKA<#>"ѷS`Օ>~PMkg.vaTBWo{D_jIe졯 =n㖭 WUnJ,: yjF}Inz332pΐ5`!$BFb#saUQLYM;m;^U31N߹7sPsG;/iT1EBl*4ET\bLst1tPcb?a;ێ}J]83[̝H*٬ Sx\ {tR`='Q}NS"N>CH#VxS$BF(Z_pA HT5*E;u 2 nGpDU7+RÌGBX*yYK6v!n5!д ;pHE*U~-)Yj%y`0EIf@oߤiƾqvY6\#et_$>4"8DL19- UY1+icA/؊ޒ+6&'⿚Am-/1\a#!c¥a@oHIrNbBS{eC֥XþڕqNd =q{H l8{,B:6nͫ,V%9~0U؃^CMQBCkvb2~ MsV[MRhLt2F/:m pL쟁s \ F}]?|>?`? Gn?|-sWVg ԋWd Ćp}TfRbbB%J|:7 ѼN5w܉螇2aiWpGظ$'YķG%̄1-+P9Tb AQF1B=|sL8jMd@Pw߅ZL?BylSCB&o?,~[ ̰j)or#x 2_ i"t[  Nn|^;BO0әgweS!~Sfe{x[Lh8B26hz9"9jFqż>i3G݄' +6L0f sR[``8UگݟE#b'&Q-pi7Φy.vP'\ a&:X i2Vty:iAo!ۛjW=-qi Q-| jPwO5\i6۟u9 ב!uD'xpq:,-Û3 ɠV *0V|+Qa T-G X~#9R^x ޑ0$Z8@zd*viʝ?%>8Js ?3D7lsė[X&᝛LA ީYPPcQHCkww#!h3V;DMّ _#^cs_^D=Y^>')R ̜S|ś%֭ĊkNX&[α& a|9| |)!WD- mˈqsrII784υ tLސpf7-?`$aj ;)E|ㆱ:?~eι $C DK\4ޝiA %$#hٿX뾱6h25 0{dR9Ơ$:Nl<- ?hޚ/&kQ=V> PTr1[Z>W?u=d#SyFH] l9bn Ԣd (6w`n˕0rLHdm gaۭMMVo k*ԛ{9L93z>ʬ#ds,, RLJJʚN)qIlVuMᮈ sc04yw(oѨ;ͺtж栝!kiJ\Qn}ٔTQkΧ|rVN#BLDʲǼD2bOMW0"|r6tJLճ.*'+a$M~vw`@F6/_+To\IqLc|'+IeL!J9dT%]=6Ũ[4&8eRޫ!S~vv-LܦHb:JdM 7s%vfT/C)|/ "[\{gas?OnUG}IKT;%n=,4b¾UgV, w|rJ X`]twhHp2*W ǨLENwܳ,♻ [Oo`7MyT"̺n]Lyk6l$#}sPCk"=YG?Y`$C[l_}w)l"QԔ7 t ԘKbPiU)w%0^iWzP5πۢZMJ!fP[|T&hx(c6lpE#kym Ͻ3yQYDڙ棠2xZD)=k0YCzh N@AnkC P11v}J%@IL$y-;r{IQ&oYn[ p@ HXy$/S(DILґJ0EN5#z$V7j/V6@ 5+Y0[^G+i=XhlkHr/N-LqVgB 2 lY߂jv$c:(BAٍV򁏛ad1.(VUI!(6h@QW-ihCwJIJdHy46YU&1Cg5jd %&Ζh7;[4OYK- ή-:%ZF9&,bD}e/4~$ f̍PRsOpv!Ј8Хw,?U5bzBW4#"=ym09!E9b۵ooXt(|$rk..1^FCކw؏ /4ndkbwZF:p M|Vv@+{2Gҏ1Rd Uv:01BrTq$u-.qr(D`w-< =nÏfT_133 /C\W!DV`2tϜ(I]Dkj9?p<9_@VD g$0 6);g+w6 RveO Z\WE?*3ҝ֊ehĔ7b!Gj׾'<52E6 x6}L$@Sk#U"y ʐ%cץUYбʻ(lN2`4M̕.G*T|*>nAQr;޽Z`\|I'*~ 6lg6u=|LBS=dq|p yjϸb}ڸ1^y͑/5t.+1MvzȶQO Jb+Ӄ%!E=|n4+S;̰aIW//`j$UBLGrܦ%L!fg`Iߥ/Pӣ[hpOT<<-,S{(( ׯҔb},nn/4.oQ'%Y"CN glD~M#;Ɯ2֘ jk5b$Խu&})h"}pH퓿 !4"k|sT6]L&M;I#z yb` }Fc^>xR0[\o 4t# L*'oܙ*`ٛM^1*(a掃jtMm"lQ4"f7`'啕?>sGw{Qy,G]"($> CyL'/2@V mfaxyyy.Z( +v!/}=:.8U%,SPp ?/i%$఑Niw)aWHH׼ iefz4!eAĢ6 ҬuѢz?;VZ[}5pU*ihJfMyBp7f( .Ca4z7x tu?r$)ԞNKv.*l(DȘ [9B 4 ]`USb 9V@CӡZ_k+meU\t+M`R*M׿F9OBۇ"t~ +֐~(,x8*u\l:p"v iR"nv ^<9eptht8ܯ])i`'*"ځ l>, s("*wyoƸK~ѼcF84#/f ΄PE>;УhwIP:~=ݒϪ>PQQGܺ(p,Z\EzFH2ғ>Ft|RQ'VZ&2т~h\s߫dRr[,f??ǫm%&1l3wo9Nvh蝗u-1=642){g;6[Z&-3Xp^oʱ S#/sXl"Kg9|Te-m$BccBm~[Z,c HeJf9JWV}*cR'7_͘tnxԩ])wX=^;R[B fK#4Uj'L4CM?-u,w#b2K%]p_ ')'iNi^R g 馉1Ґ֡z{Ӭmz{]dQw~I>n]F4櫷gg] 1b+V<%|ULFu dqX$xI|J1A/vu:ڮ$J,k9 ]k vh|^[cI3BHvIe\m6L@AGo~?=5A|`dDw, it˳>]IX3+"1+TcQ)\i-0?˱" ۍdCoT<8++#t FU񗙫ϓYT)]WOlf'ěs#ߚ ?1}8f|WA*RclAqK0};=N6cR/a\Džtony*yGoZJ+K]DCt."UUp8?Sǣv m rPbPRzzڑW*bJ=G6oFCH ZfMwЫq#/v*VԳW!g@HxxY~gX}{2-ˎDRHݖz(j=ҝkVtskfVap<};|-cn'q,ȍ'˲^k`h;lUx^Ѧ!p}kfh98yE_*hwaȖf C{XF׵a.}ݳUz/ƊR S]CxlJI7gU4JG4+Dn6uKXw\2ZH:|i #{Q1.w9 i= mvTB"UH[[:+vV#n1̟=9:3?NVQ!͕ܼp0  ?cEp $8y Sz5٠@~CF}a90D5nj0e.evG%mqt?B> y\B!w1ishkM'伻n=j, 9:Bؽ6 wATfPU/Q4.= Py aHײh)5mJrNLw.?62"NM*Ydr_ 'b 5 Gy0cWj(Cm/~ii:MS#IzbzPlU0WkA#5x{[{i8!{8thPY$y[f:3~GSl=U,3H=1{T ִ_r&H';g|_ߑ?U= *YwGFQs3*!gŽ߻yNjҎKLͲN\X?İCth;UXVf,\yA+B_(N%E'Q#{iUg/F[I$ _)'RS%iZd2‚onjqoA~-/Y-mAWۀXu=ȯW٪!_$KԺ=Lٲguh/4Ҭ&,=8|*9R. 18I4zcF[pTݎ*L 9vSY ,4q_f[FA/6Xge=hX'i uzQ>NTb Y)lnăPHw_@&Ƚ Nu;m =ߵU]!*w(>tkB_ 6{X/MLJvNRI-Mљt{z%?᱅Jq,܍{? n._j ?@18۠Ln~ y3=ҮV-x/ EdtΖ3t2 t.p]U1E~-bжHz070-Lk=][?EJ܌$)x6efĒC=|RSYqR=}8JaT߀okk4ü DFY3|7cٝ֔^o#q;ĈGԚ']jgOo`Ott4ξo@]J)H}.׋ZJO5"|PVg{qcS}hΝFiԁm)|ke_/%WK(Ѵ%uxeUn Pt9onD$Ƞ5[ ϳ(|.8 T*?1/n(R&<G2#E/RQ 'ۚtDAxbq·B,4S%oN= (xYQӑ˅ɖ=q(ٯSa`DXM m^:c~~T[!)-ԩSJW!{4z(͝!|rp?/IY3> ܸo=qQB0eܤߡ3՜{K-VWAa jF;8x{}.)xvHbymLlJDZ.2+q"]`Tv%h&i֌Aݴs7:XAfs (l]aB}E갦>@g ũ). W=Z;8mф[[eDu% v!y84'?iP*@ ՁLq!^bV'D@ReucfxQb )]q^#NJsv@ЖSsT[.VByQnOnzr{;]jx`,^dED(!(pXiZUh7tjP9AK]\FCD~ QFQU9+EF,`*uLG[%81ZnN88t"eP2wKTޑbє&4D[kEt&[+liK`hs]SΩh$_,J-ܼ JTs߿v[`Ťѽ}g-QŞ@]^Y]v샰ۛ#ds4y%nIr&^?yӹj{RlcSaڌ};*YUq) "D@Q&$'/,҉ z {saWQO#Nt&hRt6ԛW䂬\Z /ypb!%R'7mk .;%&;HE_E-=(n]AkHV_ߓb4+P{Zs Y#X< FhԷf0%RM<00N]`E0 fS x <YOi6q}Qe4g%Wg&Vd{|\ʶ۟_Y0z Hpџ{'P[0 } 5 Ђ>1i{,A r-0|B઼ 0B3R  M E{췟Vԏ-&|HuJ?wigC+ߩ:w٥fy\%鞏&hwC'1 :YxSU~1¿co"&F\Ҁ>;taIQ ^|ۢlPPFe*fCkMڒ,8W ǧ–m\aHAm۴˿^ O+tvKx 1FO3Dyvpf={YlJ7Ȁ.|5ÏF]LrJ!)hcG!feEdzb&I8"#]yHVN|~-X1qSæ+)C=EY̰el]u*r0ebU YXh'(|znR N Ky.yKUe-^+ηaSBYdc!mT@s(ڛKHQ#SD -yP^W1 0n]`˱:Y>e"3{:T&N. 7}4E˘! GOW~[~ۂPjW L9dJ?@aR]/#3XC<[…q2EqDxd$B**X#;B5 ᪮e3db+sB`5.@dՙiOyݨ_8(jza70r9ǨQlTD1L @ȵip1A|ւuHW.$JbZes*#Z(4XV)P-?8I^> Ar;;wVtec[A}lN"cvʕIc,głc|g_yM!,ױM < 2xS#(IRuj-EGHB V!a8U}Ë{iESVz6'}^gxf;,R;vJmufY`ӆ;π} FɍQ:&I{'3͚WTÞw2o I;N6ܽt|bGDz28ı- Oid /?XE4w,2;ՇU48E3g(kʞMV-l+:ԏ Ԝ@7^_QpkK" G3+Sh Gࠨx;`ƲnY3֜)TmJ5>DR|&tvrɁލ4L[s[X]mP) U}ӞJJ#jut\RFM3v#zCxDc_m%Xpv?4˕S -YO@PMd=LD#xLyrxjv,=|i5D%扞vmNn<*HQԜRSP]s+X*֤ ޭȩjҷز {R%U ;{ ň87ׁv4$V܅Asw&L8,u^?;}]V"ssY;Iʹu"kGfO;k ,d}Cߙ\A&_nKr"dT@-eCGM d' F(r6\QY_xڤ 'K~#OE{蝺V䄾`kƪ sY?(x ʐh;FgzYV2# pL:|&bV u=)$jX(E E0lz=+SCyk;>,"jA.QP`*؟E$^o}^swAk@:MPrUb92G 呩1o $,(Ctg/B9:"7X1hKV)VMĉ-I4.YN6Ƙrmk8{gՈͮİ>GA{["IΊ;G-QKDA[<qJI$iMh>d"TJÂc=* P9|An#>z3 DA,u8d}Rs>bN\:4 g[Yi)(= UmtiDxMzπ蝂kpO8ڂg@!R?oE˵ayj"ûESEjp|6wJ70]εOr-9^ã;7׼v]_%x  #GunH!QsKcomӤ{wLQTih*)rߏ,^{{5P:Q7]7 nh !'yeVɧՎѿq\CcYoSP('_4]N$*/k }#O[r edB,[P>jV;EYp]8[ &PW?_V?ey{3sL(DYYy(y`cGg~7Q߆ L v鏡\vBO=|1Q IXA;xAg'J6b,MXM%ACk5:)_߽cJ_ Sirydx44QC}__ !ZւuJ^*ꈡ|T]CR, YwZ*hdplF0ȹ{5QY{LC'{m"@Fzk5=>ĒYL1wM{HyYڻ8E'ctM0NQ+Ny>9 Ry+@rqF8>A)ތOs^;x&OFWf3uXsP< # &O52S\Npmw::U*djc8+/x5:{zً6ƳpkZP $]<+.l Y\cX@dVS-߷iz6 e4\ zh$l*&Igxc;>%XS> S~jQk4jm4gU2=`k`LdOY/54~mہX%BL}!_1f7XhQGy0u&?Klv즿 ] bYKM/k*^o׶\e;?vBJA)U\`00Hb\9Y(K;ALtveA :]1d s|$**Pv9zjmq_69o#DU{Ԋ U;_1%S i={!5^t_/R>C[?3+1W!#‚y]ڭ'U ݮ ¹nըGw7fߕfZ哙FưX:e:Ta'џWI8XD>)~ͨgNZ\z $3?ǖA5>†e^'FQ`k][YS溡޻]`.엜~ڒYB,3{yG9ӫG tL?Ad %l-p WV# H%} SJ@-.ؖ#7X?+H4恕$mO ScaϟcD9QRfsثgLizPR>c=#5p٩1j^;S 2Xt8+ ?3McFyM0׿ٳ/^a"Whi0ۄܶb7~G>6(~l=UiLˍNOKNf4hEZN+dNX>PR`ۂDl5*V>!bc7 uܱתIxz;"'B"oCyF)ݢEǘaQxDXg/v$+&W|x^x3byƧ0M)>0Ȭ }5z{jN>0mZ>]BOY >t+ZfG0E&cfKm @M 﫪zgy{4l8f(t$-iY$mOkZA+-3UMīϓiX~+z(nrӷ8A$uZ@Z}/wzp4Ai[U l^ e^:jkYh_%Ev .Δɭ >FSb{NCũIs LݛnX no^TN',Lv qH?MQ-0`fd .A%6Bwrx }g ȅT6D>*چ-m_Sɝyˏx}ʳkZAHg1Ed2\S66܆ŋaBv+-A8y&FA=Jg̤^_ \|(5OlF{9R24ɋr4xO,|kKzO`B1!sr %:dk@J28hf_. N8$*_LƉۆaRژ0CR^%D،S߶lnJ.{A/l$lH/6{zyenpaNբa%G^ E&ſ~pr thpmVX ȵ1HZD~A}"'jhy+%6߫Seλ>fa\t;MNsMEIyBq`$}wpLe:j Yy 짳_wU ."ؑ?C N7F~|Z!Ԗrkb]DL4X$ g&,e0߁;0lHƬf]@tP|)nT\C11;e5>)X 'Kua/#r]>`\"| nUȾ3ʺ@i8Y%^:1,=P`Ev.1gEtʱLFFIC`uYqM&0xº>G l3S,69;8Ǽ'cjaۊيN-_.ArOjS(H*b!$A1P 4'r?C?_^-L W󢦉 O+և D8h'-ѮcI&&>(JVЗ4:biCWdziZ>=t+L@GcaD!mmC5] f2v+"|,:S?0*mܻMu Iۍޑ_epN+DŽ~$cyq!7}/) ]MB]6|T_He `P{rXq'ȵ9l]=gp.S>*j9_3={[]sCřP(fW&*SXOyT!i߿a*G es1a$ZDV%[ PBQ8 y5%,J`wYk6aJv4z3hq_ovǧCï[ L̈a n$B{ dݽfGk 殮Qhz:`,oaηJI5'4|=rcAc>Pt59cӗϙ(s9pQ#[,(҉ +]7n wQ;ʹFmGCmA], dy= ,cnq8fs(>O >^ZV9%ǫтu ^=&\Dj `&?\Sw{Ԑ"$*=ƒ7\77"XsEj$kh0oنqoOќYSmnZ%YG4EzY]]IUGZNİly҈QG<c`/_[?VmQxUUvS̛*m-k;.mAY\ NgD7 Ex-!Xv4 ai晠sŴGeL1$@T@_RĞ`N10IaͮrJ |&K/=ȣy߇!wv:/oZG4`&vs._ n $~0`hqƢKǂ:V} Qt7ve%V;h7h4=+ryMVZS E}i^uؑ;9 E5Is%͚D{i M7v;7xSvk8܋G<Lო-=g(!1a$xUk/ʙ| -jߞ tTѧ1XzZ ~*I~)┩G7m)*@CөBG-,B8'K0-pC]''%:o_D>=lK%c yHU>Fkl%PTZJKTF?cjHuci-LN\Bd)[6W7!y1KBJ դwbJ-4r`ELO80 fxeߵK"MUߩɚ&~[R/] ֠ج܎fZ <*cqr|Lۨ<7>$!$ŠB$kkហ ]9a^Zbf.ʽ&ژ¡xUy~D1 :5h `/=V,>]xҌVxwCVr@ .3_Cj͠gAD D[f>hN.lSe?cm|65R!7"KRtK?ZV`Ȇg&Z E1|3ZֹN8$!XqN7qeU٩c4eAL6ԡRL L]y"#zV[Ŧ"Pvm&>=Zh)G{ohϠ,> ST>o$YVk( _|"M.ӱQgɮPFg!E7k*[8~exu7!C2~Z9MsI INU5}u@2)Wr-\{x0OƶZС5hI#Ԅ&(i@sQ^M8 GQtjhRNh(>N.?~ȧB(U2Xf*+۟V9"V=ѕZC a )=21H^}R 0CoIyM{w*w_)clnrM:npwt)[,+sB5dPThZ}o$_?2 xdQ@;S Q$0PD*'bK`bV~8R^p fԞJOfimN}۴<]l3jᓱ^Pddh=w|JEkdUD~CԤe0 KbhFGr0kR0KAke}'xGޕű@ՙaGBBi%T6șb:X~TBG jߧ.1'ZלM[9Z*Pt \!q-d[4ȁbk7D +vpJj56 vIT/,ZaL &q!Ά[fTE:\fU|b2e|(YH62K:IO;l::&M[lMjY?VLGDCԌŇ@*Ēk$sW#d-z7q O' 0NL#{aYNv 9"JpJ}\af v9 *im7"7ݻu pHs sњ { ^_hag/+)K1'(m= pH(ִPIWFUQ4 JT_*Cw;p$ NKYyAG E>ԛI(qn f&8Ƨ7fΔ觃  yUR CLUDS/ 9 [5RD0 yվ}[ww:`K_9,c$P4i+}^ȁ0YQMX`(`>cåx!%jR]KbH[ 5R#L|Cq-3-3(*5: ÜlBt ^ өYN)- +Q{eHY.T3ղ2w1|`J[lX1eEUW@ v#y° <1d,m9ֹ%J&48Fq cQU6vD|S ߱dVqܝˤUv]4} ]ZA aCÂ}Myiōxf_9՚TOR F@o1+ }EO2e6d$x%4{ |ou)ݫsQbh!۸Zt,fbdBekh s-!ԶL=ksf NUůΊ[\׶ kQX|~a֤CsȒb-O'$kH~"i!,Vm ;@2^ ]~HcIs;+Gqm/ zEfQa50c"ѾKmTC߭?sqк | [М搎PO^qR"3x}^l"D>c V71L +Lnf ZY+IxW'Ǯ^̶4}DEzO3ƭftz2-i`€ғ@ԳF=*T dd:+!wfUݔ&}2L3mz"nj-c[ȀT9-'u:r:_i|x8q9eX@*|Gۓ?#2SB>i~ˏ)I.]:mp{gNb: r˃ ;6 ə:]siS_a_y!zHh$'̷`|Є;ڭN 1R-mʹ }&6_⎜>305 I Y9SͿQ(A} 8/_}Cgq*޻\%uc\?_9td@Ū EyȐ' ,~c-:'P83ju%uOYrC^שYS2g\hQ&OjYp0ЖhW 3_302Lo,[WA{z# N/[D38眩?oK-iD[iJz'.cLAsk+TNR~2v=Qo0)ڨCÞē@OΜ3i5'@* ^30 -6|`ݬX\fjU:tljiN ܯU)"4] C yӦDi+Xw҈H0R 7+ "39>ŀ ZnK=z4'D`rOٛc,M %t%A,kJ*`b;6}x<ބqAO6g'JU\BƵ[z3f?bE{DdYgChB!-RCILf"}5 afaԪTB0!Ӏ8䧂 jBӤ _GVsd֧ v7_nERf`ザ/{[$׿WBy Q0Y5n˃LyvYs/Lw!KǟґQsO m:>X$?\8Kx!eZtK)%[sޣ59z fEEsAف sܵ.$(i!U6~R9gZt |pf#5J6CA?NP @^oζD%ccj_ %{/#G+?)0^UUDYj1%.zز,EAhnĄU t~ koe,#L>%7v 䄈$N@(3ԍ[ܞS48励@CӍzÔP٥YPVuYWY_6J q Вvo%CsbBIUp@Y0%ZvsG!o YE;TOFOkCM?Mc,vNI;>aU89sdD^JYv+Q! s sqWWX``hP0`I%aB V`̮BQr{sE,'^<]_EnpWоC)םK#ũ3 "HHzDyU`$THW 5ᖧ3}l ꥞ fiC- >OB}YQ;zCzװ1q 4%Iɔ%ONɚ.>doZF}zGin3#c|<Vm3:ۦ@VNxF۠ynjL wiT,xq>W/_#ꜭ#R:Ièp ; n*Y hHͧ(avT "TooKoo }1'zdxhS<I6Z9׷B[0N/LәI0Iw@kS]^pnsJ\,C3S)eU2F' 0y*$u|Fۛgf4;N2D z~ЖzuyjsZa;V3:K6&]N"ut K>D؟Hݤ|-gT㦃Ô YhC##?zIf<łƂp SPߔUj؞[>%^EkC#;wvt9~%%*SxOV!C{dH`7J̋sqnvG3\~TE3)S`oJTγ=Z$ 4l ĄL^Έb5(ϑhp_2^ŕKϖ0!vxKӖ1"f:U[J^;ܾ \*ҞYiYwLc c"iJiVC[9BԖH%2(oNK<< yߢ!a*PYm\@ޱs|Ka>vFt?MT̔}c` vю7  ?2tpb(gXלJ7)*=y7z^-i9J爵1Y= Bģĉ(Ϩlu\q8Rp L k "כg h.jfЯkŀjMj1-! fmh0%[а}2C6W6$iCS p]b=5޺韧?;Es+JpC4K%l: g>=مAJ l # lvQڅ8rŔ ;|xhXi8ͥ]\]fZ*_ n.lC(.gj :x {=V/SS_ 0/rCUy_ŒT^G 1fໍ,VxNK 2JQI1!1\_m$k5d1`I(SߍB-@=qrJ[2,jGk#y}ڨ]ʓn{i}?kZ VXqxNm>@M܎uMOʬ/<i_DVҵke3; &}gHe.OkMy0}1qRF`Iv]ZU{;bqmx+gm?ZR]{"ϲ!;S>M.F^֧u؀6YGmkj]o; nw4? :bs&uͺ`~6w'n$mQԪ2|. b]vMW%ŬmZ˪%TjB9Ch%ak:4%ӗ1e C@L#;6"x3kr82|7#)T BDu{؎WeޓonIVbm|* kTdfݹC^pqa}Č\Hh\P[-6ܘCNʅɼffSȵi8/-$mu#%gS ,3!A wDX"%w`LM?g+W S=[z'n̔9b1&#,;|=>pFя[{T Ib58,TYWӆsƽJ/H>ct,736+;.^{)fbt+Q~_iqMY Ǐxx1sBaArPIu??r e@Xh!q_U'd$jI) \*ѦTH[G/3`_Ě Uy^A!T1\|;f$]xoqvbF|pr(Ŵ5#c]a5ͭ-/*@4+Zcy*ڗ Շ,R}/.$9T_loʨ>Ҥd ꄐ4fU8ܛ} V ~Na1Xڛb(g}qW^>:n]G:À67ˣyܭALڻNӑO68S^NF* {opAPzUsn!c80#IoqUA 6@\湲srcy-eWŧ2gv@)qy3fPEĴ{` dcU9swEboG42z[<#,G#@JU_u0(k<*kڮNMg-W!fQ.7Bm| mV"FY>J,$f CgEFx ˿l"חi-aL*!E M8ZGc@5 $bh'dT57hKLAEO0iw充"1 p$Kc2z,4t(C0TJobl{ k\?"uM㕖rQͰ9q~t}S y9ؗ$(/m ' O+u BK uآWa}~ ^bMYY1f{N-ދ@%_CKi |цc{ s'ujITdh@'"`!9Z Xk1?!foTkZ_ӻ|wdaߚJl0 .c$5Λ'u[*xG \;@k'J̐]AaVtJK߯/@甮Rʮ[."CI 8SpǫC74}n9KcEՠύU6ySjK&PP=OqIl_ X>ەp>P#bw7!'0Egp,{ϾW m&~1O۠!886}v Wܵ~pLV#y; /HpS#Ηph)yzJwk*`0k /-^㧎?2o_T }S x*Ylڣ|K 0.Α` 0y00Mҳ^QEP4%[uM8ߴ5{yuUg?wT=v$Ġa'/Pr$$4Yԇ`LzuKX 0()uIAd(Nj=oz*tofG `e@[ubu_R@y"ܴE\l/L_Rn޺)|8`,ʯj-iwN*#d%iSj6lCNȕhGE  K_ ׌HLtTp%~Aj4ѯ$lf"N^mso BQzz/nB72.@D!G06ZɚcV, !4X#ᒓӦ&:Ň7&a@i^^930L687QH=QxKWlsJ6]buw][쿄3lJFhz2T`>:T$i/opq7UžImMR;kʔE3o̷n+;Km%ߌӆ;mMzD{yB롧j]h*CybyE uPumScRZS(l4X(8Bb:WDc~-Q%~ؽIa'I1۫b4%5IQﳬ3manq0mE߇郚9 )r9m=.?yjrۭdMl ]8vԸU ]V%gHш>#!*9/iKHk1Q2Qy2IW^0 c~%Ԡ[8;*iMn*-vUm5p<+q9݆!\b+Rr#{8}wG!1<>4[e qB\ˊKa`m[Yk`Y S(j-B_8O ߵw\`~oǾ ;q/L&%0HcRĴAH2:} /9T ?G|K+k ]LuI{^}χ.KƸ\T~f,8x[z%<ڡXjmhS܌ eV/+y+OFBou feBa>#3Ƕٝ2ʮʨ >~78."*P }/;u34i8&9)(-!1_;m7߲=i6«nL6xoW" TA.aNq,坾MQҌ1u64ܕس:eIr |_M|NXNXH{~)` pӌID$y$'W j u0p?ҳx4?# =h`ȹn+Y2L~v?'7Ż2 iu{RwϠk;ϐRl:+׀p5jI-Rz-{$m CiPi~`5רkĊ/bct^hmrMLi> ktUo.^bXn9p{lRZdf Qu y`ebxO:J++4=!EWܮJ $9&O-S^Mu  aKf9w c( As:s R0H0uӸ߇k Jwr+nm6 ]}.C K HBpCTҤn ".'ry]J5SE(Ѷ͠߀P o ۽gQigy!.m,ҍJ+Upw8G2I*cuBe:LH7aИQh]4!.LRdQZ4|Bi)uR ,=ݾ[jάt, \CK2+'?j+MsXh:_:01ԒM3o`=NܠkLIns^1/;p[~|G6@.o-`eP8Lï9pRQb`' p ;@3], xj:p[EFNSI~qɮ鹳&Pb /,KڷZ w2?iUDNyZE/Y2RR_4M-W \;tj`̗~+gHBtx< *CM~t7?JJlœcҮs+ #W_RoOmZۃOy!\*[ȷЀFhbL0 n)Xm؛4\TVZ E04zBi3ϔ{ 2jZ|; #tJ:j9ڍfyPt@Ÿ6A-BLe89իF䫎e'yqB]|rhld!yb(DkHFFE3xz~?kH>5n#ܾj8z5OǙt=s82;(~ & &-E|.`FCZ8f|, 8Ir`ng4N-4*Zo~:~PZ v-Ul!=&9U&Ip RB*nTϨ@ɬμo.l2K||K9w268ا,}AZ Z aJvGz5L<K!8'U 9k)h!P0!lAb=㳳 yT-Zr{#l1_D,x:擏D={YZRr ADJw)~J0~NyLLrM5 p)֛9$񺥟gs&/ϙz,vݭo B͚L/v4?=ʵJf-qpgkΝ[/24ˆ@&%ᑝ*~Z 94YƷJ|?@/Ofe%Qqڋ(?=(I6+}qQ{g(MH A]팕Ԛ7(g˗eek>> tOG=-`-ڮc0RՇ~LPC) q%X߲ysՂpdQZ%=5u%%8c~P_j bH B6%[qwΘ)ؓW],,b1!I՚>:j"nO*9(QܯVCP.ӷ@p|0u@^qyKL&ʳ7JvDWfk(<$*HF)#.8WQq /J")t_[Vd:;Qin㭧ō_纏p֑X(!\)VwV[›ȭЦJ -G7.ajT/j݇C&#?V(\0&TYda:k '#P-țB ijik99Tv!n,w&܆h"{w XV+)^p u EA d PX~,Pjf2܇lΒ1 Xx+/|ˇ Ey=8ؾ*QaSv만 '$|q8"_c睻YU h\WW`.cKgX3_A1}0Io[ /Ƞ109^~VMY:8bs+v2OyoP;L]0UJ#|xB3Q -|FCݯяoBb/`tRY/cxp0Dr#:sDOIqՃ =]pl0~+IBd]QVkN KaV-'U~m28%11lU8m|Xܚei}O%I#R0W3FZDrʞ]璯T]0/97#N"50^oW:<8D;%y)!wå1b,E.1!7Q 8TcvБڜb|Nu)~KBiJD4"EsͰ9`su[< BKc7ʦfh߼3uٳ-T XvõV8Gf_NjFdg"go&F_'w9Um९/"3-ZN+tXsIoR+tw QD% -R)vYўE~4tQ{xԺq [!jϩ D;!GJMMY0u< vƈWV%}y]`zmf>An/td.oYN)SR;#H{j4̝  d$_:qxQdE\H_,$AW %i\j]/էQEG8Ts yQ.9X3)jXjs=.]'! H>^Zɨ-#J_HwL8ѷ:'jL)T6@0QE~O ogj} .t Vq'}tp?ka?B{*BLjq oAXjP=p$ou#AЕX7.+g#Ұ7(еs_Nnӓ^D lMapt68t1Nз K;[v,<BR#FZvo*{1X)oSp@"i^ V'}X@k`$=ngMݰV.LRg'e]dϝ qAݪO-@:Gj}DdU'caHNMn%=Uٺ!,Wr:foR=鱨: 1Q ":酏 9B<3TړX\x,bU&.X\$fѓQigl*E2tjRiէ2ܶy=@=* y@x`<ĸ]W9҇SbErnU)e\>, RCSW% ]fbYĬ&߁&464u.EU铋׫T?0n ]`c͚g!Jk3bR x&I{5L D+V3=įAj@=}Rb4߹@@P!UȾO^A W`.% '+3F;ͶsC fTbmFvk&'YA ,B8]HD_ 'ҋpFo!W.cKU˦79I=C={/Ls,X4Z5 xҘYB8Û`#g&H 9ޡ}WK`RX(]~GlP0SPyW/N01Fnp.?eABOl4v%3;U̬=ؿݹ̡jًCa)uKqhsjBNfxQǏ&KyVI*KFkIBl ۇ:( 4\LxeUr?OcPH}m?̧EExۛld,T7 o '5bp]S!an%;Yb=Î"JaStb)ɽ5ZHޠ§?bMOs)Oy18_LQgPj‚vu~،K.}*pv2pVHޅDfψne_ QT1ۆY7 <kVu_TvAC5i"j}ۅu))m޶ɦT2!+iȭHWQ(G⑅A ph0(ޘ|1?r ޵'i "ܤD>Iޚ"U]M -dS Ħܺ,M7ɷpW F4p K9xwT~ D&">)IVO:wCAN{)i.ئ}Ŕ!.܃}i;XkPI޴A]d:*1>u22C^ځ^LR~eU_TC}Ӈ]C _i׼\O^ ҆P`FLٍ LaɲV3%P]!YOZ:rlRy#-]vi8Р:n;͖hq~dNa잸^NXH8%sł(G'o4BP  oDO&ƨ6ǩ?Y)):rhm4O+Q}TK]4RJ@9!] k}:s!DxO!Ozo 1檃+i1iEd+YX%p,FZ<>/ Ҫp N)`])9W _LP36ܴ9D<+%-LiW Q#.0Cj<5SF$5k!/<<& }[/#a1l0AsV\`UWXrLaR 2x8 Oarc 3_U(w.G]oZN=lY{6zV Se0'{.9*@vrkC0^z"cwheJxk4Q2L v4KBQLw2*!@`PRmhޢHb 1y *\Dž1H7^\Vr FAdR?цэ= uG+܀.{f3!"S"XXvf`M8`RA-WZ5%؅Lux7ZZ$ PE(ޢ1w>HM&@JyS=م䮶4D8| ,c{wID!p(ٝNc gi+6D]9F WRc~sa%l{2n\lqӏևr@fR%tm|yż} Q6tum߰^olg2;ўu[bBgPhsS18 $~BQPP}E}Vb9LL 5&4"r0vUSߥ?c%>ReUG:[78l@^%+>neHpTw߈kZ5a 0j@2qBCqqY?*)tT _ ΛlPd Ĵ~#eL)LOp!Qܯ1&^^9 T{ޭȉ\8ڭiSFԇo*-p7GD4`}eY?mܨȏ {-ÒQGJ[mi,,{ >vs#yEŤVc2<3yaG|]8ֆT6W![Z˗h`(]Y%.G:kv\I'h.*:{Ȋϊ 7 !K߷)/Ms$w5'\@WfzN9`(2벙hY/8Lz^$=st`&!՞e^t̓qԤk }/EmUOYGd7#jYJ8Z%gc{~O/2: } ɸ5gO2A\cFd޾Z E)&FNqghpb\Y>d%)(&I" CiX-8{I_'(\NG_PBd2<. s#';ZYU_Tyʘ*Nĵҝ3+AV]Gd&te' 嶀:ra~r gݻ8WSꎞ߸.:}  >dƫxأk PiAr˿n<v@Q,SՊ=t."6͵h>Iv#=}2آ_'Jځd/j`wά ?q)4RG %#DOS!u* yS՘ւDH¶UV2w1PD%49FJq0}_~7XbL274NogR^k"Nb<&BӋ< 4 D^A^?Ant$K.JڡWOzCVk4Bph.yR=oܥE,^lUBC Ir XL-e 鲘]6pPhkH}\'إ+7fw'Qp*g*Q߫FIY#o ij闷^SP>)ݘ3YbF4)6xB $ET4D,laSĆՍ̜&t[źwOD/wto 9gAƯ2XU [!Lh a/›:ӾQ0%5ӫ2FZl͗dg$EF=b#%^2U1s{au99]`ސ|Lb3(l,v"ޢ) .*/iC,طfJ˷,\ZCd3{O-vX &(j'8;D:ED(@,Z!mNkOA۲.kޡ#'T Q>tJ܉@ɮ>># ZsѡilBG̤&clά D %{'tE# ? s +eP33#-)d+Fe |[|@ҧ9 .Z8Q:Y{I%ASf=Q0MV ѩ*`PyO5gW-:$_U/Y7].sFnD<~u|溾m@#d6s)Zjf!pw5h^|ʿFVLs3!•dmy)IJrR@V"NX=D%Qlxl id2ھWJڿN 7/i{:h);֜jPUnPWdݾ{q79] 4D96oDVAl, &rC"UTU=Gn=K )Q&!1Vkڍ=Mg! Nv/o͚/twOńDmn<͌@H1W.%ڪ^Q]HˊI\zU5v3 ^mZQہ|BBUn$ζ&lLdJ\0K a1Nî9ʎIA84:у}&mן[džɧHknZ mP+?{Sgq|A lqc[$DQVsfkNfWP^s1k`_ƙ ɍ2c8Zx-p킇ѱu1X!s( 3>QO0Z7<3)rPT՘]O wJdLK}_=7܍Uz4_&׬}hAFCqԛ{#@':oڢ}(AB gd;vژɵe_Vz&s|+ʵαV^gfƘԄ'皑4r.,)f_["xE7^uن ; ǰLX.:j|WHغJ}o;GJ_phJr7+  ;?Gݥ<ZgڣD}215rWaF$g M8 V<kgHm-gt\6 ^ caSjȌt XT /n@B"i,qdu쀗a&@1q!'#Ɔ&!ZKERAK1a!x.\Fm v&RTf @ JdS:m:֠\dbY -/A33i~d;^vt>v фx}77ZZDȮoBIfjw-v~5|~14Y]=6>(&>ekV/ٕ^%;bفIb(`Y}֖6"\; ɐL=: gѽM昆"t^ ^1Wݪ7GOmSԮ,SJ26vzaR)!h/C8{%?B- AڴJ1s맨^8 $⊆띛h ?,cy;Z@]'_ wW_=j=5O tQ`Dh㟮VJ'i  ;X0'Ds#9hJ xC/Vߒk :Hq.N: )0F|M*J'MuFB}2ƒT."o|GÑ z;Z ]+ehRmMЕfz?I2jҺۼN]] b͖i%^lF(/TُB>$(,k?Ӑ4ѨC`k<݀oR9ӝzA3溬J1җn_FZJj֨28'k#x QHO,(sv gm/6I x!-(g[ \}pE^jtZr}MFڪ}9䫩x0("Py"n@&uR99-5r( B׏v .pbFM(NX=.8 } _Cmtمm.::]7rYY* g@3j 2OJFAhoԏ_s)&;/bm'c1Q@(u-%T[$Dp%"]k,4Cb5 ~N!%_GVL!@K5|M"S(k6>Kt rUd};QcH^ǾzJȝI1RT?YKض1oe4|VRIq1]g"]{#j'㆝Xe%d<~NCldjDȚ{ զ6/I T5n=ųy(YX~.. ޠE-i3=i`KbLV EY(~#쌧&EiHS/In]&nOIjD-HgݳYJ9Фr=5<.=cgE,F\l:Y4!FNe[m oEy[5 yfR$/l:Eϣ̥> %h_g#f;f%R/tbC<w ŵ=;,-c%g:gCe||v4wti :<\F- , us}y*cݳ 'QNZʜwuݔy ϩ:ۛkxL(!!q|戮LT0M$SJ/XS]$POSCC4:YãspU>%99ZzX-쁹YdE+]'_|έ)AdEQ=\9 kvScs{7cY~pL}(5ݽ7B|SՒD!s]#Mpki%"\Qfd&`xdpJD!ZjR I-RZb研k1)*D]'Э$C Ptܻ&Pa$-wbUָЬ{y ✂R22S_X`BEw$2/-q"IoM* wG9t误,/v|:qHCӹcyw#/#- d#mE(hǒ헰#e{9dBK!Z/ Zn- {AmpnCzr.N:Y$ݸo憨 BLtIv2P+)f#]Q*Wp6ŌR{MTFfE$^gS ?"(m(\CMS;UV})M @9sMTo)ʝo6ᓛȌfH5f*"Rִny΃MsT!|ſ2 Bc_[ą/ jz.mK --LXgmb,JgARr9х-1ǔdA|rF$. b8 Е\b%+}8cс^G 4(rVV)F|a#Oj>хm w;MXdZ4G ̒i/5B$_ ~!զߩ njZje5PcrQC,'܌ˀ1CH֭ZA6FӭȘa]nc9NnWtMiv١ƣ:ۨYΤ3Ȫ:Njl@c]hڙ}bN_I[ZPyͫ1p )@bwfM?Z{ڬa1-J~.D(IJ&@hj+1VWݧ}Pa0@x?>>҈V>n+a1/ < v=B/s֣n":T@&=Ǹ7rNĵINQO`pZNsn5u)E= 3EajE@:9QO{2a~#MAdI}oe^G |"{ xe`!IJ[J!˜>7JV'I8ji(xDy\蹃BWJqK Im"/}|.&[ނyi~G1Bň݆uߡ'9\V;QT/pDZ5 ;i(4Kp&EiHn5y)GJRI Ѵ[(oQ.{h(UMЅzk٨kn {C%y4fg>QOy %Yqc[yA/Tt]z]ڂ$". 3ń26P-і=U{:봁dOf7l願I&'$Kx>w-f}HD<[N&(?30/u<[W-5';,`1PR†^X%Q2; G;ӟ@I,0%LbG$ȥ)$ 6~ÎY?Wpu鋲UpB|y$IZ[EFi=WIio,M4jn3z#'gXZ#&_ 1O{[O&X .@bpw+U 7iZZJHnM$'k_2eP(]Q+| tYRrI0yuc(Oؒk36JgBo|C}q7@?=;3:߻#t`L􆣣|y`h=HK|!n ݤyy k'a҅e]( wP'W)8׊QSy6@" O2D_zQNW 8F8)da PIg))҂Mqʼ(@=XeV?c н ~ H7) |ufptPu0ِa.*%BVO4B5 >sӻ0F$Ҝ?,JקfccKTB*Pe,ȋőGcl"t?ΚT`{kRα6*}y8&¹o'u"< `q4pIu?>siB?9-R>Dpɽżl/hE 0s0O^HC3Vp"Cʲ`&ء/Ŧ"D7R>I+$a?%md@p1b'I+m{?H٠O%p ĝ^zt {q+IM|G,Y^Mbt=7,E:˱J];ꚍK;+z. GMާQn[Y!,h-h8m껹:"Fs zr~mi0pnNY[+JmVz#fscOqQ ܧ&ylzgRQIH ۅ[إh jgoBcT NBLǾB=6o剤[ɭBs,VG"ߙh,٧̩BEڠM|]l7|e"X/="7$"K8,>H9buP-F,dž=a 4[;\ 8: jw" *>58xR/pWs;c\c[FLu?=YF 4eU[OHb C92Q9Њ $[ Z9km-Rcml~3 l? ٝҔ<}0`R>p`"R ^jmO̠vt5Xb> u%͌ᖜ ^=?y>%s^0$ $ 7W,m)Ec{6A\it C0\Bd_ &"9C՛jnc_Ѐv-[["`(O^hZX ,wZq{* !5 5OaGi=֒2Jy"̚H,}@Lf!/<9dv^.;\3o􏌧Ywn0lz @}_T1s1'ho?i|> JC0N011#vRBýߞzUUb֥fwZ YQ319^ެv ڟp38t  n >"JIr΄"qaz c 3 dbu WegUgny"4Ski;4KJS-d؞u ۽R^_Tl0% s4fqJɔ}KT"QMc9Op u%<`nW/$3SUy?+Q솃6)~? ł4\O;zwQ*JI^'S8gh\ˎ.>4_ 2f7 S5GyyÑS`||7!QD˹B@vu)!,Y5˞tr#CXʨJzOLJOpG^Pv=YtuZ}w]ݱ='pL,<]gi37j+<;$G5+-ܩ\aSwWğeU\_vb.ҏmНa7?,PN5䭆y?Q +JsDkQ.Vū3l1. AbIv`@u_,b^?4vSvxFoF:- uqY_dϡAsj}~<@Y6-j ho2~dm-)G,2mkw=x'k7C1Iy~<0y,9donc]*"36c{ju !![\kD0(4^4;.aoC{@"#՘A=نRHǚb=ePz2]{uMyi/I8@#Z,c)c~ t1D"àn[8jyq 4ƭjkm7vX@F 6ࣤ\E964cCps1YD笫&sQigq@:{^,H~ˡhb#oCk)릤ZCy_[ cViu3U&~Fo=PM[~5X&tO"G {,l9^uOkL]"UN0f."> !XS Ê/į8=g'ldK1c U#@.dWt If on H$CDh6 ;2XGKp'x+]:'{龛i)8R%WfI9@rf,+!~$/"쇜:F0Eó-UHtԜ2s7E>Zy *u6+We7QhzAA 9{F6/%Zi˙C۹}?29|e4"UN9?rkenB]2aVu"C{؃M~wC? >͆,[|9B,CR- >FM-pŞ Z2Uf2d4dL{XA G/5O }VCC*)E;i,u<Զ%FdF̸O%WW_qYJTaT< xai~/oݬc6YaSw Q#Cc^[LZdᚪ(`:OОUeOVCCaR+(FArNBlx<2) %=FW!srNH1A=!L+2śh&Xl"5c}1٪B~ܯz9W|oЛ& *.(zfcܖh wqtU'Dҥ2tBVZ'PۅI(94`d ] VNs>->S$ F!Uv;UIBAm*0y*?"X ft] =XN))^ad$n2XNN6`~b0 ) _JwDNe[Q=e!rz n )|E| ]{|ޅ5B6lH HdD^GVDs{ ~W|$PyթJx@$V@P \WDKH.Q(}=Q[3#k< LWaTdžߘJ ,IHޡm,~8NEՐ,,'%'ÏcJUĸcKBQșc|_fP8w?d`D:~n;Y4 G D^[2N;,[=sw~}$"t>{1qeC('2$٨M6`/yR ~e})r`4@=؃-' 26AZqɱJa%D$ GC!&(V%V`׹M͜D?̧'YcgT)Y>a{C:gH{zG 'H}FbStCV,˝{ I#!"CbKHac0KArPT,h 4DfS|nnsq1|Uz:(mX*siwaově+6F |s@vMݠ%QӟW-*F!1xSfH'u(ى]Z @91jDkl$XS_Gx04­Q"|7'Zϸ~byޝ}SBn $9.]g^Q--mCQ fӂ5GxGj8"*KT x`56c.YςȽR{T6[٬ԼxI%ĐH{`*kJGƚ֐ qJC{c?O~p{WPo4!姙i &5яiR lh@%U@=J[mU.ugЇ sX/cyuL*? Rc_@r%<~j%!+\=)R%VCM AjR< pǾqżj2@?z@;26N~թ 2dة [Cm)߿^#,G󹍘D4/QiŸ{4Us}AVxd͚G` 5B@:sVY[[Ni@J=p۠j/yNS=߀uUZ&'-\hLlHX-Oƛs| Q"M"PְByiaJ\og$\:c)>'ԙz4ș!F-wRI[OB_dB:^1թL ,N]+8fHeﵣz@ 0!=Ku݌VJ7Sp/ ݠjɀl>c3 ݉ ]ZQ.[Jү:)+,X㍣.c6I l2Āx5sgGD,I)&oebI-qT;*l7얈ۜ>CC^ŦU"4{l9Gfi !!.(NH\^PoAb(XcHtr馄ChUwc  PlX^4 \G^RX-16TZd<$[i]BPU)%:I4C _Q@ܮq).$78^A05%O]/$ rȩNAn܈=HiCTtI?dH6!\`A9mͻ|R5%9{F&F_+5Sl]o+f)#ݻG"So".ܬy>|#M"ZjV!)y7~4ņ;[_ hx܄nh$y+^G씅8(ٕ<h૾%$(Ge  O^"u{ AWin4Gߵ8e#!%kFH/<1Ԛ%H"zKəGjQM ՀJ׎$>>re9KJL),h;,1Vj)HuT35IuהQ+-o~ pZOGL Iza{,Nh}uiq#,@|Ɉe1az% rdL(>Dr:W0\^*cVE{PcHOto<^ exSP &2Amb9EU\bl1֚םK@$3|F={*d۞^7=-TpQ=-]j0Acf$j& îTMb[JxoB y6]S3/=}0hSQzQV4yX9p U%s8Mg=3)\*~]1Ne!zOP)$X&\E v[1Q#_1}Cq:[tZ%'%p,WG(jV -#+2TxPOR4'%|jcca^V5wuQ(C$Dӣeh-n[P@/V?-|fwpՕ,p_U]B ,0@PO\NKԧ'f".i<J_f1x24wW+TKw }H!CK"mۤt0^BPg]/0RBTBmB f"g3m{5/5E T $=i²xKJcb%8˩ziheY" ԞYCnpBF]f85b]ob [upsPvM#5G י S5T虭Ϭj  *f-Uq@Ƕӊhjp] wjsu1ePǍY 7hqXCˤcto%fytBo^fxP?*&J)@*lH*Y0WtՓ<˴*B{|g)s*$gtV Eʕ7ڢ2De_%08 OmX3Io-rC飀@]Q@kghSβ\KG6,YV> w hcFdΖ[˅SZǪOaJ Pv |~S˝ ^]n1! h(!IzP[͆4m;4Bl )O'-Z `hqZEM0Mm;Xkc@5M) qFnc?cU07t( =zrP Dy ItY^$E HŪ!ߵ}WCڲ0Du0lF'8-'WΐYSoʈ:N=5*_xU ^\'U7EO4_ ߩp8RIC+9' kViTj9VF:rK ?BLPG$KB%|õjdlX;ux>?tP:`݅d1a?ڴ8:w\gT:&f,uUm|ed6 AT#V c/kUXf>ˀ$= oc;^ŢP[v.k^ow zA1ȃӢot8Xy3SȎ #=VՆIY2%4Yy [Wb4{>lDrkemW ǵįysTi ɩeR͹.d$dH(JΜ8 5>ZrBM>u/ch+|iPw65l+ϑ>x˓C`O-Uv" .}k%))-0c]/i>"g9ػeƒGPT CPmϋZSa&>`~[*HWq.$jJw\h C͜Oq[c7>ۈD?->\^Hߑwu8pz /A*d,BK<ًݗ;L)},DΗL+{9͋ Yi|WdYxR "A4 \ݩLg:6GO$ݩ,nq㟿\< z,p&H99|7F>#~T{gjr zD&7|sHfu]h}[6y=NyBwjikZ.&hzªp7RHH|d5醲;ݕ"786]߽_1^f=F)W-vϩ%B> S(gUK~yJ.ǖ -+ɓC8k50BY<Dm߁ $j|f DT%Ob5 x!#w^H8][wXϷ;*U c(\ x̰ґB/&)fy oh-o׀űxGbjwf[&F S#QR,/eb׻7oPbp%Q#g|>IRR Hy'N)ET6H7s*A+ZW t5egaBJ4 i@0 e*7njy?i畖xgؕIvYM0j;Is `,K(@<4BF;DՏvj *6]8KLRA~+4}~DeBƢ.V\!1eRV-ϻÜ؏E3:ensАc~+2 Dڎ:ـq4Wh6V ySnnM4(P/$TǾ*fu2C\.4)}mtٖOv$=_{G~b+eb@5u ~\տEtD"e~o\=)iy* 0ܛ Ҥj-n =YNH&}CT!z(r#$<\ҭo CY LD-Yx×;gN-NOm@;fWe%'zpJ΀ K9_{&iXal̉G՟p8 Å I67!$w/u z@Q8<7\RRL˦R0pz٣g#tQ Z7-Fz2_o`X_2pf9x. %鹸 G$FGG7 XwDlgp(IJ;xu]{khL[KXn'clm|1웚HhP^10ee%f߇#h݀QQm6N篲dR+`ICTax1P _vf)!)S<>$X".Ab[FH*td#_8`{!Sa=rK<{S8 }~Tt2 )#85nXL(ܤݤ PIKWλn2xg ;xd!כoam1e;,&n-AmfJFӍtkL3H@0h_+ J Ie_fq2&hoZ+>gXA:,# h,Ӈ]ޙ5~x]#3&uZ5=[y>ˡdt ?[t^щ b6iDr<2(r6HK.s*"!'pzW'TC;6hfK J`oҩN.L2HWu$kӴ6 "OazRIB(E!3n*'$ջUŚaʣ@qlH CԔF$Q50Yh??O+DIh. &H2SYp˘$*C3(঴=n [:e8}D[3»NEpED X/8׻[hM, N!CuKB.NIY30Xd} ` rt`T:(҂PY\X$;ĺٍqY$Kd2F};.`!-QOC aԥ0Յyѿi6~~DT)c Mmw5%RDINjCNnzG'9O&zK`Oҹ1.L:>BѷFD(@0dџI|B8$\P}K䡀uXnq?TOcU+,ؤʆ)3ϛ́ߝ :5 ycpޥwPb%+&K7%?s]@Ry3ri7kl$;^J4"&p.*FG?G28ʶz'Z"dBXh oʤ5{|iFJyK"UH5k.W|}mq=v̕:d0*M˜9`X?^!˳8 Tu͊%Nk@%<`x2azx9yjYbL'~A-Z5'S_'UՓ=G)RN٣y 2IӬp0zͱ Y1֚k0wR* Obz9E>'%ћ(;~˱X ̡3L3,'IzM)3?Uсh{p\x8! EZd\02ı+7ک6%LPΤR@9ޥ;"x"3~mAI1N'C XK>Q[SwGN b7p'oaoG؈ fHҞ^,αb~v% =eD}"T.'#ܵ^SX.!]̐ڷõlޣ` K}?/uY*V|ڛI_Qk-\4Hh6,+(Ø}*-tmQE)gi#|VA˂kvf(@*wRÈ篩4?a9UV\60֑muSJի53͙Ko xOKCzȝ(xy)M{F EfN@F!ޭ` TS<'ի^jwaG6Ld' UA|P,U `+%’o{3{b_ ᖡ6lj&3<4io"]]|ƕd@z%%jGw< cQM>QٵV(KsE#яJAa9"ArEO eT?A9 'S)xM rIڗȇq$|fEXj PXևs v1 #2e8ף"Sw\L[O;ޜu0m+٭bM Vw8h\ U͂j߅{27)>J+ՅP$_LBz'ezȏ&t1l _vp/# ڼzW/1&+y4[X4zZ*h_fͽě :J?i>[{37wYSpK !j7O ވ^[og;C?oK)ȻhUZ jbjX 5OÈ9c2ܹ]_IFdhx}vC·6;zSMb+%bw![/^<+f*=w/g(2E8r;ѹ.f;mTѪؕfDHP1GlsB_ڢ*1t<Ct[EV: Axb%6z?gFsP#s_MlT >deiI!!z4^:ӷ;,:+ͧL|=+BOF6'/h)?THS0`Oyzw6ےcp;zidM)d%84iXƳ=J;Ys 0[ 2$9)XȏoȺ*NtJX?jŤفjfӛ.j讞Lpz29_DN:ɸkrV <#mΊ _&x 3h~B?ni| ?5%澺?T 7oLUbVRyuDî+⽶0 `^r٨abl*`Ri.5:63i}6TpdRx4ݼg kPsy%xzX)+u:!1 ~׷ i[4_Q)AN-CiMRΝ6c,YlQo+J:mFO ("sgxr'G@>wgA.fJǑ|9a<8"7M wƋ3>CgH˭{ҍKy{dQ})Z&o+$Z XkF86a2O K1} ަ%Ff:z^n/v /rpޤ+Ʌ@NhKVXi&|3gȷ i:"e 2W 6vH'= BN h[lV]5;?Ҩ!Zqm;کd%he`җ q{FP4#‘#HƉMUjŵG-ٟ"102u)Yo5&~qR pY `^=!Ϣz=Y5>G$21`H9QB'|)KdlM⿡ڃ+Ie'F@Dq)j)kJO+y( +iK S0:f;=ZgzLt7>HТY7@m=ȭ)E,~O$ i.Tۘmdd_וy,!r9bnWjRYlůc9[q(XVds zA}TiC`, F1{oÅIԈ+&o.Q hq뜳V6Y8\jxzjRmUDPWVv'%ˏNL̝_gIN8C)ļN$媉6]w-f=i"BLto<2SIԫZb~ ,Ǒsk pBoL-qrPY#ԣ z/u൉ oh){`.*+QkjMq-zzm- wbuBccc=g&"3(N$p=1qZqq&.,Z X*a*6OIsMVnX1,}7;+(ƭ+u1/=оn.@?_ ~uz)ž¢VӫlOi^ǣ/#rKv*$ *|8cev [LC|QjUs;kC 6x䫺`5LașUt/x\,įP 0Xq ѲLyxp UlX>{0NA#[)O!5pղ{=i^7>ifi!k*.cVZP8fgGHwlȹ;HhHK S@C!wT2.G>Q:y6*f0e_vOW?)"AAJ^lJg*uvw/ ;-1nm7SW t5⩘؁i~̻[x@&K!_m"+bM'@, Q?s?1S%k_Ev602)*v\>zAF +VG?~>TTnsGxo*XpHfZ77T@;lɫZ;mzp c9o|֡DÓjƷ+MV`PTElk (8唤c%;CoCQ5b%ܧ]73N+}ͺy7 x!iliҷI@~_b. IR?ƥg(h^v^'ps.И>!sT3|2ʩ#2_ YYӇ|cD"fl_t堆hB7 oQ.u8p1љ7vf ,=Q& \V 3 elise6N13$b,qhjN1#D{(SUMI#};[>qqn苑Ty\miQgKWNΈ)qoU&{—U=Ci֒aUjyR _25kAK,)e %.9>JV)p r:J2׋Gx]_l5:|g3&! 3uB hK5vfRȳGa e%ƺQ K%yJY|_- bբ-ϭT; :av>D5jQi_9 {Sr릷{c%!a/@|J}ƴ@b,>] `2` v籟wvP RK!di ^[mN-WԈX&5 \(bftّQ ŚU'ku\~W(bs`D4]diM杂ΐ>)Ո?o=eK. x|;E];\lAϗj|#ˡlvki@=Bvd[GU'zVv ؍[k,i|A"+hK7Q,И-p߯^).}74(ڸ3YQK'hhzv*xKI} V\pjIs$(7o EUf%6"]?metj<'Ϛ* t+2s5RMjϫö/#4/MH݂G$VRfJU9]z[m$-qb+-2T;W,fd71G&`y_LxgoIGT^ʷ6)l$92d89CcvJ^z]!5eW 7j$1i1n4ހ8"gD%ދ`X n'ݳ "#< \x&d̻p_UiL99Z+WEeMҘ%-&72P\r> U@D2pi8çWd* .:lt<Ѣ|Rh@w1>uowd*'̳ߪW\͙& sjO;StBb K&ǧ_R#n59I-MVNs$H O(Aܼ̰FV I}:j)j-QoF?!8הj@8{l{RW{axHScu7I.o;:FYP%1T8"h˚7j" oRr©u(o}ɔjM?:zHSh9w3cWn2F9Ou|.Vpz3B_1( S=|GENTyI; {op;mQ4Qy7!^prHI-7Xf:b )<|溺s4A|){wd/!!DID6*~@,\7AxsS;{t힂r< W z}sk;uIY?ĴZ kzd@Ee/(#^=e] #h23ў+\D L(@RxFLJБUia:R#UާL"If1>cYD0iN`둟%xdKNԽm/U/24$U A^99f}M&'խy5КV3rѿ:8|p/C>Nj9?AAQC<vTEya4fPCiXi2gw.*mvܖ^8!b'4:Ādcex* *[0ĺ !ՈWV,Ϳmd$6~Ʒ3!?aҦu#"?CR3!3>:Sɔs: SaZ`j q/n#Ey4ɒnp#w-Ax*j]LGj^bl]w ZJl=mנ`B/)]].dp8LYg4̈́HiE#^vy!y4m-;}`Z$8} `tq/LYoC}"Ptauto?r?xM(A rz3g`vf$pSā/(֏D71 ;_1.yĒTm;^ji=b8ZK52aP{W O$ϳߜmMOC2 a07f4yُ1O"Nо5!}a/`1M{ &@0-6e ?v$cQ.rnpY2mOj#@ r3M#Ue/]{s[ Ev^U3EWgݵ!W`Q$Lbߋ#o\fNtX\=8g_5;rW*B8nxL\ǘigeEz2ύ.2&m~N&bBs θP~v$g+/^ߞ˓ݳ@8h[.db9{3jP}a9p@`Da۾6mv>,z-4C2LM"cL{)lfdQfK.O^qȂ]/}>PH;)NܴbJb)GS(rgIO؜ƋušD鳂Gc~ЩEAqY7@d}r` Bͅ5`!EYZrIEsǕF279sWc%Ȏ}672 ]GG8f/)>5u\*l~A٢rrV<[F|kP|ɽpJ"(MV('__hA&03}{ubgB`6Tf#r8#X'B78ɍbT .<_]!JL@D/2b@ab]-m|&el)>*agn6Z Ma0_y5 564[9;W9ob2\MWN|mCˎ_K7h+Ӻ+g*ynh:U5DmKA-M ݋@M'HG Eå%\^lmTxΦ]0/ p4^O#t# Y'K5}dJcM~DB(ć#i%/X>FYOmG,8L=[%ɮrXٵXS)H26/)'6H7* chiXǃ5L fύ*fPY, bV k⺛~&k]JN"rܜؿQ~+e{4 K()]KaТĽkD]){GKXabYXoGL{WooezS?y<<~I 7"fx"3e: cVNԶSgLŇ%C xW}wݛ7b'ۗ;q)'AK tw 0b~iYV$QS>8M{Nf4 PTKrfÃLT* b&tZ^ؕ)ľ.\^5)w^vxYI'X {nڸ xt;X ybX.i~.m&"T1.yPu^aJzR+MsȆ+TMpk#:J)ωˁ}t( FD]Ri$EH>_?JRL%Viqo/W2΀DMd^,̀-rE?2bqc^]z?XD, v(gF}}!L۰ G ; f an_BE&h?7D=~XbVBhTCj."rid /G,h$L08シSpB{`V T}ߌ-Zc[Y#r ?= (E4Ļ-]Bq:/)AEwoR8}mXRH)9 8ŏD9 U2@*v9mR 'Y"dQ! rP.YߢrjtXQǰ+Fna􏄋9~,EDעb;:8e=U`;7-rfP*ߖ0|1JVI .,KW|B-Gb$onRU$-V=E#h)h g7W쇛@~CsUFLU㥚x*S42WD}8 KscզAmKxg+c9uW~ED7Ԕ?*8ۤ >>dyEqϲ@D"}tjDys huޅ㊘h|'6 |PFFY%Dr_1lxf(\U/;yobZ+oצxѫQJ[ N+Y㨞[}U=DZX0AZm~\~,戉IAkضl@8K4JK~;lgo0ނH_SD{lqk/;-T3tq7C\ϚJX->>/ѩb"@_!;|}+6ȵ)_DYC7lnɳm!rxDT#Q|Ưb?*ɂЏ9LfG;G`݇ X'0xg6KmMqv粠^%4.@I'{)SwC汪!uMNW/rKߙ# ˩+Dd"t(uĞ0]K{y;N[̛Isrqk5L,= &?qF2N@/B`ʻ\d ww;/:ʢ#mfQ2V<@bZTfH+񥏐\/ \Wh12!yɟBSYf}@hJLS2(6Fi bXw`n^z S2ְ&:ElbA3/9ہY섷ۇǥHNQt8 LtᴼC"8#6& Uߟ-\kJ֣{{Q܈U(~S=LG*y,Cw\j"zrk6bgz;{`i؊ߍD%+as|ߕ2Ŕkn&#J 14-u&Z%zl*ʙˣ:iKqAIn8,Y@6)9c=13nI~ 2`9zsziō'' OH|)5(0@eN r)Q0|N0NG"[7:x6zuUpY pVvXFVn*-}2~PoïFԮ((0*}lpv1a~Jۍ+N]PafOqUs!?kEڑ U_X&T-x5:I _jf/m~j!*hy0٤<3{6bi`l8fa|mo3:P!WM^M %oR Hg~΍9$SF14{acӌiC4{'o[50d~EӳgnBfG>Sσwm,xME% P>ł=7-&+~EdRCcJG>wvuc+~twtŖS?ͰxTNڇt ;ba9jxb3X cb'$~;:M&(}`) ?/>h5Bu]T𞛤ź[~m{T""?7)8]k¾7%x;',`:ŏ;X@Z SC-y"'e+7#֋{k(o{{aD)@Kw3dX 7T'.MO'e0h̕{ٱ@.zRiMWGB&܃ā<[["P.^SXTWjN(t[-qBk'g̭Q2'HFeQ4q-FZdtC ՔFg$@;pT7mi-hrIpVXUT^LP1`R3ZY2-=v r0` )n5ͧH'.^Y;u^c.jƤloz9xt!H%tL#MǢCx,vJvpU%Ĩ*,ңqhTغ޷ԘXR$R2H]=޷Y5Ĝ0V@s XTE ʞ3uƐ-28LbX>1@T@މ^a@.9)z-Yk26(,H4IdD?Xb/[,I&dZ;$Ĥ4AI x/5̹>z[GI#EI5\gaO}2*+]gM8`2x% pmFR&+R؛dJ 2URQY=:OzZ8)'GGw< Z) ZD#F0\sFvnw0 ZZ9> KM//.t( ̹,@ }d L_QūҼru [&f4&TY?xz0a|Dws>;k@zݨ"ۉaNj=Q_95 S!M#o2@! KF== $!OrЁ(Ɋ.qzJ*J%"7G')?Mֈ}G'#d 0HNBA*L9KBx"$(VD;Wֆ8[7k3{>c[o=N}0ʅXXZZG [e/8u*&#x^ lL؍`?VK "Ya{dmݝ9?ZL^#~̾Q n@`q{i)nĉgZJJ Ir~F4l8)]sx$!yUHQ-n-WGIѤXepDj}v@鬵U5kP1Pgk!k+7$lR9L[%N+&R<*Q1>ڊ4h'@,1;$*gOx|[.)M=?Sw긴JƐt Y QݨN .up4:67RNV[$=TzE,o&!A7RQX_Tɥk ^Y5A2 UDZ'F|.Op=m; jY$-7`9?<̣BO*rZfV4>h\s5)KUJ,aѬOa%?\7wd#a186UD5AEp-C]eY(yv!^[=tz-c^esE^a b3yz,+k'.oiz"Z5L9k?ˡpib׿J ݏd׌PyB/E6U/Nߟ ãb\xgQ~w+A"iF=54Hlg@ST F[z>]\/ŧq6*,hqTJoNmWY85՚w] x6 eJx1|_BZYrVM !q16H;}h9GB.H^O$ZZT_HfoCJJ&aA%8KMgRp$6YkRf:)e$l E?o8U5? zOy28YX^ `@:V3E|cF& aDݱk툨2^Ox%;#,!TB.cFB4Ғ&SNošOhnLղx>˴ Kq  nb SՙW=U\V` pI0fSu1/J4 YxUЭdI^8((X|} =?=NZrL3Z9 s,[ 2pHYՇ0j6 Ox7Sn_m\kуĹuG}e&Ν Aͳ[,$Wb:~OiSR$_Z;`2h$<)#tqCjx ,pQЄ&^uUh+@֠֡CMW:-N @wN`t2F|0o?I^n eUb5U֣2)ӝҺ,nJ%Q0<c=g[>^hS1ƚU&W Y2ԠB5QQ2`K D#Ϥ/Ɛ^ ͬƍܞ𵩏.e 0 \|u+ / EeMLz;__)ǗyfpLjm9,k,Č`^zE pU] r˱.pS`~'geGleFw:3g6zH Bd(#Z}?KM ]@D˔i;Z2'*a 9ލt۔$&hv:Ԅ_+ZZ{ \͛1yvȶҌlRr|o1=`8OYvfT]/5=B,aޖ'P9tnt,_[dDR.VpnVFVҹPx)&ce`;O`%9Η.QU%A߿?a-3ϡ.1^"$qssZ7#hf4:?rT $i~ԃ ѭ㢼Z#YD&5>4G˸ͬ-,yx tnU4~cD"Ep? wV|:@IF͛?aW?%GS%=\0)RW,dcg +" ~+xn1&ȗ2.APijan!⃾ b;g \g/zePW1t cD=pLC&o Ƿu3\-]Nz,(ȫnYLY9K V-;1$ 6dyޫ9&B> Ch_aS0N<1>aat[_Ɠ&s1]bx Q(HI)j{V\h^^w裌>NVjOiCbC,ݼNeW- V5iY{HO|[>#N8`?Ihx]()H!D ty*{X~NMK Y t4(Tx"֌Xsy!C1luv-/587qu|;ϨyXcT( UP;}A:DnlF|iSUCX)SxWN "QQ8 *EioR?m,?`v;w|t*J)KX|zwǀ#tN \Z ]>EG)S@B/ =gc1h1{=`yfD;s3m|M}oyCl tW; fk*Wt $)1 _b4jjj'v?@AբQ 9U6.E kaD-zVN1H}G&+luJ+SA' vЀ%z& ZԽqM и4bvJuw%[YA>ZVBE?- WK l?z- .X4-0g>m10dPj׍_mV9CWE_FF 8VTY"tɱ5^=+{8앉r+a^ꖇAt4]HX_C-9Eڐ7ks]F# cUp<˪hl󡯮 k2\ɽ`!<hU.YHíP?T*hRNH."2ҲJ{`ٹq}'lӳCZV-M䙷Y6H+g.SAϠֲyKt(fꝆXP S/[/|pr_g!Cd#\iq1}ECu :WnNP~VCH5Is;Nӷs $)ӵ݊4S؈& wChJ$\WM$)NFq̲QL)U}.dS q }> ߝQb ^ aWV'C6|uNS|<灭MOfDgPCjܜш, ~)Xv辎J'g^@Ǵf}X}ma %y֦J&mwunmWEizTd@ 9~$ājD[1K3juH'ϾT</ntų]굏d F>C>,֬kKN3lcJo"p1A|%U|wGkHƨmAH SNJ"Jp '-`Sz. *LeOHٰw!\dZId59s5F"</@w݊rPݗ0 q|%popEdž6HJg 3<:MuHf pp^7kq[S2CP%:g!2 1~|X{u{r8ҰtsZO]1UPu-2Z5:RTuH.}B02K9~t<,OE['&q"L9=8i_[@XΝSt{~̌,;o=0ȢD>LGTdqv&Ћ6: ŲX(?ɮ&=^A&S2ЃUKZh(*P&EBR3eP @inx"B{iX*'cy\uw[&"Γ!6^ݧ|~[ӈb:)+f43~:deq3q%DϬtpQ>UηjcG“qcrGs7_c*UyJ"}G,g#H r$rBz,hbxlq+KT׭`>\gYȬQ\ѝ AX>6y%4\T nQqA*Z(|2k,4>#sل|ߊe&Q?m:%}=A)Z!,yLxp)% Rol`lh:Qc#cyCCRõA`?1+Z?.- heֿ5X޶ISEm4Yрj*{{l.?@<4=zyXNFJs 3Glumă( 3c㸡W#8o.!$Ea4-6b!\y[mYE* ."dJaD!qΰqN,aAkǖnMmz/ 14Y;3P >%ױZG]p7eSq"2FNsw*X_?L1 _렉e/7!@椇#718@;ߕ#ة[v2bY[ù3巇l,1AsEco6qbHD_U[bUyve'\ߣaulpȔFZ$}D&BO0OR%Sb!W!qOK(^ġ>JٸiS_4is[`N=AoH̍]Lfq5w5rMj ]@5G6.xM}]U3ٯ/@[h'?ӥeCźq`,,oۋދU^E&NCWEs \̄9x?=Ƈw{p0K;r$ӓHuy(E%Sb7W B2xa G"d[xTLc6^cFb6ٜTM4fb>^sQ汎ؚp'j A ͙[MY_ϑIRZ[7*vvk0bl!)*TyM+#,MVJWjQׅV!VN'K1 0-<'Q{+ `Gdj9~xp {ηџyW psw8~Up"T043RY+!Gw9O}3_wu+`]Ӓ $N~W}Z{"Q~0g\0>21r?$=.(s .t) DA.T'Kޯ/Q'&3mor2 :A{B13V>@= `WP`v \2ŀ/` ]Ȫce,4<JwlS$am*o~fU )u,FܙXdrb !ce22*8-f]/RC۩D"⳿Svf ĹYk-ȧ` etuԠL5KPQ}qѡ5G=:6"9gzt~bS-| F^ŌTlZh۔NT'g 1=1h4$ˆ^`[z~v=CKa~+ iCK.d0 l_8L* LqU)R_0;M#I"-*cK#.z^xEɜ!JPDXU{(qt]Q&IPDG?hb LCG&ci MZ,Rx$CTnxZ苷uyn5zҸUaSsx,&٫DLTV . Es+Pߚ矐,חEǫ_s=-Rta#=j{lOl[A2L47㈋z>|=C2ȵȆ:/X.5ZBQ ǟO`F`ޥޙ8 趘Ǜ`4.+]A|F?OsSr)=tl'k͈˔4Y-'GXU-IOUC \iȪ^ZGaE~"YsCO 0Kܛ%#Ct?ǘ=Ap٠υÅ q&~];]Q)T<@Me&x:MmTA}*EG!՞ZBh/+XSNJDڭ$Qtcp֩u-$3j5 NPxkZM5Yy0 lA/t!3m^4Y#;Kx!Qno=Ap*IPoD0hfM{&XG5ۖ0!TJYdS=.OHXD65t  1( O@ԒfqHY3Ux|ЧJآC@l@w)|DZDa)(W$v)SjA+V#o .-|.lj@F/71?*}ܚ1 dPcd#$VksǠX(9;~֫v_1F2r(א!FZź2?p'` Ǩ~(#3}Zm?:G4.$naJ}pL46\Hѱ=7ܲk[@ j&dYA쬚#DMw#5l1Ipa&{R N8w NA'OP(y$=6 mjɯ?wIcy+\U쓑{c:IJJ o3:g|b )a`KQ0:rJhHz}7Fm*qIQ=w1T_g(cTX(TyWǨ ],3Rӏ/`*;;ngO]wiaDh*u0K,TxXjn%HM PhqD :3N~ 8i=+# A~ ֓ϺGO͟w|f#7BXjfl^/@J ~FVlоX =Rה<2yNH-WG_Dz"Vpb@2jX \1p 71gD۽zV|$'el' %=A.,;P(H|o--C);p*43V <ѵYiC+q0BgӃF㰏A3@CG6M=F˯JwX nPz 3ud?[PH WU-zpF<]d1)禙DXւֲjtic=x3_VMjį:(mRa"C:u\BQ?4YoE;gPTu:+/Q=e2I< -P@MM R ˋ+myLK'7(Ɓa4D#A}l]xv3/T)5??q;MAL 7)I;գOz H;Q5-e !@ijP1OT۞jk^9+֯})@Ȫ^ĝ9mTux6\[u<7`!4\E7FwӇldxPh~.[ z {8 E~-u#X." \ Ȗ8L+%TAhcnbx`bt,~᳘:BkQNؑ/]E4+p 8LrX%Y{T{iApBI6齁E 8+:0{>:oָ?]Vw S+QlS2> $'ϓAWpB,wfn+IP㮈BŻFu9zNe$>螮0)g/FM'{ l]ۡPF7XMb"/ܦ%`Z&J" T}n-B!Ok}J7:&#>F>9wE~t8&$3߱=ոvi/۪a#VKKTplbZCk5*pt&ۥTBNp $~7}w|CIgRDt2Huh-7 NSZ^QzmF'{%d2 ]+:~wLJTHlWb; >V1G"8#3}6֚g"WqR([Ȧs{fb,]?͞nG Hs<m84{+7idUL6fai̍fZ}ZTS@>d,ԫH:|tH!uRzoF׺9SѩgFQ?#zWp+ yh1%+̯"~ Mn٥E/% #4)='M+}6$%CgbҘ]q6N $%/`|H)Dߴ:nG{Lt 練48hATREJ:TX; yQ&wdA&Oڗ0@|3 Q!PńO/mHV]gb*(Fm;ȣ4C9Js(d:jdKO9M ln*=Jໆ9%7^X?w1'cTق 6D'';48maa<i%P x:Bɯ"6S ;:.r3):vLfLr$_[HklSOR"z$O/Lnw8@5O_˸/V`w[RAw 9X T!qH60< BU:NEzJ }ޅ抇zzxq_ wxzk7HZ%Wa'B4a ȸʰNH\U6_Mt ^Iض* nD;= &vC WLV){.#d&ײL%NSJ%']sN36pҶXy0֣ܔޅCI5nZO$45@r:ahj&"" T?pލt:)GijigQ8z秊rBʱXȽa7Jt5q]XٳUiTӅ^Ju(9pb4<0ݕNb.4!GN770YD!TFQa<( Q\0 +RO(¬&Xd2n5Ʃv2|Y$ǟB-n; N ?z5on@P yNJq,u$29kO12`!Ž/%YN -L 3 JK:?0u9 %#1pNnl}ێy9`r$%9xBP@ا7L7Lv/fuhe>C΄giOM7#:'ɋCûxSAvXk%P(C &H\SNRտ;X:e0178OkV_<3Ő@M܇PIDj ),MZgūGBTz =2; E?)B9P&y\:Mo0aeʽ؆)tEk)f!s,bZDӭ!@H`vO;kPn!=td۷dJzs0f8gGijk8P&B9u԰bgs^EE&B% OTIZۀ?Uz)Ǻ}O>|vHO9d;uDž`Cq$եKTs`g6t'FG)jzwu{82#҂ݱ30zI펽5[.:5=0;K".RKN]6ZALA. hPq lKq`Ns<;3Xt*]F5ce(4C\ /Pk$"3XW,vIP!^%g S[۠>ۣY񺏵d^wiC@ ˀMI#%!} h3se䞳o)ĤHՑdaþ.ۊ{#GbXA1Vr1"Q'5-8£-cr8BK[IZpɛ_N42u2J]~ {]ԍ$??B $ #8|_f֪w, M,.r4ڴ$21?Z<%i8JmV\-YzT4G-*Q;`BIK'y^44) ,FGև|윺?U?{DmNDYJ M ٶX4lByʕ|5UhBF"[-,{I:R!Aq ہקh؎X".>(L۱@>UCSC[mY[Sz{ w JMLvsIjQr2@8<=X&%ˇV3 ,st4 coy {,c'iY_ҀYXjNA莔8œ׋U8Y$_0YbW3!Emw.@L6es]GJQBS+ 'XfDk˩쭫thD/ A/&HD0ugY1RKzZz"A%eE鱁i輂vd>#IsIr(\> of\<ԳIKn-V7 W֨v8}ҕ_zID8X>xV_NIIl44ph>!+zov6t'\!I] fN PܱZbE[[9wZ'3UZ5n8rޝv_i#E6B61Mui_TfqA1Oǫ.zI aPB}~q73`,Dd,?VNi?,;1hpk<9QԿ` +TگnŰj#|/IKlBӝH/{@$I)kn; Ǽ0%HǐIVQJF(Olӄ%w ɀqb}}A$9k@ec^Q.b`=P_ @]\`h;K}i y=Dɒ؍ةba7=or3V.^`oZm0iN4{$aGio3D\rK '(&yh}8J;$rs`un{(r? Jp)-%*-W'?m7G[3/o՟p >bhݺY_s5BZtr.c%Qxkͯ@1sfƛS-]4 Ŀd "̃"f KwfN pZl}n"rX۠6SP[b5|!1JA&eHy`Lj17VK$'BȎb2+28Z7kg9i <@,)2%}63{}NۯSZ',x/'#j #e2OT*˫:cy~890`7&:ج@3 S,ȉIB PIB920qx3 w^5y$ ek#%(ިɟ@Jf u= LuaE0PV{vkJߺ@σquNU&OWeƴ|<ůn0=1y̐0U2b"4٥!Hxk8#.!ulI`왰#l]).`0 łpODᴐHH Ol|V*=_Qe}qaQb|zqBkmm{M߈bt n:ǫAp5F|s> 6@IYP\ECFmˀ[#v*BMWu t4a &h̟OY9rβjd)ͻcPԒ8@4p.4 {r m Ԑ۞NAr3j9YvAK%4OX0[qF(.B'fRzR;Ki@cc`9a!EHwX_\off*ɩQeM>)<`'l3o~b/XPOҫIwB|bŐgK\S]U x=ὤ%tSeV& 6ud- ][VrK  m\Xx=ԇLuD.vZ&Uptސ#k!Ό>A;PgAqCY%iFN$rrg`!F"oLuBb/g?m~.&.I(IioAS+ehuccE]<ɞҕî!gBk̡eg>"7@gP F-$Z04+Ow}BqOtI[j,<`X h[3`&BMVQjߥ_RzN&]3m F:1pUR8X99J4.ܛ_(<>Ѡ Kz'PE.Kޭ!UNF x'3*I}X)Q"UDT_<4Қ5) RiB x3"TEr|}<QM&2S:>b[yC!ePR#e{ҍEg7%+ȼƏe#n)IwyvͅmakZ{4mnxdP,vi,!x>Q:T C tJͨ8X2Q<!]XBF&GcytF&6J8-4#xĘv~B 깦uBkfT4l|G , h8਄5'&vGԏa. oLj,'""~YVzYaƄ&ܹd9h)#.-6}ъHQ]8MR0k(Ԇ6 1 SV})K w?2`ꊭLFXSCUkLP)^ ;aGCq/XE[wJ,p>ОU^SUR>T*-F?!j igKR/>$x V*cZ+O.' oQiQo}&막2(zjeσ8"7ݐi)*bd2"ІpyDJHxRp*|4FUxx "iE::ĥaxMlKg[HU!侱zA)<.~~ L~ŚFm'S# 9I & rmqMĠE7gb&k:sy"?OslEeʫOcW4?yn+f x=)5)+ёx#)k 62nJTfQغee[ֽp2Ǭ  !Ps"Ba!ʇc?Vq Lh_w.u4EЖ'#gfkͳ'#~ՖB?M J9 c]3H]d+ژ>񱃅^ /P) V^"zd8=^e"{9SebI{?tB6  , /^?%$h_6OzTjú4Cڃ$וbX\.4c ݯFf`E4Hj&0=pyLIyku< eV=$8.vruy.^8rHAPpwY_H3AD:vgqzi(rr~cIŷIfPd)u']Z0[Gx-:OI`OZ8ckSYfגѣvcu7D iI PCV4 /=b|^9E.K*\jS~]w5ob$uvWt$i mmPiܪ6eT R&/ JHҮ{VT~y˥㉓39!8kZ~tBOu(qO ~%M*}]6^ ;C; 饳IA6'Vd;-q0G& O cxQr퀍n$. x l.|ŏ(*:D(w鐯Wpv 8z7A4ڕ)`[SZZ+ͨzCL˂b& gmf' N9\Ӊm| xe.r)l$5Μ+٦y8>_QXZma$Xeqטtq8cTufe /Q`z;D@uҁ]ڀe.wd;+tUD<0Р"LUvg+@CuKk2Ѫ>Aҫ%Gֳ6A1go:a )0 Ql龜,U afnE0mJ 1^gߎϋuN7R=;ꪇc*~yi16(%`E>CSB6 kSR$$Nye}c8\ igyE@֘Ubԇ-)SxDh ߐ{ ? p\L٧YP,׾QIA&I䎸ʚ~&ݞUh(iE&*-r*]SaB=+Ko#]w{c+ɖc{ ,-7'Io.+e/+VniV\\״ >rc3W˰1_*˗F}HF~ Kǥnw +^֓r$yu x%&^-K8Js~U*-c,lz6pq=: ߱@߷rOᓼ =䀸\ TA"C^ٴv((lPl$ӌ905]}d/()%AA/ s =G\YR r7M7Rj6T>4V^a(ݗu_T˴_g$tP3&[HDdB\U#ǟ?ŋζN;ra.75{Q88G>M'3.8Ztf&8R2S&Ơ_m#՛*TiZ7pgy]5./Żs )EeH6,"xt7/e{mQLzH>DX FIt!`zl?u(b'rk8u{(EDicjDG g#.<u@@rU] ֌ɪX$ fô~zgPsfo#U1 {WEͪspLu%C\D/=]9(ānzʗ~,EO$(z?=d W]IIV~Tk@]m@|3|ܺb9̲,GZRL ~θew]cir+ 7X{ M[xsa!9de{)[CEI(G;x 9DM8 BD7&s,)k_ dƭ*Ž2DGu[i ro6㰿.(#nao{?bXo0ySٝxӘU>+hsSeaR[o(/4T30ŸEт /O폂9<ㆿ߁Սa z5307s69=t^jjY:B- |~)BDv$ϙQKb/@e@F7Fɑj W<1vpӢYn 9Vx?" u*:HnG1cҀv+XۖUhX^ 9[|wqly"' 'u` gځ<+ܬi:Ѱ-t+ir #'^̇\z_էIsD{i3C&/WAL-4k/xH\A+1._O(4`ջQ:LLAci6M}铞mh(oAZjIvp;=wd6' 6j'KB 5)P E:=Bwc;ǎ]Ivڱjc;BQ: :!UqtABڔܠ\R}AH[OEgi'@nf,#0I풣wͫGw1QV& AW Vטݦ4;6rim3'~c "㐩D7gX1G#GB0JStoYV0}z-3peDl-+q.Bl^Q-aGOF<1g&:n,ցW`j"uVjtER  PX%9Q~<5}+Q'])ir!W9=}#佬j;pdD-s]xV,L >xyfxѼ*p oiV^MR"f@ci0a6Wwl(K"zo^r2gʠn#;.M`u?:ݟ7 D Dڻd4*(mϬ+11,"!a4jDYފ,S] h/xCUzUT9UwN?/\X/A}I^Fgč7%4^|l V&*_2t_?oʰS& g?7CA *}U۬&`3 <^:tKvcO, c+.v{05.g?!jk9;(:_-Pq|"<˰ բbm] ,DVoA]~ Mxh!d_-Ug&\%S(AB韢׹m!ؼ󒔦NOYmۼ#FTQXw֯ɮX{|ojGi0 d  v.GxC5tuAQ-}$8U |z=2`kUu;jAۭ*\470<;Bn`}h|3^I}Z<'\?hfe`27ymt_6=o1UC܊/RAxc薶o9(׀+J@eY./UC&Olc%KʌOS>q)cD4mB9#f,Cq (o%ʊt4\,o=?2užfzwAD;Ik<mvJ[O , cu[pXY2Q^1(}j]%mPR/#G(jM6'V*+s#GMj҈(H_DHB5@tyhod9xd{Y"Џ©ÅofU,cDe,RF\q5|%4?ƯOW1:h˥ZєzC^ǠTN GPR]'6!نz#1Δ:,LX@ɹS6v:8zm(O_~(pi !#j",˖ڑ_~O꧉cuEЭeB=(Bڈ+ AL,`l1=笊~7]~R 'R6!N0('-J@ʟGeT7>څd4m*u_>UM4Y/7h\b;!M;@bb,|J>OQn@ġϫڟ_6ZsbqG4soѻ8v?dELEzd/}Vҭ(8l̿<;%Y&wT)VLVjAeHc}=a2Ct8<éHJC@v:8[2/ף$џ5˿S \^e)(qbUTqMeev[Y7{0{{[V4τLt}0O IFPWB(13 V݃]5ΦG$:X01m(O{M4 \} c؎ :@b7h>brI Fas.ebVtTߑGv~Ijy[.,@d& em17n3P ߥ"9BN:Ѝ&/qG%0՗[_ _mt Z{XP96yFgjcw-6`C,^nsiМyn"{{U}ڛuW_[Z>r=QMbx]8fڄ3H 9Y.>Xd˘(\B@RΜ-44+K*$~A~Bސ,)L+khKܶmoTpR,@)6[@}[7oRaI28bI-ooFo 2 ǁ<9%΅>IQ.̕5ZoE6!&YcYT7cHxJ1LPE"lbx,OvU GE7Φrt ϓ `ZЎ|׏yMaGA3mj7'B_76"yD .'?6Y)|i`7E2݌{X)022x?ckVB$T*o` oi@s#oQ#=dp5щm{7=k;wox V1]5 O˅1꿁W\ԥ lWPA$(/0}+c.7s)_L>D_簞df U-GE͹耰LQgP"/L3,v_^9,uȰ)/4Y%оjpY gf7'MV2{-QPcjܽcz-R "s lH#5h)ѵP ̽iyNa!ZF,uO>h-tv4ZQbr}@o- $r>88$gp7/>m+ϺǛb39i!-|ܯI畚%l#WhV*@D4mҌ'r F[gțKGo_MU PUJgrC4gM%zufz,p[( A/l@'TrJ{N𑆌Lx$ @^o҃#lRi1Geː+K+`ùZ D#{ XyS 1dqiU_9 0ԙe2?^W GۆkGp2K/HxX>'LΦ>:.Y;y^ Up *[n?#]3l|=Ɣ\dn j= 5Y#gq޹;Ժh5^ @a; ~FZ[!Ws ꊈcg˼~Iu^5C/"š`qBhm,g +J1lвѦ7jq/(Z0.j<"ːrX`~Ju5p䘖1MbsaǛ|IҶL9]?)hW5ULn5 =ҧE I$AA5*6m1lwMI>]9_$`]"}YEQ!Nb3P.mm BX|R.k/ͪLϮlg.gm?h %+Y_:nх2h@it-z R]W$-NLƺoJXh7p$ :{A& wз_ lKYҿ%fc"A[&ӥtv9WX̆BrcdʯBc ?mߡ1 vOg^s>ۢqcFpQmؐ*rFk.)!6 tM~)s$ z?xix=NST6_R ;5I;I~.:IGЄ"bI_UO5]l ēly] 5se+UKKCR;ps. BAFRjixĪob=mxK~tV1˰:W4_;ujP':ڱ,- ,!p Vm ,B'AI[@(tGj aT-ɑf[uׄ 2;ϳ%{OL[dΔYãTxtd&iwؑGcȞPS#vbN'*ͪC\SZYE(kXP3[6vI !e qu]U7'h+b#g4I'y?ڴ$Au̾2=]^G,\<=S &@$sBS[aҗ+ć敟&*vz?n8j$ifpX -p(ӳ6KfW/(-HxI-'Î8^txJ5J*E'۶8rFܯG)j4ۯ ]y 5DsHXy r-ɐvvC4;L V)i{MB5\ͭ v(WT@xx ŊM ˞h,|]pj۵mw 4a }@ ϡ%^~u¡w߼1AO2xB@A\B͗׍5BQY46+zuT!WuhW8aK3W'"7Z5v?ٍuk)A=7"ug}Wm]>cq98kpU"Ri]D[IHlVZ7{xeBRa$@}Ѻ߁d-~,@Wh)&*FQBm5dFhOfMy]*#B{YHTDԮ)<:;"Rm?X5--[H_ ڴԥ}R{^&~ML#ݦ{%zJ*8a~?rÄ{CW@07|`\{9$xႰT 1G| nKGYډ1q?$ԄYKǐ1ob)2;#cƋ{v*8&ǞiJp+l_v~R%2>cM3Qѽѡ'R않VyVOvtLe|p3|`?mi|v%Hc Ӱ{TBr*d|KOBB[͸KT xU|Y3SlbRYʢqy=מ"9)׊W*1A/?%Q&(|mL圃bfRLz\L1{בKɚx NE6^zwQ^4 Sԥu$aQuyJouhpNt^ˎk\D`4w[XVj[Qm xuV::rU7+ (̅A0fI|wFYJ> 74U&e&a2զbXaϖ;FJ>*`P;sGfZ-FIF͇D uU( Iy AgAP]qLi|G}$NOۭSBj_ A6J\O%;L-dMX097ɖ L }PA;QΜ_(5æ=LvUv7PI>T،=xcG](g zb:73,΁=NM-eчc]}#vIUUr\4yS<؃A5N6v4<]!+KX6~"Q * 9XZh z& (r!jEjR +cᒧ3EKڃ' otM@Iv VAYjy&]QDߴ> jiJ.( (RquuwB!p[ƇUm_pn'O}AI^8HyDBl fն,a%[?iBKlȓ!6(pi[H+Φx23:+wLE:h"JW'{hC~zۍ4^7G] "uc H9m%~⧾Aff(sܭdAq9 =K8gYЄ@PTw;M]=˘tdLzd7Ο3~JHԨyfu!.s<|;5!8pCrqU"p/N)$睝n-Ύ81s 4DZ[ifOkh,׵|ΥTU@5<;lQ-KM&RnȋN:x2 J@1 c^JvH/QГ\h};1{wW3'!N' ŀ1GFQ2r#rP&?0]7[$7C`ȏD`kG8 6aiͬ P\wk2^89m]㝖.Wϓ. gQ=jXaWEp8$BA{le/ dliQ- C'wTG 8uo=hj@rDT@*YEocsI2"'TJv:cEVR߮UQbzԫ4gi_M&x 2nX؆|"^J8.6oKJ4.+ʶnl6@%Tϥ`RՅ:9*h,#;,dW214|Al|K!qפ^rb#?x[Gxq Mx h@T ZW'+_0T嘫k\sbbε"^zk0\`=Θ` .bX";Y5,@%Os(,6i6;I[j:6=0\\$w^~ X^[T߅^z`_fr ?;afVFjφd@F>W#Lfǻ0\L|> n`u Ss9ǧ^;OB\]!x}͙<;7 G|pmd)^߈\VZCx JL]}\|#Oc)ը Jo4弥E}do*.*!"ךgZ~^RBb]%fDs9;j(~R*ʓPcQN_a{5`u0v΂eMGSP &7ESM 1ݘfZZ# v~@a%AWҮ\;pDX24JCݸ^vni<iP*K0 e2?m\#Cxs7дrEoT԰7FG/cW€⃼=;OeWDɽp1`+n1nR+}*(}>. vHMI.{)Rxyxl`Q/2 T- $Pq>ukUL._dfơKȾ:}fpk9)_ 4aڤLP(m^$E4jdIUΘqzt2vUǫd&:n,ig)dvT)z_j &TmxAE*dj@bn@ڸ JSvQ֗U#!\O10RUnIf 9v:1 N,ɴ)w!]l HƳ~zbTNG`\u3Q)y1lHNٿOyA7W+YcZ*QycBrA d0h"HL &ĔgV| &`GWʌ_C $R2gB1+g,t>L/GLg = q+D{w'yoP#jٴ44 [N˓mrP|+7lxI8@b6eBM5h.}7bHk>fՏp4 Yr!^@J޵r|&Þ:YM2l1_˜)f&A#EMoKiclYm9 ,?ag۞z4Bz^_.Zd&J2:b/ߒYӝcYOmfz04q] ʤ䄰hmsA&י0@Fh!m0jZ\u2}sSTo:G)?agDi7)R[d۾3Ƒ`UwS}kxLd+4R)c{LwU]Vg:F1m\JHksJ֕sjn Ѱ~5=yC#+)6U>鱛)gtXE҅;$6Ng3~zg;ycǾF=ݬX*[!+86}~Dê3UmAf/k~Dijӑ!$oB_ey4&bsVރKDnKb+w +_@O&£Of x8D32>\ig1w+EaٜXOz/JO3kͥ [\zTYQd~uXc ZIÉ3NN|heQ{nطh+> 3 ÏMYjڔP@Q(P2ʿ(}kʊȥ7MjIS|U:ĉd`6rvqcOi8 uD SOy9]`t_u/H$A3Yuq(Qς{8 5Ue{ o<:~Tb,ԙ'Xmd=jjgkZjRm0L6رg( \kPcR?WiU<Н<͗]3>S\-m}MM(u8j^Ѓ5$Цu I1Z@tSD}T Rlw'<@>nSzi{EQ?eC-L6|gYN6hE-F,HV5+<&OR# Z+N੘Ȁ1PGk[,# +{u]7FmTt>dQuޭ fy~kU!;Hx )4-[lpCXWx26 r_ ơFʚ/3, 2?!|A50 ٖ qfdlH- MDI-0%E޼#ĖČ4|%*o) xyaHz 3Da)p}j'`ްSS3QGrI r" t%3U,L׍ y_~-FosxF1mme K& Sep paTi>hB2v9Q}Bq2n՟?R$| LNҶxCI3v&>4dOXr=KeOg|tG_gI3hiĻ ?oImRVK]y2шֆ=}h>kH+MAk!,>w X0>#/\br 4jiҨԳ9_N:ߥlCt1l("l]jXU x9@ݝic`jV#yõ?95f.@k ,mz/?i}'B/7wsw6^s '|Ly E~bʵ00&GދdP\\BmDLP|$b3/A. `[%^Wl`߹RsCFrueg YejMT7 jk]9ˣ=%utYfуg[v<5g׎ЇuWɨ+N$5`gUs(NI"๚,ѐ L!}!7K>(4ITM3{$P13XKЈ}5*Rn 7?0#RͳGաqC>(Qݿdn冣UkBT]vnT156 UjKIw.Ef 6U5:j}A3"ۈrM" XM>}K5ar~ o(A#ܩJ0 T56J: -QےLuNVE^K?إIEzEBZ~2-U$Ԉ<~@<8WCm͔Cd' af>IGKϫ_? A8u[dD4S<@ DT/lwda,)[:Gڂt17p1= *xع3M7I/g:$rqGMrmG7ʽ퀐au@j8:3}b_<0͞ |6$t# @M 7Aܲw'x^\uIʙu[8ޤ/*Xh{ek'Z gq}Vhx|5XA4/^"9Ƽ-@M~ָA}J_İl WEq-7yC֛;O瞇в2KMAi&i_|rt+@ʨGo 7$.#"#d1%Mp[(f-yoH3dž[%'eN]K3pδ+H,4J3h0Ϋ,ʆeP~NehBg碄}E@~FɾEݹ4Vg#J,5rVL}dU1Iϰe8zkiȥ~,}6C*]O~5֒9ըt8+^/mM e +Z ka `hB6Oܯ-buv"H)^Q))uh74μbk " ߲rxܲ#.[8ga{S|!#Z +.cm;sHCU9h[c4&;l(nq%0)sES-kC DjS1σA?ZoPi e?wVg)R?2Re5 #DhVƑLhNօBDg:hs[ԫ%]5_Ővhsd!XvtP$& 6PN@<o^Tj0U@8]Ny֛8CKj^FS54[oM^Jrb?-rA[?bJ-6wܟ \>M2#"v8/Q&>[ aE^jzٙnR{Kg"mX7V]þì;n֭iT[TMA~Ls=y0|m!(@aha(jf23 ح1_Džj2^y,JHG R5άWk39,RߜUЉ 'Z}^9JYu~B⊱y}/m@'OB QVg1҈xehћcY?Vfd&(sz(59XA~T9G%T,#O}DUʼj~NE^2Y(zOAgCoI(4|ݻ" 3D:m_jR9S4wS$0\_{4Mk:!'&Xl1KmC儿 *ٝV^QC?ut dq`Mn`i"SB)ijh j_+Ra,-O4*NPk͈K°lRױ ,15,2VXn_̿J>h8ސ.Eٲa`#nSMu*,M@-GSh_W@K[OB@,l0=₧U_ 4RfٓX2;Ce%ջDsmA,O ni~L%r 8PVi;q69\n.]ˬY,R?GC,Ml8YƈdRz_pMJ5Wa$O@a6 叟`ZtB7ciDB䏀?ȐB|9j gc$bܴD[2~& |x !6~XVkWWMVMA8 ts/%Sˆe|0]첗*Jk/mh i:@An|c?m:X+TJ%%:ĮI#U[@I1;0 P[gh Rɒjn,DPm'/-6bN S㾗.Z/>S3#tjk~"dّпFsdR*mB"}sxm得(˝ڏ8xr"epưclR,όl%h:;#?ܗLO98TNK3oe0fh3ch>SyV 聅lo4'/uP~ftŻ'%7QG^KsBf/fCJA[\A!G{-R6*~7sRY9*oWtnx7Wrt`vi7eOcO߷)U%!D.kf7EQyOArJXW5Eģx(9c/; YH\=k-| G\14dc) U e3_]>_׳DHDw /H줶e!|7#A  z `(Ƙ9||m(RdzbSZ7a'DYhJY%+ptRfvG9+0$D0x$`äB0ϔNqI}%_$)X-U(U9WuŲwO你BJ5xrĀĎR|biB f ٜa:|䖭Q*22JG[e}B#2  6n`DItReNE bѫ|rfx>fx2(OFPAU O̥]UӎB]36'"9P@ώĬSS#͹ 򄎑}X&EugFkWB"y\rp;z:6xޟ[dfBu[`S={r\<,_%<Fx71=}yMщv@t7,I4h|)Y$;,{Jsg CgH IuiTL2CWv}NUF[ƞR$ lzX+a|q"~n Ҽ鶻A[{ =r58*]˼ %zRH0-{>T)K%=,i]yDoF?Y`z\u_Xa?g9O {d@Pj\\nmXNk^嵈AA PZ;Nu;Up$f?J2)+exvyt"2yȂ&dY 9݀k]B;"=q;sOgm:/^5}Pj44:<n˝4 {zjPi,.z y[(g3ys Mݺ'y9);Ztpz$mE՝Q&KO^l-ڵՕhru^ujEg@=iGL/ Qn 7ڻ ?.u-kuw.q8k/PsS>m+D:$r]H`C Q1Q=K̼-&E\} П|!֌QM+RASMz23o6খ ޏ<~a%Jj.!R7\;~̵`s4H7mR{wȽzZ?3 c&hݞ Tw8T?Vbḛ̌%@զS`Zj{MP +\T6a $@.6G"rOF>GuçKr'턷OA C2[:F3_n`V&?Jy=6uџ1?R=RCL7v&Y'*j804vJZN $'G">%Vv7PĘʻ7ckN dZOA xZḥðq/SYA`{>:ˎPO|јޡviUPYgc?,!Eh;MDa~C]N?ֶk]g> z3e Mk>_)SHɾ=P{or9,H`gh-))1\:1|ۛ!dzDv$}E1$JhjL7ѵ5>}Z' PhOF _0Op HDƃۛPP ZwU2 6{|ZwO) IA}M9 v84]: [ O4z\0MnNv&?p9d' oH=HSQZ^U!bG$9:^bjJ8z3:i,Er93hc5및= ːLCl% P2jхK?BئNT"H&9@ i  3q{;H ِ R?-aAŒ,g͛[x2ċS_V^SW G4^0dkR-jv:V%?&3F`3AYѪP,i^+D05`OC7S /3#⊛^(5yڍE_!$ %,GA/b{Rt>m+aaQRՖ3ڊbZtm谁TzYQ3e,Za zܖ_/k!ގ-b= [I* Qv8?ϊCPԅ3*?2Zu-%TpHMH;"a_l\D>" j#>|.yt 5pͦ w|j"z -Q ^1Cs!oaeo =59~~{Q\.76O 1EsM7&zȡn䱘yަV.9?w=M9X\jmp.+ԭEu!}Բh Qt`T#DS1vŘ=}m~WxNZmL3aJ 3B@|MH2ڱrw)"c7"9Fa ,pAR&3h9&2*Qn%[RQ~V_vd/Vc[(іWIGsn;zѤ7+k> V)1"}d4RΑ0oq@\jp^Ĵjab;iQNggy\m]x|O h6R`D"u_mgGD.$4rj#'Vм-$c>b@dVƾ}Ii/B:p"<"3a``ɠחf-i<)\I=pv=$ vڊb^>{Wm~⏃Ҫ[|Nϭ]_ae#-P7.G+Xx֘G=Vce0Oi\bV 09Tu0G*A%2 5zP/eLRH{%"}Uh bۋ|k_3S2sh ˻ 7cuJ9dc ̄CtCUX 5Pr5UK=RODqP.А yGQjJPφTmB <5pپy4Bw8BmTGc [F tA4[G=gO˯!3*LXt)g)roj(VC8v~7TdǶې@#W?~k[P aVڌ EczU6lr9r:@VB$T*& jlk-Be>kG? WuN/!I&ؾZl 8+'jo#=@{6]X}+pDi?Vp"p _KڡW̗)pZ%?:fld#eW=*^9*weCh罀噑SgU,w<1hPNBkD&iYvʙ625vC?riU/\LƂ2@-~}'w^a 0tr_3S|3:Q ɘ{ ifrQ h_\ѿ8x>D+ǖmV'ok\X e~g]#2WH@Ht8P]Q'8<N6ԁcfK>JMILR[(ITyi 7V?`HYLOR4jD85x2v]vx6K{L:hstdp&Qj4>AIjiL1`:7KV0*m#:pϲoOD QjQ)"hlVɎJ}_g9,xKێCGU'&,e sh X֕Z,ȁ|a}'!PnYPt ig̡tskh.}n,eBZtSjŸ7:6Ye"˘[jg%g+@̲YCPGl17xH6E HV7lnE~aݚ&pY}XzrI ZKhvֽYI xyʎkM@1c*6QbS4$9WPM&AVg7.,U쌍W<҅&]ý@^ $|%^1ɂĞCd4x Dь猥`{W*mA# r=jAgKWU.,gdޔJGj#㻻EisiX 5Sjڊ}6N9֚[*BFGy`b:UfR>-'3eދŁۙ{xM{pJ}ň mn#T8o͹p6nVxc:hLUΧVmgnt @?A.J܊8`m a%AU\4I>T2JrO> Xs g|Vk-WئٷWČ]PG2xj'% -qqC|kp]0V(rr]4Tk#veB*$`Va 1T=_^Gp?pXQF ٹ0txXnr᤬ݯ]S4Mlq͚$DCY9f I!(p5ߙ|kPY@soFY^TN)F*Ka{wD-e}mY XEpD|GO(dliOm:QΙyI] ީrl`D qLClK6KƉuuaH UAE[nsl- 7,hsy5ф7{7UEޮ9{unN\gS=}85w8BjC,m}h%=bn머مäLiq3du17Zb8?I.@D&qU8/˽ 3$;吊5xb0HTkSz'm5n̦63vẙJ\.Cj(Z@TyTMr$V.&b]_&jO yAjvFn*Ҵܸ@ طam8kTDAI[gq[Կ`!\wIG;}p*`t/U^d5eX.܇60WT.e^2ަAY)OmLF`ue6C`MR]iE V&-01 Ս6(waR e^-o^ѯ8]%oL^:׉"P"gGB5Dz; w4 I5 #ގ#0B ۠y(c!ĵѳF+<]6TdI=ˀk BPXC36Y%!Ax1M"=jJ?8 #BLEp(P> u;Uxq®9K*74Xz HPҌ9)?YJ tRg `SҊ%ҳU\%@^2ruxqۥuNjoB\U>%w6s|F#-=j""u{ӈ:ܦw.ܮ߸0 ^-`i,AB_B5v}CaG2E-.UFcŢM%-Aٛ;KwzAhBwڡ)_XL}G@(Th/iEpHu;GONBEd:xZo{u9gZys.{;-Ny6H!o>vs"0۷EɈft{`v=Sw95ƶ>JV0n_8^H3X\CAdw[JEA'y-8bDRR;`-80A{h1Ώ+m;\st3Єj0ٺeɅ10LN";"RxvتDlǔg(>:Kf}Ա;YMRnW.nzXtdճj#a|{E58滑 .^*ep%80K+O, Dl*!e3w$% Fz]F5mKxP6N0P#fgLSDTJ躗{D[W: 9-U[6[{XrOB>ribzwqV:{Y!/(hl5x[T@;m1"<Ͽx P k^9,Uq~ yMSYQ7F0~8qO CElNԲ]{s]B{t,riviZtkGDrz& 8AOhyM$%F^6ob,TVpP&j>fcbpo ԣy3*(Ġup Fa,F,畚:%n*#ݕ:r0,`aNv|&8V뜾/#$#A: A)4᳕c.P}IjJ|6$]j$ZݙKK .4"pj"eqDW.2y&]s#Qo`9gVVA4Gsw .cޞʠx1h^1cX4'Dݻ%">Aw KJ]RtpdH r?4x2 {npzzW?jApnKp R 3iRخ>O[ C[0H(K l ?Oǵf|Aˣ)|+xvvϝm )j)Zj%N;@n5Rؕ$'٪,"-a ohkѬ_ݤo{_ʋZ&?78"c 39LoHzW^ԊpR`y; پZ1NҝA] G \9FGq]@yJH7 3K۴УCqS%A$.;=m2ԽB&->VLйE(gr7ۯx?'47"hEsWًIݧʹm a4x ~TޡE#J]׫7@nJn ϋڻX(4^|N9̳BՉ{xe 5r:R+:D)gX-5iB?Yneh|?Ea9J]-5rWRt#D|>-2#?DLcF"y?\zVe /ѷyUZ  ãP%|a6GAzIf+P@oLӷOˎ2ɨԭ`7I'H<%l>\M"I R[e*+zBC̨}5(jf& < pw2M'/W8d!#A- w.zk91K eJw0vn#ΤHFkoړ&VqR؝*;gtNMѴyƻݳyzPwU]&6ܱ*. ZlK+9xxMXwȏCs2j𞻧?5&Me5/*)!˪<U!1.IBgWU@u/rAKۿŰ3+\^䬆\θiUFr\n|XH؆Ԁu1{ƟG4-Q`,^=MP"n/R1 AqMhcKf¯tVIf2]e݊^ߕ Y:HG-r_`O{cutBm/KLAot[7se^ҌPgOߟN?L/ xw:tX3kGD"{"q-A`nfhF d0(.TM0 M܈ UDS? l e.R Ǟ&w1(ͪRef?ynXJ5KgSGf1?$!qmH}1!Fak3FK6sS<+"$]UV)߂p[ H9d-Qc"\' B+6xZi{ν-YPB}YCP\f]eOv|DoȷeΞ!gdhT`#4IH> AkUrb&47Phw9i a^4,Fu}MmO=cja݅to(?E8*Ui9u,!; CHxЌvwH?`q#D []AjG`vfV {2ݴ!ma_ q4L}X*5"11IܑpjL!kt<͌fo)X* ,I毳+ӭAv8F轺1$xM4-ی|97T)Iwr] MN%}PJ,Z8gƷ5ͭE/2#տ<ՃKXoql0'U~Jn[,R;W U>JrQ7Şq vYDnCR,,9tV8}3f!⿨8d%gD5^L{U٧tr'(nB"GNfL> 'Ix-^UPX1tR#ERCKCO2l'`sB3Xp'T:. :S_{]r@Vd0e2灋j`ĝ[m+9GCR;K=XU5fԭ [S=VћmjljwAژ@287tЌzy)2Yk]!$&6z6 a{-Z!t~<>t>HQMGz[C7HtXxSmޡ3[ʔ;EZ@TXgF д%Ha+B9v|zXnP 1f(pf2z\H{s%5ƌ؝ZPUCṣ(J°PD>*V"CuWfԪaJ0x˜TXmXE苞X /۞1X\)Dphݧcâ|UnftՀ? ͂%0-CONպ<*y #UgY,b6b:KT=o4XS͊·s@AQ8J UZ ^Po(vnpGf.%_d*II Z/p /w)wiCB"j4C^=2äݼCʯ;nI |L 0BM̼$oRd:t _71'`pĕ|pLuɒ]?#Q{eH":5ؔLhfZV-pPWm3e1D}%,(TmjWGkV1=m?74MPӾJI3xNv_`I)]^v.ş^ĺI'.0""*|ߞ/xċ~v<&FE{aU1,ѧ68:qJ1w'uAR~st>K<kZ2:$䧜b!>1g0E!y:Z7O8 '! ɜE'h%ypAi97p22]6V3ۏ$A5l{| 4hQLm.BWH yO 4p[IrY5 '[E:5>S_+i@7J/A5(^}gi5+ (h^Ǯ.|&ф~29HkboCqρQG4Rz:E)Z$/DΊC4Pe_gv`ia;\ևc |.d^Exc <`tN oxVᑯŰ*v3ˮ&W诪3O2_EPs]rwwLJMxRsWVuQO"^N+EXЉ[\,K8b:[$h r$ʵZQսZz?FS)W6Ѷ* $ \} e|0j@WLބwI1,]S0> (#h'HBn ~g>/X(ѵ65sF~w.̐ c).d gϘTI/HH}M@n 38Q'BNBW&>BHȭOnB噴DWϮ[UVFgX@opc¼K6#©yU 99c3S,+v{5\:7f[FH@MIm" @KpGuDq=sRHa;6;\gJgMֳ$–8BlMWIsRvޣIpa- nRZivN;Q*XS2e:AӴQ0N_OKҔcon5SZ_2Gc  1ܢt*"*ص {']\j5#J ض~dԉo2[ Ͼq{ښg` LYT|rggt4YXlx Jp4̃RJ|l~U ݤz+@KHM;GdMjx O>:ƘvsaЬF,׍;]džb~31KTEX?([W̞HEt!v&)WٚhUy@' B+ [޽K\E5|:?q *;-ڡcSҽWd*@TsrOzrWA>ʩkzX,^$Ox}ZKQ$[sTC0jzaT ڭG~+w76jŝFn$<@OQ 7Nz`$*RosVؐs:ճ-a-_upfN8vDn@ |u "?3n!8סOVanO…D¸:NHaŃP 1=cb]x"g/^ˏ39oqq:%5@ [̜x~|oŮ/RXPm$6I<t[Åj\)Kܮ؁ߢ$7 py!T_ȵ^ Dž Yxn1s鵥p0gL $bdD$K⠘L@,Zf I,gaWؠpĉn=tEMEYٳ:nVB>!'zN;AI€үV{[Mڢ۰qe zo#`$=-qAч^{,] }0nnsvx9t|s̊,Zڃ]pqa ٻeAR>X\q +PPu9w3u-2!Z vn"UIvgZ{6ނΌ97tHF4aQ*/Vmu'M=F$cm}0Cm rS+)Ձu6͕C VR,Gct])+칣B˚б*gBQsexUJ}.n3Co2\;0 y+5Gwk G]tnNÓ Ƥ7 l;99G<)C+i_фRpb &o \<ݛs-s(kj[(>jZ<,ktIrֵ=&nӳ{ak;xpJ*?CTDB2MH-p  >"mFeB`XU|QEd*ҊGz8ՙcf&ө++@av7$FjfţX 9\ 7*C4;.| !,y3-x:!_5[rAfޘ~/ZGΊ=7CZ 2,iyyoOh҂BbJE wAQe[U铎OƟg14ӨZE1yK&CK]#>t^rOPM>ilw&,|ѧK6ȡ]X[ak(X5XakqGl͡Hͼ00;V.jH_qDT( m+g݄L2?QH:ntp?pf) aX266$l=K֗$fr|4A^v|IGJ]B?YtҿLkQ8:V#R@ƼcIֱXL!xKvAkq;ĨðHčO:YភdCL:2+L& A w!wT v;Zrex߇ĉCngsp vӢ2QVQ/鵷cBi ?.!𒵐{)6.+߹+V)K+,QHU|k :ܱ T_Xe6Vgm4) A_h'g]D٫hr2Q5[j+XцcE%oZz pQLoZj3uV+a [#A` m's@Y{i!Ji W/B%kqc |ӤSY7m%4-{r{+UPCqHҺ;_ ]ߤx8)c[ye8ut {<m~Q<[QH?JTƠ_3a Ty􆻿}y/ڡ/jЩ{ J|7#}(!\{ DeHy8GU%E\rom{PpnшFJD^cqQBX7R|N[ء>T&~!d%Z+đ|l~ 3;A! /^@Wj h!0IyKΓSBBsbkB|{9?ojhݜMB׿e6d;Ҏ0 lm lǗAԈltv؟4.M5Z8]Wk9 CBF9[E?uK!9:TqMボ~ڼ6q<:lƱ~ 4?M=oV劦u*䄎F3 1=b1(E29nF]D(W|e;*J-UVpQ^}}6+6lsW0Uz={Ì_oTcg݂8PMZ*Q)ALPvZpOP61𹸨wGCo=J,R- lX2㭟> HF wh+Z sˍm r5_bqt6vD&0W~n0iNJuJySU).̝5F ?K0;ٮݓY< Z QL}7o;CZQ=r 7lm7RB6X'pt0YfσM2Neˬi!zWl? V(jlKIor`YWf.%sƦH^-#D|wA|*Cl%=O99;] g@bP[:sD:D,HʖӬ_e_qtYԌB< 3.KJ `;`cVڱ W.1ic #{WiGr1l+&S,RԦ+vMՕWmDۜv1O OE7Nb `F57 [:avPE){mUZth6ܪ;>f܃uW;drymsGm:4 (rv32J; +žʕ.MΌ]0ok 4jZ\uX۲ uS `hTބHdgH]|R{IFZ-c'-h>ڏm)B>}Q4ɳuIMЯL_&$e#<`wJ[M|N"WAYH} Flӹe+FSޣ9BNQ',J`=-aZvBj E! :Xs_MYW\*v4TgzfܜN yxe}j{n <!j邰/dԲᯏO갎' w"*;/XyOP`K`+{k;)̾%<Ėtrs_6);Cwq@T7A&Ȫ]V&vJW3jwѲ 9$Tc*eo]/ WAfW2NAV_j^Y(\IWř0%96t6N,]`=~(.?pg]h׿@ {tdA v];Lꖗo]BA$b@M,HR@OCFvcI~{48S^3e&ҳ5& %GnuLA/zT@Y;ju&]1p:P5zd_8ي)9 E'bsNC?>KxIjR GX70U^"M!# lttnkw:HNS}8P))ʴpywE<`FTUM،TZNK ^r[S#ؖ՘м" ?=!5>(q"A)M3Hw_8iTDN< Ukl q8&Vy =B0J IK sp RH>wlvh=?FyT3{ioWpg/{_hnصTHXXe6\XU8q+j#P@;/L`UzwEZ+R/_HRN h~ [3 bXDpזRXq, `п4)Axl &kͦ@|+skgK>EWDȷC)ю>$H %Am_9.삻 hb o4Mux1w)Y FWx_N1xUZ*7 ;#_ϪŌ D4OҜz|A8-[A]ڣ^؛#%6L6[2P.:W1bU#sRoNqj#F3U)5xr,-hA(E=.ĴPQ%&}u9J`KހOЖ0nӞe2q(qLAl- %_9oJݲ-k h.@VbFao~Rft-Z{9fv u6%?ݦKK}FwǠiY~[VY/ ZU[y@Q%<'VEj\b|_"I.~skQk^Tjlh'/)}PUE3^PPd5.*ЛßMyd {̙rxLh)D7j8 -UKmdLAT[?-'MR'ViZS%%RXw"կnVJ`}Lq-cv0#u)o82JkО'Z:YrjI\8^Q+23UC7s{7{ÝײvRҳ`ZKS:غg'XI\I{mM,ޫ[|zLdղ2mٴOb [ %o8˅TZ"A,I1Ocs(cvױu$%=/ء-gY#eL2#zfzнiGLSOhEӄ 5h1nGT73="FwT{%ٶrܻ51_O 'f V=k:F,EltIޟ1m+o|Q'F;eo|[ǔ{ze~{S1?bٰ1EzsS;g`(t˱ރgE0p4ɜ>Dp-sAXX`-CSq >h,&O7(gG^U+E +Ɠ ;sS3/Mh1Go3&T~ 8 @('ݼ%zBg_x25vb !:@W:?o,kX9K/d.zΘp2|7M?ۻS(+g GxRn/!(O{^wABWߺ5oB[Dz).Xy* sSU0ݥDZmXtg}X7!7H)qXߌ!׊uߩu#$wcr /hLF[%`&uU艷 ӊ )n63?%$b舦/VuF`;%o^oBgPIjۢFG1yǰjLW쒋 9vճ Gd!rgb a%{usgwSD@A5RnP{2_ԹVЫz'T#_E)88} ǐX >y܌tf|O*EEg7=0vҚ=8dǸ r$q;~6|^sdV*V 7h71r -8ZNdDϲ8Bz'!l(6gj'Yh39I8qGJ%O5b@0z|&}l"z^S\DibN-hi=q{O[oW_c쮘&Nj]wFL58cuU>T%y{-ftDD7)'NzH|6=-< υ y:R{0.5CM,6&YV4s1A=a?oLK`6o"$V0WO Tk%8r*,e4q\$ptFƁn`Rq%+DqgQ&I̫zǬ:D1ZfQw[$a&u`cX{PvBmqW0-h/zrhw&]bd_/=.dZ~K9)Uň3AeEcn T|B`/D%~]aoJb P3 EEfȒV ߮;y2QP;qi@f0K*fQR|D ->* *F| hl)!QExF4z0bmz89;%IdJuػ(f:[1%gWwc6^ Z_=6T4O]I9 4(||P<]&5FU#L25ݽ=^}5܀ =T6xWRgqV`dXGbgeË(vKOJ gCnU`%bu c>6_` ۛR< q *,W^Q1KXs"G~>JJm2 / ŵj]3PYXVbJv-#ۯ0> -{x8p?g.͢VYzT=lq. \4) ͟Pڸ4n;4qHGA띤e2$ oNg5\wAaRK#1F!áW=p l[V#DwQ6mw"˒x1;`>G\u1j'(01 )=zKhldcT|9"d|`ɹru=(݉XX x)!ۭ5xIG_1/{*kro؟D|W!FOIGOdGنn"Y.iŷHxDĮLuWzJrF\dPdj( -ZUU޶HkGPtxDe{-"C1, QQxg;Y`fGR≓tk4sė?Me 1iX<Ry#XWS4z(B#^o "Ş57(Sk |b}3uXé^Z Yp{."zf+jI#?i2˥pIUrx;]65+9PF:@&i\X2.G2o'V#ڡ^6c ]xn0ʵ&4Okg@ڬ vC1 /*  -ZP\M j SÉ| g2ki9,@]90lPly_i8C e%q[ oE4ⱯG&!}䔪PmqYGuX:GQF"JP)O't2Yyj6߹luF .8X%l ץnzĕ룦tf .*00欝߶Wi hofC| r<>փ<2KPƗ(wʫ%[-ǛtT]a?EFi[Ӯ鿠*tM{.d*diU)c :j1!*ϱ'\xYQuUX+2+ |#:G; 4,oeN:(vFl l ц@v"SWL]9Q/!UR ^'R01m>gOJo;^ڲ\PǎfjȎAv)7(#\ ύXmG5u0TS~ɣM,5>x|$H"ޔ0in|>wre&;A|>y]c-KTA7h?o^}#UWR 7t\,Db4N }'̑!dK׃NGag$$x<8,,_j.ǙY΄:3wql'k^^&. k_X*<ħfe`r{gUlRnLc2^80Øg}"1;X| $;&1bEO1XIC7fcٺTX#H"?oIb:r;*pk%%u\ 2LEURxG#ВSUk9k#cQ:iʦcFA;. &Ġ33A|2{:q#λDOXy@8Vq=,nK&;쭪[iv~`.olq3C7K2Pyf7O5 QSaBh'#+R8$T('$M'c6i[G\zBUKBS̠=|8PGUke"? ȅݮYwvQ_DSȑEe=4Nj- SW! M,Xb] n+YI5ݎ`GP?$- ?Vn\4MKWN|yrW̧.zy ,1YunCӞN9SC(A'r(+^8si?s_|%q 97l#Ur3 E\-/鬳 Ay>@D(R(EC?@  5` ݼ)(mja0iJ7.^e ʁ9%ڪdgv,B:kZN/:ŶҝyoS]+𳟣OʓEn&9iṙFNԌ.0o"Aw+:[wC!8w~BVI+x` s&vBSOFm4d B[qDzzmf!p.ݬhr)؛ng`}yي12scVJ0t?h/}Pf,}Q`;_,+`zRE7,2]lGҋqJbؤZ]n"[ ~?J Xmr8d꾋,agbo?v1) apUUWgLX͙ǤBiл'6ۀQ7=B#2{BKH$屟\~tN-X-sY) id\I[*[9> 2.6RhFԓX+آ xhe$#r:.n) -wU._bNzQ2.0[/GاvpRٝw^Nbž~I5.Yq`}PiظpfZ0n/͉Mrn{{HO.?_pDvjMQ:F/39i;3^qYf5sMD (7\UVqxg`f5_{Ny>M{h^M"q#f;M9|hW9;-?oW TҜ:[ 0ꛬCrIT coP =CI&f)G'P{[ 3Ss~AŎRb? a$̇:U JOc؍\y' %׋x (UhIDT 2 z%&RtvP/nxRe f@ Cn|UR+͸cMii"i»[$ө o:\(o Y..d/dB.>4-_HٍFcƿ /r^[AKcFb!HW?n 6ZQc=+A6fBC8`+|ͥ%0Tam $2 \@G!%EJbMzkCgݥIkR,-LJYWY g(SofݝAx1?z^ 0~eS$\+ D"(I#<伔'-ɏ%9AeM%-F($ 5B~#TxHClTW)WM +o-c "4\υGqG;L9BO>w֞$禀kG/-LBx\ZR׿@^A[g'cIwgcd3D%`3C`c_Zlhb*LŪķd79\R;1<5XzHh&s')ǻٟ>cSp8g~:w zⶹNt2ta/z\XZ60jHU^@7jiݹ1<^sRQ{:|DT@ܯsEq3`ڒMDuW,epJcؓxv1֥~jKL{_l~J* p/?N/t-[Qh䀰0Y|]Gz' sUvz?K3F;!.rChG):JY.},kVg0T]$=7 m?$0dΜo֢X^umgD?Hɒg*"'T#s2s9 wBQ8WQo"  en3mYjT:.:ܿdM{Zx VӬ#80,}ӣ5>!85\())%^sP y0Jv]c~^ۉuq-@$X4Xu:{)$'I[pmd\R"" >~SDO 65B,7js{,CZY & |>xxBЀ9;ǿ^ p48 @f&.XݟIjxNem$џ#]1I<9&}|qZ˭Z&9b 4Vԓ|ڝJ{ '}L'IeR$)@*bu̟ez7Hmk7r/1yЗzI+'IځkƳ" OŒZC cc4 ? 4F,@D b-!5J@Aqxds|!lU&aaUE?`ۡ= :,:=M1mg5!xJXC=@LSX˷lu1,(i- TZGV=nr,x9z.64c㼲?SkH+DTz2J8\Д++aEgvQY{/h˜jWYȮM]F=?.W,Xn^q_b>W@2\N4>=<"uIGVn q=, M:lm,zoB:O(M'x>ey!jUC@s(ϸ#3c,/ԅeL[k36ivfB;#wd5PnY/@%BBjz$ZE 茬+ݷkw<-Yu/@ fGv=hh8woQV}#xx8K}?0cH/w;DZ sq&`.wnC7bA`Ҋkߗ;K?|G*%H z!rc^R&|}bKvSR7Svy1X>;ե؝k΢;R{YVխUq{:!Z~d&Ø"K GUblb"owFfz;d nu#Kc>7@+~*9: ff׆4Mƻ}is>YG bCJNwcja_jx3;Y`5Iԁcp OTEtsjA_䅬<)3Ɲb-|`'X 8Ńܹd%Gӭ,|%ouW! };3A~,zFs!C m=|y?tXD-X)T֐yyK :.Mcչ[!6&=y[Ϫ!ʫ4'gហs8EױJXጡxlW-ɂ.N8ZnE*n-]Y61 - Z?-3'S_"{>\vC#2qG dA>%RS.Q[l,QM\*u5CadbS+Vt !ؘ^Lx*;z!NfR&klav1tcۮ< zo;1e#Z1Y80\pӓbc_&lOuI)jEyѠJ]z6[ޏi}AKo gG ^}8c]197y#fwš_RWIRsK0, SvΤ~qhKE^mPm*]ÇX(}1 5J {L@X{7=%JAb3=:Ju4v+`V+ԟb_ğ+rđj"eA|9h+dԽ@RBۡŔi!LV%sǷW"3zFMXo\y7ϽZE#RNcO,s!̲\J/@i1!P:N$a~ݚ&0 wI^ {p0)2Q~ @ # VuԔJ9$-A@pWS5*_qIf—5j9 GV?~KKfYl\WLs B25?B#>1fuy6 MD75r3 1`$Km]X!λn4LJsƩc_gp}͓&SY{#,%֓1-p?'k) #3]?DEWR,wecY6'm_+Rhڕ2HZY%kPB1J~-`>hޱo[E9r| :e@isy~zUw&!7x T..2OpPx NlgD$}Z/o[iv\?>;NzUɜ:e4y2CšSSo)ωtPN%\ َG?/̰C˩vݷOͥOM[mI{CK;\%9B'Wv|&{4zNBfcDAq;FgTe }xVݒ6uONdKv<2i; zȲIX~4"*N! nvP!zpiAFEZGs@k))Fy05h9?n @ 9c$9v_~<44ƶb:'Lzər,w8t%Te^s8|)D›vba  tFp~Z.ĽX=llH7!M*B>Z@/y`eCbs04Xh݃ nUp89˞)LQ^2V+gQ[O?N9浛ۜ M#D3b1a5ADZ6@3559uMfL` l; DObR9ҰE+dt%o%PFsSsznU6b{+IƿL(TAm*Khwk8H9eP1`#0TCdDRӽoԿ`؟@406JX|W2oJFAz1ں4(:F-bq,:yCpY#KHn$Yxak(.ж(ȬFXJq 3GϠ;LRd᥻PWnvًģ/D78G(Ϯ[ z[x,5J1M-m,& _X|,Tv;)6)XgQr#BdU4LX+#jp;B`P̣F/ۓѲ=WeӋVc ,X#1Oj%q@II/̊BI~SkXon&J?u'ؔwI[qK5AtAsAZyje^2z-n<V|BƄUlAiOm} fq!PN!~4TH<^.3(jϏ]s[m>8 ׶\o&7EGt9AFV~3^=SA#ro\ن:?.+TVr|,ZW Q8ޟb[Aktd⽥Q.C&imD4%ã h s}Rp ]-ՈYf~pM҅ >(fJי|w]_kŪ1}%|9Tޕ߻BK5l[=c3i ~ejO#MW#,J kc `"\@+5`$_ŁC`A"h,]`2~ݨ`rԌA5P&VԦ^Z̶eE Bj{p@ ^8=I)d-~BiR>bbއq/!N_s#&IՌ8@">4.8lS)߈3})`,-mGlҒ@zY;V 嫃B!W{\q7c\JPS_1Ŝ&uC7fa.7YQ{ܳ|߲ }m? եTrRu?Vo?Y>Wy 5\uF@BqPMm?MIۈJm4|b~GSUQ;DZ Qm@'ZȎ[rd Z i*hϚ kT΢[=\N ֡<s<ufXą%veߋĤ[b\D0W_ .-#6PQS8A+^YW _? S C;86NPo0K4iObmS-4Z8VΤX Nsª}AtshD3G}:Ąf:$>NID@f~$N)Owט0h3^X.#㛃dU<2+ZLA-ݼLjATWS.XC[׎؆sȂhAkQ869CX7-#+ a0HO[:~],d9 *cԈ߰rþ;Y tȓrs4LEG15L\p.nc@v;X,Cyo)\$@}٥] l14X>:\*U+=ߡgJ+;^qA5}m)sp+OӫZђ;<_!)7?E)_'Yo-0;FT7sm?aQ4kՍ,fIpDGijugQ#xZXȨBtPUC q~k ~@C%ճήY/B7 0ۉӀس. ԧkzOrأe\JﰎVP:gA2+@&ZEH2- 0Rtwa"7a['6`wǕDY,Ņ,q&ԡ/QÈfp 4ޤI-un\cpfFt@[RN}-)ޏU*_M9V7 g$ɮ*o'Nk@+ċZtpǡw桼(2QBq, Ѓ쪟Bݾ4Ä؄SbzvYVM.=Z.y8 x~>1.z Wd_?32+zBwmi zC,2Oiw9.bi8`R L""3CsCJY'N^(L-ny`}6&o}׸ ŧ,.ڲz3d tưL"ؕbhXz8u =XY/9Ev5-rZS=it+èy(PB>C=y׹ '$@#g$239!s-0{^FRWm\CדF &LFVhn/.aASe#j 4w Hyf WQCvsW/6^|{c OC2>1GsOv!T\Vx"ȟkE""WޙT׺Wy/5EhǾ=Ue4e4Ǯ-hba4+ǗuhčDTGx7^GT˕ܓ/->q"Yt:a&W*[, `;#.GXoeQתʵӧSgnA$ښY l_=+0ӯKijgrCRBCjn׫=^𸻫7Gg]XF`6vΡ+8^?9ZMX=ahF+iqFL*~(͵m3l޹/׭2ֱGx6\{GQ|iՆ{O-p'0qa iX]4LMjH3̥G Z"+Cܸ}0)DF@?wi8͆u[nlÈa1,+'e_zH4w\I/)$ơt5>'05 >Ϧ1D I(ʝh([¨!Q-pWLI:bI,z6"RZ7`rNNJ.Onz$,{mܓW1]"9) %%ne4CºNҬY",7=զǠ0#ZB H__x>HBZG`@J< `SQFV}JƳXߒXpȳM8NeX.5%q"D.a i-m#WdD1L X#-mYxmC(6K߉G #Ȧ ᴠ a?՝9w`/jq% 袩/Q;-ʧݹ\ȒCۣtkaZ rϝ.c:K:= z~O]L'_^B@COD MGO̥\rT0EoF4`tODxfěׇu;GAB]FF8?pΓ+YJd袷ERRQ^Bo,..llgOZнvM*8SP1f6_=ıq[_\_:Et(?+.xVCLWmX6>|u q24_ "wmp66^ZWORH+mTH )Z.Q1{oUe6x)^ʙ܍~mW PuG$V-8؁0gP˥-(P1IټVΜnAp##wFmj{ ,QuKL܉7#.grZuGVlzGug)I5$qS'!IWb(nM*\!=e;3`ҼB1'w"!\sM$.TF* iKhr6VkpJI@ h8}|^{$WvM#K~o&rpNpϵxV[$Z ~K0/ԧIBCAĠ=bސ4ݾddn >gp'eXQhW0FapAɘq*#({$[\D1vχDc\i?$Ek(O(A6Kw3<=X6>M |n=O: >;TQs_"V\ ) *dPMl SF!]H퓁ޘo78m i sEk?T 9>!'~Y`; B$l9uZ/BK^7(fi'R%5P/9#R"u4kqC2z(3a)Õndɦ=j5\$>pojVD$EдԐ P*(ԩ]6Z#]jj(U =P[sw,R< l #zv4CUb?m|¥Nfx0BDPs/;`6=!əePE4Uv%n]pG˗0{v@%(tBw)J-_,*oDm;([;i%#>Y]_$Hsk K643$mtTQ]d:nIC]6{ ]`#gn#L<-)콽D7PY \l۴ԛߧFVj5yU\O6fPh6=+D_eͥ/H6݄[BIwᙙXUWvLw>QHi0ځ\Tszx$3dD 6aJ:yZe|Znjt/MރBrg=ٯ8:kV jVg/nZ4PDgdQ~ߩۿr<~ v:2'q!L ]4GѵIAzgAu ugw%&'{/W%=-X<=:9Y 4Q5A馦ڷTxl4O*! 2IlU> }/;| R?q;.4w9.S*:Q?\K\r|y{(XHN|m5| 1%gA{ُ+“2:懯ydmA[]w3SXDOU,Vy2ń[^ϱFRH$/w=#8<xͮmrI/LDjf1ٮ- ks E abNfY3If(\B$WSRj?Q۽6TkUfQNN1D=(p|RVob@ GV@VS.ҘMUjI[&l ־(ݡ-Y[}TX {z8ڶ)Am%qҫWHj!Z,yo͘.g_7g.<2.k3YwєW/t-sNv8Ђ}krF9. AWrmk;gQ*@jf: :_]htǭ}>tKp27 g~'lHszN\> ">< Qn(~4F{EW*D),dW6,P`!%qIRg{ݟ{{{H?'q=^Q^mרI (iqv<%YI`TMdԕdBe0X1 XI;?B5)$1ݏh~6otڌNwI;piFuo_Ќ#K_G-[:[T弸sC yw[!Os%^b]a|pxY#7U2aD % 2l u-z(GHKV ?('}%,|bΪuM[#UMi̜C#}ΥZ`bq2 o !6z3ze˶=>+#A|JTڔu,m@;kP=؂#4D(O|wY*C!˓e!rfY2  E-ؿ-uiB[ 1="gQJis', jAC_`]Ձe& @&/&i5d15t<R1 WfrҶ)=7=l,j<~\;R₨Ĭ6$9J=r^X&o {p\#]RZf$~LC;4kGBp+;0^ҧ;Q=b('8;XkmBWFMoΞ(Vκ&fUl̤ݢN宴 ~*>GŔ.ҊV?cA+lix!w+Zܺ@$3` 5&"jջ'*"ySJϔx ŒO(]v7{E3fm1y Ip.`tuuZ5L]Ya]] lLJYe"ENж$RH_} 6by.tòldBYrljL;V)~ٍ>هf74ҡ)/XQߐKm8ȸƜ{_ al"ba%gNNQY neg޳N_E`oSx>{]E\ YI( SYh$AJ’A&YkӺ U{\KP=)T.T˫ =/v0_oSfygqd+ :,m{X@?2S+\N%Z/1cn*Za.dJV/ݙ[%eCx?.YөORjLH74&S^ݧ- vrE/,II4l྾LPp]׀b}?z( vqF$b]m]cy{6CuKJ̛u^ {׋} ɍbnʄLv9IۗBU6gùyYxUV^Ҟә#8y!wuD+@cF$9! a"` vYhmi!ĤJ| ĉcC<9 g'ٲ#.,x?^3% Zp RN;`9^r&S{tzSVnkuyأ ҃ឍ֔zw$) 5Don m lYu.LTbR͖ 3r2aZhjfL`eFZ!Q[:?LWܚAFK@$1֙b]ۤmӖ3b:-o7|il lqevA<%DǤ`>_Z%լRݧ4^3u=. 9 5reۇ)46P=JeK P'w(hydEW߹*OE+D?3FEW.<^kwvݛ&~\Rqy+ie6^?snEoo2Uz]9$_ȋzCesF)wYE‘CKЙPO烃\LenX~(1B_zKO} ap4ж[~֩PC\]u9 H AI=8DOÃb\^ͺz:\HDKn8SuKWF´ԙ 'Yy&Hus7ia4cm.c'a^qR>M QmTSIvX-sif^@9IbKg4ay!sz^qI!0&-~l \bN(딲.#M̋[Be.y(Ϟ&hRw81g?S&T3c3,JƑo-2Y+G4D!+5Ip^T%~G`"Tq:YDMhBl3]CO<%p;9eq~}/zOT4^df5:%"/2kް0QP^\ *Y@7\K=/2p,܁)@<;0&S_)|JJo@xÍH[ z3@Z 3.'~D164\HIQ[`+3xf$AnHwI?rWBV" H䫀άhbU-w⺡> :$FT#{#UCQZhUޭʟ(D-,D+K>KyU hn"H=׬1Fl?dʩuʪYV:qvX~3e1ď ҹ6[9{H0A[xDS)`H]~r{tF߸:lG {$?=OZ~u-!9*!(LW J{SfJH +"=)#1&@ƙ[&k\s- C…[NM9筘4OxV,K}ƺ!F7اZ%L210ϖrcjs"X;xa5]epj =NίY>F=v4m-S#sD%hlhQ-;%qLqj4yS2Y.m!RϺqZ 4ǁ&##OřeDzW]Dj]%*b0q#HP =C.zp_ ܈ HEA$]:ET?o` ΰ}sx́ mR뼹Ư9֬%Ht^4b[wZpկ5>+o3b44E|ݴR`DI]!cNpvKޣɁvNC3uKwO>~Je')>KONԑgduSnv}hr%,;JU: C4Ε~|0%+־qmhp$O~씵?&1!3ᙤ+0H$߻L<_&QC?p⭙hK']2Y^<-@;þhplMY}ᚁv}q.bIcov5'֞u yXF<`KyLpbT[_ Hé^H sh lqly@ `Zg= ݗQ`+%ݶ6fb|VqgI<ꀡ`]b-:k>c,dRfQQ%F}9 woEsMDT$&/Kgl!.δ#]l ?hk#`BSrliUeJҜv2$meA<عm#f=-&;GXtQ$,fOFVk:'CGݼZwÂp;pxh#aCǍJ'-kg?S1&+ܰyKl_bPb@qvɨk\\w4*01*b~Qg;2N.BՐF<׋ /C/˅۾+ͻv3f!\b#qUE0=z[tda.[qXPґԄ&3+[@LP4K#"rO`R&MRdYU3H>5ͧڙщS>?xE$Ա\~iOZ3+[vKM{HաQShxI :Xƅ&(-s:j{!DDع8إ@,gߙVSD{Q*|':K<:Dr1}~8YCHy=c*WH,)%lBޞ QernP4A]k;q4iu&/'9λewc{U5i{Jƪ[j" R]3*yE^dDx),#qUɌ<’5~?qKd* d@zEw D\ўg! ?;wbpD%\֒;vn]-/.8 OAlg,EK#^ 'e@=I<v9.3!29_15ROjyRvěbf׮MI jh=w 1E.r4d=iqt;%tܨC{a ƜF:>v׫^ێk *]-p5syrWy፧'_/fcX-غ:fNμCD|AaSx8,S9l?JXӗCTף0H!e7Yen #ׂ(m] &&&:]f%*\MxO@G,KBiӮdRvN}07ڔ (J~$`\ @#S5"HNS˧fMYW_DY@添b>h (c+s*3EQٶ [U[a5dcQX9  #NbINJ?fw g~vZnꡏ otRhTs;iܟ;lj|"i.ScwqN=; <.Ņ: MӕJPw :)ɔ l;A臆:T8gݠiTzz7^#HŪMȐʣI<\WpnxEUe<[*3Jwtm`*Ml;Ս1iQ0a.ٺzy Z{a>"0Z@s`'X V:-e˓6 4_2ztcdOFbƜgT3m"Aiyj쭲g[=4'YSǒ*Ң7#] ׋$.+3PX/b(gGz@yЁ~78Y؅ikF)-EPQP=XM)(xJ`\gȋѧg{ riʆd KWqdV6gge^]F]o8sH }Ħө1' EAyn Mn†`Z΀xM겈Cyb}3H2Vq5e'4{F6on8ᘏzcjMiu혡4 0}QZz/hFUƒ:_R*=JQbcD|PY!rX-Iq Gl( qXN82}/˙1E"2uן^Z& 3(/4]dyX?I`._>]>7OIį_)](o|{o1T&|On4%t+]gV9c"xJ)5VbF2^(FaL9kE "辙] xRHiS "XčwyA~{cg``HӴ0MB~sAa{{Wk6* )GֱцhCx=^Π@WD(v@+2ݩ?辥({4jHubVLwsH% NV4%٣wS^%Tu y=wD9M}{s`Dm :v3sƤx̄ c{u$ m&}2Gv^fuSCPhR /͇Kb ~~rp-QkXse~-۔yʏ11LxP24 mq0+Z14]9WBV hypg*Zv*|Gc} ObF=աσ5:w爮ï`A8c%!ԾF5݉@je8lĄJ'$fB?UÚ z8-!DRLcTh(~cjs r6ImM,k&wR$?}y ed< b;>X6|_~s `&Ic> ְ&Rb"3A~*eԝaܳ7P?kƺS񘨼\ 6(ܛuzx34΋_}O|a(Lǻ23!1 ZqNVj ˧@T`L*eU`??`EO)p:"$tC1]Leq=F8!c}UڭF Kain}u "xy3ʰ3Z^kZHY=> w^7*=+aS4lh,xR:y؞A<*Iè@QY-0-ui:;g{[_.QlhK|=b?7}INx&{LNUdÁ^"V/Xl1t4eS!- 8)̾Yqs^~y\w$$.jO^\֤/z%@lODԾ/cJ#:P#M =jX$q>9"funד+)! 7B?2S2æ@H +OۥYsb."rc'4y[1FLh)7~E{&N[$~S|S]j5kJiy:kwdqA`$IfIuؘuCsXGiiƁNk}ϱaOK;`q4A(va PL3;0xK=?A%uzJH!vvή-9/wKTqߢQRE  -zc4߳w~dY`ĹǂrB^F-%zH?~/[=O4pSY{͌&FTU ϩ0C!wD?g4XW ·M{cq Բh4PG<%piosi-mwIecM _(_e{1ʕÕ ii, F`<|`y|YTAY[k,Yz4ᜮ#g1K|&FÇ װ&?΍*Ư&>&LySQnsȠ"3@ 7YhCǩ :\+zj5劇]:AgDY2vYa,p#ēcc5̔xJ#]k|͜託R{(XyL3<% ;|iC\x &Qn>υpfp%+WɃYMu^oA{J5sfy0)!\ |._{&O3ܦG_ؠGkP'!( †\%e50A&G}Ų*$/=E7~7Z 2Z侘kBwO,ZC% Gm{B![ ulDJ u%%}5=M ^L~{ DrleHxXI(n36|U?-yj7͞꬜6r'G0y2lba[)>;U32Ml1myk2,\ܺ N o pcm%pv驫U%,L!ץvr'W{V )ؽ ?^aV>wLȖNٵm[, *T'[8x!SdN0{$WeRN5:^* P/JE,6q. Zz7?BS9a1̤~qPhe87$ bxnpCަ# U-RnX(-} !&~UUAK *ڴ HXtMjlHT}uV.1ޛ.M4I"M /ۉyn0Ө7؍ٯmd>M%ĺKwAOt@PxEABEB@'f7q]xAԄ΋7b&GD9rg72At+T՝s)!>hD4tpFF/0IE*cIGZaT9N©A+'{ D~M!s%qdk7aDǗs#L(yXkLOݦr-Az>YOr9pWkJ_[A"gB?1: {lr@bЗ'4Gf+%.?@F,K}H?+icodg"A;+ י gۊ@imJ{Nͫ1"R`ܿP$u0U==6(`@yf`ޕEDlls/Y4@S.0]kXZŷ2ڴ/ӚZӹimBÃP@O]#ܛXLӧ;!.:*u.c8J}<Eꇭ4.sHJ)XcīnJꊜ ru&J?A,12A,aF #a-v3lj2BH Պ\o(/#iginEU%W{55^ r4y,@BNfZJeg4??{^V=NN"gJ]+-jU'>!I< XXVfSqZʾ]Ok~ּyȬ6zsӧʨ̭)okW؉4WVhA2dÃN QF*'r4wWiU&Wt` g5f$"鯵e}5 !?W̯D6j6([aNULYL/lcv΢ 8| ل,&Xn ݉ĜdPV˵]S$b0#B$reuS?K`=Ug,/2NBXFIOm!7<`dg1[cZ|FKڿ4}Xmzw;[5I{Yw[)^vSpDg%FzSU)ڤݓ8_!gSV2L7t%vyIҪ떳yNN+l+eMЅ_K|~_2 -$L^mG<3#;qsuŸQкξI*Ah^bY B+ sviOD&Kn_ Q ?!ge&4XkwvACʃB,gbx#D%+@أQm! y>iߞFXH66OڏB}K*n ‰e3+;s9 XQ% OANʷŧd1 *`,ljrR!]#[^3{æk3t*M6l;n^Qǎ?;"c8b+eSPҴG ;$]o}3_Mt&iyO]DFP˷\l4Ki.~^~{o 6ў:ӈ^cIټA{#[Iu 2#T"r8Xq)ekvaoT -`Ƌ~JK y8]!T2ʄQm_"" l~?x'%#jk)8+j-OpO97g,R"xO#Hྩa,IݴߛLjAFNnAc,$&:q1S ?T-ڹ uag΁%"~JT]octM=dpA jte9Mx:N-d*6A/͢Ky9RpAMjC0׭;͉xKMa%T[Htq; ]|oMUb QQ]w[ xG}a ? D s~!MT8q..$յuXŐ0A.֝סnG72Aa,᪔%yu0}*%ѡC9_7 oc5(D&CGu9)f;pBʥIn>= ݗcݟmXT+јb_n> 肹Q *JЛ[oH`K征rֹ&B^׈GoXn DE*{a.z,:< m ]ߗhQC"2הL!# /)LzNS-o~:1E;ldCWY7gN5_v`!,{+1L^hfn4MvZ8~#%]~`-褧_W"'DtUslL.ZX%Ek^.$0|VOK/bQ6 . P"N1,'8dFK p\&EZGCU9}+kc^"0N_*|C3іz=B!#Vod'^(kyt\n Ŝ=o`~/k兣U`)=6{>ADXu]z̦*P5K`|k)1uSbJΠ/4Eff)ۜU[tB'e(gx:E ؏R%ם~I_Bamw6"L dCc(j"Ő>u{e(#r Hi$u >JƔVx|+ND_Uɛ ks9(RHnA>֋QK\U|6lTh&|,b0 dKĊC")NN޳#PT{3iewXmsT -prW ,,ܫ뜪-xuV괲wcJ#Ypr*ǬzV%W)<MY3},y3dJQX*CCmtRvII+۲c6.VƒFiK3^,o~k3k1E$E MLV:X;\a*j{ITOnXHwMTh|=k9DŽ &~ Vڧ[8b߾uvw?0;$~ƺ-t[:5$){w/V(V/4KsvI~.~fWm Y#7Sjl0Վ,Vf~COjmgjEtnFO[M[ R P=#f#cCUFFWͳNrȔp މ8Li͋! DdB}+#ƴdOڴHVj\utsr<.?o}22TzA0a&I _CQPqHS$92PK;ԝ,-C f [$DrsTRƫփi#7Hɧdy@Ђ;gaԭ\xl':ه+MꗾT?ZjFV\{*A"1 Djm5~O9kE!Nqppe(wcKz3btMGOcۖi1Z*)gB)2_ϴBA~c|ʑ˩U}>,Sz bjR{/ڮ Y%~c V]w (7JBB)6qc~<4lw( +Z.9P3~ZK\-QTy%S(Wq6-gaCcJ].d /hbFZ'փY0- 26⍂A)xX/MM6&#лgfi[X!{1"ؚ9B1'NHѺ$FxD2?K{ GU(P}wqZ~F]Hֳ2!!l(z#6(z˔LNjsU-v8ᕎ6q)0W͕d#f{|wM#Y߿j:@^򶤞$^Wu@p'-)l D^='"}*;z-2v=Wx)rtKdNR(*8 Q^cY{v>q4XU+/Q+O~ioІZAŕtCO`WUyeğW |mDY_ az p2cXc7t?sdcPo/&5t0+>C' \7M4n馟{($Zzik&ƋǨ ?!\~E*ՔӕN1 uU7<Ɋ=oQ +F$PH(V \l!\pqxk_ 't 4&Y1<שDCW$&>P72 1a摚\>V~:f\ 㯱Utdfv PAPk~eHd`9rP{$qN<~2 (9m/z2hc2U!QI%[b9EVE7eu+'~}"Et g?Vr(%^u$˄y (0J|69o$d^X\&FDC? L|?op/g"/nK[.M&" hW}t~WV̫ika$I^&ݪQ-ur;qL;mԱ>/!MJ9$Z?'3iW)1vQahp #a{Z%#UH"0c=B ȑ&lA9a8Ƞ!^\dE&KR:z_&O^axDJ8wBx)2Tx`k6*D*6c<>PS*j/5SEA0Vv֘}\YCW=" -HA)@#h}Ǡ3K $^il?d}!!˛q_. m~J J}twBT,)2|Oj( KB+5J5-(F7+ pi2 4oUc gN@g.p3r|5E.\י2 cY5.9Ƶ`t@{6i|ydz;OP"S yxSP;VtqށBj9.x5=_}|79>U-6g>b K6a8<:l)WQʶ[kم /N0+ + zIy9-v>5dKacx~|Npy_ݴ:%ulp I)y;4{b_Qʨַ6Un.e5;&xfYl"!TU,qXv ެ*ׇɭ~YD,oQJ s䵂>>0+.eX|*io~YeoA(,?.Yx}sw ~Up#kyVoTB>g&gɷ% HWQe"8 a%E0u 62YK0#i @Mb^jY8 pel.n ^ҷON1jٸI0]n"lcl `1"RjHtl8ƕ̕[gmu;dQm5?Sx4y(^fpb#$uO^c6<( 0caqbtHKmԚo],`+w1qǨC5+7"uc67n+0(f 1 *kNE11id@)$SVGW~** i+4hA)8E\ M=xU1%AJ8Ky]p D S+"k=KlGu|M&qYj}cٍsVeee$>)w7PMV J4r[Nu/=9[E/&+$i+{O~vNk2s6p{QS,MJcST.EdDf&ޗ}vXC <$lF2&44z!-{6pFレ25'Ͱ칬P} ,V2 go"Z*:JN)sFT(m&7:h:)9CJ;`erSNoZ$ \5RƳHTU Hʴ?Ϊ9/ e]nFqӰv56K P Zs((P2ᆚ 4J RvB Stz8#ɨ `j/Ƭ[Po)Tw7iL(T )x}5pE'K`8ź"+2k|He$xiG% n"Ȼz $\g*Un)IOf^T|y;g|GEi uvU12iI}0J̀L~pG"kr߬frTp(E2/Rp7;ꃕJ(%7b2r|\Fގ7^α=|4@jyQIl` =b ;>ᅽ\Zu D Bg2u[j"W;t_XSn1Ev4~RL}x ( {p:Eom}VhJki&_ oU@~<%}P[1n NtXn Eu~ezZ\:չ:s "zsl>UNE+y"3`3!)pD{Zr'@Դa)}S0MR |A84K};U >j3LfNwտw{rXkѰ"B҆Wzŵ9<9{e|Pe,XN"}CRf=𼘪cD[ &N5ͥBk#cZ&XVhɌO npOGP޳v#ϔ"cVu;t:)}u/4\W9&ZD}MV*z/$m´mx>[*.8vQm%*=d~+5S&'>ľgo2 *%sE,M* h/ [=n|sYNp,{Ж0pR{M!TˑV- BQdyzǾ Y-n cYi_>eK?x|2ޕ 잸}\}A}`t*Z خ_/%6ό` ~0q,c}._V|MZmOR5Օ'\cqгeA%zcfفz=F\u(3]f1ƢA &Y']Rg[ $H}N)?%"r@v7\yaC,"*g]lB[,P$Q$u%ź* *>I+lwĔ Б$@hBR0ywΨri{ ֧B/%Fg"h9.I91\<xxk"j_!E=\ QM*9R T?qS@HNHleDAnƃ%*:O֏7b5fKK>־XR63|ɚQ.cM:vٻ`I)mK,MwSC[ba,հUfdP?bi5$`;}T % ڕɁcˠ(]r}T=PK,;XD:1;S6A07[-U8 50TL{Jz)SɥS- xuT=7B&Al98 Yk{?\ a7W1#'!]r@ai(()LۭaU`ѥ9c7e "ZסGw'\49pzu\`S;cj 3=6{ zl"VaZL肇`IC[Lj{T}dV)2^DO : UU:Jڛ`Sy$lB?e1β/>}Xg`N !92Wfe=ε2{赁rnVՐށ}ňV#_bU0>\@<|h>LY %\;?Re]VlƱǵmp~wSGQR tXOaCh Q@PFù%çA 33gXlDŽ7sZ3텿X{ʂ'ڙq%8K֕/Υ%;el+$4I][w~;>F,_fɩ;U"ו^pw: 7c7?omXʔֺW$.g}5܀ xrzG@OV Or b6TY"AiED3ϝmoIb ;:;nŪ)&x0H-`_ VWD GԦ(@U^7QJ Q!)H?!K#܏5C=Ld07p՟XTwdLu'wG2(][.S!%`_tB:/y, &l뱜?a~Rߢ5Mq 8exê[mX 6(%sxU0=fc:p%'k!]l0s}YǬCfHZX!)5Yr Pu(0Zזavgz_FȮU;j}=_d;ujS)/Kz MZdv2{t'@`N>ǥ|!bt62(-,>`ivA{J;U kYłePV"ϧ/W0W1Gõ 1`z,ǙC>:l6J19@ 䃄RRg*a*p+y}Qk{ĖIP P 5T!b[rԊ MOSsm1 ˘M\ %b0MɌ5HliNL;< ;h:$J ce;'Bseѝf*\”Mٰ]5ùWҦIR_xED[X&:vVXUbNzn7RW;PFN_:N]uڛoը>O n*o19c )Bn5fI* w? B>fј0h>ѹ -!^z0l ̄ Ԫ O'DV]F,һPnhek [ ̍ik+e z`5z͎)u,¢Sg^i^QXiO'W*}qdT*Dόp ky\}9Yb K7 ]t;ľݖYbxcY+] Y¨ BB0թ0eV8?3 +V:ɂ{׬@d^KW+O{ SqM)}xQQ6(UV–6<'XJKS4[XZe/LHT:26$SsE" 7TjIn0kierONo{e+M5㿶wLXFΰ;R%0dqc׷>Fl5J(x@V,XmwSYVelMJ]V:Y8,8!ukU-F+A`]1 E[<+es:P,CQIl?U*p4\R}űA;z,^Ֆ|ɏ$% %NdOIKmt(f 0dCVy݇7γ?X >JAJDYNFl×I j#<%"[kI 2@|R vvl;vћGR8R?-GQsr6W18Ip14')-ٿPGG֌! c7,5e:F&-n{&+=8gs:USP-%ѵG WP|N&u{U!I4S\z*d1q`@u oP`vi@a\MKSβ TmԕzQJsb33@eA$shECvEB)*^Ļ 1YKz*'q!HP`(SgP8lC5vqbQQXI)O4= jaliܐ& LJ&3irM\SpJ9 G pG jI4ķc@Eܳ?;auZOgLaqH@(U%|C~j 6T՜kj0tOL!7 OV^)32,Ng>}bY"w2!J ̨x[Pԃ UG/[w&[3hp)ћO70U|PC Zf*E¾X] I0VK@yqKQLj:\ԌaFgJl=:5R^'gbFXM۽Q{^ ʦ,h=(/AF ѭB8iAWc[JIg̍dfixļE)n(=wq}l{WvZAңtq%R"[}|;)ND/(d@?1-'ˀ>v_k } Zбeñ:m.SzKK3SBo\vc@R4i,)X&ɹ͛=<5'P5Qj^ 1H&}';rO,-gr㒴cXx?6NFCM LaRb2ؖK.e[jLeL]SH'7ö4+ `@ǟy=K:<6f/w#vղEAkϗҜK?rB-L56S-L,4K.0{ϩa:p>k9i\3>J{YQTM$yJ20U8?L|(h[t-"C*h\i\P O7x1l8Mkk>98Cɟ,[X`'VAD7;A*Nrd0$X9m w6 ;,#&%QkɝV)p2R@@cW8w rwcd: uk! k4= 8fѾJ4Q @ҷmVD;b#G\-|8FC A|8/>]+Ry4@y@qmf:/{I%>4۫iv2M뙣&ip*ƞFa~tZtHk6A䑝c +1E{VtG R6qC14h8pGNL/^^<4J>ht L7RUYp"J!J VL82]`D+DB4C.`Pc#.'hf<9d;+KSw MCI6 `AnbbYYVQaSO.JרslyqƷ}ot0$^Y\x %iA pP!ZJ8S|a&x]@IyBqc,cgnZ*1:̣tb;Cė-;dx5K+'<ǣ~2k?J)gQR62o=O}֢DA pH?=FLۜHFqi98A@t/C5!mxmr=(lǦM(Co3fyWw{]*SMP?俎\KxE~R7>b{xC4?ISSejTNU=iE5,ii(kAonr=v8RkEZ%5aTF?>CZ8&IXJ 5LT@ 9 |r_9E]<5WOLfe-pYJ?߹ oikZ%5SKM>d9  {s ɯf1C6|u`- I8BDw(!;; g;v04f*"/:ʃEՀ?;(ORᙩ}V_Iu:bL*3crppc:Z݊(GfM.Z۸v)M;콂{sfH]vޭmJ57zy `]'|(qDžNPD|:MGOCTfZᶹ /Sv9IpReEb'҈M~ HVdyUqë>ʺr=򫫧ZbR#3䃞oaqޏ~!Hf؀|Y@S03hŽB ʚ,62@U5ǮTw9I@e#yMdV\`@vن+u]k_(("."4쮏6*%xD5D^ > %#΁qQ3P,E/Pi%+smzK v`h.Y5~B93tE-:u`In@m+/W}r4V3'ǽ"R t]`FXٹ0\ŀܪ6;sNH l Ozn>rJЂ5e'spy')Pa#aZ5('j7O28Dk\3-M_Y7:L"(Wm -!%lRlSbSf?Vb:,M m   _&i>iݏJVͯHBzp:NsLQ ;ZBG9PeΆ69Zǜ*}HoQ (X:AMww [Bc_a]4 K闆"GcиҺOݖQ׊L)[#{J>TOoG&"ɾ3[ىxh>חʬl{KIasY(z~h!ʂ"97WJ~͵ώҰTwkeM=wӏ'˴(m?g'O}5jJ__saHrM^ Ub ՜gOM]0{Vf*,f6E!5mm%Vx*3T ]t$F5g*zZ̺g՚|a9,_SXMuޮYpBU' %_dv c1"sX#(-v}R{|HA l=!yDk5U64~"H`gCzHʺ/&Tf^xt-]Ά Cxb|'rٽK)㍆5̳)=m%?x<cC-&bR ܢY,VUDPoMZIYa$ʖS2.wP$Jǣ='Ion.QQl0Bg#5Pց[1v%x]/ =}mlE%}˗jgg`Ur`! K{ #oR0c<$؇hѺS|Ȩ8Sö|^ě§VK2<.1]Yd}qR [ŵY> +3U">PopB;WiN pXX{C'hD񵻋`h =z^6x|l tҟpP,,A^;$bRj2:g_ihNMY^#e[X*j0HT, eo ȉ»l rnxMA5Đ!.]l+ƊJRSFPN'@z9fjxGm٦`veC ڸ*<oD1t΍-dssԯ?"|,),ogDƚ`>2? k\U.&hӣ ȗE)WDgQDl[ Kf;8;7I["r^Ud(m`PiFD:.#Iz8}*z|]e~ u~{胠TsuGz .Qq ?k+>{^;^ݴ}={׬roϷ#CV=f(1+ݖv2j dJ=,E+Â~^$X^-n=)|6ZWK7g iuo#AHғ[vf]WOqwfbشZMYdÁ^O Zm 158S}kՑ#U|~m(^cN)\NG`#uIOybsT0;$WVٲ։dT   Yl{@-m<.>ɾK]mE5K CDuUK.? 5N̈́?N~!Z_uЃ_;#^Hױ_hɬ#y 8Քۛ RA0n[uZ0=Ŀ,ӁC{&Z0Jn5pAV MJTDZ]s_5|UdZ}F48]6=ɬ rl"G[Ot-W4W?/n 5bc 2!hƣC:xS(J+LYaҭJm3&s'$j'8#0o5r_G7J.\2^m:2ʍ7-o'/4YucȳI}@*uܾV7MVEG-տӏzd*U,Xr/ ǻ&Wt|E썺Nj! L s&&VmXgz/y6D>3LM{d*8kWvbc(__ b* i|ir}4i9ߛZO2[qinpBÏ|.zkjCF^?q&b̑Qez1c 0z^"H^1?>w5<:Z.w djtJmPe?ג9b3z}5B(jNWUiT9ic g-pjڈ)%y߽nufY' ]jRtW.f,]mL:zH9YryUCt._6&F\CTonwvICP,UY؏iTkok+K{c,@=ʡy è'fBGYhm^3@aZj]u?r-%rY̡Lzm[~ i.&gÝ&e"NO.Dԓ?W)@+磍 d/ռɎ \2c"wkp) C(3(<éO" `GC|5E&׷#1L lS{\4-|7āv):ũ)3 \ dH(?_(i}jpFbN2eO^9-Yͮ,p2B:X3Μ1TT+OkH̔Omh=k6C> QUm>_"TnyNlMMX?֚m[e^B'vV!ιir% rh lOJp#n7q RL=4RK&Mϵ` o5ٷN;M?#.#bȂܸh2P;'6烗RGiΜ`lG:[ӓa%#; 4z-YZ@W &ۡȪŋxfwڨZύǏK256vP,m~0B)OO 6Dx˟BJ$>/Tr؅7=[,*%2ުxm[shgcD_j!$d+ĺcUAz4-|2Z\VO1LDns 5舷 ;/C42;LkC@I !zg&W:Ya)(6ME5O0r<$Ѿu"Dm*e@$5jMc;02EŦlstY^3:uTF^'vU W V87Y2o#s1:ɹz;gfq' {eρQK[͊yA4]$.Wfnݍ?i(/KK\(s5FƏ7vע#}a?jMיJǠg 8{ 1<4Js`F6.v74Z=*- ʨÒYdX̨kۥe~;A*9~}pW3FfQ/%ˠX*0AQ/$Jֱm +MbRnH?C*l_AG2FY!<m:!LSL|5HQWއ['7m264CCl#:W'@Ȍ{V{ ^>_lZ)'zTWk; !W }]Gi~0dpa~3ó7~( "Ko㞏;:aDBAM)>T9[uKYCVlRU 䋞]6voLC?0|yW dϊIrhNa;\:_ ѐi) ZZS|Wp4S]ci;!!o{yHS%9'16'/3X80X;(C4gT3,[$0r;Zo DH`uqVa%b3-FJ706̸!v|q8d> c7cC?,uesr TW2weCdSWK$k]6̤fO? !8{>4(L19U[%kZ[i5i*p&?r*@lf0?'d5J ;= ^ZZPhn8Lܦ7JnNSPG8?AglWXP!B ;^߀hF_/mmPOv8RE yWS<=P,,ߓsq"˝Я.ѐ+G'Γ@H<&2?,C(DK( 6Byb*#hh0 0@O&}4E[@ԋD!ܼyto>+- $q,WG]Ѻf5!gzBh褹C@FJQsU1?~V',On.Ee!YyJK2WIEY7gVw& }^dCԌb_h4 qoӢŮ臓!5Dx:]`FAdbjl 0-Y= }*{YK@׼Ɲ{䅚>w0iW-h-S4(m6uUHV#{h(!Y RǷ=Cٻ&3)4񄏼hf66uQE!r| L -]vLe}cJZaўBb +XbeȽ1TKj4lĎwjrBr.Z m ~Bz.[p_-1k{dx?򳺘ZDžGQ=z:jW"TZMEfk|%tW/g5:mrE8mAFfM3 >54b#-ev1ZD{Z+ɫ.ߦx޼l\G/SZ{f">6F.0ɽ'‘q4'"Dd EG x $JqI.JvqYČ_ú54 Y ž N {g@;Ax#Sh%&XR7oΡ CE<|>Մ3WϘڛ^ A㟤pS+n8ꢓ8SD^.'oQ3̜?TŽcu _=_ȷZ ngrHJ ൎJkHFWn>/>cJĩy+8s$7M^!zox~,l\+~=wl/~|GglH!5i=./>=qba 鶐B_OhOi\=xOtpr` ~sn/ӗRKоХyl<)! nEJA?Jfb- eYe[P$9ba dw< \A&gj!BЇHV^,TܾpOf䥭YCDCIAC1F3*1q |0u]ǃ N7Gy 6$8ػ4 9[htI/ژtr);D!ti?Ž QdSjKr- '&}:7ݒW ~vi<06cS[n=Z׶GAG)1RRl7OK]/r &J="Q%JgY|"&ru/U 6Udt"]T#w.<`NE@)'qF͖>B-+٩3E:WIh_GS:1dO UVrqxq~zZ7RP _tƉ{ D9F.4!v)m½+±1W8|bv>0#Dªc=NL)ZkZ;O}6`=ykˉ@5OZpڇyƪ0zz ^ / '•{oƅzEVǶЉzouBbHz k {ʪX_XOI’ XBplQew5 =uvgO-"VkFȣ3lٹ{K;|$%>@ԏi] =`ŧhv֪bOP՚g >;Fp-I,Y=PwhAɐŦE66O.z˗ZrLrXJ^_[G9!]31 09KKN[B5bbs)X {l-O,W4+:=p]$q/$v2iۡYV6dy.~^12_zLe@]/{YMŻh RguIĬٿD'k.8OTb9a# ÿXToa5;QAGy:X}+4xs"0R`>f|vt+&1N]XNΠVٝq =lT\ !G#qV}$aDV%չyÓͻm T|me-ҀJ^kc( #iYOm}!dJž\?*`{ TWGї wN<&.>/T|O0=MAɀ$:ɞGTQ3?ӯ\B3-UcfE "' VyPK 0W,fiػ ѧ;ķNDvz&[fzB,$-F]T?e6S( cY5*0$k^ VQ0<| !R6j2>jIйkx+nmsg y90wN{ɰbF:,a^<+VJhw':vuJ2~Pݭ#Aî 'Mx|9Vy#YzqSŔr0qq)o.4+'b>A<#;[GO--tHL۠ֈd}{o[ 4;x.1²ۮnhTQZ (Ј*1;KnoqtR8LIb̜Aorع>~S,zdۇL@QG"KkqBmIQөTͯ.gi2vHC̟>I I60k` SKeHjLuҦbqWrWq~0$ ŮmĚ7$ @Yvj$TdF,I{yf%`,EXfYu&P'gefk=%ZNϳ 2,'Fr o"TH;6nw9{MBj[2~O _lh|I7QޕL]:nLL vY <r&/&ן_x*SJ[WJ+qM6gpyQF< ]טlGqudӤv7YmUS{g(:Тw'g]Yn5t p@)hv98 }Ј222A-'wK7:suv mY08[[K!`QEW~Uj^ט3 S/XG:V4pt#)cųhV%IMR*Y]7$CƓ{F ä۽5zozY*Uů `iЋ4c?e=_d$:;Db_{TpH5c1`TV+'{˽4m7eAm;i`(ڧ̌},%Kk0fg Yҕ}B]DW)V.t6HLJl Iim3=)s\1;4Tʎ'}bF(*骼>Fn\mMP}ij yس@q\O}' y'$7yGjweg 6h֖]wD`GCt8Jlp?h"Z`_~T9dP{P(q?<ѧѳ[,V9˱nS0b3(ϸȟl , ͏d®f>Ͻ LW5@X $`~=ܾ焹RP`C(NԼ6sD9^n,ʷS#{N9w""[i᧮cIJo_{VG9"L:zH::I3pro .vi' 2׹7AmLmVJ7r幊lB370P3~~Q+ 'w M(ݿ95h(.(Ilve4i x:pk:Ia$Ҿ8að>? X$%/@tgLw^|9}Iۀ3E%x?hg6B&bR90H DFמ~GhmPto#tLMUx뼃Fßݸ!FHiDly% 8/+xXjqdQF-ޒs+tt7c+(5_S=s*9]17+ "r?7J^1n+Ru *~jN s22~lzîNK ;ϳ-!_micZR^'}2ith1,9رK9$]JP2 19m|վ{D4oV!E8|wF[0f.oEWNFCĄ3A&E%`0:MTy5U'cL`k3N)n?ElA~; +O/- Ppqd^t[Ne`B :. f;*%SpB`M)N(+uILqDQ:\ '4&^VRj浐\ѯ#~c2l+n+XlG,U8Q淉|,l#*GRq= hn+K v J ,Z}U}̙܎8%y)n 4nd0(dGxI}.]jR-NN"?B`[3K_6el͍]HJ~z0"B|+&EY[3ͩ_8 F>WUoڭSR 6'wM:F 8=^2|-3]y|of%HKտҮjTvҳ$q̞S9Ʈa!SjH 1֫ґbZ R1zwRS=h'0*@V1jh-P\H + wI8?B] {ۓa>7zτf{79?HթAmo"&"J'8//(ԶcrğVN FzH8mhs)~9QPk([ JaW]M,l?ŨKeplWGaIc%M(W%ZOWw2_=[{lgn|ߵVv#69PF:qkH -L{9ß~/9%{, !űh4w\Oz^7@ 2s멵&C,X7prUzN$q5tiP'kI)1xr06ƎMb\ZUO}T8ALbLJccO6˒\7BXI BZ8[u2 L=R17ΗNƿ3xgӨ HxܧLIFjVVG7{tEb|)-i蘙WjHf\M6o7M>-fJ\rNJopUg*5SMI' ѷ}' pv2bZ ?4 by?f ڜy)[S' 2}-"z얔I o +:ĉuׁC<(hV q:C3b>t]=m@3zlwrjD:oŘZnX՚VL^Pz uu-to񌛬Qhf_Fo­ b3yɿݛ^ջ}4p>QȰeI7 w(SI>PAwaOe3^N$[z$l+3MBqO\$R9R+COO), - 4rCOzIzv A@QmXuOZ*%m_:<;칩U~K-L*4u0:+D@`Ґ<HK`Ņ0SMϲicǿ\[FkPQ;ݴ!8D\fǻ$͡-C%CR/`ٹB> t×<򴝸*WCuh6a E1a"!~:*a[lHol^-G8 &(݌' &= -g#pW"!kC]ᑈUV3oפBpKfAsfL:|'>GX,x *g#}j ?3ʅ:o#]s I Aw6Ҝfp+ ӷLŒ`Gp@HKEX̅9k)/۰:7(:/TY *zG٠H;D͝ށ%UY_Qyz,'R*O8Z3*|TΖs, ;+ ;5Y"<av]jtVU\^Εp)3AF<%S=I|Ikk^7#uKm]ŷl٠ >v+cunw4SrzZ~ dH.B\Qt3GCg(BDx>3ZxXVK>$غI*Q򖫆R";6#Y4s偵stVHF \B,]P~в]+D'ZcBuފgZX#$ pB@2& +,&'-xmiSl[/lk#P9\&TWU$"$ ɹ| 4- B,mJ Dc-% _5M1ӗyzQFB|z<"T*,[S?ڝ#7Uvq4t )U3wÖ|vuȆ8xKo647e}y+Ι840PD7?U7̮Vh28Pq| DO'QkX&hOj^7d3 2E:Q9m5 g0ί;RH0 kzM %eݽОM hx'n>Ciw%cyKTEvMiD}4cLQmMRHۈٴS>sf^ '3l/c kAIoXIG ylP8\IV!,}L}Q 2q\Nu`.eRN݁iQ(Ѱ 3x Wy>.̎ 4ɉ3r8`]~`$ʏQh~4~TVdjت[ VX94 s&=98V5 vS[5NsĢ9INB]Va0Y~Zv1 ixk+BGPKKy>~}SX^,M_\,e 1 ؙ{Ωh-5Ru3ohU^/=|恫#"EwZuQ#hU{VFӜ _n+*VJBAW1^U=H pO,ueIO$|Hf;!'.iz1dyvQx3Il2]_P?aKJ> QH~oe'VgJ쑠|L:PTٞ3^m1sOe9E1.YWN *;iΤu\H֖MES ~}UP=}|~?ZqBުeY 3fŷ&fʶ1"ˎHq@S'Nk>7$D2bH#n¨{M EsXJłHߗgA(쟀ñ!:Yɹ>p"ٚmp/\{gis!UǛe, LĤ)r}1u볾i;d)!j6i)OVZ҅$_A?6rsߌ!U!cҫ`)$}fz諱o1p&״5*pV /FheAB||yy 8og"ʦQt`y?s[)X?c QSbL nuæpZK|FwCJz߁Feu-Ej(mGOnaA&ϖ y*x0/5.QUπ,jv}i:g#݊ љm`-.`2b\9"H9š4ΫQ+m%gLl]Ov0f{Βx0fK Էs\|hyBf<}Py[umՅXGƺku5D*yGRP¨8razQFkES,qMX̙x}P=Hia }gmnRQYq$O8cGF>hH"X%Cϵ:'a3)ٖr8=~Sc!r qǵ֛.ǵ!QεX( " Y~ At:ͨ@P訂+N#\H$rU^`MymMvcumT39ER'ωPKNhvP j NC}8Bk*QѠyhbs!s]!·+aqv;p ^*j͌I\I)Ev:R痙"dZB0ZV[C\/R+n_]Y+Q54"A،PQDn؋^ Lsoѩ?cd4-2ՙsi'Qd0\&)tzm$uבT!u"։.(A0,6R5Q_-P2nwCma;:.&e17ur8C ʗjmwꆎ.L >HZ:S~) `hbvwRI΅9Hչs2U `ĩ,aO._z1҅C)\IbjLGS@&5VcF;r:*X q>a$s#a]CPW8Bq&\q>ƃY>9BZT]68XT{E=hœ{gfH2w"DC`%!'1sgtԄ߇[v3BHjq.8N?05Y,ad69ŋ?!^ XaW4Gw1@KcYlwzg + k*)맮'zuI) J(Oe״ݿ'qd[DX91kHG#R@A/8Z$R"uQ+UTwiiFme{Xzǭ0{S.tȎ~%GMNz>WUBr~ WN=2|۳ji?eY\0˘SE3<4H"&^ gK6 μ-&s Bb+DDM׺FM@Pc&M[(>!7oGgSNGpFBzz(r CWyz9s:ϸȦ;fS=N=ɔ ;QDZ{nr8e.y8G/~_Zs2jg?t M"L#i1SBeqɵDc,S/ջ]Q1XoIB+9-k4<X̿wvBNI~.sy syj C67a2a5.M{6QY)AvD<'?] GAmtI-G BpjĐ>ڏƋ|MDOTۭ[eWrPrr4Dj2P`u3`}J|/8gb%GG;9\z'Qdp9 b1FR*_p걻3Z^Q<cV& )9 PZX>IGݩ y ԍ8+xTQ-/pwr3qАYXcg+GL%kQ[D. ~ 땏 *Us/LhZBvB{&Ÿ}kjUطժN Ԯy~/`†z;nuSH'Uj'i"ccU' H_OSrJs`,Uό;ڠbLip]ԛ=@Ff_{m2o\*)x {4KuU!L`>? +Ru-eT‹-i @뉽?槬/xJ( \ף`K C;'0;S/S,_k vJ*}(S€˝@T&neG]_¿kåSadU^MFp)dNSntkCv0Z,rb4.&kQc{Fou+_Zmws)>P0"pD6П:%1ĘDU_@}z2YBNMOMʌ C$6Bq1U@dlk׮3̬y, | 7\ |* a_ZF}tbqbgD}@—=IH J"F$6k}z';gOU5s5#jc@Vmnͫ+ˡ1ws[%|Q!~aB^ٙ6|mD||X^lQ+ 5*YM0'T~ Jrݿ<FGVR/[ ?uÉa*xCNuCԢ4Sn)E`?0 OQd%ʳ^H(単^_Ah&b5B^j m` Bhժm7]J)K&w"۶T$!.:#D~ S>swK}t9BC.gQLGe-nSj'xLk@M?Vz][ n>F\#]A`DRP>p@OU-lkPME٢74w< -2/I*p"X?:21ohǼ{SiÇѮ_#Xh 0lQcT$s)+=X ۈ 9'pW\fA8}?c:q_H>DZd'1ַ0`)"O1!QwHrIVRֶpڄ~x⼼Sm(Zͮ`zβ˸ SAv,yFӜ`%bՑifn zXV`c?))? gA< kkT4aqK3$+66 H4 a=7y5Y[4(83XvQZrh6-?01yMpG޶ZV`ͯ\݄@/,U߁#!ⷶ3kRX嚕tQE"@x"{REi2V>niDbU=\YN^tSpv)G ׼p?7ԫ޽5h3~d[63z|WH춢k9F4JHVO,҅ *iNCy_%JL'Ƞ4&{׿kśzT:ZZ"ڲD7kt>?]v:f岹WgiIs䆽6խ)kqu\^a"9:gy+"}!Aa1s |D5[?*nkL]OVMr*˃2=V4Ř=vϜSH)x$ApϱL+cWq28l}d&8' Єi\9&}:?iNHQEB_TXt1c)\h,WиNn#V>DԊϭ k=8%O[%7&yTQWܠY(2zۉ.8ʗF,u($WDOrblM%yvV/pXi &/&Vʩ7rp%T/>ssH6?򺒟,'Q9}vڟ^?YTzgB HE`zqb7$_ VqR6}&`@](-Lh,7bD?pB˿6hkZK`>?^.:#.+MU6 A"+>L+U/ RD _O 0>kp*BL n /R ٧!H^ M(t%L$T6A`xQu7-TUG ՗2QOnWlv$t0](+HryI6:sm|:H\CXF~2_"FL!<1^H?K%C6hWxN힌uXbU?ce L</~ rZi;SlMܻb yI6"),T]KC'E":ALvNlȹOu#}6Kxc-H^LR<$?a+ 4l!D)Y\[E?!vTpUMk\V4phehi ),YF|Z3IiPk: VˢYk, Y"~GӀ 4ztz+ yG+L{tnL ,F{KӪjcP; Xby<]#t{4iς}7֥>oJZLᄩdd@!NeJQ7$97(\PFJW4ocwD\ W%Ki?Ξ*b*!5#4Q +qpg ڕ7"ć'5q &kgAUrTn9 8[7#Ep#GQ&{o aCq} l,Ԧ+rv^ECiy~'Piٚe=v&9$Ubs:OhFՠ1/Yw_Ij1/lk01R ِ8a_E:&4$>~aH:1|MT*-VTvw-ְk5[FVb]1IUcD:[4Kv[b{DV'C4%dQ{G2t_8a1Kb:[l:EZջKN6.V= C%p'`?(&ѳ?>k]+ECP \ikHEJd`bhԳ9I]!pDc}Q5w{e|A Ru;xSi_]й@X\4^[Ršˍ[dk# ;7ko٩9>º-LyC)h\b4cTrmx?u[6]:b-}do8{PoT'1&OpinQNxb7>'r=,` q1t2+X (Á)S |/T!KՎ< =_j6n tF6j O!#A P&,9\! E/8]̲0J& /bh|Q~q͢)t'֔Sf]w)GhºFnPm/~lXUr EYJKɖm)c*HeKZZrP0]y֭y.n'P.ٍ _rguAo,̆#r0}%@vK H~jtig-T(R)̺}P9Ѹ 9$nnε/QؠرX?3!/+uI̪ ʬ' U~TKV>*בAx; #Jwz W<X"pхf]C4Ko WI4 dp=1Ҫ$1vK7Hik9OIoZ(LhPZBƛ-%ZD~w,;۸ :XUAaj&( N*1PUҫDGJwut\]JQ8>;ʲˈvwCP vcDS;Q qSh:4tT H%Kn`MRИShO-3ك@9QՂ5|l$ ̈Q&? ~RJKv \֚,;j͹Qʊ`8)hySÑaƈ>R k:] QL]7Իp|Ip*|fbm"'P3Q(TC^,Y#i9Gkӥ0P,UֵxTljE2?%^&N[2D1s+yBYFُ2-Zi 32+پ__XI A*vaY+vEOZ @Clӿf}=@4Q?x-o72@\^+q;y&-If wF ˜m[ ر9Tl?xm&yZ΍H8,_Ӛ_x>[WLrox1lJtxr\|lKh3Sٙ4'R;݄W)H%)ԙaI_oT0X=9[9pW]_.1 Y{ܧMw$:z#EjV![Oie #1 W!/ uJ+.,cSR$Q![goaZ\%{>04U,JZZبwJQ]Xn@ TGʇEY0%;FQi B 6 1l9<^lqh怐cHX!"?r03~kڸ(kDRݭ0LY߼G[ej @s'泬Jxn8 k`ceޏ/aԅ>O@/UӂNJGU=\㢎l >LEQbe`_-^LIZ>U)* ~jhvoN8R[t^V "0kh,gLqyHAYŤ~ݫ ._W*/qrZD]2 ieV >6OC" :GcT׫☪gG#XPU>u_'^FO@DA:PC@ʃRhmUbte޲fM\{ڏüUH8 f7qE]ArZm@j芌ЗF[bR\䬭 ocRkհI?>ک.Bj9]2O)s2;`fB?OZÓȔӡEc!{~\9:5jk ZSֶC9trIѳz~9  2S23bwnP50 >eOk}!V/Ze AS;a`bE㿲Z $gȣNn撯)pP^f]ӱ/A~h'w"T+:h巟X&7EgF8Dd,eMC-3q&#03aR~h.lDK<"`z> %:Qڳ[_Us̏wϋ@8ډЈ ybp'Ta k @(ⷥ(GvB42+uM<* w,]h4_o/eG "E#32)f5g#fnTws^;\ڣ p3ZASLoHM)fMaJ3u* ±)g>NRY[lSh<i͙w/(5l~Z*ީaTO\) -ԫ{}a_8Tク/1Xto>bFh.x)C_ljr jhH&nOĆ6FRu Wń. %V`26$(U^y*UڂH҅. ۆ"4_5/:w,ӧJU)252;1cm7tNH ߏQ}z~,Ŷ",H>:# [ ~H'8mrD?/ľCM J|$FSzq{S3ė=M}7૘CNZadxw?uE b/񿶑&X_Ԁ28TO-wXZq2=:l9MQ&VI9P#@~MEéVv% R3mh淄fuF)t;!iczM- PS^I*4&zy "'Ho%RҽN t KFy2"w 4ez!?~lj8FedR rY 1CNˠܤ k{"Gc ff*&-f#j;[y%y"IHf[KՙO w LoV>\hN6lvG]ao6'#cRgvNRGE=]6F)NX#3@;g &t|M9*~Q&N-`j0L_Bǃ#c6 -vٰsnfIPMog~1 aWB߷䟰mU&aJB tCSԥDvۄf?LNІz͖؞KZM}Z_)ƢUu[HeFE j ֦܌SWcn`zTi!ھ:6E{Yӏ:+F6lUdߦYG1Rp &EaQo0>^!x$MHgDtp:*mZDkT7 LY̺FÈ3HbYvǪpg}+^80t.Ȇ@&ڷeGrwXȅ L)xvS럭G(q|3ÖmnؔN~#:W5vԠ}&wS/wζTT07o(wjBKvdk0D.P[GY%-f}#eo ` ;p^X USQrM8Nnϗd)mf~ꪤPZQY]?rtB?oGF6xi?py ~g~u+c5- 9a"nL.}XP[ⴧ ٿٰF@uv\hjϹ͘ܠP>\1Q՝<M{DC!`_0lOÁĿb@'VM]M{vڍ$j|rܤiP2Freh- z<MD =]S-AC8g*wu wg-[rs$ʒފAFͶ`ٳ\(=): [Aܿ3 ڑZq7M>}'o$ Y`[߶RgjWC!*!k>06Ǣ"nDR3:݆5׎Z`✗y@0±'j˚A}k30`hZu%ȾU4};9upMBiY 9^'.FنG͌~L(͎{{\T=%( u,7g2G(xʈ.~'TNo{JQRAG0CbX׮dԄKq jPwatA\);L~Lx/:j]9As91lXH0"Ij-_Iő~kYnj&uhD˴WRq&/]Ҍl&C ݣL=ndGe^ f'Tl+jͥ.478c2s,BI~cMa#sSS'Z 1 5:7,5 JX~1BMB{EߪhrB4C̎3,51ZЛm|;bSL )EԶ87t''#mxU Z5!U9&~KJCyxU`tVvn2dnIrl;!Qx ICƎ gLnkb¤yK/CՄ \nz]hUFf~Аg^n&Z%YqGc)/`+Piff+msxŧl;Q%&Lx(>ˬW#/<}e2 =Ir%m1-\3f;~U w}bxst. Z>=iWLQUK 0~AI'|=2V$ 8˺#øpy>ZPL6`< ɑ(zל”$7йWǸnephתv|-hWU\ ծ-^tLywJ׌眼 *0NPYɋ:{*4rh⿃=Q=BH"۵w&J"(N?S_nqU_%N(s1`DӠ?]Q !GDLkA3l@@S.L:I8MpBM eA ռ6Έ>83$f4KBLm3آ*Al8NB$=V}U5!ы-s}4U-+ivZnEo?@Vl(:5o|VGew0-jnrayLu-2Z x:*Fw86{)f:ͰS=)O݌ ̆"jc&R>8RWSrSUw>9hC{u.~n`s=cϼ4y8kӏoŠ 8UƠGW2-abGbq JtfN YViFuO Tle [7ACOScEOLeiT#WQ$yO,uTk[Qzyq!u"̂e)h6>mbB/ns •3Y 9K0'fpMsHYy7o&Su6»oWSwPK1qz5)/ q#z1}`m@.H]~S"V`/Z x{lpu-҇sӁsop&5wɯog䉜rX5@6-6@Mcnr!Pf>=?wؘy|HuSovpdWdK t_hA1_ Ŋ~/e, #̕r5(vo84=N'75Y}kK3#PsItLE_ (+,%c)(:] ~5ʫͮ- ,DcC1!P$ƃ2'Z{f8/,C-qbJN/۔D\(k"U ,97ڤ!颉Qr[38 b%ŭ|8Et2xw/7&9NЫE\o/d}`taB UyĵK%Qb % m һg`|]~LʔjM e @L5sfъtb/a.5Rg?=0҈F(U$4@ʶeRlsգ#gc hgdWNL3f8z0-Kw L:+q瀚S;P 9ZM',ƾtiAà{nSڮ.X ɬ/IZ ^W,1.#6 pƵ2ӷiVu/ 者9Sty462)0{2gƥ@%ql2ASlVj%ˋWse& B\<{f.ʒ܃U=˙6E:U H) {]'Audyv#tTzUM7ֵXOoNX-A*qIېEF!چ6O 1 ҖTPc)HH.g~&. pQie2~ObHRtŦ$L R(de4PS_4fūFJ5 lt%Sm >/_$6Tc+t׮tfK}>Gػ-񁝡7Y2q!7__ 6I19T/|ަ9*GNBgC!Q-C_Jwhs_a&39Ml."}Wj Ǽ eϳ&E0vf$2 ֧N'-Db6^VPcM=LX7JׄJ>Xve-0p"!Գ4V!M=F ɮ fMu*3^Ԗo\a_S.T݅@tւ?66+(Wt! ϗ`uw.QWtj{ӸSiJ(#zcX+R%k\Llȓڌs8&Ȯٿ.l(ccTܛ`vc9I+G'YCro{rԘ ,!~ xOu(S $Α8G>ABe r `Ii}q~Kt+iT9.WcҊr g-ժno {ӽqi6e8͉5c̸> P&p#\劾m5#l$e2J4r/Зڂ!\cmuXzykG٧\n0iPxvWoÂbBA@9ԋ,3{F 2Gⱨlh! irOQ[/E Q0#XPH}9dXRs;H,˂5cTw9,}{19-qZk4%k*Ԯj+.``

нyA37^C8؏]Ey)u^ztM0Yy#l#.P!a֓pij^InFM-F!, =c_vd%<5[Z.d%''/m,n\ǹ$֗[\*99Gy'6E~H"qP/by(x:fu 몪sPW @DCM +i MH?:;iU!ЮCV{isӤ{ ׶lr kaYXVSJڳW.u ~F]%v<j _Nԭ+PɄ.üO YAB^]]kL9eOK:7-9%PJa(?P: EbT XƳ)#7WS iF*vG0AS~>RL\ %S|pUԞh9"Ȋ'}똇rt; ve=:d3a&ie^KEkaM + d[HR#%RvI Kz1Y=#\KHn?]-2ϯ_"F[K{?Ba͞7u+-x#qQ۫Ap05eH!nbG87.$ņPI_Y5l:%3 ?j^/Z@3nu]5S7G$[ɩ6k($2UE3"9k.[3wX*?9Lvc 8!_eЖN6%.R׆@0O+\L,@K$̐@\Zyeƃ_=z)u!ThB<NOWw BabpD(B%Y x6aض d n]Y0VXƘM] ¯!XuNH{=2ÈqNw0ˍsyU+ׅM'`Ih_jswb7J4 Beeٵ\Mn'R/3DC79XdeI?V>E鲍&2 19oID!)[y8"Yå<%nhl'u \ݙd7M] X mm| ,2; ? |IEi2 Y 5t+DUdzB.3_}ޚ/y["ȿc ޠGb'A^Z_?ޮfl'p7ЏPMP<,Yr<{}$w;X̬|жO\C[H ӧW S?J Wv'BDY9yP/ilw֭$ HɌkz s OڻЎ],15́ڽg)[]~*AX%^W 1\>,ZרcSUq\B҃W"H8 \~b>& {J ct%Xڋqk?}#gb.XKl^,#듰 ;75 o"'b"Vvx!rFlYa ,⯪Bd nv'Ih 'gRt+Ou$Z~؃QQT/1#gwl+sw`-&BmuhLVPyZiž0E{!"8V4LN :-R~ND#. ^\"|r:#k`s{&T%ʏmT#4#]oizD*~'d./7aTLyRόJl~3mpŶ,TzYm`؈ܿc(U7<'Lm"v] ߳EuxPlH)_Ar/<7-Zx7А$yl2!sM1K'#pԜnj9jJ#x5s&Z=$Jm#t:@]I$ "ߋ`(*JlUTH<BI v™7ȝ9>T rOm|q:Cb8kF.tz $dE%G@]w7*nbvoXcmÁk<6pNޕ`Ypjs d`xD VbM_OaTj!7E`!܉;L ^c;rzQh6`q:y7-F}zf C2,fFˊSmeC$ї{"$ym}}AH<-mӭB_I}7lC3Md}H(Ӫt6`WDZ@Ɛ#qr+ oZ汛v:`= %MجY.ua[2 Pl9b%Ɖ!4VIq%JLΌB?A)&txM*ն[|97kwk򮟚9.f/OyJOG%v&X-ƚV G/[yI4㢀ѕh@wV ;r#i'K;l8BG,Awq׍j| }D I!D9o \?m>:.sFH|2(tPXF”{ 7T?L~0, QC$9d:Spd n) q2}P/{bҌ#2]f҇z!i_頧Pdfp ;&^5 ZˌF ~4Ē&o#޹,4'27dۑ%AiNXhvh)=ImFE;}$\wF 'MWWz7mcSnTlZs k;]'Oaa43]⒌.Phl(vw 0sYGu$"[ G8K,0=a.{R?^ S5kff ݶK{qͩf7)F'qgT~ew,UߑKOI+b][=DZLjm3%Q+ a c:R tcggȓipOkA7Ą禘KRX%;ݶvhc4kL<Cc:YpBĜk Y)sD-S_1ˑsTdo[g[Ss?rb-%b2A`jT!m>(dC%3gˠ5P7T/aF!Ym2 i]窄&mUw[ɉY:C9gi@h嬶]5YR#Q;6[Ņq.G h}:;B}ʼn2( ¡;Y8/HU}V95Nk6l~ 'O5> P D(muojkMW_CI-\98zMb:% ٍjXgV>1ٱPuJ iN!R! 1Z:}J\TO6]7sv[h?g*>%2glnYpP ҈(k+kz64XkU)\hU"2Pcpe'B#{, .T88q{O PL 7'*CB[0WNv&M<cSԻR~?V*U#HbwPZL¬wیE%"6E^ZsLp:_06(΅*$h G\.c*i!TR3H5{[cdLE1!ok!XKX7qJU|:ԣÔiUׯ,SdXʎz'sT?2ˢ[кd(7Yъ|+{} r@ Kſ+ j۝/@ }ݹj 4 p  PaȪT'fzY+uFݥA#HUl`I)q \͔#Մ@JUXgٱay(#xqƟ& 5.TGu)8tAJj ol PWw**]G ihu12PCnrzġ ixxBpu mVb8 KKn}_r3{mH{ioƛ|?/Y,'HD]Q>MC!}UNZe,/ViҎ4(IH.Ť.WXYA"l](ZA mJcPMܘD\|0^"@>luE&yz{sjU- ͷԇ13gt.=x/WKK^N[&Vwj'QϷFR[: I9>VeP*@ikڴts҅F{E$w^AP KxyIpEm%"x7jנ܍/"׋gfLA\X@rRF],J2&]#]}Z ԺD|'FXZ Tϫ%N_BRk3$x1zՈ1H,]\SlFM/]n,/l}˦,8 zU0dcQ-Q|s8r(elU@\9#Sp̤ub6hgR!hU_st_<<}qSg~:}4'98Vsw2q!+nhvv1RR g">oͩThDY2K_b.<|N?籠 \w?w>-uR)V0zUġ:wԲ1n0nqm|ql;O0j_XQ\e0oIu,QO?əwvyE}&NM w?샏G@_FO-_W Beq$/{LN)ͳ,O1JTRp`齻JQxg 트:Ÿ mF| @1QufhBK$T`#QtmaJNI;pU([ɴ< Q$&( h,9sØ4 C9F7[ƴˁkʨm!9ț5[1#&J >BLJuVw}.^ $e 'H3ꪁع UI+:MHұufU3gFgّ+0]|R%˼qcZS_ 1hdwK:M>l4 ¬t_4}޷awAK1BwG{ihy񖣀'<"D]@Dmڥ4:j3j9,T c tMZ*pRR'5Y9jvcQUP& Z)O_ˈ-XNTnRAX|L^߯[_rY˯} Yh>{o ̘=o3`NzVi)fdSu#˯p٘G#ϫq~-tZK`g1N?,a<6d[`"e |= a XfP"nX6ÿz+VdK7_Ԓ_P[p[Kl[hr=/Cy=L>m;{l4{ӱ|*SDFA%t9 -&6"UMc Y`6mF0Tyʮ rsB& {;蔌*sGnmALg+ C e_&+)o\b.db6pSkN[yZċ r֬NpX̼>Ԏ̮ a6% 87nNNj_<2(767\&OÊ #ڝ':E3R-$rYRڈڰ_hV"@s:UaT~Pc}Ẍ́}\ρw-J%~+?H^& d誮j}0j"\̓n ]s,kVPPf0)<A̵}~T SLp/N` Cb^>#.u*'5Dm8˾{bۂRBV]JuY 40nPyhf*T3iQoDUur#hXL+UVm)[5XBQTTYEm&(!vxc_e/3֒ L_})p~ˁnX/J<="}DH:G_^Jr8i IB-} c_jښk:2wۄ`3 &1lH q eaV7?Ѫ"`k4t&oP~5Bc'T.:/ĒI}%Q/}k*<gbT5 I6g\e2lQ|^ZRF^qfg$-|tNN/ZZ.77N ]׶nДM? g܃[M Kskn[)_,zpՠο _S*+*8eͿ'mcQm_+0{^a[U-)w +-}>eaH1ⰾL||.(v?x0?OH֝EBNKaMt Œ )Aovf4y qY0q"O ,RWۊrb P1_ȽUZ"+Gh$ӞAB\KV,ʠ땴MY>k0$̒)SN>20Դc[RȐ(]\!$Mu%e{2Z!*H{N'q~0%h>]YMQ.6$1> +:(+3Ԁa?)iu5#<1Av"*).iO7YYmV'Wa5,}9l'gÐ MC3.jA,4٥:㺺+|P?JJ3VxJO"3 tBUӈAj[%|?@ciXUJ9d[E/,0?¤uLyN-/>38#ơUc<pύqa@%W{<<({@S 73eh\~ "}lҟUKESCwWyzGBw9ncy.[ A1ъ(*"sLR 'HXZ w 8o'X͗#H.kk/ p}l:|0 [ޫM!%j,p"=j2Dp'R/ R\'/L_ HuBQ-sOl+QD {/FA" "O'k-VᑻJN|~ɒuG9M4nd>:ui澔xˉ7DmN?,zzUT"4PC9R&&_uX4aFFscTs9:0m0k9se@U&2,AF>mMz:FثF5B ~ۉ41s塽)X{t'/?c'@|/w΅i4\?*|Tp";+8b^7 &-Rnׇ^Ä<n hxx_G@"( ~~8\)4pyY \?) 0gcL;G7*"He۝vL$8ɉu~4%(/5xADDAD.rM4T}Q3{^zC,68u^gs˰oB9|ՔƋnj.9dL3_ |zϕk\cTTcӞ뺓w~4`jQy1 ×9/>ˮ8r e9&׮ßXb3m1 \YLJ8R+A.B}S!~13ʐ0,CS;v'{F`^U4!'?H88V~В i5|'UG+0ۨH4]tDl)ljLau788/ [7@ׄiꔏC]ޝ9WONռ.lC)"| h*LHMqafOҒ9 }ӌWA@4027/Мtq#{=aʙr_~H^~1Q,5xv/O/4" 2ko퇆JZkRv߬k)<& 8;6p]̳ bh5DRFĜRx'm;AzG(G&5m$#6=!W,s't:ՀCg>8RK_%V&/&F^GzUػ/`T ̺R@/aE (@b_4rsƨ#KTJp_Q$r^?q+utw]Ժ,+Iy8ˊ~z@$|#bI8&uSZ^QelJ[F Eizci(w׾O-K%,wůi5?6Y=A?d| \]DjRq= {\=h,É %-Z@%03ܱ[|pŃ]q#JmO([Mm=uRn)qξ\>h4%Ǘ|Tc^ yCI~LR . i? S6ZK(H3c=["ul䅤$,.,^qnƢ"^M=XPH'<\Ԭ8H,^#voA@~%, 3i8 Qs].tmDò@z˗.&oBȟjƐ35l`U x>s^ƽ 2 i_ & z^YQ8ibxP^hf\xT\LmdMdj*fKF֛fF{H j?8IcE1/$d;Ec蓽4e;S NEB~#C%T1qeƴbyաk`k^B%e~S5EvS=+yهQЋ0 / \Me|ĢYrv1B18~BA9;s/ȁ# m\X/e|B 09Z4⏄ qMDgtu}"ܶ.y\ 62iz! %4(/Dk M.1p^"˵S#RWqĕt̸ 6ŇVlVx]5ڞSzffwݦGYAܰ}#J>) ZNAe~ՎSGOӦNK [N'*j:}Uא0VYp\lV |!9DR7뜅S(t/!>/ ^u*n;4;[Vn5,Y(OY:/Rs 4L/.?(d>:3-/Pn̔(x?O^A[W@`측F{mYQԫxTTE؊fR̠qO( C.VhIp #~L)(ێx 4N oȊS3cX05.ligp'm5^H pbԆ|D|f[* WڝazGq{֡m uUۗg}?C$DVǽQu:P C;55)|%`X{1\a!Vq:^Wv'm).=¡U^uvkA%p+-,"{lKwSC 1gKY)Lk2';3 IBõ2/۳1n[xg<2^X'WgCzױH}|CQs,cA븹toH뒤i߹e4{0Y`0K-dMw RH?ݵ=fg?UT"#*F>j޼Jmg;7pĆcd 4. YS$MZ%"1ZcA̦vhrڷ <#t鯑5>![`a' kAA@RnǨs3}+(RK"Dm2?? g2)*c #Uv:t鴴VlMSn=av'|0yu_ݙ?ZNۧ6'J&%fi,6+ A:ʘu&7m%fR*49^vNHqIe:K M[> sl:C`:7KEXz{!-GdWTWsg@Lr-/>+{ɞeg:ҵNL-=gN(K% 0Zy@ GR7 rc0,܂q (:if"jG^90(| C ڔ㵝tݚU^ DsH$[xU(}p0ԝPCTn00Kޡd}>zS`:C=5k^H̳S/s zKcW%aA)bR7MnGcNq ujCPf/@5Yw J9 w˹Bst{խֲsU+ 9BsXۭem˰\ qU t~i9ޘN /҆[BІ7_HY=y ̌ [urlU>H2Ťx?m1 #2iX`k*w(3(,Ų4FruE(lJ z*ji`L!{'`&`-Z TPÌXM^ԉI/:U 5X3yuxi:ƴ^V6E{y24F, 8*[go2f,fX I+r`.ss^jooqK[CF6]'-F~X@CxrPܯ#ٖSgc޺-ތRG'9`F>>=Z[ zm٧ogz"S&nYM[͢wIY.RD59 Wj2}UeO3dw@<Р}FYNdv%zB6C2ij7~Բ+"9gz!h4Ņ<8!U3=j{*4'MR@~VI*׉TԅaƗVr/qpzǬjy4 @9N. eI}LH%,iï`쾡Ss4K,^Fݐzҡq V!5cg~eF*S1%Ȑ80+|EaEA~ĥ*} xoؒe%L|d))9=N\J]n`iVkh:09e5I& @)or[TTd-l$p>퐁T_<~X`TgSbdmq7KNq51j𾛹K<7;[Mi-BX).x A>6t6476˜M!(-fr@~BKd_b0<ܿ*3Ey|]Kuh Nl+bC_I⤄HYg$9W;i h)O;g{ ܼBL{-'U8]dR/--{ƝҳX y&ΐ=W4,qZ^h.̯܃@+Y&CT a'9؁KWo3RLrg|9k<U'L~ og)cSkN悺F<.iQ2_H^t iRK( V\"-w[,>^&`bRf|[Ā;bKvvMh R TLK .zҋ+262o+0W\ewzGO)\ _6ӽY]3+.gs[vַ4<.t"A}mDQWe 5iY"-U(#Un?Su Z 62_+/fW;aG8fS.#c3  F;" )˕5.aRT:8=m/lJKw މ5[t3. `Kwߐ|'~J(̻(\Bx/|neg\ZG)IIUOW)5)s\ nMSRA;Y !LLƳEkc4LSvN4P`Gė"q#8B{&.W|$b+Y_l$!"[8 ^N+*pҹ&نe S?DB{[ [Xj],)ػ]o/k82Fo`zlVFJ EVv>ê_(.9:6ƌ3['T='gx#m.Rtg2\;"*W!**D#vrΡtihn| Ci5Ӂ^g;xn0u,H[uM<a~@:97Grݰy=$ofmb_xе#j,Ό@fXQD0&??DvyhܣVE1tV o(jA H.JsTźc$ɐsVvx.Goo>A]1[J~Z;2; JB;Ea^[6qp{N\{+~BE9!n *7"_6u*e~6=e=Zzxq 57לŎhF3%SꚹV'γy {WCoNc(?oq;ZOb3f5?}9EPe b~,ycExaT҈~lom(n\خW"*խ2KWƴ9ՎSNa bm_P ]WIx]~B{~5Ct|dA7XcH<.B/~ 7=oh<(ZI.̒٠ɟ^g';9*DkC 7kL5ʨ T )|YݍԩAS줘O~hE)W&jaj50C1vY7}zx U 1^Y 0ZÅy4)F]Rsy&WBV"yJB t*'yRQ|6Y%Yd  sLgAõNn `jc'+u`>T/`Pi5αQ{\ZfH,AN_w0Y~yLor')5'_׹+Q\]`*^ږs{ׇe7Rg9VCZBZ8F϶^Qz2x|$.Qڅ~25!<6WaS`r?E=,Zp3+Ex| ̴_ﺏ+֒( Y\Q8B;Z>hI_oA,'&/LT o^@KJpIe椻e9V{4hM`e2onkDqQPho5]2s9V:f&01Y <@ibU-EGdZP;n껂ºч?Zn(TMd/46?]!R h8dF(C  s22j W6c=l7d=bg9c19CB74&@p kq^M{xVO|ՋgWB:)9@ Y/~#DBLs`BB:^ Z[eNt5;:EFuxϲ=Ҋ*Z_9>S* ]kYzcZ~%nQ=dLw)C %KS˹SG3P9_ *q0 EQO}SVy[O ^%jA>0>_87ppu`qGynVݼ+H,DdSNM?ʉp}D_d@0FSς>$J0F*%{/EҁFG8f-2a—>Rp.wKJ!Nv cq^G=4,sK!F=R3`?~L-$c L DU$iqj9&)YMKtݤYCBvE{s¢3ߟؚ\Gg1)n5lca٤DdW57n&avCl)R=>#wdOC_>(~˞ ] Objp{gm.7m)QZ >EB;WpҺ*_ҾmN(!K;1x0K&%%lWBJV:cAk禚U#~ρalOGs}߉pNd_ooH𕝲P%R0>-://.cI-}^m-ݗ20.X?qvdX2uޛd6+DUdADe2:#ƈq4VF7QJ8KG2Y34z.EilScz˴]V2XL6K aGI.3^FI׶E{“i9gųt.-aˋ kxA%\+dg0BJ΂;CS25s|5Ht_B~Q*B<.<AKe&ΩV#@ɍ|;H񐮓8ꛯJ;_a-x2B Sjy٨g9m_f̞J#/Q;]3H#&-{bCGgָ$ǂuLUqﴅ>|D|ǐ:C8Y"My w9eIh?_zNI\Bnh CC@Zce.n/bP@&x+v>f=}=!f1sHjԱk2fCmg @PLŔ%#TAS k83dءlRMZs+h(̯/3/ p@cݓ(CgvqSj1faffJg(z m=w@laLgbk2p'] nKE}DIJG(*q=uQ7Cή` l 62⽹t!P( /8)ޮQI64fW^H]yҶ\Vg4_E @Bi-4I7Q-z2uJH +;lΑ9]g+Jsȶ`LۚP -_[ <\.֋08Gl&C=:,1ڊ}dڹbg#^U%*1YCs&^{GiK_梛vmq5>7{zW{ik*~0{NUO!p3Cy{FaH8?􍏘훓U:\ ^6,fpP3{W i7f?"GlSw+ h܋vܳ~;z+_i9իkјjOcݓ 54IT LyBEl?H%ɍ2MME@ȂE2DrgxÑk [R;d4P5Co-H/a}D]^<˭U>ߵ|Mtʉ}PMpfbfҚ=eM/N|^)9/Wv#\F.0HπV9b,nSPd0Ѭoȣms[[.Pc(Fۿ‘R8N55pߙ:!4?:1Ѽjf*~o-  >ihʥ:AxfpﵟyGX>Q-CUY&ڮݭy~eUs5bo ub7.Ԟ,nM<4k7KU] O OtcaNba{eH 4_lb^G1nk$W°rV^ΑC q4ȻJ`T 2^tc/ɀEd_յ{'($-[CFKY'?%x  <p-h՛i\Љ}ai)y(|ra {`MY eWHAݝii/i!ӭ@umƃ뜯DL>Ҋ_&V*Q1LN&{-HMϜd]Ɇ-wg2/wW7X(/%n\5Ӓ-*µgOELN:[:Չ]|%^=XI[{vsoBQ͂YРp8W_tc)a? 8kB)j2 !139vYG1h-wKZ",%`G uuev/) W1QjATJx^'`zxHbǠ#C)l;2nEء:r]b0P2@V,56ykC1mv^L3z}!}%4Pi_ds~* VPr5D梇L] OBVz0&[| G][}rNdZGk+kE8Y&*?ꡔ܇.zk8*P ĸB{m.]l/t*\7{659K;T%r[7Mݐ1^ǩ$k5ZN*ˁ:[-iMkJp7RӀ,^֝9pn4 ^'32p{ޡ_lM*cE M3(.jufM.=+3FWr«Pf@g9S/ӂ?nTZ1-K`Me/q4y DSciWWeN]2^2_cYJp VU+ B1T}Wwʿo(Pr-V+ָI&2/A{A]ͦG[ibEN9]Si*xE]$,$/\qB(O$@OCj(ٕA*7Тu42p3|)VzK0!9$NX"<eW~5@s#OiCM85JeT _oےK!s[ pmf ߷M/g()Uq+{Nײ'. ȉ?J;aBu|Z}Fa}SYk[nׯv % >p.D ,k_vcd"m$`#U8i3df>LjL0J ]Y}7"]es$.6$B 61࠮Br xG]As(!d&N `?FWXw+;ਸ਼&;#~<)R7~k;Po;-ʝJl5sLBm,`EL3]~-E6"M q#nL!^s^{ٓzHQ z SGeybh[R6T*\ûV8Jrfd H \[Q8RK3K)|ppyS##`IPb(Za~CvJJEmCtƐowU D, i\$B{Wc7\0cȹŐ^ⵓGӶ0!1χ<9p6uUtLi277ΞZ̷.Q9#bx(=h9Y;n .ho$.)S%Fe善+Ah'nT9BF0G13)\u7tzZ2㛖(GrM)|q>)&z6t+Po ʇ|C >c՛ŲfXC} 3SU'pW;΍lD;[V-Yo,;r=i_2$X4kzӢ}G8_[b~sB֨Gq>DOox5*WM`T!nЩ;6 PwC^N!wf3`g6#<6WVU/1g:Kl f5M-HL-U ^Պ8j)UsG[#HOc`Ͷx‚qʡȧE +`)$@L,M4O!e1XLV+ Pp=*=*{D,jťЄDi*>#6C_ V*D7k|fEXUZ.)ەƊI" I#vAEjw y:Z}bp*ߟ6N` щ\yI8q KB!#9#蘀6||6yYKY_jl3Jނ2^gOa"#V*yA=,$,taAy%Y&sC9ß!! )/F4PK$kħaDXAŁ ^>K4ܫ;3ƻ 7? vao@}ʀR5rk-~k95l[ :_3c,Gj䴮Jx9KeY3\Ig}iK-6ޮpرjy-Up;9favUpl͂F5j.n犥Z~no f|BӀ)YJC#Jg/jбQ,bc` R 3ui 8ۉwȒvDh}Lf9!Hu$<P$jq]~1\&a\ ;GEJZX!O 6]4Ӿ3B%//tDm̎ʐ6Q4b ԻyQu *SI@*H.g 'Nw}9g6Iv g 6C6kJ8p{hV!ÏJk7PBf^ӚE~w\+ӄ4&O~R=ynbONĒU\Xcq2p ŀ"0p)x7~ Cי|!ʱʣkT 0ΘRF8~9lD$q\~vv ]0s+i--/ cLcF? ♆%@笖ZXd+{Zxk)RsCv["i߸iA&PXa]Ɗ3gMБipU Ȍ y7 qȿqEO~im)K{!u 7dn=6/L[spf2S`tEԷK;5pOBԌ@~Nb 5_*fx&!rQ =+8 [QkUvZ{E$ {e$URo@+88 cװw5,NH"!Ġ&4B~'`Z |4Șw"/ ]U(G[&]NA$_ܧƮI揟y}.03tqgm@+%G'U$tEBpV~ < :E, gf-4#-}`@B+6Vۂ\w aѼZVQ4[IWc')%x͇Et uDnb}` ûf2\>{$F- ܹ\3 ^Ղi4$n{&iF#kkWN?6Ԩ,!icgJ{`'P$@-L t׬rLJ BƊeZ7+0+`Y᝔`e$:~Ϲ־%ih/rsAsWVa.^Q=H$c׌~t1VcA_L@Y:zHP~M(m_ xJ);Avo?f>뒃PbM}7VgnXY%xhY "ˆ2r$J=-Jk^MdvoZ7̻J rAǶ3clˊwQeϜ=#h,rňOWЛnpՀV6NɁё89-&PoF{o(k<6gKyZcm,d)z^ 'UvBYlq}xW$6+AՒj'E FC 3qLԫ Dv$Sos9db$} 7{9Iq@9]V;'3pHK BwVZ!hD!,; NC"̸/m @-b3a$#Sˋg#IꃄGK۲9CA#t|W`$?+PzSW/(5x^!_]\s$\_XRє4?/yݲxll'R|k/XP $]yA]nE05h[Ŏm{ پ(^\\a$hBAa f]I$nj.^׈狱kko|"a%*֟S^xmzo!U48Q]bMYaI*w!-f΄%|L !/7px u?a5""$C6Ő6 9Υd 5s_B2h G%mFܩ'mt=~f9)5ۼNn;'멁 oEa) $Q|K Yyҹ(n>gLlA\G_u2!X,#E&Huѓ.^9wZH/>vo5 F$Ϩz?:̻PLƴ:X 7FWZ,x=q>FSdN _I}JF>zg'4nVZD JeD0գ8m -^!hFcAzѲzd! ,e;llyZFD,h}z0r2KɶsvrPDf7V8"i}ccVՆ[]Dw`CiAvtQ@8DHCk*Sf$q*<Qs7ZaiOvQ&󝙁Pmz0V<}/#d6j1R'ua:6j֔R$L/i8p4ˮH?D  LUlJz}IS^ܾs:1H3M0XK0~ahېaꞻJѺybe!TBfޒ>Y7X"fHQǘ(MbD-syqdm\!pBxn+KV'୏{w Cep\sQ8/~d^UGIP0% 9(mr k0E"H((zUɪgQM!qZ9qR"ˤPb%"vY"ЪrZU HEg=IlƊIJ67hĒ`s.vl%e# g;! zE]bK/^ {ܙ$ xv4ys"B̸hx}Zc,>Ee{V=n4qf6=p: :zUœb5Jp5wb-P?gmK @x)H*W3\¯U<` /:Q)bC 8{#:&ܜf^|>%XIo DˤM(0/FZ*]H-tIB!CCsyg+UvV ˣsfPTRVBwrn=#!S{< /+w], C wgn&KUK]O 3yō3<v S &,MɝćѷE&+KP#``x)5p*Rzxh !00QU*P,(նְRJTA-@*O$.du&8x,4i`9BÚ%[?xgTs8%'[jwIj8Q+ =3s\oI|?8^_k),(صsLRzǢ5>bɈڞ!U-awJU3 nXW9s dR^dK~S1`=Vmb3"0yH:DeCWGgR{ :?|[": 4&kL)߰bHʒϊjH Ep8 7?b~̊6Uh@ʗxnE0֞ץ#%3D$0Tͅxe^ԙSᇚ}m8DbᑻZ'q3mtEи1#עeI58zkyNB2ZW!*p" 3:Fٻ1 "-Ha}Wfm "6^Jkp/f(;3yF*^ HXUh!7 3 HbZ_x)Q&Պ_C 8p9D3jA5%,,B%Q6plrX= ;"Fhs nWup ŁXtE&?PO$<?4nEBmUfcY]!ƻѥaIX|䍌 (`߁͓YtܬP_`򯎇@Xx &jE#;/?Ld~BqM *Yp1Jj8 JoGbwpg#W_YUW DZ!xơiaηwH/tTa'BvV 7ȔР`!6 5%.v0.YX Qy&4Wq--H8T9[2S3;!rL:aZ{ig߫܎&.r4 ݣ6Ƣg0͍S _;M(P!P"I MXbi27͚fŏb8Ԡ<< ! )6ahm&bW5B*!кL?D0(k6Eel,,X![*?MhnG?]B<>ithy7B[ϯt}q@Y0ɐ$bd}c=hg>" şF]\vRl4l3+r+ ;C=]_uGn*tG6b:eܤpp5#]45MA4#g/@"ɚ1-:iRU*`ؠ?*CG=ⅯCH|&`̈a2Lx*ɿ[4B}.~SWuWgu]*d"Ȳ[_ 63i!ֿҶ|l5&XA1i@P~,6V.k׎5"Tes;OlHD_Wz2G$uЛhVX|Guama-2 (1Ѱ.C;Pu NϾ n[ x_}Tv >Z#7 ڞxMFnX|c-«nũRrhy+TOg>fm@tS=UdKf?_p}:h5-p|2 J;ɳkD/p (݌FEOE<[<&LҾCKe#@ %Y꫙O: ,@LZH7cbw=P'{wxu׼Ρ*:ulGClԯ, 4\q`#.Xoze1M@.]rk.!hi=X|Uuz My+m4trݠ8H͒ؒANF.7 qИUUbMئ0Zrc4= Tjтl囀?eZUtOkDXY6̾fLdUe txʥH5c]GUдx ǢR_}Q˼"IY>z~qޓb`Հh 0OZ[0\#.y彯1G?eGCwyhտ! CSR5pMJ4<9 (dU$&d+'FGۊI6rꚳ+*)+x8Np-PT7hyz(0 g+ Dnh)'VkeN(u#ao'ى`h%##z޾zԥ& ljt@v7pJ>;nq2zij"K(AӔL"-(Tl(R9 |\A?Df $9u8C3TDOGۛK}8 Pq@z<(gjuZ%]!*vZt9*eBۅdnU4DJ8a1&"@`|q^K4Ka ۮ$.&bFenݑ6ʩ^VȻUGE*(nR/+}&MLM*Z/6kqNQT v4 ٦4c.4Ozp fؕ=ظ=1%Kx Y!iĵ^+OX\G֓c.#Է5S!P&Vi6ԀvU}~Krn]22"|0lu G{+ H[@(>Ot .3 Uz5HL6ںw8A55*Msq}RϚC EVt&}T>ݲaˍ|9|_0Db:()B~fµ+.!rf)o~YLG޺mKD◬k~ ŏ~BPĪcO$q[L& z \+nTKopii*|_~ՙtu8AHkj0As5\G#b3-Gkv!D/IOo0@p#jxqJ(]jO3,B!NU$8kZpLU\mH֦,1<~G>}O)B$ժw&/~USa7H~Qe/^µ9V"]'Lw3zeRf 8j/,s^0zJ_A@\DX۵)os9p NzIbWTZw?9,VU<=2b i: {?|DpB#|]hw{U2$LB"J 0h9hW15ҝԏXʫ)ճɐ09d#ja6ܢUm5bi@#dg_c(i~dL{@ k c} @1<^z:f皜#uj$Q-\\Tmة&~3fӡz;U8+P{dPA5mp+ *Jm[en@(!' f~>/RNv`t%EhOl3!:OVA'r}TlG+{m ]>mY=uǡUHx@ ܬ6'[&T*:)FSYuVAQ[ʅ}]b&̢o%6ܞ^}/{ 侚dPFUÿ2Uj"1Wx|Q9`[~n o`Ӂ/=h-yxLw:r2.S<hr{1|_Ѯ xᜮ1ܓ^Uaթf@rB*#Qr߳I eJ_/2=Q^+c/`h5"T_BNE=p50sH*t\Z=9MZ[5Cn?TɎ{紴\g$b_D^ նZ|{ $>x^ږ]n,P cd;!k: 2uɌ34RvZwa{ [ oNR\4n`GCJ>NQW\LÀ!9p: QޥV|&l\sn)'D푄Ԟ^&r;hgXR 41f|_k _TzFg4P'Irwʯ9k P=S,>7fP0LQH A=6eK7Q?Uc# JɢDdIrH`Qon7^-'-(c4ڟm5چt9zKG&mEM Y*E䘺_e #د-{d e}iQzq| 5Bb2]Vkԟ )-ݟV?Dvd}L*n;7噤W\ Z~)TV%0zhaZ={2z`i8)=9:jX!Oٛ.V{ oSKéH҄B`^?U\ 9w>`\憨ꦶ~ưhPѺ#8J-.% C"S}v$|VW4~I V|Xg$+904 6h ȄoS45{B^F.Ƙ@g`ξ 'Wf!9e˂/FmKE`o?X7vw7|Oorª݂#s[{Cvuoh)J *_7Rz U/n?KBxHq# ۮ!Yynp#JF6GKnQQ($t(;U RYyMQ$.L5%!_ {u; GgwF b' WYU;e@XЖ _QtN+RHe7X<OJ4M݋1tũ0"eu Di|5r]r݀!@rqYmMRҎ5T4v眦Lrp@v7d3Y O]C(#n7Yoϱ%wKzP}`ܩ0-m)w(`1ëj8پjTwIEP7n)Vw3{tyۆ'$׷LTM@DD>q ҈0wjqMc0O >4ftQs"AT?{01<ܧ}- 9Y|M/S[RʹL_NEvbCV6c&H!LQ~"rą< kq?u#udm(c'2`f` =?kv> eJ$G3;d ߲K(k#dg""FQnu|q).(V *qVovo~U 6=*ꌢ9:$y#/q:ӣE[26KSzkn|_֩ے:o0?vQ Sei$K^/2l{:1/5N=1h*Ji +A_VcEHzS9 ӎPPnģNIϨa;G Aj8 n$1nIZxQ"3܉2$mQ+P=e7Z=}陿  o!=?kV&vP`l1vw)e;?߶7KDFĝ}ř7603`A|+{-Hqk'MJiE"fڣG Zn~yࠄ4J`H PY&dPD!ӯR'Nut܋)k}>FOlQ욘ֶn/P9e MmdGjK""ecZǿlyzR4;o+VQ܉?d\I 4y$ Zt;5c/-qzЛψ$jt1`<|-7q_͔0OI+ͻh6ʩaS&44yO_x2hlq>肷Nh9i< We ک8 2ܐJZboh~Jva}7 P}oHL΀I,w )r_Bq(Rf6j]kh@ GhPu$+Jm+wVڠtp4,W)K!Ti.:2T=W@Zy{ظ=08jӡ}e/C䪇lfl&[U̓>-V=8dbN"q/Xl{ęם ,}N2P V#v7;Cu(OHePLJJ8M̖D%:C$x\EČt3չa?<!bUj#©: T|c\ɴ$3nŜc̗J/q|#)؞ٚm: R)4 /^Ψ=_1'F>̽yu`;$JGi 7M:+-~s;i4B ̱Xm*zrZ XqW$خAAk<2>t ;gAwu=q͉duxഽ幱(ɉsy}駢+鯁&bD_G=Oi<ύ=6H4fW!23q`]DٌFSHԴ-$m0o֊F, ǂQ~ *S SA]CpY!%05` zz?Cjh+Nf$*ԕe1ai+ym.qMi3?Tyk>$, ?[~b(zJ-7RpE@1uo%e%; ױ/`t<Ӈj\S\ BwR"sNQâV2F $9]}jiv2=yEQ MT e:+XBkkkhbZڌmiX_%C%Cű[D##>z? VPSB~ΑmXdڷ̫Ha o=dt+3 CX^ie+[#5=E*OU쾇SdU/n7ĽH㠇2^+VܖN'1o$1 Un%5u'Q'T[_n'*TyDM.B}?~~X8Я@0v3íBxٲi>IE+7ۻ.?VN)5Xłaz1,$X?|=};|hXGh3sn|vSY3v"\ceV/r"sІ3 d#sqX9&[Ǻh y"Hc*AtiH=[|v)3 yՈoS6ޣ0';7 fXǮX1iF5fmBs}iڏfMu8B_jT=UT*Q#&wr(=E:f_NU,Xz H_P{f4-q.N&6kqj O9 G)B4\ \gB>IځH~."v#۳ti%Ţ{F:PHۈ@KB^Ek N>$"\ r,Ӆ,WkCSow}C:sQ=|MjDhz1%uي[Rxs쯿bIg2)TH9HFєݨ]16*{d1^Xx?Y((/c,9OPe}{k!q]_RFIcR\o}ZsR6'r[ú3N]GS4[ZCPe%^[Vr 5 #}E0%V:̑nOY4? t:;n?̊~{ͻV]t;zknr@8QƉT}m\)!KC{*럂\d$9څjؔD>  \<㓲QzJ!LVo#6k 9ޑ+$.10Zo4fekQZi0z {L*t]c H:_aV GC0,]([kMVkji8R[(@@PMflSG5~A~!,B\;~rP1 ϼ}E z 5Q ?Dɉ):Bɿb6ja׋J/_;d2Dbg4`MQڳ;zNEPY sH/ְ؄CN$Tk<a6 (_NPo H͎<-wZ@Џqw. J#Uf~+DARx#?ʲ11xKsj,cG{ԇd=JԝX0q'z?O4zI7j̘? XBR2$O. ȓA5+(4 1u {\PωUAC-S+ uɉMj:^n+jÀA'}? w ./Q;-d ӉOGxP -)94M:+W2tFH+ (d+8{&<^TUun`3FL=+;_?^aL(C;Hm  f\OnwA'6MQ?&QpJ9$:n@Z>VO֑"[)!ԶLfJclDܠ"VCěg 3k,iؘIzNdε,>;z%uGBv;]N͂wusŀ;S㸎EJdN!`w~R+R }~"x6ꁼ"9cR<:zN)aI~5%!0".هgb,5_v18ƒ%<-Yz݁`o1)j+Zdӓ=i΍ IrEFcuV!vѩ_*%x u8DžR<ɾGvNDzUueM";A2NN.. xsBfdzF cZuj(=\C2flr)؏1 %B3M7nP..z;-qqu\vP9)|JiWSWj'/I9.8;k4T r5K.vI-hwt~4.{A t_ 6TPj'$N}ŠeTa<:Iuv%29d-e YTl=is[eԌ7jMZ"]}f8/dF'%=.Wnٮt#+m`_]7IX@J󀹅aⱿ.FvNqjwM'y + ѲòAԲ;ѫegZfiw]X8`މPZQZZp'RD$!_^$3[i` &==:ISn{NQ⊟ζhM _r B2sjM !zՖ]75uhSFѧ7[&1m 'VݐUQ+E/:PpỴ:PvI=Z^ V/KqA1қҗ)cYRI4̉|q>i:R7?'Զ\iiݙ2+ά66 ZCFxXLA#WYG^]2J;+Frm^t-2Ϡ(3dʻ|w4팒:q9,xAUERZ\P<,? &F,w0g\)i/HoZK5+#M5QG!~SuT( D$ "G뉮4CTzvչ[@;oh>֪M,o3Rd6<}Ll34ٵOuzd]o漭 :M6JyΨyDx/=Nck5}oivsJт2yʞ:rG Mډq;IׯNfOI͕6FZ>Jd>|3@r>"DϹ>҂.cgn]j*D,9 ])87_:Gv̌S⅛ Y+^{SGc|MPN5#T 2g7daəĵi!p1z^/0bCh;69#xxaegT6Vh rw66!Q̞(G:sIβ,'Je#{wZ\ E kR XcAgqh`SX_a GfOKЛ`yt L!qɫr5Xxz, s@}?T\'2SUdZ?#x1kewjawlKHmv1n'e"0;6$"H|ZnQ<<Ҹ̄~D~7ӔAXi{5A'"&-특^;L< J}3[7rBZk9g cF;]# Ci #Fҕ1gl^) 5oeMJ-HbDQ]gݚٟD`2;5 m Sߢy{3u'P5~TP 5ϵn (uD_@+(:gD_CBa;{w'm@1KEA8>^jh+|ri%߿*࿊D;PD9t4M郘[E0i uR"1Aտ6ɹ\nerqúo J/l' >kջ^YW?`HH?c$1E'u|GgH>Bl_ycl+ i<-mqVas𴎙bJ.e1ඒVW sIp v9r/%fT<Ǔ'enhP VD^&i,#ƚL @q]/|^W7ؗEP![Zk&t$gh[7$neBt.6Q8mhrSQcO5u5@j*zd+bٍNdԄrÑ&\QAT+0y9vfMȸ.^Wcu!w.$7oIb×oJƵp9'wE*-q@ 3"a7l 6קFTki1Yn5g&K|EY^sdq=q{/HâpOHH> epMT WwSmr$, Uq$Kuų/Va.[<7%5ATǭ6<3vZ4yV굗؊S`zls)-A(^5jhdb^"AjWU}NN#Z &}h.O)fOl$tߜ ~q ߪ): h!s+a`i)+")wD+s,88lg/zod=֋.tHZkԣž黜ى Ñv]cT뱙B!{Gƚ36)5Q!Dv8gҧ$G!?9¾m`wf+]`77\1 99ճ-|/T`7R> lK;l`g\[NRBxm]Tg[˽EۍL.3ԛ\6 1si>s8eti< # pgnuA2Ue=o <$x X|ʻvl,_ѕp|/7i >L#>#Pww$宇?j gxDvjhMҘ$%z=S t!V&:$RTBѹ#QGA)=ep ({n .RtĢ)s5k L߿rx+OGLlze`#Qa Hx'KxG*,x&_G Sx?Ow-}d^ǷQ&oܡ↧f˧raX) 9Hٲy}g)R4K Ro[=Hel; gQW^8&ʹB0xyL?iv-js};uO>awjv#-LR?~/8UA8.IfM>x*ZiQ<#9fRߢ4dAYAYGBVzd2Z2 D'NWyh?7.Nad1v+,,(EG*+)ČYUR B줨"1uZi?d/ubɝtO238Xr@?eurݏKP؛5!,z`6H(fKAc@+jDx7 6A[ᄣv &Ot_IӤ֢-J˻^5A/ -}T/;<>^: .T÷5 _b&KA)ɻ4n~:Mnn-aLq]5e;!v7{ٗY2м@NܭJ Dm[Bt1݌qVnk/ űD{`uS,U=E4ݑΠP!/U +RfȲ"9YRvU˶fKsb^m JXf _gy0R Ŗ-J:8?:xA^{͈y_Zb16\z;]2麕a)ȞC{s@W"~Uq f~:c4}^H_ k3H <R Z@eO}`|2,,K,Ǜ[:M'[ 7DdT99U:(-k]| qoճuss+|{DV4'~D`oR5s@ӡ/ʝܟf;+N| w}.WY##fq-C5ԧGPMV:φTn>~}~B^2 B{SR^%&A{>K F*d$BڥlBPU5þ͆ &XsFVBӸtվ8)Aʀ2[\v4.neERДӏeHzZ9`RF:+U7Q?;pwe̐ͨt+ / h/(q%i0gVQζ$X0Af_o R Β^C[NxрNUc pV<'I<;AfYƊ%f`s4R!KR !JqWãb#{nđ̬B}pa_}DD?pz#0>g ڱw,heI fyu[6NxG=+FN3|&׺?d}bLؠ:Q H,ǣzo43Vpt( l.{w4ǾsNQp5H2~vNd>r+$`e۞[oG*0o+XxIt| kE1ƾjFDo 9eY+QNTn0Kg]?M qaHp8zZTcVհ߭$`s)cn/"G/lЊ' S3fve Iɩ?m@'w6&Lu%'gpZM7U: Hڡ/fzy'M}5:CxsOw%CkTLpV F_]SACY\K,n+ b>ʴ8E}DhF",~NZV5PN滲yK )~Ȥ]9ϫ}*h "2CTz@NuO4cdV\m[p` Gm}F }ߒC읃G[\uY2}i)c =9io|V9 >:6˻ʊg2[HԛOX1u d[CnfUtuS2GcC nDFKm["ZIl)< V/E = OK'U뢈 igS!/iPH@̪\|#ȃc~=~oJT΁k4D#V~:w8HAb/FSN4=TNĜqs< b؍Nԍ>[ ]*';ht^kIro\CNjBoG*zt.dO2k o`,H4uoȻyrDI3Үuumfa[%-:I!cƙb=/;Q!gbcGo~|o3Mh'6$Ev`V'x?C<[V-IΉƢPXEܰK4b/ʾV]m<FWZ;m5hFmD{yGR͈U\eX WA5.Px;=-0!X=([q<W\a Qi}d;66]"B{G#64%DH.uNu`Pxn#R6qCEvr,UT+(ǭ WATʥ pKkֱSL/8zC2;g08`->mqg/_J4' Frn$}.3b﯁Q͍[q,l{ (#7ٿGZf#׵SM}CGNn򯑭ͯ  0zVd ²Pj |wP6C>~C0Lb5e6{67?=(=,m09'5ѽ+3uNҢҤZR QP]EDAa lݚ-KԈ^ay= a×jGD i|EN[@8u4e>tȵ` #=<Ŵ^ҐzxKֲ̈́;V=h7clKك9*F-"MAE]cWֵXIvڴTU?J+E2bǏ$rxy h|/gj}'Ikm[)lHK4)sNϽGq>=$j,Zxi%$ȃN~.wc_W|1PI svP~3sZ5XZdmVAl)n|_4s&7A~VnyMsk2t#8=;IJ-VI͡{fY܋e Xe滸UπT-Dqʑ⮿Cϊji,fR>\[/ڻ_\VčGfz 0F]$RLr6/b)DbPUq:R9V)7,m/tq&!ΤmP%fw!.TӨ'|&"֖+.99>MbŹ~ӂevwR / O~he pxZ{bIkɔJQ k'KCĿq%O̹CpVЙHVӕ3%OXԛQggtuhʦ/D+uTN(8ڭȧY il]cA>CEZƕ0`n vQmn;"^07:<$%< 7ފӠLͭ%C,L4U:W3[ ly9k]P+LXEӖ C8Y_ܕK#6.$nbʡZk/=Ђ`Wh|Yzµź){QUG6?T]b>#AI.y;!wZV > L^)_4ԕd $XsM`#FDF#q\6Qov}+i Td}07m5Ujd\ Kr.Ǚ?Y͔ deD.%̘]C(QÝ .eކ\ӽW2Cۜ(f:ec$|ޤ!ť,"ׁ\WWƠs@ZCW|2)ŅSLCiƴf[!;8b#NOli I- :teQXMj_D# 㕰DZ3Ȏ~n2m_4 "L1jK : SaT9T Fp 7s}J>~养N^`njnMvttd*STS qLa7= :QKCjFWBV.srNOԍPCf51ଫ0. mL%6DPC7sTY2wm/c>GlXیMz:é0#$m73:.X 53&.B"z01Qt1+S0՛=2nwftҫp");[bh+id<ī ޟ! Hu8P*}RaZ kj`+!-Nzi ZqBARe,ډmTMgΓN8j`t:5p޻n!Zl-U}KVc"VS Efz@ۓSB Itv aĖy@c^OA,=ܢH)nB޲f}.W8[~s/շ)NW9+ww] K4yoqaꧣTf+QjRjwИ<!u_()kT4>Ij98lF96TVUALi[q 9V%ǻWiE<7Ef~|?0$ ְ1QK3TXD~uȺS:+'_ƠIGa{ODlCz+IJ؇Odn@`wbG @JFhvZGG^ [ sN 9jϑv {,usgr6VK:#FՌU !'k^Êgl:U",:40*{a \}H66,Eg(\#nLP2қ[F0EX_6{4̴uj,QX-E&TLsɣ,K׊Kˡ+էd61^}Ԑ# tz:cٍVL0]0z~O";}ȕ @)j'u ?0/,:XHzLp)@K<}db.t cpړ}QOÌ)/xȜ9Ku]׼\& uD4q]P2ʜyB#AYMھ" 񒼻Ӣ>v NC$-YpN~j5Ze1yϞH DZ_rta\m|`BTdho3qT ɽmZ4u`6P"A'L-v3a=CïCT{PXܭ񍢷F@V6|@V88uf Ch%o lHq$QresHb8T9U6+S_3`:@Ł9!Fdjy\ BF!h`$J'cU\7Z< tӸ+.-XϠ).|` 49U˷-T;@T ²NS8ԜEIOCD;!"1- "TvTx@+ﲃ-+2Zv X.<̠!{xjEZfƜEeU,P@pAA>Z{ [qZ^Ivho ?SDaךt~5dĀ.f?37-`,y J< hr:x%>)?T;"Z FY, ")KCF>1q.z"Պ` lf,Y+Ne$=Ru2F҆(Npף]Tw4 i,J:M m%(]T lf0xCW^)lC'/+5}IrrVQ '{s.[w9(=G/_%"|;ȿ)_g7=:iTui@ 9nGC'@z'D~,kL~@Lϩ7͆/, 1Z fL{(a8z[LjD5dd,Oڇ>sehaZ+(v+,☻<qc.yؕp(GÏ|J]ZQz窍0DC>Rud϶CD`{÷ eQ2߁sA1t00y!ܗ"f& C|11>?]c\֛}J}Ȟ@k[d{XS O_}æ 1ۮfTBW߂o8}Q>bux, Yqa\1ȧ:+G^{J1૱oWxRBݩ,h2/Όc'~$Ky_Cj|xM@d,'An"xZrUKT~ CQ+?4^ooխ,KNA<&0Z.f7OXY@fPs<:23!_&6g}*4TpN&Y#ᾴ鍌@?  Rǘ2|QڎK^9!rQUv%]$1yrŘvC=aE8gk2hd[<>xqN>ىۼ$lwW؁S#͟ʈwf?+f{E5, wTF ϧ[6 􀦈pyG>[P4SC>HCq%0v[Th׻0-Аc4F Ot+rI\K džp[hקp5\38!.YRT2c/#h@ 2~Ʒ9; L>eHR($l@ґ bm9QW?:g eU?\9I=Ichz+)͞hߤSTM"O&TZ,C#MGY}ƒai&0JkGERI YV\{Զx-Hcs3!4˒-^aTWMvQ4 d`P7xnû6d2+ôMb * S78FN,Ilb䁟.isH*ܼd5Y{e, @J](zcz7LA i`yZ녨#Ց Xynb;-#4PPhʭ)0.Q2ZIFu[8@$}XI?ksнKufLyA-5Qg0D]c*؏i x:ђN>ԛT .g֭-9r˷t=~+w@n"g[TW]a_ Wa ji (sީp\;M[4K!ݩtad+bra/:cЄ]T9ODu9W)`-ejLՔhZ;Hd޳&&dEܤKO r: [)'&vKNS /50 ɦ7;J]Q V\+X 8cPd YX;fg8͇iə?R.;G5/6uӖ4&sYٱY$&8 S<)p~ӆu~6o7v10%_T;F}Kgmn rFuĬ2/Lryz1piY M\"ؐfɊa=THlZ!wP\nE6݉@:g1pa55$9^zY PHw @dz"nA(kA%s[g\'WwVEr*+$d*`hoH*cIe5ڊ(]mWͲEAq4$brRWdg86.D-ၘ# BXH#*ԁîx(>yOo2amu}̹4Ϡ22@!W F)YŽ uGZ *GQB=n߭Q(Z6~@|UeS ,fp6w<062m>v̳KѐE1 =8@lױ2eO{ w>N!gek;cq9ox-i*e6i\3q Rzl lwGe$>טc[e5PkCT[깍?&qDGMdӟMX3e(3)c)$aWJ/՚d;Di Ǚ}<9j6?V}I,9şލ&|`DrIҺ\:L4)WBT}~ج^zC_I] jw k =*LÉ24@Ǐ '^ˍn[`e[Ľj%1z3T(l a/ҷR{vy/e.XyLȩl(eCr j Y.̻l:I ^A%.';5Ӧ](<@3=>=tX+V\EL*"|LI hi\HMCu 7ğ#OnCߧ@v]u h}47>>=#&E=@2Ul )<0+S l Q&O"#s+T%У65i[3Ğ8Ĉ ćp &4%r^ZE׼/nFnVJŋϩ?Zp4 udf-)Ñ cPRf곢5]&+s-Ta{*׊nnR_ZK.2_Zˀ 6⣳q |ʀU]{HKqz;~\>a!qt/=֩c˔_i7l9,Z9")ڢAbO ?62gr\92Ԯh|GQ_Z'gII!3}3ҋqi ~ٺIA~K#@ipBϢDՋ@-Y8+P?T,hoL  O=*^[\^tjP^TV^Fw܋/=L399'fuo7 Z2{1:[H-k܆ i6ܙoqGPltr>s x;w)oQ0=RgD{ɜq97ٕ$N}5ۋBi+Hƻ|ùIW4 (4Â_T ]@ BK4pjE7nl48-dd s$ӑoGcwJ~{@liG(s.9`s(49xڭǛs#JI޹ҝZpbˆIid+Rs7\7*l"(.\qmI5r:Cѐi3Q[쵑 kȫKx eA=vwk.<16=0oXmh Z(O$۟e&ZzH)b9>@scO3.̒~Ku |sL?,77A+;&zɐfh lG|=EKd"Y08Mٙ~A]g6@ݣ\=3>B]$ O/kR v:ֿv7'I %r`mG,18ʨhsez Yo~v %Yd@UBjjJ>5u!dQBHo࠻PN $|SR[eφZ$N?<'=Dm[8}'dGZZJVl씒xLཇ&oq1m5Tf[ۏHbA8h[o;x_1S":4|u՛9 u$_݅]Wȫ6W}\x&զ>6?~'m t'+M7kC"Ǿd,GV/tNޟwcE6m 0Ez773}~b0}G3Xu?!;hb[U}>г<2 ݤR4ʿuXS+5>7 .yrufX0idZ(VNF|5FzOԵ+uX0HPcLD>F]m3'BIϒOʏ5iYn{f`Jw-Kuwv Ln13N]}Hd8V,ǃ1 `9ύT|iIB[`\bbtSf>TI0$%q3WE󭼼@ `3'* 2/,qo-rr|7em\f K!:jcrSEEDnxFxtOz~VPq&En&FTi|WZs:Ff$<;^*{^aPP>&J1k,*Ō0JL^ǔOj2MWcZl:([|׉qMs(G9VpY-GUT*0!"E_4N p"\=i' '2(`eWLokfƺVYp=g&1l^+f3ْKе.3ߟkm*~"0l1Bb d-7/Hh0޵viWZmWOūC<>F?,*fgr +GxrX֋ BOmudaq:C$?vU׉~iwO?j>n%Y-\Yθ 3n "1_͸ vy_ \QNM<0h]O>A@e,[|b$? D7>ӆbs u%6a]K=lA^vXx T ,GmoaF@dAJh̶z;S[&Њio1P:;S-ϒX*;% z8aȺ#;-Ku ѭ7+wUe?t;|1Ҳ%dYO^Ɓ_c/\mM S 4(- p̱g&yd"͢H̲'Q{c3 SG3TtR (C뽔nq3(?4Lܾ͘򩯗#HZs&)]f"gXaB{I9bx+c֋J !L"X3ddkʗum@ uNVVSOnݢRɼ)D$cX/((U $^EztKCHkl oh EDd/H+jKhz+,(l+ jaZ=7p 3Bvs=SCquصT-K0ZO]8% B19rKl\'0־%GQ"Z*tT-$}4^75t pC_[lɋYbFۑg _m:LBEB]hT0&0,Jt?SsucզrL kJuZ$,W(:h!8\U؆]0~݅ ߇;Ntt`{"깺R=Bz 5E\=D\6 MR!+"盃; UYy5b6$mIvW<{ !LczP ~/YfiHؕIsKCϿO14;䩼|Dpla>TVd}a1"xBcS= `p=vbL]d.ߙI BßxզJ5AI#_|u47dbM,mVT@pwK)Z*dW٨O$,c/=Y0ۏ >gXUC~Y{3MWـ7SME@ۊO21˾/xBJL{7J+n5݇r {uĸ` p4C~4a+1 Xd]1'CcnmvEV =ŲT'')tU_̓G[! 9z!Bњ4}3hVnzj)n? =̨{Ris[nag~'#3H uʄjE;'AѢ(N3d>)ô({- {bK"l1 }YE4> Jqe?ޗeL-JF̼aST,<ΟpC̫BkÇExlrXǒA:YOZ` #AN*Aw$z>a*ohUM#卓hfݞQb휲g{ RqW0U{\J` cʼ޻Wj5NJɔ輘( 4e!<- $꿍OJ %5yB-J]nqLCƙ͈3U;c󨷧ĐxB(g=f/z?N;v+3?ؐwtHӋU=h- kw ,1b=~GЁTO`uYc9eIC Lۊܹߪ %<#Z'8@\§ ݿ͵ X F'*ɢuESI||{Lf5Z;u!DjR/բd1kRk΄78E'>_[`aHLhRrҖ~l&$MĻd+@b9m釘, 68 -9.ef5cvnNO':u.QN3Sjͦ:d7XW ؿ1 $( >SJ(CI@~gcrMFϯqX.ua}cS"ˁ{wH9YT)r.{GtxZnvONW~sf'yh )}꒎eg$Y;2$N>io~A$lO3rQCu/ˌtH97'6:!Qmզޢ ka, 6N) ? ªjOkdu}Ze\" 5ӚK ~~D5PU(P.9ⲇ-{rJ;S˪IdzFY0W8mq.~H4.@O"m{YAnPs;Vєam{PqsP'NeRHO U2; IFʞjIRX@uV0ńM3h^EbH Myx4mg| #[4#\JګD4k-F2L} 3MHIw%fEsM ԜTn0ṅOxܘjŤKOZecB0 %(r~MWN:*4RyF:/!9KV[K:Y[dZ]q~6B PN _;c{ĉ dp[ 4 @pOoD)!}ĔZMGrfnrQJ-[s-9E*1w[gĝ.S}5puy5ɵ[Q8y2&|ljoD Tƛ}%PҔe&ŻڧYʍ&(U+ A"낟cBaM) RXgYI\>]=$oÉw''7?&p|rNd-B|TF8V2\ڑ^1;'`23Au `F|׵`2"qƌYvn[>/ ZWZzy/3$<Epm}7 { vkqj*M˼frț["yaIˑ ǜ ~/c=7[߱3)բ%#(f4Z`?rK:HjJ@PdU2XS/NZpv~dlUX.Ҕ>9vd+Bf]'}MPT//C.TRʦx],p{ers*OZZTQ_% vFz(QG6l}.+i诖N %#.uU~ ۯVPfWhbEl}4!jWIa{lZܾ \ @s|x,޶9 Tw wB7qXƃ 5].ê姯U*Ѳ>H؞'|[6W b 6mF#Ͷ'f ơ^/}Ĩo`pܺ5V:aI6I%u[Wӱ۩qLos?+' CmO5smd܋RU6lޖ0w<픰ɸ+75'W_ ]sf;1Y9m;Er([֧,"bA.cJr =?Z"ZVYS0R?wIs˶^s&b`L:$}cq*#5]׮BX8k>tBٛ~SmI4pz&qS;Pn7N Jkp_@aS%2] ,u̽I-,HƓ8!*2IcP[LKz[K5s'jL{iv$o]`ޭ]`YMom(H_/9~5 L;=HyLwIͮQX9ۅ77;E6Ξ*O"q)G= ѐeS~ 9$?(WD7L9ȹJ{')]C"2JK3)]F,#?5LDDLЕ-Q&r!UifBq1t;ErA;~E by0xR8~BL4(J$PDG+S:A<k!7YIhS}ʼ,1h Y; P iH:/fm&zYH )݉3GD~q[lN.ey&:C(3&~moAK ?1 Yb-x0 oѸ]j#CO)o%h `'ê>z}>:fC "i-8tBRq҃egC?=VS53G:gШ14ݿlL>7`նQ~̃G1ꘙ]t\1ިB|姿 W`?2kFsfAV[mnهmGb@$"cG@p+tiRw T䛂5.T'1q\h ,ST0P*' ͕>탯o.i V2[͆u%1#r[|&@zW=$,9@Lw)SX(jZ2|Coĸ?Yߘ٦{'A(l|Yށ^;T^}4Eew1n>kz𻀅In? س؆BÙ6޺n|`2YP56`GE|ܠ6c0O +Of?ON +8P_+mz ˖w)6>NbT0v~T;;h@ b_ 7يL\[T׍"f,NBRDs*D0oc֚52aW]RR}U.h *O_YЮ9v/V7I xOl} aW/:/X,+C|%!pxF0&]4Mv]?[M^jL&kɜө܇i [ѡĮ֒efipl4ot͖_J2+xs;Ebʃ/Ƨ@Vq᭘r&v;<*lb%&J׎-&HpI^(̾ˊu"E|AV~cl\rJzUO&Bh޳Wb΀ Ŵde[<fl!\Iۄ#JIyS}ܭ_. . O> =>|Y}c(ax<.bT& &'y,spW`JFﰂ(oGͅ%縰v+bUV]SJ'O[MbgC r͡tՉӺTrMDؔcP]iC"\5_P/#";YbB OVubm^Ϙbv=[jax|zkSby{X/v!G;=cT k0 ?,8z7Ntj@7#Z$zLs!Uzx@ۓ% g]= 2B@)[[FuKO5o;{Zez`KlH>*)%ضWt @dύihwRbTee){=ĸB8$T r i]'e*FŚ8r,zP8.\񥠄, 'A!T 3DN֩f ҕJhݬ891_ȗG87q?/Ny@\a4fg6ߏ,'E8J޵3 jpdN{/ӾD'VzP8nEvSCA*$n = xY $vsaac>M<t1d@@2ďڅ]!?".4S woc[FHE?9 ϴm٣"HԜG<:s6fsF M!Tq2I(vB*.1r eXcndm:)tj*$TYESj_?qCw99U;h-"B X1ώ\ԨUO<_3*om$fx](zJ)Hй 27JB>8u`ζ e/myW,PoyN_Eg7X1F9>,ͬ/0Ǿ/˲N~99Q9ǴWDW 05xcǶwGv6=(YXmhcsmQ. }Z 2]3s-* hJˇkmx0Pf{ 놢]rÕJ&xN8 j6rxՕ j3Y8.&Pm>Q4R^u<]<` ֥ә׏F%..H??=w E錿ϑe##SNl!_>BPAݳN űz2J熗Ƀ%Ir(pz=3BI$luY8N$Q.=bBm戻4xWW;.ćm ݫ3"3 UMȮ4 6¥X1cм[8*#|g[GSw\N Z\VḆ@qS,4Dyp_h5<9Ҏ`y&C$Q3by3'PI߁q ?q]8R(m-\LQVݍOe̲:b+Hѹ1qs)8Jz`DhjR+ b׏/Em^2SIa:-q~IUr B Kၠ<ܔja|z=vDž DbW8Wل^7v=peEƒsݛ -g-)aHPkw@cٛ'4텳j$ Qphi >ڂh Н/{幆M|>E37Y:{Bx;]h XwW4|ynfᪧqkMf7Tٶd`CES sR*OfB-!]!kͤT14* KM\Sd69=gfE_P`:?¹u-RP/ 7fi_D2vc$ ߥmkqs;MqZY0J^lwr Q_*crx;³ơȘS~iխʧQ!=꯫I_X;z`S~J#'E W~m7$tNTL$)YHg, nK~NQ3J' m5 ]F~z*pehDq}}b5HwLkWe qKz_,fچ;RuE)KgKy^pX-8rA1)dS958P,=d@N1?:8wBx d/Zp)HwpOK_:UjAG_n**)1V.IX.:OV(3[ZAY<˜&@~>k ;FSBSJ0k(w숥%I1)O-Wa--OՅUh*"yus4uoEO߮r֭'<E=ٽ`9W:]ҭHJ?x{+X8L:Wk[Z*y}n. L8iG,Õó:uOqN[rIٓ5gW\[y;Gd!` $pu:ɸ0J?9 ݍ"VjcK;SF>7:`qFi&1 K9*|+}/e/!r.43 EPG Id8]8pƀY5]w\Be\zqw/ vTA^_}IP̸#1E]LQ`~Y0< /U$Z"b/"ˆVeSi(;bGn AKHMo \D8Wq Nѕ p PDAbIavXW|5mRhkʊT؞խ4]ؑ}[1}D5-5zk$]SMW*Te%x_+RcOzij.uM>mmؙ9&(,#uxc XǓ5e*u>ɒs&4@1ll,aAn4)~qO1| M-ƜKMnZBG4CtS\lpђ$ZEi+')eA0e&azaf`LLX< pyMN6=kRerd-#]4D[5s\A"'^LB ˧aTPn#a Y)++F>.!fKQSzZ@c܃C.!bhs?B$%٫8Iހ)ʃX߈Wzk:{ĦgѢ8逩:J4@l*H ,ЀA~Ɍ} z 1&T2HY"`$)մךkM&fi|%tԭjk̡7-}$fi/vpevN֤,4zy\bp؎5sӒ$.qVB"f2EXFi׼R!͹{y&vcz^R¯ uEȈ=3;joa%ߞcum;̘Iڶyg0:;}jݒ |!0m|X2nAODQ$oWN_ۘ0m2'w\nR' jG0 R#U`F2*Uԕ%4"P0,\K@Wl4]/~`1 ${(6+88b#/E`s>6ye;_tT֖6.dD*iM/w }|1X5OMwsq0w33_ n($AvG'/J[ Fiۊ$ة_r24)(yUd;5!+3g =&zхWG,a*if!*`wz`8햭)m w~|$<;Z`&w.A< 8̒NmSԚ{3Sʘ@WI0|edu#X9ey*f))"5'2~@zYcb}]s!wj0g& E<&yn[s]Zl~؈]^tnPtGeGSe#zcEq6.ӏ=3YʟpQ(0]%/{bNfb)\ɾom5Ƌh.OK ZRiμ|Hx.2%oL ]ۑw$הG?L,ېT44Z[CK!; ı^íŽL1Ѕ_ͻpT~g*>(2(<+Ƞ-!l``xby|K=~gIHOeJ!'?0n-9y/ T/L}Zy;9{2:d40p-@`Q`=P8Qy?1 K[&Pt﷡yFqoo9<]L^zٮ9̏ ~\\:jS9ٺ(=XNOQZ4zљĚlov-Ḡh&w/E\HpElJ;>+Gbu^2Z!8j#7qȾa&,)  , Ũ9ӌ'{ATZHܒ!dz_ d"6T~vE3|OJ}*ė67ƋtpN[tKy)% ' A ԸR2Q`RjV 7w9rDŒ,mT .Ϊ^Jg&6DT> BӿFB Uj痭Eqy$WJ}Qq[{c{1P맀@uh̞I/}{|ّ~q:R4H|nkw@jW~w}H::܏,.&9NAvh{>y|"ee }N6Im_zU=p[٪;@^N50AobcsP9";Lz}},^ 1ƔXeƒ@0)5%B=xBTXhX!9~zsхֈ2z0y%5ieC ֖X+g;dAAmP!Yͦ~ \ӥLx)Lxj{~fb,B|̦-ΩDXGѬS7~Ĝd movsݡi'M*E贀 O+~UUq^OUasW"2gq*Ց;5_nGǷT5;3!؅_0p(AT+{G>J}g NNbvKUP :eڣ RX8#^7KӑRB«/1)` |qR _%N1WuEQ_Ik_TrPNqUAfp#,7J Q9lO\]DNMwN遦PFòLmx |SbݐDJ񃡨Te66&}jOh14 qX[XU\p$9qB|@6 =F6F8d()|E`^%02==3WW+hfLg#j-(7޼~-_+ސ%Œ-$<'he!Η.PX| ihԚL#p(o|}m<"aVӰ2 :r/T'uBt zDK-0 օ2@6Eȅɻ@`Ee19p8}粩g$"t,2 ::EheNT֑K}vAi+m_?k$hg,lR?x 3d%h"RV}jذ}1.Zl!~u᩶št8 C$6^f62[jX O >ر7l`C*1a8{ۍ.j#%ze0f9gY"g=ĽOX U|yd _ F}W$#1֌,:q~ 8oW2Y'>X%8i"p(\EbՃn8kSJ1!ڊ|#:GVBcE(irVcyXt$\C6i vB_DmBu%v JNOx%8E? }¡,mUZ2{Șw Giast8}ª$R@pb \/~Pb%9E  b%~LH-t0l~a Fe+\$㝧4XAD|$5OF~r񷺖̀62COuݱKYNLas+Kޑ$d[$?v*FqP?{'5(MHhRddMӤ&)݆b`mJuxjgDWb&xRIVh9+-E>Bkhm%Ȳ\;9?,qwWr- 8 iuͺI!jJY8PXJ)TOc-'? ٭~3f|7$UM,#{K:X=2ʃ?tc=' Ø ߳׮3{<2,UbzOWKb>vѮjUclw$.:Whb Ű>(dd|qaE( n0vbknm}H]ܠ0%Vv)Zϖz^, >;6{F[ |lH':̅Ou4uZJ#{뱽(WLTq);:Uq⏗XXʄ&pF! PY ?Ѽ}I^nHëK&-Gt%W9r+;D~k ^.A`lWھU;b/}#HxngA9ϮH %ơ qlf%*3J?54Iܰ't!NwZMQI{0axwiifq׹^EIp6U:֏IpeB-0KH"PB$_WϘVuYUZ{~ZXݻ<AT6O3b I] I!IFk<Hi^dLL\@ڄxcB{6scj535{a? JtcV+ǟf Qa׏@^Oh!?$|,$[k#I]8M"Uc4:j¾vIT!#BC`.KB4L*iZpcOe~)gFϝsjuh:Ƒay1kbcjG܅@6 ?*pWϻ2q S>&-FT:vet2(O6:Npů̠F4HB>E(gȻ!V+]M9&'yDT2z믒'TF6E@HtEm̘,glj_Bɯ2::Kw%~pΟ39 2s־:FUȗ/.%05ؔ՞2D@2ԧo9fCAGzPM,u ik1VPm}J7MtK@=¹*m!i})Tj~|۪ٷE%tVA Eьraܛ9F!i(fТkHEllsmKh AWsca&&,h]Y^g^Iy>F{>s D}av5>pWC%;`y)X)䯴n@B*e`'p qS+Ң,'jgV`$YV#ݎ ĵҮ0(JK/o4苰08dO:h-7I=Ž3Hϓ Њb)BȀPf"AueƘ]xn{Q0 ޡ?lX+4%i9<}8Z5 j ^[mm˒d5dU@ΘAdx84ѣ&HG/Dfü,[HN"LT^shf8m1 jWUV:~ _ȇ5t gKu.mlahG~v>ـ>QX|yO$ٱo򺬙B`г1abIލ^})-W@+_QL"zk/Z钡-mkӯ0؁ jAURYW.i ezgv@Q/ɐ G=)R{['Od_oa[|9l4-5D`S8|pgt:sA%r}jL+VckxH+-{X7X8l Uր|)PnHxEpn84?MZ(M`䉆VR^\íE@ڗ &N ƐH#50)=sdZON4p r[l;7Ԅ84wWQli02nЂ{Lۨ9??^M'\@LT(j9] G2ݙ딼hڰ/4"T@ z W_༗8>{{Rt[ߤzBXE0 {n40*xc'f&#VwJ-=Q˺ԫ߶B#+_Ay[e;QjOf"-t'=ZCXK GɅ Aū Yqdk2-T>qh]Sq,|sS? CXmU7>׾i $ˮr‚rbeff`e}VA GI[KX lߡ3uKQ!yr"/4]*f9ENM:!5vgv(X$BR : P_;/ ʁ7̇!H 6 6AX' 7flhb$8\"9 ?M;@UMYn3 Li)<@F¶ugbm6,)7L.r%3M~ɭ^\+P%a4ű<6J?b^=ƆAUq)^q&0UBDLo*5㒝gSډQ&7Gu{k&~q0FW鬱;Rw Rbm] î\ B]ܮOp.ՎuS P^1`{to3?J޺1S[>փ) i19B$@_bbFi]SCL75gTF5GLXVl`⅋/(ć~A4J)d': dH+m3s&1+,*#2ڀ(I~ blt^G_+մh|Oέ=TٕxJNK@/_Aei"`15$ q3392^iRП+Y!$ Qu铬"(1o!wJ]7Ĭ䮓Ec%bR#$ =TU0..Ǵ[No2 Lfjmp|1;C3;Y<Į %7J+@4h{#V=rIA@m=m)Rfv+=?[iQwٗùBok%Xaq\wtE 5ɋ͆ĀLjى S_Ef5=yHcd+dр7r8/Eԃg*6,1)+F--O3̪Mk-ꬣa DWj#D: jo*9No';Wn<818\z=Xxl/CS7Ovɬdڮw t M˜ Ie<ʗ؍]~'b{y?`,hIm?L~ͮp[%.+Aﻢ ZCJ~z5#ה6qj' Qls|PFAȉpvtPB*Ot jʡ#1FwGOА!ߧ.= B/k:*pV8F&:f1'9:Eki {7+䬓DhGʎgCAA^7> RC5K-Z ޕP)K3g y Q3(+{تEUK Tna!Ȥ'''#S>M,s SgQm8>t? 'o~VHYBw0~Ͷ3D@ agP8$G4 l }Xit1A?Zy$#|PGZxN1s X*b%7=:n !Dj LPK+(M:=-ȁ@偮њ#rC"x-@: A =^rR조!$@oF *GDgU‰ 7>)_]'Z?i)|TT*DI-HTS.h3S}rNHH[. ʈ}G+7/%{po-fFg5q2DjYFDE ̶20R<?|2~ \&w /KeM_^~-J/SM ZJ#*s';@0(B km!Mzj:2}O*`w{sM0W"$Y!WT2I͍N62rltdm)mv#1X?>X7tT;lX)BVԳaPﺋ -T"i nJ( ,SA(O_v7W}oUj}EL;q8@B|rd 5/:iխ51_ޢ3 {E;tN[e9M2N  Z<!Fdؕ%=+-. 7VHm3Vњ`9=ЎNj9E{$*ab,#:f&EZo v_$nۅFV'ץtKh:bNm^}_p+W5E9 .I,hNKn 6{NjpOObG!FAڬ?7.> Kk !A@)@u0x=@_f!v[<*P$]핾#O %ȳkòt"9oRR̮P^{Rʯz&Ʌr^ ZXK/j<00_4-[ ߫w.w׹79fluA.Cj~7nY j#6nWi2.']TB兎bHie8iyѪ2Ms_")Qg95 eieE@)8mC k)Mav-8NBiĴ޹dś-p$jlZ 8eh !0U0BF$6F Te ezw)Ş jv$ *%·!8im>Rn>}򛆝֡6=X sv}8}/3RWbMچ\LYD1UR-uG#:^ISyXG/ }J+n(#K}* Bϯâ\'$0}J_?qY14QHPV(3< NL7 кe+#*3p2LF/ODr* Wj,)A5 bS]> Ll7fE#KhnS5q)0Fl,V Mv{Ρd\q,bM%~1s L=$^u~؂#߷uGUjP[cl".2D| ^@-~^7]3DM +Ɛx%!-h{͏ x xɅy&hiG6} ;&,\/2""c՟FPqS%0Ɓ-wܩa|c le@? =e|O_L5H(1 VCȫhhH2@cZ^@^ǔInv%I Q-#FŽnפ%\jteeLSyh?_CXWz;ps\nXca6*=-l.q *^1gN*!W=sP%\(e6&m6qf x-G0}poD}QhvB猠2Jk#o[8g׈azRJ` t#֢za C=1gv&N!ƅIMSRx,K"PQF86 E,vCyz۴:Ѯ/\ :zs/bl_8]'IM T!Li碳?}X_#`bt0־+|dl|@jK;ЀlE-K=짺KHqFXJ[mݠzRaܟE`MdK,4/nkf70W,gtg09:PrEu]D85!!; j21l*7PƳR}OYT.{ޙL L4e*xʪIudF&x:ab#|5F0EA4Ձ9ӊ !a@NF66^־PU{ S~Uk Ʀ1 A?`REe"WhurmW[hU5G\eK/,(jsBy9tOK=T 9H{R '˘U;-PB0q4ɭya0FFڻEBZ>ȓJa?{v˫Bjlz~Z92wCmȍ%<:ye;+Ht\N?.gIVO)UINծ&l|?硈%rYFaQ/nFs1^/@%BQC@1Ԗ4W E/opjq%ŝls  1R o9geywԦazYAx|2掘i@ 7CM7,"C3C##ʙjKfa;V58:G<퇄4}\ 4tց qk;o e=F; .ͰXME_~Ǭe+İރM2yv3n!$EM-ja !"^Ƀ\| f΅q)^b9Fc '~!\.@_F^zUa nf i͍V;6 `b~yh;)x3H7nl:Ӈu tӄ2ټ4=m`dƢ:[W{Ny ,.~-7>3H+N NV-)Wy+`NZ1}95XT2Ia8&[ \kWOtEEh@;8%ܽ@[\*fi2GAPRF+' Ax 5b|8ޱԞ0WjYz:39Rww)zBcmeXJ 5h*&=lbVMHkWكRlX!m~f5Ї,rDTթ@̟̆'X+F)b ԈDA RxpQWAmH 5vg훮I)y.68N I_N$&QHc,'(^$SrR}m*4˥`7EHa!6 cFr%mUce'F䕷_DL9Vl`U]=mL +;Ҽu1;DE-{ rT |1aP 2RSzKhs.dR;>H0lo#t>3 /;xjLX:mSP A鋀jRF|IN]p*&طryD#!~%֟>:VtDsfrϞlQ׎!Js#x^OE::d)!k/cmH̑}ij^0"t6F$C"'(%Fk*-brA6 7LL4ZxmB+%)7oU=@d߽Sʽ~]>\j_)01`?^ i of< )RCQ:ō 7{Y''' '¾%9Rόoe>y@v'Tߕ^(FupLx] qfnP8|f|QveaXef~AJ"mh)de|~|/r痘$%|*WX<-QwرX"w!)Ԥ5XP}ZHQ ϐ=bH1۝}(r1j4xB ƙ)POpghAuVJ |ȮŷA$JrRH !bq{2t`3e.4aōnCyRE_ ría(|Bgo{;oat8G=B,>gh3>!"Smą]pN+F"sٸIb7zTtХhI`J]\1[ֹi*R95%+Z|pJOe'{GqF.#&=)_H\b[?65tp%ZO+`aFp]zq-)wCh~K`"]]KpS΂i`ͮ޻ny[w嵫EuϫBh䁕 qGTd}?@Of[gA%&Yv'Wu1w{V{^\?ڻ}Ox0(5ρ9D'k@o&ꀇM~5 a9xE =LUusVT/c>܊WbIlۏH]Wk4")jA#˯2uAV2hCd:@Qto-+!%,XAtG$kc^wqP>aIfS&e\%+ 8~ P,JJ0c]IN:EΝWu >\|M2{0Lo0DMVe~xtֶ715x|*h.C]3Rx9!&jZS ىLsi"Y䕴h=Z`R-[0U=fgg\?%@n`TpmJ襯Kb*6- Xh 77LB6e>M8M")/)6}Koga9qTgsBLJ^;Fr^QE[|{gz tgQ&I 2#u-kmbI:u xm!X=R0)gXիD&xܓ/Q'pF>(M 7^a5yVu 3i0HaBlnrh=.$-x5zkQ8YEItETN3 XΙ{*9g.$Yt~A6\{T2!ğC\K C&$*3Jx.J7 c-؂V!'5l>Jɝ#i`p:+qZ޺N:X8e ˆ!$'Fh5Bvլ??AEO~p[5+/e.MÃ/ \/XҼ38 # =AS2AzTw.i2HZ6WH@N(c>2-p~fOBjƝ "p f[ t mW9Nfj`".Mu]X {$bRRr "(lk7nRlm *|)@yiSӴnNGLO(_:Zc ji[cI[`!i'j WǾbtP R|X9ᄘHIS?Zc f9]wTİj<>ގ[TdƮhjmU/noջג22;"TJXB{'0Иl&(m1OY@!ʸZ-:"ذfo "O97u>Cb_E˖2;LF]S9:y]*[7VR0G²ZB%Gl{D;;? it_'&S tV>0|xlrX[%"ހ^t h^|ؒcfy.L \wbtQ[(,I}f@C՚c. 3?eبlm>Ly_GC${藎OҢ)?XFnm&@&1R$ \P# = =[2,│yI'T<yՍP+WH!?^!Υ"'b+=Ũq6W.a&p ݒ.4&L@~h a@qTv{Hۓt2KS"iB1/dݓͮ@]l~8t ×(kp ZLNqM1)$M L&GLp{gyq"] ЦؖjϹ kz&FkcyoҖ;"ٰk* DdD0E8*>hb2 i$Z #s=- (n7x[1R^HpÑmp?ZF7q8ˆ'rymĤTݺЀkiw=㵩M Q>Sѥ?֎ɧOl @|^;;n}QUWgIo)&-nDylg?SDXH5^|-Ў*g ˝QۇSjWI/]`<NB),h ;7O6{OvhNDMOS͝)jɸR&{-BZA9C "_Yvg@ <++*xӄ?͘\v1i}]vGHt4Cz>z{Xp,zZy 5-HxTDٸdE1VM,%K9_lE~jI!Ӳ?vba.sw2{j`t 3] ԅ.;@F8zH@f̅PBTe{ɴ/*u5'[Ahz2 |. A$8jQz E$ufq+eDaBx6gCY6H-[_*C32,z,6Ʊr-;-|`P WKKӤyИiN͏gS8qq1PdC-k?(Br"h=#Gz 7虴)XhBLu|@u#'*6wJ|B=*$2@?F:dn‘Q Ee\$̐$0Ll~T4lS ɋU'yΥX[2+@1To^Df~1܄cR84ވP 楴x}|$ذ_ fEJY(C}_ w,y: \Wjg-5 ڶ@ Z.eভFTX>*X,T*hbƠmmuBdijp#D_VT$70wAgW,Hp_nImyFa> K|~ċgxG.__ofWvt G-R6ȸK|g寄؆mىєZ,%tOukPǢw)UIjI0eоZ. 0MYʙ'Oz9K@X )!xh:ylC[LCVuzo>5YqE1K \&LpdcKX-]6~3v?o=0 [ ݡd{o5gv ?tN_` ]zi.)m' p&B_>$v4KyZ*G㯺?lݱw#oqWyƗ]e@tza+9}?"ʂ7|D| -҉xmd"m;a&`ӀRK~tr}[ԉtc} n_k >?? z<:7 J8B1P2-ȇhg/slJS761{JS yk+pLHnF^~*.bi0F)4 3Xy^'#k݌W;ҐMnWi19I+a$-[CtDjfbj4S;gxR1va[H'jЅN z< ,LB̄ &MHZ^_/7OYt(,Y$,j ofE`@#L + ΐ:@]"1XU`J%uu{n:K UUjDrjY\w8DxYVW_3fj{e˹ׅ8[= 7\TLEDxR')T:8Pq׋c[1B<\.A_3 6%H]6Cv@gI ߅' ~Pۖfiy[߲Qeqꦵ2x^kǎtOvgNiߝp2D/,stX{G_'ccҢBtzU8'/<ԍo7K \9 @'^uk[<<|8H]hhCYŏm, a⯨|d79vU?OC Z#[Fvu﮸;7﫼[È]W TK@M]/bb=Y3;yrfGpNb5~Jq3"42iK6Pto~wr2ug/A OӖM?.]R_Kg4bP)燻gJm/@ϗeWHޱ5&?6bGS;$l7,25ֳFAY( Gŵ)[Qcs*/y?esI? eDtufVc~<8#1=pc]r"l_ʗ`(쉓  joD9 o DGn"bݖb<>-8^'\}8T#aB9M$i-}]N@&_~a >آd>J#1ޣL +a?9M һx$<ٷ㜠 X=3M6S ]NN0/N_g!mo̷Hr!JFA!-CՂ1Na9GR'8Bnc@.}pF*wT†qaE7p)FQ#71Uᖰڗ.U GWOd/& ގ3aVp-XAwHE+-=Q{|)ܚfY05K +:CX_|\aCè6<|SQY\T2 ,w"وtm\oRӂ?\dUusH㣮|W}&'GucaګtbC6uH&<[h (.;d_| wuI{c=]W8`4$U ?-||0sT((w܄sOխHŜ=ٶ+ rM[=Z̖/짍ݼY f|(EZ\W] {'ep=⁠$)TL~yUj9Xי7 t<(GH4ޅ%%wcKv;_Rj7;+/9>)< Cyi(GӍXh>y5IOe'DsJ5ks! OS$y=~`$}}ys~]Fl?`$Ã9,i8-ÅE9Iqe }ǨrwhּšJ#f/y;'rX@j„zZɮ+9 &1Ϛt=5ısL+`,.r&󨻬Ytψkh/&> O -+|}QoX# |DJJ>`gҡ!~iu "$}ExQ=W^F UN @iYm|){'*/&33 84-/xs^aLޑWf1-Z;̩py'}~?f #j"-۲u-jٌ^8} n^)Cv~Pjy48J|'21o6zT;ټװ pRbf dK!ސ߮qem^xֺHjʸGUEͷ@o_`"&?mkr'a7svT>aý4փ6UOYˉ?w}82*MxR|mgQ;N6gu/JWbL&2/ FP4RP qȂ9#&.r*'Af!2mN/l΃T}MخMGijJ |Wج>5[ʘJڬhPnBϾt} !_J Y~l`jE 7wŒKӨX|i!VZ4scުs ֹHxBS jv>4!ڤ, pr7 -yd/+$x!㲦?xp+ LK:D 5LRʠS(b*+mڒߎxA|SӤixzʰ)Sߤ{ƱⱜǁOcIE͗iB$  *d(\TyX>R)%U.D]:2u:wiĦL#(8)^xªQ\~$&G+ +tdreٰCh h\eIӲnF%LxXҩ=g͂C;{PHAN=ZAx yfJ~ wnMەv ,WTT1{zͲsx!u{qm善J/lG %[g$C=P;~JSgQJ󓨞wZFMW_HA2f 0 Y+BpM%JX5-OHoN6:nΛCSZLvՊ@57bTvW?:'gJPKvj wY]h7VݖL~UuH`v\@9W XWY89#\ߔ_*Qp*)[9,n% a ?;jo'JǑy&}wiHVafo|<$\&x}Ogk[M'Mz8E<nU-#ӎn/w;!5P?XZόS)(͗b:vQE$ %A F b5+ qY gEh@\{,d"|!K&E^`FAY vݓ{A~5z i5+\\jQ.J)&2[8O #!ߔ&=BV`uȄK 28z!ѽvbw#NkHr ^CLD-P ʁSL9 ֐{%G5Oj#;0h&#!mֿ/U;D3q'b}V:α3-Fxٕ"eQ͗` G!/z=aOy~ uyJ[$y;eb1 M)#.u݄htUǠ8wAyJ(=k~l}\tXɬ: {zFQѹ,"U{WQ Zl<܅d;ḧ́GBqZޑmlR׀6rJ%Y M""g|іmtv]6dPޖnvG$WUΐ&}znvVnV퇂 4,{;a 5#v\.snch]㓞ay 8chSj Kye ӒNZio]W S nHguNtr[1_PǬxcv4[ĜkLO i->Kx¶,41!-vRZ$$ 3(~8i"# _';,?ψRnyȹOu1~@u>;z>7{jܻ{qⲞ0R ;3EZN\sB?Nʍѩo4hR%"hְ04+]H^ &åa \_tD֚D4Y`\5S$TdrT/Zp0M؈+ga~K͕,k\R*圖 N:PO4T>DP]!-+cM `It"*ƫƞf@zߍ#:߂?e>g~V2ؚw:g"D!o~dyҳ9oˏC}@ DȼKA<|k\q6q"ϣڄYn#V2eBMwy>Jh4  t mk37ȣ+Ç]J#5Ŏ +k(`4=%z'\ z-kN.6KEJ2P1]K1+ُCl9Ad8ЭڮHԬu G8'[8踤p<,Qc7!2jDy)T7˨8c8Z{!2r.h_]c&bNzu?O]6Z4,C&ߜ"۪b[=K .b,oһRw{ЧH? '"릸sy355Uz(W\cuNatxC 4tHX0hwb\eTͪa߅'4/y6͎k M3`;IxTrS]Su'OW\S!f݄7 G{$́n/GcI.yHT^8q jrl}m p>jo(gz !o4N3GjX@~ f]HdZiȵz!ss)o(Mx]g:JZAgs\wU^MDLKȃqgDABqlnbS3Y j__:/ 3Y:)4h;mAt{Kleme.2Ck̖K(ՌަSi볣$Lx˥QqףJotu:T}!켮44aN -.J9 pཆJyIM!{x9iWX~H[Ӕrjry:%vfqPx%D^bq,~\h:`ہJ4`/&J)If2vH@b}.qN&v XSvyĕT;FzbLkXV9 ҪQhUAS3 ]SPױ2V0Cf Ƌ%7!{N ̐X#.Z57!d{Gt~v),tC{ZMe :کBy2<zf4R?ɔ)~H ÛHU  8&aeu)ކ~xIq!ډp @vd6cKbYU}vvRV/%.}pI >qc ވ'azn<*G+oO#`oܰ@*K1݆a'Ku YP(U]kU P R[ŚsDaw؉`D=L0~pv Iwz?;\fr.2J%s'JCN,ڲ0h03}Gs9~l*HsU GbmsMEM}gMЂ|J1~ m_EUSÊasn9^{ĺ\ i@'INZ\6yɡ{-bNV3]Tz𡹬ʉád]Y Ku@ĬsjVk2m^erM"*oxÆiHob|x` OTUC@82ll|%QJv1U43~ ט 1N,M :Ҙa\b6Cߠ 4'/Y$L:%Iǰ.R H0 &q\](:۟r,`-:8 lb_9gW%,*(3RADᮍr:U!m+%SܓS/B= mǐEuE5 rQU8Q7js9:/e*qYvnۏx0QeMUC ~ŕJ SAA.eC&ΰAy&8̳ǬM񇧁'2`lS7!~/!!E.Hg[qB 繻쥄 |) Y#<3>&Kr%RB2Yp7Q K'l$ 1hcoΙ2qM=x%G+|wqF[F$yrb@WEkR4M(l~Bvz2-PF.MzmAѯ:_[GufH7D4_;бt&kU5=&͟NV$4911hhwq})Ly0Ay=@N'46{Cn6~ T`xP>Ӻi{=Opn ^ wE1~;u۸͒"<Оf^DcLGL T! SqJ)ABj?N"Z񖤲u^&0."^d@Ew߷ 7ۃn߰RNgô#.Rz#9̕*dQ=Ƭs}s+:p5Q /S]R৹uA&<Hn5Ƣ9ފ8s%X<*{YC6;,3TPbc x3"e {Jֽ>5+dKg h!ui QS^oTx<m}d;]HLZ#Pv:PPz7hOűCM>ux$¼\zUc]1 :\BOYXbo|6.f& p[G#Q}7'U.+b e=/4G9jְAnߎc {tƕ/eqg1\=G Xc4Ώܹn6-JjPfA[ss4drS[Ys&'Ƒ" 発b(i^C=KȰ(MNLq.u<ўlMLu3T^T.|S|^v*hzjZtv R0hJ%67?B1nX< gP7;RkzuX?ߥ˿ 7-u11Z2t_I(SmEÀX#V8w5?7k:\b/hKp#-xi\uwׄR?1h3Pe,i ĝ)I0hE>)-Fշ6=Yh@S$AEb]d%s1ɫBØBn#Rđ0]C4nV`ȿꑻC}>T)CW"F˺ = J5J c(XMOCeC?jrH4YFM{j@$wJ\'6ԚBE{7gKPhEs7毛!-yO@UŒ 5B^U©Qݞ,DX6-bHV`e-~E ZaTV|8kה?CV{|\z%N_ؕY llhAZOӗwD:>tSZqբ6Qnj 7k]bO{dø8SyXv8IǪoHy l7( wN Uw%UddŮDسg8hu"Cj@- k}K3MqKcVjѿԙYԫLhʧe{g;J"J,(F y`:Y0s|I}ꗍX'o ("'`գ?=1)h](0*?;=[`\;f}^. G򟊂ҭi[dykͿ Fc8ڛMȡr`6֨y -((HEة/Fz^0T[x";jEn~ga-3E\pCtZdC9+&6\Z1 rAc<F!@dCX8ٙRdodI3_n6pDS?,z^<(q4S^fV,&9n[^ Ks={&$3y8s_; srɺ,hݼW\@.,g:mΪ|iD!b4Rօ-kUAO`m+}{փNFa6Feo= "Tx$ p,p$;{Ml:)'(鬭?@+F@s.013I2L8L0$o.ju<&)TO#ӑ,j/ uJiO])Ȧb8; VenHvrL:U >67Sl $^xMPdPev;§B)Yqvry #J5ܳd 볨ڧwhjmMսaER2mo.q[Uvi..AUdv#A@02ƈY1Υ̐ةқز$1M'W(tB|Թ~_S>4W%+4bMԗ<?kT&s8[p;`Q,e%=M2+hmho6k[3a5{Y6* k}L5&J!tk7ZDjM^@Þtyt# "D۸ KjPO/ 5zRq0m{rtKtX e :sЧnL*ݰ@PQo_?'ᅇs쾳 P%Q~cUU '-n^n[C;x,aE>u#uEjv22G)[ _Djoٳ.8LP*hĔFKU'KKUÙ~e+[md'vKKΜ!JU)C:>cHhGUv ʔaXۮ[ T],ɧk6QΗİR -m]֧EUN]~+&fKIt)TٳXMGEV*o0zv]*k:Vy \'BO*`*>F*\LP:/9&u y4E9C|b5tg4D!ru|{ᕎ~ S5t#VGK}Kѥc!D8'vɡ&mG#*ͱ7[Dn?d>붔όƳ,v|$t"eUmTj@Q2(? QA״sL"jotd(];)LdbGEz&h-d߱iLݲ!t]௝zbB碴Ic/g#Z6օ+[{rAt40Ky tSUcJ"RK妘Yȝ GL<m{w=PlcI%J\0SMf(d> rc^TYz Nan#S=EfhKOyD u^JM16ȭ.f0A]tͽu.M3&o[vUBsETUyCp? Ӥ7jʆog@/ U hs ` G jpierNܝwZ.(xEnx~zQcД:l>yz`Յ, !F-PLTe$\QwmH_snsSw0SM~ՔԬ@{hS%TD >3nP`g=1U}GK0A./ziJ};dקvb>Ws<~ӣP#5cwΨ#d+8X =pa`pXc1<Leoπ H=":+و^`tL>Qٹ~cީ85-dѡ;D{WnuPIIԣAt{e3 `p=d@erpgc!>}X ,,5]5 i!w5Iir7^J4"tSL߀P,!;291oaVpBuz_4^7ƽO&h$WYLKW?U|P8<󠚛fV^,B׹J9pC#O(VP@-5^F&I6QoӱP¶? M >۷/!|Zy{O/~}-)m8A/ =*im\os#.CY[AMiw朏}Gi|>{N)p0aRd, u`ۑȠf\Skg{(%sqLљfm׀J rFuf`=[RBHAZ(?d5?%%fWPWj6}Z1 OXfwkq"\*OLRo HhɃj;C/V>'ڡC%7U6В+ֲNgKbf2f-+E yyaE{f1=e/V9h%25LYǪvjg?mwgO S˺6"l !1Q$[C?yy =?G+:#ɧQEJlK `G +;V:.f*6Xxq7jWB둪nS/=k>ftCFK| 0xp߭ryPMN EgS[!emRa׏SŽ߯Sn=+6td +⢻dxg.\+hu7iX$p!&mzD4xkLk۳ S ##V&.%@ݣR#{v$ãU4.pqkd!BHxhrI7&Wd(h~+yG;"acpQu=s ,[ C^g8vVKPsu>Iv)A.{?fK)jÃD;.EQxr#h[߹aS~MʤHO3EDMt}07qsqV=kfMtҥ1{z:VnV3?$7gdLvޣ[J-/T?SNһtHa? RJ(f]x0jp#Ad?`".h-w/66nHS[!t,ّhGjVODIwZUr :nT7WY\PNTOo\KTF_> ^i(J~ώl8ܯ{ ·dĘF BC'AB"c7J. S܄CCբi^Ez@>qF5ב*CAŗY/|<%u$~ D ʬ~"'觴e N;gd-A[G3r-pi>m-  7KPED &LdpJk Ҕ&.ЄRwKS2h Z/$tAJ8#+4H;ub$ x1zD,d?hu7_أʧвP"ΐgP_OԃXI ^M*i`B{5S2g^b&ۘ6I, ![۔>Y V\#Xӣ>98 k1{)ҮQ4)5H ^dX)"&m* ubZc]e]xL,>\撾07g6e(/[)` S\Ʒ7ձ #"h?MlPQ%K (P(m3$(Jg/ A)c)u0N)8!E/A Dm ys1s.pV .$|壿vj2=+q˔g#Lt-U 23,W8@h " ?MVJhH)߃ꁓj%eqC~Cꤦ8@` vKoj"oPdhp$40, m"aro؜EȊ@4 ܧ!k֝K`|82ЂK n,->ؤB7dSFC$2T3_)阉?Tq!RÜ67t ל<&}ѡ QuBNfh \D3eRvg tc+(6KrWՅD%1!C|)LStj$6Sf9<3r\?8b2e5wDO1DItm 05l0fD5 d2#B%הڦٜ Ǐy+ZhłD-veU^ y|Wr>%h7;}+-2#s0HTi7xZʼ۟OB#j' e԰ლK z*Q8-N6S5E:}DG;ةr‹P&[;SoЉ,Ӆd~ Hw kIZ6%#r;wv08#_CEw3ΑxٌHe9)Q CLQ@䙧w3 `d6߁yWbꃏ)QS/ll|)np`,JR,5j&zfA2:iD2f ez :-l Z9sRK/A£cuۯsMC\dl-20NR\1t6`aBʦ%F|/r]NW}<^ {p=R# ^TqsSE8~q T9(*襡i;J>򁄯?گ5nmOP <(#*+N;+&_63zFe0\GX$ԡ%qq5LeZp>Ͽw>婩7tv =٦m;9[0t'~mSȈfN肧 ѣHCd|!ٖ3'.-tׄE(YAE-S 1a*G@(0RvLҭe>!ʠmCe>nUH@9 ?a$zGDgfN'y(ѴgjBÜ^BfNy%ɧR5[qL&[ 28,(/FG4CZ F(|lu^N_//Oߪ.'};C PO֙HPZȯӀq\;`,fĽ>ߣ R$@tE^ãJr:1{a,Ԛ";06꡹ r:ފEхp{!˙hy%<-. 6> w5u&Ggq8ރP4Am]UW x vF:b[9TbNY0}@*?,dU1]DR %!wTT]ce`n`}rZYG'&s{ q܌}x"g J+C*pxxf.Z\?i lڷ0=K ւZ=o(hP3T?_0_G8&́/E!jc(X2ij%?Ci gm|n{bP3*h }3eX\oO~%>qT$K?5ykR8xx_%)aܚ5R܁͸Ȱ$v<[|xbQ7[XT; mP1xBTE/^ X!iNufjR#5;u$BGQҬa-)B?)F=4c-(o,w7[.c`.^QM)d&~SYOE2=m wlj6ߧ`1.eFeaRPgX9 n*9k?*j I[C k{{L@EjV㗄Q3$x BM[UQYeG^Q0u#76'l|#^qqY?`,nvǽsU˅ʛ}qo- +u(.Z~ԫf~ 7tCMVú淊sEv-ˬH9:~T`j و;SkY7$bO7fGX@Chÿr 2n؏xvh&tˉvp#ōY^Dop +Xtjjyn!H.!s8%Q氇"(e sQ~ 9¥]yp4l'|&!9,34BX璕!AF6F?7}+ @ׁWWGQ\kɌ-#e_}ʠfҞ8ݏƲ q G)ベhAWwQ,t?ReŽ9'z!9nt|Hs_rںp)m ye`.)vAҷ%G` F9 yb!' cLW}譈k!iUK+QFNKȦWV" !F1Zi|cer†%iòc>v(7ݲgg~:8NʯIr&# :V$~aJWMAR-ĩ8F^XLXA7h9sG&vߋg4XHv=eԱ`\!ˈ ~#PiE{QT>T F$S;i+.lCe-olSXD-v+e9 K𐊹fX2ղC< R+2Mݠ9?d< (]Mo6- Ho 59/s$E9عX/JJ> dEd  28mMfbm~RlgQ K)ٳn,*Zi(·1{f#dK+/QDUl|RkX6 .GP5/9u:~6@Na= t,:5nfǹ(ٰteUm!LE]re9i=o@pxH͞[bk<S14 8L Gdx0ѯf4TVEi#Oۉ/M. Q$S. 52@ƞE{ *=wɓv(Od2 3%?` U?ɓAǽяg{?!W AaBbg2-J!%~01M5eoh`JJآysAiGDE4xmVr{ļq^Z'\jAJ{Gz1OIPӱQYh͢hu=cdR,!Fy $ǿF#BtUcO.lF^,ɣM 9`- 6v}ٝZNvw;w6~ ٬*;Ti>0j=;n6B* 'R;za-QyN*BP?L/z+G{S، ?#?bd]cG yX!֜XҐ-\7"ws|$$i 6Z·E ʔEy>KEcqi+cɽY'\gFlW0=<̒ŃO)9HܖAv-oE2T8ժFcj>nz(Ƞ7C{!a^#i7"Zpvi|Hl"X۰?HB*82BRk1eL%(BbȲճ불< }:.T8Pʰ8oF֯OULԎ%8N+WjMa:a<,3p>ugrfV f:aDiZU@mr#<\*=2>a ՑI|\d{ə\{&~0h%..n '=3ΥEYXanT0za)EDk`+2(I=kֲU4FL\zM< a./Z ne=䠌Nukigs )DapQ1><,B}#amb)ƴ܅Fn^âf|l9ujo8d*gn& n Z_ eIHH.W:%|w {XԱ[\{&5!{]S7x0_|L;'mx%kU@= !k؅ײN+ɔ 93؄jc!ÿJviKr:ʫ:f$ђqYYcBҎ@ +[s.CL)`ʒn0bTe⠑ez~i;7D KZ{ w-ߙU ZGy97MTKVzfE{8Sv4&ww<"ЯWV-v~'̆!!֯B6;pImY-Yn:rl%_ԏB]I-V+ook~[@L\:3Tn,<%fəZlҊ7ypb3=X>n&ɦ`C2m!r}Ҋ,*#Z2,l?]?ړa:Ԡ=9Ƿ#a fhxo5LR|u4[@, lNAc`-<8ٜwx! IsgA~d ) /Z{PE;qr]G \*H 2LAF d?z/ $2m)~ʃ'UtLj ^ V uhuAJwuQSU4{ .#L;VnC |Ң*COQDiLL q:{>;Yb+ ؟y_v8t6oF7vKc\nn2M;RmjA^l~98OF$d9/Np(3׏=qmG9c .bȴ< g @7w֫Ya&g'C1ɮ׽8|!Zf@7 Mt|qr/o+;H yYIŲ.p@֠2yRM_ObD㈯ 7~ĔTΔGmK2wׇXc'Js/h}ZWFVG2\y(./^SN`܍h#+fIMAj|lBBI+}∼~k}(CEqgv)oB:axӯ)*h=n38s5Y|B [( {_-P(w?Ң\TA#w)p,{$tVM+hINoo <`9$9pE)YHtAo+V,̀1/ne"8>u7'/jCL| h9FA=TiwL"EHl+]_<+3.#e/+:tn_ezؓ:}Bm@- ܓ=oڼ%n+#~ab[;mLсfu_6v> c/lki,LzhGw\vE"dJvNi_8!4&/U@QUdbkz-S?>`ǂљY@3̥8‘R(1gJWO&{ @ IaB@ + s53{z:Y2Z99gRFmiHC$6>3kk\rxyWs].0dV Gi(cu͏*OEvo:'V^ՒhHX`fV컶|mZF.Fe^%Qq J_ ,PG%Gsۀ !1+M SDڜAP;Juaʭ\`(T{WLDE]5c" ΑfsP0FW(_"m̽fpN ܨFB9Mg UȂPuD%'y ?*-4 }QJBQp7:"_9!LCdZg!}.VsK˗Ԡta֓wsLwͪh+犧}jA%䷃|S#x/^Vu_XD&(zb F&,8vhXKcǞyZGk & Hm㵊,]1( Њ>qO5!G |"dLNHsqb ~1*`IIh3we]CyGc 3AHY,qEb'URh^!i,tFȪDu{LT#׵EQʑ"KtT_U4M9YzAȢ9Enڂf!<:-"Ll :2|?osN*!؝}rGkpwvjuU5G+iO5={b4qH˼.A8 ^/i^')N:,+|F4ʷy}먝^׀8ݥ62FA\Ns4%ڧ`a"yQ6-+UUK5 GK0(")F,mWFJaV$E/Zd4Q($%cvXJ]}k6:GqLqp܁9،O783GZ1$䮚䮟XʷgKy/- a/-&#a_]v޸E]F /)UvYdi{KMJi&AxɠFp{;S{3VΑ9QQLSm=wsR}8Z@({Opao`g }*Dٯ }G8e>!sȋRW3y@ҝpJtdUe!Sno"yS)j?4j'SD6A4;=5HV iI@Ri2G$hRFY-jWO"M.WȢ U@RT*;/HLzAmz̷[6vOS/-4}Cs(H@4w @zsH )El &7k"Kvn,ύvbrUVODuX ᩧOž]^s-{q؂BϑΑ%ԠDU Ta&lK.{+~ =&ISmب)ś#9uKԏ} ~EF&[I]5g2@rAc7xgrRi  P"ueB@v@;BbAsʔ^9ѱ֓ p4eaxAR|TM6SobUXu*OWy'iivŐhlL>ʚbj@Nx1,z'ivfc-w lϿX bmKXUy$u#]J%;NƘ}D^N1WuW PyYnP nEpmv_$= M͓h|r;+eJ^俼Q9#Ʊ,vre6߳իJ'R4m:D^)0Ma&Qt7 N6`7u,QPfɽუ3Iqb%gN#clqȕ(s"#"g,HUeS[ HfO*%D3LwV os֢w<[->\`"-4 1.&ZcATB&g\ƪmRxG4>LRRY?U,pe 7%Aթӹcnx لz>"C}xx.8"9v@Y:~9`x- ~8A C喇y'{~Z5q2hzY W󬁺10?)dL an5l)Hl>?hpgQ7 sg[n<轱¦ ֽ:Z95.(!)JZ-Yzx8s%~6 ,Pq_ۇ,Ua8UjwY_b1<>@ #̤s'g)cT?SdK`netÅN>5G {3bPž2܎育Hn?`ap0{jNJ7|1kaE;"ޥM9')BD_bMW6a|i+픕⛞kjRx{-DNC-D_dS~wC`I9̹6M d51lv]s_f;Z1;0u~9"]FLH-K)"%vV#_g= B~^3))%)gB-뉀8{vCMW>#6PFyC=ᘄ T'>N~G=D*gmJh!ūpm4#X9Kt>^8!3V̱ݬG6S*4#b ("ޭdT#N%ܛNxSF'w4f53i4{m:F&@Au*!L P_xGC5s<6jտ*9l*3:tA;:2 kp&r 8 2։g=:2_~0x**L2:{ xaԠMիaSw;F͏.ew[.g)/%Z*=D%ɬ !^HIӫH ?"^%q!V3ꆄi+9?),aE;_MPͨg@IMrY^!^}JӾQPQS~ uqr$JI%%?;ے,WqVtt„SZ|H_|%E(ۮ^a 9.b&E /_sYmOѤ#ot_'-F|5oE-{HhN|˅Q3/_+9~́F,g55A$~m0`)N|1:i ~N*RUj1x1nuۺd~/["YbԫA|3{6*r u`/G꾟Gl/5!ugYW'1au Cw{d ֠#`n ] `&ol+sLtvT6/20=htYvе-&2 \S:(q}-pl[dHkWʤʐ֎My|N{@wAIP45z{+3va `vzş_욋CE+^6&,ƽDCֿ߃GixSBe)9Uπ' 3.Ź y h°FJ_JRHoR'S].'ӯܱ)ފXlB F~B.v % PwlC& d$0I o=Cj]vW dL7>(h5d'ԥ_ .7hx}Sw0Z$ImQS&J~l Ї2a(n^@hzDAc5fN43Ŝp14N* 򙷬MQGf|}l,t*kJs[Q6^>29y/Ht`A 7 ]^27V7+ |_1Ybay$ 2If0kW0ww@Y^$q]u/oEuH\?-j o_$^1_R^>E5cU.O^Lj8eP{tax-(,W(/05~I!8^:X2apv㩅nG4w>E FA9K ~ M1y"V4T=MRilDoejrca_<2[aZM]_MjLEI5nTSW[S 0rz$9q#ѽXB/`ɪ7y[8+$_ ù,}]hB/l-79p:jz֫YTTgGI FwtZPtd=sT'SmPU u}t!24蘧k )C(kT"`PHf}2֫|pSKK~m+KΘ$^t^[Wi}evÏ=i{  NT(ߏ2 oF<~ԇӠ67qvHWOG2R?3 o ͪ`P3mU,<\`2lӮ՘z^}g!seWBb.F$^5)<]f(Bԍ<=j2;ʡx #(AS4xHS}ELOCu\Kbѕ i&%Q|xqpAD[L57Cobk^$raCI^ ޔ~)ޡ֜gg\Z=2n&u9DY5^w,2y$e;ߍw%}?Ij]qa6rIɏY;&yeMIo';[,O,]ly1 k=h}Po+qxC0#TmX׊!>Ͷ nxh!ރ qw8 _׏#AVv'LXgJ~t( zY?X&ґhPg|=s4xM)##H%OКׄp?$0Uu`en.LqꥺX< HuU tJ(\S$ՏSBv$TY~MxQ#3nR$gj~*2]&Rrw-j='J"PnWG KƵ5 !Sʏ&7oJ͍$Fc܁IU8K؏"Ooj6JP^Ef "ߏۛcM\l(SXD}MD3/'b׋Y>^1CaqU]DT7Hr~"{\'_S ?*:jŀ&Hhn5ti9%Kn6eO-m4LV/m|>4N9Gwe樦 xƴ(Bē`^h:u 0˹FB3H7JBYu9)S5'l(jl_,̀cZQVD'Vh97RV8c8T-'~ `<$cYWe{rpYF=iQ"9}jGj"(40%$yH-pAE >7 3WUjǰ: 8L0'D´[2egsdaC5-2}(ߗnXP9|DLh_בF2:_-;ƛ+D}*MrSbǰ}YY+9>iWA3Hyz Ul:ۙ? >C^i*-E^,&&E^bZXN:*} hSl'̔?R / CrR QݰDŽ00n- :?* ,)Ոķn;94Z29! j5Ry/0t$$:Ӳ9^kWQy Ce]v &*n8r.q0bh$uj́bk _ ҵlԩa?^<=q<$ga,Bst/ b=Y<`>1{lqp:'K$ZmrB@7k&*S랳ziL-{zA>^CK" <-_c7w]'6f r;f3,lC$- e: q~IBSJK!dU_t#v8D7yM3oOsw^H>_J TpCiL"nsm%Ǻ&9`3C"~pGkUiC cU NA B1!^h4$JO>FL9a&~PZXt  ?B9_ Z߽Mbw{_fC!9c%-QV9|!d9F]M7 K`ov; d[mF&9p}{v?E{ן^Wa.+}Lv˭\fM 扖)d2|Z67`=4v=$t== fgDQ<`@k`CEwk0#ly"teGE|:RG# n+;,3ΖxՉ"/w ~dl`.İ'r5 iQ(n?R #fLoZ$j.upt W~18=V$E|?mNpV q^34i[\L4l|iӖ-74hgLv :LF< c#OP ݩdY,}̛2)5{~ 1D`1sQosy!秖¸L >L5 ~˹j{["Rec_݈wdkƽ=3yOgQ[r\6ܺej VggF:dEW#D46=$ $mnF-r&,J mB!0T `’;Vȗ tFnʘ cN[ ~nj4X?slrc:VsB }ᶻsnHg]2Z}&eKzcLyk9Iٓaj5"IhsaV-垇 'tЮT~ nzn8w;]vwj9WD?qylt0#wosF X nn!U _?,_Qavc8dȃN?(=e@s}1F'Ʉ]5w|[%)߮np;IQ۳qHqb;{mЯOuyKI>e!KB V[\eӢ6F`]I+GgZvUXg\{ 3SXA:dDíV2$B MJ3cH|# _pŠ +g0wS1Tc4ǞAэ/UoaF*;as3٤/zNd2s~-rv~~L^:Zŕz.b.OnF7K=b&CdLYoI3V~L3a`"A[Ӯ3Mň047޽QNXLkG#HÔN/>1 ~iۦ^wA}nF/LѭAzSD>(kb_un=(o~U4oa<%} ?6F1Qhyfahi!s^3@6_oKͼ?1y !&ԋAHeW˛otjѲJ>Ǽei)D7_t#lg-7e TЉǘb"V%1iLs>M¬kZ*6NF`Yf^ J)$eɆօu೼' >2j$Mz) e'U:З9m1L5e7n2 D yzn孄k+H^BZj7E <[v g{hN-I-SѨD#(pQwh#&gaRA܌xGTps1.`֪vqnL[U^YGyNi6٦{y5 u\,g;۷A% Z6,a#ф\`f/&~6!qQ>6:g/%*jj}upgVFeqm+.kVS*}L;axmQnPb-`~Y땝f'#8paK~sq YXA{'*gŌH*%QEޚ=81i 'P j!㭙(jׁV9K]~[eD4H>a&B_h9"}).9r8rLڀCoK UEB#0ZMR1O}c5 TD6VLT2YJl^"S透.aȦM)*vɮ+G2_^FJ]u0aJ`{IHnce*<8 ?{\c՜}>"jCQr׸QzvHŕrQ][jH {ԅh3h0]~RH^IBO}fۑ¹clsŁh4J?5n!H`!6SȄ:"z阯ʂlÔQّELWo~NlQ  =z˶wiY {+2lar,&礝&T~"N*<ˇ3xk[1gӪE CB^.zb _''z{f`}_(dWLKR\€1s'e U-nRjvqJ`gO2V933+T@rIӍaV7P`rU ۻ1RR\/ϜV5eA] RnMŕ}>~ʶx}G5謮wiڷm9>U4 Q>%U]?[+J ;"sw{DKto sn ~; عkV,@H x7k@aVV =pLiˉEzZ!A;4b@L3Yzqs5ϯ\tHM.}HD6aoۀx˺6?pq- dD4jӰ8*"pdTu8-* $ j2 ƬAb9)6k=1p5.8{I67>coz[>vo Z3݂XNCX"I:RUsokGK+MkɓD: A)M>dEZB"ggvmȠhZhH sZH\CoupR4ALLl̀Qbcnk{fPV8JΎKa&]Nꄏzy!Bh:?k^ irf"zgbޓDRs"V0Ʒ2ۣYK$YcYoH@)KyrޙUx4XCH^E;ZbΒBcN~X8uD8|fe@B6n1Πv_GRG</X~#uv6$2}مRkm^`DAj~Jo;z4z\:1')Fyz=D'bՈt_# k$mZ$i9G%GEoxX,wA)(:(ҋ##Wo>626N+sɓLJyIGE,.=ꔴy#,l# Aĥ0eqXڙ/{7/ی7#m3gmp`E% 77zM*GN̈́)y6+}6v.N9V*~:2(^X_fmM:)Qs:}`9Cd}`9˥T@`D;{aSJHF3p Yx #գZ't+$! et<6)P{9 xCR(?1h!d|ǓUc' `mU|b0m#uSV '>6ew `ſW1Jk_CaA`;8oPSYm}J{1 Yw+!aq1vX6a23 vM/$k0 ģ`NĎ^GԮRƚ #SkI.*n.A(M|e0WյmN={TNӲkT˺%0i@aS!|΀F_VUAs|e$gs2u3/&Ȁ9m-030 ̍ĂRunsZ'#6Ʈ`_VTle.*=2[uQg9 '眒ȋXo9܇IV xG1퐡{WH 99g^\3c.#5CTb%Pi;SW KE>;ݓ%)DY;i&E|dgOGZ/}Ì |^CxiE\C;M21BjbZSa i?'џ)ȅ+5ԍM3˨BQ"|C[mdQ,Rd2.-)ysٺ5?\0忩4 qg!jtςdQ-OǁA-\$ґDV^|f\O$$|`-W_?KJ&f ,Ke3֡IڳB^,bDbuPΑjkI},.b "-Օs$j-,\ѯty:%IBB[ :sߚ.N#D `6 ʩfh˱7nYy>0]!l-D}V?1$E@` KfˌXAw5؁LD/JC.ӲəyPrf* @aLlZ vm-[wr6L(Jl!f*PR)wشFĄ!Ik'g>gtͲ:6W}JXoU7Bɺ"T]jD}\uiQOkO5Pv- xK~.k9`؏< 17u& y+!?8P[rZw82h~jΡrÛKib~4dm1,(9ׅK堁?y(,Sl.lnh^b> ~kKD3W~eAC/Gs1Ȟ_JF~KI+KK?';dDh$3[]|g`)•LߦV晰+U j1wPw‡~ica@ qdRB [~_m$:s28ly%; JjC4=ݧCSLz¦{e&Q9ا<>M[z+G}gIdڀt)S(iy~ƻ;Y?O"' 6=1׋.9\ Uhzt>@$O %]>.2,3 ՒfS[sĄ,C+B9\S]ɬж0¢'SЎ'sNw/ЎICs xY|s#;ȒI'@SPƾCX+b;Fy$: h8rLaFO&lP^~*OVuR^્GI#_m)ҝ>i?"^T3M#Ϸ* (q(κ{Pa笫f*IjeG\mcg{b. ? =٬aA~m9U>mXuEQc2rH:b\|c$.53'}T6Z >/%do_1_8 lPsZ/y^JvJfoO`\.MK{oE7Q#al+?0r9 Ͷ,pYR6Pvtwfƾk"xM>VrW0L~8^?mC^YߨR9eU,m('չg6iAJbXv4,wۯ!y, ʰ-<_=3@HUsJtЫ Z7CK[Cںl2Ons ƈ*J5N7?[¼L`DG_[1,ܠ;jXF $n|b2]~Q/pU'xtਿ1 f2',p Kgj ,EӡTou;7j)Yߏ@\ڡ{Pb.b6nYκ1G&pː.[$,~OJ*bU q-eFk1][q4SDez}ӿl zAOYrI'Ho_;xYEBrմkWj-Ú|:Sړfś* P0`n#J/(dh#ֽ֔7LƳ 0iB"`UʓG/ #O ৒!g8NV4X}YeӔ"ُL=l|qK2]JЍn^a纆q9P# rFt# 16 G|5  $Էʑv<Ly(0ϙ̱f͸|^nO !1ϱ64N8̜j9IcGnƩMc  n׳璾3.x;O^i #nʈTR'FFK>Y;l+?0z"2˱+$@g2BlǩFL7]].fjK|q#So(tH\˲*Ĉu +llK-l{J iU[tCN'KHR|1ip6Fy%@y k_|@~}|၍ShĮ/<}?kp9LhPI"is9DNs2A4S_0xc0iZF 5s._ 9!;DTcbMpWZpJ3v@A?PKrS~r"W-Wl09I.@m(rc5QWyTyw0AAO Y iGʾBNƳ,ϖse4kĢI-_>s "DHX.@=qz+"Z#s m/X_y\5/;78*  aSZ(Y&9Ubޞnj>dH Q~qC| ˻ 5eS'²`dʨ+8*{O/ID ezg"; (bYܖObNr,K#Ya|d, XQ#-һ؜q[D~Լa?sÞM1)TNǪ&2*M='F=:OlO@l( 2PzӐ4!9e/SyHM/rRv̇wV-ƂB+,Q-{#y]& w6f4sCDdó"-&6-̳*Fz9BM 'jŏuEkC>T7Odw>ZvUڀkXW{NJ' (wԕ7@*S=}O)X=}u.ǣP*JïPq-3C}"i54y@9n)&9QsK ](Px>sK 0{ۗ2́i7 mo:c3 M=Ja6-GHrfع<][rʧ)8ZfٻQ_uy1)Y`ʃrfP5 &qQ'F+uEr`6,xKp7Xngj{[m_NQ]vG2|Ԟ vwu˳uZ[~yT!#̾ky $WQFJ NC/T;R{J7%IhY ܾ=~wІwr_{ANȍZ<[> 0(VJi)[~Jv)pRߥgW*a"0*++!B^3h)j -Dj gf_kgSuC2 'WY73HTZ1P9ޮx/ebʵuHW=g`RqG51b:glMY3E1S6# RfC #_Kv9” T:]@};2)0KgSpKG*7WB>a9p `6jVyAߌsړiOU62'ʫvv\ޯ>)1hpKuK2%u:GXY4Hu=\槂ySB*<ԇ"1{^`TʏbevͤmC%8$lڙ]c g܇gקKҀɔ"=v@)97#^HCe93$!Pd KEdW&-ڣD439=*kP⭺:-a5fO;HJrRkc9}fBゥoE; Vw:WBJR~P=0 im4moEf_▣Ɗd0?d3 ǓZ |3wW& rwWlzĔ6֢j*v'5ZBȹ'Qʉogu`B'wG~渼IxRs 0l=eVC*)zI,<ɐF\o#B}`ȏh[kŠǍ^],ɻ"ֶG{oR#@-]YlWL9Z|1zr]Gٔ2vd\, (Sq/E#努i?SrTHuw>]$}_0XĠ FMz(qNn'PqcjT|-T2 -k \oU%3&PAe]Ƒ>NFa ~P!=Pb):&kngQ,lΜ(b ct;Oy A5 f_U.EINH18.XmYD<ͰUddXǒBoXge7൰+5:ef43#X#_vP+X޻٤ #1;4r<9sOu$\M$ӬjH octHmfϨ:T^g&Ц7]7KWi6-YV0e$ۻNCej_@]i 8l1 ]9VN!HV R$>`x9lu;#u:,԰E/E# ṯ0X°f8O/b3|ßlqa*ZsTJUw<]+O&^jʧr]aWGbVAwLF2VB ~i0a\V<? u-K78l&vt־d}J`Oul [SyvߡHeCgIHIa,CJ FĿxB.iN)HۆXZ%+c;2_,:?W6*5C;րDJN-R{  c(%B@$G0=T\}M8vzX8Qmڻ$78Ç0"o/D6^5y7!t?08mSߛ'MNt9;+3ЋB $."6fVHLå d"aQWI]C.riƪt]r$uq JvH浣m 5 ,SYdK@Q# -MKE30y2dkwzKe&_%a(t]%"F]f@Y-B` 1V/ >\\'l}h>7+4 :[쁬2"qNsV[ ڟf#!cn|Dj}[J9ÆHDiSQs[ Pd㉋?OK]K6za_ Hm,M`2=:% JaLˬh BgLB$e6|zr?v FOU{{{7ѷ&pQȧN+tRq`n$'I|LWϒ 2xzc1NP$8*:gOHJg.Ū\grC# d/`n(O#x]:k>A *)C!*lrG`tSW͎7:OJ `oϏWZQ *#T> cԤ,{ȂMMGmBéxFFtPq3ɿ(C.:2ǂkaDAn#i*g#=y5FnVbAjSM kvY?ظ%4ivGS:C4OSSpS a4YA_7U[ sPMmdy߳77(Xf(okI`_kw-N(ׇ"{_&Fcl[uG2EAV;|aޡ&M$ Օ(4kw|(@|ڭZܝa:gNes&U?Is&NYN'D_m`6B%n[zcl}ce~EhrӚnRؖ7d7[1Y!eڇ8łD^nrmCݷ ]&njo1 %郾`ſ%'>o%8A'xi5 xCUҎk=xҹt_ bpi* ?U6h.h@ ^ XTj?b[Fe qrE@L»l M`~Payv&Ots9E%0LNC "bH0KY6}' XM)dLŖ`ؽLXČZ  wX$\BӦUn-c Y|ӣxcW񷭚BH7- 2N$kfSP0C{o>ZYzQEAGy:07.vIE؍ lIiM `}W $[R'5C<σ'v<*8WS,#rM,ЂDUTÕZȯqu^ cdGx3s;ǭ\.(4GoW8x+ba~_IE5pBE'KkM!;w D4CTn7<2.3br]˳tEv{C[Ϙ5ɛ_UCVx>Z.sr`]|i^׫-$ 9Go0"Z,蚂xZz ƈM $UZ5mӟҤii;&D% | ̂ZqafyJSCC<=|h1U=wEV8=jSLeQ5Dt+Zc5}T|ʃGO B0k~tRkpTJDAI[5_qi1=H `d˝mZwpU[,8YEupqW{\=BdxP?<\۵vi\ ,Lى>fqWkbEzSq=~F6,:`qLZF%\O^?gF:w"HgYsCC϶/}|[mqX1G_Jjy4xm@4p}/= +xINviGҕ_OYv]^D0+ץWgrWex ǮֈTEdj+ǡ@,ZB-Z;/tN勊Y! m0zã0*%i?^*~Yl.ɂHUtFLm&.~` ZABMtMQ̡M 1x5H'L޿BWES'R(I]J[ Q|Į!D30,f-m9-->5[K^a>ryjGӋ &aKm~Fe̾Py[R"%8:͝c٥>0e0| Yٗx". &׷N}%lr7ahA4%2a64T<Ҭ;Odž{DGn?_@tlVjZnHs*/,Ą_b Dv&j] *ߌBr;A~}#6S* 4kCJ;r /#BEsҥU#Ixhd 3^\x{&m[4&ٓ[ e1wuf#WϧSeMn -dG:v(o"QӶU>.pR-<'PHͼШ:ݢg&Hz BR?*orIPh-Q%e雼F☎]~]˞i i0~r Au 0BLXض ~ռV NuuQӸt (䉙B> ] 9`p_$hFJyWuCwTo52KŗC!ǹePWO/>kNʘ < 9\s OJ\p᪟F4v|R$#? B):f2Al+20Gbftx^&KIyG$7CfW! <%Iu,[K*#:S'?$l.w rYP9Ǡ̚w+QqUe$M."TEle-K,ݖִEJ^fI 8\!#isVy|v~l5Pׇs3ȹu:qS aŊר +`;2~KN-5eyZyoeRS Yz q ņαPW,q06N]=BQ?5"{R+ypPRV.}l'+ͥܓ|q͋5} vI7im2baYs6182#\]t_vud΢-gf6DX~ahOi<&dF"FD+8xmg'=58᤟&`F/-Hq@EZtD!N{!p+&饢9}D֦T'WH*n#9<%%xL،ngz +KŜLIi Cv]"N)/dPjfC8̔ʀpO/>!/(47gܟxʳ+EݮbL>\k]s5kIKQ0"u3Wvhv+}Hxy`s|  }5*mt_@PVGe 3GPsjɅgOƐ\{q; 88]O$=sی B_4V`vMD[@3G6vm?7咼kl:fJ~caID]` p;rs擇80N&=Lb3BEzLucŬ3trgd JW.Eu>.FN℅O䥩. ҏ=(9!(^CN7X Lʉ,gGX`bSO_-/9/&X`xwx;760ʣ.@!;f>{<{%uJ[5KKj%M5a)\U|NJ_~nuRŘαUm@26wfZ&{憠dJ>t9rQ% v"1X; zMn3u=O1^<:BiUS+x{͗"5?6:~Idb ut- G~1y:ig^=!TV˪t3E}ITLTXJ㰱xn5EĒu,I9_kDL`k-"|C)+Y @+|ւr/:' Ot"ҽ~f ?w 4Ii[W݃b;Ҭxw\Ӭ\ 2 b~qqǞyp55%j0|<.*fʏV=xbqIH:#5b+VjdٶfKTo;~pꓧJ|6#H l,x8tN q+eDa^%, lq݆wY X^vBXz$+3H]([ \Wd]#g&;Y 8F4ӭsVӁĢ2ŕz}kUȚ?LpI@RsSf즼xw*NrxLF'B<-eLZ a&|`W ﹘ "D-d7z5]ռkҴ ?`ƨ=?YEbτ|vVk[eɖ8~3 >O6>@VW[@w"^{1} (a맠6:eZ\}[h.`;O=H.(2ab|}|o|/)ů4|T[!f~Lxɤ~u%S_gۏzI-9΄`1;jlГ%J2GqE]~s=&leW$m~c4\ȠC{~)H F5s8v<]cdYO 4V:1&.L:lgi߆'˅GS<֧nF65n+V` ]Mܼ=$ /WYˢ zmd~u}g"w+'x֪&/ (A13:sH!e] !](ds7̈́Z䚽پLҟ~@*)Lq0yiЇ\u#grlderY0ܷVN! ys~&a[b!"֐Kk3nthI6X"8{ǥ嫩é3a#r=x_Ԑ=2lb[E3Ʉal&Xt5_oV菚6kG v`C qsljfMeE.R \"z~eǛ0͙9Jlg]W3/ԕ:1ŏRٛ#Qfiԋ+vRz'3Y \,t}2nl&FTn:ZL~ͷ޴#BW0H ˉΐ0Nrq-1D쀑'LXzu65a%,&Lo<Ƅ ˇ!Tny%߃+LxTBEUZ}z gGos Xi68(Co2L)/)D! (PimlU!VV-,կR 1=g:^bQ]L#5-!h4k\5 (.P*)ϼUx$s"`A6HbF+;MMvHg{"v>I/̪4N=VA  x0(Ȉ]~e:za͹\EG5~+5i%kAQ-¼/'X ~]ځ x vA['t;XG%<^ATcˀ$ɉ8.N;ڎorz,DI+@%_GZs\k"|)<4|汸m%_3jJjnv#5#<@%gɹ;(K=`Ĉls_pij4Sd=7Im>y(&4TY;)Sg /^~Iךi_ot~5IoC@d) TӜZAjt.+eMc9p`W(R,2ɿ Xvo1PL\ݛPU>FgZu%/Y/ amAM:n Hn2˒9/} a}L٠+gz}# p:&Cih2j~貧X3 cOs·["~?ot 98K!SP> - dZZ&NgXစca121:lH t^n<f*P%gi>+6gID=t@w4|6 $5uuCթХ[׽(c_{; bhtb*)bJ.R@USYϤ;'^ -B&NnQm9V-srQ. d>gV'+} 4KYq9vW 1+i`ZcbC;eƢNXۇgөbgW>rC6%UU%?,svcddTpA"}rk؛d>TdYX/hoNownx<NG~h{6$aE8\$,gZ:|b39i^/k4r8ںUi".:oӎo$ ,6Y6茳ĕqEdkfbI`SXp!e/xYӰ]fp25} wEXRO-qML %`LEI޵̴"?qnmz?H|Lrt\Iқ$v-Ace)OVFQa&d'62 _t٭:V&W\Fs:4LBә 6 ;2({p!`YE15RvE[d8 Bb028m OovYCОgg9Ab]j0|vHX3 Y7mvg>$/H,QA' V.K}-Za9z|C_*+s)ހ1t_Ҕ=LdmoȟhVq)'ѵ=/ 8&ԕ\h"] l7y9DjK @ne۠$:W].nE>65*yIE©1'F5FO8ŏVm:"P ȍ> nmy]؁*<ϩxL{2H1oO'1xzK佚-%.5eyn.Y\+b8捃mU30&}VPwܐgQe>Qȫ(y[޶2l~O9 IQyos@Wۓ`e W0U'L&آiP'qp&mMPvPkFuV~Dv 'ErޏgaX&!-sh] fw>,]7%pu4ň  u6b,̰󝬁%G .Z1';=C"˵B8 oнӠQϑnޝE0'm<5{-?U5WxFEW\jQLƤPxwx'+tΜ8eƞ*Dr6CCi4]>::e"i=Év,=1'ҞVCZE0r6gsF0jFv@Y":}#'PIR 7 lpUyuӿ v(QC]ɱJv 9Ǯ׬] J*lEʴ֤Ѐ3{`v(@P.qZiثmǞl]ࢤ|F^;Bxtl<$Ͻs縞.F|Ɯ`r X;[*<'9fwLç0VϬ[c+qR.ޘ3V/p!5=W 1I_^'Ŋ7+[B[sR1` ٷ6Q&t7`ÿ{ \Vnlf>uzE?ZpДmWHDح+0=L’MEȐ.˨<< '2nd! M#L O yJaRݻ.-z=7+k]'K;!w&52j;Fc,h-ehX$^gzQe/!K!EemXD M1+.̜gB;XۅvQkxIa[ 寉Z)˶;zmvu%}_8f,n"Iwly6-!SuSA_sg+#T=dm/$s~v";m@L[@^=q:b*;Pq|S@0rm*QPiQAЇ_ k1CՒ(IMtz|ǁP/:VWLؙ1|ĉmxbvmG_~r _֣Y|D$"XO(fz9euQ)1q/ӣjqE ^rjY|T50##U^F+Ocgc YG*IF@t4&ub19>[WyhX&v^yhqH,ix?l0FDQvz6 wBSӦh(esM+3-` 8/P8ɈF=:5mFFh봳2[}= ׿mwʙ?kmiF ީrg"w^vܮtruoNg7U: aE[1Y-6@p Wt!YZpP_XtP1SGh8c٦idvB#yqt2&MgUD~1%݉xë %Q(mnH(9 zcЮDťϟоv-g=][2W_ g-oψ`;M(1&#d,Y*"ϱ`J5j3W˸1Ql4tV:3(Sp][g\:W'GQEYb|2w?Ny%ˏ B~ |Y O2)CGD鿀<6ݰ=־aA=v{,KdkW:'2Cr:u!r"  &RAPnܬ[z!X) צej{n6;utfky<CE(C\iAlFB^=pnLx-S[÷@ӓVb!1EAkЅ&:G)/Ѝ;XO,g?')EԕlJ*&Ʃ Di$SPKq\nΩQ˼ )jѿrJX#quoQeqs&:ai r6jkn*(NldMnn{W8o7q=li3\veve 04[[ڢ7cl=I+|Yy^\0Lw kF  l$зE. ZZ ~ MU`b$Gr /B6grtG(y8Vj^#[+7_1 DQvt'.p" z.q!T2Bl5#=- u;8e׋l4$pnCxlEz'P#hiqY6E*V6f!씳ao7nk/~E>IMU\>P)p;Y2"{wes#B XSxI!bKd ̗DJ&uOu*0l)g7a5e4tV|M,F$E{MA(7t&R+XZ_64ԯvY=9bKC;B@X 0D))}^L?Ncz?8g$ k%ҩ;Bvt)5^x2DWP¯'߅`].,s,yb&Z#KU-G᥵]0#r?{"ϲ|a4ߜiؒ;JD_ Ф #,HwM'݊e*wW}ɟ|IDKVٟ{xð2>BU(PŜ(B3o'n{0R}Q*M8JD̮y\:GqM@8&d2ⓡ  B;A zU( u[0(_ksMp)ԽCJfڃA z2-7+YΜ$BE/ d3ߋg7Szn .B\̰2:xNbh~2| ~.Xދg;;g}Һ{Yur©ÍIL),,]}wWt. %uG&Njk3LQB-П.?kYةz%"YPB@ Ozn%2^+;HGex又Ҋ"f>􃠎]ae;{q6+`ÆQ 3 /Ԝ-Zg  U9-T|P ŏPGH+>5-0`(! "!X!vDxXzޒN8Eƒ$V}8jf9m0kV⸠9Co"~f9M  ʀb&@v0mϣF4]=vc{] mj j_Un$X~] gmq;Q%g-rt ˨<~o]:%Dn)EJ+ ͭH~o&|pCf \NtopSAgy1k 5O({)"H}s[X'9 anpxS2;M,em\OG~+0"w5 ?q!_$H7BLSɥyuԥ˽uq&v^Uxs^!Ҩh( dq?!c9{Д"gU3b!u"s3ux)(s~9Hݴ ʜLśS6Uz(| ŌA=.{ZIa}~ n6=Õ​w0s]s-EXY_iYR^iލaU:~;F$1:^oYsP`Gv|t9tayPGzj:D_IQ6µ1Vט퀅U=6\Xe>ގ_'G7O{=nVjz[^p GH,mKFRdq=(k-3t[^0[vUb~֝]&BʢA{"eR8֌؊$!l_  ³T꧛9:=138>`nϙ1 g.T@*4_ t2ZO j\sj )="F 5zjFqg#Dt#1Z= zI"5ny wo:pQ!,ZkQ_K:~P8$`*MOfxF1ewKPnD%c$d): x^C>`ࡼ[<] ?"kʼn6gO(klX-~XhQFymRsJh.GaY}?EOjN,A`7`yDC[<^To S`Q+W• Ȥ+&CE.i5{OpNoH2z!oPBEub苇x$Gm3%֥y (@"_lFcbD"@$me lRrŢxɦФD2&}( P9$TR~h~uNWic_qczB)uPʯMv2G֊IOCbCdP kA7%~Cggv-*'n$=G>Ի9[^F~(X(wnqzheaNuOV451ADZ~ ?̀=g:Z!VQ߸by `֙\V(ܩI%⚛Y}M^ՊGn^ !;O;Q/-[靘>f#Yͧ$-E!e#q1/^Ukb=Zv14>qĽ%Se8ԧ|oj!i?7ɾl ĢfՍKh7 ߸!&JQ~kLP2PX|Hݧ4oSV#U P8R2,|OYa} KA%-RIGͥP\^M*WC2apP0 DOWG[;RۋLOOL+t(@ =j7|Y){"Fa'R kx#-ORo<D^2lV}qd=wT$|B#Dŭ̄N%m<D kmN]z)rMa8 Y,{f?P5ptGNu&2ZpÑ&4NA\HH Y #Rsd nqTUXwi8[/ Ø\"w cʻ7'V,>1g_HHHƳT.چg[:@ck8_HBjgjrHrwQ6mk3$m͍M`c5^ Q꜊; #a;mvFwyz p_amC##lnHǪR o5mOg3썘!W*='\:SɃ?du=\$bn-TuJ"-.GcYFOᇟ4Zxй/fn JF8"*| BR` a/M% t'iLmگ !rY<1!M `XYa9?IryĬ4<˫`kԅ%6Uk1* P@4YqjE(oRʦ$9ƗV5/4DŽ<dxG为jfU3=owCdKR:,U߹wgp(YdH%k%ClzMw""6btKԛ{oAF%"E1U Hd =^*ExڥVJL qF}%rV ~g9tiKԅj':.['疞1yDGau3H51;8cśdI~ rMsH7ToBrB PU0Dͣ%i9OB.425 uHBM.lsmr.ł;$UoQt^ZT0S eSyĿ g9GNB/h(O{5SmkA{Q#\$}B(c<Ӱ,YznG4Xs`vF,0N)9jRZ}SyEcd͏+G)Zq{07Q9AXwkql!ߙ7 U*Hc~7Y=m()57#g${"s'"-嗻,-h0M;-RVDh#bW?ϔSU[GPAs(|.FMD1xìˀ%[f63hnjo:?FC)X1.uVK-n6aNFm rbf; Bxgo~};6[HQ>ͽTWV/`m<>߱oïe3lWɄ3!J^'j.׋=fHU',=<>FZ%_< gG4pYj6qpZ=z"b0V`hTymK3M[.s:n? F~dF?"lj0b8!{nBYNltv6- m`Z0V>3<{|Eapf!=jn"5ף/RW@Icy Iy$`QQ$L9[N6OwB+Wp9X_)g%eX< YЋ,wA+C$uOSeBWs¼L'XnP\z첽3m&C՛A|!V cWN"d.EsRՃ7r8K=!ݴצH(S~a}]cn@>;%Wɮ"lm/?'g:iӴ'A#q#Ȝtus!qw(C ¦pzO6ȼ'P܀T:`oeeA#ʇXk~W9)/`jQ;^ݜ\l:$OM$|N>2/4Ro^+ȈحKXW!Q[Dl(fOkK./G[{G8Kh$ty[[֊mQT40~eG] @~&e=luie]M*T<:לF߁NK2RID*#u"qacB_x~)/qD&*4k"OJ@|.ЗyCsѽInJ @Odrt{ ;A9wCGcj$Q܆s:g7yW=_;\UfcuHpV3~jDKuvz`⻜ooY=~tEQKWoMx/B؎Rpb.5]s %fYf8c1X&h=^P*\d YF/7~2!7ՙ-s vC<cP=^aotRVsG?Η8ER|1󜂶#^B>ؐ ᖭz}'[Hчs.k4o:(Ws v?=7yBWݠsAl4'1* wPǒ; $$OX,a1Yf/29OlxhQ!BWUzHO]n|XVRadMNU>hH=|J`A 5D}08>%e9m8{?帪 C 觽M=7н> )[)#?#%8W? 9xFmnƕ!,_Ffeل\ʼnhw6;m*[]ᢨumZCP-]w4slB1d5(lAƬ6?/Z(:{ =4-XxPzTZqN$tv[D:yh"Blђy1.$r3ח#: SX0d5`'?5SU#T%N>djK}Iy\#|08T 4s1 \epՋЀH7ܴk<^tP25(Euco*5l+1 pZѬTKJr# XaC&I");kc6l)|<#~(8Z,HyR|;YP g˜_ZJSLL.Zk/a!zM$!3n(-pQ>x Y̼rLh޶2薬_[luՆ P~ (tNSK9km#YYC~ 6T=_mw`ۗBh&爗1ZH}ep2 NSK34_iHlhO+n7pA|LZJTl#XQR]tFN꩕#qj;] n2KRQ1L1X[xgRPnE7R€I  CZ~)`r /9lje(7` KG]2h(\!>4s `/Sa zEp cP+uKvs ܷ֡&&,ө\u#х* wӠQja+n({hl\)s&Qd7Н2AF'\snݕ2 3IhGu8ѭnK@1ZGKmmTzǸ=/jixZqKpCy c >^0KkrJdm d*>A|p]Dv:AQȰ?jJYh^$V_~B5YK4{ H0YqգMل7[+2¤l!'M If [b޴HI&{o}QY|΍fNS`>Jhw*6`Ҕap|WZUtvnBvvH| FQ ~k@˜Vi}Fz1hsPdWN\aw6٧ rF _Cj =᎐d5L];ic#΃MzPh=KzSxO{xٗ "sRq{~:^2(wuY Zl,:x35Muֈ5/d;궑޿9,eҔVϫjT$)eE;Y Cv#guRa>c8_W/|g e* V֒(ts\lEKatha S>1!#!$تcka>Ca,bj}fL^G0*{<){ _& h|J7y+qVjϯ瀥AZi h@ެWno{2)ς33G)ۈgH7gy<"ow_q=ޛ1IR??LOP kb[-C`ywb'Ff6 _UtZe8,uh爖+U'AB0yɨd}r.~D5 j6b/{ bR2@;wPUi8m]&~XKa>r,:{5Ę[yH=ę/ uv / Jp'(/rUm^zI)+-f895yl2Uv8(EXնYx9qR $}:~4Gɿ' _P@L׭F8 A~]6 R^БgmqI&PpjVH\(yFt+%b;`\ Rgt4łٛ>ZçAUrjێ_`|yFXyiQ3XxڃVP>vv7gWrߌ[Yv0,|t~)ԥ|wȎ3^Pv]JAMC1 >^]b 6/Yι|{7]=zˆLs*"x)wԵh%͑iZmœTygD 2Ķږѳnވ S;IHu"eL,Ҿp?p,|$1)}.y^ P_k_M8"y YIN99?=>IZ8o+w!tcz5 0jH8xzVmI֬bPV A G,Sѿ£}8SX Bp16]D[vQ%s ى3ᘜ7^vPc9Z4 RVJ眹&2@Nt{/@W_kć@d Ћ zQ:Bn$,k9:"ۡ(ØlҶig-ڐ~Ȼ'TUr/1m7X/^;w%irTpabtPPvp)[ZD~[0ݮ&#g9]Ta fWD#p8 Zz$?#^K+$|**]\ ]1ȸ4$ekb9] cG9Xxy4.@]>b6 Oz*bR"ijO3(/#*=P;<y~ w*z_-KO[O3StSc+e^K9CbIN's `n:$fE)%=)L͢ĂjOlk}쓀:X&%=I&<"eLȱJ]*Eisŗ wNtIQi,nTޒ_'9dInWkT!œY]in@#Sr.xCH?`]mGqF)~r/,.kv ;F嚊;Dއ>j@h' ZUey͂&= C|d'%0f:1wrԑL76AW&/H蔘bmqd[s{PmئEp6Hy&^ڎYO&%6jʟhΐٙS?@:2":} hѮV0'hL5q/WҨ>I5~a=g@^c> z^avN 7$}!.X҉Po^);:y^Lja_v/u̓6CǓirY>W({z,#{7( jm/vwJ-'.SSCQwj.7Ij~P`koQg >~d~LH_+&ɹXy/œ F+4i`S1f?f,-ip3uDe3x'xv9,L $6 vE!Af΍1rԵV3wlm5摌N"ΧƄieoNe⩋,|,^@n(ɏ%izr׭IK{#@+m׌6i % R8LZjaPOeQ4kOKWk(r ["A0*7eIiJxUC֜Fjґ)" h%-cGd`ا&l:X8A@5~0g*O]2lbj \֟c!O.l=pYF{2EG )s/%S3Zf w<~b,벌>#i 3$Cm0D'NX,CQ.2ʵ'5tĎumgޯ,drV%fRc,іmTh+d0giJ!wu*GmnNj)F隥.+cNbA~D !TQ<]7+SĒJ=$G~+/y[W/Od+ky>W8Vb$0O& RdUCc?fЦɋG>LDF/@Dn߁%(@qSat Nqd |$d^IT#7^/MM֪S3dYsia/;ԍ;fro݅b4?LD1‚}"o;m; ނORC(/: zhuE|?SM| 3eu%Xc1)<,3H$y敟>䜱&fud7Piz 6rQrp|y`s4f5Ƕ3=[bm8-OdJ3s Wχ 28B N{Te)lv>yGt;k uwwRʦǢb:w+'_aZ4#2]h@T29")g ܞ 5j%|.g`-۞ ?IoA ~guyMU!So޸3jz 8j Wժᅨ{t>A^~Yr m&RoN{QA;~6Zu2f4gvٶ|?pfŗ tuХy5b;̬aG?}3|{HNX5Qѳ%]8`?Mk]CU<Хq3~ ]JgD#'Yo Iۮql n5W:/4!pu ̀x? ^/ЕЄ3Q,[>苵SGf\JH@/+̂4]ՌJ$*'9]Y^Bf8:fDb9{(R(iXJVCݽ+P1D=‹%X׸,%Qߝ݄e(&B嗲56rYCNXf&K ng Sz1U$fO,=tն4p'K4"'F ፊВtȌ: z.`]%"uO_6$سc+[k3սE2$ (j] x`cs#7#>NF?Lvdo}Df+}I᫳F#HAAuH/#28]cAM>RyXڕN] uSho=g8$f{ Q-R155!UYGK>s0_QKDC[4ź V&8ujVyy3Z7+h뺫~4\lK1;u(얭m#'W]-KEѦ[/5Iw>R'zΤ$o$9?U7t-?6 pɶ.Uy4p4*>.B+3 ΅pxg{JHKsE`-=LkrqsSo>ƙ7r5Ok<˰1G .atv b;v]7u<`! |ҳDNcRRfx^bp?'djRüz[d}t D,6]Ryw8TyΗTj6|-&O!Ս7f[X3;UZU ֺ >w{dLd<|Yhµ}_g0 _ X*K, -Wp _fxߨqyșZmE#% H4 #A߸ݿTGMt_Q WY[=T G| ˤlR"򪀘 Ur}0fn2vwL:K`z>[SUޓ1Hs|p^0tk;ZX@) A8zS1^gx|Q+f (40Y%O78tj+0=MUGScAe6W(Y_:kB9}1@Q~zp`ѾHq6(z)wB/S)b? 7UKtqz6j|"=6 jm~8&NpE@.{ [D"=gjv!{ㅆӊ(: 枠'ٓ) r(wvfrM/q'{L4UI2Ed(?$Ն-+ςxv'K\,54YA #\懆=?ȾlU+˾ZοIlj i9i+ζ#t}uOʫ2"D6}fR&jRK/WҍdX3gȭKVcW#Z f(j#J,j7tHÁKPM!a2`o/EI0R4MtP>]%]vN8ӴjƵI7 eTS{e'(=U7oTإպZ¼G(=,""HDNJĄv U!i:ExFY5ȵ+=܍7 0|TԆ~ǒ  <\3B|4fYJdm4CsG8#4y(Nw;hM`kPU^o1䬰7'h"^}z UBÅG9Ih-1; ڳjhQ-*8Rx'qEeaZyP]WdOw~?zgʕ]-4z@W7o#;릐4ISH-&CՖ'f&Xԡ8Kz}wXCpkAT]X^3E4 `t@V4q4XJ2CtchE=[lk\Z+%Dܯ֟9\W茟p]8zA6vlu[t4>]ᤁUuä_ZfN󋛊_[s#A9蹉5h\1l05vl_-KQ4կhcAVWՑix!ÂWAAup9QdȮu̝ ̨CZ"1ˈuZYbki% sD9Gg՘ 5H>"9タu?HI~hm: (>pɆX׻T1w{qE^U*rw$[r<#~~q{AYq,@%lކ"#a6?9Dc&%`H8^j??*K$hQ 4)dg5;Q$ܕN fAiu DvЍ1c_ސѵ.r̃u/\ɲW{>T3F%e#zǛO:i +X7x$_S]2o.7\9f([dM{qs*H r-gǯ*Sau э&O4 HĊ{ g'}d#)Tύ g˽ϝM=ŒEXbRJU*f0{R)Z`겟[oDo[=V'5?oVr 0PDވ~y6 ͇!YE(i+سX}WH)`S]<œvᤡ_8)}_"[t=kP@H{]P>^M EJk@V8P|` 5w+e#ss9ϧݞ& Q#_}$@:%1qMkZ_ҚgydbEzUΩ~[.H&Y+bn}f,7v mV+4ĕ>z.κr { [~Q \jVmr86;Lox:l8Ƞƶ {h5TynnjY)ģ02S/' )v%kSY,@OJʨs;z^sWڛ<<$Ib߷]5McpYjE"7AcC󂍰h];EA[2LȀM;DuHx5\NҪ2ݹ#]Cx ō4SnmBU;f^2X{*} P@Iw xv{+eXw ՎYMN5 mrBH_s-$PG5|&S v&qoxXoc}1rrI`u3,fo'UG_/S!&„.p|,)(…26#o#{&-e||% paԌ0 }6'yR]kQ#Zls += NќsO"&HѼ7‘7?3\Bm|TTβD,u[VӔp͹ٻ0#^#˗@BT Ŧ?kw96զwhU9(⛍}|'nھM7FTv˼U$-"؂ ;ufN, }$:*rz ^v(J$pek.'@/ d +Une`#Z'3Gi J9"~j~.QOДT>ӄ0cr&?# 髺j7jKim7>qv>Лnsߤ?5kLΞE **y.>*L-6%9C`Fyn;x$iʛW̃%Za1}F38gP|v7g[¡dpA{Zd=sR`@`HweNz@RЎB!fr07K2c'(d'kPŶ2PWhV3/w"K̺N#1Wl<ʹt5vY TuCBsCm B1tk zʐ-2|\DE6U'#%Ŀ.P˜27~Eg`OU,ɶ{UaQ9*Db}jlU+5*/lqR{CB Zp AvQ㌱A`o|dFKGԱqk{.h&q^ fWeݮ֤:K[ܔٺzӸBIǓ/ ?yc<ӃjwM#@|L0a\H H(`(V: \Ej6G.'c{f"|3i 2^gYeo*,cP2SN䛃9"Ws  X. T!l,P܋3\9o527sy# Vavyɛv;7z9a.p.uqWO/1hYO۩ [;,1C'wN*.3O[ޘi㢢tL@l:Zgx/t+|m(lsiam]J)ĦѴłYĵa:1`OC۱{V/n˯Qi:w*~( n9QZ{jys-5$(Ž"-3AJF5>u5wv䐅[ZV%rr(><%NO߻! R.s.47Lpn&g^DDk:ͺzQ>jڇ4 Kϸ3_1}'yG3ul#hYi_Bo"Uhh{me:H\hIbB.wd6̐e Fڢzxfm\dIY yxH$T1vكQҪxzLt[zɁT't5ҊcmΘ`)`7Nt.A# CwX} `Z8di`@a':*Ўb4Ɯ#TTⷰ'8p/B:G̐&dpE'y^fkϏ !d=ZɝҒaB #EV\^:袇Ĕ, JMCf#!p@G i`:5|hRjyZr°ai۔NZ31KJ m%͒Pӕa]p!/1o]sLv3}iSd2/@B(Bsl/ ;d ӡ |扄 ӋŶ\&e,g{)֝2)oοz SrϬa+0`j{΀w|8)K xwlK+COܐ|B<:ԋk%:i@kn%1vHwwWC^nݑ'P6$ Qb}kàoaHxs p TWN 37C(# u_]+ϹKH*?,}a˛uSbm_a<[z4`2s3BUyIW  ~ :XBE@أq3пFj@{6xo4i$/]%P~gl n]o)Q5= 81\6ٵLDoyZ 9(f),{x| ӥ$VEIjɗ@4ڍuglzAe팲fd][_tv*Zg ;Z}T47>?$b\b<=rAC(SKK BQED $)}&_׺-x̀ǧ9(UΞ%OG3\Ӡ2 k]92] tU֘~~ܾ8i!)Qʼ}'O3 miYmOD y%O39F1_b`Tϗ6 S| aW*N'y;H.F5W>TPkx͈#!FL! h2]GLu7{U5zae/7:,&~iO>G8@05 _~ K 8Dٱl jHz? .|2IjQटL]iW_`zmzHy%*}d`5[;tuMd9чOt4`a:$ B&x1z7{ڏ#I:^ϞV[Fo {@wׂQd:FM_nJ)!y7aZ@~2!F]8%]|!RrqJ2b/1\l&~6e<+{muY>)sowUmT"`{S|VGÞ ݽ-(2Z[ Y;-`nJ&jsw֌A.Vun Ę {xl5ӳRNaT },k=v+L+HĵSrP9 ECl~&e؟h"vp&0bd jC']lŅ>M^Q"/Kg?e*r.N{0pY$z\"7}|*C .J 42-L@uvo žz1%L@loh+ i.#GWR<$tg?Mo}'=h@;uB-#p&PSԲ57ˠJdž GFb;'92/>7GG6#`w¡DֳoEwmRxbHqНTs$h3*ܶ ouC(P)U逎%V33gNQټBw0S%[3>pipF˼xHnIK(U'iNP'O`ZZGe ÈB~z\3E16bR=2+Ŀ?5a&L%`Db[T?G_LMIɳܵ*rMcqB߸ <++ -ᳳM/N2tܙR$%GuM1c:lJrt[\3'boxK^@s{-l \+55/ÃP1Tܰ{!(GUXgU> y9P'A|i[/oDQꤖ#m+x%ף7lH[I4q2fY62ee)br0U<E5 ̓ER>[~m[ʕ 6P0%bcXG0X=iE5r58!sTan<1T穻zTv]Y *7Q!.\?*ClIo!pw4A]PpzaTA! @OCmz&uDQV7F~oM@'C%%Vi?z^:Ud֪n^Č3¡%K6rKz Jj1b4>#ЖVϪIcgUa sA^Ԯn(l>8?Z*ǰ !pvcS*fwH˘9x)Ŀ™ XQ'#MasHxZ2 6*F̺I+!x4n蒔{gWm_Ooge{W, SɛypVc%~CV_^<&883> bI< ƼU2; a7ёR $%D)-T"cKI6VTl1*ajd܌x!)1c0 `& M/)x[!gYC#@V 6V(Kq2!:Mtbue'( %alHǛ@E ;3g/YtR#ؽQv@=ICx1C:~`OЫȯ_BdZsZ~i—b|T"/J#2Vra mJޅTj=ia9YG8j?Xg9rXlHv{~EzLgo="" ,^u+Fl2c"K ftGDyPȩR3T!ml~0i pv8KRQ&Wډ7.׃2DF ʑ㩦uytFN s O5GUe3o3Cygq($u3UwlFHTFZM6w ̓Vƅ1r+]WL]J]pǙ5m?-EQF~n(xCsu~' l'ۙt*yQ[:_5qE%+h+K$:CwbNǘm-O,f<=!y%le4X[?>?Xھ>_qК+iE u SpHĢ/LvS+>HFj>c2axSJ5[ma :iξ%>yC;K^W$`R}VtTI߈aa3f2YkKұvtNʮ; zb@o[RU-#A>_i D=.bC=%G>C@-p`"L?'OG`'C}$ք[1k Q$:Y}H͚j F9PgM#uc2sܾOt {Mu.x*+ݮL0oc(Ox*1}uX1hY9P\~+{%wb])ӲگO_"F8atv?4e#bS4-3oߦs0Lfy+R'/”']f(`Y.>Ai?1zC'91³\<g tU"IGy60rp#aI.KHj3cb]{s11}3$S܈W3\!#=&mBaǃn#Di@`(~C4U{b<Zꢯf^svC.Y/Ep}$1}ɖ8DjƟ2w|Зګ'lAYz|mV0E-6z<W5;")Uw[c"Mxȟr*UiC՚yQ'~ZYݍC`'K7&Vd#|A%щD6ԡk\'c9KyZN(\h-! &K6r?܅QqCHj;KwzxGhIQOalsRAppڇZ{!^|Z&uE{GcP67HC7ޕV/7 @iNJx;6T9 p=iF=y~4V'{u:= a%ܚ YڷJQ7RcQ.|?(ԇ>9O"U"]~[YibK֗Ä}[LdjO ȁ:ν};\|?qdžb ֵ^h8^#ys+Ê͒bq\]rJ!Ɠ)k;,͊KV{W:eXQt*Q Mapb@1qn5¸;M 20$n!+2tP3q1-t BZ]`Rbs+QF K?$a#:sEٞ#f4 V6Їh7񼋱Nk]PL>^X*09DʧMx=9 #g`H0g'y@:"^H// Y\ї8W'o[|7aq׸,rwG%FFp,TG!TM/#l[P[ΘD٫K];Bx}2 ;/'}l(@=Z_7}V}Wѕxo3 /I9g[!{/Le;4to'U=D3e~_J }qZR?jzItѡlL4X2v:%$ҥԺ5#G:u7~mzy6;wyG $Rt=`#~+-vkZ',2}-JeT^;_$t[(> [ZR"x]>UYҢ?xkWixj7grꢀ?"Oicƞ栰,@ ZŎAֵ꫔6l:k{;Pu!pҋj!BPnڍ h['(BJa6ʛuV5`IscD ^W058!B'>%4m6 1$R(E`2?|~t3)5;] [P)=6 7ݻ`& pxm]øCaLA~ |Ȇm/vi|Pn L4'&v\!I5h|<2E} S8&ϋӆ(k̈́÷)7ݧ>gPlntҿ}E1Is9UyW*YPN̤cTѝ9"~ܱe dN>A} 48 U#mXdwBxۧAPo漏k&y2U+Ą*} .bsM;WHm3Ehݞ, u+ؙ 4扗 Iq: , ڷf%Q[i5.<  NY<@/nި'~d|J̽)>U6Ԁ+^=>fPx3]c Mb9?&õ^sHǡWK(YgnAy[SL%^!,8[ig_iɇ~>&~s'.(r%_+1Hi7ԧ!{ < ϶/jA8lLK>{ZdzdC\ȹNfi j0dPa@7L^8 "IQrnW~j(n}I7>,,Jm5\Kf"+-?gmUx$wXXo: 5&,UDωf^|%֗%̬ý-@'?)O]~ͥZw=^9~Exi{.ȬiŒ@a&Qv3feIP>C۝l= x̿#V:4 } ӣ2Q~CJh,:J/_|{?>eoWNSTuE pP-Rdd~~,yB\8Ή1 s㉑Fp4*o׼uǽǦu M-ExlG$hm4%5-Ƈ"4ؘڽq%4U0k]et8eS21 Q",ڻz f9{9Ք3H{w&z~%ޑOcme5ŽK^` JyOXꥀwq,>v![r2; _~ ?֭􄄽!+ŒjŗK4|wdȯ,d΁k7m;5A|DzrmY6zLUGPOLGHjqvI\c/*D1YG ^# :hpL©Grh_$A&5iNi0Jnz[=OVKgRBG{W;O?WKhr۩Pk9*DAyD2j V?64C$jVL2]2\R9 =KUfl G!@ZbS_4! r-MkJ^5Z[ tXπ9Gw_*v W39M=.~RnZnd~M2s~Od($ wN@(2{+}Y}>T]6!XB!/=Hl^8~( @>6ymJ+M*\5(EJpg>p}莃һYl #sHO!D| Q1ΛgjWF*Ɉڧ%#ZW0ҫ~~9{&n xy!S&8CC&z082 ,>%QШm vgN_Ĝk]bJ%G+R0/zTM(`J<{k@‹⪤kx9ЮvhEK5C`XE:_WJ9H}Rmܾ݇}~J0[r\=(+MNaӾJeiN8`6̮kn? Bv_5&kI*KDΘsƀ n46?%Y)=|0!0QE5]2q\0Ѫ/^b)u- z+t3+%N#it M1v顧(vMY>LSBT)4.; _D. ؋BFLhD)XpA|s5 mZb=$ Xu%95kp"x=v1uvJ-̟Y1K Z=T׳d0FA IBgZ+[[48LKZ o3k)?tL~Њ!/?ʵwakw$S>/P$@򾹀䣽@PCLg'}+ 93Iv*YPkh*3]K&wiѽrZ:ph`?1<_0.-m:*Q݁[&k>1hI}9XwZx5@,4+2ʄ-1Mj<3E-]dٮ7MԮDYQ`69̈́7…ybR:| ]!PtL1-, %V"b}#ǡtp@챵"- ıcR)Ew|84EP51 +z5tܲoQ(j)Hhh E,XRO'">"Gn=sP6ۛ q5'*yoJ,M-" i v%LŐh)nc)JTum/1ÃyY7x&T3Imփ970nHDMSy"BwRh>t CK$+Ycn9iKx"{)~8Hj2 2'DJ8rԱVٷv ;¾)wt &A'TݔAMٮi7BY[0\i̳ģ3Wrn[=Ʌ}_b [@Y`-St]K)m> 2Yqq" YW3q>e^ↄ/*&`ҋv,%)K Uvy<ضH.B Ӑq=4q^852Pɺ1:L (d_(ֹ͒?c_Θ]Přx"JD/i6ERDag*&=4h[Yn,K16>0Ϸj:MPx%x 3CX 7N }=O"~CAwhoz浰 V2-gж7<+/e.= nUQSI5 Y+܋#5NGف5>ՉPٌ*? !uٝѬ*rC鿪)+wFhhN'+p)u#AnfDYf,Hk>MmMդzD8d᱒aI|j@6+Oʝ u8sjjQ{ܶG}eOOp9r^TDe7Vu8©N\u'L.E:u)9Y3(p0gC?/3:GwI+&\d|B;(P`KO3rϜۙ= @uXѥ1Cx~uEj)f?(vlZeˏn0àjNn]T+BhgÝioRE0*Ld:Xېxz7WLjbZZvL͖\1d9tR\ |oR)~\Xi|=s1cHGRn.NJLʼLuYfD鹨|a-oY~!|[_8|8%_лAfod֥d} 8e#I|1pVuqswd"~0O gyC#i?\C\QXg7<%F2 u}8z/cN8njDt0$fLCɿ)Pʄ'b'Ɛe;+ٸVׯ܈ h$5tYqN"HmP3e\fOyPMO @MSc֊8q!ċT*dK7Jмrg܊yZTpz65A֏FdsD^[0ȎI#iJ K:X<5Yٖ݉:y[')­ A'd ;}.sH]-g”w 3F쇇:9!977b0bfh?k`D;sD es'z@!_8Nm $% ;Oh%H"'\oPP*Jub_Y3hO34N? '3`M;RL9PP39RbTGg&u0WDoy7 V@i(HY\y}(h0|3)asɜYиh/3'7 Uң 9J>up,؊>$W%%} O3 YZ1<M=П b. oV[}eHdl,6\>^e}/wkێq[bǓ;6I5@8,!GTjk y#MɌ׊@Hkg !Jg>hӾ1 ״aTzZ-.׈Ѯfe5LI\~H7WG.،|P `&QA f_n.#$&f ]|,`)mt={bt|甦> M-;&vJs>kӨ(2!d 8KffyI}9Be íciAW|I "wY_=5vs;hx;\`H 8"߂פZ ]|cٕϿtMq@ U !nuYWm>A;-&{'(zӲ_%N+Uǻ()'Ykgl)uv)6$;tk|y Pd9>AĢ\FTg_P"5r[Vd[bn,qmR%`>?KQɉI^mDuAwrJߝ8Ϙެ^Lzw̵4^Jv8w/aHa:'?SlpZ]b<Ntⅲ36K|UA=Xm VGDXV\3oQKԋmkF!y /wzjFMD>*+.KaQ@s۽` 1 +tWsn0lO@;_O7짃^bR]ZÙ.e?NP R2>ʏRfŀNscR`D*Y-. &@H|9EHx(rmQMGeoȾwM²ͥե"t+*y'Ó3ڦnE~󙧬bhyPGKA 1J˶UY_NEUWc/, x",nirKN#u3g[IDp6ya8&nm,  p&~{ѭVVU/c /W&h@ƟbX‚ЅZ355ʴB*k½\Tyo8jT_I|ј["j|r_y0h0Y.aujв&d*-Ha3WC0L[f^9[47)LB_uДQ"oKJt(NT!Ȳv-PŅ^jLlPF0)s%[ۯj򜻷Wy`! Bn bVYMzhWԉFc"A~&T([]KWXbxʼnE&E9^Ѕw4p+3]+E_@2 jsy'R.10LC_! o3!j_%ASV>) oq(Gtzc9L+I楧4ᆦnKQHvsU7=՜30U8Q,nոy{U!bnݸOHDi}bq#ӶДA>0-HˑVa!lp|&mxKi4BMC6=At3}{:1'g]^?˂M|U#$f8»GBT >"^#r RB|}K 9K"40O U0$mlFhZݹ O5qc_g;D*|峆IBS`1jb{\2%9U#^ ":\54`81"Ӫ$vYһ$C g cУ\f\=s-(@ׇ(nУ{cuc6Phʋ=XOQê/?҃q~eNW+DRX*#;f w 9̘VNBu'G@A- ^4ڕBo2ix)^nUw94t5e "9]T%-s$Ȗ8H%u*X5.+WCiNn:d/V\v&ʎ cJU+(u 4OKi &u0˄ʺ89`< ů:\*@M[8&m'YER26Z1Bn- Y> +Lg 'VOFiO(J1#3]t6KK6mS=x)j:e:7Š&fBH5yb\^gϿ 慌a_%/@dy nR\Y4 -F-z甅|*,W <&_Hv4: w>Di_^"o.>i G"j99{Vd 6M"+Ai(ϧv&Q<xPg\؞q. ^M:Ir[$g H;r0F+>añM h:Ee=Iy]63/FDTGC’Ya)S>l|pLaa  G6ipmvfz+9Q#sRw,]pᘁ0mPB\5ERoi/y qz y_<)΃1SMP-Dܤ)@~9k.'!>)n `ldP17T͓,Bcl}'vQWWC(}Fx5UP^&s^awvI;oBy $Gn";;+ݎ1>ld1@5uhPŇ0`^Hy>zjF飼z%_Y_Zsox$n\+%znf׷{ߣKY1c&ˍck< J^_[ſ'D0RG ^Zx^A [yqǭ4\fo'1G7s > Lu4{ެ0kQL|\݀05`ρ-S kY^=N~^'(LcZMrVt{ [O ({ֽܮ;6˷mg.O M2pG`b9W2י?0d!pe۷ء>܃-EZW9¦ |XP^']Tu&]=l[r?8-1uUzZ+o`Fd2*Gvhj49T\йN^b< ^Xpt u@wM1o:e-{Xe> F˓Vb"`[oWQԘDz)~;rX{Y*@jZAS/rk10%w9lN8EV{NQMOsdyg|yX1)NwTAiRM,jٯn%삫#\%<cQ[dYӴ$MfsWYXBOuVUHң_M,-p"Jse\?LP2~#[W5xćp+ ¥ >8fDb&)>~Pw ވ=:A90WP&UJA.7"5cz#~Us{@' 8OKҴv<7";711?p"|j\fXW%QbYzY}"t/GJyo>O~9d1[Tv]5|(+hR/m am#eaReӸ*F3+j`;0wdHtI;DN`]|A}a_0Y]P(*㾙(ğIxLd]s5Fs).6H ft W>y|`^w~i߷C(ƶ[R߲t}뿎8" 6`d$V?u^ˁ P#k=Zh*=+$QWPY+ӂF^v]f.kR(D7OƁŎ;>$qR6Z]*E ;Хd.>II=6zׂ)!`cxgv (BRX r!HI*͕?6}'z!'qFUL1i(\ҫWn1>kݨQbDiyL֡P/>|Pc4EF#dL Qnv84pz-z:(W {3nmܬDjV8t3$?< ߇z/y0hD"lj8/gK^ΛYp.E<~aEi.EnAԟ0yћ|9q@ Ʀo d:XiQ'ڵ;t|ў;sNM5j~%Yp*4Ll+&BdsFx(G-;8<٧*d! `"Qh)6Vi=8gm/@ t}j bEPFXXf:% MO O(K) bEN5?0El8ԡTJLѴZq.{6[x )5H)1nAiGS>x > !3MPH;-sCfGX82x謲fa2{}0Oz}<2eOJTEcLs6tizyNDDg5fSnN8\7-|!M 8,p9TLϴ7U u泝Ș-cJXx(6⠰H[>c |q ճr8ϩ"0&,_"΄msŁkS ރ]qHI=j V|ȷy!ۤFGo"5 L8Iu+7h(>lI(IƧD>QShc0;b=, oVűâɒTJN-;Eg k= Vd!6f |L6+lͥ(ljZEStXYT/b:C&b -Jrqy4l U̠Y9WM[3& 'BA:Icy#&jv%䠬Fԯ?4&Y869pܠOO9k{/'4aT[9S,F &K)o~6Uq3jTk &Xɂ캠_񣸺;t5^J:&>?_[-]L ,kۉWf&cMo El0'xPc-L`.dj.޵9Lb̓fcȆb bˌjk + lbss8^E¹"`"~#H"1b nR{S!'V$GϟHr)=w YcFy[{+{jh~16.Dgg\[')~v%} X}Rk(>4#|Ý6tR` .LԱTL2eK7ID.O=#9K 5.9DY5i;݆D0WFg ܀&-L_?/`%F ) -F.j_zMY|$$W<OAjyta#MDҠ'zmWQQJu耳44쨱6",7=z֓8l<0"}$s&5# z'I߀#+\ohμa7ngV~4^]֯+7ʘ+bmm!Ay9%<^;tuEPjq.c ?AA|4iS hS'1+8 T@(zYCX,?뙬0K߻ bdaˋԡa 3^ѻB߷ cޘ93#iA#JED2!J WZ#F~_KI??{\ݻ2_t5 !z8)pT()瀙߰|[OqG`dk6}Y'fcZ&0Arb.IiBp\*(  +C`9@t37nJ„7q$b6 W:v@? n>e#7m DmboNpdԢ?qK0 ahWxD{Dm9ɱ`#7i-?:ўI!4`IԻRneQnYr b!Q38KazN! 7܇inK NH'Z &-aI:`G[9-D?sI~CZ @Z;Q3r Uh*%\-=sgބkkP#+k=avD+]s7t37U͉ˡ& |2s@$u`C˖_zs1[+z{DYOBhixc1^W u }MjJO׍.Z.@nLh@Ḛ~攵y5QD,tHNxaI C4T cGsJAp0btCRwĻnxM̐h}:R}l0!RWrhHiZ; C\l;C'I7BjJ˿~2إ0\h:>PtG= V+v`] }}Xs>5Sx[@R={dM0%LYlD,.㹱d6:sQ yo 4g}?MiGC(Z<So$AOhL&L(0l" 6h: RaG[O#:> Ed_Y2ߙ}^ ]{e׼K$b2s»Þ0q7_4֙}vB{ðhtՃ: Z\>WTOzK8(E4:([.$#g[V9@t Yޝݻpӡ0ƜilgKɗ*9]b$@bxUDԭjF!XXnP=1OWY X|lh>iVi0B/kyߠN17e4$/)Nyeg%㮭ʸ{1^)fM>1Qb1CJ@:r/4g0e"p ]d5g|-+ymA =~$+Ik76e$έr~o0ˡ8N8<>I>{$r!6نDi_?ϵs]'U1'Ŭ/;/5/3LZ܆ юB ǽǷ9Ƽ ֔y!amNی7i☢G>MMgf)`?3[+ᷦφrn&jy$ŹVZ}3W>y3՛CP*+ݵA)߃Y=j (k3@ZxDVaF^mHœcr5yNVU΢o!^KyL5EH Q[IHB*''vdkk>g LIYZ53F%6;7tr|I?!kD*o` @kT4vߞWM0Nˠ)GR&E&U5Ob` O R]ky"\ Un\xr"\g[}$#$M3FT {RNf9abXtԲ|_:i%\s?&֎ÃVKz%D[0r T19@u^prjJ-T\h%Y(XΖ%v`G&R<.F>r ~#)ww-!@ڑwdS#V΋½ I}=P^#XH'/5O&\,6P3,hB'.`±/ꊻU _e\/rq`ԃ8;ִ;dI՚H=LhX1w: -zV4CKt۳TH9hyp`L޲RC"‚RkY]"}pU6="6rR(٧b*k[;QO}AR@):qK#RqJe69:X2=Ikj_ x!ycTN~XjW?ڍMgd$_4ɐ^`ʄ$Ur_&N©5l6rJ1&1[8ߘ>et!w/M@"Ȫ ?~Ž*rCё\y։iE, rկT9 -60j"ef%ۤN2puP;iMtdUc,eNy]KՆwDi$]ڸg T/YJZɻ.RScE8o)eVMҘby/!ED:Bt;.Fw8\4o6I*PVPFDߊdD&a]c R Q4qmOd}s`k+\{KU2ovs,"O]*{ƒֿ ssC" tBi  ČQ1ܭU>rsCKFr3IנPg^XӺ Bh۬UϔIاo4v ="/$4Fͣ޳% UꏕRwJJU,ŷO@d<5!AެT/*`!Nd>߇y`!|klm̑x,uvnjU{[7 {*A;$dy*$zt>0X2ͽtdcq9+Qj$nd;6}I [Orrs|d ^pfH%*@[H5$z0͞!/X76NNX ;^ s݊Fƥc]3˛ipBsXa"p# lѡڥU~o nq\8:e%{ ^{z(9Oå\X=Q[H4 LpXc} lMk_Jԡ~Bflf-dZԺ]Yd ϧT7hd3ZjV!0.gw0E[%Ȓr<9m?q_M T#y Ba;"0PV\ ǿ'T&Pv1}%I> h(G,pQܲW*.\ PrLJ 1g/{)Vt-sY*{[QB.:֋e ^b4$|2RB#cnmɪm _,3u޶VQJcIIZBOQB2]>DZypLT=DF7sS O!>g 9R'Eu7GFx0Ihԥž@r##D^MgVZS9NMj2(Rûu$r~힃&SPD-.>8.qऊ•CٮZGc\,yh`_,yx qLxHk3ɵCWBﲘط6FvL{tX‡;2ͮ^@%a?^h/juYWc:#-g!Qwi;@Vjux~ \oH:*>_c> J+UL,T}gc{`)fوOJw\~A8Cxh5,rlh9Qw%,x?P%{"zj{t`oHx$ݸ.3Fsan%Tt!Zr;?lcW~Ov0B$+H䍲' I_y+D;8!m; `TT5: @kvny>]471H:n2О$)LK.8ճU?,8h;uk{ls$+?{ݓ9tc6T):RTZzaҼ? jwT8 ;`|lg}[K#-4x-N9p))Ƒ_ FioG` j>BlM*vo8h]E7{ Y|x[n@=qy&m:O6c*`e+1R ju[JÄdEDR[asqe&fs 5|4 }?Co@]u3V$xBRzsg;C40xʟſ[6|;˿p|# C[x[qflLRn(}4_v#US~m=j *ybȥtB9/4*H[p*9TQ#S5*R ;Ge-b|r$f hlu_14څ Q-o|nQ>t$h3:YАEi1޳#tyS7 :%zq( Vz(&d=W*Ed8#֙!H|&<J+,ߨ eWw>hU>?\Px$QtsunchA@Rp{T|k\Vy31*AU@aN{]O`\RUjdaBkWgC=mC evi/ՠH!3g@5M0mgoI|nj"j0S$r;T.Z#άŻfFt{VyG:Q yB:ˢyy}\,t:ZIَ--0K@uz Q"Jg#%6=l 9P&wqXxV')W$< WQ{ͻd•@-1#' %V`\z'B ae0wK^%,*.moMćjf3,7λ++Z(h );8sF4VN~l( Ip4{R$-jDkV[SEpmoxoHl0lVO3WQʛ?bjѼ5m%dT㡋a@TSs>s MX{~zj%@p΢l5.#D4Xjx&w(5yV(pc2P`h [%x"Ȗ@9 "Pyi3E_'ԭ˂4ٸ Җŗ*׉Yׁ=dg݌ hڇUH%c"[p mPRݟȺ-v0'd%uM$_ڒfŚ>CCM \:3iUAe1` Ke;>ֵ=amڜghW1R=>Ӕ0K*yEr.6:BI0I D=8a$9!s ` :Jz&zK{Tq9n:(Mus@7$V4~[z{W壀Vm;!Pg6|gŗ>_tpdY?p^j~kgG`LK/C@ _MuLb/FOw1Ua83y |p8VFr{<?ߟɃ*V~灟Nh(Au-G} _'ܧ] I-VO@QbpaȤ蒪L틞6 8sdk(Rs5< I~MA ރUS <7NL!&&:0#*pI.kn`u|#mdQē[Xw3v&L)rW+@itඊw$隻RUŧraT :oV Ӻ=_ DN_sHqѱD8H\qtSYpjᖡ'$"|>ǟ.`M- gR }6Yu?dLz[m*XڑbUhdL䊪=ٗ;ҽ)xeD t:C%7wNd tp['ᐻT?4c^ӰQ7݅7r cOD7ØJg!hiP{U;%xvC< 9;e2)"-[@11nô s&H&FÈRT魰p#0chuc%ګ)بri~&U4ʋ)A`*G};K0{CFcмxZB/׵Wgm#eO)1\fR F4'd{@"kE2 nx|N'kC#yj"օ%!Im}0k|}naՊ~T$OvQ3iEp3G$bP?G8nMK^А.w7JID=@JDTzk)-C?\]1W?n*6O8%&TsGUUќ@d|&zHq %Άu4ROPñs vJ$ۥ}5'YUj!lr9K=𕁴Ҷs^N}S*6׌w tH1kdJƒ8Uݜ2iWOYVǝfவeᶬS1)ے0]K :v> q|f~Mg XVns 5M(.caU7ߒ5`p .K>Y=4RP`&Eƅ [G K=KU޷ L߿fm52/'|{w>+, ]6uhT"&75@c%?E/ʎ* FlC LK7OF14lwޚ7ŘĪ%$ m;B Ҥ-b{oMqVx2BN{”.Vk&.b8ٽvjJ<bԝa3yF}ޅ2KخM)XrNq` EmFMCt()cK$u[pN)@S>vm-z!VLLXjIWwC{.|Gn{Z1CdĚtzkpoI׎Whb~0pxUԫZw9Z3.uj)@rGpE*3uJ]gCV2WoڏyD# a&_jTq8QGQ9xMC<7*8ХwآPǦҴC>'qG/@^Ӿuj[jDYhVu Gl3ϔ{MmH mC3qFtoO"L"ڎDBWQP2ǑUy'dvuX!WƮaʆG aF$>Ǥ_S}Hҕ@7J 鿨4ߪ, ب8&gNO>` 6t`Yg4XSqYCHDoL>_|S LDZOHֶ{bk ZoBwu0ROբ|ۼሽ\o{ua +DuM8G@Ϣ$=?8+6AcTJ8%7LКbseCAPHR u tBC[$}Tj; W(z 4c+p [&ۀn;a.4gS7۳ rjؔ~=1f(NJ(&5}Pb@ށsX6۠t?Bf⛬B'PpJ],ߌziP{E8SNi8 ƪhoU,ƹ5͜d8h*"YX'Е2 1ɹztئ hX/jw!zXp 'ɯ>3l\oQ@@ '׌Z&l3-MGV2-$VXX{B?Oq{zƅX}Di MebA,j:9"gz18aa>5`'!+*%DAH=q'$@8 -p.ߔѓ\FV>XKH*\UmFZtKG|mѢ)  Uhtq@q"Uu\Nn 랾B=( N^E_O^qőuKF}SoQE9QD.7J|2骩5B11=ԖY2,H}ύNWC?Yoh]es@+0jI[}ޏ>qjhow*oe_M2<34UK5:'Ѥ~H_{'T=`qWtbj~S׺ll0GQ} c&ڵmy)xڇ{r'i |6h|+3Ū3eJoE9/xlMzR*-թ3K? Ae3VCJIGʇ `f!\Y068Oo8E~5V6C.~؛W}B}Y}ʪN6f+B(Fk%:R{V6o@@>'UV~Ս1;OH-%[tL'ZN+=oyjMy<8OКvLH:1퇴JdnIg?SWp 8 ?l{`C-ezbLXk&.E$ h9aR!xBw ҥ Dt]n\Z"Ԕ\Ņ0H22 k]]lĦoޫ_XM^U-G?T?Ǝ;V?8D KH:&O >agzjN1 m{ իJIx/(N$N@Op2Z Sx'Nk#\ة2 @B"2He7b6s>4e-a,JD>$tR_kI~v4J{TFHJ Ͼv 'NE7|p/88I2uLܭ"@R︰ik:7ʧŽ!oh7uϭ9'~K:q W,E2Ig"> %li56sΉeK :rn~,OeXhOA(~$7sTQgI,} ;O/nP6ݲ߹S2" fU!HL͜#fυqn`{~2cƙĀGNƎGY#شU`j)bE2%a`WU]EFZ+&@*ۡ1RxÅ!Lh buadn6.iLIŖ1bfԨ5%.pM ia氱"[ހ_ yW3S}0ܟ栬bƬŚ)WBBvҕ~/?N0 4e;fX}"IwaDcMڽD͔PK@/00tt@W0!jδ35p]Zr:C-q'K," +Zޢ57Hg|Х nC鮋 )BKn Pҳ`O|KA7e CҖ ?V)šX7Dbȶj{Ou-v6s+r`6>ׁNKjnQ!b-gL d[̣vh[7*]'1'\Dtc=ǁU3*F,?M mX>E@^_|HZ7aIhhc(8YzJ\\ecғw= M56YP@<9sP.wʤqz=62D4w\{Qz_,@'(y*pHqmdi> ?[\ Nʽ>: ' ͠OG,R kVfo޷o^BZ_tT?wƗBC5t!,[YjĻ(a NIi'{!-9Э\~k[kSz7R? m 5LpUaA ߲xպa*Si^ @Cw7g&{eo\K__`@aʲs0_i%ܱ%6B$6=y,P'1S7@ =Q4؊O2-n*&Z`E!w% 6Խf8.YY 4 JA λ1oIh^&݄%Յ2  Yxf)3GAw\MTϊ M%ԌP<^G`x&$Z5nF$\yBVQ^"~"?Iަ6N/iBPƳ43` fBp/ *.:5Kc>26)bv#N-ɍ"j@G;/f\WgpB.jxė2B33CwJ&f?*6\a{ޓo1-pǔt10 )T kLx^ c*p2o{;2+1Bw 9X$`m &>b_y\>:2ڔjCwN\'#YbSmr5@dtzj]\r2' &/+HjOD/&'/ _b>:"M:U`T5%KWxOB @T/[.ž$4@=ܹ[3| D[wW;gK{e `H! zqSrNd=fKA8#oyǰ,T tF{+ω橤Ͱ:xVҗm:+y c.S5ECR8& {xE9 QPHj19Ŷ4$1T:ƤKTTp,`1*5x>EZ(mّI(L'\}YvAWF"MF|_Lo5=7b4hG[&Lj!@`m⪋eIr :)%>~:>J`X֑jQfK۷)y[gmC!P ͔; jn ?)K|͇loйdbw_դK) h LqE9]?f(Gbp N=B1"ޏg[у_1.DoCn8~'ty-Uh|oJ!s jOfJÉ@͔XYSU3yt0"|eV_-OX) s \5tg5wv+D禦%^qzJLq6PS,iu(礨JwjqTD^sDf)B9pn5- O:]`s-YÇa]n4pו؀E)/V{&?+{Y Gd.[wfDXkP6^>zO n&rmT57 YYubz / >w!tQEf iEEOSkhZ*R>Q$HSl#\f~TE-w᱊(a35PrL*]M~@Ck^bbi2_Yј:J֒O' nV\\4@3FOf!pK ?eQǸ֑5jf\ vddqA`ֹ\k[ÅNm.BqM,_Ls>ޏCޅ7t(":$i) /V f|TsV􉮳F)>]ƴWrqߪQkunD#RT뱶ih6sߣiO>,g7u#dd_[`7Fm].c HJkL^ ! E,cqe. kѝG)|wdRj oM.hkvEvеU˽ݑGYZZ'V,7&;`T{^O gb@Y0A4?Fl { z'$X|xvGųw=xqoU뙅dEۙ{'jYwpG`n@' Y % # bnCL vtPH`)ŝqI`#/8p$b{q~-;H38FA[}\V#O3|tZ*Y+ A"$k>8meԉo\N$M", Ύ vgti( `},Bs$.%ϼ|Sm+ 4,+tMZ i?mObخ3 W@qRYQt3TV$űY$G?Ulv5k %>qRJ#Vrm|']|DVDwd8R}dNZo8ꛬp1V",q{2Z0f|7_{δB轹K"L~ ф+< qƦq3U~LBR}<_Ɍ Xץ5"ƬS]bpNqXJyeoŀWe-5]&M; EGh~.G{M(,gI"~D2_H&BMG~zl~3OƨBM%aή jVyFj@$pƨ.AFv D#Nr&D>0"[UqU~}S Ok)_/~M?21mlQ./CGe+dOE>Vcgz)|VyPD) ҒPdT4gdpeJAY+DR(ُ0ÌG.#K|E@ 2yC9Q9 hx*~JSQx D[ 0r2U𓂷kԢQLLg]5R=}yDUzJDKև t$s$kM,L~[v9'茰4)΅`Ƽ.z3l=bzt@| h , D+ue|sRsB:YROH76.#)8#Zc!_4Mٴ@&gK1_EoXr{5*{f]]ΕwqK:[D@͈V`jn.L_{0GeiL\ 9EJ.4sx>pquwWx3R7%, E f/H]сU+gn2U bU7b-خEumkthGX`ŦTzJ?C:ʧ뒋e}>YR%9pQ9!f>1 _`P/Z'Ozt%jD]v0c_*5ܲ&>یcU)>zR%>٩ǃ]@#{HMGy[!G 5=Ay)s֧4I۪ xܠ#vCjnh#5 +:qˁd PQMmn*5|W:Fi_3!V4Ⱦ to")ܸ+"t|5eFÓDhd2M:F/ ww0e  Ȑ[#/f ſjxאYR094 :xD*/Xi:0vZC'1&['b0I18bCmi7A:̮^`\Qm=T {c$G4t4i/r_LDr9G 0 @5u68xBXM&~;Ib$z m,xDH\q KiV*IwĈhk(׮{4uݱîR$7*BSt QiKq {T (8Cg.tȄ^M -nKqi =}%^Ry1 Z,dphO|s1M!K{%MjѰ x)YCJAb]O)ymH@x=nAȍ[+}C&bɲT a"#ɚy H~65ӒݫSo)U4Nt粶eCF|*vIy2y|jv9 DOy.& D5uZ']{=Fѧ눜 '~t,n03c!rPN~^׎U;ٿ/?JVFH/NNXxw`{?0Ő_NƎͯGCdqʲ|EJ^*M-V}>]W(ŧVe?Ј099ԜakcÁ;S!@f`px]&Tr_ an#z-& $&Ejv8R뤷:%q"HԭכcBVK0΂̀a+8a D]qhT E;wm ڈ.ob/#bҮfZ>i'PkY4OϫVs_Gz38t<]=&t{FwjrGӬҤfk%9"E%a ] $i0=F0hf1Ifh? /6Fm[,}fɛG0M*R 8'"w3$ V_d\ $?`(=\}M*ҥP/#O$M}) xv;n.V9%)Ad&7){K#ܜsޠ{g8gF^Wk*fNFN" w_A`p‰R? 0{&=WEN/'O9*=D*&eqk},J^/ͧn*yh{jCЕUe -Ǣ +o#ZSP JHS|V!/-j68HK&ǘeճ;m]K5wz>՘4 `n;pJpgkB*Z%kG"C O t I {'Zj`G֋& 0\y7cS&půbڷVp?F4QBW_̯a}a~J^fF,Tl(P9V;zƺxXi4mr( ō{(!uP^#mkBCOR2h:L)uQazl۸rlm&0V k+& ߅<;!IOW<`ȝ ,]!P}ui'QPf~띧]k$BA:]߱qG0(ⱻD qD (Rlv'T| s<>'*CCIftu+1╜u 2/z r؜! 15oץC[rYtA%Hm\M MnZmf&\"f 4e^^oIc`+5}VO&> 2d8oP 4QAJgt=w0u OJP`Mד"RLCc&_ds*o'gm#@Y+8zPy m`%~N"1Tc- > "p@ڎafgԺpvsh{'pý "OX"^Ip4"z0j}H̕[<('~ QQ`H~=d;&co"9US[cXe dF ?%: 5]_H@yAxE{tb=**ߪ"Ew[PkisBpX71fb UH0f(KDKH5\)05>  [kXTjOzQܜu7 k98Nyg]kX;Pa4_֡t}04+ rGOZD<1 VoS.,S(o|z[}SU_ 5f\jED:t)PeH1!`aŸ>%<|.ތeb {RvC[lEĢqsV^pGy]a)N'sDLF,Z5x.uKWpI҅s{_<{8v\&!IBG ܵ: PKViM}=HGJ.P#u9MBap-qd+hFu4p;f7ښM˗\P9 kWt ,60]Ue!T8 Lr9\qh*֌=N]ʿ ixa_Y)~Qr9oW6g )uA\f#QyO#pAbye[#K} Ġ {6(_ل*&?ٶ+=6Y~Klz3B-2S`񺫎aT&:xlWkW +:;, v@ ~-P "Vz8'P~=U&Ιbhm@LIVbC^Бu5\Y3G,5HuKm"O-`k|py䳇ΣK@G(р9@O] #R u&f+סijtld9#X% 5&׻Nq^cߪ-Do-.J~7)0I'2fN J^YjNtNNH4z(-^~>Mz2 !bJCSWoකS4NQ5J>aqey}ApXmMbpʾKOLv@~4:lw¤ ({~o9}> %tv :@!ψlm5eE v:Ôz,3~fj Ϙ'%=[M(iO,DJn:@Z qdӜ ~+ 3L7Э UQCW4pqbGOw:Ȅ*U2W5-q8BέTJWdA0^(UYMB]=[d,֮ ם");Z*o1g8AIX|l 4͗5rs׏/h`\Yc7o0V@feu^"BmzoўDնj[q>4r‡<^mKŇ3ALL)K,pop5)}yƭ ָLMB=tڼ70_kw8b\yo䀌lnƶL3esQ^|Rk)XK2)Cvs,JqoY*崼Qq |b( <=@gȝ05ӨWȧTuol *zruԀS )-Jnv&dhz>ƗQ|)̣^+a }Nh*CzS}Ty~(xE tef*QY2" jp=">e}g E8z]Bޑ oak(%CnsyIrĭ\xl* t[3k v3 %3=z L^=bʮgc8KE"%'e'\\ tw6\ ohW TOX{΀$%ԟ60MSYޢcIUrE~ji3UK >G%r#WLt O.TfMxD9DUB?;Oݔ)V -EgE$D0ǩF ɇ$zBB!&Ms DPIJ,#iJX7 a38f[h\j'#(W?!n4V.Hhɹ 8C`FbWYf۸qEs:1e(wɩr-XjO3vk|=ü`4^*珙Ŝ;)3.*Pq 1f28bRr dES[P 3#A`45ik(, aA[~_(96|ڨi뾸x>}>yP4lﻡ*˟A|6QCƿؑې^J5havx^nސ "Kb:wx;60RnWd]꓊rr\ |\g?CPzڼ7\sB.<$X',kh(=#0 Ɓ 5I0(\KW;2oc#ZeNdR"%AHBtތ:2Hdo&uYn^5,"մ^@R b 샜/^5 7o:LtzT-)}2A+ Lq)lkA9HMS:jļ2ZȨ>*ukl94ia{qRdHhf!~R@k/~J,XPHr[ `?K 7;^\Dn=}'>O7OjX!WV9gNPRBz8MWMP|:4+369fV>7(Jh8lt izTH_p'0AFN_{i= }NP]@ /_ ՁMU*] e &.ǧ^Cwŏ1~x)%ٕj, o lcπ/FK׵?@B[}d XaW+K_sN7p[M?:t*叵)QgNn?2ɗ0Rp3[to7dT NnfS)3B$McXoÍf fg^aflQ:U!ld6NSI*dzvήGf %YMxM a #a7ױ2 UE˸&DtÂcV֤74* iEKUޏnpj@qJU~ bч~[t1·8ca~/H]t|paPw ^Dx0>* 9"3g"뉒i=-}Hh^.iufHn/U%ki*GU[ R[ҧ*uo–)^ql9gX+TIzNʚj^Y*]9JX9Jf%m D6oMRR"c\DL`v+G"BC; oy#\ md(wm,XVf6duE:aS(gY!Gw;{=->[7P6e,c~G2}CoB;B9$AFgecQbi7 ) 'H"WAR`E[Wصj, pH}{cR [4y9%3,Hf=*QB[$ A>)Y`6G9nn,L̾am!}Cp}qph@^sq>9Z۔9Kӧ /]?KL;\+ 4վzR|ON"{94G)r\͡ Egyju:Ly=a_֜?ь Q͏ $<\Rɿ ^3$zhy4.H98r)S`OI6Jer2]kBqgl+LqoIFa >wXj oAiL~Tmz!YV7-oꕑbYԏ!ozXyzoVE<|8^͟* 2gآf%zN0fjai-HYZdxE9hp& 3d l!_{Y3B7jc6./6uDznyn!OOj+8>1b CsAvjC|UFZn3fHq1aj-& 7 6͛oWȫ+G+B{JM"\e#VyK qy(uNu4qc"D]fE;zgI6Ӂ>kz/=2",v5N]w&j@Z13Cm `V[?rvj| TegFf6}!S90hnfrقvzMNqwpogATUwyf9tӜ! 2غW`kH0荡{pNv!+%6Lj3q=PVڪ5P*nGf+6CL -6jŮ0wTD;$=?U^ $Q&{#Y[⨔L&H~~zDxle0Q\H޿"1j1b=ΗCsu~ܞ1ǿh Q$~6x"Yhs&& &ʗ#̣P Qh}uLt|&UrOĠHkCdxhՁɚ"ff gn"q<&})zoW&"oI7B% zyY3g9`+HG?MlK+^xQa'/At䰟zecyz/b]lL\[adpOAIhZ. ;\oyEiI?+C|dZž$=CoyVTXU'$-tyv3ZxSqhYv*0qJbμepۅ,PUnl^7w@cbQ'nmDQi yҿX)-2~s'SЛOxU.?%kOEW(|ORpc6i6iy2wg(M9k epJȳۀ D'qw{ _AW1hOWV&jjXk +ɑ- .F1 nvayo&H^l/D4W>n_A0i̦;*,J|LLk\Qe3iaS~ EedOOdևZ(YH ۻ. gmI~IkB,4yvԑ(V<,&!IJL2@1^8i$J@4o|#t]>L_;F-jQЋ(M7"5rцTG{&mvLfDI"Ձ_z˸Y}ÑYws$6uF$DwnB/]%k@02rx;a ͌ąe^?G r&¯mi4ܠ4בtۏ6Co:7)ZQ{A ߝʮ,RQ+isNT!)/Z4A| 7ôE\Y( -x" gc1KBzlӽer:{jLӘ79fnPZv+q)ڊD/6k4J{%%jd[>LA}1 %B&58eOߡ@%ͼxqYMڔj_ũ{bdF.V%Ug4g_d~NrA0 f=KѳC X}"&{d ?'?;䷭ OWO]~Z\䰪0!G;VdSf`\TBbi=_6 I|l=^`: }-o1j6&dj7 v^\n}v%&R78lZK/~eYb ި$b:䫎Fqep7B@0>m9ǚ^"FטrQ`t[[pkwY#:*=Qܻ6/EtLq1Jz_ZR={Ħ͉v_.4mgxT%oN/0Cmєs]w|a2.#1)b ^ݷ6Z7*Œ; iRy SH E%Aw,&R.L Blt-mR-&R$vBɴV:(mV* lApW>e@nQ$ )BI k\O#-G$<ېTI(5r;MsGoCՉ4YH8n|fz9d<[c`y2hъ̮bO|:IY4mK4%WG<#eVaϬ8;͞SޝlyԥV] Zi>OK~;gFT2j(Oon'mhkvֶceO !2PZ^G@⾳뒞۔Yr%87CծTGs#z 4D+…6śc-}ond:,)/ ooPCYu<`um\0 Dadn 8oW@ؖ5Q5zñz}'R< <8}>lT%ϸJn泊Aſ-a*vɊ7^N+(_gMѐ muv x"K4 vFv732k?n4!L#Ż|u'wk'ihDewp&YoZVs"hȟ} =&we 7Y*/v!a#ӂÔ`h<)>,Q^fL?Gj._P_CFX| ()3tosj2NĆ>_4⑫ƽGK wghDC1$ʶj}tlB}0+zOtLÀyFy$A>655Nq>0oDD-l }̱3Ȼq=.,/wz&NEķgr^] ϕO PB{x BY2g>vWzr1AlY錂]joRkIytV^^*Pk kt/k} =#c3uje 侊 $ )JIOw:&Q}BL7$R,hUe{ԍ?%%w\"oCNi#/v=VR3|*[ TL7 \3]}"/3K]Y ">$j$/1mr_uM*::q՞Yme,K!؃K,tV2rҁWzU܇8hH`9S`q' l~@c>xy?p(~JxtOWJjeG*1MNHpǞlĝJE䞽-nLuO{dψA Evo;TV7ҫ |q#@Wi.^õ],(hZN Å0] C\i9J|ײַK]bh 9X'x`U~X볘V7+H6\ g&54]DBSctךDAOgS1Vt<ǃ%^\4ܩǔ<_2[B.9yl,4X-3Ō,-ks75UPU`$8ËRYz[ is.hEG`d2|7_9ʌ0˔, @˼ޖEkx ~~gz3#WLpU=Əڍ0j7hpߒ7itn됲2y@+? Hn_㭗Ezݿj 湰9nCDIK)"7t/6@U"hCĢpF{ 7ls͠W$g cy`sh>qDzaHG̈tYi#\q4iDK괜o9-ȽRR0{XY My ?6:i'Wv"\~sHe_@B)vK}/K!gfwcy$TsM5|Zh4oyB( 5@nHS .P)D\DLCIƈ /Eugq&ɭ͇vkDHKL~_ZLȂP6u|=h4k{+^0j2eϥVo"! gh!!N0Ӭ7fg Qr [)@ Xj*hq>>y|ǵ`?G]S4wJ6̳t7ky)cO+P24[#0Enk߿o01'u|qu.=߫jSUݒd 85[:4 H" K84Gd鿧{f98CL٬}L+-+srqOڶ5Z9yW8LCj1Dt-wrQV&L[kfhXǢppBDV|ْ9lZ#@Ud +PSiB#";|Z)؏dm>2t(F|/=HhÚive 5la]0],r1Pneӣըv4lm,짊CYٌޱ]5aS`~O 0 kJ>ey^{2RB_L""9>Bi%jXGj +/v Lȣ}/b,mSŏ8<v R`c#M7Al jMwrP8Yx"|'r5{BxyaMψ61c,UL#8-q|Ձ^ c.v?ݿRB=u׼44}F7Btӡ=ag-;v%I2n\1*}RvЉy,?OѽSJ;kNVo65EϚf?֊(quBՏbc4QzG;y29`p1DeN_|}vYWk^lXXdW bn;vTm[fRjާDB23NL<صo"{/W|iz--rϭ_(Y5V#qd%yr$1Fbd1'ؗŶ7t 7k03<49 \* z~P%\V7RS|={ `Rz.mGx$~e:=vAE-?O3<:.Hݣ]5.2' Vq߈}9m>@;d nѱ!fg55RdP m}쁂2 hGf/96?YrGqAf% dS iM|s<+m78!mm0O^@D> b2i.B Hl1xP8 gC.ԇ_p͍WjεCSdž9cp~# A ዃZ` ǡ^o7W׉Wt?\_ ! {)GNvJ׺ 7ʨ,KB`E7,̺GVc&Ф~ є9AJv8 U},}FqG Du,]by4 ˔#L>RŠbe(VVxF>;=U/,چ&H|_Qu{;0 l &/1u7c@sPO6nΜ%|J.`Π_[.^0UJhhc=r;1DƟ+ם3ce3J㓢o$J_Hcj_祯.!], pOu+4YnMC j'3pF~w|2I% vN6$XqQjl 1Sjs׎Vgُ!ޕ:6˗Wdy0oŎyHZ[8 7pI1/(ن.`H9{0T?0xg7M[^)rq$!T3Fr}ܗڳZC;Utk@ 6 ~4(C:VȧHG"0yjOe29Y|k$ضv엥꽵"Od-4Wx4wj8 `9gqLz %a*@o?.㭋=<wN)Ӟog"|>DvG651ϋGuyxvٯGȇJ\'K_YwfF!ˀ&kG'Y )M'h4JSh!7\U)XSoE`Q}W?Ye,My^'fN%irTqeљOeD'OIBtX$Czӂc d5.•dtǍ8۷$cɢ pTm+곣O`>CvNkY0=Tlјyu -Lq5 ݴѤZt4@.PE.q6D3X!x =n",sUȈ4]"a`п*Ck,*)ڸ.H|+p>Cq΍hSF:&KBQr^3G:U,T=ŎKY.DS+[lGMO*5-JL (  @&Va-ŢcrЏ讠i3U._=0>s,erSI(vMӮפW9yXnk8t3!9G)_ѭ(}*Hxvq.efswQa,!n>װ}Vw*NP#p@{|' 1&kک :&d4G1⾯&*`c 06,jgyҌrdȨT>j@10ϦX{" 8t !%.}6zLrIh]jt|gh D#fH)Y#T!ŠRJ?e_Of[VoN^N31$㵎ѐ#$ l5,n80IA&`e@Q{XӸ(scʪ,`cR@[q0y;{fHc@i5h3=Er+5Aj=FI }z."= AxifB>@]"beT1 UӱAIλMO3XHpr:gXwA|o_9Õ:/^vp"lV p֮p*ڋv*sL4:E)6uC5CؿnwG#qA㔣K#D#'99j8[>: sJ {ZPZ!#$])5Ov7UlKna71+])q~\Mbds#djwDH]KV)X Mk#I "'(^|]ȆY(\Mw^?G_׀o[x (,E|D'nAX*A}FL(pL:nM{opzK_:&qzf^#`)4ba.O-㳋Edzh}DɁGjڤoFZXع84˗R[ gk姣,bHe\8S [Ea񨔻8d%[LݜȡL#8@Dl'6^6ug}t9`qY[~) RrAӇ 7__^5`:Emjyu.^Mo70VLWӾR%uFߙ!H|PD+(UaF8;UG[Ήl2 =]wykg$r%ЫbQ;iUAnV^ Fc>+J>PJgJȣ0 s aԳx =z&@3ID=d %Ί$VxG aeQ ѳe\hW.  U`?:pt.FԎJ)@i%D -0ѩL{c!3qh78jk1}qr5()T Ƕa6ݯhVίL5Gr1s@uDr7$m%EQ4=N=x| k5lS9Rna3+eq='W!_xV7|ٕvIzB.n%prMl-wuwv6ELlx!"œD]4{ fx!Z F^"FjQ|obPX%L(T:5{$]tDⲕ}!G7^s*x Λbp5`4' jpt?;b/C_ㅈ*YO}jf́"ksf~%\̨8K-fn0vL tkrp8ŦWR hy2[ͫ*3jER@0JndtC`J]ԙ3h'F=vh ΨIZzO2}I4$bccELB tZ1Uww S MNӳS"!p,d1Y΁I8B8E܀eENrG0+ԅZERkNW6" zaJ\$XyAY:Hr*4,cwcp!:qƒ]9oPqx6KZR s9~ZI:x'wX2<,lKgxO~z䱜[\-!Bkjn$B#ؗnb뗦? 8']1~Oe ;c!JADRPG`nF$j&k2d"h:]$B~wPs*L#QPB4ЬG|s^<좑-tL}6}r$NV465٥@'jM.ć֧3cx s۰d1u6?#XGxCBtWpe&p{VŵMUJGV8raD8^P9G_4'_#&9P: %84=sHƸ#wYW6lp(45-/KAӳ &IHa˼RY$6QӾ+N (W΋/oԻ%,,bpP]N7XM*Ó!{X߂TE%v2"hl5 1+hWG_@ & 89W轸O_ cM&ozT(߅UM2OP=_(kwunGfFq-Ź0) "]:Ѭp0]DnC.')AL790 UԐH/Oy.r%H3u@g@Nj;8V*2yl,liO?l*:=Sir=m 'q3&QwϽMѶšǀ-ݮ-U[`.{oG|k[p ʋp437V)q .klT)齍O ;d|-|6!"1r6!g&c蒺od6H =AYm|IKJ;`-Vm8J+Db쯱'FaB8J4w>Hh? k$KM`(C7 fWX~_Vs-ܔ_6jl ]V9vre7%phvlsW3ʽyW;<6ynL2* |hy=vU[xR w,MoU {H h=O'N%Z%r1ewh/1(7yG5GC%ko D;КR7 /JiWr.Vex%c.;Kfֽqur1u$D-驻G[+j>1\HdŅO?r,ϢܤT#=ޏHU)xs/.VsTgWS#>YJ8/Wze^ܜ%` Sj'W[EX}JtamOZ{:j 9zO+ 4S< V Mڡpi nU7"aH]:4,?"Ӣj9unWζ138L퍼JeCmT;+ uU)E>M֌<*S&Pe4WȜZpCL {n#[* ka !0@ϰ:h`5`}WUi1#DOM>ۃnR(^kB wEA>JƩzo-*5Dğ˷,AUUYϳAn^ofsRrrE$m#/v)߾jBݞ;'{$B6xImQ׃QlX;?Tz]Ey.JJ [MY(xiU2{V3YV[>n"J;&*KaȳTSVU.}AֆC0j~ױhn ]} %_ڌXᛏ$Xq^1c9V+;I5fC|iS!`/ˈ(r3ܑ]l,c[]#!ob׸Ey8ŋ\/y6y1CWjV*]g!d@+j.R+mh˼暭‼|ަ̰U@>,ˬdIޘ}xRJ=zk-sI t#{c,?|'M Ae z:Cb646QҰHKh_JNVSmcN=h'XE f! <3Ue͝cl핍ˆFð-jBvGnenb,n!z,rV-n^'ѱYaun+:_[ f>Ryc=((gY]壢1fEH`H,7-dɠpA=| zcg]+ߚi<ӝƞ x]ҫ FBvfHt8B< %L¾ޭDIҢQ^4 $3~ŒRB, tBR|;LkPS>udeJJS wג2r\3>n_[j$1>`{.sٶܺJ:>ׇ7;QA N#KwlYEt);m7( XQߐDI'ϣС{f\bK3Z5ϣ̡/C fCdޘu=5ŰEDQ YF;L=Ѧ6u\M "&),⽆U%~iak+L GZPS`V](F/4o9nc5S<bp|Gy_R "a/QolДWuіXv[oCSޞ25қu"5c5A<maUKxfvKH-jDbt{T[cȕ,ɸE]=71%A?-Lj z-3z-RXFiR+=, L߃aU)$Jn 9m;zqBԕ !E(nB.Ev{=N2e$aFpO1!Tk</Y(͇h{m,=4\2 7-"*Mn2k.;B!A4̪UE˛}q'DH;OxlJM8q1S\JBaP ?Ԩm.ncLV ~3>)޾%tzjW \I)IEN%E߿+ӈ.e̬PN$U9djzSm.7f6D"JeV#qKb?fI -+$n֮x ƇoiX~0/Yp|4(&bV{nZ,ЀĺxA{hSW1 4R͓*g:dHi@ @D͝,7ɀ@)G꙯-^fj FǀRa hufw< |g<9jG/$9:5R̗u/j~⭎UowݛΦC ƙOZ~,ߤ'ݧw0ؑ}CmusVxIr(˒kqtNUa,q4**_N=g]"Oz3q-ow6Z7ӊW ء0}Zw#Q".*= ˳kY)˪4LckKsr_ݾ8v }Qwe!C~J/4Di;Җ9sBcڶ_c6MHtWzp,^I&C59Nx?ߖɺ{ ;E|(_RgEvT0@jp *c8muRF5tV;Kp п\QԀC%LܖB5=haY8H@n ,?&buKUxH#o?S>;h\]rô:_)8"8eұo_9DN$،j9K }-_i]=*TՄå"t+l 4GHϞIW Th8Kus$SqIwW:J8V!Sȅ0B^L[i T+jZjTѠY_y#{L6;խٍ$تmm7Ϯ EĦ>}:_'PtK(GFSt's_spɤ;A_νE 0hNccx:n<ͬ;BRοTS #7MF9)b2KNSBJ6ps|lT+éG`jv)Z"GQ?iUOiE[@D'C"* ^7T4Ypn!#QPmyWg-R͟@¥hAS1p fLEZ^2G._$Kf;nڀlGxaݽbqRW S^mwY &]Ƥn3M[BmP #x&yvw!5\JdBH'M .IUGZZcPhNJ['Y:Fwr Q'Ew 55ݞLIQwj9X16_c>_A'o#I-;dI"V 'iYy?ZO ]—XTD쫕Cmi-8xiɶ-5P{~5V"o >W /8k>2*LXe I83ʨ{v8d[?4(A@:{UlzANGnCVboҿRru z.{I2B;$L.ݱ4XLW:?YaWl)F;HURbC>Ys>t0>6̢݊]^B>O9+GTHvMsY^`adHoWޑ#UYPa; l{IAե8JisdqF MHpAj+4lEt3Wl5˨#eX``MCB6MWQ$ 4Jk脹PcǹO m4B~ _A"NSUq,&ctjjSjBavĸ*A5i?k/`,8wR[kl7KtoWʊa eVbO{k>xb'B8$ukm@PA;wJ@7,sI(*MC#$HЏq'*)@ ]αV@,LVR@ww!b[Evd-)NkzX~K_MxbT2練Ad$86  U6#׿ɼ`8ZKsfL(}ĉVYT ~[Y^p7f>6/J۹,]qJhQcMM )9cN8Nn©9E~zFTl-c*``OMF`/hd7vu{7 LP䢮e߰z$vݍSq xMȈ]ߨ3  M8eׯiw8ZJlTb!/' Oa~:bZ颗øG=[u6.DzL53/ gAD\Lo=1P}!Ziq,z~Pb]m\G-)YNd"*gxX5>)gX4:Jc,\#‚C^ " 罅/6U$,=hɀ(V.|l07 )\P̀bExd`KEa v_E $}1 )t@-ϡJxf23M#p z<(卂]^4VʧrSK-Zdv:_n)h=XT0~Ql ȣ&>nα'̅c)< m4KBJ |nsDPa9 x"K/  RȘ[2J"!ۺ2M!=GWG7́ ̝?$r;j/:LW$7Ihu(Sr}th1ǽl.OIjYƼ~gdt];UId`QnZtg $s4랲m-ÄP}4t yh-Oc$rR7(ST,T  r53^זF9$6zM乗6&u0-t)iSs@(F߹ņύ`8tpm+r ⑽*tEpS f?$?+`J|IFBJ` ʇQXpDd5RZ̿ J" b5PǵrK8?8tRObqiCKuF3щpP^5r9\8畚fDо09hZ U#UJ8_Q!|:VG/;UmtB6փjp,7!;Ai]GY MX_=1Cxe" 8R;3(]I\\Ot``cb!D|/AJ~ϳ_.S2wQV&-,ՅƼyCϬih w!!'zBCدIG.sf9bY{̇;z#}[}[Nu"FZBy.o'[ܯ;yINE9#`W#mVc HP{B+wFIcBgNg;L4mrZ4'a2Lf~H-~-G,С> 4߇H)߶Bx]yR?5eO/So/hW*60"NImy>oDG_ı6L,%,A"OaiD7 OD![Gw`/ \&Bߝx7%fokb%<9u*bTvm׽x+L_l@;y"_w 0z"q ~ܳ<l#(8\' a=jkvseM[ 9WtO$37O/z=4/36mgiA X5g9pwʐ ܫ%6vW`?һs. 9nQZȗ^LeYN@7 ^DH7+YRJqWR?[Jt'#uiEW f>vz@Q鱍|S$F^$9)+C1,r%Ejkl>!QRiIYpxwu|iTTʝ8ӖTJ)'jufi|y;XS?Lx iy=:3`dcŝ%4Mi>J̐(~`FfZiM%WËum'H`5uқu?1ǀ]19񏝓cbW0b+s"Tx??j5 )rn|L5D%~1gp>]O$_)K}DNUˋR'##LڦJ"*%[~iV P/hD*2䖵NR¦MD8xďZM`+[>A*,S4*j>oz Fbϟ68kFҷK+4Yx^4Z}TE!ߺB:kjv.gpwtHu i!C;8&fMgE@WD2a+˱81i}H +G;EyjvZtgry掲^ i.w_mO-T/$ p gF/bȡRp$ENz+?_W &ZAޕ9n`hm_y16sm?]'nŬnY0}me\H9ML`=UfV||{{ƨ,L!=>_'ݛ~sG-#켊3f dpwhчw,b7H_uV`QQgaw6V'$X7liBjMFD!m(J{F.1x=$jƆٸ;b3|W]dLܘf\:nhmaCeS,-kL"I_Az Ҽ\` `➍C{4#X[5/\*'~f% S7 .jSiM%Kn)YÊn]~B=?55:y. /fuNa!ʄ )бb'1O Q;1͙}ج1!Z P6aMXV!J;2Qoϻ`E > X Gm1@SQG ۹g2IEv@PIБRV|I?4#Ԩ%rr= hJpI JT%nj.ALIh/\3 / (]1Zέ_|s%ܒ 3 d 7>6i}.M ӐIu歕Rf 9cޞFP.L9߾Ua? 8*9CM=&bQYP4WHDmq`H1x^߫v^j4T?*)!f 0IoTRX$2eM, d2:e!"T,L&o&E$! 9qYQ@SmNO0郩ۍ!r& STBB;|لnǜjSŗ2 gaG9 @\K*D_}k 2aױۻTFnjezޝzҷp*8t`uÃXupǝON+HO;jY_:Y1R_߫cֱL u gSGa?ZJ0_v #ȈwZ]Xi d8 s#iMIW$E~* L .Mv0ksȒ$,miegr)sXZ)>,qa,bK>‘3EcSvsaq7sJ aw`ɾj>CZp77R`o.ץ5iBh@[7 .(A@,Ŷ̈{wn9$hAi*tqW/T4jsv`R^;E fӳxkM%Qu R(h_9InJ=,v=vzW|R4i 4h1#F^r˨[\щ!ܿn͚HU{-A]"\ py=I3^01܎T3@E.F Q>G L0xTefAIYf.zLf"0>S~Ɵ)! I*c`/GXpc16XYDYY<[yH|uuxvL*,iN N ӛM.{+ֵV?Rmay>-8-* g]O P2=PI dj[SgՒU]YgfìrŠ~wٗ-}n_ I+#0OSzBh@>_w+n1pZE=C%J3MNEPG&>c`ĐNt>ApgQyF2dodXݗ0_$NQtlcCynw;x,|sH핦ۣ\dAZ-L^^)4m).7eRE|4ȭl< 0vJho'%7ȂbQPjceOF_bZNoA'JA)ɮ4E9k鲌1ͥB-SfB5*Vxa닿U<]s9 `E ͠Nӑ~zOxjxy^e$u\X h_i,, o)Z[[V6 Xhi͊e8"l1 iۖ 9ɹ{Ͽ o68k6$$3` H[ q<›[@ k2߭ʭ[:Xn8QYJvߤώƣSg\B/M@n~Sٵ$V *em2])s OKjLO^O-* ŚnI #nQBsv'ɚ'k@3g-Fb#Z:G(5$UȡU 7!򛏹vˎ^tzh_f t4U%ڽp#1] J,ݼ+CSTlIa6ֆ\`ڝN,aޏ >`c9%fvp#>RzV4U3 N&&S9iyd&kῧM\"FO;8B_P{6 t4܄;6uz%&QB.\`WTOZdLD~:@DVptE ''dJb(| !qnȗ"\d|+Խl2Έ~HsH$AM uF"h˞BЗѻxMzOsu|k*szyI-ͼEc]첍 jBS>`֗,m(NH4rZGKgO)-,[m m __g٠\W2Mz38ö=ީ{F\AfB{/_NP0}5i+~e?]Bh [2k!na-fq-Xj@6ZB};. 5\+(xım5 =6xi|铒ܝeA8_sΗtSxN\hjy#_z*^9+( "7ÿ)ATLz[ߚ)`) $t937.9>{ܢ$\h>Qw^s*",yw_^yL\EM$geCcѴ Gx?KT/Ap+s+ @,Rptq$& dh[i 5uqhPuj!P6D184 kp}8,\ 16}Dfȸ?j _U, zv2vAnf/{S*./49(Y䤯.DSg2Z;OIleVtugRKNLJ'9)6tyO^{jaM]5S #[q`:vV&_!? _hmFMr(3M2E~G$ptiӬ%'퐙h[! ϥo|r}@5 Ld. &\!]'Aj;8S[ޡm[?D>̺hPJloFE|y3`u 1=pY=JEwʋW9gMGFJ*(#?ؔASKm2~Kp^WW!x}^%9ڥS`) NʥmN2b]" ʵIKY8ɞaA຿9@B|0ƋJ qJ4yFӟ9- T7KBdHg(߶N}jlI"ujkUL3.0\ mX5&AP,g*Iwc~}j-3kC 玸Tߔ=j SďRګXAT}p b"Q7z2\a{u^<"Q2{Gs!D%a$l_ڻisbd+V$Ⱦ&Z:GP{Vaq1SVe"J87qnĨ+Km#JҘt[ #qm"Hz !(\Fzk/g^UI =Qm6*1{ԾὉe1"O"PT7ɡZ wNs|eъ-'Ȕ!/S4gk2zǔ-T/=NO:Ʉ=+un/\ :' sEP vp>{e CQd'4,jM& MVU@¾|zֆՏl6Jl~YBS Q}Qe .ڗ9AOԾ܄7J>԰2zeUˊ|OrrAS8pWL:/'[%}|]lΉ81`H W,-g6q[4_PymZu&p^# ‚9%dm2]]L}0]Յ%wC"<|7٩<ډkR)䠤t͘y<.ЫF mM.n{Ǭ Iē&T*sB>U=f}>{M4TF 4itPga+3+onYNeh.-Kc9QCrb5Iz2giᑖ֞^H팸vOO`؞ÉWt̗V p@s䉀nWt^6g,UfJO(eiȧSI;6*z} ;4Dt8ep tL7Xb8)टI;Wpyq'&=Cf P"ɤ:bY_j Dx|=֡<7ʬ~O>?tK_nTcۉaۊG,D^l-ޠB<̇Qik/JNS wb=wY"2))cp,jޭAq9 M Gl^Àb>>Ùfװؘu͊ti;1XܜXe21̚P&.Uk麟eL;?t]/K ]nul(?c=='HKvz0f'%Ua) {4 O-AL#vVQֳc;v ]\jAnW_ѣ^YԲ:zi0×():^HD8`kf#N UT.v]rMqzp*bnS"(sy iIP@̈́{[sFasl}7Jsi`vӎgDb H;5:oKe6e=|Ce(ʩܸze^GzĶv`fHcV 4Q@Z U+l /fSJp<8JH JR=?::@/kWuynd2]PTs`aLdӮrxAQޢ< J=BpA9"VC${3G-D[[)ӛskEF#>6Wd?Dϱ.X9ږb[2Z8L5ug'D|Y OhM7$DAhof%)bfPCH!*Dy u؂C2,eз,n QMW93rJt*y(*%b.QVW> %O~TVJa[5bgk1jYC'hoձЅośc)j RDhZw~RaAg#_@ -O_W4 Zue|DZl)2C'7p܇/5d>D:}c|' U6XM@VW0訰˿&,R_{*ps6Hn߱b5?&) 0w_2c ]< Ʊ|s4ELxZ̆P)*b)h(u0QWC]-`gȈG'Vʮ)7kXy2/ Dib:dݔ4H71UKs8 ZQ *p5o$Pka_A(PN13LT\zbtY ӧhU]"SbKf%صI)h‡{{2EDC4'Q='=xx?TC_X_#M&\sZI@bn"Yݿ_uйf3^/JVÛIdg lϗ /\5r Czp՗@Y}tHwoMBd\'kZ $qXrR諎subJj28:Bs?umAPOq m0uŨ*S,(.PeO.m;Z +~ 1"]w܇O>kxvb(CM_AOn8QΎqׂoU[\[G^`t&tpiOO#䁻GItLN,koPeܢFOj1ݒ9Ȑ %K/,8sހpAEq*E.v!q ؚ,6+E,lH˰}*F e{ e\ƛq)fKI7{5tOH$z"7g.̸/cp)vᆚy<ʣ3tpK /:<^=a; Ty $Ic>O ,,X $(y69yE.jRС’A|ydl`frjm6d`eG ˶T.՜ Ú^Q,yCw!{>>lRG&{zN[Jk2~ e5l8 S:jga<^3("w-R]qzի#*uZ[O7'"De([LNcb> !,ĿD_30?VoGNch0:'{S.^uyIW[+bVL/ǟV _i?[aQS[ +S|R=5[H"{+!lst2l]{VY]z:5NҚdV+%a >NWNQl3m0+/fx3b3>ދT>gH{k_cCRb0Qs}x-9+$c.gfFch|aPoYo,im.Q#8 1;/ڢJ?gW; $\oſeࣧAӍs= s/E;"/  ԓW̟8]`$5N.>Ks.^i s,廊7Os#DIIGAI鶶L_40'ocʖP KeR4)g $Κ90pg`FYk"h>>xD9<1= -Tƈy`?vuwi:à?b"}2E/B5 C[طmW%}τKK-hD6kvoX͉uWbʢ}aJ@5:ߌ%=*MT AFFOdj31fޗxxi`JB yR̊;5sDHb_P /^~M;G8'iAnFeI&ObzHM)WH'w-#MG >JcuL#O[1-(︢a moo4ʹMJ~'*G' Ɋ\g*nFMXMnTYFxaTr61oG$5{Jb$vBs'L>\}hۦ2NƚQjL}ǒ4qb-rG_ Psgx T[e+_͘t[5sm_z\o.S c|M[`D* k|/%&.Sua +vX? imȻ#d7lv]顒\(A6:?SYvZak)+l7|!L]x^-/D7}?&]Kl tNOmbЊ`wwHDmm*6 bʏa豓qlem濹xp 58 ј'04t6M,y8( ^rEJYoke<'s>ðI"^<* Hkr@\P`Rg{83>f"x'\+wR17I{;9,Ӷ`K8ҬI̸ S"A[~|K^GJ7h5PpbKXEAmh>jIu)`FU0a/ F_?gL,v0nC|}Y⪡vZ_;Y_qxSH ~&l[.zwT9"DűV' X ~ ,C:۟BHֆp o~H$Ґ(a U4eyfP)5*|?Nm&5[ks| <@"DG`KjPro9-*Ӄ͛`Lq|n2rঋOJiV񀼟!UقϚGPrVܖQ&k3ְF J7cpH^|9# m\(Eg5Fky"]&+)f)R8 Mϳ p?~$l%@:^Ã`r28g  tKdG_2lKt+; 搖~(wi-ߡ8 `6Ai裐6EƓ:V$8CYTu'K*n0]⤋jhbwF~}u/lr¦-SO\5$ɤrVD{nY\T.pΐJz=ltԻ%^?9\njKZy$rb\dhCN_D'( U(:;yj +elլě>h#h 'A&p2`MU*T=q`eW|L 6%jNAlT `|(b qz_x;M>[k'eXAzi W{:4M9-ǐSMͺy[2b5ב֔[!3x-Dw7U5FG ҂ʜQtM*WSdM@W4 kËw(RˉPflvg{ QnTY2zQid=I;.T۱/vBM>l7%{ Y*m#[> '|ʥr[E IلfD7rGW ? ':5 Fdm3 Alk  4+4)P蟗LjTH`_ʰ/?, 8!_65fu0 KOy)N{\ )fNJv*Xk9A 誀o2_|wn_a ~g+1P5{7%fiQH8hhCU=3YxUi*?~iɹ)=Pâ`>48^?%$v8!zǢW=cWVpC0=;17z+A+Yb-0^MÇxB_j?ے^B5KNUZ7WfAZpy~)%O} rM`ؓ'A)snv>b6 BٟǮ^jѧ[(&U^Q^Y;j[_G?V]Tf!06=Ғ'SފpJY5g~+fg}:Ƒ«f:CY<ϵ%t0P]KLȐ6 nGko5p#8\35; Pnnv_ B~yg!JeCtN@y0 o|۹[:2c'w1A=&YYVd8ὒ}:Y+%^]nhG{BU p. X'ErQm+f:H]R\I16엕.m 1jS9< Qd;}ٰb,[p*}J;[vF8!IaÁ1ȧW!L !=4\UM/`6Cj{+]WBxo";[De%:>vʀwf>yg\ǝdbsu2v., 8vߠDc mR8Q UZ8ӖQ[Ijay޷n_hHiyԍBY?LN H+QxCX^eĤ$5YE"H@3e§/2CvN7M'XdJQ:Ti#-U @16$0zTӗ\ֱm"8\1 Iq+5)oIgV ֺg?Vg/ TIg_q 7hbnJ )wU{!?,`ok A1ᶗ  X<V5% )V~c.mrQ: qV0R~[NKפ9Ѯ,cUj;Ճ?Šq$ACJ6ՀW ρ[g,ÒɎfF#7FkQY.zm4u °:/TD@#fg w3RgxP4=>t1OJqNizu]U. Xm_)juKDGxGƎ>=Ka!̿ ;T) 1-y:~abs5Eyf"Ύ˅XbδҌ9eЙ2p\S}.*b0t1VU v9 u;h,sw}.>YvsLbj 7<=Wô?VX4* JC0gW+zpx[+OBcP2h\g1)G)uM8.NMR.×VWooϴJ@Hێ*+i>^ʺm/mI?ƙ|C~[_*Fen)9Γ9{yAh{^ $mMY0Ad݄NC;W_ N I|%g5 o™@#N41 }m 2aeۃ)95EGhû2T\ dk6M q004TfPSďGO~2hIv); }VfdMưws䥪.HՈ0q =$Owxfi%4%g cJٱCTHY , ( 2(b)^88^IA, %`YFX T|/o@8a=gEp#FaX>% #)[qRוjSdZCzuIQ)}kAVeLU XV./{6ܵ kq& u3KRMӓ&gsPIBm }T?SQg v+f'ZfՖsH/.ߛ-pxڈ5?٦5>6$@UWhG9xpyOJm"m݈u &>gm0c(T-BTu`G^@;C4$qP`y$)4y4_Bngz)Y.H@}7kR҇2HlZ[M\~F5M9@&5F> C#k$,T\|"M51;p:px|nlPã)Ux 8Iі73OnΠ͵F0J`pyǭ6TTՑ 6d%eQ1?Wj$dʇ_mP,(2+|hx%ͺúC ѤVms)IC%3Xz QiJ7I Zz"e4-6߫je{k9_]sHTꡀK[) 䭔}X,q2k~Jõ?[K8X`ږ%49jGr:!o ]p0ݕ<5:-l+)Ȱi.Jf R|ud$c]~IfYC'+Z6e\1.Ҽ7V $~ĽK qK9 elsOUZا&B`^A(2S8YMPT!3wWl:X{Kh@s$~Ҩ : %KUOC}LddF-^h&_ "+oX>s|^J4< 뒑@xur#q'5K zXb#׋W@pdIPͭE=d+R8$TQS1w6[_3n N\.>wQ3:X9:lg(5n@ 72,TO4NPh񄵉qz?iXC"F@ɬ{fee~$:4:fP%3$ZiPZhkK| 4,$ UL̓y:#bg?{ZZgMv&CS%Ig$73e&:Ҕ L9Z72m+@9`f+j0~^+B%F^pK,=%:*w{O}uHB'Y?F݀ߺoK3du@P,Шt qM ӊ*9H$\G/H,N]IÒ++2n8#<[KhȞ$= 鳯*xρдf觜pkzH,1Pp~Z"]v k T!mx*T:*S {Z=T|5^M\5"yk m 6ӷ(h0!|mZSo]fsyt:P nf.h Ϫƶl%UY˸FLӊQ@RlF! [ה3oCHHfVUbMMVow9b~uLzusGZӒVsqMJ%l+H̸ xgpleֽzWan5oG*y߀-w]ƍ7tfʿ6PC'mҡ"r/)^U%aP\"q/iI$SUb?/>RB J4;w*ؙAΡg핣 2;1  >1#sK%oZq49s3 *MgVaw}1'բ5PM;LU)$5&;'WQ7mFI 3dT0Z/'~W'cO&?ӪgcthzR| k")Ul=B\Yh)0O]aBl -Of֮4eY =H 79ȭ(bؔ,"9!ʞz=s {&%@e5[UegT"='P`ĝ6;߄4܃wf-wm%!JfnRFi, Q;~B݋7RZbs,rC{̀*y Fv_o{\=#o WɡqtwCsR3ڑ9Z)kOtco$ 0G^ cQjCi\2)q\ 8aȦ1X`?F!Ȁ@B a` h ~nQ/,]5zn2S|MRD^{G K'K13:591lS;)izwIz&^f78 Bf:C4WWLC ɘ qLEF_XVaDtf~g"J.Dg[1_ @e[Byx+gho1'P&m#2{ЕfFO^.n!: ^& Ao&qHA..7Qrƽwz4htmfܕ(wK̎VA䎍@ui OAd`^W# ~saJQHT:5[@T2, Oޞ 2ͮm)R`R`/UҮBG`/&)-kWIH+zcc\9M|Jd޾q YMfc7|=E+2QJY  `H()doi{ ?O[El-6SK#e gڐ#/i.Z<ߡk#=;[E䔣mOef.] =YFsLD-@p13*ǺIqԊm4/?9Qu"qi@q=.%Wa'N_ɻbs\|xT;%۸^2Jy2@D8=m:2cUO"oq`(aG!4!7Eb{a.w6wg\t1@s?y>PULb9ˇu;uQk/%FE[p7grq"E)#6 Ǚ俋ĿSƾ}tE pWC6g4sqg6dQ[ep{kMKίv 5:[5@уgk6%n. >iw:o`|Zm9量ӕͅ\Qnx%ԷRDW@_Eyt,r75?% #mUa5fcD0oW7 TuT-r3[>d}.VZg0'&mϕR%&@? /!Iڤ7"l &>Oa? H`ܧwj|l/U<9_3oJj١ͯ<rECXk|69=TE@y i?cݑV1{rG/穹z?z;7^l:[QQB\YIq¸6z#pJvLt&o5[ h^|-L5L!\#ޭUMsGUvE b~VhဃXW缾wAFR5F(4aq 䰪eBKL`[/ӹ9Q^Kd#NH-k[a3DY~ivHܣ]}ۅ+WO%eTfpO,S[hft'F8ޭv7s_v0u4OSyꛭYQS܍%CcRw; OR('cen6߷/H;%^;<8^hz4,HYZ [Y|[E6\˓hxRZSgbaYlXӜW]gHZ' 63x\/IYE]<3}N#EHI.A+-O.nFtI5~%^6/eWݲnB" zm Pg_Wb^4c-4(gq&BoK3#H9n`,jٶBC}bk*Ld8ESbLzu`@،?tÌ߶-Gk7(!0HSoifW! +ibG~JrdgG]9בU[꡼~B]_ሦ{BV.D1@1[ǀmyޏk$gD,ipT0sN 3Mq8(㖘f[ϸqF3B}? ϬeQd ԋF ⹮ lSEZ x:(DG}=ۛBxlXڌuϣ G s!Nd-wz 1]W> kߓJWo. + #*,lz-\_z \L3$>(=ШN5yY$АMXU GOxN2y2Lfҭ:3#nK~5V8b][F;L [>P(kh>em$I | d ޖN s& KCrZ M4-4&VeǢ xGa蒅Ve;3hM1!y<3L]aƣ:P gDmG+SύnZy"ha_JzAj!}& "iK18BЫT8Da )&I'J]Hg1۝ ?Qcڹ\sffk'Ђ$2f /@>pgb&-SXp߲9K?wg>A-x(Qca? )YBDT5C]#;H:}esAÉsDr2DU=$,ll}@TYSx-} aV.ЯUXd0(]O+ׯ׉+(J{I3\V?~0%?QWzn0]5O{]Na`_ODbe, !l@ #ւY՜=g xwBT & qTK_ 8A5a 3&z@bzPIB:LM_Nԭ~sl١EwHz}p6/ HYM}& e9,bl4@imu(Yo{8 K LapQQVGlksMQWy(VVif1\.YW"=UOU1o plBwK_"Owqg2 Ax+菋Iη]'c辗l 4* ѵB-wﭼ.1&٬,Nm/'3ږ=r7P L<,/ԭF {OVԚYv՝Oa|wsܨ1A5Hzm)ݓMSJ.e;lI҂aV1p֞G͈OdͅgP[TfGN"*]5f$Y«m]) [Au''c''\"_3o5L{ ٫U PQ~`6k4ʤtz?״7l ^,#C`Tǚq,Knr48izsFQs:]{ :)%Ys &]ؓ?MM6|^<}7W"eDbPDybJn.-&o 8{_z.qL/ f!MXgfT@TY|W|u;un%?~(ρaB3:'NYreC7`sWt) ׇD&\{[\4G>G ݨK-\ոls~lfTS=ƊFg "*ls?:~E;mg^.+yBtAxڟmpIoV#j8zR:Xϱ?yIbtqY#b'Y\<.l;x*h3Z)V2bfHi%SPmWm#`7ҳ(ze[dM%Aգ=i67ߜ[%@3u:4X5Gf2ܦ.#䐺[DRK:aDAT6nݵZpttn*FŘMo zL8B2QoQFurWˋl746Qgq_ jVVDaUs}Q7+Znȯ#cFdAHQ '3Iq 0j|b6~WYt䜣}P0nϞ"Z5!nHRCi%A'::/i7]ࡠ۠||],bE7's%5(=8h/ G|au硫_"VK4;M<ݖWk2 Tb ljsy.[o6UVPkV³۝1I哺/i$|]\F˩Ts63|i7W!1ێI,ʘ-]n*wFC px)= _hcc]@G8/{߄rvoP1 "rK\hxME-.V /< 1(Oa1'qO5nQYy>o0T6eǙB0YC0+r1ĸaa*O tYlRkY %M)%& fhk//qEz+~i4lA&07$Jch'}PtV(F1erEJ~q%mYIM b ˦-Y*?WThU#_T?!5JN+ ~?A`&UORG: `& o m*D2+K}UP#Xʅ Otb}%iJ*efVIS#{8JS@/qy%E[ O!uWr~?g+U+tv;^)u'KD*"Œ!><amtz͊m=9u߳$. 8^k4 jĴTp)*oKUCLG f ruB2T3ρE+ٳg,㏔BZC-5Nr>ʜZf 8Mo g~ Bv\9q *Ѽ:rcT|C$k8"(?H {/xaϵe:/}3BI$nYxz®i򯺟**{ghdzm)(s!>嚏_u 47_XKX)b5Q(>y:w=$N;e4qigg2-m;5̣|-QRd!P!UVPEH&'\zt]^ˢ^FcGZ!aRPr_n8IuyNXh[ 2xo fV?K&MvQ:& X)|!y ESǩdjQ_FOC~gǁ4^1yH X^sekd cneE3^ꗚ†G$k@$ /UUHY9QdDдx:1@v4;k9DŽhآ*Z..;1Τh aF&߲VE-%73oV{z.YĸFtf0Xt'r\VJ>Q/x׊yf=VZ-, 6~>NS2A~#`gqEsQCN%䁲H4?|qux7 تemVF9z,}k>%6}qɪZYx>M,n.VixޅUcd=e"ܟݎ T kd&݋peRhlÈfz1ra@ژMq00TNJ4srMD֪dRv{7DjCYsҐϊv6Z/WJ Ή|J#^!c1o /jj醯\nE=6+>AzC4=8{17^xpo*t=̬?ؚs`_CxPu3~V zCfK&͇JG{h=K!#qr2T=3C詩I(a"?Y}411 4_*Gj%=f֝«6+nD!݊9)<{Pjyu`mV_ 8`)n"ms(.I2 `TkJ5^#" )|21iNiN5ʶ Ј7`۰,]jz(NG*2kڹnD4nYC2Q.} y\sbB |l4dޙi));"2?nO=ncy+GʷrVjӛ,/ /q{BKwSR>!,FQ<] dl'OΝJ EeY"$ҩFߣ0tvIX[Ka=nE<@˹eK1m WsѤ{ܢoMY %Q&(^фzX8&1~Xyp?GF\7̸wG˶܂6%™6л#6[H*#RMgDBL=Y8"2z3|{2܅sƂF4Izg[Vj⤛噐%Q8iWۃt /γ'aA'UIMs7\¥(ʼG0r@ ΗziFk$"dŴ#xڌdGd![?r?-le:BWLU%g*T%2p.5\qSKk n<`J#R>Y 'ܒHm])ddV:ryPQry8NҿjhRy$Vf#Ɏ7 ˢbܼ4~0x' ~u=`SG7kM}7?TdP+RZ#GFfZy۶q.YD94GJe1_G K2t,Fk>~0 ڒs!I ;N2GctFκjgz&/ZY}Ս? Oh@wKu]fڭ0. KǍYI-RUr9 㰈-&rVS@T(UN_d,Ƽ:F e~&*@f(ZI p*llUgKК!S҂:<;6\=Mx8k#F` .WDh8tum 8r`q[n3@_"s+93~ <}PӿP˃cCh@EO|{9SNn׆HA"}Iʀ0T&|.kacܖv|6Рɨsv_@ *] JjO%Ey i\.6G-o2HO]y|AZp$g7HZ/b픇,|4aIT Б.i&B2Fֳ׃u؊]yQNh *_R@5MkK,M4@T؛:vFdϛ'ױѥ^&NqU8&VO:<Г; 4PdM1 :}qMFl+|ITYEG8+1r#YjM BcV>vv`qa&Ԓ&w^l`Ca:q{ K/*T)R桎:eJ4 mX̶?bs0$T8jyds4Z"8cTն7@2NDcERITg8] rUR\Ư?u'N[WҲ緝j!t :0' ]<Պ,CQvW+c=a뎸:E{37פļ\[`FpBqxkX⌈ve3NOOoFþ5{i64f^P/2J\ڹPϫ. Q#Y[\W<#T#}x&ZbSnX :w}I KY^zY~$"`=SdA1wڋmc/HA>TѦPFZ&mo S4TIsЀhf;Gx2?p­U6`'}qec.lnCf8uĊ@o+ɒk;˚ʾ5PTVĥ Jr?VcOA4+i?2猢ՔS9q_ő 6a(F2"՞])sq$rT،-t奉xDf0BMR8wqX3͓t\[B7&C`]m5:,flVw쭓Ϙ)SO\M)b~h%~F[w짷ª¬HK|G' | sFЋz҇T-f J'?]'i@96KEt27pև8y@eEpJIfia@-2"1h1@K,Aݔ) 9Ԓ>3_W~[4jOta{A[J3iޣLjb /z{Z!p>'N:e,8;]~xN)@o(K8Yu [kN5TY=o 2-gnH3 v:Z~Ll;NS8/maVZkY;ʴZ%sk Q^m?p81C\yvCDO?cd/D~p8t2!ځhqw A8ĩ'Ia`Ug7]F;@}|)e7ִ~^1~V9f+9EFb1K>^*y?U}Q0zQ^2m]jVt ݹbY\7|6'jAn'o_9d|^^jwڱɈɬ*dI%) Db9+i,6@Ɛ=>:7 OԽ?e밠Jٕ F*5YB:7m4ʟlu2ocME,6)@9=f H 1kד rswDEI9F-b!2}+*VXeeBl霐`HAwcWW@U߽ZTסq\1?K=3<`hI:Uu:nl/~A.J;lp1Ōk)>,tLg±/ -OnX:?f͖s5WBsuwr9C( 7W`o7KᮃDJD؊Z#lqZTE^>JʥvXwOZdߌBu'3~ šnVO_DE"҆+$)КV)s oļV |ue^X^}Zu,qY O;p;3+ 󕨨~F7u->k>fB*%&/Xh6Q'+K,]kcƯ!1ˤyxzab>Ga(8ZXTxT9CcUL{ϖN#}kv{GDdEz^ Wj.4jH`ft|_6''kyCN<{NLk8C}<2 HcXLv!bdy1D.hxCC_Whi؎Z.Ewp= Ɉ)M+cUt8d`NjtԋOd@ `A p }/\)D3CLJHPx;&J(vf:'kƃ!F|্ -0'tuwy,?pt]BJbL*^ 0{-َ 5T f[҇\;JvQh"L nT0Qf^e&,-o[bs`m$o&? _/|+@f?Rk1nT'6[.8fl3}kyvG@6-(0fдD{^dPrl_l{_F(_U![~168l ɽ 2ga=`%8'o~W^^W+'ֺ [>m?Ju ^.*iY(/mvh1:U'/y+s]{ QVm`Vt'y1h߄ VE0Xc#4TO`TKz2xصi&A2)tykH䑲3TI'"%@qhnh6b풋cCF䭦O[ԗr$Npbh="/dp"}-@*{H|$:F"x}A3٘#y"ֻ'p@Hˋܻ ěψZ&!q`ݮ?kqr8ӯ;P <9t [(qQ.'nѨwF69$;F:NX@&Zz,~iచhT;ocoOX.}NVˍef8<'JYx Y7N"P C x6.T_+c& ' Ogzf"V661VbfǤG=]?˿G=ɠ°!I>c Oޑy_] S{-A9 cz~Y:LmXx:n,Dԅ:E PΖSغh"LcHq~w:kO(k^B#3zb)Xw5׊ġRI)=uf﹆_BflZrgbjs B CTK x@b4LХ\κoUfSBJ1Wpl6;t>8PA'/Մ*L*Pm%+L2.je\>+hN[V7 J _©%V bȆ37`YCyN0pP(Եz` T6(|"o*s0 "C!H[ %ǃѥͲ\*'ߔ$`r 낇O~PtRHD j3wv2QZE[\C+D/5T߯/||/\w5wde*_~@byU qH,ZXڗOlױgC7Gڪ+7x߈΂" ]/`;MxH{k؂YpI>SqO%h|\ȣlrq?wa|:V\HYҭn.JAU$kom 'OPwc[d teCK/? eڐd O@k-ӖsqlM KRRJ\{̘z#w닑kN}d ec[wmh]SH ZV: *_v 1>Wtq NH5?o4OkMňQݩqg\Z ʰ D:lzmUld\⺟D ޻Z<:mΜ{J?i-w냬42f}[:%KHDXQ[PckH~9zE0~mUs@sƑ*N/Q},ȹҢ ]n"LlgvSMjOB edʢ>9ƪ˼po3 Vf6ymlq W7;|<T$HT6L|9rOς_Qb "xy_Rm3EVLJI65A=+M:tkMCFfm|3^(j:$]9j*K]]5Qm~3#kt"=SZs{ٯdੴ&$ku8Ǫ5/;"mTX]K>/{U,8x%G{!&\ H\.|_̜: nWj :6iD^#y3 4gYLu('z15?UИߟ- -I !Xk/0a^:g`cgdi#&H @)2v[(3mg]m9 bg3e);.Teap{NlE,w'ƩK(YB;G1-SYK|Hw?עC[ +7i;4z/hu-(@T#3c;[6օAȫ?X sEmBػ j ~L_\@(r$K,c,KĹq5$՗H-I24<,8 p~)Ӵ~y,BҚ;e k"N˅4@h:;Q1Q%fh4'[d{Kh}(DssV_J WF+8k (eawNnw:;^aEWкCNZ _` FQE56rVÁсaX6^k(&GjY7``l8CoU6 ڱAP55dȉrR}#lJ0n‚.R*;,8x{j"be_v'q\E˗h*U5D "d:sNhLt'yCɧ}Dgd7I>/U3qZ~x܌86G=tQv{u ȠSp+NWrLU$|HXʽjBRf;h&l$Fq"pWߑa1lɅu. h[]~@oV7,xo^PfBkP$psl * DH@qC`Qp+;МbjQ1Kv@,@c~*dViskdҵ aLE{tѓO,ЧN; An,լ#4j vk/xmgdS'lű<~-K5R2 Qg%``, jUNaFц!6E[w׫5'. )S׍{1yIEI ;+F*85i H_dAN-B@7nI?|Ԁȡ,xak&tgѰU )L^@_H-:,ojp'( cbϐ WLMٛT$!\pā 20>bE㐳%Yãςc/lwL㤽V>l(` B`:g^*ULDs ˩JҟdL/ک^k3,Y1m>-HL]!t T+i_0ØiYf]ͣ~hK'۸YSV6Q͝}jҝs'owz~Z|~oo. Iq;0zn(Oq3@F,%b>űqm1WAjģ@^ i c40(G p{D?~Wҩ砧`z]Jg%|0|F*i.1ecBZe{92z*ڵ --ð1Xmu75pXB0}vXhxowtBެC֊-H ٪O*E??3da:׌$(&9CVn$|y"#knMcI@`;ǛJvƆ)2*E/-w0FP2r~nˏn c;^U&}T={D 7_5G٤V(W cf9 DP·Y,V?,#rRd 6ZE18MpGWZUe xU0dEx f\|>Y5I1""Y:2^$%ykq :bmXmegyOHtW63wbCB@z:Vشah uqY8.pܣb_ 6UĝL;t..I_6ۄ5ƏB%TdnVI/@E8' .pt7zQVZ,N߳ #߅} ]oK1.Q|r6W&nNx/OQ2'{i#&\f5B`/dm_VR S_Ρ?2uczͬR q$w辆#3w77e?֚GdrjIL x -IziFKQd3(FN"h.STCb.88b2 7|B;}!hqc\j~tCJ/k+ `*t`,E9 3-2v.N ?7ca&pAHwUMRQ=Xr] h&e(U #&ӔH5[ /BQ!#;> 28>c4KNz?b5""'d4Ap[1A=^QWbGu򑼭qyc8`Y̅)`/wCa_$ʪY/"ItIiA:X5@Ouj"VYpL{"wSU׍*.߸Dުǜg+\h1Vߟ* |d㨮8 t5YÚ&*`# 6-1&AӰ*ׇ+;dXPWV6Jԧz>J{6 T<ܔ|s 4T=Hs:6':+ceahí#`mBpQnu.咆;:lhG}IdV;:ˉNS4c, +!9|VLaeArWZ;|eOLzLCkW@UvI's%eSÜTfh׹]xOC ! oZNCIV8<>ЖdҔ*Ȗ`wO6=%_ qv@y߬T:gpEQSYr6.E5 3 RW8PF dXq7-CL㚮<:ɸ+j5LdYt{Oc BXc|gմzi]"c$W^j~Km_gUyQޯZ}]}&<TweWil`jJf*j[a:Z-ʼV\ U^_֩g'ԏ Bixpf` 9u49U+ 0XF`Vu0Q&#Ct!@0,L uP#f̾QXunpR B?2 ̇87;e~doWdy:q}Aul T>$w] 'iR4ftH: ŝʝnp 7Q/: ?Ul|R!_KsGZ WtV-ĠAn D>@v+śMfN0xڛ un7,:o}ಎ+e0)`A# /Q:< !_a &2B/A$*\zeY X30B;OKܹĜJs1,E|&DAyu+&R̤ѽbYI*V*-EZkN98 uU6=W#m#ܪH_H2t/6p )K%oҧd;KS!rPva#Nm"qrpd*00V54FXFC@-k&^}i옅qQQ l~g'ء&։|dVsNyk@k_gk?( dg#0T 0 Hiޔ<3`I^ITݝf# 7&I"U W6C.n A\Z]0 N $-7R<ŰGHJ$>BjzM#y5m[Ԝg_1L)<Cwg+F[[4y ai$ MMvO?cq@{:*r'dYm@ P2ϰjͨx2Y-6#fUAb]o1??0!W]|TdMPSG.^O)1 }3YN#"t;ӫY׺xUA-CrЄ||+u9Ί*SZ,e)¼:MvtdnS:ԭz;Y]?.uVzd˂ggVV} p9[5_-!h\$r6]yʤjvJ>]e^uřF(F~&^+ <'S ]\EaπVG apEv#t3UF b5~Nbt 8[-D}s`Cx z! cc{Q"#I}@{FuwZu^`}&8Zz/}!1(oJ06V[A>-h 5Og (,:n%tF>T䡴!bg7)uz7u> ةS\)_/^YɃ rku6NF>yF/UፚG ʼrꋵnmFPJWˡZav=Dayu7w` 4WrjtEI7/2lԡZv:1t,u$lViڴXȕE:}ΐǑߨ eB-pZ> EjN<"o#)=ބQGidЈXtxN~=IXI {VDF^ݟobF-J_Q<eسW;1бŊCEe+#tdee]n.ͼl@` _vFU$Tj_K VWm"zm7#BfJrk'Bvt! U0H (O_,}~B 7UqRD7VZئ g\40C>D+Z 0ɰe0aZ=oE -]& {H"pDݓG)`8Xfg ΠcO|c ! yQj-|hǑ\5քQUzDZ!{AnH'rp ɚ)'y]2su':ZS{%۩5J7 hftl 2*k )8żdIKv1Mz~U]:z C1B,[f'(4?<@8L؉Vw6ҭ:ޕ!SPȡ^ ۞lY(A0q>C]^npX>Au9ͬxmK6p6`UBX h=ZɬNz%$˝hVk8]Qo_eag{Fn>]mcC>ʷt*J-<͓ۢ C{oZ H[=wIlJx:\fLN9Xzc,:=jw5 m"ߖ'ݥ~͗~͹p:3l2u4+FG n5,+"|OIɪFoiqGc 86"7 !WwZR^LPھ.`٪Rۻ,t<D@&icrt04eXW qu:\e)22 V¯dlUaH<7t ⇇ALg Hd-sىf9ӍcQ;텬~cy1֙Lu/`b {ݤLy9!) 3CxwGZ'͓}fnWiׄ Ĵ)!Y"%bSѸV<{u+5a - `N15\0D=qC.bkuoI!f*)uhfԚD0 haI2h oyުU:u"c+=8tflt8{u)]ke1⩼C{{8G8ol_(Nc:,#)`j~Xx'lT:X|b@ThӇ> uΝ5< Vǃ$^a"& M,MRd1׉7Б᧦YhGdnm@~2_:&Dv *4$.?No4F)E,Hooٔ8ʈq‚J {Lb\3#.EV{^bˤG^wk7i76w51a<˱AP)+úlտKuM}] zQJpjwJAB7gIBSm5ޓO<~/(_j%e{D\# ʋKY8U'D(M+d 1 C}> PR۳5fgmtq)pc0,[A@+~Fغ Q,-5!]1ZݧhrG Man_: j%lt^7 &VFb4ݎEJxQ$sHF +-ߡet1Uұ}4R6@LĒkJ6Q< NE%+<_AMe,B )|hj MܽuuUk`1)KEG\`kM1m>>(mKU&5/GׅvEMJ+x,)I炵$ 9bN9d B>$| C魴rsgY 7k# x*ntD .s,M6CٞN{K nFPъ鏄 1|#P{JX/~ahU5)=xUD15ísl'!9j zi ~JoX 4yx,_XF?5 n5uK3` "5I &2<l]+X(Va+ams,p qr'uck|@@hB9>HߘyFa]bAc6%B,ko4_CďrkĭheR@TQP Xos!}U{2P/@<gP†Giٜ]4B^0olڑ--327pc_ (0֓Tv&ҍ1^~3A}Y5%wߡ xNGd \!KeNkEEHxE،DJohmƧ|eX1O:TeƮrޜި/ȃQܩ*StW5OhSߠCd{K+ʿXxס&ٙKT Ȩ/_歩Hh/ ٖs7e!"J1LD 7!CP085nn͜7gRwR+H|Wڋׄ16jb=p2뮞e;rLJ\hkX(sBFov]ºœ$7AQ:"d1+oaXg5>`]ޒJ,{MU QSV.T:qNOA.(a>ѺPm `.DLw9'эUu^B\W|ԵU<+UO}8ȹiɧ[kS|\PxOf9<}y? }ql_M֋Iz WdpK/vvv{Pы#jg$hs/AzwF!sPj|k2I!)Vij ┛7%%i*P8'̗_bo N+nږ&}i -ve>7} )&6,RWQ43UyGΚ; sӼ(DDwd mh;ވW߽B`}6DռBﴘ]7՚='@*0?,b\[yۙ ETϡIΡRz[E?cA{H|WM5#{p׶v ͠uB4w]uڷEsT7*6R0W`{ $$1 `O0Kr 6釼(7 .Mg2Jt+q2UIfWA/֭Zg>"\F}`ЛƯO)x4#n 56i:9Vg/N>HdJpЌselD#pcS` Nt%kNM+^@̺8H0e0_RfUU 񤏯x MˬѸOb S׏嗞f`g:3\aSz{\^W$ov,jliL[_(YM}BcoNuL0`MibȏtClTEE2Dpk) SM?AzMsړhLY KXΧ4?svHdxm}b=3RfZW2*O#R0{ 3{" KBѨ;5GW#&(װkR ̚! cYYoӐ4=Q*J\L!>7 ȔcG[JaJaG\}d͖S5;0'(`)H5yE[Bވ (cm`D9(uU. vrǠaQ2=J]tO<l$t탲" M#z»q b|4JO冮܌z{,.NK.%M*]|K CbcxfF\BK' ӎTTM_3Ȕa&c_.<&aD*浼 cMx:|.3D)"%1KBG9FԭΩޞ 5Jˡ#op]ZkcAs*0Aҡh&q"ٽ#s #& =73*R3/XcϢ7&!,C O\V;ĦIMCetcӧbQLʫb Ok8ұ\@bܙlA I!7 3Xs`3v4i ǫhB "[J jKg շWMx4Fd[/Ί٤߄]CΦpےl( ^|l2 q`NvHR)PmϨ ЦVsz漂#9v!um-З=@SP;E{x31KކN %i= 7N3m37%*Sḧ́z)bv1K^?U-of3-hXlOOoE?ظpVߌXx k݂B +hY3q ؿwpۜ fɭz:x,8s7ZVGXADr]5c#M*Ikpz:Tlx)FݬձrԎՃʘ3T ^klT* Zx!H %D]A6_`l0%{ӟ < 3p 7Ak/[LmHl= p !|FTQe7%/Azf. > n-mkѻG[{; bҴwV  =ҟӅM3F PNN00Blԗaj/j!IqH|*$[=+T.S-$R$Wt[#0ɏfҺO s9r8|3ϙ81c;g,Cݭ%Խ F(;aX >5+Z%S%̂@2MXJD!;#kjl:F. 9N:x+_bIQIZهCG3k4Yd4)GvW]:8;TLiSIFG;`mukFp[}3̟ )93 C[9zeObJ~HIxL!{wN ?m4Ru!{RM@y"W,ΐx!O2j>EB-k[!PCTD K)f<#imDY^ ?YoOJb1*C.lF?B7e! h"]g;Wv+Ny2(4 [OL0]OzA:,ķ3g{blf!a++K]e'.b'$)׊/F޶Z }@ UgjvgK)$Pt͓u 3ݓoV]|F2[Zɏ6:gi+ݔ}:J`Yք04kT/'4bx9;bA z}Bv a'"iaUpnm-uϰǪt]W8XC4}Xn8G}1jr Ew6=|"ҥeZj"a`2yA-nSƁDvY"Fcb5WDOkERp r3?<6nek;$%- FeË+(LD(~P!<RB# İma5OvnTcW9Ǯ]9}ݳqDk~+B䫠-bn᭦t`j&ΐ%ޒ^K-?P&(s)uU:ZΣI__&^A;~C.KOѤ dB sH Ivlze@ӀIє r{Tt|WZy:]Pv,UĒ5|X}ޓ~4.u$zUm5SDeS,~ؚmOp ]F0sHLbO>%F'3@[+NfwL#*؂59gD# g* n; 5/?  Jy5U5 mJ \FkBM';Ʒ=bg,/ߩi^Az\R,9~!Er#]nBK+)ho(=,N}=^S'2n7`2MB0>s%-PlG8JTݸe| ZJLXU)\PZ7`45t|)%HW&LSO;nz 3ws3bKh,)yb5ȖvR슶!k-T+Y!J-ЅsvvcT*mDbTw+ttJ]J lOk-Wk<ӅȲ5VF{\@ ap T5~ \\FG5/Q1n%~% 1 u)nKsɺ$8 @_T~}sgZPDP K]ծw!; [ԋrD#\~%~bki%`Z@.rdÐVwM+_V!S9bqIqW7]o4 DߧH L/geSh !W=P<. Z*-H9}>eVtRӹ ɰY{ַdi9Ơcܒ{Zu&4c+k^U;= ž| ʣpO% ܇Wvf. } fg9 yS/= )-v?BftZj(BEAߛZOJu8d>*gU06i|\:$K0~Nb %I~ _){Mvt>L4RdU3It`.cmGy1pa20xow~~4{a&Xk+@(` NZi0F?ЁJ:fƂ7@! nn5OC 8%yل(ϻs,m#yw MjN1D/tAZH#*He# 7[ kQlIKQ/|u"ykkf8gnhnNd9" @#@WWr팓SF,#hU%;-C7 r~ zŖjE6ZY@$j̇C/Rd=)9hp:v`h`oZg$}Ɠ2T̵B 1J~_*$SOCV]~ {ߩO֩["B^<+v[t٨2C>tΛL8l%M5%+hs#QuF?EqݢͫkK]ӟU =p{gxhK fjkܚ}1Kk K^8TqnRrm ̳̔1(H!G U֨i45=\8D4Tlk?l/ߪp[^EkY.X%+*b{]gTbi.Jp!)ib^zb%Gx.ąɆCYjjF;,Š4,b3s4ܝ ^1h~:vo:*a"&Ox_ɶŪp$V8"plؚjS/]EU0YM5`j@"=Bli%%PԱD $BmD˜: o=x0HVdZ:nU Cf[p >?vjvȰ}@"5}:Ba>҆hOGE)d̬dyr 1ZB&iɾf[KZ,n 6g}tv˕AS}Q-*2|Uc[_g4,tÊ|+)>ܸ?>׼9lS\~*ic"y`ݳ/\[~PJIp mJԗf DjJXWCjlH3*KTVRNcka3҉p|GGk[ꢼZdsG,+ +dzxDW&~@ t_ma.ޙJ%K Hbd|Nl 8D72'$z~4/If@ZT,QXo)]`K!&~s2n51-t:Tš]9!ƪ Ӕr,0$$"c7=KBĸ%}| mocu=v0K.[3܇:Y024aIm'uV^3 \k^!Iw/_O %G8dR:Dx9˵AIIa4HO3T(k!cg\IVa;^BߛԭÓ~<\A;ʱLlXO wIu˲nfB151ɔ1agR)sTW}IPntHZ@h=*\14Q6lP3Ϙ,cWie7H4;i~DZf.`Ǵ ɳ_FWrRjA²)qJkA 3_KƑ$SsB>HW˱(,h 6@}Z臄k>%#6w|RP Š,M#0nY%dsiWba:6?bb;@q|2^-?sͱg UMvT>(+FN ׉}zpTgשEccD'CӋtֱYh7Nܬ^v_Å 5{Rrn5YRFNj|GpL!xM5VUdݯ N\3F[)P?,|'q=Cb5ؾJk4k@ID~պr]㐮֕?!ӾE\ YEOUIFԂxr,Z7̨v0Qʔǘb(R9& pUOc]|w  L5;^e'!PVaKE*=ZmMe'hN6x[)yf!u8>u3!||7My)X;JC::[ ArɣK`Ea .0?vP0ʟKHsFNJ-(ejoKr/>pJNo4D#J?VoN29X570NG ɥ'}1֫d_l]}%:|)JX=G4L+J:2_ Q[bR'-˚wSwr;~zK }=Z֛-[#1~k 2b2=M<\Wޝ11P]d("PR/ίx.9ad{6'嵮.{VRy>F,C&X1{A؇"k;`'4NPH$yDgqK5>7RPS-ܚm#(Vj/zSz.7?@ۏ>&$cZ$~*Z'LanIdW9X :i |BGT~.MR&h}6lE/N2g'{+ +"7"c4 >WZA^[VfrWVhWLSԨrDݨ<٤*ߌ-]Ϭ/&ik7졝 s#} myT [ Mة4bt7Q'_/9/̋n+h.r>%(gd)+Z1yy )s[P1m!{nj< KW~=D-^/6 SY>0J 9~>1*@B Mk"ANU:9vs%6H!u Ω_E(w${pp2{ly~csV]!Aџuy|KW ^Q?#)TX~ج}m,_O {2"Y˖N/dT{E؞VЦSet][Mj0UZ- VƉmHDO;PMo d̗Ϩԃ31nwֱGΈ%ۏ*NqM k}>H2t܇ɗce?@|NY#t(~%|ݓ"?]p@:0Yn[:orCskuI; 6*9&^vϥ>Ksne2kq¥d[GO%4*pNvf~\!AƉ:_e-mS yXa@8bPsKn9+cKʻ_.'a^#lu_R5Ryj;Ʈ)D[$`],V[ޚRrm~H>(Z!)V[b;t A~ UreT. ؞RKB.C'&Z# G5|a+*q~|:@ s%{| E ]i)d 78$8yeO\Z)Dv]r! [H4p ox`Ƽ1ݞP;(r2Z01c:t3CHӝ-UN:3zgxbO`30,fC*cZ<VB/HRG1<氢nzW/G7,qibU4FEAxbp#:6'T!#k h:'6D֟qs!B`t`z~%R|2e;GEg`ыx3ªd~5TqZpa2V5 uOZ(Xu9׻m BV,y)oNN*1nX9{=KE B6iOݡ}!DRڠZǻ}r 6UGM]Ʊv%e3$!x FͮX(rO}v8 wxB҂A`쯾X,Nb{9Vb|@heïhѲs'̯߹>/0QSGX}(q QjvrEY)Ӳ LT.AR#o6i s4-̜1hdoi% L:q75ۅ 0&| Sfpz$rrϚ(9 3pU.jCBE1gG2,o5fX}~LI񤞥|j1+`''ݿ㻶VA:;{o8JzR";hPgHM7(#, vCK}Cr әSϟtJRTS; w\+졣٩^Ѽ@`%r[L:ok5alzbK^f+lGNJ68ƃkNtbaf3 q1h:vvЧ_Jnǎw%co' _ۮfF)X^ͩŪ &Q^0`xWG,> G>XZ{2~/ 4El*&QV.kprere@mM_}C=YsZ >@rBѠuYiP͛VAi.]$3fEUkZnlS&ǝ:_e5r?ಠkM-YGhguҒŽdrț+\r,"PI 34bx7pxi(g8Hv)ۧ*h0Chh54Ȭ#E`-Wo9':wL!q!]MC7Y=J9hF@ZCGc7Мh, ަky`?4Tc. e cW-~Qp`g %KWn|2J|տtÉ7̿]շxTw`\e]BM^>>8%Z 1-n#Nk#A j;Av'+¤/*6(UyŬჼzlK ERwUzvo*|Ea'JHA Ϗנm~⏷]+J/')oeW[< -QXDQ0@砣A Hr@epMkƔL$F~g sIy.8dJ K^yHZaHB]YGåxs6!q4f 20nDSO,]g(fnIzZT:j/hCIUHq~ټ7!'OLns-kc7SJ~iX^׿Bq;;mIIWƛ*r[x;O$g塔F\{K&*Z~]t}(j8GHeJDp&?\DBJ:{H[ݢkwܲIrtc4˪Q ٬ ̉'\ryQ:0ĕ€>1c*1"2zX?K,IQb*QTx4hT{zdtB},+m{|y5uz(#t^] fZh(KV /O-^Nx+C2CMp$<{8#b7p/3jni 'EZvL.?)C7TY$Rh =yUs iqX`CHslWdwhҙkaæ{ q) 'ҐW\g (S,A+HLztt4a`X[GIܾ(뫜CrQ F6vbSjvz*0jVljI2]'Ƨ\ɢ\2w=x/6ZF:6SPt`TIBFH$nY0&{ATf|zP]Y7urtA=uIīN2b7fդ`ͤ֌3>FҮ$Et"峢M` +6 / q{}$ڳP{I_ةټEy<"! ZA; otE  c[獂JcK_Q -VeF"I]KָT.=安B6o<@Bg ۪mE {4TrGڤ;('Fnz~A>x#6jZpgJ fPj&Ol I?u (N,/ZDޤ {ЈV3)$QUѺrg7Pp0K~l|>aЮbpP5h*ke;eIK$?Pŭ@晩F.ΙȘF߇51$;1])k2yJѝ4Z2)X$e]D֖pXhb'fFۅr%' Qa . <2Ͱo]؟-Ky+@2;qg& i>F.rqg`7ixn,xWN+/mĊB;Qv @C>/IߓM:?}$k0jwt.\SȏW~H.Zt̙iik^8nEmseム& @v̢$V ]}׆!tȅK82r]ӡ ?'zH qIK|EhKz?>!FAXkIv Q}Bammiڱas# $UGiо8d,$]~f@wu#?]7C<{/[,6nz<O!e8/íu+O-O!2v1%8q972ڻWFr8^CLPrZIVWJAՖtG+3o|ۭ~^uUϠPM s6SiTm(ck'jd(_Msӊ2(xV "V.7.K~6i{;e[ <}&fa\,]d~j XZ8o Zˤa,FtH88ȍAȃLTġҵ΃l2, IAۯEv]N;7=hG(Eu/0B eb.w)߹a#!zu{_<\$}ߐwPU$)@hB/AE3~'x>ĸf6d6P2L }t߄&ؠmY쾟5UmHQj"SRw)~Ρm.rwKځ' &nnnñqMJ}@i7Zokr pFWeN1r|;hoX`s{fhkQkat%uO5b0NRͤt{:06(*2c`%himZHy6򍬙,p8$Oxk>S`d}]9{Bxs.8կ~$Mhj|DQJ,Y%Bd:Â|5;du&Nl *!jQdb=qDO05amY zS1 9::^*D7[wsmK<\X"u֌?3M{<`R& 6p#a09)Z"9we у&rYn۬qO(?|>E$rqpTU3pd@}y)?/2BepD@E]n0.6)ᱷA?j@1+~_]uf9#vm1H|;{uSh$:`ͨÆ#)o>ˣSRO*B GGdwO+v'FӓŞ+E97t*.N_#]S1^ ]|#^Xc|ƫ,Cs݋HJ/g5 {Bv_ {wփк'?5FT7}dţtARO^r}98.Qe=9nhOd=f!a"j!@,(5"]ݶ+u. k ]άs">prS։~$+~`UWTw `C 2\eD(p8/^y[ 9Ipg>1c49ʼnYJ"XY7(̾aH]xLȹqvȠ{mRa \ܚ2NAy}%1apN8R?popß]qp;0L =ؽcwgu|fSk+[.sDa=TR|!Bb*,4ܬ5_ۙJvx*ˈ5_:1OdvI4yŵ~#>4PIORI謍L#_Z~W$#'H"3PbQ<vi;G_m .%:;*j*icE5`v'|+™fF='@RĹ;5k M4_;]~jXȄf Ӻ:=1lଊT"f+,{/,ՁE\j,^tĀ[R a}_7V$=4sM$H\FMu\*7-IIILM4+mi 6 4 6u*{˳kB]Jڢ|H YbDf6i(%gO$gO#~ڣ6v^(6ժG3@*6's2]`Qw*p|?-`ij3(o߭ }6 l^XbX蹰d~<«B~7N+IRλ }aB{-mL'yu'DOQR'u\?Щe gاH䑪8ӎDMr;JCk񞃄üeQѐjt:(D9(sQX&@]K3so} E$I[)(ܟz⠽JۯK~HU%@Kef)DِG|2׌Q;BGvla.!x 1{!.x}(AJ '[zڪɡ[F.-* yV +XdՃ6_ox̣z:U4̺,捒& ~t4ƭ5u]y #WXzݑR$g3Z,syxF(J9cyQtn׌z17n m m߼ W&7.FMk^fϮ+ F!!A.nVT|]y`Gcpm& /6:.6H %b}(>bƁt*14'_hÄwwfCjuK;Zm^ kC2"}hˊTSsg&1BHDZ ȡ/2jN(Ю]-\ma dj{.mG3\J\ LO;op7ﲓJ.̍҈JBAD=%Vn]j RQ:E\)ɦM~[*tGBYXwJ׽[J1OtOҋ{Sv(ًz`\{c}p s./ۧbW|ul_q |\p[4s.rtl}RQǕKwhߗ/ /wt%-uF)D%1Ju;p$S4l["Q3%RA톉 uAOS(Tܖ*~7XE6 w﫪i{o:\ΊYn7 [H)@3/.5 &Ԥ'S7 ȣE d{1:@ӵEONP+Z :oUNzܮR4NlX Ӑ1ڝ] f{DFo1 QE #>Rm/&ֵc Ә~1Q'zA,Ś3w1x>6^MMbI-|A"!mKcH#Gҕ Xxsv-MrM _mS,PNo6?aAȞWצE:Qa]095chp#aI(x4 2,/?2X\ZCpojƌ &:^]4cg5fZ\`;Tr>ҌTlVzi6/S[7!5陞tM:2(dKuhr%PP}]|-7,WhJ(v^)jyjRE;[H歗* ,R;p;1y} );UF dPd 3=Fٴxu;Ͼ!1~( UyU{[5qn)+9b`(WtDj c@ngYvu&W>3MV"Ա_@R}.d,Ɯc /Qv c8HSLͤ3m7s 3_N䖢*{",C*q Pյz_k1MǛtubfKLsVǜoؾ{οLSf<ǁ?|gTP"4ҨH0 itW[bU#OSM؇n£OTǬh [j/rt #"s1wUؖE`K74IywXlf9\eڐʍIg Zlm7ӟ@2coC.NpNdZ Ixӄ *}nj#/,SQj,zi`OLpMu#t_"Ff9Ӱ#R2# ocnǤ{WFWVHMΚ<Գv:FH$7od1v%"=T7ƽ"O/"a3-. e^CK?)xL 7̱H y() l$r/v [@7~qU{ $M2J+>xnMQ ];|7}js9q,%9t"u}-K֪Ӫnw=" qSG fq'$D1%+5- J^kp |2$Kǯt]cs1E3E(қb6|91w'qS] [,Ã#OV: %tb6 LMD,Q//bLavKnFjZ] M|Bdt Y4.ת?&հLA[`,zIas`>*y<)0uNXۘ!LMàK(0hw[`$Vh@ %s/_Kc-Bx1j@6]l]IR~+`}hpV${JYl Į;b5r4|z߄XQ/ڇl[дB a6 |;[eÄ:8H~߁&2Su[ Բ. n!uJtPl9˱ 2+j\X:@(89C VCB5GEB_9RC4Kņ^vGP-#`/6j#_3jTCDhbMnp"mCU>&eݲ x5%R_IV=!5 (24 !>tEavRXڡ45kAZN-Bx @U?ץĐƛІ aŰ^иqT|>5#;ppmuׁ"c6FGf"Н`ȒyAFAq j ɞlzu[}%bG^T"*F)sR}BvM85@5ZE 9닧絛NYl퐴.Fxx+]1@"Di$y[yI&+z5u^zw =\fZew3b{CFǏcIk 8i}B-ǡY9/I55hRf',v0۝;"G5׬lnה5)A VH4iG{cDW.[$X 転ZAT8LSԳn0ESX"7:wTTQ$7DU!;2MMȹ{깮W礐؟}D^eu<p={$ ͧpuJ:r+#3d.#Hl@ƍ՗Շ³kv8>cu>cYO):m[Ltf7YrE#)fՉ0L?(J+^y y , Uqu @=8xE|ul/GC-1kJ}x**c$+Juye_& hx҆JOFsH"]GlI'`eqEHWx]*wRײ8G|yV2{&A[;J&\ 3%c%jIi$2)EeJ&p,P7!wst!T/pa*=Ôj!ܦX@-O%ڲ~03m1Ov0=?i+3ycrE oHoA R_! @-BԬH҅w"&R.? h>?~f@kLiuvImFǰGyRFtY&<[j8Q×2~.2`K4CRxÆՔWXu[03^V8;vY)8bK8_+iis*A*todS dܝXԈtR.洱+s,d ,\S1]vؐ&}uQ5IoU}rd+adԭ^føtxU3` !| șţ[."Y@nLF{|hA:?٬4)70_VmCȖM_!k+$}Zi4cQ1re;ZLoL).^ UaL_~riZUf%-M74w֚c K徘 ~jO GVc,"8$mV)$mL\%Py+*EJN2/pw% $j4]Z6S4FCLYƈU4<%jo\ԃF9 yDE^3Vr g%X|(- $R2*O" Bt S+`fh~$ArWqJj@b;s)s~z$7  9iH$@(D:c_խ#ˮS>@!©NH K-n2>1E,&Ca9ĭΤk3NO[<N7DZQtɥDb*Pwԇn?C bP- & :[f!om:<P ~MU7KrOYZm@K耱lmJ>Ŵ%V]|8Sy xd&:{"fMZ`{|/T m9Ⱥ #l׿FְD(oߖ7pL3cGyM ZbQK]gG Y7讲ަ_qP0i["^;IMw7(u6Kظh0शbPz'*ya-$̪ 63Jdb_"p^ց ,$Yj,Xc)2))Δ}P/Wϣk/{A0.-nւ۝D~]$`DKâ/7F2m&ևȽy@'ؕ4aw_ w"5O [DTB*Pro>\9)rX5+Pz焖.`Ma.RM9%woxSj%8րSGZbXCzxЊ"LͤRU8gV3gdI\;jsbr>l+@i["Ahgk+\>r]; ĩ txL?b|Eg1aC<[*9z0d`5l?d$3."7Ui*^r7җ9 Pj͏yFқG~# }f68| '83x݄"<;vxT&e@phS=M{-խ.ˎmd i{JE ` tqR$5M[y[鲟#2˙#R I>BDRbE",#عڇ 15W &S5i6! "' CqCN#wSN]SP훰g!`f3o 4xĻ4=z.7qb5qvXznv}>}stXb,2ocۭzM0Ξץ&<'$ ]Gi^@W n0ﷄrI^yg=^: l6dND. Um&sUpMgU;".679  ϝ_߲vƇ|76 QM] ܌얻ēWi8N~QӗHI*`)Apzf+Qd'Cwu֋Urw*͟ MkwS m#Ǿ>7UɘHh{+tk9?5+|k]uOTକ sqEJ횒D'h.aNV ͩ^l{Ee.YЄkENROC ~*/v.7ZU13xӉ{k}#`ޢLb&8*pQbJؕϖx_w"&!Pd6B!Ɇ2JŷeŃ˺Ȱǚ vj֛@j|$x#^]-phf| Gbi5+CZDZENPkKEMUA)6:\Ur,=~`ӴO.2'RsKJpÞ$ZMG@,mPkP,H )CZ&U!Iw LbG=pO2A@6O&Z}h0Ͳ yi~pP@b0Wuyb֤xg? +<<({ѧf"{+6˘cH0ҝ"@AA `-7#[N@TB PA^(r\&J"$phww,s~"tq-̕c(@-A`*wH@()At.UxgǸ},oK'B(Y[n6}/pal FZ'6Q!T?^@ɟԣ+dۣ枭RX%;g5Ll:Hq/R)+@L{)+8F\a0a'yB]-xp ,Oz1ѷ\ R;~iVO,n<ФIe>}iZh: 0,tqB[Q|2۳gvRAr \"$~K>B@LBRӈ/Jy4w2 ԓͅبQ)zj)ǵ>,;$ a@̽gd7#őӟQ(@l@Q#2O50ZvjB Q5 L!{۵͜ԭ輠{줐r-) %)A'&.ja_@sJkF+'gx}<& HX-ڂcq[2IZ!֪'g q,ژB`Z @0clc u%!H2=דR>GNhv#|FK3nmx%4l@׎*zf_N'xΊi8wi`z騯 -y!v<;=U7+s\j؄n(&)1*7kBMLqy:\ n8kĴmm{fY4ګQy`e`I/NK4T'w:b>Sg'n‹^JeҺ%OII$e#Pw=yzddq@8 7V~(0X7i؄ϤOL YUr[kH{{ޝpSPǕי˻#ϲDɒXJ5*T\YQzaXfr'?'l&B Έy,R59ۛ8)" ea#łzFٗZ1@6Q ʋRN1Zz dBް[N9O>me/j:wո&]i:-m̗:d-N)tΊ0i쎩c\uDn]2\1x;dH<`@K9#j^Oc*hMZ$A.`m ͗AҴFՍנ[+69ًVM\WRRI"{ƺyrceJs|MbƄ17QqoN\ ?Ifb{h>;%v3U6|TgoA`[gN)B#fYL2b lUNJ<@5A *P? Ql#]I?kkGP>(=0MSE?Յj(f㹗^6 ή ta[wͩsS 8eьoz#\f{Zj c)e 0-mmډ.jz˦o* KًL#S?^q_d.>c#  2]I7a)cįݯqwv]_]G֥@L&{~ P~_[[ǰ/ix{oRR4UhKq2q 뛰A´Z{pC1ZE3Inf^b,Of<7ebP'7gmכ =ߛRiK=`H72{(aeu 0ҏ9'P 1|>KʹN\]Fs3|o˴oQdtv2 iyG)i#R^QÉ*ԩxҡ-yGG@ QDGiz(SGL ,s-9ӥ){9hJ 2cm 6E)VZ{Do SzЦݑH&h K,dd=T;&<FS.Ċbָp@ux$om>N˅RYP I-CaCwԉ{ HBXQG<ЬL4@I_!쨾>djw>fi'Vj(F4kT IyP"Y@*>t|,Ǚv$0yt5 Y])X t))Qxu$hSQ IxxM5I&SKukL&ww0XMԔV-zҘ!IgƏ!k#CUn{$@1r`m L2*el}{)U;s[+2M90`p!˩` tKָHSuB$|3XCTL0vN_8-)JiSB}{%p~UZfJU+q6/\bQba,y$n? k}_N3R$jlDwMT$>12;~^pչ#ed d@[:ksm{ZQlmSY4/cޟTLNWU -wTbs ]Ͽ/#]v9Oe\iى9(.yA6HB7 Ka?lNj- |;QQk^!Uo}~E<5ֳf2Bd>`Tx LggpϨ](ղslN56nYfȏ ,9Rw]||px49lp/VmNMf[uQ>Sx-$v)~ P:BU ho^VpO!N-_VU6Ғɘdž6N H0 p`0D' *q ʇ/R `^YSe5%![1`sKWH[џ64Qyu4::]}Gm q#wW_: mr%C}JDKn߯-S_y|C5׾]VRHKOH{h@QJ7}~^No63!B鞏74·WC!Y.\ڔ+,Z[PgSɱTxNE^NՓRa*G*}&CK_Z#d>"ĶF{_{}1tz~5JJWQWq۱ Szfw'0) ;Ag,r0G=u쓇äj_')*ciiyϵmsHD+yt76A}HS8G' ~eFnzMMs@aZ&>(10\$ru'$&=u70K JtHhyB8P(Jj}Iab _ή)C1;>Q3!؎^=,|l+usfGȬ:vzkFMRK|rc ^с)E//!=V0{Bs%~1HWi#gDJwi.խ{ABz i-s,ec1t|\+Xi_2e&)PwZ^gC?:~ nD|`E8+lP3.\nZ0icj!+R)mb'e{> `0%1W^yc((A"U7N5$EVhJVZ+*kBz :V$ 8[*7eN^bDwV~G0.휶(U7U)4գ'{Aq) XBB :M$ʺPuH:7ByP&]E}{K$i>57Ajр!fW#_'1fvϕ @KCһQ"vnX9D|NTFKFZHm?EN+='*'lry!gIenElXD^U6?a>a?ٔPȓDax/V_&ȅo #Pw%/L}P2⛭_V[3AL e4e9||V/Z"n43E$`i~.]YXe 0jܱFv*A4h֔e y{%{g[xpJY\?/k?X;szuqZehNq;W'TAA\ ">a5Xvl2s`/ \Z_,1p#g Cv?!ݺHb|qR˃l>_tS4h~[Np΀~ ? v/rhHg04u#NH g%yS/ӻ szҧҦW]ǪY}iVtoPD:+q[yL6[w H6aNuEnC!bJSKN#7b#3EI\QF->X7SD؁ŁS='vzbTocN).5T:1! 4S_9dmAcĄ/ւ.jlar􆰫f& Bd n| Wi+;Z4']s8;` @>0[k4q M])D,a!̌i9y$mK%֎/QW'.]f^8s+'ۂ J,„,ek}#o~iwWbJ>ORJjS,Q:IV_0 'rVxƅ# _S;!m ̸I`d%SovM9\j)g\ɥ(Q>aNxwQp+:T)T)A:C{Q!*5ͮ¬7j`Tn"5}f*q' kf9%DSM4md’o\>d]ݩrtҴPTB˨TPmFG&90—Du5"~)C(sr.PX}2&鐛"I"}ՊR9*_hg*3YtKa`R ƳpգR2d~m~JhdZk{OMbB̈q,iۿC.i.Y̷Vx})x wwgw,ee^(J|r(d="khwۯw;I~Ԯ_/D >0'|3P *:GW{>ajbZuyC&e`v'e: 2T;kg+aoV9,>=,U"N7Xڞ3ϑ-ytOEĝmxQ.DJ SB"L|Kt"p`'L[j*`ϽmP"5B0¯b#:Ԉ(+J33w8σ* ,48I̽=%v0% Ko i2 Z i&q$qڂ1c/Y$~>/V^%bTT^ΥaK3EcjQP z3xpȬ7vmrE:bW:U:!qNMwռ;5Yt32]Y vpT6Ck&OҺ!c_pgn鯷v_Ϭ*-B@F9uIxm\w'k1EϺQD6MmmKsYoH' 01D+Ĉ:9b ? 9s~^tE Nh6xrK2%u0v;q 1>ef-J0SO@y;Dؒmp SVġb;$dYa]Eb? Cn+p2~.(y ˵ YD PyrP6V8[}N|m5$7:I\|t8Y1ɶAl?د{"['BC*dv #Ē,ʉh}w=%Ž3EP=S=`Kӣu|ZNH]ж2z~a: NGlk{'b vvc^-7SMp9xͭs҅9o!dgmo-0G^|QIdSq;'c/ !j{gZȇ~c@w9k5ǽ=-AEQ[c(T? nLqa.DtٯmȗŭojCMV/-bݔ)&#iD4XnCBfl]of,}HM#q'! =UM? \~.Q|}%n3~\~>Hu/1F2^%͝ |Z$FwT y"7"h1b8LW_LY *?#dԴ_?xd 58?ѽeTs9kţK ,P4.9^>w|rl2|S-XգN4w$A]pV vu.r*f!EB|s_Q:H9mɄOԋX5A҉\˕זKj ܔ`} A~ewN&IP,t#*<@=!1.ʚcmT܂qSgWj\'sƛ^kq2:<PΞE܋ĹRhrn\_!27R_G⚍~$GkE\`_1 ȕbU4IA "Q0g1Rr27t?CD*}$ک4Yg&fh)H]Vs|'C醓 kOrqW摊h9 _|e) {)(C$gHή`0ߪt2n(Չ]-}'#`>7|<83Msy?v'-hb,X2̋aDUAk}%"A R_`' |sxjnN+C |@&)s!OF9҄Z~ΰIw! ſ~må*:μ'łg%::c+78)7E%`}x B?C' tdhRjR)_N׶8onBTnm*1$H l%c3?*kaHcCrGF(Ó|[f l I΀p!ʞQ|ZQdWv5+ қBf)Mr QHs.P{nPg`Y ;l"=IYq%hgaF+GDBap? vNapwIV b( gUVyXLQj]jmCڊϞfښBer//W}9$`KL쌩P c"ol_,lCL+ 7s׀]6*0@z4U "%q!tis70E|zK2=C<~ `өXmU¨PpōԄvN[=-GNZv[f>\FGeăpZ+ \:~j-|djcRSAߘ^s]~>[>O,t P&ↂk=ڿ#,( sZtBs 9ͤ;}Uȯ`wm\9Y"`"scu!| X ߊӘG^uRƪAh3 b:?rVvGD' %RHV&Y(.Ɨ)[˓=(M4iI7h32]LgiHJ{e@c"azk//_FkGe֓?HXQtsʼ߃Cvhl# %Y dAVl8@nhm#RPt!I JNxj|ܪɰ`JaiI|tSE>59>GvaHA3G{W965[̴.Ld?(&ilm&X>s|~c=!_^Á)UX_OW^! KFK-l@].e͵0R6V(kX*Ȃ[g΅8b_]Hi_;kAr`civ2C i9ؠAP3 9yͲp0 /RY.؍SP>*]\A`> b{^.i5UBO#[v>5岣-i/~k[X6 ߋcf,:EĸLƞf=A>69O5zm~S-~eT$UFgp6n9{*\aafbUIm[SS#57Oyu1X@B$ U[xPpNdRfVmϒۀg,ޠ⨂Sݙ9%jt߫^ߛ *8Ay/ł2&,+9FsP.1١|){lksc8v>xǨE|+o{i3³n^q_| mM0=u$֕32=oy Zqfzi_=*Hc*-N;tAԗ`Eی4zv,l>ً'ͪPUy:tKtE)=4c 񟭫;{&"q}H-6N3HJqs╿J=Fx a^U&3S !ԝ$8_{r}~A6$|Vn^ 5"`s$4l>iMr{c(*"R\=\4Qr8iOPs[Tkq<ݮɞSX_WܨaLQ:y_iZg9j2W\K8KfN)QEHQ5}2]`;WO"|èޯͱ`,o+|#Ţv՚hYn>I> Xu[ң.9 C4^QҊ8, b}xI MWk&3[Ģ fS)ݥl+R".itU ^h- BYݻq8`I]To 1_?UW`|,+^?:OYE1[Z X HڴM΅ڪVl&z ,wE!)v3!s{=JjkLQ{AL n11k˞j^FCErC&Sp j C NPD*(=&Q`ոt{J*O[nW+tf~$ \hvG 1?78.ՎƙwNcG,,!Es,LV>)TTDjXbI?VdUs4\X1([s9C3 t0dȫfZA WNG2*BՈs4 7;_2&E'x ]7w(5Rh'' yJ~wln複&$eY4n屶じ Li<`np)VS |XO T@!fo["@f.jFp8^QɆ@^ZQVJNJVꫢN#͖Z>Mġ QdxoPdGA/)dؔI򥌅Q BMsMXPWZ;mGY Y-_H`*2FFУG&v$oE5u[rj-jw;ɭs8gʌ@@9`~i#a ϖ_EU]7P,N[4R^2mS$֢Bڬ]$ԛ=wnRͣeER F"v`OO|$,L. ~֒?Dlf<^d䀢j>i\ `z=bk>Iz&/5ާ٪)1]#h.p, u=Y2 *@ lLQ('՟O'>D#s&!?m,P{h4dyMPP1oN~Vݰ܃x kY@_d$t^6KwrMp={fT_/kx<dh2?j vb7X+C$jZՅ-;R'Jj iKfWQdzRqP3MPkN_x]g@vCޞq rF=_֤%?U(fL̽\ǐo, p a?6x풎z~^-f(oG[wEVn} ew0>rl? G2o?_ )mUL(@vAs3-1$l(F[8ŚAmQLwWӰy+,Utzp}ūcьW0lNc0`:S& |w5P'BrcmEQ3a RY v&68Q< ?{4e /q;ǐ PM`u& ן3va"vY!ctCx|P'Z)O%9ѥt=ƛKdLE|XEmWX w∿swxΰ7=4%Yq D1r.LJ8Ex!Jfw S 8_ zjRx$5as#@>2w)]eWnb2VC'G}/ e | &waQ9DubO~s }ٱ]&]!u\ƸiW g6wutO.N'#__[mrd1,5@K6$Ggjؓʪ*+\)5C@c, h#R]kMTk)Wh3$WBOPXJ%+sԲ/^}YX8|JRRe(W%T/#0S Yꬉ Ż~YD ],;֓>:n1Ƈ dO>9t$d}d𤅊T#ٮ3#:M4@9VtQhDA1cf +J @ &I :  Dw^eV151Xli*q4xaX,ܞ}YjOlкARAIŸ&30Jd,?m֧ Bw7ki5&}X`6+DlI(F7lA1w]{==L7̷ MA ƙ#h:Γ4U6_kY1GVh1 xwIx`J{8p2;p)qr}k%aKr1^埈Ro&zsUŚe4 hrD'幽;Mbx4%n";$UD! <$~덅A39{G[J SC(%6"0bMi)lH!1*ov]"VSReF|+s ^>t?o>ywRXz"e7C N` 3eu|vyK˿@;L _&ّl؆@KeT[)1 Lᙁs +Zv8?{ jt*l\԰3} F[}.e-RMX2% [w)+i:GΜ#>׭c|}E%!nA-uGn\gRb?<|;ܦRDzA&oI }4P0M'~Rc dɴ"jl8FKڶ2 VO~OhyQ474D|?Q$~,~i<D4Si\ r)|v sN|N :rM/*4bbEZybq#V*e C1o6'fivQ'$kxc9Gz‰jdžآJ;>+^^Rf,GUѳWKXo/2q^Y; `V4ㆢ:qh J!c^a_A1@$ #>e5eMn R?5eC "ű1`2op%t` ΖNދ :ٲC 2+l+K8 ܵLh dFq?ox >KF^JՕU "` vo ?7hqIր,}i?J=lĔMZ Q'iI_k6v kӈB( Y>ؗXOq3%NwS [Z1 O9T༚/nz%2YɢkP k.Kuo*v_5.WjKsыUNrqp)xKoDD#lh|dΨX.UPN[ = 4]N:RM;ewI ZVIT]!5-qpD?3Mtl"^7$ni!h)հ2[JQшzzN){WMĪ徛∗E7J_C%1$pHfx +GGŌաs exJcxNO .iFɂўWQX=,  +?q lp>0׎2(`o7:IZ-Oe3!^?>z?Ӆ ?zC!l\H{XO|:WASsyqWz~zՃ[mzܗ"i&xU&CV Tc)B{VUVSo_%TOlT=4ҙ^Evl=BWx-ղ$YoǾdo?WEnFje$e|81&A0\foop﹆4ؖm=Pw6?-Rl %35T&I5ߜ6*64 .FửQ C7Ki~Ŏ/wlډ^`"mT90v?WX]0X%1u %񋚀?*s5OkwbHW0ʆ/A&2gє[FI6Pr0Y-ާ+G a@,?HtUcFBP5ePn !M/ XD&_∽Dw/!'#Crmjn y\eHω`Dvߟ ؞-Ir5]0\BԌo=rى\vIbM#+puR6s 90i irq$Gh 6/o_K'\XǬ5Vு Nگu0hGY/*"J<9Nx`EpwaOP=#­6XDؗ3kΧ}(sX$ i j򈶆$^Q^LDbc+}@-}M8$/%8"M1ds;+~ :!g%fQ(0[I(J4xd.B=|{-b٥?'tda w#[//%:#57*N!F_ :542`$Fi)@G<(,`K:f3q8n^nFmoةq͟xCPrfZ >|@gIwr3rƷrM])-MIK\\[]S _umʶ_ZPc\%m 0noh;m97c6rVy3 :WA(1pϯ@f/U8}:Rsnֺ옻^ReiEi(luEKZ**en+A#!A gqk6wE7-]Qc?ŦJ1׉,)Ydi;(c!pNJxX,=޹]\f7HDtf6 <}t22Y]`3ݫ|iLl| rTaj(IXiaȔ'=?h}DŽ2<ÄLgK(^xWsgצO@5"qV5#̘s*RVOLV`UA;>yw{`- {ä:@D(6QԬfWKe!E f͇)"3Bbvt*4-/*Gº]"XG6aڟe޵mmT9@5':QU3y=z􂚓2ڞKy%ZMFxeͰ#S&cñ{{El.W%J@w Mur[i]4MI3 k/#;TƢe?rN5_ цmLM{?EuRT-"{X1+ψР)ŭl-'J_) 5':rTUv- *%, KUuLIMG]ht)Ybj)3 ې$=$Sk{{} ڳ 'G|HFuHړJ<Q2 b!ڒZϣa y}{+Iy.Yij0-4 ["\g 's'Q 5&T+SkފD C+Q 9]njճ]s"[t^^۴ qr5_ዩ\MQع6μ./ -VnϤ`FC5$óγTw I[>B_hK͗!zr&pKU'?n11k׷Hd9l|3^Kx6\Gh(9TMg#O Ŗ1)z֟ļy\=UB!];nl\TM| n&jЗ?JjeJ0V7|O ȯ̴I![a~_ғ_+aɼxa #~ڃ0WVn/ߋߎ@}.7 ztj6ƐpE4l[sh- o )]dҋ5@zp8 l_K`g)]囘ٶw7[{$X C~4hQ {~ 4~@L/ A#ASHdxd/!Y<@T O'As-_Iouzҩ?2k\|7!帺;F38lBP3IMܿ.mUHPZR#8. >3 FD u39!.“ GV6E 8H}nاG}Nt/hxCH*c@n0q#aJB>NwuC zO%df}$6᳓'ӆi+֓q{77oj kFŸk @Ŀ)i\$5g`sqMDw UMpA#SDKjtSEGX?A/Ԯv_>gl٧eY nч1u/( !E4v~M_I|B՛maJl̏DGoj%eX1QS4[=J/]|+$'oz4\~d€Ju>[85Cfd4y#ɭdIG=t':9؇&%&iRAXأB=jq%EKu.diT\@k6.cG(qrV0wdÞ,]\Y1:eJx,nX^@j"B+}r,F< z_DXEr@,O.`7*[0uLb㘏e1}!V03T cUt7tgu0I֦hȩZ'C k"V"TmS7mu#t$Vw4KW<P47%Gv s?Mpw"OAW% $WmKDd oF3z_ q𠒔GMoerz6iIᳵW IC[2\.1LKc'%ߊD n3ib6KGR08:;)[M!"XfDgPPx9y#LÖL&-eHlls諲fTT|FUYX@IܳAgIc)K*6 -tΰTRZ]`OA@46YaLxS16pa*&SqD`tɋH tu ptTM5O{Ga8[/>>lm{7|_d%#3#WtDxikp=MWd£2A2bi*..=+1 ?f(RK|s.D1O:!7-^(RgyT] NcMOS>gXDeSq=μ{`WSsTC?^pP=&>6佌a-+רѝY=сɩF"q?ڛ>]qDҠB\[ zwZ [v2Ae~Fë;)\"J"/GU!̤1|TWSa&M^&%넗g|=G]`P)̨1rI"6L=n/?yJ[Yz/bmr 4 ac^ sr^b.>\iS\,⪶aYY0ɻ#A\oȾBR7k5V "\!EkAnl%H8 B9pL^}y\cEIPNѴ,GrT`gμnA67oq^+~%~fEũ=B;QY޺??eB1␫6ϯ `XoA,?IZVvZGl |R1YG"ŷޢ+)ʞSGJ3b?MlԎ`A`uǛyy\ڪeVJwYƧ~n (Ƌ($ݳdnepʶ!%HهEyH]mQә'O2JUK\/Iɒ>Af26S-7=ŭt(xyg_Jnǰ̍h俫TnkiI9--J4\=٤ڮq݆ ]\RzXw+J\0֎&9L()^Ae;7kG"-:".eV7}$R6C̪cz.(@|0ez]%TÇ2/h jzXD56hJIwxz$ޥ%谊T$QIckOncxI+{hfryA 6j<ՠR%^KsY23QQ۫%(_-ܩb~G|R[>}lblQ<(! *H,K,$H^ "PlLSM8`P1'f(m ൵,=~*'/*G M{qb#4Yڠs1dlmrfh0PK t,:b{q1tz؁1~Yrz4;3 wC+cL';49c?8coV}ONU.w=E*>1@B+ zyyҔ,'dJVZXB4|+e-N-q4[R>V εg}QҪt>~O١´,{R= VlgS3ivۅl#2auBr7 Ѫz_st\,FOXb;Q\-ˈCY'7hBVG~? %lCgiAS#m(}ؤ>֚D5R}xj?,_?B%x}棨?́ HBs/gf5zOp?Kù¶.C1aָ(f]sN{ww j2,> @("3|ssi 'C46)A L& 1)Fwu@y쀈Rk4&5YX A'u\qNzr;!-K Uxh G5z/ЬR%j.3QE"NJAJoTI8jGAtWYawHA;m]-a\^yU g-f-b0 vbyt=P8يh ~)+m6dd 0KztH֥KDw-ȯTĻXihv4sP:-eh3)>U&!?Qpνȩ@uPC2UnS$8 +TPqF΃ɲ40|Mt}5nw`bTS.ގ&0$V R AAvf-b vĞA+˧R-7 & b $a ͗l!\XVXEDc)Vs ظ^q1مŮ w/"̭ s`86(|,yEtMhai ՜)D$,ߠG ?ӮL唇hM7b* ԟ]fD2|F2ZQnȓ Y1*':2H>Q&@9l&i#\qJn>6>JNrF2 z)Rr:\&: gbN6u$0%>_:(L"TeN m!/>i^Fo6fz1걯fAL,Un^W ;p1tsRCv&n2^=KqgfZnh`Z.>v/@F0^?w,l@\KVL5gFܧ!lLW$16bk"5]܌] 3H[{i&/Ka¦i)Ő$F?4nK4ȑM47Wkt_/ B^ͱwgQ@`# MPNe4VYaNkJA iOUHQ_.Qj ^U>#r0tobJ"Aɇ r 㑷3뿏"7G$CLIg5["`qJ+r?"_xʩ1[°25h0d#$pow),gDBI|$o"P&0kLYbƄ=bm{o7+ eDׁܶm~if3G!1R&@ŭ)!an%,ud< Ә ĺd}6 Jz7 35>fDP&;@f8Zn1_}W4!*D!Tcd535sq""斥x=-3_H`y!sR];jiޔl¾eMnJ<q((B ;83 Q^}?:#MX5u]/)EE0yF_G4"i/."co+}zFA׆w]#\?G,򽰕yޞ)X\Z(֮R%zu'*^ !/%{ʿhtĻay\i <~lӋFRfZư Yo /݌@w(~>AG q|A ;#^6i>v{[=ÃT@= i4ف?3oK +k|ErUjq<gMYgm2f0u&UF bǸ`0,aAUzf:Ͷ9NBЗenĸAi裄gcl0QJ)I=DeLN֣=@秖A.Am HlCo7mFTa xX6Ӏx< aE\Ehḩνokyެd;+x\>-6 9x1Zb2qDsb_'/1n91IXG"qKmZ C>wxo[ ӈ4gZǽCO2Ɵ-}2Tx:#Bۓ3zV2Z7Ulγs !)#i=It|ۧ=hyru5Yt w?1mHb?O7g'f2?U9}e=i#TF7\ԪsW9C$0Glڸ˹~*S"Х;ٿh>4&3i=oAi:W ao`+sMSA[fe@L.^LX y݂9c~w,әsgwCD5Q ,MdO쭶̫OM0>tR5"ZNq=Nn7De{!]gmް:m[=7q6?=cL~!@'[M̄]=]&y8~g/B[*| R-:OcBu#Mgl-I1HFU " :KWD:4B %^X\̂&BGFo1v'A4Rd,a[%DTl*7䭚"&>VJYkȭorN4%t 0)1Ge0PJ9iG~`Vw+N |esk%s7U!PoaRvIL}Pdeל++uÀUDe-XE!u3/vUQStNܾ *ЬR> ht,$S izl&,M5-WWY=jO]]؆_{cclDNRҭ^* lE*L9sΞM.c'\ީC m:3nB]ʽ`'+b*ߪvY_)IjA{c!aiy1œ$멛RX-BGl켵xuN]AS [KQ:Ka:?MPW.(.HF0q pD:r1@8Ͳ:I7\*PEe퍁q봐3D֮2{an._fSoU"G0@CU?z1"U̚[@mU g=ͮ%cnמ\V7B?rL`|"_nUiI"t˂>Lz|u!WŽ{1Aφm/a"Thmz4q2tYhZxbe,2>6S>Z3`\2?2Υ4#Y"Y_cdt2]*7g)=چYɊY0&ew=cp ˾l.{k,!YW),x6/%c]Q~Jt5sYvߒX vh@Mh25E ZXVPTcxb/}v<چu'؝61h;1Ydf{$[CEJΕ{88mT G9jM̶FxvN `g(=3֦(1׏\?| xEK -7Kظ*WqG4}T|۲x(J͎(;΃ ՛b\W O~94ZlVJtw}14X/Bu.'v [p>;5DL,!UȸQQ"p$[,LBBG\i$T~hXsD_wI6ieʎG/.Ku!bnrwkux'#u \u<'i񃇉-n߯so懞NMs! V3xgpdUxS߫Ǻy0enR"Q[skXJ(VFJvubL-$#&-%Qa#gAvH:86?%kcSlݭA-qZ^ٶ{8ށ]; YZ+ 2k4*2* B#ȸͻ ܈^FU֞JO9Rz%!r68AnMkm+W H&@hS pz*<7dge#(F_!Pd(~k?LF7x]}-U C ab{DO'n5%ڢȳ ":oZ}E&VF]R͔[*N)AGtIrM@95G"i H1p%b1/KK7Љ[H65b KPߩ㑅ZM^{Z.pXrU(O@ޑ@\g*bEjJ-و'FgܧEU$7KJ1!.+мD\^uZ^(  o,B4ԇg=aPUFcع|A'IbGEs7 H6mJ\D8BН8 y6Ӳ v}͔ }"ae/FGLuTtmԫk,kpjM̦f òxfc \c4Y;&D q:G ^L/ԊRĭ8S#@zf2cpKw]!|{۔_v*Mj_}Uם S~S(-/B',#RU6`;@fw?rjrCe8LR:N, ?eb=وϋ?CVMT/D=j@64k *MwBN pvO ʨvo+FG[1TG;"@ެU狂#bcߩu z]\כT[sсtN4?Śi\F ?.8QlLRħLRޯwn ;t'4PU8f 7KL,babJ1Uq1xE,-ܫK6k؏^z(zsqwQiڜ6[]^ [mTicizk htJ8XhllY?aP~v2HO/BF@h`#C5>Aثtq DELs`fVSx s Qc}Ϯĉ+jڶt8FN0l$|Us?f{lQ.VMj(~ȏ# 2ļ6O[٘Ҭ=oUʦ(m|R4LfNk[{ ~Tt@퓓򃦨 G$QC*YA\ofbIxO稸]~_TDk{,s?D&Gkn=poV'.!cA>Yp]Q4vZ-OR`ø$p̭/i==}M8{ה'/?-1~wie00c2L+נSDאxON'|>vqn p}n;QHMHhFǏNKO"ZKI 8Y7W󫼮#W")-W8g#&FABJJ~AA3IPP > ȩEe~K #1AFq)}$z ]͡,#yu-txLȜ}qUc>Wŏ 5mњxݪ~4Vf'sV[mh[0yf5G|G "ii7xG+RMPϺdͿ(OX, {ǘ"hjs5d376(4eG14W!)p3]OѾ9H":}:(=PMMi *EβSb^"ii*/\tT]zrdv؉A*UafoR _ CQ Eyꐁ;5̭{Z}S,btEudHLj/%E?vZx&oVDk Y=GSi'6=Oq׊ݾB'bbYY @XqF-Ⱦ<> {~0XrkT<^uDzN:"ݑ1Cs{}kAILr|E1 P~9DmR1rv czZa*[22fm#J׮ Xd-S@Ye~!Ҭcr.4G;PWJ(zt5!U'/:8JXSGu~:2vfWM4ai\^t4(^OF7/ s |L\` Ѩ~Y#%Rwq3 /#RˤkbX,+xAhDC/^]|A6ojR ai#BҬk}va^˱ŹaǖXYIThDfJAZUİ\_!'=RGL%R4y+!SW}_:^2z^%Nu?̘ 7 $zěR@xY`ٺ^t78)Ώ }.kWr3 A,$WOKCWhb1`LdEtC#SNa]gCBuLuM/ =s~/W"Sd Hʋ\2]E\MXche!Q^W~ʚ1U]"fI96[=/1"yR|/zBtC`}sԌ"N :O_G?4m=|c 2Iv<5O\x2'GQX"_wA9M+>WaˀZo&&} w l*"<=^78&?.S{lf=햏@ߖ'%VԔeٵ $Ko ԫs|(yN7#q)B`9RxM+D`Խ-vR(ZTܝl;trC6G}¡/x 'Xcx/JIi Dds~RT[&<&CMLڵ}JDbS`_1> IYy*SsV bg?aJOwS=T"wk7UO=s63w.FBIڿ/s›xP*z LnʼڅFU.FP^遚%ʹu} MU*vf<G,?OkK U?1DPEBYXP f?Pa'M=ʚ,qE\YIQB(2!N8ƟwM #u-qG%.>{Y:CԘǂM[؄f225o(>Cp! 'X:ݵʈ9{: yk ;v'_V9&zoi$HfWlя4d&G% dPuH?(ymjd{[ Q5J"m6%:[7{8 Yq0z<ܐVK#gV zAǽ`*p]i,4 #fWʧ?%9LcrG> UoQhng-f]NREW %,C$?k,IpcMP8 o)KM"H +{*M>H{{.*?kFR&~=[&/b`iq$&óm )i{Њ$ 7n"Nʪ8դEʩ"$2ck N"AC!c}z$s(װC'bD؇j> 2U3GJOyz!vV$ZIE9}cLyhyp\I XcK2jdoaq;cB٬=3i]:YmCٛՓ05k< qxN3&6.["uKmDMaz!͆4_l H24lMWɤI@qnhގ0Y{#4 R`7%w0DAgHj: eٰzml,>G 2jcYuց-M`?pp)1hP1-K/S?:ByPiX!ݛSh? OH%~g"oKxUUGjF~do(1^ ` cuW͇lp֭-bOj5hژ* Dtγ}vf.U3E]V܍ _ə 򑖬țvkNW`hZwKC0e ;Y`WTMQ6dQ,oH FB^Lk*µȯ7oet\\"O ܄-icay {%G.2B{zZ3'ʈfdEg;i쾷v=r{S52xڈ s[^#9@ 5J)sM,Ly޼[Tgm ܬ+  ^Rx[N) P>>z,{zQ|Ҭ1[-Rj8G*yopM"}A,ܸD'܇R[RV 1ZۅH'wZ:.4V τyD6r\M0A0Lb! :x%ir af8F"% C?UjǁYD8{57Pl=+-6`J+4[X󋿁?>gz4-= \޺ʽA${4I&aD3[}}~h?BZla3 jh\Y7ki3}6ʊ|p3~j:eıK i,A4nk:YT3O4i z> @dcb +3Vr1ôo-CY}=MGM,%s̔yI;i5wsiЗ/6ayP#Zc0gxaFn57ZtuXɄ$`1;8@}j~٬G4; +X>82$rD=W>GH_?yݞ>R8ǸᡀJ2i[=gn={$ wid>:ƠCQHk Zh-k,)޿Sq;[ NpI$C r4d}X.W1%sx#58Vm_nD/4{sˎ9z{s˩Zؘ|fwa͕buq`^/j[Ztaz$޷>14br$Y *?8W׊2x{2n3ѧ9PNXcK.S٪kF1&[# AӍW޿-wJ꩕gΕfG `<56#fiSJv3IGEx{;5+=SDÆF5='۝戻iE W9^7cY%#T:F TޗKg$'<4^6&3=k 6n{o(iNg  sJbQZ4C+9P]Sp$ oxō6LW^wsrPcj*;z GN3젗 fM>GhҲ2.J 9H9Ϋy:}3*eݷxbZں5&^7o1+QNMA)CAAɧmXLoZj\RgsW8iyskb[djX XʙVLj_]ه:yfD*L uЙ7@>^7UBo+Ne4 qid5Zhf=ׅ}LTJr7fI8gxKpc??4iq̡G/?mչpga}r_>-#Pz7sF 9v V@`oadC..0! sbR7ml*eK\2Ɵ-hLqh_&`cŻYk@DGg]k#S Ų1Ac_vrC7MPH""=x#7$ YA#5~= }1&(c6`-`zRL[? Ď=mT;F+BJ3ALjO0IXڢR'`TM)Y:5 IM!Ϲ<۶;.У[Yy3V7$ͳwX5&{de9dnX-' î.M{]崮֕KgݖS`,6qy:h)ԇƳh$u @Zl+n ȽC]Ax0 "]|M2Gf7t*38_?[|iH ]8f@TEb$`#v){K$Pu8pv⃡ĊxX}HT%)Ki؊)g9kl0-|S2UZ1xt0e *ye*b<@VߗD, *#Mؒs`ƽvoQTNx =mbei~dS MU50X3#3Rc b|ZmDi]HP,|l ϳ2G>u;_GuPT_jos?~W-Բ#sYJqC%BfOb0^`Wt?z˯oLI\ǜNX&k{_kFi)gQ^qdN0xnr`{?'>O=(:(6.I\wPK+FvPgBС.)3=z̚r2nnd}8qSߎ[Py7ky_!f5" u8!W#%Nu-3+4Љh) \!ۚ(TIp!% #s\5 IҜK/Y$W Ev\ǔIrf>_w9$Vyƚ^a!AlEK g>aQFlplmjYVcܯg2طEs %7`;9VF, AV(0@ڈCv8qzm]~dG53^"`VY4Ĝ66n|@?ߚ6uWڽ9G:M< C*({og'٤Shsv6ݿ\aT[9w& 2PXq&㣰 WwP kUzZDVp[v6k3G2B.qu'םHbSڠ4?ZvJ?^&OЮye6!M%\1\XOPqhNF2^Р F@8]}3K \wX4j15.}owdias~z-.:GB/E ǡC>!UDG7u[QZRG*EF]U4Fb`eu \r3MM!%_཈ =pn3ki/N,ѕG;Ef@K}z}‰vR5Kl@sVXJFT4җ )94#KP:`6$@|bAkang5CNPTXި^F iU8I. AM{4]h] ]& 69-^6Hpq Ct?;Tg@|/+hQ|,lQj |#64P7)[{|EGk"3?@?SqfpJBfD?)cNiN/-,G‹2 `P?5Z4̮؃'j=' :TICS835->ۯ/Z^sLGg 2^~y=ـN~lɕi?tDfkfT U1Q.r zpx}aroe맚3BDB!RD럵 6!ؕGX*Zbcf-N5I 9hJci/(UhEڑj4/ * @!*:J5,p~9xcWw" :\;&B7 DNj2 LD6A,'/9~ +9>ryM^=#fkRn>}Å@]-W,n]'daaBmG<2_[SY4_5:Z"ܯ T Ae%cwUŅ4D͏`?q`/꓋iV/c4?F~$=YR`*Op~l#Y8őɴWͥTU<`-%G0vʸFB[ȮeSP.h 3Q*,߫#Gyŵ>8gnQ!7f׮(ܜ9y0T̾=:qΗZX 5 +Gي$[d*&^dQo2H-:0FO ߘvί+~)w ؖz{b D$ eM|\$T}直Iu!7fj PFAG;0#k8Yبr) Yu;DH-$~9%'|[lRyb.F=(nsKEQ1ńp^~ $˟v<:J/ 0*OgIMx6kPF\kWy_K\SQ*z$;}PXYl}_Q mv|Vؤ/ΒF5">%9ϫWmji[0BqyU14tX!5l%Vy>AI;( +C~.|j 4@ !c`W41~q#FQ QO*ɼ>H[Ht*Ŀ4,gHa=9qԩk!6 ӣL/0͉$q՛-GMqga_7wL^v^?Fe(NktLŘ& @]NMD&I(0eqg2(jkKh |`=7)x~a љ[5"&^멬UǑyŷ%gdǔSwa,[2@ 1Cm"AĠ1+2hJ芆;u<_!c7EfpDgbĹRS?~ccj+=My8PlY\r/p.3~K;3X?m|rZ 11kBHk|qǾɴPvO4ilhMx\s=6gʥ&⴬:9jcjG5ٮNg}uފGۚh=`" pQF_pi/*( r7S!Wb08R[=v2~E_.Dר@r&1ߙ\#!pNYPJDCKҴaOJ1mbbŬEOpq۬ނMfn õ&ቑ ()Hr@TG(_1\Ef}uP[ϫZPt5!PЂE5n(Q!zR;CwD(5"GW7teƴq%]&|OU1Y1k9}R&H˲Mܐ2'8#h]*\e%QssJڤ\VVJn_D0Rl1WukY$FX!UN|f3_QW٢9MŅ.".p:6a`z.W!&_S @XEhr1ǣpnNP c#ezګTG4-{ў%*K*3D]rLؠឪ揢ۓ5#&yKHyob,= ^0?M; Knac VS-:+uPM:6UCcId~A d$4zuL&rWk`9Z6'F@Jrh.4> U־ChsE%2,8Ũ 􊔽띍|0iaM!eLf`/h=isqAu*\x*!iSnYJF(%g{J=mx]R uoBkp,6wHfG"&fX&kWs\S|RyxeVcj;+5Ro~NT^! Iإ)ՋAIx-+erut,r!GdZӃhaGӾ*{K0=?NT)*@?+*f)&0/I9;h-%T(+R$aF^􊑽6tʤ=ѡ8\GP"s.NI<{ (<, ZB%]dѣD>C,tZӏ>G  o8`ĢB~fY&Q [cI &7cG#H\Ŋ,GBPBZLz}sUo+vK!f ~:B"ʟlvBUa8:5ґ?h1S2%Uqec=,$斍 ǓjUVԳQVn1˙+(^BwBC S¹wmtA)<2 34v=L݋ڰ[}nÆ}Rw{;,0 41G^hr3Ae/^T"K4n> E ~a?|: xD9]bC?jױf4kpZ5hEHMc2f@/?ghHE+6"k'05[.u=5ro7KrbgBːOGrY7:jퟢA )G7:wX[) f7Ayһ46?ᕸ5V|9[(.ٮd`eZנfkO=H.l5~vz'UWQ4ɢTT2[Ṇ@j0C"$E z1%p>>B[ƃ3HM;ӯ2 ^,|K^ kG^aleCK_څvK stuF$ FVlWAAkce ?:ꥣфb0[t \YOT9i@W c֐"4)_ⅳ胙QϤhcGb[}5&p(TS(IV[!*{`_J+ :͞\_T<lD@ p&= =Rɡ Uym` o]GP O`9'?qE;r<0 l M4fL^"_mF ,5_зi3Ko:C?oc#d\WoC_N0eʣ8 |qD"A%dM{ ;ưO<-uQ vuCm6{ J6sdǵ^[ōAb}셗%S13'is|#1`Hl^aB6C5w@(b2#dxvA(r撪GRd,L_Q(J喎z (C6a1Oz,QrwNr!Y:\b{~9\+? u6<4)2!ܿ Ji&n#DB iFi\I+Wp`haL>`!uODmX,x۶LP5<T h{w𻶪 ح& ɡC_6vXюJbEM]•*RԦl);t#!29#C``6 D9 WWrm&z2<.ѽ$IN,!Ws6(b^lPb@A >sVoK!Q!`̈8!RRSvHhI{M b(=H&2m"VV,LոFcF'S8[(x?)c^Ntк|n74XyKDVؙ=s~Sq-gX?}@R\Hm^~q8jK pfx) Ip#죑,I)^ˀ7c{U\F+zLYxv}r27<@Gx<~V&VJjU}'0ۚC[F=8G?J`lf|lCc^#:÷a?WVoQiV#\E$r}87D\6Mda*[`T f+i^6[!8ަ-(2=]h;|것e]$,KbO$4y*;]Q{X]@>~2t!`).Wy؜Q"08#8S_R>ejP {^ijD||_",K1ߎݓAǭD8k/q+MtD!dbe.l:c?@Tc_9[IθeE"~DBXԍIO &۶23N2ifgpɪ~G0t\(Ұq"N8Q):+{蓆Lg*9"yJgTg*Ս7H[>a"Z2Ѻ~B /F1Mx^dҐ}h&{?A ⊢d^NW9U/,B)TcAz Ț5A{?ZLIC:$Z,4yl>`vta9;U`q(N%0Gk9ְ4Ww.^1PYLv.kxn#AZX[0x\ &Jmtt!S:)3Ne$~dɎuSҥ7Y\-1ǵF6.CQ`Vi'ZD!(JPVLpgWK@EVW.bU0lޫ!/Ym1xO ?a.rC͎z>w eX{ SЦK9eH:󘤏PQ*Iȇ7~D#Oo?+!)Bd!D;335T@mt|tM d(MfT`!4ye)T@BYϫ,9#VdB!r}/N+$ٌyZ)8I~gB5'i*M[公C>gw&x; q5r#*,lN[r:h$|'-ξuKmVܴ 7kdw]2ќ; 47P Rڭyz[Jt:QOZ~ĘDC4Ec0^*؏n`0֊:} ,UrOpq]HzUjY;cE. l>.@2U\ߓ`_ d-.KZ x,z<^H:#re֊,i00 FNAk%,_$"%S :=}(3|fz_åd#{бDF{;eU )QI3(=x dmFoy-I>o MT=F C!z{Ś ct"sևr0ʹF'4_ne\ۮG9&Y'mh w Mh ' z6:H\)y {K?\"rZ}ųl))aF4.*;_uoGx\ $o%@^}s50ל€x̫{m,"/u:Dkj0|Ln[\Ks6=YZ2,93ka;\$YO$MElF =xL}) ͖;/vűީAhb>1 4XTlζf=YDvk ?iw AS ^ṭS/' bهW%&?VQLueǥwzɩє?7&ڣC,2{.g_e\J+򩈬K%cz 23Kܭ<ATaUXbDxx.SN'|Ek%ZK|ﺉwWx#P/!6z[=6Dz aGP>)QN׳av-{x\Zpi2;'TyG2 1[n^A_o]]@)ߤd< vM'qd1DuC|과o"'0\AbS1--Ep@o [t"=rD8j:Gw]܉5sSLU& " ~51+y ]mӟdBl#3Ny@djH],x;ښPQ'2ΓjJ]j b  -| *Yumo:׵c(+ιц*+ɹìH2Ի4 z/k+3Tsϭ'gg2}pc.LuA^'cYi%鱇*a++8r./~/ '9'X'FcS QPj˻]8țs=iSt@6Wj m@\ӗN0_;&(,| t 2!1~aBD}?}4ѕo^v "{"Z.d79S"f*i^F_Cfr2 LA_aޤB楁Phް] O0l݂oM3uė[Bu3 hcO:Mh{N>ɻ/:ti0(%NB^UMe;.UW ]R9O:.&} } 41`:EaKG۷T@=Z=3׶ˈj~gCN1`Aǝ\a%0Dƾ|0 +\nG,oz*Y}@ygRSyުIdJthjNx XHC WffB$YHZ6EGwѯ5|54Y*HNذÀY:Fff0rLgm2k}dsR>:*kY#q >>3m54^u }7' ^NC!Hm91Սf4;gbf-RqZIXyDĵfz)%uYیZsL1>rjlpܸLBwv =Gc}4p4m5OWZBtۀcg@?QM0ؚ3ѹm|iT:ITﻳ9#u_AfW/ZLyj8`Uv47y`JcXy'c$o>.f@D@@hssW2gw{)t* ZJr n!$ooJ{&0RQ. nJ2MvՒ ޽ Zɡ۟4ZբDOQ?hGڄW+ɴF}eo'e9(sJ|iV&BPU@S*X 2>kT߽ \6[5(j&wb0kśf9.0?{K[W'7,y\Vw%)hו'N/ 4NSֺ-6#Ң]lz`2g L;K+[:TRܕ{\' rsb6_R6L)akx1*Ɇ vLWs. @BBԋv[ӱWSƙ4 WN긓r (av WFJtED$ ܽJseug/`5B|5V=# iߠ09Um 2XQ2~,`V.Ke*XLP<(l^vŹhk<Ϧ?Mk]Hċg63#SWꎌaH=jQ?*x~1mS)A/xL'E?WF_u.1֘lMl'6# krm +J*wNUޱC9uZ֧,ܯ4^ jܩL6Q}!$û! \c5hl``4!Zqܘ27#$⯣ ` -<@S!xߜтqLJ2` *TǴ@RYec)a."@ dp{FdsƲnxP_k!b`+>)WgX|1BnIZ3rX3X5zվtqHAHrT\Vc51SgH\i;!{iÐ+ &xۈcFT1=:4Jt D) blЇWY{wߜ>>J/U{uZxPYy MxoAG".xg4Lh(ʯ0?SR,H?!5]q}a&e %X B~ltG:}um*>595X5 PaKПs+Onԛіv{J=aP,H-mǩ30._+mR_s>xڄƏq o̟sGw3tircjIKgAD6CN*n®yBYA}C<(1,[ܾr.men:4fn"0EY譋́Vr !vT"ބA_ ϳzt0ܳ7fE㶨SKK?džFE#D1tyǧ"kaAaѝ_GTZhX=\OZ:W`ܭO_há<V X[)G&NIs(n3 HQpW'AisB ;}hV6*#ɖ'HhF,./j" <O,J e;x37,l9ۂ A){9 ǿB#5 }o׋>\ &VpdzJ$aZyPV$+nRg1\t(%Gwyb?(q|9qkvdXU~)~ L5j.O0'b(N,+Zg̯;dp͠?:9 \eΘw%t--*`eFf&R1"DkO M} RY 1iW\Cʓ~3w9w(r"pIZ{ YLb{M ^taɴ"-́帢+ő;{YG~8d<X5dP ZL< dQ9sLRg.bl.d²D>nk5|HE/Lȯva8ԉ]'W6o2OIY2ōp" T~vF6mNdZzrlV |yMGĹ8h$Qːzzg#ˠV#n<^)x 4L)P;ȞBK.=L魼{144U:?g=pN#hm)w SF%b 2 q ] K*!1X6AZ,)23+bwQ/*m&@7!+т0,>;ZRH2ދ.QPc*cۜܿlsПG "k:$:;%i~]i=:#Wv.3ʜ@ڏ_m e{]gᬜSO3!Ü6~`S$e_򋐈ptJ)،&xacSqrVY'9ZJuV|3L,Q&%G+* 8Q؟VYݾs!ʫ rjq+f8xbk͎)+k5謂F7,v:+.9+(Z >p>a?|\{J"Hq#*L\'?]H 0T4킽SG aI&4g9sbM8umsIr \i csKSE!ɋw+){"|2í3oC&(r,Ba=REF`KX$+s3 Dͩ[ms(<4. Q%)4uM,iXkKmx:8yWrޥPU0hC>Aި8CķT;/l"]P²Z1H9r!4l®1~3Vбa`]x)Zo;\1 sDړQMe{ 62͛/& )Hڴ( t$.a,o;M6x %UgFt~Ό*YJҷXxκگ11G(Kmb@9HY_2s"HdB2 VGKýRXCZr,=LZ:hl DnC>6V㐯7p뾵^ aojl_5#t~+FLI GvL{(b`$+c?9Ȓn,G~EjƵ$"l1pT%pBb/:0}qTG>_Nj}v6}Nn,87ŏz̤Tʓ ŋ쮺npj|4BLtqE[CTn[6׭)Fn[7s}3Kp2ّE+TZ8h8GFnY5IC}v_j3WoIbO';f+Rҍ:Fyw=c39䊇̑LpREaP|2 {]څ-o.C _e/=$Qq ~T-.HYZ' =R_{YbC}$e^ӹ E,wS)Ej>n)r&O>uN"cƯDKhHѬ ϗMG3ls}]#EW#dIڅHI j!\2&ҵNzV3@@Pa}PS(kJ|.seSf!_.Gh1 1 ߄v.DYX W* s:R]n|vguN8e,l?K':6Mcs18ʼ3gտ#A^iTC,h hW LJ8#'ːkNak3&WOzv%*Pġq.@T["m%? xJҶgۇŜx5[ʽ#=Qb3k%Y+[\[ D u#C<)q4/T.?4;5p犩J5wB<̽ڝA/NԡE*V-N\jV7t>&NIcZ\ 7s, Dx\gӡU~? "o)C@y8oSv1] =-G-[XG{)6ܖ z b<=\j̏Q5r66~sMr뜧vTWEs9̷h,V]q0 3֛$>*([Y.. ("ޕ&UN!E4A2Y808\lK&&p|.6L|S d܏ԫ&ln0ܱ LJEm+RUVޫaignBrwR0( m'9)Eυw~mN`RǙ$ m Bl&6RNt=mKOc^/|?Vi8xJ<h9]?GAHi1ıuxkv #Q*s"D6!i)Ȓp〷DM:80F3CZe<u!"M^==>cSC ijT)yQ Mʜ@Z2vTսq;haBv~qO81J!ܢ T@0i\.]]ZL0e#7'"}@Ϻ<@<\|ftV(f4>ZO4"z)ߐTf(R1Dd8.Yq CbTja&:0ʛ~.,UcFN2B$j J1 %A}˃j"9Gd2]2 tJqܕkv9[i=d"q4Wfh(( (:,|P\6"ԂJCz'uTݾ. hyqw4_T rpg>h|LYEL4frN %Dq{H=CQ2`I;DBql*oBsm2Ad3M&lRLĥ"ؤg`z2Fϔ}on|vU'ڰ{U<_ 6 @䊺@¸`c#=7, -}&@0~C9@m6p*5 -_M{bu ʄ񀣖AJZ:h^u\뎟X"k粜zQ\+<qIqMBaF~ʨcH<r$og+׉ƊTiN)oۡ8FJXާ ^uNNeHj1.鳺.X2rQgR'5 ѺӲnc"qFI)>kw㢅i Må4"^[VҌV/@@͘>A֦%A`YL0!t).YkhJ|-m$'AFH5Ƭ OyJIb; EoMȥ š!L2a; *j[},  Q[hGn0rՏ lI&'mlB.z;bb5dU~P@l#[I\dֿxs1s6'3~Xp`luV3aC=!g-3(wveWvv購J!O MD>g9%E ^-Yekq;}S>dmuR,zB&$Q l#(p2/S&$9ef{3n/&>'(ҫL'X`2W/Ө:ϮںWA'%/j8Pnfb@9W q}AlJ>ܵ4X}D@;!R_^GSL cm#ܺDFB1}l6pGF-f#C|uCZ9=j{@t܎pO)ͪ%\?w,jAC#Xtx@DRar-ܺ~lJ// ̶i{1\UY{+- e?5M2UCdz&xmVo j<8 *[mˤi݉`f^)L,J\R4#,5۫f8]P۞M !&S~4QFfl, S}q7H^JV3XUf?]7kV%#O08}L.JL8Y=e@H >-KO*]7M :a*ީ˖F{}PB/1WvH.@u#Q&,N9"Q]oc[-[ J+gmO9R= s HdMD~1aҊŢ` v?风:4]Ƹtzc1cd*85=qq7ͺL]!A i|dcj#XwH<"MWޖKjw8Q"K~BGxQƴyH'H ?Z`)A ^ONΪn^Kg!#ʈFLy ԰J OrbWV:ʯ QxSF}@OEMU8n:m9OK WfZ!7iwE k[ޙ/B/1buN+S_b4_u3o>'<Ue?_-ht}<]CTAzqHT㟷BP;/z0{ްRNMhb7lM7L֬|1)4J e$5:LPR $u}M.W;qcC|̮KR]k?x_9nQ]ӔYG n%~ilYw/ce=KdEWyd%t k{س~` aIIsZ| i96Hqc+,SH֫(wbIu _a 2J:Q@y7ս*F/Z\;]>NezUu|6E!Q])Mc3 6JFKg ЏS^Gn.P;!0IC(29B #ufn9kxOA9Y6Nuy}8|a=`Ks s)7fTTD@=j;Cb(c2u|c]Aբ$b`}w#d:( d@m$fɰ5!FpJB|Tkv{AG*;cs%–*<kT/3Q']: `.ҝcYRti ж`w@q#l)0GHuI@Ct/(}Ml~»c:-; %BYZCAїScN6uzKEɑ '^%y`)4HXUNo@7'(7˽p/`Njh&XٔJ  qb JͶ~*9TODrԥЕ!^9 kUVqsb۔G#XQZ=1 *X/Ӡv޼4 3R1Q:.J a*[8UJ2%&sAvop{'i. B{tw{2Zic$ߺ XeLo/j~qS &<@(TO $+~FrܕsB~tyvmb$uc¹PQzx̂|C=myaHl삑oцpىJ T>y2m*aÎSsd$mcqn]eb;CSUh uF[툾ٻ0 0E8mOInm~+Ȇ},%QBY o/1H8L 3 ox7Ϟr|YMjhFLb0 /ha%=KY-cE}F o! ?Vtv2Y CnUWP(/K:#-f?L빢Ar~GN«>eG<2}\Cd=+YZ$BL trӘBSS}-R VAp"`m(@qP2X%:hzK0map@TE񀽓7o4aD&[p ˄VC1*폻 Ew: aJןA=~uʚOoc}d S. F6tnJO;!x)D!5^52re=~ ! e#$dTXM|7¬A>FDLgVb#7Jgß@UFB'p He䰎lӱx&e<7D;S8{TlRPaw|) E6P!ZT!*;ꝛfiI-6ZHQ>֧iI+f@ӵx $-)%@T2\."rRxh-!Y: VBr%z/7|2(tiG ƪY06) ZUL;Fɔ~t:Grc#֤փЁ,>G F\ 78ګW=޲4j/v2^TQt&>[/L=Ė>04:)fɒ λ;.Qi=(: :>Ac뿳 "*tКX);R@%!K^GX:4sHu$ExNjԶ;aUڦHeIXsWsWu;QV`TRNvUM 1Efc.2 S͇ۨ='?.i  j:HH<#2,dѨ3QPKS:K((FhL.%d$[*;BFfXZkk3Sj'5LcD?倳$Pc #|bOePYe:D ^G5_Xha,x ׯ̂P<ٜofq9+h uwWCU@j(AE?nOOc\:ПGk^I#P?~IvFA /)czF`N|B@xxuAۉP`Nqs@(bf4 R9Pg$91{G oE_ͨ^G *W#g`\ ĒHCd@G zj mЯTv9~v$$_\AJDebw쌏)2V530KC'ҷ϶K؜L#z~ t|91(I 3ѫ`ǚq5Q/IBۙf)PCc.'n[n@na{ \cֿxup6rs{9ݜJ/]7UfhcM:kٳJ}u[_08ax&c=B~gt[|}sWa !ǪS#.Y1ЧUDFE喚F3 +(?ra2y3E;ȫAk9de,  - 2_+@&0΁)k?_ZQ\С}@+˒Gvo2",}w`ߺɗ]9vLJsZx _gFj&YU̡?!= _,딨eGRGLPO9/շJ:~Luk;}J[=N_xV\c'xfIg>A~s٥I'"Nv#f&Z@3=gݴWb^"o} };y?Ր快)B4\z J68mC퟉eMWfYD5jzMIU+:EzW< kJ7ZDPԇOf¤UɊ1P}UsR[p'u>Ng)5PAmP^Iir+p?i NҴq'$hHi]V/ >R9j X~JbY~ Eof~al}TW?1 #.&)g>g>'nGo~h kڍb!kzaPjD9rjDw'> lKlqj->@֋j-ZdQ3ޭdV )Q,Ha[97{p"E#L$ۍSi{blKIoI> 0<5WOzbn >|69@G`ii ^~S'S[PC V1 YXaPVj} 8,q饲1lVʵ,'dĝ-x/S2'EնXa^(`@ ]V $ =Jn^|u U1&j-z$5[c(L"Qxv6XDyn@ϕK^ exVs"J0g}.$}wYC_m5iND^nEK3Y˶Th,: ƣFaH'}yoߍn  p.b 0Fy{j??uՑ~}: ^!`"_czlr;|_QIN4b=^p2%ߚ .']G7DkFvVfu\R.A%< fΆ~IT& V"M}ta/]ߴ=S- 6wg;6Ԅ8-[ yP/;ϰ:%,_@4:63Q f&zZz=#' ʨ/= uAT㉑$[1M*7#rb/$] ]_,`;.Y_{J zMX ҕXf"7{ +VK׸՗JL.B/xE#փ;iD9Doƥ.uUEcj?pY=3z%[Qˆy8 "J xub{+ꂱfE_o4Ķ9As r:@"} ğneoz-y a^d La||`]EMȢag]xC}|1AMHXۜ墻R5nBaa+%ε&8pǩNn:%_k0F‘>phZc *]Csx|СN $hh&Ue? |&üE%2T19@"t6)q}!aJ8BMI%tPpi75V!wWP@p?}SXN8M@fHGᕲTdCM^O>(ce7i )w{?<+E[H3C'LF%AJ&h'D 3`f]KW|uRI\"ÆĂId6Rr5lNEwy="[`H._}̮Σوc.b&'% $4I=IOG4 C)#3hT\բa,X/u8-&JMX!--wCGXrCW>_h %B(S/ 1ϧ bБtGFO B/kw<*? wo,K# J'bR P̋DL''>2fRQ O8o!F@02R&*Lz"LС <"m`Z; YW/G~0ukOu2)9LW(Yt'p Ѽ,0߲̽Z%CN_>d7.d 9o%sl'~w w>/ M\$TGWD(AAcK1|tOf%RB1ɾ~ 0gowa( <@qg9`[ā@P@[}-QF4|-Ood3%C/\xB mNAlЫ"4oo(_[]s$~`) Dž6&R{=xU$+iQB]nyBjE-9Hvqvl;8ǰdZĭ:#2Njgj2enL+B+my'SE7lRNU(-J*C/[HgG򵇙_GXf1H"'X^^FN|m/֐7nT0s]LA.KA0 |*?讛ɉr]˞Ƥ̛.r+Tbj헗.aA;bWJ;C p$fb7Dv]YFS.HGޡ%z\S Q%_0w`7FfGN)h7/<1C:hvBx\$#dذ1Q i퉯0vEurxG-rK zހƫ\9%E~lQF{Ǟ{| KPMmoӋ;QUnB=๷̿}G3ł.v&A81֭CN%Evw T?{s3lmL=*QGZ?8[GTZ1g 8~S˞ :U-%Y⇔0JK@n:χz'z$cs`&F&UDrJgAn{[ΉEPauJpZ{O(X ߊUljt 2sD=yp<%־а]\EmM7}o9w*_(ۯ;^+\m{[.UژB΋@| 蚳lV1m~FBk'<(pX)wڴ6OoKtFM'ɥ gS|TŭɁXL㘱$fdt;J/N-u zϞ&z{Ae[IV_e?}q`>}$Z뼡s"[_ Qs>4أ$eQL{xRuG]k;zHD5YGxed 'Wogt-FJaZ?ȯ3$1hxOVTf^ej+4QgMP47_G7bRנjjVԳA0 Bܨ4}<Ӿ6zKOm0*hG1) ?_3"k)4z~b0k1(gX5*IRa dE rQ~s*R굆밙= >R#4>+;ͅ0ts̕W0ٶFZqr0ymێh>=3iFZHA,B8㩛蹔BxO&a AA/A-t;)o3$jxœC*0&a F>*ި}wDH63#G_r'gCͫ׫|<FSٸ! $t78` .!O s<}WVqn[b.XE)X';8T.bwҘ [kW47B;~zDeFKF~.l bad 2Bt1n#ڔ֕mwUF7!y]X>4Dz+m!v諪xl ؙoCAvfÿaG:7 =&bb- ƌFZ ּ0 [mE _QwzL WN'PyQ*sp{?+4czTm3wiѼMIeW g^ذBW{+ك,$]{E̮Ke89SrV1@M(K'f-v*RP[19s7DdBF ikH\_Gp0~:QNfdREC"ni} v ?%2ʀu$r>j&T71<T߉6Wj<ߏ9*biMH [DaIm5{)n"Xݭ슦us;X'qp;%Q{yNG HZ k-'9/z=ul)p 7X@TX:̂C}WK= t{"[489Ȃx2j7gϑۄ$q,B Av(ڡ1Q{?aEZ2DT4ZgƫɾLò1·kI7ϤX]I/.? ,$&m8RA'eF`VMMPt.Uy)(v>vu~v] Y)Bv,OQ-js9a@ 8'ѿl&|i% x)Qa@a mf}+.tӋr_:м-јD6P٨jYra,Qˋr`jG AeSEu(UmD7Ud|gu/Ґ+Gvn.Mmʽ4tn-Ueirٴ\<~H6Evx.4/f֌HiFou2xf'!]M>d.zyJŲ?׵9 v^RIOGqw%WЖN 7f4Zn¡CLU66RǡͲGXV3`p#tO=\_4@J"Zz%a2.W`u?wb=}ݠ@ Rig1>`H …s_NYU|O7MlfEDJ)/be߳&%1X!W@GZ"P[j2q-ҔM䵭z L ::AVO;Scٓ5<$)W:.dI".p!x諟7&adY+Me-Qcw6{+3 V_Rm=C6%dW7MXtET,;_`tR{XranQ~قpM oxێkNP.<()}RhIrˇ~TݖaQ~;6pgxtyu>Qw.[^cA]3W||0)!XD*) g;'J܌hZ{U"z4LxK<,In(2|0={m z[PF<3?J™dpe%[ Y؎|EƹyxP+ϖ {Qr/'y;3mu٫& ך}lT[)~c܁ ִPj,.0YQ]2hv/ׇ ,댁b䱋kx_*H+4;yQ<* ُ"15$X=#N"?W-;(vdމ=qr6ƠD{} cMWFa=/YSh#<!V{ MDXZfOׯQc?'3y1,ɰS6OF̪A7|j@fT5j&U{`^/8m w=9|gϯfpwTw~ϛ)c@LX؏c (%b;dcXc1))*SM:v_.Ҷ\m짦Cr[~oڮ'WuN5 Э_C=I t/;bk#3t,6gʁZ.!WuYS|̔f56Ϻ$sdh&AkҹgIӈ#”=\}k:Z*_$H-G .X%Է"OZP@i4PؠwBoi׹PЪFr=Z!FcdT{ *H^-E]缢a.cl/G;˯ޯk׏σIe uf_߽Ƙ.7>%w:j$ ?(6$o]ڋI DYW zO^wR;OjJA٤yrU`w*65B̵Xx2'k㇭Օ\>x $x l3J>AI(C0ʼ-( NL&zw3V]wEL5c(4C0x&ؗMq׍rd<]?޹QX:j`Ss*^yFRL;Hiy|ddQfD❹L, S9S":'DGZvvW/go<+(%%cqէfŠ#Ag,g;tp܊2w6/]p'8c[SjS@}Ԕn47zI:]xcI=F(TCZQ48X/5or'wB^&vs7Z2̇=_y}Hvo4P:[_D1ɦ d:Bqu<()%H9ìXȦ&tɹ%DXysdI˖VwwcZ$ p6RN+GMLk_a6]dWDp*NJYQԯJerT$CMϊw+p:s$ wE!9%VRKl|x:" 3A*;/[@FN#cʷ;^O5Axk̯^ZTq3/ 4TU7u\Eb]MTO<[ Зȣ)/4%-_2N32Iϑ5?& L$X\±]1 ^z۵)f1#1,+C +j{n,v d*'+TgbqUzyG D,=rRb{/'R|T7Xmj}2y0 m).|FUb0ٻ26LbB^WCiĥ /`?-FlÓ<븇ko߂jEjH0}òS$&#rP?׀t6 H6b c rK] G,2߳#Kw,7?0O 3 }&N灟#UךI'N}3y?^GwMB_$}≹Fzim Y, 2rm!+  /$r8=|,s`*F7uY"E s ^YJud$rroI1Ðb0 ~1X0[NyK!B*1o:KH}T]qd968Va?ojߝae. u*\ej3"Atde.>&A,xmLejC77\sT[5W[pVN ƺ,H8رB LD-Iaa^N& len@#r3 B y]AVf Å^[ jlR'kit"8ivc(jre6*k1QNJpGH"x,#5kS^Uߏw?C~1gHa eh޾,2!f0g4Q ܳCo/끽s:"F@KC'UeD01 p\,1_= +]]E}.9N_7GRm#5 ^'*6BӐix~!v¸VA>ԛf}.q`<\B\}`O(Lиᥞ.5"!aF+Rd)vff|hP7Hݟ&%(w}X;l419,MXuUÆF7Ś[︶(1E;ԧZDXjLkyV9guf G֨h_#RɧЋtp ·sf?y *ܵbQU @r0iR "?/Fcx'߸ګ7,t^quf!&'!ڤI(4q{p+ev9#L e/{Cjbɂ k3+?_oi抃am1QJeo _MlhU%)KFֶ 2H /f@?NL w5NϷY^M- |:I$1,q)KeذvJ0"㻥b.C[X^(K =Atc8χ5kֶtU?Lp$z2lLٮ{°VSb.t.r+4t.> bqKHhAwuT H:Ә/oL?4;עh}E-:|o;YhUT"4Xu6ʪ_[% 8޹>LYŕPoΆ+W0!%VY BΙj>҄`jCr0y~iD#RVʏRJ䙯p"r/߇M o͍hJkQA+Խ8\*CEt̿Oyyk~<5ȎbmZ?agz0 3>gC귋ⵠŒ^i mJU=)~g=GOp]z{ 1k[iFFBDm@ffPɚ X2d;]-~AtpӽA8uAdJAc&!Ύ}xTG}H`*fiV!ceKjӠ3/NjT~7/!D96f#N^6]sٹO)uf7O+lܽ-y:؂ĮI XzHrf Zɽ$},rnqԴ"yEj 5/v;qnT?4g5jKm@{OHM[ $"Pj;4^o{X?m} Rt 3P2Ž왁_2=RFC[ 9bkc>jqfWLM17 z.uRM$u%O# _p*_mYc*J,S:VbBdHy!ձglEbT|#Ux8RسAgdufcsfKh܇nS$fZ*AG"ۺz,n]JP. j7aX޵XvpF!`B$&M)Aέ!KFΔVTHurHF?fL~YVHtH h<M}aL^J|knhcuB}fK(fDꆘEg1⺏> 1fwEڨ^ݏ F@Ki4M7JN3, Tq%}N@ L9cD:{2OyyZQꫮ܂ \v7+BI%uQcQ?am{p,pX&}{1tCv|˂ h'5u'/؞P4.:[M(vԆ_Nď)l/#)K%"u,TH;#p/}ɨ Nͮ,^ <;hA9ǢP) OjԮc2c]C\3EE`<ϧK% x^ndqnsku`:uIdD1ǔdǨ %Ƕ~}L .C"Qu0b+jN 庨3#$ǺIMҬ?1ANsTGi~O7Z5iS|[U*Ah7}ZFiSOyC@p521zmƤī 7]W`̊,=S6g+JF++o*b!B?}lӉ8 ewKɧ 1[(Cݥi.;2|w ?i/[@?T-9b;=ўmf;RƓM* [pSI iqoc"Vg~~&*hEiSlQg_5Ac4ةfd /jPO*fT-ƿϱ*'&pue58-Q¶ ;U}_~q} |\M0ykߜۇ; CRu\p<J(Ј[{tGZa'7mg1Yqi*-@ԭZyTQ,& 9k Я^kGA2U脊-mJ>se+qOT/-Q8$T5t w&`%{-2}渚t=d7_=;`̻>!L\Kh!g6\? Gg{M 0|XJr(MԾ5 Pѭ{ $oڦsP//tKW9qiÄTc5CavLAj'x)Egʆ}qܷ{CچX]h|Đ:=|&.J6b~ӌ 4qagB,|۟rܑӬw>@@/AAE o|+87w?~{dD'Xڬ-Y㚁2Q}Idgi6`yDRR6NL)}2 y[\ 'Eyp LK9vZ5<@3rp~-' r+NsAM+TmrȅsP\Y=nGf&X>n gb՞$V*3t La{9H 2_4~9=E~1YHL"Ev]H,ljg1&cQq|3Ia6.uӱ Z"3Ww 7SWl#{ƈNH dP~Y-:T]fD^1Lfb)wO~_nL4vEjJ:c7k+h¡M8{r5"Fߕw>)\^N VT @&`w, ϔH8?nCgE4?2?Yh̿9&Œ%h S(Y/k]}h^~Wq;[.ʥſR|)I{2)4o}`wY' %\g0ňAD<Ji6LM} 5di4|)\'P 3]8E$z#ed{#~Ք!nc,[fptV5!"H6>\To =TzYVwO {`N|@7c0Ԡ|G?pzvBUjk+@[4dy[J#O)7&ʗM:[u 6v(dT g2#N|h =odܰWELfODudSeÖOnkLNZS1 $6x?,m<W+fM%)7IofFev/JU=YAsj£q()8X|D5 S6me㴝UHDY)pyލq_{Q<<4?Iႁ)g;SoۿА%4"ayq,-mkaZiEI }8/GQ#r['\ä)bв1oaF[>=+[{ рŃ_(I&0я \2mP"ҵ|^J؃uG#]m˨ذ^W8ɩG>|H $ ii=cL/ ?O~S8ik6{bĻfNB&|Rփd$p\ɝ_? 7>J@RYd@) -o{xӼ;/fUri׷\2PƦBUTug^4aEjgS,s Zq2 QY*h-(=Cp)6u+-O@Dȅ%Ml%#K_ɖ}x 6YP1J!B"GkmWSUSJLiGW >h=>c@Mm,xJDU gbM_Jͱ{ ]$MM|}\#r_Vx4g&̯ MI7ԄMGn?# u@tJ>f Gx Y^oau͞w#%Rk D ME`A?M. um51NVJNauNxr؈tOÎ)]Er"r)醙OQ>*"%zzcWMx\ץ`"RޯVnz@TK"NnaȦF{ ç6\lqEQv4emXz'm8@І+[k]m /{2IеX|hC4X|Qoowx)1}Å n+y xENKDm&A}\pҽع@8Vv@={`L cA-CSލdk^MX"~8gxM?'OCZdHu)5j~B;\rƬzӯZ z4ժDRKCg!ƞ)L4$w}ím(@n{-4Os*^\Kk}'"\"}OUsxf:\"lg9o6,Xޠn{*a Aj rE'u](\ހ]0 jְˋ[QJ[I!b]8 (3ͻ `9wȘSNO +A'Ϗ θX pqź{{^%>(څǎK"wLp#w^Xx:Z}.Ja5_?aՕ:J:ߓ{+2W.%kE+hqh Nb(K&[~pfW5.bB,.o!6X9N ּPsxƏzzSFٲP=O v)$9QW-GTTXLfuX-k]ANt곚ֈ)'QwZ-7绋?a>""}WS"WVo[4FQ~[I> fMdW3{Nz⵨% >IJʨ~'kUцU_=<Q>˙\d :qq&Љ۹JL5wi'vilMB+Jl~ЂѺ`JTS! thhs fR46vr*镀t1(Ň&3 9k2uÅ3S}kRD̉%tANĵ^2U%1d|0U\*PG $};(n4(-d y:,,wxU؉]b$wEø:~f$o\^],gjY'[Npύ_P!#HlZ63d7ytz\7_ܨZd_#ZnKFBӃэ~n砆9 )kO_˷!kV&?xQysft|X2x|BJ +Ⓔm% HP A({pmNQVw^N`j@F>s{^7ւ0\ |o3ͮ0Z6nVLwF|/ bP՘`O<.(?$G߂쾲^ ,CP^6j5DJd[kp[=!*_ z[ak%qJuW 0@ɟنO 1;صʋ7_P};9TH$8ժ:1C`G!ʙ#!A*(:^7]u)N9,c58 Ẅ́QzknzrjMUEz[~GόcʣᅞU 3eŃ X]S(%К"+ϱ:J \x0O>ia޽IPJL;l^C 8Is|օKW cOˍNf\7ck+4딞OH{GubPAS곹d҆,"Y};>w1`k8Bf.xԸhygLuק$/VN0P\ ]uX!w0&B0HV'#a c:`b5o(qHt'8ek۰!礶mﴔr(D(M'wfpD(tXFlhLzsloc=}ic,aG&RlA6VtWb;~R[V @^+mOȨj٩ %cTk~Ěw}yqx\<e`B0>M#{OtzY[ S}N~ ~\Q5ްȕJ-˕x 5~Cyœq6LֶZ`f̸z4>3[]+:(~S᠖PT|ʽf-[bZ JM~Cy !,r@>x"cp>=j1&mcXe&e;!vsdCa3EPg"[*(S W,G|M?w[3 w* $`DyO7jK'T6q9'"O()xdMZdv}Krc+u`*S.&fy0TM9#ig1e  4|}(gH=y歃{!L#Bx1=J"({0{~9{Qw'} JX&{ ]ϣEg}kY84N㓨VlϞ0|UYVN F$2M=`f`+j&Oe DM1kd+Zim8@hp?xF1@r؍;֡'?bOY~#E%zR}ghK 9E0 լXfUk?78wLZVgS9+٧yFto{K σ87#ε~bԜ(XYeI- Ƿ4 R|YvcNf2~Nr+M"N& ɎLٕطßsSV-2wN_-ϙSxpM?u3;GQ N9z:n;b7cyì^._>Vt=sSӬ*"t[]`-f" 8IB hiV- EJ.(VnD2R8L7zuᙅF>G^&Scd7e (˜ ?xDVzMYVM,K\7!|C;9}5 nvJ\ٙ11L]ZXࠏ"1 ˺dF:^g1yAcl>mt}7(% 4H Mi qzp_:qB$ۯq塁+5~B5 (eykKf'B&L$4A߆*؃tap\A._?lc9svÚIOG犱]K4}5m8&8olR?%|Ep߷f῎9|+ yA^;J$kuナWy][kƽl cI=F&#F2ɰ VfHk]\^} ̬Rp ^cV]L٪ԠgX=R:2չ-Q?"Vq=]Ooj99jEp]iͧ.auA<&i04 X32:ǚƬt"wUN ζ<K>,=k;cl!ur7T34yE f*lNhKnC#{fGM\ "*H}Ҹ41vɱŕwX<'s_=ϩ$l%!Up)o"N=OYi{ql0EUI4i)^!2J!?pmu5fz8E.~"uxlD,[xQL-  oͻ{*gg E`4(Z@)bR[Fc=NS|hXc;h2DL,$rdfvݯ`Q`ܠOMZ 8 M7G6gS,7Rߔ_U""?UשvT Dok6FTEOmvrEE6m64ˢ?5>$6}_oQ^V/Nw\oq>Tr^9|\\ .3deb0Y{nǦbɺ4/?/<ɠ>(dSJաDDa@LC7B ~Ednbaj BA2Rum3Dpݼ|bVAi6Q+&Qˉ.2k`p^'b,x8~1dZ"RoZ]iZPj*L6E5bud)i)vcv_do2֮sdVJLMEï:>풎ǡT⸤v{%?zT ׏d14d W"6ZD>QcWjɽu$ES"k@LLz%.+@*GX(Ū A=p:뤂']%O Z% ޶4uNh.C,0[ҵq9H'XlMq 5.)if.mW]&[4 Xyr'<F7;5 GqiV}"0^|-.AOB{οk(}fT(S:1هC(LP= Gew-pmR>0řڰӜx>r\A+)d3񤭱loŵA t K;`]|?$:sͨAHh.yl lCsؓS /\C NLf&2xcmy>3`ۖ,m?:%ʕ'YzJ7ʋ)*l*ag#;LHkmڥdt kcO\SU˛NK y ?Wк(v;1A=! ;ARԍr3,` k/CmzLYٖQ6HFdևLLѵ ֬㳆6U)nF0񿜜rPS9V1,i5:HܥdRUӓXy ="iMj˥cxg}yVhT)+ދZR`^datFܱxA.oTqGHwn E. qژVߑ6\ϔ<3TMȧPmpOjoߔX>,]^h|ics^ ,X / rIg{:\k3JzQsvGߑ>IX]Vw>a",PdYk"_2nS<vLA_u Z@,{ˢJdX+Y~U_\R]y`oq%Omtlh,dq5ZۍbK)cC ETƑ^NI_9ӺΉki31(lgs:uH\\6> ?>W,+^9Tn4§JqL}zng_r|s|1w@т5 wcC>ق=Y0ޜYIK`p-e?kz ?F }GMcn[Fۈ@B#g4-$7l:FZ#xBhզ`T-Wέ|?[Pҿşh&JRE}98/"iھ DՖ/)?bKi#?7Ĕus3ThR}^Z| ]"A-Y`9D?=ވc 2I1$CKOŋ\y?#uHl'BWq'9 N{;^t&U9B23 lcFݣ,|g&13YTyGJ|~V7o#]#$֫6"/RD3-DLpAL[h<9 ]%RiQ>O.>k%l9ɽ3o=7lY?J")6hd'z80b?z$sldgDo{0U<Lu Jt/턘;g*CE^ ݺUV/ _X]'l_4ϬeY$p^jvPx Z9yo\*4eκr^$ $\ $O:'I3V?-d]4LrlS$@t`%ۋ7,' ; 0KB'q%ٟ7om-O/[MhÍ:~h*g*/Us! +F,k^pV$|醘?7?1nP?ZeB(/C*\˚4PuF#is%dzW+y/HC0͇Kl8XË{)>]GFj1Y„Bk9f.RUxx ?3ܶ̒nLD (_wnGኔv)ZK=s0ɿ%V{`ZЕXe4ҜCC!F!K{šýG8HK nA@JHSYX% Ytt݆xhUdde"I;G?"lNX!)qY==@I LQ"Zev$CH Ow+L\F4b#:Rr{m@i+؎|5h ܀&@l!&$S>%ɮDDz*m˶%YME˪ ĥ?ϥW(*ޓo)%(Z>q;g|Z_G9cA)e%Eh͝ý 'C)w+Jp*e j[jzp,P3sEΨ _E@̥nP>i ŏ\ʉf'yLj^Ee^ $u 6D_3t9|*3b)ʫIS\D X^WHlrwq03n)un4ĢZd1嬖Q>+خiYJxA1K˵h/(\%Lc=>KARV곽JC(=huW7f Bz>!+ϣ"Af,jb JӉ ?`h*d/s0Wx;΀6ho;>nH-2PD2xh㙂}T¯cYvZ1PGLW*Vvp>ՌBA.tɠށOG IYy>DAaAI867 Lj6>}O)n/=uM{@ s?0gc.Wai@zSqcFnL`{-oRhv@W@p⠪' :m :PA0qS=D/ţu&q!8z4adjZDuPXW95"aɈ <L?ȯi*8 hj.A I3Rq-R!E("#O@ӱAmڸW[ e7NJ-OCx:?黇R_x1vL#>ÉP lc[ [-hQͲm=`CvU|Qq7ɹN6+,R@ 4\+w 0CDC] k# rCdFsGϞ)W5<·s\ WQCo2@= #G˔Ep;`hsnPW|)tETS奴Ș,1O/VR$Ci:hU40~ @)fC)v#\F4FS53AnX#,lpHpW4r.@,XO8ey5Ry;.=Td%ޤ(]8'yop{4"ѵnHX4mo#3o^  נ9pVEvc]cJrj^,tdFߖelHCo|@ B4-H u3ڸe^'xd ciʜ J&*^eĝ5&Gh%;6u vMSpdѷ2jlNsXu}\!=)rl;c;O]1m!LR ڇBgF!ջybg#OL@[[}( 5>ٖz޾:(+l0N t4`x]AQkiɊ>YSm2 Y nɫ=u-m `·ӖxPr\ԑCZuNMQ@ 7! ak~þ3Hn8B#aZrݘkݥ~zvo;dGBO#7әRro[8/{:ELt:us/x;7[6a,3? B^jY$ƒN*\|JGʉXq?n'z[aVE۲NtCI O֛\II;(o!XԤI+-QTnKμdwBZʼnzs^>T2M! 2 L]ګy+-lOnN/#ˮ@fэ0-#MftMB"켝1Fu-e,Y< HT!4{g*^;Q|V?~Wΐ.6!t>r}lAF))3&,K*:HQP'a% GțXѝuL6Ȫ @mۓIoVRsTIT'e(;o< h||1pbcuRly[q.Q 꽡jM +AS]Hs>UHxskVqUN}ꅺ FgTϳRSЀW\,s% (k:tdTVhNO3hjQʂ|hELzϹ<2'0lZ/TM@YpO+:Zw_3Da /F /ݣL)cm5kؿ?:u7Na~z=&\&ޜaZK0GW4bW ngBROi^뤭8\JB@k9x0n`2*@1 gqV$!!2'B$26;\Ȋg'AZk?c/TL$xB^;\ƃI T3Ep` Vuٳ!>65+ O pc["$$0kw.o$e _߾ܠd2R33׋6Osy/?fJF**dLCEnz259`+ _bH;|l6qUyhKS~HfOI-yǍrbvGɝtJiyXEͅ+ғx9PHn˽J=?yوK\!=wԉ+x `X?XXIP^ӈ?JlޗF-CZJӀ0Łb&C,zvv ."߭>]Y6HzduüiV nt~f&JVȰ.w^uC"Ѕu&>Ā1x.GjjI #tf@꣉L{UchL{*f)P%bqIQ _Ȃ>CXиs+@Bb59MUnyMLDaFOgY%R2H pBA Yz<-= gjd<SkUxe.[0⯯ǰ ˁsoo~&tt¤J}md`Hքi1{V%c+E$rlBr ȳ]BCv90ByfA<2_в0~DOl>]nD.U頻izN^Dֵfe6$ԥF>O}L85bÕLVҺ22rT }x)c?h6ݦ=mDF\(y ș&HLa632W ;cO̊V+3ԚJ\YJ8l)=@ec7Ìwʦm>~23>gv|=^C6Ӹa'f+^ѿQC}rO]-R%-?7s 6,O-r p"=VC'y0vB,?aܞkWnG'ϔ>O'OA#+bL3(1 .6  KCp_V1*V @ߊ׷aٱz5ITWmUk|C-vJC`Qz`+޷ @lPX.0 fx@V| !dn Np :2O|*V@ TU!ٻ/ d p$B̅_՜Ubu[CIߙ%Tm\f gSAGe^#5rMRHYp+~cO=7Mk rg-n=Gacŭ{8&`Ȳ+I(L<m*@8dsз$=iSG&O>4t :|#0ߝv]FMq:]oQDԵ =zb-Wϯpy[A5`d-jd2ȹ8/>u5>2?-K{G~іtFYt|T9olUKm{cpXŶ[%[DSuH0CkD"gW9Xl*gaޡ83ZmXfW\1u(tc+5B-IzmE n* Y]|DVԗT TcE˪afh'6YWо5y>TCe-_&|kjv>~R1vx8v^ʥv)Q1*Gc-^U Ufu18{Ac`&]oInOכV@i3lBvU"Qm"WK/<>5Dw/Ji1N"պ{@ƮoOVi$ ϧ:{oTPmxKNohf3y4hÛn/ l7TXl5>g}btQ!Żnb7rhH11;`}u<9PV#wՇ ׌S-h?U+Q8wU5p' KB&/`b)[ahckx/5vXU!M+ĩ99I3/R _~̪W=gfS_fLu8J_[r~x r6Gbn'$Fr%V*['_%(ڱ [54qn!c7R*sIu3fPLIvِJ|X\ |lpFu,x[+zG]BW*d';`#dS 1nFUU=<S(:*bϰK7j4xk3ҽS߭x#n}[7~5[-bBۓiOY3.9o|*fգIHH6~)qCLII!T sjʪ-$ĬVK3Pvmϥ.b0ñ8ujӿUrnn0|'VUSܶm,':FWJq*8C,)Btnia͡hO/s 3F2#i7ݎWCxi/.V2gPz[mOK4~߾Zq'wxGB: ZP^PerkHV' dZL[jg+{taEO29IL45Ğ0I/HZQ;=2ˡꎆ/ HM$YP_фHzf2Jh`Kv q1󳧲LKQӌwto_<>m}8\aduP<q-mh%4);).yEl_{| U[qx*շÕ4%V >n6qU}ǨUZT QN%kI}0B-"RQ&e;qٱ: Lz=(ͨqs;)+_runBӉ otEª>3IªHy &ywߤ*HO|: A÷-GsӞL /\!<.n&#p#7@)뛖a4fZ8w$u@_?6) +U22/ G~ nks^d!_pia^y}+yL>)?Xdc?CӚXN~}(<i}2J!ƊGuGQ&*},xӁ@bo:?4}GL7/c?# 1.q]( K=E}kZ5Сf)m-{0~6+*|}W,o_aA`qkikvi,ًͯmtIPT*rdZvE<-y>MV(i07ժ5ʥq \y1rriT`$cVu7+ZʶgT4wxlmHw ,IG6M n\IC\!~G>)4?UΩx[ӁƦ\qm׀ 9GW湿Rxnz&KlG12 &&GkBCWvgwJWhTo'ؔS;yh"HQR4O:΢y@Cl̻o\3"Hʺ3mdwkqR|n@a^ܦtq*/< ,r\WX &B=1ݧ#YXd0=;6fʌ?!+"t }Cq(ğ5G#e&32[RFB=J߫f/Us-nj~Q_~`CʷeLSOڂ4קA٭rdN_z-cqt}Z>;lc$ _GL'((LiVڭ Ā}0flB^?]W~00 Mȭn>SC#BVmxr1n}w7P|Fh=ՀlɈɍw|2HYpbӋۤJ̠;AqBw&a=3zL؞.V2,6Vޞ~WuV u6?%;2Qn>6f :n??ep|Μ/PS5J'cPv3P2B @}??RZq@IQ9cQlINF]va:a1Sӄ[=Y2b^)Bfw~ ;:־&=?q2b Qdt%ﲚ}(/!SN4ikCX2MEbiAD}[T*M%<68v?[)__f v2)h Upeu o=D5[p1j]atzcKK~:(sn|-Dk{$ h5L2Bde7I|S҅t1e rp" O̎'nΔHü ]!&5UB"䇊r~t+{*ЩSs0 ;憬,8&e[<*U"$O̳@p.7NYu;F{6 ;Wʄ5D!!{Bc'~ps V"%MU4`(#|XAϚL@IZMhA?w*wdi\F" a7nФ5v" D[YcܺQ7:Ov/GFJFjoџ sLm69 'P-CC8| ?D"ʷ"0[߃mm_ ,5`?7Ӓv\c< K,>B›e"KW Y!/XuTyv` _9ƾl{ٞ5L9 Dol4p\<6 Ff֦32[.oMQV/[kNFBthtNHoNϭ (M@pʛپ$]+Dk<[Ypu2ܰIGPƾ=3H}?ـye\M:Yi-PU!E܇KL /p Q$.8ϻT}j=׻mG̈́8v ѓ^+d4k%LVdĊPT M4= }W:G)Nx奌ÝdGpi0 蘲k :m;0N鎢vi*'kCAA8:(3T7l5Q"Pa=ރ:9ZBV# 8)vr1H&[uu@DghmnށmD5ȣk,Mq 6Y8M_FagUܻC҆H P0X 3嚍v~9Q䵹eފ0(h&bHS$>X+$,dG}o%8)lSU>KnWWkwj۩G8c"L.mt!6܎KR] D,:t f;Nu-H^1 h_sN%ڦ]/_|ĉ5X^QZʦ7T~ HY巷^J,|8Zbz[d`* <7 1 o-xeKsk0L)Vx* So ،ǡa%26x&'$:IɎv06q=8*Kd0+ٿT,mޗ2?VEffE W-rKQ`P#w8O*%+5#XD|͂&}㨿lpNH1IGѮٹ%M$:Sd8SF:4}C\`~FwsnAϙ1NvaM{ndrY8U+ƈR(0:qWwQo`vq; REP5^#F*g-$r?NSn_jd޶as؛BZqȏ Gǎ^d+%{ [Ysv|oHxxf{vE:Lxfhg*YW$&ʥ5X tCzvdjPP.=jՎ|D4אܕL:g^T0`z<лs;xmHꝌǜ=50%*? Q̊pɥDVgtbFRț)w=)DLz1%auXLZ鱶5$Hzd5y|GÌAdeŌ)͌$k(g~Vea >DR_@.>Jre)^Dq`>9γ<r7fxMnB סSZHʸ)H.j}.\ Ja &r!'dU ^c (nٝ?EEIDv}-lw7Z=!3Z`{/6R%su`VEgp6*GU}orC"mqpqOGp15J%DKL8!*&̍NV n M2K4A DFzqR0K\~%vZQT\僩Js=W Wh`.u)5=i2y0rx @:en/ʲЎ{`h[:ze-ӝwMfLFE.wiy$܆'̚84࿬}޴>k/TgJtb[e\jhvzy81`= 4͎ ,K` xm˅A2.T@|n9&xQiU=oN1O6UK+s驀x+\YP쬮f/*$d/W.܋9Xl_Y< ӍH=V!Nw9~߳)Eh99Ȋ8;HN~h^L\c7+ZHM䶄gի5@g1yvW_mF''Nxacb#ľ+0k@nVJLC$W< u7 *[SV?\"pt >`mL"fJAN kB^gDL}zΌDXX IްHo=rC)ӏfDu^Yy# dXMQŝw9ݼDf^=:hlp-Aˋ)S7Ytç$&27xЌy.ǫ};*K_i 'x{ 0nRbb30ӵ'i?ldؿX>eYc gL͒-ʀp1˲\JأW?饦4޳HuH Pc[hBRǵ0 KZӑ3~Pt&7`Ju$oKz-3/p:V6ُRү{Pb숏:fd2,nWWrB:kj.Q(,9kVC3!n(l:Ęޱi_rsKuJ9#0 \5$.K:Q:hZfd"3u ƄL#̢$Ъ`,QOqOv̓?[oĞ.&`Q3,t!_fF>hɪ?Lx0z!D'Ev1C60ֆ" q+")66=.6F3}(7~ߒ6,tρBv7“: {І _s\@ tH7pjЭQQiVpJ[mE-L/^Oq8|KTĸR/IP.1D5\켿 hE`aWת7=;bgژ0m x X+(VGHW;_aUu0xQF⥊(^r@pb}hQۙXJ1KH>@G?=*n\P:Fs/^P)":9'2ἔHtuky+BР==L3" zVI |/-;Xo}⁆,`R% ݏp*?RQ`)C];W9z Z&OtKb4詶Gcq]5d}H:h7{ ~~f^pp,Uw1 S&UY'@MXfTثj=criTkQ(r$Cv% mf(^f{\h#EOB!ɿ PPn6م~Kp.?cIšuQPI"!3c-Mw+oᜲRdE^婸~-O]o;8c7ݠJNE-~,M|׬qGzfUg3EwGr1 *G~eK0Dmø~kj% $]j7h* Q)vJ -A Kў\/x&בI^`e?NVI@26&9: vRCe_G)[\E_SpiVg3.4Yɏ<C#zޙkÏV?TԊ֓ܝ?ge_bs?~[IY)PFS: " Db@`/S)o0hˁtʽnK9;\*m6@ inEj>`'ÊM|N C,w@yOc]S4,꓂p /VMP>nPM8?8\< w% p=IAKZL_B>\Ǯ9 \ Fr)>'1C2>ISY&G{sgE-una/⿆-"K8s\wJIuLQ 4qW:i U1N62,g`e_] 9pTIuW,GGm8ex P|G-9O6Eu_{fJ^Lole2C)7k)ۅlIƎ{yR+!k:+ su1 zoqZ]vKnb@q6rlOFKGZ` 'bnsn#)UT H??GOH. ykb?q,ټy/,I4C,|<| e8+;9vMμ f-O[37~>te2XD( FJrGtz}8m^ EA8cOX3<ҙ(uMh-aH   3RQ;Nðّ?\pί=|"Yb4N=}%4!*% Я{hlH 1R6BvENA엤d^ƻO~Tb(!YE0W )?壟wQ~و<.tdoy._f?!p-EύiQܻ fg\ 6/O|rxZ7W6S h3gTI(\L^08Ԗ D WaҚ-Y$»ɠZRU2A쳘6/>?Dz8q 2~;>H6@OᦂH #VRfZ {@+)LEn_fTR0ObS aMW2`CR Q:k5Eo+@w[?gvPY$RU.Uh,ϟV(|QTV]P*72-Tĉ2LR:u&%h;(/|Wy# ? ;^]CR3p Br W~" eIBl{:~&9g¬3.o$}50%mb'Z bRS.0!cud%B҉ 9HmF{y'G;%k邖(Gsgqyo!i_@8m]GH}Gl]B'ty#p>=+ Ar 4SҘTz6ʵ*ڂ,S WP߷5S:=eW]k 7KEsXX*i|`3=3 S*D=bnᔷtK(WD ޼^֪;&/t|X:'%սIPEO鐛qI@0 1L;leq5}m8Iڦ0vФܼtUN}OxXq"K.= ;EBϓcOOLl`L. )8մ1({b$ lau}K 'dX0Z2^sf߻F;ڌ6ݯx&NQLI*D紲,F}꿺&gف/.~OPE004iHhNuqSQEz e2{/!t LG0LXҞxźʜS\oi /8yۗ;*B3Ca(5JdDۊ* x6`&,a1k_8&-I_R稓p ŽOa=IQŰMzyE~JV}8hұ)#J̏v?BVF9Fڜ&&W'&e}YuRhtad[mz35\$_nr'{&#u ]Ԩ,*\ k3/s6 x~<`ImH^-s3,8-bm/yO$}KHёжQOY'KbUD(' 乱ؠ>80esO·պQs%91YЉD*Z9~( XsXʿIJ顾&z\GymqhlMnVON98~dd`C>1g,廎qp]'2leE=WadX0i\q}EQQ:ѥnͣ zG矿2nPgf^IX001FtJҰ+wyol/W^VM\%+VwVnOBߞFIos"<>OP˨/ڈJL{X$F\Sg"E_o6Br )bf af7+Bx F8w9F8dPmaUƞIu&qChG8Pwٲcxq"l3t[V˗ vϬ<[;tU[0"]Yctm6X *BaK][}ܬ;a' µP 2dc2>40LqchoPP6'/E%"#_Ex9m=5xdR.T̆T0 IT,ၜ3˹d^}or/9ʚg[1z"hOS4 >"j H:9sܢ{{{?Nvk6?m[PkαtS6/Z*9q7Կ!8P 2d!a#]$Pߴ'EmцI)'s$@Nc_&I aW~dz%

k5c%]@AfsIF+<ꇶ۵ev:5jA^5ގd 0CMP9@F OZzsqZ<$VmECӦFsD"cwtbI8WEЪٰb0-7rirP!䆧jK"HAs.c}Q3c|'!,wgNrfGh|#Y U GGGD=aD * DCzcKи}?&1bP2R֪P`/g,ݲbgIg]&mn'u$g0 WYśGk(yO_x]?;K4kudڀDJ'EP_പOֺ}uԢȓzi3(qz޳dJAvq3'[^pdMb_S- ,reYBZR85Aii K)!Ωw.@'Ҙٻ0[ 1f9\b˝oG̅bKEG}L[,䗈3nid0hW[T_ċN WKZxHXXĘ^m?sXo8@(fiP:A [Jj@ym=kY洶hRfP IcD-M!s+ :m:{к/m >%HoWRE=2nhG%%T(@y7yPTUkV%YKoV,=ohCwJe5Q )f{uT,Izbj;% ƙqZ&_?j׀H35!5҈q 8aB8؞~1$ {꤆3s{SB^&suxn/%g!HKƘ­<ð/\V7h7]J/0C$Z$M5а3 ˻#&^ƛ;*:mZf|g|YTfQ$$.mr3\ Vl3!K|zMK]U6ЯA ,h](L]0^t(Ay4ki}yv^]#s{ib鍵u Ht O2* ;#1LJ -k&ů\,)0rO 1Hdz-Fި_[ȖIW{>Ean{ F2^ ䷛ ׯF`GCI fȝ_@EOo"fضf (f!z g!F%22!g5&rmVߥUe _u@Ƶ\^|^ǿKec`~s%ѭD= e @U6 ȏoi,Mik&*r&%,Gri/uO)^cL[at6<0ʇK\~L^In8=vHn{!~~GG/•Zh`@Y h`XI*vh(U9u[d,GkH#3myKo2v%# ,/*dD-פ4}Y{ U 4Kzv7?U=rLUw,Y6(LXgr?J]ҩ]& 3Zp᣼n%pG1|d{wy@U$XVVF1Sk/[o0Oa@݆ǎ O=MWfѻ*Pz ]HS{1m#hGέEEAuF'*?0^cZZjusl&QC`z[[WOj.g7a$*l`9 [OG[`~ͤ% )d sbƛU{ M?CgˆezEBBZa#;/hZ> /BϔןUĞd4u|;.{@fd8;UT걷jT܊"dwf8!8KNKAs1n 0ـ2#g@/tB-IPRk/4h5mָ[P$$T*AxbZ'豙*;Tub&*YSO $ۣ,Y)I /m}!mmG/jK}rY_O|6WUw. 2Ydnr;ݩV0/|bn{qRv}u,;u.eW{7.'ѕJﯡ! Wda&XKyC #N!]bwP7Y_/7Iov)&].1~L0wMiMP֡ /#C${e)a{?̘\>qg>mFv U΁-U@ֈ0,=$6O3@n3pd6bbiw!,Csz$>#Aڄ'4C.&k/+ 4_Ze*Bs:x^x$Rr?xܽjT>pZ`s{=pѬ]%ËI]8 7o?R-%oBhG4гFXſyv ᠸ'5i 7Jq4RRKd{>dsFc`NjuY(kn:@}8nj}^~mӺ8Ib xVaiU$elJHz~T9BVS5]bi-.'ji]Hvru[ޖK̻ v&MWoL7; ^VB<鳈9h$~`7ٚ=o8B!1p`Mҧ.MۄK;cVb(S8YF'3{ѤO\݉gB %ɩ>_rPԅFy5of)(?ɷ b*,<ң@A(zѨgMO-K1 ~[jNJݵ,fU)/u$I{ X5f.oaQ!.)lE\NA8_EٞNdr59:4*lJOBT hNT5/쪱2\ t^L1;/rG:2*|TZІ2 2wł}q\z5C]χ<7ta"DQySLBZ2?_ thx:A5 gİe oxCr#|^W'\AՔ2=ǔU+ 1Pp"&r({8\ iR Ig@ hXrHT0ro?[3$"Cn4='7~ԷWnw~d6Rj =gnQzR\UV֮&BupdU:9}@O{?/M68Oxɦzwm: R6c猷/K@R>1n$]&{y(k_ͼč{L - ~ֆQz@Vf:ZrG9@cz#"WIta]  CAuJ~dž1)܎t;1ɫ/&*0']?mj!‘-{0(7v,]/ɫꍺl:A,ў 0Sgj `R 3Up<`Ép *]Ͷ:=fˑLQOp?L4B>a]SyX1<-f4:Dd5=PqoS(yfq2GQq>̨-&R!f>P􆣔L%"~9#e̡v,X]e&4g 0pQ[ը?ց}))޻&u=.vl 0HVmue >K*Y V8ctvE1 apNpKcKg_Xc2hg2oG_C`>lHju󇞁|k~A5b;%y9OiGܙ)XtUXk $][j:ꁱ =uZlx]Ճ_ scLK h(B.k}8/܀[900Q3'?A+){BB<HmZtR Sy吊jS.\s-8Ga9^Cz+{\J642'veZ: qe=H W;13 'qGqk-'ͰŃ'-:ьs:=G^sejp S`)*R031=w7y.'Pw}~17`~VZoh8Mݼ@>)c-Ac`Ad/$V.I6:*CɹժRi% JL=ؘ![YZ^5wIZڢ?z`nLX2f35lEץb"s)(jfE'Dm\l-ۆf1\ %^/ 'P*t&:Ŏ)j˿߷Q, =a 8^-`Y0BZ@p54D k8h<Zt*C+Qܲf{=ۑ0D8I3P?i_gcޚta/:_W36},oo݊|Nמm};c$N`CrE7F:'(ɵ5(:&!X˫US}*Tg}ZDu܏}* Q-⹱&1rY9.1oC68YtS4ٽXID|ѷ/y0ORV[=~Ae[yi^aWwn K.ZHa QK)Ok Ģ&yJӌ(>_ձ$jܵZ{;LX _ e#18`qzj#ƕ@DNCuVf:!om,>,)N|pֿaS\L uW^ʺ7FNb\pc?oNH0px%{_8 _=x= 8I i;ܫ!sHL[d@eoAJ=y"a 4^q]:B2_? oC70=y.oi}֗VWrjem50Bx}1@o. .\lUω:=E }BA2bqc̿o!KRY}?U` %!6$;w˕3=>=h$#2: љB^ g\ajG%-Ӄ1 K6gV^zc?i˼aX+q^Ze<1,4@3tQm& ;frO~ſCCa8(򅋓ya+Ջo8AbC_zŽsM7T]Z1 /*3z$D( ]6p|$[xaXqiqT2x6. hVH9I7) |j,)o3: +ON>dעo5Z6ی[|4,L=y4ß[)cJˁ.{Ũڙ}eNVdmI{DWiz{KdIуof^6QCԡN !K]9ydͿ:v(- ) !nvx0:tɃEfY*ç%\r`/8D<|OU%"qؑ+2oZ]v2pHbaK,2C!c }8 (@woG܇7YWx !SV/ fL#!ՑRƿS ~,Fİq׊.${jWG>e6A3N57 :2Jt@ u= SlcH4W.CWn*^gWZwZp+DۣT!W?7XEg"`2YS7znc.X" 21"| &!f87{ڹ~X0'JBn^D[L%ՃCtMl JGe|$1D}&J1I>h9Pms\TF?+.[7qZ/9<,P[$[8݆O1d@~EMr<z*'ÉFh# ^k(s,.Q?1 6y4c+F 25sYO. L{= sVlR.t fGm_cvexm3z PwG 5dY4orMtN5t#M*/k:Vg/TD<@6 +\Ы4^losAIyP-4e3d"UT6i7;5ہ]eMD>H{7g۬G^/TX!&e&A;@ծ:K?5,)jFQ,f}%h_Σu "ݞ]rZp9/[ǃx5 M$m2;`.8Cd{&$@^|E)+T. heIb~'^7c,ei0k-/imaE4>3T#2z|ZZ8tKf H @`4%ڬy^ݸ([ YCS$΀mq2ٽ%[,ȹ۰.da9ywթzB WIfi8}F`;?YHP lwIS>b)Ȑ_<==еtjQdchdUtٔhܫ^O^hYr<̢$bh(K(> :s8˿NJkҤJJvU ,ú0+3AIiQ߉6ȡa NY>8d%WɃC:d/qCa  }RG{'K˫`W⸩2_d긷voۚrd°[`CjLPm .ܴqQCAbbcD0Ċ1gȹ*T~i B dh wK  $f| fE[@-BX>EPB2 |l:_Nq𫘝ߣ~"py%?(ݯ=NEe51:]I)f / OpK(Krjsb%?KNl!8(&f~%9hr?5ӱIfPK t>EPo.ްw|i-j7$]6BEsI/=Q\'H?qOl6L=1 }]5#6~W{A/ҏ6&sF %4O|9P fS?-_Cq \I/g߄Z\ T/:ג\̠ s<>?XlX[z\$ nXCM1zS1x%@k7u_6 kVU/f}!+6nw*}"SYIhv/2\'#'po/MC;7JxȺx 1[$ \AQ0`{dEffI [F [Dx39p_$ S>ЌFwwoV=HnZ-d7z ^{WSHE2`*#FyQR ^w#l=_[7 l4J\6?Ow|0"kŏ0 %%yτYEtʠKјp.Q+AW&!Y[>{z>ݢR xzbk>H&40u-dKdt 5-f࿵2 ܥk.Ǒ BuOUOEʵT(dK!]C1'9ir;]t3 U;M]W[gihiN8ZCe#͍EJ7]o RW ˡ1j.NhMcL9O ,&I%p`QL>aIi_l]Aj&[OpoE9M"7HXl1k%4/0hWdcY)*MazFJ8s; I Y{8Uf6o8b]B3imQ+ :x=YFp>$c1 rlDj ()`EhE;<DS4ܫӟzU" Yz\b(:vn2~PH) yяhH-C/ +$,=\ֳc2]{kzZ+,{wU}ߔ!cE2E`E yї1F#EP^J6(- + =&̨Xdd#l+Q^aޣfNRW֚O+`zjHb3ޜۃ(}Ή<$;cluha$tŢ 5] Nئ v< dťKNvHK՛/p5saEFԢu -v} )"L?!v)ʲ!<=L 1Ydkq2Ѣi%sH0^, 0U;3naBs@@ @t2}5 i̺ԯ| ҩ8B I nrJ|=AbB:Z8ߌ4أl`gڭѾ\dsDZiU{޳QmȌ*9 a5`3,Fv P]-A [fyW17 7!f oU1p떣` F[L0]y17 2S#iEH\?+Xp2{H'&du <Ⱦ`^Zmq 2"u"d(nP4aSa~W &Ab`ehjcU!֟K͝`#pLMMCJni=j8&ύūQYwumyqwYqD$0}iU w Yl[Yi1L[}x=؄4Y=3²M}̷kB;<^=gvٍx *]2~hrrZУ(,>zKY']~)ܽs ?O/.^߼_NĂ^r ֌_sӯz=5=X˩PXER'Y`#tM$ &(Kzn#.%N`Sl?=, |_wהI9_ N4d`5XHiV_>t(UDڀs$UBЪ,rQn/T,YTdF_b| '>#Pv,'3SkoF ޜ*tdzܧ:;iNMH57xuvJnEm~39Ei!ȝǙ7NiI;̐^8ִS,8ZU S+&%O I}q5¶ɵxE');êlVFc3abLݴ<~|H/ n/ԣ 9;$+u~d9 Z;!R`p;Jrj,cof4\KceY9UgLR]r]T5ށoo:ܻ $^1F^@m!=ƅo>ɼs:k>#wavx WYe=W [{Cri!uc_kM2T7S"$F!̢^8 #㙅O 6. }"+fyoM3^B INMo8 ǰ􈿤e{d(UWVvW!q1} [ԐC6 aHWw_ M_D>I9Z0O}tYiWy({qOfCTo_=VXEzKݠAWV5aRo )I0N2 f%Yַl$tE<ӿA/7 ^wZ8@+B52{])もctsT'o޷5K[ԖE[DQ¿9,SF#sSAtK([dDg{o?1R):<'L"7|[Ȗ*pm)>0C ԰nE ZVwTStbKlE,!v$ 9Ԯsibͦ$(2(e9DmFyN!YS 1!l.e4fھ9nOIF"9a]XґG$*ں:e ިbq_b-wdI :D9JZER'Ģ;?mݯSwU~k$7?:OB( Nw{U'5JMLrrk#g=HG}-cthe "5uOEo!H)9cĹ16cnlj VmGyyP^|6& cyHLzDg$ SdݨtJBqP 9B{P'l{^1{eq}0,BX‡A/~fHY'vgM ƞꁻ`Q;zIqYPvVRBOrk+ZDV‹znK<)Ibz/MVd:r-7ZL(B9ƊTųC04NfxkH6H>h˶} |@F/_5nc1k)R8 Nt |] -~8A.DΞR1|"ΔBzT#bva 81<=֔ !E4>/MzɈIG*aω`i8}7rN`a㓘g@b@p\j5N!ZOVmw!|{@B Sm; \Mаb;8AlR+<(9=1;Gs7z]yAzc^^*ᠻT75k Y}ۢ2h? e8ޗYΥ'"E6d"1[S@,-5z`Iެ&XUo^RO{eH ij' FCoΨ x$z;Vmy%ˉS$Sf[Ьh[hE7%VǹZB\qXR ='Y*`XnREF,*!歹=KOsn{Ni $P[ju9tB%v'Z'S&^Q2aĶ*cw]%2-AIM-[YHt@ݣPF\wKsF܌*!&6+]s8wˠ|u,ߖ/.ցl @a:>^HDž. n5 k u_R*`0nMyY9\5.81ӆw.Z_h_ Xob?E5' G|Z#KŤ0ȒK8|t s&h MNI OuXvWw٫?\.#o# ?8@^gHR⺃fP hBoX;f+z3H,`|"޺lJNw.SS#ҩ-2y_N.Oɹ]]h;'7!!@ * 3QjsO㯧r!8r3*~l%2~~G_V N-H̙ڽ=Dkw4IOSp|35LmeiNwC4Uy".gg,v1l,3:귔bI}xFW5(G#ŐufNuɩ63?[f 34Q.Y5Dx`d4͹ž=m T*NfN[1A\iIDi323UOH76q0 DE\_k?Rw6GJә5as޿v[0!is\_&?BjxFu[Bރ#bwzb~$V%iEO<ad_N!s@K*.0?U& v _^Z(h40ShB!A#XT 1x1!M'a ǥ: &h#k%R{KJP‹Ǖs UGK'H]]wX氁- d"k3cY%4x )C$w c;vXùR+u3h>r5BܒŲ{,)`(퇱4/ 87&wSw=*,[΃uK2/2~ Ayx?y"5qׁX ZooacYn=V3mqnd*̵Kr0 %xÐ ߭*ܕν/3ԃz:-7 |Z7 )Al)agnYLSyҰ3|/;LTQ(#>m,$kY61ϞfsX#::a­l*`>" Q$Нy7<%Q&$7+sU ȒF2+ŷ 0xv}O3ɂycç"׀ߦ'r'uy7r|_thKg,ty1~+ 8"do+޽疰UьM/- `n Ռ3V^ qTE2{:K<$()?Naj;G*P?QF/ftVO&۽mYTTbGƓxNh{LpJԩeA%ʂf.fx H.n( sumɭ҃}q9dLn@jȒ8t?Hؽ/DәlU&!I@5yd1$#Q(/8|7Y0V ots'CV,NH҉tC lwO5We 0sDv (::e]{na:e^ )} d zs8!%lJpIjrՍd@Snb ;)zHW{{?1j( !pBa! rЧ׃VSˁ1EbQE֊E6`4M-97@·.m.e8J1qV!⇛OMwgoRYjgB1|XWZ GK@g☩;̝,T2zZN7%2eSG/m"kn*w(@ctkWT)߃-pcNPv"<(/NӫnXwѯc=s~J/p2G=ہ/.uĵ'2g眫9J(@}$WT(iƩ<},WAJ[ho_eiΟGCK_}{~J5})(ߟƎhgϣ:IШZ6\ oO^_'x>gXІNb4En8JuSA29BPJX*zgCq P`+@Fؼ}TB/`״avb{]riuոX^餇' RPf\8^9k܀\%%T.!ܙ| )KR:'G\w9(2۳V/4Jl ?T=k_6y*L/ȃ:aCCY-F&2:wKt=$ETXZ.2⎔ϛ i$c J^'O3` ^,0ۓ&lWe*plgVG3lKp-;hIzD8ۥ*`'eT G2!%6} ?l$}zEqjn%CDzkЫ8@,'㇕WRlDLkHd%v1!>cY67]kXx?(JGDҐou1zCQN'\=c歒Fҧ],ƣw(`}YZ~b$iŮ[Xw)qWy%8QҲχ&;qd̕|\su)s E]jj}XӮtWzW|AP)%6\.LzOdž&I"XpS:.Pᆏ\VOKL=@+7s|š+[:[M8#0ǐ}  pgybmLN[ZԽ x5vKx , 5kVܻ5N}PR{o7#'B'|1^n`<;+WGyat`Y^Чi]E> ~yU7 )׋vŮa!!!jd_hW=.%LˏEm,EDΦ. 4Sq$^[!X B x5$^4f696gD~[wB/"tdJઉQ\I ѣZ-<~>Oԛdq7ٖ,6siF\?=L/Yls.`c. *n#fg{۰IîkC Sm Q."m Ĕ i1!WDPLۢ`+`?13q*bx;|s&-%3 y$LGk\%e?wAż,+^'=ϥhf~i8Y5i%FR;+f'?l,kݩ]︌ 1taNBL_=Қ9%p_ !\M&+]-_-g5ꎞb_/KCz 'Ɋ#&-n 3Į %o@ 4[mC@Q8UT5j*f[YpTfif0bP0;9FZdZz/{"|CxrwܡMt4aVO <+ԃ7-̕re]e(?/T&1$]ѷxRُYЋ5 v@  , N+&ᯫIt۞TjqeUapekx}L3Q>^lkߴit)pf mؠזraIT53 aK{{%6Y^_l ӕbw5EM鏲 .]PQt.W)ĥdu/KٹnhH'{ŹƔ˴܅+tQWiRRxKo'Y68Qh;=F{;{5#7~ QW93kFf)iN'gdY+r׭f[:'K64GUdTmZc>_~j3 cvL䁎(>ȈEԽup=w?6.@;5L=p=o|rL-lТ7@=KETPnvy2Yi/ fizG'xxSF魰Ŕpn0KR[˾>jD%LN+nf&1M}g'dʁ\ F9<? `L1< fjۘ} aXu%P 37L$Irdy0 P0=׭Y/vs0fdQzhogD7pP>Fh,vSG HBwgsL…'Fyw?ؾb[*a'WCɤpIu.R<׶qnha[TϽ7vޥhOR\28BRBFicZ`#-m\ڔ)i,Uc _vݾ(.[- Gj{/%vӿhxuZ>ok}-PC^C_y,w MW,uIِ Na!枖I@cUnǫ%Vyʅ3=Ck9%n {ŌG!^zƣN^)|HBk&#W}0xaJ)B/{fuzM CiEC?,3x}"+^syG2{\HԶ!goU?*MYt?P. 6K~KLMcMZ$=jm]ƻeAʶ8Fy#6ꍑ]tFZi"hxe\ )wG|h"`yWXc^ӑjEa7[׍ E 0^[6R|YnM%_$9cj X]tQjE(X[wOBY@.(gb'\3ze7|RLtx4bMOYwH4 (W"nTDT2n(~%cJwBƭL D{ <`4ʧAfc[?j9 lk[eb%:"(X[ ׮q"MHrﻎO'1h~g&"~[Dbڑ`@BXodtW_pe\cn?>$ʤBz -~,VtYM۾%96fI9%E".ygubiKV @`ފL_S <*2wW ։S=EK׀v0gقkYr?Q4Ǜ !_TpgtYYKk5atԃ>F)~]N;[Z,>37'7b3OGgV)&~PmrSߘ$/eq>d34N%W$7Jb[Yȧ{ Zh-jRQf'@EpDS6:oz.9kPnr1hiI#\ˍMvO;W*AP Q07O 2RN\^ ^r3ՆjNVq$r~) ƏO,8TAMc2jr : L;Q^J[z! K{,k9`S4bAdJ*zp h-a5 G;\wZ}z44vy,jzG!8v7bڠlzC6n)H_4`Tv>D=es%1^9Um< o3n1D)Qr8yo:L¹8lb.|]7ny2Mwzh/r߻ 7G}}ZQAlws# JHoVaKlPTU~$q6)[2gIM5~\%ݖ#䀜1} ǧ ê<'̖Ӧ6"兣}u! YfT+FR}ͮDxHR=`BB]rǾ7|%ȓ.B<,oZS9wh>pc1 }&6,0X 4s?! ɾ[̻ފ~|vή$W:TX}*8&ۑ^S8yҸ>ʶ7~,;oxGQwe?BJ`45L2^857ŽVn0e {`1-*f^m)Y x[$ 4 P"xEްDv޺nmI$`W)pg++ȋ[صBKfG/)ʈ[Ѕ5XQ~e,h 껮,;Ak5$-gK"u㮧d/ߐ;G22y ScJ-hi(wv0D\{zشxI>V71qxWy8 2ᤈ-q ;Jp?\oB6 ьVP;7fbBݿ z{.tRѩe5Lt[5J. v_e0M>꣩{tx/b\C)< C+:$M F/||~a~I3`s®:s?p-$3&aV/4%Ӡ9My<6>v9KG4ZR,wc4 CRA) +d/Pg|K~c1?^׍)t'-<&޼(c`x6* օ-QїYDWW1e~A2!qGr>E-3 &Zy=Y]/jutcSGhuI~CKm~TP[K³Cۘ2 ETKJƂh kp{CbWޱޏ˷W$+=bGt4q ?Y8QZ^#"rv!/R!×M(DC, ?D]$=gːU2yQb\ &bMw:D XMfo x*3&Z}Qx"'<]D5/R~*uJ" ѹ2P.R Y,r?1{vLg0"mfޫHgTuh(0&?o\rm?$4'Uh4:=\NEHIדbd sEQ|_Sܦ#CL_LF0e"5E")1YŷRdp//V!ۅL6C7it |#9cZTe4}d+zm.[ݚj(1~1Z4pCfgZ6WTN˜WE^- jQO-YoۦqnYB:"W1Q}J} J]H7{ <>=-KoD زil;rbM4ɺhȗ=m 5o{8C$rTa6qizvAuhzͫy;[ M0maTf0qӬ;3|A,3Ųx0D4G)X}M D߾tܕX>3 :f /\%Vj6VR3ލs:%,` [~pwά 4A)uM<浘XOJ)'ˡ㛁E;aJ>i1|UXΝktRzIM.Lo2ٹe:s 4n*W42@M<>PQp긣|Z|_ z`j9B|%gTN[q !_%Ş;̒=# Yz7A"ΩTl*!+ y{ecB$EEUNy/laFX"t k0Czhٵ6ieJ)˨ *K޳S5U2GE"4}ݦ0!1’ >av{9^?%uLkk%gXAϴA.פMAW APЂJCd5*yPấ؞ = s; J3]R`/kk(: D@>έ!n'56h2a W]u=խ]'B w0KhO)ɡNa/gYb)*>ud jGMa#6OO,iY6o"AQy ۺj> \[AYS\o丷ZT=tyy+S&F)THZvT쁫_gfo[љRML^VMX羑1v7bbpCdVSxJHp×tY1,(ĭX*I u"+<9\f3(_hw >]36 Kq{p/Qv\}NH1l'YK+VLPnۄՂ:|/6b,:|Bs#+yI~eN l,,*l HWЙuzɤ8a8Ť|8Z&>n!UEA 2N'%F~C%YںϼcŠX0/$%$yi`0Vΐ8 XjҲ`HSTO_΃&~9oGK8BF'~4QpC'pH!P%pf@Eԣ[yD]p5P<0D"QdMq_J۳:bg:9ijsU]|#&@x1icb=&Q`jTIX>T:,`Fn=Huʬ~mN;'a@Xhxs|j*:R̮IM }eGDW ܃apa$}'˵_8Hv8!e"G= B}>OY+2Vںh_2sߘ?Ӯ]C[$""}r(~m_ѐ>=M,ڷkwPduMf d&"Ԫ+4xF/ń:p,L? jY=Z@;Rw«=1\>:tϙΪz^dH_kLDwe'}Iy@|oᣥaw1!{b#s$}+V:q+7נ-CW1E;iB`6,*ys%C}vc@h_ǂl'h"6H~B۝@ԨUexכW/c->1,~Q\ f@V:m!GQYl>9%'>Mo&QvyB耘N3q;Kwn\"_!BZRc+LK'X_?Lb6K1Nۑxo+H\:Ud2,-/!ZwN`b;ܼ /= +R)+p;5zU@ n p?AGs_F,. 9ĮC2 ͆{_$ ZSzȳO ]*pNf?s(=(ztf* SQ7۹Vparx,(%]yE(t-ߙ )equ֨P\)^446b6S^2־|Z hq,햦B$ Ͻ|Z-2[̓H.|g]H0#J4ml:vw|wv:صh0 3ˌa 컐t@b#qG]!, AzP. 1njs |s6Z>`@=%ptbx D~f\̈5J5FS18d+;\[Qo_x9ny&5"JM $X:[/@eX] \w ѧsfx“[M\g=l@ҜpV8 .¸)]+B6S.ܣ24|:l2_켔#|idXJBΆ[\?Ep.K^Vu;bGA)IʼnJad7O+6χ#P}߿ޝ|*Lxd&xko4^}#ɺzL;/)v1*?Μ𫼩޹ppKaXxx/$>yw;vKD_%BxxwU4Z7E}GC-JY S&KXťSy_&w|,ǝ`󴨤ŋf~~vJw2pk,~68׍KUic)kV*Em7g/MtN,-F$:,T%_!j6"Tr).SZђiUf@ς9˹9 +)'a)$իoSWq Уi.,šq4TtTZ9PUi U5T܍=E :ehU@z`A's_CA-%n<Q9D((̃k18UV,>o$Q ZB5%< ] U=C 5Zګ[rwh+.4sb Pڅ,!Ÿ {Tznp ft#?Jbp4{$2;ךGG<( $\. /+9%Xn<Ռ*Jԓ-x)TXok 1  9q|aTGK~gnt.HOVQm ۮ/E-^Ju4J/hu/C:T't`v?1wGp'e"7QGnOGpd`BZT ߌ!Qasw<$G6n!)[.oOjrU6+.fF7s?hn0r)m 8 )kL'!z-JsN'?Ʒݼ4"D189E!BG˕@.Afh3G74^}ǂޏa;} -%V#1.GTD{_I I2ٍaĄUD‘B&UO<fw2cyC[>s=8{u*1,ɆsGGbnGsS-l nRxym3ɸp?Dطэ/ |J.VOoFwL6rmQon6.7 `T"sG~ݝgU̳_UBLg#>I"Oוo`A{77O+f!a7789Ab`0d1m_0kCg#K\"4[}*c/X%JfJZJ8)b ƾlr%\ ҾuEzZ`qxį @b_kZǦcPIu9S h.5^`1nA>%0zs)CTz74+<7 @ݨv*Bc#ի  emMV ^~+x\A>?1uDBlN͓>n;3X X,s#RwqTzEi@ H|F94_ٖF;2aR]YSϏ.hYF70{l͍m{N;+1! Y S:rXo xA*੐ugp {F 3ɓ6ˇ~TjV%LNԜoNq](Ex-X9+sC4alՂ|3xe8{MXzOqXhDNTCiž'mX^NF6Ev^5ZIfJwLH#ge:W$Tԇ OmzRF1!L&ܝ1iW';qCUO}e-(|^[^FXl2O\s7Ȅa1.:+t" QcpM!)׈]JGyj=t+Գ{B[Mf7bѹܸ֨Yoz ^guٽ8$s)nNuG7][q+BA܁qϫ,?Psv FrDI%dm}&xk6=,Mfn<1T=w.R=Gau6}[زYh3,;+qNѮu4Nn`ZN"&yӸ1<{fKa:x/>X&;Ѝl_)1sw´a `U<98٤ i}17SҌ͸F]X !2/{j`UuĥjMyWn,85moܹ&8 ,>)\':)FXlg.#W}N@M-*eB{*Q"_ؤodd92P,Z:x JG̻bR ~bC;bt$ Hޝ=Q}QhbVVF F#^ИU' Gm&&PwlїM.u4& JnjkKGst ,(vzo3WpJ_o! @ c D?#G hYI%V]3č`p8 sPcD-C#Zu:ķq ~֥L-OٓA?UhxT";*Py j9 k%F8[s0vĴa1-g}ڧ4~/f!X&<6#,@vH/+^ @[V~x@-v 7艎qXXj$_.q!AgςnϽ4\1Ϲ;c1Eu&cuCf W~\O539Dn@sכZŘ0a iL85 Si^®T>yQ $Ȣ;Ri^lad:Y[9$@}Y/SۤLYGxX16$? 2P^cA[qVVi\5`{ pOշZJq:zKèvƄ1$.mk8$o~?znjR%3)^c7sÙg'ZnV)ow:`7!ƛew بl$".33(q}/׶~ K+<Ғ>h3DU'1'xtlU 0jj9gֵ;tU͛〉ϯ«M,e ~d;+PRbFӭ4WrP_E#>%yr2lGnE2Ȑu#n$ čhӑϪriP>0[YZ2M" PFB,)F۹Џ|^ePC}juÝ֯W; eC"; x9U,^m ~ 8K;*!}u |I|rCJ|v)z3[YCK|,%qdkO}M$*~ܬ"0lrgeYk#wdR:)`8}N{źB=UHRN [j0?YjdNKm*̄*QjMBԕxHჱrn(FNgCS R<|b63U7ED0AN!WhcuƧM.){qۑS$gbO~Lp>ʥױO EcUk^-wc cnQ"qhN_𗢩D?숅3xj$x0+Lf AjD*մ"ZagHq@HНU7 ȁ )E7Zj+*Xct J`R jCh3VX]6i -g hKiE|b`Ҽ6'vZ2D`DQ\/5=#i? &Q#u4'Ŵ\B}fQv>ETj¡ࠦ0 DObTP@yl6+ fN~%o gu# ezZɕaؔz]8/ \B])\<4*.kke5r [t9}D*L翼GЅN觍i唯Q]>c=j"AXrExP%ezwAN Ss!-~GMk&׬dYno0 Y ,Hs]1TAJL>R ٻ3z4=7ǤF)/mw1 [pq !u4H0 $*1ibN" ut'Qn׎piHHl5BUK4jo^s@,Ԝߐ!:eqncjs:T$G3ɫzgjI7MM`1aJJž@K℆ |n׳KY}G^\*D:>OL}dTFKuƤߘ#A1,_zzxs?nG֭èwKǷ3FTBmפwh$}%u.(c5o_&Pb!Z4}J`m;E9GZg6U"wWᆪ5Afɕ)[3_fv,=?brofQķ}Թ {Bצy1!* }Q +W_@ԟuOZZ* T v\b50wӄi5)ÂA;^Ȇ.#?uG"~MVs^#0S^>P;60EKz,6q^L0EGr5L.:䱷UH<}LJCԐz7NZNQNXq-b\7ˊǗJO>2X>I4rVtn&NOVrY;p2JLMF{QC9i۱;i{"c!_OӼ R ģ4D~*#Igđ#PAeCuME~8vJۃ*xm &$Ê _ x|k&,8~~,#-d.O$2@3 ˛͉>|qN=,l[AIʴLH}JWKq\71%j7TxqgJ\YQG5SjVbO$ bYFՔ w1Eȵ. ")q٫Bf\&uY)WI8xXZBN+-CL|Hdwsݛ?RoF Z֜ȃ%YT_ũs߮Au9XqI9rEƒSП: 8դӅ{*?., 7jξ ~+DasPfKp! 4ЯhTQ 4a4E @ j݌pDߪ8B{QcLύvC l Ow݅.BFGJ&zcEl`f'e,Г9IN|`.M$5|ջ>a:mBOwtNO MFqQyT:agGX͚uyOH-)HGX'v$?:ˬS TxdWed^D+ӎSY[|GB'V46\˞xRٜg / K~HM?h:&`|xcRl͔hRQ{wF"g;h2nf'4 ֗ʟwmu{;60+tI>HysUMЁ}o{y =*dזqTkމZrkߖbΊz؀A4XG_%d8'5އx=?_Ks(12\ޅ<<}I3=+9{gTŀ`?ԆPxRalDEpHx_#'sMtg<zF&̾Ӫ&7Z/<1`MI0p9ZQ(݇iB+<=AK }e8t(Gxi.[\[_2prNi{U OcfLrjm }c\0cIȨ\$4V;br&Cn)1yTyjjwon ˮPw< c'd4×{t!~[_N w7z3z͋i~@#L{͢2̆Sm}je|:VK;G$N_1޻K*s0Qju&]{(f1uAOUH>.^$iC#u2L gb"|hvիR?\0̃=="2az!9Z}&̱"M !̲;Sc|j\8KXz ~:z#4l(H]x*b%egHD "Q:?KkЉ?gGf_F>!OjwWRRtƦ)"|.?28&SH& ܜRY c~5!tgz-<7JԜaiU~Gia7.h 8k>>8 k۹P:G[H5 Zجlo٣D- GXc$66O. 6P U4x fYtCQe:E[+8n|a0b!չ9gqm6:K WSj!t ǯ gJk=FiMeϿI=LT;30.RzZj Lz~ V^Xld;Ltmue萣:-@s6GDN|瓝QUͤڰ}8͂}0x2nnpm=xF%yzLg?҆ bU>7BĶ8_,y<.i{f%C<:ZnLYڭw tB:w~x(7Q,a(Ŷ6=!'JTkM-T+~=w{"CNԼ;-|adV|VX-,U?c͏|֛i+"Na;Z%]1 \@F)0K@Г%llpKgR-矺mF W;Wa&4V59_y.X|s O.tWDx&M|N,D}@}MD~+vxr*5w;rK6-YnpzpXm+ 6i(ηf>c ygiF)JdX 6ӏtKQscMwtjω|Smw%x{I >2M*"O.\&su('pՖ0p/Fҭ"$M=Ss9ZW}:UK2x?۴~iysa~QPTG6~NrT`T֏RTm%J u8<]7mϖT'>LAAs)y sLQkXe<4$3xԎVuϝx>iA])yf'VJnfvMg# #@W'vtҩ;**prQf8gH&-D[󲛪BF~Cۖ2?Y U g|ɖ Ҝbb;b F2xz$]%__ dl)Xw]PHPXbTpK2@iQâ,cpZս*hNcF۸DR%M%VF嘄{bf8@NpET ewqs$r}QM7LלJU"6#j l4/6]Eصj+Hm@-Pύ2ÐM'qYBuFl)}> k"9B8vyU5^89C`JtTù(zw.bbSIbi>)}b-DW:?>-#(I>BJ6jr|tt&ܫ#g+>ͷtm Kr'gh0SV;e%M'ݗm>nNXTqn.ͻdY ܣ4껍h1\SD{Wcrdk 7$o4; X35w4 hL_Z4 .'~.| ҕkgӔxTygb .Y 4A;GUobg Tb'h~E!Wätd]/~'W94Y|8nYS܋Y;-I5/L8Q B%_ۂ4i_h+텱;)uO^B); =iA@ d1 慨c_1F|1Lry %Jxh>UVB~'7D1_t\ H`- yG69^4%<UqϘujnNVF.1ߐk ;~x@a6:nI(iM>Dze圍CI]VPWs '9¤/VP4/(V z3R]w X}NZtIiE!JA=z`^9`EgL#}7T44YZ{J <}ޯ[cB$d&JE'%4'r']ׄ/~|YYٖtKgmӃ8X@}'&>dS8'D0ÅZQndWb0< @=M [aY <z)^VjZUy s\뚢ddQt#즒լTW!s ֜mhD$.Y7uspIUgna %TMNֿž-\|紞5i,s G>|/t?9gw-BSA4JrN8 b#wcFFK .uvoIv_Ɏ@)BNTY͞ϧ)MUєBЂ%21&@g.6 "iQQhBtJJ딪2$b0q7Z0OVog8l}-yroٲASݸFfKYniݯAwm EAa^ťZ^MzOa Wsy ĮUt80x6!N F @kfѯPY~H$>Esq@fI.LDd%382AefGEvE# Q#+~$J|nr'|'G$>d Yb(F[AJ,(^fl0u_A+)y;| I1LݘPüCbeUG&HF{A>B(y祣4\R, CdЧRMmGYTDOW?;N>3i3hΉ]zT$K#JJQ970oӤc-_Htҽ-K v!,2q_!cRf݄A6d&)0$BB$F1[*0j1#^)1Mj:>^ґȗ] ږg]E nnM}Xw_cfÒ'\f:Q_rDv:O_Beո= .AQi> PYJ_J$Qeh͊~䇣)3^#v +$9_u4&ֿbY!dTMϭ,9nݕ *Ϻ`>:/Q҂=[/ݞ=rzh*p C [l"#ϽjjvW4Q!;rp; .ۺq<ĬC5OFEt@ B^Ԉ@Ws/ք>X+8F&)3苣)> R5ݳxm _QW8cNNHb'_z4L~2%Uw;Ķj]2T5Th]X4sT0ڭ|TcCQڢ􂛩*k k |\~5)4 \,luckXc2YCzT)_rp^1h9b* +KjqFSdWRPWf5ۇMѽw26mc1A$d`ul+7Q/L0(uU奠˘H;b IoE=X`~hB ~!h磀_:3@WAR'8Z.SѾkin 0QhC.{l׳GsXuŸxPʃW#/7yUJT1y3McLk .<3M QzoU+ES džƏ5*CjISVɈ:Vk>U4x5GXJ_1\\ƗmFڬYZ$—V [L#WuQ_2 g$ e^[#)tG9<"#iiVɭg>gR<@Y:#K_d.S2ʑn9'*ܐ`bf<b=@ƺ}OK򂬄 r(~P>{{1bGۖ  {/u)$:$JSwS$ 9*FΨ;t'阾DHTqxQDIuN<4s9=x=!TF>{f ̤t`YNfbF~ry"& ez6dL_2NKRRPƗ/L&m ZՅ b7eC_.hZ,M yI!zI3ru(CIs!((K4}t|r 3M:rwQi}+Nf΋Me2@F[Uz[>Is{^~~% fcSJ`j@+-W.JZ_A=.27[3_( !!ˑwE*ooS78S=lqkzvF]$vloDC8y8c"Ldꒌx8a{]Z?(0> ,GdA,Ş6į".`{x*F%忎'9 G_mdΥe2 u vjϊn-l]pNS>Mt#-Ϧ>`' 8ӳڑ3YU7x.pZLAUTnyz%E_gi#oFrKہ<'{i^Db<(wD{K'$)U3LwAޫ;6Lnk`VQ$_88,羲Gbˌh8mڣ3+Q<mA&6d.gg9@ NI_"̔4GȕL sFu(˺H󽚒 _ȥ\)9Q JNH5$Q5 PD*Y}/cBC.G~{рbi WreE%Aۙ.h `n @̞.Ù>oXXc̎0T BK0y]}ˏ(;/b|ZSv8ū?\3e9,WEلd `9մ'[fj ;! b~eB~{H[[v C&#eo$fw[(Ʃxg+Ip\Ydm]8B !HQtGekW ձ*Ҋl|%E;Y>JIl $+l؊ñωg[ՒB R7jԫq`K9)S\.Qr( TrDoP, ݛﴯ!SkQ`4_I5 1YQ7p 1iGyczN0+MO*Gp^!e $9 MVXr. $V@ "}yl$_~ ⎳h4}3Mɑ=XkBMJYm78X>xULs! s&Y8N(VFRS4{3yaxҬ! D%ΐ_Z[+昅/0[7$4$*H%̐4°Annqp*w} \6OU['S|;?Pc3 kp5zi9 f<.%l1漼;k|Nח(*hY7l s~Q{/ʙMt! uYJxMJɥRG*Ž$h`KQCpPjg\NZ䷍95AB*g{{P n?-kś+{G #qyLlyǠʑ۠یF(ʈfkiP9{;o Ea?-Kw*<狤y9 2Z 4l-gVR"ī$#ɋ5FK|̮ͫxdqe)6I-#ofqg|͇cQgE75jIsjf3D˞ /gƔ8Zѵ){Md- /1"5ReTt-,}0ⱻ| |6Q~udwE5oKLc)e{cMhMy2>ߏPL}@(Q/8[]Fۇdw햘N<Ѓ0.gZˡ[_rSͯ2V}vSkKVuq~0k@țʰEG@FbX'%Yٖu*Ѭn[s1>$p3KjNxFgGϿ\/$pŜz9b̅xKó rSfA'6;.X2Eڛyۛ45pz6֘횙g|Hpć׵шɂ :oP}RUn3 BuKjEIa9:8PnŰ&g \(`F@UKHpMnz]GDYD6yD HVOY;B^v*hڐV6sI_6Xՠ8^Gdfqgpa-X*-ke^Q| r~>,9b$Pa<~'rC.揤iXsLe<{oI{RZ.6mfa-ZTCx$lND yzB g /Uϗ5 ! 2Cu Dmwˮc#RX`Q%9S"ڟ,!98=|{ Nx>;O4tR؏zf3 _`:s\M"JF;uYzLƌl U Xw]&5lD0y[7'{{ K/Y]j&cBfGEYm9$܉>;*~"U<[;Ym<H9_y-,^F} ޼u쇽.FCJ+nNηJRIF2 _+*]9oM5s*[|2"YdA) ]Ŏ]&c,shѠ4޻}4HPN꓀o_jU#ζ!et'f: l$nLwH[zK]^Mޞ3܇ ePxy:P`?|s?_*odq[5"ڲf`tctaM;"LJM<,\y7\'yY1ъGӵQ[boQUxC87X,M_) cg77a1 u{!}pp*&o6P&Bba+.{QH/߲fM? cw]5,-^{0{up{;W`堳;=DFx_[͔<-֧xld;ZHȾJNF|4hhu?vF+LX΢)< &'\p8 ?[uÃ7S[Xk1tK~?~6qzLqMPb|g`eN>1}-ah @c߈JعAI.UU+ڨ#ى3xݫtyC,Wz21HTCAuŅrFL/,<ۆֿQea-ZdARo`Xv̹TDƵ ,Rsbe:T{P%kWho Zj`$JiьX'A$h;ND(i~u>u/5I Hg6ѴZUCnԊK~IrMӏoKō }Jb*,D ƾr8iU9D]èNm>Yۖ#5q~" [LiPK>\STbMe#=VzY]>QF C_k.2-wT H(С D D+@f<,v]1XI3!B ]c> $ݖ.1Egf<NM,dGego?uugbfW=ɧC-O1>H?;@CԂ;?7@uO?&  _A2K027Tu)?#3,1DwpQm;bF,L5.KKuz@^LLjrap7W[C#3쐤en?g{  k(_cּ ZT##~Hypɇ㉤j SMe{|] 3Ö)$cQ ,- #!):ײ~1iBN@So/noqwoeRϿI>u60`HdrZ7VSZ)}foHˠmȑgA^'bA-J3WmKAAb]iyXnD5^pдK)Tv$>l*<0;O=Wͦ+Cnbaz~ϭO!2l?Ƙ%VF}}@"Y#1e~qgV'ZBp=./i*q>>o_hX .' vZ̻KZ4C3*rTGyY'GN}a >c̈dzs2*X!Ti=ofKm}T+IhY"%$^[ݢ0EZx>Эc5p {Pr[@]Haһ;‚8r%@v9nj}e"cu؄KcI4t GMDp`;.č0ihegV`*xQ6Pkẳ't{c !ԾkkAM@2e"nFޣyJ$hqY@_%;>9N>p1G;ot]zdgqU:6IDiHqU$eh[]bh{:LWYMu]RpdDT/s5ҽi!xqT8kGg}l&-Ι17rhSM_QPv]_v6ZyJi]sjen@qի=Y0>M>oPؖU`2 SC+]\" )p:AGOn k9uĵ7xdllҟmYHwVh:mk0f&5`ǟtO[oDžofXx!& D3ŋr>M+fHoRF,"[+ M<^2 G hmIME̬BXzW53Ol,PcZ7{EFD4Nن$,} f{* @QW$=`txs7[iJuIZNϞmo!+;-co>sagZ{bpsF-g(g.ˌ_ G!$e%Cq ⌛K~A+9}1x7ظ؞~-uEvSs3IÈdq` ZtYk'6fsvHA_HƵyR%qAC@(^נ˚u>uiz|}q/1w2Y/ (Vҷ8"dAf!|nooBw2tW~#s`njT߻Ƙ~~MBϞ I!K߱&m?Qz2x5`Qdw>qkRʧ>N>za{9QɠI\;L^|u>6D$we_ɧH _$fvYgHn7nͣ1"l&H :FbqkVw[8&Jh{dXf^uҒ.6p.9Y9? o2Ǹn.Y!QnO-wyv/e?CBp_y.31u(}S8δvIln~6T eCl:H˝@u! (C<]~ӫrgVkDԥMֺh犃ifUZK \ޔX{(3d_ݲÕ6!ҟRVktBǏtWϑCskQKg?\,޺4|'a9]@2ﻙ4$wFMӘ2Z>c%M[Z\WXi lkF}pk %#{psb@ ::R"n).J|PxPhd$i-g@wa*2%N@ ˡH7E;|>ȵ?.! }qϚ4*Eln;n\/sŰ ~[z!IeW*ˍ~'HD3;t|íY 9/"@T2:ڀ hf/"RegYm16&9ވ>r*Sf3\w>u\U6#}oVA3ܚƣA&XW%Pu@Pz*"yě@h$F` A5Q=b. O)KtBF][|܅Y?\pdGatQf[EAljGc_6u7G8%(gƅ v2@3GpC2'Que8.J[Sx Epj}?45|N% W smlHqwޜhzF'c4u\G;rE)G[֘:E )*QӾ9oW̢-2i9Wa5a+_,J@=l()]%}rU-촚L9i 4;S8R^^{0k]Ni*Y,3M{zeekLimʾ`tMFG=/GLxRrzN @5K{-(٣D/( 9r=G;bﱼaL,1,kYh`r]F-F$xL &OR1Q=x/0< YQuvh|;Hr+\r€JγKړUV6w6@61;x'9Xtz%޼@WILR!.1)c[SrS+=H<{UٔHa+c\ߝI5z` zIhX8ɠ=6Vf^ODiʼ/Jepq~Ȝ=ËH/#B&)jPͷ,HJvAo\WΝH%iѫ1\:¥v0A`cTFkŠqFD'ԯ_O':B&ڏp6 -r3@?'_W]?/y#wo_ ;6(<1?~d$f)0 [> >֖~>SfC"Ψݨ9=ѭI#O y61[XL)O،d|&瓥5N󕮈rze,$t˖oLI6,ۻf$ wQ|sn>0`F;gW!aS,p,n^y'P=xW%wG(D@ʞenRԞ6jIQ w^䫛7<,R;^%^@X AJ@DZq9㫻V7/A:Œc@pFs:կ1]wp/l^N^RlD}ىtsAS̐ (V;ҙCL 7/RoxS;Fr;iʼn\^x{!p !mjw[`ƯOK%%p H*WQB6oCm:st*J x( <.X+S{eG%^So61c72TEh*3΢u#Eزm*Za 0sEk a}T5{[ؗRv'@24 E0#a˔}{tėhFTҖWR5ė"tTf֓jѦY)G!%[%>%[%bXxK$Н,aS*'y7!O gU.{]4d ĬrInx"C-s#M /^[ \s|JSV9ߌwB^S,ʰ&5$f! Y _5Z,z4U$mn3^H4FZb.Vݡˌ;25TႪ,-%ɇ>hٌ#mh*ݰS(0.iL[m^"LXRwOS{@ >klZޥ\Wىr?ZS.'%PZe}ĊH ~B'ӡwvʲB8s`\Tl6kx\Я8Ny"hO OP\kط]q,2sʢ-@.c`}8-y=z (H";t-C{h<QZ/r洅'/ s83vuC tPfKh(C?,üz8WW𭛹bok~qDc eqU|{e-\_L3ywqp%}ӒR/TսOI\=U'ܗ*VYc`]L_ѩG}rG;AΥ.>b'{";,҇ '@|RXo4gy˵&デVDc f?kvhQ(|mV䪳0" a*mމܡޱ $$b5u&׊>d$l#* ~GMV|g h'aR.a8/!XobC,'K;SM* TB+N.Ͻ;n[o|TX InmG"B<2VJ$&oM[Sx,@lRjEqt ( ZU3X<;#Nq6SOg5Y*4`B H}w aެG/EMLU5f=:bDx{~k HjтC뻕-ٙPtHM5G'N]Yj ]P΁Ǫ=v ȳIcc<=?1ρѣ(zISp9 8g{'+BC=;UivOyBMY*SG0{SA,}.@P݄d3(=0!H2Dze{tX%+-EvBota퓾}|t2Ċ]0#ݖ+ˌ6FQ4rn ¢n>S%N~ oR0ʴ)Pn(kRG>_qdAMzz%<0E#,\5iY/}:s7-D+|~4:!HJʐFkA(mC.06=IoPI6I~h"X__ +=nJJ;뭒/Tt v._0ǣTa[$K[(RUas̟o9>' Qۄ~ X4C GZG}r<|YuH[U~<3+x'ɴc`cKTa%T=PPJ5X 36]ձhL@А;ή3;1h$HM;.KsT2Ks>CIݵžs@hX1ڽk:mgOQ4ߔR5Kx צؿ:8^ߴ@N1xiNnbRǩ'm Z6JmŅlIpk&ɣu*wLE,xԦGd3ޝǛg _؟Fv\gܵĸe9[(DCدC'`N~+(Hg`a C@℩펻3ޜ6U>\h%tRW7c\ q4)P|Fɖ:o'o߼};[ۼMWpL\#U߾w8:z(yDLX> @v~u4Cx'7Æ*,o6\,m&]j~qzq^ܑatN ά]QF E|VN'޻[^wiPGJ2`wsXɃץo;)l]$ 1Y0o9)g|c8$XfԾ@RM%?3"~׏ΚfA4 Ej.CWN /iZ̬9mgE}3PS^T'h6fBf<'#=OA H9ՙWޘkGhXuA'7q$i6+j(ELReg禸ʧ L 9굁a>:1A"N&V|P{n%3UdO7^<)BTmmn0q'1{mub0'xEK'WX=-Rbo]f꧶ƌ(jUO03vQ B ,lcPB[8Fj-%pn/jVC>$XbW񼜡E{)3l'Yc߆:Aeg>cDtA]E$)Nʼ +/(H2L"l1žjh0YpRWK& DrG2nUq8!3e +?Po兇SecpܬEL3yO%%\=^@)WG ?r X_1RBtѴ $Q坩0~ݹ%i=59֎5uGv l$E'UFq Rs;A0}6I׊͛} q 9jE,cV`6 ~nUCG+j ٘%MYͩQ28R6Ifkw(;5(Iw ^SJA* Je?}K*UH!Y$=d_nz[Q\! IRvVEʃO;GރR7R612uF-B'l2 7vX+]>zat[6|@XOB `V|2m#XT:ۀ, e7S1a?NtTS_" >~ M<&643x+n`m.%HG8[HjC;d+[1\n0fK]QQGX26SNYR;ʠ,iHߵ /^L A,{Í˖be%Kw/He/Ϟc)<.^AlB 8 #LRvh=!4 H' Mj~(ؔ9Nd v IՕBD>)|p_/wWg~VkIZ7G*6f"@~)E'(0;ٛtÁtQŘJC5 vo"-n[ߨMڬY@Xss$?q1.[%rhRӳaF_6~{ې)tiSb~ v{ޭm34J 20o+: Bsh9.OԽU063jD4Iy?֎o>F#U@= 렦ai[X VW?O#|=Qc'-.;q,CMx![BYa?ᇄ%䅬3ڿpՐ=+ccPQYP@:!YG)jGS{ڋ#ޤ2'hb5UlcǾÕS e5T>Ǧp`& pE5L{q{W[z A }[!ی#ofف0mUEzԅ:j(-'PD ťnP t ҳ ԘKTLLSx+E41tM6zAˆRfFʭUBo59Lm"q<?ɺ[@K;c4 yg]eB}Veh:x޳=ѩ)R ׏[lB6i$:b0e&+@0Z+>mթf698GjQc R6v=Yy, Ĺ,Jc K+NP7dzerD&stK}w?_Oq^tp x Ջ0%HxIHiFWԸoEQ^~=)nIMsOs "4"ΟkdݛB9*Pna~o0bVKMJgk`⚌g-2 ߾ls8--&Wa[f =Am#LA㦆J΄eUd 6_ ʭn{&0mDڗ ֻ2FI;MF&+lD큍(3% JA @Jbg|+ V" ǚZya8=T( ‘1 3p,2(62=xtByBY+icQ^J(mݬg#5PU*etx-~UOSREK3P dSH93ect9O^ԙ#:A;~d=JGABTf˩>[ rgplE`|cY ˍ߅A$s$iW!7l&5HpL3gEK:mK<>܉-3I,niqRJ%/󋴲VhH~ՔC˱<0 #̦`Q7(iKQT_Y^ jcF'$xa,#T2͔@5߃no`NES{ |Ɩ",y(u10֚m7jkJ-derL^JUA?@X{Ve`Sx ~<}6s [K73-/VpfTYGN EF8 % [{} 岎sVG.[⮶A3zVjvaN@dw)ь# ",P8Dx 3BF7Iį UexN G‰Vy!bV7ZRaj - d ,t߄F٢jFn?rŒ0n|p1?|]\t(7mԴ`d<4Qfr-GvDa Ѳ&%[:0NiVi-_y0049Z>~Bxa{ϔ%?0#V/Lw7ձN)`ڋO%.KƬ'66s_!-՜,8CU5<.E=>c2kpρN ({HҾQzBѩjœh Ċ6R<p<fZŽ1c$U %[\2jF|@ V~i{kWsJg`@kV|Xqjp]mzMi(rvh)jd!S. ^oI]A8@ KK1cJyh!X[%z%>pJ7wprDgwRȩE!AZ%:.a-}2U6+eE6ߗ]RT(uX(:)m(9Oޑ!Ѭ[&C|w`AB=|IFoԣEbz[0|x$gwpM-:"2d;'ABJ$O V101 |cV}`(G?V<W9q/\ g]l1.JA"CVxFi~hzFXhJG .牞f)Ft'Bv06 ce͔BLw""4E$q*<4ЧcL,*?& g׸wǐflƶKg,)MEY2bdxH.X#]oA%䝻 V <PġoԴ}luY y !G9#pR^ͲN@wXi60XRA#4T]غRn=.qpP#T+aкmݏw)L4 Tdu1{n|M r/rg58-5j k=kЀ1# d20ts݃ [#৑ ՘^I:;ʏR f,Yu7joI M`>~-Mq[m|0]! r>G!Vp/ޢ>2.TecH1#dnd%a}Á>jhVm엗Lƺ]_ :%,Jzz1H1DE⓾3=_|R^+zO0Z`r+Eӌ%dP8d*$o$" x&}1@o!m(3ULNl[/*Ddy]8JQ3xDCfZgh*Ĕ'<CMު萩ߠ|ϻOO}v2Hae_'9AA>0\C=E Pz0(}߫ J65O4$efN'6Mj`\ }-'GL3Os@xC~h$ŭ5G[6)˗F*jj:@3>荑@vWWs~gY|,SY0[Nb@2~+(LPTZdN*3^i-IʊU'*pdm`G-zBӚVGۘ U1e1n=^u07@;3-)N+b.vE2f XeibT4Mz:r(*n.8k?RKPij*G1׉dK7oދk3mYQn&tR/a(OLX^ϫTʨsӒ$f%;`ٽW z:'sœi$ddd;2xxn@&|'=Eyt"ޠx ~TJ1m4j)K}ʫh5ioqb- z5kWoxOxZ?xM,Gxmrf5cY: P͇q<,F6cHMy̆RʴSl'3y%7ȨlZV*nwh8leN_aPԊSP~W<_?W%Co7Wi-#ͽBWW蘖q:LTvGPyY>J828 lB% vYAG?l٧6 u ǣ? r}ߝi*ŬHއ;Gh +eʞ:io nGVNd%=<(Gfx'T4Xx"GnZÆ܈UH  1߱ϹmJG/:Լssψk_ˋS(ib D su!L SfꡄDY{q}Uu,`ZA -˻?iDe%\T6O0wA#T]VC&שG#lŕ5' JRހ|E#햼hx!C 丩VO|Aϰ.{1p`449 v;dH$$a IHˁ.ֆnK_ K$TI6u& 2k(9=M0KU.ʑaZ :bbgWƔd9/H0j7]5 Z4 i3hx>fmFT<8:Pcdrڠ@Gp^a"'`r`POiuߌ@Nb: ^삏SˡqP7ZӒZG$!ӟYNurTMY>b!z 'q퉉OPKV!}^Dwф)VHh`( ]'~>edNjo uuRCs|B]MrThPo{OL TVKZPBIx4Qyv6vێ`ގk;~^Kzoa'9wb3_+%:1[Lbucc&>AyK+I9^'@RIIi5/~DP`eA=;RE Syϩs ;MS !sb ,$ 8T> u2K(ܚn.)Z`f z=S Z>m/K\> B=-" l[}בǻopY8Xzo_I]q`9wV=b8[dx2L'z@ m c/FgFSWudHfya& ;~B8+i y -:ڊ5a8r4 ׂo9*+oz.}%UFk?V.275C䮴T4lM|dԀheZp<{ƃiGK#5̄# Z$ 'q |Dqm|SG RV$cq1qڂcf` F򦼑0Q/ڑg14$FwB_[S7{(|"d7˚ NEc\ḯkQl.dr?!.6G<収 ><)Â {Ǻy:TVS|u+OM$܆y0uvTo:B9DWVs'pzr9 (@Hޝ1:6CiX()dǛ[&_eΝ<Հk=Rkf$w<;n jT(MQx"4/쭁6/·$cMеW8s,k \LTqZ-aMubsLϻ?չƳIOq_ɇ;5,t7p =}\S p3uݍvdϼ)Q.RAZ" $WX~Etg_>bӠ)nLHf .•oIg@R -h{ }0͸rxuVSᙀKy1sD͓~jF{쵤^\=ڏs o0>CR`EU6y͒+Rмoi /N.6 }$J'i鎦;B%3'Ш7ܹV*-lP+{ sp`N7s Nw[X'/(1b+p6Yشd=qz9 {1sҮCo!G:wbs@DJ^.Z"H ~ޕ:3b'kzTwydp#\N^1[6y+%ek? lFTl?ZL36'x 4ꈻi <.!'2ۡX[ϋX<@3?BO-<6v6^{ڨY[8HoqY ]73͍F 3޸CŠz&R6uXJCtd^Y]HjOtj8lYks1W|<3pM޾D$*wM+^;{PtS*fV:ePZT8H_ytiiE< "]g;xnЪB>z|W!.ChDA[Jȡl7eהhAόmv:3,֘֝(*[,m\t,{0#{?2k}<!.Aؗ4 X"XN/vg0R6a 4* ޝK:p $tWv\YnTH$Z|[dQOO$յ5uP0r9@(Ԣaٳ&(:7q4qyۥ%Y95Wi=> $;qFNʐƳys AkՎ\V #:|V!_j텵Qqu4C$N§J›ŸRҼ&em4_>12¬8aImI5senVvz_򷤮}h+_58*79yvz+}4M3x S22ϴ,1$!Q}.8Wc}P^7ρ{w=:i.%_= uXs)(_u/{7D47PGi3GF5IAFÜkXqA@xg2JLMd$P iuL:t*us+JP;`-naX,z)YvEeq5D6ݿYːIL_+FKRH': d,:iHhoeFیh ץ#/A")UqBaK|}CPW6D hyq[knb#nlBK22r.U)Ta.S͵xA6jڦlt :XE7xΖN#FT9 Aa$֝eifoNV8i(Чr]&Ч7 !tH&ՌEC6 v@MA'<܊ĹiYe?{U޺͞(Ǜ]``~LO:ioTz dPWãȜ-Y$~8?=NS'"ߥV}$.hC2XI5Z~[H-Esvқ&AFCƷ34VoRztpb%uj۟OІQ׭y 1r!!ظbSzAJ5#ˬUW 'T-e֏eJWU_r]9ˁCjdKiObA/GX3^7it9UjI.䀇lZShE7 dg # '657}!D"Tk 'Y.oQ*22pǫ^,JcbZ4􄮃2@z,Mzl`8{)~򓻌v;kׄ&芜hnF+\Q&^aR%3Fvu+(Bf\(q-UY+.+Tjlm0JH(D {?Iܧ X(X\.J6Y@RPZ*=cY\UHNB*:$am;ځ7#$j~86;[f#iRS_2 f=&:ڽe4;6qG\뛏OJO=;FYÑ4VBTr1S5X ^UϗcImL Sg5ҠV+6%A҈> L4 #x|.݇}<;?QwCEco:lVD2qӅ >YW.P ^a!_ѭ"g O.;2[J so᨟c}'&ԭSUmpz?S\WFM6_2sL4\"rvʭ\i1/M~=}B65xtzϪ-[ ,;R[<K,r6p>k Ҩϴ CM9N e$*y.#( dp+k€*6[UzDXrGU*씙Ut"NΙj+pXd"(&@1KwfξKfp52aUFmɭVu`lQ:/FLʼQIfn.a9XEɉ/sVڷ'zǹ]rZ(]9]4ՎEI֕J챕q|݋}/`lXDt0yBBg" $ 㔑H2*BXn5 gho/=ҿO=|ŝ U*9~@.lQ7LKR/r-n:kyaZr;ޑ/CߏJ4YVh-HL|pwFqmBRꥳowVUCywvHC;W-|qꋚQr{#hyoW8w'VRTHX^8g}7KSr7\3Oʉgj&]9oUϤT+iӁ)Ƽx9LӢj E wo l%%L]l2B|]vuRt+6fUkʥyY×];*'3'F`ĮC5L/":fַ:_6poY 0t'ʏBJGyXБn*ٜlLJĔwnI+$u͡ZZ dc6tpK ;&)P&I6Ň%,lbkʶL_0"sZڏܸhg)& ?S2=XsUpӶRú+ܿ"ݛ ,=~}Fn/Pn.HIV4tҳR/7CHV E>cgV .;UD\jI(U'Mz&-%ΤK6Sͥ@ɺy ];/ӖQM'k߭D2bϨ wIGuM&_-`F')qtLY\02s+g{]>xVri ,(f.ۂ:ѐ;d!o*ZK'Oj6E*Q݃ξ̖%G Vf dlbCt֊6b4ŌTDh]`gF$]_e9W:Y$Y-^:kz蠂q~qF7*[#t4L [ZB]ƤkWn8Vm|,HI'("'%}rR$т髻7THʲǒ/-ϣÜAgPrJ/,{^wcq/{K9ID3=1vHIƍA0[|+ZvD,mU9]C_?Gb?U^tFe"-7^]%IREUj\S iODtv#MwR`j=TgFZ{QOS}j6%$m[ۃ}oB_zԒKL R_nMzM^|RU 7U9vIRBYepԮ!ħՉ%t<_y͊81,A)X1G#NFyBMF$wӨH*,YA. ]{g: "Lm-qGrH{] =5_g &a_ [ gRtV۲T>r),ؕ7K^ vv rTHu뇭N]]mqLHG[=}6b} Nr)'_dn n }RBK:ORS}cyK5Vi U=I Y[ё&.sUĢL|Z;N@*DX`ދ57p5+ w|њfWay- 7`O6W]"hA d_=(*za<i Kcfh6ʏ>XU ?Y~@T<ղo᳨]wx[^p=2fR%=,+[O5ץ|kuCvk}18M-}Qk@'pvJIwN 8H:%eUɝ"^sD @#W'J#hY7_v,x5?V֎MfuR_J6n?sE!i޾#zpeD9vVYYG@L#k7\r ?(RZwZ&8UE#EY"gf^ZyD\>;RdX񵪕F?ۙV͝E҂#YwB.dy,l%V ;.:pT&-xR욐~LM(]֌V|UP ]Znl"Ny?4UV:HPMɡzI@_MF $wG&Y֧L{t {b~ rꊶPƺ-Ҫn `mӍ$]wEKI!]+Lι|H[z]W"UOVF&uGQ+{*S+3,XGxn^`m>ߛ/( =tn Cdđ`<$:T٢6Bj7}]ˊ5kV {9(+Tܟ`&Q^~0mҘIYu]2^% mI\>L[UiD\mUP6!=^4 QdPƣDsoU`{M , 0I>)hH&܇Q8QΌ;Jt:ΠZҥ8x Ny/g.XI ۻ.g.]wS ZHNuK>01&G}AQoEW]HZךzǿ $U!Tov/D6^ih{yx"!X+<a}$m?Y 7j}XmW s!OK՞N`$S]znyWܾ -q.Kv d$(Z'%]R.PyLy w_lҁzCN m-g0wdjEՂ~ѧ=gC -&$zZBm=_QJs+d"{-ҊtwkoߣPD}m?BSR{HH\+VW{e_57N'A: xrg>N+I 5#d1"f: ikɓWAkZ@"eǵ-]@ UZADpEOC;͢TqgbQ ~;0N7KS/ l#Lpު?{ nN\tDkƒ Jxr r.Զ-qH vЎ~u$,݄g5ʌ h_o0 I'ZoP({k6,֑ 8^s](C<Wsky,: ɩET Asu^hYnЫZ$ٸHT=6IjܘskNlڈRPGүJ^Oqʃ$4RS s K(>:gH[Н;) U8Ŕ3EkU 2랬;zQt(( l0aH }c?p9lyB Y)Wr]EU4C(\ _T͉~-HE7ߋ[층tZ1XtT&f8*9zn;dU ~!Mmda7,K@L05S/sd8fc;;wS]F4t=ue]eFA7Ǚ*9eb5^tP7l g~ zl-]z 8Nc$4QbPLN7k|` YA2e2*].d 񙢙vBNa#S谺&$Y9a:ʪhCcX4~oE=!ޥJ5Κ<FfAl>>"-ЯI&jsGyq_wI2xA3}Rq'&MBiz"/u93Ok-/kDG|[h3* *gt֞I  md|Hm H:g z#z\u2;C4V[f$ i /3* ɜأӞ}[LR<$i߅Q;bpSн(dOŠs?οd]{顗"=RZW8^5pp17tUogS8pK\1U=U(!5Bm !шO/$ޚHJJF Z颊1`|z/h.:R;MŪ!0L ߫F Dǖ:w-(G;r 㠅kr Ov+Al+ VCݰpd  39_O|?*ւky*S{Ut'h.iȄbp;3 &ph)ַ__?yd" F)'rE ^0>0<|N3+\(G8. MĬ؏fhiYMr\d`^5Z$"v/;9xl< W$"z0|9ǒ do1tld@Q2Ѿ t;6mXlv*dvOd>~di'd1ǟŔ ,cĠ82Ư2Yu^⬓]VTFhZ&L[vɛK˲$.Kvu%JJ`㌋pq)S?o-Q!z^L|\(MsAi%h-Z;4[9eG0Xҩou]~]"P|X0aՋXȀ184?ziD# W݉DA"dʽcLc cCWOK K 8TQ> ҰM~^EZ @'{}Faw2~=mIfؽżP< PhF ZA[e yo=7Ȉ؝PĮxso*w@uOtDzm`J h,?A['kf4z{<0gͣ-qGTU\j:k|&szb;=b |FtфAt&X4O˅A# \;(r[aːH$NtwS+$ԗ25r" e>1:aXoAK-{֘6>ؓ7kp[|3n|(5(,~J]4Hh\&b5#sr0f?]2嗊ʊӐpM+OL~; B:j)cd0Ot74 OʸQ!\.dK#;O MI%w؎:˫1xEHFĠMgC{$B-Q1^lY{'Ji+ߔ ƒy")hG1uC=ݤDC0H)jS7 .`i/Jl`P[ٹ Cs$BVk|ZdnVZai*d[ƾv/d;& 5V2/I_N@4_QM/ 76pU@vA4>Qipt(G9!F(?FVVəc%dŶp .9^3υ7m;f^ D=D~5hK%"{+xb%DYJL%"mfzGC{X 2(هz' 3[pH?8VdPcRׂ&vHxC5q}J^MT3{ 2,30>Fjclk%LcA݋)f +T\{p[j8 95|$t‚CodE֙7q;^^6.%}tԄń1D9;[AWZ=f,#}ByndNY-a_vn'ɷf"cyhz3_#];(]%T=ԾCJHt=db>C%z\W:o z[b T?[c`~ 湫wT"v= kT<('&dx+&C&=$,Hϼ`B3aQ e68 ۖ{+L2!/BMTO\&mjlӵqRNSd,mxSҔU0۴CjC;Pն&jqݎ3ֻZ {ebBEm9d 4ɁqztKgDJBMAC,z ½Mv@IY#]M=KZz΂tTҗ=YitzĬ.d3i8Eb}#z3+_78 mn9<:G̍˳s F6$L?4KU4CJx;Z-ItSULb&0oPÒ.P"@GF_js+ڷeu$!JOl]Z ur;/-LtGV Ĩ'XgOU͔3Zؘ<ٞ&&wyUD vϙMl݅P0rZぐ6ŬUd&lBIb\RFR#yH"Sʹ ߫j [wHBxkCAUx1Nz3\m{UQ }P.tfw6,G(_9e*x9N ]?1 ]^#Yᶩ 8|$qt v]|Q26a"ʶ*YT$-,V=`ƥ)t"k"y_ƂN 7nvZhMGG:+ 2;vZVjaI%bYXHJӪq>C9 Qæ 8+;c} oЄ|Ez?'xxz,1jg8ɱURNEGYGtbZ '(aE sװ7]J/0//ZGM#.Fy=|ʲk2]:WLJ/bNϞ^o}4srt/ y9tyToDbK6q>홊#n0_+Vo?w?= ["rzޮCI[0(#-s}hthܭj Cł'b SƻQ[ZR4T,=)QY쑝F(nXޑ~sK6tњ/Κ!zrf?f?D5}޸5Fv-e/O4qUȭ  PC# XTkѩt.KaM#B(}f62B Om~LhRzFЫuI;a`J2JhYT{ Vyʫ(+JF14 dɘn @zm@I+/_^?t?.n.O3jS_7jKrl'7݊>=5Dթtyc<>J!~|* YAG&LQW:tr3`&pUESes7XrM3QQU9ϑ0>R˨pIKDKۆ[>g8f^3xȼ,:Iyv!Xإ /as4=7ՏmEyt! $c\%x=LSl|` ,z)BAv|Q0`b%%&^ꟍ|{1T%bj؝txu`{6 yy&m"<e ]. iD!UvoX$cepVb"Ϟ>ɚq,`CdLdyb(TљE'\}be${ԧLKJLۮ+l-/բ$͘Yl} >yS:[NJP}SD\M[ *M{Nf5-5wek_2eUh 9$Ph=GJLm'hcy =} t5  H>",Sj(+@xAsHˆewQ,x Փfl*tKQ0H|~yAL%n4 +oEL`WS $k}m?-bY:I(c4Rc'j|ჹ9O/]D{;ٺpdAfa3lhAur\3!źwod]&n^;_}@qM/>{0L@/D\4G Pv BG7fQR卭,We{z=b I> \RZ_}JJ؟+ybW+j[Ӏ+ˋ2]+*DyD^mz$`~ r2!%t1O9/N/.qB qJM34tӭv.^m_bL ʍ}/L-7yJn[W,DsuSCpEhf3bXCFFu6 ީ$@fL$6{j`%pIH{67h-^`wmCby-Yrv[-A#jӇP>W>˪\33im8;t(8/LEğh|LyblfpUEr=g|H/&< .@0)u8(IʫNH H y1l6UelvND7sJZN>< L/Bƿi8|E8C?,lF8t/i"( ekKjUjw43胇l؅Ƥ ب'O4!JÀωbjJԩHZ5?ԫD#6W7 K|7H\%n3~9Ab 4WC-GMeȄ ,8Рq61ޢYT.C2yI)0nl:0 2lyRHM touûU٫Ǐ!@Vq|ƺ[I7>s|Ρ~{ǵ^+]zL\5.uXw$,Zp!keئ/:xQ]Ő2|.{E%q.=Y P1nU{cFm=ޜ45fYvIvSXvtjnJJ\8SK9F`P${4/'9~"̀Oh}-4mrlwU([]&ƈ4si;]`}i_z6#?(uxG k{}آyNn&Ɋ~QI&ݐ?7^_1yEP}`'K+A(o!F;993xX~Gdm`-)1]T|(lU/7^fagi @)XՖ•k/Z<>}XL:UyR*`[yA&dncQId_2FX3HtBh:OݛB+GTv 3z>e@.$ gw5ĵvW`9Ok@(p|g8+5WƂ l|2 `ٱM@[5y˕ XsAXɯp35L4I8c LUԓkA:ڲLܧ4`- J1s1c]:9]ޛ xlB,Bi"izZ˷YH8Q߉ Vunq?%Go™+SШ Qd7ƿ_|mFt>e`{$:?OPFy=w !XJm&ؤJ&>OZcp:D*w@2;H8uv#ܖM-ȍ]P) ` sJCHiU  p]K.eH M8g2&4`8͟R&~)%*xm=5ކ5;H茳#уl|-^G;\h>2_EF]I@qhᎱiG]ݿZ:DD _=.f>^:e@ЎTJa9sAPk̮mGs VXHvPD=-ļ9ljQZNj%k( ۋfbʈ2/H{#/[ƹ$BccD ~ BՅna< 0'7h\|JxR W`Mo4xq]jjKFZ2I_܂YQ")HGC9pPp{zLnE 1^ns}FQ;!eG_STV3Tb_!"֛{0}lox+V{CX(6]c.7 V!I@Q ;L<"B4j 3@X\f|t}M꿼Bg; (Ҥ]p_bqӴtvZƘfa_̛hX.j{a3XEhgΜk;4P&NF%LNhIDPɋ):-gG_Oq7͢d|r .r|$GYR[{=O :o',ˑ#C&_BS7 /c\ʙ?_'8 Bl{qxxطE nWc8diDXV?1x35E.#|h .ACXȽb/BqXs |3V[u %&zY3.YOǓY[)L}=ٟ./3׬n"{h i˸rO,~o^H֎Op.ih_/A6c6872@ҘؔSxuOLgOpqӗ,W*)]x ;-z`5"2e-HI;_T^Ǽ^Jnϳmh'A0LMg)8ؗ%BV:g'by/XnL4 |S}ZE5ʠ{92O׊*D!"" Í\Z'忒b LHi?E?BG(wNϙ_ܬn.v$p& $̟<_vE9kN 8G%i f'ѪNC^Y0*z,'NT%u-8I{ן{鐈3f5꽘v^F5[V 7OsI d"dYlQU&Ŗ!u`jɱz{W]\ 4.ڟqu^%Er0lXO2! Қ 5]d%Âճ/*Jd9E`"p+p *`\Owv8 jJL0Cg\)mU.Ff)7%-W}z_U%"RI*le4뙐D?bqvZUEc_~$WitOTLMVGznq*Q~O89ϗS,PX[G~΂׌POS{B{Mxi2I|6x{l:8h; C {!TKGMG7"q x]j[G P„e/wދ ߼[+QgvU3x冀 $OMFUI Os~gW"U271D2]ML'~ޟ1ZqWZPޤHaCcvp5SӬBr` ӪeȨ{3 _·D]c5KC=$8%ՂCk!8#h7/z)[r$.i {}Z0'f[bX͞jid'l*,•Dk;6RƓDjVhoNlUPo~ٖq{Ncu- ;N(.$3mD#4ògA,lɋ@ijp*Bv9O'm!۟8CW~ЕNՙpn [1yW( ?޼IL (vdnK[ҥKA]8Ma`h)$2giT: aވ0?6 ,g|R*Je # Zj`)k}EY30ESτTNaHt(2Ą $a?\Kk3&66aG/O0Ɋvek'M,*u}ZpfnB1 &Wt>؎ ޥORrV/tP?KE{޴T_i9Q1u=4|=7-h-pa0`hb&f?x?MCy5@KenﰧM\??Nj {<Ҳa;YV0rq}Ce3i޾r:3pdQ#hc8+2NyDV,loQ򸽩F_LP.@^ͩޤc 0s}_:oߊʟVh(K; i_S.rDFmcEќΝ+poa*M[%#0P=0L̘7cT!u[qakj$<*8G0gmhdg z(bND]KGNo5W̭6v&NbysKsFGJLhyx\fCY#ɵo)Ζݸn!f"& O3J6 &p҆eL }; g=E%$C'[1(h!^#`5`PΘ9؍8sR;(G?gߙP+CB.}Z|EukX=p ^MT͘]/CK],E^b Y~7H䳨v\X?>"L.5LyU;>Ϻ2<ɛ(3~Ifgvh3W60X^#XaytJ8Ke ic{>~KaշH*v^U m$Sb7Nf,EJ͟c;z7m{r7ah3+Qc҇o;УSծXSo1*B !tPe!J˘0ZÀZN Mdb[Nsb6v-FDѵRPYGc:F8 Xw>|ݕ\Grh$ b x$X(! Ő` G,U`]2+R̎7/~r'ؗ'D:$kDAjùRN4Elba6jdx,$2A3TLm`k~]"n[&OLVl>ajʅ) ǁd<\ {cSŴ^\D0xegFIX8X@(!:b"kMJ4$/֗AwJ|s9oD˂%)I V9b4?QfZ*/" u:jbHUM訮bZ\ 2Ju'KVclhI8b}jhیWN3\7S; ,]u eKe6go%Ϋfo `cmz>L(CVM4>Ϲ f̻ئH44w/nrQTD9述 9Q9nNID]k,sƢHM4F7qo&ZE.k仉OJ[y"᧥̅+ 0(˵4XD$`f} {$(wgЈø=./0K[yIsXLӎI 1%'? ">yc_1qOy,|d {wo=ޤa ڵC(Fe\/TmWHAe_jQhTkUEG)3 $ m8T  xbٟڼwM5F*$4V&y?RcOI|dnM`m~u=b;?=dr1rJ Iqo"~!\AgeO)H'$Z_B~~J{y=2 <)]H#D7+快/Lúz\ճdc*W~ 557Ůl$lcؑ[]Ԭު`bޞ40Ԉ`_9%$-ܫH'өg9]XG0v|gi~JqU+y\M+T91zSx_x^ͿWH^0lQx9U@ٍwhgMtv<[T:*fC"J7 Jy@g7jdt;Mɲ+ݙ\KhA0M܋L|m#\ɘ al"!9H8i?P9rn9oAhSuf>sSe_㔈nc ^tQhjAz0)_P]YCy1'hva.F5 m&Dpbs&1v[҈J6Йzkχv8Y^YHMIMC{TT6j.*Y/xSrF>¼*2󟴻'qIE Wwi_Ki*ᥩؐ`F ,Uh;'¸C1aWW%!}L51v=Bttm)pP0z| _t)ЩG ,m1}p 4/tR cM~֤q_>Cؾv#w]k;i*-L)iDB[[/~8it`pJ^)c3"Jk2x^z/i|r $pXE3${X_ABQn̿e^(閴6ȟf]կuNM )NmA]oN-< J*$f2/^hXoPl0 wO!֦'5>|OD]xJ`%@L%MZ{KYj:&/a77DC3$%VtRyUC6H7p(b=)# K9Y;)xFzf^YJ 4Bʈ41\BIM rvpcY _ag-fOcUet 煻*a&lWl ;N`uԫN%":" $& G[薑*Fj^սcV' L -}rĎ /P2 ѐahaE%J{0ߗ<Y  uUb 7YjG>u6J8ixAWи5lėmB3InbʚlKofiOCIjn\/b#:;!IB诸,r<^guc)9'=.Xd턼tW6#Z4'.jIsj IY .CJTKKïTPYhq೓Wז t8rѯ?e!^_C$%!B̥ ؇RWW*}tZ8{fFm: 8J}bUpn#J{`h 9W9 Ry~xa 1゙LC9י%'t4Lw4ߑI8@S3\ĝ/O茞hx.Y Fr_MM/vW [@άeQ1Ǡ^1 *LLpE&^4v]\V;Gy_\g z E\*Jy[2'aMH^%G el/0\ KXҧ9X\^W&4J9=3RozxƷX@il_9P9)ԀfphYTL M<~ihg0:m!We?_ $9Š|Bx!JYɗSβ-]6afsK~WIoaǢڇ^gm]3dop8Lt6QmnpQ_"u^ůM5|AFp8uHd ."wB_lCv؄ֽ$r/t1jL!71b *UvF/(&&h(D›Wnkub<_oO%,Ȫv2g6ó X+ƅ&ܰzj3|*˸;Zu,Hs-uX0GʪGȔ i]ݝ" /تN(>p;!#8̈́u@@'/DhY<4oІɥ2ĘD?o>ՆS҂׻;ö0.@.0񙢣zncRBJ!VFxoǖz7˞ jޕPR64^8؃(ܠL9heRUE%?X6Fp5qPrbVv }z*xpPMp]҆9`~6Sˆh-˚+O%ΚD@wj-=gEsUr?CS-' vx |W/_.~ Hlb6'r ߯faN"OSWkpԶ^ep8 HEB*NQ<$UysC> F/l|KZ|75$E"reT'r#R6aשbDӴ/Oѫ*|M zn9-f/JeR߆#[g]1l+ isf!ٕGm$Mj^DeD7ϻ*VN0۴yg4CXMzrxO [&G:Wy1ai%GV'ۖtWz>b2,6/qjRoL _G+<~zNVmDnn?%EJ.:"UC0~uP]LioK>Ko="6) >oij :TW^dD, $1W`| Y= )dȮ8hݶ̧/h3P>&e{+^^R?IAeI9@!o= }"'+Z"CXkd8K?XB3`q(*&S3E$v#5:2OHw&1wECϟɲpG64^׳֔jQ> 3I-_ׁԐy_n~Ϟ9޿Q#wezKle,+{f8B}+jE%(9l]6drֈ?.% +2o@'jfz@P{s]O/B6Tƹk辸ut'։%֚{h>SC) D}#ʿi;2f i85RYXFHҞ]^TCf2 !yobYxLJ8i$Ͻ$,"DO5u ɉ6{ ?7~b3ݏ =?8Ws)8X4 wrrWx mdx-VtQ:bCyYS;~b1Ҧ!' gEhyL wz ;׋H6@}3 Vss(Sq1B|(!-/oart29n}R-\l68`zKsR lPHd# Gxc%΄ lۅ_^\/kֽ*J ҚA괙okvPM-Nq˧iz0œE̳8LcQ2OU!{jzԸZD3NDeKLqؗ th1 zkTƠwނmLF_m-+m'l~hщmz?uE.&7V jŃBu|A,jE62t}i{%$kwi_kozNe%P׶-qyAK[@ķ/~E^bKYta{qz_JU*[rz2g=%rبo4Ed8i0SqKd0pw3̌%OafBѿmYOF3c^ڜ[x&}Ҵ }TT+$hq]hdl!;}weh< Wfr7Z|Q!pd[J),> 9,]( J[/qiy$iLr4\:&(*,DM{ePYkrl|jC4R夀B>TӇ?DǓr\~.蚨IabMUWF~q"< l:i㐒f;Yqf)%`i\dJ" }rT#jjZ,/ULP˰Kg=0M(h`<&GHb-N?I(cyΎo_6LjJqӋs6r.Sdu>?d/ź7e7% =e˞5}Ɠ d6y΄&ʋ[Vˬ'gfIePK7ESG%dN QΡơ8KB|v5RBA>܅DxLS{aR\d)TN )IT@XZta˪/7Fouֳ}Ep5D,#ypdk wo{g}Dz`,c$H'mtӒ<橉epwk˺ݯ5oZ\|;`PCIsK}X4M=@ia=-1'7IJ N+x%ZD2AI8Uvxdf\2NOm On&AIE9j}*qq3xQ@|4UI5/ED_ۺJ^:~RUሧX&]3?:$|F֦`<3pd7۴Ѥ8 uUIR{4U95'9b[ꇼr!g.491.g|Q˨gU'׍KeSH aټI҄FA!Y!,<waCeiߛ(+Z\GXknoz 鑊)2wPJ+ _'7^UT*kM3LaWZY~ Hp_1ѻ#vqmS:Qg. $KV}<2,@°;$qҩ2$p`KT*^3.I6B Q!S@ܛjՁ>ϰ<`ѧ0^h7`l3 NW>xgMIVAw|%%޽^obWsPLts(oj{xn+jݕ^{udϑdFcHc{Wy%בhZw5XE*2aZĕ}OUڋS`Hp tnǨI7CcBBKgݮ%5B`*IUV1Rl)'reس᝱[ {U";WLQ\'?O`Hm.ljyJ /%l&~d7M(}'5ȅU"iɰY2vP@)4+`>][y[pGA #\ hF^"6DijJ>~ C;8٫G&X*Sw`OO]M2T[{%RD[M!^Tg dsYǍ:b:q=#s:BC_M`uAX^2,)i\)5pQ(2+xd4W& Yw^;00,@Dg·iMbGDtſ,Йy):*ʵ(RܘCgRJY\2` pOe(-i<{~1Ǣ$[X8Y?wAkj1對Bi`l^S%?$ Re)D/Ȗwβ vai'K,k +.7[d[o͵7/6`@qI4faRg%ۭ(k~uQ#%I[e8 6v(e&3esurNz.C*T< 2 v麐;n>0٬OtIYޤ|q2/~Hlf}TlzB nvH.?td!z>Ü#0+D #o&~R\A&҈ o =^>7/$+ ubW |պVn~o_fl趝E > 6ڢdFg(9$67:/(Y ?-dp"TJ]YezyM{m,2yɣX2X!Kn*f_۱0SE_wHRbZW<)i%KttG,kڭ:б-n1.H8b}{ pN?0Vb^}% %i !t&X}\yʙnX]8yl.ۅPHpf/{ܒ]\2mgBy6ǝ>,M)s3m;Y mUBC2(Q!0J\{^uOsyjڟ 1WvuRŵ˫.%ߏ7Xӄ"CPTPڻ[&ܜňX֊<}$>R҂M\y)97$'"3u;2'fUA dY!$[.z=}w\2ϻP: -b]({s!S]$D %z|:XÔRRDm$MOGMj:R{BnU>Y/LWʼnM\G ތKLm2ݯ2l80|=!ύZ5ɩ%])0  Γd ]}Zw4y5$nh݃@Kb]z˳ZвH|;`Ͷ{DbةFu܁K!<q f&U< 2el ,OD.%:fSds5JZ  ,rC^DMJՄHp{-;Ъ\`D~'/HVZ<12Ug5YT`8I'&`F-Fko1 *Z7`7RؑHܫP `auenKv{fՑA 'm]iO?}9'\;5N,W^{IV w;p߿iU÷3q#Ѕ9t^ܶޜ?>v_$z% ֢bVv"#ނ&w.`. 0ji0QowB(m? ?d=6,K9 >aqi|Ì$"Y[ORvQOS8& f.:g [qf^ai< P¹k'^qoiqSIzd-uLcwvG7a(2҇Cx!hO"a\ЇzM<t0HZ3v ֞`,ʁG-I%a<y5mknJLɲe/{@oAtq ։(^)`NTP.*2n#9@ -㾉$ـ\`*[A{/. k| Ω5 8(8@&t=J芤w:d$ * QdF]*<3'Z #le奄 zhf̃% E(.xe[oU>}6{,gbtlq?(y(1H+:k,2J6%L1EX sf?`>@! & J2ጲ~)- 0Eȟ eHd6sRߠU~Ayg.p;(#(V0@ &(<Ԕw^0TÇaIXP Ia&NWw=e*;Cȟ0u다ph? ">Wd/S麐jGFu7S&qĆ:"7oNm27ڤy$pRpeŕ `L/,en2>0[yLQ /ZfI`V307y=ATq)G<k4&t[qT&럶fy\ gײ5!ڜ\D wdIrOe$eצ֍c{XM@Cux'yFPo3aY9A$-\O#ڤjm(EʇO:!{X6Rs.'J ϚןgT?ߞ=LhxN.!zJ IZ:Sr%_p eLe qvƈIȞۦ s$*@}pl\~ΝuQa : \UJuMU8,w_$&2Pbۍ8^U(AF  8"4 :+vqv?dQ?WuЇ6fLHuX'+C%#|hp;՗aDJNCN:]Sm0Du5 (Mn;SWVryaqJ914Lo$?Z|LRv?w֞ЇtKY`OE7xXzX 7kz>y•2'-λ1(|GֿwXtM'>G4e Z E#(+jrG'7)}<H5R0N;\^VQM|֯(۹{I-آ{u$|7u!n,a5Q!V %JFVح2 iәڭ}o15#5o}NWȀzLTT9j[K2/l|eK9+z}q*lC/h1𬁇q /W'KǙ9)PE`8;,F)aBzKBr&Rr7.A[M_tԓ8U/N)<?`l1: lh"jZrၾQV S\4fqsY0D&^`;BETR:@ e͋sPfrGPP"L ZcFaUAvh7IQ`S\)yXR"/F'6N$H:qP_YhT4AץE@zbe9)UyU%#_( |N;,dY&ޔolE#{*2d$tZҜ _\CZDueW 2V*8z w>l~bDt+iZFh 2⇀M4?l0z6x$΋l tIW=j{$tX&adWFGj$zZ;]#RH8]MqdԿ񑀀RMEk5N U׉SOK໌~{LCm';%SCY-` XsV)Uy:Q}[c_4OY16x>L&w ilSQ _aS,{b#Ȅg[E(z$r=q!q %l[-}RIc1gx#Yc:7_>y2O>g'B 挤T~ nH^= ҶtVm ge'.'_N f|ZG;;?j-vu?m̦)5< 0Tp:\|u@lY:IԑNI :9J-)8|P@lWxŁ !ahM†T^mHw{0xaǐBtZcΤaq/\qtUUc-Ev98TS8bqUX!Hsϛ>84}0;arMl١qX " ԍm,dgt׹5kAq_- *ú6[(߀hY륀 Obx(ݭJ$#p xzTb%c\R1Բܺ짨I-[M@L3X C Ug/-9r&p!FTBrƪTůĀ 0*rj9bVQ? 7ftNc쒍,A$'fƎ%Х[\GF .uj 1yFFT0]&j%.Bkpi xhP%]޾⫽$L|1T+QWwܛ30;==6;Qi;po ԩt;8xϤP]Bش_ԪBτ.%`*4 ?o )L9dG4ߖGi?>=ڦAwLˆO.>næ3l AQt[cObkѽB-._WfTɡ-a:#JOUKw&rK'&:A8+#(䙻\i#y7C:t:}UI] i(!Tia4Yw< ;agd+DYXA ܨjB+iu)Ӊ;P5m6⾍mR0:;3U+Q I3EJ; C8oۖ6DmN8=`\p;, ZS ?)w nS.Sxk[ja2xeReVU-FI+8&ϸKN/"4*]#! Lx!YK KXqK^w80jdˠسaw}'4 d"O䇻cǡs29wq=(zpRh:b 9LwE4C^@vA.T*͟INZ£]nL@L -]| /3 (~W07*-V}B!YR`$\P prS-<#.m=I C=rCB#tj+$t( Ea8$KyqnRzԐ:'LmBbm X &Tф+<@(lB$p~:.xH?eUnIVv|w nKydU ^gA^dvL59+Ggō;kZg$*>zqe.(,h$YG11gqR95op^ 28i˖{ ޥϱtx. gA%CBH-N2Xpv,$B9U^4vwPδ&H^FY9S5b ]T3%[]UHz*SR(n;J$fY u'v8/Vj8 H );&΀P ή=zqlOSzy#RU]6aBNa1,n#T^! tĮ'YA_|476 D!D, ǰ*Y{J*pB$d%3&){˃+heDa+v+D,1V38!Ӧ!q@cQx/冼" ,wÙO~XQp C. bjr]%vXtS\EPM,#SM@@ݤ䟹^;,YwF~Ydsz бQ+/"B$t3 ?i&T*p.H)rAt3# }fEuF)l';K~l=yJp\}IoNCxC>m6qY:'.ߴDYI,}!45T Q}Rx&>J}M1QLWhV@OAӵ+ߍ*-xKԓ,cB{Jf\ު `,v2q43կ\pe(ܪM:4׳anORw[*4hXZn eyUctL>Iq\ℐ $#m5TBN^)I7{^2_pUs͠2è,;$ ڂ5x鷷6N:%h<.9cCbF!ܓ}>B_PJ[3IA-`V/p@' W*"BQg-~1Ɣk)d WU< GXMC }l"ov=FD'Z4ٍ2gǮ'M^p1JQ%bf5q+͂lCqwvqVHSө:͜ w󊦑 CJ§Wv*)-MLd"2 ((E#4&0elr2|?<)UQt:r~ٍrrF TM_/M 8XǪ0;q?k yk'@’Ζ+`#ow{:E rԑFRJ'ByJOpIcbYkz "@a'Ƕ. OVNq#1!ƈ  @\9,B%ʤ͟}0->K}HL)u[pQaCZmXAOq\, ۋx [/2iA Ve/AG3ӈ2JUrxE:0n%tm91u{1ҨEץB.I{ϑ)B@Qg.c[]}B0BFlE `}(qFrC*t YQ#4\. k>iNm 6f_"Yؙ{Meh$q&A-W/"0 '"M:^pX DaCLK6bk 3jo~E[L͂Z[{ݺ'1G8(u1?ľ5̒- hrQSeZ:AU}k@am]`rgyOYTA )38i^7YáY]+ i h#&Е0RTxi7/߶;gqN=;֞>PwV}~Qg)Y7+kpXl5ֹ=aىg `<=}=%EdWO:zJ~3t͓{MJ+d o2iM/ܙ+DUA8]\8x3-98we xc'gOQ|ǎ5!USI]d:Õ^V'/Mzܴ9.E[[޺6]V-]1n`4y0wXK[݂EkFnk DAKClCBww嗤ߎ'!qU3ZuZ1 ut8[SCPV@DfyqZQig*^%6rЗ$IBM6# rIuֱ߭tc"֒á 3W9m\egfҝ8sMh֠bQvk&n@0J;ښATekpcݙ#2zc%/JŰ`B¯6|z{# tZ:u̘|"Lq|H вrN],=zהqOi˼5BHԑޝcERIˏk!cr9~{l-$طX<ɹO/\Q5BhB㱑qѫqr7 (X*ݤzmI -+0SUYBYDiXW9Sv!H,¢?vpț0ѻ~OyUqRtEZ"6x5" s6R*(,z{ۡG )?aLQ4N[ŸD͇%ms2!j%1F`.=) KS-3v]:Ÿ^ Z 6bY_%tɉ,f%䭷 ˛MKZ;ռYzݘu-g_ :Q+:]yTrWs,ݡ*+6}럓]}O$>/3f <3)^ eUIS`C*ɅŰL?+WO'9/nZnZ7"f}bfJxgT_a: 6B3[ԠJU kL>`{?c:&7\[v}wBCi!1_IMvWKbR*뭚8ȕ qI|\yJde]\Vz=VtC>nWks< }Exr/~Kh64s@%PZ*h^vjb ns$l67bƄ&q^g%ҌSxnpt5&*?j“$l`2 gC;GcVi0LvbKNr#{-uG<ʖLD$Xl = OdV /h!nEP$dAX' <40d]P^>\qaNq)Bps(ڠķrgSHUzFW@8&a$ 8C!%Z)V,|vKq ".[O%$.@ZIڡC+R߆7lwI#yssB#iQaeD e9X7 .m `ygvOHT!(ZFU[hd] pYl8"B}=[| ^7͎_0 IE16Dy꾃)'eν~]1 )5F%jD'LIU, WQ/d@|̈́n$.=35I'!_DJY3y_y.+h>'*н(ω(ZYݝ11{ {Ƚ < ҷ2FT2J"%wJs`ESLfpPS1 a)zWBf}xxq5R9>/'&mo1l^l=%?&i)2+'p{ups/` im<n~6+܃7JXZޒ qc-\] pYL(٫ٹTd߶YXhF%0qH>e'F_3I<ɧDPYS ٕ&7P錟~4gSEY^ yaEېC9-Z270$83j4\ʈOd &:.Fo,: ~/VOj<.QC]+~nGJV~-gC 6$Hr}QN@E{:K0vXbN#g9 xeޖt:s[k i>ED>7k_F:Ip' B0 /"e=B!Zs:Dhˍ0(BMM*B!pCZva1EP94ʱ8`h^с⁾/n[4J8Ii|2 oWx7%/}vLʈQ]$9tM]6|:X/v!8~5 ܜmOƇ{KfoJ J7L '^t?FW%ñ uƐʹ'F@ 7麬{gmQxֱo ˗қ.o$+ crpgQK+d0uł7u;o:T1_l=G~hv' ~@ov?/-鿅t,Of&x8 g_Cl6)9zZ^U{@@HH%YeƸ.elt/ѐ\с(݋}͞w2$NDGӲ@Sw}`T\}TrZSYgi%VVǥ-;Tͨ&ļS6Jc;+W=Fn]g o c hMR2yF=TZd-}Bn҇18OT5Y;̞lԝ3oΦA}<ӵzmc2|HÓFk: z*=kn92v1J!TYngOjZu[6+@ 4KBQ{S«QY 3c:"Jy2EftU9>7CmGJUlzPRuer`5hl/xW8&LǽL?9\LʭSV|GȢLҷLAҜs?y?PWHl3TlDX4E I lȑMCp6b_4L"y/1(q ǃpYOpecsђsTLY3ץ{)"hUUr#\G+6ƚL(yW J.ڼJDuq?>R2K^LD) \[%C^q,K$aժXhҕbF_6Y֋-"f{ ~3L{*@TjŦlIC<(y<(FR;}Q_{GbuL5&ɼŬ'ލPّ| ,*i'ٯ'`Uj-S4%YH7]7o 9ӑ]`}pTqz tniua}&2HVd`{x66ҭ :SqN')HBHb~2u!%Ip Ƌy] ϖχo4C0C4\6JkecJ.%f-RYS7b#u8W}4. "^ݧ@e (tˏFK,.F A=L}@⏮zq~`K&\U+b J7CwMߞYvhS+7ψ[`sAP{DJ}vէN^P@ Z"z&{ NiD5'4^e^)MQtl j/1Fi> ,N=v2iojю 6\ INxfklkn κDI%(%c=Q>v3:li &K,(Qc+{PHgKEgʄbňz~}\UGS":ӿj@s!g#f݊\u^jZlfH:gix,I `vO` crx@jSWLB^q" zO.2xۘ7ِ٢Na}i]'vlL71"- RX%IfQqu?T+_%Ӕn4M!g=g^+atzX[ BǓW<ಌ ™*gctLS{\6jL}(7Lvf )&)[\׌ @zR$@)#K%Abd<$:Cn-,<5s[tE*1 1l݌?yNUq&"\{N-T&6WN紅+}Q*Cȅ歍F?йr4Fp9!J5dJrk=]pvqb*{/-ÊP-_ Œ-)QKh d7Rɑb9 magic-wormhole-0.7.6/wormhole.1000064400000000000000000000022041046102023000144640ustar 00000000000000.TH WORMHOLE-RS "1" "May 2024" "wormhole-rs 0.6.1" "User Commands" .SH NAME wormhole-rs \- manual page for wormhole-rs 0.6.1 .SH DESCRIPTION wormhole\-rs 0.6.1 .SS "USAGE:" .IP wormhole\-rs [OPTIONS] .SS "OPTIONS:" .TP \fB\-h\fR, \fB\-\-help\fR Print this help message .TP \fB\-v\fR, \fB\-\-verbose\fR Enable logging to stdout, for debugging purposes .TP \fB\-V\fR, \fB\-\-version\fR Print version information .SS "SUBCOMMANDS:" .TP forward Forward ports from one machine to another .TP receive Receive a file or a folder [aliases: rx] .TP send Send a file or a folder [aliases: tx] .TP send\-many Send a file to many recipients. READ HELP PAGE FIRST! .PP Run a subcommand with `\-\-help` to know how it's used. To send files, use `wormhole send `. To receive files, use `wormhole receive `. .SH AUTHOR .TP Matthias Geiger .SH COPYRIGHT .PP Copyright \[co] 2024 Matthias Geiger .PP This manual page was written for the Debian system (and may be used by others). .PP Permission is granted to copy, distribute and/or modify this document under the terms of the EUPL 1.2, or, at your option, any later version.