From f618f47811640ddc867cdb023fa9f252f1ee7915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Forment?= Date: Thu, 26 Feb 2026 18:54:01 +0100 Subject: [PATCH] WIP: multi-platform builds pipeline --- .cargo/config.toml | 5 + .github/workflows/ci.yml | 248 +---------------- .github/workflows/release.yml | 368 +++++++++++++++++++++++++ .gitignore | 5 +- BUILDING.md | 96 +++++++ Cargo.toml | 2 +- Cross.toml | 9 +- assets/Cagire.png | Bin 26749 -> 73360 bytes assets/cagire.desktop | 7 + build.rs | 9 + crates/ratatui/Cargo.toml | 2 +- cross/x86_64-linux.Dockerfile | 14 + cross/x86_64-windows.Dockerfile | 13 + plugins/cagire-plugins/Cargo.toml | 2 +- scripts/build-all.sh | 428 ++++++++++++++++++++++++++++++ scripts/make-appimage.sh | 136 ++++++++++ 16 files changed, 1097 insertions(+), 247 deletions(-) create mode 100644 .cargo/config.toml create mode 100644 .github/workflows/release.yml create mode 100644 assets/cagire.desktop create mode 100644 cross/x86_64-linux.Dockerfile create mode 100644 cross/x86_64-windows.Dockerfile create mode 100755 scripts/build-all.sh create mode 100755 scripts/make-appimage.sh diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..e47423c --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,5 @@ +[alias] +xtask = "run --package xtask --release --" + +[target.x86_64-pc-windows-gnu] +rustflags = ["-C", "link-args=-lstdc++ -lws2_32 -liphlpapi -lwinmm"] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f659a9c..cd9701c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,8 @@ name: CI on: - workflow_dispatch: push: - tags: ['v*'] + branches: [main] pull_request: branches: [main] @@ -15,26 +14,20 @@ concurrency: cancel-in-progress: true jobs: - build: + check: strategy: fail-fast: false matrix: include: - os: ubuntu-latest target: x86_64-unknown-linux-gnu - artifact: cagire-linux-x86_64 - - os: macos-15-intel - target: x86_64-apple-darwin - artifact: cagire-macos-x86_64 - os: macos-14 target: aarch64-apple-darwin - artifact: cagire-macos-aarch64 - os: windows-latest target: x86_64-pc-windows-msvc - artifact: cagire-windows-x86_64 runs-on: ${{ matrix.os }} - timeout-minutes: 30 + timeout-minutes: 20 steps: - uses: actions/checkout@v4 @@ -45,6 +38,7 @@ jobs: uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} + components: clippy - name: Cache Rust dependencies uses: Swatinem/rust-cache@v2 @@ -57,13 +51,10 @@ jobs: sudo apt-get update sudo apt-get install -y build-essential cmake pkg-config libasound2-dev libclang-dev libjack-dev \ libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libssl-dev libgl1-mesa-dev - cargo install cargo-bundle - name: Install dependencies (macOS) if: runner.os == 'macOS' - run: | - brew list cmake &>/dev/null || brew install cmake - cargo install cargo-bundle + run: brew list cmake &>/dev/null || brew install cmake - name: Install dependencies (Windows) if: runner.os == 'Windows' @@ -77,229 +68,8 @@ jobs: - name: Build desktop run: cargo build --release --features desktop --bin cagire-desktop --target ${{ matrix.target }} - - name: Bundle desktop app - if: runner.os != 'Windows' - run: cargo bundle --release --features desktop --bin cagire-desktop --target ${{ matrix.target }} + - name: Test + run: cargo test --target ${{ matrix.target }} - - name: Bundle CLAP plugin - run: cargo xtask bundle cagire-plugins --release --target ${{ matrix.target }} - - - name: Zip macOS app bundle - if: runner.os == 'macOS' - run: | - cd target/${{ matrix.target }}/release/bundle/osx - zip -r Cagire.app.zip Cagire.app - - - name: Upload artifact (Unix) - if: runner.os != 'Windows' - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }} - path: target/${{ matrix.target }}/release/cagire - - - name: Upload artifact (Windows) - if: runner.os == 'Windows' - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }} - path: target/${{ matrix.target }}/release/cagire.exe - - - name: Upload desktop artifact (Linux deb) - if: runner.os == 'Linux' - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }}-desktop - path: target/${{ matrix.target }}/release/bundle/deb/*.deb - - - name: Upload desktop artifact (macOS app bundle) - if: runner.os == 'macOS' - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }}-desktop - path: target/${{ matrix.target }}/release/bundle/osx/Cagire.app.zip - - - name: Upload desktop artifact (Windows exe) - if: runner.os == 'Windows' - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }}-desktop - path: target/${{ matrix.target }}/release/cagire-desktop.exe - - - name: Upload CLAP artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }}-clap - path: target/bundled/cagire-plugins.clap - - - name: Upload VST3 artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.artifact }}-vst3 - path: target/bundled/cagire-plugins.vst3 - - universal-macos: - needs: build - if: startsWith(github.ref, 'refs/tags/v') - runs-on: macos-14 - timeout-minutes: 10 - - steps: - - name: Download macOS artifacts - uses: actions/download-artifact@v4 - with: - pattern: cagire-macos-* - path: artifacts - - - name: Create universal CLI binary - run: | - lipo -create \ - artifacts/cagire-macos-x86_64/cagire \ - artifacts/cagire-macos-aarch64/cagire \ - -output cagire - chmod +x cagire - lipo -info cagire - - - name: Create universal app bundle - run: | - cd artifacts/cagire-macos-aarch64-desktop - unzip Cagire.app.zip - cd ../cagire-macos-x86_64-desktop - unzip Cagire.app.zip - cd ../.. - cp -R artifacts/cagire-macos-aarch64-desktop/Cagire.app Cagire.app - lipo -create \ - artifacts/cagire-macos-x86_64-desktop/Cagire.app/Contents/MacOS/cagire-desktop \ - artifacts/cagire-macos-aarch64-desktop/Cagire.app/Contents/MacOS/cagire-desktop \ - -output Cagire.app/Contents/MacOS/cagire-desktop - lipo -info Cagire.app/Contents/MacOS/cagire-desktop - zip -r Cagire.app.zip Cagire.app - - - name: Create universal CLAP plugin - run: | - mkdir -p cagire-plugins.clap/Contents/MacOS - cp artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/Info.plist \ - cagire-plugins.clap/Contents/ 2>/dev/null || true - cp artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/PkgInfo \ - cagire-plugins.clap/Contents/ 2>/dev/null || true - lipo -create \ - artifacts/cagire-macos-x86_64-clap/cagire-plugins.clap/Contents/MacOS/cagire-plugins \ - artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/MacOS/cagire-plugins \ - -output cagire-plugins.clap/Contents/MacOS/cagire-plugins - lipo -info cagire-plugins.clap/Contents/MacOS/cagire-plugins - - - name: Create universal VST3 plugin - run: | - mkdir -p cagire-plugins.vst3/Contents/MacOS - cp -R artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/Info.plist \ - cagire-plugins.vst3/Contents/ 2>/dev/null || true - cp artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/PkgInfo \ - cagire-plugins.vst3/Contents/ 2>/dev/null || true - cp -R artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/Resources \ - cagire-plugins.vst3/Contents/ 2>/dev/null || true - lipo -create \ - artifacts/cagire-macos-x86_64-vst3/cagire-plugins.vst3/Contents/MacOS/cagire-plugins \ - artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/MacOS/cagire-plugins \ - -output cagire-plugins.vst3/Contents/MacOS/cagire-plugins - lipo -info cagire-plugins.vst3/Contents/MacOS/cagire-plugins - - - name: Build .pkg installer - run: | - VERSION="${GITHUB_REF_NAME#v}" - mkdir -p pkg-root/Applications pkg-root/usr/local/bin - cp -R Cagire.app pkg-root/Applications/ - cp cagire pkg-root/usr/local/bin/ - pkgbuild --analyze --root pkg-root component.plist - plutil -replace BundleIsRelocatable -bool NO component.plist - pkgbuild --root pkg-root --identifier com.sova.cagire \ - --version "$VERSION" --install-location / \ - --component-plist component.plist \ - "Cagire-${VERSION}-universal.pkg" - - - name: Upload universal CLI - uses: actions/upload-artifact@v4 - with: - name: cagire-macos-universal - path: cagire - - - name: Upload universal app bundle - uses: actions/upload-artifact@v4 - with: - name: cagire-macos-universal-desktop - path: Cagire.app.zip - - - name: Upload universal CLAP plugin - uses: actions/upload-artifact@v4 - with: - name: cagire-macos-universal-clap - path: cagire-plugins.clap - - - name: Upload universal VST3 plugin - uses: actions/upload-artifact@v4 - with: - name: cagire-macos-universal-vst3 - path: cagire-plugins.vst3 - - - name: Upload .pkg installer - uses: actions/upload-artifact@v4 - with: - name: cagire-macos-universal-pkg - path: Cagire-*-universal.pkg - - release: - needs: [build, universal-macos] - if: startsWith(github.ref, 'refs/tags/v') - runs-on: ubuntu-latest - timeout-minutes: 10 - permissions: - contents: write - - steps: - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: artifacts - - - name: Prepare release files - run: | - mkdir -p release - for dir in artifacts/*/; do - name=$(basename "$dir") - if [[ "$name" == "cagire-macos-universal-pkg" ]]; then - cp "$dir"/*.pkg release/ - elif [[ "$name" == "cagire-macos-universal-desktop" ]]; then - cp "$dir/Cagire.app.zip" "release/cagire-macos-universal-desktop.app.zip" - elif [[ "$name" == "cagire-macos-universal" ]]; then - cp "$dir/cagire" "release/cagire-macos-universal" - elif [[ "$name" == "cagire-macos-universal-clap" ]]; then - cd "$dir" && zip -r "../../release/cagire-macos-universal-clap.zip" cagire-plugins.clap && cd ../.. - elif [[ "$name" == "cagire-macos-universal-vst3" ]]; then - cd "$dir" && zip -r "../../release/cagire-macos-universal-vst3.zip" cagire-plugins.vst3 && cd ../.. - elif [[ "$name" == *-clap ]]; then - base="${name%-clap}" - cd "$dir" && zip -r "../../release/${base}-clap.zip" cagire-plugins.clap && cd ../.. - elif [[ "$name" == *-vst3 ]]; then - base="${name%-vst3}" - cd "$dir" && zip -r "../../release/${base}-vst3.zip" cagire-plugins.vst3 && cd ../.. - elif [[ "$name" == *-desktop ]]; then - base="${name%-desktop}" - if ls "$dir"/*.deb 1>/dev/null 2>&1; then - cp "$dir"/*.deb "release/${base}-desktop.deb" - elif [ -f "$dir/Cagire.app.zip" ]; then - cp "$dir/Cagire.app.zip" "release/${base}-desktop.app.zip" - elif [ -f "$dir/cagire-desktop.exe" ]; then - cp "$dir/cagire-desktop.exe" "release/${base}-desktop.exe" - fi - else - if [ -f "$dir/cagire.exe" ]; then - cp "$dir/cagire.exe" "release/${name}.exe" - elif [ -f "$dir/cagire" ]; then - cp "$dir/cagire" "release/${name}" - fi - fi - done - - - name: Create Release - uses: softprops/action-gh-release@v2 - with: - files: release/* - generate_release_notes: true + - name: Clippy + run: cargo clippy --target ${{ matrix.target }} -- -D warnings diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..7915fde --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,368 @@ +name: Release + +on: + workflow_dispatch: + push: + tags: ['v*'] + +env: + CARGO_TERM_COLOR: always + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + artifact: cagire-linux-x86_64 + - os: macos-15-intel + target: x86_64-apple-darwin + artifact: cagire-macos-x86_64 + - os: macos-14 + target: aarch64-apple-darwin + artifact: cagire-macos-aarch64 + - os: windows-latest + target: x86_64-pc-windows-msvc + artifact: cagire-windows-x86_64 + + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} + + - name: Install cargo-binstall + uses: cargo-bins/cargo-binstall@main + + - name: Install dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y build-essential cmake pkg-config libasound2-dev libclang-dev libjack-dev \ + libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev libssl-dev libgl1-mesa-dev + cargo binstall -y cargo-bundle + + - name: Install dependencies (macOS) + if: runner.os == 'macOS' + run: | + brew list cmake &>/dev/null || brew install cmake + cargo binstall -y cargo-bundle + + - name: Install dependencies (Windows) + if: runner.os == 'Windows' + run: | + choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System' + echo "C:\Program Files\CMake\bin" >> $env:GITHUB_PATH + + - name: Build + run: cargo build --release --target ${{ matrix.target }} + + - name: Build desktop + run: cargo build --release --features desktop --bin cagire-desktop --target ${{ matrix.target }} + + - name: Bundle desktop app + if: runner.os != 'Windows' + run: cargo bundle --release --features desktop --bin cagire-desktop --target ${{ matrix.target }} + + - name: Build AppImages (Linux) + if: runner.os == 'Linux' + run: | + mkdir -p target/releases + scripts/make-appimage.sh target/${{ matrix.target }}/release/cagire x86_64 target/releases + scripts/make-appimage.sh target/${{ matrix.target }}/release/cagire-desktop x86_64 target/releases + + - name: Upload AppImage artifacts (Linux) + if: runner.os == 'Linux' + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact }}-appimage + path: target/releases/*.AppImage + + - name: Bundle CLAP plugin + run: cargo xtask bundle cagire-plugins --release --target ${{ matrix.target }} + + - name: Zip macOS app bundle + if: runner.os == 'macOS' + run: | + cd target/${{ matrix.target }}/release/bundle/osx + zip -r Cagire.app.zip Cagire.app + + - name: Upload artifact (Unix) + if: runner.os != 'Windows' + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact }} + path: target/${{ matrix.target }}/release/cagire + + - name: Upload artifact (Windows) + if: runner.os == 'Windows' + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact }} + path: target/${{ matrix.target }}/release/cagire.exe + + - name: Upload desktop artifact (Linux deb) + if: runner.os == 'Linux' + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact }}-desktop + path: target/${{ matrix.target }}/release/bundle/deb/*.deb + + - name: Upload desktop artifact (macOS app bundle) + if: runner.os == 'macOS' + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact }}-desktop + path: target/${{ matrix.target }}/release/bundle/osx/Cagire.app.zip + + - name: Upload desktop artifact (Windows exe) + if: runner.os == 'Windows' + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact }}-desktop + path: target/${{ matrix.target }}/release/cagire-desktop.exe + + - name: Upload CLAP artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact }}-clap + path: target/bundled/cagire-plugins.clap + + - name: Upload VST3 artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact }}-vst3 + path: target/bundled/cagire-plugins.vst3 + + build-cross: + runs-on: ubuntu-latest + timeout-minutes: 45 + + strategy: + fail-fast: false + matrix: + include: + - target: aarch64-unknown-linux-gnu + artifact: cagire-linux-aarch64 + + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.target }} + + - name: Install cross + run: cargo install cross --git https://github.com/cross-rs/cross + + - name: Build + run: cross build --release --target ${{ matrix.target }} + + - name: Build desktop + run: cross build --release --features desktop --bin cagire-desktop --target ${{ matrix.target }} + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact }} + path: target/${{ matrix.target }}/release/cagire + + - name: Upload desktop artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact }}-desktop + path: target/${{ matrix.target }}/release/cagire-desktop + + universal-macos: + needs: build + runs-on: macos-14 + timeout-minutes: 10 + + steps: + - name: Download macOS artifacts + uses: actions/download-artifact@v4 + with: + pattern: cagire-macos-* + path: artifacts + + - name: Create universal CLI binary + run: | + lipo -create \ + artifacts/cagire-macos-x86_64/cagire \ + artifacts/cagire-macos-aarch64/cagire \ + -output cagire + chmod +x cagire + lipo -info cagire + + - name: Create universal app bundle + run: | + cd artifacts/cagire-macos-aarch64-desktop + unzip Cagire.app.zip + cd ../cagire-macos-x86_64-desktop + unzip Cagire.app.zip + cd ../.. + cp -R artifacts/cagire-macos-aarch64-desktop/Cagire.app Cagire.app + lipo -create \ + artifacts/cagire-macos-x86_64-desktop/Cagire.app/Contents/MacOS/cagire-desktop \ + artifacts/cagire-macos-aarch64-desktop/Cagire.app/Contents/MacOS/cagire-desktop \ + -output Cagire.app/Contents/MacOS/cagire-desktop + lipo -info Cagire.app/Contents/MacOS/cagire-desktop + zip -r Cagire.app.zip Cagire.app + + - name: Create universal CLAP plugin + run: | + mkdir -p cagire-plugins.clap/Contents/MacOS + cp artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/Info.plist \ + cagire-plugins.clap/Contents/ 2>/dev/null || true + cp artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/PkgInfo \ + cagire-plugins.clap/Contents/ 2>/dev/null || true + lipo -create \ + artifacts/cagire-macos-x86_64-clap/cagire-plugins.clap/Contents/MacOS/cagire-plugins \ + artifacts/cagire-macos-aarch64-clap/cagire-plugins.clap/Contents/MacOS/cagire-plugins \ + -output cagire-plugins.clap/Contents/MacOS/cagire-plugins + lipo -info cagire-plugins.clap/Contents/MacOS/cagire-plugins + + - name: Create universal VST3 plugin + run: | + mkdir -p cagire-plugins.vst3/Contents/MacOS + cp -R artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/Info.plist \ + cagire-plugins.vst3/Contents/ 2>/dev/null || true + cp artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/PkgInfo \ + cagire-plugins.vst3/Contents/ 2>/dev/null || true + cp -R artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/Resources \ + cagire-plugins.vst3/Contents/ 2>/dev/null || true + lipo -create \ + artifacts/cagire-macos-x86_64-vst3/cagire-plugins.vst3/Contents/MacOS/cagire-plugins \ + artifacts/cagire-macos-aarch64-vst3/cagire-plugins.vst3/Contents/MacOS/cagire-plugins \ + -output cagire-plugins.vst3/Contents/MacOS/cagire-plugins + lipo -info cagire-plugins.vst3/Contents/MacOS/cagire-plugins + + - name: Build .pkg installer + run: | + VERSION="${GITHUB_REF_NAME#v}" + mkdir -p pkg-root/Applications pkg-root/usr/local/bin + cp -R Cagire.app pkg-root/Applications/ + cp cagire pkg-root/usr/local/bin/ + pkgbuild --analyze --root pkg-root component.plist + plutil -replace BundleIsRelocatable -bool NO component.plist + pkgbuild --root pkg-root --identifier com.sova.cagire \ + --version "$VERSION" --install-location / \ + --component-plist component.plist \ + "Cagire-${VERSION}-universal.pkg" + + - name: Upload universal CLI + uses: actions/upload-artifact@v4 + with: + name: cagire-macos-universal + path: cagire + + - name: Upload universal app bundle + uses: actions/upload-artifact@v4 + with: + name: cagire-macos-universal-desktop + path: Cagire.app.zip + + - name: Upload universal CLAP plugin + uses: actions/upload-artifact@v4 + with: + name: cagire-macos-universal-clap + path: cagire-plugins.clap + + - name: Upload universal VST3 plugin + uses: actions/upload-artifact@v4 + with: + name: cagire-macos-universal-vst3 + path: cagire-plugins.vst3 + + - name: Upload .pkg installer + uses: actions/upload-artifact@v4 + with: + name: cagire-macos-universal-pkg + path: Cagire-*-universal.pkg + + release: + needs: [build, build-cross, universal-macos] + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: write + + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Prepare release files + run: | + mkdir -p release + for dir in artifacts/*/; do + name=$(basename "$dir") + if [[ "$name" == "cagire-macos-universal-pkg" ]]; then + cp "$dir"/*.pkg release/ + elif [[ "$name" == "cagire-macos-universal-desktop" ]]; then + cp "$dir/Cagire.app.zip" "release/cagire-macos-universal-desktop.app.zip" + elif [[ "$name" == "cagire-macos-universal" ]]; then + cp "$dir/cagire" "release/cagire-macos-universal" + elif [[ "$name" == "cagire-macos-universal-clap" ]]; then + cd "$dir" && zip -r "../../release/cagire-macos-universal-clap.zip" cagire-plugins.clap && cd ../.. + elif [[ "$name" == "cagire-macos-universal-vst3" ]]; then + cd "$dir" && zip -r "../../release/cagire-macos-universal-vst3.zip" cagire-plugins.vst3 && cd ../.. + elif [[ "$name" == *-clap ]]; then + base="${name%-clap}" + cd "$dir" && zip -r "../../release/${base}-clap.zip" cagire-plugins.clap && cd ../.. + elif [[ "$name" == *-vst3 ]]; then + base="${name%-vst3}" + cd "$dir" && zip -r "../../release/${base}-vst3.zip" cagire-plugins.vst3 && cd ../.. + elif [[ "$name" == *-appimage ]]; then + cp "$dir"/*.AppImage release/ + elif [[ "$name" == *-desktop ]]; then + base="${name%-desktop}" + if ls "$dir"/*.deb 1>/dev/null 2>&1; then + cp "$dir"/*.deb "release/${base}-desktop.deb" + elif [ -f "$dir/Cagire.app.zip" ]; then + cp "$dir/Cagire.app.zip" "release/${base}-desktop.app.zip" + elif [ -f "$dir/cagire-desktop.exe" ]; then + cp "$dir/cagire-desktop.exe" "release/${base}-desktop.exe" + fi + else + if [ -f "$dir/cagire.exe" ]; then + cp "$dir/cagire.exe" "release/${name}.exe" + elif [ -f "$dir/cagire" ]; then + cp "$dir/cagire" "release/${name}" + fi + fi + done + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + files: release/* + generate_release_notes: true diff --git a/.gitignore b/.gitignore index 80bdebb..ddc5aa4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,11 @@ /target +/.cache Cargo.lock *.prof .DS_Store -# Cargo config -.cargo/config.toml +# Local cargo overrides (doux path patch) +.cargo/config.local.toml # Claude .claude/ diff --git a/BUILDING.md b/BUILDING.md index 5bfd0ea..5b2a3b2 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1,5 +1,15 @@ # Building Cagire +## Quick Start + +```bash +git clone --recursive https://github.com/Bubobubobubobubo/cagire +cd cagire +cargo build --release +``` + +The `doux` audio engine is fetched automatically from git. No local path setup needed. + ## Prerequisites **Rust** (stable toolchain): https://rustup.rs @@ -68,6 +78,14 @@ Desktop (egui window): cargo build --release --features desktop --bin cagire-desktop ``` +Plugins (CLAP/VST3): + +```bash +cargo xtask bundle cagire-plugins --release +``` + +The xtask alias is defined in `.cargo/config.toml` (committed). Plugin bundles are output to `target/bundled/`. + ## Run Terminal (default): @@ -89,3 +107,81 @@ cargo run --release --features desktop --bin cagire-desktop | `-i, --input ` | Input audio device | | `-c, --channels ` | Output channel count | | `-b, --buffer ` | Audio buffer size | + +## Cross-Compilation + +[cross](https://github.com/cross-rs/cross) uses Docker to build for other platforms without installing their toolchains locally. It works on any OS that runs Docker. + +### Targets + +| Target | Method | Binaries | +|--------|--------|----------| +| aarch64-apple-darwin | Native (macOS ARM only) | `cagire`, `cagire-desktop` | +| x86_64-apple-darwin | Native (macOS only) | `cagire`, `cagire-desktop` | +| x86_64-unknown-linux-gnu | `cross build` | `cagire`, `cagire-desktop` | +| aarch64-unknown-linux-gnu (RPi 64-bit) | `cross build` | `cagire`, `cagire-desktop` | +| x86_64-pc-windows-gnu | `cross build` | `cagire`, `cagire-desktop` | + +macOS targets can only be built on macOS — Apple does not support cross-compilation to macOS from other platforms. Linux and Windows targets can be cross-compiled from any OS. The aarch64-unknown-linux-gnu target covers Raspberry Pi (64-bit OS). + +### Windows ABI + +CI produces `x86_64-pc-windows-msvc` binaries (native Windows build, better compatibility). Local cross-compilation from non-Windows hosts produces `x86_64-pc-windows-gnu` binaries (MinGW via Docker). Both work; MSVC is preferred for releases. + +### Prerequisites + +1. **Docker**: https://docs.docker.com/get-docker/ +2. **cross**: `cargo install cross --git https://github.com/cross-rs/cross` +3. On macOS, add the Intel target: `rustup target add x86_64-apple-darwin` + +Docker must be running before invoking `cross` or `scripts/build-all.sh`. + +### Building Individual Targets + +```bash +# Linux x86_64 +cross build --release --target x86_64-unknown-linux-gnu +cross build --release --features desktop --bin cagire-desktop --target x86_64-unknown-linux-gnu + +# Linux aarch64 +cross build --release --target aarch64-unknown-linux-gnu +cross build --release --features desktop --bin cagire-desktop --target aarch64-unknown-linux-gnu + +# Windows x86_64 +cross build --release --target x86_64-pc-windows-gnu +cross build --release --features desktop --bin cagire-desktop --target x86_64-pc-windows-gnu +``` + +### Building All Targets (macOS only) + +```bash +# Interactive (prompts for platform/target selection): +scripts/build-all.sh + +# Non-interactive: +scripts/build-all.sh --platforms macos-arm64,linux-x86_64 --targets cli,desktop --yes +scripts/build-all.sh --all --yes +``` + +Builds selected targets, producing binaries in `target/releases/`. + +Platform aliases: `macos-arm64`, `macos-x86_64`, `linux-x86_64`, `linux-aarch64`, `windows-x86_64`. +Target aliases: `cli`, `desktop`, `plugins`. + +### Linux AppImage Packaging + +Linux releases ship as AppImages — self-contained executables that bundle all shared library dependencies (ALSA, JACK, X11, OpenGL). No runtime dependencies required. + +After building a Linux target, produce an AppImage with: + +```bash +scripts/make-appimage.sh target/x86_64-unknown-linux-gnu/release/cagire x86_64 target/releases +``` + +`scripts/build-all.sh` does this automatically for every Linux target selected. The CI pipeline produces AppImages for the x86_64 Linux build. Cross-arch AppImage building (e.g. aarch64 on x86_64) is not supported — run on a matching host or in CI. + +### Notes + +- Custom Dockerfiles in `cross/` install the native libraries Cagire depends on (ALSA, JACK, X11, cmake, libclang, etc.). `Cross.toml` maps each target to its Dockerfile. +- The first build per target downloads Docker base images and installs packages. Subsequent builds use cached layers. +- Cross-architecture Docker builds (e.g. aarch64 on x86_64 or vice versa) run under QEMU emulation and are significantly slower. diff --git a/Cargo.toml b/Cargo.toml index aaff0b3..35ca3d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ cagire-forth = { path = "crates/forth" } cagire-markdown = { path = "crates/markdown" } cagire-project = { path = "crates/project" } cagire-ratatui = { path = "crates/ratatui" } -doux = { path = "/Users/bubo/doux", features = ["native", "soundfont"] } +doux = { git = "https://github.com/sova-org/doux", features = ["native", "soundfont"] } rusty_link = "0.4" ratatui = "0.30" crossterm = "0.29" diff --git a/Cross.toml b/Cross.toml index bb0fdf4..c1c90f4 100644 --- a/Cross.toml +++ b/Cross.toml @@ -1,5 +1,8 @@ -[build] -volumes = ["/Users/bubo/doux:/Users/bubo/doux"] - [target.aarch64-unknown-linux-gnu] dockerfile = "./cross/aarch64-linux.Dockerfile" + +[target.x86_64-unknown-linux-gnu] +dockerfile = "./cross/x86_64-linux.Dockerfile" + +[target.x86_64-pc-windows-gnu] +dockerfile = "./cross/x86_64-windows.Dockerfile" diff --git a/assets/Cagire.png b/assets/Cagire.png index f7a4b2381694f8bcf68f3d7227f1b3cd4c9788c3..092177d9ce00df43c079790950cff69678601b68 100644 GIT binary patch literal 73360 zcmeFZ^;?_Y(l?qAAb5~s#i2!tI|P>^MO)ee#T|;fLny_HwiMSwfzo1y;uhSkxCeKa zAOQ~D``i6I*LlzT2b}BL$q!lgS~IhJ<}7r!siw9rwuR8s>yxldyO(164M(0vMc{{@8E0MP%H1_16Q-G4yY!2c=D zM*CZe2FM2ePx=ob<>R!p`$qEFywq{iQB#GQIoflXm^+$UaCzA~{UHE|dqMA$_7-j? z^j`LM4z5ry3C4d>K=0Fkvbh=Q|3%_vE5WFvrb#d7=wd-H#KptK!zhVEPfsuIVr~h2 zA+PWc`~8yyqqUox6O^0V)6nBiF>#(cMjgk?~JO|M~p8ofcj;|5KBL>p$JP?;!V|5^i2D z9`64yHa8o~{|nonl7F-Pt6%@FPW+EBsHTmVg`KXvjlG3~>wVKCMFn}q|5eTZQSv_x z{a>6q|5wicRr3GllykImbkTA$F|&~TTiO50`d`$4+6~okv9Y)x(mw1O0BL}-yv$24;BKRCoJE&6bE0Q)p6!mm zTyBs9KpsRd4S0mU|KRC!Cflz^)`{WRVy3MwBIbIK0JrxvX4me9sC93rDPBX%R+4hg zXpRqWl%738Mtm7>-zU!Pl^Z$(f*xjOcV#CfBN?+ zP7d81uv+%}mH8iP*gX{=;4A1ayGu9>4@UjE?gPia%Vec7VQ&8sO>i$MuI-uj$B;jK z_dMNzID&sy3nT1ixR>Ojv-PC>Z_Si|-@w0>h{{W2N)xafJSF?X_lE~04gIG9vh-p1 zlDbXuesuqBhdDqA{IAB{XRHzeDFLEIZlt>ZbPRWC>vJA3pudMp!0rK?Z}z80IfNAGK~T)Q(k!oGasSOSo2n|0ms|-d z>u18H$x_!X-de?<8J&%-9(>2B*hnd7bDPBo4(E7yZzJ{@?}6Js<3;ZqEW5{OoDG+B zX~{fR1hfMAwUwAKwuJt?O5ll1BAj}TKIZ57z`=qU{ok`->`6}# zGWHw`{`wcMmE~etV;d_jy|$D!-XX+lyzyRK$fp6kep_vUyB zwCt%{rLP8*M7M-yqN{3e-g5GxU#-et_KrT~4>ADl*%SWMIQO~7zS1!1-=BiPb);yr z#z;o#f@^R=e*bB=lE86SjtdLmu8Qda;>KutBLf4#@Wyt^i6=HC42bDA^EjmSyt|5K zjZ}ldshNo$ga{}#NjPYF3Uj>TytN;NEn-l2I*1L|a|WW;;8KXwW;G#td+mh}_XA+u zN2KXG=c3f1`47y6?<-341L~V&9+{{UB38Zn8V!6c9E6Ti_Zrt`mEGnJPR*eic$3a> zO+|VAU#W7>f&|W~g9zfkWqVkfD7~hYuX}JWmE_M1p<6#=M6Y@XjPW<4*oYNKS26n3 zwzQ(CmiI>4`y$Edd>@M%==rvPm9Nb?o$n$VtdYuhY=K~qw(V0pnGA{DV~~kxmngC3 zDXJXU_D*M}z%rD0)B3YjiM$<&_-cK>hN=Mf7+nvLqk|PB_7t|VApgTY)5ylnV_G!R z2znDv8PrB+SZ(n6#(vq}Pp|sMyLMy}q2-HA>4G4VO@yg{a>h0$<9^LfBLakz2fhHm zg*Ogqd0B$ugEjI?R+b;~+nGWw0AGKOWDrg%-1{$fOf{yQ=%F$&Go#>O^SJQQ{WVJv zf!9(z%qh)ruND+-e#m9IkXepTs@WtvwNr)&*ZwoYRzz_mh{5IJxxZRq7w2Bs?uWN= zgnu0m53(R9J_jpTZHGTziPL-&nd*kCOEYHd6?6VnJ@eIk>a~AV!c8x|Z*KPCo_WWT zBv<1HX7qi6KYNH^zgMsTYd9^l0D1GIVM}b#4gRhVF^6#|ok2IR7KXFw**ndhaY8U} zauaw)T}8gE+4gdYNXp}3J?KddmdrH6$meLnnyh;-%Smdoq_=8^5FsM;yg1cS((j1{ zKtyJivgGvi92t$F=qq(o;y>0X7{`Jallk?YJmIAU5n4U?eirHrxE?9rFPK@By2DaE zxp8F}DCAwQ9Gkp6Qr1|7NRwptg-D0$-!;}4^hbZ>W7Xd@8L1(8DQ6#tsrd z!}q!tb~09HklYGoSsxFT5N8>1Q8{?_xaeow0sM06NIa8l)&A%jB!f6=3o*t1$?Hzk zMZ|QY4yKh!Kf`Dh8hYe{F>UkZa~5F@_)oVWuT$llgb5LdyILm2fs~tTHIgnA-yw;l z?~^Upn}gRjA4GbQt@U)tc^$J9Q=+GGlHKBsj-{f`+h1?S%HpGc9SqJ3lp55UKH=rW z5397W(|i9seyM)*lfxD_`0h-FQ>&gJw>PbMwd=it2AP@#T~q9^eZ5^Fp6UG@k>5}D z9JgSh%Pth%%Wa>@7n#bPE)p^M_Mlt8eN?1oHVAaFyJl;7-YclZp_pq^F(S}K_cj?! z=S{)K!bc|KYh%-cI_siKd5)Zbqy^C-zW~e3fTltYRsAyX0uPM zObkv#e-uDwsVu3nFq1LZ2k$o8Kw$4+B-1iiyA5B2b*2$Yg zPB;xd;SeqLDkZ>UTPn4E>iP4}DTFmiMBNTsNSBC5^?zM!hGBBx0N^x430*c@3N0NI zQqX#NPS<(1@vGv2{RQ)(R`b5C-}%GRQ4Efg!{}K9$D}E) zX0L>n_4yq&x})<;06VeAxGA7+?@8hXPSE@xqcX3F`)Mgt0TwJCi=3AdN`#gtZQKm) zE}Qvz(~q>DzPAzBrVz>f*f2l?2>I@P&>B6q5vJl5ur^a}GygWthxZ&G4x25pcN`bo zFv%`5{px`U$iLb0MBpW=@5klU;!Pvyh9|M(dVXMNr5XdF)NTyuE@9G3klW+gw`jFL zJV?FRiFCTIZXLx>%PzaDGU2SB4Ix9RlvBM82cOAlfR`JxL_60~sH3MR+;J$Ed{t&)<%<<&}1=9Q}N&tF|Ah z4wfB0n#XrKM^t@FePA-NGa3ADSo7m3ib7fR#^{_H6t+~G_p6P9yb&*0ll~#LE~dOv zfiHto788%^N!`#F&7;4{WcAPPyDYR#c=^xfk_H1gfo|EuA%vT;fPyP;cr4v^@)cwS zwGnJMdv*~eaZwB}HP#G}q{+D8vugDIZnQ1a^I4|P-NpA;Nmo199ps`{I(%E?B`Y3> z8Ai#K4LZZS<^n0zUo=P#p%XmxpRdxEJj+OrL%baFb;kJX=YFNMJEuMijhP3EJ#Gy9 z*M8H^lwZ_EpE}y7p%H|rs^?D(*Z`=rl9f8}*(t%DZ;CC+92TC5u6-Qp5Aqi&0;`S3 zsJFRvN`n{ZxVe%qE6*M{5^P3$d)<@@LzwA#5W+U$Xsb89gi+f_c#M@$FMzC;wCLi;%wYbSdw=6!}Lv)H4mP6Ww z*c8D)8{$Efyt}dseZ>={kI?Sq?Fhjk_HGC>k+~5A&gT+b1yHpe@vP6GIOQ_V-WpSo z@)hPOD|n2exS^Cn*u9DiI) zYP$SkIpj98Nx@9lbaU4cg1bK6m-I;s1&29S;z|{z%~Y=H`#0sqWO1Z`jN0hifT9Fn z4Q{e+5(6f9LL?g%aIJ867sVWIckWP6lf-X1Qz7K*{mrNmTaUyqCxlERD5Pzu-mQn} z%Vk|)bZwQcR|h-&dz0xd^@RR**EMrbfPIj{?A)z$qpiYMraO9a)|r0oANjw8?e+0K zjg2@B-*)zd_2YJFxNT+SZXx?zX>U9F0&N|NOY@>y0=7<3xANHrl++xdfJmtmHp6nq#UR=1Qc)WNft!A-BcmVD*Pv$@UO7jA3F*xtMFp~PgXtJ{Yw9r9jzw<4tiBL+RQSS zge7BCKV42b6RA7^tG8HspX*7Xd7)OUX|v|yz)6@hz%0woeOM8yEPwcMa374o!Q;Es z;BP}Dt2v47^^TxlXmyusSH-lQ30S)CGrL;_Qf}lW>Hzm5)}v4Gd#^gO{)rP(kDe|` zm*e0U6tAOJA4oE0MINQ=-fEGI*Zg3c_s(xVzt>`m&D@+PzUBnQp?*V;Gd2$sqw zvt8jw;9;``u z_Hl5}bw2bR+o^CYdda>H|0u_XxhtSp(}q|Ai)|c>y-S<48W8sYe^Dz<$lZ*%cqbzzLwy?1So$AAysq!+yzvu{i(%uu(C-wUmqxXK_?|{B6Zv2;hFK}d7Q z^18R6CfKpkF?ptI%3~XUw}Z&8SUg;2CjKM)&2_d$Y^%*UU0ehTRGFC4X;eU~X*8A_ ztQebj8Y(9EFgi4)(S`Gs@eXp49mH_cYusaZ;44 zQi6vQt&FGCiH*q%7c&&3G2!Y=C8&LD^f#MHv_`h6a$fQ7+}eI}&`@E-p<07>&{Uz} z?IwxqZ3fc$mxF+2^@y{^Zia%DugExWMf?K4s7dA}%Bp^<@ziSZrx^Mi*jGtfv85EX zF5Hh*1+F8=yfnBv%&9%x2WOy^^c28iQi7%*nBrP?>_n$xB|eCh8Zk@Y&QSvF(Hqu- z+D2pP`0iGZSeV|4NM09MmlzoF+;s%rWsI4v3%d}4@I5I+G_@XhB0Kj9;2zDhQ=}hp z;2SX+fEKe$8lTtsA`t(Ry-99Fe*^@&70v{{OX1emN}hOwe^T4l)xUBLNmdZoYA@0q zA1V>*e|S6B|KO|uisSFI%*J!#h92yRAG*>*vJn#@b0(LAvO>)o@uqSpsKWrR`=N?r~e*;)??G+im&c5hT*wB>>A-;@I1K zF@WmvLWdinATf97*TeKr+-7lH-k5-blL|DkW#)yNR(Mdx2H-uWv{KhKk5p&E@Jan( zCNcmE>~p845ld(3296NwY!QjR=w#L6Jn&-#8@<1 z&%z}eeLE5*t%zdtZ?Z!|55u4XQpj`lHW>Bgb9S-pE(IL-Q0K4FxjA;uj@H6CKK@1B zrJZ{}HNRuJV+3`|f;hivcKXS_p~+F@Ot`Jp!+MnJR{iK6d;dK;fX6Tq&X|jF!T27a zc~SwdJ=!o-xex6>IIf;^$84M_F!=R(AY&k-Z)mA1wg%BopVvKFQYgQ;)U|Z>@!>yZ zll5G1j#`^Ou_*=ny}|=6Q|w8(OmY~$XlMQ6OIAL8bZz+VJ=#HyF}8YBctcg->46gM zVQTgM&-jVXX)6X!3E*#r24vPJ2*1*C)bWYUi^;@=$mz#UKE(5rN%z2gXZzI>rVMPf z05#aSh#UrIzX@`E#d`!~6=HHkab%uCzD*)HEq&qPtv>r^?Zq#h(e!t#)aYO@ENUzj zeV_ycztCajaTA=Pn#5OtsCQi==9??cNv{N`tRTd#E}aNqr$R*{coz(ofI%#wfpc)Me!+}mZ9*3o~1?QL`sZRz*w{U zaEV#|LgABW*?c42;xtA-34J*Peba}UGq`(83HoJp2YdGulx26ABop4+v(bI(BPD3k zYr1U4CBB!FFJxFkxT+oowbG&1s(oLsy|#KBaPQeNzy${veYZ!~`NLw}itSwys%aQC zvDK@WkJ+@pua74g@h@JjGz%~>QFr8M>XoK6BWD+RnvXlkRVy;_LU(ocrf*})hPWku z)*H>^ZtB;A=^VIMol8xu8He_#;@+24 z8@N2V>%PI@l<5alAeLzLXCP`mbQ$>d+Wx6qx991*n(@j0f$HYymQj0r7&?WZO0JgW zUCQFrb7wyOTp;OpH2M{y;oF{AAucaF%xux9?&j;=dPpWJ}PmD zW`7;{fmVFt=u3V-fQc1vo|mX&`(cL8O|OODIUg+J=V6DLsKB|R^!{)&AHW04+M>dj zsBE4TTs`(pprK*p>g{hq=ACTn!&Y@?tlQ7_tj8wb!i>cQY~DTn{26(Hn@eN#VJ~vu zNG!GfoT_i3N2=jKyheeXMm-ZONd_CQW*I{tw+$@3if^79 zwGqMpaW=}>35W6ECEqZye~x2KmEI%!&u)!|0yn~5S+8D;uUsS^G;du`23*xUXFTR# zqfk(2nm;nH=4xog8rG>Z{y4QhZp-}MF<^fPXnt^{L2-~7*4*e7=9X5=;+Pfa)l8ZB zEIt~rbFD7-E#9;DKvInxgpe$r5+{$m=`y4a{*a)kZ$C#ehTzfO`+45nROLXkjk*n2 zESuQT**InFTl?^(ZE!>U>Em}I2j@q<|H)1mwh|=qoy4ohwH;0xQ*!#p7 z%^fbJ>Z!9Mc`ez6`$129V9d!q9sw(`}e`-T6 zUGn|V}CIS+|1e-vJ3*M@$K0DpWosFMwZoqS9S z=Qelyg>jedW#0ai?;$sT6hl75drG9+8oVgK&yixo;l|&cGiRQTd8LL{9bw*9xW>$< zNgQ^69vt>Q;QmZ{GZGMH63BX9dd*B0biaD*ae~A$?51CZeB}8bOJs~?jcLr2F7KX1 zgs|g@-Pj{n>MA{d_2aQtdxTquu_0x}IB4Jj`5~niwBkrWaN|+eHRD1cZV@D!d_vDGgLjWbPW+CeP|b zC>Q2vw!x)N5ZEUuv#e({EdB0V5nF5`nCI~`&UF<=(Cfyl>OiXn$?Lu`-WKtY!%la6c8T;uYbK>YEYLfzqL{=DVcLXjl zc0Vh%Z}x;z33O$m#&?4xR6}B^1-LZQCeTp0%U2epukvv$ck!MC#66L&yQ)mom4L83 z)mA-ZMWhju3>~@l8|F9mZhqW6=3;B04T)J3V>s1g5r&dhl;$pq%t-<7$5M+8q~Ut zr{7%aB?Bq9%yr+(xHTSr)8(RWM}=_X4%RmF3YYoKVek%DDLhE0J1R6#Mt<8h{;_GT zm`T-8K_lwH=mI_L*#FE?%W4{DsBb82dlKEQ2(-bOA`o)HyL>$U=@Cwe$fm29DGuYX z6QYzhh<6LZ%4&AvLH7miwr-vQU6Zp?mvt5}E+;`F8iNya9YOQSY0{htWIXvY1brF{ zSY<(Q8%zPvfAY=vb1CCTM*xD!n*v@|;42M+DZs9C?fkr}lufXlW)?%Nu>nX5)Fp3b zJ!K6#+!6A!0fOPYlrz`qf{BiMEz0F=r>%sa-2XmhB{uj7;iwn9)HBnq?;w*gjlwh= zbJYd3C^_{gV2xDzKhE&5Xn) z!SfzELt##w;Vv*h8|Y4FL2{N>J-EsFo*kP>3%%gG_b+%;P8>!#iFe5LA0GJuIM4k+ zo67^?CEW|6C-AJX&+JdiG*>?<#f2gbNNGn;eMqsrCvI0 zdSHw8SjkrJmU=e&l*nod7N1fuWKdYC zDt*h2PIB9p%wjY6hMEpl-%6wh01wg|jY|yDc0>gDXz=rdyHqSo@S4LZbYiS3ckC;U z3DURx3WTMYJfm@JOG?sWZ_ki%MlU=FUe)hYt86_UYV@0d*1)Sp_Uc)LU(hcNwmAzR4{?ZA(%F`)hK z)93t`aM!pF8@k{02NO_g#Tys?k_Dk^qhhf_({+yPPqmkWeT7~D2gcj0xcN|L`Vj2m zPa!8#0@0NnzeZpeDOyJDo*11b@$K&lM7Ax(h>Q(Nn12X1gXjc&GuhIJJ(Aog zYi8Ltg^m(|Woqybd!1Ni#d|HVfb1aQ?V8bQ$J-roZpots7IH~TWZ#iV99*H%5tDWY zMXxmX?NZAUTn~#BaUe95#0OVJyd4)87sPjL|HaTk3ENA>(5Vr0OeA+Kz~nXJ@|GOTg7O_IlJ#eL4$P7?={-?&sG}F36AwKO57O z%l#e$t3p*{e2!6>RL@Yg2g%6yt@JO)NORNw1`D${WF>3Yiu^~OW z2j+e3RV=u|g$V86mcH!AeW0-H$9K8bzt=zR4=7hbW&9!=LgYTzQoj}iV%t_0MXyD9 zyc!(0&83Q#5)q$;ZYrO>wNF&}ef^O01cjqMvs3Z9tIKIdXz}Lxd{LWjSMi>6bbTk& zW)>jG>ipPx)^o_;++mROYx?fyc)<3Tm36Jy^j$AkVFbdR*ty!I>vNgt<~LJp<9- z4DF!BxSE00(;~o8xpf}g)fI(~V{n}9QPo`OUXTM!>w`m9E5I zAYat4Z|jUPOj&-wj1exZdsHIxcy5TXOmF35gO-ylE>9M*L=cgqd1HYM-E2 z%@C;mtFLwS;j5;H=hpe(ZuH;Tj>+&J7I7g6->oy^RZQzqqa(5>g*JU*ft%$C)9ep#&|`@7XMLYjExRt|PGC^>zQB+Ox<05S>0p~~Tg zR4MhXp!?6xRK9&m0G>8hmo2q9wdx79=(knF{Qw=z;QI$u1-0mIss zL~cyd5(Mt`Y2Q8jGrsN(xNB+1>bYsDepdQ>iIT9U`j1!F_{yl>@QwP2;z8fXZyqyr zmdsL2iwAr06RZU$q858pJq_y&-(UHy#VF2P1zpeHP%EoQ1z}DUId>bgXf#bvKQ@wb z_M3+Tq57DI%~4&C0iCW=jo0nmNr2X1Grp<3oSLv^+dIkk45cz4n>73q8kTctOiN2T zpWkD`4!&6!-%RDk*sS1kc!9)2FSsa0_oPF_?%a-0pX&y((d?%t!~?wa(CQjSz#~FergzU8XTYf)Dw*k!=@nW(#Qmq!n}oXsa&^@6nUKl58aCHq>={s z8hRstnn(|whn&zQul;Z|L8&?AOx`Z=8wsy~k>`SjI!(tHhWuy4k=?UNkQCYTu{6n5 zD}U8YFG-2A7AI@O)a3TeL0UNLUtmvJ$SNq%BM_BrA6`u>= zY$s#FkH6R69{(t$4j;N@$v-R(IudxDU4H)ZMRcKCT@N;zox)W9FH|JZDkU@sqs|Bh zjiv6giQlyaTjMHo^QtQ3kfKQtB8UM6HwID;U7R|()F?17pnS?@Jv)4B`boZC?%pfx zSCobebG;jod}^;+(x{4s;HaPJ+g4o?{lEMeTROEr=e?)ISp*=uyhE|S=(qpsL3^hr z&`9TOmdlN1uC7vm2PlfT=mYzoU|KH`!xe0D*c@Zg_z66)>3JqD*c7YL<7S>k#C)HZ zr@8td=fTR@XI`N4+)`?o5DOpBbc%Pp+ytfDW_;ddu)m1`stk&989B;bCL!vHM%1l4EV9Bx(udHbKsg!A%e@Cz?*DNmK_7I zT`okI&du&ft}vY9N{y+O%rvrsCjEZzjg}>+rqKHMW|dOuZ!~+~gw|di zu}~B>JQX>lrKA!Z@}pIEsj&p`<-aKQproNjmFgSuEncOa#7P)*uJtv;RtRH{R94r| zyM7$#^X&-YiSUYo?`HOFK~%u6Mom{SHbsNMicpPazmEtJO6Oy&7?5NF1yE_!VXS{I zvNTt`$t3i`@`?h%6<~<&zJ`~s$by(Zs8}kAJn%<_>gp~NgtN+|&GNAqIQJrWS3j;Q zgX}EMCA5rE_dYi(H@2|BnvdsF+-_RKiw63W3j%lg5NXD5-OcSfUlwE^s0T@i-l$~0 zttp3E8tUD?qqBELaD5P5n0-X@51FGtZ20nwm2iK^g!~RB!@u& z35!!siP7%)RLJ9Mnu;8aHSF#Dkezz+Wu`Iy|JR1sn4fu;bPAEHb8 zWU$WSRoNUJ=`?kLfG&8EOUIr5IDFA%uS9Y3a5W6nvf3^JJ!Z*qobip|L$1jkO<#t6 z2`>x>Ye=An$vVbi5;a~On3KUA5!D;y17QayhoNm*xC09F;%Bv113iiw!BUvpBEw|X z7#o0LK(d}bf8hDe$yCW^P?&)5V1O{~*U_U_V?jGsG>&2*gn|nB^bUE%q=UcR#D+=D z*Yh<`mhc4vT+3Yqlh$>vkCMnNo@gm!JcpM{F<}H-=0%n z3p_kUxF@c+h;5DzK#m&2+OcvMhOHrI`C`SURp`KPmotjW*SlT(Tg6w;x4pTDjH`QE zvb272mBpT4*^t`@?zu@_$DQgV(cUABQIzH?@d^tTLzW!L$is9nboI?S>gtJdBSP^vOQPyJW=@79rJEX1&bCm3>o+g*5P=(gIj@daZ#a$%!>M9|7| z9yv!tQ*h&}cB2>T!@NyW^M2S)0et)*81%M=HjqUU(4V@nzC-|8fcV&ztp%A5gCyLF zHeW%-Zu-N%fvGeV>Irt$nmaXoZijzlv0$8+Y_YQ0_(@@AeKFX`L)PQ|RMj2rEqbzJ zaX|VZX`y(fPy9<8QNB%q%+Ef znkZfJ?Gy=ntvv18Na42?&!6Ed6KyG@Mxj`SAu^iK{Q0H}Ek&C^x*lC&+jT`P7jk2)B2SD^#O`Us z<#VH2BU4hY{OymyI~Pk` z1Kkg(=_Lw&bEN2WZnw)^XM_g)5|Y>?=W6&plE;zBHMosWjmf@pO&_*V2~20!5D%+6 zlk|bry!a*@^D*E6`X^fGL%Lf8*u}i})qT)2rs;1euLt5{kYR_Zw0_A$4?%-vN_Dd> zeTq#?!`+Gm?npVmM8OzZagQlgRdr)yoIKTyz7}(P`+x4B)%NFFB4v~j zx#A)hdqLWlt7GO+t+|m+CHxqJ2QlC%>ZrBYoZT-{v?w%tny-)Ky%ms>;knkltsNOo zUtS7UcKmSC0F$vTFQmk%(nfPeMjut+ebo5g2G%2ZoqJ9D%nGoQ`_qSg6hINefZSwA z&plA1;Njh=Qh8SsHQ+2#+tK^FD?4!2m`c2izhmWjOZd&mK(J+%_tfW=j}PS_$%AR^ zlMAv0J^G}c;n}_YJtXLCJqezDJhYM}WVxj{of?u!m#^9LY^{NTXw zyj6JBWXg)t^2)PRhsK`eA2k_@_cuBQ%>pJ}S0hR4D_+jhym(@ZtjO?faXdFX)lB*v zp#s>=24nlxS7qLSC;(sgpw{5a3&*|S)s&}gGEI{}Dcw_DXAb_ped+}oHEz~jH}--C z8Xb&-naBGlwu=P57Q-yXzIFw{^Z0?hI-VUJLk5%;QKDHP^)bClna}a;Gnk8BEVoOM zi^v&Aa}w-3Kl%!P#V(o6Ch={W294_{vd`|~{9p)BV;gHX%PrbAx;DM2;5qP);32?c z@>tdKjdAESM!lc8$RoTsMTn@+xUXf^hlU-juX-H@ zxX?+X8#asI0tnr3(y2iedon4hl6O8!L=6Tfl;V-}XUtlgGe!p&hmWM1ZoWc}-8F6& zyS?owx+JB}EK4sF9Twk<9aIsqG~v(Y86(!wEFu?LKRv5PzV@abXAV4?5FXBSXlh*M z_M?hgg;R-EAkFvL@U2C(;8Ms|%Eq&mZgbW6i#kd|XO9)~{XQkR>0ULb(Zr^j6e(zTcs&_2P_^eXM+3Cn@`a%< zinCLLr0yl{hhp-9;&!thZ>i&C_2dzGSj`FoY~%M%>Q{SEuKN80%ZT9 zL$fn%|4axmrf*cmLVPZahFG1{iJT0MpDW^DT{Rrz&a~1k!Y*ty{TZ_x(j|2|%l3-I z=ec!p>NHj57`(rYWO7oGH%?}2rK%759pRJ>is#o1k>9a-bY$LBMo>s;MzI&WJSJ^b z#2>RaH)+E@=Wq$O;P|Y7fXFVwzD7~>s96l%?nA*hSFNP&1z;a8(kRu@+F?h5IrrhR zE_TRk{Znj_549LZ7?b>jE5EyG(-%bMIs1%NJ*7xz6n<3UHAj1I8odB>_Jmb}G(&a@vOLPw*;jnc0vX=A5t{?rb)4X(roK}LQa6$jv5xdtwqWxPfqUG828%0(w}GVBUqDeK+zNO?*~ms`&M^JUV85Ylih zeWl)`VW3&lDeLMX>f5Fta@C4Xs7oVDK^B>9UBbbce7BUKT}H64IivHf*?*&WKZbgj ztSJm=ito~nR&GQUTyQCM?MGQ5imgElLA8h-q_{dF72n&UAmXU(%l-|i$;vhErJ6Hs zen{ZLF9^uiu{Y#Q@{FAaV60!;yQ(Pt!Av80B!Yh!qggz?7D4r;&D)FeGPIj1n0&Aq zZ-Lre7^}Mg4{{W&aTmsxBP8(*N#5V*Dgf;3i|kGD=s{EqnUEH?oPEPaEE%TY5X_{uS?%9Yi2xyKZeP) z@%#!t-c=-58_1CaInAo6&R*ekLp@ahK>KEKOds_XQpL{m44+j!=x4!Hb#;+ZEPjd$ z70rH`PLc_nv-dtLp;_IbORswvE#*J?th{1C$8zouGrW^XJgFMNXNAicg=4I8-T>@J` z1FtcaNGvm_wHcYu6ZF5Zc~0>jNY}(Z(RxZmbweEq_~*X>{yBEwVMVLA#Lk}lrT3PN zpNrIrnBVf6udm-?l!HAiUSI#jH3<3n%eyUJTAG=Z-1bu(iGd2Vcvs3#HehT+kKj0n zItbXhHg8?$?nKte$~(H9cp~;lzKv54?*+5^_;1QSD|z9*C+n-V0k799L|!TqD*le+ zEttA0iI-QcIeiWnUc_}H@$~bGxaM1K%ri@}U*{%}+5INN97L{cB^&r`Mq;LWWp2do zd~!TUOWGGwbh*~xv_4XTVbx!+r&;`gdrK*`Ih;@SkaOTWU4@eN zsQbhZ`_q*KpP2I6E9ay0fN#fVZ&hM)kyOT85JRt0r@jr~M?T2Uc~o65lsJ1>ZgKiKIG&o-6m5L7BSHZ*_WL)sG`}yD53**I4_7v86M&|qiq22wf{k~NxR{!vXaFX; zRLr)CH^<_=vGEcT6J&iIA&I&huZv(`&UlaD>mJ2a!W#orRvQTU6wQ;lbJ6q?55!zY z3{v8T(_!4H{Sg1k&R3Oi@q20VSqFQ#nismRr^EF6>ykE6lCvGOSruHx?Tq?!>5XqX zNRFK(w%7srf|D~_TWVC2Be#jL%qGShpO&vxKW*mAsaWMiLaGiKxVuOk*;4q{%lLZ0 zM9DzvE5!VzU&$KK@ghQQf=Vn866foG#8+m3kr3wjx+y!4f8^qe#?xrV{3UorlM~x; zMR+31^koo*K&qML=`sj(c8xGCDIHiEdq&Xo(T`ew zPm)SS*L>E<*&+!5(H;mc$`OHh8x^d%+u%HMeS3$13=OB$Gl$ol!9 zV_KGY^hpzoO^fg4VKj<6|9c_-1|^aZGeU8~2~D3aUBuUk60`kG*$=(b%r4`jiF8BF zT-oe#@?+icvXH&SrnAVG0sFcM6=;Sq!!!%LsKq>_7oDhn`Hgk1c%8&6C8Se)GxhE> zEe!rk*_pQJsVHEskVGo@Gxvj_jJ@eddshcC7w`&KbNRk#p692TBscD6J}2Kh)Z>#} zh+)KF@qy+s{)g)r64WOAb;guqjKm25khb7z%SqU+;{`<(xMHXfi7HPDC~H%itkm(qV|Cf3T^n;)c&i-_XhwkT?jdd~|oP z1~h1)2>Ail)<2iRqJOPhE6q49UFyEv{b?ID*YnQXm@WenuR3LfYA&rF zc$iVuc>YoIk@oJ_uJf!;*f9lTJkI)lGm6)tBP>a{d|U#nesJ-3oTuP@F-J1sD(*ngkT1s4qYsJR_g&*{xdy zyPrr3OGl_93#s2!*z7dQqx~FSJkNuXQW?zd^|u~VRF6`L^QPE$dK%gyF>M? zr=~2Rk?|{6%HyF`M2jXX%)hhV+9GU2?GcVcn6l2f9hjyb<^v+u+emv!)x@ERtkuek zFnVZ+hcebG&CRN{4bn4|1Htp6MeI=!&_ff^ThT zVxM^MeiOC{czQX`Vn|Z2o%WQ^;)o7=R@QIZDw){(fAO~q5to_x7~>}VF6s^Ti|yC{ z34hfb{CRI^@l_$tqkk;<{cCeuqEol0DG!ze#H@NmOp*lc?F#Z%Yy`3>ZFu{3hEOxQ zD#z;rjTJAwGCs~(B{X3+W;{G2Hp%Y@a7kzia4@8OKEW{jn@=rO1xbUBQ(#;l@tb$# z0q3%*Zq9YL7{B07aDQ5|;wq4tMpVQ$q?vHXji4u^En*O6IFg%U{BGJL{j0JX6;rBK zK?mbxhaUlvzg4QBvO}qzsO&;IZEhP*&?3FvX7>BbQR_NUP8EU5@qudFw{`IWAmBU2 z^vYkftGvFqFE=$m$X2JW%*kbpjr@O@ddsLd z!fk7}acP_ccLWo#57Z;}$#w_u#?Z-CcvbI}J2$A7|XN_qk*KtbbKC z-kNLGT+af-U|$1n!&Zsa#CJF1Fm-F{T7q@O&y&87f#-1%lXhfUPgzh0$Q&_@eAvf9 z2!;Ge1u||K|3YvG|Jio)4v%Q?J4K1RL2PuMNT{$qF6Y)`eP`Qshj)0kl$Pj}a0<`y zFR9Bt5B2G`vm^gF-Oa|vKZHUUKl#!%w1E?j;_Z)J-H5f;+bY*UDrXCT>_0OfC$NLS zn1#anepksAlr}j3Of-7}O%m35lW&B0XVj<0w{Q9wYrmO*(gF5LF??7cM-;yg2UpmL zn_7=0HHulmiUL3idm52Tlk8D4-K4k3@jw~`j_dTFf8K$Ec1M`Bx?-}kp3U_ZW{o%I z+G%E;137iYa@%j7-L2=zPV?tZ#SFF}*ir6$QejRb~(}BR_4h%?Ebtd`p^475)K5NeaPR z*Qu?}Jip^$hhRs)GaEP#{nvy|-I7I}84xm{zXa<1j6DzH6j07G@*cBcSz+6ot=e;B*~Li@+0{RJn5g&)T(Mte2$IiYy#S?N8F z^;x17-v9ReAkT@!#q&i@Dxw4?*FX6#s9^I~n#_N6ov$MH$kJ60I}hPqeX(~l*8(4+ zKD9-;c%{7DyM>ZSldh7@3el+eRUyBPqE9A*VC}$lm@R)OdgKq2srI*=Kckz9H5-@IJNx^=x6k16!Xc=;=~)&e8qI?RWS}XA2j1FtDN;-cH9$UL=(S?Btzn z42%b?Lp8e!tP0t~;a0gf!xrz!n%AQOL>EPTgJsDzsQ*+tCbzc{o);DozJ zHi%|))+VoBE$wF@v;Fg&{Cm&}d(nrz(|WCdhFYHXCDViXu~1^c;T)b-=@hDGwi>|a zj^57Ww^8Y$-IA>2z8L)o64P`IOnV`Nm)WGTh#1Pw7ZX-EmgP>**iJocLg}A-q4>Oy zYZm^57drcVvb56)lnJwc%hDFJUK#77bIB~pDFv^N&7S~*rWYX_@W;j{E<aW5uxP3e~{Nit2X!%DpWFuTxY;9#8c_1$QZr8P;bLk{t`U?#f=8i zmk^Fng%usM?!b31OhNKpThStLCY~6C?0ixF;72a=kDz?mFHi7s(t6eMz!MMc+@U{% z??~i{SEXu)cf02{+4yq@>RXni-%PNR)eZdnEf-z2e(&_N*^fAS7n>yo`=#)e^zuH} z?dRy4gJE%`+SvLdHe}*t89T|7b>$(qW{;4v4Mi7^!d6XlcgvOYW{PPeY-f)ce4e}dy^?&&o|Ft`VdPh)mnyX=q&wvgr4{^Ohy61l%08f^L6~bKY1~*B zv{UoM7qRgVSYfroobLMpZ}gRLqPtShF5)uykQh!b-32KOXXXGuBx}5d&uF(+Z2nHmI zsMNcJ*1W#!IOI{TN4Q}Zz|)i_`W`{3F982g4>4GCa=hHupp`TEe4Y)4Y zC0pUxY&+R^cGdXXPZb^duaR?bAmT=$%8Q7GPK|N?M2nIp9XSm~ILkDf(}gFxF32x- zF;g3SKqZx_NJoiqbKSV5wY4kjHTa~A17?|9Ubntf7M+W_K5;{)a0JhPq?cIpQv!yR zQlb+XE+@ytz%tMq#Y8>9AzUF^Np{Hjk#H?Zw?c&mOGH!|aH7w))X}zszN8FiHzfhR zJ@#%Z9Dafx=)tPiBmg#xlQXQ>YzFR#!Iy(M5t4Nq=b%+25@ac?Xl|v7eIth098_KI zqra>JOixkA+>vLl>#N*`gMe*IXwKyGdrl6fhgl<5IPS<87?)H)yTgKi9ITg>*pJ4? znC}#f)iIUFu^djSA+00^rdf^@6jU5_|I7HF47T`2yJV*?pThgfB+P?lrq=o!nlK;F z_UmP@tmGADcF6st(nhA))Rh*F%`}^jXphe40e}m!97+tjSv~QsEXDL?W(C^W#D^;b za$Vi0wCj|WFxynVh_TD<$D)_Zefk2SPCCSC4h!T9N(g_~cj2sSVB4@25;orQR{n_P zNB#wm3C|0&0EIREC8}kCc2^=k!IfvW$Qo0yH<`hu^E^|u0i9QjFTZAAihYnOL0Q!C z-q=T9uk3h}k!$B^evd78H%jss$sA7*0R$qXr{Pp*`coIyH}0L2kd%+2?hUI4 z>?$P2wg1q~Qm7IO;5J9namh3>W_?$Qs17U4x`@OQu|igX=a;&ujCyAulhk7B$xmyi z;|Gx9eaw41{dEo8oWs_7;4OW~H`RP`E!GK3wu_5p6|~Jk9*$8?R$qE9P-nuVTFMhl z`+L5rv%g=d#B!4JUM?@h5WbKoB;zN(pXt_Ru`cUU`4M%Te)!Yo-<;^gu+rs;YXV;% z+FqHb8!?=$2Jui*;p4?`eqlH2)J%+{KH;5Ou8iN){tTtT*7;UH$JY6L&Y9T7nfT$b z@U>leja`W(KWeSak)$UP8H2&$Xiv5+@*943DihK)LOruZz*1FTp~XIYU`hPPC1iKC z&5pp6bPWN}ob&=!|9Cx-R=$hz!xxWq3B449zFObj z5zj4&GqgdKE{rz_hW6I53{8knub7WdTjC|0Wj_NFNa@tSLy{wE?557b`yIo}_fsq~ zj%+w(G3n1xPBX`g4$M~l;3X~J0^VqmQhG32t|cL4e)t0*X^yrbN%yw?8i&EKrIMc< zZ*P;L^V{u{C?%j?Wf>dkw6oB89y~OKvM%HYs(L2;N+hbAdnicy)O}N@@7wcxE{5vB znv;)4&jkkFn<0;3@_xjA^_i{SDqWNo3BVsY-nQCjk0y;VR@;wjYc=2CU!Zw75_z`L zUR*?tm_g#aK;o~LtW|+GvFrH8smLo9jLzR3ioOFf=v?Fgk6 zuQ1GDwrbI*Ka@WbW0THD{J{=i#T7~4>9bgb1gr&T24D-hQjuXZ!IsYM`KnAL^w#M?!J8rebp*@qt%GbnvB|m7g*=2sP=GC%wZHZvzveQys*?67d~GcT zVe~)65!|E!C2EAiv1&@Y)bjXVFhgaf(d-n{gsW2&&e#Q&JG_#DqfLiwdRjUf$f4sI>8GtAF>Pj6U}956O*K z-5?Z9GVo{OqBGWN%$yiQQX<=RL;6)~LwVlnwWj-q1<4dV44sS#wtqp{By-qW9@{kHHL-A3AF<6KG=*E4l1v@>ayYQXU1{D`YbDSg5aML7Dr)xY3}Sw#`;!|C78h= z0CusxNzOP_%>(kw3>5COei|7W|5fELJ=1P@x;qp~#`_03eK5H%&B={D8Z8%wMulq| ztD=y0jhvQ{6=8yKBS17Fke?Ur6aj&g2wSgA$4?Pb7$S_-d;>vf5axiSJ*6dBEIHA7 z{bh*|*_HF)XT;r@&RNK@EgeT1d>CT3w@r8L05<#Ql*;Y=Yk##@(C|loWEkg65S^n=GTj)V?j=etL=En23+ik$D_@Zx{Hp$+ z&ut5lKgayVvuH$iQo@+~bPLy6s`W{+6=>x)wV0auwOdOAG>r6T!K+_|p5CaE0BB#0 zCrVYWA)sB**Q-E9)`US>Itt;aG$YO(l6)0Y6P~{9rc%uCnFm@6AR(=>NZ#rPc^Ueu zc#gIZ@Hva9LPbFLI3Vt*C0 z@~T`=;95pvC*o?X-R&8W@4(}k;!`jBJ|6jCES3}J$3@$!$epJ)=z&_`)X(7Q}E8{0Mcc#QO*p4 zq8!e!oN}ypBDstd83s|QSQT}kCA`%+fj?X4!blYte z|8*07Vunr3^Va6)1+)kgYmy^=^2E53MOG_uGUpyN=PfIL#29#7%Tn7U%@Xr43$tBt$^8I}qjH={RaSvAaiGTsv$ z6XCNAv6OGa+Ai8Q;!(S?^0_$Tx_+5eXnXn!%~KR@=D(R|T@M?2?E$B_Fl#3i(LFf9 zXvSw9k_--)@o0WjFE|w16FNTxeUeU>=CQRejyARjoUuc|*t!}pp(&odBHb4|GGXI| zgSa1*S}R()WGfr6wfE9DZy}pvg-r3q>pMwo8=6@SAIHAr62WspBMF4;I%Kf}%ms~K zbgNVvzYRZCM)R?4-BHvCCM3pid>;Usli2nviT}OV0Tze>TIrB5)CaImIHl5y4*JXJ zTTke3N^{2#OB1nZ7xLMvEHF-cdOj)|pD&n8SAC}WJWJiP0Uupc9=WY~$@H03J~@*2jGs}hGkLhLa|9Vm2Gw+0 zCUiH8NRExMezh7H8+U$%uN}KKJ6HhJLYim4kjH3j!n{7)brgpdlVVjWdMVg_dMIC2 zPULs{p=ljCnNW)F`qkq+)uqQw_s-(=AEm(e>W^g&tm8yk?pTH09@o}FbL;l0yEP7J z;X)`ykE%o`kXsM!R=Iu~$khS`>=`Y+HbGKn6Z~0NfeDeflfrJ1}wlGqK?6~Q+%HBp>OKZSuQsXIiqWiTr3r8!!!_k*hi#@_{ ztC=C<(5n+hh*m&xuh)@R<#7Dm(bcq0xjBZHD@zu3{KDDcuLqEsMh>KfLWWH4hjn<* z?#@fu_b8@{l06Tk($8Nd3+)yrn}8d8I_vf1-$DuQqZCXEd$v2)64o)@uX!Bl@6FfG z7Q@E`FTb3?yB9??jQG}cxM)6h(;{8L!Yv)v!>|pOSSLuYEO>we@NZsa039^`p#tr`EeC)#6p2w#yBL z{)zE+>pjECyOuYvX<(PdevGUG5y*98Wm&v9iCJWg@oW*aJf5|$9qq<$a^)3RRUfEk zP4>EN;bnRF_SazH$h+765m(kT{B%N|?=8?%sfEb9bUA_ay42TXK=QY}>gWx3uzGWB zdSll21=HbHCe9<{Q51s=>&5lV9~aO=Qz^l{U1=Py|KH~D0_cB`f(*@D%>UaPHcX;X zzR3t?%xxQ}{iUaLIf}66TtCE5I{ce_5iFlk4HQMb|TfYfJbbVMsc0 z**oevbvY=(KCjB=B>NiZe6o6bXbfgdE%S;= zv@J@C34b=GYcudcbr`F+aODj78G8|%R@5%|#Le3{)SVvdiD#x8Fn;K;f9MD0^)xqo z1QPlid`38$pL33M+bK5aO~Nmxy>sOd_v3hq7!34Hkd16WZ+Zn zqGIDY3Eq(ocS2&UpBx-}vhY)XmsZ-?qPzOfwgm`94nZjS{}?X8Lm4}-Jc)$c?%eun zp0O8in%xrP?!!;zi zyU|WC+>ab%;4*9Ybc+&4(eWM>1Lcx@)k8T6@sP3irn;%*);mv?j_2)D`iHfr-52k- zBA+e~Fs2#szGan!UX+2!8szusk%f1sdb0Z1Gv7ba&-%gj@#63<)tIj2Kxf#!!M`wc zI|FxlNDHbKR;dUll^uyna%;`1s)hbXcZ7l-cRIS_yQ>N@KgcHrhFn$e7%t6uxmFmZcN%sUG9I z1;J&NCv=zau9#6NQ#g*PYz<*Zhe-gKSgOP8&XTy_D9Z9Pd{ zy(-tAVm8ySDEEj{wSW!o8S08RlmwZR<#VQQ%Bw(!lIZKX&&;Zeh^hW0r;0=3k>n!i z8XRHCaEf=cyjl_a@(d;H6fgq$B;jw+v#**B4JSMwCd#(`VBt};CCCt;PFl485o4?@ z(oU!orE7qkq1ky>{@J1X#x>PvRP5kY%ta6)=*%Ah+M(zF>r%e(#qXso1?EVej7<7M zdueQiytWnohhq*Ly|!WYaZw%G7d;Hun$;&jj$?-MLQBN?w{f$Lvf3Q3QGOFyU-26s zyvT_(m#e!=C;{I(@;!Lts{Zs-U+07?N`=3Q?I8(rM59yOm$rdhG9SETiau97rDD%E z^7$ltZ6(O->2SMZuwnMbO82~G@MW*RJ;^_z$J4Wb-&;_=cUDlIIC$in%z(zO#4r4j!#0EaI(r43x z;vr5wy(nh46EEbSlDW~s+7aXLf8X7UDWB*g-w_p*M}2pAI%_)osH)dp-<8J*_A5H; zBbY{*6mAGjS_~{uR-Cs^cH5_LavTtwS+?uQn3jc0kUqMc(cxKfF8HvWyVCF2`&EAG;Lc*F@aYb-KTVgUWEm#X|ZWZkUsEU zEBdDBH|zUBxHb=;1}X}LGUTeh1vPZY9I@1Z0h4l8mq=s`x=1~0$SmJ4<<|==)YJAH z+7gCDa)L%TT#>M%>?LB0=v3Ba2UhJn!b5Rd43=|9w;vw?IXJ4{+DJbQU0$k9$tk_tfZJ^KQ zZ2t1rYt1^Z}! zCyuZxciTZmL+h;WUTO3+#uvkjdP?rhGTGxs#rfcP!el`9gbzpo6L3cx@Gm?uT&b-h zwb-&>Kl?;(lx&IsgFnyoe0rPDlm~OU$EYSj3%Nv|i)`0Ae%7an+GgCdc*DY*T&*bD zadFFC0GXMoY!(z=ymbXi16yA>t%R*atlVB2F_sudkD{cUA8#hQXj94ZN9>SVa56o% z;(m7kGKdJ;-Q3E#}?;1S+{M;V-d2%iG$E#8fw?$4#!Z(G_KSpE)P zhhN}Y&m^|n4?I|A^rC$JUTejFB+Wng0=*fiNUPJKwD<5R0&a&=2Gd@vLfaf|k(V@d zx^a(14hAcYigS863p>bs3XwdQ(Qtez25M^{(@_-??2}SWL#MR*Me~){CCcmrF$!Md zwAhR)&W>}s;R0zOJVpsL%4b0({F) zbnYjCLfd@&Zum4I&l5CmVMt0IzCibSD||Eb6gtCDjRCvxI&0^T#{5}|Co*Qaswb3e zl3a5q1hq6MskYc$fIG9)%AMuR3!xM^6n!iJ=)JaOZ^8uvV?>19&+q=r&+e{VW&nq5 zEh_>=6aR5P+&v`sL2ixIg=av;3x+V7%=s|sQ=29ywjOh}L3m00W0!_{Ujz8Qa za#^mk-~nBe1#77uQO^+P*}Ebs{=*B)%WZD+_v>_iIwoVEMJ})1d~dL9?cy}MB!*Pof=1=xn4Of!^3;GvYA<2+t>z;3=U65T6Ly*g zY}^B;3N?g`FR$%5t5N?LD=jk@jruwEGY2ild2>{^6Xq%pJxw4T!~P$qU-8?Ix=K7U<(H8}cfYr_6f>e!|UNr+uEg~&}s@XQ2b=9=Q-Y6e^` z6iFn5zB z@;a9OYI)j*N{kbHevf|d$5}m%v+VOd+@Wym<`zoq74tHqYGASu>?i4EsKUN)?+w=7R(;kH0Yg%ViS#xU~%TSwO&%fjjl= zXgXy4Y8Gi2-=~LaNC1Cd?GK#&;PUu#fAvD0fMH)?oM7vpaNj3+8)l#0EbFPMYQTYj zW+36TGzUG0Gh|`f-5ce%6X{?Pk5xt_S-U3Kl#shp6h2}OnM+t&;p+oEi77rvHD_2x z-bN1DbY#(1G$ZwEgY437BrK47Yr(=pPfIO#@ORkb7aX~6-+0eFn>-q9opQ~0`p$fR z=I9|M>Nz& z);n!2(aja7u5NwHq3C%aA+VT!+cx0R217txy;f8#gdZ?FV}m=Td`|Pt`ng+dHqY>B zZ>4?ecPJBiK+;-CN?(ojkmG(f^TyqH9BX&(xT?d^+B-5s{nqc4L`#%gktb$YA(;-P zh51>X_eJB8e^6Wkw1Pq}kD{=%SB4O!fuOJ0J&)kMi+FNYvoo5av8@%?6X}gQO3l+R zr792iDhukEuN$urf2w&$!Q-)pSB$)mEH{q`FAv4rb+@V=A?J7-mWm~QDokw>%MNE3 z2yIP-n<>rwkC4BS!ipW%m*lIrIO7)(+^38l906!ZipcFRt1phR9$)Q>P}@;(ki9Y? zsQR)ys|_R@#|aZ&Tnir@c5g|MF=4UHQBXnMA9{EP-tjC3m!lnju*R|;+l5BfZ-4Aj ziChh8yp6WCHm!aP>ooFt`J?r)gNY#=E`D*}n=@m6)XPaRH<)qlexX?7@|=DeX4@WH zBgh|Y|K1y|A^Z>f`StSr=HlaX&>SIGBmJ{~A%wwog}p6}khS$kVnrKg?3(hKPu2r6 zn43&#Shg5PNk&wp@|;n9WZ^onevQGQv$S4)Z0ce8<5#f6v3X3>k}&4aypy-P3>4{{ zngkY)M+Ck~blmC`aD<;rInLT{GX1CrvkI37p69~rCVVBy}4_*ARIR%*3l!#^g?V?C_A5eJIAi2I3a=PoAE z_Bn!up}Ibv|8k)qrwHFIzBOuTzRu+tq1(J;Lhlk)nbDo_37QFv%5P}O+O^9~1~2a& zC=7vWpHACc0^4-z4P-|Y^v-K9V7UVACa-v>{7}st_NjZXNyA48>x%+aO^RZ%3{QRb zM~YWW7bTm*xavj7K@Vk4jKKOo*59{?KFmTp7E`fyWo53!fRbaynt&Jbm|TGNk#T3Y zaPBL%N9Y4Z;mN}$xZ9YGO4WYRa><6*aoJG9j-@P(A8Q30)9*{GSZRPvL<%iV4GBQI zV085qmnr_XI$E?G6HF7*F-RiIoTO$Z<$ahy`3d#>xf+wze_KzyFlwCB3^2<+S<#P9 z^sase?gO7Rf~V8^?WaJQbuM8zewNG<5lh2uL*l7`899zh5I(HK#KPzz0u!*DoC5^| ze>YeMl7Cs(PqRcL)79;qr?>GgNj&((d~f_AanYLmWVVK%VZfTf_oIAHZyB7JC}$pn zSBEIN00x7y%dbgZ%hbQNUKz40%qGi*m;yvk4TL0syV)?SY@x>{g2@K6N@TM>(t1bW zpZ;&a(~iU+ZlMDR?k(9qS(_0fPMA%KA7@eN5N>-@`;FfBrp*T z{N&wLqlFP?F>yf`kK*dYR5vC-qQrqLiuw)fQO<3G)$#sQSL=)K%^FOunyd+5!d!aC zN8M~y<5nSS#@Q)EfX-G@MM5WasI~EvhrGSn%tt^8&ZYtc`<>skx>xoxnPa<4wjLhz zJBcp#zj6qsQ!Yk~FsFcnT7w0z_7l`e?-UROAmExdDzO)~%rxD&%Zm4n#PXW_r#Or@ zV3@{y=x&%OzF?#AUL>BycVn~Mh9;vJz0}Oa+v;YEww`Ul z3ao0IU{~b^VZ5;Pdql%kN;%qNYx(!nb=`;ho`yI}2l;hTXVkmu&RO0B3B?)}?vu6) z>Xvc-MT_X6Pug5Z&7#gsmOhi!;3nyt1+0Q78F`I5cBQpMCPNGxhxAS5=HyAAB-wvk z_iZIgd%=#~^@oY4fM-*EA{U+Dr}#ZGNUN<2)%MK;8%&AP%Yzodt8M;j`TNY7p*u#V z^x;FLs;Hx4&4G^TM=(r=YekP}bAjrHPp*rN8Kb5Y0sAy+iwiFcLz{x{ly(y&gher? zIUQx!xm!z}hrVbLgTsHFrn-Opr6jviI45QhqALnYFi?CzAaVOQzbX3T^{U|B)C!39 z*vss)M%l(XW}-~_&_|>T^@QWax;TY)JpV-W;A_G@{zvPIs);r(oF~vOYs!$N`IPt< zq=&$gBu1N)o4{9hB~NzOpa9{!pI7JEn7+O}Ko!nv3i>@bxxXC{VkhO6^@@yaw;ENn z5Ed#h;-eT%R*HSA{%=mh7lpdHYerEN1YSKjW5~LW8e8)h+oHAqwz;FN^Q!%?A?abu zdH=pb2bs0)8y_NHnT2Kc(@i1-n;4?>{L0;X@XA*t z%E$A*;x$4GaJN;>xXS9$abY_N2~8l4 zkFGrjH-hwUyvD%O_JH~wHUp7Yfn6KQd>J(F$05$W#ryoyG`4SZ{EKtzPfLquA^KCu z%+DE~P`wJOYhU|&Rd=x!*wQM(SM0zzz>?v^+3mkUMjJl#gLsJ5)N_qaDErR$b|QRo zfYk~1bw2I)S2BAPZx0)!=GROwiDJrjo;(t#b_*dktl$0-Veg6RUOFcHln&y9(6-si z(Bok>Ct3V(;u}F6+-?)07Fnx7xEuVXNjeGD+wG|Tn5ljX@dM6@5W5}tt5L13gmT+HX_i{~E^O5!FhrZ%>O6iv51k0q z=rc=|pf<(K$A15Q;$_EPUS^4`+U~647%3@u>s+oThvC&qA@)V*-Fhm5kBkhZzu4mJ zDK_2D=!-WtlBwdz`BYO2`N*OI%TEoF2cEy}FYlh$A`yD|9LXW~_U+sB-v}%(8gDNp zgbuCA(y0s`dh0RgnOy2x^6eJ?!dTauzUNj21;2kV$zCp?L<&TLR=jS-i|d8N!@324 znutv1rlir-Hb>9e5@j8_NIG`9ROhM#JhR<2No*{YWj9G8LmRF*EYb@X!6@dq^l`kg zHR1k4xg;wjl-_EM!XJUEVZc@uCd;+k2bATX>k%99v^KZh2_HJU@izWsMqJVW0W@Qg zK=L2MWN;3l$vO|7^7^Hi3tyT9`f2?}-;_h^@0NnBE$uy8OCsdfj7JkT1q(l=% zv%_LQedC|pCjQ;(R*o9y?0+>CLp6XXNSbF@k=aV+!`{XJ#I^4E6_in+Aio(>9UPzf za)4NX2YR76_YgGh-bM+1Kx^`${rL_-@UZ`;e&>6Cn{iNr4;l=7r17Fpy^nsB`!PN) zK_kwKsJt0%Dc}5U2@d7oSi+qqYAWEu*C`o*dwfC*Uu&0`M6V{BcmI{Qd*{vubaQ;e zit0Hl;`>3~06slhtq-~dEnJ&G&xJE!+f3GxvLc!KFD(7Phk7iXgBD#Z0U#+qA1^}= z{y#$aEo#Plr%T^38B(%B(o-HI2;UivjcFt!Qx#?5_OXdMsEo>UGv2@C=SKWGM~j-S zeVd1XJ#W_by_Kneq`lrR=p0(+V);9T!PM(|t_dTd9lY+orV@s6biID0m_BzwY<(Cv zC+63c`kX3|aNBj^TD{A^ln@fcbM}ta*rTC;j%}Ml%EKi@}ZNs zr%2d`sct1Dzx!0GOi*v$jtOKF0jlRzxj%p%N*a)FhPbkZrvG zcaWffL)FT$miEUs>gVLi&#LnXLQ)le%kz3G`mz38-x>Dm`s{HZP-~vAMLH*Aw`TF-(%Gllrzth~8IXtR}up%@=k>;FpSk3nrrh;polJ z|2{a^Y`vxx;v537qSSB(lu6s49(&dgL{=m=!f&2R{0n|A*f8IhHl#{Ow${M}JF0)7_IJHl>5hrobp z2*g2!23$5dxQ4Y+zROj*jbhLutSwT`B${ zZv<`-Y@O~{BASB}9Cf#SJ`eWQ3F+S zgpa`K-8{r=H=TFpBc$k$pR?-0a5miQ0e#8F@g^Oylnkv3w138n1u6?P?(C!{(1}W* zTr<4-T-RieDX-66I$ZNsC9Q^*>HB?_@U!wrGaz*T+vWZa1{Rqr5LaAh$6XQ*=1b>jCh zS>ap>Ldp%(E+EbX)E(4XsRuIob53PkpJJzT1nkLPVy9INY+rdTv;A(5{F!~I_R|O~ z%1LrZLPGswnbutVV9DZ=ot6P?(gPNj=2j0Kd-A_y zro_#xoi~m;St=ut;mg#9*on=w4rQ-oYwKBiga6{Nkg;Bnt z=;t51nWs<5R9kpI@i-KWV;JR499)#h`Z`M{60<&N117&VGyuFcM`<6^G%!t7o4JHNS(c_nd2pB%i}p>b%# zb3xz5h#A49V0ZsPTfT*G_A%D&FC(9r4djAHIomK0$e+uw17C-4x3{UJ=8CtTUfGQ7 z&1I<@__%^`Mg&?&R_JDZy6etuhq)eKh*fMN{lF?rR$~KCKL!{N^cm7pn{l2! z7>mi_na^0Ww2}C6yDM|lsMQmH;?*cU#ub^LB3wBepZnKMXI`$^({fcGWUR0rO|K_OTO_%JMQ_gwGdedNS*p{@-gUR)V!HijUH#7qq(TN)$IP z1k{Z5`Eywlfj<1*U)t!OM%*wp0m;~SOv-p<|6u_H#~$p@o2%;Oy0c6 z$?#C91X4ShZc623IZ_8!g$C8HtymvN^~2xWiaaxTvl?R_IYgf>AjtPcYzVNod`{t> z1lIZOZ}A!s%AVkCwg9(@SZgVO^~bC%=P(hDi2lsHwu=kr zfT5>ApHen{y7eFBF7D*+qgI__3ehKFvm%9old3LkTP#6Y_;^d%>!L#ct}||_wAHep zQ?XC&X3>Cdxys*>3oJ+jJ>T3>5YzvWQq5IwGk>Vv^=R1kyNk@3YQ3(wWS^}NOXY({ zB?Ooe&+~)3o65W-?&PPczkIl(^Z!4|fAoKG10eU->(^Q4wyure)EUhI*6NXaLE_Hi zcx?8k-ioy)hWPXL({Q$)ePa#R+)Vl~$GOP)FHg>Td4z%V?YP8bdkJ;V+?11s6!+kh zBWJ2al%#IWNSWt7pPWaybtguhrblz|_q-?OLOWdtuqe0vWJku*{3-mR_SN-Jt>a|$ zLz&20G=a&3&+3QCqu05;qFP?4utBv=c7DD!nWq0zzbX-2xue=K8iT;9qY1W&?2)Mu z8uZiq0IWy@ujIv$g3Y3O%-F|)uo?L|RNdNPA2X6&E^O{uu`9rk-DLq`b2op8Se8XQ zN{In{sMdm$m}qX10$_{_nX?i?8P;q|9|PP_@hp-cIo@{L0L~;+?{ML3zu`uGfjjqU zG1sR_L@kE1j08rOINz7=kYyrG^q12Kg2^OE9F#C~Jio`zRas+;)`-+kZv1V(o({}k z83Ha(FAqz3CW>@edU|Gj=zKBIK(RKs_f-8#H>t!_F4T7X4RWwA@+i;Q>^t#=((H92Yjwv6$_BlC@m_liI; zHonU4vo`~ud}gyPfF@OZhL08DPI9F8y3sL0BQ9{Dht6t&TKzJ=r03GecHpH8JvzMX zya|?fjuEa!yAFHUVXd!>4Q$!b=y=v3&TGbOvSgZ!PU-%*d7S`w^c~{4ORgM-Jp*eH zltT`PWfvM(Rw&b;6~s2SFP=bZ+Y%^M^?9Xm{m8Xs)ac@^+v|5t;u8#cG39RCV~u3|-B=63(7 zpxBWgpPD!##x`V(avH?%W7%GFv((RU>U4NuhA?kJpZKv|ln<$6QbRla#^&-T2+Ejj zjMwa8>B88&tQqxqQrF>5Zq*Y#mNTnmm}$n4>qQ|;)^{+Kpql$ZW(i(0Tw<+=G@y;W zm0wB(l^GqHE+X0nD%bSD&zs4JPO(2mIC!0%Upx@j#pVNRgl2lP!>=v^uPZX9R;Z5n zS;>fMZw-8~lJb=8hiLSuLgT4+-t1d>S$*4;b66g{lAr4KmEJx*=qdD(^vJ=2xYDAw z*xaL3jXWkfHZ_}80)c?TB}0ce>+}b;f_`e9?Y|A4Q?ETFM~#mLb~LNd3(q# zmX)YfN*p-g%RPa{Lnwhe8YYyEZhsuToCcEf{06r79>h{A8*)6pSa$u9f>DOFQ zkK!*IZ!M+$I689^($|D+*SyLYte!~o?5bom7wolPb7ISs3X{Z8@L5ei0v-u9MSD-f(x^hp9@KwbSc z^_uztmFoY*yKFw5CppMiCBsaAQLxk^hVUVWb=tn>n7AZ@I~-EvYBHGg1Bu4{9YD>G zPxCK9QmfevtsE9bgp%4bZXGBF7Y_HI>qzmt)<$Ar#H>+`o@h(F4)?0I7z551(Qx=@ z)ZT-HDXsT<{HY=DSzucYQ{6cX!KKUtvPyg0KrJ?pmQx${QmXcV%hQv^?K zx%y+d`+#N~&qFk-6X!+r--_)fBmg0T*&(>K0je8f54SU%=N_VO89dM2bR6C_(QtB3 zrOE^kI!+XK1mT(f>fHEX7!9}+H`QoseX-q!_-MesbXjl+{r~O%9iFTJpj~i!M(e96 zrR-3Hp?Y+}kMSR0zLFUAoSx<26f%AUqf7n}B-x6Rz~oMVWgwPZ3-TwIUui!bxhv0o zv)KI|T7oH)&d1B7@Sym1dN%^_!mejDwS|kV;9^(t_H#l_lQAt9}6rnebB zvURZC_+ELIyTsx)aeY(4{0Gwzw$)uw3t_K{itN(Q7Nw+S&dWWi_x^uWy=7EfTeCIX zI0TpAt|2(VJrLX>!QHKC+%>p15+JxGI5ZBy-QA&a3GVJ6=icu==Xpo}*kkmM-g~UQ zx@y&&vu3H77E6=!f2Cjd@>p2=nV-`46MG3;?%eP{stVfK^Z5<3Lh2TeMa zi%1DlYL0G|Lq zrU=Vm^Ki$(dbfcf#(W1hIt$YzU@OOscqx@)82Ep=2=jkph-LvJF3tZzR&(84Ig2IhHr_L6(-8m5VI*iVZey{)4{0gBB8PJjk6#C5nFg+fm5GO62_Tfli3 zf?mlmim10^PbK`-n4iadE)O;q7|<4HjAyGGcQZ?M9W^Y%oW>?)a041rTD8a z>dY8TKGNjDlhey{^RFmtbaz;dike$p-%+#cz^_2#spB!34Oj?Oj(z`b`!~UH|LMP3 z$J`?Bnk#oF?PnFvILXJY_xJu*4f4$@k+dioQShPc_w%zO=LAKqdwD+`Fp@c%U=3DQ z)ndBy-7p~9yyxdtNf9WSY>V=!0LBOs6;P%aW_TGc)iT#E+cyZrNRWbSOmKy<}@5e88uyQ!zvTxIx zOtDs`xDZzebm9s~2GGZNBB^N%NcbfGZ%h4itq6smf?c<%HQl8CPh!jY0Y8N;#^^}5 z{wW?%4{6EC4&uVh>49^Ued5ge9Mt;hPY?)9Cr+B`R304Lc=_)4RiHej9oq^k+*Dy8 zZaNk{3SLUUj7i^)Gd8n?=h=w!hg~Oh9*@`6YJd&t<h%gIi~p&YoB;)>mpp zP(vtW2n_0rFQIrq1+2nWk|b6CrD>VqIwuG<$=A~QD9nJ8kq56dE#8J_uXR4{)dKun z0is?nuXeRv$CHdx!Bl|N`u;n@&uB^^oHZ7{Xzm7r{B45?W0;nvgE~Q;{ohETsQ_yY z^?H(54BbPn$;Kd!0F3k8OkL@cAE%N`|}Yde8lQw`DHtI=#2n5 zgiT69PX2!m;b#yWBF~;s7Ox}0Q7l2&w?<5R%gZMxx;V&8+`e(&iFmCx}oO19;d`^mFP zOpY-0SSvwg?$7nzscQBz?I$U7Npyg`Mry}DF|HyG{%i+}+pW5UUg^v?a?Vm36}h~*Q0SQQL_8z%3H1;CU$#|DD!f%Od|K(PzB zUGpunC}eQm8sMbxd#V%QEAmcE8lf=DNIY3RiPSN8=pg~@V?L}tQB{pfOGs7Nn(g=ovUmvXG+Zyu zHs_BIivkq*Mv}lGUDHf_{y>mCH&^Fvm^yMVJOiOO5c0n|h8}Fhc+MQQ2S>)wQ~70@ z-h&?1Ml$Jo$O7WyjkUZHhs(!$5wqka`9j%TUV+8nGoCfmChme35Mo8-SiL#yg>~LulCCC#8{&<@dbAYiMmLNyBw9&50fh$m?J{ulo_e54)~i zyr@4V4X|9kWxR{Sm?qr7&;lvqk!)SC@5K0;M^kgp`jY2Yo-UaZ$(CAYD+vbTJX~#Z zq)s6QK%bYrDDX{VMPf(+j2qhiHS;|?XH$0vc*+0KEochd{s=G@8 z-;=2kUk}zx*SS}KelU~2XT;O}t@drcqCEnQNu8nqiu-m~s+F-D zc@TETO1?Zy?DH$D;=}#+hC&LI)Nz5AV#$iBmIG zv6-|=rKih44cZ||a}lfHo`dE3Q5TB9X>eL*p{~9*6T0-6y>u{YfU0Yb#SBv`PTh|V z7v(~NMTDFSUSh?%mTKdu2LEx5f@2%??eDSyK`ZcWG`aNnutQ@SYm1BYh1=9U@e=vf zey{{x8AWdOhDOncb|b?gem*|9QP^!y13JoAiV^uVO?l`Ra44aC<~kv^E;RsT&M1-Z ze-Yb$SGV57@`6c6`=zCATwHV%mDiB>m?Ayc9XvUIZ>(fKUTVQdTiQEM-c@9G=!eW^ zdKu$!tuqmaIwYNS-hxUeQL4_!h}5LpwbdD#f2LriYz#322JkeUj|iW*soJh*hJ@-U zYFf8YA7(xth7$%EW<%Y{CJ9EiX~)6F1NNp_QN!WB9d)*yk+=)Cbb&Q`3vM_^)>9jO ze7vcB)`Jv}%(3>U09Fgc$=#!he7#zSaEk{?WDRl=Up>C2=9{2`nvq`y^(Qnwc6&vz z6o_uQPSNMQyT~15KgmGYE36JG{ds(n9^jAHL2vb^xhS`M>E9A^S(#C@iXvsI$6x?CZ8`195(CF z`&0)8IGp&4^LD4n^fwpm{)4{uySj_8F~c(?dI6=m>)8CI{~`;G#l(zK=aQuJof21+ z{NeR`$2dji!0VwI7OmRpmi3Y-fL10)H*$zqh!YD2mkdU5+|0V=u%4XGe=A?zv!$wh zIB@pS6?A~0ZS&f<1xZTXx|vD0`@3UTgzo3f5=pCNw|O?@-Q3jJhe8#8$s}|T$%%m- zuk~l`+<4b%v|C^}V$%V~5n|I`uo7J?%JYI%>}csF=MjIDC^Ii7-cU&HS-^@HZ1u#R zdw#w;J7ak&__Y(^0|(jAj~KDK)I18KUk38#E{meG09z!fggHsdRCgsJY=-PW(ghb zXn@V2%L#vUfg$2PsW5{!5C><%l(d2y95af?+}p6_K-yKO=liXi@?F4ta#7O{s-h54 zjZ)nBWoF;yKTxP{Oov6{l1o)ksGUV;9rMlY+{E|_5KZTCt?OHRNO5DGKTNGxU-4GS zYM+6`d&l!(Y~@%@Y&BH6l@4@>quyhp;xfEw`?C!kTbDia^uQH{82)jRHXx2W|41^8 znF%>P4~%u?`zE%xD#R8}uKS`_W%%*YS}`x1xy)uNr>t$IgF=)Hlf32nI)~q}07NSC8p$44RS@*Eh5Qgu8uNR> zWly}Y1lJ7OCYmjlPrQgT{s(i`trc4iX*{6`4 z%n=a5X!F^;a)x$W@ng@ZkY;I24O2*K_g{W1T-4@FUkpcFovk_mRo)p9GQ731z2W$S zh6Mcm#J4{P6Dcls##~>MD!yFb%YML_e!~ea(c0pFPorI4#V_l5mB^&dWS|<2TRDiCvWdoOg@aW=fM1l zpY-2jHHqEpHD~_z@v4wD6ieA|-G?CASllFA8WDbm(Fyz3+J?@wGycitb&%rqPg-E^ zR25&d`Be>DcBf4mMSFy?i}f!M@Ve?|kk!2Fv(tH>?oxt)$esWxL?Rm4&~PaSEE7Fn z;^-4J*DQ}MO>bDetzL|U81)(utkH4+7#dSA$gi9@Ir%+5$O#j+E>6xJ8$+kKFE(R9 z-c9{(2HFpVmi=5qb&+uG8Qt&CE&|)KbRz*UBM*iw{v`+KJ{$SzYLQOI9|UMXz;h@I zCzd8z1F}K6PswA%2+fL%CbJ;hpNF|oYpsFiwgJuz15c9AN;RazbL+|O4XeQrH6~0` z+%qFbwb5wJ)+(@_@3RfXo8eM>_cIJPdgI}AKDiyj!!RcD^p<*I^(kh~y3L+(kk(B2C5D^H+0 zBFdDo{fgy{PMbHnCBkP$h4qJ3W&(h;5=)q|Sr^--elR!>6UY6sAhG;I zb@fDC26}it;DL$GF5vY<{eoocI^9J-K)*q=yW~%Am?<2HuF!T zW!0a4=oJTZKJ?6rG??ss%o@L8$@yuNQ~DtvHi&*65eIb~c)ugx!Y%n#Ts+MbMPjY8 z1Nab9NLHYw0Q#9&Xjxq?PY$l5Nzy+Q59ZyvftnNY6(jg%g@%zrsR~7xc&%ZIU88^+ zdW8$_F{My9-#bn{g9$^m_tILP4xame6@@7L4gQ$ypSQh9U#Z)bL>2|_)%?o(p@Vkc zM*bpCUqgMEM4vc-TYX{>kg8 zV-fJlC}&vD=jEBQ48=%PYWkSOAvDm2Jx{`(>$!bz$Kj{rYFI#VfgDt=C3w=sH<5yi zsN=(H=6(66p9(rQPn6Qy+?*E!Cw!kW|kmS9xg}I>A$dw_tIe6nZ&xlQ4r&1c>N| z0O>Pce%BR}pC}Th**m}2yn|5Jkm(s9-MV;5iY2ldco}GwZGZQ1ukDp|bfoW>0|H3kPm!@l#S zq==wL{}GD2fpe!mS$Ty)!#Opx+EB#gr`p*^cc=dg5$=Gm1>6m|MT)N};J2oNJ?FYiwc$*GY zl7ZIl#nv45=MZ~_LHW!SPpc3tWyHb^_IrHKG7yegfINMVCtCz9pwLf)+855-$mYsS zeKf--Bz^=KR|? z-HBxN zBH?R(_m2U)QR-co+j&M`aAGgwg2JP98G z5J}M%k{KBE23$cDQ9yoUfqEol*h%r*e;#x$*L~9Oj9#d3Pkr=ZgPsv43ocU zt)QOob`DqbC@pju&Pn7}vPSKiJXt&7c^PJW&6|w3UIggly`)(+{aP0>MJ3z z5k~7V>V{>q$(Mm$p+?T0=;J47mB?!Y-4UzF5zh%CC&V(#aDGkOW$Ya@yzF(JbQQ&?Eo0;fwqLM_Z*?R)ZWqRYI2avA4RT8+)4sSzIg_*)A5;=Y&~ zr9_=l?`n)8(Kc7ReuS!5W>m!Umhu;^$LiK0QX2Sg`_j&3n=Xuq-CU?C(uP{GyD!}g zPu+9Pd&f-_8>05j^1u|wh^Xgm-Cg5}EBFY+Sm^o5M4+R6a~KcYUw*L(uUctX16G;v z$&Jo%B;7(<;o*>StR`$#FjEb{h-RXxRbc2;Ntc7LyX3>Jcw7pNO<4~_-=FqPDdH(a zTzYIf|2DY74UTN<;@;`ZAbAM4uI~IR8vrOZt{xvi%V&GxslCz2C+(%^q%9uL;p}ux&`Plh8ituJ&g->Cvu|GWIAsgN?T>itC*ldYPr) zMiv9660`J~TVqY@kEn86#H$D{lJ3P5&h27heGUSYj8!HE?q!%FnB^N)n#|q~oUA+c z@gPx(PmixtZ+hTRUKRfPYEh-=&Ij_oRJGM#kjV5;HR^=YxW;Y% zw{3K|&4j>u*aiYV@n+2!<=sUf&96iv; zxG8o3lWRD%L#s}p;IFi&?;JeqTkF9(b{iQbgPB^N5JU)TLM?lZ=uJj`O2&1r|NZD% z62)>WxV>8vo(V;KfF@i;qCs^nh_P&sl#SW#Ek2s{xnT5F*s$yRO8&{;3}JfCGiMVd zMLIGzrc%~+U`oVqyu&=I6M*$ILrU_=t`iCTf;KW{qBVunw>Ze3a{&(e+|bdPgc@j% z8eohQ*fH3SLIKA^N`Wb1_oACWI{b+K*0J%VaurU4xtlXpE);3ci&?Uo=P|TzaPAoB zaVgICSzRiKP;{Zatm5zNsEhhqRRi)qe0ECzOGkvJ?$|C&gbOR|-A2wEzRT2Im7+;2w6sVl}omDNC@#GR}rUuPvd8Zip8WJ$u1EZCa!G!+r*%d)^k; zWwa%Kd+6l^NyCoSRg%Eyu|k$%`X{^mwdI?wIa6kbW}%T!9v2O&5<(AXaZnI-Wz$bO zp~Di5^XGG;^sz<&hU48htnZrY)Muj1j;by0!V+y99x^DFpB4 z9)%_f%>D0rn>ep=lWm4P5BJPo;g%XHmgC1?eCew4YWG{9B^~sHSfEc--Cr z*HzW%vn1egtEZ=hhkh)(mh{B~Ej0E{L@d9GU~eWur}3u1zTa&Z0Bb{~uQXgAvxUIC zmmZRP$!Ar2MMRFNva62gEQIr^UE;HZ25NekrgBSVjJEzgscKlzq$!Zu>Os!WGf{&4 zFQgR)PDSfYMhPg0iB&SU%0YPD8%)00S}P!#jYj94CE+zLn^Oj4rKBSj)et81E?U=x z^D9S!&HJT2Q30qm_-vjF$bx}`+!-^AJi3qQbtuDreMB;9@1+8k0+b6~UckQ%>`1M; zJL95{pM_h+;t3mbJa1p9+sHb4f1qSMWj{Uq)_L8bO4h9KO(oF>C@4i2dpAJ5HT~{5 zVB1z&bymbVC?bmg9=wb<3?7&7u6_@X6y_0`)&bycWxlkMxbm`36xnz*en*%u?;6r6 zE4U153Pb@pIl(>=UJFvR5=|x6l8)4V5u3h{TUVzb%DA#aa!u&&4{$Rq4qDd*^xxrk z94)ViA4?LAm>5m^M)ZXtms$G1Qq}<2_q`AH6W0KJ{)b*?R;0WFeBn#1z#^fT2J0zD zmC{lIdD{th%d7shEho;};MYqQGi%Qkd3p?k{EyY)XYX#Fj6_DdnQ}MGz`=IJ+qNPH zS2?wv`E>EuN1I-`Hb*x0Kmq?kOZx*3iFz8t>bCob(<&o}wjFaKqFs+pguT0-?=pWI z-W@zFm2Sr;zTh3C_anK$)?u6L|2Ts}?<(UVCSMoIGW4nxqS-$E4N~1?!Gkv=pki-P z_qKW3eqVxz%AvrbURiX?5VyAGQv>t*^wIz@;rj!P88`Rt)4v`G*0X7QZmU`z#@!d7 z%^w(N;tch~C|PWX8`upxG;|hVZt}(ovKDsENb9>l*dO%k(m!g`-+3KWrz&lYm!XkG z$0Tjht;QmTHMCRQZIgj zdAsktTpDhmpN%4(>y%Nhl7}Iw5Ee{HU0>b9e{!|r0 zEj<+a08;YJ5pVak8mYfLQe@=Q0#r0zrG!OArYhq0Roo^eI_hD-4SsUvegqDe|{*gK|24A{vYcWeDNfOhf!^smp9j2soq z@Yj^~Wz*JftdS)`AX~0BfBY1{)cVcap>px>xLJpyGXkPS*ImRubDv25quOvza-$8O zDHy>X4h$ZzJFH!i0X3-e9=3&XH=P*$it*INY6pglq@-E`u zJU?!89B!?t+L>&h(=p#=2P*fOhtCfBOtHf4zmEA5YJl%K&F|MlSJbX0Ug@zmB$j8Y zMpwuhiN{vmB2NHu0SjV1SM%IG0w8T|G+60HfyLNr7V{S73hFZ|Ki&4{<4_vrHS`y* z%bMff6Z41AU(-E7Sy1W`mpu;y)Skz|xnian;D^JjcXi|flbxL+q=d`xSlx5}I>`ox z1dkA^9;35nFGlxEx5MFYn2E+4H#JOaN|92LU5i~D9tH6{kCtyMn~ap~*eGyLIR8yE zWzura+|j*ce&>%9>u4XE@D1bZd`Ff4PZ1MJb0KDuuF(6NREHVYXG>h~yIDNMtLp%I zonN@w#(_L+;z!B6@iVOWn;6;9fbd`vR8F?ue-)l@DyX7=#CVZBb|y^!!6b4L;hn$$ zf%jfymmVkYQKi|(-br|@;{GM@j{rh z@PCE0+jy~NGT3GnJC}|k>Zp@w_KUDd^}$Zy6HY)n$KBkI2_?#1C2&aLngG^QGBXM4 z1>-$S!&l1rr}%}yl*-dIOH=;rV@xOS6_cUYn2q`e^5l2MK#^(1tQjh2W+USxNH@?W zmw>$HI)3-=&f*Z=zu1CnBnS_x9i-Me(Gjb=;0awQ6BcUQTb5tiuBRdPpJ zI^?X~^GU^yz@-P zqaJkE@SU_Uc`ynUMavC8a-nC43-H}fs~lnBk9cNo)LJEYXuG%8mzKAi3+%V~k!3;q zG92;SQ$>WhkhV$=S7SnPwKk`M^vW*fGFtogvy$hYSGK8pBk? zhg@^Yu6)jpkL|x0Xz<;_@(mI&gPRTuldj9Elji>_<9T%4`6>GciV--?m7Cj_CXR91 zwy|}+#Z~92$}kr7(c9J!-vQj^VDDkY@yT}97Mc~G$>LGjo{Qm#+Hrtc;OE;+$%SSn z5@QBlC_D~UB;QC7>NEY+MPuHl3oju-`cR%V!T+sBzx_AUY07V_JMfIHe+|ZPm&t-)VbGGsj8A5Ll8iQNL zu-dFg-pYh!uwSJ$BIB$iJ4DZx{_E^R6w-Xb{+17lGT~|{<2||1eodMM7<~W92auWx zPLoOxsWr15#`kYkr>vs!A;`q#`TP_v5kxiJ@ZU;j^xnLbg~Zw->Cb}?()=c*I&*3w2Q^gHYF_USi@k{ zm`*sbH_6A;gkZZuEOjMS>Fd2GuhF6*a|SC}uhl?Up3>Cl9nxuQd@8d4b2Hm@17Z{U zaudj|HQ@D$;pf@PnPm2L!>OO)T91*Tv61)NRFvn%X+sa-@KfqObWdK?{=SKqs|Et> zE_}I|>L+g*ynbcK%rG)+yDLxmynJgMFUs);**C5^NaA3Tw{bMEG(JIk$jtoS6cdSI zOLF`Q@~p<bW2HzbZ&0c1D#BV<90SPWwzvOGbg>My6-7WEYNIpxj>!XQ8_%BdWUFMk&>UEJXxVb?R3HH=H~! z(6cb(iU@jLIFq88;-BQnEES$yW$ScD6@^Q;ZB~JclFGxx87@TI6ZAAY3^wE+I%-&T z7And*ijdsmc-FB2`wY8c7-AeUa-x-wNg7r!Nsz05sV?-;J{=%! zoK>QbE?VSJ8N@hNNl zu(`{aqA@qiJ8pmw>dYq*ypf!I&3`HLdM?D2KIs^4xH>^}UC! zDe#y>uc58uKCd%qC$ApoZIHe93bsqY`k!_8Ro`$D{1yF#DWmgJh+#?HHL$z}hsAfz zHp*uaF~|E$b7XSd&ZeHjncy|2O2H3?9pX@_{KofQQlN0O#{Jba&W6sLw<&M_<&Uw7 zyZn5QugA@6+`c0g>nXmmzRCyR2TsW8z*mRhwu3OL>!*ED^JsuC;VqYt8Vs9VA}g~g;lhbOkQOysz)$Y^P1(mG?s5zCFLF&{-+=<^c%Z`jcGz%qG1)LLHcA7~jw! zsEA+z3xU@lvomv9{@%etN?>qlDxwf-5gep+VXT#lLy zo@|C>^$R1;NaYVQ=c5IJP2_%#zcpNt);IJOi%|p@FV8AzfS$Kf4C8s)GPiMp^A_pO zICEiGtxSPSahhP1fBH*3KL}NJkyDWvOXoZCrw9%;#OcuUo7flvL<18C$01QY0O?G+ zRxOv%gBJBq6VilIy!;OHZbH{_H^Pe}BlEV!`sl%)ev+U#>rf2czNaBCT4pf*_T^5v z`u;Hm%YpSDpFyl!x zmz&fktOJRsx*VU(;xGRZ8;K=!&?ShCQK_H5U!&XPj!&a?*r5yHZd+W($w>R=e=sdh z%a}%cwj@hgkEun}b#F<(zN|+gY0k-N3|lYkQLzgJI7EGHyEh)Qv0k1cX0KxVM2i;n z5Dz#f)LAylkd_v`&al)L@XXEC^NvE*ArM3oR3;v;wy$S{F7G8R8d#+9oS`9e=(=dP z&W!27Y8^1_*qI%3dY+V;pMF({Aw`F)F#k$S=uZR%z#OTVoAk&(8CSN1><4+oUXu4K z{0Y^~aFm(G=tE?vJs)721PPdvl6;>;D;YZdKQDj;((HG6pauxiI0tJU@1Nt}DG}tM zBa7`Rx=(>)F16EXtZ0jNS>J9=;X00wCjylnZN@RxvL+MXU3})R?N|J)lcnUWM@Rlt z8`Mj6&YsR$(xt`O!+jwYY8Y&hHh{tJ%m_9F|dl_U8_q9ir1X(qZ_d5kh7JDu}-DItv3 ze~2ot``msa+F&T|Wu?NafklGv`4MlUFf6KR6g*uqFPQupUh0RbN1j?$BDiRFc6?*( zCM4^ti^-wrmhX7SqRX7;XRby@dDxCLTM+P8VJDu9#AZ;v4QXMw*7GeUcQpsvoNiyh zMjxU;O0`QI5R11~{2g_lC=-+m`<0KMn|>sv`n3D9%yBm*|bzD?ui885mz1RZL#Zh&>~1Ws_sEkf@3zbXf1|0ux1` z=4ArkGsP&pdk_N<^o^soonDhS3eoJ?)cAo^iEY+CQjqV)+vb;rbOCGeV6jrS*C}F8p;h%gb1xaA~uM=5WCVAFyOcs zK2`cKXhnSLH6%cBP{gv41lvO9CCwtn|2^rHGQu3)B9$6Flm5~tUcKDIm={jYCG;UL zV@dQ&gddU?m! z*m$+iS1*D1*FOmlgbeSPtFFl{6>r8(9P6MzR{c!PJ}Dk8--b3y6vq*K*N8QaqlFvC zP_9KC|6KL4D%(E8GGwW|xJW8HL{iB6yd^Gqa;h@2ToK~HNQ;6d2irH5VXveG|fn$co(V40MK z-V3o8?M()sNBAG2xh(#mNwAdT5!j-V>mr{NY=n#5{QJuva_&Q{Y<^S*kSDpQbJ6q# zrEk_}a^w#|(qO8*ay$Lnt?-oPWnt z=tGx&=F2lNk1VoV+}b*Uu?HXlWyOZ+4IG3=AE8$R{ptsi09ngGz$2@TPnqaaxbk$E z^98QP)H?;i9u^WW9ZLWM=51KP!aUaoPV4_tzxy6n7I#%0Ih9Cg7nq76fBwF9bX!Lb|W2lD%Hvpztc< z)1JlPndLQnEv$dh3246cM^0%^OhxHZSY5gP5fw+myLQdI&0@b9m-sIG)=l%9m9YK# zD0Of0PWYJQ)tmj-Af0P?Rn~a~zw7NPW~+d<+5OI`QA;C)fi&tn+}g_HTM?GW>!Vgs z3K0oY$gVS&^Po9|)V2UUFLjqy;-ex{?{#%F#wZhocsjP&IJq9LYi;1bKdyVsJZemk zd5Qg!?(qTFfol}!7X5^q8pIpN=m8i;ULDz~MMY4|U5lY6oktf8^ z-(zucu8N)J$Ju_j*avtBa$o)+YeOqaA)2?G$)}_y=8q9L7OVic2ANe2Yp%K z6-bJlBn{%_+Y-{^zsJqxu=s&Wh6}z`pPt{kGrj7W)?$EE>j?ej#~@LT85U6b#DNxi zBBZmqU-ea~_5zsVGPtXiN^SjvHf&=#mro2wsp1DIgN;sgLwbm{$BFAEX2}fDXsL6X z-QJp2&ON+l+Ib*95W)X*?iv3;tccocS56&&S9m)Yn*8tor|4p0{HN$j7)|>r_ixd~ z94OakjJ!U26DEjy5WTs%?GzPn>E2!Ln`heEOR*~f0>Nn5Cr==M0ljWyV5>Pq?;q#z zkt6*u(Nu)BU|Qf;$gSAEMsGf5szrn*_K8IZSYJo$mPj^?c*k2dV}^JA6-tNxb`YD{ z`5A?1YLTu_X(h>WnoN+neDFzo&xsM(v~%-28r20~W9su8U4@fFmbb7Px{=cJnLi1b zK0z378q4eEl9Qv3zn{}W=bP!V&EGyF?0fYw>s%J8>+81-8bXmNc9qw4Ad_# zZ{^()F(-*c<4)cf;MtKQAjASFsZbncx{4jf$Da?&jU-Urenb4C65kCOoBQ3 zglIZ;zd&v$S!rKhfro6S>*oIcxS^0?pFJHGmi=x?fTOaazGltkZI2>}bAF(dXF_|$ z`!9euB}+NMsR6zf*<{~<{TD8w)mbUG>eGv4*ccYf4$B5VIUNS0=z;UDc5auvkFzKc zps?3lXY!dv-{x_{my(FsSPT7jivR)Ixc<~X%{E?MllkLkcW6QtQ8$6nU-d^bg!;Dk z`uG(hY}(y&M4$`T+no^?<1gz4^;t-$0xEPE#L{nKIcIjn?NO}6v8QuYW|QVp1(NaU zI^l1&$fN_QfY{rUaq$X7P~mHLL`J0obiumF|C)FFY&)(p)4HXxCQ6s*yHp>ALH1M> z91@LTeEB52yK}q zh*X&dk_}-VwQQ9{j6rQ3Ybv+P-h_btm&V?{{N^ttEjlb zrb{;-JOqL}2@)*0G){02!GgQHyIXLFpuq#dp&M!3-CY}Z*T#l#X8!rstaJCCyR+7* zw`$j}rzUblZQ2Ysu8aa3#Z{vThFq;+Vay9JTsu)v3xW?g-CI8>t=q^hZ>PRc`mR_Y zae37qw38J)-#UmJ`+@_V6v;UYGjmDQR2!)b7EM$sX5wZLnbxE>b{Dw?ulmbg5a|b^ zCEc;GX6;55VzUtK$CXNtrj6G=5i+mHCfh&AQwugM)xe$@d`})fKak3`_}eCa_T3o3 zHEsRMRavPJXYN$tV}g9-)f8CXj08U%7l(y#m+syYBq2_o(bqfBr$^JRWTW!!{%30} zJ9MRwR5)G=WXtrU76Be?)r`&(b_|*B>dfa5T#OyNOb$-!RntaGEJoR9-NIw8Bea1UeCUmXKZzgg(`Gg2Z^Y)mh^5r?WV&e#@1c~9zyoQJ-f z$YriO4FlV4y#5Mdi>ziE;r~LA*ip0i~*t3 zsQSb1zfCuixjA!?_h>@=>Y91ZtV#heRtepHSiff-(uOx><-rEwUmL9vduN?%OZ1@Q zC)cz9{AGzi=dDfWKRk(ZSO!ht{gk83W8!Dsrrd%W2tHDFMO;S3PLZrn6VRKVpq4koWbhF5!xu$O?K&=XPkwbaU|G z=pUN0IdZr22h~|RgIc;7FYf;$w^z`NB#mbqd~rW}mF}Xp`?nUQNszc8X z1&ipp8>4PEIuqCh2Rm~wf0Z~mC5Uyg`R9+2_HV4hkz8?16L zYk7r2qg`)+nfO)dU!nW4xS0Ye`|kLEf0G#YmPB=ZFYZH6G4O8%{1}EM24?Qtd78s3 zBemgxZ`Kh1>wOL{?hmxK8b(=4KeY2zb~2FtS$>TyseFZ=^8!nh$zIxrwLMSY5t6WDdJ)6Cofpq z5daCzI)StS%fh52XCf?|&E_+^4+}~%@j27*HcNT1X3Iw_lt*WtuItO--3Nwmnwmta zoF}{e;CB$ns9a2qsE>Hkvw8!J_ZJ8EyLGxa{Fr>s`iDNs0RwOLQh5LqwO;D_H+5gk z*r2lSd?G1G@70(4#zo&*4~MjiFKKwD5AEd#tN*ik;51gNWS(HVcR?#GkFY;i4_i%7kXeJ54ow&X_w}5Yst+RnU=3J~23Y z=RX>9bmt0E&1zpDB$!sa66>)i?75GQLBE0J@L*~28}HcWyjsJA2{_p&l&koGm?RNy`wU78Z%yv9!N1!{ZPy*G!PZZ7tn+Esfz0tAe;I*sts+Yg$dRK<=G$&F zuWNy$N9kdBBhp5qtNd66d(=E$RG0v122DWzyU$rFHVig(*;IyJF}UDP`yL}uj~EWo zF)4r)BFCue{!cuOL70Alkkzwsv?DFe8)wS+#E6@%LW2G8w<}Nd!K-2cAx~9sg(5N9 z2{*IrUjDw4%3?ylm__`3V^1zp-}%v@NxtP7J0$s_<-{sD z;$T{6e1;>oHtWYF@-;xg%)BFds)JF5BNjt(O5!5yX2E=OV&Ergu~4SBTRW+o4=su+ zkG|4Cfh9t4lE802JpFx#zzOE}J^PqFo=C!chh?k^pt$@*aKU|+$g#tfSiC@sulsNP4nk4tKn9>t)iOL0Qcd-d9Da|Lw0pIFOi(l$l# zQF7V4asho}(0;xF1Yb97{&Pq%98LC4QCz@M_ELP6Hn@Z4Uz|Ak@PvcQjB-Eo(Y@V{ zVpPA~4gP4!XF>ZYUIrEBFhlwV_-^*SmTYrtwML7amRl@kV8bVy69c)5e?IxcgI@oc zgJ^L%^&^)=s1onB*YEhImQPPAY(@Up`;MZN!ta%?V<-CAqYvC%Q=-RWE6VygO>0Kd z9_y#q)}E?+OlM}U-zzk3c7OlJ{FN3lq@qet9k?u~xBgk8hlH5E7XKD=as2srFRmTC zyyBKN;9TYGah%{Q`!DYDu22w$O~03|HZ!Y#mSw*-SQrp@-F>!{ePO=-l$I*bKb!(# z-UN-~J?|A@9|pjPZ**5mJuyNVZ!5cn`rG!xskXQw9H=MMqvFxxNHKYTvB9T41YW{( zyV+?^eY3U1z{P;dW?9shS}j!|7ja64%a8@y+>8BM)>zgZ7!{2=shZ4LQ-QXq&ECcl zVgH4Ek!Q~B@bIB8(40yinbDFYTyE2QK93@w($PM6pRU|{X>;9-N~_h?8kyadhb&#n z`;C_BcEgN>K3xA8mE?dDtxY9%XXAH|enfH8LN{!M0!~>V=g-r5b2QWTd2)293_P_4 zBQ(^FFEc1^)(^BJ8;^ahW;U+$1>fB|0J~#&n52A!eecM1Ft5~O$~pRsHRF7CM}DJ{ zR$C4d|Kv9ZhEatCCt-Ywy=x)qfRkO;`c%KlxBQoODuC5hvGlvLPV~epuW%m?9b$Kt z@lt;NxSvL*f@!9Sp|0H-+hx8dUIROGTt7QkOmuY0&&DkLI8%$U;2rSizCNEQwZl2u zN@P2mf1sOafr(2$mQDN|gfFI}GT*|Se8lNUyamBZb&EYB1rC_5I7x{l%%0AMRg$Y~ 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 FV1f$9_2K{k literal 26749 zcmeHv2UL^k)-EzSwy}%_928+xL_k0VL|R}*5$RG?1SyJAr6V08<0zvDj3Av5rK2>Z zmk`tuhhidxB3+~zq(}=TA^CT3=1gAa+`H!9bMF72xyxD0HSx=rFYo*8y`R1Jv)_30 zq>kFUHGFHhxVYA-pE#z^#q~uo`_HN`;mX{_{4d~t%iQ$UzURsz?V!S6PF^xnx6;<; z5{1{RxVV>X;##_eYZ(_;kS*78_U-UzFZ_YW+*|g?yZ5+%fA@>xdtdzVnth|9;9(Yg z@T{$&k-L$$mb|5tgT(oZP8TjocsV$;Z{Sk&l82WLm)y?_dO2Knbd&c|+O>3tJiKOK zmfR({bc?&a(k>(IlY&Q`TrUY8mN+1BU>9bMprD|l>qRSh{bR>}`#AhfX_t+=yR*Ec zq^GB+gr}5*ldHAlK{+`&$peQZ4;>PRJH*|*9o^4+i95RO{`ipJpL6Vzo29F*v%9U6 zqagda=Px*2aaY>4i~U9a`0wL7-EFP@_$EiU-?jxClw`jnc~Ihj@);?kYSwcox+QIh@T9EVi$$!9xS@Vrq?@BH%6)yE--x+!> z8)^IQr|wIM!XF+8#dO$x|J`>wCdR!IwI%(mJ-ogZqiAV#@Z_cfJ;P``Y;Dlm2VAY+2oA;+oeY>o9xqfP+82 zf;F_LOr{4^Y>O~gB9G6`E1jCCD`&I>b*$86eyehoYZ>?QRT~ADUhuDFq=)*p%5z+T z_evxMJAGFD<0kftSA?t19gAz$p&x&mEsI|0TDz*aEB6%_@>zJ;7s!Rr5974KXUu+c z#?OBCIh;Py65A6#vj!(gd}dk>lKAWzpIu`a_vgIH5fYzED$bDj>>8h4<6|Z9Id5`! z!soonNfMu38)@6l%a?sr^*@Yrj}!c8 zJ*?yja{`m*(bPNPrj{(Px+KZpvtEYpq*W*pHvgf#sa&n{U)I}ll=BK#;Mj^EJI2n~ zaQ!hnfCp@JB%q^%cV;RjqXE~yL_P}-+m2lLcRwuDT{&>s(o91|@I!Z<^|c3;8liXv zJ{doIx})J4yUH7!{JK1D z(?-X5;~=ZwM>9(+d84=d#||~UDH&v4ukKb&ng}=wNH^bEy4|981*xZ$_nQR&(Z~$P zhF~+Sudm?`eM6z4KE%4!up*0t%l%x-xA`6x;#|m}u}TT<{S03y=Q@JF73`F#PSjTa z9RwKg1eWq_bR6;_+}O=A?Wwx3YE^OYBWr_A9HzC%0WT>v%kAadMcy`m@xn;kUCvF! z*e~n#$Z54d!inwv8&{qG>N1@#9;}vL+Rtrqw#{ESK3Uwoy0g7hRU6=|{_;}Qb}}{)_bwSEl^x(k z)0#YwnYF1Kl1j;yGz~*pkp=2_&M$>ir@bHu6dNJv`;4!%SMe(Ms;(ow3rAwR#y|G@ z#stFDfa3z#{XZq<0|$yRotUbRi`}`!YkVMo12f&6eDcjqaj~^m{KK86-prLIhb^R5 zE;+O4>bd@+O<9)61}!|mydzm%$NsTp_KQdeFpa!Wp+A6teYXJ{AMhs~P0V?)H zK8iD1mRku6c9KZ#+K6>es;iV_FMn^u>Dn7(a95ob6zpZc=7d;9Xj$)HUTCPHeCwkn z1IASOO5z=|l8K$9NKFC8fU@5kT~Z~j_6wE_-JCh?dFHLAlS5C4T^Mj+v-Yh< z4kW?)cU3+_G2I4HyiF~g(~+)L{RBY&G?(+yIe&Xd;CTT0{0`jr2>QFh<9EL;k3%rM z0aO~~;=Tq!|2BkC=uhKz2&UVPtCalJg?{v*ZG-!k7F)HAduY5fI7f-zE~aN{+W;^g zGuQ89PLHWyqb>?rn*}f)+0cwtA+S6?B%5P>6);oaVS1z4qvd+IUEDWS7RL5kr}pd? z>Y1gI!)q3)rM$TVECuF!^Mv>v{_m7!Dx)_L43`DoS>flZFv)#R7uh!j=H!&^@`1>{ zj|0o9nO%L4BJ2YQ`y3TU5&jhr{&lUh5(1GHjO}%t-YrKVItvhaFUt`|9GnU?O)aqiY$h zQY5s0q1f2AL^r8ESGrhDYZ_<}myLJydGpXTd zY+9x(FU(D4IO$PTp%FKmJm!xpDWJxqjN$y?);y<}cVS*jbdn7KeHYJHoqVg@&rW4e=}Kk`t*fM{zjN-@n(I`p!of@ztdG?S z9kop{Vu8jzvu@X$8V+DeM{Uj;qa+^$UbVqaG8y**EAQ)`mg)NM|^+bI2 z-fjRf`I2oU3Zew0`_AX%oK?|P6*Z^~)an{V5rZk71H4Oud(dTt0#AlUrJh2N^#Z@9 zJM$7Xk!A6(-a*Yclf6kW&ti$q_Evh03OM4|egU@@l<^#P4AX&T&R>-Vy zrCxiYuo&dYlECEmGwZ^Xd2qf<1+xA$9nTV#z%Jlq``QcgE~ZV>Gpl2TbRKSxr_Q;U z)@b=Em^73M`KMXyNJz-Z+8KTwcxSmr<+z5i7B(s}A(Q3|UBphulphc%_yD!-=0DRA z*L&l4(aURde=zm>8yU?Ie6Y38Z$bXvjptr}MVdmEA`a3E$dP>F*bSbtWKmtt(T0U$R3ir z3@JuFKRt?n{4$#Hqzs;A&r8@kF?_>K?e-y@d6gy(w4VL158?O@x0akPH9n zLY*(ZqU<<+6`l@t;`Zr^#%CI1L?fTMt20g&C5mrsv5LbZ_PJjL4E9%vMPq&_Ta~+yKwGFsi}Z#hL@AI*aI=4pL@uB`2n5-)~A&&IT~9=)h1UZmyc5;ldH zPaaQ(uBPnVhcWvRcHi50y05HB3X>Q36p$|oX3*u7r7A1*d%H<3Z-k>`q84xeYV68dR@;i&9O@js&WBygo2|t(fy}8&stm~c= z?H=wvHRPbjM1iFD(T%e5a^n8JGNk%6>O;|)1g%pS+JnEBXT8o3^T!TL)4C}be^&)s z+J8?%gN{r49jb|LGXXyH{bCI5xH19%%+>s8$7KoOYUxz9h}iT%AyA*p{Vx#XTU`FF ze|>lp3gzc#%qyY_y+P)hs|N<|Yln(C)ILZ;%UWQeyPMPj$<&0|rW>%OwPjxgW6rYS zk&u%#4hw0s%vay=Jzd1n;+LmQZjBdiQh(Zgs$AY*SZKWTc)rX+)`U(qW{T?BeS03u znlgW0Xxke^TujfHX6IhW%-FM)JDV$^)M1z8UFOWaIsWXN-5yS-uw+m4ET%jO_fJ!v z)#!Hn(J*r#&f3*qQY!Lf>Qr=nV&d7xq1Us~)ACjhHz_gxEhQbo#WIFCl%b`-$E|Be z(Y7K3B*~VOSN0-dQx5@#6Dj_ruL1qgBDLX~j3ioF1CHIL0P4e&rlr>UHb4P`_8R zcvD%dL)1t8;}z~{X2Xs64H4cN0b})j464@DySpSzre;r5l0sz6-a<^N_T46=c2l7M zG?e!ZI}p70z{RALPb6!o2jk7c1`$sc1j64e^od|y05mo2BaPPgH-V=1Wunbu8dxB$ zHCYa&DM(<))Yl>Fk%spFFk$CQlwo(}Rm>N&Tz}re?hHlB&E44T4ZS+Jj_t3LePODF zY%>jO1UJ$(NuXa~w?^hVUOs-M@RkP6Fgd6RIsMSd$LK@F0l@imYm+|qO zncHm-XekYcLO8{_KvjrE-YZjsoYigB4p2t_$ugsQ7M$sV->_Tpl#zg!K>KQiyt%4p zcyZnk9!cfGszOrFgF?@F0cB-e0|rxtq?^f7Y>zfxXUZ-``Pt1;b0kmdY;6*LnmElD zBL?QnX|dhLX}y#B)Lp+^0~x_%SI*M$ga z)_9_uqc*;FJ1CgAl|C9V2gHQBJCY*q9Wr-MK=t1uh~C7A?QyR8mG=% z<8S%S9i5w!8OXGG6hG%+JiO19BtE*bhz(v9tEk`HfJ_ z?iJggp)o5bH<=u!9Ht{do!YSSJ-iz%+KI1>m=4ie&|={a2>98GjJmm6Ehy=~XNJ2` z+Qa85Qq7mRslLOuYL=wC-AZkwm^4i3%SvTKG|-;`9X+dS;6pg!B3v9yxy9+(%lUw# zwwr~vaN0mcaPvk-DdAI`CJ=lDb#BK8*8;SZiUp36%iP78wgYcKRNjbAmfp2 zORrATL*6P`rgGdT)?drhbMuK6jpGf|bP^Q16@SlS_ah-u$NnIs7f{PQx7UlOx|lYP zj$XdfoNKk(4_`H0Jvh5Kft{0bVktXI(*=YS96WydMmnl;XcL*wI_hM~Y;?leo&_usptlbSFk5_*3QaibV;I0Y#?Uesm8q4|%>a^p+`Di&5iB=s4l=s2qo+|c+j z36&IMfwZNPJ-$Yqvk7R-zDE8pE!1MZK6CBL!u84{o#{Q^Q+eUata%uOV3{-9h_9j8 z%rWhHeS4|anF#FJ64i-MG)X2;k9lWn&i+yv#{2V_+o6{+3gXoK8-6t-GCty^#A=2N zDXZ5onY@Yap2lb0665b`rJh^pbAqHj>Ki8#TV5RJu1lyW?`H58_Dpw$jP^zRC+b=M zYWcq(FL$NaVq|Z185HMkSr5m1%8T=5h8HD-RV*;e8}XM40|uK)h}E%Ek46^^QfLu6 zb`_c7^!N5(xgA}XUXZ_ue2}g+q^EYZDvw)8dG`&%d|3LrMYk7FS{L*(amz zDV=MWX;8xmc8oKQd@ZGYs`+cdyc00DG)-}cM-+KC_7_txgs5_^TNRw2*S5ooGft`! zU^8xIMwXnhXK@F%t=e96mJ^`^=>SlIM2ivUW{mbg4!=|6aGDeKdN%0k!7@CYp~nN` z;lH{}BaGYd(c(!N*JmC-b<;m&_M9tL z9t*m1Ibfl3?^2*}C3BY@S-AM?h+Uj(+GqnKK?iRIAG9Glp;8hOvxRf-S5@jDq1JUY zZ0B74s$+2Rmz19n>l#CrHR%rRMzbt{yn8Q7daoWsmYwvNMtutk)$IpG&@3ATSvIOT zSr%FPPs^jo31!Y3Pl>|KRoqL6P?iu0K6j+Z)(2aIp-5@c%v`ZGrNQUo$8Ij}B5umx zEO_8X)mX^GhQjyuFOuZ(oyWCqAuGLi3Bq7t^j!$Dsa?x@4`0wn`BfY`c5x>)Cr--? zZUlb)Zvpv8qpKU3&EnCD)3S$mUxh9uBPS)JIyQn%i8X##m=bi~-XJ|(DY7YTs_BRn z!GwRwa5j2xZsroVWsAe~;Q06j1ki0z_VQ~q$|3tX5C>k%M+oNhc@>L&;NSbyhd3LQ zt5r4-2{zLboIL_p;C+ah`+IQc39DoPDY>B>Rp4)civ)$cuSXp0He}1cy3ndS4UQfM z;p6MShD0Qv@-_@x!R{nJ9(oYl+VU>{m&}V<1+4`+{f>ppHw8|QM*4-NSnpkAH=b2S z+`4{?&yCLX5N8LO%zLx+evgwnK}Zn5Nr9)M+lI$b;`KQ zJ$=-0+TilqxoU36QhtW5-VFcbU>uB>9DJ1GP+oz-$N!wdP<1Ee#7o8!O&o=y4~TR1 z?Qc)^DUElR@P$40m~;oJ^3|-(??O;u(GnyX_urQ<$z2QWk4il1pKcZtYnZ{5{vGJ? z$Bv)W(K@dHnvkLjegfjuDtnywJkXc+1yTX$=iIY#vgc zJKh~SR9Z?D05PAc1@e+AJ01OzeE$^t7zumtpSI z_BAzEINdn>rm)r1X+yx^>y=S4>y?PQFomxC7pBnvYSsSNMSGy;k#!|_q^wATS}A?6 zJ92H+ZSjwwJ&I?~%=0&UfvoB52R+}sZt#pM- zS#r%wAzuyHwc8vO_d59M>|F=ZE44aw%Tpoa4dEF3PV+;=_VX(=Jd{UX4y30#&5k*DnY_PyjzT1U@30n!6;$`?zOg~(n^RgS9}2d(l_uNu^J=xop|{W z(=(Q{mSjU$R(lOaXy9dQ)JXnCTDV)#aZ#!i!MEOfuToAfzotpZ`)=0s!xGvrwHo03 zEioblUwu#iSr0>u2OesiWByRG{AX3^|5_{bvH1EL}$aFKCz z9qp%<92VCa&vo%^PcBPMowoiFzu_4%>Jd@RZX{qNwoyFQKW#{Rn6Y21fv>2j8uOyt zwnj_HDYw7VT@wzrdbS>s!lj=!l{ctagwj`4ect9Hx6VSX^Mssr#X=riqeYDslIrU0 z39B>rAFIirv3X+H&-JgiXn(l|5&Z9I#6GH5;<6dC+*AAVeEaOATfpV?Om$VMBSKOy zlR-wXb-3v-nIkDT&~OVYBI9F@Xl_A?6( z6MPRDgh&YwtzRSq;`hU{T)StwI!=-J-I(FA8Vmd7JZ+i)--$bH5^kSWUKC}Y%3J7+ zaB(n>X{Yxe-g*ihKfVOH=Vi`uOSG?ni!EmozsL`bP_}D>=V8* zWvo)Q&83cnz4}3N_3}h4E%Tn8EtOrC4sV&+{i<%(X5qMIKVfK7HqD+=tQdQ7CyOK! zOI&nldGG8$YD9Q;EdmPC^$%(_suMG_I?g}TRMbppbaR5@^b4HP*_(Fu)9@V*dLeWJ zVSH!QWestpOP7Y(*x^zhZM3+DnXXAvD*79VI5+?te=ax;%`MOuiZ|$^2U@iOeeE1o z1H>dJ;XGWFO(v&Q#}&92`tQB1Ng_zoybngtngvbBOkX7eYg#5<&EB{jdHu*P}&&PANn zmkS~8Y2okLe=}{g)-B8gmd(VnYcG(PG>mcO?NB4A;cT^7;cc1=T4Vw=L>+iQ)t>Tn zn#t#>>!US}ohcPgzVr9x)qkoYek5DH)TAd%-bz|(o8q@LACam&2j?8uik$2l(g~5G z45WDKlEmic&%tjl>W#0!&r-BBNm(*jAIEj+_s0_xT7zweJHqVL>O58Tae$wRW)ExAbT3cHvz>oi}yRzzZ~ZcaE?;I}ZW8wwvE zn69tc0jJjFJhSsP21Q&RG&r@}OZrD`OU>6MWgW!Akv6x~LdzcWWU{+1JN5f4HUfd_ zjk0Tg7!>bQg0pjZ2MAc;hTfWIQ7kfx-ki5Gz|A-$*34g`$G=8}nyA5kQV0e(BKr2$ z=0x!4zj0mgzw_Tq*OR)opXoDb1+ulb-;zd%nm*fC&zDc`i_P?}84)U%l=JMi(;UIh zT@z62V@oG`T}ix=ufrA-DQ3P@w@I4abew!-#Uh`7RHwOR+BDNRKV7Q1M46x<^Wbc8 zrAOA_M2{~mwlJ4COBP@}>ls_P{O-Fj;`Dpq4OXLo_%Gw>Na&{yETl<|O7`SM%m&gv(Vn=%S=su@B`DW}=LSBRR1lC5tn z9OL^yTN@8@r&ktR+iRaGv}7ABHL);3gLaoDPm2{gJ&s*CWf*Ybk`NRQ?CRG}lXQFi z{t{o;?uTTh*q!Bf$1qB-U?lz@RUW`N|P87u)YV;irq<^?mfayi!F^l za!Hu^sCM?m&6XpDmgANEOulibx!jKef-wG$rOAa|$sD>!+e8U>8)}fjiO6L4vgHH^ zH{1F8n9w-&awJpYgeHDfLa0 zizX#jqily8b6Q+?P{do8T1t(@l!|-nead^#eAX1&pvO5hV6?DFybvi6UZnsC{l?Oq z6TW5KLXh`wMj0aof{i}JysLN|I%(PjUvy0K-(1~%%!5Mac^QRliA#Ec#Z+d&S#S|! z1@E$yir{uOy2)(aPO=3p}Sm{pY+xPYr>1GLb^*f(o4d&o?v8n^V2@y3~M|;L2 zI=r;kpef}P?6~>myI@3vx&Y&@H2o8QD7ElzHWXypj>pXryf?x?;9%tUD6(*@%;AdE z0*b5=%oH=Xp!L{8u*<{v2418d`vop)rJ_G>Fowa2N!RU4q-+%AS(=D`r%&K;W02^* z6GUc4Y-t6pk9thohc2pF&c;nMmI_uWooc6=Z62yW_G_3{Za5X zj;V|=)`9xNN;kwfLvywOxcRyV@8h7Q0}r1puIV@{;)kMx&c>>El=LrZ=7^IaK*Q2@pgHPwbC`#6@}ej^x#T&D|L+gV21N0 zxe?o9pSg=!l#bH=eCm7PaAY_-d~sZ{zqrfnPY22KI@9!B5u3iszB*9U@#nMYQJ{>Y z@=w{;yiO0_KOJ|kg3Z^Uy+AQ{#8mNki@Ikp{o$U|we=gw8uJb}DD$4SX{H}Kt-_wQ zWsgnCVRXx(rM4bud#ETZPRgAwdwKbJrYb&jv51~kU&)#w>-jDA9jaY-KmPgA1np~E zDbtCK`6dIQL-cHoFyqwH`LI^@QPv;*-Ix20l#JLXBh> z$HTblwp#l=R~|HJZPzC69Cn~Hrgcm@4aCw59OcWM94W%)|M$C$>Tt~cQyXanXZ6uj ztnW@&xps^;+n}e5^_SH-hzg;dY1bMf$8rK+2nwgDMX7dbKN1c1OyJYSe?HZ}cgU$H zo8la2(rK>RFyDLj?q;6=ZmQHFtuZ-ov)P`vW1gvl&JmGj#okk9p0NP~m||OFs#H9~ zI}Ko+u#gQ7IuhTq_-sNtXFi(96st8$*r8f_`aX|Nq?y>znc=jy0lTfL))dBA@(-*H zsn+Q;H_i=sKX{!^IGxbgYMM&E)$CT6<|$ooTAKa{=jWzSl;MMTTb|3Zy3y(yew1u1 z*BUv#;5mi<3h%IlMQPWO(ocRSd>KCfI%yaIsHz&AeY>!yAi^xS#VtztO$^cB3%)M7 zI^faQzaE|GK7!9%20uV;v7I-je#82fn#`$Z`Fm)WrNEbMilWE1d@Hji)l+&0zS|(x z>Qa^yaUOGv$og=wc2qy(Li^i9s#*!(>@D>S9bJ7wz@r+=C7Po zOdS#+&r zA(e63>3T)_`On{HzP(F}BVo8wWp>wJ$T)?!?Q-|%>Ew|-oq#a8ti~{zzvT_u^_JM|$~Yegsezy((9e<(tvpF))|!FJA1r8H)PhK8sTEA8v9Ue!Z%K z<&NrLjvZ4&EPrxKUMJ6!U(j@<3|@@&OxlfPlznToNIjJ%yjbgkxwlNw92sTB;C$OW zSLTGDvbciJSTwnkk1*KXH~LOSY=!Vp{t@N}3a?&~D_%S?J)`DA#&fN7C$kr(6<`!n z8sYQ^CC()xf(`Dg5koHgv%`xkxCCFdsKTC!fBc`V-T=~f zbiLy?4Qm18*OBvLQmF+?_?Lm1U*< zK9yH?S(Ikm)S#(18Z07_`>DM0bzbM`f{Um{G{GX#pUNv4tF#7Ju6$oBxu*>{Ws`k) zn{S1K{;bu+#%86&akbKK@3!1t%kx8d*k0=!d87ZvWo)<+mo83jO$nzW9#x9~o%Kl<|Uru&R70 zGo*vl>#m-cLzu-~60$J!mNZIYx)4eDO_OejFTXPb>R;SyixxPEoANp_Lj6NXfWW^x zH&8?uYeZR0QOKgyU*lIYY9-&m8paz7C68z#YpgD#AIoI+>^rlXpFG<)_wwzxq_ity zGJVg?y$%%S9$1`gJEQ04g55gs;64~{=1ftzlMGf~Yq($(eu#YITySh-TqH)UjfdHh zK%IX1-iv`{OgXt6#$~>ZZRzx_2%-DcJaHff6?+lwui!JAT?=oS#IWh;x`90TmBpnr zn|l{B;5GIVt$+vl*xEns1r-H$}qNTMXk!64uB`an@tzb77BsdI~zM%hENw<?j}B#@z&eLb;}F3 z7mf(%vbGG|cm?>A9HovxHVMI& zNOf$tA7B(%K}|bSYn?GYWgi@usV5ZebK36o Comma-separated: macos-arm64,macos-x86_64,linux-x86_64,linux-aarch64,windows-x86_64" + echo " --targets Comma-separated: cli,desktop,plugins" + echo " --all Build all platforms and targets" + echo " --yes Skip confirmation prompt" + echo "" + echo "Without options, runs interactively." + exit 0 + ;; + *) echo "Unknown option: $1"; exit 1 ;; + esac +done + +resolve_platform_alias() { + local alias="$1" + for i in "${!PLATFORM_ALIASES[@]}"; do + if [[ "${PLATFORM_ALIASES[$i]}" == "$alias" ]]; then + echo "$i" + return + fi + done + echo "Unknown platform: $alias" >&2 + exit 1 +} + +# --- Helpers --- + +prompt_platforms() { + echo "Select platform (0=all, comma-separated):" + echo " 0) All" + for i in "${!PLATFORMS[@]}"; do + echo " $((i+1))) ${PLATFORM_LABELS[$i]}" + done + read -rp "> " choice + + if [[ "$choice" == "0" || -z "$choice" ]]; then + selected_platforms=("${PLATFORMS[@]}") + selected_labels=("${PLATFORM_LABELS[@]}") + else + IFS=',' read -ra indices <<< "$choice" + selected_platforms=() + selected_labels=() + for idx in "${indices[@]}"; do + idx="${idx// /}" + idx=$((idx - 1)) + if (( idx < 0 || idx >= ${#PLATFORMS[@]} )); then + echo "Invalid platform index: $((idx+1))" + exit 1 + fi + selected_platforms+=("${PLATFORMS[$idx]}") + selected_labels+=("${PLATFORM_LABELS[$idx]}") + done + fi +} + +prompt_targets() { + echo "" + echo "Select targets (0=all, comma-separated):" + echo " 0) All" + echo " 1) cagire" + echo " 2) cagire-desktop" + echo " 3) cagire-plugins (CLAP/VST3)" + read -rp "> " choice + + build_cagire=false + build_desktop=false + build_plugins=false + + if [[ "$choice" == "0" || -z "$choice" ]]; then + build_cagire=true + build_desktop=true + build_plugins=true + else + IFS=',' read -ra targets <<< "$choice" + for t in "${targets[@]}"; do + t="${t// /}" + case "$t" in + 1) build_cagire=true ;; + 2) build_desktop=true ;; + 3) build_plugins=true ;; + *) echo "Invalid target: $t"; exit 1 ;; + esac + done + fi +} + +confirm_summary() { + echo "" + echo "=== Build Summary ===" + echo "" + echo "Platforms:" + for label in "${selected_labels[@]}"; do + echo " - $label" + done + echo "" + echo "Targets:" + $build_cagire && echo " - cagire" + $build_desktop && echo " - cagire-desktop" + $build_plugins && echo " - cagire-plugins (CLAP/VST3)" + echo "" + read -rp "Proceed? [Y/n] " yn + case "${yn,,}" in + n|no) echo "Aborted."; exit 0 ;; + esac +} + +platform_os() { + case "$1" in + *windows*) echo "windows" ;; + *linux*) echo "linux" ;; + *apple*) echo "macos" ;; + esac +} + +platform_arch() { + case "$1" in + aarch64*) echo "aarch64" ;; + x86_64*) echo "x86_64" ;; + esac +} + +platform_suffix() { + case "$1" in + *windows*) echo ".exe" ;; + *) echo "" ;; + esac +} + +is_cross_target() { + case "$1" in + *linux*|*windows*) return 0 ;; + *) return 1 ;; + esac +} + +native_target() { + [[ "$1" == "aarch64-apple-darwin" ]] +} + +release_dir() { + if native_target "$1"; then + echo "target/release" + else + echo "target/$1/release" + fi +} + +target_flag() { + if native_target "$1"; then + echo "" + else + echo "--target $1" + fi +} + +builder_for() { + if is_cross_target "$1"; then + echo "cross" + else + echo "cargo" + fi +} + +build_binary() { + local platform="$1" + shift + local builder + builder=$(builder_for "$platform") + local tf + tf=$(target_flag "$platform") + # shellcheck disable=SC2086 + $builder build --release $tf "$@" +} + +bundle_plugins_native() { + local platform="$1" + local tf + tf=$(target_flag "$platform") + # shellcheck disable=SC2086 + cargo xtask bundle "$PLUGIN_NAME" --release $tf +} + +bundle_plugins_cross() { + local platform="$1" + local rd + rd=$(release_dir "$platform") + local os + os=$(platform_os "$platform") + local arch + arch=$(platform_arch "$platform") + + # Build the cdylib with cross + # shellcheck disable=SC2046 + build_binary "$platform" -p "$PLUGIN_NAME" + + # Determine source library file + local src_lib + case "$os" in + linux) src_lib="$rd/lib${LIB_NAME}.so" ;; + windows) src_lib="$rd/${LIB_NAME}.dll" ;; + esac + + if [[ ! -f "$src_lib" ]]; then + echo " ERROR: Expected library not found: $src_lib" + return 1 + fi + + # Assemble CLAP bundle (flat file) + local clap_out="$OUT/${PLUGIN_NAME}-${os}-${arch}.clap" + cp "$src_lib" "$clap_out" + echo " CLAP -> $clap_out" + + # Assemble VST3 bundle (directory tree) + local vst3_dir="$OUT/${PLUGIN_NAME}-${os}-${arch}.vst3" + local vst3_contents + case "$os" in + linux) + vst3_contents="$vst3_dir/Contents/${arch}-linux" + mkdir -p "$vst3_contents" + cp "$src_lib" "$vst3_contents/${PLUGIN_NAME}.so" + ;; + windows) + vst3_contents="$vst3_dir/Contents/${arch}-win" + mkdir -p "$vst3_contents" + cp "$src_lib" "$vst3_contents/${PLUGIN_NAME}.vst3" + ;; + esac + echo " VST3 -> $vst3_dir/" +} + +copy_artifacts() { + local platform="$1" + local rd + rd=$(release_dir "$platform") + local os + os=$(platform_os "$platform") + local arch + arch=$(platform_arch "$platform") + local suffix + suffix=$(platform_suffix "$platform") + + if $build_cagire; then + local src="$rd/cagire${suffix}" + local dst="$OUT/cagire-${os}-${arch}${suffix}" + cp "$src" "$dst" + echo " cagire -> $dst" + fi + + if $build_desktop; then + local src="$rd/cagire-desktop${suffix}" + local dst="$OUT/cagire-desktop-${os}-${arch}${suffix}" + cp "$src" "$dst" + echo " cagire-desktop -> $dst" + fi + + # AppImage for Linux targets + if [[ "$os" == "linux" ]]; then + if $build_cagire; then + scripts/make-appimage.sh "$rd/cagire" "$arch" "$OUT" + fi + if $build_desktop; then + scripts/make-appimage.sh "$rd/cagire-desktop" "$arch" "$OUT" + fi + fi + + # Plugin artifacts for native targets (cross handled in bundle_plugins_cross) + if $build_plugins && ! is_cross_target "$platform"; then + local bundle_dir="$rd/bundle" + + # CLAP + local clap_src="$bundle_dir/${PLUGIN_NAME}.clap" + if [[ -e "$clap_src" ]]; then + local clap_dst="$OUT/${PLUGIN_NAME}-${os}-${arch}.clap" + cp -r "$clap_src" "$clap_dst" + echo " CLAP -> $clap_dst" + fi + + # VST3 + local vst3_src="$bundle_dir/${PLUGIN_NAME}.vst3" + if [[ -d "$vst3_src" ]]; then + local vst3_dst="$OUT/${PLUGIN_NAME}-${os}-${arch}.vst3" + rm -rf "$vst3_dst" + cp -r "$vst3_src" "$vst3_dst" + echo " VST3 -> $vst3_dst/" + fi + fi +} + +# --- Main --- + +if $cli_all; then + selected_platforms=("${PLATFORMS[@]}") + selected_labels=("${PLATFORM_LABELS[@]}") + build_cagire=true + build_desktop=true + build_plugins=true +elif [[ -n "$cli_platforms" || -n "$cli_targets" ]]; then + # Resolve platforms from CLI + if [[ -n "$cli_platforms" ]]; then + selected_platforms=() + selected_labels=() + IFS=',' read -ra aliases <<< "$cli_platforms" + for alias in "${aliases[@]}"; do + alias="${alias// /}" + idx=$(resolve_platform_alias "$alias") + selected_platforms+=("${PLATFORMS[$idx]}") + selected_labels+=("${PLATFORM_LABELS[$idx]}") + done + else + selected_platforms=("${PLATFORMS[@]}") + selected_labels=("${PLATFORM_LABELS[@]}") + fi + + # Resolve targets from CLI + build_cagire=false + build_desktop=false + build_plugins=false + if [[ -n "$cli_targets" ]]; then + IFS=',' read -ra tgts <<< "$cli_targets" + for t in "${tgts[@]}"; do + t="${t// /}" + case "$t" in + cli) build_cagire=true ;; + desktop) build_desktop=true ;; + plugins) build_plugins=true ;; + *) echo "Unknown target: $t (expected: cli, desktop, plugins)"; exit 1 ;; + esac + done + else + build_cagire=true + build_desktop=true + build_plugins=true + fi +else + prompt_platforms + prompt_targets +fi + +if ! $cli_yes && [[ -z "$cli_platforms" ]] && ! $cli_all; then + confirm_summary +fi + +mkdir -p "$OUT" + +step=0 +total=${#selected_platforms[@]} + +for platform in "${selected_platforms[@]}"; do + step=$((step + 1)) + echo "" + echo "=== [$step/$total] $platform ===" + + if $build_cagire; then + echo " -> cagire" + build_binary "$platform" + fi + + if $build_desktop; then + echo " -> cagire-desktop" + build_binary "$platform" --features desktop --bin cagire-desktop + fi + + if $build_plugins; then + echo " -> cagire-plugins" + if is_cross_target "$platform"; then + bundle_plugins_cross "$platform" + else + bundle_plugins_native "$platform" + fi + fi + + echo " Copying artifacts..." + copy_artifacts "$platform" +done + +echo "" +echo "=== Done ===" +echo "" +ls -lhR "$OUT/" diff --git a/scripts/make-appimage.sh b/scripts/make-appimage.sh new file mode 100755 index 0000000..e496e0b --- /dev/null +++ b/scripts/make-appimage.sh @@ -0,0 +1,136 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Usage: scripts/make-appimage.sh +# Produces an AppImage from a Linux binary using linuxdeploy. + +if [[ $# -ne 3 ]]; then + echo "Usage: $0 " + exit 1 +fi + +BINARY="$1" +ARCH="$2" +OUTDIR="$3" + +REPO_ROOT="$(git rev-parse --show-toplevel)" +CACHE_DIR="$REPO_ROOT/.cache" +APP_NAME="$(basename "$BINARY")" +APPDIR="$(mktemp -d)/AppDir" + +LINUXDEPLOY_URL="https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-${ARCH}.AppImage" +LINUXDEPLOY="$CACHE_DIR/linuxdeploy-${ARCH}.AppImage" +RUNTIME_URL="https://github.com/AppImage/type2-runtime/releases/download/continuous/runtime-${ARCH}" +RUNTIME="$CACHE_DIR/runtime-${ARCH}" + +# Map arch to linuxdeploy's expected values +case "$ARCH" in + x86_64) export LDAI_ARCH="x86_64" ;; + aarch64) export LDAI_ARCH="aarch64" ;; + *) echo "Unsupported arch: $ARCH"; exit 1 ;; +esac + +download_tools() { + mkdir -p "$CACHE_DIR" + if [[ ! -f "$LINUXDEPLOY" ]]; then + echo " Downloading linuxdeploy for $ARCH..." + curl -fSL "$LINUXDEPLOY_URL" -o "$LINUXDEPLOY" + chmod +x "$LINUXDEPLOY" + fi + if [[ ! -f "$RUNTIME" ]]; then + echo " Downloading AppImage runtime for $ARCH..." + curl -fSL "$RUNTIME_URL" -o "$RUNTIME" + fi +} + +build_appdir() { + mkdir -p "$APPDIR/usr/bin" + cp "$BINARY" "$APPDIR/usr/bin/cagire" + chmod +x "$APPDIR/usr/bin/cagire" + + mkdir -p "$APPDIR/usr/share/icons/hicolor/512x512/apps" + cp "$REPO_ROOT/assets/Cagire.png" "$APPDIR/usr/share/icons/hicolor/512x512/apps/cagire.png" + + cp "$REPO_ROOT/assets/cagire.desktop" "$APPDIR/cagire.desktop" +} + +run_linuxdeploy_native() { + export ARCH="$LDAI_ARCH" + export LDAI_RUNTIME_FILE="$RUNTIME" + "$LINUXDEPLOY" \ + --appimage-extract-and-run \ + --appdir "$APPDIR" \ + --desktop-file "$APPDIR/cagire.desktop" \ + --icon-file "$APPDIR/usr/share/icons/hicolor/512x512/apps/cagire.png" \ + --output appimage +} + +run_linuxdeploy_docker() { + local platform + case "$ARCH" in + x86_64) platform="linux/amd64" ;; + aarch64) platform="linux/arm64" ;; + esac + + local image_tag="cagire-appimage-${ARCH}" + + echo " Building Docker image $image_tag ($platform)..." + docker build --platform "$platform" -q -t "$image_tag" - <<'DOCKERFILE' +FROM ubuntu:22.04 +RUN apt-get update && apt-get install -y --no-install-recommends \ + file \ + libasound2 \ + libjack0 \ + libxcb-render0 \ + libxcb-shape0 \ + libxcb-xfixes0 \ + libxkbcommon0 \ + libgl1 \ + && rm -rf /var/lib/apt/lists/* +DOCKERFILE + + echo " Running linuxdeploy inside Docker ($image_tag)..." + docker run --rm --platform "$platform" \ + -v "$REPO_ROOT:/project" \ + -v "$APPDIR:/appdir" \ + -v "$CACHE_DIR:/cache" \ + -e ARCH="$LDAI_ARCH" \ + -e LDAI_RUNTIME_FILE="/cache/runtime-${ARCH}" \ + -w /project \ + "$image_tag" \ + bash -c " + chmod +x /cache/linuxdeploy-${ARCH}.AppImage && \ + /cache/linuxdeploy-${ARCH}.AppImage \ + --appimage-extract-and-run \ + --appdir /appdir \ + --desktop-file /appdir/cagire.desktop \ + --icon-file /appdir/usr/share/icons/hicolor/512x512/apps/cagire.png \ + --output appimage + " +} + +HOST_ARCH="$(uname -m)" + +download_tools +build_appdir + +echo " Building AppImage for cagire ($ARCH)..." + +if [[ "$HOST_ARCH" == "$ARCH" ]] && [[ "$(uname -s)" == "Linux" ]]; then + run_linuxdeploy_native +else + run_linuxdeploy_docker +fi + +mkdir -p "$OUTDIR" + +# linuxdeploy outputs to cwd; find and move the AppImage +APPIMAGE=$(ls -1t ./*.AppImage 2>/dev/null | head -1 || true) +if [[ -z "$APPIMAGE" ]]; then + echo " ERROR: No AppImage produced" + exit 1 +fi + +FINAL_NAME="${APP_NAME}-linux-${ARCH}.AppImage" +mv "$APPIMAGE" "$OUTDIR/$FINAL_NAME" +echo " AppImage -> $OUTDIR/$FINAL_NAME"