zoxide-0.4.3/.cargo_vcs_info.json0000644000000001121370003522500124270ustar00{ "git": { "sha1": "a454f7cbbf7c5e84f0cc23e9dd0c3c668938d4f5" } } zoxide-0.4.3/.github/workflows/release.yml010066400017500001751000000073051367770446300170320ustar0000000000000000on: push: tags: - "v*" # push events to matching v*, i.e. v1.0, v20.15.10 jobs: build-linux: runs-on: ubuntu-latest strategy: matrix: target: ["x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "armv7-unknown-linux-musleabihf"] steps: - uses: actions/checkout@v2 - uses: actions-rs/cargo@v1 with: use-cross: true command: build args: --release --target ${{ matrix.target }} - uses: actions/upload-artifact@v2 with: name: "zoxide-${{ matrix.target }}" path: "target/${{ matrix.target }}/release/zoxide" build-darwin: runs-on: macos-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/cargo@v1 with: command: build args: --release --target x86_64-apple-darwin - uses: actions/upload-artifact@v2 with: name: "zoxide-x86_64-apple-darwin" path: "target/x86_64-apple-darwin/release/zoxide" build-windows: runs-on: windows-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/cargo@v1 with: command: build args: --release --target x86_64-pc-windows-msvc - uses: actions/upload-artifact@v2 with: name: "zoxide-x86_64-pc-windows-msvc" path: "target/x86_64-pc-windows-msvc/release/zoxide.exe" release-upload: needs: - build-linux - build-darwin - build-windows runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - id: create_release uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ github.ref }} release_name: Release ${{ github.ref }} - uses: actions/download-artifact@v2 - name: Display structure of downloaded files run: ls -lR - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: "zoxide-x86_64-unknown-linux-gnu/zoxide" asset_name: "zoxide-x86_64-unknown-linux-gnu" asset_content_type: application/octet-stream - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: "zoxide-x86_64-unknown-linux-musl/zoxide" asset_name: "zoxide-x86_64-unknown-linux-musl" asset_content_type: application/octet-stream - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: "zoxide-armv7-unknown-linux-musleabihf/zoxide" asset_name: "zoxide-armv7-unknown-linux-musleabihf" asset_content_type: application/octet-stream - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: "zoxide-x86_64-apple-darwin/zoxide" asset_name: "zoxide-x86_64-apple-darwin" asset_content_type: application/octet-stream - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: "zoxide-x86_64-pc-windows-msvc/zoxide.exe" asset_name: "zoxide-x86_64-pc-windows-msvc.exe" asset_content_type: application/octet-stream zoxide-0.4.3/.gitignore010066400017500001751000000036521366237774600132670ustar0000000000000000# Created by https://www.gitignore.io/api/rust # Edit at https://www.gitignore.io/?templates=rust ### Rust ### # Generated by Cargo # will have compiled files and executables /target/ # These are backup files generated by rustfmt **/*.rs.bk # End of https://www.gitignore.io/api/rust # Created by https://www.gitignore.io/api/python # Edit at https://www.gitignore.io/?templates=python ### Python ### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # Mr Developer .mr.developer.cfg .project .pydevproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # End of https://www.gitignore.io/api/python zoxide-0.4.3/CHANGELOG.md010066400017500001751000000110671370003473100130600ustar0000000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.4.3] - 2020-07-04 ### Fixed - Bug in Fish init script ## [0.4.2] - 2020-07-03 ### Added - `$_ZO_FZF_OPTS` to specify custom options for `fzf` - `zoxide query --list` to list all matches - `zoxide query --score` to show score along with result ### Changed - Increased default value of `$_ZO_MAXAGE` to `10000`. - `zri` is now a shell function. - Symlinks are treated as separate directories by default, this can be changed by setting `_ZO_RESOLVE_SYMLINKS=1`. ### Removed - Help menus for `z` and `zri`. ## [0.4.1] - 2020-05-25 ### Added - Support for PowerShell. ### Removed - Backward compatibility with `v0.2.x` databases. - Support for paths with invalid UTF-8. ## [0.4.0] - 2020-05-03 ### Added - Interactive mode for removing entries (`zoxide remove -i`). - Aliases for interactive `query` and `remove` (`zqi` and `zri` respectively). - PWD hooks for POSIX shells. ### Changed - `zoxide remove` now throws an error if there was no match in the database. - Interactive mode in `zoxide` no longer throws an error if `fzf` exits gracefully. - Canonicalize to regular paths instead of UNC paths on Windows. - `zoxide init` now uses PWD hooks by default for better performance. - `$_ZO_ECHO` now only works when set to `1`. - Using the `--z-cmd` flag now also renames the associated aliases. - The `--z-cmd` flag has been renamed to `--cmd`. - The `--no-define-aliases` flag has been renamed to `--no-aliases`. ### Fixed - `fish` no longer `cd`s to the user's home when no match is found. ## [0.3.1] - 2020-04-03 ### Added - Version output displays `git` revision information. - `--z-cmd` flag for `zoxide init` to rename the `z` command to something else. ### Changed - Query output no longer has the `query:` prefix, so `$(zq)` can now be used as an argument to commands. ### Fixed - Queries now also include checks for if the top level directory matches. ## [0.3.0] - 2020-03-30 ### Added - Automatic migration from `v0.2.x` databases. - `$_ZO_EXCLUDE_DIRS` to prevent certain directories from being added to the database. - Support for POSIX-compliant shells. ### Changed - Database location defaults to user's local data directory. - Database schema now includes a version number. - `migrate` subcommand renamed to `import`. ### Fixed - Achieve thread safety using unique temporary database file names for each `zoxide` instance. - Incomprehensive "could not allocate" message on database corruption. ## [0.2.2] - 2020-03-20 ### Fixed - Incorrect exit codes in `z` command on `fish`. ### Removed - File locks on database. ## [0.2.1] - 2020-03-16 ### Added - `$_ZO_ECHO` to echo match before `cd`ing. - Minimal `ranger` plugin. - PWD hook to only update the database when the current directory is changed. - Support for the `bash` shell. - `migrate` subcommand to allow users to migrate from `z`. ### Fixed - Interactive queries causing other open shells to hang. ## [0.2.0] - 2020-03-11 ### Added - `init` subcommand to remove dependency on shell plugin managers. - Support for `z -` command to go to previous directory. - `Cargo.lock` for more reproducible builds. - Support for the `fish` shell. ### Fixed - `_zoxide_precmd` overriding other precmd hooks on `zsh`. ## [0.1.1] - 2020-03-08 ### Added - Install script for Linux/macOS users. - Aging algorithm to remove stale entries. ### Changed - Database schema now uses `f64` values for rank instead of `i32`. ### Fixed - Multiple hooks being added upon initializing `zoxide` multiple times. ## [0.1.0] - 2020-03-05 ### Added - GitHub Actions pipeline to build and upload releases. - Support for the `zsh` shell. [0.4.3]: https://github.com/ajeetdsouza/zoxide/compare/v0.4.2...v0.4.3 [0.4.2]: https://github.com/ajeetdsouza/zoxide/compare/v0.4.1...v0.4.2 [0.4.1]: https://github.com/ajeetdsouza/zoxide/compare/v0.4.0...v0.4.1 [0.4.0]: https://github.com/ajeetdsouza/zoxide/compare/v0.3.1...v0.4.0 [0.3.1]: https://github.com/ajeetdsouza/zoxide/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/ajeetdsouza/zoxide/compare/v0.2.2...v0.3.0 [0.2.2]: https://github.com/ajeetdsouza/zoxide/compare/v0.2.1...v0.2.2 [0.2.1]: https://github.com/ajeetdsouza/zoxide/compare/v0.2.0...v0.2.1 [0.2.0]: https://github.com/ajeetdsouza/zoxide/compare/v0.1.1...v0.2.0 [0.1.1]: https://github.com/ajeetdsouza/zoxide/compare/v0.1.0...v0.1.1 [0.1.0]: https://github.com/ajeetdsouza/zoxide/commits/v0.1.0 zoxide-0.4.3/Cargo.lock0000644000000530061370003522500104140ustar00# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "anyhow" version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayref" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "base64" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bincode" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blake2b_simd" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clap" version = "2.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "constant_time_eq" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crossbeam-utils" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "dirs" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "dirs-sys 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "dirs-sys" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "dunce" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "float-ord" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "getrandom" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "heck" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hermit-abi" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ppv-lite86" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-error" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro-error-attr" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro2" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "redox_users" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rust-argon2" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "structopt-derive 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn-mid" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-segmentation" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-width" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "uuid" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "version_check" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "zoxide" version = "0.4.3" dependencies = [ "anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "dunce 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum anyhow 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" "checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum bincode 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum dirs 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2fddc3610d8f9552384e06ebc87f714e1d0b2b64a99194d2faf36d7ae5f48549" "checksum dirs-sys 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" "checksum dunce 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2641c4a7c0c4101df53ea572bffdc561c146f6c2eb09e4df02bc4811e3feeb4" "checksum float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" "checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" "checksum proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880" "checksum proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50" "checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" "checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" "checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" "checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "de2f5e239ee807089b62adce73e48c625e0ed80df02c7ab3f068f5db5281065c" "checksum structopt-derive 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "510413f9de616762a4fbeab62509bf15c729603b72d7cd71280fbca431b1c118" "checksum syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" "checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" "checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" "checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" "checksum uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" "checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" "checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" "checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" zoxide-0.4.3/Cargo.toml0000644000000024151370003522500104350ustar00# 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 believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "zoxide" version = "0.4.3" authors = ["Ajeet D'Souza <98ajeet@gmail.com>"] description = "A faster way to navigate your filesystem" keywords = ["cli"] categories = ["command-line-utilities", "filesystem"] license = "MIT" repository = "https://github.com/ajeetdsouza/zoxide/" [profile.release] lto = true codegen-units = 1 [dependencies.anyhow] version = "1.0.28" [dependencies.bincode] version = "1.2.1" [dependencies.clap] version = "2.33.0" [dependencies.dirs] version = "3.0.0" [dependencies.dunce] version = "1.0.0" [dependencies.float-ord] version = "0.2.0" [dependencies.serde] version = "1.0.106" features = ["derive"] [dependencies.structopt] version = "0.3.12" [dependencies.uuid] version = "0.8.1" features = ["v4"] zoxide-0.4.3/Cargo.toml.orig010066400017500001751000000012731370003473100141340ustar0000000000000000[package] name = "zoxide" version = "0.4.3" authors = ["Ajeet D'Souza <98ajeet@gmail.com>"] description = "A faster way to navigate your filesystem" repository = "https://github.com/ajeetdsouza/zoxide/" edition = "2018" keywords = ["cli"] categories = ["command-line-utilities", "filesystem"] license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] anyhow = "1.0.28" bincode = "1.2.1" clap = "2.33.0" dirs = "3.0.0" dunce = "1.0.0" float-ord = "0.2.0" serde = { version = "1.0.106", features = ["derive"] } structopt = "0.3.12" uuid = { version = "0.8.1", features = ["v4"] } [profile.release] codegen-units = 1 lto = true zoxide-0.4.3/LICENSE010066400017500001751000000020351366237774600122760ustar0000000000000000Copyright 2020 Ajeet D'Souza 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. zoxide-0.4.3/README.md010066400017500001751000000145261367755154700125570ustar0000000000000000# zoxide [![crates.io](https://img.shields.io/crates/v/zoxide)](https://crates.io/crates/zoxide) ![.github/workflows/release.yml](https://github.com/ajeetdsouza/zoxide/workflows/.github/workflows/release.yml/badge.svg) A faster way to navigate your filesystem ## Table of contents - [Introduction](#introduction) - [Examples](#examples) - [Getting started](#getting-started) - [Installing `zoxide`](#step-1-installing-zoxide) - [Installing `fzf` (optional)](#step-2-installing-fzf-optional) - [Adding `zoxide` to your shell](#step-3-adding-zoxide-to-your-shell) - [bash](#bash) - [fish](#fish) - [POSIX](#posix-shells) - [PowerShell](#powershell) - [zsh](#zsh) - [Configuration](#configuration) - [`init` flags](#init-flags) - [Environment variables](#environment-variables) ## Introduction `zoxide` is a blazing fast alternative to `cd`, inspired by [`z`](https://github.com/rupa/z) and [`z.lua`](https://github.com/skywind3000/z.lua). It keeps track of the directories you use most frequently, and uses a ranking algorithm to navigate to the best match. ![demo](./demo.gif) ## Examples ```sh z foo # cd to highest ranked directory matching foo z foo bar # cd to highest ranked directory matching foo and bar z foo/ # can also cd into actual directories zi foo # cd with interactive selection using fzf zq foo # echo the best match, don't cd za /foo # add /foo to the database zr /foo # remove /foo from the database ``` ## Getting started ### Step 1: Installing `zoxide` #### On Arch Linux [![Arch Linux](https://repology.org/badge/version-for-repo/aur/zoxide.svg?header=aur)](https://aur.archlinux.org/packages/zoxide) ```sh yay -S zoxide ``` #### On CentOS ```sh dnf copr enable atim/zoxide dnf install zoxide ``` #### On Fedora 32+ [![Fedora](https://repology.org/badge/version-for-repo/fedora_rawhide/zoxide.svg?header=fedora)](https://src.fedoraproject.org/rpms/rust-zoxide) ```sh dnf install zoxide ``` #### On FreeBSD [![FreeBSD](https://repology.org/badge/version-for-repo/freebsd/zoxide.svg?header=freebsd)](https://www.freshports.org/sysutils/zoxide/) ```sh pkg install zoxide ``` #### On macOS / Linux (via Homebrew / Linuxbrew) [![Homebrew](https://repology.org/badge/version-for-repo/homebrew/zoxide.svg?header=homebrew)](https://formulae.brew.sh/formula/zoxide) ```sh brew install zoxide ``` #### On macOS (via MacPorts) [![MacPorts](https://repology.org/badge/version-for-repo/macports/zoxide.svg?header=macports)](https://ports.macports.org/port/zoxide/summary) ```sh port install zoxide ``` #### On NixOS [![nixpkgs unstable](https://repology.org/badge/version-for-repo/nix_unstable/zoxide.svg?header=nixpkgs%20unstable)](https://nixos.org/nixos/packages.html?attr=zoxide&channel=nixpkgs-unstable) ```sh nix-env -iA nixpkgs.zoxide ``` #### Other (via Cargo) [![crates.io package](https://repology.org/badge/version-for-repo/crates_io/zoxide.svg?header=crates.io)](https://crates.io/crates/zoxide) ```sh cargo install zoxide -f ``` #### Other (via precompiled binary) [![GitHub releases](https://img.shields.io/github/v/release/ajeetdsouza/zoxide?color=blue&label=github%20releases&sort=semver)](https://github.com/ajeetdsouza/zoxide/releases) Use the installation script: ```sh curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/ajeetdsouza/zoxide/master/install.sh | sh ``` Alternatively, you can also download a precompiled binary from the [releases](https://github.com/ajeetdsouza/zoxide/releases) page and add it to your `PATH`. ### Step 2: Installing `fzf` (optional) If you want to use interactive fuzzy selection, you will also need to install [`fzf`](https://github.com/junegunn/fzf#installation). ### Step 3: Adding `zoxide` to your shell If you currently use `z`, `z.lua`, or `zsh-z`, you may want to first import your existing database into `zoxide`: ```sh zoxide import /path/to/db ``` #### bash Add the following line to your `~/.bashrc`: ```sh eval "$(zoxide init bash)" ``` #### fish Add the following line to your `~/.config/fish/config.fish`: ```sh zoxide init fish | source ``` #### POSIX shells Add the following line to your shell's configuration file: ```sh eval "$(zoxide init posix --hook prompt)" ``` The `prompt` hook is recommended for POSIX shells because the default `pwd` hook creates a temporary file for every session, which are only deleted upon reboot. If you do want to use `pwd` hooks instead, you may want to set up traps to perform a cleanup once the shell exits: ```sh trap '_zoxide_cleanup' EXIT HUP KILL TERM trap '_zoxide_cleanup; trap - INT; kill -s INT "$$"' INT trap '_zoxide_cleanup; trap - QUIT; kill -s QUIT "$$"' QUIT ``` NOTE: If you modify your `PS1` at any point, you may need to re-run the above command. This is due to the fact that the hook is stored in `PS1`, in order to be evaluated every time the prompt is displayed. #### PowerShell Add the following line to your profile: ```powershell Invoke-Expression (& { $hook = if ($PSVersionTable.PSVersion.Major -lt 6) { 'prompt' } else { 'pwd' } (zoxide init --hook $hook powershell) -join "`n" }) ``` #### zsh Add the following line to your `~/.zshrc`: ```sh eval "$(zoxide init zsh)" ``` ## Configuration ### `init` flags - `--cmd`: change the `z` command (and corresponding aliases) to something else - `--hook `: change the event that adds a new entry to the database (default: `pwd`) - `none`: never add entries (this will make `zoxide` useless unless you manually configure a hook) - `prompt`: add an entry at every prompt - `pwd`: add an entry whenever the current directory is changed - `--no-aliases`: don't define extra aliases like `zi`, `zq`, `za`, and `zr` ### Environment variables - `$_ZO_DATA_DIR`: directory where `zoxide` will store its data files (default: platform-specific; see the [`dirs` documentation] for more information) - `$_ZO_ECHO`: when set to `1`, `z` will print the matched directory before navigating to it - `$_ZO_EXCLUDE_DIRS`: list of directories separated by platform-specific characters ("`:`" on Linux/macOS, "`;`" on Windows) to be excluded from the database - `$_ZO_FZF_OPTS`: custom flags to pass to `fzf` - `$_ZO_MAXAGE`: sets the maximum total age after which entries start getting deleted - `$_ZO_RESOLVE_SYMLINKS`: when set to `1`, `z add` will resolve symlinks. [`dirs` documentation]: https://docs.rs/dirs/latest/dirs/fn.data_local_dir.html zoxide-0.4.3/build.rs010066400017500001751000000007241366237774600127410ustar0000000000000000fn main() { let git_describe = std::process::Command::new("git") .args(&["describe", "--tags", "--broken"]) .output() .ok() .and_then(|proc| String::from_utf8(proc.stdout).ok()); let version_info = match git_describe { Some(description) if !description.is_empty() => description, _ => format!("v{}-unknown", env!("CARGO_PKG_VERSION")), }; println!("cargo:rustc-env=ZOXIDE_VERSION={}", version_info); } zoxide-0.4.3/demo.gif010066400017500001751000003616501367571035500127060ustar0000000000000000GIF89aa 1$/ F85C %pA&d,#Z #> *y 8w  $G 1Z (J E,PA .!3P.L+B6Y!  $-CUU]7U ! #1q#@]$ .$4J$B%Z& ?&='! *I_+" +g, ,?Q,J`-K`0000023,3N`44+|78EV8L]9 ;-;j<<=% =Vb??{@QA8/ABBT`EN\EEFQFvG/G5GHD?HJU`LpM6MtN@*NWbN[jNrOPROV`O{PMEPT\QW`RG0RN8RRARSVVSTT@TUJTXaTXbTXbT`jUdlVXbWXbXsmXZ[L\&\]\^Za^r__`aaac0c1dffg; ghhiL+m6mneoropibq]rS rtsuvjwx- xDy{ezM!z{@"|}n}~~nNLst_3gf0fɈUU viET *y 8w  $G 1Z (J E,PA .!3P.L+B6Y!  $-CUU]7U ! #1q#@]$ .$4J$B%Z& ?&='! *I_+" +g, ,?Q,J`-K`0000023,3N`44+|78EV8L]9 ;-;j<<=% =Vb??{@QA8/ABBT`EN\EEFQFvG/G5GHD?HJU`LpM6MtN@*NWbN[jNrOPROV`O{PMEPT\QW`RG0RN8RRARSVVSTT@TUJTXaTXbTXbT`jUdlVXbWXbXsmXZ[L\&\]\^Za^r__`aaac0c1dffg; ghhiL+m6mneoropibq]rS rtsuvjwx- xDy{ezM!z{@"|}n}~~nNLst_3gf0fɈUU viETw~vxpN̼ unX&[{d-VȦfأ"ݸ(k\t'-V(?Suچv &@ fF- '&d+J;sprX\ IBL"F:򑐌$'IJZ̤&7Nz (GIRL*WV򕰌,gIZ̥.w^ 0Ib1 ! ,! /H0La… !>tXPbE-fؐA=jɓ! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,!@H@*\ȰÄ"J '3jD8QbECؑŋ#Sj,i2 8"y:&hSB37s䩔!K2H: HԴcT>|1ኛ4K0ʝ9]<| ;gISYH9=;GQ R* 2``jTA@5cȨ@>*C>I ;)M'huޥw)@((:a2Xz8BڹX2A"c9bp'|:#qařwxdWG e0ԗP`VS@$q pmDy= aD҆%!F7*I䣎0/J! ,YdH@ ,80!… XPB %R$hQ$a,<(p 2XÝ#r.1)IQLF$I BŘĀ! ,ab DxP@ qF؁ dJ-!(@ai"@A4m hϟ  Q`8:8b@! ,`! ,h\ DxP@_(#L/ 91bKxsϛ|V8!ּNu PA}:TgS! ,o< DxP@_8D(F&.2tX"I'MDrʆ/ D! ,ujH@ ,80!… XPB %R$hQ7.cQGDTHc17#¼84ڰbiLArOO@чKK@@Fps'FZh1 ! ,}_ DxP@C)Z,!p>ܹs"C}4F+9242G 5h+sh"@0o0,u`r;NT&xD jTp⊚6ntL 0B;.,U +JYq"dzb@! ,` DxP@:&LdXbƍ7Ç8É9%E5|L:a,`B7i$ ȆF! ,nH@ ,80!… XPB %R$h1 WܤY n#dP3WԴqSS3e00afS4a+i pkD! ,`! ,_ DxP@ 8QcAwbb8x3ƤDq$#39|6xp1YG7i`0#æL ! , )\@.t(A )!E 1j1+n,`5mYqę1X %8!;c ?c@Ɵv˕`oV2pB"M-9:A<#2UX1~MPF)-M{|bzHV"7:#diY וy)atij6צX WO)蠄zG8)#)h]F*k zS@! ,`! ,`! ,`! ,`! ,`! , H(\Ç#JHŋ3jȱǏ CIɓ(S~dP˗0cʜI͛8sIB@ JѣHPӧPJJQVjʵׯW}KٳhbM˶۷p\+ݻx߿+È?$ǐ2LN'c̹g?MtЦS^5װcW]D۶qp .S<ȓ+_s܌7س{ߟM%{k_Ͼ=BԀ|x*?Lܽ}!)'wB(ᄬ Hr)s 6ARh≝Yxar*cK~[">XP(樣c*(K08mL6W顉-{Ȳ04[3SL%m4҆Jl%@ >.Wr2`}??Yۙ$案0$IJxDŽ1I#%]($͔/%NM! ,`! ,/ ^H@ ,80!…  ;GJhFxhPbȑK D,Q~Lxҥɘw#&J.̙Ra·NBu2 ! ,`! ,` bH@ ,80!…  ;GJhFxhPbȑK D,Q~Lxҥɘwa@! ,g AH@ ,80!… XPB %R$hqcF j($Ɏ'5bxQb Q9d̈́! ,n fH@ ,80!… XPB %R$hQatб;xRrAMCJx &0p'|r'͑Q#F! ,`! ,`! ,v Y DxP@(bB r' <O#ESI<<ۍ!2DEw PBC&nO?O1Jm©jiƌ2pr-9x(1ja9zs,-}\W#愉Uz¥IȨ.xvYmT pf-Q紋`1D$ρ#)fn֫:! ,`! ,`! ,"0[ DxP@(bB0YY# ud"Cd5zHOh2T m*?RĸTŀ! ,`! ,)0b DxP@(bBL` Y1 C'zx0`I-Hha#3]Zthj"PGYB>@Ќ 褈b@! ,`! ,00= DxP@(bB`Qq$&rL9QdH,["1 ! ,70= DxP@(bB+RĸQaX2!'v$I51 ! ,>0X DxP@%CHx BQG ;"$bB%]|!r4 rԑ)0@F+U2 ! ,`! ,`! ,0 H*\8ÇJHŋ3jȱǏ CIɓ(S ʗ0cʜI͛8sC@ JѣHQӧPJJQVjʵׯW}KٳhbM˶۷p\+ݻx߿+È+$ǐ2LN'c̹畚?M4ЦS^5װc\D۶qp .S<ȓ+_s܌`7س{ߟM%ю{k_Ͼ=BԀ|x*+Lܽ}!)'wB(ᄬ Hr)s 6ARh≝Yxar*cK~[">XP(樣c*(K08mL6W顉-{Ȳ04[3SL%m4҆Jl%@ >.Wr2`}??Yۙ$案0$IJXP(樣c*(K08mL6W顉-{Ȳ04[3SL%m4҆Jl%@ >.Wr2`}??Yۙ$案0$IJxDŽ1I#%]($͔/%NM! ,`! ,/P^H@ ,80!…  ;GJhFxhPbȑK D,Q~LxҥɘwpŒ$I! ,`! ,ZP )\@.t(A )< )"ƑA⊚4K0Tbϝp1 y$0l^u`x8k篫M%ю݋O>AԠ/}z*P|g!)B"ᆮ)t)!uV(Ar⋝yat!*cK&\*^XP0)c2Έ(K8긣oTVW顉-{Ȳ0T\3SL%o<Rgt%@ F"._r`??<ۛ,Y磐u8$IJQk$.+;ӝRW"@ܺI;]@! ,`! ,`! ,`! ,`! ,`! ,"`[ DxP@(bB0YY# ud"Cd5zHOh2T m*?RĸTŀ! ,)`4 DxP@(bB+RĸQaF 5PdI QFT. ! ,`! ,0`] DxP@H!Tl<N1(|J^ k+M@-f˗6DQ Ӡpx1#(P"R! ,`! ,7`^ DxP@(b->@6K,s V,Ƙ,֠@,^ V&LHDiG @hFO! ,=`pH@ ,80!… XPB %R$hD]UM#g@KD%1Ũf-$`a6 3 mn,A7-! ,`! ,/`NH*pÇ I"ą -j8D1&IҡG% ;uU,ELvR .vaqeŜ9ȦZؑ:)*\PT1 `2W*R چAoR%]GZ Uw '9x[a ^~I`CjXw#Ӷp 1CnVSk2FhH!0 Īgxp3 9#J<9A0wc) mZ ku&no_E4):PR5aN`}h# } P17X`Y`px9bQ!LE㴇% .6H(W_} T>I3)9݌&Ĺ&qs"h;, <XLsoiAOiD'~/}"ӊ"b#SL:#O3>s)pSI<<3H:>,M?OM>>d܊+G^I0䣩C<ă($ =󭲪 yψ'>tG㘗2' 9F &<?hVRuJm;.Un"s^|G>z'l0I'k_?]kW-뇱*QO9 TQ#)܇UW`zخe͞Ml8W¥*w.Ժv͋t/_~ ,'8#xƎ]! ,~Hpࢂ*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜIE8sܹp@IѣH*]ʴ;xJJ*ϫ<ePhЦ`ÊKٳdSm[psRIWh˷߿ lPԸq(P#KL2Hn W#ʔTp,Z\Wc˨S^Z/fT Kf-XEft ^5lٲ}7OݻKMح?0e0w\'iԳ_Ͼ adke YL_bc#;A"Cw{ 65 Pw% ~NO?O1`o B,ȑf0- '2Fœ+J;st'蕋H&cU,-}#i)2`a{|b~V'"Erydp)jc~jDEn 5矀W'NX ]] 裐&%aU#)hv)KPJU@! ,`! ,`! ,"[ DxP@(bB0YY# ud"Cd5zHOh2T m*?RĸTŀ! ,`! ,)4 DxP@(bB+RĸQaF 5PdI QFT. ! ,`! ,`! ,0] DxP@H!Tl<N1(|J^ k+M@-f˗6DQ Ӡpx1#(P"R! ,`! ,7 )\@.t(A )!E 1>QdBհYPڲ8-X"!%ƘH "zЁP(;^ Ve oJ:x&Nz:д#)Wp Ul0% qC! ,`! ,/NH*pÇ I"ą -j8D1&IҡG% d2o䴝;sEXZ\R`X@V@4\TVT* چAoRHMaYI00H˛9*{VRK `wR!E`)Xnd.a Sb"@b݈LDUpq+x)HVf J!u % ܺ!ȉD*L Ch!@p﮵ʖ u]$^tj3^y4؄BJX<@UZ;՜cc8&p]v @&^qGYg_u(7:17e"O>T>">c'*C>?Ҭ(iBj*Knsj+oMB&!2brO1c#0FH7t>}1I$3=Oŋrg+C(&{& q 3K/'%Fx(\iSwB#]1bm {NȌ^'l\&?HA~zL2 rC+S"{ۑ(o\q2$G:N6sBgG?d<{|bΓNԦ:as &b׌xjX0R--`>Α2]Yp\3яDz['~6SNq;a=Cva(C\)͆ ▦, !9SI<xDŽ1I#%]($͔/%NM! ,`! ,/^H@ ,80!…  ;GJhFxhPbȑK D,Q~Lxҥɘw#&J.̙Ra·NBu2 ! ,`! ,`bH@ ,80!…  ;GJhFxhPbȑK D,Q~Lxҥɘwa@! ,gAH@ ,80!… XPB %R$hqcF j($Ɏ'5bxQb Q9d̈́! ,nfH@ ,80!… XPB %R$hQatб;xRrAMCJx &0p'|r'͑Q#F! ,vY DxP@(bB r' <O#EYBS P㤣'|(ґ+nL1AVb! ,8 DxP@(bB+R1G>pŒ$I! ,a DxP@(bBl& =玓 @ȠfE'i%a```&fۤ9I`+6Uh1 ! ,qH@ ,80!… XPB %R$h1A H´I㤣'xqb n``F]TّA*m:L ĕ6WM1%v<`AdAǂZ ! , )\@.t(A )$ 5&D1 ኛ4K0l xC󎓙5o&@ԌIM 1>*q2X #kfhQ)`6iE9ST:k Nc@! ,T DxP@(bB r'  <O#!+Â04!Piŝ1}R8TŊ! ,`! ,`! ,`! , H*\ȰÇ#Jŋ(jȱǏ CIɓ(S\ɲI]ʜI͛8sɳgO} JѣH*]hFPJJի2bʵׯ`*ٳhӪJv۷pʝ+1Pxꃻ} Lpʿ0 +^̸1>Lec^̹碙~MimO^ͺԮc˞m6۸[.ͻތ84 Gxȓ+_)УKoFYr04^|5 gyhB˟O j돮^=E)qh rt{b tG"Ѐfak .(!$cJyxDh݄xbgzBb&b@X20Ǎ9[(TE~zhb,3L!֌>SI<<ێ!2DU)r PBG&(ȟoO?O1Nqgiƍ2pBs-9(A^It,a-}#慍RMȩ "%ynT0۬qvO絋`1Ddӑ#) n{J! ,`! ,`! ,`! ,"[ DxP@(bB0YY# ud"Cd5zHOh2T m*?RĸTŀ! ,`! ,)b DxP@(bBL` Y1 C'zx0`I-Hha#3]Zthj"PGYB>@Ќ 褈b@! ,`! ,0= DxP@(bB`Qq$&rL9QdH,["1 ! ,`! ,7= DxP@(bB+RĸQaX2!'v$I51 ! ,>X DxP@%CHx BQG ;"$bB%]|!r4 rԑ)0@F+U2 ! ,`! ,`! ,`! ,`! ,`! ,`! ,PH*\8ÇJHŋ3jƏ CI`G%S\rɈ-cʜI3˚8sxsϟ@ J(͞F*u9tӧBJԪX^֮`~ KزhkM˶۷pʝkKI*iR֔Kd z%pb)*b ra 8xdhg< 58F V % "[lBa$cj l a"jy39tG7@U3L}LմQ@8q %Y,%e]wnu@ U Du Bt&&Hp^5&P)h" )n `!e݀E@"2Xl\@L0`M ҈%b1Pf4䁉AE.%`#)fy4 gWBޝ57P2%g ~U'm&. 5xHKڼ'tB(UKЁ70h,>0` 6`Pmp&@,T&yWbfz&IPYh) l@ZWBJ" 0ƗY_: \'Ll \n(Jh. +Ջ&`hbF3ET4/~,A=hWB-6$6AsY "H0*4&kiͪi26є0=y-kwՑ-Iچ+07 # `^x[7vv|N\[$j pv{PKWl3ǵ2$) A-P%qo/j/ooW^^TL F]EL?H#od'tYfL"FPT#pBd?42MGOd R[bA V'7Oc(9Aƕ p;U3=|Q'?o4@5\A xP"p0 mdLL ֐d:VWROP<6 [UZbg ׳ʬxv g(V#% i:c֤?xSղƋMkQC-3 Ut iRܤWN{Ok gu٘VY kۜ u[FϿpͶ=r@喃lsZ\Jw|wuK@h1(0fcr1zùAu! >umzYx =1lދ%x"Q/r<yĈW+C&FةxSirL*[qY^A &rHdxB9!ӟČO2 f4#uTFJ!!GNsA&5LNNE7_hFRرawp=9tȇ>=ƖrƉCP8CJAtA j[e$]D5㘀jѱBl>J>REՎW' )}Dj(q$aI}%IrE(9(Rʻ`D;m'%|91qƛj*>O<%@ sf =i&N")6ɴMLa>')ruٝff1Q믢/}~y`ϙS E(`A(HtaiXTֳґNRJ/q¨LU7©tJTcM'gmt ǀU®R 뾨 0bUseYG e*y=+\X˭fk[4OL\cpF HC$EW1ίzY{"ײ,6krVhfئu)kʪe;n?[(.%ú6KS0_OsW*]˖`_u_5yA^`E9^^i-#8gBrK" `Ǡ e] ء ^x99 :=c;#b5BbX"'1)b bC1c:vx㓇z=|؇H8rQnhHX`qXщH! , H`A *\0ÇJHŋ3jȱǏ CIɓ(S\ɲˑIMsd%F_ JѣH*]ʴS2IΫ$qç`ÊKٳhbAMշ5bhE˷߿d=Lє{ʢ\)L˘3k&IذMCNǏNװcF3Ml.m ԑMa׶0e dÓkνdke 4L_b{T@DC{οZ$@ 9.qRX\??T7~vr%[UzL28AC+sNNa!P<5}2aU4v_~iPF)%K?hآޑeM8difEUez] DaBttc̱&CЕv* Mm H eG裐Fښ! ,`! ,`! ,`! ,`! , H(\Ç#JHŋ3jȱǏ CIɓ(S~dP˗0cʜI͛8sIB@ JѣHPӧPJJQVjʵׯW}KٳhbM˶۷p\+ݻx߿+È?$ǐ2LN'c̹g?MtЦS^5װcW]D۶qp .S<ȓ+_s܌7س{ߟM%{k_Ͼ=BԀ|x*?Lܽ}!)'wB(ᄬ Hr)s 6ARh≝Yxar*cK~[">XP(樣c*(K08mL6W顉-{Ȳ04[3SL%m4҆Jl%@ >.Wr2`}??Yۙ$案0$IJxDŽ1I#%]($͔/%NM! ,`! ,/qH@ ,80!… XPB %R$h1A0c H8&X1 ;=29J.()@F+!k``eN lhƨ%̤j0Z ! ,`! ,`! ,6H@[0"l!D).XB zbD$p$L%X).)OhFr Q&Qy0@M#Q.aV §?xj^bH06lv50@/ib! ,E: DxP@(bB`Qaƍ ;#HdXɆ/ ! ,L )\@.t(A )!E 1jWԤYa7+1tT <|YBS P㤣'|(ґ+nL1AVb! ,`! ,` DxP@(bBL@ CrNy|%D)@((ƉEOs JWܤb"#FOV! ,8 DxP@(bB+R1G>pŒ$I! ,`! ,`! ,gH@ ,80!… XPB~1D7v`<|Cɓ,?bѣC4G$N,  eLH&LH TS! ,[ DxP@ E9S>:#ĥ! ,T DxP@(bBT@rΜ.QO2 C9=B2CPDMPh"E! ,hH@ ,80!… XPB %R$h1>¤邡c$xR1. HWv41%5b4(cǩ! ,V DxP@(bBT@rΜ.2MȘS$ ac!D4m20CVȰ"EGZ ! ,dH@ ,80!… H@ %RѠF&ϝ#!&$JAdʇ3k0.`L7<*pfΔ  Ā! ,eH@ ,80!… XPB %R$hQatб;xRrAMCJx &q'1|r'͑ jD! ,$iH@ ,80!… XPB %R$h1A HԴc"xRQ;/p` >YBS P㤣'|(ґ+nL1AVb! ,,8 DxP@(bB+R1G>pŒ$I! ,`! ,`! ,2H@[0"l!D).|XG6_^`xR1R@@PC$lH7* rgN;y4eH ,@d)@ZŊbDa^5eFb(V!\O}KbAvBR`$! ,@gH@ ,80!… XPB %R$h1H¤Yc'n" f``` 0@tANGOò#"I:85F%! ,GdH@ ,80!… XPB %R$h1A+n\I# 7xRc1 8*8A6"p`Kl 5y4R B1ŀ! ,O; DxP@(bB`hb#CThq$!\H1eDIB ! ,`! ,Va DxP@(bBl& =玓 @ȠfE'i%a```&fۤ9I`+6Uh1 ! ,]S DxP@(bB r'  <O#!+Â04!͜ `8aE! ,`! ,cqH@ ,80!… XPB %R$h1A0c H8&XQ ;=29J.()@F+!k``eN lhƨ%̤j0Z ! ,iq$@ ph„ |pD%N|!q~@pA dAK4$@fD7` '6lhA!͕)IAy.pAI AE b ! ,`! ,o@ [0B"l!ăP\7"fPG"%1$7"T򤍚4K0p#L.V La¤邡c$xRbD3c0LHb*SֱM2:L`ȝ;x8;i0- Ԉ1! ,`! ,`! ,X DxP@(07&2x1#pXĨh0e<12?J)JxsfD<&%1 ! ,`! ,`! , H*\ȰÇ#JHŋ3jܸǏ8Iɓ(S\ɲ˗0c<̛8sɳϟ@άQѣH*]ʴSDC>JիXj}uׯ`ÊKbײhӪ]˶ͳnʝK\v˷P~ LpE+^8/Ɛ#K|1˘3k~KtϠC,ӢI^ͺbծ/Mڌ84 ǻw )ȓ+W~mFYr0{E gwhB꼳_Ϟ jO.^<Eݾ1r{b rG"~E(al!$cJwx$܂ wh"hZabD8Y*0Nj1X[ݨL |zhb,3L!֌>SI<  IY 0 ! ,`! ,5 $@ [0@"l!ăP\(0Ō7vq!41j,aHP@L(mNLp-X"ڒ!) @6%(D :P Ӡ$ɴJWަVOB u*KG\”V2Y0Gt "FIB! ,`! ,`! ,`! ,  H*\8ÇJHŋ3jȱǏ CIɓ(S ʗ0cʜI͛8sC@ JѣHQӧPJJQVjʵׯW}Kٳh>۷p5uݻx5[w߿ wÈ+VXxǐ#m,˘b2ϠCӤ,Ө%Nͺkϫ_˞M[۸s͈ Nn)_C׍kνvFYr0dd}{/N%ю䕣߮ j'u19ͧT(bB5߄b(T]%RI:39 W?pG"އPhVfx!$c {xpH0DRl#?f% <?,RI7#O+0>uOI#b;nUZ)cAYri@y%~/}"ӊ"G#SL:#$O$j¹<?d?}9\^ \T*+ꡉ-{Ȳ0d[3SL%"̼d,M?cLD CO?sJܹ⧼* *v"C0ǜ%j2 >Jf"# 0bDdo$ Q,]H-pS9902n,cp f. 'vS+J;H*v$#"P Jwz#Jc $@3en6yrn{Ft',cK m&z[Ctm+P^Z拠ϯC?ph9î-ݮ >omt%tnBz3蔭FԩZM޽}cSf̣|`< >N^ġ=R  IY 0 ! ,{0f$@ ph„ |0A+^lQF-F T % !R!/@ k!;P Θ3{Lˎ,y2c'>ȑ"U! ,0pH@ ,80!… XPB %R$hD]UM#g@KD%1Ũf-$`a6 3 mn,A7-! ,`! ,`! ,`! ,0 H*\ȰÇH@ċ3jȱǏ CIɓ(S\2cE-cʜI͛8sɳg×} JѣH*]EPJJի2bʵׯ`*ٳhӪ*ڷpʝK7#u˷U^L*ME̸Ǐ Lj%W̹KɂMiO^ͺԮc˞6۸ /ͻ N8qF[<\+ رν팲`؜y '{˟_J /OϿ?]ހy:(Bo?@_%ܧ~f!)yW =TN?s}`1J?\H!!D$bg0ɘ)T>I3|ni9\&n~"h;, <VX pcAC>&~/}ɝ"ӊ"V#SL:#O3>s(@SI<<3:>,M?OM>>4܊+;.|?DI$<}zZ?l "Czf8猒%k2ɈϨ&)0R? #030-x9J8m$d]L0Fc~z&߀{ijrG$IJi%H*\ȰÇ#JHŋ3@ eI2bG!A\ɍ)?ǘ4sSΟyJT&˒"kԳӇO*E#7Sj{pcY`%@48˖m^0 Y[eIyWkzQ-T(]ƍ_ ! ,@ H*\ȰC"Jŋ3jȱǏ CIɓ(S\rD0cʜI͛8sˈ= JѣH*ҧPJJ՝Mjʵׯ`yf Kٳhn۷pvݻxZw߿ fwÈ+Xxǐ#m,˘R̹$7M邢O^rְc^D۷94 ǻw8 )ȓ+W9nFYr0{= gwhB꼳_ jO.^<Eݾ1r{b rG"~E(!k!$cJwx$܂ whbgZabD8X*0Nj1h[ݨL|zhb,3L!֌>SI<ͻ:ra=K<ӫ xiko*?j{(]t|VuW߃a߅fF~ ~ou'o n*`4hFxG:ԣOq)^AӍL6PQViXf֏Zv`)dihlpfxq04gw&x.'q&n"1 @?a Y'q)e説*:1N jdݚ+k+ CQA J'Mm|ô|&4nD+9CitA>\qp- a]xh+ob- 79GEKjl2 xkgkPD,L NFHJHBi"S:J7,/qIL[@LX2L @F/&uZGF䥘$00(ЩNO<ǹf'9ZڳE0ٍ8<Ћ<`[Dy€E'}^T]D* f]Bړ`rY$3,JPHyьڴoi' BP&{e~,~ul@'0ϛ7~4X7zeN$>!7  €. 7@ @.Hyԁ@  @ w[XO$`88@* p@ B{鳀`A8SGU @{gJ;8V6_Qf!CF߰ 8Mx}ⷃ'><=؆1pz Ї|€ B|eH^9U;z6Z0ZHNCH܀ p0R |`w.)(hM2U0U~"|U' N@4} #H00pڗ 1"VmVbzgP.ۇyG؂ H xA  'G G wy@\E$UVx_y|$(|.EN>wJEN7NE))0#V1!/~[͜5>^^L*x`LQ~, )&.){՘a~EV>acӎ|6"NŶzS-cc?dbAcB/Wt./rl.500"L.LD /ɮ]&&fN-1131gs4S=2Eh15s3u3;S()3Ag-(!(N싆v|&4;R8QSS5-5]Sgiw3@i>m6a'7xj7Y36'/fji5%ObrG(,&?c:s*3$93=Mo:xpk$:lpq:C3mM'ܖq`\m>3t_v?3i&cF=?ţoʣ@=#t;cfoCE?>gFk& w?at\:onir?4@ݒBt*G (?_A%Ap7)so@BdB,6s 9.Θ "IFē7a@F=~RH%MDRJ-]SL5m v`T"̜2:+nL1 $NzTi4N"%jlя| LsERjBƜN`L~̺J WNx1#Nʕ-_ƜYfΝ=L8葤_J 钬MJ=`%!]Ɲ[n޽}\8 H´aA͝?]t{߶]vݽ^x͟G^zݿ_|k_F4J0~j0?0B IJPA ` 5a$=;qBWd1?J D0ƑNQ[G XHd`&A|+ܯ#*q+.-/H3D`&|4ӓ,1)ȂL1PL dQGm z9z$, `2S0D@?TUGg֓@$h6D.SS?UeETQRaWVm6:9#~Sͭ]ee5Zf_lvk[}5S^`3иа.cwŗKTV'~UzcTHe$-r%/ F X.A]PX ?AO(r1*^L꤁HLs1H佮pKE64"XP4Lf,nD8G/= k EEDA(W ]Ҋ&9WyzaT L #00@X8!H:L.z!!gj" 7HFFR,;\ Hi@O&G<@1(PUg &m4KGәVԪ}5umTma](ACVVlOJ;qhġhCi 0p&xcWFjn#luk5yUr P3dfP{IP؈&f5) F4Jq p}mTN` a{ZI+`}!;# rBεmePRCinsNTѫ2RP+TlM.eX!FTiVkC;j Cc(T闍6F_okcdOxٖ+ŹFH *s5!/K!-sMuW͋b86}d8rW{ biiaG;֡Hi@B?{'_>vqGؒ)B ('( pc8&A!D$B P'„(E?H)C9CI+,t.=S/B*X195Y!CqCC9ACd0&B< B=1d6,1ěMDL DEdĄpDeIDJAKhXZ$a(yEZ0R,S`EWAXly1]FSwŵa܀8C=[YXa('fЇx(JcxWADplEq&jhmk`F2b|]8GN;AP؇(fA{Y~\P[4YN<>2 3`&s\dtxWh~8JAēwEit&Dʐ4}(d`SEU'NIl#zM{%Ws .4 I'hwvAx.큊M;=} u͉0`R8W5/˽.µ8p73( 8p\`5*3X ,8Q "EQ ܍ ]}\I"p hMM]7^ǀ^\]Q }\\X'@88]ɥ\=0x݀uu e2֌Q .@: NW3 u83e0 P;86Pba7y_TM5 76a2<> >.X*_?Vec1 >ր9#6.0]7b"H Pb&a4b<(X?4^!m41C6 %+/uE​\ Wo49)T-hX]ƽ+f>g\HPPyNE3v~{gOV_w eS<n>hs}tlQZ؅^gކ^dl]+цq&g^`))H+(h.衁(]. -go + %<0WEUхT枮ia %XA Yx,ZHzkX< :S6kz}k.vԲym P!lGuvm_ vcm 폘T gM9M%2VP Ƹ*Sb|Ŋ P9 voHދ`Rpکk֋) x0H7e= oވng%ippINm^XNRN6P nk^ -orpq ? Nn H] [#@ `~;%o Ycz9&$oOx!_$r  L!a 0s/o.P5G6w78%?@d!۬0d;[ @ǘt@tx"1$b.A2-ә˄Fhui,[@j6q8Y={+<[F\emuu,voWL/I=C^4P v|uk7`uv_4Lp{p'wt])Ck 69^3Dl$D qL|wHgxzor{˃?NoApyna07Ƒo^jD4,xLei"~h/|7tϑlLˏ'7JjFZ?!@ b8 w)vv_o{EWg񛳏{ܼȏ @ͬ|4H7<QP/D(C=ê tPD9}FPBG,7w~؜>ddt80D׽JZt~~f,~HfC> BS`Hys,h „ vGkƒT*J#ƌ7rX:,i$ʔ*Wl%̘2gҬi&Μ:ws*վ|*ۧݦEOQC=x-m?y*~GR}K8Ŏ,+ a;&2!Ɩ@D52Q|r3ТG.mME:GKGynG~X=J.]5X ` Fj@)ց?@x`U  5?;);$Pk$M?RcDIZCp#?aVsHU?}-"ۄB$B/GtTQHAV6XS4" _UZy%Yj啌#ԁEA# @V:p B\j@ =DSN #5cIȂ؏P3e!9|@M X5&p):*ځ p$^a[!$DB#'"& *p@dTpP DK(I,\3 &z.骻.0 NFDv9[t4$X.>,Z塽JD?8eIIO^{qG*S2h# @&Dl2u}7/F&Y#FPZ;8B'_\@%EQQnyޙk9(k F>:c1杫:뭻z.;#)~;nA2; ?<<+<;뿿i(β4D~:qE"NI@+%h֧ { CfV΁10ԓF# !p{ ( v#a0E w`(GL@=f^(FGi>1_$ؒbPE/2#vq~ }C鈇RV$` Hr(|M&*-V0#70#4'>I*E賟'@*Ё<(BP2wcDrЉR(FMFTgFC*- (JS:ϑ)"NҙRԥ6iд )PԧF &G8(ԥ2$+L*pnDM*V`H8*X=0fAݪհ`$b5+\q m% YW#Y]ּ*WZ vT5,dEPI  8].kTΒ6OKZs}K! ,`! ,`! ,`! ,`! ,`! ,!PgH@ ,80!… XPBPdEt`ʼnE2T9dʕxZJ o0GC0c~,@d 0G dP& )Ȱ̪P! ,`! ,'PK$@ ph„ |pD\!FE6>xDŽ1I#%]($͔/%NM! ,/PfH@ ,80!… XPB %R$h1+e04På'!#cȑ%5LL <̈́ Cχ& Qӆ͎cՈ! ,6PhH@ ,80!… XPB %R$h1 HԴ#"xRa 8`7vԨ %8 ;HqM)&,#FZ ! ,=PgH@ ,80!… XPB %R$hQatб;xRrLCJxXM2:L`$;N:xN#J 5F%! ,`! ,EP< DxP@(bB`@#A&62 bE"eIad! ,`! ,`! ,KPH@& ǰa8*aC)RP l`HԨCCHGXPc˗1M؀ϝ# r' <Τ?xO'zjuQ`QL},7a kر֥ڙm>0t?!^|#o\ZaLipI3pF >H l#|}d@! ,`! ,`! ,`PeH@ ,80!… XPB %R$h1 >¤邡$w1. x12"a)1;GȤ07cb0'|T7)>,ahǂ f^h1 ! ,`! ,`! ,P] DxP@(bBX).<cƍMB0C3 !eL~y&ifp#E ! ,`! ,`! ,`! ,PeH@ ,80!… XPB %R$h1>¤邡c"w1. <уʔxX &02'?r'͑ jD! ,PT DxP@(bBT͜.ȸd&P)@2XQʙ!s"CYBS P㤣'|(ґ+nL1AVb! ,`! ,`! ,P8 DxP@(bB+R1G>pŒ$I! ,`! ,`! ,`! ,`! ,`! ,PjH@ ,80!… XPB %R$hQ7.cQGDTHc17#¼84ڰbiLArOO@чKK@@Fps'FZh1 ! ,P{A* 7 6LbD ´IC& xr;\:8 a' u:ji"޼sgLɘgιf D}F'Gr! ,`! ,P )\@.t(A )!~1 !F E4)1+n,>|CNpŒ$I! ,`! ,`! ,`! ,`! ,APa DxP@(bBl& =玓 @ȠfE'i%a```&fۤ9I`+6Uh1 ! ,HP )\@.t(A )!E 1j1@$W0iXvYcP)d;=pRu:й3$nL֥B$#ƀ! ,`! ,cPfH@ ,80!… XPB %R$h1 H¤Y "xRb1@7e00R;G a<]dZc1I>HWv41%5b4(cǩ! ,jPiH@ ,80!… XPB %R$hQ$a,>xb >e00R6G abx dwVv 0$5T1! ,`! ,rP: DxP@(bB+B| aDQE&)l2bˋ)! ,`! ,xPgH@ ,80!… XPB %R$hQ$j|ё<((I 0t;Kdjjt4ϝ\, @㊛4SL85F%! ,P )\@.t(A FEnbHAb܀ϝ#T˕4KBt 3 7-[  1QQ 8'" G.| W&ؠ̴|dOP"̜)mߎ-+eQQZL! ,`! ,P] DxP@C)Z,!ps"CjFF$M"t sGw<`9@3"E9S>:cG! ,PaH@ ,80!…  ;GJhFxhPbȑK D,Q~Lxҥɘw,"ڔAixP !y,N촋L,;20 ӋP>ꍣNP~:G9Wo}@LChx'9S_P;ǯ_ofB/GA/=x4u[¾~3BAY~[d;{ `]w,B]׾-Oz*T#h7I0~̡Dqn <"rr/ACNp4 *Z@ %4܂)@?aJ (>Ѝ8)CwD*b#܍: 9ԁ/d 7$`K %c"9m2saHQ^L*C~r,gIZ̥.w^\IbkL2}e:~i"OJhZ\Hnz3'k&r%9q jͼН̧> EDRӔ h<9qS-yЄ3gC#JъZͨF7юz hdNbT JEҖ'>Vv2**C%aRԥ@Z ! WJ@dzR7,? T(4f&Ɓxŝ9pmxijx 6Msc`uxG}-T"`wNr ¦ }W>tup PG0up ۧ>-{'svGzD&mpp7Z `zMPq,xqz`q lnHFDM!Hn^OOs=D+FjA9='$S>T8[(b?)NDNQ8yPvxxz|؇{8H6p؈x08xY/8H'pH p@Thm@P 0 @8 3 P @x xxTpXJōQȊX   ( HЌx0 @ƨX ; So PP P p=ѨIIЏ>Б:%(H=sd6   P` r Hp@ `Y` &FsvI&1甮 P @@9pLyL   h9 `̳A䒞l2Ihi 8r  6?y 9  })稈 CVF0>  U6y0 OF V Uɡ霋 E.gd '` 鐥yy "9PYƈX М9hpGːG IZ🏨i*kqʈH:9B~dszZCgJ*`|wQ4/ɉ9 ZcxڪMȪbwVH0tv'Itnn햫n*s'H}qH(mwzx7}p#{ׂ f+-׬ؕCs`8s}.9Ƈ ř\RLɚ|PZʧ,m8:v wӴr@u3靭`I HnyA) ? λ l Z}LBɚxŨSP7]*ʢQ2Jj8 P Hj|P  yR,l@ PPˁ3a Fe8o͐H։X֧C_ ̿$fz]z׷Ʃmkzحظ{"؃خ&*ٞJH+nٟٝ٘jm˗M Xn]Ŷ8X0Rжӹێ yQ+[MC}ɝPܠD6=#-y-P G]dǽ=]-4uY1S1R:`}A0L-qSQT .>3TkV~4Or",OUm" .VɁ]A1r%"n2U20q!_Ñ1i3W1a1䶱;.XZ^'+AYAZq!^S fU B $_@cⱅEoX.7!W>(eu\Q]"B"6n\=-/2+l]ە#*"@$! "5\>"TUeOfU'r_B%b"s.j"#n`)^'>0%YZ`\ f^~U)!(&(!*c)%/D]",*"*3#+1a^bhic^(j2+hsdǢβ,-/dQFٲܒ,?.L.&fo0/R/S]e%m@\aeC!//?o6q&0 A2#Sg 312|Y Sg g*T3^3P32~VV1c4P"W7cH׳jBD(QtN{U F+o|_:{7 M$56Ao6O::o4A?6-nO<}o+ْ<>ONv/s>#F>+@F--U?mW?h?4DO/ao@@Lp >QD-^ĘQF=~RH%MD  l F[<@@r$  %.\0'DM.UXԩQSlRV]~VXe# ,ziRs }1UPRӾFYƍ?YdB탹Ww%RŪ#zֳ9[n޽}ޚVٲe<%Y/YH?-@A9rĖpv~s b͟G^<|P_E"R$?6"lD0AdP#j1"B /0C pC?1D DOD1Ec?_1Fg4E;1Gw:K D0 8 P"(eJ+'Q.$Kʢ-! X) g"*XʼN;|1K">! $B 93RI'PO@$j" P%`%YBF lj1a.L_JVpƄ`TvXB3cjH5[3>\wJ߅7^,j4 $()^ (E!{5=$8Ȅ` `aAn9PuTV xRlG# kfcI%hw>IX. K(b iUШ(\c FTlnSuF-nTΞqB\(ɹ܄`C[m5SA/tD]&Zbk|qB]؄\'޽l!S#NXyOkrᅲeZH>lj H#!,LO!N]k ,@?q8y\P& 5oz yb&ShtD8HsզwB `25+Buƒ *wjɍ4^XK@F0جgJd"պ' 8eT$ϭ \j4ޗYΘF@6Q X£ yD"jk-IO~ӟh@/ Ԡz@PT#p5&VԢ9T$5Hk uQDڨP1TC(S\R\,Z Vm9ΤGEꂊulsa)E xr*F b@ `( eYܙT7e{S`LlT 9bkZ&6 mggML6ֱTmq|u-'W` ucq8uQxLǶֵe_\'[ Oilȗ8;o~CV񀁸 ^\~冽 B Xt8! 9=N\${L C QTeU6$ـjƢ.qsx5qT0r&x7Έ,/2׼*9Ʃ`s<9"xCͫ[GAwCOQG9WI:xdLwkuH)h\c_:.u%a"|Tuǘu'ݕa;w?K^ @!X1]?x0>T8YOIOF?b]_t=h{2QoG1*c9c [ B̒?KB{2#LBۃO{ӹE #)>- &C1,SË6՘@. 7 T(DC,98P'/tK˹ ũă;p|̯ @\˜,LăJ˼􀑻LL|üK|Lw8ߚl^6UUVaV`(8Y]ᄈ`8p| H]_ h_ޖ)H+(eߘ`9.^IMONH"K>S֤U3'n_}c|Q.h E>\4 |,9QLI'MU^޿S} PKd4Ö}d] MIedOT5KԞMVHeJ(9e݆c7q4\⇸ZC<3vxEuARf'pgH~HP cQ'wš Ll6؁r)t6HPdM(dl]&hq&)0h# 0NN܅C$`)d(^εNicqi,PF9idZ℘4(PhgNg4aXNNjNVnj(M(rfDQ\%꥜ &xƆ"78<>n~Uu.ًx3 6i1hlx0Y.) ˽Ȇl>@4wmlFfv׆F S;őmcE֊ G!mH{m&;ȏ`@A+4BH,=p co@p&>x Dۛ*)+IqGDCŤc;h>ᥘ?(Ox&}i/%HE5y Rڔa9&ey&+J}O<Ơgfl#ijϋT ?-Bc1t3?cz?<#-S)2xTkT 6$!`c D!&+qFuHx"K>H|1KNNuR,{.UM}*Ɍ5}=f3+Ow(bϋ+$Kq71'@ߝ{p|З{=N>ȓN<%P$}3Cv?fnJݸߋ<ӌC=< O%R"ȣ;&JyL] (v"R %OSa6egcK:$Ʃ7!H(!Zq%|'uSP!'Lkj} @cԡJU,ZuVոe"UiVj4 vEXP 4@ \x6|!A %`+|p;a +8ಙݬ*6aPZ`WPCiK Ԯ}k9!C\Y2HC..leK[z@Mx9Vv) I0( mi]WZ8 sl~Yjnw^/e[*.6@hm$x .k`xMpe?T _Bie<CVC%Lx Hm=_VĞ) .%S1N=#%<67fʀ^_΄2` fZwc5\&Xn*X8O[ i"vafx0pd Nᆕ8^s,:`aaxg Rl]yuzp]3Ůo`ӡ4a`m/1\S]zӹSaxdpW crX.a'j}sVi8->ϽӑlX*`%ټ2nm.{ygz P ~K1D ^Iw\0a_bh ^\Wԯޞ HasP`۾fO|{il@ ^4࿥ΠIJ 8OE@\$UѡJ(aOU]:"#6I@F$*  ! .|]D%(r@LmV A' ^!n|R"a!+` IeaEڢ1-LL}( A^q^ך{Y8b@NXٕS٢Xcc7L#|BYeś A68Q%ud72EHԢ_;`TdMdAT b#F7vZL򟵥VedE@RR8k8߫Cb8eNJ3>^QI@Mn\hAs@$m^n[4J(oAv9A@a%ne\%dY)_帔Xљa\f`vK(]\ZLH0Y^j8Ը8ffDH[ @a^&A_f_`a fpDsN~xXIcƞiJ&TTRez2fdAߗiv%v\^~KT'gJx]EjKn~Z\w˃Rń2(Tlkdhv-^R(R8(Cn;o(hըh^in> M̒n0œF˔ԒT )FXTJX)BQjEVEޤ^B険)RnihWiҩ*))Y@. PΒAA8IQi ^SF*vj1>NҪRQn&iꦖjAʪbNY騒*jS'.k!+V+u깚+f~)+^+k$j"kkb+lƪkrk6꼮k搪0vϓ~rkfjjȲk*)iiv,⬧BJ&llbl6˦+&k͎m&i@ V,..mzm(ؖ2:FVLҾ)q*jT-fߎ*V-Xibvi➪n"MbM^Ud.h@! ,`! ,`! ,`! ,"P[ DxP@(bB0YY# ud"Cd5zHOh2T m*?RĸTŀ! ,`! ,`! ,`! ,`! ,`! ,`! ,)P\ DxP@@_0Ld(0Ƈ+Zȃ=V( #GZ"r̆/Y@h! -mBL4¥! ,`! ,0P4 DxP@(bB+RĸQaF 5PdI QFT. ! ,`! ,6PsH@ ,80!… R,@'VF t äj؎yZ 6PZ0bUB58LfB?#텁?C6lH>  IY 0 ! ,`! ,<Pf$@ ph„ |0A+^lQF-F T % !R!/@ k!;P Θ3{Lˎ,y2c'>ȑ"U! ,`! ,`! ,`H*\ȰÇ#JHŋ3jȱǏ CIɓ(O\ɲK)cʜI͛8sɳΗ@IѣH*]ʴ)IPx!LƼ괫ׯ`Êm*,T+jڰ ŬnU;uݻx݋֬_x1ۺ f4̷ǐ#K%Öm zٲUę+YӨSztB̝ W=;&Wů[欺wN86h61nR-N;س/&ޚ9ť~ÿ o\sZpnC>Z|h dw^Ul`uVh_%XV__^x*=iJcD$rt\&y_N'fjFZzxw f꫰jqh۬5:'6Į*5 6]nVWf-na Fi{׬.S H.[گl /oon m$+n(m,{r0{n4gx"۫FӢs@0s Z?KtIK4/Hި5[9^ܰY\B$h$qgg:gm7kMsh+-xEy]X{8y&Ճ-q%/Z>\ WxM\稇.ꪗ}tnWD6Ƹ,Ww^fxS|3r9sxOF+u{>2ސ/ ?hR}V6 %+ԈAx8^p~^ ~C*o{ YbA .4;18 "$'4ARX!&7I>Mχp'ӆOZwӌ(;ڐ.R*JWtӮFiNY̙.[6EOp9%Y3VP k@fG!o&Gּf D8Мl'$CR)IuT#O_*?sP tAP- C]Nh.jj`$>bY$-I ˔RlHK9js*ӎt=OY)RxN5ElRjUi!ⳫB,&XÚձbuf!ZӪV{|Y*0HT*^׽[*z䔇_ָ<2_aE)YD%S@R}/llfLj3ZU.|BOJɣcKf<֍mg?C2/x"}J|~|E_SM,k~"W?6Mt&nh~GtG &vV~uUfuoƆe6/zx%u,["h"|L2w7txn2.w)xG7anW7yFXzofoݧ#[NyqB'gg[z{$}`bv8vWj.!ֆBap-96r_vx敇6C[|,BeH,[Vł㴈"Ȉobb.vz8؉3|fy1X$Pc(} Z(b|G34xh`&_-!_[ `-x2eB &^Tb%}ʈu֨^HjWNixhQ~^ (D#\%'`:8e~>ɸ{se]?^9H~8 ~ ǐSr3#2Cf" ki~wwL#e+P+ّ0Ш$i=ـc8vw>sUgPnrIYja.9‘csR;woxh?Yo(J;SthsZHy6ygiJYĆm9LW|(vg`R'aַi!=\If4;hAIvi%x]k)cF+y*Š9ǛIc#A2jR.j_0*1R5zz9;|75@ p #q3AkP P*NZ!RJ<>P P @ =p!r AP _J`@'a=@P ` NЧ JZ7e:zZ \Q @ a`$Z  Az20 @Kp jj h   dp P &Pӊ ᰦ P ` ʮj P ՠ `݊ j `J ZQ Uz_: +J^ÑAQ Ep pp {0P N / PL`jh y{i mG @Y{z* `n rl#[0˵ _ J J @Xo  ۮ[_AǠ ΀W4WjpPpkP ^p  F* ʼP^ } &`+^ +[ F N0[pK; N]*+  | 0;:̯ Xqp sWJ^ N5 @ pڮ<( Z JvkZ^ 0{  kp* PWS<– 5 EL 1`pO YC\0PŌz B!\im{52#+6 [Vp Պ 6 ؋F0 =pP_ ˺=PЧ|n1[dz LˀLZK 0 ?3_j@u\ j & Fۺʍijb{JP/  Xk}=N[_ʷ~i&@F-Mʄр6ХMG PP ǣ ;{ѧ81Ʃ-K 0 6< i, }yݯ={ 1x- P06˭i׎`T׀- הj|ǂ_6pm]-Mbdb-{k ܙP/&-} l| a oZl/, AޒjZQ  j PNn>Nqأe ">$^&~(*,.0b4^6~8:;b@B>D^=Nܕ LnN~` ` e^ްX>Dzn0E.2լJ/pb&1@#>BP8Zg>BP P0n7p.Ln'.@nA@ FzOP `SPpDp uNn\ ~ B^@.p^.5PKg S MnS  lOP .> Tn)愰Hp /o"o W1 t%.n kP^B .nޠ @vo/q?A@. yW` P .onzORp_ 0Or A `N_ _ O* Og̯ \!_s.4~fBX/'oc@ :>rE_1FgF,G/>-6آ( #(H!dRM3#pcЛ?ii( b%'>jʏx )qk5/d7u,!A?@⏣ҩY? Fͣ(*IgBj{P SNJ& N\(6Xa%XvDVm|&]ͻ{BgeR 6fUif)|t;RAb:iYZB4zBΛ)/\t zE]n@ZF;Mw]iH!C 2c:h&:dϜŖfrx7yzޠ#ɁIcGk L \$h8{9;ngZp#A"p cKHi+&h;(YoũǛO3'&k)tu:UY<*:x'ŎHWe>*%BbiSygҔrd nM{%{ҖN)moƄg {Nx`%X4HzB/XL-@2];Ӗƅ!ZBla žG&8D"ш1`e4D&.z [&ViTbE.vы{Ib-EFfF2эoc8юwcG9яc 9HBD$ K}$CI̍.Me1d(d 5J@)QJUFK1XT 0 SGa$.[TcSϜ)U?2 "#&8Դ&6Ke9!bs/ yBӞO4"2EӖL9 J E^̄"4=9Q_1;h<%u=U:&+(EW2/L#>F-iJyQVtБӨ%QhJҤ+*_l`xvL'F3ZTl)6JʓBvcS)ץZ Ĺ%_nu2f+d A2%] صn$ibET>j"[ZVm,C [Ŧ(j[:X%Y k@ l]Q|-`9X鮳; P[Rޅk$QrN.oջܖ*@ d\*ov[^r7%R[[֦խ~ ^U^#VرY4d8 8 w錰y5[`ز6/Fo'U6^V]x c< q ̥ŵK8LJ7- -B y^v0S|yͅs\d:x|,w{tw|QЇFtNяEWҗc!h3׈ҘuE o}'vGjV:X2[SGՌv]k^z̈18}9Qikf7\NTA VĔ1vNj> Ёŵ%m8 w ju{`7-G_uH9gG;JqK=o{! ,`! ,`! ,`! ,`! ,`! ,`! ,  !*\ȰÇ#JHŋ3j<8c CIɓ#=Dɲ˗0c̑eȣ@q'2B !۔B(RBbԩ n[э"<1V՝ 7GС!e(S}g p-!R8"exb֭=X1b׉ަ0s Wbncܭ5aShᯬ]ڶT#Vz~xS|]+1c4}QJ=p{CA2jOY󮞽s9(ZQ_bHm=_H-V[sadbRoT A-TH=LŀR LŴ-B%eC=N{9Sj's,"Fd[y GXLqXsVy%kɝy IrAyOrFts7CVbE'h=&WO=z3 >'q"9'P޼!T_9aba~!<8P2J=HX,`\nEڜS41O%ꪋ EveݐHki#h !=6hyS#5c*=HioFAOv®%D %xYQԳN 1Jan r1"kBaO-7ћqzmH5([c~.sDnkLx /ewL@ې3YEn7}L$|%̚]B}J?1zq?c_aV#9 {( YO>orAsM\OA3%8*]*J7i<&a^<Y_(HЇT g7Q<ĜnM#ل0|c Q]2]&zOG'v!~C$҃lwkH>O&BM5.`*@ЛfU 2C)XZKBҨxk1Wx-֨/I "20GmPȨDbW:PEDzG| R+8_*ҙ.1P#ATcH0FH'=T\VFVS`b@a Yn?B`iY*o#ĀL 'p)k44|armO C9S@%\1iO8-#fA4͙ nbn/nL&wЂȰ9RDtc+6hEMV &E I-J&d1Adx, MQ:QҔ;)PA$ƠLDAŸ A!Vi H]HT p|YТ52iC <µ$v+D `K}@*ldJ5,_3z hGKZnMjWֺAH^K[8!$1^b%J\ll2بqC{R`E)(-bvE5a 'E/a{AxKQ]* vA{`gXmp$@ (8@ k#< E(B. "еc@,B Id8F6jaθ`E8 \7L$+MUd9${ n5cCOVo,|fm\R_a: P1B8E d!bfcH~s<ۄQFb (8ƃ5`ۖF#[7F@RZ 2@ Uִ } a*ٱHxm7lY{[9E5` mj[ m@.xMlcSnF@^o 1 ú@bkX\U Qi .bJ1w_P/䂼: F{]Wx wosgz*̹Uot<Ԉ4\mvkn&B':m b[w^\S8< ]`}U ~\xAAe]o.3kɢg; Bj86Al00w-p=b`6@7XcW {QAvWeO{{6GurA ZgvrX7k3[dWu6 =B F0 =@Y%Ѧb ~u&`ȁX%gn@^|Ҧ1 ^h^xLvv "H$vat78x~u\wt}%Up/W@erZ*f &_ Xc5׃fl :mlxXVkn~plf j؈f~{؇zx~6wpp0y\gg '{v(熝aY{ omxNV}hw^ 0zx%2 @`ex]d8z0kg>hhR Xgug;cG\Xr5_c} fhx\v~XPzȎh]]fvʨ,Xr0Œ0Ђ bP/FYfXu_8mmw55m7\u1WRX4JXUT*Z#Gbd_iXdnZb)Zs (qYGn՗~9*[Iy}ir! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,` H`A *\ȰÇ#JHŋ3jȱǏ CIɓ(Sp˗0c4H ,9Tɳϟ@ Jѡ2ɔiͧ$qիXjʵג6iJ&TTM)A 00ʝKݻx* 리=L<"Tu  ǐ#KLy2_1 Kfj)5 ^qʨS^ͺ˘_jVfgENPe5J0 2dehGֲadP3SL%HA B/G$A/=<0c($N'@ a.qҗY??|7ЃU p p^vX"G WPF)e]'a[SzL2\AC+sM{YH!z(^r6 S|U2}-}8#9ahA hWDȱhvYEk px@h '@rQ+,6 D>B@@N4^fk.^D@ܦOL.H k⦅ .2&,p,;X74 7ZR"RgUXcei$/Z`kXx&,fy6h0@7fvL<_i6tXgLǟ;" 1lnl*8b/"#6⨣mb%)&f78%X闠*Mwgz* ʸ稧NpzUK[n;ǰ{7X#WR,wXKwTaAHij@?G5Y+S  (!CBb,؏~?`685gIwx @c!/" | ZP~9n[ENB> &s(C:aHC0p>-&Ht„L jhNӐ jH0P+w7p7p9LH0A 4@ \(xG/qa'2%j"Ғ@#"q a P"%]K%sC a L$]SC ݁ x"Hz G%Hjƒ/Z3:.lJЂ 9$vx %61!PC@7 d ҩ!c l]xCYs AuOqP2 'ӅDBqh͒> EpیܭF7'#$|!S yFD \pOP,T! 8 Y*45;`0ha LSM.&YHG0LgڛɛR!LCPIiWA4͡X\rY֢y)9u~H!xs`n砈 0u/lwF8MPQ @ z 30lԨF43ޡ P `#x82$d1.kX ʘP  x wА `#è(wsgjx,)בl5@Ő ٌ6"鑵ؓMi~&)aŒsMaRcS ݐ0З ٌϸ  O)ư {91!EMvsv4w1%/鰊 yy I s O Л 5byP~9' qwizsU7WQ7 s ٗP  9B sɗ  ),4* f~cIAyQ` X 0UR)ItS0:<(*J8s2iɊ: Rِ,ʟ)/6Y 0YPX +eL49[21~j9nOHGȆxo8;zAjÃxfbzσ]fڪzZ5誴tvsGᒽ؄86i@w㰨. BڸIj-jvHgv͚FSg!lpƶYU{lm5vPG^]ml7ӆz&o0oz.oTjt'ygu@wpp`{dzЂ* tA7p * !'1x akA:f_MuMlys睡DKl7t}Vt@߀q !@"0`i>{pQ7u O[v.K(Rzsw|w'tyMkM@G|k(0z[}98gzUw 1{;;o({{C,$pK,봗U0xr, }=ز+g:(7q9~' cYD$Zp hpki3qڷqg|! ؀$Kzx_hp*r'$n}gP%ȃI~km+{V+Cw 2zF6Tc dFD΂^X[Tz,ܵ<[$‹`%,<×f/ Ӊ4:7LÄqß2'z~HƈFI@IĂej(f4ܛƚ#\<^L8II-Z P МjJY B*ƝV0oۨ89;ٓ?Iy,O@ R 瀘L \i#TɜJa)pg03G6'N*tixZ )) *ʗR2œ陠yX:{̨ kRmW7b#Q)\ٛ ,,x5B-zj`L/MMD@A]@cCu2\S1Be,=j&B*EHNY聮:ݭj8y@ bbUWDGvF?&T&ER$utwtꩮG|G AESc`TKwDa"f>FzNJ~G>%lWTN'J@4Mt.{LXLQTJؕH%LTpL.MoXs2+WNBTZO/OxDP OLZ.T|QUP*>.OOOOBQ%OEP 0c)+d8o<#1]wJNBETc USUUSpbf5UnJX4EhFUUZPbT ^eCQO"^"ML1]s3TO$Yl]X%eXM_Vg%X$O?XYEY q>Yb/3m$\ƕ]ۏ\Oԥ|] ]u@A\ dFٕ\?]q˃ .0s;ca2C0oD ų瓭BH.UԩT!’'`E9e0$Kv Wܤb"@ IE`6iM[l`)"Iέ{ׄ9=Np#JN߹ M߿0 9$PڵmƝ[n޽}JԩѢßREN ݥW:o =,KVV>x͟G^=ōǓ\~T,C~0mx$@D0Ac$'M< /0C 7P{09F8DOD1EWDO>t*D"o1Gw1C2pƣdDDv1I%dI'c`5H9r7  3L1$s(ݠ2)QL9ʨ@/3O=4 &SsS*S;dQG-O*U }3DQe>E&`dz%;UW_'Ie~RL9MM (XOiX6ZiO>=4eY!jFx$cj*R ^H^zx`-<%g_dZم[NV*PZ7 d5M^|S: @ }E9e{lA=]&N\*Wŕv9Ȩ*FIY}{5:|aeĖS[B:r^noxY ӶOG=N3]#=&Vvov3B><}!G>ygy矇>z8K D$vX''&VJܥlp&舥}`g}=3@ VЂ%B( "%BP`E6f lHB 1Q $+Z F8 $2a8C @B30 D5A (& X ڸuC^ЍoMF#[7F@RQ 2@D`K@ ch `5L`D*L"'b:$ z|'*2QX$IIKї I0 F X.A]P QDa*XB.IMZ 4t0%AN0fހ_A.:''0КdPd 9Z&r7@@KH`M( a5t1L"b ` syȘprzQj@c h( GD'MJ:U>g(2Nx~aa Ji2x OIk @i!4UƢ P@ Ycoqnjd%,^&XR:2aeY=&Y}ZQ/d, %` D X[6TANډoe`!`U_ PxG6*]U6Q ~5b PA}+4x X&u!R7nI_iN$O9jQ4@P8 tK%۹t}S,a[NܚcABbT{ 4HiDJذbłbWb$TQG50?go(S(T! ](Mv.biG7,$5JF'd{7IQғ,))UҡpgW[RAr.s={[Y&!: hp&熹oISt&4IMkS7ùZ3\g6΀˳ =Y3_MCЊ_yw9`ش: {X;4)t|g>Ϙ<%l*[QtbT(HEJĶ⡦Ζt2]|MӝA,G RRW<5H.Qcg"@GC Eo3)=T!*Y]_ Xzqm-W%}v~^̾5%aX>M>A(l:jAGF>,2 ,:,҅v]-2Ҳ!պ#z%-.^).JA䲌 ds8; ,{̭ \>՚-ح-c) g;3/R/'{hS::,sB:&)*+(ͰɲGք+Fɪk&;pҪ ©3o<$<ʨ([2کH:Rp>,[,|,틿֣?gQÄkYpI.X&}ڪ"1Q F L#$?@A|A⊂7A@AA( LJ(j(% I ( 8P'@?AFB>d*K& p p X;CAdAc>bG(bJ6 H;Xe(9d@vDd:6  ]VeVfc e7+51-2Nc($ "88 %x6BdA 6pU֌s'F!~YYF9fpb(1p"8f.` ,N1჌Rv-68>h" HN(;p1p苈h'~.pbc> H~F6e6 6h^@HQKBŃ2($8 .xFZVfx( ( S.``x념'@@bFih<6iiN+H#@끐j Fzƃkɖmϕ%sACQNZ؊8+fh`0`R5 H1ᾃ.^ض8p73(X18m,3` $;0&7U'.x>e(o0,ƀ_w  /^po֟'N Vni'@8nwn悧Z>p0xov$ 2pa]h[j酊u\N9Pb.@:Wh3Ⓢ7hsBvn ߂`0sh@sv7h /兰ep;ظØt3F V;'HKmNpF'iGgR?6GU?3 W7i\GQ(tJGm&q~u eCs`΋C=7 A~t<(uʨAX7<=ٙ[I ~F64ZA vqFO-Pn;mF='9)He86 x_&Hn`HPPnfx_hw2P!eAVb~u/^x`x(6w`A on+b؀@ wp`ψ)H+(؈{&Fw7Ǎy=k"y?Hb&G8.eR{(p^.iZ/j.ǃPi}` Z&}:n"}Q@~wxֈ ^7O~~ 6 ٮ|GF 7w0M7`-"]c}O`Xf̃ );/\"1ܹ玓2H`rcǏNLFRɘ2gҬi&Μ:w'РBP ԤYs5mxW̙B6i\,x08@-@FpsL${A;qN#hM3֯k0!*FXtعgF}ڷ)rW0GYSI<GT͠s:sXU@<|_} zک]$(PSEV@UD :-%U^}ӏ[?#)#CɃ=2t#IVʲ` U U~.F.BP c#!4n# a#6J7#Q5Z :#;;#<ƣ<#==#>>#??#9]Д?$B&B.$C6Cc@ʝcP<$FfFn$Gv>FdYL]G$JJ$@$1 /" K$NN&KNLJINQ%Rd$S]]]$RN%UV%G*1R^MۑTZX%Y~$V._ݥ<`UPb ^PY֥]e;ycKtM[ v]aU^H aU =b^&fb 5Idb1"WdiJn&g2f<♥V&j&mbj/fmomfg:o'rcp 7fQ $'tF<.'n6}ᬨchOp'u@gQx'HVdܡ{HR$l ];n}:r ;D'caȁnIˀDFVxjR$UdMYBdI@#Ph"ƀM(OLLhcahP&(x&ďɐ~ }JrR(W eLLiLOI%i((o阒h)MN Ix@NhZpӔOTZiTLLD<\Ei|h:fڲ07Dv K-iY AK-o:ZE qA @^F|,p$ .ʬYi /p`mo©]K,ܱ(' G~@ 's#b_ uU`Em $Cmhm*EP4b 鞶22uȅAeD*;Zw6I4 ~+S1;p< sA3.D4c-;s^n  1FD6n`-3::13.rd \B|<82L@4/}G3/#/de`>+9 7/sAX(22/r/2C;4 >f&އ=2m"(@ @12=p@A:*7H}:5$B| DQ/q^z&uUktsR7p S5P5;F@\$KR5 BcXSCcEB0XCOP6MVCHr65esfB g[viۅt|XBtR'jcg6Hg2!ք{l5*R.vrGMR4R/N(+EL35VA-ADSxA}xJir@v[.ۦH-agkDLDE@6J|7a;tsolx)r0GtBg-nCuL8xkyZDxqDS 5~|FE~DytO:S|S>tWwv,҅pF|L@tLcsCn,8gglw߹yFf5V^|Dr+]8kǣl@s4#*HyǂyǫNjƄ|+k`$OAl`0T(ǜx4찇 :y_0 8(l(T2p7pJE/+9#œ{܅(k~{xA_׻y{I¨cY-{N, DKIi#|xiMx ʝ'TdwH̫[̫<ř#AFvχђK|=`X|4|_@P@pZzLeTސ')"Jh\ppM~< t or~i jr X˂5Gd;t d4bz!~MPXؾ?PTyx`"߂P 9?7cQL,J补tgssePGE( ; R! &S N`䉤ylGb\зx ,3dTƖǂJ٤tѧM)J?7-cSDqe>ieTQEVb3L "3SQM5e~VH)bytdsմEkdYSwT}u6ԙz4TU-X-MMlCeqI'b*ǘGaA'E~yǘ[q|eDŽH6a|GMǘMPIt.rsiJhU]yceTi NH)ωnii: Kh6F.&xI#Q=ʖ>LM~TZs6Jx16O]hcVYa֖l6y;![|C@w`մ|nYzV(ǣyOXQ^ C[׾ȏ%4aAñ7R]Lv#G2`ufX% sB!1x) Q EC-: zGD)Nf ИE-8Q*\%! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,`! ,hP[ DxP@(bB0YY# ud"Cd5zHOh2T m*?RĸTŀ! ,`! ,]H*<aÅ#JHŋ3jȱǏ CIɓ(SZtP˗0cʜI͛8spϟ@ Jѣ YT2bOPJJի&jm )֯`ÊKl֥Z'z5˶۷p}@w˷߿ X ̸ǐ}EUȘ3kb]'wM vװc,۸sͻ Nȓ+_μs"0e0xܽ;O~wpD tQD yp_c0Wހ6cL`A| W}A냀B+mXtY9t@+aGEwj F(́hv0nfpQ! 1 '(#/xB ֺQhGp)@ j:uq,st/@Z1F/qbHctdrM}Yi+gPwMAto(H-`w@@JLJ0{-2kǔ .1&0AS%4H)FlA {N@=1^R@?]: O}}/o Ôp:9@ ¨ mHE0;a!D4J`+vJF ֪ eZHD@LXшĄo tH4Ċ7ؑE & 4X`@N(IŭbYu`/`ā:nmQ% 7Ȥ(*A%3Q~$HgP ^?2d zqF $P9`8 2!  N( H>2h3n 8 h%Ԫ%09T@M7s!X2I QDGgA 4Ȏo<00p)`&/u(=N9 \ $qC>9pmR"yসx~ ,0(bJ$-)hRU`0"B(V!r@&c@-C*L1i]+.xg0H0.T1Bc^خ:v8@2 O)4dEjQ%.QWR$P@Ƹt;H QaX60d1K\2!^rgdӾ{Z%Ee %;|ͯEL~.;0#[XNΰ7LD #qnx?qHlxǃ3!αn*AZT"6Q tCD3,.^&lfY&<܎V,Xqc}fsm$*qLWEPDGH!fG%q]kZeV2#byy`D5-[;2SE۝Q3: F?|F>P1yn+F+?hMD(&Aq_܏̧;N:y$|9>!tcwnŬokx?Qw=F+"oy9V"R8Wp;b]cٻ2A cd'N{/7ݟa fLr 1)^vY ! ՙiixU#&vy` 鍯YGaaj6Yt֚ٛ88e c>dBFdi`%jIRʙYe]efI`+G `fؙ9vgzg}sО|i@2V  <}h)kW t@e9XjI4ܸۨ~ykli7s&ek@ dvzo J ֖dئmZunnro Fe&s(py&|ioFr@p7q_)´q=Zrx'r+6yɤ(nb2yǷwHJyt{D0Qxuwn\uRxF{I0lCG .d{_ŷv$Gy w|kyyAix xbi~7+k+b٤nm4GkwzwUJg{A| +*f@hО? gtawZ>~~GfTƈ%ۅ?ٛU[ۛر=ꁧY'y&k(/%۲ G( 6{8_X=+?;_CKEۂ_*IM_QtUˁW \۵ZK3hghc˶m{c^ q+lv+ Az r~y;釙 ȸfk۹29[/1"'1sr+,ak!ۺ0񺰻? RÛ>{Lӫћ2vA.2$0#3R#7%`;I=ի' "-"g&IB4b#W%[;"UAr";%#a% #{΃ݣxp'R#b'=(1(.38Ӿk|7x5:ub)@##b&|*=$8O`*G0]9"+)L, %r-%'\+]2Q-,[++O0T|,X ֢+S"[,tR\9dc")\"/q0 0dªR=f{C¿©00?0w1|ǖ|!97[7<3@63:cLo335Q73ÞIB3?42|4\ "#*hsL86"pďSusa8s!L+6]7N p7 }yc4 Y]=Μ9c:ّ+}: P;3c< -[h"G+-3/=:BM;;Q YI,UTvLsUNnL'C 9N(;芞Hv;](@ p <~ v>ۃNkP n$pkO AP o"`p@?:Q >룓{^< ~L ^0 P ` @ 0 @ǐ R_qP st 7rn ֞`0 ՠ ^EŽ /'s@ a #@ P*@ @5{!p ~L,` &`JNK.~,N=A_ (?CQ` B2U/ 2.G8.̞p@`P ^p  F@ PI6 7"֮KP^ &`O1@e=_`x Np,oT@t!>/*G`HN^ 5T5 @ P R/ՠ  _ 0@P%*" vh%(@'V`9z@PDzUF=~RH%MDRJ-]SL5mޤ @N=}H ƃ(] @ Ī`[ iJedX$:4Q@$aLX5j=@*4M TJkڈ.<d͢řYfΝ=Zh8FS. P"];)a?^hXV0NȾ561h0'?K0DڥD=u7"(~|ǟ_~k`īS*" l렪t2A!pj˄,P/P&Xm& %)@ V`A(2CG @$')%G,?+2K-RlkHLx@!J") ^p g"j:;҈>J8*#QG4RI'MЅLKy Cԉ1, JOE5UUWeuMOU5IAl5W]wW_a_%XcE6YeeYg6ZiZkD[oף j1 \;ʙp߅7^y?S g(Bu7 =`F$sP攅EV%l$lj1 'sLlo9gkaښA2 ;2JH^ CNE2[`4J:_qd:TըGEjR6թO}*:՘ xjVխBիPeDr@USWժ֯TH:c `jXk^VRAq5 :#XXRaؗ zDaTX_:~D"SG>{'+-cU{BvF2LVG?#M=p 81>w+KK`U^F28QfB+яsxQq;3jegyV.4 f1X2l51,V;--fpEӡumhSwW^~թqOxCq7:` JǤ>C\<VPa VD~P =rD<ǹGH^t(sA.0t0 X ;zrDIOIю0PjSez}9# @8HCs+ P5\A ̟ wG<>K ϐ<_;<4tl@T.r LʇAO~oD<`>?o}|<@`>޳˾?<8Às/Õܼ<<"Xh=%x6@ >h7p@sÏ{:܈+< .p'p<\Qx/>?'8j#)Ī*B!x .4:%l1X1<7.:*r'Xì ;$9ǃ<6 5!|.8r8p73(lDzvwvt 0."9{;"Fd!; GH Ȍ|]N8GH \ə0xHd9zt乞,GLǡH$<GHC'@8HHXH{G.o#@ 70IG7JYˊ41 H]d2Xk C:;#4upΔǟ[G ʼLhפIP>7ͪL??p;(=$NKJ+ɌkM3<\B7B8ɵ@=Ī886\Jԁ 2\ΣO +L`x.@HM;̳͛ xؤSM2Ϭ⹒9żăI+ECM\qh=,M 1p +AQ XĆlGGЈHPP'P+-]e*R-5R[Q>|TG3ex7UR+( }!9% ;M+R-UI:H@u‹ x;H%-ӛCQ]$2 5ԉS6MLcR\G+軱#!B\g?4!Q hN%?䂮#Cd=3p;`C_7H=X;Bn"?}ü8ϴB]ڦuX98ZN< [U[| JΛt=֛=e[U=+ LcGԍ4Bڰ ڸMtԎPu[XH\ءZXԴtM%}978"=Ue\8L8, %!7h^qy=}[C^|ޓ-Q\m4U5_@_3P_m^!em_," (`h0H`Ώ=6\#88`j`?~s3-vb#F`+^‚j6-`H[dФmC$Y$"9 ``Q#0f]['޳/-**^aFa_3)F+58b96.)`b$~b>c&b #p by ~:NbSNc)F-AL`@>,Y$ kR7?1JεRkz>)e:oCa)cdIe 6*4`|z | 7e\co>Ze<6fQ2]af%)dN e2*{f^( (cpV/s^fycdZc29Fd1bhrzhVHSOR$  esbegb`NfOcf皶c.e`daN Q9YID`},#ֶjaN,sS`j NFHNkFPv+뼾 v+¶kڬVl`t86/-`]zJH~y3ɞr'ꚉ1V`HyX2>#mܶ-ҬPdnmǮxHp}ȇMt}hMXFx~~J|@xz~xEnV`}nTP%cn}m& naaaEb?LAQVLEzhEm|G((tHhLJHPnyp~&o>W%Zp3llJ84^R$@vpUfxGH ~~0/7H/}xPrnnLJ6mp0T'!BյfdYxrdtx*WnH`sG7LJcP?qNsNW5yEfs؄K@T>heebpG *wH^8s0's/?m5E-Vb:G~0H@Hq_qymZ˴i ĸfHrLdϻ(H?HpyqVm%+on_T؇wtnWiguBvЎ~6 (m(%TIOrwZM@fpo10}89?wp~f~nZu,=4e֑!i(ypzzy5tf3u [~{3x*gvr7O|~~o*Ha%;HXJ/mnG}opׇ8ok>zZ_@}X~WHNVxx؈NtЇ.~kO|sq_wgHxC,h „ 2l!Ĉ'R[>T23_+W-Z9H@#VM4&8)oSY'РBi(ҤJ2m)ԨRR:#30"8#(U<Qł_MXʳhлx/.lAœ.^M J0/AX*Q⯒ŇS'ρ-w/زgӮm6Ñ3,>F"W ʫt ({;Ǔʨe焧Q3}U.O_M&?A%7zCkU : v] TRj"#u_@$Jx")"-"18#5x#9H #A8$E9$#Y$M:y$QJ9T$Yj]z%aH"Wny&"&m)јeu6&y&PQҜv 䞅z} :刮!:)~ק}(D:*a}&(O 2Dv:+LjB+Bt++By ,&@{,*,َj꩹R[Bi;.r. ([)#)ܻ |0 +0 ;006qSlR<My 2U#"#rlwq@@T,'DuR@ Mυ%G=tM74RE5SKIJ0L0V8tP63Zmo+'_Ͷax5o ́QAXQ  F_Xau3'PWܑ| [Іs`n+\%%y0mG_A Fi8a83.=n^{;)  ,O|9ࠂ'rK :e86p}SAU u3`N迃XPrZ*/\t/<vK`vyqAp1-@<:<  D)Œq2 #lNx71ppq#+FD%..h4#˰CzΑT 7 HC #XHb7B0 ÓY)Px\cp:;tb{p2(P$q/3.^c֤9`fuՀ i7 ox > ܡ 3M)vPvnoXjSP,a`E-1|o#*Tm. nJ a @VZYԥ`> BZPΖlN@A`Xren+\vhD\>~n5P|1c *L("lVo:';dlN sq To]]LysqA@l~snĪpov]Z֍@ | 9<̾N[nͶIY0vkl+f5OH{\F leGC-gYo ,i(ki@@2jus/mu=pA&Zra,Za`GӉ-@*?BF<0( 8<봊qvc58aH+AGl"zUr[D+ #3`03=}6c@xl{n<GD֦uޜLxmt)~G|)|hvp3D ć,[[Bx6x5 8֪63WNqÜ"➄ɗW,p6]{ם {ڋ:sw o  I}SH {ߵC}E1mR,hBīWl1%EDŏNDB_=`>DVl ݔ ``~JƵF" :EBHD^x Qd1DA, REkIa Z!D zT`Ra҈d 9J!EaСCa$jaaU(2"24B2 ^d$T6CF!P%EAHʿ(H"L((Ȗt"b"( †T 28O JV 9"* PB-,%- '~"-̏b+"p#_5 8&(f0"yb 8T0E\1TA=Vـ5$KwԢb:#whc**8#Dd9CB7cDE9*d6cy"6BQ.v5gjG<& Y!O^0yNa',V!+NDzFJC'H|FD~'^'*~n' (&.hj2"` FN(VrfX(v~h䀆|(ZII( #9<(F(*$GJhNɕjK%-ȀÌ+&4CdEqC7?)."T:G~GC+,*CtD<CJj2$f((Ї">@#?C:D?C3D:zjt.#*tC;.jjJn"j*"0;tFBtC?t?ƚFhGhH鍲LȄFMN?&~@( %+JI(y#t?`VppWdƒYZ[\8)9l#kJBd,tj+(|E$>Ib0c@& G+**vgƸRF0B$r>/G*V/fo}o/x_Ƙl ^o/mĉo:d/FpP 0CpO_4P8arR +40npvTKI&2 <&1 } info() { printf "%s\n" "$1" >&1 } warning() { printf "\033[33m%s\033[0m\n" "$1" >&2 } error() { printf "\033[31;1m%s\033[0m\n" "$1" >&2 exit 1 } cmd_chk() { command -v "$1" >/dev/null 2>&1 } ## Ensures that the command executes without error ensure() { if ! "$@"; then error "command failed: $*"; fi } need_cmd() { if ! cmd_chk "$1"; then error "need $1 (command not found)" fi } prompt_confirm() { if [ ! -t 1 ]; then error "Unable to run interactively. Please execute this script using interactive shell" fi while true; do read -rp "Is this okay? (y/N): " _choice _choice=$(echo "$_choice" | tr '[:upper:]' '[:lower:]') case "$_choice" in y | yes) break ;; n | no) error "Operation aborted" ;; esac done } cargo_build() { success "Compiling from source..." if ! cmd_chk "cargo"; then success "Cargo will be installed." prompt_confirm ensure curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # shellcheck source=/dev/null . "$HOME/.cargo/env" fi RUSTFLAGS="-C target-cpu=native" ensure cargo install zoxide } main "$@" || exit 1 zoxide-0.4.3/ranger_zoxide.py010066400017500001751000000024631366237774600145100ustar0000000000000000import os.path import ranger.api import ranger.core.fm import ranger.ext.signals import subprocess hook_init_old = ranger.api.hook_init def hook_init(fm: ranger.core.fm.FM): def zoxide_add(signal: ranger.ext.signals.Signal): path = signal.new.path process = subprocess.Popen(["zoxide", "add", path]) process.wait() fm.signal_bind("cd", zoxide_add) return hook_init_old(fm) ranger.api.hook_init = hook_init class z(ranger.api.commands.Command): def execute(self): try: zoxide = subprocess.Popen( ["zoxide", "query"] + self.args[1:], stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) stdout, stderr = zoxide.communicate() if zoxide.returncode == 0: output = stdout.decode("utf-8").strip() if output: self.fm.notify(output) if os.path.isdir(output): self.fm.cd(output) else: self.fm.notify("zoxide: unexpected exit", bad=True) else: output = stderr.decode("utf-8").strip() or "zoxide: unknown error" self.fm.notify(output, bad=True) except Exception as e: self.fm.notify(e, bad=True) zoxide-0.4.3/src/config.rs010066400017500001751000000033731367755154700137000ustar0000000000000000use crate::db::Rank; use anyhow::{bail, Context, Result}; use std::env; use std::ffi::OsString; use std::fs; use std::path::PathBuf; pub fn zo_data_dir() -> Result { let data_dir = match env::var_os("_ZO_DATA_DIR") { Some(data_osstr) => PathBuf::from(data_osstr), None => match dirs::data_local_dir() { Some(mut data_dir) => { data_dir.push("zoxide"); data_dir } None => bail!("could not find database directory, please set _ZO_DATA_DIR manually"), }, }; // This will fail when `data_dir` points to a file or a broken symlink, but // will no-op on a valid symlink (to a directory), or an actual directory. fs::create_dir_all(&data_dir) .with_context(|| format!("could not create data directory: {}", data_dir.display()))?; Ok(data_dir) } pub fn zo_exclude_dirs() -> Vec { match env::var_os("_ZO_EXCLUDE_DIRS") { Some(dirs_osstr) => env::split_paths(&dirs_osstr).collect(), None => Vec::new(), } } pub fn zo_fzf_opts() -> Option { env::var_os("_ZO_FZF_OPTS") } pub fn zo_maxage() -> Result { match env::var_os("_ZO_MAXAGE") { Some(maxage_osstr) => { let maxage_str = maxage_osstr .to_str() .context("invalid utf-8 sequence in _ZO_MAXAGE")?; let maxage = maxage_str.parse::().with_context(|| { format!("unable to parse _ZO_MAXAGE as integer: {}", maxage_str) })?; Ok(maxage as Rank) } None => Ok(10000.0), } } pub fn zo_resolve_symlinks() -> bool { match env::var_os("_ZO_RESOLVE_SYMLINKS") { Some(var) => var == "1", None => false, } } zoxide-0.4.3/src/db.rs010066400017500001751000000214401367766543300130130ustar0000000000000000use anyhow::{bail, Context, Result}; use bincode::Options; use float_ord::FloatOrd; use serde::{Deserialize, Serialize}; use uuid::Uuid; use std::fmt::{self, Display, Formatter}; use std::fs::{self, OpenOptions}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)] struct DbVersion(u32); pub struct Db { pub dirs: Vec, pub modified: bool, data_dir: PathBuf, } impl Db { const CURRENT_VERSION: DbVersion = DbVersion(3); const MAX_SIZE: u64 = 8 * 1024 * 1024; // 8 MiB pub fn open(data_dir: PathBuf) -> Result { fs::create_dir_all(&data_dir) .with_context(|| format!("unable to create data directory: {}", data_dir.display()))?; let path = Self::get_path(&data_dir); let buffer = match fs::read(&path) { Ok(buffer) => buffer, Err(e) if e.kind() == io::ErrorKind::NotFound => { return Ok(Db { dirs: Vec::new(), modified: false, data_dir, }) } Err(e) => { return Err(e) .with_context(|| format!("could not read from database: {}", path.display())) } }; if buffer.is_empty() { return Ok(Db { dirs: Vec::new(), modified: false, data_dir, }); } let deserializer = &mut bincode::options() .with_fixint_encoding() .with_limit(Self::MAX_SIZE); let version_size = deserializer .serialized_size(&Self::CURRENT_VERSION) .context("could not determine size of database version field")? as _; if buffer.len() < version_size { bail!("database is corrupted: {}", path.display()); } let (buffer_version, buffer_dirs) = buffer.split_at(version_size); let version = deserializer.deserialize(buffer_version).with_context(|| { format!("could not deserialize database version: {}", path.display()) })?; let dirs = match version { Self::CURRENT_VERSION => deserializer .deserialize(buffer_dirs) .with_context(|| format!("could not deserialize database: {}", path.display()))?, DbVersion(version_num) => bail!( "zoxide {} does not support schema v{}: {}", env!("ZOXIDE_VERSION"), version_num, path.display(), ), }; Ok(Db { dirs, modified: false, data_dir, }) } pub fn save(&mut self) -> Result<()> { if !self.modified { return Ok(()); } let (buffer, buffer_size) = (|| -> bincode::Result<_> { let version_size = bincode::serialized_size(&Self::CURRENT_VERSION)?; let dirs_size = bincode::serialized_size(&self.dirs)?; let buffer_size = version_size + dirs_size; let mut buffer = Vec::with_capacity(buffer_size as _); bincode::serialize_into(&mut buffer, &Self::CURRENT_VERSION)?; bincode::serialize_into(&mut buffer, &self.dirs)?; Ok((buffer, buffer_size)) })() .context("could not serialize database")?; let db_path_tmp = Self::get_path_tmp(&self.data_dir); let mut db_file_tmp = OpenOptions::new() .create_new(true) .write(true) .open(&db_path_tmp) .with_context(|| { format!( "could not create temporary database: {}", db_path_tmp.display() ) })?; // File::set_len() can fail on some filesystems, so we ignore errors let _ = db_file_tmp.set_len(buffer_size); (|| -> anyhow::Result<()> { db_file_tmp.write_all(&buffer).with_context(|| { format!( "could not write to temporary database: {}", db_path_tmp.display() ) })?; let db_path = Self::get_path(&self.data_dir); fs::rename(&db_path_tmp, &db_path) .with_context(|| format!("could not create database: {}", db_path.display())) })() .map_err(|e| { fs::remove_file(&db_path_tmp) .with_context(|| { format!( "could not remove temporary database: {}", db_path_tmp.display() ) }) .err() .unwrap_or(e) })?; self.modified = true; Ok(()) } pub fn matches<'a>(&'a mut self, now: Epoch, keywords: &[String]) -> DbMatches<'a> { DbMatches::new(self, now, keywords) } fn get_path>(data_dir: P) -> PathBuf { data_dir.as_ref().join("db.zo") } fn get_path_tmp>(data_dir: P) -> PathBuf { let file_name = format!("db-{}.zo.tmp", Uuid::new_v4()); data_dir.as_ref().join(file_name) } } impl Drop for Db { fn drop(&mut self) { if let Err(e) = self.save() { eprintln!("{:#}", e); } } } /// Streaming iterator for matching entries pub struct DbMatches<'a> { db: &'a mut Db, idxs: std::iter::Rev>, keywords: Vec, } impl<'a> DbMatches<'a> { pub fn new(db: &'a mut Db, now: Epoch, keywords: &[String]) -> DbMatches<'a> { db.dirs .sort_unstable_by_key(|dir| FloatOrd(dir.get_score(now))); let idxs = (0..db.dirs.len()).rev(); let keywords = keywords .iter() .map(|keyword| keyword.to_lowercase()) .collect(); DbMatches { db, idxs, keywords } } pub fn next(&mut self) -> Option<&Dir> { for idx in &mut self.idxs { let dir = &self.db.dirs[idx]; if !dir.is_match(&self.keywords) { continue; } if !dir.is_valid() { self.db.dirs.swap_remove(idx); self.db.modified = true; continue; } let dir = &self.db.dirs[idx]; return Some(dir); } None } } pub type Rank = f64; pub type Epoch = i64; // use a signed integer so subtraction can be performed on it #[derive(Debug, Deserialize, Serialize)] pub struct Dir { pub path: String, pub rank: Rank, pub last_accessed: Epoch, } impl Dir { pub fn is_valid(&self) -> bool { self.rank.is_finite() && self.rank >= 1.0 && Path::new(&self.path).is_dir() } pub fn is_match(&self, query: &[String]) -> bool { let path_lower = self.path.to_lowercase(); let get_filenames = || { let query_name = Path::new(query.last()?).file_name()?.to_str()?; let dir_name = Path::new(&path_lower).file_name()?.to_str()?; Some((query_name, dir_name)) }; if let Some((query_name, dir_name)) = get_filenames() { if !dir_name.contains(query_name) { return false; } } let mut subpath = path_lower.as_str(); for subquery in query.iter() { match subpath.find(subquery) { Some(idx) => subpath = &subpath[idx + subquery.len()..], None => return false, } } true } pub fn get_score(&self, now: Epoch) -> Rank { const HOUR: Epoch = 60 * 60; const DAY: Epoch = 24 * HOUR; const WEEK: Epoch = 7 * DAY; let duration = now - self.last_accessed; if duration < HOUR { self.rank * 4.0 } else if duration < DAY { self.rank * 2.0 } else if duration < WEEK { self.rank * 0.5 } else { self.rank * 0.25 } } pub fn display(&self) -> DirDisplay { DirDisplay { dir: self } } pub fn display_score(&self, now: Epoch) -> DirScoreDisplay { DirScoreDisplay { dir: self, now } } } pub struct DirDisplay<'a> { dir: &'a Dir, } impl Display for DirDisplay<'_> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{}", self.dir.path) } } pub struct DirScoreDisplay<'a> { dir: &'a Dir, now: Epoch, } impl Display for DirScoreDisplay<'_> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { const SCORE_MIN: Rank = 0.0; const SCORE_MAX: Rank = 9999.0; let score = self.dir.get_score(self.now); let score_clamped = if score > SCORE_MAX { SCORE_MAX } else if score > SCORE_MIN { score } else { SCORE_MIN }; write!(f, "{:>4.0} {}", score_clamped, self.dir.path) } } zoxide-0.4.3/src/error.rs010066400017500001751000000003171366253255400135460ustar0000000000000000use std::fmt::{self, Display}; #[derive(Debug)] pub struct SilentExit { pub code: i32, } impl Display for SilentExit { fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) } } zoxide-0.4.3/src/fzf.rs010066400017500001751000000032251367571316300132040ustar0000000000000000use crate::config::zo_fzf_opts; use crate::error::SilentExit; use anyhow::{bail, Context, Result}; use std::io::Write; use std::process::{Child, Command, Stdio}; pub struct Fzf { child: Child, } impl Fzf { pub fn new() -> Result { let mut command = Command::new("fzf"); command .arg("-n2..") .stdin(Stdio::piped()) .stdout(Stdio::piped()); if let Some(fzf_opts) = zo_fzf_opts() { command.env("FZF_DEFAULT_OPTS", fzf_opts); } let child = command.spawn().context("could not launch fzf")?; Ok(Fzf { child }) } pub fn write(&mut self, line: String) -> Result<()> { // unwrap() is safe here since we have captured `stdin` let stdin = self.child.stdin.as_mut().unwrap(); writeln!(stdin, "{}", line).context("could not write into fzf stdin") } pub fn wait_select(self) -> Result> { let output = self .child .wait_with_output() .context("wait failed on fzf")?; match output.status.code() { // normal exit Some(0) => String::from_utf8(output.stdout) .context("invalid utf-8 sequence in fzf output") .map(Some), // no match Some(1) => Ok(None), // error Some(2) => bail!("fzf returned an error"), // terminated by a signal Some(code @ 130) => bail!(SilentExit { code }), Some(128..=254) | None => bail!("fzf was terminated"), // unknown _ => bail!("fzf returned an unknown error"), } } } zoxide-0.4.3/src/main.rs010066400017500001751000000016031366625176400133450ustar0000000000000000#![forbid(unsafe_code)] mod config; mod db; mod error; mod fzf; mod subcommand; mod util; use crate::error::SilentExit; use anyhow::Result; use structopt::StructOpt; use std::process; #[derive(Debug, StructOpt)] #[structopt(about, version = env!("ZOXIDE_VERSION"))] enum Zoxide { Add(subcommand::Add), Import(subcommand::Import), Init(subcommand::Init), Query(subcommand::Query), Remove(subcommand::Remove), } pub fn main() -> Result<()> { let opt = Zoxide::from_args(); let res = match opt { Zoxide::Add(add) => add.run(), Zoxide::Import(import) => import.run(), Zoxide::Init(init) => init.run(), Zoxide::Query(query) => query.run(), Zoxide::Remove(remove) => remove.run(), }; res.map_err(|e| match e.downcast::() { Ok(SilentExit { code }) => process::exit(code), Err(e) => e, }) } zoxide-0.4.3/src/subcommand/add.rs010066400017500001751000000035031367755154700153060ustar0000000000000000use crate::config; use crate::db::{Db, Dir, Rank}; use crate::util; use anyhow::Result; use structopt::StructOpt; use std::path::{Path, PathBuf}; /// Add a new directory or increment its rank #[derive(Debug, StructOpt)] #[structopt()] pub struct Add { path: Option, } impl Add { pub fn run(&self) -> Result<()> { let current_dir; let path = match &self.path { Some(path) => path, None => { current_dir = util::get_current_dir()?; ¤t_dir } }; add(&path) } } fn add>(path: P) -> Result<()> { let path = path.as_ref(); let path = if config::zo_resolve_symlinks() { util::canonicalize(&path)? } else { util::resolve_path(&path)? }; if config::zo_exclude_dirs().contains(&path) { return Ok(()); } let mut db = util::get_db()?; let now = util::get_current_time()?; let path = util::path_to_str(&path)?; let maxage = config::zo_maxage()?; match db.dirs.iter_mut().find(|dir| dir.path == path) { None => db.dirs.push(Dir { path: path.to_string(), last_accessed: now, rank: 1.0, }), Some(dir) => { dir.last_accessed = now; dir.rank += 1.0; } }; age(&mut db, maxage); db.modified = true; Ok(()) } fn age(db: &mut Db, maxage: Rank) { let sum_age = db.dirs.iter().map(|dir| dir.rank).sum::(); if sum_age > maxage { let factor = 0.9 * maxage / sum_age; for dir in &mut db.dirs { dir.rank *= factor; } for idx in (0..db.dirs.len()).rev() { let dir = &db.dirs[idx]; if dir.rank < 1.0 { db.dirs.swap_remove(idx); } } } } zoxide-0.4.3/src/subcommand/import.rs010066400017500001751000000050161367755154700160710ustar0000000000000000use crate::config; use crate::db::{Db, Dir}; use crate::util; use anyhow::{bail, Context, Result}; use structopt::StructOpt; use std::fs; use std::path::{Path, PathBuf}; /// Import from z database #[derive(Debug, StructOpt)] #[structopt()] pub struct Import { path: PathBuf, /// Merge entries into existing database #[structopt(long)] merge: bool, } impl Import { pub fn run(&self) -> Result<()> { import(&self.path, self.merge) } } fn import>(path: P, merge: bool) -> Result<()> { let path = path.as_ref(); let mut db = util::get_db()?; if !db.dirs.is_empty() && !merge { bail!( "To prevent conflicts, you can only import from z with an empty zoxide database!\n\ If you wish to merge the two, specify the `--merge` flag." ); } let buffer = fs::read_to_string(&path) .with_context(|| format!("could not read z database: {}", path.display()))?; for (idx, line) in buffer.lines().enumerate() { if let Err(e) = import_line(&mut db, line, config::zo_resolve_symlinks()) { let line_num = idx + 1; eprintln!("Error on line {}: {}", line_num, e); } } db.modified = true; println!("Completed import."); Ok(()) } fn import_line(db: &mut Db, line: &str, resolve_symlinks: bool) -> Result<()> { let mut split_line = line.rsplitn(3, '|'); let (path, epoch_str, rank_str) = (|| { let epoch_str = split_line.next()?; let rank_str = split_line.next()?; let path = split_line.next()?; Some((path, epoch_str, rank_str)) })() .with_context(|| format!("invalid entry: {}", line))?; let epoch = epoch_str .parse::() .with_context(|| format!("invalid epoch: {}", epoch_str))?; let rank = rank_str .parse::() .with_context(|| format!("invalid rank: {}", rank_str))?; let path = if resolve_symlinks { util::canonicalize(&path)? } else { util::resolve_path(&path)? }; let path = util::path_to_str(&path)?; // If the path exists in the database, add the ranks and set the epoch to // the more recent of the parsed epoch and the already present epoch. if let Some(dir) = db.dirs.iter_mut().find(|dir| dir.path == path) { dir.rank += rank; dir.last_accessed = epoch.max(dir.last_accessed); } else { db.dirs.push(Dir { path: path.to_string(), rank, last_accessed: epoch, }); } Ok(()) } zoxide-0.4.3/src/subcommand/init/mod.rs010066400017500001751000000040541367571316300162720ustar0000000000000000mod shell; use anyhow::Result; use clap::arg_enum; use structopt::StructOpt; use std::io::{self, Write}; /// Generates shell configuration #[derive(Debug, StructOpt)] #[structopt()] pub struct Init { #[structopt(possible_values = &Shell::variants(), case_insensitive = true)] shell: Shell, /// Renames the 'z' command and corresponding aliases #[structopt(long, alias = "z-cmd", default_value = "z")] cmd: String, /// Prevents zoxide from defining any commands other than 'z' #[structopt(long, alias = "no-define-aliases")] no_aliases: bool, /// Chooses event on which an entry is added to the database #[structopt( long, possible_values = &Hook::variants(), default_value = "pwd", case_insensitive = true )] hook: Hook, } impl Init { pub fn run(&self) -> Result<()> { let config = match self.shell { Shell::bash => shell::bash::CONFIG, Shell::fish => shell::fish::CONFIG, Shell::posix => shell::posix::CONFIG, Shell::powershell => shell::powershell::CONFIG, Shell::zsh => shell::zsh::CONFIG, }; let stdout = io::stdout(); let mut handle = stdout.lock(); let z = config.z; writeln!(handle, "{}", z(&self.cmd)).unwrap(); if !self.no_aliases { let alias = config.alias; writeln!(handle, "{}", alias(&self.cmd)).unwrap(); } match self.hook { Hook::none => (), Hook::prompt => writeln!(handle, "{}", config.hook.prompt).unwrap(), Hook::pwd => { let hook_pwd = config.hook.pwd; writeln!(handle, "{}", hook_pwd()?).unwrap(); } } Ok(()) } } arg_enum! { #[allow(non_camel_case_types)] #[derive(Debug)] enum Shell { bash, fish, posix, powershell, zsh, } } arg_enum! { #[allow(non_camel_case_types)] #[derive(Debug)] enum Hook { none, prompt, pwd, } } zoxide-0.4.3/src/subcommand/init/shell/bash.rs010066400017500001751000000016401367755154700175450ustar0000000000000000use super::{posix, HookConfig, ShellConfig}; use anyhow::Result; use std::borrow::Cow; pub const CONFIG: ShellConfig = ShellConfig { z: posix::CONFIG.z, alias: posix::CONFIG.alias, hook: HookConfig { prompt: HOOK_PROMPT, pwd: hook_pwd, }, }; const HOOK_PROMPT: &str = r#" _zoxide_hook() { zoxide add "$(pwd -L)" } case "$PROMPT_COMMAND" in *_zoxide_hook*) ;; *) PROMPT_COMMAND="_zoxide_hook${PROMPT_COMMAND:+;${PROMPT_COMMAND}}" ;; esac "#; const fn hook_pwd() -> Result> { const HOOK_PWD: &str = r#" _zoxide_hook() { if [ -z "${_ZO_PWD}" ]; then _ZO_PWD="${PWD}" elif [ "${_ZO_PWD}" != "${PWD}" ]; then _ZO_PWD="${PWD}" zoxide add "$(pwd -L)" fi } case "$PROMPT_COMMAND" in *_zoxide_hook*) ;; *) PROMPT_COMMAND="_zoxide_hook${PROMPT_COMMAND:+;${PROMPT_COMMAND}}" ;; esac "#; Ok(Cow::Borrowed(HOOK_PWD)) } zoxide-0.4.3/src/subcommand/init/shell/fish.rs010066400017500001751000000026331370003473100175360ustar0000000000000000use super::{HookConfig, ShellConfig}; use anyhow::Result; use std::borrow::Cow; pub const CONFIG: ShellConfig = ShellConfig { z, alias, hook: HookConfig { prompt: HOOK_PROMPT, pwd: hook_pwd, }, }; fn z(cmd: &str) -> String { format!( r#" function _z_cd cd $argv or return $status commandline -f repaint if test "$_ZO_ECHO" = "1" echo $PWD end end function {0} set argc (count $argv) if test $argc -eq 0 _z_cd $HOME else if begin; test $argc -eq 1; and test $argv[1] = '-'; end _z_cd - else set -l _zoxide_result (zoxide query -- $argv) and _z_cd $_zoxide_result end end function {0}i set -l _zoxide_result (zoxide query -i -- $argv) and _z_cd $_zoxide_result end "#, cmd ) } fn alias(cmd: &str) -> String { format!( r#" abbr -a {0}a 'zoxide add' abbr -a {0}q 'zoxide query' abbr -a {0}qi 'zoxide query -i' abbr -a {0}r 'zoxide remove' function {0}ri set -l _zoxide_result (zoxide query -i -- $argv) and zoxide remove $_zoxide_result end "#, cmd ) } const HOOK_PROMPT: &str = r#" function _zoxide_hook --on-event fish_prompt zoxide add (pwd -L) end "#; const fn hook_pwd() -> Result> { const HOOK_PWD: &str = r#" function _zoxide_hook --on-variable PWD zoxide add (pwd -L) end "#; Ok(Cow::Borrowed(HOOK_PWD)) } zoxide-0.4.3/src/subcommand/init/shell/mod.rs010066400017500001751000000005311366427470500173770ustar0000000000000000pub mod bash; pub mod fish; pub mod posix; pub mod powershell; pub mod zsh; use anyhow::Result; use std::borrow::Cow; pub struct ShellConfig { pub z: fn(&str) -> String, pub alias: fn(&str) -> String, pub hook: HookConfig, } pub struct HookConfig { pub prompt: &'static str, pub pwd: fn() -> Result>, } zoxide-0.4.3/src/subcommand/init/shell/posix.rs010066400017500001751000000061711367755154700177760ustar0000000000000000use super::{HookConfig, ShellConfig}; use crate::util; use anyhow::Result; use uuid::Uuid; use std::borrow::Cow; pub const CONFIG: ShellConfig = ShellConfig { z, alias, hook: HookConfig { prompt: HOOK_PROMPT, pwd: hook_pwd, }, }; fn z(cmd: &str) -> String { format!( r#" _z_cd() {{ cd "$@" || return "$?" if [ "$_ZO_ECHO" = "1" ]; then echo "$PWD" fi }} {0}() {{ if [ "$#" -eq 0 ]; then _z_cd ~ elif [ "$#" -eq 1 ] && [ "$1" = '-' ]; then if [ -n "$OLDPWD" ]; then _z_cd "$OLDPWD" else echo 'zoxide: $OLDPWD is not set' return 1 fi else _zoxide_result="$(zoxide query -- "$@")" && _z_cd "$_zoxide_result" fi }} {0}i() {{ _zoxide_result="$(zoxide query -i -- "$@")" && _z_cd "$_zoxide_result" }} "#, cmd ) } fn alias(cmd: &str) -> String { format!( r#" alias {0}a='zoxide add' alias {0}q='zoxide query' alias {0}qi='zoxide query -i' alias {0}r='zoxide remove' {0}ri() {{ _zoxide_result="$(zoxide query -i -- "$@")" && zoxide remove "$_zoxide_result" }} "#, cmd ) } const HOOK_PROMPT: &str = r#" _zoxide_hook() { zoxide add "$(pwd -L)" } case "$PS1" in *\$\(_zoxide_hook\)*) ;; *) PS1="\$(_zoxide_hook)${PS1}" ;; esac "#; fn hook_pwd() -> Result> { let mut tmp_path = std::env::temp_dir(); tmp_path.push("zoxide"); let tmp_path_str = util::path_to_str(&tmp_path)?; let pwd_path = tmp_path.join(format!("pwd-{}", Uuid::new_v4())); let pwd_path_str = util::path_to_str(&pwd_path)?; let hook_pwd = format!( r#" # PWD hooks in POSIX use a temporary file, located at `$_ZO_PWD_PATH`, to track # changes in the current directory. These files are removed upon restart, # but they should ideally also be cleaned up once the shell exits using traps. # # This can be done as follows: # # trap '_zoxide_cleanup' EXIT HUP KILL TERM # trap '_zoxide_cleanup; trap - INT; kill -s INT "$$"' INT # trap '_zoxide_cleanup; trap - QUIT; kill -s QUIT "$$"' QUIT # # By default, traps are not set up because they override all previous traps. # It is therefore up to the user to add traps to their shell configuration. _ZO_TMP_PATH={} _ZO_PWD_PATH={} _zoxide_cleanup() {{ rm -f "$_ZO_PWD_PATH" }} _zoxide_setpwd() {{ mkdir -p "$_ZO_TMP_PATH" echo "$PWD" > "$_ZO_PWD_PATH" }} _zoxide_setpwd _zoxide_hook() {{ _ZO_OLDPWD="$(cat "$_ZO_PWD_PATH")" if [ -z "$_ZO_OLDPWD" ] || [ "$_ZO_OLDPWD" != "$PWD" ]; then _zoxide_setpwd && zoxide add "$(pwd -L)" > /dev/null fi }} case "$PS1" in *\$\(_zoxide_hook\)*) ;; *) PS1="\$(_zoxide_hook)${{PS1}}" ;; esac"#, quote(tmp_path_str), quote(pwd_path_str), ); Ok(Cow::Owned(hook_pwd)) } fn quote(string: &str) -> String { let mut quoted = String::with_capacity(string.len() + 2); quoted.push('\''); for ch in string.chars() { match ch { '\\' => quoted.push_str(r"\\"), '\'' => quoted.push_str(r"'\''"), _ => quoted.push(ch), } } quoted.push('\''); quoted } zoxide-0.4.3/src/subcommand/init/shell/powershell.rs010066400017500001751000000033761367755154700210240ustar0000000000000000use super::{HookConfig, ShellConfig}; use anyhow::Result; use std::borrow::Cow; pub const CONFIG: ShellConfig = ShellConfig { z, alias, hook: HookConfig { prompt: HOOK_PROMPT, pwd: hook_pwd, }, }; fn z(cmd: &str) -> String { format!( r#" function _z_cd($dir) {{ Set-Location $dir -ea Stop if ($env:_ZO_ECHO -eq "1") {{ Write-Host "$PWD" }} }} function {0} {{ if ($args.Length -eq 0) {{ _z_cd ~ }} elseif ($args.Length -eq 1 -and $args[0] -eq '-') {{ _z_cd - }} else {{ $_zoxide_result = zoxide query -- @args if ($LASTEXITCODE -eq 0) {{ _z_cd $_zoxide_result }} }} }} function {0}i {{ $_zoxide_result = zoxide query -i -- @args if ($LASTEXITCODE -eq 0) {{ _z_cd $_zoxide_result }} }} "#, cmd ) } fn alias(cmd: &str) -> String { format!( r#" function {0}a {{ zoxide add @args }} function {0}q {{ zoxide query @args }} function {0}qi {{ zoxide query -i @args }} function {0}r {{ zoxide remove @args }} function {0}ri {{ $_zoxide_result = zoxide query -i -- @args if ($LASTEXITCODE -eq 0) {{ zoxide remove $_zoxide_result }} }} "#, cmd ) } const HOOK_PROMPT: &str = r#" $PreZoxidePrompt = $function:prompt function prompt { $null = zoxide add $(Get-Location) & $PreZoxidePrompt } "#; const fn hook_pwd() -> Result> { const HOOK_PWD: &str = r#" if ($PSVersionTable.PSVersion.Major -ge 6) { $ExecutionContext.InvokeCommand.LocationChangedAction = { $null = zoxide add $(Get-Location) } } else { Write-Error "pwd hook requires pwsh - use 'zoxide init powershell --hook prompt'" } "#; Ok(Cow::Borrowed(HOOK_PWD)) } zoxide-0.4.3/src/subcommand/init/shell/zsh.rs010066400017500001751000000012431367755154700174330ustar0000000000000000use super::{posix, HookConfig, ShellConfig}; use anyhow::Result; use std::borrow::Cow; pub const CONFIG: ShellConfig = ShellConfig { z: posix::CONFIG.z, alias: posix::CONFIG.alias, hook: HookConfig { prompt: HOOK_PROMPT, pwd: hook_pwd, }, }; const HOOK_PROMPT: &str = r#" _zoxide_hook() { zoxide add "$(pwd -L)" } [[ -n "${precmd_functions[(r)_zoxide_hook]}" ]] || { precmd_functions+=(_zoxide_hook) } "#; const fn hook_pwd() -> Result> { const HOOK_PWD: &str = r#" _zoxide_hook() { zoxide add "$(pwd -L)" } chpwd_functions=(${chpwd_functions[@]} "_zoxide_hook") "#; Ok(Cow::Borrowed(HOOK_PWD)) } zoxide-0.4.3/src/subcommand/mod.rs010066400017500001751000000002431366237774600153340ustar0000000000000000mod add; mod import; mod init; mod query; mod remove; pub use add::Add; pub use import::Import; pub use init::Init; pub use query::Query; pub use remove::Remove; zoxide-0.4.3/src/subcommand/query.rs010066400017500001751000000064221367571316300157160ustar0000000000000000use crate::db::Dir; use crate::fzf::Fzf; use crate::util; use anyhow::{bail, Context, Result}; use structopt::StructOpt; use std::io::{self, Write}; use std::path::Path; /// Search for a directory #[derive(Debug, StructOpt)] #[structopt()] pub struct Query { keywords: Vec, /// Opens an interactive selection menu using fzf #[structopt(short, long, conflicts_with = "list")] interactive: bool, /// List all matching directories #[structopt(short, long, conflicts_with = "interactive")] list: bool, /// Display score along with result #[structopt(short, long)] score: bool, } impl Query { pub fn run(&self) -> Result<()> { if self.list { return self.query_list(); } if self.interactive { return self.query_interactive(); } // if the input is already a valid path, simply print it as-is if let [path] = self.keywords.as_slice() { if Path::new(path).is_dir() { let dir = Dir { path: path.to_string(), rank: 0.0, last_accessed: 0, }; if self.score { println!("{}", dir.display_score(0)) } else { println!("{}", dir.display()); } return Ok(()); } } self.query() } fn query(&self) -> Result<()> { let mut db = util::get_db()?; let now = util::get_current_time()?; let mut matches = db.matches(now, &self.keywords); match matches.next() { Some(dir) => { if self.score { println!("{}", dir.display_score(now)) } else { println!("{}", dir.display()); } } None => bail!("no match found"), } Ok(()) } fn query_interactive(&self) -> Result<()> { let mut db = util::get_db()?; let now = util::get_current_time()?; let mut fzf = Fzf::new()?; let mut matches = db.matches(now, &self.keywords); while let Some(dir) = matches.next() { fzf.write(format!("{}", dir.display_score(now)))?; } match fzf.wait_select()? { Some(selection) => { if self.score { print!("{}", selection) } else { let selection = selection .get(5..) .with_context(|| format!("fzf returned invalid output: {}", selection))?; print!("{}", selection) } } None => bail!("no match found"), }; Ok(()) } fn query_list(&self) -> Result<()> { let mut db = util::get_db()?; let now = util::get_current_time()?; let mut matches = db.matches(now, &self.keywords); let stdout = io::stdout(); let mut handle = stdout.lock(); while let Some(dir) = matches.next() { if self.score { writeln!(handle, "{}", dir.display_score(now)) } else { writeln!(handle, "{}", dir.display()) } .unwrap(); } Ok(()) } } zoxide-0.4.3/src/subcommand/remove.rs010066400017500001751000000014561367755154700160600ustar0000000000000000use crate::util; use anyhow::{bail, Result}; use structopt::StructOpt; /// Remove a directory #[derive(Debug, StructOpt)] #[structopt()] pub struct Remove { path: String, } impl Remove { pub fn run(&self) -> Result<()> { remove(&self.path) } } fn remove(path: &str) -> Result<()> { let mut db = util::get_db()?; if let Some(idx) = db.dirs.iter().position(|dir| dir.path == path) { db.dirs.swap_remove(idx); db.modified = true; return Ok(()); } let path = util::resolve_path(&path)?; let path = util::path_to_str(&path)?; if let Some(idx) = db.dirs.iter().position(|dir| dir.path == path) { db.dirs.swap_remove(idx); db.modified = true; return Ok(()); } bail!("could not find path in database: {}", path) } zoxide-0.4.3/src/util.rs010066400017500001751000000124351367755154700134070ustar0000000000000000use crate::config; use crate::db::{Db, Epoch}; use anyhow::{bail, Context, Result}; use std::env; use std::path::{Component, Path, PathBuf}; use std::time::SystemTime; pub fn get_db() -> Result { let data_dir = config::zo_data_dir()?; Db::open(data_dir) } pub fn get_current_time() -> Result { let current_time = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .context("system clock set to invalid time")? .as_secs(); Ok(current_time as _) } pub fn canonicalize>(path: &P) -> Result { let path = path.as_ref(); dunce::canonicalize(path).with_context(|| format!("could not resolve path: {}", path.display())) } /// Resolves the absolute version of a path. /// /// If path is already absolute, the path is still processed to be cleaned, as it can contained ".." or "." (or other) /// character. /// If path is relative, use the current directory to build the absolute path. #[cfg(any(unix, windows))] pub fn resolve_path>(path: P) -> Result { let path = path.as_ref(); let base_path; let mut components = path.components().peekable(); let mut stack = Vec::new(); // initialize root if cfg!(unix) { match components.peek() { Some(Component::RootDir) => { let root = components.next().unwrap(); stack.push(root); } _ => { base_path = get_current_dir()?; stack.extend(base_path.components()); } } } else if cfg!(windows) { use std::path::Prefix; fn get_drive_letter>(path: P) -> Option { let path = path.as_ref(); let mut components = path.components(); match components.next() { Some(Component::Prefix(prefix)) => match prefix.kind() { Prefix::Disk(drive_letter) | Prefix::VerbatimDisk(drive_letter) => { Some(drive_letter) } _ => None, }, _ => None, } } fn get_drive_path(drive_letter: u8) -> PathBuf { format!(r"{}:\", drive_letter as char).into() } fn get_drive_relative(drive_letter: u8) -> Result { let path = get_current_dir()?; if Some(drive_letter) == get_drive_letter(&path) { return Ok(path); } if let Some(path) = env::var_os(format!("={}:", drive_letter as char)) { return Ok(path.into()); } let path = get_drive_path(drive_letter); Ok(path) } match components.peek() { Some(Component::Prefix(prefix)) => match prefix.kind() { Prefix::Disk(drive_letter) => { let disk = components.next().unwrap(); match components.peek() { Some(Component::RootDir) => { let root = components.next().unwrap(); stack.push(disk); stack.push(root); } _ => { base_path = get_drive_relative(drive_letter)?; stack.extend(base_path.components()); } } } Prefix::VerbatimDisk(drive_letter) => { components.next(); if components.peek() == Some(&Component::RootDir) { components.next(); } base_path = get_drive_path(drive_letter); stack.extend(base_path.components()); } _ => bail!("invalid path: {}", path.display()), }, Some(Component::RootDir) => { components.next(); let current_dir = env::current_dir()?; let drive_letter = get_drive_letter(¤t_dir).with_context(|| { format!("could not get drive letter: {}", current_dir.display()) })?; base_path = get_drive_path(drive_letter); stack.extend(base_path.components()); } _ => { base_path = get_current_dir()?; stack.extend(base_path.components()); } } } for component in components { match component { Component::Normal(_) => stack.push(component), Component::CurDir => (), Component::ParentDir => { if stack.last() != Some(&Component::RootDir) { stack.pop(); } } Component::Prefix(_) | Component::RootDir => unreachable!(), } } let result = stack.iter().collect::(); if !result.is_dir() { bail!("could not resolve path: {}", result.display()); } Ok(result) } pub fn get_current_dir() -> Result { env::current_dir().context("could not get current path") } pub fn path_to_str>(path: &P) -> Result<&str> { let path = path.as_ref(); path.to_str() .with_context(|| format!("invalid utf-8 sequence in path: {}", path.display())) } zoxide-0.4.3/zoxide.plugin.zsh010066400017500001751000000000321366237774600146110ustar0000000000000000eval "$(zoxide init zsh)"