sudo-rs-0.2.2/.cargo_vcs_info.json0000644000000001360000000000100124310ustar { "git": { "sha1": "f3171451e551cedee60bffb91e910fa5346bdb94" }, "path_in_vcs": "" }sudo-rs-0.2.2/.github/ISSUE_TEMPLATE/bug_report.md000064400000000000000000000013541046102023000174410ustar 00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: bug assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. Please check the issue tracker for similar issues before opening a new one. **To Reproduce** Steps to reproduce the behavior: 1. Compile 'sudo-rs' '....' 2. Write the following contents to `/etc/sudoers-rs` '....' 3. Run the following command '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Environment (please complete the following information):** - Linux distribution: [e.g. Ubuntu 23.04] - `sudo-rs` commit hash: [e.g. `d085c0a`] **Additional context** Add any other context about the problem here. sudo-rs-0.2.2/.github/ISSUE_TEMPLATE/feature_request.md000064400000000000000000000014061046102023000204720ustar 00000000000000--- name: Feature request about: Suggest an idea for this project title: '' labels: enhancement assignees: '' --- **Describe the feature you'd like see implemented in `sudo-rs`** A clear and concise description of what you want to happen. **What problem can be solved with this feature?** A clear and concise description of what the problem is and how this feature would solve such feature. Ex. I'm always frustrated when [...] and this feature would fix this problem because [...] **Describe alternatives you've considered** Are you sure this problem cannot be solved by an already existing feature? You could also add any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. sudo-rs-0.2.2/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md000064400000000000000000000010601046102023000227760ustar 00000000000000**Describe the changes done on this pull request** A clear and concise description of the changes done by your pull request. **Pull Request Checklist** - [] I have read and accepted the [code of conduct](https://github.com/memorysafety/sudo-rs/blob/master/CODE_OF_CONDUCT.md) for this project. - [] I have tested, formatted and ran clippy over my changes. - [] I have commented and documented my changes. - [] This pull request will fix issue https://github.com/memorysafety/sudo-rs/issues/<#issue> where a proper discussion about a solution has taken place. sudo-rs-0.2.2/.github/codecov.yml000064400000000000000000000002611046102023000147250ustar 00000000000000ignore: - "test-binaries" - "test-framework" coverage: status: project: default: informational: true patch: default: informational: true sudo-rs-0.2.2/.github/workflows/ci.yaml000064400000000000000000000271471046102023000161100ustar 00000000000000name: CI on: push: branches: - main pull_request: branches: - main merge_group: branches: - main jobs: e2e-tests: runs-on: ubuntu-latest env: SUDO_UNDER_TEST: ours SUDO_TEST_VERBOSE_DOCKER_BUILD: 1 CI: true steps: - uses: actions/checkout@v2 - name: Install rust uses: actions-rs/toolchain@v1 with: toolchain: stable override: true - name: set up docker buildx run: docker buildx create --name builder --use - name: cache docker layers uses: actions/cache@v2 with: path: /tmp/.buildx-cache key: docker-buildx-rs-${{ github.sha }} restore-keys: docker-buildx-rs- - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: "compliance-tests" workspaces: | test-framework - name: Run all E2E tests working-directory: test-framework run: cargo test -p e2e-tests - name: prevent the cache from growing too large run: | rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache compliance-tests-og: runs-on: ubuntu-latest env: SUDO_TEST_VERBOSE_DOCKER_BUILD: 1 CI: true steps: - uses: actions/checkout@v2 - name: Install rust uses: actions-rs/toolchain@v1 with: toolchain: stable override: true - name: set up docker buildx run: docker buildx create --name builder --use - name: cache docker layers uses: actions/cache@v2 with: path: /tmp/.buildx-cache key: docker-buildx-og-${{ github.sha }} restore-keys: docker-buildx-og- - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: "compliance-tests" workspaces: | test-framework - name: Test sudo-test itself working-directory: test-framework run: cargo test -p sudo-test - name: Run all compliance tests against original sudo working-directory: test-framework run: cargo test -p sudo-compliance-tests -- --include-ignored - name: prevent the cache from growing too large run: | rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache compliance-tests: runs-on: ubuntu-latest timeout-minutes: 20 env: SUDO_TEST_PROFRAW_DIR: /tmp/profraw SUDO_TEST_VERBOSE_DOCKER_BUILD: 1 CI: true steps: - uses: actions/checkout@v2 - name: Install rust uses: actions-rs/toolchain@v1 with: toolchain: stable override: true - name: set up docker buildx run: docker buildx create --name builder --use - name: cache docker layers uses: actions/cache@v2 with: path: /tmp/.buildx-cache key: docker-buildx-rs-${{ github.sha }} restore-keys: docker-buildx-rs- - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: "compliance-tests" workspaces: | test-framework - name: Run gated compliance tests against sudo-rs working-directory: test-framework env: SUDO_UNDER_TEST: ours run: cargo test -p sudo-compliance-tests - name: Check that we didn't forget to gate a passing compliance test working-directory: test-framework env: SUDO_UNDER_TEST: ours run: | tmpfile="$(mktemp)" cargo test -p sudo-compliance-tests -- --ignored | tee "$tmpfile" grep 'test result: FAILED. 0 passed' "$tmpfile" || ( echo "expected ALL tests to fail but at least one passed; the passing tests must be un-#[ignore]-d" && exit 1 ) - name: prevent the cache from growing too large run: | rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache compliance-tests-lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install rust uses: actions-rs/toolchain@v1 with: toolchain: stable override: true - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: "compliance-tests" workspaces: | test-framework - name: clippy sudo-test working-directory: test-framework run: cargo clippy -p sudo-test --no-deps -- --deny warnings - name: clippy compliance-tests working-directory: test-framework run: cargo clippy -p sudo-compliance-tests --tests --no-deps -- --deny warnings - name: Check that all ignored tests are linked to a GH issue working-directory: test-framework/sudo-compliance-tests run: | grep -r '#\[ignore' ./src | grep -v -e '"gh' -e '"wontfix"' && echo 'found ignored tests not linked to a GitHub issue. please like them using the format #[ignore = "gh123"]' && exit 1; true build-and-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install rust uses: actions-rs/toolchain@v1 with: toolchain: stable override: true components: llvm-tools - name: Add cargo-llvm-cov uses: taiki-e/install-action@v2 with: tool: cargo-llvm-cov - name: Install dependencies uses: awalsh128/cache-apt-pkgs-action@latest with: packages: libpam0g-dev version: "1.0" - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: "stable" - name: Build uses: actions-rs/cargo@v1 with: command: build args: --workspace --all-targets --all-features --release - name: Run tests uses: actions-rs/cargo@v1 with: command: llvm-cov args: --workspace --all-features --all-targets --release --lcov --output-path lcov.info - name: Upload code coverage uses: codecov/codecov-action@v3 with: files: lcov.info build-and-test-minimal: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set rust nightly version run: echo "NIGHTLY_VERSION=$(curl https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/rustc)" >> $GITHUB_ENV - name: Install rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: nightly-${{ env.NIGHTLY_VERSION }} override: true - name: Install dependencies uses: awalsh128/cache-apt-pkgs-action@latest with: packages: libpam0g-dev version: "1.0" - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: "nightly" - name: Update to minimal direct dependencies uses: actions-rs/cargo@v1 with: command: update args: -Zdirect-minimal-versions - name: Build uses: actions-rs/cargo@v1 with: command: build args: --workspace --all-targets --all-features --release - name: Run tests uses: actions-rs/cargo@v1 with: command: test args: --workspace --all-features --all-targets --release build-and-test-msrv: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install rust uses: actions-rs/toolchain@v1 with: toolchain: "1.70" override: true - name: Install dependencies uses: awalsh128/cache-apt-pkgs-action@latest with: packages: libpam0g-dev version: "1.0" - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: "msrv" - name: Build uses: actions-rs/cargo@v1 with: command: build args: --workspace --all-targets --all-features --release - name: Run tests uses: actions-rs/cargo@v1 with: command: test args: --workspace --all-features --all-targets --release miri: needs: build-and-test runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set rust nightly version run: echo "NIGHTLY_VERSION=$(curl https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri)" >> $GITHUB_ENV - name: Install rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: nightly-${{ env.NIGHTLY_VERSION }} override: true components: miri - name: Install dependencies uses: awalsh128/cache-apt-pkgs-action@latest with: packages: libpam0g-dev version: "1.0" - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: miri - name: Run tests uses: actions-rs/cargo@v1 with: command: miri args: test --workspace --all-features miri format: runs-on: ubuntu-latest env: RUSTDOCFLAGS: "-D warnings" steps: - uses: actions/checkout@v2 - name: Install rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true components: rustfmt - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: "stable" - name: Run rustfmt uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check clippy: needs: format runs-on: ubuntu-latest env: RUSTDOCFLAGS: "-D warnings" steps: - uses: actions/checkout@v2 - name: Install rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true components: clippy - name: Install dependencies uses: awalsh128/cache-apt-pkgs-action@latest with: packages: libpam0g-dev version: "1.0" - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: "stable" - name: Run clippy uses: actions-rs/clippy-check@v1 with: name: clippy-result token: ${{ secrets.GITHUB_TOKEN }} args: --no-deps -- --deny warnings docs: needs: clippy runs-on: ubuntu-latest env: RUSTDOCFLAGS: "-D warnings" steps: - uses: actions/checkout@v2 - name: Install rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - name: Install dependencies uses: awalsh128/cache-apt-pkgs-action@latest with: packages: libpam0g-dev version: "1.0" - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: "stable" - name: Build docs uses: actions-rs/cargo@v1 with: command: doc args: --no-deps --document-private-items --all-features audit: needs: clippy runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - name: Install cargo-audit uses: taiki-e/install-action@v2 with: tool: cargo-audit - name: Rust Cache uses: Swatinem/rust-cache@v2 with: shared-key: "audit" - name: Run audit uses: actions-rs/cargo@v1 with: command: audit sudo-rs-0.2.2/.gitignore000064400000000000000000000004521046102023000132120ustar 00000000000000# Generated by Cargo # will have compiled files and executables /target/ /build/ # These are backup files generated by rustfmt **/*.rs.bk # Code coverage in lcov format /lcov.info # Generated man pages /docs/man/*.1 /docs/man/*.1.gz /docs/man/*.5 /docs/man/*.5.gz /docs/man/*.8 /docs/man/*.8.gz sudo-rs-0.2.2/CHANGELOG.md000064400000000000000000000110111046102023000130240ustar 00000000000000# Changelog ## [0.2.2] - 2024-02-02 ### Changed - Several changes to the code to improve type safety - Improved error message when a PTY cannot be opened - Improved portability of the PAM bindings - su: improved parsing of su command line options - Add path information to parse errors originating from included files ### Fixed - Fixed a panic with large messages written to the syslog - sudo: respect `--login` regardless of the presence of `--chdir` ## [0.2.1] - 2023-09-21 ### Changed - Session records/timestamps are now stored in files with uids instead of usernames, fixing a security bug (CVE-2023-42456) - `visudo` will now resolve `EDITOR` via `PATH` - Input/output errors while writing text to the terminal no longer cause sudo to exit immediately - Switched several internal API calls from libc to Rust's std library - The `%h` escape sequence in sudoers includes directives is not supported in sudo-rs, this now gives a better diagnostic and no longer tries to include the file - Our PAM integration was hardened against allocation failures - An attempt was made to harden against rowhammer type attacks - Release builds no longer include debugging symbols ### Fixed - Fixed an invalid parsing when an escaped null byte was present in the sudoers file - Replaced informal error message in `visudo` with a proper error message ## [0.2.0] - 2023-08-29 ### Added - `visudo` can set/fix file permissions using the `--perms` CLI flag - `visudo` can set/fix the file owner using the `--owner` CLI flag - Read `env_editor` from sudoers file for visudo - Add basic support for `--list` in sudo ### Changed - `visudo` now uses a random filename for the temporary file you are editing - `su` now runs with a PTY by default - Included files with relative paths in the sudoers file are imported relative from the sudoers file - `sudo` now checks if ownership and setuid bits have been set correctly on its binary - When syslog messages are too large they will be split between multiple messages to prevent message truncation - We now accept a wider range of dependencies - Our MSRV (minimum supported rust version) has been set at 1.70.0 ### Fixed - Set arg0 to the non-resolved filename when running a command, preventing issues with symlinks when commands rely on link filenames ## [0.2.0-dev.20230711] - 2023-07-11 ### Added - Add initial `visudo` implementation - Add support for `~` in `--chdir` - Log commands that will be executed in the auth syslog - Add a manpage for the `sudo` command ### Changed - The SUDO_RS_IS_UNSTABLE environment variable is no longer required - Sudo-rs will now read `/etc/sudoers-rs` or `/etc/sudoers` if the former is not available. We no longer read `/etc/sudoers.test` - Removed signal-hook and signal-hook-registry dependencies - Improved error handling when `--chdir` is passed but not allowed - Properly handle `SIGWINCH` when running commands with a PTY ### Fixed - Only call ttyname and isatty on character devices - Fixed a bug in syslog FFI ## [0.2.0-dev.20230703] - 2023-07-03 ### Added - Add `timestamp_timeout` support in sudoers file - Add ability to disable `use_pty` in the sudoers file ### Changed - Set the TTY name for PAM sessions on a TTY - Set the requesting user for PAM sessions - Simplified some error messages when a command could not be executed - Reveal less about what caused a command not to be executable - Continued rework of the pty exec ### Fixed - Fixed exit codes for `su` - Fixed environment filtering for `su` - Fixed `SHELL` handling for `su` ## [0.2.0-dev.20230627] - 2023-06-27 ### Added - Add `passwd_tries` support in sudoers file - Add developer logs (only enabled with the `dev` feature) ### Changed - Only use a PTY to spawn the process if a TTY is available - Continued rework of the pty exec - Aliasing is now implemented similarly to the original sudo - You can no longer define an `ALL` alias in the sudoers file - Use canonicalized paths for the executed binaries - Simplified CLI help to only display supported actions [0.2.2]: https://github.com/memorysafety/sudo-rs/compare/v0.2.1...v0.2.2 [0.2.1]: https://github.com/memorysafety/sudo-rs/compare/v0.2.0...v0.2.1 [0.2.0]: https://github.com/memorysafety/sudo-rs/compare/v0.2.0-dev.20230711...v0.2.0 [0.2.0-dev.20230711]: https://github.com/memorysafety/sudo-rs/compare/v0.2.0-dev.20230703...v0.2.0-dev.20230711 [0.2.0-dev.20230703]: https://github.com/memorysafety/sudo-rs/compare/v0.2.0-dev.20230627...v0.2.0-dev.20230703 [0.2.0-dev.20230627]: https://github.com/memorysafety/sudo-rs/compare/v0.1.0-dev.20230620...v0.2.0-dev.20230627 sudo-rs-0.2.2/CODE_OF_CONDUCT.md000064400000000000000000000002211046102023000140130ustar 00000000000000# Code of Conduct We abide by the [Rust Code of Conduct][coc] and ask that you do as well. [coc]: https://www.rust-lang.org/en-US/conduct.html sudo-rs-0.2.2/CONTRIBUTING.md000064400000000000000000000057151046102023000134620ustar 00000000000000# Contributing to sudo-rs We welcome contributions to building a memory safe sudo / su implementation; this document lists some ways in which you can help. This project is about building a "drop-in replacement" for sudo and su. That does not mean we want to copy *all* of the behavior of original sudo or other su implementations. Whenever we add a feature, sudo becomes more complex, and unforeseen interactions due to complexity can result in security issues. Also, sudo has some features for backwards compatibility only---it makes no sense for us to re-implement a feature that by its nature won't be very well-used in practice. Other features have a very specific use-case in mind (for example, matching command lines with [regular expressions](https://xkcd.com/1171/)), which are very complex to use and would require the inclusion of a third-party library. I.e. every time we add a feature, we have to weigh its benefits to the cost of adding the feature. For this, the sudo-rs Core Team has adopted a few criteria for inclusions of features in sudo / su: 1. Security is more important than functionality. 2. Simplicity is preferred over complexity. 3. A feature to be added should actually *solve* a problem. 4. Features must support a common and reasonable use case. 5. Dependencies must be kept to an absolute minimum. ## Feature requests The easiest way to contribute is to request a feature that we currently do not have; use the issue tracker for this and explain the situation. Things that are currently possible with original sudo and that pass the above-mentioned criteria are likely to be accepted. ## Testing sudo You can install and run sudo on your personal system, or any other non-mission critical machine. We recommend installing it in `/usr/local/bin` so you have original sudo as a backup. Although sudo-rs is thoroughly tested for every change we make, a real-world test like this can uncover subtle problems in technical parts, or uncover common sudo use cases that we ignored so far. ## Small contributions You can also go through our code --- if you see any small mistakes or have suggestions please create an issue for them. If it is really a minor issue, like a typo or formatting issue, you can immediately create a pull request. ## Security auditing One way you can help is by looking at the security of our code and proposing fixes in it. More eyeballs spot more problems. If you find a security problem that can be used to used to compromise a system, do follow our [security policy] and report a vulnerability instead of using the issue tracker. [security policy]: https://github.com/memorysafety/sudo-rs/security/policy ## Working on a bigger issue If you want to pick up an issue in the issue tracker, please reach out to the sudo-rs team first. The easiest way to do this is to comment on the issue. If you want to work on something that is not on the issue tracker, do make an issue *before* you begin to make sure your work will not be conflicting with ours. sudo-rs-0.2.2/COPYRIGHT000064400000000000000000000005151046102023000125150ustar 00000000000000Copyright (c) 2022-2023 Internet Security Research Group Except as otherwise noted (below and/or in individual files), sudo-rs is licensed under the Apache License, Version 2.0 or or the MIT license or , at your option. sudo-rs-0.2.2/Cargo.lock0000644000000025710000000000100104110ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "pretty_assertions" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ "diff", "yansi", ] [[package]] name = "sudo-rs" version = "0.2.2" dependencies = [ "glob", "libc", "log", "pretty_assertions", ] [[package]] name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" sudo-rs-0.2.2/Cargo.toml0000644000000024220000000000100104270ustar # 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.70" name = "sudo-rs" version = "0.2.2" publish = true default-run = "sudo" description = "A memory safe implementation of sudo and su." homepage = "https://github.com/memorysafety/sudo-rs" readme = "README.md" categories = ["command-line-interface"] license = "Apache-2.0 OR MIT" repository = "https://github.com/memorysafety/sudo-rs" [profile.release] opt-level = "s" lto = true strip = "symbols" [lib] path = "src/lib.rs" [[bin]] name = "sudo" path = "bin/sudo.rs" [[bin]] name = "su" path = "bin/su.rs" [[bin]] name = "visudo" path = "bin/visudo.rs" [dependencies.glob] version = "0.3.0" [dependencies.libc] version = "0.2.127" [dependencies.log] version = "0.4.11" features = ["std"] [dev-dependencies.pretty_assertions] version = "1.2.1" [features] default = [] dev = [] sudo-rs-0.2.2/Cargo.toml.orig000064400000000000000000000013731046102023000141140ustar 00000000000000[package] name = "sudo-rs" description = "A memory safe implementation of sudo and su." version = "0.2.2" license = "Apache-2.0 OR MIT" edition = "2021" repository = "https://github.com/memorysafety/sudo-rs" homepage = "https://github.com/memorysafety/sudo-rs" publish = true categories = ["command-line-interface"] rust-version = "1.70" default-run = "sudo" [lib] path = "src/lib.rs" [[bin]] name = "sudo" path = "bin/sudo.rs" [[bin]] name = "su" path = "bin/su.rs" [[bin]] name = "visudo" path = "bin/visudo.rs" [dependencies] libc = "0.2.127" glob = "0.3.0" log = { version = "0.4.11", features = ["std"] } [dev-dependencies] pretty_assertions = "1.2.1" [features] default = [] dev = [] [profile.release] strip = "symbols" lto = true opt-level = "s" sudo-rs-0.2.2/Dockerfile000064400000000000000000000001461046102023000132140ustar 00000000000000FROM rust:1-slim-bookworm RUN apt-get update -y && apt-get install -y clang libclang-dev libpam0g-dev sudo-rs-0.2.2/LICENSE-APACHE000064400000000000000000000227731046102023000131600ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product 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 NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of 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 reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS sudo-rs-0.2.2/LICENSE-MIT000064400000000000000000000020721046102023000126560ustar 00000000000000 Copyright (c) 2022-2023 Internet Security Research Group Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sudo-rs-0.2.2/Makefile000064400000000000000000000011601046102023000126570ustar 00000000000000PAM_SRC_DIR = src/pam BINDGEN_CMD = bindgen --allowlist-function '^pam_.*$$' --allowlist-var '^PAM_.*$$' --opaque-type pam_handle_t --ctypes-prefix libc .PHONY: all clean pam-sys pam-sys-diff pam-sys-diff: $(PAM_SRC_DIR)/wrapper.h @$(BINDGEN_CMD) $< | diff --color=auto $(PAM_SRC_DIR)/sys.rs - || (echo run \'make -B pam-sys\' to apply these changes && false) @echo $(PAM_SRC_DIR)/sys.rs does not need to be re-generated # use 'make pam-sys' to re-generate the sys.rs file pam-sys: $(PAM_SRC_DIR)/sys.rs $(PAM_SRC_DIR)/sys.rs: $(PAM_SRC_DIR)/wrapper.h $(BINDGEN_CMD) $< --output $@ clean: rm $(PAM_SRC_DIR)/sys.rs sudo-rs-0.2.2/README.md000064400000000000000000000130711046102023000125020ustar 00000000000000# sudo-rs A safety oriented and memory safe implementation of sudo and su written in Rust. ## Status of this project Sudo-rs is being developed further; features you might expect from original sudo may still be unimplemented or not planned. If there is an important one you need, please request it using the issue tracker. If you encounter any usability bugs, also please report them on the [issue tracker](https://github.com/memorysafety/sudo-rs/issues). Suspected vulnerabilities can be reported on our [security page](https://github.com/memorysafety/sudo-rs/security). An audit of sudo-rs will take place in September 2023, the next stable release will incorporate its results. Sudo-rs currently is targeted for Linux-based operating systems only; Linux kernel 5.9 or newer is necessary to run sudo-rs. ## Building it yourself Sudo-rs is written in Rust. The minimum required Rust version is 1.70. If your Linux distribution does not package that version (or a later one), you can always install the most recent version through [rustup]. You also need the C development files for PAM (`libpam0g-dev` on Debian, `pam-devel` on Fedora). On Ubuntu or Debian-based systems, use the following command to install the PAM development library: ``` sudo apt-get install libpam0g-dev ``` On CentOS or Red Hat-based systems, you can use the following command: ``` sudo yum install pam-devel ``` With dependencies installed, building sudo-rs is a simple matter of: ``` cargo build --release ``` This produces a binary `target/release/sudo`. However, this binary must have the setuid flag set and must be owned by the root user in order to provide any useful functionality. Consult your operating system manual for details. Sudo-rs needs the sudoers configuration file. The sudoers configuration file will be loaded from `/etc/sudoers-rs` if that file exists, otherwise the original `/etc/sudoers` location will be used. You must make sure that a valid sudoers configuration exists at that location. For an explanation of the sudoers syntax you can look at the [original sudo man page](https://www.sudo.ws/docs/man/sudoers.man/). [rustup]: https://rustup.rs/ ## Differences from original sudo sudo-rs supports less functionality than sudo. Some of this is by design. In most cases you will get a clear error if you try something that is not supported (e.g. use a configuration flag or command line option that is not implemented). Exceptions to the above, with respect to your `/etc/sudoers` configuration: * `use_pty` is enabled by default, but can be disabled. * `env_reset` is ignored --- this is always enabled. * `visiblepw` is ignored --- this is always disabled. * `verifypw` is currently ignored; a password is always necessary for `sudo -v`. * `mail_badpass`, `always_set_home`, `always_query_group_plugin` and `match_group_by_gid` are not applicable to our implementation, but ignored for compatibility reasons. Some other notable restrictions to be aware of: * Some functionality is not yet supported; in particular `sudoedit` and preventing shell escapes using `NOEXEC` and `NOINTERCEPT`. * Per-user, per-command, per-host `Defaults` sudoers entries for finer-grained control are not (yet) supported. * Sudo-rs always uses PAM for authentication at this time, your system must be set up for PAM. Sudo-rs will use the `sudo` service configuration. This also means that resource limits, umasks, etc have to be configured via PAM and not through the sudoers file. * sudo-rs will not include the sendmail support of original sudo. * The sudoers file must be valid UTF-8. * To prevent a common configuration mistake in the sudoers file, wildcards are not supported in *argument positions* for a command. E.g., `%sudoers ALL = /sbin/fsck*` will allow `sudo fsck` and `sudo fsck_exfat` as expected, but `%sudoers ALL = /bin/rm *.txt` will not allow an operator to run `sudo rm README.txt`, nor `sudo rm -rf /home .txt`, as with original sudo. If you find a common use case for original sudo missing, please create a feature request for it in our issue tracker. ## Aim of the project Our current target is to build a drop-in replacement for all common use cases of sudo. For the sudoers config syntax this means that we support the default configuration files of common Linux distributions. Our implementation should support all commonly used command line options from the original sudo implementation. Some parts of the original sudo are explicitly not in scope. Sudo has a large and rich history and some of the features available in the original sudo implementation are largely unused or only available for legacy platforms. In order to determine which features make it we both consider whether the feature is relevant for modern systems, and whether it will receive at very least decent usage. Finally, of course, a feature should not compromise the safety of the whole program. Our `su` implementation is made using the building blocks we created for our sudo implementation. It will be suitable replacement for the `su` distributed by [util-linux]. [util-linux]: https://github.com/util-linux/util-linux ## Future work While our initial target is a drop-in replacement for most basic use cases of sudo, our work may evolve beyond that target. We are also looking into alternative ways to configure sudo without the sudoers config file syntax and to extract parts of our work in usable crates for other people. ## Sponsors The development of sudo-rs is an initiative of the [Prossimo project by ISRG](https://www.memorysafety.org/). An independent security audit of sudo-rs was made possible by the [NLNet Foundation](https://nlnet.nl/). sudo-rs-0.2.2/SECURITY.md000064400000000000000000000030621046102023000130130ustar 00000000000000# Security policy **Do not report security vulnerabilities through public GitHub issues.** Instead, you can report them using [our security page](https://github.com/memorysafety/sudo-rs/security). Alternatively, you can also send them by email to security+sudo@tweedegolf.com. You can encrypt your email using GnuPG if you want. Use the GPG key with fingerprint [C2E4 CAC4 B122 25DE 1C3B B1C9 289D 0820 03D0 1E95](https://keys.openpgp.org/search?q=C2E4CAC4B12225DE1C3BB1C9289D082003D01E95). Include as much of the following information: * Type of issue (e.g. buffer overflow, privilege escalation, etc). * The location of the affected source code (tag/branch/commit or direct URL). * Any special configuration required to reproduce the issue. * The Linux distribution affected. * Step-by-step instructions to reproduce the issue. * Impact of the issue, including how an attacker might exploit the issue. If you have found a bug that also exists in the original sudo (which, although unlikely, means it is a very serious issue), you **must** also follow the steps at https://www.sudo.ws/security/policy/ ## Preferred Languages We prefer to receive reports in English. If necessary, we also understand Spanish, German and Dutch. ## Disclosure Policy Like original sudo, we adhere to the principle of [Coordinated Vulnerability Disclosure](https://vuls.cert.org/confluence/display/CVD/Executive+Summary). # Security Advisories Security advisories will be published [on GitHub](https://github.com/memorysafety/sudo-rs/security/advisories) and possibly through other channels. sudo-rs-0.2.2/bin/su.rs000064400000000000000000000000461046102023000127660ustar 00000000000000fn main() { sudo_rs::su_main(); } sudo-rs-0.2.2/bin/sudo.rs000064400000000000000000000000501046102023000133040ustar 00000000000000fn main() { sudo_rs::sudo_main(); } sudo-rs-0.2.2/bin/visudo.rs000064400000000000000000000000511046102023000136440ustar 00000000000000fn main() { sudo_rs::visudo_main() } sudo-rs-0.2.2/build.rs000064400000000000000000000024011046102023000126630ustar 00000000000000use std::path::Path; // Return the first existing path given a list of paths as string slices fn get_first_path(paths: &[&'static str]) -> Option<&'static str> { paths.iter().find(|p| Path::new(p).exists()).copied() } fn main() { let path_zoneinfo: &str = get_first_path(&[ "/usr/share/zoneinfo", "/usr/share/lib/zoneinfo", "/usr/lib/zoneinfo", "/usr/lib/zoneinfo", ]) .unwrap_or(""); let path_maildir: &str = get_first_path(&["/var/mail", "/var/spool/mail", "/usr/spool/mail"]).unwrap_or("/var/mail"); // TODO: use _PATH_STDPATH and _PATH_DEFPATH_ROOT from paths.h println!("cargo:rustc-env=SUDO_PATH_DEFAULT=/usr/bin:/bin:/usr/sbin:/sbin"); println!( "cargo:rustc-env=SU_PATH_DEFAULT_ROOT=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ); println!( "cargo:rustc-env=SU_PATH_DEFAULT=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games" ); println!("cargo:rustc-env=PATH_MAILDIR={path_maildir}"); println!("cargo:rustc-env=PATH_ZONEINFO={path_zoneinfo}"); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rustc-link-lib=pam"); println!("cargo:rustc-env=DEFAULT_PATH=\"/bin/:/usr/bin/:/usr/local/bin:/sbin/:/usr/sbin\"") } sudo-rs-0.2.2/clippy.toml000064400000000000000000000000161046102023000134130ustar 00000000000000msrv = "1.70" sudo-rs-0.2.2/docs/audit/audit-report-sudo-rs.pdf000064400000000000000000016005701046102023000177740ustar 00000000000000%PDF-1.4 %ª«¬­ 1 0 obj << /Creator (£}©òH»&qF\)zZÙ—¨ÞšùâÂêèE³|:u„Êf,»Ž©¬¿YI¼*\b#ß³x„öƒ³;¢yi¶\f) /Producer (èC¢bYZqfˆ 04ÂYfùi4òG½œ`}«VÞΙߴûx?Ó@½Bµö'0ö¯‡ÆFåuþ÷ìœï13˜³–ˆ) /CreationDate (R™Ò‡nh·ö½µsyò¹â0X6‰Åït—¦š—¯Æ'nä'A²N*òd«6ŠPtóعê:tÃÄ@,¸ÛQ) >> endobj 2 0 obj << /N 3 /Length 3 0 R /Filter /FlateDecode >> stream Ìûi's¥ÀÀ'ĸ»Ù€üP'H¥@ýÃåï¼XÜôUÇÜÀܶKÁ i¥c¢×·”kçMíâª:. ©F‹qŒ==4¯~2Y\yBMŸ§>¾Ý:ÃFqÐKå~„§ZTsö8VûN·c’„‰BLÇ•fW¿ºë›î2CcŒ‘€šVÙ á;²ÇþÞŒd]îÃ6ËžJnÁã>Ÿ­Ìéå<½Õ(€Þ—Ó›5NôeµÖ|ÿ‡1ž2fU©°–dyÏì"ôÁù!¤»;HÏH{„ÙÉ —Gw»ÐÒ|4f%.‹‚›Ÿ/$8(,íóToUüKŒóøÝ0Z껿VùœoèÝ×oØsµ“<&è3–R\åݬI‘ÇÐÕkÑ,ÜØ§¡kc¼ø5Q_ãê²å4“M±ëe´{D½XŒ¿¤ý2ñƒ¼6™%±›é½ ‘†B]¬‰ñÓhé"YÚÒi&’ŒùZꑈF¹wŠ&èÁÞ’ {L"ŽlÞÒEAzd¢v祣EóÅòð'å¦wד¼04Rªî¦n(K˜:¸¢¡˜¦™/;—&RR aAøOi¢Þ’C×¶wƒú NÉQ ´MmÊ,KF?oÌIÈžö/’«ôÊ&°¸jƒ«Ö¸Ð¯ ̶”ì?rAÐ%§·BÒaú\^).œ^ºHºíèÞ;Æ—£'eƒJâvÓ·jd4Â#™©[Á+q̧Pã¡ì!=˜®žhŒ‚÷zMLΦ†Ú_ýG¿?E îÿK™S=’hÆ;]™ô{JÛ!¤¶ˆK難H8ƒÍ¶) ·™ìLÅropAçSt¼/ó {a¬é!MÙºQxCز‚ʾ;ט_¢]Ó^~šö6JTîàó…§#ä­ÚT-Çš©&|!×ÙÂ2Èô46dK¹ºãh°ØQóÀÛ;å?·Á#ãÁ8‚R*&JýØRðñã}!]û'´‡¶ 2­“»”,òdJz§Ra”Ø÷Á(·ÙûþGEhS`¶Ý5ÓONÿ~XOøÌzµýhêÜ›à‹é³¹)ó6×èZo$o÷íªwß%ó®|& =˜ZÑûyë=$¿ªn¦=fs¯ò¸NÀS¾Ñó6ѱœ¡-)µñlÆ\ZC”ÎõÄ}l=îøx>\ã¢!݇OÒë[ú’.&ËÆ}$¼Š“#Á{¡½¡'VœÆ ´pîä[ætÆïÕâŽ-{ж›ø:•'=ú¹’|>9ø~W+Â;ž©Qy“úžõ×AºôîðºÒVÁØÊZÖž=ñ‘ö"»J…Ë™…‰#‘¼Â$Ï/÷µ P`*@îòéD”9¶)÷GÕ _¡Iøà¼¾×ý¤¯Þ+üŽ ŸÑhѾ8Û9ë‹›%kL—ùQQLéjÐ@!pT4Iåt´ù[¢¢©fŸ>§ªª7B-ÒzN›øPEˆ:~:ìU®;¶—¦Õ\âhIcø.AøÓLš 6EwðÅ‚×@ÿ)c $ú-ÝMuÄ1­ZiÕ¹u›é.Òoô#×:JìÉX2ƒ:z‚¿²1yŽ|ŠëÖ,0|¶Ù‡„¸Ìr¾´:†ÿµ-è55áRÿÙE<ä–íïÀý˜A ø®¨}ü23„yX‚Gó©öÙeù7ïž`^hVXßí²€¯ ÌÚ¨ÎâîZm¿:ªßä€Fòå$Ÿîoèó›‹þ;¼/Ý?ÿ4¬Ô/}‡|æøAILLA€è£×³˜ÑÏçÞ×_Y×ãk{N5,Çw'†ÔfêŽø¯VK;üˆ;HÊBFø®¬#æy¿×9Ww^Vãëe¯ æ¾XãG b@3ÑJ°~A±h¼æŒì§U›ÄTôQ[}M@‹xµg#ó#_r§í]Ñî‡1Ö©†`ú Z±Cc_ „f,®‚ÕmdÁ½Bhš—’M¥V8®$ +VÅü–?t ¾· À[¸=/YOÌ ‚íÑX­¨“fí¤±Â—=o(ô ê²Ü¡õ—˜åwÎY¦Õ÷Ð<Ô¦‡öîq™0z'9К}(ð€úDÑ—@×4‚šFK Sn›ý½­×f„pŒàf`’¡à|uãè8Â2âº#ã3”Ú È«uR0d¶£§æ2â_ F©-}“™|챑þàeEe@k“^ÛXb(̈ͻ ƒŸŽô覒8?Tzëc#tt–¾:eE7$̆YLŸ¦c&ᬗÃÉZËöòÖ}{øþ…*q(þ¹¦¡A_¡ºóŒ#B&Sd>!íùÌy«vNÖXyCÈKšÉ©·÷ºX³mŠùJŠ› ½®·w×J–£ºt{„mSg<'{_ T€>䑌Fxh©ŸëÃmlu™Š£ cÜĦ†ô=ÊŠ]ðå5Šõl¹sÉS’Sõ ý O}?%ïýIÚÒ¸!‡žDssó$d!X;g¸áùŸ˜ïÀû÷$dßwÊ& ¯ïv¯j±:š¨© ÍÁºÛ—îêÑûB e²®|}ƒuUwÿÏ%­BF‘dëµþÿzÏÊïàC6œÍï ï³7›•ºD^?BH1K«ÁÄ––Þ·È>€‹TT¸Þe‰_ »^ç"’°—5#³ Û.ƒO¤€pAó½~(°a3¤¿XßH0Ì={‰h3ÿ,»ßZ»UôDt9«"]øÖÝf³ù1>ʳV/Ÿ¡ ¢n.=œtòAïP)71§Ò»í#j(Ôߥf# ¯š¼ãÇŸŠÓ›ò†SXìšÀ‡Î!ìäåo¶]$xîàG,JgQÊ(¿”ÁÿÕãOM7€ÿ' “†aÊï…¡„g—^ønÒË@€OËHh) h¥+ìK°A´6Ë=›ö¡&ý¥þtF/öèuu·OÞX`šl]70ûBµ+uJDzƒóp"ÎDd"ä«Ú[” ‹Z­vó³YÂO!-ÊåÖŸpH„Ô†éIGÞäß6­¬iA1ûÙ¨‡‘¡ræ• ¾—ö>˜%Œ¤^$å6’fﯹ_% ·ü…ÖXE…÷Ú@÷Qˆ¹wmÄIRC.SÜ|éó‹FÓ‰Ûà×{}¢µ+h¾§¯=™¡\Äè…oîk{ÄUg¹Åä endstream endobj 3 0 obj 2496 endobj 4 0 obj [/ICCBased 2 0 R] endobj 5 0 obj << /Type /Metadata /Subtype /XML /Length 6 0 R >> stream „ǦT§y8vÇêÞk`ÍÀîqaíŒÖüI’->ä£yoicµ³<ÜkKNJÇçÚ„'¿GË}¯ ©Ò =}¸?¶tOÀ1¿Ÿv¸âÈø1 ÁÒÐ.µ\kc±ç¥S>žœ ^Ñ;ŸÿÈtvùQ°%Mvù°V*·5œ¸¦Öõ³>8ÖÑ”ÞÆÙüÛß{~®;¦ñ1ý÷Êô.¤õœ«ÐÆPˆY3&Ǧ af¹¥ƒ–ª5 é£˜cfîn/<ÅsKØgb–·ô½ó}Ä3º€Wƒ,”` À訋U]óx[ÕèÓImf[ãC‚U[¸`t°Úl(ÿôo(úʺ¯gË? ýyiQ‰›Çd7w;AjÚ…{¸]¬ôn]âÆ4*îž»mþ3Ìzßf=q† ðGλzá Œ”ÈU‰ãxδ”çHÜé˜#ߺæ"Ò“jz¼ÕŸÕ.ynñù–fÆ,ÑÔ4>Q¬•烠ŠÓLÒp-" ¶ö§#säÀQ7Ê<û<5{ÔÑÉtWHó¦…¢ØY9)ì¾K¬Ñ˜fóÃ3}JIt°ÆÈrWäÃ2v_=úaËï(Jh¸05;ÊvhI&$v<áš¾\ÏõæœeYÒõî0·[žZa€ÖDã«:ÀKmWní«Èü©µr =MÎûEÿ1”"3§žð h½©XÂÑB˜ñU­"××,Hà¾éèíS5ì“mSжAºÖÖètõœ)ïŒp7’ó¡‚CGõJ8> køÐpyEý›wÇïÁ,úîèwºòÛˆšØÔˆDšÀM/G¨âTô<Ì€i)û,1þñ•õ%÷%Z¢¹( ¼3Tkï9E—€pŸ¦š„£8¯ £h›!M á×\j½F^úqtφv¡Èaâß§~ËêyI¡5²·“¡ÆL|¤GX~§¥šô©>d¡ï)'Ô÷g¥ʱ^†Á=í|Œ Òòç1ΨPcŠEdÆ5Xì½[—¾· réÈ Y1Ó.$ nÞR_ nŒª®,N3j°ñ¥¨g!@~Π—xü·%Óï|¨ŸUS±©ÝYsHLýAŠI†ëE( 9ç5¤·™I–Ÿ‹:¼ ›QÌÛjÃImê Áþ¼Åú©NÀþ endstream endobj 6 0 obj 880 endobj 7 0 obj << /Name /Im1 /Type /XObject /Length 8 0 R /Filter /DCTDecode /Subtype /Image /Width 2480 /Height 3507 /BitsPerComponent 8 /ColorSpace /DeviceRGB >> stream %«{âp† ¨ýŸ^–æÐV .¹ÓßVªƒŸ«|®+¦wqœWcVÙ… ²?ï40”W’ ,ç7Á<øW‹6ÿ’e"sÉG 0(ö„€3G}ôè”;âwä‹è’.éŠ)dBÔ'&š êGb MG‚ú¶œÐo¿sþV•à×S͹ën7`ÜZY+Nog· …”ÅzøŠ#à UX?ß¿R9<ð6ø“ÒqQ”‡€—C²†OgvKº W…Æ·“àÔÀ[ì3i A­ù¿º•¡fˆy{à«áÒÅ k“+/=/nJwêUüÜ•O5eáÞ~Œ½`Xó+µÇ Ký¶¶"€½˜´Š÷> ñ6ûyû¡Üù_BN¤ÿ^1ÿÎ϶j9þ Ìi'ãîríŒøÎÇ·2|ŠñÖX´ Wàt:Ùš1½Ø''ä›Zµëm™k\õoYï\@2Šïï¿YåÔ?mg6†P?ŒéǶg.æ¯`ýÚ_V“õÆ ƒ£%Òv¾iF_e†áœ\=ÿð»ø\ÄZóÁì9”‚õcŒ»úš@Y5÷²=Ê;O#Dxò¹–{ªZËÚK÷s[D(Û’ÞäØHUà¿u3:ëW²t|è›—KGª7x»LÁ0é÷ˆçŒ4Ÿ|g¡H¡Ÿe—2ZM›~lS=ÑtüûáTÖ/qç‹ÙÅŠPÛ,¨î"ŠCMN³o×ø{1n*4‰Ò培L»òÊ?ÇÏ÷ü D} ‚x.ö~h=’²ðúÍVhèÙƒùmõ0±ïj”á.Æ yŠ8ÿ¾×žÊDvœHu}‘<€J†àE Ì ,úáo10!P|áÅÛ­ÇOŸÜqüÞPß©dÂm˜¿NAØ[h —í½ÄÀ•£Ž Wã?+\¨fÕOˆ•lí(Ú„šbÔH28§Í4@l%ÿ°“ì© s6ÙE-iÛHì¤T)%UäBópÓéâÝ»£4¢0º©&h0#ƒý5&Ç ùrðëjr]zïRî Y¡ÎäÆlø<Æîœg !Ó( o8¥x³jíW#Ï»gâ_Í¿•÷î¢)³ù­íF‹ü—)ûGjcfa øƒ#…@Vbðb…‰õfžøöDŒxd­Ör=->ÄzÏyש4˜§–ti1¸&×ÞZùJ”í‹U~Õ2ú^! l.ÛàWÂ&pK:,øôRÞI•õLóv‡Ñ(¥ü’€ô€s2y«…;+Zéó½X²è£ár “©àX(ÇOŽÊéL¸g“1³öÃá1ÞòHYâáƒù³ ­í3œ+†)¶`ßJ°ËSº<®|`f$Q3ÿ’¤`á–3O ›»rÙžÊÚ¦äÛ‡zìÜ+4X²m‘rRâ¹z Ãóïñ§Õž„|»?,² ÞÛ¤ªˆ°„¯¯ ®Åm¾¦k§W™¨ïÑ'¡@>'ü|Û$ð1h5~iaÈï ‹»œ Õv¬Ç1X±*IpÎÿÊ苹nUꪕu³ÝÖµÈ1§‡7N]#Ý‹Eª\¹–ØLÂág˜fºîõõÂt|µÖQE®‘âYC¯­ÅŽ‚Ú¥¯q < ã€óÛ cyÝôÜ“:c¦¿&0Þç¸ÑµØ+†‡;lÛ©E™XΧ£‚1t¯p¡sžÎ¹ÜÏM)ùu÷ÆŽR…gaˆËù e‡-N—gµL,BÐÌtöh‹0U ÈQ†¼2¸ëøªÙÇkótDwk˜—;¾µ”0Þ'Ù×U%“´/o…aHOLèêçxGj$Ï0¶ú̯n“ázöF)pb2(6Ød–,¦ÏBªä\vyËJ«ÆQ_ïév‹aߢ Í7ù%{„|©a^ÂÓº~1´û°­`Èt#.q®K¿Gα'ëöãY£ä ˜´HûáaZu¤³yE é>Ÿ€=ǬO?«A9ú›ß t MÈRÀÇ­D÷{~µ-ê=Srôwƶsïg2u‰ØM»£kÖž±\7-á€ULÉ5zÅbu òK›ý}¯øÜþ!³ì†Ó“Qu¥£‘{¦¾ú[0@•V¦$6LHJC¹áÆgï²]YhØ{ ‘¬§dÇ?ˆø&.?aä˜ÅÜ–{ˆ.‰ÂrÚ¸íX4 ®/tˆ‘n'@<‰„ßúû‡-h?Zëéb-9ä Eâƒ.fu@2 z{צÝtK nlëІ9\rY·$îuW¢(qºNË]è\DZ”…9oN 8#áº3 KÂ-ØPcØÞÑ‚OEq|ì8{î\:‡Þ2 Àòå1í9_tc!’tKu8 Ô¤g›Ù`ƒLu{Š´QVa$éúèüs£yzŠ×ùÑÍD â¨Í70äË®Nù¢³¼×'4'1'µW¿»ö T,è-YÁ{âSè×çu”/½»!š½°qZºadANð±\}3Cû ••2ùºìô‡EóáFuésrL… á{“¨)ÈÚâ´Ü™<'{óð‰Õ +É‹Ö|©}Eaå,Ƙ‰ Øßñ‚ @'RBaÐf'íŒd°òÜÖyšÜкpaà§FÈùSihXç¬."a…³Î^5?4ôä—¡{Ì–KÜM.VÅ6µbá8ä>Ä|9ðœU#Ù[bÎhëEo€ÚÑÙýÜm x…–Ä–æM˜k°8›‡£$’3´?/ð/õVä±Î-¸ÇÊ(®¿<¡¶^TðZ óÏYFJFJA¸-cAâÍ%&5*;>k<ã"Õùw—ëeÊ:QõÖ?‰Àµ.#XÂW²ƒZ$åãëÔ±R¬—‘!•@3É´’7j† ÄÃJ$y"q¦Š¹ÅÒ|Òž=´®yv¾KÀ&4Þ¹ååx†•åÿ_ãÍä¥ µX'Ù+ù¨sP!%{ý1sÈúk¶Û: §]À_%s“(6E|g5\Ÿ*çJ…ÝϪ&ÂÝÓ>½ÉCÕùÑN‡k²ysOÿ›Æ3í‚+=§ñNPÊ©g„'tü'[¼ÔŸÅ$?ËR°ÎÚ­bëÁmúwqgJIU}¡¸=NÀkÃoÁ*ÑÑÿ@Kî¨V5'书GRÊBôŒògº˜#`ñx¬™ÔƒèEÆcõØÔ¦/PS­«ñ;¹Cº!$ÛndÅ‚³nÎ:P" c èQ¸‘{Ëw[Iš¦Âw¤±U£¼¹¾Œê²o4håÓ¶|wAV¤LÀ¨dÒçÕWgÑdìvÕÔ÷ƒ•8ò‚[ñÓ‡¼¯4^oa“p¿É˜…3£@Õ„ÎN/Úï‹*+x²jÇ€±ä¾šÞvŠhBH‡Ƴ„yqrz§îµ aè.gñ²ï`W&¬x}¤³5ŽÅWâj7 (ÏâlY³0¨S³Ûý&6°àà³ZA¸Î¦‡ºÑø½ƒ:Ù„~û¿{¼4Ó{R³¼àý ãÇ:ë\î6õÅGr^†soí®%_ÜÁ]2ir“ç.zM )’Üž{y±[f/•°Á]È4_C°Û¶šP+P ÌW£3“Õ¬¡!ʇ"¨”/0Áà‹þ@V;h°u•Í€q§€ÃŸät ›Ðî7–5¸Ž9Ñ*3HŸ¨UBóÏ8:3)0’ qõö|¡Ü=ß’ 0Ëÿ !6ž‰¹ÁÒBz|áõ*pò±?Ë4 {oj´Ø9ê}ÔÛáíïy/RˆÊè4ʲѬ¤°¯mÈ­;é|'˜ñõžVç/b|ÇXÅvZYµˆîGÀ;…4]d˜’tãþ‰K©L3¼ ¾@?„o<<_‹ ±\‰–,cÕÚnCþZ¸G݈‡Èm0ä}Ù¥å#Ñ'0惔ÿÁn…3´Vtüô¨[i•p£a »C iA5]P )z—ÃÍFâÚWƈhSŒ~‚P8û>šž&ÑñÏýbèz¹RçjM$óËto3VéøHF3çe^ECr¿8Ln¾WÀ²xÖƒº«˜lNE Uâ¨H„ö«Ò‡¥õ]j`°Oæ ,UµŽŠE‰“¾Ï…“–ŸoÝàËjÕP F‘~hµ-¢0ßÓó¤˜7—_™¾ƒuÙøÃè(¸á‹ï¡ªAi\„B#¤™žk3Pz…1Ì[áà锨ÛP+.á§¥µöè¶ õE‡Kx$îÛ‚p:sjAgÕr°›¦ÑoBôÊ µi^ÆU²·¼.lÖ—žÃÇâ*©¼œu‘¼œ°@fÜçž…ê*ÌT­ßßòGQ•%Zë‘êqÝ ²¾¨Û«aü;½¾¥Y,-þ Üÿo+H“ïêraËr 4"Eõþ¦ÌèŸX~b¬Œ0&Ç>i.G(…Ó¸â¬y”_âµ=M\‘Ë.{•9­©ënD: k`ñ!W‡±eh}is^•‹éŽ{x¼ÇÂB#1„Á@ ø›íT‘ù‹oƒœ:À­OÖMõóí™Ò×¥}ûðJÐ;ÀÆvoB¢vÆ b™ßkûÙ^xXžÆ«DÇ?âžïöÎŽ} †´Í¸¼ð‚¦cYÕ†R¸rˆÂ¸ 'çÎŒ ÉOZ.%X—dÙ ºhbORáñÎ _Ú«ýp¬wÑ þ/ªr³£ÝÇáá'l™‘U©,>” °5„\úkþö;¦èoo âjohWº¨¯`¾ëÅ™\’ì3À†¬[ŸË"XÈ<ˆÓî*å]MÊZvžRUÚê¸ÒrAœÖ‘’ 9 *PHYôS|?â†B¯»L<ˆŽ“uâÀµ- ,o”¡âŒ¡zµ“ç ri®Ž¤_»8ÈŽí ‚D—=ôëÊ1¿kwŸósèFû™Â°Uìÿ jLdšäÑSòSëï[\Æ/Âbqí±žäò=/ÉÙ†ÿ ΰáŸçãQ 2ý< ¬/ÏNwµß(±˜ƒûÖT~ûy§@Ò+Œ}£B ÙKð§Adø_wР >Zj¹¡khíÿ { ÚbT9Ò49†—yȦˆrGFnWÜü Dpñ±¡,_‹¿°G\Gd§Ó0ûêøQ'v/R¡³ÏqÇ!4…û&ÝŽr9WœT˜Õ¿H¨ÉgÙŠ´¹õµì“¿{Í©‰\ÂÕþДU² O•ζúdÎí=•zã–¿Aþó¿`Hî$¸)¢œzWº~Í4"”>5™ºsòOê83¥«KÌûó²{ùœ2ʦ/=;ìh"Ïp Z®T‡§p*j‰q2B·l#ä ¡“­òÖôO2„ÝOÝ禽7ñ@žnñ”ýÄw¹ø¶mOD…AcN_ò·Ìßãàh'ðkdʵtÓ)ÁåwnZ@fº¤;l¦Gâmb’û(f]¾qwmê°DDqaäÙõ¸ò©ˆè âñ¾o ÃHâ‡$‡ôRêÕ´eWZŒæ”€Ânv6w³Õ/$ZûrÐ_†ˆp/ÿj C'ýe"|Ûv‡X£Ôu-Ó˜õ±]–"Î9"Qº_º‰ˆÛ Z„Ï"\úoÓ•ÇÇÝ_ÄDžÒ8´Í.XeN'¾¢k¦»ã…SsâG§´NWÄGè,"Y –ÏG!íÈCGÖ àoýÜðŰ_ ðí­îõCbcäP{„å# ]÷–7Ê›j[ø¥úÀ¯•ÞlzX,}*”°J¿ñ?ÙW ð©ùN2^^óbã‚nTE猲^Ÿ¦Yµõå€ígI™•! (D­,«þBÔ¡!£%WZï±Ô$)Ö‰v’~Zi©Í:&XŒ…ÿ#Á¾îR@ÿúBÚ—$nž'nˆ-V=°Üò/Ä îÑØoÏ ³êל›ðiÆ7Ϭˆ³£Ó ­0BäR™ÚX«+ìUl{%#s»¬ㆨÆû‰6Šédy&ýâcnë\•7ÞÇ€Cóavi^[™°m_fÀ(‹ e´-9˜9¯HèŒi%u;ÃÝ10ÔÄÓŸð+R8£¢}ÏÛÍísiô×5Ú:jYZ­ÈµP˜4Ò:¬ø„ùxºHH‹1ú´]viŸˆ†Tª•z{±Œ©œÞhÁМKñc@«Ëøà0SbÛ Ï­äc¾·‡ÓG©&3súàâÔnUŸÓlÒÓ( "6o¶ÁÐÍÄ[ð© çïiWÉØpø¡¦Û…‡ïûãGPz›už÷'i•|ºò@²v³$ dÎZî~XYH9¥€™Z¯wßÓlYØ‚ õ±Ê¥ìå Þ´§ª´× m–†Ùk?e¿·uhb ·ª1ü»¦äú|Zq¹²#êt¶ Š› ³øý†Â/¡”¶yD„ Jذ_Ënç%CúßÓ3«C©6ÎJ óMXèîrÚL¶Rö’ÍXÎü5Š8 vÐ “ú¥°ŒåhçsFX¥P‰õkÞþH=ú ;/sêË#†Ÿ‚Ó5uª•pݵ‰èÖ1x/GìUÚÚÿVV4IMCsÞ½ãšZÎ…ø¨–fBd}··A›¨Ûôôhí®@~xÝ6{ª@—UÑ þ`±•ÕDŸjQè®áÍFœ{ìLÅ—û‘:‰²ö2ÔÞG}­dÀg'Lð#* ¢‰ž+ƒÊAZù ðIâ»óž=7[!"$²¥ZèNãå¯=âp>{#`„uÀÙ:WÈn´±ÈÒPzA¹6ï,­ì\Y”µnUÌìå¿¡á<yûجW™­ŒÁWh“lÈ; ÐJ•Ò Îµ|§ rׯ3»¶Òž×^6ŒaÝè^¸ù/#Ó‹.:pµž¤õêþ ÖMÁ¼+d°ÖÕœ _JÆŒceµŸHÓ«8«Ó‚ÖâýeJÏKˆ\¹ççf^A¤+YÏìXcn6–Ó.(kQ5ÙX“R8gï…õ}]Iz¼Ùò5ði ¦ÍóY!ì*ñÖ}u’+²-VÌ)Ã0í½± >aûŸ´Áè9†´ß°1ÀfÅåš|ó×bìüƒ›&ᦂ MNÃ[hƒA¶³G„^3g× "åŸôò+Ù˸ †¡Ñ»Z39/î–oüÅRYçˆM¾ž <Îçá°e“ì$¤%"Žß2Ë¿µ•ÍßÛˆÉQ«YªáYÙmûåöªFÞ/ºow/Š×W¬AT½ùÛÓÒ;%o(>÷ÃÝŽ•/m].\ ½,c’8Öó›2àeÒÆ*½³Œ÷’¥…+J¾Eþ }±Â>®±ND@õ°öÁ¬f6{‡{‡—øUøKìéH-·)ïÍ>#5Bw¾£—×9‰ž´@|±±²”µBoàÍòHcæÉüfeÀM¤ÖQ™5mßp{J·åè2oÚÞ0hóëD­‰üª¿³‚+ì‘¢Hñ>˜ÛÍ\I³Ï ~C¤êeá¢UÇû‚2`Î5±üC0ø„˜fÔúòšÈá{¡è[,YTg :P›ŒyýO*šÇ2`„ÔÆð­ì䙥­9ÂvdFÿ½›5˜B¯¸ÁÅã| (ÄÖ9¶57=„~,Í>WBmìÆ³FIa˜Z%ŽÇôÎÙ.Ýô»-ï·’_#HäôRQì»"!;%([Ù›F ÛaX_ñ/WØuªlD4¼ª”è?§b*(Ñ̾캢ɵíòÒÅyÅ-´ Ÿö»9\ߨæ9è F%ÓÑ)óËDÑ ë ‘<šº~(„‚¨±Têä;¦àú}®SíI$¦wú#Œ ˆ4âãÐuÞ“fëÒri' ‰ÐÍyJ¸—ª7¿_" ­ ¥´Ò쬠ÜÅŽ‚…1Å.Á5ª›O¤Øb+"à éTåQþÖpü¼ƒ(€ùÙΣs´wûÕgx'Å@³ãžÕœ'ˆÔõîåîô/ÛÒÂÏÁÀÿÁiÉ9‚|Bé¼A‹‡øíÀŸ›…£\jÊš¦ö^ăD8¾Á"q“Fßv í’~aáΖ¸ ”ÁWx#`©/;+6Ã_÷$•IâŠÀçŸ<±¸ågAÆs‚ÈôwA‚H ­`kN,52ì.ìá6»h÷Ëþ'UüÄæorxVbæþP§=¿Ôºpõ/Ñ…¯gò[ÿb ÇÚ¥­ˆðúIï³-P‹hv‘œ€+}…µyf!&¡mT ÉQãµ á:ä烲wo‘Æ)H!·.—ØÜär¡­ŸWUxû3¹Ù±Æ í¢–pSÒºoá̾±5-­,ôӨ͗æ•ZÈÔQÕ2×ÈÏKǃ¿¤Qi? ¾^”h;; {–[¼( 'ïM²þ–ØŠ;ðÄzÍÍ䤃‘ž d¾„dXþ@<Øä/‰g3ºô®•)øW€Ü¶t6‡PNPRfïV&’°±ŠÑÇ¥.~%†plýTw“ÇÑP¢¾¹`|˜[þ ºÏFéÝ(ôåsõ†× 癓²žË À’³z#Ù,'F6Tó›çØãp†¯Ù'Ö»Êèg”‚€£›s¶ùÕiªäEeo5U¯‹8h¦­?¦0\¯Ÿt'Ó¼yhaÿW~ñ˜ÊÿéÍÉKÐåëøvN‚²·›¥†¹Øf¸#HrÐËåQ`íS¼²ðåÅŽ#7X-0j¾Ë}* } Õ ó«@ÿÜ__(§Æ”è1Ћí!x×)y¦è«—o(Q¬Y;HÑ?DéÜ1éx hðãçˆÈ?ÝèC³à³i)¨Å“@Ê!ìŠÖºöSÈ;„ûC— òxßãT®YšÑ~‰‰%áÑ®p{æì|¯Àé›8ãÚ§$vÉØj_Ú›£mˆT³<§Ž{tÅ})–T¤Â½÷aƒ¨>ά}—°M¡N%ga¯ÓÁ†O§\å0×á3ñNÿà§Ó®y¹~ÇŽ’ÔçÅmJJ²)Z;€(‰ˆ–ï-²Ô Ö‚j¶¥0±8ÉÓà·Á‘ƒi’ Í^¯e˜Sóž;®”ˆë…e°´…:š Œ`ææšµ¢šÈ>Ë ÅQÔáø*WÏü‹Ã¿8Î ½•¼D§E˜ä"“šgéÖ8·[ÿ_®¶+HÖ‚È—Ý騯gÛ=1ÌΡ¹›¾‡»nù°Í6I:WlnCX° Ü=^Ôä–¬°O$¼E‰Ï‰.Óþ(±cA‘Ò.7hÆèv¹²©$î&¨&ÎàƒQµ)b3W 9A:øœw³ÅÏÎ4B‰¦Êo¨•r2Å–¢R¬ ¾ótÁÀ±¼¬E}¨)9²á$õz:G¬Þoj™õÁ¿Èut÷¨—Ç œUy ~pÖà½MŸwNܶ ò[|ßQÁ¶¯0'ÕÆ^Nµ&÷.–A¤°»Úi ò8¶ !OéÂ33"¼Ð²`9È[`Üj”ˆE÷¾aªYÕ?›Ò “‹1ÖžåO£±—ÚpX‡´ˆÆNÈ^ ?:ŠšJ»µ} Ýk+â ‰–?ë €Ò Hûƒ1#¾Mœš;¸;¼šÈ¢/xëŽeä±tYt€Iq‘`™â®Àȯ‡hÖ±ý@ F¨ ¢ýÙ„Â/˜£.â-T!ÖŠ4Tr@ˆù"*ƒ„¤ç eŽ€ ’_ÀÃîm•ÿA©M™¸= ÕNkÙ;…7ýçJ‡r2ç3þ§9Å­’¸-¿îþmèÙ1-CY¦æš«71µoÿdÝ Ç†gÓD)ÎmŠdöº¬J×C¬ }yªmrfpÄï`ø¥!ËUª4Q,}SXs1æÖ£úÙ‰UøÔ¹ž?Ÿ—|õ¾Ú¬rÁàT÷0÷²`Þ„â˜P¦Ï#U»3” º°czHh/!òe(þÉAù®Ú•õwßzʃ`hqm)än9ôÎHS©«nýÒŒ¿‚Ä><ã«x‹ÁÝCòBn£ä-¥!Û5‡@ùÊõy—EªÆvÈ¥Kò¯+ôŸ’ÑÜŒÀçÑ¿íeùõH1jÏÀ0î8€?h01D²¸»2+ë³Â—Û'Èʾ+¦¾älÌ‚ÊIˆ&âÉUJ9#qgò ùiZ€¦öÔ€\1øgê"1kÔHo¨0!KôOâ!6ž&9;ó<Ñ^ãü?fÚ~=j#Meh' ½Hò’ÆÌæ @ü .ÊlÐÕVÀœøõ’˃Ȳ“Qúñ’ðgLþ‰RyI{@ócægö½~ò—ȆÕ6ú&’ ¹£—=Î)^†ÃÚueraÁ‹ÃIȤvXR«Ì…%"ÂF¨W‡˜É®|]KB.mÁÿȹ`ÕJUx·†Ž@’•M™@tý$ü_ƒÜNئO‚x–¼×± Óçù5 ×t 㵯÷xuç°Î€?¢‚vMÍ›SPWt‹É°ïaóç@Ì¢Õ½83æ†4ÀL‚½¸i êk@rÅàa/³oêŒ_Í(›ªéŒ6pg7T‡”Ùd‰z»«œ¾“#—Æ?[/~xíž;¶ˆ·6­Tcb±`î/G©7<[Z‹eõ¥½ß¡Ý‘þ5“ç.Spppb+×µbdˆÈ{‚­jαTüÅ<’Uƒ?E,E·§ì¬ÞØì‡Í=«\— ÛXJÍf_î|W”µi$a1 h3hÅ.vRõ.j2X°pì”Z¯d‡pÇúú:{ñvlj»¸Fˆi“ù÷f,Ľ­þ7ˆ/ÛL€*ÝÿÂåý¢©RÒF xrŠ,µþ ¦¥ïQã‘7¤AÇ}-ÆÍO3ÞÜuíI€æC¯77õ‡¼!í¬5YÁk—Àš]¿°~ ÜãL> 3¢©ICN '=üë×qµ¥Õ¹ßé¼FÍbÓð6YW5Lž¿,!ßYL$kÔP!&°”Ñe¤ªñ‰´a!Õ¤_=(/À«Xn"ƒJÐì&¶Va{´RØÈ§<Û%å*¥ˆõ:+³ šqÁ•%! ¼¢Øå¬m¡Ö”g¹?°ƒ¯ÏÕ:å.¨Lq¼ª\¾îŸ@ ˜§\Æ«¹Â?@*ToÁ‘â§ä˜zÖnÞ8’ÄGX £hThkù?ÙôoÝwåü~´$Ä"¸cNhop'òv5:ûѯ¿MŽm™KL—$U‰+p²¿BÖ"¢Ê˜´+Höÿ°wz=’¡}¸ùLœD §eu{[¡%Á7Å’TÊxÛ®Œ«šè܉~Ýûi@åd›«^_Ç\gžZmŸ¦m¾Ry‚u)HPlÜsúx2z·?‹:r( 6™`ᤕÀ[1dM"­Æžg:cõ [Ü5ÄRƒ¹–¨à<Ù'¡?!ãÁUsåεÞ@õ¤FT+ÎyP ø@@­¤s‹³„ɇxö*Ðx¬ö3¬ÌáÉ”lÍÐm:ïòC‹›Ò 9ýžÿ"X  ’Íú…òzöŽÆ8H¹›…X=®tõýýÒ‚&ر,Ae½Ç;åú+ússHx™‘SiIï%¤òæ²x²ý;×WZÀÛ°þ+8– ÷qAU7ô_¼ÈHÖä@Y]9»u1—.ª˜ÑòpÊFàëÚ“×}G ïIj6‚-S‚™‹9&Óï½+‹VöÀÔ•À4x·‚x‚ƒ½Šµp'ßÿilnµõ¶Ý–ø+c•ì%Ϩ “²6?xÿÉY^Î12@Ê3¹ŸÚWtbÝРoâþ¥—¬a«PÏ¡/]thðîÃiIA0„#f¼9‚òçóHÛò©ç²ùØhoc‘ÚTõÒS;eÓD{GäŸ!eÛ-ÈY†]Û×TÎ%O"Ϋّ(}A®Dó;©fbo+xíoþ°°®B ìîu½>9¢TÁZ ðʽåk«8ÇÀ[a[ï!zˆ‹´]D¸ûÒ™I¢v´ËDÕàß}3§ƒ&y%ä¡ã–RKYh,/ˆ§f*ň—ÕW)Šcjz8}T¦5‹bEa-ovRYsËðìð²ûD[ÐÃÔF«£ÝnygÄð‘ÐV7·bÑÝ¿Œu\°`îž½ƒoYZ†XCòPJRžD8ø_þsr”ßȈ,À„1ý,—#bÉç:ûóEÓ¡nócFÒ6df^‚ÄÜñÆ#ß)5ŠÐnà *ÂÑ÷&šŠ x˜"êò¥Q|¨ÒSZ™Çá×E&~ktMŸ.HBÞ³ž+!‹2xµ@_#Q1‚¯Óm|Ö8ê±-³y/„nµxÈ€èQé8škT«û÷›„LÜdeˆØ‹ƒ9ÑÌg©«Ý¬õÂï þt<¶åú?L‚‰26XnIr‹j¢1’ÃÀ-‹/ ´gõ@ö6Ô º¨ƒÊÚ°Á%“äæªĉ¯¿ò]sê`áÒ?Å3‰Ï"ËØ“¶Lc‚Š«]å0/Å8§¨é›ð8àfÉÖ*¯ýwÝI"²úº\$(îQ17½HÊ(Û°µSÌÿèpßdŠK¥ÈxÂwÚ¶ Eù “µÛMýØ{ÆOý“®=i¿ËN‰áÆ) ül Ñé $‡(¹àÛ@]å9Pmeú-_:czz,øåXUfgÚ_»„Q—ûw΀Åz5i¬r'_|g„‰0×oÇÝûUQ‘œ¾æ`'öÇý ™ð”OÍDw^°=MÉ¥8P 3 ‹úà‘ŽQš%ŽwÜJ—´2œKYÅgÀÌÏU>!&TL¼ÇP“Ð itÒE‰$$o$Jóµ Ö0–xmóŒ’v$(i"€ÒÊú$õ{%–6Bᤰý ]~bº$¼Š V’6á YΞÞþL2Çè$5ú§mr0C‚”2FÈ)w«$x¾!ŠVîŒyš?&ÆÛ'æ¯nž}¹Õ[ÔuÈ(?,ÿjzð¯Õê¡z©kW'9¼$9MWPyBÖ“âÿ€\ Î¯¦”H®å-#¼ÂàÁê¼'/ÎÑ+B·Íãp×Y¶Žð~V`sµ« gnfqÝô Ç\¥6T»\ˉ$$ìCKÄ ]Šª.LKµßb¸3ËqpR¥ô¡‹O51´ò¤\õN¹Ø$Ov|$n!OLKDÞÑÌóLé °÷^h¯W·&^x¼1W:¹ ýK.–dÖ¨¤@Ü8ÔAõ~y¤>Ûý*\9÷ù’y+GƒF$ß¶œ„y´NÑ:Ù{ìe³ ›>Úw¶so98ßnáoñÑ£2ѪU’„›êXõɾ3ªEºÊñÁÞûù`›Ü+Ò»…ë )£!ÙÇ?¼âÊ窥ðåíWîm±BS¨MåJ…°&±¼¡nç9Û™Ýã$ý4賘B¤3';Éݯø-cºÈDó–§šîbÎüц„N²_¹øê:\5‡ Ðéž½w©ä~û½º=<´ó#R hðò[­l¼Až/YgÈ|¼_Æê5¯Üî!Ùj®Ù Â.բ嚥•~¾©,>y½µtÑ­'$¼¤\£!7×¶}×Nz+@®Û&ØË`½˜òž‚ã¨î™M²úDv E^ÌÆK…."aeXù!;ʼnÚ·Ž ŒÞ‘îN3Zo7 )”œ¦ÏÅo¨¸£…› ý¬—Ï¡RÉm`ç®AZm)>®t ®1‰¼vj Ί–þ ¬aC)›Áð4Ñ–ìHí p'§•,õÁÜq˜6*ýUæu¼ÓÞg¾4®ÔýÓ0£AD}òïù«g¨˜»ÓhŽ\~O."A‡ÄØÇÖœ z„OW ¬ãnQ‘´.g¢0:7†Vm[^¥5)blAZ&”G¡ƒ‰¾¾Ù‘¥ˆ¯qÁðÈnS"/#‚KÊ’«á;]bŽ“Q¼‰fÎaKÇ#õrKd”ÿVAhGÅ^í!3Àua¹4¹ÖA„8jòâ~ÿX £Àòtº,.‰uÑ/„Mr׆ÒËhòÌÿQ„;wˆê%>Ó;QذŒªu@8ë @¶Ñ©ǾàÜ¢Ö7]wô"ÊÆì˜/#Aߘ㱄§W³µ9hYé« KÈ+h+˜†×¿ÍG¦úí¢îC÷?KážWpÌĹ»šY!EQ†~9Æ ¼ãCÚ4sÔL3r¶=9j2ŒßÖ]–Yï1˜¤äbûÿ²6oWޱ醮ŸÞ<@Äž[c¦:·j ¶gÁaL7<ó±x¸ÿÑi\ÂÄ’µ²¥**]¿pdµŠäUa aº.÷üVìE8i$4YUòjÀçŠgn¡ÁY¾’øZ!KSðå€ÝÒŽÒóŠ´R‘Ÿi=hŠ^Ýc+u/ŸÀ6 ÏÇAêÒ¿nþ2ŸàÑìžškØÖ:ßÞ t Ê™p¾ÅÐÄà¢Ç'eEï5DÊÓ“ ™!OaG©JÓÉûV;el³àˆùÇ'ݨ®š5jÜ]ˆÅ µêÔà{Ýs$ íÚÑ ¹µ¯&s4„Zˆ|¡-œTÓëkœÁõ·5%ž,Ðýœêø¾\í²ÇÑ$v‰NÞÆ† Ç¡2o %DÆ€@´^zû’«\É…´½ÊãBùÚÐî’æZÝ!—7@$ó~¥ã ¯×_Kšgx^(ÿÞÅw·‹ÜRí·®g±sœô˜cP³©NÇI…Á¶‡"Çö*!yÀÈ>Ðk§Óì@­Úü^ É×þþÌ€Z¦ö‰Má„f¸ÆWÒ%æóo#;f ù;áf06÷»‰:/`eßí{×zÄfMª= e×d"¶ë–Fy qu=gÊ5ÆÄ®fRÜYpª~ÊŒök©ê¹¹›à”=f`‘Ð-›N+sÈŸB‘Y|CJí-GøñP7ùÂÜŒ[mP9ÿÝÝÎaÅÐʘÉYßÄl™»ÓáæYWŠ Z †„V‚ 3„tu¦9‚ì¥û<º%¥æÕS8;I&Ÿ(€#ÏûfÜbð-¡Û†Ê7 »&†"eI •ÂâžÒ¹G}2P±I¿”Ê—'d7ßc.ûl÷%Žâ£Á±®¬iÉjgÔ4é|åìmÅ(ïýóz£ðE 1\n…èùÎÇfv§ êzT2Õ‰LŽÊ’&t—o,)TÂæL2’€æé9âá§-[ã•d>vÑRY<ø Š9¸ÖıorMp~a®z\à°¢_ñ»á#ý['ªçº ØÃÊ,ÉÄi ° mØ6-¦ 6  *[ùá°ÉÓlÑx× hÉ3$ìúSÖoȯÀeþV¦´n IG½çJ‹-Ò ¶Ü÷üAÈ«ü\˜Ü„Fdª’bîj¤êgŸë­ºI»½Ýø_ÉL©Ø²Åqyòz}:hD†ó%š© zÚÀ{M0k³7lµ¾¢µ7Jª#p›¼j¥–¶9åŽt*YØö\AñÊëaî1«r5ÓâÐøîîÅâ9‚îyŠÎ?7§|C°‡Ê’û4%©žo}—µF>DìRŽäõŸ½›ø_-¿v¿ò’ÆXðª•<ß1:ùTôM[&Å•äO,¤(ìî8À¥écZ¢TŽÎµµ¢‰ü4 P 5V’ëPüFëŽÄVµv™ÎY„À¾C²Ì–4&Êo ’IÒ €ˆO×¢¨z­{c 9‚ç«Æ€ª™´¢mÒòxØï ÏÓ2Œûж>ÿé}H´‘\]&Þz0‡Î¡³ñ¸Š==¨¿Â"*c S¶ñ†ÚÜ{¿wçÕK®.‹þ²E *'?4G#µY¿gþIµ a.ƒAäÅW9·*ª¸l)°ü9–ª4Ó^?E岪!4VÙ»´¶C­¾:’Ó—h|ŠôÓgéhÉýÆ$7N´V+v‚…Y‘ëâä•­}׌[?Ù“ËÛõðPÉÉëêFÜâ×íJyü~ `lKâè`{VÉ*¦µo(XíÆÍb"ÝfnÚ:GêÝš¯UL2sI5.{EÝ÷àÝœ‹‹Õá'*GŸ÷/ÓÒK·ï•i±tu‹-çÑ®\æõÙ N{›]|ŠŽ¼:ôµ®Cé.ÍB»(­ X«…‚BrlwoÛ±OyˆQ£ïòÁ¸À:>5Þb¾ÀÝgk©"/ÌšÁÛ[;¥0IQ(À²´®AÖ Ì~I,Š ß®g$XqSYì`ªW„ÿÔŸ^ º¨wŒºb:¦JD“Yún¶az²Þ¤ÿ´¶Äc3°ÌÍ# …¬}9½9¨õh™tÝÞ#÷˜>"äQÖ‰õ¯_>s´­vü´ERišömkJɵŽK ¯~ á FY¦Œýì4†åhëC±-øå\hëzdõ8Á:€¾èßcd`„6 WàZy.‘ÄØ ¯Íð=ýŸ7§Á°§_𦈴uøŒ^ßÖ%v5²Û FÖ>à$Ö+s×'P@œN‘K¡x߆hß¼¦}Ot@ˆ4Œél–œäFTåf"¥î52¨åÕã’XK-ðHÛ©›Êñ>qþ%°5zcÍçÓa°‹ê94ߎ½ÀZ:,tADØMغáûÓS¼õfÄÔ*ùëL{‹T|×^Z¿Š^è ¯­´hâÂw~mcº™î¨^¼©¢KÚíG‚ZÜI+¨jÔÇøxèÝ<¸ ž—„Ê̆ Ø"'¬›ù•|lîp¢¤åTC4¤>™Û«ÀWä"^˜ZMÉhWÓKøùWJrkkü»dprGÝiK®u™£e›owô Äsšb¾GÄé_pcù(àçë×àT‚Û”Ô1/ôîkT¤S«§ÜÈG±æo¼sŸ¶~æ«ZWax’„¬äžÅ§=Hæm§5Ú'·ËâWé#YŽßÚQKzriEâÁù¤0á¯ÔšÁÅÆý§I‘<7äÔö¬nÊëÏ›Ž‚ûäÜð½S1Ù~­‰tÒîaÍ›Ђßå~N'YR¥~Ý·U»sp>bU^`pîªMê§¶30Ås€Ô’«6­@·%@\zd Þ1ÆÚ²¡–ȉ·îDõÜTÄ·Zhâ{!’ƒ†ýüƒf¢¸?wÛŠdЇ®gö¿BéÆì³‚ÍhL8ÁÔÒ¼°¢ÿæ#uÅ¢Õüõ’}fÐ;¼¥te0ø“[{Ûø¨Âýœ[Ïz;âþÊË;€ÞÓ¯d“Ãì ’|ÚBä,ìsíjÒø>,r¨£‹ „òRd³²°åmþ+áAB,ïàÌZ2ƒ´–ž³6;ê@¡¯V1Ñ04ðªcÌ ­?ól^ÃW)|ƒb7oÔ"{›u? Þœåú7¿¦£“¨ájJs@¹Z1ÍgÁò¯ /X‹Ð/ÅÍQß¿è,ãCRÓêÚ5IK‹ò›±*m°iÁûQ›\FêùêуýQ ÉsL½Ö"]#©Û¹òáÅ+Ä|{ú*"½€¤9Ñ¥múå1ÝI¹!¼’ Í>Ãè%šeÿ,/ÿ®1 “‘#%Μ´ÜLûŒ#‚‚‚D¾£š.š%l°š6½¬óµD!؈Ýu–g•Ê€©¢lp I‚éjMðo ¤GÄF.ëvé+¥˜{«!åôÈÑ´£5?¯gS¾•Í=§Áæ½¹]€§•ö¾Ã®˜0¦Ûü[ ÷Bï[|•sÜÛ9Œ–þbîPåˆîÏÃíèÜ^À/ƒ¥>Õ®:ã ÔN;ÊÉOœ—hxYÊTr0©¨7™.ÿ àºýœ$ÖKÿÃ+•e‰g£®@ØÿÛ’®ÙSB5î ^ńť “Àj·ÆaËýEìÐ?á±ÐÈ×ïìÌñ AŽãÍp³ùk\g-H¾}[¶8¿²të„HUÅê¼Cüüx\Ì#A[èø`šv›–ð3„ÇÌD‘ðÃù£bV@ð+JªF~ 6@ˆ bÉ>ê6nì¬SêèªB«¾6šï¼…ºLÐi]¾<ŒZ&ƒ¦¿¤‡¼íã²€ˆZ™ÀS¿–z,—#zëx§ªT>?×ð^ª6‚Dn™­õ@”è4H,ê™–:#r 1-¤ñE²EÞnßSˆ €¦Nù Ðý¶Þ›†Áìä7\Æâ¥²’æñ8>oçéÎÐÞXˆŽù\ ñ°˜qöWþ,'kEœŸàf“BO?ß˃µüb}µ’mZfW]P.ûCèÒW —îf`ŸýÕ'”Hs fN2ÂÉR›‡\?xã^ÏØEgWüÁèiWR½þx”×{|G•ú3ËN˜›¥CÅ1“{ðãÄ-óPF¿¨—wÕ¬\óŠò S”ÚãVÁdÔ~­-{½Þ‰™ ¾æÒs4B Ï¯åYñÐÝÃe0&øÝ‹û,DoM xXXGƱÿ¬ì¶U|Í쳨¸,qܼ™ï¹ô—$a‡!o¤Œ‘øQMHMŸŽ‘~ dÈH‰šl–úí¹ºM˜¡à ,ønøÉ—ãÁâàsú®õ:ô9‡¿‹QHK¬œþâÙ €º“?ÂYÚ?#êZÖu‚‘gÔÑT4L»$0][äûNçgØ7Å?ì'pÑ3¢Ñ<}ó6ØEÄ+xõÎi`O W†%DÁQ'R‰ ´S@œÍé,~ øtÅ.æ£ \=…n »±½@,¼3(êÎåÌúì ò¸ÿÛÙÙ-YnëC@Í#(¤£iÎãêqß,¢P½þÖ8C4 X— UwL6W •Þá9( RK@W5®¦lL.)¹c\yúý"ÉUth_Ù¶¿¾†Èá^fö@œêaà B z„NI­T°ì‹9Ÿ€úT„)–ÉóØF°sFÅw±Æ 6²H¾ÊönHm9 ¨£”0꤆,›S,8ÅNâ“¡a1Ož>ˆˆ¸Û…Z<<¬þóym¯%±ðÒÍ1ì R€ t×ZíipòX­‹I•Ç©)_“ýVäKåçgX„‡‚5©/²(qÿR ¢2úâ@<ûi‚Ñ›Í<Ù`–~yø(­¼`Óµ|Çôm©Xv*¶ãßû*M†éuxjÙ ¶,ãJ´TA]½ÝÏrÃõnaánz„hœ4‰ñÊpDz¨gm¯§ý¦ÃÿO é~UÓi7ñ<¿Òd|Îâ ˆºcÂq0È6,DHä¿&á~ÿ—äZ/&5¡¼Jô“ÿ0Vˆ]œÞä‚Û6mÝš2K´äÆÌÒ\•XÓ°^SIŠ{3`i»P&F>I~áMÉ$Þë{ߣÝÒíï‰îJu䄈f@rëpt#j7… ð#–*² Æ‘øtïòÇÿnl œþæNiS‚#¦3+ÎD~Z9•òy-]Sÿ»ïñMµ©‘§2£¨†Q2©#jÍ߇+lÂí]¹= V‘=ê_M¸áî¿3©Tæêø%²$§Å˜J'x¹ïTî›3Qe±Z' ·e^KØÇtiÕ?žŠiq@í÷§êãžÎK‡‡Nü| áb¼™}äVãh$¿DŒ½4ØÏSë²-uwýñs™eCù{æ ê©Ú”FîfkÁ‚Чdûi+ö¦Ó KNŸM ÞXýZLÆÌ¨¹÷²'Á?t’¸ðßæÕÊ$ËV mÍ$í² ‰zŒç„3½[é\‚^­¢ÕûUdF\›·köòòÕ5Ë?k°ÆÌíóÐeê– h+¨ ‡'RF‹vƒÐŽÌ „v}¢˜Žå¨w¤{‡ÃM¶#¶`f²ýtMÂky؆ðØ4ÝŽãPt"…j~g£èþ0~óÁî(wŽ+9Í@ò âPß@“+ï‚}9’ê ˜%ýøsNCP>£ZsÏÕÐòÈ©œßÄË]?g¥×ÊÔöC¥º,“ä”ïÚ8!ì<ÓšYLàqƒñ×NbÄxʳ‡ËÐúèlº;œ7{Í ¨–¢¬L‘‹µÊ{y¨HƯÅÈ}ÚWW VŒÉl¡úJ'-òŠY5<èý*ïåQ10ÇðÍcdou÷Þ *0YÕ½h­Ç?â9:æÀ^f8_•½ÎÇÇIÑ \Ìù0S\lM1­äL\ÔÒ P:À¤U²uy´Ô©Ëd8Nz3e݆’.œS$€5÷!2&7|ÑÀA”4¼5ª«\ç#k×7à°hصlÌ‚öE2îx®jã%è‚ÿC<'«™ýC~ÁÓ˜0ÈT[²ÃßQÊXÄQÇ–Ñr0u³g>5pjŒ]æoí){”  Ù25V!þðÓÃø~ äý))O`Ã-ÝABÑBëÏÐ8±o~­09ä'®ù:M“ÙŒßG3áÄü¬ç}h#õŽï ÈU);z+~Pn È«4Ø…š‚J4ÆÑeK. ‡’‰d"Eî¹’WðJWÅ㎌8Ÿ×ç¿Á€KQ<0ÁUôÌHâ \2“VvÛT0e ÈŠ<p0,Ä=:Z›òNCl_ý‰ôøý°YÚ O7­y© qôtUÍŸRÜÆû ΩËZŸÿ#d*–ðÚ+±N½„í^\î©¶2žaµÃöð½DgsbB[zØX¯¯…~\›3(…Áb¿À’2„Ä BQ+®ž'œ¨‚\n×ïe‰(Ë¥µS}˺’E©—w—Í$ÎÆ’逄¿±š½ëä+·l¡ÑÊ'±4°Ì(—N—ÿŸ—¸˜tEüXñ·,±qfgéu{ì9àNð€Š'º‚Øú%»«$6å§ÙûÕüR¬~ihkí7Åá¡át0íª²Ý^*W“þ]7£è7”Е¡k5«" ·lg1yóÙ^Ë€¨ &xM yFí¤e’ÛówNqF÷J›gt»Û07%nÀ§(Ú•ä2“«>7‹ÓY¹$ìYÛÇm>¯ÕÅ÷Úß‹9ƉÿIºd¿…6| ]¤œ%?ëî?ñY%툒•Fõ¥¨Ry‚®å ›£–Xsm3ºˆÆÛªu>œÔùaÜýb¾.Z“[.êG —!ó¡µ'e)Y'àø `«(Ç*¤AeD­AÎJ>œl¢ N-x:ás¦ËÉý¬Kc÷Ñ¡c¥¸,çí!gr"0*%Ûåþ¨c¤Ü£â€[Wê{›‰r¨±/| Â빎sÆã3“¶Rèù£H%ÝI`îo¬|£ú1¨‹9¼ÓÑY]Ð9©”E-lq“Ï ¾eãTó‚“ã-cQZ«Ùs)þ;E5M c®œ«´JLR]L|âå`•å¸N˼©ý˜•`ÊJ !üβ?Œ9èÔ]0…m£×m‘&xûs«µñ‡J ÌÒ€¶þ‹}«´ý &Cd àJÝ+ŠIT÷TãûÃÛU*‘¯‚ögqóáR·¸]Eý™½6ˆîŒM/G† ¾ƒ…bµÖü‹Ð…*kƒ ¾É˼íÚ)¤Cß÷Ìà=ÖHÌrŠA^j]o ×o5çÂó´NJ/B/•ZvZñ:v’í:a˜hö+D•…z¯ù¡²Äqa@½#äÂÚ /…‹=N{zYÏ*{–4O%߯gû òÚÀÃ|)Ö&íX~)W. l÷‰4!3U1ZÖ wœ]Ûgîñ‡Üâ]#ªïÆ(3O‰™Qò`E }”è×c‘ µG²­T–¡.‰÷‰ åà)ãç×4«ì¤­äeTÇU Ûed`>ì³²jÜ_7Z¦ývu ­ÞULè,’1f¿äO{ŽùêuˆØ¼ÒCŒBF‘b^’=@Ý!̈i øºÔògpj¢øŸÁÀ}ân×5-"Ú!%ìšOÁ<©°ôµð:™3Ì]G"N-²ƒìD±vr×}.Ú(•aèbÄúµ $Z]„r¦Ò@9ÚàëýUdÒzeŸ—výÉNÎIµ—¯¿äKíË}{‘1¶pAúSIß@I~Ñ[UµDÙˆ)Ì qØ%ˆ9Ö¸U}Ä'c\Ä@cð=ë:Y‰£AESûU ÷/î˜]‡”8ò2É4_t)£ñÚ”ä£fþÑ)°:cF‚¦#YWÖÕ£/³Qœî–®»ð’Gã?'úÝvN…9‚{ ›ÝÊj奔…'¿ôXSY÷ ƒ…±Ãlì—,7Ž–9$ÜØz¢@Ë­Y•·f¬`]‰Z÷¤û?â- æ¦ACÉùá¤Q¡\DÄsìõ²„‹Í0 €ÝSAýtˆì ßëZÄK75è¬ÁúÒ¿³'”¿ÜTH4&óÍnÇc7DÀ®ñ8;:¤De¢”æ •­ñð¾ùbÕÓJtÎckR¨]T2÷°÷°ÿÉÞ朣鈨 ·¶k¯¸­G ËgÞµ!ÄÇR’Ãs´O×+Èþ”_Ê?þHÌ  õnô ÊÄ…®áôY|A5pí7•ç"èÅ5«¨ÒʸSv›“hå<ºI”hh!\WRÏ¿®ÎåÅÒôjŸV÷è%7¶£Ø‡›] àX2`»V¡ÏV[ªíË){ »ì®µ×޼9:– Õè¡wÔ„½y£Ýy·=và§›­FZÀîù<×3ðRq}è‚)eØ\ŽÎ[õÅg[Ol_t=,jKà°I‹„ê9¾|oŽ_8úU2˜Æ«jl^p#´ø¬RD®æ:~”]‘F%Zð˜34‡÷#3¹RÂ]ØÝ#F™£˜gìgЏOúiøÅ!ïWç>#ˆ¯FÂE1ÉØ’Ü&Z}S^éììW»ðGÂ%ãX«ëCIDþ+Ù 4ð™·‰é©@öî¾s7è`¨oŒx®N‡ˆ¬¶MÝ#ŒÑrYi­î‰XGœE fh³¾a"»¶D¤7ßðµØgÇŽáR÷‹Óþƒ|qPö¸FózhçÎR”ÎÛ«;aÂÙÆDþ'J ˆwVv¨I7>ª þ\Ùê”$,CnÉh,;UÑf t²ŽË×á6GB«ÑÜó4‡`ò !î@õhØŠcªB0ùí4Óæýݤ¼oNæ ¥ùŸ^Z¤™Wµ!«ÃŠq=¥;CÈðWãõö”5§lÏ^H?59`ÝIæŽÌIvN"Ò˦û\¾ |bAo9Å01TÚ'»…ÂIî|ËŠ5z»ÐýµD(Ǫók ªI´jþJÃ0ŽvrüoªF³ò^ãæƒódGä*@YðìÓ¸¨cM2NE J[ílØ©;œv“|‘]G §¡"xËEÝu#ðæ¢½`÷®¸˜¼WüŽÛ]p O½3JFT/žìéi~'£w]A³a™B?A|ß©c¯àöa—á`G %Y'ÅÖ+OÃJæ' ô¿€üËê9 ÏÙv‰C;†›ÑPY—,⹚ùîgZc„no[凔çq8©´¸íà œj«‡Qà\¯[Lë_bX'â"Q%†t.\TÛ`Û}0ýì+ßšB.†F© q»µXÏÐ( ¢½z¤”]k’W…7ìG°Ý)¹äOv”¨œuo5>µônbº_òªØ•Ä6,„AbF3¸åÿHà ŸPµ†§‘4‚Y6sã“N(èº4úiO nµ1£Â‰ðÕ„òð]Ù幚_š¨­+`Ó@9N»Ã®y?Kµüb¦À°‚¤ÞŸ u>8¡/ŽéÊÁ)<(ÈÇØfžÁØBàN¨¬æl ¹r‰ ¥ºÆo)¾è3['x“¬ìÂgOÎÍTþŒ2Kú~ÁŸ¢á-?©*Í´'ÑQ&6ûÖ7ùµ´*X%Aѽù³’†û½¼ömt戉̲ŸMà@jØÇ)ô~çÈlY5œÎT¿Qyf?&ÄóÝZ~Û/SÎk»'îD£½©b°)'žô¸ÿimAn±sª3™½^•k«¿}áxE`[WÂݼjÇ1ߨ^wõÐó3>ÿ·\XœA¢@‚¤ û*⮉»ž:?M·—½Ò±W¹ÿXª­_ÈözZ GÙ`2î%¹?C™ú§ÝÌ©ÐÞ &š&äú_óšT{è ;T—R:ýîÛÑNSÿXºúÖÁ í_ÀÕô'Ä"Œ7*ùÀ±æšsLò1Ìà òÖ1CMÿ}AQuˆã®0ØWµ ïîÆÀjü)^ƒ‚…ÆÈ™Ô‘1jŸ¿Ñ’ü¹›ë ˉ ì·ÖR ëEÀ„±¥ûyá…5nÉü‘Ùþ›÷PiýP{G#79¼U/% ÿÐûè›)o¾Bk·²½ÞÙQ[(S呃”£ƒ³ÓñâÁá•JuI/›)ã3PÖoÕvÒ盺x>˜ÒõBãE'EÉmewyjË)cþή²HQNO[{ ó¹’£¥h0¶¨…ïˆÜâáÚeŠ­ËiÊq@J@îŒÜìtÂ8ÊÚôïÆVAןĦ“iˆml± ¿·Ì˜*1^Õ”M×jE[[è Ù1PãVfWb!ñA:0“ÎL ¬ä0D>£'…㨰n¸êÐp Û¤ð :Ìv‰ØêW³È…’|;¸”¬;Û¤¢5k® sÍvíxBà3C¯+4G¥¬U×kà%í¡Òr~,ÀåV>r™ÖçÇyác¸¢ª0gY5%ïãÈÃfIÓ]¸0kãõ\A@@k4Žs ²uh<îSPG>AÂèk¥9PjÒ nl© Ì,•(ÕeúU—xb¨Ë5XQ¤0 ë×[AÿWwn¤ÉÀX÷äí´Ò¡ÌJ¶<á·p`–yÛÁ­»K”ÖŽ¨ƒåQ,P ƒú3ÕÌh8É­'¼n!.Þ°ù'¯@@ôuW˜@¥ L«Áuô•dS8"Ü'@….Š(í),4ˆóÄœ×#¨ž¯ðÁ¾@¡3Ù–†KÒÍ"†µ¤ nwm¸”Ø}Ä d÷µƒ³Lå!pló–p*í×J€î2eŽkïôN³›ßÅú%_1[ѧ¶í4åì5H¤F´×Õâô¸ádSM»|Þ¯VQÎsİuí 7áRræÍ•ÝS¦ê»T§ç½Ê´¡˜±{PB‘-Ág&K¹»m’Y8Op÷ŠAHLäÅK0šMºîWQ qífrR Þ¤˜íè vbF©^WOxRˆÇÑ)ö·WÑZ»íÇŸg£7²& hV\‚IÒ©õ T¡C¬ÆÖ˜ë¦3ýÕ@”,`ÐIFŠÓ‰q²V­E–™=Sî™fólW—'òo5áÒPåÒ>\fÁ{«¢ànt–fYÀ+)µn¿lÖ.ût˜Ë&eá}SO|ËSíQi‹?VÖÓZµa¼sàe¿ýpðqköùÚÅÄÊ_a‚¯;ß‹*„¦^C©mo§¾Ójâ3^g 9Wùû˜Âãö8SõG±WË¥ >céxNV­% É3ýMÑ[Îÿí?ˆìÝ$+y"›9Äx_õ,a¼©Cc¾5³¤Ýó &U¡RÍÓÏ?E×r6²¬A«pï`~ØÜÆ£Èé1c! “j䲨£r4(fï“B!’W*‘A}Îdíì±ì\«Mê™%µ ì4쩳YØþ$'ÖªKŸ•šîÀy#>AGb ‘"E¬gE6‹|×èÕh4øa1_‘ëQÀ`×~ä–ü§·/pV_B¨|=è4¾ÇxzWtUçÅ7-¿ÂÃ}ƒ L§î”™¼Ÿç1ø’HÖÀoþfÐ[öî2샂â…7@qàïàxJcÕ Uv1y/λç‘»Øe»Š…Ù…G5šÂ @د'l{ë \R‡nëG!Iø¨§£\± ÑÔ#ôW´]¥–Bîm±»ëúx¥uØÕô¥gð Âô.0¼„¥ÁÀÎIÅ5kǪÀíK]&æ_Õih\Éx¯(·í=-évx™ËviÏþq3à‰/Ãç³£"õrFr µc.@ô…;ì¿C«¸î–§ýœ _N‡çõz·é¶Õæ£/ŽX×CH6輺Œ²;L(P(úÖB_æu,1’^ÿC$¸á´Lq˜—ˆÒÑÁoö6s Z,<Ò`jд{HòŠTnˆö*(ÐJ7§þ™WuáázàȈ”ê:Œ†m>¡…ŠÌ¦7’0Ê8LHØ èß׉ÿH"JM×ÇmG&%-‡ªttÙ?@¶m,‚—ì‰fÒåìÕ¹$€gã“Ä?]L¼¡¸ÖÌK4ôQ‰l,¸tDhérž²w9 ˜Ÿæ3É(V°F¯]õŸâ„5pMç^g4Ò6Qþ­?Þô¾Ðë€/õ,P–Ë—pƬȔäB¸{ *€cz„ÓyÌIöÙÙ{ê¬õ¿G á²yæ.;¢{ ÍË9¨l[Üa5Í&vFnÕÑi7=lKGƒéž¸&Ú4,mnYª+ÁÑœ›F !×wbgš¢´y.ªvy†~ŒK1¼–5Ø)é”ågæå-ÇTž'h„Mfã¦c„½óÄÞAé–ˆ (÷_ÔG'õ¬ë_nG'²Óä7Sù´ò%wüŠ Ì%¦Lw݃ŸECZw` ]Zò³Û1˜^‰UOò ûÒ{sˆïæfíœÜl5˜K¤z Ê·,.ª0@8%µP„•ì ê–rÅ9uZêƒÝ £Í´/¢Ÿߦd›Ö÷¦Îú¹†zúËbÑné|Œ’TãiAÑêË þ¤(5Ǫ^¾œíñ.v 8<ƒ`‹ºÎ#Yß’¶ß­e™?ÛËÝzà¸þŒÆ®·äËT›«%{c…Î;ü¯±,•gt–UøΖ}Màb~óýšH5Ú¨)L½-àžOÇ çÝy÷SMÑ .gñÃÈ2fß@4Ÿä_~úñ( À;;n^zfÞtr¾n s;qÚ­9Ø‚Q$¡e.‘Ø„¬æ)3~¾G‡Ýî›D~¨¡…fÞ¨ÕõÜÕáò Yä ŒÆ–çÉÛôKµÅD¥øû÷²CQ{œš9äRÀ•⃗V ‹$WóØZxìaAƒY+ T°t¸šîí1Y„’©¿ý“´ÉA¿F^ó¼ö”Wiº_LÌٟ¡™`õ¥‘÷v¼¾íŽÍÏ矗ø¶ Ø%ãâ©.ñ3FÄh‘<12ólÈèòÞ)Ö±ûÂß[ÖîÕš©Âš2 K>à®@Ë”¨7&r3á(·FSxüz¨ÿsÀcuíSžMîh©úì1渽„D|h?ÌÎíœZCõÍ Æï™"¡¥ÿ¹ýEcH ¹/ÛpÙfrÆÊ—jýJ¥ñÈÏàϨY«Ç©E,šû%×XôÊþ ŠÊŠj~îq‡ÏRF…2™»p¸³`Åâ0õ­[«Žú×c<øDŸ;„rÖ£ëžñ£vó¨X·6_›o4Ÿ¤¢”0yÝ®õ–ÄáEwÖvÝùשúÏòƒAœNÜKú]ʇ¯Rš3PØW>Ô•*gàLiÒöh3Ñì×nÓ€l¹NïOm7~§+rÞ˜XÙh‘UTÎŽäG{÷¶ µ»°jÁ›› I‰J5¹Ë…n=j÷èÂõŠ­™k;œIó `ü‰ßNÍñð ”ôÍ ZÊ%°@w*¼í}ë‹b’„š.Ì|iMò!;ìјêØðŸRÆ‹n¿õMÿ^µx@H™_AU99kµž«>¸Z!2,4(åš%âY–¦‘I ŵ)§¢ÊëXlŠÎmµ{¤CBÁÃ]Ê>ˆe:Ã}£}u+ÆzxÓЖ b~õ{ž¡LUê¼Á8ñ¾ óÓhÖÂÒx]¯T;Ãöšós¸Iˉ7Â1Vé$µîžHöƒuÙërãaÅïi›¦€*¿pÊ dùÆÈH”†ó:VHÛ$v±Ô‰M·S9|î­ßf–,ßÛ–"Ã'ùê»Z«£i „De›Ë£(…ýÈó‹Í}UõiS®&èF«|7vç·Ê%Ã)»Þñê TD EgÎr‹c#^=òuýY+Nx¿=–½õúU_jÖ>ÙIV_‡ý³áZö0ÅS—,$ ÕïJ—EÀK60Žªšªé1-+€°÷\Ô~ýZ ³æ™× (x"_d¯‡9ÐܲIˆK%Ø0Ú`Ô8žä[­cƒ(]ü»ÍÞtZÔØóç[¹V¿Ü$–%€tˆj˜Ý¸ÚêRÜý¼[´Vº—c¶-›ˆ,ñšl.'¶grJ©V…Å…KǘݷäUÎ~sVÜfXô¼ñ%UL]£‰{ò* äw›]Tfôá_åc&7žô‡#ƒòUìG§¿‡lŠ1ú÷׈Ö_FB8µT>Œ 7 Š ‹…ú#xz áQÇÜÛ2«K6‘ì˜ñ\1ý ¬mè!ÆÓ…¤ qJ™ÙN ÿùýÙÌNÆ·¦èÔÿŸÊ>¾èl-¥ë ŠÙ¢ú0™ý»´Ú¡ëuõô4rxîÒ¶`í^ç`íÑ5>_bwêcFh•©å»Ð²ä¿Sî{Eêe÷uðm_dÚ¤+]\ã¢ü€/þyÞ#âœe‹-e6~'»âBÖ&Ásª¼ áã6ФÚjÖUB—tZ-ùøÂ²µº‘|ñÚŽÄ‚i$—9H ÊÛÑQý¢ oÅÔ{ h(¶[¯¦X%ˆ¿† JxÇ/ÀVM4ŠS«årW»XX’ÙÛNÚ0EË{ާòF>ò¦¯Hœ Åé˜f”XCÞpª 4VBàN¦CJÌMxÃјº?]‘€gãî¤éþŽÈ–¨”Á7oaIøâƒâÏ]Yî,r¾“Ç]!÷•pÊØÏE ª€ˆ]%`Ò³µ²†ekKrœ"–Ð0ÖG.'ºs91Uþî#uêÍ¥)&ú5ä9:—Ä–›m…¹>°×É„k>BXdõÄÛØöœŸy˜.Ø¥ˆ I¦ng¡•|eSw—¿Y7GÍȾhéÙ*W‹è·›‚ƒ”’Á&2 µMN ¨iËTøFüÅ2ØÉnëi™A ΣØ×²R{Æ«l;Qæ¨80®8~Z1Ïq½X¬¸)„vð xPǪu.¿¶$|\_ÀË`>hIÞcîDâ}mCž ¦`¿]Fø…·ü&r³©%ó»fœ&ãs;<@ŠŒ³XsÏô&Zê? Ïøoþ-íî ç%¢ža1ý«^8¶ÃLUVæÓÌQäò~½0—sèíIJ—2;¶:1™ŒOㆶëâ çûúÝþ/5Ë 0Ø DÑž]v=XOZ3Û§­Ä|aÒu¡5)(štx|è 7èÊ´¶o 8ÕGœíÔ«úÐØÞ^‚Ÿç@UPM‡*˜_xPí’šbmDZ½AjðeTCîž×/nœrè!GvSžƒ‰…´-wœbµ¢ì€ïUŸnœÜ¤}¼ûÑ13oKu_ô)PÕé$"”BÑÓUk¶ègÒPðWðœôNa(üžÃÇKóo&-ã>é×ø­ºv?T:÷ :f†©Ì) ¦´žxü‰lEÉ`9¹ú¢6…%Ö{Òem3;)EVáú³1§ëý8¸½ÑŸe7%´õDÀ€äª3רOÔ5fÞe|î^å4‘MŸÉøæT‹3a£› ÙŽšCãKу5^óGzô Üʼ[\ITD¡!®%=Çœ;?­RMßSm¬3]ƒz2¥Š@rA¨eþb óDkþ€ú-p·Z¤¨—X°CÈÌN†_F* Q ~~ •ªó i÷'ýøéÜmâhá9û*D/_~7°8³ˆ^3³½WW­ Úó·81¤þF¸2±ßŠSÔPw ÂŒËoÊ=a#(pq}9†¯‚l"È7•óàÃv¤h‰9bç»~ÜÏ4"]‰ ’Tv¥¯é^$5YæÚBx—pÀÛX¥ûò©èTÑ¡½ål¥ ÒÃ}òÓ‹G5ƒVAHÁ·¨Œð2 á/p†nPÙ¸/¯HC_Ÿ>À覶{WµFÍY6]ùg0Ѭ¨¡´“ü|ÜÍöEPLR€qSo„Õ§®¯î ÜÂv¤ÅÆå6d[áq]<LùM½36ÿì¢Iȯ žåh‰4Žnü¦7J¸}L·[l;’±x,/’Y¨‚:jj]q ÀbÑFu9@8ΖN(§à×Ü-ø må(z¯W{Ã=M”‡ „gÏA˜?ŽjK;…²âR†U~ÎQÕ`WÀ&Ùu-æŒÞhŒòŒ‡x&"äHB=÷«ò8„ZÀùK‘j3‡{=V.÷Ëñ ô^veÐDïÑ¥#«*<ámô‹¦ ÙY`èZÛgF¢ê¿'x²­‚°]†1ö—¾úå•ÉÚ²ó/PÛT­}_†rÄ;¯¡"lÎÇ¡(~£=jsŸb¹¡g’¾ê±Ü™}ü”™t«¤¥ÍÌõåv%ÊÓPc²†Ÿ€¡xiÞ¶¸öÄÆ¨Ú‡4Ù°Àн8’a¬²Ɉ ç< [Äßò[ƒo€zlE| ŠB^‰£ÍÞ`v¿yðnÄÈŽã,ÒL¼2ÀFAkȬ/Éb[w]é€Þ[àþƒæÏg1ÅÜeóÕJuØ­YÄbYÕèvø{#n˜}cL¦ßFr÷Aƒ¤ñŽESÔAºÅöaÚÄ–7TðçQCàfU¤ :AdN¸ï!íc>—Ñuê¨ïí'¥W-±¶ Û Öh'€±럋߯4õW{î8aݼóÓœî/yñÑ™ARé\ ®SˆÅ ‰6m‚Ñ[u•8[q2ÿä2‚ K'ìj:™Ûûó´¸Aðó ŽhÓ¿m­È€” Ö®‘C#’=<˜1¥mƒ‰”&*¬ìBç—PÐ F*n¬è»úêã°Í!íGÈÜX™¾ÌÀÿVƒÉVz‡´ìuð˜A´¶†aË’DMµm€íñ¸}ˆìR: ¯‰ÖÓíLVΗ-¼Œë‡É19™¼}•ìï ¡Qiçìkoæˆàûâ¡+ÑéjYkpmFõØ«sçÒtÜ‘ëNŽÎ{ 14P:ª DÂ'"Ër¯hz©>÷ý4µ–·钼¬þÞRàqÿ¼„uæo¬¥ºµì^Ü`k6vs|†¶,›Üžgzá­BäîÆˆÁ%‡›'Ýsrö²cî©Ã‡(ã‚ôÈ 하ɋ î³übÌ|¨ÀBà—Å´8$ €=Îúãê*)©º2–jxv%Jø¶Õ®Ž%‚÷âê{G\¤0­n~±A{lQä5‰€™¤§}ix»´,yaØ+#¾hzªŸ.M~²foÐÜ®0µ•Lû4¥@I¥÷E-®èX]dÄÓò»òú±‡Õ¨guÉÁé{×9†Šä7Å0KÔ“R¼I鱬Èö9gNF°#q5ô‹þøÞGè=Ù¢±êË;ó/Ð#Ñ„ßFA÷üíN GúÇУÖ-v+èßÜ2G¦œ¸ 9±¢+-WÛ`%íZ–™¼ð†MØ*êvÇŸ ÀU#xA²pG~h´Æ(µj˜]åš Ç«^OʽüzÆ_¤‚+H“ß0wíõ«*U´E9z¦F‘N7+LŒ\ßÞZJâÔÊâ*0×=óŽU¨SD)ÄO _ˆ¾'L½úñÐȸ·êA¢ïÜl-…°¼Ó`b«””j9JÉ45ËÎGõÁ‰³@4ë$)ÃË®ZÊ6І‚ j=C#”ì’Öüž$´SŠdÑ®‚_\JqGñ"‚²|ÚñœtÑ Õ1CíÍBÚ'ìDÊ^[ˆŒÈ«à Ìû\‚³—uXB…›š ó„/ Òu!5Œi}(¼ÓÊš@›Ùt+£×…·,9)´Ðú*ª,Äeâ¿Ù Ä/Yħ²‘†ñápâ[ÈÐìKNë_$øœ÷ºÁ ¢€ø«…±e„(É "»ìi ÕË/FâT‰½øl§ÙyùØ,D±Ïü÷ô>úJx—‹)õû.dÒÖóÐ?æ;9µ 6LÉ œGÆB–!KüþG‘¸­Ûèh˜ nû.VDZ©%Ú–N‹ ©žòÓ¶.¸…ôÙ½˜H{àfÉ ˆ¢#sBƒ¶EéEP³38õ>ßææ°$ÚÑ-sýc¡žà*`vŒªû+@û¥dº üžw.ç2)üÞH™p|e¢Á ¯æ860 5cì£mþ½D“àS²g¶BŒÕa+³â–ÀÎsÄ#kê—í§¸%,`µ|§ðý)a+WlY!.–*Î<"xá¬Pþ®ƒþ–gAåÜév“³K9«•ÁyA5 L~ƒL^…D¦çʳ)R7ø$-×·CÒ<;¢  –=Š#=2‹ ªŸ¹qŽšbB­ Y<úîÃl•»tÓ—/×JQåÝD"f— ©´‡z‘û»&ÿKÄ(±x~W%òö"›ŒBÏWƒôti!§¥³ðÁ¶¾ŸÕGË^€`¢ýw×Ñ2bvœ20ü&øíÏ2ç§!'˜Ô ™,²F/æÆO_b«Ì m'}ç ¿U 6ïZÐ"˜[Žã±î¹ÍÔ™¶}¯œKÿæÓ¦¦PÁø¡ü.8èß"\6Iú#pâ0µË–Þ7Y§O† Wþž;¯ß?û´<ï¢æA‰!bCѯQuƒkÐO?l4è&N–Quñ#§=³„ ”3MtàøÌ/“—-©îtû†JŸ<*,€ç›Q]6îvÁ ™™ï, t8PO§®yâ•.´¬‡ïŸ‰ =y{QO°'ñÓUnCJ>+éŠÙ¯ËDcà9µ„'×½7ˆ·Q ‘{­A±-æØ¸bÒ×ñºV´Œœ¯©´úÚu–'ß1ï ø³aF8Ð{Ĩ³ã^Bùì$ÌZ{Ü ‰Ü  }­Z÷ʬÂ? ½Iã!¤Ÿ5(þ€Ì9:fÐ%|¢ª½•î-ð•ò`?Rž Þû¢´¾vÇôèPàŸã»Ø1L ™]R6òól21XDÓõ°OÕ®7Ë0ù÷\ÑDº6×*qi ÒŽà(HM:€p}¹NÂq6vÞÒa ¤Ä ŸWC”.¢aû¾üv± x¹Bi—MاNR—Ç÷ Ñ 1¾ç«Q÷Œp«E9Ÿ¹å’aëÖbŸgõ^ ƒB=—"óÍiEæÔ“ULE(È&IG6:ñxWu@7ÝgM·›ÁÈL ;.S®!ÚT4ä"Ç„L‹¤ÚD÷Þ«o é{óßžE0éd¯åjûRïþÃñº)Õ²“=ÈôêÀa'g 8´%D8òW²X6ẃEûÚœû7¨6¥éî:s)/ì9êÛ0ôdÙí}ŽÍ0f6ç1| ¨_}8,¶’rš™Œ™,4²ÉH5ž>ÞMOÇnHÉDÆtbgc®%f3kÞþ°ðµNº¤¦8RÈêOÔs_6¾¤ÅUvÝÇ´¸9\ŒïEù3:ÀÐ5©m\*E½êéjrlŽ;†ª¸à­[º=HW9´ÀøÄˆ‡Y²fâU‘³MÏFr2P¯´ q]g?ÄéÈiZì©ÍdÍDÓÏñž-þ·ýÉÄâ4³ÉN4õ)•2™ °²VÓ®ãöÇ*K¨*„¡B¸ËMðEÞÍ4å>¿ãÖYm?šÓ÷Å=¢OƒŸ5!G¤V޼Pä]ò@uéÈá8[âBŸ'?Jjé´©Ä”;3¿šŸ¦" Í„ÔVÂÀ RaH^w–‰hn £ã|,rïé2þ·›‹±¼*·à’dŒ7.žG•ló/B׈÷ù!^\OèåÑù_µËc‡¶TvPÔGè&!Ë–‘Nˆœ°ð†—P»Ã‚*ËPÞ7Æ¡”¼ÓÙøš÷Áw—ädÆ Õ¥Ê¢"¡g?ôªÏ2>Y­Šíø Ÿ*JÝ2±«) 1žfŒ{.fî Š¢´\¤’û³ý„ŽBÕÏ‚öÏ¡5bî‹|AeúdvR ðeÊBµæª"”¯€Gÿ—q\ÛØG·,MôâÆg„óØè"ƒJ)+“=pá¦$‹+˜BqÆ÷änÓhË.€¡“#›Q–À‚Pøl5c³i°¯ü§%ͺ'öa$˜Àõ¾Åõ©–™$¶ FyÁt±ÆÜí:ƒáYé Ñ…Н#7ª³'4¡üæ)?§½Ô—aÎáïg ºÈW¥Ü/ádR&Á´C±÷xm¹§3 ã"ç^[.öu^>\šq/dXõr1ìr¨eõù©íT9µ.˜Ü?"i &6d:”CTÑkUVÉ@K­!?•˜]J±Ômw|YŽÃMÐhó)ì‰wCm_F¯vݺþ9¨·¥Gýc«2†Ë.£„héOÄ’táfª±»/Ë'þ¡ å«"'ª‹pyñæö÷ æU;4mÁŸË Ol;Ô~ºp*¾z!”âáÊ?³fÙîcô• ÞÓð³µ3aÛ"ß©«å'45uYÇãJ‚›áT[YJÁIÀÎìFlµK‡üÄX¨8+&„ªxíÿ¶þÔPÞÁ(—Ÿãúöq5#…A—Ú:¥ž*ô†G°ñ(5¨ ïŠtÃb$qž:…@^WC?–lÔ¿»ÁðÆr“žÚöTŶGdVD_Ë¡•p $‘8LL9±ö¡ŒÔrØÞDºÖþ¡žÃ½y{]eÝ[’`×a³ Kw-Z:ÐÇH8%M­™/¤ë¡R;)tÙc¿Zl\÷aˆ›sþÇÚ]Ô2ãoW[˜}/µû…Ÿ™X ô@ —!8Ì#+–Y¼t} O¹’\N†q€¨K –h´­o1Ø<ú›Â³Ž;sÖóàKíú™ønYäÿ(ôûéîïD£¼û¦´ŽXŸUè†% cDÑo& i:Û+–P“²qª÷YÞDP(\ôv·ƒ›%©Ãw?Õ›ö5kò>6ÅH„éö›6ËÚ¥£ ·YÆ]ÜìÍ`ZYú=…?nB·½KΙÖÑ££Q•þW ]oMDé'¦EŸ&„ùP­Kio×!¦ð¬á} ø'âX3EYçÍy#Õ€œ*T±¦dêÄgà·ü¢zZö·ê¢ÙØPh¸¬}Å&äû4 Ïd–îö ½irCâRØï*7K¾)#<`<ÓQR5ËÅ}mRN¿}Î+ôáHõ¨ÔæÉèÙRÁC¢}–Š ˆ¤i,¤É& úB¸>Ì)y®m$e?-Ïš¶€Ža6‹ÂØç}ær|!2‘ÂØÎ÷4¡r?@N¬É€úÈ\¤\áwk‰x±ÔXGE¾CÐ—Ç $©Z8«‚≥l°tUÿcÛú1ùDÔAÄÚÊ.¥ÜÉœæ†ÓYù±³¼ ~]Mð~# ;‚4B{–¹!Ùaƒ©ÿ¹¨=$I·ÿ¶Óð| óïêEÈyˆb‚¥ÓCòvô¥!yÜf ) òŠ3ø,{‚͹š—Þ´!Ž]²ä¯Îþu–Ö1‡°b$yÁÜ>ƒYYsŸº,ʵj1û’Y >ãSˆ%v¹°Óï¿=þtžR’Y/) ¥‰t“¥£Sxµk¬Å˵\  ³š2Qê”i«ù-äi3Ü‚|õ%¾od¢¨Kz.í áf ¥šAzm„ ¨ä@ ,†¢ÍMù¯7æ”,~=ÑF4©z¾7m¨iÙG¯^=dáÒ÷‰ËPÝ‚É³ÜÆìxÌÌrÒt|zè¿ ÁÊ£*_‚Öƒ\hœ§%WŽÂÜÿã\ˆXR%×u8ê.4ªŒ`9[KXDŸBõ5dyZÑ2ŠÑy®ÛUüÆl”¹%𺠤èÚº×þN/ŽR–%¬ÃV(×ôγ å탕ÕËÜ ­Ž(cÜ«Ì`á× `à…ƒúŠÊȶšF´á1XGqb¢)ë—²±6Q4®ù¥n¯;R;@°ç|óÉÃÕ"dƒSïÉ“¶V–@¡ ¬„*Ф-Ñ·3ñ!ç–ìµg˜ý»™>OyKKÙD¤â!áPϘ³€r*ZÃ)Úýoä9;º’Iœ‰TÓlݧþæ h<ðÇJ…TmôMrw–iÏÃ(h­„Ú”e³†Å€¶ç RsŸ9“QVT¼Œ/608àí¨Ù6<­ iÉÍC+̦²jKІ]ÜéügDŠÖ«@úb*2ËQ‡=ü• ´­ÒT«¾È d’[AÔ`ZþO=w¸€ˆ ˆp yîbyò­+¾åûÈ!Ã…žûÀŸÌGbëI4A ‘!§"넵 rYtJRuò“çc‹žM?æ3X¨‘˜Åpqv.pà š}nXò€{~i˜tñTñ¦ŸXŠÂdÖ…hS.Ø”<]ú¨š?Å>lÍ'GÖt)^Ý ëŠ[RI oF‹ƒézRÝ7SçSÖÆjd  ¼‚7¡'wHXÞoS≲Ò@ÙŠIyÝ¥âÌ;î±v¤ÿF¿*ò¶¢#^ÖZ†î¯møæÇï= ± V/ºøÖaS¿ôË¡Œ÷±"õGT¾r+I1²îívÛ³½I[yq6 øT_9(Êh Û™"ÊÈnP •©7AÕÁù+ºÕ;G»7´þ¤ j<¸ ëRŽ3¯³Îéëb®æ/§þ~·›Ö¿]ÉÆÒid‘ALcåªXå5aɾ¯í"þe™þ ¹Àèÿ¤j8I¦óœKàT3´ÞP3*AìÛ½l#ñ¥æqaÎ1T¢$(~÷ßߢ6ÖÎs÷œB«á¶–{ Û jA½*] X]Æßñ¢.hï3¡]n› ï¥OÌêѺ·Ïf‡·ŠM(Æ%!ÅàIÿØÓ–D,¬GÍ•i}~ZÆá)Év‚Í1G8 °òHª@ÿ½†Ê’™…¹bƒzࡪM˽ža¢:•×8æéÛîÉ•þ=íç™îÄPìß!óûÓEdœŸÌ=xÀþöë‘®¦¤"=\»ùv¨ÕZh˜ú¹QvHç9Øwì>6gü†Šœ:7½„+ {6Ì#š0Â1Òé y,ÅåðtIÈUëªÝ!ÆšR1ë™ßcOZ¨xW8•3_Ø[!JïΩT`)¤2QìH^¿”´ß§F¨ZZ/¤ ylãi§')„${¾× %qp[&"´}¤j í Ó 1ÅœîU ;®8hK1܃ä_ñ0Òf ¾Gõ2àͦ ¨«X–=…_C‚ÿÓ= N»qw¿/°€Qò4xkç]O–nI•L  Zûê Güפ:b&<ª‚NKJ'¶ xaÀLÃsvŸ(™m®%•äËý"ñ‘ò F0C9"²«L€€6-TçvjDk ¦~hl²“(Ïí|x7 G1'ÕcÃ:¶' øI M°  Xþ3yWK©fÔ-Ÿ"þ¬ÈØE pñÒ+ò ^u;+IPíêí“9º/gR¤´÷ÿlŽ8!½&¤ñÛŸ´ã zŸU4~+Yg7Üd‰{·Å‡Ñ·…ôŸ¹S Ù=aU¢9OŒe3žS]äZµèß§MÞµÄÚyŠÜaçrýù2¨éòÓaö€ÙÈnX{Yjô.P’¥³ÀÈî6]X´œ`çD?wh™ã ­ËI›™j~]*>l@7yÉæ¢uŽàYúµÛ usÛ‘›À,€)òQ}rD6è×G«ô+ Xýì÷ßÎzÙúz,ú-ÓÅL_ ›½+¡C§s „ê­ó! —äÑyhÒ~ ÞØ£ìßLÏóÉ®KKeï{¶/S¼[Ï`{À™›p°fdzlú‰‹MüpÀ©pR€à^ SÏydè_¨‡êÔ›3l¯•ü£¹ÿe‚ü±[dDé5Wfk­8WªO3e*†Ø„(ÊòiËR…¯ãÂ}x­ E.p"*õ'^l©¸ÿ¡‚ßY\0|:ÐâÍÏÃÅØ+Ò X{§òem¾õƒ(wa"¼õ€®è}4ÅNoÚ¨ŠÏè+ÆwáÉNQ YÝТào Ècƒ†ºO_BÁžk¡TRž,¢–:?чf}q?f€;LûÊj°vï&L¶b2Nå ¶Ç3,KàÑß6.lž¼‚ËñÞ:Œõ_'Þjl5{=g:LŒÆ¢LFXoƒ‘³ŠŒð-*ù’Jl¢X "uÒ¯M5æ¨Ý+C¼×µÿÿ˽¸ÏnÐ?LJèPÞ‘Da5œ=Òc$Ðj8¤8i’"há$’RKz›"çVÿ]ù®Ò‡åá3Cºh7°Œ$Éî<Ÿµvñ³úô3…K5[±fêIQK`í’ѼÝR†Öë4õ"W¹Ñ%ež:'²-9øó}1ÇßPQÒxnÀ uM8¿ÀÞÚÁ†arð‡€ötsçFYÌo•¹G"u5'ãš‘E¯ØšãíΓYS¸x忉<œv˜¡fvèpþ±½IxYöØæ1§xÂ]ßWÀK§10É㈊\¾šœ6c[kÌ’“[* éÖ÷½À4ÆáÖŒ Dð§¥M¯XÏÑG¸³Š3ñ[ÜäBí…$ººKsÏŸî›Ú“–Å6ßxQç 'íàÚÇ·½`#ÕcĤ"]ÕWãÍWD¥„Ôh…LTpñ2¬–™ærhÃCèvÿÃ,Ä9» b…Oý=_YGTpõgʶ› ð½A¶*Ó³{Ö5î‚«Ÿ:ì|5!¨úŒQ-,òz¸ w²éilõþ-Ð5x0¶§6"=œê”6 ³_ôc‹ «td.SG²‚|ç".ú j}7Òo7Ò¤b9¼óuYÄC­D‚¾ø„ê“ôDÐ3:¼Ami·qlóãmÀQiV¦#9ÜÏ“7f—«ø>„Î;_±÷ò² 'ô»m V_¼Êv1èO^•ýoº2 ß®ó*/¬%–à„EO¼³ñùa2ëw ZÑCIkEgf¶ †XÍ+5êoÂDX…±¢WïX¤ŕʮÚ4Dl6¿Þý‘ë_&?KcígN‚:S2%¿ ÿ2? òàùá\ÀÉD;á­.¨/¹88•2¸þëc¦[ûBÇ«”‰ü…ÓØ$Y†?«%—M3aš*=<³vËÓ³iõöòNýŽÛ'ÔQ†Î]ë*©2!mzNÒ¸E¤·zK—-Ë¢¦ÎC0ŒSõŽaÖwé+‘±;-ؽ&ò…*àf°ÿPÑÜlj]™¶LÈ O±_gûÇ3êÕÄltQ Ë©i ¬DårŠ>«jÆPD©w ÏÉ”þ÷=•ÜJµTl}Õ­3tÁVL6"ݾP*™eHHiº¢ø þñ`0&\2Q§9nø³ô Lš´®lìÃæ&·úWR“ï_#…?úÇ÷D1“‡æN£˜š¦¶û8U`¤.eª=øÍ$F–šƒpå,•,Ô&– eÐ %ð¬ù6 Q ¬—¢iJ³)÷›_x±`T©¤UÎÛ²ï±*ÀL,B€õEˆ½ ÐTwPËäQ¨9ò¶ºÊ1 ²ËWq!bòÄ¿†`û±ôØ™CZªÑ˜0p5„6#²¹rG>ͨU¥Tå«iRÙh¢¤’5.ibSý¦Ô ôüÂ13 Àå+° (™¬Õh6Ôk€´‚w¨§ßîóÁ@ÿHŒü‰T‹$ÿFyw? ìˆRÚr_#‹Å¤mVД‘ [2 Xá#xÏ )A/ÕѤ»ú’ „i*üäk-)0õí3÷hfdÈ9}¼7qXó ˜!=¤J:4§¹04PØÝpš p+·dï23æVc‘,Êà©ïmÕq÷–`%¤-‘AJϸ{Ã&K ÝÜ6Ýð?÷€._±øF! îc»G¤›Ý¹P#;û#~‚5Ô׊¿ )sw•銊,«EÚç¤ Þ8b/wãÑ(Ýî‚͈¾Ëë;I‚¿¬E¾â`Ü–lf÷S*–ÁøÝÁ㦄M?… y¥IæI¡ä8~ÚóNƒÀJN(Êœ¦2–˜o¡œ/]9ÂJª’á M4ßæ=åNÑ£ˆctÒÕÒªeA³Cü£<ĜݑʻeDîzˆÄXóûÊl#`Q±)Z¹ ®\8‘ á®tO­ßfKÿ‹º98`¹ëQÿU69›Èoò7a»rTþ¨ë#¿% ­–à„N}£Ô#a¿9ƒ„Š@ïÜ!Êñ­mFµN46œ‘ ÓWbN‡DtÏ9g^öñÊ?¸3ËK§&õ’î‰ãÎŒ%KÝAP/ Ç ^Å H#:ác4zѾ䠾˒¹Ü^qν HæþËsð#̯e”ù ì F‹5÷eUå™É ñ|½[¤1r™Dit’Ó¦þa,g§-Y‹{ ŽEõ:ð¥A‚ÁÜŠ)1=NM¥^[T^ýY·ëïùU£Ú¿¨º—Ý”@ûûK{ï²Hwƒ˜!ùªwT&õ p§Ùè=OlÜ—\Ø!¼N®»C3 Vcxa(}kKIJœý&_yËkÞúr{뢠Øz“Üõ {ÑŠ¯LÍPéTÿr,ù#XqH4»ÔI§  ‹pÛY):;"-j5~-E'GNüÌ0ÛïˆP6²³tñ’uY8>>O¿eœ51(nœ‹w G™Ôh‹&?©ÌDíDî›ý<ù­eÈp¸Æ·eôŽ:òçWùÉ‚­AñÓIêiŠ’Ô¢¡ç•º]Þ’$c$­®\&Q"ÕR™LLǼã5Ó³†®[¡-·ŽZtľ£{µÄbïe®„ï6'Ô¨xÆ;´ÝQê-x(éáE^~| óðNŠF<žØ0¹”Ÿá_ =[6Õ/ÿ£U”©ñ*eü ˜å¶DZŠá¯u˜Àv!Øï‚¾üXØ@¯^d2SUÿú=xEé«rÕ…Vïl³ê ¼ºfO‘Ûƒ‡Í ³åè9ë•:왞՜ ÍQS/Á.“‡(ï†×+ã Ë$à®Ù,; 0¬¨¹ÔÀ¬R–}šµ¤þöà$çè×:·™W@])±É&O†¯üçýœNmiÖ ¤b‰ë8j´Ü׫ŒxŸKgó†dÜ«—8Ádä4W{cÊkÚrIöWÝë–ÃÅš¢NîÙƒ lF”Ékö »yg'ù ‰üWÀvÕ*¶ 2‘Š+ Ûè× dn9p–SùUXï@¥AÂ:ˆ768×vã༜³ŒKR>:'Ítf '¬ÁCÅf²ïýägÙ òÁFºþëz«n¹`þý•ïP8dí×–î $¹r"(;Îí^Vµì§ ¬¯±$0 þçPò €¾(“xßÎ9­Dî#å£ÕïÅ}E*Gtl#ö¨­3êU›?ê1èBÈ>HÕMŠß$=?¡VŽÏxuÓ–½Ï°r-9«ˆéJÃpš+æ0i?-RŽài«!â) _nªy?ào!ck«\!ýþÎèWðöX )&ôUgù¸¯‘¾Æ´ê¡¦Út×úpí÷Åiûå(‘íÈB´PUòaeš–ý -ûرEaP­R9 P?Çdô“Ýq0–>M>$¬®¦¹,°Ê¹´1Ç2™ú[Ƈµ¾0«lòÌ%‡[{QºâNFtRëàlŠ.UçX¿ËÚâ¶åÒ`^ßÓÌâã“С÷’ã@ÿÆX4])¿£}’LUÍŒZ³€Â%¿›Êý¢P–Áã>y‘ËHm»–¼6d6íϾ%²7þ·è æÿ…n.?ÚjuI‹P¼}À£DÝ)nB¸ìu‹a>v¤HM°imçn\#æuX;ÁƸãOëâ@zNƒ¬Éæ‚™v³!æ>dBe¦»¼ïÂ2¶q~[ÉáëõÍ«ñÃiÐk4UŽ%Ÿ5ôÁôðfk–ç@ÒÇ"”Ö³´Hêè–ðHE[ŒÀD€rèýoÉ›ùÁ;(—»LÕᯛ©¡õ쪧UºNh `×[DªíS†-¯µïñ«)ü«»Öv¬†[Ì‹(cøh™ó·jëefFñÈ:RPS«êóXú9u_7òG¶#’g¼à ?à’mD›Î£÷²^ËFÀz4”µeÖ9Ö£Oo>ŽŠ¯R7Í‹¾×vþ1¬•¹æµ6´¹„ãÝ7@Ŷ[R€ZAY\>è2¯ÀÏ‘o޼–6Îòv³è‚çãûw8Ð,Ó®zyü À v]ÕVÊ é˜rJȯPƒ¡ÿn¦es[X¥æç쇕è&¦osºÐžÖ¨Sªñ\T<¶Hü¬ßÙ òü(@â礙à×HAÄGXuÑÞ†¤/þ•Ðw£óþ¾R±¶íÊ´¹ òzÉÖý¬±'U*ëg¤ýëÐh ³2NBÐc :N†1l°”òE’h³8CX€„>‚FÄ9|ŽwAÅ^Jµmm";7ì)¦roà§!-‹g¶ÛæÛ;:ÛÁÄæi–ÐdîcKt[6›p DC€ùV4¹-à‰Äv\EÐ&ÐËüÙ*ÏÊs!Ðb…*hg’M|.°åÌ7ëVÂiYu\ÞAóÞÝC—e´{ÁëofþŒT¢¡Pë1=¾öŨHµ ÿ¡óuõÌÀšäh’>ÇU’g¹®6§?P´ÐTP¬½Ü˜Ký.ívübmƒ,+ÿ¼ 9ä’îØ 4NÈ´\ØkßÁžJ%•ÆÒ3\üYˆzGlÜ7Í¥=ìø’ºØ?î¾P ç‹WZlð<¥„¬’.x  í 5ÐÅ|‘‡éü4¾#où‘­öTgøúQ  ЩÞ@¯DDì–ÌW›t<ÔpÐ*-ì¥oMú×#´RN™s_ûŠÌ¹û É©glým‰8kÁ³nµ`ýôáx°£·¶qøÛ”UæûØà ¬p™G dë ÄYY)Ìôi…+z•,íØº8Ýî,fŒ€á—Æ!â ºc8~”Ä58(C‹ÑŒc–w¸u¢3¿ªhˆ[â2Œ0÷¬ÎCÛ¾9Ì„„§køðêFƒõÓRûRm%dwÔ’C»ªøò¯§ð9¼Û&7'ï¦Óµ’tÊÝȘ8´Òû“`Ž™4-åˆå‰˜ê.»õ ¢¾Ö\Œ‡!±ô©Ú~Ü}c‡ê2*£fÿò]Vƒ×kS ¼ŠÈ·FmpòKT 5¹,C¡S<ءнKïÄO,$C•ûROà/qõ„-.ieÀp®ÈE†æÏŽÜ5}\L¿RŽJá©ox”'4|«Ž©¹[y×ñ”ãæ#ÖOÓ}?8 ޲ Ž+M±„P¸ôar>h³@"ðää{í¤2gÑêÂÖüøûÔý÷ò»fÞ6S·.DršZr³ñ 6aÒSItôoPuŒztQ:•¬j #G&½(‚÷äô^¶qSN³¶‡·Ó#ë«* ñ`¨­zw€à÷ëÜT¢;Ú.Éýä…§ò:ììZè) B .02 A‡ç¼càÝõ•DžÍ‹‹ÆDk—gÈ=Ÿ{\oãO»4ƒ7J'®áo ©Ê£\5‚òûx¡‹F“|¹5ýA*¡ò긗§J)~qø?ñWÎúë´)ÃA©«¡jje¶3¥æ4¥Á>ðÎaí ÐòÄÎVu*4,^²BxfáyŽ’µá>˜qyx¨<Ä[gñ@äÁ]SšÁÌJ\œwâk¢>~ešxLЧ«ÏÆÌ! ã 7ƒé¨Hã‘&~Ίmb]ÒXÎù7…+OfB[é¨Òí–ÛVB¹#Mk4Žma@)ÓòÔ²±$\Ę®ý»ÔÌiïø1@ç–£¼0z- “”÷1>>ÚõП¨Þ1 Cj€6ÿ´Cf®¹V"n^j;S¼ æ‘J±‰h·xWâ• ¥æ¸æÙìº°Žø=L¦ò}ÁtˆÓIw± ˆ‹.5«sý&JÜ:·ÞMq·ãõK×F=`EGJÓ&£fV†°U¥ cÓ1?}êgÆ$~n0Îd¬ðn”Ýž“ß³Á0(ž<§@†©§WçìGÚãYµC»¸ËåªçKT#½±K-üþ+Ûk«Ÿo¡r%0I÷·%N,¬ã-îo8Èê5bÂ{–øÕ´3€xÔ.Ð~í;E&LÚÓýÛ|O+mfä²$×ÓX\±ãU`œ@ÕÒ¥ðK)ªL €Uø…Ï“"Â`“é"H€Ïƒz’¬ÙŠ1îf‹ÆÓßký¢ü•~4窎Ñ0[a{E(=„Ðô.¾»…'ö°söSpß]ÚOÖkw;ÔlÙêIï2 vë‘QSÕŸí3øA:9íÇrö=˜å·H¯› ¬‘‘¡H’þoSJügAÌáèá nI®TcÂ×ã¾R ´¹úæ{S£ì’à©Ã8Ìa,Pmöt“†lwoù/*7OMàkh|€ƒ `ËeL,Pûñæqm“âÒBÉe`S7ëÏ£žaÚ.Ÿbñµ²ÏOBÊ ¾oÏEï´ ¸ÙF°ÜœM2¤ëæ²a«©{e¤†d]ÿ4â ºü9¯1lL¦Û¥âzLåO®å³Æ€©»ßi“ÑoÎøµ9V8›&í2mLx^¼€ê’@vŠåY(W‹œä>îÊ=tføÈ­ôñ¤7‰õ;ŒIS|Y›/¶d)C‰a?ÒY¡ä¹_T°TNöIØÇ=^„^c5 ½’$ù´ðc1_ŸœöÊàÍ`q âbáèhÄõÎõDãD¼±ÓxÓtŽë3펫Äf÷ÅïêÁ,€¦ð}#:Ùú‘C (¹Øù«å=Z?2Eù=C>g ÅOÈ- ÞúOE)±ý Á/—‹(æ*=­éÑW4Îc:ô9êßýzÑXÏŸ_ªõƒÜßúöÌPÅRYeoKûƒë.ú’cߤ/ƒ™]HÓxLéëc6_ë˜íÞ#~y)Ú'`kAÅx®C½T CÆú¯cðYQNd¯Üѯ‘ ›Xæ12×}tŒ:ÔRú«5’ÄÖÛæ5æœçYw x‘GQýÕpdªZàƒL•CM̦Ê(Óð/?Ä«{h+Ý—Q‚DU«º.=>±o1u/…Þ‚±:DGU+χv¦Îs,ç`gÕ’%?÷‘ì' ñM ȉ»sA·z$w+¡óX Nÿœ“gµïõ›‘ä$œ0ÁEnªni±ÕIÑëÁvV‘bïÄ÷(!WÚ‘¯yç{$Î_ÄÎw]5àªÅÁÉw˜ŒüŒ×¡Üñ¨ò M ×Ó׃¼wFž³­¨²ü(c„ãìe½kK¬ I:ÃG&G®Æ îì9ï²/ëáÆ:Û½iZx” Fpj³—ßS»qO÷9'¾­ƒ¤€ŠâÉØÒ(»$&Ço€YP¸t¢J6ëCO—oX9‰S:ämŸK(]çd ©€>ø±‰å‚$jCÚâ9®fIØ+ßï/Þä|'jÌWq5fÑlçòGLSòSßÁg ]0Ñ3*!ü}é@@üRœ4áú4&3»¼$¤',;Þ¥ ˆ‰üÎ0ªÝ®‡ü÷ÃuÐmøÕ-´Ë·Ð>+;m{ ƒ`<¯õTpUÔX]o33’¶ÉýeìçRß…žÁï[H_o‡@SÞÝÃι÷ú6‰°|qbO¶æx“zOК3 jB«Î™%º‹Ö;a×´‡£*_©;¿F£É¬µÏ1àÖ÷?m£Yÿ¯6噼ä.¦®æ¸þúkã,K­'ë!άDU4V6ˆ¸”¾ØtŽºÜÁ;ÿku&·Kd^Wv¡„níðPÉáv($ ER‰•dö Õ,ÛnªçEÊAXS|º“×6²8ÎУ¿Fžœœ bmÒçL"Nq„”YÁˆ·.ko²Þ ´Š%ž#¯ïë9 ApWSöFê=•9Üéy hâdøN!éZå[YÚúãF–“ÐMÝó¯ÒW·Aá–Ç“Újš„[E9M›€úƒwx¸„òbKqn1_³üïóäw¹9׌•Á³Þ6«€_û½”}¨53'³Œ‰´*Da÷ ïxt G©#éHͰ׆ÒIÑúš®&«Î‚’½õdcõïµÃïñ`TÙøÈï¸ÉÈ~b-×å¥H¹õ`X¨n¥ãle :ÔRš„VÀÎÿ|D)¤æ­o×r)”ÀcÒ6J E‡\aØËj^A;üR¥Ÿùq].ÞæÖj(ðéB'OÖæ›»íèíD„ˆCŠÁå)¨݆؞ŽQ¯î˜°êïìbE›ÅÉÿ+è¸#¸[¦`SŒ'[c­øh!VYš!]YF­7ïR1ãæRp!w _Púr~"ç]'êCgSç§ÛKä…v±P”æºw_r,‹áÞí èÒå¢yi«\$òGÅ–ªŒù®½p}›ž=ø!…yÕ”ýe®H?yJ8N«rùFŽ`ÅLŒ›n2 ' ‘ õñ²W©oŸ},ƒ°ÁHí\ƒ„Ñûã³™k£ƒˆäþоÌÎ>iJ€é{ΧV·öÂÖ œ}Tᕳ+MªÒ€‘™q_gd}J×ÓÕO6ɦ þmJP9n€Ù"ç6‚ÏM9`¾ôèåËJ:‹%•Ű:€›Ü%àÀÝýs6×ÿÉbr,Ì«›©ä8ÊãTf–Ú¾9Ï6ê2ÄÃážýhà¸1Ìœ|Λ·Ö€Þ¢VP…€Ú+Æi@¤ß#º©D¤ÃÖ~WCL#Ú›ßÆ{ÛFŒEº‰ð¸&T‘Ý<ÞmEôÖÏÁŸhg&Š+ÿ§Æ§nq½N¥§X(;Š&7Ûg˨_Wø͇ƒVÛ"õˆ\4uª-g‰ÌcÉ&DuE1mjnØ™Sy3b›ï¼«l­šž“³ì%žäŸ"±XÔ ,ÙËRŠŠ… ¿´õ$­èôÅ‘ÄY-{$æ,’êƒ&-ݘ/™ÞæõâIPô·ó-q%t¾¢%ÊnÖ çn ºfS»ßrbÉ10´ºâ¢nÝ•<ñg½—syÒçRÍ•Å8äé-Ȇ¼ßò.Ÿ®¥ù—XÞºÙy ½äÜ.ò’iZTq•ç²pß½¯_,ªþgß`ˆÁæ-•7Ч´œ-ÇïcU¥Ž ûJ'ÁˆE½tÿäÝùs÷LÍî”BÔp¬»rÚù?TÓjCŒ£í–ÆHÙB’½ç/]uS嬻VUZ4:n›Rƒ=‚bŽé5Z[zˆ£& bÝ![ÍlQ8¼3 Ë“IÀȯ,½].íqÕÚg¢ÃHZÎýDÔë:!u“7Þ¹d!‰÷Û‰DxÜ®»M›o;øê ‹|§šEÏÜê Ý›šØyÃÁ±[4±1¤ ™Éñ«¦FTÆÇ€þ¸‘3—$¦º¢úÚÚS^·O|µÛá’«A­cLF täÅÔ¼$€µ(F3ª\Ö‚¼y†­u¶ÍÃuî&&îµ,ßSß *jËü7Ó(16bšl6ì´7Ÿßª:=”iÜ›xª¼‘­åÒJšŽÐ0‚•V ‡ÒäßFÕɆZøÕqCdD^KÀj"–@Â*t1 (ƒÁ‹“ÂìêÚ¿Íf¹8eï×"KNIçÀµ/P)ÃEÁ—Œ ФÚ~¡´3à1O+ÃáᮯZ9hl,¾ O Έ fíÎt¥kóWÔ–JÅ®¢ráe·‹ƒSé>é+“`0AQt(:çÕ\DÈZ¼µ$+EõÕ°þq&v`üŠª…<ÎV䯡Žjbþ©>µòV ŽGef-ACÍB-¦Z4†(@öÙgÁ1… 93ç’º¼Pöò¢%/ŸlÑö³~ Rªfè ØèŒÅTE#ËÈý¤ÂL|ϾgxGS Ú{Zu`MËÞZØðw[ß7)á­…–6P–áPÊw¤Ío?xø,ü Œ—2+sP0›)§­JªÍÛ;°Î£ =¶ÃñÑL-ûÀO>•y³'LF×µcÊœýY6Øq7Z4(Ž—º²*€SŒÓ¥%ªž·[:£W«Z0#‚šS@¾âÆ&{BxÅx6ÏhK¤®â€ \Éáò»žÖH,½Ž ¢&Ý]åFß›êaÆ7()É3ÿ’ß'=rf¾ì›zÅSU;W×·¦‘†ñ!eÜQ¦± ‰R pû~ +$àÆ5ýîãQÙZDãV®Æ¢ÁÇ ¦À¤UU’üÎÛºaV8˜ùÌ÷ßÉ|ÐRr»AË/&~É6·¾VÆA—Ýö)n·„S4çFãljìôf)„£EŠÕäv‰wRÖ0›§æÉׇ9¦“pl‰ã–s[³;:žïASÑô”­q½ŽòÌ‚˜,á±xu*XrHàØD§H\ã*8¶Õ­Ÿ‡@0N¥\#¤ 5ªëâ©×æ}‘±Né˱Ri˶o¡n6ÉÊùŠË·ð{¬úIßhxzö«­ºˆí½ž%4•Îæx!‰QWµFÕš²:åé.} ùðªÔ!6Ái%Ö¢ÐQ±`¾}sÄòtí4Ø[Á\êX-›ò f ²ü ]JTÁQÿ•´b‹öÚ‘$›‘â´Ûñÿˆô „ØÕ4ÕÕò 3=‘~‹ì~-F‡ü­Qk`Ä€ · U´I3nrÞco65&1¹™%\-v'9ì15‚¹ëÏ0.æ Óg )Ë0Ñ­¬dWÄínîÙ®¼hö`‰€­â@Èd–°OKÁøV÷P`¬TiÀ~Î<‡NkQB×*õj»³x÷MLØYãª\>²í,ã„H…“j~õQJõÀ¹ÉÉA:»v®ÃŒ¬u˜âÚD¨Àã3Ô^÷<]Ý®X¼Jñ×>}£Q©Iâît.Š8”ZSµdHoÇTÔ“Åg4½æ§=ÓÇß&<ÉSôõ2­)¿)óΉsÝý"é…AÞæé£È~’eÚi !ûòZÓÐêŽ&šÏKtð›Í•è'‚á À‘Î/ˆáy«Pž+”ÈÕ÷Ô‘" ÊÍ>"ü%ráæ-ùtnU‹!cÆq{ÕŠ„îM¾ðŽý}r‹Ytsí5ÎÈ.Mõ®Ý§xT*Á7÷{©Ée)‡D JÚ£WôôF­oå4žá <|„ä‚qž¢ œ8ë¥ôoj$ìh|>nñ£3{…êiÊ|§Èüç|˜(ðìl¥=ß i¾2‡.\J¾š…“­¨c:`ÌÙ0ffl.ô¶J!Þ—é ƒæ!`Àdšø<Šä@´êÛW«°©þ[¨ïëÁÈ9D_HnãÐ÷ä…[J!¾×”©R*£õýMiÁvg­ï–Û׃=§`\ôÊm=cQâq|4%“N/UuÈêœ"YW;ŸEÈKKš‘:|/¨ò›ÂÆ}6<ù­XèÅÕ+$'P7ÛÃÚD‚ø5¡€' iÑ"&+ùnnþšž»x2¶0ý‘‚RB ÷%uqß"_ÑÂéœÆ; ÙÚì½³yÎdoÍ->•4q²óEçdl‹¿­mÇ8ø)RÜÃAo[2™F&8Qá¿Ö4þÙ[â˜xÄØSÄŒÂöìÞJ3Uј?"u%S=DÊè@«mÊxÇåÙFݺ‚j€q/dqfB³FI¡¯‹,¾\µ‘ߪÍl•W«¹ŒåŠ#@QµD{œÚ<[.Ïü!ÈøÜ E} ;öéŽϾH(ê¾öOª0Ð=„@nù°&D2×U¹<ËÚô¯ëÙÕðÕ‡àåÑj¬x'“`1<5Ò„ÀX>”tË52•ÉÐë°Ùu¥žÐå ¢Þrƺû#žEZ­w”owo”ÌõžØ­añL_^ƈfÕÛ2Šk‡øóßyÛÛ¨šø(Ê@›¯‡‘º‚E úÔ—à1ÕKc^—¬y¿‚Û¾$æ„È&ìÄO»¾VzÒä¾Q(!þa~l·;92à Cço耤CŸ˜«¤úk[ÓrâÎ?ýÿ=–:ÿ*ûå iJÅlu¢)6E‹·Uöw9‘¾ÜÀ88~p_|ÒNJö'ªçÅÁ‚Õ²Hèw’²µÉË‹ÄT‘o“1BçH˱ ¢xó9Uí¨l/¹ö5ÂÄït1-Rôþ‹“-~Ô—ð]÷‹ßøÑý­ ä0ú žŠÎеbßÏ1Õº”qèäN2^Û\62«lAwÒâÉßlà ìç\ö¬òÉ¿‘{¡Óí›^Á±ùãµ´k‡É4ù"j‰3ïª_ùøIÁŠ&’&’}’TØTxò¡{²»|è<€V½`IÁ ;³Êá“Æ¶Ã*.Úi®µhÕ"®ñlâAÙ Ú˜c¶oíú.\iá’u zCË‚êF'ÔÐØHŠø“Ð h¤Ž«Ý»¾³ Ú^»¹+eÒš©?TYm•=AxˆÉœV**î™ü¼h´³¹ðzZ’Îs¡yº» ²†ÊëŒ õD÷.Jâx%fLñ¸Q.íõàey“ õ]ì‰ÈX¦UÏ x©Áæ“‚NêÂ×Àß<)!ªO»ô¿ûf)¹™ÄÔ™ÏñÂË¡­òf䤯ÑãoM)`´· ³3%¾]a‰O ~ZK‚¼ßŠ›ÇÇy°Ÿ~)äá##B ‚ô3}Uô¸a“"·Ë¨¨¤’ûC—‘©% @ÿϪÝ´j…Zç}B^ô½ßÊжÆÙ~šºw¥‘è.ȱñ]«N.*Q´À2E~ñ•U§B@ò ïW'üÿ&ürl&Æ™`9%¸Èœ|÷ü“lá^g¡¬âg×½ìiTxÕ´¡×Ÿgâ%ü ǵU“Åq¨ ÍIxMeÈ<3pÅìª]Cüä¿ ÃÔ*Yó(Z®Zc_å3›wi¤,… çE·ii?š[ªt;ù¦ŸŒ©™=)àÈÜ<Ñ Ç²ësEO@rŽÿ–ಽpE' ;…“£{yÛò½B¤£qˆHB¯¦Xn‰ÉØì³A4=J©Í~KÚ›`ª¤Ž§<Šš8¯í1ºÔdTEÚr$¬3íìNsˆ‡ž?Ãñ"Þï$Ö7‘„P5AðŽ¬ª£™ªºh#ǨZJW©Íc÷†~ƒ!›ØÄ‹†ŒX\•3w¼Iô×ÂjyžÆëW¹”*‡;hSC¾%‚‰?Ø(‰ 9·ù2€óK™¼ñ«“ÔÔ•F0JìƒÁÈ]})(z7éÏØß.1Ò÷eÁ¸j%¼5e}yÏIÆ Á,ÌŽQq¶‚p¼èRúÓýÒƒlÉ­½ö³ªŸÁâï(+åö›º8ÆÊ÷låKä%Í9)#¶‡~«Á§„@´£p P7 †˜üØôŸºÆ—cRµˆÒ²Slq‡W®ž´;Ž Fù톟?‘¸!°£\Âë™”ßr:@Õ#ÝØÒþ¥®žµ%‚}»:˜/.{=ˆÕKµò¢%:·‡k·øø=åaª_"dªÙü¶¢è¤\_»ÉîüÕ¦ ±*¬t gýéDDEû˜:¥e¡35=‘Áæé×Ý*+,ȵäµn/|C;ýŽò¼Y„ÈNé$“-—^ &o.Iº÷CD~ï÷¥Zùÿ“àZîòÃÿâKç?¼½bO§R³b2lž¬ük¸Â¹/èC  rÍÚ¤‹"¢ËXÕÊü\]—®U50ûq:¥Ħ#áß!ûf‚£¥Ï˜¾vḔ–z”µ'¤ÿgEÀå ˆ%Ä£Ô:ú\²|æÏ¥=ÒÏ1OøkAްm“Xk_˜$^ÍØþ„U‰úzü¹ý3Œ9 sûcABàÞn·Ùº‰6þB©Yñ„nÌàÀ.ÙIFí |rúeUœŸ™•I#-Óð–Ò=ê‡<•½¢ü u»²[bʰÑé>~ÌæÑszWöÁ ¶›J¶– {*7ú·ìFGzµg0Ê#'°¨ˆóæzÒã©¿ Åó®{)˜ àû…•Åîæ`CA@Ç+ü(PÍáßô+hŒ½dÉá Â4àÀÏEÔô@‡lÖTÃó©2FõŽ"9´µ|Õ ·W /t“‰¯ å=Ç›ëp1î X½”9™WÀâc‡¯ÐÐö~ôKêð@î9ÅZ°¨A)îÇ6‹Xã\¬O$Às> N'ý*®H7Ú‚yîi*A„µ Ä·u+‡%: Í‹çE`¿ãÅÅ7Nv““õ¦ ¥ò-Gj¢j¡nf†­b9»¾¿ôÔÂÓ£|oØa-…ÓU/E»Š¢Jžˆéjv¯x²ŸE8 ›2´F¼´|íUw÷ºw}hòÝ…ôæ Èh¤ ”†™ÚÀúõÇ ÉÖ·uù²E¼i)õÆæ tc] ô A‰ÃuGH­j‰UN_yΫÓ=+—Úo,¡°/á»Æ¦lB¤l”užü&º«xº‰f…Lð±ÏpßùIÂÉÿ’…oìÐ¥‘*Üí|]iÊnþJNt³ì¡ˆ9i fÈŠàIáÑp0нÿ6ÃØ¥Hë(Ó7R5j7˜ÂÅ9ÔåÂeèÕ\¤yåzÒ”±—èax Ÿl4`¸mkaÏ®—¶úŒj|äðý¤zg)*š´hXëiüî ñchëmº¬£ÊÌwÔ¥Ù_œ-PhÏ+*вá¦ÎÖ}ãÔ]Œ)­£,“Âñ€ÂPNèæ˜¬Sšš˜DbùŠæü PË%Y£úÆ^Š©Ä üRS\4Ë×Ë:žâzg³™»¬Ð{— S• _M±†ÒAÇI×Ê_z9Ï럾#1-IY‚uæ ·&ªÄ†nyLÂß„e§¼§T[:£!ð6(ef¶èR[gpà ¹è [zÅM.±¡cËš/O¯±ûï—¥íäb\±ÈõÛ±K]¸ç§ÁoZKÅù4œÇ åd¹×#Yòº—Æ,["à pÙUëàb†m5õMŒ(­½ùÔ¼ôeCc²¥«<J#œö]&p—xPª#§ªÍf ççkxïXˇÌãõ9ç%ã~_L=¤ÏTwUãª;ó$HU»xà­×éÎOuGT;¤õ×}s™sp*}3T΋ÆÀèä{’è µ6K§H}A‚àzÞoèùW²#v:T¹ßª‘JXXtüoãˆ7Ÿ#`–ŒÚ¹’ÚŸÓ›Èw—S‘62Y)_§ ÑÔ²ýVt§ñõôxìCÑñ¥ãa4pVæ«3NHŸFYè€Ó·ÿ.‘êBoɸÏb\oµ!ãîdª¹x63…~áMVoÅH˜™Ä,uES6óš0è|@ê@%ƒmÃc¥‚ñ¹Š ø¢‰0A{«~鈴"¨”¨š¸³rÿMfXWB9çân²åkâq¶~ ‡:ÂIG8€ýà(Å# „£mIx1Aë,z³í ¤D¡vWê[\Ö81à[XÓ~V¨äÒRe‡‘ȯˆÐIk#Íç߸ägŽØcv÷‰Ïöä]Þ*‘adÏ P2Þ’ó8Œ-{.’C!Ý´Caóác_Ž’Ef–ü£Û0Ó;ì òTãoõŒìK.› ƒNÞÕ.ÈèW°Òøo Wĵî%G¡VCþê§`ãWœÜBN>wÞ/¨N3ÕÚHµ è$aШƒoÀ¿¡ƒy=˜n¼eCv”䳘~½ðô›ÆÜd@¥n7ÀYJÁ-Ø·wtè[»r9RÁ­'«H¡?uÙê•F`‹aÕ0ÈÛiÕ£†O¥x…4h§s`b¡iŒÆa0—µ‚;š»íf3Jœ9™›í(Jä¥^¾’0#žì2bz_4h©Z@Wã¼mN;–®ظM\P‚užbÅM¯È7$ò3Uâû56UŒvÍõ0ÎüÚî~³EÌÊß&¦ãáÈ‚`ÿU÷4úqB»´[‚†ÉOÁjO¾Ý"rÈ‘}¢pØ‚ËMººí+òž <¤ž¼í9k› êkŠ "f³µtëâüX=—¶æè”x¬!šµ®ƒ”œ0 b¸"p±Ýµ¹tñ,RŸ„{YAbëø_Fˆ¼@£yE¨²QHŽ8õ~ÍLä$b£ê¦üì@!‰žîèÅQßcH…º+wJñ‘`¡2][¢³Á.]tò ØÀÓÆÊî9Ï$n2¨‡¾äÑè˜I?6ûªr]Ùš¢@óO32:^aÓŽâÅÝä_J¯/]±‚ÏojF âІùj™8ÃÖX†‘yÓÙG7ÁSÒ[q%dz{Ù.'éôÐXÏ3=?·‹ŒßtI}Ÿ°»°‘·Ì»:–»Ï,^9Ž-òeÊUŸf…Y 5(" ­.Øé­œ±çï@ œ2§µbC´“êþ#k—+É.)—ÚE5:l'h:J/åb}/Z»˜Î Ì}ìŸAàñÔçSF‰­»Ï–Šó 8uW"ózßA½ÇX‹?B¦QˆP>Û- ¼—‹ÉAØ×ÛÞ–T€:] ”¶±á÷ç%V%½¸UÎ6–?q®¿r¶!–EÎXfYE«"ì• IÖŠRëƒ9šSdòÔ/ìK­Œ)#ú>nó%õ_ ;qµ >9æ¢ô@1A}=ÈNM—ë t$79EZ¢"&kíOd}±ÁéH1_ä)¼[q÷ÔëºÉªž™,\Gtš¼`Õ$áV±'‚ ¼-ï)'1ê›l…ýYF¶™46.aM­<øEb Mùó¢®Å%GmIÂqÏÔîîÕcGÉ1…Ù©N5¯À ꮸ^ýŸ˜‹šs·»5{´îNô[=ÏPrŸ”f«ûwi7= jIúÿDJŠ5'K)2TѱLqØp¡f)ÌtK Ð€Ã¡^óy¨6üxúásØô~kÝÅ•ù§“œŠ¥V6¦G[d÷ô«Gp‚ýæƒþ<Þfa>‘=/$N¡ò†“ƒ¯ÓÅ4àé&¯Uè‹L3,¢.äU¤lØHÂÒÛK¡×:ÚÂdõøXÙÓ 'ùar%• |µ\öWv1›O†ÖÏ~ï×Èç†õõtn¿ÍÎϸZ3 ,¹%ˆÀfðC/8ó¶ÐÍ]ö¨Ø'ú:HÚ†Œ38 4¬Šö†3áHyŽe€h6GH@È[åX"ˆՆZrxy4êÊtWŽÕ”oˆß•‘AÖ¥MË¿!gz-²Yþš²D…õ5_¯¿¼,´4a09¹I¨Dôsð¾ÍS3ê©=ÛJþB1ÚjC í^yÿ;¡* —™(‚Ùv~ @Ò:’”¨ïk§ ExHº‘Oð²1ªÃ› 6—Ø=r{Æ_1žŠ»À ¥ð«6ÿp¼ë¥ÅÎõÍÜ´%‰±¢¨pÃgÔ0IÃ+~à´Rv‘ÿ¬¿ëŒ­ãþ:Qýv©mœ7ð({ó7ð<­Œ™ïÜßRg§‚`ƒ^bú$Û}nq¿Áò¿ØX$(U<¨<ùŸ,  %è=K“ˆzWŽá¢v^ÕQÊ-FFC•Àl Ùâ «¤.…ªŸvMÙ—ó¸Ð¥ÌsM·ÒÆ2È$÷ü‚ªí%=â‹X͸ýˆGŒßÿúF¯ˆÏ:Àv Ã’{n{´ü®ÉØmßÒ[ò_² j öúšë"aúnŠIïÓö4Q]ÅÕ,9ñ=¿Ð¡×G'àf£¶>CC¬Ì¦Ê«3Åð§®\K@ÛˆðôDÚ…çnØÀu•ÆâawJax_g¾\8ßy»ž)µož„k ¯ë謀 °u…‘–9n,žxgLµ~x3É‘«åíoØ›WvΫ|¾Â'W5ÉÕÍLwô ‡Üâ4XtŠ´”Ó\âj†ùÑtØsÆI‹IT ‡Óôobxf´Vëò.SEpÛ@Ç4 Œ7{ÏÐGðÙøD±Ó J¹ñ¨ÎûÌnk£‰çʪApÚ†]?Ü`5죾âQIbˆbªð€ŽÆrè"jöGÓÁK’"úF†ÅbµFyzO¦WC¦>Âæ#FÀSÀç†ï ƒnG™³+eÝl·½ lõƒmZ!ŸÇ æO.ŸÌôjF;Èω#šrËš‰%PL©Tº[GhÎ ‘UîÄud5ñ.Þ —ÏÑ\`ÙZ&µHiÚótE:CˆºŸú7Øîh-È_4·›Y{ÖäÈÏÿB­©Hœ²òt½z*Éw¨ÜÅ=éì¹›ÁÒÆôMï”6ÛpuwÙÖÄC9ó\fÊcß"¹V1s¼l¦ Ôª 2ô9€Î.v1pBñý@àËéû¤lùÙˆ1¯ÓhçÆ–m§m¢ÅÙGöŠgž W®ÒkalóæêMVYå'ÙB.Ç‹–ZXضÚUúnvË©²Öö»•‘ã8¾U=Ó*rÒôÁ$EänJ„[×þŵ37ޤ!ˆòjÙ~»%{P¼¹ªö.ÊHˆú÷¬ñ£™aË‹£ÅxPÌ´Vâ EtZÉ 6b¨l’yŠ]÷òª/{tLó{Iœ­C[ü&nT˜ïu¦KNt4ë¨åNŸj v 'V£ŠVxþÒ4F~ -·ÓI¢ÇÈ3ÆY¡@_ 7…]ÞÜ1I$¾˜-öv2¥AËÙfÂÇ÷²r…ŽžlšWÙ,D„=Â=9U ^_/“~9k\öµÄ+øxöÞ)Õ,Y»VtPίɟ}(K¥ 9kØA붮̮éè‹x/co¯÷æ‚¿™ÿ ý‡r“"5…‹Ôk*K­Œ• V«Ã“9Ê8³öÛ³ò©Ijiôûƒï¬qÊøôËѳNoŸ¬èŸf•zÙ‹èD,’Â\_­øþ~ü0ºhÝenË…}CHŒ® x”f/ɉºïÖ Ë…4—âÊ¿­ëÏ =§|š4(ûíJ©Ô­BB£¼ÖSáUðsF­¹Ã0¤•ïsñ'jHñ‹£Ó¨å9%ÐÀ7Ø)(sh±/¸ ¤%ànb¸ûC«P®”ÖeŸù^:4²<ÀÌtòttÏrßoáœe6–u)Úî –™\— ÿÿ·þÞÜ=3ªåiõ% AàŠ”) ›ÍÔòÝéMÑ©V[cXïvHñÞn’h”‡±Eö³•JÂÂ0.j¿ÌÃå.Öçhж©Š#UÃw|9Œâ¾d|h:›'¨J0|§SlhXtó¦—”ÁVè÷°Ì}9¥£©UÛÚéîC ΦÏ¿m›”¥_ ƒw’ø¶%S%‹V7ÌVAfƒ­)èz†é«Uœ~9aæ°È[à¹rôƒ…¾ßî­96ódØ÷o:pɼˆ²ÅôB1”ìô–å“‚ÀÒìA!î·r½)ñfúmi3'ë¯êcMA²;£#)ý±Ìeƒê)ºl )ÿ@Ðe°äSxb‘òó¦5\XM`ÏŠ;îI XYßnxuÆi5åáÿŠª´§zÝf`'êZƒð¿ Fü½  Z¿--é#.M’Ï'ZKq /[­œ¨@¼Ûˆº4¾ð×õÓš=ñt½‚ ùÙþOƒ l³ß¯BÙô6ê`˜s‰*¶ú‹£ïÎDܰFg+è:J;ߛؚL*|ó¼d„œLó3Lõ¹.û­¦Ä6ÿ‡íãó Ônš‰7ƒD+p–i¶_ÞU‹y$­ÛA`u>}yWm]Rü¼Õ :Õ¹•ñžy³Ö7?MÙJ)óŠ«¿ºVÝÁÒH¢TV| zLÚéGŽ‘öF\ºr²ñŠˆÿöC…öû¾ ÚBgäíoËç“wB˜œi"i*í"ƒxê–¾÷Ü»êfÑLùøa‘$R ô±ŽÙ%ˆÔqKˆ6±Ìx$Œvª_ã²½½áÚ›²ÜG !R .üs[p>„hâ9¤lpÓÏ‹Ð|°u[{–b˜QÚq¹nÞ›âè~wE}ñˆ]lˆ%dÍf?Ty‘Á€˜ЕªiÜñÄÝú¬“/åGKàeâÊ6Ñ€aúMdAKkkv‚(Á<Ì%õIC¿\y'Ga¾zβpÐ)]61uIuǰ:à|; ìt[ÿe}LXP®™þœ2]ŒÔ“ƒ¤ö_úJ®1âcèŒ õKhÊ/;oеœ­!Oë„ÅëÄ÷Ç çAáíTïêé®íxy§q{ÕõâŽN˜–îž’ö‹Òª®*h@.bóðÄ‘¾ö¿±ëv‘Çÿª€í¸tµþKíKÁ¨@‰ ÑÝ–¾{— %ÁÚæ5I±Ç ±¡q¬ïvƒPü­ÒRÛ”-‰°½†Îñá}l4›ÿ«eû¼#&ÁtYT7ž†ÙKñõ·h÷F0\·|âÁ›=´]}”gÒ™žðØ2Wާ'¹ú½eÝ5)Ízu] +@-Ï·3êþãì‚GÇU]ÖÛ]0ì)ÿ‹_ð© Ú—©„©  M0Paà°Þ~*#¹‡#ÈÒ¥Ým4&×ú_ƒY9Nýg>Y0ÛöݬK·3 ²»ò¾Âµ›¥èJ=ž,Z)²3¨0ö0(b>d",/Ò€0µóAÌVÊ¢.¥àyzY8¹`Ú®}…Ú‡kP–QA;“®¡s0hê*ÚBp*À§ÏZuo‚Uàëy˜9±ûL:ÍVÙCÐ}­ BÚ»åêŸK-ÜœÉDìäÄÛîyøµ^×Rú'÷€?ÿ¼ ¾5»ÀݽJ¿-£ .-Ög‹Å$è¹2èƒb1:âR—Kbé4¼;„õŸhйÓalwùËp‡ª)ÆÃöÝ侘„WSW)ÙVËùþùÒ¿ô®7Íæï(8íwL¬uSÖ;ΠÎ7™áöSÒ›£`) ã¥Áøw˹2ËoŒÅÄvR+­ƒ‹Õ9|©ÂÔÆY!V%Éá«ò¾Ïcrt›H´(KˆI ¦ën•­?V°(1–6™ä†a5—cÛ¾k²s¸¢q÷ݲÇ!ü_Ž`t(Ýsg–|Žà…Ó{{XÔíߊ,¶%…¨ðtEèïü¶YõÓ[¾Ù_Q²¢ÙCø7ôÐ#·–Ù“±|U¹2)A=…Ŭ>=sÕ× 45à9ýŒC»J¡)úͧë½~dôÐt^9!_gØÏIËÆÂ}‚ç-ùÊ=Ü¡Ÿo¾ºª1F¶K•× Å8–WiEüî‘€ì˜D•YïM-È@­¯ÀÂE7ÖÓÍ¡ÁTWÉ"öã,`]ei6‹d¥j—ÙN¬8Ý—Pþ!ö컎¦ÈæÓŽ9VK&yÐ2f³GÔ¾±R=9˜8)[§¨m÷ïo…¡]Xk3³Þç‹ oÕÿzköe®Ô0 ê"C _H$Ó~ÀóA<Ø…–³õ­ñÌáÖçÎü¯?bé<‹Ñˆ[i¥§zX±«gɽçheUËPOfQl\s]ŸÉ½k{Ÿåý¾—¸”Ú…K›_NÍ=YVþœòGÔò×õo/–QÙö7¬Ðèg\j•ñù$ê]×%Cé1ó¸u8pQaeïÓè½”¾÷ð£IÖÇœË"%Å<\ôNXç`ûµ—à??W+`µ)Í­ø/LJe-œñCSSIAûš®¿F§¸ZÊ<{{xÉ` oÒÇÎÎuêóÏpoªºA·øÚ‘˜³*ô=Ѝ{ŸÁÓß;n¿[º0È™+Šø}„[ («{ÊÝKØeiîÀìA´Ì1PötŸëÌo`«·b·P+œîYÄÄW%Vv!¯ë!cöŠÙ¬‰ˆj¾¤úÏœÊa;"­Å9‚…L|Ãú¡úªAøF‰O?ÄìÕÚØ,`»bÿ#GëpŒ(\¼"$ l6Ó>^–]j°í]jþ:Å>áŸg‹28–u_eÎ9‚d‡}g,2‡X”ëÖ2H}1JºÚ?¦ë^x¼ïG­2Ñ^?À¾ c)ˆ“sL AJü(úê¹ñ.Ò?ì|7º§zLÔuÃȈs.Ü—¢bL4…sï01ˆ&íÖê.öP-ÅT-€#µ$ÏEp8¨·U8ê ã¥øŽ GóéI,8ȧ‰LSZ›Z!ùòvòL¡©(–‚µ…«4ÍàÀ:x`^ ñÁ»†ÂÛ¹9/€-įŠRb'›"ʑǓŸ(-•LMðÍ79‡ê¡»õf"yµÂ:Î]åÖÔEËØ‚Eõîj\c¤Úçܺ`¶uUÞn»KâúiÞ /Øã# siVB@&h+纚&àµnz”ŒOº8iâFìËnˆé´ñI¤)´Ü¶79T%½H­T˺° D)0ZâÍå‡pC­¯æÊìø¸=õë#Ì0 ‡éUil9+¸¾6¦«[pkçøo ´³ÈDbY<«4”ïѶ‘ö§¸åã6}díÈ*‹r¦ÙÁ6z¤¼7Ô(? »XiT¬ÏšÔݘÑÌp§â÷)NH °ò‡–SôâKž,N¡Ø_×[²{ ˆM³@•œÖ5b(u7Ê@žgx˜Üþ«§jxxÕV¥ü5–Ú+y}”˜6TÞIU´K¤–"ïlv=­‚NˆwIqµ{$ùMð£=oÍ·˜"8ãdLÿÆ/¯Ø7ŠPnÕå1ö8®†„wì,;9Aû>ô<÷õ-'D&úÐçvÝU?š‘…„ä\íïk [•h .J ý»9‹¼«žh2†ïàs­7àI8˜¦Þ·•Ù{xûŒ6©ËÃfáïÔËUEyyo™Rd”_A†óPýϹ7îã>—¥ºÿã: ÇKð1n¥r²[Ï{LžÒYÓFE, Û“r˜`áZà¾Ïî§5™3]?©ÎȱA;$ÌÃv1vü„ °ðH|ýoiŽÂÞÿ@î2ƒ=êEa­Ä1·ˆŠdNË’³#í™û_«Íâ½Òí<ÌB›–bHTH2òà%x&8NÛcôIùfйZêev=AèJ¸Ñ€a#7hKåU‚z«Fü®ßw^rF²ÎG%qØ0_Tõ°/•Š|I°gþ 5j «_n³¿÷ÇÐê.(´R“P Ï8Ü7i2gšÇô¤ A8€õKyõ(ËÜ4Ãj²¶ ÀâŽw ºÃƒSެùßO®ô`?æ£&;íbUd…Ò­•«òú”&žÜù8Í`Ý^Ú\_®PÂDƒÓƒ3s€Lâ 2RZà@çmD”u%ÈðVÁIDâPBÏÇd:ýŸ†±ÃÐxÞÄÎ_[(:’Î+4ƒ~VK‘›ñ w׸ uí›oLˆ³0µ"tËÙüšÀ¦jÆu…›VW)»ò›ð®Ø:¥©h£;GâÃL"äGl4ŽH¼»è*¤ã,)…»o³¨M§Û—¿†¸xã3ê? @ž§P•b¶ nWÁ¤’ÐëyÁ,°Õë6UßÛD¬æ-HØ›³s‚ðÅZ&ñšq»UQ’òù†ô˜ŸJ³$7ïk‚›J©$Ú.½Õð;4¿ÁÈîñQ2}/“‚_ü¸#°ç¥v³0Þ˯ÚjQâËÛg¡›¢‚²iÇ©˜Ù—š#óÕ’+̧ñ»9ó;"qšHw»ÑêÕ=ø¾Hª¸Ý%åñ±mб2:Q»7[î¦TÈëp¶kÚggÃf²lƒ`ÌE2Ä"ðÛn%ž 5CÓ·ùbBý¿5»ÉÅäG¥@¸ÁJ0õ‰»íÆÊyŒÕLý’¤ok´§ ÆÓ]1á×úgIÌÚ[|0½ óÎø¬/íËaa’åÌ–‡3ìG¯$s=œ©Œ1šâ.´WщGFa¤#œøSÊ…Þ£º˜M]ÑÎE*e@Ä¡”ds0ULCEôþl߇h X‡ç9S·‡st‰š'Q­ˆÄ±Ëj½c0ƒRw[çò·—Kžl‘,ÂPé"5“ӌǫöá2ÖÚ%WßÛa³(8aA~4L|̉²ÛZ¬î0hy_ýYGð¸¯ZÀJ׿   vP¥>ü^0?ÁdXßLÜtàkjÞ¾% ìPSL; ‰Iò°{:PÌߤ2:ÒXõ"”_Xó%AS±˜öÀÃO7%¬²›ujiø;wL½ÒªÊÑ’çoŠú¶ý\û¥‚q=«¨BM؇ ̺qò× ŠˆÿÕ A‚Ý7*‹Lx¿hKÓ*†Ôsô£ Ü"ÆBÒœ¡õ ,Ù2FuÔ•%Ç:.l«â²¶B¢a³×\Ö£¿!óíý+’ý‡¡¶œÜWÕ<zFWý‡ÎGŸñý»@%TM»e8˜4מõŠÍw%PEøêUµžÆ Ö*äó2@;q,éY-õœ«ùïòŸ8a¢ËŸ´vrWËQðñsÌ× d,®ÃÁÃ, ÁðMï`Öb´ÀlFv ŽÚȆpô-ÞôÎdQ#Ĭ)ð-ƒ»E^ñëüWÓ¢“ÅàT"¬/¸9efg eµ®b)W7§ \L-½x9EG':”›A!ÌÔ•.É9ÁN.Å_ PP»ÄóÆJÙ¹e# Aýlª.Â@Ÿ]w†}rÄÏT,ç]æHŠŒôƒêíš —qöW€ô˜W 9'Ö¨9¹ƒÔØWëã†ÏôóNCJ“E£&z(c·Fz§ðîŒæ`W©’³ÚO…¤YņŽ‘ÿz Ï“Ú'®ÚðáiQôǺá!wo“Z_û¯á½­úΘªùØ=I`Wç‹ù¦Z,-ØúŽ31åž7;Ï^óãÿÖ¤³y{Üq Dt­(@t` äõ&jM1¬>Ä÷[{g EôaJ/kÌåÍÑ;Ñt“¥ ÑÎ[•+{1äqQ’ÃŽÔ…“r]ÃvÓ£ “ÿçɧ%âÊSÆñÖÓöKçws4vÓ" ! ¿‚‚°E쨭¸®ƒY +úÚ;çÉ—á3¹‡>YÙ™ Þ‹SfáE'=”K{°ãVt5€ä^ÌŒÀéÈúT>‚9KJª=¥ÿ=+ÛfßL»ÖGÝÌÃÂOÖ µ³+&6¸-œ†ÆÎ‡¸0UÇû™ÚA"„OÜÚE{¬ïS&‚?Umt‡E"fŸýoùjr“öÍ3b¾º.l—Þ¯øþ]êCý;b„bQÅOÀ¢/Ý´¹2Ød8",Ž +sFR9)N:7¸¢jK> ݧçËx¿µ¹R6@=$ÌA7P•ááy9”ì¢7J9Ý›^„*™ÒF£Õ¼×z5zÊñ=ô¤jÄÁ>ŽÛÖwf.±ËèçhððM={Y7#ûâ!‹í<1AM“Z4á «Pÿ~/~r@ “e’~S”{¿‹Òôz6¾Žþô?Mè·‹ɶö-YüÂ3)IÕkïö|oíduªÈ¢HJëÛŽ~NMϾ‡Ôönƒª‹b..ð— œº¢1×Ãü3ÚI=ÀWné-¼V’/éªùÊ:yŒã­Œmcãtûþf’Xj8«€ˆãöóG8ù`½L¯”-r£ÁHãÄòаÅ«€cLåÁÈ-†ãrÊÌYýÌìíù&í¥ºé¶m˜µdKÛ“kÙôJë¿l/Š9=¤>JÂÆ`Œ‚šÞ}Ø[ ¼«jÌwÊX7ïäÈm¹—ëÜrtü­Ê¹”Þ¦†¤âj !,9Qnx÷Mm„Üþðx z–UmÒ¯¬Ö/h5Føh·ZKÞøtbþ­¼«ebØAÜ4ÅXïÒ5¦Ôœ&¦³õ•cá\1U¨xZ*ýÄW]ñw§á92ío™ç™Ô®ƒëH!²EêðHlWݶP¼CPpG8a¾Úk±@®`åÅYm\šÉÑ:è)C ÏêØªc»Šº/AñueÇeTHŽ2ä´ÄÊ<Ôã+eÓ¢õvžœZŸªÍRÑy[C’RQ@eί9Û”%×ôœ¸à¨Áކ)é¿aå‹dÜ=CCw¾7=0ÑwÁ 1‚ŠŠËºMÒeDt›˜!ª{¢¹ß<ÞŒd÷³´Qj¤vJNìUlýÂÃ>PÅŒ)ãD;ï±ßWÞ‘p[Eí§Èƒ^HʯÑ&º{Ý4QÛRiÒ­CÊÔÂX¼Þ2%^Ä3ÿ( PœÞ†¥mÒîñøÏúoý>¶5C­Dc'™™…mȉhÕq 96›edV¡Q…Ñ˨ƒë®Œ/›F­r,ör¯n£šÇ5ô/8ÞBW¯4½¾ÎX¨a}hn©õ°ÄÒrÔ¼aeª<<Ì|Šw— ÷G …Ô0­s»¡!Y³û¤Xbç<(Ýý| ]c5È{ôÃ`;¸áB^м:²ü/OIûøúx~:ìUb³~¢ÅûGQ“CÙ“wY2mŒËèʈõ3¢ã, 6DJ´|M¿X翖Ѓž?‡Äˆ7M°ÔULVÇô6ˆþ)åî–þ¶PýVâsÙÒ¹BÁ ò"bk¸£ç§d0ÇI£€Ä˜1°„ÙÜY ÀfÀlöns0Û17ãDiŸ¾^¹ZÍÉ’e-C‘ð½‰&÷2J+£&r;ÐwO:Íï?uŠíÞ2–)×굤•£/A»Ïc® æ=]%·ÂËð,óå±g«Œc Öµ•O‹ º|¢}ÈQ*ˆGü"Ä’ÅL2a÷u˜ÖK5ß¡ÆóÛÉÆF°. <| Ækt( “Ù°2Hß‹1eñ6M‘Mê5‚“+ëÊ­ßbpd®äOm©Ô?ʪáôRÕa$w¶÷Éä"äm3ǹ¬ÎÂaâ׿(yÖŒÍÌÑb`º"ö…w?|^£e⪶#¦ÇÿUIØs«ÃŒN©hGa•ýe üîk÷iâ:Åíl…lNÚ¤gnd¶t ÉcÜÁGe)pÌ?äxÅ +“‚Ô—¬klœä¨“@P“·”ØÊirý©Øžƒri c›Ñ—)C:6ãŸmÎÉxÅ•(L´ãØÞ Ž‹j!@›`„¢ü³u ÍZ?¤ˆ »¬} –©gµnx€Öwh¶ÝA§ÕNnU¬m˜ãîÜ·ýår3VÂ¥¥©:!ËЉ`urûi¢š&8cU_æwÝN¸·ÂFÆtÐy©æ[ä‹>' ʘxOrÒÙ•b²þ9™C!EÿÕŒG»ØeñSHŒê¢| Òdô‘¥2‹OŸ˜ UÞë‹`Š/ß{Wr²ã‹z»0A|_ÚY¡ºÐz£”%Be¯z"ƒÂx¦•tþ¶A½ÖGÓЯ` qš<©àíÔ=’üÚ_ùgoËè«•Å–_™cŒÉ#7LpBÁJg”ð‹<ý ‘éøá&Y±Ÿ ^$aü€¼õ‰š4‘‘¸Þ¶Ï 5ä­z:uÃ>½èÑÆÕ‰›"BFã#S4NOãº_#xîÿLóÀ/Š ;‹{îí¡×Y'K™ãr>ÿzÃ'¾Ü˜Ðï=GC¶®ÒH°;¦ˆU.LjçTF‘¡gr')-*¡*Ð ºü­Tïίÿ3£ÉÇ|œD€(Š(˜Ü2­¤à§ÿ:‰3A%n'}YQç—7Àdý=‰#&TŠ.Œ¼m$'m(͵z;:ž›ŒÂÿ,m³‘ãP¥GNOaBw CÚ/¨F³Se®e)FË{Ç"›Ù“5FXëS+Z *V)ñ)‘Ö‰´×1^àŒ]73ÈΉS¥%œkDgñSŒ ùSPÝ{ôŒ9‚\'þÈ¿iÇtø¹lŒI—ù½ ¬ï8úÌ&‡QýŒô9Œ¢ ¸±¿ŽneþvS£H¹øP€ÞUë9O5s‘î[j‹ŸàqCf½ç†ysÃOÈ*䑈üôòµ#þ½ÐDÍ‘F¦òå›ZŠržþ&ãôéÎØ5Nö±v{¿ãò»~•8{•?„f|â>Ñ<1LoÄçvÕ2Ú ëꬴïÂOöOÄ?ïJæ‡ó'×z)°Pà 䌲S}M+Š`2RÆvl5þE‰gê;ôì)ã-zs¯®Þ.–™MCä/|ÌÉ ÷Ó™½é`çË e‹ÄÝãÌ€”ÝjÀYw BKbêÞ´«õWšfO¤ÍC£;Á«Í*ÒÉŒ ·n¶x»I9YLþLªöfJ[®êˆJ?tË’;• …íº‡ÔÊ0w‹2ÿ¢qs“<ä%É\_·Òä¥\º;š ßÙ_ïWUÁ"DP¢ó[½ 0ývÍ™ Sk% ­ÂÅ5Ú/—íIü2ÖTö¡—ø‹î~ Éc ùÑ4íÍòõød¢7×â¬0 è7Rºlž7.DZ§–T¸9:Š=ƒ²ŠvÍi!ÞòÒ]T„Õ<@k[½éD¸7V+’Dûe^NEbé·#tB¬ì‡šJâ›þdzÆa~ïP§™»ð¾€»WÛš>æ½·ð…êOa z8ö(4fò•< Ÿ¡“Û[º¶n1æ|bŠÙt‡ñô|ƒ›DG]Âà¤8U¼¹l5¼‡H÷¤Âç"YžÎ.µ€„úÙ–50")_¤YBw6c¥4Ý`(‰™ueSc’Twúý2Ü@è ÚÚ–ÞcADí0 Þ£ÊaKF5*ïÔˆË ÿÁ ­Û’W:16 ÃÖ·!‰*i¡¥Ø;Š›véˆÌè-¦u<>ÇË`ú*j£ ½’Ñd’¤%ì«Û2 ÁV±k<Ù·&:0J:ìû!ø¹éÔ ‚Ïêxýq_¿n@Bžw™_òB‚ófWþ®«ô­Tf(§¡ï! Ÿ îêSøÂ;ÞmÁƒšñ‡ÆÉ½ku ™¿¡Œ¬»èÁ4á@TÝ¢ÄÒ«ª5H¥™uµ²âG¦ôQ}Ñ}Û˜Å\84Ì/ùÄãÌZ¼ 4µ'šìFl 9{%õ_§Ì.®¼Ð;ð`-0Ýk‰° qi¿‹L¥^a’ö\²–ÍQñr­hûZ×-/ #MOøØž”Ÿ9Á¸Z©¦ÈkÒ^œC'o•ޱʎI³¶‚¥væZ¼fÒW™Ýnî¦¹Ï ™€„UÿK³œ°ÙÖÉ«ÁÖ°Óâic¢_€ë,¾ 6ÉŒ5BBZ^l©?\ë>»½iæEõÅ0£tDèâàgªõ`ØÑU¢OÇ­•r¹×ÀEƒƒBXÒæ9“à"-‰7®Ytã%+þÁªPû)½ö÷²Ž·Yš†97hWÁ“j¾«/ôh>œÙ oÓ¿•ÊD¿Æ>´ß»gÇÆ)z ©qB rËŠßG±|žmŸÉúDÓÎguk a†(Í>0…ügfúZÀúŽ¥úÙlzj*Gî;Ç¡¢E<]×e¬fã²&­‡|d´}£îÀ¬i‚U«rƒÁϳÁußR©ª±»àIã¸~{(øì*­<¤Ü®ï%³ë`"FhâA‚ý¨Íyˆ½îKy·G~HoúÀâmæMzŒk_û"bðd2§Ò™IH`Nâ$Vt)¤Wç(iÁi‚ðÊÝ>X˜½@ÁHæü}ÖR#<¨²HD€%qaˆ’ôW\n¨iÌzf=ío[aªªl™+ܾ!`R…”øA Ρ«~k„1"“tG©ÛIÑYÉÔ$êÇæ­ž’“eÉ?¨ò,šïï8úâA°YƒÍò„ÍU¤ã«èµCž'YÔ>PXÊ¢Ý\.å¼oEGyÖjqzš-Æ+þ¼eß¿ð_bÎÁ yÊ6Ø—_wj,.׸;®%Ùnñ8?¯Êü*RSá‘óÏexþ¼œ¬2lø¦Y­áÐN R¬ŒVö¯ekÐûíð·õ¥ÄÍl_H€½^³läî,Hàug›:uË@ŠýwØÍ~MŽ]r†„|°N=‚N÷é ê=õ“w>õmSsà—§Àf`ù šóÜ’ð .%ÂäíΆOßÿ×ðÞ„ëÅ”Ã"žk ‘¥†PË#̓Ÿs€è2 ®“¸Š± ôëÄ3œàXL3svçò1²2% {tšù¡²Ÿ8îÉ!¤w3ÆžeˆËKr*G€K$%Ôå›9ÜÛN8fíéìø"1¿çŠž³I—ƒM¡æÿ€Š½aÊ ¾é eìSŠšˆqTs†Œ;uæ}óóâQcZ^# üòìÖíB ì^YF¡£_:Û³÷²^.‚&îw\I‹œÃ+Î4àj5É~{„7“M~´dÔ!2 L”¦¬-Z®ß²”ì&l“æJ^ž¨99|äe+™›óQë´£™Ý7e’ÆÒÕ»DK,¾4!FÖm6à‚ÃR¨mâ5ž)^ŒÈ„ºHݱ߈¯ßöœ‰!Ï•iç|¿ŒéˆÁ9ÿÁšÂÃfg™×ÿ ½ %·¬é1Êö…>°i­½ì¬ÛÖBG¢Æ}È9°á”¡˜BèPÈHú9®êƒÔ/AÿÉÓZÀEʉëã³¾dÌËåeîÍW! [ëaô@.uCm}›e…­†á:(*¨ðÉCõ_ÐÑüÝ úú7rß›pÖ«¾îð%S*ß¾¶J…—­Z|‹,äŸË>3UÂ~Æ;÷>ꆫ‘ÄuŠC)\G¼7ŸÂaó@oO£óiµ3eš'e ~h䮹Šì¿ëØ& ®¤)¡] é³^y1"ÁÖ€M ¼3TW͹„ɘ‰ÓeOQ˜Â>ke®ëgêðTm´£$×§´È6 ’%=È »²´1}gUÕ[úØND1g¼¨"ÏÀšY²ïçS%!f­‹/A¶ÅUk»±»d’]ɯWEÀe0TŠ!*‹½ã»´ÎD<#íg‹ø¬’›/éèY³åœ>Y×\õZšåš_y†CøtxúìyLmnÛILpÚ’IßñxþÉ”©¦¨=ÃÓpHÝjÜLL&ù oÅOƒÈ%©S"1oÆÂòW†r”‡|¥øa ͹°&|Ò·tR·®ˆÝ«+I_ÅÅ®²-›áiâ@µ¡LˆŒÙÙÄêÄaƒš¯ØÀ ä9„ß'5Àô‹N›ä-"ªCÁ.¸ú\PŽPتÐ'æ´o¬ü勿ꉛ ¨Ç‚/q¼?´«àd¬iø@eÔ©ØÇQÈo}›íp–§]Ô}H¡0\)ÏEUäAÄ4Rc<æwÚN,t(ü-MêNq`6›PRvÿ*\™í)$*ñaB [‚æv*‡^ª¬Å娸D4hçËpMüvBF@ú}Šø]^w.m~¶©Î)^Ñ¢&©)¹Ç´½}$ Æ&ˆQ-âì &–ÃÞf¾Š_yÁÎ869 í7Sï)ý½Àê‚Âö«D{<€­”»<%òõ(Dñ#y˜÷ß=@/sùøþ÷ i…›«jMr+7-ʧݶ2sKˆµÈr¯lLÖ©èá4ôv,xáyÌifXkÞ0 Ý$1Z „œ]ïéc§o Kž«k¿¹¬¢j,uà}5€¯2`UaŒoDª1ŸÖ_£Qç¦ñK.î_i>T&D¶‹r–H…@¦!]$ã󵿶æ|]{'¦{Ê€ëQH)]c×4ت®€ìJ'[úWìÔ<ü™K°$rsÿ9OóvËÄ!Ë<šòjÚÈ`ÆØÕîÛ‘ÓëòXÑ</ÜëÛt%¡‚Yï3牄úVƒŽÔDý®[ءڴRÄ=‹¸o c~¾p‚ÓS´ƒÔ;A™91¬“{ÀÞù)sÉ•àlÞ-T[Y1è±EÞ¸UüzV™÷ –?T /Zo˜éT«Y|:ÝH¦~vú¿`R V¯"±=Ñ îåc×Üʼn< fsù¶É;©Z–\÷伊O8³ÍÎf:zQÝva{xJÚ ‡×¢^.f Á>£Íïê}úbKXsÏÑH‚raš™fZ –«9†) GÄ@>rå#ÃÅCú”t®Î‘ð(Ýzžý-º%E£®”DÞò>È\q(^”àå8d•Û‹Ü{gòòÛGºF.ªi¨Ô‘)ñ¨ ‡*ëž#ä3Å$f‡¦Q‚è<Ÿm¨vIйj±^Ü/»˜bjçêi‡õx4#/ÈíMhQÄ ³ÊËyï?ÅSZ9âÿ šP)0ÃÐWÐ΄$L0-µ2ÙB]¶–ñÁà¯Û ‰[l²¯L‡7uqÊØ#ég÷ù~åºGþú0%1I>Q˜3¦ÛH\MPìÙýlATŸ5ý¶T}mœuµGßÕ<àÃ…-þ Öãà¬éæòddí(R¸P!µ#EŸg”|"'¬ ›ñ¯Çôç¥M¬=U±E¼¹Zu V0ÈÊ$1™_2Õîj"âäÀõêòÊ˱TM_Ñ}Øõ2«:t¾É^9O³ ÇŠ¸ ‚Ö^b¬Ø‘݃ôbR•”•—ÖÆH›&ª”¤?¬£fSßïÃ)o3fuTx³m0-ržšÔ2%5ø}ûW…¥ºÖ);Hÿ•êk+©2Š0*!z*Ä™%-3™H&ʆ{™oúp:¤¦¹Îšå°…U%Aqt²±”„yÒÁXkåxÄ™ëSË&õßÐÙ#j’ðbè¶ñ驚™F¯íµ0ŸÓw°É n©˜×¡€|Õ½w#£19Ç4ìøÐù+æ—Äñ¡õ»ÝeDÎù¸1þÊÇÿC}ùöKYþ¡o>óu‘Ýõ£2 ºw2©6—‹øÊay¸†èp ƒ(‹”ñùCããmîÚ*6q˜›kÄŠ =¦Ý+á9UJºÀ/˜ˆdPSë~›¢œÇ}ó~ž}¤ê?¸Cqù¶/S—ÿ(ˆ„Ãqt‡ƒb>ÉiÇ-z:'ˆsŒE%HüV7Õ^¶Ç4Èíìž.ûñeX‹•¥DбŸók]—id7)¹„ð+2z\ã!¯@ æ·’0ruúœ'±³(,вFŠ( p[…**¤Ì ³^›n6¯ÕH™ZfÔËûœÑö>étª ³4“Ê}cKŸ)ôÝdl(sÍÔÌ¢³¬ùÿ.š‡F•­gÈ£²ÇÆd·KïrÎØW0ToÍÇ(¬ôq.á We³±°ð¬i4WWËÔU÷¸®®Äú=ãš y­%~uû ·µuL¿Þïô ÷&³ÏáwšM!hè_ZïÑÙOYÚ_ÆP‹‘#òh§àÙI)¬Ä‡Ô“‰àçŒû,³5 ‰5 f|ísˆ-ôrÔ…®Ÿ†>Î1}‚$yÜ7Óz[K}Ó®ˆ»µQÁÕõ¿Æ{>)ñ©‰ð–¿\™LS‘ŒŒ/[Ý`Ýb„ÚAmîé¹A+îÐaè–áPÿí}EŸp¾ƒoËÍ‚ØíÙÌÒ¹1Ò×ôÝ,Ôy¸ÙÏ+1h^%ÊG]±øVb›îñÑo´Á“תÐK4!q}õcGVyò4¢Dy˜yM’XãÁ6é$—›íé’¹xhWA«¡¡ÐqÕ!ÏÑpïoZï—‘†›áAšî «pYàHó ++ð^Šk”BzÌЗ/k_ûNÐ^9 6"QM è„›^:óë{:³L.Þªè¥S¯.p÷j~Ž¿c¿~«žLÁnª‚޾õ¦em Ý·³¤ëPl½­N Z~(½÷…#î1½XàÅ$cñÝcžíœ°‘à”={ïÞmµ¹è©dÝ]ÄUØÅÕ£zQÇ`XÔEÖã 6Çí‘t„΋]¾7ª4éõÒ;@¡òœ§°L‡ªÑåóÇ­UúvSvB~ÃÚ¶Ä’ú¥:Zçjhc\ôø´à 5ê°âÒÕÈ÷S#g£žv—#5mMž6‡¡? T»Äê‰ËLNëUè9Zuh"Ä ÝÐBÑž‹;Á`…gÍZÅÍù¢¡À`-…lñ<:‹÷uMëÜ{БéI ðuÓ8uõª€¼×ñp]S™Š´°£?haµÖŽIõþw.µÂ5—Ú=v••퇺àŽ1¦W ô02ÛK©LH$QɯÕbÛ ÂÌYTö+X ±+Ri³Ž±Ôs šFزCzÇBU•Ÿ²ë,ä¨b–ɺ!µFl£$’¤xX”5ãwåc—™ÖjeÖŽ˜ùh|¹«uÅ$žÖœî®¥3±ªHª\’@?!ÉR8ŽUÛvž÷=•Š{ܲ‡èèɦH§åØÚŽÖ9þZ}7Îzk»Å~/…ó%0jdIñI–õsôL½v8ØM>R4ØÇò–’Ý0Û®-ܵø~áEô%¥âV½˜‰ùi%І_YÓ©¢UúNÐ)mH詪æIpD+B{ïQœnGRW‚%ñëY ò/º[Údöüˆd»t-ÒÁ4@fŽ7‰£Ž„À·ÒdI½ Ôþ v¨ R‹Ë)ëô$§xδ—Ññ@2e¹Ã>qò†Ý€æ’ºÂ…"±§~%d0Žÿ ÷¶_¼;q€÷Hšß¶zu•W¼Pœ°[dkzæ2ßâ‚Î0Çì{P ´‘-´R(h%§fçÊfñÑR,iòd{'ýâ”kR` =PSSkÒèÄõqêpZJ5P½0/ÀwXËU> :ÙXÄšF _£Žàæ¸ëtu¿¦¿Ð¸J°Àào΀ú7æ“N3(Yþ†š,i„޶ 6·!å¬{‘'I0ï‹ú÷Ò !¸±Pz ½¿½-NtεÖî•ÒŠdõ^±d-3ñ冠ôSS°üÝÁñuYDelov™·š‘ðj—™îßËÛ3„ÿ±w› WÆ£Åqo,‘öæ_7 sŽÔýOÏn/<4º[¹„„öC†ì\qìú®¾¶1B¸ãøŠÄ¿*nä bgüpÕ½ÜCtÒ°©1ÃŒõ: 2Íí[§=J,|²ÌO•þÏê >!Úx'@øŒCÕ IAb˜3† ¡NÚÒ$úÖ–…ëH,<¸âß›«¸I/RõYÿxcÉÌ,’¢1Uè †ŠÒR±IËÆ÷~7’œ¼mlöÆøXáAõ-e Ú¯œ–õ ”sËý12 ‡}ɧñ V¿z [ÚþskárÙ#&X)¦ ß®*…ëB£ÜIR@r1g<Ç`mOøœ¬¸¢ÞbXÕí4±gBdÒÄ ]„¦/ô\í|ݱG­Òu7ro–Þc‹Š Î;×J£á’z¤jb/¸ÃM Vyoýé 냣‘×kÑ5øXDœj)D.‰½ ‚sÑòÎ(?¿Ãý­¼×“Qz¤†R<[_DQ ~¼*N²±弯/ÿdàÚlºðóZÎÇ?†ná UÈç¨5åQÀ>þu;;ÑŸÖ¶pwÑ¢Ù }2D$ÃÀ–ŒUE;9¥e-G_ÌvÓ™¹²³˜þ€J=»9ìá= y•(`‚<¦,ExL*% zo˜Œ¥pFG0Ñ©¸Í _×7ÛÊ‹J¹Oïªý!þÿóî*¶Lòã=]Ào+æ¦Êá›Á#¯6Ð@0sE-ãÝø‘@õ}Š%¡ý h¿\EÊÎtLïÚ®›ü ;}+È/ÝMS!£¤m=²ÊH°<+1\+éÊ(‰w÷°”ƒj/%¡œT–nYà×ÏöŠÐœ÷µŠß •ùÕKÙI´Fy‚å‘ýw@}4;ݵ7?ÿT§iY]þ¢C·Å8¹¢u\76Ò‡¹ƒ½œmÓôÂ’_ß—á¡úÂÆð‚qS[úF–Éhª3ÕÜ××cSbž¡e&æýƒ=¢§ƒÅæ<Û®¿·š8CA£gûËZÚía‚ ó6î/½ö×ô¿¿¸ÛuœÈ±Êú›ŠÜ„Â~axôð»ýA[Ü5A‡»ìåïÕ#çxrÝ…¡åz6”Z¡V|OÜ\à MWtS¬ü6cœøyÉ âÅ GöD Ç4=ú/ʤM{F%ƒp­ˆ(òÊ{ûK†NÒìòoº>yG‹U»ª–˜Æìׄ–%8·ë¦—„}ê›Þ#MáÿAAüö+ñ…©<×ÕÀBPì佃¢™°‚ȱîƒóaº‹KiŠ÷jÏÊŒ,w;vy V6I¢0~gõžyi‡A³F *Õ_†i7‰r8¬WH¸EÛ/^šƒ@_<°3“èË+@úH£w|µ°ýÐÛ:2g%k——ÝP/Kõ¸K…rÄÁääcló‰BJ×ÒŠ«"sI,=¥>ï\±)Êil x°‡‹êpEó¹9ÚØ6M æêÌT1î™òÙUÊ|R”@r¢·úuNé†h'*ÔnKœ óX†ZŒabû»Q\áÜ’?ÁZ/˜UÍ“Ñ|ìo´cÓgí×q“ÎÏá>vµ£&¤Ë[[a3Ú!F1¨½1ÆõïãÆöõÚ‘Ž¨À .gm@Ín;Mkì×8NŸ¸€Œll à.½·r9‘Œ§öß4?Iã ÿÕjª”¿[­å!µÿç›ì±ãkM± gq»ÇR>N·{ Ã7Ï7'†ë_àÃÉf?ZÓC 1uêQ9ºóéÅtLÉç>MÜÝ:0G4ÿ,£oÞC‘;ž›$]Jª6K1ÞIõÅSU˜ &sÎΧrÈÞv,¹ØÇd¹èýœ¨%¶Å–*O|6!W¿}ôN"b²ÙGä¤úKv¿:Ò‚…»JªcÖ» û£+½N÷66ˆ0 Õ­†ãd©¼ý´BŸçû‡ ïBw>(ÑÕ™ÙDÂY¦uï8=9²Ý¾ŒÜ§$Õ¹¨îy—äÇœ”9}Q³a©kÌ¥ª"%;x¥VV$•´µ£Ó»[‘Y¬¶ÃmÒ¡Ê •eký Ì^/ýŒ7÷pàM k“ ›)Ù– .šàz‹ºQ?$+Ž–RØ‚:éXvüÑB±P%ø1u¤':ëN”Ô° NšŠPYrnLø¦Ÿß(á* &•’Ï‚Ã?F2‡0ú4PGrà[Yœ³gKE‘ã,r‚q€úèÿ½}džu:xÉ͆âVRúö.‰—ö½ˆ7º˜÷F¶þ=dÌì…Ú0 ʰ޼GMH¬üYnøvþq‰£ó×VÞµVTÃþ‚VqV?}ϨÌMFÓмk«ËO´¨¿Döz$]rÔ}òó½üÂ8pv¨”&kÌ¥†¦yƒåZÌ8 Î-¼ ¡ (}–íƒÅÀïªxfuÆ2 Åü”ú2¾*H’|¯!«“å®ï¥ý/ä 0Þðíü‡°öd'a{u¬r`ÄÀ†È ùv¬XáÓœ‡ì¥s8cНíhàWÙæá¦í;þÎ9’œµº¦ÿÕb`— ?!uo)&…bTC¼ ;ùð<ãó×YäϾ?Ì°Èæ£=Ua9»‡ÆBFô¤E—jSaã`m_bî*3…©exro¢+D"qwê’ì'!»­o1gHnÒ%ÁJGÎNºð›'=ÛxÒT]vë\Y“H7ô{%SH ò9Jô3€°{é7÷€ÀÖ:½– `‘q©) -±Ü½R®ûœU>ÂýFnfá>ž?Í7šn#ÝäÜãEþmO;i)žÐ§¥ÕróR˜^‡ŒÌ§åsa_0º¯Ø˜/Ó qv4×þË/hËôwMz€ V ‘#ƒ ­°¾4S§žZÇiÅŽƒ€ÌÊ–ÛŽ<¡4ý’xä¢{“qxÊ·ý¿ßùK2ÎN‹IN…¥‘GÌ‹pzí5Ú$IÈkÜŒL«Ã8Òà„g~18`ý©=¿îÇïÞ` ‚jL׿¶¹äQw¸Q’å‰yÐÂ'AÞžÏ P˜jaÚPÓ&t–NhfK˦Y‡” ‡ –=¥ç&“³hR˜+n;ñ‚>ê¬ÿdjå½Z<8ðñ«Ûpln¯)qÿýºå?ט‘å*ú·K¿ÇË̦KÌY¹“úYÃþTmºƒ$Ä2„ìRdK²b¼Ðþc}²•&OÔžñ“ˆ:ÌQ7½ÇÔùx_ë™åãJ-¤ÓÌ!öÅ>>9¾Ù¸ÅíRNÜLÀqV^dÉY7—> ·>® #ž XfþL Øf¶€CƆڦN_[Z4Ó´ ‹„çÎÐ7ÝbZáÕ)Í‹‹HÝbÔªK«ÙLš×|âØ¶{'C€ÛZ¤Ä Az±­öŠî„ß廚œ‚AèÇùùº-md ƒ(­[‚âÞy`ææ(7ÉBë]*ÎC ýÛË_°Ó¡h—„p—oœeþμBR¢Ä¦5 Ü¥ Ÿ‚–“£¯#$€½Æ&,'B¨ :øô>Ñ!¼ŒTÓ‹'Ë!ßhaº0£3Ö°`j‹ªŒ뫲¯ ±]øŠ6¼à4A¡\·¢Ç:p°äx¨j—#âW—œ» î!•~ôµ—“uþÔµWàiCš`ê¶"ÀsÜ’ËuYPoØË `á„ÆŠ’q~(Ó“•ÓwpÁö°„x1lO%[Ъ;+òÜCL^"L—&æl†O`ÓÊ:Y©1„fë•“RD†7¯<í:"™eVB8>søAæÉ³¶ÐTõ$tj:H¡#~ÅZfO°pQÄßø†§¥—˜€Pï|¼xÀcª£1<èæ–î7Üf‚Om@2…,Té%!àØ¸©ñ†Öß..ÄaÖààOL—¹P5¤7ÛåǽõÔÊíúš9‹ ¯ Û“Å Ñwôät ¨ƒ’œeôø”JäQ)ç퀈 ¨w>™ ¼U 7J_*Ðß?áwysMhç«á±ÕK®½Dî@MvÑ™/X¥¯/f!QÛs—ËÙêã¨`šèaá (”þM1…Ð5/µÝ:‚¬=KúÓß·fÁˆýEÈæ7Œ`Á8ÑMÔü{P…±4$Uð24kE$™jHÔY©ÐUoÄC†™®§lä´ôÅ­ônl^à,>ÓêlãõçÐJ$ηÄýôì˜ñÜaü"8×EêG× çøí3]Ʋþ:’þó_š^1Ë ¨q×xò öÁŽ¡˜Kš=ÙOáaÐg1úÕ[¦OÍÞÚ•®i";Qñv¬áRËqt†i(a³ N§µm<Øio'-;­ðmaÒ’åÛÄŠÉ…ts?w9inþj×ÛH~k—cVï6'Ë|‡©~²£¹Ûn)&ÔpÝ‹ïôìR^òè¦ØÇöŸ£šS¥œAuOÄZdÎñŸæ/ŸEÐQ##ïTKVõQpZEÒ9EÌ¢ü¼e[ p‹±ñ8ØÐ±á;5¯25¶r¨:Å„§ß”Ulϯ:Œë®i[«óýNû¸ã-ÚŽ ßB¥õEÂ)øÔxy’3æ '² c‚ØQæ¸Üâ ðiŽ1-ÑÓEë,ÚŽsvÙ1iî.ò]Ä$=G‘Ã`›GeI°Z©]!‡5FNC‡Å­C¦µ éÚn1œ9ÒP7 ±«MŽŒà×êi\s{ ¡Æf왳е·c` Ûå.·¬Ê:âøw·Y´09Ú_Ù-1¨ÊÄ —³q_ðøyúVÛŠ`ñ™kœ°-‘Ã:XÌ¥Üߵ؜¨¥‡…‚Î:”`O*;îØš# ƼAG,Îr:@d­„É"AÕSáq/½Ý¤Pt$ñ<\œ×êT×Ôû°ÛÇ¢7vÔ4¹@Îôlj‚ºá ¨µÿμ¼Hc…+µNtÅ à) `o&(BTýL[Ù‹‰Æâ§-Ë`/xæÇ|ö!Ÿ*?Œ± ŽY¨«~’9v4þà¹h{Ëþ$i£mÚ0+ä®g%Þ®–—Ðé¿MRWö0-­p${9È“Üj,öé”XiëÊœ>¹G6ù Ð÷+ 5%ÕVÂJåû®O]7¼½-y¶pͰ\ªî5ufy¶G}5؈ž Ûf DH³5¬£[2]nøgY”?l_˜½9a›2‰áÀ„ˆ¹üõð2*Y7¨K7ˆÑ Åßê‚Ųú»hŒ“¼Ûþ/êÊ€DÄ ¨§Jòç* »¬³›B Í[y'¾dî˜̨×ûÛ>ÚgÈ=²$›_ìd+¨ÔØF¶bÌ³Š ßL?úïR§á c ~ø‚WR›á&ÓÅË©Šó×| “n‘´‚zûíã—ÃyyAmî aRÛëÇ)t¶hôÀ™GÙž¶Þ8æâMXŸLÓ+XaîV€lýŽ9MÎ×'&5-Òy¡ZCò8qU4†„×N®DÃ9Vœ$ý­ŽN¶ì®_ˆ’W'|êÞÏÅÏ·ŠVwÍxƒNX#Y +=ÌüOtsí¥G¶W¡dRÄλŦ¶7LjpåêÚ¨åÈŒ?ëðŸþ r^¡¾×rmÞrÄ£…pÜKÏ·f]0ä>”âŒð%$•Œ>o<ÒÌÞ‡»¦s;µÏ2ùÃÅ«32ÿ­Œ·¥ä(‡Cb”ö*ªÄâãx³WjJ:ôên¦;TÌNH_rß0#Dè¬iqnJpOO“Rl¦1Ìâ•BŽÐÌr`‹C¤†©F×m‚=höÎ.W•ëó<•Šâp¡¸êÐØG^uœs§–͹›~²¦ØÊ‚: ?!f–µ»ÐÒÂú7uI¿ + ôVÃLäp³ÂQpÍŠ³ÕÍF$w™øË|S”­ÂÀt–à(dn{HE í…Íç+z&ЊCRlhB NSK÷û.S<ôÂDooNðý $ô[Dü˜´Ž/¡â5Ÿ°­¨õ}b…ª9]KŸ¥kÑÇð=px£ðçÖòDmÏ "çéí/ïqv6õeG©-=^Uؘ³š˜¾_ÃÀD$8œ­ÛnK$4‘'Ÿ)iÍOÛ«"Ɔü yM-šnPËõmG¼ËDæÚë9]΢IÂ94w”c±aax±B{í]Ë«kçNGC²Óqu’–›þ\Üo.ð~™;;ÚÐx2›S¹ j65ßp–ÿw`žŸÖCAN"Ð;žlçíNŠò¡{9MÈõê 3î„ ùªº¶²ˆæoAu&ÓxÞ?B+Z;õÈ{V Ú ëB²üÒSЙйèÕ¨Ja;’ÿuª¯º…LR@aŒÓX޶f èsŠÇò‚HDð¥°AOTÃbêùEôÑÇ¥tœz;Ú_äÅ©-ÄÑôb)ZÑÒä1I~¾n^ƒGõ|­¼ÿťʹH„ÞKCL Žã%‰ÕÂ6¸ŒˆÅwófg~Hýz.2ìÆ|þ ¶ú“ð)‹ç炈P©ë\×cÉffwé4÷ÔX Ö„Ëx®ÌÎQA†Š%\w±þ]†™©ñÈéÑõu²rXÀ3ÅzK5Gz& !3e®/,´BøÏåT¶.b/ %›CE6Dq?•õ«±).½yøëû ÒGæê´ OZâ4/Ì? ûD¤ŸËn0=»Ø¥(çhÝãnp|-´2,U‰c­½+#¦þÂ'¤ýážþ8ñ.\M2>Me4•Àe1º³À/îGÞ UÑ{-" yœ.™UÀ¨fø :qÉÿñ[œ RÜ„¨ý“n³Nù,©œÐ× ££†méó·g±ta¯ƒYµaôÔß¶´0T"èRÂH«ªsÌMl x*ÂLä[où2 ìyÐ_æ¬ñ‹ô‚Ø5`ËÝ#vŠþ˜:Áë5ñðûbÆk6Àtù¦„•š ÕSUîz©“t‘ UôÉ_€Ã®väÉŪ±[ÈÊ—h¸ÑÒôæ¬ËDçå^Hžh£GÖô8³}ÓÆ¡3™Ìòö“ìÿx [ ÿì…Ͷ>–¨úåãG W©DK,dè,púˆoßNŸ «ü;IÁß_C ŽœÊ.sÉyÝRüøUP#¼á¦ OÌIRm?Á(•[çôqE ÷¸B59êÈ–…MÒöÍz„L—¨Ø}FI¶'sLVX`üÚ›y`ھăæµtI¤™ƒ5óÇÿûG»½—Tºa»ò®{ˆÙ€FT;àúÆÿ{™Ä-\©*xQ”ÜqÜJ7)ïehâãÔ´ê•lF\ž~Ê×9Ï688WbË ‚¶4P~T®}<#Ð|‹È Æ5 ±fÈUçRu€Ñ°šWóñá1Wòhª.ä©2Pl:±ÉÊc©$êJÉá¹ßø”'ž‡¤¬? eÜŽƒf£ã¦>z7…¶1ˆ<*L„_9-+$Nßéä‘“NK„sÄ`Nu˜;»Y)í&Á+ NDÌ&PØ‚Š ƒ$¿ìAåÔO[èѬMõ/ÀÔXnw]sÛvÎEjî+¡Ø’N'S~ë;f«Ö_O[Ì7uåŠNÔ§FýÄcpùZá{’ÆžÌÑ5:=rŒ‡™ÁQÛn1Óu?±ðyážµrYpà_®« jgË8i£“þÅt  µ–¾ÔRÞ;±dɵ2KPûLNš#JÐïëi=æyK.Ñ>_ìªÀ=ÎÝjÙi°Œ"Lš³®îˆLÔÉ÷šFD[OÏs "¤¤œpcdÞ²¦î 0WqÕZëéå·°uýKŸ >¡”Š0ÛrÐBÅ|syqÑöˆáÔ›•ß9о-àj†$ƒ¶ŸšcäÄØš^'Ö+…€ò vÒåfð…Ô$û^ª©¿½ û²Ry>»ª)äW ¿÷ÕÅ;œXRo„,`Û|Moì¯U„Fùê[¼o¦¹G¼yð µ%?‰'/z?“¾”9r‹U—è¼—êÌn½{ >W>S³Çnxº«?µ$a§Fâ6ó·²µA÷~ª 䄜©Ýw.­Ú¿¬ÏCe£¨ÆlŠÛZÃ\Gš™ˆ–ÇfËÀÜe,…1GÛ?{ÖŠˆÁÖ™s@êb±Ó] lÒýo® –{Q“\Pqér/ÔÂÇÈ‘®K§=Um=còÑ©¦Î¾lHDv&’¥F#Ù0|w}º[ ! × Ó—¥†ýž89 RHk”»Å?A”‰Id§ã\^ÛV…![âw§(’èFvWH´^7#ˆÛФW_¬vn2äyÚ¤·nàbÓÒ2‹`ìÛ¨„²kž²'bS) C?',¦uªý%±…TÆ‹Ÿ¨dçLÈ=?þÀÂèÓò.Ì¢«8éÊŽ5šþe³ü{no)P?õèë#rF¼+Úgpw~t÷‚M\,¬eÕÚâ$鎢Ñ8Ià‘·ÞÝ"®P‹Â]wtšz†ú´ø^3Mª›DîoÑ.ãÏçLÙBNx@òTüˆ-3¢&Vôv|e»¬ÙÁ>Sùƒó‹cÕÆö›ô„/$Fvܲ"d v¾[GD…Š’N¿Ip£ÓÈ3ÞHéò^Wi¨ÿ$#ªî “+öú¹Ó!ö;ëR°‘×Ûl©p‹jÛ¸²‚Qzën‰šÒÒãfìã“íþ<}8ßá:I ˆ9w,îÞ X©Gå¼Ô¡•§áÓ/C½é©VäúYR`FÈ/4¢DN´ÐÛ‘ƒNq¯ O†çO±z€GÇöp6Ï_g&mŠùé^#-/Q$‚öXàŸjÔãeÍôMhÔ ÁHèAé+€î\Ô[h7懸'æ³+‰ÚRIQ'Ž;ȺÂ<3Ð ™0•ERf\ÔFæ¦ôZ!æÜ™K»•£D¸7p.äPÛ¿0o2•3»r-V…®àDûÝtfå%%ÊýDâFEϨU£{¬¯Y!8óí¾‘²†Ý ná2s×oë¸.'>úAÖ}Η£ðSo¿¿ý"™gZË!å¬ù½C”*Å XÖÿVoB>b[¯?OTpÊ"\Ö­ 8X¶†»_[4ïþã­¼7¡X‡³)ÔÈbµr‰·õá-Ó¹(í#±;qH5Àhä¯\»f“žÚгYž.S"Þ/t30É&>8JâøLI×MwpUd‰ÎæÚ{²‚ÎŽ':ïÀ/÷ 0ç1•Cæfo¿˜‘-˜‰¿ ŽÓí×H´ÙDðÎ[ošÔ—•IüÄbgÔz'Á%T”Ô›}ÏMŽl ®çíf5*6ãׄi2O휠pã®y=ØŽV5=ü5³“ïdêòB2¿G™Äê…‰«tÓ…RéÃ赇¨ŠcV[°±xϾ_óÂjÐ_.$®QQlœÿ0ØtXE÷\µš0³¹Sq¯^xÒ:F­"œ·^%M‹ZsË"bKÄ,D(€‰ÈÛñ£ç( p©¡Ú™Ý|Ðñ°ªïvâK!Ã,°8Ÿ^‹ñºÂ+z2³Y°1w×IXå°Â]ÌT¾)Ÿ¿ÂªˆÜQb%íYx¤Kÿ©å`•f˜Q$?6e˜¢M܈ź £ƒúÙ7"–”C üš’y“—n>2’¦[¦ªì«gÜ[t¨ð‘bs¡§éf4(&]üf€Q}Ä%z{°óŽ×¬!”žv¬Ð“±rB7=’B(qmE‘ÚäªØÝ]Ý­BMQÈ1t{ˆÏB´5Áhr±í=e„¼æCË'M§uÆÜ)½9e®Æh¯ d¦”“—'vco[M §l SÕ"ÄzÛ©Ï1œB5a¢+"cGôùiñÃc ©w’d¸$û´ÿÇå÷îlÀãŽJ·ñ™Ã€6$ptô7üEJIœ7}%¾¸Àíì‰ï¶ …2e­%9ÍØçéNF÷½ù7[ÕßNÂçìÛøI2YùIŽ÷î*Âyu¿¥øP„«i¬Çâú®K@€oNSY9&â';lky,÷}|0†1..b[¡ªŸÙ>Ý>u¤P-¼9û/ê6®ï„ÇYËã‡.rX)á+ÉD¯y1«Þí#I_frZ;(QÉäÕcEÐ2:|Z?¸‰Ù'?@ß«õ`¡èÑS}<–)†ßvÕJhfpBD#uÆ&aÖÃβõh§oQ“ºäÿ{}@G¼„-§™gDHj¦‡$—ìØ‡ ¹‹ô—{‰5¨j®œ_“,Üo÷S²Ýk"î °ÕhŽFe À r8– ÃixƸµIk“ð*Y ©ý«Y ‡G¸•—¤X’,’ËÛcI o‡˜7ý×ïÅeæ¼"¬¶tã¿«÷8P–»ÒL@_¨gïݸ¢í'-ò†¢)¦asÊa¾<‰uÌäèozJ¤–É@Û Ò*íNtÛ³Ä`“M¦‰M>ãÙÒ+É`±X3ð™Æ$öµ¸{ðÿV{ÎëËF¨ˆ¼Ùõš{—3oÃ$¬¿Í?^Võ$1 )áSíî…óL{§9Hc{W…2Ý PSdH…„ ôLÝϵҬ­cl…xµ$ßYóÐd-%W“dÿPòçJã{ [Ê «FƒÔ:Ú™­ƒ(f œ(ö¦×F5²U*O3üHâÄ^‘j­€ØF F´ÕÕßšo6¹|µí$çJ^ÔqÄÄ‹5a[•ד:ʰš ,}¦–ËiH ²‘K^",>'ý;>ÖjÞ…?‰=Š“Õ+s³´ ÙëÅw)J¿(ñØKЛýb e7ËD”ðg‹†RÊËõU†ýÍLµà#׉Ð`û^€ˆ=}Öà ra%ü®¬½7—‰ ÓYèSý!+¢±™2·ÔËŠ¹v˜²Â඙ܶȒLùÒѾ„µåÇ8©U…äsNÎzÇ %®éóC)$RImmÊ"j“‰qBplpW×µ¾¤üÇen$|2QRΟCŠê}6cóçnêz ž×š¡…#‘B®Î5zÊîë 3¤N`áô¬@ݲõ·‰§Ñڡ̬Òe±Í/Íú äÀ„ˆ•³äôÜÁ(˜y*Ü] ­‹/I•‚ŒPÖeΦמ‰´I"Ég>Ï¢M«¼¢îM[»SR°»ãøûxc«'^œäåã6³•{eæ CQñ²>X~š­*bæÍ„»´GC—âX¤h@'KBØ8Î`ãiS¨„\=ù2ykÛ ~ Zþvú/YA¨™dÖ õòRî ¸è{1®ØÂr?²J[m5ÒÛádeZS_„ƒZRy‘ŸuÇÔvû±¨N[B‰|ˆª‰_Úx¿C ­¾‚UÏ™}3pcÑ\Ͷ *™íý¥^SÿGr"y§WMVö }d޶³Ki?T„7òÊY3kôô­¯Fg  DÀ Hæ£/¡ !0~âAcÃA&LE× jz£§Äö‡n§¡$Å™Ë5†â0ê­sÑß%ªX!ÍRꉫÍ1tlÈÉ;/¢Ãˆ“ö›ŠÞ6Ž 8Ká”øùÚÀEÌPlñÈ­,·Sž u}žò¾«.ÙÙ®b¨Ä)„j‹ºZ~ ¶ª_¤ža'dz ±ž+nœô»SÉrd‡ü’O{»Gu’g˜ÇOçYÏÐfV >C£o±QÂ;Q™óM—沫 L^^þòóÓZÒ¿"Ö¢CÂyod²fN4¼&_D¹µRìèÀÒ¦ór;ãÛ>`Ã/MW¢œ`Yi™ù˜ƒÊ@Ùp º)V‚.ó‚+XjsHâUläç¡©sÓ°`m Ȫ8=VåúA\쨨½k3¬ŽÒCH'"/N ¼šcHPˆ$s´óô8%Å âUs î~®¯?Ø2Øÿ¹Δb1Åcî+l@±/u‹4= !É¥ÉxûÕåÌ:€æÍ3¿Þ&Ždâ_í¹Li³“/(ÆåÕÕ\XwƒsaÞ…=ÅÉób…!ºÕ·sa}¼r„v¤>€ÄªU—Vu¼?Šï³¯+«í`D(m½5îDV ¥!wáåTTˆå¯‚bËCH‹ÝîUî8Yc¿èÒyƒD[RXŒ¿§xW¸ÿ]]Ä—aÿF0è²dD Ýíþ}×qarlQ-…ÎⲎ‹Ì`Y{ ®è¨-Õ¤À´ÊÛ˜uƒLVëâk²‹ôî 1k”é½U>´Éh%ç0iz0S¾gI#~xÔàM¨SŽèQÐÜ› kõŸsøÚNb½k Œ•LR™aã}™Ê-1„ ‡¼ —6æ×Øáç%ÚóÏK_0çíŒ=îò:ØÏùr¼—«Æ±å ;í:ïr7ûPך[ŽÙ wc˜CGÔB°ôÈ@jìš“6UO1åwAW6º§ó„©·ýyŒÞ¹«Á¼X®ú€ÝaX¬$Õ¬ü«ÑëRøTÆ¿Ô!ƒjT^¨•Ÿb’Ys“LÂ{ŸBµmã‡Ú› %+(Ä8'ù—vÿ$1;«†ÖiÇÛ ÒåXŽìчxC¹êÎ~í@1ŽM(!¹‚yÞ5\7CAü¾õÕÎÉõ”Â/°ÚqT  å°VKïžÄ~Ì´ÌƦ?b øMR¶R„Òùýl»\èËЋ…;? ™ôæZ¾yFsA’Óh|ù'îlynˆ5¢<Û+m2­*ñù”\á)+W½‰’òNêã ¤,ÇDróÛ!ýe†„>î ’jƒ¡è9 Éà˜åÎfmõqÜ'Ò.„0™[†€bûn=Z`ãå|ä¿ æ¶‚ Âhi”Z¦›(\m†²VäÉ%}…É€?6µ¿¶s,†ŸRu{çR·Q¦…¨ˇÞÚ <˜~0â$dwÖùX –Ù‚b¶,˜wÀ… ØqkC}5›/„”îÁ€Ì8×U?›/r‡ZHÓ“#"ÛɳMJwÏD…víM_Jg۾ϻÑ"Ç·.«éö¾£àPjÖtßÐÌ‘@”Šn±v¡ÐŠnrƒÏŽûXnÓ}ñª›‚ôTspßWMN÷AMHæ[¹›µ²[{m3œ<¿ÞLP?gˬ1ýÜÀ"0=åT‚†¢E¤2ôè¼”²¾ÚÓü|êêÝꤴ¤ `Ÿ)óçÞôF„ì¯-Eå5ZbR‘>èK¾(‚¸; ¾M¶¥N¾gK. S^Šœ¯E]A:¡’iÀ€UD¿\¡ú˜/3È÷Õ@o‰YRá¨Ñ^è v-ˆV‹}È#BlÙîŽùÏî~¤Z‘NŠ‘¤K‚ER;(¸!àPm=¹c {½EÍû‹ÂõžÅAOŽ7ŒO€ ñÓ¦#1‹9;ªÀ1÷aÃ[ÓÏ®èßJþ²Q9_;ù·05êaJÅÍ×|©æ\P}3 ×ô a£}I² _Ö¾=r¹þ'èz©žàùß<Ò{ˆ->ã6€üØTíã‚@APëãÓ“ü¾kIü#ävM½o8{¥„Ÿl·B+–´A¶DúÕ;áì+W±£æÿª›ô®Ú¡Ž©m{Çž–[úW™šñ¶Ëþ¥îÁ,¿¨ÃЕI60ÀË ¬…jD-„/)±G5hËÁÛá;ÜŠ¿Ù¥†2Kli–än•ÄÒW KÚ ÂšÈNJhˆt%Û#FpÍóÔ„‰w\IË1”ÛŸÞœP~ÈE-LÀ<Êß5™xv™@Áèræ¾IÇÖcËÚ^[Ãd SMº@„AÕ'ĺAK>­Ç¡” …ø)žil+} nuÚ îj¯åmi•ü7êïBÀ%<Æ ³€ âQ´¯ä¾Y 3Ân/ŒCê'$ù×gyA‘sPÖ³-u¾¶šu† oL{Mugû­<µ·Üœn"*dvHî«Ñ+ö”ù¢´À„Ì#%Ès¬xU=Ž3ùaÙ^‹D†uÜ£{*ÓžÓuQk*­R‚ƒ~̳ØÈM{ÐÆ¿-SÚn#ç`´_(mÕ“½§Q½W©t`ñÞ÷gž°#— [êHsÒê÷ì;n´ 8ï3†i„ÈÞ_—ÛGîM”öpÚÉÛ lƒŽmNÞ<)T"ÑÀ;À‰„„}Ìfe’½Hse·Ä»äÉîCGiêQèƒn+CA†…¡X(Êr@íEôò¢h-ÇŽ¡5ß­À#æàÒÉQa7¤¾XMYjp(¦àÌ@TówV¿Q“øZñqŠ´î~zx¢»Zd«È2o ^>ì5¯Œ¢t磒57öš‰ÉÌ)À`·>/j5Í:|U¢T=ÈàË~ͽg É‚Ót•BÚá74þã¦êvmÑH¢Ò–<­ë^Œuöh}lùsÖvÏZvë¢× iœ$ÑìV‘¦V!ãœ1„±Ã–ªË·qT³¯|ÉœHxÖÝZœNLæCvµ&áî‰dòUYŒZ-Ƀ˦F=Ö˜Mƒú±zÏ~‰ „f\+I•&¸*K-À̼ŠAø…ª|ÍìhÀü𼸿IÿSn—šóñ]ôK _€,¥§…3Rtx$-\Fš¶#Ÿs]p'°b¤h…íºî„9PÔ‘@U@ÕGZÓUÙ™Ì<æõÞ2ÅìnÚ´7•ë‘´Á@ÍOœ“#K´lå«–÷‹ü£ÚÉêÔ<¯ƒŽÄM¡ôf‰}Tõ]íÞè:¼µ¥“u¼;Xï¥ÃÿÜxªç½¦¡žaÓ»¹š)Ð ¿yæ”þû÷ãZލÞ8¹ŒÍÛÜx#çÃÙ;W@¿Æí”ËÅF\‡x/Ë»º‚mšhÆv…qjÖd>…HMeÛþE$ÈXçùþ”]ÄðYä[ÌyNb~Bll¹ãÒ­‡Ð`²Ùbç,¦„0Žv¢‹îø‘Ÿ}ÀD ã„!¡n©d_yÃäx Õ¿ø MžäÞºyEúBý›ž×ŽŽ1B`„nÖ:¯çI\-\Ä„OùªÃSU4F"#ËFŽgq…ÙzB×|€5éCf,wšàØŸÀ‚ÕuíW¤þÒBeö]…˜=GR–ÞF+?}‘wAÀô\wÓ¸Âf¢}¿d"¶„öxÔûd¶šIN®—¦þr£s¦©lƒ×:ý>e€5y 3š `åÏ=AäïáüóªâÙÈÙÅ:•ñ;b  !ÃhdÓì’:jˆÊy>·å¯O­Kj‘¢ç>ᡆW<1lHLÓå®*ÃvB–UÔƒqÛ~] ©/KÌaK\¶¿SiÊŠ[3Ð’ÁާV9:Øš²ê zeQÚ[2_ŸØŠüQ‡ßGvŒZˆ^)ͤIâý.æQ«ˆwÞS'òvõÊn>Oý%xӶʘëÑ]‚N¢ }ÖcPóyq©¯Ø+–íó+·7!õHbc·t]'¬K8õÏigxðâ+ŒkSß°þ‡¤¹…GÞP–lB‚þöx Þrž[ËýÁJDÝ“GM«zç7Ú‰\;IDlV·ßzÔ;.-tn@¦) “´2·{¶E‡¾ò'%©Mãû¡RÂYïÜU ‰Ÿª)K×íãr»“).k6ߺ{iÃå ?úÏ<èCoRØLM=’¯CœTôs6üñ‰ ·2CÜõ {Š=íû%‹xGkwüášð²€ÿ/kCƒ§È HöxbPÐHGN¬Jüÿ$ DZÍ<åƒÝÆŸ+r”‰P÷è7ì˜*3 Ïͨô‘^T]Ô¼ÉÄ~©öMÇ óé„öЇÀî?k°+œ9ÀÇYŸ­(ÐÌoÜ#té…y}v+SÌ'çctrX(ócåo¤a ¯[ÈŠ[àÏN]Æ ¾7„œ ©é& Y r2p¦·××ÿ°.ö#R5Á&ü_†">Ä¿0«}w€Ô¼ “”ýÒ+•h±}ô³#BÖøßâ×S$KÝâΈÌyÙqx ©ÌUß´™„« Pf9B§‘¹p[[v›#Aƒ%øù®ñ°f # ÅÇê?•æÝ~]EͰƦ!QÒÈ•7G‚_Âã9˜’§LÞÛ¾чBãþë:ÎàèpN6áöU]ÅŠô}TQáQöl¸Xc¾ø¿ÍõÒzŠ[à@ w±LȘWÂuDL¦Áy.Áe”ïb)ËêÄ9МÇÜ<å˜Åü(è$ÙóäO11uM‚)r““ §Äi•Ý­W qÂYÜ]S•)%(:h Ç ŽóuÆ–è~Ô¤2wu{Žž/Z¯Ía’ÜO{Í[Ã!wíîtÐ}y`ãöŒs5–í¶Ëý”$²·0 0A´£Bo£yøÏ xÎÜÔ·g†"•ÔÎ.) 4ÂÌ¥ÁXæÃ#Pÿw· ö§Ñ’•áëø:^, Ø2˜ñiªA3>ÁñC ݯÎS¿ÎêJ -¸P‘Ð<®*¡fW aabuÃk;OÎ+ä%­$@óû̶f¨Åôà¹Á,l»¯¤ÊV§ü‚þ´À~F¦VƲŇÏÓýëñJgº¹4^Ô8”ê–>Æ•ýlGòð¹Œo„Ô)¬2NÓîõ~‘Žc~Ä„?‡6µwR` vÍ~^åÏSÿð‰³ªx@à€Ç£÷Þˆù‡w­Þsݪ5Ÿa.Õ„©”t©T™iëò¯nH…Ú–?Í<Ç©V wJ´Ÿ_v roø—¥ÃÆ‘\™®0|x\’ ð 8žw[2ý>—[µ-x²‹|„8g‡îÏ1mó"²YþÒäØl‹*#ÌÖþµêâ†iÔÀ ú½MŠ'í˜lž#9¶±·lʶ„ ÿ–U*2˜|¬$¨-[e0T´žÆ =Iwä¯IèÜÒfšF0Ènü5s6bmÁü×¼„/gH$Ìö\ЛªÐ«µÖººjC ÿ2¡ÔÎÛÀ í(7*+(íÐÂäf¿&xÕZTeE$]e¼¿´KCª›Ysv4Ë@âœÍ<þ‰"þÞ¡Õq¾Ú: 7~ÐeMbýÿ{ž!xèÆÇsJ˜š§ž eaé˜,Ó—°MˆòÚI†AC´§Š6†¿g¶)%eJ±ù`g9ý¿sìo’–ð*¡_Ùs]$§| µ67»[˜ƒ hЫN±¥6j*èçO®“‰§mVÂîˆÆ)sœô›üâ?h)oü&—] Vååø)Íð¨c/³›±€œ¸ºuÑDæÄR±úhn;î[‰pAˆ©4þMõ*ÌXaÉÊðlî|ÀíŠaú§[WguëÏãì\\˜üAÿh—)C)w¼äº£–eϲ$.Ôu™ÿ Øãzôò&ɧ=X,úŽÐ7e þ7ÿq7¬¯Æ[ÊXV´ßÑ´-q]^d\lÛxw€V›¢ WB+##œr–÷0ަ™ñ¡óM×)ë>(,ݱ…†bÈÝŸÎFÙ›í¢ßúmq'Ðà{·`jVÛšp¢¾\Øk¯BÞW1ophU.2?àl$Iû#Å¥8 ÓJO-û€’Íh*†n]úå?W8S7­I!1ÞH" …°…¯>ÞÚfÛT4XGQ'›ôûŽB©k©œ£p¾[!­kå:b“ K\G×é¡D_«Zñ/ý«ç`ï­’€Ó’p2ûu‚ÕNÊ'N¢º:Ï]F¸ù¨:+«ä2\h’Ê¡6»Ï©ÞÍLªLþ>Ô=Õ#ô4hDì… P ¶KRÞMë}ª]÷&n¿Îqx ÌR¹P&cU+›ÛÁ7†N¦lCõºàÊĘÜ(®Éð²Îäp|Í…kÆb˜³·[æ.« ®â Šƒå%´F´P{eE†€„! >(·Î)¾å÷°pçN; ÅyoÿF‡øÏ6Gù€ª ?:@8"<•ÝÑxT7ýZ â:Ì‚[¦1‚ó¾\5ÔXG“b#Ç?Ÿ?1èÖKÈk¨)ø)†ªNž*¨>¶¡­4š`“%ó6Þþ7 È`ÏHèÞ+Ë2L!ÆÊ^¼@É|²(URŸYÅù›Qlë˜âC ☂Và âWÞl.Zï‹Ęs™Æ]Â'7ŽãiŒ·ÐåmóQÕ9Îe?öp¯I[æÕ-Z2ì˵GŸþ©Ï‚ÏK‹Æ«•Š€ò±_k+©ö>¶…SY*Ìšÿ×bc Ò‘cåÞ™í™F¨·ðéΘTKîCaWÞªFw3µ!}2JFèGæHÒÿ5†š~áaŸk73Q\â)¸™Ï´=•%dÛTÀ"ŽW[ïÖt’Œ´+ùOëKÆ=•ÇÌ{mœÙošÛ÷ÅpY ü\@Û= „r‚û™~®]ë-eí;‡ô°b%ýæf©”³®ÚÜì¬ÏøÁ•Ê¡y°LP!}kØV–$’0¼g¿iY{ÆH~\ø²!ÿÕ9“à«s+˜I \ò¡`ª%Ÿð²ØJ¯“‹N4’©Ÿ9ó¯Q •#ÕhÏúň%ÏêÞ+ž‡jª­‹‚gûMÆ´ ‚¿^¨Œ$¬€I$A·ë<2[8ˆË¯X«0ý7­‡·K³‚ cøØè»7Y§V—wÄáóÅ3’ÙD²ca”+ˆŠn9çF22@©ß­WyŸ(£0òQ„-û›„½cS=˜1»AxÝ.=Ø~$ÈéœÛ˜,¸¸~ÄCÇa%„iVˆ9‡x§–ºxýãò£¨5ÙEÚÃ÷ƒp']>]‚tKUBÏpÁ¥ä* h }$š«õÀÇ»uÌf@¢ßAÉ0sÂy"«P™ŒºgV •ÒZz¢1ÑÁãRÀóSex}j[âZš¢òR^ëÂ,ÚÖLÀvš]¸„7%"Üz‡WŸ†'Ûk9:Þõ ² [«ðÍ ÈüžáuW:/r*pÊôD_=¦”‹5ÜüØrp Ç ¯õ>î4€\©“n 3oÒz.`ß=ÖòÔV‘ÒèÈ,&|ÖÓû 7 çr™×Ø5µôé>kàŒ/øµ1¤0"ì ¡™»ÊŽ.ií.€Ö]Æ™§»/Vó«GÉOú–»— ÏX˜Í$·NÏ!+]EF»æÞIWBFÛüÅç3@³—h‚)‚Ƥ¥ºmø‘/¿jswXÄpq¥OÖˆ‚n‚–¶U6eÎ?ÅntXtr¤ñûµ9ö8âV_RhJ\[h˜r"8öN@|cE;Àღ&œ÷m„ÅsvȆ$ÿ"ˆ¸R æäåÎ$/n¨I¿sñgRx½EjKk.⬅9Ž Ò€`,+{¾uf•¯vV¼$˜ß$‡üGø¥-É69%ów߈ƒðµ€b~°2,Ϭ¿üÀO¢2òb…´,°y~ò_GËF^ƒ“HlÏ”KIj_C†W0&„¦ªn!CYÌê"O+Ò×¢½œo­ Û¶?šú3µ·DxI/þHBÂ)}PÈqÉC³šÉAæî[ÔÌÖKKÀ¬Nªœê¥»*ä!¬¶œDM}ŒY¸T·NÓ¬žîÕ)ÍK‰ê†ÔÑ :e_¸CÏôÞFqc" ñ“cζ0¥º5MNÓÚ‘äÉ%!™k i§†ŠÞÓWT/Xûä½øµÉ¥]cÍný—^L'Ì6oWrH6¹Å>„ããÚ‘,°·±ô©—­ÄmÄn]JÓ *?‡,äL‹™ÚýDÙn¨®€&Ž š~?3­à± ÄÖ™FÏ_VŽ|R|cŠe˜î̯±š”Õð¼æýÚšË&ˆŒFaœ<–¯T‡ÿG/{wðªÜ"íçð£Y.tm”n2u AÝÂr ?çÛir <² hZf¿ýr(h}z‡îŒÚIÆ`î9GX€õJ3™§¨žj Ë-³ãFç–Ã8ìˆÅ®ôª^âC‘ôSO¼Î¹W¢%{#“[„=+ãen-@þ]Ö˺­ÂËÚóš4"æÄœ` Î~_B'Ö÷þ0;ÅäËÊÆÅK ‚þë/]M½¾ÀÛ £±ˆñ?Ü{\Û‚¼Â¨NI¾*Âtžpem‚|Y_bÙ’TB‘o9î¾lß{/êQMƒ:5x%wÌs{Ìòb pCFäušà 8îÁPcDÈœÊ4³Èú‹Q¶®M]VyO7cp˜F{Ù*¼ðǨ«V“Ê”È Ž1Óá#sŒØ)$º€{ÑW²‰Êë.þ«Jþ£™sü´>l>žëIP/ø-qTº«Wµ•㤔y½ Â64m$nZ&ë‡*Çöæc^#¯Â¯²ª“Ì` ²[–?+ºjB'ï{³ï3mDúÕ‘8¿GÇÚ&nɵ zb"V3–½y4 ‡/øÂU/ʉy-Ž8éÓ&ã=E9ÁT»ƒgTtŽIº®,{SK¶X3«î²IÒ+w×(”k(M³ÙŸ`懕ûýSç€â¢–)4 Ê½°ß«Y55¾Wj¾„¨~DÏú»3Ò®¼\Qc3ž›éº 2‚ZhµÖÑ ØÓ˜$´v-HÓµD÷oK9ùߢÞî´óûë`Â\ÞÔž0Ç9ëY™’œ¯ý5ªy±ŒÀˆ›% ÛÁEôÕÿæÎ@iò åÙ#8bµ§*X¢}n4 ª®v¡ö]9b¨ÝB¢¦_oRU ýè$o¿ø”ëÌÿâRÛ‡Žøw²hQ4¥ž€×U!ßϵÀz`W‹ “¶K¡S/jÉÆ±Ü[‡¯Zr[/¹¬àLƒ§ÍÌIáË–jF(ÑîÃCû†¥;ð±´^jÞÚÓŽm,¿IAy2És–JV–‘g$·Îª ´a!¤Œæûk¾®JÙŸ“Lò(¶œ÷Õ%°ßx IT^Ù*ŽOª =a%Te.›€ÚWªR™mÌrF:T[-ÎÑq µ1'…l æ¼©!Š:Ã~øÜ øŒq1«~­¹ÕŸºE±éÕ¾Eû‰æ‡íOEdÙ À›¼Uî§-uì0S–@“=šêÚQ‘hÙ7=‹>Ô›3íIi` ]Äm¬„5hÎN_§«?HÓîí·Å1jÁ I,ͤŽí;ÙÃ܊䜔‡6 SlÏžÃʲÜC'Üp"Éîóƒú±ôµ–|Ÿiå¼ÑÌ2´Åp#“žûçB73§ Ãóˆ[Z;á Ôs7´²bŒBòÂvbâˬÒ?†`w¼œÙ<¯srU3 Íä3h£æ•±BˆÛɯWÄî‹ zö½æYôóV;éM¡b Ñä(Åß+oµêH,ó]¶™b-—bn¯|=)™nSÿ· ¨}ìu‘ÔòèN­Ì›ž;Œë¿¤L C\NÒ§ÈYê@a|¿ùsìæ„ –wl«koÆM‰Œ,’c&OòUK#—Ôùf§õ|ioUã—ڨ͞D2·5A1kšÇQ?U:ËÀË­CZ¥R4 S:T+åbl'¦H,)%÷«Wn(±ô‚:!½ì‡+‡çVWÙê)Òb©À[ÚZ.éüÅ ]/«FüêNþ;ôˆûóz…Ú¡I–š¾¦J¤9‘ÍŽ yâIþàUä?ÞØãKÇਢxn]^Ì~'ÿ™*' |v»»Ë‰‘‘WÙÚ«ó3 R$ÓÆ”ÔMn3p”\¾¸~©õ“8ì[ïµ`ñR ôîÜIÞ`¨¬‹šœâ„ÛQCæ&é| ¿M˜tÖR]ˆÌæÏG©`<Úxœ©zG:Ožë6K>SáAíþ¢M«}‘m,—¤ÏC—-‘M¼´<·´HÅ£' ž^.âˆùláûb¥}u•–‘aÿ­‚àQvÝ’Q¸žzpòð(«²œ#”`Kêæ×~‡Y—±떦®a«w¶ëWVš@öâœj÷_+M–ædŽó•“G«ð:`Ôüû^"}ÀðB†–´ïîö$ö{‡þI%lAòúsc`m_ðl`Sñ|†=U €.=ŠR"ÄNx£ÙãVþ ŠÃ÷†e41 ô«Ó‰z3{®¼6‹>úH> ±êÉ‚Z WÜsBèösïæW‡ý3²Êg5¾· ñ@U?Õkl‰’±Å0íÂj.VxH¢‹P¡ÑÑ Ëþ4ñ…HqÒß„ ·*âj û¬}à‹)=f:Ò6ÏŒ‘qóÌÛËôþSÿ¦"ºŽ›_ÏÒ U¸Æ¯¹ús™Ù¤—£TxónWiŠu6cƒl¥fjîÝy»#‰ðg‘¸”¹7µ 2w¸wõ\W%NXÕZý(»õæ9,(`r ŠØ"ø :`ðç]é¢ãÎ0=f@TÄâ.:MUD›ód×ù‡WÌCüO ÄX–±_kÙÝH ¼VÂl¿ˆÝ‚ùV›·z%x@³þÜQ1ÑüAáÿn&IsKݶî¹ì7 Ã4¹9ë8ôËÎ¥aê‹k5•£œHi†cöäR¹H¾ÑBaÿÄŠû ›‰¡3>rKB¾ìÆ$Äf±Ç 7x¼)àXôo’>¾Á­4‚n/û»š)XhzñÁ+ÎŒ³w†Û™ÙUg^‡BSØ–½¡å‘} ŒEÏ1ôð-f¬WXõ?£¥y] !˜jd“þÒ‚üLbÑñ.F*ÓDkqOã5¦`F'1z$ŠäÁ!Ê0ùeé&‘Êõ1#*úœal"Rm¦èiGµgò~jí“)&9ÈFíüáÆãEŽi|•^â+—A’$“ ©šeÚž7œIO]¬ù/h`±€9mÇð£Ø[¼¬Ðmf%ª3Þ¢èݺ‚!lÎ Ï +—Àê•OÜ0l»H– ž "d5‹kXùÞa{1­ËNs[Ü ÏâÈ@´¼MOc¿¶Þú‰…•ƒ›þa³‚÷žKôýÓzBW¿(-8¼Ð•~zÓðÞVäÏ”‚¶%_Óø-ß2yŒSEÏ<0ý1†sàGÏ\ ýdÕþžÒÄÔ€¼hêXF&{ÝÙ¬èù1 7Ô3dZN~ç‰Gˆ]gÌÌi±x—íÿSdB[î›K™Ä„‘öO1Å_I% +³Š´uåÕ°ŸT…¾4ßfÊ”¨q'hn'G‡àùm©ME©‹âæ),ŠÁhègƒôàUv²êè;›!À‰]üÉN'Ñvº¯ÃÃ[Nß ’ª=©“Œ¥Ðml²í¿V£‚ê&ÑþÂj Á…IõZÈ´©ì}Ý÷v-33¦fW5z›8€Æ×U/…ó- hws¡¢?Š2¸gµ‚ ¯^ÖÅPØSVJ|/ «L2¿—3]ž‹ÉÄRÞÊä8n9Ý:¯+±)_ö{mˆ™ÕÞÄ´SOÓ âE Ë ¡’ùs+¸y ²1¤öωÊÚ™äWj 1ЧÅåÞ….|¸ÙK “ïùŒc4—'¢Ma_åb‰ÐÕp­ÜÑ»LÍ/V«Á0n‹'CHˆ|"žïSÊ£õotMiš>ŽÞ¥mGIOÁµy×3ðXiÈâ+ˆ€j#•uYŸjâTG™ÍÓ½—¼à³w¸„é«]¢Ê¦Drŵ¯ç,¢v/b6'Ê쀣¯‹¨CC©ÝÀ¡­‚ÇäY8Yë›Ãá*ê0Ïíº¬d‡¤â%˜¾o¿Æ÷Gƒ!òŽÛÏ·ÍL@Æ?`‰d1a3jc»#»ˆjü]ˆSJ¹l¤÷³~C0þ‹ÿEø•¼¼9• Â\XZ—9µNX9äáÜžz†B"ÎÔnˆÍ…MÈ çôÍ«85‡Ñx'Qä.ljÎ<ÙZª~ŠªÑÜÏ´ØÒ$•Õ½VÔé4¼çUlÁ -Ŭ+Ç]ýIîÖÄQäÇ<åRñ‰•t|/òë〧„ª GD‚ƒMs¾@ÿ}ô8_‘4i#µI——§PALÄq)pD±CQg›I^WØûÉ#6èÛÖ>Ú÷™Xƒx30£a-®‡Ft+5ŠýOc /ö)/‡C¸™ÂrsŽä²4°ÇN‹+úËw3™ƒÑ™xÂ9õ3RæÕ«¤S=Åf.†ƒæÉsÓ?Ày¶&ϳϭÙĬg!&諌ûò/ˆY$8fª5.½ÿUƯÿ­Ðîüßà¾=ŸÎO0œð»19 .4v šhvJ)ÔÌ}îÁ•7^|’ó K†ó`ÍPw,§|$¦Ø˜àUvÀ>-)Ï7-­[9_ÃCæÒ>¼Þ¼§¬,ø/ø?Ðh©‡‡Ì²ÚÏ:=¶öÝç\ýƒévÁU——“]!á×ójD+µ,¢‘}=¼¨Æê%“OòB¥¥!"Cþ`YÔ<¶ò%@ø0AG½Â{IÅ·¥‡îÇS il7>Š×-úŸöú:E ¾„.  [Èþ™üËä€yLï4¾ÏvÝöKS ¶jÔÛÈ1µVÉN-kÞʦú]5‹œ˜ Û=–(êtïÁ¿(CyBÜiúgþšIrŒ† Iº}\,¦9Ô…ÐS\þj3¥÷lŠN.Bæ”gŽLûé˜û;Àì°:™‡Ã}¹~ÝÀpÖIº˜gšvéÈ?Ó&ªç1vÍ ª¡c•—ÿH—…¢Wô¾ÖgVÃdé^‹ð(  Џêäh&*!d°´Ë›4è3¨Ý#Z‰ ˆGJ–êÅâÑ#×"·æ}L¯œ~…:ææ¾¢T{¯PÄPÓKæýÙŽÔÕ±¼»?N¨¬š½•6†õ¬.dKÛiÆÜcj¼<Õv‹‚$êeJü5ò wÖÊô›‰y£ðKÐ嶘†d æR±Ñì”K‡ÓSÎC*“2B‚¿TjÍB(ËÑ¡ÿ2h4Ý šÛQ­¸Ð7b]VO+•Óézÿ’.}ÆU‹Æ-ï¥_©é_q™Ñ “OHͨo¾Ú´Hˆ‚ø˜À @MxTR°Ù¾pvéì{ýh3Ç~Í ¼z¢ã“%uŒö±„ ;Ò^HÖЭð_Ë:µÆ{b¹ŠG•oõ¥V½|ÈDZë™çv•Ö‹ðö:–:oÖr£;qlAUe÷è6aåäÈ^@Ã{*Î &·+CJ'Q©•dR¯4ñ õÄâß@m;¾)lüµ—³ôÿ$?øÉ‚:v§nWI@óåpOÔTšà? ›ñþ,EkêLÊ_` €À€ûKn’c”i[ ²8ײÜE”2F¸¨&vÅÇ v\ÂäÀŒÛ¾g†ªôëWòãIYãü>åˆ;=mèˆv5ÝÝÓû«¡Stea” •K56΋I/ªë¾±ØÖKœ-RÉ–3hó½Ì±Ë+~ÈGÓ1Ÿe@4q3A4®¸:ë=3^zŠðߺÕêuî¥ML¨*ËKô¿±@úJ!s©óm%:0Üw“qõÛZ'‹å²Íá­&o²"`€íÅü!Šúˆ˜chÆf\á - Z;½  `¬C4H¸iTJH[zt\•‡—òî’ý>öÀ«»“?×`@ù“­Á<õåÜ‹³{¿ß±×™ÞjúÅ$¿Íuôˆ¥…vš_¶¼Ä7»Àɇ/äÀ³ÅS¬º™Ò9 ¹ìþ–d›$àKvû›ëSÛUë  “C' R‹B^7.Ý÷W9LÙOmCÉ ÙEK±¤ÿŠ‘/X·‰Ä {Ä~ŽW§G;ìXãg.•ôyŽôvDj»|k ‘#Ê·F(ÑÌ;„³ê×+ÌÍC¢ASXž^ nÀS.j¶ÖX€Wô hcèÀ¡>þÙGÝ 496„C©Ff"œíîD¸·_—½ëFv€ìhvîœó5©°dÅ áÅÑJCapðM ¬ZuC ßæ>PÆ+ã…c1Í‚2b™iÕ.3Áü& àt-Pº(éõÌ©³®{xW|8=ƒç“xÿ³GDùÚ^f˜³›äÌ,ë&ö×&Øå ½Œª—¯vü–&AJeWÀ¨´JUIèƒ|ÛýTíqu”dþtæ•o‚˜ÁxÐÜAdmoê$1BºÎ²áQo&·× puÔäzs“æ/X‚RrD!Ê*Þ|Nh°‚þk™:É[¤‚Ód·‰ NKcÈyîçÔdn@Ûâ\äóÝ6™MñOmþõæh S~*;å]ZÔTÄxän‘²h 8~Í‹DYeY/]}*Ÿã¥§/êæ¹èñ¿®d^^Bð~gn"Âxý3AvþÄl¬Í¥’ ¶Ž­„²¥‰‡CLÐá)BEÈ yœèéÄ‚Œ­H‡âsÜYaÜ`n£ùHXúéÑG9Q„±è-‹Ë¤Ã&)3,v ‰Ã™~”è™r ç­§Nâiq…Rßtî _PJ?òd Z¥ps–Es(o›–JÀïÄR£lݾî×=æy¶ªìîãÄ´NÚö%+âH_Å]4cv®¸­½K(i“S¼êx´Õ ôŽÍüÇ.ì Áë©Ò^„®?!º]ZWJœàLÿpj×[ÚûrÝÒ• !Ú”8èûÉø;brÝ5[‚Ü=¢²J½M§Ú èGö6CJ—í†ö®ÍвÁÊÚðšD¹ÆöØ]¢¹¯âjô3ªsf´és»éìê]¹/[ÄÉ`ÀÌUç?{½j7&’Ǜ֛‹Ì~ƒÚS9ÄÇÌÏ)¼0+Ú‘þ_8Ÿüã×ô^¦Ø˜¥çµèûmf|žó\¹ñ×”ßE¤ÔgÁ²çœ”ÆSaßMÑŽ^‚ ûnË 8Ä'¨ñ B¡­¹uB¬ãPÄÀ9»s8icãùž’›b7˜oiômvzËÞßZ•lb`ôh,®æ±®â%r>â°„f]>‹ 5=K—U~Wl— |QPLt7:R³ÝÖÀ{©#j1½=p™og|Oªsq;¢Ÿ´«'|Æ{¶)™5àóƒÔ¾ ) h¤½s—.<ûµzëbÆñ?æ†_M“Ѷ¡^ €µ.%ÒHIž$HvÔU9—éXfÈ8^ºÅaô‡Pe¡ô¥9‹—Ë9§>«-‚Ö§?1pœ}WCÌ„õf#VY¾¯O‹çÜòŠÈ~ß¹ƒë'„ƒ¼î Ò«)…f˜7>èú®ÌÓ#zùo²ï©šÎÆ]Ìòÿøj®*bÃM›QØrK¬“·ž“† iUrÎ/[¤Y$äƒO‹1Ú!zá‰v1y§Ú¾»ÄB¿?Œ¯Eqbg\KM*HñZ»_]ŽlXN€ |Èð<Ù„ÉÊ}]vÓhô”-nГD’xÃfa‹+‡Á¨Vä“^?ÚÄ9À•̈½[9²ºt•åýÒK2…ÕÊÚÜÝÌ[åÂîz»8Þ 1v—)yFaf!O[†è»‡©5¥&-)ª/2iP,(ŒµL§ª˜UÇÑ&=’~#ÖAäf¾’ETŸ¡³ÜÓêI°jt1Bîàº-@ME‰êV>n•{ÅÚ>ò,eCïß2™Õ ÁNEŽ‘ùWOGÚeMÄNˉÌHfJ_ò«0ñ|_hÇÕOFüDEé¶Ã»Ì€ïl;ñˆi­þgT¶‡ù²5ñóˆ‘ÍK$"’[ö…¨KŠ+H{Œö # ¯¡bþ×r·Ç^)àÞ³’¦V_÷RŽHZENP’Þð e1ÕzÚpD˜b ¯ªhݬ™+Þ%²ÅŸjpel†‘„ ŸCæÃ‚ó}%Ÿ\´»Þž)5¶LÖ%¦ Î-ãp0Xø31¢W–µM¹tn˜HÈ!¼qݵ¡«e¼y`b&ŸÊ5¾%1ó^#-)qÄÅ &kÈaÖ±BR ’ƒAø¤^¿ZȢ²ÖþÂh C-ëp/ì'OŸ Š¿¸s?M¦8?×?ì+îÓ’M9‘­/†‡Ô_ßоmØÒõ–;¹êh:Áž¸õ©°Sâö Kgêü>Ôs„šm…‘rF˜¾|笶šßæ{š¾T=¸f©h€JŽu…y™ndøÌLX†Õí}ÿf¥‰qŸªÌQÛl"×2SUXã&^p  Þ$ÇNŦúEûr&ç”}õMEá -.ðge ›uÀ~¸¶–Ès?Y›¿Ãd±µ²¶êmµF®J˧˜Ÿ$£Vv_'[PÅü¶jàÙ’¨Þ® \t é8nÿðÜí?H·uåXžžá>f/IiY?RD^ BÙüŒ•²‚ˆê gÇe˜˜í²’ ¡MlIoõ„ŠéúôaôÜ ÍÄe¿Ÿ¾nøü¼‡«ãã2º¨Ž4—#Y<µxt~ç’Í·Æi™ÆÅõVhÿx‘‰ò¹BÅ °Ö¾¤ZG¸ÊùMT.T°¦Ý1}éµUH8ºŸge‰[î‡[‚ßïÆÙÁ”פÉHû>áE óm)DÍUk@,:aP§-vHޒ͵ˆõµFS;Ïëj²„g\xÍ€}W%5ßà(¾¡4ÿ)P³LܨýÓû EÈ¥›Ñ••5íemà™’×qt½¡_Ê_$¯­Ù©žZ¡o"C]Ùó¿dOO®ü[T(;TEñ:ÍeHp˜Í- ï³°«)+w$c P¤6sQó@@GEZé€Y[6ÙíiÃÏ@ÅÀ2*PU6V04ß() çö¿doޝ+}YcÜjfæÚŸ€Ø2$ÎÁ6b¦³륄IžÈ ;.b­*Ó§`Äœ}²û®ƒ³Ý·“w–ãa`AUÅÀdù–é~s‘é—ö±•  ÜþS§è {û8¼DÿR)}F’3ÆÅ6/1qÃS}U¬[+¬±oSÒþ{¡¦èÕ˜Ç\f”¨ C  ÿB#á!:“½–ÀËî±9q÷„C?ä­ ¬²f ëÙ8h… ùâÓAÀLÀÛ Xd(ª¤ÏESAxƒÈìp(‰cÝŽS]ë›BQèÁ·L2$ÜCÒ@Þxૈ8,§ˆ{ Æè:Ñ»íørÓXº •PÑ`_ ò¦ZéæÄ¡ßí¥x‰äÏ8ãs–FÃÊt_–ƒ\³”ä³EÌ<ò¿Z Û„x¥¤°¼|Évšðý…7vêñ":Ìâ´˜a»•£³–¿7Oض-Ü©²*ëñ³Æ=‰¡Ü¡ÎZ¼¤ãQ \ív¼Û¼›<«8œ·ŠU®$ûÌmH=¨Q‰1Û—ÇCã[tËqÏà uÖxÕ†¶yØhS¿CW@ð*–9`bù*›õ©ÓÄ%^¾u»<íôÛtR¶“¦!ç…ãÃqst+yƒÎPUÿ¼˜£óK#ì£+O“ù æíAÈæÀÁÍëÕ…íä³4ùÓÿ:­M-ŠˆNõȧ.XDÏ*è.ê~‚YÕb–X\Ï­YÜ"áá%‘" š¿y>ztl^¥°ÏœVØh½½± YÞûlÍßêëËszµh×XR&=gÁ@ã mÝÆôʬ5Þ8¿½Ì!ò°?€¸r:â‰uÐÃwis³©D· E”­ W¢%¤$S”±V;e錳JoSÏ­wúú¼Ô—pEÄC÷Ø îÝߨ É£Ñ}êžðø) Éö&Ó¼5V{|ÎÏfeŠ`Û·gôr†£ûÔF°l‹'FûŸ}úèfäŒWFËò<E°Í«GÞóvjhdÁB®­„ñ óáVøj8¼¸ŸFÈ~ÒèËQcaÝ«ú£Ó¦=8ÜÊÖ˜â3HÝŽ(ëRMŤªû.j¾ˆ›”y0ð[-™bN ;}V5£ñ1e@Ã9=ðrªÚå½i5\ìÿ/@ša¹†)ŸBþ¸‹Öb™‰>8Ç%HZ_~ùPòþö¢è‰r¥½¢`YmòE0ÍÛEݪ“½3>' ‘礉â4¬1ÁaH>©=–néulùÇ[¼’÷Î[šLÿàbO“_wîüìÕæSk’Æ¢T-2Áìÿ¯ò8§'K¯¾a*>÷2ºRØeÒÅVóÛ®¤Ý‚J h§9ͪҴ¹\Óµ%µW­ù¶ïí’ &"Š©UžÝ¨ 1Ä@0(‰§F¢Pcü붤Šà^_@KÚP±-eõ—ÿº¼is•á0Ý÷=d–‡=ªÃ û ÖëGŒH¢ä/–üP›YAmlÓ S¿ãÐ5ei?ìÿ7ŒúK²„ÇCuRûK¯!Þƒ@K¿0„NHaïG iľhÃ\\)#ÄL2÷vhÆ`)NÔ{i,Êvtƒ,ñ¹gl#\›J7úA CÿB;‘§­b”H{ò÷$!!•‡q»ßæmÛ‚˜Ðçý†µ^ öH)ÄwûuW8\5šyÎøÇ‚ýOu² ‡½GJt|)9JzQ% ªÊFC¨09ìà(ßluÚ†Uež ½É ÿ¶kq²¡ûyE-†2cPûSÆ“ƒ«ÅnlÝ9iƒ ·-¾™œf€²¹{Ëš‡[˜5g-à*|É(ÂÕ‡V§æ°û¸}TQñO¿rûáÙÊ ?ü=újŸ Vðž÷ƒ¥¸àÛaÊéŒÕÎ~(–Úvò4‘*o†/‚ÉÍŠw±uµ©v )~ Ĥ¿­qúôÄ>Uu!“¾úèÌCõ"%ƒ¤“‚¢ASîòyï¤7UJú~=Pš'¾.úammNõŸÄ`ÀÃ8†°êóÜN/^c%R™!îÃìˆ{+ž­sÝàü~£$ŽÞnè»10z–ÎFº×ÞsS÷¨b’«qî¿EÖ¢™ µ‚xL?\¿«3‹‰'Ôú/œ³í#S|QZl_}|"‡RKf¿@jôü¦ÛbnýqžMå(Ë Äž_àvœÿnÍ5Ì _¥>oû­¾L¤Áò‘ÃjWQ‰~|5ÝÐK•[…ð9•…=æzaðûxQVé7qv±§×DÅâãH!…lKJÞuk›'%\¸%o{ì­ñNŽfHÞ¡¶µú‘'XÁ£*˜JX!8r^Á÷"pl9k÷Ý3=»äyÓ{MÊÆØÂ 9ÒÂØHŸT& o‹‚«HÔeüÔüé b>G%«î¨7:P5Vzù„š{}6£É]{¹”èOÿëÔñ)-o0ã§óVMN'ttæ=$Ü[¿Ù¦ ‡êƒU*Ó1dÆ"Zð{ÂësaÁP7Ämvy¬B¡Ñüo6ý`«z‰èD/à†æuލ*¥ì`@#¸Sæ4É%! %þÕÆ i°TOI¢Œ¿obÂUѲÏ?7y¥¯pwÛÂuÒ|Ñ—qå²'§L»Ÿììr"¦ °q2aCÆE¿N/·æT˜%fŒí÷.4­;!ÆÔJ„”Ûègþó(R½™wo¸ù˜1Ëí~Y“ýH#I|1±¸”S¯¶j¯ÅêXE±|Hpz Øc”ýk ¢\~™åÿ^8ÇQÚS•¯lh©ŠÏv)+ Zqµ*€Ûö@¦D qW{ê1fc%_ûc›sÐ?ž‘ùyʈÂ3[Ñ8-ç7h —ó×HÛSco  gå2"µ9LvU BO÷š™ŸBDy"¢øxÀTØJ¢“‹rRûªÀñK&¢`Û¬¦ 4à=Úf¸ö£+† 0Â’/sPʆ^Em—jÄir¢XC½´ x¥ó»Ö°M±4˜tÅÒtÓqoãøjuÔU¤Óû´_›õªÀ«Jx'£J·Ò}°Š¨NýîLPÿßðX~~¤ šìú0åßæd¥çY-])àR›H£Â¬£_–"¯}öÅçÁ7ò23«hxyï \¶õÃàõêÑy×âRC¨€ù-LÉq6´zÂéQxùeïGJdÓæ¹4za÷‡œ/7vå.BÝÓi^Úú:k«š"×d•ž6"ŸŠÁ¤ºÃÐP®hd€ŒŒåǺ,pºš›Dië1GO2ÇSÇv®Ýˆ¥þå¿ñÆlgáS~.k¹:óÔÊ?šÈ¤gŠ9܃Ÿ@Mø“f‹=#ȈçÔt ¨ÌFgáU—¿} s{úS‹ÔGô€ 뎽™‘¨}*®ë!Õ:V”`Aâ3sCUÚÒÂæÌ^“Æ’«Õ j} èd:¶ÅT­ûT×®ýäãZr*ÛÕ‘‰\lR¬]+ÓRQôÞI€ßrU®Ôþb  ³åÓep~Mc`VCV °^%÷˜ŒøóV‹‹îW@ ÷h›ïaÁ|QlE0 p`xò&b= J!G‡àZãÝèHÁå¡ÑV8ÖÿSzKÍÓîà~µÒÔôµEùEå£+%ï6³\¿éÿTu3Y“VÑÎF„Y”OÄçÏ|Ò…Ÿ§‹1kG²=PNÆY@˜FÆä¶`Pe¯ð*·W0ñáÝXl³¿OÀ§Ö*%ÿtQï%¿ñè-iÐ r`X…Ö¬?Îc ] ¢ó‘Õ¬ëüýt¡µ B._Üð"0Ú¬ÐU¦âÝM“NeÐ(&ýo!Ê6z@D[—ÂOÛd(nNáDãùTm7`dÐô…q%@Ùϯ>öÌcñ­dˆÂ!× Ruš™ô‘'¥Yœ@ÖwÀ¯ÀùwÎ=å){¿O®¥}HM`—©uÏ+~‚ËÓUz•áy¶Sü%™`á'ÔÔ9F3B® B¯ôHXâRŽñe wƒ½©è@>†8Äî‘û䜎A€ÈöžOÄâãšrÛ ýl´¿—¾—~_©:ôËË““ñ[¥ì@çÉéÈS†vžŒ‰±Ð÷ɹtÕ[¢Î&ådS™šªÀ\[ ûTk¨™lø:¨LçâÍ@ž=óIîŠ ªBÿQ¿_à¿´µ‚5¿8t†ëÎ<Í«•?&®9£XÔ©Fi˜ÏŽ¥ÊÕ´`ˆ4|‰“ÚÆMæŽÝ.ÜûT$‰Nzp¤êU³v¶RV‚좪ƒiMŽý;µl§µ.çøU$3L Í‚?¦[ŒÖ“GÄ'c|w»v8 ÚEVôÑGÒ´j“$¢VZÁ©/5‘Õ¤•ñ¦Tés1昻ÅÈc|U„€’ßi„:àð¥Å]XŽì±½Q  !úßÚ6 [šf`´!9*nqtžÙåy´4šJÄëÍ´ÃwÁtý+t|úbHõJàŸX>”Döãî°¶¾Äÿ>e·JsÍ¥u:>’üš˜ýCÁhŒD<Üg­èhfG¥/„×´ðß¿çYy^„&ÏA·ìò[„( ²œvp³Š-U¦ ç1ůÜž’zhÐ NâuGäщÛi*<ôHž_%xóqî©‚•"3UÀm)¨˜™Û F™Ê¸wáfþþ«;Õß'âüÞ›ÇËù~†àòýÆém½±uZˆÓ6»Œ8úG]â‡Ú˜‘$µC×…Eã$û…­B`·£»ÔnRºãñ19u®¶ùµ„GÍw£G°ak—]\ïªêµ‰'¹ îï0=rJj’“®J×'M!±Ùv£tsfò3n„óÂQQ°!±ŒÆæKé˜@sïñÜÌPÝRì` î z<ÆOÆãVwnží«5A\ÛJMCµmNÄ„¿¡­Å¦„nMöÈÚ“¼l¤¡MÞC—æéoå3âR—鹪ç ‡ùÚ}ø`úJÀÃ9ù{1(¦ô-}‚ó7?4I…`•ÄééN Òõ]æä¥*åС‹¹f7à\€°2=yëÅÑŽù59uŽ9ZOêEõÕNÈé¡ð×ËWXdEéSðX#Ô>Zz«Pˆî¿G·Š›C8Cypq@5ä4ˆë‘0G.*Å»‚É;y.£I<àÍ@ƒ‚Öʽ`+'°HLJ©-*SjÍ.þZu…É—«oÎèl4œíM¨ÒY•4ëôÁ Ä OL£)ZÝÞ72ÅG;Ò … †2øãƒ%i|aiÍw°&°å?z·;LëÙº'´ÔkžÊfý^ë±CžIßrøfíö§õÄ@³o™Î #¡u¼Tr÷ät×öÄ¥,W6Ñì‹7æó,têß5Ab‹?)Û ‚’}R‰(82¤RºÞħäÅgYÒ›&d;Ÿ°àðùÀòP²»ùµ’às#>x‰‚Ôfeç€{!'ôÄ·!5É3»lÊ­ƒ/»Šþì”Xz|«Ùi';Î,-è– §“ F'V½ o§­ ¨±p˜‹û3¸ªôÕkß÷=¦×ó¢¬;1ë('t„e®uÏò¡+u`‡Ž„]£–2áež,3­°GŸëŸÓJ_uQï°ÆýTPÊX©ƒŽØ|A;$Ôí¡Ê®–] ·l:ýÁ:žÙæ3Æ~çyÐ6@Ñ@QÀ}mÐf`ݪêm-IÔCíVZAÔ¨Á5tóGÇ}T-µ}˜\_úÝ{™Õãwvn ¢ C8ð3v/jÿJBN<Ú`8ÆFaREšËòòÁ \BhÛ=`mT@ ÑèÂ×ÑÂn–¦™Ë¾TKÀÂ/¶w %Ý ’?%VÿáˆEé!Ø‹‹œ{Þ}rlÏ0@ÞßI7eâ%áŸç¢ {ÆiAÀt‰ ¤ÆöuèÖBÏœ*µ£³ƒ"ÖìÖ5=É^ìß·qk»)7((*ÈDÜ@ ÀZ/:OÅeàK¾Ï©õmX[4©||ĪÀ1\²†;™.9å¨òy^ý¸¨Ž_êE3Ž¹ÖƒS{¸þG°Ü'Wð3S˜”ö.ÃUÊÎÝS¥ŠÒ¡ddáU[pÀUÏ&ó&ço4p×P`ŽmÒtt>ËŠÖ<²ŒÇ[½iãÞØ'JUNÒKEDsà8ÄIÊ-w‡'ðÊæ@¬‡Ï'!ÖÒ1õCT1oïÆ‚7 cæ+d‡>žup™Œ…(ƒžq'ü æ' ±t– E6ÁÒÀý‡§’ÝžXud „Ø® “¿¼Ðçkâé¥y÷…7óx¼7ÐâŠÔíçɦ¶'Ù³&ëåÐŒ„A¨L/Ú¸…»‘økÑ¿—@ò¹-x.Îä*c<¯¾qÈW…ãGÓ/³`ë›ßa%8óßÑØ¾ªãÿd2´$Q&ÄÔxXÓJ;¤t.š!„ñm åŸ;´|ï¶Ìïô`ý`<›‘_ÒËtV ËI|×Ýkˆ«öY¥mW´˜sUÛÒT*¤ÁB™É¸èÉ!¤¤!6^ ÒÔ/Fý–ÓF…W px½ÐU-pŠöÅ› O×OõÑ:öý"O©®ï¡]•¦zѹÃoµÔI«jgGåVÍÂ=µû¨oå3;Ùó•èYGRµÀ:A\SÅ(Ð2€Úä¥j@IyeI‡›®yšEtô_™·Æ—™4KÚ$ È¶ýtù#‚ÄÇj&ꉖjzd^ŠÃ§Zê镼ö$ÝØ…ÀáÓlÄõE°žWo;½¸eË”‚Ÿ—•²çiúþÅPXmjÆÄ]‘C&ådè$Üí:îS”GEáÅÄp¸îÇa zˆ~ÌeØ1Ø[Ú™±¦/8Ý@ôE_eÿ¥ýÖ9iêâÂ’˜ç­©âÅ ®dmWsCYíyI[ñò±1C#ùsš € ¿V†ÊõÜø©qøjnÍ{ÓeÁ^݈],‡¨å½ê™>~Œ®”݃uìš:Ä ‰r[m øž=ìî¢ ·uP(}è¿vÚr’„WÜ%d*N¡aÝÏ:Z9GÀšŠÉØxŠ™²‹å:ÎläFFì¥ò»yê)X]-‘ö†ª±­Uz¦X¥¨r˹àaà¦Ý*s*rÕÐÕ¬Hü RG効\š?'!ÿÎW ‹Í7-Іç¥EýõA#yy÷G3æ¯_Æg•üg·³5Å3„ê^;«\8 î[‡_€}ìc¥èɰRÙ c17‡g²5Áƒ˜†“ñ¹ó#JRbuŠAYþÃj§²è/µó€w«…mζsj—® ìSÑoF6)°ŸŒ`DÖÃ]iVeÄd§[~«Ð…ru @m“ä”ïJp˰b˜bm4äO+ÿÇŸPzG¥BÌes|áŒ0÷ îß¼%Óø÷?+A;ãe^_2ºIòŒÏ’Û²$Ýç©gV‚¾àXâö6 «F—5H¿úKiÚÎÙÌ@dš2Õ1ÄØèqGÈY!Ýtoej¦šÑFœš±.„KøæOÇ„Èô-ÔEû«H3i‹*ÇŠR¤PÊoVw(‘LH~ÄÌDÇÞKnÿ󬻸Ö/ÜD£…i â!aR½`O™½×½‘ïÖIÁ¶é•rN<†mdYÍ[íX%™ŸöŽí)ƒµ©öFœ‘HþY¨°EÍØ£œÎT!¢hBägQœþä„`~¸cßï™Â²hWÄ&ÃÄ’ÊTUv5B+âãªy'½i‡dZövúI-7ÑŒ:¸ùµó"¸ádé:’¶I—ÏEªà¶LB `þލõPŠN99{ •xd“C©(T÷8n^Â** –øvnîë;z±£~¬óÉÿK’)X­–R[ä…Ü!®»æ:é(³X„Z*wwÙÒ«0¹å‹^šjŠtìê· ð™*0õHŠñÕ[³-Q—(RáåÜ ¿\¦Pc;AgÊœÙô;XØl°¹#Juš Nu»ë#G›Ü}ý—}?hVãm‰!3cŒ â©àŸü3÷~!òLÖÖ& ÕHãttíhgÓö”PG±ÅÕÝo‚â8ž½FùæëãQGúEê{¢©†%>¦üéY‹¡jÎWBV Ò‚‰Pb’­TL0RöÒ㢾æ^#înÈh Ã‹ha¿7ê8q)-²ô ö‘_?ëðôC[‹P·Ì&bà詪Ãà†–aF‚°fîш˶g @A‹^|Vü™Ú[úuVðEqåsÒœGñPƒîc8K*x=iyØ,Ã.Ž…ëUyÅ<ƒ¹ :¬õŠ ‡nËÉÜøHh µ+xn”Ÿ]õË- ê=Я&x+ÛYtg wþÈc£™F°ºSÓ½A ;p°¦šÌêÄ“ŒâƒÌr=4_Èb>Yª ôý®ã``¸ý6 ™òÁíkâ>|-W럙¤^”~R&@»MõŒ¤ö«]¤"oÀ*>àö›5$›TtxÒÉO­ùa ñ„ ÂÓϽù—*.?cü¢ .•-.˜fkMÞºö™ÒVUèâ8ð\k+, ­¤šˆž‘XÄ­¦q’)™Ïž\ § ªòü>ú)Fî÷a‰i7:ýÇi£„ÚU±aA g`@¡A0ÐVѵ…a«?×oavÆí­ôϣ℉/Víž*nZÚÿX¼x_?q+ƒ—Ãâï!ÐáÑeÜŒªf¤¶a#¢'ci„f–R3M¯ýõÀeŒA<(±¯]Ä£â&RÍfµ)¨š_néVùÞóé #•µÈ߸’RNG~„+÷J{TµC]ŸgT²:1žéւи A\w”P|$Å$Ä݃ôœ¡ÎwY©ÕÖs. Å'3g%ä-_ƒ.*‹Û¤|Ft|ólƒ¼B”$·Q|Jñüq&3|Šºáº§Sõç¨,´†<‰‚4±¢À•iuôÓÆØ—"+>22ÚcøWqàΙ6.|jÍù¦–_€ðÉE•ïºT±„’¦iN«óêj#¡5Ÿh2ðâ?qZ_ãÛø5`fk@ÐO‹Ÿê†!-J2ðG9SÍÝÖã qŽ wüœ¶Šéìã} ®B2Ê p5ÏhB$Ò)­F¦É!Œ¨ÏTºP]FÅò{‡hV*¥ ñÀd¼q}¿(§@ï¯k_5Ù2™á¸B·HêZ8å &¤(ÉÆ™-Å´^çðvýדŒÍS wâß<J3°EÜz*Q¦ÃÍ’$›Ÿ`;8© R9±ÙihgZT0˜GÄôrˆ¸&Ť×FϾ^FÁjQ™)·ÓwšQ^³¶ð¤ÃÙËëlÏoB‡J.}¬Ã[Ý pÍàŽ$Ñk Dèà÷K#.ŽvÞ5šêùv.cïD #TC «©}%öÌã_¯:aKbÈ6pÖ×ATËZôÅùj†µ5+zÙG^•‰äÔý_Ôöwõ…£Ôžô­èÕåñÊOúl¨H´Ò•1n”ÙƒnQtÊA[ò—ß:&”øsE­:Ùü¯ñ‹3²”ÎÚNºõd’TõÌ"©¿ÂÒ문È.«Â©®u…ïÉŠVrJóéGâff,ÖÎ;-ØqaÖR3¬ãf.)+¯d…"SÙת÷¨‹½Û\xÍýê pLž¡°`%Ì_`—•9VÅe9°o!Qàƒ$u[ˆCŸš&/…Ðn°WƒîáÈÌE>t"¤ûý8ò•έS/Á— s‘\W~“Çä” ô®á5×쮂8 hf„$ßzœ”””úôNo'™Y7|“§Ìã\`lÏm?ÄÀýö&ûÙ% 2ºVO².ð,Ç>Šê€%Ùl), flvæfÝ¿¼þ^9Sµüì;éá|@3ö`­z}Õx£,8z ––KÞ›MÄé $}èå…ã¿¶¿1œ¦/ò-„Œ‡™¿(bOùoÌMÀh]OG'ƒJK6Ó;D6ù%%•ÏLÃÞèÞ”œ®*÷£eJOÈv¾éÇZÕ:$9 V€%$"­“Z‡¬1ªô¯ƒÙܪµ=9ò)¢P:ƒSOŸ«›Ä_]1 ¡³+ _¥Äsr¨ôß÷ÎëqàEBêT˜É…o>à)!Ú¨SbŒ·à)yº´äCÏ¡KÀ`gL¦Q#w©6.mw#21ó+ŠßxˆA˜=êö{vµGµçgM™ØdlÅi²”(шKì·8ÃÛÙ‡ €bU=< x/øì_mgï|‰ºeÚ%Ö¼§²[@³LÓAÙl¸ÁÇäy©Òœ$ëýrç²¥Ùjl@DÏ”a½÷§1I §Ë9WŽ=ˆ5ŠWù27Ô_¿`Ñë},:‘¾{Š" eúÌÌ•¸/h%ŒµÖü ègŠ–Bâ¿U»ƒØc3Òhh½soˆËR£8¤è×A7¹ =õtU.gª@ÿ@ð¼LG`ãö­õƒÜ$·§ÿCV½À´¿Ä~<í¥-,»]bÆè¶‘I©ífF¥úÌWB­k™þM Œ²á€¨Qh!ÿk@‰båxè¿/…c†¿Xjvæ•1¹iâ9—¤ {ôÆ«É1¥Ó©3\nõcØ4Wh£§¬Œ¥üÈa¶Øl^–׈L[ ‘·™†È¤]](•“û02®ÎŠ5˜c[HŸ!ëòôl  tƒKdˆ(5wÀZ}üà <¡† SL‚sYå=«{EÛ);\0ýÁ2mn—Èá$¹—þû œSöéŠ8{´‹¬»›' »Øh`Ë;ž£ï¼øRuõº~}»â¨[€ö!µÙ²g‰|«-1ÎóâλÏ¿¾?àÆ\H7 Ýûmðíy[žÀ}Â09цؑÐs`| á=Í®¡¬üò¡"jÀoÝáz)ºz+ %2CŒ!l¿Gï ¥Jæ[£ ›nNq‰÷¡­Ïͱ]9MÇË;}âúGÇì · œHpáÀ 36kP²ÁDm¡Ï«<ªÀ²ƒ‘ÕÛ:ò¢/MÉDÖ¾¦1Ëì²^ aO%…AiÄGÞf·zˆwXå:Úg*±ðçлÀ‰á]r™þA9ÕŘÈsÀÍÐ~ù)Ö·š?#‰àÝŒÅs¢;†ܯà’¶«ßW}ĉâAÜ…ƒ·ŠõWàPæû6Wöx‘þÏIóÝ©“YpžgÑoÎlÛëeaÇ´˜®š9Ç( è">œþ‚ìÅú¹Â 2çkIØùÑ­ßV½ÿZûVIÿ÷\Q±ÒŽ:¶E”í»aXš]»:e¡Äêñ¾%1¥¾Fõèîî™»ˆNoñü*œ[ yÀ¸‚DÇZ¼ ޾ÑwX«„3d­¨¢òeyôh`¦HæÇ OJ€Fo6·´©Æ|…w8¥=ÑÁÚã&µ?žšž×g$+hv­04æã>·‰‚Ϻ@Xœÿ_óG@†PŒÉØæTz€7H7gVñ8 ínr–è óÛWû[Ógdz3øÆ\Á½2“I‘sÈŽÙVÛû˪t{xlYí2ƒj{±7£¹â-×AÈœ¹¢c–'ç{WÊ%Öp»ïñF·,Y‹¾<•†Ö[㯿ØÉIeG[Û¥Óõÿ0Zó-‰˜“:XG»¶m,OdAU÷7§óG†Äî¦çîçÞׯémZÍvu5É.¬Çöö`eURwÈë.ëg:¼Z0Ú¶XM'ùAl^CÎA1»­üd׬ž' Æ9÷¼æœ꟡Í D[` øÉí1°'x¤9p"; Ù¸g ‡4¨Y÷M?¾¡½Û&Lœ™f~ü ¯ÛÁUÉcéx¾äŽ¢cózQŽ›kx€ŽåAª)Ÿ iýÐ5ɇT³¿UÌ›^þKà^kCÓÀj²»õý€GÊDy•: bœôJCËê‘o¤@Ò§™}\2þEXñ‘²åFÊ•ôçÐ2χ)y …ôbƒ"L5=iˆž¥ª‹Q|ë¬'[æzõÁØ€4xŒ„¥ÞÇqM’ Bhɨ?®Ö5NfÏÂòsLÐ/‹†ÓàDî+Dýõë/\«*ƒôß ,«ZƒÅõ<›2cG#·LÍ{i[z×ú'_.~¼7øæ&o5=…\–.ŒöDoÓ¦Ö(»0rFÛÈ­N©áíVêÊÑNÆÚ½¿#2žó¿ßí{;àéÚ2eC#<R’Ë—"ÙL²_YbU“äù›2ÐɸU-Ʀ4MlGÇu ݱÈñ ˜Ç•ÕÌÁ‡_í’j9ì«£¹‡PtKEû•I¡ ›ÝÑÓ¯gäZ+&€)¨‡ºÙ4÷eÈ€“¨¢ÒE 6Ýıêru¨Ï:=?M!/2!ý8RŽ-fÇ¥Èúº~Ïã¼ß<j­Aî¦~»Õ¿eyÿ‚Dm—E@6FÂZÏ¢¹]j”>ÁkÞùòý@ö+ zL¹I6.ìJ¢/ú¸®fIGlÌìb¡_†ó%ê ,É‘?¿Òž{bá‘j‘ ubwÄéCáþ“Vç9‹8"ÌT¢ôœŒåÄìšAzʧ[÷C‘“1¤‚Azô§ Ÿi/b—NÊC ›î÷ã6ÏkÂ|[Ζ“¶v!ȯ %"·ME-µ·­½ ìH—ˆhp–Ôzž;Í:˜þŠ ë¤Ru+¡½fž•Õòh8®Í·gK®²jŸ{ßȇû›ÐrðUDõ!ƒpp8Øç©rÀ ,½ññÜ!S‘÷d² žmÉkcó~…4ä9ÕÚo0Fü®”ßõȼ™+=3;D#³ûèâÙ©©¼¹ÜglWg¡À’çà ù+-)ýø§cŠÃÓIÑÄ8¡×]µ†—¥x0;â[ã€6© G`ÇíF­*ë¨ø)bÜÙlzÝ&cß9‰eŒ² >g)CË·jMÆ£¯57ù:Õp}æÔ?îKXHQ—–ö=_Êîé0ÂE±úCÚäÉÚ+Ïä¤ÕR—Ï“è=’lGñ@®hÄÏÄʪ¶®«‡D¹Î5=x1ê| qË–ä]úÿ àÕ Eßñ˜1B~»Éo¶Áº½Ym§8ælMÂËmH…¹ä¡F_R„¿AÑÓp1->lSÏY¥1ð[ka§(ì›$ÖœñÇr¥;ÄÐËÍ(FF}ît™E¶ÏZõ>¹õk,I=ÆeÇNîÆUêT“Šv”€=°ù”ICûÿB++¸ ¥À4Ÿ¬XWœÚ°#iFlÀYØh1V–ÄAŠÍŠqÕ«úÎÛFnI(“íΟŽùË-‹-Üá« &Ó¿2Q@Aó[q¯©ó­ètQŽ‹‚cÉô Nò~«5"ôVdA…ÏŠŽæ#ÎC޳@3}·»T‡¾/ÍŽÏÅ0Çdñ;{$Jìûß"é’_–y,F{ÌÌe6ÙZf£*EH¸VPÎOÊÜ=D<ÖM›~pj06t(là ŽvÎó³º,¹1®Cs•ÛѬI?^ÜSˆ„Ä•ê™s7T7¹…ØF›³ ‰¸a8jêa>¿KP½þ´E–€ÆÕÆy tT05O!NÎÓ`;úôVÍíRÃdULe\”MB<²ïpÑgå¬ÒξcW~íq2ÔÑLwcŠàíWwôÄp]¹—ÁúQ¸‘É©Ø%kâ©·`o­ÞÆsÉÝ -£Ýßå@¿-§èxÇv2Öë™þmR=]–~–óQáu³_AÑ”owxOxÙ¸®¯ËwþéþûÄÛì p½Dù©’ÒeÍO1GÇ® 4§!”Æ-$ c û§ÞñAZá‡aéמ„Çu¬#&—·³Ÿ‘ÿжúßÖ!?FõÁ:óÿ<ÝênͪM»6݉àqÞ®;ÜxS€%q¾+Àã-ïúE½Þ¯ˆšeKG­cò Ðd=nøCøÆÕê¶ph#ºpþqë_f÷‡àý) …#cŸØÏÆÏ ‚~#ÞªÀ~r·ç×GebÛ Årÿ–Ä<ŸðËR"¡•?IUÞrliþ÷üšLÝ­mOõ iÔ1Hð¶öåÇDßbªàw ?{ktj¤$ÑßÊPèI%¹,#ÀG½†šE¤±DÂQs3uzÑxlŸA_ú⬠I«O¿uUhet£R)Ϲx ±Ÿ%É»ž$; Ä§nûÿ:’Ï7ÖÕæPäÔõ%ÒO¼È"ð‰ê¢˜[ý¤§d0LfŒøKß|+þxóÃýØõ5–q”p "8÷‹kí‹'|ß¿Ÿcp®vTi=T ì-„1F½|¡¸¹lô¬]÷Qg]W˜haN¶„¢P†43À2!xÔxJ|Ï™Ä7,®²}„tiwöiö¤xZy™MƒFLžcÇÕY¾ÄâeñsHÐ,'Ÿ¾ÄDß¹Ä[’&æ&1k‰cˆùRÚíé"̯ñl¡îÕl>30°màq­úŸ&©ºž>#ÑâÀŠx±æíǼ?+2¬$;,Ü’îGjwk Ò×6LûÀdÌ›éÕÙÆÀw@KWm“ƒ­Ò:êo}Ñ¡¾–\¯•ôKœJù–^w¬Ël Ð‹qÿœz5y–¦wb‰wŸv»k>–•ðHÆ- Üü7ú8ÎTЄ¡°ÒŸ‹áwÆC÷> PGÛ‚¢€2ÿ!v\§-ä”èÏ7 RL¼;¾úŸÞ&‰“ñ%¶LáDÈA4“þ4fA¿‡÷%;‚IØ0ê‚d†¹ñf1€uݹÂÏæ‰p@§/VTUûÍgÐÕSÛqx4nk´‹]Fáßw“—IÒc-78ÛþÕ6ê€ ‚Õ_P‰1òYˆYd\xàï¤ÛÞ:–³ y¾V¡Áb_å—Jƒx+vóU¥û ˜ÿËt¹';%?4ר¤h–noQB[å‰$’‡Ï‹øxW@´#U½CPmµÁ§)ÐAh Þ3YÇ:×Ð;V¡’¥´iYõÙ»ŠõfƒÖëDñ.0‰PÈ!+Ü—Á&ô³*$ìSTS¯WõÖòQѹ™•ORü¹À+îQ%>Ï sàÀc« hà¦>¢èQ¦êÚEè­«OJÕð†¦ƒ¤øm½J*KÕ“'±ZpÉâåt½jq!y Öƒ¬*d桊€´Ôê´ñ©b kC¼1‰{+ÉL—›:(TÛmëËi|²·gŠ/ë) ¢aø.7w<‹Gôâ×5ÁJfz%ÿ qŸô…¶È P~بïd—yÜŒð¯ä~û­?»å8™Ÿ->˜Ö ôZ«ò/ùßÄí(Tž‘oSæ¾Ò$ˆ{¸×†¼}ÐN«§µ*µÑwàI#Ð?ôWýkX=‚{4»³QžEÒŸó1/Çd…Òå¥%í(¨±.V–¡¼ÃY*ùŠ|‡“¬º ‹¸Ê«¶ÿ.¸òÑÝ…‹S¦»œP!Y²^›Ûà-ÏâãÒg÷áK‰e7QÛKºXöû½šªĄ̃:Ù@{œOô2™ÚÞ „kr²GåŸHÇÉ8ìþ\”,/T˜aÏ;…0wdôÖ0޵’΀K›ÃÝ3ª}¿ uáÞMa@rÎÜAÏÅ-„¦QR9N(œJ:„U4(C Aí¤ÆqÎiW÷%/dÅý—2CÒAv›×;Ü? é†„ŠªæÆ$‡­5wè…¬jLôRkyxY+¤¼!9žÄÌß8!…;5 ú±1ÒÙa¯­ìÓÙ»Ô»8üDªäªW?U‹” …c8SÕúïžââC¶”¿z3­³Â´]9ô½ÅÑHáó¯â6·'«Õ”ÞvC¿OßbN2Ì&íš"õqLô½n|qÖQ*sý3ÈEÖè='k®ÄB›® nÂ?ñ/VKm^íøh¡ÇÈÆõjIÎ]At×@PBûôE^æåw-:NA?Äùx,WÅѾ'K0Füm(8‰Ùíàn R#%T›&8äÓá(mnòÜPÝ#?êÕõ‡‹ÝŒÇŸ¨cÅg…ÓB»Á8]J÷Ìn¢ÉÇݼó’_·ÏéÎ6þk9ŒLh#…hDdD1 ¼Â®&=7¤d§½p’×AE&¨Wͨ'9@ŽÚ™^L‹>‹¸#%¦”2ˆÚ{ûè¼”¼:Y)kãÒ3FÃãn;féÏ‹8e>­µ£ *â6m¨µ5Ù¥ÇÌ`”ªKóõïlšñ!×y»ÚDðy}ûÉhˆÁ†$òüo·Ìˆà­ÄânKÕ*#º¦ìD#Ÿã¨¸ùÛ‹öj¹)ªaºÓÀ¡R`_¯œÑrÊ-½Aöh/2èa_p1%w Xásïq å…Ô²Œ¥– ·nÔ)»ÿ2­ƒÎ®»¨ìOÏF´þ Ú€¶‰‹RÜHX·\îÜa¿píçøÊ§ƒ–¶˜‚Oé¡Áб˜÷éG{MͲ¬váò ¸ÎüQEÌ£Ib¸ìjS1òúá`Å€ÝÖB½€šÕì[‰ß¨‡ûŽVƲ´}Ðw¤1S| mQOÒU¼¼7ãE´ò¢X<ÒxLK£Ñ¾+. 3‹ëùƒE£Á´¸$ç$%ì¬(·¸=·t{-ž¨¨[ʺ΃'w¯¯çÿóÙl‰1䯴à­\/%U;¶¢É–/*EŠM*ybÖÊY & {VW‹FŒÅ°Ÿ”ö#Ìb«=SLJ<=L‰ÍóÜš Їê/Ô™<ÜÊÀy°=è_x"KJ‰ÐJid¯çÈ=v÷è`ìw‰FþMÆÄµp|(a–?4_>i‘’ZZ»PbÆÐh7Ø1‡25hyr©‚×g%·á°¬ÚDÌÚÏõkÈ·¢•š¨‡É]Öð‰üö™éQƒäÛÒT€jNK›sß– ««ˆBgåVÕH9oD×÷Ý*÷B_Ð|ò¢¡Q†v ²[nóV¨mly¤^ÛtÖ~+.‹Åg z™®(5C¢4v_À€sÍm£¨ØˆJ‡è à§.¨ P¹o» ׄ!÷Ÿj– GŽÈdtb5š¯$H™±Rè·µ]°Ö›wdñe¡¶*HÐ'ÿÌ$îÚ¨r :GÆ;!½G0èÃ=׸MÖÆL õv2”º •þ4Z†‘FÔ\Ò ÖL¤Sº>a®Œb¡¤a_j4e\û{¼ |ÿyÕü-ÏŽ-FIvj‡ÛSr4åfíDj×(õâýòˆ€¦ï8Ó¼J‡Øœ‡C…ŸMI1jOÊ*‡}2OÐN5½ ¬ÏFÄ€y’;‰v [UÒˆú2œN§  jß3Á4#…cÙÉS“³e†Ú±ï LžWnRv`”^Yîöulÿ€—m ¤ªoQú¨/OnÓ¡‰T.®‡+£ì2Oc„WEk¿DÎÚɘ|6p¬÷†ìÅúO*Ó>øÿ(,ÿ(0ü4§2&Ëù]E˜¥ ¶|c¶-("ü§ÞÓÀIþ'û6P³Ð(Èß²ÐÌðYþÂÕ±c‡IŸ­q”C‘ê%[=èð›; TÖïP’ÅîJúC}½§Ž/y’p¿èH©öm$™ªE[¿ºX Ó{›G5o .<ÆIÊï…4¸ëçÜ(¬È”¹eä½Xòã(úr¯§„’~Ò&_‘´¯X9¾ƒîŸá3V(vqZ/~ÝNÛV7¹ÓÏ¿«(Œü0 Ä¿ã7ƒ.]s»*jJüOÔôÂÎóRð©Î¹  +U›–ldžG[­PJ,aÇ<„Bö²Iט®+’¬óº°ÅðÌí{ZÙÅ·!2'±YBòWWn›¯—ÄäŸB£P½t}Œµ¾õ·­oÓœïUÉþ%D9]cÊP®{µžõ ¯fšÅ>GA2\t~-Wº³Þ\|8â£])p(ú”*jùÖ˜»áBÖ<²9‰¹ÑïËþÈ‘Þ"ÑÇP=¥ô-™ùÞæë<¤ ^ûóƒ©çÚ‘îExÞBì— Iy*Ñ›ê3ÇRíÏKÓi=Ʀ<2¬#›YtŽwæIëí4æ €æ1äÔ’ðµk†èÕ˜[¥¾Ìˤ-·(¬÷IF¤ôÅ ™3˜¶1&NŒÝô_Œ€Ôþ5é þçÜ:CÇš™‰< ð¥usë$ ª$ÅX‰Õì"N®õðs=•DýAÿØUÁ—À»9rôäíZt&~`ñ°ŠÆD`­â<0‹{‘º%uMöìïúš£þog‚V:>sK›¦÷=ëæJq̈v”ôª`_[–QÌQÏZÞ÷V\Ѝ0¡8BtÙ˜ü‹ÙÅg—(NÍšÞívÒþÚù“öêÔ€!¹nRÈ7j§Ð²jÑ^ÚlÊo?Ùô$–1ýµä9g5w¶.l„Ó7<@SOEÃe=h…§3N³¹ê¨×aûNâÙ$ÅvÄ+ìCB̓ñPÁ‘e#„ºÊ€Ç²Uƒ®Khó9mwß Äêål+Vt}-†·3ÿOöÝ+±"n;éæ}6~‡I"…e>ï@Žå}A˜…Šûx0|]*=€TE¶ª $çv#Åhì°¥—À'åü¡mBh‰¯tÞ¥Xt,E&$rnÃÓ©ÚYRÜóLÉe–N:_±×б°¿ã*N{îñ 3£=ÃÞçê±PáÖ€ïGSi§„ ƒX «ü@yžª_ȱ·:¾4VE^êU· Óñ¿žƒPîbÜaÁ¹ÂÛà¡ebUÀTî2Fæ»D:%\i]×6¦ ¼ÌY0‹ t‹Û«£Ô9¶­¯•-­ðFö6n‰mÔЗ—Íà÷e@ ˜ ðôOÜ~Üéò7gÝOèk 9Š’Ñú[³È F5Ӧᙶ–/ÜØ+»ßz<%5+È}¯{okRQ´Zýw®Û©LÊhí÷,F¼¿Žà=³G¸ û #$× ñ5Iµ¬Wzö˜ ŸÕºY‰õF¾Žº‡#4ベ%í'8ñ^¥Å˜PþßmÜF0ˆ4#ÊHò]PôEN¤•D ×U>IŒy1×zs»˜ÐF¤ÅÛfÔ$ÏOCͼŒä=; BÙDþݸJ(ªw —wú×áÍ”±=‰¥ÄŒ7úN€íüK•îš š;˜UµXækÒ˜„ȳ×wÚ‚El¼Qy@qÔ‰3‚)FdPj96î“Q®£"Z«nî:…l²Q¦Å~æ®ó:á"ÕïÁk±§Ë¤ê¾ ý$”ù=†7ì­ˆ/~Ý”kLw MÙòçmI G/ÆxNI-gÅ}aÏÇñ8™¸©/Ž7½ËžÞÂ%l X-Ó3Ç›Ä`éT¸äè gmÊMÔP‡=˜ýC«bv†úér®w« ¡r£gM|nJ92GÎøÍËÒ®Ðì8Xräå>…UVÎi€ÃÌ.sã#üFÇÇB8‹}^¥¢rñ‚O c :Ðù¤"œlùÒ4~Òüw ™~ZWÅÙBÚˈaq#mÇ”Ïn#èòwêÜ}Smñð×E¸Üqü¼ÀÄÜ=€Ó:¿¡Yþ’ù7z™Ö¤•áŽRÇ.¬H­ùÿ*˜*û;á“°CuY]X*¬Áëo†&"†áðÓý³vµÅ5¥»+C³°X‘meâ¬v4(Q¿†ù0­S«¸Å¿ÛÚáŒ^PS4•Ÿ”ä!áÓYqHúy|Èî–aý£(Wjÿù¹ïŽ»&}5ÿœ±…€-ä¹øíc¨“rÌ-݉‡AæÔ±CK2ßtÄ9Û ¡ð»FŽYqÓ}„O…dB[¨áÄ\ô8)<™Õ\È Qfà}ú²*?öÝ“s”C˜ãÉ KŠOé1^­± Çž; ¨ªÙdcßÜk‹éRPb¶Áèº%€†ß³3ÄtV´%ì¹Þv+°`dpšM–L p`y¬™3ÊMÏàiAú¿:Å 3:âÇ`çµüɆŸü¿FÝ¡UEæÍ ÑqDªn¥ôŽÄq|šq"½†¼Ûœ"7±Ž•iÒ…AÏѲº?ÎWÕ’¡)¨M::å4>Ç¥ó¬*ó¼™Ò53}ó@„Ä•þݾwÿãµ eE9M§S:Ö‚ [ûÍ]î{Ó=qÒÔâZß#…U¥´áŽ0XüÇex«d«{„‚œ‹S3ýG 4A–JnßlZ€å;–} ç4¦¼Ôs±9$ŽýÓ_ïéÈúsS® O1°º½ßLœó eH\çÓÖ:sË[ÓôHr‰Æ%òÏ‘ø~§3 ¨Ý²Ë‹‹¢9„1PåãºCèaÓG]Âõ1Ñ8lÕŠ6ö”;7ŽâuN ÷ÅÝ9i_؃óΡãÂó– ‰û{2¦Y/ÂÏ…"›¼ ²5&xGƒeæ¬ün|¹¬[PcžsE7ƒþl@lô- \_@B>ÉR´tlú^Q3(‚oR/úÆ£òÿ,$\%‚zÜyÝWmùlK¦?ªVŽ!¡+ôRŹa{ê‹ôŒ*%Ï öõºTÅÌxQ}«ñ¿[“ìV28ݯñËo(`Øê”vhþ)9/ä!%Ôçùû¶yÃ{749ýP™êe%Ì¿[±ëG‰G…á«?auLÕœ-‡£3Äþ£ºh>Ì‘.ˆ<±ßG4YÀ·Gë˜Z‘Qœ¯¬e3.ÿYU Ú+QWðü³kчñw÷›˜‰ïFf÷ìënÆÑ`n|Âó(y0½8TÔ¯,ô\Ð ®¹I/•uý)ߊçEX5„Vó!éR#º'#fr*o%"­¹~ÿ&}«kÀ¦§âô;tU Þ¶¢ï:•0½º¸|£ee_Jõ$ÿÔL'•k ô¶D#3`#SÛYSCÕ·Ô¶†Î7Djæ­ÙýJ¤æì†fìaÞàn¥„±(¾ÓÚ€êæ€騶t¡ÓAà{0ñ[ô 1;lb¦òùkÇoÍ5”¹@ø¯# ÇIz9«ä,ʼnýX±ü7Ç_ÌòŸ\s!m“\Ic-TÉEÖî“EŒ¢ RZb뽯 d•žÅ3–r /©§åÓKÆ[Ž„(ª6Ü¦æ ¤¼Ë…†ìÔyw†_Ô²-š€`°Öz¿Õ>¢Ò+,+[Ä¥j-GhÌõ¤È^\6po¨@Üãœ+àL4®’_à>Ç—5ŸÀeôl™wåVî©D¦é×~Î@ üÔ/gÓÝo#Œ˜†Ô¨Œð ~XãÙ¶åk!¤S–Úé> ¢Év—ùN/ñ¢ˆÒoò1GkââBâoþ4Âc™5Æ›‡š 4§>rrfÕŒä[lLר+dΓÉçkÐyt€ëþñE.Šúžr—ˆ]&Fu¦]ÃÈE#Oyä «›±ö‰O\7EAÛFÊ(4ed,úüÌÁM“×°Äò_ØqéxÈã2Mùð‰à¬'ÈLtÊ7(ê¾§akå ¦WxÇÃ2¨Ò“Ô¼ ”·)z¤sSÄo¢öcÃ9>*cÕ7AwÇFç©™Î9PqÎ^çQÚ©…ü!xô°ccÏW£1Þ¿ ÎÕŸd2$áC@,õ­o³¾ðd,åàbÀ¹·;{òvØS¯,^Ë1îÞ&=èj3‡%ã~}ס¸SUàÑhøn>øÆäŸäHôèsÑ”ZõV( Û„›ÓV/?íaæôBÄ`V{bÎBÖ0 ‰àIpwfŠ"SÀ¿=σ¢5uL_øs–5ÀÕÙ+Ý]~Aè 9wdF-Ë&³Àq9ö”Ü霯]œn§ƒˆÿ{K¸{C„VO"ØÖWåì±áÚ±”ír³+`À.åd×H`h»üKø4*§“¾ª+Å9>—NòÊå?KÍ//ÔõeUþ"4H¨ÓÌ÷ˆ‡s0`޵ÞÀQîwTOÁjÏO‘®«r².rÔ¯¬…Ë<=Íìž¼ž¼Þ“±40€éFbñÜð¼ÔÛe`¢”(¬€Ó9þÄihŽNUà˜O³Z §®ÎpÌ"ÌØ›&Âb˜3ä_®6½u8Û*­ f©±‹^F:^.âs"Ù5¼ÞéÛólgM€Ánë—“™~ºmãÆ(ÈmëM(ˆpPb‚c¼Ü–»ì#¹Ûåîì”4ÈñÏZì ‘Wï©ô$÷Èr›Ø'¶:Ø&ê¿U ߥþƒ*zhÏMÛôŒ:?¸rûKt•…'_ß=iD|Ô¨‘ ¹u~vä…GciLüß·~óymî5«Úò¸Fñ¿ímò_¼j]è¶õ~Ij‚ßïÎ`“9;f1ûJ½QöØ“…Å«xÂÄ ç'‡³Ïûð÷Û3Í7o0ÊP'˜Ô¥ô Å{BY(ÿª¤—r@¿ƒ8›å€L*ï Áëy—oßNÈ>ý©¢Ó~ï÷ sËáO«?ˆê‡8û7EÒŒmSü œj,±ÀúoízœÙX?l¬Œf¹Žp¹Z†>\­À†6Å'³ú½AÙ¢¶!“Ƭ<µ?BÔ[÷J~ ©õ‰¦>‚ÀLj6D“ûô¢Ð5ÿšGJ&œKÆñµãJ(qöç©{JñTù›C7?E©Ñå· ¶P¯Ê©CcA+Ü(òÛwŒ¼rL¾2,™·ãqÐ Å„Kð&¶üX`G÷úLiŸ1«Z+ê,Œ³¢Ž¿)Hc8_äUë[{]`{qz "ȲꉭK¤«ZÍxžòu‚Æ[HK€Ã4ÅjôŽNŒ\”;ûÌ•xæá5Åd_"Êã³É¶Å+~(V¬-†ý7©Z÷äÚ€;öövø¸ø3³¾··ôXÏÐn£úˆ U&=ï/‘þuþ6äÖñ)˜û)˜µ‘éDów±{äY:²)4–‰h“Öƒ®Ð€·81A)ujkóNoüÙË÷„–ëJA…SÌ*×½Âi?­êˆÞß2ÖNôæÝaÕŽ¬L!ŸG”Hµ‘ÓÖ»ú9–3ËÚ²ùÛêÛ±¾œkKø]À̓GÌðSkûúlœ§Ä\Ý™>n§_nÍÑcü6´:qÍUx­Ìîb÷”ûq#ä!²¬Åô0‡^¯áÐ*w *·ŒdÊuLCÏ¥tŽZ¥ä?µ ŸsR+¹‰[Zù9ìû˜eÙÀr¿EðìòÏ„S« tµîÆÃÕfGOÝÁ$IFŠÎnµcl†5ÍÀ5,½r £&†þ–fQ D#,c\t±¥™UÓ6‘5¢ÃLjÖ4² &ßõR*â< zEb&ì´ÄJ ¸ÖéÔž3óŽ âK!fˆó¼Í¡Ó³Ë/„ˆMû¥TÁß¼qîcŸeRÐ(‚[;‰Mœ rß<%÷̈X0º‰Øý²úRè¨véOèÓ¨BŽð~+K@Ö¤ñ°R¥=XÞ³£Z"VÂÜ)ý1Þ—† 3 ŸzQ¼ØLšâ¥ÎÅê¥FÔÜûˆüÃvI²Ô¡õ„ø‡¦­ûR43×KóVJ©Š+°îÅ=“Ê`Dò…àŒ#ð+à}•øUz0Þ…_¥Ë-ª[ •nòùœå <ì!åÚÿiDÿ„Õÿ4aoèЫØ{Ä;L±¢ 'Ò8Õ  =?îðî%?;ñ¹ÐÊ úÎÔP¡à,÷«¡“k@Ð!{ñ/S®žgzs=³`*ÅZ«QŠ¿–ßÊ\ôÊÿÓ%o$¡q­ü|ÃA;5 ìqœÎ1y–¸¬Œ í0LPÄ>L×ÐNˆ†u~Zhv|Ô¹)šƒ ña6k"öoˆ½’y: ždOüÒ²Ü@Ô­I ÷”ÒÝ!iˆ^ÒR= ‰1¤hž„ DËã®”ö,Ýèä5“o)Ö² WèpP2Â_®£vïèù´wtŽB– Ÿ~螊mÍ TÕû<DMó‹SIšPLº,ÃËàÿánˆ=íQÅÏFø4±‚N¸1Ì3ên1_‹?ÜÓŒ[À´oî?UŒŸ¢!{ß‘Á¶%ì]¿@Œ>õŒ£¼ÞÑ3OÏÃUö‰?xXȯÞqè€\víAn$7úÃò£hΤ x›ÞÞT÷‚œç£ï÷*‹ûμÐ\kà l„ouÇ œ­(S&4 ;KX[]GÆ ñöéÔ6˜ÏÈáÆ ½=Ç·ÕX1sw Zìý·|š(ä>q‡Ue±eB- m´ñîc²c¾âÃÕ”$°($I±üVBÃ%ú†M€Õ‹k°6çêx¬ã*¾¿-žÃ‚”Vd§R,»^üL™ Ï~êA¹?×…¡#¨Ðnë¬úÊclJ5_Óº‰Æ³Ñ终s®ÔƒO Ø*ök}žI2˜ë¼ïÿ>˜ÍÈÊØ$‰zÛ…ºR‘ºÄ¬<°qzèÐà¬ü›{ú{œª gVüß’îÐ=¿Ü#²qzS½”¢R«ñ0üëÁMÝ©@¿ÅÉV¯Di °,˽~ªòÂ~–6eT!ç 0zOg÷•²gYê9#^u;£yÀ†7©ý]+5îÁ;è~ü¸RAk¹$S­MšîE8j¿"°¹ ï]ÌÖ §#…g°™¨ÝÚrK“šµW~ÙÓðâbY½TP¡Ó¡Þ&’“ˆºÞéÿûº/|†KCßÀ‰Õ~\àQCNm@M_7?a#ôsTƒê( T%uÏGf˜C/w½Ô–öøòíDì´-f·.;ꮯª[çÐKÞÌSmK¯6V ¯!ê™ç.îÝ•âó|w Ù¥PHDpç°(WlEèzæöv+ðnl’ ú‚oäåé“g‘ÐÅÍëðèðm6ù_u @“W“ä2Ðc¬ñÒO{±M"6·BÕHÌÄÔïù’¤Þ–1ñCJÁR|Ú¢çj¹µ›AJµ i•N:¦ OýCc6T€)ȧîXþ¿w º¢KD&KÍ–;2ðÈ“b¨“ãäU€ØØ!õå)ÂŒr[ÆZÑÕûcÄæk)Ò+m¼èùhç—%ž‰ø•õ÷³¦év¼ÛŽ,ƒoÙ(ÚáB ‡΀—~ûÛCx¾D‰±œV†'íIΗEæ‚3VaŽ=/º Ù¤¹Âð®zçL¬ŒQ2è‘2¹ µã-¤~ˆ¶SeŠ÷3Èó…!Â{è‰Î›ž§ÝÛ›KÓäùdºðåνq³y\FM.¢«âýxôÞ #¯’e›&Ö|j n‰ò 9È˨îá×NnÊZ/ÁBÝÍÅ_!»eÁJs»x~¶(*q!1zÒ^Šþ[Ǫk{É%…ù¹×C滈Þ:ïÛíû¬8sP§à23/–˜¥Ñ£Ž?‘xšËŠ“­ÎË·OÃjNÈÃÈš&+PÓà¾<ÇÆ]ß³©'‡2² Å¡Â|J.ø¬s°¾Œ¬ ¾l8Yއ~ÚB·¥µÀòTªKr£¥=ÚPOÐCÔAÁ“5T²ˆ›räOhÅcs u§ñ™{:Ó(¤¨d-¿Ø>Ê‹ãˆIQq¨I“h Ð¥c=¨C*Ï¿ÂataŽR)R¶]Zó­Å<©2t˜½Ê´sî\xƽ ¨aÄ·Ý<–Ü gÍ–ë5ê×ÞE&èÌXg•§Åoi£=ÀP¶9“ùXÍ\Ìruš/Ëd yàÏŠ­˜ïÎÒ“‰†]+šËH ƒ\Uÿè|wˆ*ñmpd’¼Wø\ÒÆ˜£ûä`–kšÿiYR 8ßÿ{vuÀE¨œCDŽÚß?1ú{•"ST£yq"Æ{iRÓ¢cdx2Ñ5½`-Yy^ÀÓF&YŸíÓŒ°ïR‘µä"èÁ•ípñ×FË5¥N9¤[ê˜y‹­p/fðÄ?)¥Gà…ÖËEc‘(>5™ößðu”mœ¯z—qs€]O·ñ¬_'­6¦`êC»ÕOy‰W=¤d3(‰ö+Þ0h®ž’6¿…aó|÷}(ªÍ”5´åÜÎëYÎëYp<™RÖÃa·*ÁÑ0–µèFíÚâx¬ÂÛ_h"1rU­W\ü+£*zZrw{VÒ§ ‡âS.dB†î*KÀ{®Ëãßs]à¨aoFÞ4Ä FÞBÆy×ײY†0•èåd:"üS6ð(®áI]æAÂÝÇná^3 ëÞ^ï´å/Ôþˆ›®?êÈB£Á§büFÞeB:³¹1݈bÖv(US‰Œ´ýñûÓÊxäÌãÕÅ5å€ä!]‘©ºëtýná|=4`ýðj–—lX%òQÜ÷õO’ ñ)šý³ýφèkSð`^ç„ÌE%YŶWe$âûÔÖ¾´y_Î8‘‡®8>Ýeªûì¤~Ðü¤Wå ºMç“Ðßþõþ× õ¯·ä 9j¬Ëd£ó[dÙ¹ÛDß!Û7cåš)1QÝ5Ÿëа«Üg1Ë Ç>ØžÕ|‰'¼Çu ‹f+؜Ģo£¤Ìª>yC"æØ«¬™h|gÀ9^žNkx y)r~©¡Ó `d8ùðvZiZLÆ„MǶ-1ôõ䋲Kg1ó/8Ù²ñ·!9\ ’jèyìù»mb.“ɶû£Ç z²Ýˆo̼ù…aÎÓìï¦þv»¹¶!WgžvdÓäã‰6+¿³!]ÓÈÁ ×ç´UˆW_.—îtD¢•äÇýr,dY-ÌÉWª÷\‚ÎYŸ~Älé·ñV”7+ýÍ’íî;ËíP5R5¯ø1å.›'ŽMŽÍMß•`7Ä3ø‰ÎQIR˜ ŸÞs~e÷ ïðå ˆfCëò m#qðgå­¿òkwu(tìHšG¬ê+êÌãP¼CIŠG[ Œ/àéˆ?Æõð]Õ‚3!×¢hSP£Åy£bJ•Ôdé£Ö7 ì²Ë¬ïC‹bã.8¿,sx-Ë¿=P?yˆŒq‡ñ/pi}Y+Ð^å/ìËU®á[È–¿²NpêÀÎ_‘Û§9WRšKcPE®L›b!!tƒ8SQ%‘¨LÀ‘*Hؘƒ5Ø KíFýwÛêÐtú6Sì}*µ›§»±}Qþf;i‘-]è•f>ë¹À´< ¡oš²0ÜÚÜ*8XÄ4nö޼“"AüóZ„›9¾_ãÔ•°Ì……·Ö®{ß’ñŽãújÒªûÕèD%–ŠWÙMÈy#v™rã–¸û¢¸whói÷Uf±râÂyš¯ã}Öý(—ìD 2‘ʘ‘Ž‘¼Ïp=÷œ¤sPœ$oHÿ¤Q{ŒâF³´âD"j|`Õr©gwz˜[ª·¨fºÙ¿D,ÌäNÀÅ0-SŒ"Yâ.\™Õ„6TRR>V«£Fø»oðl¤~'ÑDù·¿ôz¶½XuD^Î"µaþɶ´ÜI‡Õ".ª™!¬gß´Ér ‡tŠZ zƒ&+újþ`þn_ÕG7=ë´D×Àæk'thX`¢Iþv=‘s©Ü­£,;ç M šâ†Å¢®4Õhu ½¾æôr†V@VüžÔ­¬%5môŽG šµü4gð`„0˜Sä½ûÅýn±ìRë¦Öè£0n¾ÜgPrÿÍ’\[ãߘ €Å ‹AÛ'­O›|ê¬Zp\èÝYE2äÎÌΙmióø¥6 ÄÖ>‹ÿrÓ¼áyR}})Aà´„¾ZTµÉޙͦe:†ÕrÝE„â5µ÷ ×R¥0øÚ7ßyÑ_K÷¿#\ŠBš? l/ð‘hO®Bõ]vYžx1G°‡ÎO ^Ae²¤ìܸ_URI[=åÊj©,]Ÿæ<}•]`lBOÒ/5Mú<ã~U$Xqp3×U^qí¤¶y=mA†?LЕ3Hï·«ÓƒmpØòÈ¢#]ô0S6sTÄâ¶qõ­±¸vjjP/òæÏEé0éÕj®2?ÖNQëáDé.2þé(÷wÓ½YàÓ-(hC¬òyqX²œ,}›Ýzþ ½AqÞ€À¦@c:tXÔ²G‰€h×{{†J÷Cð"ªÚe=ò(–‘‚n[4ÿˆëÑåUÐl(Ž KGÜ5« ¦#B dÓÓxs0m‰±÷øóÏdç{.ð˜*S·Ã¶œVöÐ&öaëWŸæ0T0I`ÖyÅ_˜ø<Döæ(Z±²rà#g—ô¸^i¿˜„ÖW•‘ƒ—·}·!8»Á”Ë.Ê Ûò ¶pGKÆ­~¯–³=kK%²ßÕ­«ËйV¿ ¾VÆXc³¡Ù(9þ4ÄD¸ (%s„F1¥S!én´nør"©Ì‚{[môSÏÄûÌM!š`†k½j?~]"d„È[Œn«¶p”:…+ðKÃBž2´•uEò³toápÑ5ÃWa‚K$¹sŸj¼¥CÀƒÀÍ®©Ì¬€çÚ&a§‚ÁÈ5F89Á6¦’ÎëÔ0¹7ø8‚bG±ZUƒ~dá\;æ‹‹©Äxì¬A~˜¯ª!¤,‹Úå¡b[žh¥Ô /ê.£ýZº‰W„º¤´pŽýÔެ—î3ü¤Še'„OПÜ·c#UЇ–ßõ¶ˆ$l¬I–¡ÚˆÈŽø‰©oV‘0Л§Š©™F‚HWgº¥'GnTl-‹n+3+ÀN– ¦ Hݯø™S̼Ðù) `ÏåníêhF٣Ѷïͪ‚Su„ÒAÉ5M”(Ù*û+áV9¶vØEgÚ”Œ ^½2–MÓ’ZñTÈZ@«÷kagh~Rj¦·ñY…Vë„Tg•ÞåZ¼C²—ó áóÛ?”£™¡Â׺ö<ˆI“·¨¯×ò.ƲèzWñ§v2­J(¼l-Ø Ë껕9¤ÔF¿ý¬×õ™¹o4A§j!êôóžØåË"оAŠ®]–íÅ%©‚9¨Æ¸Ø™¨±_Øs hÓ”d’SìyäPQ÷Gôý.¬qoì »>jÅÚè?•N%s[MÄWè´rÉRÃO<å¾öXÖï's„j~'tµ 2¸/1yA¿ËÕž™¹Vgu‡æ¾µ$:ݺërÂ`rŠÇüÉUJÒØÂöÍá›-L­[*€TÑéDÜ»òiÑz¡Þ–Ëa«cA;óðzN­·z¶'uŸ– ]B!Ç`ƒ0Qy>núhrw¶7º6Sq/žº\´£…ÍŸ¶}­Ÿ¼"c2Ÿow¡[#+l,÷G DŒfZ§< ^'î>ŒoU(u`u’<lÝ,ùûq ¦¯²›æ<4Ô­˜HÚèCx*׎²AÀÎ’ò{x$²áäý 3rlgDµ´äÜö‘–QHW|SDQZ›‰ÿ–‡òÌšÛB|²$3‡ Ë̶ |Zð…d뢢‰—7«¹\„潂z*ùÿgëùPÀK+ÈÔ"žšqh.gw]Êü™ü·(†”âÂKX"–Ô•ßà5ØH»ó¿žgþëæB Ð[ _ÀUï?NœN gWŽr&æ:…¹nÐìBʧ'‚T¡·¶pÞ=|è`\ö«\±¾§ƒÇj ‚ÇOLc§R(nW 4€¶ì‡RŒ‹æôs¯¶µò›xâ´—Œ¤”û¿¦{Î,ÑùC»­ÁÎVE!Ù› ô ÷p#úÞúAävmLyô¥ãCW²æã?4X¡¶Á•ôm¯å¬EyÝ%K^ÖìRøÚ– 0`¯¤øÒIïUº›ƒíÂ7›Ï›F‚oÿDY*VG£%½a·yõÑ»HâÛ7aN¡†¥î€RÜ—+†x„Ý÷o£Kjï—¿}Þ j9C6àm–ç¼×` ­u.²Ê-«,Pèän<ÂX±…Üð“Æ€º|~Ö›å:Là?AfÍÈ£nt†²CàkñÚ©,>G‡Ç{iuså8Æáåãô­$À…âõ²²ùœÞ!Oö>kɸaˆÓí¢û˜QÄo’1G»ò Îu*Mòm”Å/F¨a"¯W±ÓŒ´¹þ*Æ…ø@x b¼Us³7iXÜ÷sS£"ú«YnEÚáŽSôcNSä/Ð…Š!#¬Ïß!ŒÎÔŽêÆ¥,a¹NDV"¢-L`ª«°þ`º{­i‚ë¦c\ðëœ~ #†°ÝÆaSŠšåßC-"µAøt¢8ÿ*Áu® y¨ò`¸øLcbî0‹L6uíå[›+O™‡g·¡ LÀ˜ °.Fâ»­Þk3jÅH#éëÄë[¬G§7´õ¥ûa2´+°¶RbF´-.åµéš'Nц{Saó…»%爴—ž… G1 Sîø#ÔýN@Zù,eøÚ¯Kw_»ò=89s»‹S¹èYuDGÊŸÄ kd8LgôYèùÛ¼µ’ª1ûK28 iåù¿‰Ú)s17íYu©jÝBæ«þç”X €Á@4òjp*ѯ¬nô Ù(­8U¸ÕBá´š…ÚJ¼³Ó%Ùø=s1­"œ»L¼n=–L@&Ä£öŒÈh§5Ù'c7OØ2>1KëqCRÖ¶e× ’ƒL±&ãÖ “üýÑ7›)Nˆ7’äu­·O€©˜âf” 4½7—ž×^„­tŒ2‘° ‰ç%£Žù¨ÿ 31¡[Yeè˜ÔÖ ”åø&·Öˆn®•QšõDÇ­{7 |FJ«ÂÄIkÜtÐèE§Ì\¥9Ôê ­mÛUñÜ4¦îrmŽHάz˦'˜×bPù?¦ÂKñ‹þ0ëa䟥53Ê’„4¤ý>%å6BW–Â*)ÓJ]ôK€wà à•Å`JàMS=štSð‘ëK@¡äÎÕ4Ì»妧‘Þ°´?ËöC'˜ˆG8^ó•!6OO…ÆË`»V~Z×D m¶XÌç9µ6 akG¶JR)½uE‚l®}'Öbí5¬³ôlV€ó¡§P8ƒ{µ!f£«*ÍxÖu[OÚAŸÁ¸¨ù7_ÿßôÈÀ\´gweõxù·DcT»ýC»¤¸”þ”Ó»=ütžü'w…üïT“UÞç´×.¤ iÕ„PRTpÈζ´8Ÿ,ÀI^ F+ä%;Õÿ®Xrn@ú0߃É+1“6ÆL5rµÅ}Dº¹D6ág]?’(£¯‘«n[+î??¶ßzkÉ‘N§ÈŸQ;’ÕÒèöï·’š=QŽ£ë­JêÜšŠ2Ö/Þá|n#N½{„Œ³òUEgà ºÛþq¤<Ò^”R ±GáSjµÅDé,” †9È‘ cÐâlÆlë=IP8òqÕVRÔäH&ã‚<ºîMÄv&j‹iJøaiã­Ë?âôB¬+ e_ušÄ×2€Ž@•3}BZI“‹¤ÒÂEÅÅék÷µµ³®´èáðo?Â"$Išo%wlÕ1©j+«µO( .„ÿ\wÜJŸ¤×¥ÃÈyÕ“ ÛÀGU„­(¬ëç–åEé}¬Žpt˜ËËɧ?¹——We–¶ýÇÁ·\T;ÃÂ>ÒØ »ºlÅwâIÊ<Õ©Ôa‚C0‘Òš[,{h Ù`ÝÆ+§žM]‹<ýî°Þ¥YŠå†7-‘+_.©ŠVޤ¬ìp~®™Â"Mu¢¶ÄC²«ÊU“Ë”k‚λ£úèxU–´KÂdXa©UÄAV˜x®í— òÛBÜ;ÅÍRƒl¼²˜· .Pù³Ôºa p0ëhtåôø£?ݼ)앵²Y®`ÂqÃã¨J§ ·gEÊË=ûèÇL&ÂW ×{\¹áÌÛ(½/'õÀ•aKw xgí;`}ÔŠ¹ŠöøhG:(-I$Íᕵ9ÛÊøfg¨}Nº'o÷æ|39 n¹ôý°$ÁZ÷©7Êãy~’*ú”½áN:©íw4j†¬ DjÓeHX‡=˜"–7èõ…í3ì%€ðõ `—†c[l_DMý½Q iÊP³ E8e~»@#G2ö™ç4-Ø­%üƒjS8äo¿îê7¯jåsQe¥0Ç9ˆ=Uæ~ù-Õ¾ö_ -=äæÿ·`3ýÂÔ(äúª©íDEûQ«ýy¸œœÀÊìx”P0SP1™\ÎI³6T½fa­ZœæÄ­ý†YØ=¼œ ®n—/©Ò‡³%p¼~A àFÐ  d:Q¯YÀŒHP·é6tô¼\»¬Õ‚ᦤl-K½A3ç² ’V+Xî)EÍEõŠ éË«>n—p7´{Ø%KäwK}Ú0ñg‰ï&Éò;Z«:GÔ¥ 8™Ì}Úd”öß°T²‘Ó…T/Ï.ÈÉD¿4xníÖÞúTÇö(so§ÅˆZ<%–ßoVMëškGGn›Ó¼b0#yÝÉÈ~d×ŸÑ pi?Ù¶´E«ÖçI¤)(,›ß»åmÝÏ ZŸ½ÍûSì½CxÿTZÖÃÚ9  M ŽÒù°°åìAë@“Æ,¨òâ0¡úTŽ„}³"6,ÁЧùˆýÞ¡ê)·)a–ìcÃŒ}{`ü3gžE'úwè&ô0õÈZclÎV{ø÷¬ùn®R•vþûêx+Ù¡*eEKé¸&H`:y‹Gàl3Ô¶gÖÁ+ä;~¦†3þ1}·Öñ²³#äØŒ¾ÈKÓ~t”6UhJ%]oï,Ü…Ü.g«YWï6—}¾c¹`”€° å—eË|[„‚GÌsžAÁœ Ôts ”?±ïwezÇd~ç{s§üÃXòÇ^a¼ÀÎÕ˜ ×[YK¼i¾öŽªéxÜãlÞVú§½Ó~;5WÁqljeg$*Ò³šÀË1ƒ `⬿ˆ«Dˆš ?’&¼­´o´âO{Â:ãcÄÛ"Ñ9ìxÐøµô[MK¼Ôk´Îu¶X˜™:/%`ôJMqˆ;^ÄzJ¿ŽQÚæPI esôú‚}{ äµëážYZœhùíÂí+ëPcø)Ÿ‰ý(Ùʺî Ïϲk‹Èù<Œ{–“¸ kÝm~H6¢϶+zm«3·uoÏq0ãÅ#ö€Òú–S††Ûƒ:gÊ”8«OW\/ÔöoÊ)Èû½NÖšö}æG„–Ì îé›Ë¡OSkûžc&. ÌÚj•=N°‘ ªÈÞ¾rD#6mx÷8×¾XâX¯ÁÔ&<íÚ¬5°g‹6(‘ ­_ŸT<›ظvü­iŒ±­ÎÍ7§#vSŠwþ]Ë%¡Win±Lh|ëý•ò Ø÷õ­Nõ0¹â¬¸Cx´šû $uÜXesâMJY:DEQùOø; ãU¹“Ïv:8¨Ëƒ¤“í¬’FHîÁH{¬ý¸Àòš§˜ü/pü7!<Ú(&4#ûôknf„‰œžÇDsæ„9-ó¬ üŽ¡ÛZ–‘ˆÔÚâ®j~0¤h\ÔöŠ ƒÜD•áñìm¥Ìy³fQ[„5hfXODZ„Aj‡Ú:'@Ô÷2`&,ºc+"£êøÀß@.ËœfÍ3–8—Œà}wú’ü¡Z¡ŒÇ í™à$LÃúöxjwÕ³~]Á,x¡®†PÿzfÒF‡Ï/¸çðÉHmΊùµ° HBó;i²üÊvcÂýEkÉ­š¥–àýÄÏÉùTÇ!ÿØ€lÕÙ–ü:=žìKÊÐÃs›r~ËC "“þÀñº3UöT>1›4õT8Â#}:cϧÁY¼P*ù­vÊ\U‹½«þìÕŒ'q60CÐÆæ%sÎQ²5ù~´jë2Ðö×ܾi9¦O§o“¯hM½«Q¾*z”4¸c¸¯jþ âN&úOÕ¾jpjèl¢ !";óŒz]Ï·TiR§ #™ßð›Ä׿×LÑ”\×fÚ˜T.í3ÕèÇçøY••m.pËÿh‚C˜„­¡ùñmtõ%$ÌvrúÐ1 ‚懪"Š™ÖÚAk¢jq(»i ^cãì’ˆ,Izç¡®dd†ÿô|BméÈKà?Õb^•/­£Ó·® €™ý&œ"!µèªb Ç&+õµÑ†˜áÜr³pQsHë=üï/§˜ÂÇ7AüKx©áV䯯!U¯ÝFÃd¨çü9HHˆ[¨°¸%^L?øs*IÆ”ÒÒÁí? ‡$‘ÓØ>Z3ï™ÓLBYBŒL냲›ÊÍà«%q)ÂDÃoûx+-"^Æ;]À&eŒ ¦±Ö'ÏwHQ€‚(ͪôfQ…íNFbqRP€YÛÅp¥¶ ÓZmV°Üà_]M$\°–ðÝfÙóذʇn¢øC §ƒ«‚<þÅØ× ·‡šàøöZN—…†{>+2%Pä¨ý ëqôð=ÿ‚,4õݡ黶¡i#¤å‹öÓH‰(?i*8½¤–;Ì­>Üs4‰¾´Lh„œ"Þ&U /–÷±ü§*5™ï°PØAºyµ©?ûQųW×þ¿sb7ôÇ>Õ 5#â*I€Ä±ù¦_u¸þjvŠú2?3›É&r/âjUï\úç]‡¡B*>L—E-°¹íïbKÔßåï*7 7¾ÐJ ªÅV ™º*ñq4ß3Ö»çe™Ìê³ß?fµøŸ·· N²÷£¦¶øÅj¡{ÐüöåÒ‘¯éDd–8õo… O”^.Âím;’‹šuoÊ)’ý ÃÿmVéÊ6Ko‹î+GÚ[xÜ›øSF=v‘sãA:; Fù é2‹´‚Cò^Cœ¼8©®ÖÅï=¹‰k!.Ê/&*±Óôý—xS9°‰˜ž_·Ø>o-)„ I¼FÇapµÇºÉi$ȳáÆ6éb½DF}®,}¡qúÅÐs0»ðš‚/o·Ã}KÚ¶"šûݘUÌßÊR+>z÷ÄvýqXo•;§‚]á_ó}Z‚ãô|Ü–´âÚusÜÖîjä5Æå%ÎÍÉ\C;›'Œªëm4L¥YÑc®n÷f C xm‹TÑ?^å㨙/ÄùôÛ«dô“æŠécÛÁWTôŸ~Öm¬¨ˆØÁñ;=ýÚ/i +J·fY5÷¦Q}ræežeØ+xŠãu5ô2M¶pc``²S#7P‡¦Á® JLÕ$ ¤Ó]ñ¤6Üùg3@‰Ò¥¾Äøòç_§66==½7F5>‚ W?;¢ì“KF†HÑÿöd3!´Æ„˼]pG _j+OµÊ¹K×Cn)Ô>Üd‘ÛÌ/¬=ÈDbFÐ¥ËLY~M=ŒÈ´f¬E×2‘¼ÚHþ€ù°­œ43Ì€¸U’%~CÀî2HÐÑš˜Gg4’ÕeGDúˆ,»±·0”ž¥?Y&R*œûÿ¯Iõ½(÷Ä÷]Bþä6n1´Á6‚JGdÓ%9¡©]—Qd—]«§i½ñ¯N£)u˜ßÊùQÉ%„é8ÂÊ"š¸3ÀÀâòJEöïùa9R÷2ó0•KßQS‡ÉQ¦ô+Ír.cå.;:™€ Iæè™'²Ú9û<¶÷–ù…FÑû$ƒ»hº“õ²KÝ«ᘅ°ÈÑHå‡Ìçú>Üùgæ\[Ц¾W ï²’‘Ö¶^CÎxk]z¾þ;|Пgém(¬‹ÇycIW-3&ÕºäÕ¸ž§óÅ­TO°«îh-0œ_I/N1ì±±«|Y¡ÿX ½ý_ Ò´Èþ++eS7á7L«o@‹­*`ýw‡wCL«¯ƒòH.Àypr#ÉÒ­Pa–hþâ̤Ö*7¨2¸xzr‡–^IMÉšõoJ·Õ,<‹Zpm¨ðUªÀ8vô€º#Çüi°R“]âäSÂHkd&¢->eµøÐùxx zeŽ.WÄp–ßÐX¦O>>ÄAPC9ÝØ–ü,rÐü|,“åØvµ‹ÆÚ­qÆ{ßR¬3ZLÐQ®…"¡¹’Ê«ÐÆ¦óךÂöšÓlâ†ÏºÝj©p !ÌN­Ï ­`uh)•ÜþÑ ÖVÞ3áý÷Uo·ðHV >ï54XÛSQOX6Î%1æ_2•}H\…A œt°‹G¿PÎ& az©fÍ;’þ¾”‚Uã{z&ÆÆ§‡x"iÎÎ:-b+éŒu[aqÚo´¿îôÜÝÑYÖ}ÖjT3`ßxõ²¯²Ø«3VsKÐûè!’S%f7[J$¥[Lú{¦­£«'¢·!imÑÿ†Ìš-QèÅOš eruÑ0ÙUа;QÆÌâ(L E×ú˜€&´ñT;Ëú|²âáCÉÄö°ò¬Ò&iâcµC¬–MqðwËÞn)£ê=ÎH–²½Ff¦LÜ—7Ÿ½JFiBM¥‡!Âå;›|0U¼ÐhÇ Óëž'^C2pþc‰ÄÁÞ™„1ßQõ8(|Û?õž?Ù—äADH’#ÉDŠ(Ç$¨…œ•ýHEH<Ññ?æïåô;`Hdk‹’¢Ôƒõ²`E}ô3w2Á—v~éC"Ä‚ …±pc‘uJ—Ú{+2|P(#ߣòçú—fžhд\19þ*Œ ŒÀv)w™ð‡ Ê´¥CüÁ‚N®˜Õ+[>Ó$I «i#ÔD5é‡4Ø[ì SÒD^Ò§Òç5ì¹Þ —’|,íŸÔ©x®¨}ZOî,ÿ_ù¼va-†uÍf…éQò¢öÞ+sø…ÔDê,æô1Ϩ¡’ìÖWØ[Â2¤$ÝÚ[æù'Wq%cx³ y1l ¼³×œ‡ŠÐg›b6+®XN ‹5/‚€Í K*‰òI5“Ì¥ˆ !ÿ ØÞ¸4Ÿöò¢ŸéB¾Š+'@µ¡Ö”±ú:SÂÕáÒ@‹?n¼*<­xx+x_§u  ­Æ½Û±4“)3)©·Z$ïmÝí1ðŠÙ¿—>¹íè¨9ø:‚K7‚Ùß'®K*_jä“z?½ë°œ´®NOzƒÓø›ù<÷Íãî…LeWí×Á‚n«PHâÄŒÔ΃1ê„éÿë¥i—¤ÉG~ûˆ|dTݨB¿cv1Àâµ{¾ÄÇ_ù°I@þ8þ…Wð 7M¯“"üvŒ§WÊ=€ñ0iÃð[ë}Ù è,„1gsªuWj ™ïVãLVf2°¢ÚTΉo³»{àɦÃóì‚E#´7~[%Á\ÒÚ¤ Ø“6üzãö9ì`…õ¶|E¸Z梳òb`ð!š·cíó'ï”jÖÜBÉrÙÏɳեIÚ|ÈBt¨ó®-Ê`)ÁÒ´K¯”È!~jÒÎJÓ×&¥n-'iÄCÅÒ%½Køõ§æZˆ`Ãó©úyÿe‰wñ`8rØ Cú­ògìwXŸ—x$º,^R2gÌtО‡UÞ©­mœ© 1 xºÖmÜðÚ<€Þ_ÇÃ=ÜîÝ\¦Ž!mÏ>˜6œµ¢@¯þp^O€/†bí26æÜ3êñ´l;À²ÜÞV‚õtážz²°† ¿£ÿOó8Úú6œ[+´5ÅÙAÙ´ðTz£j£®IéËhg’kÔð‰‹´Ä}.œ”<^HI¯%%­†v…Ü/L–佨/WÅVÍØxã•FLûtÆtºnîÍïùÿ’§— ÅœI9èμh×X;·:q¸”3&÷ò aw¦Ñ9^køÄï7"?”é¸?·‰›@ÙÕY¬íFüìrd5Jß&g|UÃßËXvƒ†–‡Zƒ°â€v3+´ÒuµL!+\(^:¸ÐUæ¿H¿~7O'§­Ëöë®*G…Œ8Wk%¤¦ÔnÊh²õPd«š |9Cû0lv…Ä×äÀµå˜‚øEIê›/úJdÚäÇN ¸yƒ)qÁg°2•öÖº›Dëk€Ø”kÜ^bŒÖq9©œ9 j†J}a¬Ó‡-õ…ÃÚža Þ‡·ÑŸ¶·Fa :¿D’¼N_þŒÁ™?§hÝ1˜$‰ÕçÛí|¿Á‹æîSzU®¡Yì†ahM4Q¾Šç¿*.ûXŠ.œÅʱ¸½ÅÿåÛËQs K_þ›£>®Ž)¤h(¡_ÔaÜò´M1°ò -9…"U?´’ç†jþP­™×ë0¨o"_¼{ä©=SLËxëÓÜJ€éΆ§ìÖøñûgnº0á¡’](4æ.þÅó†ss±A0–!}ý½Ïi Îâ…‹§ˆDÖö8;àªkþ½¼¨—ÊO}¾ÁX¦`Â\R‡úoQ[®d,ç.KmE“……Úð/hß$C𤾸rm@Rò­©¾þóPE5 H,žû£U~ú\mÖb5çFÔõ>T!”á Tè!â‹øìÍ_ ßÙ›9!=7„żÈh]¤g„vñz†O(F­ÖÄr4E­j¨}õŠ_e°âŸ;“ðc®f†ÞsSxsÍÛ«Év{+BíØégj´‹l<£‰hec5©žHO´ª³qTÑúÄÙAµÍ¡5³èÅòx ÃظO?ÅuÀÏ@©ôÑ¿îIÇÊý"÷fjR1¼(úE?¼ÌTÙ3bVS ùËa§Á»¤-NmÍщa—"˜U…Q}«KcFb‡Qž¨oš¬K¥¿·¦Ã)† ÐÙSÛ’lÉÁuΟnWït’ì=s\¦ºÖ˜Ò¢¬Êk­`.Tü® 2°{»6íë!ÊžŠÅCç ’[²a6„Ræ@𣊹ª°·‹vŽ&&— ÄÛ5¹ôt±¡Ô}*šÑ¾þýŒ';ˆŒüWºÖ>Ê!3ã.­ÄQ3š1B!±Sw£³³$Öj't‰sŸÿß“EØÎŠ/z‹:5Á}}\FL G÷84݆¼È#…èv¢Ã‘.ÕÚã€${fˆ5¸‹<ÿÅ®a³Øî™ÔŒÒ[ºÞ[XÈôº¬äfèÉïDÓâ%ÊMÜår¥°ÍÇG榦DR7tå<÷®dKž«ò%è'ZŽMèç¿ÌØâ·‘h?Ípôp ÞÕâ–:Ô*Ô¤á¾ùò, <¹ÎɃßüÐîNƒ(w¨ü²é¾Û†u@îäÇœ~óž>w鵪 p´-“3ïÕÿŠºgFH´ü Gx·²¿ÙùÄ<»W«Ë_QÓo¾Õß,¯ §Ç¥qŸÁ#“?Hà K¨²MF¸3¹A)Ëvv 6³Êùy—øÚ"Aü/N6õ¶ÅdbVPBãýü™ÖÈ·ñ£ˆSÂ2õže¬Ì¡›ò—1ÍÓ‚œc¸®9P‡Âê|ޏ.œ ó¥£!Ôö3+„Œnr‚Ó®~—À‡Œ}ZÔÍ–»Yºf}ð¡G2”MÎNø#[gÄãL ÀÎdÙÓr!œ5¾¹ð¦òÒÎ@äê³F¿˜7åó9 öGâôKZ콡6`´y» hí5²›fV:汬àg]…ìÌL¿”x0|dµ-,ÂÁw Û xl»¨@½í¶:ûP¨/{SÓ/ÅÅ@XY³Eø÷3t$É4Ý››b' ð`¼Í¢_wÓfŠR“4vÉyô¤­ëw£˜Ú~m±.¢a½°‚»ª'{?¡gBÍÙ?4på6¿‹1^P]sã3×£ææž®_lr×Ê“Vrë,º»ÜÞDìÓ i!?ñ{ØÀ ƒs5|ýñrÄ|;õµ¬_7:Q¬­å‘ãÚnõ¼wÅ¥!" n@¤ë=Õ÷2¯ÐÞ€ ¢a)tþÊ„Œ /%N³ùœ4PÁi?®Ï¹ .*çŠ$÷Ð.¯.¶P¶áô_:ýe%1Ðç/}u?Èïžò¢c YÑÖ,è=¢ºícª¦5(6Z¨ðÿ†êq³Æü¡ÜoE ¦kÿ¸"ÎU•yÈè©øGã™K@­0c>±KÔÊìáqö‰8JRŸlm~m MGØ,y‘ÌËå¡ô¸ÿ6ñ•KßQ2ˆ6j*f,Ü ¹=“¹î.R‘[€!I-•[΄¬óÑê´:ÌýŸìy1nZZK1Ù©䉀o …4nÜG!ˆfjs¶©\]˳ À÷8ÍŒË V]S<æNÌ)¢W&›q’•X™ $Âqx(ÕG9Íù§‚[IìVU`ƒ¸'%ž ñå.¼ë'A§[óhR¥Ì»ÝwWX*']  ÷aÀ3™ÀýiIT®€i:_‹4w‡ æv©ï8Á·$£ø…¡Bm=£$ûn]êXšDÂ$Bœ^Àø4~ù¿u(ð#$«{öœ³~ø?«pÑΞA\í:%ÈüU¥ÃÇ>ëwž4È6%¦Y¦ù2éãQMʃÃÒ6ÝAã‚`E™j‡V†×¨·Y—=³Iìq§ìZ´­„”ü Ç¡ÇCü,SsÉÝßqÛø§¾Üž ¥*þ&k䟤Ÿ˜‡ŽŒa6'ñƒ]„ž6~VçQFÀ@Ÿ;^{¡dPcxïaxÊÔ•Fç B¼L ,ä=x6µMqÃa9õ0Ç^°•+€<Ÿ»ŸpÚÍàL¸ÝõF@ÞíìUš1Fk%9‘xñô¾^¥ßg¶ÿTäùŒ‡‚5Žó£oŸ³?µl«ðÔA™1šXÉö,¹½‹èc•¾ÕCP OLáÛKÚùe+F/ýy‡4uÀ±]¬e 'ÊLÿÅm¢àhööz¶*qH4âèÑ~¾x08“Ðt\O‡QZ7÷¸ñÐ7ñäѸãMã˜L³f ÒÏþšwÏqò»™V{0÷æÈþ6!Ärͺ™÷ AÀƒ¸e8ô‡»âA²8‚z[xâùL–«Ç¨6¹!´|@“.ýÉNM*ŽMØh˜€,AººÜú*d*Oe‹ÚÌ+xYœVÇ¡…ÉÃdÙ¶/[%o+*_B´ò¼P\€”ú,ÕV´žñÕîƒÙ«Yôäû[øo#{%T\ÊŸ›aô³piÔ¤+Ç'Œ`§#awú®V9Ô° òû6rAY‘#“?¹E€è³9dpÝP'ùÿ Spç:åî)pC i÷0Ów¥…T?ER‘ €›%6â ®Ïòº¦tyTð†Ò kB^eàôÐás%Ѐµ"Õ1à¨sÔÍ‹ñîºãrhÙoiâíìÕÙtê‹Íί0käðI¼X:`ËDà«kª._2—okDµ÷‰<¡ÙÜ´#ç«WMqÇ[Ð@¡pkNª‚7ÉjsŒVž.ˆ›mDóÖ&Áq¿ÄvFÍ\a}ѧº•FÃY(N¡&j:Q”2Wf"}Ÿî¬ØädâÔ€U¶‘’zš˜~Ið_{KèúD,b¬ß Ñ19Ù±”&Ý…ªb!—Q»'\z'åwÔ$ÀÞ_Ô´<…û‘)\(L¬D¹˜«£å‚ªËevºÚ®Dþh­g"žH?EÝ“ÍPrÂñÝxEïðKÆãý(ìXùêv‚3Òßõô9Èöæ œÞȆ]!Šr›1»hµ ùœ'ó×| I4àòcÌO#ûºþõ£‹G´Ë ±*„þuÜå[C=¶7wAù‚ÖRÐ}Ì4ÉH=,׿²ß)ýSÙt­µ¹·Œ-sì_ÚÌóOß'œ«©ö1<+0‹K¿£Þå²òuyzš=º18ÔQP&>™ž- ¯©¼xGÜÝ4J°©½ä<ò6 ·wÑ€ŽwŒ‚èþ ?};BåX…¦ðýŠ´OԄꡪÑzM5÷Žã *Hi%ã訖Þý¾}©•U¤$«wÃpõ^VÓ–Q¿t oÙyÛƒ Ì«f^¥M"³ýžFБÛ ,ô­ï@wžÑS/ð^uea:¦ü&G[›ÄõÈÛ²øËz‡Œ@£HIB·ã˜<úùH;FÊ‘Ø+`{C°/öÖ·QÛ.¦:ïæ8×jlëµ'Oò^›ëíËIOjˆ1²EL~ "5£†)¿¤šéЦÀ9…ÔJ…Ù)Øžl‚ÊÉù‹ŸsƒqÊj¸Á!$0èùçïö4vÜòŽ:à–}Ñ’Ó"Õ2+[Ûœ†ò-¶–$öǨ{eK^aP´WûDwñ\ÿ¨çŠnrO>/›¶·ú‘Z)’i³¦P1ÅIÆÈc­]œ9k¢asALºüÇUÝZÇÂl”ÒxŽäÔÃ’3y/ä­ï!™«š_¥ÖögB!g¹+ü0TÔX¥>·ž­W"†c¡kv©²¡J{¯c@­AAë=¤û¹Ô÷w-Îñyve;¤kä]ÃQ1 {‚Û„oªAß»Õ30u- „‰k€¿œ¬¤ëñÁIJ+$ÿ Ž0u[»™|6>舎Càd²ŽðBõ]¥m-S%fPCã9â GØ ÿ=XÁ!†2v X†áGZ5€&¶±MŒkÒ' k Ú? ½A!´1%‹m1æÝóuöº‹/…5‡œ죑Ïʬ0<GABëcžsñIï.â©­ Td$g}PuïrÔD£9Эߔú²…WêÝ5xJí’àžUiR$H™ô¢EFiUÕ&ˆ5U%×îóBpZh./‚àô&­t`48£Nag„ÇrqÂV…Hõ2˜}ovÓèЕw¤@Åž0»®ÆìÝ#’"Mdo]’ù\—V{¥Ã¢ÙN/ØÞqÖY”ÍŒ ¢e[Îeˆc á2U ŽCÉú(Î(cŠ“ÇÒÞGõ26Ú­PoL¬‚ƒ!ƒÖíY²Þ€Qñ¢Io¹jÿ¬u=\Ùp‘¦B¬8쵹枠[€H۽ꅚØyÍgBØÐI„BXTO:§6 }ÄE9ñ>êÔœÅF©öèfTºHæï³ rëK@PœÂ‡©óAfàd¬ï ÍVÇP1<Ü.{‰ÔÓˆ€˜/Oùma¢Ã3Ç|òRÛÓj•è³{³æÊ©Õf++õ˜#F â`êªãh6vJ즨åˆÉÖ)Õ1˜Ö!ŠÙ É!ð ˜{S d¨ÉÎK)yÈJÔ¡«æùÓAܸ“ô¨Ýg4 ‰cøy¯Øíå_^µ6U|$%6´*9Ïݹ['Ò­VO3Ch£_Òʧšd(wE$*óD” þñµ!w@Ðõ쮃/BG)sÆŒ*}!ècüš–'k¿qýàÊÝ]õ¥9è[Tòù΢•@ŒúwÈYTDx1\ž§¡‹ÖÔè ;ªÅβº8ÏU°èÎŒC3ão€&du‚‡‹QúV²íÞê~ÂŒº‰Ô =m‚¡YA°Yjí¨Au4pd>pÑ™ŽÄŸ–Ò÷™Í¨ rõšM_wÛÌ÷‹ ÇÈ9²Ÿs0Œþ¿Ã žÜ ²Ä3]}´ëEè|(xðï#®_Üûcýá×i¿ýØS‚-ú‰Gô×ë&LÁ†OÄŠøôã{V" w É‘=Àƒ1,ðTTH–?Kási¹ÑB\øXyþ»÷‘…ù‡½_ý\ÖÇdÄg¢š¹õý_‹y>ºØ¯ªLk ß°8õ#/Bº»õž[õ¸Î€VXÄ­‰+®ÌÞRtÛ)Éß*!  µ ýZ9èvq×çk¢£Í¶ÓN›*߿©›ÆÎc­ФÈ#†`a;_o ¹úİÈtç‡ÍgºC§ÃÃËlkµ%±µ–TîÊ5ÎÚ øAâoÌ2.q4uÑÕliBáq¶Ü8"Lµ$âδ¡M„»ñ"©œÅTÞ™…j\9µçÉà®^<’:‰Ü3 ãŸB-¢ú|¼¤œP Ý%j_UvG¸¼Gô(;øpC:~>ïx•¯|ÈU¹³ s¡+¦¸²à•5åÞÕ­Þ9•Ÿ[{Š @0Kð&å™=oÞ¶aÀWº ë~à’§­Æ7ä¬é Rðt}â‡×–¸»Ió©–»Œõ¿D Æ>¿hTãú¯Í;¦EÌ’yž¸JÑ~Jh>¸¬ÐØ\Õxä‰ÕŸöZšP—dn©&ÎæÊØÞ2Œš]¿Î5婆÷¤òXs¥J|œƒ{¸‰ð€^/TRÖ‡3V€^áƒ:`Í=Wøév»RT†)$hýŸ’cmÃרEÇ1£w9t½cƒ¼ã`« zŠð´¬7‹;2Á^휋ë_†ÿcYž¥™øŠÆŽŽæ"ºGtš¨·ï¼Ú—›¼HÙ©¼U_ï ñ„£ã½š¤•DËÉ^3öf«Xdr˜áÖ…Üùıw¾ÑBtÒj¤äÝZ8sx¹d kñ7»Ç2Š4Ðs§K}5T¬û»-Aù(õÙÒG+®!îî±ú‚r²OfÇewðÎ$mt¡Û’$’:Ïk•`ídî½¢ÀjtI$jqyH ½lš¹Mÿpºö²Ì8˜$‚¿E› ®[ Ÿ=‡qÐz¦q·ÃõÌ–hR —–²Ó‰l8ÄÔ´S]ð`¡Oãã°þü±PÝÑ›îK°S¬@(fÆ u0‰"QPc¸,: •©›¶9A^à  Ùî±h¡ÃÔUÜLãê1# `’–ó…þ€˜ïô^i¬Ô;Cn°"õOáHg“1ð*4%/ªZV¯ˆxÉájÅn 0Å5l“&ë£ÕÜ¢¸Ý»<^˜#[–eëdhw‡ÀϺ̜F î¼)úBWP×ôæ¶ìN’m¹½|¿Ü@3Qh6yI±7Mç1Îô­A)Q‡³+„ükGeÿ\x˜ø¢3böù"ønÇúÁ?cx¢!ñè¦L¢}ÿc¨Üþú¶tô×¹È×rz©ø›Þ[4®a€‡7ec,eйõÒûœ»Äô$˜O S67§µyÑcƒè[Gz:Д"j: Ì ‹U 8W:äí¿t3Í6@J#8³C0õáÍæMl×€Jåzâ]Dü[þx3'JZ<–,ö̮Ӷ"ˆÜpú¤šNU‹×GÕDsMÔÔȱ²ª· y»oÔê SBW…œ·§šB#´h~&hœCž’¤âxÚ÷žYöȘÑ`jR;wÁÀwC‰¼«ž%ö™¸—Z(E¨Rõmüí>J›^>K$VøØ$cƒ¼Õ.¤ðp‡Õc8Ñ’¾îœUÉS nŒc ˜äSfí8£Ná^PÅÃqŽÿáØVÄT‘Ìô¥ÃgFx™Öm° q†5gŠZ`Öþš#„¿¹:yUuH³sp¾ñ9€Â-äAVïÝgÁŽÒEÚòç©ß¦ý̳»¬³SÜÜút+#*f~Cy`úäIZEbÂóM„ÄãbP{{´¼5Õ Ò£ç [$”ÌÛÓY>Zmšï%øËdÜ!}a%{ðž\ ¹/ŒY…Õ`>TwîëÜíÞê?¡¤ºåЂß{½OÙ3®ÉšE§Ô±Þ:°¨ú°DÄ1o_$‘¸#Ïá€Û=ç\°ƒõçÏç°â*w·ïãC(ˆÂ#}T^ùó±î(bXcʇwE º6·bIéÂrásmVoLŸí­üx ]  µ4RôÆž¤w˜q~Û`ÞáARî¢ÿµ„_@}-¡Òˆs,~áQøïæsð¬ÑÍðf3Æ\3™Q—-&$GJ%Ïõ…í±é#GOã I„ožÚåñ e…ÔËh££„ääÿM)¸âGR¼!¡›Œ€% ª©Ö•·xú@£?ïŸ"Sä_¼jM²hŽ’ˆ…|¥ÕÕñÆœp,>ËØ] /ÎQ·˜YX˜²|Õr›ŒaFB{#br..z( §N¥àÚ«þ© iÇÐÙ«ö³?!iªM0Y'ƒð#®“Ai)Ì47iµˆß)Wb…ÑuTýu ¥v“PË‹º[ÃÄ*¬ÀÂÏ(È(˜GX´vø7Ï;îa~à•´\)ð^B Ž–&@éthW…SMñ§Uö•c¢w2û¥Ž14¨}¶È|Õí¢“nðß$CT€,™Ûù÷v.ŒŽàJy[¶$ª‘¼¹Óژи°ßáÇ,î¾×አĖ_¬Yr¢YGð1«þ@†W9vëÐ`ÿV±°nÉ}žäîpМÈ‹mÀ÷")/L„ˆã‚Š#¸tOÕ47tÉË:yýIr†Ó™ÕfIk¾ÕyP†Ü)*>¹cò|¯Kûé2eÅR‰S÷³Uö½v_·„'wˆvšR†ä«Ì3ïõ°§jsöíÏM÷âU¦[ WŸÛ7gÅi» œP¼™ùLóÏÀðæß…ã¡íºÛ+'ù¡Û¥Ó#s|ytôöö=Ÿò¿Rp±Llóï°ù§4O‰Ýˆ„—- }PPõTŒS¬!¥ ;ç“‘¨»Àˆã^ K‰9;-ŠÒbH€¿vı†¡…YAN1#>B¾2x+êŠùz×&1¾=V¹½c#“þ[jÍêzà|æxž=<–#-·(mk+t_å–bŽ„‚äÖ¶V(Q“ Ãi }(íœÊW%@‡]#–w Jï/yËRÍøOdèxhqºø6ÿÇ5±@ó¾ê…Þ5׿¢ãÄŸ¬õÃ÷_(8ô‘Z¿¡·fYgܽ¼ °·Ú[ò®ÏÝ0“·í6~¼í!dñI¡¶Š³ùvºqI?1Û +lš––µ6‚œ@›.lجe›|>îÓ"ð·Â)šÁµà'f#:kÁ)$Tþ1ÓóÑÖÍ’ × ­c*³—’ªdµŸ¡éƒ“^š# øîÃ0o%‰bÞ¹Oe¥üøý—$,·Ž++þëÜŽ{xQ0ðd]$Œ©·›~ç̲3 |]íR]Püú©Ê -Rœ{d-¼au(Yð–MXØÏ©¹’'̪À^é QéE‡¤Úbi1çë÷ ÿ`Um>«/ÂÀMÅŰöEYl§.»æÎ:¡"Œáþq6£Ðo|mj/óT¦ÞórŽÔ X£ˆ/σü1ÿÃ⨬þÏ£ µ½¨ÞƒÄvQºÙʋƵ³%;°¥êT„|½ Nû•ÚFfB\<‘)œóHÃÞel‹W‹œ'mlœ¥šd|<ûGÊͤ܆ÆÅO_$”ÇË(?dVßûè°Çï7ï[%ãCqaGW¢$ÃŽ±N”¨ÌÝ:JùBþ:­ZÕGzæÖLJØž%Vá°Ùf¸}|ã_Ò9¾K‹±¼-ØMÄB€äAÃÞñã‘T‰w1‰Ì¿~û÷¥Ø%ý^]RsÙ³Sýyii9¤¿Q¿Sä"A˜BCÀÊØœuõ`åÞÐè0½lˆØ·ä?u/ÃêW¨,Ç€ÿÇÍæ-lH&Ô±<Š#ßy °ópG´®œôdz54|%/EŽXîŠ ?|ŽjÌ Û(ÂFÀ>·"¨„Tñ,WÍçÍÞqçH²êÀBÛ¦n2YwÄÆ¨'˜#*ŠƒPüøŠ&ANš£WŽã?3=½~8å…Í’D]Ï?ß7ÇRk´A³S?¯MÖG9º«(ðÍwgb“£ØùìwTPÏla0ù4è}ù¨"„a*ˆ€> ‹Ýöøµ›NN­H&Œ»™$¥V¼c¬²‰OS–Ôt‹²ø–Á VÖ¨ƒVZcíÊI³KTˆLböRĬí þ|vŠkð)ª»Oœï=TwÅjH‚¤QbÛ:–³rð ` Ç1b¡§Þ8 'zšÄ~ËÍ:¸pó8ÄÄd‘˜œDžù»ü‘­ŸÈ@u%óÁàíê|ÿÇ‚Y'é-/`?ë/•=ŽgvŽ]½Õ¦ÙJ#‚«Ó¹î‡Ö/â¬öÿ){—d½&%e’Ž ·Ó˜4Ïû¾„͇»`ã8ÙιV yÊ Å?L€ò܇‡lû4ÀW4§HЋ%_–b?WÍ ÅšŽÙšCƒ=ã˜×·çǯ5}‹öû<Ç;E+°ç¦,>;ÑzfÎ`•füRŸÁ[^Òq hž*½Êؤj«L•Ñk߯mò‹Eï®w$<;Ûc㤣’pÎ‘Ðø@Fðiˆ:…'Z'ŽHÇ`ž2ñœ›ó¸Ç%ö8¬­ ¸µyñ÷ÖÖw¿–‹ãùúpdÂìZZÌ€¶°´t«©1õ_p¿ëÛµô£FUÛﯱ·e ;VÕ ]u¾Gg+—£m{@->ôM6ø.×T[õÝ+£ §º‹ì©‘`"ø\ŹzÊEïikÂýæŒãÞöÉ<ÄÍçrêœÙµ š1Ž«=’NÖàLWJ·|aÞàb#8è ä%²ÄÞ”-¥wÄžÙ¢  Áâw”Á¾³âîâ*öÜ@zÂtzÁ/cDO纳•íœÎšèi„~ìpÎ_P´›²ÆÕÒ¸GÜ£æmþÇ¿I™l—3&&vðÕ™Ñ6œZû> SU <#Æ}r/M~ú=vÛ^ssõ´ÒÒkx¾r/˜­£\Ç&“Ý¥“ã}O:Iº¯õ+ü; ̧œÙàw¤¡A<èˆÆ¢ÜÎÁ•ʹ¨3xxY˜’+Uf8£2&T|ÝÊF-¤Þ¤b¨ÞO!\ày÷%%­Ê8U¦0V?œ®>IXý¯!z +eIˆ:@6¥j:ѲYüeÁ täGñÙÞJudÐXZÒaÈ%ÿ;­)”ë¤ÿ tÜãÖ ë_‚ 2„PkcàûÊú›#éj7N}Ûëˆ|n+Åæ»åïG’AN¿w»4Ï‚„»‰Žp¢]¥VàãHc‚cˆbqÈÛ¬ÑZÙpõ<‡¢¼}öl‹Sî¸ O*Ü9ß6ò¢¿ØLÉõ­üF3YI&%Ääõo?[»”;…jªY*u£¦E½¹Á3ë±)>þ{©XßÎso™ÊQ/ÂÌ ŠÎýø¨’ÕŽK¹þ€}N„•e߸¿WaļPâ­òIo(#"8J¯u{þ³>Þ¶ã“–ë1e°Õ„ñ[ðª&³ç£û\«&އGlCŽÍ°®íU/Ç‹y)‚¢'̱t¥®~¦ÔM\ØI›I-lfŠÙóyˆw ªN#䦛èNŒ‹ˆFJ!vIz9­Ûž¼yž²–Ô0öS×}í ¸[Vw”ðàET\óXx+;[õ\ä[v9e è㥷‚T°Ýް²ý¡{ øÚˆ‚ÖrOQÎUò Þkd(°¢-÷Þ =ÿÐZBk¯º‡;‡rç¾±wŸ&ÜXâxPu™ÖHÉSšœV¸çƒUѲ³·v'þÚjfç’€wÆÓ2ÒùÏŒw”Æâ)uÀ¹#D0YGb|úE1ùòúöM$ ædkæÓL79);[/~¶r8ë£Q@¦á`¡z'eD.*ÑÂjgc MßГì>24¯ L^ø^«¤ ¨ídš„B®…‹e£ÉeÛhO£>™¼æ%ìCí«[”³›­7¬] šì’¶ÍÈý±&y¯”8 @9½Ê·Xùž ¡ñ{3˜¸âWûâU /°Ç·NŒ-?÷E”B­Lšr`ŸÂŠo Ó˜?b­E/Â*zoÉÁû»køö™n1»½.Ü+². _êRðˆÔ‘ãi¹/ìëp©årƒ±dJ:3~+™Á¹löÈq*-ÓìdvÜ€|D‹FÏ÷êÔî›k,!P¥IÈêéøðÔn¤Oáê{™Ê9ôy&â!q‰wáºpo8aéÄOÕè±SŠãƒG£Ï 8Q›P`FU¯¼8& 4-ሠÝIÉ* hÔÖvh¥?µO«Í­l5ÎåcTbæÝOÌc»ëk†MoOU¦QÞ÷ƒ-Ó¥¡ð§üùŠê†H½-æÊq=%È/ŽW >–âP¸_a[¸¯3ÁUr$Ðw4àñH»Æ‡@ÇLþXÃÖz•V(FÈ÷,C8†?ˆKÓ@·ôͶRùt!Ïëã ¨˜vŽðX]ãSìâ[Bå4p-ùõ³ÊEÙÎòJ‹ôï0@H~tb‹Í.¨´<âkÆãÖËô4ëâB4˜ép9=t³áE{”±m¨f} c¨nÈp«4嵎X÷Ïüf&¡\ê˰Ø/úïâl|£F0`¡7–Ù`3ý¢ ØMÓ‰ ¹@è﮾(e®zrÁ_ #¸ÕÛ\[.èíLÉ¡ìÝ·Æã¼âh¤ž"ûŽ˜UAI Q町éP™Ö¶H‚LwÍIÇ‘?¸É£,]®ô»ˆÚí!xo~´›n ´°o¥V¯Ñµí?_¾Ätìø;ûÉÒàn±¤WêÑ#UŠBwÍV¬3 ÑqãÜSœD%¯—u6Ù©üæiIéöqH©.šÎÇúxÂiˆcïáªQ-õ w²Ú½ï)Wcá³ì&a\:6^†óŠŽeáH¡pj=òù‹ÈÃ&QÜša²º<Ž/Ù¡fÀËDÀ2ïáîØ½¸r59k öüŠ¡ £Õév4øb ¾×#ªÁj¾,^Sd«ç÷3ù°˜s1šÊP¶Ö17T‚C͇êùY‚{@!»ä!‚-8¬Ôú½´ôÁ|j¡p+À +ªÂb–§úؼt²;ü»?$F¼$ Ylž 8­ùÛŒtbÁ6Uóì1Ëv¦[æ@IB‡fÃDAâõ<½¡À…²SEãç"Órë xáoæö¾êü}Ýþå=Tî›Òv/µdLBȺ1B.lüù|E²ß?’ï«mÌ )·b!&Q¨ƒhëHõÉAß<$ŠŸ%ÁLZ%ûŸûÂÔµ–’…‹$ ñ^“ö÷†ÿv:IòËõ¾¿F4Ú·Á÷…NΞÜSRå(!eä&bi~€4µÊ^£L€4²VØŠýõüÁmÙ>øTý>„ ú-R˜X‰ƒ³Û@<žš@àíõœßUøœ?øOu-Úµué]ìÓAÃøÒk’ 1Yj…WIJÀã|½y½`²Ø¼ë:pÀ{K½£ré‡'z˜åtLKx[áLÇaWÚoã¥÷î³bW ß0$ola£e’Ái&5Ùu6ñW¿TÚSÌOÇÃhÑ£½ÑTîˆm¹á °(Á–$K¯4 hj%ývÀ¶qY§%“VÊÐ*’Òp-©ÅãÚØ¯\@Ø øRÛ:èstڈЗAÒÄ.ð,¨ÄÿûaÖ®À î(BXh.­‘O Îíî0!b=¿U¤ä³ZžI ’É×ãR“U yÎL6Ú•@r¬´Ž©¿M‹­|‚£jVB¬ äí«A«¡©à©Á¤‹‚KLÖx¥°¥îDÛ¶xü§º%¢ †H·Œ¾–©¶,²üV.§Šs%Ë$–î© NVù®>·_ ÙåüÞ²`â?½ëÇú¹­Êhøf%œÝþÜ,ž.t;Z¤;<÷é€uÜß—C—*_#rØ%SÓóU|é†VG¨7¢Ÿ™üuYÖÐÑo ÁÒþÉ–ô(ìçáK]è ‹,Ñøõ&Hb‘&•ŠÍ>êz,ßµ$¨´w qO• å*Q|Æ¿ y™±Ò׆4L€sIºe°»žH{nòUÎ2SÁëIX)uÝ=Á —ÕjNàûQo°í5ä£È9ס·35JKuðšì×ùÓ†W˜ÓÉ_*³¾GFe)¨Ë³‘—Ïs3ÇÙç`|ãXpJß"4êíÓ}p†?keëCE¡ë5ä3ô3ê¬âèp îÿš*Àb±(q¥Þ¬WˆzÅÚ3¿t¦×¨Hª´9,Þß´oÏ }¾2dgð]A¡|8”Àñ.òojZ¥°,Æúpn È:_iè}(I~Û,ƬlÁò¥Ñú—£¦•i†*< ;ûÌœÑ=›VÊ—FõsÔûÜ¢¾€ü)à‡G1¼ÂˆæŒ V*`hûó?ø¦¶`Œ(Ë€»µ¯Ï³°T3AÑy<‚É?Õ½’·àŸ£mbOApLè#€AªhÂúÓ f¢[‰|á´F°ù å/Sý õléI?mW¸$’1;ò™ á?oòRîš×°àØ,¡ÝJüÒe´yC¬Î–ÎjpÄO‡¿%ªfKáÇ[¼¼ ‘ðõ1Ð ‰•õš¶T#k_`"XW˜½Þ-G‘œSè3´–ôF®ÄCú4ðI™O[J4†Õ\Žû95¹æ]:Y“Ê7ù—÷† Ôý³¨ë”¨G¡ªw?o©Ò˜¾úãnĈ€ø^uߘ‰µÓÄ«pÂÊðzl%Úµ­®~9ŒÑ‚E½ì©Ì_ù“¤w~ ‹ŠHµÔÚǪÔg€@4áVólj'pC`ò,™9Zhj¦ˆfõ¿¥¬]ˆÆòïI\XZRug„0¿¬ÍOg—"áTÔt» x±â%£VWЀÐð`™½˜ cÆ6yÕ³Ì8Ÿ ƒ’íØRo(¹)w/¬íç´Whç¾”ßd`ð9®¡™‘§¿T¡¦ú ÙÖ‚(ø”ú¿¬ˆÀÛt²®X:af,/æ Çi0 _é·…-ü[¦ë®%VÞyÖKH—ÅÕè Yjdª_E™öÐ=é¡aúƒŠáÄÙ;Èž B¬>»ü’Ñûl_51/Ø1¤•ÒWOÌggÚËm,²‡ %3Øeç…«¼;':Ù úl_8Êg“¯•V†š ¡ÁÕ¢¿I»¬Ü§½˜õX“‚™mÝÂUKð6ÚÚL*…bDc¨ÂJüa.ÜzGÊáƒ\sÆhÚÇ1"K‘²¬˜Xµ/¶6ÿ:²"q@à¯&ôBNáíl É_kÙ«9Æ8‘#2þP(‡ÐN~ݬ,©ó[ O’®qïH‚†;rYŽ Ä§cø¬î6XñÙὫ­®òÈ …’E4Óæ”×ãÊ5Ê3)D3mbØái·Jªyþ…J³€k<´T.œ»SX¹ÀØúà½^gZ u¬mé1tm³‰‚î<‘cûl`ôbu›BúŸ¥ L7Îq­vÒz*lÉN£;j ¸¬8Ã;³ÇàW£Y|s¬¨x;ÍÉÁ{æ×Vu'¨oô¤Ö˜+Ñ AªóŽˆ~Áˆ_ €‹ŠÅ·“•Ó»HÝynêM ÇåxBŒ} íX›ÂrhnRä—RÑšª0bH¶hÍ`8lƒ%ýîCn£ˆŽ»SBÞHEwŽPJtý—s09þÒFùâ¡k·d(.ÐêÜBÆìƒ¨k°bþ6Y>CE~3Fó’üP:s¸Û¥}¤Ð 'k.ÁÝõBÓâê›bfŸM“=þÌ<Éëáÿò©è{„Þ‚oŠc”кha®àƒ¦½rn[ÇŒcU£º:™²êÞú†ö®€sª±ï-ÆU•ißbÊÜm0Ö}$©±”:c:<ó‹ÎÆ,üÁÅýš,;åÅÉ¥³½Ý© FlKýHŸ·'lî÷×äcvç>,Fž‰røû9„ä@ö|Pƒü¯wwònQõK”«†?Ôüp}éæw„Uæ€AbÌ“ÏBjÔ©íFFrªpÔè£,XÝýœ| WÉÝÝ‹å)ÃÍ-x„L(ˆÖ¥ÃRIHŠ©¡×¨–Ð]Dÿ_Ëd¶!…o³hB6t”~!36]a€J}óNñqAéKõ<Ìuj¦Z.ûvV÷JÏy*9fÇÿ‹X¤WÊQ'/D«2|½£é4ÄÊRÁO–=™EÌ8&æ_‘VQÿE ï¥Ô¤ÖÒQ‘Í‘õÆÈRÊç¢;s„ý^xåM2P}]YKØi±éé5rÈ*\jw˜ºbxû zNÔÚ¶Ø)ºa-¤Ñ…ý´N@MØÆë­dÂu]ç<˜Yl[¼ÁHÝ»8™q‡•ª›…¦Óyã[f¥zÖ"Cí>xÈn Çç°þg9GÀ—wcï—–$kŒ‹™š!ù,9H#s“òd¯H¢}«\ç1ž46-´Ð)Þ¥¤0ƒcÁ¦¬‚g‹™¬;`ޝB³’«Ì“õ Vð þ›H~.äÃ9¾.=}©/c-hF\æ=JLŽZåªQw®‹gçü3í"Suü‰ì“âèÑ+*³Ø tÌzÃÚAxqÇÂV€!ÏftÔi§¶öO#>³´Ž»øêFèBƒ  ä«Ý5’î®›ËÒLôï;ÏL°oCÜÓôU£\ˆ-[¦GðÒd¢$6cPlÚ$vŽp˜Êš¢t¹Â4™L;äþ“) âua)_³X/w ¥5BÆ^²•¿ ºD‹¾ÛöÁX¸yt3åH¾ÇÞ“ßL&,…ë¨W/ˆùpݾ€×àdawÚ(4@^p6IMý»Ÿ¥ôݲGâˆàœ¯¨§û‚ úˆgJMiÏøß‰ô»Y,Í1šÁ¿¨î[5Å]J¯LMÇc˜ªpŸ>õ&4Fïc1áX±tWUíIò8¡p£ƒ«~Òý%ß)LÓò¶²Ùi SÄÿû@毪°9íÌå«çƒ.‡™`ZÑvpͦáF`™²Þ+¥„"J¶¤®Þ«ïÙdƶZ+­ì£aƒç îÕÉkº*W‚5&’8@[­Ø HC_ÐæïWySßáXòÜ&}Z!ÙíÕKüÒã…„é¨ Zu¨à÷dï;jmòìvÒ£ úŸöÿM£©ó­DžÞY£*Ô Ô~J1jH½Ñ«[•D üó~?¶˜a­æY’²$ï,`‚Hªëñš(~¶]iV`9àîV¾ ˜‡Zì †CäØÎðqÂþW ®5³BM÷ãk¹€¦¸E€ð”cüsÆì¬IM{I-6 £§,K § )híT›]$¸õyÕ±"•‡-¨‡x¡ ß%Îj¦¿,UßÒK‘\ÕÐEú׿åÓa(4 1ÿe?¼AÌfõ¹ºbë$YüŸ óo×faN€ƒ¿§³¶X+ë·Ç ñÜ"þqÌ#ý –¦\ f¹â\Y„¬,iíWÐRHßçS¡ÞñÉ$:=­©¸L²0bŠ…é+i*0ú\Ö„|pgé-µÖ¼²;Â[Œå[ÊONèÂ(‘*ÃóôîÉ¡áä_Éq…, ;¦×ä„eÛm!ü˜¤L;o-¾OI¶=ÆðãƒK¡zðyS†Öž£ì¾‹Ú¥ƒ€»³|´y Kw÷’R\,Zhà5³ý:Ù3ÿG{ÖÍç^¨ÈÚŽÇÙán¶/8纫MžZqöÇ g«'Hêø0ìäGùpäŸ,“ÚÝh¨å³;ÑNùGz¯–Ô;3 "¡èåyhIzª±°iìgH— óívèîsÐ m@§1Õc›±ˆð|ZNÑXZð×í"³•øØã3Š#)„(O¬83mÜD ¹îëï;ô¿Öç A ÿC0ëq®[–Øù†Ë7}ös2!ì.øáhkbdùo"ƳŸ!BŒ·Qµ.räŒßBq…È¢'½¬Co) ]궬SÏ:ÓÄ$ á"‡Nõ¼ÁãõÑ`õ¼†ft°ùмÜOñl§é› Ù ß²EHM‡àÿhÆ‚‡Ì§÷ð bå'¸DŠb., 4aÕLWÝ’°l#{Ë W?^õYåÿžXè8˜@ÃªŽ£v(#/9Uà¶>Sáß0K!7¤á;Ý(V@;KÔ­QŽyæ|$Àܾ£ù«8»+{*;ØSi~ûéžTRfX;iÁdö¸º)FÜ\pòSŒÀ¼—›¤uɽ»ç’-ŽW¼“›w>^Äoô·ÕSløàºÉj‡Ò(Óñ¢8Bt7 »©÷§xÁèKè¤9N{Çq*$I«õá¼'±·§á;ëj†L6’LC࣒”‰wp%e9W8lŠyÉdá=ÙÁàúæ°•³n ­£gvο“ÞZš]Ý%‡D E¯­á(ƒÏ®2ã8O»3 ž²CÝ•ŒS$w/Ý—j… [£ôš,£ZÿôkåÈ.»zƒY¯#ní®‡ÉæsoQ`סT¢žl4ƒ 2-ÙÀÙ‘a`4&²ÑZ©Gåòóî¿¿F$|{2©,˜žŠò-èÑõVtJâ$iÝdBaí7ë›ýÏëb,è '¼9²’b‚ë ´GÒúù×*êÖtOš’ß”V¨Wý·tÂ¥¬äÌt,—÷æ«a\S ]àËIÅ  ôqþ”ºx<œ÷@¡cdܤÒ¸Õ0›ÙõQ‹âˆÌlëtC˜’¶ú3íPÕæµÚËžqŰ­ã‘ï ®ã—¨£ÐÕ¯Ø ƒ»[þ#òþÛº.Vl‰Ÿ#Ç´LõF]¨Wd]Þ¬Äþ…Š‰â‰µðvÂíYŽ¢Õ³P…öèq{QÇѓb¢2ŽèÕÏa+šÎ]+Œ„Y†:½¥IröŒ!õ¯0Óç# à4åÜw™ÕÏ_Ø+ÍêïÒÒµ8rT õ ®] bU"Ê2Ôþʶ¸âvˆ KÆ^b$è)—]—µGvÄm=÷:Á¥—’?7Àð9åLœ›ˆ!0Â!É•sÒuÙ¯zm‹ãàíÔ=†€ä•}¦ÔÑÔI'­þæ‡3ó*‹eãTK%ÞgÛûÙ·‰À²E­¾}±ŒÉd¢ê.òÀ„Gaèa" Ú<ÌbÔ)jš»‘V60'Bäà w™±Q.Ï·ßÖdg| 1e‹÷´@9[£™ÖÖy~ëÁ^QªˆEŸàVkz¶ÖðT”)—XýÅuXf{ZsQÕ gai`ýƒ,ª42Ìýíµ ÂBð“ƒDÞ±fP©¹OLf1ëŠüªa»ýUJÃËM‰Ô„ ï|ŠÓ*däxw¿º¹†-ìé v˜-+å²±NƒklnFFO†ÑÁù¢P~e= ïÃηp¤ZpÉàcÖ$ìÑóêrG¨Áwš}„Ù!ÅdÑ"L;c*—x»Cµ|€@GOåssd}aU5Êç1¼ŽÔ§ +b1Ë@G(%KP—Õô޽á?ˆÖ!š!©–HkøüôCtœ]Ð>t‹C꺘ÌÌX¨ÝÖôÏ¿¦è×CQ#! |@Ðñ®˜£úf5ë­O|ð•¼X%Qu‚ %·Ò7o)Ï (m: Ùq‘Ô…DHŸë ÷éÇùSñ tÜÒ­þÐ’¼‘ºñ ]MEW­p‚.X°ÝÉÛ?ÚÎÈ<‚ý7÷.ß–ñm”‘ˆ6$)ÔsØtçÝ”;U/ð>g64;*|:u:¤ã%wä!_”Îa¥‘w6tdÄ£¼cÏuàÁ_õücà‘r$¢àdb„eí›ÿeìÅÚ ,Hº{]S’›±~]VÏ ¹'xüFÂý§†ëÌ0!Uß<> ay‘yL®ê Ý¥8'k¥ áìMîÐh‹Õ§Ÿš#ZÄàoF8ò\mp‰7̲½ÀÃvTíXÚÇÁÆê~z©HÙëáæ3ƒ¯ìý€Å;2óV2lox¤THJwûc’»ç§ñ]VÚ!wc%yÏ+«3{é®ýq9n3B\¿²9r·2œFùå2î l'µ†ý-ðùøÌiBgvU‚”'ºx]ÓÁqáÂð)r3Lôx <üÞs@´*rÌ;Œb°‡oQê~LºùûŒ~ÜÿZ˜iC·ó¯×F,fÕU`|k§b`ø‹´];ØôÈ?}FoÍXiWoÑÆÆÊ>„ÓÇM…‚´p¸“¡>û\2³•ºÈ@70çAÁ AÞñÔD@د+Ù 2eä1ž¡¥SwCêÊùª~æß=ÃÀ–¼‘ÝÏT®¢~±Ï·œ¡FD‹1Aû,¢ÐX_å»f BeŸìà‰k·2Û÷?ëúªp\«ä1±Í@[+ViŒ×bûGÕ·_±ã'ÞñgÁ:Ó@«((Û`b:ëNî‰å¢0)¯Ô}uU˜cK¢%ò†-ëpÞú÷g eý†ãs…³sBê˹<å=ãûÖz²BÖm‹c_îSI¾Š{ùÙÁ†w.•E±$C>âár±Ø[³J ¥Üh×kkâÅÌhÅæ+‹ ÇÉÞa Þ|MHbʇ\ÜוN䆃IµZm„ù5àÔ¸¬£üv¦ªï~2«ï>V²Š%8i¤0ýŸö )ñSÍËiG‰Ç€f;¾`ωržÓ|EMÔoߎžÜ«`<éW¶A)QÑɉAŒ¥Á '$Z\V:¾;çó.yñÖ«¥ÊùúŸfõŒÌ6 f@I¸/e `—¾ížv«à@7HágD8îÅꉩ¦Ùïµ"xhšœN6Øq“”m¦ÓRbxîöÅÅ«b“[¥‡†Þ1b:BÖ¶ŽFBö«y”jñX1r5¸“Î Ü]…¤Æ[.lñ­š6‹´aÍÎáZ´åJ×T[F‰ï¦z¶5| ¼Nî·xW:oÔ¾Ú1fÜ_ê%Õ­³Iþ"õmݘ­ÛR~Õ ×¨ðxF:åeì`O¦dd¸Ý©]ðæ]c3~˜ =ÓhÝìÃm ·ƒÍòÿ”òneÙsŸìU”â§!àÁÿÈ®Ïe0|¦,õsߪÅîø8pW ÓžùŠËÑkkæ/T>¶«AÚ‹~22ò÷]Ì‹’¼ÜTΙIJµ± ¢O»;xÉ”9OGÚ/É5ë³tQ©¡ß·¡µI–Mº–¤Óuý¼àæqˆì*Å¿R]M» ¶‚ª9`‚v¾ÍÅ9^Û¶£M÷Ì%ÆzÙ J,ÌçñKµþH­¢P+“6cú>ܸ¥Sô`L‡þjíø›®!ÂùÛ}tß9ÉJ°ÂÝvöbuÎÛ¤²l ¨ŒÑ€ÿ @+ ã\ .”¨?'Tï.õÆ•5ÌP·ÝÄ¿V¶«¯È9RÃ'ÕBŒI™Ø¿!êÐ Äᇖû¤­øÝA*'î‘Qüê@ U"ÉËÌvï&´\¬f]MËÉCÝ(nÈü#é÷¯£ âØ´°¬oÑã™ÉRcñaàI sîáä´k§µǣؠýüC8´:0v³ðí?ú€ã§×™$Ge°M¯gÝ•vÀž œ|ûFoHÈ”ŠéfG­’9ew R¢;8>5)¢µç³Ó”Uß$aIÄ´Z–º•v>[ˆ  F|yØ&ï;š§âNrQG´AsUû1›ý®Ÿ½ööU-ƒü¹m1Åù )ð„¢ºr2)!z¦ô'T·¥1nûUìL Ï ømtT6Ýa+ m?s„«²Lä5&êH³g^©â§€ÙokþÞt_¼=êÈ8'ƒákàlŸ© ö‰I ¡­ŽvmÕxqegºkeN<¢Ù16Þ•¸Ú­ÏÌ41× `º¹}ЛŸÊjmœ­óÖkx®©Wâ 1bØ nÑ.NÀ­G§òe¤6²§ZñLªržû¦S“ìºïâ<èëèâË’l¸î °·Úø^3a;`Þ°qi3ÑF¿ÚK_¢«ÉA¨ÇNƮŸ1“GÌÉd™F”âc-ÇÆzÉC|r¬ÐÁïy”‹ÖÒX£ô^÷™œÖ8¨¿ẄN/ÁsƒL»«ÍÃÈü#væ?pfó‹Ük¤×oq¶6pº=öE%fŠ—åtèxdH ?¬´ÿtÙ[ôø§EÕk  à Jkâ ÌÎµÕæl»Í}¦Ú˜ƒr‚mâ(Ã~·=~¢+öDIºðÅûÁ±˜>;.aŠr¿LÕã__K¤ˆîVÞš83È?ö¦}Œ›®¼x`ßâÑCz$.N‡˜ô4¿´ sj„øÂnyCflñt¶ãÌÇç'êÂ_½8‚qF„80'%Á{CM ã väpëÙzü"]ºëeåo÷¸DˆÆ–£öŠ2ü°Ã*it£÷lç*˜Fr8Û›Cê„F]tÌ ‡?}Jþo;mÒwUdÚp¥ÖP–ŽëC;6Cñ dÀÍLín†¸IQv¨FÛJéÏåÎTËÑ}ß©=Rœ”=,.¥D®gï.žøžª—¶Tµ³Z•À°ÓÂeM·#À~εÒÐ…dévd<âÝÑ¢…&ìk6—£Îˆ³ñ÷¹j²R±l½ é^…!Óç$6Ú†÷(×ÛYÀ—Þkd¿Ëo3ùïô¢Sä=­œ®C…‡¹—8 8³4 ‰¶åòOË4ßpÑhÀëѵåRº*|%CX,y fˆ‘lúš²ié«`AéRh–»4$ÿ±½eÍÔßs/ƒ´ä÷%çþ|6o=ÅÍ‹Šµ[GÍê/´«çÍ»!ÀJ:ê44©®yÚ5¢ßg·ÞûÓį¨Vù>³…]×¹î‘>æPr\§feÖgi?!b}I¸›ÁÁ¤çvûÄé;`T_Z/͆°Fåÿ×þh¨Œ6¸—ÓÕ…š6ÿÔVR’x”— XÑá€Ñ×LŠÄ µÏy¶T ‹^C.î”X°%å¬Ú¬@HYu\È×ÖAömèô“õukAevðcGÍG:´´ÆÎÃ&v|Rûž÷ßÞæÆp[©²’w"r²D!eQõIíò­ÛŽ9 ÝEÛÊÉt?Ð`Õ‡Öò3UK³I>J(º1pãÁ~H3mRôj‹Ú¦ÙŠOTãsF­Ù-ý¡ç4—›Â”xÿ«¨UïÛ£m[mfF¿@ÿža)åpÁ¶œ­¶èkÕ‰­!ðJ— < 9öž‘û£K[Ac ¸3GÛ/@š‚]Üw¶oÿ„Ê. ³—È…ìØ0~î-ÐëLŒxç(¡®‡ƒæÝOK»¨‘\}a%QÀæƒ WŸŒÏ•ùÑÊ?²âÞ•m? °D€oÙ__Õè;>(ø}¡ë@2pÛ¾>/g9ìW_O¨É¤$8üñã/º&Ô‚êñ”÷#0l®YqÝ`Öü#2:ÿ­Ü¡xU$ÑØ»­-3•}a2'3çĺPùÀ'6¢bËßy “kO,ïä¬4E|µú×£qï ÁªÏ6º¿ou½˜ÉŽÁc ,àI³4ˆñ/`ÒÁT:É8¡?º\hoébz45jâk‘%º ÎR[ê.·&z†Û¤›å+ü0³†ß²o VUI»|ØB9+gfKa–~g+£œ*>´¼R5‹À"‰ÿ-NÚ|H®À©6ùߦù%Oh,|y£Ç×Á Îaý©5‰è\[|< z&ªÖfaj67ݧ"*àÂÍrÕI/ÜÅ{f­€ø(ãÒžÑWß@Ol¹.e>cB.îÔ,àè$Íu3ÖV$$,μò|¼³àV†Í@5ÙŸcÞØ=LPcxQLÿÊ—yò Dq g¾Ÿ„ö;ûô+Y/ª'CîĨԫ–  fØõñ5µ„va, ¦a¢`h¶BóÙ:o»¯Iñj¶ç½h ZðF‚Ä£-çA&´ÈËWmtÑ|dXx$”ÙßÀ@°Êµ-ÁÞÁpÎÈ®œÍHÅÁ=4½Š„ɘGn£JÆ»-FÝÑG sû¼à!|Œœ¥ÉiÜ XïŒp¡&7ÔÀ*Œ§Xi$öïD(|Pì;¼€–íô"%ÎIßìñö¯É…ë j“FË›šÖûNý䙨|2ý‚äèëiÆPK±=6ÑN>Êqbä;R2hA¥”ŸåÈ´¤ ­†TR1€±mKçW[‹n¿†FcL£0¾•¢÷$=$Жã]†§}û}5ÿaAŽm“A¤Üd¿ TÍ/ÓTú€z#"•ý™'N¯¥Oõ‹÷®]{iæ‘ ›Ïm&üO°¾kN/˜Äæ‡høßF”æ¾Å¿½FÇ«ud çÿ˜± /oÚ½í÷—yš£n_.zJj;nNŒÓ&C¶¡×1²œšÝOâÅœªÈÉÁ¡%é_„l‰©>è/sŽ+^­ÇÊf8š‚vo¶Ú6åY¦ËBðMI {,×f¤·(¡8ÕaLo¾<×7(¡¦Äf"]?­]EòƒKAq%¼…Gu^ÌíùãûßB'ˆõÉxéÄz)û°‹¾VÇÉøŽZãl¼ùÄ!€¢a(ŽtÝsŠKäŠ-…Yi©™ecžàáêHL&šo§âÄ +ß2=úK­MPèöl°é7¦F¦Ö|q‹Ö›Gž7¯rðÑ• VÛŸ>)ÖUL >û”Ìp åyåEuÚŽbóázš—ЄOŸkmá&"gÿÿ–'(6ÍDÓ•ƒÈD½’ a+  ˆPÈf{ð‚ÀÙ”-ñü€¯«Z/ì3mᥖ9ÂÚÅ%¨GÇçØ7‰5R‚®8_)³ ŽÕ¶"‹X À]ËtOH›²j]´ƒ×ý7[6½ffõ¿ý¨5heO&Dè­Ú,]‚æ«ßæ¯ÂåjSY_‘BÍæZj#9 ´±ˆ–íÌa'²Ç6Ò ýðH“þo0ög®âU1?Wc£idEïlŽhî ÷yíc˜V­ü;ôU½~üƒ­íŒ¥ùŒkfšfö™mÅR2†Ê#ͧ}ŠÁ›i¯¼Ï2¢ÿ¸ÔÕࡵ@È.[&0Ó\µßÁ†¿ÌoD^×i'”7šè×X®zmñ'5BÞ€”æ"Û‹/½ãýˆ¤=@ÛÐä4ûÂ94¼ QwbÀ…ƒðƒØGJñ°F~‹ƒ?n\uÍ30s´ÙåZv_ãîÿ,Æ!³Á_ÎûZ¿î³ý2–tœYûãêqrÔ„±[U@t„´°°ôB‡¿F‰…$Åéš<þùé°÷BÈ2~nÀk˜ ƒŸðÃ"1„b±Á)¸~§ë¸ÙP;è–Ê+% ‘™ÄG@“êUÎ'd}²KÄÔÀ»»\hæ¿î‘§VAÞÃMñÖ~8’Ÿ ï«5uÀ1PiqJ¤a±B=;#a|¾¶ × Ébos3ýˆGå‰û€A¨‹MsÚ¡Æäü¶Öàó0Küîde›Ùä*%Ø-Cãdú@r)Ü@®p) Ë»äk¦?òg¥ŽÆ+8HÐã/wöñØ u÷çÕ×oÕ–ˆštßʹ?X+:mТV}•ý 5î "~Z‡þß;F-_Æ¡§zâò'AOsaIo¿%ä…iËj»õf%U!€Çù´ 3SпÈBªRð¸r ³d| òÙ1¯¾Ø•ªtR>ßEõc¡H;Â"®Ð¬…îŽåS_—ߟ¢ì$-ë ¤¬C¶ú•j£—m.çn† ¼©*ß`( UBÇB¦b)à/ (pk:€7|T—Mùh¹ISÍ›Ñçÿ&Í|(»/mÃjÛG;9Ý Bí ót>'âðêd>æ`æxÏ)u‰Ç…g$ŸÓóÈa™Ù˜Ca)¿À 1¨ÿºjVz¾ˆ¥ßy>s˹‰@8W¬÷ÌÙÕ¿yhÒ´cã{ èZ'ãy"QاP"¶oåVn€ßÉúÑéê”A);Á·ƒ>‹Œ+K¿¶]Ó¼®K±±í¾=A²JG_iâüßÀ÷­y6a¢$È'OFªL[rIwi g]ÊD¤¬o¦y4­ ¨cãòa;ýføÂƒ¹¤¥|Ÿ(¿§ÌhŒsï²§.!'}Žo«WzÂÕ%'>ÏMÚ= NÄ;N¿p8û“L¥Ò#Òµª·Ëø`û&QF GMÚÂ(– 64å¡sx÷¤‹9†'^Õ™«ø„öº_Τwº‡ad„3ìÄza¼]Ítéç^Søqkho£·ì# ™qó¨;ì¬f `6éÞéòâܦ­ ‚Þƒdû„xïüÈ9žér}ÐÞú¸âšåM{Õš*Ìeâp5ráÐ^x›VÒÊZ¬B ÅØ³¾ÆÉ^Ò3æþÅ ³º%SÖ[ ÕßþNsÕ´ž£ï—¦¯GgGSvf s»ý C*Bœª ¨Zj8ŸŸO»Úi5Ô­û;íd‡¬ê:7…_ìýóÔ父ðN/ =ÃAWÞ4f`$P&äc*è•< Ò¹ìÿ¾ë•,åþc§´Àw ûáóI èh_Qó('ËrÀºpH‹4W›µN\à8·IË-Ë$µÄ¿í há®ùì0i}> o-:ßn…‡çþW•ƒBqe± úU$¦ðý Ÿ·H°ÆbcˆÉæŠr1|™b{‡«BF‚!5¸à^¶ÉسY¬©N}áöC²qò¹ ¼Ñøh<¯GÊÕÞž\Å¥‚šÂ%Ks¯ŽXõŠKââio˜¸<ž$œÞëkXêú–úEUóVÆ3Çf)“CRyõ7ƒVÌNrMB¥@^³?Î…ý÷Å{8%q~[©Ñð[¶¹oÍ·3‰ïMhG¯$ÖéTÂMkm_˜ß×%["¯hUÝCj¬o¯+æÓóEðŶšóÜkC*IO ¶<¶}%ŒoIÃpVÑÔ+†´Å²õ=ä´mc¡ O“˜Œ‰-œK5•XÂÓÉ£ù=:›ë[cGÊìŠOÓí8—®ÅÀý¯õë? ºJ3h­ýÍD7)ëóCyœ„e ³vŒIl¨îºP0-CHbÀ•îhrI„Ƨ¼™ ¹­$È"¾YÊYoj LŸÈ}ø V™›ô)ÉNŸÿ‚r8I5õ’Ðíf•ÏIçÙLœdïsgB)–PÔk„ ZJ‹¥[ÆŸ¸`žÆI±nàê,årʉesôý)ɬֈƒHhƒ­žÙ™‚†14»0޶€rÔ‡fmŸ<¼6»#©õ„#0å!ô •‡ñŠVØ#šõP/Kza¸S:núG2¨¾Ž–žÈÚ5Õi +u6$ò±ø,ñ[°þi*g ÿsg¯tsÈÿCgDzŒÕ2çûV%M{ÝaïÈŸàßxèz.p‘yœ?ÈIñ ä2A©i@F§ƒ&BS•uÆœ›ýI§keˆ=D¢¿żv12ž¶’Áš¡Û½GÖËÝÅb„„PÀé2*ª=7œŒÏÝN~!ÄŸVb'Oü“ÈšI›)½Í¾ Y†»(e;í¤]~sçBî—££û¸«ÃßrÓÉ]÷KFzWAe!¶γÜy\ i |*?pÒ6Ô×/OkpÞ Ä¢Ú®Ÿª¾Þ3VZÓöLø^Ÿš½úðFûUj".bõ¼ƒ‡Í°+Zý5¯å›eIm)fÐð­ã™¨ŸNŒy_ñ­nÿÙ"Ì,´½dÝoW‚Ñ»Q¤i(™Ì3=‚ÇP1my>Ø õ@½s$1DUþ <5'´vò’Fñ®Š¨güÂ<¢¼{,í»Ÿ€Zlßðekf{C™|Tד[è…dLmÌF%ípâGKÙ”~j«´éóT+‰\*±e³7Ì»úÔ oŽ<‘Òžl·¶ˆ ·)VRÒ™˜}È{j8r!5#¢Ÿ2C$LÉù^r7Ò¿J ý ÿX/÷vI?ÂI†7Ó³u‹M¤ðjMDÕ0 ó]  ¤ã¢Sœ$ßj(·q¤¶K£(–›‘!C#E‰õƒ—.–8»ˆµ 5x÷zôÑe–<8(€ Môý€»w![;¶øøóüÀÿ𸖴¸J’;]*>b0TVË pa,2ÅÔô aüh0FC31y2ÀÓˆ-» ªÓ&¹šæ¬ßäÚyhé.sää^8¦yqàü7¦+ƒ:Åœ,b«…¸¥½¿6—X{VÐÎ#6:©‘:q–ˆNQ)= WÇO¢gÑŽAEÒüÁRdòã¯Ùó;ÐÒjË-ë‘ñ+JŒûùžFËÙ‰-í?ëËÞ.á…‚ "$“]e÷žiÕÀL ? ‰ùx-C½ò…ê6ę̂‚™Fh>q̦îžñ+hMÀ'Ç¿šúW[šäë¨Å®y'a´Ð)A¬µI‡VO°7=©É­%–ßKV)aše‹“× ]‰ ñÎýÌÔð[·$`xÑoR¯éz2y­Öú“Y|{ïååkª£—ðu¸VqqŒIƒKøŽÜù6ñŸHš/W–ÉXé°:5]ÉýÒ-F÷æñqÃÁÚ¼öž F›g‚’|¶hA·ª?|™µÍ¤‡9BÎö#_ÑË8:xù°¿4õpã8œb0½Ga½ŽQu‚[™‹:iÆ >æãû”Žgî'|{<„Þö"öà U(¨D®òÄ!u±å¥1:/¯Ò¯P“}ûû7øŽB6ìfÍ÷)½.S4kùØç”2Ÿ‘‡„Y„—–ª uNy„s,NB+š7ßß pƒý$ ½Æ>ÍžØ÷ð³mù! k×§ÿ´ íâ‹>äšØSÄóDG]iW¤76 GTËÕ|÷âiá3cÈwÂjþÍÝÙöC¿•}éGÓm[xp™(#„A;ó%’eÑõUjþg”µÞÞ`VœM³³ ¿“à@þ ^§^6ø EÞ¹~2açþ‹•$äo´ö€G©-µÛŽ —eS´¤¹Ìí#Ð"ʸ¼”>9‰ÎÚW2Ñ!ú[õ›ÇJ˜b1¬©¢ô§1çê†,ñ#F|ÛåfmÞ?CûÝ)›ÚµÔÍ×ýÒʃð2tœó¯ÁtÁœ­h¨s„äããÙ` ’s˜Fˆt0$Åe­`¾Z;WÆûÅÒ…"ªE”†q%MÖ>«ø{œl¶Êw`õÀ(XFÁÔðZx|½gRão²ÐÁ}æ]pw7²¬×·ÎSÂa±œ*WÁ ¨Éiýã…Èg´Š)›BïÔ-‰Ã·L]‰«p±Y÷5r !´Pœ‹É­5sšnÜ=9ÄWà4°‘J™.,@Ö Xµ´³ºöб}o…0²‰tÈâAâÌønz¦3kÃXEŠÌ2¾áÑç.IÚ§×î×å ·ÁSç—6jeeWÒŽÈ@æ PwÂ1¶g,‰¨ÿ`ŒY®ð?Až”0Ðßj~‹€ú[s Yfˆ!.4 u|UαTÞmD߉qõCŒŸ×àe–¼¹ÿ©%y³¬ï÷ɽŸï»ŽæÞþÛß>]5VÝJÉdg²t* Ü*xS¡ÿ•{‘¿`ç ¡¸~Æ‘÷µ7ª §[ä0R£( Y1M𢆟zrsNÔYÎ?!@uƒB>°q\ùFø z„W½VGk*€ëŒ Pölõfö*ÜΧøVlé ¾´Ý§”ÒºY¥ê]n^+[öe¢1¯à…|'²Z»ÒrçÊáѯ7Ô¿Óð@:LòC_aØ€=’9D›ßÐÔh£ H•–´WŠm¦C“ÇIU þrÅÞ½"¬º%€Oå=+Sdõrf°ÝÍdx1“3ÆÄÛ Ì'£KF€xVwðé1§ë„£m¹‰ Í»_ñhÎÞŒ4.–ì¶CÍ9ò=Ã3»pŸYünô>CËÆßÖ¿ÀêB¿FÝ×üÑî3Äò]AàL?G¢£$…·­WÐî­(ö2:uE€Êcå;ïcX Î|@f±A‘†Šý`zŠª,‰RtþÁ¬$/߬q®ß°6íàâ þÞW‡Ý¨­)ƒœùầõ\ÜgoÀAgÃÎíˆ5%Ý7(׌]òF•oÜvúØ.ÉÚV$O;huZ[¿øS^Ó”ÜÀ[cKâ·¹’ZUTg/=>,a/ì0‹ikÇ[ê÷Và"m†#É8 ! ñùM²ÌÞ»„ïØÖFfRCQµdÿ¹ê%n†J¼Ákx%`ËÖäÞN²¼`űbË7ÑÚ—Ç=]äïÉ`ñ'W39÷Ü|pï5—ý?Øö$g–΀æ^¡¡\;bÏÖ[§YÐYadkJ}Gf¢p›¾Û6–,¥¢»õ~Ù¦¯¢ s] ë «h7Zç„úVIþ!<6=;eMµ2‰í¬z«îÇ vJß!Â<:ó@/ÊynpŽ¿ùý~úÖ˜ª3¹“9¢ßØÔŽå¬S×ûT ã„jd;Á³_ûÐ =M952°Ö$E` ¹‰Rì ¹zܵ$mCòÈ.<<ÙÚbI›ˆOÝ…ïI¨/áv“£Ê/) $¸qT†–—ƒ « ¥ÄFì K]‰¤:I„Ó€äù^Øügˆ}ZÃa ßÈêll0÷Ä`Œc¯`BGÇÞkDT;ÔE^.œä·‰gj”õÛÍ–9qDÖ†<é(ÂàxRÅjÂ[Ê%ªÊ†ÂÏ*ËùÇwfP0÷?¥d\ l%íKð²OpÂéãªݽ¼9—¯Bdtþ56XC»¤Ï¡û¨"ÆDBé’Î𭉆å¦ã˜=Ô¾‰Ñ’ý@IÿOq*#A‡Ü}hr²5?pRÝ7LJØ F »Ì[˜}ÙÞÂö DE¬,ó(”éJ‹WRó*OŠòš…Ž]½_Ì![­·ƒ¯ô"“ŠüÕÿ`pcçЇiŠûÉ£+d¡fЇ:q»° ÿ†d¡}ÓhÚZ5Á†à“{‘¨uRAî¸ûèèñ¸ÖmÝ›‘ kEãÃâØÚnLÄ‚U$»ïÊÅc´kÝgiŸìC[+‚sÀiA 1„™9~ÓºUÝ Øçé¥Ý°s³ò)¸%Žþ­¡}Íÿ2€áD‘]̃bmmrí^³2ÅøÖâ)±™`2§ç±ÇÔÎ,0&¾2ð‚Ê£<¢+ ¿üÖ½ (ù¹ßHôÃ;ʰܪÔE§(ñáññí¶ŠŽ(VªPÐ/¢ê)2Y¬O¾EÎÀ (‘dYSA}PV—k2‰Yüzg·üÀ,â%>*P?rq®Ttt5*ƒ¢‰U†!8µ.Êo?0ã|¸—Ý:7"“¤l±¶~RAœÚõ}k¦|ÊJõ1Á)Rm~~ƒŽæV"¬tÙK±±ÿÑÀ¤®+ÚaÀ~¦Ù[È7•‡Îd=#{?ƒj–ý óþÄïl»”ðiùße _ÕÞÖ?‰žsÔ/Üms\âÒë_s=Ü™.bècZΞƒ”G¯2@ààã޾Ä^ÖÊ…;J é@YÚË‹B#b0ÙÖká7þÛÑ"^9±[wᕎ”˜ðŒ:I*‰sW6oe œ7~è€ ¶äâÕu»#³4Ò$ЛÜj:äÒ¨·&0,FÙ_fà¬ÅªQy£ÔùEN#@Š&FëÙ®ì%áøÐ” ÁüùpÐ Ìð¾jÄÝûJåÓ3ïsçO­C|²U‘p‹Ãýˆn‚ƒWEn’Π ÔÑ{@êX.˜- Wý4Òâ…ÐyH(/»FPo×ß#5p áz#›#¥>ÒmÊhk¹U\sgM"u]r¼ªñªï÷’ú—Ò•®ÙcÙô(¦¾í/ÇÀaTµ×5!¾ïgSÂÿ‘†âÂFϺ¡¢ñ~¡z©tgç÷"éo£Œ©Nâ² CV ßö²ºˆ‰<9G–äI05C€# »i½’ì‹¢2;<#¢d¤ z“(_eN_¸‚ïM¼å}ýG…°s¬°”Eѱ)«ê ^‚·?Pâ•™1#BÁÿaËžcûÇ‚J¸ »„V§'ú²¼’f¡t©lŠ["6iŽ;Ä4;#é“þÁ†AÕG& uiÌÓ¿Â}QUZ£þ+hžö÷*÷ï Q4-,øÙŸ3lJØ(Üö‹q ‹$M×8•­ÀoصyÛtÝ×—•üë"ëm޾‰wd¦iUk‹ÞÖ'c&f÷RáóͳAf¦Æ¸læÔp\Íc~Pß½fÿw¶_a¦¶J*iø6þdTILÎbÈ€¸|…[¹Zø£Ö5'=õ_‡¡,Ê1D¸,¿àÞ·øÌJOX[êEDüõÿæ-d`Ág'ÎÅÄôjAgn' éaˆìžBŸÜu<íð޵5úñÔ¾…{rM™´Q:®cÑæ˜ßp,]·qªï&yDû£Ý½…]S¾+Ák†O©=R“Ã)v^ärSz:ƒí¯Dö|ÖpuX¼¦O_Ö3žzG£ò[z‚EcñCá&>®¤¡…»žd¯\ýòFtCÕíõ¦ÝPÔ2ß­¿q×Äö¢ýõ2øƒ3 Ý=žlÿ×/78±«Œ¦)Þ(ЉëX«ò‹Üã £®Ð$gÉ•…G¾-ÝÉzxd=StÁ——÷CGv æ§û^81"§ GUû²ÿ› *®÷ gG…ÓÃY) ÷ 3“Â%;Ž2]­IÁ¸z~yjüH_ñ¸›ŒÈw÷èüÒê‚S@^ob%Ù´úº[œ¢4“¦’d† $H5 !#fIÁÕUL†e¼ýt [߀7΂j‘"ý4 ÔÏXYÞ(žC5ãÅö‘Þå!rÇösÅ)&¯¨iÔíVSô¹Î2Ö™¦¸ûï•Þ5y¹çÓÿF¨Å¿‘'#«XÌ %­éCQomÚ‰ðþ`œ‚WQ©Zʰpj¶óýÜ@ãÆŒ°ÕPsåÿûX¤,•#³NpL ”žž åKøûzÂp䦥¿w}äïáµü®¬yŒ…A¶¥m¦‘€Qanqêª(p·md¤Æ†ø 2Àz»ã)q Ÿe2]“I[°ÖÇH†Ÿ?7?Ðá0lÀ~ cò•©¡0Š@7ä,ãÛ)¾±‡¸,S‹ç9ζ¢à E¿nð­Ì¨¼ 0A­Ûj„#l¼+Ê»7ò`èe7+|ËØ…ÛðëïÅÆ¬>™sSC„:PY?¤×õ ¶$Nÿä 7`7YêYb7L{õ7‰®íMqÚ§ïñ¯ö3JÓÇä}û¯J+hᨪh«Ô’'´œ‚¬•‹)ò(F ¹S¬;ÔÐûÞ5›íºì`-Ÿu¦+Œ/f5çÌÊçÓUÀ¾šŸfÂo÷rBnI+()‹G ´]|^;],µAÊ¥ˆØD›¢]ÉgQ2Y"`(™ e×7ËV ŠŒÓ eWŽ•`º(¦ ®{»™[=ƒƒûÉH° x›lÉ9Fm2ÆbÊTS¡¶Û¹æ‚7¬eiÑ•&MO'IXWÄfl¦KžLxšKWä(fÄn¯š‚ oå^P'ÎòJ ^=[¦$ðú®èÄ碣¡œ•Ý‘¶ p–%GAMkêy޶ìšë¼ €42γ@ؼD!éî„„™‰“ÆY@ÒâW¼¿HMvùeTöZ\÷ã;2 ràâBúÄ¢€.{0)òðe?ü?B?¿¹é„s»'ƒ-ÞE‰öµ@- †.·ku%ù'7üÒþáHÛ¸BðlP@N”Šâú§ÙT¹KQÅFEM—­Æ7gˆ q8…îµFfÝ»u-Õ<³E„ՆüÃpà´JP‚n:µuXØÀ€‰ö‰¡Ðý„jÂú«õØÓ©XaÃ3^kAê£kJ×`\2¯{Ñþ¬'B ¶=‡ÇM†´’Ju¨¡œÇêcÇbº„‘âp\ÕÒèÅè&óRBC¹ô?,föZÊ9„ߥ;s~´SåP{2EgŸËçØ_LåÞ%&ã(’‘˜.ÕÖÏJÖYâ«u©Ýd‡Í®'¸‘e‘X\ÌBC5?' !µþä ŸZaÿµp$úÆèD< ÃÉs[«dúv§—Å9IdqZƠΕËJnDò½É&N!‘bH!vHâéjê„–$e…m¦ª¢8äËÈ›‰“ïžðœ6Ï%ž/½Ó;–ßã…HÛ§A)<£&N›KrýN쓘٠™:P4õ,×üîøP_‡ÎÄf$0Ý×ÇþÓÖj¦}²äu° HWL b<…OàÔ»³ Ôq$·šAH°±ôödÈ@·ÇLíèd½B†9Évܪ:•ì¾XѪô Œé®üÞqMð€lÏq+ÙÑîBÑ<Õv ”r;¤5ŸµÆ¨–vÀáÅ܃T$ÙÑË3*ue²Oã@Þ ´?CæVz"¬AÒíl°¨§,7Ñùi»ñžU)8éŠX$€•ªžøRÌ ÚbßÅðK ã”O=ñ¶éŠÂ¬‡ëmhçx¤;3«ÆPÉøQ”"?`5E,b¥ürN ZéÓÇpÝL-±3’ál+ùί)s}äl—Â.¬_®ÕÅ#i^ý3N’l—A¨ƒVF=;ôÓôÞF„yÑ*ô-³U©«4ÿø‰ÃŸ¾+ç w<ª‡p‡ä™qÊ0\DUIT²éš? þˆÓ2º„L±#*:~‘oKmó¢Qp¹ìu±–cÂîqËO¿Íáp´ÆûgºŒxÄdhÉC DÝܧò;¢iVòœeiéJ÷ 秇|3YE«„Sº¨±Ý¶n5ä«i01^y!é´îwð…Hàç|='è“ýÂúY¤bÏ@}Ów\z«uø¹Í­¦8L‘äm$;G©`BÚ_00Åv˜åK„5'.ô°² Ï&ƒnðu/NÓ8;Ò·ÒÄ(pPÌVî\ìÖãG|”•­ŽËwž ã a6®fì¯ÔPCDN_©€/BÀí[«ª4*;6úvMÙ¨™ûòºn¼Q¤½2ÏCÉ?»>×HB銒Wº‡…„¯ÔmZšE ç™fÆ€i¹üÃŒÅV×ò´ò^¹.yŠù%YYO¬ÈèêJ¢PžM*ߌÙù?d2È‹’¹“ó§¨Qfe¤¨´t“›þ ñã{¡ˆ$À žã& «W½¡é~C6 jX5r-4?3O)ç}=Æÿdî^™ƒv‰ó#8c zXl¾ ©Ï_ȃpòÐB{ÊM¼å-¡"°gÒù8 µûƒÁ;zræÞºüOs'ðå8‡ìíÉZÌS`•Åð/j‚`:¶ ¤ô÷ÆËÇ’÷~›qKÞ7fØþܦ;N,J¾ª~CÇþÇiC𓹻‰ååÄgã¯Ñ™òCô® ʇ1ÖÀ®¬Á·ŽŽÔsë=Ù ûìeâó@ðk(@K¾ÊJy ”Ç£»YB¤¢ÜuøöÙ~3Òâ&C¹3ïßÁDÀÓñ|’Þ¢®ííAÕcÏRW4.ß‚ÒsJ"̧˜ˆ‘¦/zÃ&£©JFéÿŒ´ZèIsU ú}‰¬T°E'>§$úÖrìû¥2<~°„J°iÉ®ºh&Ë»3fèzÇňE(cþ¤¼1¶Œ•u¤¿÷!QÃÌÁŠRʰsÎrÔ_Q2Ï!i¬Ö‚¶c!sั‘= ìP¨Û‡íi€b %Iµ¡qÄ-'iýœÂ´Ún\ƒ¸>ÆÛC`„^6æqg誵M`Ϩä±Íäu1- ª)Ë3JMõÈÅ[šjå™ÐFqº[4˜%µÐsß’Â[ˆž­Ô@Ï ©¢ß ŸÄ±2¤n>êÛU-²é†Áo=Ãm«²MPÎëN³x)l8†ã}\cZ?ʹ©žM)`&¸óÚ‰m.˜ûËVmï÷8ø¾Ñ\åÜk¶:™M «|póQVóɄΔΈmCÏÜ»_¸W¢¤K\ª§ÃlÈVŸ™zñ$+}¸ÿE…Jµ_ü÷ˆ=ïï1H¶zÕ0}D¡²zdÐûºÇŽáæÊïÛŸå¥Øè½p(G¶çmŽ£¿½1û8Ì !Y¯Rö P[ï}¦g%´¯¸È/‰æú­ê?šŸÊ|}£»d‡†jÈyË„ÛwnŒ9˜ ìV- ëúZ({c¤$˜â |±ÅE,º‡R}l .‚ð7S½Bƒhúþ?] |£ œ£’ F95å[O¦ú'JTcÒ`èÿ8««>®Òv-òúóÃ×p4+¯|rߣ9á[ÿ0&xè=[Çf_€ÁB|s#gòzËm<µíŽË/qGªÖ¨ô7᪜ÂÓNŠØÖ p>z©{Ã-‘Èà3ϧLuENU3ílˆ+ºþ#*¶°ó©\Â7Ǹ”ÄÆ I˜*F€5ÓN›rN‡.ÌS3õU-4ܧÏeãeáø‰ä†ÀÙê!pñC§ÇA2ZÔj7Öco‰k™Ø¹ÚöišÊ›…8PÀy­'¶1dl=]—0esb€Ï8^¾oeDÝÿ7u ÛÈÙ’}•íJ¾öl§‹ä 9Dø]: ¹çËõi8ït©2 rþ<Ì"mìœnã7N–¨x©"WhíÇÝ:G‹¿¾íA²ÃC/V9Åš®B˜/Š„‘HU$üwÕ0%pu A£S÷N„®eXÍ¡0ÝZð»›­ÈäjaŸ\¯Êž6BÀVbZ\‡¹Í}†ôÁÉj˜àÌ\bhnÃäv«Šf‹u^Xíýú°!Kº—ô‹êÙ·U(#Îþ¯ƒKR„÷2$¹Š®p°™pgq´ná&ú°™Ä[Á Ó(Ä>øíÑnfK3†m,SDón|¸¼¿UË¡²+/Ýû(}À¦¥Øˆ$ù KÍÙ¡©Bæ\6Ž™=z4aœ:Mk"xûgG÷¢+6•K˜jiªúª/nÅ¡žuƒÉéNÇHþ,/ii¢ž¿ñ‚°bu¾)/g„¹ dˆé]­­i0:? °Ê‰8L‰S¤Ëßå¡ë¾ÖÐBÚhCªôÉyDß9úÇ¢¿s]§GÿS¹ ÏG– Xÿ"–““†xoH—í¡8*…afºÀ•¥–ç ¿gtjÂB#>#îTË£:-–HXà2+¯Ý„Î)ÕÊnL³<³kìš®±àªïli-GÃïþé[Hãq^’Ë~L²¹I |`Ôû¬.–­!«fÉvüt.Tl>)zVpÄÿ’¿øÔä*“O»BÖ§Ä0a(“hŒ‚³CHÚºêlÚÀÅRG‡ìz»´ÔíÊÉ©€ãýìNR‘Ma¼™ûñâ‹é¼ØDB©1<¨jÅÃ¥q?x‰P!þÿšN‘½>£ææ‚•Ðw.‹lýä7ÉVð­7kXÕ»­ìÍpàbõ  ÇdÚ_lìÐPô®0á8μˆzÆ(O­ ÿgEôŸÞënµ“¤3KU|Eè¢iÎà •Ú} Æ8Z'RjLÔ =Ë Þ¹¹;4Ô¤Û ›h>B¶1×j‹Ì7¶‰–U[+œ<˜R2)kÇ—›B½£F±Xã…—·BCÿjd ê.ïej`sexSk‰Ñ¨’‘_&£™b~Ӗܧ؀9Ò†ô¹?ýþSͺ{vQů>œx¯ÙÂ\i;+ü£rs'æMèT½J2 Jë)z®ÃöA¹÷@w†IU¾Ð!3Ìønç:]Iq?oYé&[]Ãô?mãŽ|P["_-âmíGBI¤Ù㪀¼œDØ¢­‡(¯ŠÛ9OG­xi$ýB% =º7HVÁPNT™Ñͱ&  ,L¡)l0,hq¼šÓ»“ÃÄ.ýÓÉæËŽùx𢽉û³{É[ì7÷w¦WRꜧèä3ÐKÞ¶Å‹‰Ë„¤•€¤EE·#„ç³6€#®éŽãh‡*åÀ®+úC‡í·Èkð}†®²NGv– JñÚ¬Í×ä°Q„ý}SwË×î±|p,ÑøÃ„Óž},âl{°*:¸ù`èé°ì[[²âmýÞ‘Š;¾V‹az¹þÊãO-~¸#S§t,q4(-n|Ùÿàêk¸CýAALö/ÝÇ|H¸DšÔó[·ßߣ+•Þ™ñHVã1¿³…N‚tžE©è~Ûñ›ŽÒVÎpŽá7ko #_ûõ‘(³æ4Y*:¤”FBE/ˆ ä¶‹h3ù 4ÈË/}M£L©EÓÃ7pê@,yØôðûn´‰‰„’¸ËÜû‘‚Ù¨Œ†,¦EƒŠókÑbº"DCYóIìÃÍþœëÁÉÂÑ®A²1VÕr§„L:Öõóc˜DîTÄØ{fìX5˜jùµ– …ˆ0Éײ-¶–{Î}°Sd˜äs7á æ«êeæ?¡Ù4ùŸ…ŒnÑB¸—Ú‰,¤žŠMá®ê ´CØ0>¢ãÞÄ×çˆÉxŠïâuìUÁel^LaÆZ›Ó™º1½8E“¡ô“¡[K“U̦²k*g† àà ß5NÎeÇ­Àöר΢äÒm­ uÅ{J-ű½ƒ½BãŽÆ`"E2Ø:|dýû"÷€T‡£d˜ÛÕEÏ .6}ùŒÂ¯’¯ø.S¸ þ2²N[¬ÜëþÇ  @miàÑdRŸ)ª Ç‚TõÜçεåÞ¹d­m`!•¢´%èBxsе>.-5Ÿ8òÓkN{êÌeˆ0U¼‹‡ô‹ÖÄ š˜q¹¦|¥`Û0àEðCògç¥ é `Pä„ëuQ–7GŸ.>Þ#¹ýô@OÑGÓÐÞóä š{§cXÛÖ²´ÿ«ëçcÎ/<§ã.«©ÏCœÝ{£â¥*œÆ ÿÊaĶ —Ä#¯ åP[¿æB³ÛIS %kZ½ú“ñBÈxS™ EI'ûu w4(œÕ±LƒØMèÌ5P¹Br­ld>êIâa+Žyà[ñT‘AÎOM’êe»»QȯäRL&ÒIaÐ&ˆ„¯®Çø Ë…q'ZVƒ}kÊE¿Òðj{MìÇdÜEIçvÖDÁdx„gX¥n¥\ÑÍêÁ!„]À«µåqÕ˜A@¦?Øw•àF'"HûÏ Ú{›{4ŸKØl*\ã„ÒïùŠÖ禿ô¦õžd× Íx&õ÷ü‹×ræ ìϳH«|f.íjäÚ„§þÕN¡:úŸPFƒ›e¹rž‚4lµÀmÁÃØ0çê½Ùþ© =þ¾¶” ›‹Y|¯¦KëÖÅ_õÉÀˆ2û¶Ö+®CM¦e²»Ô~i{µÆ{Ú7cº£Kö™í@Úâ¡õ¹ìrd x®ï5Zä(!Kä¸M²ŸkûÊCv5ë&_ˆóEJöçܠǬ‹ÊN5»¹Qž=°Ê / r:–ø>^Ïm>(…%yõ§æ”29ªäjò‰M” n#¯†ÇigÚI÷Ûù6Í0~ý.Õ˜“+ÒÈÿpÂWªÈ©?îÝ-³½ àeÔç¼#‘↠s>³­gΕ9Òñ½Ä2hC§Š Ždaº=uX•ŸÖÕéjù¿–¯zaäÐþTëòr&cxiäƒûV¯Ä[›0ùSˆZ¢;²–ºtø½å†‹#€½^[¶:×›§É)ΚicB¿vò‡$”ÔY£Ûç6Àu7Ê#geVmÔå<ϳJ¨Lúc6¤'!bâ6”Žô0¾>-»Ú=žBO„âØ™vž&fx“IhAø{ @Û]ÁÕNbÕ’\•@™+ðžßw«Ä胳¶=h!¹Ec2ñ,,ÀKÆÜz2ªÝ½í¦)Þ5KÕGíU7¢S¸ëH¸®óÌI Ý7øi“¹9ü?ʘз¯ájó77å+U5Ä ¿hg¤Ë*†3xCÞ¹1?¿, ÂÆ†`jòªtÊ·* WöO ³Rø\ `*±Òo½Aà?ïØŠ}—ÑhKé±xs¯°*KÙlqfÝP ^˜®™ƒ/àºW{Y1eCwèzC­õŠS_ÖËœÓ4oߣ¶ReÈ_IõÊtB÷.Àr¸ìèT­Wƒdú`æSцN¶¦gº?ÓIê¡¥U‚g9%†S±1`ß”bA·„Äs(š!˂ܱ–*߆ËÙ¼\I“pïg§?ªfÚºD¸·ºKZ^þCy2ˆ8a¸Ê†YÇQLÆ¥‘A:5™§Û©Ûó!ÚqJ`Y/S»qé<ùl¸<<”óŽßñøZ4Ÿ´ŠÅë x£3l;â 6Â¥Úwï_;|³†&»­ì%ùìwÍð‡PX]pÞ É-}Ë­¸6Ì9Áþ÷ÈÎñiÐ'.´hNÞ._Ë¿YãPX;粈÷v­¹uY†É¤5Û˜¶†Ú•˜_(#[ûG¤9;l[§°`EÓŠ"4úÅëÓ T3ËžVu'¾®³Å¬I ’^ @Bm+©PÍ3¶`Ìü$A‘½b‘[£Ér)û+ K lET'¦ôÆÐ?8«b3+Y; ›ÊePv|† ± ç„©÷À;ÿnt•£ëõªGã}á„ØiþŠ«žL|æ²(t›·—¬Ì›4Pò, ¶XÞƒ¯Q­‰ø?ýNÁN.¯\ã@®  ¤9 òÅž¸ÐÓ?ô-DÑ7ñcªcX0³íÜ~ŧÐχ蚛øP«Ùb6]Ò<Õ7ò/~.:#ˆ£-¡Ø¬]êªìÄ$G~£¿½°Ê ÏÒ„”¾€ªb™ÿÁ¯Ì•˜ú™Rg$ Ñ/|=$ÃÀ¬<ÓÿùQŠ$ßç­nÚ 1cr¿áÀÅÜ7)íÂÁ©1-3ó4úGû¬W`âqyö6IõÖ5æùõÎÙ’’%©ÙÑý®µ†N=J‘ÅÇæQ Ïà sJ5hÈ÷¸×OÇïœFÆä D·Aìâ—² gYß(­Õ÷P- š¥+t»_1å­Ôóv;-k¸q©À~(vBp÷ÿ¹æÿlóØî6Z¾¾vöÎ+`2òÕMm:\#ä$^Ëš¬€yRO2ž¾ >þ‚oP‚~{³\RM o¢[QjÎÝ!Ytü.Š™Ú«ªuº.„›„\”/TèDlý?uƒºSa‰ëŸîâ´rôV¿×𦟬KÃÁ®;°å‚ÈÌôý™¯vº1¿o¤pž¡¼ŠÆ*s43kôö B‘”ìÞáÎs¥óÎîÌ,[Iô$ºƒ¨ó˜h“bP"àœÊ–2‹¨S¥ ›æÛÒ£¥Ê_ä‡Ë ª¬^õèªÉÃd$}Îm&] lšo®–àjÁÀ˜Í™È¯Cµ%?îEe?EÜñ£Î0¶ia]yú¹ ý;Lö‚WµÖè[&hßZ—@053^@µÛQõï'/mjO{«[ å‹iaÉÌ^Ó]Σۈƒ¡¼ {Œ£ZÉ7k×u‰O!³ç"ˆÝ­åªÈ!@YH$‚h@ö]9ñÅòÕåÛÔ0–Ôó°ˆ-§|¦mTk‹â%À¡LŸ”O~OÎ[+/)ÛÏþõД¿P§_(ì¬Éù.Ø·|­Ñ=ó'!í‰@v¥Ž>q噤PQ¢áöŒÑ3UçÑ…¼qǵ¡Ôg˜V¡7?§]O C’ìý¶ä£óÛµVn£ýÞT7 …~Nh™mUXWÖ‚ s¡ƒ²ë§|8ÿ.º ºBûxdµsR©†ðÊeiXGl–´UMÓ“†…~zÅJ¿ ÀoWxÐrùÿa¹ÄkÚ•Íÿˆ@æpÔÿ|å F¿ÙþÅ*!l¾— ¸èÜhù~ôx`áH =a(‰ X²nþ ‡N }¦Dq‘Ã;1ÀŒÐZHV@|Ó0ÔžçíRcO&¯†ãnPôuÆm8š”–6å„ÎQœú$6_»qÏ(r6v6OVßÅÿcH޾׫„˜gý!1•ýÓº“ŽKØ=Ç_¨ÏûmÊÄßgЇ>—…é©©¼a£EA6gHf¼‡þÊÈAÓ}10 Ýd^mi%ÿW”ï& $7Œ z|ÍõÂË@÷˜¹Ôš *Ú?Ębçî q jÙ\æ+!kTíèÔÈRgér,¡×x°_°Yj&ùÝ”ÓDÚêOEÛ§g1É [Ì܈¶ø6kj-Î…”uNñåV Àw¹îð¢2‘ÉB‚"÷hÄV|Šƒ^ÁaNªµ·Ç³mþ–I¥NˆÃŒ|öÌ4}øT=„‹s¦­Yê—IJ/SõU¸A¥¸«°Vá37-ž'D¨hs=ŸçŸ#be»+AŸ­mv ½Ý‹[ÜáÎhŒ¶Î^ãñáŽs°´¡»«Îžzé–Ê“³ï¬R+tÖŽgÉÇ­éâý¼f¶B".Ç?Ÿè–niÔ½@QØÙédÍe ¼ýG8¼Þö&¨Ó˜tSžj>|d;k¡w™ÌC.+Zœù9;Ò&ôÊE£ú¬¡éE gš `KïÊ6‰’Ç$7ÛÙd-­¦k1º.l÷q™®i$×lG¾ÃÌ®äæ6½ |(¹•­ú‘/¸ìø†*7l °âfôÅÿéIFvÀí®îÎ%€×±c"Y¤øZùhiñÔ½­3ƒ $€—},Á9IOF.-{Û_c<ÝÜñQåMJØ'3LnÈ:·afI‘YÁ!áþÁøl*çwªâ€¤T=€'×°³¯tJ`?8tH ¤ì_5•hóÓ–¨9’îØCñ]û.c•¬|ÇÇÌ:¬fP¿´$ˆV§‹›#È­0h†#¸;âï[ceY(v[(2¼O,Ýw ÀÐtÇÀˆúêøqÖª/ò­›%YRNÿœ>!æÉ5ËP¦Øræ„•!üs ²렿¾®5¹ ¥al­Ë¡“7sÿúت˜à#É« BzRþ[¤UŠtÿØö‚õ›Ã›î‰,R_°ønc 6‰¼ýŠNëÖ¨XÙÎhǧe_+¤'Lòæq>sêëÂ{éN¶÷å§@=¸3›ž#¾‰P[;‘<ùp¯tµÓ„d3RbI öZªëÿÑ㸆wûû­7 Nà ¤®'&»Ž:u´º¸«÷”:0òdþ¯½ÓƒTZ{UVlH7q2ÍÀ©¡¼ƒêë1 Õùxí(÷CÉŽ¢ïëÑÉåÍè+7VKtÝÿ8‹nÅÂ’ÈfD®8oÑæh£j+¬nªÉÂ'mGê®ñÙJ›_eD\žÜ2QW1t’M'ç¾Õ¡.e˜…F6Oq]Ù*2tkLLiŸ=°É)ý:.NcŒ–³4ÿê6g5¢ç¥ïMã«¿¢éÇ-=Ò§ìç=%ª ö•Vâ1@Aýsõ&Ö¤þ32 Ö,”õNÃÚA Û’´=ê c8-L%*ߌt#9BE&å©?þ]à z9'æ¿á^tP…©ð3O~œª›Âï™°¤Nî)]éDk­fB@%èVÁ1¸pyd¬ÑÃU§ì“zdT“ÐnˆÄ 5Þ˜‰RèŸÁ^ë¿H>9,{f Y?¯"‘5QY¨6Ø›KÅŒ»~¢.}+ûͤ ¯>š.4aÔ˜é1 ¢Ïz`i1콈·Œ‚ÌE8¾0<,ØwJÊ.M˜‡Äl–¬ò ì<~}L?žÍ¼Ðy4H5ÅÞé,°~]Ô­A¼2/G¼âd½saõÀë ôÌÕYõ¤Œ@Ø>(3WA1<.o„:ÖÙ‘.’h x‰¬+§e.0Åc„n4_èZ3s [#¥ËÿŠÞÖpÒF ‘lBý¡¤¯½ÎH•;×äÝ Ð¦ úÎM’¢Ù†N~3BÊ¢3ó0€"g¶FS;Ç‹i$jÀh+Â`D <êY{I°ËHÓ5V¿¿Ít‘èD8q°×_¿×÷;wF oô£6ï ‚òüÊ.û$‹•@Én<•Ó6hÉ&ëìÜïšëãiw ÒĪtD|`ø”Áj¼.¤Nõ—àƒÉ“!  E›v!ZA)L¸àM½Šv ª.j -ì€[ͪ„y÷Ýk¿hxˆ˜YlPb9ëV_íl]ê'ÿ)#'×>Ôxå¾ðÛÏ;Ñ+§0mÍF0Ë!u£¼ÍŒƒ(‘¾Gûœe‚„$@jž(5¨4’WäH’‚YX‹nÎðà‘·³ˆ‰@ùDœ9¾¼T´u«Â M­3 +ÇLŠÇÔ%¹…Àÿ§ òº¥$¤:IpœÉj@Ø7#°Ôo\Z¤çª!±1ú"¥ž„ø}ƒøáé(‘÷´/»BdP{°(H¬Â|aMWüç=ah4ìíÐÄ_€áÙ>‰[ñÙ_¥œ<\øˬJ?œ›É~GʦnO4®tÐr¥ ¼  —û)l•¡e¿zTkº"é˜iŽæWiš]àæŠï±—à°„?8ºM&¾Äø˜'XèÄDº&¤ýDy› ¬ ÆG¦o`7®£-“ã¨[’‹WcBãóô°tÕø+Ë´òž•åNQ3wŠGa’îÅ õÞž”fª·Xl´+AþuÜ¡é}è;dbæŒòs(/´r´k;ï:ÈT44ÛÜÓ ˜gÞ %÷OÌÍø„Tøîqd\)§( vÀ5À£F.ƒh,Í]Y f眫–uÓ”ÅÞtwúlþ /ܬ 2̃óûÒ«cßY½HK˜ÐÊ+ &ìån–èÁÒú@©qUédgžI/r¿2Z­–!YzÚLðè"ÏHKc G¯N %Å_ÀÓpyÏž¶À‡[ªT„˜/¿Áɂ횔@Lmú4x L[^½ Û ˆsÝ%{béͨ»ÇŽRdµÕÂb½8"ê¸ÑPšU»´Tª¶L‡qÌwIm·ÚgÍö-âвí ÌéG-‰ëà"¼¯¼Ê=[©¬â¹'y‹,"ë­8· »†°þo [P+D|… s”9I ü`~A=Ó²#ûhnÒ46Ò±Ý5*ÃÔÍ(ÞCÕ, y–1”&ˆ á0àÌücI¶Ùn´o]y'qüÊ6¢ÄŸá /dwE·c3ß'Ÿ£&-)´£ 0%¦V/‹À$ܼÊo¦”ÙÎsðB qÃÕÐþmÑ]¶¹ßðg\^âÙ,i>äb‚7ù)­ˆì0Vïý· uxˆ„£3ä¦WÁíY|Ž¿»b¯xØÄ*gÇWhÝ2É”m'`ä46Ž-†aU»¦ªÚ¡ÍêóÖ¨e”Ò|µY‹ŽË¨ìæÂã‘À4×w°Û?ìäÑ1"íé¿{ËTàÿ¨ÑZ_-dWF_« zc4¯ã.æ˜>É7úœ›œðŽ»KLH„–|¿ªü‹ô71úÓ´Üèi”[,H“Ö90i:œTNwb¢È«€½ótY£3õɼ€™!‡¯A‰7j™—òhù˜è`¡†éç'cê†óeAoLSÖ"мÞ!Ø’¯$WðЩ³y9N65nöWÙž³V Ó̺°#íˆúV¬ÐmÄD¦º#Ðâº0¹Ê±ú–Én^ÞYÆúa"u=šæ`¦UŸ_bæ “ -C.Ú¢}™«}Ÿx?+`e?Œcîרœé›N¬9Y›}O›ÊÒUxŸÇ2&€}°ÊAÃ׋8ÓK™©B$„ïaöÊec]óŠÀ5<Œ,(0È©ƒ,~í¿Âx>Ô<¤]QÐ hþ"“ñþ™Xç<èRžÌUæƒ:ší á$¯„1|J±«ÏH Ú€ÓL,8i|}Zî…hN5ã ·`ZYõ š„&Ç0š¡Uí†H¬…Ú¹ì L/Њä.òµ¯È“‹ž­ç~G¯?œmlŠ@ù 9u]®¸¤1.×™)à÷‘· LÛv«C%RozìˆdØŸŸö‰Çiàé§-óµØV§iOÙJsÃmÎÌt€Œ]2ë&­- ^«Sk9£!¼Qe’P ¼êÜ•<®N%hkELBéÐhÛE‚ŒÃ%ÀjÉ l}IšòäºC÷ÕóžJ¯ƒ½æý©å‡„û™exüËFÕWF¹åVKÕéõ˜MtسÆÖ׺.< Tê¬Ègpd4XhÛö7ŒÆîÖ˜­öš&°Ìá¶V˜Ètµ.¬ôŠ6yY‹15Œb\`ùÚ;¥Àot‰²LýÈ^Æéé_йŒêK_ dEÓŠŠ™¬ä#àˆ’®Ž×  /»Ä“ *}±Ê4sʆKA¦½'ö†¹‡ûy`Qt§ <ð‘ΤÅöRM’”Açwl[Àx'´…»A;_PKòßiï°Ç^Jœœ8±:Ó¾~cúô†¹97¥7Pª`6СZ䉶!7"*m0C‹¹Ûû\hø|D’€ÛžgB7ï·¸õŠÝØdO kk¶Vº_F1&â³/ýÂn]+ Ú=…Vfl±>5&uñ`ÖÇúÀê-0O”˜m€—öw3Ätn |Ì }¥u„O]¢`‚ å5ºèN•s1UÄŸîñªc3“†C%ÜA. Ѷ<‰åNYoûì™tÎê^´‡+é»g¥|>ôÎøºÅir¿¥È@§ “wj¥o -yè$Ï¥M»cUö³ºLUªé™8·éÉT«zMãõ›Ì ð@O/ GÜV­·“sTh”­Š‘îaºR_Œòõžo& µýìnðc,(±Öoã9txÏ&–.„0$Lžäƒ^àM¹}Su/ÏC#ê3£Xm5¨€ó[Ú×÷¨uxäuß\ËMe3Òb,<æLÉ•ãw«ì…42Þ}æ'ô”wZlen¦ªò!cþxrû„eéã¾&r›Ê…z{¨Ôò}m*q —bžS0ÀB ˆ6„¾‡ç@DÝ“€%ø.HGsÄ<öÖÇŽ«K @“l ëÒFxÔMqóÙS^#±Qx,·bJöF`e­ ¶QOñò Dè}Œk´Z.a¡,Úé\uŠÕOEÀF=Ô+’„_‘ˆ7&Óz›jÔà?­'* læ"ßÜ7Üz]kÅ(_–àÕŠ6Åc P†*¤ö>ˆ?9dfPŽn{UÔ¬_$„Âs y“³m?E2 ŠÀ4'â‚6¬dƒØ%Ò–\Ã"Ä™®ÿíˆ*uäcñ.ñ"{JµJÖóø¿&“°å¦ÞåBY"ƒ@­ÙHœýmæ;¶¢eKú²̼3'j;EÏ£ñ/ þùUJ°Àê…’WÅ» M:hö÷wæYúã}耸4k%¼è‚œP„â»ü5«•O¢=(®úNÀËÍ©'ÿnWÙIuù|êbO¨Vï ^z™ü™$­´o-%%4ÃÛ”%x¼ƒ7åõU[/¨ ÕCFÔyr×}†Í;ç©DÆ™8̺’Ùî–FT1dˆô¡#CRÌ‹³ýO¿ôl?M·ø7Ÿ&ùô蘶/RL†¶Ê ;ϤÊÖefÁ¥âP•®ƒì”DCæYTR[$ ¯aYó—ÈÔtudÙºüþ{KiFµCft$šØÑ+ŽΗœk[²è×A5þ1:Sà'sdB¤\¨‰µ6•tBÿU¾gý‚ÕˆáօȤ¤&‰'ÔUËèçãêÜÄüÄs²3—‹Ü6I`J=§¡îê•IÃô $ß=xi“‡¼é¡§.ó÷SÙ—®­{H„ªaò^ŸÍ.¸ƒrÓq{£`…<j?$ÚqÑ[¸Ö »6Þçfc¡VWÿN”Mìu'k¨WîÉê¨SD p‰Ÿ„‡\£b!,áDÁÞ¸©­5]†»ð‘w·¥Âr¨H[…ðWÿǼÉEpó˜+ñ/0S8‡¾§Ö£‘3º›þ`Qõó“£f¥GÍî]O1²–Œi¬x–hîëöw Á䱂™UvK`ê…ËÔñÙýLüXr„ÓÈígrÒ“q€@êJO¾—|Ùâ,ù„:œ™“¿ýÿÿm£¬b4üœø+­>»EL˜ìì ~!É)MÄÊ$ôâ´2‘Äøå[놠ÿ£)Ö ë?g/Õ9©:ê g/iõÏ•PÇ ŠªòØ@™Û ^µÐÔ·Žÿö„z73=±’zULÀN¦”D=DÆ»œ[}êmÑâ–†:*(N+îŠARÉËø=­;© ˆSLu(UÑîó„µ×@÷H#ëG4ùd>4ˆÉèáÞÜç» KS°*a4’˜:sñ¢îò«ŸôÚú§Y\Ï4iƒƒs1ÛÀ©Bt%ô©Žì? xèϵðJ‘søè¶‚}\žUŠVñ •ø6ÑŠmÒŒJ‹ÉA‘pÈ"}ñé´(>Ô²×lÞ~E<ÙÀÏ„” Vcñáä+«ÊsµÊhj|KQj¨½LAÝëôÌHyÐRFG\0]« KÏv·mùoyÜ1'iü¬âœî˜ ´)xËÍã5(¤Å®$Ü ñnó»UÕòRö?tØu«#á´ñ†=MÞ‡ÝÑ+tìM(j"«j¯ü–ÐFït²_wF¤±Ì–çѲ²^ Øa‚y¸’zy|Ë&U®˜;„l Ó£täH%|ý·É»þw½fšš¢Ýe‘Ý&:σdŠ«~]°ý?‹E8ÑZ9Œóéçô×§“ s·líQ*¨4%Ë;%¨P³{j–þîŸ\t1o‹¹ÌJo½¢rë©2‘Û–¡‰¿É]ýYMtXÿ_›iܳK½‡õ±pbüRÕ^í&Œ`9­¶"ÒŠ7½ ÈÖ^­Úû1ï[%fël€/Xš_ÿ{"ÝX¥ŒOĹõLßËíJ;ÎèFÐ?£-f`ƒ˜ÚVŠË^˲b•e€Ê@L¾¤¹5¤±ÌYת {ë†uWA0çÖ‡µ"Жßó}þL¾·ü7D MƒgT¨–÷Œ Njí2æeûĘRl¾F™¢¯~óMÜ¿®¹ŸçZpáã,ìðŠSkÚŒèTÏ<0q.u,;+ÍjÛ²Ðÿ†Áü3½Ü",Å«a1!ž,`!Cã߈î±Ó©5ïŸB0ò™ðlçcòXkuÞWðÁÆË²›Cüw»Ýsÿ»(Äz—Xâ?úüÂq§üÇ!ÖifKŽ¢æ4&¨Òij^ è}B¯)O]òFòe2‘kП ™H2â]AðCjAW[Õ[/ê²:¯R]A\nGÕ|{àLj ðrÃTÛòœ ¿xãÖÆ#êw2õýËaÌÁã6ëÕzíHµ–À‰nKXúÐFD1ÕuûÝwò]ŸgÿïÇ¡÷\¯=ÒÞªìé®5‹Âüü»#]Úú¤hˆm~êuˆ#^ÁãO_PzÝËùŠŸ‡†d¡e=›û>74‹ß «¯Û!ËêzÏ8kL ÚGÿí¸‡'›AYÀuAáæŸpJ›œ§Üž7˜ùðˆJíd|r‰ðÝÛj|")4°›b(õ_V‚ºRQñíE÷SÖ-¬¿,`ËÄEãO7îY}—çø¬QáæY!ULB"¨R—LxÍÌ®ï'5'5¹ìÓÑ Kô(üÓÏîµG7Ÿ¹ˆ‹ïÐFíZWì›ëæV¼ç$ä$nD½º]¸àÂOc±( ³4HǹâÕ6s¶ýàXKˆ/Ò]àæ&夕H'-'Ø>›nõý‹X°@˜a…f%… Cðsžgšz":xó}#Žcà wRBÅ.ØÕ 1ÿÑ ¶Ï|ÝßGDˆ½Û摃2l\ö0pM•ÂܘÎܨÙÝYj'9–ÉÿÄ6Y¹!C°…bô‘š[6×ú[ÔÑd"Üy? ¸H>¨/g»%¹É0¾åÔeûƒåî>NõÒ5<.éx¥…P7ó:ü ºPk‹m[ÍŽ •ºÂ×Änž†eÝ7÷Ê••¹`¼:¹ž šV¸Ë¬>Ñð9­¯ðЇÌ&w$´DçNÝ™à×^”òö×Ìà}Üu`]ªÖ¹í¦!=_/ Èñ¬§1›èÀ¨½ÊoT—Cºt¸®Ìi™íºÒd,nIBº¢ØÒ}‡í ‡ÊæÙÄC²¨0¶m‚§j·±WcuŠˆïk|Yf^&xžN<ŸKéSñ4s8e—W YúW^Kù­WìhæeHaê÷|ö[W«¾Œ5ÿ 8Ý?4 3ÈŸÁÎÎ2ðG.(QØ]¶³|¿Ðœš]dUŒÑ«Ï_úD¼h-3‚º}mÂ/(C}9åT „`4öªZdÒu0B*d¼” ëï"Úç9¥x €‰sýP4P‡Ž-.Ú·ý“Ûšj2b‘ÛèüÀGazNÛ QË Gú‹ #†õ…#Q”×<0S ¡}‰*p©ñ^‘f»0xÞ—×14Ì[Oaã<¯Tô¡Ã8s¥hã ™o2{ aVy6ÂÝÛ^#ÓN¨`@(n?äsÊ# .N{ˆí˜ò"죿¼ÆÖ Í¡9Ì€÷Æ–„N”¶$*˜a Â1cõ¾K"NLCmÉæ“kz!”ÇÂâ.¦cÿy©UX…X….ëþàø~wGè‰C/ ‚ˆ<º6½C` ^ã”ÜÛÏëÇq(’‘·½%ƒ½21KN¨Þ#2}<³AMþîEاê®p4{U¬²„Fx‘+}ÇuŒ×ælðÛ„IS†³µˆ²›ÚÁ¬M?o’9µ9‚›vwÔ(hýóÇ©æÁÝ»²Î˜÷ŽÑÕ?f³Á4’î8Ÿœ¢UhuÜ‘Q‘CMy3•<©9Èléž ¿ú5ó uz¿ˆ¥rB9‡ ÿ¢”åõkÐ×x4‘@é÷»RPÏ?ê·ek² ¶V)ÀÊPy´7›0¥ÉO·ú*½µÇûÍSã)Ïã…,VãyÂðyŠÈЉ”Y»ƒ öX [jŒ±š€¿[ ®W¹lvÿ‹fýHuǧÀç6Fo..qðé˜-øN@Ϧã=èïXA,O°¥™2éÏ–÷ëþb…´ˆÕdj‰Góï•–ë{zV'd×Q(šceæß:»;B P:ßb΋!g«)ËÕÑ`·Ã­¼†¼á¼Ã`ñR ,•è¨ÜÁ°ÌCú "0? ÂŒÍÊeÀ•Ïñ%ó §Ý Šº4…ÀU–²MïçsEû^(0Šî¬Å‘ ®âlúO©ï!±å!Û³‘ØNÏ'øriºót6¬ö¾%°Eh@îᎩR²¨·m™|k;‡ŠR“±ÙÅrpÛѼ1jnð;Äyä6j9ÄMäÛÜ^Ýn¸ߢރè_k,^H8Y™Çwßäï:f¸%è7¦/“ò‰Æ Ðp÷Iˆs7³|²a•^Þb`Âl—¥¿G íhyvðßX×#q0ËEM°ÊS&œ& gÈY™ðx­3ñc·½A'9ÔÿŠåáA`¬PZ¿I±÷áãZ³[jY M>Èr$2:#†Oï?CY×¥>fè.‘(ÌŸ«Š«r¹¥É{ÒÞê nòUn%TÐgÏø;‹Þ݈1¥œ˜ÛÞ/Δ(ÉÉsÇœ°›16ˆàÄ Šbè§I/r³±ÑÙÊò)Æ uJäP•å1† näñò:Ñ÷ù|¤-Šn;%8xéûQ‘HÅríwA Þ|EŽ¡ŽvÀkNqLR' .íë®Ãç8Pÿ|<8:(¬ê‰ú¼ƒ{yãÆøöY"¿C¥Å,]Ôâà °ûœävÛy8äF™¼¬¶FpŽj§ô}íµÏ×\vB'»;¹2Æð'4@âÙ”ÿ±êŸaû÷ƒßófI­çƒòí¦^dØ›Q6K³p½ È'3¡!Д)á)^êš6ÕÖ!;Bã™ßùá:êGnÙ5å»9"šiižËbú£Þ§_äs?¿l¾ézøó$ÐrRŠ+¸™ä½ô&Ï MœÁ§¶¿ùׂêLœµô$ [„oBùoC»^d_ÍC\ÆÝóÎËÔ&Xð;š;)¬’ŽÃÑw+ë@’º3â$¡u&9pi%]½8g•¼KU‰ê¸5V?Ha^e“FœI˜Ä¯ àc¡Ê°^ÌôXêƒ4— ¾´»_šØ"ÆïŠZ_S|7ˆÂ«¨]Ê‘úGæ²>º‹Í´Šp¨-&!Žäㆱâá´FÚ+yH0¥5Ýyã«ê¼ƒT÷Mu^·‰dCc4öų•*ýc#^þÈÂÙuCh: ª÷;å<ÕŒY-]1 ¢ŸU,IS˜?“'³ ;)ý›tþüi3¦qŸ >Ñ寫ƾÿz9îI Ý³ÊE{„6ÆU•5Å¿²F',‡\‰Q¶„ånùÌ.H}Øy°RÁÈ t‚Q˜t!v\Æ'GŒ¸Ç•WzÊA›Á›â/¥ò×g½Áæ|+T2éˆí5±Û`o3áÞÉšB¨Û6+ãø^L|"•þy¼OœéÏàhÜ Û´ .ßLûU£4ïijA!ýžúþ©Ýó¨‘Íd-D6SÜ»OU¶iÖHóƒmšãdÇð³dÃå&XúP,‚•­^‘ÓÃÝëÜ~€æuÝz–u™ë~0tbó‚HacTXä.ÖWÚ"âX]e+S›ÖDÖu"Зø±õ¡È¾pzý˜µÄÓèo"<{KwÎì“v5õ'˜™Õ,Ù‘£ ®a5$~ö¡y7˜6J“5Ó~FT$ÏÊ+]* ¿ôÝã®- Ëã$®Uü_÷ôÊ]ÍžjqÔ³íêZÎ.€êUÛî îÀK7òpê­IxuDabS¼â»A.?F³ ô’nK·‡ôÙøÄc3ŠKÿÓÏOª£ 9ãSг>îÒÜ^æ8ÓÂq8ãpèCÙ³C9QdëQÓ`Âü¬¾Xk³ÁÞi°®‚'0¿ âPyr4ÍVïp­ÿQź¾$mW›(BVi({D_7„7œñÍV‚ÍÃàÝ2ó·ÞÆVÕè¼%W¨'lYã¾¼µ–#8ƺo£ ¨oÍI8´A!- …R ªü$_T`[¸¸×4J7Âßf/#ò4Ì­ñ~JÓ yïtg¨DžÎ×£EÒ\KŒÓܵ8¦6ÛÿRÇv2ÜHK¬÷åFqº‚"fcN|¬*”¹k(^™å™™šólc–XmXya)F8Ó&@qd´®õËÆóÅ£Û„NgÆ)ô&\Ã>Ã@’ sÕÿú£>ÜüÀmIu ÏÇñ-Ñý¥æUʑ֤®0S.²/è»ÏÖ¤þÍåæãøuÆàƒ—ráÉÊñfHšàZq„D?‡ŒîÐ8‰1¡Îÿzÿ¯„À±žP…äv/=š›Td<c/8|м¿½¾Ñåía«u°|OÉâá˜Lk`ÆgÀÑÈ+ÄO?z¤îTUt’ZÐ÷Ü1pÒ¸–·À¾pÐÍÑ'f"Q©º«G¡õpP˜'‘|¤”€A/šó­ôEÚˆ+¥ãÖwIG5§LÅÌ8ïd²@PâkÿФoúè©Ü ,2\™‚i6¢uó²v~íM°ê£ÓJ%k§Š]Æûr"`Í,–÷«”¶Á3¥Jé;÷ÅcD(3Uy–Ü8è87ï^éè¶Ðð3#âÐ,S*Eæ"/¨°Ž9ÇÅKê·Q n– eâ¥W°(Õ#ÚÕøxhW˹ì&‡¯fü$I{»Eï…á†=²ï'*%ì±ð‰4$ø—<‰|DŒiY¹Õaéb^ƒHóšÅ(¡Þ-9øRÔ.âK äåédAÖSÏIMÇýýo×ñØÁækOˆÿ"QL:Épm¢ºµ …Œ±éŒcû?†<µ~§½pœ·ÎÕìsˆpy‡Þ;ºg‚<ÒNSÐq²Õ…øg&:}è9ê2ÎÚNãùôŽþü4º“^ÔF§XNLÑ+Ù[+3s#È)_zÔyúü5øF¾§òiuÞ¥xì‘o- €[‹&—riÚ·û£Sf_þAá°ìRÖ®rü¹ñƒi-¹N"¶)G˜Ä n]÷ÿÏ#»˜p‚Y§?@I.†V¬¿ô$s‘ž7«ñÂëŸ^ƒ”‡ý •¡1¡ùi4(¶ý3e²á*Gq¹ò›xE‹M¤!_Fp1u¡&sÑÓçC@áÏLÏî¶VyF©Á4ˆ¯ëÓ|€Š?º£t¡**U½È¢Òm›+Õ<’ËþÚ3*‘Q% ¸Lqp’ÆÝa¥Œæ@3nÄØ5|í!»C{êú¶ˆ›µ¬±„<$峎Ǵ1iú+¬?üAk@2:G ùœû~l¼·ŽzÖx­ GoİTáý¬¹Ÿ²þã•Íü  Õ_âÞª9ILå2vàYåðp>ýÆòƒ«¬œ”7¯Œû$]KJ7:–I`yHüRÅ9£"oTÛÙ‰Åóê+xmá)˜ÿÜÒž]`:†Ý©à OdÛô^Ly$ˆ’Ô–2³ç‹Ù¨t8µ´6Ñhž‚}Z™×¬6‚^ëº4¨9H~ü¨}ŒðÊMêõtÇÆÊEÃ÷_ÉG+E‹«"Gw£8L½zL§:ZŠýÕ‘œö6Ç.æJƒû2<‹QyÏA¡ tA?Í0ÑçžW/¿MA"Ë-ÎLI{Çé’›dù ¦T݇@NÁÏp ú-ªÙlªmŸÖXm•áÚ|0bç³¤× £<À6ÐQ¦VÊJy匿DÉ40`'º -’¦$¢ Š´ü^ܪ®]?Ž¡Ÿ°ý9¶Je ŠìáK™õë¡H4ÒËù3ƧóŒøbûõ‰çïЋº+›~¡©…]©‚ÏËdbÔ'<“Ñ8ÀM1ù§;NhM¬e¤&ƒô"@¶UO9³Ø–m­{¥Ê˜fЇyª7\àR„u¸4F²g?6ÓØš¼›{woÉ=|¸oØ#I.ð៕H‚’Ôüä¤X,ßÒ°r 4fÙ»š‹,¡§¿¹ÿ°gÔ>CÙ6øõÇúwiÛ„ý_úbŸè²lHÍò½ÈS<‚š®HíI}_†ÿ[A{³Æ««0.ðAåðÕlZ„™Z$ò÷{%vÍœ-WýCÂ{mï3bÊ“èæ¥þ;U7”«1ŸÐpè\¹åèÜŸwAæ«mA×å«m¸"†'(u¥Ž…&zr.Ü ÞN©hþš9¹?lTD‡©#8?c°‘‚§àûó<êL9o¼l1Thv›”{ÍýÌÑ¥`pð ?þ† (–R“룬ð—‹|UÆž7œÀAclž«NQ_ |%Ár…úùTƒC^F†H÷ú£"fô¶ªþàS6ÔœvàV+ªhÏ÷ÿ#>hêrMûXÊBˆÚ„_9DèV›O^%„ºs‚¹i|«²ÉžW„Þý'#Üe bôØý¡1ô ;2Z`#`Hþ›-´ƒáº¥µU3>ï?‹Œ²²Kä+ð€Ú­sêÏ·Þþ¸ÞîåØN¸/[œe‹Ê†°ô‹ÎÆàë#»ÇdÆ)1½}ɬØ!ÕúƉ° ?€áÛ‘Óˆâ'¥ºÒ΄-öê´Õ¸ÁÐJ AIÄ[vWñè}-îÌÒÐÆöȡ NmõÍÖÒGÍsÍä)BÑ-9»²]’E$7™·'œZÉuÿxO@×Ö&+ j@-yÑF#ñº1Ÿ„{ýZ4H³²ïÎ#°ªØXÓàßĶË3l_ÕÿüRYÌ`¯ôŸu莀–Ó Éô.ERÅL%Ò§Kóîùïbæ™™Bù}†éŒ(”DXxüÁÓ©þJtà9L¼4Ÿ²¾ƒ¬géçcïè”§Uý—Ági¹ŸË³¹ÃnÊÐä<ÿö’å}¥šL$”X!ñ9f}:³u3¾Ã­j€2„Úzݬ¾z™­ ,¿µzßZ"?M\' Áè(…8È0æ.{ 0Åôõ Jïu<ÞG\½\àÄ;f¹ßl3Ë¢KG…¯¦ˆoi1%'©k@k§"èX€m)6A$D Ak—êH[7÷”?Û&yUQÔ‚?TDÛx´¶À¤(ÕèØé);¨x4œ¼€Ü9Óº÷ðAš¨cªI¶QQ’¾)cÖ\èÝçÕ¤³˜>ؼtÌÿuýšï᜘R÷a†à1%(ÃRHáÁ­Åß>AÇMŽbíÓ’ÝŠ6´§óh— Ú{Ö‰~'îr®å5*'à–NRÆ‘ú +©3Îü߮˺>EzÜlÑW»…P^%pº À~œ=¹F$Î÷^*Êz§y[”×ê Õ“Iù¿+9°Hš@*T'D–1C»J‚ŽçËHÆO{ ûÒ'l}'Õí%¾Ù½ìtÌç=Ûé ·vÿÁM3ð( û]ÍL¹¥kæu^·ÂºsgŠrßûyÀÑ<¯vi جÞš}µ¿핞”µü{ëU2ø¾Wcà 4$ù&xh5Pš[Yx¹k £ï)HÖZÙÙÉâ€b´/ä"bY¹ýæ5ŸS·ÿ›3¸‹4(MúyWMo& äØ¡íèƒW›Þ¡+]¤Ž¯?uk§ùw”×Ãk‰æÇ¬‘¶vþºVI6y1çi´¬lFc/Y {Œ…öû3ž(ˆ‘¶Ïÿ™GÚP ›¨ž¯È¼ôË¥ŽE³ÏûªD_˜Óœ¢tÂÁÈVy8Sl/*)ñyÏŠÌ*Æ#ÝÈVžï.US˜’JJËÁg¸h@gqÕžÿl¥“ïÎ;ØE˸tX©è³ŸN½Aê3vÎU}¨.§"¢ÍI‰ùj—‘4Ÿÿ%žÞæój5Ñ¥ÖTj%Ñ5+ó5JÐ!FÍÊMwgÑqzÂè Ô”ú½öQN½~òÒ#JóKyàuäÛƒ”‚r-ua¼ÊŒÆOëf°6—#7•ˆ_,îfÿáúÈ–]ý±Ñº¼Œ¾…ðïö}<ék÷Õ·ÛP.WB'˜ EÙJéÑjJ‹zjR3·lÉ£Ýd;µá±ò"ò£­$`2ã“€^ü$ éä‘Áy^ ¡©Ú‘ã}þcO¾ %@Ä?S\²ŒøcÓ^ ¥Ëày0˜¤€š{ãœ/„QlÆEïÙ=!´ú8€CÁ«¬Nµ‹ª"Ü'wSß•{ojõqs’ÁäÔѸýh ˜Y6’§¼Èîª;˜¦W°"%º€.Ýyuò–ð¯Ú¯ˆþÑÖ¶iÖÅ CS³ÜÿŠX(3ˆÁ9\“ ›t¸À{]ŽòÅ!Ñä5:œ·óÂP åí' >ûËäX.ݡªF¹[!Ç›>^À —Áæúʺçs žS*"<6ÿÆ·GSÈ*… Ýëÿ@ú¿ºÛÏZËr.X´¹gÛÖÏáS6hï(´ïÏxÜL†ÛÁÐÁß7éÆÝß%6dMØ0¤T¡BÏØóx1ô[rè=+¤/¬¤ýmZ‡§PO±c’´QSƒ0ãGçP÷¸%¤UUºkÝíGW€¦uRê˜@èÁÔe]†FPÀ¢ZK×5çóm0 ˜Ú!‚ˆÎZx*.m<2ò5='9¨It#õ³ŠP(ûCZ²£qûJüåAYÚÛjiRj/—GÓÈÜÐUý&*Ä% ,A¸0@r NV¨§³…ˆ^±ªÜB®{ÙvömÝÆ†hô€È@жðòyäÑ/{}Š;eŠÞ$•¼.—€±ýéÈ.Ö:Š]΀×W¹îeFË‘Ðv®Eà“°…}ôŒ3[øï“üD‡lÃn½¾÷f]"y?¦þð1z0K‡¼2øÏUˆ<—ˆ«²¢Š´}Sñø ßÇ(>¸®&`7ÈÓ•aô:˜ü§ ³”ã=ãïÚ½±Ì*ç,¢9˜Ži¬RªÅ5V'Û{†Žßê|Ó/BUDä÷2ÃÒô „»AWüØEáä³~n…| ‹wçÐ>%ÛÓ0òEŸ&!‡ŒIR>4šQê•“Óác$N¢ÍÂ1QçŒ_@§kÒ9eq=»¯8³JÇ‹5ñ¢ây\ø=túîP ¶ŽÞÀD ˜§HÀg{çÿØbç+ÍAè.Žc5²-Ò]ýg ŒØ-_C#!òËWYÔi£#Š #ÆüGz6§ñóp½ýeV}#K~/Ÿd):ûk½¯©Ðs•{š°ý»ö¼fó:þ“ÒX¸F£!½/€üS‚ô“–TG…vTþîüØlbmI¼»Œ[{É]»FT†¡[ëÌžrá7·š@•xÌ›R(û’öá^俳^k—Úâõ‘çœÙ& ©_5 ¦ÍòÚ@@[uIó lñó΄¿2X¦fXZÀ™{48^Éc9lý7,gà`N—k÷N–´aƒ³Š‘bÞÕé*‚“s§0ì$ @¶Ï(P—B&P>¡Øô³úÏ¿Ñí†G*N²(0¥“-*<œCÞsÝèÈÖt—rYÀ¤íT¬bp…ÚŸ‰ÉCeËŸu@þõ¶ú|¹hCYc““ý:1JÀ¤÷ò7kÞ÷Mæ:ï\Î]…—W3óªZ|r=·¿ÈŹ—àWâMn†‹È—XâiCuÌ›e6ÆdêŽ)ý¢MArÀ•¤Ä+† j¼´V zàS,Qý ¨ÌQ`Õ×Ý5ž¼Ü‡r 8NOb'{ ûìßûˆÀÌÃÂ?æUÃ}ªÌ=¦GÇkÓÔ!†˜Çg¿má¨ÕvïÊ0™º×Ú‰ND¹+ÍȈè¿vÀ èz|s Ø:žZ\þâeç—¸dÕ(Âå3FóAñëO…/Øcˆ6(–ÜhaªšŠÉ]ËôÞ¡éY}ŒÌ¿HNËáš쌻¸ü…8‚/?Ë®£H†é<š˜þºBŠTÄK°IOx\rò³½þ-3T[rËp2¦8™ì€NBšj?Žq»BËó^!ñ‡’8+SÚiF£‡#u£à­Z½–1lëKmÿ¦ ûœ“Cÿ¥)²Éœ²•[VÊ·øœ^H[K“bçKçþ…=øÊŠ0¬4½<®—B«U«†=rËíºLÅ¥Z’ 'ÄêT™{µR“Ý0ÌPÑR’D6°}ÂáhËÃR; '‹ü¢dMŸ ¿'AÆÆ\Fþsö¼¯ILzøGœ• e»î€¯Ý’–‹5‚p‘F*9Îoz¥<¤ì±.ÕÜhê%°¸±¨›J”Ô÷íËòÐ(î H ú]ÝÃgÁ<àyO[Âzù[ý°ËãŒNAÍØ™Ìö,F÷&hC0Ô­¥BÑù5¬_à5 Çø†ìª†K8¢ó#ksÕ×à˜ÄPePH }$“2°)Ï|õþ¨ì}pË3“±®™Žóæ+Ÿ7‚s4ÿhD6õ$àT~Š£¾áÜN¡7²œœšOÓJÊõ ¸x#\Aħuö%|­r„¤ÜSËÖ—æ¡ÌR·5#r̽z¸¶w,F†{fSa¿¿boìøàçPº±.&ßßâ [ú®=ŸI»0—Ã`èroù8èœì޵…•iMÑÃX2RÌùXÆnƒz7F«è (´¦ªÍ†ØF6¦#îWd¸65:¾‘LÿÝüËð8ŽæÈsQÕÉ£ö€“iA“B ^å6Žïädª)ƒ»ÚöFê ÑîÚg÷bY·•Ðäw /2ÐÐ\G"1Èx³N—Ïœ:8æ:,FÒ£¤+C¿LÒ˜"AÁVÞ$Ô´Îâ÷ùjƸ7¬*Ürjxb ²¶ÆÅ˜/­‡UMͬ“ .BþßB7>Q%hÁ¾Zî…õO–ì¢r·Zü…É&ªK’ª6#í„ ‡àgil¿0ȼ“¹„0. ~;RëK¦ÉåHÔ;<2È‹P{Ô™ZC é$ýN¶h:)9 ÛX ¼Gj¨¶Ã z½¸îÐÞ²™·Ejõ𲹫ßÄXzXrÛŠ•Q¾LöÊDx'! ΊT‘8ÍŒ; ›J‹÷uŸM¾78ÑÌI³=d„$w2°g goöÁíÒJ`9‘Á_l)‹Ì…®‰ÇÎ*ª´‘y&:Ð*â&ø#óŽ² ƒžð#ì×5¯6ešurÊ?Ü®Ên~ æ×ˆîke2>:’¬œ¤íÿS-{1 " þ<ä‡^í}¢Á²÷ÇRŽWÝ-þHl¿q#€Ù¾ð¢& ç0À¥ïš8›0°ÒaIÂ+¬3ï?H5Ýÿ Ô:•”ÒºÞ÷ Üã„@* Ôµ2‚SÂr£D`ŠÓv3Ô‡ƒ= ]bÇs+”d”N¦’ðÑE ÅN¢*0;I¦@R±1Ç>ãOòà MQ4Æž_-¡x¡Ð¬u¼6l+«ä‘Z~ú Î¹Ûâx›¹ÿQ 0>íæþkýk-y>²’,h6¸óñ6YóèÔŽ(¬ }øŠKà/çI¤¾æk¿Xtñ⩌ÅÉ-t–l_?Ê?e£„­×¹1ÙØ³µÒh9[î<Û>6Sqì´kïÎe*-–Gºõö7XÝÚéØß ‘âʽÚ4O{t”§>ba1F¹û'¸» íˆ]Ÿ¤ÀffV‹‹~'¾0⢴zô\¾jiz ¸§ÓšãºÍCéímñÓ–Ÿ©˜[䈡ÿg5+Ð|­FŠAݯRCödØ>@t´«bœSkA‚Òì̓ҊÞôù¯æi\Y.e^ÎyGv ê}•Õ©èW¨L6Cpül¨¢ü ¬3l¿ÒÜ8E‡Ìïûî=On(<0ž °péýñáÔpvV¨™3SþƒæOJ!žºÏEí£W6V®oœ`k…c³D¨ÙdÓÃWaì™îá®# ¢˜¸d[fDƒžs'3Þ#Ý+ !I´/Å1•­9U3À ÄЩ€™à3¨ðM*bÈ»‹¸°»tÒ/_Œ,'yhT¼6º»ï'¡Ì9&|×òƒOŒkŠ5„|1p}iÂ*¥RQU›šP‘ÏÜEŸs™¯™uïϦÀ¯·”º3*NÎ$Z²±Õáï‰'^ý¼b[Ö¯²d¢:°åÛÕï–]¶‹§–!|rÁ̵*i×ÊWÈäöÝ“âë[™,‘\$ññ ÀM›¸ZYo%‡›`IÍa‹Ù7‰¬ÔœåG=°ö½fÇqÀ"»DŽӕÏòCyGw[j9ãkz8аb:SÈSÚ›mãóÜr]# L&ì`s[.tûP1j %º_òCÛø!PبC¶dZwÏVùš(ßþ³V£Üö˹(`§@G\¿$T騮‡üÔñP»©ÁC¦¬IÛƒØÅ‹×'5lå9´Îzí…ˆµ¡–ÔþçrHð\ ‡éa±˜úy93U‹‘D­üŠ) ¢HÈpÒMÿVðA_Þqaå(k£Aæ«,e ìü¡~mh¯˜ˆƒxÎûv<g› Iøpþˆ9uWYñv“©;Fj–妧A}•‘uMd¢n‡v½qŽõF‹‰$ª–{(ÓâTwa£ì]ƒ•ô"ŒÅر*9«s.¿‘ÌâFòxΩBfµ¯¢n µ_Œr]$&…sã#5Â(w\/Q:ŒFÝ‹bÕ¦ÕÜç LdÂÃÔ›8ḭ̀RU.Èœ†á%g±éa¢¤/Šââà_ B⸗éAN|áYqõk[¿$ 1gÄÜf##»JÖÙ·=µ1ý­Oïx£Å™î½ –™¤*C›Ô.Ž`2ËgâØ*&l-’Á€/Ãýö¿:gì*dâNíçšš_–.m•ÅL#¤#¦ÑRÖÐPì`C#ú¶ödÕÐ ,Ù94Œ:œe aµ†®3yâuB‘¿¶‹qŒ¬¡tË( c°bK/fv1'Ô†®*®ùA›*v^Wri#P‹NŒ'r.÷ÍÒß^´:ƒcݾš}(\¨˜À VP“Å,ÞÊ4±jv.¡3Qtcþæ°·޹†3Zd÷1ìÑèú¼Õÿ†ÐC×_Úô·QNE(“ëo­&)ñÿ.àòq®^ì2ó‡­MÇE¯œ€ 8áî;¡[x”¦rܰý›Ï#Hz:#4„Kå `iÅÞÆF:š·@Ï6w%¡=Ä·{*ùÀø'¢À$¹´®ôàËÌf±u%3§gà`–?GJ¹±º742˜ò­ƒ«ß…¤þ¨v¤úÆÄ+.AöÛÂJW S²ÙÀÇ‘ÊZ¥*4Œ]ç7Ï›X#Œ-ÚG°/’Ö;¦1ã;éßPü¸ªá)–Ð\ªµ7¡¸À"6cº‚UÌ:Áï*ÐY!í¯Ð¤”¢„Zr/™/Ûèmú…·ñ*eÔk`²ÀUøN¿öF†¿¶ôÆÍás©jèýœ¦eþËþ?œËŸ„s¥EHȸ|‡¶Çøx2‘âòoùÌŒvñè¹)Ò“ŽÂÔîØN]Kšìð.Ò×bëkžH+»wWþ›žPê¬Cèô×.¦e Kį”neÇÇfP™¸b²±q§Íy¦bÑw‹—]:ö>JR¨Ìs“4”_²À(ÇCg’«Ø ’P•ŠHÍDÓw 쮈¿P!ÏͰ’j9äAÍÊ4CH£ È™l³-ó…•w H!pÈV:'°˜6#:†2 +ñ¨xèŽ³Ú Ì½é‰ßN—ÜtÏõïÅK§¯ï-‡¶kÎý‚Ñ>+^†Ë©ÔR°þJy•æö­ã6Z°Àå ÝòGh ;­p¯ÍýsA¿8ˆPŠp—ç[5tíܦ4>þ”Pfamà"ôšØzÄ:´‚ó}¥ [ÝÜØP(mªÔ¦gé'O½ã±ÌýDñ=•¼CUëDfÎþWª|©šø}wT3džIU ü¶_ ^Go[ÇW˜Y`é®TmÌ­ÿ‹:§$õsCmþ ^lƒ ¾Käóy—û3-={f×BäÖíÆACŠøˆ{LRG*=ç~³f«ö­™ŽÉ[Ü—½Øƒ ©,1ÔS¥aát]e7|õÿ“…&w Ä6Ͱ2òÃ"æÌM˜ƒç~Lïþ¹rAsÂË<ÕÔvH“bßfDŒ/$ÌÖ/Ëê1èæ2’z$MY  |ð´g²{¢šwµùTÙÞ/뢮ñûðšU“Ì^H‚h ³?=°r w¶A ‡p“3ƒrÝU³[G¤”ñ¯2²ž ô#l2=™*N^ÈUr梱ÅÛƒ¢À¨ÇŽKÏ{ô` ‰¨_ù@Û×¥ßΧ®étLO‹;²7×áÜ`»ð¶$€j’-ƒ8ðبû—1Ù·æ÷%9øÑ âãZñÇV—M¤3—÷™àkÞÑÛÎs­Ã{ÕK°À¬¸1•f%O=>MÛ8Øv;ZC׳Îmk\3[ñ1 œÍ¯{'däŒnÌ]Á°ä¦ƒKÅÖªéLl9ü €L72½”$ ÍàO Äd¥Ök|ñå 9ýgW蓸Ÿ”ÝwÆ™6,!fgíÛiκÊ)KÃCäv6˜´W™ÂIx•ÏU-‹\{’ëXØn$ÛFw®Ã¸r4à™; >Á÷Äò’£\;fÍB >•³÷Û®L)rg(úK-ñÓsÔ?¤Eì®úNúH„±®4„rcž¬ÙùSZ/À ó­÷q¿7l4Ódœ³ ˜MWi>—Ð/ÐËù˜ÇÝ:Ίˆoƒ¹Ææf8IFëÄaå}$€¦›/ß<ëW)ìÖB‹ØûZDº]|½¿e­fVs;ÌóóƒaœÇ×y{¢Æb ‘¬ß£&°«·‹ÑŽ Ê}Å?à0¡wÃH$$ÛXhkÔÆ²ï‡–.C…£“Ñ+ÙôWAÂé ØÐðr+kq™&ýÿŽ^ 2µ+ÞfËþRɉà‰Ï¾>ÆE÷yĦ¯Â«Í%‡Ëy@_ßÛZà»\É3±[‡*X²x{ÒHmŒu^B9¢ü±‡ 9\‹"…#Î_½¿î­ ƒ°¾Ü¹)²ù2{#Ÿz>þM 2^„É›íèÏ­³C×I)8eˆö„¬…—…b•Y’køÞm–L=*\’d¨ `(ÎJ5@Vüƒë$ÛÆ>÷¥Ÿ')ÝW”‹‘LÕÆ±ZXZ¢O wé»Òæ*bž`^­û“RЧ“U2„w“ñw¥Èå'ˆ@˜ùa›Í[žç¹óQEîÍÍ)2¬êWYÀ&ϳ“ÔÞ;'ª­LÒñ-jÁS4ã‹k´xnâì7’E,O™¼RnŽ¢΀+ šš×Fù¸4ìkúÈß1;S7þú*Õ@m9¶ÍÅõîuð#CNl:×¢óeVæ©ÁcJÞË´hóÉFÒjËsä oxòòbê”l¸Lmò¶5È ’ ´H^œ0ÛÙ[0Hßû¡ÉG.a2ž+ ”ô·'dŠÅfór£J¾D¢RÛ#FÇ¿>6IÓ¥¿Q÷(L4pH«`øpØL;·¨]$NÈò`©‰ §±?AD!9Öi9Ýk`)£–ß…pf¿³µ x)O˜%ÙŸ ŸJZ¼Šÿ ú™èuª®™>1ÍI’â(ĆçyÛ ãß‚eÞ04O?É!Î1J˜xÃ:e¤üÅ*KëòBÞT 3œ€ü!÷=åŠBc@è+mÞøž‘›®6´R8`!/cçƒÕ%…ûêpç³ôûúŽ$°ôCKý’>V¤!YʸB6<ÖpIð¶ ‘(RMs»‰GI²ç¸!D¹ O(m[5ÖY½];@FÝ´û-‹}Ü£kóÄaÞë‚­œÛé.­.N¢úËCò£uª«‡rûf}Ú¿ëÏ€šÚßÔRö-›‰ÄûÿÐù£u÷ÎN…1‹ï½÷öÿCK21­–iVèéyJé ”‘³‘;Ën± 5ĸd‡_õ­A׊ ¬‹H[Ñ÷ Žn†ÙDûÎÃIdòS•ô‚Ü>µ2Éq±ü\›_²9vä¯Z5„«äáŸd+ t;˜°$kf»¾ÃŽæ÷Ÿ6ì@§ý4½PA!"“¨›ˆq_®Á.@I/nµü”RéýI¼/ƒ}ºÌþ¤‹¬°O~QÑçsûÛ,…0à:ÛŽfr=‹™å K•Euxé½0 rŒ‘í¡¸>d·"Žœ/Ûm5ç¢Ð{=mRó½Íòü+­h#J|„8WøNñsàÑcÑå¼%rÝ¯ä ¶;k;²eÊÍÓž}„¹Xõ‹%"Ô2h†Í gU"ÇÍaé«HÏ ‡EœS)yTîO?·ÑèAµEýåzOŽ ïž&trÐØ‡/)sÑÕãÕæ–æí}ª».…Q¢+²©÷²»bÞÆ–Ð4$†Q¿;ÿ«¡ÿg ˆI}qî¤B¸ Êz…pëªg6ȳñëRÏ‚¶Ð b•Æd³D{C'²Ÿ£ ‹6}]Ù0ã›»Ýu‚lž)è3q&yÁ à@RÎÖá¹lAf,¹d« ã»ÖáO¯¢¡ïw=D"Jç+Ôà »6ìSÜoÝâEA&É2Ng8ñ!éš/—õ7Çg¾)§v1O²’°.UžëÒ)Vqs¯ ›e‰•¬$¹yeª'Åt!bÊ©…&0gûØÌLa ¤Ž6$Õú‡S‡y³g'‰Û¹ ‹ŽšÅ2ܸީò7Ò“ÍfilR|¸Uph­)\@Æ—ý²D‡&Äc±±hlNrFö]ãúm£Šp5î2ª{ÐS°w%È~JÍB#tâOeﻈwóa p¬~J,©Dƒ²Î¤ :efí3ÿûxøÊi÷ )\d#F(4x³#„2|/š>ëþ~„¬kàd Ú´ï\i-v2ìÎd„ƒÞ¾$cCÀÈ1Ezú ° O$‹ÙuÑ6(#³4È®åé¹ß:+ UÑ”ëp è x£+ÃY)¥|g`4ÈD:rΉ}ì ¯¶èwcjPƒÃ5]ûËÖ»mû´Æ¦QWÛUëÒ×›³ <Ï‚²ã\$A¥•²úÕÔ83ºã ¾g~Aˆ´IÅ¥:9ùvO‡f{ËýKw4[‚·B(ä˜âG—³žžÆžŽ„-Oþª`r%Ù˜š„+ nes¾Åî„Ó?rïOO4o DR³®GX]QŽu±°•žìŸ3ÀʲžØ´¦Q2V¼@«ÎdXÛ|Új™œ3"Ñô5Ó®¶QŸ*.ÞÚ®Z,wÊö*âøÃº«‘”üe‚ ¿U­¹Yäi°]B]Û^ðéã$ÝHYœHµþˆ¶´åù Û5 (çй²åÒJÎÙ–Ð?»ÈëvèƒîrÇŠ“|2 ·*Ì#³Bô⃠ÿŽ6cÃßËU¤_zÃoîö‰3Ba„’6Εÿsñ‰!(ANs{׳~÷ðiÖk”d ìµ;íø+ jóÒžð¡„ Ù>ðOMæ ØðÉL3ŒÐaUIb&Ö¯g²·Ib(NãÌúzÈÊÒˆðŽXM€¤ÒŸ‹±û²¬lïW⤠‰;TÂþ!Î'Ô‚~‡ì4È%àcú>HG,Ü@¿s¨šˆJmÇã%Hÿ6Mص²YÆ®U¬œ#ÚìP¸–¬•­c1¾†çÚ\žëù?Jm}¹¢mÐh†¤KñÙ%ºã6!¶§¡ñ·ø½ös 6ÅÙûÐnB°ÌÛ•–Ž·ü5Ñ& ×ÀØPøn hrÆ7)©»UÀ±}#°6,ç#)ÓmœxwçŠHs»vÒÛmûgìùo(ô˜¶ÊÌ1⹡–w®uql$1 Í{_·ëF C&*ˆdaêÂ’b¢CØ‹Wù+¿k;ßßE%¢š!=o.ÊÅç>¤rîdduWTËÆª€šýºÃÓ¸û¦wÓ" ßj;ÖòÏ‘E@ë]˜ZñiBª‘[ŽExËUòGCà+÷÷RºWhß®ü´Ï]êJ—zsqÓ j™)T [Ÿv,T:ê8ä]»ãˆ(Ç[‘šŠcÌøóº]‡,óŸ‡È§µqB!â‰G„tÁ»ÄÂYr£—%>= ‹¿Vƒ‡g>ž–XzLB/ÆÜÁÏo™½ö ML6Œßî qMc%¬ÀßXr,˜´|É£›æÃ_P6ôköœ=In·lÚÆQø—š·’âQ’‚Õ]xd„bÀ4զз|üD0XóÁ‰D|¤~ŽCýGÕc³ã°ï‰ž ê²1\Œi²/Öi‡ö¨ðIhÎ(&Ïá¾1\‹üÅ£$^¬ó²ê] ÚõI£3"UcjçÄgå·Håè–Úb[çŸSÜaúFÕ}1ÔnR2QˆMÀÝðà§9P}¦nÕm’•’¶_miw…zÏFî¿óéW\MQù*ÎvñV¤œ{æ Oõ/"¹äqMýøJ³¹Êa¶fƒÁ—εþËqâ:ËäáW> stream ¢¼¸‘õÖä¡Uš¾(óËIì«ôwçÝê!1ìËJ,¨+ZËàù¶Å+.$rvqä/ÁË#c¬\‡_¶dá~$ÄŠŒô/몞>UùµÞ ë®Ë^¿Ø¼è ÆÒ »ó}búP`ˬx#rCŒóe¢a…ÓÝï}óWÚGXÉ#='7ý‰Êõ9ƒÒÄÉûÝU4£¨ÌoË6íCºÅuò»æCËî1ª} ãÅ"ÌjcH,Q`p»bWO=/ ¥VëÔ2ka³—ÅO' œMôK¾{Hyí\•õàö—Ò÷êŠ|¶Ð/-¯Â$=ߪëMƒ­³à¤fßOJ< (zö¨¢uhï7¡ënûժї]A/Çã¹¶»©]{È‹XÙmІ€ËÏEfó§W~úÃÜ迦HþB’«à@íü»-oí ·Ë:,?–ž^Έ0DMÅÆ"wW¾žõlˆ!ÿljùFŠðûªÃø%GÕ³‡ž•Z‰È¹à ”ýÒ¹Ï[Vß8JxšöÅ¿÷»<ü ¼–çGIvv†Ç8;8´7†ÜÀ ¹¯Ž½ü`tXºDœèÈ_`7„´$m‡¿7šL¬ÓKå€àœïS’e Y»£Ñcî8ä`Fö”¼ˆ\8ªÇÞ\‹) ¿Ჩ ÿ÷vmå;­­!VláPã*%‚.À-…Œ&UÁ´øýùx9_c­–óÑegS™rÂÂð¹óQ-kIpñüÿ£¥Ðü™s¬O¾g&f"UwøJ\jO?šÇñ>'±{Tv™²¨­@O  Þ8wÔV]íö¯0Ï?igÜ-5ý­×·íèö±Â?…Ïdk•iÂ0Wåæoµ Ÿ)â4b¢Ö¹Ú%‡Â³Õ¿€ Ê5H–K8Q¤4˜Aå;ˆ„Wù;v€2ü± F#å$X…$ ª[>9¥ U°¢…ø\L VÅš.ñ¨Z°.$ÿ±´†Ï9`p7E»F÷RìGt~Z_U*`´Úã%±7Ð<øêÐ Zc òìûÑ¿µ8züáš`É]ꆷEkç"«D¾Ú±!\m@€À#ª÷ßa÷õ9Òc@ͤðôÊÓâ ÁÈGK³Â+¨×=Ý%ý Ê.ÈäX'“]áÛïÁ^*q,1j½bÄvyj7X;ñÄ%1½ð]^¼LëUâÔØ‡°ÿ/“šÎÛdëj‘ŒÉ…„)˜Œ8ÜÉjÅXjºŽlÍ›q\«?.× ÞÊJõ“zÀˆÓÎcæ®ÆÖÝÙ L§ÎrwΧsG}+r¹VÕC9˜8ˆtÒà&>].ÔƒæWö¡´ðÑ^^V¥ÓB„Åå9‘L”$OÃKÃt5t3>q‚¨!·j¨†¬Ï®¿zç«se­À›¬÷Ûû¬:K¼*©ê¨Vœ³O¸§‡6)B´Vþ¡÷ñ¹£¬/QEd’wði°óD…3²Ævíóê`zº³~‹åp»…ÓjýÍæ[XGá¬é:eP@”=ÿÅ3}´ÿ”’ÝÞËæ½°YˬýµØ^ýÿÝtré¢ÿÇp/à£>7­ˆ^»OÃÊÿŬQj(…3IQO´–M9KÔPÀ± ?Ñç-Ù4¾á®ø)Q$Ô v÷ º¢"Q èÜ”³ÍŒ-LRþkÑgTm´¶QЬ­¿,¢nõ3a.Ì.ÚøÄ{e ¬zØÔr4 šv–ÉóÝ! £{i¸éþw<)ü÷7üñœ;- ·£_®£„ÁOúœ»)¼È{IÌ]Üé!ÍC^x3ü&›u W»(…«PnYCQÂÁ&0qLD‘æÑýõy©w ñ»]c©Ì2Œ´M8ÈRŒ#˜°¹Š§•[³7S¬âç ª=kó4¦ÎJ;øÅ”Çy¦zè6ÚÍ¥®‘a/Zw¨Æb_…Û§sëPèBămt2xçâ·¯éªÜ¨ßÓ›vgX=b¤ÙZôÎãö“Ÿ¸s'‡oc—°ž¯É8yöXµf,!PìïæÜòg¡%9«ZP¿òWëÞ×Z¤±qîÉ0ÖpFU^g¨úgѱ‰J2,*í[F“ÙØXå}]P²sî¶Ì wÔ®ãÝ…Ù>Ú™%‡5øoZöZ3é ѸÔî(e›,»)¾†-Oà§Ðù˜²P)F›T²¾Ð·ð[õ(phj>ŒË[ÌBÎójŠ,爼ŒºzeÅÌýÄ&ŸQ­ðäQŸuRÍz3¢eˆÈ°îﯜ˜£à>­§Îÿl\4AP·,¬ï¤}WÊ)|Q­ßÆáó'u’ÝÂÅÑ´HŽôd}LH€Rl¯ÆÎƒ~<¤÷¦ÿï¯Û“ Eœ±s±‚˜`t#Ò\ö¢v Nφ֎?²œL‚°Ïü¨š•-Ó ëâçi6ØzƒÐV_™‚T °-÷âULÞãcH%(wÐ`DÁáÍ„c@o®ìdÿ¾º„“V¿<ÆÝÖñ8ò⥂oéoŒú?FÌçQ?¸ãŠý4£LO:&!øM5F3Ar¯þ•§šR¨_›sÏa6gF ’e@{ ¥‡CjK…‹Æ/-õw2°NâmÎ8—QôKÊþâÃûiA†HNmÉRÜTƒ§CÚA1«‘4æ›ùÒ?“ˆy¶õiÆyBGÈn¥ýÛx‹(NUª1k¾Mùdô4EÀõQ(Zç1#â½°[w.”ôU3AÂêÐm«Ö~±¾xM•™hwÖ¶§üêcD»Ù<¤\'ÆO/ÞP§ýäàyi€•GyIzÛº?•OÎ0 ¶M4é;IÐ_Öv*øsDÌjž´Á|Q¸ªšãaû=éB‚Oôy^ÆÜYëúóÜ¥×÷ð N툎˜š©'½ Iš;Åž¤ßÞ4~mï?YÝ/åð€þ•Ä_Óûª£ä,’Ÿ)aÕµ™š'È9·øŸ6$¾ÀƵAZJàÐÉ"ã•Ñ`aR´éóŒu|çÓ¹Ñj+±ïÍ2wÛêH¿.îÀlcMNËùÚLEd+Ûé†â~âë •—³ò—Ôº†¹È ÑTJ÷—hȘh?¤C+¡YT^§hbhH:¶ØZ·§êÃÖwÿò÷4Y.&óB'€†ÙØÍR¦GC ÜGéû¼ãŸTiL&t»¬ÍïdÛ5¶k­W!LºÖ ]ƒù6òÄSÐ7ØÌPÍ’óõlã†\qU„ˆÖ~v»lºnòAzWÔÓèùÛW„I¿¤'ò Å㪲}ÝrTW’ö^y*S È_st=D èµnø!ëËžçÃŒœH?ªP¤ÖI›‹bYN«ã¹ F<:æw×$Ðýyzí8lyCŸìa Ù&þ&Wí1ee›¼(ã@–Dý¹°ó˽ÐcÚ]æ_ÿuÙÉËãy"ÇÑûÛ°Wg ˜øeï`‘-1Ih§ˆº!˜Õf—Rô“ƒ½bU1!Þ×o!Î}}û 1òI¿â14]ëÔ øMæà—‘ÿèœ`0I¡{v9 c«'‚Ñq%’¼Ûæ¾¶vUPÓ˜ó÷¤WÖâvW¬¤>‚åÞçeýÁú&Çœ]dý©è”¯õÅÄ#22ôl¬Ñ\ø‰  {pDrÓÑô‹ž !»}ÝÿsšÌãÏ‹ÐIofncŠŒ6„Zˆ¿ tëú°o´“ñW"çœýølj<Œuj`ÜŠ-Ç|S ô©ü6Ó Ì<Êÿa`Œmv¡¾o^x:ç0B K³ã oê5·÷ökUœ —Ѽ#f  k>|nVñP¯»Pb‘y\W¹+X÷¬êÏB~ò†{òq{£cjºìš:u×–Áâ7ˆ<@úxzëw«~Ÿ"ÿ(GâôTÆ9F,ûKR~r«Êþ_üµ~ön’|¯­þô˜"idÚèÇñ´ÿ¥ÿ\.ÙÁï³Ó)Ïä³Ð;4¹c3{?žã$اq|ÀµR7dèÔ1w"÷cTa?,Ð"Éú‡ó¡ Uav“ÓßöhJ?îQI¸Dí™=VgXi1CG„‡Ê‹vÞˆ˜°ör(‰W¼œði-w:»¥¹-«É„ßFÅöM¢4ûõÀWšƒ¯Uˆ~Oú˜¤ârذ"¢fû½;PÈØƒ­ìÕ Hµ~B(ßRŒC– ÿÖo›ÜUÒRËĹ’Û9 £¼+d#ºtrI¢`yÊ–n±ðÇžEàAŠvaÐËåÏx¥¾6ã›`-<¾m›tÅ7(ÁàŒþc ÅP£>ôKBÝ´Ì*sÓZû@ß@ÙG77ŒÉéŠLÓÞ¼jJÃR ±§‘tq~”E ñÐ.(#oûåóôIá‰1ipÌß¼A¦‹ ¯¸À®<…ß­N’ž‚#ÆÖ&ýÕbZ›± ñßgLvÙ@\÷‡i~»ýýø}½#6 Þ ’n×Á²Ê¢-RÈ|¶˜`­F„j¥uÿè£Þf¨É6C»íäѵ­‰/jÃ=ȈI‹Hƒ¢¼“Ã…pÅ õï„¡Ê~醛›´ÞƒdD–¨îS¨}$QíF@uC#BSZ>Ò ÒÎ$µc#»6z°+ó–>Tr—èT†²ˆSš#ÂX'c,ï„z'|øõ­!î[(LŒÏöÔ”ðâQ©rº*ü’†›Ñxð•‰$õ¢±CP1ÖÄVÊÓã¾nvx^SØyÂØ+¢J­XëbT½ú¯xïÔì–âÁéÍâCÕM¤¬P¿¢¡246P Ñ]›“Û‡/ç•>³ìÖ@ ÚÛÏüÍQ+-mx“‘7bâGl¹j•n)ŒIùBÙÇ”ú=“$Ö¶añ\vÑ‚JFǬ 09y)ˆì£ ƒ˜ZãÏäŒ=Ê¥þêð%yœ©—iH>–Ž#ÿ€#%’jLÕ# }+5>y!mÊœdýb§*&d¾sFx…=ÒZøé˜é ª–hlÃm‚‘{T•S¶M¿PhoüxÉtÒïèÄP~NÓ {ÙÂM\îµ¥ö8ÿDµz$Ùõ‹çtˆ¶! XM¶pä|HÃâIc0æò=*¯ÇJq\\6¥/TŽÞÊvP©F=†Eªògqˆtõ@Å®¢·jõŽ¡DÓ£µ§˜ ñò•f¾Fwt¥Aòä›Ñö ŒÐ3J`¿Ý;vƒëÍ ÷"~f+Cõoã #W½öf-{Šè›rÌV’‹£Ø‘§ì„ß×Äñ¹]Ÿ£sÛÅ;Ë%hA\Á #?š.Òá„þa~´ 戾^™îá²@ªí÷Wˆ›Ï-èCAR;:å<"±²…nÈ (ò$nq‰\Û¸&}ÜY¤k¨ÉÊ»¨4Á N‹V4µQ£ò'ù‡v„b•€&CFÖ­#>/®7ýäãÿŒTÅpØ®.<ö€ã ¶¾…¼·ÎõBr‡‰hÇ°Ú ]ÊÐ.ŽÏ¨ Xø¶i¡oÑÿËò¹þNÄ0…„ôþ»ÇåStp-Íñ¦3{ÏŸÍ@¢Äñ²-P´$Š!` Ÿ9]úöµ×;ÏùÞöÜéæ;¾äKG¥*|ÆÿëN‹¦«„D.³EúU«¶§ yYÆ1O*ÎgUªw¸z´í™FŸF¿Öy®røv[¨7¹ î1ôÅírc€wLã+ -ô (ø¬íÄ·Y݄Ě“–Uš(Ÿ–*®Pòa%z8[šfUºGdp³ƒÌ›@¦vóÌ<™AÅéªÙp¶ýƒ¥¦ :wðŒE¸´Æ$ùÕ|Åå ¾%Æ)>Lôô<>ósêþ§ôî{âã<ªÉ/žóÿ ýœ—œ Gÿ#+ÿ4—n­¯Hðh‘Éh‚æ.ït2Õž˜=þ«àa8=i!^¹(°ªj­Þ…ÄÊïˆ)Šþ iÝM¬ÚaäÇÙK-I½ü“PYœhÍõufÖCV£Ê‰OÓø|âmW+K4ÍÅ7µ·9KØ[]•ò€©3ò;[–5c†j;ìà#ƒdÙ†=íþgTuÚã¼T úTÝ€Té)JZ$Q»}ZÐ, N±¿Û”‡ðK¡tˆ¿ûŠ>? ä߀æËܱ“vî„Ó:5¼‚*胴âz¸°XaD&}ãwµª™Âœ¯e?;ƒGvwW7`|ý­L‹6ÇŠ;;d[Э]è6fu@èý}Í÷o2 0AfÉÛKšxP•¼E§`£.½B Êñ±óœÒoOJÕ¢Šl#Ï…äˆ÷ûo/b>¸ÒHo¸ySr§gµ00Ö26LX¸îÙ)Šmɦ<^òÔ~Ï/Y{IÜþ z£~gŸ4©ÆØ3Ǻ€;¡·ß_ÀùlñÙ9z¼ïùsL¦öóà?ev •,TJuåP"Ú÷ŽË»W®•Œ³Œ¨ÝÜ®sI¡Ñݾ4ÒðmÏ8 …š•7”~”°€[ÿ bÀ÷í(ƒÈ‰"=Ÿ¯kUå ƒeúä' Æ•8ÐÃhK$ùR׆Ôü8+,!1/´Íß'8%šÑ+C9,Œ¯^æ.%å3Öóÿ?¯ðÃÙ`ðªc­™ª‰E Ó ^REžeƒÊòÖþÅ—/MW„*…·…guÆÐTHfgvîÏ’‡3–3 `–ã²1qä¾òÜŒ±Gé9riïýn=ÇÏ­Ëè}“7š¦ é§Ò;Oü\8Ôöü¥Â¶ÃŒÞË͜اÚÎ PjµÏ€(Uh;tîlœ­âDDËm¶P¹ ]µÍ´Þc©tÇ–BgUÉm@Ò€îñÑÒfèàÄ­–€_%Hvî¯ð:7}ئ‰Z|¬a!ðÿ°ÑƒY²Se™G¹,äNÖf˜ð„ua¿…]gJ؆ B’Y–@¤˜Ç¿½*¿d*jØß]® #°ÓÃàÌK’jÇ wHÆgNäâóæÝìPü"4Æ:E7 µÇ/g¾ >:$ù¸k•üž,±«‚XL»Q3ÙŒ¶—›ð¬$ˆÔ™wï,-0 ¦QËé@55µ(‰gøU¯j ÄiÖ¼›çvÛ ¦C`eµµTÉt’iT Ù"í%oöÓ á}äõ#ϳ§™:â ôØS§#˜ÛÁ['q ü±{Çó8$¢çNì—˜~ v("Š‘1¬Ù8Ê’Öñ”zÇ›œòÍŠ?BXO‰àÔˆZŠ¤Í¾ÏÁÍ;5àðÄÚÒÆ$‹·aè¼»6 a u´µß>e*’¼È‹-õ¬zhRblpBéA­Q­vMÙ„)@`¸Ðj¤®¡”RY8xÐFØO£Ž¨îM­¸z…-[ˆGWlºÔ; þ~É­žº¤tî¼)i¿ªš@×6ÍÕ`üÌ:Z|ì/¯è|Ó dBŸ)8ö/Ï9/W9U—UÔx$ç»Õ#áÕÜKþ͉Ÿïö‡>ÆMÖöÊÉDe(kñÏ%óçÙ]ž±(Ë8˜;˜­Ù¢gá-mÒN×­½²hAÏ“CŸD²ÔâÆp¼@Ì?^ÌÈÜÏïÁ"Ú"³1äHgQ£eø›Qq$3ÿ(¿ay3½ÖSc,{‰ç‚eïÖ|ÏzB²™¬>ê"<ÛŠFé4àõ˜õµùà0ÓV¥pÍ<=­”Óg2Z¶ôsL¥ÙµÝ¹8 g€ªA²íªD¸Î…A®·{Â‚ŽŠé™úÈYíö(uÞ ]©›Qï˜I²°úLHõëÓܯëô¥‡Ó68Qfÿ&¬Äº û'F)¼ºš·‹ÄàÝK‡UÝÄã}ä[Z^ðàè\ÿí?¨«ñ•úQ‹Çñg“´{Ñ)íÙAçi…¿Kk‰<€Ïˆ E^i!0Ê·ìáW3–:,Öä¿nêI;îýi“TÄ·ÓK&nqÙóÒb×Rã/P‚’Ͼ_x˜j:³ýnIÀŸ÷§5à"—çsí–€Ù¡ª ß–(r’¬•yhƒæeìbÊüq¥ ‰k:ƒæ‘œ(úH2¶RÉc/†Êƒï"#øy 53Z|åõXÐU¸ƒÁûom—æ“àÃ뤑³lNë:ù!Erˆ)Çô‹ËÉ?(`÷êXd'"毴=1™\H¥¤>g-ýþÚÌw&¬ŠÉ¼“FZpTÄX@‡J@¬ÖŒRÝ¿Qý²ÁÄÞÈ©­wôS°¾Ä½M­)êí"Bp(Ì}= .ø¹ÿeuYè¡—;rŽ'¼e28?õ<ïH¡YnýÂf•›Ãß)ø¡Ëú;øº¨sPXCñm‡ @”·P3x¥º…&Íø `‚Ö7”¶9’4"¢¬Z Z¼ÎÊ¢©ƒSU;‚É–Èc7|\ª×-IØùÁ«*æÒ!²Ïbšð¹¿…ÒGxë/è /ä‘*c{&àlãü,÷ÅaŸô 'â\kÙ:a߇óœI7ñJ&ôõ³4­…Ä ü;u³báJÕ ¦ Ð[õ¹ÒøÔÇï. ¼I˜Éi Êüù€¥·Þ$ˆ.ñ÷ñ“:iBß´€¹¨c4èUî ®PÜY¥ærÍmXËCE›ë#j6ŸC¼GKô!GóŠ{é´QæRŸ;„¤œªý:«ƒš8k¼/ßÉ–}Ãn}ñ&[F–ÓÁ”2µ:þÚÕQÊip¼³I hOÿ6‘HôäE’l¼s¡#ùjJR†É0Þ<¯­¼±Ö¶²+øp‡0D *ÞØ»‘)‹^ÅŸÅÈ®-¶t<&š¶’ ?Âé].÷Ó°Ó§”¬íšŠ¼¥TV ˜QbmEˆK(%$íQTc®)Íq·Õ"wÑbz]ÒùÈ_òdàá·j”RëŽ G1™õÉÄcŠg¦÷(ߥ¶{#}K?QÔ€CÞCŒKØ §‘ПZ>àõÆÍ)5uõ7™çam¹pœ'Os,ÎfUÒ±9Úÿá”—ý{–ÊÍ&¼—FêÌ;*{’kÚØ„Nê­)Ümlˆª¦i‡# Â ¼>it/ÆÑ³’iÚ%ÌR÷k~N.ÑÉ÷fnLºÿ‰eràÑ—5ÖM5ëË6 8䘻,úŠa.É`Có„AfÝoäz°¨æiÈsÊìß@f|€H¼8Ñ.ô`ò5ÖÓ¡4ÊI×I„êš¹Ž£"‚Q•ŽØh°9lPŒíp£ ö=VJZl¼°&Í“}“ùíðTÉu­SF:p8²©¹öÙ ÎÁÔIçù}…c+ê´yÚ~óÝM@Ÿ¹Å>gÕ·}gÉ,Áø?Ô#ŃfÆ'’;6â)×Ño|fõAz9ãë7#ãK nè…ÙóäüZ]àë ›ÈRpG½ýa¤’‡^”˰ÿ ¾-@ÐÓ¡-+5ÃPJ°²5yÝ•µŽzrçä§;xïl÷ ëéÛq 0Ë04•Îz&ȵ>8]ë¾3í ï w´Ùsˆóµ¬Þnfˆg“¤ÒdÁF‰Ý b"ã×I&‡ƒ”F0@Bleå“óS#žRLÔ´_é5³†Éƒ®~©Œ–È"ƒ¢ÀAż|V‹Ì«#ë¶SŠÌŒ) ÉÊNîô×ÊÈtyó´vœµ)£Àƒ:ià‹Q¹6ÉKÙÕ~01'7·²ZÁRÐE úÓ¬ŽW°¤9KÏ#î­::ÙiYmüåD¶u©·Âòà€„”ËBÅðÂ’í–ƒ—cC#¥mé‚öã¢þ¯0£à+å»CWòD ·eò€ •º_VÒûr¶‰J2Wuï\ý‹Û&•|g¦:<ªY¨î ¶;P ²˜hãåÄ«6D<Ÿ¡µ -(])Ÿ)3Öi{:%Öf‡(T,ž=ÐÆH.Âýä÷…íܺ´¾%à…Ð0Dñ³Ô‰ ÿ¤vô°OnúoEF,«+¦¿DŽ QÁõÁã÷^´Ò£»ÜLðdÝõ¼(@.!dŒÅititÁì8©äô&ô@î)_Ø’€¹s—›MõÇ}ú±Øÿ6؇W{Ø)Ýù测TÙ€z¥™§¡¼¡éýŠðâ#\¹- ï[z‘õzn KÌ÷'êØ¦5fAcÿ¶Sâ«­mo†-ÀD×{Á+ÏÏSÕæÎì Ñ·ÿ1dÏã‰&7莑‚‘x0Æó½mýÙY°»C þ[)€²Ïš±ÎûùÎ’A>S]£[TnžÆdˆC¹Y‰I(A16 êPWˆ°±æÑƒãö ½d^b¨@*4\As,Ý u*ÒÏ.´úvœÍ.Û™>sþHeŸõê?ÅÁ“jeÔ(ÍÍ::U&òê×%p¹›šžt)8C¬ÏèýM%’íz¹‹YÈ¡Ž!}VRdOkŠæ]ªÑÝi] dFƒï¸9ÕÔÀàfÏZÓ¡y@ô>YfÜ4;É€²ø$V /Ë1+^šxSzø0}n“³!OAçó5gþ ݨ’>ê}Úßù~•Ãtö9Ý*ÛˆÉÙqr"ÞÑš:c0FRaž P[¸—±ºdº5ºbCbµ†×…ÿk6r([hè1Ì>Ô\¢‘x6BB{3VD½u¾¼íB‹E>UKwѪŠN¥¹ñÞ3^¸ðâ‚ÿ!ˆiçVÛ•‰³ñÇ.\•éÎò8–˜(•Ð$mYÒ!Åd1„õ¨s:“ùpáÒdw^N².*£áœÓ;Ò$þ¿@{¶þ Y¡o5³"OHrv‹S7ŸÙ§ï]…ÖÁg­ß(#”*é€ÅÓ¿ f7€á`[õŤۙ#Ù/ük¯õŸ+Ù äb'mÙà|8c«˜@•„¦‘¨Œ¯0èžÍ;:YämüÊhN¡©Åô ÎèH@2ÚLLÄV)Íñ×Cž`ÁeMP½}¶:¿QëÜÉŠH¢¬¬DM1W“©{"Ž¿½ÄÅ lzÈ£ùÒºš5r| è@<ýär|uTz ”Œ0 žÊÒ8Z®gÅoȦÐd¢á¦1;pC´yÆ2ò3E¾ …)XcÀɪœZAlnaÕ8ÀÛF þtd¼ØS¨³Dð8›é))¬XìŠÏÑlnèpöÉ ¬Sîãmu£Â¯Ýª7µ³”´eç~BoÓ½¶¹‡Ë<w€hoV¦+°Šü„ z÷ÎáÔ7û»ëL¹+[ªŽvÔ’Ë®<œIðé7 ìLJ¤Þ-“08¯¥ñlÔmn»VÍ]„«¦Þ‘lµ0†3™Ëw®q?tLônž[¹NkýåoÃŒ¨õTPŠ‚xÊCÉØm.Ö | E‹"à p¿ö¿ñµB¨P†ÍÕ;V_ל‡зwóuŽíí$ôÐôÁæFHäwfÓÔÞühw©Pvmn”ì´åcgýg@ËNÿ4‘%K( JÆ%Sb¿,¨u'|?>öðúOcò·'¯’߈AV ­6{´Ñhr¡yƒŒ½,ÎÈEç5it:Ÿ¹.‰×±6ý‘Ié¶DcþF^®ˆã¸ö0Ü>蕨 ââ|™çLzI’¨„€åÖ<™:€‘ä<{ïÑð; lÆ0œð¶ü@Š!åçi¹àÅhµÚÙi×Ü›Ð)W°ÕCPê *:ŠÑêQö³Q5M̺|õÃ+ÝÛ –©x.†pžúËŠ@¡émtÅšƒÛoc^JœL¯5ß ý }S]Ø,X9 ©JÉÀÃón•·é„,Qy)¥ŠHñOÖ­e¤¥l Áöôºi4Ão¶÷.m¤°5¡G'EQ:ò /ý ©æ:<èóoÄŸ] ~ÞÏ ¸¹ðûÖ¥¢év|¤t¨­éZ0骟b^pøyYNw2ÂØc­HÖ?üræ¤\ [wu¢¿cÔFΫZ>š¶å;5=ävÒbSŠtÙ¡mlì5*Õ¢Î@–C§”z÷ _‡G8ú(|Uq6`ä™=6è¾Ë'Fòüž†é”^À¸ðZÐJFaÈ®*»àrD‰Zë"moÃKê(æÏzOåÿIbÍFƒœ×tñéЏƒ0÷¸_2Û⺘šòI•È#dÖõbOÃÏ † Ík ÆüKö¸pË0qÅöÞ”Ñêâãã¢AòÊéÉíæy«ù©ÕÖöC}צ‰çG3ÔAø©¸ßÎ78Å:Lâa¾8¹¾XU Ó‡Mä£S(OÆvD`òUŒ±€¹ýO–ÙÒLF„ãƒÒ‘cï,Ç’³;¹ÉTêêãé§$Í6{2pÜGÆÅ "‚%t£M…ϼ‹0Xò­fub5øúRxšÞÎôŠ®]ÎétRMN,Q¬$mÙ÷Ñ^k岘Ëðç“m$> oou¯k4DTÿo縨pJÂõðî‡üÅ·µm|êQhd “x|ˆõ˜Ô8X ÈŽ6ôuú9–š^+uH¯àxøijEè]¶×¦~ÑÊ?Úy‹÷£[ñÞPSîËÛG{)«É¹Ç›‹>$^”cqfÙ÷쨙UꧤN¾šq[ncW†óìYdÚú h 5¼kŒÍ<ÓC¯¶z¿¯k­qÕѯú_…22^*áÅ. ._‹“ôÆÃ:³hv×÷Ïkj‘n$þµy GãÎÛæ13…n^iܲùgáåˆÆè¸V{žããDQ+êáÖ´‚é}1ô“$¼«ƒ•[;*x-Êj‹¹ù U#¶Í¸A>µPß <­hë80 =Î`g]O¥Òê|7å¦ã\MåVü|ÁQ †ø‡”¸m½ÀÙÉ *£¨Æòh8”?™$-(-nk‘¶dŠz¨m¯šNöú²}ËøÏvÛîzmSúeb„EÎSµàNFL‹0,Íxo´öÓGß)½¾ ¢Ï95²¤uáú½THÝB¿àHctŽ:íúÜrl§æ›ŸPÅ Ê[Uå¾UÒ;Þq;ÓW…(­q˜JsmÐ_®ßϸkà¡Oã¢í»A8¢a£o;6)¿ËD6±p–7ÍÖ¦5j&ØÒ\×£S³UݺqbZwž vΤ€‰^Zž Üȇvì-žPU†:aad A", $åÔýµvhV:ç>øÚÞâp¢ã…ïÄÝSHi:CFb|á&œ3Ênl·t¬òÊy¤zdª® ÒÑóÖT/Ëð‚id )@]¢m0Ÿâ, ¸y%¹ØSÇc~ ¹=ª¾ÕŠm‘ç&ÈK[ì&ɠ;¼Ö°2#~@!b¯‚Ÿ' ¶e=7™ØZüݾdÜ>ø¡E[®QÂ$‘nrÒÝxvÏJÂðçŠ\•À¶êÆÄÀÉÒ((÷LGŠ&Ø5‚´á}Eðµukx];F;yß[+ï{˜„”33¶†Üâ'¨3"–oi©cþ˜÷ÄÍ•Ž×) ô·¢Siü4  ã„“|I­Keü¦ÀD‰Í‹×P&èyifUÂýð+ƒ¹¤Pó“âº5”¤"®¬õkŽÓîz¶”€&²fÇP¿}÷Ð5òŸ–jÝ߯µX ó dOØø—í{ÁÕ‰,Hãëxþ$`íéEVLÁ©¯ú˜º6ÓNwM—vuùÿ-ÑòÒÍß5éݧ˜TG’ K‚ Ý.àãIw¦Û2°u³›£Æn‚`΢L{45Qçf*¦³{Áó<$zZMQŽ`FXªÛ”^ÎÍŒ Çò‡uÕŒcžã®o 1NÅøF5ÄesÀÍІ<å%×jÃ÷oôÖÉ¢¥j¨·±=þ&^«ú²MiµÃÞ,¤`ï«¥;ëgómd|æçIçM¯§rjpµ™ÄwH€½UÂõÛ¾EÞN`ç½Öë:M}…¼îÞ²{b}?ëŠÓ1uJ%o,Iñ:ð÷´óEÚá–¹^]ËèÅç7) ~ ^*gô¯§91Y†‘;5´Ñ-âSAWòK_×µ’–ªõ;[°¾äJ-¯qœ2ADí©FnUÝM¶*#}†l¯··CýSPâTUje¼’ºÍNTª‹ Þ=/*bg ìB¡ƒžd×Fª ©N8‘ôI¥XóU•uº!o— :l@¶ÃôÜ. {j/š ¤Ú%}ޱúðEío…¶Ç7þ×£÷•‚TW±Ó£/S„$t#úàÈ`ßÔ{€‚*’÷¬CäÌúˆ™*m­~nYÅ5-B*6²:€CÀú °F$‘Û¯æg}€ÛÞ$tŒJ”}7{û0:Šê)—’‘ç‚¶„ì›g>ދ猠ªÖ¨M+À†Z[© ËG(˜}øŠ.ú+pêpm7H/ ÐGÓ,ikôâ_¹ñO²! FG|ʰÈ ®·È›xëLqt5%Re4ERÔ|tÃ1*¿Òë¼£ØwÈO¤‹5»-¹ö§o)šbޝtqk*õóüŸóŲ ð[»ËgJ˜üþ]ûíž»Üô³[U„¶ä•ä æWªž¹:‚‘|:„±¶ÕbÊYŸp´…aÑp¿¢ÖËý)×áuznïÂä#¢÷ºoêËíZiÓͽÒ}›ûa3$™»yd¥+MòÝý7 Õ×»VHí ï £ò ¿@°ˆ-æjmúƒËQb¢“R7í89Q 5Ís½&ho•gEvü© k ÿŸ,÷&ß¿+qh/¤{c‹@íP¯w_ïøzjµzœ÷"úýâ&Äù´ °™ˆ6ˆŸt BôôK¥(^wÐÆ®H÷B˜U¦u<,ƒë \›Ò¶5o É×i†Ùmôƒ¦w%ýÜó!¦ÁÈÂL?SŒ£¾ä¦û.ìe…±X!Œ ‘Œ$)™R[;`cDİJ¯Ã=vO„vŒèex…Ù'Áæ‚Evýoa{5ü^ŒNpå >@d Híx¬Ÿ&Ž[LŽ|ëd~¶¦!¶¼›Í+/õnI)Änz|,ÄüØOqHŽHN_–8ƒÄ7ÍÂéÑ$³“¹á|.¿–;ãŠë7)àÁ¾_¶Ñ;ÖAÛ§‡¹")ù=1½øàtÐï `-Y™tPâ1ñ/“¹¼¼á3èäèÑI" t¦<æ(xLcˆ‡­?nÀÅÙ_ý:ŒY{C;^àÄÀqŸÇ€üR¤Ã3ZþšÜ<^[.NSe[}?-è(gžêŽ—A?ÿôõ—ÙÐÖÝ6óævÙ‰›¸).g|뼌ɱM…oC‡Ð,BB@QÐd{ á'Cóš2b•ûc zO/ª+Ùy„¦U°â°ë3²Ì.*šSóz0LHÿ}pÈïЌnInƒâŽR|s¥ä)ªS3w¬ÿ°:e…{wÕ®ñYŠúH?ñÏkèh…èE-pä.¯íÄà”ö~»Ä׊Ë3ÿFèüIDýÒFh²¬¥o½ž0i¶ÙÛêªÖä‹9ó7uÞ/º Š«·¬AHv¡¡£h—2ÅÅ4ŒTß„—²6Ð>=Ê ‹çV½•³É RûÆ'쬔 YbŽƒ2'jñXU&µXÆùa{ ‡Ÿ 6}û–ò°ÁÌPurÍ$­P’ç ãé!ÌTò’ÁlµíVô‰ëÇR”¼Å€kÌo¹EbÔägYŽ6fðM{Ž/›–X®ŽA6åGðow Gx§ŸíuwӇנ;]n)³:± ¹.&¾»rf†¼ÎJûlâéjœ ¯›Új1*ciªÀC%š°ÖcMÀ¯ó¸ãÑ65©‹ƒÜ’Å-¡„oŒ=50oÓ ‰~èõ!Ãý9† –ͿĞV#TÍÏ„ßÓÀ}ĵ ¯+Œ5l¼lqZή8>ȱÃ5Ƀ£íÁW cUñÕK*Éuæ«‹ôqUÿ˜ækyî:Q(? SLOdù á:70­÷›Í™ÒîÉi=³­#°Ü O¥•:×$Ézk­Í07õlÇ÷ü¯ìî*O$0N¦Á“èë&Ï®™›!ÞÔÉýÔò¿4oìC%}È(p—`‘‡3€àP‹:¾VíIP¿0ôŸ¹v€Ü‚Ð,é ¨iˆ6í1𠯫ÿ€de^VhF4È¥²S0]‘‚ðeIWw‰¸~ÌŒüp7Þi|·¨P ÕITœh(ã)þˆë³ó-ŠÜ1ÿþ>|šeE¬ëÞÒ#¬81ˆÁS±uûÌâ@‚G£L~ܘÉE”vûþ­ ²˜6Ï‘Æ%ç|äÀnˆÎDúGô ¢ÒÆ*_X ôïV%þŽ Û‰]œ ¨Û¬3KÆÏÎZ)pÑ@õJIDWˆ€KC4 þÅ›vû&`<ÄûìïB"îÈ¢C¯¶’–ÍR}_°”¶õJ>Ú|ÚKCìákïÿIÂߢøx”¾-^\SÁ¢õ¯‡scš§Ž†ÄpU›¦D™«÷[‘9ŠÄ Oí%Gßü¨r §], \úi†ù˱aü‚u ÄÚ“[Ȧ™BtÏkíüÿPe=Ú­€Ô0ÜäQ»‹uÉ þ·¥>!vû’««]Œ+GŠbd*ü}*ÿ»¦ùç$f6‘/ѵÆZ༌SÏ)N xØ=åûî=¬TsЛ¡8‡ÑHíØ'$F˜o9¨êŽÛJQ§†ÙUÙ°YíÝvåäÜÅ>…v…nä½u·ƒÂ½K[œ¤ )Ê‚@ݺЦ‹#‚ÿ¤(£*$žyÿ¥_— ïUÐ#÷Cøt½{G‚ñ© è¥ZúÛp ÄE‘ÝHúþµ]QÉ3^¿%@Äð웨ÃïâkÈœø¯ŒŽGóõQÕ—cÑT| ÔàPòÜ®SøIljOZ‡8·¥!š½fVš_“2z1A¦PÑ M–¹©(¥i Ž¥$¡©Ég@ë:À¢ÿXŠƒ·÷=@ ?Ì»JþØ×°¤½$MÈž—q7Kê)i*ê³l$RÕ1¤Ÿ}e^´±x’„=WB.¢mô QjpPð¢0G°6O…<¾VnA®Ï)¯.×_ú [[4%Õ³‹<©µºXQmä2UYåÖßu–l—{,ó,^”6Þ•O¶5¦¼Î­+ÚC'½ÒT1è èÊ=® í÷NöoáÛ´Õa‹ì ×" wà«Þ(…®ì„úÌu5=Í& Ÿ Cw?õÅÃ9êÛŸÇÇ=^»öqŸ»a?rã±4è ÿÍöýkdñ¬²%[ÊàõÕ^+ Uû¿ _¢2¦<¯åû QûJÊö²¬9k4— ?˜ÁÁ­ÃŸJzÀÃL$â}t>Ó‡$;‚Å%­I—u3Í¿Em§ð_$‹µ›)lê‡ùö I[ÐôÞÙò Y4/Úí©âB¢ qVœUˆˆÜOÂFÔê0¦ûµ¾íË´Aj gŽ™Fë€ØƒÊýNò8$ˆa°{¡ªèqÛRËf¤aV1N'Ü"ʃ0_%!Ÿö;–-‡Ž^€`ÅÃÔ+ Kõ»Ov,I¾$«¶›F¾C‰ên&’îkñlÍ>V¶d3n9?c´ŽÇùQƒ‡²iIw a‘P>ì`œ3b“ñDøÌáA'Ühˆ9ù¦ýK‘Sñ![…fÍÏÄ (F° Û¢Fá(¾ÛÑÏ,c~X–ó% ¬ùüyÊ^/™¥ã"õdãom^·³«œ¦bå«,÷{%8ç¹ýµ·Zà¹CO™ÌnÞpæÃ¨8e‰#¤„ýg‰15VieÜMÜÓ¶8‚[÷H'”c—¤ ù†ù뜛ôz;ù‹þ×™‘§ï*sd™›f]“ÑÛ€þ,£í–Tsܹ¢µÆ‹ïÅM•>2HC× ów`;Sxܳ<KÅÕ“5>€Ú@œx blë™c¶\{ûÿM«é}ý<,X›ZitÛ/ªÐçPDÏ\½R(±¸v:Iþƒ{M}C$¹œ'ñS?€1å‰ò\…J7ÈÙ»¢ê9W&¾ ŒHyu솼‹B/u×ÈĈP“jODäG<_‰,©¨!/XÓwšû3m„’ˆñ{]J¦È ä»Qò«–.Xǽ*xÃÆo¥™­(€Åh¤ØÏå#>Õû:H[¶X:X·W“,¶ÔròǪ±ê7“Î(§2ÑG_6žTnU|îQD;–.å^d.óú¢Íí#¢;öè&ÔYm¾,±ãçqü×ëÄ€ø±ôê#ôÞC™œìÒE@ƒ¼žQfÙ9Y[u¹L1ô~þö[¸]jUžÝ—8ü 56œ7Eã8L|I«¹Ç 2Ë3&,ȈÓÑB8׿àr.ÙGŽÿÛÙ¼èW¼oÐg° }¶AtÈú2x2Í Q~—MI?-‹æ¡Uzzxã¨Øwâ(k’Š™•° ”*ƒ}ÀŒú"˜Cñvu–¿|ö.°§èy޽ùš1`™Lpÿ±=°Vq¿6KÄ2JUÐW¯Ýc~Ë@k FqI™£o;hSþ¼â7m_8<«}×oz£5­¤r`e9üÍ9ǵãþ,Ö¾ qX¬H}÷~ïäô]ñf÷i|ý‡™Œ¼%Øk—epˆU¿ùFY!Æ`tÖVêßål ¹V€åšÐSyîhd=°$¦~7E:k7Ùían^1í†aÌÿPšàgg¡Š¸“°" ÄõVÆ×€_ë2!êêåñ§ìú½/ä`‹m5M袣³ÏõtBuxë4³9õÕ/ LŸM:¶µ.ü«æþÈQôB>0NO²…ð$Ú8‰ÔºröYR—c‰Í.~Ii€Ü\ª³žYkvÕÛÍ))—é}ÅmëðP¿EÆ(ÖqŠbÒVe]~Õ8 Ù}é-(ŽÊZíì†5ëx‘ð¡v¦õ.â%ñ”C˜>ä6ÍL5ꎙæOVI<<ïì˜/Zu"ºwLu®B^Y­§g³^ PKWµÄëå§Æp= VoÛñüƒY*¡«§ó…_Ùq²Q{a‹%zú±ES^½W-gFRÒ]®ŸÒOæ´»á ¸g-Ò;˸íªs332Ž£{«Ž˜s‰wa0ü±(‚ lF>>°51«è~|aV1ý„ Õ&ÒÖx’¼° ¼®JΈ‰Í©©Ê¸`iôx Y£·ç¤–Ã&ò¯²#µyퟴز€®Ç·¼œ@zàˆÔªä@u¿ß8´Ê•ÁÀ {Û(Ȇ ôwuÌ“¥ÉÍ"éÒ€‘w>äOÈ™=NY§]j˜áŒ Dz`õqôî]€u%•¬ú*©4®.³– ßJÑ*yiW½®É4”dÐ.·Õ^rIlBì_ ³d1²ÊÌ.Њ÷-øEŒ8 mÚbUô¹®:rţȺ9}Ñ·ˆaÚ~Q™¹ Á(¨JU4jáç¦p‚Â\ѯÁ;Bë¹½X¬ªÒ".­¥âGTÖ‹(T‘Ãxz‹¬Q ¬…àU€‹H²¡×ÜP7œiÑ_…]TÛoJÖ]ûøºÕÞ_˜ŸŠ-øË &lYÝ¿X&àø÷‡Aãž(˜J~ÓKf$÷Šsטr€s8·ëkYívO°_-çeÁ/á0bg:ðÓç´® {6[rœúk]ÅßAfÚ:GœAÏ‹öâÅw¢Â¿†üÌàUg÷Qw”ñEÂqü&Ã];ÕW®% “^Èäcwï,nÞÖ—àÔÃúz÷“äB}~F̃õ‰NTè ¶xfiŒ±Ÿ»ØêˆRÙ"HÔ6Õx; ø1Nöÿ–Yf¸eŽfS£Ú8µ×ê«ü²_9=)÷Xju/c¯­÷™‚n–7Œ:…ê²f z?¨ghÀ¸ çøÂø®î~ 7ÁaKÖM&*Í`•ƒÐî&~~f×ÉY6Â,ÛbáEˆwWwŒ‚ÎL6ŠExN'#¾%CÒ29…á„¡4ÅÇ#T~/Étù̲ˆ'»ÏmêÍè>-Ê‹Ëà¶å…†E_ÝÅn#°Þ°æ~}NO=ʰßu¶¨o7h†áà+¢°Ó)…2ÝÙ0@çé½ùyÜ_¬+Œ¦K|þ‡k,ñŸ‹”[ôËmÌG#¿"Î?ÓKè¾Ù Û¯ß[ÄUð¼V†ŸåÃy}´àÍCÐ7÷ ^&Á=·P­±7]C*,S—ÛËczXµ…„ÈG0°–ªK‘Œ"Ænµ Ñ{.Dø’ìøarÁÆð»ƒ*†Ö&ý¸#W(ö)/|J>O‡f<|’ºs„ˇ žBL¶•tìg]g–$÷.tqÞÍɘèÈ¿mœ#Þ…Y<+Íd&u²‚ÀLI&ÿ§ç{Á·ÇÎv¾ d©{ͽsÛUç ‡h˜9 ƒUj.¨'›¼Ÿ<‘67Iê5lwÜÏŸÍ•UÞR<ÍìH¿2½ÒºÍgŒQwš¦&Ž[Ö¸ÿ<û¯fv>‡ù¡¦!ŽùÁ8àÉ(tI€ Ã3£… ÛîàLѵoV;eæE!wxG©&GAT~A”ñµsÊ Ö@Ö—'FY¾k´CZ»çY(R¿µÑ Û|>ycÙ3D]êÐäg,(Ú/(Ù4?ô¨}še´ô¾´Àg„ncQÐÈQ穼ôküGÉ„ä4ËDa-Š}Ž$]+³²€<¦5)§|¹‡˜Õ;`ÅM޹ñ=å¤}‡çõ'œY‚©ß\2b9•‹Å_zØ[Ö+ó‘<ÔÏžfö&I¹ðX”£ÿ¨20mMdNŸ7¯,«¤w<€Ü B<“œmfE¶#{JО¼+bÁÁíÁëœKº|XK¢Èö°ÍëêV¾t zsÌðôa“°íZÞ  6¤­ç*$å>¦âbÈÖl±bé*ÍfÐéfþÈ 3º$j¯Ö^a#S Óc—… FÙònJ¼ŠeåÀaelPÈòí§+:¶ƒÍÕª»ÇB*ê.i1GÛdç¤ÎU7‰d“‘§ÊŠëo›oÛeÃ8ÝVãNôÁDW•¾›¶ÛŸÑÅ47ð© aòÖy¹8{ís±íÇŒ×÷…òìäw#Ë Ü2¶ñ7ëÈXn*;·XLÈ©-ÃÑÔ̾wWºˆ{YÞ:o²10B,«Žñ¡#ï†nÆÌã®ÑŽô7!Øß¦XéÏ6PÄW"×èsž-e¿úèåU$– ‡‘ßpÝÒë_z&¤´l슼Š"-ÑÿÍ øv¢Ø…6üh«{ïÑ|õënÿ¯]¦íwE¬U}à»kìåS˜”‘{uÿùQÄ}=¼:ËÜ»oÇÞÓå% QtÕWÌ>Þ¡$®°stfgÉ@ YdNS‰:“ßfô— žT¾dôøs®‡ÝÉô.%Dm/ŠVûñ‚ÚÄ›‚âe7ÌÄTg¤Œœ÷«þÊ_¤ã·ç.“ÓL˜^ÞÔW­%*¾ÆóÒÊvúÃÍB ‚z™MÖSÁyd,žµÿò˜Û?5yÑaFåÿgÈâó d>xØËíhº}™2®eõ ˜¬Ñ,¦¶k …ê–öX¾jÀ™?r£§é(#%ôês‹ž¥Fnú½¸·ü%F-œ'¡sPWÈ \Ûqzî Æ‹¼Ü5Æ…G¹§*NP5-êåTwÓÆ½wë]ô©wWîÄ‚{ê·jX~ÑVîr…Ón¯)8ÙyÕ:ÌWå~H\ñºØe¤˜zê¿7û½ä[–“‚ÌVûlž¡TÇ3 è˜p1Ó4Hg(¸ûJ7 ©¥¯ ß8m4/ØÅݦ£ô¦š¨ÿÿ`£eÏ+a6ŽþérÁ•zÄ‚óK»o3ûR¦ÍÔ$w1Š%í䇦¯·I3P7Ñppï”3{Q¡_²â-æo?ÙêŸrµðtW4÷!] A}˜‹ @!‡ „ýq4ÅÀ‹5üb%¡óŽ•Âÿâ¾Mضõ}çS@£ó´£Ôž¯àØbîƒ3o[Ù.…!»üEþX —z¡Lï«Û¹=âdƒH»$Ý?òa6S-Ó'„ØÒ$ëσ#„™xŒ$O®ÉAJÑÌI>E«v0‹Ìü!ö½;ëÿKì&¦Í\ü› 'Ô£j ÊYòJ„5I _1©ÞÁystqîõóz›¶¾Euð>@}Oú!QŒ‚›UÂøz©ËÒ>{ÆÖh[\58îÇñ¦0b•Ëß<«ßÐ Kä6ˆ“,töã©%ÒðOÀ˾y6¥hbÑÆ9¶Î%‰EŶHðì_(1=ɰHç잃 Â6±ÇÇq|ñ~˜@_)â'¼™ïg,›XzÜÄÌ4a¤ûŒ…®ˆ¹…VOãE>žk`…Ñ]ή(~ºÃh¡+ÑT·€Pª]—}Àð\6½sÝÌ{ÿüQ– p~7¬Ž¨~( ‚t©F<ÍÊ31¢2EZöÁ™à'Dòáìn$÷dzÉgÞ¨N¸Epn—Î8ÙÒ¶Aª¢Àc«ø»YùŒâþÖn>B¥ÞJªß‹éçy0®ãM¨å\\ ÒB^ëãúë¦ÔÂìtJ®ÊƒP;OÖä² 2a·GÒü0žæŠý®@ 1zj`šo垀iñy„œÑl ˜ïL£coÆÊfЮ­ÎX&‡L«BAuÍ?T¡ñ"6?_.[£‚©DN6¶åЛ:pW«‚³Šýôf0¾³®6Ðä?ÏÞ¿Bjª±Qש»ñ:6TvRÚ³íiXBE†’}À”±“µmÂ/µ©‰o-½ îëy¡Ù-´…Úöh73›‚¬/ϸ~8ä¼Åz¯G¶"Ñï6.F IÈ©mwß­Ñ]ÅÉgò¶•S=޸ǙÙQ2õ)ï»mIi–*(z㽸¬+M!ý+$ï‘-Ø9çœ\‘hÌ“Ø&³}Y9µU¿ò\}ÖÿÈTr©Ú˜_]»ð›gÇêçh AEY× [à‘Åp!_€ÞØ¤ÓÆMli@dÙjÁŠ@W2S}ÖÊdë>²ÕOùܲ掫晗ÞY–7¼([ëóó•’¯ÑdÐ íšÚÅ:ùÃôÅr™•™'ö!N”¡mZ²ÅÕöK°¤øc·(¸³¡ñGá‰~Hì$p½§–ÂÏ”:šQ‚û0¢Óº¼åÁ¾í0©…Ù •%R÷RÓÚ"~$.XC™ê_¢á42ûîŒù*©Ü‘⟑òÜòøRØÏŽ ” ù/ ’(ßãý7 ‰3ìÒ¹@È®%¯Éþ–ç³Ç·ç`Ȇ€€Ý†kŽ•†ßsíìú„bñv‘ºZ"»_ÌèÚFÒÜÃÊö¥ŒŸ¤o|‚«³²ñ¨®Î;j1'ܨ rþC¯ÈN%q¶ZÞ_—¯ÉË™®ä9ì–„:Çè  C|'ÓxÖ _8LÚ}H2¦@guÑ»QƒÀÚ[™)ínÛwž&žÂuBØÑ£*$ò­­ ÁËuÛAêwXO=Ö]JçÏÝž]¥+>`¡Fq¬øŽ»gk@vË›ò#Å_TgžÃC+u7µeU÷M½ÿ 6~3×1ç ôâfcÍËZcˆmá GV׿&\ª…MºYxÇs`c¾Ö< ™¤¨Bx„ÅÙXº_ï™w¡-ôª¸ƒDhj µèþ”ÞGQeŸkÐù.ø¼^dù¹!Z+æPø}+TSJÂfgî‘•íÖ"<]T*E0;bÅ3½¤­¸œ)€pŠ.©óƒŠ0S¬ ~ ÓkO¨êòZ‘¨:¡Šægn4ÌzIý¸’2½y¶_£æìi¤RÛc}õæ%†¿G‰ÉwNgéé¸CÚV%í–—?ÌÈ´†Qí«/ÞtKr1GúÀÑ7Bì?Oìmq„Ý¢`[LõÉ›õ;“Ó<Ûî´Ã"ÂãDÕ(0Øs^¥‚ó…ž;y†÷+­F‰w¼¯Dväßãºî@áH›:©ï×K\yó&ûÏö.¯+!9˜uíÙ‹ÞPÈýVý”ÕPÏÃzÁ9á×û)©Ftô&šz¼êJõ17XBõäšeéJÞ@‰+SÿvÄl6Tiƒ»ûV¨za 5õÚHÕ”†‡øEW½ÌÚWk|R>©ÁIÖ¢‰ÚDµê±>"ð\ìúóÚâÛU¬‘ wjoφÎGŸ’@ÙåHjìkÈ[Z*<¬·ëÞÞdôÀôXø‚ ùËT WU5`æ–hM×´$Êz-#xã×LÒ]øºÿ<‹†œ^D”î&΀¢ûé؃”@ci¬/ØҤß.#ÇZï)ù®gOÞãÍÕô€9ÁùQÅe’Î(êCl¥å´.†¶‚˜ÏÒ¡PúNƒz‰º¯Aµô`'–C™árµS[½´~í²æ«ŒnÎÈ[ ø¨V= Dˆ3Шâ‚ÕyLK€Å…ù9úýg-îU2êÖh{ó6~ÓÒšjÊÄKôrF,‡Äƒr@Ï÷ ƒ“™›àãµJ%˜#•òJÏ#M°°à˜Âdþ¨LË¥xRvc‘uÅ2Í7|õòdÿé¬7½’K¢ô¡M컵NWÒÚÜdžYÞfe-7˜ˆÆè>㫸Dà£1M.mškîKòtÛŒY¹Fþ ’›m¦µ#©ìöuRĉvzËo %Fò©pî?¢Ä075Œ­Øídïìi?x½Nx7Ó]e8c#mýw9_0îÌåI"£4 yëo츢õĽ¼³§dËuëhû9µÐ_ V%–57qÐÉèÄ9#ŒP‘»~j¾c´ÑߺïÚ—¤ìAŸ»ÿ£Š»ªœišMÆë‹ÕSZ’ƒ“`ÚÐãÊ3’íʹ‚n¦oòòÕkÁÞ†T°ñoìüתB>f^ñ°‚æp!ä4C:þO#keLX܈gµ ¶pÊKþ ¹5½X8®*ðí5ó”’ÿ›øaæøIVö”äÑ_0Ɇëv¨;aÕ/ÅÒ Fçâ:äö'¡Ï‰%%ۜƘzÃÄIÁ{¡g¨Ê ÎéLßz=ØàBF|¦?o¾yæq3”ìg¸~c«ÊúöX{)“¿µl_zEöã·Á˜´8œL€ÅèubOÈŠ˜Ø¶™_F±lìšÉ=Îï#wýePqHù˵8üQ õhgªf(±³,'?zcy­ôöoˆøÙ ˆ£2¼ÓIòȨwÊZÈPW¡âœýöÛÆâa g07ù׳Šppn¨–ÅäÜÍžâ//m¥OÅlßWf\Î…›Ÿ@²Yˆ®}«G=¡¼¸¿qðIZé)HØfväs £wÜRÃçrPGаÂQÕT¿â¸k+ Ž~«_Vžyi›ÔÃóqqQ¯ ”éìÈö%„Û7Å5^d 6ôþî`—6›A|Ó*.(ïE=È­Í/ûÐsÁ¸øÅ·Q4†;ŒIS‡}=¢½Z5ý³ÃZÈUû#g‡—ý.¹Çvƒ†rAìÍK[5LXšÕaÇõ ¹›Æ+^Š?hk¥¨Ì6à€Çå¿*Ûá¤0Ó6/Wx4Ã0]š0® ÕD±HúQÌG>ëwíú·Ýªõš":ƒäê*ÒUr–G®N·We»\ä“óÙ“çp#ô2òûe™‚àÈdÁz1‹€£õqyN„ÛSô‚ åØI®Øi¶ˆó+±ú×vÎ_.Ul«ˆ†‘ðŠk´º Y¿ªé[–'c"9¤ßϾ0à :ë–}¨ªsÂò¥r²›j|„ÆÊ }=•/÷Âv‚¦êM–ˆä]’ì¯@dv÷I÷×Éõv=ÚM«)°·›=«ªU!%‘»:f}Û¤öc²‹Ä.aLÝùªZyQ|“ñý±º><*r0.Vzº§‹TH½hÄlƒã¼#Ç|ÔÿÆ ËïD½fãH]h‹]˜Ø#j޹4J«Ñéb`DzÃpý‹V‡6{¤jœöÞ30~VëÔ'è7ÚEqa*êLÝ/ƒ¤ªŸAÇÇ®½’ÜAò ˆÅ…~¤BÀ„+ï1™#nÓEÒ 1xhX1/‹ìWYØÍ7⮯̢"ª1Ýn™KŠyÒÑ–…ž-iýS(ØtÍGüFÇòöZ¬WˆO…Ù•Ý·ú®×y†MÝÖ4bÔq|ÖWªHoý*yeÃ)ËQÀÂ=¢N }~ê0Ù%{x¨Y?7·2Èøø†|]½n'޵ÈíD¦b&‡<“ÄÕZ]“.zº»?â°ä%*Æ€Aí0N¶û/ŽS6ÿ­%KHÅ}Cå‚o‘wód‡ov‹R÷‚úhž›^pec礪¿1« Á/åv8ù\aZ¯”….¿sê º¯x†ÿwå¡Ãoa«Ø'‰ÒÔ¼vÏSÒg#WÔ©L!V™‹Œ¢âz¯C&Ì0 iÜðó}· c14ÄÁ·Ež5v¤%JH…Ì Dʼ軺Yù÷‡ý¹Æ3LøS»hã,Y gÁÌ0 [ô§ƒ›Å`Õ™•Ë òe>@—²ÉJ:ÿ–-PQ§¬CôéêEækK¸UAËŒ~î5ëB€ žaIcijØcRä­”EevòG.<ÅáfÏ/OÇ[Xÿ’k§$#âC8yçвI~ÅÙþT‰²Õ€Æ¤ì†&ëýЇ±¹zñçI_J”¬«åÛ9;]Èûåð° ªþsI<\x¤ü:`½žm*ß”•¨bo¥MÌÉ~ÁêöïEüq# 3>Îè0„á/ódžœyûö³H'§«=ò÷’´ÔüÁWŸˆ6¼òAÍ»ˆ1—x°õrÿ,9P!Ô4è6âôÁ**1Xma20Špi¢Ÿ^¿æLÁÉ€Hˆi#J ÈÝ ëè½|ØßÛœ Ô®ãUïÚ¢ކ¸rõ4e<°D@çfbCó€¦ÌIëF*Ûû®Ê<ÛÏýø<¥ß†Wzq°­¸Üέð†râ¦ÌÕ:²#¹çzÓÛ™×<­Øû³«y® û϶ &ÛÅ»m³h`ÿRw©ø*eÎ~†„‹B~uP¦Ñ?N=³Ÿ¼#I*£ÏâZqÒ!•ã¥`ÛµÚ ¹lž Û0OKs$_™LÕˆQ¾PP†ÈÚxž& ¸ÏM©â²¦!SÝŒ</”¿* (í£—Êd˜ÏÞ!›Ú¬¹äÍšÍVÛN—üo0 ­•ø»†~>”CáÀ¥Vô˜ØmW¯f9_“8†aË&ÚAc è4—ƒ!ï§׈õÎbõ$)Tv#½õÊâ¼À†I&\[<™»ýtÁçÛ†ÐüAúkýä xzú;ýuUu`õJÔdœ~™zg³/·%¥h´u¼/ícZêL8þ夆Þ[’ 5˜ÐEv¤†ìæs £^¤ü1 g¸¤æû‚=ç%bû- >ãšØ Xh‹Å)j‚!ž·Â/*q+âf&|u{Q’Y{3WC½lzcå…-ï¶§ xq4Y÷& ¯\¼gè 'PŒ¦ ÀQ•`ï¯øç[Ïa­9˜zl¾ áÔKJ¯žäÁ—ÄWÞ.¥×há*€¼-3S‡ú_n©¼ã”ˆQ-tŽc.öè¶X:D†¤-DÚ{Ï3BôäO ™m:÷Y/š¶5°·ŠÎ7x`Z΃Úp°&ñpêŸ)¨ý ÷s3-„€K÷ÞP‚ g&VÃ_ÑÛQä]é¢Ëâi·|õ`CuÙòbAMCHÚ>ÌÉJŽé¿>m+ì_i‹cj>¥Pð„UPµ ÝU£é0øþ ΞkÅ‹ø¿î+]oí[Í”/s%ò«í܃‚Jíò'4䆦þÌÝ`h™1ca>p*¤ ]¢¾ÞÃ=ˆ¡ôüò¡úÚcâMèN¾eZÏÅ&Y£ÃSÙâE \w†ó¨Þ€¤ ãñY±û¾’#.©‹éL¦VYpUo”ºÆÒÂ×%,V"Í0ú€ î†C¸1Ðww…þïÑôjŒ®Âÿ¶¾Íðâ_ŒÂ½Ïzðn„å] gaVÁåR¹ám³«÷àcâžsß9Ù°A÷Ž"í×QÂí%+¬Š/Yc’r†5!HH~ Å:sGÉp´…cá«lì…аl¯^k %oš%³küÀ«ßœz&o¦‹"õ‘}A9¼L«eµŸ{‚dòǯ¬[•½!”L Œ¿¹™„<—â–xÈ€a¿Qxñ@ú!o¤Ý î›BÈí‡ÅçeN¿øc¾w]Ö÷lõÙ×Û¾§‹)Χ½‚rÅH¬ˆ_h‰y’aEi×gñX·Ï_iÚcYöð+ˆ­Ì k?ÖRõMî³+/ö™Î+¼}"þjð®ú’tÓ* T’Ò‰‡¤0Ñd.o~U;AÚÈ?]Ó4ªuÊ_ºùm«£i¼£œÉó&„ótÑM KxÂi—÷°îò²?œ˜™àÞzÅ[V­{ ÿ bÌ&4ïKŽÆ©ŠÐ}øLÄV" BÚ"‘!›GU<¼Âޜ݉ôïÈéÒÔëPîBX};DFÕŽÆhíSTÔ}¤åì&÷‡Fk^ŸßN?Ôn‰b‰@ Ò~2ú§»«)‘d¤ÄB6ÊÐö9DçÇ¥ ¹íÉ­r@z‡ë{êžÄ^$ ÞÜí9êöQ0£¤ œânÝùAøÆJ4i.6UƒÇÎ:©gùWÁ8‹¤ÿ¤Ÿ|‚;õJd¾£ù² K…º­¢¸±µð$èÓÚônmÚavuݱzÉÜ¢XmW×Ë,gÜrìè®=‘›,T{ÃËè;ЖF"VhuÆö~Ç2;½Yù1¡º'ƒO|}2žÌ¿¨KœL™%}µßV{QV7(Õíîsµ‡¶R{°ë‡Y« “—8ôYm?czÿµ }WüÛÞIÔ§J¤¿ ZÜ*‚Å-˜ÔXóúd±žÓrx¬x*ìT¾ a'Ôäe¨ðñ²Pç3•}x ¥ÿN¯åó_Y¾Âd¾Î=Û[²À¥ÖË®m EwsìP_¸C#í{EѦ€?éuO}´:ãÆuÔ/öÄT°½FWªO“‡Ã^‰Ç¢oí}ó£q¥`Ūœ8¦ncÆÈÿ ýz³æž UíÃn%žuž¾@5Æ ÐJsz¹øâÒR2¾ t•*Øõ-Èl’ŠúžàÍ1§ÖŸâ êRôÕðk3_z¯.ióЭ9røÒ©Lo1c³~pþEy‘wˆ‚uÅ^àfšý,]ŽJo¬ \*gãôCh2“ƒ«7)¢wL‹Á2寓¼hö– ¯ÅÕ‘E/sç*j~‰p ™ia*Â~¡“mZ¥T³ì¶¯nP|æ9Ú^ô†ç÷{ý¨´ë”xWfO@¸›\÷5<³ÅoAèÍžÛ­ø!óã¤èÎmFÃÿ`²Ãÿ²ð¹«=¶@•Ñ Ñ'´¸Y:´s*·ñ2*ÏM¾½¢ä°Š©½£Ê†‡‡ô‡¦c¤›,‰Z8 +ÏÁÏ--=£Æ%]}ÓFð!õÃü ¯×˜°ôÅŸm“¿Z"#ü`â%k´ ÚÍJèJ>{7bØkïàÂñÈßG9íÅÕ;ÈÊu eï­hC„X/ïºÍ÷ô;÷k^76NÈu²Ò"¼§ñ’°) ³w?áòvIÚÌ-óÕOX’ î–uùb‡eYËÎî'Æ<—èýÔë4¤«vV¯¥úÌuî½¹r/-q÷h‘†F`뉖òµ†31´FPj™Lh>òêalê¥&% y´´"fßtff‡c{HûìIÉ‘GjÎÀ0 XVô\y‡¨Zžô !D;Ú“‘ÿ¿ŠÊ4u§Ð:4#5C¨ýü’Œ}V™‡*œÁÕ}ê¬Ü$rx °_–Ë÷C²•úÎPÅj,ƒ<~³ò(Ý…WQ†iw"7j§Ûø1™Ù“?T ;^1‰H¢Õ ®¡¯‡Æ“I‚ÏA?! ú©³úTÃ!ŠÐˆ~i½.wÏý:äuQq_‘  GJ2ï+ŒæÒ<ˆòªáaôÔ x‹œ xÑÈÆ†#áЋìm‡§*µ(D0oî_Ž˜Mu(~9{Es›Jó9Éh6{Vȱ4$$RƃO¿ckï¹4Ùl,˜ áj²¢àoWÅnTYx,yßndÁhévx¡qîí ¤Ç:Tf* ÐÕAn“¬ÏK36ËL±‹¥†Š #²ûzvjcÂÀ‚ýë ':ó»0¼Ëéo`sðþ¢M « =Ñi KÍ—Jº7Z†3sIQ§÷9"z­n}ãûî ¦«{Ó¾"PþvÙÞ, NÚHûŸ¥ƒÁ··õø¾FaâÇVIÿ3˜(lhõ£€ˆ§QéàlÄrÖ}iøI£t,TÜÀj²R^è°Q0P³Î7R¥#RÜÏ•lII£h€æ¼Å'×ïŽô®º‰‘aB×Âp kÙ÷ä!‹T"¦7¼»;'£K?á|cyˆâ…Žsu¯¼`“§‡ï˜NƒŠ1!è]É@¶o‡@¿M0eêˆåhH•ò{ p×é0uû³É1A¾r#æþÃË“hDN“ƒÒõ¸òø­C&÷·‹[¯/¨ÁÄB77³!™òFô srÖ¯mþKáÇ-–é€òìÑÈ•Ùí4«›¢,¥`»¸¶9á,‰„KÈZ·6û ª8oðxVPÚÁK«ÒÕüñe©Ú 3‘8ŒlL·m8è´F¯~rëö¼ö~—…­±ñ°6ž7¬ _ þë#-›ªèa³;ap‡EH69[ËqŸí¡•Èn¤ÄB¡¤W Š(„zð«mñÉz]8ï!±ðRƒ;FŒ)¥›Ó¸Å/"Çkˆå¾¡F¦öö¤²bÇ¾Ü ñZ‘t.íÄw™U…ÙÛÎЩ ²»ÝP 'ë?iMUD¾:ìiFE\Šì«¼¾È]ôböé™s˜Sa×Ýh!¹·?Å·¨Z* ô-ÅÈÝÆ~\ýr:äßêS©ZÛò±©ô‰yTåçƒ ÄPóßßYm˜¨"65ãW ç°|6àŸîbã'XeÃÄy5%×?Uʇʮƒ¡e—Úóíä „.럑_Q”lü&3Nôz¢£Ñ¶Ç6 ™[vƒý¿ÑõëȃYÙGI‹Å ø±¨c²¥Ûg¬¨ƒ´’[–åöUžü•Ø9Æè6ä5kÛáš>pb¿Ó‘-ĪÎòfÈÑÒ¢FŠ`•–1¡½5‘Ç K1‚ü¢'"¼ê[K´X®¦E“%{ÿ]²ª‰è7=Ęï§%x…·dñ‡­˜çPá×Sß<@ÙÚXì59è¾2†µ´Ç”Í=šq×ðV¹Wþ:΀A³§²¸Ñs*<)Be€G ÒT‚Àdký…Y: ËN„½ÿÓ·ØEïœÚñ‘I¸Ë]%¦Lšu€€U¡\Ø—ÿL&×ND9Þ_#—ö/¼a³û«×ú/ç5DaÊÌS¯çs!¨»Ãl)æÖﵯmñ+Ñlÿ€ÖÔ̾ iÎI{*Ôñ¿PÐF‘F2li˜q+JÑzj÷w"lîŽ>‚°ÙÁ‘ë‚ñœh¤6nŸOÜiŠž\ëˆ ,Ǻdtk-Ûχ…Q˜Í}Œ½]ÑÈÏMÒÅúçCH¡û¤ÕšÜŸPÁìÍV[,Wùs|VÞ;¼ùCV°æËB*6vÐËj°®usG¡Ü‚3I*Òj_­‡Òä…A2½§WÏl¶9M$u-(Â,L/eI–uy—LP3¸vCª·²Ež·Î_šÇD;ZÕÙ)=¹U<‘);<åUÄdd‰T³•7mž…ÆñIhJ8Š‚Uu‹¢ÆL˜Š½Píp4sž²A0ì~ïÈ—5¨³%Ôß_/lÕCeX ‡'¦Q…ÇÞä+µk°K¥6hÂèk<z.‚n?CõìßO*ƒükŽB<öü%ÎN¦¡KोÞJ¶5ŽÏš¯®Žá5í4iNpF‰¹íÝþªO)â9R–Ûâ1áxÊêÔhUÔ)0Puft!}º0Úµ)šBÜËÌ!ÀO÷uy#„ò®^,ºê¦(Ø×ÃÄåÀñu<ñ;ÎY®8hì§ðX7Øt@yíäü‹ú+ãJVU´¬º$’Õžz7>Å"t{Ùd¤Â@«à]’+÷ÿưeþT¸ êZ:[¥eÄ Ü¬‘¥”fÂ/ ÞêÄçÃh÷Ú$ÞÞ­à¶R©¢{\¢Tº&.·œ¬2Â5†C¤ûÇlSv›=ê¿ÞrNÿ?³¾ƒ Bô ˜C|ÄÚ?moÊaJUøM1–Û)Å+çfúb…€g‰àQ£ Ê„Ýeßÿ ¾ÚßþL2IÞlëÍM&\† ½p{J`—«*^1+€ªˆ™—4¿±Vž8[è³99Ç«™««h>6‹O¸'0<Äî”ÿv¦£ànNaOmuð„L*ÁIªÃGÿ5ÐiT‡¬“Ò]êOŸÜ0«Š2ÇÆìª“ü°âÚ8€Þ®žj[Ðg­[k×#¼GûÚZÛBé>ÊT§Ÿ“ìÀ¯š·‹2³ ˆÆŸ ªIuµY0H Q>Ç—ã#=ÄV|ªI ¿o,ßöo~>ºxWâ·,‹®r/~5=Gºê›s&K™¶v­…­<À ÿüL}FÇ€1¶[·„éÁÏü“ëé4«†x/Œ3òâ²…‰øÕŠ=³]Ô²?ζ+€‡BD–²u‚5œÒYxM¡R¹ˆwI!èÌO´«é—Ò+—3-T¼/õÇ÷S—;ª¤¤O½œÍ5Öã&P‰.Ó÷« Q ¯Ù‹²­˜öÕ™• µ¬Ìâ*{Xø—ªLêÍ ÿ k-q霟ɒ@uÑ/wŽ®JíH¥˜P8ûû q‚è0ÚôηÜTÚ‚ýaým ŽF“ÆVóÕƒôÖ‘âq¨Ø[<ˆÙ®Úú³.uŠ×Ú¯ç/Òžw&Ò¬¯¡‡úrY˘ ½¬hר¨=Þ}çËEŒˆoÑJÛÃßÊhòÈè:QÎjZ§öT©w­Ä“¿¦R:ĉ•€°öäŸßnSµ„lé³ôÊŠY³‚ݹM6êÚêE*û·ÐÉæ‹¼nƒF¬F ‡[¯Bz«-D4Ÿ/òp+€ãä’ÿw™æa™BfE[N‚,ä]Å©.ì! ØËÌ /þGõÏÙˆ'¢ÆH_ÅܹÆ|Œt¿çVi}ĩӔÄ'ÿfxÖƒ•jz%Âuðx¤“¸Åt|Äѱ~©pºBû"ÚE‰ËªhrÝ;Èïý9¦Œ-ÕMé"L[E< D €Ûàìæ…=EN·2ƒ¸gì(ŠmJÐïÒ…Öc£×PaóËÁ.__ËO”2:ŒÞðmIæ‘;/•VH—­ýuø¢yAÇv$?ClÓ_Ù2+yýî&⋵gBm{£iº‚’É~äxLFs µ0êHðŠ‹Ô˜ÓœG¦þERÆj¾™‰EXÏ °¾Ä‡ùZÙ7n>ºÅò}ƒYÜÌoT"½ÑðŠ·þñéS¢Þ’yiÃÓ0‡Ò¸Ç¼±³¦ÒÜMרxhßv¹(Ἀñ玊õ´lÃÀ'•LÅ ê\Ü:Büìò<æ®+íq{oÙÎ~‡zä–PÈbEÅæ™ð)ÎÅé(yƒ¨ýéã&S°s¯2dn±H1G‘Š9Úø.Ü@5ýjB’Tt¤ãÆ>óz€ëÚjƒµ€·(.Ô³ù\ßí)B牜.*ºJŒ ó—Zú/ç¯IdÆëÞµñ0¾çhƒ= Ê!V™úwËÝn%ñí@p슃YÔ¦ø–Ü:WЛˆÂˆ ´¸”5>© ~zJÛµ‰Ù…„Ÿ—baÅHùÑÒ&šZñ%6ÚïÏÂÇÜò¾Aá‰fŒxoÚ í¶;q\Ò§-©5Ü©åB¡ßetœñjЙl1ÄÍO îUÙ̹UJÌ”:yöÃB…ê§Ñ~ŠÍõój±#àð9™'Ç×`Óê`@i}¼åíS ;Ñ×I1…¤@üßùJnAq®oö‘ñŸ‡27¡$ý”âŒ÷™R9tû[Ë£?þr`µéCä–ÈM@²PþƒÌàǹ7ô[õ3Ú^¯•a,[=̉×ÅE%¢Æè¯¯9Ú*Ȉw'*Ÿ\NÕ¥g“uÑdýOA¥ƒÄNÏj`ö èÿéºÌtœÕZ|·Þy4aâ)˜nêö–ŒB²çrf¯"7~ ¼#ç§—[+Û1Yè©£Øt¸ï“Q 8çA1¼±)§OÂ&;üEED(²Ê%«ãÎ0ål}uântÈ({ï:x>ðÜF["‡Êà‡ÿ‹ ¨ó#Q׸|t´ÄРߺŽW*ž”ó¢äØ+Ä-é®[Õú*ASQ*Ÿì¦¢&³çÂ<1ؕuwÊJ¸¸zô¹Ä­bK3ÊÀ+sví¾Sy©‡ê0cGeMÔò{ùS^y‹Æ!áÀèß U,¥)úþ0ºéàK´WÉôV[ë¨ÆJ¯§L`¥È—•}œ‹T\» X©šÒôš–LNCÊCèsà\!iÛãè(€ðAtZ÷Ow—ÉWèY1nÈݘðQ¬¥ ZN÷Ÿ™ ’®ÚyÔâs„QdH"]Çor·lœTRV Ãë,SÖ­ëÞG ¥pÝsU¾"ŒªÃV厖WŒÉÅxËWµÕÒ—eýžÒ¢öSøùFž–ó(ÞÄ´žÆZ=¼šœe¯çQ@'FÆãêW@üûÜïe(@+`Ž/‘Ì5Äu¨ï#£Ö.Èþ_M=jÂ:b»ÕÃëµÿÂ3P^xéVv+Å/É €Ä‡,˜QìRINßý^…É«K.zóöÚ±ì~¥÷VH¼%§-ÐÖU%Ç4~Kzlw ~)T¿áJp„çàôëêâŸqØAÞË©†§Ä ´.dïÞ¿>IyÖ¤D¦®·Á㱊H«iÊ;öµ˜ª…xe7“ù„‹%ÌÍz”_6’šrgIö¼¬/fr“×MU§Y{Üu”h—œ9ò²ßp„]ãÏ1Ó¶¾0Âm¡ *jŒx¦‹´C‡ÅÙÜÑ–±µÜØ㎖“Êy8![<Škå¬@cEú"©#FÜ,–¿) °qÇ4»ï yìÚ„Ve…ÚjèqIJ!v”?ö?îå¹È$óP€Óq>wƒ¼­k³&bÍúò7 …#1E>…r„ W´¡ ¶®·d£ ž¨Ä:‰Ë÷·%)åv„B)[Ög¿¾öÙilÉÆÔ Vv£bªZFN§ /Σ–É߯Á ,Üó‘Â(š¦‹Ò5× ¦ `t_¹µÉÙ5X\IÎ)ø*"’¦Í æöS¹ç»š² ë)a =—Ð9M¤ðžº&£Ù3$,*oC’L}ÜãÒ©"¿° Ss½ÁÏþKäð5þ¬¸g­ø¬/éAò:oêCÔd§zªåÊè•)%OªÈ™œ}vH7ö”ïœ4nïnoà“%1•¦œ‹€­ðÀ¶ŠFê(·8Ô¶n$}#ªiûmA³IJñæ gÀ»Òž÷”–²Üs¾ä½›—;vòÍ?ŸÎ–ÍdÀ²ãé ´c¯¼-@ƒ&ßw"¸©5Ä1¶Áf¬ &ÍÉošZä“ÑN0ó_ªT<=OפŒ?ê<ò³¹PâSƒ¯Ö……å<¢ó S]Š/=Pš¾aq÷ž†p= /¿¦Ú¾ ÇRqRSQ›¡üÄcps Ù4ÏoæÍ%:í,SËsjÚô‰RÖ\Ÿ…Öâ¹~hYÆ­eIÝ댗&ó3éHlFŸ±ùìØ 4v\T¹8$(V¤ Œ°à®ûIÃCOÖG4QÉÓÝÅO›HK-w~…¿¨¼~êC«>]ù—ú[‰ÞHžJ-Zj{ßÔ쟡<¡ÛßÚ†7¦€Ùq•¨÷"„ ErrC]g¯ÚéŠáhÔc“@|[t‘·P`GpG«’üv¿£\‹¡Æ€E…L‰v³CìÖrëé ¹%Ií\AÜõ–Ô­þÉc‚ÜO t³ü’@Ù™åû;’ò‘°9'_09,Zƒ›Ãìâoï1×Ĭ/¸<Ý-çßE¥«f ;©{¸aË„ýžQ\\r†že Mâa[/ÈöYR}rö<¾aXMd`ñQ:ôWV— ;ª^Ø0_5¦a™Z¼{>›OŽj\Vlˆº9Í”tę̈ôŽÍ’j}Xó`º®3Úh˜£:¤‡åPªõœÃßNçÏ{{ðY…ÚÿÒô‡Î-‰g¶Y,ÎBM—¶EèIŒÃœT£Sw±Âß5Ì¥‹íl^¸/'\ö&7þÐtœsU±Oø¸iMVí“ñUS¨×˜Í_‰Ï¶àxä…mf1ÚT{·gŸÝ»3ly!jsýx.¢°kãl¾ÐÅzÎéÕ²üH0 1[¼›÷õØ­PzU:Àå/²kè>_ðJ. ΀‡ÏøÕ¼›d@6T<“–€ŠOf®‹$Š,öõNtÖuÜ}›Jĵ‹? ?w]jnZgWíõ¾« ¹ªµœLVó9áh¼nÚK‹|³Z„ÃóÏ#µÚ`¾Ì¯á or´·€~ÕÙb{Z+ݹYjZîUÀ˹9°à·¿jVZæù; ¾\ªÚ£Q¬5Mhhh^€æÈãĹ.×&ƒxÊ?äŸ]òsª45Eƒ\j£æ¯à5pÛLþ?Úˆe¨þÉq,àÕ-yY11Sç üå¾AÚb÷ªoG7\¦*ð&©x±_ÛDëDd>ÉtÏùFù“oµÊº %yÈP3.W3È»§ÊM»³Sùè?Ÿ“N~ ˜½TïMiž­ ¤a  ÝX*H9½Ä^ͤ؟O>ümé×õЙèoøœØáJY÷éIŸlJ0aQSôï‘»æ3¸,¬ªÿçV 1•) ¹€—* ²U~‹ áK±ºªBç@¥‰.gûÍFÙñcú 8²ÿµË )ö_+“"Csm8YÉ%yšY;S sÇ ¹;n»r‹äS,-*Š×±š+õ0¿­û¹=$‚Wn_”ÏOómôºÁEŠ­jóO‘ :o˜ì%üöqá>Ò€øŠÍ¢ÈÞ]]øÝ¥ŸÑ%¶šy ™ ¹b £Ý¶`&þ ÙG><::y'Mÿò×]”®rÃReã ‹¤7ió1ó!´#޾PJÄc)skmà eK¬›ê ÷Eùåë} ‚‘]_—È'£3e(S†Ý39‚y¥ÌnÑJÍzÆéC{Ý%u#qÂFÛGßÒr1Òtw?Ò–>à !¢÷`GKy¤[òí;ºcKCÌÂÐ,P+ÙÖÈ ·çwX;.ÁŠ¿ô.¤ïÅDl&ö\€>0\IÒí•9þJ|=ê’ìâœÞ“lüÄ(åz=£Ozðí*Úƒ2•ÎÜmÖ¶Áfw¢R³ZªÃÈda{Ÿâ)£êËÈÚ’›zUy»ß®ô€õ¼q”]ò¬d¾ìãúƒö1šjWÓ=Y~…ÒV²Ý֛ɪp‘»mÿ(4‡s“–¦‡¨ÄÃ&ø¨1¡ðŸIV!¯â ŽqûîÐÿ‰”ˆ*ÍGè:Xû£Y™ßÈŽ$[œB­$¾Ä“%R¥wEÓ•M¶PcGª*úvÖ(ÔÊ7ç„C™ô®ÙýwäJ»½O|[º¼}:$Ö#ôT±Ó ~âá¤ÓSäÙÇŸq¿ÖTzþÇÅN¨.yëÏ6'©Ð[aF¼~1ÇT³E²'¢ ¶9îC£bû'e0ô|K|ë|0Ãf,\ç™è;ÇO †JÚ¹k lø̽ˆ-v¤g0ˆ½¥íÈ2 5Ÿo#¾D t ­˜s:@¼ø ®pÏäÜ‚#åý†uä+ «9©Ç¯ \º^<ÅÞ ñENuKò3„M¹®â%1*®/SÓ*㺆E{ž™Šh¾?p\ƒ 䨒qÉòSvÃþä–_¡Zé°OŽuÈr"­Ú&fß%äñ-ˆßeNÅ_Ä)¾*U?M„ÚŒó¢óÜýæ5¨2ÃÅÃÑÌû á§4Û]¢‚Z¦ä£‹“ùОööÌóZ´ˆ÷éîþýYË4!³‘\©WI»ÁögH.ÄXâ³¹ðf)ø•f ÜƆ  ."öZfýP˜¿YÇ­!ÐûçT¶5ƒe¨p5wèL/*– Z ¼5MúýA”ªDÇÖsmeW kųÜà²l°ß9ª âõS7*eA9¿¤ã{ §œc3*+…N-`1DÅU>Ó¹3¤þ”`šû76ƈš ù(,=\Íûát {U .†œåûÓ a~‰bî"j>:Ô‚¬µ‚ôj4 øjWa‹.Á°Ûô>æªbÏ–`>*¼-‚º÷òkí 8Ø/ÑZQ('íó×"©s;+CóŠ ô×:MjŸ¦ÿäf`O “º²¾[´ÞËÛ-œ÷Žè6H"™lóËvêÖE¥˜ùÁ„ÏR{·Ñ1˜Msbç'³aÃQV]'"$çììÚÅ„Òì`¬GJÛÞÓ·;É0%ñZ«h…ä”–ož)žA`ú›&yÖã/•n€Wˆ+ÆÉ‚+!Èêvv•f†N³¸LPMBe˜¶ªàöŠéT¬ê´ŽÛy,‹º.€×ÌGd ñ2@—B—› ù Ÿ ¤‹ßY@_7òê( Çhd@<Å·à ÎŒ›4ÆfirÆÕébÚÁ24{¥sIwPés¨Ê`í%™ðräÆ2ßW%²)Z!›Àã°èÈ8èÞ|®2«*§<Ñ ñ¡h<çžÊ ˆ.G„õ§=³5!Ó13Vu@ÅŸQ¶Æ?·àØN%Öüäüéì+Ë´KPT“3ÀŸ5~€ØÙ2PRí]¢£uû±æ•ú·¯ß€»ÚøWv£“næ—V¨Œ'"BR&Lsj"†öî(_¢*ŽA*œÅk}0«ï³‡×v¯:\†QàG‰ˆ›µ¢µ<îq5¬ÆWwÝ×k :~žÇà(#o†Õ[®¯–ê3^%ûWmíܳ?‚üi]&±™j£_©‚ÚŠ0ãíÄN1*cf&düäÐ’q4¿<âÎÓÊeÒ½z2@Zø»!HrwæB-n*!â ¤‚­¥éHD—G”iuCbÆ©ÈPBÜ^b˜o|tƒ;ëViQ TϾ<äuPœú¥«èáâQÀŒæ»¤sR>e¹pÎY‡E¾‘< uiõê» HN¥àÐss| úËágÝ«ø ·IE–ˆ~!ªv¼.ß0ÓNä)äbÓ­ò›Òqk^ã„…@ý¨Qäx8T¶cž°V›uî‰é(Œ¼Ð%Z‘žp ¦ ÉÖν Àœ0r%xlõp»%B‚Áy¥õȾ«¬ˆúÕÒˆ§òJÀÿWIsœ3Ón÷TêŸì>ªÖ{d¤x9óå ãî©UNd tf¬ôÃbleäé_]L„î¼-sîX(h¸#R¡Qî Z•Jós¥Å”¼.[¨Ýç±^Fb ü1ùí;Ë„=˜‰.ª†²qЋÌ G„êèT<°M«”²‰S_X™Ãh×R¦ñghí¥åeÙÔÊÉ]Íìr|÷¥l1üzn!Ù¶¤)ù¨ÙxäïÝŒAdo‚Í+³ùmIØŽ×J;â¾u_ù2Ô×¶Óíì­ žäfÀv¡PÇŽ€'ÈãB÷àþ2¨ã}p{iíà‡ÖÊ’’'-Ç$qµèÒáìêBù碿çjMTP §ËÁg÷Üùx¤»÷¼Ð¹GSÕáì,˜á×­.¤‹Ì¿%µî?Ôz½iFl=-„zÄžg‘\èéž9:UV%tð[Ô„Mo¢¤ñ|~’mˆ/òé,¸ñ!=âý·°l­÷Õ!X§†uœó>Bc!Lò–©lFô&ÀªÌÌš*DaÎBÑÛWI¿ø ¡.š±4=ÍúòX·?µö㕸êÁ…ÜÈfl„_·ØÃò‹+`ÿZgjkhkQMÃ=£¨¯_ºïñj$ùê ð"‹¾PZ©¾«ãÌAµkŸÖaóáoß^Á;o‡™{Øq¥Zx®oJ¤~Ë((4·øT;Ïa$ž!„È'€, |…EVI¶³è_Ù·†rùQ=OÜåô0 3ûI˜×a”ä®Q9pĉÄW9¥5”u *¬º¯‹^.غA¹?1r@Q¦SÍ®*ÿ瀎´i£ÔztóKôŽØzJ?«ÑÏ'~O¤T"ãÜašñÂcìðaþ,"¦ÔŒ­Sô:LÄ­2‚›â” ôÔp—v¿¢í;#\ÜýüÛõðι}ÍÝȇÇ`Ž!à€ ò6–IOßgÂŒsxnKÔ•ˆœ²Aœ¨gjL;¸7NتÑáÓéÑʵ 5Š CíLÂ,˜˜ Ó}g)6îâvåÜŒOî…‹–*Õ‘ëq7S·eOSr'mº•‹»€”¢6oèÛ}Æù-iùÁÞݳ“+RfU£kž:å°xX²³›3,ƒ}6XWö!¬wÔð'¤† ¤‡~‘<ФðÛ·w˳³=Rí~m'žò¤¥ÝÿèìPkÍ}0’ÁœwR‹] +ÌÂU.8š]®^þÀƒ^/VZðÇFºå}šà+¨4¼™K%èÍ&¡‚µ²&&IoIÓ˜ZLÂ}žYØ5÷aI¦ƒ hYîÐÚþ›†¹`¹jTßË" ¶Æãû.¸ª—NPF™|µ¨6fÉPvpä€7ú@} ¢Í_æ›á"]êUÉÏ„Ž.ÒŒæ4‰h]ÓpD¯Ë¨ÞŸ‰àU ÿ”Îêøýû;.ÄrhÏ;¤?âQ•?ÀPmXë´£àž ”9¤¿ ‚–tê|÷4ÝÁË¿á©D?˜9pα¾ÏþÅ‚f•¿e",g9½Õþ³Qû%ì—ÅÞçßíp#•¯vÐ(Å¿|öß#¥V†4§z«•K\s8£Ý™d΂êwIhÄE>m¬9ŒK2üê\.tÀ`ò>Çáºq{íí†PÿálM³_ô§æˆkÏW ÿ'ßhß§ˆ®ä¥Ž&õÚ¬¯¿¼ÉMHa–”ð73 ¨ÚL&f<ÂÉ×TŽ» ¹A áSîäëmVJôq²Pé;&šÞ ž>9A 47€µäã]N¨¼f^À"Wu·ªä}A ¾—ª<üPé~ï¦;¶²:@2™i+³¥¾°gÃ(½I@•R d÷=ä®2>‘ŽÄ*˜^YyY‚ê&ÒªÐÍá6²âäux4ô§crFÃ.î²Þ°cU–®D=tB"7 öØßš8Ýûº-0Úºœâ?^â( ZCòÀt‘S RM«£åš¹€ª¨,¢¬ºªBo>¢{«? «QÜ|ÔI‚µQáÞMo)zÕ$eöÊʾz3{¯„ý(Jðâ†ìL7!@îÛI¼ò¢,®PõÄb@šW"»ˆƒ2ce»¼‡xò®GQaLÕðÕ“ šy¾¿ÔõÖVžŒ\nàêU¸8ëÌõCè„¢ —yz3ÄžDôÃòc’ ïz"‚¥JZ¸¥eô“< ‚èÊ=Ätëöf·ÄÉ¡µË8¡-x‡oÿÉJýÒzئØ’ò|ÉòƒÜH¢=9]š&tÖ—éü’yôuc$+1ýýÿg¸YiHU"!Xo ©‘9 9BóûRÍ ¡á°É|tÆ0+"vx4¡ß/ÍÁEÆ,j`_šÚTó|59»Ìšµ´–-CÙ`±Û©uu‡7v8—ñ¬›‹Ž)M,:U§°·lGáñÊ9Ø'_÷i"öê‚U5s»zM\ ™: zŽmVÓ‡?#bŒBWR0½¯\ä¤c„dñ÷×醤`rÑKV¼éU’€Õsðý÷6â=:@xõÌ9º‹9ìñ²„0‚ù½­Ë¾H$VþrR[•æ—¤Ç[¯£°ŽE#¸à)9Žž“& }«ðË …JFßßË™ÿRÆbG`[AÄÖ·äF#ŽY@lvk¯RÚ>Iÿ‰Ôy.Ñ}€;Oï.ÏRØVš^B‹`r3hyÂJ~Æ Nv9„”h6ÎÅC°Ï1¥+™?€|'™ÝR0öæüä8$ò¥ÝŸÿ6¨Õ7sŽÈZ_Œçõn§YAÿ)@¶>™Ñ «NäÂ.hCþ›¶ßj…Òœ¹ÚhO×"¥úU#Mz[u¤-¥å#$äZk‹HCåæÈ¦9¿èÕ£µ l?æ·V uz³^[/ÅQüàÞÙV¯ƒû¯6¢ª+y áßt‹ºv4C>åC`ar¬„>w1ix¤ð_Â×~í@ý"üA$C©¬Åоw»ÿǺC«}÷ÌN4z>g=µÃy+‰£]'XÓä~³VY#ÀiAŽëFôU©Ø¤S«TÎ’¼&O°Añ鈉¿úäÃÉTu„¤œQô©ã;d‹*ø¤u ’¥Äßkãî…¹Up‘Ôk¹©+¶þ©6¦. /Eì¶ŒLv´ƒCÌAmž„õ»^Ô%R›1#›ÀòxÇÿ3o²­‹>&©¨ìx™I!ûRqÚGò޵I~ŸÖq­vÀ«¬Õ΃£¾+7—\¤«#Š9ðwmûÛÈÊ_3Ü}"±ÿá«:±ž”äªÈÂ.7KÎÏ>§¡óÔµ îµQrÿUßþ~D,¥[6RvbÔdN{;P¸Ïþs¡%Tv;¸´ñÆÐ÷Å4 ¦zR.¸€Šeap)ã#^ݵX6—¤‚yï¾¹°ÉZMʺç„QÖà<XŸRõ K‘rBçLŸËÞé ÄHÉöÇpìXTFœ½$ëcÈJx¦%Ã~!v|šëx¯,jEc Ü«^ïãU©Ôš©ë€ßÞžqÝÒ¢"7a~-G*×W;ðõÒD+"ÓÓûR&EßIÈa+'¦l‡°7£LIßJ<1Á6³ έý~û çˆ$õ³¨È¥¼ÒQ^©Œºüž·UßY_Tf¶Wé­>KÀpÉ•Èü&iç­G9˜ ‚B·d WÕ¼ a";…Ô Ñ6O5¹Väì§¾ßd Å+iâ5¥Æc‹Ïw ëµ÷ŠL!ÂÍ ÆŽ¼XÔz åHw¿9zªµTgVEŽîõ@PMä]ºÁfodœ(£!Æ(HµK,.ʼêÄC-¸¥tmJŒ¹5%Wñª–«?•A‚§Ïx“ÞY€¦…Zln¹ÜHVâhQû{ï¢OqÞ:ò»›ëxP4—ì;‹õš¿¡å¯|Úå˜þKž¯[ÌÆÓk£ Y!ëÑ©k«Õm–›H|t="‘+ 6\$xsù¤DV†èô‹e½6“x”LG{G—@qsU—­$(“wl5Ì}‚‡Ág•©ë¢¹gþÚ³ùÐA(T9¢¹®ÓÈüà×?ZL½Ma2¾2«ýÆr1Ÿb•`óƒ2J™sµ´'/‰¡À–à!9ŠbxÜ»K"ð\Õ¯°_<ž<³äÇìê–hãaÑÔµëõv›/5†ù\X„8Ãf<ÍÙ6Û2{Æo+^éñkÎç.R¾ÿ-øšíÎÍçÆ÷^Óívö˜è´ØäœË9û(«Iiå~ù~Ó·.‡ ˆÖ^BÛáz%|„Soô‹™õþk3O0¼×½eÆÚ=Ö‰¥›#ºþ‹¤‘Ueüñ(Œíè!Ñ ]Ùˆ1‰Ɵ옹Þn%‰³á•ó·–ç‰éXÄ›r0à¹3p³‰¤-úºàÑ&…Æi.DÜö—÷elukt(^ä%ÖÇ“ü¹Cµ¼>‡?M†)ý<^GjÅC‘fëÞ_¦spU¸È ‚A±az4Çô™UÒ18ôt köYŸ-BøqŽW`f©å%y,žÔu–¾·ÏÂÕi _ü} @-p¥à¤1ÎÂä˜ð´Œ@£oå (݉x9·-’GY}dHòZ 2ßí{Hó¿«U(€¬«£‡ÐËŸÈœÞ/@÷h…GVU½"éßòŠ‡Ý—ò_!¨ÒÙ®‹(‹Áž„…5ÜøµÚN¿à¨ìÇ ½ÔÒ _î”ãñTaÀ£]WiÏÏkÑû%D’²YùÀÛ\ÆÍÇÔ HížØÍ?4ÄeíÝ;†xtÅQgÐ2þ‰æ,üè´©ñbCA}/1#2t]¶ åá½ óç£/²ŽmsFÖê_Ó’ N€Ì#×qµ0ö}ëáchýŠ©=øàéØhmÙ}«BŒ²;$ífP‚‹ů^ùù~G[ØÂø 1¿ ƒ7ØîÈîO÷Ã>¡4Ùq—>Š$yµó$ ³úV‹Ùzz¯™÷ Çàø!;”óIeû,Ó·TÉ›3Ñdþ¥3²Y3mIÍ7ìd>–õ£ˆ>¿bm5`ªžÀ©ø ƒüõyXßÓˆLøtrLüa‚ûp’§¥P/½À뱉à¦Á´ˆ¸¸™èÊòJ>ùK<Á×~PI§Óû7U÷b³@ËÅzÀyYÌâσ<'9t)ŽwEÕ:½¢@ãa“%3q*Y¯„aàp¼4„ЕÐÂÀþ 8õÏpTË ØúÝðÆÑkñ÷‡š€%³¾}G¿Å&îæa×Á™N_aY mj¼W—ÉÂTq7Úlr³¼V%¿prð ¬ùZõ8Ám8òg§"0ÛF]ãžàè0𬪰’5•ËôÏ&árѹ²KØôètÉÓ­ùîÎÀ I©ÞÕ2y„ØÆòÖuèÓÙæÚÒ\뜰#I$›Öàéšw¿1øJ<~7¿JC€Gó|l»:{Þ´T"¸FýW[3€3€Öâg ÉŽÑ~_ JM~vo•Î)†v ’ C¬Æ†·’ùôy–Єa ØÙtPõž£TôP¬°g¯Ïmc_qû ÚI®ë '63os'¿¢Æ˜sÉ´`§Ì'U}¤ÚW¥Xñ´4lÞŠ­‡£)èÎw²†à¶ÂuŸ¡)$Wc=DiJêÉGÃ5ßëTp\¬áJÊPvÝB´nÀ¯íT&89»¤èc¯µRÔ 4‰è5Á¸¯kxi)ðçßÑc!RŒ…0|÷´~_C]Ïó%°ƒ\4Ê‚*ÆN,È䯿 •¡ üÝ2àZw7XGªîJ†ê#·ß°b‰˜»ÛY­…2aÖ€ÁêJkEœKχ>ñ ÍæËzw„žã½°ÅCÌeÇ‹@€ü#oû¶~åâ®X~•.ÅÎJ8­fÛ ;¬·6QƒÝ!‹i/ÁO‰ùf/’>܆eûÜ™¯J°• ãXûÅñ³ÊC.Þ™£q—Z€CÛÐ@»WO8‘åÈŠ/ÁqòXòaà)Ÿô©îï XV`–+Ž@¹ÐW\Íš½§òýÌŠ°4âWzã»úaÂj©Fd¡;êÙók_œRéKÞô Û>€/ey‘ €y WgËÔSbîÎk@n¼|Maök–;Kd,Ø0Í6à3†±¡",9NˆíÊkãh•½¡&dè³­…±¦¦•‚,BÈþñYvç¶›ßB­LÛ”•ŸêLÉRà|Z®T üŽ-$‚Ñ¡«¥¥ëžÂ­ÇsºÝŽ»^l^4[›q×FÊ’ê4°Eôû(å½.Çè}v鋲 k,ë—Qù£Vp¢Æ#8TZÄ(ðÝ Û]„UJv˺@¡¡ÑË\8ûÅ‹"pw€¶”Pé‹2ãÒ6àɬI÷îîáú=(Ý6èç® >¶¨ цƒ|¿ý4%òg'êÔQÝäŠÙK=Ub‚èÅùÝ€PŸC·²ç‡Ÿw4ò<ËÉÊZ ”ÉVNµL[1RkÂ>kâé#£}Æ®¯ìˆ^ü)üáï%:ö‚ÇWºXì_,ÛoÁ«Üø©Sûcº@ìqÛùœ'Ê[AýÙªw€¦þ±óLÿwÆê3—U$Ðßð^¶‹ë>D€ 75Š ±(„žîÌÔŸZbÞåã‚ |ÉÁ€j:a}:>ç¯'@•f©|/yÈyaõ{2»x÷2j!™pEÎ6»0Ï3½ášPº->.þöUžAÑ¿?é ‹Hl6"nžRw'çF¤¸*ôØÿû1þÛ&L§[í0ÉõòîgÛ¢Œ®L‚¿wIÀ'ðŲ…¥HàŽGºT{?Ù@±z|ðŽ#­SC"w'p«‹¸ß¤Qe¡â³ÏH«Ý(Öª+%Pu›‰iÄPq®G6€ÐÅ>j¯xמ¬½8Ò©Õ;øHiˆI‰ùÖ€Ú#˜På(9ÀO®’KÛøß-ÒôHVAøÕð$b ÑŠ~é'\9"Íܽc6ì‹•¥ÖÊWvyT¹9 ¨<•IºïŠûœÏÁ6ö¯ÄSTÄîxdu¬“ÒWùo"üT ±ˆ€ö+/p§$Ýtòþ¾A”ª÷uöè›bÐÒŽÀõç²bà]'^˜öÞ[œû¢±¯íu£Iq±í'_l%µä…{ÛÒûd4d&ò¢4„"¢ ƒw^nŒyb?ÚRTðw–õf\ŸÚAÇë8\ ²~¯…]ý‡Äg)´îî˜?^X½mët u¤@zš®pÌí/›?öbE1á:ŠºøþëÐæsZöÏ på¿tEöIŽ·üŸ™#¾ž9Eqj¬ lj¸‘zͶH·ó?)a 0ŠÌnOM‰€ƒÔSŒ¡û™sçëªÙ(Dÿf½@¯ Û/W`Õ½&åTó”5¸O“ä*Á*Ì/$χ$ ëœSAÚ9'1Pß_ÆJÚ¦¢*j*jcϹ†’ÆÔC´,EâàÞK•Û,¯Ù+¿4ÅGy1ÈQ"†‰)m$ÙcOâ3]¾;]÷Ã@Ûô†v]}øÆ˜"xHÓ¦ë¸ˉQCµ½×±q¾¢yúPÒÜn‡c %ªc³wØËòyx_]ÆN«X¥òO—dðÇ´P?VóΞÙC7ÌÝÅSÁÞLµ ã0ý~ízŒê²,hH°+NEoP ¹ÉùÏ*a3Õ/ç§]Ü´¡;=­oçûÃQ&¹¿…ÔÅu%\¤r]Îm¿Šünê¿¥:ÙrË4Ï/Ôc™Áém¾‘|#´‹í­@XQtëñë~Eÿ*€m¯ó!Ò=ýêBIÑ+äuÖÃïçu‚¯Úȹa¬¦|œ.ò“‚'´Z ÚuI=)ê^eÔxMÔ îÁèkϸ ‹ºè°@:1~áýõua€tÀ¦b#9{VÈ’î)ÓÁ†ùˆ®dÖsã•§Q¸Úy@çìQ’ÿ©§ýyZ§ñ;ZÜ(;œ àVPÔÇÛ27m¢‹¢_¼€}_ÐÀ2µáŒ®z£Ù¼ÐŒdã‡yûFÆÐ|`ˆÒ¥ÆAðLÂ?J±›|Þ–ˆx€_‰‹—¸7Ó@0—R£…O.»85ÁÃDfnÝ_f€M5­>¥N 1!>üGªþõ_±–Ú”dsÞ.þ7‚€þ»ö31–ª@FÏôBú(9‹!Rbâä\€Ãõ¨Æ…O[¹VG‡àë;Ü£ån¬—×<õÍ!á6CN÷ó]†¹4I"ë |D‡ö!ÔŒê$3}kéo§(«ösf+Xu;>yS0¶^"Q°Ž™›ÑÜpÀò#Àf$9£rŸÐë:œÝÛ|«Áê ÷)’Í‹–8¹_€ª0¤Œái¯'÷Ñ'[»?ØZ|þÃ6ÎU.Sjà_…ËžE°øŠmK¬,QdÕ'rPD¾~h²¥`bágÑ÷°]  Îp•“6Ñ“—yì‚qÍ¥8VpíVMž&°ˆm9Îõ`ÿiB ¹G– E˜tl>ÿ—Á+cˆÖ GÜ9HQ*qÜn!7¸¸Üf(\Ðsæk|¡6Õ-Le™ºÏÄàb6¤[\Ù=–²ßVÔªU2JÒÏNC*–EûƉ†»b)ñîTbÊAéëÀÉ…ŒÁfÇ·ñ×7±=†®ŒHà>Ÿ©÷ùx¶°‚Póµ× Ï„›¾-‚•umðÿLˆOT·¾Cᬕ9ðClËv÷^Ÿ%ަjÉ>ÃjQ†ÉN5|>¡U%7t²ªþ.”Á}²l—A^Hxk$ fÂd2„Å#’;-˜TÌD¾!nYn í{m¯îŸËoó 3=‰¥ÌÀ“B©Ü€ß#ßEì×j ÒúT„žž¸óx%´RYªÎ]þ•7ž=4 ÉMF¾ÕÖ$OSZøh^ˆ–u`¸ÿºxàØ½{û¸/WG‹ÃŽÅçį’'tÚ¼ÄNÛ#rä>˜jþQ…úƒï% ÒÞµ)QÝ%à™à*-Økxæ6Ë/iÁö² )0Üœ¸¤Y–|Ú¬ëõ«x0Ç1kîCòÔ84AÂÐBßI@¡Nµ|2ªw$Z Zdp0¸úÍŽ™2€x½ûص¼±fØÒÕ;£”©pu¤ìÇ\pY¬ºl𫿉T†ê_ò× ÚÏø,¼ä³„%ø k ןZ·erÖAÌàMãfð"½Êv·µ³yô„Vx<iä|à%\ïŽà!„×§pdòAéúø‚ÀÙM|±ÏC¤_2{mÐXm~†›7?Þp)‘u¡È4="$i„ЫŠô­Ná KÈû;'Ó,L\BX;7¿Çk2Ïäý;¾,nÒPêŠnãYÿæge+KÂâOðÅxZ_7¨T¾tä±5aÈxK+œo1ºÝÃ{…Ê^ÀZ0*õÎø˜Á^6#Ë¿=;úgCÆ;ÑÇ¿œh;ä׃DsŠ+ ±—}dØ‹¡áCQ²:Ia N $ØoÝ¿y½Ëík†ýY_qv¾JO¹Ü™EµÛ× ƇÈÕœj{j,Ϩy ¤õðÆDmÿéIgÌ3WŸ½Ñ€é©ÿ3škÁìZ?ìÛºäLд¼‡˜Ž§ onH›ªQóšÐŸêâêä\Чè3ƒ¶Nz·c<>’½C*‹}.î+VçbÐHÖo_y¸•Åó¾èü–DÖ·˜ÿd>u¸¬%Ef…ÿ&|¿”žU¨ÇÙÔ×Â_p+oÉÚå`YšZÞ_†(ƒûe`9ÂxQÞÔGyÕtøX¨Ë¦ íñ')…,Iì†<üéß>%Ô¤Ž ÈÏG*;üÑ¿{£-ƒ¬eCNÔKŸïšý€-꿟ÜÖž§Òö;G¯°+"žâö ŽžéȦŒÃ7#ýS ;–\4­—U*ísàT‚àëˆÂ×¼.TV]1¦…Í7XÊßbØ Væ/°žõábŒ:…`I2ˆyh‘uŽ7aCŒ;ôn¤ÄÔy¸k~lKÚ‹ GSV`ÊŸÊ«N2–>:ÚKý—˜kQ>y‚¶Ä?:ixÆQþ[½ä¹-RsÆ,‚ÁVÇpÛÈe:1;&†áÛž¬·Š ôó·õÂÕ6åô°„~ûS0 .-7“–u¨œ5?PÖ‚cy=³‚ n’÷R|aÃãT€ãEBÁû¸šÜ@þªbcüŒšžZVs³ã[ÉÆaÃaº¤Õæ ¿- +G1>_Û†ecX‡¿·rP‰y;Dy•›Èq W endstream endobj 10 0 obj 46432 endobj 11 0 obj << /Name /Im3 /Type /XObject /Length 12 0 R /Filter /FlateDecode /Subtype /Image /Width 2085 /Height 1259 /BitsPerComponent 4 /ColorSpace [/Indexed /DeviceRGB 15 ] /SMask 9 0 R /Mask [0 0] >> stream Ì9bAÂ!V‚2–‰Ùw\ðÌ@·Öþ£ Oª5ÎÜ@ܽõÆIõúœ-¼_V‘ƒTnt|Òɰ ‚oÐ$1È@­Ò‚Ëæa±¦&ZM¬¹bp%"Ê“¼â´eæ•J©—ßd\'0è[)Žè ï“+éÜiÃÖNhÕž¹{Âã`pÿó»¤j/‘Ñ/¡(_b_‰•ðBó‘Ÿ›¯—=£ÀÄè/ˆ#j›yq*i`Êq×øá‡½ÞB¿Z–,~q jˆ“]+|Q¹§Ut’îÇ}k&ÿ,àÞ`v- JnJ£VÞ/,B,E£6ïU– if¢ÀÄlë”Áý—$¿«Ra¹¸Xm9„!Îôy&Ö¦† 5o·5§3)Íõ–óUˆ$¸Ç'šË7ßоðÚ àNLˆDäò×ÑÌÛCÒ5[)œJ’@}pË&&mד@·Eº+ëÝ_áЦQƒ¼KæÂû“l°¶·¦M ’‚Dà”{+k?åJùº!¸2)½¿HÁàÛHp“ çnâÔ<šEPŽ˜JHÚñóJEXüRr1ãn}à’J Såòþ¦Ãð&”äV¿ž Ú*Ιޙ·½Þ˰tý»1s9Bºe¸rEÿ kj˜jf;_\`Çj„ú%õå§c4(§ºÓX¢ îß™ 0—ø´ókIõ,Z!Ã份>` ·½m;´yš)b }fI œÙÒnä㼿«ý¡¢;-ýœ³3D‹†÷×OH†d…¯×Ÿ—6T¡13?ë2a!æV÷’d£Ð“R› dn|qjŒÖ¬çädßg¼Üchý†TÎÇ g¥æJ´sOGÆ7÷p6Íߣ€`Ô©ÿ޳ëðïÒéuÔÄM–vÞ8<̳Èf3V‘ýéuË8};÷QLLW¹‘ä½ú ^";툈NŸøq¼Ä—ªæ3²ßÇ zì,W*~Ïä.Ne˜òÁÜ,å™UÖC3Qì: «ù9dìÛ§†_xá4Yå•[YÕ,çШäç Ýüs±Z;RÔ§Spm:µ;zã§iÖoTøwú;JU$R;hÏÔ#YÜA¹ÍhM&çº:¸± x¹JY˨Ų岺œ?Õç~•ÎHí¢ç‡þ±«ç;ëwÜ 6ã9C’÷ž¢È$âEwŸYB€ÍÁý«Ù6Fá>HÞì§XW¿ÿ)è”Üz=š>[Q ¼ú\¼†œHæO†ÃóÙ2¢„×&gGóǯ÷þfësÏʋݑºMM@"gÅÝî2΄²RTô°sóˆ5Ið ‘ ,×f¿^DVüš¥îF´ÉuéTLTYµ5E“išÙê±Ù¢/´xÛ©½Ÿ÷S˜‰ky­5á[ÉÎ^Hƒ0­ÌŽ@lÆCðc”×@óóú{1YåNúº8«c×üMé3ÝT—ÛòËü«ËÅ^Ö'E_a*!…¹×ß&r´µ‰¯Ùg‚ŒÛZ H/xüÉdŒLÄÁzY¾xíÃþýðê`àG]ÔyX§,dk®+„Ä.Ú95µ+–ÕJ€¿O]˜¼àæ|Ž{P“| ÀTf5ÄO2z–È&®ngN±Uã |Âdf’|¦ÀG¨Uñµ¨`’uû¡F(/5¢óˆ )Ú²Í㩞Ï⨕PëmàKmDÒ/2%pÚñU9¡`¶É¡fÍÐÞ£ÌÐTÉ›Ò}sš+3Gs å’¦¨4ɸï@F7ò±æÌÑþxÅ èÆLm€ÃÃcÞ’GµC¥,jZ¼ºÆoîæ9'äMDB#’<Ú€:Ѹvq6R×¹b#ËÐ1ó~>(/ Ñ+±ÖÍ4ˆ°S<00a:«=ÂÖGÊs]Uæ¥ôÎCúذ˜ AµO±ü|;ý}Jz? ^BšHɨ˜Þ^oti.»| (R¢‰®ªäáW ü >´ú`ëÎÍw•Ê&,‘…óÞYF3‚Mw6‹A9zÆkIí™wôGVÉHÕÿ†LgCI`”½muçºY7ÁÑ_þ¼%F…7)â¶§¦=À%Xè¯ß ÆbM’5ŒÖë¤mkÊrœ ð±Ä7T‰BÆ ÝN˜–†\‹®›Œ0¡å‘¡wæ`“BÒ[æOŸ…þÀð>TÃuËÒ‰.l7L“ð‡¢W2Î,ç Ö as¨/hEC¥Ƚ^j±"ƒ¶kÿ™•š´.DiN³×TgõÔÊ& j¤ •||,N§SS Ë5U>MwœÎàjˆb1¼}H#Jçúýõ—z›…œšu„oË«LC-§°HŸØÇõÞS¿¿q¥…µHvH•X1*žþ¥«ÂœºÎvJ›˜"ž(‚ªò©™Ó‚¨[¼`ÚÏaé—Ñ—ý~k£ªÅUºÔ5*‹nöên®ª8=¹ó@zk7jú­WWŠØ4t*©e¡4UfctŠ0‹ZªÓÊ' °þÂ(e)ê5­,©qh»ÓT­×$] š!êˆV`-üeé¼ÉŽ(<ñçä[(ªù±ÉÎtƒ>ü ߆7ëf™Óë¬8M¶¯íkC¼B¹C÷pZC]§ÃêycšÂŠî^ze­*^ÎP¤Ç9*–‹˜`éŠ0 5ÿó\(aþÜÝ oç%ì.—s8Ú¤àÒþ8’@ᓚÈ&}bâ|i¼‹wmq/ché¥/@9S¦q ³{÷;u&Üï»&_–Øÿ¿­©Þ¶qîýš=ª"]9¥çËÇ«è$«hm#mÝâ…ÕRYzúLúPȤÔjùïr™ÖQÛ²³§éE4ÐÉI$âQÚxçTDS¾vÿš´áKk²Œ$¹ÃU©¥É$jȶð—_¬òº9,9H`f>"˜§àvµTÄŒ zô–W¼Q%›1öNŸxR+ƒg<òë>…W¯ß¹sâÅæH½:4ˆÝöN‚b.ÌŠ/0ì|úD¿9lz¿¤Aó3ës8[îTkJ;½Ìš™Võ=°i€Êhê·’¦IW„®\ACš²FÉC8Ù—øÊwâ+×Ï¡0ÅÝdn2òXÀqß”þ4»ðÖõyݾ¬ž ÏúHy§fJÒ¸A°7­fðú]º ”ߣW.|‚yé\ÇáÇåbM—;c–J9¢‘CMp¥§ã¼Œ£,¶f•+nun.„çz Ó¯° rIi¶‚‹*³´ì °Ÿ\ÀÃýƒº`]àÒ´r —cr]»†$ ÿíðŒ'm¾ä¼œT­ãÝQ¶ÍðaèÐh¦Êéešˆ\ç!Ú-N°sût±íMúƒs ÖÖRcÌ»Ÿ8’ÞeÃ/¤ï ‹P.§Z–ñ(V#GóÁUw°Óñén"+‰"_9žÕèÅ0°^ÙÖ-‹wcg­%°ðþ¶¬•â Ét¿·¬9ðñéo¬-ý›O´] Ý“œ d0tè{ÄËQ`R.Tòí¬A¹‘è¥8Nµq}[mgô½›o8âÜyå¸ºŽ£=êÃsðûޝ¤xû¿<|ú²Ùå]®œ­ûXá–ý|­ñŸ>’n­ïI×j¾ÄWj‡#°ÝEh ¹ö!€©0‡½šì9¼Ïîjd†âN>p©ù±GÔŽXm:€$’¨Ü?hŒå‚•Q€GFüqö+ýK4à.`yßrsw1_0P-•.e.ÜÃAC XµÁ×XIw3^pc·o»ÁÂ%™þ®PØŽ´_QѭДˆ'júÁGˆVƒÉ¿Ëå‚óuèDÌã#L°Ä!1ž OÏoú[n}ǘ%s1«º2mQÌÊa럧ӥ]Å[„‘ºW}´Åcj6Søí4å§DXðÄfiB?§]ÏÄÄÏû;Û£#ŸÉïXÈ–SÏ‹g%@Wiï?–!]¹†N“‰wh`…˜„ð†õÜAwü1¾Äç¦î2*µÁzlã»OJV37-¦xù¥HUÆ"4¤Ç‹/ââ¨kªeâ­ª‹á„1õF£‡œP¦ú‘^:îL!Ù÷~^—‘ª6¿{‹xÏìüêÉV§”:¿“YÃÍH §¢¸ÄìÄ6ö8úNRÏÁ±•‹#žN§ó†j[Bň+':^œ©\Æ¢VÅþ×£RƒcÀ9ÌØ%Â`XN#b缪#òÚE§¡ÅSú†ýZ¶ $œŠôC‹¢ô\û ⇠农 xä"‚´FÆ”}ÙZkŸÓ™3ÿƺð7ÄPeÂÚ—Å¥û¾j'Oä6%ž2weœ|³ldBzÎâ®PEÝç--6)¼Û(Pv5½M2¬þL‹oLG&`<U9¢¿j-š”'†½Æ±ÍËAÔ-Z·û2„XC·^uÜï¿ëãÆdáO}Aš$x`TÌ(Nš‡Œ„_}ã¥eógÅ>ªN[W£rôÿ0­'d#€lva‰¯‚uÖJŽ^s±5äø¬n(FÝu-MŸÐ*œ˜w?4añÕµÊY89)˜vCüç#¥sãÛþ‹Oq›³42nç7Øæi@ŒdûäU°2dÊ´b\ È9ñy>Øyj.‹Ë¾,AOÈŸ˜¯VÒÀ/‹Z4¯_S ð @ÓrÚf–‘»Þ>Èbÿòm¶luã"{dâê âûU95çab~Óó‰™eº€.8ÇÚ sÞlÇ-¨˜µè³’Û)4¯ûçH˜ÿ°ð"¼;™ÆGµ®ÒA‡Â*㟤U] yK§†þÄÝ©d´Î§ë9™Í¼À‰”ù ¡×äØ\%±Ù)×O·Sá5{&KØgæZ¦sÐVˆ ºÐó…[áù½×v°u½MÃ{=Ubx…ë>°µå¦,mˆ1ö-0Ôã&ãÔêiÜ?©³Ý£æ Ú(^VµUq€Cp¸áXE¹¿õÃÔEˆG¼‰¿)ý©'áQƒ å €F/â!)!q8ø"iÅ[”-}´P¢“¢P–¹äY‰1øl›v€îý¡Gû»amö;“–—ç?šÑ°LBN éAúôc-YfÍ O”ÛÆïgw*W"N+&-íûs:ª¶=¶Ê¤àØâ2й{1¿ž w}óõº7áÕä°wJ]EÞá­oRAŸ©ªAðTt ã\MiøÅýn*Iƺél5Sò´zÓLê8 8“·¤j«s•í(úy¿W˜0aØZ9»DÍ'JÖ!L³æÊtÂw–ĵhÍMmçC./&¬H];ÿÍÜ$[¢Oøc_4nà{]?H˜mºƒÖ¨¡Q— º¨ï¼°ªçMêºu‚H¿›>”žÏé€z qÔŸY¡É˜XÇ2à‚í²×q_,nmÆ›ç` ›a^⢛4L_çÐ'¯üTgÏõqM ðKMg~,ÐN<¸ZÈžF/øý– R!Z‰ ú{ye§ÝÖmå{z2¥&ÈÁëBç×%ˆ+#yI5‘×–ÿ-®µ·9÷ á/ˆ2“$³¾ÿ]´‰Ïþf•²ø¢È!zýY«í|ÆàÍz\“°sûÇðìMêš…ÆGÚw%O]'âijíSüAeäÕŒ_ö²¬],LB©—}«6Œí²p@äÁÛ¼.犾v U‘ÿ¡Wxà[—v»%Q]?dLè3¡Udd™ä`ê¾²ÖÑÆÿcÞ­€\ Õ’—à—¯Ìp”#¯ðÃÍ5Ȫ‹šåF9_Ѩ—|l"ã-›âO!Ößò¼:­…Ï÷ÈCŠP×»Ó…Îxâ–íÔ £x“ú.¶Ðž·‘KñrŠð<ìpT>»ët9rùp~A_Ý,¹®Z/cP”¡³Óî¿´t|;9n1ÀDÈR¶Á+œÿɧ㠦C‰ $9þ§ÌY^'…œýáèSÚilK'ÌÜ¿“PŠ RU{å¤ÑY+Nb$¹ ì]7Bo:#z©Bfš9Þ‘Ì»†KZÅ]6«@¨‹…d}Y* ØêÛq¾wƒl-§ßa‹ÔàÓ` `¬>%˜©æ}¨š¾Á¤ãe/‡´Qã˜Ê7ˆ>Ðn9Ö»s5LÑ’xŸÙI 'qÔ!ŒSu Ž&$þLª71 ¯m.áoÓgžÍi‘9¤Í·´Emó6v«ÈÈý)Ý6C¯«TÖ<ßVäí°¬Ñ“‹ŒÀ¯û¥íF@zåHº>­f'oþk´oÆê‰¦Hñ£!d´Ijè‰ÄÓ™äUë@ûòÄh‹ê¨+–-ÑÎôBÆØ¾ºP/ˆvFÒ£0D¶à'9pîšoÙ¤¿o­ëã )¶©Q@~qã* :Û mNQ­0 ?\dEÝÁ²îGìÈ Ë¨Óu3ê½M›å© ìð62K¶Î5'Ã-‘Ä_…R™â4{ÞâO,Ì$þ¸±y$#%úŸ"|XÍΔÌíáZëVB‰ƒEs‡â}¿{D™’d¸…öû’—NÜ»Ãô?âÑŸé‚@µ5—GŸ± ”-åÁq9UñÔè ´e£ë ¼½Aålä’ØMcÈÅì.W#oÉÊzÜ[1û„Iè’þƒ±êh!åZÌj™5GvÈQ¦ùÂ*„M—a—_ÕØë|mìg¶7é}´Ù§[ýfÎîzY=&_\è_Q2Pe uš9J(M½Pø8XWZQ(}N%Ы©üþz©†UĆÆæÿ=ÈQª¤ µÁh°áþ¬jâÚ͵$‘ h»ÚÞʼ– ÁeYf²OŽ’©ÈzÕÇ©­wO‡eùð¦7ÏXõ/ÖšCX?ˆ(÷6Ä¢ßUB*ÀòN/[.™‘í:X¦¨¤j”ÂáÅåî±ó¨ÆIÒ MfÎ ˆ/  {¸½2 ~ÅtÏgÆ] üm•±µáÞKÝø;Tç³ÛÙ5¶n‰ŒK«©@c®ƒ¹$%?½g?çd6p>x£­œLXÖ zÎúL„»½G*&(Öɦɹ™ÅÍÞÚËçyË{þ&„(õ‡ˆoë´ò¦Nàc7íH8¦[‹VŸ˜AH$iaúî¼Ã¶ùÝ´ ÷H»`~lJn­|T€3Üsj(ÅMû»]Ò•UNV jz`Ìì_!Ú±˜ q!{zÝÏ$)æãwP¶ÓWž_UUØoèw&Ow‘ö_£33}9Ë”3~ѹ²ˆïY.DO(£}ØhA£IfHvðߌjéUlÅqBg4Sˆ rÚÜJѦ#æä«fÐëlõåôö¯Áú# ³ÒŸs°@Í…) þ>Ði‡DP¼3H½˜àˆÅ¢4r%Èì”ÖØÝᙤD=貯øâЅߢ«œá•7M’ù¿{—4e­{‹­0éw~*ºÒ蘑¿Àbk•ˆYÜÁz ÇèSñÆaƒÊë¢ñòŠ-{6ЉÙk+Ȇeë«’&·ðIm‹FÎßš/µ0%ŽFÿßùþnFïåÓ±y×_ +:8ÍIB4ýÖY_{ZMµ[‡ôÜ_0#ËF1‚µDQüóTut*(ÛSÛ`£1‹‡sƒÿ¼2ðY¥Ÿv¶,JÝP^5¼ÃÞÜh14èuúä&Ö¤ý¼H t)&/¨,UçŽ\Ñû¹õêëæÛè ˆàé2s®DXï®Í@ö>y†T @Ï €ò¶J=Çn ¬îI£ÌC©j!ï@ÞÕS¯[„Θ΃êŠIØÎÜêqkÌ 9É'…öZGq£¹ê06qö:¡"œÙ§M~)@áY}×tN 6!µ>3ùÑ 3³'tÛ\òºÍ2âaìP¿ð™.›¢;wü´VÔ•7  `æc“»M+U£õ“3òáÆ^ hçOÏûb@Zß@{§–ÓxGq}Ŭ%6+ ¡`O Êl•ÃQNR¥ OGk‚wƒ7J€šnUÏy·€¢üá ”ˆÃ?Ÿœý, NLÀ«®fµ³i y,pÎ7„~0Qû Ñ îËâ4¿‰ŒíÔÉ«ë˜dÍ–Ã,¡Ç𛇯Òô+² ñk *éfÚ…ßýØ~ö¡p7ü4äi„ekhÿJô׎5%2U¨µlqÙÁ1%3–gfy’™¿2q¾¤Òœ˜*^œ–˜xOþ °o³D<ó‡á~fy¤ü³;zE(iÂtßJÝøXqô·€#&Æû©mnÛP~â"û‰‰| ŠÞ¿ëìéb,Ys>ÑNO÷쉚€òw½ZOZ›UwÅy* Á ÅIÄ_úNAà‘tØ®FXXÐôÍ÷< ›YݶÅkbÎÑ€n ҅騶£“L¹I(]ZÀ3X²Zº¤:\¿—N\ œt—Ô´-ÞrtÆx‡ ¼Z9 WŠe0Yb|Ð/¨vâ÷›8OÎ=ÒÃÝFÙ0¿S#P‰aì?nŸg“ˆ±‚ç÷=³6>UMC'Så›hê­c'üqëªãàlK5/w ¤‹ô2¯mç “Rr/€UåsI¶\Áì7_†³Ã’~PE·%<â‰pìÉð¦Z’Sž yÀVÂP¢øùÞ~à‹:ä¹§¥ÆÍ{Y»˜)xز¶¬õ}awQlÐà–ÚÌä$SchØ2ÃÙ‹…ø—ð‡¾Æ¶í²§ÓÜž’n†?îEE¿àâ9B†ëÁ‘™î&+Ž@ðÁRž¤ÞNÍ~9ÊM.ßÔÕ»·Y,t ‚eÀN|Uu¢­ðÜ»9*´–¶€êÐ7öüõ'Òx*¯Øµo/Ê‘ùéÎð2”ÓÌ:÷äÃMÂ5¡,÷‡Öë·Å¾˜ëýÿ`JAfRÀ¬Ì6µC=˜±i¯+s‚F±µå¥¼²¦h¯{’j8¿Xd ÇRÞ¦°«þ3gDZ k,×FqÝÅ¿°Û¢ü«š^[ùLJRµ)hru€±Â®RôMß»üØ%õøè×›p·§§…ˆ ´ä{‘ì6,}Ô÷jMÕFØaŒAIᓱ¤±«‚d'G\ŒâÐè’ä`!¹`—†PˆžuC;Ø}¼'hÔ4E¼1eEQÑãúE_ &Ëç.Šmþ™4N¾‡“xÝ¥MܱUcÒhÏê¨ô]Ž–Ÿ­¦3Ý\À.§Øå&¿‹ršÍƒ]v‡”‘%F?ŠGcšê{Ô{€¾mÅ%>”ýÝ3à L˜ó`AŸâµr™ÿ'«8”ºâú9,ÂÜkÐ$(ž7÷¥Ø¶ÀH;OI/§iÐSúüÔ­ Sw€G†#Tyó3BB.êÿhúU%ÚpìÞ+ˆç'ý‚㎠†SûÁVÜvÑ>§Ä1 µl0]ŒjWìeŠI,§¿ÒF«Øžˆüª'Ûƒr#DfüCo´ÜVÔ¤ö<ÕbM1%Ï] ÖŒEÜnõ]£Í%. ’ò)”4Þ//¤:x·"pØ ¬‹Xݰ&g†ÕLÿ|ŠÛþK¿<öDU½s£b•8‚U[–4W{DU[Ù¼-´|¦È¡evbkU1Ž`²Âaã•n …ÞZ¥uKã; îL¬âxMQ¡#ÁÁ¾*0zmšµLGEØçxÙDk /ßê£ÿE…|ðùÙO3>žé €íá]7ã-Ðô3Dž¾бÉéÃü!ž: ¾ÏUI£Ü£6}±hÌ^—½v`©Û°«©§½1¥dó\ž5Ä æ1\׃2Ù+ó¢^CY ¬üÄ «î•ÊÃ9NÏŒ÷§VžC¼™dÑ(‰ØÒøzïø¨Î{JdòEiÖèó¨/¡'0^–yŒ¥…ïËlñƶ÷< !ä±àt»I‘s’Iáz½ÕUÁjuFqX½ $= ¥V èZT:ÌöOŠæoª÷þØÿ¦QQ|é²F¦ücw~Ö¡ñãOv\(ü|ÏýŒ&)VјyK*íè³HzŽ9Ps*V™v*×jƒ»•2³—|§AœâÇËs (‚‰‹¦é‘#‘‡¼ª†Ý3 }c*#&à-UêF42¯ÇJ"gìèájE-£Yt}Æï9(€7î²ÁxñX9Nõ6z×Ëß{Ù§©”¨äʦ .jó¢ãTzNk ›ñ!Ýh‚…™J˜÷rõÁ»ø*”k‚>%(þÞu•Û„(ÏÎCƒ(ªN˾_\S"iƒ½ó¼h_ ÝñM´1“/ îa¹áOl¼EÈRÊÔuiß‹Šm´¤ºkÔëôƼœ‚ø¤2ν{)ÈÚòáîëìÎTÑc|Ô¬²ŽÒyO‘‡K“Í0ÓÜ@”•e³JÉÔn?¦µº'”™zl#Ô¤ßIÒaˆ®^ƒì##ï•þ®þø!LC…I‚¢ø’%˜„1Ò×-ĸjþåþÈUó›/Õc÷7ç,³Wg‘lÌÎq æ¤gOÇ Œ…6lÜ'h` ·º±oóÀò¹y§Ž\ئí'œ}8(ý&ÏÃÀüè .[gi|… k‚ò0å¦põN8 Ù“T6µ¢˜´s2N_ ü„:Ê€Mt›7ÖŠjà1m ¾ì¤íñ""bк„Ò¾&KÄæá—ßüøÜ‚-f)Ÿ±ÐC›cÎ pþ h‘¾1Ýüß]U_ä<½¼˜•ËJ?e‹Ä 6™7Ú†¬kLZYLN¦$­¯¶þESUÖò Ù5nY ëIóôcýìKÚè,FËuUÞ$/K~½k]€ñFÈc]€£žbB€’tfdŠ$ò+êo‹1°Û@žß½rÀý÷ Á­>ñ‘;¥âs<š‹[ÔY5Ê ¹ é™ E»`kÍT ¹ð7=Ñ×j½ÈÒ›ïf* ‹’ý1F¨¿ BÞXbÈ_¨³ Ó‰;—»Â ±ƒH·ÎÞé}óýŠ÷„¿× œõê7R ¾;~\•/Õ¶äÉΨ ¨#q8~Šº{ªÁ‘¨qà8ío:úO7XU"õB¤$3ûIXgÃgëÚšÒ­C±Þwé?¥.hÁ1Ç~Ád`ïuØ÷´ F<hµùD'5bÿ&‡¢(Ë&£1¿½q± 8 «253tVî÷˜1zÑÔEvåè—²Z˜øF†‹‘_É‚Ò7 \.2#&Ê?ââÖš2½0èèÆI€¥døf‡ô¾PýB@§ÐÑšÖ^ãr`C§ÉD4«øáÈ ¤TÄ«t"ˆþ1*ÞKy˜=þŠ$¸ œĬC/Oz!‹ŠSØ3ÍD½ïį™N_ð«Kôm –ÝP2F Ãn±â8´û‡«!*]õèA¨†ˆ“Œ«°r@óµ (3#¨4ÙÔí7–*(/HùÓca 6tD‹CTK6 ô¦>3ÅaT®’ÁL¥R=Ü•¢µóZ€#ªC¿¬ÊÒ«ø@)W½n­ H¾8© øBqÑÞPž¸Ó ¬jÔ³z5\ãçqÚÖjÑ“š_¡%kõsþUÎÑ’¦Ï¬cXþÅ­ïÑ¢·~’ îžÏ\%Ïï;ó„Z-‘=yå^¦l¸kàÚMÝÙz áu¯€D¿ÆB{4‰RKvÖ¹r$´æ¦ØÈÜÃûzÕZáx€P˜rã Ÿ²ñºÍ÷Òí¸Ð¹ä=dÉ=Œù$V›¨5Hæönò&9#•é³ö†_šêPÿ[ê®ß ϾALØлþôIª'¤JRéÆÄWALË®®ˆªB£„ }Iq(äøžÍA{ûT ̽¯ä¨ õáŒP½uÞ .Çô´†¤\róšVž÷0nã×hø¯*ŠÕSCý,˜ 5|a"KqYؾ4J¬ƒì-ŒqÃB 4ó¦¦É/Ëê Ïöeªƒy¦³4ʹ±B)-þê<•–ö˜JÄa~Ê¥xÝ¿\½¤Á⻑ÊX¨Ìâm<ɶk£­U‹5ÉþNÀàkg§R}5¸“gdm_ìdånŒóìª/§öä˜n»bcÆLé‹&kz}–—ߊÍB8ô™f6(D¼ëêÒMœ7/QçtÔ« wGX¬¿а.¡¾¶´›:jêº -ßÉ8ñŸ-´-¨Ã´Ï.<½Í ôÍœm‡6WÔ;Ô-éãBÉÈ SîòvÖ ìþ’#s„s"¤¸1¼›'k«ÿaÛªò>@Ã4 ïã¬ø2ž”î,Èí"}s"ZjsÈ’!¼ƒ½ÇÁJýÅgiíÊ: gr-Ðy­]tÿxÁZܲ“y©Ï7 ïX¿x‘ïÙXÂú›'ÕëâÚ\Iù›©¡ˆ–3vâÆ·/“Y+‡d`Ìu`7Û¹Ÿ¯W ‚|6l€l7í³¾´ªYY4ã©öÄÇ3ïŽlôÊI¯ÖcÐgSôÀŸŸ‰QSªÓˆÁ¹ß"ŽÏdgtzõy¦àiœA”™ÜJ±Ë°Œ x±Š]¾I‹Êy7ð$­kfL‚m_µ­(ÝKÙÝó\gTèñp& ž•RsÕ­5@±ö•„çŸ""ìÁ <}¿ÀKñÍM³ íKÓÚZ0Tõ) )‹÷ç3‚ËxÊéÄúišP˜h¸=Wöea„pÔ¾Þ,ĬÛ(±W>šÐ‘_ š(…Ó’,EYû§ÆV¦?øP‰ x‹ÛƒI Æ@â¦KÀ^šyÆ="š#ºú÷­/{;ºùN»8†ÂÆ7jøÙñFgeÇO×Êxú·[]Eþ?þ’„tÑÛ¦Ù¹˜_… SßK®Ÿ¥è¨ …¹Â’Õ·éM­Ð'ÃåAäÑ^jÒ«ê5ŠŠr…öÕŠGÓÜôc«lÃÝj 1¥";Wϧ?W†m&Öª¢€üg„¡!fÀM yŽü-¶¼ç¢±ú©ïod‚šš²•©ÎRŽGtІo.’#}m⌘¬“ìÈNçu)+ù«(CïQBúž±-‚XpiuüÇY¢ ¨¶*î‚”üê8ûAI?ɵÙýPÅ$ *e0J0†g$ãwͺ9–. ·ðbõñ°S ª—f])ø»e—0rŠ!q鉞`T¯D`›ºíG`ø^Š·w¦Ã™wŵû4)°x$UBšª–£Í 5 ¼×~òBTµÏŽ)¸LUO¿©!ÌÏá'ÚÀ êÀÃ$ý Ù-‚†¢Tî }ø› éŠXÄ€sÝ,` y‡®Ù¶7èÒ}FIößçQLŽF¹q&ž ¢²xÏGô£ÕAJˆkqöƒªÏäÚÍÙÏ–ÍÉ‘ž­8¶MùiÐwÂk½ùp¬zDšª¹K@iÚËô´Í£ÅϽ†lþcÔ“r± œƒº¾0vâ-(d–øÛŸÊmP4 [h¼ ¦ó/sAážµ,hoÏ;—2†a<Áa0?\ éÁĬ]Û%ÇêçÃÐã½8íÑ" H¥<]ìûëïvÿ·U0ÀT2ÑÊAk\$_·œ {™;Ý<€o½‰Õ f>ÿ»*Û½‹ ðúØŽ“{xý·î¤ ©ƒøýeå‘Åeø ºµ }Ó·nq˜þŸ (j¢Œ{Ûð·²È°"è!¹yò2ŽR"ºÌqBûÀªNEžW+‰ë‡EeägÜàâx ûðÑ\ÆÑðØg:C’5ˆ¥?óžSpÌâŸDmùHZãB|Þð$ùì~ùÙ¡†Ò`bþt9;ÍÖQc­®cIbúÁ þ"ÄÉ•¤FÞe5bÊ\˜`˜¢fb†~ô jPÅB sÜÎÔ 9’Ë~$‡DoZá°Q[[?6µs¸à\‘‚ ÉëÔ?ìå;ÛèÁyÎÈóÑ'†¨2u?¾Nþ!«m kÙ6üxN1ãÞ^÷ ‰âißûŠów{Ýñц‘èaípGþñ‡1íA¼ÀÎÅóA‚P±™¦¥@&È~!ƒþä §>¯©†Yße!Á™\,ª›9ù$‰èÙæp”†sþ7”˜[àÓ“[*G f+†çÎpŒ¦7~¿Þo1¥Ië1~á=½ öàçgƒ\"`‹B„P"1>NÊëÖ{ÑÙZf.°Zx¦ð 欹…±džúdòíJð.;×–=§Ãc¯StP‡+Ǧ9GšˆÜ4†ØsË'?þniÈEÄoèOgC;ާ?äY#oj¢.Š­U+]Ù8oú¨Y~äyªía–c\º3æä’é µ¡RÙ›o5pLªð¶3 ‰Ä‘À.£« ¹ àÖxLå"L‚…k¼Õ¶awWÙ2•B´ ÕÓm/x²“Ü[¦-z¤¿éÌÞ¤Õ kHª¹ßÒ?J}æŠdÑÁK²ä>hhsó/DQþ¼ò>ôì:z©¯åþÏ Úœk‰6$"Ùˆ"’%”\‡ L!¯òß°Ï8ÿDqΤ©t†äíl6šN•-‹]>…Á9·$–òⵉ¦Äµ[ o!Àÿú±*¸‘¤ÉlÍŸp@%5f™hƒ²¬¿$Ø_³æ½œ>T¬òòü±;t £û™åу€#‡¨EÁ}ªŽ“z€»È?Ìâ$üÇ^v›H`Uôn¼$Üå¹uÃ^¾ÌBm’kE #þÒ(¶æÓÂÅï¼±æŒíµ S<:‘ývq!t)’ãÔü6žPhQ\SØeƒ'okqò è®jæ§Fuׇ5v;Â)¥T˜%l¢Úª¸Õïè²Ç>ébÇ%ÁTʧ€tÄ?q—·W×ý7ÀͽŸœ{Ék~Qvæ.¢âžÌ1ÁK‰@ÆP ]‘ÉP Àÿdä»%w]“ÝÊ ¡³Éüeƒ3Ñû«z,´%å•ÁŠwÓÚ5LÚ©;Û”QîñŒgœ@†¥–RÆ$¦´ bl»ŸR꽸J°”òÑÅ8,h?_“ïUñÃj±þßã.iØy Ü3kÛ¢¨ ±@0&k™’´;ƒÆgÐjN ÚF¶¸Ö&˜p´ ™WmïL¯'ÍPú-WÄn#ƒrº N³¼b?)µe7סiØóc«ÕT+‘ûEº%eWØx–¾ëRÅóEéRc&R/‘9rô,‡`€ˆˆ?œ콶²IçæÍ"}»=€°R gí ô°Ié ‰ýaÀ’ék•˜É:\S¸GÎb cóiùÛý[É“*Q4äâM£¤áJÙ(DEj2ÄøMƒNbæv3]]›>ìdÃdÔ!dé&ìº7‘0¶›”ÞýQYg®³SQ­«î¢ž¶&í+‚kn¼ï«´;EãÅ,X*lëÝ©•ÄŠnþÈsêîI)äìë+>Î(ú ©rŽg·sÇËòá"cÏ(gêìW.š[‚ëäûcn¯âF”C}>$ë¨ ÊçÂa•#FáñÔ  _ik6ÞQ‰üð³Çß”æåË`­"U ZÒɽ–EÜBwo¯^ã µ/h©zý?4Ø4£3i–‰çð.n(«<T æÑbR³)Gù| ´¡¶y§×ÈU9¹¢×4ÿJ´·ÿ“ŸÛËà]Ÿ™XÚÉn ׎ðè",©Ô1Ìøôƒ¾Ĺ É£‰ìœ7_nôgóv¸öIÁØ^—}Q´ûÀ%¦€ÁÂm\ ™Y¦PR'¥îopíJI®ù¬…¡Lå¬sv&•ÈæéAÀ%µr½ ;,1˜_L5×`™‚Q²î¬ÞwË•ÅãŸÊŸÀQÌ +ó½£¶nûöF¢w…Où*23h¿t§)oºâQ5<åÏic*D¹ìh°–[a« ´­Ç|Fd[æDiá+d ‹ã=–Á&…g'„–¸~qæðmм5å&£#/û#/@V+ §þ„*?x˜¸þÏÝ}-UžzàÌÉ$ðræ'4Ö¬•Ü ?-ˆ`Ëø;ZkgÞJ­Ì`×ÅÊJ·²´žú]D+¥Æþq;˜ËÎîM0¸\tæÒtt\ªçÌøç¬º•œ—”.EÀÉš#B”P…‹Õu^{Mï-šyÏ  ¨]ÄA4iÙ4F!Í´"“B!]äFͨŽ[o\Ó°>§$Å/®ë·ü¼çÖÐ44o J±zêÑq9,n˜NꔊèOK˜ÑáBÏVYX¦x!öéjjâñ\|Â@ö¿ª,ãÍéYú,f$¸ô¢*¸*æLA“c#¦Äõ —7媼KT K vÆŸXñ„Ç{Í›ï:a¿||pÆ*ÎQÃÃæÈ²‚iØÅW11ŽÈ8?¡~˜/8’оÒÔÚT¯î•@µo£t¹p—Ñ´m1!,£tÒ·h]¸$7ÒN'iØ–ÏØÂÀµÔ6á!c‰€{æõ°›ÿûÖIÕsªr.ú¦ø *ª“Éîž°Lbi'j|“fvWÙ”+Ú‚÷º‹Š)æs½îëý5»ax…z‚=ÁoÆâ ªÙ]}\6ReuïïG rs_ˆ§Ù§=y8ƒá†@XØE’ž³0Ôã&…¹UÁ;r¡Þ¯%ñãíí"\¨(—Oì6?‡(&|÷ÐJ‚b ‘“5|Òa2­‚²…ˆ“Wã\_k[(£Gé ýÔìî(O»Ý9휭ñ„ +éÝ&2s¾ÇЍ+PðJ«T clÓ)–³Ó§HçKqgYRû¹51­FD{g}ÏjuMŸiùÏ(T!É=;Tó'ƒˆCß¶kUYqfI¨ŽÁ(É‘M ÇV¸€Ôñ78?štÕ¿Øw|"g鯊§ÂJCõ6…¸dBÍz±®¸Slî ¯þVK]Å`¯îqB¢§ÂØLø¨à»¡IxËÅ#7÷£¯Eµ t¶žø^a[ƒÌÆ\A»£¢¢}óÑý³êÐý¤†ÊNªJÛÌ[½LÁ¥:ïH(Þè­5ÔØ™É8únîªÂ õ—äSvG\ N¤­‹Ñ~Æ…*«Å”òbm²0]"Ìï:zÌùáß‘w¥FÏΕ/ÈHâ·éG†˜cïÉ ]*öµâçsmŠkLw%£ì »Sël‚»/ô-G?€/ÆL ­Žzû0Þtd”×¶}õqðÎSh#86þ窡aiÓhh˜tçÉ,e÷ÖàÖpB«×ç¾K³Ù 'ìh1Ëhç’Òo›K§)º<õiœ{NÎP¨/öôóP MøÜÁ骀ŽiJ“¼%ŠŸR—òÖƒuWGÿ<Ò_ä¼å·QÛ·"½òè·=éÄÅý¢þ~Êix°f†Ûr[ÓÚ¹œ4ù”©øi»@ž¡w“ùË»«àTåK8 ro`¯ò†œñ—ïÂýÒÀPY îêÏ/°/²[LcàCûCR‘ŠAìeo’ªSÀjà‹Ô·¡7PÿbÄ-JPÊEÌF u70ÔQùÅK”JUŒt»°ž†®3z/mSèzƒo¹2Š6µzG}—ò¹plæT‰ñJÃ4¬-c˜ŸbXʑ͵õ,ÙùDНæ×ûÞYûzA9+œÁ5Fêµçœ•A®âÌ=d‰ƒ¸—þ„CIÙ… )¸à5 £7ÝHߣÜû1SÎð eÕ+îYµX̵h¾éRÓwž“Þ¸êæJ–ÚELˆÆÆÚ«*5¢‚¥ ]©³ðNUMâ€écvåà{¼o}<’ÔåG~B.Òhæ: †<ÓÚ»’Ú,‘ÕIœÈàÁNnð(:âMÑÜ œ¤yèGÊÞ«Záá,ÞÜ$.‘.Øß{tÍ€Zžä@ƒ“ÄfÄôÛ'ª:‹QŸÜü~b­ò–Æs :þMXÁ·^5”Öšºì|±ÍƒSƒ34ðºwl%³²ÖÅÂTQeŽdÈ{xލ9ô”Õª9 8©ó¯ø>#:úÀÞsÈ]ô?P™Ã ²Â¸„Èw*7½>rc5ÒÕƒÐãÈò$BœNøù $r¨äg¾VCÇÿy8Lÿ?#¾<¨ké‰ ÌžXÀy*Dÿéìâð“*k!eó'Mù Bújwö²õC¤€×ÅlçÝGˆJÃ6]Ê•ìxå)u1AžQA´k¦"mƒOÿ§ôùJM:^Bù¨B¡ IPø½1·½ö‰ñ.΀|upðŠº¢¬“MUläºN°zñÔ5p©¼›ì”Ɯ̓›%¹Ïœò¨pª&ì–t@ ¥¥h-c¾ç•Zä ¯×|vâçû8RîîaoÑ”Š«7HŒg8" ‚|wX F^ Ms¥€UäÞIX楑nÅ„š[©åÑnÃÈ€Ö d Él¼}S—ƒ¹Uó¿ÆÉY FûµØõ„7]X 8Ä}½œìÂ/5!¹Ç’šÉ9zßB'©Öî=7‰•’tùãjIëU²b“×4~ÇáSb ëó ýwß™%ŽW‹71“ºs«™ì˜*w^ñ}Îv}‚wÏŠq2õ=t€ñ4Xñ T¹„Äîyb…Çs0Ÿ˜;c^ŒÈ°4ÐL$¤®&;ïÙ_ú=ˆ¦þÃ;[~#Ýtl{µÝ¤ƒ¿ ¯ž@;wò™šŒ 4ä€U€’ö¸é¡¼h*¬´OÌŸz㘭y)lèb€ouq—,TWÙs=ÔYãûäÐ7I‘ä±öDBØK!³Ú?Ëi󹌉"¸xçÿ1Ìíf¡Vƒùžõ»†Ù{àŠ&N¤R õüI† Xú©™ æÁÈçú*\ïuëéf$dÌk1DÁ¡4¦lRÈ1Þ°ž¨1»'æ¡Q™¨#ÔogÛ4‚}mý(!HÀñ¤$¯$hŸfßë˜e3‚ ã|Gö #â€ׯÅú™¤¶†GG©ŠyÙAüƒ­ê§oŸ@"¼Œ%†¢ç³AÌ»Úa3æßÆjYvûxöiçÅàD¸z-º²bJbê÷‡hÝ-L2›ŠökØé´xõ¯Eï¾ Lˆ œFÿ`“Åmõîáë z»iµï¾ö¿þ PcO¿ÿ®^aoÉÑȦۇ«°.T†T¼xGóøÕ˜÷&§ã&py$ ÄŒpÖ^.Ñ–:üØ÷ò v<{•1`Wh–誻‘Cgõ%L¢0»EÃJI@™sáEΈȗí2wQkCñù¤˜J󶃹 ÉÈz45Ñ…æp€ì³ú¨**B )c«®Ž‡föŽp¯X£Ý¦‚”mY™ñ¦ ;R ÄáXÌ9$>~Üc¼…D[ 9+_ëãÊeE,ïÐmÉtQb@ÆÝfðŸ“̸\ªÌà»DFêÆ#b$%Óº¥£>òn[$髼øûjÚeÐ|.ÎH{ Ì@å?I/êÞø˜ÏÍÚa”WÐh½/¡a­\èÌh:xïI*ohq5w'Q)ñœÃðâ` ·ž¶r. 8Z掙Xj z°Ë~)Àô‡èœ8ªkKcƒ¢’ý}ŸÍúl8”̱Ó;s_%:Žv±…¡’§Þ1mêPôu’¤Z)UJ£¯°)Ï‹ÍÅpwÖ ›á_lƒÂ:nNbfSßÎ¤Ì I˜ü 4q´(ðÑÂ1ñF ÙË¢]÷¶¿xAsf½BǺðÙ{ó|M„BWBHxøûk*A3ôbçí÷ö»ŸKÒ‡áw;-Ó⟳D]§?î+Ñ«×r~Ã+ħƒj8ÉVþGY5jÈjë€}©ùÕ¿wpF•DëJ…u‰ÞQËÈÃ'8Œ¬.†©6H7&óAT¬˜Ò;Á¡§·(—#¥„iØ_óŠù®ñdyi§9kÒWÆT”â°È Ögx¸¤†’h0¦fLCX¸·Ùl ‹‹vsBDÑà€r)Æ,;naE«4G¬åJ‚¡~î;ëLXK(†âƒ(WšQŽ^S¢Z߯j±ëFPî…Š‘0·bZßö‡»wó¢³»1ÃÎ|¤äGé ]Hpr`ƒ‡¸º0KÚÇæ %ÉvÜÕ ÿìÛ8ÜŠ®U@UßÞâ-ÿ’ãZ½¸K¬3bpu¾1ÓJ](ïylQRF“a~T^üíÜÄÞÒ$óÒ»@ØJÍì7¾}úxR ;eùÎkÑèåB]£¡¾ˆ‚+ü„Âýâ*©3lÜh„YÝÑ1F~«štе@ÀñÒ&ï(·ê÷‘óQT8R*w·bQ3Ô&wFÅÚ¢4¡Y­¹tnC6oy¸S‰=Fû•²xQÃö˜BO_ÜAÁ¶‹8sŸÈ¹éMÐ4œb³ÆÉ€¨¨'1žšÆ£ðPOëqSÎ@ˆY¡3/4O¼ú ‰6¸ðyt ê)ž€Ц“ >6BR4–@¡‘3kÍ>`Î| ƒo%8 –;€žýoZòZq% CûÐåí±GR›\ J²èA±§&›l”F¸ØZ t·Z$Ï¢ Ló2šõzIŠ4\8- ¬¢LÖ ñІŽöë".Àì¹&J–‰I'Ï֨΢‹SÒ‰Mä½TÎÊd掛dæu½´ñ¿~¶ }¬­þ™Æ¦õ@ê.ó¿…KŠñ–‚¶ È_×j¬¡¬ÐÑcFÑ/¡_²Üµ&¡>Dʄ՛YÂ7l`Sý¯q$‰:²ŽÙ”0yû«ÛñØ+'Ê—/1 @X´ŒU…ªß€‡^VI£q0>ñý ¿@ÌN@æÜ–‚ÑÞ‡Tð,|œ«0Œ6×Z{zˆ^E¢(m –†š»E™F`ìÆAÙ}zEÈéy1}"˜í1*-ÏødæÉ0ü˜±ç¶ýt”¥d¨"%®4×¢Ìøv ãͱ’,XVÈúgÍV;”ŽM*4ípÖj޲Ãa)Ë@ŠÏ𿯀¾é>n=‡Ã³þ_y¯ègG4yâiS˜©üy‚ɧªiô%S„^ººó¯þÌ&NkІêtQW¥êH4iOO1-´ýþ ‹b†Ñ½4ЄJt-j]}8õºJ=ð[ó(äýê“÷`(󞛾ž×-¼e x{OîÝÆ}<Ïþ,7©k¢›,÷4Ù{gƒƒ§N „¾â‘ ÆB+¼'ãï[d#C¾ž¿üÕà­å§F9ûÂS¼ˆüœb˜xþK´:Øãˆ,!ø!m„<ö>_à±Ù^œÜklþrFž»y³4~íÍ~îE¦*I…é#;’{ö'ßåü–êûõIc¸*} ím$ MÁYÄ/Té­ã8“("ì.kòtìcn'Z7…,Ë(Àï×yFe™Ú½ÐWv¥ñ® ’¦ÉçOëÅL¹N_4_r¥‘`yõ±f %R¬á  „7¤9ˆŒºOWEÙ1æ1âÞ[³‘I}%éý hUx']öÃIP‘&äýF¸âè©% ;#\¹—Har”Sn³ýOƒ< ¹éMàc–šèÙEŸ9ô0JŽ-ã™’Ãä6Â5^Ä¿äüÉýU%àÝÍ`3,¿zö3-H×»3i+É&´°-Q>RÂÖ%„,Ć&Ò_.hì¼é—¸Ölã Ìóªi[pÓÝÝòCÖD¼{TûWì;È2‡”;M×Z¥¾àPËÁ(ª …·Œ*à; Y§~Äm‰“âÔÛð§hº¡™ÀM4%4{?!€´ŸÙ,‰f óÙ+”À‹î"Ìà³DWiŸ?j~5%tê÷ÃY:":Íæ®T¯ï B°DgÒýÝÁ’ ¢!= —§ã•™6o‰‡'5è¡Ú ›ïaöÓµµ0€¼o}iž ‡`›}ci¿{==žÞ^ÙóLd~Ó®ùm[ \hIí˜4E ]FJj[þð( ".s·Ãe È ’2Ä)3Š£ |¼ð‘ YN)‰âøL¥™H¢LäÂ%˜›OÒµH®©’+ÈÕ"¨+0VêÜeüéËe.V.¡T«ÝGñ€Z=àô?À{¯â³í;DJ鼫/¦¥•ºzÒ®A° Æ­wµª¨Ê-d/0òìuÊ`‘ò¨à* C'ðK"û1 ´ êqN̼œ™€sN§ü#9Izþ¨O›„€^ýÇS››è¬Žc¬ A)e…Ô9ß¾ƒ¬Î„* Ô‡ÊØJß8Ô²i /mÖi(M>ì!([S âDÔ)P(VCKTçÕê¼rž&ã÷Âù~C‰ÐÙÕëÁ§ûeí°+ áº9¬cÍà²ÃÚxçŠÛ¼”ç?€o*—U³¿õ<ðú}iÉ£Tüuº8QÆ‹µ$03f‰…)ÚX ìÁwòѨö%é>5$üÖJAáw”#dø#Ðû¬‡ÐÇËM9ag[Íþ5õ¦^Ï/5àÛØ–T“YÓŸ…³€‡å1eìSªQÉÒÚÿËŽá÷€‰;1~X@–’F‰ W_V|GëÒbÅÂÞ–‰a#À¯ÄµxuÂ÷„€š\ÙÅîÊ fqpÕ¶X’6HCÃ'…Ʀp ¼ûj®…1>×­ÓýNçþ  ¾‘þÛ­sM´ °àÔaþÏ- 9Ü)§Ž”Uf é­ð¾·…§(wF™nIdã;!ð€•o>Ú­¬x]\ÀÔ'‡ë,4 ¶ÓcgæÊwèD§Qõt˨ÛÜÃçuEüKÙœ“ièc•º'ÍVapǹMh+-k ×çp3X•8ÙRå¡&'4<Õ`Zð°£"¨Ç5w¦#Èzœ†P VîTMg(pÀýØÕ ïf¦yfÛ©û5Â~´5®«CìïË­Tq»ÐóRQ•90ªãþôPøTûPôæãܸ¤…d*±"lº^‚;PØ’ÖOÙGÿÆèñ¹Ÿ~‹xU4öÝú „÷z &cý×oâÝñ'HÝ£G›?îq±Ðû,e¹˜à·gë½òB.W%o"¥l Êe•<¹3^Ê#ù`ÞšEê]Lº¸…™¡«ìe:UD[EæÏÞ)rû…–½¯ LI¨¹ƒìÙ(àŸoÒÛÕCÔÔàKÏé2­°êgò¯¶;è‘ÜfºOÄ*jöøV¸˜Eä?Kÿ­T ž8Sô^,}BÆÉõ4¸Ë‹[Ìš0¹ãƒ5jØ©¥ÖFê ðŠ(“ §‡{Š!®‚ÊxàÐìÆÀ¾NT-íè}Ÿ\5èW$ñâs-JÓǶ8£û™û@Ìþ!^½ìU0ÀªÎESŸM‹¥0ÛaŽL€A¢Ug¶ÔM¤a§-°ãÚ;F(ן6,­Í "‘h™dB ^ýñm`ƀ䰺Ul¤qõì»MÒ éø>Dj¯ƒgé»n„þ‰•Îeâ2Giiˆ9/Ì÷Ž}²ÛaªÊÀE“§ M;¦Ì“la¤¦ÝôVR¾ÒñyG1G´Þ÷)/®à.}€BòÔ(á±¥•¤+_ïk]@Ü 7¬WÛ@¨þ•K?ʃ;¶î ÅÞ±;à#Ñ’`×í…áߥªÈM,¦­Nø*}ÔìÈ%èÀ 2ÊDµôç¿¥‹#î!üDlYÏé´_S’¬³¨úL³úŠ-Çþ¦ r—¨ß¯“V^ÍÅÌ«k)cÞºIlÔ{¡b%þfWc½å¯–uCC±ueÚ˜Xßž±)Dg]ƒ.D¾k×@ÿ°aL%ÎËË9 Q¼˜ËÙ8 VËÒ¯}%ô˜2О²aRž²ô3ŠßPðHø¾È_×ã©CüÚJL>¼u­§–Øï”é[•dQ64h‚%ÿy!0\B[ˆÑÛ~OßÓ=¥Z$žªoW² ø_Û0›¥(‡yŽG…,TÅP{þ{H Ú(!DòàÊLL_ÑÈà%l«¥ãݽy¬³Œ xŠy¾ä¯(A÷e 1Ù³•#˜9¡Ý]ǨühÓkÕ§ÿ´Ydû…i9hæ£êƒ[ïØÂø‰F(}®*{ Ï\˜÷~Ýr¤ƒâ~@qŠj ‚A$Vñ·¥ágC‰Yƒ> ½üæM5Ôù•n®3mgZÙ[¬¹qÒu£µ =€R¡ÑÒf†\Å¥·Ç©”Í*sXÙíhÙB”E6ÿà„÷’6‹µ A¿É[mïX¥}¤¸¼>P4 !ÅȺA [ é¿s|™V¢ÍpZ\ß\qÉJa?'îų~9|úÇÝГ¶ë‹ÆQb¨isösÖP˱4zÓÌY(…~Q‹ÿpijØ­q[™-ªqÌ:Ez+ç6€Å7ëAÂa‰¤ôÈDêíÒžtšHè•’§<й2>K†!JÇWu£Ò0üŜϯdR¶†ã“˨=áôæÂÅ ­N-Ë6ªÍÓÓŒåâ­N§j»çQs°_ý>ºþÓ ßæÚý((‹!pr´ZC¾›ù]ðûãôŸn Èþ¯~Ïى覥Â'„o‘D¦««¥zÝ”ˆboì&¢H\> =$g.t›Ó nñÄÝÉgã®E1° ^Yf®l¹¾ þ~ûYµäI™ÛafÔýÃR"NB°§²¤€~`b"£~ÌàRN´û‚ÆÐ_î>Å 8lfÞÊðDÐ4ýC6¦¡ƒjomU9׺ñ5s †î"GV¸pG´‘¬õ ¯NìËȉE¡)ÞQ¹ãh ›…Ü‘?ÀµÎF²ý`Át¦°è*µÍˆÛB~¿÷ÿ©m>)è „ù÷ôxꢂn|8ÆV½n:²±Õ=™qØÕ²xÔdù9 ð¾¥cA°)Âo¹_¨}Lý*Ä5ÏÉ*Ï©]l_N>uƒïÊ.Ùd RËG{  Qlè¡èý,¥¤kÞ ãjæ/e¨[§i¶×Ùs/oæõ&çm-õb27Éóž£ÿîþüËU#åéÔoKOv'à´¢3ÇÁ^ ”F‡NUY*ÏÇQßmŠø«,ÙîV~‹5, âp9œ7 TˆhA–)îyY6ŠÛ_V¶¬=—fš±N]w:š&}¶¢·B7ÖPœ’õªI+aV'ŠÁ”d´·8žÿÁ.qðÂj†Bˆ¯™Œ]Ó9¿9«$Òt–WÛ¹™ö`6Í­‰ÓóV–6¬²õbíf®uBº>Ù‰öŠħ±ZÖÖtaù¾§f·Ÿ^àr ^¬äT1V¤n˜[L}iìf-Ç]œ.^ýcã'§!C†™ E×½KCT}ZÃÎÌJ;aAxo‘nl«P‡&·…é,wæ¹Â©´\(– «eђ¯€€,‹RÜõï 7&=tÿ tz–ì Ì‚}‰x.ƒ‚䩸‘mæBZ'áÂðø(ì`iDjùçÕéÝ6ÿ-M‹5̆¹§ò`É”Ø>ý†%zÑù*ððÒeÆ]hñ±PË”¸-´J} ;zÄ…åðPR1Ä¡§@Q,¿øQ±ÒÍß`¸FHabŒmº)¹O4ãïq¶@Îuĺ±üžr§ä·þ8 3Ë6u.«7~zb»)gmÒ;¤+¦ëPpœÉ1ÈRIé£îÀ©oLOAªƒwÅÍ 0”ÜQÔ.V} Ïy¨=%GŸ‹S\hñ笾*åµ.'±Š2Ö¦_wjÔc!ÁÈÉ®C.M 08݆)^{¡èo…fµº±ß€ ‡÷‡¬´†O~,5=½¼HÄq¿¹®˜Ä®«Ótt<Ç×Îo¨’žGÊðÈòéYmߟ™`‹>DµJÐkâuš—î8 '-ôߺȇ´ŽjUŸé.Št?!3< Ùß1n¤S^&Ó+vƒ$Ö‰ñ‡lÙ«UÕ¹?û¡:ЀÿS(ÝoÝ‘ªþ8¬ª{Ì}ÕÄjçx’]ùåŠCC\I¨¼à£««ª"ÌÈ]˜ŸýEî8Ø‘­@&֭覞3@o«J —1©˜H¥{*\"¹õ—¸X†£êèWFêQàsAWâ#±–Ó½¶¬¸_X¨cúÍI2kž…3$7º1÷ûƒ¯S¹{®;,oá°dÅ·/®D^õA]ñËŠ;¨X'ÐÇÝʺÌÔ³ñŠÜo\"—é€.|;­‰V‰Œ® Öű`4Æ'Ô®{[XÅÐI¸æëån¿oLCÔþ¥¡]oГV˜¡#>©ZŽóP5(éš*·|¢¼"ä«‹š_«,âdØ®Kï8ÛT%’j»©»–™$ =ÛþE>>ˆ&0rž_!œoz hBÐÜß«ÊóPèŽN=7ô%¥Oª™’˜«GÜ›álFìî‚y §ºWj ùÆmbìˆXÇB&´ó梞…à·ûßÑÈI´ýhe;çu dÀ›†gb满ÈM'[M†ÀÙÃh½È„jY&ÙLúÒ¶ì“{t’D/ò‡‘^ФîãY´.­£{·°3{ÁøžÉæt1¸(ËÐÜIOþ® ¹æ‹³oHnÀïšÊ‚'ÿ±qƒ2C­Åa_u6r©züÝtqÂâ)í¿t ÑS>=OÂú.(¾ÇApÚw¶+bE"³ãîÙìKì}‘Õl ”óCµÅF~®ª zðV…îxÉÖºMÖJ§6ËHò@㽃¡›1 > ÍbEÜä…’dÛ²Ã\kUàŒÅnÐѱ–…*ÞÐÜ·%—s4—pÕUÊÅjv60ÍgèP  ÓVmÀÏ\(b1býpr̾׵wÈxx½õ.{ÓÐN¢>Y -Ò/°.U)ѧ×ùQ(Æ­(å Xô·ìrï 'Q\õ–D]?ÑfÒ-0ÕîàþÜž |ËåW— ³ï6Šý¿÷O30E·¦˜:Là˜}…p_ò»éÝÍEI>`>:RìjC8aËå}W‹0l>^EÁ±h æÒðÀU·Üã ^Àgiöƒ&·Òç‡xK»fú#:Iøþ±côòk÷ë-Þºïlœ?«EàþnXåüf˜ ±ÑiÐpõ:/ø ïXr4N›¼ý´¿(ƒŠ¯âèe£ön‹-r0ë©Õ7Q«\$xín^O[ÖÞm 4ÓÃÄ…Éœr"»erPŒ¨´•òótÿ’”XOÍÈtP¼…“±ÚÝá‡a¶cµµ¬´¤µþ6ë“ï1¢È1›¯5‹!Õú»_dþ“= álDZ.~‘«'é|Êlƒì/1Ï/|M¨ò;S”ÊÒ!q©¦ý@Üö™‚ßñB7*^Åü¥7â‚ÇÐôD@îé!¡?"^sÄåz.C¤÷€[ Ê‹kãú”VOìq¶êEÆù&WVŽ»‡„ÂkwÒо¤A–rÅw>ÆÖ–ƒv•·gBÅc¼øè¤^ŒHÎÜÕ3:·i©%F*³K„Ò-Þ„‰%Û :Õ^¦чO,Âè/ሃŸAèQoRÓëŠè^x hœYÛê.ÜùUã. ñYšs|ÿ_âÂý•£[ºÿçqÁ©ó›¨nhÉÝcjz· c$ Ax 4D/Óá.ПZ確ÆéÙŒþŒ‘ÖƒÜeÌú³d„3²R5lÂô’u„ˆMLBš£†QÉ«ŠÜ,‘Äa5N„ŽÄÌñ/²õxä†Á \ØzI/|MxÁH„7Ò^˜$Xü‚9Avï5Àø†Þ¯ib¤³z•éÆBô,gTì9·¸ÏntW²òjG^[Í)rÌË\­ùüåÙœójUKý‘ŸëœMÏ”Í8Ü&3¼ï¡Ìü¡Ãg¼Õ¼—t¶Ìý+i5bz­sØ~°²Š—KÐ& K ó[.¤[)]NÏñqP½ß`]3 X[™YžÄY N¤«º!G꣋ÖcÁÅ&ØâYÅ÷!­¹Nîp¤È vŸ< Úë8 NUê1½ GÃÆ+YT`ØÑQh,_–œhö¢×÷ v£;´-lRÉe²8h£?™±Sµ!¶cêÝÑgñ&OÕ‰DHûÔoºéÕB Šv?ãro°L‰"_$¨:/Ì0E!hü¢~yØÓâhβ8Šl×-þ¨‘éêz×û®¦aíɼÇé³·kàŠ|4¬;졯#2"ÁÂý¶ jp)#y4ßS ûirÝÕÒOï!o˜×lGãxÉçêÔEúÅÜL%5aƒÕÅR5â³Ü÷˜¡TÓy’©EåìD’„±Vâ^ªlÂ~8Ö-¤b—±ý3 ú\èËmXh!5 µffê(Óåz‚×^bý‘æ±÷wð­Feu® v¶ÃåCÕí'ë‹0m>êã´BKÍú‹•ÜjÝ~ rr´rÒZŒ –RaC:!/Éïχ¸ì°G ïÀyÄ#81góge÷Р൓ißk*WÙ£ú…éôÁXú.`Þ~*÷øã…>štÒ†ä/ÀNi¶«YX%½‰æëþ‚aæ`ÓPu±Œ½«=›@X&¤t»ÃUÕD&Ëeû#–œ¶ŒÎ÷ÇŠ)÷T6ˆêƒË-+™´ð†§Ñ^—ÝúZâÃ@n Ö’Jª¿gÅ[G¦È[›+Ê•«¹ÎJfc/nú×ÀÊÊ÷ÉÔþx\bGXBÆB>Ü×k_}Èš5a“ýÈèØï왯€öD·¬‰,D僱õ{Fî%¶~¹è€HpòóT®qÉrÒ‹ñ¾ LJÛuDqêog;}Ö܂؊õ³ªÈ|D=àBÏô‰\WCÆŒñT ¹ÊœÕúüp´;„¦j/#X ¡´×pCöÝÆ…jálC÷ŠžË{òìÖ:"VYÄW4|´Ë.iWGhœ@ðHÞ"8sÙ…Ñ@ –´Òö“çøL _™þ¯h€0ÌÈåÓlL¨>~ƒå††ù8¥½¸A{S€BúA0ï¨VDÃæ Xsd;9) ï(6Z' s—ŠÎÚŒ9!Mð´)Tc¯¡¸Ä÷¯És¨r¶œ$Úذï=GP˜\|F®Õ~©(Mˆ£Oèžu®Új‡6Ò<¦vû¯èØC-_'ÿº&+•Aœc9ì(Æœù—ÎÕÇgè»QY=oOöi†¨ûððÁ‰¥œcQ%¥¸Õ–ÿ§ ¸¨ÑÊt5CúáXœ"“·…[¼_—`÷, (\¾ý sÏ>zQs&ÉåPÜè¼Æ…ù'ѪÕEãCt¢(“­ÌÃÿ ÅKJOÂ|OFõã¦8Þ¨8þÜ;ÝTäCt©Å‰“Q§if¨$µwèë=~±eùvc¸ &¨Ÿû<¨·M‘…ü­…Àí,ZíÛúO P0È(c…öáÑÐ숀¦ ÖË©•X±ŽÍ>ë²rOë ·ü.œü·lv>)µCÃkÛÎn_6«¾ › …(ïÌ]dÆTsœE¡UTbLõï"‡RÚ¸KüUå2Gx_ƒgwåúêê*<ãÁ²þ+dáÖÎ Úaé»ÓÍÈæÍ}¹’hÞpûDe#¯  öç¼c[Uj Qdy€÷Q~ÐZàÖ@µbMq¨šÚ(¢sþò³›håiµOÒ››a>^½õÊ–˜ɘW$ ”¾ÊEÂ}WNÆÁ©këÊ’3 FSÇ­aŠÇ€˜:5œÜ½HK0OG6ƒ4 X´ÒXê°Û64n^d<¨±ü_Ø‹U àYvIV„êivSΈb¸³PækZ?èâñP<Ý¥:bàòoº]vƒŸªƒ(Xºˆ¯bÑSl-ÿ¿ô2@<,‘¬cùËÛäZi²Ç®t’0†mô²CFª;çWê¿?kPî¿ú³éð$6KÙ\¡6°@Ÿ`©Û•kD¯Þ6cVE?Ž¿€³sr™ Ök<Çͯw\–3¤Q‘Ûp£ŽƒË.Ó~ŽÐx`³¶r¯y†ï/ÚÀèËìdÃ)D¤Y`¿ëd>Íç¿Àéñ 4¯jä„"±Žã׺t°.oÇï²€fîлÉ—6ÛS5ŸÌ]¸XŠgìW³˜±Uèæ~Eì® üºÊƒJ=š– ò°vY·³ô³ku Ü‹*d£lL@6€ä©Î¿¸ýÉOÛkëd_™íGKóïÎî¦õ’G¼šLLÑâ¥~qP$$Ù ÷>K/Üw¾Š£L_¤3ˆöóÍ€Y(®|GÔˆŽ"=z[ž—ý©ÙVÒcNõ4{DJ%Â2[r'a–úH/ý-u$ÿ$}èN€‡ÁD.ç°@å¸_¬ Q}]C̵BoçÿUEÕŠ™#s# Ùõší]˜\ž¨å6YηÓ[´)¼‘çh´Ž88‰W²MÔnʤy¬r†~vONcTƒGT²)ø&Ñì`‹Ö?’ûÊ’â<¦hTxy Z•8ÿ¡ú9Vx¹”ý¹,Ÿä­Q&)®Oeÿê/?!ú?b8Ú[¢ôØ)ºþ6»µÝt®2㮺sV|™ÆDf9{‡Ìº†ÍŠýMÓwTí¹°ɼ¡ÇfѹGKÄüotþÊGS …™¡2ÑêUj]!œ¶¢…û¼g†Ì- õ€‹÷ÌP!ˆ"»ÐÐL+³]½xÕV€Ú5·¶4u±À%Ý48_×÷-µE­È1)¤@GÌ4&Ð窰ۖP{ c3`)÷ë­Õ‹®´È_]ÿÅ«žÕ­²Ì5*1ÐÇ5¢Ñ1Ÿ|• VŸ EÇêý1ì§ì3(×è†Y1-$À©Šß»e¼ÛãB{SØúWà@óÍÜ®¯çµU-f ìñŸøŸ‰®(ãf’¤‚R øÊ@¼ åKêWwxèÚ(@Nb;úxft0¸Êdžð·ÇÕ ý/=>ÔðkÍ·¬¨Ûš»ê^ÐaU±z©ˆø$çþ-Ak !„îÞ‹…À§Ö%ŠôÆZé”ýT…ö“:é3«Ø_ün21åF–=zVÇ›Áz*ËzV'ÙÍHü¸#¡“h('øwÒ¥j$4øŠ"õÖpŒnֈĊ¥Bò}Û–L€rCåÍce€÷æÙ­úæ­²‹¶9l£,‰ooó«? ¾Ë‹1Ah}¼—Å'ŠÍ+õøÝ5À“Ò2en‚ù kÝÏ06ÇNyºÍ8˜–`ïâß‘R³R‚Dï9Dc×z*èÝw,·sâšglËOúwOÒq…0·I~û|ÿŠ'ÉGþ}V€w˜ÒÁ㤟DÒ‘­Î¼eØùîçP{ú)Á¶SƒÆb©/¿­Éll<`è®æi ŸÜ.™ÒÒT2Ÿ(éa L3ñTíéû›^ ug¹ÃÓŽ•f˜¯oºÄû²?G7:!vWë]ùçŒÄà`dfá-{Î.åÁŸ=Á“È 9A-ÄóÂÒ†Ý| /—ȯ¸€ÍI”y¦)zÃ×¶LŽøZMÒ‹R)2`ZA¬ÃöÂmQ3µ¯Gü$Ðqcxf4(ƒNŒ–ÙSÁ&+à'¨seivJš|p?¶¢RÏriôoÞCú‘UìÚš×…y¹ãâRwÀ4EãÐA ["<‹¬¸0V"Âþ›uÁT/j®Y¾Äâ:G>Ï£å;˜0{6èI€œ(¿˜ÍõémüNü¡M¢é@né2²1Í’"i™” ›®ÜŽKQSü‘&2©±TjÏê¤AÉn†TÒR.A*£ÃåVp=î$˜®ºÚúȽ\tNí„4ÂŲê+—Èã][Qø¼0ªw™²hȾ?~–òH\Ó‹|È,¶#„žÁ號›òwÁH!óoåPÁ‹!žªêVDœcø»)2¢]•«’—'AYØw·P7æpš‰Å¶È&òçÜ£=ê?s°‰&ÉÞºS0ntsÓ‚Á釛Jh¡/oòð“v…]®5¤¤¥#(vµc·/[‡6²|¯UzV UßÊe†Ýµ !¨h8‹Ù ÎÙýD,© ¸Ù IzÎÔðY úºOÿ¢ ¦Í'­€Ý[dT~]ïd®¬E÷hû„È|ádm Ú Æ­4èzÖ`¨îá„€¨9¬»ÓTv³mìÆ^^ååC@s¯Èké?¤EpªD#$O(±:ýš·m8÷µåZµ r$iî…fA3®¶¬›áSÆÏe§÷øF˜nç |nZÈ#ùÄ .noð6‚Ùî³p—kÓœ-¥DÖ0lÂH8~Ìߌ|¥l § mÄ[(=¸u^cwº§ÞzPÇl÷¼BCâ(ä(d‰ÃÚ°óZ»¤ÛTì)Ä ôÚå5X0Õ.ò†Û» ~Þ-ãXqéÆñN¼ïÐ_Ö%ó©¤åWX™A­ª©ÿظª³c[Å@äŽ,'ù¦ö8Õ¡/w·©´šRyÀ§Kù›jEÊu(vNÞEÕ`¼Ž¼ɆÅ"x,ÊÁÍ 8jd=õÔ³)û¹èލ2åËB4þW—ÏŠs‰Å<=Ô}°L°Z‘ƒx1µÙ‚,h†A“Mg}p ]ІñÃÞ%Eð¶MÝ¥†R«Ÿ˜{vƒ†çXŸ9a5x1€^¾yyz£×¾n–¾aEïM=ôÂ)ùmÑp¤˜ÎN¬aÝùeIþ7°q©¨œªßê#í á¯nPs´µ-Ê¢ÑõA½Yi¿×ÓÍC├i­ŽÓ×ðÙg_Hn½N–èhS+ô>AÙx¡þÚ‰¿ ß} 2ðåž³•åQ¢»7ÜIÀý+‡F7·IÐþxp[%Ø»_£'*[j!o*¥3TΓ87,<ì“ÛcBøw™GgQTµTáA³ñ 䢇ä×V2™ç“M'øVJì”÷M¬ïQöAxÊ~·[‰lúôVÌC]‰ À_ÊAUñãë}¦¤r-$†Ü“ùL1}äÑéq½¿š~3p|"HõÓ'‡¡ÛeGM£3Ñ„Ïq™USë” }ù@"çAæ®îýmÔv­Ôƒ•0ŒTRÈjÿïHçßOGq¬+~Ü:1難¨ÞAQ ‰¡4:h’߃A¯ÅÝ*‘úåY“ºc¢_ÍT*¹5¬ñèH9Ø 6àZ6»õçîª'VÇ;‹`Lk)‚PQIñŠÑûº§Ý§È`u¬ß¡ÀpQël“¤ýõ¥9S³È¦«¨Œ"¶øØ¼ªiÒ7J % †•O§q›QÀWèT–,ÿD­>Dt¾²¿÷ð×íU¿ 3„ €e ©Ø‚^Ê¿s Y+5xL !«‡ Þ"Ÿ·£ó=ryCxqÛ˜½+¬•çiÏœ1ðÀA÷&D-“ËË0Vxâ§ë„¥Þlƒ:å²&²Ý5- ªuc߈5»L5~«þ¼[®n]ƒ'“‹Œ·Y‡ŠÝôƒq™8iÙÌÞžªpND‹o 0U–¶ÌÏ:(ò‘B.’øh¹zJärI]a¦z3‰yºÖfͯEGÛ«;a â½¶3‡ ¿©á@ Kúü%4OûµÃùÞz ¯Œd‡ÒýSÚªh–Üq©Rá×Úöjè]üº *oý¨ûîå£sRÅ‹öwõhˆTccËÿIïËåZo0”B±™õLërW÷V‰Ú€”#ÌÅL¾ÆAÎ Ž [êÐFÑÃà~s‰’]4âs±†åÈ7_à^ã aCu%F3ýnªjDWðn6p3Nf&_tØØ]Êc´Ó3#.Œ$ïÂ8‡Ú B‚½(ã=cGëm©Z”ö±h›"˜Ã3Ð Eÿ$O­P«LÆP†3gjCDÊÿ@kÎQSÙ¯o‡‹Ù×tùY€}÷µÕkzúQi%÷ %u“²È&TÞ+:’Wš…ûÓ§âÄϺ6àŒ,+  À´×§‚ëo奓ý%KÙ™ó  wâ gk¯É%©Žtµ"i :uñ#ÇO.Sðtóðåg pY8¥2àÃâ¿!œÂ˜“v¨A(C`!ˆåð#÷Õ¢YÆ „ùH]¦,­©Å×ãÜ›³¾ùS8ŸH—íÃåJ"º¾kðbÝß™¿Ý‘!®V¸¤Ü•†zk}¥äš³"5Ìgl¿œý5á®ÆáÖÛ.š³¢£ê¨~šÉ÷ xœ¹äÉÊ_X¾ã£1:¨[7ø8ñŠtù¿zmTßõ“ÏMñÓú [Iî$ÅA9ߌ¸,)‹ìÇ$¢\ÂOö×aÅJôòuæ·A¼®R ’¾fpó’;O–Kôü"Îôw¬lŽØsÛ§¨‚9ÃU‰1˜<Ç`¨Â¤?e¥Piᔪ‹{ª²SÁ:Z¬c#D»õ¥Í>=«é`ªCZhRù[æ­‚îUšøl¼©îÕÚGÁªñS;V÷3€É&0F(„ñ\÷ ¢?૱ïwŸÑñô°[þÇøÒeèØïsæÛÓŸû% “îûåvð„÷9ÿzˆ”ždã ýQ;“D(‰\=éZhà^˜93õŸÌÍs¹›íç]£ê,iÏšøUöx¶o"â¬?Q! ’ÜqGÁ u+×ô‹KØ¡Qð[‚Ô”¦ó«O9øo–ãUÅX7.:H×¾=Ù†!Ã@Êí5ÚÍOEún*ω¾á’a?iÇŸS»£'éx#­_ìÚÊžH´Í˜vH.Œþå#”4Äëpý±ðó+s˜ š-¶V¼|r“àsÝw奯ˆ3Ò`Õ¸þ!KümÙ,ðõ×}ßÑmÝ íT`Ÿb¯Ÿè„‡Jþ©Š[‚Wf=LJcS À9© Ììè_ø ßô÷Șaúb…ô·ÇpXüÉbË Ûü± ‚½áh3H²POn‡ ×îå“KJ³ní½ ›Âá#¤µ ôÕå¦!‡vµßÀK"b•ð åq“—wYØÙ÷4S¼ 'X™ÙúLø ­Pm‹® $5|ˆñûÓ`(²–8®nñ;>©Û3ÐÖæªÙÆ]68ýåG¥RH^Ø©¡¬ùJ<²\ç`$6­y·uv£ñ,.Óý$•Á×Ì’Å”ÞÑ-…Pú·±Œƒ§UjêÏ\ž¦­“›w5n JY\M¾€‰d×Z{´ ìƒ7ó7ÔOöæDæ#ÎX‹y@àQT˜jÃ~~)“ì!qp×½ =ÌM@7•$¨eR@øª1¸ãĤ_I—TÔ{¤kØaN›ÀLª+nÂa‰élÜÝšVç’Äãž/N&¸Ónùºh‰®.X¨ø…m6[¯?´²$LǵI.þz'‰å˜c?ñ\¯ÎÚ{beò+ŠßïÒUX•þ¤°§™pºg’—ùFrD¥ñ-¡Dô0ìÊU3¢ q÷Úk…^ f|Oý๛‡Yç›êÄçiU¦{}×»Dâ#@ã—€ ¹†ÁGf<=²êÒ±{†£R<î½ì5VŠ*4”KÇ;ÐúÃd"cëfŸŸ¹~ÞÄÛn —ÐT¥flÿu •\B§–&«²Ë:g)½…N••.üoóÝTϲç8dq”©çT‚¿LÞЈ¥b™x½Uu1MlÌ?µ:$z¸§Ìíóv¨µ&AœÔ›ÎÜyzSò%gx"ÆÂ™tù…ý’5^T{óVoËâ²¼Γ¡ƒÕÝi(¤#b¿¨}¶/{O#”"JâÒ±]ŒÃI‰E2Igø$C¶Šjo±à{Àð®*¨¡<8ä×9˜RWŸN©û–ÂlaÙ&_!]W;¿ñiq¼­æ ÉÍ«˜¹Â«蘩“ד%°ô2ŠIU$h&kT4^܉ AW˜xæTS924±<ð¶_ÑËÆŠ´§q5<'eiF›]g-¯H™SçÍÄ^¹=¬º‰^¸ÍpÃÄú] ^ä5¡û8E3!‚ëôÀ&oC$æÄN €!UHþ›î>ª¤¤,NšSËbñ‚1°eËLj6JVþ¨þ}ïÖÖuìLV2$íªè]@Ñ=4Èœjºe¿Æq0 ƉY7¯A»¹9¸þyµ#¼!´£âF6Ž-ƒ“ÓøT¥òüš}UõÌ„Lb629jØë.2QÁS­A˜ˆ»”0›n~kÓ‹#;ˆ ‰!ÖzÞ¿òm j,̹sŒMÃíÖ[@°.„¢R;¿>3QÍfMÚd¦¬ìž¸ÔGÝê֪ؕ•¥†e‚&ûdvïpçï¼ÙÍËѧìeúªhº9Ÿ÷¥ ‹‘¶ïWÎŽN”£šEÌÐm#Ì`ôõ,¯(ÑqãfýyÀ7³ 6m}±Å^³ÔÀƒD³£n»Åå´#ŠÒ5ützœªÕ!Ž6´§ÀM¯º›¥ÚÔôx˜BÐGz}}ê,š;qCj^Z+M ûêD°_ïÞ< ô2žX}ãœÉ~ƒÛVcL›v¨T/YÇ!¤âœ!JϲâÈR¢rÌɵçFY#S䯞ڬ8ŽF˜òHI›>Èä3Ü+åŽc.…l5‰Löz¿õÒ¾éA£, SRßfp0T£’;Ö)¨Å…Ø­ÛxÇ;kn Mã¿Ëƒ  Õ"Ï–ŠÊÚ‡´÷Ä«¯(D½ñbr©ÒаȲÙe¹*bLþÇRÙ«Gûà`êüa`´cª²e%Ú ëwI‰ÁW—Róú4Eç|ZFÜq3éå°>R¬/èŒ*Ëb* r‡ ߬eðâž]Ç3Ù¬˜s·±{C›e§»«¡É©¼8»}f*iO)ù¯ |lµG1*•4p’ +íÛÞ[î.Çã¢ýiRŸY„ì'cëz1E_IWìzßa¹ÔòSkàh\÷"й² .lˆ—ºò))ó€DÙ&Q.ZÔ>î,‚¬c¤íšJ¹5ˆ»às¥NurÎô®n•û\u׸í¦TÖ»\¹4{M§”‚õ‡€eA¸Ewe@!mx‰Œ”cbäˆc}=l¡Gäß„¥.ñWïËŠDÄ×NÒÏ$T¤øi’§*%`Ø@Êyaã(Óž2òñÝÅòE4½JRL¤µÔ(®ÿr êÉÓY*U¡D(H·¨3¤}íˆQfѶÃäà‡j DÁ+ÝDïýžOKù""ßÄùÈŠ(ãsl»S±KÀÉŠrP­#½íŠ[Û(Æ(] AŽÇöð4ó}LLϹîv›ÓkZê»áÊ|Nˆ¨»•C’•Ð-j­íCÏÒv” þ†±Œ$5ïˆY¿9ºÎßÈíÁN£íì\Îe?‚ŸŠ—S¢K +CP›^¿û ý¡aª†9ƒ»ÜQEw¥g~ 6ü3T^M ‹é¥9œÖ**ÅŠ&ô{ï&¼Âè£ôèˆË«w†Ãþ±Öž&¸¨“¢qŒqXö]S@¬©ó2 HÝp ظÕûËÕɽªJ-ÞëW$¹îì¬rx:óu’#ˆw¤ê÷ÞØør7cƾê™2Ö{‹ ì¤¯û3è3ý“’ó×±ô¾ˆøUšÔ0=›émª—Š«z]FÊ ,‚LIàn²é4¬€ø˜Ú[SQÝž)¢Vèlq1jx(¶OÏúǾ7IšÎòî`œöîcù+Ï™PÌò7‡ÛªÃ§Aq·7u E  õÞQ¥d¸=~e$;Ó38[ÕƒW â"}Hb=Å‚ØÒˆ2£WðŶw" ’¤CR«¹$Ì>r?ÝV;å­½EK)âlî ëcÄ(FlÇCÒÍ«ï"P£3òÂ%I5$_–ÓÛ´p§%Å~‰'ºð;µå_1J­Ë·W¡­ÖàX@œíÈŠHÔ°ØÀBŸ`X}Ÿíæ}Ö¨6ñ?¨"bïyudæª5Ý*O”üÇ85X²ãœTû„Ë,l­\ÍË ¡^êéÒ¤V .ÏúÌxüEÒô. /Ô¨•üÄ9í)ôžÍú󟜶µZ&7ôOŒXª².œ@ì2·L*Ã=%Á[’4.\Íà¢\x4p\ ¶“þ—O.Hö|AO¹ÄÉóWx,c5{›â:õµèA§/«+–Ñ8füFB3¯“@Ç<ñbüø?ŸÅ (2øAlp±ö.ñÚ˜½’ÎåüFLùƒUƒaèù-WXoÇÕò–ÿ™Y,@Ž6ÍトýY@ÏGð Þ ÄP~º$ÜèìÓÿšô;ëcÙ<·w½ÈÃÅ­ÖŸnóÌWºAÍ#¸=¡sÙ€ØÌ I+Ó!ˆ]¥©Ø‡›ƒ”Ö¸@ϰ‡(W›íË?”± }6úØe±³„¬Ü¨-Ž/5ϘŠññþ™XWHÁYÃ|>OÒ¯=ŒÜójRÛ7 ô‡®àˆçÍ{<_“–%Š»:Vø=`Ñ[ß:™îö7.5Á2limkͦü ±/˜½1ÝyƒZã—ñ„.¢ ˜L{Sû¿.îÊC B}``ò-¢¶w‡%uÛekpz[Íå %ß SûQʧ¶¬¦ãÖù­ ¾ ÌD`Â@õ@YO×N¨‰¢pÖ•œ2_"iØ„SPJ+ù±(úyù-ÌR¹ô¸á3gòiÚ½æè‡|ؾð´x/³FëYp„CEA•¦6öci+WÆ,×›‹î|ÌV·nVFÇ_ðCt´v˜4áº({ŠÜ0ø*Ì­ÆA{¾±˜Ÿc†FjÚöÑžÜðœÓn׃ò嘷U‹gD¯ DºóOg`}ÑÛY¾BÔ•“*®iaÖ 3Žm@AÇôAÓœ@À@9L ØÜ\cõ~ ^] 8KuLŒÑ¨ˆ¬k€Öœ¶~Âo—eð:V*¶¯TjÍù£{yn$ªafr‡»=²g/(fªö‰ÍãüM`<{C4œ±ºvjö²svÞ] ÿªžÍAÓšˆ6?<ŽÕ)¿/4àM\M7t+û×®P×ñ›S÷=[k‹`´§ë ã a²¬Íãù6›àsÜ[Eö!á"ÇŒŽ˜x‰='õn~8àô²›îq¿ê‘X³Ë©ô~ƒ«/œ$oQCUN›<ÎÆB¬`~ÿ†6[}Ùž~µ…ú¨éî£ùM:"Ÿd¦'ö¤² >å/)†:¿e› èuªZë·zwgQÝP„WgÍxåäl[¹Bl%Æ3’®2B”A—0Ïó…PË‹ï>ƒcîþ ý$"9f¯T­™fäeee ˙Ȫí‹d®g£Â Ùx Tõ eòA ŠYàDÎ_îDê¿]®Ò3 6æº é@K…¦àÎÏ™[§W¥Òõ¯·AKAÒdpÇøAô(E^ùà@àŸ¶0U$”­£ƒ0HóG{jÝÉçÁü4+aþ'.dø;˜ ! |Å$àƒÌœyÄÕ™+è°Ê DÈÀ9tu¢û˜î½øQBK`c|¼­ Ïû³g’ú:3÷¾µéýLÆRGŸáÀó´ü±]ŸÔ98@©´ä3Å')ÏK'¯÷Š‚ÈoÖ®q²?ØYG÷]Ôò>'·ÐÆÅ. ˆjÚtŽ·Ü…C6LÒþÖÃÌR[–rÜ•g@Š¢já)QÑÝq[ÛœæÕÏìUwËC¨œibZй¶¿`vÖ)ŒÖñ;r ²Ë •ϱPC?ÛXë% o‹’þ@L¿Së*EÃWÑš-°ëÿÓÝÎlä=ýó`V*Ú)t,Ý5•Û{ú4Ô]Y&‹šÁ†‰ôͧ£F÷;뢥¤Opë.ëbºýÏún4Lo’Ì6‘ä©æî¥¶RÃÄ£L^6[A¶‘ RMˆê õ«\-§>Ú$GZ±3œP@TPÎ^33ÒßC“ Eº®éš¡NSæWÔÀxûù,ÇÞ{;cÎ …GW·M½dhÿš˜êÙ§&/!¾–$y—[>ƒùÒåKâ+*“v虯ÊOAEÌiûæ¾b€†@;îª0ϯZ’£×áY¨œZÚÌwtz+iš¼˜-n¸ªÕ,µ×ÿÝì—NÊ °Ÿ¼!!>ù¾]]„–XÁt¥žÔEkj:›Ÿ±LIùé>ŠgO6K$|\@£¿ oȃ9¨ª—¨„S'N;ÿó± œ¥ÅcƒH/Ã>o|½2Ï Ñ-zµ•†]…ö-Ï€ û*úYˆ6#~¤_NJi{‡¡€6)SðÈcÛ¢¿Ñ÷>W·°ÓIáµüWŸÛøîÞV^L¾þïò  0#X›ŽMÖÔÌjÉOrß6~#pXqz°>ÜÛ³†õ'¤÷!#€d\¥ßïÍ,´œC¸í ™€Ž6!¹®£Ä…$x`„gÁ<³*tpcg®f[1]—¬W{î ¢:ýQÚ™Y~ÊcÜÃX‹Ò=fÀt!!4¾j„ªÜ‰küì‘í^ R’Ž È%òñuž!œù*•€šÀ»ã%`OY¡›¹V-@Ò)}öa5އŒû=KÛzc`DÒÆ\ ?ÑÈ¿:ħfø€‚65p-'Èã*$)Œ¥wô£ZÉ,Õy‰TR YË5™ÐÀ-:Tx¾'ïy”F ô Vq8èöHòR •X‡x󛳜U.€$ôSÈAÛÈîvãŒÂË8_Å“üJÄ-¿ÅÚ]Lè‹/äùž¨UH³÷°šðå&ºêuRŠïH&ÇΉöŠ:Q×DYDJjh„°yÃ97Í©‚¿bƒ;A^t†UAxÌo懤ؘ%˜î8òíòÁÔ}X?Ös;äp)yŽÏ„&?ZîIÍTg‡T)ž=,Y‡Á*ðvuå†ÀÅ#ŒN®‰VdS ð§–ŸãÁ΋Ëý…—éß“6„§WÓHAZ¡dzWu”ß퉅ùˆÄ–Ú1Ñ¢-úÅ"¡µ2ÑIfºØ-ðuà”R¯£Ï¥‡+üR Ù½½‡ØKýzdçÈmKëYvPôÀ ÄÿI,§!êhÓhå2Åו9SÓšŽ_q ønê+~B·ü»‡<Úè¯È’ÔOf¥«Í?X¯Mà¯q)DŸ»?-lH_aÃ'ÔÛxÙkcl‡" °/qK²Ú]ý¤"nLtO¿'A?SÆì!òK*_RzHššè0GàÖwƒNŒê‰·ï~¡`;÷ÁÇ샬ÊöæìC)#Œ›­8ÏÀî§_‹ :r2Ôhˆ&5C¼Ã0*ñDøZŠœÜ …>\¹)´âº ²f» @Ë–N÷ÇïvJÀ¸Rx‡+u kžŠÄ.Úê&6î41ïŽG« ]QêŸhûý,8ú b«¶‡ETe‚HgüÄòŽ.€>š×w»°ÑNéhýܺÎëÌ.ô?Ðl9\‘!iÿþ®` âIÍgB8[RÇzÑs6pa®`>VÇ«úì3ë¶ b=×=Çrÿ´:ÄÜÛÆë¹ÞÍTÈg²i}õ lƒKèˆN?·â9,Ò ß@o¢öa±StRevÀÿN*”ò‘E¶¯¶``üLø¾Z$Ü´Ë‚¶ ¸Nr3ú5Ùe ö„ñ€Ûgg Œ²eøiÞc˜ÇÑ‘ûøîŸ²øiä×·h¡¯ùʾ:‹g ëŒeâ…µ+Ó‹]9–µNnþ›%(Ia V_~G¡‚HVò; Tm+ªH 3$ {é¿R/†ÙJ«œòò{Žq€¯Tz6þ:6ž—ÃTíê9o{æQ4zòiÔQçóL¾Š÷¨hMl“Õ³2»ÞUœýOO)IÅÁ·°“Êq­€8æ³Hà?ÙÍGŸûé÷7´†}C ßþ ôólàžutg®&…êÐ íNûpñ÷Îú**¸Âø'2ó¿sÖ ¿o->¢þL¼®ψÐßùÚ}yÀ÷èFDÿù±®~âÎl!­}]D0ÍÃ1Òo û2YÓ*ž½‘¾ê+à¿ñŽ5.—øÇ'Þ0”€¦!Uþ’wÛþŸNöjîrFÛ‹™ÄC¯„:$±¥œ.Êáš\L"\($eÿ×:)Áp¶b!4&DjDßЂØËeÒ:þ1¨ŸòAÓp é‚ÛNyJátVjªUòžÑ0Ô»Uð‰\Ѷ»“MLt׾ū¾•† »|ÈiÜ·ø©GH{ëµsŽ vE+M(°¿æï8àÍ$7ŒPþÿÄÆ¤·’ØLÌ{™±tÛÿuÎ`ÿ/„,5ˆsúNá‚qÕ,ö.;å ñ§ÏcôQå!:y¿#‰I³ì‡8.%~òóÊtàº8Û–(Søÿ"Ð¥òÒÜ!_û“`Pª]z¨Ú ˆË'ÿØqts^Èä$xšéÊ[×ödø²Eæ~%JØÈ$PuÿÒ±±QŒOO'éë­ó ?f}Ϲy lëá\ôýÄZ$§ã¦86,«¦­¢N·m‹¯/9DaíMÞ¦Çó¸’(Ö¨[ÀÒ_PO8:\¼¿R+®M¶ ‡ÎR€E…H9)æã³¿JôI£Í݃-GϨ`¼ ×M ¥,¹çýzò٥⛅q‰À`At$j=+ÍpðÒV ÌD‰3Îû’ 3àµEì"æÎ†}-?_Cì3ú$SÂØ…ËÃáGÏÐ2F1H7xµ:¾Ä‚vE£B,Ãø}iêݹ•¿ó"¨’Öš†“@d[Q“ku(®TÞØM94ãÑn…F¼ÿfÆ^ƒc°áf>à0m%òJweþ}ׯ—&¡0zÄ=þÞ$pñ-Y ‘ÄÆªäJcµ±·p£Èópb¡Þxf•Ô°Aõg‹i Ì‹if­Å¾XÒSÄ{‹óN4ìuB£i[$×DO¨x;fÅ`—wšåH˜²Ó0¶·E¡;ü^훽¨óDnðpÓ›Kh¶U=ñ`S}zÄ°Ž¿Ø"òæOË‘Ô1 ?‹ïüXôVL ÖÚO® ¯7¸J ®Q¡f²¬Å»•ü¨¢Î 1X3HÓð™ñcL÷ÁÚD²Ó1RßŃ}¥ þ¹aïSeöõÝñ’•¾ç6Ä‚ ñOµ©¾{A,_Ùd¶ñ‹‹ºÕêú‘c86¼‹¼tLXæ{³!óƒÕ9Õª1ánðSqnŸ| ²C0 Œ‹W­>¹j ûÖ‚])â\C®}^çùúM…»sf)ü.ÅÃóýM<Èћڡ5H쉂⮋k0 X„5ô¸¸ØÀqÑ9TåÉ„ÉÏmتÞZV/ ½SOûY žØÔÜð~œBÃëÅ w¥q¼i¶.É+ƒíx…¼X¸¬`¿-ðÉãÓV86jcçˆ:>è~'ž‰‰…ìëAœ¤¨ÌzÿçŽVå™Èc:¬(B>ýçlgIžKôÜéœeAhœ†gCHà]‘‹#%Q°@þÎ'‡÷Ù­0 p†ž|bØïñÔûä¦Ëgkx•â²Òªªà2¡²WêC£K#e¾Å(ÚͺÏEeãi”äÅ–™[‘Ã] ˜_óbÆÆ+þ?ÂA…iþOMß³BÀ‡}ñ6ÚvËD×LË3-’jÉn«à,/p¹†“E—‡dXèÂjˆO¿Of«žõlÚ}J»Î‰(ƒ†jAÁ-:·×P×ô½¥6rLq÷•2b¿“LŸf±Òý¤þYƒ¯ ,D¾×œdFÙœBDôLBïGâdyŒhevºV`ÝÁÃóÂn+XQÏ[, Ñ4I \[JÔ¿O†2ÝÃ'¹â“!(ÞtXÔ–ÆÖûød¿†è³럻+µf}Ò³¯‡è‚wÏ|‰_Ödæûø‘oÏ™×ì4ŸÜCÍË‘R¼×O°ô´[FÅüæD%»¦™žÓ¹¼„=Úg¼ªšÊ-¨ù£‚ÑÜ’f¸µ-T¥]Xã-«£*&×sÒ9ýÁ‹¦B0Q³#(áeDŠÜcéëĸˆ÷ОGkÌðclJ¤Úø 8”ÒGñŸ{`Ö³À“™éÝÊ( öÄñv(S“â^Ðs›cñnÍMùÃÓ÷ôVN‚sH â¢£,ÅßÑ"ÂõÓåòÀüÏ%» ý^¯×Í¿>:É”Ýñ«!Q›âÕ¶ôD|Í—ü÷Y~†õê¶àfïÓnhsBOÐÐø.‘p²» hrvŠ¡õÞïa 2° ð8ÿ†ÍÈ"G*í— CÚ–yÙ Öš ¨²Ð'¡CC„Hî)8ñf6‚_||Yé»ãw>«ñKÁÅݼ }zAšË÷&‰ï©§9ÑýQbÝM”Œ“™ìÓP$ürw:Ûë©b¬úÎ2€­M”1š_‹eAùøX³iΙ))¼`Ä`DD‰Ô¬y÷Ë S’nà B*el§§Ô!/?ß>ð q5tø[€ø>–:js,ø¼úO‚üü$AWoÐpÿ žVެ˜‰"Sn4ÂhÂLËù+:¤º 1sö]”5nEÏ4XQX Ý¿Jµ F„)Væ  FAßN—ó1¶u¬Ií•ZA>mz ˆµb.7b/Ê©H3 ÛÙ2’}Ó¹8´eÕ.©zó@]oÂzS=£ØÅî—Ûn‚ÇòÍK–žPµ3„”¾Á²¤ægµšÉ-²¾ vX?”ÂxÄÆµØï–ö͸I|†á822NC2I?RÁó‹vÜ,‚×n?Æý’ ó-œNA9 \{H‡ÑfÅ{¦â"˜Ð¢xv׉¦jjV?¤—![$¯ûvm£hðϨ7oÔ·Œàmø ýKRwJäyh¹§×Ý 8¶¿ª?Hy$XÀŸæ½*² ªc¹ªDû›H%îHNi™éRKéôê»Tä¾ÜCïÎÃð„eÒB%p„«¤3/àðg¸$½T¡`Ý'80^(ì—¶íéÏÁÐ DÖá;9µþ°Ç.Ï)9¶¯®ñE$‡@4Žø5¶¨U“àÔähõˆïÄÀ ,…9ºê‚Ç)ίO¹?·É(x_Lw­UPÌqž@k„ëh›9 Ë{çn”jnø6,LßoHïtofutâIðÏ"vŸ€®‰—¡. pášè¾‰8 $I‚8iÚuî&©ÚEG»E•l+ vš«ï=}¼7ßÒû<ç¸oÔ9nK#` ñÞèÑùeùª§Å2Úrâïå_ŒH+mð@£óö °wŒñSlFcîn¤6ìño¬bC;ÀF}ÆÅìûŠ”BÝ‚²-MC*ص"éø¢ÄÑþøðU½@KÄвÂäQž¹CãÌ—.΂»+¢I Á¤ý0å&BÆâõYµŸ«Æ>Ö{퇊öÀšÂ…Tªµˆ¢ZõîãîZ×U<Åé‘iéÀ,Iä-üæîpÁý‰žîCIâhE¬VZ‚Vôt㽨PƒÍ"Ä(öïI»`öðr£â€*ºÆ7¬è‘'œþûj]Ø ¹5§=-Œ´Ú‡Ýw‡Ó"ÕÕSÉ—Ú[ó…œã“Žc³úˆMM(®íºãq¸àŒehíËíhÒî)¯ßžž ¹fe¤jsº~¹#8RǸ²?h0êWgGEàF®Bšâ…îpΟŒ¡š"Ô6~°°ÇÙüŸÀMG¶ºÊ¼ü°¾XMjŠ"éœ}ôB)­ÓõëàT›X‰<"¾Ö)kùTßj<ÑΚ¶š\rìg ÅwBÔÏ»hÙç>)T ÚkH‚_É’`;ùÕ¼ULQZñÖŽ\náT©¢7ŠÄË…»Òµs½dš´e&^•%R†V·KÊΆs»óªm‘7ÄgÛ»|Å‹æÜÇ6ÔîkªŸy_Sù ë#ÛeuG9 ˬÙŒP@æý¹f”ìôÜIV ^d÷IÉøó]™ïôÃN•í…òy—e%%¿³u)vö––Í%fdeدÍ:ç±Rº§»ûm§Þ€kVyº»êRqÝ-QoËn#8vóo«E™¶ÛˆŸaJÐÝÐÂìS¥¶=l ŠÑ'ÏYát–¹F7Ô<ÑñCÜìfcU¬†Ð-’ßa.$6–ìºRHÛ?ÓÜ×-_ÝùÀÃmßðJ|ê||sع4X¥xêÍbâÀc_ùû%@B ‘‚I~-âf}f0ý‚8ë¯"l`âMI~µin1YØ9!µ<$¯h‰ëÉ>ËQ%ߢùáE'˜Ÿ.ñÆOaMÚd‰Ð‹¶ó3ÆñôL«Öø‚Èø‡PyF矬‹mÄPÒh‚äw1Ùˆ2ïjhÄÝ]56?EQL¯×T´fAÄú7¡WM㙘¬ÐKzƒs/(Z§k?jo.Üë(bÿ™öŠq›<~ÈuØüýäBÆ,ýÅNÄp`Bc-Áé¶¿èZlqÅ}ì6Õpå5pF °–°PŽE#¥ ?DÞTA@fGÚ¸æãêTö la ›m|¥â ¯³áp÷0ûìîñ©.Áüh»{ÁŠvê@óˆV3bƒèC_JîD¬¿³Üð ¥T&*­©Ù¡Ÿ?[‚'‘ÞZÞV‹k¹^£òîÚ•3Dð1Þ§‹íh›†Zlh óœÎði ½ª­6)(â•v2"…ª?|Ö«&“ŒûªÐ]ðmä7ä›zz…I½Å@.1†Êí¸UjêIðô€lP©A[wÕ Œ›†æwPQÖk›žùš¡¿è–l,=fÚå$¸@¿;’£rÃ^…k÷Ñ^“IèÒRiÔ¿s⿸Qd5t³%ä¤éÅö«êlqˆy¡—n™Mrbnu@ÊŽÁC1¯Ý мýç©&‚Ó;,–žJ÷çE½¶y ž‚pe/_—ÙćQ¾¯¨Ç˜´ÀÁÖŸ‚áx­èÎOi{¹ä mU¯Ín#±z­²…¸á¬cCÇT5‹äü„x ×x9Óß¼Û ž ÚPgdûª‚tú¥ÇòšÎª»8­KmÔrÎÒÜZQ¦Íûuð¹WæÙÕaŠ:³k‘—JVVOWj÷>IîËn䌼°¢L(Fúƒý!*W0¸z,âeê|Ëç­(·åžÊÃYógN²¸Éy¡~ä°˜ G΋Dmøf©kèëdXåvæyüTÛb4qÉýÂâõ¿÷¬Ã|#õO]“^ÃË7‡²ýP S²œ @@àåÌóXέ É,w*œñO÷X_ %+öñåèYÂy\Ä<÷‰P²!ø¶:_칚ް™µúâÒз/Z‚i— («^F÷ÔÐoh®ÿjC83qIåò6o‰Ø0ímŸ§3+|E$>Ù¶@ø2Ì5%?ŠDôªÅ0Î4\ŠY³d˜±£›Ù¼EÏM¢5”I,\t À@E›šAÚ(s-á‰ËÁþ’ayw!1¹*×@±JíÔ u€nÚ¾2ǧÙgñ×2+Ò ³¶¢Cç:Ý‹g {ÞÒEôÓÒîCOm”þ8?œÉ¿z×bz5EúX6háWy,.ìte5Ä‘Å!-‰œýÛà)ìWï6X|ÙBæ”ååó8_ŸöcЉÙ×k’×â$*¾ óO‡Goí Ö鯒qñAlMXÏ…Â.:LJ#xö7:4¢ßn™In¦êMÛ=fy—¹ËRˆãBÏåȆ“K:Ϋ¬ét5<$ußÁ#âz ïav|óÂEôyÖ›TÕeà§=s­Ú±€€xgàèIt‰­û°á±U±Cp‡®Ê©ð‰WFW¶yt_õ¸cùyˆF[.Öóû)¶æSN§Þ:%ª&Ò½w&IVIÀÃÒ~]QЏ¨,ÇšÏ6Š.XÌ) Tœ¦ê(û䵉T‹‘Ô«V_ 8ì¼ÿ‰5D̲3|S8A_XEÊçxBãOr˨˜`‘üÝ̵7&ž±Ë×ôý Š+™i(¼½ƒ’†ý¾ IyÊ‹¾W44IóWDëªüª)úÙþ˜”!)®A• Û¿í zpŒÊŸ¬ÛzX™ÓB5>ßÑÛÄ$gã–<èó—±p¦¦ÏÊô€òbR¢[á}äQn†0©?½îßšeY^Ôò5ô•óò*^lý…Ô謸I{¤¼¸©^er•¥/ÖÖ ÉÏø°í òYþœø¶yØF1z¸×¶…øL((Ì&æÂuëhù¼î˜A=TÎáñçæ§Ë=âé Dt,à§‘W HBpŒHǦ+ÓyZ“Ÿ'“ƒ>õ[¥÷ ë%7¦I´›¨‚ÈžÒ‰=@}W ,ìO‚pÓPi (ÜJy™µ–ŽÕˆ H1ÒK{™ðšœ \ÖZs;û[vÑZ‚Ù¥ò«tÆîâ™1ÛXn¬®rÃÿ.‚™M,’÷AT¤[þÅub‡F‡÷ †·Jh€æ¸=ìæÐj__«»U–N¥0JÞ`îÇ©ÏëB<+ñwVáë¡,æqPkÕTÂÕ’Î&k(C!®`Ñ3ôž #sŒŒãùòäÕ'¼˜ǨÔ•üu>>i>Q»§‡k†Óùî«Çh˜4Š÷Š›?Ýû§$RPØžlº §É[‹Èç~xj÷Q)$èî±%,Rzð³….aàÙ¿ÁŸ4ØQ ?°™D1†=‡XXw ã”úЂWöÎUHV1Ð×í܈uÒ%>s;°!€Ý3É•zY“W§óôúÐ}:í¥HTïÀu–¤o7,ºaÿl‰c–]%W Gl d÷ÓIœöã¾ žG¤ðÓ£tI<Ÿ" g†æT‡ûøžÞ¬™ÌLëÖî£*ñ7>MÓIcŒf¢aIÏÒ#Ø1ôJýÃÕ~LgÿÞîÍÚù&¿5€¬h®¢ÔÐÉ™£c­P;Ÿ+á–úÔá²xõÖ).ûS7« gŸÁÔÇ3|xpËвOš-AHÎŽBhVØ÷ÿ©ŠB‘ã2èÚ8T¿´¾f®‚š}ܦñ2y'¬Q’ÁnÌ „‰Õ¥Ý쎿¶´[ÿéoæ…´ô¨ÃýÚvÝц­yHò»®Ì€Ü/Pú) |¢á ë4ññaû d†o†á-Ý0üY5O*çÙ4i½,8yÝÍNEŠH¢~ eF<ãঠí;<¼gÈüôþzžÛå.ï×% Øþ Wã–ˆá‡Ü©VÎL½ó·Ž]¦‚RÕ—GejgžFõÉÝq>«åg ëé·d{ÚÄ×üUÿ%¿‘]›1[F¶¡Ù‚ÏkR.lCÌÉ¢ ˜{Üwg¼Ücgüðdó-äíÔdUy‰ ¦ïm*äœoLmˆÍá¥`DÆæ%è¡›çÞ÷]Õ.‘œ»Á ïôSaVšï`S¥q°ã£(˜Þõ_:"ߦ˜‡Åô’z‚+†ìÑR&yH"€”ç:g@Ûe×8-ï¦cÚº:ôÆûy'©ö‹É! O]ßó%ŠVõøç|³W ²?ã5aÖ‡˜ˆ\({º[ƒ×úBB}˜*(xKúø÷‡ÕA4ΓúkœQXúüÖ#‰#±oBOÖÙ*Ÿî ÓkJŠìL®% N­¬a.] ø é¸+uEŠå(96B”Ñ¢h•ûÇY¡R_«—î‚*¹æÍ!vÒäã““2]² ËÉìnâœU_¤Ÿ>ØÄ½·ÕŠ|¯­ÓUŽ›‚þ–¦}ØMeñ¾ÊÖÁEE@I¨åÉo¢ÜÑ*ü{¯H‘ØÊ öåß$oÂ}Õð pKý ò£R§¢ïbÔÅè¸<™›ÖøwÅÄ'ÁÓ~èXÄxbAéÜŠáà6]ù"çÓ,Ênëýo¹F8}*s6ú¯ZVkZêÕ^h(8úÒß?„áó[(šéGW÷fÓœædÎÀï>Þ<•¾Ë_6ê\\‹‹)Žåp&ÆuΩ‡”\#¿…ñ~š)ÇTïçåböu˜·¨þßÖ—Aˆ*WZæ¼ùs!È““IÓ' R•zúÇïÏ\F¡4EWÁò–P~„£Àe"hµj“b´ä³ú1×ÕyÃy‰Î/S'ùPwñRB®Ü-:]/Úz\˜ÒqÙo0MÍþŠðV£ƒ¨äÿó|_îŠJ`œzx¢Q igÇzCà›q®'µÏ€`% _:ªÌ¸Eø[öo{߉yðk·S y(ÿÞ4È•V§+±¥0@ ]äÞGv£0Õ»4~ ÍŒö_Ob1¥¥m㿯ydúœÎ"žé_¤=çú_ ·º†ŸÓ¨ˆ´÷ÆO=Ñe®¢=k;.«õ¹§’˜C…ÁbgÌ•ÛL)t#}“ƒFõARþ9 kŸRzJc°UÞsQ`ûwÄuîäx½ª žüàVšÄç‡ü]OcãH&,Pö®à¿áêb”ÂÓ==/úUTêIiÝŽzƨ÷Ÿ±µ¥ÕÍ…$æÓQ½VéÇSï­üŒ¸¯Uj? Æ%`\¯º?|¶Õˉië$ù-ð2µ6&AÍÒ7˜ß0ß;­Q:7‚®€+æ… ¢ÚW€ã üyr¬m&2bØ~8å×—ä?Ç­ëM² tä4ÒýXœ¿ÓŽ}$™¨¡ºF/C=Ì9W*Ë ,Ñ4iõ³@@þ’»AòÇ¡À¤íŒ»ÁÔè2Vò©c3âì@ü=ßü®ö5vÛ—”þ(:séí]aÓšè6XØ\þu)&ÅNïSXéÐ+mê,¥—ÜW=2öI-Cò@,b2רb Ыæ•j9 CòçÒYsRîv1Þ@Ÿ^¾še¢Õdr꬈[L=ù3ËçÀÌ]wÆ;dgâ—˜üñ'~ºoEcï:ðç[$=|³J)Š™kñG±{z¤f¿{kßíо$Ê«æG¼>²yڗ蹡àφ9dHñÄV$œäD(p FŠ“î¡Õ™ŠS…Ä¥»•!S@³b‡f‡¹{Á<÷û×Û,^ˆå[„žé5.þ"ÿuɺêX­1?æ]‚´²¢‚oá:‘ïy¶Òò8Ðò[ºª>c¸u úÇ’tÞ”Ö³.r’µ÷>Î91Zµ _>´94Ük¬c+îì$»ÃÀ ÿ?8¥Ï°Éá æÀ‰Ìœ@—Ŧ1jº•ÁÞ0«Ÿá>y80öÚâ”68qß°CÃ^–i2ÁfH.º­}‡2³~HD"2"îßÝuÊ`Þ ¸(™;–fj˜ëô÷â|há‰"OrKþúÂhr ĺ#ÁÙ“=¹ª–÷Ñ#,ÁW U½£2•ÜÏ”·æß÷óVF¤l(i8›%´µ”‹ÛB¿ð°6;…¦X6Î'Ÿ_M*§®™åc"Ñ%XýÜ%úzÛ˼PËï¾OƒcQ¤*d€¶T×Ò9D&'Õ¢Šº…ò Ø×KÁ…)Re,$jž*¸™Ú E[G©4BÕ@v•†³à1ëÕÕp‘7æÙ6¿Ä©ë;ë}†ÀÝÔT> endstream endobj 12 0 obj 43648 endobj 13 0 obj << /Length 14 0 R /Filter /FlateDecode >> stream `šþxÝ€¬A§±ÖÂvþ0fëÚ$>ó–9l§<ê…³ûÁ¿»¼‚Èáúü\¢@ï”Aî\>)÷«™‹ˆ¿t?IJm0`s2ÛEöt¼vv!:TÛ¬]VÄ[%â¬Ù™M&ØUû½üá›L…ä[¿-û{°«`zʨTý˹šÞ~·FýÀœ{l¦¯îÉd¯‰÷ K¸ºÀ¨ÌÒÇ&ö¼ZØhÛÁm_Ñ8¿»Õמåx¸«Îª¨‡—­•‰^§ïO©1îTãp#Éf€Õ¾Ìõ¿-!O†¦oKŒ¤Äed½ø¤§.#ÍÆÿ„¢‹\Ðú(ä‹“|,>›—ÎÅo¹³ãÂ!–3”‹ÓÇÄ‚º{N 4µTõ&Áý,0 Ê:Þ8¦Tè­~ï;Pì9ñ””U ŒLצ†ùù¥’íWE!¶í¢ OÈI¤ ‘RsÌæâ¿AQ«Ù<±;MPÞæ‹‚ÐIò )§¶¤?èvˆNsm«€{YÖÖl+ì_ËcýÉÀ¼1·{!C‡OZbv…eÝ&šÆBBB+!%Óù~˜5¿Œ%§Æ ú»ÈiÝx'ºDuåDÕ³™ …+äX1 žý¤³Ë¸€)cæîÈ7X­tí¢ “á &›d5ÌEef\p"$ýpìAÄ`|Y:‘Ã-Šöè´²¯;$ñjZÏŸýΠqOáæ•]+!×$ÉÆìr.s]Ÿ+Ó{ŒÄé')ë±y‘Žä&)> endobj 18 0 obj << /Length 19 0 R /Filter /FlateDecode >> stream @„›‰Z¢@v‡Æg‚9Ââù†3»1ó‚Ò‚…ÃhpÜRÄÇVŒy¹/šç!Õ †ÅT‡ÜhsJQÁÞÕ} ÑG§ËÿÊáæ 6=ç1²JÑ»uªY®­6ƒ4WÏ•9HRêv䣺ƒqNÏÉ' ÁK‘ Åtgÿ.•ð‡®Ý6À ¬?äíÏA'}ÙQoÅ>¶€ƒ43 ÝG€˜QMpÁ<–t6™û…ÿµ6ëáð”=}0ˆˆ·›œ„cÏ9ÈöŽYš¦ø8A¹R@ ½#H¾ZXŽ%½òSOF„^ã~z%'Ðè IJ´G¯U–2ò£ ÿn;PµF×rñR;’ZuÊÌnô‚“•ü?2M—·-ué\JùEGÏÔ‚fNí+F…Ès–&2ê)´¯´ÊvÑžZp¾½^1}î±—ϰ³i_!²À§ºäúäôêV2øùÙ¬Ö“ðU[ Yå¸FÂ=ªÎý[–(ù±Ò±½J®Nÿ+󇊂àÔfáÆô…Åظp5 RY‚ª\…¶GUGߨŸÜåAž2£ 󵚜ÝpˆÑ?Ž1é¥a¼ ÆÖtSînÍßYŒ:Û0¶Yü²{ F´ ³$Æ<&MÈ%)†ú™ZQ’ge,’¡ˆÉs âlX[uS3‹I8·ë]6I„Øå U«˜%2wx½@ÅÓ:40»¦„ EïÖ~ïÈå-,O«ˆjØÊ´þ6ñ”ŒëäH…R4ü–p~I×~î(-§¬î»­Õ[…(‰wGlH.“QŠÄ%œ›Pê„ïR½‹ùIø…ŠR*°é)rÔÛcÇYð#¬à7f÷…·H¶HXkJâ×´Içc"®¢ø£ô)'º%Ü* èÑâ¤8yÃ'Ü¡ÎÓŒ–P8§:SŒ8*„±Êbdh€ŠAASÙŽ>¤1ŸÅ¬‰ºm49s7½«¾HeÒºQfõ—á Õ(,Ü8çTTýÄ#±MQÀÔ·ò$!¼¾SëƒÎ'u‰+8ÈDá^?ÔhÿõýmçB¬ ±+º5h`øgrË…¨ÅgÛMˆˆ•d3¬PÂ6ÇÌZx˜«z\fJ3I$ð1·Wpÿ"þp!±JÏ‹ðÛt)ózðYcw‚¯ì¾PÖKþ]6î¦b;ÊøcøÆ˜™úr3•ËCæ×sÎ[¶Ñ&š|o8‹ùàȲŽ„5IG=F9T]Õ“™‡¥H ²ºýX’_Ÿ ÏiÂÁÁàºxµRÂ; @ʳ%…û|ú˜ÞHz®É”&š`mDÉX!W†rBL¡‰R·Æ8‚Ud¥nP£¬,«ç …^l¢áðJ–ÜðK à;ð¹¦o²sV?“á¦é$¹~4whªnü Êm§¼ÒEl ÛÊÄÊt¡ñ+÷(à»è±Æ#4 éMÜ–°ÄÈ×yžk°êÚÐõ°çdÖ! Ô7#s¼–)M9¹ðé9ùgu;~ «éÂÂÎ#Óžÿ¸—Ý[z~f>û¦I5õawûW­CuÊzÔfÝ‚yx†pßYÓ᡼Šô­zC¸<ƒ 5––©„Ä-Q[•ˆSÚ¾ŸÐœòYÀV¿Âä¯Abßrßò*1h%˜X1§3š†Ÿ ®+YÏQçß ÌÒ~/ô“ßu½$˜ÜMï–QjwÐý×9vG§E:»|Dš|§ªð…³.1ø—§Oü7=ýô™Â|ï~m ³©¨ÆºDËð›·{R ~Ôà‘8œ¸×©i/œÁ©jŸÊÖ[#BIû ¸™VxO‘¡Ä:Ì¡ùÖºÈÖD È¿.¦E¨œ—0ªØg׃æ™þ+^˜Ri'Môßaé©%Ë*rïX3øex‹©Tê7Å?Á9 mreãA£K× 9ɸ™ß‚ÑSÙt!\v´K~³dk.ºm õìéoˆçÞA>Ìèšn _1»awHŠ]à9Î4&ƒe]É(»ùˆV«àþ*%eûKfâ—~[yYËŠSÃ›Ä r=Q³éeU¶:þKÈ‘åéªè\-žÉh†¾&å{Ë #Z^“¶¹PM8p?ÀVëN´Œ9;·m –ÂAÑ= Z ëͼÌÛd°˜å,† Ž÷cð¸w&[Z¢ãð.W0½E·×që°›ÊÍöŠ´ÝÅÞsÆ-ÑJøWhŸˆ¥õ]0@¢×òtH`©“Hç¦$$…+„"ÔFHø‚/¸¼»ŒˆÛÎY9Å !›è!Y8ÒZ"Ê ´ö®OÛk ‚jIÓèÔy'ö0åW Ôìº ñxõgüG#ÉË^ˆÌ Š&¸=òðuŒRþEÌ…ýή× ›Öéóv-«ˆ"Ò+…;èÂrä.îè­%·£d]ò» N3à~.¦:ïJt’)O¯þ¨K„ó‘=äv9ì´Ø~-7x D à+¶È}‘iºª{‚ LúR3ñIèÜdk:=¼%ÅùQÏŒj•1)|æC,Å3ϸéØò7³¸JbXj0WÅë 8s¤ÝÃS.Q ˆáÒñY»…ïRîùcªK²—&I’í@‡ÎšÁsÕÓ&%·œÂÈçµ=sœàcè“òäq1aáoÜWšžáâWå½×‚G”CÚ+îÚÁÌ[qdo—ÎHX®¤sâ’ÚéïY MÝJ5Qð´ñ+Û `ØoD2xD„r>d˜þäT Êkû¦v`Â@vc² ñ[DTÔ$1^ÁV¡Ñß5uNÆHV“ W­¥aìGÃp°·Æïš ¡’za7|œ‰:L»¸¾è¡½à›.Q€~¿ƒ˜&ðv"ãÅ®ØïKÍü;Ð¹Š‰(‹|`‰¯ZÀæÕ$jÏ„¨páñº¨³_(W8„ŸI»6 ¸ÞnHÚzÅØÛ‚Ë_ó>¨ëö¿$’}ÏÜÒjtøî9·n Ô$Š#]?C¸JIÝ/ôÊǪËïiÜéó!‘Ûžâ‘=¾*DÉλЫ£Ç?&À°„o$íÃÇ~3qVäÛõÇ{ØËÓp⣮”<?È9LK”è ûI¥ðçf#âª-æìØ °ñtYüÙœi1Ì5©Ú¾T¤%?’þÄÇ2·[[º¯™‚\¢§Éòp¤ëhT>žZ(¼dî1Ê4‰•©üzËû¬¸Sç+…þ.Ô) &lö Üï¦~Û´;€kûvt9ÑE wý¡æ¨™D®Û€ßNdN?oT¨z ° ž²Š¢¾î„ùšéåÍà8OÈ_†öÜQ”P!3RAïb÷•9E)Kô5ÀÖÅWñ± u±Û*F |Ú÷üXÄW!D0BGøG$7&C´—-sÚâ¬ä¥º¸2S;]k"˜²õš¬;hGÉÇýVZŒ©È/‹è'IÁ–Âúݹß%;c3 lËßb8!e àŒSõ›T›ƒ©qýãÄH”,-*AÀ˜uene¬%Õ 8<´âƤë\€Š™=bý <õ=ê½@\p;)±Z½ÙÕV¬ÂÕÌ[ú}ꬪÆÀ–‘]‰öPmжuxIÀ¯ #-ž6'¨û9 žP”2¹ðéuR#´t‹"—å?õCŸ±fçY¯¶ÖvÔ v˜Ñ“fsxƒ§¯± ç~?ÌF]ãâb–îÌäXjwË]-Aæ#œø¨Ý`"ÈhV¤WLÜ@|Péþ Õ´nZ.11©Ü„(îK:;‚ÂeÃ=ûhËhœòfJðÐ2;GՃɢW´hblW endstream endobj 19 0 obj 2864 endobj 20 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 18 0 R >> endobj 21 0 obj << /URI /S /URI >> endobj 22 0 obj << /Type /Annot /Subtype /Link /Rect [ 76.534 541.228 106.586 551.546 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 21 0 R /H /I >> endobj 23 0 obj << /Type /Annot /Subtype /Link /Rect [ 325.235 125.257 355.287 135.575 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 21 0 R /H /I >> endobj 24 0 obj << /Length 25 0 R /Filter /FlateDecode >> stream â»(«…¤}:åùè¯sÃî´£äÈ t‚õ¢Š¥iÚ…Û|Ž oÙ.û²Äú¯íUînµ¦¤ðì!Êm¬p•Õp‹\´€èðA)d›¶Á€Ñbö’ŸËW™nÔ„–5G¶öVŽöA«€q%£˜çâ 7Ù)¤Ð\¡Ó´9A(Ì÷Qåxaw¾]iÔ׌±E²Ùù!ÿTëJŒ„H++?m{gÇ›ŠÑºQMQž’M’îK%~[•¨4ÁòH«h»—sÇ—ãÊ´7'ã ÐÝ A6Žñ~íVÄéâ19@sÖx3¼»ð¾ëeF[$NBæ’(á °;J ,8Bå‹Ý«¶f’ä(Y_)¼žÌýŠg s–q‘sk3nsnZò„µV‘÷&@²æXâçqÒ»ÑÕ"úZ&½8VÒ&t¢åú'بLe1'yx†¹ Q?° €ÃGýa¢_ßgûVJ©×îä8âì€êÅds ¼åçÚ0$Ñ‘ wz 2WÉ>üIr°•Ûî·ŒãÈÈ{1±û䡀¡ª_q{ƒ,ѵ«%éa$ÌC‡ºî!¼¿ð„.iQ#›/×gz¥†j‰ºÿ€ÑP+~äHž7*cO~LÚçZ PþÈNXÃa«ºù£%«þÂ!ü]3ÜE ËÆáÚ°uíV²Ò 5 ­½åµ¦¥MËÆÅÞÈXΞJÿ÷l‡r†ë$Ûˆ¢Åzv²èÖâÖú9Lh&+ýù‘S]£ºNnšùCpÕóš›L að]ÍÄ*êT+?0±œb`Ù O#,“ é LJÛÏõQ@ RW•ºÛåòRäKtZÆÌ™E2}{68ÿâê&?¼¾üýT†GÓò)Ë›"–ÊHG‘Z@Uêkx8BÜÁc·†·Û£éHë@Ï’˜¤”*«^6›pJ–] æ"óUû®&0ØýVð ᔚçôë5[Ái±ýR/¶xw)3·ÂkÒÏg o_+¥GµaqŸ)žµRE}T´ý5X-Ð ²y3&M0²üòZ¡ù¶äpg#–×flv ˜H‚Û!"»E°_Þ®?×sЉgô„ûÅíUavÁ•÷Ô•è¡æ¯CŸ[8]›ž:P‹dàq/k¹«aB°Up¹ÈïwSqß¡©'ÇÁ8?ËîkîèÒE¤¤F_Ý¾Ž¥ï[Y}ÏñÞ1Êj"ÃIÛaê„æiNNmN&`õ~í#H‘_l¸°\u³Â ,å/Èn³2,û ƒq{?dâpeöŸ‹Ó•1`Æ-ýÔK §óVHÓt+¶Ž áE‡5IçŸÝoW0fMbs1ðªï>(,y^Éçú ‘qì2'há»àÕ ®Š&ë‰Á?°=4 }ðžu_ùŽI¼Ÿ …8¡‚%¤RÙ?rm÷£z¬.j¶œ"Êg摇I–×f yþئR³ šB´ ,ŠYœƒ¹8¸Úº´=·®Zªp˜ü)–ql5'Éb†rä=Ò†sq³lO˜ =vS‰ÁbNÃWøKÜúø¤ ³$f_$NTZoµMߪ/:Z>‘œàPí}í~Í Ò[®¨ãȆñ….b®âêO£Í{a'ók² jVH=!=ÈÁ%µDÓüeÑᷰŲV$}]˜^˜bnJ\hñed&Ôegs¿ýÖj>†Ølk¡yJy k`‘vâÏ9Ú]\>ù¨{þ¤÷¦ŸyR¤a­Ä1ÍÅýnåzÕ 2¬úS äõµQMÒÙ%=;A-e"ƒ•Úã6f‡ h-2$§µ?f¤4HŒf|…€¸ÈèrµŒ/WµJ8ìîb¿,•#cuüYgÎÉçtÈ¥¢î§J]}fZ±B¹!›Fˆ¢þ¾ï­¤ ¿dÐ0¸o‡‚@ô^÷¸Å™ÿé!RrN^a²„]R•%_²¡× •„ÇIŽàŒ@x¶)EG`p=çãúñz\$U.HMjf=ü£(dž²{<íä\PÆn H@„ˆ;Í0ÊS>î: OZQ„ZJ:C«¾13†‚TÕ#–dät@~„d4^¸(UD§m¤å¸õ—rýv äñÇ]luju¸«˜fqaÙU°Ùz·eà¨6åͺÏ=KG—kÓLaS˜ùf r˜ñ(³<­·EZ‘,$g3”×¥ƒe4"ÑQ9švsïT˜=Pê³±@ìwÉCùµž:Â)¨rP-SûCÆ»ÚØZó¾mf§9^[½¢cãЃ>T[.ƒO·}Èão›¢ã"¥ÃÖñ‚í<hî;p4ߎ¬,%ˆr™¹KÁ‘;›i´…}Ö¶õ.ëCe(ú |`ÝPëiC°æÜË×CN/ߺ¬2Y®æ›CuÞßx»¤½…éRQ$…Y&#¹:y§–‹ n`/[þäÆÁG­S‘c,jÎJ®Ã_¹3.6>5Ñù>‡3þÕÆÜì8!Ü%¡‘Ç>¾­òR÷(•|ó{$óÉË= S‡¯ÙÞ²+=:òÌʵ˜4EEU"f67 ЍÐõÛåa5]˜ûKÍŸ|㇡¡$K“Zº{ó_´—4 ûŠ&}onº'±’ÉúˆÆN;¿DÂÃo{+# ©R4}½?/ƒd§áSoQ{í.õ\˜ LœÊZq(º»]©Ž‹Þ˜úNLac'`.JÄ×Av}Ó.I8†õ †±ZÛhÌÀz5Ã[pUö£ endstream endobj 25 0 obj 2720 endobj 26 0 obj [ 22 0 R 23 0 R ] endobj 27 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 26 0 R /Contents 24 0 R >> endobj 28 0 obj << /Type /Annot /Subtype /Link /Rect [ 411.285 722.519 416.301 732.837 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 29 0 R /H /I >> endobj 30 0 obj << /Type /Annot /Subtype /Link /Rect [ 389.725 700.52 394.741 710.838 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 31 0 R /H /I >> endobj 32 0 obj << /Length 33 0 R /Filter /FlateDecode >> stream AÁÞнÿ½ ×ýxv—&¶V÷<ÁL•† páqâǦPh*+°óÔzSIk_ž*Ú y]¥W IõÀrÄ!œª•ØYx͹g¯Ùe²¹T„ÞUv*Þ«?¼ÊÚðþÎ×ú‚å—Ñ^¯|‹y˜S gŒJa­L9÷ø•z,¡ÝÕ»àuh_(EJì[CÌX,¯ÿ!ûÇ1lÙÅCí©p<(‡‚ÒÇì0ƒm×}­¬Ä2HØ‹û\[+Ñ[G±å›ÞKyÜÉ1ÐÀXSî?²’$IéFÁö1º’¨aòû¥ÚÔ {Ÿn·IUÖTž]iÚÈDçÉwD"CG0Ð2CÔ7ºýl7Û~¸Eß»ô\tÌG]>âx¦ ò¦Bz`ÇËŽô·¯ß>«HjøÚÕ¶Ú5_B髨 ò«„êÄnk|aÀÇu’gÒšVM­™Jà}ô^|j:³â 3¬ýˆò%oW•î0,JmŸ†îtÚ|ø1vìèöŽl `Lw"ˆŒ3t1³ãÈÒ‡ÃøÍùA}`àB¹¢vôŽQùS¶B%êä²ë^óÆkVj¾¥r9ÕØ³„Ød-º_Xt£V& Né5&’™A…5À&±¼eö"U„`ßE£Ð ˆˆà‰¡ 4 ¼MV†ƒ@šzóº>ö#Óš"Ø<„ܼµÅ¥nÎǸ­•E9ß?ù²aàÀô€t)äýô^^O¤ã ' ŠL*ЈO¸¾XލžªŠC±k²ã qE/JãP×ÿ©°á4Ȉ¾ÇvµªýÉ`”*‡=.xjoöVm]LDnoTüóaLÔSÇ ¡]œOb kåë.6»ò^s<Ë+Yc^‰“hð:o¸h€¢„ƒûøîÝœ´Ul5f›×Tç`~NbhçWO­*p†I¨;™Úé`W{Øññ (ÈR#,ð"¹äXýÇXG¨Y6ª6…«YÄÄ ’š%v[X)&³Ý˜[w8B‰ƒ¡S2wLQEÌkæóíq3ÛbK蕱 ¨ßyl^äí¾%p¨x#’Éü½þ¾VÙ†õ“¦X(«À¿-XÁ#ès0‘)Ïc&{ ¯ñV &`‰¤ÿòúúsvAb%]¤ÉÌkÞǦVá]‰MòÃÄ·À0±u˜¸ü|ŠÏµèƸ^†`ÿ%Ìq…ž=yLªQ€•¸’Æÿ¡áí‡|-Ã&º«Œœ^:…±[ÍÿLWöçñ ÛÑE‚¦D¹_Û¾]ÄÄ~-@÷cjÅR;–†HyÂÿM¯0wÊGX ÜRŽœq!ïŠÝAØ¥•j ©hk¦Üî‘W‚AnK˜ÿ4Ýä“ÄP¤¡qè½\™åÊŽ~ûÏ7µ˜×‘Ãôg”‰eì¿åÔÌÐÈÆÐ²M_'AŒÎ°|Á¥·›´AJm£l}8gÔ;Ë$ÿì|äbÉ5ߨ~žÍ¤éí5<œÖ[)G"»ÕŸÂp'"ÆÜŠ- _o><ÒQF㯶ì7i äc[¢ÌÁsY” Oü[›WËÌϨ°¡4‹¬iï+ \+YhãYY&¢ÿ¥£ÞŠ-àÌýÌózÄßzÜâŸ8nqëAwzÆêWLù äNÙÜvN)±Ì‚< 9Â*(ºŽ™wm_6„ˆuÌ_ Šåœ|­4Í,•²þÖ JóÌùò(¸ëeÓÒ¼¥óÒ«[G®‚m6bö—€nõw³í?ÁNÈ^˜2ŽX{ ‰¹‰ð 7½ño«­àST˜…yŠsdËæÁlÄÞÔµÜñø×ç^Óß&n“"_%ÜýœŒ™`U|0ˆ/j ³„œá‚ìWÞ£Ñmd•åë?sÎZöõ˜r#áe†™vUw^[X“]÷íbÁœï§WÂ#¶Ÿø³Êœ‹%œÎìýdˆé«XtÛ £ž{zA`„ò̘ϼ¾ô¿­Øv.;¢ JVžån«¥#°rõ endstream endobj 33 0 obj 1728 endobj 34 0 obj [ 28 0 R 30 0 R ] endobj 35 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 34 0 R /Contents 32 0 R >> endobj 36 0 obj << /Length 37 0 R /Filter /FlateDecode >> stream õï`VÛ;sFÒ£æð˜‹2ÊÀv,È3c±¥[1< Â;Y@âö9©fÀ{} JÌû®:x…/h:BzÅ(qîx¶JJ¢·"V ‚H|PvžNZÑœ°ª:(2Zuåç‚aÕǘa :¨£¯ÃY½™¡¡©ƒþƒáö0K<4÷Dø )Œ.©Õzw6€ŸXr[áx)xk \ŒOœÙ¦½§ë³ÔXÕ&ÌÒT/éÖ¼‘í­—}s·"`è´Ü2ƾFSPŽšãHèMo4ChƒwBw –k§õÛ¼ÉæËÛ×`Ί!fÒJº]òÇFì-Õh^éÞõ‹ÄÎÂ>¹Açao\:þ_P(¹ ’$ˆGi=ZÓ~U„˜‡K(NØÀžžþÄßë™ùŠk '’Rxé/2]‹¸Æ¾¨¹²«§0–Q†`Mã: éüáy®ƒÆiõÕs¼°Ž<óŒí¡œÐp^‡j‹%ÙwƵ×ÕXi˜ÑâÞ™±mòy ¿cÛ²y¬¶hí0®½'0Í˜ÚÆmjšØ~Íbè'ÕäÏVý0DI[¼!dÂܼ>¸Öî˜õ~…IÞWÈVˆ“´È£%â+Öî6 (DÏ„Š§+¨ÊÐ#^Ï©’ÀhÔ¯Ö=!?>,>Ö¦@˜2ØØARƒ@¼ùyñÈÐläpø‘9ץɈ뉥º#2À¶,š‹¢Ónh2äfÊúcuÜÖ§OK£ Ï•”äð÷Zµ™Ô¢öo ÂÎÿÐÐ_Èí Üí»å:§'¡$Q¢[ 3£q.]ÏÚO ù ¡.MbÊèJ½:N ‰¹ãe[å°.±DÈ"¿žæT(;Þ&t"}gçÁìÜ3ìua„Øì%†#ËŒ2ÿf f8$¤‘aÓƒ@ä[­T3,BÎÌ0{ ‡g ;VçÕ(,çÏ’ƒØý)ÏZ©„"Cˆ²û ÜÆ¤´Â×çJ†t²¡!…%>›®±ƒprÚ¼gG¬SWâXTìë®Â š1b½?š]®Ðâ¬6¯f”TÒÿ¤Ü?å}i°­Û•¨ÿm:ˆ¦f¸9lRo7è›àçaB4îýMØ®8z#vŸ€ñƒ§½B%Z8RÌ( Þˆµù[K6¡9a4Æ/¦Þ¨ê­nè cЦ_9BZû2Þl«;Î$GÿñÌÚæUu†öô³Èzí± ‰<®2õPU.æ1úáÖêw/Ê­ø¯±|i_›L è…o{öÄšŒ7 ,"Éä«jÅ÷™ü³æÔÝ8yýô(4q^% qÒ¼áÔ<¾oßèIëMã2Ã>êÄYµ(†›Ÿ)$¿”ÀÒÊÃpnD¤ïA ÇS1˜,–W-±0ºËwÁÑ' dßQ?›pí5~Vkj]åbpF‹ÐÍcÌPà8áKQ|©ŸüŽzËË ÀåºðU•؃sǼßÜ»OUIŸ/*'•~³ZBRœÁÑÑääŸ\ÔÒBNÝD¶<©îó:c)Õ¿²nZëm݉ࣄnÀà6ºÿä?e±|e$‹; ¥órNBЮƹ³¦6¹©Ó“Å*!lv3:¥#¸œ8Øø„º0ß©TêD¼v» B ¥ü2 (õõE\Žní·‘_RCªi 7t€ YcÛ—w‰],ËW.Ü€²ëôlì(v‹M¡wK0Ñ€±¸)wñ|ó¿œf÷ÍèœPF"@%é‘Ê:„6ŸÃ±Þ¨µjŸ'›ã®–ç7‡äj’:á‚Ê3¥š[5T«|í3¼°m¢I=R¯+Ò `Dhż¡. 1ÚÒBÝÍàRuÔä äÞbùŸý…·îA—4ä{¥iü|z—)ÝÍ[´jÊgŒ¯bEÿÆò̹•¡GpØÛ®´÷ýöêÚGž4Ëòµþ¹£öÁ ^ îIˆ¶š¾‰,–¢L€J¹å¡é†7RNì­uzü¼Â()^FöÁ×ôôe({¼qß<|j¶®ÁD˜2»ø‘°"\GKMæ’ëÓy•¬S¸!IªXnÞ÷6m=Ò;¹eÂßDᷜūä€yN…ðF=ÖÜ刂MršCM> XOä(‚æg…}šœï:ÂN·z©3°€êu±¯u¹½9¡>” ˆ z°ÞR뼃€ƒÈ•€à{­Þ©gßz)´×Šbþ÷OãNÿgjgþ+„MæðŽ;Ãyƒ?’‘û·'«@“àÀCEŠ«ÿ&؉úþz‡íÃþ¶¯žŸž³HHoµÉ*(Ô—è*Ù¶Ê U"*ÉP½þf<%=¾&†‚îÐÕð¦¸À3® îÍ÷*ùb°æ§fcu ¢•ŒU¡~N2%”îdA·’2Ü×Ìò5™AÞðªû¾H¥áÅ{þ`ã«fÆ>MX¦ .€Æà? lLº„pGu.Ü(Oh_† {Æ\ÖBÀMi âk†ÛpYñirƒ2[¿[®ÜžÂû–[ ±—àQ*`'U]b>*âÏØ¶ê@6?í¾wœ·]°è¢%ÈE™^WG‰ µzÝ)!F ˆdèÑßdݨ ?ª£ŽÖêQ®ñEÌî˜lÊMy"±µçÖx ½ÕüËÄÒ4lHhonlú¹^¾ 1o†¼ ÷£käZ0r‘ß6QLùžÏˆ«·¾‚·26—s ºLt LxµmkC‹Ïù²Œ¶ž”õd«…#¦K±V´<Šq ©E0Kƒ±É Ù!ÑØ s'®ÿðzõl£‰‰ˆ fÓhJìÅf(B~F>;…þz‹ýæftkç‡ù™á+u=€t`{ì1 ³WrvWï¤"F`ç+=âü.Þ½üÄÔ¯àNcÜsíúBϦŒáõèÞ§Ç6œæÂl½¯{*<Ô5!³› endstream endobj 37 0 obj 2368 endobj 38 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 36 0 R >> endobj 39 0 obj << /Name /Im4 /Type /XObject /Length 40 0 R /Filter /FlateDecode /Subtype /Image /Width 51 /Height 51 /BitsPerComponent 8 /ColorSpace /DeviceGray >> stream t[¤š—ýF'j;Ú±=ðjgxñµ–÷Bö+½ÄÑØQ÷±ŽÇ4³°³Ñ;ÒÖßøêKx¡T[®Ÿñ¦”P5lÓ€¬P´º‰$µ¼ÈØ.€’±OÏýŠËÇ?[I—^Ð_òïûH¶‰$ÞˉE£‘M †9Ï áU“¥äí\>ã¢G•Òâ>10‹"é ä<î¾µ}-Ÿ”:ºÔÕ;z ö@BΦvýlå­ÿN·GÚ‡x¥ö²pIÝcTÐ=täÍ> Ý g0†;¢àpEGw%NæÑÜànï¾”õÿk?^¯*f·µ÷A÷Î>Ñߦªª|Ǹ5zHšwwhC;¼¡ÍÎv‘$NpœÌxŒ¨Ë Bf7&#ín>Ì#C ‰|r©iG† ´§ µ¹PÕîK@݃RÖ‘§»‘QÞ!5U§î¬ Úsam?4|¨åᣠ…ê“z1AÐ?gb™Ùå“Ó9¹ò5 ÿæ@þ (#9ˆ MYX¾Á9©B Îû½’žò>–˜ °ÇDR+K@» gÕ<“·gôù.}ÿQ!€½dÌ„ÑiÚäkÒ°ÃεŸûs”Æ 3ֈئ–µ®%q„é4G £O‡ÈQER«“çûï_Õ÷ef?hå9à~¬óƒv˜.¥âäÐ:êìTtkr€#½)Gg"¬,r¬ ¿,–µNÚ¥øO& hc_(Û¨‚³êß²/q25èÎÜ +coØÚ_:©ãà’PCîvŽRGöùÌm9^)¸2ˆê£y~÷i†ö‚4j$*ØÏò€&épUµ¾ «–i‚¬ü 9nÖüõúKz 'ÿpd»ñ€w åÓ4Ðw \ïzí3Co>B3«!›7ˆ D8/×ö´žÅP‹ÆÞF:œá, ½ñ<ù4 ý¾Ìkææ¢Êu'_Hל‹ JÞz_Kãñs#LŽ“>ËÇÙ½©{¿Unõ?„úÖu¤£¢ÑN]U†êÄ|ü;õ£ZýÄ $ÒQꯕ{cSz5(ÛÚ]Ÿ;.u…J[ …¿}Què壔f¹;ÛÁPµ"“YRkyZщP­žˆ9Í ±¿ªVŠL.y!š5V#LéÃI\itœ¡¶ÓÍÝ×»POaK'Á@”%çþ7¦¯Æ‚€– endstream endobj 40 0 obj 1040 endobj 41 0 obj << /Name /Im5 /Type /XObject /Length 42 0 R /Filter /FlateDecode /Subtype /Image /Width 51 /Height 51 /BitsPerComponent 8 /ColorSpace [/ICCBased 2 0 R] /SMask 39 0 R >> stream /ï;®b'ö¶b€õ¯‡“* éƒz‘3i¿@¬ëŸ$–ª'ÇC` Ž4ö¼ä¦ï ¾näqAU¨4­. 'y“E@û\å TZ{uíaÏ çØS,lÃh!L^`A|ýøßßòg%v/ êñTŒ3ü DZ•àÓÏÔ€a6ËãÆ( …êù°®ºÔxyq¬t BïùpÇá 5)×Cåø¡ê·=lbï÷‘¾b;Šé}Þé]ƒ›8MÔª‹Ÿßè0@öÝÑóñKWä“W+ã¹<›“’W_º( ,dƒõP‰U-[uÛP›]H¤ûïšu¾!«RTtõ¯#ŒñëVY”P(*z¼= àÏ'ôØÄ¾ð–u_@!3ýÄ?Æ/êdubê~ª®Î8|#=G;qó&šŒjzy@mx@4Ý™„[‡qÔeúÕÇÂÌÄ.ºg-Ð&£¸[å}Ã,CôGŠ{úqèÖ‹ðNÉrLÜöþVrGt‰É£LðUMTW7 øƒ¿–~_S±ëLª“µ‰:k±–VI·#i5?D_ó•Y›;öÇÊ(n¼oLƒ¦¸•3 *‡tüm|Ž?]=­fXP«’è¦qŒÝ:Ÿ8íû·Ðœxç¬AôR˜ÑÞ]éã}g¿U2 Óè³lù™`,‚HÕ\lö;¥ï3ò8~„„U¨*êl‡ÝvF ¼ŽJ¨·Ø35*ýáÙɇ/1ðq|ã­qŠìTn2÷÷ È8r—_ZOP­ç5àçW†’/#µ¹õêpüíéËr±uÐ9œçr¯_QI3í?œ´÷^”©›¬XÙSä²Íõ«ýå –ÖVÈC®W. èðnMý¦{ÞPûVW©1§|МÛC7$¼¾–/êºÖ+j4‡î!ѸsEÆ¡.ÕFzq„‹]f9’}³Ð‹j Ëøq.™ÙryÝ@ð^¢*g~4Þ ¢ô´ 'ÛW²ÔËŠt±úHñAÀ¿ñkìè]ØœâŠ6fì½WÑì²h,ø}}‘bCÉ\ˆdÿ)«ýoþ]"‚Í_ÞzÄœn $–B‡k€Èë°êR'[³d† /S /URI >> endobj 44 0 obj << /Type /Annot /Subtype /Link /Rect [ 238.544 703.506 451.57 713.824 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 43 0 R /H /I >> endobj 45 0 obj << /Length 46 0 R /Filter /FlateDecode >> stream î¢K¬z¤j¦èwOBy&C•…pÜ×2@ÍÈRÀºÑôoçI¯ô‚P"+&çξ俈+0éö<ªŸ˜q/ÌFMy¡²ÊúQ€f"ä4|ñH)ã:ô[ f»9^ö¹3r"‹zAIÌU 5Õkñœ´@‚èÑ3ŠúÑ銻¼n\Üù ¶ëœ+CÚ(Ó$­CŠâú‹ù-RÉHóÑAÂ\E¥jü’ü·íuz»­Æo^iG)Q6¿ûÞd‡›&QÒ7ûÚi X'±D +­>w†Mz^”Ö³®iÑ›þ”ÛÉàM;o6 `[5ÝÌb(‰×ܾûªQý,o“ ª*ˆR%ƒG!-LÂ;©Ÿ Ó#²Éú£ „'ofMÑš˜:ñh£cb|"åªKð¾µh•—ð[,ñún›¾˜4=·P ÕAKÎx3.„6Ĉ+«[É}e0`4¥‡ƒÜ)§ 4ÊœJ3ÅçŽÍœ'ó@GFßÁ²#¼t¦ÍgIƈ²Òº%ý"ŸîfQë©níóÊnŽy‘I&€S~×’_ÂòÛiÛä´ªëößz}S¯xC–]ˆœ¸sþuº¸S!z6¦‘ºø¤áÑ%{ØA¹½=÷#Èð­{ö¯ äûµóÑ\»~ 95ÇGù%¸_²'Qžàs˜ dŽ&¡°Ö\Øéù9f¯«•Ð)§KGÌíÏpTöÇ⬠^fg¬gP*>»ÛÁPÔ¡nhôù¿k…掩Vów<'œlGNz^ƒPà«> b¶ÝJɽ،Åj¸„<94IŒéŸ´‚¡Š·GSàé¨!¼rn×䣢ÿÌ'D7 0á)K4GrÙÍœMÐÁf.ùd˜3.O¿³ŠvÁÚ¦Î),‡~«œ<•Ð>Ìb&“ž Vò—ý¸vÇ%äëûõêl(NýOmžð™uáíÀ„FNÃ¥Q…sw¨UÅxwÞ¯lKãz1bcl† 4b+]÷–÷«¹¿.;E&µÂ|¨B½ñͤêfV:² –C©_ª—2Qû"\CáüwË/^å2"ºyñÅ·s ê¤m`ÁˆýiŒGÛ¸€ÅÈø5§]ÔúPnl~úñä=–üZíæ_ä™™{c5™ýyÑbßbô€µsÒAx_sz‡!FjîóPHÇ"S¬È«šOiô¶Îý6¯­•ÀËh¡äžUL‘Zý{ú£ø7¬ë ë:Š]HÜŒÿ#x$Ý•f•c…à¯Qf¤¯t{ª ÙZë¨`ULí{z6äOa#ÀøÒ¬=t¸)¹GG²1¼É Ýëû¿ˆVBÝ™&ç0¦ßwï==먽„Ós›ÐÉFògÞ®aR›€ÞÔô b#ÒÀÕX±(XêW™@G%ÂFæ…ð@³óHÿáX×T3® Ÿ3tˆ¯>LwSü½$KdÃóV²¹|{óõ“Ð ”O ðteÀ«Î/w5ÜãÇ“Üê6ÔÕú ߦ‡WAw23¶k‰^G&s±²¶žÉ Ä×û“Ç1 j}Ѥ:‹Ø—µ¨b‹`‡Ú0q9ÀÀÂ-…~Bž›±/@ë¿_¶\öƒ `µXµP»ãC8qüÓ!°ÔÅ-‰Ëxb_YvÂwmú9 Äø+7,ÚdÝNAvóÑÖ—¹9Œåç ú xmÒ¶«-˃í|ˆäà–,i;sµz‡‚§;»y1ÝèÿoE7"tàœz’äN«ãš=…dsº”¨ô{Ù°´G;à²åCKSÁ‡GnÊ0´7f°Ì¾ÍAàXMá¢rYÏé O]‡^æP´'ŽæyrÚlBŠLiRpøý‡Œ/ <‰ É=úÏcå ÓX_hQSC̘}ÛÂTÄšÇá›vS?EŒÛj endstream endobj 46 0 obj 1424 endobj 47 0 obj [ 44 0 R ] endobj 48 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 47 0 R /Contents 45 0 R >> endobj 49 0 obj << /Length 50 0 R /Filter /FlateDecode >> stream +%üvFž¹jÝ-Ɇ¦D‚²%ÕýŽðw×$»  <ím30ûbc *÷0R{k|U ×p Ȫc;6ÜT¡Æ]±pmz’‹—Ü(\q=×·Šôÿº\t#(ØïÝMq¥hÖýîÓÌþŸµWõx„Ïé5••“÷>J¢tþÎ¥x-ißèÖBNösœ§ƒÉ?Úòî*ß\×”ç5êYމ樨õ7ÈŒ|·ó ÄôöxWz$6Œ|zÏa»×äS€g,Ã!0‚•õ. Ó=<öö%„;«¹aé‘Fˆ¿?h‘©ÿ Z›wÄH°X› šºÕñlF©zÊÔ“X{;ݯòÄC2HÔU±â5™€»Ï•è7€­ü=qÖôŠ-–âtÔ§9Ÿc3³°tq_dRÀhœ5ýΤIqk™.°”zà^¡G%óò׀ƞd߯B–;m¼©l‡|*Þ`7<*÷Ñ`þÚ©ÖÜ&XÞ\/gX£,bÀ#,hÚjÀ»*`Ì "goq;{$0Ãÿ0ÔAOHÁ~î!î1¾QbåB#ÌÉy^YA†Môîò ˜<@.ü‚´JžÙ2< ©Øƒð‚.ÜîÛÁ£ë¬{Í­¶ßÿǰ±H=p4´Ç©@JÄ·…֙婿ä÷¡›Bûû îCÅO Ÿå”|‘ 7ñµÇ*nŸ¦W~ŸR^AÀ±åBýNv˜T9ËDÂòÐlœÒ­wp$–¹½Ý¾»”ª÷°_c¿Úúïàù´Šû‚,„Á“JуŒ¢¦¶‰0FrÙÓ’,Yz¿šÒr"A¢}5¤·ŒTϤÈRh¹PüAš¥å?þNíÙ¹j­IÐÄE©”WË?o”¥G‡žŒ’®_/‘¦ÚAv‹`–BIͼ,7â2áüô âm7ã}¥d:Í0”êš5œŽ{Vå\-sÔ!*&>—Tsຸ¼?o5·œLAmñ ¢²pœJm¼ ÷†ÕežŸü¸Å}…ÑgÈù¶r|‘: ÂªŽ’çà­]Þ¬†÷º¬Jë{pSí÷k}rdãJ2Ot ys™ ¼aíUAµñ'.yò.W  ïÛŽéûÀ` GÁ?¶¬r÷TÀÕÍ™Vìúf±Ä@lËÓC(8ƒÔ—L€2a…)8ô~ñs…ܕԢ*¾K{dðÆ:B*"âJÚõwyÄÿ».ÈÝMÌO,žÿpËpÚ£ÒÉΧéÍ•]Ó•ÊžlˆþfxM{ÖSY‹`<·+|81åF}…ë³ùO*½×¦µÀóº'À¢s¢R™Øõ3Ùj§&ÈŸ±`˜íe…­Wlƒ=Aì-ΊT“Ú½ùÙ”L4Y³éy߉GBVþ´ƒt%ŒLAZ ¶Îtò¢^-'ŸF‰Óss-jø]õîóly±RÎxJ‹XÝSÀOæ »ŠCFgÅ…yO}ë0<Ìô7¸˜)•ßþ(zH†æÂÛ;{»ä}r¯Å„ÃîHŒ÷ÜÍ¥ÁÃR|dšàu ’ÙówæDné˜,u¾?¾î*.‡Ó[,æ}‡iÕƒÎÉÀ ¬¥ÕMÏ_hYcÕ(Ú¸Ó“2gƒ("F\`šXåÞB®æöœmEúc‰ ‰qŒo®¬„4A-u| •·p×äëe>ÔäfdmqÈÞí…ê ˬô›AÊ\¼0ã‰f'•DÿѤÿéàî²(Žè‚:‡C€t8i/]{Ïæa6Â}ª6”Zc:™>Æöé/Æ V='í~w)–ºÞÏÏœÿܯ„Ýv$éHðÌN¥ù# WôæÔvWBèppðϰµÿ'µY=çS{+PƒÃùgÁµx"sãxú¯l̘ËdjþÙsÞP«%RÉJƒThÁd¸Aeƒh+mn¾‡›MPŸ~´Õ!«bÿ™o¬MrA\Ìb±ÍYÜ·`X^ÔL|izZOg B V$ oâóÒ³$&;B)ñÉïQôî¶`jÔõòæ“Þ³ý&3î æ{¦ñ'^ AícwÁx {ÄbryІj9•«Ò£Ó«ý§º§}û7u¥ý»1rû ^S”–÷W|ûú̬-ôgo×CÚªº¡;gýÜ—höð…1‚ÔÔ¡u¹'£àrééÓÉÔ¸ µ,®µ^ï‘B–ïÏ<”øH‰PH,йíw³}*ÿ|Wµsô$cë râ‘»±Óó÷ê!B¦ÒƒKS"^ðßmÛ<²"{„‰4y)W¯ƒŠüƒ8&…vÿU;ƒ—Œ¬ÁÃá=jzjB»v)a R ¨½D^ùëˆÿöÜIµÒ/ãXïM½];Ô›ö1ÿmà0Pd{¸˜¹Ü–Ø•žÚ[(`A´*ß‹R¤:ÅrágA÷"‚Ó•5P’atuî¹HäûÏ‘`Œa:Õ|²ƒ÷*íR’ÿ3Òx$²©ý§Ç5ÒÝV€Ñdï›e‘LÒ3l Ζ 7Bƺmá'Örèf nÊ;4×h>‡úqaÓºh™$ãyíiš4ž0 pç ÄHì9ú…·ÅÂð ÐV5°7ƒ 0ûwC壢ø)_Eg|ó„Z˜n‹ ‡cÁ+…RbEóÚ•'[R‡MÍsa¹ŒAŒä,jr;¡AÊÉ«ÊÛ––û³ Z4^C7‰<ù´‰;ø²60Ñ]W¶W/+¥GÅ,p<ò[;*‹X¸qÝG3ìR4Ï*Ë8]x¾¾nÃið®Vê>âVp¢× ‚ðÆBÖ{TòÏ{Ç|2¥Pþ&cŠ û±‹ÖN¯ebm%°ÙÕÁc·‹šÿsnÞõ4¯h<64bÁ¨ó½L„ɱÎË@} ;žQb4² ɺ¦ÿÙÁÒ€zV…Š8GsF2H’ !XÞÊ*’ c©#8y¦q›•`ÖPÃbÑ|¨ÿt[EU›ñ’ñ¯R‚Ó„#ñ5þ–fIºmØ.¸0hùV©MÞÊW‹WÓµpÄ-©4Ókvª¿ZÂÿý¼ÔL­|­Ž"ÐG6“ÖnéúŠf3è÷㨥`Î Hq^C\‘vÏÛu?®%¢cáNÞ9¾–ëí;ýÊ>‘hÎòãøì~ÓS¾°ýéôu®åúé3ÍCKTQ«+^#FUáŸÿF™Zæ™_ÕÐ2 ÕZ»YË?Bœ´zl:î¦Xt¢b•µ³`£¡ƒ_HØùôH«ü„è¦,¿4€WžY¡.v)k[lÛü&ÖåìxL+‚²î5Ì~¬’šÄã0à÷†ú±1¾åxÖ)Á¿M”Tôhä]9½!ž¶Ž§MT98Í'…Îε«Œ4±O–éQš+mn|\n·ÀÃô–Y0šìxqatW 'ì?Æ„— ?´ûÂo{ÍÖÀI,GiwÆÚÿK+/¶»HÁ˜ÍÇÀ†«Ûá<´âu³Î6F]<àEê&=}£ú@‡š ÚÖ„ò1¼~ô„%ÌGâ›påsÚ£Tstu-¸¬”þ%"v³˜•Š$¦¿¢k-éKŠ´¼W,‡—ÞØEµ3£ÑÃ51ái±4ÏóB²G¸åvìy™Q²[Þ0Y«sƒ «F§?Úk _ÖÕj­ âç¿—w:D\3ÈrÄÇÌ J'ù¼Å’9a’!«s$#ß”…¢ff¢ü2y£/~ÉeÁ>ôdr½+N‰vÎ7Öâ©…³€Hñxás p)ß/,šÄÍ1ÆÞÞ­ÒôËè_ >9[Q z¾° A`.À»Þ­à>>v&—í2ö•j÷Ùi-ÀØÌO55ë¾îøŒbÕiܨ­æÞ%¹+P¥L}Âoï%Há­âx†òÂÐl§º@;ÜM_Dë\d¤ˆ27'º“°¥s‹½.e0n¶èRéVQ¨lŠR”ÚvGce‰#<$zŒÄÖ裛®|JËç4[]ÈìT±xU?`<Ø-êZ縠ü4Y•…¢ÆåÙ=¶NóÄšá¼+Äz'@lÍ0°þ7)ñk1±&éïë3áßVn+«³ó•r€#ôNÍ­™„lnö ƒUD …Yp“ºøÊB+ëûtu˜b“b%ãx6‚&ïÕà}¤§;òPO±kxBo‚›Ùa ?™w8„ e¼ˆNu üœÛBê«™ yÓÌòI•“ÍQXSt·HÐ6ß³î3èyÆ/»y‹W#%jÉÅNó‹µ×ÛS¤B¶Rã‘cø³]¢z£pä½­–D4xû_dýÐ\ÖHT…ƒV…áÁ×xèÇbÙ å£Gª¿€ˆ3˜Š’£ÓsIµµ6”¼ÃUshÿ¡Ãÿùó(u*v³agÃh™ÇHE§ñƒpI+¦ñ˜³Èž’êÃŽOÆ=> endobj 52 0 obj << /URI <950EB5474FADEA423324B566F07F547B85506A7A0D57FADBDD74FB36CEC08972CF9C83E9FC4E4628E048B1FEECC989B614D386DB23E41A01A430AD934B15CBDA1EACC1A9BB96BBD8625637F0ABBE31A7CDC4163064F7F0605413B617D83DBF94> /S /URI >> endobj 53 0 obj << /Type /Annot /Subtype /Link /Rect [ 115.786 143.113 165.418 153.431 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 52 0 R /H /I >> endobj 54 0 obj << /Length 55 0 R /Filter /FlateDecode >> stream =áß*R‘µè"U_ã“®ï™Ì»¶v¸ç팜«{aþ€Ì1r5‚®Âã—Á[Â~3c]p„¿±½*y심ûå>1«4Ǧ§&±»ùbõÓ·3š¬,–LÊÓZ%ioùͽ¥Þ0çÎ1W¤´Pt€ú3q,d ÃY­2•—Â| óµèÿà°Å·¤âñœíÀØl%ãÍJgèKЧC0à´ŒµO ¾Æ·)6ÙiÏŠA¼¾sõ'áE±ÊôÉ›‰9Mmª@ĶvZl?HâiöĬÂuòªÒÅú‹ûdäåßÚë'ÆY)cò¥FÅy)Ð,§Ô9 žf_ÍÞ¬_ó.µì;>½ØÍNwðÙV²ž²ábÝA’¾Wø/ÔXâ°}ì °ºÉÕ¥µüæn‡OšLnˆä~çdú2Ý–Ì×¾÷Ø¢Fi¹V£Ó«B5=Tfé±E4Šœ³§pJ'P´ßÿdËé9°g¡»ˆ#Ë —ˆ¹°êŸ¼Ãdl8Bú@` ’ @ÖdJÈrE­À¬óœw%€bå/;…f(.­I²ŽøÄgÆÇžBá¯1ØB+×(xu†mmº«‚ VrÇÌÿ1sOhÖ5e[·ÉsfOª3upkŒ 3xÁƒÆ‚”ãƒÄÊ`vŠÃ˜<)Uñ¶Ë××m‹«ñ,Ž`ÿ 2Xüˆàu™{Ò•’;ˆžÁí´_ó©p*ùÀµ‘ÙÑÅZ-X ™–aè²ÁíE¶¿îÈ`‚ëûhŸTsËÑ`¿œ€ß¼N´üË?¾ôÎãùkîA0ÿ-¸~æd’¼]vËm°”ü¨’`üú´=ÎÓøëÆžàç/Ÿ¡U<8ŸÈ$ÊKÃ\âCù rék' [³«ïçTþ…Ø`~ºè‰ÐRer©‹œ ³0^sJs÷Ž“Ÿ-£,ƒ8³7ÈÞFæ(gi¬ŸIï F”R_o2 ´guoV¸LÔúp8p·ÕËÒ“ÿ«©_+Q<—·sô@ëýDVðŠr SJLiN£Oµ%L<ù¨wMÎLOÙ VçJì=VÅÔøÝmC«z¦J“õ{›K1Ÿ¹‘‹éEzð1ˆ:YO³ÍØ%³©I9Kx@[ ¹6£V4éYa&àL­e‡ˆ«òÓä,VNoo‘qfsìÏZdj…r‡‘KD8îœ#2fñn90U ODÕ%ë,ÙœêÎüÑßI±Boà÷sÅ–ûÄ”oÂî®O@ äÁ¾Õü0vG8}äbúåY„Ðlk\pWng~ oDç¶•@¡±àqLÀmÿ qüžX•V R°ËüMçi| 6è€'c÷µÔŽ:hFÀ#>Üf¡¸B¨ Ê`¿ÈZ6íÓÖÆ:S(k’â%DMŸ–%šhÐG‘°·î¼e#ˆjMº¦¯g*&·T75…¼wg0ï9NV8k7`·éÜ,ßr{«ƒ«UV¤Õ”9ö\´_DƒaòRŽÊÄ,Å"k†}ºR¢ƒ9îŸZv`3Ñsaü|J_4Ýzc* AåZ)ç’œ¾“f@ËKþpË*·ð©i®[ÉlA1{*¨ñÇÀqÝ»~•íMëã…paËÊßpf *Ùfo‹“?ýlßع&sÄpµŠ¬‡¶Ô’hM†æ ¼Øhçt¯u X68z׿/3ñ#p°%Ñ1…¼ûu‚c«à!O]´ýþê/1=L8ºˆ½¯˜yÇÚB¹¾z¿$…Ë¨à³Æù\tr3»ÄoµØ©Èó¬Àlè'ÿ¼_øJ1§® B9žÓº ž½°Ä}uh^‹Kïç¸ù7+l¾ N%fE’”y©·yZ°cÚ½¼{WÛe#Ú•^AQtÏJ‡³$ow8¤Æˆ-l*,kíö*rýˆ6Õð÷8ƹnþV×$²Jr@º  !êת°ý™šœâë3½ ÙX+=’Ϟ⹩⽳)ÑÛýúd0ö“!ÕÚR“³^ú¼nÏJ ö_dú;„Kâ ‰ÄINþ¬IM`p”ào+迟“~Í!Ö›‚G©î2™÷ks¼˜fZrT®ýÐ1F;Å C­¸Ã6<ßæ7O©\gcúÎ0‡zN4µU^°†Ó$gr'Þþ z­¿áÂkÄßì¬}Pç‰NOì`¶‹Hh7“Ób‹‡õûÒù"+3c3r^ÛÕ‡ÖGç' ÛH¶1âÚ¤G_C? “ÓäM7Åžï_ô[Tªºjn(Ü›‰›Ór€¤EܬŽÇ}÷òÙç’ `U¸3fƒ ¢¨ëctV×’[´uˆd”0¼û2Ú¼´W$¿ z@®9áöª²ò×aH"áMåp¨Sf7ɲՓнÅÚïÞe• ¥P´9Ψ‰{¯*·áŸN„#hÖúà.•,M oÚH¢#N{í ¡G7šñv‰6¥ìEÁãOݲ´î>?­7FÖ®«ÊÝŒ[`9@%Âå‚’VœB‹lØ—~5þÙÌÃàDîÂ}¹®(ªFÇÚ•ý 3í™Z—1ÐÞGWÒñÒ<2*îÆF£aK«eN{þ/iÙ:h@_:{œcstŒÊ‘Ô…‘‡ÔŒ¦«Õ¥åî#ÎóÝ÷+ÜbËñ(~‡Ü‘'íê%lçì<ƒÝè©M6âí’&¹€¢Êø09R¸ÍÃÒ •½Qø°Q‘Še‘ö8ßí0T@½T|ûÊÅLÙ=DצQ—?¨ÄsI©­O„Éf«éëTQƒ(xÂÏÓÀœÜ‡ןZ/"VÞºâ­ñÀ-ßœ£z Üq’ÖܨÐ4–,–±Õ" +„nH=P„Vñ¼t¢Yu2+c¾¿`€çì‘×/Ï ½9ï ØÿqÎTA‡|Ešîø?0-I±“AƒôcJ£È¤!ÆuOÎ"Û0÷/?]14ÍXj43Óù†O6Gš¤ ívõ©¹à%cF3)Í_üL˜fÿÙηŠËÈÌ9FÔ/Ør Ù–3¢¢&(CŒµ–Èð$Æ#µ0Õ8ý0å5¸I¤úÆn¸t1 Øc_ ãú¤ šöÃó’áÉO–)ì4»¼µGnó.$ÿYQ“8ƒ€`ú<”†ï½Ðü¨µ¦ï5vÚ¼¸}¢Êø9ä’gÄ ®Xµ gŸ)Wå…bÈoêã  °ñ¿Úû[Ÿß§RJ[9Š–®2¾|¿ª)ôaa‡¦?qƒ·×ÂVKÜi° &Qþ=*%û«_þÉ”ÉÅÆ±¹5 ŒóÚ<ƒñž¸Gr[ÎãDU9³&Ôa¶ç¯—T ®;N½ñ§ò~µ±¦:å½GëØ<„ŽDÚÅ=ˆ’ú¸pœhaŒ”º…Pšßì&™­bñWÊã ô<}j¸É„¹ÝS\ðj÷ç’Ö4ýõž¸ì<û7"P£« Ú:âåv ðõ¨¬Á¢ƒ´Ë¢òZL§Ž5ìûúŸaз•(†ƒ±¦k=ª´ŒŠ‚_Fþ1„zSÒÐè%¥¿²J7•Ç›é^ …»PœÚ|*²Ë•üw!'}Gr¤^÷,GWoH+¿÷„bŒû°½J¾\'é‘“jj4BÆr2,XÛL¹jÑ<>k½íç[an|¯²ÅqYz1›˜[ò]6³´¢…踰0ˆœq–*$÷Ãäk{P5AÒ}E@£&ñcn墚< ԆšÀaVM¸ò˲ad)7fÈ䘛¶+qüîs%»—}ÌËòö99ñç­DT•~Ã’ã&[[26ÌìXs%Î,óèU´°Ô“ éø…Á‹ü+Eqbb¬^œãl5}TW,x”±ǂSjAuqöy¼¦s²5-¨ÝÙð_ùMe}­ŸeÇ–@Î* 5|òNœ´þ¡C²!Ì©Ë00s*Ÿ'>Ÿ¡ÌÎ;ƒçÅB×IJ»7õŸšn«EìˆA'~·`P»b€†+D Ml£ã—“©´jW”‘€µ2 dí¸’ÌÖòg)Ò%ìQ()Vfõ=_Ø +< äøS¢ã'õ©m“'€%F#£veînÁ£ŸCt_Õjwâº%ž-ÀNÔˆÖ3±c`ÁF„CƒÙ\á :jÎ9¹±yH0TÕtxí7íV.ŠþÊ2‘œ¨ªüVþ-²~Ì`¬.%9nØ \Œá®Ç†%ï“ܹ0E[º›¢l`Êa´:cÌÓ OÑöžèY5ŠpTÉqo-ß, ²< éÌ1[á¾àIîÈ9‚¹H {v±±Ùr ÿjÿÉä>ë_êê~ –DV8Õ*uëÀßQ¥‚‘çoì8Òx±’­§lŽíð@: ÉX)Á¼„~~ !Dòž šŠ‡™;°¤Æs+ `v£r\èåfâ'5ZIËWNµ!&Áð€n'fëœÀ@Ùëü(p÷÷Ç>ûÕÇ&ú‰³O£ ½â{z^>…òà7û@f‘üàÁCU²Äv'.¡¡ ·¶ q­¥€ŠO?[@múFëä·2É8wµŽ¬4–j=ÆñHOù-]0æKÙ™4ÙAçç¼sþ=ʼüµÎTè?´„C¡jd¥˜šÒÝç¯)°,wÿ*,+§¼_ØF2™è ô¸»ã£7î¬çÕtÛògPÝ•“OZÔÉ.?ÎÕÓs·ç–qæînu× I&œÍ§ÂçírO%L*@d—äc <˜¨š¿/¢}{ÃYÏ×èƒ}¶¤ÊPPc]µ;ò†F=OQE8¤‰â`$M¯DÔëúã0Œ‰º4X r·rP)Wþ¨ù€ô¦ÏFž`Æiù¥{IuåÖùÊŠË!MÔäër–z7/nLÙ¶c ¤I endstream endobj 55 0 obj 4592 endobj 56 0 obj [ 53 0 R ] endobj 57 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 56 0 R /Contents 54 0 R >> endobj 58 0 obj << /Name /Im6 /Type /XObject /Length 59 0 R /Filter /FlateDecode /Subtype /Image /Width 1337 /Height 115 /BitsPerComponent 8 /ColorSpace [/ICCBased 2 0 R] >> stream Ì@P2¹?yfq%Âî|s@Gç(ý{›OÍÕ[³þVñZ¡Ü`¹ ƒCŠèå.UCcI.zú1‰DzŸ³÷-‚ÌÿÑ/çq—¾8 Ö}[`Ä@,×#„./•lI×§GFŸy¡û÷jÙ9”8eR`ŠT­U® XTR*€Ã@™(s¥4›Zù+R àÿµfXÜÐEÀlRŒmÜŒt_ôw>W¿ ˜ NÊä†Jû( ¿:3çDU¹a'ÞV>ì€SO?ޤ£úlŠ {Ë‘ŸMI\ˆrÅ<¶õðäÏY^p®¯ÒXéÖl‹VGÜ“ìEÀ¹È^M.NãNÏH‰’RDƹ3CºúÙ¡`fÙpVv6´™~¿7ïeè8öŠLÒ-¾¤›”‚o‡xª°qs>=Dœ@áæy¹ÀuYlÂZC]#Ý‘”95hm‰Ò­Ùº}Ý'ݬ<ËN†È“ wX&:Lí%—¥¨êkœÎ B‡4yÑakL¤Çï£]ºá²*ý`1ýó°6Œ{Íúå:‚£Þe錗ûcAü`˙ϖ•ܽœ°ÖM5‹‡.͆6á®È~¢&˵£Ü&1‘eºrá á$GÇꊴ F-l…)zFûü®³çbSDţijÕWr‚q‡, SI܉²qQ• >Ñõqtµ7²>MQÂ~ ,ñÆ€=63Ñ]^é.“H¢)¯×}c§Ëù-JTŠC|ÝAëàt€iWö/¤ÙûsË!qéçðÌèg„oÛЇ…'sØ×ƒöŒò¼3WåË]š¤È¯ày%}cËe¦Žx݆*/ABZÀð õú}CÿÚYÄçófà‹ì×›ê¿Î°šÑ~JÜ­…]»Uqü÷òe•ñ²XRÃP¾æ_.À`‹Kycî@’-Ùj2ÎFu5c¯%úÑY¶ÿþÒ[äß·¹Ê¨±°¼“³»?wiñ±ø_.ïÎw×móÑ#Ô³©§’ÒL;²ß¦a›&¢ù‹¶Xh¯CÙãxs>àTY¤ù #¹tÿ¡XQo `‰‘˜z5™Ø|T,«>“$áƒÔ'f„ZLì¹RÙn½¥Ó¢Í#„’¨É/ ´!ùäeDýXã­’›áUšv†—²qsE¦­¦J”–äСŽvéÚ‹tÖJÑ.:¤8cƒK(W‡lŽW»¤¥¬oÒ±@”5âL™,FSÁ©=\%o`¬s$ þÆ*Üâª^ÉFßëôu:¬ÄJP ¦¹:=ˆ`é¤kTÿ4ÇXˆv)—I™=zþÀÛETÌùÜXÇ [­ýKÑ>ÇÏóóÄj6B±§&œ$•U)Øà¢Ã zu/µÑuò«&ŠÇ'¯HS ÕÈ“QB`ê鬨:c/}=k¾,¡³?ßÄΓåJ!ŽöÓ°QD¢û÷­TeK«ò»Ésluá¦ÉÂÇ7 îaÏÆXiy‹Òl9½'ü„ß…bà÷€Ù–§¿›ó'Û%ò…>f„ð²µ9Ÿ5v¦^|½¢ÅKüË\ L?Ûßú¨$KîŸÉ’ƒEFY@!\"™rœ¦ô+šß<¨VG>Ž~~N¯,}A“žv–8éN ñ¹ 7zL9ßœ²‡LY̹OÞ¸¹9wú â±2°ÃJ£šd69gÛbšvÓ¸mcwf³~´Ë—·È*˜?õiÞ¿í^„K ( Öô}Z÷ExU56ÅâWŸÀ•cüW“ÛT èbX=’hÆx]¢CHà<®—ˈìn¦;j Š F5ݾ¨ÅÇ}?½þÆ ý²}*^}‹Þ@p¾wG’ÜfcÒòž¾<ÆBt—Ó°(½%½-é=´:ÿÂೕƒ ìÿ øô4G«yµËu‰TdÌE‹ääx¡RˆÂüÐ!) êÀ´ËA±¬gÀÏtzÚ˜f,ÉÄ“P¯@Ö† 2>1ºÝFîlêsœÒáhˆo*J\ä«m%.o*ÆÅ:¶ÓbJçž!Ûš2∿Æ×â­I«V–4ùyËSõkõÈE¶iÉ+õs~m¦Ïr¼ž¶8Ï‘%Ìú÷†«=«Vñ‚AW†Ê’ÁùÊcPþízo‘*¼"— QÙS?`œÎ©bfc/怅»’rÉÀhÒnÕ¨75€ˆ‹p«ˆ^Ƥ‹»7Žq.rŸ¿æQ ÎÔ·^öžlcûý\ÿјLQ~žkµy  !l‰•îÏ‚¬ã­ëÜÚ)hó7òUª}ç¨çõ’Òã+£ÿ„8N|2¬—kQ¡<­¤¹Ÿ³/…ìp^ó7¹Züœ8J‡”ÂPkE»ûÌá!Ððk/^Ìnà‹<†÷¼L³«¾Õî™4åfÂf‰ñ$÷ùñ2üÞ+t]!×»åèâðËï?VJÌÑM#@§;0$¸½:ã¡ET>¦dš./±+óÙyïúh0¾˜ú0Mx:…ưm°tµ‘û¿Ù¥â5|^BgSŽò™Hé?*YÙ"ì/ ëV”í±U:ÅpP¼ñ3Oã}9YÀ77Šï5F—>ýÝÒâwñš mo¹Ô‚¬â³Ë°F^îo]ª¦.ș݄¼϶a÷TéÐÓnLÀçWJµyrÍ׿¼ìÇÊ-¯`vq"¬:z…ŠÜ œ<ùªô’ë)SÖ7ô¹°Í],]œ&©Ël€îìYØ‘µ…YAÞ ¬£~‰ç]b •Ϩ(À»£éçÌÖžPNC¤¿¯ÖïÏ‘ìù¹Î·˜á¯é‹åÃj¶º M6§®k&c<žµL 6yÊQ{@Ôfˆ„f‹,ðbçö×Ñg$éÀÜrœ¡AVRq)nVŽJð¾)ßÝò [Ž>ª€‚7!œPºä¿—¨öq¿¬)ëjïMæã¢Q”Ì_«ç¦ M:Q18#·›b…¨ååÊ MzÅA3®&]1˜~ç[9%T½Þ„Õ9G9jù«„\‘Úqp/Åu~I¥íãˆS®i¹È5v: ÆûBÌ^MbMqÎí‰xâV9ϱAé0‚ù >StÙsòœ8˜ɹù‘2T Õ¬Ÿ(‹þ»…Å6™aæ¿‘¬%$«;^ =b¥eMe@9˜7Ê|“oDL•ÊkŠÖ±J]J…N-3o­•´õ ÔÒ1• Ç_æî”¿wywH‚C¤¥P²ó\aè¨~Ï<¥]7ÛN´ïßöÚü4¦×nôÙCܼcFèoßU97ËÞÕÇ¡Ó[î-þÁ’ûÀàÀAÌÄ–ôU6¼Dé«[z¼úB ›ûàÉGŠzs‰Ö"XÌêtŸ¼H‚Ûœ JÜô»_«6”ŽNÿ§bÁ8cÎyårà…¶à\E* b²Ë¿Ùé¿ÃŸ(L(ç +æ±x!X9ögæDhðR=•0ùÈ ŽcÒ"]íä]ERוQ¦Tä'†>žç·“<›—ë!ìšOÄžh­XäÕUÌÁ2,µÊïXFŸ]Uv“j)bÅ £\mþW%_ÆPùæ÷àE®©£º½ø‹Á$Šol£˜¼Ò@¬¨TéYt;ûóc&uLiíÈ©Z£vS‰ÓKÅ~µ':ü7r{;æŠÞXÊýP—ö“r}v“ï€tÐ$­—¾ôøu§IûO‚¦ ’7;ÜÎR ¿í›*þÜ\Ð'°Cýã'|#ÝZ´²ÉÓÈ·i:øÒ«uã^©vXxíì>ä…³&´ S«Fçr©eéxc’2Ï NK#ç\eåÍî`nÁã/` t†ŸKÓeìÚ@³©8·²‰«ÓjŒjΉÇp„,ò9.$ÿÁÕ^yvýE ÈéCâH­Ÿ‡à_Ë‚ƒ0:Elje”kÎæN&x5Ë)³K¯(I©\zÝ-]ÓUnÕÙr]/¯2Ⱦ+Ы׀cVæKwÏ+@÷8Å}ÜÊö ΪébiÒ®-þvjžžIAÍÆìm¾©ô„Ûˆ‹û²#g%ÑžS¨á‹„U5W”ˆ°)Sé^Dª–ߦWëð86{‹\¾œ\jÆ'[á.›ÝÂn‹çÌ`>kw‚ªñçŸQóZWŸ¸ ­›0}ºuk`ÍŠü0s¨ñ†’ò„tйñM9(@R§Á㥳½É$¶Y’FPsa÷Ë`ôá(¢ƒVŽ›Ä÷Ç-mÖˆ¡qÁ <µ wxÒÔ=nPñãݾõHéc¯¤“iŧÂ"ŽWŠ…ùpL~e¹±ŠãwåÖ–à\Œ?â¢O’»â¿ "èœ ž6øÝ¶jhâZ²œÍ¹ j9Šb•.ð`^^dËxÁŠLÀÃzm)`¥¦0›ÖVqŒxáuBäÕ<… zY o‘ !}Ðmb”Äz²óщô(.˜QÙÏbé”Ñ^‡i>T£\Û3kPYfa»á”çSE! i í¨ •=Áf±ãõ™éà $o…Nx¤©•(x—¶”ÎÌ>ð̯õ䀯ì*‰î!BG¤e“·ÃVÜŒw<Ëá¿'ŽðÏòjv¦2Ôµ¢%lÁ—Ešô©”þÔ¢ÞÉìa¼‡CGWlÞCå¥ñ×c³ œ¨3“³‹q4Y×¾@ ͼ ×68Ü‹æ™c™jSÂF8®ÁÃÆ2¡yET\†û¸¯ªœJŸžáÿÖM¬Ñ-„R*5?…ð§À§*¿«Š¬-Mþ7½í(lG¶NÝtíºË1eYiq%™îôU¥TUìÔ{t¡ ù¯Dßa1CUˆp —¥V¤OLßq;kÜ[É~Àò¼ïOO(”ðT4qO‚÷7Ræ0m™LÙ£BåÚ­FMžëÒStð9ëJÃù•¹€z¯ÈßJÖzieç2Ç™ØÎxå9ôç-ºÅ;_u/Fø8‰ñèøÙjêZ~µúm?'ùuVøšò{7ÊÜì˜O{XX&ŒþŸ~ `Oñ ¡‘q̃’Pdž5 Ð%€™5SÂMÞ½ák ï ÁDOˆx,¹ñmásJ;#î¹'˜Ês»¾),nD*ŽzÓ¾‚¤¡âÈ ä¹\9Ãò’úß]¥ûa¶¶‰D7·Aç öjôhsR‰ œ`Y˜{jàénÀ\»1Ð<ŸÔr^Óo­ãXó†ÍÅ&Ùk±µ°¦l†ËmI“â)ÿf’IþìƒUµyÉ$7†¦ôÈ­ä4Yœ’€ºôñ‚µ²Wælû%Ù̼y'6ÕØc.ì4âWìó…Ñ?Ñ=¬.÷ª^¤~Ã>ôçg)!¹‰aa°M/©ÝxB/"¢ÔI“Ø@öá–N¼tªÛòmb)ë ÅAóÓAWÊ9¿ =¤4Äb[â€Y¶y[Ä>ë FÍ?Bí‡wR/baÒ iߨ\ÃÛ# 7‚“Ánúqÿ{~' š^8j<‡ZÝ?«yd%Û(2@â/#_ м°G'ÜȾ›l×Ü2,™†4ds I\Ô=÷òð½N"ÀƒAø¶oÅ‘ØòD¢@€‘pnXjRú-…‚_'=Ø[Û–Å—úJ]œÎµs2-gdÙà¼Çk4Ÿ¾?Pû4Vi$ý?e]-M5РØ4”k›vd,‘ÉÍ¿ }eE$˜ŒZ5núü7ü._: Xjܤ¿.‰ú$Ûø»!!NLô8kŒ{6[æQ°\JïÆ…ì0WLtî.ï·B‘â16§çP½¼X«®±èO¦YXö!‚F*ââ¿‘G+s¢„NÓÜ)µôÿ¦5›Á¾KÄÀþgØ¿½p[È9>ãQ¨a»\ U ø„mIH=Œ»’ÒCr¬Û!Ül%ÕÜt°ô{`$«ŸôNÝH‡o"€5ŽöI©7*•ž‹ó"8!¯ÚíU`j©©Ûö|Ar^€Émõé‰Ôùh¦S'6vÖcIêãN 3)2“AƒÊ÷Z~0D‰Ì©„(¯íU˜-Lå\µŒV²‰t]b°ltÐ1¹ÀŽÄbßüÂâo¿Æ0¾«®g÷:5^Œ< âþþ#¡+A1·¸ ïepWªÐç?IŠ·Sx’Nu¶G0S-?PÁ]žk!ˆÔ£FÄ’’QW¢›jÑBƼ>S'\¹ ELl¬ë¶Ø `šôÙ¡NB‹X-•£žvì ™×²Ðí‘ÃMeøâ!›ÅÊOQ[û¥OA²ýÜ2öRØ·q›’÷E“ g– DãnE(ðá}VÖA¾Mú?º%M߸À†Vdt!Ñ:’˜I¼feŸpÜÅÞ%®¥B¼·=·ê_^‡…§°Ù{•{›¡DÊ&…ó¤®0¹ykFouíO ïÉØ”àÅ„U0¿µmxðøG |ÙJ_…"”xûÒ´¿Îz»ÛÙJÇ>ïÎRÀ c1E 'u½w@Â-»jßì·¢†¸ûÖlùHÓýÖ³Ò«¬¯Ò~‘;Ð(R¯a€#Kœ€ˆì]éÒ³kŠ©š|[¢UÙ³Ô× ¢FŒîÇcS`¾Mn§èÉï7ªã¹°%FæR®Dhꉖ1æŠÿÚ5Å/vµ2ÃxÿÚÅnÌryžr»ä¬SÔ˜Œ@}Y:Uû¡Kp€®UÀN/ 9[HIÉt&<8>««ÁÝtБ! CÇw‹egBrÓ2±”½ÜÐd²ßÝoUNÊœö,ŽYÞà«ÈÉ¿vµþH½»:…Ó» MtÛ¥,Æ‹J-Šö2ööò]м[¶Z¹`áë ì,?Tæ ¡–À·;æV¡@Æ÷O1ŒÆâ=÷¹Ìí™cG\ÍùÔ|­éûO‘‹Ü¶í·ÔÍ.m\º¨u,…°e`lmÛ5JÁéÅëù˜h«;³Ÿ£ô”F´¸aôô43æfÎ9ŠÂ“ o*S¥!bôäYH9Dìë)÷5ÂR¨t“”Øg/¥£ŽáGôš OæJ˜ G‚d`w5íýÖÀ(] eaÆcC6Š«Mõf}טü›œ\|  úŸÌ;‹Œ%æÑê°ÍÎ]H’ê €÷ª3¶v£zT`vÀm!æý8Ëï•ð IŒÞB–ˆÐŸúF243«ZúÖá+‡“-â37{©£kÔg$"Áþ JS°¡s“yܼó’$|QB¥¯/¶,¦aðTˆ’)¬ÍÝ6{ôNÔ`?4£¨rë:g¡#©ômMG rI6~BQ=é›q¬©U’!¯žï‘ñ`Y÷WŸ¾È¦¨5Ùe²ò EX¡±ÌçØ‹¬Ô —|?êÚÜ΂ºmf°ùöéæà3r^CYcH‚?•Ÿœ=ñLØBM3i}\0óX[þtމê_ Ð8ø«f]ÏeGÌß¾¦ŽÈ´ß蚪+|¢¡íµ!~Ä¿ªV¼„{ÅÖ•ÝÊKí"¾ÚÐnä rׇ>26á%ßK3Er¹UiBWúTê²I-Z.cõ˜ìLFýÍS8tGÊßmm?ø†J*|–ô\0¯ÿ!l€ßMïpüäÏ “¡6}ÖÐe ¹Ïa®ÎR"Ý|ÝU*é‹B×îwò·aMö°À•9æ‹‘·È+@Hï¬0Ã!'4z=¬ ”1|³Œàÿî‚&Ü‘PíNèL8+$ïÎoæõ£ÌóAb`&`¡Y¹È±EŸœ¸nš±ÒÒcf"Ý9Yæÿ«éÇ.-añ¡‰2¤#it¾MSNçåœ}YEÍt®¡y+. ]ˆ==Wø]e¨.'Áà¨ECëfàú¨4å9¬Çò¿9ÏßÎÊKŠ,¸¨®ZÎý„+ìæcvTdŸf‹¤jJ{M½î¼åÈ«y͉¶C*·œÉÎÞ.Óóæ³L2Ó 2Š «¹Ÿ­Sºz|»ß·K×[ ~¢ø ÞM€Ú|ß0@ÇÝ‘5&¹lgkÔÿoÝü_oÓ¼â=F¹kÞS]UPìvœ'pò玆;2vêA†¥ž ñ·ëcÅÜÄE¤ŒbH Q•€ð±~>„ªÍqÁ8Æ9²³¿$“ù(Ü §L×Iöö$§pR\îÿ ì`~ùί2ƒƒ—V«´h7ÇšÒ:$ç½U¥$I,½;&¯]›WÂx“šCá6·¨/ùÞ€è^»_ÈtkèR>˜CphuR[mƒì‰fzgbo •Æ$åW=ÐWùœ*bâ;ó2—Õ£xUCwTˆlY¨8¢ y F6+ð©`Ѱg-­pòê‚¶þäœ]WItY¤D,{:±MwS扨†Ú~^&á‰îlšœ½yuHPD÷½j+‡q¡îÇÅBÌäšÚ½úÊeÛÌëÙˆÄ€ŠžÑåìRpkÕarêÈ{æk?÷®‡Ekšpýâ$Ý…&ÙØ5R7*Wâ[Qø¥¾Áê¶›_OüJa5°?¥Å\%2„1„D{Z|ºt¼ ÐpÑöOœ™· ”.ʇĆ Íá¥ï»û«w5_[ëû;¼í9§ä%v—û­,4ñ)ë % ¯Ë8—Ä(iM|Â Š¦ã'àOú6׊¿ëƒÖ–ö†#_è.ðlè4qæ/€ëë²ô`7.²~Sý´¾—Ð"-.±Iå/BÑ‚–ãL¶ÀÁAÎõ[qLjFy[e<Ƴ|¯{û¹ráᆂZØé±]lÉÈB÷ÄöŽî“Œ@U7¦”%îÅeõABVYŸƒ÷®»·œnÔA~ቷáÉB@Z©ãCŸ´K¡Û¾„-Ÿ*ã.9QmÓ+†îü a0OZµ«­€ÔS{¶ì¹(¶1Ô /Î"µ÷ûq¿ ½IwˆY¾þþ(ëz¦}1µƒ¹ž?®¾Bé-‡n:¹Jþ0&`Ê]FÐJÙšìÒx܃E>Ðlô´¤k+ Æx ÌCÆø;yL UúÎ­Ž E¬ˆfƒ@ Cɼµè¾„ĺžïK’Ý7ÏÀ¬kDë90£ù+Xޤ§ÁówT™â(ŸŠ×(hXñbÛUUU‚$²‘U!K78a§ëÔ0Üá£`¥•ïîmŒå'§[FO$Äîb×ÀëIØIôª³*f™!Ý¿ñÐ¥vÁþ£QQ'Ç”Œ3°Ønð7o•JÔ1Ÿ>k¼ö ƒ\YŒN¢¦ãç¡w€SI4®4ÉT¼Ä!ps) ºÇ5®¤¤@c˜ÿ «´ô¼¾’‰ˆ¥ÜpO}EöÙAUeÈ0ÇR¶¸E¡P†ß±4p ³IÊD\ß4h6Æô#öØîèú û‹Vºoú'¸%‹®®„a[+¦¶ˆ}©bâèiÝ×Pô€ŠÔ/+3¾žÁºU_ ^>Ís¨‡yQݘpü`]¡Ãœq6®~Ìž?~âDmÍ\¦MÑ)”È0°YÞ;¯}æþ——ëi»È&5ÕÀ€ÜÙØlŠGT… 3Ú8æ2 ¬ìÂí#º¯âV‹?^ÐÆ1 ÿR“jóh„i¦bóÂÈw.4æGî”Ê€ È…ÆŸã>·wºJÍ´ UÍu~Ûm /“¿Ñ"ÂFüÉô»JÛYÃb’eBc J(_‘¯¦<6î\ ¨¬:pÎL™¹CÈ®ÆM¦W<šð‹àÖüP¾ ìÇßÝ’G¯¡™›+ùô%Üßtƒð@] svôÑcÒ—î·¥6qgLì~’@†bI*!h!7ÎÃ¥DM£Xm\|ghIÈ5Ç@Úèa(V¼ºb[^¼T¹¥S£+¦4Ú=øØŸŠüzÝÑöK(ˆ´FÂi°½íogàVÌ~=õÉ^ÐÏIݵ‘?´6HFl£˜ÝʆK(½äÊÝB»\™6„½-M!(ìÿÈ"Žkâ .½Ñ”­Ê§ÂOœã{Ð[U•'¼í`$nDðiòÀq2g7¥çÅ›Qlî3íÐy'¢ÿch(`k–بA„ ‚DòÔŒ"§à?—tðœÇ öIÐäGKt3³×@—†+.ö³X43+ÜYɱó£Ó6Žyãc&¾âœµ4ĵa‹u9M=X¸õµÈÝ@S o=Çÿ˜†ÎMÕ­‹‡Ãäú唞­WÞÛÅæZáÞ'5†uÐýM85C‡\HúÄN!à¥^ΈÇ5\fmWuΜ>×¢´úF –=%#Ø7étïwÓ€”,¨™6ϱ,³€¢3™’WMyž)ì£Új³IQuë){%É¢’’&ÞzLë]¶aqeµæÏ½1» 0a‡ð'håqY½UÓ nS—À.C…õ ÍeJúùOX”r‘™M'óD& ùMeµÎþwÍž ¯õꉌ#V§WG /Šôìbvå„Ã'»»KÁÊ<›Ål”4ÚQ äþÈ¢ý›ÃM6qr9¾«cI¬<×5‰Ih­Û¯¤,‡^¡örʨ¶ˆpQ§}K”/±z$fAòëg¸ÿ{æµÈWöâoÎ gºóŠ|ÍD½rJevš½83úêŒä;˜ðþ[ôTÏ·`ꮨX¶IæþƒÁyßµ¡—\qV ±Q ¹3!1Ь›¸rY¶(®5“uO»!GzÑþÕÌΓO²1ÝAÁrI=e#”ÆÛæ·_Mþ<Ë1Û‰é²Óó÷DZ`ÛK¾F˜ ©ÖêcÇ*‹øYè3S!G×_–ÕýaÇW»©24Ë¢õ = ¸¡©Ë9Xþ¡3N…I+°¼Ò¸a—wç³a=˜_² |#Îûau‹ö¬¸‘h,Î\šsœD»³ŽÁÁef.… ¨³3Pí%Nnõ’K+qjù™%&á*¤Rý@èÛpÑ?È—÷ÔFÎɧœBº)=»µA¯`Ä£ÐÞ‰á÷¥­•÷íÝùë4ìFSÊjæt_Aì:ºÎÐöiÎHcZŸzä4S0 övJÛŸ¥Û$`ÃY.»OäŸ ÏR™/¡k½íBfåc9óľA²ŸÒ/Ê×£3¦ë’Ÿ@œÕ´*«·öüòão”ó¡e;˜{ æ“kh/U²úé¹p³;,°33‡¨}Û±IŒÚ ÊAÀü•ßÒ!Ћm4fÕ¥|xѲŒW _Þ*I 7ðf(¹_ã’äÈÅ¿íMÞŠûübö¹ArUÂù §È¾m€8þÝ…üޤ§7H«UV}v¿†ÅëÞâ}—RÐ˰BÖñ ÓEªß|õ=X¡—µé}éןÒG(Å÷byî¥htfóUxaí‘B}Õ&ÙÔ’6ﬢ&'I êdßmiÄE·•z„™GÇöýºµNÃ~BþªÈ6¡Œ«æÿZ-¼›1·ËÉï>¤`[3r¤£Wÿþ)§…Jjv¾w{R9RŸ ¨¥Ð‚-ª•Ò-•"áÍÑëqwsç+@…!ÁÙˆ*Ân¦ªøá3¥©¼É çßâߌ_„×aöH¹éÔß+Wï4-fw <“Nÿj­oÉ6q°²» }J­—Wk.|¢]2Ï Ô×øþ^êH‚Ö ü!O-—”Ì-djœÁÆ(cr¥ô0y’]ö)Ió?Ëvïjé·KbMëã[E^‰›SÆV^äqò7æt$~õ°ÇLJütà'£ñÔåd~bÓ&Ò†û¬§¥Ü'´ÈcÓ˜‡¢)ëÊPÕµ_ñI‚»„U˜Ôß0oAí|Ù:ì“XF¼ÖV”†{ ÷1ùLð˜nž„ؼ%± rzüV¡nÝà¡ñæŒê­ˆædqï“çîÜýÇR·qÚ_xæScŸÉn´1ôªe¹é;TE2WçyaK•¼”ŸqT0ÓÍ­1˜…`Í{ ŠØÖ§i­À~©ߊGí‰_\#\ˆޢ˘Ü m’;,‡ÅrÇF}ÏŽžà0k£=¢bÎŒBm«*ë±¶9`ý5žŒ6|Úz4ÇOä¯QTÖèµÜƒ(qÕšj‘šùYuXRQó¼X-”Ñl>:Ò'ÆåF uÿvý‹V>"ÔäžéÊuì9\]´(§Õ ¨U½º ý)ñÕ®#‡½¡Àu‘ì£*)rOFFd` ¢dU‰vóGm9óÐó]Mò±y ™¦%FB³80:¢Ã¶fôs’aú§ ¡Ùû)¨èMIkÐÆ}£Uóù£ÚL¸{ r{„gZ9c2ÎNBÅⲓQÏæÆ±Œ:ß. ‰WŽÒç6Ü}¹‹Îs³Õ%ÝßG–í¾ï‚t„• ®X;>€é[mVÏÑÇ  KV©ºìºúýôþfzÐuñט¢£÷ƒÂJÊ€ƒÉ¬ëöiêìe²Ø¾m×^RO—~@Ë®Â?³4²i$Âã­ýD3yIŠn8¨QM"E©`@j&ø@^q¢ók1^‚Ý¿"lI=æZfôGi-Œ²æ“pIêÑ›ÈÅ/&£fwœž«ÏUoƒÖKÁ­ÇõPÓ S: ’¸Sˆ¢ž$äÏÝ7wÑ*$pœ•û½kâáH˾‹—{y®ôeŠ˜ì|XÞ0¶Júpσ ¦ õ>¥°ÐJZfFëâç­²ìR¨}öè#Â0¹üMI¸Lïwö%Žê’yXI÷q?Ôt“²0 âtÿŸ[§`£PÐVÚ b€Æ»¿7¬Q/ˆ°Åx Íýɼ‘›ŠÑÃÅ%‚Gå°Þ[³ÌŽn)ŠÔy398“–ðªÞ s…JÔŸé$uaß(´ÀRèØF›{î¯hÙ- ·‰ÜìUê–r–c_ èŸ09¥µüŸd¦„‰Q£ [çO°?í¨ûÒ:aî971ê.­¦T>U¥Þ\—¸ KB.€¯h|Ò«ÌD)wr¶¡{‹¼þ`E'{¬™ É?ijâÚûVóÝ= Ål£'äà]Œñ%£'Â+¶is¿òy#qªÈwë†ÆÔ?£=.œ§Ý÷¾°i±êwÎ35³o’B7Ž:Ê“E©™¬ÎºJÂwùŠDµfö^ ’-LŠ’o%VZѾÌÜqèG}Ã? ÖX»ß)6 ù©0òËgðÀB.®ÄÝ Ìÿ ‹|Ö5Øð-\ÁÜÙõž_Ì oËIzðl ɪ¤ôµ§RÓîu—ÏZú›Ë5¸~ µ¦©ÇfRC ‘¶!IÞ„/Éç zŠg䄆°»Ô‚>7°vL²#/3‹qWfœ„g%ƒâÅÊF$dn1ùÅE_¬NOv˜…³LùªÃ™ºxy§XmÆ *ÔOÀ}5By@CkÆ•œø¤öD žAŽf÷E6Ð(µvÊ?>î F; °´Áçžf*äo¡Óô§  HI=`(Ui{ùÑ2ê·Ü±Ä5´ô¶ÕÖwó_-v-0vG/j‡X]߬¡ˆލbTû¢Iw€‚q™Õ:¬?œ ÀÞ³Gà#(Ms Ö(§¼·;’ìëí™2[õWÉšC&-DÃf µà’N:–½pGÑ{@=§qk¶‚„LÎ&ÛûÁ(™/Íݺæ¹TNÒ Éŧ»p{Þ+ô³.<ç„âÞW¬RaÏoª…?Ñ l¦ Ôÿ &å Fá/þûgþŽp¤\s1*±g¬œASç{žoFH¿Zê=î„ï쪅¬›Aö Íb-Ѝa±>Ÿ%Š77 a Õ¾ƒb¢›ä߈å ô;Ñ£ ’–,ÇymÓ2bð¶I[ Qß#áÜ]ÓÕ{Àîüí‡uòRY÷R÷M¯Û’ðF\.³¯%ùZV"u@T_ã¾¢ûÍÁµ 2GÇ3_Þ7,ß5>ÇI©]üêYõ¢Ï{œ&€7;ßQæ7"†tœ?[rLìû@‘¹²t«,ý8È´|pÝ-±1WúÇ£„l)ŒÕ|^}\Ê 0Ž#»i;a*Kˆ7ôcZŒòÿêái¡¤Õ/bfçÏs†¾Ø*6cMèeck<´03àq艩4s >‚%u¥&Ú7Ú-0àt¼£€fÑÉôI<€“È`œL<Ê~=¥Î¾-ùÚƒï-%dtåô[oX²¯ÐX‘ñE6„.)lÐ?/z×? ]LiPæ¢ †_EjPnnLºÇ­v“ñH;e‹1+sãA÷f]›×h¨dVbáçͧ‘ÿ¿ÁéRÂ®Š»ø~Nd³ñ4¤âC·!×!$|£{/Ã*´ÂàUa³¿’¡Oá¹â ¬€õd>èõž‰vdå3 C¯ç]ÑB½Ëó\ 1Ï:ŠOíÆÜpšeó{b÷Ì@tÏ4j®ñë¥6ô˜9 òÿZâæ;Gz”ÙYÄSAæÉë­A¨‹¬t/?ÿö©DõKIHÁãïJ½!àpÝêñ/eñXŠ}º= ­°J_[FHÔæc7™Íl‰ûq ʵGL¢t-³ñG˜†[r†ï¨ñ|ê"[K³%l 5óa°E,ášl]Õ‡$Cˆr?3¼|`nJF={)ì+D„Yq'Y!žKmÞáÒÊ.2jÙ“½˜]ØÊ@Öí}B!Énœ $‡ñ ¸Ë WsÇÊB&•†ÿš9\\ô2ÍðLU7vÕrB#ão“ RŸš‚Bz›ß›ÁL”Ù­é¼ã½É)ŽNäxê^U­rF®ú+]¶$F´ ‡>žŠÜçªiHÅbêí'íðôê‡Þ0S pó&ÒY«EÓf ‡-Ó»™riÔH!*?eY³óH¢K£¡Ó/\zÅÔUÒÔ/EO7øY‡EsÄ ¼_Ö¤äÞuî\à-íXŒ°þ»Ÿ”Œ±qñN·,óëÊgð.P'¯,°iŽs^­ø)Ð56dS z%ñ«oÕDáB¯†\$ ²M‚EÅºŽæŒ›=|‰}²¤vOL[Õö»ó²™ xÄnÏtÜvýD/ªM%»â"-¿hH¡ÛÜ J3[{”:0¶Ùåh‹±ávÁ­â@¨ù÷]Ê{ññ ôy 9Þ¯åôÈ}D,7Z`ÄÊøx¦AEii%X­ÈÜa¹~ÔQÃ?¾» ¹ÅŒfÂÉÃjõŒ9#œÁ÷‹©¸ÉþP8e·1+†FÔVG¦þ}þ•ç?›oV'…0î×Ù´7NUL`³¥ìncúŒÃŒˆ îíâ~ÀB˜š9¼w20˰YÏHó×fŽçäcü•b“ð9‘+m Êd÷5¤Mh Öñ_8`‡ZV`7¿¨FÄ‚wíCRå¹Ñb3¬*Ââ M[`H.P'€»ì>Ó‰‘!‘ F[l!žO$0]~…¦ Žü(½œÑ{ÎH Hn& pö†çSœùï*9Ç¿÷YèP›Qñ>®PN§–,”nöŸÈ”ƒkª˃ỷä+NZ* à5Î1i-O©CÍ8DfûI',Çú“¨´«¡„’3‰Ã Ý@UVíîBæ3ÍèZˆÞ`ù)™ù1QX˜µ*Ê]øa¤““qR‰µÍ­‚þJ=¾äÄ嘉Ó®rMš·QïÊç3És¤ªÊ£që‘èYÅ2[ù&f«{뜾C´Ìñ™:~<D±Îl¾ñkIšDY‡Ž;,Uæ¦ÅaÉZ3Ãf(Új+)vØãŸ‚ÿËʤKó9qÙVô)pàë³…óÕg„Àש8²:¦ÝmZÁ‡0äöÀO•tz),e";hì¹@Ù•o§äjÏ’ 9W1ªR öíhQó d¶.õ0ßÎZ\™—(Z—ðeÜ9|Ẏi­dÐõk¥„Ð~ x ÷Òña5J'§í¯»WKÑn ¿îÀÂûA+1¸gÑ!œêg$$θfKd§*nÁ÷¡8“‡.:åS–X‹÷tkY6¾_Ƭ è¿=WTC ;ÿ¸ï. ù´ˆÖЃÎÉ*kÇ7Eh€ˆjX q “Äk¥O1ŽË7ÖiÄ¡‘Uá%ÅjúHÅ›án &Áʼn|¾Ubd8Y‘ > ËdûØßÿ ë¶é2-ð53ÞIm‘jØÆ@°Pq²ýO*&îÕ¥ËÁø©‘ªànm¾ˆüÑ`EX»[ðT5H„¶/1¯l0×Äƪ1ÂÆ4ÇRÒ\8Æ' Ëçø×¾qwµ3<ìÌ÷gšUKõÉÆžÉõ÷Õdº#sfJ8©–Ó.óv¸Õ#¦‹_Xmœ*®uò2ξ¨{ ¿¤×hGfÖ½ÞšÞV·ß&kÛ1Æ æuXqïì@ð»·]pEgvÓ›%HÈ‘YÏ]”Á%‘ލð­BÆÓšØ$µY¹÷ùáËa¡³jÿͿ¡1n[uôÕ]!lhsAþГ¸œŽ”œó`%¢A0«\ÓDy›ÃÓéÿ_ç¢w-ÃÕúýWêú“Íï8EKyEï~Ïy ¯Ú…âѦósËd9 ‘ò+YZäÑKë !Ÿnsœãò„gøÁõzIŠ*~M==Œ:;Uɦ“ÂÈCIr¸KÝBpÖ¥½-µ`rÑæ€˜LVõÒÓÕŠi.ÂmŽ 9°ÎZ§?H6OoÆœ~E©/Ð Ø9#Jþ£„……âztÊ™IZVlÒ½r m¢s‹ÆÁf}-xBžÐê‰áåI­ö-²þœPž¿ ÚšåÈK(lfàQ »£‰Ú4ú•ЈñˆÓ‘Y¦{œÆNÕ‡spK¯f—À%š§í¼î1`_é}Ô ì¡¡££w9;UIÀ¹mvBò#qÎU¨¶.“ÙØY‚6\„€·?ÙR(ƒGé+—ÌyÊß´ØpwÌó˜í® ”6F8ËU¸U¿ÝG½°PQš¸,×›*g}žQ i]) ê,ÏãWŒú2»ßæ‡öá›þ²½ždkw.cšOaëÈÍþý1%g\ÜûƒDJ–N²åQ㥠‘@ ?„<¦xnë+M[î˜z§¢à6=*ŠÓ»—Fù¨9úŒz1¸Å^ŒI»8U¼4Ì^éÄvC¨šAŸã=unÆôL6cïi‡Þ1f¶{ÝÄ»‚\²¼‘¥‘B¦èÏ/OÙÇCaªDÝ·e©¹gï4ømíhc¨èDÚì/3A;[ð]þWå$m[˜G;wÛ˜OO›I–d…ʪ:ñi‹pdå°hÅB%£ÜЙa±ê´Mæêüè”!¯‚4Ôö2媊@?ò~7Äî0u“¼$ ë€å=l&äÒ)×-ÜÖé1€%Ê{uÑO$âoÌò˜ô¦²Öᇄ›‰ÅÛ¾µM«RÞîX%Ú”Ö­©)¢»h5QWòe™‚êeyÎà¡{Dl–­©Ä'þË…ÉÉ{R“V=QË)1…p¤K¥”MÄ];œŸË„0§¥¹*ïvvàQñÚ‘æ¶‘"1.zŸW[(-›LDG7*‚iÀ¨ñü¢ü•8•8ÌÈ"M-äþ[þòï8pŽó~TŒè·ùdá¹¶•tÙeF Óºw¯ý/Ý’+…5B7Žx˜Àå[‹Uu('“½É³€´2Vª9áæô+Kýõ!ƒ'š§ïTäffWô“`qÏíḙೈB[º§ZØNBi£øC® í,‡yZm;Ä_¯ˆëΉ-\JMªBCaÀYJ¯1i¼Æ÷䆒8Îþ6èÿåhaÔ´f¬Ew{Lx`8—œ;õ ¢ˆël7tº“hµß²ˆ/4ßNZã¡3ן­XÂô 3[N!;®ØUí"t‰ ÞQûÈg¡ëí™,ô_×ÿ{½Vý}õ¡ÿ tÆ…‹¸xwò=Ô::6l »,ø|äŠmú²¦¼4kÜû)†" ˆl;È M’»y¶~ÒDaöw(Ê(ãÌ:ùZïO¹²–Ý™ZFxT Œ¤¼•³J™Ð`²‰¢ÌˆLh ;ûÍ™yÁ`áüáö³jU“PÄ;mNs Ó`Dްçjb_Ò³oã]abHï3mË?»p¸é`<¹§ŸZbß8ízdx¥iÄAaÿC®zLÔ ú5#%ØÂa97k Xuûóm¯¸&ù3r&„Œ×½%씃Dû˜%ÁÂÛzÖ ¤ï†"Üz¨.ÇËÚ>=]Q§Ø)q˲ÕpS-_rW¶Â+Rïü™@ÎÉd—cŽØ,ˆÓ CÂtò?,±x·;ÐëÞóÖñ‡®ke|¢~5 žÓLç/4´+'„·¹ÏìôANÉÕxÆAÐ#Õ©àB‘r:9§ ³¿ÇŠ"¥ïÑÜçî®]O.ƒdå"Êà¿“KÀ¥ ÈêF|Ràhõ#A ÐÒîc˜´`OéŽ Q¦ ·vyÊ ÑÒ!‰ƒ¼AnçJcËÿDÖìÔû¡õ¢oŒ¥’âIºùQù@$®Òtü‰€ È}õŠ‹UÖVaçúñ:–ΞëY¡>*Ìuwоm÷Èÿ[b ¾aWì=ªGßdzß+ʯ„IÝ(í;6Sùê½áK ܉ݔ-ËÀ Å2ÓpµpÕìÎ5‚Ü´ÍÙèu7Þþ;ι8Ìu}W÷&ŒÞ=CÕ¡?ÔÛÑñqözR_”†W]Â88~ ¤§]ÇV0EÛ¯¼ÈÀ 9¦ÍýÅïr TýJ'˜®À`b/òI{œr;äÁM©5Fˆ3Û{“éiºÙmìçmǦ=ÅK‹Åœ èÉéÖ¦CM×ðÊÔ\{°ùýyºdâå`ø}ÂÛb®šk0ìÔ m¸H· q¾TrF"BÔ^J”¾Î'DB滌Þ}ÄÄj Vc¢uµ<@4Ͳ–¢hHkÀK¼î1ob$Pÿ`Çץə‰•&A«w0IÍå1”öŸdPà“Éð‰âïmòþ=uݰ‚AØ=óe†4ôÌúAäó†t-¶SíP?„°ô/û PwJÚB]Î51•*l#7­Ÿ ®ÊÔÔquSÖƒ}ôÿ=M[ÎA—¢URDÑúëržBðšK8¬É–) ”+…,ì`$óŸüm,äNÿah“†D!£ñXPt÷Ód‹ü)6¾V=µ5™Ù–Ò39 #“ `3^!ÿôóá“évÛ  Ü2RŽ¢µ›ó.%l&*oôrœ·†^-}üÁ=eÍ;–/¾ÚíI ‚™_üüBEÇ \®ŸÔ8³ûõ/^Îf¯@ñûçyÚdµÓá¬2+¦-qª~µ@`aøöT*?/OB2Ö“õIP09á|²Êá(ýéP›EÍÔ­W¹Ö„4aµ’ʦ¬ðT ]KÖVˆ_Ï~s•R¸×xID—¬#b®—oSœûšgRut9K¢#“ ›«a£îÙafÐÖ‡„·¶íêÕ[7YºËÆ7Ð\ó9°!V§˜,Ü™‚ñŠB6€G­Š¶ôÄÔør}9I^äímL:¨"Žá`S´2Û’ûM ‹Qo¢ÔÛîýÿÂ37i+Œß‹éëÑRº.šq?(eÞ~î>¯šPSØ7mBÃ{†|ÒÌÄ ¬]Â(X^ÙŽù&€¥~®OP ?íxU¬KW rýÄše1Œ ö€Æ«™â|rÙðž&¬ãU¼¾¼¸˜ïÀ€njp·ˆÃÒå®Bô!Øœº†£ï·¾~%­ïرH,³‚4ãìŸë•q´Å”£w)É^n®¿6%›½<=8Kë`dTöÀ\Fó ×ÛKsK\ÒU7Û`ªÇ¸7Zi3U‘ýj4„ê¼Ò14ä(}w 6Ôˆž€N^Ðid$Þ0©Üø4^;Ña œå„÷¢æ©Já衹ô²¤A»&[ÜIcÎÅ%ÐÚá€Ãb8ÉV%ö H£Œoóª}07O ë<‰êö‹³8ZVHD¿1ÌF5ZöšGÄ=Úǡڽ!‰[5ŽáV±œ´ø`ÑÐwx>CÎXÍã'ΚÔ⺠>TÉV9Y:ü»Årº|BÇ9ïÄ+Ùd»-Îã•퀘úH—ÂírXôJv¬˜Ãˆïÿ²&J™F›Q?Åû9ˆA:©ïù#“Í)KöóÔ“)WÄ@F¤¦u7ðÓ~—^ûz@…à¶§Q ‡&??rŸP鯯n‚¼ â |~z¡ðÀÀ‹ÑI«V$€…®a‹9}dÕÇTcX’ß82„ÎýZlù^ÖdºôãP3ŽÃYöÛD æsöÉ4îáx²yvR¡R·GÈå 2°…è‡üäØÂ,ÌUÂ"ªN­òˆÁõº†O­‚Àó£K Œ™'‚rÓ d¢óuE¥YŸây°R´¯/E¾åYâ”íã]]C¶» 86» ;@ÈÉtJ$#ɤ?¤¶gtV¾L†‹–2Ú¶â t%"^fÐ íG¥1ó£°"Ÿ¶Î?‹Ÿ¦t"S5Ðå'4¼›ÊíëX.Î>~vO{ €Ê”3Ñ$ÁkYÂí\oܽiTÿé”’]GNüV´À#)#ÝY&‹ËõN{ŽŒÑï‰GžBuÝò%Š6qõ |À!ÎhC` ÙH6¶.ÖnÚ½Ê×* ø–áâ÷¨F¦š#Ìí•ä±ó–,ócpÛç²²™28P§hK‹ÔChAÝfË3sJ×P*ìO‚ ç"pe ea`¢DÝú«ãÉò|ªèˆ_–×Ò‚¤e ™ñË ¢ìÓ ؆ÐÙYƒ0Wgà‘öŒH9×å É£\Mï°º>Ïú¸xÍD-qÛ+·²²`¯Ýd“O‚öu™[®ÏD•ðç¹ß“á.Ã3TéIÙo‡\âs‹gƒ•÷»]Yè" åß:{*ÃêÍÚðÆ-åÐ(ƺ鈩‘¬×\ïß‘ Õϯ!›1*å#l Gw~ïŽC;J…Wöº[Š)Ï–1‚‹4½1r€îZƒÀ “½¢HHí/>õ™L£tô¤”Æ„õã©^5 Ìã£Ù'nü‰sÌTµƒgÕä©‚5*›A—­¡”z4|97¡ñI$Äl³¬áÙOo¯“$o¹/A]d—vLúãú´M˜3ï-˜fæX>jÜOž"Ò—©š˜1 ˆêÜiHóÔ0‘¤ixV'Å®/¢?@í#®]ÛjÏþ¾Az„VÄèQ-†wYð‘šqrâ;\ŒSÃéÙºŒ¨~dãÝdÂA¸=oÊfwЀáõµ¦³,¼é›ºÌØÖ˜Ò·Åê–{ŒbÚ c3wø86°µç†*Ñr>Œ¼>³{På6À¯÷7FÛûò%ž>Ù‰kúa’[mW‰ªÛažRTÈQ¤©¦Ñ õC´wpÎ*_»¨l/m•UÜ<èòjŠx“*Ý‹ä1xì×Ûçó…ØlLá8@ ³l s½Û7 œ¦^„ÌR¢è“@[=JZÑ;’yi$º·îò+0§\aúO¯ß Í•—ø|ûÞ9/ÍØ£©^Jt¼b®"fzWtÉ*&B¢g{$aE9 Ó|F¥ÖfPǧ%Ãå„v…ú2G×Ü@÷M áU'C×%Ü£O•H¹º¡P]€ ´}qdË _87ηգ%‚órª 2TUn7W5Šl[¯Ew¾ûñT˜ÇÛMÓÚkpƒP씆fˆŸ%.‚W©yO.T"Kƒ·Ôõš«Šœ"­h*‘µïIÿéSpš3;É%VpüDWE˜J¹üB'¼?Íó›3mÙ6 â¦O,ü».óc÷2iÓb×á/ehiG”-é,€Šsœ™7[ðk<ÑÓ¾ÏeW„✢ÆÒõ…¡âLkc±>—AIa]*Ä`ÝC•Á *ø¿“:íÏÑGRáÛV}Þ¢QM"rËBމ]z‰ÓX@t×BbAy^ÁÓã©\ã4†q v½O½…ºC3Ëû°%ƒT¦«dƒðfrËCåèP!–>éþ¡Ðë?JIǦâÍ ºÌùîV Yq&sÂöƒ Þ7ª‚Q¶’Ê}¤]ºé|ºEˆ¯)E¹z#2m¿ócƒÏe`›¿\Òq¾·CÀÍc }b÷ºõÚr#‚üÿú\]ý¸òæ&:Ü5€§½;%Þ+±LÖ L¡Ñ!Žž£’'ræ |5—Øp_‰ŽÏíÿÀFt¯Îë¼oÃS;2ÔWv‹UéôKªÁHc…ãU¢3{Óï® AGy…¥AL³S…»Žw@‰”¨‡“yPŒeûveζST£;KÐø.—×½‰1^K®R‰ˆ-SsfñY¯fxé’Sd¿à; ;v3kÜve=Ó¬¹6ˆÁ+ÑÐÕêŸ$Ѝþæ¡´œ¿²ýØ\„-ûFÖç\nçf¶îêƒðµØúHì霵çw&L‘ È1HÊœi‹üýbÛh6%g)ñ²(p'Í®~Fš|+’×*7X¸Û€J(€S ÷Ƀ‰3×cúlë ¶ûÓ}n“pê$3íýïí€PņE ÙµjT0çÉ”÷µ´LKN®9Ò±‚hǾìÇ=:nN>òïaæí`³QÌ9ãÙÊÅëN˯qúíZë®è»âÖ ^<ÀdP©Šaƒ¬ø²É«l3¥_2ãÔÓ^F¯$b‘ŸäæÜ¢bT¸â-Kø¹õLuhf¡¤bþðô`çÂzkß‘¤A.rÞÍ m·|¬" Vƒ½8\ûó[$5É- x1‹ŽjÈqôgGÿ€€qlTòá~~×ïÓéÛ ¾KER Âúü?×oßµùïØ3.ë†(¿=“û@»6„NÛt‰5®J¨Åyþ^wJ°"âe Öþ›ˆ—¡T•è¬&„¸^D¿ß!ꜫ±¹> ¾É\ö#8þÚ·þµžE©>lýÔaŵqÆe+1¥WÑT¦Mvk›¾ Ö›ª€“Eœ{+µ,l—£žQL£ÖÍ•®s–HòµÆÃë¾å]É„›)õÕÔ^’VcCI°j‹[8®â™Cë¹L*6 3·—Æàö‹ÝÓ~9Ëu— Ä4ryHd¯º»¡<)ð|¯‡§É m P\L2lñ‘–š·éëªùŽ»Ð9€BPÐuå𦌻Æ'SÓ÷üZâ¸ÚyI«ˆ” endstream endobj 59 0 obj 20336 endobj 60 0 obj << /Name /Im7 /Type /XObject /Length 61 0 R /Filter /FlateDecode /Subtype /Image /Width 1314 /Height 113 /BitsPerComponent 8 /ColorSpace [/ICCBased 2 0 R] >> stream O 6Vm׫„§)£ÞeE4vê§ÍR‹ o«°ás~˜n5:QåÐÃðNmþX4¯¹yç]íY“ë»ö6Ž»Y²ËÈÔM¿Ybu»`‰çÏgÅS‹xé·Y ˜SX'yÒüÉËÕ°Ñ [Qh/ÑÐàÐþÖ¥*¿ºgÉþ,ÇÔœÞF‰SÙ-·ŒGéŸkº~k+5¨ûJq×AXCb ôĦSRA¶*ÎÅí£kN|cïˆyŒŒ±›Ž8|týW:FY¥‚ÒË©·¤¯®ì' ¶R,¦5:ÓÓ"/íà1t™Ó–v÷GÔKeïú’ÐòáÁp ¥ÙÎBë¬ð S:ëþ±î~LA•x*Ùgfù“¨ˆl›žQmõ¢þ³óÝýÊ»žÿ¨é·r}ó¿P½=InÈÈéM#.[ýÕ†ºF_\•cgÓ»)5#OÏ} v Ó¢Li§î ww‡ÒpÅ6ò6í’¤+ÊDÀ%u¿!þ˜whÉ)ézœÀæáØ[~?fŽYÚjT•Tqµ¸A3â£iÒ†äoˆ7kK¢äåjlö ¶kUbš 6q«ífzs"Ñ­”W½Ê/EP»×ÇÝ_h.ÙUÁó¯Z°bQÀ6rkUð¥TuZ=Ŷ›4‡-Í—bÂï«GuÖàR¹Ú4bõ-‚}êðn[΄wö]°\Äž…ö§ï*e À­Vh‰\Ï*Ìj °¶¼÷ t8É(»ôR™œ^âQ<ºÄÍÙ'-½W¾¯ñ ´§}/aÎü\œ½ ”Ó˜7f–ã‚Tbjˆšzõ0D¾YŽ:y,“bØ6°(íxE—RwC˜Hw£<øÜÉ7¬hê•Û˜/4†Rœåßó÷}ôW¹U5˜olx+¡&îa ã±ëJL0±ŒÇ.¸ÅW6W·ÞOº1%“”>Â+£…š¨ÍöÒé~«Â 3i¯u¥x¬{}˜[Ù,æ?zŽ=eµ–-‰VŽsið×¼àJ©›#0N%´”áî|ö¹U~¢bì—ˆƒ‘ê-Aí‘WjsCûñ¨Dõ’%_%G㢾Õ¸Žù3:vϯ^†{<}Ù+9¤[EQ‡Ë©š¦nÇ›CèüÎ< i¼yõ`ÂÓ0É1ׂÎë$÷ÈZ¥M5´”ÞµÛåF4›3ÔoÁŸ` 4Áä÷ûè®~1–]×3hl/-”CÆ‘l/o,ïÄ yÕ’¨MvR1Ô¹­Á4Ùßý㆛iÙÂ&]á­ªØÍ¤àÓb翎ˆ½Êqû_…L´*Þ´c[g«,íGÊ„“ÉèC­¸Òàþ•xvÊ»úxhv.ZÇ ŸÁµ)çò¬ÿGQ;o%î—Gö~Ê~‰ÔØÍ'‰Z°?×OZw¯ªaoÎeS ÷9Ž £wºPz]tdl¨uEýt®§*(X¾ž8côràIH=:²¬}6àƒ âqçÿôE°P·XÇS‘¤(s÷>í°Êûû¥2áRu cV€®TçÜ¡¸DbWXÿFÎ¥AÞϵŸ‘­r±ƒ¾×D7#kZ†ŽŒ+Ô‹[Em»—Ø>»É! §x©ºƒ§ óñZEª Íåì€7K2ÓósfîWn}!¿¤ÍhV|ûý ‘@ɽwá80F˜Q‡«éñ*(ÿwÛy…· g+7^ÎöT‚=Ûdo#ŽåŸ ¥oQº\ZQøÉxôMm– A˜í‰ û!8 %ÌÊ%û’W÷ÖÉm®ìÇ;ýýðiƒ½:dÂv­Ö€ò„š¹Œ ‹Ùøa(‘]DNbWæ’2Z®K/ój“ôÔõ 5’Ó„Ç—Î.\3F’z¦ˆttõ=Ò§ÖügÛëë~&JG^*Ç9(‘ITx[Šà¦8¡HU—®ìb²å‘‹÷%¯ZoË3È×|ÏôVú²³×E ‹p¶fú,€ůBàsÇ­­‰ÒxFê{µ,Tf×|(Xªm²”~çr¡c^lÅ©0YÖì¬cq‰ÓM¾³¬ ¡ýb¦rå\.AJ*äbåiÁˆ¦0ðÇöX»# û~7 ïô‚7Ôô­àMó‰öpˉ寸dä+2u•]±ˆ“@ÁI-Kß1Î i¹•VÚÓeÍn/? (î ÜÜ)Ÿ©°ö†Çw4ž¥’]¹^òÃ\3-8tu³"ÇõÁfެ&i‚0‚y7G2oŽÈ‘­P1A`ögƾJƒ±û!«©&ó Xm3²+£bü+½ÕÀ?!‰êà'ÈÓŠÐî„«¯´vivÿl<ÍÀÃkæì>23ñ¡1âÇ[€‰„'®ö¢(Â[¶µèØHrÝë GØ€êÏüì-&ˆxãryÇ£‹*y\?†®BA*þý<Ø_ÉŽï”®Pw—”ðæí¯Ñˆ™u¦Þ£hÜtȳäwblÅG'ý¨ÝE©fë#Û+÷¾öÕª_ÊL|ÂÏcjøvÊ'”ûÞU*# ñS’¥Å4@=Û "Hª!xâµH*•¾ïƒK©qGc•щÁ¥¸¯ >ksíãìq©)W†~ƒ }K-¹Mïô:g;cǧÊ-(MïÞ¤Ë;Ã[ ´¤©$LÇórO§Ï*òå]—³SP…ÍÿäÏ&œ)öÞ µ·¯à'>žÎ›-L—žz=]o`-bÚ>Ó¼UX§ÍÉ+`=²K?z}ƒÞø³R˜:‡£ë-rà„ÎøöKϹG”žo¥ï›Ÿ’ürª˜wiÏmÎŒ‚¹\ê{Qð’dQrÁØY’ÖÈí;¶Äæ·N¨Úª ª{ú2£Šc!8?Xw`ÂcNÊÀf—|™¸mSÇìGNmG:>wûí h‡¶· åœ&¹Mk¡ã}žþ„§ŸûÍ·áZ:Ú¦xª,´@í¢SÀÖÑüY ‹¡Õ¿]Gh'£þñ0 h$â”9;ƒ\aœ"jÿ`zxá|†ôPŸ®²N“8XÅìSÈ,ÔŠP šq,#nËì2æÛ2rw.÷#]€µIºjOíbm…g7cJ¸ß®…35·EiöywÀ{í ZcÅ+\>˜m»puÛ¤JÚÐO§ŒŠ;uOŒE$R§ø£@’;céƒ=sÿk•`{Ç[?†!S‘Æþ,hÚYô9*erVh®¤¾ÿÎÑq÷ÿTÓËò*RµCºí&µbG‘.þ­GSÍmAH »±†5ï$Y¹ÖÞÿ_X3Á©ë­B4ŽÐƒÐ]V[ò}ÒQÀ˜\pg€ŠüaC` 183?¿D³$Ô¯]Üñ¾ÆÁìö{p÷ò³!eyÒç!§Î†jóýßü]QÝ\Ê÷ä„oR™”éehWéó\Å[¹ž©èÐÆ*ø‹±·O¼5/¯‚&‚.KÒüÔ# D„±Qq «®AGây¾1Ô~~NºU@i§4Þï‹ã—-`â¹+Uê zqE«²BÒ»Kn©´hGˉŠkD-»¡*ƒ8»{–ñv´’¾ˆM”þ´HA~3SÚW.]¥ ŒÁ»‹~©Ÿ8¢ ¿ýkfi–äò ˆok¢W/v»XE†€¬árm·šYŽ ³Qsñ`ëwí}âbÆ‹µvúæÏó<–? âS„7*‘&I.ϰ´fý0Šc“L1{àøN.¥“k*Kr üw¯Ún=5 ]îÁ ûà|½)ƒè±¿y.‹Îµ½*p¬á=:ßB‰HZjïGøŒ2ï÷ª¡÷ƒ)Ûé}_4ü‰ë)T `ÃY&Óõ×ä¦}<‘NDy$jƒ—=ã $¦‚ABdzÐ{aÅh3º0g4÷òD¡»éú6¨Ü&…Ä 4gÝeOšc+Tdï; ?ºÙK£$ ­°åšº1O\Å Üšš>Ôx“X¼-¡3ì&z” ÊÝú@Úw„é[&¡w. ½_Ð%wÙúDv4&MÂ$xÏ¢ý„aÕ_€¢‰gÒ9êä|L“ª‚e³àP<.¤~v2‡Õå›6q¾//Å’JÄÝô³Hiº¼ˆk¨œN¥‡Ý^ˆ$$În^ø¼ÒÅg‘2›&‰Ü ­.a¤"ê‘‚{z 2 ,^t®Þ‘Ÿ”NÆ&›kLÁˆ–póÏbÚüz× At˜f`…ÿ&55Ìf˜ Ë€M¶‡˜4‰MgÈ@IG#ÄÙ¶v@d³H—ÔÃû(³£ŠØÄ[¸ª‹u&QSu®1G€4kÓÛac& ÁUêüݺˆn+[±ó*¡TŽpô8!Ù÷+ÁOø˜áúÌÌ0#ˆ~éºv·2ã“7ü›-O·¼ÿâs¡í·,%^²@T2Í~âáï{<)õwCrŸ\ÞìwÒÃÄe¦ø²NvLê º….Ε°òá6ßKm¨%ž°”+nÄ*ýjÖT^‹èR´ ÊC¹ÃK aâÊÉóËiÚF*¬æî¼Œ\8¥™|°4þôçdåüäø$Ã}Vƒuÿ‘2“[Î' 4·)ß¾ ý«èdŽíýE/OjàmïC”ØKý½a²£ü-E%É9¾T[Òƒ¤Òà ò±úAÔùœ›xï$yg¼æfž£-þ] Ž ´w¡æ[®=;N«ð5Z(M~!äwGyÚ‚6Qó^jBÆ¥3$h:”'–9¡b/û)à5 Õטpƺï/éÌ:”@ï7\ +äÅ jáPeG¼@§É;ÄÆµ~Ïé‘ååfùØj÷ðLŽ\nOÞÏ‹©w`¶P—e¥É½Q”R;TŒàw©³^pz¥ñU·m*§SWg¾-Â]Î9kæo|’EÛYÜ—–HÞ4¦¤M[q4¦qÙ34¸È$º+¬þÜ+)«:näà-–‘|÷€óϰL.!‡%”±Þשm¯ê›è \x‚ârwTQ¿"Z È—¹óÒæÄE±JNÒGQÆÿIô.\pÏ#ÁçZv rÜ”€=êc î4ükN}µ¬©ÞSHFYaÄ&£yaÞÄ7â¶B b”eL÷ÐÑZ~.óÓ}ØùÉ¿Y1õä¿ïᦸì’|†[0ï5*\ ƒ›²èÁp8›œR„Ãlj(S .iHH=gd#֌ҢWzÚMÊl7áiÿÕ3D¡* §¶éJ¸`Œa|ël%˲–Ù9ž‰‘ÊûhÃ3åj†Íܬ›vêdp4ðÒ5­׃Žpo Õv¯ &ÿÛ1‹€1*\C[‰ÀK>jÀçSžØ•*½Pià$I (-x¾Ë4Ð0ɹRCõZà:XÇúè_K_‹B¢òPðfÂkR”èê“ÏQX%Ï%‰´H’ƒé<ê\AC eö?Žë^õ¡*ò~VKw9ùÕáׇã¿^r”K~ µ „ùð/uÚ>HÂÚ@ZʸgëÁ F€¨gkº¥Å¼–COF8v^Ö›0üV$œš(KÖoYr¬Å!ÅÓõ!r~U­¬¯T“m゙9xÄ h´­:‹ˆÞ8k¥8X“D—2oÇ>žqX#QkŸ£HáÃÕEþžÁŠBŸJJvÏæÌy^©§Ô{ßînjë^ýw˜'ºfÝä_A<›¶#íÓDÃ2¼"øUó¹6tÿÄƵä¿Ü¬ÏÖ5´BÆÌkAÂÕ±ÿ„í©­ó¤•è˜ ý®Ä „o1Š?‡7Õ ’KºÞùh»TÊØÉbú0FH úÚ–÷Ë# ©å$ XTÞ ,=\422m*P¡Vºñæ uH E¡t¡òÚPL8ÁÓà´S~»Ø5”Ž| o±&[D©ã^&ç" sX ‘r¨'c¦É¸© ¼‹^mp`°wúñaA–IO?ç+¸Þ¸UЬîpÝ.ÜnFŒ"i„ éÊ~Ês@é”„ÔÆñÍ3ÎÝðúúyd­\c™øBÎõ¥„œ;XychÆNDÌŠéäÄYÌ“…¹$Ü~=ÇÒéìݸ.gˆ!lÏcì•÷HC°r·/:»3Zå›O£„:Š4®¦§" úW~чä;5Æ/Œׇm÷V!d éÔ?ÊåóÁS7Zþ$7èóëO¾Ÿ¿ÁJÅ,cwØù1ó½ílá›c¢WB¦?_Ë&¿3x G_]»TCª®à×xd”ƒæ29‰ÂxªŒÍ•™‰ƒ±¿+#1¬30™šÒ§®…,PŠ=&V„†n@lÛûyzy1¬ì5cGß\nÁmÀ¦ {"0Ü»¹ulÿÕ ˜ï3ÚQj;6;¹’ÃL$Ä¢u—óÁ†ñ^åO.æ¡á¹ÒZ¦ôáZîlFuI8 2^À‘u§s´´\^¥ZÌP šÑðålC¸ÖVÏÛ”#´Ìa +Ï©¥Ibh#¾­f’ÄÑ·eeäšäY'céíÞ†Ù‹_QˆiîòØ‘`W^:Ý0m 3BP!´çYŶÆÞŠãNJ‚0ŠC‘¦Í³A¸s¹ð“Z }‘r¥Z¸üU†üƒ£m,iõ R<6öÃqs&ì4`3”6ä@çÿ>î¼±T¤ý¤E5ï$ó Ø¿TCí¤·Pªë”ùþÙlX;i¸¨ÔšýCÛZƒ£e¤þ‘~ÑHáõ»‰½€âuN Šq.æÔ[rfYjH?ÌÃl~„ðð«‹î ÆAḠ.¦©åáõ/4éžhu+±zyFø(oïš<¿Ç‹AÓEÄ?Vpî׃U…\én@¾JFMAF~}° h|ûª"£”[2«¤ßVu}Þô½aµDö¬gòRåL!_+î«ÎÊq÷œg½iÔ¼{U•ï(+»Œ_Í\ôºšç®ËñË¢ùüñÉþ•f Hti ÈÊ"I[n±¼ÙÌx.(,ï•é”î.óÑ#¢Hé*ÎÎ'nñÄ^0^0­r:Óçß\¿4‰õŠy¡%Ùn‚ý|É^NêÉ1­åô6, PJ£µw´0{V´±›øÇNgz°‹oö:“[ ¬@_8ž.Â-:Bý–Q’ÓôÙÊÕÿ$¯Yq*÷¢7`㻓FÀõ–2½Š@MIô݇b3`t÷1ê¯áR´´L;ï»+|â©õ¹“1i÷>¸ ÿ!Îo¾æ%;ôÓRi̓»µz±öÞÁ?‡m Ȉ&Aå·à$N~âLßÿè\׃C‚àÇga’¨ï÷*Ó]· ðùnÅr`9ÊÁÀÊEÂî=75W䟴’ã,fÚD'–ÞB"áK³¯¾qiPjPȪ‹Å‰[­¹fš§†ãþ½¤ì‰î¾ô¼«êGûËkŽõÄ)¦sv¸kÌ>ð—‹»FÕPI¾i\ã¦äÈÌFÍOï#â›Â#vG¹p‰Ä¾†Z¿ÉÚFT ŠƒòTm5ç|÷5ç¹G©wÂ*„R¢*ž*0þJ/—[‰µÍ Án©¨í%SÿÂו,³°Ê—<¾,ª’{ ÔW~Oô®]7»4gi˜çóˆ÷soÆŠ¼š¤~Å¿ýYwë·´ 5eUVÃ>7ÊIÓ#p§_ÜÑi4¥ÊIöéÙ4X Ô%„Q<+©|lézºÄÌŽ?©¨V¡ŒœIedæ>ÛõÖÆ+O[˜K}KTÖ* …µ KŽßS_ìjXÀ˜¶ÈÏkÞÇÛräiò?©3¼ÿΦœ¡ébIÕ¶yöLb7o·Æ5-7ÛŽØÐ≬ÅJ×ÕZ^¯¿æ2T7gp»Ð?p œFôªßâhY ãÏ.KãÏ_çÖødÁYsIRÕ¢‚ÂD' Ü6PÃZI‘ODžÎk·¹ƒ¼Ñù€êéòð±Â¬0šïè‘Dÿoå}÷&/›Vh1ÒPÂ7Þ¢Ü×> ó÷ޮω%gçú×gj?½zÆk‹dN.«È=». ¨@£„ßX0¶©<34úç(ßd+¥-­'T”讘Lck.¶m¿ð2+Xõ ð–²6~‹Ltr²½7·qD“êâ'¨Æ˜|Jy HŒÊoZÓ"2«›[c%Í•9!WTäb‰§ ›´ÜùFGVK’韴t\à†ä8ÓîíwËó<á¦nñ\[÷€š·¥'×û}øá·ÚМڎ9ö?=©ªÊµjHß™%£ÜÔ#¾²á&ô¹™LRºóYŒpÕÙ%ì1Ëäˆ ÎÃ?#»Gû%ª¶ëbÅUéÐdýÓ+ük+9Ëé‰ÌoѸËèàïT#ttÈdÀImŽ~‡VUž+-Ðva¹^c+ÕÊJž&€0|#¦IÛÐYt¶kt0Bä–Ö¨få;wŠzûÐcÀ±¢Éfü¹ÍÛ$“¹n†ÿhaÑÛÐ…c…‚)¹rm(ý÷¶#~–ç­•i¾l¢& ×èe&W¨¤ùøÔªúI…w+ž×ׂ,· â;Œ9UÐ’Â妮ަö_)¨QîŸ Ó‹ÜZáñ´_³ÞùœV «[5=Þòèñø»¥ÌBÛ3\\¢I²ž qX2A_šd ôùH#[ÔÒðÚ)®SXF“êBP8Btñ+„FØ&0¡Š2‰ÀZŽˆ•”§süÃNgb~—4”s‘':ÇËÝ­üõ ÂKÖymÙ\ˆÞqš…yG[$'%yBGŒZh¡µB0%AO’ʦͱ$$lCQY¦f£·ÍŠv'n¢ƒb±'Á⃪pP–‚„&æTõ¹¾kb2‚ñ!­-céc^9hщlPyÖQ`(lç<#e§Ú¹cq×!–æi;“oÖPl¬îŽ$ƶ‚ˆÈ=ãᣓϒÖx£Ñl•—Œê§Ýd.9_ …T‰-ê~P|íe~n!¸ŒÍÕª;­›Lœc*³ô«l’ñ Ä£ÅbØÑ›sâž3V Vb»6œ$”iõ/r½\\|sdPý:³•a4-¡Ì©$Œä<Þ†æQdDŸŠŸ„£…#V÷¿DULY?o¢åCñ¥ãÄ¥S§jiû È’þçì‡ÜÇLõ+žm)ÒQÌH¥û‰5úQðჩüc¨œ™ÑB4A·ãZžnqå ˜qÃOΈxˆq™—™~ÝÖqc|‹T¤‘sê"_èWŒ"@û‹?lÛqR**¦[jK#êk»ay““a Ô6r‹\pÈ«3 ýkJ1¨S–z­tQ—ÞÖvPàqM&˜‰ÙC[Tì{z;Úz<h6ï1}ó3ƒ“p]¶6{;Üö/·$KªÁŸÞ*…Žwÿþâ€ê ÍÌ-]¬NŽnk÷ M`_›};¹E jqz¯HaÃ¥²uc-­‹•1â®ò|r"U‚j³¤4ÄÇ>"º|dÛ0âÃ`¢W%<ÜFmPÅ=ð°X < Ï4o³Ãš¨³)Qø¦grk‘HÖÈZ ~qÄ ´ß‹ÊìüåÅ™1´´iK›PZÚýÔ7ó-”Z˜T*cç¯l¿€'d¤ûF¤G˜€éå$ØóqÕ]%¶¼sÃzG®¤!bè°i—Ϋý÷®.âˆ&£\§rüi‘™Ñx [¢@~ªÊf¥Š½ú€dø_ôTJŽÈ_  9«ÉT½ÍêÞ)xC¨±1ÑÆüö9pµÌ´;¤5K„>Ö Ö/q™£GX”¹t†*@Tö…¬¸}3ÃGý¸Í’Ô°òÊÀ2NRÅô”иHlÅ5rý-¿û|'ÔYÌ푨rpp®‹¿]5#ÏO-ò%8¾M| ü­„ H10k9™œUç¹ý¶ €ËÒГuÑ»ñ åºÎ5g%Fí N¯à+˜}$½D{=éÖpØY™%IÃõæõ]ò§!FxònÝê–Ê'&†ayQ2–Jb›Ç·<ÏxîwÇý ¡UTL:ˆ)B²tÀ Ò|»¨>ÛÏk½È^ªÒŠJØXÇ´^£ê)È„_pÁ"Ôë¶ø Rº_ˆ·«bkà6'“Ëz™<İ1³Ÿ×)ßeø`æ¨Q*LíçÐñ–ý8¾ ä<ݽcê¦Çµ#[ü!1+íßqC3ˆñvTî¢JçDç\¯+¢H8Ç?ôk£~dÐ;à[†—wëM8/2 s‚ý”'“ØX_¶âÆXýÃz[˜µõW‰‡¨1ÆÕu®<ÞÝæ¥~*2€¤QÐň*Ñäú/Qu˜Æ=]"’BDaªVôäU4ñº gšþH“¶=û_†«ˆ?hÒ*ÉŽ‹ ÒL‘LÌØ8çÎ(*ÙRwÀdnØûë@lLÖlŒSšvCjÅ"l®z´"  ›‹Ý ¿·KötÚ9æ]TŸuzruìÚ5X“2Ý‹‡ˆ˵‰.Øp0°6xêÀÿÙ$›7§®ÃÔòQqâFn«*`"ýŒ4ânìZ¼+3¢ç×ül5yåÇRšó F9³ÙΥЈe#MÇz)ø'/r09|XOO&ötŸ'ì¸õ~uøŸ Ÿ¢+²%°ùD6òÊl;µ–Ç„Ñí&?×yê÷P4hŠÑ§Ž8%S²9:k)¯²Ë}q —ûë+)Z=²ç€þŸ`£wáU÷@V‡;¢Ogßr ³KÛÚÿ¢@©#©|-ªgqð‰6îW^@*5^÷ãÍÜSí60ªMQ¯Jˆ×72& šåÇŠ€Fyp˜Ý ¶ê¿ì+ šE|T™‰1æ•&ƨ ž=¼Æ¸5÷û¹p$ k"ä%Š#^fí£Ö§0Ri †Ý”PÚvJãݳa˜NRãÈ(­rúf)šô¨èÎú­L³Íj“/èy«†£Ú¿6Ñp!Oª»?5à!:HúòS‹øÂ]£ÒŽ÷¾‚v±ÛïêÍ8µ-WÔp«¯ºt6†wRò…Ãf½T­ÔN0QXzñ‚icb]à¯Njsœ3ˆ™OéC×à ½èhƤó¹9+¿’:ùØ{q^_˜mqôÃ@éÃ& »O\;Ó>9öP°È,(Ÿ'ˆ“ÍYO]!“a©>R ®4’·5Ç5‚PG"ÓG?”5ˆ½¸1;ðt|Œç=’ö|¿lƽt§(è¯Ø0^b{9YsNJ§¦Þˆïrø¬Ú2€žøù8/wš@[‘*}žˆ¾¹B¬·Ädn4>U–˜i>7.n–?!˜¹¦dqŒ%Äc³ñ¬1wÅ–9­³Ë¾ükvŽçµÔ™ç#}þ¦}ÜEBŒÜ_¶Zª¸lôi€äruÂq¯vQó®:ƒï€$h`‰ŽaK@{¥#yª$›ØSϪÆŽÔ×QÔŽ¡×ÒÜÅÒ‘ˆüÈd¡%jCËæEww‚tè}§ÁÿÓ€+fÕážðÔ@kå’O}“JÆÉõˆý‹'É6ŸE ÞŠVœN…“¶Á®)aógÔ*„G#İztB3z.Ms£¥8éäB_´iGƇ»ì‹¶ìg;:èL<ÖÁ6tgef#hk–¦ùdŠPú#1 kV‡ûƕ܂dR-¬¿îâô®5{›#u»Q,ÌFþ‡ï³“¨µE ’Æ–lO©ÃÙq4ޱ¾;^Qʤ7÷I¼uóX|úÇg4/Ù*xxØÓ` žÇ«l.‰%Èø‚¾¡Ô;sˆ"hdÕTwü…Š)?ŒžK…©¦ëúÐýb}) Ô‚Û#’ñ·;þ‡ØÅe9Ùõ¿ ,²Ž¢•~`ËqïѲÔ2Q:匤´§ßëmc[ö`Q él¤¬”hmåÍsVþ`]óš´GÒ¡$ ï„_/2D"9¿žû€:tÈbÑ—ëCrê`õqD/•¡rˆ^µÔC¨{–g9ƒ¹G‹ð|tCR1PIÀ,þ¤´&aä?È~ˆï_e1<üy" 3ÊT¤\Ð-¬R-ë_LtjËá1ò²¼¿;à⹜C¶AŠìzëKÎba€Z¾‡wFJóÈ'b!&öÂxÖiš—üÅWLB}Ç7@êÊи—S1Ê…•r7‚³?úµ Ú‡4MO]†Î4#¼fßÄ5°u;£Ìä.ñ{onw7Œ{“6§tX«h×â©#§3ËšÜ@Ø ýàd P""„ކÒ!aµÙyRä“ U.õÕ@?]ü®=  ¶ßˆïqÓ.6×q†Ïb uK²òÆeŽËº¼Ec¥Î…P$4J~÷®½ÅÞ"ò$)úVb;1çñÈžH®ûEÕòs¥>Oo0²¯ %Ö´XíÆüƒ[{©鸙ù¡Å¶i½µ,ú^ã~¬3$‹Ÿg*‰…{ÀéX<ïÔ{Á†Z޳4°Õº *ºOSj|q£‹­*M*ËEMSŽ÷ç´°mT„’4m¡s×c“!¬6•ĉ§ž+‰p`@·. oXt»â¯ÏÙyÜ_­ egŽM³Aâ¨äDŸÌ<Œ[’û „/OË®ƒ!s.[¡,å"ÌzZL! £®~æòQGÆ}@¢Ÿ|“®—Юë°?s `•>„_øÖ«Þ!ë2‘&‰@›4‰6ô.tÆkÀF1›ôv³~Tkm΃6”×¶¶iÉüÖ÷g…d$êV‚~NkPÊ¥qÊf.Éüïýp‘+âø';¥â|ÝæŸSÕî²ü±>†G,0‡Y4¦Ó‹¡‘LXùég$e<½\¸«M ­¨%QÓ‡yaô<êDà;B¾’ådh—•u,ï3ÒÓ …ÎcjÝò[ïò(”ãÛÏàí¢¹‚“–R6ŽŠ°}K@ 9±UB\EkŒºnͰ¾“¢è…¬jtvù Ïýz±ÉCc½ina¡˜PtäöPÜBâú]!2Wì go<®í;mŒWË­ëä5Ãxûƒí¿÷j½¾&½&ŒqTHs‡ÜÁ"“K’…ÊÍ΀"îU¸‰?›·H¹$g9!NqÆž„S6…¹˜õ†âý‚‚ð'¸Ü.Œ¼W—m›ÐKœÍT<Ï˵P<xÿ{ÈŸhzl~–m†—þ¢…À6Oì7‘»üèá»òùÏG'ÄîLïŠÇûª±«Î×±‡>¿—cÙŠªÈ.ÛÝW:07vÖ –%±Î³*yó™AÇÔ²» Kgyk`±|>ŠAìÐn˜|ÒWÚ€"U¥¨Vœ®A³Ç"Þÿ@¸Þ)§ø {WQ%Í“¢ÀAz^Nµ*êd.I@ìžeÈIÇ÷eŒ³#/†ÁLy‹nJ³nðÐæòŸÃK{¯c~lj¢b3:¬`—4Xb[a«qvy-õ ”\“ÎŽˆ¿HÛôUþeSœzÐTÒ ¢w.P,~žÁ fHÑQX1ÆŒÍséDVÈ‘J_‘?œ,‡ò]hë5"¤šLX-½}L4Ý}x6(|%ùNý_÷b(!‘ÖÚ ½ vC?β‹ç¯{©F¦^i¡ï&$ÜngFŘÐwXtµˆ'›ú?¯ékpȨ)&é8*Ž‹Â}(×u‹ËÖk*Sÿ<ˆˆ'@P©ú)úÙÕnŸÊ<{‹=—<ß0ÑŠ'+*öœøÖÝB™Mœ›Ã›ë‰Ý,ˆ\ìR_6b8ã½1X‡ëŸÜÖ¦÷Em‰xsHW‡>qß߇\“§ôŠÝN4ú=XoäÓ+¢”$)tBžD2àà g•ïIoW‚†Ñ)h­Kd\›.‚ëÊ`?…¥ÔçMya~fß½ôxumÀñïWOÃÿeæú+hùÑxãô–ƒ}.®sï2d%¬‡E7kC åšK£˜MÓ¦%ÅÔˆôáƒ+4tk_4±þÐ[yÉñlÏUŸé‚eh!Çð0’ÈQ‡í¡JIt¾_Ï|}#$%ÜÑxA8β¯DÂ5§k°êÅHßø +Zž*{&î'Cd×/q,dË¡xTÀüé:%ê"UÿØÒ„:)&¢ŒSþQ–(m³½ò¥¿á€Ò‘:0ôÛλ+*^ Fëºy«y[‚|ØkèqÉo ³È)ÜMÊZ«3—ñÊÄ—†®¼6»P•€‹Ú»v]óDÜÁϽٓ8P ,ÀSO½ßËie||#Á¿'’í.¶äµ£²k$‡"/²Èf–&&82i½BŸ¶e?[Æ¡!‡™¼â?¿ÍC¬šPdËL˜dÜñëÏ^E »ÇH6ÇÚÆ‹«ëÚ&‰5ÖDë½ðM/(¾Œ©Ÿ÷æ‰.À¹–ü€o\³C;ˆ²ƒnû¬,jüãü˜n |÷•ÆU{¸¡jÜäÐMK žö ¬·3<`œüúÇ¡s7Ó__ôèìºwàHuh ž‡”¾ŒG‹wê3{a]_‚&éUqw`L]"Ú¶b`$;¢ç1õ&Û›IWçi£¸³™{ëø˜–q£\¶Á]ç‡ZÔË%^ø%:ZÏ’`½·K†Fi†¹Ãb·5Þû0¾H³áÔ m\sb—šÜ¡ȡعu*»Ø|»fé_f'ËÑ´³ ¨¢n 4Pû|t’˜ 6–õᬚ»r3Š<ƨöÙñ±Þ0ûUr —iŽÞßË®–,D·ªèþQNõæîþ›±mÂ镸Ù1ZPÐI™дêg[^BW†7‰[‡:Q¨0¶7¥ºƒˆügi£]Tן UÓ"<²ï£ÀÈ Õðïÿ2%¢„濜S¦Çad÷w]Wó•¿rÿ\”7fhÇ_dUáß­83 )Bùò"ÊówDgŒ'¾‘º‚gB=`"ÄÉêP øÕíÿ×°‚¸÷Õ@Éj_à> «¿Vý;'’µD9>éù#‰ú$:'ï!¢óöé<±fB›Ë+‘¨ö‡ HuAD¾ƒ„ <ˆ̸{`Q¤JÜè”Ì FGЅƈ·ô˜já‡m`´RáèÕzÇâvnE®ÚÒ/¯å :5^JÙ·›þÐúŽ,j6EU‡v›¼þˆ‘]Ûò¶3à²F¬Ú¹œ1Vüûxðמ¤¾6P¼ènîŨø¸8ÆÏè_½£™~¼ËUâSÒ¨*~ÿ‚õ€2¸2¥vº–%H1¥¿C÷-À²ØÝæ´±,ñ3T”œ‚èæê—ÌöÙá§ei.eÛW¨$5KDͳI¶ŠüAaém¸)*îbÿijˆ¶ç›P_,Lö ©NÔƒ«…3úàå-Úšê]7ÅÝ•:-ðM}éÁwÝèE­cã±A³§‘v•åc j͵•êKÃäÊáiwÕ¡tÐ^!â¬Õv@`¬ÐÂfGtÖ–Iø@>íNǿձ|zX®˜sý>&õRßD¢La…¹hz¦xO ¯Ð’—iŽ·í«Rƒì—;<5m—T(o nPÖ)¹õšË(µ?:ÿ‘ÓÝ^ñQËÙnŠEáùkñNûÂx¦ó316H"ößUgÍ­—ŧ–þ |÷Ð7OÈ96BÛ« ⸻¢½½0]ºƒVÂ5|ÌíÚ¼ö@CÂQ¯ûú¦w‹xË0¯Ù3j0„ˆS‹MyÅE¹#ׯq>¾g}©ÏmL{ùü£áLÿnÂY=a™Z±47 sz°6+ ÜÀÌç—œ|l…&®N–ã¿$,?å¾Àë¹ÍùD.—¿>±=23Wîó èÐjJá–§Díäp'cXøQÛ0‘'o"ÂùD7wZ½ÝŠÜ¤ÞÚéí¿‹I‡~QÜ[.¸°ÞêÓ3Æ;®[?êÆ.Qé3wÇc»ÞC_5&ˆÅx >LæÃñ­Æ;B…\Ûõ`8S!f^àO¿èÒÍlƒ¬Nls)Ëïm`/²ËSwLZoO_qö2zÄéÕS~>Ä>}˜“eý¯5ÀËVÅ)þYº-÷󯡱,)>c{3Ð…B‰äž~Rú¾øAñ´¶Æø‡üøn„žA¸Ü£ iÏ™û¶Çá“7UzÒÊó3X³½LÛ©³(ò}¨"“ùj-î)§‘žµÞ&Fúkÿ’ÀÆôSµzEá&ë‹YkçÞúîîoK[¨ÄK¥SÙåðo’¬>’‰’ÒÖ "m¤ùˆÂ©-+‚$†Õ±;yuâúÐA(voÉuyÑlygoÿ€Ôã³7zŒþ§e$¯9®a!ñLÂÄÆ6yà#¶ ï0%Oœ;a]ÿ©È/Í<ëT󋡦mê5UÊ×TªÃy¼‘už˜0µô«)ÓÕ¿ŽÈ3WZ5õ[¸öO¨GÌmC¼oƒŽªŒ<Ò¢ œ¡ ¥àÉâH–]ÆÅ#‚vÔpÈ~•P)µ4¹lÅlT(:¸´¢þ)Å‹žã,ûž¬ÂÛBÞÛmì¯óžâ’í–Î,áü{¹ÓyqT~µF‚ö*=ñ{CßÓ »ÈÞ‹‡1ÞŠ¾>´úÞ¤HûÖTëœvÚríNŸ¾ËŠ\ÔÆ_V{Íö_ðÄ¿û r«?×è{®ÚÓŒö±© ªøézë‚pPn#¹: ùÒµ1å•M~{º^XÆ¢’φß/‘$í`<ÿñ;¥Ûï¯6ibRUâY ßË DTÐ…I±¶ Õ1° <þàØˆÌãe&Ò¼lý™y1 q(Æíw Ô¡ŸßËДôîô°fi8I»ÚöYHL©+™ÙêM^P1µP"®ÕÝj–“™öƒ´yF°§-©íTYltìé*+<û h@”1’Å–™CÇNPÜv£¬N5KšáeÒq¥Œ´`ù™¦z¼zqɦC”s¯ï"•ìdIW *ï~0̤ªz“:2æýÁß'àXÅÉp>þºþ… -f;¤`ÿwVÂKN•±ÿLÿíó+Ñ Q)9F¬ô¤ÌotàV¤l‹n&*C;Hî*—´ùml O'¾¥Å0C¨V¬¾[æH2K­³¼{XMvOS630æ0ågVRS¼ìéúQõƒIðê—ä,÷’°^ÀšÙÔÿ<7ÍlCõÇ*>tÝ|Ï"LNAΚŸ­ÃK…ŽË¥ëm4C^²ŒI|~Y¥äXÿqµÐŸeV[ ZhZkq±¥SU¬9³œ 9¢àRÌЇ„óUµQfØehYZ9­iS] ªa6çÌ;N|eSä™ùĵ»Ûȉ«ÖÄ¢pòÔSócÓ  (jéIE)qƒÑ5Gk “î<Ò’';;%ÐáGá8·Ô§Õñ9Ø›ØðtÉ€âêÍCþS¾Q 9äÞ¿CUå÷SuI¶¦!:z9BISËæyÅc0ÚÚPr)ÇA˜¿œØÅ9 ”ž…HSËǾ…#[<ÿ>]Üc]“Ô_gé]ÒÑ uÞ»¥ ÍýªOÌZ}1â|@¾¯µ dtR~Á Ò$éß„†,Hûl*ºž€»^!äÌl↛ó„Xäl²·ôU¸i~ pUSJËÝ©wRV;8Ï")[KÝ=µÃÒ2ÝBu¾{®ÅEö²K#%âÏ‚Êu&ýªË:>ÕÜÝúÀáø·¹þÙk-ƒ#ÓÙÜöS¯â¬ÏÞ\_HbØH‡+VW¥.‘h˜DMg-#09¥¾ØÍ3ÿÀ¦,Ö[$׸EwhLœ«ðÂD`øÙ\[ˆ‡gÜ(Ó„hUŒÈntæb£˜IDVãyÙ‚ö ”ì;&dŸ»ï iÝ$)?Å•CU,ª +…³@JUdK±I±<«7‹ás®í_w Œù,1ˆ¯ÿ^6Õø0‡È”ž®ýݼðé='«Æá(y¹Î·«ý ¯AÌ–ËèÁ°¢I ‹¶ù‘D½Ó€X:‘¸÷Žt-Ll%|s+K:˜¶ü¶ áCU(ieý¸{ë&syÊÃò,øn”c¾IOÒ¤ÛTêe>0dÐKkYkh—Pñ¨î¯/î'E‡ ´j¶EõŽbÍŠR'SÒ£ƒîözÇs?Ÿ>kXˆ/µõ :©sï|±×³ÞµMgx-.ÊÎÁ(÷mÑm›j¿²L ó°ûK$x„¢Žû4>O$)—®8xÙ䣋¢‹ß;îX×…;*“šÕ‡ºçú±ÔÕ×΄‰rÎ$)x˜É¬6Q9@ûž¯4IjyPù¼`·eÅÍKÑ,­mh*ɼýãNc;.Û¶"ZH¬Zñ(Tг’‹H,Þ‡tÁÔùè•ßÇ¥=r¬Çç!qAcfûùrž¯ MG‹ØÑþ¾>Õ¾~‘ g»Ù@/ŠŒ΀öÁ7Ë;t ×Ò˜µ‹¥;ñs¸23}šãw•ùswú‰;šP¶ðRÅŸçXÙïßçpùÅÃð "€°£¼Øœ²*Ä>²íÊÄb;? 5¬T¢ˆ¾ZA¹¿j´xý7…âj 2æ#[”ÓfÑË›fYëýzð¸v ôºíNCæ^WÕ®àãOöÏmqo·Z_©»üž¨YÛüüî7|„Ö×x¿ñ¨êˆ…ùÂXq(œA¶&;â0Ûp¢¨ªšðóý|p‹ `QþBcu¿'/MÛðe^k2ƒùDï ê½ß# …©zŸ øX¯ç$ÕE«R­™ZÉÝËt^µÓæµÁ¢Ì‹mÁ«ÈÞ­ÞÐ"˜ûtBÎ&Ô+â‹ìUG£ý'›5û÷¨Ópá«ê8ÚÄ\K`Ùâö^µ8ÅrIÒôÏbÉ­ÑOìj>0„®¨¨/ãM[³æÖt¢($fçhfµ]V,à½7 ýfbú-ÃnøˆÏµ~U³ŸüRZÅ|4„ÇÒa‹Ïãpl"œ}uŸ ´©Ñø9ƒx–YøŒúî¦J6ÜÉ@‘ÄôíõZÏ(|2÷ÕœëÓ¾)ÛþúÞù-ü0{¥RËêÑl¤¦×G}ÍS#Âhž^þåËQgôïù¬Xd$acæ²\žh%.Ìðœ÷NÀÊ9¨²‰ó½¥*âŒÂ½Â!xÊG µ,˜¹Fňžõœ]s e<(›k}õãä°ß @¿3öc`Ô³ê@E¨’Änxʈ‚,¬>ͺKÜÆó´t–5Ûd§ciôA£¥9–BS$=>Ã6İ\+¬olP™86ˆ›Öƒ‚·]í-n¥³~âáæ¼aK£ú¤g,ŽpÈ­+¯bCÊšNä)Y¬µl›3iDÄë%ƒƒ!š¶Y‡=YɆe#ÙO ¹Bá‘oå×]5Øö´JyæWYÓþ0î¤C<™öF)p±ž‚îž$°‘Ý{ú:b`õ2w]mWD’Xí^Bœ×TÞg7NøF£pðŠ£Â1¼C鯙Ñþ¼-EZþuhö<èmƒ¼?LÙJRÖ“íñˆ¯ä‰! TÏ/l?ÑïZ{õÝg$ü6‰Ãí°ŒéÓ>!’‚F 7>ä5žJâwŽˆ4ÖÜ‹­åº_A=‹ÀdO÷%ƒj¿âí<‰^·QÉÌé a“Š9ä¥vèQqŽ*ƒS1³­+ÔlP*Ù»[5f+õpHÚ’ÁÊFU=ý×–*‘R#é”C!(:2¨‰*"|‚zsM{n‰$¢ (ãx¸T·‘Û 0‰äb„ìUJV8¦ÍÚ©¶l E·Qr7~ûmzöD¦¦[^å™ øk¢cœaão–ûLÿŽÝ)Í#Ù4’ȾUõ¶E°—¬(ßfÿð¹G0œ§ä K^iÜ/4a»îéç|3#õăp0蔑™+G^#Ñ´åEi:ÇFv£ÞV¶7«G‚ ¨}HÅ2š/’H*ÖÛüݘs×ð`bb7Àò’ÃwzHO¯™]BF7‘ÎluO<ˆu®'Ð*”kQ‘Y¯׈‹8ÅhÚ4:æ³üwÛ ê»ÖãXŸ·°ÐÊrÉ#7Hãµ`Å T*#^Ž‹pIw2|C j¥ …pSø@°]¦–+äã_ˆw=§uɬ° pO““qì?¢`>ñÑ,î@v=ä”`œÕ#™#v&;Ävî¹lóBÔÅÊöô½$ËgP?^G}çísÐàÅUg+ïHsIm7K¯Y nJ-·o¤ÿçï:gz@¹Çõƒ1 çæH’Ñ(i“~+5uœR‡‹3[Ì»“‹ÕÙŠ$ØP¨ŽéˆrÅR… åˆ?V[[Árõ WòÊýÞö)þÐxqÓ÷îõ#‘«¯ün<¡>~L|g•&G-¹Û{Œ”V‡ÎÄÞiݰUõ~ëËPµhÎì‘XˆöÂæ¡þ˜ [¥ÓEE5’NòM—s¾ÆüÜ© 8o†bÕ^M jçmÓÒɈjnòB=Ó0'si ×ä+¤o£êg\xÍÂÄQÈð~¾1Jo‰,ÁsÕ²j âͧP³[†hRöe¶'ÏgaÆ0ágÔĽÊ%}³ÀÏmÏQÔ"ß°²ïõL4dŸj‹´´ËI¿ÒËj@á‹ìý¶N…à³:{EUÛÐeªúôˆƒôâàMÃSò#áÞ#œ©¶Š‰¸åZül<Þû7ºä†÷> ë˜:Pë$uÓÄ|UÁO‚â­é@¸ä¨ HŸ§X½áŠ… •E{ªëYX J½éPþTéŠz iª°ÂT²s„Õ§)Ö6aùÅr&à~·`b*êÂpDGIAoË^zÍSzùƒ,H®o_މ÷îo~Æ9…ØoØÿ€ßÝ»õ KXF·íŸÐª«“›Š}ë†éD’p¿ª/±³@â%Mù«)óÇDv‚?lÊ4¹_J»[+átþe^žº[YbøéËï~ÊÅZå®vQÞ %Õ×W’!ãT®Ÿy”ú(Æt%Ó.º"_G·óU%½u2Ç.OSê ò'>Õã ܼ½ª<Ës9ÊœÉ[ñw½÷Ž»!M#\ ßcT.bš½[« „RBL»+UD˜ð†Ú; ÚTôÝTÉV²Ö5T ¾H²Ü6÷GªûuÍSrýW¡}þ®gž_f8| ¼™J¬y¼Kq~KvþGÆpÏÈ5 Ãy„ɽÕÂy3Ú ´Ü»6sÌb8ˆ°ÏØù ølÆìÈÀIìÜý6Šª”eO”ÅÁæÆé‚ÅŠ™Ãê“´¸Od!@¾?Ý`þÚ;û†;Íúêeí˜jcWMÈuOÅgʾ'só¤ñŸ®.oàE`©ï-1¶³»Ü»ŠO ÿIÈ^Ù:¨0ó@ò(°y'º{M\[}&”3ÇàÛÓÒ**Ay«K$eR³xyt€öì¥q%1Ø Ó2Ó+ÉLð¿ºUÅèuÚ÷dwÔ=I6ïí7Ö­C°„²”^œÙ[~§n±·Ù/¨ïgÎhý5;;C¹€!tQ#Bhý d‚‰L¦¥éÐ_ QÁë:ÆDhÞŸ<´ÇVÊXé4ŽÈ‡i?KP‚.vMbYÛÿá&ÉȈ„mvi¦¦I@/µ{5üH¨F7 uôµâ㼡ßׯ¾¯vg/ešéÒ5ø¯Aý%}Õ{ ñøø•¥Z_nþoÁ3  ƒ´€q&H2dÓgÏ:2ÜåxžHbîÏý`Ü5)/Ý_܃¦Ö¥ñîÜyñX¤Òð©õOúbú.÷”á‚ùZGäMÇ;gÅ“odmq[¢ü”‹£®© ñ_Ë3‘¡dÎÔuH°>°ŸÔÉÅüw()wܘÏgÄt!&OÙXÑ„Ëiy¬+ŽªäÉi5ëž_ µ˜aÊ«üŒµôˆø“D­Â‘Éqû•ýïÒÇ«ºÀˤÔìT¤é¢½Œ 5ay‚ö¡Ž‡îy¨sj?*>eF@táæìi?ñ+_ àÓ#jliº¬ãÜÇôYÐa5@k uNcãL‡»£ó`ý´·xX«Ë˜Ê…êhב}EÒŠÑèdåµp‹¨®íIr2/îCzJèBÜE­S¿»/@Ù(Õ¢Rwu†Oþ²ânÑLfPa,uŒ|±På O ÆŸjÞhB¤kÈ5‰ÛqÛñà´j‰2ÅL¶~ KO 1Ÿ†hÈZrÕ(?÷e*ý9PFÞA¼›«_ÚóHü±[õ7@ÁR‹­ZQòµ|Í…}=ÅÆÿbªj¤þÓóFœÿw^øvÔrßðë«×îå’J¯žQÕ{+D| L °/:Õºîªð*t+vÚó¹èîÈ U›ì}ÿB•s$ ëéåC×9 å ×T·FûZ’§ßï2–3xËäZ4[AèGÜc~+êµV`E;ý¸¬®]k@k¦yEo$Ptä¦õö÷L;˜Æ¿]úfþÁ¿Äkä¯ajÝÝ + 9Rj¦@3–™ ÓÉ)Yåaº>µ^ëÒpI¯>á•«IÍA œö²ÿ ãoÛ·z=›r15`ÊëéF›^Tj JˆK2ÖíÀƒM0_0éΡ>õÛ)›LDQ´}×Åö×ÀßÍ*øHÿÚÌy17B[û\¨8þ¢RÀn=ÊrÕã“­Ÿ3 ïÈÚ Í´j>\¿ö;=wüZH­Êî«•¬íÉôZLÝ:7þ`8½sNή3ÞGAHÞ9TÑA¼.øE?€jóN‘U9)ˆW$„ù]»A›ç-¯ú?@+“laÖžõ&J§ô¯},ï ØœÇÍ /S /URI >> endobj 63 0 obj << /Type /Annot /Subtype /Link /Rect [ 470.292 372.172 507.89 382.49 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 62 0 R /H /I >> endobj 64 0 obj << /Length 65 0 R /Filter /FlateDecode >> stream )Ø} y+7Ã2L!þ™Ëéìð¬…ãÓ¶ûâjÜÕ1c}9 —`!\?‹×‚?;ݺ%µoó’â]H#6' ›=üvævq1í׊ã H&pUg56{«xÜP¾_’?p_ò¥©ãM ÓGÿÜÕîR(Ïq1Æ ¢J‚,Øàžß Y Ÿý1‘ú<ûî±³´1µÉ?ÝFÑ’-Xç÷QT=¨³’Í÷3µL­ “8P(óZäÔü_ðÔs&“ć%t‰¡çÔÌ;q9H·½¸­ˆÙHÞä(Ø%TöÅ|úÿêð‘+aÁë$”¢âÞ­óWýQVLæN“J?CvIå^ Õîý 6„56#!ÝÖ³»wR‘ð[ð¸¾?š£g{wÕØþêáì­+­¨ûv>œÝß ˜»¶+àÞΔùùFÈ/2YÞhµ‘@Hï@DÂS èhé"ܾù‰âí4ŸÃm‹EDXâɽ@{S4 3Á&.V<¤Ó0RéHBRvx¦ÿF„ùY œfn­½N¥R™ºé¾kNõøÇžƒJcÆ=]ã°ª[’Ï-·¦ÁN_ù½³Å?ðclnã“Áண[ ÷2ÖóÔì‹=â•\vqäú>jŒÅÚá'ƒ¶Õõð•m&uèÄV >™ݨD¥>Ú™-§1TB#™¾Lù•?¶a®ÆaV¬]$Èì²µ®WøKoÉΨ «}ê«·"–á¾ýl#ÁYYû(Û€õÍÁ.À½X½SA—³Š"×FáÞc‹áï G˜*É׬ ¡rçýJ[ªS0ô^Ñ#åשØÌ'5È'AöÆ¿!ñ>E‹ÉŠKso ©& ï sb÷³­·Œ­É¦sQ?˜™¢XjÍ.G¹<ÈR–Ê`•ïáTÇà«Ðö 52Èøì‡"üï¥Þ?qc¹ø5*bvKEÚ0œO‘ôo(ç¾Ù¢6kï‚ï”~?VkNÃÙ‹Ê»÷WVôåMeæo_T«½”ø{¶±Ë&¾ŸÅ1y›áì¿e¨óÜì)?ô œÐÅÁtÎ \«Z+8\ÊÅCwÍ>ýkl oÅ:ärÈ/ ^kñ}²ÚBã`ûé^ûAÒ@)6ï¡&Bq«¨\¤&ö$ÁR#ྐྵÿŠwÚÙëÕ °‹›õe­¬È¥×+âAŸS.Â"ßYjˆÓþõ‡—…zsöû[2¿‹5ºØ!0ùþìÖØ>ú–¶¿¤Ðh!è‹®E/eö7&6.­ì¸ûq"å®|;—âV¯÷Re#åÇ$Ï€F¯^úØE]îc‘üWûnÕbiʼŽ/?w¨¨@í-JCð®nC«‰ù³zRH`À°ôéFé_BÛåTotbq°ˆ2b.{nŽTU5z U¨¡ŸdŽ¨Â¶6/„(éÈ=~½aÛÉ)ç™]ci÷a G6©Ž?  ê!à„–xÊ0»Ja~÷´Ž*üÕÔ©G V¡‡éåØêý è¼e°ùÚV^:Ä)1é]hâ  R…‘+Kv9_ ª‚Fþué¢.>OF$ çÔ•¯a_Ʀ¢›3Ya -Òú1 ³+°ýXd³}¼ïvý"A[QTGk´ôà5«“{SqÒ.zµpR:¯Á}ÕÒ¯oâ³]¼¯}ŸrMwPÀÝAeqž°Ù×Åð·@Ð輇ÅSÆ”" §“Lt`t®Á¦®÷o2<ÑúõêÜžõ”ÜÕ·Ç)ÏÎ Ž)¡ÚÒý‘ð× z†ài5|º¸¦Ni¡/'ÿ󦮄²ÃË.f;xÈÚ³ëI¸8'·¡Ñ á\ å ,G¼VBxæ·^ôo à!I½€nj;;nãíxR÷™ú¡¡‡ÈÏóæK¹*/†¶~§Goh[G$£OÙÔj71EÌ,‰Dò¯ € ›n1RÕ#pb ë¶®úÿ7C9¼ŸÁ@„ `o„ñƽ´T¥-pâ§7ñjäY¬5žÀ¡Ý½Mئîlj& £´|òª3ƒŒ<›;(QÆþAṅhy´_ž%²¢_Øj9gôŸXô»då½8ä(+.ïú3û™1Jµ~^b"7±ýV;“B »²V‘TÒ\c:¯/­bÇÇâ¥j3Ü&˃à­ÿ€æa+ •êvùã”⋘t’–Þeà N ¿ÍžÞ®§Au½-úì¿áè • ”Sñtöbeó¤¹2Ég‚V1~[ «Ò“]9[zÌIC{Ö%ÍÍvõ3UUåtc¤ŸäIú²ëΰ£Aë¤8ýÚ5s–ëø‚cO‚‰9aš?qΜ”4#ÖZ7ßÿ¡ü©”\|¤ƒl#L4n"S‚`Lš©‹³Øšüo€G*á »4Ÿ'WñŒ"Õ+å7’hÍPÚ‹ô™ 4N(%â´ÒŽ©i¾Þ¼O«ìƒGòÍ—Áí»oKÕ¸z¢D\)…Õ¬ˆ­D¼yøgÝôâ^“‹ xˆ ŒÚÚÛ‘èIÂÄxFwÝ€üR–»ZLïáP«’hh½CçÕwJ[åSWN”û1Rmœã©±ÆY!fü Çq¬Ío@T¤s(qÌs¨µcîÞr·°„Å:Ðà4Ô§G‘·\¼¤¨[qðpÎ%E ðf§îž~À¦þ¢üëNl0»Ê0ÈÜ`ú¹Ž;:%`ŠVƒC¼…ª÷!Œþ¢¯Y"Uy8aÚЯáç$>ëH1O”МàgkN?'_ÓyWÁL“Ðþà°‹6(Rg gm`ó8ÌiÕP9jngÐÞ5¾.}8ó`#Ä» ëh÷·î`È+ì´AíÉ^c_¬=~¶ñ|Éä&šJ·ºÂZõ½b ,d“Å)QC…72—9Yþæ2*ß?Â0úáµx+”üuWM^˜‡Ü‹Ô›h|Þ¯ ²í|ÌÊÌE-{‚¬GOÇ$è¿Òã3R?2)<ÊçÆ§t;uiž™vöP7*½®äº`u&Ü ªâ$fvJ¥¥Þ•Ã=ô¨ïN¾¿Ÿçl¥\—ö4_̧ï×ÃQ7·!"õˆ¨äʯùvR”zMøùƆ„€Xóúb°C4?›·q¬e¦ÇÍFÈÄóò«þä+ endstream endobj 65 0 obj 2784 endobj 66 0 obj [ 63 0 R ] endobj 67 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 66 0 R /Contents 64 0 R >> endobj 68 0 obj << /Length 69 0 R /Filter /FlateDecode >> stream ŠÄ‰·|äÅ-¬ÿŠ{ÛqØIû1V˜Ã„ï³Íû¢á“ǯ%ðœÜIHü@žUSX×ÐöëÀ¡Ï1sWó¢‡í ì ãwdÜŠj³;¤?ñŠýƒ™„Û1t¾ù;­G³0"œÍõ›û(Ô–·|‚ÖÉY¯T•œËj…F„JÁWæ&Ö48N}5ÅBd$Ÿ:9v\`öçQ£TwKžz¨ÎG«Ž =kÃI`Úø06À«£BjcÒÆù5¨¿¡óÝÑÄëÊÈÄ…1/'þ™ÇåcR"¾¤ÄóŽ ¨6Ö1‘;Ýò%’‹ |У5¡…,0qsø¬¸ä6ŠìÕ;`£#Å ,Œ„Ò4]žF/§„šoôUXcH9Ýâ‡4ˆf1gIü¿²äv"Z:éaWeS-.mÊs”œ«P–p–¯Š™ŽcßT—…RhqH-‡ô‘Vóžî_K|5Jˆ‹ !“z´”¸x±%šš'ÿ bç0ã³1Üïy†XV6³/ÅœJXåfÏ)0dV•L–H—† ‡Ù¸X¯ºÕ¸aˆ#µïw ½êƒ‹2¬Ÿ@YŒ£và—çáVSgU8r‡+rkw‘‘%vX¯y›Õõú (ï1w¾±"ŒïÓû'ˤ‘œYåª|v®¬a ‰ZÕlÎ(Ñ·aHGNót4 ÈÛïmÓìToWu4Æ-b# Q‹wƒÐ±“,¶3.Oî#ß\X0˜¯g—cð] EƒM!d¤ ՌڶéFVGÁ;Ú9av‚ ôV÷ÀZYŽøªõ…ÄWtœsËMüýz‘’˜cP ×H‰àsŽ«ªSNGs‹oúÇÎ Ÿ>·êiLLñ Ölçk˜±'!ü)ôÀ¬‰7 eÚÈÂýíb|Z1ÈÖ¥,cç?'Bþw&ºF*ç_ð¨à-ÏÚ5²“OŒQ}œCìýÚú_ô4öh{2® WèKÞ ýtÐî;2Ôë7‰e36(jæ>UªQ A PÚ’´ ä`}ɶdýgl—,’eè¤Êd5z‡A)¾$ÀÎ(Ü?YîCÙáOhùàÒ%N6N @5,–)ª¬^m锌AÓ/GŽoGž¹õú寅¼¨s’sê&/Ôd¢–°,IUÅb¡é”²YîS(xÉD»ÁwM°dr¾Ài|ϹGåJäy¡fÁ¥»2HkNéƒôœ»µgPätKç©>?oVæ"c´ûs+’uËœo–6—Âós*öÈ 8FSé†×šŠ}§S0'Íèæ ö¯‹”lwô÷P žŒL–é}œé…>ψ½a`ÊÆä ]I¸e´`ݼnç³t§²ÁBÊèq o§º“ôïµ#FU„†´)ÃRð¶/tB™¦ÜwaQl‹JÒ§o®N!;„w…©yn_ÏÜ;¤è§Á²vÿ"žfe¶rXJô'•øµ–ÝcYéèÙñ‹æ{ß¶¹Q.ÚèÂsˆ‚™ØÙn ;K€C÷þÓ‚ßKKô¶AœûŠH³Kÿoò20¼ØP,7l^ y~Â'A$,Q*Ï=.÷N;V5Í4tž' ÂèÚ”:ô&5ñ”q=é¬ìÃ3f÷5)oèQ”©ÛßH<!˜O1ø¾ÆjælQØ"òa 勞 Ìot†kÉ-F’5´vˆ>BÔäÖdœÌÀY›På¤rﺙ—®ééÐ=9ä%Þ í²7jÏü‘±íR/Y„à&o>QhÇÿ§ûº~wÞ'œl¬vu4Ì)N`ÑÅÕeO/[ù¹MÅYF$ÕQ¦ÅÀp›¨‚ô‹¼£ÒpUn‹Md]:w\b¾M/pž·GÓ gŒÁwV‘Ù¤F Q‰ˆe§ø×ÂéY’Ý8Zö8ôbµSö[D5جV‡Ö;½Õ‹™ˆû:³Ì‰EÅQØÍ„B‰Å LÜW5²3ºÍ†ï‚Õ€n•uùeêì%ª/ `[j”åñõl}3Œ~W%7C ¿Èî«Îv0±—ÍÒ9OSGˆ¡Ú øùS·–ÊR<}µ_u©eXñG€Ì*s§þûßù®ogKÆí­>'zèßù'‹Ø¬b_ƒ…·a1¡—úª«`Ïy–¨ ¿.Y´ÜÆz‰¶´[A€‹=›îS£_N`ˆ é6òŒÄ7xãÝo«)~ärQïA «I>µ¸2мži, &›mÁúP¤Æ<×m–[¡öžaÉ]zlt' _Å7±tDý‰<)e$T rѾI•Zó3ËT¢ß/ëݧœßÇÓõÇ=Nßë`¸¢mêI=FHÉEÙÀÂêv,“­~ˆ#{ôø¡¦)½1jXº%¸‰’è$'&ýúF¹n¹*I¼ïPÕOS¬ÃèG÷aŽ‚ðæK x!-pWcÌW‡é²‹ãK!ˆb'MÅ(ºä¬f§^Uœí/½m&#šjÛQ"ÊÌX‚‘Í(`p.Æ?W´å®,,Bµ>Ý  ½ßœ‡Ù\ﮦêïDŒ&~Uß5øB5ñÈ kE"-r!}I?‹%CÐ:fo9¯€oW/>zÌ(‹ €l1%.€8ÆìVÒ=Èšè]IØüNe!箜’÷}=õ©z8Bí8xÆž}vѹh7ÏÇŽIš5ƒ£ñã°Ã ©‹ÓôøtŠ´Žyüf&ä…µC!?A&ü\z)€€CLÐÖœ¿Sáñ”•y¢8Òy¾´)úJö‰`V‹úÓ"ÎÆwþÄØçì÷EÀžúĶN©ä†6.=ŒÏIœVεÀèqèj&çBv±e»t0bø¾ËˆvŽA`WLŽÂgv&Ì„À'ÒcoR?ä£(IÉ8îŒÜT/CÃ^xßþOZÆ%—~¹ÉdažSh@íI­¡§&…ÂÊgH™±d†¨­ý¿éçG]t›Ù*Lq€il,%¿r‘w's«jkÂú‹û>7W5é8ñè0’NV#çÂV&Vf‚æˆGYíI7i’,'' „š#ñUõš ³ Íœô‹ÙúBD9üIgI®t²n ï’ÖÒß+@¾÷Ò’ö•ÒUš¶˜ñK¤¬&S”>0X.¼%ô(Äâ!ÐYÍrs§¯œÆ4©~Fd ÆÐú[vÎÉ ¿HVWÜ¥,°µ†nC# à¬sZ{oÎ[b0…гb„vg¥ÂÔ«Èuwì<6÷‡Á¸Þ¶ï¨:Xû~Öìó» ¥Æ%ÖmÞmÂXøÕQ.'Qé•­ (ÆÐoCýk–,DÈðÇñ#ça·–YÝñ\Ö­ÿžD}Mè´­ãhí"~¡C‚âœ%Ï7ÕáÎï—¢®–/™NžúŸÕ”tø~¶T¶Býí‰ë¬AEL¾²µ„×ë“ú×ÊqïáY‚A± 5[x™&ÖS§¶ží2çô„  ‡"³«Gv2…r6C^dYDJ]dû©3z‹À Ï;(ÕõûÈn¯Q6œxîÔkI6?D½ÀÍ/ñ£›f?¶µÍªç"J&H}òËÌÑzó7Ëç ¡˜¥j½3˜+eü-WO¶« Ü-ÑÞÿ¾m ›ÿ`W¦wî 7W¦9Ûß•,µþITÊsr™ðê‚Ô<…õJ«²\n‘¹~µáz^’È‚ïÀ‰/·eË´cÅ=¸ä¿l[2Û$ÜBhŽ |›H\„gÌ{G…d2ïá·ÕŽõ±®‡¡[ÚŒž.}9i? ¶»f8¢¹4¡ç}cÅc {*ݳ.$¹cC²uÅÉK/Ñ> endobj 29 0 obj << /Type /Action /S /GoTo /D [71 0 R /XYZ 61.192 484.713 null] >> endobj 31 0 obj << /Type /Action /S /GoTo /D [71 0 R /XYZ 61.192 452.313 null] >> endobj 72 0 obj << /Type /Action /S /GoTo /D [51 0 R /XYZ 56.692 680.317 null] >> endobj 73 0 obj << /Type /Annot /Subtype /Link /Rect [ 221.945 666.657 258.003 676.975 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 72 0 R /H /I >> endobj 74 0 obj << /Type /Action /S /GoTo /D [67 0 R /XYZ 56.692 700.159 null] >> endobj 75 0 obj << /Type /Annot /Subtype /Link /Rect [ 239.974 592.96 276.032 603.278 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 74 0 R /H /I >> endobj 76 0 obj << /Type /Action /S /GoTo /D [70 0 R /XYZ 56.692 627.572 null] >> endobj 77 0 obj << /Type /Annot /Subtype /Link /Rect [ 337.192 592.96 373.25 603.278 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 76 0 R /H /I >> endobj 78 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 472.954 97.25 483.272 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 72 0 R /H /I >> endobj 79 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 440.554 97.25 450.872 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 74 0 R /H /I >> endobj 80 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 408.154 97.25 418.472 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 76 0 R /H /I >> endobj 81 0 obj << /Length 82 0 R /Filter /FlateDecode >> stream Ô˜ëñK³ŒX¢1_ñD9ÿ‚ËÍöÈvÈ ðûÒÞgDgñÒŽ©ÃMùŽÇajç9Kú.ÀÒ‰ÿFÅÎå¡p!¿Ã^B/F¸aj“ vñj{#tk¡#ƒƒâ(g©BªÙÚn57>id§ËÞÒSG’IKÜ0‚CÛƒyw¶ár¼¬Zï:f>—äjÕjÊ'~aHz £7BaL¯Â ñƒƒ5ÛÙY·'JŽ…ÏwdÄ/"Ì—”­„6òb×KŸöAú߸osÕ{>z}€'åñ «8G2½9WåÊäê)IÖéW&,;Ñ£™>LNœ3¦…ý8ŒoÓ¥b:֞ݧ¯õÙ½$Ÿ`e»5Ú]D>”¬ ¯mª…¤‘EÚQ, 7šŠÛÎfehiTµöIJmP¶Å$GD™½EFù‡‘žLÙ$çR¤b8ëþ³¿W`_òOP‡ñ²ÌË8æ·Œ\q»ãF"ôF cá›=ØDò'%aFP¿iŽÑ…bp@´bá]2ÎKˆµ© Lÿ5à/Å̤b±ÓŒ¢¶°àzÌÐzz™Qçl`8P«ODÌ´ ¤ÞBlG¥‘”<‹Ú¬pDÄ5®éü%ª}ôY²ê\٬΀®*·ÚDê·_¾öOËCõk»ç¤;Wzˆ,ͽ²ÎæÈ‡# ¿}¸RNËTƒŽr(h¡ÐmÝaã,ÿ!]6>æë}Êâ·Ó*Dö_~TdÅ™‘!²ˆä…î7¯¿q*¡JŠað ý‚Š1IÍÃ+š'~¿'ÆìÊE*:­3a5TÏ&ì1ȉ" Ñk£]*.éêr¤|)(áG­7®¹‡†ûSl[o¤µo6ǽÝô“Ó¯é/ìœÑ èJŽ¢SÓÄn– «ú—Ž:Ðáñâ¶XbãÔ»ñ÷hMÀÌlé½ .Íê¯{¯q/·«CI »@Ò71ÅïíU6áß%~ÖPÖi„#Î¥äüú›I“®4+?¯éª7Xq¯ç÷E¥äã^ôƒ’p÷|çR:~5¬÷GiD¼’%g±/ßjG‹¥FhÖùƒ·ÿ¦¹ „Ø—ò©®‡ŸÞ•nÐégŹê¥ïêÆ B/¢gBlnÊ% ‹ýTÖáƒg·ö¯™¥ïd@ýž€ ¶ òmÇ? øÇCÂÆŒ’ã,Äëtz^8Oa”·"2$1áxã"/ Ô±¢¡yø$S±?Èv´Ò›"ÊúÎ wÉ¿ÎF"‡’ßçÛ2iäÜÜnÌêöèÜ gõM°” 2æ*E)⌬Ÿ°ŠP;„ïèÁ 9¹å* ‡¡”küB¦=ó?§ùÐqöEó5–RÊ ÌÊ{CõzN²ˆÊŽfó!œs®t$gS›l!A*ßÛsX.A_¾Ìã}rѯ¶{6Òö‡Ÿ—Ÿ‰«†Î†ÏÓR327ï×ë’Šë;ÝIˆ^JËTPïækfÏÐ] —- ¢Ñ3Ç€%jkÑUß`„Õˆã™_Ù¾±‘qÛ\fqzhíD‡›mV.çÜ>˜O€›Ç2Fp­÷ɪç9î¾¹û×. î5gi̵g“‰zÁúåy7ÎÀ·˜ç‹Ô¡Z•2 AÕã9hû¸ß`ã~™–3Œü~"Î 02CW'j3üß{٦˿uî¡Üd·9R2«n>Ú·ú¿vÁ!œdµ¯¿ˆ…Œ•Éë$Ü™ 58š'Ñt`emË»ç.°å=Î hxØ)vñ\½ …=ÓÎ c5Qr’ôœtx;6’¤é±«;÷¸¾èÝž8CŒ ‘Úq"ÕÂq/þ”|èçø$ŒÎˆÛ¦qÊ;´S’ôõÕKæ°s­ò)ÅF]i/À‘*”ÈÄã £Ãxü‚„E~—ŽW÷²WWÙ’â±òëëæŸ:à8EùáIKXpb›Q€Rj0>WúíÃûí“gëI‹z›¢ß23d‘ÆÇš?N ¥¢…ÚzeñNy®sþß÷æLÛØ?ˆ7E äÑS:)°Ж è)ÝÔæ¿,HÁ1Êp‚p.ñ[£Iô$› –'¸²†õŒ\¸P|0\=ð*š•ü°Ê×6‰™}€KÂê9Zi•ð`\of¬Ù 3`[ƒ´Fdøú}Žedhñ,‡âÄÀŒ0þH2³S¾…ù‰»m"ök… 9­ þ\U™¹š8~úÈbÇ—œçDB†‘Íz©£¨ZdÁ‰al|’ÞØpyâÃÝ-’Ãã'Ôb€ÔƒÓºgµ¢ÅrÊi¤œj*%7ÿx‡tÚî3×Ïè~«þÅ»-³ö°RBÕÔgòÆ«nBʯôI!£à8Âαy¾Éf{gã¿ö,»U¹eiÁ´vÀ›+\¸î³¼®~«%mpÕ.Li-m¹†Èå ¶ OwwT@eE¶ª¡•òtb%ò½Ù7ýÐDJ³Aœ{¼Yšb ”—ä|Âä°í$Ýyá`qû:.ê dhì6ÍYï;v‚ÎYÀ¯Å”‰`Égª£¿J«fzÕ˜ÇÊ ´O<;³k>нHgoª¦g“3;•×?V„,©ì¬&/æÐ{íßzzáâN«€¤x=mzÐæ]f²LÍq‚©(ù~$«A¾nK›þ «ñ¥šŽ[ÆIó×®e{GU0A[É >å†EG=«ÏrÝlº²~ty)“2Òº2æ]“²d¥.{ú/ƒÀž[U°®M HÄäá÷C•Љï?i‚–hÐbÊÕ÷ÄŠ^ñ›™Õ\v| DÜÜtâlUÇùä7ÂiF‡ŽÛ•AG›ÆRÅ-`”/ã öôõÁiÄGÀR6=jŸE=‰}޵ì}ÃeáDÉ¥½ÖÒÏ[¸òq3åB¨|kz«‡Iñm·S §ÏïZ ²-Óöá(î* t/çôäGP ò÷%÷skØõ>¶ZJ®ù£–vEJZÇ¡=Fµ(OLFªœ h{+”šO·Ž*7¥¯‹‚jâ÷ÏYi|vž:›…eüÕ̤Á8:¸5Q›6È¡å`öùPÿ$œÍ*XÍØ†X mfxp}Ρ­LÒúÐ;P¸ÒØ2§rO@¯P³5‚ã´6­íbAÖùY6®€ê%}Ç'¤ÿz•^w²=ažM=Òb)I¾ù'»>¡(sª×öØîõt%6~>×KQ¥2›á1ËÏÖÊO_åüoÑw2ö´­§qDüîpI uMHÜÕ$bhe]£\HÆR‚%£w\åì)G+öA»Œ™ï[Ø9TB=!š¾n(@ÊÝ)©Ù#-RWÏrn$tÇ ¥¯"°J?ËüØÀÛíŠÈ*KE¨Þ1¸à#©"%,º+¸„ç¨àp7¾©4®¢>éDÀÓ”kÈE^×9€þRÉ/š´ÿ¤°õéÒ›à‡vúö&ߢñ±5l ä@Ü»áïb^ÝàÒã’ˆÔ‡ãÞèRÛ¡\6åFýgÃgym±ìì¹ÀžèÚwujpã1D.¾Ì;1ÑNA¤ óÃÚs†œà© (,ôR×`6æiêK×™™zÞqˆ‡¤G3ø‹r´›åÄŒbÛ©…Y†Hƽ ID›”ö0Õ\@ ”4µÂ±!Öþ6Š”'!Iýê9ˆaÄ´Bò«f[sð±ôW»À¶>®ó Nÿ¡ë׿—4Ó‡õâ$£ë!lƒóìä¾0†c²#‚¶äiºñØxX­ î;ÉÍÄr\QÃ?­ º;Šü­U  ÕV˜õ°×6p|Á[EŒAhÕEÑ á´¬ó]a@Љ§nÅd¸ /&ÛkWíMC /\U°Rä€Ðšÿa2%8n*Y™BÝôcÉö!‹U@ZÙi:¼pϬ£ˆ4uDÔW3&õ šT Ôׯr÷”¾8Æts&PÃ/òàITË\¶­íäÑ]OG üt\Æ@,h(•€Á•œ2º¼ïM3‚E½®ü’„Ū=ã.LáG¿€SØe­–â>°ÛŠ JMÀ) …].ïïÌÆƒüމb_’T¹l2’8mª¦­Ô£üØ ó À`‹:}·¨¾¤¶ÈŘG¥“)NÂ]#_C×Vê(]WÎ9„¬ #(§Ð¯:øu¯$Òm=Ž@È÷ÁäCAüŽÖ»àÎj5Iîåßݧ¿Í$yÉe0÷‡ U¹ФÚên‚ªúQó=.™0Ö\æ ¤S.D›š*Ã1ó˜ùü¨âœ endstream endobj 82 0 obj 3632 endobj 83 0 obj [ 73 0 R 75 0 R 77 0 R 78 0 R 79 0 R 80 0 R ] endobj 71 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 83 0 R /Contents 81 0 R >> endobj 84 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 699.716 97.25 710.034 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 72 0 R /H /I >> endobj 85 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 588.116 97.25 598.434 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 74 0 R /H /I >> endobj 86 0 obj << /Type /Annot /Subtype /Link /Rect [ 61.192 555.716 97.25 566.034 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 76 0 R /H /I >> endobj 87 0 obj << /Length 88 0 R /Filter /FlateDecode >> stream Ëü¨“¬EÉ»^½‰Ù[rîG·Xd@٘Ŭ¾*FÒ;h08}AZ|0"ÝŠŽ+äQ(ãw»©ˆ†ôÃjïÈãOU ¬@I™ÉC&bØòKßîâ÷¦€FJ«J3ÔfF^­^‘›Ì÷æÔíþÝÚ—zù×{eÅ¥øŠ ˆâˆ CÏè–¹K‚”üÉÈö€Mf´óD{.’Yþ±`Ðñzž|æ}îÐøe{8Æ*²¨r2ˆÃn ¬–óE+SVôÂëÐìÛ ÖT8H=VÒŒu.ߤïtTf9–Ó¢›4+=[ÚîšZ¾‚2åLT«bêø]X|ð˜%s{6e­Ë³ÓÞ9\v=º3ì\“"Ù–Ûeãüšß.nóÖ4ÓT—¨ÍJºÒÖ5¤íÅ¡—›­8uh|*Œã´p²++úd‹£¯ž,T@׿i° j!òï’­aUjÑ v±Äf·Ü@×]:SðÀŸ¶çCj¦*’¦ÓË—Õ‘ ÓlÜ4jöþIv4vÈÒ©¡%ŽzÕõDÆ€ï+9´Þ¤J˜[ ¦3#¶Kž$®õ˜¼(ÛY/“ÄÅÿ"%ùa³–—Ü[¸±Æì9¯ÀÑÔ±÷B½7{‘ yð]Fõ>½#£ª”øx6Œëããë­[èXo;Éx’¾ÄІj.²YºL0ˆ6Eb(0Š·Á\@–«™_÷_gBÇ⺪a{‚þÅÒÐðâÓÄtý™Ð`‡Ð™~ÜÖPûþÝ6ø”V^ŽÒß1Á)?åÆw| –g‘"6Ššó‚[®Æ0eù’Û’Ó‹‘’érS;áGöŠºJ x6ø8 +µs´=J«¹.Ýþòàá?¹¨Úòí˜Æs²±§‰C^ÖöCa°wrhM•—Ñ„îó5²äжú©ø€ aE Ë:Œû[LÅâÜ Ë^¬*FätÌ$8IPñÝ"nˆÙ £ÅÛ5ýñ)3ÞŸ°Š¯fi\*­]’Ö!¶Eòd^Lk?ÀNHl­ûŽˆ~üÎGîè^~Ü8 þ–oú¢Ë®|M=;ãq9*¥í=O¤n47]t“ n)u»Ñ96oø”›!0ëȨ¯¥±cüû)Ý‚£Š„\n<ØžâHøúÚ´• ¼@@ø-yxÈhÀÁ¸¿Zå)Hž†6Ìo¾Ã)2†*- Ñð‚ü€ôrHË!ÎôNöÇV’X#ZQ@ê_²ý·,–÷žgV„,&œEüNB8³ž?OØy¨š}aû¡à3nÞ©~oøeŒ.ÐùqØ&µcWÞŸÒBý—JbÌldp jaÆ‘WDëz ®Ý¢6Ô’sª7ý¹RvPiU‚g‡ºŸMYÈÆ× PŽ›—D8yÑÎ š ¼¸÷ŽÕ)¬Äì,…_L‚<„5źu}€æ5+ë>Ðm5räÑx9¡vNe|wpª šÂþå¸&÷\§ÝÚ ƒÚ`“áµÎ°˜Y é䪇ñËR°÷ë"gÄJ«O°屺M5µHè‘I*†‰Î%#âßß«‚ zñUß[ðÈCò‹>›Iˆ‹71Ü“DìÊp•=»±Í¬[軆•)œ¸¹XQr<Ô“Ù”ÇqÏï—Fç㥲{CL~ްo‡eW±”GgÑ»‰`éë$ƒOm‚*âÒ¾#Þîò4ᬼ/Px>‰¬_fDÄÕçbGSÑéÒD»Kú®÷½¤ñ϶>;×$Ù}%¼1áX5Ìøi÷¤>{ð÷9bðˆH(|Ù"57öÚmÝVb1’ Í®~•ã뱂ãïh£"9‰÷ÕçWÌQ …´-€†ˆF†>o¦DŸo˜ù8iÀŸ îâÀóŽäX¡®“³žã^­zöówÃRZ"ÇVdº Eóï›xóéßí%oŒ¨im©ábqߣŽo-BO<DdT¸} -™º!aÃ; ;T?ŸL?>u`†ûÛ]4P†J†>æ%æI,%è„sà ѯ–¶¢˜”ß…+ݵH7ÔÆÎ¨Ì…<¡ó„VÃ@Ìü„™“~ljYcvε٧+âÇFÿ«œÍtÕ›â/º C¬"Åx¤_;±ÏeÖ‰áõ£|W©7í±ê­Hò‹ߡd¯²oÃÛôdžtlÆÙ*‘-ø&lÔê'ž»4XLX”(™IÙÏß4¯_"=Ò[žù ñ'bát 4fÉdƒ4 9 í šŽÂ´p;ZÖïãí O䲢鹒!¹¨o3Ñl7?5ƾÀï5„Ëh#ìÊÏ¥½’§:°—0·Å¼¥Å yÆxŸšY9Ž&C'\oTÑŸÀ† ¾“TåX½/DèeÊ¾Ž ̤’"ºëST5þÆßÁ,®®²ºÂ ?°@ŒÚw‰¨¤²¬FîÔš†YÂWdüýë ÄÏò¡à€ñöùÎn$g—H‰ÖéÔ뜯ǚîúD™ ¤ºMñÚk~]ŸìV°RDP!lÚÑ׈å™+ĈꮴäÝR‹[ož]RÒÌe¡9‰:˜Œñª”Y‹µf˹+ßÅyV̶_ë¢ œU÷ôůcÙˆ’ÞÆl’­ÜÞCÝŒŒ_Uò(º+y<ðøOÖÐOKlöŸ¦ôp?ï-Ѓ[“h1µ³T&%¥ 祖¡SdîG^CÀ@ˆ¥çÌcÖR½ñþURu()ÌEKýìºÆÏýI•¢OS0À*r endstream endobj 88 0 obj 2560 endobj 89 0 obj [ 84 0 R 85 0 R 86 0 R ] endobj 90 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 89 0 R /Contents 87 0 R >> endobj 91 0 obj << /Length 92 0 R /Filter /FlateDecode >> stream †Ç#†|ØµÜ TD&¾g³ t–"” »Ývq¯Á%£ÅAŽÜú/¶"µOÎûæ á¢ø$Δ­Ã&ä yÿ ; ƒÑW’ÿù{ë¥,²I‡?jŸ’î>ðˆ\ìÀÈIz"§¡Y……ÿ"ÆE1Èaxø1‚1Ì Åú5>Dþëé‡û&ù^ÉtÔü.&îN5G·œ½µöïÞ(€‚?ñ·ë,LS§nДºCž:œŒb½ýð6ͯëõ‗[Ocs]ƖÑ- ‹ñlÕÞ3ʈÀQØäÛÔqò6îc‘jìû>H h~ nŠ×&)ü õxÐ|$Ecfqð…¤%ô^íÙ Yo¢Ëíd'“¶î“ob•ÙòÏׇ#‚ÓG;4iAb‚Ý«hËFôB4ôãR¥¢sÿtk€ ÊìÂLˆçÛ/.«OL﬘5Õx­¸Dù¨~fo\¥~ATjàVø#a80¾úØ-C„´ì‰½Œï$à?'Ù‘iŒ:ýG KpÿÊLÇ™ài¤:—eÈ_ñ2|Ÿz|&—)s4ô¬”„ê» ‹8ûåÀM€õŹœOÕG#½n«/Ľ ŽÇOrô¶Ù`°b¸äì*ßÅ®Êxe¥’Rj ‘zîÁv’fÈ>PTí›z¾˜>7m3#»:_’á«|çûÁ(À°&BùîQ*ûŠ…Ÿ¢D(A1òxò’tSÁ³*¾[–òý5Ê¥·ÈâËi7(^}Ê8ÝT镯ƒ}”é’ó=e6Óð =?¨÷Ÿ©D54,b¨SëA“>o¾È^ÖüCÜ4ظ?$ÔóÕÒY$k‚èÕîÌ$¯½Ôi—ÄÝaœM˜âyÄVÇov5yJxkjä Xî0¤À­’4»z úñÝÑ_äÙa õí!ÎNnæQÂ;€ t)nÿ£¨§“2A è\2- åAØ/††4paIE`¬]}£†áWcÇ9fØÐgx ‚"îk]:Ž'©ÔŽÅC¡Î™˜%ˤ9rw)·šfú þÂg;g"íÓT,¢˜Þ°ÖŒ1[ò{…”88²¨jMä0P3É}î†Êˆ+ƒµúm{¤æG™l,èÕq#ºá±+¬ÒÃxåHóyÿƒptÐþÓåFñ Î7:‘ò_Kƒ-³òâ©s¢¬#• ‹Ô-i÷½ aŸ.þ†Õ6ávpNS{ÛØ‰,{Dì@¼ˆ°ÄÂ\/x òƒQš]Þ7M>íDЃ Ö_#A¯LK×Ö!§¸ U½»·³­5j©býà­¹èãßqCþÖ‰jñß|ûãñi Ib(Ta8–›û€¡R endstream endobj 92 0 obj 1216 endobj 93 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 91 0 R >> endobj 94 0 obj << /URI <9BED5D471FF2171AF9F35EEB05E8E6BF672517FCD318CBC2E91B65972DC8EF01D9B8F29968079C4DD56C8ABB69EDFC6606FB028B2BB6E6490D858C163034CADC> /S /URI >> endobj 95 0 obj << /Type /Annot /Subtype /Link /Rect [ 187.537 564.613 229.623 574.931 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 94 0 R /H /I >> endobj 96 0 obj << /URI <7FACF98E786476097887FD3180F9809918114A2FEDD9F13E7C331321FD32FB62C39F371724242820A6237BF8A34E1803C16A68A9F88DAC0446B8994BE5048498> /S /URI >> endobj 97 0 obj << /Type /Annot /Subtype /Link /Rect [ 249.687 564.613 284.755 574.931 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 96 0 R /H /I >> endobj 98 0 obj << /Length 99 0 R /Filter /FlateDecode >> stream Äõ¼DI±r)ÏqRUÞÏJ£ê*øF®^Ä®‚ë®Þ¹â³Z£F*½½å–Ólvã¦à˜ë´òÈüŸSå¹¾o—š”^¡°ž ýŽÌƒZH£w),>cAtxÊ@·?ü¸ÅF³k%—dKÖyëhÕêNVKÆÂ0ª×¨ùH%_ö7jk'9Çæ•„ â (6ÃÃ7KƒõcŠÝ¶ƒûŠ\ ´_=/­U8œ!)Ï{°9aP¼scbEXïD©úG›:¼éÐŒváÒì瘨á*‡‰Dä¦oÑ*×& ºŽOžåé‰xztí¼råËuo°0‡1¹·ÃðLºÍÂioI|ln3 LA®-[\%jw¥Ý7µcϯ’%À†íA!]ù 8ç²Gdª~¯Vkdjã±ÒYpXÌãÔZËýŽÐw|¦×˜½(8§Ã%¨ E,¶ÂI¨qß^Ð|‰¯ü”ÀSÇ!ú«ÁÚæ—2,jæ²6ðÊúÙg b=•1gŒ‰¤ûÈň|fû›?ÿßâ 5¶&(™ÄŒÑškBéúuWÜ/~4O39 ¢,Iì‘U,yþà²Ø+Ym  ø­õêÙZ{^áì]Á¸¬ŒO¸ åo{"2≽ ƒt™‚Ü„ýPÅôšévÓ}äýIàð&ÌØ „ìº6@ÃÄ‚ˆ“´9PUB¾°vˆ{|µKçv‡Æä¾ùÝ2‚XLnР̰Šù`ÓÒ…Æ^TNGöFïØ—Ûwf²#`ùˆW;2S¬´˜w/*Xª´cá¾Èé-V ÖÊoæ‘ï^2›d&·cä_Ý£žMUõUNªRé 'ƒò_X(‘6JˆÂ¡ï»:‘ÀQë 8ÂIH6B­TI‰¢"‘}xqÔ›ìŸACÒÖy¢@ª~•ñûnE]6E‰/mÀ´åáè% ‰!Zà…á#¸ÉŽ3r¾?§ÍÖáíUZTz%W@ï·+Là×0ºk¶ç»Mb„3@ÍÜr ŒJ:ywRŸ9;IÇÝí®CZËÝÿ¸ÿÏÅec&M†…’˜‹RЧb¸­Hº&”­øû@‹Õ’m=Æv¤í-G‘Ê!'Ò Š!ÎûÖù½?]õŠÝF]ÞÚÓB¿ƒ·z•åuÁýFj»Ü?…}]s£ SÌ~Þã¿Já¿»Õv¦9qõG_9FÉö¡ ÉGòAÐõRå<@óÈÿlòÁOnò;©'úr0»šª#99Ê»ÇÔXâDWèJ"¿+‚aÂÂAipÿM=Þ`´X5û}¤Ã¸]‰D…äþ'×~itìÕ]àþ³I|eÝ?¼›÷»ª‘Ö16_}Ie­n»Éë¿ËîXí`›%\zšd¼íý ÌÅ>©MIŨÎvÀ§gšóÒeø}7Õ%²YÛ0PpJ\QS‚Q7½^L™6|† Û"ßP¥<÷šžŠ§ Óî&§CoÀ]³O®Œ_U Æ[è¸!è‰ü&¾z¸ßs‚É߀?t`_à7ÚäI@Ï6 ª]J‚ZH¼¯©¨)t€Ø7¢ËSmµÇ$5ÑÉœbÏ$[_ÎE‘MGˆõÖ×Eð î’˜Á4Ôñ#×aÏ“Ž mê¬Üuï axbïßím¢çY!d@8‚:HÎ䘔ù|²ñ…Þ Ô£°œŒ¦¨Ô¢&èErôªrdÍý؃£õFp®s‰ÓŽlyq5—]}Œú*¿v¾ }Äó ØYê ÊÕhÆ %ÜA7cxOª€ñy?Ù™óôà£ýÕÍ™×ýúë4S•{½iá5ÑÌ®6ìcŠÕ«õ¼Þ³¥ßzݲW_Ãu¶Ü }^¢êáA8Xg˜ä»M`ÐUF¹+%úó²Yï}¥=ªu£Z´ç„˃RHœ¿i¿E­õ!wù<žñZŸñ¢¤|Çq%eÅYz‘\’/»4(O~ù‹™ª[2vÂ+‘L0 czÀêw^Õœ—ÚlÏ´ùÛÂÃI«œîo¹Ýßiͤ,§‹"—J;,W:IESøeªÖ„|yÿýAFr'¢ÆÓHSÍ©%Ýé@ (Œ.çWhщ7´ŠšQRÚºaEr â5^;wâ–Úx÷JÎ%–­®ÐèÏžN¨òRÚ‡–óeÓ5æ¹3æ¢Õ`’p)û¿$2Ã5¦è C Ï¡øGˆUø¦}µ­«¸kIb¨Ê_Eä§Ç€ŠôÜ[}T­!áà;Ö«í=ùŽ™ún“ЬRÑôO•lý`®¤›<ìª70Ä(ƒ†àuŽA¢¥Óbçø—nõÚ$îv¯ˆ)­ÑµG­E¹SìµÇ»Ú/ ƒpñkNQkï†Ìcɩ¸U#5ö;­T$ñ‰ OŽ´#Z%*q.ée¹•¦1 ÔÌÖ©#ÊÍ|ß{-0š»9cMiK‹Z7=_Äz“Æ¡'Íóâ*4ƒŽé˜Jõæ Yþ–¾Va*.¤yñëý.dñ?M˜e]V°§k.Ê57øŸBSî€ Üº|>ísWû Ø¥§óHS´y#˜ø"Óš¯ù¤[õÉ€ç5/´˜HæTwÁÐã‚åS³ X¥¦™~±û‘ EÝœ¾Ç»; ÇXÀDÛVÑ!h¢~A˜,ø¾àc”÷´^™¢§{ò4ï°,ÖüIz¼¦lÔÆ¾Èù-BTÿnJSv¸íÏ»ñ¸­p•¬C_7uLɲDs"‡éÔ„€…BkÒGl€ZžéKy‚^¯Ïo`UÝdÓùD¼ñDá#ëÒSÍbrO„p,—"p¨ì»¬çn_q¸ùžrÔÑ̲|‡¿!ÙX6A¶$€4·n3DJHYþ›¦†Ém¬·@øzézÏBß#„CsTÌ@ÙIŠÜrf4É šàãdYÊÒáê2ÑÛ%)ú…ƒa«Ž°^;·»fC•»¿0eoW Åb/l¥ 2¬åÎs½Ø0ZöYÜ€ßÏ8·lþȽù~Êbukf*Ø=ßɘC±ãof¡M%`íw5Ô‘5ÈJÈÕ[9wMB°•œ>Æ9áýõ¬ã à@:ÙA*´‡l4@[~E¯m‡¢Msaw‘•ÿgòšU)ƒÃÙò¤®Ç´§‘µ„9!fþ”Ê/•HJYµ+!ý¢v¡ß&ñMx:œ3-ï=n]õËN½@4¥‚zÄü™Ï€BKøn¿œÓz¡» ÝlÛ~úÝ$ÁäÙ"Ø\_ »\ ””BѰj9þgm¨¦Q:#¯£\´ß ¸Ï2=|ÝP¶y¾ÃM²_ùˆ×´è!lN¨Ø''Éc*VŒØ›šéUùÚ·~j!ÀËÿÿ˜Ýx/¹"Ë ÑWÅ]ÇÝ&߬MxZ¦Aæ$ÃÛ×7ü/Á쟈»ŒuæÝ„U4ƒ‚{*§¬š„Ъ×húΟòb3ÇÓÍÖÓ1˜ÕŠ!Kpƒúªl~Æ›­P—Tz‚«é¼Ý5¹ÂE&¾`1žHh¯!‡<+?1 &¬jƒÚ]1D†1-ÏÎ^!A7u’;¿-©Ù`>ºwúƒEÁ†ï­t§ffÁºUæÆêâO»rœ­p™:uâv&rkízƯÓ{ò€¼ìJÛ¬$ø[r¨~ïvn‡± endstream endobj 99 0 obj 2896 endobj 100 0 obj [ 95 0 R 97 0 R ] endobj 101 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 100 0 R /Contents 98 0 R >> endobj 102 0 obj << /Length 103 0 R /Filter /FlateDecode >> stream 8‚ô*#g_H ÁJˆ Ëëc%q?è š2Ë9Ëÿw">,v%«.Â=¯íŒJ¿ n¼v½–. ¡“9œÉ6f¥\DHQ àUTî[£…íê×q Œõo³ÃÁjºÁ“¾ö~„£êYÜæCgùqFÂ,Þ?l =ÀNPãÛ%XMÍWZ‚ÈYÃ{bf«~dÓè›É\h¬ÿi+ HÉù#»-U":fª#wîsf–¤^(šê´ÕmVþ}iL‘Á›"V(TÎws˜Õ“ëRÜû- ¸BHä¢Eb¦˜JÅYÛ­q#Lrj0 ÷þ…3§4fíªR •ŽB‰ÝÌìÅ ÍpoÝòu_+•´¢Ää6^ïrzEPkß”ýr¢k™!1+—jAþMLeºÅH2ö ‚›ð¸æ ?2d.ïAzK…ŽÄA¼@ùšoòQV¿äHCÏXƒ?ÇÉãPÚ1‚þ™Þ¾ÍX­Ø'.®³xãÇ×@Úþ¿ äT¯(FùºN®=Ó˜AÏ[µ”{Ã.)µ¡4;1P?àp<=„«ø6·_×¾%ƒ£Š µrÒ$Ÿ«&é.Éó>^S;×|šÝ¥î¾?ÐwÁ®C¼J˜9^ 9£/(Mà˜l)w% óoŸiëŽ5¤w Šh]¿zFS×ñŠËèvæ²1ÿ(ÞÑ•¿@x\,‹Íˆóïj$»A~ýA¹Ûߪ‘’«Ë…2Œ*½äª ]QUÂäxõ³¤".Ei¯¨»ê×bÎÁƒg¹÷èP~â–º†+¡X›ûÛ(w<#Óœ ECNêÚ¸ÏΉùUU=[ë@yš%0ì€i ÜÍ­D¬Öu€ï`U¶í¸²K¢4橵€Ö¤›ë‹€RZ&«fÞîü M5uÀìà|Y(ä#YšÞ4¿$ß}w¦y~l æ»+¶yl™–ƒX›¡ìýÌ:>•>9™÷C_À;¹Fÿ"Žú8?¢úb"öymO‚B™ú@Ú"Ùg+ÍòoH¹Ê)QÃæ¤°ÞºáúßT™ÐÆË;<E±úQïºÄèÏêšÊßöšÀ}µâCÌ ²v^+m Y'ê—È.‰Xîþñ8y¢Ñ9Ó·ZjÚ°\) ²ªHódiá°R‡³çÝ+vD?µÈ%úÍsiýE~Èeˆì’' –—ßÛ֟ܪð«¶ò}ÉPƒŠÁI¯¬ ²5¤Ûpùž$Çg4 Gfî}m¬$ª]JðÛeEb öîç—ìm|ÔÚyL™§]?N’†i÷[¯ &d¬ÞÉålûjJ¸ZùØ®ÎF!¯zn¬ Ž\2œhÙàãü— dcÉÌ)0#¯I<±÷Î(…UÝ))ÅÔŽï®:'â °°Íÿ2a’<:`Æ79߉™b.-å ‚¯w™)AÜå}P~ʸgM,5cpÇÀ£ذ‹ Ô`ù]®Ù»ÕnIéŠä+ƒRÌR%ÞïÝSØQ‰nqEÚm >w§â”qó‹ÓºÑ2ã¨7@¢®C”©Œ£# qzôOTŠ–/6ä$µ\bŠBÙ9YˆHd»]α°>ªéšÔ\·’åšžºEÀˆÝÿgŒœob $”¬2 k No3c¦‚Gÿök7:ÆW(‹ÝLŸ‚å¼Péæü‹!«ržÄÊd"¶}¦¸…Æv ö ®­îjsnèF‰½n4´ƒ]Aÿ¤Ò"òÜ^Íž!’<…@ERUüÅÌô¥6~nŸŸœ[1ÚNNêI3óCù’VóZDð±®èÍ.mBÎV’´k›éÝ/.ÏJrï…”íÁõbdØä óãkK²øupò™l¶µÆsâÕk(Ób“FË ÓÆ iøf¤þM6C"Ø"¯·Yuç›òáÅfêva-ŠÈLNV„XHÂáebvŒV0-ï#Õ,6´Ç|ÒÐÆ„3Wà‚%³ìa©þœ1M¨›Tãfà·•Úµ.­øžDc¼UöÏl÷ o$¶¸ƒ±ä§SÎ`ë(ÒwÐ 8­­¹¶ò¢z÷WÈ1r6ÐWMdñPtjsh‚çæá*CÙ<¦lE^ÿë(G„B[Sùø"ì5· (—ügŽž¹DhB÷ã1Š ¡ üÞ{ÄBÇ.áéüȹûÙº%óÏT²Bé½›øhWw141€E?,á.©E‘g‡0’{É%~ Ð1Îð¯9¸"ï Žú endstream endobj 103 0 obj 1680 endobj 104 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 102 0 R >> endobj 105 0 obj << /Length 106 0 R /Filter /FlateDecode >> stream nâ=j¡æÌÜ[‹üÑÁò×Å{\ÑHTKÛìM…óÉסëÏø›ßJ¬,b**¿ŽWf‹ˆ=z)Lupuƒ«r³IùˆÅÍJGoáö„´›Ä`œF-©ÈØI§º›£֕óBÑ9; ˆ;i¬¸Å¬t§GRËôÓ1³”µcI™(ô˜Ž D.ˆØ3I$ÌàT|<Û—Ë߃Îô£j98çvk¡¶4ݼáLË:ô®t8h9˜6E¹it^–âô þ[­S¯«ÚÞ‹nÄÂy£S}ÈÊ§à‹–‹B±Ð¡„w/ù£sèÁ~˜CMªºË2Ý68ŠÏ5Ü“YVëD4pkÎNm_BC)ÁG:“Z,¨jÝš˜²n%li]$žÿ+´ lÇ ,$ø’â;aíhUr¢ï›b4¨&¾Xw„÷Sà8Ñf¾Õõh4’õnirÔm‹°» A¯¿.g‹¦Ïã F–‡_òœ%Æ` P¡§^—ýÙ˜ÿеp9ê•òÒoK«K‡³ˆ8–Ì‘>1.ÀÜ’†DUî‡Ø+´—S щýÞO4!.r˜¢MË({Ê/ÈãL'2°ð«sLX,»o…ò¹Åà§( «Õhv§À['ˆØÍÒ ¢,v^«ç"ð…¦}þœpýN§?½æ>hÍP‚&}xrÅnôǫ՘+…eºa+´Ì%j{c$ô›X&c½‘×ì;é€gÛ“=ÄlÒ‚àIRì—_¨|Ô²ov&e”ZµIަù†m%*Ãîô_Uh;OóáùÌ -À% Œ*oyóÔ{ ]ßèm¿ÄÚ5w¿€†ÞÛ_ßëjêUI×x'HUé-³¥e€\3ˆ=HŶf| Fiæ}ëdof0,d§*·¿G?íLs6dmtÀ³³n]Q,E„ÐîÞm7â¨!bL‚ÍLßµ$rcÆ©]bÍ® Ú„/ÀtÉL«štñJ&GÜÅc–´xmÓ£7‚*¥›J¶ šé’f f)§”·(¸„¹…Œ×6tzÀ‘Ž…ÅàìÖ‰X‰…Fdw¢d×+p[-Ì™ÀÀ0;O®ZìXê”™#(ÑÉδÂÏÄ Ëm‚:vëRn'„í ¤W8c s“C\H 9½ðRôËgÛÙ|xZT@¿Ì.? ¿F7_¾#=íeZä/n×XËïOÚ“Æ|–bû‰ ÎϾ9H¢Fñ¸À¼ñô7JoãL«2¬øà_þƒwªï?‘iqûd麫ÁÞcü;[ÌŽ‘Ù—‰¾B§4…ð&ªÂÝ::ÁxPÁ3¥F¡áToÂߚϜšCÇ\ÕAF³@Àãád+.™8u3 ¹Á¸ÿ‘TGÏ£Š´X:­ö.ªšlðSN`ŒËØ‘îŒòàÚ¦ña€É_vϘD¶ "èÙèsuz÷f„±ýac –¼tóø°÷ª+<®¶5Ôï2JœhÚJ‚á, ¬óFÝÕ„æe">L? endstream endobj 106 0 obj 1168 endobj 107 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 105 0 R >> endobj 108 0 obj << /Length 109 0 R /Filter /FlateDecode >> stream \ žsä|+ß0j[̧x {é£v7&އN™4鯄®Þbg–°pƒoš*AÑÜ0¼a.Ùj*³uvÇC¾ÉŽL*D(×Z£2§E˜ÉIZø›³ô£˜ÍæòÑ2úYúéoò·÷DR}}Ü„kç³…F¹¹Ïucª¿šc‹ ­2MYú}RßÅ- 0Z{žœp{¡mpüÒ¼ÂXޱñòËCÒ_5©.á—™;khx¤JW«I~#i.§HäôóªöBt dô)ôcl±ajtúíÈœéo7Ÿþ„Ežvä®´>[žm½ŽYê7Àñá‹E•/­~ˆõûD²q|NóõŽ«ŠÍû¼s}X³‡—aý€ Ayjf®HøûK¡ )êè¶ñ´¶»–ÂPp¡{‘诇¾ÿ@` ³¦èVƒ {ÕË?6YjÐ*‹}q±:ðÒ$݆DQ§šÆñ‹œ-TÞ>UT<œÈ).-ôƒI»rÈ©~²&h£Ç¤@-Òî/…_X¯‚ºwb!ˆÈU‡€KMÖ¬AºŸ*§5p„ó9«Ïóótï­;w_ØIËÓ\…¿éÁÝ ¨áRE€¬ñëV)¿út9AäŠÁVG–0Zq²Çf€öj´7ÅqlYOqhÀVøÍ) qQØ P&`aNÃËù[ª†Î3A 8ÒÚ•-0¼Uj9EƒåÍúGÆ„™VܲäMo_ <ÀÀëÔ(­‘MM´}ÚÏ7†MWÛ9puäYáÆžG_6‰¡:#å“R³{1GZíì&»Ý üq³¸u%Àñ ~„"@¹ ø‡0q–ÒIÍÌß‹|›½ªðsf|”žáú. Õ4bp£[˜c38” úxÏâÉ?zžô"7 ¼ ·Ø SܘF×IôÍä—X&ð+Ñ›\›»é=øt]œ‚§¤@ª²øŠYfy)Vëï^’³˜DÍšùù*¶ËHþp{ÉÎI¹hÓí…ÅöÚ¼úÇduwwÀS»o©Û–½‰ªñUÚñ™.Ë<è ôS~MÿØŽCš™_—ç!=ã#q¢'áÉH Í“‹ò¥#tìŒ6k4ÿÔ@ùÞ¨wÄ!SQø„¤ ñ;ÓFCb®”ðm½ÚÏggT»”Ñ£«èçÒx 7¤¿Èœ6Ë ¦£b¬çͤT‰…J•©nëg_˜X1jj´t¯c\2…r°?N)7ÙˆÒ.– …Yí"³á³ˆdAX ÔÔ‹£çš‰x[iìdûxψÈ#ÜJp'¦¾FmÅZ'c¸øÅŸ’t†ªÜêç|̕ǔ ÉbÝý±iÝI_é6IŸVR§ˆŸÄßžOAS„] …釂}pCu¾b\a”úâÑ«ÑíÆgSÀ]þá~‡&sÝð™Q7¯¨µ:.Ó$a±sRuð½ð–_ö!Ó6L´ ŒÌÔ¡ŽÿÎ൙mÇj0ö*ê]p«c.h»å<ápvÈvŒÒ¨r.ß]«¯’\yâoÌÞN\YÃȇãd©Í±hzkŽçn¯lOuc]óÊ›£S*¯§›Vé.t؇£Ý ­FìÉ<†å[8Kÿñ“Ò‚õ†`Ô+±òv¶[ö…õ9•žùœ&‡*é〆aè×—ŒU­ÝV›P,W‰¬õMóÓ€üæ{»•VÞ½p)šZM¿<÷"ö ¯]šw³Ü=H[áåÏæ• ßî÷Þ·"µšõÐMB.Ž/Æ­ iеjSW6ÈÅ8¿^®¦Tp ÖH‡ÑÒ}SïZâA‚5sf„ ‹qÂS÷g…ø‹n¿„†ª›‡¯èåÁƒs!©‹5k–G‰¯> endobj 111 0 obj << /Length 112 0 R /Filter /FlateDecode >> stream ðŽ̼4yl·®q{¸r74›Ü Ç^5íq,bgß–ËÁJ¨þÌ}—xåãäT¦‚•R×xÇœ€‘Ã; ¡ìoOyMøùïø U7[õt¼L:ú0 ¡òP-É_±A÷ªäxe|#ÖÊÌr® ï1²BÖP«ù²fzhÎ •qàªWX„ñâ`r»y)½p¨(zûêÍäÀCTÛ Ök?ÜހРûsG*Ô-ý ÎE2#mögákî#M!Œ.GHe°ß Žž‰ÿØl%7j¢ôÜ$èsÀÉ>c½+Äœ­Hö“Ño¤!1!ܬ¾çzð¬eƒ aÀªëEl“È¿o»L®ê4¿üÙXáïű¸`û–ˆ«¦'$Kÿ”váÂ_.a`*…¼1´‘¨–{"=×9ÔÄ|ælç2¦¬vÛ£¼ÃX'©„…é|TmË/ û1VªœÆ¢ÊK b Þìx¢°ìçaÇÞaö­²¿tB» ý»€X°-ž´í¿Á^c\{6'‘< k‚krÕ½&Ü„Fù[ÏܯÂhË kï> 9)‚–&k9&ªœµRM$¼R£´i””·‰$¨ä3S¹¹tG\Êã4ÞKࢋJp[$ ¤0áèÉÿ¾.v¿>­üÀ°|Ð6KþN±˜W\l¦v9¥±~7“ b„áo5—Q•ñéìVH@EÂ7×àÁ3Á“¡¸ÓÑ^] _ö³6¿>$«§T¸hM¸s_?çaT)¢õ”\ýAá× H!›TºÛ”SPS°§‡iœî¦7*¬èµ‹ï˜r¨§=JBFÑŠMÅIéž¹šÙ’åÈ¥TòØ$Ê,…J$“b #ºx¹¶CLG@¨™: €¾ZwfÜÆ»ö˜Í¯gL z)šL\ç.̶äåé¨ocm[M?&™} 'ÛÈ”i0ßÞÞq噤×ßl‰'¢pø’U/2rÈz™šÅ›XoYÛùÍ7ô©£ûÚ‚¹HkÃil½4Ÿ ëÖ'ckk°ÈV),ÀÖbع)c ¢©¶ØS䤔ÀÇ2&<þ­Ézï©^ÿ—˜°ƒé.Ëß%dG”dNQÙøÌ6½m^Ÿ!½ø-²þ”éˆéÜ^:I«…—®TmÿOðl­o˜\ì¹ây·0·BØWêt.Õ@÷Á¤¢õ”OžÈ‡\V{ê’@œôJ%†ÐQÍØN(<€pw´‰=­ §j;΢±_ï#ï\{ÃM¬QèYž8!— §ÕR=BQÌ€¨-eôÙ¨äG‡‹Šn>7þÞÎmË*.ÄHŒ¾L—¹£b2¹—ùÿÙT\ÿ‘”!×yœ#8º³Ø˜­‚2oH$—ÜÃ&²ìý'Rt¨ö^a„‘®Š[‹)If\U’Ïåh†½Sˆßâ&`¿iJdp©Á=L,‡å1´È=ÔÀ2Âð1”»Ìþ*-í\ me5"9Ô¸3„–ý?¨ÍVúMÿgôÃ/ŒëìÇâ‘ôðSÙ^:È*p>ít ‘| ;¸û·¦|Ük´fMñS×HíÄ?jd\l6!æNE6Ã&7ÀkšY¼ÙØžÛˆ™ñ·îuçic2(`nâÑW†"Ô§ð»Å»,\çq™ŠÌÊYfH:íüAuÅäÓ2ûwí-¦Pvq[ÂD<*Ïeõciï¼ÔhÊhc脆bê1v …Ç9ÄLâW9ÍU~…0GÍ:­é'¾¢ïyè9Í#¶~}Ÿ\ ÿIÏwÎÖm¯™+2 endstream endobj 112 0 obj 1376 endobj 113 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Contents 111 0 R >> endobj 114 0 obj << /Type /Action /S /GoTo /D [27 0 R /XYZ 56.692 771.023 null] >> endobj 115 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 706.484 61.708 716.802 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 114 0 R /H /I >> endobj 116 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 706.484 209.812 716.802 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 114 0 R /H /I >> endobj 117 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 706.484 535.492 716.802 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 114 0 R /H /I >> endobj 118 0 obj << /Type /Action /S /GoTo /D [27 0 R /XYZ 56.692 734.174 null] >> endobj 119 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 689.033 69.232 699.351 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 118 0 R /H /I >> endobj 120 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 689.033 171.268 699.351 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 118 0 R /H /I >> endobj 121 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 689.033 535.492 699.351 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 118 0 R /H /I >> endobj 122 0 obj << /Type /Action /S /GoTo /D [27 0 R /XYZ 56.692 612.289 null] >> endobj 123 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 671.582 69.232 681.9 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 122 0 R /H /I >> endobj 124 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 671.582 181.267 681.9 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 122 0 R /H /I >> endobj 125 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 671.582 535.492 681.9 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 122 0 R /H /I >> endobj 126 0 obj << /Type /Action /S /GoTo /D [27 0 R /XYZ 56.692 388.358 null] >> endobj 127 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 654.131 69.232 664.449 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 126 0 R /H /I >> endobj 128 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 654.131 194.808 664.449 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 126 0 R /H /I >> endobj 129 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 654.131 535.492 664.449 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 126 0 R /H /I >> endobj 130 0 obj << /Type /Action /S /GoTo /D [27 0 R /XYZ 56.692 272.142 null] >> endobj 131 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 636.68 69.232 646.998 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 130 0 R /H /I >> endobj 132 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 636.68 158.013 646.998 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 130 0 R /H /I >> endobj 133 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 636.68 535.492 646.998 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 130 0 R /H /I >> endobj 134 0 obj << /Type /Action /S /GoTo /D [27 0 R /XYZ 56.692 189.94 null] >> endobj 135 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 619.229 69.232 629.547 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 134 0 R /H /I >> endobj 136 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 619.229 207.832 629.547 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 134 0 R /H /I >> endobj 137 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 619.229 535.492 629.547 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 134 0 R /H /I >> endobj 138 0 obj << /Type /Action /S /GoTo /D [71 0 R /XYZ 56.692 535.758 null] >> endobj 139 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 601.778 69.232 612.096 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 138 0 R /H /I >> endobj 140 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 601.778 209.328 612.096 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 138 0 R /H /I >> endobj 141 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 601.778 535.492 612.096 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 138 0 R /H /I >> endobj 142 0 obj << /Type /Action /S /GoTo /D [35 0 R /XYZ 56.692 771.023 null] >> endobj 143 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 584.327 76.756 594.645 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 142 0 R /H /I >> endobj 144 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 584.327 222.88 594.645 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 142 0 R /H /I >> endobj 145 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 584.327 535.492 594.645 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 142 0 R /H /I >> endobj 146 0 obj << /Type /Action /S /GoTo /D [35 0 R /XYZ 56.692 459.332 null] >> endobj 147 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 566.876 76.756 577.194 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 146 0 R /H /I >> endobj 148 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 566.876 192.322 577.194 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 146 0 R /H /I >> endobj 149 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 566.876 535.492 577.194 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 146 0 R /H /I >> endobj 150 0 obj << /Type /Action /S /GoTo /D [90 0 R /XYZ 56.692 771.023 null] >> endobj 151 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 549.425 69.232 559.743 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 150 0 R /H /I >> endobj 152 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 549.425 250.435 559.743 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 150 0 R /H /I >> endobj 153 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 549.425 535.492 559.743 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 150 0 R /H /I >> endobj 154 0 obj << /Type /Action /S /GoTo /D [38 0 R /XYZ 56.692 771.023 null] >> endobj 155 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 520.636 61.708 530.954 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 154 0 R /H /I >> endobj 156 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 520.636 180.189 530.954 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 154 0 R /H /I >> endobj 157 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 520.636 535.492 530.954 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 154 0 R /H /I >> endobj 158 0 obj << /Type /Action /S /GoTo /D [38 0 R /XYZ 56.692 734.174 null] >> endobj 159 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 503.185 69.232 513.503 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 158 0 R /H /I >> endobj 160 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 503.185 159.234 513.503 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 158 0 R /H /I >> endobj 161 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 503.185 535.492 513.503 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 158 0 R /H /I >> endobj 162 0 obj << /Type /Action /S /GoTo /D [48 0 R /XYZ 56.692 771.023 null] >> endobj 163 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 485.734 69.232 496.052 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 162 0 R /H /I >> endobj 164 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 485.734 197.294 496.052 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 162 0 R /H /I >> endobj 165 0 obj << /Type /Annot /Subtype /Link /Rect [ 530.476 485.734 535.492 496.052 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 162 0 R /H /I >> endobj 166 0 obj << /Type /Action /S /GoTo /D [51 0 R /XYZ 56.692 771.023 null] >> endobj 167 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 456.945 61.708 467.263 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 166 0 R /H /I >> endobj 168 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 456.945 161.676 467.263 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 166 0 R /H /I >> endobj 169 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 456.945 535.492 467.263 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 166 0 R /H /I >> endobj 170 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 439.494 69.232 449.812 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 72 0 R /H /I >> endobj 171 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 439.494 277.473 449.812 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 72 0 R /H /I >> endobj 172 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 439.494 535.492 449.812 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 72 0 R /H /I >> endobj 173 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 422.043 69.232 432.361 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 74 0 R /H /I >> endobj 174 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 422.043 321.099 432.361 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 74 0 R /H /I >> endobj 175 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 422.043 535.492 432.361 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 74 0 R /H /I >> endobj 176 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 404.592 69.232 414.91 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 76 0 R /H /I >> endobj 177 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 404.592 265.945 414.91 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 76 0 R /H /I >> endobj 178 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 404.592 535.492 414.91 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 76 0 R /H /I >> endobj 179 0 obj << /Type /Action /S /GoTo /D [101 0 R /XYZ 56.692 771.023 null] >> endobj 180 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 375.803 61.708 386.121 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 179 0 R /H /I >> endobj 181 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 375.803 182.169 386.121 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 179 0 R /H /I >> endobj 182 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 375.803 535.492 386.121 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 179 0 R /H /I >> endobj 183 0 obj << /Type /Action /S /GoTo /D [101 0 R /XYZ 56.692 680.317 null] >> endobj 184 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 358.352 69.232 368.67 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 183 0 R /H /I >> endobj 185 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 358.352 294.82 368.67 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 183 0 R /H /I >> endobj 186 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 358.352 535.492 368.67 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 183 0 R /H /I >> endobj 187 0 obj << /Type /Action /S /GoTo /D [107 0 R /XYZ 56.692 771.023 null] >> endobj 188 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 329.563 61.708 339.881 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 187 0 R /H /I >> endobj 189 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 329.563 177.021 339.881 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 187 0 R /H /I >> endobj 190 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 329.563 535.492 339.881 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 187 0 R /H /I >> endobj 191 0 obj << /Type /Action /S /GoTo /D [110 0 R /XYZ 56.692 771.023 null] >> endobj 192 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 300.774 61.708 311.092 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 191 0 R /H /I >> endobj 193 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 300.774 173.193 311.092 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 191 0 R /H /I >> endobj 194 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 300.774 535.492 311.092 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 191 0 R /H /I >> endobj 195 0 obj << /Type /Action /S /GoTo /D [113 0 R /XYZ 56.692 771.023 null] >> endobj 196 0 obj << /Type /Annot /Subtype /Link /Rect [ 56.692 271.985 105.257 282.303 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 195 0 R /H /I >> endobj 197 0 obj << /Type /Annot /Subtype /Link /Rect [ 124.144 271.985 179.067 282.303 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 195 0 R /H /I >> endobj 198 0 obj << /Type /Annot /Subtype /Link /Rect [ 525.46 271.985 535.492 282.303 ] /C [ 0 0 0 ] /Border [ 0 0 0 ] /A 195 0 R /H /I >> endobj 199 0 obj << /Length 200 0 R /Filter /FlateDecode >> stream †º‘ÜÕ‹VÀ“)ôþIRÛ¬pU3ç-…×v·¨Š-º-v»èæ·D&ÅÌco ðŽ¿YyŠ+ä`Z'ðs$mMw†é,ÖšNDñ6‚ýã ”‰% Ì–²=^¡X~šÅÂü|¹¹í/Ê &0ÏÀ}KƒBþó팖vùS’GÜÈ?wÕ#ºr?¸Ð–ßjÂäËVÚ4f%f’™¯ ‹Äzºµ›­Nà˜‹ö¬t@D$ˆ‡áŸEÃpZÛ°‰¦n‹L‡³ô-×üIÙº«MÕ­G‰1Râ/4‡œ‹B¨®{D±¬dç„;ý¿ªQE‚w–îtLX˜N…(&ïÙÄó³ÖW“Œ¾â`™cn=?NšÍËfÖ§nF¸"ͱ†å’^h5Ð~é2“Ü€AÃrºÃ«ÿÔ}{!±hã'Ú¸3gh4qóªoxBÒ ýK÷w êBˆ‘”Þ}¸GŠ–Ǻñçt…}òÏ K}‹•öáj'þ¯ÜèVßlQj<3ÑtÝλi¼nÑ€o—å«ßƒ>HµmïGC"X¢Ñ$ ïFiÅÐNÃ*èIÂ[>*X c5WmÉ™ç(:®ôÌ œè¬L )D¯ùŸsá·æÃ°öøÛtÜ%¾c™¸×Ü™HÀ›IY´§H-Ê”}`][G8¦u6›²scÁ^hÛŸ¤&é9V&hqlý–)-Œ·„±ø+égÞÈÊ BMÜuB†ÆtÞm@M‘àMÃ,`"š·y?õjBÌšš5àŽ&¼ßJób%<@·£÷—Á‹#¤€‰tbCIæ³N>q¼µø©OBpîQ»í&‚JÓhäxYÚçÊ U[2ž§p².ØiéÕâB¨óx z óQ!^žçþ‚#fLK‘ÔöxUöxÌ œ ©ÌAe‹Ïk›ß¬â—²º›¿NÝi“^J0›Ø÷/«ˆË_Áz·³ôÚ®;pA&¶ýùÖö°*ØáÚ Áº Öñ´ƒ«d­8{`nqÁ2õ±Ï½Y¨OœSß—Ÿ]ÙðŸfªà5-¿gÙÅ_‚°0è-w¾“Ý4):…¬¤½,åCèPÒA§ý?9äš“ºspBÁïÔEâ.€¡±Çùç«Ò“ˆÿs5Ï»ó:PR«ìD¥ÿjrOÇÌqãþ‚°ª€†V]¿ ×q"žŠw€`«VGGXñ«Ç›žÈê=ÍÜ\£HèŠýî|¸—‘$rE"gí´ŌèlE[€DaŠ`ZíX^a×Pèçv¢†åæX0)c„-A_Pœ£ã°¿S<'«y Œuå]êºâéj<_juV¨s³9c êæJlD°)hxš{Bj„v! ˆKX²$ó(K?$Ó‹ Ö)€ÄÇëaØØòÁð¡\l Ò‹¥t©ó} t±œˆîç¬Q$MR`¡:? endstream endobj 200 0 obj 1472 endobj 201 0 obj [ 115 0 R 116 0 R 117 0 R 119 0 R 120 0 R 121 0 R 123 0 R 124 0 R 125 0 R 127 0 R 128 0 R 129 0 R 131 0 R 132 0 R 133 0 R 135 0 R 136 0 R 137 0 R 139 0 R 140 0 R 141 0 R 143 0 R 144 0 R 145 0 R 147 0 R 148 0 R 149 0 R 151 0 R 152 0 R 153 0 R 155 0 R 156 0 R 157 0 R 159 0 R 160 0 R 161 0 R 163 0 R 164 0 R 165 0 R 167 0 R 168 0 R 169 0 R 170 0 R 171 0 R 172 0 R 173 0 R 174 0 R 175 0 R 176 0 R 177 0 R 178 0 R 180 0 R 181 0 R 182 0 R 184 0 R 185 0 R 186 0 R 188 0 R 189 0 R 190 0 R 192 0 R 193 0 R 194 0 R 196 0 R 197 0 R 198 0 R ] endobj 202 0 obj << /Resources 16 0 R /Type /Page /MediaBox [0 0 595.275 841.889] /CropBox [0 0 595.275 841.889] /BleedBox [0 0 595.275 841.889] /TrimBox [0 0 595.275 841.889] /Parent 17 0 R /Annots 201 0 R /Contents 199 0 R >> endobj 203 0 obj << /Type /FontDescriptor /FontName /EAAAAA+OpenSans /FontBBox [-549 -270 1204 1047] /Flags 33 /CapHeight 713 /Ascent 1047 /Descent -270 /ItalicAngle 0 /StemV 0 /MissingWidth 500 /FontFile2 204 0 R /CIDSet 205 0 R >> endobj 204 0 obj << /Length1 11428 /Length 206 0 R /Filter /FlateDecode >> stream xJq=£}ƒMª·ê¡Â“ºÝCØóP[^;I›$p¦ŒÏ"PôzPÀÊu"ÛûÂfª¡¢¡¶ßö7ÉÎJ™%cq‡ã…mÞ’C?Á"8u†êÍþHÛ[{”ºëŽÇõͨøVB Æó¦ ‘L:¤÷ûon¼ü  bàFjv›¨u«ÛþÍr?í;JºNФFP@™´Ö×E™®­Ø•kE¥T;éÜWÛ˜r\€­áfÁo˜Ö.Ã}4r3+Ìo‡º>ßè^w ×…ŠâýêEì¶û¿P—;óû"‰¦µ£üΫ5!¼÷@, ”ÂVÈÚߣŽçèÿÌw—ƒù9¨ÈýúÌ?£ 'Ó7¡°ŒoÁ²_Xß—YlR /éõ¹¤¥í(•Ç­‰±– v×±ò·wóâëõ¿k«9ÅhæF±šìÕD"ù|+{t¸[ 2(ãQ<›Ñ<•§™]ø‡;4ªËú{‡ dï«®®7KèO¹à…)¥ÙОQ¾—ðâ÷pVøã":‡öU¥Ž"èó †h‡ƒßvÆ"ý¿53MCæbË£!RâDUŒµ=ºûÁa…ãÞÕÑmT"Ý"ôA*ÑJò¶-@¢u£@÷„‘霒‘ŒŒJÖyï+> ”Ý`—ñmЇ[+,ør uúÿkõOb4Ïv~Å›üwà$&šÐñ3À3Ô@uzµ*Uhù¼±Tk BuG ^ïX¦|…-ý!5Þf¢Å86”|BlëcÖå'J{ïÔU™ð–½Ç5&纰êZkPæ;N·ÆùÎ2ŒÈš\̮Ϯ§„ИLZcB@bíõiﲜ§ §›‡—Aëíò5YQ‰æ_ccpø?ìÏsë£nUÎ à*(³­Ô4Õ½Hâ4Þ¸ý]²ÙzÒ3+ÿŽÑn±Àò¯ÆWLŠÌ=ˆaì8•/ØþI0OØ—{àåî8ñJ@•ؾ- ¡ÍGÄ\Õ‹¬ÀD#>P}”¾²(°¤!SX+hôWj3ÛX™ð’ââÑÕÂäȫʢÚî)ˆãËU-SkÍœýk3TfŸó£ ®IŸvÜG¿Õ† s/Þ⟓Å}ˆûÒÀœM˜uÑkmÛÜÙ\¶ˆø`¢’ð÷Úvk}kÚ." MÓ‡R¡â*jyóºØ0îª"Nô‘\]¨O~™QÎäSrþ­±êÒù¾ö¾¥±¯¢ÂIønj¼:Â’3ràf¢ãRDÚY—éhVݵYnì'Áy¸óffÁÉÆ› _Kê. §A= ˆJ|Ó˜E·"¸Ÿ†vùë¯ÄûÛiÍÁ¼—âPlɨ4 »XT¿‚’È}Š*Œ À¯ æš’Ù°}vîÞf¾ê»¯í®÷îàìÕ¬ Dª~œ|Â{•]ñɉY¨ë•$²ÆE’û(̹/…g9ÕŒVúw‰?Ëœ§-¯/™WMŽ÷¬Ã¶·Ýì˜ÔkCGNÂã­©ªåY–uÒ IÅøÌ÷S`%y\æmÁrjdB§N´fP¼”ŸILNEý!U\š)5} ’ÇîÏpCµÂ*˜QfaÄçÂ?±E8¥!Å8µÖxä¡ kÆSo‰µq_j6©ÍñJ³·#¯72i&l¹Öo<…ñã€(()ãÝ¿ßÆ—Ùè÷KNu­ nÜwÈÔ±ÚnM G¦ÅÆ¡¾< -È Ø‚€®¹þ¸vn˜ç46p´@ŒÅßú‚¶È 1¿2’:¨ÿ 4ÿ´µæ)9¡›þq›/ÛK ½”;ž¶²Ëm Úàaaäí²Êÿ'èÐ_‘^"ÛNÖç,ÝÉ Šp0µ¶YøJŸ Œ ¡CxœÞi‰N ãµfÞâùãýÿ»ø&ú±ª .*ÇÓ¥8Ùhãgš´ \Ç×8^Ø:]®OÍæ°L”Œç {Qõñ>]‘U¸ Œ)æ¢Ã Šœœ³#ðÿhºªŠªÂ²m<¾±G»ÀÑÉ}¡!–'çgÛìÔµmÚÃü+qŒE"¢º|ˆ7ÚLL”'PèwOà7ø4´qÿn£ã‘GuÆP[z¢ˆâ`¸{Ôà¯^èu¦o5˜¸g»™ L¸ÝIäV°À5%ZÈŽ ¿²u7.0m¸œ®n>wÔ\âDC»lÞÄ¡+ˆ ìaûßà(ÂÆŽ“¡úùùN)a(:Üþ×ʸÇ©û5 À9ÖMˆLÕgñ×R¹úãÏ)ŠßÈ’HXä›=ÜêÓWlÀ=÷˜’v®æ… o–nüì?';ˆÙ“: æ€E@»ý©þ“Šª=>ºó/—ûUÁ° ?Q6.°õ.~I!MÙ•Ë`†ª^ëHØ©{ÜÇ̦Óë×ë Hp¸á?—“Ž'|ÕÐÃ*Þq-Mæ;O8W¾·›|R‰?$:õÄÚ Ÿç{‰_×[€ll¾nnh7So@¡ÔÝt‹tËZï'ÐubGŠ`qB<'¸-–-η†b8°Rj»HÈ›¤…H™)@5‰£lP\C¬.ÂBA jLÍIeÜ!ƒt‰æÛdñÅð#pYùCS™fWËøï¦•F ë"/Qt ÁTtRUhßt*Ÿ›¤øI)ÆÌNÎ|J€}™únÀ"2½V¡FDãé£-‹>v º¯_1YGeê·¨æ|ÊmãM«¿­c`ÇJë€I扨cÀ],gÄ]r2”* “̨:-1>Œ€¡‚½ §AÚm\õÇæíC4ˆ±ó×2½°™ªà²^à¤ÅÈY‡£±Xù6Âï„vµ_h!S&PîCp÷á%‘}ýmœ(wW'0°] _½_ŸŽÏÉ™úC‘ÑÚÃâJñ*ÀžøüÛVU«æÕÏ¿'õ02xÄ-IWh(gµ·Meê.þi7è`Ëœ–ûèøÍf>b¯¯ç÷MøüdW«ë%Œnsu2ñØOrùçMâÕ(kSo¿p®Þà¼~h–%ìmæÒ¬á½¶7w`·ç„]XP!órÜ”è‚@ûAq qm(w\­ß}d‘±g.£ž”¨ÔͤJ³é#Cr+ÿ³GQ¨ \Ü‹âøJÖ×ûØŠ…::zžÔŸÍ¸ž%¾³P‰¶ŒhÜ%t·"Ψ·WO< x—3xp·Ø»»„èoÃÑÛÜ3\3–ñÍDÖÿàD—ƒãT»E•¿)RGW2«mô¡âwÙtè¼ûe$¦6·€ÿ1“‰ µ/îlóß~Ëxj…P8ªÉ§P›Ù‡¸˜K!w³ËŽ˜)õÛ縳gÝŠa‘ר¼ü˜ ëá—@”˜&بb’ë$0ÐYØ×à"k—‡>èLz°ƒžÝY([uk÷Îg¢Uˆ–¡!¹ !JÕ/”¸8¯5ÿñWöŸ~Sö)U¾ú¢Úë}öIŽÌ£ôGú¹gÈÂ28Æ*ûÎQÁ%ÉÆÁ ý—EFchox¿Ö+¼py¿ zyr2nÿ¯ (âFZÛ9Õͦ–÷ÞâBo ©|];ÀCÇc²·p¤bn”j& ¾é™ªŒ6“9Ò€ª/p†Í¾wر.Ëþ FÌ_¦WÖëSá -—åu®tPåÐK=(˜qvT•n¶ÌKž`¢(ò…–HÓyUX÷‰– ýM^¸ÿPå}49ìÀp]_ÞJç=–[„U4HeèÑIvÍ+¦#Õ%Ï{‚L`QL •Ž™O¹—uÍV™ÿª¬Ž0•Z¬`~õ/ ±X¡Óöj,iÖ˜w”/m4àÏ6LËRËѶc@$l±Ê;Ê;›€0à îìe±Z‹wœl½Àå ù „îƒä£Èû‡#Qèó´) <í7սĜ7Üt§e›-”Ó´ûØgAâ¨W}±k`‘þðŠÁ‚÷ófçJ ã<ž©Á1¦y¨9„§ ·h¥Q]ð¦È ú}ï%ž™5œ™Än¸Cáùzl™€BYËTR?qð4ò±øæÖ#^„DK ‡æ#濲+FÏïÓ\Q{Ä¢ÉïXSû0«ñxi/BØŽS >Ö«·Zxœ€×˜NC® XLÜìÈ“dݘ ´8;¯g[©ãÒÚ´!Z²Š6&åu…Ú˜ùíÔ(µb _TT­â.iî¦m£iÞµø3ÛŽUåwaýåï« Y‹ü"}GlmÁçÇë×&Úª¯t5ÖO¬ÑÖ ƒ{Ì’Ý7!hÅI^ Ï.Ô›ð†i4ã9¾ú°¡ª$2ÕãmÀ¬×DÃôv‹(nI@mÅ5i’17× ê°°},Ý!Mn6±`ÀAL®6fNpñòÉ®paV¦J!×V56t:Á±x¼±k*e íSë7‰ÄXÛ'0>i^ì?j7)Ä8m¾n"t|m¢JBDÈ•X–²ûS« 6%¼ø=<0:‡&¬ënxž5Ò ²Ú’`–€#q¡éLF(hÌ­ù›8³pÜ)Wšï¥#B?i|_ßR¤ Zð™!¤`KÃ>û¸* [BÁ ~«u‹‘y‹¨,ü–IºìHu„EcÌ^/]Ùþþ"WgŸÜNÀ•ˆ¯¶ ßú£Àêט”›¶,üEãì7jêªì-@Ý•(Ší Á ¹„ewÉ|ßÞ•;ÐËWIT^¥…G¢—»æ®ãwÀ*ˆ†@Ç”©*ÈýlÆI1ÙÊrÔ@¾t'bÌŸÃ ¹ë2ÀQvÜE¢%æ¸4Ty¡²j¦|03ÞÔ˜?¾¥©(–šfU 3þ‚}V²Û•™ÎK'£<̯ jÛöMoÌyÑíßuñj:_›ß­[ Ï&è"T‡V˜ôÿP% &å‚FQ èוlO£È~eJƒ5Ïp¼ÿ²µ‡P`¶pÚØqihnË"Z²9ô…-£›[â„ïçï™{›e”ø*¿jF¬è/GÌÔ3;Ò‹÷v “T6¨ùK¨©(NÌÖ0¢ ù‡Frkƒ+;ªå·H_åì$GPò Òlù5£H»ÀÔp_—3oØb ØùjW±nL×Ô*i—!-𥊻ŒHõˆÌŠ!œNM28ëá£2#4–”õ/tô²E +íE¿Ð±„3–}ý½)þÄZoaß±û¸· Kþ1þ?:‡FFËo²ÁÁ“4ŶZv'˜GÈüçd˜´m¾¤1ZÜJc¥Ñ Àw‡fvMň)qÅæJã¯ÈÇ‚ÆlÇ·‹xBöˆÀ”ºÔ¡ðqj °« ùZHþC†j0Tá‚râÞϯêc¶‰»êÃÌWB.–³6*DPJuRN›4:+˨% Ö-¿<㬥|“Ô`Õ׫P'ö[ašÍVÔèœ»×ØA~ĺvÂMâÛ.’žûxà ¹wJ¾tG&®©ÿüÝ×Ð6q‡ë_\?V€Á$}§^`Ýbª860MC@Wé," †üuÍ`•/¥|@ú¿-u¦± ¦§>SkÕcl¢7 ëF´ä"E-z¼•¢âòÿp͸šáø0ÏAÿ[N©†»Ñ”ó{#¸LõjØ“QÌ–zè„ä<5寶ÕèHN6tˆmòæ#a~™³ÿÚ[¼€Ç+³E‰ìc궉èkõtÜC"‹0rä&\dwìí©åöÊŸC¼,ç†o@”F>!ÔÍ —›¸¢ËùKa\g£væÊZÝ%«®ÿ\ÒǨg/¸?uëf„Lüæ¦ü·S4ôe\™ªZPc~ÁÍ~®ý*÷ç6¤¬Ld|µÑGL©4¥K–¹†ÙQž‚ü"“aŒ¿xj4€R4Y¨\&Ç«ƒšFE³ÜÄ}]Ó8¯.ïžbHÖQ©BP¡"”$y›{ÛÍÚqôœ1ž¶o¹4²l]|u”‚¿ÁÐæ+,ÏòiIàœýd8‚Ÿw­ÙûÏ<ÊfÀ‡¯É˜aP4!ω xé’&'ÅV3ùÎ!.ÈÒ0÷B]ƈ§<ÑtàÓR38µå@ªzº(?ÐK\ãÅ´,K¼×ôH…XñY»tÁJ³šœ­ë ñx䈺ÄMÖÜá#é’ 4Noî²ÑÔûÇ2Z<ú{…n÷Ó¥–±d ½¸¨Ï{ê0xU£ÓO#Þì9áÔñ|ŽäF¾rùŠD½]@ú÷h»LUÐ8P{.›|¶{Þ—SÆ>ü*vNÇÌЙœA u§@åÔt¥©=ÂîYnάÑйEnEÿD8U$L?âtᆌÔj^rœ Õ‰VŒOã`EÜùí¤¸aÑÈè2HáÐg¸±ñ#œË* ïùܰänàÈ”plç·ÙŒhtÅÙä™L2|Ƥ1z}”õ”ElAwÓ2uå–•vË%‰ÝX*©¡’"f ¾”Û— ­*\ífý†1¼™É`Z^™ÞC8tñŠ•gNKë&òSb¨%7´Ê–™Â†×ž4_æ/™p†… ðÝÌLŒ„PÖ­8ˆ„œ¿Æ:û5Q&(%hÔY /ôÖ܉S ÝSbé©y:‹€g¥rN˲§ YÃV(¢XŒwñ}ÉÛŒ³£SE¥›¨>BùxCaV°ÒPл´BšÅº,›,>%`}äý8qf’ Äö3pO[•Åy‚nêèq Wªæi2çâ8‡ñ±þ·C¢c³QÒo:¼w‹„ódæ“/á Õ‹Z¹sÌ3m™ÙöУçu¢2ðˆ#¨† iOVÊ $m;܇a¢TuS9ªó{fús–Jé÷7tÏÏ¢7tgô.öÈL>y×¶<‹Ü4¥Qß{’ضTWíkà68í\ñ5¸pe}p›’;£%©ç"YL ©Â¹¸£òùìúGû|'bã²碌5Æ÷Oë†d´‚ý"iÿvª  ÂàÊÄÅýû¬Bs…Í”RÖ²Po¸ô ðãTH¹À )8חО2äòÉÖ/¼ï¸þžŽ8-™ L§[Ñôåcö“6Eq»²=9‘+|6q@9ü’©¤YÊ÷ª„4aþm£¾–E¼“¶¾Âû«=;ëî!,ÐmDÐàñTü¬‚¶a2G5Ô[•®+3¡ÓÅàYhµOo7ç}ý7· k¶"4Á¾Ó:?Ïq°‡÷»‰å‘ø S£Bœln½Î¹©Å¢Ò«R+bO“«Ùî¬Ðx1í&&&V­øQó âuIúdWâkÑôŠ6"‘mðû~£@ˆ~ Óû2lפ°õÖ›V¨ÄÈøš kY?¤—B "Ëe$æòcºm¹ÊnÂ2ÑÌD’ïƒpØïSí£Tàü¡i |F <±w°#Úé”Þ³À ÷ËÕZ/تühï×P³a8)¦4ûXŒ¨Þz‹{lÌ{‡õÿ9V\»’»>(I½Úl/qØÆ¶M$›Álž“Ñ€ñã)K—¥Lþÿ¼ˆØR!Ý£nšTöeô0¨ËàBéuáfr%[·HI@¸‚¹wÝ÷1ïÍ=a„Å—,n|ƒO7D‰2©`{e HÅ`@gW³¢Èœy¼ŽXùs[_~€•á ë?ßæ¤e¬’ë…ö[ËQëÓ¸ sß,Š¤Æ¾Ê04~“µ`b­…6ïî˜ÚB¯å´E:ú~ÚóȸGXÂ4E±ä%Óûž¦]¥„i=Ô6vüžú½w×BÅ´1]Á£pî¦0ß/þ"ƒdðjK³…’¥8(ÙbY¦ç$"0{5fErCGÏ‘³JÛÀÕ># v4-=ôJKƒ®ìW»–þÊ«Ûåm&:žÈ¯,šN4N*?¶}Ñnlf˜ýNtM¾!bÀÄ¢‚¨j—ä¤L<,øØTVò@ yHÈusTß=cðŠÞ5ÓežÕ–àì=Î'«ì–pé_þ@<œ%7[¤8ÝÆÐÈ hqâI17íé ‘ï:£Ë«:³Tôä+2irÂ1^¤9¨š¦>ôog Àñ"ቾ>øÊŸ†Ø±kž3»ѯ,(o„mÏ^_b$ðë|Ãq]_"Ãê1jvÊïE"V’ ù1ÓÎb|ýx¸±X¦~˜d=g~ùzü­¶ŽÕ™ÏÛ&qùOq JöœÎn¶üëËPÅ7ò=%ä©Íóý¯¢"4þK¾&d "¤ßAš´àú섬@o8GÀÅ]­7}ÈÎoçæ3%×~©/T¬úVÜêÜcÜÈŨ8^1§6bë«–¿4wiYhst0ýX89àHèZ‹åŠ+¯ZM÷ÍÞ×ùùªƒl®G¨ôÞÿXa`‡þÉö„lJ㜽ã]8Ì ýÂå•8¦[û>66 ” èo8Û"y¥ÿÉ"ü°…o vW pxÝââåï×Öeãy Áªôbûéªväh1Ý4–á#z g}F)f[hÍkkÍðéâÒî]JQ‚‘Ù²ÚÀˆ?‡¨xÒ4<ʱžÍñöœ’£ÓSWƒ‘‡#Yr}¥U ¤Wݺƒc¯Pð¸{´ajzÔFUˆ'«ZUÞÚ¼ò¿þ•m¾TCôJðH‹R­9 Œ|šˆî. _ð]¾]4TB7:]Ê( x˜föyš°sÕ{r»¼ãÞ·!£ç±PÖTô.¥»ÏºáŨŒIýü‹ëõ±t MdÅ`†@PnÕk"ú¾ÞÉ]Ö˜£ò©\í{D²G•¬×{»Dê™ä˜ƒ;”%¦ÝNç0X~Vö_ZñHŠóñ˜:í \t¨1ŒÇuô^(™y"¨f‹t…ên‘{5)(h}“x…8Îâ®ë:lèð÷¸VÄu¡t&1¤ Ðöù[ÛKû`ª†”]G‚e¢pdýAf|wö¨F endstream endobj 206 0 obj 7728 endobj 205 0 obj << /Length 207 0 R /Filter /FlateDecode >> stream ¾Næ"Oêü>ä±5ݪYàÅñÍ…Çë? î{ÇÔãù§AUŠÇ¹û–ó{̨ܲ· ³Òêç Ò«Ëà endstream endobj 207 0 obj 64 endobj 208 0 obj << /Type /Font /Subtype /Type0 /BaseFont /EAAAAA+OpenSans /Encoding /Identity-H /ToUnicode 209 0 R /DescendantFonts [210 0 R] >> endobj 210 0 obj << /Type /Font /BaseFont /EAAAAA+OpenSans /CIDToGIDMap /Identity /Subtype /CIDFontType2 /CIDSystemInfo << /Registry (ËîÌ=˜›N#ÙRƒ8Ž_\)±]J§¶‰W#ïJ]¯qÔ) /Ordering (kÈ`{ìrXe}©ÿªM?Ïa+UO2%ésOÈ;ã€p) /Supplement 0 >> /FontDescriptor 203 0 R /DW 0 /W [ 0 [600 259 321 548 561 476 613 408 630 604 612 618 500 252 777 612 353 753 519 613 500 553 728 252 338 729 930 602 477 595 556 612 571 556 523 503 266 278 571 524 571 252 571 571 632 613 571 516 547 571 902 591 571 1000 266 467 925 259 ] ] >> endobj 209 0 obj << /Length 211 0 R /Filter /FlateDecode >> stream Düßñ©hæ² :ádbêAŸø¿Tƒ“Sœf¼´oª'Ѳ…ÝŠõôñ<ÃgÖbÆdaQgY'„¾ð\vK‹]uK€Æê¹ÀêbSÂLÐr„¥À8vrÃÔ\äTÏ:PÐ7‚‹«»€–È|1”´äï¯W°¢àW—6j ̸bU¶íy%LÊ]àºA£(¬J ¸«ü¹Š|×mA÷mÿK£%§ðò)Ï1ø÷ûÔ•­úÜË\áHrÿ •ŒX¹ZÁò£É‚É5$Õ[:+ütòº/ÝØž¶vŽ¬ï••«¶Îu ƒ(±6²ZÛA¾énèŠs³GiÓ­Tõ[ÁG²åü±â¨Ì%X*Åý´À-“ži&7žæ‰q I¯RŠâÆekxAøZg·È£¿é]>µ&Ëlui!•¦c‰&÷ò°Ùì0¼[ùòü_ …´Ûó4 ú Üy`™3[® ©H™N³š¾ðl>È Ï¥–/Ó²/ÆÒN C¤}ÃÀd3ÇÆžl©7Ží#ÉÞ;¹ˆë#å* £7[V9ä÷@Ã^z?íƒ-8UïÎL91p#ÊËdzèàFtu·Z=OŽ~%þ!½¬K’ ƒ,ÒRVýD@JtÏ÷£qˆê÷tÕžì*•Õ‡®³#áüczp2Á²MÖîx- endstream endobj 211 0 obj 512 endobj 212 0 obj << /Type /FontDescriptor /FontName /EAAAAB+LiberationSansNarrow /FontBBox [-166 -303 1000 910] /Flags 33 /CapHeight 687 /Ascent 910 /Descent -303 /ItalicAngle 0 /StemV 0 /MissingWidth 500 /FontFile2 213 0 R /CIDSet 214 0 R >> endobj 213 0 obj << /Length1 19612 /Length 215 0 R /Filter /FlateDecode >> stream Ýöyo b13ñ(¢HC¼C’¿IA×?Ò{ã íËþ°¦îY»r~*äëp ÙZjÈYRž„Þâñª*²‡…Ì&¾8Þ¥g9TŽ`_B€Mؽ˜îH¦"/ ¼ãƒ–t;ÁHx¾šZ÷šsÚ2šþJkeäùÓ×ôÂ]ð:ù5‘÷/õEh p0$R¶æÀtÙzwèk“&ìp©ŒjÜh¤)ëÿijÓ<®Üذ¡ñ(§>6HÓxÅ—¬Å„ºïÈYÎ~P@bwß½¼v§37³¼iSC4b˜iGt抸ˆÔ¡©ÆÚ‹ 4ÉìN&ûêú|ÔZÁÖ¥3¨ÊOǧöSE¬IBG¢JÆá”'^õ© ³ß~üÎQ Õ4íJ.½¦k¸noÕWçÊÏg¾H5j‚ž€ß ¥‰”O¢“8J*tƒÔ˜€K΂ pdö`^mĉ[òÒ.…öËžÐ[~ò"e0û'?=i¤<]úß…ýêBD”\E'¼>аu¤Î‘(ü¥]Éøa°éNª¼îqvîkCî–¾ÌĹ›w'u±ol…Å_k›T½‰sS^OÌãy4^xè÷7bІ.>ØJ¬÷⋆œS—`×ÅDÊœ‹¸à2<ѾãÿLE²æªröªŒu€±6ùÖ ¸“õ÷}Ÿ¤#&2‚بÏþ¢VÖ¦·°— Ëö™9¾±·é’FØ¥H¡•ú^=’°ðl[¤Ü–°!Ë~ÚleEßc™µS¾T*npP!`åùgãÕ‰+cân?Z†*3+M&÷>SEÄÁb Ç4Þžìxv5íHqrl¾VÀAÿ:¿"?³\'Ó^™&r¦à>)iPá!H#"°Ä6VÂ0Tl.ްW/›h«¢#¡ ,b­k¼Ò¿ÕîÀ@¥¶)̈!äæ¡¿ð1ßéS»êGg9u6ÕØë§AÂõCuyT¤¸µ§å$'ƒÛóD§Úòi ‡¬Ýgeì×Ðd¥ÞŽ5=&1ä?YÍA €"­E,Ã'ž„O½J_Fl( ¦2ºS3NÝLùmï=ãê›ú{!§«íIáç§Ž  ´ ¤WÜBÄæå§gkyg:8D÷&C=ÚY»uXÊÆ&yêΣ7Æ.Õ~Ãá*$ánLþ»411òSŠ£,ÔÍÆÐ¬ÉEµ‹ Ã׎ ª/bŒø™L‹Ý¡‘«Öœú\£ZMÕP˜2ÚˆeŦ ìœÉ-‚Ñv½tŽÇÑ8wÿÿhühH´3éH{;¾d˜eß5áVœ´´ü¨»bA²z$n¿ w0A¦=”ÐñŽ÷Õ@-‹8ÍÊà q—øgœeÈ]¶kj"fƒä‰Ú¸leù´|öªEñ>ß5ìÇ0¢¥çp8P„<¤%Wqm€Ñ© ±Kµwz“°üÕԅ€JIú{?÷tpÞ„v> eK¯û] 9u×zÖ#7‰ÚÕê†%Øêë4?³°j ˜®øãéÞŒMãð‰ž,S™Ô}mXY€Nœ÷_ Iù+iuå\Äá}1Ï»ãů(Á˜ó£jÀ‹<<ó}|ªsµ²ƒk¤4y.ÕQ¾iÄw É(íÔʾ߲E;D† ’PQ/G\«%y”påÉ_YÍL½"èÁàê^'$o”~…ȨŠ`íd†÷ÒY%.PE¸Þ»çæMéå5ýµùPtl÷™Ï.,O{Ÿèº¢¥ ,^ãŸ+oœ`L¦cÔ$¢…äŒJ§@¥‘*ã¶4³¹6ðéo¾(Öq¯BNtðe ×/éž4§¹ ­¹&Ë’Kžáa`ùŒšþ°²†oÊÄþØe‡» ISÕ;½ï¨®GÆ›(ðb®"®+s$X¥}…>’»P^ËÖ'…ãÇkwŠ2¡ Tqd%tTçÒr¸['¹èˆ¶¡Ì×î4Û˜;`ݯ(üE2óç@ è<¾¼ßÖpu ™XÜHoÊ Q˜°–Âef’ÿ§y-zx õ’­ZNÿW®öÕ-ɶ‡¬7Zè&è¡csÐÿ›6«J;ˆ Oz¤ƒK@yÎXÇϺLCïÁî'JÙ£3ëÏ©ãŒÛ’ÿš3µ¸KÎÐ*iN‹M“X•ÖÖÔÚ,¸Ël»†:Ú3¯TGRÑ´;ï Zöa´È<_ýä§N1…6a>hÌÔ¸Ã${–öÞ]ûDržXø¿ìż+f˜Ê={¡Ê=¹ÁÐÈèj‹õ™„8ÔáoêÝYv¥5>Ùf‚zyáC®4µ‚b«d¬Ûrë& S¤hŽ‘¶b5ñÀOhÊýi“Û`½Úä¦ZÊËÖV½®b*ÿQÍâØ˜¶Ëøqû¿†D2á A×û0‡ÆßÍçUi“.¢ùù«”r®¢ÿ Kتbä®N|+üÝ­âüú:$™uî?±™Ê=Þ…Õ*…˜úqÙî8°ñ椲҈Šs’àI\D¨­Ò¤Oýrf„@H¡À{úFv•Iq` è Y©g÷:‡9;úãnÐ0UÐL7†ÐH®T›‹Vàc欩ԯ쉸%Ñ|o¹âVCù¼!™°2Rñ ÇÉkHY)Þê)¼'Z9–Ê¢¾.ˆ‹´Å|ÀQÝ}g~Ëî*áyáð‘Ø½‚–·,R¾¸ãØëÚ —+~ ÇÛú¤Rö#¶,öÉÄ,€œ¯ “N]¯ Æ¢Žrj!Gèø9Ic‚Ü"¦ì ¢t^x{S\Ýw";E¶éÝóàÖ÷iš]ËRéP“­F3µ,y}fýÀÜKî²é \ ¹5¨jíë\eÑÓOV]:¹»Í‡Éí/,£ÝuHBt\¦èÿ+%›/–ÇÃU4IdkÕB:œq¼ d±K—²œ9厑M‚,ëNÒ1j~ãu@¬{÷àtŸÓx±µ«6Òzz•7K ¯#ÿsE‰[:Ûœ0 VÌlh·Ã‹ÀDÞ™§oÞfÒëljv|‚‘I*Ÿ7Õ™Ò%¦ ºõì馭ðÉ£â)§K5 î°¹ÍÒõí1F€•ú'8„Ïi‡Ý„¾IzœÅµM‘¯rÈœr™¡0CãO¶X­¾¢òöµ–Ù JøËx¢‰ LÌš8„|g{‹¿¯n?ñ »k¹¢ñÀê-ûæ-stýùN–E-y ÙôàÊ…•âè&F[Hän ¨6µÆìæþúŠÞÃúGTãÌpszÓ$†µ5JÛ§)´”¬rYÐ`)€ÖJ@çMßß »Ûœ B=N†övm‚À"C-îÎÇð»q”¸¾pú¡;ÖàhýµÌXÉ3cJ/º!]< Ÿý‰E$X¡S:|ƒ0cöÝæªæj bãy¼Òˆ$ý8{ÄÉÅ@ã•~¹]_Ž?Qº‘ú 3‹Õåù#?Óݽ¸¹_y˜Ûu.‡ÍEw0óžnÒè½á¤âæ&?‚èáh«Gªœ*­ã¶O‚@íìQÇñ‡üq 㣖}ü¼;ÄÛO”n4¬é1¥ãÝ®dóG(sþÑHëѬd~ΧIL:µ‘‚œÌU%[ çe2Ô 6U´Xù}^³™¿U¥'Èoƒo°xÑ‚é½ÓBJDˆÎayð¤ Xî;5ÁH3 Dâ ×^}ÙÙŒP\'ý㱎3¹i1"D1ÌŽÜu‰%ÕG ú¡Wþ¸-ß4:ìÃë;猡‰aî ÿ׃5t†‹ö`ƒ‡kb?vBðs*(^ʾ׮T;vïßÏËkÿÝ›s4µUn%æ~ô‰,ñ¡Þ»-æ>$W2•Êœ-÷n]ß8kOŠè4í™KVé}eбx?ʱˆ—êæjrðÓi lÑ”Q”Q‘› óØ33·ü_éäµ8|„ì¼Åâfå+Ën^§"’~ê·¾dƒ zñã iÏ'Ý^Tpž_ã[ w¨çɆÙ7®Ÿ¡HQˆ$I«æª|¡n3 Ða]Ì3FÚp 9Õ5ÓÉí/IÂo‘XÕ,ʱ‰£ÆßRèÿËcÝT0ð0û“寀(æCûñ-äN0íc´Âú„ˆQ”чÊL NŒ}Ä[‰SD¯ñZ˜MʽÅq+?#åIË4ëºö¤r7[¹ˆDl°mª¨½X¬Zò¼«£#Þk3ýÐíÑJ:ˆýt%[l*{{XÅ®†»ÂŸÖøõJÚeÆÂ_ÊøjƒŪ:¬)çÌ,^Ðr Ë&ÇÌ¢…UIÔ‰!öÊ1ñ{*Û œ”?²gjõ"OÌæÏ)_N3fؾ@ýaÇóž6}0*&Ñô &qy]ðÔµW²ŒÇÅÄE£ÜÓÓÞö³o¶c®µü6ŒƒjÅsë±þëòWé»­¬(ý?¹ûQS%ê,¹>x1Ï©Æ\/+ ÊÓOe±oè&çšž ¦¥F—ðCÓ0Æ|ÆÈ»ÅUÜ6À÷²ñ¾6X3n«™Nˆê¾ÈþŠd¶>Gÿƒm?¯YC[DŠÊ±ÐßP2áˆ[ó(˜É5Öb€.”W¹Ôx¥gÄ6ù”c_70±”«–mScÎÞ+ŠE>Ó„¨S<²†ù»ºÂ—JÅcäB|:&&?i[»>ž¤è³ô•,®BÎs#×vöy»É gI½yÞN¼\3 p¡†iÕkS·&i 5‡(ý{Ù>öœ¨¬t¡¾·å»¦*ØA7öÍýÚæ’›3‚3Žƒ$íΙÚ-$|<⊠`™\~À—O‰þ1¹ °¡ÞHŒúËç×ÿÝœšîK^]íÍ€qHsß([BjñÈ—‚(¯"=srkN1>†Êy£&l¨#¼#P?‰+ôªŸ;r[Ÿî é£H«ƒ[hŠ’‘BÍÚ®H_D.92º‡‰@¤äSþ\Ь^E©BÓRf­Ôì=ÁºòÎ\À C ’Y•f‘ ˜Yò×a€ 'ÝAø"R¨º€ß\bÁ•v¸ÿPDйŸéíŽ#ÂPõøÏ‰Xq•ðô0€ »åU´ÑV͂°“6[8çû©n³âg»¼Ð=µ|4l+áQx|ÑÊW›ïY7ÎÄÉN6 X^Ñ{óxǧ9£¼M7¯“&ê…'“ß0PÂ9Âúß”ÇgËõp=N$½ôÏ$˜ÍZO” ‚à¯ý ÞD¯6?jÛ¡@ç²ò0Û~òGfi쿉®pšh'Ði.Ðf6&¬¶O×Ý©£m0?©Ò­ ªEõÈ¢kHÊׇSwÚ DÞ„6yÃ5(?éKÿI¿‚úƒùÅ0 r¦«Ý—"”»;Åþ5„¸?n‡ÛÙ×UNöä#-Ö$q0ÂcF±*æÆrÉrÈ1T¼]œ–n¤Zg\bYÒAØö˜J­#¶~‹ dGWRJû›ñ€æé“K yu²IG(ó\•z3m¤—aÉ35c© ¿øûÔ|>¬qð+ö’NÅôÀV¸~¬Yü#½øù0̹Ò$Ã~û—ñxž¸Ÿ?ÃÌ DÇ…º”’z¶Ò¸KìcáO¡­`x Ñ_WÇð?a7¨§x9hð~ÑBþwïTh7ÂÀ0DF„Œ´Fº†SÑiŸQæý&9Fö7~rØ<ÿj"Û%”Û8ÍÊÉJK{"vC} v­¨2¨2š=Â$ï¡p$(êëÆî®qÚÜäläu7© C‰}yîĹRòM` Îò,v­0ôøcKTpFèñëÓ:V©Ow¿d;z âø‹½r·k“ÀAÎYõ®ôž°W2LÍd¾Ã›Ô‡•C ˆÿéZ’‚GæÈ†@ìå#G(]Üár4Ffòüy}=×èõ¿ý¤MÏT¶hH™í³O³ GÏÍ/ ¿6êÏ]jÊC\ ”Ô Â-.в*Œï¬…‘›\­*Zœ±óY±ÈÃÝÇrM²x„-hª‰¶®çö²bø¦‡Ö~RüÁxn}4,¯™ÇP¾G%Z4œ›º‹dc”/œƒÈ>crœf ºöÞR®< ú’‹rè>ã•Õ,‡Eƒ¯µWÑ1.û¡J#wt‹Ö:AÆ #?´aå+C½ži'–IÚ;²_˜žë: çÿÑ_†ö¥Î”Ĺ}¢/-–`YÖ9^rÈG_ëò°)Ùt–>_t£{¯¶KèWtÞM.ñýR¼y $ÖD2~oCK¡#0ý #Qu͈PÃ…]ßç1'ßKж&bÕ;³Ž¼l¤9+få)eýcy™/ZÉ!‹ä ¡óDõøáÍdámÖvì‡\m“³˜NF)Í‹„c7•ߢ¼¸êbî‹ÚÉ®àa>±ŸOä²Õ溥9ø`aýÔšÖz°Õ­,8~JùMº«¹Á•RPqh ‘õî‹d>ß²“UXnØ'W@ç2\Rb·'Üja”kɯ‡hŒé>u";”"Hêªiÿ䙜áÏ.´ÊQ”û¾q:1TÊ3g °nþ—â%ÝÚ›7ŒÊP­¬J¡,÷ßfº—ÃëîD`Š{éåâŸz[EIóà—{LÀ’?á/Kk1¼­¹g¯œ·Î:wÂ/0|!(( I…‡¿Û9´£ÜFKdÝþÖ ½úËV †6(6Ýn6A€“íu˜?$šü+ËÖO¹9øó7Þ’¡IýN4ßîõœ¬挭‚'úº/ånÞ±yìˆ@Mêñå°ò,|E8 m˜úçܹ„Ê}"Í®òáŸmà>§ñíöýXò²|¢KWj§2ÄïÙwÞúGþ;ßX2g4pGÝøŠ•.?É/kYWwïôpYLÀè!V­ç¬}JaÏ#½—pϸ:¼a{yÞYb»>WTVg·ÐÁæ² TOçǶæBÂÖºcDQün6·$pöÖjŸº¶JÒ|Gï`/•s˜†+wä-—3âQ‚ßœJ$‹õ°aõb=I|éÍ—õ«ŸZL›rñèÄ"QS}{µohß® qE}$Û~œ^°'Þ}ž%G³ÑÞ77J«K}WôÜfÎoû¤Á¹ŽÈ¾iêãÂw)¢´³¯/£´'‹¨Ôa‹QóYºY–%ÛJªœ#ëB¦)ÿÇ»×~þ3DÈš u‰g¹wJÇ£ \ëÕFÒå2%ÅÌÉû©­BÝö¤Ê¯"è‰hü0fYàsB-¥ÌcÒHˆþ/†Ñ:ô¸D§"Sœ¾«I4"(Ë@ƒ"].4}\“š==®;¬6Ö·ÛJJþ#+š{¤^)#U½‰Q®z%©v5,‡¸ "ž )‹QØÃ¹Om ûÌbF<ž²GÜÕ#qr?¥ ³¾aã wâ{?Ÿ·=° ¾Ã=Úù~Ÿ‰……"ú‘âÎÃú“öKЭøÊ7Ç6(aL†ò¾]ðÿÎ{8`³æ#6{‘C-{³!ÛùaÌÝ |U1òø2}'”;“ú ¦³ð_Õ;œ%±ä+0À^ OýAþm;§¸ø_Bv€mòű@<‚’¶ŒR·Âñ%2¨™6ùæ ²WSugLå3€T® = s"¦3Ò¼;ˆ7@LœØ'O…abý{½¦ÜíÀ¶a ÞE÷ÿú—lÐW[ çÏh©@ mµjÆ>;]¥Wo…qyÉrbBWÛ"J¯ft$ì/Úb`•å(=@>é)Ñ->t‹ý|xŒx²Ð¼-n :Y'yO9IÐÉjkmË" f§{î’ÌVí{8./ƒ¥£AçoŠðF!Á F ‡”<è¿™a•±ZµnàO1÷ÓÎ|.͡t…*™ g·¥¢ÕI•úË#‰W4½ßÌÒ•ÂÒéx´Ý¬kù þÊ ðv%… A z -Pí¹€Jò>œ)‹zËEœ1”¬ h6³;¢“Ï·Í…$Âÿ˜¤ ‚ÿs£9D.ƒ¦k‘hÚXGò"«ª½–™]Öd%q£†æPqTD©ßáøë­ßеáyÄd¤¤µB=-êPøoØÝ2¥$ ×°µÝÃ8+¾Zèn%}EKYÅ<=¹§J4†ŠXau5™T ^—ø§óV­¬ò¶M6òéèÓC÷ß àg, 5ùôpé]Ú/O±û7ˆhL;SApÈßÛkÔüZZ÷VÝ Š¯sk…Îz¡ÏÕíŒ*8 iëZBÛMúY}ƒ3¸¿JLDJ¹B<âüƒKÃíñåÑb©ý õÕ|\ Œ –c‘x°Ââ…'Ô¼Ôš’òDT8w„%6(n†\õ­áîb‰³¾ Çx,¢®··¤àí„,xV¥ä˜cÞY n³tÙXÛæP°‹ÿúíÁm 8Õ×1öï228»¡Å !]*øoK>…”ñ[7ÏÚû£s½Š1Sà±Í›ºéÊæ)ÖX\7 åQ EüÛrÝ™{Ä|ÕÉ;k-óùË=JJu—ذP‡<"PEKjµv…„j ‹åÖ/#;åFÆ­ÍvE:—˜o\ ñPÏNûÆ×Å' `™‰%%VÃï™÷GöŒ0O9IfL»"cDz*öŸ %/ãÚÞ9-3 $ ßoÚ]|0°ÍZõ°Û¼!–ïµù$5̪©rr0¼yÐuñ®OàÕ¬<࿾R'ÿ#ÌÝ‘ñÌÅõ«v´u“‡è B+gž¸ÃÜuRöÚŒbžÊJMýH€j_FšøÞcpÇCš 7'ªÛŽK$B íé hì—azèÇ$Η” y³,%P;ÉÚÇÐì…«•» çPX˶SÜak#爊˜{!3w ëçoËxøzN°¿°Ùœ •Iíªi¬äJ܉ Y&×}€’ûsñn˜»Ã˜È3ç(¼y©ñ$DÔ;€ÍIm¯ÕHú 4†.ËW?ÉuG¸9Á×täïðܹ0kEr Ò=‰ñ!ýwp8ûޅ㥰˜í›òžë@ñgvKué…ðWÕòóò\£iœéV/8â‘*Pšúœu1¨l~8ef+ä%<æÚ­dwÑ”óÎ}U :©Žî@#(ÞDŒ¬ìô8†Zà#À¸-q–žwS¬¸¯gX|)þ«QÝÂÂçq¤D7(ágb¿“†¬jûÌÐI¹!ï“Â'ã‚ïÏüäÔ}-Ž«&à*<ÙIo^š‘éF’øŸÍÆô CšêפõÝ'³Setšš„šR£óAÝÁÐ ÐI•ìáprËnM'J¹Uæ`ëĨæÄ¦—*G—å³}!9¹Ñ_ß]nÐ I²~k3ô–äx^×é¾]ÎâÅn'¸ÛD˜ù¼¬ÏEϘtˆíB|ó'µù½¶Œmd’È?X]·‡ÒÒìþâ­/Ô”ìNþŽ9·Àùþ…H·©ÕïúÁ(è¤(±Ç>pdŠ)?€"à3(ÓUŸ=¯"9s¾YR’‡†ÇÄqå Æÿ‡¤à³>†ÀN%%î6…µIÑO›$µO1ô9×ÄBöBõ†Ü4»_Á K4ÑzßYVCZ~ç:&è“쌌Ý9öq¢Ø_°á™}Õ1!Ýo*$$…fe쨵¿ ï³Ywü-gx;q5MQÚ) AQf$%|9×¼‘HÖ™ŽÃO„£þ¤J÷þ£—&S)©žŸ=H“c˜6ÇãäÃ•г ¦|÷Ý,f"AüR³ d;!nÚµ÷Mã5sì¬äP¡j ×›ÂEMB8,u”»n[™0#y™åz¦ç,@Z/ß:x9J:õ#éX/虚þ(­¥oÞ0Åyrº •ŒÄ‚”p† l%‚{²ž‰Ç ¶ qœºc˜+‡Æ9å²´ÖUxÝx®T¤wý¿L1Ö”yÂã@a¸FÿšMàFæ¿Q›ëL!‡!‘ [§„*»i f!ޝ²rõä†y {_EŽDÃÏz‹ý"e4;øîÊÁ'‡€×=´Q¡½Z¯Þ”Џ,afhL,}[§Ê½vÇJg³%½ÕgS\,ö†æ)è¥n£[ˆôð;I:ea·„ª$Æ®“H±³£¬b‰½ÆŸ¿6¹íïøÃ) ·éP'OJÏxéÐú8þ}‡¨·ŒŽp¼|Õ¯QÍZm‰‰>ãVhð24m¦|œÀD9ËaƒÆ]5ÕZ¦Ù™‡¬-éD¨'öàà5£u#¤Hž&G£ñ€Æ`Æ~î–i®¶ýeòQ–L-vÀy'ë(DÔ§bâ*‚M’çü¿J‹J]­Ö+}‰X+zgöE!6¬?Kß©îä ”—¦Â¿Üò餺­ÐdÛÒþ²«E`nOÒ “jy(ckFc³­íO(6Šì›™‘vH;è+¥9¢ÎuÁ@Þï”0þ,±<~ÅÈçºDèo±ÍÍ+oZ!špö˜Ã=B½ð¹‚¬ö‰÷v’Ë MaÍL¼(î.½•Å<ÉwÅ*ˆ©tž¼—ªLÌ›õêoß: œ[ß“ sGnbî‚eP¹LÓ•Úl¦õrëzh.C –ã%À7 žÙ½’ DÅÿú³´åø–HGÜ_²ör“õ(ðáßÓ?¬D´oó>/²’6Öä?¨C‰[½†’R$“Ç_í¿‘Fa5+1˯íêu7y4ýóxrÐd<#/E‡‰D1ǃJÝ-oØI‹3)×+QÂKòÅwË=n3€)Íăp[uö±|ì±µ&¶tïE·IOxß0·sɼšÑÔ66æÈ‚FAôÛA‚æÄ«¤ÓL/“T5ú‹2•ã/S¼‡üÿ ôb‘æb3êcŸqÍLË옧[­- L„D! „”—çè Xew¯Õ©¤BÀ­ªð×\µÓHªàŠfÎnG aâÕ6ÂR7•~¼þý(u+Ó]ìÈœ#LÞYB×SéC|EšD‘—â&Y”à‚iÜH]iعå„On€ÞÊçZM$Ô†~dв¾|¡†O«°ºfN ÅOaܨ¯ø£—t¶±™ PŒŠ£z4vÒ–7ÁS(©HæÝšÊߊX„šsh<qɇLÈÞ&Ǿ¡CÒ‰•Énõ ” ÿ³…áÁ•kS¤:È‘l&6Éã‡;·@^e+”š00Q}—¬)ŸsŒ§+:Ë]IÍ#»ìFgJÀà«z´y•ÑVlå§.¶,xt¡½¤ˆ:ð4Ó½±G@wvÒí{!Î+8Çpî¬.cHja¤Ó¶ù8Ó¼ç2 ^.¿z×É„îgß.1· A1N÷tÕö=¨!Û¨uñÛØËg¡ˆ%¶6¡2.ÚU:#]vŸØP¼i|‹àU|GI)‡4uDI†&šiI£˜r¡c/@J]™ätwçN}P'‘b=—lŸ!‡ë‰Ïy ‹ç2Cù|L0 ¦£3’%6qÕ¦6­¡f]@¥ÐŒb@71°£r›rø¨d,ŽU+]mÑ sµ£WVð¥Š$î–Z4E”¹q—ö[ˆ|¾³l¸¬Ð»´Ïò˜¬y$¼¦¬0@ª»¥rhxË€¤8\µXµý3? ZTŠòÀBÈ, éúÂ’V•ògužÐ¹NLZJòÚ™à6\D½–˜«ÅÓmÔ¤Œˆ]‹$!¨%\ÓŒ·Dþa]=¡ÍM“HžÃ( ÂPõÉñùÓÑQ7Џï£Åkä0vs.oî|»Ò .ÃÖ_B„éƒg!“_cl^hxõQ2CXê-F~xüö¬Và|!LwÖ¡xíÛ\ô¡ã}‘׋bÓÖäŠV&ätkó’Ü4·Ga¡í@¼•- ¼ÕÇŸW ²Áúö`ÛDZÍa­hà YnmjUh½ÈÉrÌZáWuiSEí9=ûÅÙèy„²mΦ>¨˜¾ðÔ÷‘4Ì&ÿuë§YÚÜBw(‹Ry£>®¡§éf)šk‘ ³$0ÝR„ <€hÒ ” n½¸›’‹f Ts$´©ï‘} eœn³œ„,-§”«’V#x¹ß¤xö°öRãàW%>*«ªPÇy0@ë EDr­›KÞ¾—Þ56cˆO«¹O(‚Šz§:\Ü{ ˆŸÅKI@0àô9BæÊ%Üc¾lü(ò~Ôþ¢Ë¿glȉڎ“±Eõ‚O Ö~XSÇÄDv{6uñ6Á§çsgC5g’›w?ê´/œ9´´e”1Áë{ï~( ”ûÙgźÀP0ûñÕ³êâ{,‹ð‰(ñ 7­Ú@jãâë*¯ñêʤC”R?^ºPHíŸçííȪ!qâý¾«–±m ˜Jöbrr¦Pͤ/°©ñÛŽs_Ø}¨É§ ìº ÷³—ÄÎßj˜?¬áã,2 KÜ_öÔâNu·Ý@¦]*­áÉ£…Õéý1Ñ¿Q8ê{¥×­Í~Öb𠯔éŒ$7lLƒ×Êm(4øqøãÁ±¬D”-±º3{EZ#fÍâÐl +½¥a`‰‰Ë¨ü8À\XÒ>)SÆã„1ÊIÇã Œ«Æi@ûì?»¸™>Ï*ý› ~ÒWŸ!~€T€¿¶v‰#¤²òØ r˜ê·˜ÇñÝNíLTR0…½ªÑæ8èãWÑ]ð»Œau/”Éÿ“×å_ÞÕ7M4…«cÍÖááhDÐtXX rütqƒÿd¤e`Ó\9a””ÞJvéæÜÍêâÅ©šenkÑŽÕ„ˆWñ¸%耹$êô(x=8 €|5«¡È¥AH:}$Ÿ‡ cªÕ—LýÕ¨~^W¨”ë0¤,-ñ8ò¥Ja' „6i¶È¶æ»FûZ'G{QïÇ£å/UY€ÇÁNÔ4„d€ä˜Ù㈕аÞQ””×â§í&YÑRs™a0_;G ,N| Fl” q÷=¢ùæì¹ZoÙwâÀ[c-Àt˜¿†]æAî&¾_vK$Â?Èà;ù›%Øí,ŸbÚ³n;e¯DwZLäÅÃqÄÿ24φ«0˜äÎDB51¤íE§0ÀK\~»¡..Íf½ý5Y÷ ‚_iÖß»ßÇî|}ÍbIþ_;Ý"à-Å»×ÿê©Ã•Scæ-f0të±Í„‡–àɬˆÐý˜CsòÁ²êÊŽÞ“YÑë°½†ló¬Y¥ñ•4•C¶Æj8u‚¨¤}| K9€ÒI±><™ èÝ8%“—„ûyEïl`f¥‡b?”cízµ™/ÇàÚ“€ŸLå¸ò†kµ´ò‘Ïg¼¼åÚ‰.—~Î ¾÷ù”€aüK?>*Î|úðÝ,×3ìܹpX¾êÏCa¨€K;p&WoÍu®éÇŒ5ýE>; ÓíÞx;–[^…f+Ǫøøìì¸k˜!|Åïʰlù³}…™¬çŸºn(ŽªËšF4c‘û\°‰M¼¾2êß—ÿ ¡UM6)Ï€ÜHÀÎÔê?ŸËŸtÃŽzñ ŠŽZ0&y»å0að˜ûÙWDaéü*¹éP¹z"€:mú’²Q)¦ëÝAcÄ´R®­ª{ªjÞ àãÂÅÁ3;ÃX É1¥=T«J»Úo®lz·k€/ª{Ú8ÞÍ,4Ç‚ô&þ½è9&ià×ìWôþš·Òønˆ†Â>ZTXò¶À¡wêÝü]qO)ÎðꙞ9çyÝXûqNoÖ÷¼hÍ ‰/þ^ÐãÚäÕ”˜§­€?—Г9¢] 6„0­aGó{®(¯!{ ·Gò@óa 2ƒå9¤`²f¨mÑúÉÝ+±+.ç‰ÇÍBf÷¤ßCDÃæ}>Z˜UfÖúê8Ð7 šLoŒ­Ý­À Å/ãó_"âaïÝ]ƒâmÛ³'ô/MË •„& ”Á°ÒDŽØSðž¤køHZx„ÝUƽ³!áJ Bâ½Ô |Iä;õ}ô>` TìYL?'s^¾*¼Ç+wDe»œ´§î1Ég‹Èï5Ò˜"©¶rÈ}‹LX endstream endobj 215 0 obj 12864 endobj 214 0 obj << /Length 216 0 R /Filter /FlateDecode >> stream 'ºé|¬GsÅx Ð¡¦£A?Ö!GϬÜ\ÇÓ Ö»€·rš÷®¯ØâŠ1 Uß endstream endobj 216 0 obj 48 endobj 217 0 obj << /Type /Font /Subtype /Type0 /BaseFont /EAAAAB+LiberationSansNarrow /Encoding /Identity-H /ToUnicode 218 0 R /DescendantFonts [219 0 R] >> endobj 219 0 obj << /Type /Font /BaseFont /EAAAAB+LiberationSansNarrow /CIDToGIDMap /Identity /Subtype /CIDFontType2 /CIDSystemInfo << /Registry (äVô¨‚Rœ^ZiŒc€¤OägÐ,ëeœøöÙaYâ) /Ordering (ÈEŸ»}“æ‚zÐ^e[É[´˜IîÌâÔ69) /Supplement 0 >> /FontDescriptor 212 0 R /DW 0 /W [ 0 [228 228 272 546 456 228 456 546 683 410 228 456 272 456 456 228 546 456 456 456 456 456 456 546 456 182 182 410 591 456 591 456 456 500 591 638 456 228 591 410 456 272 456 456 456 456 456 272 410 683 546 410 591 228 500 638 410 546 591 479 546 832 182 819 410 410 228 287 773 228 456 591 157 729 228 291 ] ] >> endobj 218 0 obj << /Length 220 0 R /Filter /FlateDecode >> stream ß+tÞ¡ðœ`ûbz€f$[終ŒCTU£Ò%?Ä–i &5ïp¿+ø$Àé¢Ì=«þ ŠÉÒ’o›áƒ&]BßÕ I´ ßÅûÚáÙ*ðµìF±BÛQ‚%(Ü÷P’R™ÿŒ¿™tÇÑpâcC}baJׯɮ'ŒpñÃZ¨ÿkªjÀ ÇÃu‚%$ûŸ¿àöˆZ§‡?IÇ»h€ù|?町ó1ÐÙŽuyvÅø:¸Ó½aØT—£ôÒùÓ qÞ/îÕ{Î(¯Ã´V÷˜û¨îþ?¡&6‚)!&ºì§ùèä[‡1´YhxÂÿÙ§Q<"_l\'{ ¼/ÊQu±ˆ2UËÙ])l–£È€hŽm³ Нç#ïÊ7{8?Yí,³­“Öâb±¡Gî‡3ëùoÈOb¢?ÜŠŸ./i®Ì²Á©Ì£O×}6;-ç?7Ñ¡O7ÕJÁRò¡ï¾Ò×%àT­÷Õ´’— Ù7Õ€±yJO5ß i‘×Ö ãûÁA{GDiß]ȤÞ?’Q³Ê¢sÉc°É’x.»bç ä¨JÖi¼ìH=Lþí‘‘ºú.§§CK S tCCjžPŸ% '†Ï®:x(rôŒü™0æÁ[0zuëÉ÷M©´šW‡FÉ››´{ÝàiÚåIù¥ZL3ÕôTȾM7çs‚ 2eˆÆÄ‹àÌB)䀘îzýGòÏw endstream endobj 220 0 obj 576 endobj 221 0 obj << /Type /FontDescriptor /FontName /EAAAAC+LiberationSansNarrow-Italic /FontBBox [-223 -303 1000 1014] /Flags 97 /CapHeight 687 /Ascent 1014 /Descent -303 /ItalicAngle -12 /StemV 0 /MissingWidth 500 /FontFile2 222 0 R /CIDSet 223 0 R >> endobj 222 0 obj << /Length1 7732 /Length 224 0 R /Filter /FlateDecode >> stream ¹Þºòëaÿ\ÐQêªùÌúíàÆ1XŸ$ ¸Æ)%·bKUåŒÔx¿‡/ƒ«…¼C¾ÊâÓÊàû7ó_tÿSÌ'ÆâÑ÷(ƒ‘+6ƒèj„V¡€Õ†Án’ìÊ“-2„-R²E¤åʥ深´É]w2‘ÒL@˜1–p(Š)}¹D"˯r!ÏždÈ3`µºõa!K$•lµÐÛvû¾8A&+¤‚Ž 2ʯ3ƒÈ™†ñöó=Ýü—ËñÓÐÒ›ÖñYò+|ÁàÈÉÆ ó8¾F4Œ·ÇºvÏ÷Q9ËVdÁ«$Ή·èSA/„-²ÿK-EÑ‚„2¬…’µhG ° €í¯#{èÃVļG­Å#{›š’UþAÉ4*ðà›Pv›å¦¾J}.ò®õï˜ÚdD?\ÑKÒ£‡ô)!Dõw†í vÈ~cÇg/u*I‰äøe‰:Þqìó¢ØÿmYc‰+qr<âÒS=Q¾ßÞñgW^ŸJQÒ/là퇋˜yäNlM-¢4"‚R¹ïÄe âAtº#`‰¬×‰Xª-Ì9¸©ˆø†¾3aQ³[œ5jB}š«® ðíý§V|”!ËN‡Ú†äL§ªþ~zQÁzÊô¦¯r)ýêõB³T3²"&˜:¦ïïXtÂ/ä€6œmÏ øi™Šd¾Ð2¯N‘Ž Â…x¡3k’v:çO5ãGŸo½Òb5¦™‹-ª1Í>·%CšSõm*ÿŸdïÜGPBõß-ßiç¶3:–‰'ZšÄ߸[†Ì•Æ–k›ôà,[K|íÅú´%}±¸'ÒpGït )´™k¤!92Õ„êÇqkðšíb]vï;Üá§z4 Óµ¶b‡xb<¶˜âÿ¿E›øŽ Õ:©ÐÓÏ£ò^7bï\…$Ç5¼ãU{PiYÄ»1Ò„s‡=¾ W¹¢†ò®êyôXj°ò4"sý]"ZÚ"5–Kþ•ÔJiFv“¬É ˆQûÜ; arú•Á>/²tt]ºbÚ‘i &±¼@ô¦ OëUÍZoîãû¿9c[ØŸÏ £ëö#·}‚§‰@¹ÏâÝûŸ Ï’œÖQÔ%2Dx;#%=Hì!Í£™k4ã¢~{Ô½æœ%Cš/O<^c…ʧÿsRD:¿%ë?º#þ@,@àÜêæªÊÖÌÊ-Sý‚Ÿ«0ueç° fõLºá¼«›ü 5ËÀmÆ«â,ã,ÜÕNò…$†EO6b¸¦V#(̳æêÐ_ÆVî—Ù8îöëê{„a˜E­ç¦dô@åÎ>û3¶¼ÿ¥Lݽ­ šÚø¡µ=C’y#_ÝA§g˜¢¡½FŽZÊëoclME…'aÿù †Ê.YfϰŸÇ\†`åð÷‹[Rôת¬ ´²ûŸs)<®/OTÏå7T Ûe¨;üÇX&òùW_E<¸ÙRß­æáþ*ni•v1vÕÖçôù™¶"Ù \Á5‚d°ÖKgÝ÷—} X7£2ì—çéKy¯õÙ[ÖŸ„Ú ~k:œ€M]¾îí¡ªïQ|4¤‹<å±"ZT'OABÜ,FI&¶²ŸZXäsÇ}3>=,Ãô[8(ú¯ùžRì:RÑØYÏ‹ÆÙŸÌi¥ðt xµ-4y,XêÑÞý9 ˆŒ~:t'Þ;  3.M® ˜rSö ×ÉüOnŽ Qs´8ñå1.Õx¤›šÎº`Â@ŠfƒŠ¦nReŒ•|”ú¡´™³ë­ ÿÓÖ‹Ú€3 €„ýºGøsØÔïP&K½Ù›gi4zðOþ˜˜ó0ìÞ¦ÊW´ %®bE€L1ÖHCË„ñ]I¡òá‰×M©xhX<‡3’3­„¡]¦F XìØP c bµ©UÕ9”àù[p×?&åý¶4fw©¤çºùc/úò ¨,!°¥9WócïÌÖ)dv÷fñ„±Ê‰?º 3ìl&½ü‰Õ_4,¥pÛuæ†;°%ø ¾§Ü.Öy”iJ=¬Mx®íò¥Ù|;%VrLêøÖ¯øpéoiA%†¸‘ÎŒlíŒ!›_˜ÔKjŸÞrÒ3ÕÛ } öŠ"ƒ¨§ïP„ú "m‹ï\Ú§6²réù|Ö/B¬nð4‚Ám`}aþ;œ¢L +vVîØ(™ƒ*ùbQKcP…hÉkë— Y­F·¥-Êà£W)z)þ³\”<š]jJZ¥ˆûÐè¬Õ1w´¥Bš0’ê#cc›®Ißȶpú´$ááFö3>²×@ .Ø]Öüõ­Ü?þƒìm‰®pâôì$½?te†bå¢{³P ÆcL<üzÄf¶O‹1É(;Q–°ÞÙÚ×¢?ûv^/°wÞþ“RxCšy9‚߀Ö©‹íéiRíõGþnÆýˆÏAxëó‹Ñõ2NØN¶cûï£TÅ%OºF͋ްÿZؤ4NLR¼øþ(•Üa àæ=45|Á[œD·ãdJ¬"¹˜„o7²R,dÕLþÎÇW‰öy\p4¾!É9ÂO0¾º†èƒ™y‰ë(DÃΕ‰—™â§†_! lÏdëDî¾·\¶Œèõ1b"ܤVå{ …2z×›á"I‘+Uëx Øûî?$uIu÷€%—ß§€¼¾žÅëó.¢xæ“Y¬Å?U&(aÿ4^zC‹fZ^°à²rÝï—sÇ=uB­j(¶¶UR}p4:Çþ²›Ú—oƒÏ‘ÿËtöI€F‹ä.°Ú`yÙ9—PÐ÷ H¿†ÞÓï;§‡ &o[™ïö«©ý—Š¢ËÔt}|Á5ܰÂ^õ$bDQÃs4$VEáF@1 :"@ „-Ò¦Òdzìø[„1‰×¾ÃH€Çr>9úXǽfÈöº@¼lŠÔÌa`àptEÅ™W3¸»À¸¯¼Šr±+ì€úþqF%—¬Þ#Æns[9ñ9J.cªŒ‡©Ü;—YoyêYÚÞp¸­ïÞ §‡Såw}3 '||þØÒ}¢$ß qeâB“#¸q¶–—ÜõEvDÑ…l>5:úm$í¼7$°lkçÎî±ÑñaPt4DwùïSJ7–?é2è4‹¥xÊïJ¯Ô Ö ež­¿Ðó˜ÍgžiíEK¤<ý©Sýo0o•å Vvæ¡jžùûS–½°ÇÜêqQUYhì±"]vÙVp· 0ãôi½zîg‚˜tmÃE>`Gk³õ‘]›¾:ä' ÷lž.ø6@ yðY*‡ª9ž•.2Õò…ðÀü[1üÁ_k"Z”ÝngZž«yÂkzœ³EÛ.õÅY¦¯Ç2õ§8\Úµºá$h‘ŸA—*ì–À·‰¢¯ç ˜`œ·]Ë̶AÒÄŸ ×±!ÅŠ±+íK¾B9ÐX>ÝÿDÓ„—÷ñ•b=•¸ÇO[¨ô!Wïe$«F$Æ¿ï{(Ÿw¥ÏU> sSOù'ƒ£ì á¤X¹X,ÜkÙ£Z ¼ è`¢œé3U?\X¾:ƒ²ÑW$!£†ZÈ9‡’¿ÿ=0³-¾µùЏUß¾é}EèË\‘œÏþ%7[WÆÙq'¶%À*™#äšXábãP3–,ï‰ †úÌ\fà°ìä7@ &E5¢ß^_Fæ"¯<£íb‹Ò!¨¡{Džð ­â36 ¼éDqß…QrϪ$³2Vå›Ùèøb!%«áz'P—$‚ò€Ó»’”Ó¾—”Íz)ƒ Tø™ž¦BB¶êv•)v–Hìo¾RpZMXŒËΟ¥©Vö¹Lt¨âÐ9³ä° ¨Wô<â7ª_–µ0^©t¿éX$hð¢þÆE}ŸëüX‚±ëJl´6;ÄOý}u> rôDBYn¹}N:y»ÏmAüí`S»·[#öjË´¨hæ4å XYÙóÖ8 Ï0éFÇø–„÷4D¢óÛ¢Š§éòÕŠ«³+ÄáiÈy,”sS!%™­9çä®Ltã2Å¥G€‡s¡w™_]oe­(Åúƒ–ÄÍ‹UÆkæõBYF‹9 n乿#QÒpkÞ˹¬Yrö¸¹çk•Ž…ïHft ôy¶IãenBò¥ô©3T¿l‚1ž,…ë²ÓLs/„.ŒŸN'®b#$^nÿ±msîª(¸Åi.eänÿä«{¹ÄmÔyàClé€î™Š³á÷—}S+)|ÚªÿÎiW(=)¾ Õ§<'?\ð-!ÚªM¾¡jÌa;I'ƒ{D÷ 5ÚqOKø£f”œ=U;M!&náŠómø4ŽÁÝÉŠ¿ 1dó' x|2+5û“%Ñ®(×Ó<%¨nÐ$‚*üÔÙ]kF"T̽l_â• –¦öVšâùT‹Rö]ùóµZ,˜ÙÕ[Nµ‡Å²Òã Egˆ!K¢˜úŠVØñ³{Töà6[h7Áö 2õ€í›Ü)³rÛÜ 6”Ϫ jB¿ÈñÑeÅ¿ëå>3S¥ÕäÏÃ’¬œ9€<À(ûB’æî’ ÛñU¬¾‰/µ%}yïr<£§îãÇŒ&Ì zW óˆØ€uÖjô³m„òÝïÙ2Tñƒ7›5‡uI múQ¿àÓRlÐ)Ëü«ÝÔÄ þï!J,­•­÷~7Idë½/ŽÖ¢5€4Až& #Ï, \#&ù£Xæäÿ- ­ Ó´ŒSøñœÝCIö.NÆ2ÍLŒê Çv €™·î¬B)Ù-(±.YýÍ€0è¾Ù7ÛkØ]¿`¼ò€‹Ì"ZmÒ_‰öNWV«•йÑý„ÔxK?j`¸s×ûñÂÛ[B§ ‡Ô¢Î"¢ êþHDP7|™^qêÑÆ;Æjñ¾’Ùe+Ã" ÅIp`%-ƒ.mœc=ë!®—»É§øž6 z—cá0°Q¦)Ó¬vãÀxAÇR{¼äÄØDÂnçØšQKæ4 &a»=ô?Zö™W{x'Áæ¯Ò†&NĵWE ú†â/u¼ – þ}.ÖÒ6ƒÞ)W‰ü ÞmTº€}YF>iû]'‘Çïé½°ì=U[„û1’¦çêWcGP?¡ü‰óÆ=9KryºÃzÆ!ßNhå{GÚ[Ù‚6±], endstream endobj 224 0 obj 4736 endobj 223 0 obj << /Length 225 0 R /Filter /FlateDecode >> stream ó[:•ÇT›-1±u40£‡ä'–öþ¦swÂC÷eÊè)ˆ«VN˜²O5åÊŠä¾ endstream endobj 225 0 obj 48 endobj 226 0 obj << /Type /Font /Subtype /Type0 /BaseFont /EAAAAC+LiberationSansNarrow-Italic /Encoding /Identity-H /ToUnicode 227 0 R /DescendantFonts [228 0 R] >> endobj 228 0 obj << /Type /Font /BaseFont /EAAAAC+LiberationSansNarrow-Italic /CIDToGIDMap /Identity /Subtype /CIDFontType2 /CIDSystemInfo << /Registry (?«jÜ…zDqAÏ÷ªYŸ2QMae/Vüv¨ß;‹DkE) /Ordering (bæ Iÿ—Û:#!\)£ÑOä}ž&[äb\\ÄÒÖ) /Supplement 0 >> /FontDescriptor 221 0 R /DW 0 /W [ 0 [228 228 272 456 456 456 228 272 456 456 456 182 456 456 410 ] ] >> endobj 227 0 obj << /Length 229 0 R /Filter /FlateDecode >> stream gû²Ø&ñH£‡mWŸž;ä{¹Ò³£­ÇØwÚ.AÛ¼È&I”©8t¢ƒSQ“쎼Kßž À–+Œ½`hñ‘©‡ôÓóM(?Ô$/¢vë…Ù€OÜ?MòC­¬P® &‚œ‘›Ò¨óxï'ˆ!NÂøÙ¥_\¬Ç'Cýø±Óêá5#ÀØÇÞ þùéÝTñ—KãŽÛFÎq•Y†º•[BT 'é1q…ÈŠs½ž&îÁ Éo;§è¬~û=9ñè6|mVÛÆCxF”«¥§Ð@ˆÀ”Â^JRáЙÕ ,à1PĈY76²˜ý—mh _OKúI}thòÔdÞ¼lõò›ª ”ò–'¤’×K°½=SšGMa‹#o8K¬N`…ßÉBüa$Z L#w øg˜Ø˜ 8'ã9¬ endstream endobj 229 0 obj 320 endobj 230 0 obj << /Type /FontDescriptor /FontName /EAAAAD+LiberationSansNarrow-Bold /FontBBox [-151 -303 1000 1033] /Flags 33 /CapHeight 687 /Ascent 1033 /Descent -303 /ItalicAngle 0 /StemV 0 /MissingWidth 500 /FontFile2 231 0 R /CIDSet 232 0 R >> endobj 231 0 obj << /Length1 15180 /Length 233 0 R /Filter /FlateDecode >> stream -ÇA‡·(ʤt™èÁÇÅô|ϼ……§ÉQæ–xþ˜¤³dw‰dAM7 îõþ ­Û¼}»lÃi¹š=ò6éM4ÀÁ%tÊUpÒ`êÇQ屬à.æ+°‹Â¨ç:´¥Ÿ„ÑtQó$ v€8„è ~$f--â‡êÝ••£åÀùfB=L’-¾ýaÞz¨èW$`míH.¯3¹ã55W©ÜJs}…Ñû1ø,D2Z=¥rí™Ü=a“\u !÷>ê,U;œÒyíŠ&Ï3µ«wt~FEA¤Olþ²•½!š6Z£‘·š†œ6<„ :ßC3Ó£*¬\Šó±ÕÈ1¹ ˜aÖ`7ìI×v#îæMóaÃÙÔ*óÖ~þæ±1ó~žËìGÁǰ‡¸pÍÃÈs Ïȹ¡ÜêFHT:§iµ'q%ïΉEdâØüáx¥N³6žHSu·É€|7Ø5X±QPˆ»b·PrÔ—”­[dalÍi‡Ë%Él/U@˜M‹=²ö“ĬÃç:p¿ ÿŽeH¡ýSï©K½¹L0>‚ܾFÂ~Aã*é¶•¹6”#èÆî*Q€Ûó  @9 xÂAáœ6[Ý»0>D‘÷Àã@´ÆÖž¦G.7ªÛÊCJvVÓ8ùÙbp .W$NÝ>¢ýã¨çCi,ìåÏþÔŽ2ßɶ kTµã Æì9_[ã‡Ê 4D”"ÄYs¾\Dƒäc‹†öOe7m ó‹ûïËSýMÕŒf‰ÕC`[Ÿ`퇸[¼Õƒªb¿£âs† m$µ3ã ’D ] f¾CI(òGçp–-‰¢•/-–nÇB°è»26ÃÅÚŠNéXÿ×#®x ¦ Çi!ÖÎÇäyL¿ÉÂ#Šèþ0åêwÉUD16,8퉼‰E³Èè«i§3ä5•s -ôÌÝpL?™(ø¥¾òý¥Þ€] [%NNÍ,Øþaå[KÂa@b+öÁP£Ð\œ_Dî|”A ¡øg:b>åÙßÙ§€!#×ï?ÆþÃMOHYgÛMÙäÏŸýê¡[;[9D[.~¸ÆèߺÏ>MáqíÛ L{æ˜O³Ìâ.‹®Z¡½gMʆ2y/«…„hVÞ›gU ¡3kaÝ왉ø‚{‚ÔLÅ’$ÔÉ™”¤ViÙKƒKPOA'7°—‹«d ÂÀ\gè†äXÍ¢Wsh“Ϥ¸¡nVGnèÔ.h 7Ò£sÜ6¢ ÒnUœ\}¿-ÍÎɽï×ñzus¢)ºUÅRTVƒ´-GW.|£… ”M¯ŽïÇÇfnöµÈµî™?øe{ÿ¦¼WAÒ>Þ] eº|h6ƒú¨ÒBβÛúRË7³§+úèÓô½ìMn»,4òɹ©àáÂó,lç“Ú‰¿í¶;¶Sª'¦\Ô¿c:¯RÃ.çWFK:Œ˜¿RJ\AÃúSdi*sùkBg£àvX ˆº†RϘ¢š“úàõ ¬;´Ã«øï²#?»'eñnRò>þP1³à0î6»Ô[Ë·j¿ B’çž:ðø>QjpÅQ?éŠBcç`0 õ¢…¾ÆÃ^»EÊ=€aƒçS`½C´éZ«Yýw$Ò°AQ¹)´ˆW}·UæaÈý W:œzEÈØE@#lÍ©ëß –û£ë@hG¢âUÌìÇ ò<ÔÏÍFÚ÷U6Z,ÜuåȦ9öŸAbn =rÙ5[‡0ÊÐÿõ¼,îßt0)…› ?Žzê¿.‘ ÛMGc9OhÞ™,Èg¹€_’À©ÁÝ͆q„ epIšIæ8 ¨ÂÙWôÿtèDnâ§.GÛùj¯oÁñrY¦>l±Bp¿Ç¯Ÿ‹ÅÁ‡…ú7¡q˜¿Î)¨ €óÀ¯8’g)Ö¬3ô|~®$r¬·ÓqÜEàî´%Xjɳ+¶hwœóÞ›ü×ê˦±WÂ^,êAy–±·ªë~á¡ùQš»9ÍùCÄFGgþSÁ]÷O‚!Ð^‘1b¦Ì«i5Œ²å'7OÉ-á[Øò¹fW]ŽŽš_¬ÇO“ÓÈhö»²"Þh¼ÍëÖN­c=õCikî«Ã}"_^ëÊ^VÅ$&2üÜêŒ+™ø}ï8y°Ê¸›ÖM& Š:´EwÐ3”ÊYµJ~>ò3Í6![]Ù D'“‹ŒÜWP)¤3á® k[ 1½æ °~tbÕ+¦Ÿ­KÞ2•qP¿MAcî½]­M—æòŸÏm5rÛ&5_3ãzñ¤¨¦Æ ¨vãËÞÍ“E–A‰cÅȉÊÖ ¦6))"ÄAzC5§“w|[áÑÌ48¾e©Ù}h"k#ÙñHƒƒs,8}Æ‚»äF¿‚½ƒ˜¢•2!G«Õú7MÚŸ²¥¡Ä*ªµ÷QÞÖNíõ§ÚÁœb›åÈŒÜãG/-ÞC ý¹º0ÎÈÝ‘Øûøq5l¤jåRùY·{« âøÚX"C¿ ŸÞŒf'£Ò<™lœQ‚ö𬀀á‚Öm; aûŠ^-Ý]^¯ææsKxãHéUt¨ÏXy­€F/ÀEz§«¬„’KW•F5N3V«J!zrç=𛑠[Ù_1 >ˆF…0PI„PAŒÞ>®s–2t*Çq‡…ûÙ¡£[Åù¨¢#šÆ3@«$&+0<‚…Èj˵/ºÚŸ#/Él3îWpôNÐg} Ù´_°œ±#kgô­e–é$”ïëQéqÙDà­ü“Q‚$¡×‹Ï0EWμzgd¤ú‹™GnÙަkU s¸þ‘:BUçeMö‰i›1{K%–…CU[20¬…Ü4¾{iÞ¬ ä°ñس(*hü&{LÅxX{í§°gÏÝî˜Mêa‚œÕõzkÖ«Zä"‹6Ÿ˜Œ˜œ–¥t€QÞÌJkõ3²BopYUSY)°ê Í—,Ѱ6ü~èf_2HLáXØÛõp¡·î0bÜ$ ù3D‹VA„°f˜Å$‘®ÚäGÁ3•=HáOô'ÿºCJ·ö•F"ÈŠ2ÛpÑǬœßËÌñ2œƒ³#fò ønÜä»jàE»‘=²U ™”P¼]7¸Ç)žI¥µŽŸ{£îä`Mz¥,7äËŸäæZiöXœ¬°í ãÙy)zäœêg'Ÿ÷[HœUŒº„Ã… ˆ4)¥}>ózI\Öè]ô.¼ù!¡d^!A˜ÞÞª¤,b•y?±M0ÀóMXÂ?ã'áz¡Qd/¬—…?½oMñ^¿I–ãŒA Ø{«.c”TÈK‚˜«RÕèó"¬g³ímS®Ë‚‘•KY*þ°ûŽÿ­Å%<4ÝïH2ÜÔY<ªy¾Q>–2´ärÖ…`fÍt•Ù›üƒ@Ù=ãEê"‡ã–BûpWp"žÜåëgL }uSZGòÞèû³l^g1õ/@AšT:Ey†¹k"vÓÅ‘rÒн(fQ%l¨ÓFÂß¹ o£mM”Ü¿^áЏ’y†ß"‡I£_«±Ý¤°Òª€U6]ùÙ0Ë[”¤k Ça7xБæŸeO`â’fY™Ä¾9ÉÄÉRK­u Ê_;heïáÝ^ö£RdO %z€ØhüÃ,–;H(·‚À§jáQv(ÇbP¼²~\lÄqÝJ<ù*‚Øe.È‘£Ê•:¦Ú;p¼º#]Ì5RÔáàß,ÙÔvú±ç:Bý­Kç:½ôkÇ÷š0SsøýRsvn†"שœÄ㢤à5´GµQŽœòªe5êêJ”n.^&J´ ÌhA&®îšl1!B)båÅL~Ÿ½tƒÜª9+.9Þ\•Y Ži~HJÐ%rè¶|þ­ï@½ß ¾ª\w¹8ZÀ³Zò~ÊŠ1…M¥èÜëçu›Bà>hpŠ­5fªÁ³‰ŽÚ²‚è@nS†]4#± ~MqÝàŸ 28@– Zm2§¹HkÝ‹€6bW´jør~›FF\ÿ#!„¯[Zµd[¨O‹‚“ –UKÃàåÔ–_àìíYvè"Òÿ[¸§2-2ûeˆÁíÝô‰›Yôg!Uñäüå%– YC6ÒÇh]ˆ„¦¾SíÚEo˜dåN[Xeàæ´¹dä[¸h3&ïlxÎ6Oõšj÷mM‘r¥Ñ{Õ+†.f`PN—çFæ£a®µ¢Ò?tiN4{1鉓´(P1ÿ«±„EÙD ÃZ §çÎ7V5÷âÜwf@ Ûçûà«Pc?>öK˜öd•~«÷uÀ:à)[À¤qH_‹9íºèŠ’¹­žnÈÕ1ä„nóÍ mÂð*¦ï'þ´ŠÌ—›ýþ6Š=@ÙRØC}YBšGk¬ < â‡nV\*Nâɬe?lƒÛÔ‚ëªPj(Öhëíþ¨ÃÿTøFN¸nx½Mr|³ñÅú›šJ!‡!„Þ‘"¾î·ÕÇÓÝHÚ SBÚd—5&pßš¹q¦ÿÎ^J‰ƒ&)çÎû|¸>ž$[|¶fµópÃÇÃá5˜ÌVAP{á,7õtÿc:â´¨zúìÚTOFT`¼\Òl£R'ÝÎo“‰ìöÓñqä|id»^+’˜^c /ð[¸ìFËVÉ/õioepŸ ß3 {Xz&Ø” ÁV6š0¼¢‰>…F•¿!×¼šË؇ÐËÁƒdOÇ?‘dÕZ¼³•hZxÀåó› mM$Ý%Ò£c×ÉõÊ,Ø÷ÿ ¤ÔkuÆÉX"^ï¨yóò¶wB±Ø&ºÀ ež‘¯H«lÀ_=êúͺõ@­jRéÙ½ˆ¼Ø!ŒP¸.êJ‘kNÇ®K wk7P½ 9bXy•<'þ°é›uÉÑÔ¢çÆV;ÇÔ„“%ÌôÓe(|É%|’€âý¨¼6¸Óý:¥@ŽÌ‰wü/‡ûˆ ™jò„+u_›­aR<[¢á°.÷5û5„2,#š3Bk•fòˆì½JtŽ—}ƒëHW&W|/E<œÃ$n]Wñ&}?_–Òº)Æ®£ÏÖ®žÃN¸Rà©ìs¢}BÚ›áºw,ÈD' I+QÅþ| Ÿ$²+l€qlØÊ*^!]º¶7ÄÑÛ£ žÖŽ{ ‰òÛúÉQm3UÕ4Ç—ºÊ+i†x¤ûÜÒ‘½Å…Qÿ}=¿ F$åz­©ãŸ‚D(Ó8à1˜ë%îP|rh@“W-"Ýãi“#Þu+"žª‘Ë<Ö ¡ä…¼›VÅ[7æE/ùÔù꣛[փжµD„Ð Vlnµã÷®‹45´)¼®Žïú¬Òý#OËÏ«v@k ˜I;¦ä™ˆ>Ù•˜MÎIœvé-Øà·A[÷g7|·“ »õQÃÿ§»‡*å¨oÛ$EîàÌX„_å~¦ë…ËJ‹.zíö¹¤-ôS CÐY§¥ §PÁê¹zA¡€àå Cò$ÖQÚƘFå¿”S\KyÌ×¹rs†¡k$â.ßrš³êæ ωÎx1l 'lm‹ô'Qé,ê9(>À‡~<Š^9EZ8$€ZÁ§¦­rJ&Ì… bnh×­ÊbE¸/OÃ=¾^£öiÔ‡ÚFõ;ót©uä«ÂÒ¡–VG+d“w Ï 1.Ÿ²‘õ'ôa?µ[ÕIÒCàÇô=uš“*çkëØˆÄpý r' •ÁeM6߇}ÒÉ#T“†"ª–ŠuŸ±Kˆ{*o)Ãñ⬶Nérûd‘‰Hæï£ÊŽK˜Í@âAï­S§dŒqw2=†-M“âŽö …9¦»aM°L’1 [o(Þ(`ƒn(;4MàÓ¤•Ó3ôySGô«£©ÿ8;t—¬{ OøîªJQ;3˜*LÚh(XrÎR©= S+§k,T-e<ÎeJ6ÃF‰U+Lz.hsŽVž5ƒÉä=ã[—¸R׫^µb@ìV„‘; H'_ ×ÊŽ®jª§JKž‘G«®ä¸Ûð\žä>»ˆ,”09³¦§•Âé™Å4øóØ’R³‚î¦.Ùåý/ór «y&¸š.ã`ªŽq :‹åUïS,™ÁxÞ·ˆ`CJ°L–uVü^¥™êˆ†¦{ù,[0¸¿Û?º²QvµÄÝŸ'¼òàÓ=dµí9üO¥|½PÙÿNaöAþòŽë¿×åT¹à!Utˆ¿—‘s"Bꦜ8‹¹hwk3ìš×·ïL‘h‹J³È0?ò-®Pˆ.¼šW ®‹±ö œœ3ò·ÅßKÂÿl}±ŠÈƒoõN¯áÒØ™y³Ù©Ÿ€IIçµW¦Vž –^öœY ¬âõùg¿X{—ü¬vîƒÒ+¢óˆp"¸Œf°wšŸ$¹==,ˆ¨RsO±êÀöÔõ0ùcƒ7=©)îÇï–ÓÁtf€©¯áˆDª©g瀌ŒOÖ¸c(— Eò™]NDþØz) ”8Ñ*o*` Ôˆ©x½ÁÊÌJ[v`ÂFæ Inàa•H6·ºyç`NZ%¤9‹Ã9äIªš¿÷ {wçg2dœóÅüÂü› Éþ¡zˆ¦—ù'žÆêÌÜ»Wü2ýJlÔÞK…O)¶AÐK÷r_lT ð1s o9ÿ³.DáåýêýuµžÙäæ6áI72•›¶ÓhûæõABÄ È”NbCGj)ÎÇ4—š©hƒ“ÔÚÁ’¼ˆ0È'd‰«9˜ne€×ŠRwK²ãI¹±Âbq püûçîh%¤ihmO®2œ]AE¸¡ËŠ«º,4ɉZ]3P1NÅ“ôz¸Þ°pD£7?¨a¬§ÌÛ©•2Ôû߶ަýB©ÙU š_UÈK±€ÿÿäQÞ~”/}ô£S§FSGÅ£K/±Þ-ž/ž£/[˜{¤frð?Ë@ f;s‹›~÷j˜Wa”›b? ÌHªÆú>)=ßÁ¸‰[ìÍ”Å$Ã-¯v_çm!ˆùò`}Ô\)Û— 4ëÇAJ&|ÀR‰­oùÐÊ€SØ%Oér°/•´Ï£,ÓýzbìipœGûÅÈûÜ­ðY›ÝbÙ´‘JSñ?s#ÛkiˆÚÕ±^¿Ãg…·È>ƒ×1Iï¤!Uipޏ|ÑÊ7 ³Ø¬e§4KoÁ¬üÌ Heçó§wM‡w¹ÃéíLJÏåDqèÑ,³÷ÿÜž.±÷|Ò;Úë3kƾï’Ö¿šª;ìSÉRêènu^_Ù^ó£×9ÕÁÚ0ÞøS¥ˆ6((¥l^¥s4²±‹sáÇEþrþ¾ó ÓVš!õhTYB-ÀËÞºðºk&,»žëÏÈåMÀîÁ(efßú«RC§û„Ü„¦tx)ÕdßënÿîÔ­òåõ†z”ÊÂ"òe'™Ðº2§ÔÀG;äo¡V:×ó}€€Q›¥¼7yålV⣖èc¤bŒHša‰Dóßv”ÄÄø¿°Õ}™. õ¶Æ×97ª·MìxSyþáGÚ¶æñ:<šÎí[‰ÔáXs5fLÔbhŠhõÙ= r¨4bB„îk8€dXè·/lfðEÖI’‹î4>_° örœ×£"]*È›Or/Éœ™ï\m%XC^|þ9 E®ÿ ø6éÙ…eŽß\§Ä¿„A´¹vÁn&ú:Âý(Yeb} õ²™þ€Œ'çHÔü#z‘iƒ€õê牞M¦ŠÓ¿+3–¸ƒ°ÉŽ ”’y1ˆ*ìØbßüåZ;Hk[j1ã§ bøj¹@-pQÛ;Ï%3ÖpÞ§`‹@×GmȈkõ ä'5ãÍÕCÍÙ:>W 3n ·3‰»ÆcUbU¼r¤›¯}Í»x CÆþß ŒªÂ–Ý>v^¤$ Vo¡þÅàh:¶v€fnHº øº;œˆRÄžû§Âëðïǰ5ß`ZØÍ”ñÈÄI cq»çZÑOî ÜFãÏ$fß-—YUn Žc ÃÑ’.íÝûŠ‘v OVª3³Yߘ¨g+?ޝñ›é?8ø‡½²-ý•S«( Á®8k(vÕ¼ÈÃóo9iZ‚µê6¬f½Ít‡ÃÃÒß§îšÓ )én›ÐCRp@ÅMñ ׇð?)§Wàz¼ eŒjw:mVx1ß±EŽ­h»ÆIØÌoÒöù›‘óÚƒ22¬üzxrj¼ò+ù:ǧ÷ ¸=@^¢g»xeý$õ»?5\ŠE+ï{ßzð ùPš`5ê¨L³ù½÷´cm}ß@ÜÆ/÷…£ä¤Uñ@í·¤­ÅáLéCcTë…ö×t© 1©Â%6./õµžŽ½Ÿäô°!›¡¹’[}kï|Áö½û¸SýÿTÃûÈFÐ2[öÚUïÕbt§ä6ÿ"hÌ*  ym B«í±A¦C^µ])YçCiÎKµFM~fø»B® 3Ò¾O·˜Bv1÷Yä—(«øk¨PC &fávëÿS¯à›/²Y—óÙKç£2åüPeyk"€ñÂm*J«V»H¼4f‹|'8¸ä’„Ë^0^l­‰ÖŽe8:ŸÓN Fƒ™"i!«E‰IÌ¡á*µË6´Nüu(B+úš ÏÆÂYo!g¨OV¤ Ü—Ë>¼ÁAšˆÆQí©Bg½(IñyÜßè!&è¼KE)DÙzÇ$7jv¢S°‹<©Ýß/80ÌQ YÀ!«uh!•Ιٙ¡?k LÅ‚5~QFv]9jì˜Fö×&¶£ÝºZÏrW“0Ò¬Ç>a^(@ƒ0 8¯Â•™P¿C±Ë®ÚªäSôåéÏ>ïB`a¾6An¸P2‘fzŒõ¬õÀë}\] .ø~·i‘`ÈP7·U*p A¦ä––Öf ÍiFO5zò%µ¥z©͉¼¦„Ò…pË—Øޱb·[~“êY; b*¬zè±9 ¹--ê’p$L£Bæö‘@÷ûFZùêà“Cép°Ç¥¸Ñ³q¶I ²¶ËÔo½Ýsµ• _!{ª¬*þ§U­äÀdmëiù(òÒM­Ü>ûº ÉŠ^鱯I'ãèÜ-a겦襕ö}…ÝG³àè†{¨”WN¯j] †œ=ZT‡íÊ݆´Ÿ¾´²g0'g’Tlòn£…€¯o i¶qv<]Jr xÚµL´ÅD4‰ÑÍÖàe˜ï O¯$Jh­«Ì²áwdÄǪò>®•/8,&Ñ¥*¼QC¥lä$ÓÎÿUwÿø®1[>([µÍ•‹ùdkÜÔY؉+)Òßlû‚¹xˆä¾4þ?Æþž¬T­g|Q7%)TûŒ 3ÞBh²üß ÊÇfx-¡ÓÜÉ1¿|lÀG¶ݪê,Xj$}g^¸´³lË#Å„‹ 9¬Oû¦œ‡i âòñL6rLÐnû½ó±Š.|œZí"%©Uóœ †6ŒáÏòU?6Ì•™îËm€^°ƒA ’Ñ~Þ¾ôñ3$b¥lC…>´MRQaFüK…T'ºËÏõ@“°e¤òÕ4ÿ™rÖÑŠž¾¶’N’S*¡ÝCe˜}n gñ,¤¨ÜdRޤÙ>©MR9cžRì¬Ò–ÔèJ?ÐOÿ¬€B#¤Uú )9ÿÄ?yý޵ìJÁ5Yí︵èÛðØ4EVG”­U5/ѹ,†t¯©ÁR$´¯ôþ¢ºèo !7âšêö½†·xQФâ¿h#Xãss XfªͲƜñ¿rhÅR(·K×\sà?‰h¼ZÕMöñ²Ÿ¸भ&„»±=K $&]é¿K¬+é?ZiJ([•?‚öÂY]ãB“T)ÃnÙ/°fñ]”WOÆü %ýnPN±ÀÄpqijã.æðP¿BÄKÒ ‚=ÖŽ‹°Œ‡\2Wš¬ .:ÑÝ3ËW©º­-AÌn¾Ä 2‘ëWH£eÆ™bÄ Çè ²gªó•$,é Œež`ÍÍèÜ’SJmð2‰p(b(ª…lÉ¥Ü)t aiF¥.ÿ²ÖÄ`g÷ií&vadzp\çT;Qž[+À­¯ñÙÓ;+L¨Ð“¬í¶ôº¯ÉIVKOONŸTÓy„…Š€7ú¡•œåǹo¿‚üZ›àw®ì“Ëe‰q¯*Ù™#E_Ñí=¤t‘âòYRYh<»kž7?¥M¶ÉláÐ^ÏtF¿ˆ%.¡Çqž‘ä~D²åÀx½Î6•òö1øùŸÅ‹N¥V5WG)Mý] ”`q`s ÂÚýˆO/¾*öÍDa8ìî¾UB |4—`hidb•Ä0WºCi€Žƒ˜ó$ÙZìË1¨@Hnöí9´æŒŠ©K”†+¯Š¬âãÒ[{¹ŸÎéOVV¶rp‰o„B ô£s†Z#Q{³BJ–L e ex‹ŒvÁpEÅ·v=LÀÄÆöÚüR‡ k5ƒöœ—܇ Ê2:šf sξ؂ïÔwܽ­þ`ì`ŸGÄ¡ù:ïàa-":O¢ÁSÌê›n>¬º[Õkß•Re—QU„ç íÖ§ö.ÄU-Æ!ô‰òx¼ça ‘Áä-$-¨»ñÄ·T aá“€Ò,q1çvLÿ6 û¤RŽ_ˆV€­wM9K8¬&!}”¦)Ð~èñ Ü,0÷Yò OÂr`QBu1ôí14w Aš6ÃÝ€L!×q¨ÛØé×1®Ÿä¶ ÜD›PZ*áéMTu›vÕyÜež#ŽëJcäx gFþ TÿáŠ?BöT+Xáb`ÍúMpeÜ™ðÞ@Áüõ•/ÅéÊ<¨STW5›Ï…€ƒ’èC£T÷Âõ®÷““¸ÑRu=´G¤S¥§Æc¶¾@/2ž7O…eyd;²UBµŠ\¢~(÷Ä [ûºUÆHÐo suü¼x¿ý´`§ÔvÃ;¬'Î „²¾òB΃'Y®*ŽJˆÜßKNOËmk¹F}Û„¡ Æã’vJŽjÃlcˆÓôôoëî u'É2í˜5󉛘õ#©²žlÎÁïüAl/À?x–ª_1Ë—‡ÒBŠz0â+s¥×.°vúòäüfæ&&UÈ\1ìäRãÿ9ÿt¾&(K³|Jà`å+‡…°££—)I• Tº'®‹cçRÇ][ßçߎ.ˆéEh_÷ôs ; endstream endobj 233 0 obj 10032 endobj 232 0 obj << /Length 234 0 R /Filter /FlateDecode >> stream ´ÌþÐ0ÛK ‰-RŒUkú<ýÔíø´»±÷v´æx‡¿¿fLù?ÙÃ…¯ÖÙú! â endstream endobj 234 0 obj 48 endobj 235 0 obj << /Type /Font /Subtype /Type0 /BaseFont /EAAAAD+LiberationSansNarrow-Bold /Encoding /Identity-H /ToUnicode 236 0 R /DescendantFonts [237 0 R] >> endobj 237 0 obj << /Type /Font /BaseFont /EAAAAD+LiberationSansNarrow-Bold /CIDToGIDMap /Identity /Subtype /CIDFontType2 /CIDSystemInfo << /Registry (¶1=\b.‰dŒD*g‘¨Ô®â1wÍ´}*R>x2¬×K) /Ordering (7á,\f£™NVæ²÷ÚÒn»W¾œ¶Ì¡m=üæðtèæ) /Supplement 0 >> /FontDescriptor 230 0 R /DW 0 /W [ 0 [228 228 272 456 546 456 456 456 500 272 228 456 546 729 456 318 456 683 456 500 500 500 228 500 456 500 500 456 456 591 456 773 456 456 591 591 500 500 272 272 456 591 410 591 500 638 456 546 500 228 591 456 456 ] ] >> endobj 236 0 obj << /Length 238 0 R /Filter /FlateDecode >> stream HÂ,†{î?#²«ü~êˆÀÊ þO)'ŒÄcæ£Èåó]“&v)׎’9N•æ:“¶ Äœè±W®½ðÄr;t% Ï­ #‡ ®–Š}á­¶,A6Æqª~à8)Ì¥××A"†ÆØF8iJátcß–ÆÕùO¿-gËÌØì‘/#è½#}ô4IÿÑßò¬ãý—Kä~ “âÝÕkÁFÀöÙf® 8€A÷ó'‹Ðl”0fýpcö@í"`ò¶Ð›Ü< ¥P±Jh,ïBÛTýðïmV¥ÅÒ¨]å¯\ÉŽ‘FÞµž¬¼ÌœŒäùÊ9õF–ÄêXˆß­ýAæy¨VõûH‚îS´T ÊaÊ9–½ŽSñÈŒàîÖºwëDŽeSºÛFÖ÷ï@T;,D<Ù€gíÃç2{ŽßNÓÀË–° £4™ú'¼ÄÏñëd»–`ºŽUgf$ mUè"Hª´Ž 'Šú’yZW®êÛ ¬­ÿ‡¡á-X3o7èíÑÚQßЃA+QÇѦvlsŒËåÏäú%y¡ž˜ÿÔx=»—&´B7ÀJPhùõóUtv¥'?×£©Ä#'“?eâÑ5C0õÓ§í endstream endobj 238 0 obj 480 endobj 239 0 obj << /Type /FontDescriptor /FontName /EAAAAE+LiberationMono /FontBBox [-481 -300 742 980] /Flags 35 /CapHeight 658 /Ascent 980 /Descent -300 /ItalicAngle 0 /StemV 0 /MissingWidth 500 /FontFile2 240 0 R /CIDSet 241 0 R >> endobj 240 0 obj << /Length1 18020 /Length 242 0 R /Filter /FlateDecode >> stream y¥fky 5 V`;n¯aØÇŒžƒÓê§Ýe)f‘ì\.¶Äiw«`@˜ .Ñkz}±O‡¤t7!±`Dä™Åð†¿ —¸*D³ÀÊÚ¶§X´Ü’|…7"Å„Cï^:0ÓàÏd5BÙˆ¡Çu©-?&-ëµÆÚjãGÔ<WUplj¦ÂwýR …•ª£6^qOæàÁH…-|¿Ù'оå%תãz °/þ ¢ÉŠº:%#›jX€dötâFívô`Å"ÔU熀I˜²QFš²á½Ö§)öøÇAÊœ¤Nî¥ÁpÉjÓ„3J•C5É¢€Ä+L5¢üéþ0Uú‹YB»rÍØ<ƒ)¿ÁµšÿÄfæÓhô©À+þšÀ&*¢÷È9xÓ¿Ísè|±„GȱD†Å<øšôkÁÏVtÖ\Ò|é‰B¨òï›ÐÐE–Ïh¶ûv²K3jOÆؼz[{Éóó@‚”¢‘ÙU¾OBÕ #€žÁ†­€—2\U–è¾¢y%WÍœu F‚càKÖ-'v›¨Õ8uk*h`«Ëßôƒ·LÙºt)ØŒñ{u…[ùùçFî‰jù°ªzû¼ó4-,ºî ü§•;ÿ^žKþTŽïH¬¾É\ž«¯¾äƒ|"”¦à;d8©Î+P'PªØ†|‘Mèÿㆾ©û#Ëž{¥¤Ä÷ªþSÅ3`?VÂ2PÂÖ—ÛQœÞ´z]žD»§•¾€Ý-â®,|¹ïb0²#{V*îzy!$jÂÉrJá‡27ÞçxéŒ<>…¿Dc`( \1=ð|¨=•> Úöˆ’?2”ò&Ó‚^Oæ¹¥#;gy˜5 uW'ÂþnË0øi„å§ Ì@(vy‰ªŸ¡> Uà$Z641®P*#§Û£þóž`º‰ìÑM^Wm ›y¥›p«à2-($°&ä™á|w­¬u€¸Æ¦ÕŸô{gt £Ô ½š`Žœ‰°s~dg“Ù0(1&y¯CÇU´-ú^ü°†F5DRÌ®wI hïߥ÷&Hf®þ@“²ËƒÎ¢©žA KH(šù‡ŸÓŒ¹×)>à RYC5ì¿çÇ·˜±^j?²aú!Òû2ygÓÿÙ:ž(ñ|"jÍŠÖÍÆžFjkñ¨r…ñnÑÿ—0þ¸ž2.>ÁØl¦”á|c b¡¥}ô}ô¬Gs…ë$Q‘ÉÂÍÔ›r,–S¦§Œ\í«†íß`i«wŠšA5lIUˆã«éÊ ‘]¼Øô9ìk~ܧ^Zo°Ø|âÍ<`Út ²ox•˜á,V•ñ£sÞ!evÈKèˆ.e¹òcÇœ¡ké 4¨~ Ò² ÜÊŒÖYÚ'šÎ3)ëו›‹¢ÖzL½¥Ç¼éRzÑ 2“V¨ò‡%m’¨ã¥L)5UÛ|¶@4žÛè’Ìܘ¥ÇÍiTÃäzH¶ó¹Åµ±Ž(RkRXµŽ .ç-ÜÍ|¤¥E~Lµq‘þNhZ3 ê@Ø¥+$»Ò®s‹Z\3ÙÈq¯ä%ÿ†_+¸ÿD±°óI£è´Ö¡fˆÈ°ŒO¼Õ^ø|X ïQ[q]ƒô´9ît¹\½PyÞ?›’:L¬%õ¥ª[Ÿ7~]ØBá•xkù¯iÞ£†Ï@ãº$’iZõ©Î6éiÜAß â@f,‚¦%|°´“­jQ‡üìØâ .J¶FR˜Þ£ð†™¼n-¡o¼g+„]q a‚\™>‹«jV(­i‡æW¶Dm "ãÜè¸Êã„|i§á¾öPf“˜J†·±Lƒl\!êùF°©‚hCiY*DêäkUUcùE%þßIì|âaK×1“õSŒÈL<ŠÊœÂ´îÀhº¸q,¨(GÔßʵ}+»Â¡ÑºFÉ€{(ð‡ý“½¸µp¾·Ës:`€PÄOîG ‡TéƒkÕ‘Áئ ÞÑ–f©LÌ ­cpµóÓGÛ}$ F÷ôuc¾ç í¨…+'3ÝÙ—Dw#Gûnæ”´/²mW¬ËMÂ×è%§eèûô©Ê”nlù)ÖÃòð/ÚI±Å+æsi5àÕÝ”rÅùM”'ËOns’ÞŸ ¢xpÔÜràcdS³‡ë£g]âÝ$—Êʸ>vÁêº-@áÞâ€t¤&/ph77í>éÒ£zàG Z"dçËÕgU†ú'ù$#Ÿt‚æCé§_[3!¶ i @+üzVÁõïàˆgS\ì~>¿1С‰IÀÄ¿yFjéÕË ÔE˜ÌIG’¸Š€c”¨jõ‰.-6Ï÷nÓy©t’Qg-/e9þó¡í~™Ÿ×k„V ³*™ÂJ¡;A¡Š7XMà[¡ä¯1T—w@«œKÚ #ëÝ>‰e}tÂ7ãd>\¬]² ˜.¹òŸ›ûò- ôÉ‹ý0¡Ï®uÌÕVæmµ!ö¡fRÆÆbåÄ<> èŸÈáiðn We—§F |û]â{íºR–—üÀÉøÄ8Ü£Œï`%j‘Ãtéç¾×"çigCØY)I8KÆC?—z¶ÍmµyÄ0Ïæ |¼PfÉ$!©-NQþÑ ³<»okÆœÝÞ˜”×=àÊAg„Mš‡¯ñÂ3¨—ËõWÊŸ_r8aÏj/ÆjÉr¸íR´gºØ ú–ùeéà+ÇjÛÖ6\^L•¥)k8… óÄ8²&-Ä¡Rqkû Lpð2¹q‘>ÖÚ°Lݵ±®}²Gcc)m;=X0’dì«^®ÀÃW iiIJHÚ¥Ýô¿Áþ6 Á[Ðl‡àÔ—_${kãNN¼¡êÕæ 5bz²UÏdì+Wì~—Þ¼Ôù>díˆÅ»‚%3‰#1bSQúø{¦’oªbÑF(ÎÂ…€ô×Ãù3:L9p'(ÅaȺ‘-n§ÑM]qœÝJsþX/¼à+kÍTç%WŽOMßèÝËPÆõ9.´ÉÁ$HÂ~:‘â5ÁC5GœÂöð>¯¦±ùe‡îÓª‰9np²ßé!0Ñs¤:Ïí¥aNbºà«+Ü J^cÓªqµ‡Všàµ;üøV´6|Úƒ ¬öœaÑ#7=³®`i_·"¿ ŠC¯dú’þ²yiƒ:ZžGÂ?Dÿ¥ý¢ ­WrN5mY2«Âž»Û1Ñ•(„¿òL ÌÖ6õ§}m5“ T·‚$Ç$÷.@WÓW\X¢UàªåGµú­‰®ªŸU®°Ú"¬LôÃãXäw>°‚H @Ø¿D^˜õAä:TE^ñ7uì‘:FÀ]ÂïH˜÷Fµ÷Ëw¶»£Ä§¬‡8Ùqìå§r ¢ƒéA-¬…~*&õžvëPî1šÒdȘ.¤É\´ã’Jæ‚XVÔ"”ôü«Ù®+Ò¿Õl3pôÇ2vÅSnFu¼$ºÈj˜4 <÷Ôê°yñVš H†p)_¤{¥§4ƒB©Õö†‹^Û4Uß®?e.r¿“(êjhý̲Ì*•<][ Žz5®Ê ”e¿Îû›%,&wb žÄ>Þ}¦´¨)6¤(JÊjÈí¶Wã„‘e ÝBklD&W$T¸`÷¿’.Óí…J)œƒ½Ž÷¼¡ª–†“sKÁ¦üÔ)÷˳ýD‰…ªb,‹‘ôbDB/Ì–˜Ê ŒOÞ]Ä“W;–«Aea£å¼êJúl2kÿï´þ|vÃ܈>¾| Úgh/;gn³¡½˜ùŒ Ï¿“ˆÎrrh‡|4 Óx¼ºc?ë `s`ðM}iÃM–"ñÌuDZävÅ18L¶òЊ½ìçù@ʯŒ9rïÀ¾´6 ÃR2פÂß_Ù¹<:E(Ô8šÄR  ˜§)›HVY¨dÇðd?jÆüî)?lz »fBÍ+D8;¼ó{öÃ…ät°=qÇêˆ&NRìÅ —]dwUò|‡Íµ6qñœYFIOó $ZÚäpþD"ÿ,Î(:nßÚ6jó$ÏŠ¯-W)…‡¾D´…çv’R ­:~Ì,ñÍfG>·ÛD±È¦ݙճÇõuåmè²j',~röç1&‚ü­·7ÉÓIêM¹—¾x=3)M|c÷íãS‡Àõr`òÁüìsâ)…0px—Ñ•FòQF` ©Æ[ÏØ¹ÑtO}Ö'u.ÄÀA¼àïÚ3âš³/šÉZe„¥bÚ—!òe¾/˜ô¸‹d#^9 ˪ •Y¦˜"ˆÞF­F蚌9ÇR¢ú| jUéë´ð°¢ ÊkÓqZ¾Qi 4íWfe„öb¯×5ßl Ö¨úž„®(‰ÄM‘Ê}J·ÔÞ/ —â’s°›U^'¾§0înË€íp)¯ ¶gÞíëõ9ƒ—qž #¸¨ÞtüÌSÂBø‰/øêújSR˜h—…)YKŠŒ¤É«˜‹"Su„gýK[Ív›¸„$,À›\(çgj3Ê2âðKd lÒX9JÃÉO~}1 g±7‡”«þã8ÎO¡}Ä‚›BQ_Ðpå{}ìw¿| Ü›$É—a%ÄŸEa2&Õ€¥^{Ù”L~Ey·Õ8¹Æ@8ä+0²yæŠ`‹ë´£äOñ†÷úøà‹Å’Û›Ù4;´8·}x*Ip@›~øjG¥ØGHkÿ¼Ox0íñ¸Þ³²³¤nJm‘b¤,(’Jvºõt¯ì‰ì!²‹G2Ý¡ç8æ¿¢ÿÒR¯i;MBGdüˆ…2yó-Ý’­˜Ý꡾=£âüå¹Â_VéB[“rk#O“¾ÁN…Ó äôiqΧ2«-%²ïQ ï<¦Wöæ­bç*_Ó­V¥xtö¢³þÇÏZSzuüIT£eRŽ. /lŠ)”ª#‰í™fQŽïIÚŠ¤*°BÈ3ï7£­®àßq5N%ÆAÃ(‹6å§áìî¯rdA4¼gý)Ð-âŠõþÛ¿ t§OFº‹Ê>+ôòqE—æ·ÑZijßÕš+ß²#eRóøqÐá[U1 b0²‚Ùðâ40ñ?dwŠfÂE«F¬¼ ¹›ÆõO‡AÓÝ“ js}愵x»Ýºá»?ÏF‘æH;Š–¢9ý(IjiDxl‰yùÉ@œ Ä9yZtVgkyøÃÌ̃¦Øn#ÊŒK eýò–ƒÃ—ÇÛ>Žú\éÞ<Öz¥”Éž#0ãÉ’u·ÊÌÓ?!¤•=õ"<7{LïsPVà°’‰kt Þhõ ¢Xf ˜¤³½ÀÏX‘x¼êÙ3OA Ò²"H—ÖDØþ^ yK©¯Ê¬0ká; bü©è #uÀ˜ {AH/¨Ð[^*6ê&âþ)[6)ðìÁ¢gk]ÉÍÿ÷Æ.FßeàT¢,RP(Åw(Àýº™_u¯ÀÔê¨APÅÕt }´€ÛßL€\爰å+µ™õ[Ò‘û¹ †˜MJ—´‡ù¶, 4Õ„Râ\fy®ÏÂÏ9 ò·!I¨QeÉ(FyÊfýÂ<_·cÜ:q„wë_¤Ò°_è?ÒP¬Óµj[\ŠåP,ªí½®>¡T˜k.#…?Å©Aœµ•Â{ÝI 岬1£ «¡~õQT;ZÀãêdî[ã?!ÀÌÏè½JÎ6‘ ½Ìcb «MžàpŒ8‹D`zPÜ­›uÛaï0Ç6­vvŸ µº1Ý–U;)ëS¢.·nN¼f¡›÷L5¢ îü‚Oª™›iÏ6Óžz×GF>¢0Wéž®6Äúƒà÷_认ü]›q4¸ØnlD% oE¿QÔEÊ”‰¶ð%œ²Ü"ó!«ÝàáÀ¦T²Ø~üˆnlÄ à€Ï ¤ˆøSóÚ‚¶uÖå3D€™Æ«`´$O¿ð/?öÁežÈ1"TVƒîÃòCU(̘v5Èöàæ´Iû13š«§€èB·Ú=«2ì — ;h-àˆñ~ÚU¨v~¤œ£l Ô³r·º¨ ¶¢g¡/úPt²°Û1ÍÏ[{ÇÙD;+p)S ör@Ÿ˜z×õ7ÄçïBwÄM¥u÷V×OX–gGI’ À/6¹\Ú@N‚1lÍ|€RZ8¼1¦ÓehI=j<­¹饰<)€ ®-˜ zûƒKXP*Y^éÏî– òß ä¥똜@ÍŽ ü ´ µ»s󞑦Ëk±?…s©²gaξê¢F½Es2^”Fä(¨GÚQô¶Ð5»þ¯/ˆ¯Ï"ïØªbóy.4)‡bHiƒÌމ21Üæ‡AE(¾Ñ[J™#qOêM¢ï¢b›.R®%)¡A>‚ŽcÿKN±ÚwnKŽFó%töAé“öbDÅS—|qêU%θõÚ¶« ë+-üPÐÖ ÕóPñ¼1)ƒ>EØEF’ô'ìüGH7Q®vÀY »­ü fÈTý6‰÷'l²¤ìAnõI]•Òqcï&0â£t?f¨bçté”÷x÷Q îÈbß³§!¨š,Eü0Ì.ÿ¨”|MDçu¯nõi€>ؾ.“áɰZd…„1J£Ã*¨.™~r¶>›+'féÅ!SÒo>UÛŸ}~JCr€A`dÜm⑯늠¬ÂpKÐ ®žŽÍܬÐÛhû'3Nþýó,9&ð,¡!d ×s‚Il¹å¡>Ý){¾‡át"µƒ‹I™-žj ÇÆÑ†v¼zkÄKŠåÈ!Ò ëÕŠÇ ¯ú iú¡üL±&—V\†º‡¢Š#äénF½Å|`©7Ÿêä‚òM~ÕPÙ‹¨{:f¨\®Gi~Euǽ(Rçw˜ÃÊÞ¬@/—,yÕöìk­±-A ƒèð®"T{²Y%’†÷B€ü< 9«"'=]0pDɱž_I+ÂA'M¤ÃŠ9tùÑ®úBö#&Y7bì`#ulc™ûr lº,ïtB7DPCr‡ ¯ïEfn.:ØÎ…T“Ö‘hYr%ht¨6ÌsÏãŸZ:#48q›QÔ­, `XjtH_2¼Ì74éµPG2†¯è‚[h|þbú®sÎGŽP¤ªÄÒÏäÔsóYè]t Â'Ы²µÀÃÖkU”m§ú¾~É9™%7=®qê/¯çÇÐxzž90NÞ‡¼NJT÷ÌXT¨ïÍÚy¿Ñ„‡&†ÎŽG dÓJ;U¡û$` ‰5FX5ö¹<ÅÒ±­å§ÚVçzI·sÙAþÝ ú{sãEže¨dýQBÊj­´"l_ d™SŒsΗãCBÕTæß¨ð“”>øÑ¹ZvÆÙ_üD×~túïzsF4£â“}{#/9šOo©‡¸òF ŒÎsvWT„å>âTírª³8ŽÃ²ÆWpÖÃjòLÁªË‹ žVÅ&’!ÿDÄ8%æ0 …X¤I™¼Ëû+ÕGlà•{ÒŠ dOñ•?‚“K€Ý6—™ÑVVõÕ(S$‚è¬ûŸµÇqQ]É—'k¿G]}é¢ÛÆ^M¥öÓ¦)±qî-¸*Ac—4ÊÉ-¤2Á Ñl„!³ßy¿$ÿ ,.„Y+ n€ë @š%›S,lIž|9·÷æ&É£±ú Ý&NI~€F…ör?±7¤¿Äúan¿k£T2ûó=l¹m—¦ö´ï.Sý¨úŠa«ó¿ÙìW¬¯®ªjÇkÐBC·Êî®ÞÅøÌÀp}¦1Ë(ž¬K¶¹ Ðqd¥R€¾[iÎOÒU"3ô|RÝЉCçL-rØ÷±êÔ1õÖ™! ièɲ”VÉ&ï¿ìÝÂè)ˆ¡¨Ð\Š‹ ©¶›&d#KÇ}÷&{³2íÇúmÍômÝâbv£ñ•aZ½ÿçC^›0Çë"8<ÒÈèˆpc5ÜÜÅ6‹£g@õ:V%¢kÅðg›ƒi¯©+Cæ-qgüZ“ÞˆpI$RÜ0}ÁŒuc¨Y£½™¶ zŒ=r^¹µ?Ä`¯0 þé#øI]UIjaÊ)š¡^?»õ/ ´p£…Ï¥ý‰3Z¢0¾T7:°]ZõvËtεÒ™µ#ÌbèÆVFÕ•,«´R ”„[7§/ÿ|6pïaPÓJGZK$î=ë@›!~˜Âçíà15e°©J—¤LS¤=i"«¯<—í–%>‹Î'.VÕ𜠷ⓘ¥¦ É(µé¥h’ÃÐ%B Å‹¹pá½<쀟hë®Á^ÞR¼éËYÚѸ׊ÀV¹((YôÈ‹|@–Ûê¾Ñ(õS^;€Ëþšo…,Üwaÿ×Rú‘ÞÃûMGˆÄ%:VÏfÃA6É å }ˆ~0æ »al»Å‹WÖ EãR8•SQå ø9}ï'ÏÊáÅ(Ãs´ >©Ð7…mSs¦Š×%Áœä¤ÉFŽªÑuŸW2¯÷°¬-„Y¤g¾üešŸkWvÚ‡g¹zh¿_m‚lÇ÷³ é-ÿ¯!Z³}jeiGõ¾¿*ˆÇ„ÓküÏsL-VŸæýpg’†F=¥¦¥ÔüŸNÀásÚÚ'ízkw "Զו$Õp7Ì•Y,H¨ÚÎTXï‚‘ÿ¤±UÄ.Ö˜ø¦Ÿ¶éy³ÞÂ[*z½CÓŤÞ(—ÏÎÎZ¢ R²‹Cp¯YsÙ\gH•1ÿ™…-MÕ°þ§„JÆJ,¬ÿ1§Ìµ7ù7B¨iß•¡6pŽxiLÛÛºÕ\AMO¶µ˜ò`\=ÙÍ+qT΃™GQy: ™g:GgA|?¡«UÈÙ©çjÈ ‰ÛÎÖŽÄçK¦/1粋Àð1#´ §›~ݾ‰-–¶þ¬Jì²á—æ°-²×7Ì.ݱ+…Ü“â êlÀ€æjƒs ±CÙl˜ü1oýþ´T;šþõüíu9ÐWPtõÙ—Ú甈åºxÎ.7{x÷Ñ2©­Ge]¯áw‘ÃüæÎŸÆB¢§ªˆ^ñe?ÁÒÿø³æ{÷L¥¢ø±g¢Ë‚Uœ¾…ð7n0)“ñÖÝ ¶ž-Dö(pÁOMr•"¡™eGW¦” 0­œÇ>¾C•c~ƒ0“€bÁ¶Ž9œs”9 e2)iÎ×+c®:¿#s 6¿mFÁd4CðåN£fjè;0»Rìâ+ „xvÀÑ'j€`º%¬/X×êaðsýC 4€¤zpU]Ǩé=ÑGØÙ—6)Œï‰Ì×YáÍûš‚´%Âü .w´Y6}—Ê¡ ¥bã‡çtà*/W¡:Ûe³LÁ×ÄU`ˆÓÒOÍ•g¥ÊVN½ä”fíŠgø¯ÎaæÑ0.h'´q/ýN?Ò×ñ>㪅Q©ê&´’ÕN‰ŸËPFW‡JºïŠ€ÆL¿õÉöŽÌ75pi86pä SïÄað¶.µ§†³Gµp‚7l†¢ÝaÕÊZÉ›7L¡ÓÜŸ!vD±€‡bp3²›2Tž_ÇØiD'víÇ”XZšœcU>ư•§Üœ†«‡™S‡yãŠ8šÛ¯7=ícñÑl·F±Ia=”ëÏâ¨Òݦ‹-C3¾Ç) w½W£M1~_$Cý´)œU0K—nû« ¬ÆŸt£¬xѳܥtHpú]î|ìž·¼¼ÃÒÒ`Ù–êä^hj|Y_•×±v§›×Dï߄ʕ£&ΩÕw»#|›Ø}ä[l×Q3Ë%Ú‡'o†]*¥êÍg8»cxµ|âê¼BÆW¬‡Hx¨WønŒæ@Îfåáö ª—¹FÍ  ‹žÔãN_šÄEâl‚H]–ŽWˆ*acw†Gk÷õ*­&JʵäêhmVYÁùŒ¼7fÙWòÀá‹[­_]›‚Ý̦œÞž ß< ÐDS‹#Z&ßcÎ6¸ ŸBòUä–Â8H"¯žœoÐzöBMKléMû[±™ ïSj_ƒÑç„«n (>ã‹‹ìVØúèí>e×á‡ú1„[,$Ý\þõ¤ü¿‚ùñQáÝKŸL¤¿]9:bŠÅ2&"yPÄ®wm‚Â줩•bÛh…ÄÌ©Ý…ÐæïqóøU©—NARíý¬ùýϧH¥\ÇÄɰ$m‡U'9zBý~´¢uÎkEµE%]û*\Žî<OLCÁ‡d¹pTj|GöÜ2iöb¼,ä\°¾~Έds÷Š—x,Åë·àiõE8æ@i…Þm”WWÑÑÓ䩉œ›­’Z¢>+5q²‡#7І´Ågaq À“œSoÔ–[èéb¨”j0HÝzJÙŸ“`SµÊ~d†¹!p´¡XÚï¬Ôß{`®ßS‡¹pfGçÚJû©C5rþ yO]tšÏ Y8Ó¥žK¼á©Â_qåîÆÚûÀKÚ\N("z·£/âÔ˽°"BÝÄ)©X  ðRàÊþEHåR¸1Éýì:CYdÒdoØså‘)Ñÿ#åHP‹×ÚA܉d1œb^ õ”! {qR(²ÕÙ6ÚéS6{f3\…2& œUÉyñ=`—¥SUØzÍFÈG¤3 NTŸã‰ö²Cö„˼¿ôÃ;¬¨Ùl Ž•< ~þæµ2ÊJç nk?—»9“Þ#³e½{^ù²~j+¯Ü¾¯ˆðW€„j…Dò…É„P`6T[¤Ìì4d$À)ü9&?&JŒži3 ïÂí+–†º~²5¯™á•¼ËÎmKªð̺ÀR^õ£9:WD\!¡äNjœ#™K=QÄ$sÚfÞªl‘‘·‡—_ªbç~FÇÊ9;ißHxñíÜ Rœ¤ Ó—“EL ëÂÖ<ÆžƒŠ¼‰¼¶ùÆXù¦$Sò"ߣžQhácgij„Íã£1¦`[ ‚ Þû~ÁˆâOzáãdS4˜iå8&–Z™qâÍšX‘§€Ž£"ãŒ{ŒBA(q­‘9ÚxöªYåXçtü É£€PÂ9uvRfµä‡|–S™@(",E¹:¶õJÕaœSXÆs;Ü tbßRüûÀ<‹x,¶YN$M­…š'Š’$V1u’ÉÄ"X?µ`x¯$ÇÚ&>²¯Ú™T§Û£öæÛ»Œb¹Mò'We®ÙN ƒñn ˜ìG‘,eËèûArlEq®µ¿/ãŸI‚³:íI—û·2øý] góæƒÐú—UèÆÐ ã&dåàõê4Ïz5gzƒ@ö”æ¼Þ¨[·4~¡Ú¦â#«-3÷ äýÿÃ…üWç4Þ¢ ¿‘ü«UiÉ7â+hð/!û*øI¿ëÑN|T¬©€h4£RLê©UÊz8œ|^ðîËùHY;I0¤FŒ¤6Ð 'Wq`ìÇZ|b`WŸÉ¯“ª1&ú->‚v¦ àfê7ßBŒõDF¸øO¶{6úñÀ!KQ ¡£çyä²E/B[É}D‘ÍýjÕkl4Ü®[òLùMèv|H›õ§ÄÁ'u݈ªÖp…hiÞ6BY¼q±.r„l焲ð²aE˜XÆí×c:n»×Nãë‹[àŽª€453_?L‰TÆæþnKIyô§_è_n°!Ax½¡]©…AôwPÍ<ïÅe.7)“)é)Ô¢¹3³ÐÌjÂgÖ°=dþå™aRÿSYnþ "s(š,9×Éóú Cÿ!7J—F¯öù} £÷¥.“ÅÕ&O§Õ.¡Ïó%î$ü+pÒoTÖèhº wä'tò€\êr^¶‰b~ X¤·çý"„Êv•¨ Ê(vuBáN;ãæùaðXÿÉÙ–D¦FÇ7K?éåõ M«F‹‚"¯nÆXrª¼èn¡\-NS€^Åaôòä pi7˜Á›tî'î2o_/ ¿ KL‚é¸1É›9¼Ç¦CŸ&S bGf'Б SDX,D½È*'ñ–ÐïÀmR†À•‘Wà•?“|)(eÛñÒVÙeÒX9C(¡2Ýø\Æ$¡§;Ì›Èpgþ,¿òwd‘° g׬"È—w"°sª9Ÿ;5!I}ÒhfmÍoíýÒõw5zÓ¬nyiäU5b3qY©„CrM‹bPV[#Qab»(ŽÜ55Õ“¦Ù†dšÛÙºuû´evé\põ¢~ˆÓˆ×߉$®x0ðȸÿ<  HájÍàNJm¦w©Z¿1Á ^z²’7;#gù©Þ>ÆüGÏÀ®ÀïŠP¹ÿWÚô+F÷{Ó0M±{θì|=PKŸ€º bÇî¬Ã{YŒðxѯc€:ëòhêz3Ð%ÛUß…Y½k}ÈMXçJš‘þÙ™"z8y endstream endobj 242 0 obj 12064 endobj 241 0 obj << /Length 243 0 R /Filter /FlateDecode >> stream I××ârÇͧÏâzáO‡.TR’·ì fl v‡±(OÚH6F9Ð7\ƒi8¨ä» endstream endobj 243 0 obj 48 endobj 244 0 obj << /Type /Font /Subtype /Type0 /BaseFont /EAAAAE+LiberationMono /Encoding /Identity-H /ToUnicode 245 0 R /DescendantFonts [246 0 R] >> endobj 246 0 obj << /Type /Font /BaseFont /EAAAAE+LiberationMono /CIDToGIDMap /Identity /Subtype /CIDFontType2 /CIDSystemInfo << /Registry (ôž•,C`ICÀ€Y3`xœÈe&úžoáb\fWQ) /Ordering (^ðP‰²ß" ^½›_'\b”sÁ ù]ÌzòiÙj4>) /Supplement 0 >> /FontDescriptor 239 0 R /DW 0 /W [ 0 [600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 ] ] >> endobj 245 0 obj << /Length 247 0 R /Filter /FlateDecode >> stream j94ž²ô •³É"¡ÜºØï&¬ž¡7À ”4Qe®lØJi¿•-ìb ½\¯OË»0ƒ†ja})Žñ™ï¡E&{ë§Ù±‡. Žï®uPÖ»qs¹äõ÷ûw¾öB«ß5P=İò×~/哽‚ˆ/ßOOTýùÿð<:%»á¸ðo«mð,VöÒ *;˜”¼?áuuddÍå?˜¬Íεêé9êâ<ó”çóá°æš9¾@Sâe‘RÊ€•MÊq€£VQ½Á‡Šh2¤§’þ›Ÿ{w3ý§øxk vÎ:JHØ8Wã«çç_|ÙÐT±ø ¥SúÃßY$Ä$o³ËÂb!üI#Ñ=éÜŸŠ ®8æ}%^¡s$mæž—“x”cŸÉCQ„c·ï@ CïfªðeÔuÉ<¿éÎ5g”æR ü›¼~×4 Zyó‡Î àΰðÇͨB”7ÝРŽ¤2 Eá©BóÈ ¬î¸P khª$é·ÉàŒ'6Ž¿§ £,aG “ÔWbX¼0¬S!Nã«X C¾4W?Ë›7/k—Õ¤üÓ'ÆCÉ ªŸM_tWE× ¬íÂIšÙ6ÚêɺEć3"£šÜ=¸Aµ¡ŸÔîšIµ>ýÏRǬPʃ"—ÁÐw0F2z¾£êá‰>lfèŽÝ¤ìFÞñɹ€,±+3©‹:D_Í]èöó¡_(”ÅÅȹÐ- ã͉T‰Ô endstream endobj 247 0 obj 560 endobj 17 0 obj << /Type /Pages /Count 19 /Kids [15 0 R 20 0 R 202 0 R 27 0 R 71 0 R 35 0 R 90 0 R 38 0 R 48 0 R 51 0 R 57 0 R 67 0 R 70 0 R 93 0 R 101 0 R 104 0 R 107 0 R 110 0 R 113 0 R ] >> endobj 248 0 obj << /Type /Catalog /Pages 17 0 R /Lang (v—3³²s\b¶ÛÑ42R1»{¸[H>¦\(É­ôßû‘óN¬·ï˜oʹñwuø) /Version /1.7 /Metadata 5 0 R /PageLabels 249 0 R >> endobj 16 0 obj << /Font << /F52 208 0 R /F43 217 0 R /F45 226 0 R /F44 235 0 R /F47 244 0 R >> /ProcSet [/PDF /ImageB /ImageC /Text] /XObject << /Im1 7 0 R /Im2 9 0 R /Im3 11 0 R /Im4 39 0 R /Im5 41 0 R /Im6 58 0 R /Im7 60 0 R >> /ColorSpace << /DefaultRGB 4 0 R >> >> endobj 250 0 obj << /Filter /Standard /V 5 /R 5 /Length 256 /P -1036 /O <42A2E7C17C7065A2DBF624B9BF68FDDA7F6F8EB8FBD492FAEE2D07CD874AF447626DB2D828CB85B64DC72E447D1E3FB8> /U /OE <618B3B96514FAF511E87A25BDC98978656C6C3AAD3D596AFEA4A73C0E077EBDE> /UE <594B6FF177E25FDE05255A998665EB96DF8BF6A66902ED0FAED57B4D42381ED7> /Perms /EncryptMetadata true /CF <>>> /StmF /StdCF /StrF /StdCF >> endobj 249 0 obj << /Nums [0 << /S /D >> 2 << /S /D /St 3 >> 3 << /S /D /St 4 >> 4 << /S /D /St 5 >> 5 << /S /D /St 6 >> 6 << /S /D /St 7 >> 7 << /S /D /St 8 >> 13 << /S /D /St 14 >>] >> endobj xref 0 251 0000000000 65535 f 0000000015 00000 n 0000000273 00000 n 0000002854 00000 n 0000002874 00000 n 0000002907 00000 n 0000003876 00000 n 0000003895 00000 n 0000195951 00000 n 0000195973 00000 n 0000242609 00000 n 0000242631 00000 n 0000286689 00000 n 0000286711 00000 n 0000287507 00000 n 0000287527 00000 n 0000452862 00000 n 0000452496 00000 n 0000287753 00000 n 0000290693 00000 n 0000290714 00000 n 0000290940 00000 n 0000291106 00000 n 0000291245 00000 n 0000291385 00000 n 0000294181 00000 n 0000294202 00000 n 0000294236 00000 n 0000294479 00000 n 0000361111 00000 n 0000294619 00000 n 0000361193 00000 n 0000294758 00000 n 0000296562 00000 n 0000296583 00000 n 0000296617 00000 n 0000296860 00000 n 0000299304 00000 n 0000299325 00000 n 0000299551 00000 n 0000300792 00000 n 0000300813 00000 n 0000302540 00000 n 0000302561 00000 n 0000302759 00000 n 0000302898 00000 n 0000304398 00000 n 0000304419 00000 n 0000304446 00000 n 0000304689 00000 n 0000308573 00000 n 0000308594 00000 n 0000308820 00000 n 0000309050 00000 n 0000309190 00000 n 0000313858 00000 n 0000313879 00000 n 0000313906 00000 n 0000314149 00000 n 0000334695 00000 n 0000334717 00000 n 0000354047 00000 n 0000354069 00000 n 0000354235 00000 n 0000354373 00000 n 0000357233 00000 n 0000357254 00000 n 0000357281 00000 n 0000357524 00000 n 0000360864 00000 n 0000360885 00000 n 0000366140 00000 n 0000361275 00000 n 0000361357 00000 n 0000361497 00000 n 0000361579 00000 n 0000361718 00000 n 0000361800 00000 n 0000361938 00000 n 0000362075 00000 n 0000362212 00000 n 0000362349 00000 n 0000366057 00000 n 0000366078 00000 n 0000366383 00000 n 0000366520 00000 n 0000366657 00000 n 0000366794 00000 n 0000369430 00000 n 0000369451 00000 n 0000369492 00000 n 0000369735 00000 n 0000371027 00000 n 0000371048 00000 n 0000371274 00000 n 0000371440 00000 n 0000371580 00000 n 0000371746 00000 n 0000371886 00000 n 0000374858 00000 n 0000374879 00000 n 0000374914 00000 n 0000375159 00000 n 0000376917 00000 n 0000376939 00000 n 0000377167 00000 n 0000378413 00000 n 0000378435 00000 n 0000378663 00000 n 0000380853 00000 n 0000380875 00000 n 0000381103 00000 n 0000382557 00000 n 0000382579 00000 n 0000382807 00000 n 0000382890 00000 n 0000383030 00000 n 0000383172 00000 n 0000383314 00000 n 0000383397 00000 n 0000383537 00000 n 0000383679 00000 n 0000383821 00000 n 0000383904 00000 n 0000384042 00000 n 0000384182 00000 n 0000384322 00000 n 0000384405 00000 n 0000384545 00000 n 0000384687 00000 n 0000384829 00000 n 0000384912 00000 n 0000385051 00000 n 0000385192 00000 n 0000385333 00000 n 0000385415 00000 n 0000385555 00000 n 0000385697 00000 n 0000385839 00000 n 0000385922 00000 n 0000386062 00000 n 0000386204 00000 n 0000386346 00000 n 0000386429 00000 n 0000386569 00000 n 0000386710 00000 n 0000386852 00000 n 0000386935 00000 n 0000387075 00000 n 0000387217 00000 n 0000387359 00000 n 0000387442 00000 n 0000387582 00000 n 0000387724 00000 n 0000387866 00000 n 0000387949 00000 n 0000388089 00000 n 0000388231 00000 n 0000388373 00000 n 0000388456 00000 n 0000388596 00000 n 0000388738 00000 n 0000388880 00000 n 0000388963 00000 n 0000389103 00000 n 0000389245 00000 n 0000389387 00000 n 0000389470 00000 n 0000389610 00000 n 0000389752 00000 n 0000389893 00000 n 0000390032 00000 n 0000390173 00000 n 0000390313 00000 n 0000390452 00000 n 0000390593 00000 n 0000390733 00000 n 0000390871 00000 n 0000391011 00000 n 0000391150 00000 n 0000391234 00000 n 0000391374 00000 n 0000391516 00000 n 0000391657 00000 n 0000391741 00000 n 0000391880 00000 n 0000392020 00000 n 0000392160 00000 n 0000392244 00000 n 0000392384 00000 n 0000392526 00000 n 0000392667 00000 n 0000392751 00000 n 0000392891 00000 n 0000393033 00000 n 0000393174 00000 n 0000393258 00000 n 0000393399 00000 n 0000393541 00000 n 0000393682 00000 n 0000395232 00000 n 0000395254 00000 n 0000395803 00000 n 0000396049 00000 n 0000396306 00000 n 0000404155 00000 n 0000404133 00000 n 0000404297 00000 n 0000404317 00000 n 0000404986 00000 n 0000404475 00000 n 0000405576 00000 n 0000405597 00000 n 0000405864 00000 n 0000418850 00000 n 0000418827 00000 n 0000418976 00000 n 0000418996 00000 n 0000419759 00000 n 0000419166 00000 n 0000420413 00000 n 0000420434 00000 n 0000420712 00000 n 0000425568 00000 n 0000425546 00000 n 0000425694 00000 n 0000425714 00000 n 0000426249 00000 n 0000425891 00000 n 0000426647 00000 n 0000426668 00000 n 0000426942 00000 n 0000437096 00000 n 0000437073 00000 n 0000437222 00000 n 0000437242 00000 n 0000437925 00000 n 0000437417 00000 n 0000438483 00000 n 0000438504 00000 n 0000438764 00000 n 0000450950 00000 n 0000450927 00000 n 0000451076 00000 n 0000451096 00000 n 0000451837 00000 n 0000451260 00000 n 0000452475 00000 n 0000452689 00000 n 0000453734 00000 n 0000453164 00000 n trailer << /Root 248 0 R /Info 1 0 R /ID [<6A93FBB8258FD1A2AD5D5F2C55BBC02E> <6A93FBB8258FD1A2AD5D5F2C55BBC02E>] /Encrypt 250 0 R /Size 251 >> startxref 453921 %%EOF sudo-rs-0.2.2/docs/man/su.1.md000064400000000000000000000020201046102023000140260ustar 00000000000000 # NAME `su` - run a shell or command as another user # SYNOPSIS `su` [options] [-] [<*user*> [<*argument*>...]] # OPTIONS `-c` *command*, `--command`=*command* : Pass a single command to the shell with `-c`. `-g` *group*, `--group`=*group* : Specify the primary group `-G` *group*, `--supp-group`=*group* : Specify a supplemental group `-h`, `--help` : Show a help message. `-`, `-l`, `--login` : Make the shell a login shell `-m`, `-p`, `--preserve-environment` : Do not reset environment variables `-P`, `--pty` : Create a new pseudo-terminal when running the shell. `-w` *list*, `--whitelist-environment`=*list* : Do not reset the environment variables specified by the *list*. Multiple variables can be separated by commas. `-s` *shell*, `--shell`=*shell* : Run *shell* if `/etc/shells` allows running as that shell instead of the default shell for the user. `-V`, `--version` : Show the program version. # SEE ALSO [sudo(8)](sudo.8.md) sudo-rs-0.2.2/docs/man/sudo.8.md000064400000000000000000000067111046102023000143730ustar 00000000000000 # NAME `sudo` - execute a command as another user # SYNOPSIS `sudo` [`-u` *user*] [`-g` *group*] [`-D` *directory*] [`-knS`] [`-i` | `-s`] [<*command*>] \ `sudo` `-h` | `-K` | `-k` | `-V` # DESCRIPTION `sudo` allows a user that is permitted to do so to execute a *command* as another user (for example *root*). Permissions are specified by a security policy specified in `/etc/sudoers` (see sudoers(5)). Sudo-rs is a safety oriented and memory safe re-implementation of the original sudo implementation by Todd Miller. When a command is run, a session record is stored for that specific session allowing users to run additional commands without having to re-authenticate. The timeout for session records can be specified in the policy. Some care is taken to pass signals received by sudo-rs to the child process, even if that process runs in its own pseudo terminal. # OPTIONS `-D` *directory*, `--chdir`=*directory* : Run the *command* in the specified *directory* instead of the current working directory. The security policy may return an error if the user does not have the permission to specify the working directory. `-g` *group*, `--group`=*group* : Use this *group* as the primary group instead of using the primary group specified in the password database for the target user. `-h`, `--help` : Show a help message. `-i`, `--login` : Run the shell specified by the target user's password database entry as a login shell. This means that login-specific resource files such as *.profile*, *.bash_profile* or *.login* will be read by the shell. If a *command* is specified, it is passed to the shell using the `-c` option. `-K`, `--remove-timestamp` : Removes every cached session record for the user, regardless of where the command is executed. The next time sudo-rs is run, authentication will take place if the policy requires it. No password is required to run this command. `-k`, `--reset-timestamp` : When used without a command, invalidates the user's session record for the current session. The next time sudo-rs is run, authentication will take place if the policy requires it. When used in conjunction with a *command* or an option that may require a password, this option will cause sudo-rs to ignore the user's session record. As a result, authentication will take place if the policy requires it. When used in conjunction with a *command* no invalidation of existing session records will take place. `-n`, `--non-interactive` : Avoid prompting the user for input of any kind. If any input is required for the *command* to run, sudo-rs will display an error message and exit. `-S`, `--stdin` : Read from standard input instead of using the terminal device. `-s`, `--shell` : Run the shell specified by the `SHELL` environment variable. If no shell was specified, the shell from the user's password database entry will be used instead. If a *command* is specified, it is passed to the shell using the `-c` option. `-u` *user*, `--user`=*user* : Run the *command* as another user than the default (**root**). `-V`, `--version` : Display the current version of sudo-rs. `-v`, `--validate` : Update the session record for the current session, authenticating the user if necessary. `--` : Indicates the end of the sudo-rs options and start of the *command*. # SEE ALSO [su(1)](su.1.md), sudoers(5), [visudo(8)](visudo.8.md) sudo-rs-0.2.2/docs/man/visudo.8.md000064400000000000000000000014171046102023000147300ustar 00000000000000 # NAME `visudo` - safely edit the sudoers file # SYNOPSIS `visudo` [`-chqsV`] [[`-f`] *sudoers*] # DESCRIPTION `visudo` edits the *sudoers* file in a safe manner, similar to vipw(8). # OPTIONS `-c`, `--check` : Only check if there are errors in the existing sudoers file. `-f` *sudoers*, `--file`=*sudoers* : Instead of editing the default `/etc/sudoers`, edit the file specified as *sudoers* instead. `-h`, `--help` : Show a help message. `-I`, `--no-includes` : Do not edit included files. `-q`, `--quiet` : Less verbose syntax error messages. `-s`, `--strict` : Strict syntax checking. `-V`, `--version` : Display version information and exit. # SEE ALSO [sudo(8)](sudo.8.md), sudoers(5) sudo-rs-0.2.2/docs/sudo-cve.md000064400000000000000000000173061046102023000142270ustar 00000000000000# Past sudo CVEs This listing contains security issues originally found in sudo but which could also be relevant for sudo-rs. ## Possibly relevant CVEs / advisories These CVEs/advisories are possibly relevant to sudo-rs: | CVE | Tests | Sudo Advisory / Attack notes | | ---------------------- | ----- | --------------------------------------------------------------------------- | | CVE-1999-0958 [^1] | | Relative path attack (.. attack) | | CVE-1999-1496 [^2] | | Information leakage on which commands exist | | - [^3] | | https://www.sudo.ws/security/advisories/heap_corruption/ | | CVE-2004-1051 [^4] | | https://www.sudo.ws/security/advisories/bash_functions/ | | CVE-2005-1119 [^5] | | Corrupt arbitrary files via a symlink attack | | CVE-2005-1993 [^6] | | https://www.sudo.ws/security/advisories/path_race/ | | CVE-2005-4890 [^7] | | TTY hijacking when a privileged user uses sudo to run unprivileged commands | | - [^9] | | https://www.sudo.ws/security/advisories/cmnd_alias_negation/ | | CVE-2010-1646 [^10] | | https://www.sudo.ws/security/advisories/secure_path/ | | CVE-2010-2956 [^11] | | https://www.sudo.ws/security/advisories/runas_group/ | | CVE-2011-0010 [^12] | | https://www.sudo.ws/security/advisories/runas_group_pw/ | | CVE-2012-0809 [^13] | | https://www.sudo.ws/security/advisories/sudo_debug/ | | CVE-2013-1775 [^14] | | https://www.sudo.ws/security/advisories/epoch_ticket/ | | CVE-2013-1776 [^15] | | https://www.sudo.ws/security/advisories/tty_tickets/ | | CVE-2013-2776 [^15] | | https://www.sudo.ws/security/advisories/tty_tickets/ | | CVE-2013-2777 [^15] | | https://www.sudo.ws/security/advisories/tty_tickets/ | | CVE-2014-9680 [^16] | | https://www.sudo.ws/security/advisories/tz/ | | CVE-2017-1000367 [^17] | | https://www.sudo.ws/security/advisories/linux_tty/ | | CVE-2017-1000368 [^17] | | https://www.sudo.ws/security/advisories/linux_tty/ | | CVE-2023-28486 [^19] | | Syslog messages do not escape control characters | [^1]: All our path checks should only ever be done with absolute paths [^2]: We try to take care to only expose relevant information to the user [^3]: Our usage of Rust should mostly prevent heap corruption bugs from occurring [^4]: env_reset is always enabled in sudo-rs, additionally we apply filtering to several variables to prevent any additional attack paths [^5]: - [^6]: Sudo-rs uses the suggested realpath function, as it is considered available enough for our target systems [^7]: To prevent attacks, a PTY must be used when running commands within a TTY, which is enabled by default in sudo-rs [^9]: - [^10]: - [^11]: - [^12]: - [^13]: - [^14]: - [^15]: - [^16]: - [^17]: - [^19]: - ## Non-applicable CVEs These CVEs are almost entirely not applicable in the current sudo-rs codebase, mainly because the feature they relate to is not implemented. Sometimes this is done purposefully, because the feature has security implications. Sometimes the feature will be implemented at a later time, these CVEs might become relevant at that time. | CVE | Reason | | -------------- | ----------------------------------------------------------------------------------------------------------- | | CVE-2002-0043 | mail functionality is not implemented, https://www.sudo.ws/security/advisories/postfix/ | | CVE-2002-0184 | setting a custom prompt via `-p` is not implemented, https://www.sudo.ws/security/advisories/prompt/ | | CVE-2004-1689 | `sudoedit`/`sudo -e` is not implemented, https://www.sudo.ws/security/advisories/sudoedit/ | | CVE-2005-2959 | env_reset is always enabled / blacklist is not supported, https://www.sudo.ws/security/advisories/bash_env/ | | CVE-2005-4158 | env_reset is always enabled / blacklist is not supported, https://www.sudo.ws/security/advisories/perl_env/ | | CVE-2006-0151 | env_reset is always enabled / blacklist is not supported | | CVE-2007-3149 | Kerberos functionality is not implemented, https://www.sudo.ws/security/advisories/kerberos5/ | | CVE-2009-0034 | The group matching logic does not have this bug, https://www.sudo.ws/security/advisories/group_vector/ | | CVE-2010-0426 | `sudoedit`/`sudo -e` is not implemented, https://www.sudo.ws/security/advisories/sudoedit_escalate/ | | CVE-2010-0427 | runas_default is not implemented | | CVE-2010-1163 | `sudoedit`/`sudo -e` is not implemented, https://www.sudo.ws/security/advisories/sudoedit_escalate2/ | | CVE-2012-2337 | No host-based rule matching is currently implemented, https://www.sudo.ws/security/advisories/netmask/ | | CVE-2012-3440 | Related to Red Hat specific script and not sudo directly | | CVE-2014-0106 | Disabling env_reset is not supported, https://www.sudo.ws/security/advisories/env_add/ | | CVE-2015-5602 | `sudoedit`/`sudo -e` is not implemented | | CVE-2015-8239 | The sha2 digest feature is not implemented | | CVE-2016-7032 | The noexec functionality is not implemented, https://www.sudo.ws/security/advisories/noexec_bypass/ | | CVE-2016-7076 | The noexec functionality is not implemented, https://www.sudo.ws/security/advisories/noexec_wordexp/ | | CVE-2019-14287 | This bug is not present, https://www.sudo.ws/security/advisories/minus_1_uid/ | | CVE-2019-18634 | The pwfeedback functionality is not implemented, https://www.sudo.ws/security/advisories/pwfeedback/ | | CVE-2021-3156 | `sudoedit`/`sudo -e` is not implemented, https://www.sudo.ws/security/advisories/unescape_overflow/ | | CVE-2021-23239 | `sudoedit`/`sudo -e` is not implemented | | CVE-2021-23240 | `sudoedit`/`sudo -e` is not implemented, https://www.sudo.ws/security/advisories/sudoedit_selinux/ | | CVE-2022-43995 | crypt/password backend is not implemented, only PAM | | CVE-2023-22809 | `sudoedit`/`sudo -e` is not implemented, https://www.sudo.ws/security/advisories/sudoedit_any/ | | CVE-2023-27320 | The chroot functionality is not implemented, https://www.sudo.ws/security/advisories/double_free/ | | CVE-2023-28487 | Sudoreplay is not implemented | ## Disputed CVEs While these CVEs are related to sudo, they are disputed as security issues. Either the behavior described in the CVE is intended behavior, or the issue cannot be replicated. | CVE | Notes | | -------------- | ----- | | CVE-2005-1831 | | | CVE-2019-18684 | | | CVE-2019-19234 | | | CVE-2019-19232 | | sudo-rs-0.2.2/make-lcov-info.bash000075500000000000000000000013011046102023000146650ustar 00000000000000#!/bin/bash set -euo pipefail rustup component add llvm-tools llvm_profdata=$(find "$(rustc --print sysroot)" -name llvm-profdata) profdata="$SUDO_TEST_PROFRAW_DIR"/sudo-rs.profdata $llvm_profdata merge \ -sparse \ "$SUDO_TEST_PROFRAW_DIR"/**/*.profraw \ -o "$profdata" binary="$SUDO_TEST_PROFRAW_DIR"/sudo-rs dockerid=$(docker create sudo-test-rs) docker cp "$dockerid":/usr/bin/sudo "$binary" docker rm "$dockerid" llvm_cov="$(dirname "$llvm_profdata")"/llvm-cov $llvm_cov export \ -format=lcov \ --ignore-filename-regex='/usr/local/cargo/registry' \ --ignore-filename-regex='/rustc' \ --instr-profile="$profdata" \ --object "$binary" \ -path-equivalence=/usr/src/sudo,"$(pwd)" >lcov.info sudo-rs-0.2.2/proofs/sudoers.mlw000064400000000000000000000050201046102023000147330ustar 00000000000000(* Why3 specification file for selected code in the sudoers crate. All proof goals generated by Why3 1.5.1 can be discharged using CVC4 1.8 *) module Sudoers use array.Array use option.Option use ref.Ref use int.Int (* loose models for the types in sudoers::Ast *) type metavar 'a = All | Only 'a type qualified 'a = Yes 'a | No 'a type spec 'tag 'a = { inner: qualified (metavar 'a); info: 'tag } predicate contains (pred: 'a -> bool) (a: array 'a) = exists i. 0 <= i < length a /\ pred a[i] function who (item: spec 'tag 'a): metavar 'a = match item.inner with | Yes x -> x | No x -> x end function condition (item: spec 'tag 'a): option 'tag = match item with | { inner = Yes _; info = tag } -> Some tag | _ -> None end function matched_by (pred: 'a -> bool) (item: spec 'tag 'a): bool = match who item with | All -> true | Only x -> pred x end let function bool_then (b: bool) (x: 'a): option 'a = if b then Some x else None predicate final_match (pred: 'a -> bool) (a: array 'a) (f: 'a -> 'b) (x: 'b) = exists i. 0 <= i < length a /\ pred a[i] /\ f a[i] = x /\ forall k. i < k < length a -> not pred a[k] (* Why3 model of the sudoers::find_item function *) let find_item (items: array (spec 'tag 'a)) (pred: 'a -> bool): option 'tag returns { | Some tag -> final_match (matched_by pred) items condition (Some tag) | None -> not contains (matched_by pred) items \/ final_match (matched_by pred) items condition None } = let result = ref None in for i = 0 to items.length - 1 do invariant { forall tag. !result = Some tag <-> exists j. 0 <= j < i /\ matched_by pred items[j] /\ Some tag = condition items[j] /\ forall k. j < k < i -> not matched_by pred items[k] } let (judgement, who) = match items[i].inner with | No x -> (false, x) | Yes x -> (true, x) end in let info = items[i].info in match who with | All -> result := judgement.bool_then(info) | Only id -> if pred id then result := judgement.bool_then(info); end; done; (* perform a "virtual loop" to strength the case !result = None; this could also be solved by adding a ghost variable above *) ghost if is_none !result && contains (matched_by pred) items then for i = items.length - 1 downto 0 do invariant { forall k. i < k < items.length -> not matched_by pred items[k] } invariant { exists k. 0 <= k <= i /\ matched_by pred items[k] } if matched_by pred items[i] then break done; !result; end sudo-rs-0.2.2/src/common/bin_serde.rs000064400000000000000000000075511046102023000156100ustar 00000000000000//! Binary serialization, and an implementation over Unix pipes. use sealed::DeSerializeBytes; use std::{ io::{self, Read, Write}, marker::PhantomData, os::{fd::AsRawFd, unix::net::UnixStream}, }; mod sealed { pub trait DeSerializeBytes { fn zero_init() -> Self; fn as_mut_ref(&mut self) -> &mut [u8]; } impl DeSerializeBytes for [u8; N] { fn zero_init() -> [u8; N] { [0; N] } fn as_mut_ref(&mut self) -> &mut [u8] { self.as_mut_slice() } } } /// Serialization/deserialization trait using a byte array as storage. pub trait DeSerialize { /// Usually `[u8; std::mem::size_of::()]`. type Bytes: sealed::DeSerializeBytes; fn serialize(&self) -> Self::Bytes; fn deserialize(bytes: Self::Bytes) -> Self; } /// A binary pipe that can send and recieve typed messages. /// /// By default, if only one generic is included, /// the types of the [BinPipe::write()] and [BinPipe::read()] messages /// are the same. pub struct BinPipe { sock: UnixStream, _read_marker: PhantomData, _write_marker: PhantomData, } impl BinPipe { /// A pipe abstracting over a [UnixStream] with easier /// binary serialization, to help with the buffer sizes and ser/de steps. /// Uses [UnixStream::pair()]. pub fn pair() -> io::Result<(BinPipe, BinPipe)> { let (first, second) = UnixStream::pair()?; Ok(( BinPipe { sock: first, _read_marker: PhantomData::, _write_marker: PhantomData::, }, // R and W are inverted here since the type of what's written in one // pipe is read in the other, and vice versa. BinPipe { sock: second, _read_marker: PhantomData::, _write_marker: PhantomData::, }, )) } /// Read a `R` from the pipe. pub fn read(&mut self) -> io::Result { let mut bytes = R::Bytes::zero_init(); self.sock.read_exact(bytes.as_mut_ref())?; Ok(R::deserialize(bytes)) } /// Write a `W` to the pipe. pub fn write(&mut self, bytes: &W) -> io::Result<()> { self.sock.write_all(bytes.serialize().as_mut_ref())?; Ok(()) } /// Calls [std::net::TcpStream::set_nonblocking] on the underlying socket. #[cfg(debug_assertions)] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.sock.set_nonblocking(nonblocking) } } impl AsRawFd for BinPipe { fn as_raw_fd(&self) -> std::os::fd::RawFd { self.sock.as_raw_fd() } } impl DeSerialize for i32 { type Bytes = [u8; std::mem::size_of::()]; fn serialize(&self) -> Self::Bytes { self.to_ne_bytes() } fn deserialize(bytes: Self::Bytes) -> Self { Self::from_ne_bytes(bytes) } } #[cfg(test)] mod tests { use super::*; #[test] pub fn single_type() { let (mut tx, mut rx) = BinPipe::pair().unwrap(); tx.write(&42i32).unwrap(); assert_eq!(rx.read().unwrap(), 42); rx.write(&23i32).unwrap(); assert_eq!(tx.read().unwrap(), 23); } #[test] pub fn different_types() { impl DeSerialize for u8 { type Bytes = [u8; std::mem::size_of::()]; fn serialize(&self) -> [u8; 1] { self.to_ne_bytes() } fn deserialize(bytes: [u8; 1]) -> Self { Self::from_ne_bytes(bytes) } } let (mut tx, mut rx) = BinPipe::pair().unwrap(); tx.write(&42i32).unwrap(); assert_eq!(rx.read().unwrap(), 42); rx.write(&23u8).unwrap(); assert_eq!(tx.read().unwrap(), 23); } } sudo-rs-0.2.2/src/common/command.rs000064400000000000000000000135461046102023000152750ustar 00000000000000use std::{ fmt::Display, path::{Path, PathBuf}, }; use crate::system::escape_os_str_lossy; use super::resolve::{canonicalize, resolve_path}; #[derive(Debug, Default)] #[cfg_attr(test, derive(PartialEq))] pub struct CommandAndArguments { pub(crate) command: PathBuf, pub(crate) arguments: Vec, pub(crate) resolved: bool, pub(crate) arg0: Option, } impl Display for CommandAndArguments { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let cmd = escape_os_str_lossy(self.command.as_os_str()); let args = self .arguments .iter() .map(|a| a.escape_default().collect::()) .collect::>() .join(" "); write!(f, "{} {}", cmd, args) } } // when -i and -s are used, the arguments given to sudo are escaped "except for alphanumerics, underscores, hyphens, and dollar signs." fn escaped(arguments: Vec) -> String { arguments .into_iter() .map(|arg| { arg.chars() .map(|c| match c { '_' | '-' | '$' => c.to_string(), c if c.is_alphanumeric() => c.to_string(), _ => ['\\', c].iter().collect(), }) .collect() }) .collect::>() .join(" ") } //checks whether the Path is actually describing a qualified path (i.e. contains "/") //or just specifying the name of a file (in which case we are going to resolve it via PATH) fn is_qualified(path: impl AsRef) -> bool { path.as_ref().parent() != Some(Path::new("")) } impl CommandAndArguments { pub fn build_from_args(shell: Option, mut arguments: Vec, path: &str) -> Self { let mut resolved = true; let mut command; let mut arg0 = None; if let Some(chosen_shell) = shell { command = chosen_shell; if !arguments.is_empty() { arguments = vec!["-c".to_string(), escaped(arguments)] } } else { command = arguments.first().map(|s| s.into()).unwrap_or_default(); arguments.remove(0); // remember the original binary name before resolving symlinks; this is not // to be used except for setting the `arg0` arg0 = Some(command.clone()); // resolve the command, remembering errors (but not propagating them) if !is_qualified(&command) { match resolve_path(&command, path) { Some(qualified_path) => command = qualified_path, None => resolved = false, } } // resolve symlinks, even if the command was obtained through a PATH or SHELL // once again, failure to canonicalize should not stop the pipeline match canonicalize(&command) { Ok(canon_path) => command = canon_path, Err(_) => resolved = false, } } CommandAndArguments { command, arguments, resolved, arg0, } } } #[cfg(test)] mod test { use super::{escaped, CommandAndArguments}; #[test] fn test_escaped() { let test = |src: &[&str], target: &str| { assert_eq!( &escaped(src.iter().map(|s| s.to_string()).collect()), target ); }; test(&["a", "b", "c"], "a b c"); test(&["a", "b c"], "a b\\ c"); test(&["a", "b-c"], "a b-c"); test(&["a", "b#c"], "a b\\#c"); test(&["1 2 3"], "1\\ 2\\ 3"); test(&["! @ $"], "\\!\\ \\@\\ $"); } #[test] fn test_build_command_and_args() { assert_eq!( CommandAndArguments::build_from_args( None, vec!["/usr/bin/fmt".into(), "hello".into()], "/bin" ), CommandAndArguments { command: "/usr/bin/fmt".into(), arguments: vec!["hello".into()], resolved: true, arg0: Some("/usr/bin/fmt".into()), } ); assert_eq!( CommandAndArguments::build_from_args( None, vec!["fmt".into(), "hello".into()], "/tmp:/usr/bin:/bin" ), CommandAndArguments { command: "/usr/bin/fmt".into(), arguments: vec!["hello".into()], resolved: true, arg0: Some("fmt".into()), } ); assert_eq!( CommandAndArguments::build_from_args( None, vec!["thisdoesnotexist".into(), "hello".into()], "" ), CommandAndArguments { command: "thisdoesnotexist".into(), arguments: vec!["hello".into()], resolved: false, arg0: Some("thisdoesnotexist".into()), } ); assert_eq!( CommandAndArguments::build_from_args( Some("shell".into()), vec!["ls".into(), "hello".into()], "/bin" ), CommandAndArguments { command: "shell".into(), arguments: vec!["-c".into(), "ls hello".into()], resolved: true, arg0: None, } ); } #[test] fn qualified_paths() { use super::is_qualified; assert!(is_qualified("foo/bar")); assert!(is_qualified("a/b/bar")); assert!(is_qualified("a/b//bar")); assert!(is_qualified("/bar")); assert!(is_qualified("/bar/")); assert!(is_qualified("/bar/foo/")); assert!(is_qualified("/")); assert!(is_qualified("")); // don't try to resolve "" assert!(!is_qualified("bar")); } } sudo-rs-0.2.2/src/common/context.rs000064400000000000000000000071651046102023000153430ustar 00000000000000use crate::common::{HARDENED_ENUM_VALUE_0, HARDENED_ENUM_VALUE_1, HARDENED_ENUM_VALUE_2}; use crate::system::{Group, Hostname, Process, User}; use super::resolve::CurrentUser; use super::{ command::CommandAndArguments, resolve::{resolve_launch_and_shell, resolve_target_user_and_group}, Error, SudoPath, SudoString, }; #[derive(Clone, Copy)] pub enum ContextAction { List, Run, Validate, } // this is a bit of a hack to keep the existing `Context` API working pub struct OptionsForContext { pub chdir: Option, pub group: Option, pub login: bool, pub non_interactive: bool, pub positional_args: Vec, pub reset_timestamp: bool, pub shell: bool, pub stdin: bool, pub user: Option, pub action: ContextAction, } #[derive(Debug)] pub struct Context { // cli options pub launch: LaunchType, pub chdir: Option, pub command: CommandAndArguments, pub target_user: User, pub target_group: Group, pub stdin: bool, pub non_interactive: bool, pub use_session_records: bool, // system pub hostname: Hostname, pub current_user: CurrentUser, pub process: Process, // policy pub use_pty: bool, } #[derive(Debug, PartialEq, Eq)] #[repr(u32)] pub enum LaunchType { Direct = HARDENED_ENUM_VALUE_0, Shell = HARDENED_ENUM_VALUE_1, Login = HARDENED_ENUM_VALUE_2, } impl Context { pub fn build_from_options( sudo_options: OptionsForContext, path: String, ) -> Result { let hostname = Hostname::resolve(); let current_user = CurrentUser::resolve()?; let (target_user, target_group) = resolve_target_user_and_group(&sudo_options.user, &sudo_options.group, ¤t_user)?; let (launch, shell) = resolve_launch_and_shell(&sudo_options, ¤t_user, &target_user); let command = match sudo_options.action { ContextAction::Validate | ContextAction::List if sudo_options.positional_args.is_empty() => { // FIXME `Default` is being used as `Option::None` Default::default() } _ => CommandAndArguments::build_from_args(shell, sudo_options.positional_args, &path), }; Ok(Context { hostname, command, current_user, target_user, target_group, use_session_records: !sudo_options.reset_timestamp, launch, chdir: sudo_options.chdir, stdin: sudo_options.stdin, non_interactive: sudo_options.non_interactive, process: Process::new(), use_pty: true, }) } } #[cfg(test)] mod tests { use crate::{sudo::SudoAction, system::Hostname}; use std::collections::HashMap; use super::Context; #[test] fn test_build_context() { let options = SudoAction::try_parse_from(["sudo", "echo", "hello"]) .unwrap() .try_into_run() .ok() .unwrap(); let path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; let context = Context::build_from_options(options.into(), path.to_string()).unwrap(); let mut target_environment = HashMap::new(); target_environment.insert("SUDO_USER".to_string(), context.current_user.name.clone()); assert_eq!(context.command.command.to_str().unwrap(), "/usr/bin/echo"); assert_eq!(context.command.arguments, ["hello"]); assert_eq!(context.hostname, Hostname::resolve()); assert_eq!(context.target_user.uid, 0); } } sudo-rs-0.2.2/src/common/error.rs000064400000000000000000000071461046102023000150070ustar 00000000000000use crate::{pam::PamError, system::Hostname}; use std::{borrow::Cow, fmt, path::PathBuf}; use super::{SudoPath, SudoString}; #[derive(Debug)] pub enum Error { Silent, NotAllowed { username: SudoString, command: Cow<'static, str>, hostname: Hostname, other_user: Option, }, SelfCheck, CommandNotFound(PathBuf), InvalidCommand(PathBuf), ChDirNotAllowed { chdir: SudoPath, command: PathBuf, }, UserNotFound(String), GroupNotFound(String), Authentication(String), Configuration(String), Options(String), Pam(PamError), Io(Option, std::io::Error), MaxAuthAttempts(usize), PathValidation(PathBuf), StringValidation(String), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::Silent => Ok(()), Error::NotAllowed { username, command, hostname, other_user, } => { if let Some(other_user) = other_user { write!( f, "Sorry, user {username} is not allowed to execute '{command}' as {other_user} on {hostname}.", ) } else { write!( f, "Sorry, user {username} may not run {command} on {hostname}.", ) } } Error::SelfCheck => { f.write_str("sudo must be owned by uid 0 and have the setuid bit set") } Error::CommandNotFound(p) => write!(f, "'{}': command not found", p.display()), Error::InvalidCommand(p) => write!(f, "'{}': invalid command", p.display()), Error::UserNotFound(u) => write!(f, "user '{u}' not found"), Error::GroupNotFound(g) => write!(f, "group '{g}' not found"), Error::Authentication(e) => write!(f, "authentication failed: {e}"), Error::Configuration(e) => write!(f, "invalid configuration: {e}"), Error::Options(e) => write!(f, "{e}"), Error::Pam(e) => write!(f, "PAM error: {e}"), Error::Io(location, e) => { if let Some(path) = location { write!(f, "cannot execute '{}': {e}", path.display()) } else { write!(f, "IO error: {e}") } } Error::MaxAuthAttempts(num) => { write!(f, "Maximum {num} incorrect authentication attempts") } Error::ChDirNotAllowed { chdir, command } => write!( f, "you are not allowed to use '--chdir {}' with '{}'", chdir.display(), command.display() ), Error::StringValidation(string) => { write!(f, "invalid string: {string:?}") } Error::PathValidation(path) => { write!(f, "invalid path: {path:?}") } } } } impl From for Error { fn from(err: PamError) -> Self { Error::Pam(err) } } impl From for Error { fn from(err: std::io::Error) -> Self { Error::Io(None, err) } } impl Error { pub fn auth(message: &str) -> Self { Self::Authentication(message.to_string()) } /// Returns `true` if the error is [`Silent`]. /// /// [`Silent`]: Error::Silent #[must_use] pub fn is_silent(&self) -> bool { matches!(self, Self::Silent) } } sudo-rs-0.2.2/src/common/mod.rs000064400000000000000000000021361046102023000144270ustar 00000000000000#![forbid(unsafe_code)] use std::{collections::HashMap, ffi::OsString}; pub use command::CommandAndArguments; pub use context::Context; pub use error::Error; pub use path::SudoPath; pub use string::SudoString; pub mod bin_serde; pub mod command; pub mod context; pub mod error; mod path; pub mod resolve; mod string; pub type Environment = HashMap; // Hardened enum values used for critical enums to mitigate attacks like Rowhammer. // See for example https://arxiv.org/pdf/2309.02545.pdf // The values are copied from https://github.com/sudo-project/sudo/commit/7873f8334c8d31031f8cfa83bd97ac6029309e4f#diff-b8ac7ab4c3c4a75aed0bb5f7c5fd38b9ea6c81b7557f775e46c6f8aa115e02cd pub const HARDENED_ENUM_VALUE_0: u32 = 0x52a2925; // 0101001010100010100100100101 pub const HARDENED_ENUM_VALUE_1: u32 = 0xad5d6da; // 1010110101011101011011011010 pub const HARDENED_ENUM_VALUE_2: u32 = 0x69d61fc8; // 1101001110101100001111111001000 pub const HARDENED_ENUM_VALUE_3: u32 = 0x1629e037; // 0010110001010011110000000110111 pub const HARDENED_ENUM_VALUE_4: u32 = 0x1fc8d3ac; // 11111110010001101001110101100 sudo-rs-0.2.2/src/common/path.rs000064400000000000000000000052711046102023000146070ustar 00000000000000use std::{ ffi::OsString, ops, os::unix::prelude::OsStrExt, path::{Path, PathBuf}, str, }; use super::{Error, SudoString}; /// A `PathBuf` guaranteed to not contain null bytes and be UTF-8 encoded #[derive(Clone, Debug, PartialEq)] #[cfg_attr(test, derive(Eq))] pub struct SudoPath { inner: String, } impl SudoPath { pub fn new(path: PathBuf) -> Result { let bytes = path.as_os_str().as_bytes(); if bytes.contains(&0) { return Err(Error::PathValidation(path)); } // check this through a reference so we can return `path` in the error case if str::from_utf8(bytes).is_err() { return Err(Error::PathValidation(path)); } Ok(Self { // NOTE(unwrap): UTF-8 encoding is checked above inner: path.into_os_string().into_string().unwrap(), }) } pub fn from_cli_string(cli_string: impl Into) -> Self { Self::new(cli_string.into().into()) .expect("strings that come in from CLI should not have interior null bytes") } /// Resolve the use of a '~' that occurs in this `SudoPathBuf`; based on the sudoers context pub fn expand_tilde_in_path(&self, default_username: &SudoString) -> Result { if let Some(prefix) = self.inner.strip_prefix('~') { let (username, relpath) = prefix.split_once('/').unwrap_or((prefix, "")); let username = if username.is_empty() { default_username.clone() } else { SudoString::new(username.to_string()).unwrap() }; let home_dir = crate::system::User::from_name(username.as_cstr()) .ok() .flatten() .ok_or(Error::UserNotFound(username.to_string()))? .home; let path = home_dir.join(relpath); Self::new(path) } else { Ok(self.clone()) } } } impl From for PathBuf { fn from(value: SudoPath) -> Self { value.inner.into() } } impl AsRef for SudoPath { fn as_ref(&self) -> &Path { self.inner.as_ref() } } impl ops::Deref for SudoPath { type Target = Path; fn deref(&self) -> &Self::Target { self.as_ref() } } impl TryFrom for SudoPath { type Error = Error; fn try_from(value: String) -> Result { Self::new(value.into()) } } impl From for OsString { fn from(value: SudoPath) -> Self { value.inner.into() } } #[cfg(test)] impl From<&'_ str> for SudoPath { fn from(value: &'_ str) -> Self { Self::new(value.into()).unwrap() } } sudo-rs-0.2.2/src/common/resolve.rs000064400000000000000000000250471046102023000153350ustar 00000000000000use crate::system::{Group, User}; use core::fmt; use std::{ env, ffi::CStr, fs, io, ops, os::unix::prelude::MetadataExt, path::{Path, PathBuf}, str::FromStr, }; use super::SudoString; use super::{ context::{LaunchType, OptionsForContext}, Error, }; #[derive(PartialEq, Debug)] enum NameOrId<'a, T: FromStr> { Name(&'a SudoString), Id(T), } impl<'a, T: FromStr> NameOrId<'a, T> { pub fn parse(input: &'a SudoString) -> Option { if input.is_empty() { None } else if let Some(stripped) = input.strip_prefix('#') { stripped.parse::().ok().map(|id| Self::Id(id)) } else { Some(Self::Name(input)) } } } #[derive(Clone)] pub struct CurrentUser { inner: User, } impl From for User { fn from(value: CurrentUser) -> Self { value.inner } } impl fmt::Debug for CurrentUser { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("CurrentUser").field(&self.inner).finish() } } impl ops::Deref for CurrentUser { type Target = User; fn deref(&self) -> &Self::Target { &self.inner } } impl CurrentUser { #[cfg(test)] pub fn fake(user: User) -> Self { Self { inner: user } } pub fn resolve() -> Result { Ok(Self { inner: User::real()?.ok_or(Error::UserNotFound("current user".to_string()))?, }) } } type Shell = Option; pub(super) fn resolve_launch_and_shell( sudo_options: &OptionsForContext, current_user: &User, target_user: &User, ) -> (LaunchType, Shell) { if sudo_options.login { (LaunchType::Login, Some(target_user.shell.clone())) } else if sudo_options.shell { let shell = env::var("SHELL") .map(|s| s.into()) .unwrap_or_else(|_| current_user.shell.clone()); (LaunchType::Shell, Some(shell)) } else { (LaunchType::Direct, None) } } pub(crate) fn resolve_target_user_and_group( target_user_name_or_id: &Option, target_group_name_or_id: &Option, current_user: &CurrentUser, ) -> Result<(User, Group), Error> { // resolve user name or # to a user let mut target_user = resolve_from_name_or_id(target_user_name_or_id, User::from_name, User::from_uid)?; // resolve group name or # to a group let mut target_group = resolve_from_name_or_id(target_group_name_or_id, Group::from_name, Group::from_gid)?; match (&target_user_name_or_id, &target_group_name_or_id) { // when -g is specified, but -u is not specified default -u to the current user (None, Some(_)) => { target_user = Some(current_user.clone().into()); } // when -u is specified but -g is not specified, default -g to the primary group of the specified user (Some(_), None) => { if let Some(user) = &target_user { target_group = Group::from_gid(user.gid)?; } } // when no -u or -g is specified, default to root:root (None, None) => { target_user = User::from_name(cstr!("root"))?; target_group = Group::from_name(cstr!("root"))?; } _ => {} } match (target_user, target_group) { (Some(user), Some(group)) => { // resolve success Ok((user, group)) } // group name or id not found (Some(_), None) => Err(Error::GroupNotFound( target_group_name_or_id .as_deref() .unwrap_or_default() .to_string(), )), // user (and maybe group) name or id not found _ => Err(Error::UserNotFound( target_user_name_or_id .as_deref() .unwrap_or_default() .to_string(), )), } } fn resolve_from_name_or_id( input: &Option, from_name: impl FnOnce(&CStr) -> Result, E>, from_id: impl FnOnce(I) -> Result, E>, ) -> Result, E> where I: FromStr, { match input.as_ref().and_then(NameOrId::parse) { Some(NameOrId::Name(name)) => from_name(name.as_cstr()), Some(NameOrId::Id(id)) => from_id(id), None => Ok(None), } } /// Check whether a path points to a regular file and any executable flag is set pub(crate) fn is_valid_executable(path: &PathBuf) -> bool { if path.is_file() { match fs::metadata(path) { Ok(meta) => meta.mode() & 0o111 != 0, _ => false, } } else { false } } /// Resolve a executable name based in the PATH environment variable /// When resolving a path, this code checks whether the target file is /// a regular file and has any executable bits set. It does not specifically /// check for user, group, or others' executable bit. pub(crate) fn resolve_path(command: &Path, path: &str) -> Option { // To prevent command spoofing, sudo checks "." and "" (both denoting current directory) // last when searching for a command in the user's PATH (if one or both are in the PATH). // Depending on the security policy, the user's PATH environment variable may be modified, // replaced, or passed unchanged to the program that sudo executes. let mut resolve_current_path = false; path.split(':') // register whether to look in the current directory, but first check the other PATH segments .filter(|&path| { if path.is_empty() || path == "." { resolve_current_path = true; false } else { true } }) // construct a possible executable absolute path candidate .map(|path| PathBuf::from(path).join(command)) // check whether the candidate is a regular file and any executable flag is set .find(is_valid_executable) // if no no executable could be resolved try the current directory // if it was present in the PATH .or_else(|| { if resolve_current_path { env::current_dir() .ok() .map(|dir| dir.join(command)) .and_then(|path| { if is_valid_executable(&path) { Some(path) } else { None } }) } else { None } }) } #[cfg(test)] mod tests { use std::path::PathBuf; use crate::common::resolve::CurrentUser; use super::{is_valid_executable, resolve_path, resolve_target_user_and_group, NameOrId}; #[test] fn test_resolve_path() { // Assume any linux distro has utilities in this PATH let path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; assert!(is_valid_executable( &resolve_path(&PathBuf::from("yes"), path).unwrap() )); assert!(is_valid_executable( &resolve_path(&PathBuf::from("whoami"), path).unwrap() )); assert!(is_valid_executable( &resolve_path(&PathBuf::from("env"), path).unwrap() )); assert_eq!( resolve_path(&PathBuf::from("thisisnotonyourfs"), path), None ); assert_eq!(resolve_path(&PathBuf::from("thisisnotonyourfs"), "."), None); } #[test] fn test_name_or_id() { assert_eq!(NameOrId::::parse(&"".into()), None); assert_eq!( NameOrId::::parse(&"mies".into()), Some(NameOrId::Name(&"mies".into())) ); assert_eq!( NameOrId::::parse(&"1337".into()), Some(NameOrId::Name(&"1337".into())) ); assert_eq!( NameOrId::::parse(&"#1337".into()), Some(NameOrId::Id(1337)) ); assert_eq!(NameOrId::::parse(&"#-1".into()), None); } #[test] fn test_resolve_target_user_and_group() { let current_user = CurrentUser::resolve().unwrap(); // fallback to root let (user, group) = resolve_target_user_and_group(&None, &None, ¤t_user).unwrap(); assert_eq!(user.name, "root"); assert_eq!(group.name, "root"); // unknown user let result = resolve_target_user_and_group(&Some("non_existing_ghost".into()), &None, ¤t_user); assert!(result.is_err()); // unknown user let result = resolve_target_user_and_group(&None, &Some("non_existing_ghost".into()), ¤t_user); assert!(result.is_err()); // fallback to current user when different group specified let (user, group) = resolve_target_user_and_group(&None, &Some("root".into()), ¤t_user).unwrap(); assert_eq!(user.name, current_user.name); assert_eq!(group.name, "root"); // fallback to current users group when no group specified let (user, group) = resolve_target_user_and_group(&Some(current_user.name.clone()), &None, ¤t_user) .unwrap(); assert_eq!(user.name, current_user.name); assert_eq!(group.gid, current_user.gid); } } /// Resolve symlinks in all the directories leading up to a file, but /// not the file itself; this alles sudo to specify a precise policy with /// tools like busybox or pgrep (which is a symlink to pgrep on systems) pub fn canonicalize>(path: P) -> io::Result { let path = path.as_ref(); let Some(parent) = path.parent() else { // path is "/" or a prefix return Ok(path.to_path_buf()); }; let canon_path = fs::canonicalize(parent)?; let reconstructed_path = if let Some(file_name) = path.file_name() { canon_path.join(file_name) } else { canon_path }; // access the object to generate the regular error if it does not exist let _ = fs::metadata(&reconstructed_path)?; Ok(reconstructed_path) } #[cfg(test)] mod test { use super::canonicalize; use std::path::Path; #[test] fn canonicalization() { assert_eq!(canonicalize("/").unwrap(), Path::new("/")); assert_eq!(canonicalize("").unwrap(), Path::new("")); assert_eq!( canonicalize("/usr/bin/pkill").unwrap(), Path::new("/usr/bin/pkill") ); // this assumes /bin is a symlink on /usr/bin, like it is on modern Debian/Ubuntu assert_eq!( canonicalize("/bin/pkill").unwrap(), Path::new("/usr/bin/pkill") ); } } sudo-rs-0.2.2/src/common/string.rs000064400000000000000000000064111046102023000151560ustar 00000000000000use core::fmt; use std::{ ffi::{CStr, OsString}, ops, }; use crate::common::Error; const NULL_BYTE: char = '\0'; const NULL_BYTE_UTF8_LEN: usize = NULL_BYTE.len_utf8(); /// A UTF-8 encoded string with no interior null bytes /// /// This type can be converted into a C (null-terminated) string at no cost #[derive(Clone, PartialEq, Eq)] pub struct SudoString { inner: String, } impl SudoString { pub fn new(mut string: String) -> Result { if string.as_bytes().contains(&0) { return Err(Error::StringValidation(string)); } string.push(NULL_BYTE); Ok(Self { inner: string }) } pub fn from_cli_string(cli_string: impl Into) -> Self { Self::new(cli_string.into()) .expect("strings that come in from CLI should not have interior null bytes") } pub fn as_cstr(&self) -> &CStr { CStr::from_bytes_with_nul(self.inner.as_bytes()).unwrap() } pub fn as_str(&self) -> &str { self } } impl Default for SudoString { fn default() -> Self { Self { inner: NULL_BYTE.into(), } } } #[cfg(test)] impl From<&'_ str> for SudoString { fn from(value: &'_ str) -> Self { SudoString::try_from(value.to_string()).unwrap() } } impl TryFrom for SudoString { type Error = Error; fn try_from(value: String) -> Result { Self::new(value) } } impl From for String { fn from(value: SudoString) -> Self { let mut s = value.inner; s.pop(); s } } impl From for OsString { fn from(value: SudoString) -> Self { let mut s = value.inner; s.pop(); OsString::from(s) } } impl ops::Deref for SudoString { type Target = str; fn deref(&self) -> &Self::Target { let num_bytes = self.inner.as_bytes().len(); &self.inner[..num_bytes - NULL_BYTE_UTF8_LEN] } } impl fmt::Debug for SudoString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let s: &str = self; fmt::Debug::fmt(s, f) } } impl fmt::Display for SudoString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self) } } impl PartialEq for SudoString { fn eq(&self, other: &str) -> bool { let s: &str = self; s == other } } impl PartialEq<&'_ str> for SudoString { fn eq(&self, other: &&str) -> bool { let s: &str = self; s == *other } } #[cfg(test)] mod tests { use std::ffi::CString; use super::*; #[test] fn null_byte_is_utf8_encoded_as_a_single_byte() { assert_eq!(1, NULL_BYTE_UTF8_LEN) } #[test] fn sanity_check() { let expected = "hello"; let s = SudoString::new("hello".to_string()).unwrap(); assert_eq!(expected, &*s); } #[test] fn cstr_conversion() { let expected = "hello"; let cstr = CString::from_vec_with_nul((expected.to_string() + "\0").into_bytes()).unwrap(); let s = SudoString::new(expected.to_string()).unwrap(); assert_eq!(&*cstr, s.as_cstr()); } #[test] fn rejects_string_that_contains_interior_null() { assert!(SudoString::new("he\0llo".to_string()).is_err()); } } sudo-rs-0.2.2/src/cutils/mod.rs000064400000000000000000000104351046102023000144430ustar 00000000000000use std::{ ffi::{CStr, OsStr, OsString}, os::unix::prelude::OsStrExt, }; pub fn cerr>(res: Int) -> std::io::Result { match res.try_into() { Ok(-1) => Err(std::io::Error::last_os_error()), _ => Ok(res), } } extern "C" { #[cfg_attr( any(target_os = "macos", target_os = "ios", target_os = "freebsd"), link_name = "__error" )] #[cfg_attr( any(target_os = "openbsd", target_os = "netbsd", target_os = "android"), link_name = "__errno" )] #[cfg_attr(target_os = "linux", link_name = "__errno_location")] fn errno_location() -> *mut libc::c_int; } pub fn set_errno(no: libc::c_int) { unsafe { *errno_location() = no }; } pub fn sysconf(name: libc::c_int) -> Option { set_errno(0); cerr(unsafe { libc::sysconf(name) }).ok() } /// Create a Rust string copy from a C string pointer /// WARNING: This uses `to_string_lossy` so should not be used for data where /// information loss is unacceptable (use `os_string_from_ptr` instead) /// /// # Safety /// This function assumes that the pointer is either a null pointer or that /// it points to a valid NUL-terminated C string. pub unsafe fn string_from_ptr(ptr: *const libc::c_char) -> String { if ptr.is_null() { String::new() } else { let cstr = unsafe { CStr::from_ptr(ptr) }; cstr.to_string_lossy().to_string() } } /// Create an `OsString` copy from a C string pointer. /// /// # Safety /// This function assumes that the pointer is either a null pointer or that /// it points to a valid NUL-terminated C string. pub unsafe fn os_string_from_ptr(ptr: *const libc::c_char) -> OsString { if ptr.is_null() { OsString::new() } else { let cstr = unsafe { CStr::from_ptr(ptr) }; OsStr::from_bytes(cstr.to_bytes()).to_owned() } } /// Rust's standard library IsTerminal just directly calls isatty, which /// we don't want since this performs IOCTL calls on them and file descriptors are under /// the control of the user; so this checks if they are a character device first. pub fn safe_isatty(fildes: libc::c_int) -> bool { // The Rust standard library doesn't have FileTypeExt on Std{in,out,err}, so we // can't just use FileTypeExt::is_char_device and have to resort to libc::fstat. let mut maybe_stat = std::mem::MaybeUninit::::uninit(); if unsafe { libc::fstat(fildes, maybe_stat.as_mut_ptr()) } == 0 { let mode = unsafe { maybe_stat.assume_init() }.st_mode; // To complicate matters further, the S_ISCHR macro isn't in libc as well. let is_char_device = (mode & libc::S_IFMT) == libc::S_IFCHR; if is_char_device { unsafe { libc::isatty(fildes) != 0 } } else { false } } else { false } } #[cfg(test)] mod test { use super::{os_string_from_ptr, string_from_ptr}; #[test] fn miri_test_str_to_ptr() { let strp = |ptr| unsafe { string_from_ptr(ptr) }; assert_eq!(strp(std::ptr::null()), ""); assert_eq!(strp("\0".as_ptr() as *const libc::c_char), ""); assert_eq!(strp("hello\0".as_ptr() as *const libc::c_char), "hello"); } #[test] fn miri_test_os_str_to_ptr() { let strp = |ptr| unsafe { os_string_from_ptr(ptr) }; assert_eq!(strp(std::ptr::null()), ""); assert_eq!(strp("\0".as_ptr() as *const libc::c_char), ""); assert_eq!(strp("hello\0".as_ptr() as *const libc::c_char), "hello"); } #[test] fn test_tty() { use std::fs::File; use std::os::fd::AsRawFd; assert!(!super::safe_isatty( File::open("/bin/sh").unwrap().as_raw_fd() )); assert!(!super::safe_isatty(-837492)); let (mut leader, mut follower) = Default::default(); assert!( unsafe { libc::openpty( &mut leader, &mut follower, std::ptr::null_mut(), std::ptr::null_mut(), std::ptr::null_mut(), ) } == 0 ); assert!(super::safe_isatty(leader)); assert!(super::safe_isatty(follower)); unsafe { libc::close(follower); libc::close(leader); } } } sudo-rs-0.2.2/src/defaults/mod.rs000064400000000000000000000103201046102023000147400ustar 00000000000000#![forbid(unsafe_code)] // FUTURE IDEA: use a representation that allows for more Rust-type structure rather than passing // strings around; some settings in sudoers file are more naturally represented like that, such as // "verifypw" and "logfile" pub enum SudoDefault { Flag(bool), Integer(OptTuple, fn(&str) -> Option), Text(OptTuple>), List(&'static [&'static str]), Enum(OptTuple>), } #[derive(Debug)] pub struct OptTuple { pub default: T, pub negated: Option, } mod strenum; pub use strenum::StrEnum; mod settings_dsl; use settings_dsl::*; defaults! { always_query_group_plugin = false always_set_home = false env_reset = true mail_badpass = true match_group_by_gid = false use_pty = true visiblepw = false env_editor = true passwd_tries = 3 [0..=1000] secure_path = None (!= None) verifypw = "all" (!= "never") [all, always, any, never] timestamp_timeout = (15*60) (!= 0) {fractional_minutes} env_keep = ["COLORS", "DISPLAY", "HOSTNAME", "KRB5CCNAME", "LS_COLORS", "PATH", "PS1", "PS2", "XAUTHORITY", "XAUTHORIZATION", "XDG_CURRENT_DESKTOP"] env_check = ["COLORTERM", "LANG", "LANGUAGE", "LC_*", "LINGUAS", "TERM", "TZ"] env_delete = ["IFS", "CDPATH", "LOCALDOMAIN", "RES_OPTIONS", "HOSTALIASES", "NLSPATH", "PATH_LOCALE", "LD_*", "_RLD*", "TERMINFO", "TERMINFO_DIRS", "TERMPATH", "TERMCAP", "ENV", "BASH_ENV", "PS4", "GLOBIGNORE", "BASHOPTS", "SHELLOPTS", "JAVA_TOOL_OPTIONS", "PERLIO_DEBUG", "PERLLIB", "PERL5LIB", "PERL5OPT", "PERL5DB", "FPATH", "NULLCMD", "READNULLCMD", "ZDOTDIR", "TMPPREFIX", "PYTHONHOME", "PYTHONPATH", "PYTHONINSPECT", "PYTHONUSERBASE", "RUBYLIB", "RUBYOPT", "*=()*"] } /// A custom parser to parse seconds as fractional "minutes", the format used by /// passwd_timeout and timestamp_timeout. fn fractional_minutes(input: &str) -> Option { if input.contains('.') { Some((input.parse::().ok()? * 60.0).floor() as i64) } else { Some(input.parse::().ok()? * 60) } } #[cfg(test)] mod test { use super::*; #[test] fn check() { macro_rules! test { ($name:ident => $value:pat) => { let Some(foo @ $value) = sudo_default(stringify!($name)) else { unreachable!() }; if let SudoDefault::Enum(OptTuple { default, negated }) = foo { assert!(default .possible_values .iter() .any(|x| *x as *const str == default.get())); negated.map(|neg| assert!(neg.possible_values.contains(&neg.get()))); } }; } assert!(sudo_default("bla").is_none()); use SudoDefault::*; test! { always_query_group_plugin => Flag(false) }; test! { always_set_home => Flag(false) }; test! { env_reset => Flag(true) }; test! { mail_badpass => Flag(true) }; test! { match_group_by_gid => Flag(false) }; test! { use_pty => Flag(true) }; test! { visiblepw => Flag(false) }; test! { env_editor => Flag(true) }; test! { passwd_tries => Integer(OptTuple { default: 3, negated: None }, _) }; test! { secure_path => Text(OptTuple { default: None, negated: Some(None) }) }; test! { env_keep => List(_) }; test! { env_check => List(["COLORTERM", "LANG", "LANGUAGE", "LC_*", "LINGUAS", "TERM", "TZ"]) }; test! { env_delete => List(_) }; test! { verifypw => Enum(OptTuple { default: StrEnum { value: "all", possible_values: [_, "always", "any", _] }, negated: Some(StrEnum { value: "never", .. }) }) }; let myenum = StrEnum::new("hello", &["hello", "goodbye"]).unwrap(); assert!(&myenum as &str == "hello"); } } sudo-rs-0.2.2/src/defaults/settings_dsl.rs000064400000000000000000000073031046102023000166720ustar 00000000000000macro_rules! add_from { ($ctor:ident, $type:ty) => { impl From<$type> for $crate::defaults::SudoDefault { fn from(value: $type) -> Self { $crate::defaults::SudoDefault::$ctor(value.into()) } } }; ($ctor:ident, $type:ty, negatable$(, $vetting_function:expr)?) => { impl From<$type> for $crate::defaults::SudoDefault { fn from(value: $type) -> Self { $crate::defaults::SudoDefault::$ctor(OptTuple { default: value.into(), negated: None, }$(, $vetting_function)?) } } impl From<($type, $type)> for $crate::defaults::SudoDefault { fn from((value, neg): ($type, $type)) -> Self { $crate::defaults::SudoDefault::$ctor(OptTuple { default: value.into(), negated: Some(neg.into()), }$(, $vetting_function)?) } } }; } macro_rules! sliceify { ([$($value:tt),*]) => { &[$($value),*][..] }; ($value:tt) => { ($value) }; } macro_rules! tupleify { ($fst:expr, $snd:expr) => { ($fst, $snd) }; ($value:tt) => { $value }; } macro_rules! optional { () => { |x| x }; ($block: block) => { $block }; } macro_rules! defaults { ($($name:ident = $value:tt $((!= $negate:tt))? $([$($key:ident),*])? $([$first:literal ..= $last:literal$(; radix: $radix: expr)?])? $({$fn: expr})?)*) => { pub const ALL_PARAMS: &'static [&'static str] = &[ $(stringify!($name)),* ]; // because of the nature of radix and ranges, 'let mut result' is not always necessary, and // a radix of 10 can also not always be avoided (and for uniformity, I would also not avoid this // if this was hand-written code. #[allow(unused_mut)] #[allow(clippy::from_str_radix_10)] pub fn sudo_default(var: &str) -> Option { add_from!(Flag, bool); add_from!(Integer, i64, negatable, |text| i64::from_str_radix(text, 10).ok()); add_from!(Text, &'static str, negatable); add_from!(Text, Option<&'static str>, negatable); add_from!(List, &'static [&'static str]); add_from!(Enum, StrEnum<'static>, negatable); Some( match var { $(stringify!($name) => { let restrict = optional![$({ let keys = &[$(stringify!($key)),*]; |key: &'static str| StrEnum::new(key, keys).unwrap_or_else(|| unreachable!()) })?]; let datum = restrict(sliceify!($value)); let mut result = tupleify!(datum$(, restrict($negate))?).into(); $( if let SudoDefault::Integer(_, ref mut checker) = &mut result { *checker = |text| i64::from_str_radix(text, 10$(*0 + $radix)?).ok().filter(|val| ($first ..= $last).contains(val)); } )? $( if let SudoDefault::Integer(_, ref mut checker) = &mut result { *checker = $fn } )? result }, )* _ => return None } ) } }; } pub(super) use add_from; pub(super) use defaults; pub(super) use optional; pub(super) use sliceify; pub(super) use tupleify; sudo-rs-0.2.2/src/defaults/strenum.rs000064400000000000000000000015411046102023000156630ustar 00000000000000/// This is a light-weight "enum"; it restricts the allowed values, but doesn't offer as much /// compile-time guarantees as an actual Enum. On the other hand this allows for a bit more /// flexibility. #[derive(Debug, Clone)] pub struct StrEnum<'a> { pub(super) value: &'a str, pub possible_values: &'a [&'a str], } impl<'a> StrEnum<'a> { pub fn new(choice: &str, possible_values: &'a [&'a str]) -> Option { Some(StrEnum { value: possible_values.iter().find(|&key| *key == choice)?, possible_values, }) } pub fn alt(self, choice: &str) -> Option { Self::new(choice, self.possible_values) } pub fn get(&self) -> &'a str { self.value } } impl<'a> std::ops::Deref for StrEnum<'a> { type Target = str; fn deref(&self) -> &str { self.get() } } sudo-rs-0.2.2/src/exec/event.rs000064400000000000000000000172651046102023000144360ustar 00000000000000use std::{ fmt::Debug, io, os::fd::{AsRawFd, RawFd}, }; use libc::{c_short, pollfd, POLLIN, POLLOUT}; use crate::common::{HARDENED_ENUM_VALUE_0, HARDENED_ENUM_VALUE_1}; use crate::{cutils::cerr, log::dev_debug}; pub(super) trait Process: Sized { /// IO Events that this process should handle. type Event: Copy + Eq + Debug; /// Reason why the event loop should break. /// /// See [`EventRegistry::set_break`] for more information. type Break; /// Reason why the event loop should exit. /// /// See [`EventRegistry::set_exit`] for more information. type Exit; /// Handle the corresponding event. fn on_event(&mut self, event: Self::Event, registry: &mut EventRegistry); } #[repr(u32)] enum Status { Continue = HARDENED_ENUM_VALUE_0, Stop(StopReason) = HARDENED_ENUM_VALUE_1, } impl Status { fn is_break(&self) -> bool { matches!(self, Self::Stop(StopReason::Break(_))) } fn take_stop(&mut self) -> Option> { // If the status ends up to be `Continue`, we are replacing it by another `Continue`. let status = std::mem::replace(self, Self::Continue); match status { Status::Continue => None, Status::Stop(reason) => Some(reason), } } fn take_exit(&mut self) -> Option { match self.take_stop()? { reason @ StopReason::Break(_) => { // Replace back the status because it was not an `Exit`. *self = Self::Stop(reason); None } StopReason::Exit(exit_reason) => Some(exit_reason), } } } pub(super) enum StopReason { Break(T::Break), Exit(T::Exit), } #[derive(PartialEq, Eq, Hash, Ord, PartialOrd, Clone, Copy)] struct EventId(usize); pub(super) struct EventHandle { id: EventId, should_poll: bool, } impl EventHandle { /// Ignore the event associated with this handle, meaning that the file descriptor for this /// event will not be polled anymore for that specific event. pub(super) fn ignore(&mut self, registry: &mut EventRegistry) { if self.should_poll { if let Some(poll_fd) = registry.poll_fds.get_mut(self.id.0) { poll_fd.should_poll = false; self.should_poll = false; } } } /// Stop ignoring the event associated with this handle, meaning that the file descriptor for /// this event will be polled for that specific event. pub(super) fn resume(&mut self, registry: &mut EventRegistry) { if !self.should_poll { if let Some(poll_fd) = registry.poll_fds.get_mut(self.id.0) { poll_fd.should_poll = true; self.should_poll = true; } } } } /// The kind of event that will be monitored for a file descriptor. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum PollEvent { /// Data may be read without blocking. Readable, /// Data may be written without blocking. Writable, } struct PollFd { raw_fd: RawFd, event_flags: c_short, should_poll: bool, event: T::Event, } /// A type able to register file descriptors to be polled. pub(super) struct EventRegistry { poll_fds: Vec>, status: Status, } impl EventRegistry { /// Create a new and empty registry.. pub(super) const fn new() -> Self { Self { poll_fds: Vec::new(), status: Status::Continue, } } /// Set the `fd` descriptor to be polled for `poll_event` events and produce `event` when `fd` is /// ready. pub(super) fn register_event( &mut self, fd: &F, poll_event: PollEvent, event_fn: impl Fn(PollEvent) -> T::Event, ) -> EventHandle { let id = EventId(self.poll_fds.len()); self.poll_fds.push(PollFd { raw_fd: fd.as_raw_fd(), event_flags: match poll_event { PollEvent::Readable => POLLIN, PollEvent::Writable => POLLOUT, }, should_poll: true, event: event_fn(poll_event), }); EventHandle { id, should_poll: true, } } /// Poll the file descriptors of that are not being ignored and return the ID of the /// descriptors that are ready to be read or written. /// /// Calling this function will block until one of the file descriptors in the set is ready. fn poll(&mut self) -> io::Result> { let (mut ids, mut fds): (Vec, Vec) = self .poll_fds .iter() .enumerate() .filter_map(|(index, poll_fd)| { poll_fd.should_poll.then_some({ ( EventId(index), pollfd { fd: poll_fd.raw_fd, events: poll_fd.event_flags, revents: 0, }, ) }) }) .unzip(); // Don't call poll if there are no file descriptors to be polled. if ids.is_empty() { return Ok(ids); } // FIXME: we should set either a timeout or use ppoll when available. cerr(unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as _, -1) })?; // Remove the ids that correspond to file descriptors that were not ready. for (i, fd) in fds.iter().enumerate().rev() { let events = fd.events & fd.revents; if !((events & POLLIN != 0) || (events & POLLOUT != 0)) { ids.remove(i); } } Ok(ids) } /// Stop the event loop when the current event has been handled and set a reason for it. /// /// This means that the event loop will stop even if other events are ready. pub(super) fn set_break(&mut self, reason: T::Break) { self.status = Status::Stop(StopReason::Break(reason)); } /// Stop the event loop when the events that are ready by now have been handled and set a /// reason for it. pub(super) fn set_exit(&mut self, reason: T::Exit) { self.status = Status::Stop(StopReason::Exit(reason)); } /// Return whether a break reason has been set already. This function will return `false` after /// [`EventRegistry::event_loop`] has been called. pub(super) fn got_break(&self) -> bool { self.status.is_break() } /// Run the event loop over this registry using `process` to handle the produced events. /// /// The event loop will continue indefinitely unless you call [`EventRegistry::set_break`] or /// [`EventRegistry::set_exit`]. #[track_caller] pub(super) fn event_loop(&mut self, process: &mut T) -> StopReason { let mut event_queue = Vec::with_capacity(self.poll_fds.len()); loop { // FIXME: maybe we shout return the IO error instead. if let Ok(ids) = self.poll() { for EventId(index) in ids { let event = self.poll_fds[index].event; dev_debug!("event {event:?} is ready"); event_queue.push(event); } for event in event_queue.drain(..) { process.on_event(event, self); if let Some(reason) = self.status.take_exit() { return StopReason::Exit(reason); } } } if let Some(reason) = self.status.take_stop() { return reason; } } } } sudo-rs-0.2.2/src/exec/interface.rs000064400000000000000000000026331046102023000152460ustar 00000000000000use std::io::{self, ErrorKind}; use std::path::PathBuf; use crate::common::SudoPath; use crate::{ common::{context::LaunchType, Context}, system::{Group, User}, }; pub trait RunOptions { fn command(&self) -> io::Result<&PathBuf>; fn arguments(&self) -> &Vec; fn arg0(&self) -> Option<&PathBuf>; fn chdir(&self) -> Option<&SudoPath>; fn is_login(&self) -> bool; fn user(&self) -> &User; fn requesting_user(&self) -> &User; fn group(&self) -> &Group; fn pid(&self) -> i32; fn use_pty(&self) -> bool; } impl RunOptions for Context { fn command(&self) -> io::Result<&PathBuf> { if self.command.resolved { Ok(&self.command.command) } else { Err(ErrorKind::NotFound.into()) } } fn arguments(&self) -> &Vec { &self.command.arguments } fn arg0(&self) -> Option<&PathBuf> { self.command.arg0.as_ref() } fn chdir(&self) -> Option<&SudoPath> { self.chdir.as_ref() } fn is_login(&self) -> bool { self.launch == LaunchType::Login } fn user(&self) -> &User { &self.target_user } fn requesting_user(&self) -> &User { &self.current_user } fn group(&self) -> &Group { &self.target_group } fn pid(&self) -> i32 { self.process.pid } fn use_pty(&self) -> bool { self.use_pty } } sudo-rs-0.2.2/src/exec/io_util.rs000064400000000000000000000011321046102023000147430ustar 00000000000000use std::io; /// Return `true` if the IO error is an interruption. pub(super) fn was_interrupted(err: &io::Error) -> bool { // ogsudo checks against `EINTR` and `EAGAIN`. matches!( err.kind(), io::ErrorKind::Interrupted | io::ErrorKind::WouldBlock ) } /// Call `f` repeatedly until it succeds or it encounters a non-interruption error. pub(super) fn retry_while_interrupted(mut f: impl FnMut() -> io::Result) -> io::Result { loop { match f() { Err(err) if was_interrupted(&err) => {} result => return result, } } } sudo-rs-0.2.2/src/exec/mod.rs000064400000000000000000000155711046102023000140720ustar 00000000000000mod event; mod interface; mod io_util; mod no_pty; mod use_pty; use std::{ borrow::Cow, env, ffi::{c_int, OsStr}, io, os::unix::ffi::OsStrExt, os::unix::process::CommandExt, process::Command, time::Duration, }; use crate::{ common::Environment, log::dev_warn, system::{ _exit, interface::ProcessId, killpg, signal::{consts::*, signal_name}, wait::{Wait, WaitError, WaitOptions}, }, }; use crate::{ exec::no_pty::exec_no_pty, log::dev_info, system::{set_target_user, signal::SignalNumber, term::UserTerm}, }; use crate::{log::user_error, system::kill}; pub use interface::RunOptions; use self::{ event::{EventRegistry, Process}, io_util::was_interrupted, use_pty::{exec_pty, SIGCONT_BG, SIGCONT_FG}, }; /// Based on `ogsudo`s `exec_pty` function. /// /// Returns the [`ExitReason`] of the command and a function that restores the default handler for /// signals once its called. pub fn run_command(options: &impl RunOptions, env: Environment) -> io::Result { match run_command_internal(options, env)? { ProcessOutput::SudoExit { output } => Ok(output), // We call `_exit` instead of `exit` to avoid flushing the parent's IO streams by accident. ProcessOutput::ChildExit => _exit(1), } } fn run_command_internal(options: &impl RunOptions, env: Environment) -> io::Result { // FIXME: should we pipe the stdio streams? let qualified_path = options.command()?; let mut command = Command::new(qualified_path); // reset env and set filtered environment command.args(options.arguments()).env_clear().envs(env); // set the arg0 to the requested string // TODO: this mechanism could perhaps also be used to set the arg0 for login shells, as below if let Some(arg0) = options.arg0() { command.arg0(arg0); } if options.is_login() { // signal to the operating system that the command is a login shell by prefixing "-" let mut process_name = qualified_path .file_name() .map(|osstr| osstr.as_bytes().to_vec()) .unwrap_or_else(Vec::new); process_name.insert(0, b'-'); command.arg0(OsStr::from_bytes(&process_name)); } // Decide if the pwd should be changed. `--chdir` takes precedence over `-i`. let path = options .chdir() .cloned() .or_else(|| options.is_login().then(|| options.user().home.clone())); // set target user and groups set_target_user( &mut command, options.user().clone(), options.group().clone(), ); // change current directory if necessary. if let Some(path) = path { let is_chdir = options.chdir().is_some(); unsafe { command.pre_exec(move || { if let Err(err) = env::set_current_dir(&path) { user_error!("unable to change directory to {}: {}", path.display(), err); if is_chdir { return Err(err); } } Ok(()) }); } } if options.use_pty() { match UserTerm::open() { Ok(user_tty) => exec_pty(options.pid(), command, user_tty), Err(err) => { dev_info!("Could not open user's terminal, not allocating a pty: {err}"); exec_no_pty(options.pid(), command) } } } else { exec_no_pty(options.pid(), command) } } /// The output of a command's execution. pub struct ExecOutput { /// The exit reason of the executed command, pub command_exit_reason: ExitReason, /// A function to restore the signal handlers that were modified to execute the command. pub restore_signal_handlers: Box, } enum ProcessOutput { // The main process exited. SudoExit { output: ExecOutput }, // A forked child process exited. ChildExit, } /// Exit reason for the command executed by sudo. #[derive(Debug)] pub enum ExitReason { Code(i32), Signal(i32), } // Kill the process with increasing urgency. // // Based on `terminate_command`. fn terminate_process(pid: ProcessId, use_killpg: bool) { let kill_fn = if use_killpg { killpg } else { kill }; kill_fn(pid, SIGHUP).ok(); kill_fn(pid, SIGTERM).ok(); std::thread::sleep(Duration::from_secs(2)); kill_fn(pid, SIGKILL).ok(); } trait HandleSigchld: Process { const OPTIONS: WaitOptions; fn on_exit(&mut self, exit_code: c_int, registry: &mut EventRegistry); fn on_term(&mut self, signal: SignalNumber, registry: &mut EventRegistry); fn on_stop(&mut self, signal: SignalNumber, registry: &mut EventRegistry); } fn handle_sigchld( handler: &mut T, registry: &mut EventRegistry, child_name: &'static str, child_pid: ProcessId, ) { let status = loop { match child_pid.wait(T::OPTIONS) { Err(WaitError::Io(err)) if was_interrupted(&err) => {} // This only happens if we receive `SIGCHLD` but there's no status update from the // monitor. Err(WaitError::Io(err)) => { return dev_info!("cannot wait for {child_pid} ({child_name}): {err}"); } // This only happens if the monitor exited and any process already waited for the // monitor. Err(WaitError::NotReady) => { return dev_info!("{child_pid} ({child_name}) has no status report"); } Ok((_pid, status)) => break status, } }; if let Some(exit_code) = status.exit_status() { dev_info!("{child_pid} ({child_name}) exited with status code {exit_code}"); handler.on_exit(exit_code, registry) } else if let Some(signal) = status.stop_signal() { dev_info!( "{child_pid} ({child_name}) was stopped by {}", signal_fmt(signal), ); handler.on_stop(signal, registry) } else if let Some(signal) = status.term_signal() { dev_info!( "{child_pid} ({child_name}) was terminated by {}", signal_fmt(signal), ); handler.on_term(signal, registry) } else if status.did_continue() { dev_info!("{child_pid} ({child_name}) continued execution"); } else { dev_warn!("unexpected wait status for {child_pid} ({child_name})") } } fn signal_fmt(signal: SignalNumber) -> Cow<'static, str> { match signal_name(signal) { name @ Cow::Owned(_) => match signal { SIGCONT_BG => "SIGCONT_BG".into(), SIGCONT_FG => "SIGCONT_FG".into(), _ => name, }, name => name, } } const fn cond_fmt<'a>(cond: bool, true_s: &'a str, false_s: &'a str) -> &'a str { if cond { true_s } else { false_s } } const fn opt_fmt(cond: bool, s: &str) -> &str { cond_fmt(cond, s, "") } sudo-rs-0.2.2/src/exec/no_pty.rs000064400000000000000000000244641046102023000146240ustar 00000000000000use std::{ffi::c_int, io, os::unix::process::CommandExt, process::Command}; use super::{ event::PollEvent, event::{EventRegistry, Process, StopReason}, io_util::was_interrupted, terminate_process, ExitReason, HandleSigchld, ProcessOutput, }; use crate::{ common::bin_serde::BinPipe, system::signal::{ consts::*, register_handlers, SignalHandler, SignalHandlerBehavior, SignalNumber, SignalSet, SignalStream, }, }; use crate::{ exec::{handle_sigchld, opt_fmt, signal_fmt}, log::{dev_error, dev_info, dev_warn}, system::{ fork, getpgid, getpgrp, interface::ProcessId, kill, killpg, term::{Terminal, UserTerm}, wait::WaitOptions, FileCloser, ForkResult, }, }; pub(super) fn exec_no_pty(sudo_pid: ProcessId, mut command: Command) -> io::Result { // FIXME (ogsudo): Initialize the policy plugin's session here. // Block all the signals until we are done setting up the signal handlers so we don't miss // SIGCHLD. let original_set = match SignalSet::full().and_then(|set| set.block()) { Ok(original_set) => Some(original_set), Err(err) => { dev_warn!("cannot block signals: {err}"); None } }; let mut file_closer = FileCloser::new(); // FIXME (ogsudo): Some extra config happens here if selinux is available. // Use a pipe to get the IO error if `exec` fails. let (mut errpipe_tx, errpipe_rx) = BinPipe::pair()?; // Don't close the error pipe as we need it to retrieve the error code if the command execution // fails. file_closer.except(&errpipe_tx); let ForkResult::Parent(command_pid) = fork().map_err(|err| { dev_warn!("unable to fork command process: {err}"); err })? else { file_closer.close_the_universe()?; // Restore the signal mask now that the handlers have been setup. if let Some(set) = original_set { if let Err(err) = set.set_mask() { dev_warn!("cannot restore signal mask: {err}"); } } let err = command.exec(); dev_warn!("failed to execute command: {err}"); // If `exec` returns, it means that executing the command failed. Send the error to the // monitor using the pipe. if let Some(error_code) = err.raw_os_error() { errpipe_tx.write(&error_code).ok(); } return Ok(ProcessOutput::ChildExit); }; dev_info!("executed command with pid {command_pid}"); let mut registry = EventRegistry::new(); let mut closure = ExecClosure::new(command_pid, sudo_pid, errpipe_rx, &mut registry)?; // Restore the signal mask now that the handlers have been setup. if let Some(set) = original_set { if let Err(err) = set.set_mask() { dev_warn!("cannot restore signal mask: {err}"); } } let command_exit_reason = match registry.event_loop(&mut closure) { StopReason::Break(err) => return Err(err), StopReason::Exit(reason) => reason, }; Ok(ProcessOutput::SudoExit { output: crate::exec::ExecOutput { command_exit_reason, restore_signal_handlers: Box::new(move || drop(closure.signal_handlers)), }, }) } struct ExecClosure { command_pid: Option, sudo_pid: ProcessId, parent_pgrp: ProcessId, errpipe_rx: BinPipe, signal_stream: &'static SignalStream, signal_handlers: [SignalHandler; ExecClosure::SIGNALS.len()], } impl ExecClosure { const SIGNALS: [SignalNumber; 12] = [ SIGINT, SIGQUIT, SIGTSTP, SIGTERM, SIGHUP, SIGALRM, SIGPIPE, SIGUSR1, SIGUSR2, SIGCHLD, SIGCONT, SIGWINCH, ]; fn new( command_pid: ProcessId, sudo_pid: ProcessId, errpipe_rx: BinPipe, registry: &mut EventRegistry, ) -> io::Result { registry.register_event(&errpipe_rx, PollEvent::Readable, |_| ExecEvent::ErrPipe); let signal_stream = SignalStream::init()?; registry.register_event(signal_stream, PollEvent::Readable, |_| ExecEvent::Signal); let signal_handlers = register_handlers(Self::SIGNALS)?; Ok(Self { command_pid: Some(command_pid), errpipe_rx, sudo_pid, parent_pgrp: getpgrp(), signal_stream, signal_handlers, }) } /// Decides if the signal sent by the process with `signaler_pid` PID is self-terminating. /// /// A signal is self-terminating if `signaler_pid`: /// - is the same PID of the command, or /// - is in the process group of the command and either sudo or the command is the leader. fn is_self_terminating(&self, signaler_pid: ProcessId) -> bool { if signaler_pid != 0 { if Some(signaler_pid) == self.command_pid { return true; } if let Ok(signaler_pgrp) = getpgid(signaler_pid) { if Some(signaler_pgrp) == self.command_pid || signaler_pgrp == self.sudo_pid { return true; } } } false } /// Suspend the main process. fn suspend_parent(&self, signal: SignalNumber) { let mut opt_tty = UserTerm::open().ok(); let mut opt_pgrp = None; if let Some(tty) = opt_tty.as_ref() { if let Ok(saved_pgrp) = tty.tcgetpgrp() { // Save the terminal's foreground process group so we can restore it after resuming // if needed. opt_pgrp = Some(saved_pgrp); } else { opt_tty.take(); } } if let Some(saved_pgrp) = opt_pgrp { // This means that the command was stopped trying to access the terminal. If the // terminal has a different foreground process group and we own the terminal, we give // it to the command and let it continue. if let SIGTTOU | SIGTTIN = signal { if saved_pgrp == self.parent_pgrp { if let Some(command_pgrp) = self.command_pid.and_then(|pid| getpgid(pid).ok()) { if command_pgrp != self.parent_pgrp && opt_tty .as_ref() .is_some_and(|tty| tty.tcsetpgrp_nobg(command_pgrp).is_ok()) { if let Err(err) = killpg(command_pgrp, SIGCONT) { dev_warn!("cannot send SIGCONT to command ({command_pgrp}): {err}"); } return; } } } } } let sigtstp_handler = if signal == SIGTSTP { SignalHandler::register(signal, SignalHandlerBehavior::Default) .map_err(|err| dev_warn!("cannot set handler for {}: {err}", signal_fmt(signal))) .ok() } else { None }; if let Err(err) = kill(self.sudo_pid, signal) { dev_warn!( "cannot send {} to {} (sudo): {err}", signal_fmt(signal), self.sudo_pid ); } drop(sigtstp_handler); if let Some(saved_pgrp) = opt_pgrp { // Restore the foreground process group after resuming. if saved_pgrp != self.parent_pgrp { if let Some(tty) = opt_tty { tty.tcsetpgrp_nobg(saved_pgrp).ok(); } } } } fn on_signal(&mut self, registry: &mut EventRegistry) { let info = match self.signal_stream.recv() { Ok(info) => info, Err(err) => { dev_error!("sudo could not receive signal: {err}"); return; } }; dev_info!( "received{} {} from {}", opt_fmt(info.is_user_signaled(), " user signaled"), info.signal(), info.pid() ); let Some(command_pid) = self.command_pid else { dev_info!("command was terminated, ignoring signal"); return; }; match info.signal() { SIGCHLD => handle_sigchld(self, registry, "command", command_pid), signal => { // FIXME: we should handle SIGWINCH here if we want to support I/O plugins that // react on window change events. // Skip the signal if it was sent by the user and it is self-terminating. if info.is_user_signaled() && self.is_self_terminating(info.pid()) { return; } if signal == SIGALRM { terminate_process(command_pid, false); } else { kill(command_pid, signal).ok(); } } } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum ExecEvent { Signal, ErrPipe, } impl Process for ExecClosure { type Event = ExecEvent; type Break = io::Error; type Exit = ExitReason; fn on_event(&mut self, event: Self::Event, registry: &mut EventRegistry) { match event { ExecEvent::Signal => self.on_signal(registry), ExecEvent::ErrPipe => { match self.errpipe_rx.read() { Err(err) if was_interrupted(&err) => { /* Retry later */ } Err(err) => registry.set_break(err), Ok(error_code) => { // Received error code from the command, forward it to the parent. registry.set_break(io::Error::from_raw_os_error(error_code)); } } } } } } impl HandleSigchld for ExecClosure { const OPTIONS: WaitOptions = WaitOptions::new().all().untraced().no_hang(); fn on_exit(&mut self, exit_code: c_int, registry: &mut EventRegistry) { registry.set_exit(ExitReason::Code(exit_code)); self.command_pid = None; } fn on_term(&mut self, signal: SignalNumber, registry: &mut EventRegistry) { registry.set_exit(ExitReason::Signal(signal)); self.command_pid = None; } fn on_stop(&mut self, signal: SignalNumber, _registry: &mut EventRegistry) { self.suspend_parent(signal); } } sudo-rs-0.2.2/src/exec/use_pty/backchannel.rs000064400000000000000000000221331046102023000172240ustar 00000000000000use std::{ ffi::c_int, io, mem::size_of, os::fd::{AsRawFd, RawFd}, }; use crate::{ common::bin_serde::{BinPipe, DeSerialize}, exec::signal_fmt, system::interface::ProcessId, }; use super::CommandStatus; type Prefix = u8; type ParentData = c_int; type MonitorData = c_int; const PREFIX_LEN: usize = size_of::(); const PARENT_DATA_LEN: usize = size_of::(); const MONITOR_DATA_LEN: usize = size_of::(); pub(super) struct BackchannelPair { pub(super) parent: ParentBackchannel, pub(super) monitor: MonitorBackchannel, } impl BackchannelPair { pub(super) fn new() -> io::Result { let (sock1, sock2) = BinPipe::pair()?; #[cfg(debug_assertions)] { sock1.set_nonblocking(true)?; sock2.set_nonblocking(true)?; } Ok(Self { parent: ParentBackchannel { socket: sock1, #[cfg(debug_assertions)] nonblocking_asserts: false, }, monitor: MonitorBackchannel { socket: sock2, #[cfg(debug_assertions)] nonblocking_asserts: false, }, }) } } pub(super) enum ParentMessage { IoError(c_int), CommandStatus(CommandStatus), CommandPid(ProcessId), ShortRead, } impl ParentMessage { const LEN: usize = PREFIX_LEN + PARENT_DATA_LEN; const IO_ERROR: Prefix = 0; const CMD_STAT_EXIT: Prefix = 1; const CMD_STAT_TERM: Prefix = 2; const CMD_STAT_STOP: Prefix = 3; const CMD_PID: Prefix = 4; const SHORT_READ: Prefix = 5; fn from_parts(prefix: Prefix, data: ParentData) -> Self { match prefix { Self::IO_ERROR => Self::IoError(data), Self::CMD_STAT_EXIT => Self::CommandStatus(CommandStatus::Exit(data)), Self::CMD_STAT_TERM => Self::CommandStatus(CommandStatus::Term(data)), Self::CMD_STAT_STOP => Self::CommandStatus(CommandStatus::Stop(data)), Self::CMD_PID => Self::CommandPid(data), Self::SHORT_READ => Self::ShortRead, _ => unreachable!(), } } fn to_parts(&self) -> (Prefix, ParentData) { let prefix = match self { ParentMessage::IoError(_) => Self::IO_ERROR, ParentMessage::CommandStatus(CommandStatus::Exit(_)) => Self::CMD_STAT_EXIT, ParentMessage::CommandStatus(CommandStatus::Term(_)) => Self::CMD_STAT_TERM, ParentMessage::CommandStatus(CommandStatus::Stop(_)) => Self::CMD_STAT_STOP, ParentMessage::CommandPid(_) => Self::CMD_PID, ParentMessage::ShortRead => Self::SHORT_READ, }; let data = match self { ParentMessage::IoError(data) | ParentMessage::CommandPid(data) => *data, ParentMessage::CommandStatus(status) => match status { CommandStatus::Exit(data) | CommandStatus::Term(data) | CommandStatus::Stop(data) => *data, }, ParentMessage::ShortRead => 0, }; (prefix, data) } } impl TryFrom for ParentMessage { type Error = io::Error; fn try_from(err: io::Error) -> Result { err.raw_os_error() .map(Self::IoError) .or_else(|| (err.kind() == io::ErrorKind::UnexpectedEof).then_some(Self::ShortRead)) .ok_or(err) } } impl From for ParentMessage { fn from(status: CommandStatus) -> Self { Self::CommandStatus(status) } } impl DeSerialize for ParentMessage { type Bytes = [u8; ParentMessage::LEN]; fn serialize(&self) -> Self::Bytes { let mut buf = [0; ParentMessage::LEN]; let (prefix_buf, data_buf) = buf.split_at_mut(PREFIX_LEN); let (prefix, data) = self.to_parts(); prefix_buf.copy_from_slice(&prefix.to_ne_bytes()); data_buf.copy_from_slice(&data.to_ne_bytes()); buf } fn deserialize(buf: Self::Bytes) -> Self { let (prefix_buf, data_buf) = buf.split_at(PREFIX_LEN); let prefix = Prefix::from_ne_bytes(prefix_buf.try_into().unwrap()); let data = MonitorData::from_ne_bytes(data_buf.try_into().unwrap()); ParentMessage::from_parts(prefix, data) } } /// A socket use for commmunication between the monitor and the parent process. pub(super) struct ParentBackchannel { socket: BinPipe, #[cfg(debug_assertions)] nonblocking_asserts: bool, } impl ParentBackchannel { /// Send a [`MonitorMessage`]. /// /// Calling this method will block until the socket is ready for writing. #[track_caller] pub(super) fn send(&mut self, event: &MonitorMessage) -> io::Result<()> { self.socket.write(event).map_err(|err| { #[cfg(debug_assertions)] if self.nonblocking_asserts { assert_ne!(err.kind(), io::ErrorKind::WouldBlock); } err }) } /// Receive a [`ParentMessage`]. /// /// Calling this method will block until the socket is ready for reading. #[track_caller] pub(super) fn recv(&mut self) -> io::Result { let msg = self.socket.read().map_err(|err| { #[cfg(debug_assertions)] if self.nonblocking_asserts { assert_ne!(err.kind(), io::ErrorKind::WouldBlock); } err })?; Ok(msg) } pub(super) fn set_nonblocking_asserts(&mut self, _doit: bool) { #[cfg(debug_assertions)] { self.nonblocking_asserts = _doit; } } } impl AsRawFd for ParentBackchannel { fn as_raw_fd(&self) -> RawFd { self.socket.as_raw_fd() } } /// Different messages exchanged between the monitor and the parent process using a [`ParentBackchannel`]. #[derive(PartialEq, Eq)] pub(super) enum MonitorMessage { ExecCommand, Signal(c_int), } impl MonitorMessage { const LEN: usize = PREFIX_LEN + MONITOR_DATA_LEN; const EXEC_CMD: Prefix = 0; const SIGNAL: Prefix = 1; fn from_parts(prefix: Prefix, data: MonitorData) -> Self { match prefix { Self::EXEC_CMD => Self::ExecCommand, Self::SIGNAL => Self::Signal(data), _ => unreachable!(), } } fn to_parts(&self) -> (Prefix, MonitorData) { let prefix = match self { MonitorMessage::ExecCommand => Self::EXEC_CMD, MonitorMessage::Signal(_) => Self::SIGNAL, }; let data = match self { MonitorMessage::ExecCommand => 0, MonitorMessage::Signal(data) => *data, }; (prefix, data) } } impl std::fmt::Debug for MonitorMessage { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::ExecCommand => "ExecCommand".fmt(f), &Self::Signal(signal) => write!(f, "Signal({})", signal_fmt(signal)), } } } impl DeSerialize for MonitorMessage { type Bytes = [u8; MonitorMessage::LEN]; fn serialize(&self) -> Self::Bytes { let mut buf = [0; MonitorMessage::LEN]; let (prefix_buf, data_buf) = buf.split_at_mut(PREFIX_LEN); let (prefix, data) = self.to_parts(); prefix_buf.copy_from_slice(&prefix.to_ne_bytes()); data_buf.copy_from_slice(&data.to_ne_bytes()); buf } fn deserialize(bytes: Self::Bytes) -> Self { let (prefix_buf, data_buf) = bytes.split_at(PREFIX_LEN); let prefix = Prefix::from_ne_bytes(prefix_buf.try_into().unwrap()); let data = MonitorData::from_ne_bytes(data_buf.try_into().unwrap()); MonitorMessage::from_parts(prefix, data) } } /// A socket use for commmunication between the monitor and the parent process. pub(super) struct MonitorBackchannel { socket: BinPipe, #[cfg(debug_assertions)] nonblocking_asserts: bool, } impl MonitorBackchannel { /// Send a [`ParentMessage`]. /// /// Calling this method will block until the socket is ready for writing. #[track_caller] pub(super) fn send(&mut self, event: &ParentMessage) -> io::Result<()> { self.socket.write(event).map_err(|err| { #[cfg(debug_assertions)] if self.nonblocking_asserts { assert_ne!(err.kind(), io::ErrorKind::WouldBlock); } err }) } /// Receive a [`MonitorMessage`]. /// /// Calling this method will block until the socket is ready for reading. #[track_caller] pub(super) fn recv(&mut self) -> io::Result { let msg = self.socket.read().map_err(|err| { #[cfg(debug_assertions)] if self.nonblocking_asserts { assert_ne!(err.kind(), io::ErrorKind::WouldBlock); } err })?; Ok(msg) } pub(super) fn set_nonblocking_assertions(&mut self, _doit: bool) { #[cfg(debug_assertions)] { self.nonblocking_asserts = _doit; } } } impl AsRawFd for MonitorBackchannel { fn as_raw_fd(&self) -> RawFd { self.socket.as_raw_fd() } } sudo-rs-0.2.2/src/exec/use_pty/mod.rs000064400000000000000000000006361046102023000155560ustar 00000000000000mod backchannel; mod monitor; mod parent; mod pipe; use std::ffi::c_int; pub(super) use parent::exec_pty; use crate::system::signal::SignalNumber; /// Continue running in the foreground pub(super) const SIGCONT_FG: SignalNumber = -2; /// Continue running in the background pub(super) const SIGCONT_BG: SignalNumber = -3; enum CommandStatus { Exit(c_int), Term(SignalNumber), Stop(SignalNumber), } sudo-rs-0.2.2/src/exec/use_pty/monitor.rs000064400000000000000000000376761046102023000165040ustar 00000000000000use std::{ffi::c_int, io, os::unix::process::CommandExt, process::Command}; use crate::exec::{opt_fmt, signal_fmt}; use crate::system::signal::{ consts::*, register_handlers, SignalHandler, SignalHandlerBehavior, SignalNumber, SignalSet, SignalStream, }; use crate::{ common::bin_serde::BinPipe, exec::{ event::{EventRegistry, Process}, io_util::{retry_while_interrupted, was_interrupted}, use_pty::backchannel::{MonitorBackchannel, MonitorMessage, ParentMessage}, }, }; use crate::{ exec::{ event::{PollEvent, StopReason}, use_pty::{SIGCONT_BG, SIGCONT_FG}, ProcessOutput, }, log::{dev_error, dev_info, dev_warn}, system::FileCloser, }; use crate::{ exec::{handle_sigchld, terminate_process, HandleSigchld}, system::{ fork, getpgid, getpgrp, interface::ProcessId, kill, setpgid, setsid, term::{PtyFollower, Terminal}, wait::{Wait, WaitError, WaitOptions}, ForkResult, }, }; use super::CommandStatus; // FIXME: This should return `io::Result` but `!` is not stable yet. pub(super) fn exec_monitor( pty_follower: PtyFollower, command: Command, foreground: bool, backchannel: &mut MonitorBackchannel, mut file_closer: FileCloser, original_set: Option, ) -> io::Result { // SIGTTIN and SIGTTOU are ignored here but the docs state that it shouldn't // be possible to receive them in the first place. Investigate match SignalHandler::register(SIGTTIN, SignalHandlerBehavior::Ignore) { Ok(handler) => handler.forget(), Err(err) => dev_warn!("cannot set handler for SIGTTIN: {err}"), } match SignalHandler::register(SIGTTOU, SignalHandlerBehavior::Ignore) { Ok(handler) => handler.forget(), Err(err) => dev_warn!("cannot set handler for SIGTTOU: {err}"), } // Start a new terminal session with the monitor as the leader. setsid().map_err(|err| { dev_warn!("cannot start a new session: {err}"); err })?; // Set the follower side of the pty as the controlling terminal for the session. pty_follower.make_controlling_terminal().map_err(|err| { dev_warn!("cannot set the controlling terminal: {err}"); err })?; // Use a pipe to get the IO error if `exec_command` fails. let (mut errpipe_tx, errpipe_rx) = BinPipe::pair()?; // Don't close the error pipe as we need it to retrieve the error code if the command execution // fails. file_closer.except(&errpipe_tx); // Wait for the parent to give us green light before spawning the command. This avoids race // conditions when the command exits quickly. let event = retry_while_interrupted(|| backchannel.recv()).map_err(|err| { dev_warn!("cannot receive green light from parent: {err}"); err })?; // Given that `UnixStream` delivers messages in order it shouldn't be possible to // receive an event different to `ExecCommand` at the beginning. debug_assert_eq!(event, MonitorMessage::ExecCommand); // FIXME (ogsudo): Some extra config happens here if selinux is available. let ForkResult::Parent(command_pid) = fork().map_err(|err| { dev_warn!("unable to fork command process: {err}"); err })? else { drop(errpipe_rx); let err = exec_command(command, foreground, pty_follower, file_closer, original_set); dev_warn!("failed to execute command: {err}"); // If `exec_command` returns, it means that executing the command failed. Send the error to // the monitor using the pipe. if let Some(error_code) = err.raw_os_error() { errpipe_tx.write(&error_code).ok(); } return Ok(ProcessOutput::ChildExit); }; // Send the command's PID to the parent. if let Err(err) = backchannel.send(&ParentMessage::CommandPid(command_pid)) { dev_warn!("cannot send command PID to parent: {err}"); } let mut registry = EventRegistry::new(); let mut closure = MonitorClosure::new( command_pid, pty_follower, errpipe_rx, backchannel, &mut registry, )?; // Restore the signal mask now that the handlers have been setup. if let Some(set) = original_set { if let Err(err) = set.set_mask() { dev_warn!("cannot restore signal mask: {err}"); } } // Set the foreground group for the pty follower. if foreground { if let Err(err) = closure.pty_follower.tcsetpgrp(closure.command_pgrp) { dev_error!( "cannot set foreground progess group to {} (command): {err}", closure.command_pgrp ); } } // FIXME (ogsudo): Here's where the signal mask is removed because the handlers for the signals // have been setup after initializing the closure. // Start the event loop. let reason = registry.event_loop(&mut closure); // Terminate the command if it's not terminated. if let Some(command_pid) = closure.command_pid { terminate_process(command_pid, true); loop { match command_pid.wait(WaitOptions::new()) { Err(WaitError::Io(err)) if was_interrupted(&err) => {} _ => break, } } } // Take the controlling tty so the command's children don't receive SIGHUP when we exit. if let Err(err) = closure.pty_follower.tcsetpgrp(closure.monitor_pgrp) { dev_error!( "cannot set foreground process group to {} (monitor): {err}", closure.monitor_pgrp ); } // Disable nonblocking assetions as we will not poll the backchannel anymore. closure.backchannel.set_nonblocking_assertions(false); match reason { StopReason::Break(err) => match err.try_into() { Ok(msg) => { if let Err(err) = closure.backchannel.send(&msg) { dev_warn!("cannot send message over backchannel: {err}") } } Err(err) => { dev_warn!("socket error `{err:?}` cannot be converted to a message") } }, StopReason::Exit(command_status) => { if let Err(err) = closure.backchannel.send(&command_status.into()) { dev_warn!("cannot send message over backchannel: {err}") } } } // FIXME (ogsudo): The tty is restored here if selinux is available. Ok(ProcessOutput::ChildExit) } // FIXME: This should return `io::Result` but `!` is not stable yet. fn exec_command( mut command: Command, foreground: bool, pty_follower: PtyFollower, file_closer: FileCloser, original_set: Option, ) -> io::Error { // FIXME (ogsudo): Do any additional configuration that needs to be run after `fork` but before `exec` let command_pid = std::process::id() as ProcessId; setpgid(0, command_pid).ok(); // Wait for the monitor to set us as the foreground group for the pty if we are in the // foreground. if foreground { while !pty_follower.tcgetpgrp().is_ok_and(|pid| pid == command_pid) { std::thread::sleep(std::time::Duration::from_micros(1)); } } // Done with the pty follower. drop(pty_follower); if let Err(err) = file_closer.close_the_universe() { return err; } // Restore the signal mask now that the handlers have been setup. if let Some(set) = original_set { if let Err(err) = set.set_mask() { dev_warn!("cannot restore signal mask: {err}"); } } command.exec() } struct MonitorClosure<'a> { /// The command PID. /// /// This is `Some` iff the process is still running. command_pid: Option, command_pgrp: ProcessId, monitor_pgrp: ProcessId, pty_follower: PtyFollower, errpipe_rx: BinPipe, backchannel: &'a mut MonitorBackchannel, signal_stream: &'static SignalStream, _signal_handlers: [SignalHandler; MonitorClosure::SIGNALS.len()], } impl<'a> MonitorClosure<'a> { const SIGNALS: [SignalNumber; 8] = [ SIGINT, SIGQUIT, SIGTSTP, SIGTERM, SIGHUP, SIGUSR1, SIGUSR2, SIGCHLD, ]; fn new( command_pid: ProcessId, pty_follower: PtyFollower, errpipe_rx: BinPipe, backchannel: &'a mut MonitorBackchannel, registry: &mut EventRegistry, ) -> io::Result { // Store the pgid of the monitor. let monitor_pgrp = getpgrp(); // Register the callback to receive the IO error if the command fails to execute. registry.register_event(&errpipe_rx, PollEvent::Readable, |_| { MonitorEvent::ReadableErrPipe }); // Enable nonblocking assertions as we will poll this inside the event loop. backchannel.set_nonblocking_assertions(true); // Register the callback to receive events from the backchannel registry.register_event(backchannel, PollEvent::Readable, |_| { MonitorEvent::ReadableBackchannel }); let signal_stream = SignalStream::init()?; registry.register_event(signal_stream, PollEvent::Readable, |_| MonitorEvent::Signal); let signal_handlers = register_handlers(Self::SIGNALS)?; // Put the command in its own process group. let command_pgrp = command_pid; if let Err(err) = setpgid(command_pid, command_pgrp) { dev_warn!("cannot set process group ID for process: {err}"); }; Ok(Self { command_pid: Some(command_pid), command_pgrp, monitor_pgrp, pty_follower, errpipe_rx, backchannel, signal_stream, _signal_handlers: signal_handlers, }) } /// Based on `mon_backchannel_cb` fn read_backchannel(&mut self, registry: &mut EventRegistry) { match self.backchannel.recv() { Err(err) => { // We can try later if receive is interrupted. if err.kind() != io::ErrorKind::Interrupted { // There's something wrong with the backchannel, break the event loop. dev_warn!("cannot read from backchannel: {err}"); registry.set_break(err); } } Ok(event) => { match event { // We shouldn't receive this event more than once. MonitorMessage::ExecCommand => unreachable!(), // Forward signal to the command. MonitorMessage::Signal(signal) => { if let Some(command_pid) = self.command_pid { self.send_signal(signal, command_pid, true) } } } } } } fn read_errpipe(&mut self, registry: &mut EventRegistry) { match self.errpipe_rx.read() { Err(err) if was_interrupted(&err) => { /* Retry later */ } Err(err) => registry.set_break(err), Ok(error_code) => { // Received error code from the command, forward it to the parent. self.backchannel .send(&ParentMessage::IoError(error_code)) .ok(); } } } /// Send a signal to the command. fn send_signal(&self, signal: c_int, command_pid: ProcessId, from_parent: bool) { dev_info!( "sending {}{} to command", signal_fmt(signal), opt_fmt(from_parent, " from parent"), ); // FIXME: We should call `killpg` instead of `kill`. match signal { SIGALRM => { terminate_process(command_pid, false); } SIGCONT_FG => { // Continue with the command as the foreground process group if let Err(err) = self.pty_follower.tcsetpgrp(self.command_pgrp) { dev_error!( "cannot set the foreground process group to {} (command): {err}", self.command_pgrp ); } kill(command_pid, SIGCONT).ok(); } SIGCONT_BG => { // Continue with the monitor as the foreground process group if let Err(err) = self.pty_follower.tcsetpgrp(self.monitor_pgrp) { dev_error!( "cannot set the foreground process group to {} (monitor): {err}", self.monitor_pgrp ); } kill(command_pid, SIGCONT).ok(); } signal => { // Send the signal to the command. kill(command_pid, signal).ok(); } } } fn on_signal(&mut self, registry: &mut EventRegistry) { let info = match self.signal_stream.recv() { Ok(info) => info, Err(err) => { dev_error!("could not receive signal: {err}"); return; } }; dev_info!( "monitor received{} {} from {}", opt_fmt(info.is_user_signaled(), " user signaled"), info.signal(), info.pid() ); // Don't do anything if the command has terminated already let Some(command_pid) = self.command_pid else { dev_info!("command was terminated, ignoring signal"); return; }; match info.signal() { SIGCHLD => handle_sigchld(self, registry, "command", command_pid), // Skip the signal if it was sent by the user and it is self-terminating. _ if info.is_user_signaled() && is_self_terminating(info.pid(), command_pid, self.command_pgrp) => {} signal => self.send_signal(signal, command_pid, false), } } } /// Decides if the signal sent by the process with `signaler_pid` PID is self-terminating. /// /// A signal is self-terminating if `signaler_pid`: /// - is the same PID of the command, or /// - is in the process group of the command and the command is the leader. fn is_self_terminating( signaler_pid: ProcessId, command_pid: ProcessId, command_pgrp: ProcessId, ) -> bool { if signaler_pid != 0 { if signaler_pid == command_pid { return true; } if let Ok(grp_leader) = getpgid(signaler_pid) { if grp_leader == command_pgrp { return true; } } } false } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum MonitorEvent { Signal, ReadableErrPipe, ReadableBackchannel, } impl<'a> Process for MonitorClosure<'a> { type Event = MonitorEvent; type Break = io::Error; type Exit = CommandStatus; fn on_event(&mut self, event: Self::Event, registry: &mut EventRegistry) { match event { MonitorEvent::Signal => self.on_signal(registry), MonitorEvent::ReadableErrPipe => self.read_errpipe(registry), MonitorEvent::ReadableBackchannel => self.read_backchannel(registry), } } } impl<'a> HandleSigchld for MonitorClosure<'a> { const OPTIONS: WaitOptions = WaitOptions::new().untraced().no_hang(); fn on_exit(&mut self, exit_code: c_int, registry: &mut EventRegistry) { registry.set_exit(CommandStatus::Exit(exit_code)); self.command_pid = None; } fn on_term(&mut self, signal: c_int, registry: &mut EventRegistry) { registry.set_exit(CommandStatus::Term(signal)); self.command_pid = None; } fn on_stop(&mut self, signal: c_int, _registry: &mut EventRegistry) { // Save the foreground process group ID so we can restore it later. if let Ok(pgrp) = self.pty_follower.tcgetpgrp() { if pgrp != self.monitor_pgrp { self.command_pgrp = pgrp; } } self.backchannel .send(&CommandStatus::Stop(signal).into()) .ok(); } } sudo-rs-0.2.2/src/exec/use_pty/parent.rs000064400000000000000000000634571046102023000163020ustar 00000000000000use std::collections::VecDeque; use std::ffi::c_int; use std::io; use std::process::{Command, Stdio}; use crate::exec::event::{EventHandle, EventRegistry, PollEvent, Process, StopReason}; use crate::exec::use_pty::monitor::exec_monitor; use crate::exec::use_pty::SIGCONT_FG; use crate::exec::{ cond_fmt, handle_sigchld, opt_fmt, signal_fmt, terminate_process, ExecOutput, HandleSigchld, ProcessOutput, }; use crate::exec::{ io_util::retry_while_interrupted, use_pty::backchannel::{BackchannelPair, MonitorMessage, ParentBackchannel, ParentMessage}, ExitReason, }; use crate::log::{dev_error, dev_info, dev_warn}; use crate::system::signal::{ consts::*, register_handlers, SignalHandler, SignalHandlerBehavior, SignalNumber, SignalSet, SignalStream, }; use crate::system::term::{Pty, PtyFollower, PtyLeader, TermSize, Terminal, UserTerm}; use crate::system::wait::WaitOptions; use crate::system::{chown, fork, getpgrp, kill, killpg, FileCloser, ForkResult, Group, User}; use crate::system::{getpgid, interface::ProcessId}; use super::pipe::Pipe; use super::{CommandStatus, SIGCONT_BG}; pub(in crate::exec) fn exec_pty( sudo_pid: ProcessId, mut command: Command, user_tty: UserTerm, ) -> io::Result { // Allocate a pseudoterminal. let pty = get_pty()?; // Create backchannels to communicate with the monitor. let mut backchannels = BackchannelPair::new().map_err(|err| { dev_error!("cannot create backchannel: {err}"); err })?; // We don't want to receive SIGTTIN/SIGTTOU match SignalHandler::register(SIGTTIN, SignalHandlerBehavior::Ignore) { Ok(handler) => handler.forget(), Err(err) => dev_warn!("cannot set handler for SIGTTIN: {err}"), } match SignalHandler::register(SIGTTOU, SignalHandlerBehavior::Ignore) { Ok(handler) => handler.forget(), Err(err) => dev_warn!("cannot set handler for SIGTTOU: {err}"), } // FIXME (ogsudo): Initialize the policy plugin's session here by calling // `policy_init_session`. // FIXME (ogsudo): initializes ttyblock sigset here by calling `init_ttyblock` // Fetch the parent process group so we can signals to it. let parent_pgrp = getpgrp(); let mut file_closer = FileCloser::new(); // Set all the IO streams for the command to the follower side of the pty. let mut clone_follower = || -> io::Result { let follower = pty.follower.try_clone().map_err(|err| { dev_error!("cannot clone pty follower: {err}"); err })?; // Don't close these as we will need them so they are dupped inside `Command::exec`. file_closer.except(&follower); Ok(follower) }; command.stdin(clone_follower()?); command.stdout(clone_follower()?); command.stderr(clone_follower()?); let mut registry = EventRegistry::::new(); // Pipe data between both terminals let mut tty_pipe = Pipe::new( user_tty, pty.leader, &mut registry, ParentEvent::Tty, ParentEvent::Pty, ); let user_tty = tty_pipe.left_mut(); // Check if we are the foreground process let mut foreground = user_tty .tcgetpgrp() .is_ok_and(|tty_pgrp| tty_pgrp == parent_pgrp); dev_info!( "sudo is runnning in the {}", cond_fmt(foreground, "foreground", "background") ); // FIXME: maybe all these boolean flags should be on a dedicated type. // Whether we're running on a pipeline let mut pipeline = false; // Whether the command should be executed in the background (this is not the `-b` flag) let mut exec_bg = false; // Whether the user's terminal is in raw mode or not. let mut term_raw = false; // Check if we are part of a pipeline. // FIXME: Here's where we should intercept the IO streams if we want to implement IO logging. // FIXME: ogsudo creates pipes for the IO streams and uses events to read from the strams to // the pipes. Investigate why. if !io::stdin().is_terminal() { dev_info!("stdin is not a terminal, command will inherit it"); pipeline = true; command.stdin(Stdio::inherit()); if foreground && parent_pgrp != sudo_pid { // If sudo is not the process group leader and stdin is not a terminal we might be // running as a background job via a shell script. Starting in the foreground would // change the terminal mode. exec_bg = true; } } if !io::stdout().is_terminal() { dev_info!("stdout is not a terminal, command will inherit it"); pipeline = true; command.stdout(Stdio::inherit()); } if !io::stderr().is_terminal() { dev_info!("stderr is not a terminal, command will inherit it"); command.stderr(Stdio::inherit()); } // Copy terminal settings from `/dev/tty` to the pty. if let Err(err) = user_tty.copy_to(&pty.follower) { dev_error!("cannot copy terminal settings to pty: {err}"); foreground = false; } // Start in raw mode unless we're part of a pipeline or backgrounded. if foreground && !pipeline && !exec_bg && user_tty.set_raw_mode(false).is_ok() { term_raw = true; } let tty_size = tty_pipe.left().get_size().map_err(|err| { dev_error!("cannot get terminal size: {err}"); err })?; // Block all the signals until we are done setting up the signal handlers so we don't miss // SIGCHLD. let original_set = match SignalSet::full().and_then(|set| set.block()) { Ok(original_set) => Some(original_set), Err(err) => { dev_warn!("cannot block signals: {err}"); None } }; let ForkResult::Parent(monitor_pid) = fork().map_err(|err| { dev_error!("cannot fork monitor process: {err}"); err })? else { // Close the file descriptors that we don't access drop(tty_pipe); drop(backchannels.parent); // If `exec_monitor` returns, it means we failed to execute the command somehow. match exec_monitor( pty.follower, command, foreground && !pipeline && !exec_bg, &mut backchannels.monitor, file_closer, original_set, ) { Ok(exec_output) => return Ok(exec_output), Err(err) => { // Disable nonblocking assetions as we will not poll the backchannel anymore. backchannels.monitor.set_nonblocking_assertions(true); match err.try_into() { Ok(msg) => { if let Err(err) = backchannels.monitor.send(&msg) { dev_error!("cannot send status to parent: {err}"); } } Err(err) => { dev_warn!("execution error {err:?} cannot be send over backchannel") } } } } return Ok(ProcessOutput::ChildExit); }; // Close the file descriptors that we don't access drop(pty.follower); drop(backchannels.monitor); // Send green light to the monitor after closing the follower. retry_while_interrupted(|| backchannels.parent.send(&MonitorMessage::ExecCommand)).map_err( |err| { dev_error!("cannot send green light to monitor: {err}"); err }, )?; let mut closure = ParentClosure::new( monitor_pid, sudo_pid, parent_pgrp, backchannels.parent, tty_pipe, tty_size, foreground, term_raw, &mut registry, )?; // Restore the signal mask now that the handlers have been setup. if let Some(set) = original_set { if let Err(err) = set.set_mask() { dev_warn!("cannot restore signal mask: {err}"); } } let exit_reason = closure.run(&mut registry); // FIXME (ogsudo): Retry if `/dev/tty` is revoked. // Flush the terminal closure.tty_pipe.flush_left().ok(); // Restore the terminal settings if closure.term_raw { // Only restore the terminal if sudo is the foreground process. if let Ok(pgrp) = closure.tty_pipe.left().tcgetpgrp() { if pgrp == closure.parent_pgrp { match closure.tty_pipe.left_mut().restore(false) { Ok(()) => closure.term_raw = false, Err(err) => dev_warn!("cannot restore terminal settings: {err}"), } } } } Ok(ProcessOutput::SudoExit { output: ExecOutput { command_exit_reason: exit_reason?, restore_signal_handlers: Box::new(move || drop(closure.signal_handlers)), }, }) } fn get_pty() -> io::Result { let tty_gid = Group::from_name(cstr!("tty")) .unwrap_or(None) .map(|group| group.gid); let pty = Pty::open().map_err(|err| { dev_error!("cannot allocate pty: {err}"); io::Error::new(io::ErrorKind::NotFound, "unable to open pty") })?; let euid = User::effective_uid(); let gid = tty_gid.unwrap_or(User::effective_gid()); chown(&pty.path, euid, gid).map_err(|err| { dev_error!("cannot change owner for pty: {err}"); err })?; Ok(pty) } struct ParentClosure { // The monitor PID. // /// This is `Some` iff the process is still running. monitor_pid: Option, sudo_pid: ProcessId, parent_pgrp: ProcessId, command_pid: Option, tty_pipe: Pipe, tty_size: TermSize, foreground: bool, term_raw: bool, backchannel: ParentBackchannel, message_queue: VecDeque, backchannel_write_handle: EventHandle, signal_stream: &'static SignalStream, signal_handlers: [SignalHandler; ParentClosure::SIGNALS.len()], } impl ParentClosure { const SIGNALS: [SignalNumber; 11] = [ SIGINT, SIGQUIT, SIGTSTP, SIGTERM, SIGHUP, SIGALRM, SIGUSR1, SIGUSR2, SIGCHLD, SIGCONT, SIGWINCH, ]; #[allow(clippy::too_many_arguments)] fn new( monitor_pid: ProcessId, sudo_pid: ProcessId, parent_pgrp: ProcessId, mut backchannel: ParentBackchannel, tty_pipe: Pipe, tty_size: TermSize, foreground: bool, term_raw: bool, registry: &mut EventRegistry, ) -> io::Result { // Enable nonblocking assertions as we will poll this inside the event loop. backchannel.set_nonblocking_asserts(true); registry.register_event(&backchannel, PollEvent::Readable, ParentEvent::Backchannel); let mut backchannel_write_handle = registry.register_event(&backchannel, PollEvent::Writable, ParentEvent::Backchannel); // Ignore write events on the backchannel as we don't want to poll it for writing if there // are no messages in the queue. backchannel_write_handle.ignore(registry); let signal_stream = SignalStream::init()?; registry.register_event(signal_stream, PollEvent::Readable, |_| ParentEvent::Signal); let signal_handlers = register_handlers(Self::SIGNALS)?; Ok(Self { monitor_pid: Some(monitor_pid), sudo_pid, parent_pgrp, command_pid: None, tty_pipe, tty_size, foreground, term_raw, backchannel, message_queue: VecDeque::new(), backchannel_write_handle, signal_stream, signal_handlers, }) } fn run(&mut self, registry: &mut EventRegistry) -> io::Result { match registry.event_loop(self) { StopReason::Break(err) | StopReason::Exit(ParentExit::Backchannel(err)) => Err(err), StopReason::Exit(ParentExit::Command(exit_reason)) => Ok(exit_reason), } } /// Read an event from the backchannel and return the event if it should break the event loop. fn on_message_received(&mut self, registry: &mut EventRegistry) { match self.backchannel.recv() { Err(err) => { match err.kind() { // If we get EOF the monitor exited or was killed io::ErrorKind::UnexpectedEof => { dev_info!("received EOF from backchannel"); registry.set_exit(err.into()); } // We can try later if receive is interrupted. io::ErrorKind::Interrupted => {} // Failed to read command status. This means that something is wrong with the socket // and we should stop. _ => { dev_error!("cannot receive message from backchannel: {err}"); if !registry.got_break() { registry.set_break(err); } } } } Ok(event) => { match event { // Received the PID of the command. This means that the command is already // executing. ParentMessage::CommandPid(pid) => { dev_info!("received command PID ({pid}) from monitor"); self.command_pid = pid.into(); } ParentMessage::CommandStatus(status) => { // The command terminated or the monitor was not able to spawn it. We should stop // either way. match status { CommandStatus::Exit(exit_code) => { dev_info!("command exited with status code {exit_code}"); registry.set_exit(ExitReason::Code(exit_code).into()); } CommandStatus::Term(signal) => { dev_info!("command was terminated by {}", signal_fmt(signal)); registry.set_exit(ExitReason::Signal(signal).into()); } CommandStatus::Stop(signal) => { dev_info!( "command was stopped by {}, suspending parent", signal_fmt(signal) ); // Suspend parent and tell monitor how to resume on return if let Some(signal) = self.suspend_pty(signal, registry) { self.schedule_signal(signal, registry); } self.tty_pipe.resume_events(registry); } } } ParentMessage::IoError(code) => { let err = io::Error::from_raw_os_error(code); dev_info!("received error ({code}) for monitor: {err}"); registry.set_break(err); } ParentMessage::ShortRead => { dev_info!("received short read error for monitor"); registry.set_break(io::ErrorKind::UnexpectedEof.into()); } } } } } /// Decides if the signal sent by the process with `signaler_pid` PID is self-terminating. /// /// A signal is self-terminating if `signaler_pid`: /// - is the same PID of the command, or /// - is in the process group of the command and either sudo or the command is the leader. fn is_self_terminating(&self, signaler_pid: ProcessId) -> bool { if signaler_pid != 0 { if Some(signaler_pid) == self.command_pid { return true; } if let Ok(signaler_pgrp) = getpgid(signaler_pid) { if Some(signaler_pgrp) == self.command_pid || signaler_pgrp == self.sudo_pid { return true; } } } false } /// Schedule sending a signal event to the monitor using the backchannel. /// /// The signal message will be sent once the backchannel is ready to be written. fn schedule_signal(&mut self, signal: c_int, registry: &mut EventRegistry) { dev_info!("scheduling message with {} for monitor", signal_fmt(signal)); self.message_queue.push_back(MonitorMessage::Signal(signal)); // Start polling the backchannel for writing if not already. self.backchannel_write_handle.resume(registry); } /// Send the first message in the event queue using the backchannel, if any. /// /// Calling this function will block until the backchannel can be written. fn check_message_queue(&mut self, registry: &mut EventRegistry) { if let Some(msg) = self.message_queue.front() { dev_info!("sending message {msg:?} to monitor over backchannel"); match self.backchannel.send(msg) { // The event was sent, remove it from the queue Ok(()) => { self.message_queue.pop_front().unwrap(); // Stop polling the backchannel for writing if the queue is empty. if self.message_queue.is_empty() { self.backchannel_write_handle.ignore(registry); } } Err(err) => { // We can try later if send is interrupted. if err.kind() != io::ErrorKind::Interrupted { // There's something wrong with the backchannel, break the event loop. dev_error!("cannot send via backchannel {err}"); registry.set_break(err); } } } } } /// Suspend sudo if the command is suspended. /// /// Return `SIGCONT_FG` or `SIGCONT_BG` to state whether the command should be resumend in the /// foreground or not. fn suspend_pty( &mut self, signal: SignalNumber, registry: &mut EventRegistry, ) -> Option { // Ignore `SIGCONT` while suspending to avoid resuming the terminal twice. let sigcont_handler = SignalHandler::register(SIGCONT, SignalHandlerBehavior::Ignore) .map_err(|err| dev_warn!("cannot set handler for SIGCONT: {err}")) .ok(); if let SIGTTOU | SIGTTIN = signal { // If sudo is already the foreground process we can resume the command in the // foreground. Otherwise, we have to suspend and resume later. if !self.foreground && self.check_foreground().is_err() { // User's tty was revoked. return None; } if self.foreground { dev_info!( "command received {}, parent running in the foreground", signal_fmt(signal) ); if !self.term_raw { if self.tty_pipe.left_mut().set_raw_mode(false).is_ok() { self.term_raw = true; } // Resume command in the foreground return Some(SIGCONT_FG); } } } // Stop polling the terminals. self.tty_pipe.ignore_events(registry); if self.term_raw { match self.tty_pipe.left_mut().restore(false) { Ok(()) => self.term_raw = false, Err(err) => dev_warn!("cannot restore terminal settings: {err}"), } } let signal_handler = if signal != SIGSTOP { SignalHandler::register(signal, SignalHandlerBehavior::Default) .map_err(|err| dev_warn!("cannot set handler for {}: {err}", signal_fmt(signal))) .ok() } else { None }; if self.parent_pgrp != self.sudo_pid && kill(self.parent_pgrp, 0).is_err() || killpg(self.parent_pgrp, signal).is_err() { dev_error!("no parent to suspend, terminating command"); if let Some(command_pid) = self.command_pid.take() { terminate_process(command_pid, true); } } drop(signal_handler); if self.command_pid.is_none() || self.resume_terminal().is_err() { return None; } let ret_signal = if self.term_raw { SIGCONT_FG } else { SIGCONT_BG }; // Restore the handler for SIGCONT. drop(sigcont_handler); Some(ret_signal) } /// Check whether we are part of the foreground process group and update the foreground flag. fn check_foreground(&mut self) -> io::Result<()> { let pgrp = self.tty_pipe.left().tcgetpgrp()?; self.foreground = pgrp == self.parent_pgrp; Ok(()) } /// Restore the terminal when sudo resumes after receving `SIGCONT`. fn resume_terminal(&mut self) -> io::Result<()> { self.check_foreground()?; // Update the pty settings based on the user's tty. self.tty_pipe .left() .copy_to(self.tty_pipe.right()) .map_err(|err| { dev_error!("cannot copy terminal settings to pty: {err}"); err })?; // FIXME: sync the terminal size here. dev_info!( "parent is in {} ({} -> {})", cond_fmt(self.foreground, "foreground", "background"), cond_fmt(self.term_raw, "raw", "cooked"), cond_fmt(self.foreground, "raw", "cooked"), ); if self.foreground { // We're in the foreground, set tty to raw mode. if self.tty_pipe.left_mut().set_raw_mode(false).is_ok() { self.term_raw = true; } } else { // We're in the background, cannot access tty. self.term_raw = false; } Ok(()) } fn on_signal(&mut self, registry: &mut EventRegistry) { let info = match self.signal_stream.recv() { Ok(info) => info, Err(err) => { dev_error!("parent could not receive signal: {err}"); return; } }; dev_info!( "parent received{} {} from {}", opt_fmt(info.is_user_signaled(), " user signaled"), info.signal(), info.pid() ); let Some(monitor_pid) = self.monitor_pid else { dev_info!("monitor was terminated, ignoring signal"); return; }; match info.signal() { SIGCHLD => handle_sigchld(self, registry, "monitor", monitor_pid), SIGCONT => { self.resume_terminal().ok(); } SIGWINCH => { if let Err(err) = self.handle_sigwinch() { dev_warn!("cannot resize terminal: {}", err); } } // Skip the signal if it was sent by the user and it is self-terminating. _ if info.is_user_signaled() && self.is_self_terminating(info.pid()) => {} // FIXME: check `send_command_status` signal => self.schedule_signal(signal, registry), } } fn handle_sigwinch(&mut self) -> io::Result<()> { let new_size = self.tty_pipe.left().get_size()?; if new_size != self.tty_size { dev_info!("updating pty size from {} to {new_size}", self.tty_size); // Set the pty size. self.tty_pipe.right().set_size(&new_size)?; // Send SIGWINCH to the command. if let Some(command_pid) = self.command_pid { killpg(command_pid, SIGWINCH).ok(); } // Update the terminal size. self.tty_size = new_size; } Ok(()) } } enum ParentExit { /// Error while reading from the backchannel. Backchannel(io::Error), /// The command exited. Command(ExitReason), } impl From for ParentExit { fn from(err: io::Error) -> Self { Self::Backchannel(err) } } impl From for ParentExit { fn from(reason: ExitReason) -> Self { Self::Command(reason) } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum ParentEvent { Signal, Tty(PollEvent), Pty(PollEvent), Backchannel(PollEvent), } impl Process for ParentClosure { type Event = ParentEvent; type Break = io::Error; type Exit = ParentExit; fn on_event(&mut self, event: Self::Event, registry: &mut EventRegistry) { match event { ParentEvent::Signal => self.on_signal(registry), ParentEvent::Tty(poll_event) => { self.tty_pipe.on_left_event(poll_event, registry).ok(); } ParentEvent::Pty(poll_event) => { self.tty_pipe.on_right_event(poll_event, registry).ok(); } ParentEvent::Backchannel(poll_event) => match poll_event { PollEvent::Readable => self.on_message_received(registry), PollEvent::Writable => self.check_message_queue(registry), }, } } } impl HandleSigchld for ParentClosure { const OPTIONS: WaitOptions = WaitOptions::new().all().untraced().no_hang(); fn on_exit(&mut self, _exit_code: c_int, _registry: &mut EventRegistry) { self.monitor_pid = None; } fn on_term(&mut self, _signal: SignalNumber, _registry: &mut EventRegistry) { self.monitor_pid = None; } fn on_stop(&mut self, signal: SignalNumber, registry: &mut EventRegistry) { if let Some(signal) = self.suspend_pty(signal, registry) { self.schedule_signal(signal, registry); } self.tty_pipe.resume_events(registry); } } sudo-rs-0.2.2/src/exec/use_pty/pipe/mod.rs000064400000000000000000000136671046102023000165230ustar 00000000000000mod ring_buffer; use std::{ io::{self, Read, Write}, marker::PhantomData, os::fd::AsRawFd, }; use crate::exec::event::{EventHandle, EventRegistry, PollEvent, Process}; use self::ring_buffer::RingBuffer; // A pipe able to stream data bidirectionally between two read-write types. pub(super) struct Pipe { left: L, right: R, buffer_lr: Buffer, buffer_rl: Buffer, } impl Pipe { /// Create a new pipe between two read-write types and register them to be polled. pub fn new( left: L, right: R, registry: &mut EventRegistry, f_left: fn(PollEvent) -> T::Event, f_right: fn(PollEvent) -> T::Event, ) -> Self { Self { buffer_lr: Buffer::new( registry.register_event(&left, PollEvent::Readable, f_left), registry.register_event(&right, PollEvent::Writable, f_right), registry, ), buffer_rl: Buffer::new( registry.register_event(&right, PollEvent::Readable, f_right), registry.register_event(&left, PollEvent::Writable, f_left), registry, ), left, right, } } /// Get a reference to the left side of the pipe. pub(super) fn left(&self) -> &L { &self.left } /// Get a mutable reference to the left side of the pipe. pub(super) fn left_mut(&mut self) -> &mut L { &mut self.left } /// Get a reference to the right side of the pipe. pub(super) fn right(&self) -> &R { &self.right } /// Stop the poll events of this pipe. pub(super) fn ignore_events(&mut self, registry: &mut EventRegistry) { self.buffer_lr.read_handle.ignore(registry); self.buffer_lr.write_handle.ignore(registry); self.buffer_rl.read_handle.ignore(registry); self.buffer_rl.write_handle.ignore(registry); } /// Resume the poll events of this pipe pub(super) fn resume_events(&mut self, registry: &mut EventRegistry) { self.buffer_lr.read_handle.resume(registry); self.buffer_lr.write_handle.resume(registry); self.buffer_rl.read_handle.resume(registry); self.buffer_rl.write_handle.resume(registry); } /// Handle a poll event for the left side of the pipe. pub(super) fn on_left_event( &mut self, poll_event: PollEvent, registry: &mut EventRegistry, ) -> io::Result<()> { match poll_event { PollEvent::Readable => self.buffer_lr.read(&mut self.left, registry), PollEvent::Writable => self.buffer_rl.write(&mut self.left, registry), } } /// Handle a poll event for the right side of the pipe. pub(super) fn on_right_event( &mut self, poll_event: PollEvent, registry: &mut EventRegistry, ) -> io::Result<()> { match poll_event { PollEvent::Readable => self.buffer_rl.read(&mut self.right, registry), PollEvent::Writable => self.buffer_lr.write(&mut self.right, registry), } } /// Ensure that all the contents of the pipe's internal buffer are written to the left side. pub(super) fn flush_left(&mut self) -> io::Result<()> { self.buffer_rl.flush(&mut self.left) } } /// A buffer that stores the bytes read from `R` before they are written to `W`. struct Buffer { internal: RingBuffer, /// The handle for the event of the reader. read_handle: EventHandle, /// The handle for the event of the writer. write_handle: EventHandle, marker: PhantomData<(R, W)>, } impl Buffer { /// Create a new, empty buffer fn new( read_handle: EventHandle, mut write_handle: EventHandle, registry: &mut EventRegistry, ) -> Self { // The buffer is empty, don't write write_handle.ignore(registry); Self { internal: RingBuffer::new(), read_handle, write_handle, marker: PhantomData, } } /// Read bytes into the buffer. /// /// Calling this function will block until `read` is ready to be read. fn read( &mut self, read: &mut R, registry: &mut EventRegistry, ) -> io::Result<()> { // If the buffer is full, there is nothing to be read. if self.internal.is_full() { self.read_handle.ignore(registry); return Ok(()); } // Read bytes and insert them into the buffer. let inserted_len = self.internal.insert(read)?; // If we inserted something, the buffer is not empty anymore and we can resume writing. if inserted_len > 0 { self.write_handle.resume(registry); } Ok(()) } /// Write bytes from the buffer. /// /// Calling this function will block until `write` is ready to be written. fn write( &mut self, write: &mut W, registry: &mut EventRegistry, ) -> io::Result<()> { // If the buffer is empty, there is nothing to be written. if self.internal.is_empty() { self.write_handle.ignore(registry); return Ok(()); } // Remove bytes from the buffer and write them. let removed_len = self.internal.remove(write)?; // If we removed something, the buffer is not full anymore and we can resume reading. if removed_len > 0 { self.read_handle.resume(registry); } Ok(()) } /// Flush this buffer, ensuring that all the contents of its internal buffer are written. fn flush(&mut self, write: &mut W) -> io::Result<()> { // Remove bytes from the buffer and write them. self.internal.remove(write)?; write.flush() } } sudo-rs-0.2.2/src/exec/use_pty/pipe/ring_buffer.rs000064400000000000000000000251021046102023000202170ustar 00000000000000use std::io::{self, IoSlice, IoSliceMut, Read, Write}; pub(super) struct RingBuffer { storage: Box<[u8; Self::LEN]>, // The start index of the non-empty section of the buffer. start: usize, // The length of the non-empty section of the buffer. len: usize, } impl RingBuffer { /// The size of the internal storage of the ring buffer. const LEN: usize = 8 * 1024; /// Create a new, empty buffer. pub(super) fn new() -> Self { Self { storage: Box::new([0; Self::LEN]), start: 0, len: 0, } } pub(super) fn is_full(&self) -> bool { self.len == self.storage.len() } pub(super) fn insert(&mut self, read: &mut R) -> io::Result { let inserted_len = if self.is_empty() { // Case 1.1. The buffer is empty, meaning that there are two unfilled slices in // `storage`:`start..` and `..start`. let (second_slice, first_slice) = self.storage.split_at_mut(self.start); read.read_vectored(&mut [first_slice, second_slice].map(IoSliceMut::new))? } else { let &mut Self { start, len, .. } = self; let end = start + len; if end >= self.storage.len() { // Case 1.2. The buffer is not empty and the filled section wraps around `storage`. // Meaning that there is only one unfilled slice in `storage`: `end..start`. let end = end % self.storage.len(); read.read(&mut self.storage[end..start])? } else { // Case 1.3. The buffer is not empty and the filled section is a contiguous slice // of `storage`. Meaning that there are two unfilled slices in `storage`: `..start` // and `end..`. let (mid, first_slice) = self.storage.split_at_mut(end); let second_slice = &mut mid[..start]; read.read_vectored(&mut [first_slice, second_slice].map(IoSliceMut::new))? } }; self.len += inserted_len; debug_assert!(self.start < Self::LEN); debug_assert!(self.len <= Self::LEN); Ok(inserted_len) } pub(super) fn is_empty(&self) -> bool { self.len == 0 } pub(super) fn remove(&mut self, write: &mut W) -> io::Result { let removed_len = if self.is_full() { // Case 2.1. The buffer is full, meaning that there are two filled slices in `storage`: // `start..` and `..start`. let (second_slice, first_slice) = self.storage.split_at(self.start); write.write_vectored(&[first_slice, second_slice].map(IoSlice::new))? } else { let end = self.start + self.len; if end >= self.storage.len() { // Case 2.2. The buffer is not full and the filled section wraps around `storage`. // Meaning that there are two non-empty slices in `storage`: `start..` and `..end`. let end = end % self.storage.len(); let first_slice = &self.storage[self.start..]; let second_slice = &self.storage[..end]; write.write_vectored(&[first_slice, second_slice].map(IoSlice::new))? } else { // Case 2.3. The buffer is not full and the filled section is a contiguous slice // of `storage.` Meaning that there is only one filled slice in `storage`: // `start..end`. write.write(&self.storage[self.start..end])? } }; self.start += removed_len; self.start %= Self::LEN; self.len -= removed_len; debug_assert!(self.start < Self::LEN); debug_assert!(self.len <= Self::LEN); Ok(removed_len) } } #[cfg(test)] mod tests { use super::RingBuffer; #[test] fn empty_buffer_is_empty() { let buf = RingBuffer::new(); assert!(buf.is_empty()); } #[test] fn full_buffer_is_full() { let mut buf = RingBuffer::new(); let inserted_len = buf.insert(&mut [0x45; RingBuffer::LEN].as_slice()).unwrap(); assert_eq!(inserted_len, RingBuffer::LEN); assert!(buf.is_full()); } #[test] fn buffer_is_fifo() { let mut buf = RingBuffer::new(); let expected = (0..=u8::MAX).collect::>(); let inserted_len = buf.insert(&mut expected.as_slice()).unwrap(); assert_eq!(inserted_len, expected.len()); let mut found = vec![]; let removed_len = buf.remove(&mut found).unwrap(); assert_eq!(removed_len, expected.len()); assert_eq!(expected, found); } #[test] fn insert_into_empty_buffer_with_offset() { const HALF_LEN: usize = RingBuffer::LEN / 2; let mut buf = RingBuffer::new(); // This should leave the buffer empty but with the start field pointing to the middle of // the buffer. // ┌───────────────────┠// │ │ // └───────────────────┘ // â–² // │ // start buf.insert(&mut [0u8; HALF_LEN].as_slice()).unwrap(); buf.remove(&mut vec![]).unwrap(); assert_eq!(buf.start, HALF_LEN); assert_eq!(buf.len, 0); // Then we fill the first half of the buffer with ones and the second one with twos in a // single insertion. This tests case 1.1. // ┌─────────┬─────────┠// │ 2 │ 1 │ // └─────────┴─────────┘ // â–² // │ // start let mut expected = vec![1; HALF_LEN]; expected.extend_from_slice(&[2; HALF_LEN]); buf.insert(&mut expected.as_slice()).unwrap(); assert_eq!(buf.start, HALF_LEN); assert_eq!(buf.len, RingBuffer::LEN); // When we remove all the elements of the buffer we should find them in the same order we // inserted them. This tests case 2.1. let mut found = vec![]; let removed_len = buf.remove(&mut found).unwrap(); assert_eq!(removed_len, expected.len()); assert_eq!(expected, found); assert_eq!(buf.start, HALF_LEN); assert_eq!(buf.len, 0); } #[test] fn insert_into_non_empty_wrapping_buffer() { const QUARTER_LEN: usize = RingBuffer::LEN / 4; let mut buf = RingBuffer::new(); // This should leave the buffer empty but with the start field pointing to the middle of // the buffer. // ┌───────────────────────┠// │ │ // └───────────────────────┘ // â–² // │ // start buf.insert(&mut [0; 2 * QUARTER_LEN].as_slice()).unwrap(); buf.remove(&mut vec![]).unwrap(); assert_eq!(buf.start, 2 * QUARTER_LEN); assert_eq!(buf.len, 0); // Then we fill one quarter of the buffer with ones. This gives us a non-empty buffer whose // empty section is not contiguous. // ┌───────────┬─────┬─────┠// │ │ 1 │ │ // └───────────┴─────┴─────┘ // â–² // │ // start let mut expected = vec![1; QUARTER_LEN]; buf.insert(&mut expected.as_slice()).unwrap(); assert_eq!(buf.start, 2 * QUARTER_LEN); assert_eq!(buf.len, QUARTER_LEN); // Then we fill one quarter of the buffer with twos and another quarter of the buffer with // threes in a single insertion. This tests case 1.2. // ┌─────┬─────┬─────┬─────┠// │ 3 │ │ 1 │ 2 │ // └─────┴─────┴─────┴─────┘ // â–² // │ // start let mut second_half = vec![2; QUARTER_LEN]; second_half.extend_from_slice(&[3; QUARTER_LEN]); buf.insert(&mut second_half.as_slice()).unwrap(); expected.extend(second_half); assert_eq!(buf.start, 2 * QUARTER_LEN); assert_eq!(buf.len, 3 * QUARTER_LEN); // When we remove all the elements of the buffer we should find them in the same order we // inserted them. This tests case 2.2. let mut found = vec![]; let removed_len = buf.remove(&mut found).unwrap(); assert_eq!(removed_len, expected.len()); assert_eq!(expected, found); assert_eq!(buf.start, QUARTER_LEN); assert_eq!(buf.len, 0); } #[test] fn insert_into_non_empty_non_wrapping_buffer() { const QUARTER_LEN: usize = RingBuffer::LEN / 4; let mut buf = RingBuffer::new(); // We fill one quarter of the buffer with ones. This gives us a non-empty buffer whose // empty section is contiguous. // ┌─────┬────────────────┠// │ 1 │ │ // └─────┴────────────────┘ // â–² // │ // â”” start let mut expected = vec![1; QUARTER_LEN]; buf.insert(&mut expected.as_slice()).unwrap(); assert_eq!(buf.start, 0); assert_eq!(buf.len, QUARTER_LEN); // Then we fill one quarter of the buffer with twos. This tests case 1.3. // ┌─────┬─────┬──────────┠// │ 1 │ 2 │ │ // └─────┴─────┴──────────┘ // â–² // │ // â”” start let second_half = vec![2; QUARTER_LEN]; buf.insert(&mut second_half.as_slice()).unwrap(); expected.extend(second_half); assert_eq!(buf.start, 0); assert_eq!(buf.len, 2 * QUARTER_LEN); // When we remove all the elements of the buffer we should find them in the same order we // inserted them. This tests case 2.3. let mut found = vec![]; let removed_len = buf.remove(&mut found).unwrap(); assert_eq!(removed_len, expected.len()); assert_eq!(expected, found); assert_eq!(buf.start, 2 * QUARTER_LEN); assert_eq!(buf.len, 0); } } sudo-rs-0.2.2/src/lib.rs000064400000000000000000000005171046102023000131270ustar 00000000000000#[macro_use] mod macros; pub(crate) mod common; pub(crate) mod cutils; pub(crate) mod defaults; pub(crate) mod exec; pub(crate) mod log; pub(crate) mod pam; pub(crate) mod sudoers; pub(crate) mod system; mod su; mod sudo; mod visudo; pub use su::main as su_main; pub use sudo::main as sudo_main; pub use visudo::main as visudo_main; sudo-rs-0.2.2/src/log/mod.rs000064400000000000000000000112351046102023000137200ustar 00000000000000#![allow(unused_macros)] use self::simple_logger::SimpleLogger; use self::syslog::Syslog; pub use log::Level; use std::ops::Deref; mod simple_logger; mod syslog; // TODO: logger_macro has an allow_unused that should be removed macro_rules! logger_macro { ($name:ident is $rule_level:ident to $target:expr, $d:tt) => { macro_rules! $name { ($d($d arg:tt)+) => (::log::log!(target: $target, $crate::log::Level::$rule_level, $d($d arg)+)); } #[allow(unused)] pub(crate) use $name; }; ($name:ident is $rule_level:ident to $target:expr) => { logger_macro!($name is $rule_level to $target, $); }; } logger_macro!(auth_error is Error to "sudo::auth"); logger_macro!(auth_warn is Warn to "sudo::auth"); logger_macro!(auth_info is Info to "sudo::auth"); logger_macro!(auth_debug is Debug to "sudo::auth"); logger_macro!(auth_trace is Trace to "sudo::auth"); logger_macro!(user_error is Error to "sudo::user"); logger_macro!(user_warn is Warn to "sudo::user"); logger_macro!(user_info is Info to "sudo::user"); logger_macro!(user_debug is Debug to "sudo::user"); logger_macro!(user_trace is Trace to "sudo::user"); // TODO: dev_logger_macro has an allow_unused that should be removed macro_rules! dev_logger_macro { ($name:ident is $rule_level:ident to $target:expr, $d:tt) => { macro_rules! $name { ($d($d arg:tt)+) => { if std::cfg!(feature = "dev") { (::log::log!( target: $target, $crate::log::Level::$rule_level, "{}: {}", std::panic::Location::caller(), format_args!($d($d arg)+) )); } }; } #[allow(unused)] pub(crate) use $name; }; ($name:ident is $rule_level:ident to $target:expr) => { dev_logger_macro!($name is $rule_level to $target, $); }; } dev_logger_macro!(dev_error is Error to "sudo::dev"); dev_logger_macro!(dev_warn is Warn to "sudo::dev"); dev_logger_macro!(dev_info is Info to "sudo::dev"); dev_logger_macro!(dev_debug is Debug to "sudo::dev"); dev_logger_macro!(dev_trace is Trace to "sudo::dev"); #[derive(Default)] pub struct SudoLogger(Vec<(String, Box)>); impl SudoLogger { pub fn new(prefix: &'static str) -> Self { let mut logger: Self = Default::default(); logger.add_logger("sudo::auth", Syslog); logger.add_logger("sudo::user", SimpleLogger::to_stderr(prefix)); #[cfg(feature = "dev")] { let path = option_env!("SUDO_DEV_LOGS") .map(|s| s.into()) .unwrap_or_else(|| { std::env::temp_dir().join(format!("sudo-dev-{}.log", std::process::id())) }); logger.add_logger("sudo::dev", SimpleLogger::to_file(path, "").unwrap()); } logger } pub fn into_global_logger(self) { log::set_boxed_logger(Box::new(self)) .map(|()| log::set_max_level(log::LevelFilter::Trace)) .expect("Could not set previously set logger"); } /// Add a logger for a specific prefix to the stack fn add_logger( &mut self, prefix: impl ToString + Deref, logger: impl log::Log + 'static, ) { self.add_boxed_logger(prefix, Box::new(logger)) } /// Add a boxed logger for a specific prefix to the stack fn add_boxed_logger( &mut self, prefix: impl ToString + Deref, logger: Box, ) { let prefix = if prefix.ends_with("::") { prefix.to_string() } else { // given a prefix `my::prefix`, we want to match `my::prefix::somewhere` // but not `my::prefix_to_somewhere` format!("{}::", prefix.to_string()) }; self.0.push((prefix, logger)) } } impl log::Log for SudoLogger { fn enabled(&self, metadata: &log::Metadata) -> bool { self.0.iter().any(|(_, l)| l.enabled(metadata)) } fn log(&self, record: &log::Record) { for (prefix, l) in self.0.iter() { if record.target() == &prefix[..prefix.len() - 2] || record.target().starts_with(prefix) { l.log(record); } } } fn flush(&self) { for (_, l) in self.0.iter() { l.flush(); } } } #[cfg(test)] mod tests { use super::SudoLogger; #[test] fn can_construct_logger() { let logger = SudoLogger::new("sudo: "); let len = if cfg!(feature = "dev") { 3 } else { 2 }; assert_eq!(logger.0.len(), len); } } sudo-rs-0.2.2/src/log/simple_logger.rs000064400000000000000000000055741046102023000160020ustar 00000000000000use std::io::Write; #[cfg(feature = "dev")] use std::{fs::File, path::Path}; use log::Log; pub struct SimpleLogger where for<'a> &'a W: Write, { target: W, prefix: &'static str, } impl Log for SimpleLogger where for<'a> &'a W: Write, { fn enabled(&self, metadata: &log::Metadata) -> bool { metadata.level() <= log::max_level() && metadata.level() <= log::STATIC_MAX_LEVEL } fn log(&self, record: &log::Record) { let _ = writeln!(&self.target, "{}{}", self.prefix, record.args()); } fn flush(&self) { let _ = (&self.target).flush(); } } impl SimpleLogger { pub fn to_stderr(prefix: &'static str) -> SimpleLogger { SimpleLogger { target: std::io::stderr(), prefix, } } } #[cfg(feature = "dev")] impl SimpleLogger { pub fn to_file>(name: P, prefix: &'static str) -> Result { let target = std::fs::OpenOptions::new() .append(true) .create(true) .open(name)?; Ok(Self { target, prefix }) } } #[cfg(test)] mod tests { use std::{ io, sync::{Arc, RwLock}, }; use super::SimpleLogger; use log::{LevelFilter, Log}; #[derive(Clone, Default)] struct MyString { inner: Arc>, } impl MyString { fn read(&self) -> String { self.inner.read().unwrap().clone() } } impl io::Write for &'_ MyString { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner .write() .unwrap() .push_str(std::str::from_utf8(buf).unwrap()); Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { self.write(b"flushed").map(drop) } } #[test] fn test_default_level() { let logger = SimpleLogger::to_stderr("test"); let metadata = log::Metadata::builder().level(log::Level::Trace).build(); log::set_max_level(LevelFilter::Trace); assert!(logger.enabled(&metadata)); log::set_max_level(LevelFilter::Info); assert!(!logger.enabled(&metadata)); } #[test] fn test_write_and_flush() { let target = MyString::default(); let logger = SimpleLogger { target: target.clone(), prefix: "[test] ", }; let record = log::Record::builder() .args(format_args!("Hello World!")) .level(log::Level::Info) .build(); logger.log(&record); let value = target.read(); assert_eq!(value, "[test] Hello World!\n"); drop(value); logger.flush(); let value = target.read(); assert_eq!(value, "[test] Hello World!\nflushed"); drop(value); } } sudo-rs-0.2.2/src/log/syslog.rs000064400000000000000000000153011046102023000144570ustar 00000000000000use core::fmt::{self, Write}; use std::ffi::CStr; use log::{Level, Log, Metadata}; use crate::system::syslog; pub struct Syslog; const LIMIT: usize = 960; const DOTDOTDOT_START: &[u8] = b"[...] "; const DOTDOTDOT_END: &[u8] = b" [...]"; const NULL_BYTE: usize = 1; // for C string compatibility const BUFSZ: usize = LIMIT + DOTDOTDOT_END.len() + NULL_BYTE; const FACILITY: libc::c_int = libc::LOG_AUTH; struct SysLogWriter { buffer: [u8; BUFSZ], cursor: usize, facility: libc::c_int, priority: libc::c_int, } impl SysLogWriter { fn new(priority: libc::c_int, facility: libc::c_int) -> Self { Self { buffer: [0; BUFSZ], cursor: 0, priority, facility, } } fn append(&mut self, bytes: &[u8]) { let num_bytes = bytes.len(); self.buffer[self.cursor..self.cursor + num_bytes].copy_from_slice(bytes); self.cursor += num_bytes; } fn send_to_syslog(&mut self) { self.append(&[0]); let message = CStr::from_bytes_with_nul(&self.buffer[..self.cursor]).unwrap(); syslog(self.priority, self.facility, message); self.cursor = 0; } } impl Write for SysLogWriter { fn write_str(&mut self, mut message: &str) -> fmt::Result { loop { if self.cursor + message.len() > LIMIT { // floor_char_boundary is currently unstable let mut truncate_boundary = LIMIT - self.cursor; while !message.is_char_boundary(truncate_boundary) { truncate_boundary -= 1; } truncate_boundary = message[..truncate_boundary] .rfind(|c: char| c.is_ascii_whitespace()) .unwrap_or(truncate_boundary); let left = &message[..truncate_boundary]; let right = &message[truncate_boundary..]; self.append(left.as_bytes()); self.append(DOTDOTDOT_END); self.send_to_syslog(); self.append(DOTDOTDOT_START); message = right; } else { self.append(message.as_bytes()); break; } } Ok(()) } } impl Log for Syslog { fn enabled(&self, metadata: &Metadata) -> bool { metadata.level() <= log::max_level() && metadata.level() <= log::STATIC_MAX_LEVEL } fn log(&self, record: &log::Record) { let priority = match record.level() { Level::Error => libc::LOG_ERR, Level::Warn => libc::LOG_WARNING, Level::Info => libc::LOG_INFO, Level::Debug => libc::LOG_DEBUG, Level::Trace => libc::LOG_DEBUG, }; let mut writer = SysLogWriter::new(priority, FACILITY); let _ = write!(writer, "{}", record.args()); writer.send_to_syslog(); } fn flush(&self) { // pass } } #[cfg(test)] mod tests { use log::Log; use std::fmt::Write; use super::{SysLogWriter, Syslog, FACILITY}; #[test] fn can_write_to_syslog() { let logger = Syslog; let record = log::Record::builder() .args(format_args!("Hello World!")) .level(log::Level::Info) .build(); logger.log(&record); } #[test] fn can_handle_multiple_writes() { let mut writer = SysLogWriter::new(libc::LOG_DEBUG, FACILITY); for i in 1..20 { let _ = write!(writer, "{}", "Test 123 ".repeat(i)); } } #[test] fn can_truncate_syslog() { let logger = Syslog; let record = log::Record::builder() .args(format_args!("This is supposed to be a very long syslog message but idk what to write, so I am just going to tell you about the time I tried to make coffee with a teapot. So I woke up one morning and decided to make myself a pot of coffee, however after all the wild coffee parties and mishaps the coffee pot had evetually given it's last cup on a tragic morning I call wednsday. So it came to, that the only object capable of giving me hope for the day was my teapot. As I stood in the kitchen and reached for my teapot it, as if sensing the impending horrors that awaited the innocent little teapot, emmited a horse sheak of desperation. \"three hundred and seven\", it said. \"What?\" I asked with a voice of someone who clearly did not want to be bothered until he had his daily almost medically necessary dose of caffine. \"I am a teapot\" it responded with a voice of increasing forcefulness. \"I am a teapot, not a coffee pot\". It was then, in my moments of confusion that my brain finally understood, this was a teapot.")) .level(log::Level::Info) .build(); logger.log(&record); } #[test] fn can_truncate_syslog_with_no_spaces() { let logger = Syslog; let record = log::Record::builder() .args(format_args!("iwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercasesiwillhandlecornercases")) .level(log::Level::Info) .build(); logger.log(&record); } } sudo-rs-0.2.2/src/macros.rs000064400000000000000000000031211046102023000136370ustar 00000000000000// the `std::print` macros panic on any IO error. these are non-panicking alternatives macro_rules! println_ignore_io_error { ($($tt:tt)*) => {{ use std::io::Write; let _ = writeln!(std::io::stdout(), $($tt)*); }} } macro_rules! eprintln_ignore_io_error { ($($tt:tt)*) => {{ use std::io::Write; let _ = writeln!(std::io::stderr(), $($tt)*); }} } // catch unintentional uses of `print*` macros with the test suite #[allow(unused_macros)] #[cfg(debug_assertions)] macro_rules! eprintln { ($($tt:tt)*) => { compiler_error!("do not use `eprintln!`; use the `write!` macro instead") }; } #[allow(unused_macros)] #[cfg(debug_assertions)] macro_rules! eprint { ($($tt:tt)*) => { compiler_error!("do not use `eprint!`; use the `write!` macro instead") }; } #[allow(unused_macros)] #[cfg(debug_assertions)] macro_rules! println { ($($tt:tt)*) => { compiler_error!("do not use `println!`; use the `write!` macro instead") }; } #[allow(unused_macros)] #[cfg(debug_assertions)] macro_rules! print { ($($tt:tt)*) => { compiler_error!("do not use `print!`; use the `write!` macro instead") }; } macro_rules! cstr { ($lit:literal) => {{ // this `const` item produces compile time errors = it performs the checks at compile time const CS: &'static std::ffi::CStr = match std::ffi::CStr::from_bytes_until_nul(concat!($lit, "\0").as_bytes()) { Ok(x) => x, Err(_) => panic!("string literal did not pass CStr checks"), }; CS }}; } sudo-rs-0.2.2/src/pam/converse.rs000064400000000000000000000337401046102023000147660ustar 00000000000000use crate::cutils::string_from_ptr; use super::sys::*; use super::{error::PamResult, rpassword, securemem::PamBuffer, PamError, PamErrorType}; /// Each message in a PAM conversation will have a message style. Each of these /// styles must be handled separately. #[derive(Clone, Copy)] pub enum PamMessageStyle { /// Prompt for input using a message. The input should considered secret /// and should be hidden from view. PromptEchoOff = PAM_PROMPT_ECHO_OFF as isize, /// Prompt for input using a message. The input does not have to be /// considered a secret and may be displayed to the user. PromptEchoOn = PAM_PROMPT_ECHO_ON as isize, /// Display an error message. The user should not be prompted for any input. ErrorMessage = PAM_ERROR_MSG as isize, /// Display some informational text. The user should not be prompted for any /// input. TextInfo = PAM_TEXT_INFO as isize, } impl PamMessageStyle { pub fn from_int(val: libc::c_int) -> Option { use PamMessageStyle::*; match val { PAM_PROMPT_ECHO_OFF => Some(PromptEchoOff), PAM_PROMPT_ECHO_ON => Some(PromptEchoOn), PAM_ERROR_MSG => Some(ErrorMessage), PAM_TEXT_INFO => Some(TextInfo), _ => None, } } } /// A PamMessage contains the data in a single message of a pam conversation /// and contains the response to that message. pub struct PamMessage { pub msg: String, pub style: PamMessageStyle, response: Option, } impl PamMessage { /// Set a response value to the message. pub fn set_response(&mut self, resp: PamBuffer) { self.response = Some(resp); } } /// Contains the conversation messages and allows setting responses to /// each of these messages. /// /// Note that generally there will only be one message in each conversation /// because of historical reasons, and instead multiple conversations will /// be started for individual messages. pub struct Conversation { messages: Vec, } impl Conversation { /// Get a mutable iterator of the messages in this conversation. /// /// This can be used to add the resulting values to the messages. pub fn messages_mut(&mut self) -> impl Iterator { self.messages.iter_mut() } } pub trait Converser { /// Handle all the message in the given conversation. They may all be /// handled in sequence or at the same time if possible. fn handle_conversation(&self, conversation: &mut Conversation) -> PamResult<()>; } pub trait SequentialConverser: Converser { /// Handle a normal prompt, i.e. present some message and ask for a value. /// The value is not considered a secret. fn handle_normal_prompt(&self, msg: &str) -> PamResult; /// Handle a hidden prompt, i.e. present some message and ask for a value. /// The value is considered secret and should not be visible. fn handle_hidden_prompt(&self, msg: &str) -> PamResult; /// Display an error message to the user, the user does not need to input a /// value. fn handle_error(&self, msg: &str) -> PamResult<()>; /// Display an informational message to the user, the user does not need to /// input a value. fn handle_info(&self, msg: &str) -> PamResult<()>; } impl Converser for T where T: SequentialConverser, { fn handle_conversation(&self, conversation: &mut Conversation) -> PamResult<()> { use PamMessageStyle::*; for msg in conversation.messages_mut() { match msg.style { PromptEchoOn => { msg.set_response(self.handle_normal_prompt(&msg.msg)?); } PromptEchoOff => { msg.set_response(self.handle_hidden_prompt(&msg.msg)?); } ErrorMessage => { self.handle_error(&msg.msg)?; } TextInfo => { self.handle_info(&msg.msg)?; } } } Ok(()) } } /// A converser that uses stdin/stdout/stderr to display messages and to request /// input from the user. pub struct CLIConverser { pub(super) name: String, pub(super) use_stdin: bool, pub(super) no_interact: bool, } use rpassword::Terminal; impl CLIConverser { fn open(&self) -> std::io::Result { if self.use_stdin { Terminal::open_stdie() } else { Terminal::open_tty() } } } impl SequentialConverser for CLIConverser { fn handle_normal_prompt(&self, msg: &str) -> PamResult { if self.no_interact { return Err(PamError::InteractionRequired); } let mut tty = self.open()?; tty.prompt(&format!("[{}: input needed] {msg} ", self.name))?; Ok(tty.read_cleartext()?) } fn handle_hidden_prompt(&self, msg: &str) -> PamResult { if self.no_interact { return Err(PamError::InteractionRequired); } let mut tty = self.open()?; tty.prompt(&format!("[{}: authenticate] {msg}", self.name))?; Ok(tty.read_password()?) } fn handle_error(&self, msg: &str) -> PamResult<()> { let mut tty = self.open()?; Ok(tty.prompt(&format!("[{} error] {msg}\n", self.name))?) } fn handle_info(&self, msg: &str) -> PamResult<()> { let mut tty = self.open()?; Ok(tty.prompt(&format!("[{}] {msg}\n", self.name))?) } } /// Helper struct that contains the converser as well as panic boolean pub(super) struct ConverserData { pub(super) converser: C, pub(super) panicked: bool, } /// This function implements the conversation function of `pam_conv`. /// /// This function should always be called with an appdata_ptr that implements /// the `Converser` trait. It then collects the messages provided into a vector /// that is passed to the converser. The converser can then respond to those /// messages and add their replies (where applicable). Finally the replies are /// converted back to the C interface and returned to PAM. This function tries /// to catch any unwinding panics and sets state to indicate that a panic /// occured. /// /// # Safety /// * If called with an appdata_ptr that does not correspond with the Converser /// this function will exhibit undefined behavior. /// * The messages from PAM are assumed to be formatted correctly. pub(super) unsafe extern "C" fn converse( num_msg: libc::c_int, msg: *mut *const pam_message, response: *mut *mut pam_response, appdata_ptr: *mut libc::c_void, ) -> libc::c_int { let result = std::panic::catch_unwind(|| { // convert the input messages to Rust types let mut conversation = Conversation { messages: Vec::with_capacity(num_msg as usize), }; for i in 0..num_msg as isize { let message: &pam_message = unsafe { &**msg.offset(i) }; let msg = unsafe { string_from_ptr(message.msg) }; let style = if let Some(style) = PamMessageStyle::from_int(message.msg_style) { style } else { // early return if there is a failure to convert, pam would have given us nonsense return PamErrorType::ConversationError; }; conversation.messages.push(PamMessage { msg, style, response: None, }); } // send the conversation of to the Rust part let app_data = unsafe { &mut *(appdata_ptr as *mut ConverserData) }; if app_data .converser .handle_conversation(&mut conversation) .is_err() { return PamErrorType::ConversationError; } // Conversation should now contain response messages // allocate enough memory for the responses, set it to zero let temp_resp = unsafe { libc::calloc( num_msg as libc::size_t, std::mem::size_of::() as libc::size_t, ) } as *mut pam_response; if temp_resp.is_null() { return PamErrorType::BufferError; } // Store the responses for (i, msg) in conversation.messages.into_iter().enumerate() { let response: &mut pam_response = unsafe { &mut *(temp_resp.add(i)) }; if let Some(secbuf) = msg.response { response.resp = secbuf.leak().as_ptr().cast(); } } // Set the responses unsafe { *response = temp_resp }; PamErrorType::Success }); // handle any unwinding panics that occured here let res = match result { Ok(r) => r, Err(_) => { // notify caller that a panic has occured let app_data = unsafe { &mut *(appdata_ptr as *mut ConverserData) }; app_data.panicked = true; PamErrorType::ConversationError } }; res.as_int() } #[cfg(test)] mod test { use super::*; use std::pin::Pin; use PamMessageStyle::*; impl SequentialConverser for String { fn handle_normal_prompt(&self, msg: &str) -> PamResult { Ok(PamBuffer::new(format!("{self} says {msg}").into_bytes())) } fn handle_hidden_prompt(&self, msg: &str) -> PamResult { Ok(PamBuffer::new( format!("{self}s secret is {msg}").into_bytes(), )) } fn handle_error(&self, msg: &str) -> PamResult<()> { panic!("{msg}") } fn handle_info(&self, _msg: &str) -> PamResult<()> { Ok(()) } } // essentially do the inverse of the "conversation function" fn dummy_pam(msgs: &[PamMessage], talkie: &pam_conv) -> Vec> { let pam_msgs = msgs .iter() .map(|PamMessage { msg, style, .. }| pam_message { msg: std::ffi::CString::new(&msg[..]).unwrap().into_raw(), msg_style: *style as i32, }) .rev() .collect::>(); let mut ptrs = pam_msgs .iter() .map(|x| x as *const pam_message) .rev() .collect::>(); let mut raw_response = std::ptr::null_mut::(); let conv_err = unsafe { talkie.conv.expect("non-null fn ptr")( ptrs.len() as i32, ptrs.as_mut_ptr(), &mut raw_response, talkie.appdata_ptr, ) }; // deallocate the leaky strings for rec in ptrs { unsafe { drop(std::ffi::CString::from_raw((*rec).msg as *mut _)); } } if conv_err != 0 { return vec![]; } let result = msgs .iter() .enumerate() .map(|(i, _)| unsafe { let ptr = raw_response.add(i); if (*ptr).resp.is_null() { None } else { // "The resp_retcode member of this struct is unused and should be set to zero." assert_eq!((*ptr).resp_retcode, 0); let response = string_from_ptr((*ptr).resp); libc::free((*ptr).resp as *mut _); Some(response) } }) .collect(); unsafe { libc::free(raw_response as *mut _) }; result } fn msg(style: PamMessageStyle, msg: &str) -> PamMessage { let msg = msg.to_string(); PamMessage { style, msg, response: None, } } // sanity check on the test cases; lib.rs is expected to manage the lifetime of the pointer // inside the pam_conv object explicitly. use std::marker::PhantomData; struct PamConvBorrow<'a> { pam_conv: pam_conv, _marker: std::marker::PhantomData<&'a ()>, } impl<'a> PamConvBorrow<'a> { fn new(data: Pin<&'a mut ConverserData>) -> PamConvBorrow<'a> { let appdata_ptr = unsafe { data.get_unchecked_mut() as *mut ConverserData as *mut libc::c_void }; PamConvBorrow { pam_conv: pam_conv { conv: Some(converse::), appdata_ptr, }, _marker: PhantomData, } } fn borrow(&self) -> &pam_conv { &self.pam_conv } } #[test] fn miri_pam_gpt() { let mut hello = Box::pin(ConverserData { converser: "tux".to_string(), panicked: false, }); let cookie = PamConvBorrow::new(hello.as_mut()); let pam_conv = cookie.borrow(); assert_eq!(dummy_pam(&[], pam_conv), vec![]); assert_eq!( dummy_pam(&[msg(PromptEchoOn, "hello")], pam_conv), vec![Some("tux says hello".to_string())] ); assert_eq!( dummy_pam(&[msg(PromptEchoOff, "fish")], pam_conv), vec![Some("tuxs secret is fish".to_string())] ); assert_eq!(dummy_pam(&[msg(TextInfo, "mars")], pam_conv), vec![None]); assert_eq!( dummy_pam( &[ msg(PromptEchoOff, "banging the rocks together"), msg(TextInfo, ""), msg(PromptEchoOn, ""), ], pam_conv ), vec![ Some("tuxs secret is banging the rocks together".to_string()), None, Some("tux says ".to_string()), ] ); //assert!(!hello.panicked); // not allowed by borrow checker let real_hello = unsafe { &mut *(pam_conv.appdata_ptr as *mut ConverserData) }; assert!(!real_hello.panicked); assert_eq!(dummy_pam(&[msg(ErrorMessage, "oops")], pam_conv), vec![]); assert!(hello.panicked); // allowed now } } sudo-rs-0.2.2/src/pam/error.rs000064400000000000000000000230001046102023000142570ustar 00000000000000use std::{ffi::NulError, fmt, str::Utf8Error}; use crate::cutils::string_from_ptr; use super::sys::*; pub type PamResult = Result; #[derive(PartialEq, Eq, Debug)] pub enum PamErrorType { /// There was no error running the PAM command Success, /// OpenError, /// SymbolError, /// ServiceError, /// SystemError, /// BufferError, /// ConversationError, /// PermissionDenied, /// The maximum number of authentication attempts was reached and no more /// attempts should be made. MaxTries, /// The user failed to authenticate correctly. AuthError, NewAuthTokenRequired, /// The application does not have enough credentials to authenticate the /// user. This can for example happen if we wanted to update the user /// password from a non-root process, which we cannot do. CredentialsInsufficient, /// PAM modules were unable to access the authentication information (for /// example due to a network error). AuthInfoUnavailable, /// The specified user is unknown to an authentication service. UserUnknown, /// Failed to retrieve the credentials (i.e. password) for a user. CredentialsUnavailable, /// The credentials (i.e. password) for this user were expired. CredentialsExpired, /// There was an error setting the user credentials. CredentialsError, /// The user account is expired and can no longer be used. AccountExpired, /// AuthTokenExpired, /// SessionError, /// AuthTokenError, /// AuthTokenRecoveryError, /// AuthTokenLockBusy, /// AuthTokenDisableAging, /// NoModuleData, /// Ignore, /// The application should exit immediately. Abort, /// TryAgain, /// ModuleUnknown, /// The application tried to set/delete an undefined or inaccessible item. BadItem, // Extension in OpenPAM and LinuxPAM // DomainUnknown, // OpenPAM only // BadHandle // OpenPAM only // BadFeature // OpenPAM only // BadConstant // OpenPAM only // ConverseAgain // LinuxPAM only // Incomplete // LinuxPAM only UnknownErrorType(i32), } impl PamErrorType { pub(super) fn from_int(errno: libc::c_int) -> PamErrorType { use PamErrorType::*; match errno { PAM_SUCCESS => Success, PAM_OPEN_ERR => OpenError, PAM_SYMBOL_ERR => SymbolError, PAM_SERVICE_ERR => ServiceError, PAM_SYSTEM_ERR => SystemError, PAM_BUF_ERR => BufferError, PAM_CONV_ERR => ConversationError, PAM_PERM_DENIED => PermissionDenied, PAM_MAXTRIES => MaxTries, PAM_AUTH_ERR => AuthError, PAM_NEW_AUTHTOK_REQD => NewAuthTokenRequired, PAM_CRED_INSUFFICIENT => CredentialsInsufficient, PAM_AUTHINFO_UNAVAIL => AuthInfoUnavailable, PAM_USER_UNKNOWN => UserUnknown, PAM_CRED_UNAVAIL => CredentialsUnavailable, PAM_CRED_EXPIRED => CredentialsExpired, PAM_CRED_ERR => CredentialsError, PAM_ACCT_EXPIRED => AccountExpired, PAM_AUTHTOK_EXPIRED => AuthTokenExpired, PAM_SESSION_ERR => SessionError, PAM_AUTHTOK_ERR => AuthTokenError, PAM_AUTHTOK_RECOVERY_ERR => AuthTokenRecoveryError, PAM_AUTHTOK_LOCK_BUSY => AuthTokenLockBusy, PAM_AUTHTOK_DISABLE_AGING => AuthTokenDisableAging, PAM_NO_MODULE_DATA => NoModuleData, PAM_IGNORE => Ignore, PAM_ABORT => Abort, PAM_TRY_AGAIN => TryAgain, PAM_MODULE_UNKNOWN => ModuleUnknown, PAM_BAD_ITEM => BadItem, // PAM_DOMAIN_UNKNOWN => DomainUnknown, // PAM_BAD_HANDLE => BadHandle, // PAM_BAD_FEATURE => BadFeature, // PAM_BAD_CONSTANT => BadConstant, // PAM_CONV_AGAIN => ConverseAgain, // PAM_INCOMPLETE => Incomplete, _ => UnknownErrorType(errno), } } pub fn as_int(&self) -> libc::c_int { use PamErrorType::*; match self { Success => PAM_SUCCESS as libc::c_int, OpenError => PAM_OPEN_ERR as libc::c_int, SymbolError => PAM_SYMBOL_ERR as libc::c_int, ServiceError => PAM_SERVICE_ERR as libc::c_int, SystemError => PAM_SYSTEM_ERR as libc::c_int, BufferError => PAM_BUF_ERR as libc::c_int, ConversationError => PAM_CONV_ERR as libc::c_int, PermissionDenied => PAM_PERM_DENIED as libc::c_int, MaxTries => PAM_MAXTRIES as libc::c_int, AuthError => PAM_AUTH_ERR as libc::c_int, NewAuthTokenRequired => PAM_NEW_AUTHTOK_REQD as libc::c_int, CredentialsInsufficient => PAM_CRED_INSUFFICIENT as libc::c_int, AuthInfoUnavailable => PAM_AUTHINFO_UNAVAIL as libc::c_int, UserUnknown => PAM_USER_UNKNOWN as libc::c_int, CredentialsUnavailable => PAM_CRED_UNAVAIL as libc::c_int, CredentialsExpired => PAM_CRED_EXPIRED as libc::c_int, CredentialsError => PAM_CRED_ERR as libc::c_int, AccountExpired => PAM_ACCT_EXPIRED as libc::c_int, AuthTokenExpired => PAM_AUTHTOK_EXPIRED as libc::c_int, SessionError => PAM_SESSION_ERR as libc::c_int, AuthTokenError => PAM_AUTHTOK_ERR as libc::c_int, AuthTokenRecoveryError => PAM_AUTHTOK_RECOVERY_ERR as libc::c_int, AuthTokenLockBusy => PAM_AUTHTOK_LOCK_BUSY as libc::c_int, AuthTokenDisableAging => PAM_AUTHTOK_DISABLE_AGING as libc::c_int, NoModuleData => PAM_NO_MODULE_DATA as libc::c_int, Ignore => PAM_IGNORE as libc::c_int, Abort => PAM_ABORT as libc::c_int, TryAgain => PAM_TRY_AGAIN as libc::c_int, ModuleUnknown => PAM_MODULE_UNKNOWN as libc::c_int, BadItem => PAM_BAD_ITEM as libc::c_int, // DomainUnknown => PAM_DOMAIN_UNKNOWN as libc::c_int, // BadHandle => PAM_BAD_HANDLE as libc::c_int, // BadFeature => PAM_BAD_FEATURE as libc::c_int, // BadConstant => PAM_BAD_CONSTANT as libc::c_int, // ConverseAgain => PAM_CONV_AGAIN as libc::c_int, // Incomplete => PAM_INCOMPLETE as libc::c_int, UnknownErrorType(e) => *e, } } fn get_err_msg(&self) -> String { // pam_strerror technically takes a pam handle as the first argument, // but we do not know of any implementation that actually uses the pamh // argument. See also the netbsd man page for `pam_strerror`. let data = unsafe { pam_strerror(std::ptr::null_mut(), self.as_int()) }; if data.is_null() { String::from("Error unresolved by PAM") } else { unsafe { string_from_ptr(data) } } } } #[derive(Debug)] pub enum PamError { UnexpectedNulByte(NulError), Utf8Error(Utf8Error), InvalidState, Pam(PamErrorType, String), IoError(std::io::Error), SessionAlreadyOpen, SessionNotOpen, EnvListFailure, InteractionRequired, } impl From for PamError { fn from(err: std::io::Error) -> Self { PamError::IoError(err) } } impl From for PamError { fn from(err: NulError) -> Self { PamError::UnexpectedNulByte(err) } } impl From for PamError { fn from(err: Utf8Error) -> Self { PamError::Utf8Error(err) } } impl fmt::Display for PamError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { PamError::UnexpectedNulByte(_) => write!(f, "Unexpected nul byte in input"), PamError::Utf8Error(_) => write!(f, "Could not read input data as UTF-8 string"), PamError::InvalidState => { write!( f, "Could not initiate pam because the state is not complete" ) } PamError::Pam(tp, msg) => write!(f, "PAM returned an error ({tp:?}): {msg}"), PamError::IoError(e) => write!(f, "IO error: {e}"), PamError::SessionAlreadyOpen => { write!(f, "Cannot open session while one is already open") } PamError::SessionNotOpen => write!(f, "Cannot close session while none is open"), PamError::EnvListFailure => { write!( f, "It was not possible to get a list of environment variables" ) } PamError::InteractionRequired => write!(f, "Interaction is required"), } } } impl PamError { /// Create a new PamError based on the error number from pam and a handle to a pam session /// The handle to the pam session is allowed to be null pub(super) fn from_pam(errno: libc::c_int) -> PamError { let tp = PamErrorType::from_int(errno); let msg = tp.get_err_msg(); PamError::Pam(tp, msg) } } /// Returns `Ok(())` if the error code is `PAM_SUCCESS` or a `PamError` in other cases pub(super) fn pam_err(err: libc::c_int) -> Result<(), PamError> { if err == PAM_SUCCESS as libc::c_int { Ok(()) } else { Err(PamError::from_pam(err)) } } #[cfg(test)] mod test { use super::PamErrorType; #[test] fn isomorphy() { for i in -100..100 { let pam = PamErrorType::from_int(i); assert_eq!(pam.as_int(), i); assert_eq!(PamErrorType::from_int(pam.as_int()), pam); } } } sudo-rs-0.2.2/src/pam/mod.rs000064400000000000000000000265471046102023000137300ustar 00000000000000use std::{ collections::HashMap, ffi::{CStr, CString, OsStr, OsString}, os::raw::c_char, os::unix::prelude::OsStrExt, ptr::NonNull, }; use converse::ConverserData; use error::pam_err; pub use error::{PamError, PamErrorType, PamResult}; use sys::*; mod converse; mod error; mod rpassword; mod securemem; #[allow(nonstandard_style)] pub mod sys; pub use converse::{CLIConverser, Converser}; pub struct PamContext { data_ptr: *mut ConverserData, pamh: *mut pam_handle_t, silent: bool, allow_null_auth_token: bool, last_pam_status: Option, session_started: bool, } pub struct PamContextBuilder { converser: Option, service_name: Option, target_user: Option, } impl PamContextBuilder { /// Build the PamContext based on the current configuration. /// /// This function will error when the required settings have not yet been /// set, or when initialization of the PAM session somehow failed. pub fn build(self) -> PamResult> { if let (Some(converser), Some(service_name)) = (self.converser, self.service_name) { let c_service_name = CString::new(service_name)?; let c_user = self.target_user.map(CString::new).transpose()?; let c_user_ptr = match c_user { Some(ref c) => c.as_ptr(), None => std::ptr::null(), }; // this will be de-allocated explicitly in this type's drop method let data_ptr = Box::into_raw(Box::new(ConverserData { converser, panicked: false, })); let mut pamh = std::ptr::null_mut(); let res = unsafe { pam_start( c_service_name.as_ptr(), c_user_ptr, &pam_conv { conv: Some(converse::converse::), appdata_ptr: data_ptr as *mut libc::c_void, }, &mut pamh, ) }; pam_err(res)?; if pamh.is_null() { Err(PamError::InvalidState) } else { Ok(PamContext { data_ptr, pamh, silent: false, allow_null_auth_token: true, last_pam_status: None, session_started: false, }) } } else { Err(PamError::InvalidState) } } /// Set a converser implementation that will be used for the PAM conversation. pub fn converser(mut self, converser: C) -> PamContextBuilder { self.converser = Some(converser); self } /// Set the service name for the PAM session. /// /// Note that the service name should be based on a static string and not /// based on the name of the binary. pub fn service_name>(mut self, name: T) -> PamContextBuilder { self.service_name = Some(name.into()); self } /// Set a target user that should be inserted into the pam context. /// /// The target user is optional and may also be set after the context was /// constructed or not set at all in which case PAM will ask for a /// username. pub fn target_user>(mut self, user: T) -> PamContextBuilder { self.target_user = Some(user.into()); self } } impl Default for PamContextBuilder { fn default() -> Self { Self { converser: None, service_name: None, target_user: None, } } } impl PamContext { /// Set whether output of pam calls should be silent or not, by default /// PAM calls are not silent. pub fn mark_silent(&mut self, silent: bool) { self.silent = silent; } /// Set whether or not to allow empty authentication tokens, by default such /// tokens are allowed. pub fn mark_allow_null_auth_token(&mut self, allow: bool) { self.allow_null_auth_token = allow; } /// Get the PAM flag value for the silent flag fn silent_flag(&self) -> i32 { if self.silent { PAM_SILENT } else { 0 } } /// Get the PAM flag value for the disallow_null_authtok flag fn disallow_null_auth_token_flag(&self) -> i32 { if self.allow_null_auth_token { 0 } else { PAM_DISALLOW_NULL_AUTHTOK } } /// Run authentication for the account pub fn authenticate(&mut self) -> PamResult<()> { let mut flags = 0; flags |= self.silent_flag(); flags |= self.disallow_null_auth_token_flag(); pam_err(unsafe { pam_authenticate(self.pamh, flags) })?; if self.has_panicked() { panic!("Panic during pam authentication"); } Ok(()) } /// Check that the account is valid pub fn validate_account(&mut self) -> PamResult<()> { let mut flags = 0; flags |= self.silent_flag(); flags |= self.disallow_null_auth_token_flag(); pam_err(unsafe { pam_acct_mgmt(self.pamh, flags) }) } /// Attempt to validate the account, if that fails because the authentication /// token is outdated, then an update of the authentication token is requested. pub fn validate_account_or_change_auth_token(&mut self) -> PamResult<()> { let check_val = self.validate_account(); match check_val { Ok(()) => Ok(()), Err(PamError::Pam(PamErrorType::NewAuthTokenRequired, _)) => { self.change_auth_token(true)?; Ok(()) } Err(e) => Err(e), } } /// Set the user that will be authenticated. pub fn set_user(&mut self, user: &str) -> PamResult<()> { let c_user = CString::new(user)?; pam_err(unsafe { pam_set_item(self.pamh, PAM_USER, c_user.as_ptr() as *const libc::c_void) }) } /// Get the user that is currently active in the PAM handle pub fn get_user(&mut self) -> PamResult { let mut data = std::ptr::null(); pam_err(unsafe { pam_get_item(self.pamh, PAM_USER, &mut data) })?; // safety check to make sure that we do not ready a null ptr into a cstr if data.is_null() { return Err(PamError::InvalidState); } // unsafe conversion to cstr let cstr = unsafe { CStr::from_ptr(data as *const c_char) }; Ok(cstr.to_str()?.to_owned()) } /// Set the TTY path for the current TTY that this PAM session started from. pub fn set_tty>(&mut self, tty_path: P) -> PamResult<()> { let data = CString::new(tty_path.as_ref().as_bytes())?; pam_err(unsafe { pam_set_item(self.pamh, PAM_TTY, data.as_ptr() as *const libc::c_void) }) } // Set the user that requested the actions in this PAM instance. pub fn set_requesting_user(&mut self, user: &str) -> PamResult<()> { let data = CString::new(user.as_bytes())?; pam_err(unsafe { pam_set_item(self.pamh, PAM_RUSER, data.as_ptr() as *const libc::c_void) }) } /// Re-initialize the credentials stored in PAM pub fn credentials_reinitialize(&mut self) -> PamResult<()> { self.credentials(PAM_REINITIALIZE_CRED as libc::c_int) } /// Updates to the credentials stored in PAM fn credentials(&mut self, action: libc::c_int) -> PamResult<()> { let mut flags = action; flags |= self.silent_flag(); pam_err(unsafe { pam_setcred(self.pamh, flags) }) } /// Ask the user to change the authentication token (password). /// /// If `expired_only` is set to true, only expired authentication tokens /// will be asked to be replaced, otherwise a replacement will always be /// requested. pub fn change_auth_token(&mut self, expired_only: bool) -> PamResult<()> { let mut flags = 0; flags |= self.silent_flag(); if expired_only { flags |= PAM_CHANGE_EXPIRED_AUTHTOK; } pam_err(unsafe { pam_chauthtok(self.pamh, flags) }) } /// Start a user session for the authenticated user. pub fn open_session(&mut self) -> PamResult<()> { if !self.session_started { pam_err(unsafe { pam_open_session(self.pamh, self.silent_flag()) })?; self.session_started = true; Ok(()) } else { Err(PamError::SessionAlreadyOpen) } } /// End the user session. pub fn close_session(&mut self) -> PamResult<()> { if self.session_started { pam_err(unsafe { pam_close_session(self.pamh, self.silent_flag()) })?; self.session_started = false; Ok(()) } else { Err(PamError::SessionNotOpen) } } /// Get a full listing of the current PAM environment pub fn env(&mut self) -> PamResult> { let mut res = HashMap::new(); let envs = unsafe { pam_getenvlist(self.pamh) }; if envs.is_null() { return Err(PamError::EnvListFailure); } let mut curr_env = envs; while let Some(curr_str) = NonNull::new(unsafe { curr_env.read() }) { let data = { let cstr = unsafe { CStr::from_ptr(curr_str.as_ptr()) }; let bytes = cstr.to_bytes(); if let Some(pos) = bytes.iter().position(|b| *b == b'=') { let key = OsStr::from_bytes(&bytes[..pos]).to_owned(); let value = OsStr::from_bytes(&bytes[pos + 1..]).to_owned(); Some((key, value)) } else { None } }; if let Some((k, v)) = data { res.insert(k, v); } // free the current string and move to the next one unsafe { libc::free(curr_str.as_ptr().cast()) }; curr_env = unsafe { curr_env.offset(1) }; } // free the entire array unsafe { libc::free(envs.cast()) }; Ok(res) } /// Check if anything panicked since the last call. pub fn has_panicked(&self) -> bool { unsafe { (*self.data_ptr).panicked } } } impl PamContext { /// Create a builder that uses the CLI conversation function. pub fn builder_cli( name: &str, use_stdin: bool, no_interact: bool, ) -> PamContextBuilder { PamContextBuilder::default().converser(CLIConverser { name: name.to_owned(), use_stdin, no_interact, }) } } impl Drop for PamContext { fn drop(&mut self) { // data_ptr's pointee is de-allocated in this scope let _data = unsafe { Box::from_raw(self.data_ptr) }; let _ = self.close_session(); // It looks like PAM_DATA_SILENT is important to set for our sudo context, but // it is unclear what it really does and does not do, other than the vague // documentation description to 'not take the call to seriously' // Also see https://github.com/systemd/systemd/issues/22318 unsafe { pam_end( self.pamh, self.last_pam_status.unwrap_or(PAM_SUCCESS as libc::c_int) | PAM_DATA_SILENT, ) }; } } sudo-rs-0.2.2/src/pam/rpassword.rs000064400000000000000000000133761046102023000151710ustar 00000000000000/// Parts of the code below are Copyright (c) 2023, Conrad Kleinespel et al /// /// This module contains code that was originally written by Conrad Kleinespel for the rpassword /// crate. No copyright notices were found in the original code. /// /// See: https://docs.rs/rpassword/latest/rpassword/ /// /// Most code was replaced and so is no longer a derived work; work that we kept: /// /// - the "HiddenInput" struct and implementation, with changes: /// * replaced occurences of explicit 'i32' and 'c_int' with RawFd /// * open the TTY ourselves to mitigate Linux CVE-2023-2002 /// - the general idea of a "SafeString" type that clears its memory /// (although much more robust than in the original code) /// use std::io::{self, Error, ErrorKind, Read}; use std::os::fd::{AsRawFd, RawFd}; use std::{fs, mem}; use libc::{tcsetattr, termios, ECHO, ECHONL, TCSANOW}; use crate::cutils::cerr; use super::securemem::PamBuffer; pub struct HiddenInput { tty: fs::File, term_orig: termios, } impl HiddenInput { fn new() -> io::Result> { // control ourselves that we are really talking to a TTY // mitigates: https://marc.info/?l=oss-security&m=168164424404224 let Ok(tty) = fs::File::open("/dev/tty") else { // if we have nothing to show, we have nothing to hide return Ok(None); }; let fd = tty.as_raw_fd(); // Make two copies of the terminal settings. The first one will be modified // and the second one will act as a backup for when we want to set the // terminal back to its original state. let mut term = safe_tcgetattr(fd)?; let term_orig = safe_tcgetattr(fd)?; // Hide the password. This is what makes this function useful. term.c_lflag &= !ECHO; // But don't hide the NL character when the user hits ENTER. term.c_lflag |= ECHONL; // Save the settings for now. cerr(unsafe { tcsetattr(fd, TCSANOW, &term) })?; Ok(Some(HiddenInput { tty, term_orig })) } } impl Drop for HiddenInput { fn drop(&mut self) { // Set the the mode back to normal unsafe { tcsetattr(self.tty.as_raw_fd(), TCSANOW, &self.term_orig); } } } fn safe_tcgetattr(fd: RawFd) -> io::Result { let mut term = mem::MaybeUninit::::uninit(); cerr(unsafe { ::libc::tcgetattr(fd, term.as_mut_ptr()) })?; Ok(unsafe { term.assume_init() }) } /// Reads a password from the given file descriptor fn read_unbuffered(source: &mut impl io::Read) -> io::Result { let mut password = PamBuffer::default(); let mut pwd_iter = password.iter_mut(); const EOL: u8 = 0x0A; let input = source.bytes().take_while(|x| x.as_ref().ok() != Some(&EOL)); for read_byte in input { if let Some(dest) = pwd_iter.next() { *dest = read_byte? } else { return Err(Error::new( ErrorKind::OutOfMemory, "incorrect password attempt", )); } } Ok(password) } /// Write something and immediately flush fn write_unbuffered(sink: &mut impl io::Write, text: &str) -> io::Result<()> { sink.write_all(text.as_bytes())?; sink.flush() } /// A data structure representing either /dev/tty or /dev/stdin+stderr pub enum Terminal<'a> { Tty(fs::File), StdIE(io::StdinLock<'a>, io::StderrLock<'a>), } impl Terminal<'_> { /// Open the current TTY for user communication pub fn open_tty() -> io::Result { Ok(Terminal::Tty( fs::OpenOptions::new() .read(true) .write(true) .open("/dev/tty")?, )) } /// Open standard input and standard error for user communication pub fn open_stdie() -> io::Result { Ok(Terminal::StdIE(io::stdin().lock(), io::stderr().lock())) } /// Reads input with TTY echo disabled pub fn read_password(&mut self) -> io::Result { let mut input = self.source(); let _hide_input = HiddenInput::new()?; read_unbuffered(&mut input) } /// Reads input with TTY echo enabled pub fn read_cleartext(&mut self) -> io::Result { read_unbuffered(&mut self.source()) } /// Display information pub fn prompt(&mut self, text: &str) -> io::Result<()> { write_unbuffered(&mut self.sink(), text) } // boilerplate reduction functions fn source(&mut self) -> &mut dyn io::Read { match self { Terminal::StdIE(x, _) => x, Terminal::Tty(x) => x, } } fn sink(&mut self) -> &mut dyn io::Write { match self { Terminal::StdIE(_, x) => x, Terminal::Tty(x) => x, } } } #[cfg(test)] mod test { use super::{read_unbuffered, write_unbuffered}; #[test] fn miri_test_read() { let mut data = "password123\nhello world".as_bytes(); let buf = read_unbuffered(&mut data).unwrap(); // check that the \n is not part of input assert_eq!( buf.iter() .map(|&b| b as char) .take_while(|&x| x != '\0') .collect::(), "password123" ); // check that the \n is also consumed but the rest of the input is still there assert_eq!(std::str::from_utf8(data).unwrap(), "hello world"); } #[test] fn miri_test_longpwd() { assert!(read_unbuffered(&mut "a".repeat(511).as_bytes()).is_ok()); assert!(read_unbuffered(&mut "a".repeat(512).as_bytes()).is_err()); } #[test] fn miri_test_write() { let mut data = Vec::new(); write_unbuffered(&mut data, "prompt").unwrap(); assert_eq!(std::str::from_utf8(&data).unwrap(), "prompt"); } } sudo-rs-0.2.2/src/pam/securemem.rs000064400000000000000000000067321046102023000151300ustar 00000000000000//! Routines for "secure" memory operations; i.e. data that we need to send to Linux-PAM and don't //! want any copies to leak (that we would then need to zeroize). use std::{ alloc::{self, Layout}, mem, ptr::NonNull, slice, }; const SIZE: usize = super::sys::PAM_MAX_RESP_SIZE as usize; const ALIGN: usize = mem::align_of::(); pub struct PamBuffer(NonNull<[u8; SIZE]>); fn layout() -> Layout { // does not panic with the given arguments; also see unit test at the bottom Layout::from_size_align(SIZE, ALIGN).unwrap() } impl PamBuffer { // consume this buffer and return its internal pointer // (ending the type-level security, but guaranteeing you need unsafe code to access the data) pub fn leak(self) -> NonNull { let result = self.0; std::mem::forget(self); result.cast() } // initialize the buffer with already existing data (otherwise populating it is a bit hairy) // this is inferior than placing the data into the securebuffer directly #[cfg(test)] pub fn new(mut src: impl AsMut<[u8]>) -> Self { let mut buffer = PamBuffer::default(); let src = src.as_mut(); buffer[..src.len()].copy_from_slice(src); wipe_memory(src); buffer } } impl Default for PamBuffer { fn default() -> Self { let res = unsafe { libc::calloc(1, SIZE) }; if let Some(nn) = NonNull::new(res) { PamBuffer(nn.cast()) } else { alloc::handle_alloc_error(layout()) } } } impl std::ops::Deref for PamBuffer { type Target = [u8]; fn deref(&self) -> &[u8] { // make the slice one less in size to guarantee the existence of a terminating NUL unsafe { slice::from_raw_parts(self.0.as_ptr().cast(), SIZE - 1) } } } impl std::ops::DerefMut for PamBuffer { fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self.0.as_ptr().cast(), SIZE - 1) } } } impl Drop for PamBuffer { fn drop(&mut self) { wipe_memory(unsafe { self.0.as_mut() }); unsafe { libc::free(self.0.as_ptr().cast()) } } } /// Used to zero out memory and protect sensitive data from leaking; inspired by Conrad Kleinespel's /// Rustatic rtoolbox::SafeString, fn wipe_memory(memory: &mut [u8]) { use std::sync::atomic; let nonsense: u8 = 0x55; for c in memory { unsafe { std::ptr::write_volatile(c, nonsense) }; } atomic::fence(atomic::Ordering::SeqCst); atomic::compiler_fence(atomic::Ordering::SeqCst); } #[cfg(test)] mod test { use super::PamBuffer; #[test] fn miri_test_leaky_cstring() { let test = |text: &str| unsafe { let buf = PamBuffer::new(text.to_string().as_bytes_mut()); assert_eq!(&buf[..text.len()], text.as_bytes()); let nn = buf.leak(); let result = crate::cutils::string_from_ptr(nn.as_ptr().cast()); libc::free(nn.as_ptr().cast()); result }; assert_eq!(test(""), ""); assert_eq!(test("hello"), "hello"); } #[test] fn miri_test_wipe() { let mut memory: [u8; 3] = [1, 2, 3]; let fix = PamBuffer::new(&mut memory); assert_eq!(memory, [0x55, 0x55, 0x55]); assert_eq!(fix[0..=2], [1, 2, 3]); assert!(fix[3..].iter().all(|&x| x == 0)); std::mem::drop(fix); } #[test] fn layout_does_not_panic() { let _ = super::layout(); } } sudo-rs-0.2.2/src/pam/sys.rs000064400000000000000000000511201046102023000137500ustar 00000000000000/* automatically generated by rust-bindgen 0.66.1, minified by cargo-minify, edited to be portable */ // NOTE: the tests below test the assumptions about the padding that a C compiler will use on the // above structs; if these assumptions are incorrect, the tests will fail, but most likely the // code will still be correct. pub const PAM_SUCCESS: libc::c_int = 0; pub const PAM_OPEN_ERR: libc::c_int = 1; pub const PAM_SYMBOL_ERR: libc::c_int = 2; pub const PAM_SERVICE_ERR: libc::c_int = 3; pub const PAM_SYSTEM_ERR: libc::c_int = 4; pub const PAM_BUF_ERR: libc::c_int = 5; pub const PAM_PERM_DENIED: libc::c_int = 6; pub const PAM_AUTH_ERR: libc::c_int = 7; pub const PAM_CRED_INSUFFICIENT: libc::c_int = 8; pub const PAM_AUTHINFO_UNAVAIL: libc::c_int = 9; pub const PAM_USER_UNKNOWN: libc::c_int = 10; pub const PAM_MAXTRIES: libc::c_int = 11; pub const PAM_NEW_AUTHTOK_REQD: libc::c_int = 12; pub const PAM_ACCT_EXPIRED: libc::c_int = 13; pub const PAM_SESSION_ERR: libc::c_int = 14; pub const PAM_CRED_UNAVAIL: libc::c_int = 15; pub const PAM_CRED_EXPIRED: libc::c_int = 16; pub const PAM_CRED_ERR: libc::c_int = 17; pub const PAM_NO_MODULE_DATA: libc::c_int = 18; pub const PAM_CONV_ERR: libc::c_int = 19; pub const PAM_AUTHTOK_ERR: libc::c_int = 20; pub const PAM_AUTHTOK_RECOVERY_ERR: libc::c_int = 21; pub const PAM_AUTHTOK_LOCK_BUSY: libc::c_int = 22; pub const PAM_AUTHTOK_DISABLE_AGING: libc::c_int = 23; pub const PAM_TRY_AGAIN: libc::c_int = 24; pub const PAM_IGNORE: libc::c_int = 25; pub const PAM_ABORT: libc::c_int = 26; pub const PAM_AUTHTOK_EXPIRED: libc::c_int = 27; pub const PAM_MODULE_UNKNOWN: libc::c_int = 28; pub const PAM_BAD_ITEM: libc::c_int = 29; pub const PAM_SILENT: libc::c_int = 32768; pub const PAM_DISALLOW_NULL_AUTHTOK: libc::c_int = 1; pub const PAM_REINITIALIZE_CRED: libc::c_int = 8; pub const PAM_CHANGE_EXPIRED_AUTHTOK: libc::c_int = 32; pub const PAM_USER: libc::c_int = 2; pub const PAM_TTY: libc::c_int = 3; pub const PAM_RUSER: libc::c_int = 8; pub const PAM_DATA_SILENT: libc::c_int = 1073741824; pub const PAM_PROMPT_ECHO_OFF: libc::c_int = 1; pub const PAM_PROMPT_ECHO_ON: libc::c_int = 2; pub const PAM_ERROR_MSG: libc::c_int = 3; pub const PAM_TEXT_INFO: libc::c_int = 4; pub const PAM_MAX_RESP_SIZE: libc::c_int = 512; pub type pam_handle_t = libc::c_void; extern "C" { pub fn pam_set_item( pamh: *mut pam_handle_t, item_type: libc::c_int, item: *const libc::c_void, ) -> libc::c_int; } extern "C" { pub fn pam_get_item( pamh: *const pam_handle_t, item_type: libc::c_int, item: *mut *const libc::c_void, ) -> libc::c_int; } extern "C" { pub fn pam_strerror(pamh: *mut pam_handle_t, errnum: libc::c_int) -> *const libc::c_char; } extern "C" { pub fn pam_getenvlist(pamh: *mut pam_handle_t) -> *mut *mut libc::c_char; } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct pam_message { pub msg_style: libc::c_int, pub msg: *const libc::c_char, } #[test] fn bindgen_test_layout_pam_message() { const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); let ptr = UNINIT.as_ptr(); assert_eq!( ::std::mem::align_of::(), ::std::mem::align_of::<*mut libc::c_void>(), concat!("Alignment of ", stringify!(pam_message)) ); let mut offset: usize = 0; assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).msg_style) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_message), "::", stringify!(msg_style) ) ); offset = aligned_offset::<*const libc::c_char>(offset + ::std::mem::size_of::()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).msg) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_message), "::", stringify!(msg) ) ); offset = aligned_offset::<*const libc::c_void>( offset + ::std::mem::size_of::<*const libc::c_char>(), ); assert_eq!( ::std::mem::size_of::(), offset, concat!("Size of: ", stringify!(pam_message)) ); } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct pam_response { pub resp: *mut libc::c_char, pub resp_retcode: libc::c_int, } #[test] fn bindgen_test_layout_pam_response() { const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); let ptr = UNINIT.as_ptr(); assert_eq!( ::std::mem::align_of::(), ::std::mem::align_of::<*mut libc::c_char>(), concat!("Alignment of ", stringify!(pam_response)) ); let mut offset: usize = 0; assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).resp) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_response), "::", stringify!(resp) ) ); offset = aligned_offset::(offset + ::std::mem::size_of::<*mut libc::c_char>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).resp_retcode) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_response), "::", stringify!(resp_retcode) ) ); offset = aligned_offset::<*mut libc::c_void>(offset + ::std::mem::size_of::()); assert_eq!( ::std::mem::size_of::(), offset, concat!("Size of: ", stringify!(pam_response)) ); } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct pam_conv { pub conv: ::std::option::Option< unsafe extern "C" fn( num_msg: libc::c_int, msg: *mut *const pam_message, resp: *mut *mut pam_response, appdata_ptr: *mut libc::c_void, ) -> libc::c_int, >, pub appdata_ptr: *mut libc::c_void, } #[test] fn bindgen_test_layout_pam_conv() { const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); let ptr = UNINIT.as_ptr(); assert_eq!( ::std::mem::align_of::(), ::std::mem::align_of::<*mut libc::c_void>(), concat!("Alignment of ", stringify!(pam_conv)) ); let mut offset: usize = 0; assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).conv) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_conv), "::", stringify!(conv) ) ); offset = aligned_offset::<*mut libc::c_void>(offset + ::std::mem::size_of::<*mut libc::c_void>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).appdata_ptr) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_conv), "::", stringify!(appdata_ptr) ) ); offset = aligned_offset::<*mut libc::c_void>(offset + ::std::mem::size_of::<*mut libc::c_void>()); assert_eq!( ::std::mem::size_of::(), offset, concat!("Size of: ", stringify!(pam_conv)) ); } extern "C" { pub fn pam_start( service_name: *const libc::c_char, user: *const libc::c_char, pam_conversation: *const pam_conv, pamh: *mut *mut pam_handle_t, ) -> libc::c_int; } extern "C" { pub fn pam_end(pamh: *mut pam_handle_t, pam_status: libc::c_int) -> libc::c_int; } extern "C" { pub fn pam_authenticate(pamh: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int; } extern "C" { pub fn pam_setcred(pamh: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int; } extern "C" { pub fn pam_acct_mgmt(pamh: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int; } extern "C" { pub fn pam_open_session(pamh: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int; } extern "C" { pub fn pam_close_session(pamh: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int; } extern "C" { pub fn pam_chauthtok(pamh: *mut pam_handle_t, flags: libc::c_int) -> libc::c_int; } pub type __uid_t = libc::c_uint; pub type __gid_t = libc::c_uint; pub type gid_t = __gid_t; pub type uid_t = __uid_t; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct passwd { pub pw_name: *mut libc::c_char, pub pw_passwd: *mut libc::c_char, pub pw_uid: __uid_t, pub pw_gid: __gid_t, pub pw_gecos: *mut libc::c_char, pub pw_dir: *mut libc::c_char, pub pw_shell: *mut libc::c_char, } #[test] fn bindgen_test_layout_passwd() { const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); let ptr = UNINIT.as_ptr(); assert_eq!( ::std::mem::align_of::(), ::std::mem::align_of::<*mut libc::c_char>(), concat!("Alignment of ", stringify!(passwd)) ); let mut offset: usize = 0; assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).pw_name) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(passwd), "::", stringify!(pw_name) ) ); offset = aligned_offset::<*mut libc::c_char>(offset + ::std::mem::size_of::<*mut libc::c_char>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).pw_passwd) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(passwd), "::", stringify!(pw_passwd) ) ); offset = aligned_offset::<__uid_t>(offset + ::std::mem::size_of::<*mut libc::c_char>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).pw_uid) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(passwd), "::", stringify!(pw_uid) ) ); offset = aligned_offset::<__gid_t>(offset + ::std::mem::size_of::<__uid_t>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).pw_gid) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(passwd), "::", stringify!(pw_gid) ) ); offset = aligned_offset::<*mut libc::c_char>(offset + ::std::mem::size_of::<__gid_t>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).pw_gecos) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(passwd), "::", stringify!(pw_gecos) ) ); offset = aligned_offset::<*mut libc::c_char>(offset + ::std::mem::size_of::<*mut libc::c_char>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).pw_dir) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(passwd), "::", stringify!(pw_dir) ) ); offset = aligned_offset::<*mut libc::c_char>(offset + ::std::mem::size_of::<*mut libc::c_char>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).pw_shell) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(passwd), "::", stringify!(pw_shell) ) ); offset = aligned_offset::<*mut libc::c_void>(offset + ::std::mem::size_of::<*mut libc::c_char>()); assert_eq!( ::std::mem::size_of::(), offset, concat!("Size of: ", stringify!(passwd)) ); } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct group { pub gr_name: *mut libc::c_char, pub gr_passwd: *mut libc::c_char, pub gr_gid: __gid_t, pub gr_mem: *mut *mut libc::c_char, } #[test] fn bindgen_test_layout_group() { const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); let ptr = UNINIT.as_ptr(); assert_eq!( ::std::mem::align_of::(), ::std::mem::align_of::<*mut libc::c_char>(), concat!("Alignment of ", stringify!(group)) ); let mut offset: usize = 0; assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).gr_name) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(group), "::", stringify!(gr_name) ) ); offset = aligned_offset::<*mut libc::c_char>(offset + ::std::mem::size_of::<*mut libc::c_char>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).gr_passwd) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(group), "::", stringify!(gr_passwd) ) ); offset = aligned_offset::<__gid_t>(offset + ::std::mem::size_of::<*mut libc::c_char>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).gr_gid) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(group), "::", stringify!(gr_gid) ) ); offset = aligned_offset::<*mut libc::c_char>(offset + ::std::mem::size_of::<__gid_t>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).gr_mem) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(group), "::", stringify!(gr_mem) ) ); offset = aligned_offset::<*mut libc::c_void>(offset + ::std::mem::size_of::<*mut libc::c_char>()); assert_eq!( ::std::mem::size_of::(), offset, concat!("Size of: ", stringify!(group)) ); } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct spwd { pub sp_namp: *mut libc::c_char, pub sp_pwdp: *mut libc::c_char, pub sp_lstchg: libc::c_long, pub sp_min: libc::c_long, pub sp_max: libc::c_long, pub sp_warn: libc::c_long, pub sp_inact: libc::c_long, pub sp_expire: libc::c_long, pub sp_flag: libc::c_ulong, } #[test] fn bindgen_test_layout_spwd() { const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); let ptr = UNINIT.as_ptr(); assert_eq!( ::std::mem::align_of::(), ::std::mem::align_of::<*mut libc::c_char>(), concat!("Alignment of ", stringify!(spwd)) ); let mut offset: usize = 0; assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).sp_namp) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(spwd), "::", stringify!(sp_namp) ) ); offset = aligned_offset::<*mut libc::c_char>(offset + ::std::mem::size_of::<*mut libc::c_char>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).sp_pwdp) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(spwd), "::", stringify!(sp_pwdp) ) ); offset = aligned_offset::(offset + ::std::mem::size_of::<*mut libc::c_char>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).sp_lstchg) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(spwd), "::", stringify!(sp_lstchg) ) ); offset = aligned_offset::(offset + ::std::mem::size_of::()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).sp_min) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(spwd), "::", stringify!(sp_min) ) ); offset = aligned_offset::(offset + ::std::mem::size_of::()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).sp_max) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(spwd), "::", stringify!(sp_max) ) ); offset = aligned_offset::(offset + ::std::mem::size_of::()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).sp_warn) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(spwd), "::", stringify!(sp_warn) ) ); offset = aligned_offset::(offset + ::std::mem::size_of::()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).sp_inact) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(spwd), "::", stringify!(sp_inact) ) ); offset = aligned_offset::(offset + ::std::mem::size_of::()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).sp_expire) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(spwd), "::", stringify!(sp_expire) ) ); offset = aligned_offset::(offset + ::std::mem::size_of::()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).sp_flag) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(spwd), "::", stringify!(sp_flag) ) ); offset = aligned_offset::<*mut libc::c_void>(offset + ::std::mem::size_of::()); assert_eq!( ::std::mem::size_of::(), offset, concat!("Size of: ", stringify!(spwd)) ); } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct pam_modutil_privs { pub grplist: *mut gid_t, pub number_of_groups: libc::c_int, pub allocated: libc::c_int, pub old_gid: gid_t, pub old_uid: uid_t, pub is_dropped: libc::c_int, } #[test] fn bindgen_test_layout_pam_modutil_privs() { const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); let ptr = UNINIT.as_ptr(); assert_eq!( ::std::mem::align_of::(), ::std::mem::align_of::<*mut gid_t>(), concat!("Alignment of ", stringify!(pam_modutil_privs)) ); let mut offset: usize = 0; assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).grplist) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_modutil_privs), "::", stringify!(grplist) ) ); offset = aligned_offset::(offset + ::std::mem::size_of::<*mut gid_t>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).number_of_groups) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_modutil_privs), "::", stringify!(number_of_groups) ) ); offset = aligned_offset::(offset + ::std::mem::size_of::()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).allocated) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_modutil_privs), "::", stringify!(allocated) ) ); offset = aligned_offset::<__gid_t>(offset + ::std::mem::size_of::()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).old_gid) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_modutil_privs), "::", stringify!(old_gid) ) ); offset = aligned_offset::<__uid_t>(offset + ::std::mem::size_of::<__gid_t>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).old_uid) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_modutil_privs), "::", stringify!(old_uid) ) ); offset = aligned_offset::(offset + ::std::mem::size_of::<__uid_t>()); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).is_dropped) as usize - ptr as usize }, offset, concat!( "Offset of field: ", stringify!(pam_modutil_privs), "::", stringify!(is_dropped) ) ); offset = aligned_offset::<*mut libc::c_void>(offset + ::std::mem::size_of::()); assert_eq!( ::std::mem::size_of::(), offset, concat!("Size of: ", stringify!(pam_modutil_privs)) ); } #[cfg(test)] fn aligned_offset(offset: usize) -> usize { let offset = offset as isize; let alignment = ::std::mem::align_of::() as isize; (offset + (-offset).rem_euclid(alignment)) as usize } sudo-rs-0.2.2/src/pam/wrapper.h000064400000000000000000000003421046102023000144150ustar 00000000000000#include #include #include #include #include #include #include sudo-rs-0.2.2/src/su/cli.rs000064400000000000000000000557351046102023000135730ustar 00000000000000use std::{borrow::Cow, mem, path::PathBuf}; use crate::common::SudoString; use super::DEFAULT_USER; #[cfg_attr(test, derive(Debug, PartialEq))] pub enum SuAction { Help(SuHelpOptions), Version(SuVersionOptions), Run(SuRunOptions), } impl SuAction { pub fn from_env() -> Result { SuOptions::parse_arguments(std::env::args())?.validate() } #[cfg(test)] pub fn parse_arguments(args: impl IntoIterator) -> Result { SuOptions::parse_arguments(args)?.validate() } #[cfg(test)] pub fn try_into_run(self) -> Result { if let Self::Run(v) = self { Ok(v) } else { Err(self) } } } #[cfg_attr(test, derive(Debug, PartialEq))] pub struct SuHelpOptions {} impl TryFrom for SuHelpOptions { type Error = String; fn try_from(mut opts: SuOptions) -> Result { let help = mem::take(&mut opts.help); debug_assert!(help); reject_all("--help", opts)?; Ok(Self {}) } } #[cfg_attr(test, derive(Debug, PartialEq))] pub struct SuVersionOptions {} impl TryFrom for SuVersionOptions { type Error = String; fn try_from(mut opts: SuOptions) -> Result { let version = mem::take(&mut opts.version); debug_assert!(version); reject_all("--version", opts)?; Ok(Self {}) } } #[derive(Debug)] #[cfg_attr(test, derive(PartialEq))] pub struct SuRunOptions { // -c pub command: Option, // -g pub group: Vec, // -l pub login: bool, // -p pub preserve_environment: bool, // -s pub shell: Option, // -G pub supp_group: Vec, // -w pub whitelist_environment: Vec, pub user: SudoString, pub arguments: Vec, } #[cfg(test)] impl Default for SuRunOptions { fn default() -> Self { Self { command: None, group: vec![], login: false, preserve_environment: false, shell: None, supp_group: vec![], whitelist_environment: vec![], user: DEFAULT_USER.into(), arguments: vec![], } } } impl TryFrom for SuRunOptions { type Error = String; fn try_from(mut opts: SuOptions) -> Result { let command = mem::take(&mut opts.command); let group = mem::take(&mut opts.group); let login = mem::take(&mut opts.login); let preserve_environment = mem::take(&mut opts.preserve_environment); // always `true`; cannot be disabled via the CLI let _pty = mem::take(&mut opts.pty); let shell = mem::take(&mut opts.shell); let supp_group = mem::take(&mut opts.supp_group); let whitelist_environment = mem::take(&mut opts.whitelist_environment); let mut positional_args = mem::take(&mut opts.positional_args); reject_all("run mode", opts)?; let user = if positional_args.is_empty() { DEFAULT_USER.to_string() } else { positional_args.remove(0) }; let arguments = positional_args; Ok(Self { command, group, login, preserve_environment, shell, supp_group, whitelist_environment, user: SudoString::try_from(user).map_err(|err| err.to_string())?, arguments, }) } } fn reject_all(context: &str, opts: SuOptions) -> Result<(), String> { macro_rules! tuple { ($expr:expr) => { (&$expr as &dyn IsAbsent, { let name = concat!("--", stringify!($expr)); if name.contains('_') { Cow::Owned(name.replace('_', "-")) } else { Cow::Borrowed(name) } }) }; } let SuOptions { command, group, help, login, preserve_environment, pty, shell, supp_group, version, whitelist_environment, positional_args, } = opts; let flags = [ tuple!(command), tuple!(group), tuple!(help), tuple!(login), tuple!(preserve_environment), tuple!(pty), tuple!(shell), tuple!(supp_group), tuple!(version), tuple!(whitelist_environment), ]; for (value, name) in flags { ensure_is_absent(context, value, &name)?; } ensure_is_absent(context, &positional_args, "positional argument")?; Ok(()) } fn ensure_is_absent(context: &str, thing: &dyn IsAbsent, name: &str) -> Result<(), String> { if thing.is_absent() { Ok(()) } else { Err(format!("{context} conflicts with {name}")) } } trait IsAbsent { fn is_absent(&self) -> bool; } impl IsAbsent for bool { fn is_absent(&self) -> bool { !*self } } impl IsAbsent for Option { fn is_absent(&self) -> bool { self.is_none() } } impl IsAbsent for Vec { fn is_absent(&self) -> bool { self.is_empty() } } #[derive(Debug, Default, PartialEq)] struct SuOptions { // -c command: Option, // -g group: Vec, // -h help: bool, // -l login: bool, // -p preserve_environment: bool, // -P pty: bool, // -s shell: Option, // -G supp_group: Vec, // -V version: bool, // -w whitelist_environment: Vec, positional_args: Vec, } type OptionSetter = fn(&mut SuOptions, Option) -> Result<(), String>; struct SuOption { short: char, long: &'static str, takes_argument: bool, set: OptionSetter, } impl SuOptions { const SU_OPTIONS: &'static [SuOption] = &[ SuOption { short: 'c', long: "command", takes_argument: true, set: |sudo_options, argument| { if argument.is_some() { sudo_options.command = argument; Ok(()) } else { Err("no command provided".into()) } }, }, SuOption { short: 'g', long: "group", takes_argument: true, set: |sudo_options, argument| { if let Some(value) = argument { sudo_options.group.push(SudoString::from_cli_string(value)); Ok(()) } else { Err("no group provided".into()) } }, }, SuOption { short: 'G', long: "supp-group", takes_argument: true, set: |sudo_options, argument| { if let Some(value) = argument { sudo_options .supp_group .push(SudoString::from_cli_string(value)); Ok(()) } else { Err("no supplementary group provided".into()) } }, }, SuOption { short: 'l', long: "login", takes_argument: false, set: |sudo_options, _| { if sudo_options.login { Err(more_than_once("--login")) } else { sudo_options.login = true; Ok(()) } }, }, SuOption { short: 'p', long: "preserve-environment", takes_argument: false, set: |sudo_options, _| { if sudo_options.preserve_environment { Err(more_than_once("--preserve-environment")) } else { sudo_options.preserve_environment = true; Ok(()) } }, }, SuOption { short: 'm', long: "preserve-environment", takes_argument: false, set: |sudo_options, _| { if sudo_options.preserve_environment { Err(more_than_once("--preserve-environment")) } else { sudo_options.preserve_environment = true; Ok(()) } }, }, SuOption { short: 'P', long: "pty", takes_argument: false, set: |sudo_options, _| { if sudo_options.pty { Err(more_than_once("--pty")) } else { sudo_options.pty = true; Ok(()) } }, }, SuOption { short: 's', long: "shell", takes_argument: true, set: |sudo_options, argument| { if let Some(path) = argument { sudo_options.shell = Some(PathBuf::from(path)); Ok(()) } else { Err("no shell provided".into()) } }, }, SuOption { short: 'w', long: "whitelist-environment", takes_argument: true, set: |sudo_options, argument| { if let Some(list) = argument { let values: Vec = list.split(',').map(str::to_string).collect(); sudo_options.whitelist_environment.extend(values); Ok(()) } else { Err("no environment whitelist provided".into()) } }, }, SuOption { short: 'V', long: "version", takes_argument: false, set: |sudo_options, _| { if sudo_options.version { Err(more_than_once("--version")) } else { sudo_options.version = true; Ok(()) } }, }, SuOption { short: 'h', long: "help", takes_argument: false, set: |sudo_options, _| { if sudo_options.help { Err(more_than_once("--help")) } else { sudo_options.help = true; Ok(()) } }, }, ]; /// parse su arguments into SuOptions struct fn parse_arguments(arguments: impl IntoIterator) -> Result { let mut options: SuOptions = SuOptions::default(); let mut arg_iter = arguments.into_iter().skip(1); while let Some(arg) = arg_iter.next() { // - or -l or --login indicates a login shell should be started if arg == "-" { if options.login { return Err(more_than_once("--login")); } else { options.login = true; } } else if arg == "--" { // only positional arguments after this point options.positional_args.extend(arg_iter); break; // if the argument starts with -- it must be a full length option name } else if let Some(unprefixed) = arg.strip_prefix("--") { // parse assignments like '--group=ferris' if let Some((key, value)) = unprefixed.split_once('=') { // lookup the option by name if let Some(option) = Self::SU_OPTIONS.iter().find(|o| o.long == key) { // the value is already present, when the option does not take any arguments this results in an error if option.takes_argument { (option.set)(&mut options, Some(value.to_string()))?; } else { Err(format!("'--{}' does not take any arguments", option.long))?; } } else { Err(format!("unrecognized option '{}'", arg))?; } // lookup the option } else if let Some(option) = Self::SU_OPTIONS.iter().find(|o| o.long == unprefixed) { // try to parse an argument when the option needs an argument if option.takes_argument { let next_arg = arg_iter.next(); (option.set)(&mut options, next_arg)?; } else { (option.set)(&mut options, None)?; } } else { Err(format!("unrecognized option '{}'", arg))?; } } else if let Some(unprefixed) = arg.strip_prefix('-') { // flags can be grouped, so we loop over the the characters let mut chars = unprefixed.chars(); while let Some(curr) = chars.next() { // lookup the option if let Some(option) = Self::SU_OPTIONS.iter().find(|o| o.short == curr) { // try to parse an argument when one is necessary, either the rest of the current flag group or the next argument let rest = chars.as_str(); if option.takes_argument { let next_arg = if rest.is_empty() { arg_iter.next() } else { Some(rest.to_string()) }; (option.set)(&mut options, next_arg)?; // stop looping over flags if the current flag takes an argument break; } else { // parse flag without argument (option.set)(&mut options, None)?; } } else { Err(format!("unrecognized option '{}'", curr))?; } } } else { options.positional_args.push(arg); } } Ok(options) } fn validate(self) -> Result { let action = if self.help { SuAction::Help(self.try_into()?) } else if self.version { SuAction::Version(self.try_into()?) } else { SuAction::Run(self.try_into()?) }; Ok(action) } } fn more_than_once(flag: &str) -> String { format!("argument '{flag}' was provided more than once, but cannot be used multiple times") } #[cfg(test)] mod tests { use std::vec; use super::{SuAction, SuHelpOptions, SuOptions, SuRunOptions, SuVersionOptions}; fn parse(args: &[&str]) -> SuAction { let mut args = args.iter().map(|s| s.to_string()).collect::>(); args.insert(0, "/bin/su".to_string()); SuOptions::parse_arguments(args) .unwrap() .validate() .unwrap() } #[test] fn it_parses_group() { let expected = SuAction::Run(SuRunOptions { group: vec!["ferris".into()], ..<_>::default() }); assert_eq!(expected, parse(&["-g", "ferris"])); assert_eq!(expected, parse(&["-gferris"])); assert_eq!(expected, parse(&["--group", "ferris"])); assert_eq!(expected, parse(&["--group=ferris"])); } #[test] fn it_parses_shell_default() { let result = parse(&["--shell", "/bin/bash"]); assert_eq!( result, SuAction::Run(SuRunOptions { shell: Some("/bin/bash".into()), ..<_>::default() }) ); } #[test] fn it_parses_whitelist() { let result = parse(&["-w", "FOO,BAR"]); assert_eq!( result, SuAction::Run(SuRunOptions { whitelist_environment: vec!["FOO".to_string(), "BAR".to_string()], ..<_>::default() }) ); } #[test] fn it_parses_combined_options() { let expected = SuAction::Run(SuRunOptions { login: true, ..<_>::default() }); assert_eq!(expected, parse(&["-Pl"])); assert_eq!(expected, parse(&["-lP"])); } #[test] fn it_parses_combined_options_and_arguments() { let expected = SuAction::Run(SuRunOptions { login: true, shell: Some("/bin/bash".into()), ..<_>::default() }); assert_eq!(expected, parse(&["-Pls/bin/bash"])); assert_eq!(expected, parse(&["-Pls", "/bin/bash"])); assert_eq!(expected, parse(&["-Pl", "-s/bin/bash"])); assert_eq!(expected, parse(&["-lP", "-s", "/bin/bash"])); assert_eq!(expected, parse(&["-lP", "--shell=/bin/bash"])); assert_eq!(expected, parse(&["-lP", "--shell", "/bin/bash"])); } #[test] fn it_parses_an_user() { let expected = SuAction::Run(SuRunOptions { user: "ferris".into(), ..<_>::default() }); assert_eq!(expected, parse(&["-P", "ferris"])); assert_eq!(expected, parse(&["ferris", "-P"])); } #[test] fn it_parses_arguments() { let expected = SuAction::Run(SuRunOptions { user: "ferris".into(), arguments: vec!["script.sh".to_string()], ..<_>::default() }); assert_eq!(expected, parse(&["-P", "ferris", "script.sh"])); } #[test] fn it_parses_command() { let expected = SuAction::Run(SuRunOptions { command: Some("'echo hi'".to_string()), ..<_>::default() }); assert_eq!(expected, parse(&["-c", "'echo hi'"])); assert_eq!(expected, parse(&["-c'echo hi'"])); assert_eq!(expected, parse(&["--command", "'echo hi'"])); assert_eq!(expected, parse(&["--command='echo hi'"])); let expected = SuAction::Run(SuRunOptions { command: Some("env".to_string()), ..<_>::default() }); assert_eq!(expected, parse(&["-c", "env"])); assert_eq!(expected, parse(&["-cenv"])); assert_eq!(expected, parse(&["--command", "env"])); assert_eq!(expected, parse(&["--command=env"])); } #[test] fn it_parses_supplementary_group() { let expected = SuAction::Run(SuRunOptions { supp_group: vec!["ferris".into()], ..<_>::default() }); assert_eq!(expected, parse(&["-G", "ferris"])); assert_eq!(expected, parse(&["-Gferris"])); assert_eq!(expected, parse(&["--supp-group", "ferris"])); assert_eq!(expected, parse(&["--supp-group=ferris"])); } #[test] fn it_parses_multiple_supplementary_groups() { let expected = SuAction::Run(SuRunOptions { supp_group: vec!["ferris".into(), "krabbetje".into(), "krabbe".into()], ..<_>::default() }); assert_eq!( expected, parse(&["-G", "ferris", "-G", "krabbetje", "--supp-group", "krabbe"]) ); } #[test] fn it_parses_login() { let expected = SuAction::Run(SuRunOptions { login: true, ..<_>::default() }); assert_eq!(expected, parse(&["-"])); assert_eq!(expected, parse(&["-l"])); assert_eq!(expected, parse(&["--login"])); } #[test] fn it_parses_pty() { let expected = SuAction::Run(<_>::default()); assert_eq!(expected, parse(&["-P"])); assert_eq!(expected, parse(&["--pty"])); } #[test] fn it_parses_shell() { let expected = SuAction::Run(SuRunOptions { shell: Some("some-shell".into()), ..<_>::default() }); assert_eq!(expected, parse(&["-s", "some-shell"])); assert_eq!(expected, parse(&["-ssome-shell"])); assert_eq!(expected, parse(&["--shell", "some-shell"])); assert_eq!(expected, parse(&["--shell=some-shell"])); } #[test] fn it_parses_whitelist_environment() { let expected = SuAction::Run(SuRunOptions { whitelist_environment: vec!["FOO".to_string(), "BAR".to_string()], ..<_>::default() }); assert_eq!(expected, parse(&["-w", "FOO,BAR"])); assert_eq!(expected, parse(&["-wFOO,BAR"])); assert_eq!(expected, parse(&["--whitelist-environment", "FOO,BAR"])); assert_eq!(expected, parse(&["--whitelist-environment=FOO,BAR"])); } #[test] fn it_parses_help() { let expected = SuAction::Help(SuHelpOptions {}); assert_eq!(expected, parse(&["-h"])); assert_eq!(expected, parse(&["--help"])); } #[test] fn it_parses_version() { let expected = SuAction::Version(SuVersionOptions {}); assert_eq!(expected, parse(&["-V"])); assert_eq!(expected, parse(&["--version"])); } #[test] fn short_flag_whitespace() { let expected = SuAction::Run(SuRunOptions { group: vec![" ".into()], ..<_>::default() }); assert_eq!(expected, parse(&["-g "])); } #[test] fn short_flag_whitespace_positional_argument() { let expected = SuAction::Run(SuRunOptions { group: vec![" ".into()], user: "ghost".into(), ..<_>::default() }); assert_eq!(expected, parse(&["-g ", "ghost"])); } #[test] fn long_flag_equal_whitespace() { let expected = SuAction::Run(SuRunOptions { group: vec![" ".into()], ..<_>::default() }); assert_eq!(expected, parse(&["--group= "])); } #[test] fn flag_after_positional_argument() { let expected = SuAction::Run(SuRunOptions { arguments: vec![], login: true, user: "ferris".into(), ..<_>::default() }); assert_eq!(expected, parse(&["ferris", "-l"])); } #[test] fn flags_after_dash() { let expected = SuAction::Run(SuRunOptions { command: Some("echo".to_string()), login: true, ..<_>::default() }); assert_eq!(expected, parse(&["-", "-c", "echo"])); } #[test] fn only_positional_args_after_dashdash() { let expected = SuAction::Run(SuRunOptions { user: "ferris".into(), arguments: vec!["-c".to_string(), "echo".to_string()], ..<_>::default() }); assert_eq!(expected, parse(&["--", "ferris", "-c", "echo"])); } #[test] fn repeated_boolean_flag() { let f = |s: &str| s.to_string(); assert!(SuOptions::parse_arguments(["su", "-l", "-l"].map(f)).is_err()); assert!(SuOptions::parse_arguments(["su", "-", "-l"].map(f)).is_err()); assert!(SuOptions::parse_arguments(["su", "--login", "-l"].map(f)).is_err()); assert!(SuOptions::parse_arguments(["su", "-p", "-p"].map(f)).is_err()); assert!(SuOptions::parse_arguments(["su", "-p", "--preserve-environment"].map(f)).is_err()); } } sudo-rs-0.2.2/src/su/context.rs000064400000000000000000000213731046102023000144770ustar 00000000000000use std::{ env, ffi::OsString, fs, io, path::{Path, PathBuf}, }; use crate::common::{error::Error, resolve::CurrentUser, Environment}; use crate::common::{resolve::is_valid_executable, SudoPath}; use crate::exec::RunOptions; use crate::log::user_warn; use crate::system::{Group, Process, User}; use super::cli::SuRunOptions; const VALID_LOGIN_SHELLS_LIST: &str = "/etc/shells"; const FALLBACK_LOGIN_SHELL: &str = "/bin/sh"; const PATH_MAILDIR: &str = env!("PATH_MAILDIR"); const PATH_DEFAULT: &str = env!("SU_PATH_DEFAULT"); const PATH_DEFAULT_ROOT: &str = env!("SU_PATH_DEFAULT_ROOT"); #[derive(Debug)] pub(crate) struct SuContext { command: PathBuf, arguments: Vec, options: SuRunOptions, pub(crate) environment: Environment, user: User, requesting_user: CurrentUser, group: Group, pub(crate) process: Process, } /// check that a shell is not restricted / exists in /etc/shells fn is_restricted(shell: &Path) -> bool { if let Some(pattern) = shell.as_os_str().to_str() { if let Ok(contents) = fs::read_to_string(VALID_LOGIN_SHELLS_LIST) { return !contents.lines().any(|l| l == pattern); } else { return FALLBACK_LOGIN_SHELL != pattern; } } true } impl SuContext { pub(crate) fn from_env(options: SuRunOptions) -> Result { let process = crate::system::Process::new(); // resolve environment, reset if this is a login let mut environment = if options.login { Environment::default() } else { env::vars_os().collect::() }; // Don't reset the environment variables specified in the // comma-separated list when clearing the environment for // --login. The whitelist is ignored for the environment // variables HOME, SHELL, USER, LOGNAME, and PATH. if options.login { if let Some(value) = env::var_os("TERM") { environment.insert("TERM".into(), value); } for name in options.whitelist_environment.iter() { if let Some(value) = env::var_os(name) { environment.insert(name.into(), value); } } } let requesting_user = CurrentUser::resolve()?; // resolve target user let mut user = User::from_name(options.user.as_cstr())? .ok_or_else(|| Error::UserNotFound(options.user.clone().into()))?; // check the current user is root let is_current_root = User::real_uid() == 0; let is_target_root = options.user == "root"; // only root can set a (additional) group if !is_current_root && (!options.supp_group.is_empty() || !options.group.is_empty()) { return Err(Error::Options( "only root can specify alternative groups".to_owned(), )); } // resolve target group let mut group = Group::from_gid(user.gid)?.ok_or_else(|| Error::GroupNotFound(user.gid.to_string()))?; if !options.supp_group.is_empty() || !options.group.is_empty() { user.groups.clear(); } for group_name in options.group.iter() { let primary_group = Group::from_name(group_name.as_cstr())? .ok_or_else(|| Error::GroupNotFound(group_name.clone().into()))?; // last argument is the primary group group = primary_group.clone(); user.groups.push(primary_group.gid); } // add additional group if current user is root for (index, group_name) in options.supp_group.iter().enumerate() { let supp_group = Group::from_name(group_name.as_cstr())? .ok_or_else(|| Error::GroupNotFound(group_name.clone().into()))?; // set primary group if none was provided if index == 0 && options.group.is_empty() { group = supp_group.clone(); } user.groups.push(supp_group.gid); } // the shell specified with --shell // the shell specified in the environment variable SHELL, if the --preserve-environment option is used // the shell listed in the passwd entry of the target user let user_shell = user.shell.clone(); let mut command = options .shell .as_ref() .cloned() .or_else(|| { if options.preserve_environment && is_current_root { environment.get(&OsString::from("SHELL")).map(|v| v.into()) } else { None } }) .unwrap_or(user_shell.clone()); // If the target user has a restricted shell (i.e. the shell field of // this user's entry in /etc/passwd is not listed in /etc/shells), // then the --shell option or the $SHELL environment variable won't be // taken into account, unless su is called by root. if is_restricted(user_shell.as_path()) && !is_current_root { user_warn!( "using restricted shell {}", user_shell.as_os_str().to_string_lossy() ); command = user_shell; } if !command.exists() { return Err(Error::CommandNotFound(command)); } if !is_valid_executable(&command) { return Err(Error::InvalidCommand(command)); } // pass command to shell let arguments = if let Some(command) = &options.command { vec!["-c".to_owned(), command.to_owned()] } else { options.arguments.clone() }; if options.login { environment.insert( "PATH".into(), if is_target_root { PATH_DEFAULT_ROOT } else { PATH_DEFAULT } .into(), ); } if !options.preserve_environment { // extend environment with fixed variables environment.insert("HOME".into(), user.home.clone().into()); environment.insert("SHELL".into(), command.clone().into()); environment.insert( "MAIL".into(), format!("{PATH_MAILDIR}/{}", user.name).into(), ); if !is_target_root || options.login { environment.insert("USER".into(), options.user.clone().into()); environment.insert("LOGNAME".into(), options.user.clone().into()); } } Ok(SuContext { command, arguments, options, environment, user, requesting_user, group, process, }) } } impl RunOptions for SuContext { fn command(&self) -> io::Result<&PathBuf> { Ok(&self.command) } fn arguments(&self) -> &Vec { &self.arguments } fn arg0(&self) -> Option<&PathBuf> { None } fn chdir(&self) -> Option<&SudoPath> { None } fn is_login(&self) -> bool { self.options.login } fn user(&self) -> &crate::system::User { &self.user } fn requesting_user(&self) -> &User { &self.requesting_user } fn group(&self) -> &crate::system::Group { &self.group } fn pid(&self) -> i32 { self.process.pid } fn use_pty(&self) -> bool { true } } #[cfg(test)] mod tests { use std::path::PathBuf; use crate::{ common::Error, su::cli::{SuAction, SuRunOptions}, }; use super::SuContext; fn get_options(args: &[&str]) -> SuRunOptions { let mut args = args.iter().map(|s| s.to_string()).collect::>(); args.insert(0, "/bin/su".to_string()); SuAction::parse_arguments(args) .unwrap() .try_into_run() .unwrap() } #[test] fn su_to_root() { let options = get_options(&["root"]); let context = SuContext::from_env(options).unwrap(); assert_eq!(context.user.name, "root"); } #[test] fn group_as_non_root() { let options = get_options(&["-g", "root"]); let result = SuContext::from_env(options); let expected = Error::Options("only root can specify alternative groups".to_owned()); assert!(result.is_err()); assert_eq!(format!("{}", result.err().unwrap()), format!("{expected}")); } #[test] fn invalid_shell() { let options = get_options(&["-s", "/not/a/shell"]); let result = SuContext::from_env(options); let expected = Error::CommandNotFound(PathBuf::from("/not/a/shell")); assert!(result.is_err()); assert_eq!(format!("{}", result.err().unwrap()), format!("{expected}")); } } sudo-rs-0.2.2/src/su/help.rs000064400000000000000000000017421046102023000137410ustar 00000000000000pub const USAGE_MSG: &str = "Usage: su [options] [-] [ [...]]"; const DESCRIPTOR: &str = "Change the effective user ID and group ID to that of . A mere - implies -l. If is not given, root is assumed."; const HELP_MSG: &str = "Options: -m, -p, --preserve-environment do not reset environment variables -w, --whitelist-environment don't reset specified variables -g, --group specify the primary group -G, --supp-group specify a supplemental group -, -l, --login make the shell a login shell -c, --command pass a single command to the shell with -c -s, --shell run if /etc/shells allows it -P, --pty create a new pseudo-terminal -h, --help display this help -V, --version display version "; pub fn long_help_message() -> String { format!("{USAGE_MSG}\n\n{DESCRIPTOR}\n\n{HELP_MSG}") } sudo-rs-0.2.2/src/su/mod.rs000064400000000000000000000111721046102023000135660ustar 00000000000000use crate::common::error::Error; use crate::exec::{ExecOutput, ExitReason, RunOptions}; use crate::log::user_warn; use crate::pam::{CLIConverser, PamContext, PamError, PamErrorType}; use crate::system::term::current_tty_name; use std::{env, process}; use cli::SuAction; use context::SuContext; use help::{long_help_message, USAGE_MSG}; use self::cli::SuRunOptions; mod cli; mod context; mod help; const DEFAULT_USER: &str = "root"; const VERSION: &str = env!("CARGO_PKG_VERSION"); fn authenticate( requesting_user: &str, user: &str, login: bool, ) -> Result, Error> { let context = if login { "su-l" } else { "su" }; let use_stdin = true; let mut pam = PamContext::builder_cli("su", use_stdin, Default::default()) .target_user(user) .service_name(context) .build()?; pam.set_requesting_user(requesting_user)?; // attempt to set the TTY this session is communicating on if let Ok(pam_tty) = current_tty_name() { pam.set_tty(&pam_tty)?; } pam.mark_silent(true); pam.mark_allow_null_auth_token(false); pam.set_user(user)?; let mut max_tries = 3; let mut current_try = 0; loop { current_try += 1; match pam.authenticate() { // there was no error, so authentication succeeded Ok(_) => break, // maxtries was reached, pam does not allow any more tries Err(PamError::Pam(PamErrorType::MaxTries, _)) => { return Err(Error::MaxAuthAttempts(current_try)); } // there was an authentication error, we can retry Err(PamError::Pam(PamErrorType::AuthError, _)) => { max_tries -= 1; if max_tries == 0 { return Err(Error::MaxAuthAttempts(current_try)); } else { user_warn!("Authentication failed, try again."); } } // there was another pam error, return the error Err(e) => { return Err(e.into()); } } } pam.validate_account_or_change_auth_token()?; pam.open_session()?; Ok(pam) } fn run(options: SuRunOptions) -> Result<(), Error> { // lookup user and build context object let context = SuContext::from_env(options)?; // authenticate the target user let mut pam: PamContext = authenticate( &context.requesting_user().name, &context.user().name, context.is_login(), )?; // su in all cases uses PAM (pam_getenvlist(3)) to do the // final environment modification. Command-line options such as // --login and --preserve-environment affect the environment before // it is modified by PAM. let mut environment = context.environment.clone(); environment.extend(pam.env()?); let pid = context.process.pid; // run command and return corresponding exit code let ExecOutput { command_exit_reason, restore_signal_handlers, } = crate::exec::run_command(&context, environment)?; // closing the pam session is best effort, if any error occurs we cannot // do anything with it let _ = pam.close_session(); // Run any clean-up code before this line. restore_signal_handlers(); match command_exit_reason { ExitReason::Code(code) => process::exit(code), ExitReason::Signal(signal) => { crate::system::kill(pid, signal)?; } } Ok(()) } pub fn main() { crate::log::SudoLogger::new("su: ").into_global_logger(); let action = match SuAction::from_env() { Ok(action) => action, Err(error) => { println_ignore_io_error!("su: {error}\n{USAGE_MSG}"); std::process::exit(1); } }; match action { SuAction::Help(_) => { println_ignore_io_error!("{}", long_help_message()); std::process::exit(0); } SuAction::Version(_) => { eprintln_ignore_io_error!("su-rs {VERSION}"); std::process::exit(0); } SuAction::Run(options) => match run(options) { Err(Error::CommandNotFound(c)) => { eprintln_ignore_io_error!("su: {}", Error::CommandNotFound(c)); std::process::exit(127); } Err(Error::InvalidCommand(c)) => { eprintln_ignore_io_error!("su: {}", Error::InvalidCommand(c)); std::process::exit(126); } Err(error) => { eprintln_ignore_io_error!("su: {error}"); std::process::exit(1); } _ => {} }, }; } sudo-rs-0.2.2/src/sudo/cli/help.rs000064400000000000000000000032501046102023000150270ustar 00000000000000pub const USAGE_MSG: &str = "\ usage: sudo -h | -K | -k | -V usage: sudo -v [-knS] [-g group] [-u user] usage: sudo -l [-knS] [-g group] [-U user] [-u user] [command [arg ...]] usage: sudo [-knS] [-D directory] [-g group] [-u user] [-i | -s] [command [arg ...]] usage: sudo -e [-knS] [-D directory] [-g group] [-u user] file ..."; const DESCRIPTOR: &str = "sudo - run commands as another user"; const HELP_MSG: &str = "Options: -D, --chdir=directory change the working directory before running command -g, --group=group run command as the specified group name or ID -h, --help display help message and exit -i, --login run login shell as the target user; a command may also be specified -K, --remove-timestamp remove timestamp file completely -k, --reset-timestamp invalidate timestamp file -l, --list list user's privileges or check a specific command; use twice for longer format -n, --non-interactive non-interactive mode, no prompts are used -S, --stdin read password from standard input -s, --shell run shell as the target user; a command may also be specified -U, --other-user=user in list mode, display privileges for user -u, --user=user run command (or edit file) as specified user name or ID -V, --version display version information and exit -v, --validate update user's timestamp without running a command -- stop processing command line arguments"; pub fn long_help_message() -> String { format!("{DESCRIPTOR}\n{USAGE_MSG}\n{HELP_MSG}") } sudo-rs-0.2.2/src/sudo/cli/mod.rs000064400000000000000000000613131046102023000146620ustar 00000000000000#![forbid(unsafe_code)] use std::{borrow::Cow, mem}; use crate::common::context::{ContextAction, OptionsForContext}; use crate::common::{SudoPath, SudoString}; pub mod help; #[cfg(test)] mod tests; pub enum SudoAction { Edit(SudoEditOptions), Help(SudoHelpOptions), List(SudoListOptions), RemoveTimestamp(SudoRemoveTimestampOptions), ResetTimestamp(SudoResetTimestampOptions), Run(SudoRunOptions), Validate(SudoValidateOptions), Version(SudoVersionOptions), } impl SudoAction { /// try to parse and environment variable assignment /// parse command line arguments from the environment and handle errors pub fn from_env() -> Result { Self::try_parse_from(std::env::args()) } pub fn try_parse_from(iter: I) -> Result where I: IntoIterator, T: Into + Clone, { let opts = SudoOptions::try_parse_from(iter)?; opts.validate() } #[cfg(test)] #[must_use] pub fn is_edit(&self) -> bool { matches!(self, Self::Edit(..)) } #[cfg(test)] #[must_use] pub fn is_help(&self) -> bool { matches!(self, Self::Help(..)) } #[cfg(test)] #[must_use] pub fn is_remove_timestamp(&self) -> bool { matches!(self, Self::RemoveTimestamp(..)) } #[cfg(test)] #[must_use] pub fn is_reset_timestamp(&self) -> bool { matches!(self, Self::ResetTimestamp(..)) } #[cfg(test)] #[must_use] pub fn is_list(&self) -> bool { matches!(self, Self::List(..)) } #[cfg(test)] #[must_use] pub fn is_version(&self) -> bool { matches!(self, Self::Version(..)) } #[cfg(test)] #[must_use] pub fn is_validate(&self) -> bool { matches!(self, Self::Validate(..)) } #[cfg(test)] pub fn try_into_run(self) -> Result { if let Self::Run(v) = self { Ok(v) } else { Err(self) } } #[cfg(test)] #[must_use] pub fn is_run(&self) -> bool { matches!(self, Self::Run(..)) } } // sudo -h | -K | -k | -V pub struct SudoHelpOptions {} impl TryFrom for SudoHelpOptions { type Error = String; fn try_from(mut opts: SudoOptions) -> Result { // see `SudoOptions::validate` let help = mem::take(&mut opts.help); debug_assert!(help); reject_all("--help", opts)?; Ok(Self {}) } } // sudo -h | -K | -k | -V pub struct SudoVersionOptions {} impl TryFrom for SudoVersionOptions { type Error = String; fn try_from(mut opts: SudoOptions) -> Result { // see `SudoOptions::validate` let version = mem::take(&mut opts.version); debug_assert!(version); reject_all("--version", opts)?; Ok(Self {}) } } // sudo -h | -K | -k | -V pub struct SudoRemoveTimestampOptions {} impl TryFrom for SudoRemoveTimestampOptions { type Error = String; fn try_from(mut opts: SudoOptions) -> Result { // see `SudoOptions::validate` let remove_timestamp = mem::take(&mut opts.remove_timestamp); debug_assert!(remove_timestamp); reject_all("--remove-timestamp", opts)?; Ok(Self {}) } } // sudo -h | -K | -k | -V pub struct SudoResetTimestampOptions {} impl TryFrom for SudoResetTimestampOptions { type Error = String; fn try_from(mut opts: SudoOptions) -> Result { // see `SudoOptions::validate` let reset_timestamp = mem::take(&mut opts.reset_timestamp); debug_assert!(reset_timestamp); reject_all("--reset-timestamp", opts)?; Ok(Self {}) } } // sudo -v [-ABkNnS] [-g group] [-h host] [-p prompt] [-u user] pub struct SudoValidateOptions { // -k pub reset_timestamp: bool, // -n pub non_interactive: bool, // -S pub stdin: bool, // -g pub group: Option, // -u pub user: Option, } impl TryFrom for SudoValidateOptions { type Error = String; fn try_from(mut opts: SudoOptions) -> Result { // see `SudoOptions::validate` let validate = mem::take(&mut opts.validate); debug_assert!(validate); let reset_timestamp = mem::take(&mut opts.reset_timestamp); let non_interactive = mem::take(&mut opts.non_interactive); let stdin = mem::take(&mut opts.stdin); let group = mem::take(&mut opts.group); let user = mem::take(&mut opts.user); reject_all("--validate", opts)?; Ok(Self { reset_timestamp, non_interactive, stdin, group, user, }) } } // sudo -e [-ABkNnS] [-r role] [-t type] [-C num] [-D directory] [-g group] [-h host] [-p prompt] [-R directory] [-T timeout] [-u user] file ... pub struct SudoEditOptions { // -k pub reset_timestamp: bool, // -n pub non_interactive: bool, // -S pub stdin: bool, // -D pub chdir: Option, // -g pub group: Option, // -u pub user: Option, pub positional_args: Vec, } impl TryFrom for SudoEditOptions { type Error = String; fn try_from(mut opts: SudoOptions) -> Result { // see `SudoOptions::validate` let edit = mem::take(&mut opts.edit); debug_assert!(edit); let reset_timestamp = mem::take(&mut opts.reset_timestamp); let non_interactive = mem::take(&mut opts.non_interactive); let stdin = mem::take(&mut opts.stdin); let chdir = mem::take(&mut opts.chdir); let group = mem::take(&mut opts.group); let user = mem::take(&mut opts.user); let positional_args = mem::take(&mut opts.positional_args); reject_all("--edit", opts)?; if positional_args.is_empty() { return Err("must specify at least one file path".into()); } Ok(Self { reset_timestamp, non_interactive, stdin, chdir, group, user, positional_args, }) } } // sudo -l [-ABkNnS] [-g group] [-h host] [-p prompt] [-U user] [-u user] [command [arg ...]] pub struct SudoListOptions { // -l OR -l -l pub list: List, // -k pub reset_timestamp: bool, // -n pub non_interactive: bool, // -S pub stdin: bool, // -g pub group: Option, // -U pub other_user: Option, // -u pub user: Option, pub positional_args: Vec, } impl TryFrom for SudoListOptions { type Error = String; fn try_from(mut opts: SudoOptions) -> Result { let list = opts.list.take().unwrap(); let reset_timestamp = mem::take(&mut opts.reset_timestamp); let non_interactive = mem::take(&mut opts.non_interactive); let stdin = mem::take(&mut opts.stdin); let group = mem::take(&mut opts.group); let other_user = mem::take(&mut opts.other_user); let user = mem::take(&mut opts.user); let positional_args = mem::take(&mut opts.positional_args); // when present, `-u` must be accompanied by a command let has_command = !positional_args.is_empty(); let valid_user_flag = user.is_none() || has_command; if !valid_user_flag { return Err("'--user' flag must be accompanied by a command".into()); } reject_all("--list", opts)?; Ok(Self { list, reset_timestamp, non_interactive, stdin, group, other_user, user, positional_args, }) } } // sudo [-ABbEHnPS] [-C num] [-D directory] [-g group] [-h host] [-p prompt] [-R directory] [-T timeout] [-u user] [VAR=value] [-i | -s] [command [arg ...]] pub struct SudoRunOptions { // -E pub preserve_env: PreserveEnv, // -k pub reset_timestamp: bool, // -n pub non_interactive: bool, // -S pub stdin: bool, // -D pub chdir: Option, // -g pub group: Option, // -u pub user: Option, // VAR=value pub env_var_list: Vec<(String, String)>, // -i pub login: bool, // -s pub shell: bool, pub positional_args: Vec, } impl TryFrom for SudoRunOptions { type Error = String; fn try_from(mut opts: SudoOptions) -> Result { let preserve_env = mem::take(&mut opts.preserve_env); let reset_timestamp = mem::take(&mut opts.reset_timestamp); let non_interactive = mem::take(&mut opts.non_interactive); let stdin = mem::take(&mut opts.stdin); let chdir = mem::take(&mut opts.chdir); let group = mem::take(&mut opts.group); let user = mem::take(&mut opts.user); let env_var_list = mem::take(&mut opts.env_var_list); let login = mem::take(&mut opts.login); let shell = mem::take(&mut opts.shell); let positional_args = mem::take(&mut opts.positional_args); let context = match (login, shell, positional_args.is_empty()) { (true, false, _) => "--login", (false, true, _) => "--shell", (false, false, false) => "command (positional argument)", (true, true, _) => return Err("--login conflicts with --shell".into()), (false, false, true) => { if cfg!(debug_assertions) { // see `SudoOptions::validate` panic!(); } else { return Err( "expected one of: --login, --shell, a command as a positional argument" .into(), ); } } }; reject_all(context, opts)?; Ok(Self { preserve_env, reset_timestamp, non_interactive, stdin, chdir, group, user, env_var_list, login, shell, positional_args, }) } } #[derive(Default)] struct SudoOptions { // -D chdir: Option, // -g group: Option, // -i login: bool, // -n non_interactive: bool, // -U other_user: Option, // -E preserve_env: PreserveEnv, // -s shell: bool, // -S stdin: bool, // -u user: Option, // additional environment env_var_list: Vec<(String, String)>, /* actions */ // -e edit: bool, // -h help: bool, // -l list: Option, // -K remove_timestamp: bool, // -k reset_timestamp: bool, // -v validate: bool, // -V version: bool, // arguments passed straight through, either seperated by -- or just trailing. positional_args: Vec, } #[derive(Default, Debug, Clone, PartialEq)] pub enum PreserveEnv { #[default] Nothing, Everything, Only(Vec), } impl PreserveEnv { #[cfg(test)] pub fn try_into_only(self) -> Result, Self> { if let Self::Only(v) = self { Ok(v) } else { Err(self) } } pub fn is_nothing(&self) -> bool { matches!(self, Self::Nothing) } } #[derive(Debug, Clone, PartialEq)] pub enum List { Once, Verbose, } impl List { #[must_use] pub fn is_verbose(&self) -> bool { matches!(self, Self::Verbose) } } enum SudoArg { Flag(String), Argument(String, String), Environment(String, String), Rest(Vec), } impl SudoArg { const TAKES_ARGUMENT_SHORT: &'static [char] = &['D', 'g', 'h', 'R', 'U', 'u']; const TAKES_ARGUMENT: &'static [&'static str] = &["chdir", "group", "host", "chroot", "other-user", "user"]; /// argument assignments and shorthand options preprocessing fn normalize_arguments(iter: I) -> Result, String> where I: IntoIterator, { // the first argument is the sudo command - so we can skip it let mut arg_iter = iter.into_iter().skip(1); let mut processed = vec![]; while let Some(arg) = arg_iter.next() { if arg == "--" { processed.push(SudoArg::Rest(arg_iter.collect())); break; } else if let Some(unprefixed) = arg.strip_prefix("--") { if let Some((key, value)) = unprefixed.split_once('=') { // convert assignment to normal tokens // only accept arguments when one is expected // `--preserve-env` is special as it only takes an argument using this `key=value` syntax if !Self::TAKES_ARGUMENT.contains(&key) && key != "preserve-env" { Err(format!("'{}' does not take any arguments", key))?; } processed.push(SudoArg::Argument("--".to_string() + key, value.to_string())); } else if Self::TAKES_ARGUMENT.contains(&unprefixed) { if let Some(next) = arg_iter.next() { processed.push(SudoArg::Argument(arg, next)); } else { Err(format!("'{}' expects an argument", &arg))?; } } else { processed.push(SudoArg::Flag(arg)); } } else if let Some(unprefixed) = arg.strip_prefix('-') { // split combined shorthand options let mut chars = unprefixed.chars(); while let Some(curr) = chars.next() { let flag = format!("-{curr}"); // convert option argument to separate segment if Self::TAKES_ARGUMENT_SHORT.contains(&curr) { let rest = chars.as_str(); let next = chars.next(); // assignment syntax is not accepted for shorthand arguments if next == Some('=') { Err("invalid option '='")?; } if next.is_some() { processed.push(SudoArg::Argument(flag, rest.to_string())); } else if let Some(next) = arg_iter.next() { processed.push(SudoArg::Argument(flag, next)); } else if curr == 'h' { // short version of --help has no arguments processed.push(SudoArg::Flag(flag)); } else { Err(format!("'-{}' expects an argument", curr))?; } break; } else { processed.push(SudoArg::Flag(flag)); } } } else if let Some((key, value)) = try_to_env_var(&arg) { processed.push(SudoArg::Environment(key, value)); } else { let mut rest = vec![arg]; rest.extend(arg_iter); processed.push(SudoArg::Rest(rest)); break; } } Ok(processed) } } impl SudoOptions { fn validate(self) -> Result { let action = if self.help { SudoAction::Help(self.try_into()?) } else if self.version { SudoAction::Version(self.try_into()?) } else if self.remove_timestamp { SudoAction::RemoveTimestamp(self.try_into()?) } else if self.validate { SudoAction::Validate(self.try_into()?) } else if self.list.is_some() { SudoAction::List(self.try_into()?) } else if self.edit { SudoAction::Edit(self.try_into()?) } else { let is_run = self.login | self.shell | !self.positional_args.is_empty(); if is_run { SudoAction::Run(self.try_into()?) } else if self.reset_timestamp { SudoAction::ResetTimestamp(self.try_into()?) } else { return Err("expected one of these actions: --help, --version, --remove-timestamp, --validate, --list, --edit, --login, --shell, a command as a positional argument, --reset-timestamp".into()); } }; Ok(action) } /// parse an iterator over command line arguments fn try_parse_from(iter: I) -> Result where I: IntoIterator, T: Into + Clone, { let mut options = Self::default(); let arg_iter = SudoArg::normalize_arguments(iter.into_iter().map(Into::into))? .into_iter() .peekable(); for arg in arg_iter { match arg { SudoArg::Flag(flag) => match flag.as_str() { "-E" | "--preserve-env" => { options.preserve_env = PreserveEnv::Everything; } "-e" | "--edit" => { options.edit = true; } "-H" | "--set-home" => { // this option is ignored, since it is the default for sudo-rs; but accept // it for backwards compatibility reasons } "-h" | "--help" => { options.help = true; } "-i" | "--login" => { options.login = true; } "-K" | "--remove-timestamp" => { options.remove_timestamp = true; } "-k" | "--reset-timestamp" => { options.reset_timestamp = true; } "-l" | "--list" => match options.list { None => options.list = Some(List::Once), Some(List::Once) => options.list = Some(List::Verbose), Some(List::Verbose) => {} }, "-n" | "--non-interactive" => { options.non_interactive = true; } "-S" | "--stdin" => { options.stdin = true; } "-s" | "--shell" => { options.shell = true; } "-V" | "--version" => { options.version = true; } "-v" | "--validate" => { options.validate = true; } _option => { Err("invalid option provided")?; } }, SudoArg::Argument(option, value) => match option.as_str() { "-D" | "--chdir" => { options.chdir = Some(SudoPath::from_cli_string(value)); } "-E" | "--preserve-env" => { let split_value = || value.split(',').map(str::to_string); match &mut options.preserve_env { PreserveEnv::Nothing => { options.preserve_env = PreserveEnv::Only(split_value().collect()) } PreserveEnv::Everything => {} PreserveEnv::Only(list) => list.extend(split_value()), } // options.preserve_env = value.split(',').map(str::to_string).collect() } "-g" | "--group" => { options.group = Some(SudoString::from_cli_string(value)); } "-U" | "--other-user" => { options.other_user = Some(SudoString::from_cli_string(value)); } "-u" | "--user" => { options.user = Some(SudoString::from_cli_string(value)); } _option => { Err("invalid option provided")?; } }, SudoArg::Environment(key, value) => { options.env_var_list.push((key, value)); } SudoArg::Rest(rest) => { options.positional_args = rest; } } } Ok(options) } } fn try_to_env_var(arg: &str) -> Option<(String, String)> { let (name, value) = arg.split_once('=')?; if name.chars().all(|c| c.is_alphanumeric() || c == '_') { Some((name.to_owned(), value.to_owned())) } else { None } } trait IsAbsent { fn is_absent(&self) -> bool; } impl IsAbsent for bool { fn is_absent(&self) -> bool { !*self } } impl IsAbsent for Option { fn is_absent(&self) -> bool { self.is_none() } } impl IsAbsent for Vec { fn is_absent(&self) -> bool { self.is_empty() } } impl IsAbsent for PreserveEnv { fn is_absent(&self) -> bool { self.is_nothing() } } fn ensure_is_absent(context: &str, thing: &dyn IsAbsent, name: &str) -> Result<(), String> { if thing.is_absent() { Ok(()) } else { Err(format!("{context} conflicts with {name}")) } } fn reject_all(context: &str, opts: SudoOptions) -> Result<(), String> { macro_rules! tuple { ($expr:expr) => { (&$expr as &dyn IsAbsent, { let name = concat!("--", stringify!($expr)); if name.contains('_') { Cow::Owned(name.replace('_', "-")) } else { Cow::Borrowed(name) } }) }; } let SudoOptions { chdir, group, login, non_interactive, other_user, preserve_env, shell, stdin, user, env_var_list, edit, help, list, remove_timestamp, reset_timestamp, validate, version, positional_args, } = opts; let flags = [ tuple!(chdir), tuple!(edit), tuple!(group), tuple!(help), tuple!(list), tuple!(login), tuple!(non_interactive), tuple!(other_user), tuple!(preserve_env), tuple!(remove_timestamp), tuple!(reset_timestamp), tuple!(shell), tuple!(stdin), tuple!(user), tuple!(validate), tuple!(version), ]; for (value, name) in flags { ensure_is_absent(context, value, &name)?; } ensure_is_absent(context, &env_var_list, "environment variable")?; ensure_is_absent(context, &positional_args, "positional argument")?; Ok(()) } impl From for OptionsForContext { fn from(opts: SudoListOptions) -> Self { let SudoListOptions { group, non_interactive, positional_args, reset_timestamp, stdin, user, list: _, other_user: _, } = opts; Self { action: ContextAction::List, group, non_interactive, positional_args, reset_timestamp, stdin, user, chdir: None, login: false, shell: false, } } } impl From for OptionsForContext { fn from(opts: SudoValidateOptions) -> Self { let SudoValidateOptions { group, non_interactive, reset_timestamp, stdin, user, } = opts; Self { action: ContextAction::Validate, group, non_interactive, reset_timestamp, stdin, user, chdir: None, login: false, positional_args: vec![], shell: false, } } } impl From for OptionsForContext { fn from(opts: SudoRunOptions) -> Self { let SudoRunOptions { chdir, group, login, non_interactive, positional_args, reset_timestamp, shell, stdin, user, env_var_list: _, preserve_env: _, } = opts; Self { action: ContextAction::Run, chdir, group, login, non_interactive, positional_args, reset_timestamp, shell, stdin, user, } } } sudo-rs-0.2.2/src/sudo/cli/tests.rs000064400000000000000000000317761046102023000152570ustar 00000000000000use crate::common::SudoPath; use crate::sudo::cli::PreserveEnv; use super::{SudoAction, SudoOptions}; use pretty_assertions::assert_eq; /// Passing '-E' with a variable fails #[test] fn short_preserve_env_with_var_fails() { let argss = [["sudo", "-E=variable"], ["sudo", "-Evariable"]]; for args in argss { let res = SudoOptions::try_parse_from(args); assert!(res.is_err()) } } /// Passing '--preserve-env' with an argument fills 'preserve_env', 'short_preserve_env' stays 'false' #[test] fn preserve_env_with_var() { let cmd = SudoOptions::try_parse_from(["sudo", "--preserve-env=some_argument"]).unwrap(); assert_eq!( ["some_argument"], cmd.preserve_env.try_into_only().unwrap().as_slice(), ); } /// Passing '--preserve-env' with several arguments fills 'preserve_env', 'short_preserve_env' stays 'false' #[test] fn preserve_env_with_several_vars() { let cmd = SudoOptions::try_parse_from([ "sudo", "--preserve-env=some_argument,another_argument,a_third_one", ]) .unwrap(); assert_eq!( ["some_argument", "another_argument", "a_third_one"], cmd.preserve_env.try_into_only().unwrap().as_slice(), ); } #[test] fn preserve_env_boolean() { let cmd = SudoOptions::try_parse_from(["sudo", "--preserve-env"]).unwrap(); assert_eq!(cmd.preserve_env, PreserveEnv::Everything); } #[test] fn preserve_env_boolean_and_list() { let expected = PreserveEnv::Everything; let argss = [ ["sudo", "--preserve-env", "--preserve-env=some_argument"], ["sudo", "--preserve-env=some_argument", "--preserve-env"], ]; for args in argss { let cmd = SudoOptions::try_parse_from(args).unwrap(); assert_eq!(expected, cmd.preserve_env); } } #[test] fn preserve_env_repeated() { let cmd = SudoOptions::try_parse_from([ "sudo", "--preserve-env=some_argument", "--preserve-env=another_argument", ]) .unwrap(); assert_eq!( ["some_argument", "another_argument"], cmd.preserve_env.try_into_only().unwrap().as_slice() ); } // `--preserve-env` only accepts a value with the syntax `--preserve-env=varname` // so this `--preserve-env` is acting like a boolean flag #[test] fn preserve_env_space() { let cmd = SudoOptions::try_parse_from(["sudo", "--preserve-env", "true"]).unwrap(); assert_eq!(PreserveEnv::Everything, cmd.preserve_env); assert_eq!(["true"], cmd.positional_args.as_slice()); } /// Catch env variable that is given without hyphens in 'VAR=value' form in env_var_list. /// external_args stay empty. #[test] fn env_variable() { let cmd = SudoOptions::try_parse_from(["sudo", "ENV=with_a_value"]).unwrap(); assert_eq!( cmd.env_var_list, vec![("ENV".to_owned(), "with_a_value".to_owned())] ); assert!(cmd.positional_args.is_empty()); } /// Catch several env variablse that are given without hyphens in 'VAR=value' form in env_var_list. /// external_args stay empty. #[test] fn several_env_variables() { let cmd = SudoOptions::try_parse_from([ "sudo", "ENV=with_a_value", "another_var=otherval", "more=this_is_a_val", ]) .unwrap(); assert_eq!( cmd.env_var_list, vec![ ("ENV".to_owned(), "with_a_value".to_owned()), ("another_var".to_owned(), "otherval".to_owned()), ("more".to_owned(), "this_is_a_val".to_owned()) ] ); assert!(cmd.positional_args.is_empty()); } /// Mix env variables and trailing arguments that just pass through sudo /// Divided by hyphens. #[test] fn mix_env_variables_with_trailing_args_divided_by_hyphens() { let cmd = SudoOptions::try_parse_from(["sudo", "env=var", "--", "external=args", "something"]) .unwrap(); assert_eq!(cmd.env_var_list, vec![("env".to_owned(), "var".to_owned())]); assert_eq!(cmd.positional_args, vec!["external=args", "something"]); } /// Mix env variables and trailing arguments that just pass through sudo /// Divided by known flag. #[test] fn mix_env_variables_with_trailing_args_divided_by_known_flag() { let cmd = SudoOptions::try_parse_from(["sudo", "-i", "external=args", "something"]).unwrap(); assert_eq!( cmd.env_var_list, vec![("external".to_owned(), "args".to_owned())] ); assert!(cmd.login); assert_eq!(cmd.positional_args, vec!["something"]); } /// Catch trailing arguments that just pass through sudo /// but look like a known flag. #[test] fn trailing_args_followed_by_known_flag() { let cmd = SudoOptions::try_parse_from(["sudo", "args", "followed_by", "known_flag", "-i"]).unwrap(); assert!(!cmd.login); assert_eq!( cmd.positional_args, vec!["args", "followed_by", "known_flag", "-i"] ); } /// Catch trailing arguments that just pass through sudo /// but look like a known flag, divided by hyphens. #[test] fn trailing_args_hyphens_known_flag() { let cmd = SudoOptions::try_parse_from([ "sudo", "--", "trailing", "args", "followed_by", "known_flag", "-i", ]) .unwrap(); assert!(!cmd.login); assert_eq!( cmd.positional_args, vec!["trailing", "args", "followed_by", "known_flag", "-i"] ); } /// Check that the first environment variable declaration before any command is not treated as part /// of the command. #[test] fn first_trailing_env_var_is_not_an_external_arg() { let cmd = SudoAction::try_parse_from(["sudo", "FOO=1", "command", "BAR=2"]).unwrap(); let opts = if let SudoAction::Run(opts) = cmd { opts } else { panic!() }; assert_eq!(opts.env_var_list, vec![("FOO".to_owned(), "1".to_owned()),]); assert_eq!(opts.positional_args, ["command", "BAR=2"],); } #[test] fn trailing_env_vars_are_external_args() { let cmd = SudoOptions::try_parse_from([ "sudo", "FOO=1", "-i", "BAR=2", "command", "BAZ=3", "arg", "FOOBAR=4", "command", "arg", "BARBAZ=5", ]) .unwrap(); assert!(cmd.login); assert_eq!( cmd.env_var_list, vec![ ("FOO".to_owned(), "1".to_owned()), ("BAR".to_owned(), "2".to_owned()) ] ); assert_eq!( cmd.positional_args, ["command", "BAZ=3", "arg", "FOOBAR=4", "command", "arg", "BARBAZ=5"] ); } #[test] fn single_env_var_declaration() { let cmd = SudoOptions::try_parse_from(["sudo", "FOO=1", "command"]).unwrap(); assert_eq!(cmd.env_var_list, vec![("FOO".to_owned(), "1".to_owned())]); assert_eq!(cmd.positional_args, ["command"]); } #[test] fn shorthand_with_argument() { let cmd = SudoOptions::try_parse_from(["sudo", "-u", "ferris"]).unwrap(); assert_eq!(cmd.user.as_deref(), Some("ferris")); } #[test] fn shorthand_with_direct_argument() { let cmd = SudoOptions::try_parse_from(["sudo", "-uferris"]).unwrap(); assert_eq!(cmd.user.as_deref(), Some("ferris")); } #[test] fn shorthand_without_argument() { let cmd = SudoOptions::try_parse_from(["sudo", "-u"]); assert!(cmd.is_err()) } #[test] fn non_interactive() { let cmd = SudoOptions::try_parse_from(["sudo", "-n"]).unwrap(); assert!(cmd.non_interactive); let cmd = SudoOptions::try_parse_from(["sudo", "--non-interactive"]).unwrap(); assert!(cmd.non_interactive); } #[test] fn stdin() { let cmd = SudoOptions::try_parse_from(["sudo", "-S"]).unwrap(); assert!(cmd.stdin); let cmd = SudoOptions::try_parse_from(["sudo", "--stdin"]).unwrap(); assert!(cmd.stdin); } #[test] fn shell() { let cmd = SudoOptions::try_parse_from(["sudo", "-s"]).unwrap(); assert!(cmd.shell); let cmd = SudoOptions::try_parse_from(["sudo", "--shell"]).unwrap(); assert!(cmd.shell); } #[test] fn directory() { let cmd = SudoOptions::try_parse_from(["sudo", "-D/some/path"]).unwrap(); assert_eq!(cmd.chdir, Some(SudoPath::from("/some/path"))); let cmd = SudoOptions::try_parse_from(["sudo", "--chdir", "/some/path"]).unwrap(); assert_eq!(cmd.chdir, Some(SudoPath::from("/some/path"))); let cmd = SudoOptions::try_parse_from(["sudo", "--chdir=/some/path"]).unwrap(); assert_eq!(cmd.chdir, Some(SudoPath::from("/some/path"))); } #[test] fn group() { let cmd = SudoOptions::try_parse_from(["sudo", "-grustaceans"]).unwrap(); assert_eq!(cmd.group.as_deref(), Some("rustaceans")); let cmd = SudoOptions::try_parse_from(["sudo", "--group", "rustaceans"]).unwrap(); assert_eq!(cmd.group.as_deref(), Some("rustaceans")); let cmd = SudoOptions::try_parse_from(["sudo", "--group=rustaceans"]).unwrap(); assert_eq!(cmd.group.as_deref(), Some("rustaceans")); } #[test] fn other_user() { let cmd = SudoOptions::try_parse_from(["sudo", "-Uferris"]).unwrap(); assert_eq!(cmd.other_user.as_deref(), Some("ferris")); let cmd = SudoOptions::try_parse_from(["sudo", "--other-user", "ferris"]).unwrap(); assert_eq!(cmd.other_user.as_deref(), Some("ferris")); let cmd = SudoOptions::try_parse_from(["sudo", "--other-user=ferris"]).unwrap(); assert_eq!(cmd.other_user.as_deref(), Some("ferris")); } #[test] fn invalid_option() { let cmd = SudoOptions::try_parse_from(["sudo", "--wololo"]); assert!(cmd.is_err()) } #[test] fn invalid_option_with_argument() { let cmd = SudoOptions::try_parse_from(["sudo", "--background=yes"]); assert!(cmd.is_err()) } #[test] fn no_argument_provided() { let cmd = SudoOptions::try_parse_from(["sudo", "--user"]); assert!(cmd.is_err()) } #[test] fn login() { let cmd = SudoOptions::try_parse_from(["sudo", "-i"]).unwrap(); assert!(cmd.login); let cmd = SudoOptions::try_parse_from(["sudo", "--login"]).unwrap(); assert!(cmd.login); } #[test] fn edit() { let cmd = SudoAction::try_parse_from(["sudo", "-e", "filepath"]).unwrap(); assert!(cmd.is_edit()); let cmd = SudoAction::try_parse_from(["sudo", "--edit", "filepath"]).unwrap(); assert!(cmd.is_edit()); let res = SudoAction::try_parse_from(["sudo", "--edit"]); assert!(res.is_err()); } #[test] fn help() { let cmd = SudoAction::try_parse_from(["sudo", "-h"]).unwrap(); assert!(cmd.is_help()); let cmd = SudoAction::try_parse_from(["sudo", "-bh"]); assert!(cmd.is_err()); let cmd = SudoAction::try_parse_from(["sudo", "--help"]).unwrap(); assert!(cmd.is_help()); } #[test] fn conflicting_arguments() { let cmd = SudoAction::try_parse_from(["sudo", "-K", "-k"]); assert!(cmd.is_err()); let cmd = SudoAction::try_parse_from(["sudo", "--remove-timestamp", "--reset-timestamp"]); assert!(cmd.is_err()); let cmd = SudoAction::try_parse_from(["sudo", "-K"]).unwrap(); assert!(cmd.is_remove_timestamp()); let cmd = SudoAction::try_parse_from(["sudo", "-k"]).unwrap(); assert!(cmd.is_reset_timestamp()); } #[test] fn list() { let valid: &[&[_]] = &[ &["sudo", "--list"], &["sudo", "-l"], &["sudo", "-l", "true"], &["sudo", "-l", "-U", "ferris"], &["sudo", "-l", "-U", "ferris", "true"], &["sudo", "-l", "-u", "ferris", "true"], &["sudo", "-l", "-u", "ferris", "-U", "root", "true"], ]; for args in valid { let cmd = SudoAction::try_parse_from(args.iter().copied()).unwrap(); assert!(cmd.is_list()); } let invalid: &[&[_]] = &[ &["sudo", "-l", "-u", "ferris"], &["sudo", "-l", "-u", "ferris", "-U", "root"], ]; for args in invalid { let res = SudoAction::try_parse_from(args.iter().copied()); assert!(res.is_err()) } } #[test] fn validate() { let cmd = SudoAction::try_parse_from(["sudo", "-v"]).unwrap(); assert!(cmd.is_validate()); let cmd = SudoAction::try_parse_from(["sudo", "--validate"]).unwrap(); assert!(cmd.is_validate()); } #[test] fn version() { let cmd = SudoAction::try_parse_from(["sudo", "-V"]).unwrap(); assert!(cmd.is_version()); let cmd = SudoAction::try_parse_from(["sudo", "--version"]).unwrap(); assert!(cmd.is_version()); } #[test] fn run_reset_timestamp_command() { let action = SudoAction::try_parse_from(["sudo", "-k", "true"]) .unwrap() .try_into_run() .ok() .unwrap(); assert_eq!(["true"], action.positional_args.as_slice()); assert!(action.reset_timestamp); } #[test] fn run_reset_timestamp_login() { let action = SudoAction::try_parse_from(["sudo", "-k", "-i"]) .unwrap() .try_into_run() .ok() .unwrap(); assert!(action.positional_args.is_empty()); assert!(action.reset_timestamp); assert!(action.login); } #[test] fn run_reset_timestamp_shell() { let action = SudoAction::try_parse_from(["sudo", "-k", "-s"]) .unwrap() .try_into_run() .ok() .unwrap(); assert!(action.positional_args.is_empty()); assert!(action.reset_timestamp); assert!(action.shell); } #[test] fn run_no_command() { assert!(SudoAction::try_parse_from(["sudo", "-u", "root"]).is_err()); } #[test] fn run_login() { assert!(SudoAction::try_parse_from(["sudo", "-i"]).unwrap().is_run()); } #[test] fn run_shell() { assert!(SudoAction::try_parse_from(["sudo", "-s"]).unwrap().is_run()); } sudo-rs-0.2.2/src/sudo/diagnostic.rs000064400000000000000000000030601046102023000154530ustar 00000000000000use std::fs::File; use std::io::{BufRead, BufReader}; use std::ops::Range; use std::path::Path; pub(crate) fn cited_error(message: &str, range: Range<(usize, usize)>, path: impl AsRef) { let path_str = path.as_ref().display(); let Range { start: (line, col), end: (end_line, mut end_col), } = range; eprintln_ignore_io_error!("{path_str}:{line}:{col}: {message}"); // we won't try to "span" errors across multiple lines if line != end_line { end_col = col; } let citation = || { let inp = BufReader::new(File::open(path).ok()?); let line = inp.lines().nth(line - 1)?.ok()?; let padding = line .chars() .take(col - 1) .map(|c| if c.is_whitespace() { c } else { ' ' }) .collect::(); let lineunder = std::iter::repeat('~') .take(end_col - col) .skip(1) .collect::(); eprintln_ignore_io_error!("{line}"); eprintln_ignore_io_error!("{padding}^{lineunder}"); Some(()) }; // we ignore any errors in displaying an error let _ = citation(); } macro_rules! diagnostic { ($str:expr, $path:tt @ $pos:ident) => { if let Some(range) = $pos { $crate::sudo::diagnostic::cited_error(&format!($str), range, $path); } else { eprintln_ignore_io_error!("sudo-rs: {}", format!($str)); } }; ($str:expr) => {{ eprintln_ignore_io_error!("sudo-rs: {}", format!($str)); }}; } pub(crate) use diagnostic; sudo-rs-0.2.2/src/sudo/env/environment.rs000064400000000000000000000251611046102023000164710ustar 00000000000000use std::{ collections::{hash_map::Entry, HashSet}, ffi::{OsStr, OsString}, os::unix::prelude::OsStrExt, }; use crate::common::{CommandAndArguments, Context, Environment}; use crate::sudoers::Policy; use crate::system::PATH_MAX; use super::wildcard_match::wildcard_match; const PATH_MAILDIR: &str = env!("PATH_MAILDIR"); const PATH_ZONEINFO: &str = env!("PATH_ZONEINFO"); const PATH_DEFAULT: &str = env!("SUDO_PATH_DEFAULT"); /// check byte slice contains with given byte slice fn contains_subsequence(haystack: &[u8], needle: &[u8]) -> bool { haystack .windows(needle.len()) .any(|window| window == needle) } /// Formats the command and arguments passed for the SUDO_COMMAND /// environment variable. Limit the length to 4096 bytes to prevent /// execve failure for very long argument vectors fn format_command(command_and_arguments: &CommandAndArguments) -> OsString { let mut formatted: OsString = command_and_arguments.command.clone().into(); for arg in &command_and_arguments.arguments { if formatted.len() + arg.len() < 4096 { formatted.push(" "); formatted.push(arg); } } formatted } /// Construct sudo-specific environment variables fn add_extra_env( context: &Context, cfg: &impl Policy, sudo_ps1: Option, environment: &mut Environment, ) { // current user environment.insert("SUDO_COMMAND".into(), format_command(&context.command)); environment.insert( "SUDO_UID".into(), context.current_user.uid.to_string().into(), ); environment.insert( "SUDO_GID".into(), context.current_user.gid.to_string().into(), ); environment.insert("SUDO_USER".into(), context.current_user.name.clone().into()); // target user if let Entry::Vacant(entry) = environment.entry("MAIL".into()) { entry.insert(format!("{PATH_MAILDIR}/{}", context.target_user.name).into()); } // The current SHELL variable should determine the shell to run when -s is passed, if none set use passwd entry environment.insert("SHELL".into(), context.target_user.shell.clone().into()); // HOME' Set to the home directory of the target user if -i or -H are specified, env_reset or always_set_home are // set in sudoers, or when the -s option is specified and set_home is set in sudoers. // Since we always want to do env_reset -> always set HOME if let Entry::Vacant(entry) = environment.entry("HOME".into()) { entry.insert(context.target_user.home.clone().into()); } match ( environment.get(OsStr::new("LOGNAME")), environment.get(OsStr::new("USER")), ) { // Set to the login name of the target user when the -i option is specified, // when the set_logname option is enabled in sudoers, or when the env_reset option // is enabled in sudoers (unless LOGNAME is present in the env_keep list). // Since we always want to do env_reset -> always set these except when present in env (None, None) => { environment.insert("LOGNAME".into(), context.target_user.name.clone().into()); environment.insert("USER".into(), context.target_user.name.clone().into()); } // LOGNAME should be set to the same value as USER if the latter is preserved. (None, Some(user)) => { environment.insert("LOGNAME".into(), user.clone()); } // USER should be set to the same value as LOGNAME if the latter is preserved. (Some(logname), None) => { environment.insert("USER".into(), logname.clone()); } (Some(_), Some(_)) => {} } // Overwrite PATH when secure_path is set if let Some(secure_path) = cfg.secure_path() { // assign path by env path or secure_path configuration environment.insert("PATH".into(), secure_path.into()); } // If the PATH and TERM variables are not preserved from the user's environment, they will be set to default value if !environment.contains_key(OsStr::new("PATH")) { // If the PATH variable is not set, it will be set to default value environment.insert("PATH".into(), PATH_DEFAULT.into()); } // If the TERM variable is not preserved from the user's environment, it will be set to default value if !environment.contains_key(OsStr::new("TERM")) { environment.insert("TERM".into(), "unknown".into()); } // The SUDO_PS1 variable requires special treatment as the PS1 variable must be set in the // target environment to the same value of SUDO_PS1 if the latter is set. if let Some(sudo_ps1_value) = sudo_ps1 { // set PS1 to the SUDO_PS1 value in the target environment environment.insert("PS1".into(), sudo_ps1_value); } } /// Check a string only contains printable (non-space) characters fn is_printable(input: &[u8]) -> bool { input .iter() .all(|c| c.is_ascii_alphanumeric() || c.is_ascii_punctuation()) } /// The TZ variable is considered unsafe if any of the following are true: /// It consists of a fully-qualified path name, optionally prefixed with a colon (‘:’), that does not match the location of the zoneinfo directory. /// It contains a .. path element. /// It contains white space or non-printable characters. /// It is longer than the value of PATH_MAX. fn is_safe_tz(value: &[u8]) -> bool { let check_value = if value.starts_with(&[b':']) { &value[1..] } else { value }; if check_value.starts_with(&[b'/']) { if !PATH_ZONEINFO.is_empty() { if !check_value.starts_with(PATH_ZONEINFO.as_bytes()) || check_value.get(PATH_ZONEINFO.len()) != Some(&b'/') { return false; } } else { return false; } } !contains_subsequence(check_value, "..".as_bytes()) && is_printable(check_value) && check_value.len() < PATH_MAX as usize } /// Check whether the needle exists in a haystack, in which the haystack is a list of patterns, possibly containing wildcards fn in_table(needle: &OsStr, haystack: &HashSet) -> bool { haystack .iter() .any(|pattern| wildcard_match(needle.as_bytes(), pattern.as_bytes())) } /// Determine whether a specific environment variable should be kept fn should_keep(key: &OsStr, value: &OsStr, cfg: &impl Policy) -> bool { if value.as_bytes().starts_with("()".as_bytes()) { return false; } if key == "TZ" { return in_table(key, cfg.env_keep()) || (in_table(key, cfg.env_check()) && is_safe_tz(value.as_bytes())); } if in_table(key, cfg.env_check()) { return !value.as_bytes().iter().any(|c| *c == b'%' || *c == b'/'); } in_table(key, cfg.env_keep()) } /// Construct the final environment from the current one and a sudo context /// see for the original implementation /// see for the original documentation /// /// The HOME, MAIL, SHELL, LOGNAME and USER environment variables are initialized based on the target user /// and the SUDO_* variables are set based on the invoking user. /// /// Additional variables, such as DISPLAY, PATH and TERM, are preserved from the invoking user's /// environment if permitted by the env_check, or env_keep options /// /// If the PATH and TERM variables are not preserved from the user's environment, they will be set to default value /// /// Environment variables with a value beginning with ‘()’ are removed pub fn get_target_environment( current_env: Environment, additional_env: Environment, context: &Context, settings: &impl Policy, ) -> Environment { let mut environment = Environment::default(); // retrieve SUDO_PS1 value to set a PS1 value as additional environment let sudo_ps1 = current_env.get(OsStr::new("SUDO_PS1")).cloned(); // variables preserved from the invoking user's environment by the // env_keep list take precedence over those in the PAM environment environment.extend(additional_env); environment.extend( current_env .into_iter() .filter(|(key, value)| should_keep(key, value, settings)), ); add_extra_env(context, settings, sudo_ps1, &mut environment); environment } #[cfg(test)] mod tests { use super::{is_safe_tz, should_keep, PATH_ZONEINFO}; use crate::sudoers::Policy; use std::{collections::HashSet, ffi::OsStr}; struct TestConfiguration { keep: HashSet, check: HashSet, } impl Policy for TestConfiguration { fn env_keep(&self) -> &HashSet { &self.keep } fn env_check(&self) -> &HashSet { &self.check } fn secure_path(&self) -> Option { None } fn use_pty(&self) -> bool { true } } #[test] fn test_filtering() { let config = TestConfiguration { keep: HashSet::from(["AAP".to_string(), "NOOT".to_string()]), check: HashSet::from(["MIES".to_string(), "TZ".to_string()]), }; let check_should_keep = |key: &str, value: &str, expected: bool| { assert_eq!( should_keep(OsStr::new(key), OsStr::new(value), &config), expected, "{} should {}", key, if expected { "be kept" } else { "not be kept" } ); }; check_should_keep("AAP", "FOO", true); check_should_keep("MIES", "BAR", true); check_should_keep("AAP", "()=foo", false); check_should_keep("TZ", "Europe/Amsterdam", true); check_should_keep("TZ", "../Europe/Berlin", false); check_should_keep("MIES", "FOO/BAR", false); check_should_keep("MIES", "FOO%", false); } #[allow(clippy::useless_format)] #[allow(clippy::bool_assert_comparison)] #[test] fn test_tzinfo() { assert_eq!(is_safe_tz("Europe/Amsterdam".as_bytes()), true); assert_eq!( is_safe_tz(format!("{PATH_ZONEINFO}/Europe/London").as_bytes()), true ); assert_eq!( is_safe_tz(format!(":{PATH_ZONEINFO}/Europe/Amsterdam").as_bytes()), true ); assert_eq!( is_safe_tz(format!("/schaap/Europe/Amsterdam").as_bytes()), false ); assert_eq!( is_safe_tz(format!("{PATH_ZONEINFO}/../Europe/London").as_bytes()), false ); assert_eq!( is_safe_tz(format!("{PATH_ZONEINFO}/../Europe/London").as_bytes()), false ); } } sudo-rs-0.2.2/src/sudo/env/mod.rs000064400000000000000000000001371046102023000147000ustar 00000000000000#![forbid(unsafe_code)] pub mod environment; pub mod wildcard_match; #[cfg(test)] mod tests; sudo-rs-0.2.2/src/sudo/env/tests.rs000064400000000000000000000116371046102023000152720ustar 00000000000000use crate::common::resolve::CurrentUser; use crate::common::{CommandAndArguments, Context, Environment}; use crate::sudo::{ cli::{SudoAction, SudoRunOptions}, env::environment::get_target_environment, }; use crate::system::{Group, Hostname, Process, User}; use std::collections::{HashMap, HashSet}; const TESTS: &str = " > env FOO=BAR HOME=/home/test HOSTNAME=test-ubuntu LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_ALL=en_US.UTF-8 LS_COLORS=cd=40;33;01:*.jpg=01;35:*.mp3=00;36: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/home/test SHLVL=0 TERM=xterm _=/usr/bin/sudo > sudo env HOSTNAME=test-ubuntu LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_ALL=en_US.UTF-8 LS_COLORS=cd=40;33;01:*.jpg=01;35:*.mp3=00;36: MAIL=/var/mail/root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin SHELL=/bin/bash SUDO_COMMAND=/usr/bin/env SUDO_GID=1000 SUDO_UID=1000 SUDO_USER=test HOME=/root LOGNAME=root USER=root TERM=xterm > sudo -u test env HOSTNAME=test-ubuntu LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_ALL=en_US.UTF-8 LS_COLORS=cd=40;33;01:*.jpg=01;35:*.mp3=00;36: MAIL=/var/mail/test PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin SHELL=/bin/sh SUDO_COMMAND=/usr/bin/env SUDO_GID=1000 SUDO_UID=1000 SUDO_USER=test HOME=/home/test LOGNAME=test USER=test TERM=xterm "; fn parse_env_commands(input: &str) -> Vec<(&str, Environment)> { input .trim() .split("> ") .filter(|l| !l.is_empty()) .map(|e| { let (cmd, vars) = e.split_once('\n').unwrap(); let vars: Environment = vars .lines() .map(|line| line.trim().split_once('=').unwrap()) .map(|(k, v)| (k.into(), v.into())) .collect(); (cmd, vars) }) .collect() } fn create_test_context(sudo_options: &SudoRunOptions) -> Context { let path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin".to_string(); let command = CommandAndArguments::build_from_args(None, sudo_options.positional_args.clone(), &path); let current_user = CurrentUser::fake(User { uid: 1000, gid: 1000, name: "test".into(), gecos: String::new(), home: "/home/test".into(), shell: "/bin/sh".into(), passwd: String::new(), groups: vec![], }); let current_group = Group { gid: 1000, name: "test".to_string(), passwd: String::new(), members: Vec::new(), }; let root_user = User { uid: 0, gid: 0, name: "root".into(), gecos: String::new(), home: "/root".into(), shell: "/bin/bash".into(), passwd: String::new(), groups: vec![], }; let root_group = Group { gid: 0, name: "root".to_string(), passwd: String::new(), members: Vec::new(), }; Context { hostname: Hostname::fake("test-ubuntu"), command, current_user: current_user.clone(), target_user: if sudo_options.user.as_deref() == Some("test") { current_user.into() } else { root_user }, target_group: if sudo_options.user.as_deref() == Some("test") { current_group } else { root_group }, launch: crate::common::context::LaunchType::Direct, chdir: sudo_options.chdir.clone(), stdin: sudo_options.stdin, non_interactive: sudo_options.non_interactive, process: Process::new(), use_session_records: false, use_pty: true, } } fn environment_to_set(environment: Environment) -> HashSet { HashSet::from_iter( environment .iter() .map(|(k, v)| format!("{}={}", k.to_str().unwrap(), v.to_str().unwrap())), ) } #[test] fn test_environment_variable_filtering() { let mut parts = parse_env_commands(TESTS); let initial_env = parts.remove(0).1; for (cmd, expected_env) in parts { let options = SudoAction::try_parse_from(cmd.split_whitespace()) .unwrap() .try_into_run() .ok() .unwrap(); let settings = crate::sudoers::Judgement::default(); let context = create_test_context(&options); let resulting_env = get_target_environment(initial_env.clone(), HashMap::new(), &context, &settings); let resulting_env = environment_to_set(resulting_env); let expected_env = environment_to_set(expected_env); let mut diff = resulting_env .symmetric_difference(&expected_env) .collect::>(); diff.sort(); assert!( diff.is_empty(), "\"{cmd}\" results in an environment mismatch:\n{diff:#?}", ); } } sudo-rs-0.2.2/src/sudo/env/wildcard_match.rs000064400000000000000000000056561046102023000171010ustar 00000000000000/// Match a test input with a pattern /// Only wildcard characters (*) in the pattern string have a special meaning: they match on zero or more characters pub(super) fn wildcard_match(test: &[u8], pattern: &[u8]) -> bool { let mut test_index = 0; let mut pattern_index = 0; let mut last_star = None; loop { match (pattern.get(pattern_index), test.get(test_index)) { (Some(p), Some(t)) => { if *p == b'*' { pattern_index += 1; last_star = Some((test_index, pattern_index)); } else if p == t { pattern_index += 1; test_index += 1; } else if let Some((t_index, p_index)) = last_star { test_index = t_index + 1; pattern_index = p_index; last_star = Some((test_index, pattern_index)); } else { return false; } } (None, Some(_)) => { if let Some((t_index, p_index)) = last_star { test_index = t_index + 1; pattern_index = p_index; last_star = Some((test_index, pattern_index)); } else { return false; } } (Some(b'*'), None) => { pattern_index += 1; } (None, None) => { return true; } _ => { return false; } } } } #[cfg(test)] mod tests { use super::wildcard_match; #[test] fn test_wildcard_match() { let tests = vec![ ("foo bar", "foo *", true), ("foo bar", "foo ba*", true), ("foo bar", "foo *ar", true), ("foo bar", "foo *r", true), ("foo bar", "foo *ab", false), ("foo bar", "foo r*", false), ("foo bar", "*oo bar", true), ("foo bar", "*f* bar", true), ("foo bar", "*f bar", false), ("foo ", "foo *", true), ("foo", "foo *", false), ("foo", "foo*", true), ("foo bar", "f*******r", true), ("foo******bar", "f*r", true), ("foo********bar", "foo bar", false), ("#%^$V@#TYH%&rot13%#@$%#$%", "#%^$V@#*t13%#@$%#$%", true), ("#%^$V@#TYH%&rot13%#@$%#$%", "*%^*%&rot*%#$%", true), ("#%^$V@#TYH%&rot13%#@$%#$%", "#%^$V@#TYH%&r*%#@$#$%", false), ("#%^$V@#TYH%&rot13%#@$%#$%", "#%^$V@#*******@$%#$%", true), ]; for (test, pattern, expected) in tests.into_iter() { assert_eq!( wildcard_match(test.as_bytes(), pattern.as_bytes()), expected, "\"{}\" {} match {}", test, if expected { "should" } else { "should not" }, pattern ); } } } sudo-rs-0.2.2/src/sudo/mod.rs000064400000000000000000000114701046102023000141120ustar 00000000000000#![forbid(unsafe_code)] use crate::common::resolve::CurrentUser; use crate::common::{Context, Error}; use crate::log::dev_info; use crate::system::timestamp::RecordScope; use crate::system::User; use crate::system::{time::Duration, timestamp::SessionRecordFile, Process}; use cli::help; #[cfg(test)] pub use cli::SudoAction; #[cfg(not(test))] use cli::SudoAction; use pam::PamAuthenticator; use pipeline::{Pipeline, PolicyPlugin}; use std::path::Path; mod cli; mod diagnostic; mod env; mod pam; mod pipeline; const VERSION: &str = std::env!("CARGO_PKG_VERSION"); fn candidate_sudoers_file() -> &'static Path { let pb_rs: &'static Path = Path::new("/etc/sudoers-rs"); if pb_rs.exists() { dev_info!("Running with /etc/sudoers-rs file"); pb_rs } else { dev_info!("Running with /etc/sudoers file"); Path::new("/etc/sudoers") } } #[derive(Default)] pub(crate) struct SudoersPolicy {} impl PolicyPlugin for SudoersPolicy { type PreJudgementPolicy = crate::sudoers::Sudoers; type Policy = crate::sudoers::Judgement; fn init(&mut self) -> Result { let sudoers_path = candidate_sudoers_file(); let (sudoers, syntax_errors) = crate::sudoers::Sudoers::open(sudoers_path) .map_err(|e| Error::Configuration(format!("{e}")))?; for crate::sudoers::Error { source, location, message, } in syntax_errors { let path = source.as_deref().unwrap_or(sudoers_path); diagnostic::diagnostic!("{message}", path @ location); } Ok(sudoers) } fn judge( &mut self, pre: Self::PreJudgementPolicy, context: &Context, ) -> Result { Ok(pre.check( &*context.current_user, &context.hostname, crate::sudoers::Request { user: &context.target_user, group: &context.target_group, command: &context.command.command, arguments: &context.command.arguments, }, )) } } fn sudo_process() -> Result<(), Error> { crate::log::SudoLogger::new("sudo: ").into_global_logger(); dev_info!("development logs are enabled"); self_check()?; let pipeline = Pipeline { policy: SudoersPolicy::default(), authenticator: PamAuthenticator::new_cli(), }; // parse cli options match SudoAction::from_env() { Ok(action) => match action { SudoAction::Help(_) => { eprintln_ignore_io_error!("{}", help::long_help_message()); std::process::exit(0); } SudoAction::Version(_) => { eprintln_ignore_io_error!("sudo-rs {VERSION}"); std::process::exit(0); } SudoAction::RemoveTimestamp(_) => { let user = CurrentUser::resolve()?; let mut record_file = SessionRecordFile::open_for_user(&user, Duration::seconds(0))?; record_file.reset()?; Ok(()) } SudoAction::ResetTimestamp(_) => { if let Some(scope) = RecordScope::for_process(&Process::new()) { let user = CurrentUser::resolve()?; let mut record_file = SessionRecordFile::open_for_user(&user, Duration::seconds(0))?; record_file.disable(scope, None)?; } Ok(()) } SudoAction::Validate(options) => pipeline.run_validate(options), SudoAction::Run(options) => { // special case for when no command is given if options.positional_args.is_empty() && !options.shell && !options.login { eprintln_ignore_io_error!("{}", help::USAGE_MSG); std::process::exit(1); } else { pipeline.run(options) } } SudoAction::List(options) => pipeline.run_list(options), SudoAction::Edit(_) => { eprintln_ignore_io_error!("error: `--edit` flag has not yet been implemented"); std::process::exit(1); } }, Err(e) => { eprintln_ignore_io_error!("{e}\n{}", help::USAGE_MSG); std::process::exit(1); } } } fn self_check() -> Result<(), Error> { const ROOT: u32 = 0; let euid = User::effective_uid(); if euid == ROOT { Ok(()) } else { Err(Error::SelfCheck) } } pub fn main() { match sudo_process() { Ok(()) => (), Err(error) => { if !error.is_silent() { diagnostic::diagnostic!("{error}"); } std::process::exit(1); } } } sudo-rs-0.2.2/src/sudo/pam.rs000064400000000000000000000120301046102023000141010ustar 00000000000000use std::collections::HashMap; use std::ffi::OsString; use crate::common::context::LaunchType; use crate::common::{error::Error, Context}; use crate::log::{dev_info, user_warn}; use crate::pam::{CLIConverser, Converser, PamContext, PamError, PamErrorType, PamResult}; use crate::system::term::current_tty_name; use super::pipeline::AuthPlugin; type PamBuilder = dyn Fn(&Context) -> PamResult>; pub struct PamAuthenticator { builder: Box>, pam: Option>, } impl PamAuthenticator { fn new( initializer: impl Fn(&Context) -> PamResult> + 'static, ) -> PamAuthenticator { PamAuthenticator { builder: Box::new(initializer), pam: None, } } } impl PamAuthenticator { pub fn new_cli() -> PamAuthenticator { PamAuthenticator::new(|context| { init_pam( matches!(context.launch, LaunchType::Login), matches!(context.launch, LaunchType::Shell), context.stdin, context.non_interactive, &context.current_user.name, &context.current_user.name, ) }) } } impl AuthPlugin for PamAuthenticator { fn init(&mut self, context: &Context) -> Result<(), Error> { self.pam = Some((self.builder)(context)?); Ok(()) } fn authenticate(&mut self, non_interactive: bool, max_tries: u16) -> Result<(), Error> { let pam = self .pam .as_mut() .expect("Pam must be initialized before authenticate"); attempt_authenticate(pam, non_interactive, max_tries)?; Ok(()) } fn pre_exec(&mut self, target_user: &str) -> Result, Error> { let pam = self .pam .as_mut() .expect("Pam must be initialized before pre_exec"); // make sure that the user that needed to authenticate has a valid token pam.validate_account_or_change_auth_token()?; // check what the current user in PAM is let user = pam.get_user()?; if user != target_user { // switch pam over to the target user pam.set_user(target_user)?; // make sure that credentials are loaded for the target user // errors are ignored because not all modules support this functionality if let Err(e) = pam.credentials_reinitialize() { dev_info!( "PAM gave an error while trying to re-initialize credentials: {:?}", e ); } } pam.open_session()?; let env_vars = pam.env()?; Ok(env_vars) } fn cleanup(&mut self) { let pam = self .pam .as_mut() .expect("Pam must be initialized before cleanup"); // closing the pam session is best effort, if any error occurs we cannot // do anything with it let _ = pam.close_session(); } } pub fn init_pam( is_login_shell: bool, is_shell: bool, use_stdin: bool, non_interactive: bool, auth_user: &str, requesting_user: &str, ) -> PamResult> { let service_name = if is_login_shell { "sudo-i" } else { "sudo" }; let mut pam = PamContext::builder_cli("sudo", use_stdin, non_interactive) .service_name(service_name) .build()?; pam.mark_silent(!is_shell && !is_login_shell); pam.mark_allow_null_auth_token(false); pam.set_requesting_user(requesting_user)?; pam.set_user(auth_user)?; // attempt to set the TTY this session is communicating on if let Ok(pam_tty) = current_tty_name() { pam.set_tty(&pam_tty)?; } Ok(pam) } pub fn attempt_authenticate( pam: &mut PamContext, non_interactive: bool, mut max_tries: u16, ) -> Result<(), Error> { let mut current_try = 0; loop { current_try += 1; match pam.authenticate() { // there was no error, so authentication succeeded Ok(_) => break, // maxtries was reached, pam does not allow any more tries Err(PamError::Pam(PamErrorType::MaxTries, _)) => { return Err(Error::MaxAuthAttempts(current_try)); } // there was an authentication error, we can retry Err(PamError::Pam(PamErrorType::AuthError, _)) => { max_tries -= 1; if max_tries == 0 { return Err(Error::MaxAuthAttempts(current_try)); } else if non_interactive { return Err(Error::Authentication("interaction required".to_string())); } else { user_warn!("Authentication failed, try again."); } } // there was another pam error, return the error Err(e) => { return Err(e.into()); } } } Ok(()) } sudo-rs-0.2.2/src/sudo/pipeline/list.rs000064400000000000000000000146561046102023000161240ustar 00000000000000use std::{borrow::Cow, ops::ControlFlow, path::Path}; use crate::{ common::{Context, Error}, pam::CLIConverser, sudo::{cli::SudoListOptions, pam::PamAuthenticator, SudoersPolicy}, sudoers::{Authorization, ListRequest, Policy, Request, Sudoers}, system::User, }; use super::{Pipeline, PolicyPlugin}; impl Pipeline> { pub(in crate::sudo) fn run_list(mut self, cmd_opts: SudoListOptions) -> Result<(), Error> { let verbose_list_mode = cmd_opts.list.is_verbose(); let other_user = cmd_opts .other_user .as_ref() .map(|username| { User::from_name(username.as_cstr())? .ok_or_else(|| Error::UserNotFound(username.clone().into())) }) .transpose()?; let original_command = cmd_opts.positional_args.first().cloned(); let sudoers = self.policy.init()?; let context = super::build_context(cmd_opts.into(), &sudoers)?; if original_command.is_some() && !context.command.resolved { return Err(Error::CommandNotFound(context.command.command)); } if self .auth_invoking_user(&context, &sudoers, &original_command, &other_user)? .is_break() { return Ok(()); } if let Some(other_user) = &other_user { check_other_users_list_perms(other_user, &context, &sudoers, &original_command)?; } if let Some(original_command) = original_command { check_sudo_command_perms(&original_command, &context, &other_user, &sudoers)?; } else { let invoking_user = other_user.as_ref().unwrap_or(&context.current_user); println_ignore_io_error!( "User {} may run the following commands on {}:", invoking_user.name, context.hostname ); let matching_entries = sudoers.matching_entries(invoking_user, &context.hostname); for entry in matching_entries { if verbose_list_mode { let entry = entry.verbose(); println_ignore_io_error!("{entry}"); } else { println_ignore_io_error!("{entry}"); } } } Ok(()) } fn auth_invoking_user( &mut self, context: &Context, sudoers: &Sudoers, original_command: &Option, other_user: &Option, ) -> Result, Error> { let list_request = ListRequest { target_user: &context.target_user, target_group: &context.target_group, }; let judgement = sudoers.check_list_permission(&*context.current_user, &context.hostname, list_request); match judgement.authorization() { Authorization::Allowed(auth) => { self.auth_and_update_record_file(context, auth)?; Ok(ControlFlow::Continue(())) } Authorization::Forbidden => { if context.current_user.uid == 0 { if original_command.is_some() { return Err(Error::Silent); } println_ignore_io_error!( "User {} is not allowed to run sudo on {}.", other_user.as_ref().unwrap_or(&context.current_user).name, context.hostname ); // this branch does not result in exit code 1 but no further information should // be printed in this case Ok(ControlFlow::Break(())) } else { let command = if other_user.is_none() { "sudo".into() } else { format_list_command(original_command) }; Err(Error::NotAllowed { username: context.current_user.name.clone(), command, hostname: context.hostname.clone(), other_user: other_user.as_ref().map(|user| &user.name).cloned(), }) } } } } } fn check_other_users_list_perms( other_user: &User, context: &Context, sudoers: &Sudoers, original_command: &Option, ) -> Result<(), Error> { let list_request = ListRequest { target_user: &context.target_user, target_group: &context.target_group, }; let judgement = sudoers.check_list_permission(other_user, &context.hostname, list_request); if let Authorization::Forbidden = judgement.authorization() { return Err(Error::NotAllowed { username: context.current_user.name.clone(), command: format_list_command(original_command), hostname: context.hostname.clone(), other_user: Some(other_user.name.clone()), }); } Ok(()) } fn check_sudo_command_perms( original_command: &str, context: &Context, other_user: &Option, sudoers: &Sudoers, ) -> Result<(), Error> { let user = other_user.as_ref().unwrap_or(&context.current_user); let request = Request { user: &context.target_user, group: &context.target_group, command: &context.command.command, arguments: &context.command.arguments, }; let judgement = sudoers.check(user, &context.hostname, request); if let Authorization::Forbidden = judgement.authorization() { return Err(Error::Silent); } else { let command_is_relative_path = original_command.contains('/') && !Path::new(&original_command).is_absolute(); let command: Cow<_> = if command_is_relative_path { original_command.into() } else { let resolved_command = &context.command.command; resolved_command.display().to_string().into() }; if context.command.arguments.is_empty() { println_ignore_io_error!("{command}"); } else { println_ignore_io_error!("{command} {}", context.command.arguments.join(" ")); } } Ok(()) } fn format_list_command(original_command: &Option) -> Cow<'static, str> { if let Some(original_command) = original_command { format!("list {original_command}").into() } else { "list".into() } } sudo-rs-0.2.2/src/sudo/pipeline.rs000064400000000000000000000226431046102023000151440ustar 00000000000000use std::ffi::OsStr; use std::process::exit; use super::cli::{SudoRunOptions, SudoValidateOptions}; use crate::common::context::OptionsForContext; use crate::common::resolve::CurrentUser; use crate::common::{Context, Environment, Error}; use crate::exec::{ExecOutput, ExitReason}; use crate::log::{auth_info, auth_warn}; use crate::sudo::env::environment; use crate::sudo::Duration; use crate::sudoers::{Authorization, AuthorizationAllowed, DirChange, Policy, PreJudgementPolicy}; use crate::system::interface::UserId; use crate::system::term::current_tty_name; use crate::system::timestamp::{RecordScope, SessionRecordFile, TouchResult}; use crate::system::{escape_os_str_lossy, Process}; mod list; pub trait PolicyPlugin { type PreJudgementPolicy: PreJudgementPolicy; type Policy: Policy; fn init(&mut self) -> Result; fn judge( &mut self, pre: Self::PreJudgementPolicy, context: &Context, ) -> Result; } pub trait AuthPlugin { fn init(&mut self, context: &Context) -> Result<(), Error>; fn authenticate(&mut self, non_interactive: bool, max_tries: u16) -> Result<(), Error>; fn pre_exec(&mut self, target_user: &str) -> Result; fn cleanup(&mut self); } pub struct Pipeline { pub policy: Policy, pub authenticator: Auth, } impl Pipeline { pub fn run(mut self, cmd_opts: SudoRunOptions) -> Result<(), Error> { if !cmd_opts.env_var_list.is_empty() { eprintln_ignore_io_error!( "warning: CLI-level env var list has not yet been implemented and will be ignored" ) } if !cmd_opts.preserve_env.is_nothing() { eprintln_ignore_io_error!( "warning: `--preserve-env` has not yet been implemented and will be ignored" ) } let pre = self.policy.init()?; let mut context = build_context(cmd_opts.into(), &pre)?; let policy = self.policy.judge(pre, &context)?; let authorization = policy.authorization(); match authorization { Authorization::Forbidden => { return Err(Error::auth(&format!( "I'm sorry {}. I'm afraid I can't do that", context.current_user.name ))); } Authorization::Allowed(auth) => { self.apply_policy_to_context(&mut context, &policy)?; self.auth_and_update_record_file(&context, auth)?; } } let additional_env = self.authenticator.pre_exec(&context.target_user.name)?; // build environment let current_env = std::env::vars_os().collect(); let target_env = environment::get_target_environment(current_env, additional_env, &context, &policy); let pid = context.process.pid; // run command and return corresponding exit code let exec_result = if context.command.resolved { log_command_execution(&context); crate::exec::run_command(&context, target_env) .map_err(|io_error| Error::Io(Some(context.command.command), io_error)) } else { Err(Error::CommandNotFound(context.command.command)) }; self.authenticator.cleanup(); let ExecOutput { command_exit_reason, restore_signal_handlers, } = exec_result?; // Run any clean-up code before this line. restore_signal_handlers(); match command_exit_reason { ExitReason::Code(code) => exit(code), ExitReason::Signal(signal) => { crate::system::kill(pid, signal)?; } } Ok(()) } pub fn run_validate(mut self, cmd_opts: SudoValidateOptions) -> Result<(), Error> { let pre = self.policy.init()?; let context = build_context(cmd_opts.into(), &pre)?; match pre.validate_authorization() { Authorization::Forbidden => { return Err(Error::auth(&format!( "I'm sorry {}. I'm afraid I can't do that", context.current_user.name ))); } Authorization::Allowed(auth) => { self.auth_and_update_record_file(&context, auth)?; } } Ok(()) } fn auth_and_update_record_file( &mut self, context: &Context, AuthorizationAllowed { must_authenticate, prior_validity, allowed_attempts, }: AuthorizationAllowed, ) -> Result<(), Error> { let scope = RecordScope::for_process(&Process::new()); let mut auth_status = determine_auth_status( must_authenticate, context.use_session_records, scope, context.current_user.uid, &context.current_user, prior_validity, ); self.authenticator.init(context)?; if auth_status.must_authenticate { self.authenticator .authenticate(context.non_interactive, allowed_attempts)?; if let (Some(record_file), Some(scope)) = (&mut auth_status.record_file, scope) { match record_file.create(scope, context.current_user.uid) { Ok(_) => (), Err(e) => { auth_warn!("Could not update session record file with new record: {e}"); } } } } Ok(()) } fn apply_policy_to_context( &mut self, context: &mut Context, policy: &::Policy, ) -> Result<(), crate::common::Error> { // see if the chdir flag is permitted match policy.chdir() { DirChange::Any => {} DirChange::Strict(optdir) => { if let Some(chdir) = &context.chdir { return Err(Error::ChDirNotAllowed { chdir: chdir.clone(), command: context.command.command.clone(), }); } else { context.chdir = optdir.cloned(); } } } // expand tildes in the path with the users home directory if let Some(dir) = context.chdir.take() { context.chdir = Some(dir.expand_tilde_in_path(&context.target_user.name)?) } // override the default pty behaviour if indicated if !policy.use_pty() { context.use_pty = false } Ok(()) } } fn build_context( cmd_opts: OptionsForContext, pre: &dyn PreJudgementPolicy, ) -> Result { let secure_path: String = pre .secure_path() .unwrap_or_else(|| std::env::var("PATH").unwrap_or_default()); Context::build_from_options(cmd_opts, secure_path) } /// This should determine what the authentication status for the given record /// match limit and origin/target user from the context is. fn determine_auth_status( must_policy_authenticate: bool, use_session_records: bool, record_for: Option, auth_uid: UserId, current_user: &CurrentUser, prior_validity: Duration, ) -> AuthStatus { if !must_policy_authenticate { AuthStatus::new(false, None) } else if let (true, Some(record_for)) = (use_session_records, record_for) { match SessionRecordFile::open_for_user(current_user, prior_validity) { Ok(mut sr) => { match sr.touch(record_for, auth_uid) { // if a record was found and updated within the timeout, we do not need to authenticate Ok(TouchResult::Updated { .. }) => AuthStatus::new(false, Some(sr)), Ok(TouchResult::NotFound | TouchResult::Outdated { .. }) => { AuthStatus::new(true, Some(sr)) } Err(e) => { auth_warn!("Unexpected error while reading session information: {e}"); AuthStatus::new(true, None) } } } // if we cannot open the session record file we just assume there is none and continue as normal Err(e) => { auth_warn!("Could not use session information: {e}"); AuthStatus::new(true, None) } } } else { AuthStatus::new(true, None) } } struct AuthStatus { must_authenticate: bool, record_file: Option, } impl AuthStatus { fn new(must_authenticate: bool, record_file: Option) -> AuthStatus { AuthStatus { must_authenticate, record_file, } } } fn log_command_execution(context: &Context) { let tty_info = if let Ok(tty_name) = current_tty_name() { format!("TTY={} ;", escape_os_str_lossy(&tty_name)) } else { String::from("") }; let pwd = escape_os_str_lossy( std::env::current_dir() .as_ref() .map(|s| s.as_os_str()) .unwrap_or_else(|_| OsStr::new("unknown")), ); let user = context.target_user.name.escape_debug().collect::(); auth_info!( "{} : {} PWD={} ; USER={} ; COMMAND={}", &context.current_user.name, tty_info, pwd, user, &context.command ); } sudo-rs-0.2.2/src/sudoers/ast.rs000064400000000000000000000620371046102023000146410ustar 00000000000000use super::ast_names::UserFriendly; use super::basic_parser::*; use super::tokens::*; use crate::common::SudoString; use crate::common::{ HARDENED_ENUM_VALUE_0, HARDENED_ENUM_VALUE_1, HARDENED_ENUM_VALUE_2, HARDENED_ENUM_VALUE_3, HARDENED_ENUM_VALUE_4, }; /// The Sudoers file allows negating items with the exclamation mark. #[cfg_attr(test, derive(Debug, PartialEq, Eq))] #[repr(u32)] pub enum Qualified { Allow(T) = HARDENED_ENUM_VALUE_0, Forbid(T) = HARDENED_ENUM_VALUE_1, } impl Qualified { pub fn as_ref(&self) -> Qualified<&T> { match self { Qualified::Allow(item) => Qualified::Allow(item), Qualified::Forbid(item) => Qualified::Forbid(item), } } pub fn negate(&self) -> Qualified<&T> { match self { Qualified::Allow(item) => Qualified::Forbid(item), Qualified::Forbid(item) => Qualified::Allow(item), } } #[cfg(test)] pub fn as_allow(&self) -> Option<&T> { if let Self::Allow(v) = self { Some(v) } else { None } } } /// Type aliases; many items can be replaced by ALL, aliases, and negated. pub type Spec = Qualified>; pub type SpecList = Vec>; /// An identifier is a name or a #number #[cfg_attr(test, derive(Clone, Debug, PartialEq, Eq))] pub enum Identifier { Name(SudoString), ID(u32), } /// A userspecifier is either a username, or a (non-unix) group name, or netgroup #[cfg_attr(test, derive(Clone, Debug, PartialEq, Eq))] pub enum UserSpecifier { User(Identifier), Group(Identifier), NonunixGroup(Identifier), } /// The RunAs specification consists of a (possibly empty) list of userspecifiers, followed by a (possibly empty) list of groups. pub struct RunAs { pub users: SpecList, pub groups: SpecList, } // `sudo -l l` calls this the `authenticate` option #[derive(Copy, Clone, Default, PartialEq)] #[cfg_attr(test, derive(Debug, Eq))] #[repr(u32)] pub enum Authenticate { #[default] None = HARDENED_ENUM_VALUE_0, // PASSWD: Passwd = HARDENED_ENUM_VALUE_1, // NOPASSWD: Nopasswd = HARDENED_ENUM_VALUE_2, } /// Commands in /etc/sudoers can have attributes attached to them, such as NOPASSWD, NOEXEC, ... #[derive(Default, Clone, PartialEq)] #[cfg_attr(test, derive(Debug, Eq))] pub struct Tag { pub authenticate: Authenticate, pub cwd: Option, } impl Tag { pub fn needs_passwd(&self) -> bool { matches!(self.authenticate, Authenticate::None | Authenticate::Passwd) } } /// Commands with attached attributes. pub struct CommandSpec(pub Vec, pub Spec); /// The main AST object for one sudoer-permission line type PairVec = Vec<(A, Vec)>; pub struct PermissionSpec { pub users: SpecList, pub permissions: PairVec, (Option, CommandSpec)>, } pub type Defs = Vec>; pub struct Def(pub String, pub SpecList); /// AST object for directive specifications (aliases, arguments, etc) #[repr(u32)] pub enum Directive { UserAlias(Defs) = HARDENED_ENUM_VALUE_0, HostAlias(Defs) = HARDENED_ENUM_VALUE_1, CmndAlias(Defs) = HARDENED_ENUM_VALUE_2, RunasAlias(Defs) = HARDENED_ENUM_VALUE_3, Defaults(Vec<(String, ConfigValue)>) = HARDENED_ENUM_VALUE_4, } pub type TextEnum = crate::defaults::StrEnum<'static>; pub enum ConfigValue { Flag(bool), Text(Option>), Num(i64), List(Mode, Vec), Enum(TextEnum), } #[repr(u32)] pub enum Mode { Add = HARDENED_ENUM_VALUE_0, Set = HARDENED_ENUM_VALUE_1, Del = HARDENED_ENUM_VALUE_2, } /// The Sudoers file can contain permissions and directives #[repr(u32)] pub enum Sudo { Spec(PermissionSpec) = HARDENED_ENUM_VALUE_0, Decl(Directive) = HARDENED_ENUM_VALUE_1, Include(String) = HARDENED_ENUM_VALUE_2, IncludeDir(String) = HARDENED_ENUM_VALUE_3, LineComment = HARDENED_ENUM_VALUE_4, } impl Sudo { #[cfg(test)] pub fn is_spec(&self) -> bool { matches!(self, Self::Spec(..)) } #[cfg(test)] pub fn is_decl(&self) -> bool { matches!(self, Self::Decl(..)) } #[cfg(test)] pub fn is_line_comment(&self) -> bool { matches!(self, Self::LineComment) } #[cfg(test)] pub fn is_include(&self) -> bool { matches!(self, Self::Include(..)) } #[cfg(test)] pub fn is_include_dir(&self) -> bool { matches!(self, Self::IncludeDir(..)) } #[cfg(test)] pub fn as_include(&self) -> &str { if let Self::Include(v) = self { v } else { panic!() } } #[cfg(test)] pub fn as_spec(&self) -> Option<&PermissionSpec> { if let Self::Spec(v) = self { Some(v) } else { None } } } /// grammar: /// ```text /// identifier = name /// | # /// ``` impl Parse for Identifier { fn parse(stream: &mut impl CharStream) -> Parsed { if accept_if(|c| c == '#', stream).is_some() { let Digits(guid) = expect_nonterminal(stream)?; make(Identifier::ID(guid)) } else { let Username(name) = try_nonterminal(stream)?; make(Identifier::Name(name)) } } } impl Many for Identifier {} /// grammar: /// ```text /// qualified = T | "!", qualified /// ``` /// /// This computes the correct negation with multiple exclamation marks in the parsing stage so we /// are not bothered by it later. impl Parse for Qualified { fn parse(stream: &mut impl CharStream) -> Parsed { if is_syntax('!', stream)? { let mut neg = true; while is_syntax('!', stream)? { neg = !neg; } let ident = expect_nonterminal(stream)?; if neg { make(Qualified::Forbid(ident)) } else { make(Qualified::Allow(ident)) } } else { let ident = try_nonterminal(stream)?; make(Qualified::Allow(ident)) } } } impl Many for Qualified { const SEP: char = T::SEP; const LIMIT: usize = T::LIMIT; } /// Helper function for parsing `Meta` things where T is not a token fn parse_meta( stream: &mut impl CharStream, embed: impl FnOnce(SudoString) -> T, ) -> Parsed> { if let Some(meta) = try_nonterminal(stream)? { make(match meta { Meta::All => Meta::All, Meta::Alias(alias) => Meta::Alias(alias), Meta::Only(Username(name)) => Meta::Only(embed(name)), }) } else { make(Meta::Only(T::parse(stream)?)) } } /// Since Identifier is not a token, add the parser for `Meta` impl Parse for Meta { fn parse(stream: &mut impl CharStream) -> Parsed { parse_meta(stream, Identifier::Name) } } /// grammar: /// ```text /// userspec = identifier /// | %identifier /// | %:identifier /// | +netgroup /// ``` impl Parse for UserSpecifier { fn parse(stream: &mut impl CharStream) -> Parsed { let userspec = if accept_if(|c| c == '%', stream).is_some() { let ctor = if accept_if(|c| c == ':', stream).is_some() { UserSpecifier::NonunixGroup } else { UserSpecifier::Group }; // in this case we must fail 'hard', since input has been consumed ctor(expect_nonterminal(stream)?) } else if accept_if(|c| c == '+', stream).is_some() { // TODO Netgroups unrecoverable!(stream, "netgroups are not supported yet"); } else { // in this case we must fail 'softly', since no input has been consumed yet UserSpecifier::User(try_nonterminal(stream)?) }; make(userspec) } } impl Many for UserSpecifier {} /// UserSpecifier is not a token, implement the parser for `Meta` impl Parse for Meta { fn parse(stream: &mut impl CharStream) -> Parsed { parse_meta(stream, |name| UserSpecifier::User(Identifier::Name(name))) } } /// grammar: /// ```text /// runas = "(", userlist, (":", grouplist?)?, ")" /// ``` impl Parse for RunAs { fn parse(stream: &mut impl CharStream) -> Parsed { try_syntax('(', stream)?; let users = try_nonterminal(stream).unwrap_or_default(); let groups = maybe(try_syntax(':', stream).and_then(|_| try_nonterminal(stream)))? .unwrap_or_default(); expect_syntax(')', stream)?; make(RunAs { users, groups }) } } /// Implementing the trait Parse for `Meta`. Wrapped in an own object to avoid /// conflicting with a potential future generic parse definition for [Meta]. /// /// The reason for combining a parser for these two unrelated categories is that this is one spot /// where the sudoer grammar isn't nicely LL(1); so at the same place where "NOPASSWD" can appear, /// we could also see "ALL". struct MetaOrTag(Meta); /// A `Modifier` is something that updates the `Tag`. pub type Modifier = Box; // note: at present, "ALL" can be distinguished from a tag using a lookup of 1, since no tag starts with an "A"; but this feels like hanging onto // the parseability by a thread (although the original sudo also has some ugly parts, like 'sha224' being an illegal user name). // to be more general, we impl Parse for Meta so a future tag like "AFOOBAR" can be added with no problem impl Parse for MetaOrTag { fn parse(stream: &mut impl CharStream) -> Parsed { use Meta::*; let AliasName(keyword) = try_nonterminal(stream)?; let mut switch = |modifier: fn(&mut Tag)| { expect_syntax(':', stream)?; make(Box::new(modifier)) }; let result: Modifier = match keyword.as_str() { "PASSWD" => switch(|tag| tag.authenticate = Authenticate::Passwd)?, "NOPASSWD" => switch(|tag| tag.authenticate = Authenticate::Nopasswd)?, "CWD" => { expect_syntax('=', stream)?; let path: ChDir = expect_nonterminal(stream)?; Box::new(move |tag| tag.cwd = Some(path.clone())) } "ALL" => return make(MetaOrTag(All)), alias => return make(MetaOrTag(Alias(alias.to_string()))), }; make(MetaOrTag(Only(result))) } } /// grammar: /// ```text /// commandspec = [tag modifiers]*, command /// ``` impl Parse for CommandSpec { fn parse(stream: &mut impl CharStream) -> Parsed { let mut tags = vec![]; while let Some(MetaOrTag(keyword)) = try_nonterminal(stream)? { use Qualified::Allow; match keyword { Meta::Only(modifier) => tags.push(modifier), Meta::All => return make(CommandSpec(tags, Allow(Meta::All))), Meta::Alias(name) => return make(CommandSpec(tags, Allow(Meta::Alias(name)))), } if tags.len() > Identifier::LIMIT { unrecoverable!(stream, "too many tags for command specifier") } } let start_pos = stream.get_pos(); if let Some(Username(keyword)) = try_nonterminal(stream)? { if keyword == "sudoedit" { // note: special behaviour of forward slashes in wildcards, tread carefully unrecoverable!(pos = start_pos, stream, "sudoedit is not yet supported"); } else if keyword == "list" { unrecoverable!(pos = start_pos, stream, "list is not yet supported"); } else if keyword.starts_with("sha") { unrecoverable!( pos = start_pos, stream, "digest specifications are not supported" ) } else { unrecoverable!( pos = start_pos, stream, "expected command but found {keyword}" ) }; } let cmd: Spec = expect_nonterminal(stream)?; make(CommandSpec(tags, cmd)) } } /// Parsing for a tuple of hostname, runas specifier and commandspec. /// grammar: /// ```text /// (host,runas,commandspec) = hostlist, "=", [runas?, commandspec]+ /// ``` impl Parse for (SpecList, Vec<(Option, CommandSpec)>) { fn parse(stream: &mut impl CharStream) -> Parsed { let hosts = try_nonterminal(stream)?; expect_syntax('=', stream)?; let runas_cmds = expect_nonterminal(stream)?; make((hosts, runas_cmds)) } } /// A hostname, runas specifier, commandspec combination can occur multiple times in a single /// sudoer line (seperated by ":") impl Many for (SpecList, Vec<(Option, CommandSpec)>) { const SEP: char = ':'; } /// Parsing for a tuple of hostname, runas specifier and commandspec. /// grammar: /// ```text /// (runas,commandspec) = runas?, commandspec /// ``` impl Parse for (Option, CommandSpec) { fn parse(stream: &mut impl CharStream) -> Parsed { let runas: Option = try_nonterminal(stream)?; let cmd = if runas.is_some() { expect_nonterminal(stream)? } else { try_nonterminal(stream)? }; make((runas, cmd)) } } /// A runas specifier, commandspec combination can occur multiple times in a single /// sudoer line (seperated by ","); there is some ambiguity in the original grammar: /// commands can also occur multiple times; we parse that here as if they have an omitted /// "runas" specifier (which has to be placed correctly during the AST analysis phase) impl Many for (Option, CommandSpec) {} /// grammar: /// ```text /// sudo = permissionspec /// | Keyword_Alias identifier = identifier_list /// | Defaults (name [+-]?= ...)+ /// ``` /// There is a syntactical ambiguity in the sudoer Directive and Permission specifications, so we /// have to parse them 'together' and do a delayed decision on which category we are in. impl Parse for Sudo { // note: original sudo would reject: // "User_Alias, user machine = command" // but accept: // "user, User_Alias machine = command"; this does the same fn parse(stream: &mut impl CharStream) -> Parsed { if accept_if(|c| c == '@', stream).is_some() { return parse_include(stream); } // the existence of "#include" forces us to handle lines that start with # explicitly if stream.peek() == Some('#') { return if let Ok(ident) = try_nonterminal::(stream) { let first_user = Qualified::Allow(Meta::Only(UserSpecifier::User(ident))); let users = if is_syntax(',', stream)? { // parse the rest of the userlist and add the already-parsed user in front let mut rest = expect_nonterminal::>(stream)?; rest.insert(0, first_user); rest } else { vec![first_user] }; // no need to check get_directive as no other directive starts with # let permissions = expect_nonterminal(stream)?; make(Sudo::Spec(PermissionSpec { users, permissions })) } else { // the failed "try_nonterminal::" will have consumed the '#' // the most ignominious part of sudoers: having to parse bits of comments parse_include(stream).or_else(|_| { while accept_if(|c| c != '\n', stream).is_some() {} make(Sudo::LineComment) }) }; } let start_pos = stream.get_pos(); if let Some(users) = maybe(try_nonterminal::>(stream))? { // element 1 always exists (parse_list fails on an empty list) let key = &users[0]; if let Some(directive) = maybe(get_directive(key, stream))? { if users.len() != 1 { unrecoverable!(pos = start_pos, stream, "invalid user name list"); } make(Sudo::Decl(directive)) } else { let permissions = expect_nonterminal(stream)?; make(Sudo::Spec(PermissionSpec { users, permissions })) } } else { // this will leave whatever could not be parsed on the input stream make(Sudo::LineComment) } } } /// Parse the include/include dir part that comes after the '#' or '@' prefix symbol fn parse_include(stream: &mut impl CharStream) -> Parsed { fn get_path(stream: &mut impl CharStream) -> Parsed { if accept_if(|c| c == '"', stream).is_some() { let QuotedInclude(path) = expect_nonterminal(stream)?; expect_syntax('"', stream)?; make(path) } else { let value_pos = stream.get_pos(); let IncludePath(path) = expect_nonterminal(stream)?; if stream.peek() != Some('\n') { unrecoverable!( pos = value_pos, stream, "use quotes around filenames or escape whitespace" ) } make(path) } } let key_pos = stream.get_pos(); let result = match try_nonterminal(stream)? { Some(Username(key)) if key == "include" => Sudo::Include(get_path(stream)?), Some(Username(key)) if key == "includedir" => Sudo::IncludeDir(get_path(stream)?), _ => unrecoverable!(pos = key_pos, stream, "unknown directive"), }; make(result) } use crate::defaults::sudo_default; use crate::defaults::SudoDefault as Setting; /// grammar: /// ```text /// name = definition [ : name = definiton [ : ... ] ] /// ``` /// impl Parse for Def where T: UserFriendly, Meta: Parse + Many, { fn parse(stream: &mut impl CharStream) -> Parsed { let begin_pos = stream.get_pos(); let AliasName(name) = try_nonterminal(stream)?; if name == "ALL" { unrecoverable!( pos = begin_pos, stream, "the reserved alias ALL cannot be redefined" ); } expect_syntax('=', stream)?; make(Def(name, expect_nonterminal(stream)?)) } } impl Many for Def { const SEP: char = ':'; } fn get_directive( perhaps_keyword: &Spec, stream: &mut impl CharStream, ) -> Parsed { use super::ast::Directive::*; use super::ast::Meta::*; use super::ast::Qualified::*; use super::ast::UserSpecifier::*; let Allow(Only(User(Identifier::Name(keyword)))) = perhaps_keyword else { return reject(); }; match keyword.as_str() { "User_Alias" => make(UserAlias(expect_nonterminal(stream)?)), "Host_Alias" => make(HostAlias(expect_nonterminal(stream)?)), "Cmnd_Alias" | "Cmd_Alias" => make(CmndAlias(expect_nonterminal(stream)?)), "Runas_Alias" => make(RunasAlias(expect_nonterminal(stream)?)), "Defaults" => make(Defaults(expect_nonterminal(stream)?)), _ => reject(), } } /// grammar: /// ```text /// parameter = name [+-]?= ... /// ``` impl Parse for (String, ConfigValue) { fn parse(stream: &mut impl CharStream) -> Parsed { let id_pos = stream.get_pos(); // Parse multiple entries enclosed in quotes (for list-like Defaults-settings) let parse_vars = |stream: &mut _| -> Parsed> { if accept_if(|c| c == '"', stream).is_some() { let mut result = Vec::new(); while let Some(EnvVar(name)) = try_nonterminal(stream)? { result.push(name); if is_syntax('=', stream)? { let EnvVar(_) = expect_nonterminal(stream)?; unrecoverable!(stream, "values in environment variables not yet supported") } if result.len() > Identifier::LIMIT { unrecoverable!(stream, "environment variable list too long") } } expect_syntax('"', stream)?; if result.is_empty() { unrecoverable!(stream, "empty string not allowed"); } make(result) } else { let EnvVar(name) = expect_nonterminal(stream)?; make(vec![name]) } }; // Parse the remainder of a list variable let list_items = |mode: Mode, name: String, cfg: Setting, stream: &mut _| { expect_syntax('=', stream)?; if !matches!(cfg, Setting::List(_)) { unrecoverable!(pos = id_pos, stream, "{name} is not a list parameter"); } make((name, ConfigValue::List(mode, parse_vars(stream)?))) }; // Parse a text parameter let text_item = |stream: &mut _| { if accept_if(|c| c == '"', stream).is_some() { let QuotedText(text) = expect_nonterminal(stream)?; expect_syntax('"', stream)?; make(text) } else { let StringParameter(name) = expect_nonterminal(stream)?; make(name) } }; use crate::defaults::OptTuple; if is_syntax('!', stream)? { let value_pos = stream.get_pos(); let DefaultName(name) = expect_nonterminal(stream)?; let value = match sudo_default(&name) { Some(Setting::Flag(_)) => ConfigValue::Flag(false), Some(Setting::List(_)) => ConfigValue::List(Mode::Set, vec![]), Some(Setting::Text(OptTuple { negated: Some(val), .. })) => ConfigValue::Text(val.map(|x| x.into())), Some(Setting::Enum(OptTuple { negated: Some(val), .. })) => ConfigValue::Enum(val), Some(Setting::Integer( OptTuple { negated: Some(val), .. }, _checker, )) => ConfigValue::Num(val), None => unrecoverable!(pos = value_pos, stream, "unknown setting: '{name}'"), _ => unrecoverable!( pos = value_pos, stream, "'{name}' cannot be used in a boolean context" ), }; make((name, value)) } else { let DefaultName(name) = try_nonterminal(stream)?; let Some(cfg) = sudo_default(&name) else { unrecoverable!(pos = id_pos, stream, "unknown setting: '{name}'"); }; if is_syntax('+', stream)? { list_items(Mode::Add, name, cfg, stream) } else if is_syntax('-', stream)? { list_items(Mode::Del, name, cfg, stream) } else if is_syntax('=', stream)? { let value_pos = stream.get_pos(); match cfg { Setting::Flag(_) => { unrecoverable!(stream, "can't assign to boolean setting '{name}'") } Setting::Integer(_, checker) => { let Numeric(denotation) = expect_nonterminal(stream)?; if let Some(value) = checker(&denotation) { make((name, ConfigValue::Num(value))) } else { unrecoverable!( pos = value_pos, stream, "'{denotation}' is not a valid value for {name}" ); } } Setting::List(_) => { let items = parse_vars(stream)?; make((name, ConfigValue::List(Mode::Set, items))) } Setting::Text(_) => { let text = text_item(stream)?; make((name, ConfigValue::Text(Some(text.into_boxed_str())))) } Setting::Enum(OptTuple { default: key, .. }) => { let text = text_item(stream)?; let Some(value) = key.alt(&text) else { unrecoverable!( pos = value_pos, stream, "'{text}' is not a valid value for {name}" ); }; make((name, ConfigValue::Enum(value))) } } } else { if !matches!(cfg, Setting::Flag(_)) { unrecoverable!(pos = id_pos, stream, "'{name}' is not a boolean setting"); } make((name, ConfigValue::Flag(true))) } } } } impl Many for (String, ConfigValue) {} sudo-rs-0.2.2/src/sudoers/ast_names.rs000064400000000000000000000063611046102023000160220ustar 00000000000000/// This module contains user-friendly names for the various items in the AST, to report in case they are missing pub trait UserFriendly { const DESCRIPTION: &'static str; } // this is in a submodule so it can be switched off and replaced by a blanket implementation for test-cases #[cfg(not(test))] mod names { use super::*; use crate::sudoers::ast::*; use crate::sudoers::tokens; impl UserFriendly for tokens::Digits { const DESCRIPTION: &'static str = "number"; } impl UserFriendly for tokens::Numeric { const DESCRIPTION: &'static str = "number"; } impl UserFriendly for Identifier { const DESCRIPTION: &'static str = "identifier"; } impl UserFriendly for Vec { const DESCRIPTION: &'static str = T::DESCRIPTION; } impl UserFriendly for tokens::Meta { const DESCRIPTION: &'static str = T::DESCRIPTION; } impl UserFriendly for Qualified { const DESCRIPTION: &'static str = T::DESCRIPTION; } impl UserFriendly for tokens::Command { const DESCRIPTION: &'static str = "path to binary (or sudoedit)"; } impl UserFriendly for ( SpecList, Vec<(Option, CommandSpec)>, ) { const DESCRIPTION: &'static str = tokens::Hostname::DESCRIPTION; } impl UserFriendly for (Option, CommandSpec) { const DESCRIPTION: &'static str = "(users:groups) specification"; } // this can never happen, as parse always succeeds impl UserFriendly for Sudo { const DESCRIPTION: &'static str = "nothing"; } impl UserFriendly for UserSpecifier { const DESCRIPTION: &'static str = "user"; } impl UserFriendly for tokens::Hostname { const DESCRIPTION: &'static str = "host name"; } impl UserFriendly for tokens::QuotedText { const DESCRIPTION: &'static str = "non-empty string"; } impl UserFriendly for tokens::QuotedInclude { const DESCRIPTION: &'static str = "non-empty string"; } impl UserFriendly for tokens::StringParameter { const DESCRIPTION: &'static str = tokens::QuotedText::DESCRIPTION; } impl UserFriendly for tokens::IncludePath { const DESCRIPTION: &'static str = "path to file"; } impl UserFriendly for tokens::AliasName { const DESCRIPTION: &'static str = "alias name"; } impl UserFriendly for tokens::DefaultName { const DESCRIPTION: &'static str = "configuration option"; } impl UserFriendly for tokens::EnvVar { const DESCRIPTION: &'static str = "environment variable"; } impl UserFriendly for CommandSpec { const DESCRIPTION: &'static str = tokens::Command::DESCRIPTION; } impl UserFriendly for tokens::ChDir { const DESCRIPTION: &'static str = "directory or '*'"; } impl UserFriendly for (String, ConfigValue) { const DESCRIPTION: &'static str = "parameter"; } impl UserFriendly for Def { const DESCRIPTION: &'static str = "alias definition"; } } #[cfg(test)] impl UserFriendly for T { const DESCRIPTION: &'static str = "elem"; } sudo-rs-0.2.2/src/sudoers/basic_parser.rs000064400000000000000000000342101046102023000164770ustar 00000000000000//! Building blocks for a recursive descent LL(1) parsing method. //! //! The general idea is that a grammar (without left recursion) is translated to a series of //! conditional and unconditional 'acceptance' methods. //! //! For example, assuming we have a parser for integers: //! //! sum = integer | integer + sum //! //! Can get translated as: (representing a sum as `LinkedList`): //! //! ```ignore //! impl Parse for LinkedList { //! fn parse(stream: &mut impl CharStream) -> Parsed> { //! let x = try_nonterminal(stream)?; //! let mut tail = if is_syntax('+', stream)? { //! expect_nonterminal(stream)? //! } else { //! LinkedList::new() //! }; //! tail.push_front(x); //! //! make(tail) //! } //! } //! ``` /// Type holding a parsed object (or error information if parsing failed) pub type Parsed = Result; pub type Position = std::ops::Range<(usize, usize)>; #[cfg_attr(test, derive(Debug, PartialEq))] pub enum Status { Fatal(Position, String), // not recoverable; stream in inconsistent state Reject, // parsing failed by no input consumed } pub fn make(value: T) -> Parsed { Ok(value) } pub fn reject() -> Parsed { Err(Status::Reject) } macro_rules! unrecoverable { (pos=$pos:expr, $stream:ident, $($str:expr),*) => { return Err(crate::sudoers::basic_parser::Status::Fatal($pos .. CharStream::get_pos($stream), format![$($str),*])) }; ($stream:ident, $($str:expr),*) => { { let pos = CharStream::get_pos($stream); return Err(crate::sudoers::basic_parser::Status::Fatal(pos .. pos, format![$($str),*])) } }; ($($str:expr),*) => { return Err(crate::basic_parser::Status::Fatal(Default::default(), format![$($str),*])) }; } pub(super) use unrecoverable; /// This recovers from a failed parsing. pub fn maybe(status: Parsed) -> Parsed> { match status { Ok(x) => Ok(Some(x)), Err(Status::Reject) => Ok(None), Err(err) => Err(err), } } pub use super::char_stream::CharStream; /// All implementations of the Parse trait must satisfy this contract: /// /// If the `parse` method of this trait returns None, the iterator is not advanced; otherwise it is /// advanced beyond the accepted part of the input. i.e. if some input is consumed the method /// *MUST* be producing a `Some` value. pub trait Parse { fn parse(stream: &mut impl CharStream) -> Parsed where Self: Sized; } /// Primitive function: accepts one character that satisfies `predicate`. This is used in the majority /// of all the other `Parse` implementations instead of interfacing with the iterator directly /// (this can facilitate an easy switch to a different method of stream representation in the future). /// Unlike `Parse` implementations this *does not* consume trailing whitespace. /// This function is modelled on `next_if` on `std::Peekable`. pub fn accept_if(predicate: impl Fn(char) -> bool, stream: &mut impl CharStream) -> Option { let c = stream.peek()?; if predicate(c) { stream.advance(); Some(c) } else { None } } /// Structures representing whitespace (trailing whitespace can contain comments) #[cfg_attr(test, derive(PartialEq, Eq))] struct LeadingWhitespace; #[cfg_attr(test, derive(PartialEq, Eq))] struct TrailingWhitespace; #[cfg_attr(test, derive(Debug, PartialEq, Eq))] struct Comment; /// Accept zero or more whitespace characters; fails if the whitespace is not "leading" to something /// (which can be used to detect end-of-input). impl Parse for LeadingWhitespace { fn parse(stream: &mut impl CharStream) -> Parsed { let eat_space = |stream: &mut _| accept_if(|c| "\t ".contains(c), stream); while eat_space(stream).is_some() {} if stream.peek().is_some() { make(LeadingWhitespace {}) } else { unrecoverable!(stream, "superfluous whitespace") } } } /// Accept zero or more whitespace characters; since this accepts zero characters, it /// always succeeds (unless some serious error occurs). This parser also accepts comments, /// since those can form part of trailing white space. impl Parse for TrailingWhitespace { fn parse(stream: &mut impl CharStream) -> Parsed { loop { let _ = LeadingWhitespace::parse(stream); // don't propagate any errors // line continuations if accept_if(|c| c == '\\', stream).is_some() { // do the equivalent of expect_syntax('\n', stream)?, without recursion if accept_if(|c| c == '\n', stream).is_none() { unrecoverable!(stream, "stray escape sequence") } } else { break; } } make(TrailingWhitespace {}) } } /// Parses a comment impl Parse for Comment { fn parse(stream: &mut impl CharStream) -> Parsed { accept_if(|c| c == '#', stream).ok_or(Status::Reject)?; while accept_if(|c| c != '\n', stream).is_some() {} make(Comment {}) } } fn skip_trailing_whitespace(stream: &mut impl CharStream) -> Parsed<()> { TrailingWhitespace::parse(stream)?; make(()) } /// Adheres to the contract of the [Parse] trait, accepts one character and consumes trailing whitespace. pub fn try_syntax(syntax: char, stream: &mut impl CharStream) -> Parsed<()> { accept_if(|c| c == syntax, stream).ok_or(Status::Reject)?; skip_trailing_whitespace(stream)?; make(()) } /// Similar to [try_syntax], but aborts parsing if the expected character is not found. pub fn expect_syntax(syntax: char, stream: &mut impl CharStream) -> Parsed<()> { if try_syntax(syntax, stream).is_err() { let str = if let Some(c) = stream.peek() { c.to_string() } else { "EOF".to_string() }; unrecoverable!(stream, "expecting '{syntax}' but found '{str}'") } make(()) } /// Convenience function: usually try_syntax is called as a test criterion; if this returns true, the input was consumed. pub fn is_syntax(syntax: char, stream: &mut impl CharStream) -> Parsed { let result = maybe(try_syntax(syntax, stream))?; make(result.is_some()) } /// Interface for working with types that implement the [Parse] trait; this allows parsing to use /// type inference. Use this instead of calling [Parse::parse] directly. pub fn try_nonterminal(stream: &mut impl CharStream) -> Parsed { let result = T::parse(stream)?; skip_trailing_whitespace(stream)?; make(result) } /// Interface for working with types that implement the [Parse] trait; this expects to parse /// the given type or gives a fatal parse error if this did not succeed. use super::ast_names::UserFriendly; pub fn expect_nonterminal(stream: &mut impl CharStream) -> Parsed { let begin_pos = stream.get_pos(); match try_nonterminal(stream) { Err(Status::Reject) => { unrecoverable!(pos = begin_pos, stream, "expected {}", T::DESCRIPTION) } result => result, } } /// Something that implements the Token trait is a token (i.e. a string of characters defined by a /// maximum length, character classes, and possible escaping). The class for the first character of /// the token can be different than that of the rest. pub trait Token: Sized { const MAX_LEN: usize = 255; fn construct(s: String) -> Result; fn accept(c: char) -> bool; fn accept_1st(c: char) -> bool { Self::accept(c) } const ALLOW_ESCAPE: bool = false; fn escaped(_: char) -> bool { false } } /// Implementation of the [Parse] trait for anything that implements [Token] impl Parse for T { fn parse(stream: &mut impl CharStream) -> Parsed { fn accept_escaped( pred: fn(char) -> bool, stream: &mut impl CharStream, ) -> Parsed { const ESCAPE: char = '\\'; if T::ALLOW_ESCAPE && accept_if(|c| c == ESCAPE, stream).is_some() { if let Some(c) = accept_if(T::escaped, stream) { Ok(c) } else if pred(ESCAPE) { Ok(ESCAPE) } else { unrecoverable!(stream, "illegal escape sequence") } } else if let Some(c) = accept_if(pred, stream) { Ok(c) } else { reject() } } let start_pos = stream.get_pos(); let mut str = accept_escaped::(T::accept_1st, stream)?.to_string(); while let Some(c) = maybe(accept_escaped::(T::accept, stream))? { if str.len() >= T::MAX_LEN { unrecoverable!(stream, "token exceeds maximum length") } str.push(c) } match T::construct(str) { Ok(result) => make(result), Err(msg) => unrecoverable!(pos = start_pos, stream, "{msg}"), } } } /// Parser for `Option` (this can be used to make the code more readable) impl Parse for Option { fn parse(stream: &mut impl CharStream) -> Parsed { maybe(T::parse(stream)) } } /// Parsing method for lists of items separated by a given character; this adheres to the contract of the [Parse] trait. pub(super) fn parse_list( sep_by: char, max: usize, stream: &mut impl CharStream, ) -> Parsed> where T: Parse + UserFriendly, { let mut elems = Vec::new(); elems.push(try_nonterminal(stream)?); while maybe(try_syntax(sep_by, stream))?.is_some() { if elems.len() >= max { unrecoverable!(stream, "too many items in list") } elems.push(expect_nonterminal(stream)?); } make(elems) } /// Types that implement the Many trait can be parsed multiple tokens into a `Vec`; they are /// seperated by `SEP`. There should also be a limit on the number of items. pub trait Many { const SEP: char = ','; const LIMIT: usize = 127; } /// Generic implementation for parsing multiple items of a type `T` that implements the [Parse] and /// [Many] traits. impl Parse for Vec { fn parse(stream: &mut impl CharStream) -> Parsed { parse_list(T::SEP, T::LIMIT, stream) } } /// Entry point utility function; parse a `Vec` but with fatal error recovery per line pub fn parse_lines(stream: &mut Stream) -> Vec> where T: Parse + UserFriendly, { let mut result = Vec::new(); // this will terminate; if the inner accept_if is an error, either a character will be consumed // by the second accept_if (making progress), or the end of the stream will have been reacherd // (which will cause the next iteration to fall through) while LeadingWhitespace::parse(stream).is_ok() { let item = expect_nonterminal(stream); let parsed_item_ok = item.is_ok(); result.push(item); let _ = maybe(Comment::parse(stream)); if accept_if(|c| c == '\n', stream).is_none() { if parsed_item_ok { let msg = if stream.peek().is_none() { "missing line terminator at end of file" } else { "garbage at end of line" }; let error = |stream: &mut Stream| unrecoverable!(stream, "{msg}"); result.push(error(stream)); } while accept_if(|c| c != '\n', stream).is_some() {} } } result } #[cfg(test)] fn expect_complete(stream: &mut impl CharStream) -> Parsed { let result = expect_nonterminal(stream)?; if let Some(c) = stream.peek() { unrecoverable!(stream, "garbage at end of line: {c}") } make(result) } /// Convenience function (especially useful for writing test cases, to avoid having to write out the /// AST constructors by hand. #[cfg(test)] pub fn parse_string(text: &str) -> Parsed { expect_complete(&mut text.chars().peekable()) } #[cfg(test)] pub fn parse_eval(text: &str) -> T { parse_string(text).unwrap() } #[cfg(test)] mod test { use super::*; impl Token for String { fn construct(val: String) -> Result { Ok(val) } fn accept(c: char) -> bool { c.is_ascii_alphanumeric() } } impl Many for String {} #[test] fn comment_test() { assert_eq!(parse_eval::("# hello"), Comment); } #[test] #[should_panic] fn comment_test_fail() { assert_eq!(parse_eval::("# hello\nsomething"), Comment); } #[test] fn lines_test() { let input = |text: &str| parse_lines(&mut text.chars().peekable()); let s = |text: &str| Ok(text.to_string()); assert_eq!(input("hello\nworld\n"), vec![s("hello"), s("world")]); assert_eq!(input(" hello\nworld\n"), vec![s("hello"), s("world")]); assert_eq!(input("hello \nworld\n"), vec![s("hello"), s("world")]); assert_eq!(input("hello\n world\n"), vec![s("hello"), s("world")]); assert_eq!(input("hello\nworld \n"), vec![s("hello"), s("world")]); assert_eq!(input("hello\nworld")[0..2], vec![s("hello"), s("world")]); let Err(_) = input("hello\nworld")[2] else { panic!() }; let Err(_) = input("hello\nworld:\n")[2] else { panic!() }; } #[test] fn whitespace_test() { assert_eq!( parse_eval::>("hello,something"), vec!["hello", "something"] ); assert_eq!( parse_eval::>("hello , something"), vec!["hello", "something"] ); assert_eq!( parse_eval::>("hello, something"), vec!["hello", "something"] ); assert_eq!( parse_eval::>("hello ,something"), vec!["hello", "something"] ); assert_eq!( parse_eval::>("hello\\\n,something"), vec!["hello", "something"] ); } } sudo-rs-0.2.2/src/sudoers/char_stream.rs000064400000000000000000000032301046102023000163300ustar 00000000000000pub trait CharStream { fn advance(&mut self); fn peek(&mut self) -> Option; fn get_pos(&self) -> (usize, usize); } pub struct PeekableWithPos { iter: std::iter::Peekable, line: usize, col: usize, } impl> PeekableWithPos { pub fn new(src: Iter) -> Self { PeekableWithPos { iter: src.peekable(), line: 1, col: 1, } } } impl> CharStream for PeekableWithPos { fn advance(&mut self) { match self.iter.next() { Some('\n') => { self.line += 1; self.col = 1; } Some(_) => self.col += 1, _ => {} } } fn peek(&mut self) -> Option { self.iter.peek().cloned() } fn get_pos(&self) -> (usize, usize) { (self.line, self.col) } } #[cfg(test)] impl> CharStream for std::iter::Peekable { fn advance(&mut self) { self.next(); } fn peek(&mut self) -> Option { self.peek().cloned() } fn get_pos(&self) -> (usize, usize) { (0, 0) } } #[cfg(test)] mod test { use super::*; #[test] fn test_iter() { let mut stream = PeekableWithPos::::new("12\n3\n".chars()); assert_eq!(stream.peek(), Some('1')); stream.advance(); assert_eq!(stream.peek(), Some('2')); stream.advance(); stream.advance(); assert_eq!(stream.peek(), Some('3')); stream.advance(); assert_eq!(stream.get_pos(), (2, 2)); } } sudo-rs-0.2.2/src/sudoers/entry/verbose.rs000064400000000000000000000036551046102023000166610ustar 00000000000000use core::fmt; use crate::sudoers::{ ast::{Authenticate, RunAs, Tag}, tokens::ChDir, }; use super::Entry; pub struct Verbose<'a>(pub Entry<'a>); impl fmt::Display for Verbose<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self(Entry { run_as, cmd_specs }) = self; let mut last_tag = None; for (tag, cmd_spec) in cmd_specs { if last_tag != Some(tag) { let is_first_iteration = last_tag.is_none(); if !is_first_iteration { f.write_str("\n")?; } write_entry_header(run_as, f)?; write_tag(f, tag)?; f.write_str("\n Commands:")?; } last_tag = Some(tag); f.write_str("\n\t")?; super::write_spec(f, cmd_spec)?; } Ok(()) } } fn write_entry_header(run_as: &RunAs, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("\nSudoers entry:")?; write_users(run_as, f)?; write_groups(run_as, f) } fn write_users(run_as: &RunAs, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("\n RunAsUsers: ")?; super::write_users(run_as, f) } fn write_groups(run_as: &RunAs, f: &mut fmt::Formatter<'_>) -> fmt::Result { if run_as.groups.is_empty() { return Ok(()); } f.write_str("\n RunAsGroups: ")?; super::write_groups(run_as, f) } fn write_tag(f: &mut fmt::Formatter, tag: &Tag) -> fmt::Result { if tag.authenticate != Authenticate::None { f.write_str("\n Options: ")?; if tag.authenticate != Authenticate::Passwd { f.write_str("!")?; } f.write_str("authenticate")?; } if let Some(cwd) = &tag.cwd { f.write_str("\n Cwd: ")?; match cwd { ChDir::Path(path) => write!(f, "{}", path.display())?, ChDir::Any => f.write_str("*")?, } } Ok(()) } sudo-rs-0.2.2/src/sudoers/entry.rs000064400000000000000000000121631046102023000152060ustar 00000000000000use core::fmt; use crate::sudoers::{ ast::{Identifier, Qualified, UserSpecifier}, tokens::{ChDir, Meta}, }; use self::verbose::Verbose; use super::{ ast::{Authenticate, RunAs, Tag}, tokens::Command, }; mod verbose; pub struct Entry<'a> { run_as: &'a RunAs, cmd_specs: Vec<(Tag, Qualified<&'a Meta>)>, } impl<'a> Entry<'a> { pub(super) fn new( run_as: &'a RunAs, cmd_specs: Vec<(Tag, Qualified<&'a Meta>)>, ) -> Self { debug_assert!(!cmd_specs.is_empty()); Self { run_as, cmd_specs } } pub fn verbose(self) -> impl fmt::Display + 'a { Verbose(self) } } impl fmt::Display for Entry<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { run_as, cmd_specs } = self; f.write_str(" (")?; write_users(run_as, f)?; if !run_as.groups.is_empty() { f.write_str(" : ")?; } write_groups(run_as, f)?; f.write_str(") ")?; let mut last_tag = None; for (tag, spec) in cmd_specs { let is_first_iteration = last_tag.is_none(); if !is_first_iteration { f.write_str(", ")?; } write_tag(f, tag, last_tag)?; last_tag = Some(tag); write_spec(f, spec)?; } Ok(()) } } fn write_users(run_as: &RunAs, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { if run_as.users.is_empty() { // XXX assumes that the superuser is called "root" f.write_str("root")?; } let mut is_first_user = true; for user in &run_as.users { if !is_first_user { f.write_str(", ")?; } is_first_user = false; let meta = match user { Qualified::Allow(meta) => meta, Qualified::Forbid(meta) => { f.write_str("!")?; meta } }; match meta { Meta::All => f.write_str("ALL")?, Meta::Only(user) => { let ident = match user { UserSpecifier::User(ident) => ident, UserSpecifier::Group(ident) => { f.write_str("%")?; ident } UserSpecifier::NonunixGroup(ident) => { f.write_str("%:")?; ident } }; match ident { Identifier::Name(name) => f.write_str(name)?, Identifier::ID(id) => write!(f, "#{id}")?, } } Meta::Alias(alias) => f.write_str(alias)?, } } Ok(()) } fn write_groups(run_as: &RunAs, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { let mut is_first_group = true; for group in &run_as.groups { if !is_first_group { f.write_str(", ")?; } is_first_group = false; let meta = match group { Qualified::Allow(meta) => meta, Qualified::Forbid(meta) => { f.write_str("!")?; meta } }; match meta { Meta::All => f.write_str("ALL")?, Meta::Only(ident) => match ident { Identifier::Name(name) => f.write_str(name)?, Identifier::ID(id) => write!(f, "#{id}")?, }, Meta::Alias(alias) => f.write_str(alias)?, } } Ok(()) } fn write_tag(f: &mut fmt::Formatter, tag: &Tag, last_tag: Option<&Tag>) -> fmt::Result { let (cwd, auth) = if let Some(last_tag) = last_tag { let cwd = if last_tag.cwd == tag.cwd { None } else { tag.cwd.as_ref() }; let auth = if last_tag.authenticate == tag.authenticate { None } else { Some(tag.authenticate) }; (cwd, auth) } else { (tag.cwd.as_ref(), Some(tag.authenticate)) }; if let Some(cwd) = cwd { f.write_str("CWD=")?; match cwd { ChDir::Path(path) => write!(f, "{}", path.display())?, ChDir::Any => f.write_str("*")?, } f.write_str(" ")?; } if let Some(auth) = auth { if auth != Authenticate::None { let tag = if auth == Authenticate::Passwd { "PASSWD" } else { "NOPASSWD" }; f.write_str(tag)?; f.write_str(": ")?; } } Ok(()) } fn write_spec(f: &mut fmt::Formatter, spec: &Qualified<&Meta>) -> fmt::Result { let meta = match spec { Qualified::Allow(meta) => meta, Qualified::Forbid(meta) => { f.write_str("!")?; meta } }; match meta { Meta::All => f.write_str("ALL")?, Meta::Only((cmd, args)) => { write!(f, "{cmd}")?; if let Some(args) = args { for arg in args.iter() { write!(f, " {arg}")?; } } } Meta::Alias(alias) => f.write_str(alias)?, } Ok(()) } sudo-rs-0.2.2/src/sudoers/mod.rs000064400000000000000000000716101046102023000146260ustar 00000000000000#![forbid(unsafe_code)] //! Code that checks (and in the future: lists) permissions in the sudoers file mod ast; mod ast_names; mod basic_parser; mod char_stream; mod entry; mod tokens; use std::collections::{HashMap, HashSet}; use std::path::{Path, PathBuf}; use std::{io, mem}; use crate::common::resolve::resolve_path; use crate::log::auth_warn; use crate::system::interface::{UnixGroup, UnixUser}; use crate::system::{self, can_execute}; use ast::*; use tokens::*; /// How many nested include files do we allow? const INCLUDE_LIMIT: u8 = 128; /// Export some necessary symbols from modules pub use ast::TextEnum; pub struct Error { pub source: Option, pub location: Option, pub message: String, } #[derive(Default)] pub struct Sudoers { rules: Vec, aliases: AliasTable, settings: Settings, } /// A structure that represents what the user wants to do pub struct Request<'a, User: UnixUser, Group: UnixGroup> { pub user: &'a User, pub group: &'a Group, pub command: &'a Path, pub arguments: &'a [String], } pub struct ListRequest<'a, User: UnixUser, Group: UnixGroup> { pub target_user: &'a User, pub target_group: &'a Group, } #[derive(Default)] pub struct Judgement { flags: Option, settings: Settings, } mod policy; pub use policy::{Authorization, AuthorizationAllowed, DirChange, Policy, PreJudgementPolicy}; pub use self::entry::Entry; /// This function takes a file argument for a sudoers file and processes it. impl Sudoers { pub fn open(path: impl AsRef) -> Result<(Sudoers, Vec), io::Error> { let sudoers = open_sudoers(path.as_ref())?; Ok(analyze(path.as_ref(), sudoers)) } pub fn read>( reader: R, path: P, ) -> Result<(Sudoers, Vec), io::Error> { let sudoers = read_sudoers(reader)?; Ok(analyze(path.as_ref(), sudoers)) } pub fn check, Group: UnixGroup>( &self, am_user: &User, on_host: &system::Hostname, request: Request, ) -> Judgement { // exception: if user is root or does not switch users, NOPASSWD is implied let skip_passwd = am_user.is_root() || (request.user == am_user && in_group(am_user, request.group)); let mut flags = check_permission(self, am_user, on_host, request); if let Some(Tag { authenticate, .. }) = flags.as_mut() { if skip_passwd { *authenticate = Authenticate::Nopasswd; } } Judgement { flags, settings: self.settings.clone(), // this is wasteful, but in the future this will not be a simple clone and it avoids a lifetime } } pub fn check_list_permission, Group: UnixGroup>( &self, invoking_user: &User, hostname: &system::Hostname, request: ListRequest, ) -> Judgement { // exception: if user is root or does not switch users, NOPASSWD is implied let skip_passwd = invoking_user.is_root() || (request.target_user == invoking_user && in_group(invoking_user, request.target_group)); let mut flags = self .matching_user_specs(invoking_user, hostname) .flatten() .fold(None::, |outcome, (_, (tag, _))| { if let Some(outcome) = outcome { let new_outcome = if outcome.needs_passwd() { tag } else { outcome }; Some(new_outcome) } else { Some(tag) } }); if let Some(Tag { authenticate, .. }) = flags.as_mut() { if skip_passwd { *authenticate = Authenticate::Nopasswd; } } Judgement { flags, settings: self.settings.clone(), // this is wasteful, but in the future this will not be a simple clone and it avoids a lifetime } } /// returns `User_Spec`s that match `invoking_user` and `hostname` /// /// it also distributes `Tag_Spec`s across the `Cmnd_Spec` list of each `User_Spec` /// /// the outer iterator are the `User_Spec`s; the inner iterator are the `Cmnd_Spec`s of /// said `User_Spec`s fn matching_user_specs<'a: 'b + 'c, 'b: 'c, 'c, User: UnixUser + PartialEq>( &'a self, invoking_user: &'b User, hostname: &'c system::Hostname, ) -> impl Iterator, (Tag, &'a Spec))> + 'b> + 'c { let Self { rules, aliases, .. } = self; let user_aliases = get_aliases(&aliases.user, &match_user(invoking_user)); let host_aliases = get_aliases(&aliases.host, &match_token(hostname)); rules .iter() .filter_map(move |sudo| { find_item(&sudo.users, &match_user(invoking_user), &user_aliases)?; Some(&sudo.permissions) }) .flatten() .filter_map(move |(hosts, runas_cmds)| { find_item(hosts, &match_token(hostname), &host_aliases)?; Some(distribute_tags(runas_cmds)) }) } /// returns `User_Spec`s that match `invoking_user` and `hostname` in a print-able format pub fn matching_entries<'a, User: UnixUser + PartialEq>( &'a self, invoking_user: &User, hostname: &system::Hostname, ) -> Vec> { // NOTE this method MUST NOT perform any filtering that `Self::check` does not do to // ensure `sudo $command` and `sudo --list` use the same permission checking logic let user_specs = self.matching_user_specs(invoking_user, hostname); let cmnd_aliases = unfold_alias_table(&self.aliases.cmnd); let mut entries = vec![]; for cmd_specs in user_specs { group_cmd_specs_per_runas(cmd_specs, &mut entries, &cmnd_aliases); } entries } pub(crate) fn solve_editor_path(&self) -> Option { if self.settings.flags.contains("env_editor") { for key in ["SUDO_EDITOR", "VISUAL", "EDITOR"] { if let Some(var) = std::env::var_os(key) { let path = Path::new(&var); if can_execute(path) { return Some(path.to_owned()); } let path = resolve_path( path, &std::env::var("PATH").unwrap_or(env!("DEFAULT_PATH").to_string()), ); if let Some(path) = path { return Some(path); } } } } None } } fn group_cmd_specs_per_runas<'a>( cmnd_specs: impl Iterator, (Tag, &'a Spec))>, entries: &mut Vec>, cmnd_aliases: &HashMap<&String, &'a Vec>>, ) { static EMPTY_RUNAS: RunAs = RunAs { users: Vec::new(), groups: Vec::new(), }; let mut runas = None; let mut collected_specs = vec![]; for (new_runas, (tag, spec)) in cmnd_specs { if let Some(new_runas) = new_runas { if !collected_specs.is_empty() { entries.push(Entry::new( runas.take().unwrap_or(&EMPTY_RUNAS), mem::take(&mut collected_specs), )); } runas = Some(new_runas); } let (negate, meta) = match spec { Qualified::Allow(meta) => (false, meta), Qualified::Forbid(meta) => (true, meta), }; if let Meta::Alias(alias_name) = meta { if let Some(specs) = cmnd_aliases.get(alias_name) { // expand Cmnd_Alias for spec in specs.iter() { let new_spec = if negate { spec.negate() } else { spec.as_ref() }; collected_specs.push((tag.clone(), new_spec)) } } } else { collected_specs.push((tag, spec.as_ref())); } } if !collected_specs.is_empty() { entries.push(Entry::new(runas.unwrap_or(&EMPTY_RUNAS), collected_specs)); } } fn read_sudoers(mut reader: R) -> io::Result>> { // it's a bit frustrating that BufReader.chars() does not exist let mut buffer = String::new(); reader.read_to_string(&mut buffer)?; use basic_parser::parse_lines; use char_stream::*; Ok(parse_lines(&mut PeekableWithPos::new(buffer.chars()))) } fn open_sudoers(path: &Path) -> io::Result>> { let source = crate::system::secure_open(path, false)?; read_sudoers(source) } fn open_subsudoers(path: &Path) -> io::Result>> { let source = crate::system::secure_open(path, true)?; read_sudoers(source) } #[derive(Default)] pub(super) struct AliasTable { user: VecOrd>, host: VecOrd>, cmnd: VecOrd>, runas: VecOrd>, } /// A vector with a list defining the order in which it needs to be processed type VecOrd = (Vec, Vec); fn elems(vec: &VecOrd) -> impl Iterator { vec.0.iter().map(|&i| &vec.1[i]) } /// Check if the user `am_user` is allowed to run `cmdline` on machine `on_host` as the requested /// user/group. Not that in the sudoers file, later permissions override earlier restrictions. /// The `cmdline` argument should already be ready to essentially feed to an exec() call; or be /// a special command like 'sudoedit'. // This code is structure to allow easily reading the 'happy path'; i.e. as soon as something // doesn't match, we escape using the '?' mechanism. fn check_permission, Group: UnixGroup>( sudoers: &Sudoers, am_user: &User, on_host: &system::Hostname, request: Request, ) -> Option { let cmdline = (request.command, request.arguments); let aliases = &sudoers.aliases; let cmnd_aliases = get_aliases(&aliases.cmnd, &match_command(cmdline)); let runas_user_aliases = get_aliases(&aliases.runas, &match_user(request.user)); let runas_group_aliases = get_aliases(&aliases.runas, &match_group_alias(request.group)); // NOTE to ensure `sudo $command` and `sudo --list` behave the same, both this function and // `Sudoers::matching_entries` must call this `matching_user_specs` method let matching_user_specs = sudoers.matching_user_specs(am_user, on_host).flatten(); let allowed_commands = matching_user_specs.filter_map(|(runas, cmdspec)| { if let Some(RunAs { users, groups }) = runas { let stays_in_group = in_group(request.user, request.group); if request.user != am_user || (stays_in_group && !users.is_empty()) { find_item(users, &match_user(request.user), &runas_user_aliases)? } if !stays_in_group { find_item(groups, &match_group(request.group), &runas_group_aliases)? } } else if !(request.user.is_root() && in_group(request.user, request.group)) { None?; } Some(cmdspec) }); find_item(allowed_commands, &match_command(cmdline), &cmnd_aliases) } /// Process a raw parsed AST bit of RunAs + Command specifications: /// - RunAs specifications distribute over the commands that follow (until overridden) /// - Tags accumulate over the entire line fn distribute_tags( runas_cmds: &[(Option, CommandSpec)], ) -> impl Iterator, (Tag, &Spec))> { runas_cmds.iter().scan( (None, Default::default()), |(mut last_runas, tag), (runas, CommandSpec(mods, cmd))| { last_runas = runas.as_ref().or(last_runas); for f in mods { f(tag); } Some((last_runas, (tag.clone(), cmd))) }, ) } /// A type to represent positive or negative association with an alias; i.e. if a key maps to true, /// the alias affirms membership, if a key maps to false, the alias denies membership; if a key /// isn't present membership is affirmed nor denied type FoundAliases = HashMap; /// Find an item matching a certain predicate in an collection (optionally attributed) list of /// identifiers; identifiers can be directly identifying, wildcards, and can either be positive or /// negative (i.e. preceeded by an even number of exclamation marks in the sudoers file) fn find_item<'a, Predicate, Iter, T: 'a>( items: Iter, matches: &Predicate, aliases: &FoundAliases, ) -> Option<::Info> where Predicate: Fn(&T) -> bool, Iter: IntoIterator, Iter::Item: WithInfo>, { let mut result = None; for item in items { let (judgement, who) = match item.clone().to_inner() { Qualified::Forbid(x) => (false, x), Qualified::Allow(x) => (true, x), }; let info = || item.to_info(); match who { Meta::All => result = judgement.then(info), Meta::Only(ident) if matches(ident) => result = judgement.then(info), Meta::Alias(id) if aliases.contains_key(id) => { result = if aliases[id] { judgement.then(info) } else { // in this case, an explicit negation in the alias applies (!judgement).then(info) } } _ => {} }; } result } /// A interface to access optional "satellite data" trait WithInfo: Clone { type Item; type Info; fn to_inner(self) -> Self::Item; fn to_info(self) -> Self::Info; } /// A specific interface for `Spec` --- we can't make a generic one; /// A `Spec` does not contain any additional information. impl<'a, T> WithInfo for &'a Spec { type Item = &'a Spec; type Info = (); fn to_inner(self) -> &'a Spec { self } fn to_info(self) {} } /// A commandspec can be "tagged" impl<'a> WithInfo for (Tag, &'a Spec) { type Item = &'a Spec; type Info = Tag; fn to_inner(self) -> &'a Spec { self.1 } fn to_info(self) -> Tag { self.0 } } /// Now follow a collection of functions used as closures for `find_item` fn match_user(user: &impl UnixUser) -> impl Fn(&UserSpecifier) -> bool + '_ { move |spec| match spec { UserSpecifier::User(id) => match_identifier(user, id), UserSpecifier::Group(Identifier::Name(name)) => user.in_group_by_name(name.as_cstr()), UserSpecifier::Group(Identifier::ID(num)) => user.in_group_by_gid(*num), _ => todo!(), // nonunix-groups, netgroups, etc. } } fn in_group(user: &impl UnixUser, group: &impl UnixGroup) -> bool { user.in_group_by_gid(group.as_gid()) } fn match_group(group: &impl UnixGroup) -> impl Fn(&Identifier) -> bool + '_ { move |id| match id { Identifier::ID(num) => group.as_gid() == *num, Identifier::Name(name) => group.try_as_name().map_or(false, |s| name == s), } } fn match_group_alias(group: &impl UnixGroup) -> impl Fn(&UserSpecifier) -> bool + '_ { move |spec| match spec { UserSpecifier::User(ident) => match_group(group)(ident), /* the parser does not allow this, but can happen due to Runas_Alias, * see https://github.com/memorysafety/sudo-rs/issues/13 */ _ => { auth_warn!("warning: ignoring %group syntax in runas_alias for checking sudo -g"); false } } } fn match_token>( text: &str, ) -> (impl Fn(&T) -> bool + '_) { move |token| token.as_str() == text } fn match_command<'a>((cmd, args): (&'a Path, &'a [String])) -> (impl Fn(&Command) -> bool + 'a) { let opts = glob::MatchOptions { require_literal_separator: true, ..glob::MatchOptions::new() }; move |(cmdpat, argpat)| { cmdpat.matches_path_with(cmd, opts) && argpat.as_ref().map_or(true, |vec| args == vec.as_ref()) } } fn unfold_alias_table(table: &VecOrd>) -> HashMap<&String, &Vec>>> { elems(table).map(|Def(id, list)| (id, list)).collect() } /// Find all the aliases that a object is a member of; this requires [sanitize_alias_table] to have run first; /// I.e. this function should not be "pub". fn get_aliases(table: &VecOrd>, pred: &Predicate) -> FoundAliases where Predicate: Fn(&T) -> bool, { use std::iter::once; let all = Qualified::Allow(Meta::All); let mut set = HashMap::new(); for Def(id, list) in elems(table) { if find_item(list, &pred, &set).is_some() { set.insert(id.clone(), true); } else if find_item(once(&all).chain(list), &pred, &set).is_none() { // the item wasn't found even if we prepend ALL to the list of definitions; that means // it is explicitly excluded by the alias definition. set.insert(id.clone(), false); } } set } /// Code to map an ast::Identifier to the UnixUser trait fn match_identifier(user: &impl UnixUser, ident: &ast::Identifier) -> bool { match ident { Identifier::Name(name) => user.has_name(name), Identifier::ID(num) => user.has_uid(*num), } } #[derive(Clone)] pub struct Settings { pub flags: HashSet, pub str_value: HashMap>>, pub enum_value: HashMap, pub int_value: HashMap, pub list: HashMap>, } impl Default for Settings { fn default() -> Self { let mut this = Settings { flags: Default::default(), str_value: Default::default(), enum_value: Default::default(), int_value: Default::default(), list: Default::default(), }; use crate::defaults::{sudo_default, OptTuple, SudoDefault}; for key in crate::defaults::ALL_PARAMS.iter() { match sudo_default(key).expect("internal error") { SudoDefault::Flag(default) => { if default { this.flags.insert(key.to_string()); } } SudoDefault::Text(OptTuple { default, .. }) => { this.str_value .insert(key.to_string(), default.map(|x| x.into())); } SudoDefault::Enum(OptTuple { default, .. }) => { this.enum_value.insert(key.to_string(), default); } SudoDefault::Integer(OptTuple { default, .. }, _) => { this.int_value.insert(key.to_string(), default); } SudoDefault::List(default) => { this.list.insert( key.to_string(), default.iter().map(|x| x.to_string()).collect(), ); } } } this } } /// Process a sudoers-parsing file into a workable AST fn analyze( path: &Path, sudoers: impl IntoIterator>, ) -> (Sudoers, Vec) { use ConfigValue::*; use Directive::*; let mut result: Sudoers = Default::default(); fn resolve_relative(base: &Path, path: impl AsRef) -> PathBuf { if path.as_ref().is_relative() { // there should always be a parent since we start with /etc/sudoers, and make every other path // absolute based on previous inputs; not having a parent is therefore a serious bug base.parent() .expect("invalid hardcoded path in sudo-rs") .join(path) } else { path.as_ref().into() } } impl Sudoers { fn include( &mut self, parent: &Path, path: &Path, diagnostics: &mut Vec, count: &mut u8, ) { if *count >= INCLUDE_LIMIT { diagnostics.push(Error { source: Some(parent.to_owned()), location: None, message: format!("include file limit reached opening '{}'", path.display()), }) // FIXME: this will cause an error in `visudo` if we open a non-privileged sudoers file // that includes another non-privileged sudoer files. } else { match open_subsudoers(path) { Ok(subsudoer) => { *count += 1; self.process(path, subsudoer, diagnostics, count) } Err(e) => { let message = if e.kind() == io::ErrorKind::NotFound { // improve the error message in this case format!("cannot open sudoers file '{}'", path.display()) } else { e.to_string() }; diagnostics.push(Error { source: Some(parent.to_owned()), location: None, message, }) } } } } fn process( &mut self, cur_path: &Path, sudoers: impl IntoIterator>, diagnostics: &mut Vec, safety_count: &mut u8, ) { for item in sudoers { match item { Ok(line) => match line { Sudo::LineComment => {} Sudo::Spec(permission) => self.rules.push(permission), Sudo::Decl(UserAlias(mut def)) => self.aliases.user.1.append(&mut def), Sudo::Decl(HostAlias(mut def)) => self.aliases.host.1.append(&mut def), Sudo::Decl(CmndAlias(mut def)) => self.aliases.cmnd.1.append(&mut def), Sudo::Decl(RunasAlias(mut def)) => self.aliases.runas.1.append(&mut def), Sudo::Decl(Defaults(params)) => { for (name, value) in params { self.set_default(name, value) } } Sudo::Include(path) => self.include( cur_path, &resolve_relative(cur_path, path), diagnostics, safety_count, ), Sudo::IncludeDir(path) => { if path.contains("%h") { diagnostics.push(Error{ source: Some(cur_path.to_owned()), location: None, message: format!("cannot open sudoers file {path}: percent escape %h in includedir is unsupported")}); continue; } let path = resolve_relative(cur_path, path); let Ok(files) = std::fs::read_dir(&path) else { diagnostics.push(Error { source: Some(cur_path.to_owned()), location: None, message: format!("cannot open sudoers file {}", path.display()), }); continue; }; let mut safe_files = files .filter_map(|direntry| { let path = direntry.ok()?.path(); let text = path.file_name()?.to_str()?; if text.ends_with('~') || text.contains('.') { None } else { Some(path) } }) .collect::>(); safe_files.sort(); for file in safe_files { self.include(cur_path, file.as_ref(), diagnostics, safety_count) } } }, Err(basic_parser::Status::Fatal(pos, message)) => diagnostics.push(Error { source: Some(cur_path.to_owned()), location: Some(pos), message, }), Err(_) => panic!("internal parser error"), } } } fn set_default(&mut self, name: String, value: ConfigValue) { match value { Flag(value) => { if value { self.settings.flags.insert(name); } else { self.settings.flags.remove(&name); } } List(mode, values) => { let slot: &mut _ = self.settings.list.entry(name).or_default(); match mode { Mode::Set => *slot = values.into_iter().collect(), Mode::Add => slot.extend(values), Mode::Del => { for key in values { slot.remove(&key); } } } } Text(value) => { self.settings.str_value.insert(name, value); } Enum(value) => { self.settings.enum_value.insert(name, value); } Num(value) => { self.settings.int_value.insert(name, value); } } } } let mut diagnostics = vec![]; result.process(path, sudoers, &mut diagnostics, &mut 0); let alias = &mut result.aliases; alias.user.0 = sanitize_alias_table(&alias.user.1, &mut diagnostics); alias.host.0 = sanitize_alias_table(&alias.host.1, &mut diagnostics); alias.cmnd.0 = sanitize_alias_table(&alias.cmnd.1, &mut diagnostics); alias.runas.0 = sanitize_alias_table(&alias.runas.1, &mut diagnostics); (result, diagnostics) } /// Alias definition inin a Sudoers file can come in any order; and aliases can refer to other aliases, etc. /// It is much easier if they are presented in a "definitional order" (i.e. aliases that use other aliases occur later) /// At the same time, this is a good place to detect problems in the aliases, such as unknown aliases and cycles. fn sanitize_alias_table(table: &Vec>, diagnostics: &mut Vec) -> Vec { fn remqualify(item: &Qualified) -> &U { match item { Qualified::Allow(x) => x, Qualified::Forbid(x) => x, } } // perform a topological sort (hattip david@tweedegolf.com) to produce a derangement struct Visitor<'a, T> { seen: HashSet, table: &'a Vec>, order: Vec, diagnostics: &'a mut Vec, } impl Visitor<'_, T> { fn complain(&mut self, text: String) { self.diagnostics.push(Error { source: None, location: None, message: text, }) } fn visit(&mut self, pos: usize) { if self.seen.insert(pos) { let Def(_, members) = &self.table[pos]; for elem in members { let Meta::Alias(name) = remqualify(elem) else { break; }; let Some(dependency) = self.table.iter().position(|Def(id, _)| id == name) else { self.complain(format!("undefined alias: '{name}'")); continue; }; self.visit(dependency); } self.order.push(pos); } else if !self.order.contains(&pos) { let Def(id, _) = &self.table[pos]; self.complain(format!("recursive alias: '{id}'")); } } } let mut visitor = Visitor { seen: HashSet::new(), table, order: Vec::with_capacity(table.len()), diagnostics, }; let mut dupe = HashSet::new(); for (i, Def(name, _)) in table.iter().enumerate() { if !dupe.insert(name) { visitor.complain(format!("multiple occurrences of '{name}'")); } else { visitor.visit(i); } } visitor.order } #[cfg(test)] mod test; sudo-rs-0.2.2/src/sudoers/policy.rs000064400000000000000000000122431046102023000153430ustar 00000000000000use super::Sudoers; use super::Judgement; use crate::common::{SudoPath, HARDENED_ENUM_VALUE_0, HARDENED_ENUM_VALUE_1}; use crate::system::time::Duration; /// Data types and traits that represent what the "terms and conditions" are after a succesful /// permission check. /// /// The trait definitions can be part of some global crate in the future, if we support more /// than just the sudoers file. use std::collections::HashSet; pub trait Policy { fn authorization(&self) -> Authorization { Authorization::Forbidden } fn chdir(&self) -> DirChange { DirChange::Strict(None) } fn env_keep(&self) -> &HashSet; fn env_check(&self) -> &HashSet; fn secure_path(&self) -> Option; fn use_pty(&self) -> bool; } #[must_use] #[cfg_attr(test, derive(Debug, PartialEq))] #[repr(u32)] pub enum Authorization { Allowed(AuthorizationAllowed) = HARDENED_ENUM_VALUE_0, Forbidden = HARDENED_ENUM_VALUE_1, } #[cfg_attr(test, derive(Debug, PartialEq))] pub struct AuthorizationAllowed { pub must_authenticate: bool, pub allowed_attempts: u16, pub prior_validity: Duration, } #[must_use] #[cfg_attr(test, derive(Debug, PartialEq))] #[repr(u32)] pub enum DirChange<'a> { Strict(Option<&'a SudoPath>) = HARDENED_ENUM_VALUE_0, Any = HARDENED_ENUM_VALUE_1, } impl Policy for Judgement { fn authorization(&self) -> Authorization { if let Some(tag) = &self.flags { let allowed_attempts = self.settings.int_value["passwd_tries"].try_into().unwrap(); let valid_seconds = self.settings.int_value["timestamp_timeout"]; Authorization::Allowed(AuthorizationAllowed { must_authenticate: tag.needs_passwd(), allowed_attempts, prior_validity: Duration::seconds(valid_seconds), }) } else { Authorization::Forbidden } } fn env_keep(&self) -> &HashSet { &self.settings.list["env_keep"] } fn env_check(&self) -> &HashSet { &self.settings.list["env_check"] } fn chdir(&self) -> DirChange { match self.flags.as_ref().expect("not authorized").cwd.as_ref() { None => DirChange::Strict(None), Some(super::ChDir::Any) => DirChange::Any, Some(super::ChDir::Path(path)) => DirChange::Strict(Some(path)), } } fn secure_path(&self) -> Option { self.settings.str_value["secure_path"] .as_ref() .map(|s| s.to_string()) } fn use_pty(&self) -> bool { self.settings.flags.contains("use_pty") } } pub trait PreJudgementPolicy { fn secure_path(&self) -> Option; fn validate_authorization(&self) -> Authorization; } impl PreJudgementPolicy for Sudoers { fn secure_path(&self) -> Option { self.settings.str_value["secure_path"] .as_ref() .map(|s| s.to_string()) } fn validate_authorization(&self) -> Authorization { Authorization::Allowed(AuthorizationAllowed { must_authenticate: true, allowed_attempts: self.settings.int_value["passwd_tries"].try_into().unwrap(), prior_validity: Duration::seconds(self.settings.int_value["timestamp_timeout"]), }) } } #[cfg(test)] mod test { use super::*; use crate::sudoers::{ ast::{Authenticate, Tag}, tokens::ChDir, }; impl Judgement { fn mod_flag(&mut self, mut modify: impl FnMut(&mut Tag)) { let mut tag: Tag = self.flags.clone().unwrap_or_default(); modify(&mut tag); self.flags = Some(tag); } } // TODO: refactor the tag-updates to be more readable #[test] fn authority_xlat_test() { let mut judge: Judgement = Default::default(); assert_eq!(judge.authorization(), Authorization::Forbidden); judge.mod_flag(|tag| tag.authenticate = Authenticate::Passwd); assert_eq!( judge.authorization(), Authorization::Allowed(AuthorizationAllowed { must_authenticate: true, allowed_attempts: 3, prior_validity: Duration::minutes(15), }) ); judge.mod_flag(|tag| tag.authenticate = Authenticate::Nopasswd); assert_eq!( judge.authorization(), Authorization::Allowed(AuthorizationAllowed { must_authenticate: false, allowed_attempts: 3, prior_validity: Duration::minutes(15), }) ); } #[test] fn chdir_test() { let mut judge = Judgement { flags: Some(Tag::default()), ..Default::default() }; assert_eq!(judge.chdir(), DirChange::Strict(None)); judge.mod_flag(|tag| tag.cwd = Some(ChDir::Any)); assert_eq!(judge.chdir(), DirChange::Any); judge.mod_flag(|tag| tag.cwd = Some(ChDir::Path("/usr".into()))); assert_eq!(judge.chdir(), (DirChange::Strict(Some(&"/usr".into())))); judge.mod_flag(|tag| tag.cwd = Some(ChDir::Path("/bin".into()))); assert_eq!(judge.chdir(), (DirChange::Strict(Some(&"/bin".into())))); } } sudo-rs-0.2.2/src/sudoers/test/mod.rs000064400000000000000000000550551046102023000156120ustar 00000000000000use std::ffi::CStr; use super::ast; use super::*; use basic_parser::{parse_eval, parse_lines, parse_string}; #[derive(PartialEq)] struct Named(&'static str); fn dummy_cksum(name: &str) -> u32 { if name == "root" { 0 } else { 1000 + name.chars().fold(0, |x, y| (x * 97 + y as u32) % 1361) } } impl UnixUser for Named { fn has_name(&self, name: &str) -> bool { self.0 == name } fn has_uid(&self, uid: u32) -> bool { dummy_cksum(self.0) == uid } fn in_group_by_name(&self, name: &CStr) -> bool { self.has_name(name.to_str().unwrap()) } fn in_group_by_gid(&self, gid: u32) -> bool { dummy_cksum(self.0) == gid } fn is_root(&self) -> bool { self.0 == "root" } } impl UnixGroup for Named { fn as_gid(&self) -> crate::system::interface::GroupId { dummy_cksum(self.0) } fn try_as_name(&self) -> Option<&str> { Some(self.0) } } macro_rules! request { ($user:ident) => { (&Named(stringify!($user)), &Named(stringify!($user))) }; ($user:ident, $group:ident) => { (&Named(stringify!($user)), &Named(stringify!($group))) }; } macro_rules! sudoer { ($($e:expr),*) => { parse_lines(&mut [$($e),*, ""].join("\n").chars().peekable()) .into_iter() .map(|x| Ok::<_,basic_parser::Status>(x.unwrap())) } } // alternative to parse_eval, but goes through sudoer! directly #[must_use] fn parse_line(s: &str) -> Sudo { sudoer![s].next().unwrap().unwrap() } /// Returns `None` if a syntax error is encountered fn try_parse_line(s: &str) -> Option { parse_lines(&mut [s, ""].join("").chars().peekable()) .into_iter() .next()? .ok() } #[test] fn ambiguous_spec() { assert!(parse_eval::("marc, User_Alias ALL = ALL").is_spec()); } #[test] fn permission_test() { let root = || (&Named("root"), &Named("root")); let realpath = |path: &Path| crate::common::resolve::canonicalize(path).unwrap_or(path.to_path_buf()); macro_rules! FAIL { ([$($sudo:expr),*], $user:expr => $req:expr, $server:expr; $command:expr) => { let (Sudoers { rules,aliases,settings }, _) = analyze(Path::new("/etc/fakesudoers"), sudoer![$($sudo),*]); let cmdvec = $command.split_whitespace().map(String::from).collect::>(); let req = Request { user: $req.0, group: $req.1, command: &realpath(cmdvec[0].as_ref()), arguments: &cmdvec[1..].to_vec() }; assert_eq!(Sudoers { rules, aliases, settings }.check(&Named($user), &system::Hostname::fake($server), req).flags, None); } } macro_rules! pass { ([$($sudo:expr),*], $user:expr => $req:expr, $server:expr; $command:expr $(=> [$($key:ident : $val:expr),*])?) => { let (Sudoers { rules,aliases,settings }, _) = analyze(Path::new("/etc/fakesudoers"), sudoer![$($sudo),*]); let cmdvec = $command.split_whitespace().map(String::from).collect::>(); let req = Request { user: $req.0, group: $req.1, command: &realpath(cmdvec[0].as_ref()), arguments: &cmdvec[1..].to_vec() }; let result = Sudoers { rules, aliases, settings }.check(&Named($user), &system::Hostname::fake($server), req).flags; assert!(!result.is_none()); $( let result = result.unwrap(); $(assert_eq!(result.$key, $val);)* )? } } macro_rules! SYNTAX { ([$sudo:expr]) => { assert!(parse_string::($sudo).is_err()) }; } SYNTAX!(["ALL ALL = (;) ALL"]); FAIL!(["user ALL=(ALL:ALL) ALL"], "nobody" => root(), "server"; "/bin/hello"); pass!(["user ALL=(ALL:ALL) ALL"], "user" => root(), "server"; "/bin/hello"); pass!(["user ALL=(ALL:ALL) /bin/foo"], "user" => root(), "server"; "/bin/foo" => [authenticate: Authenticate::None]); FAIL!(["user ALL=(ALL:ALL) /bin/foo"], "user" => root(), "server"; "/bin/hello"); pass!(["user ALL=(ALL:ALL) PASSWD: /bin/foo"], "user" => root(), "server"; "/bin/foo" => [authenticate: Authenticate::Passwd]); pass!(["user ALL=(ALL:ALL) NOPASSWD: PASSWD: /bin/foo"], "user" => root(), "server"; "/bin/foo" => [authenticate: Authenticate::Passwd]); pass!(["user ALL=(ALL:ALL) PASSWD: NOPASSWD: /bin/foo"], "user" => root(), "server"; "/bin/foo" => [authenticate: Authenticate::Nopasswd]); pass!(["user ALL=(ALL:ALL) /bin/foo, NOPASSWD: /bin/bar"], "user" => root(), "server"; "/bin/foo" => [authenticate: Authenticate::None]); pass!(["user ALL=(ALL:ALL) /bin/foo, NOPASSWD: /bin/bar"], "user" => root(), "server"; "/bin/bar" => [authenticate: Authenticate::Nopasswd]); pass!(["user ALL=(ALL:ALL) NOPASSWD: /bin/foo, /bin/bar"], "user" => root(), "server"; "/bin/bar" => [authenticate: Authenticate::Nopasswd]); pass!(["user ALL=(ALL:ALL) CWD=/ /bin/foo, /bin/bar"], "user" => root(), "server"; "/bin/bar" => [cwd: Some(ChDir::Path("/".into()))]); pass!(["user ALL=(ALL:ALL) CWD=/ /bin/foo, CWD=* /bin/bar"], "user" => root(), "server"; "/bin/bar" => [cwd: Some(ChDir::Any)]); pass!(["user ALL=(ALL:ALL) CWD=/bin CWD=* /bin/foo"], "user" => root(), "server"; "/bin/foo" => [cwd: Some(ChDir::Any)]); pass!(["user ALL=(ALL:ALL) CWD=/usr/bin NOPASSWD: /bin/foo"], "user" => root(), "server"; "/bin/foo" => [authenticate: Authenticate::Nopasswd, cwd: Some(ChDir::Path("/usr/bin".into()))]); //note: original sudo does not allow the below pass!(["user ALL=(ALL:ALL) NOPASSWD: CWD=/usr/bin /bin/foo"], "user" => root(), "server"; "/bin/foo" => [authenticate: Authenticate::Nopasswd, cwd: Some(ChDir::Path("/usr/bin".into()))]); pass!(["user ALL=/bin/e##o"], "user" => root(), "vm"; "/bin/e"); SYNTAX!(["ALL ALL=(ALL) /bin/\n/echo"]); pass!(["user server=(ALL:ALL) ALL"], "user" => root(), "server"; "/bin/hello"); FAIL!(["user laptop=(ALL:ALL) ALL"], "user" => root(), "server"; "/bin/hello"); pass!(["user ALL=!/bin/hello", "user ALL=/bin/hello"], "user" => root(), "server"; "/bin/hello"); FAIL!(["user ALL=/bin/hello", "user ALL=!/bin/hello"], "user" => root(), "server"; "/bin/hello"); for alias in [ "User_Alias GROUP=user1, user2", "User_Alias GROUP=ALL,!user3", ] { pass!([alias,"GROUP ALL=/bin/hello"], "user1" => root(), "server"; "/bin/hello"); pass!([alias,"GROUP ALL=/bin/hello"], "user2" => root(), "server"; "/bin/hello"); FAIL!([alias,"GROUP ALL=/bin/hello"], "user3" => root(), "server"; "/bin/hello"); } pass!(["user ALL=/bin/hello arg"], "user" => root(), "server"; "/bin/hello arg"); pass!(["user ALL=/bin/hello arg"], "user" => root(), "server"; "/bin/hello arg"); pass!(["user ALL=/bin/hello arg"], "user" => root(), "server"; "/bin/hello arg"); FAIL!(["user ALL=/bin/hello arg"], "user" => root(), "server"; "/bin/hello boo"); // several test cases with globbing in the arguments are explicitly not supported by sudo-rs //pass!(["user ALL=/bin/hello a*g"], "user" => root(), "server"; "/bin/hello aaaarg"); //FAIL!(["user ALL=/bin/hello a*g"], "user" => root(), "server"; "/bin/hello boo"); pass!(["user ALL=/bin/hello"], "user" => root(), "server"; "/bin/hello boo"); FAIL!(["user ALL=/bin/hello \"\""], "user" => root(), "server"; "/bin/hello boo"); pass!(["user ALL=/bin/hello \"\""], "user" => root(), "server"; "/bin/hello"); pass!(["user ALL=/bin/hel*"], "user" => root(), "server"; "/bin/hello"); pass!(["user ALL=/bin/hel*"], "user" => root(), "server"; "/bin/help"); pass!(["user ALL=/bin/hel*"], "user" => root(), "server"; "/bin/help me"); //pass!(["user ALL=/bin/hel* *"], "user" => root(), "server"; "/bin/help"); FAIL!(["user ALL=/bin/hel* me"], "user" => root(), "server"; "/bin/help"); pass!(["user ALL=/bin/hel* me"], "user" => root(), "server"; "/bin/help me"); FAIL!(["user ALL=/bin/hel* me"], "user" => root(), "server"; "/bin/help me please"); pass!(["user ALL=(ALL:ALL) /bin/foo"], "user" => root(), "server"; "/bin/foo" => [authenticate: Authenticate::None]); pass!(["root ALL=(ALL:ALL) /bin/foo"], "root" => root(), "server"; "/bin/foo" => [authenticate: Authenticate::Nopasswd]); pass!(["user ALL=(ALL:ALL) /bin/foo"], "user" => request! { user, user }, "server"; "/bin/foo" => [authenticate: Authenticate::Nopasswd]); pass!(["user ALL=(ALL:ALL) /bin/foo"], "user" => request! { user, root }, "server"; "/bin/foo" => [authenticate: Authenticate::None]); assert_eq!(Named("user").as_gid(), 1466); pass!(["#1466 server=(ALL:ALL) ALL"], "user" => root(), "server"; "/bin/hello"); pass!(["%#1466 server=(ALL:ALL) ALL"], "user" => root(), "server"; "/bin/hello"); FAIL!(["#1466 server=(ALL:ALL) ALL"], "root" => root(), "server"; "/bin/hello"); FAIL!(["%#1466 server=(ALL:ALL) ALL"], "root" => root(), "server"; "/bin/hello"); pass!(["#1466,#1234,foo server=(ALL:ALL) ALL"], "user" => root(), "server"; "/bin/hello"); pass!(["#1234,foo,#1466 server=(ALL:ALL) ALL"], "user" => root(), "server"; "/bin/hello"); pass!(["foo,#1234,#1466 server=(ALL:ALL) ALL"], "user" => root(), "server"; "/bin/hello"); FAIL!(["foo,#1234,#1366 server=(ALL:ALL) ALL"], "user" => root(), "server"; "/bin/hello"); FAIL!(["#1366,#1234,foo server=(ALL:ALL) ALL"], "user" => root(), "server"; "/bin/hello"); pass!(["user ALL=(ALL:#1466) /bin/foo"], "user" => request! { root, root }, "server"; "/bin/foo"); FAIL!(["user ALL=(ALL:#1466) /bin/foo"], "user" => request! { root, other }, "server"; "/bin/foo"); pass!(["user ALL=(ALL:#1466) /bin/foo"], "user" => request! { root, user }, "server"; "/bin/foo"); pass!(["user ALL=(root,user:ALL) /bin/foo"], "user" => request! { root, wheel }, "server"; "/bin/foo"); pass!(["user ALL=(root,user:ALL) /bin/foo"], "user" => request! { user, wheel }, "server"; "/bin/foo"); FAIL!(["user ALL=(root,user:ALL) /bin/foo"], "user" => request! { sudo, wheel }, "server"; "/bin/foo"); FAIL!(["user ALL=(#0:wheel) /bin/foo"], "user" => request! { sudo, wheel }, "server"; "/bin/foo"); pass!(["user ALL=(#0:wheel) /bin/foo"], "user" => request! { root, root }, "server"; "/bin/foo"); FAIL!(["user ALL=(%#1466:wheel) /bin/foo"], "user" => request! { root, root }, "server"; "/bin/foo"); pass!(["user ALL=(%#1466:wheel) /bin/foo"], "user" => request! { user, user }, "server"; "/bin/foo"); // tests with a 'singular' runas spec FAIL!(["user ALL=(ALL) /bin/foo"], "user" => request! { sudo, wheel }, "server"; "/bin/foo"); pass!(["user ALL=(ALL) /bin/foo"], "user" => request! { sudo, sudo }, "server"; "/bin/foo"); // tests without a runas spec FAIL!(["user ALL=/bin/foo"], "user" => request! { sudo, sudo }, "server"; "/bin/foo"); FAIL!(["user ALL=/bin/foo"], "user" => request! { sudo, root }, "server"; "/bin/foo"); FAIL!(["user ALL=/bin/foo"], "user" => request! { root, sudo }, "server"; "/bin/foo"); pass!(["user ALL=/bin/foo"], "user" => request! { root, root }, "server"; "/bin/foo"); // slightly counterintuitive test which simulates only -g being passed pass!(["user ALL=(sudo:sudo) /bin/foo"], "user" => request! { user, sudo }, "server"; "/bin/foo"); // tests with multiple runas specs pass!(["user ALL=(root) /bin/ls, (sudo) /bin/true"], "user" => request! { root }, "server"; "/bin/ls"); pass!(["user ALL=(root) NOPASSWD: /bin/ls, (sudo) /bin/true"], "user" => request! { sudo }, "server"; "/bin/true" => [authenticate: Authenticate::Nopasswd]); FAIL!(["user ALL=(root) /bin/ls, (sudo) /bin/true"], "user" => request! { sudo }, "server"; "/bin/ls"); FAIL!(["user ALL=(root) /bin/ls, (sudo) /bin/true"], "user" => request! { root }, "server"; "/bin/true"); SYNTAX!(["User_Alias, marc ALL = ALL"]); pass!(["User_Alias FULLTIME=ALL,!marc","FULLTIME ALL=ALL"], "user" => root(), "server"; "/bin/bash"); FAIL!(["User_Alias FULLTIME=ALL,!marc","FULLTIME ALL=ALL"], "marc" => root(), "server"; "/bin/bash"); FAIL!(["User_Alias FULLTIME=ALL,!marc","ALL,!FULLTIME ALL=ALL"], "user" => root(), "server"; "/bin/bash"); pass!(["User_Alias FULLTIME=ALL,!!!marc","ALL,!FULLTIME ALL=ALL"], "marc" => root(), "server"; "/bin/bash"); pass!(["Host_Alias MACHINE=laptop,server","user MACHINE=ALL"], "user" => root(), "server"; "/bin/bash"); pass!(["Host_Alias MACHINE=laptop,server","user MACHINE=ALL"], "user" => root(), "laptop"; "/bin/bash"); FAIL!(["Host_Alias MACHINE=laptop,server","user MACHINE=ALL"], "user" => root(), "desktop"; "/bin/bash"); pass!(["Cmnd_Alias WHAT=/bin/dd, /bin/rm","user ALL=WHAT"], "user" => root(), "server"; "/bin/rm"); pass!(["Cmd_Alias WHAT=/bin/dd,/bin/rm","user ALL=WHAT"], "user" => root(), "laptop"; "/bin/dd"); FAIL!(["Cmnd_Alias WHAT=/bin/dd,/bin/rm","user ALL=WHAT"], "user" => root(), "desktop"; "/bin/bash"); pass!(["User_Alias A=B","User_Alias B=user","A ALL=ALL"], "user" => root(), "vm"; "/bin/ls"); pass!(["Host_Alias A=B","Host_Alias B=vm","ALL A=ALL"], "user" => root(), "vm"; "/bin/ls"); pass!(["Cmnd_Alias A=B","Cmnd_Alias B=/bin/ls","ALL ALL=A"], "user" => root(), "vm"; "/bin/ls"); FAIL!(["Runas_Alias TIME=%wheel,!!sudo","user ALL=() ALL"], "user" => request!{ sudo, sudo }, "vm"; "/bin/ls"); pass!(["Runas_Alias TIME=%wheel,!!sudo","user ALL=(TIME) ALL"], "user" => request! { sudo, sudo }, "vm"; "/bin/ls"); FAIL!(["Runas_Alias TIME=%wheel,!!sudo","user ALL=(:TIME) ALL"], "user" => request! { sudo, sudo }, "vm"; "/bin/ls"); pass!(["Runas_Alias TIME=%wheel,!!sudo","user ALL=(:TIME) ALL"], "user" => request! { user, sudo }, "vm"; "/bin/ls"); pass!(["Runas_Alias TIME=%wheel,!!sudo","user ALL=(TIME) ALL"], "user" => request! { wheel, wheel }, "vm"; "/bin/ls"); pass!(["Runas_Alias \\"," TIME=%wheel\\",",sudo # hallo","user ALL\\","=(TIME) ALL"], "user" => request! { wheel, wheel }, "vm"; "/bin/ls"); // test the less-intuitive "substition-like" alias mechanism FAIL!(["User_Alias FOO=!user", "ALL, FOO ALL=ALL"], "user" => root(), "vm"; "/bin/ls"); pass!(["User_Alias FOO=!user", "!FOO ALL=ALL"], "user" => root(), "vm"; "/bin/ls"); } #[test] fn default_bool_test() { let (Sudoers { settings, .. }, _) = analyze( Path::new("/etc/fakesudoers"), sudoer![ "Defaults env_reset", "Defaults !use_pty", "Defaults !env_keep", "Defaults !secure_path", "Defaults !env_editor" ], ); assert!(settings.flags.contains("env_reset")); assert!(!settings.flags.contains("use_pty")); assert!(settings.list["env_keep"].is_empty()); assert_eq!(settings.str_value["secure_path"], None); assert!(!settings.flags.contains("env_editor")); } #[test] fn default_set_test() { let (Sudoers { settings, .. }, _) = analyze( Path::new("/etc/fakesudoers"), sudoer![ "Defaults env_keep = \"FOO HUK BAR\"", "Defaults env_keep -= HUK", "Defaults !env_check", "Defaults env_check += \"FOO\"", "Defaults env_check += \"XYZZY\"", "Defaults passwd_tries = 5", "Defaults secure_path = /etc" ], ); assert_eq!( settings.list["env_keep"], ["FOO", "BAR"].into_iter().map(|x| x.to_string()).collect() ); assert_eq!( settings.list["env_check"], ["FOO", "XYZZY"] .into_iter() .map(|x| x.to_string()) .collect() ); assert_eq!(settings.str_value["secure_path"].as_deref(), Some("/etc")); assert_eq!(settings.int_value["passwd_tries"], 5); assert!(parse_string::("Defaults verifypw = \"sometimes\"").is_err()); assert!(parse_string::("Defaults verifypw = sometimes").is_err()); assert!(parse_string::("Defaults verifypw = never").is_ok()); } #[test] fn default_multi_test() { let (Sudoers { settings, .. }, _) = analyze( Path::new("/etc/fakesudoers"), sudoer![ "Defaults env_reset, !use_pty, secure_path=/etc, env_keep = \"FOO BAR\", env_keep -= BAR" ], ); assert!(settings.flags.contains("env_reset")); assert!(!settings.flags.contains("use_pty")); assert_eq!(settings.str_value["secure_path"].as_deref(), Some("/etc")); assert_eq!( settings.list["env_keep"], ["FOO".to_string()].into_iter().collect() ); } #[test] #[should_panic] fn invalid_directive() { parse_eval::("User_Alias, user Alias = user1, user2"); } #[test] fn directive_test() { let y = parse_eval::>; match parse_eval::("User_Alias HENK = user1, user2") { Sudo::Decl(Directive::UserAlias(defs)) => { let [Def(name, list)] = &defs[..] else { panic!("incorrectly parsed") }; assert_eq!(name, "HENK"); assert_eq!(*list, vec![y("user1"), y("user2")]); } _ => panic!("incorrectly parsed"), } match parse_eval::("Runas_Alias FOO = foo : BAR = bar") { Sudo::Decl(Directive::RunasAlias(defs)) => { let [Def(name1, list1), Def(name2, list2)] = &defs[..] else { panic!("incorrectly parsed") }; assert_eq!(name1, "FOO"); assert_eq!(*list1, vec![y("foo")]); assert_eq!(name2, "BAR"); assert_eq!(*list2, vec![y("bar")]); } _ => panic!("incorrectly parsed"), } } #[test] // the overloading of '#' causes a lot of issues fn hashsign_test() { assert!(parse_line("#42 ALL=ALL").is_spec()); assert!(parse_line("ALL ALL=(#42) ALL").is_spec()); assert!(parse_line("ALL ALL=(%#42) ALL").is_spec()); assert!(parse_line("ALL ALL=(:#42) ALL").is_spec()); assert!(parse_line("User_Alias FOO=#42, %#0, #3").is_decl()); assert!(parse_line("").is_line_comment()); assert!(parse_line("#this is a comment").is_line_comment()); assert!(parse_line("#include foo").is_include()); assert!(parse_line("#includedir foo").is_include_dir()); assert_eq!("foo bar", parse_line("#include \"foo bar\"").as_include()); // this is fine assert!(parse_line("#inlcudedir foo").is_line_comment()); assert!(parse_line("@include foo").is_include()); assert!(parse_line("@includedir foo").is_include_dir()); assert_eq!("foo bar", parse_line("@include \"foo bar\"").as_include()); } #[test] fn gh674_at_include_quoted_backslash() { assert!(parse_line(r#"@include "/etc/sudo\ers" "#).is_include()); assert!(parse_line(r#"@includedir "/etc/sudo\ers.d" "#).is_include_dir()); } #[test] fn gh676_percent_h_escape_unsupported() { let (_, errs) = analyze( Path::new("/etc/fakesudoers"), sudoer!(r#"@includedir "/etc/%h" "#), ); assert_eq!(errs.len(), 1); assert_eq!( errs[0].message, "cannot open sudoers file /etc/%h: percent escape %h in includedir is unsupported" ) } #[test] fn hashsign_error() { assert!(parse_line("#include foo bar").is_line_comment()); } #[test] fn include_regression() { assert!(try_parse_line("#4,#include foo").is_none()); } #[test] fn nullbyte_regression() { assert!(try_parse_line("ferris ALL=(ALL:ferris\0) ALL").is_none()); } #[test] fn alias_all_regression() { assert!(try_parse_line("User_Alias ALL = sudouser").is_none()) } #[test] fn defaults_regression() { assert!(try_parse_line("Defaults .mymachine=ALL").is_none()) } #[test] fn useralias_underscore_regression() { let sudo = parse_line("FOO_BAR ALL=ALL"); let spec = sudo.as_spec().expect("`Sudo::Spec`"); assert!(spec.users[0] .as_allow() .expect("`Qualified::Allow`") .is_alias()); } fn test_topo_sort(n: usize) { let alias = |s: &str| Qualified::Allow(Meta::::Alias(s.to_string())); let stop = || Qualified::Allow(Meta::::All); type Elem = Spec; let test_case = |x1: Elem, x2: Elem, x3: Elem| { let table = vec![ Def("AAP".to_string(), vec![x1]), Def("NOOT".to_string(), vec![x2]), Def("MIES".to_string(), vec![x3]), ]; let mut err = vec![]; let order = sanitize_alias_table(&table, &mut err); assert!(err.is_empty()); let mut seen = HashSet::new(); for Def(id, defns) in order.iter().map(|&i| &table[i]) { if defns.iter().any(|spec| { let Qualified::Allow(Meta::Alias(id2)) = spec else { return false; }; !seen.contains(id2) }) { panic!("forward reference encountered after sorting"); } seen.insert(id); } }; match n { 0 => test_case(alias("AAP"), alias("NOOT"), stop()), 1 => test_case(alias("AAP"), stop(), alias("NOOT")), 2 => test_case(alias("NOOT"), alias("AAP"), stop()), 3 => test_case(alias("NOOT"), stop(), alias("AAP")), 4 => test_case(stop(), alias("AAP"), alias("NOOT")), 5 => test_case(stop(), alias("NOOT"), alias("AAP")), _ => panic!("error in test case"), } } #[test] fn test_topo_positive() { test_topo_sort(3); test_topo_sort(4); } #[test] #[should_panic] fn test_topo_fail0() { test_topo_sort(0); } #[test] #[should_panic] fn test_topo_fail1() { test_topo_sort(1); } #[test] #[should_panic] fn test_topo_fail2() { test_topo_sort(2); } #[test] #[should_panic] fn test_topo_fail5() { test_topo_sort(5); } fn fuzz_topo_sort(siz: usize) { for mut n in 0..(1..siz).reduce(|x, y| x * y).unwrap() { let name = |s: u8| std::str::from_utf8(&[65 + s]).unwrap().to_string(); let alias = |s: String| Qualified::Allow(Meta::::Alias(s)); let stop = || Qualified::Allow(Meta::::All); let mut data = (0..siz - 1) .map(|i| alias(name(i as u8))) .collect::>(); data.push(stop()); for i in (1..=siz).rev() { data.swap(i - 1, n % i); n /= i; } let table = data .into_iter() .enumerate() .map(|(i, x)| Def(name(i as u8), vec![x])) .collect(); let mut err = vec![]; let order = sanitize_alias_table(&table, &mut err); if !err.is_empty() { return; } let mut seen = HashSet::new(); for Def(id, defns) in order.iter().map(|&i| &table[i]) { if defns.iter().any(|spec| { let Qualified::Allow(Meta::Alias(id2)) = spec else { return false; }; !seen.contains(id2) }) { panic!("forward reference encountered after sorting"); } seen.insert(id); } assert!(seen.len() == siz); } } #[test] fn fuzz_topo_sort7() { fuzz_topo_sort(7) } sudo-rs-0.2.2/src/sudoers/tokens.rs000064400000000000000000000214711046102023000153520ustar 00000000000000//! Various tokens use crate::common::{SudoPath, SudoString}; use super::basic_parser::{Many, Token}; use crate::common::{HARDENED_ENUM_VALUE_0, HARDENED_ENUM_VALUE_1, HARDENED_ENUM_VALUE_2}; #[cfg_attr(test, derive(Clone, PartialEq, Eq))] pub struct Username(pub SudoString); /// A username consists of alphanumeric characters as well as "." and "-", but does not start with an underscore. impl Token for Username { fn construct(text: String) -> Result { SudoString::new(text) .map_err(|e| e.to_string()) .map(Username) } fn accept(c: char) -> bool { c.is_ascii_alphanumeric() || ".-_".contains(c) } fn accept_1st(c: char) -> bool { c != '_' && Self::accept(c) } } impl Many for Username {} pub struct Digits(pub u32); impl Token for Digits { const MAX_LEN: usize = 9; fn construct(s: String) -> Result { Ok(Digits(s.parse().unwrap())) } fn accept(c: char) -> bool { c.is_ascii_digit() } } pub struct Numeric(pub String); impl Token for Numeric { const MAX_LEN: usize = 18; fn construct(s: String) -> Result { Ok(Numeric(s)) } fn accept(c: char) -> bool { c.is_ascii_hexdigit() || c == '.' } } /// A hostname consists of alphanumeric characters and ".", "-", "_" pub struct Hostname(pub String); impl std::ops::Deref for Hostname { type Target = String; fn deref(&self) -> &Self::Target { &self.0 } } impl Token for Hostname { fn construct(text: String) -> Result { Ok(Hostname(text)) } fn accept(c: char) -> bool { c.is_ascii_alphanumeric() || ".-_".contains(c) } } impl Many for Hostname {} /// This enum allows items to use the ALL wildcard or be specified with aliases, or directly. /// (Maybe this is better defined not as a Token but simply directly as an implementation of [crate::sudoers::basic_parser::Parse]) #[cfg_attr(test, derive(Debug, PartialEq, Eq))] #[repr(u32)] pub enum Meta { All = HARDENED_ENUM_VALUE_0, Only(T) = HARDENED_ENUM_VALUE_1, Alias(String) = HARDENED_ENUM_VALUE_2, } impl Meta { #[cfg(test)] pub fn is_alias(&self) -> bool { matches!(self, Self::Alias(..)) } } impl Token for Meta { fn construct(raw: String) -> Result { // `T` may accept whitespace resulting in `raw` having trailing whitespace which would make // the first two checks below fail. this `cooked` version has no trailing whitespace let cooked = raw.trim_end().to_string(); Ok(if cooked == "ALL" { Meta::All } else if cooked.starts_with(AliasName::accept_1st) && cooked.chars().skip(1).all(AliasName::accept) { Meta::Alias(cooked) } else { Meta::Only(T::construct(raw)?) }) } const MAX_LEN: usize = T::MAX_LEN; fn accept(c: char) -> bool { T::accept(c) || c.is_uppercase() } fn accept_1st(c: char) -> bool { T::accept_1st(c) || c.is_uppercase() } const ALLOW_ESCAPE: bool = T::ALLOW_ESCAPE; fn escaped(c: char) -> bool { T::escaped(c) } } impl Many for Meta { const SEP: char = T::SEP; const LIMIT: usize = T::LIMIT; } /// An identifier that consits of only uppercase characters. pub struct AliasName(pub String); impl Token for AliasName { fn construct(s: String) -> Result { Ok(AliasName(s)) } fn accept_1st(c: char) -> bool { c.is_ascii_uppercase() || c.is_ascii_digit() } fn accept(c: char) -> bool { Self::accept_1st(c) || c == '_' } } /// A struct that represents valid command strings; this can contain escape sequences and are /// limited to 1024 characters. pub type Command = (glob::Pattern, Option>); impl Token for Command { const MAX_LEN: usize = 1024; fn construct(s: String) -> Result { let cvt_err = |pat: Result<_, glob::PatternError>| { pat.map_err(|err| format!("wildcard pattern error {err}")) }; // the tokenizer should not give us a token that consists of only whitespace let mut cmd_iter = s.split_whitespace(); let mut cmd = cmd_iter.next().unwrap().to_string(); let mut args = cmd_iter.map(String::from).collect::>(); let argpat = if args.is_empty() { // if no arguments are mentioned, anything is allowed None } else { if args.last().map(|x| -> &str { x }) == Some("\"\"") { // if the magic "" appears, no (further) arguments are allowed args.pop(); } Some(args.into_boxed_slice()) }; // record if the cmd ends in a slash and remove it if it does let is_dir = cmd.ends_with('/') && { cmd.pop(); true }; // canonicalize path (if possible) if let Ok(real_cmd) = crate::common::resolve::canonicalize(&cmd) { cmd = real_cmd .to_str() .ok_or("non-UTF8 characters in filesystem")? .to_string(); } // if the cmd ends with a slash, any command in that directory is allowed if is_dir { cmd.push_str("/*"); } Ok((cvt_err(glob::Pattern::new(&cmd))?, argpat)) } // all commands start with "/" except "sudoedit" fn accept_1st(c: char) -> bool { c == '/' || c == 's' } fn accept(c: char) -> bool { !Self::escaped(c) && !c.is_control() } const ALLOW_ESCAPE: bool = true; fn escaped(c: char) -> bool { matches!(c, '\\' | ',' | ':' | '=' | '#') } } impl Many for Command {} pub struct DefaultName(pub String); impl Token for DefaultName { fn construct(text: String) -> Result { Ok(DefaultName(text)) } fn accept(c: char) -> bool { c.is_ascii_alphanumeric() || c == '_' } } pub struct EnvVar(pub String); impl Token for EnvVar { fn construct(text: String) -> Result { Ok(EnvVar(text)) } fn accept(c: char) -> bool { !c.is_control() && !c.is_whitespace() && !Self::escaped(c) } const ALLOW_ESCAPE: bool = true; fn escaped(c: char) -> bool { matches!(c, '\\' | '=' | '#' | '"') } } pub struct QuotedText(pub String); impl Token for QuotedText { const MAX_LEN: usize = 1024; fn construct(s: String) -> Result { Ok(QuotedText(s)) } fn accept(c: char) -> bool { !Self::escaped(c) } const ALLOW_ESCAPE: bool = true; fn escaped(c: char) -> bool { matches!(c, '\\' | '"') || c.is_control() } } // `@include "some/path"` // ^^^^^^^^^^^ pub struct QuotedInclude(pub String); impl Token for QuotedInclude { const MAX_LEN: usize = 1024; fn construct(s: String) -> Result { Ok(QuotedInclude(s)) } fn accept(c: char) -> bool { !Self::escaped(c) } const ALLOW_ESCAPE: bool = true; fn escaped(c: char) -> bool { matches!(c, '"') || c.is_control() } } pub struct IncludePath(pub String); impl Token for IncludePath { const MAX_LEN: usize = 1024; fn construct(s: String) -> Result { Ok(IncludePath(s)) } fn accept(c: char) -> bool { !c.is_control() && !Self::escaped(c) } const ALLOW_ESCAPE: bool = true; fn escaped(c: char) -> bool { matches!(c, '\\' | '"' | ' ') } } // used for Defaults where quotes around some items are optional pub struct StringParameter(pub String); impl Token for StringParameter { const MAX_LEN: usize = QuotedText::MAX_LEN; fn construct(s: String) -> Result { Ok(StringParameter(s)) } fn accept(c: char) -> bool { !c.is_control() && !Self::escaped(c) } const ALLOW_ESCAPE: bool = true; fn escaped(c: char) -> bool { matches!(c, '\\' | '"' | ' ' | '#' | ',') } } // a path used for in CWD and CHROOT specs #[derive(Clone, PartialEq)] #[cfg_attr(test, derive(Debug, Eq))] pub enum ChDir { Path(SudoPath), Any, } impl Token for ChDir { const MAX_LEN: usize = 1024; fn construct(s: String) -> Result { if s == "*" { Ok(ChDir::Any) } else if s.contains('*') { Err("path cannot contain '*'".to_string()) } else { Ok(ChDir::Path( SudoPath::try_from(s).map_err(|e| e.to_string())?, )) } } fn accept(c: char) -> bool { !c.is_control() && !Self::escaped(c) } fn accept_1st(c: char) -> bool { "~/*".contains(c) } const ALLOW_ESCAPE: bool = true; fn escaped(c: char) -> bool { matches!(c, '\\' | '"' | ' ') } } sudo-rs-0.2.2/src/system/audit.rs000064400000000000000000000104101046102023000150040ustar 00000000000000use std::fs::{DirBuilder, File, Metadata, OpenOptions}; use std::io::{self, Error, ErrorKind}; use std::os::unix::fs::{DirBuilderExt, MetadataExt, PermissionsExt}; use std::os::unix::prelude::OpenOptionsExt; use std::path::Path; // of course we can also write "file & 0o040 != 0", but this makes the intent explicit enum Op { Read = 4, Write = 2, Exec = 1, } enum Category { Owner = 2, Group = 1, World = 0, } fn mode(who: Category, what: Op) -> u32 { (what as u32) << (3 * who as u32) } pub fn secure_open(path: impl AsRef, check_parent_dir: bool) -> io::Result { let mut open_options = OpenOptions::new(); open_options.read(true); secure_open_impl(path.as_ref(), &mut open_options, check_parent_dir, false) } pub fn secure_open_cookie_file(path: impl AsRef) -> io::Result { let mut open_options = OpenOptions::new(); open_options .read(true) .write(true) .create(true) .mode(mode(Category::Owner, Op::Write) | mode(Category::Owner, Op::Read)); secure_open_impl(path.as_ref(), &mut open_options, true, true) } fn checks(path: &Path, meta: Metadata) -> io::Result<()> { let error = |msg| Error::new(ErrorKind::PermissionDenied, msg); let path_mode = meta.permissions().mode(); if meta.uid() != 0 { Err(error(format!("{} must be owned by root", path.display()))) } else if meta.gid() != 0 && (path_mode & mode(Category::Group, Op::Write) != 0) { Err(error(format!( "{} cannot be group-writable", path.display() ))) } else if path_mode & mode(Category::World, Op::Write) != 0 { Err(error(format!( "{} cannot be world-writable", path.display() ))) } else { Ok(()) } } // Open `path` with options `open_options`, provided that it is "secure". // "Secure" means that it passes the `checks` function above. // If `check_parent_dir` is set, also check that the parent directory is "secure" also. // If `create_parent_dirs` is set, create the path to the file if it does not already exist. fn secure_open_impl( path: &Path, open_options: &mut OpenOptions, check_parent_dir: bool, create_parent_dirs: bool, ) -> io::Result { let error = |msg| Error::new(ErrorKind::PermissionDenied, msg); if check_parent_dir || create_parent_dirs { if let Some(parent_dir) = path.parent() { // if we should create parent dirs and it does not yet exist, create it if create_parent_dirs && !parent_dir.exists() { DirBuilder::new() .recursive(true) .mode( mode(Category::Owner, Op::Write) | mode(Category::Owner, Op::Read) | mode(Category::Owner, Op::Exec) | mode(Category::Group, Op::Exec) | mode(Category::World, Op::Exec), ) .create(parent_dir)?; } if check_parent_dir { let parent_meta = std::fs::metadata(parent_dir)?; checks(parent_dir, parent_meta)?; } } else { return Err(error(format!( "{} has no valid parent directory", path.display() ))); } } let file = open_options.open(path)?; let meta = file.metadata()?; checks(path, meta)?; Ok(file) } #[cfg(test)] mod test { use super::*; #[test] fn secure_open_is_predictable() { // /etc/hosts should be readable and "secure" (if this test fails, you have been compromised) assert!(std::fs::File::open("/etc/hosts").is_ok()); assert!(secure_open("/etc/hosts", false).is_ok()); // /var/log/utmp should be readable, but not secure (writeable by group other than root) assert!(std::fs::File::open("/var/log/wtmp").is_ok()); assert!(secure_open("/var/log/wtmp", false).is_err()); // /etc/shadow should not be readable assert!(std::fs::File::open("/etc/shadow").is_err()); assert!(secure_open("/etc/shadow", false).is_err()); } #[test] fn test_secure_open_cookie_file() { assert!(secure_open_cookie_file("/etc/hosts").is_err()); } } sudo-rs-0.2.2/src/system/file/chown.rs000064400000000000000000000006431046102023000157420ustar 00000000000000use std::{fs::File, io, os::fd::AsRawFd}; use crate::{ cutils::cerr, system::interface::{GroupId, UserId}, }; pub(crate) trait Chown { fn chown(&self, uid: UserId, gid: GroupId) -> io::Result<()>; } impl Chown for File { fn chown(&self, owner: UserId, group: GroupId) -> io::Result<()> { let fd = self.as_raw_fd(); cerr(unsafe { libc::fchown(fd, owner, group) }).map(|_| ()) } } sudo-rs-0.2.2/src/system/file/lock.rs000064400000000000000000000027531046102023000155600ustar 00000000000000use std::{ fs::File, io::Result, os::fd::{AsRawFd, RawFd}, }; use crate::cutils::cerr; pub(crate) struct FileLock { fd: RawFd, } impl FileLock { /// Get an exclusive lock on the file, waits if there is currently a lock /// on the file if `nonblocking` is true. pub(crate) fn exclusive(file: &File, nonblocking: bool) -> Result { let fd = file.as_raw_fd(); flock(fd, LockOp::LockExclusive, nonblocking)?; Ok(Self { fd }) } /// Release the lock on the file. pub(crate) fn unlock(self) -> Result<()> { flock(self.fd, LockOp::Unlock, false) } } impl Drop for FileLock { fn drop(&mut self) { flock(self.fd, LockOp::Unlock, false).ok(); } } #[derive(Clone, Copy, Debug)] enum LockOp { LockExclusive, Unlock, } impl LockOp { fn as_flock_operation(self) -> libc::c_int { match self { LockOp::LockExclusive => libc::LOCK_EX, LockOp::Unlock => libc::LOCK_UN, } } } fn flock(fd: RawFd, action: LockOp, nonblocking: bool) -> Result<()> { let mut operation = action.as_flock_operation(); if nonblocking { operation |= libc::LOCK_NB; } cerr(unsafe { libc::flock(fd, operation) })?; Ok(()) } #[cfg(test)] mod tests { use crate::system::tests::tempfile; use super::*; #[test] fn test_locking_of_tmp_file() { let f = tempfile().unwrap(); FileLock::exclusive(&f, false).unwrap().unlock().unwrap(); } } sudo-rs-0.2.2/src/system/file/mod.rs000064400000000000000000000001221046102023000153730ustar 00000000000000mod chown; mod lock; pub(crate) use chown::Chown; pub(crate) use lock::FileLock; sudo-rs-0.2.2/src/system/interface.rs000064400000000000000000000055411046102023000156470ustar 00000000000000use std::ffi::CStr; pub type GroupId = libc::gid_t; pub type UserId = libc::uid_t; pub type ProcessId = libc::pid_t; pub type DeviceId = libc::dev_t; /// This trait/module is here to not make this crate independent (at the present time) in the idiosyncracies of user representation details /// (which we may decide over time), as well as to make explicit what functionality a user-representation must have; this /// interface is not set in stone and "easy" to change. pub trait UnixUser { fn has_name(&self, _name: &str) -> bool { false } fn has_uid(&self, _uid: libc::uid_t) -> bool { false } fn is_root(&self) -> bool { false } fn in_group_by_name(&self, _name: &CStr) -> bool { false } fn in_group_by_gid(&self, _gid: GroupId) -> bool { false } } pub trait UnixGroup { fn as_gid(&self) -> GroupId; fn try_as_name(&self) -> Option<&str>; } impl UnixUser for super::User { fn has_name(&self, name: &str) -> bool { self.name == name } fn has_uid(&self, uid: GroupId) -> bool { self.uid == uid } fn is_root(&self) -> bool { self.has_uid(0) } fn in_group_by_name(&self, name_c: &CStr) -> bool { if let Ok(Some(group)) = super::Group::from_name(name_c) { self.in_group_by_gid(group.gid) } else { false } } fn in_group_by_gid(&self, gid: GroupId) -> bool { self.groups.contains(&gid) } } impl UnixGroup for super::Group { fn as_gid(&self) -> GroupId { self.gid } fn try_as_name(&self) -> Option<&str> { Some(&self.name) } } #[cfg(test)] mod test { use crate::system::{Group, User}; use super::*; fn test_user(user: impl UnixUser, name_c: &CStr, uid: libc::uid_t) { let name = name_c.to_str().unwrap(); assert!(user.has_name(name)); assert!(user.has_uid(uid)); assert!(user.in_group_by_name(name_c)); assert_eq!(user.is_root(), name == "root"); } fn test_group(group: impl UnixGroup, name: &str, gid: libc::gid_t) { assert_eq!(group.as_gid(), gid); assert_eq!(group.try_as_name(), Some(name)); } #[test] fn test_unix_user() { let user = |name| User::from_name(name).unwrap().unwrap(); test_user(user(cstr!("root")), cstr!("root"), 0); test_user(user(cstr!("daemon")), cstr!("daemon"), 1); } #[test] fn test_unix_group() { let group = |name| Group::from_name(name).unwrap().unwrap(); test_group(group(cstr!("root")), "root", 0); test_group(group(cstr!("daemon")), "daemon", 1); } #[test] fn test_default() { impl UnixUser for () {} assert!(!().has_name("root")); assert!(!().has_uid(0)); assert!(!().is_root()); assert!(!().in_group_by_name(cstr!("root"))); } } sudo-rs-0.2.2/src/system/mod.rs000064400000000000000000000666211046102023000144740ustar 00000000000000use core::fmt; // TODO: remove unused attribute when system is cleaned up use std::{ collections::BTreeSet, ffi::{c_uint, CStr, CString}, io, mem::MaybeUninit, ops, os::{ fd::AsRawFd, unix::{self, prelude::OsStrExt}, }, path::{Path, PathBuf}, str::FromStr, }; use crate::{ common::{Error, SudoPath, SudoString}, cutils::*, }; pub use audit::secure_open; use interface::{DeviceId, GroupId, ProcessId, UserId}; pub use libc::PATH_MAX; use libc::STDERR_FILENO; use time::SystemTime; use self::signal::SignalNumber; mod audit; // generalized traits for when we want to hide implementations pub mod interface; pub mod file; pub mod time; pub mod timestamp; pub mod signal; pub mod term; pub mod wait; pub(crate) fn can_execute>(path: P) -> bool { let Ok(path) = CString::new(path.as_ref().as_os_str().as_bytes()) else { return false; }; unsafe { libc::access(path.as_ptr(), libc::X_OK) == 0 } } pub(crate) fn _exit(status: libc::c_int) -> ! { unsafe { libc::_exit(status) } } /// A type able to close every file descriptor except for the ones pased via [`FileCloser::except`] /// and the IO streams. pub(crate) struct FileCloser { fds: BTreeSet, } impl FileCloser { pub(crate) const fn new() -> Self { Self { fds: BTreeSet::new(), } } pub(crate) fn except(&mut self, fd: &F) { self.fds.insert(fd.as_raw_fd() as c_uint); } /// Close every file descriptor that is not one of the IO streams or one of the file /// descriptors passed via [`FileCloser::except`]. pub(crate) fn close_the_universe(self) -> io::Result<()> { let mut fds = self.fds.into_iter(); let Some(mut curr_fd) = fds.next() else { return close_range(STDERR_FILENO as c_uint + 1, c_uint::MAX); }; if let Some(max_fd) = curr_fd.checked_sub(1) { close_range(STDERR_FILENO as c_uint + 1, max_fd)?; } for next_fd in fds { if let Some(min_fd) = curr_fd.checked_add(1) { if let Some(max_fd) = next_fd.checked_sub(1) { close_range(min_fd, max_fd)?; } } curr_fd = next_fd; } if let Some(min_fd) = curr_fd.checked_add(1) { close_range(min_fd, c_uint::MAX)?; } Ok(()) } } fn close_range(min_fd: c_uint, max_fd: c_uint) -> io::Result<()> { if min_fd <= max_fd { cerr(unsafe { libc::syscall(libc::SYS_close_range, min_fd, max_fd, 0 as c_uint) })?; } Ok(()) } pub(crate) enum ForkResult { // Parent process branch with the child process' PID. Parent(ProcessId), // Child process branch. Child, } unsafe fn inner_fork() -> io::Result { let pid = cerr(unsafe { libc::fork() })?; if pid == 0 { Ok(ForkResult::Child) } else { Ok(ForkResult::Parent(pid)) } } #[cfg(target_os = "linux")] /// Create a new process. pub(crate) fn fork() -> io::Result { // SAFETY: `fork` is implemented using `clone` in linux so we don't need to worry about signal // safety. unsafe { inner_fork() } } #[cfg(not(target_os = "linux"))] /// Create a new process. /// /// # Safety /// /// In a multithreaded program, only async-signal-safe functions are guaranteed to work in the /// child process until a call to `execve` or a similar function is done. pub(crate) unsafe fn fork() -> io::Result { inner_fork() } pub fn setsid() -> io::Result { cerr(unsafe { libc::setsid() }) } #[derive(Clone)] #[cfg_attr(test, derive(PartialEq))] pub struct Hostname { inner: String, } impl fmt::Debug for Hostname { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Hostname").field(&self.inner).finish() } } impl fmt::Display for Hostname { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.inner) } } impl ops::Deref for Hostname { type Target = str; fn deref(&self) -> &str { &self.inner } } impl Hostname { #[cfg(test)] pub fn fake(hostname: &str) -> Self { Self { inner: hostname.to_string(), } } pub fn resolve() -> Self { // see `man 2 gethostname` const MAX_HOST_NAME_SIZE_ACCORDING_TO_SUSV2: libc::c_long = 255; // POSIX.1 systems limit hostnames to `HOST_NAME_MAX` bytes // not including null-byte in the count let max_hostname_size = sysconf(libc::_SC_HOST_NAME_MAX) .unwrap_or(MAX_HOST_NAME_SIZE_ACCORDING_TO_SUSV2) as usize; let buffer_size = max_hostname_size + 1 /* null byte delimiter */ ; let mut buf = vec![0; buffer_size]; match cerr(unsafe { libc::gethostname(buf.as_mut_ptr(), buffer_size) }) { Ok(_) => Self { inner: unsafe { string_from_ptr(buf.as_ptr()) }, }, // ENAMETOOLONG is returned when hostname is greater than `buffer_size` Err(_) => { // but we have chosen a `buffer_size` larger than `max_hostname_size` so no truncation error is possible panic!("Unexpected error while retrieving hostname, this should not happen"); } } } } pub fn syslog(priority: libc::c_int, facility: libc::c_int, message: &CStr) { const MSG: *const libc::c_char = match CStr::from_bytes_until_nul(b"%s\0") { Ok(cstr) => cstr.as_ptr(), Err(_) => panic!("syslog formatting string is not null-terminated"), }; unsafe { libc::syslog(priority | facility, MSG, message.as_ptr()); } } /// set target user and groups (uid, gid, additional groups) for a command pub fn set_target_user( cmd: &mut std::process::Command, mut target_user: User, target_group: Group, ) { use std::os::unix::process::CommandExt; // add target group to list of additional groups if not present if !target_user.groups.contains(&target_group.gid) { target_user.groups.push(target_group.gid); } // we need to do this in a `pre_exec` call since the `groups` method in `process::Command` is unstable // see https://github.com/rust-lang/rust/blob/a01b4cc9f375f1b95fa8195daeea938d3d9c4c34/library/std/src/sys/unix/process/process_unix.rs#L329-L352 // for the std implementation of the libc calls to `setgroups`, `setgid` and `setuid` unsafe { cmd.pre_exec(move || { cerr(libc::setgroups( target_user.groups.len(), target_user.groups.as_ptr(), ))?; cerr(libc::setgid(target_group.gid))?; cerr(libc::setuid(target_user.uid))?; Ok(()) }); } } /// Send a signal to a process with the specified ID. pub fn kill(pid: ProcessId, signal: SignalNumber) -> io::Result<()> { // SAFETY: This function cannot cause UB even if `pid` is not a valid process ID or if // `signal` is not a valid signal code. cerr(unsafe { libc::kill(pid, signal) }).map(|_| ()) } /// Send a signal to a process group with the specified ID. pub fn killpg(pgid: ProcessId, signal: SignalNumber) -> io::Result<()> { // SAFETY: This function cannot cause UB even if `pgid` is not a valid process ID or if // `signal` is not a valid signal code. cerr(unsafe { libc::killpg(pgid, signal) }).map(|_| ()) } /// Get the process group ID of the current process. pub fn getpgrp() -> ProcessId { unsafe { libc::getpgrp() } } /// Get a process group ID. pub fn getpgid(pid: ProcessId) -> io::Result { // SAFETY: This function cannot cause UB even if `pid` is not a valid process ID cerr(unsafe { libc::getpgid(pid) }) } /// Set a process group ID. pub fn setpgid(pid: ProcessId, pgid: ProcessId) -> io::Result<()> { cerr(unsafe { libc::setpgid(pid, pgid) }).map(|_| ()) } pub fn chown>( path: &S, uid: impl Into, gid: impl Into, ) -> io::Result<()> { let path = path.as_ref().as_ptr(); let uid = uid.into(); let gid = gid.into(); cerr(unsafe { libc::chown(path, uid, gid) }).map(|_| ()) } #[derive(Debug, Clone, PartialEq)] pub struct User { pub uid: UserId, pub gid: GroupId, pub name: SudoString, pub gecos: String, pub home: SudoPath, pub shell: PathBuf, pub passwd: String, pub groups: Vec, } impl User { /// # Safety /// This function expects `pwd` to be a result from a succesful call to `getpwXXX_r`. /// (It can cause UB if any of `pwd`'s pointed-to strings does not have a null-terminator.) unsafe fn from_libc(pwd: &libc::passwd) -> Result { let mut buf_len: libc::c_int = 32; let mut groups_buffer: Vec; while { groups_buffer = vec![0; buf_len as usize]; let result = unsafe { libc::getgrouplist( pwd.pw_name, pwd.pw_gid, groups_buffer.as_mut_ptr(), &mut buf_len, ) }; result == -1 } { if buf_len >= 65536 { panic!("user has too many groups (> 65536), this should not happen"); } buf_len *= 2; } groups_buffer.resize_with(buf_len as usize, || { panic!("invalid groups count returned from getgrouplist, this should not happen") }); Ok(User { uid: pwd.pw_uid, gid: pwd.pw_gid, name: SudoString::new(string_from_ptr(pwd.pw_name))?, gecos: string_from_ptr(pwd.pw_gecos), home: SudoPath::new(os_string_from_ptr(pwd.pw_dir).into())?, shell: os_string_from_ptr(pwd.pw_shell).into(), passwd: string_from_ptr(pwd.pw_passwd), groups: groups_buffer, }) } pub fn from_uid(uid: UserId) -> Result, Error> { let max_pw_size = sysconf(libc::_SC_GETPW_R_SIZE_MAX).unwrap_or(16_384); let mut buf = vec![0; max_pw_size as usize]; let mut pwd = MaybeUninit::uninit(); let mut pwd_ptr = std::ptr::null_mut(); cerr(unsafe { libc::getpwuid_r( uid, pwd.as_mut_ptr(), buf.as_mut_ptr(), buf.len(), &mut pwd_ptr, ) })?; if pwd_ptr.is_null() { Ok(None) } else { let pwd = unsafe { pwd.assume_init() }; unsafe { Self::from_libc(&pwd).map(Some) } } } pub fn effective_uid() -> UserId { unsafe { libc::geteuid() } } pub fn effective_gid() -> GroupId { unsafe { libc::getegid() } } pub fn real_uid() -> UserId { unsafe { libc::getuid() } } pub fn real_gid() -> GroupId { unsafe { libc::getgid() } } pub fn real() -> Result, Error> { Self::from_uid(Self::real_uid()) } pub fn from_name(name_c: &CStr) -> Result, Error> { let max_pw_size = sysconf(libc::_SC_GETPW_R_SIZE_MAX).unwrap_or(16_384); let mut buf = vec![0; max_pw_size as usize]; let mut pwd = MaybeUninit::uninit(); let mut pwd_ptr = std::ptr::null_mut(); cerr(unsafe { libc::getpwnam_r( name_c.as_ptr(), pwd.as_mut_ptr(), buf.as_mut_ptr(), buf.len(), &mut pwd_ptr, ) })?; if pwd_ptr.is_null() { Ok(None) } else { let pwd = unsafe { pwd.assume_init() }; unsafe { Self::from_libc(&pwd).map(Some) } } } } #[derive(Debug, Clone)] #[cfg_attr(test, derive(PartialEq))] pub struct Group { pub gid: GroupId, pub name: String, pub passwd: String, pub members: Vec, } impl Group { /// # Safety /// This function expects `grp` to be a result from a succesful call to `getgrXXX_r`. /// In particular the grp.gr_mem pointer is assumed to be non-null, and pointing to a /// null-terminated list; the pointed-to strings are expected to be null-terminated. unsafe fn from_libc(grp: &libc::group) -> Group { // find out how many members we have let mut mem_count = 0; while !(*grp.gr_mem.offset(mem_count)).is_null() { mem_count += 1; } // convert the members to a slice and then put them into a vec of strings let mut members = Vec::with_capacity(mem_count as usize); let mem_slice = std::slice::from_raw_parts(grp.gr_mem, mem_count as usize); for mem in mem_slice { members.push(string_from_ptr(*mem)); } Group { gid: grp.gr_gid, name: string_from_ptr(grp.gr_name), passwd: string_from_ptr(grp.gr_passwd), members, } } pub fn from_gid(gid: GroupId) -> std::io::Result> { let max_gr_size = sysconf(libc::_SC_GETGR_R_SIZE_MAX).unwrap_or(16_384); let mut buf = vec![0; max_gr_size as usize]; let mut grp = MaybeUninit::uninit(); let mut grp_ptr = std::ptr::null_mut(); cerr(unsafe { libc::getgrgid_r( gid, grp.as_mut_ptr(), buf.as_mut_ptr(), buf.len(), &mut grp_ptr, ) })?; if grp_ptr.is_null() { Ok(None) } else { let grp = unsafe { grp.assume_init() }; Ok(Some(unsafe { Group::from_libc(&grp) })) } } pub fn from_name(name_c: &CStr) -> std::io::Result> { let max_gr_size = sysconf(libc::_SC_GETGR_R_SIZE_MAX).unwrap_or(16_384); let mut buf = vec![0; max_gr_size as usize]; let mut grp = MaybeUninit::uninit(); let mut grp_ptr = std::ptr::null_mut(); cerr(unsafe { libc::getgrnam_r( name_c.as_ptr(), grp.as_mut_ptr(), buf.as_mut_ptr(), buf.len(), &mut grp_ptr, ) })?; if grp_ptr.is_null() { Ok(None) } else { let grp = unsafe { grp.assume_init() }; Ok(Some(unsafe { Group::from_libc(&grp) })) } } } pub enum WithProcess { Current, Other(ProcessId), } impl WithProcess { fn to_proc_string(&self) -> String { match self { WithProcess::Current => "self".into(), WithProcess::Other(pid) => pid.to_string(), } } } #[derive(Debug, Clone)] pub struct Process { pub pid: ProcessId, pub parent_pid: Option, pub group_id: ProcessId, pub session_id: ProcessId, pub name: PathBuf, } impl Default for Process { fn default() -> Self { Self::new() } } impl Process { pub fn new() -> Process { Process { pid: Self::process_id(), parent_pid: Self::parent_id(), group_id: Self::group_id(), session_id: Self::session_id(), name: Self::process_name().unwrap_or_else(|| PathBuf::from("sudo")), } } pub fn process_name() -> Option { std::env::args().next().map(PathBuf::from) } /// Return the process identifier for the current process pub fn process_id() -> ProcessId { // NOTE libstd casts the `i32` that `libc::getpid` returns into `u32` // here we cast it back into `i32` (`ProcessId`) std::process::id() as ProcessId } /// Return the parent process identifier for the current process pub fn parent_id() -> Option { // NOTE libstd casts the `i32` that `libc::getppid` returns into `u32` // here we cast it back into `i32` (`ProcessId`) let pid = unix::process::parent_id() as ProcessId; if pid == 0 { None } else { Some(pid) } } /// Return the process group id for the current process pub fn group_id() -> ProcessId { unsafe { libc::getpgid(0) } } /// Get the session id for the current process pub fn session_id() -> ProcessId { unsafe { libc::getsid(0) } } /// Returns the device identifier of the TTY device that is currently /// attached to the given process pub fn tty_device_id(pid: WithProcess) -> std::io::Result> { // device id of tty is displayed as a signed integer of 32 bits let data: i32 = read_proc_stat(pid, 6)?; if data == 0 { Ok(None) } else { // While the integer was displayed as signed in the proc stat file, // we actually need to interpret the bits of that integer as an unsigned // int. We convert via u32 because a direct conversion to DeviceId // would use sign extension, which would result in a different bit // representation Ok(Some(data as u32 as DeviceId)) } } /// Get the process starting time of a specific process pub fn starting_time(pid: WithProcess) -> io::Result { let process_start: u64 = read_proc_stat(pid, 21)?; // the startime field is stored in ticks since the system start, so we need to know how many // ticks go into a second let ticks_per_second = crate::cutils::sysconf(libc::_SC_CLK_TCK).ok_or_else(|| { io::Error::new( io::ErrorKind::Other, "Could not retrieve system config variable for ticks per second", ) })? as u64; // finally compute the system time at which the process was started Ok(SystemTime::new( (process_start / ticks_per_second) as i64, ((process_start % ticks_per_second) * (1_000_000_000 / ticks_per_second)) as i64, )) } } fn read_proc_stat(pid: WithProcess, field_idx: isize) -> io::Result { // read from a specific pid file, or use `self` to refer to our own process let pidref = pid.to_proc_string(); // read the data from the stat file for the process with the given pid let path = PathBuf::from_iter(&["/proc", &pidref, "stat"]); let proc_stat = std::fs::read(path)?; // first get the part of the stat file past the second argument, we then reverse // search for a ')' character and start the search for the starttime field from there on let skip_past_second_arg = proc_stat.iter().rposition(|b| *b == b')').ok_or_else(|| { io::Error::new( io::ErrorKind::InvalidInput, "Could not find position of 'comm' field in process stat", ) })?; let mut stat = &proc_stat[skip_past_second_arg..]; // we've now passed the first two fields, so we are at index 1, now we skip over // fields until we arrive at the field we are searching for let mut curr_field = 1; while curr_field < field_idx && !stat.is_empty() { if stat[0] == b' ' { curr_field += 1; } stat = &stat[1..]; } // The expected field cannot be in the file anymore when we are at EOF if stat.is_empty() { return Err(io::Error::new( io::ErrorKind::InvalidData, "Stat file was not of the expected format", )); } // we've now arrived at the field we are looking for, we now check how // long this field is by finding where the next space is let mut idx = 0; while stat[idx] != b' ' && idx < stat.len() { idx += 1; } let field = &stat[0..idx]; // we first convert the data to a string slice, this should not fail with a normal /proc filesystem let fielddata = std::str::from_utf8(field).map_err(|_| { io::Error::new( io::ErrorKind::InvalidInput, "Could not interpret byte slice as string", ) })?; // then we convert the string slice to whatever the requested type was fielddata.parse().map_err(|_| { io::Error::new( io::ErrorKind::InvalidInput, "Could not interpret string as number", ) }) } pub fn escape_os_str_lossy(s: &std::ffi::OsStr) -> String { s.to_string_lossy().escape_default().collect() } #[cfg(test)] mod tests { use std::{ io::{self, Read, Write}, os::{fd::AsRawFd, unix::net::UnixStream}, process::exit, }; use libc::SIGKILL; use super::{ fork, getpgrp, setpgid, wait::{Wait, WaitOptions}, ForkResult, Group, User, WithProcess, }; pub(super) fn tempfile() -> std::io::Result { let timestamp = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .expect("Failed to get system time") .as_nanos(); let pid = std::process::id(); let filename = format!("sudo_rs_test_{}_{}", pid, timestamp); let path = std::path::PathBuf::from("/tmp").join(filename); std::fs::File::options() .read(true) .write(true) .create_new(true) .open(path) } #[test] fn test_get_user_and_group_by_id() { let fixed_users = &[(0, "root"), (1, "daemon")]; for &(id, name) in fixed_users { let root = User::from_uid(id).unwrap().unwrap(); assert_eq!(root.uid, id as libc::uid_t); assert_eq!(root.name, name); } for &(id, name) in fixed_users { let root = Group::from_gid(id).unwrap().unwrap(); assert_eq!(root.gid, id as libc::gid_t); assert_eq!(root.name, name); } } #[test] fn miri_test_group_impl() { use super::Group; use std::ffi::CString; fn test(name: &str, passwd: &str, gid: libc::gid_t, mem: &[&str]) { assert_eq!( { let c_mem: Vec = mem.iter().map(|&s| CString::new(s).unwrap()).collect(); let c_name = CString::new(name).unwrap(); let c_passwd = CString::new(passwd).unwrap(); unsafe { Group::from_libc(&libc::group { gr_name: c_name.as_ptr() as *mut _, gr_passwd: c_passwd.as_ptr() as *mut _, gr_gid: gid, gr_mem: c_mem .iter() .map(|cs| cs.as_ptr() as *mut _) .chain(std::iter::once(std::ptr::null_mut())) .collect::>() .as_mut_ptr(), }) } }, Group { name: name.to_string(), passwd: passwd.to_string(), gid, members: mem.iter().map(|s| s.to_string()).collect(), } ) } test("dr. bill", "fidelio", 1999, &["eyes", "wide", "shut"]); test("eris", "fnord", 5, &[]); test("abc", "password123", 42, &[""]); } #[test] fn get_process_tty_device() { assert!(super::Process::tty_device_id(WithProcess::Current).is_ok()); } #[test] fn get_process_start_time() { let time = super::Process::starting_time(WithProcess::Current).unwrap(); let now = super::SystemTime::now().unwrap(); assert!(time > now - super::time::Duration::minutes(24 * 60)); assert!(time < now); } #[test] fn pgid_test() { use super::{getpgid, setpgid}; let pgrp = getpgrp(); assert_eq!(getpgid(0).unwrap(), pgrp); assert_eq!(getpgid(std::process::id() as i32).unwrap(), pgrp); match super::fork().unwrap() { ForkResult::Child => { // wait for the parent. std::thread::sleep(std::time::Duration::from_secs(1)) } ForkResult::Parent(child_pid) => { // The child should be in our process group. assert_eq!(getpgid(child_pid).unwrap(), getpgid(0).unwrap(),); // Move the child to its own process group setpgid(child_pid, child_pid).unwrap(); // The process group of the child should have changed. assert_eq!(getpgid(child_pid).unwrap(), child_pid); } } } #[test] fn kill_test() { let mut child = std::process::Command::new("/bin/sleep") .arg("1") .spawn() .unwrap(); super::kill(child.id() as i32, SIGKILL).unwrap(); assert!(!child.wait().unwrap().success()); } #[test] fn killpg_test() { // Create a socket so the children write to it if they aren't terminated by `killpg`. let (mut rx, mut tx) = UnixStream::pair().unwrap(); let ForkResult::Parent(pid1) = fork().unwrap() else { std::thread::sleep(std::time::Duration::from_secs(1)); tx.write_all(&[42]).unwrap(); exit(0); }; let ForkResult::Parent(pid2) = fork().unwrap() else { std::thread::sleep(std::time::Duration::from_secs(1)); tx.write_all(&[42]).unwrap(); exit(0); }; drop(tx); let pgid = pid1; // Move the children to their own process group. setpgid(pid1, pgid).unwrap(); setpgid(pid2, pgid).unwrap(); // Send `SIGKILL` to the children process group. super::killpg(pgid, SIGKILL).unwrap(); // Ensure that the child were terminated before writing. assert_eq!( rx.read_exact(&mut [0; 2]).unwrap_err().kind(), std::io::ErrorKind::UnexpectedEof ); } fn is_closed(fd: &F) -> bool { crate::cutils::cerr(unsafe { libc::fcntl(fd.as_raw_fd(), libc::F_GETFD) }) .is_err_and(|err| err.raw_os_error() == Some(libc::EBADF)) } #[test] fn close_the_universe() { let ForkResult::Parent(child_pid) = fork().unwrap() else { let should_close = std::fs::File::open(std::env::temp_dir().join("should_close.txt")).unwrap(); assert!(!is_closed(&should_close)); let should_not_close = std::fs::File::open(std::env::temp_dir().join("should_not_close.txt")).unwrap(); assert!(!is_closed(&should_not_close)); let mut closer = super::FileCloser::new(); closer.except(&should_not_close); closer.close_the_universe().unwrap(); assert!(is_closed(&should_close)); assert!(!is_closed(&io::stdin())); assert!(!is_closed(&io::stdout())); assert!(!is_closed(&io::stderr())); assert!(!is_closed(&should_not_close)); exit(0) }; let (_, status) = child_pid.wait(WaitOptions::new()).unwrap(); assert_eq!(status.exit_status(), Some(0)); } #[test] fn except_stdio_is_fine() { let ForkResult::Parent(child_pid) = fork().unwrap() else { let mut closer = super::FileCloser::new(); closer.except(&io::stdin()); closer.except(&io::stdout()); closer.except(&io::stderr()); closer.close_the_universe().unwrap(); assert!(!is_closed(&io::stdin())); assert!(!is_closed(&io::stdout())); assert!(!is_closed(&io::stderr())); exit(0) }; let (_, status) = child_pid.wait(WaitOptions::new()).unwrap(); assert_eq!(status.exit_status(), Some(0)); } } sudo-rs-0.2.2/src/system/signal/handler.rs000064400000000000000000000040011046102023000165670ustar 00000000000000use std::io; use crate::log::dev_warn; use super::{consts::*, set::SignalAction, signal_name, SignalNumber}; /// A handler for a signal. /// /// When a value of this type is dropped, it will try to restore the action that was registered for /// the signal prior to calling [`SignalHandler::register`]. pub(crate) struct SignalHandler { signal: SignalNumber, original_action: SignalAction, } impl SignalHandler { const FORBIDDEN: &'static [SignalNumber] = &[SIGKILL, SIGSTOP]; /// Register a new handler for the given signal with the provided behavior. /// /// # Panics /// /// If it is not possible to override the action for the provided signal. pub(crate) fn register( signal: SignalNumber, behavior: SignalHandlerBehavior, ) -> io::Result { if Self::FORBIDDEN.contains(&signal) { panic!( "the {} signal action cannot be overriden", signal_name(signal) ); } let action = SignalAction::new(behavior)?; let original_action = action.register(signal)?; Ok(Self { signal, original_action, }) } /// Forget this signal handler. /// /// This can be used to avoid restoring the original action for the signal. pub(crate) fn forget(self) { std::mem::forget(self) } } impl Drop for SignalHandler { #[track_caller] fn drop(&mut self) { let signal = self.signal; if let Err(err) = self.original_action.register(signal) { dev_warn!( "cannot restore original action for {}: {err}", signal_name(signal), ) } } } /// The possible behaviors for a [`SignalHandler`]. pub(crate) enum SignalHandlerBehavior { /// Execute the default action for the signal. Default, /// Ignore the arrival of the signal. Ignore, /// Stream the signal information into the latest initialized instance of [`super::SignalStream`]. Stream, } sudo-rs-0.2.2/src/system/signal/info.rs000064400000000000000000000015511046102023000161140ustar 00000000000000use crate::system::interface::ProcessId; use super::SignalNumber; /// Information related to the arrival of a signal. #[repr(transparent)] pub(crate) struct SignalInfo { info: libc::siginfo_t, } impl SignalInfo { pub(super) const SIZE: usize = std::mem::size_of::(); /// Returns whether the signal was sent by the user or not. pub(crate) fn is_user_signaled(&self) -> bool { // FIXME: we should check if si_code is equal to SI_USER but for some reason the latter it // is not available in libc. self.info.si_code <= 0 } /// Gets the PID that sent the signal. pub(crate) fn pid(&self) -> ProcessId { // FIXME: some signals don't set si_pid. unsafe { self.info.si_pid() } } /// Gets the signal number. pub(crate) fn signal(&self) -> SignalNumber { self.info.si_signo } } sudo-rs-0.2.2/src/system/signal/mod.rs000064400000000000000000000016661046102023000157470ustar 00000000000000//! Utilities to handle signals. mod handler; mod info; mod set; mod stream; pub(crate) use handler::{SignalHandler, SignalHandlerBehavior}; pub(crate) use set::SignalSet; pub(crate) use stream::{register_handlers, SignalStream}; use std::borrow::Cow; pub(crate) type SignalNumber = libc::c_int; macro_rules! define_consts { ($($signal:ident,)*) => { pub(crate) mod consts { pub(crate) use libc::{$($signal,)*}; } pub(crate) fn signal_name(signal: SignalNumber) -> Cow<'static, str> { match signal { $(consts::$signal => stringify!($signal).into(),)* _ => format!("unknown signal ({signal})").into(), } } }; } define_consts! { SIGINT, SIGQUIT, SIGTSTP, SIGTERM, SIGHUP, SIGALRM, SIGPIPE, SIGUSR1, SIGUSR2, SIGCHLD, SIGCONT, SIGWINCH, SIGTTIN, SIGTTOU, SIGKILL, SIGSTOP, } sudo-rs-0.2.2/src/system/signal/set.rs000064400000000000000000000064731046102023000157640ustar 00000000000000use crate::cutils::cerr; use super::{handler::SignalHandlerBehavior, SignalNumber}; use std::{io, mem::MaybeUninit}; #[repr(transparent)] pub(super) struct SignalAction { raw: libc::sigaction, } impl SignalAction { pub(super) fn new(behavior: SignalHandlerBehavior) -> io::Result { // This guarantees that functions won't be interrupted by this signal as long as the // handler is alive. let mut sa_flags = libc::SA_RESTART; // We only need a full `sa_mask` if we are going to stream the signal information as we // don't want to be interrupted by any signals while executing `send_siginfo`. let (sa_sigaction, sa_mask) = match behavior { SignalHandlerBehavior::Default => (libc::SIG_DFL, SignalSet::empty()?), SignalHandlerBehavior::Ignore => (libc::SIG_IGN, SignalSet::empty()?), SignalHandlerBehavior::Stream => { // Specify that we want to pass a signal-catching function in `sa_sigaction`. sa_flags |= libc::SA_SIGINFO; ( super::stream::send_siginfo as libc::sighandler_t, SignalSet::full()?, ) } }; Ok(Self { raw: libc::sigaction { sa_sigaction, sa_mask: sa_mask.raw, sa_flags, sa_restorer: None, }, }) } pub(super) fn register(&self, signal: SignalNumber) -> io::Result { let mut original_action = MaybeUninit::::zeroed(); cerr(unsafe { libc::sigaction(signal, &self.raw, original_action.as_mut_ptr().cast()) })?; Ok(unsafe { original_action.assume_init() }) } } // A signal set that can be used to mask signals. #[repr(transparent)] pub(crate) struct SignalSet { raw: libc::sigset_t, } impl SignalSet { /// Create an empty set. pub(crate) fn empty() -> io::Result { let mut set = MaybeUninit::::zeroed(); cerr(unsafe { libc::sigemptyset(set.as_mut_ptr().cast()) })?; Ok(unsafe { set.assume_init() }) } /// Create a set containing all the signals. pub(crate) fn full() -> io::Result { let mut set = MaybeUninit::::zeroed(); cerr(unsafe { libc::sigfillset(set.as_mut_ptr().cast()) })?; Ok(unsafe { set.assume_init() }) } fn sigprocmask(&self, how: libc::c_int) -> io::Result { let mut original_set = MaybeUninit::::zeroed(); cerr(unsafe { libc::sigprocmask(how, &self.raw, original_set.as_mut_ptr().cast()) })?; Ok(unsafe { original_set.assume_init() }) } /// Block all the signals in this set and return the previous set of blocked signals. /// /// After calling this function successfully, the set of blocked signals will be the union of /// the previous set of blocked signals and this set. pub(crate) fn block(&self) -> io::Result { self.sigprocmask(libc::SIG_BLOCK) } /// Block only the signals that are in this set and return the previous set of blocked signals. /// /// After calling this function successfully, the set of blocked signals will be the exactly /// this set. pub(crate) fn set_mask(&self) -> io::Result { self.sigprocmask(libc::SIG_SETMASK) } } sudo-rs-0.2.2/src/system/signal/stream.rs000064400000000000000000000057611046102023000164630ustar 00000000000000use std::{ io, mem::MaybeUninit, os::{ fd::{AsRawFd, RawFd}, unix::net::UnixStream, }, sync::OnceLock, }; use crate::{cutils::cerr, log::dev_error}; use super::{ handler::{SignalHandler, SignalHandlerBehavior}, info::SignalInfo, signal_name, SignalNumber, }; static STREAM: OnceLock = OnceLock::new(); pub(super) unsafe fn send_siginfo( _signal: SignalNumber, info: *const SignalInfo, _context: *const libc::c_void, ) { if let Some(tx) = STREAM.get().map(|stream| stream.tx.as_raw_fd()) { unsafe { libc::send(tx, info.cast(), SignalInfo::SIZE, libc::MSG_DONTWAIT) }; } } /// A type able to receive signal information from any [`super::SignalHandler`] with the /// [`super::SignalHandlerBehavior::Stream`] behavior. /// /// This is a singleton type. Meaning that there will be only one value of this type during the /// execution of a program. pub(crate) struct SignalStream { rx: UnixStream, tx: UnixStream, } impl SignalStream { /// Create a new [`SignalStream`]. /// /// # Panics /// /// If this function has been called before. #[track_caller] pub(crate) fn init() -> io::Result<&'static Self> { let (rx, tx) = UnixStream::pair().map_err(|err| { dev_error!("cannot create socket pair for `SignalStream`: {err}"); err })?; if STREAM.set(Self { rx, tx }).is_err() { panic!("`SignalStream` has already been initialized"); }; Ok(STREAM.get().unwrap()) } /// Receives the information related to the arrival of a signal. pub(crate) fn recv(&self) -> io::Result { let mut info = MaybeUninit::::uninit(); let fd = self.rx.as_raw_fd(); let bytes = cerr(unsafe { libc::recv(fd, info.as_mut_ptr().cast(), SignalInfo::SIZE, 0) })?; if bytes as usize != SignalInfo::SIZE { return Err(io::Error::new( io::ErrorKind::UnexpectedEof, "Not enough bytes when receiving `siginfo_t`", )); } // SAFETY: we can assume `info` is initialized because `recv` wrote enough bytes to fill // the value and `siginfo_t` is POD. Ok(unsafe { info.assume_init() }) } } #[track_caller] pub(crate) fn register_handlers( signals: [SignalNumber; N], ) -> io::Result<[SignalHandler; N]> { let mut handlers = signals.map(|signal| (signal, MaybeUninit::uninit())); for (signal, handler) in &mut handlers { *handler = SignalHandler::register(*signal, SignalHandlerBehavior::Stream) .map(MaybeUninit::new) .map_err(|err| { let name = signal_name(*signal); dev_error!("cannot setup handler for {name}: {err}"); err })?; } Ok(handlers.map(|(_, handler)| unsafe { handler.assume_init() })) } impl AsRawFd for SignalStream { fn as_raw_fd(&self) -> RawFd { self.rx.as_raw_fd() } } sudo-rs-0.2.2/src/system/term/mod.rs000064400000000000000000000165321046102023000154370ustar 00000000000000mod user_term; use std::{ ffi::{c_uchar, CString, OsString}, fmt, fs::File, io, os::fd::{AsRawFd, FromRawFd, OwnedFd}, ptr::null_mut, }; use libc::{ioctl, winsize, TIOCSWINSZ}; use crate::cutils::{cerr, os_string_from_ptr, safe_isatty}; use super::interface::ProcessId; pub(crate) use user_term::UserTerm; pub(crate) struct Pty { /// The file path of the leader side of the pty. pub(crate) path: CString, /// The leader side of the pty. pub(crate) leader: PtyLeader, /// The follower side of the pty. pub(crate) follower: PtyFollower, } impl Pty { pub(crate) fn open() -> io::Result { const PATH_MAX: usize = libc::PATH_MAX as _; // Allocate a buffer to hold the path to the pty. let mut path = vec![0 as c_uchar; PATH_MAX]; // Create two integers to hold the file descriptors for each side of the pty. let (mut leader, mut follower) = (0, 0); cerr(unsafe { libc::openpty( &mut leader, &mut follower, path.as_mut_ptr().cast(), null_mut::(), null_mut::(), ) })?; // Get the index of the first null byte and truncate `path` so it doesn't have any null // bytes. If there are no null bytes the path is left as it is. if let Some(index) = path .iter() .enumerate() .find_map(|(index, &byte)| (byte == 0).then_some(index)) { path.truncate(index); } // This will not panic because `path` was truncated to not have any null bytes. let path = CString::new(path).unwrap(); Ok(Self { path, leader: PtyLeader { file: unsafe { OwnedFd::from_raw_fd(leader) }.into(), }, follower: PtyFollower { file: unsafe { OwnedFd::from_raw_fd(follower) }.into(), }, }) } } pub(crate) struct PtyLeader { file: File, } impl PtyLeader { pub(crate) fn set_size(&self, term_size: &TermSize) -> io::Result<()> { cerr(unsafe { ioctl( self.file.as_raw_fd(), TIOCSWINSZ, (term_size as *const TermSize).cast::(), ) })?; Ok(()) } } impl io::Read for PtyLeader { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.file.read(buf) } } impl io::Write for PtyLeader { fn write(&mut self, buf: &[u8]) -> io::Result { self.file.write(buf) } fn flush(&mut self) -> io::Result<()> { self.file.flush() } } impl AsRawFd for PtyLeader { fn as_raw_fd(&self) -> std::os::fd::RawFd { self.file.as_raw_fd() } } pub(crate) struct PtyFollower { file: File, } impl PtyFollower { pub(crate) fn try_clone(&self) -> io::Result { self.file.try_clone().map(|file| Self { file }) } } impl AsRawFd for PtyFollower { fn as_raw_fd(&self) -> std::os::fd::RawFd { self.file.as_raw_fd() } } impl From for std::process::Stdio { fn from(follower: PtyFollower) -> Self { follower.file.into() } } mod sealed { use std::os::fd::AsRawFd; pub(crate) trait Sealed {} impl Sealed for F {} } pub(crate) trait Terminal: sealed::Sealed { fn tcgetpgrp(&self) -> io::Result; fn tcsetpgrp(&self, pgrp: ProcessId) -> io::Result<()>; fn make_controlling_terminal(&self) -> io::Result<()>; fn ttyname(&self) -> io::Result; fn is_terminal(&self) -> bool; } impl Terminal for F { /// Get the foreground process group ID associated with this terminal. fn tcgetpgrp(&self) -> io::Result { cerr(unsafe { libc::tcgetpgrp(self.as_raw_fd()) }) } /// Set the foreground process group ID associated with this terminalto `pgrp`. fn tcsetpgrp(&self, pgrp: ProcessId) -> io::Result<()> { cerr(unsafe { libc::tcsetpgrp(self.as_raw_fd(), pgrp) }).map(|_| ()) } /// Make the given terminal the controlling terminal of the calling process. fn make_controlling_terminal(&self) -> io::Result<()> { cerr(unsafe { libc::ioctl(self.as_raw_fd(), libc::TIOCSCTTY, 0) })?; Ok(()) } /// Get the filename of the tty fn ttyname(&self) -> io::Result { let mut buf: [libc::c_char; 1024] = [0; 1024]; if !safe_isatty(self.as_raw_fd()) { return Err(io::ErrorKind::Unsupported.into()); } cerr(unsafe { libc::ttyname_r(self.as_raw_fd(), buf.as_mut_ptr() as _, buf.len()) })?; Ok(unsafe { os_string_from_ptr(buf.as_ptr()) }) } /// Rust standard library "IsTerminal" is not secure for setuid programs (CVE-2023-2002) fn is_terminal(&self) -> bool { safe_isatty(self.as_raw_fd()) } } /// Try to get the path of the current TTY pub fn current_tty_name() -> io::Result { std::io::stdin().ttyname() } #[repr(transparent)] pub(crate) struct TermSize { raw: winsize, } impl PartialEq for TermSize { fn eq(&self, other: &Self) -> bool { self.raw.ws_col == other.raw.ws_col && self.raw.ws_row == other.raw.ws_row } } impl fmt::Display for TermSize { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{} x {}", self.raw.ws_row, self.raw.ws_col) } } #[cfg(test)] mod tests { use std::{ ffi::OsString, io::{Read, Write}, os::unix::{net::UnixStream, prelude::OsStringExt}, path::PathBuf, process::exit, }; use crate::system::{fork, getpgid, setsid, term::*, ForkResult}; #[test] fn open_pty() { let pty = Pty::open().unwrap(); assert!(pty.leader.file.is_terminal()); assert!(pty.follower.file.is_terminal()); let path = PathBuf::from(OsString::from_vec(pty.path.into_bytes())); assert!(path.try_exists().unwrap()); assert!(path.starts_with("/dev/pts/")); } #[test] fn tcsetpgrp_and_tcgetpgrp_are_consistent() { // Create a socket so the child can send us a byte if successful. let (mut rx, mut tx) = UnixStream::pair().unwrap(); let ForkResult::Parent(_) = fork().unwrap() else { // Open a new pseudoterminal. let leader = Pty::open().unwrap().leader; // The pty leader should not have a foreground process group yet. assert_eq!(leader.tcgetpgrp().unwrap(), 0); // Create a new session so we can change the controlling terminal. setsid().unwrap(); // Set the pty leader as the controlling terminal. leader.make_controlling_terminal().unwrap(); // Set us as the foreground process group of the pty leader. let pgid = getpgid(0).unwrap(); leader.tcsetpgrp(pgid).unwrap(); // Check that we are in fact the foreground process group of the pty leader. assert_eq!(pgid, leader.tcgetpgrp().unwrap()); // If we haven't panicked yet, send a byte to the parent. tx.write_all(&[42]).unwrap(); exit(0); }; drop(tx); // Read one byte from the children to comfirm that it did not panic. let mut buf = [0]; rx.read_exact(&mut buf).unwrap(); assert_eq!(buf[0], 42); } } sudo-rs-0.2.2/src/system/term/user_term.rs000064400000000000000000000226631046102023000166670ustar 00000000000000//! This module is a port of ogsudo's `lib/util/term.c` with some minor changes to make it //! rust-like. use std::{ ffi::c_int, fs::{File, OpenOptions}, io::{self, Read, Write}, mem::MaybeUninit, os::fd::{AsRawFd, RawFd}, sync::atomic::{AtomicBool, Ordering}, }; use libc::{ c_void, cfgetispeed, cfgetospeed, cfmakeraw, cfsetispeed, cfsetospeed, ioctl, sigaction, sigemptyset, sighandler_t, siginfo_t, sigset_t, tcflag_t, tcgetattr, tcsetattr, termios, winsize, CS7, CS8, ECHO, ECHOCTL, ECHOE, ECHOK, ECHOKE, ECHONL, ICANON, ICRNL, IEXTEN, IGNCR, IGNPAR, IMAXBEL, INLCR, INPCK, ISIG, ISTRIP, IUTF8, IXANY, IXOFF, IXON, NOFLSH, OCRNL, OLCUC, ONLCR, ONLRET, ONOCR, OPOST, PARENB, PARMRK, PARODD, PENDIN, SIGTTOU, TCSADRAIN, TCSAFLUSH, TIOCGWINSZ, TIOCSWINSZ, TOSTOP, }; use super::{TermSize, Terminal}; use crate::{cutils::cerr, system::interface::ProcessId}; const INPUT_FLAGS: tcflag_t = IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL // | IUCLC /* FIXME: not in libc */ | IXON | IXANY | IXOFF | IMAXBEL | IUTF8; const OUTPUT_FLAGS: tcflag_t = OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET; const CONTROL_FLAGS: tcflag_t = CS7 | CS8 | PARENB | PARODD; const LOCAL_FLAGS: tcflag_t = ISIG | ICANON // | XCASE /* FIXME: not in libc */ | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH | TOSTOP | IEXTEN | ECHOCTL | ECHOKE | PENDIN; static GOT_SIGTTOU: AtomicBool = AtomicBool::new(false); extern "C" fn on_sigttou(_signal: c_int, _info: *mut siginfo_t, _: *mut c_void) { GOT_SIGTTOU.store(true, Ordering::SeqCst); } /// This is like `tcsetattr` but it only suceeds if we are in the foreground process group. fn tcsetattr_nobg(fd: c_int, flags: c_int, tp: *const termios) -> io::Result<()> { // This function is based around the fact that we receive `SIGTTOU` if we call `tcsetattr` and // we are not in the foreground process group. let mut original_action = MaybeUninit::::uninit(); let action = sigaction { // Call `on_sigttou` if `SIGTTOU` arrives. sa_sigaction: on_sigttou as sighandler_t, // Exclude any other signals from the set sa_mask: { let mut sa_mask = MaybeUninit::::uninit(); unsafe { sigemptyset(sa_mask.as_mut_ptr()) }; unsafe { sa_mask.assume_init() } }, sa_flags: 0, sa_restorer: None, }; // Reset `GOT_SIGTTOU`. GOT_SIGTTOU.store(false, Ordering::SeqCst); // Set `action` as the action for `SIGTTOU` and store the original action in `original_action` // to restore it later. unsafe { sigaction(SIGTTOU, &action, original_action.as_mut_ptr()) }; // Call `tcsetattr` until it suceeds and ignore interruptions if we did not receive `SIGTTOU`. let result = loop { match cerr(unsafe { tcsetattr(fd, flags, tp) }) { Ok(_) => break Ok(()), Err(err) => { let got_sigttou = GOT_SIGTTOU.load(Ordering::SeqCst); if got_sigttou || err.kind() != io::ErrorKind::Interrupted { break Err(err); } } } }; // Restore the original action. unsafe { sigaction(SIGTTOU, original_action.as_ptr(), std::ptr::null_mut()) }; result } /// Type to manipulate the settings of the user's terminal. pub struct UserTerm { tty: File, original_termios: MaybeUninit, changed: bool, } impl UserTerm { /// Open the user's terminal. pub fn open() -> io::Result { Ok(Self { tty: OpenOptions::new().read(true).write(true).open("/dev/tty")?, original_termios: MaybeUninit::uninit(), changed: false, }) } pub(crate) fn get_size(&self) -> io::Result { let mut term_size = MaybeUninit::::uninit(); cerr(unsafe { ioctl( self.tty.as_raw_fd(), TIOCGWINSZ, term_size.as_mut_ptr().cast::(), ) })?; Ok(unsafe { term_size.assume_init() }) } /// Copy the settings of the user's terminal to the `dst` terminal. pub fn copy_to(&self, dst: &D) -> io::Result<()> { let src = self.tty.as_raw_fd(); let dst = dst.as_raw_fd(); let mut tt_src = MaybeUninit::::uninit(); let mut tt_dst = MaybeUninit::::uninit(); let mut wsize = MaybeUninit::::uninit(); cerr(unsafe { tcgetattr(src, tt_src.as_mut_ptr()) })?; cerr(unsafe { tcgetattr(dst, tt_dst.as_mut_ptr()) })?; let tt_src = unsafe { tt_src.assume_init() }; let mut tt_dst = unsafe { tt_dst.assume_init() }; // Clear select input, output, control and local flags. tt_dst.c_iflag &= !INPUT_FLAGS; tt_dst.c_oflag &= !OUTPUT_FLAGS; tt_dst.c_cflag &= !CONTROL_FLAGS; tt_dst.c_lflag &= !LOCAL_FLAGS; // Copy select input, output, control and local flags. tt_dst.c_iflag |= tt_src.c_iflag & INPUT_FLAGS; tt_dst.c_oflag |= tt_src.c_oflag & OUTPUT_FLAGS; tt_dst.c_cflag |= tt_src.c_cflag & CONTROL_FLAGS; tt_dst.c_lflag |= tt_src.c_lflag & LOCAL_FLAGS; // Copy special chars from src verbatim. tt_dst.c_cc.copy_from_slice(&tt_src.c_cc); // Copy speed from `src`. { let mut speed = unsafe { cfgetospeed(&tt_src) }; // Zero output speed closes the connection. if speed == libc::B0 { speed = libc::B38400; } unsafe { cfsetospeed(&mut tt_dst, speed) }; speed = unsafe { cfgetispeed(&tt_src) }; unsafe { cfsetispeed(&mut tt_dst, speed) }; } tcsetattr_nobg(dst, TCSAFLUSH, &tt_dst)?; cerr(unsafe { ioctl(src, TIOCGWINSZ, &mut wsize) })?; cerr(unsafe { ioctl(dst, TIOCSWINSZ, &wsize) })?; Ok(()) } /// Set the user's terminal to raw mode. Enable terminal signals if `with_signals` is set to /// `true`. pub fn set_raw_mode(&mut self, with_signals: bool) -> io::Result<()> { let fd = self.tty.as_raw_fd(); if !self.changed { cerr(unsafe { tcgetattr(fd, self.original_termios.as_mut_ptr()) })?; } // Retrieve the original terminal. let mut term = unsafe { self.original_termios.assume_init() }; // Set terminal to raw mode. unsafe { cfmakeraw(&mut term) }; // Enable terminal signals. if with_signals { term.c_cflag |= ISIG; } tcsetattr_nobg(fd, TCSADRAIN, &term)?; self.changed = true; Ok(()) } /// Restore the saved terminal settings if we are in the foreground process group. /// /// This change is done after waiting for all the queued output to be written. To discard the /// queued input `flush` must be set to `true`. pub fn restore(&mut self, flush: bool) -> io::Result<()> { if self.changed { let fd = self.tty.as_raw_fd(); let flags = if flush { TCSAFLUSH } else { TCSADRAIN }; tcsetattr_nobg(fd, flags, self.original_termios.as_ptr())?; self.changed = false; } Ok(()) } /// This is like `tcsetpgrp` but it only suceeds if we are in the foreground process group. pub fn tcsetpgrp_nobg(&self, pgrp: ProcessId) -> io::Result<()> { // This function is based around the fact that we receive `SIGTTOU` if we call `tcsetpgrp` and // we are not in the foreground process group. let mut original_action = MaybeUninit::::uninit(); let action = sigaction { // Call `on_sigttou` if `SIGTTOU` arrives. sa_sigaction: on_sigttou as sighandler_t, // Exclude any other signals from the set sa_mask: { let mut sa_mask = MaybeUninit::::uninit(); unsafe { sigemptyset(sa_mask.as_mut_ptr()) }; unsafe { sa_mask.assume_init() } }, sa_flags: 0, sa_restorer: None, }; // Reset `GOT_SIGTTOU`. GOT_SIGTTOU.store(false, Ordering::SeqCst); // Set `action` as the action for `SIGTTOU` and store the original action in `original_action` // to restore it later. unsafe { sigaction(SIGTTOU, &action, original_action.as_mut_ptr()) }; // Call `tcsetattr` until it suceeds and ignore interruptions if we did not receive `SIGTTOU`. let result = loop { match self.tty.tcsetpgrp(pgrp) { Ok(()) => break Ok(()), Err(err) => { let got_sigttou = GOT_SIGTTOU.load(Ordering::SeqCst); if got_sigttou || err.kind() != io::ErrorKind::Interrupted { break Err(err); } } } }; // Restore the original action. unsafe { sigaction(SIGTTOU, original_action.as_ptr(), std::ptr::null_mut()) }; result } } impl AsRawFd for UserTerm { fn as_raw_fd(&self) -> RawFd { self.tty.as_raw_fd() } } impl Read for UserTerm { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.tty.read(buf) } } impl Write for UserTerm { fn write(&mut self, buf: &[u8]) -> io::Result { self.tty.write(buf) } fn flush(&mut self) -> io::Result<()> { self.tty.flush() } } sudo-rs-0.2.2/src/system/time.rs000064400000000000000000000115601046102023000146430ustar 00000000000000use std::{ io::{Read, Write}, mem::MaybeUninit, ops::{Add, Sub}, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct SystemTime { secs: i64, nsecs: i64, } impl SystemTime { pub(super) fn new(secs: i64, nsecs: i64) -> SystemTime { SystemTime { secs: secs + nsecs.div_euclid(1_000_000_000), nsecs: nsecs.rem_euclid(1_000_000_000), } } pub fn now() -> std::io::Result { let mut spec = MaybeUninit::::uninit(); crate::cutils::cerr(unsafe { libc::clock_gettime(libc::CLOCK_BOOTTIME, spec.as_mut_ptr()) })?; // SAFETY: The `libc::clock_gettime` will correctly initialize `spec`, // otherwise it will return early with the `?` operator. let spec = unsafe { spec.assume_init() }; Ok(spec.into()) } pub(super) fn encode(&self, target: &mut impl Write) -> std::io::Result<()> { let secs = self.secs.to_ne_bytes(); let nsecs = self.nsecs.to_ne_bytes(); target.write_all(&secs)?; target.write_all(&nsecs)?; Ok(()) } pub(super) fn decode(from: &mut impl Read) -> std::io::Result { let mut sec_bytes = [0; 8]; let mut nsec_bytes = [0; 8]; from.read_exact(&mut sec_bytes)?; from.read_exact(&mut nsec_bytes)?; Ok(SystemTime::new( i64::from_ne_bytes(sec_bytes), i64::from_ne_bytes(nsec_bytes), )) } } impl Sub for SystemTime { type Output = Duration; fn sub(self, rhs: SystemTime) -> Self::Output { Duration::new(self.secs - rhs.secs, self.nsecs - rhs.nsecs) } } impl Add for SystemTime { type Output = SystemTime; fn add(self, rhs: Duration) -> Self::Output { SystemTime::new(self.secs + rhs.secs, self.nsecs + rhs.nsecs) } } impl Sub for SystemTime { type Output = SystemTime; fn sub(self, rhs: Duration) -> Self::Output { SystemTime::new(self.secs - rhs.secs, self.nsecs - rhs.nsecs) } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub struct Duration { secs: i64, nsecs: i64, } impl Duration { pub fn new(secs: i64, nsecs: i64) -> Duration { Duration { secs: secs + nsecs.div_euclid(1_000_000_000), nsecs: nsecs.rem_euclid(1_000_000_000), } } pub fn seconds(secs: i64) -> Duration { Duration::new(secs, 0) } #[cfg(test)] pub fn minutes(minutes: i64) -> Duration { Duration::seconds(minutes * 60) } #[cfg(test)] pub fn milliseconds(ms: i64) -> Duration { let secs = ms / 1000; let ms = ms % 1000; Duration::new(secs, ms * 1_000_000) } } impl Add for Duration { type Output = Duration; fn add(self, rhs: Duration) -> Self::Output { Duration::new(self.secs + rhs.secs, self.nsecs + rhs.nsecs) } } impl Sub for Duration { type Output = Duration; fn sub(self, rhs: Duration) -> Self::Output { Duration::new(self.secs - rhs.secs, self.nsecs - rhs.nsecs) } } impl From for SystemTime { fn from(value: libc::timespec) -> Self { SystemTime::new(value.tv_sec as _, value.tv_nsec as _) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_new_durations_and_times() { assert_eq!(Duration::new(1, 1_000_000_000), Duration::seconds(2)); assert_eq!( Duration::new(-2, 500_000_000), Duration::seconds(-1) + Duration::milliseconds(-500) ); assert_eq!(SystemTime::new(-1, 2_000_000_000), SystemTime::new(1, 0)); assert_eq!( SystemTime::new(2, -500_000_000), SystemTime::new(1, 500_000_000) ); } #[test] fn test_time_ops() { assert_eq!( Duration::seconds(2) + Duration::seconds(3), Duration::seconds(5) ); assert_eq!( Duration::seconds(3) - Duration::seconds(1), Duration::seconds(2) ); assert_eq!( Duration::seconds(-10) + Duration::seconds(-5), Duration::seconds(-15) ); assert_eq!( Duration::milliseconds(5555) + Duration::milliseconds(5555), Duration::seconds(11) + Duration::milliseconds(110) ); assert_eq!( Duration::milliseconds(-5555) + Duration::milliseconds(-1111), Duration::milliseconds(-6666) ); assert_eq!( Duration::seconds(10) - Duration::seconds(-5), Duration::seconds(15) ); assert_eq!( SystemTime::new(0, 0) + Duration::seconds(3), SystemTime::new(3, 0) ); assert_eq!( SystemTime::new(10, 0) - Duration::seconds(4), SystemTime::new(6, 0) ); } } sudo-rs-0.2.2/src/system/timestamp.rs000064400000000000000000000661371046102023000157220ustar 00000000000000use std::{ fs::File, io::{self, Cursor, Read, Seek, Write}, path::PathBuf, }; use crate::{ common::resolve::CurrentUser, log::{auth_info, auth_warn}, }; use super::{ audit::secure_open_cookie_file, file::FileLock, interface::UserId, time::{Duration, SystemTime}, Process, WithProcess, }; /// Truncates or extends the underlying data pub trait SetLength { /// After this is called, the underlying data will either be truncated /// up to new_len bytes, or it will have been extended by zero bytes up to /// new_len. fn set_len(&mut self, new_len: usize) -> io::Result<()>; } impl SetLength for File { fn set_len(&mut self, new_len: usize) -> io::Result<()> { File::set_len(self, new_len as u64) } } type BoolStorage = u8; const SIZE_OF_TS: i64 = std::mem::size_of::() as i64; const SIZE_OF_BOOL: i64 = std::mem::size_of::() as i64; const MOD_OFFSET: i64 = SIZE_OF_TS + SIZE_OF_BOOL; #[derive(Debug)] pub struct SessionRecordFile { file: File, timeout: Duration, for_user: UserId, } impl SessionRecordFile { const BASE_PATH: &'static str = "/var/run/sudo-rs/ts"; pub fn open_for_user(user: &CurrentUser, timeout: Duration) -> io::Result { let uid = user.uid; let mut path = PathBuf::from(Self::BASE_PATH); path.push(uid.to_string()); SessionRecordFile::new(uid, secure_open_cookie_file(&path)?, timeout) } const FILE_VERSION: u16 = 1; const MAGIC_NUM: u16 = 0x50D0; const VERSION_OFFSET: u64 = Self::MAGIC_NUM.to_le_bytes().len() as u64; const FIRST_RECORD_OFFSET: u64 = Self::VERSION_OFFSET + Self::FILE_VERSION.to_le_bytes().len() as u64; /// Create a new SessionRecordFile from the given i/o stream. /// Timestamps in this file are considered valid if they were created or /// updated at most `timeout` time ago. pub fn new(for_user: UserId, io: File, timeout: Duration) -> io::Result { let mut session_records = SessionRecordFile { file: io, timeout, for_user, }; // match the magic number, otherwise reset the file match session_records.read_magic()? { Some(magic) if magic == Self::MAGIC_NUM => (), x => { if let Some(_magic) = x { auth_info!("Session records file for user '{for_user}' is invalid, resetting"); } session_records.init(Self::VERSION_OFFSET)?; } } // match the file version match session_records.read_version()? { Some(v) if v == Self::FILE_VERSION => (), x => { if let Some(v) = x { auth_info!("Session records file for user '{for_user}' has invalid version {v}, only file version {} is supported, resetting", Self::FILE_VERSION); } else { auth_info!( "Session records file did not contain file version information, resetting" ); } session_records.init(Self::FIRST_RECORD_OFFSET)?; } } // we are ready to read records Ok(session_records) } /// Read the magic number from the input stream fn read_magic(&mut self) -> io::Result> { let mut magic_bytes = [0; std::mem::size_of::()]; match self.file.read_exact(&mut magic_bytes) { Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => Ok(None), Err(e) => Err(e), Ok(()) => Ok(Some(u16::from_le_bytes(magic_bytes))), } } /// Read the version number from the input stream fn read_version(&mut self) -> io::Result> { let mut version_bytes = [0; std::mem::size_of::()]; match self.file.read_exact(&mut version_bytes) { Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => Ok(None), Err(e) => Err(e), Ok(()) => Ok(Some(u16::from_le_bytes(version_bytes))), } } /// Initialize a new empty stream. If the stream/file was already filled /// before it will be truncated. fn init(&mut self, offset: u64) -> io::Result<()> { // lock the file to indicate that we are currently writing to it let lock = FileLock::exclusive(&self.file, false)?; self.file.set_len(0)?; self.file.rewind()?; self.file.write_all(&Self::MAGIC_NUM.to_le_bytes())?; self.file.write_all(&Self::FILE_VERSION.to_le_bytes())?; self.file.seek(io::SeekFrom::Start(offset))?; lock.unlock()?; Ok(()) } /// Read the next record and keep note of the start and end positions in the file of that record /// /// This method assumes that the file is already exclusively locked. fn next_record(&mut self) -> io::Result> { // record the position at which this record starts (including size bytes) let mut record_length_bytes = [0; std::mem::size_of::()]; let curr_pos = self.file.stream_position()?; // if eof occurs here we assume we reached the end of the file let record_length = match self.file.read_exact(&mut record_length_bytes) { Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => return Ok(None), Err(e) => return Err(e), Ok(()) => u16::from_le_bytes(record_length_bytes), }; // special case when record_length is zero if record_length == 0 { return Err(io::Error::new( io::ErrorKind::InvalidInput, "Found empty record", )); } let mut buf = vec![0; record_length as usize]; match self.file.read_exact(&mut buf) { Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => { // there was half a record here, we clear the rest of the file auth_info!("Found incomplete record in session records file for {}, clearing rest of the file", self.for_user); self.file.set_len(curr_pos)?; return Ok(None); } Err(e) => return Err(e), Ok(()) => (), } // we now try and decode the data read into a session record match SessionRecord::from_bytes(&buf) { Err(_) => { // any error assumes that this file is nonsense from this point // onwards, so we clear the file up to the start of this record auth_info!("Found invalid record in session records file for {}, clearing rest of the file", self.for_user); self.file.set_len(curr_pos)?; Ok(None) } Ok(record) => Ok(Some(record)), } } /// Try and find a record for the given scope and auth user id and update /// that record time to the current time. This will not create a new record /// when one is not found. A record will only be updated if it is still /// valid at this time. pub fn touch(&mut self, scope: RecordScope, auth_user: UserId) -> io::Result { // lock the file to indicate that we are currently in a writing operation let lock = FileLock::exclusive(&self.file, false)?; self.seek_to_first_record()?; while let Some(record) = self.next_record()? { // only touch if record is enabled if record.enabled && record.matches(&scope, auth_user) { let now = SystemTime::now()?; if record.written_between(now - self.timeout, now) { // move back to where the timestamp is and overwrite with the latest time self.file.seek(io::SeekFrom::Current(-MOD_OFFSET))?; let new_time = SystemTime::now()?; new_time.encode(&mut self.file)?; // make sure we can still go to the end of the record self.file.seek(io::SeekFrom::Current(SIZE_OF_BOOL))?; // writing is done, unlock and return lock.unlock()?; return Ok(TouchResult::Updated { old_time: record.timestamp, new_time, }); } else { lock.unlock()?; return Ok(TouchResult::Outdated { time: record.timestamp, }); } } } lock.unlock()?; Ok(TouchResult::NotFound) } /// Disable all records that match the given scope. If an auth user id is /// given then only records with the given scope that are targetting that /// specific user will be disabled. pub fn disable(&mut self, scope: RecordScope, auth_user: Option) -> io::Result<()> { let lock = FileLock::exclusive(&self.file, false)?; self.seek_to_first_record()?; while let Some(record) = self.next_record()? { let must_disable = auth_user .map(|tu| record.matches(&scope, tu)) .unwrap_or_else(|| record.scope == scope); if must_disable { self.file.seek(io::SeekFrom::Current(-SIZE_OF_BOOL))?; write_bool(false, &mut self.file)?; } } lock.unlock()?; Ok(()) } /// Create a new record for the given scope and auth user id. /// If there is an existing record that matches the scope and auth user, /// then that record will be updated. pub fn create(&mut self, scope: RecordScope, auth_user: UserId) -> io::Result { // lock the file to indicate that we are currently writing to it let lock = FileLock::exclusive(&self.file, false)?; self.seek_to_first_record()?; while let Some(record) = self.next_record()? { if record.matches(&scope, auth_user) { self.file.seek(io::SeekFrom::Current(-MOD_OFFSET))?; let new_time = SystemTime::now()?; new_time.encode(&mut self.file)?; write_bool(true, &mut self.file)?; lock.unlock()?; return Ok(CreateResult::Updated { old_time: record.timestamp, new_time, }); } } // record was not found in the list so far, create a new one let record = SessionRecord::new(scope, auth_user)?; // make sure we really are at the end of the file self.file.seek(io::SeekFrom::End(0))?; self.write_record(&record)?; lock.unlock()?; Ok(CreateResult::Created { time: record.timestamp, }) } /// Completely resets the entire file and removes all records. pub fn reset(&mut self) -> io::Result<()> { self.init(0) } /// Write a new record at the current position in the file. fn write_record(&mut self, record: &SessionRecord) -> io::Result<()> { // convert the new record to byte representation and make sure that it fits let bytes = record.as_bytes()?; let record_length = bytes.len(); if record_length > u16::MAX as usize { return Err(io::Error::new( io::ErrorKind::InvalidInput, "A record with an unexpectedly large size was created", )); } let record_length = record_length as u16; // store as u16 // write the record self.file.write_all(&record_length.to_le_bytes())?; self.file.write_all(&bytes)?; Ok(()) } /// Move to where the first record starts. fn seek_to_first_record(&mut self) -> io::Result<()> { self.file .seek(io::SeekFrom::Start(Self::FIRST_RECORD_OFFSET))?; Ok(()) } } #[derive(Debug, PartialEq, Eq, Clone)] pub enum TouchResult { /// The record was found and within the timeout, and it was refreshed Updated { old_time: SystemTime, new_time: SystemTime, }, /// A record was found, but it was no longer valid Outdated { time: SystemTime }, /// A record was not found that matches the input NotFound, } pub enum CreateResult { /// The record was found and it was refreshed Updated { old_time: SystemTime, new_time: SystemTime, }, /// A new record was created and was set to the time returned Created { time: SystemTime }, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum RecordScope { Tty { tty_device: libc::dev_t, session_pid: libc::pid_t, init_time: SystemTime, }, Ppid { group_pid: libc::pid_t, init_time: SystemTime, }, } impl RecordScope { fn encode(&self, target: &mut impl Write) -> std::io::Result<()> { match self { RecordScope::Tty { tty_device, session_pid, init_time, } => { target.write_all(&[1u8])?; let b = tty_device.to_le_bytes(); target.write_all(&b)?; let b = session_pid.to_le_bytes(); target.write_all(&b)?; init_time.encode(target)?; } RecordScope::Ppid { group_pid, init_time, } => { target.write_all(&[2u8])?; let b = group_pid.to_le_bytes(); target.write_all(&b)?; init_time.encode(target)?; } } Ok(()) } fn decode(from: &mut impl Read) -> std::io::Result { let mut buf = [0; 1]; from.read_exact(&mut buf)?; match buf[0] { 1 => { let mut buf = [0; std::mem::size_of::()]; from.read_exact(&mut buf)?; let tty_device = libc::dev_t::from_le_bytes(buf); let mut buf = [0; std::mem::size_of::()]; from.read_exact(&mut buf)?; let session_pid = libc::pid_t::from_le_bytes(buf); let init_time = SystemTime::decode(from)?; Ok(RecordScope::Tty { tty_device, session_pid, init_time, }) } 2 => { let mut buf = [0; std::mem::size_of::()]; from.read_exact(&mut buf)?; let group_pid = libc::pid_t::from_le_bytes(buf); let init_time = SystemTime::decode(from)?; Ok(RecordScope::Ppid { group_pid, init_time, }) } x => Err(io::Error::new( io::ErrorKind::InvalidInput, format!("Unexpected scope variant discriminator: {x}"), )), } } /// Tries to determine a record match scope for the current context. /// This should never produce an error since any actual error should just be /// ignored and no session record file should be used in that case. pub fn for_process(process: &Process) -> Option { let tty = Process::tty_device_id(WithProcess::Current); if let Ok(Some(tty_device)) = tty { if let Ok(init_time) = Process::starting_time(WithProcess::Other(process.session_id)) { Some(RecordScope::Tty { tty_device, session_pid: process.session_id, init_time, }) } else { auth_warn!("Could not get terminal foreground process starting time"); None } } else if let Some(parent_pid) = process.parent_pid { if let Ok(init_time) = Process::starting_time(WithProcess::Other(parent_pid)) { Some(RecordScope::Ppid { group_pid: parent_pid, init_time, }) } else { auth_warn!("Could not get parent process starting time"); None } } else { None } } } fn write_bool(b: bool, target: &mut impl Write) -> io::Result<()> { let s: BoolStorage = if b { 0xFF } else { 0x00 }; let bytes = s.to_le_bytes(); target.write_all(&bytes)?; Ok(()) } /// A record in the session record file #[derive(Debug, PartialEq, Eq)] pub struct SessionRecord { /// The scope for which the current record applies, i.e. what process group /// or which TTY for interactive sessions scope: RecordScope, /// The user that needs to be authenticated against auth_user: libc::uid_t, /// The timestamp at which the time was created. This must always be a time /// originating from a monotonic clock that continues counting during system /// sleep. timestamp: SystemTime, /// Disabled records act as if they do not exist, but their storage can /// be re-used when recreating for the same scope and auth user enabled: bool, } impl SessionRecord { /// Create a new record that is scoped to the specified scope and has `auth_user` as /// the target for authentication for the session. fn new(scope: RecordScope, auth_user: UserId) -> io::Result { Ok(Self::init(scope, auth_user, true, SystemTime::now()?)) } /// Initialize a new record with the given parameters fn init( scope: RecordScope, auth_user: UserId, enabled: bool, timestamp: SystemTime, ) -> SessionRecord { SessionRecord { scope, auth_user, timestamp, enabled, } } /// Encode a record into the given stream fn encode(&self, target: &mut impl Write) -> std::io::Result<()> { self.scope.encode(target)?; // write user id let buf = self.auth_user.to_le_bytes(); target.write_all(&buf)?; // write timestamp self.timestamp.encode(target)?; // write enabled boolean write_bool(self.enabled, target)?; Ok(()) } /// Decode a record from the given stream fn decode(from: &mut impl Read) -> std::io::Result { let scope = RecordScope::decode(from)?; // auth user id let mut buf = [0; std::mem::size_of::()]; from.read_exact(&mut buf)?; let auth_user = libc::uid_t::from_le_bytes(buf); // timestamp let timestamp = SystemTime::decode(from)?; // enabled boolean let mut buf = [0; std::mem::size_of::()]; from.read_exact(&mut buf)?; let enabled = match BoolStorage::from_le_bytes(buf) { 0xFF => true, 0x00 => false, _ => { return Err(io::Error::new( io::ErrorKind::InvalidData, "Invalid boolean value detected in input stream", )) } }; Ok(SessionRecord::init(scope, auth_user, enabled, timestamp)) } /// Convert the record to a vector of bytes for storage. pub fn as_bytes(&self) -> std::io::Result> { let mut v = vec![]; self.encode(&mut v)?; Ok(v) } /// Convert the given byte slice to a session record, the byte slice must /// be fully consumed for this conversion to be valid. pub fn from_bytes(data: &[u8]) -> std::io::Result { let mut cursor = Cursor::new(data); let record = SessionRecord::decode(&mut cursor)?; if cursor.position() != data.len() as u64 { Err(io::Error::new( io::ErrorKind::InvalidInput, "Record size and record length did not match", )) } else { Ok(record) } } /// Returns true if this record matches the specified scope and is for the /// specified target auth user. pub fn matches(&self, scope: &RecordScope, auth_user: UserId) -> bool { self.scope == *scope && self.auth_user == auth_user } /// Returns true if this record was written somewhere in the time range /// between `early_time` (inclusive) and `later_time` (inclusive), where /// early timestamp may not be later than the later timestamp. pub fn written_between(&self, early_time: SystemTime, later_time: SystemTime) -> bool { early_time <= later_time && self.timestamp >= early_time && self.timestamp <= later_time } } #[cfg(test)] mod tests { use super::*; use crate::system::tests::tempfile; const TEST_USER_ID: UserId = 1000; impl SetLength for Cursor> { fn set_len(&mut self, new_len: usize) -> io::Result<()> { self.get_mut().truncate(new_len); while self.get_mut().len() < new_len { self.get_mut().push(0); } Ok(()) } } impl SetLength for Cursor<&mut Vec> { fn set_len(&mut self, new_len: usize) -> io::Result<()> { self.get_mut().truncate(new_len); while self.get_mut().len() < new_len { self.get_mut().push(0); } Ok(()) } } #[test] fn can_encode_and_decode() { let tty_sample = SessionRecord::new( RecordScope::Tty { tty_device: 10, session_pid: 42, init_time: SystemTime::now().unwrap() - Duration::seconds(150), }, 999, ) .unwrap(); let mut bytes = tty_sample.as_bytes().unwrap(); let decoded = SessionRecord::from_bytes(&bytes).unwrap(); assert_eq!(tty_sample, decoded); // we provide some invalid input assert!(SessionRecord::from_bytes(&bytes[1..]).is_err()); // we have remaining input after decoding bytes.push(0); assert!(SessionRecord::from_bytes(&bytes).is_err()); let ppid_sample = SessionRecord::new( RecordScope::Ppid { group_pid: 42, init_time: SystemTime::now().unwrap(), }, 123, ) .unwrap(); let bytes = ppid_sample.as_bytes().unwrap(); let decoded = SessionRecord::from_bytes(&bytes).unwrap(); assert_eq!(ppid_sample, decoded); } #[test] fn timestamp_record_matches_works() { let init_time = SystemTime::now().unwrap(); let scope = RecordScope::Tty { tty_device: 12, session_pid: 1234, init_time, }; let tty_sample = SessionRecord::new(scope, 675).unwrap(); assert!(tty_sample.matches(&scope, 675)); assert!(!tty_sample.matches(&scope, 789)); assert!(!tty_sample.matches( &RecordScope::Tty { tty_device: 20, session_pid: 1234, init_time }, 675 )); assert!(!tty_sample.matches( &RecordScope::Ppid { group_pid: 42, init_time }, 675 )); // make sure time is different std::thread::sleep(std::time::Duration::from_millis(1)); assert!(!tty_sample.matches( &RecordScope::Tty { tty_device: 12, session_pid: 1234, init_time: SystemTime::now().unwrap() }, 675 )); } #[test] fn timestamp_record_written_between_works() { let some_time = SystemTime::now().unwrap() + Duration::minutes(100); let scope = RecordScope::Tty { tty_device: 12, session_pid: 1234, init_time: some_time, }; let sample = SessionRecord::init(scope, 1234, true, some_time); let dur = Duration::seconds(30); assert!(sample.written_between(some_time, some_time)); assert!(sample.written_between(some_time, some_time + dur)); assert!(sample.written_between(some_time - dur, some_time)); assert!(!sample.written_between(some_time + dur, some_time - dur)); assert!(!sample.written_between(some_time + dur, some_time + dur + dur)); assert!(!sample.written_between(some_time - dur - dur, some_time - dur)); } fn tempfile_with_data(data: &[u8]) -> io::Result { let mut file = tempfile()?; file.write_all(data)?; file.rewind()?; Ok(file) } fn data_from_tempfile(mut f: File) -> io::Result> { let mut v = vec![]; f.rewind()?; f.read_to_end(&mut v)?; Ok(v) } #[test] fn session_record_file_header_checks() { // valid header should remain valid let c = tempfile_with_data(&[0xD0, 0x50, 0x01, 0x00]).unwrap(); let timeout = Duration::seconds(30); assert!(SessionRecordFile::new(TEST_USER_ID, c.try_clone().unwrap(), timeout).is_ok()); let v = data_from_tempfile(c).unwrap(); assert_eq!(&v[..], &[0xD0, 0x50, 0x01, 0x00]); // invalid headers should be corrected let c = tempfile_with_data(&[0xAB, 0xBA]).unwrap(); assert!(SessionRecordFile::new(TEST_USER_ID, c.try_clone().unwrap(), timeout).is_ok()); let v = data_from_tempfile(c).unwrap(); assert_eq!(&v[..], &[0xD0, 0x50, 0x01, 0x00]); // empty header should be filled in let c = tempfile_with_data(&[]).unwrap(); assert!(SessionRecordFile::new(TEST_USER_ID, c.try_clone().unwrap(), timeout).is_ok()); let v = data_from_tempfile(c).unwrap(); assert_eq!(&v[..], &[0xD0, 0x50, 0x01, 0x00]); // invalid version should reset file let c = tempfile_with_data(&[0xD0, 0x50, 0xAB, 0xBA, 0x0, 0x0]).unwrap(); assert!(SessionRecordFile::new(TEST_USER_ID, c.try_clone().unwrap(), timeout).is_ok()); let v = data_from_tempfile(c).unwrap(); assert_eq!(&v[..], &[0xD0, 0x50, 0x01, 0x00]); } #[test] fn can_create_and_update_valid_file() { let timeout = Duration::seconds(30); let c = tempfile_with_data(&[]).unwrap(); let mut srf = SessionRecordFile::new(TEST_USER_ID, c.try_clone().unwrap(), timeout).unwrap(); let tty_scope = RecordScope::Tty { tty_device: 0, session_pid: 0, init_time: SystemTime::new(0, 0), }; let auth_user = 2424; let res = srf.create(tty_scope, auth_user).unwrap(); let CreateResult::Created { time } = res else { panic!("Expected record to be created"); }; std::thread::sleep(std::time::Duration::from_millis(1)); let second = srf.touch(tty_scope, auth_user).unwrap(); let TouchResult::Updated { old_time, new_time } = second else { panic!("Expected record to be updated"); }; assert_eq!(time, old_time); assert_ne!(old_time, new_time); std::thread::sleep(std::time::Duration::from_millis(1)); let res = srf.create(tty_scope, auth_user).unwrap(); let CreateResult::Updated { .. } = res else { panic!("Expected record to be updated"); }; // reset the file assert!(srf.reset().is_ok()); // after all this the data should be just an empty header let data = data_from_tempfile(c).unwrap(); assert_eq!(&data, &[0xD0, 0x50, 0x01, 0x00]); } } sudo-rs-0.2.2/src/system/wait.rs000064400000000000000000000163641046102023000146600ustar 00000000000000use std::io; use libc::{ c_int, WEXITSTATUS, WIFCONTINUED, WIFEXITED, WIFSIGNALED, WIFSTOPPED, WNOHANG, WSTOPSIG, WTERMSIG, WUNTRACED, __WALL, }; use crate::cutils::cerr; use crate::system::signal::signal_name; use crate::{system::interface::ProcessId, system::signal::SignalNumber}; mod sealed { pub(crate) trait Sealed {} impl Sealed for crate::system::interface::ProcessId {} } pub(crate) trait Wait: sealed::Sealed { /// Wait for a process to change state. /// /// Calling this function will block until a child specified by the given process ID has /// changed state. This can be configured further using [`WaitOptions`]. fn wait(self, options: WaitOptions) -> Result<(ProcessId, WaitStatus), WaitError>; } impl Wait for ProcessId { fn wait(self, options: WaitOptions) -> Result<(ProcessId, WaitStatus), WaitError> { let mut status: c_int = 0; let pid = cerr(unsafe { libc::waitpid(self, &mut status, options.flags) }) .map_err(WaitError::Io)?; if pid == 0 && options.flags & WNOHANG != 0 { return Err(WaitError::NotReady); } Ok((pid, WaitStatus { status })) } } /// Error values returned when [`Wait::wait`] fails. #[derive(Debug)] pub enum WaitError { // No children were in a waitable state. // // This is only returned if the [`WaitOptions::no_hang`] option is used. NotReady, // Regular I/O error. Io(io::Error), } /// Options to configure how [`Wait::wait`] waits for children. pub struct WaitOptions { flags: c_int, } impl WaitOptions { /// Only wait for terminated children. pub const fn new() -> Self { Self { flags: 0 } } /// Return immediately if no child has exited. pub const fn no_hang(mut self) -> Self { self.flags |= WNOHANG; self } /// Return immediately if a child has stopped. pub const fn untraced(mut self) -> Self { self.flags |= WUNTRACED; self } /// Wait for all children, regardless of being created using `clone` or not. pub const fn all(mut self) -> Self { self.flags |= __WALL; self } } /// The status of the waited child. pub struct WaitStatus { status: c_int, } impl std::fmt::Debug for WaitStatus { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(exit_status) = self.exit_status() { write!(f, "ExitStatus({exit_status})") } else if let Some(signal) = self.term_signal() { write!(f, "TermSignal({})", signal_name(signal)) } else if let Some(signal) = self.stop_signal() { write!(f, "StopSignal({})", signal_name(signal)) } else if self.did_continue() { write!(f, "Continued") } else { write!(f, "Unknown") } } } impl WaitStatus { /// Return `true` if the child terminated normally, i.e., by calling `exit`. pub const fn did_exit(&self) -> bool { WIFEXITED(self.status) } /// Return the exit status of the child if the child terminated normally. pub const fn exit_status(&self) -> Option { if self.did_exit() { Some(WEXITSTATUS(self.status)) } else { None } } /// Return `true` if the child process was terminated by a signal. pub const fn was_signaled(&self) -> bool { WIFSIGNALED(self.status) } /// Return the signal number which caused the child to terminate if the child was terminated by /// a signal. pub const fn term_signal(&self) -> Option { if self.was_signaled() { Some(WTERMSIG(self.status)) } else { None } } /// Return `true` if the child process was stopped by a signal. pub const fn was_stopped(&self) -> bool { WIFSTOPPED(self.status) } /// Return the signal number which caused the child to stop if the child was stopped by a /// signal. pub const fn stop_signal(&self) -> Option { if self.was_stopped() { Some(WSTOPSIG(self.status)) } else { None } } /// Return `true` if the child process was resumed by receiving `SIGCONT`. pub const fn did_continue(&self) -> bool { WIFCONTINUED(self.status) } } #[cfg(test)] mod tests { use libc::{SIGKILL, SIGSTOP}; use crate::system::{ interface::ProcessId, kill, wait::{Wait, WaitError, WaitOptions}, }; #[test] fn exit_status() { let command = std::process::Command::new("sh") .args(["-c", "sleep 0.1; exit 42"]) .spawn() .unwrap(); let command_pid = command.id() as ProcessId; let (pid, status) = command_pid.wait(WaitOptions::new()).unwrap(); assert_eq!(command_pid, pid); assert!(status.did_exit()); assert_eq!(status.exit_status(), Some(42)); assert!(!status.was_signaled()); assert!(status.term_signal().is_none()); assert!(!status.was_stopped()); assert!(status.stop_signal().is_none()); assert!(!status.did_continue()); // Waiting when there are no children should fail. let WaitError::Io(err) = command_pid.wait(WaitOptions::new()).unwrap_err() else { panic!("`WaitError::NotReady` should not happens if `WaitOptions::no_hang` was not called."); }; assert_eq!(err.raw_os_error(), Some(libc::ECHILD)); } #[test] fn signals() { let command = std::process::Command::new("sh") .args(["-c", "sleep 1; exit 42"]) .spawn() .unwrap(); let command_pid = command.id() as ProcessId; kill(command_pid, SIGSTOP).unwrap(); let (pid, status) = command_pid.wait(WaitOptions::new().untraced()).unwrap(); assert_eq!(command_pid, pid); assert_eq!(status.stop_signal(), Some(SIGSTOP)); kill(command_pid, SIGKILL).unwrap(); let (pid, status) = command_pid.wait(WaitOptions::new()).unwrap(); assert_eq!(command_pid, pid); assert!(status.was_signaled()); assert_eq!(status.term_signal(), Some(SIGKILL)); assert!(!status.did_exit()); assert!(status.exit_status().is_none()); assert!(!status.was_stopped()); assert!(status.stop_signal().is_none()); assert!(!status.did_continue()); } #[test] fn no_hang() { let command = std::process::Command::new("sh") .args(["-c", "sleep 0.1; exit 42"]) .spawn() .unwrap(); let command_pid = command.id() as ProcessId; let mut count = 0; let (pid, status) = loop { match command_pid.wait(WaitOptions::new().no_hang()) { Ok(ok) => break ok, Err(WaitError::NotReady) => count += 1, Err(WaitError::Io(err)) => panic!("{err}"), } }; assert_eq!(command_pid, pid); assert!(status.did_exit()); assert_eq!(status.exit_status(), Some(42)); assert!(count > 0); assert!(!status.was_signaled()); assert!(status.term_signal().is_none()); assert!(!status.was_stopped()); assert!(status.stop_signal().is_none()); assert!(!status.did_continue()); } } sudo-rs-0.2.2/src/visudo/cli.rs000064400000000000000000000154761046102023000144530ustar 00000000000000#[derive(Debug, PartialEq)] pub(crate) struct VisudoOptions { pub(crate) file: Option, pub(crate) includes: bool, pub(crate) quiet: bool, pub(crate) strict: bool, pub(crate) owner: bool, pub(crate) perms: bool, pub(crate) action: VisudoAction, } impl Default for VisudoOptions { fn default() -> Self { Self { file: None, includes: true, quiet: false, strict: false, owner: false, perms: false, action: VisudoAction::Run, } } } #[derive(Debug, PartialEq)] pub(crate) enum VisudoAction { Help, Version, Check, Run, } type OptionSetter = fn(&mut VisudoOptions, Option) -> Result<(), String>; struct VisudoOption { short: char, long: &'static str, takes_argument: bool, set: OptionSetter, } impl VisudoOptions { const VISUDO_OPTIONS: &'static [VisudoOption] = &[ VisudoOption { short: 'c', long: "check", takes_argument: false, set: |options, _| { options.action = VisudoAction::Check; Ok(()) }, }, VisudoOption { short: 'f', long: "file", takes_argument: true, set: |options, argument| { options.file = Some(argument.ok_or("option requires an argument -- 'f'")?); Ok(()) }, }, VisudoOption { short: 'h', long: "help", takes_argument: false, set: |options, _| { options.action = VisudoAction::Help; Ok(()) }, }, VisudoOption { short: 'I', long: "no-includes", takes_argument: false, set: |options, _| { options.includes = true; Ok(()) }, }, VisudoOption { short: 'q', long: "quiet", takes_argument: false, set: |options, _| { options.quiet = true; Ok(()) }, }, VisudoOption { short: 's', long: "strict", takes_argument: false, set: |options, _| { options.strict = true; Ok(()) }, }, VisudoOption { short: 'V', long: "version", takes_argument: false, set: |options, _| { options.action = VisudoAction::Version; Ok(()) }, }, VisudoOption { short: 'O', long: "owner", takes_argument: false, set: |options, _| { options.owner = true; Ok(()) }, }, VisudoOption { short: 'P', long: "perms", takes_argument: false, set: |options, _| { options.perms = true; Ok(()) }, }, ]; pub(crate) fn from_env() -> Result { let args = std::env::args().collect(); Self::parse_arguments(args) } /// parse su arguments into VisudoOptions struct pub(crate) fn parse_arguments(arguments: Vec) -> Result { let mut options: VisudoOptions = VisudoOptions::default(); let mut arg_iter = arguments.into_iter().skip(1); while let Some(arg) = arg_iter.next() { // if the argument starts with -- it must be a full length option name if arg.starts_with("--") { // parse assignments like '--file=/etc/sudoers' if arg.contains('=') { // convert assignment to normal tokens let (key, value) = arg.split_once('=').unwrap(); // lookup the option by name if let Some(option) = Self::VISUDO_OPTIONS.iter().find(|o| o.long == &key[2..]) { // the value is already present, when the option does not take any arguments this results in an error if option.takes_argument { (option.set)(&mut options, Some(value.to_string()))?; } else { Err(format!("'--{}' does not take any arguments", option.long))?; } } else { Err(format!("unrecognized option '{}'", arg))?; } // lookup the option } else if let Some(option) = Self::VISUDO_OPTIONS.iter().find(|o| o.long == &arg[2..]) { // try to parse an argument when the option needs an argument if option.takes_argument { let next_arg = arg_iter.next(); (option.set)(&mut options, next_arg)?; } else { (option.set)(&mut options, None)?; } } else { Err(format!("unrecognized option '{}'", arg))?; } } else if arg.starts_with('-') { // flags can be grouped, so we loop over the characters for (n, char) in arg.trim_start_matches('-').chars().enumerate() { // lookup the option if let Some(option) = Self::VISUDO_OPTIONS.iter().find(|o| o.short == char) { // try to parse an argument when one is necessary, either the rest of the current flag group or the next argument if option.takes_argument { let rest = arg[(n + 2)..].trim().to_string(); let next_arg = if rest.is_empty() { arg_iter.next() } else { Some(rest) }; (option.set)(&mut options, next_arg)?; // stop looping over flags if the current flag takes an argument break; } else { // parse flag without argument (option.set)(&mut options, None)?; } } else { Err(format!("unrecognized option '{}'", char))?; } } } else { // If the arg doesn't start with a `-` it must be a file argument. However `-f` // must take precedence if options.file.is_none() { options.file = Some(arg); } } } Ok(options) } } sudo-rs-0.2.2/src/visudo/help.rs000064400000000000000000000012511046102023000146160ustar 00000000000000pub(crate) const USAGE_MSG: &str = "usage: visudo [-chqsV] [[-f] sudoers ]"; const DESCRIPTOR: &str = "visudo - safely edit the sudoers file"; const HELP_MSG: &str = "Options: -c, --check check-only mode -f, --file=sudoers specify sudoers file location -h, --help display help message and exit -I, --no-includes do not edit include files -q, --quiet less verbose (quiet) syntax error messages -s, --strict strict syntax checking -V, --version display version information and exit "; pub(crate) fn long_help_message() -> String { format!("{USAGE_MSG}\n\n{DESCRIPTOR}\n\n{HELP_MSG}") } sudo-rs-0.2.2/src/visudo/mod.rs000064400000000000000000000213421046102023000144500ustar 00000000000000mod cli; mod help; use std::{ ffi::{CString, OsString}, fs::{File, Permissions}, io::{self, Read, Seek, Write}, os::unix::prelude::{MetadataExt, OsStringExt, PermissionsExt}, path::{Path, PathBuf}, process::Command, }; use crate::{ sudoers::Sudoers, system::{ can_execute, file::{Chown, FileLock}, signal::{consts::*, register_handlers, SignalStream}, User, }, }; use self::cli::{VisudoAction, VisudoOptions}; use self::help::{long_help_message, USAGE_MSG}; const VERSION: &str = env!("CARGO_PKG_VERSION"); macro_rules! io_msg { ($err:expr, $($tt:tt)*) => { io::Error::new($err.kind(), format!("{}: {}", format_args!($($tt)*), $err)) }; } pub fn main() { let options = match VisudoOptions::from_env() { Ok(options) => options, Err(error) => { println_ignore_io_error!("visudo: {error}\n{USAGE_MSG}"); std::process::exit(1); } }; let cmd = match options.action { VisudoAction::Help => { println_ignore_io_error!("{}", long_help_message()); std::process::exit(0); } VisudoAction::Version => { println_ignore_io_error!("visudo version {VERSION}"); std::process::exit(0); } VisudoAction::Check => check, VisudoAction::Run => run, }; match cmd(options.file.as_deref(), options.perms, options.owner) { Ok(()) => {} Err(error) => { eprintln_ignore_io_error!("visudo: {error}"); std::process::exit(1); } } } fn check(file_arg: Option<&str>, perms: bool, owner: bool) -> io::Result<()> { let sudoers_path = Path::new(file_arg.unwrap_or("/etc/sudoers")); let sudoers_file = File::open(sudoers_path) .map_err(|err| io_msg!(err, "unable to open {}", sudoers_path.display()))?; let metadata = sudoers_file.metadata()?; if file_arg.is_none() || perms { // For some reason, the MSB of the mode is on so we need to mask it. let mode = metadata.permissions().mode() & 0o777; if mode != 0o440 { return Err(io::Error::new( io::ErrorKind::Other, format!( "{}: bad permissions, should be mode 0440, but found {mode:04o}", sudoers_path.display() ), )); } } if file_arg.is_none() || owner { let owner = (metadata.uid(), metadata.gid()); if owner != (0, 0) { return Err(io::Error::new( io::ErrorKind::Other, format!( "{}: wrong owner (uid, gid) should be (0, 0), but found {owner:?}", sudoers_path.display() ), )); } } let (_sudoers, errors) = Sudoers::read(&sudoers_file, sudoers_path)?; if errors.is_empty() { writeln!(io::stdout(), "{}: parsed OK", sudoers_path.display())?; return Ok(()); } let mut stderr = io::stderr(); for crate::sudoers::Error { message, .. } in errors { writeln!(stderr, "syntax error: {message}")?; } Err(io::Error::new(io::ErrorKind::Other, "invalid sudoers file")) } fn run(file_arg: Option<&str>, perms: bool, owner: bool) -> io::Result<()> { let sudoers_path = Path::new(file_arg.unwrap_or("/etc/sudoers")); let (sudoers_file, existed) = if sudoers_path.exists() { let file = File::options().read(true).write(true).open(sudoers_path)?; (file, true) } else { // Create a sudoers file if it doesn't exist. let file = File::create(sudoers_path)?; // ogvisudo sets the permissions of the file so it can be read and written by the user and // read by the group if the `-f` argument was passed. if file_arg.is_some() { file.set_permissions(Permissions::from_mode(0o640))?; } (file, false) }; let lock = FileLock::exclusive(&sudoers_file, true).map_err(|err| { if err.kind() == io::ErrorKind::WouldBlock { io_msg!(err, "{} busy, try again later", sudoers_path.display()) } else { err } })?; if perms || file_arg.is_none() { sudoers_file.set_permissions(Permissions::from_mode(0o440))?; } if owner || file_arg.is_none() { sudoers_file.chown(User::real_uid(), User::real_gid())?; } let signal_stream = SignalStream::init()?; let handlers = register_handlers([SIGTERM, SIGHUP, SIGINT, SIGQUIT])?; let tmp_dir = create_temporary_dir()?; let tmp_path = tmp_dir.join("sudoers"); { let tmp_dir = tmp_dir.clone(); std::thread::spawn(|| -> io::Result<()> { signal_stream.recv()?; let _ = std::fs::remove_dir_all(tmp_dir); drop(handlers); std::process::exit(1) }); } let tmp_file = File::options() .read(true) .write(true) .create(true) .open(&tmp_path)?; tmp_file.set_permissions(Permissions::from_mode(0o700))?; let result = edit_sudoers_file( existed, sudoers_file, sudoers_path, lock, tmp_file, &tmp_path, ); std::fs::remove_dir_all(tmp_dir)?; result } fn edit_sudoers_file( existed: bool, mut sudoers_file: File, sudoers_path: &Path, lock: FileLock, mut tmp_file: File, tmp_path: &Path, ) -> io::Result<()> { let mut editor_path = None; let mut sudoers_contents = Vec::new(); if existed { // If the sudoers file existed, read its contents and write them into the temporary file. sudoers_file.read_to_end(&mut sudoers_contents)?; // Rewind the sudoers file so it can be written later. sudoers_file.rewind()?; // Write to the temporary file. tmp_file.write_all(&sudoers_contents)?; let (sudoers, errors) = Sudoers::read(sudoers_contents.as_slice(), sudoers_path)?; if errors.is_empty() { editor_path = sudoers.solve_editor_path(); } } let editor_path = match editor_path { Some(path) => path, None => editor_path_fallback()?, }; let mut stderr = io::stderr(); loop { Command::new(&editor_path) .arg("--") .arg(tmp_path) .spawn()? .wait_with_output()?; let (_sudoers, errors) = File::open(tmp_path) .and_then(|reader| Sudoers::read(reader, tmp_path)) .map_err(|err| { io_msg!( err, "unable to re-open temporary file ({}), {} unchanged", tmp_path.display(), sudoers_path.display() ) })?; if errors.is_empty() { break; } writeln!(stderr, "The provided sudoers file format is not recognized or contains syntax errors. Please review:\n")?; for crate::sudoers::Error { message, .. } in errors { writeln!(stderr, "syntax error: {message}")?; } writeln!(stderr)?; let stdin = io::stdin(); let stdout = io::stdout(); let mut stdin_handle = stdin.lock(); let mut stdout_handle = stdout.lock(); loop { stdout_handle .write_all("What now? e(x)it without saving / (e)dit again: ".as_bytes())?; stdout_handle.flush()?; let mut input = [0u8]; if let Err(err) = stdin_handle.read_exact(&mut input) { writeln!(stderr, "visudo: cannot read user input: {err}")?; return Ok(()); } match &input { b"e" => break, b"x" => return Ok(()), input => writeln!(stderr, "Invalid option: {:?}\n", std::str::from_utf8(input))?, } } } let tmp_contents = std::fs::read(tmp_path)?; // Only write to the sudoers file if the contents changed. if tmp_contents == sudoers_contents { writeln!(stderr, "visudo: {} unchanged", tmp_path.display())?; } else { sudoers_file.write_all(&tmp_contents)?; } lock.unlock()?; Ok(()) } fn editor_path_fallback() -> io::Result { let path = Path::new("/usr/bin/editor"); if can_execute(path) { return Ok(path.to_owned()); } Err(io::Error::new( io::ErrorKind::NotFound, "cannot find text editor", )) } fn create_temporary_dir() -> io::Result { let template = cstr!("/tmp/sudoers-XXXXXX").to_owned(); let ptr = unsafe { libc::mkdtemp(template.into_raw()) }; if ptr.is_null() { return Err(io::Error::last_os_error()); } let path = OsString::from_vec(unsafe { CString::from_raw(ptr) }.into_bytes()).into(); Ok(path) } sudo-rs-0.2.2/util/Dockerfile-release000064400000000000000000000001461046102023000156070ustar 00000000000000FROM rust:1-slim-bullseye RUN apt-get update -y && apt-get install -y clang libclang-dev libpam0g-dev sudo-rs-0.2.2/util/build-release.sh000075500000000000000000000066631046102023000152650ustar 00000000000000#!/usr/bin/env bash DATE="2023-09-21" SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) PROJECT_DIR=$(dirname "$SCRIPT_DIR") SUDO_RS_VERSION="$(cargo metadata --format-version 1 --manifest-path "$PROJECT_DIR/Cargo.toml" | jq '.packages[] | select(.name=="sudo-rs") | .version' -r)" BUILDER_IMAGE_TAG="sudo-rs-release-builder:latest" TARGET_DIR_BASE="$PROJECT_DIR/target/pkg" set -eo pipefail # Build binaries docker build --pull --tag "$BUILDER_IMAGE_TAG" --file "$SCRIPT_DIR/Dockerfile-release" "$SCRIPT_DIR" docker run --rm --user "$(id -u):$(id -g)" -v "$PROJECT_DIR:/build" -w "/build" "$BUILDER_IMAGE_TAG" cargo clean docker run --rm --user "$(id -u):$(id -g)" -v "$PROJECT_DIR:/build" -w "/build" "$BUILDER_IMAGE_TAG" cargo build --release # Generate man pages "$PROJECT_DIR/util/generate-docs.sh" # Set target directories and clear any previous builds target_dir_sudo="$TARGET_DIR_BASE/sudo" target_dir_su="$TARGET_DIR_BASE/su" target_sudo="$TARGET_DIR_BASE/sudo-$SUDO_RS_VERSION.tar.gz" target_su="$TARGET_DIR_BASE/su-$SUDO_RS_VERSION.tar.gz" rm -rf "$target_dir_sudo" rm -rf "$target_dir_su" rm -rf "$target_su" rm -rf "$target_sudo" # Show what is happening set -x # Build sudo mkdir -p "$target_dir_sudo/bin" mkdir -p "$target_dir_sudo/share/man/man8" cp "$PROJECT_DIR/target/release/sudo" "$target_dir_sudo/bin/sudo" cp "$PROJECT_DIR/target/release/visudo" "$target_dir_sudo/bin/visudo" cp "$PROJECT_DIR/target/docs/man/sudo.8" "$target_dir_sudo/share/man/man8/sudo.8" cp "$PROJECT_DIR/target/docs/man/visudo.8" "$target_dir_sudo/share/man/man8/visudo.8" mkdir -p "$target_dir_sudo/share/doc/sudo-rs/sudo" cp "$PROJECT_DIR/README.md" "$target_dir_sudo/share/doc/sudo-rs/sudo/README.md" cp "$PROJECT_DIR/CHANGELOG.md" "$target_dir_sudo/share/doc/sudo-rs/sudo/CHANGELOG.md" cp "$PROJECT_DIR/SECURITY.md" "$target_dir_sudo/share/doc/sudo-rs/sudo/SECURITY.md" cp "$PROJECT_DIR/COPYRIGHT" "$target_dir_sudo/share/doc/sudo-rs/sudo/COPYRIGHT" cp "$PROJECT_DIR/LICENSE-APACHE" "$target_dir_sudo/share/doc/sudo-rs/sudo/LICENSE-APACHE" cp "$PROJECT_DIR/LICENSE-MIT" "$target_dir_sudo/share/doc/sudo-rs/sudo/LICENSE-MIT" fakeroot -- < "$TARGET_DIR_BASE/SHA256SUMS") sudo-rs-0.2.2/util/generate-docs.sh000075500000000000000000000010021046102023000152460ustar 00000000000000#!/usr/bin/env bash docs_dir="docs/man" output_dir="target/docs/man" files=("sudo.8" "visudo.8" "su.1") mkdir -p "$output_dir" for f in "${files[@]}"; do origin_file="$docs_dir/$f.md" tmp_file="$output_dir/$f.md" target_file="$output_dir/$f" echo "Generating man page for $f from '$origin_file' to '$target_file'" sed '//s/--- -->/---/' > "$tmp_file" util/pandoc.sh -s -t man "$tmp_file" -o "$target_file" rm "$tmp_file" done sudo-rs-0.2.2/util/pandoc.sh000075500000000000000000000001501046102023000137750ustar 00000000000000#!/usr/bin/env bash exec docker run --rm -it -v "$(pwd):/data" -u "$(id -u):$(id -g)" pandoc/core "$@" sudo-rs-0.2.2/util/update-version.sh000075500000000000000000000016121046102023000155020ustar 00000000000000#!/usr/bin/env bash if [ "$#" -lt 1 ]; then echo "Missing new version" exit 1 fi SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) PROJECT_DIR=$(dirname "$SCRIPT_DIR") NEW_VERSION="$1" echo "Updating version in Cargo.toml" sed -i 's/^version\s*=\s*".*"/version = "'"$NEW_VERSION"'"/' "$PROJECT_DIR/Cargo.toml" echo "Updating version in man pages" sed -i 's/^title: SU(1) sudo-rs .*/title: SU(1) sudo-rs '"$NEW_VERSION"' | sudo-rs/' "$PROJECT_DIR"/docs/man/su.1.md sed -i 's/^title: SUDO(8) sudo-rs .*/title: SUDO(8) sudo-rs '"$NEW_VERSION"' | sudo-rs/' "$PROJECT_DIR"/docs/man/sudo.8.md sed -i 's/^title: VISUDO(8) sudo-rs .*/title: VISUDO(8) sudo-rs '"$NEW_VERSION"' | sudo-rs/' "$PROJECT_DIR"/docs/man/visudo.8.md echo "Rebuilding project" (cd $PROJECT_DIR && cargo build --release) echo "Version changes complete, you must still fill in the changelog entries"