Repository: jgraph/drawio-desktop Branch: dev Commit: f1bcba4ef7f7 Files: 41 Total size: 277.4 KB Directory structure: gitextract_5n8je2q1/ ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ ├── bug_report.md │ ├── feature_request.md │ └── workflows/ │ ├── electron-builder-win.yml │ ├── electron-builder.yml │ ├── hash-gen.yml │ ├── prepare-release.yml │ └── stale.yml ├── .gitignore ├── .gitmodules ├── .nvmrc ├── CLAUDE.md ├── CODE_OF_CONDUCT.md ├── DEVELOPMENT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── build/ │ ├── create_macos_icon.sh │ ├── entitlements.mac.plist │ ├── fuses.cjs │ ├── icon.hqx │ ├── icon.icns │ ├── notarize.mjs │ ├── quicklook-entitlements.plist │ └── quicklook-preview.html ├── doc/ │ ├── .gitignore │ └── RELEASE_PROCESS.md ├── electron-builder-appx.json ├── electron-builder-linux-mac.json ├── electron-builder-snap.json ├── electron-builder-win-arm64.json ├── electron-builder-win.json ├── electron-builder-win32.json ├── package.json ├── preload.js ├── src/ │ └── main/ │ ├── disableUpdate.js │ ├── electron-preload.js │ └── electron.js └── sync.cjs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: jgraph ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve --- ### Preflight Checklist * [ ] I agree to follow the [Code of Conduct](https://github.com/jgraph/drawio-desktop/blob/master/CODE_OF_CONDUCT.md) that this project adheres to. * [ ] I have searched the issue tracker for a feature request that matches the one I want to file, without success. You must agree to search and the code of conduct. You must fill in this entire template. If you delete part/all or miss parts out your issue will be closed. **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **draw.io version (In the Help->About menu of the draw.io editor):** - draw.io version x.y.z **Desktop (please complete the following information):** - OS: Windows, MacOS, Linux... **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project --- * [ ] I agree to follow the [Code of Conduct](https://github.com/jgraph/drawio-desktop/blob/master/CODE_OF_CONDUCT.md) that this project adheres to. * [ ] I have searched the issue tracker for a feature request that matches the one I want to file, without success. **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve --- ### Preflight Checklist * [ ] I agree to follow the [Code of Conduct](https://github.com/jgraph/drawio/blob/master/CODE_OF_CONDUCT.md) that this project adheres to. * [ ] I have searched the issue tracker for a feature request that matches the one I want to file, without success. **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **draw.io version (In the Help->About menu of the draw.io editor):** - draw.io version [e.g. 12.6.7] **Desktop (please complete the following information):** - OS: [e.g. iOS] - Browser [e.g. chrome, safari] - Version [e.g. 22] **Smartphone (please complete the following information):** - Device: [e.g. iPhone6] - OS: [e.g. iOS8.1] - Browser [e.g. stock browser, safari] - Version [e.g. 22] **Additional context** Add any other context about the problem here. ================================================ FILE: .github/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project --- * [ ] I agree to follow the [Code of Conduct](https://github.com/jgraph/drawio/blob/master/CODE_OF_CONDUCT.md) that this project adheres to. * [ ] I have searched the issue tracker for a feature request that matches the one I want to file, without success. **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/workflows/electron-builder-win.yml ================================================ name: Electron Builder CI (WIN) on: push: tags: - 'v*' jobs: build: runs-on: windows-latest env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REF: ${{ github.ref }} steps: - name: Checkout reposistory uses: actions/checkout@v4 with: submodules: true - name: Checkout drawio-dev uses: actions/checkout@v4 with: repository: jgraph/drawio-dev token: ${{ secrets.GH_TOKEN }} ref: release path: drawio-dev submodules: false - name: Get drawio Tag & Submodules run: | cd drawio-dev # Get the current build tag from draw.io $tmp=$Env:GH_REF -replace '/v','/diagramly-' -replace '[.]','_' $ref=$tmp+':'+$tmp git fetch origin $ref --no-tags $tmp=$tmp -replace 'refs/','' git checkout $tmp -b tmp-deploy Copy-Item -Path "src\main\webapp\js\*.min.js" -Destination "..\drawio\src\main\webapp\js\" cd .. Remove-Item 'drawio-dev' -Recurse -Force cd drawio Remove-Item 'docs','etc','src\main\java','src\main\webapp\connect','src\main\webapp\service-worker*','src\main\webapp\workbox-*' -Recurse -Force cd src\main\webapp\js Remove-Item 'atlas-viewer.min.js','atlas.min.js','cryptojs','deflate','dropbox','embed*','freehand','integrate.min.js','jquery','jszip','mermaid','onedrive','orgchart','reader.min.js','rough','sanitizer','simplepeer','spin','viewer-static.min.js','viewer.min.js' -Recurse -Force - name: Installing Node uses: actions/setup-node@v4 with: node-version: 24 - name: Prepare for Windows Build shell: powershell run: | git config --global url."https://github.com/".insteadOf "git@github.com:" npm ci - name: Build for Windows (x32 & arm64) env: CSC_LINK: ${{ secrets.WIN_CSC_LINK }} CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }} shell: powershell run: | #Disable auto-update and build 32bit/arm64 first such that latest.yml is for 64bit only (64bit will overwrite 32bit one) npm run sync -- disableUpdate npm run release-win32 npm run release-win-arm64 - name: Build for Windows (x64) env: CSC_LINK: ${{ secrets.WIN_CSC_LINK }} CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }} shell: powershell run: | #Enable auto-update again npm run sync npm run release-win - name: Build unpacked Windows x64 (for zip portable) shell: powershell run: | npm run sync -- disableUpdate npx electron-builder --win --x64 --dir - name: Zip unpacked x64 build shell: powershell run: | $version = "${{ github.ref }}" -replace 'refs/tags/v', '' cd dist 7z a "draw.io-$version-windows.zip" ".\win-unpacked\*" - name: Build for Windows (APPX) shell: powershell run: | #Disable auto-update for appx also npm run sync -- disableUpdate npm run release-appx - name: Install GitHub CLI shell: powershell run: | Invoke-WebRequest -Uri https://github.com/cli/cli/releases/download/v2.73.0/gh_2.73.0_windows_amd64.msi -OutFile ghcli.msi Start-Process msiexec.exe -ArgumentList '/i', 'ghcli.msi', '/quiet', '/norestart' -Wait - name: Upload portable zip to GitHub Release shell: powershell env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | $version = "${{ github.ref }}" -replace 'refs/tags/v', '' gh release upload "v$version" "dist/draw.io-$version-windows.zip" --clobber ================================================ FILE: .github/workflows/electron-builder.yml ================================================ name: Electron Builder CI on: push: tags: - 'v*' jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest] env: CC: clang CXX: clang++ npm_config_clang: 1 APPLEID: ${{ secrets.APPLEID }} APPLEIDPASS: ${{ secrets.APPLEIDPASS }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} CSC_LINK: ${{ secrets.CSC_LINK }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_TOKEN }} OS_NAME: ${{ matrix.os }} GH_REF: ${{ github.ref }} steps: - name: Checkout reposistory uses: actions/checkout@v4 with: submodules: true - name: Checkout drawio-dev uses: actions/checkout@v4 with: repository: jgraph/drawio-dev token: ${{ secrets.GH_TOKEN }} ref: release path: drawio-dev submodules: false - name: Get drawio Tag & Submodules run: | cd drawio-dev # Get the current build tag from draw.io export tmp1=${GH_REF/refs\//} export tmp2=${tmp1/\/v/\/diagramly-} export tmp3=${tmp2//\./_} git fetch origin refs/$tmp3:refs/$tmp3 --no-tags git checkout $tmp3 -b tmp-deploy cp src/main/webapp/js/*.min.js ../drawio/src/main/webapp/js/ cd .. rm -rf drawio-dev cd drawio rm -rf docs etc src/main/java src/main/webapp/connect src/main/webapp/service-worker* src/main/webapp/workbox-* cd src/main/webapp/js # Save viewer-static.min.js for macOS Quick Look extension before cleanup if [ "$OS_NAME" = "macos-latest" ]; then cp viewer-static.min.js ../../../../../build/viewer-static.min.js; fi rm -rf atlas-viewer.min.js atlas.min.js cryptojs deflate dropbox embed* freehand integrate.min.js jquery jszip mermaid onedrive orgchart reader.min.js rough sanitizer simplepeer spin viewer-static.min.js viewer.min.js - name: Installing Node uses: actions/setup-node@v4 with: node-version: 24 - name: Build for ${{ matrix.os}} run: | if [ "$OS_NAME" = "ubuntu-latest" ]; then sudo apt-get update && sudo apt-get install -y icnsutils graphicsmagick xz-utils rpm; fi git config --global url."https://github.com/".insteadOf "git@github.com:" npm ci if [ "$OS_NAME" = "ubuntu-latest" ]; then sed -ie 's/"asar": true,/"asar": true,\n"productName": "drawio",/' electron-builder-linux-mac.json; fi npm run sync npm run release-linux - name: Build for Snap if: ${{ matrix.os == 'ubuntu-latest' }} run: | #To generate SNAP_TOKEN run `snapcraft export-login [FILE]` and login with your snapcraft credentials. It is used now without login sudo snap install snapcraft --classic npm run release-snap # Cannot configure electron-builder to publish to stable channel, so do it explicitly snapcraft push --release edge dist/draw.io-amd64-*.snap ================================================ FILE: .github/workflows/hash-gen.yml ================================================ name: Generate sha256 hashes for release files on: release: types: [published] jobs: build: runs-on: ubuntu-latest steps: - name: Generate Hashes uses: MCJack123/ghaction-generate-release-hashes@v1 with: hash-type: sha256 file-name: hashes.txt - name: Upload Hashes to release uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: hashes.txt overwrite: true asset_name: Files-SHA256-Hashes.txt tag: ${{ github.ref }} ================================================ FILE: .github/workflows/prepare-release.yml ================================================ name: Prepare Release on: workflow_dispatch: inputs: version: description: 'Release version (e.g., 29.0.4)' required: true type: string previous_version: description: 'Previous version for changelog (e.g., 29.0.3). Leave empty to auto-detect.' required: false type: string drawio_ref: description: 'draw.io ref to use (tag, branch, or commit). Leave empty to use v{version}' required: false type: string dry_run: description: 'Dry run - validate only, do not commit' required: false type: boolean default: false env: NODE_VERSION: '24' jobs: prepare-release: runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - name: Validate version format run: | if ! [[ "${{ inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "::error::Version must be in format X.Y.Z (e.g., 29.0.4)" exit 1 fi echo "VERSION=${{ inputs.version }}" >> $GITHUB_ENV - name: Checkout repository uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} check-latest: true - name: Log versions run: | echo "Node version: $(node --version)" echo "npm version: $(npm --version)" - name: Determine drawio ref run: | if [ -n "${{ inputs.drawio_ref }}" ]; then echo "DRAWIO_REF=${{ inputs.drawio_ref }}" >> $GITHUB_ENV else echo "DRAWIO_REF=v${{ inputs.version }}" >> $GITHUB_ENV fi - name: Update drawio submodule run: | cd drawio git fetch origin --tags # Check if ref exists if ! git rev-parse --verify "${{ env.DRAWIO_REF }}" >/dev/null 2>&1; then echo "::error::Ref '${{ env.DRAWIO_REF }}' not found in drawio repository" exit 1 fi git checkout "${{ env.DRAWIO_REF }}" # Update any nested submodules in drawio git submodule update --init --recursive echo "DRAWIO_COMMIT=$(git rev-parse HEAD)" >> $GITHUB_ENV echo "Updated drawio to: $(git describe --tags --always)" cd .. - name: Update package.json version run: | # Update version in package.json jq '.version = "${{ env.VERSION }}"' package.json > package.json.tmp mv package.json.tmp package.json echo "Updated package.json to version ${{ env.VERSION }}" grep '"version"' package.json - name: Install dependencies run: | # Clean install from scratch to ensure package-lock.json has all resolved URLs and integrity hashes. # Without this, entries carried over from a previous node_modules lack these fields, # which breaks offline/sandboxed builds like Flatpak (see #2301). rm -rf node_modules package-lock.json npm install - name: Generate release notes run: | VERSION="${{ env.VERSION }}" PREV_VERSION="${{ inputs.previous_version }}" # Auto-detect previous version if not provided if [ -z "$PREV_VERSION" ]; then PREV_VERSION=$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || echo "") fi # Get electron version from package-lock.json (actual installed version) ELECTRON_VERSION=$(jq -r '.packages["node_modules/electron"].version' package-lock.json) echo "ELECTRON_VERSION=$ELECTRON_VERSION" >> $GITHUB_ENV # Generate release notes cat > release-notes.md << 'RELEASE_EOF' ## Release Notes for VERSION_PLACEHOLDER [Windows Installer](https://github.com/jgraph/drawio-desktop/releases/download/vVERSION_PLACEHOLDER/draw.io-VERSION_PLACEHOLDER-windows-installer.exe) [Windows No Installer (zip)](https://github.com/jgraph/drawio-desktop/releases/download/vVERSION_PLACEHOLDER/draw.io-VERSION_PLACEHOLDER-windows.zip) [macOS - Universal](https://github.com/jgraph/drawio-desktop/releases/download/vVERSION_PLACEHOLDER/draw.io-universal-VERSION_PLACEHOLDER.dmg) Linux - [deb](https://github.com/jgraph/drawio-desktop/releases/download/vVERSION_PLACEHOLDER/drawio-amd64-VERSION_PLACEHOLDER.deb), [AppImage](https://github.com/jgraph/drawio-desktop/releases/download/vVERSION_PLACEHOLDER/drawio-x86_64-VERSION_PLACEHOLDER.AppImage) or [rpm](https://github.com/jgraph/drawio-desktop/releases/download/vVERSION_PLACEHOLDER/drawio-x86_64-VERSION_PLACEHOLDER.rpm) Windows intel x32 releases are marked -ia32- **ChangeLog:** - Uses electron ELECTRON_PLACEHOLDER. - Updates to [draw.io core VERSION_PLACEHOLDER](https://github.com/jgraph/drawio/blob/vVERSION_PLACEHOLDER/ChangeLog).PREV_PLACEHOLDER RELEASE_EOF # Replace placeholders sed -i "s/VERSION_PLACEHOLDER/${VERSION}/g" release-notes.md sed -i "s/ELECTRON_PLACEHOLDER/${ELECTRON_VERSION}/g" release-notes.md if [ -n "$PREV_VERSION" ]; then sed -i "s/PREV_PLACEHOLDER/ All changes from ${PREV_VERSION} to ${VERSION} are added in this build./g" release-notes.md else sed -i "s/PREV_PLACEHOLDER//g" release-notes.md fi echo "## Generated Release Notes" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY cat release-notes.md >> $GITHUB_STEP_SUMMARY echo "Release notes generated with Electron version: $ELECTRON_VERSION" - name: Security audit id: audit continue-on-error: true run: | echo "## npm audit results" >> $GITHUB_STEP_SUMMARY # Run audit and capture output npm audit --json > audit-results.json 2>&1 || true # Parse results CRITICAL=$(jq '.metadata.vulnerabilities.critical // 0' audit-results.json) HIGH=$(jq '.metadata.vulnerabilities.high // 0' audit-results.json) MODERATE=$(jq '.metadata.vulnerabilities.moderate // 0' audit-results.json) LOW=$(jq '.metadata.vulnerabilities.low // 0' audit-results.json) echo "| Severity | Count |" >> $GITHUB_STEP_SUMMARY echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY echo "| Critical | $CRITICAL |" >> $GITHUB_STEP_SUMMARY echo "| High | $HIGH |" >> $GITHUB_STEP_SUMMARY echo "| Moderate | $MODERATE |" >> $GITHUB_STEP_SUMMARY echo "| Low | $LOW |" >> $GITHUB_STEP_SUMMARY # Save for artifact npm audit > audit-report.txt 2>&1 || true # Fail if critical or high vulnerabilities if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then echo "::error::Security vulnerabilities found: $CRITICAL critical, $HIGH high" echo "AUDIT_FAILED=true" >> $GITHUB_ENV else echo "AUDIT_FAILED=false" >> $GITHUB_ENV fi - name: Check outdated dependencies run: | echo "## Outdated dependencies" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY npm outdated >> $GITHUB_STEP_SUMMARY 2>&1 || true echo '```' >> $GITHUB_STEP_SUMMARY npm outdated > outdated-report.txt 2>&1 || true - name: Upload audit artifacts uses: actions/upload-artifact@v4 with: name: release-evidence-v${{ env.VERSION }} path: | audit-results.json audit-report.txt outdated-report.txt release-notes.md retention-days: 365 - name: Fail if audit has issues if: env.AUDIT_FAILED == 'true' run: | echo "::error::Cannot proceed with release due to security vulnerabilities" echo "Review audit-report.txt and fix vulnerabilities before releasing" exit 1 - name: Generate release summary run: | echo "## Release Preparation Summary" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Item | Value |" >> $GITHUB_STEP_SUMMARY echo "|------|-------|" >> $GITHUB_STEP_SUMMARY echo "| Version | ${{ env.VERSION }} |" >> $GITHUB_STEP_SUMMARY echo "| Electron | ${{ env.ELECTRON_VERSION }} |" >> $GITHUB_STEP_SUMMARY echo "| drawio ref | ${{ env.DRAWIO_REF }} |" >> $GITHUB_STEP_SUMMARY echo "| drawio commit | ${{ env.DRAWIO_COMMIT }} |" >> $GITHUB_STEP_SUMMARY echo "| Node.js | $(node --version) |" >> $GITHUB_STEP_SUMMARY echo "| npm | $(npm --version) |" >> $GITHUB_STEP_SUMMARY echo "| Dry run | ${{ inputs.dry_run }} |" >> $GITHUB_STEP_SUMMARY - name: Commit changes if: inputs.dry_run == false run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" # Save release notes content before cleanup cp release-notes.md /tmp/release-notes.md # Create release branch git checkout -b "releases/v${{ env.VERSION }}" # Remove generated files that shouldn't be committed # (package-lock.json IS committed to lock electron version) rm -f audit-results.json audit-report.txt outdated-report.txt release-notes.md git add -A git commit -m "Prepare release v${{ env.VERSION }} - Updated drawio submodule to ${{ env.DRAWIO_REF }} (${{ env.DRAWIO_COMMIT }}) - Updated package.json version to ${{ env.VERSION }} - Updated package-lock.json - Electron version: ${{ env.ELECTRON_VERSION }} Automated by prepare-release workflow" git push origin "releases/v${{ env.VERSION }}" # Restore release notes for PR creation cp /tmp/release-notes.md release-notes.md - name: Create Pull Request if: inputs.dry_run == false env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # Get the release notes content RELEASE_NOTES=$(cat release-notes.md) # Create PR PR_URL=$(gh pr create \ --base dev \ --head "releases/v${{ env.VERSION }}" \ --title "Release v${{ env.VERSION }}" \ --body "## Release Preparation This PR prepares release v${{ env.VERSION }}. ### Changes - Updated drawio submodule to ${{ env.DRAWIO_REF }} - Updated package.json version to ${{ env.VERSION }} - Electron version: ${{ env.ELECTRON_VERSION }} ### Audit Results - npm audit: ✅ No critical/high vulnerabilities ### After Merging Create and push the tag to trigger builds: \`\`\`bash git checkout dev git pull git tag -a v${{ env.VERSION }} -m \"Release v${{ env.VERSION }}\" git push origin v${{ env.VERSION }} \`\`\` --- ${RELEASE_NOTES} ") echo "## Pull Request Created" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "PR: ${PR_URL}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Next Steps" >> $GITHUB_STEP_SUMMARY echo "1. Review and merge the PR" >> $GITHUB_STEP_SUMMARY echo "2. Create the tag: \`git tag -a v${{ env.VERSION }} -m \"Release v${{ env.VERSION }}\"\`" >> $GITHUB_STEP_SUMMARY echo "3. Push the tag: \`git push origin v${{ env.VERSION }}\`" >> $GITHUB_STEP_SUMMARY - name: Summary run: | if [ "${{ inputs.dry_run }}" = "true" ]; then echo "::notice::Dry run complete. No changes committed." else echo "::notice::Release PR created for v${{ env.VERSION }}. Review, merge, then create tag to trigger builds." fi ================================================ FILE: .github/workflows/stale.yml ================================================ # This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time. # # You can adjust the behavior by modifying this file. # For more information, see: # https://github.com/actions/stale name: Mark stale issues and pull requests on: schedule: - cron: '42 3 * * *' jobs: stale: runs-on: ubuntu-latest permissions: issues: write pull-requests: write steps: - uses: actions/stale@v5 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. See [the FAQ](https://github.com/jgraph/drawio/wiki/Stale-bot-FAQ) for more information.' stale-pr-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. See [the FAQ](https://github.com/jgraph/drawio/wiki/Stale-bot-FAQ) for more information.' stale-issue-label: 'wontfix' stale-pr-label: 'wontfix' close-issue-label: 'declined' days-before-stale: 250 days-before-close: 14 exempt-issue-labels: notstale exempt-pr-labels: notstale ================================================ FILE: .gitignore ================================================ .idea node_modules .project /dist/ /.classpath /.settings .DS_Store .claude/settings.local.json ================================================ FILE: .gitmodules ================================================ [submodule "drawio"] path = drawio url = https://github.com/jgraph/drawio.git branch = dev ================================================ FILE: .nvmrc ================================================ 20 ================================================ FILE: CLAUDE.md ================================================ # CLAUDE.md - AI Assistant Guide for draw.io Desktop ## Project Overview Draw.io Desktop is an Electron-based desktop application that wraps the core draw.io diagramming editor (included as a git submodule). It enables creating flowcharts, UML diagrams, and more, with a security-first design that isolates diagram data from the internet. **Repository:** https://github.com/jgraph/drawio-desktop **License:** Apache 2.0 **Current Version:** 29.6.1 ## Quick Reference ```bash # Clone (MUST be recursive for submodule) git clone --recursive https://github.com/jgraph/drawio-desktop.git # Install dependencies npm install # Run application npm start # Run with DevTools enabled DRAWIO_ENV=dev npm start # Sync version before building (required) npm run sync # Build for specific platforms npm run release-win # Windows x64 npm run release-linux # Linux (AppImage, deb, rpm) npm run release-appx # Windows Store ``` ## Project Structure ``` drawio-desktop/ ├── src/main/ │ ├── electron.js # Main Electron process (2,700+ lines) │ ├── electron-preload.js # IPC bridge with contextBridge │ └── disableUpdate.js # Generated by sync script ├── drawio/ # Git submodule - core draw.io editor │ └── src/main/webapp/ # Web application loaded in Electron ├── build/ # Build resources │ ├── notarize.mjs # macOS Quick Look setup, signing + notarization │ ├── fuses.cjs # Electron security fuses │ ├── quicklook-preview.html # Quick Look preview page (viewer-static.min.js) │ ├── quicklook-entitlements.plist # Sandbox entitlements for .appex │ └── entitlements.mac.plist ├── doc/ │ └── RELEASE_PROCESS.md # Release workflow documentation ├── electron-builder-*.json # Platform-specific build configs ├── sync.cjs # Version sync script └── package.json ``` ## Tech Stack - **Runtime:** Node.js 20+ - **Framework:** Electron 39.x - **Language:** JavaScript (ES6 modules) - **Build Tool:** electron-builder - **Package Manager:** npm ## Key Files | File | Purpose | |------|---------| | `src/main/electron.js` | Main process: window management, IPC handlers, menus, auto-update | | `src/main/electron-preload.js` | Secure IPC bridge between renderer and main process | | `sync.cjs` | Pre-build script that syncs version from `drawio/VERSION` | | `electron-builder-*.json` | Platform-specific build configurations | ## Code Style - **ES6 modules** with `import`/`export` - **Tab indentation** - **Allman brace style** (opening brace on new line) - **camelCase** for variables, **PascalCase** for classes - No ESLint/Prettier - manual style consistency - Sparse comments; code clarity preferred ## Git Conventions ### Branches - `dev` - Main development branch (PR target) - `release` - Production releases - `releases/v*.*.*` - Version-specific release branches ### Commit Messages - Lowercase sentence style without period - Issue references: `[jgraph/drawio-desktop#XXXX]` - Examples: - `Fixes paste error` - `Adds buffer as dependency [jgraph/drawio-desktop#2301]` - `Prepare release v29.3.0` ### Version Tags Format: `v{MAJOR}.{MINOR}.{PATCH}` (e.g., `v29.3.0`) Tags trigger CI/CD build workflows. ## Build Process 1. **Sync version:** `npm run sync` reads `drawio/VERSION` and updates `package.json` 2. **Install:** `npm ci` for clean install 3. **Build:** `electron-builder` with platform-specific config 4. **Post-build:** Security fuses applied, Quick Look extension assembled (macOS), notarization (macOS) ### Platform Build Commands | Command | Target | |---------|--------| | `npm run release-win` | Windows x64 (NSIS + MSI) | | `npm run release-win32` | Windows 32-bit | | `npm run release-win-arm64` | Windows ARM64 | | `npm run release-linux` | Linux (AppImage, deb, rpm) | | `npm run release-appx` | Windows Store | | `npm run release-snap` | Snap package | ## Architecture Notes ### Security Model - **Content Security Policy** prevents remote script execution - **contextBridge** exposes only specific APIs to renderer - **validateSender()** ensures IPC calls originate from local draw.io - No external transmission of diagram data ### IPC Pattern The preload script uses a request/response pattern with unique IDs: ```javascript // Renderer sends request electron.request({action: 'save', data: ...}, callbackId); // Main process handles and responds via IPC ipcMain.on('request', (e, data) => { ... }); ``` ### macOS Quick Look Preview - Pressing Space in Finder shows a rendered preview of `.drawio` files - Uses `quicklookjs` to embed a Quick Look App Extension (`.appex`) in the app bundle - The `.appex` loads `viewer-static.min.js` (with embedded shapes) in a WKWebView - **Build flow:** `afterPack` (fuses.cjs) applies security fuses, then `afterSign` (notarize.mjs) assembles the `.appex`, signs it with sandbox entitlements, re-signs the outer `.app`, and notarizes - The `.appex` is inserted in `afterSign` (not `afterPack`) so it is never present unsigned during electron-builder's signing verification - Quick Look extensions require `app-sandbox`, but Electron helpers must not be sandboxed — so the `.appex` gets different entitlements than `entitlementsInherit` - The UTI `com.jgraph.drawio` is declared via `extendInfo` in `electron-builder-linux-mac.json` - `viewer-static.min.js` is saved to `build/` during CI before the cleanup step removes it from the drawio submodule; for local dev, it's read from the submodule directly ### Auto-Update - Checks GitHub releases on startup - Disable via `DRAWIO_DISABLE_UPDATE=true` or `--disable-update` flag - Flatpak detection disables updates automatically ### Data Storage - **macOS:** `~/Library/Application Support/draw.io` - **Windows:** `%APPDATA%\draw.io\` - Uses `electron-store` for persistent settings ## Testing No automated tests. Manual testing documented in `doc/RELEASE_PROCESS.md`: - Launch, create diagram, add shapes, save, open - Export (PNG, PDF, SVG) - Undo/redo functionality - About dialog verification ## CI/CD Workflows | Workflow | Trigger | Purpose | |----------|---------|---------| | `electron-builder.yml` | Version tag | macOS/Linux builds | | `electron-builder-win.yml` | Version tag | Windows builds | | `prepare-release.yml` | Manual | Automated release prep | | `hash-gen.yml` | Manual | Generate checksums | ## Important Constraints 1. **Recursive clone required** - drawio submodule must be initialized 2. **Run `npm run sync` before building** - Updates version from submodule 3. **Version source of truth** - `drawio/VERSION`, not package.json 4. **Closed to contributions** - PRs not accepted; maintained by JGraph 5. **Node 20+ required** - ES6 modules without transpilation ## Development Tips - Set `DRAWIO_ENV=dev` to auto-open DevTools - Use `npm start --enable-logging` for verbose output - If using symlink instead of submodule, also symlink `node_modules` - Main process logs to console; check terminal for errors ## Key Dependencies | Package | Purpose | |---------|---------| | `electron` | Desktop app framework | | `electron-builder` | Build/package tool | | `electron-updater` | Auto-update mechanism | | `electron-store` | Persistent storage | | `@cantoo/pdf-lib` | PDF export | | `commander` | CLI argument parsing | | `quicklookjs` | macOS Quick Look preview extension (dev) | ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct: ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers aim to making participation in our project and our community a harassment-free experience for everyone. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment, including focusing on individual developers when a topic should be broadly addressed. * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting * Not respecting other people's time * Being impatient or rude * Pressing developers for priority fixes or ETAs * Guilting the developers into focusing on your issue(s) * Repeatedly showing an inappropriate level of entitlement, asking for issue status, or bumping issues. ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies to all JGraph projects and the draw.io google groups. Project maintainers are not subject to this code. ## Attribution This Code of Conduct is adapted from the [Contributor-Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version] [homepage]: https://contributor-covenant.org [version]: https://contributor-covenant.org/version/1/4/ ================================================ FILE: DEVELOPMENT.md ================================================ ## Setup Installers repo is: https://github.com/mediaslav/drawiodesktop build/ - resources for installer, don't change file names names there electron-builder.json - main build config sync.js - fetches version from ./draw.io/VERSION for build, and installs draw.io/war/package.json "dependencies" .travis.yml - CI config appveyor.yml - CI config draw.io/ - draw.io repo as submodule Currently CI build are activated from pushing to this repo, not from draw.io. ## High level workflow 1) You push to repo 2) git hook activates CI, and CI performs build (builder will use version from ./draw.io/VERSION, ignoring version in draw.io/war/package.json) 3) After successful build CI drafts new release in github and uploads installers, mac and linux from Travis and windows one from AppVeyor ( you'll see new draft here: https://github.com/mediaslav/drawiodesktop/releases ) 4) You wait till all installers get into draft and press "Publish release" Need to open corresponding draft in: https://github.com/mediaslav/drawiodesktop/releases Press "Edit" near relevant draft, make sure you see all needed installers uploaded by CI, and press "Publish release" below So manual work is push commit, have lunch, coffee and press "Publish" button. Travis OSX builds can spend hour(s) in queue. ## Configuring CI You must provide certain environment variables for github publishing and code signing GH_TOKEN = github token, for publishing CSC_LINK = Certificate converted to base64-encoded string, or url to cert (*.p12 or *.pfx file) CSC_KEY_PASSWORD = The password to decrypt the certificate given in CSC_LINK #### Travis CI - builds OSX and Linux installers Define vars at: relevant repo page / "More options" / "Settings" #### AppVeyor CI - Windows NSIS installer Define vars at: SETTINGS / Environment / Environment variables, Add variable ## Code signing ### Windows To sign an app on Windows, there are two types of certificates: **EV Code Signing Certificate** and **Code Signing Certificate**. Both certificates work with auto-update. The regular (and often cheaper) Code Signing Certificate shows a warning during installation that goes away once enough users installed your application and you've built up trust. For CI you can use only regular **Code Signing Certificate**, because EV Certificate is bound to a physical USB dongle. SSL certificate used for website is not suitable for signing apps. See [Get a code signing certificate](https://msdn.microsoft.com/windows/hardware/drivers/dashboard/get-a-code-signing-certificate) for Windows. And this may be useful: https://cheapsslsecurity.com/#ProtectYourCode ### MacOS Mac build requires Apple-issued Developer ID certificate, you must be member of https://developer.apple.com/programs/whats-included/ to receive one. #### How to Export Certificate on macOS 1. Open Keychain. 2. Select `login` keychain, and `My Certificates` category. 3. Select all required certificates (hint: use cmd-click to select several): * `Developer ID Application:` to sign app for macOS. * `3rd Party Mac Developer Application:` and `3rd Party Mac Developer Installer:` to sign app for MAS (Mac App Store). * `Developer ID Application:` and `Developer ID Installer` to sign app and installer for distribution outside of the Mac App Store. Please note – you can select as many certificates, as need. No restrictions on electron-builder side. All selected certificates will be imported into temporary keychain on CI server. 4. Open context menu and `Export`. To encode file to base64 (macOS/linux): `base64 -i yourFile.p12 -o envValue.txt` ## WARNING draw.io/war/package.json "dependencies" will get into installer, so please put irrelevant ones into "devDependencies", which is ignored by builder. Currently it looks like: "devDependencies": { "electron": "^1.6.3" <- we obviously don't need to pack electron inside electron as dependency } ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ About ----- **drawio-desktop** is a diagramming desktop app based on [Electron](https://electronjs.org/) that wraps the [core draw.io editor](https://github.com/jgraph/drawio). Download built binaries from the [releases section](https://github.com/jgraph/drawio-desktop/releases). **Can I use this app for free?** Yes, under the apache 2.0 license. If you don't change the code and accept it is provided "as-is", you can use it for any purpose. Security -------- draw.io Desktop is designed to be completely isolated from the Internet, apart from the update process. This checks github.com at startup for a newer version and downloads it from an AWS S3 bucket owned by Github. All JavaScript files are self-contained, the Content Security Policy forbids running remotely loaded JavaScript. No diagram data is ever sent externally, nor do we send any analytics about app usage externally. There is a Content Security Policy in place on the web part of the interface to ensure external transmission cannot happen, even by accident. Security and isolating the app are the primarily objectives of draw.io desktop. If you ask for anything that involves external connections enabled in the app by default, the answer will be no. Support ------- Support is provided on a reasonable business constraints basis, but without anything contractually binding. All support is provided via this repo. There is no private ticketing support for non-paying users. Purchasing draw.io for Confluence or Jira does not entitle you to commercial support for draw.io desktop. Developing ---------- **draw.io** is a git submodule of **drawio-desktop**. To get both you need to clone recursively: `git clone --recursive https://github.com/jgraph/drawio-desktop.git` To run this: 1. `npm install` (in the root directory of this repo) 2. [internal use only] export DRAWIO_ENV=dev if you want to develop/debug in dev mode. 3. `npm start` _in the root directory of this repo_ runs the app. For debugging, use `npm start --enable-logging`. Note: If a symlink is used to refer to drawio repo (instead of the submodule), then symlink the `node_modules` directory inside `drawio/src/main/webapp` also. To release: 1. Update the draw.io sub-module and push the change. Add version tag before pushing to origin. 2. Wait for the builds to complete (https://travis-ci.org/jgraph/drawio-desktop and https://ci.appveyor.com/project/davidjgraph/drawio-desktop) 3. Go to https://github.com/jgraph/drawio-desktop/releases, edit the preview release. 4. Download the windows exe and windows portable, sign them using `signtool sign /a /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 c:/path/to/your/file.exe` 5. Re-upload signed file as `draw.io-windows-installer-x.y.z.exe` and `draw.io-windows-no-installer-x.y.z.exe` 6. Add release notes 7. Publish release *Note*: In Windows release, when using both x64 and is32 as arch, the result is one big file with both archs. This is why we split them. Local Storage and Session Storage is stored in the AppData folder: - macOS: `~/Library/Application Support/draw.io` - Windows: `C:\Users\\AppData\Roaming\draw.io\` Not open-contribution --------------------- draw.io is closed to contributions (unless a maintainer permits it, which is extremely rare). The level of complexity of this project means that even simple changes can break a _lot_ of other moving parts. The amount of testing required is far more than it first seems. If we were to receive a PR, we'd have to basically throw it away and write it how we want it to be implemented. We are grateful for community involvement, bug reports, & feature requests. We do not wish to come off as anything but welcoming, however, we've made the decision to keep this project closed to contributions for the long term viability of the project. ================================================ FILE: SECURITY.md ================================================ # Security Policy ## Supported Versions | Version | Supported | | -------- | ------------------ | | Latest | :white_check_mark: | | Older | :x: | ## Reporting a Vulnerability If you discover a security vulnerability in axios please disclose it via our [huntr page](https://huntr.dev/repos/jgraph/drawio-desktop/). Bounty eligibility, CVE assignment, response times and past reports are all there. ================================================ FILE: build/create_macos_icon.sh ================================================ #!/bin/bash set -eo pipefail # Config SOURCE_FILE_PATH='./1024x1024.png' # has to be of size 1024x1024 px OUT_ICON_NAME='icon' # The "design" and magic numbers below are derived from Apple's macOS app icon # guidelines and design templates: # https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/app-icon/ # https://developer.apple.com/design/resources/#macos-apps # # Specifically, for an icon of 1024x: # - outer bounding box: 1024x1024 px # - border radius: ~22,85% (= 234 px) # - icon grid size: 824x824 px # - icon grid shadow size: x: 0px, y: 10px, blur: 10px, 30% black # Make sure ImageMagick's convert and iconutil are available. if ! hash convert 2>/dev/null || ! hash iconutil 2>/dev/null; then echo "ERROR: This script requires ImageMagick and iconutil." exit 1 fi # Prepare an iconset folder mkdir "./${OUT_ICON_NAME}.iconset" # Add rounded corners to the 1024px image. # # This works by: # 1. Generating a black square (1024 px) with rounded corners (radius 234 px) # on transparent background, via `-size [...] xc:none -draw [...]` # 2. Applying the square as a mask to the the source image, via `-matte [...]` convert "${SOURCE_FILE_PATH}" \ -matte \( \ -size 1024x1024 xc:none -draw "roundrectangle 0,0,1024,1024,234,234" \ \) \ -compose DstIn -composite \ "./${OUT_ICON_NAME}.iconset/temp_1024_rounded.png" # Apply sizing and add shadow to the 1024px image. # # This works by: # 1. Resizing to 'icon grid size' (824px), via `-resize` # 2. Adding padding (100px) to get 'outer bounding box' size, # via `-bordercolor none -border [...]` # 3. Adding shadow, via `+clone -background black -shadow [...]` convert "./${OUT_ICON_NAME}.iconset/temp_1024_rounded.png" \ -resize 824x824 \ -bordercolor none -border 100x100 \ \( +clone -background black -shadow 30x10+0+10 -background none \) \ -compose DstOver -flatten \ "./${OUT_ICON_NAME}.iconset/icon_512x512@2x.png" # Remove temporary file rm "./${OUT_ICON_NAME}.iconset/temp_1024_rounded.png" # Generate all sizes. # 16/32/128/256/512, each single & double resolution cd "./${OUT_ICON_NAME}.iconset/" convert './icon_512x512@2x.png' \ \( +clone -resize x16 -write './icon_16x16.png' +delete \) \ \( +clone -resize x32 -write './icon_16x16@2x.png' +delete \) \ \( +clone -resize x32 -write './icon_32x32.png' +delete \) \ \( +clone -resize x64 -write './icon_32x32@2x.png' +delete \) \ \( +clone -resize x128 -write './icon_128x128.png' +delete \) \ \( +clone -resize x256 -write './icon_128x128@2x.png' +delete \) \ \( +clone -resize x256 -write './icon_256x256.png' +delete \) \ \( +clone -resize x512 -write './icon_256x256@2x.png' +delete \) \ -resize x512 './icon_512x512.png' cd '..' # Convert to .icns format and remove iconset iconutil -c icns "./${OUT_ICON_NAME}.iconset" rm -r "./${OUT_ICON_NAME}.iconset" ================================================ FILE: build/entitlements.mac.plist ================================================ com.apple.security.cs.allow-unsigned-executable-memory com.apple.security.cs.allow-jit ================================================ FILE: build/fuses.cjs ================================================ // https://github.com/electron-userland/electron-builder/issues/6365 const path = require('path'); const { flipFuses, FuseVersion, FuseV1Options } = require('@electron/fuses'); const builder = require('electron-builder'); async function addElectronFuses(context) { const { appOutDir, packager: { appInfo: { productFilename } }, electronPlatformName, arch } = context; const ext = { darwin: '.app', win32: '.exe', linux: [''], }[electronPlatformName]; const IS_LINUX = electronPlatformName === 'linux'; const executableName = IS_LINUX ? productFilename.replace('.', '') // Remove . from "draw.io" : productFilename; const electronBinaryPath = path.join(appOutDir, `${executableName}${ext}`); // We build for x64 and arm64, but universal build for these two also but no fuses is needed at this temp stages if (electronBinaryPath.includes('-temp/')) { return; } console.log('Flipping fuses for: ', electronBinaryPath); await flipFuses(electronBinaryPath, { version: FuseVersion.V1, [FuseV1Options.RunAsNode]: false, // Disables ELECTRON_RUN_AS_NODE [FuseV1Options.EnableCookieEncryption]: true, // Enables cookie encryption [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false, // Disables the NODE_OPTIONS environment variable [FuseV1Options.EnableNodeCliInspectArguments]: false, // Disables the --inspect and --inspect-brk family of CLI options [FuseV1Options.OnlyLoadAppFromAsar]: true, // Enforces that Electron will only load your app from "app.asar" instead of its normal search paths // https://github.com/electron-userland/electron-builder/issues/6930 (electron-builder uses its own asar packaging) [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: false, // TODO Enables validation of the app.asar archive on macOS // Some reports it crashes when enabled on arm64 [FuseV1Options.LoadBrowserProcessSpecificV8Snapshot]: false, // TODO Loads V8 Snapshot from `browser_v8_context_snapshot.bin` for the browser process // Based on docs, this should be enabled for macOS on arm64 resetAdHocDarwinSignature: electronPlatformName === 'darwin' && (arch === builder.Arch.arm64 || arch === builder.Arch.universal), }); } module.exports = async (context) => { await addElectronFuses(context); }; ================================================ FILE: build/icon.hqx ================================================ (This file must be converted with BinHex 4.0) :%'%e1@3j0$N`-Q3iB6)bB6B%9%9B9(4dH(3%!!!!!Y!!!@G8-Je)EhFJG'mJGA0 P)(4SDA-JD@0[EMS+#P0dCA!J-6SJ3fp`H5"dD'8JD@0[EL"dEb"dD'8JBfaTF'* [BA*N#Q%T)%0XD@0V)'pZ)(4SDA-JCQPXC5"QFQpY)(4SC5"'D@jNCA)+BLNJ3fK [Eh0P)#G(CA3J5@jQEbFJCR*[E5"dD'8J*dCTE'8R)'ePER8Z#Q-T)%PZ)(4SC5" TEQC[)(GTEQ4[Gb"dD'&d)("[F(-JGA!X)'0XD@0V)'pZ)(4SC5"TBfpZ#Q3T)%0 SEfpcC5!R3fp`H5FJCR*[E5"dD'8J*d9NDA3R)'ePER8Z#Q8T)%0XEh0P)(4SC5" TEQC[)(GTEQ4[G`S+8h4PF#!b1L"3BA0dC5"dD'8JD@0[EL"dEb"dD'8JC'9cDA* PC#"TG'9Y#Q%T)%G[)(4[)(4SC5"TG'9Y)'PZ)(4SC5"'D@jNCA)JG'KKG#"jEh8 JGf&ZG#"K)'0eFh4[E5"TBfpZ#Q)T)%0XD@0V)(4SC5"TG'9Y)#KQD@aP,#"QEfa NCA)X)'4TFfXX)'9dBbNJ#Q)T)%0SEfpcC5!R4f9d)%PZCQmR)'CbEfdJG'KP)#G 'D@aP*b"YC@je,JTM+5"*EL"dD'8JD@jQEb"hD@jNEhFJG'KKG#"`Eh"c)(9`,#" ME'PMDb"[EL"dD'8JD@0[EJTN+5"$D'p[Ff8J*e"KFh4P*b"QFQpY)(4SC5!R4@4 TG#FJE@9ZG5i+C5NJ3fa[Ff8JG'KP)'PZCQmJGfPZC'ph#JT6G'9`)$-k)!T&EQT [H5"jEh9b)'jPGfaj)'0eFh4[E@PkC@3JD@0[EL%+#NC[FL"YEh*P)(4SEh*[G@G S)'4TFQ9MG'P[ER-X)(0PC5""F("XC5Gc)(GPBR0TG'8JBA3k#QKdG(!k,bphGhF ZBA"`E'8ZBfpY,h0eF("[FR3[E@&M-6!a,f0eFh4[E@PkC5mf,`V6V!!!!3!!!@F L!!&Q)J!!!$)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!@BHD@0ZF`!"CKjTFc-b!!!#f`$[J2!"lr#$li$`!1q#m!I[mI, bmI$[li6`#Hrcrrlqrr$[m1q$m!V[pIrqr[rTj[([li,`#qrerrlqrqVFkI([li( `*qrbr[[mrH6GhZRalr$[m2$[mIVKi[MKhYrHk[([m1r[l[VXh0cYmpZ!hPEUm1r `m2AjhYrHh[MSiH$HhZr`r2lqrr$GhI$rrIlihpl[mIlrr[rehGherrlrr1(Hlr( qrrlrpGhGpIrqrrcKhZr`qI[lrHrGhHrpqrhfhpl[m1lLhq#"hS$J#0lHhr$[m1h JhB(IJGi+hpl[m1ralZ$Hhpk#h`(Hh`Z'KiH'KSH$JS+$KiD!K`#'JSF(KC5APj1 'KiD$K`U)J+IrrIhrRi')KS+(#iKrXrrmr2qGFSZ'KS'($)KrXrrmr2qHBAk*KSD !Kc1)JThkmI,hK@GVIBQ'KiD(L)55jRKkiRCTE@YqLBD(KB4lekYKB+l*A@PUE(f (KBb2VH4UJ'YEijKhFfPXKSRSr[Vr[@9Q[[rjrZ*ZDi52prrlrp0PCY6rqrreG@Q %MrIrr2r5C@E8rrcrpA9TKSMHp1rjYQ9PYrRZpYKYDiH'K(CaFfPVDfPbFR0VDQb 'KiL#E@Q"E!jUDQPVE'Z'KiD*K'jVE'Z#E!&VE!8%"38%"3@"!!%&")!&!!5""3B %"#!R*b!%K38*"`")rr[lrd3!"i-J!B2rlqrpJ!!H$"3`)!'$rq[VrB!!,"!8 %J!9r"`!dpHRUmcB%$JF%"38%"3J!(Y%K)p!I"`i0"`3%"3)"!+Pj!!"lTJ!(#3` ("3)6&e65$3X,$Y&8(KJ*$!-+d2hfrj)"!T6rp[h2$`S!&Zrrq2qf!3+irrRrlKX (!"E[rrVrYJ%#Z2rkrqiE"`-([r$NpBB"!BMej2#r$JX&!`L!&`m*#`X*&aFB$!N -"!8%!JJ*J3`9#!N)#``,"!3&"3B-$!X,$!d-$3`,#h-iE@X!!!%)lIrqrrrrrrr rrrrrrrlrk[rrrrrrrrrrrrrrrrrqrrcqrrlrrrrrrrrrrrrrr[rlrrrrrrrrrrr rrrrrrrlrr2rrrrrrrrrrrrrrrrrqrrcrrrrrrrrrrrrrrrrrr[rmrrrrrrrrrrr rrrrrrrlrr2rrrrrrrrrrrrrrrrrqrrcrrrrrrrrrrrrrrrrrr[rmrrrrrrrrrrr rrrrrrrlrr2rrrrrrrrrrrrrrrrrqrrcrrrrrrrrrrrrrrrrrr[rmrrrrrrrrrrr rrrrrrrlrr2lqr[lqr[lqr[lqr[lqrr[rrrrrrrrrrrrrrrrrr[rmk[rlr2cmr2c mr2cmr2[rk'PX-c)!!!LX!Hr[QI#!lj!!m!$[Kr!!liI`!Hr`KHm"m1q3!2!$lr$ [mB2c!2'!lj!!m!E[pIrqr[rrJ2i$mqr`lir`!Zrkri2q"2rcjr([Mr!#lrVrJri &rr6Fk[([M[!$lrVrrS(r"rlrp0hHk[([MI!$lrVrrS(r#2lrp0hIhZ[alic`!Zr kri2q#[rdhGrHhZ[alr$[LI!8lrRrr[lrrrlqrr,FhprHhZ[alr$[L2!9lr(lrrc iq2crpq,HhplIhYrXmHr`liE`&Hr`l[VrjYhGjrrch0rHhplIhYrXmHq'm"I[m1r drr2FhprFmrrShGrHhplIhYrYm1q'm!h[m2hpiYlIhplLr[RIhS$I"GlIhYrYmB$ `!1q#m!hZp[rYh0rHhYrFlIrYh)(I#GlIhZ$Ym2$[m2#!l`2ZmIrjKGm,qIlKh0l GhYrHhplJJ2!Flqram[,aqIrYhGlIhYlIhYhYrr2Lj16LhGlIhpk!m!,[prq$rJI jiGlIhplLqB2q![r[hB$I*I$`lr$prrlrr[lrr[rVh0rIh1[rr[rqr[rqrr[JhYr Im2$[mIhrJri*rqcFhprFl2rqri(q$2rmi0lIhr$`lr$prrk"r`Rqrq[FhprFl2r qJIm0r[rmi0lIhr$`lr$prrk"r`Rqrq[FhprFl2rqJIm-r[rmi0lIhr$`lr(pri2 q"rrXh0rIh1crJri-rrcJhYrIm2$[m2hrrS$r#rlqrqVFhprFk[rqrS$r"[lrqpr Hhpq!m!,[p2U"q`[kqr2IhYrIhZ$dqrU#q`(UhB$I!I$`J1m"k0k#h`IGhYrHhYr HhB6I"0hIhYrIJ2!%lr$ajpf"hJIIhplIhplIhi6H!GrHJ0q"m!6[lr(RhB(I!0k "h`$HLYq#m!I[lr(RhGrIhT!!h`$[J[!%lqrajpk4h`,Hlqq#m!6[lr(QhSrI!Gl I!BD'QBH!KSQ(JiJ"KiD(K`#'KiF#KSH$Ji%#JiH'N!#(")D(JTDLJD!%ST@#KiD 2K`H)J,(rr[lrri$q!kU"L)D1K`5)J0[rr)(q"Icrc(5,KSk(")L"hIrpJIi'r2r 2BRq*KSf(")L"hIrpJIm*r2r3BfaqLBD(KSU(")L"hIrpJIm+r2r2BfeVIiL'KiD *Ka5)JGhrrIlprIlprp"MEQYVJ)L'KiD)Ka@)J06rr2lrrrlmrm9LEQaVDi#)KSH 'KSFAKSH%PZIrmZ2Mm[rGHfPXDfaVE)')KSH'KSF9KSKqf2q3!'9PN[r+B'jVE'Y XDfb"L)D'KaH'L(qZrmKLE@eLbIq@BfjVE'YXDff#L)D'K`f&LI$kHfGYE@GmrHG XDi"X"@YXDff#L)#(!)D"Ka'+IX(rVf&ZDfYZBE$rV@&[E@f!E!jUES+(KiD(Ki1 #Jhk9rq@&E!ERqhKLCfCRJ'`SDff(KSH'Jj@DQT6ArkeQDQaVDfaTCUhrbAZ$Jhe RDfaXDiH(L),'rrf!rJ[prZCiD@aXD(VSrIf!rLcprlGPE@aXKiH&MIArr[rqr[r mrk0LEQjKTrrmrrlqrrlrm(*UE'b(Ki52p[q#rJRmrkGKEQjKU[rmJ[i-rr*eD@a XKiH%MrIrrS$r#rlmrkGKEQjKU[rmrS$r$Ilrmh4TE'b(Ki52p[rqJ2m,r[crTf& ZEQ'UrrcqJ2m0r[rcG'PXE)H(K)rfrrf"rJRlrkKKEQjKUrrlJIi0rIrbG@PXE)H (KB[brrk!r`[qrIqIBQjZBU,rr2k!r`cqrqe`DQaXKiH)JV2XJZd*mFa`DQaXDR( 1mB2Y#k&PE@aXKiH'Ki*lES*`"f9TE'YVE'PQJA!(Eh"XC@aVE'b!K`@'L)KjD'Z !DJGYE'YXE'YXEB0U!QYYDi"XJBF%KSD*HQU"E!"VJ@`!DiTXJSF(KSD)H@PXE'Z 3!'`!KS+(")D'L(PUN!"X!fYXKSD#K`5'KSPhDT&X!33%Q3@!")B&!J3&"S-(!3B %K`8!")F&!33'K!!#!3B%NJ8,!#Bq1MXl1MiN!!8%M`8("`"Grrlqrrq!rJ06!!F %MJ8%"`#frrU"r3Ekrk`!"`8%M38%"`#irrZ"rJIlrl%!#33&")`&"!F!ZIrlJIm )qrqa!!m'"!8%L`8%"`#irrZ"r`Rlrl%!$``'"!8%LJ86"`#irrcpr2cpr2qa!!i -#`B%"35*"43)!+Irq[hrrrhkrjm!$`X-#`B%"35("4B%"J!Pc[rTdG(UrmJP"`d -#``,"J3&")J&&3F!X[p)!!",rkN!$`X-$!X-#`B%"35&"4B%#!"Drk3!$Ji!Trp 5!!m,$!`,$!X&")F&$3)2hrNQ"3i1"5Mlf!d,J3`%#``,"35!"43%"3B("JS!JIp m!"!,#a!!I[pi!"+!$3--#``,J!8+"!8'!!!#!#Ipe3k$$(-1erJL!!8$"3d-#`` ,"33&"!)M,#dJVIph!`N0#`X0#34irkBP-c)T"3X-#``&"3F!L[rmrIlqqrh@)!F 0$3BMfIhlr[lpr2q)!3i-#`8'!42Urrhrr[hrqrpS!!m2!'hrqrrpr[rprqF@#3` -"3B!&qhrrB(q#IVrE`!2$`"crrU"rJhprqSE#!d-"3B!&qlrrB$r#rllrfi!$`m !FrrlrS$r$Ihrl"S)$3`&"J!@l[rpJ2m,r[[rEJ!2$`"crr[qJ2m0rIrV'JJ0$!8 '!"IYrrb"r3Rjrfm!$`m!G2rjJId0r2rU'`F0$!8&!JrNrrf!r`[qqrpK!!m2!'A rqrk!r`cprq)6#3`-"38(!'6NJH),iHHX%`S-$!N8VqIKJZ),B`%1$!`&"33&!!S 6JK)(!`N-#`X-#!5#%JB6$!--#`X-J!84"!F$"3S*#3S*$J`,$!`,$!d*J3S$#3X 1#i!-J!8!")!&!3J0J3`!#i%-!!Z*$!!,K!8%"!J-#`Z2$!),$!5""3F%"38%#!` ,#id-"!X-#`3%J38("!8&"!J-#`Z,$!-,$!X,E$KYD`!!"!LYrrhqrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrr[hrT[hrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rr[rhrIlrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlqrrMqrrlrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrlrqIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rr[rjrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrRrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrlrqIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rr[rjrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrRrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrlrqIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rr[rjrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrRrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrlrqIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rr[rjrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrRrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrlrqIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rr[rjrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrRrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrlrqIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rr[rjrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrRrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrlrqIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rr[rjrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrRrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrlrqIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rr[rjrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrRrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrlrqIlrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rr[rjrIlqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqrrMmrrlrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrlrpkEqq2RjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIR jq2qKD@Jc-J!!$ZQ!lkI`JHqVm!$[V2!!lil`!1q*m!$[R[!"lr#*l`(`ljc`!qr `lr'(p!2alr$[Q[!'lr$[pIlrrS2r"2lrr[2[R2!$lr$priIq"2rjk[([Q[!$lr( qriIq"IrmiHValjR`"1rar[rqKIm*r[rpiGlVmHr`ljE`"1rar[rqKIm+r[rpiGl Ikr([m1q9m!6[mIlrrSAr#rlrrH(HhYrXmHr`lj6`"1rar[rqKIm-r[rpiGlIhYr XmHr`lj2`"1rar[rqKIm0r[rpiGlIhplIlI$[m1q5m!6[mIlrrSAr$[lrrH(Hhpl IhYrYm1r`lj(`"Hrar[rqri2q%2rqrrcJhYrIhYrHi1h`lr$[NI!#lrRrJ2k"ri$ q![rbhB(I#0lIhZ$Zm1r`lil`"qr`lr$irrrpJIF(rIrrlprHhpk!h`MHhplJl[$ [m1q1m"([m1lfrrrZfplHh1rrrqRFhpk#h`MHhplJl[$[m1q1m!r[mIlrqYrHhpr HhrVrr1(HK0m)hYrHiHl`lr$[Lr!(lr$[qIrrkGb"h`IFkIrrmGcIhS2I"YlIhZ( [m1q,m!I[m1rcr[rehB2I"phfrrlPhGrHJpm'hYrGiHr`lic`%HrlrrlNhGrHhpr HhphPr[rfhBEI"0lIhH,[L[!*lr$ZpIrrm0cIhS(I#GlIh2(rrqRFhpk%h`6Hhph Mli2`!1q$m!E[m2hrqq(HKGm'hZ(lrrVIhS2I"YlIhplIhZ+#m!([m)2["qlirrr Uh0rHJpm)hYrFk[rrlp[HJGd(hYrHhprHhpk"m!2[m1r`J[))p2lrqZAJhGrHJGm *hYrGi1AkrrhRj)(P"prGhplIhplIJ2!Hlr$[m[hrr[lrrrlqrrlqr1IGhplIhpl IhHMmr[lrrS$r"rlqrrVNhGrHJ0q#m!,[qrq%rJErr[lrqYrHJGm'hZ$lrrlqri6 q![rhhS,IJI!$lr$pri2q!IrrJIi"ipf"h`(Gj)(q!IrrJri$rr[JhS(IJI!%lr$ prrk&r`6qrrlMhB(I"0hNr[rqKIm%r[rmi0k"hi(`"1r`rIrqKIm%r[rqipf"h`6 Gj2rrrSAr"2lrr1$HJGq"m!6[m2hrrSAr"2lrrZ2GJGm%hH6rrrk&r`6qrrcJhS( IJI!%lr$prrk&r`6qrrlMhB(I"0hNrrrqKIm%r[rmi0k"hi(`"1r`rIrqKIm%r[r qipf"h`6Gj2lrrSAr"2lrr1$HJGq"m!6[mIhrrSAr"2lrrZ2GJGm%hH6qrrk&r`6 qrrcJhS(IJI!$lr$priRq!H2HJGm"hH1*rJ2rqq$HJGq#m!2[qIrqKIm$r[rfhS2 I!plhrrk&r`2qrr2GJYq#m!2[m2EjK[S,p1(HhplIhplIhZ,dKrS%mZ$Hhpk!hi( `"Hr[m1hKhSAI!phHhpk"h`2HhplGKpm$hGlIhS(IJr!&lr$ZiGhIJpi#hprHJpm #hYrIKpi#hprHJYq#m!E[m1r`lZ(HK0m!hSAI!0k3!0q$m!M[m1r`lZ(HhpkHhi6 `#1r`lr$Zi0lIhThIKI!)lr$[m1lJhYrHR0m!liA`#1r`lr$Zi0lIhTVI!Gl[K[! )lr$[m1lJhYrHQ0m"hYq!liA`"Zr`lr$Yi0kBh`,HhYm"KSDTKi#'!BH'UBF"KSD UK`#'MiF"KSH(L!'(KTk(!SD)JiGr!S5)KTb(")D(JC@XKUX$Ni'(KTU("SD)J,$ prrk$r`EqrrZTJBL'QSF%KBcarrb&r3ImrqCrL)D(KTL(!i1@qrq(rJIrpAGmLBD (KTH(")1@r2rqKIm*r[rhH'L!L)D(KTD(")1@r2rqKIm+r[rhH'KXJ)L'KiD9K`5 $P[crrSAr#rlrphKTE'b"L)D(KT5(")1@r2rqKIm-r[rhH'KYDfb"L)D(KT1(")1 @r2rqKIm0r[rhH'KXE'YYJSL'KiD5K`5$PrcrrS6r$rlqrrCiD'aVE'YYJSL'KiD 4K`D%NrRqr[rqJId4r[rqrr0eD@aXDfaUEB1)KSH'NBF3JYIrrIlqrrlrrrlqrIr 'C@f!E!KVE'TZK)L'KiD1K`H'Ki@*brrrpi(E"rMrrlKYDQaVJ'`)DfaUES5)KSH 'MSF4KSPmZ2rrY9jSD&kirrqIB'pVJQ`)DfaUEi5)KSH'M)F4KSH$PIMrk'pVE@e UF1VrmRGSK'`)DfaUEi@(KSH'LiF6KSKrdrrrR'*ZE'aZBTlrrm"KEQZ$E!CVE'T `KBH'LiF)KSL!TIrre@CYJ@`)E@EArrb)C@eVJf`'DfaUF)D(KSb(%SAPrrb'C@e VE'aVE@@)r2rACQf&E!4VE'TaKSU(#BD*IVIrrljKEQZ"E!PVEQ(!rrqHBQjVK'` %DfaUFSD$K`''Ki+)"S@2mrr`GQQ&E!GTGr(rkR"VES&Y"faVE'aVE'TaJSF#KSL 'JB%)Jh[,rrqJAh"VJf`)Dh"ISIrrYPaRJ@8(DQeVE'aVE'Z"K`5'Ki++RS#I#Cb YqrrVLA0PE@Z"E"9VE@9dLZcrpTD'LSQ*L'pQE@YXE'YXJ)FHKSL#Rr(rr[lrrrl qrrcqpC4PE@YXE'YYCCIfr[crrS$r"rlqrqf'CQeVJ'b#K`1&j[rpJri'rrlprqT `DS&X"QTcl[rpr[q$rJ2prpYSJQb"K`1%MrErJri"rrq!rJMlJ'GYE'aYCS5"rJ( rri2q!rraFfQ"E)'(")52prrqKIm0r[rpJ@GYE'aYCS6rrrk&r`6qrr*dDB&XJBF %K)rhrrk&r`hqrrf"CfeXE'eQK2rrrSAr"2lrmh4TJ@b"K`5%MrIrrSAr$IlrrB& RE@aXE@D%rrrqKIm%r[rcG'Q"E)'(")52prrqKIm0r[rpJ@GYE'aYCS6rrrk&r`6 qrr0dDB&XJBF%K)rhrrk&r`hqrrf"CfeXE'eQK2rrrSAr"2lrmR4TJ@b"K`5%N!$ hrrk&r`hqrrb"CfeXE'eQK2rrrSAr"2lrmR4TJ@b"K`1&MI6rKrd+r[YqCfeXE'e RJIb(r36mrr"bDS&XJBF&L)(@rrhqK2m$rIrDDB0X!f[Grrf%r`AqrIr*C@f"E)# ("SD(K)h0k1U%k3hUchPSE@YXE'YYCh[4kSAT"HV&F@PXDi"XJBF&KSH&IA&XK@d $C'KXDi&X!fYYD'5'E34XBfPXDi&XJSF&KSH*K@pTK'X#E@aVJf`#DfeYKfX#E@a VJQb#K`D'KiD)KA"UK'`!Di9X!'Z*E!"VJfb$K`L'KiD)K'pUE'ZHE)5(#)D(KSL %EfTXDjeXKBF)KSH'L)4[DQaVR'`"KiD%K`L'KiD)K'jUE'ZDE!&VKSD(#)D(KSL %EfYXDjKX!@YXJ)D&K`D'KiD)JfeVQ'`#DfaX!33%U!@""!%&"+N&!33%[38""!D (#!%'"*i&!J3(!BF!!J%("*`&!`3'!#5'8J44)!!'"*S&"J3(!&lmrrk$r`EqrrG 2!!F%QJ8%!4(NrrU&r!EkrpB)!`8%Q!8%"J!Qq2q(rJErm#!""38%P`8&"J!PqIr qKIm)r[ra)!B("!8%PJ8&"J!Pq[rqKIm*r[rb)!B0"J3&"*8&"3B!*[VrrSAr#[l rmL!'$3X'"!8%P!8&"J!Qq[rqKIm,r[rb)!B0$!X'"!8%N`8&"J!Pq[rqKIm-r[r b)!B0#``,"33&"*)&"JB!*[Rrr[k$r`lqr[ra)3B0$!X-#`8%"354"3F'!"rdr[l rrS(m%2lrrIrV'`J0$!`,$!X&"!8%N384"J#ZrrcqrIrqrrrpr[crS3!1J3`'#`` ,"33&")m&#!3'!Jq6rrrc`i$%"r6rriS1#3`,J3`'#``+"33&")m&%33*!(2rri8 !"JB!L[rrC!!3#i--"JX-#J8%"351"4%'!#IbrpS5#Ji1#4AGrqNI"`f%$!B,$!S &"!8%M385"`#QrrpF!!m-$"!!BIrrQ!!2#i3-"JX-#J8%"35+"3J%#!"(rrqk!`f "$!J0",lrqM`"$JZ%$!3,$!S%")i&%FVrq6N"$JX-$!X1!6ckrld%$BB-"!X-#J3 %L38*"!J!EIrrP3!2#i%-#3X2!*Mrrf!!$`Z&$!-,$!N%J`8""!@""`J)!4VQrqF G"`f$$!J0"arSrp`8#`q"$J%-#i!-!JX-#S)&!J3(!i%!#!)!P[rrC3!5#i--#!X 5!'IrriJ!")%"!JS1#i!-!3X-J384"!B!$cBh0cNa9[IrhcdC!Jd,J3`4#`d#'Ml Jrr"41$ip26X5"!d,J!`!#i!&(J3(!$VMrrlqrrrqrIrlrZj1!!i,$!`,$J"8m2l lrrf!r`Iqr[rK1!-1#i!-JJ8$!m[rr)(q#2hqrrlmrpd6#B%-#!JBj2rpr[rqrB( q!r[ra!D#$)!&"3B!&qhrrB,q!IrrJ2i1qLi%$3`-$J)drIhqr[rrJ[i%rIrS'3L "$)!&"3B!&qlrrBAr$Ilrr#m$$3`-$J)drrrqKIm&rIrU'JJ0J!b!"38'!"I[rrf &r`hqrr`[!`d-$!i#02rrrSAr"IhrkaN)$B!-J!8&"J!AlrrpKIm0r[rm,`-0$!` 1!M6rrrk&r`AprqXD#!f!$)!&"3B!&qrrrBAr$Ilrr#m$$3`-$J)drrrqKIm&rIr V'JJ0J!b!"38'!"I[rrf&r`hqrr`[!`d-$!i#02rrrSAr"IhrkaN)$B!-J!8&"J! Bl[rpKIm0r[rl,`-0$!`1!MArrrk&r`AprqSD#!f!$)!&"3B"%qVrqiAp$Icpq#X %$3`-$3-[qrcmKId%qrrQ&JQ"$)%&"3F!U[rlrS6r!rcr``L#$!3,#XMrr)6r"Il lrkF!$S%-J!8'"!B"&D2Hfi2F$p[GVb-&$3X-$!X0"5HdhGZ$h!EEhCm@#!d,J!b ""38%"33!#`q%$J30!3F0#i%-!`X0"`''$J3-!!N-#i%-JJ8'"!B("!N,#S%,"!S ,$Jd,J``%#`d1#`U$#`3+#`m0#i)-J`8!")!&!!Z&$!!,K3`!#iN-!!Z$$)3&"J3 &"!8+$!ZI$)8&"J3&"!8+$!ZH$)B&"J3&"!8+$!ZG$)F&"J3&"!8,$!ZC$!-,$!X %K`8'"!8%"3S-#jS-!!Z!")B&"J3&"!8,$!ZA$)!,D$KYD`!!#3KBm2rqr[rrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[lrl%rSrrlrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrprprpr[rqrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlqrrAqrrlrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrAqrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrErrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrEqrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrEqrrlrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrAprIlqr[lqr[l qr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqrrAQrrlrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrprpe2jIMep[Efp[E fp[Efp[Efp[Efp[Efp[Efp[Efp[Efp[Efp[Efp[Efp[Efp[AjidKTG$-b!!!X0J! !!!#$l`(`lqh`!Hr`Kqm#m2$[lr!#lr$`Jqm$m2$[lr(`!qr[m2#"l`(`lrA`!Hr `J1m"m1rim)$[qr!!lrh`!1rlm!$[rr$rm2r`rr#Rm!$[Pr!!lpl`!1qGm!$[f[! %lr$`lqkAl`6Zlr$`lpM`"Hr`lqrdq*El"[Vimqr[m1r@m!I[m1rbqrrqrTArJ2i %q[$[m1r8m!A[m1rbr[qErJErr2$[lr$[dr!$lr$mrjhq"[rflI$[m1r3m!A[m1l errkEr`Iqr[rqk1h`lp2`"1rkrrlqQrm(r[lrlGr[m1r4m!6[m2crrTcr#2lqrr6 EiZr`lp$`"1r`r2rqR2m*r[lrpYhHiZr`lmr`"1r`r2rqR2m+r[lrpYhIhH2[m1r 1m!6[m2crrTcr#rlqrrEGhprGiqr`lmh`"1r`r2rqR2m-r[lrpYhIhYrGir$`lmc `"1r`r2rqR2m0r[lrpYhIhplIhH6`m1r,m!6[m2crrTcr"2lqrrEGJ0m'hYrGj2$ `lmV`"1r`r2rqR2m%r[lrpYf!h`IHhprGjI$[lmR`"1r`r2rqR2m%r[lrpYf"h`I HhprGjI$[lmM`"1r`r2rqR2m%r[lrpYf#h`IHhprGjI$[lmI`"1r`r2rqR2m%r[l rpYf$h`IHhprGj[$[lmE`"1r`r2rqR2m%r[lrpYf%h`IHhprGj[$[lmA`"1r`r2r qR2m%r[lrpYf&h`IHhprGjr$[lm6`"1r`r2rqR2m%r[lrpYf'h`IHhprGjr([lm2 `"1r`r2rqR2m%r[lrpYf(h`IHhprGk2([lm,`"1r`r2rqR2m%r[lrpYf)h`IHhpr Gk2([lm(`"1r`r2rqR2m%r[lrpYf*h`IHhprGkI([lm$`"1r`r2rqR2m%r[lrpYf +h`IHhprGkI([llr`"1r`r2rqR2m%r[lrpYf,h`IHhplGkI([lll`"1r`r2rqR2m %r[lrpYf-h`EHhplHk[([[r!%lr[rr[kEr`6qr[rchBhI"YlIhYlUmHqmm!E[m1l irrlqR2m&r[rXh0rHM0m'hYrHhZVallh`"1rcrrlqQrm%r[rmiGk2h`EHhplHkr( [Zr!%lr$Zq2q!rS6rLIk%ri$q"2rVh0rHMpm'hYrHhZc`llV`"qr`lqrjrrlqK2q *rJ(rrS,r"2lqrqlGNpm)hYrHhqc`lr$[Z2!&lr$[lrAmJ2i(rrrqrrlqrrk$ra$ qrrlqrrlrrrlqrIMRh0rIhT,I#0lIhYrXm1r`llM`$Zr`m1r[qIrqr[rqr[r`kSA V$ZVbrrlrrrlqrqlFhGrIhT6I"YlIhYrXm1qkm!c[m1rbr[rqrrlqrrMGKp`#h[R rJIi&rrVJhYrHPYm'hYrHhqh`ll[`"1rkrrlrJ2i#rqEGKYm$i0hSri,q"2r`h0r HPpm'hYrHi1h`llI`$Zr`l[6rr[lrrrlrmpcIhSII$0herrlrr[lrrZ6GhpkAh`M HhplJlI$[m1qem!2[m2crJIi&rrhLhYrHKGm&hYrGirlrJIi#rrAGQYm)hYrHi1l `lr$[X[!1lr$Zprrqr[rrr[rZh0rHKpm'hYrFlrrqri$q"2rSh0rHQ0m)hYrGi1l `lr$[X2!&lr$[mIlrJIi$rrRIhS[I!plJqrq"rJ2rqGrHQYm)hYrGiHl`lr$[Vr! %lr$ZqIq#rJ6rk0cIhSRI"0lIh1VrJ2i'rrlrlGcIhTRI#0lIhH(Zm1r`lkh`$1r `lr2rr[lrr[lrpGf2h`,Gp[q"rJArrH,HhpkCh`EHhphKlr$[X2!#lr[rJIi&rrl NhGrHLpm$hYrGjB(q"[rqrr2FhpkDh`EHhphLlr$[V2!1lr$ZpIrqr[rrr[r`h0r HMGm'hYrFmIrqri$q"2rQhGrHQYm'hYrGiZr`lkc`#qr`rIrqrrlqrr[JhT(I!pl Kr2q"rJ,rppkGh`EHhphMlr$[UI!1lr$Zq2rqrrrqr[rVh0rHMpm'hYrFl2rqri$ q"2rVh0rHQpm'hYrGiqr`lkI`!qr`lr+!rJArr[lrppk8h`2Hh[MrJIi$rr[JhTh I"YlIhH2`m1qSm!6[q[rqri$q"2rQhGrHNGm%hYrGjrq!rJErr[r`h0rHR0m'hYr Gj2$`lk6`$Zr`l[6rr[lrrrlrmYcIhT2I"YlIh22rr[q"rJ2NhGrHR0m'hYrGj2$ `lk6`!qr`r2q"rJArr1,Hhpk6h`cHhphLrIrqr[rqrrEGRYm'hYlIhH6`lk,`"Hr `l[IrrS$r"IlrlGcIhTAI"YlIh1lrr[q!rJ6rkGcIhTcI"0lIhphPS[!&lr$[mIl rJIi$rrRHhTRI!plIqIq"rJ2rqYrHRYm%hYrIhH5Km!E[m1rjrrlrJ2i%rqMFhpk Ah`6HhpcSri$q"[rqrqlFhpkGh`2HhprHS2!-lr$[mrrqr[rrr[rdhChI$0herrl rr[lrrH,GhpkGh`,Hhpq6m)V["2$[lrcrJIi&rrhMhGrHQGm2hYrGj2lrr[lrr[r chGrHhiRHNYm!hT!!m!$[MI!1l[Err[lrr[lrm0hJhprHPpm'hYrIi0h`ri,q!rr RhH#-h`$HN!$IM[!%lr$`lqq,lJ,`rIq"rJRrqGhFh0hHhprHNpm*hYrIhYhFh0h kri(q![rihB[F"0hHhprHMYq0m!A[m1rZmI5*pK2hp[Vrr[rrr[lrpZhZl1EIh0r IhT(I%YlIhpcIjqhZlIErr[lrrrlrmqf*lJEYk1(FhYrHMGq-m!I[m1r`q2hrrSV r!IlqJ[m,r[lrr[lrqZRGhprHMpm,hYrHhHVkrrlqrrlqJ2m$r[rqrSVr"rlrr1r HhYrHM0q,m!A[m1r`r2q1rJ(rrS$r!IlrJri#rqrGNpm#hI(rJri"rrk!r`(qril q"IrhhplIhS[IMI!#lrVrMrk%ri6q"2rUh0rHMGm%hYrFlIq%rS6rMri#rr2GMGq -m!6[pIrqrT[r"2lrqq$HMpm%hZ,prrkDri$q![rRhBcIM2!%lrVrr[kEr`6qr[r ThBhI"YlIh1crr[kEr`6qr[rch)cILr!%lr$prrkFr`Eqr[r`h0rHMGm%hI2rr[k Er`6qr[rihScILr!%lr(prrkFr`6qr[rbh)rI"0herrlqR2m%r[rli0k,hi[`"1r arIrqR2m%r[lrmpf2h`6Gp2rqrTcr"2lrqq$HLpq,m!6[mIhrrTcr"2lqrr2FMpm %hIArr[kFr`6qrr[JhS[ILr!%lr(prrkFr`6qr[rch)rI"0herrlqR2m%r[rli0k ,hi[`"1rarIrqR2m%r[lrmpb2h`6GpIrqrTcr"2lrqq$HLpq,m!6[mIhrrTcr"2l qrr2FMpm%hIArr[kFr`6qrr[JhS[ILr!%lr(prrkFr`6qr[rch)rI"0herrlqR2m %r[rli0k,hi[`"1rarIrqR2m%r[lrmpb2h`6GpIrqrTcr"2lrqq$HLpq,m!6[mIh rrTcr"2lqrr2FMpm%hIArr[kFr`6qrr[JhS[ILr!%lr(prrkFr`6qr[rch)rI"0h errlqR2m%r[rli0k,hi[`"1rarIrqR2m%r[lrmpb2h`6GpIrqrTcr"2lrqq$HLpq ,m!6[mIhrrTcr"2lqrr2FMpm%hIArr[kFr`6qrr[JhS[ILr!%lr(prrkFr`6qr[r ch)rI"0herrlqR2m%r[rli0k,hi[`"1rarIrqR2m%r[lrmpb2h`6GpIrqrTcr"2l rqq$HLpq,m!6[mIhrrTcr"2lqrr2FMpm%hIArr[kFr`6qrr[JhS[ILr!%lr(prrk Fr`6qr[rch)rI"0herrlqR2m%r[rli0k,hi[`"1rarIrqR2m%r[lrmpb2h`6GpIr qrTcr"2lrqq$HLpq,m!6[mIhrrTcr"2lqrr2FMpm%hI6rr[kFr`6qrr[JhS[ILr! %lr(prrkFr`6qr[rbh)rI"0herrlqR2m%r[rli0k,hi[`"1r`rIrqR2m'r[lrmGc IhShI"0hcrrlqQrm&r[lrqYrHLpq-m!6[qrrqrT[r"[lqrq[Fhpk,h`EHhpcYrrl qQrm%r[lrpGf-hiV`"Hr`l[ErrT[r"IlqrrhLhSrI!GhMJIkCr`IqrrlrkYcIhSV IM2!$lr$mrjhq"2r[h0rHMGm%hYrFmIqGrJ2rq0lHM0q,m!A[m1rbrIqErJ2rpGl HNGm$hYrfrj[q"IrliphIhS[IM2!(lr$[mIMqrrk9r`Iqrrh[hYlIhSrI"plIhYr br[rqPIm(r[lrpH,Ghpk-hih`"Zr`lq[Rm256p3MdpI2YipcHhpk4h`MHhplFj1l cpI56p3EdlqEGhGrHMGq1m!A[m2(Th0b9h3AFh0lIhpk6h`6HhprGh*IG"0cGhpr HMYq3!2!$lr(VhTMI!0k@h`$HRGm!hSrINI!'lr(UhYlIhT,I!0kEh`$HPpm!hT, IN[!'lr(UhYlIhZ(INr!'lr(UhYlIhZ$INr!(lqrakYlHhplIhj6`"qr[mHVHhYr HhYq9m!I[lr(UhYlIhYhIP[!(lqrakGhHhplFhjI`"qr[mHRGhprHfpqBm!I[lr( ThGrIhYVIQI!(lqrakGhIhplChjV`"qr[mHMGhprHf0qEm!I[lr$ShGrIhYIIR2! (lqrak0hIhpl@hjh`"qr[mHMGhprHeGm!ljh`"qr[mHIGhprHdpm!hTr`"qr[mHI GhprHdpm#lr$[RI!(lqr`jphIhpl3h`,HhZqJm!I[lr$RhGrIhXrI"GlIlqr`ljl `"qr[m1EGhprHc0m&hYrHhqr[SI!(lqr`jYhIhpl-h`,HhZ'#ljr`"1r[m1EGbpq "hJ(Ji)2[!I$[RI!'lqr`jGlIhXEI"plIhYrIiH(IJSEaK`''KiD'pBH$KJ+(KiE fK`@'KBD'KiEeK`''Ki#'!BH'piF$KSH'K[U(!BD'rBF!K[q(riIrKrq(riHMK`# 'QBF!KYf(!iD(L)LAK`1)L)H'fSF&KSL'Ihq$PB3&JRk!KiH'f)F'KSL#KDh5ijA P"Z(-TB+%L)E@K`H'L)#EjrrqrTAr"rlqrpb2JSL'e)F&KSL"R[MrQrd'rqb1K)H (KY1("B@*k[rmrjVq"rcrdAk*KSH'd)F(KSKqYrrmrrkCri$q"[q2IiQ'KiE3K`@ )JGhrrIkEr`Rqr2qdCSL(KSH'ciF&KSMXrrlqQrm+r[hrcf*cKSH'KiE1K`5&LZr rrTcr#rlprpKQDh+'KiD(KXf(")D+lrrqR2m-r[href9YDA+'KiD(KXb(")D+lrr qR2m0r[href9YE'PcKiH'KiE,K`5'LZrrrTcr$2lprpGPE@aXDA1(KiE-K`5'LZr rrTcr$IlprpGPE@aVE'PdKiH'biF%KSV[rrkFr`lqrIrAC@eXE'YXDA@(KSE+K`5 'LZrrrTcr$rlprpGPE@aXDfaXDA@)KSE*K`5'LZrrrTcr"IlprpGPEB"X"fYXE'P fL)D'b)F%KSV[rrkFr`AqrIrAC@f"E!GVE'aTGiL'KXH(")D+lrrqR2m&r[href9 YJQ`(DfaXDAL)KSE'K`5'LZrrrTcr"IlprpGPEB0X"fYXE'PiL)D'aBF%KSV[rrk Fr`AqrIrAC@f%E!GVE'aTHBL'KX5(")D+lrrqR2m&r[href9YK@`(DfaXDAQ)KSE $K`5'LZrrrTcr"IlprpGPEBCX"fYXE'PkL)D'`SF%KSV[rrkFr`AqrIrAC@f(E!9 VE'aUHiL!KX#(")D+lrrqR2m&r[href9YL'`)DfaXDRb)KSH'[iF%KSV[rrkFr`A qrIrAC@f*E!KVE'aUI)L'KiDqK`5'LZrrrTcr"IlprpGPEBTX#'YXDfTpL)D(KVf (")D+lrrqR2m&r[href9YLf`'DfaVDRk)KVq(")ARrrhqQrm&r[hrbf0YM'`)Dfa VDhk)KSH'ZiF%L(l1rrfEr`IqrrcrUQ&ZDiaX#'YXDfYrL)D(KVQ(#)D)JD(rrIl rrTIr"[lrr[rdH@L2E!KVE'YVIiL'KiDkK`L)J-[rr2hqrrk#riRqJ[m*r[rqrIc rU@*ZDipX#'YXDfZ!L)D(KVL("BD(KS69ri$qJ2m%r[rrrIb&r36mrIrqrS$rJ2i $rl9NEC*X#'YXDfb"L)D(KVL("SD(KB+hl[b!rJErr[rqr[rqJrm'r[rqr[rqri$ q"[VKPQ0XE'Z5E!KVE'YXJBL'KiDiK`H'KiH!JYMrrB$q"2hr`+#QJk82TTr'rrh rr[lprlGIC@eXDj4X#'YXDfb#L)D(KVL("BD)Jj[lri$q"2hri'CKK@)%B'VRrrf !rJ2rlA4VQ'`)DfaUEB1)KSH'Z)F%L)(Grrf!rJ6prj!!C(#&EJ4`BjMrrB$q"Ih r['&ZDjGX#'YXDQk$L)D(KV@($SD)IkhrrIlqrrhrb@0YDiCX$@ePd[rprrlqrrZ %CQeVPf`)DfaUES1)KSH'YBF$KSRXri(q"IrhI@GYDi9X$@YYCS2lrrlqrrhrdf9 YQ@`)DfaUES5)KSH'XSF1KSPq`Irprrlrr2qbB@jVKf`1DfjKZ[rmrrlqrIqDBQj VQ'`)DfaUEi5(KSH'X)F&KSL$PIRrJ2i%rIrREQU,E!0TFZhrJ2i%rIrREQZDE!K VE'T[KBH'KiD[K`k'L(r8rrhrr[lprjTLEQZ*E!jVEQ'Krrhqr[rmrl&KEQZCE!K VE'T`KBH'KiDYK`5'L)#Pri$q"Irprp4PEBjX!fIDrrf!rJArpheRE@ZCE!KVE'T `KBH'KiDZK`1&j[rpJ2i&rrb&C@eVLf`$DfeNLi(q"[rprmPMEQZDE!KVE'TaKSH 'KiDUK`k'LAkirrhqr[rmrleKEQZ0E!jVEQ,$rrcrr[lprj!!C'jVQQ`)DfaTFSD (KSH'USF$K)rdri(q!rr[G'Q4E!0SH22rJ2i$rIrIDCeX#'YXDA+'KiD(KUH($SD )IXcrrIrqr[hrT'&ZDipX$QYZBDVrr2rqr[hrTQ&ZDjYX"QYXDA1(KiDRK`1'L)' HJ[i$rIrGD*4X"'YViIrpJ2i$rr&eDCeX#'YXDA1(KiD(KUD(!i,Irrf"rJ6rMQ4 YDj&X$QYZBj2rrIlqrrcr[f&ZDjaX"QYXDA5(KiDNK`k'L(q`rrhqr[rprmGLEQZ 6E!CVE@2-rrhrJ2i%rBGPE@ZFE!CVE'PeKiD'T)F$KBVZri(q"IreHfGYDj0X$@Y YChlirrlqrrhreQCYR@`'DfaXDA@)KU+($SD*IX6rrIrqrrcrVf&ZDj9X$QYZBE2 rr2rqr[hrR@*ZDjaX"@YXE'PfL+'("BD)JTIkri$q"2hrj@eVQ@`%DQrSrrf!rJ2 rkA"URQ`%DfaXDR5KK`k'L)$Arrhrr[lprjKMEQZAE!jVEQ+Errhqr[rmrl9KEQZ GE!0VE'aUS)F0KSKrU2rpr[lrrIr4C'fEE!eYCG6rrIrqr[riIfGYDjeX!QYXE*+ (LSB&KiH'KZMrJIi&rrU$CQeVQ@`2DfePKIcrr[lrrIr-BfeVE)PVNQ`!Dj!!K`1 'KiL)L)N3L)YqZrrprrlqrIqmC("YE'ZAE!GVE'e`C,lrrB$q"2hrNQ4`Lfi"E'Z 3!'b1K`5'KiL%IiPq"(pkMrErJ2i+rIrRCepLC'YZE'Z6E"&VE'jUBf*HD1RrrIl qrIrLCPq+B34LD'jXDijXMBF'KSL&IT+`[iM#%m1qh[rqrrlqrIrCVVDXN@eLE@a VN@`6DfaYBQq8VEDZf[rpr[lrr[r*X,@)Y!DaQhKKDQeVM@b-K`H'L)1+b[RrrSM r"Ilrr[lrrS$r#rlqrrlqrqUIC'aXDipX#fYXDf@MlIrqr[rqrS$r"Ilrr[lrrSI r#2lqrrDlE@KYDiaXLiF'KSH$N!$Urrk,r32mrIrqJ2m#r[rqJ2`&rIlrZ@4YNQ` %CX2rr[f!r!Mqrrlrrrlqrrf,r!IprIrHF@PXDiYXMBF$KH$rr)lqK2q#rJEpr2q MBQjVM@`'DfjLX2rlrB,qJrq2rJ6lrmePEBaXLSF(KSKrX[rmrrkBr`EqrrhrlR* UMf`'D([frrlrrTMr"rlqr2q6C'eVLQb-K`5#h[rprTVr"rlqrIqGBQjVLf`(Dfj KUrrmrrkDr`Aqr2r*Bff,E)Z("B@-m[rqrT[r"[lmrlaKEQZ-E!9YBmRrrIkEr`A qrIrNDfZ,E)Z(")54q2rqR2m&r[craf*ZM@`&E@66rrhqR2m%r[rZF@U,E)Z(")5 4q2rqR2m&r[crb'0YM@`&E@66rrhqR2m%r[r[FQU,E)Z(")54q2rqR2m&r[crb'* ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")54q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m %r[r[FQU,E)Z(")54q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")5 4q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")54q2rqR2m&r[crb'* ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")54q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m %r[r[FQU,E)Z(")54q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")5 4q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")54q2rqR2m&r[crb'* ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")54q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m %r[r[FQU,E)Z(")54q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")5 4q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")54q2rqR2m&r[crb'* ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")54q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m %r[r[FQU,E)Z(")54q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")5 4q2rqR2m&r[crb'*ZM@`&E@66rrhqR2m%r[r[FQU,E)Z(")54q2rqR2m&r[crb'0 YM@`&E@66rrhqR2m%r[r[FQU,E)Z(")@0mrrqR2m&r[cr`@*ZM@`&E@2+rrhqQrm &r[hrk@jVLfb-K`5$i[rprT[r"[lmrkGKEQZ,E!CVEQ'arrcqQrm&r[hrdf9YLfb +K`H'L(kmrrcrrTRr"IlqrrGmCijX!feQK2b!rTRr"rlrr2qMBQjVLQb-K`5&LZc rr*Rq"rrqqrqjBQjVMQ`'E@2#rr[qrjRq"2cri@aVM'b,K`H'L)'Gq2rpr*Ep"[c mrIr6DQZ2E!GVE'TYfrrpr*Ip"rcprr'"CQeVLfb-K`H'L)#BiIrqrTAr"rlrqlY UD@eVMf`(DfeSEXEprrk9r`Iqr[rAI'9YDiaXMBF'KSL$IC@pd*A6"XUZJ'*VE@Z 4E!CVE@TMKE2-PG-'clQ2CQGYDieXMSF'KSH)Gf&MCC4N"@0KCfjXDj0X"@YXE@C KBj9N"@0KC'aYDijXMiF%KSD+J@b@E3*ZE@Z@E!0VE'eZPfd$EQeXDipXNBF%KSK rDfZ8E!"VQf`!DjGX!'Z5E*+("SD)IQYVE'[KE*1("SD)IQYVE'[JE*5("SD)IQY VE'[IE*1(#)D(KSKqDQYXDpjXP)F)KSH'L(eUDfaVh@b9K`L'KiD)I@TVE'[FE*D (#)D(KSKmDQYXDpYXPiF)KSH'L(aUE'aVfQbCK`H'KSKmDQaXDpPXQSF(KSD)HfT XE'[BE*Z("iD'L(YUE'aVefbFK`H'KSKlDQaXDpCXRBF(KSD)HQPXE'[9E*k("iD 'L(TTE'aVe'bIK`H'KSKjD@aXDp0X!)DIK`H'KSKjD@aXDp"X"'YVKSH'RSF(KSD )H@PXE'[2E!9VE)D'KiDHK`H'KSKiD@aXDmaX"@YXDfb&KU'("iD'L(KTE'aVc'` #Dfa[JSDIK`H'KSKiDQaXDmKXJ'X#E'jYJiB"KiDGK`D'KSKeDQaVb'`&DfaXF'p YJJ6`"3%%"BF%p3@$"!)&"36b"3)%"!@#"!%&"28&!33&J!3""36i"B!%!38%q38 !"2d&!!6r"Im&r`Ar"Im&S`8!"2S&"!3&#!J'P38%"JJ("36D"3)%"`5E!!)'"J6 B"3B%"`!(9k6'NmX)bX[#Q%8"!`B%eJ8("!F!-XrrrIk9r`Iqr[qi'`!("03&"`3 (!$Varr[lPr`(qr[rf"X!"J68"38#$GErq[qBrJMrr[RrU`!'"364"3F%#!"XrrV rrTRr#2lqr2mp!!F&"0%&"3B!Z[rmrT[r#2llriJ!#!3&"0!&"3-+fIrprT[r#Il lrl!!$!3%"362"33#$0rrrCcr#[lmrlm"$JN%"!8%cJ8%!J[IrrfFr`[qr2qq!3i -#33%"360"33#$0rrrCcr$2lmrli"$J`-#33%"36-"33#$0rrrCcr$Ilmrli"$J` ,$!N%"!8%b`8%!JcIrrfFr`lqr2qq!3i-#`X-#33%"36+"33#$0rrrCcr$rlmrli "$J`-#`X-#!3&"36*"33#$0rrrCcr"Ilmrli"$S!-"`X,$!J%"38%b!8%!JcIrrf Fr`Aqr2qq!3k"$!F,#``)"!8&"-F&"!)-hrrpR2m&r[cr[J%1JJ`(#`X-#!3&"36 '"33#$0rrrCcr"Ilmrli"$S--"`X,$!F%"38%a38%!JcIrrfFr`Aqr2qq!3k%$!F ,#``("!8&"-3&"!)-hrrpR2m&r[cr[J%1K3`(#`X-"`3&"36$"33#$0rrrCcr"Il mrli"$SB-"`X,$!F%"38%`J8%!JcIrrfFr`Aqr2qq!3k($!F,$!`("!8&"-%&"!) -hrrpR2m&r[cr[J%1L!`'#``-"`3&"-%&"!)-hrrpR2m&r[cr[J%1L3`'#``-"J3 &"-!&"!)-hrrpR2m&r[cr[J%1LJ`'#``-"J3&",m&"!),hrrpR2m&r[cr[J%1L`` '#``,"J3&",i&"3)-h[rprT[r"Ilmrli"$S`-"JX-#`B%"35q"33$c[rmrT[r"Il lrkN!$id-"JX-#`B%"35m"3B)!*[rqrrqQIm(r[rlrh-!$`Z0$!B,$!X'"!8%Z`8 ("`!rrrcqrrkAr`IqrrhrlL-'$Bm-"JX-#`B%"35l"3J(!*IrqIcqrrk#riRqJ[m *r[rqr2VrF3!2#j!!$!B,$!X&"!8%Z`8'"!@UrrhqrS$r!rlrrrb(q`2mrrlqJIm &r[hrKJ!0N``'#``,"33&",N&"J3'"!*VhIU!rJErr[rpr[rqJrm'r[rqrIrqri$ q"[M18`!0$!Z6$!B,$!X&"!8%Z38("!B'!!#`rrb!rJ6prjKMEB0V$feLSIrmrrl qqrq*!!31$!Z9$!B,$!X&"!8%Z38&"!F!-rMrJ2i$r2r-"B8!$3%!$GIrrIlqrIr K'JX0Q!`'#``+"33&",N&"!B!Z[rmJ2i%rIp+!"1&$`36!&Irr)$q"I[rN3!2#jJ -"JX-#J8%"35f"3i%#!"Drrcqr[rlrkF!$`Z'$!d1!EErr2rqr[rj03)1#jJ-"JX -#J8%"35f"33#$pRrrB$q"Irb+J30#i8-$3X1!M2irrlqrrcrZ!)1QJ`'#``+"33 &",-&$J3)!),rqrrqrr[rJ3!3#iF-$JX2!)lrqrrqr[cr@3!2#jN-"JX-#J8%"35 b"33'!#Rcri$q"2hrf"%+LJ`-$3JBi[rpr[lprpF4#TX-"JX-#J3%"35a"3d(!+M rqrrqr[cr@J!2#iN-$JX3!'Arqrlqrr[rJ!!3#jS-"JX-#J3%"35Z"3d%#!"*rrh qr[rmrlN#$Sd-"!d'`rrmJ2i&rr%T"!d,QJ`'#``+"!3&"+i&"!3(c2rmJ2i&rrS f!Ji,L``$#`i!3)(q"[rlrkB!$`ZE$!B,$!N%"!8%U`81"!J!F2rlr[lrqrq6!!m ,M3`1#`m!R2rlrrlqrIp*!!m,QJ`(#`X-#33%"35U"3d'!"cTrrhqr[hrj4X)$Bm -#`d')ZcrrIlqr2r,#Cd-"`X,$!N%"!8%U!81"!J!Q2rlrrlqqrpU!"!,M``1#a! !G2rlrrlqqrpZ!"!,Q``(#`X-#33%"35Q"33%"`!kr)(q!rcrb!L8$!`,#mrrr2l qrIrS(JF0R!`(#`X-#33&"35Q"33'!,lrr)$q"Ihr4J!2#j%-$JX2!%lrrIlqrr[ rPJ!2#j`-"`X,$!N%"!8%S`81"!J!Arrmr[lrqrqM!!m,N``'#`i!Urrlri$q"2X k!3i,R!`%#`X-#!5P"38'!K,Grrf!rJArlbF&$3Z6$!d,$J3Xmrrqr[rmrl`%$Ci -"!X,$!J%S`81"!J!Krrlrrlrqrpm!"!,P3`1#a!!Jrrlrrlqr2pH!!m,R3`%#`X -#!5K"38%"`!XpIq!rJ6prp82#TN-#`S5fIrpr[lprpX6#Cm-!`X,$!LL"3d(!+l rqrrqr[cr9J!2#jF-$JX2!&[rr2lqrr[rK3!3#ji-!JX,$+!&$33)!%lrr2lqrrc rY!%1Q``0$J+jrrcrr[lrp#d%$JZH$!%,#j-&L33'"38%#G$rr)$q"Iri-`)1#jN -$`X1!MEkrrlqrr[rU`!1#`b*#j)-!!Z4"3%'#)S*$`d!GIrlrrlqqrq3!!!6$J` ,P``(#``1%`#9rrZ!rJAprdd!%`q*%!)2$3Z3!!b1"3)%"JL,!")"!"rXrrhqr[h rf!i!!3!+$``,N``3#``2#3!"!"$Errhqr[crc`H-!!-'$``,MJb0"3F%"J3!(ee lJBH!%i*iZrrmrrlqrIr#HBGh5Jm!$J`,N3`6#``0!"02HBGj`rrpr[lrrIqRIB@ )K!Cq@b!!#Jd,M3b-"3J%"`!4NrArr[k(r`Aqrrlqrrk!r`[qr[rqr[rHB!!-$!Z 2$!X,$!X$D1,rr[lrr[k!r`Aqrrhqrrk(r`Mqr[raM`m($JZ-$)X&#!3'!"h8rrh mqiVk![crrS$r#rlrrIVlqrhprid"$C)-%35Grrhmqr[krIrqrrrqr[rlqSVl"rc prmJ@#!d,L`b-"38%"F(rqIf0rS6rJ[i'r2VrD!!2#id-"JX2!(lrqIb#rS2rM[i &rIRrV3)0M!b+"3J%#!"KrrVrr[kAr`EqrrhriaJ)MJ`($38QmIrprrkAri$q"I[ r63!1#iS-L`8&"J#mrrcqQ[m(r[llred!$`Z,$!F,$`"frr[rrTVr"IllrkB!$iX -L`8&!4,QrrhqQrm&r[[rN3!2M3`&$`#Rrr[qQrm&r[hrd`X,L`b+"38'!"[arrk Fr`AqqrqN!!q0$!81!,Irr2kFr`6prq39#BX-LJ8&"J!EmIrqR2m&r[[rT3!2M3` &$J#hrr[qR2m%rIrP&JQ,$)S&"3B!'r(rrTcr"Illrk8!$id-"3i!YrrlrTcr"2h rj4B*L`b+"38'!"[arrkFr`AqqrqP!!q0$!81!,IrqrkFr`6prq8@#BX-LJ8&"J! EmIrqR2m&r[[rT3!2M3`&$J#hrr[qR2m%rIrP&JQ,$)S&"3B!'r(rrTcr"Illrk8 !$id-"3i!YrrlrTcr"2hrj4B*L`b+"38'!"[arrkFr`AqqrqP!!q0$!81!,Irqrk Fr`6prq8@#BX-LJ8&"J!EmIrqR2m&r[[rT3!2M3`&$J#hrr[qR2m%rIrP&JQ,$)S &"3B!'r(rrTcr"Illrk8!$id-"3i!YrrlrTcr"2hrj4B*L`b+"38'!"[arrkFr`A qqrqP!!q0$!81!,IrqrkFr`6prq8@#BX-LJ8&"J!EmIrqR2m&r[[rT3!2M3`&$J# hrr[qR2m%rIrP&JQ,$)S&"3B!'r(rrTcr"Illrk8!$id-"3i!YrrlrTcr"2hrj4B *L`b+"38'!"[arrkFr`AqqrqP!!q0$!81!,IrqrkFr`6prq8@#BX-LJ8&"J!EmIr qR2m&r[[rT3!2M3`&$J#hrr[qR2m%rIrP&JQ,$)S&"3B!'r(rrTcr"Illrk8!$id -"3i!YrrlrTcr"2hrj4B*L`b+"38'!"[arrkFr`AqqrqP!!q0$!81!,IrqrkFr`6 prq8@#BX-LJ8&"J!EmIrqR2m&r[[rT3!2M3`&$J#hrr[qR2m%rIrP&JQ,$)S&"3B !'r(rrTcr"Illrk8!$id-"3i!YrrlrTcr"2hrj4B*L`b+"38'!"[arrkFr`Aqqrq P!!q0$!81!,IrqrkFr`6prq8@#BX-LJ8'"J%6k2rprT[r"IllrjS!$id-"3m!UIr lrT[r"IlprpX4#SX-M!8%!-6rr2kDr`Iqr[[rE`!2#i`-"Jm!I[rlr[kDr`Aqr2q h!3k,$)X&"JJ!G[rkrrkBri$q"2rc+!80M3`$$J-dqi(qQ2m(r[rkrfF!$`Z+$)X &"3B#%0RrqTRq"rrqqIq0!!m,MJ`'$J#ErrRqrjRq"2VrcJd+M!b,"38%"`!im2q Aq`Imqr[mrlB,#im-"3X-#4$%rjVl"[crjc!$$JZ,$)`&"`3(!$(0rrlqPIm(r[r jN!!,#!d,M``(#`d(%D,mrrk9r`Iqr[qq+!%2#i`-M38)"!F!"Nq8XVHfNEF)YVH SHLi!#`d,N3`)#`d*!$D$V,HfNEF)YVH`M%F%"3i,M3b1"3)%"`5D!!-%$``,N`` $#`d1!jN!!`%0$JZ1$)m&!`3&"`U@$J-2$`d,PJ`%#``1$`q@$J-2$J`,M`b3!!8 %"!8%"JZ9$!!,c!b4"3B%"33'#``,iJb5"3B%"33'#``,i3b6"3B%"33'#``,i!b 8"3B%"33'#``,h`b9"3B%"33'#``,hJb@"3B%"33'#``,h3bA"3B%"33'$!`,h!b B"3B%"33'$!`,f`bC"3B%"33'$!`,fJbC"3F%"!8%"``-#pN-QJ8("!8&"!F-$![ B$*X&"`3&"33($!`,e`bF"3F%"38%"``-#pB-R38("!8&"!F-#`[8$!!,RJ8("!8 &"!F-#`[8$!!%RJ8("!8&"!F-#`[4$!3,#`3&"*d&"`3&"33($!X,cJ`(#``,#`3 %"35G"3F%"38%"``,#m`-#3X,$!X,"!3&"35G"3F%"38%"``-#md-!JX,#S%%R`8 %"!8&"!H!#mN-J3X"#3U$"!%&"*`&"`3&"33)$!X,aJ`"#`b!#`)+#JYd1'eV!!" !#!)!,kl`r[lqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlqrZUH)!!#!%lhrrlrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrqrIrU1J!`mIrlr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqr[rqqrr J'UMrqrrqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlrq[q+krrqr[rrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrlprp2prrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[l rjIlrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rNr[rrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrqArrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rjIlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rPr[rqrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrlqrq6pr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[l rjHMrr[lrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrIr3R[rkrrlqrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrqr[rkri%MjIrlrIlqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[l qr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[l qr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lqr[lpq[r @%J!kj[rpr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[hrfbS!!J!CLG2Pj1APjHAPjHA PjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHA PjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHA PjHAPjHAPjHAPjH6QeB36!!*TBc!i!!"(9`!!!!aU8#!J$3U(#J!!!"4QG(P`DR! b)!!!!!"UF$)J!!!!6fT`-QJ!!!!@D@KNFJ!!!3!!!!%!!!3("`!!!!!!$f0[E() "!!!!!!!3!!!!)Q0NC@B!"!!!!!!!!3!$!!%!!!!"!!!!!J!#!!!!!`!!!!"UF$* Mrdrr83!b!!!!!!%!!!!"!!!!!!!!!!!!!!!"!!!!!3!!!!!!!!!!!!!%"`%""`% ""`%""`%"rf3!)`!"3h*PBA4[FMSJ5Q&c8'9b)&CPFR0TEfiJ-5ij-$!Z-Ip5!!` !!!!"!!8%"!!"re`!%d"!5%K35%K35%K35%K35%K3red!&!&!3%K)8%K)8%K)8%K )8%K)82pG!"3#3%")5&")5&")5&")5&")5&$rA3!8!d"!5%K35%K35%K35%K35%K 3rj!!!!S!!!!!4KB!!Iq6hi(J+,Rr8C9,jFer0'R4#2@b-5RKCM1p3pC5C2[m2Hr Q-Ep8r`m[IMCiFbmL$AI*Fhk,EcGF!4[J"LM&Bmr(hi)!)iNXSG042IGi+YPUC*! !6CL'Q6Kb5[)5Ll-Bfd1D!1q!IXM)dcE0S%e+PF1p@PS$[Z%bp3FJq@5kA6#pj`6 %XZIIJNJDkp!UD5%+ZM6fVeh1ckE(Y5kY01GEXJJ,RPG"Il'),c*H!KTUmSS"m&( !0[B55(5820HedQ'`'p6IFfcD+*eHIQUfc8cf3hVchi$3$q[4X1Q4kdcXUB0U"KJ iii)NrdYiV8Ph&N["mkH$jdm$je3T@IPk31Yq,Y-2-pbad%qd)aKBAq4eZ9E*IFA `Lh$AGKP#'!dqHI0)"09q!P,d06p1j5ZeBepH@GK1VUGRJ4Dj338k2(+qNP#U+X2 N'VmIEalCH,bR0#&+K[dN)$fj%Ip4TE8(V8'4Kp*$0[Zfe+B`#Z-`@K!LURr(fQm IDEaq"`!G`I8NkmZ1"ea+AX!+T*CeCPaR"iq&r8$0%p3!bcH4R(h%C#dVpl`pMlb &fHTPeGQ-L&3m(1Q(*THb6PkQ"p@rehq4Vp6B(,N%eGb`0Ih5Jm"*ZAeqAP"Nk8L 3!,TG$J&hTp`a-*2drT43RT!!rb*l*,KYLfEBcZcAp"aq6(2Z+Mp11H#"6f4m[SC b2kMm"He"#k1a(SF+,UZVAcK,iIC'&8-9!ZibDJ[2`2*q"h(i(B!G`I8QNGHkP5a ,b9A120!r&@ITBMI-)k`Q&06JHK4IMB"qe%j)a,K-X![FDQa6*llDD9F&mNaBQrP NZjmQZHUm`-fpR&d-2BDX,"Df[SpbiPD%![q$59b3!2HBD1kZ&TTa5)1dUllbYUD `))#c9Zf!ed"4NrL1[(mIEamFf'mE,Nqr4@L'!HG0fC3"kKZ3!%T9E(@*er2h*+# 5&[!lC3e$&arNlM%C4PCr)(5CJ+jBFqCcE'r(fK-ID%`qd)!8jm6RQq"&NMm8k"F GFaGY!bm5blI#LI6T2m(ceU$jkG!qHSK)ZcM)FK-US8rS1k`,h(e%+,@d(JZ2NV6 NLCkXLZfp1H%@pT@@Ci"XC$V63!ilV-S6LUVl`r-BH!)hQZ4V!&X0(hNhbh,Pch% 4Ic($bDeKBDHT-`C!+GBm-4q$S6BT`RR)J`3H3D09SHQ5(r3+MZ!0'YiS@3MN,l# 1H01Dm+R&'kX"jc4r-G"'U[2+8!c,BbMf+QMr5%3fp#T'[CH%TKSKCQ*0f"DQel5 "kRQLpL(Cbadb$lUSSpp@pb"54qH"G$"R$Gq#FaQ0ENl9XTa%K+M*$,cml49%TIG Yrcm"j&8&N!#`!V'ZL9(G@8iI6dY,4S(bahJY$Nm+SVQUapY!apVe$lAS5,H0bQi (cH%Q3@!R*3HA-eD2a3+!R1S5+S&#p(a1!JZ)E6r'kUS6M$T$$`QiLdk,l4clALd Fl"0rKc"r'm[p3f(S2`bDBKcK+"SMUr,XF6Fkk,#XbXD[&-)YiFe0q-`cN!!pm6e EaK+U`JVr05fRZ(9bGR%YGI%a8,p(U!I2SYq8ic5e)pI,liPPLD-5$P`T'%DNL"X qrJT"Jkk86k%dZ5eNe8SJpdRFEXKTbZNL)8+*MbNB[GNhTZiTCkJ1!"fQ)KK`83d RH#X0lj`1%rZ@5JZ1AT5%4Dm6X1jaaq9TZ5dr0LCU+-GEB(9%El#*E#J5ei[LH&Q E6X,a51'jJHYBDHAr#ZC)5fMd2ZGX%2T0ANTk-h3*)QR*l2A`$C`&B4!hA9R!*d5 *Fj8+'pKJje&NBQb6R,"r)R&+,eVLiE9`Tf6j&h2#f05d3%l3eaHe42%@B(S!k2S (#TVD$AE*Y`%8-jD'"HrNkcd,&%6klR3"X!XNjq"9rhr2`SkIK3dIK3")Yih9NYq raGJ4H%mUPQ$dbS(*jMf)ZcLaB(P#j(H&@bL&5#dlFI[dN9C*lEH2!PebSGkd#Jp 4G*E6lS%M&F!LXh4Jm)D4d+I!aQr[rcK'Sj(@%(*MB93@`NVQ8X`p0-HdeSjZB9# RrUX!J[15''H%[0krNLJNFP(pdaZ([f`NqRb'hEqUlmdm89[[A"-[0,8Mem[[L@@ +&K'B6&[XRJ49`,(dS-U4*!&c`REZ+fqe+$&fC'k#dejZq2(i!(2LN48'UfB`[LK cpAi(d#2mXLD48B5B3GF["&M9GIa(U"2*rhJ+A'MZFaZM5[)"Y8JDFq*-Im*FiBK -f+hd!FdQ9V&iG!2M3JNC$68pKKRPNf4rV-l'69q"keKjlMI6Ll631%Mm6Z%CQKK LDbfJQCk%R22AjAG8VrI#c*TG,T!!-0$)LJLU9VCdFS",Ijf6b'QYN8,2X'D6V*k UX88E3[`+jlTEQlMCK2Zk@J*AAIXl'kNN%1d(0RmXS2m8kr$(H`l%2DeJ(*2NBT! !91I3YEiihfXp3%AS5Vercm"+IJ*3I8'!&1L%0U3(rL93e-q1mIY%91f2&1L&8I3 &1HTHDB2++F4ecal-%VTGqXKdKH,ECp,2`I2V'$jp-`2Rdf#L($DiTP,8RrISGKN bqJGDBPNVI'EX)bSjPZI4)T+`kkPI8C8+(3Il%C9@2fm"q4AdS[6$TS),FihU58T @"3B$$RU436(J#Cj$Q9)S+q6VKMbbF4NVXekU500U`MJbEB0J3l'qLDq21)c38aP S+BR0p1MEi0R,VV6kC$5QE34@Ic2Z9q@Lr%'lS+B-9h)l5D$q6e'`ANHF)H*S`$& bahq&VrlM5!2S2bTj0M4CM'(%1,qqU`ff&h%dj6+IG[-dJ(E83VBX)r8bqJZfcZq 4&*GHp3jUSV,Hq&KRjqqTK)jVapaH3'fA"VRh(J91HhA@)0$BhU`Q6ckjD3LA)&0 rCdmiTc"3S!F%*NehSIR@K0f[c%4hD$3p9Ilr-f0XZ9@e&"TINL"[i5f)Fr1-#!9 H'GZq32J%1j!!91SI3Q`4irK%'j!!U)4&f#q3!-H5dQ1P)NSKe2T@fhR)cLp*"XN bE61G,*08SEIa)&GGiU6SIpbGLXMk-S"pX61@Xa,XJ3RjC1Z#JAcjTDKHj2&K,De T![NbCV"XE2fqK&hY*%ZGUI3`*DjNThlZr'P'MM6XhK(58NGVZUGDErR[1ILh)Z, 'KH#Q2Y8,ZYha30N`Q88HNFJe'94-0Z!Nr15)T(VU*hM3AcM$-#Mkrd6djmIES6( fh[(iA)#Ad5!hUGI5%+hqAaVJc0EfjQLJN!$*#+hM)m!0$X0C&hd+f03m)GR1q$% R-ajr`c%*"2#Y6-3Dqih`E!LBa)4"H2Y)63-)##+cVV029LA6a'c"J%GqX*M1alr [ef51(dUYQ#J9'LLmK*64[1,2BfCi0V2L3BBT*UJ"&jPMdEaT5HmG13*mld6TQ6a fb)QF"8BF4rI#Gb#$X%9X"k)%&jXhVImR[R%e+[!C!f!IIkKMmT%ca&DcmBh6Y`* )IT9`XE@#V3UE'rY`"i@"0(m69jp(aRI"IY"I(+pbFG`PX)#@HdfBb,Q1D3Zi84F fi2bAcbaNmBN#fp+LC4R@JhI,QJ'2C3pSBAkce1!f[eJ(GLkU0R%Sh@-cBl%&)@J *541CSekX,"KBP3H$$V8-@X`UY4lXZm'GJfmPV#ke,5G,hP%0+YliTHCH2VqL'rV j3L`4X8j))mLeAdQk2(&[FF@M`b+Z6(U#G@F*Hq[RFm5'$L8qa21P2p6&cGi@L@m qfDUr[Y%TdZ2J[SYIF,Xebd&G5R'LTTRV$Zc,!FlaU!*DI!6f+KFD4J!$Hq%@08B 3Zf5i1elaY1CCqIAE&Z$APjV'@d2QkLHNB)PM#Q`l",`RaX`3,`UMY-@("$9G#S& *$-jrpL8RD9aA!l&!'Y-XY#8H61ri!leCb36Pb#@KTcH2a[m@1$r4k,"83LD(A*D 5"efb,R-f+9FK+qNY)aGfBl3)$D*EYC54@8HbV,++G`&fiC!!!9CAm08Q!I"heiP BR"3Emc1Nji&B+LkG4BZAKid'a%HkYBJSb0j6ref)ii9IEXZ#1E+ph)CfkNS""&Q H$T[Yd`b3!1rXN!!KLeJI1rCc3aQplS6JljV[a[QEha$%)"2V5MANL'V5&RcHTmC NM9iqYM4(p*DK@Z`K`(Pf9Qr!Y[[I-`[PJbYX)M#pj0m%+D5-SA!V6#0IM[,qXKq )e@Gd)@JD9+LMf4@&m02Ehb,piSPBdB6R$p,+($r2`dBRiAh(iAQ!Pp(S(r)2'Ur ZkK8r[GU,BRINGR!&$N!ea9TaNhHEQHG#jR#ZYNR)$*RUQ%dDLGljcUe4(R*,%PH $IKBBBpPq(aCS'd!+q5X0-CJD1&")qll&G2-@fQYD`5YjS9aBP)RS*2KarBK#GL@ l+J@3!-4,(DAKK8(F(F"6U1(Ge*QfBiP[&"YG(V-IXdik*6)QH,+)&iq0"6a0h)* Pq8SfP,HpZGme4H(IqmZTUN%ViY#ES%U-G[XEX@p5"%!jl!"hq)m6NQRm[a%BlB$ h#Ii1)ZQ%'+32,(-["b5MC)aAHk9q*Xjd-VkK'aZIBE!D!45HVr'jiRiHR*)%FI# #Bi+`@TY3qTT8G1bc@RY8F"M2T-BPTDAeblfCN!#pA4II@!Gf,USfF5MGBc0MX38 KNj`1kPiMJEH#i`h!4#5K9$`Sf%FP@MV*)A,G!hYaNHlM8EXIP[kkP,+i@#mJ5lB kMI+b`U#9[Gk1+*V@BpE0lBF2iVK2@hFGjSDbF-25'6e2TS1h'6NAUGfJ1E`d8VE GdAJ#$AaZ*$)jTqTlUr3hKGDY3(EJlPpFfD-%C5`-0-F$AC81!jYPCIaQ&VcVTR2 3PHQCSeP[RmP[AYLEZ["MQ0R8M)P*pBiXcJBliULZmpCp3rm,cFLr*`(KKdTIVB[ j`#*SfE`bkB+Rcdi&hD%E[c'YX311%jIiQY6p@ZqU+LA5i!BSXajicUrDQNHKSiF 'SGdpSBHQ53`cdJI-ecT[NG2&eL`k9+r$e"`6F4la5"52'%FLL1)0SFKM[lLDK,8 ZbEFDUKEZT`@QJ1(*([C%j08cG8GX8$Q$%jQUj6iB(Yr%EU1V#5lR&2m1TT!!cq5 -D@JIIKHEb0V+F*!!lDGX%e$6P"!k`di,IN!P2S%i9QV8D+mP6AE!&aA&C5hFAZE VH"(ALC!!Ci*"ACP6)qG2(f6UR&5jlUfRfK5jkJFf5dc'%&ZNGJmSHSGeB"CEiG- QkSM,SLX1'`M!Z2aqh&@C,fP0Tia`jq0X6!i"(-fbAUcS,Vk"&*GabjMjA5VQQer @Q(r2`(jq"$(i#S#,5m('ZR5Qd(+klb3MNp*5b8!fl[6XmF1RDdGh@m'riB`a$fc N280D-!PHD)"pNe34-RA8mr!$ST`%L80#q#mQ&B(QTcNT4rD+pfSSSRHM`fhhM!h V`I2eCJqIU(!qIT`!el*1[c@MM@a(AD![&ENV252-!F4FP15f0i,cRkf!hFZ[6VY JkclLc@ie+K4`Th!6qfBaX,IEhqq8bpT`#'"cc8Y8$`di-a23pYi[m`[*6iFJlEA KfEaTZa+-G,-"qj!!KZUbH5i8a,8fSMTh`-Mp3XT&dSVq!UF+-ZANH4VSr'dGded Bf'cc!FT4HFN@Yf"lGcZcj#FAl"dLbke1Ak@YQ%hZ#J`%8VeHBK[4pe+0,N(i2B, Mf@BVTXLdcfHdpQ6G1@%LbL2#e'cr94'%rJ3VV'33KT-%'%B6dH9CkQ(14E@e$CD DC5'LEADDR*!!+Mk[U)cA9$r2KBSFVT+M$hiYUUCb4HY29-eA6!PSRCFmbU)Bb3e Kp1kGmX-AiQEm!kSF3H"DGBL,T[La"Jc+8P@k3-5LRqd5cbb&3*GI#U1`k%@1$em ieDr`Rfa[V[mKVZ$'LQIPYR,kM$h$9M[U8+F*@!4,qSpdkU5jHibbe0eJ#l0hJQ, M3DUflhdmFfZ)m0DlAmr8cajEDHZZpDkCM&YQ5B,E[ZH#"MJb0cK`$d#d,#(DaJ! -Q3M`B@*r3l43U0UQ-#*XprYaAkLhcrHVeYPmmk1bhKp)F8ERGF%p!aXrc+p!YpC D6J1r(ISf2%fGUEXaZj1Ea,@dC5j-HZ9FfJbI"(JIrZEc15pc0+'Z#3h8E#'p%5d f#bh+0l*6ZER!3XLNdBl+m64'Jremr1HG*Hb(*f[QK$UR3G-3HF+*U'LjRe"9P&) $eCIZd2PUMV6!F6G-Z6e0`%(c3#&'@lR8bC)a%6H[ar[4&Z`llXlQ2kX#II#bbB- (QeUPd$Sb8+cbF#`Ca(DY!'$i`"RqMa1Y`![Dm$+CCM@(YlUYeN4lV#r!4D+jBA" K-L,)L5(66RJBTpH0'`q[#Eh(+3!GC)EbN!"65ZRbrbD!dh#L1f*cU0X#MXPH!B9 j1kP0J6YH%eXSIiE"X6"SN8c($D"04"U#!A&r2Prd0pI*rK0,k%4FcM([XZNp1!E H(KpI)cS['dS8aUUX0ERPqq6F`Zq"k`Apfl'$qYaq!l-,+Z*X@dV3c0p%84+8V&j LTHaq$6ceDRhr'@L9J($XS-6S-9NM",&$j"R$#4BSZ@6@mlp,(,E$V@e9)J0@*H' M39[[NZ6lZjNE6JJ"GShQm98MS#QMFaEm5`V,0ch-!hUd(4`'JQ5a5GCFHLjpNBS F`jqXMkP[f6)+"fVqE&h@K[pam!hrBTZ29iRq5p!1!3DQ1ENq'3#b%DHT)i59hYH $K6qHEI63%bIJV%@NeX'jbAR9hIPk!4E,&V%dPiHIBkZ9N!!CapZrmIE[Y$lGZpH b6VmX`JN1%E2VUXfH$J*L8j0@DeeiRq*GIFFILU-k8F2[U0jrrB+@UX2r*aI8Z*k Ij!$T[1@'*j!!E6Er+iFTcH1fk5$MefMccdE8Kf3',U*JIDBlG#ZZ`%RN[hT'+b8 (5#IlJRVj4,KZZ+k"%*jI!dEF-'+&X!9Qa!"P8[3&L'+c*Hla%FHQ'%k!!JSG+Al dVX8&,#&CBBjj)CMU9VNZJa"T'CRG-fHjfLC3M2-+G3&`MGh$IGXbPI%ldiR58ZJ 0P`PpR(d4AKa"UAAq")QB,#3VPEMU8K9Nk@PL4'TN8I[r(aTPda5)XHBlp6Z8lce !c&-0!ChI3a,m5`ZDr$-3N!!EMC*HLli@@H!$#M5Pp`K0cG634rmJpV51Cq8BGhB &PTiIMhqEl'STq"K*+-p#5jSI(A#,%2GaHmd(k#51E*ZE2%Bi#D)PpBAF`p6dL-1 Z$TPeE"@BFGakMN2l,8[BqEb#a"Q[$%E*B2T@'6Je[hjj(9XEI1)kYYKHN5r6-HF @p@`$[%'3!%XQQMpUY#Mpma&Ik`h`8PikLNkXTB@T4iQDpD,NPLK&Jq1USRZr""B )f`Qj%DIjF,dNKpj`RTVA9ml@**-$)TQfCf[r5Va+2-M5P&qAZk#kD-))31TN8Q9 kd)BJ55RYrbD[i@+IGm#QYBb*YhZBj0U[Q0h2SSY@B,6'$m!V'plb9kXZ[)iK4M% 0qfHBQ)d3AILp'FA-a[K5BmRQUJ%)"b*NdGqKiP`NIm'KRFKHiIk2NA@E!MYrNjf CNfF0VA0cr18(P#4Npd5Rm@-SR+ES"lDQcT2'"r4pJHedlZ9SFeSr8hY3Ym'BXJk MCQDb*F%%+0$TC9YjeVS@0*rqeB9iZcE2T&DIILhjfh%&3fMa!cK24QT`qC5A0AY G3E*BVD%#b2[%#SfN5N3VjM*G'SFZK+6-'eVp''!!`Ri%EL*C'k'qeC1'!Br@di` bT#lpG6bMCLSIi[mrVTBm*IQ2!$`N2!lMl6%l,riHIC8Xe+M5Gi9@5$+C0dCDP8Q 0L1*C3UBpE1@JEQJEBJd+[YlPpjR"+XlmLqXJZ`,&2AlP5eBaBR5IpXqrCqZS*GD p8HDkaL!b@)UQmY[E(AVblEESq+#SM3F*!NAHl)iDhh"FJdTBHe["cYEAZJTLqm+ (!E36@HQ%iB*fh9Z)H-EiFFc9ke!Aj4Cb!b1jb[((0#HPZTK!`Zap8%,8XKlcDH$ m$NM'f41"&L86jED83G!J&VAVafYEl,-5Ub(%JXd2[Yh9QKZfCKN(@KA$ZZ"5#%N GAY"4iNd0+p*2-#HbN9L*U4h)"iUFGV+RSlF+*eV4$rJ@AShr#GKf"HlcTQ$VlDi Qcjj'C%U[eeB5RHm9iT,KJ!G!M3bSkR%#rDjY[`YLeMGrLl[djX4L3VXBSM!1&Uk CR+mEh8%hBK#*e![V2cZiH&m(5Pej3r"Bhj[*G4+PfEiIA3F"QX0eQEKCpRkk)$q ,Uk#6[B$`bLC3U1HJ+DJl*RS&mFL"U&55jZj9mQFl@HME(5dLJIIZMa(fI8Ib5dr 3FH8*ZCTfa!pqUc%%648a#Ke@hBRlaYH#m4%NERH5Y%1jCdjFmITCqPAa#&f@KUI I6JpmX[l&1ap@%h%qYHHS9RH)`#+3!'[hb,iX%J'BRr,kb*0k`0i'IK'[JP49iUi c#ID)Gf48pdGh0J'r#9qldD$3'NcRi3LQF&%[$J($'SrhS'V1()8fkqSXqhGf%m, VSYBPlB3Jkqraf&!iY#[45EpYdGep*SqNN!#qDJrf-BX'bYrhXpa$k[6IJFHcmP1 Af$j&JlJF3ZGNmre*E(-Ul,8&DaBj$X+qPi-I2VaqLbBJR9qZJbEq6YkH"jTb(+( #Z`S+0K,V&LfjEb8'f+fm82m&A#FSe41b2'09@jKI5-p4-[e1L%XUIKDiBhXTc6D T0Nq6R(#fAYGAUbNA*@l0qmFeImr$SBRiG$NIKZ@!ekL#ITXK!dfNiE*dCh[c$N( I[aZ%Heaia9*!YM&!$P&BNRlFCA@c6r!Hhdi+'R3KkTb!XS!I9*@D"i1IL5%XK+L MSH8l!6I")["Hma'bjQ,e&cM+&jIBNMJ@2CDdVrkmZLXqJ8&&lDTAmc'%UPmr'Z' ,eXfm(!`aN!!R(NQkp%qMBFe'd92BP8`%"$JR*"ciIKNR`TQP*R1p"N4phR(3-SS J$#C*M0qVQU*!FjA(MbUZ2i-EG,je+[(FrETcmLH&H#l)l@JK#aMR-[)1%,m2i4" )PPlT!563hCI2ql9hhPlY0)3V&)+%lY`Fic0p(Yq'XZ[X&j5['$R,rb2e@R#!P"U i"H5'!bY&NDIeh*9H4qhQ&Vhc$dKh@LYm'5XAFHlX(JR1[Y0EKG2Y$)5D1ZpdQK' M2NDp8$alTr%I5*U'`BcVj05(JT1`Y3e`,6#DC'NM6Ch'Uq&)%P1p0FI@+'SY5BN [f1SF*S*NX@Z%*JRDFJ[Mr'ETrV*0UM!f,YbaJNDBVIBVJ3*"PUXp`i)Nc%C2bSR 8ip+5Y"QE)*r@Y,J'['4j5@jqS!f9hZk#KUYcm2KrIeeZkQD"e)l6HAHf,&5"m&$ (h1fH#0MADP@QcdMF(83!+qf4,mD3!*fP)kU(h%KZrArMlMd6Ve(YTUJ92ES9P0b 3!,9mqb3'"D%rp*M,NmAQbcMSl+Sb0i1,U,F#-Z4Y"`--QY[(P6P)*Kr'$m!V'qr hCB9Mh!Y+bf!ISJ[qHc2M$ZDb6cGp"q(FUR268VQK(UR@E'RLi2B"fL8%10"ca$" FK[#LXhE(-j`TN!"3PjYG0cJeLPJHGXN-B'GCfkN8ClPk$rNb3P&NG+%mq0YSd@c kdTRCR'5Z!d&5bjeL+NA+N!!1"ha(+EUXrK`J2+UP0QLTp@)&DhFUc3LqqP3&UY& 2r,Qkebh$*1(fFB6+d--'fXDGlpE[1FH)2V(@@hh@c$00bV$Vqj9c8Tfk[NSXb'C Zek1`V-pJCq&IZ-mm,,S-R3qaZK*LhE`DQq8GlFQaab0[p4Vq4&"E1Y9SYGT5)Z8 jCm!1R1cKM#H1`5qGdUIBYRq##BTLH&E'aDE@I@!Qe5`hNSbTciBdBK%!UH!id'J !rTbZlQPSdiQE2K4VBR4H$N6E'hTMJ$@GGXCmrY,GLa-,eIVSXL@%$rLG'Da4Nee aHC(M#9j!h-5VT4"YIJj,l3C(8%-FILmTlF1JK1c@`!HpKciE2Z*J198M#KA'$9+ HQidkXi'N#AR@rCZj-!NRAVqiQmCeKC-UTZe@ib*YIUSBFF@dTE+F#j!!@hVDPBS 86h[cP1I"(5)!2QNU`S82CT4XScq()C)2UlpDf3E@XPN!RV56D*SZSc,af3Ar*8U [KZ)PY'k(,Fp`#)mGAr,#QA6Z#CMK8#ZG4Hr0j`ADJDM6,GR#d'YfpJb2)28McVl NaR+jM)mAF'IA9K+H'03%$Kqh*0flHIcF-@1D`I(8ppKEP3"P*)6j@1F'+rYFh@) +NY)08Fh+4K8#U$N`AH@Y8(e&bU12"aLiG&6mmMe23T99BBbB4q3`ZB9U"LZr-qK $Q)Xr*bQI#FBR!ZDU%QP39@lc$X!)TYaAHq2HpRdG3V2Q5Y'S)H'KU,eqLrKG5B6 jIdN)P,NCaGhB,C0F#6`AUqrXRdQm!lCS-26G8*qrNX!-B`SI)B)FQJ+kT"h8$ML VFASeeX'TNI1FIH#,HhrZ5(`bm*e`#piMVGYE"cIBbBr5HYeMUhJPk9@Af-V5*&e JCSS+E-EAd@NMF,`38f-f#DGh&Tj!YBBb5NQ15iL&TTZlG,8ST$r'0'A)r40Z+@j Z%@@86cR$CU9Ik6K)P1If'`er"*@4bX![QbdM-RPF[XLIRP"I%4#"U5MDZC5$dIP dKf#JcVcFdDY)h96H0S,&UY98*$pem3G,Fk@HeIjlJdeG(QU9pr*)d4ATbG"'aY' Edq*-`13(8[Skeh)jX&!r1q63VE&UTqEN`Rb!YIh@X`&2`(VeR"(r#FlQXcJLf5q [RQ6d#9jh`d(MdXpF,iZmq*L9T*BR*L,E6C4BS,iCX2"),!22`3Cq"p(i%J#Y"PQ R6Kk!Je3R*KMrGY)D8BSJ*QV3`(HDqZdMJ!lqMY#GKPa!GSp'MSrY2'r!cd1)Q1k 'ra[pB,TS%e%K')'k[rK48kELmEkGZNrX+9RTK+2ei9*F,b&j2rp$Tme`bF4rAkJ m8IHEM[K&'(hUk86q)6bZ'V@2NTP-hh1SK(4I%Xk3!-!I3+[5`j'ifQ0(#-d[U5H #c4*&r&r+4X(fY-BpU%Q2Iq%q66YmqpjmQf[e@MK2NdP2Nk!6j0frUX$"2Nd(2Nk 06j0TrUUSpVlE5H4fDDGPH6&),E*+B6#@KQa(Y$%"`l#E@2eSrh-rL5GCpq,G6"k )M$iTEMDq"KV6Rq3L+4",VLm1fP)cS@+"ILbUHKhd#VFAS&AS(QAA&+U4XeejDk) &,rR`afDP-D5*2E&*@2X,ffP4RIX"9jfjVHd8"64"k55qL4IhB&h!&B"eHj1*Q0b PC0b#``16'-""@K,@%*GXZk(J&HM[MRPh*Em9CP`A-j!!'ZGFeFQMr'Ck!#AKTj! !5#'LQ+e4E3JLX(d-h6Af9j`#hk[$V@RVDbGr3-r#m&49HC2XQIV"[S9BpG,6X+K PkI3@*X2YrRA3Jl,6FSHa&AV!aYBaJXcU&,9)+ir@!B0'36p2@@Y`mJ6Hik))j[4 5"R&#[UThqLE(I#XbVf6'dC&HZiNTF+`A&@+BR`elL)4qPcfJ4m*KER#Qih$pY+Q i)'K#Q[a104r4,,3BX-h6dR8PVJ6fJ$&1cY6@amQlI)M[5Pb8d)#dV"rd8%NM&8* 2[Z81M#9M%Vfb(`CjK8@4l6rbFd4DIFRI&(cb-j`"%f#2DF5+dFbbmA(15#Y@k`H Z-'P$+1ZbBFEKMGJeKJSh!PV!394#2rA9F4eP5KkI6M%9U,8RKU6XLXjSFc$DB*T iHXPkT,1@Zrh&i0k9i"IMhm`CcDc`*TeGc3MAMHLE`qkNqRR"AV4Dj+5jAAD`P'e R+$1YSZlICpHBkb+E[M-VNSHk2iiURT3$3*SFMpEp@9LRI%5eqPl)6`,98Md`1#F r9Ck)X4@V0kY0!58-9KRpC&ZQU%Eh[h(Ja`pieI!mG-mASG$`MCD8I98ke33eQ4X fHmCe63Grq*JdlaDS+KK32)lNc1Brl#E`E0hA`Dmq6hZGLUiSD$,H2rlpM8B3L4d +HqFV#-rHKQQA3'2CrPi5qEH8fc6qI&RD&qlYHNZA5-KflNAC)$N*`lpSXmZAYPl a"k$G+%9c',DS"*T8LUZ,f&rE0r$!Uf-R4,2-4R81+A&B-KB'VNR4qDJ(qDqI05P SP5I#cd*4mr6ajQ0XMMdfqVMrIrM&1R2S-3B%FD@N'%hUQpIpPFjDJF6Cl`pKBGh EjKZ-e9aF0Y3dSebSPFT@Em#PYGJq"VreV0UEckSC99!(I2F5IF+ePE*Fa9[`Ll9 L,H+IJ*!!L51X!YrmL"U$R!Gf`q&X6S%3*qkIT&hYU0I*1!-$%N[q5@%rG3XUCd2 "NBEYf[5i[c'C8idQR5Q(Ra5%cqqNk2R4@9U!j@$rA@!@fh[b(YH+rKMimEQSUKd IT+J+5RK@h1a#9BD!kmFB@ZSH!FkSr"@%5DhdRkSLhV%3%[FfGjh8+S%0SG[L-Zk MhdeM#mX,J-H3!2HF0bh!LGr%m%8+%Z3,8F!9mFQdCl9`QV&XI+q6QL8SdhfAL)b [Nq2H5'kd@KCI%D'9mh&+[LTf8i`,A%f0DN!`HCE[i,)CXrJBE%KF@8l2i%#MmQI If&R$cha&&H6a@*S$Umj)0#BcU#Q2(TNaiR3+LJZbD8Kh6JA6%M,NQjDM#CI&jT+ f&S@ZUe)q2Df`$HAl-JBQqVCr"mfe5GDCb)mc)+9[%[B4pB+BC%M(djkC&,TYRmI PfBHNj4qY50DTi'P$S@!-9E[cjBSlX!RN"&A+cLihfMB$3KlcIB0HlG*P4mHY@Bd SbE'#9RI'i!XplXedKB[iGL&M@8AbcUf(P!"G-U0$A8ZA)$@&2iEi4,PFMcLbDXl k#X'RF0BY3pbrhelXYZIHKaqj3D#mRm%U$hQ0aDVUbILrV$pDCYPhhcL[)$k%J8p bU**E21*X!@EC6!dh5p$dPd&GJ1#'Jr1(JP'aJRAX1jGSl-dk*"cR`EPQN`e),0[ YA@b`qaPKViTIc!,rIX[EqeqVfaV@hlpMDHaRkH#Ce,fKDB%qLYcK9N)pUDZN$"- ""6*#pjPNDfDhm$$bDK[MACC-5AqD04EH@9``*14TBd9Df&`Le"+I92LB(E,[JX, X'b"T#eD[bGkld![l-jJ%EL*c@BK1VSU6GaV)6fDV9U'UVA8R4DZY0QCB)'a8ZJ- %`"qQF'+6fYdLjFM2eQRPd'lh+Q)G`kDHMVCaX[`d"2P%Bebq@XL9'5YdcN!'Eh0 E2De,khed@beLV2@%2pjA1XPm"3YD6`4GTNP[8d%3'aSEPCQ[c8&J[rj)6lN3i8E 2'P(l-PF$j8a%'AT@U!S)SQX`3jIYGHEF@%EAKY$2bPJ[LJjLZH0H2r@S808e%Qb (5-'cDq#@k3Ir%(BK'S(brNaN,2D$J2m@*6mZQQeL4[Y8*6GUqSr)!h@e'26aE(- PPiU)lH'Z8$@"$bmBh64P(3fVdGIR8&c[*#mfj#X(U!rd-a1E9@-1SJhM@dS1Gh& 2i*rTV86KjSiN+5@!q@F9Bih0*H$c2SD80IVEUfBM2@9l!5`)VIkSMJ[0pacFE4Y eQ,q-KPG(5Nd!#lLa29E5$)Vh@-3%,GGfG)6B'0!9b[FLmi!cpqh$65+Vd4lp88p UG+jb"j*S%+*rliZfq8iNm0p%S(h0qhZ2f1,lUP`AaN'Ab&F*q5LX#hJG*f`$adK hAU`9BS!Cf1B3UeT!`BVh%S'-m*X%I6R1YiYNjfERblfrDaF#3bS,PVk"p2QXlL) [*9D%D'Hej9j(p,r`H3b"4(GQ,qaaNUcP9MRK*@Q$M'YJKrde),'#6'd(KHF&5P% NlK,q!bTB#5#NJZX'fF5Ll+`3Q8TA*bY&m9%Ec6J9*"4Zar(M5Ypah68LSbiMATi V1#*JhL0eQCRZ+hP#Gq!J0l4NakPIajah0M'rLBj4I2`,ljd@0fCZKXq"Aq%!D+c cpZUYK5GJM2f!FVlrAJ[F,CM6BFa5F)+iRBZN)#8R*TT+-#U&NI9pEmB`ZiLP#`A YGKSZ)dj3hYG(p%Y*%`6#IrdrSSpi[NM@IJ%RBhdSBI@1eceA0"1%Sh#fA8NA-4A f#NphVmKmTb)kq$eY20+DPFMmdD'$&%,-@6CXX(Fd8fN@UZ512F3Cdm8JrN-X4-C DXaTE@e5E9rj2pebD@p%)d44`cC!!C1CT(bhAh4M3Mf2`VUIl"1'irKriPh(GpRT PlG5J*Qf!5RlmCf'Drd&N1ldX'XF241NmT8r'!"Y*&fd1Q+5k!iRa*mh6PZH'-r@ f!#*ff(rYNR,YKiqKYefG!8R6iahlmXfSfZ8@mSAhHqTeYj2XDVG"dN(h#TTL02p G%YP%e#%QJYYZASESI'm-VjpbB8Me3pbG0HXkG850,6U6RL5)X)Y)PYT2cK2Tdri !(cBaJJ'hlIGYGT)RCLiLGMD5[q,kVHrEU9I9TYqh56(lEI[UeBrEU2pES2KI9AG p@Tpp@LAlEE$QMc"11c590M[459U4ABD+MNH'i5C`XAT3ieP2D!U9GP+-&eeXjV! [H0T1K(m8$3&ZKAiQkP+rZeB-"[2Ud9rXPZThF"MGkZ1rEJ2KMFAfRM%,!)&KRfI 32R6kk4X0NXG1Y!K0`90560kPUNNlS$rT"dj,'TUi5VklZc!6&!a$U"`410XPQ$E S4KX0Kqa8%5,C!k'3!!d(dHKN3R@HESAE`,$4J5hk@%4V9E4+KENd0Gbi(%3%%rL p4`URqYJea$3Ak)CcPGFBdr"Xji!YZKpZ3rX4@*R"j*rbQ[-c%r4rk1q1HAFP[a9 QZ09'VXqH'ZAa#0!e,(UAP@'Jje+lDPmQmK&P0K"[IUUYrbSk!cLmSb-#VU5bB0d lF3GYlJGM-RVhmY$-#2X[6FhdHmL#eQa&5hEmA[RNC*DDI3k$pi6DEIRNk-9KI!m F*R-JP1EY8aE'9b"3*E3GD`AqU08Q)$qS@-pAJ1Sp&ULb%($GR2ji[X[45cKbj@P b@b5+m+ASR4Kf%9J'%DTKPdjZleXGDR3U11cf'Qf$8GSeHTDbEcN&*Ec4VBLTiSL 2Z$YdCP6X`6#0H+HX628b[mY'2Lf9!`a3B2M2c265KK&)UfZ+"Zfp9$8LLY9NcT& kiX#SPEcCK$aYiUE+-`V1CeIGjGfJJf6#4+JlFQ@XUJr4XLJ`b[a443m&'P@-BX' GI4dPkNk'8PP12p6Lr9'%c!a[1q30Hm33N4kRPNYp2i9rNe('i!%9%,ZL9hIdRD" F@1Sa)FB13!V[hhLe)jA+p+LQ[0l8a9QLQ'#9Xq+Y88"rJf3BH`UBJ+QmMX0rZR' T@&FNSEG(ph[8h&5dXlJKHHADD"PQH$P5dPVmY1La1l#)V,4SNJGR4'pYL(![cV# QZD1rE&L&FXIA*%6&4GqTF0NEhY1(1q1FkaCqCLjT3lTEN!$ph[FS9hQ[-3!e-fQ N`-b@IiCHURY@V'#@bf)kQj5`pE0V+#2Ea,SXfcDT8'jAk*djp(Ja0MJ9%%P[,P$ @r6kpTcSP8CJ(Jp%5q1Q``(T&+fNp*6-,Z[`ae2jhrEr8@TT)jXK)QLA56KUq",S h4N"c#9G9-lEr$Pd!VK@&TCLRdk+@j-%rJVKqZ21DPj!!e21rrAmiH&[%lM'M2P4 K+jdc3'rr8+Vcq*JdUFp)*42PJ5ifmKa2jk09V+4FeKbSL&pQbrpPcjj5-,CHpN, f-D#K$*,b5e8eclbH1cF&R!L!RKDr#r#r#CVa4068R"*Vl#RZ'j56cJ)+5rU#8,( 86NlX`IQEP"ka*Q"IKIJJcGAEil)62L4+cmZV1"R2$4p"fp3E"+9-IJ+U"bB$1Ff fPQ"H`Q6R%,$P'YFCbR2'i*kR@"f3!%[356i!crh[VfLiXN)6PYiUap(9&CLbS(I BPrh+@i5D)pj9IkEJkkC[D)RVJ[pC5Fm6V*(SaE8)q-03b#hIULA6"DpX&&1ZEUe "bMNUprpjD`[YPV"'3CJ2fbElId`0cK`')E+RLZ-CGc(#ER,P4Pjfl1N"!4iAH@$ h*q&Sd5mE$Yjcfacl)UIeV1peADZUVEilF[S%KY1`R"L$)k'TCVRkf8FV-'qiMkH !-%ja'B-C)9DTJAG4NP"hVJGNdQTbd5Khq`1jKM49TM!@4)155EP5K1BR%Z[f3D) --HH6FNd)EHclUTRrACN,$&#cqMKGPlYmD*0V*$(M+pMjVZ"HP4!rQX!Y[a+*r6c 5PZH[0B%%%i&BQL1lr'L%!"ULH3R#"aamAM&F)AAZR*DTadU6-KFZBmkNX")19P8 +!AeA[A80E#+D21)am"9&h4T&f,3#1P3-5F*AF5lCm@eJ)-`!)KhL@ChS4+)IhG9 a$c,9eKkkjSNGcS3pFpL2MhbH%'3+X60FH[)R18GJjb&)ciZGfK9$2)[96&B@bdh FmB-@#Zf)H$HD8P@C0PIZ@-fS9lr(AiK-(KqI9&qkU-8h@h(ec%'MkGU'`ULZ`R4 eK4mU''8Uak8NhAQUqm!1E%Xm[Q4"1,FdRpcl*S5C#kj0,lrkIN8@"SrV4TE%0!G r[r))ejl"V+T-XfYE3a-3L)d9jl1%@Y*Zemm2Z)T8'kBj[jf5,Q#R+LiCZJPUj1i G20C!!-@q'XUJ6pC#GI2BZFbRN!"HCQ1QIVLZjC(TrIHHNaZ$SH'cj9Z(irQhGiH DDHU%9fDc#A(JJim-EGhdM5kTI+J!Dm2a@VZYZIC+UYU!H%m(lmj-r'QbB01'Y3q *F)r)Bi#`bdVe4p&XYh4,R&)jI[c&%iBlLf(BpGBeh[)q"&H%YXfVlB!R#ZNSIpD lP3U1Em#rakkZ)4Y9A'Gb0Cc)aXa4l2cl(bX)b6YpSYrH4i#DqNKG'%kK4P+I&h4 b'@Q5R#9,*BlXE0[HhFHlrZD%lA&TfbEH"AraMcaIYSQ)kPra%IIF*PI)0bjDI64 M8YeHF-MeK504K-MqkCLDPN,`L,V%XKeIVF8#+f2hqPr*m@E$4p)BQFhZJ9k6'2f ieTClJrRr+TQTd6VGSrGL9U@aXR)9,[+$HB'h#3hp1J2hXq6RdUN3(AIiYEEQB!f N+XVYkIF%BB9QTQKI(-#+i)B1iM39[i5V%HGDR`ir!M(J(0(cY+8)Gp'j1I'86Dp 0N!#ZKra$$1KbLm!8d`hr(MVkV&,*dSbIZe6hdFX2QJ&E*ApVjAPZNN'b5,Bk`+6 PDalc*KN0X+9UV`@i9T!!SDdILPKcdpr-LJM[cqaKXqbc`l3%cAj+lLYX[U3fPT[ bR#kEeV)G"2IDr!HaC34T%h&V"jZ$(I*2rLJYrKQ!&6&&BD4"1QfC3RS5#X2Q*U3 E3H6e6Ek$cBU&2+-mKd-SJZIji3DRJ3AREmXRM4XL2*Y-[FjK"-6QH9EMm4%#I*1 9S29q4hS[lADa@NHK#6-H[&Fdhrd3PkjPq!NAkPV+L)ApCrVpA%ML$$+0lNTe!%H FQV1`,kPG-cQRE*I!kfNjkGVD&NN0G)fjGCH&DqaSV5(6"KXpSY*VqcckrT6-4E3 'h+-rkQLZTR%SK2-hE#`ApJep$lp3Ma)M6qR5+"!"MApA"2e8@3HUMMhr24+,h4l J)-6p8Sq&!ZY9NY0)`EQ`42)')+1J2r9a3IQBX9IE1VMQ9)kAkF80+S0iqJX$@b) $pq@'eYQ6MdHV'6cVr"5X!X"%8HN-Cj-r[br$!C["6DmYC[kGU1@ed2ViPFdD3JC hp6R0j0YT!Hd2!0JDXQ!!*lcTU`dCc$[,I!(AQ@r"cKmV(6Lq5C3GNI@qSc6fDAL deV%jUN4Rhq,E45%ST[(kpS,#mLS&4l0md6CSPrLr5ripkfEUkC2qk#2pB8YdNKU IQF,&)V6qc3!GSa$hF1U2ZkrNPm,%AC*5[JZ#U(89lCU[e2%-+3EMZ&F&[I"T)bF -GkPKNF4kp4&H@64f8qN%'`)YFA#4S+m'8*l5KX5f2biPU,*()Vd`,Gl88'P1c#( eY2&9(cCqTK-P69N@+RSpb6fcHp3LJEjS2dpY`5iZAJKQRe"cFdi#+jRK8Pp+KXp 9q2d*p&)FP)lY'`V4,HI)H(4&1`rCaqQf6D8,A54GEV5HENRb"Vk228i+r,D94lB XEU4",85$UpC5'LVV(dpUNK-c0kBAL%'QY2hN@IQ)d0X@"0hlDHD48#XFH'6Z(CI 9@+&#H-*j)Hp&bTr-Yd`(Tb&J%+eU*mIFQMMM[+&ZZ"Zi&L&cqTd&8bTA2DiTRFI f)8r8Y1U'&D)9,L![%Tr)90%,@"5r!3Xrf!XaCVq8JK19!Lk-ML0U"U81ANQ0'bG @Brq(4-6j'r6Y4rKeTDLN2jYe[f1k(U[[23e)JAQNV*Q&"Cjh2q5IDq,PTMd&NRY C6lU2+B#GP*1K)EBV18b$FAe'pCFB3M"LCm(VZZ$bK$NZ%D+m9-T#)(5i!&+ThC+ JUN'p%klXjSVS63a',3,LZ+`VRaI[`b,%qYJNf[VQ2Y9)%+HJeMHc04Y9dVLkE$, dhXqjRPp+5N5i%QR,E#U'PP1dFbH('PPU#p+b@`$TE6dFGS'E8'NTFrR#ZS!jh4L EaT)ammidHE3iRIZA-GTFpYD"4!pK-LX4`QCqFA*%I!hr(K2[9X1)[j[%!(UGQLE fDKLbjBcGibN0F'8`UJ@,ql88kU9'RGbAppNZ`9djK+2JdYc4[2LmlR3`d"84hVB `#&IiP`XMkYc%ka[%IZDG$lYHBXXN`SDEHR*N(Gd'1)r9rI4TGP,Y+pQ14B@dV8Y BC$dTK'SbpJr49Li$[m@eS8ZES**B6+$LmYDQZqF'Z`m%)HlcVKXmmb+2eM"Qfk& NN!"IXDN$e,f,4d0HQ5#P+C`bcMbY5r4ZZdH[2V84bkkbX"'Br*HJq-j[N`)h0bi RdjHb$M$NTEV*CAPiN!#ApUZ%55FIeY[J'4db@-T3pmj)+TK`L#*UL$KPlB0Pfkq GPEL!U'b4LE0"m3V1$G,i*9fIa@&VheNHC3K*bJQ`FH2fhVqh62mh6VpZR'2fhhq h8VpZTrlG(X2ffCqh6rmh3VpYe1D2-%il0*8f1p&*@T&GKSU14iEK*R#fY82Yd!9 Xq[X+1ek`L&4RVGY@plLSSZU#)N)Z@40iRrmeKhrC1PDh'&&GPf21H`K'(D1rLUC 2T+UZZ0Q+jI,"Bljf',mhIdI[2YqACdGJ'f`,6TiK@8(9J#c[$HdR@fN2A[fkY$0 26%qR*E&j6h)#,-59'lN-dD"i)I0J$h'p@E*36NZ!Zd`XA@kqEkT&$RmLXZCVX#, I`'92[0pV$52QQN,`aHBP5mhDGq6dE9YKREriRCR9dYQEapjP$0Fqc4i*`iU&GAY %X%PCQZ#Cpb,qac6$&MG8DYa$NLPP-bNIj,dAL4%KM`Pd3KCXqDUN9L,f@a34IbG *bqTiL[V@C8&l*Q5eGFa3ef6b-@"+lf-GN!#lqmG)2RMVRiXLkr[IEI@q`0X[RBV cHDXpZ5Ai+i-A9BZS+!JKqbQmSLLBmmd@#H2RI5i&VB@bh&r'@rP6Y+Xc-@1f`c- MZ%Mb+dFjXkEETETTk%RlI4lbXL$p$jGG2RS"'THJVk--,3j%2lCH#UX&p-ZaiLY `6XIhk(p9"bTT0@VZ9PY8Jh(5cQ4!*eCBp$kL$4`(CL!CETbBNSD4$6+hYZ%QTcE P26(9hfaa[9U[ke`r0rP+85(9!8T59p!3pbqk!''f0"%U@K&V5kCPG)k0dpmUHi6 1$`3cfS'd*4m)ph-BIFh5"jhkf+5NVTF-MIm6rDMVLG4Q),&&ePK+dj(qGlq68FH 2[4YkGUDHm80$lj@+I#cX@(NhILjT5YUM'PSV1-p3G%+*I#+rrbd8QiH46c0DjLI [B9"iGhQaA!Vf9jCh8fjQhSq06M@C&`YbfKG`VqrcXSDk"&SF*G6Rd#0%mPq%NXN -iP'cM-V2*CpZ0+GqRYS*1`d2cqr%Jb`I2)$DXm!ciNZpa"YSp8c*`(YjqG5%iF6 39N+VFd6Zi#YZK@8e,D-B94@%Yc)PNU2q%6RTD%ed$pa-JGAF4RZkLY"q6e!j[kR dU!KA*PVZZT)qcLF#krMCc`H#9&e+[mqZ[RfS+3fecNV4@cPeQSK`P6Z([FArIrX [%m&NYQ8@)SYbM34X@j-UCpS,[8+rLXj3e&*9I8K+TUjpH8Lalb,[i"#Zc9m3DQ( 19ajbZ20T5!TSAc$Xfc3Ef"r8p1bajepGC2"a+D9E-TQ[HQX0&&h4r8dPY$`#fbr r(6mh4+PleTq"LL9-1XhQ$N)EQCVN"J9$FT8@'jm0i4FmNL0+r@l)KXY#AaSa(EU Hl)c![`5!k8S6d[Y43#eEQ$lEaDBq8BT3f8P1d2+3!-#(G$H0'mkrMJLEJrDhBDk @GXK8raBk$li[8kIU*80T4M!c,XC$-3[)-Aic9A&ljSA!8*,"rd*4hd'E53%[AX# V1a@!ZMlMra`U-N&#%p5&YE5RVCbB'-B3bY&I-3*N8q[)&&,PH3-bc8mQHF2flAa C#KpGJkr3,[D@4kBM9-S',SZUNG4JQb!m3rH3!(ZA8i-DR[TGrNb`88mherm0K&D 9qaLcZDYLiNk6*Qm1XE`RZ&-fa!`hj9iZ!p`()R#9YArf2"lBpT2@Cfr3`fr$*,j riVN4HPc&S6`AFF2JK8BYS%GP24I5-R10PSIQi(UAJeDQ-4DJSP94+Xai[PSGKc3 KA[%&%1'0fFc'9#BYJld#D0DBL!8k#JRhqR5l3Y%9P@M[B"*R1cE+(&qUj8'3!'8 X*1$,45F[Xf5M5bN"2pp*RL+JY9KKP-Rq0CDHLLCI@&1%FKi9AB@cHd3Y)U6FRr* hX6[,cFc(qFcQ-mCFD`L!##1RbkB)!RQ9A96,m[UiIkMqIr9"KkLMPqXVKM$14e4 VYTNq-8Y!!N,BL6HY6SZ"SA@bL2U9#qmAd9-8ZN,$JL!NJ*!!8J,-28A#0B9EB1# #-dNl&'d-3-@D'VXRhph9F3mbeGBHZZD*(Fk%2ABPHGNi"q9r9ib#C(VN`G!`SAa 3r+T2K@cAkdDqm8p56I6LK[E9LAq$p(1[hi@'Hh`mS`,m+NcjC1e@$rcqkL1Y6Hq '4k3F&5EJ+e$PpD30pJ44k!f4I*6CJ[kam6I3j0hB9a"Q#jk`Sp04chNQTPi"DT5 RDmjfk@"eCVE1[`f,&aC9ih6-(p,bb4&eBK&"MaLV$"9'X@D5#rS*RG-f#F)hS6' EeP&X9kG#8cXr-BR"'Nc-XQ4[#kjjPUff4j54"V8j"("LFmGZ"-MNTMpU#AAP*hX )c'9m[l!,,cF8+hB8c+35EMVf4Q1$jbL8I)k!R88)5SV)8UDcl!jTqqCafF#Z9c8 L(-a"R`p61G4KF!!)CBR&BL$34KcT!6d)iN5p#j[+A+mAKUm2N!"c@mh@-i$r,TI iUBUUU5YQ4*h!rHeGQVcL55ec2lrHl--K'F4Pje&1rYHUYdJF1fN+&BRBfB,kfbR ,T1FqhBr,FNC8kB,L`H[krEffr&6h`'%kHbCJ@#FRr)paH@QXd6%pZN'Qa6U%'FQ IrY+ZS[JQCm*hEX9Kp%3)H&14pTVFD0J2id3f)lI-,,EN)!NHl,R#YGA6l8eH(Hh `hr5Y&`JaCQYb1aB$PQ$Fm[1SkI#h+aqZ5EkNAIBA"`UmLDS1VCbRI1N&F`HJ'l1 kAR[P4I@1Rbbj)&I2G9h&%L6d5FhhBrSUPLFG!eTYD!rX,(N*JL$kR)Q24BJfp-0 S-SXM91dijAK(FUbr%Q)ZG,-2KJcAp80+Q)PIc-2rD"UaPSipV@L-+46eQX4fU[d 69E2cSpNDRrl*KAJ5d("'TJG4@1Z3!!'N&*!!f3B`4$51NFi8,2!N5f!a+HaI'r` TMcLcEhSlp(+c[BA-*'c#%30rKj!!HbXXCpCU4e%SF$mqjHIBR)[))GbMljfdRhC jcmSJd!&jKbb$cM@F3dTpRiNK&,9Ep)BbcBICq"6R@1V34QT*EjUbSY1eLa5EZB+ L#GD!CG%rImdb,E$5$[AaMi*V18qElqXU%UY-&ipYNSB-dN3(3-2cqS5cbpDYTUZ B[5c1PceY)T`*D2V8'Nqe+XH-hEaF*p"9A#*VhEV["hV,D"L4[#4RMK$RBV,&Rr" `$[,(DlDAP5%)TaTqR%e+i(BlUId8ljp-RN@KkhUBC$G8j!FC4E1C#eBf!@F0ifU KKFNIFdG"0[lilaZh4GM+!DZi@fTcE3$qbp+F"UbCLkX0HPUQN5j$UV5Q"VrYXYU !*jZ46j+5BJ2LPPTRe$a1jL-)8!f0lJ'5jQY[)(mq&KPjNc%q6f*`H9-#L2d0)b1 b5+q3!*)3Y60J%qVQcYPVplCr3BM4#'j"QH[cjR%RX4T3eSL!Z9*[U5JkNKBdH95 cG-Li(21PAqLp5bD%Sd5pQMh6m-&F`5*Ik9LF0#KdT0!`a!Grm*K91m!J`-0S!Sa Sj!&&aGPJ&%G0FAk+*%c"+eQBYYb5f$ZYcKGihL*0iVJDPHIUL[$[G-%"Gd)m!cJ Q&S,UV)"E62DKQTf+1%J*I3F`fSN-j*K,eeNGBUlF2VCRFKK##lYAU4cYeG",qG3 "01Z0Vm`XJLLTCIfFTpmpS9Sbba!il9D5q!`$DHEiY[YB)Thb6Y5PfHmX8#jr@$B 2(J[SKdJ5F1T9IYd+2U#CTi*hk$iaL"A0i6C8Xhm-h,&Zpl-*HmN&-ITY2%1445( (VPMQ(afF8jDi,'i[I*U)ae'Ca-8&PYc'fhbJeY4ie3c8A4&2e!E0$'"S%(#T[VB A4H['GqA5MpjC9[JaZI*MkK*Z"+4Mmf*ld@-q$*YcBfq+j&mU'+l#Q3p3Nd[@[," jh8U6)h8mlhFI&TeX*HihrS$CTCJ#&DI&X3V9,AS,3AA"!$5+VQV[G"2[ph!fbHV Z0NI0m&HEHl9qkeEe@)f2SQJ&[UfqrSq&c0l9rc5f4KpmQUP4dSeqAa-!jb4Q869 EmfY!Im9[T4#aP$Lmj95Y`i-pRI)8pm9eF"hH'YPm$8I)qr(1YlcG`L(3GpZC@k@ l"c*UCXP6qfP28P63),$3@b`F4HNX6IK#jPN416djQF4H5&Tb0pGA#Si3j,ZYNjK i$Z$eGVH2P%`6CF2S@k)S[%"2((arBMU(,+[T2Sl6hAFd2R54$rC6AU*R1++)LIG VAYCmZm'4,`TC1UKja9-K%D3YLphF[@eC+!f!b0Ip-qX*UCA,VHH+(&lQi[#BdR, e1@#P46XG1cNjQdZ#'['LZRXpp,CkVrD[6R-USXQAbkBQA3B%UM`(q['cNGR,[m+ 60bM+AZEUP+6Yjf3$GL6qK62[Jhh+VZNBJ#kcb%ZcDpjVF0Mr"!M'3Hp-Y%8JY!$ FL'"dLS0!9@!%AIp(-[DRXjLd(#04XMb)4R*(PYSYk8(4*cH3!2XcKKVUh0G$V0e UVT!!(R'H3e5'"-8kIj8!L5+1Zm"-pG*&'icBbqlL[&$@(XN6&ZNJP#eFY9k9*6m @B[DTA+Df'KJ%Df$LeU%Z%Sc(%2N[!NcdYTGf31N4fK`qPcc#Lq+qM#cS)f6S%(J **TK3K%,*dQd"#IU[3Mjhf8[p@IQ5-2)ccqDh+','pHXkQmerm(JQGNVVA3A9NbX "i9G&`dr[j(RP+6VE@[40rBmEM$9jLA&H,MIPpSar!k[Y%ri(fAfLppSTr"!rJHi IY&IfM2l4LqSF"EVJqSp[2lc!@,br2l(N6qi#flU8`B&rVCd!B`(TjiV#G0K8R'B JM%kNl(#-B"BDRK)IeFP`N!#8VN5cR[!Q%K*j(0Gk%pep@3)4q2bkb-T*@)ri8"T dSS-I&*q[+PI$K$hB6,Brq*LqcCB+QqEmld$Irhi6HC)`K@Ehh49"UCl'-M62X*! !M'H539fch-dN)RNU"QP!2$6qQ9U-!FE`X*0311UG(+%,!mC'+rM14-b%BM`1F3d 1,c%KK8qU6)NX-#2a4#)PqGNBYkbB)RTj(rK6S8c@P4AliSYjN!!aVZ,cqBKIFlY 64Id`NLpIID0-i44#6jUUDAJ!-*!!MMLlPQ6)bMXL2Hcf@qhrI2ePQP%d%[L9M05 1lh%bf"[T1Xp$m6fQh%GR)IP9,55(9,8fkD!5%F`jJ$*`#,!N)fZaGUN*[J5+Ilm J&1VP)4leLMF@XC2P5Zm*j3266H+SeP9"cp'*[eqV-%ZJfU$VJ03!EcR+2A!h3Qh RSFqeB&J(q%q5LE-)lmdGIrp+eZJ%4`I*"e6+"AAIq*@&L06+H9L--lE)EC6cKlJ #dkRUI,4N#rV@IrrCD@-`13!!LIN!!!!-DP!J)!d+K`S!!!!8CR4jF'T`-L!!!!! !DR!b)!!!!%pUF$*S!!!!&QPSC()!!!)!!!!#!!!%"`F!!!!!!!pMEfab!3!!!!! !%!!!!#*MC'9Q!!3!!!!!!!%!!`!"!!!!!3!!!!)!!J!!!!-!!!!!DR!bBrp2re% !-J!!!!!#!!!!!J!!!!!!!!!!!!!!!J!!!!)!!!!!!!!!!!!!"!F"!3F"!3F"!3F "!IpN!#-!!80bC@&dEh)k)%TKFe"PFL"@CA*cD@pZ)$%Z16!`,M(r8J!-!!!!!3! &"!3!!IpF!"0!3%K)8%K)8%K)8%K)8%K)82pG!"3"3%")5&")5&")5&")5&")5&$ rA3!8!N"!5%K35%K35%K35%K35%K3red!&!0!3%K)8%K)8%K)8%K)8%K)82q3!!! +!!!!!)Li!!(rNpq&PJrV6RLe4T(Q`R*JQ",EI$ZYGbEM"T!!3H12iG[)!X*#A'b TcTP#h!U5Q,e)HM-,ajfL!'-$DP4KmTYP%#&$iZrNP[J&5VLI!Dd$[QE3B,*G&b" J)jU2EprRBD#RVU&6ij`crBLrDUEq"9Ar0c$RmVX-VUqA@kC9bU%k0,Z6U)F#Yp# B-`r0"DS5Y9aUc[EfS5"%aBCGJ)4`SM(#*4CU6[0ZNk5fYpN6H6Yq2"+1@mBAjXF 9mf2a&MmC$r2&G0UQYPp"[26i[YF[QCPS2pq&M$0RF*B5d1)%bfVY2KH'iq8"i*) 4P8`Rj(@Ij*ecpkVC5J+NGqJFVj-$IEKLcd%Pj-q8hCj3$%mS+8YpGiF(USjUCPI RMmUeM%1$p`cdXTbZ*3P*I+e8pNh4+ld3T`aQCqcPqK*'GhN3QlfFikC[Tr15GDc k9+I*I,D$1pf*VDbLXr&*J2BmaK$2b,Vqc2j3%0bD)P-%3c"3'PKTGUbck-cf%'D 3!%NA#(F0T$l8XUr[ZTVhM+aD[q(*`$*lT210H`Md&McErhrIKF)Y#4&V#N`(#B8 ff%Xjrh-!`XBeE5k99@RGq)VM4D"bNJVaJkF86"IcZcHV$rC&%($`IFqIF1)VM[) 1F022aAScF$!!!B4d'GQ2cCZNL#)Mf%(m)f"N"QdU1H),r,kcPaE!$)6*a&9VmQa dLCJ%)Q#*MTFaCGM`r%+BN!!%BT55BMH,I#%Bdj*b0%Q9$,XXcV9X8!@1r-ZGSf9 1e0M[edV[h9UFD,-LI0Z[hjPidB`DEA!6a3CMDR&JElf!SJUCQ["ZB2IH3eL[cbN 0dDbEamVX@+)*HMfB@KP8U1b4r+Hb"rprhi&!$qdH@rahcNEB%I "V'3kT$X,# aBbDT0aQ4VfRiKQZQ#J4lNre&RmID[apUc$l9N!!8k(2c)1e")SDj[@`dNHL-kC1 L41[fC$D1R3RJ1!Y2G@4F9lZPfCq,$T*,ar`IGkRaNePB(2D[&*l%0AK!'eFihRH CT(qVdp@3!'dh#2)q&aR*XJLBVbcYhTH[2RDpp"F8k(N8*)J8f#l)Z3&[&e(JE') 8JkA!QreXU`1Dl!%lD)cCVejik3`r0Pf#K5*i!Xl!&3PL+4I+HR5pL"hJDBZ'3R' PQ!JGdP-0!%!#9h8lc6HTMi,bSUJ%0a,2T)FjVHU,4$SdEJ25cJMFeA*-pZ%Hh-@ qKHkD9B'0BkQVSa("mLlMQ@SJ"(TQJA+4`*8EA5Gb)dT$J$(p$G&8NX55l!jYK[M ,(bpC+@NNDB`NT[-&KaikapY%4pVr"pVi5,GeP'BS@BZaGJeMAkrUGXRL2Ke#UN4 5Z8*Ra,p34Z4(Jp"U20Bi8l(I'QmhMY&6L*dLCql0Mdk0NH"Ya9fUl'eSDe&Ub[* +0c#3!2jR5AVmEQqhhDJ,HhG&**PH+#I'Kmi@ME0$P-DAZ[3YmJID"f2[FAjd60Q (Ba&B8M%&PH'bCeA565kTYlmdY52Abqq*CBQM%+3bkP%8jNhr(,EMKImjD$!3"aR 4cE+8N!"9i)hU-`jbM80'BN-AL%C0'T'T6Gd3`mGG4bX[9[D0aV(r8"#qGJIQl#$ Q$T[0lS6+3jM$,"cV5-AM1qaKN!#"eJ2KJm1h#$M'@DI4h3EhqZ#HS$ST"R+2"p( INRq"kJBS@qMEEqe%`V&q@$A5kC(P#2hJGRF'M*-EfZU(aA50i[eSc3p"p)#8()0 60+aBIJ#R!RaIe-0h(IU@BJ4@rcpcdiIH@(mj!(2JLBAh'D)qNM`Z)3bhCdSS-LR %@#fX`d11YXAHb-UfUFB`d0S*E`9,Ad6*AV-HIG1[cm+5Ri82(i8%,`RE*kaj@,Y QB!3)-RE@l2(M8NlAlbX%0NIdd$PjdSrTGl2[mD-pRLY93mq"4Rmp9Y`&54+Se2K TF$cF"rVNdAkeia!YS9k5BEi2JD9iHeKKZ5EJM2jkAF$kU39maXeZ`3Crr8%"B)e QrFL-VP8fbD[fZel[Z-f1J*cE)hjZ(3,X#e$1!3r'51kdPrUj,CeM3NSdY52Abqq *CBF-mVk$GEMHfiMb'5NBfY%B3"JG--bB#h0E'-3@%8i&-Q%I6@+$Q@Kc0Im2jVM J$M%p4$(2r[T!1MT6pKLT0lDK23aMiXEL$acCI+Qf6+)pURSIB#`r#f6i83I+(T- QbrpBq"UR(F$PrbaPh+9DeJ9lkbK@MrmEjp9i*BrKcAf"keKjlMI6Ll63-e,K(aR iXrCN*@*B*1,S(H&IQ4Q2K)kpD$*%9ia)Njaf5Bfa*3%&&(3-12ml%6R%S19*blC k@YHd64Q5--#4L6GpL8f+*%r[@QQdJiBCPQIj*qQVD-N5SqE9*lb-(84Ej#E'3"# "P5Hq(8)p+VmmiZ&SQP9*`''hcm!qIJ)3qd2!&1K5)3MCCP[$r8a44h)c&1KXqeD DbU4N'd-!N!"f(BpImf+QJiL9kqFbR5SYRar2`VfIK8X2YU-8k,TXEieK`UF*iZI %i12@08A`#[%`[kQSbqHmZE962JS2`('Q2h&0"$D(BP0SNC!!T$pE@EDGIV#c&2l i'1*Pl60X4da1T-b`jqVUdd+pfACPbVijCerL)"Vf,GeQXF'Re,SKJe8PcJR,(ar d6f`DAp-`K[RNk+'q()!+j,+P%HkN!"HKXImTL9SYJ8r,d1&kIJqQ(%AVZR(@3[m L,U(adPN@VJ!9M[bp#XJlM$1!9P-B)(5%#mTFR@0UL`%G&1LmPYlM#0(Z)9DhQ-$ (V@I!BRMNeUQph1YHHE9CkV&Q8*l[(Y1ViVfUUV+h4H'@!RUZ'p8rFbN6[$MTU%! 'eV$V8PNbiRGK20H$p"bGa)LXTVDr5hmP0H,G$pj+jQdI'UN)J*4&F5rcS#Tk2P1 P$Y-RUDB[R)4+1(6+pYQTXp!(mPSQ!RPiHE#aFU02V3,G`Q`CXVf"kjMUT1Qq)cX 9lKJp&'q%%XPb*eSj,hd4aH#Ep@IG"R%HR$9L`35HR5ZH-&qZ3c`[-0E')!+`dIi 9dfkLm,"pJZl!SPFT+KF2dlfZlVb)fPJdJ)%qJralMJD'%)@BGbULkC!!F[aiNkp EYbrPDRqh24KlGf`[Nc29UiQkG*0YcPb-Ij)6Fhj3YaX6XCiVP'lT+"DHKPS(@p+ aD9Z+SPc$5+pAV0S,@j,382(@&h[N#ie'c%I(fk)apYm4q&f!&194J!GY#&-9pCc f5lXDGM8S1,4hMr9V,qpb*k+!A,9EF)eb+RFHdHqMpCQ+R3kP10GF$ZcTNGIqZaC cPa,ibef3!1F1NpNlL(FD3P"i&4(Th`dkR&SF!Y&CFc-EeLel%pPB`['mZ'VD"0) Rc[jS2J61PTH8U"aJM%Q5CGm`q-feSBCS6G4'+MZJ-6-Sq*r00CeS,b1m[XQN(hU "%E(DqN`DCT!!@lpe#Y30Y@jKhJkme,hChSZar8dcd@Z(&(PIZILQUb5iehSMF&9 *l63k$R2)f!1p#iHF-C!!)H!QDhI6p6C@aipkTIjBA0Nqp,U(YR@5,qibSUKeEQ@ *&#G#L4%21$E@$"prr,qV1Bh3k5(QQR+F&0ATDV"'T68`IS8AbZ4ei&$,SE0ZbbC [U$R$k"pP$(9$q2"M)bQKr$NNkaQ&!2[$V%d%fKJQ%N3U`m&"'6Z5a'6h"XjCZ44 "-q#mBb%8YU4bKl@U[ZL3!2j+Fj!!@UZh@Jm0l[ip-#6QB&rkEkUrd4A)51RqD'Y AXqhB@eXLlB3Y[Nj%9e5hBHQA`aG80-fpUlZ9&jb9"Q5U8V`Ne@-#TaPm@cYEDhi 6aZfa16e(Fl-3Mi3KcC2kRcaCmeM#ZC!!Im6A3j*LfY3h&"$@i8rB3ZDQ0TJTKA9 e%'R(l+@S)()VbjYZMAqB2VkAShc2heB16H"NlFD&Vd331,r4k!ZiM6[bTp5ElT8 lL,)9F%(q"`@!FX(&0HVh$'de*94SJKGYilLA*T`8(&JJ(cAdqj-1(MY*)'hbLA& R)l%4#J4)Vi9dFZclPHRP932V5k"1`Z"mm3X(kbq)RbK[@d`AphJ%2#YrUQ%Ze@j IJTY-X'*[V#2%Me-61*qT8ZHpeD(L*pS1YZ"-`cL*LjFU3!*`J8pfipTHf%"CX'0 j6GL4K`!rH%#"D1VS-L,B)b)F[QH4"fAJZPX2*MUDA5Kp,rZfHmIUF+!P,NkDk%E XbeG0&('c8%*86)&T6[3J!kIU*e"+9!*@Fi14F*PHUXr$55IKS9(iAH#Ad5!hUGA F*eI@GV+pH&CeDGqkU5JdN!$$D65P8rSqYF1Hde2G0jp*SH2'bcbL""LH-JQHhlF DDX`30R2M2d,i2GVieKXK`i'+e$6N(pf(2hcDQL,1!pZ+cr&YV4MeDK8`PFSc9YS %j!1VBdZ4pDB!A"q`*UaXJ+#!J+9kMR)EMmhlU!ZXI[dY,,X2k-M#j"bRQr'lc#l Ufrf6Ya+)RA"l[jl4Zdb%bVX8elh0ED$p9CfBjIZU4f1$HRa'#"XrBBphSEVe5Ki ,,6CS&&UeGZ-+C'j!"9FBmJkM9U(Z*1PaJ(G$LHbIqepEM39(J(ZlfaVSkCGhDJ9 D`1E0mPVp3iXUN!#QU(&TIV5(cpF[ckZX&Tm#P0Mkb@-[V+bqd[HFI6Tm16e(eVp B"hBZUMCa+0fYS4`k8b&S#8N6Qb)+%l,QjM#ASihE,S-HC@c&QkjS4RTLDcRU%rD Ehd8Pfh6Hem[F,+-4'G8HQ+'kI$I8*G6IK!j!29%A39UJk*54i2-T4LFj-faU+d0 2NKFj[)'[fBMkRm,G&UFKrN@(GCR&Ak8+qhPEaZE,03AC%Hp'b%QP5iAU0ZfR4rD #Cdrd)Xc$*bINlbpqq8fHTp0Iea""`C1Dfdj#F-IjL`c6,d0CH"8I,+aYTF!E98& @qDKYT9J-"hm9i[Z5L)RcK8&lh-0%mRbaFUVKaL"Rd*HbUZAr6eR*$S+-P@1[9TA F-Z"R'Yf4eB4+3IVEM*46("#[C@jSS6ErIjJ-!EdbJG-5b(1bd"*kBB!C,GZ,KTf fkMYk$+H61(*ph,"I#FiHd$e+[V(+`*%M4[IP[9F1XF25'c5b1`aicRT#YBSjeFV N#-U13r,HCA60BdSBDce5h'SMiBKZX*RahIbp-RAm`q-E+6LC0l$QLbShVkcm9eZ 'I"3,'plHbAq)(MCPc6HBE@TIA[5H%j'aV"Rc#A4mf1Gm)[)#ddI"&faZqY"p$6& #RXN5UKm`JkYhMK#*CSScHRKQF!,L3$fG5lPe3-*mH*3bcQ9`6-h%8R&f9e@SCBK hpeU)IAiAf+3epq-6-aq[abPre60X&2lRcm"fIJ24q!Q!Ld["aSjNcm038)bUkc" aHSf(d+%XD,dkJT!!L8T2iB`a$`60)9(1-CXhHMl@rCeA0i(0'53$pH'*5Q'N&B( `IaAb83bU*!Z'GC@IX!'`4mr$@'IKUa2ce)#YA'U"pcB#m!)FcdfcKM!eV*N`DmJ J[qaI!'G*Up!$8+pPj,!6'p3)dqT$$6hrGj3kc$L1RP`faNiMG1,K3LLScm`*+,E 0SZ4Grh0C'YAk'mFfG[-RqAm%UC&,%lDK&Y[((VZ!2*cL0lcF5(c!cZ0E!SLHAkK 3S(XiiUY8UR6JFM[ph2SZSQeA(@Je&G,(jPDVmT+$+$PZAfA#U+2PY36U3fB81'! FQ(*DTeAc'MVK`)E,m9a(V'd8-cliMkhUaGQBbT)-)$%[6Zqm5[mDj`d+EJCFAkE 6hm+&M4V`YffYNS9[FGGVRJS3m#K2(iM@SCK"@P06-T[#FRj5L5#eJIa'jR[G55+ G)2!iX)([1P-*Dh$DemYqZ!5"Uih52UejQ0d,BRU"hqVkEiEXe3Lm1$k[F[DYSH2 L'a00[IdUKQ`hBM$16UhqE*R#R%YP14X(YeLJXeZ[p+k6,5*`Ufr59i"XIrK3,@K VIJF4XqkrF%GA9cpi2NJ"6Cpl*`FPkj')c3%KU!HNJDmkfPRbh8R-!I+jC!G+jQQ "Q9"*3C3U@c3`RdD'QTaCC5EIaD3$2REVUGecpFFm23Ehp((%4E"J(E4GJq&Hr8J 0&%h3,MZVlmlkE)%1r6RU%b5%iqY`FqRAIm%-5q+U`Ud*L-$*&Qb5T"k!B*6lAXe R&I&bYZbH3![RR2YPlfK&M8MCZB-@aY3ZJDNAQjYKIA+h`5KRZ'(F&q5S#kqFPCT i@S!K*fNVQ('q&fDT9[mV2NZb,J+kpmJ&P*QdG#h1@Z+50'2+!p6k4GSfPFTKf3b APkUd5YNZc'qlmk5rlF&IThiaCajUqYm9YY@R4!jG5%fmrffT9f2K#dCQL#(aU#@ q[3A$$i-V3$%9c`V(5LcFiA0NS([J!mj+8r(e$jRr!#eB(99GCC!!Q!P"(@R1$ki (aNPVda@"rc%U-%Af8J,j8T!!$ZL8bq4aaC2*8HGTC3AeqUF`%!HRh8-VZi8S4Ze *+IdV4b`UeV%F$0j$c'2i4DFDcUEN%$$fC0lBDD6JRFX,HhUmUQ'!+l,GCrB1XJB 3M1(P"iHEPV!M0#6XNP#8&1e#AqHVcdDUAk++m%lBGC*kQ'rlI&U+jf,bA&X%Z0c S!8hACX+ri-2YNd#55B'Sr11eCqQd2)d-0$Q6d0%U'i$SJmCHMEi#,UhI`lZ!E5H 0J)lJJBq0ZS9H!bYGfj[D(UiT&[8D#C!!51hFp%plp`&bXlp$j%X,G5%)3C80!SQ 89&UeU3QR)N%F&5P$qhdA8+H%%GaG#N*YU!q0L13eAlbfmUD&fji*UTi&X@H$26( BEd"ULpk2DTm)YB2@V*58l@#mHR&e&`XRHkLIL+e0AR1GrfiriPVjFdrjKUEd)Xr $S@RiG!XIKZ)!V9aXf(TJGAaFda"3,#%CV8aYq8LlDhUHrQkLZM*CFd)e@cY(!J6 j+M$0R9$Z--AiN!"H5F0UACQ#95Yi'r$hpM98d'#d($lUhBGLiRLa8RNQ9SV!6q0 )D8&6F3(c3db&'HLYD,0-P#PhLDRINHAq2%+LMjaa#Hi9K3T[abmA4-ReBJ'NS`Q PrFiBS@j@*&ZES6XKDfba6JcZ3H60frC'Ap!f"9-U*[,VmCrfU8aF%Q1E0aRR)$, !UlAY!TT5k-rUTbCG$UT"C*-L'Z8e3[)m@3SP6$e$`aT6J[(%H%RhFh!4ZK8#'&E ,Ej8@T@-D(0e#YQ"Uc$TN602C`D5@%IeLP1bFV`kKJ!0VZZQ`Bm8p3`Kcp"I0[5% lQ)Ir(`hi(5MCJhMNAIY@8j6qU9k4Y,G%eH2d'6BT"bc%+iEK`f)-qMNEa0*aIa[ $jqrK)[(ZK0mQUEPJ%dRR-AGc)dE%IiDBTU9%i`V5"HiI4lUR@H8riU+*#0V1hkQ k4Cel!e'qfca44iCmN4b+FiIj(IRdk9aREhEHha)rP-I"163U2HXC[c)rI)V-Bdb b99hKX!2$4Gl5*$CFCGX@NNJ),c$K,dC2B(LNp*M+[VVEq4R9iU%Z8Fcaq6kBP*a QXblFKK4GhNlj9FH(I3Ce&Hfp%QJV-GBBF&pLr,j@FT)$5pU5*D0,(plPpkNPq`E m%"rKbL9XA%VI%Nq(Sc4,[rK3,EkRkKQTcl%"Vm4FLS@0-!J3XS-Q+mmmAS60Hda jHS%&9J8mqQmlrbqqXfkhRrU0E*jN-CiV+N,XXN([pr)f1%hdhTe1r"0&eF+`)+4 2P2`fE*!!mJ1Z'B6iV#!$#Xbr%kK+NSNL*N")2P4dHS3Bhj5QfDIX!aU+@&,,Kf` TI![efQ@Im+QH9GAmm#VqT8&[+mm!b5HTjA6N"J*lfX3&$@%P"hkQe-G#GYeYLY3 +!SbSU"[@V`(QlJ6AY1M%jZQj(M"IhPdUI6f[YSUqrcm[+,H0kNJ&*ALCK,Z@`iY jhRfl!mkcXQp&LEB$!i+T0kjVeVi*A3T-UI`db,$2pXE0$5&+KMq+95a0*bl`X00 -)UKbqp9A[PCr1QG'l@'P5kCpM#GZBlSTmIQ#lDd+qUYrUd"HKLS!8dhAc"6",`* '!fb@qLVI82KYG-(R'-&3-H$IHJfZHecd$"Z*XBN5hSAP8%Q5B%1HqJ%(MJT+4$A 99k'5-+hA5m4)YS#`K*P@PK%-ZlN0b+4+'Z-"+BP*NP8UHmGIH(feYki4e`0GjTV Y-[3hc84&DT+BMVS25N6IGr&kE$1I`TEd(j*d*4Uc+,TZQpbC05DM1!V!r&bX@Vh GfNFH-1UfiTG!fqHeL3FNBGU4$EI"%ekGkH$X(bYVY+QF4R$M@(JE8ZEi1!lbq0T NY`8hIDkh&B(r%TB&6dfa*9rDA+2UH32S[6Ud%h4U*9eS%HNU5Y(YIVQd`*iqlm6 iKN+28H+R+p%*YeT*mql8d"6k&J3Xr2Rk'&da6K-9dbX5r3J5bhQiTbIEG#E,Z&p DTb%D*G&$Y3`%28N)fLQ'DVGH,$l*2BbhV+f,&40*VXS-*h3+9&[djG-f(ibYI($ `Qpp3*RpC&*T[I9N%+bdl'lC)G,DU6k#m&RB%EPD'0QHdA8@+FLYF&efFfbEGGA5 F&cb!aGM,@,#-$A*!r)!i,U-TikY3U9j)U`6',C-'!%EG8++Pi)QY6KP6@liCX*V Id+$Xqc"&AL3T%h1V$TA@iN3iZRU"r`VX&6i268(pJAb6HNSpKB!0[klV!UF1@%4 ,12KhXGcQ(CN3)GC#L4N88IZq+@5%fa4S9ki)r6-jP5FHHDbYe0K"$8FTr0mj`m+ `05iZb+4SjIQPr9LC23R)r#8B)aFM%4@G2$)62iKZ$i@FNA)p1bZ14&3m8FXQBbX 2G'0X6&Y@cYZa!eKpqFH1ef60+Rd4"k3pYCLm,0%I'lHNT+XMHlAB[I[qIeE9bD+ AU#ir5ZmZJ+eA(DRi(KMSR-'`SK85&2De@922`k)jq(3P(iEN!0Hb6VmY3#,&j6B 2lC+&Np+&QC!!pZ,)Dl)JRpp&(#ASVkblUhS[T9'GEad-5VKpGpRk+UU'(I'S0-@ KrJT##'"3%qEGk-JpVL"VJH(ID'ca)+[VlXQ%$XbYBDm,VI(8KR4Zi(D)6q$+3@, VQS,RCc,L+*SX)(cm!cfXbQPpN6FkYAkl1G)8'PEjRm0T+N)Y,eTX9H%'KLq2"MA $-b'5cQ8N%FXMY-qPadY&*M!kqdB""XK(T9"lDB05eDl$"K3bJN!0jV!&PcIqX(l rADB2ND82))bQZ#NLAPqKGZR`C)"VNTm)1M$`9ZI"0JPk6%DMF+[-,Gd*,R369G, +IehjUkI&ShhUF,Y@i1S&E`DD4QAP8$$*REb!*G2MTdc[Nd,cc!j*8TAD9%jqJek lq)ia@EAIH0mHTE$R)C!!VA%D1%m4'h*`mbK3UZNI'ZjralS#$#5F%FNaXJM5"Th K3)rA"YHM(9j3CGDjrb$iNC8jjQa4C`4UfT[8J0h5TbM8AN+bCIPR`c1`e%SIL8L )5NMJUG1[cf%r6k)IhVjiB+!VNhUZZd,+DYZlZRMkFGjc$r"UCT'bbh!cB+BK2D$ jh$kq'1Ar!GG5GNATe4Y+Dkc*[(VhK,U%l"39bJT[4d#U2Y&8&Z6c"I-%Gk4`5*C 'CmL*@GHlZ18p0)NGRLeeQjX+IPUB0PGrd4'!bmk23h"-hN)41)-aAP-,1H0Y!Aj (31cNA!N1b5fI[m*6B3&F@#Hk`-pcb#5UEP@B(UBeJ81VXr8FA$fS`6lbCBPpe4d E$KNZ`F'aN4[4j1+fejd@8&hR*14PiJje!%TEGM+Z,$4R"!&M$m%@BM,XX&-`a&r Q3Z%Yi$BPEN#A[QhErPeHe26R#B"e5#jXpYHeh@6qiJNV'58J)P5HYX'+kVGiai" M2A8KEYNJYPl%Y([D(",c8rpPS,BCFRfll!'%iMHl&EaBI(,rFCrjh56S#r"6$@a 4,,8a#L3)'**d)PmV0#(*h$CVYZJ3VM!3HZ0Ui"Sh5IC)CVA1b5bBp&)rQ,UQ+2- fR9fI2Z1(UQBM`I'q30#VKcI%J`N4I,BABcFQfl6Pepq"h`N[KL"SG0XRbELV5[K '13h,qh`GI+A!$ZGId5%A@q@rjGhJ%8KJ'#S$a6pmN@NIJ(!b#JPCL3H"2Tr%+[5 (4dY$c&dlX3l`8D3D!XHdFJpdJa%r@[k9S)95*5*[%4,e[T5i8jpE-$fIR0q0a+$ DBL8pHme@fi#Z+6b-Scqp0rXbSRGjmID+!6a5!"kPNci16SFDiRSApYB5#Thpjra qJD@XY@m1`FkiGQ#jkB$I1YU[pK'EJk"F1$IH`MrQ(d*d+S(TNU6-ckDEmZ0A,cD 6Fl2"!B!'QaqV8h3fEpNIhNm*Kqe!4LCE-Shk%mab6cH(c"I,GXX-YP'2FU(G65e Ee+b3!!X!84*`EJlYEpG@%ThM#SCq`UhiajDK#P*2(I(29#2&1qZ%LFS-(ahKl6` 9K2h8jYFjl8hjL@#ClGAR1eBibjFeQH`4dd2SDbfEJXdfC%`I9rTPJFPi1caB5Gr UK*K[8rD(a`R1FF&C1@3+&F4"i(d)JZC-2Nl*UJ!PGJ`aA&k80%-$MGDb`8*9*Dh +*eiN%Z%QE1M*e+1rZKhBR#Gl2hmH*JM93%QLkdM9IhSI6%bUQU9N&3KHN!$XKh' p"iP[H2J33EV)0Mp"fUEr3keHq9kVBX#%6D3%q$!hYiATTJf5XaS#NH`*H(XrR,8 CTVr@ZFlFh$DHf!lU[a+!,3ZZ&$KdL&3#QidAjAGireQaZ[8Y(#c+kqjTY`M-9[A 4B3r2!*AlA[CGEPRR!--$lc-)dHUIESd,K&)8A"Sljlq6&eeAl@'kIf[V4F4kGPL 5q"8ACi'VB2R,LNiP-k+@',@+mRd$#GIaBMQMdEQkEI"h-D1'9qF-mb1ZM2prVjK ZM#`!qLKLNeLq#&U"`Ep4F+6HG2(*S(-bQcSjrPj6Ze9JFI18ibaVmJEc3Jf6G2% 2pGd'e2Gh"'Um3DdlEDABL*!!,'kIY)"EZC!!5L3'eKc(4iJJZmk62mr!rRi(Xr- TV3C9+b,N0LiRr6-iE&l*qr&)Hi1A9jC0d&J&-)h!IT[2AfdVlkh2$ZfLlCZde5& &fM*"iL%(!$R3ePiQ!#RAV'er8b3h(e'i,8b!@c--aC&(3$pSm&FUNDJ,[Z&Krhp hAh,RedA,`CLE`L5@kQHY#ha)bL%MZ!"iRV$PZrLC**V@MLMhZ"dmjd3%)P6dEKr J#f[lhdfSJ(PN1q1@br$r&3mdbfqIj2UI2i@jIEAGpY1j2UFllE*rKB9pY2BrJeI `Y(q&5r`SB""8-2DQC*H+Z93$m3B5mN[fe)"CAhC-%+@b$@Hc'XBjr'FpPb*a-,h Kf1MXMd$)r-!j(VV!XQ,NCbG49AH5(j@p(aef@hNM532r,VC'KT-'bV0+lKJ`LY0 Ifbe9M&mYBhfH(TZ%c*EjL$fakdX(CpYGFY8JbH"',DcpYhqY"QJH5IG+T+f064' lE"C'[9@cYU8cCKdHTVeif,Y(F0!@LCKQPkNJQ(p5EpDr0bk0$f$1CM851UpFZcG mfX9I1E8NB&F1)P2(E38AfLTBJ6lZld#'5q-jNY#Q)1-h#!KQI'9ZehPBr9I@L`m Mj%HpVcFMKbN@0")8)982[BYJp[%NC&2eZ8`#jV2)$"(d0Ra+E-i(BraKcbl1UF+ Yd'l5QVe!0a&D8*XqPF%A%,ZKThLfb5X@,#ZdIdA0kT!!cSGjrLSmlAHkp)cd&LC #*Aq@5!-ANJP+S3e4DpMX!IK38chY!b!(-U5XSj)Trd"D@r`LTi`INJEVBHjiP18 EmPFKX910*&0Q`H,45QNG+-U-d[eXB#b3!-XM"-YJ"-GVj4mKZA*'C&l3ARKSl0A *Df4Fkk2*f`"*15eN+YNM[bZV"QMr%NIJQhba2!%+@XHmAB@)TB@"USKpQrIcQ(H 3!+`#J5BbBIIdbQ"fM+X*RAqfa@1#N!$96Ll&(X-&TPdNV'B+#Fb$"8KP6%Z3!)( +P`alClb-'c[5N!!0RI@aLrLCF'kY"Mh2K*!!cP1)ah%j8YmBQI2rI)eZk8jrb@3 ND0bcNP0KY,+JiCDeqPaSAX)XDa@GKeKq-QZ0+Zk[jmN9KC@C!MTEl0C'KIAe-GH kJ-RYk!N4i5QH)`0bT*K[6,XlBe5qrbR,ATLP00$)`+'bp[I-mBk2Q1[-rA#KV%6 IqaR0pCjSGDUJ446pmCq+bhU9@(`RM-+iN!#`k6J`6a+i6#-"`GD8&HfqDGKaIPh Z-,9Pbk'a4kB2P4'1(3*i-cba4S1JlUmbLcR44&eN16#RBacZ*Fr35!-RAApJ*Gr %'mqc82GVI,"iVC)LYq&r(4@9AcrR6Z"fmMlf42Cqj0j),IEIjDR2MZC[M[!DXL& UrhqXG[hf-eNcCrZ+p(#iEZABZMNLReP!R0'-faSc"BV5B`M3kLi!lJq[Zhb&qLe 8PLcB50FQR(95NX1aVPRK([lI$[QHDq$'FCpC(L'`4kFq&(qYkN1!`I!eT6iRH(F imf9L@hC0FVIR-dfdNp)S$%-jdK9BJa4(cQ)Q"Bh)`88"VaED`SHC8pHQRB2cH(V K6V8J+"A8C0Zr-L#eLLIbN6+Ep3aTL$6)bBAGr'dj'E),S9&IHdEFJ105aY1DGL* *-6XN&(`T($$m+ali89@-clIr(m@@66,cc&G9pq"+1NC+29XVYG-F-rmKNp[E**l kXJTR)Fb#mV,p[aV13H9NS*`*%#A-(mIiM[DaB-Y8ZlV*)@h3TebRpD&k8F-N1PE C8E`B"XXc%@X[QTiTTrJiK,ISAU`%USNeUCkKUJUNa6d#,HlTAXjMME'+LALRbK` 2*hYJ$PH29,ec#a-3,b!5DeC*LZI&V*6dcCSHlf!bP(*l9`riRi,YcAkh4(MJJG* rLLqIq6j`b3@kF[ar3[LAf13e`mhLN!",fQ+DAL69d,,0b,@,%qj2QbrmB)APB%r bkhHNAKrLj8T5,!9Kh01dFaTdcXHEJPJ"I`EFBiP&UShh4+IcRC%+jdLXq!jGSE9 mGm4`CH)F'XU#jEPa1,J(rVBG0jP!&,,*#mY83&[CP)JK(Sbh1P)cXieUYa(2&Si X5AD0jMTqj+$cMU,C5b2fe9hXCc#mZK,'!H5mJa,30K+d%fYV-(KRjBK4CX5jEDD h2R0BFYb@ANqrrc'6mmcNXUCc0r1F$j6UeG&'VepTH[badP,2+TPVmPS"maq!ImZ P@c'fDAf9M"%JVREb6,C+SiLb+*(#JZLE1CE(ZVDXd+VXP4qKNMUYKf@M#!,AS1$ PZc`XS+Y45ZEe2pTDfqh5bJB,R%I$C0FQ+b,L)Y5plrKYI#*5p+8%p`"GD0M0FKG f'JS#q#)f8%3C#E#ELIlR3V,N6GLFj8$mScK9kb5qXL`9dJTV)qMb4X4T&EVaZJH 9cN)`5Z9`A'&LE[*5$Pc9i#)9#*HpYKPS#@F84eP0'YaH@fm8`P#$D@&!-[!LHf` $T1YS5U(qR`[9i8B*YE5B6[HJMJ-dXQaUHB1X5c6Z!*3jQ*&V(dJ4+i@4$%PZNhD AB@,jhcBZirK33TcBp,8bPhbp5#C!K6),$4$hhb(24#",l5Da+)[YZTHTR$k#6&h N'NF9%2)ZlM1ID`$jA)1U9k,RU3V+9!HqIj*Kj3e84J'p&+qI-hP[GV0XZi8'%ra j(UJ)j!)c+"EjS30M&!haBb)4'Qhi`5rMM"$FXJ#*AIp93$(5Al"HEPE2fi#(12@ "T$1YEBp,,PKPA28p4GUfeMFeHRdbM[A,I5NDjILAjPECVp%el%V3FFD0jaP@jh' ,J5!Jm-$a#dDLjq89c5q2bp*LVHiFHQQil*)b)Y1X`*%RPT!!B44DNKb*iPBc1&N rD@Up6i!J4RT&TVpm(GQ3!0'5C'5l'l-P5PheV8pM-2,QHbRdP6''fVG9AAe!4%P b8rdqLh$i'&Q9UY&964*i2ai66TrMpYKrYd`rESVqfpmIYXApZNIlG(rfhIKqfS[ fk,rYZhpYGZUc%pM"N@VkC5-#!M5"kaUEf%(Ka2dXJHd[JN6LTj*'8ZSj2EMapIP j1qU3!2Z9E"LP39l"EcbjNp'H'I#VLr0'*$E4S#q3!#HPSU,(+qkeDjBPJicAR$` EK)Flpl8ARDF[pA9mca3HapXF*XFb0p4*YdFHf'0EJ[,E#Ypp3#EEq%+%!J$$lq4 "F636q40QBa([ejHF-RNqU!2`Q-Ccppa'XkN9iMl!+mhNMq3+8([iM@V1rD0Z!bc pNHIYbIZ%hfm'5VSrV38U[YcZee#,0@Q`mC6C[fXINI)p4+#h"CL)Yeh'l#!1C16 mpIfqmZ+lU'DKMYjR9`&dI8VG4T-Uq54mJ,H3!&K%`,cb&FmE8BKjaG`!0D@$+Z5 4QKTKaq5'RcIr1(e4HL4ZFM+J5S)hK9)f%)15+#AYfZK%1jh0aUKL9,d4*E$`Fl" kR*RX@)Z'jrT*$(qe%25&QjkLh*d$SM!mR)%@cM1@Fb%#FhD@0Q&P605AC8B%ZQM 2084+J&fri151Je4DPre68PX&H3'L#SE45mCbbND520,([8lNZDR1ShA2'CVBV0- l49Nej2'l&XJh)P'R)f`3aGlGYbhHF"90GR6N!#`,2rZD0jchTEiB9bL"0&l'SY0 EIkc5!4Jprf333k`9FK,fJ+(EY'[B@VhHr1VV6Pq5mX2b$*-3Z'D$h)HSY9@bE90 CL`a3X9*0FPb*LA4mj$JNlc(1mIZff#-!@PV4h2(GfErE$80()hZlJ6lC'iXFLQ) 191)(rNdG$3FSVX%5NK`U#Dbde@cHF(YJ5)QdVCIK[GCQQZ(0"TJk(bC-B0Z#la4 fFVa1leXFV6(1Eiaj2H-9"D(#YbDhSkP)*UPlj!ie@Xe#MQFZ'jKdH("q@0JA11@ IlDD54`Srm2HldJrC4hFHa5`ka&1LQQ[ZMdS2C&3&)X`Z)-R,KD58%)%[m(c%F9` 0RV0VhA9&R,$*k2Fa&l9Ar4S$cDm8@%H6j,A'YGI!FJ)pal%5fk2KQTMdE)(1aKj aXHp0F2*GYj*F9"*+P@i9*pfTAeeQcDa!2epZGRGXG5EA!GR3KSrrCU*B`hU)ccb ,%Gm&dS)Ba3bX0eaIJR`SMPMlN!!*Ilf4J0X@MFdiD`mH-V$S5MIdR1qXP$e%UPE DE*d28(0lJl`CN!"q+'D-*k%B-a2&I&JUCh&+T`ST2q8-`Nc#Ph4YZJj+AZ0RJ%p 3UJcmeV1HPL*[-d*fT1aAEZa"Td34`E@2mYPZ@V%CQ236d5BGSILbMU5mV3AfdqK qCqf0Y6`9*UD*bMp@%99b'fXq[5f5l0fNkUfI["JERIkCZHm[Y*(K"(LAmPjm)iR *4*m*Xr9#YIdk+0PTG@dZVDA9YF&HjKTiUjcdiUDV,#ZZLJ9kAJ(Sf'"l6qr''1b 5frZcpMkYrhIap"adaK[hP3*h&M@A6k$"h6+k&,,'FjN",LiFimJ,mHm"e*AEZSi `P3@[cq@NeDD[1V8Lj`)SkL4[N!"6CM%@+!XEQ!@9R$#%R#&dDq0(djaA#B0Fr"V @2Pb5C)B[M&dSSJFCc56m&rlB#+#!CD'TQP52Z)Ap9cq&qiaPEKl2(Xq(mlAJ[&k SXk*YXJ(dkXQJjpq1")#,GG"NCPekLDBa9ZdM@hKi[#*ri&(#d)4J@IHNrdKXlEh jKk+%pF,VLPlHQ5P&%qI#CkkSV"SNb4$+Lq1-H(#pC2#c*09f&Nr-K(0cT!D)2'a h%2TLb4aGIk4NSZ0#hhBY6D"dH[1Y0*4(P*f+YFV$[rh#VM)K9Uc+`Q@iMe,AdrL ECV#ZY*Q4GYVr-c)X*92m"#Mm6+bq2PZGl#lHKIfpM#`[kBqCk`afXqIUYDq,HG( r4LMr@ReEA4)YY#i2k&*8hJBCX(r-h(SF3Xd"dl3C%NN(J)BL@lf8ZYk6U%!*U5D kF'Ah2V"D[9Dar1J`k*R6ehB"A0!DSR%J)rL)95#4,L&KqC!!k+GXr[9IAEk(hY' LTkIBFfaL`f`l8!eFhYEZ((R5jG"6%i([!ic)H5GD%@4NNK#e!mLk"h[B@)HZX#+ 0NYida&QPa*e+Sc3##9h80#D%@J6PJ-&*rQlH9S[r+2S)aU5UqGBd!j)eXma69dM 9%`ZNd(2FY*4Y'Y1SmFLC+%$GV5qU(#V1qp9iRZL#DMVVYp@BqK2EB-U6kZAD@8i HP*T"NdB[J&P[R5ZUKA[#ehLiZXjI5P,m0f1CfkV`5Dj[N4r$*&XGi%9ZF3KeC4R MqHP`m+mXK%TjdFFX4QMj)c6K-cib*aTpQ%&9J0k,aY`YGqd1UR22A09$#`4KmKJ +"0S&m3$1$A4D9(k+NRaHYHhG%h0RP[8,ad2,U%p1,$N,bda*2J)i*i#-FhK'(C! !BfdqfJ3epf5KG``)j)-c+pbD2'9*S$j#FIkL033C,*LDRdaa0,kAb2P[ihU8Hbp 5T#SVK)FK+D#G$ekQj@H%TQSrf('5mX8q%PY%Am6r$mQhHFe#$"iLdc!,k)2J!'S 1%ZB3G'NPaPCi`0Gb&R&'&q39YZ)b$'3-J`!SEmEV0`&$YV1'e+F5r[pb"BC4#ha 32iMR*kC*Z6A2!&-2BGjcYiM)bq'@2RG5mN,#XVpTKdiE"Tqcej(a@)6EP4(PY,E k5X'&5e3mL)VjBK8X[!-#jq`EhFel`SM&#hi)6k8AL*UIF`I(K8cm-!eK@(Fme#k DPG$Dirml`PKTeTcX0f%`ZNA+q6f@eYZ%IU3NM8,AP4piYbB2%Y!Q0(*mIH'6aI% &LbY)LPl!aRQU4"1q"Q[P!!NTShaYliaH,4A-FcBIMZ#SKJ'GJT4lU(b%6'bI!#V jaF#RMc@6RPEYFiTYaPcBraIZ&m%NrTZaZ8!qD9*mQ`hld![PXeZ)&61q$-j$dej j!*XZEbmS3j,2G#4ChX4@@Gkp9Pd9,3cii4U'5-a0j1ET+RZIHAlQGUVqj+-8qdl D##E"&mjIVBBSp6C"5'raY9KlQ[f64EYG$T4G'X`NMk(a1jaIlR-kFUfD5Z$q%A- BVTMjEIk"!MQp1fYJ%R@GId-DaNqT'2#ihZRIrRHHDKZqe413!(KDI(I3K"2DVRq -ja$Xr"l@baIjSLY3QSMNc@8Mmc)4FNX$!(YdYa%fC3&IS(UHT'fX`6M+[N'"&PV p8%HkIE!Ar!qhpIGB4re(D-mVj'Z",d@3!0fpi44lZa&5%qTR,--blF$[pr`$()) *Q4X#5`9+TUiIr*IUI"FUBk"4'*`,RNAq%1UrF8MfimSZAeQZNQ1dH@TrHl0A'1j IhfrJKc'+q$4Bf(11i$Sh4QUhA6H[ZT1DQe3Za4)8lSP"#bP3`!J1lVl3RrShpNH 9"4qk68j6[fdH-M0FjbdD6TCc$'*,QXRL%LJYFp05Z4(*m5*P-FcE6L"RQY9Kh[@ 11dmF,G@4*K2acmh0qM5"l5UrfmL2V2F3Ra-0BjCRpE*bSK,L48phc@[[1!XAKVD Cfd24krNB)3YNIVD@kpVfeERFDN%-SY',,q5$-m0TbS+qq)[[0e(1RIS*Rrcd89P 6qUFfCLC'1cX01aCEThI"UGBP+j*C"qKr"D)G0V$FIQC-["F,5YFUIH($T"B+SlY +mSN48a+[h!6UpJCpLr-K2p'hcL'U5Ep,HP34[Gda'0K9@S*SeDZVJN3`#,pVhS- lBTdR[2BTm$6ip,YpGL$,JdKR(5fGbmA(6k95b(Q!(FS5ekQHTdY(-6F[pm$X9SC q@)&QkNRkPFDrX4Z)h$)8YF&XJQi`+5Hf(#Q*'fkj'U"k2[!4Dk8T$&M@c!(2d8L U((EbrJLL5hIiT896#j!!3pq`@Ad#NcR+E-8q[YGF'U143FJ+-@CXSj5Q"!IiVC6 P4GK-C0[9BqC@H23+QD#BY`&6*S&%&)14Jf$H[+A"[%"$5*jiF4d1JqI`YEq'MIm 'Mhm0"-rKErm'Lhm0(2iD%BrKA(m0"riACr#c!1Uc%pM"N@VkeqLAl#C@Th(8rTN HR#`NP@5p5!qSQ2-KbIIYGjd3HcSBQ#0E`2LF381dZ[[lYAGJqS9!PB@8EY-%raS Y*G*r9G5eId59mZKCTAbqYki3kZ86d5Gr$fSm4m81%[e2b*04E*qAPh+eN3R&#Z3 fQ)RkK,'FYhZj2dq'F0VfV(8K*83[c+j'%i&)PX[V9qr&p+cDTEI-lBE$9"2Z9*M %'Ld%*&T"%qL)044Yc!qDlFp@S-*eC,R,L-,IJTfTXHAQ!Xl40k%[%SNM46mC9Yd CDBIN[$3[P!2G$E+pjU'bNF@&UUD#DiBNG1Q`V3Fd*ZkZa(Y%ZF$CL1qSd1E*JTL 'bR`1YEXb28Eb&r&bD*rM5Bd8PDZ)Fcj*&hN+6($Ya`1a9I`$0J@2Clpl,rp&IP$ 1!KciVPPqUr[#k(qXN!"-ZRa3MpGP@!*`4L1q`'XP-*35rCH*V34J8!RRjR,h4e- ))ErfEI`Q'YMfME)pGrIAX`HLCkaR9D,c1B&PX,L11"dCaji[&k!B)[XfjP`[A`0 %a%PbCSSZ@(%)-%'rq[[JXS21NMMLi*k#)DFehF*PUkp5FP+BeS5mqB3!b&JA`I0 0F'cKI3aI$SPCk9GJ!Frk[cD*,B0IB5+&M-0)YbJ[(,T16N@l*)-NAI8$Yq$YVj, b`r+B1#L8Bb5kS1Dj#X&4Kk,XAfT"[qmeb&2+(9SV2NRQIH!DejT,mcVFNQ39QXE B%,5Tfq&i@2mUJ+ZbJ2MKJm+kF&*kb-ImHYjm[A!)(EqN*rR!M,PDSCYV*L4@cLJ A)+9Gh6[a!dCeTNBBGGJZ3IA3*(-I*Ub@Kj)lf,f$!dFGFr##fGYMcqbp%X'EBMD CQT!!TRr4"1+[EB4U#da+52$K,`&F&R1jR@MmbQerZaR0b'JTTSqNrc'JCH[00C' 5JGRNm,PXDUd0aLS-$4hdS+4TaX&QE@Lki-%*,!Lr8Hq'XE9+Q[4%mjCLdPlLHek SS!VKc"G-REQlI9Z#CYVTd23rrdJ!H#!MVMT2*IJD[)[3-0X8YIZEpS-ZT6GTAei -mcq&L@Jl6&6jShrlQM6i9qD-`G)GFFG2a`[V38U8%VAK-j3EfK@*)qF(*eNfR,, 09c$)+Zh"XQTTi-Mhi+*APRMUBFr((b8+[bT[RXQ"kQ(8`43#XCc%r$)q*-6rIK- KE5IEFX5i%(["1mp,@(l#m8BCmi*P$h9$Z`0QaZc`$B+c$93`E*IC'#2kEIE1Yp, h2@h6Y5bjdU5`0l9)hQpi+cjdYZ+3!2!5Uj8P(L!,CXa**pj)m!4i9TdlK1YpE5k YTN*MSVe"Le#D5BQD@cffXS,h[[99bDS8"FlErARqQImT-*dC6dlIP@DP(c)NcHI b)B4$VQMVP,bHL2T+4F13!"3hdq+QUb`VVSS&HPi"kPZ@PNhH(q$ZFi&Kkr3qPJ6 MQ9M)RS1C1p5N8+ll)&#rCDe4hB(3*YS@mGT#8))dL,#FSVeFP(Q0Q4A*B1XQ46! 9mb-r8Q'aArZYhMR8VD*3USi`r)KH49$Y`Sa-cYJKR`a)!0hf38i!Am,C$QAIV8G lc*[TaG'BkeMYPqGXZGdmG5Q`Z*3Bj-d0`*BS"NJ%J@Er'6YB%"r1RJGCYRp-Y-M TF(mY4pE(A*'1a0lAF-P`B9PhHeFk*UG64aqr9&ab!9-V`f)a3Kp8ej!!G+T+DIY KJlFRi&(#d)4#`chbQChllJ-K%Ib-H-0"`,#6!NMNSE38R,(''l9GAE,Ki4XJdF8 hG1CQ6Hj@)Z8TP4%(),Z&XR)['Gf`ZfS1$P-2MdriI62F5C[QaaYQmSIe"LRjGMK kBJX!3SK5j#q"i(j6(8j&r!YfSDQ[Je4-@UUiV"31@AK,q9p3LpA8[e'fd)3G%61 Ul5clCPpL#'MS4qA5mGD#e"F0,-bFbjM'-m6mK'@!84ZaI98BYRZX6h*1)hCH(YF "kGfT-,$3-aQX)jq[V+`P@`iU6BL*Tp,XMpP`h00Z"kC"f&m&VkQ5V!CQhdN"P$L l*"30B&Kdji4IYjIF5&J#'iXH8DVr5m5T996QDY3fPPRCq0,q%Gl%6Rr)ZNI06,) ebDA`(l*Pm-%JhMLSeHAbI$L@"rpP#i-%[18q2EM(`-4M8faVdfC-5*d#EPHhr&E #5(MhUmhXm)Ajh2mFYA$U#Xbp66N`ap'%U'Y'#3lN39XNU3dfGF%elqLq$hhAJrh 3E@LjkN"qh-0b(@[SI0R`hP9P@V%1r*S)bjHI)Ya"HRdR%kXM53j*"H8#A%af-8b Sc6(@%D$jie2j,LPkGKrITV3R!ffek6S'Mp"cK,`iTmijp9X*f9bKQ)@Bp@`4aYF A(+hrG1ihF-qMPA`8$T+dTmMrMBBf-5YRI5N#KJaMI(jjY[5XFRY0CjjD[(@6#m' d5Y)9,i%2-Mrm)HKXNk[!R*@M(H[-XY+#Qele#ZNUR#F9id)IClkBbJ-(N`K0l$! !"h&qK,mI5'rA,T['4J6pXH#b)UpPX&1T#cI`c&mjh5L'K`J0-er"jQ`d&4rK0`b e3[HiS`BE*j'CD$KEe6d,#PD$m3Ec!`)U!qkGEd4FAD+4PFapjeV[b1!X'f[a93& #8,Y[NlL&NCc,[RTjEd2J'aVSK8mqFelX31T3erkC@9#FrPe''aGYK1HCLdqY"rV he4Q`&A@#V`5mPk"hMJ)P(1Q6UFB@R'H[*p&JAcYiEj!!dm@1CSEe91rHHKRbT[M `U3+fC+A5)X21-lU[h%[Cdl![K`Q3!,G@+"2+5J@GVD&C$HZ6lQ1-!Ikm!&ekZFj iA"Hr!,YX8V`8#XT$J"!2jUSr,A@16r)Q-lbM'20"hi$X,k&(bBl#PJEd"3R3#SR &jdB4-plL[d1!m'"ce+!KHj%ZQTR%k#56@-9QdS2!80%%!aPKE9Xcij,C0`@TBHB `p-cHf'U"XA4QBRqD`Ba#mXA6r$mEm#f$@Ia5-Pk!lUJS,H#V-XNLpN[@M[fZV(# e9EA4["L),5M0I"$)%6PjmACIYQZGrLKVE"H`lNF#(0a6G5Y19G*eh[F0ql32r,6 El-16jDEY%H5BlbNR#p,cm+3ACZ&HFi`6))Gp"+'SSJpiDL",'jekR2)5ci$[&HA J6!YT"U8$r)A8L,KQ$(9HD()(8KX9S-ihCfIPRMqaPpR+D9YdBBi`6*N[AR+i3RG X50a!RijbVbq88KZIVL1IaV`'6,`VBJqYdf3h*4C4KjQ-PB(P6LRYbJ$`EJ&J(6f ("[m)-hYpl840kZ$U+2#5XRr)M8QG6rikX5LhV(f(4a1Fj!plr&D1!$6cIi0N8!N FIGS5#,54Yh&GC2I)&h$3FFJ@$!4L*f(fKf"B5AVJf%m4D,LqrKmp!jZm1MRLFX[ Yj4$ZH3F`L4MJAIV0JBlAa6#5Y%m9hccc"!`%B*TrNh))hP8)Y8hXj8T)*6UP8DJ #6l2'dqSY8DHpNDBMC42++)a61[kGfAU5,$(1G&B5)!*HU*d`C5AfHdmCmPjl!TE $5Cfffpb-@4i6Z0fpJP+l'bh!E#G%%,(3(+&QR@PR@2Y+Gf2`rN0KhT20$EA"Y0X 5+JJXl3eBfKPFddRN+c610V3hM"8N1YeUP8!Y"P$LLMH)lq996dLJ28Z6IZ)YL-H SN8DlfN,Z#pZ(dYJGD@`a'G[jZ5$&%G6&C33K01&Y9%4QkkphBT*k"cDI&9S$8F[ M1Rb1JD"#+C3@dCS,feF!V$5G,AeUHqiih(q#aTTQrNh1k[)d`pGETHM568r4)4[ [pZ(Td-VmIAFrbb`P&jZCEb@-CV2BC[die'f!+MNR85!1TUb!h5#BJV3D+P51'(j 6L[H*EU&p),Sc)kIcVd2-KKI#"L,2hiZE#db8A"-lRZ2J3,ch(pQQNrpCZiNE08V [`546cP"Hh1NK1BlCPS3&06$MULVXX09[!JPhGCqPIRD!1lNZ4!j"j%-jYbYa@'J !Zf#-TE2ZAj+A"*jiDi11f0&0PG2&k"%#9F4dBarjMdfFK1D%A"rTpSar-d[`%lm $26l4Lr!8rQDhi&q2i#Rm"Ip!ArJ-J!A9c2M&UQcj9C3XX0(*8T2(90dA93,CAkf G!L(cNmiFm@a!rcjdqii[Q9c"N!#H*F)Yr@N3#@'#Y1I%EK%Q!Za$Bd(rIjR[XYQ "BN*Iq&!DG+UVjc6AV3-1Ydpf0M%rV[LBXS9%!SC6P1Qb'5p$rhRe[AGJi5%Dr`U 0PJm-!SjVNMBm)!''*VD`jbFVNj)FQerrIaB84if4hE`)9#pHT31EL0fIFb9dXk# CbDT-Ka%rZ[TH+p!@Ep$#LlKUi00rq&1RqBH[qRFGcCbR+TVVK[pDNr'4Eh1Vcq2 6FAdT3#8*l$d1m51%#63,IP9ThS0caNJ-T#AiPBN@`XqFI6V9)XH&5$rrB)6+ZRK C2Z9)bjmEpZ@ZmJS%p-lA&ra2@3S*#,N32`FE&jrqV@'[k3dfN!#VSV`MZc"[qk[ Vh-L&CpVl!`4-E3EcIYD%M@m&'r!rq&'TPcP8!Fip9YV6Z)X$!1S2*HdKlRriP[j 9Y[EV&CL1XYL4&F$amL0I5fHI8ZjYmr`)i2KYH(bA$q"+KmQaiI*YQ$iGNi2KY)I *T$KmQLBI*42i-X2NVF2N9r`@HIi%X(`h("m1hI`)8(`p23q6@N(`p#F(`f8I2Gq (bAf(b8hq&)3q64-2NS[m(6Mr!43I$4m2NX[m#9$j0A`q6C%2NdC`I$3`q5em2NZ F2NDr`HB2Kf+(b+Ii,`!(EPFe%B@TE1$6@KY(!eb`ZRS5PfSQb1pGXl@Qb[Dr,IL a,r'iImB4#fKMV+AS(b-9XFk(q3Ip+25'SESj!Ul"lJE`e4-#p@UEXhdf8)$HfUb a255&%,BDm[5F)*F3$[NIreHJ+9S'!HLk+LBYeHPGpCZ3!1UID[e1HRbM*@Np@Uh hra(&**2*rEa)V,U)&9#P4mLPLSARG,l9C0Y`,p5Yq+%,b*R-[JXlcJaLI!@UiDQ a01I0fr'(MXH%T0epGIR#AbFrE[Te`dZYR3"qSX$DAEXh*cjV-Rr6PT)T-Zd'P1d GLbb#TZLl-%[6PKl&mK1c4fKXaZ[&)I0lKV4A($-2L2UPb4Di,E5Ma3#RE8jZj@4 [QGDXfbFi*6[&RmBkY-9iH(G$'BQ$C8896$k0JJP+YdSk(E*T,I4[P&9ACfeZ*V+ !!PPdVk'Um[41Gj,cq)-4M@'@[!lZm+J@e33Q&1R(-`2A$8GDNN@la#`0qZ(PY#' 26kH!a5X%0$%GFrHaq916FBVfe$!lD81T6#H2U#ZFXH6'l"@XBp@K"D2Al0MSX6H +aSEHMhQJAP!!)0Gp,JMrD+jP3j'C-8Eb),A-(J368IGTN!$%bm-0+b%@+ep1$11 15ZjH9i3a6rMT$A+rFD-b%rcPX2m%9NZL&fYLNk6Q%PS@GN6-d!#9f4@6@iiPk4* 4!H3jL9S%A+4K-rK`AaZ59)ACI3(p'QcUG0J-GK&P(JM2d9SNj!`BHe"dAp'@i@L r&DSM@[01+M,,f$lC*k"eI[T%EBrmqH`[Z&eD'(3T!iZ1prb)H(CY,B0'p9Yircl )e6UaYr4kjb(+%&S4D)lU2YQd566lGH92jHKHBKK41UicVSUQHr&p5"FrI[pr#%@ 6NDrCUG0cA$edKBEIT0Ti@-hAieJDa-r1)-d3Y5dPl4"ape"VaGRVUfQ82h5meFa me'hqcD5!!0`BA-HQZJ%Y6GPHfLY,kIT2$Z+AhJUHm2!F%cZ-J9DY-qqPL41i&+D G[qREVFh+SC2mbS2rDi5LH5hP0r%Cj6IR@i@B85i(0ZVlU)X'YC,(m[FrrLmZlS` pqUV@qcpU%c"H0PV@ZK@D-cH0pRk$0)M%9'3$jp3rrhrqjkSQP4Zkq(qI6KVflaS N(%+jd31G$bH02+bSkGji&$q-k[iME*iBN!#$l0NfV&HZZHN-S*!!1bFX'r2r@Yd 6%RAq(GHDB$X*m4lJ"d8Z#bC0f21S6Vqi@0SqdTj(1PqT4JCQ#erQKG+`R2c"62# Lfi)R-GPd(iSqJXDr8cUpRp("SY'ajlGr2MeTKI*Z(qU*Pb`i!la2dIZJ5rpSe%T #fB&L[SCH(RfKc4$$2-a1HTE%blf%,$LC$@(Qrd&I$mI2Q9alKN+1-PQ0$+J)TBA 9"MeZ(bikZJQfUK[9Dh"E!r$2U4Ve,-#M5rBTN!#rrhm(dQ4%Hpf6D%l"0jJJV-i K6Dfb-9cXCAdR"+NfUcKIrh+'l(0#)GRSDKP+G++!CLm'JNbC-*J)"$5MjJY(TI, B!jDfAd!fV&Z(2rkCc81Z90j!kpAKq&!C!ahHQ,A[4FAd4Ej@l!+6%1"DGpLkp#e 2(0`ZXq!p-,eF9%VV4S`1DQSYp@NKrL+A'+[GZ)"eXi,Gh(&P6,p[2$D9SGHL["4 ,39Cp@,bGb)["(6aZEQR[JSaXU+p'F'NJNCqAL+Be3`4bbhhh6pp19p2ZRp1-4Bb KaQeCMEp`ZQPKjVeQS$(V8h!(Tpj)#-DURFk06JhcaNm(pHJ#p#b!FpjlVS('i[* 4!#j5qA"rrb"U+Na*qh!GJd,)%leeH6TrIm)l8Hka@F8rRKVD'kR4Sr*r#cjZb,5 LFQ+GT!9X&"XIa%2kidTJYrL8p6a1fBRUL9Nr0EdBpqRQ425021",#j'5Xi"0rL# cdl-G(ZM0$ZkbI"Q(M$#(H!h0YjD%b2+RA&--@(1*p4D)[Jih$!ac'LRPfk#@f9L -CI*!)bANmfPI()%PZEMJ84p59F@$`ZljkIVdfqS(X!+GZbHB!cq'&(#p8-(!I[# Q1XCfklfarcFDX*c-c2Tbmj)LpEhhMKG6Q5f,KP`*eN@-YqeF2Z8&pA#J'b$5RXf ZBqH8b8+Im"#U'h1b`$GrjciS@UjXlC8@5#6b53MP%-EBGm2h&Hi[rKrTZcX-DJS e(ZS+-4NI#1f0c9N-Tlr5$(`GE'PLdZ"AKSKCPG9,#R2QDTP&Q5he3M)fI'V)ZZ` R)%ad$&"K#kXB60$LlqQ-%p*X6'ZU6)FG8de2dA,$(#B44mXQVr&rIJ4!)BqZD2c 3344$rhrZ"E%M`Y1!klM*%1eXqK,+#3dGH`+PGFK&akq`[qfbdJC-ZKC44aSJbF& #%K*3XIka1HGfGhA`k3I'pX1Pq`Z$%#p1jV8JKk,#"$UF!$K19eDD)`2[V1UEhYH ,8B&`EdM4d)6I6*[%2D(9SHF2$CJ&Z!q+MYkM#mJ2LYRaEX!UXj@S6@1K,@Xjich (#(!pF@ZmpLVLj)ZlbRGj+BajRr#)`kEK$Yc96D2f`[QZ6LZZHBHj42p3NcUQ"!` pD)$Q&pXM1V*aaKAZA0CHP'dJ9DA[lS$,jM#+k&(%lRB"U4Ffjcredb@!L[S(chZ CYP6@(hYeN!$IZm'UX1@EpSr$*m+%fT!!&"VQB[UA"PkF+`i8EqfYbdHLa2aIP'* LPrJJ(16NP8IFP*B9-bDFZRUb%3LAeGU8bmb3!,L+beIE!+pE52jaqYUp%6EHLF@ PTq%`AaaBi6'TK`fMIq!Z0bL4h!bNGe68Fb19!B&kM)-ClaY*0NFrRVJ@bYh$D[2 EIBY)Z4MGaChPqlIFZJqTAjR#0$5Xe&8F'QfBhi#9iGII6dfS`pLdd8D$p`MIYcZ Y`pQjVmkbkFAGZ#8J"J"h)qTV[&ApbY%+6fFF3TQd3c%'1h"bqY3D[M!'2hVrIq) 4#bFb#15!hb%JJ)@ed6l'ZkQKbGGEcS$k2rR(h1M(k`cr"(CV9iA5YmaFJFK-p95 2i4Vfi%[Gdhlb$k$dTDX"R513!+c%m2p"3%q!%a-QCGJ((-8!d1!AYSi61r&6CT[ )E8Q))!S6iki$6"lI-QB4pEaFI+Tr[$lRjVqG8Jh@eZc*6*J+&AHkFmT,RVDqj1l `&4*ValX+`J'kqNYG2SrI13q1p5T2adici9SV*fq4eM8G*bX$%U['c&(`N!$"3H2 mJ1YS*5hMc8CLJ3RUUZM13SmcHMcTq3N&M`NIhUIkSia'bQMZDJ3&4C9Ddj'FC@H #62SQ"lr*$*,MImK9,8M&2*2c3MaK%(Y(kddHG#QhRXb6Pm'B+m-(693cEhRKC3D 5"0ppKe0rhG9a*k5dbR6$elX$91ZeTS1+1h6`Q"&8GhVm5*@D82[*VAib1r,0UA5 5)&'ApMJ+Jp,qYT!!YT2bq*F+%,C"A4p9I*ZhC8f3!*!!(Vq')Y$i8kGB-$*C4%3 i$GSj@A,mDA$PrQ4HbiIajV369VlJ"+*dS5QNB-hIiB9feMF4NaAFfTT5paY0'i` 9Er@9meiFI$Q8J[YUbI)jAE-aHQMMajAiaH5mh6&Ja+bYNI&%L'ihYC&&Zr`hS,f fN!!BG3rT,YeSF4alpA,jC-bh3&)dc4b+&'Eir'K[f8Z"UfDDd`PreYkh,`8FJVN 9Ja1eZpVmp&1fHihITH*30Sr0JL2MD+#9a9Mk9Y2dMd%kCVUl1jhhJ+@cNi,p&ap `@j&ZA04[pF#'c4DSae!3B)J-!D3[181RA0AhU@V[U@VU,1UlldE2-h[iZ$AYY*K -9(r"2[-EH1*EQH&b'@Kpi%-88-5NjZF#bIDIK8N%aLIK,cHipR9M,'[rIeB6"NV `YV'mJ6QDK"&(#M@JReRmM"+HB'M$NBQF&B)4PrKe9VS#)Eq!J6m%rhCXVrI8+FL G5$`L6(riPBk)VfUUT8*bj"6d2PQE1dRI+`qp1lFff9QFM2h@3[p!@a'laPFMiPM Vh(MRq%""U6Krl2(hkYS**qBZ0(cqXDa!r$'+-aGj4jT@SS!i90D%"K(,U"5#UkE [U0llHL$`TcdceB*QNm@llp1khL`Bl&lB14DaNTRJ!jF,Fhq'A`LHc5R*eC3QLcj Y5Fc([+RPQYC+3hraXk&FYT!!@3b(ENraK3aQQN9p#H9+qccV`qrIcp"QUf)Lrhr bqMM5bJ!VRGV+&6HUdVYVm`+GF*@k!Di')PmbP%#a2iX4RV"ZQRf*4NLrl5YFJ'h CM&dQqCTDqHr9[EeSUL42N!$aCrRCKI'HN!#P@&F''6#!LI+hlN'aeH@&ZY)3+X1 pd$bF)H*BU`",0MVPGlh(a184VE@Y#B2*J3D!D5V3'FJLCdLT`B5#I643L2$mm0@ 0Y45QV!kUS2U5jXJ2P$'GAmI"H"FKc%5%1,aHK$-#QHc*BaD`1D'RUq-'mJHFqke mh9+6)TSr&GSC%!YlD,QEqm+TEQXiieBe!hc&f''9pS18Lb,`)bVPrVjFCYeQM&0 V!+A)VGMH`!pj)'f(lj6A@lkpTJ*)j5YCa5fI-IpVFJMjJI-MKQSaqfm(Z!YMTUi SE2AlPJi[Eh$RlqJEl,mK4!f4j[a!9jQdiq[Yp(#48#2&`fcXc4B@E+&[2*33!m0 &DZpb6Z6QblIh69-dj46L20#Am!HhP+-mmRmNjA&Ti&b*+HrX&rKkir,UUkV#"f* *iMLl3eG1N!"#k2+E'V)VjKLr'!HH@8f0`kKpjXcFM6JCDUNN43"2-!Drb+8G3&a a@#Y(N!#r6ES&UDZq1Npr-&Umqq)maE6lAkAr(F93,Ej6!)&Y!+2B8ll$bdchUHJ ,G'F0qGC'qH-V*baq%IJlb$Gb(`a3@N3(TP6@d4k(TTD*-J$Ep@6Sf1*Ae20k!Y` P'S0F-'$%STE1irp-58*6Je$6AYQS(iSG)Z,5k9q''`j'Kjb!*$3eC(0K5X415#k Bhrl*V#%l6[#5B)dGMIT&pGY(#2fJ3r+@`aMUJ!L5E6QikESF3U3J3FF4B[a"Mi6 rApdaTY'j)",`LmDm"a!rhl9N&mVjcV&JPY(5*DT!ec,Pk"ZeNajRY%#H,cSS$ZG `E6@&YpmVD$-q"`!'$kp(hi1,Z"0[hX"iQYea"[-+4`$NR@AlF%Q[XUTUTUrp2MA cjfe225)Ji(h#MdVR3If"8#J"&#-&lD1*GSjL'pD5,FXb0E5rY8kUEp0G)Nrik4U 8FK#ZHq9qL["[01JZ$`IEN@J)FQKh"YI#$[!FkiViRP`0S8AQ+IHBm9JVYmkM,rh ak,F)Z@faD1cAPe$LlcD`G2p**1#`+6[YMH6KdhedhT5!+'I*8h+LZ$bm*iUUGI( NBjIT1L'#ecSj$PU2Ye0Rr@kLX!(9r1am5fNVcAX,)-q54#Z0E2dhQffMY%)(YQ2 P1+0iUreLRk*i@'kE9mm%"UkFZRr*C1(p0NEpi3bQ'"HLC[STP2&,leNX9h2feYZ Aa$PDerK3jFPiVjjN,L@,6q[mHNj-9m1(S3iNPld58J9jc1Ym#09)$32d#(DlRjC *CLd8T#i$N!"2eq(i1FXYP(Vp&b*@Ae2HK"L'Tkm2,C($""!NF!ZQmPp"JGeJml4 f8jISC[Mi2@'Zi2p&J,dKLlK6J[UibEVf"Uh`Jd3reT6CNCIB#UGB*$$APkA2S"G rCR(i%,8jCkic`aV-fVpeE8,@Y[&!3NA%S"SDd128F3N%LkLN0liPh9hi,NB(ZZ0 MPAIJ`-m8`&dE@RDJ@VC15Np!14`@pNj''AHZME1$UFl5NUaTZ'$m%a2Jp4$`$0X !m3cVTU8-MQdeEpiaMC3PFk"lEV"DAB0*GrK2&@S`*JAULV9Za9AhS4$hKk)eSf' FZ-!MIGBD5"T$qTqKc8EH3BVT&df9eDY$ZA`emRUGNC5P-A1mb261TTIN5P#STHd %6(Rl(!+f"[V5fYLZD9*YF4YN$1-X6(rbrD1he+rIE5[m#9I9TV2UdjKmPiep5aI 9Gq[UY@qTTrE3&p6cqe#rDim[fN&p5lVkUGrD3VkY%Ifk,4mQRqI8VAfe[[feeI8 bI`VLI99hl@ApY(FAl4fqSkep9%IY*Pp@KYp@MmI*UAAe(0p94FqUTTp5CqfR,kU !Re([m(B(EPFXX`l!+P&99H`)k`ee@*!!"'Ri4'lRPEYc@8cbcM1lXB8Pm%kpN6& ,8GJS2Z+BEXf`N!#ifB(%9rHUPPp#P$N"9"a"ApfmhcI1!1"p5Kf@3PKe8P`E[K0 KX0L!Lrj-r3E2PfeQ@iTEaGappJ@X1A@)4$LIm[KYY[F82i*r4!"cS%6+p$@pm6J Q(3#mCJZVqN8-1iCLF)4,%a%Ce3@2!LIqc)'Am!8e0ANFUU5q3+!QH(Tr*hI0j3C ,X`5`$e2Pf*V`M)96BhF)G4+2NmFTS3#5V4(eiRq&pkqj3NN+56BVf'G(G3rNiCD S)Mr[er5Uc3Ba[e+SX%DVem$#N`0ijCCRD%[YYF@$*XHYR3(c*D[,dG8VAm#$B3V r0EYCVkQPBDRPi#pA`H)@NR+RRjarK0-a33GA@Z#eTaZT-2$CCV"Z+-&(ZE)eKX3 h,HLTm3XHCF1Nm@e`#"i2V#+b42C)JQ5MFr#)qQCPRrKBqX%)j*,52B1k#!5!&IU ()``rCFY,10fPJD"BfT`!,cX2`r$aBc"JS-0lM6Em&"i4#G-ZX$hr1qL4j&*kVr* k2M#d'*!!-,qqm9cMpeH4QB6p*-1j($[icp6%Nfb)IhcI0aQ9YPl0dX!MFBHPUlF r@+TQSfF61$eM3$")q3$0hF$GSfPqF!0j*,80B++fkie3i@P5i!rJI9mq`bTSJK2 c$0T9BEE-iN&24Eqf6J(4,RhA(-J3`'G"3RSeVDM%L!Z(m(hLN`KFqJA!((9SFda IPJHEGepFY[#BDmJ98E98LXBqX5iJ%9P`Da6[$Q0D3YM4b`9"4Y'8F#4cEj'C-8E b),A-(J368IGTN!$%bm*TGTp`[r+dY"D"d$4RaXqS1&XR0H!E4qV2I1%#'P"2BA[ j!3,fk+9'*i(3()QR@*LRlPS!Q-chK-e1R`Mf2HdiDL$f@p[-I+C1-,-9hMfm*K` VC1-A6T)cAf%M"qm#5l@[%SR0Gcf92H!q4ejA3*p$cQdq!kHMe`GN)#49L,68Za( !J@[Uic,DCPp#Hf"[JfdRJkA[VfE8DhFE0!Z90rLcY!,fk1'62aCka2`lEEfG@Hm U(Ba%je#QT0QhK)ak10h1@6%-X8hIkYiDEE@)UX,#[!fri*Lkj*Z(qMCij*C2UKJ %$1kRQP@cA04V[jh4)6SNq4%G5Rq[8!&lUAk6'$cL(+`,TpK+MbU[DR`C4f""XFQ Xpm6CQ5"G4rhm@3h[SJ2j2dhIfIprmEVIaR,L@-VdF-YSe05mU*m8SX$%VEj+aL) *,N'0KUa&L6T6Nd#(Z%ar-laS9lj21kChT%rQq4#Aar+Aa""Ve!!MhC@ePZ[jL+G MCQmM6dRL2q&c*B"#[beTcXb9hSQ'pap`8QMjLU)IkM&L4Z#)!&!5H"X-'Z`4kGZ adH1pr2UIraZe"3h$kJ855$'PhE%K2B2CPTLKIM"4Rk)LrJNZ+4`BJ1UB&!!q@Er rHS(A5J&I&Xc,1HX45%KBJV*mP`-6*X8J6eYrepX*aAY4fdpqEf"GrfIm8Sq%kpj Ql-8b#TljibKP$L-E4IXaa)Q!HH59+K-cRLXDMMec-1pJGXCkpAh,0iHq$)SVX9c #e()r0mhcI0mhcI0mj3FL-50Cf#[dIACKQ*'T$9mf@$#9i3PapF'Ka9GfKde8'66 *a1&lQ1NpA-$#GbK,4J(qX8%)@KDHDKUX"m$X99LEM2ef!0#P,44-LK)AFhP-16X `J*@V%bK(SP)%EXRLGMqTG&jHAPjHARU56TH1EVQ)UGhDI92P0UkZRJ4GhaXGC!C "U#YMDRF)6m[`BlL0RqlKpc8G5hbj$8fI),I"I)9!4`f6EH$lLMk#aVp61VfIdI1 QSK'&l9i9$F'&AANGkdReX#)1lrprr-S'*8e&(E0Cp&TBY6)QK'"kFd3J2N@Da+a GmEV$-XKq1`G%L-UiA+MVGlYQKKQ!bhBhl@*j@[8I!3Ec&i%!&kXZKa3-(6,Yl9L X6ch%RJkEj)ka3bCf5(8DeeSa4(BrreZbUGPII6ZBcXLl1J-J0#)qaFfL)pMBi&S EpQ+KV+X%G4fdb,&B86H8EC`2&%12dZJ@b10J6`Xr+@9A2)lr"RX#-")Gj`r5VCd %reMR`rQ%X5mMj@*k)3q8rdBD+k6JIrpP"ipT!+BMk)M0UR6P3Nf69,`l)I3r*m% f-9UmcqFBhr`HTU0,i9Lri"$G5XKMDM5UjmKl(rGk[%#"`,4&J4&ZZ9($V6iF5I5 jF%0Bd(r"Zh02rhAY2JTf32eqq&!Bql6!U[K+pl#mm8e,q0&%GmL[qd`9ahUH%m@ 3!#`,Gh"8d"GA3E[6c5bF%pcZM*l*C$C`1Y-H2++L8R,p+(2*h"Qm6cr"QjELZh* MYM+#he)H[+E1[I!(M[KBZ-!!M,T&dY#%JR,aAT0CRL'V,)pDH@$BS'Jff%lY&JS VK%Y(PaI!rahb+k9+AkiPq2Y)TeZ#am$JHiUf`SE4ME(DJSDrH0&8&2dqQd!8e&2 ,Mq1d@d!,*cX8hYqP!q4Y@$1[f-05'lZ6dfCd,kmMj`%P&`f,aaM"V%HkYAr$b3U )!pjEaQJ,6*K"jAFk'"mjDPBUZL)A5P$GS2mJKF$CGbDRZ,fH9M1XIlVpPhrr89& e,bDaU$+T1BB,rcTX,N`@"-'5GL53!"LkCbLmMjG%9m%80*G#E9'J&"Ac94X&b'r iP28m%-8+3-LXebXIdbLZr6Jr(!c'jP$Li'j2(0h`3R@i-0C`1DFQNI@5BL%M1*S PhlH*!kBikLLI)Df(mh$"p2Lme)%1B3`39b0VMf5)Be*j[CN4Nf3!$1,aik%D[Xa 9[lVZ69j1[842hSbVqBL0Eab"*6LDmQYKClRY5pQ%)ll65[lBd6L00L5Nk'NG4F+ hm+BkaRlF+0!#Gq9bDdp4aN4[e%VE"3"$FA!&@BEj)F6IjEHp9l&F8GX6@5iT'-1 @iVckXPK)Vla1EHScbdUS!!!"Q`CdiIA'5p-1Ij!!f[p50idi53!!!!"SCQ+Q(r! 3UKYPb-qFXD8H))V8JeTc#@A0*Ai)@$cX%EF)-!-Sqef!m$fUTXBiISkI5M%+k+S *I-Xflp&kp%fjjjGNceYJ"cQd!jd'Kl["CN(VAUp3!!!!"C4IVQ9`!EK1fE*c%(r B8Y)dL-B*125H%,3M3ahP#GI8YDFEA1m2G2*i#T1SaFjaSUa&XEJJ!!!!%`0kX(i TeNF)YVAVTS(TF8qU6)F1%*e1&e)jT)lTM@JX'f+LE&-`L$*M43qQZP(%KjV`S0Y kQJGR8aB[+REVjC[,+pIQRC-4YA[R`6Z"ZV3%TGYMHqUJ#%ak@UDp!CKEMd+")BD k166dAEM[)C1bbTZ9@UpKpjV[jd&BMX&3jHD-QF4I&5i5EAZk,rAHFk@@48$(ZBS EQC!!qqQb8`*VKUme%Ar*A52GfZ+jJ(VdUH40I-d,(RTiHh))r,f+JV5MD9`rlSe ikm*A2leYj3'b8P!AP"`66ljeDq4)j1A4k1a5EbQ$38D$@J06U1Z"db(%(p6'U"( EKcANS!&PbB3NqLAmL5"b'9EIl[1Bdpc[Mr8)al+UM(Ur1N%*BEIj@Z&"'#ff#bQ $J3AY2f41XaQ[F&MfHZC+"&)'-0j2I)hhV(*ffIprm)a%#"8b$jLd)Neiq%mF5"D mEi5@6q0J9p2"N!"ja9Cp$alGDVG,@F([&YY,EfiYhZqCQ0JF**Ac,6Z9cmQ-&Fl 8EU[XIU(cmrKRFpD9(lDi,`FMJQK#lq-'ZZYejr%FKhcLqHXDQ(QK'D!f*&!P*E5 c)Gjr"6qMfJ8f2&m8"XQdY($8DX$9RMaHkE[P%FeEpAPFe0ak11VM'bFDm(kC&Ic 0QT!!B'Ih-409413GIYSVTpNdE$"N"M,r(()`PbE*D'hC-DUMJZRR(jHAj0Zb,Y4 !`cA'"[XTbHk"p#4m`"bD$$GqU3U6V$Kjc)LXhGZSKHqS%CM6'PVJqjiA6EZ*!ek ,[@liXaX++r5E3&$'Vk*bNCcmH[5T"r'rG834l*r2X"9`QiD0MQ-bKG#kQX$50p9 p1dB2G*0VEU`NA,FI+i,%)MJ#V@MU##dJM2m%(9&@+"U2-8Z3!2+lapX&C'q"QaG bB'mZieXpG!rlh``9'j,0,'NcK&e#p%eP5[%&Uj6%aEDLjb%%J96i"`Lc@GaLV18 0dL(EAcYHVUFlLB!E(VlS#52,V2-bK$$*3'P)8FSq(-ZG#B'f'%ML%3XREj*er2" (jbpLV2pr`JEKbjU&8#KV0q0'CPVBj3JX)A&Gd*ejC@$db(jTK*'!fpZrHaE6#-k K)GI#FBK1j'fq10*KfL$)"@#"KeYB+!!"`,"e`q%DpZ",hK!a#lI3#FTBHC*1$6& 8X@ajG0&YZ"Q*98&JaNbAafR6JamE5#1e[`F[LKQ['FZXm&l5E9N6!4f--0-JJ%0 Z5+I[#IA91UXRP[6+)`mi(EXAr(U4YN5,HSlRk&R`S*2SXIBLp88J2BD(KUbZX!% 6'CA4,NXJ,2)l8e"i#AL)chrRY1ALVG@k'bj`q3DY98c9&hB-J+CbY%Tdqj&!dZJ XGNZHE)j6bHN18GUKi*YRpUM#(q(c&H&A*p!P`I3*DDYU8H4PEb&iC'dC9J8['cR UDZQk*J&6,PShdFf(J&$KE1'D-JH*e-1F(1Eae)5$,pG6iFKc83"12PXSZaVB$"% a#D'cT,h5Fj[%5%m(S(Y,1@fN)l,U4rjKNS1UL1YR#RSej4j#jD3hLVcal!3'ZP[ ,YN%2$j*'1[2U#jUHGr0+#TmG8UiID"@DNAD*J[i,qBdX8j@)Dbf(U()X9DQDFIR r0M8BFCDrM*GkSC,9Jph9F5HNY-Td`bEV`rS)SPj5BD(6kH-ijI9&55NMX6U(Gla cGA3dc,1k[SScG8B1XD-3$[6qAIpR@UhT32HrM91ZbZ@Zb#VXZ[PHajH-m(F@3mm J"j%m56P-LM4D9GTMcIN!CFri8kISjMV+(JNkU!UbNASe"KVEc)DUPqI9S1l30G@ IkUqdeeFqB`+QT"1REAFdTrpF-,-#3Jk`$19BTG#lfD'i-l"qNE8E10HD4cBHCRE Z,M"h*&Q1KAPAm&B-2dChpSM#bSVaT+C8Ah'p*pljj9*iZ8R!0324(aVkr9Zq4PJ PYjS4CZjLJ#Sh[LD!mUG'1h'jeD-m`c*-Uf`GdNKARE#8HV2%)b`LL4qDdBGeL(% PQ!*r0R1q%'i[eYkh,`8FJRKj,Kq,p)i9C5h"X*d!JY`)Tm8CdjPk@,GN5-aX4%2 5kMqFZ!bE8F&#Mh12Uq(G"afH@@F[+f,SMY"0)VKcCIC'#pRTGPqSSiLXP+Y$$rq )C2pUY#lda,k)d'BeqA4`93Y&aAT-X)D[iJ@'[ZZNkaT9LKHIr3@5HNDNTj&jErj &+hjF2b9V[DH#5BZNi[&#BpJ(mDj*44i*#!e8)ZkRpGH4c'&prPR%i9edp*,cTJ- qU,RrIMY&8(KB8I%kVZ4E)+a8jqC+Z@'i3YBmQ8h9kKb#kKT&RVi,&jZ,L[p++L1 d8MkRVL#SR6em5)"+4d3YPZFUf0CC+5A8F21%HS30E[P&!*UG!F3qaekllk[JqE6 FD5!F+p46CdFNG-f5r,(EQcPKq%r,'Kma"*@EB+6b&jJ(qedEhbMAMpHaQ$mC)K9 0f,i*T&9DG2[EpKjA5L6jGU-eEMfS'1R00ZIH5'HS*q9EDpp!rEB@ZK&dPRq6J4% %M[MAL$b(a%*i-$BIJKppM%E1GQ(RKGl@Q%`RbGm+#YS[&%8LBA(89h8I"iN8F8k GjeJ%K!(+,CHDkeX,2r2h#Pp,`L!k3p2aXk&G,[mJr'Q#3H#c4qVpqHCm32V0c'% @8pf'dpL5$"hCD26)HEF(&FF6Z,&+0@2QMGV&iGDZM2KNmF!eG!*EpP6+!c*8H8- fl%l+#-'#@j83qe,3HbXJKDd%(LUqC*5Jl,bb8`TK@FH5HhE"P8h0J)J85Fp9V"U 0E,eEJrd'p(Ja#,98TpQa[&ihSUS-A+K3T8&84lQ+SId[)T(P@mY2#h%j%G)1JjU MPpq%-p"G@*cSN!$Ye-65IRl'"Bprb4PTb&HU5a,P+(p&[Sd1+)D$d`#TjIZkChS 0XkHiRhh"2Ajr5paa(62EAqh!FMp9Yb#f(@VD#d#`TifN4ILJG9qQe&@U`GDpeV` ZmUGGV5#*fh*)kq5LSV4!6JEE9LpIYVAbhUdqT@H*-fUH9(Faq425Zr%EqL"-Zfl [h1L)c65GS9jkq#mq#qmc05$#++,I-,!6-qerG$`kF+Bm9P0XUr#3!1X$Ir!IJXp 10P`+lq!rL&&ql9&U&+##",E&!m,[dl"pKfT-AXKHhF2F`9kSiDfAfJ`(28PpjN% r[Zr18aXc#$DAEHpRZf#&D3k[j`6)AcSN-+A9'H1FFB@M'-N#DP)p9YP"-%i9ZC6 *IkKGQIEh"kVG#"X5JmX64i1NN!!PN!#m9'hJ#j9R&6Ye1JK,Klf[XT(PI)HLpmG rlI4`N9!MaF0Xl&Fh&ZirIcrkIcXp)l&fc8#L&!F9!NB-EpYmK%691N-c$+IrB)J 1rI0l1S3fZmEF!m5j%qHUYJC3L1rjppl&Y$RD5Uil)[$T,B1rlaf'0b*4Y$VCq2' cRA)MR%e`aFi*r'I$V$R[*SAK%TM5()i[[PHf$Z2f'!Bf-pelCp+r8TA#k0jm)Q! &86hiCG@!Fe5I6#eVqq91a5$V6j1j[fX`%lC1Cc"dh2cr'8E,`Br32-r(+!846J! EXKCkV6&B2YrNeK)FP3EV)!EfBlQKR3CVc5*M@'1dlNcPY8FXBGk)M5C)+e$AITC EbI2ZlVeJkr`!Mjp%j3'0$Ima*#2$Pb'qUMAMqY@cNed3eUdc1PZe&cK#m9@M8,q c(rf1pBZMQ-UQh"ak53C+)'YJ$3[#djRj2L@BhQKrV*eMpj&ST$Z5cQ3lS9b#``1 eiJ(MKVh-8krKQ*eQ4!fhj`Y`L'fM1@G8@c[VJ4Lh$9EG#cpNZRX'&Jm&XpAmR1a VXHbc2H)0FerN)5id2f2411G[cpMpYlM'652)&T9d#"9YKbH"AM1MS,3L3S2e6E! ec)T"5H6S`%THabfElmR2DEAmCCrPk"Zi4(1UeY$ip(aIkC1Si#JkGBm+ci1EdbT %%VH6feCaFM1M,EP@G5a*$DKchh"[Br@hr11dGa0Me2+C6+fp@[h8-FYR)8T9[Rj 4'E3")Ff1%[V8TdDN0$8+lD[JK2L+J9$e0N+EKqFpBLfAVF32R(FJc9-pM5c4)2c NE!rI,1aiF,GiT5R*!0*UXY9eSC!!)Sa2VcHQI-A(EZX&Be,Q-+,iiQ'Mj9TUP#P M5(+cVjAVThVZ%k,#qiG"T3Mk5%,G@#jHfNN([hMI%Ib*22LeahBbS+10XbhZ315 *L[LADZ64kc1B%qBR+MTDM$'c+PA',QIDUNH`i#6R'K-38kZ!F@2q(Mi"I"iDQ9P NXPlcakeP'rm1d`C8DCRd(NL4Qi!6pYT&B*Kr,`$+1R9[T[kU'c23k5F+L4E0pf3 0")-Ll)N`f)*r%UJdLTYPbe$I`fk3!!2jF#Y#+lD[k1[Mc8r48GRPa3)PjDHHdY% K!RX+kC!!5akr,"a6Rq4[5)PDX#h88Dqqj6LMH+(QMCdr&QNN#h$,BZEXScqaE+2 4HGqQB`aA#($@F%aC[E2Z5p$j3MSXBH'`hEi$bLY6G3XI,2`)Yf+$Di!EF'd1Le) PUYB1KrK3'0jG8(%-mc(6+32%"A4NVT+JY5hM$ZL3!)$3AUqd'MQ&X0r-RAq2[8@ ,6kTTTC!!&+-BUX[a0N6VdTQ[a,hGTUD$"%ZbeJUe0a0`$VmBcp"YZ@@@SHf8,h! NH5cB`,VlakR'h-DI#8Kje%(QhZj$8"ci4fJE+cVHP$$!U(H0#AqkCXqS1Sra4@- (Lh!M-SXb+dGSL'T(#*HG$)jIecfN))(8P&KU2KAfd%C6eKUFaRS-mI%lGrH0YIe 0rI[m'"`&VJpX)Y,e-U$P3mLIY&d%A&e4jHS#QXA)!$00Tc49)`'ePkPEqqG[6QE (6SE[)QaDD4@mc-ik(bJVXh[Qcqi2R8h-%+e0[#YZ+-1@c*jXZ$Ii&P,E,c+"5pm "e,l5NUaTZ'$Jj1"EHHR@JKY#JKlGQ6b[3PJ6HrRe24%`$pTk,A!dI&2m5mi"mMZ Ee52&R1mfKRRr4N)b6N-cq!8AjX9A(SQPmAh+fU$1'SQGS%SiC32-q+qQ)DK($Ia B@E"IQ*UQhGcRb4"Gq9@PMZmHqe`hiDqlPm1$Yed,U)Y&$SBIeJ4V`m,ZR6IhXm( @QlE9GS$ib3%XcYJ&mFd#HM%$dJ"TAAl'@J4%KPb`5hN&R[Gd'2+2N!#rl@cIYSL qSBIYeDrEUh"h6YqedrEH(IEH9pVYqeqrDfhfTIm$GbMj$(l@lIYTD(`X[fkErYd [JlX(IDfI`Y6IYY$pVKIE@GpY6IYF[fdEa4mKRpU,[fZ8qG!rETAqh6Z$ZelpU&q fYHqfZll8rffJ,kR+qe%rJiJDG55XU2ZYBHheqp6P4BAc)49cl9+BFr,1-lZaK5A `6Vf45R6+YZ5'5!9T!@3%[acAE+LLee1R51`!a4bGjDC3VEVj[e-qM5%3,ZJBK5P 'J*9I5%$A85KU3DVe3VM[VTHb-B(RX#()!9Yemir[UYEM8*-bJkaZ3h9GNbd"pHN cL+)$62(+SY"`)VHZEZ*refdplmd[+AYDa[h#$R++"F#"6'!(1J6'E&r#),5r-`I Al-NGc(&dk!E1T(MC1RK5+Ik5kr$SEkm2P-Z,`IBl@34cfP$bF1UK($P*L-(D3i# "j2cVkSXKY-8i"EX)-`-V%N-ck!,02Y39[$CC`28jC@4f#I@Ip(K$bFhQDjr-A@- `G'e61&[HKp6Y#F8XjSaI*[`c8h+%dc&""eGDi,@R'kN`m0PQX,XJMYZ[qm2f'fC [12-0-bXFH,dc4khQhY'3!&qIKTqIqUp4Q4BR1RCPUk-I%9f4+(ZpqBRAD433d&* S8D-$V4m+Dj,0HafXRrp*G66X*8Mr1(6&QcKm1Tm(XA5dQ@,CG`d61-KMQP$&pbL "X1qk'[M08LLUIHNKXaVASr"Tef)f'`f-QHGXC'6S3ia*,Ac-'+R%(RrelQmIbm! eY[m4+YJS+VeYfXM18M[P1CVRFGc(UlcD$Zp1M)lU-H&mDB!"9PL,2YJ0Hld+'!D &IF,SHGF(lC0``c(KY0N%&#YZZ4Sek5!Q`0S&J32*N!#&IJI)C%XG6%ihA9Xi!+C T99#J5GAb+K-R,'@(MJ%j@(rp5CAH1$e$pX5RiFfqq3J%TeCk0Y"C4D@T`d!)Tb) 6@$8+eVY(1AVkJ3'-8FkcQTAX'JI3AREhdbKrJ[BP'"q4Q6&'mL#ec"i&Y(*NZEA HKpIp%&-F(UjFNGekf#+9'c-"c%BXbE)%H2VpP160X&HjJBQb@D[`e0ql$R`9qN6 1(lUUP&X5SZ(Rmd9'!"$Vihl1jqZ[rGY2D6(J&)59Yb!#A#fTdNcap'b&"`d*MQ` U!c041apE'Gb3!'&0$rplI'M*qpF1Ai9r6`p&-B6Hkpbcla&3pZmI@+#3!"YPZYC hra82d8kNLX#NC**PY!SFPep0GSD$$(1`NdR8bY&!8a!IE$(0iE[fL``4fe*feJ# -3PTXr&LB,X60DdVSbEGG`,4&e5B!pmliSXEK*e1DVpMqkpZH4[(hSm"5iC@D((Y iU3m$5Y4A#UD0#mZ`C`(6PM+p18X!iPe-p'$ZjbhI)B9q-N4Vic5%fr8Kl6*(L91 c5'S88CR#Zr5kMdfC8SI+,K21kk'peKPQIV)bNQ5KQIN,#MSceI8R-[&HPK3I"C@ ,S`k#6Q9b*#q1)6Jp2R"!a6ihNjZI@qPLpmLMqL$(5d+J+f&kZ2-5GVhSLD"R'J+ 2rUB1!MR#cX2Gi$cf[EBfCL#295+)QS,6"YTIkGZadH1pr2UIraZe"3h$VB6kYrc 16j&9-&qZiV12ZL'$p1Lc#c@SL#UCC+%%L@M'a6Pe1ri3fLL1%kkDJ*NS(bJHaI+ 6Yk3*+chApN50FrN6ljU**MaXUUUC8eqLDrp(cp"&)k$ZK%ijJAiAiAiAiAiAi8p JAIpRr&+2K1[bc"2bY"hhlpL`S#Q8J2[UDI$aR%fYp(MTrhMB#M83SeU(PiQ4f1% S4-LD-i!bGf)Z3SGeecU*4la@pCI`(%`aS$kI+NeAJEMqZfX)#T-3+`-+-C5-r$f kbhdk8CllANNaJPGl#$I%lZ#%p[CI0CN$,Q9j*#j'U(i5AGDD1ZMFbFAC#U)*EM# 'i)!V%S4+&F*TrH3MaSMkj)9TYIY2XaI)C&0(V(d4UJ)c2YV8iD(BFTVm&c0h,3T QJBR'6h&+R!iN8pZ6ai*P6`H'EImlq-rrASIM@q4T3ph9IYhCYfA9P@,V,NpDEqU +2S,'[e-lRiej4hEP%3ELqJq5GAp``j85`Tra%1RrIpBLqpql)+m9dDpmCC*#pNq T`8B-B"h9l,Ip$-!(#Uar'"3!HdLD6ieN[[ijdGBUp!J&b%C%L[JQRC0qN!$T3Ni Nhh9+0M8Z9@3&e4E@aTRX`jNY$!Pb8Ie2pVQdQrM6bh3Di&Y,mc3h!88kXJKAFG, fT3$Kh1fkrFCZ*'T`a0NCPI@jfVX3@48j!"02hl&#!XqkdrYBjRb,8iL[iZNACP5 i"eCr',ZHj[IA`5T6cfUF&h[5kZE3LcaCP$X(#DN+"fU@bi%@d2e(*2&b2+elpZ' bCY2TVTalY@ecYFHeraZ22IM6Hb)ZBK#490"lqJM)-eY@cikR$[F@#)`@9"K)(P6 P5"HXUBcmkhQ*Pd!f)(dZN8cGGI$fjA0"IIRrIkJ19CI(8LL[+a$K2V*a$IQpeXL El%CAa&``habR1++r15j@2i8*r[5,ArprLcBDH3[)Fmr,-Bk@rc)r1Dqee2689E& mkf+EYQ3DbGE6Yp+-`HIK9c#)TX8FEf-$Z[@j@#UqCRKLEJ(l80B2dfLR&BlPb,S Yfc[T'UF`+-(#CR,&JAIEjkcAkI2iCdZ5i!-d6U5mV`eIN5dXCV9&)hXUb!4,c2[ YR0C5ibHiPd+42[Ii-M14lbMBfR8p+mpVHeCAS4(-@L%J4Im,Xc2Jl&c[kmkYd61 )A*4RNZ8Z8pqi`3&T23iTUI@-RCc9ki8iH#1SZ3(I`ec'hR,XM64d8NXAa)I3)*M GK5P9lB59GhI6lG$%G(+H2#SFahNkIhr#1e(ZX9BZ,aPH0-J"krZih`kNj(-N6p- -l,,'Z$f4RTF'dBSLL'dL,-"[`4Yq($EG1UkpLf9+lS0X##8-Z#fmjBP-Pfr"irL 9)d5NbTVR@2d#'KVUl1@EJVIT`6j[B$"[SGUSmA-GU%ai[&Q8`43NFX5bLDefi0f 1V60@Pe"3bM'KM0V'B&)6Y,d[QE(V8),qSa-+$8"VfmKPS5#U3cQ#IBm`RkI8$D' NjICrZhJd%J+YZ61a(C5XMHpBA[2+DL%cBMjXM!bpBaD`KMGjm+BkaRlF+0!#Gq9 bDdp4aN4[e%VAj,rGDCa0K'`qMVPjAFEV-1FiMQ9ULhF,b6#kMA8N9+p)+#Ge(*N )FV46*TfiTCf)EN@GbT&!!!!!hmP1RRkX6q'&T00`+!k(V&*ebb+l9L+J!!!"Q9j B%dr`%+SECFM2R,'P(L#+e)0DF`PPc588hi1UcXCA1+"i$H[+`$Sa*"GL5QJ!#bJ $k6,0!k)f1`r1%9T)j5jdYKfh%pLK#9!!!!dHRVf+h-pE)%XE-H[f*q&*dX6,9YX `mMh#0-QQ&21#G4j3R1G8iab-!QSJ-Hib[FlV$pkL[$Qm%e#-#M,0H@NJ!!!!Z8H XcCj1&4-2`6qRraQL-I*S@c3Q[mjIefQ#+`I$`JrGb9%rm+$EHTS(CapkQ3`YQKN p$,lRDpd4S1V(LiF6Qm0CJ+Gq)"m#-C)*cl!*hbZL+P!TAeZq(f"-Kd2TaBH[D4" k%!0$%R$Y3G1U()ET%T!!K-D&ZDI(N!#l2YJVaD-TNa+MV,fBRkYYddF(mmXMJ3f 8k3R+!r6L*62r!BV"H'aFcd6ZEN8GRiBIkM-p)0U-K13H&mp2ZQU@d!RAEUdhl6' 0(B,(%!U()[J@VBJB-MB%frp+dBHGQFUSDXpC,0,1L8Dj()3rN5Tq%32+,%$T44( Gp'`JSTmLc,Di4A&3,d1T2Zd[Fd9alMTF!)C!E)*0e+rH0cC,rKfpVI-TM%$X3Ma bcTiN6*llTD[J`a-M"@H(lR%J4hC$lB8S[PGZ#38'lKp&U1DpYJh@AeGH,d94XF- @-m29kCTiNaIrIr#)`kEK$Z@%E(0NqF$6d6jR[0HZLXE(l@jcEEk89rp*SCIFlrQ '`6+KN!!*'NlkRGiIP)2pk#"BKDep9&VkDB(,f[$K,Zi#"'5E@5C9Dk3ShV3['c6 81"D0%U)SbBHF+GY)2T6eS*-bbPiRJNhjSAYFH9rV-1VG"B5eYcq6(%63m2,9FfZ P9!9XqRCD4)"A@I$2h#XcG0NaXN%$BQm25ep`$Y+mdQkJGSI5bT*!j,,fa1i`10J eYmMm*[pBJd9A4lm[Z+8hK-+d1CY$TfETBqX@Y9bl5(j2&0F)c5p)+`YSe[@-6fN Zh'DF50YR3f96bD9MfLF`*!50Nj40#a4pD5@+-FL2q)el'$-rV)a2-bb5`IC(NVJ "C#GSRXV"Y-+a`!9h9#crDhdFa)1088Q%lhm*d128JH"kBi$CSJ4CEILTMaU0,R( ilER1CjT9USNab#65QHrj4M9RiRme(q"UC&0#mr65!FXbI@e-PECUUNJ)2[JJ6,N #d9@jCD9`l@&Gjb+NPYQZK%HdZVp!$MLD8ZIL%3XREj*er2"(jbqE@2L20@J)fF@ j,S&e+k`AV!+KCfe!pGr'J"AkT@3,"jhlI(`%+h*e6mq0hD&'XMBVdLCXXC!!l3P fNbTJ!!#-q@QmP@+6E90%(0L2ZY'JbD'b65DL3PN(*Me9J4pd9Qp2i4Vfi%SNA0H *-8(I[[ICC*V@Vf[&)3UB4J56@CII4ijDPT`@'D(C6'C*a,f%[5+Rk*S%0QJ8djB *!EBdIL-HbSAEITb-0bP",Nba+8dSJlV!5rMB$k0LV"ehTAGEK+F+1TXXhB'had@ 'aL%,@#36,4Q@hQ"#k6)%"6Z[PD#*[MiIFEe61#Na,e85&ZM['i66khH,'21Ph6$ Xb!f#$31%QB60&5p+)@5X9f+d)SR5AIPD5mN%hRS6TL@STET*838qH@&pUI[&!rU 5cA+QR4XVIJ+Eb)2K@LXREj(@04dR+`-3(T+#k$,de)2I"Ke)DX2kaLd*ZqD%hK5 S4HUP@S9fYZU(MJ5j-FK2D9-rp(1A,RLeA2+CV0LAC$,*,+0aB)A%*q6DQkV5060 N6ELT4Y`k*qh(8K&1C'U1kLh&4iBh[*i-EPeC8RUA!JEB[apa,ERRLVd)!',R!+r 'F@IHk9r11&#D)K1N[mZB@M'+#A5iD!(ZfP3Em!0m"(dNj,1MTG0@cf8(1`cCN6h SXm"U)c0'p'1Fp)i3QC18J8qkh8-kNj@B'[prhG9a*k5dbR6$f%6k+frMJCX2kbD M6)0k$XBE@L6(V&Rh!KJK-Q`YIQF(MArS,I+VC5`##P+8hm%NJL3RUeY8!"V!Ie5 h0A8f#81i2-(*Dj!!+hhJMRVjJKQ$4(!!ETjMc3BGlD8T`L*Ee,Fc(1JUK`[Kfp@ UEMD[TL#Nm2bhFH*fAbN(pJPrDVcV*aV8DLa`Q2f9Ye+0bhGl`BXEUIKX"BKGLfk 5mPMMB@25h`pee!3!!!P+`pKX$`K1'#QaQ-[A*qY&DP['8XY8aXDi,r3`J$GTE!+ %4LQd(E1V%)CiC,+GCQN+Y3NPp0$%jQGDZ(MX8D(jh,h)Zb%jMb@Ea#&Mhk0S+j! !!EcHEq0KR$6%B%[`!K3pCRddfj-4(N`!!"5C&rRh%N[Gb1U%)+clGfK5H5I)3%N m6I8f9"F$@F3J1-QK%,rq&`e)1pR`a8!R2,d6UZ8r2T+C%Lp9E)%!!!!!!!&PP6@ e-`DGY*!!-d&Vf3%,a16IU!mImA9$G4DM59aE3TpcEcbZYjbBbA%4Je)AFfi+kZ' 6pRjFL5Y!l+[r4p@H,%)JaM8$E(S,QqDZc)YB!Th80%*"4@Bq!qI%SH!!!!!!!PH L8QkSRK&`1Z%[0lMhcbVUh2prdYT)dBbX16"d[LY"[b-T8U3@*L'%I@h96'2F+k+ Db&&-rKV%Vq18*0KTQI5)R5d3)J!!!!!!"&a1X!rJS,bR#l,A(pDRFr)PLkqKH8f 6C0Zf6%lmrM[Lpkf[%EGereEN+3!!!!!!#Gh)kN"(8UDjp58$ZG&IC-!CG1C(A"F reB-M6UG6CE1rjG#Nie)bUh*DQM53!0CC&iG`G*)M-(9VISmE@QpVL8C&3XS$`b9 !8Pr[e[4NVf$9YcL6Mk-Vk6dDJ%1UBU9j,C`B"hV2J&4ab2aElHZMrP'[NA#J)am E",LUbprI4(6N@amH!!"-X[ITE2#,e9mC&[Y,+9YSaV$kA"%Uiql`Vl6#+i`f#TM 2mE1KA5m"U)+RA488&BE)F8JdE)NUT,JU,Gdfr(B"f&B0@pH)abElEI0!(G5D5pH EQpF9(X!1@jfiC+c[FfLpHPNQX%c,mF!eG!*HpAHUb*b&RG!rJ'UUb,#TKZ*,Y!S X[[,B4Q$)AJTq)eXK'aT@5bqJdMYY8ZZ#+2c3(#P`kFE-BLfb9V2eSNPa"@c58PK Ikare"da[QG+dALE@6J(`ZYdEcQ1MRk&R8i%2%k8F+#EU,,6Gk!aVc'$j[F@[i!A 3R$T4)b(80JA[-*h0f52CVEp(X1`L@r2Y`()r9D)B5b%8I`bbVH34h'43HpiZ1l[ M2CrS$HdE9)-&chBB1bJ0QQlAlI@p#Mpei'kri*[4G2N(5,)@,20Q',f&CUYAk%m J,h1(re[Ul043,h)+96'ed"2-+j1Z$&4m9X$HX""LId%43p8I)pYiFq(F0GTiHqm -c"pE#K01'f$GXmG41eefX3mJ!EFKMY(bL[pVc"-G#3F&M%Bl2h4kh,LJ)2ff0fL )b'V8RapTG[ZK6M,l!RV9-SfZTJT9&AM`6T8)0[+HFr40A&4&S3R3)fkFL)-6a4P RQR!FK!0Dd)`ffH"la(R4HC!!`[UdVPq[E-J8S,CVqD)G+Xcr28N+R*pDRmb9Kf& @qpNLBdCiFT'lH`TjNTK2mbKhMq&YK"e6&1cCNQhGKj&%e5rYp(#48#2&`fcXc45 &j-A4G&AZ6[Gb"kq3!&HRLFV&Pq%dX`%*BTHFl4EK4'Xb@+XBN`8K)`K[b3ZXkrB %)%hY'%kEbPp3GL!r%eApi+(Te5,)B$a+jGA+"q"a-$ikZi6pcN5mqbD%VII!rd! pBH1*"9G"XJ9Da1J#q""`+*NEpa*9[%q`rhbHJfYFS6D(a+@-rMiRA8)k4DGp"rm 901G@ES6`$Zj'#65-&q)qFPr4$8rQmq19*E'GXrp1%!K8*E!a('FfPEDqI#'&L3V `%`Z5S9'j-K`[8lL'K)cbVXaElHpV0)aA%Q,h3f@pPFPDF,$2MYb*(UF,Ce'Gp0j !LrF41V@R8M[3HA$DFF$bld"i9$'f&+f-(%e+YH#U@2imH,P!08LHHH2BfB`9SZl G($I9&deh*,[e-413!%L5[a!hP)#)#kAm&(Z##HApca1$XH&LkVBG80,heREb0A1 JSQK4hdEBkScQ*hb(c"f+Rb#K3IeCI$NKadIEj$"IFVCcQdrqi#fcCGlLDA5Vb-K H%Y1'+d@NS(8rD9iQEaf9,mBi8S%5cQ6DqKqhjHJEZ%4dU$V6#6hH9090mjKaA() TS5@Y$[HY6X-c)EUmjbY0'Nh)HFqJ*LZdp$e5T%!KJZ110C+`l"T`pFblYICrBp8 2LHii$+T-r496N!"Nk6B'"j0T3&C(cH5lLFE-%RTAR95cj,cI*RaJ"kj2(VZkMq& $MXl&lSmb)EqUkZ(Kff!b2T03!9V(ep+p0YN%5fXP6Zj5Fkr!JeakkC`X!bd6Gfj ANpRpmCGkfUp6VV&02!5%&9`2F*1DGDXM@h#Z[PGCcVJ![X,@&iiU%@jhYcAR4`r '6XrB'e'c%-$9+r4%%4LPPKl(%EE"LdQ5i*fcRl!jh"AhNbf+q4S4R1Tc$FGeeQ8 DH1T"R%-SN5**5%e!-Xl(VK&k`JidBeRlmeEATCfZYZe6#"TIjf!8KTf(FB-AQ1c (#)Q(JeZ3!$ZU,1#195@NKd@h(1Je2)&YFa,@G!CrGYZY+!4Nljpr-&b+fY!PP4) #h8'-b4bCmVc[3UmZiUZ+$K!bEr-%`"je1B,2pG,MY'#DiT8ZS8G#r0Nij`)VKc3 !Ikjh39dfQmIIHJNf2dk1d4X4RKH9SF`l%$m&q@)&Rq9'cYmhJ%6'`JU)Y[JR-1$ 8T#pEcEc[c**#A4',!b6+5-hl9qb51HDMM!H$Ap'dph#$1,Y&Q`[+-[ANML$B!8[ ,h[+E6*@b%*1&G0i"JNr9GYE`9TK,KmDj-KV%DJAfdkk#6,F)"-aMPhH)"#E@'lI VG)2fMk8KiK%SB@9SY%FiHQbGqX%!b!Cm%!4@l5rm@-@JJkXi&kdiBl%146Qr@V- e#G#r*NleqRR0H6I[5%pN(E0Um)a8("ImN!$"be&UVBJ84LBaD+MR!',i%801'pI @P0[0G&pfS0V`C$ZIa80f!j6cBaM4U5mY0""hihp*E*Yp+eaXT`cr'MCDNHETBS& 6cLXZZARiQ+pldpM!Z`5h`$'i"Y[T!*TZkAT15+40dI)alE3L)8P@M'c-54r@51H Z0lNhD#QTA+cElVpSCVB*qH25j`k(P)cG9fZMim+BqqAhMICAV"Vfb!Z1cm9ZA#r PpSdlfr0K(TPQ@qY[c`kZ"hNL6HiY)q("[jrcJk3CX23`3@P02rL8pSHUl#-`#)S 3F$mqHM*`khjR!Derr4f&-L5d5d'2*je#bbG)$ArPhaXB(%eNiVDPZ8&MT5X1N!! Xf%IISLkMQ++VlqFLX2meXFRCc$!%QZ%SkTj`TX5Gf3q6b-Y@#%+l13ekGE)&3ak 3!&&kP@mj9(rbrD9Vr"L&pTE,ID@hl5NrJam[fQ#[fP)5Ii-PpTC[Y,2i-A$qd[A pTH%RpTLIfPkZcIhhemqmfep5"B!6A(IM05jXp481$(CT1l`Q$Tm,dBc*$SX1ETj 9PUZBhA$lScIiXk04*md,Bf,T%4ENXVcj&14XDP#$&E[!L[pkjjc2RB&Ml'2r5'+ N4@#*T&Tcf+IIbQa*QUai&MTN*G0prfV"*JU@6N"0)%CJ"T!!pMc##YZ[QqEj[Qq Ej[QqEjarV8F"2pIK+Trr)8b!!!!$#3Nq[33NkbiMTh$aKB$m+fkqEj[QqEj[QqE j[QqEV8F"2pIK+Trr)8b!!!!$#3Nq[33NkbiMTh$aKB$m+fkqEj[QqEj[QqEj[Qq EpZJ+FCC53mhl6$!+QcTAM`1'M3%+)XM(+Ce3@RT)*1,MdQYfiAP&&(Ii"@YC4q, Q%IprUfkM+)85IdceF[0X1Mql0mX2ALL2MRa$[cNB$6)Ic`HYmbL41ca#-1D3!1E !N!#%RP'KcD$LFhE%BV$rIGRXXV4G8N@ePbRR,k'`f'`f'`f'`f'`f'a%Rf0Pi56 V52))MRIici+90r5#%0m1VGM'T2Lp'fa#*A9QSU9[,-(A8bRhT#9[N!$TCN(9S*1 Nr-qI)U1pAjG64`UJCd%Je"K+p)6LC8ldZq[(A'8Q-L$NbHG0-P*,IrKCD32R#Rp M6l+`PrCqE&))2*rIBS'aPK46Y+,@kDH#afP,4"RY(5dF0PR[pA6H!9aKS5$a8+h K4"-[`Pc)#&Bm-fLN2I)X(h+4fDk&KDE*cK[DA%EZ'31!!!!!!!!!!!!!!#$i8#U U6Q(S#5e`5I)!!!!-*#6*`AKrPbI$bR8Ci'b--P3!!!!!!!!!!!!!$rK3+UT1BHJ *,A"*mJ!!!!`N*-R"H(qA*m2+G4RJE)`b9!!!!!!!!!!!!!!2q)kD#($%f5V!BT[ rFV!aM%Jp"[EFm&Q4U5dB5%182"4c@#4&#J#(d%TKSd-25[,mPAmj[TP92iC)4Ub H'd20BQiTCjfRRH5ihCb3!#KSQST8Jhfl`b9!!!!!!!!!!!!"U$U2*@GE2pA((G4 HNV'[F`pKITEi[CXjRGm%SE2-V!@m3QjUf9Um!143M%flHq`rhqHTLiE8m*klTeq UT@Lri%$UmEA+M)0&b4SY+Z6lp53*`25j9K8M$`8J4JBb"kf`'rJ)P"*YG$TaN@9 NGKbR"URY[@I36-Uae%AJ8p*dSKl%`03jYSV[1kjpFVkp[J")jGVi60X5#AB[p*V r,MlU2&pS[8BKSCbURf3V`NNDCh&jJDQTmLhFZq-ljLMd-lS%*IrC!!!"!!!"Cb) !!@BL!!!!-J!!!!!!!!!!!"`!-J!!D@0ZF`!!!!UrZIrr!!!!!!!!!!$JK3!!: ================================================ FILE: build/notarize.mjs ================================================ import dotenv from 'dotenv'; dotenv.config({ quiet: true }); import { notarize } from '@electron/notarize'; import { execSync } from 'child_process'; import path from 'path'; import fs from 'fs'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const APPEX_BUNDLE_ID = 'com.jgraph.drawio.desktop.PreviewExtension'; const DRAWIO_UTI = 'com.jgraph.drawio'; /** * Finds the codesign identity used to sign the app bundle. * Parses the output of `codesign -dvv` to extract the signing authority. * Returns '-' (ad-hoc) if no identity can be determined. */ function getSigningIdentity(appPath) { try { const output = execSync(`codesign -dvv "${appPath}" 2>&1`, { encoding: 'utf8' }); const match = output.match(/^Authority=(.+)$/m); if (match && match[1] && match[1] !== '(unavailable)') { return match[1]; } } catch (e) { // codesign failed, fall back to ad-hoc } return '-'; } /** * Sets up the macOS Quick Look preview extension for .drawio files. * * Copies the quicklookjs PreviewExtension.appex into the app bundle, * replaces the default preview.html with our draw.io viewer, bundles * viewer-static.min.js, and writes a custom Info.plist declaring the * com.jgraph.drawio UTI. * * This runs in afterSign (after electron-builder has signed the app) * so the .appex is never present in an unsigned state during the * build. Once assembled, it is immediately signed with sandbox * entitlements below. */ function setupQuickLookExtension(appPath, appVersion) { const plugInsDir = path.join(appPath, 'Contents', 'PlugIns'); const appexDest = path.join(plugInsDir, 'PreviewExtension.appex'); const appexResourcesDir = path.join(appexDest, 'Contents', 'Resources'); const projectDir = path.resolve(__dirname, '..'); const appexSrc = path.join(projectDir, 'node_modules', 'quicklookjs', 'dist', 'PreviewExtension.appex'); // Find viewer-static.min.js (CI copies to build/, local dev uses submodule) const viewerCandidates = [ path.join(projectDir, 'build', 'viewer-static.min.js'), path.join(projectDir, 'drawio', 'src', 'main', 'webapp', 'js', 'viewer-static.min.js'), ]; let viewerSrc = null; for (const p of viewerCandidates) { if (fs.existsSync(p)) { viewerSrc = p; break; } } if (!viewerSrc) { console.warn('Quick Look: viewer-static.min.js not found, skipping Quick Look setup'); console.warn('Quick Look: expected at one of:', viewerCandidates.join(', ')); return; } if (!fs.existsSync(appexSrc)) { console.warn('Quick Look: quicklookjs .appex not found at', appexSrc); return; } console.log('Quick Look: setting up preview extension...'); console.log('Quick Look: using viewer from', viewerSrc); // Copy .appex bundle fs.mkdirSync(plugInsDir, { recursive: true }); fs.cpSync(appexSrc, appexDest, { recursive: true }); // Copy our preview.html fs.copyFileSync( path.join(__dirname, 'quicklook-preview.html'), path.join(appexResourcesDir, 'preview.html') ); // Copy viewer-static.min.js fs.copyFileSync(viewerSrc, path.join(appexResourcesDir, 'viewer-static.min.js')); // Write custom Info.plist const infoPlist = ` CFBundleDevelopmentRegion en CFBundleDisplayName draw.io Quick Look CFBundleExecutable PreviewExtension CFBundleIdentifier ${APPEX_BUNDLE_ID} CFBundleInfoDictionaryVersion 6.0 CFBundleName PreviewExtension CFBundlePackageType XPC! CFBundleShortVersionString ${appVersion} CFBundleSupportedPlatforms MacOSX CFBundleVersion 1 LSMinimumSystemVersion 11.0 NSExtension NSExtensionAttributes QLSupportedContentTypes ${DRAWIO_UTI} QLSupportsSearchableItems NSExtensionPointIdentifier com.apple.quicklook.preview NSExtensionPrincipalClass PreviewExtension.PreviewViewController QLJS loadingStrategy waitForSignal pagePath preview.html preferredContentSize {800,600} transparentBackground `; fs.writeFileSync(path.join(appexDest, 'Contents', 'Info.plist'), infoPlist); // Remove the old code signature from the source .appex (it's invalid // after our modifications). We sign immediately below. const codeSignDir = path.join(appexDest, 'Contents', '_CodeSignature'); if (fs.existsSync(codeSignDir)) { fs.rmSync(codeSignDir, { recursive: true }); } console.log('Quick Look: setup complete'); } /** * Signs the Quick Look .appex with sandbox entitlements, then re-signs * the outer .app bundle so its seal includes the .appex. */ function signQuickLookExtension(appPath) { const appexPath = path.join(appPath, 'Contents', 'PlugIns', 'PreviewExtension.appex'); if (!fs.existsSync(appexPath)) { return; } const identity = getSigningIdentity(appPath); if (identity === '-') { console.log('Quick Look: no signing identity found, using ad-hoc signing'); } else { console.log('Quick Look: signing with identity:', identity); } const entitlementsPath = path.join(__dirname, 'quicklook-entitlements.plist'); const mainEntitlementsPath = path.join(__dirname, 'entitlements.mac.plist'); // Sign the .appex with sandbox entitlements (required for Quick Look) execSync( `codesign -f -s "${identity}" --entitlements "${entitlementsPath}" --options runtime "${appexPath}"`, { stdio: 'inherit' } ); // Re-sign the outer .app to update its seal (the .appex was added/signed) execSync( `codesign -f -s "${identity}" --entitlements "${mainEntitlementsPath}" --options runtime "${appPath}"`, { stdio: 'inherit' } ); console.log('Quick Look: signing complete'); } export default async function notarizing(context) { const { electronPlatformName, appOutDir } = context; const appName = context.packager.appInfo.productFilename; const appVersion = context.packager.appInfo.version; if (electronPlatformName !== 'darwin') { return; } const appPath = `${appOutDir}/${appName}.app`; setupQuickLookExtension(appPath, appVersion); signQuickLookExtension(appPath); return await notarize({ tool: "notarytool", appBundleId: 'com.jgraph.drawio.desktop', appPath: appPath, appleId: process.env.APPLEID, appleIdPassword: process.env.APPLEIDPASS, teamId: process.env.APPLE_TEAM_ID }); }; ================================================ FILE: build/quicklook-entitlements.plist ================================================ com.apple.security.app-sandbox ================================================ FILE: build/quicklook-preview.html ================================================
================================================ FILE: doc/.gitignore ================================================ _site .sass-cache .jekyll-metadata ================================================ FILE: doc/RELEASE_PROCESS.md ================================================ # draw.io Desktop Release Process **Document ID:** REL-PROC-DESKTOP-001 **Version:** 1.0 **Last Updated:** 2026-01-02 **Owner:** Engineering Team --- ## 1. Purpose This document defines the release process for draw.io Desktop. Automated controls via GitHub Actions handle repeatable tasks, while manual steps focus on verification and approval. **Repository:** https://github.com/jgraph/drawio-desktop **Submodule:** drawio (core editor) **CI/CD:** GitHub Actions --- ## 2. Controlled Tooling Tooling versions are pinned in the GitHub Actions workflows to ensure reproducible builds. | Tool | Version | Controlled In | |------|---------|---------------| | Node.js | 24.x (LTS) | `.github/workflows/*.yml` | | npm | (bundled with Node) | — | > **Note:** npm is bundled with Node.js, ensuring consistent versions across environments. When updating tooling versions: 1. Update the version in all workflow files 2. Test locally with matching versions 3. Document the change in the PR --- ## 3. Roles | Role | Responsibility | |------|----------------| | **Release Lead** | Triggers workflow, verifies output, approves release | | **Reviewer** | Reviews changes, provides approval before publish | > **Small Team Note:** Release Lead and Reviewer should be different people when possible. For solo releases, rely on automated checks and document the reason. --- ## 4. Release Procedure ### 4.1 Automated Preparation (GitHub Actions) The `prepare-release` workflow automates: - Updating drawio submodule to target ref (with recursive submodule init) - Updating version in package.json - Running `npm audit` and failing on critical/high vulnerabilities - Running `npm outdated` for review - Committing changes and creating version tag - Uploading audit evidence as artifacts **To trigger:** 1. Go to Actions → "Prepare Release" 2. Click "Run workflow" 3. Enter: - **version:** The release version (e.g., `29.0.4`) - **drawio_ref:** (Optional) Specific tag/commit. Defaults to `v{version}` - **dry_run:** Check to validate without committing **What happens:** ``` ┌─────────────────────────────────────────────────────────────────┐ │ Workflow: prepare-release │ ├─────────────────────────────────────────────────────────────────┤ │ 1. Validate version format (X.Y.Z) │ │ 2. Checkout with submodules (recursive) │ │ 3. Setup Node.js 24.x │ │ 4. Update drawio submodule → target ref │ │ └── Update nested submodules (recursive) │ │ 5. Update package.json version │ │ 6. npm ci │ │ 7. npm audit → FAIL if critical/high vulns │ │ 8. npm outdated → report only │ │ 9. Upload evidence artifacts │ │ 10. Commit + push │ │ 11. Create + push tag v{version} │ │ 12. Build workflows trigger automatically │ └─────────────────────────────────────────────────────────────────┘ ``` **Evidence produced:** - Workflow run log (retained by GitHub) - `release-evidence-v{VERSION}` artifact containing: - `audit-results.json` - `audit-report.txt` - `outdated-report.txt` - Job summary with version details and audit results ### 4.2 Pre-Release Verification Before triggering the workflow: | ✓ | Item | |---|------| | ☐ | Release scope documented (what's included) | | ☐ | All feature changes merged to dev branch | | ☐ | Target drawio ref exists and is tested | ### 4.3 Monitor Build After the prepare-release workflow completes: 1. Verify the build workflows triggered automatically 2. Monitor build status in Actions tab 3. All platform builds must succeed before proceeding **Evidence:** Link to successful build run: `_______________` ### 4.4 Publish Release After all build workflows complete successfully: 1. Go to GitHub Releases - a draft release will have been created with all artifacts 2. Verify all platform builds are present (Windows builds are automatically signed via CI using `CSC_LINK` secret) 3. Add release notes (Section 8) 4. **Obtain Reviewer approval** (Section 5) 5. Click "Publish release" --- ## 5. Approval Before publishing, the Reviewer verifies: | ✓ | Check | |---|-------| | ☐ | Workflow completed successfully | | ☐ | npm audit shows no critical/high vulnerabilities | | ☐ | Build workflows passed for all platforms | | ☐ | Test cases passed (Section 6) | | | Name | Date | |---|------|------| | **Release Lead** | | | | **Reviewer** | | | > **Solo Release:** Document reason, ensure all automated checks pass, perform extended testing. --- ## 6. Test Cases Run against the built application before publishing. ### Critical (Must Pass) | ID | Test | Expected | Pass | |----|------|----------|------| | T01 | Launch application | Main window displays | ☐ | | T02 | Create new diagram | Blank canvas opens | ☐ | | T03 | Add shapes | Shapes render, move, resize | ☐ | | T04 | Save file | Saves without error | ☐ | | T05 | Open file | Displays correctly | ☐ | | T06 | Help > About | Shows correct version | ☐ | ### Standard | ID | Test | Expected | Pass | |----|------|----------|------| | T07 | Export PNG/PDF/SVG | Valid output | ☐ | | T08 | Undo/Redo | Actions reverse | ☐ | ### Security | ID | Check | Method | Pass | |----|-------|--------|------| | S01 | No external scripts | DevTools Network tab | ☐ | | S02 | No data exfiltration | Monitor during save | ☐ | **Tested by:** _______________ **Date:** _______________ --- ## 7. Rollback ### When to Rollback - Critical functionality broken - Security vulnerability discovered - Data loss or corruption ### Steps 1. Convert GitHub release to draft 2. Ensure previous version is "Latest" 3. Notify team 4. Document incident below ### Incident Report **Version:** _______________ **Issue:** _______________________________________________ **Root Cause:** _______________________________________________ **Corrective Action:** _______________________________________________ **Completed by:** _______________ **Date:** _______________ --- ## 8. Release Notes Template ```markdown ## v[VERSION] - [DATE] ### Changes - [Change 1] - [Change 2] ### Fixes - [Fix 1] ### Security - Dependencies updated ### Known Issues - [If any] ``` --- ## 9. Evidence Retention Evidence is automatically retained: | Evidence | Location | Retention | |----------|----------|-----------| | Workflow logs | GitHub Actions | 90 days (GitHub default) | | Audit artifacts | Actions → Artifacts | 365 days (configured) | | Release assets | GitHub Releases | Permanent | | Git tags/commits | Repository | Permanent | For audits requiring longer retention, download artifacts to secure storage. --- ## 10. Handling Failures ### npm audit fails (critical/high vulnerabilities) 1. Review `audit-report.txt` in workflow artifacts 2. Options: - Run `npm audit fix` locally, commit, re-run workflow - If unfixable, assess risk and document exception - Delay release until fix available ### Build fails 1. Check workflow logs for error 2. Fix issue in codebase 3. Delete the tag: `git push --delete origin v{VERSION}` 4. Re-run prepare-release workflow ### Submodule ref not found 1. Verify the drawio tag/ref exists in the drawio repository 2. Use `drawio_ref` input to specify correct ref --- ## Revision History | Version | Date | Author | Changes | |---------|------------|-------------|---------| | 1.0 | 2026.01.02 | D Benson | Initial release | ================================================ FILE: electron-builder-appx.json ================================================ { "appId": "com.jgraph.drawio.desktop", "copyright": "Copyright 2017-2026 draw.io Ltd", "asar": true, "files": [ "**/*", "!**/WEB-INF{,/**}" ], "artifactName": "${productName}-${arch}-${version}.${ext}", "directories": { "output": "./dist/" }, "npmRebuild": false, "publish": { "provider": "github" }, "win": { "target": [ { "target": "appx", "arch": [ "x64" ] } ] }, "appx": { "displayName": "draw.io Diagrams", "publisherDisplayName": "draw.io Ltd", "identityName": "draw.io.draw.ioDiagrams", "publisher": "CN=9E628CCB-BE04-4557-A5A8-81EC34B09733" }, "afterPack": "build/fuses.cjs", "fileAssociations": [ { "ext": "drawio", "name": "draw.io Diagram", "description": "draw.io Diagram", "mimeType": "application/vnd.jgraph.mxfile", "role": "Editor" }, { "ext": "vsdx", "name": "VSDX Document", "description": "VSDX Document", "mimeType": "application/vnd.visio", "role": "Editor" } ] } ================================================ FILE: electron-builder-linux-mac.json ================================================ { "appId": "com.jgraph.drawio.desktop", "copyright": "Copyright 2017-2026 draw.io Ltd", "asar": true, "files": [ "**/*", "!**/WEB-INF{,/**}" ], "artifactName": "${productName}-${arch}-${version}.${ext}", "directories": { "output": "./dist/" }, "npmRebuild": false, "publish": { "provider": "github" }, "mac": { "hardenedRuntime": true, "gatekeeperAssess": false, "entitlements": "build/entitlements.mac.plist", "entitlementsInherit": "build/entitlements.mac.plist", "category": "public.app-category.graphics-design", "extendInfo": { "UTExportedTypeDeclarations": [ { "UTTypeIdentifier": "com.jgraph.drawio", "UTTypeDescription": "draw.io Diagram", "UTTypeConformsTo": ["public.xml", "public.data"], "UTTypeTagSpecification": { "public.filename-extension": ["drawio"], "public.mime-type": ["application/vnd.jgraph.mxfile"] } } ], "CFBundleDocumentTypes": [ { "CFBundleTypeExtensions": ["drawio"], "CFBundleTypeName": "draw.io Diagram", "CFBundleTypeRole": "Editor", "CFBundleTypeIconFile": "icon.icns", "LSItemContentTypes": ["com.jgraph.drawio"], "LSHandlerRank": "Owner" }, { "CFBundleTypeExtensions": ["vsdx"], "CFBundleTypeName": "VSDX Document", "CFBundleTypeRole": "Editor", "CFBundleTypeIconFile": "icon.icns", "LSHandlerRank": "Default" } ] }, "target": [ { "target": "zip", "arch": [ "x64", "arm64" ] }, { "target": "dmg", "arch": [ "x64", "arm64", "universal" ] } ] }, "afterSign": "build/notarize.mjs", "afterPack": "build/fuses.cjs", "dmg": { }, "linux": { "executableName": "drawio", "category": "Graphics", "maintainer": "draw.io ", "icon": "./build", "desktop": { "entry": { "StartupWMClass": "draw.io" } }, "target": [ { "target": "AppImage", "arch": [ "x64", "arm64" ] }, { "target": "deb", "arch": [ "x64", "arm64" ] }, { "target": "rpm", "arch": [ "x64", "arm64" ] } ] }, "rpm": { "fpm": [ "--rpm-rpmbuild-define=_build_id_links none", "--rpm-digest=sha256" ] }, "fileAssociations": [ { "ext": "drawio", "name": "draw.io Diagram", "description": "draw.io Diagram", "mimeType": "application/vnd.jgraph.mxfile", "role": "Editor" }, { "ext": "vsdx", "name": "VSDX Document", "description": "VSDX Document", "mimeType": "application/vnd.visio", "role": "Editor" } ] } ================================================ FILE: electron-builder-snap.json ================================================ { "appId": "com.jgraph.drawio.desktop", "copyright": "Copyright 2017-2026 draw.io Ltd", "asar": true, "files": [ "**/*", "!**/WEB-INF{,/**}" ], "artifactName": "${productName}-${arch}-${version}.${ext}", "directories": { "output": "./dist/" }, "npmRebuild": false, "linux": { "executableName": "drawio", "category": "Graphics", "maintainer": "draw.io ", "icon": "./build", "desktop": { "entry": { "StartupWMClass": "draw.io" } }, "target": [ "snap" ] }, "snap": { "base": "core20", "plugs": [ "default", "removable-media" ] }, "afterPack": "build/fuses.cjs", "fileAssociations": [ { "ext": "drawio", "name": "draw.io Diagram", "description": "draw.io Diagram", "mimeType": "application/vnd.jgraph.mxfile", "role": "Editor" }, { "ext": "vsdx", "name": "VSDX Document", "description": "VSDX Document", "mimeType": "application/vnd.visio", "role": "Editor" } ] } ================================================ FILE: electron-builder-win-arm64.json ================================================ { "appId": "com.jgraph.drawio.desktop", "copyright": "Copyright 2017-2026 draw.io Ltd", "asar": true, "files": [ "**/*", "!**/WEB-INF{,/**}" ], "directories": { "output": "./dist/" }, "npmRebuild": false, "publish": { "provider": "github" }, "win": { "target": [ { "target": "nsis", "arch": [ "arm64" ] }, { "target": "portable", "arch": [ "arm64" ] } ] }, "nsis": { "artifactName": "${productName}-arm64-${version}-windows-arm64-installer.${ext}", "oneClick": false, "perMachine": true, "allowToChangeInstallationDirectory": true, "runAfterFinish": false, "createDesktopShortcut": false }, "portable": { "artifactName": "${productName}-arm64-${version}-windows-arm64-no-installer.${ext}" }, "afterPack": "build/fuses.cjs", "fileAssociations": [ { "ext": "drawio", "name": "draw.io Diagram", "description": "draw.io Diagram", "mimeType": "application/vnd.jgraph.mxfile", "role": "Editor" }, { "ext": "vsdx", "name": "VSDX Document", "description": "VSDX Document", "mimeType": "application/vnd.visio", "role": "Editor" } ] } ================================================ FILE: electron-builder-win.json ================================================ { "appId": "com.jgraph.drawio.desktop", "copyright": "Copyright 2017-2026 draw.io Ltd", "asar": true, "files": [ "**/*", "!**/WEB-INF{,/**}" ], "directories": { "output": "./dist/" }, "npmRebuild": false, "publish": { "provider": "github" }, "win": { "target": [ { "target": "nsis", "arch": [ "x64" ] }, { "target": "msi", "arch": [ "x64" ] } ] }, "nsis": { "artifactName": "${productName}-${version}-windows-installer.${ext}", "oneClick": false, "perMachine": true, "allowToChangeInstallationDirectory": true, "runAfterFinish": false, "createDesktopShortcut": false }, "msi": { "artifactName": "${productName}-${version}.${ext}", "runAfterFinish": false, "createDesktopShortcut": false }, "afterPack": "build/fuses.cjs", "fileAssociations": [ { "ext": "drawio", "name": "draw.io Diagram", "description": "draw.io Diagram", "mimeType": "application/vnd.jgraph.mxfile", "role": "Editor" }, { "ext": "vsdx", "name": "VSDX Document", "description": "VSDX Document", "mimeType": "application/vnd.visio", "role": "Editor" } ] } ================================================ FILE: electron-builder-win32.json ================================================ { "appId": "com.jgraph.drawio.desktop", "copyright": "Copyright 2017-2026 draw.io Ltd", "asar": true, "files": [ "**/*", "!**/WEB-INF{,/**}" ], "directories": { "output": "./dist/" }, "npmRebuild": false, "publish": { "provider": "github" }, "win": { "target": [ { "target": "nsis", "arch": [ "ia32" ] } ] }, "nsis": { "artifactName": "${productName}-ia32-${version}-windows-32bit-installer.${ext}", "oneClick": false, "perMachine": true, "allowToChangeInstallationDirectory": true, "runAfterFinish": false, "createDesktopShortcut": false }, "afterPack": "build/fuses.cjs", "fileAssociations": [ { "ext": "drawio", "name": "draw.io Diagram", "description": "draw.io Diagram", "mimeType": "application/vnd.jgraph.mxfile", "role": "Editor" }, { "ext": "vsdx", "name": "VSDX Document", "description": "VSDX Document", "mimeType": "application/vnd.visio", "role": "Editor" } ] } ================================================ FILE: package.json ================================================ { "name": "draw.io", "version": "29.6.1", "description": "draw.io desktop", "exports": "./src/main/electron.js", "type": "module", "main": "src/main/electron.js", "engines": { "node": ">=20" }, "scripts": { "start": "electron .", "sync": "node ./sync.cjs", "release-win": "electron-builder --config electron-builder-win.json --publish always", "release-win32": "electron-builder --config electron-builder-win32.json --publish always", "release-win-arm64": "electron-builder --config electron-builder-win-arm64.json --publish always", "release-appx": "electron-builder --config electron-builder-appx.json --publish always", "release-linux": "electron-builder --config electron-builder-linux-mac.json --publish always", "release-snap": "electron-builder --config electron-builder-snap.json --publish never" }, "repository": { "type": "git", "url": "git@github.com:jgraph/drawio-desktop.git" }, "keywords": [ "draw.io", "diagram", "flowchart", "UML" ], "author": "JGraph ", "license": "Apache-2.0", "bugs": { "url": "https://github.com/jgraph/drawio-desktop/issues" }, "homepage": "https://github.com/jgraph/drawio", "dependencies": { "@cantoo/pdf-lib": "^2.6.1", "buffer": "^6.0.3", "commander": "^14.0.3", "compression": "^1.8.1", "crc": "^4.3.2", "electron-context-menu": "^4.1.1", "electron-log": "^5.4.3", "electron-progressbar": "^2.2.1", "electron-store": "^11.0.2", "electron-updater": "^6.8.3", "tslib": "^2.8.1" }, "devDependencies": { "@electron/fuses": "^1.8.0", "@electron/notarize": "^3.1.1", "dotenv": "^17.3.1", "electron": "^39.6.1", "electron-builder": "^26.8.1", "quicklookjs": "^1.0.1", "sumchecker": "^3.0.1" } } ================================================ FILE: preload.js ================================================ console.log('in preload', __dirname) PreApp = { log: s => {console.log('PreApp:', s)}, } window.addEventListener('load', e => { PreApp.log('in onLoad') }) ================================================ FILE: src/main/disableUpdate.js ================================================ export function disableUpdate() { return false;} ================================================ FILE: src/main/electron-preload.js ================================================ const { contextBridge, ipcRenderer } = require("electron"); let reqId = 1; let reqInfo = {}; let fileChangedListeners = {}; ipcRenderer.on('mainResp', (event, resp) => { var callbacks = reqInfo[resp.reqId]; if (resp.error) { callbacks.error(resp.msg, resp.e); } else { callbacks.callback(resp.data); } delete reqInfo[resp.reqId]; }); ipcRenderer.on('fileChanged', (event, resp) => { var listener = fileChangedListeners[resp.path]; if (listener) { listener(resp.curr, resp.prev); } }); contextBridge.exposeInMainWorld( 'electron', { request: (msg, callback, error) => { msg.reqId = reqId++; reqInfo[msg.reqId] = {callback: callback, error: error}; //TODO Maybe a special function for this better than this hack? //File watch special case where the callback is called multiple times if (msg.action == 'watchFile') { fileChangedListeners[msg.path] = msg.listener; delete msg.listener; } ipcRenderer.send('rendererReq', msg); }, registerMsgListener: function(action, callback) { ipcRenderer.on(action, function(event, args) { callback(args); }); }, sendMessage: function(action, args) { ipcRenderer.send(action, args); }, listenOnce: function(action, callback) { ipcRenderer.once(action, function(event, args) { callback(args); }); } } ); contextBridge.exposeInMainWorld( 'process', { type: process.type, versions: process.versions } ); ================================================ FILE: src/main/electron.js ================================================ import fs from 'fs'; import { promises as fsProm } from 'fs'; import path from 'path'; import url from 'url'; import {Menu as menu, shell, dialog, session, screen, clipboard, nativeImage, ipcMain, app, BrowserWindow} from 'electron'; import crc from 'crc'; import zlib from 'zlib'; import log from'electron-log'; import { program } from 'commander'; import elecUpPkg from 'electron-updater'; const {autoUpdater} = elecUpPkg; import {PDFDocument} from '@cantoo/pdf-lib'; import Store from 'electron-store'; import ProgressBar from 'electron-progressbar'; import contextMenu from 'electron-context-menu'; import {spawn} from 'child_process'; import {disableUpdate as disUpPkg} from './disableUpdate.js'; let store; try { store = new Store(); } catch (e) { console.error('Failed to initialize electron-store:', e); store = null; } const disableUpdate = disUpPkg() || process.env.DRAWIO_DISABLE_UPDATE === 'true' || process.argv.indexOf('--disable-update') !== -1 || fs.existsSync('/.flatpak-info'); //This file indicates running in flatpak sandbox const silentUpdate = !disableUpdate && (process.env.DRAWIO_SILENT_UPDATE === 'true' || process.argv.indexOf('--silent-update') !== -1); autoUpdater.logger = log autoUpdater.logger.transports.file.level = 'error' autoUpdater.logger.transports.console.level = 'error' autoUpdater.autoDownload = silentUpdate autoUpdater.autoInstallOnAppQuit = silentUpdate const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); //Command option to disable hardware acceleration if (process.argv.indexOf('--disable-acceleration') !== -1) { app.disableHardwareAcceleration(); } // Configure context menu for text fields contextMenu({ showCopyImage: true, showSaveImage: true, showSaveImageAs: true, showLookUpSelection: false, showSearchWithGoogle: false, showCopyLink: false, showSelectAll: true, append: (defaultActions, params, browserWindow) => [ { label: 'Paste and Match Style', // Only show this item when there's a text in the clipboard visible: clipboard.availableFormats().includes('text/plain'), click: () => { // Execute the paste command in the focused window browserWindow.webContents.pasteAndMatchStyle(); } } ] }); const __DEV__ = process.env.DRAWIO_ENV === 'dev' let windowsRegistry = [] let cmdQPressed = false let firstWinLoaded = false let firstWinFilePath = null const isMac = process.platform === 'darwin' const isWin = process.platform === 'win32' let enableSpellCheck = store != null ? store.get('enableSpellCheck') : false; enableSpellCheck = enableSpellCheck != null ? enableSpellCheck : isMac; let enableStoreBkp = store != null ? (store.get('enableStoreBkp') != null ? store.get('enableStoreBkp') : true) : false; let dialogOpen = false; let enablePlugins = false; const codeDir = path.join(__dirname, '/../../drawio/src/main/webapp'); const codeUrl = url.pathToFileURL(codeDir).href.replace(/\/.\:\//, str => str.toUpperCase()); // Fix for windows drive letter // Production app uses asar archive, so we need to go up two more level. It's extra cautious since asar is read-only anyway. const appBaseDir = path.join(__dirname, __dirname.endsWith(path.join('resources', 'app.asar', 'src', 'main')) ? '/../../../../' : '/../../'); let appZoom = 1; // Disabled by default let isGoogleFontsEnabled = store != null ? (store.get('isGoogleFontsEnabled') != null? store.get('isGoogleFontsEnabled') : false) : false; //Read config file var queryObj = { 'dev': __DEV__ ? 1 : 0, 'test': __DEV__ ? 1 : 0, 'gapi': 0, 'db': 0, 'od': 0, 'gh': 0, 'gl': 0, 'tr': 0, 'browser': 0, 'picker': 0, 'mode': 'device', 'export': 'https://convert.diagrams.net/node/export', 'disableUpdate': disableUpdate? 1 : 0, 'enableSpellCheck': enableSpellCheck? 1 : 0, 'enableStoreBkp': enableStoreBkp? 1 : 0, 'isGoogleFontsEnabled': isGoogleFontsEnabled? 1 : 0 }; try { if (fs.existsSync(process.cwd() + '/urlParams.json')) { let urlParams = JSON.parse(fs.readFileSync(process.cwd() + '/urlParams.json')); for (var param in urlParams) { queryObj[param] = urlParams[param]; } } } catch(e) { console.log('Error in urlParams.json file: ' + e.message); } // Trying sandboxing the renderer for more protection //app.enableSandbox(); // This maybe the reason snap stopped working // Only allow request from the app code itself function validateSender (frame) { return frame.url.replace(/\/.\:\//, str => str.toUpperCase()).startsWith(codeUrl); } function isWithinDisplayBounds(pos) { const displays = screen.getAllDisplays(); return displays.reduce((result, display) => { const area = display.workArea return ( result || (pos.x >= area.x && pos.y >= area.y && pos.x < area.x + area.width && pos.y < area.y + area.height) ) }, false) } function createWindow (opt = {}) { let lastWinSizeStr = (store && store.get('lastWinSize')) || '1200,800,0,0,false,false'; let lastWinSize = lastWinSizeStr ? lastWinSizeStr.split(',') : [1200, 800]; // TODO On some Mac OS, double click the titlebar set incorrect window size if (lastWinSize[0] < 500) { lastWinSize[0] = 500; } if (lastWinSize[1] < 500) { lastWinSize[1] = 500; } let options = Object.assign( { backgroundColor: '#FFF', width: parseInt(lastWinSize[0]), height: parseInt(lastWinSize[1]), icon: `${codeDir}/images/drawlogo256.png`, webviewTag: false, webSecurity: true, webPreferences: { preload: `${__dirname}/electron-preload.js`, spellcheck: enableSpellCheck, contextIsolation: true, disableBlinkFeatures: 'Auxclick' // Is this needed? } }, opt) if (lastWinSize[2] != null) { options.x = parseInt(lastWinSize[2]); } if (lastWinSize[3] != null) { options.y = parseInt(lastWinSize[3]); } if (!isWithinDisplayBounds(options)) { options.x = null; options.y = null; } let mainWindow = new BrowserWindow(options) windowsRegistry.push(mainWindow) if (lastWinSize[4] === 'true') { mainWindow.maximize() } if (lastWinSize[5] === 'true') { mainWindow.setFullScreen(true); } if (__DEV__) { console.log('createWindow', opt) } //Cannot be read before app is ready queryObj['appLang'] = app.getLocale(); let ourl = url.format( { pathname: `${codeDir}/index.html`, protocol: 'file:', query: queryObj, slashes: true }) mainWindow.loadURL(ourl) // Open the DevTools. if (__DEV__) { mainWindow.webContents.openDevTools() } ipcMain.on('openDevTools', function(e) { if (!validateSender(e.senderFrame)) return null; mainWindow.webContents.openDevTools(); }); function rememberWinSize(win) { if (store != null) { const size = win.getSize(); const pos = win.getPosition(); store.set('lastWinSize', size[0] + ',' + size[1] + ',' + pos[0] + ',' + pos[1] + ',' + win.isMaximized() + ',' + win.isFullScreen()); } } mainWindow.on('maximize', function() { mainWindow.webContents.send('maximize') }); mainWindow.on('unmaximize', function() { mainWindow.webContents.send('unmaximize') }); mainWindow.on('resize', function() { mainWindow.webContents.send('resize') }); let uniqueIsModifiedId, modifiedModalOpen = false; ipcMain.on('isModified-result', async (e, data) => { if (!validateSender(e.senderFrame) || uniqueIsModifiedId != data.uniqueId || modifiedModalOpen) return null; if (data.isModified) { modifiedModalOpen = true; // Can't use async function here because it crashes on Linux when win.destroy is called let response = dialog.showMessageBoxSync( mainWindow, { type: 'question', buttons: ['Cancel', 'Discard Changes'], title: 'Confirm', message: 'The document has unsaved changes. Do you really want to quit without saving?' //mxResources.get('allChangesLost') }); if (response === 1) { //If user chose not to save, remove the draft if (data.draftPath != null) { await deleteFile(data.draftPath); mainWindow.destroy(); } else { mainWindow.webContents.send('removeDraft'); ipcMain.once('draftRemoved', (e) => { if (!validateSender(e.senderFrame)) return null; mainWindow.destroy(); }); } } else { cmdQPressed = false; modifiedModalOpen = false; } } else { mainWindow.destroy(); } }); mainWindow.on('close', (event) => { uniqueIsModifiedId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); if (__DEV__) { const index = windowsRegistry.indexOf(mainWindow) console.log('Window on close', index, uniqueIsModifiedId) } const contents = mainWindow.webContents if (contents != null) { contents.send('isModified', uniqueIsModifiedId); event.preventDefault(); } rememberWinSize(mainWindow); }) // Emitted when the window is closed. mainWindow.on('closed', () => { const index = windowsRegistry.indexOf(mainWindow) if (__DEV__) { console.log('Window closed idx:%d', index) } windowsRegistry.splice(index, 1) }) return mainWindow } function isPluginsEnabled() { return enablePlugins; } // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.whenReady().then(() => { // Enforce our CSP on all contents session.defaultSession.webRequest.onHeadersReceived((details, callback) => { callback({ responseHeaders: { ...details.responseHeaders, // Replace the first sha with the one of the current version shown in the console log (the second one is for the second script block which is rarely changed) // 3rd sha is for electron-progressbar 'Content-Security-Policy': ['default-src \'self\'; script-src \'self\' \'sha256-f6cHSTUnCvbQqwa6rKcbWIpgN9dLl0ROfpEKTQUQPr8=\' \'sha256-6g514VrT/cZFZltSaKxIVNFF46+MFaTSDTPB8WfYK+c=\' \'sha256-ZQ86kVKhLmcnklYAnUksoyZaLkv7vvOG9cc/hBJAEuQ=\'; connect-src \'self\'' + (isGoogleFontsEnabled? ' https://fonts.googleapis.com https://fonts.gstatic.com' : '') + '; img-src * data:; media-src *; font-src * data:; frame-src \'none\'; style-src \'self\' \'unsafe-inline\'' + (isGoogleFontsEnabled? ' https://fonts.googleapis.com' : '') + '; base-uri \'none\';child-src \'self\';object-src \'none\';'] } }) }); const pluginsCodeUrl = url.pathToFileURL(path.join(getAppDataFolder(), '/plugins/')).href.replace(/\/.\:\//, str => str.toUpperCase()); // Enforce loading file only from our app directory session.defaultSession.webRequest.onBeforeRequest({urls: ['file://*']}, (details, callback) => { const url = details.url.replace(/\/.\:\//, str => str.toUpperCase()); if (!url.startsWith(codeUrl) && (!isPluginsEnabled() || (isPluginsEnabled() && !url.startsWith(pluginsCodeUrl)))) { console.log('Blocked loading file from ' + details.url, url, codeUrl, pluginsCodeUrl); callback({cancel: true}); } else { callback({}); } }); ipcMain.on('newfile', (e, arg) => { if (!validateSender(e.senderFrame)) return null; let opts = {}; if (arg) { if (arg.width) { opts.width = arg.width; } if (arg.height) { opts.height = arg.height; } } createWindow(opts); }) let argv = process.argv // https://github.com/electron/electron/issues/4690#issuecomment-217435222 if (process.defaultApp != true) { argv.unshift(null) } var validFormatRegExp = /^(pdf|svg|png|jpeg|jpg|xml)$/; var themeRegExp = /^(dark|light)$/; var linkTargetRegExp = /^(auto|new-win|same-win)$/; function argsRange(val) { return val.split('..').map(n => parseInt(n, 10) - 1); } try { program.allowExcessArguments(); program .version(app.getVersion()) .usage('[options] ') .argument('[input file/folder]', 'input drawio file or a folder with drawio files') .allowUnknownOption() //-h and --help are considered unknown!! .option('-c, --create', 'creates a new empty file if no file is passed') .option('-k, --check', 'does not overwrite existing files') .option('-x, --export', 'export the input file/folder based on the given options') .option('-r, --recursive', 'for a folder input, recursively convert all files in sub-folders also') .option('-o, --output ', 'specify the output file/folder. If omitted, the input file name is used for output with the specified format as extension') .option('-f, --format ', 'if output file name extension is specified, this option is ignored (file type is determined from output extension, possible export formats are pdf, png, jpg, svg, and xml)', validFormatRegExp, 'pdf') .option('-q, --quality ', 'output image quality for JPEG (default: 90)', parseInt) .option('-t, --transparent', 'set transparent background for PNG') .option('-e, --embed-diagram', 'includes a copy of the diagram (for PNG, SVG and PDF formats only)') .option('--embed-svg-images', 'Embed Images in SVG file (for SVG format only)') .option('--embed-svg-fonts ', 'Embed Fonts in SVG file (for SVG format only). Default is true', function(x){return x === 'true'}, true) .option('-b, --border ', 'sets the border width around the diagram (default: 0)', parseInt) .option('-s, --scale ', 'scales the diagram size', parseFloat) .option('--width ', 'fits the generated image/pdf into the specified width, preserves aspect ratio.', parseInt) .option('--height ', 'fits the generated image/pdf into the specified height, preserves aspect ratio.', parseInt) .option('--crop', 'crops PDF to diagram size') .option('-a, --all-pages', 'export all pages (for PDF format only)') .option('-p, --page-index ', 'selects a specific page (1-based); if not specified and the format is an image, the first page is selected', (i) => parseInt(i) - 1) .option('-l, --layers ', 'selects which layers to export (applies to all pages), if not specified, all layers are selected') .option('-g, --page-range ..', 'selects a page range (1-based, for PDF format only)', argsRange) .option('-u, --uncompressed', 'Uncompressed XML output (for XML format only)') .option('-z, --zoom ', 'scales the application interface', parseFloat) .option('--svg-theme ', 'Theme of the exported SVG image (dark, light, auto [default])', themeRegExp, 'auto') .option('--svg-links-target ', 'Target of links in the exported SVG image (auto [default], new-win, same-win)', linkTargetRegExp, 'auto') .option('--enable-plugins', 'Enable Plugins') .parse(argv) } catch(e) { //On parse error, return [exit and commander will show the error message] return; } var options = program.opts(); enablePlugins = options.enablePlugins; if (options.zoom != null) { appZoom = options.zoom; } //Start export mode? if (options.export) { var dummyWin = new BrowserWindow({ show : false, webPreferences: { preload: `${__dirname}/electron-preload.js`, contextIsolation: true, disableBlinkFeatures: 'Auxclick' // Is this needed? } }); windowsRegistry.push(dummyWin); /*ipcMain.on('log', function(event, msg) { console.log(msg); });*/ try { //Prepare arguments and confirm it's valid var format = null; var outType = null; //Format & Output if (options.output) { try { var outStat = fs.statSync(options.output); if (outStat.isDirectory()) { outType = {isDir: true}; } else //If we can get file stat, then it exists { throw 'Error: Output file already exists'; } } catch(e) //on error, file doesn't exist and it is not a dir { outType = {isFile: true}; format = path.extname(options.output).substr(1); if (!validFormatRegExp.test(format)) { format = null; } } } if (format == null) { format = options.format; } let from = null, to = null; if (options.pageIndex != null && options.pageIndex >= 0) { from = options.pageIndex; to = options.pageIndex; options.allPages = false; } else if (options.pageRange && options.pageRange.length == 2) { const [rangeFrom, rangeTo] = options.pageRange; if (rangeFrom >= 0 && rangeTo >= 0 && rangeFrom <= rangeTo) { from = rangeFrom; to = rangeTo; options.allPages = false; } else { console.error('Invalid page range: must be non-negative and from ≤ to'); process.exit(1); } } var expArgs = { format: format, w: options.width > 0 ? options.width : null, h: options.height > 0 ? options.height : null, bg: options.transparent ? 'none' : '#ffffff', from: from, to: to, allPages: format == 'pdf' && options.allPages, scale: (options.scale || 1), embedXml: options.embedDiagram? '1' : '0', embedImages: options.embedSvgImages? '1' : '0', embedFonts: options.embedSvgFonts? '1' : '0', jpegQuality: options.quality, uncompressed: options.uncompressed, theme: options.svgTheme, linkTarget: options.svgLinksTarget, crop: (options.crop && format == 'pdf') ? '1' : '0' }; options.border = options.border > 0 ? options.border : 0; if (format === 'pdf') { expArgs.pageMargin = options.border; } else { expArgs.border = options.border; } if (options.layers) { expArgs.extras = JSON.stringify({layers: options.layers.split(',')}); } var paths = program.args; // Remove --no-sandbox arg from the paths if (Array.isArray(paths)) { paths = paths.filter(function(path) { return path != null && path != '--no-sandbox'; }); } // If a file is passed if (paths !== undefined && paths[0] != null) { var inStat = null; try { inStat = fs.statSync(paths[0]); } catch(e) { throw 'Error: input file/directory not found'; } var files = []; function addDirectoryFiles(dir, isRecursive) { fs.readdirSync(dir).forEach(function(file) { var filePath = path.join(dir, file); var stat = fs.statSync(filePath); if (stat.isFile() && path.basename(filePath).charAt(0) != '.') { files.push(filePath); } if (stat.isDirectory() && isRecursive) { addDirectoryFiles(filePath, isRecursive) } }); } if (inStat.isFile()) { files.push(paths[0]); } else if (inStat.isDirectory()) { addDirectoryFiles(paths[0], options.recursive); } if (files.length > 0) { var fileIndex = 0; function processOneFile() { var curFile = files[fileIndex]; try { var ext = path.extname(curFile); let fileContent = fs.readFileSync(curFile, ext === '.png' || ext === '.vsdx' ? null : 'utf-8'); if (ext === '.vsdx') { dummyWin.loadURL(`file://${codeDir}/vsdxImporter.html`); const contents = dummyWin.webContents; contents.on('did-finish-load', function() { contents.send('import', fileContent); ipcMain.once('import-success', function(e, xml) { if (!validateSender(e.senderFrame)) return null; expArgs.xml = xml; startExport(); }); ipcMain.once('import-error', function(e) { if (!validateSender(e.senderFrame)) return null; console.error('Error: cannot import VSDX file: ' + curFile); next(); }); }); } else { if (ext === '.csv') { expArgs.csv = fileContent; } else if (ext === '.png') { expArgs.xmlEncoded = true; expArgs.xml = Buffer.from(fileContent).toString('base64'); } else { expArgs.xml = fileContent; } startExport(); } function next() { fileIndex++; if (fileIndex < files.length) { processOneFile(); } else { cmdQPressed = true; dummyWin.destroy(); } }; function startExport() { var replied = false; var mockEvent = { reply: function(msg, data) { if (replied) return; replied = true; try { if (msg == 'export-success') { if (data == null || data.length == 0) { console.error('Error: Empty export data: ' + curFile); } else { var outFileName = null; if (outType != null) { if (outType.isDir) { outFileName = path.join(options.output, path.basename(curFile, path.extname(curFile))) + '.' + format; } else { outFileName = options.output; } } else if (inStat.isFile()) { outFileName = path.join(path.dirname(paths[0]), path.basename(paths[0], path.extname(paths[0]))) + '.' + format; } else //dir { outFileName = path.join(path.dirname(curFile), path.basename(curFile, path.extname(curFile))) + '.' + format; } try { var counter = 0; var realFileName = outFileName; if (program.rawArgs.indexOf('-k') > -1 || program.rawArgs.indexOf('--check') > -1) { while (fs.existsSync(realFileName)) { counter++; realFileName = path.join(path.dirname(outFileName), path.basename(outFileName, path.extname(outFileName))) + '-' + counter + path.extname(outFileName); } } let fh = fs.openSync(realFileName, fs.constants.O_SYNC | fs.constants.O_CREAT | fs.constants.O_WRONLY | fs.constants.O_TRUNC); try { fs.writeFileSync(fh, data); fs.fsyncSync(fh); } finally { fs.closeSync(fh); } console.log(curFile + ' -> ' + realFileName); } catch(e) { console.error('Error writing to file: ' + outFileName); } } } else { console.error('Error: ' + (data || 'Export failed') + ': ' + curFile); } next(); } finally { mockEvent.finalize(); } } }; exportDiagram(mockEvent, expArgs, true); }; } catch(e) { console.error('Error reading file: ' + curFile); next(); } } processOneFile(); } else { throw 'Error: input file/directory not found or directory is empty'; } } else { throw 'Error: An input file must be specified'; } } catch(e) { console.error(e); cmdQPressed = true; dummyWin.destroy(); } return; } else if (program.rawArgs.indexOf('-h') > -1 || program.rawArgs.indexOf('--help') > -1 || program.rawArgs.indexOf('-V') > -1 || program.rawArgs.indexOf('--version') > -1) //To prevent execution when help/version arg is used { app.quit(); return; } //Prevent multiple instances of the application (casuses issues with configuration) const gotTheLock = app.requestSingleInstanceLock() if (!gotTheLock) { app.quit() } else { app.on('second-instance', (event, commandLine, workingDirectory) => { // Creating a new window while a save/open dialog is open crashes the app if (dialogOpen) return; //Create another window let win = createWindow() let loadEvtCount = 0; function loadFinished(e) { if (e != null && !validateSender(e.senderFrame)) return null; loadEvtCount++; if (loadEvtCount == 2) { //Open the file if new app request is from opening a file var potFile = commandLine.pop(); if (fs.existsSync(potFile)) { win.webContents.send('args-obj', {args: [potFile]}); } } } //Order of these two events is not guaranteed, so wait for them async. //TOOD There is still a chance we catch another window 'app-load-finished' if user created multiple windows quickly ipcMain.once('app-load-finished', loadFinished); win.webContents.on('did-finish-load', function() { win.webContents.zoomFactor = appZoom; win.webContents.setVisualZoomLevelLimits(1, appZoom); loadFinished(); }); }) } let win = createWindow() let loadEvtCount = 0; function loadFinished(e) { if (e != null && !validateSender(e.senderFrame)) return null; loadEvtCount++; if (loadEvtCount == 2) { //Sending entire program is not allowed in Electron 9 as it is not native JS object win.webContents.send('args-obj', {args: program.args, create: options.create}); } } //Order of these two events is not guaranteed, so wait for them async. //TOOD There is still a chance we catch another window 'app-load-finished' if user created multiple windows quickly ipcMain.once('app-load-finished', loadFinished); win.webContents.on('did-finish-load', function() { if (firstWinFilePath != null) { if (program.args != null) { program.args.push(firstWinFilePath); } else { program.args = [firstWinFilePath]; } } firstWinLoaded = true; win.webContents.zoomFactor = appZoom; win.webContents.setVisualZoomLevelLimits(1, appZoom); loadFinished(); }); function toggleSpellCheck(e) { if (e != null && !validateSender(e.senderFrame)) return null; if (store != null) { enableSpellCheck = !enableSpellCheck; store.set('enableSpellCheck', enableSpellCheck); } }; ipcMain.on('toggleSpellCheck', toggleSpellCheck); function toggleStoreBkp(e) { if (e != null && !validateSender(e.senderFrame)) return null; if (store != null) { enableStoreBkp = !enableStoreBkp; store.set('enableStoreBkp', enableStoreBkp); } }; ipcMain.on('toggleStoreBkp', toggleStoreBkp); function toggleGoogleFonts(e) { if (e != null && !validateSender(e.senderFrame)) return null; if (store != null) { isGoogleFontsEnabled = !isGoogleFontsEnabled; store.set('isGoogleFontsEnabled', isGoogleFontsEnabled); } } ipcMain.on('toggleGoogleFonts', toggleGoogleFonts); function toggleFullscreen(e) { if (e != null && !validateSender(e.senderFrame)) return null; let win = BrowserWindow.getFocusedWindow(); if (win != null) { win.setFullScreen(!win.isFullScreen()); } }; ipcMain.on('toggleFullscreen', toggleFullscreen); let updateNoAvailAdded = false; function checkForUpdatesFn(e) { if (e != null && e.senderFrame != null && !validateSender(e.senderFrame)) return null; autoUpdater.checkForUpdates(); if (store != null) { store.set('dontCheckUpdates', false); } if (!updateNoAvailAdded) { updateNoAvailAdded = true; autoUpdater.on('update-not-available', (info) => { dialog.showMessageBox( { type: 'info', title: 'No updates found', message: 'Your application is up-to-date', }) }) } }; var zoomSteps = [0.25, 0.33, 0.5, 0.67, 0.75, 0.8, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4, 5]; // Zooms to the next zoom step function zoomInFn() { var zoomFactor = win.webContents.zoomFactor; var newZoomFactor = zoomSteps[zoomSteps.length - 1]; for (var i = 0; i < zoomSteps.length; i++) { if (zoomSteps[i] - zoomFactor > 0.01) { newZoomFactor = zoomSteps[i]; break; } } win.webContents.zoomFactor = newZoomFactor; }; // Zooms to the previous zoom step function zoomOutFn() { var zoomFactor = win.webContents.zoomFactor; var newZoomFactor = zoomSteps[0]; for (var i = zoomSteps.length - 1; i >= 0; i--) { if (zoomSteps[i] - zoomFactor < -0.01) { newZoomFactor = zoomSteps[i]; break; } } win.webContents.zoomFactor = newZoomFactor; }; // Resets the zoom factor function resetZoomFn() { win.webContents.zoomFactor = 1; }; let checkForUpdates = { label: 'Check for updates', click: checkForUpdatesFn } let zoomIn = { label: 'Zoom In', click: zoomInFn }; let zoomOut = { label: 'Zoom Out', click: zoomOutFn }; let resetZoom = { label: 'Actual Size', click: resetZoomFn }; ipcMain.on('checkForUpdates', checkForUpdatesFn); ipcMain.on('zoomIn', zoomInFn); ipcMain.on('zoomOut', zoomOutFn); ipcMain.on('resetZoom', resetZoomFn); if (isMac) { let template = [{ label: app.name, submenu: [ { label: 'About ' + app.name, click() { shell.openExternal('https://www.drawio.com'); } }, { label: 'Support', click() { shell.openExternal('https://github.com/jgraph/drawio-desktop/issues'); } }, checkForUpdates, { type: 'separator' }, resetZoom, zoomIn, zoomOut, { type: 'separator' }, { role: 'hide' }, { role: 'hideothers' }, { role: 'unhide' }, { type: 'separator' }, { role: 'quit' } ] }, { label: 'Edit', submenu: [ { role: 'undo' }, { role: 'redo' }, { type: 'separator' }, { role: 'cut' }, { role: 'copy' }, { role: 'paste' }, { role: 'pasteAndMatchStyle' }, { role: 'selectAll' } ] }] if (disableUpdate) { template[0].submenu.splice(2, 1); } const menuBar = menu.buildFromTemplate(template) menu.setApplicationMenu(menuBar) } else //hide menubar in win/linux { menu.setApplicationMenu(null) } autoUpdater.setFeedURL({ provider: 'github', repo: 'drawio-desktop', owner: 'jgraph' }) if (store == null || (!disableUpdate && !store.get('dontCheckUpdates'))) { autoUpdater.checkForUpdates() } }) //Quit from the dock context menu should quit the application directly if (isMac) { app.on('before-quit', function() { cmdQPressed = true; }); } // Quit when all windows are closed. app.on('window-all-closed', function () { if (__DEV__) { console.log('window-all-closed', windowsRegistry.length) } // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q if (cmdQPressed || !isMac) { app.quit() } }) app.on('activate', function () { if (__DEV__) { console.log('app on activate', windowsRegistry.length) } // On OS X it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (windowsRegistry.length === 0) { createWindow() } }) app.on('will-finish-launching', function() { app.on("open-file", function(event, filePath) { event.preventDefault(); // Creating a new window while a save/open dialog is open crashes the app if (dialogOpen) return; if (firstWinLoaded) { let win = createWindow(); let loadEvtCount = 0; function loadFinished(e) { if (e != null && !validateSender(e.senderFrame)) return null; loadEvtCount++; if (loadEvtCount == 2) { win.webContents.send('args-obj', {args: [filePath]}); } } //Order of these two events is not guaranteed, so wait for them async. //TOOD There is still a chance we catch another window 'app-load-finished' if user created multiple windows quickly ipcMain.once('app-load-finished', loadFinished); win.webContents.on('did-finish-load', function() { win.webContents.zoomFactor = appZoom; win.webContents.setVisualZoomLevelLimits(1, appZoom); loadFinished(); }); } else { firstWinFilePath = filePath } }); }); app.on('web-contents-created', (event, contents) => { // Disable navigation contents.on('will-navigate', (event, navigationUrl) => { event.preventDefault() }) // Limit creation of new windows (we also override window.open) contents.setWindowOpenHandler(({ url }) => { // We allow external absolute URLs to be open externally (check openExternal for details) and also empty windows (url -> about:blank) if (url.startsWith('about:blank')) { return { action: 'allow', overrideBrowserWindowOptions: { fullscreenable: false, webPreferences: { contextIsolation: true } } } } else if (!openExternal(url)) { return {action: 'deny'} } }) // Disable all webviews contents.on('will-attach-webview', (event, webPreferences, params) => { event.preventDefault() }) }) autoUpdater.on('error', e => log.error('@error@\n', e)) autoUpdater.on('update-available', (a, b) => { if (silentUpdate) return; dialog.showMessageBox( { type: 'question', buttons: ['Ok', 'Cancel', 'Don\'t Ask Again'], title: 'Confirm draw.io Update', message: 'draw.io update available.\n\nWould you like to download and install new version?', detail: 'Application will automatically restart to apply update after download', }).then( result => { if (result.response === 0) { autoUpdater.downloadUpdate() var progressBar = new ProgressBar({ title: 'draw.io Update', text: 'Downloading draw.io update...' }); function reportUpdateError(e) { progressBar.detail = 'Error occurred while fetching updates. ' + (e && e.message? e.message : e) progressBar._window.setClosable(true); } autoUpdater.on('error', e => { if (progressBar._window != null) { reportUpdateError(e); } else { progressBar.on('ready', function() { reportUpdateError(e); }); } }) var firstTimeProg = true; autoUpdater.on('download-progress', (d) => { //On mac, download-progress event is not called, so the indeterminate progress will continue until download is finished var percent = d.percent; if (percent) { percent = Math.round(percent * 100)/100; } if (firstTimeProg) { firstTimeProg = false; progressBar.close(); progressBar = new ProgressBar({ indeterminate: false, title: 'draw.io Update', text: 'Downloading draw.io update...', detail: `${percent}% ...`, initialValue: percent }); progressBar .on('completed', function() { progressBar.detail = 'Download completed.'; }) .on('aborted', function(value) { if (__DEV__) { log.error(`progress aborted... ${value}`); } }) .on('progress', function(value) { progressBar.detail = `${value}% ...`; }) .on('ready', function() { //InitialValue doesn't set the UI! so this is needed to render it correctly progressBar.value = percent; }); } else { progressBar.value = percent; } }); autoUpdater.on('update-downloaded', (info) => { if (!progressBar.isCompleted()) { progressBar.close() } // Ask user to update the app dialog.showMessageBox( { type: 'question', buttons: ['Install', 'Later'], defaultId: 0, message: 'A new version of ' + app.name + ' has been downloaded', detail: 'It will be installed the next time you restart the application', }).then(result => { if (result.response === 0) { setTimeout(() => autoUpdater.quitAndInstall(), 1) } }) }); } else if (result.response === 2 && store != null) { //save in settings don't check for updates store.set('dontCheckUpdates', true) } }) }) //Pdf export const MICRON_TO_PIXEL = 264.58 //264.58 micron = 1 pixel const PIXELS_PER_INCH = 100.117 // Usually it is 100 pixels per inch but this give better results const PNG_CHUNK_IDAT = 1229209940; const LARGE_IMAGE_AREA = 30000000; //NOTE: Key length must not be longer than 79 bytes (not checked) function writePngWithText(origBuff, key, text, compressed, base64encoded) { var isDpi = key == 'dpi'; var inOffset = 0; var outOffset = 0; var data = text; var dataLen = isDpi? 9 : key.length + data.length + 1; //we add 1 zeros with non-compressed data, for pHYs it's 2 of 4-byte-int + 1 byte //prepare compressed data to get its size if (compressed) { data = zlib.deflateRawSync(encodeURIComponent(text)); dataLen = key.length + data.length + 2; //we add 2 zeros with compressed data } var outBuff = Buffer.allocUnsafe(origBuff.length + dataLen + 4); //4 is the header size "zTXt", "tEXt" or "pHYs" try { var magic1 = origBuff.readUInt32BE(inOffset); inOffset += 4; var magic2 = origBuff.readUInt32BE(inOffset); inOffset += 4; if (magic1 != 0x89504e47 && magic2 != 0x0d0a1a0a) { throw new Error("PNGImageDecoder0"); } outBuff.writeUInt32BE(magic1, outOffset); outOffset += 4; outBuff.writeUInt32BE(magic2, outOffset); outOffset += 4; } catch (e) { log.error(e.message, {stack: e.stack}); throw new Error("PNGImageDecoder1"); } try { while (inOffset < origBuff.length) { var length = origBuff.readInt32BE(inOffset); inOffset += 4; var type = origBuff.readInt32BE(inOffset) inOffset += 4; if (type == PNG_CHUNK_IDAT) { // Insert zTXt chunk before IDAT chunk outBuff.writeInt32BE(dataLen, outOffset); outOffset += 4; var typeSignature = isDpi? 'pHYs' : (compressed ? "zTXt" : "tEXt"); outBuff.write(typeSignature, outOffset); outOffset += 4; if (isDpi) { var dpm = Math.round(parseInt(text) / 0.0254) || 3937; //One inch is equal to exactly 0.0254 meters. 3937 is 100dpi outBuff.writeInt32BE(dpm, outOffset); outBuff.writeInt32BE(dpm, outOffset + 4); outBuff.writeInt8(1, outOffset + 8); outOffset += 9; data = Buffer.allocUnsafe(9); data.writeInt32BE(dpm, 0); data.writeInt32BE(dpm, 4); data.writeInt8(1, 8); } else { outBuff.write(key, outOffset); outOffset += key.length; outBuff.writeInt8(0, outOffset); outOffset ++; if (compressed) { outBuff.writeInt8(0, outOffset); outOffset ++; data.copy(outBuff, outOffset); } else { outBuff.write(data, outOffset); } outOffset += data.length; } var crcVal = 0xffffffff; crcVal = crc.crcjam(typeSignature, crcVal); crcVal = crc.crcjam(data, crcVal); // CRC outBuff.writeInt32BE(crcVal ^ 0xffffffff, outOffset); outOffset += 4; // Writes the IDAT chunk after the zTXt outBuff.writeInt32BE(length, outOffset); outOffset += 4; outBuff.writeInt32BE(type, outOffset); outOffset += 4; origBuff.copy(outBuff, outOffset, inOffset); // Encodes the buffer using base64 if requested return base64encoded? outBuff.toString('base64') : outBuff; } outBuff.writeInt32BE(length, outOffset); outOffset += 4; outBuff.writeInt32BE(type, outOffset); outOffset += 4; origBuff.copy(outBuff, outOffset, inOffset, inOffset + length + 4);// +4 to move past the crc inOffset += length + 4; outOffset += length + 4; } } catch (e) { log.error(e.message, {stack: e.stack}); throw e; } } async function mergePdfs(pdfFiles, xml) { if (pdfFiles.length == 1) { // Converts to PDF 1.7 with compression const pdfDoc = await PDFDocument.load(pdfFiles[0]); pdfDoc.setCreator('diagrams.net'); // KNOWN: Attachments produce smaller files but break // internal links in pdf-lib so using Subject for now if (xml != null) { pdfDoc.setSubject(encodeURIComponent(xml). replace(/\(/g, "\\(").replace(/\)/g, "\\)")); } const pdfBytes = await pdfDoc.save(); return Buffer.from(pdfBytes); } try { const pdfDoc = await PDFDocument.create(); pdfDoc.setCreator('diagrams.net'); if (xml != null) { //Embed diagram XML as file attachment await pdfDoc.attach(Buffer.from(xml).toString('base64'), 'diagram.xml', { mimeType: 'application/vnd.jgraph.mxfile', description: 'Diagram Content' }); } for (var i = 0; i < pdfFiles.length; i++) { try { const pdfFile = await PDFDocument.load(pdfFiles[i].buffer); const pages = await pdfDoc.copyPages(pdfFile, pdfFile.getPageIndices()); pages.forEach(p => pdfDoc.addPage(p)); } catch (innerError) { log.error(`Failed to load PDF part ${i}:`, innerError); throw new Error(`Failed to process page ${i+1}. The file may be corrupt.`); } } const pdfBytes = await pdfDoc.save(); return Buffer.from(pdfBytes); } catch(e) { throw new Error('Error during PDF combination: ' + e.message); } } //TODO Use canvas to export images if math is not used to speedup export (no capturePage). Requires change to export3.html also function exportDiagram(event, args, directFinalize) { if (event != null && event.senderFrame != null && !validateSender(event.senderFrame)) return null; var browser = null; try { browser = new BrowserWindow({ webPreferences: { preload: `${__dirname}/electron-preload.js`, backgroundThrottling: false, contextIsolation: true, disableBlinkFeatures: 'Auxclick', // Is this needed? offscreen: true, }, show : false, frame: false, enableLargerThanScreen: true, transparent: args.format == 'png' && (args.bg == null || args.bg == 'none'), parent: windowsRegistry[0] //set parent to first opened window. Not very accurate, but useful when all visible windows are closed }); browser.loadURL(`file://${codeDir}/export3.html`); const contents = browser.webContents; var from = args.from; var to = args.to; var pdfs = []; contents.on('did-finish-load', function() { //Set finalize here since it is call in the reply below function finalize() { browser.destroy(); }; if (directFinalize === true) { event.finalize = finalize; } else { //Destroy the window after response being received by caller ipcMain.once('export-finalize', finalize); } function renderingFinishHandler(e, renderInfo) { if (!validateSender(e.senderFrame)) return null; if (renderInfo == null) { event.reply('export-error'); return; } var pageCount = renderInfo.pageCount, bounds = null; //For some reason, Electron 9 doesn't send this object as is without stringifying. Usually when variable is external to function own scope try { bounds = JSON.parse(renderInfo.bounds); } catch(e) { bounds = null; } var pdfOptions = {}; var hasError = false; if (bounds == null || bounds.width < 5 || bounds.height < 5) //very small page size never return from printToPDF { //A workaround to detect errors in the input file or being empty file hasError = true; } else { pdfOptions = { preferCSSPageSize: true, printBackground: true } } var base64encoded = args.base64 == '1'; if (hasError) { event.reply('export-error'); } else if (args.format == 'png' || args.format == 'jpg' || args.format == 'jpeg') { //Adds an extra pixel to prevent scrollbars from showing var newBounds = {width: Math.ceil(bounds.width + bounds.x) + 1, height: Math.ceil(bounds.height + bounds.y) + 1}; browser.setBounds(newBounds); //TODO The browser takes sometime to show the graph (also after resize it takes some time to render) // 1 sec is most probably enough (for small images, 5 for large ones) BUT not a stable solution setTimeout(function() { browser.capturePage().then(function(img) { //Image is double the given bounds, so resize is needed! var tScale = 1; //If user defined width and/or height, enforce it precisely here. Height override width if (args.h) { tScale = args.h / newBounds.height; } else if (args.w) { tScale = args.w / newBounds.width; } newBounds.width *= tScale; newBounds.height *= tScale; img = img.resize(newBounds); var data = args.format == 'png'? img.toPNG() : img.toJPEG(args.jpegQuality || 90); if (args.dpi != null && args.format == 'png') { data = writePngWithText(data, 'dpi', args.dpi); } if (args.embedXml == "1" && args.format == 'png') { data = writePngWithText(data, "mxGraphModel", args.xml, true, base64encoded); } else { if (base64encoded) { data = data.toString('base64'); } } event.reply('export-success', data); }); }, bounds.width * bounds.height < LARGE_IMAGE_AREA? 1000 : 5000); } else if (args.format == 'pdf') { if (args.print) { pdfOptions = { scaleFactor: args.pageScale, printBackground: true, pageSize : { width: args.pageWidth * MICRON_TO_PIXEL, //This height adjustment fixes the output. TODO Test more cases height: (args.pageHeight * 1.025) * MICRON_TO_PIXEL }, margins: { marginType: 'none' // no margin } }; contents.print(pdfOptions, (success, errorType) => { //Consider all as success event.reply('export-success', {}); // Notify the user with an error if it fails if (!success && errorType != 'Print job canceled') { dialog.showMessageBox(null, { type: 'error', title: 'Printing Error', message: 'There was an error printing. ' + errorType }); } }); } else { contents.printToPDF(pdfOptions).then(async (data) => { pdfs.push(data); to = to > pageCount? pageCount : to; from++; if (from < to) { args.from = from; args.to = from; ipcMain.once('render-finished', renderingFinishHandler); contents.send('render', args); } else { // TODO extract the correct xml if the source was a pnd file data = await mergePdfs(pdfs, args.embedXml == '1' ? args.xml : null); event.reply('export-success', data); } }) .catch((error) => { event.reply('export-error', error); }); } } else if (args.format == 'svg') { contents.send('get-svg-data'); ipcMain.once('svg-data', (e, data) => { if (!validateSender(e.senderFrame)) return null; event.reply('export-success', data); }); } else { event.reply('export-error', 'Error: Unsupported format'); } }; ipcMain.once('render-finished', renderingFinishHandler); if (args.format == 'xml') { ipcMain.once('xml-data', (e, data) => { if (!validateSender(e.senderFrame)) return null; event.reply('export-success', data); }); ipcMain.once('xml-data-error', (e) => { if (!validateSender(e.senderFrame)) return null; event.reply('export-error'); }); } args.border = args.border || 0; args.scale = args.scale || 1; if (args.filename != null && args.filename != '') { var filename = decodeURIComponent(args.filename); if (filename.substring(filename.length - 4) == '.pdf') { filename = filename.substring(0, filename.length - 4); } if (filename.substring(filename.length - 7) == '.drawio') { filename = filename.substring(0, filename.length - 7); } args.fileTitle = filename; } contents.send('render', args); }); } catch (e) { if (browser != null) { browser.destroy(); } event.reply('export-error', e); console.log('export-error', e); } }; ipcMain.on('export', exportDiagram); //================================================================ // Renderer Helper functions //================================================================ const { O_SYNC, O_CREAT, O_WRONLY, O_TRUNC, O_RDONLY } = fs.constants; const DRAFT_PREFEX = '.$'; const OLD_DRAFT_PREFEX = '~$'; const DRAFT_EXT = '.dtmp'; const BKP_PREFEX = '.$'; const OLD_BKP_PREFEX = '~$'; const BKP_EXT = '.bkp'; /** * Checks the file content type * Confirm content is xml, json, pdf, png, jpg, svg, vsdx ... */ function checkFileContent(body, enc) { if (body != null) { let head, headBinay; if (typeof body === 'string') { if (enc === 'base64') { headBinay = Buffer.from(body.substring(0, 22), 'base64'); head = headBinay.toString(); } else { head = body.substring(0, 16); headBinay = Buffer.from(head); } } else { head = new TextDecoder("utf-8").decode(body.subarray(0, 16)); headBinay = body; } let c1 = head[0], c2 = head[1], c3 = head[2], c4 = head[3], c5 = head[4], c6 = head[5], c7 = head[6], c8 = head[7], c9 = head[8], c10 = head[9], c11 = head[10], c12 = head[11], c13 = head[12], c14 = head[13], c15 = head[14], c16 = head[15]; let cc1 = headBinay[0], cc2 = headBinay[1], cc3 = headBinay[2], cc4 = headBinay[3], cc5 = headBinay[4], cc6 = headBinay[5], cc7 = headBinay[6], cc8 = headBinay[7], cc9 = headBinay[8], cc10 = headBinay[9], cc11 = headBinay[10], cc12 = headBinay[11], cc13 = headBinay[12], cc14 = headBinay[13], cc15 = headBinay[14], cc16 = headBinay[15]; if (c1 == '<') { // text/html if (c2 == '!' || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' || c3 == 'e' && c4 == 'a' && c5 == 'd') || (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) || ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' || c3 == 'E' && c4 == 'A' && c5 == 'D') || (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) { return true; } // application/xml if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') { return true; } // application/svg+xml if (c2 == 's' && c3 == 'v' && c4 == 'g' && c5 == ' ') { return true; } // Embed cases img and iframe if (c2 == 'i' && c3 == 'm' && c4 == 'g' && c5 == ' ' || (c2 == 'i' && c3 == 'f' && c4 == 'r' && c5 == 'a' && c6 == 'm' && c7 == 'e' && c8 == ' ')) { return true; } } // big and little (identical) endian UTF-8 encodings, with BOM // application/xml if (cc1 == 0xef && cc2 == 0xbb && cc3 == 0xbf) { if (c4 == '<' && c5 == '?' && c6 == 'x') { return true; } } // big and little endian UTF-16 encodings, with byte order mark // application/xml if (cc1 == 0xfe && cc2 == 0xff) { if (cc3 == 0 && c4 == '<' && cc5 == 0 && c6 == '?' && cc7 == 0 && c8 == 'x') { return true; } } // application/xml if (cc1 == 0xff && cc2 == 0xfe) { if (c3 == '<' && cc4 == 0 && c5 == '?' && cc6 == 0 && c7 == 'x' && cc8 == 0) { return true; } } // big and little endian UTF-32 encodings, with BOM // application/xml if (cc1 == 0x00 && cc2 == 0x00 && cc3 == 0xfe && cc4 == 0xff) { if (cc5 == 0 && cc6 == 0 && cc7 == 0 && c8 == '<' && cc9 == 0 && cc10 == 0 && cc11 == 0 && c12 == '?' && cc13 == 0 && cc14 == 0 && cc15 == 0 && c16 == 'x') { return true; } } // application/xml if (cc1 == 0xff && cc2 == 0xfe && cc3 == 0x00 && cc4 == 0x00) { if (c5 == '<' && cc6 == 0 && cc7 == 0 && cc8 == 0 && c9 == '?' && cc10 == 0 && cc11 == 0 && cc12 == 0 && c13 == 'x' && cc14 == 0 && cc15 == 0 && cc16 == 0) { return true; } } // application/pdf (%PDF-) if (cc1 == 37 && cc2 == 80 && cc3 == 68 && cc4 == 70 && cc5 == 45) { return true; } // image/png if ((cc1 == 137 && cc2 == 80 && cc3 == 78 && cc4 == 71 && cc5 == 13 && cc6 == 10 && cc7 == 26 && cc8 == 10) || (cc1 == 194 && cc2 == 137 && cc3 == 80 && cc4 == 78 && cc5 == 71 && cc6 == 13 //Our embedded PNG+XML && cc7 == 10 && cc8 == 26 && cc9 == 10)) { return true; } // image/jpeg if (cc1 == 0xFF && cc2 == 0xD8 && cc3 == 0xFF) { if (cc4 == 0xE0 || cc4 == 0xEE) { return true; } /** * File format used by digital cameras to store images. * Exif Format can be read by any application supporting * JPEG. Exif Spec can be found at: * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF */ if ((cc4 == 0xE1) && (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 == 'f' && cc11 == 0)) { return true; } } // image/webp if (cc1 == 0x52 && cc2 == 0x49 && cc3 == 0x46 && cc4 == 0x46) //RIFF { if (cc9 == 0x57 && cc10 == 0x45 && cc11 == 0x42 && cc12 == 0x50) //WEBP { return true; } } // vsdx, vssx (also zip, jar, odt, ods, odp, docx, xlsx, pptx, apk, aar) if (cc1 == 0x50 && cc2 == 0x4B && cc3 == 0x03 && cc4 == 0x04) { return true; } else if (cc1 == 0x50 && cc2 == 0x4B && cc3 == 0x03 && cc4 == 0x06) { return true; } // json if (c1 == '{' || c1 == '[') { return true; } // mxfile, mxlibrary, mxGraphModel if (c1 == '<' && c2 == 'm' && c3 == 'x') { return true; } } return false; }; function isConflict(origStat, stat) { return stat != null && origStat != null && stat.mtimeMs != origStat.mtimeMs; }; function getDraftFileName(fileObject) { let filePath = fileObject.path; let draftFileName = '', counter = 1, uniquePart = ''; do { draftFileName = path.join(path.dirname(filePath), DRAFT_PREFEX + path.basename(filePath) + uniquePart + DRAFT_EXT); uniquePart = '_' + counter++; } while (fs.existsSync(draftFileName)); return draftFileName; }; async function getFileDrafts(fileObject) { let filePath = fileObject.path; let draftsPaths = [], drafts = [], draftFileName, counter = 1, uniquePart = ''; do { draftsPaths.push(draftFileName); draftFileName = path.join(path.dirname(filePath), DRAFT_PREFEX + path.basename(filePath) + uniquePart + DRAFT_EXT); uniquePart = '_' + counter++; } while (fs.existsSync(draftFileName)); //TODO this assume continuous drafts names //Port old draft files to new prefex counter = 1; uniquePart = ''; let draftExists = false; do { draftFileName = path.join(path.dirname(filePath), OLD_DRAFT_PREFEX + path.basename(filePath) + uniquePart + DRAFT_EXT); draftExists = fs.existsSync(draftFileName); if (draftExists) { const newDraftFileName = path.join(path.dirname(filePath), DRAFT_PREFEX + path.basename(filePath) + uniquePart + DRAFT_EXT); await fsProm.rename(draftFileName, newDraftFileName); draftsPaths.push(newDraftFileName); } uniquePart = '_' + counter++; } while (draftExists); //TODO this assume continuous drafts names //Skip the first null element for (let i = 1; i < draftsPaths.length; i++) { try { let stat = await fsProm.lstat(draftsPaths[i]); drafts.push({data: await fsProm.readFile(draftsPaths[i], 'utf8'), created: stat.ctimeMs, modified: stat.mtimeMs, path: draftsPaths[i]}); } catch (e){} // Ignore } return drafts; }; async function saveDraft(fileObject, data) { var draftFileName = fileObject.draftFileName || getDraftFileName(fileObject); if (!checkFileContent(data) || path.resolve(draftFileName).startsWith(appBaseDir)) { throw new Error('Invalid file data'); } else { let draftFh; try { draftFh = await fsProm.open(draftFileName, O_SYNC | O_CREAT | O_WRONLY | O_TRUNC); await fsProm.writeFile(draftFh, data, 'utf8'); await draftFh.sync(); // Flush to disk } finally { await draftFh?.close(); } if (isWin) { try { // Add Hidden attribute: var child = spawn('attrib', ['+h', draftFileName]); child.on('error', function(err) { console.log('hiding draft file error: ' + err); }); } catch(e) {} } return draftFileName; } } async function saveFile(fileObject, data, origStat, overwrite, defEnc) { if (!checkFileContent(data) || path.resolve(fileObject.path).startsWith(appBaseDir)) { throw new Error('Invalid file data'); } var retryCount = 0; var backupCreated = false; var bkpPath = path.join(path.dirname(fileObject.path), BKP_PREFEX + path.basename(fileObject.path) + BKP_EXT); const oldBkpPath = path.join(path.dirname(fileObject.path), OLD_BKP_PREFEX + path.basename(fileObject.path) + BKP_EXT); var writeEnc = defEnc || fileObject.encoding; var writeFile = async function() { let fh; try { // O_SYNC is for sync I/O and reduce risk of file corruption fh = await fsProm.open(fileObject.path, O_SYNC | O_CREAT | O_WRONLY | O_TRUNC); await fsProm.writeFile(fh, data, writeEnc); await fh.sync(); // Flush to disk } finally { await fh?.close(); } let stat2 = await fsProm.stat(fileObject.path); // Workaround for possible writing errors is to check the written // contents of the file and retry 3 times before showing an error let writtenData = await fsProm.readFile(fileObject.path, writeEnc); if (data != writtenData) { retryCount++; if (retryCount < 3) { return await writeFile(); } else { throw new Error('all saving trials failed'); } } else { //We'll keep the backup file in case the original file is corrupted. TODO When should we delete the backup file? if (backupCreated) { //fs.unlink(bkpPath, (err) => {}); //Ignore errors! //Delete old backup file with old prefix if (fs.existsSync(oldBkpPath)) { fs.unlink(oldBkpPath, (err) => {}); //Ignore errors } } return stat2; } }; async function doSaveFile(isNew) { if (enableStoreBkp && !isNew) { //Copy file to backup file (after conflict and stat is checked) let bkpFh; try { //Use file read then write to open the backup file direct sync write to reduce the chance of file corruption let fileContent = await fsProm.readFile(fileObject.path, writeEnc); bkpFh = await fsProm.open(bkpPath, O_SYNC | O_CREAT | O_WRONLY | O_TRUNC); await fsProm.writeFile(bkpFh, fileContent, writeEnc); await bkpFh.sync(); // Flush to disk backupCreated = true; } catch (e) { if (__DEV__) { console.log('Backup file writing failed', e); //Ignore } } finally { await bkpFh?.close(); if (isWin) { try { // Add Hidden attribute: var child = spawn('attrib', ['+h', bkpPath]); child.on('error', function(err) { console.log('hiding backup file error: ' + err); }); } catch(e) {} } } } return await writeFile(); }; if (overwrite) { return await doSaveFile(true); } else { let stat = fs.existsSync(fileObject.path)? await fsProm.stat(fileObject.path) : null; if (stat && isConflict(origStat, stat)) { throw new Error('conflict'); } else { return await doSaveFile(stat == null); } } }; async function writeFile(filePath, data, enc) { if (!checkFileContent(data, enc) || path.resolve(filePath).startsWith(appBaseDir)) { throw new Error('Invalid file data'); } else { let fh; try { // O_SYNC is for sync I/O and reduce risk of file corruption fh = await fsProm.open(filePath, O_SYNC | O_CREAT | O_WRONLY | O_TRUNC); await fsProm.writeFile(fh, data, enc); await fh.sync(); // Flush to disk } finally { await fh?.close(); } } }; function getAppDataFolder() { try { var appDataDir = app.getPath('appData'); var drawioDir = appDataDir + '/draw.io'; if (!fs.existsSync(drawioDir)) //Usually this dir already exists { fs.mkdirSync(drawioDir); } return drawioDir; } catch(e) {} return '.'; }; function getDocumentsFolder() { //On windows, misconfigured Documents folder cause an exception try { return app.getPath('documents'); } catch(e) {} return '.'; }; function checkFileExists(pathParts) { let filePath = path.join(...pathParts); return {exists: fs.existsSync(filePath), path: filePath}; }; async function showOpenDialog(defaultPath, filters, properties) { let win = BrowserWindow.getFocusedWindow(); return dialog.showOpenDialog(win, { defaultPath: defaultPath, filters: filters, properties: properties }); }; async function showSaveDialog(defaultPath, filters) { let win = BrowserWindow.getFocusedWindow(); return dialog.showSaveDialog(win, { defaultPath: defaultPath, filters: filters }); }; async function installPlugin(filePath) { if (!enablePlugins) return {}; var pluginsDir = path.join(getAppDataFolder(), '/plugins'); if (!fs.existsSync(pluginsDir)) { fs.mkdirSync(pluginsDir); } var pluginName = path.basename(filePath); var dstFile = path.join(pluginsDir, pluginName); if (fs.existsSync(dstFile)) { throw new Error('fileExists'); } else { await fsProm.copyFile(filePath, dstFile); } return {pluginName: pluginName, selDir: path.dirname(filePath)}; } function getPluginFile(plugin) { if (!enablePlugins) return null; const prefix = path.join(getAppDataFolder(), '/plugins/'); const pluginFile = path.join(prefix, plugin); if (pluginFile.startsWith(prefix) && fs.existsSync(pluginFile)) { return pluginFile; } return null; } function uninstallPlugin(plugin) { const pluginFile = getPluginFile(plugin); if (pluginFile != null) { fs.unlinkSync(pluginFile); } } function dirname(path_p) { return path.dirname(path_p); } async function readFile(filename, encoding) { let data = await fsProm.readFile(filename, encoding); if (checkFileContent(data, encoding) && !path.resolve(filename).startsWith(appBaseDir)) { return data; } throw new Error('Invalid file data'); } async function fileStat(file) { return await fsProm.stat(file); } async function isFileWritable(file) { try { await fsProm.access(file, fs.constants.W_OK); return true; } catch (e) { return false; } } function clipboardAction(method, data) { if (method == 'writeText') { clipboard.writeText(data); } else if (method == 'readText') { return clipboard.readText(); } else if (method == 'writeImage') { clipboard.write({image: nativeImage.createFromDataURL(data.dataUrl), html: ''}); } } async function deleteFile(file) { // Reading the header of the file to confirm it is a file we can delete let fh = await fsProm.open(file, O_RDONLY); let buffer = Buffer.allocUnsafe(16); await fh.read(buffer, 0, 16); await fh.close(); if (checkFileContent(buffer) && !path.resolve(file).startsWith(appBaseDir)) { await fsProm.unlink(file); } } function windowAction(method) { let win = BrowserWindow.getFocusedWindow(); if (win) { if (method == 'minimize') { win.minimize(); } else if (method == 'maximize') { win.maximize(); } else if (method == 'unmaximize') { win.unmaximize(); } else if (method == 'close') { win.close(); } else if (method == 'isMaximized') { return win.isMaximized(); } else if (method == 'removeAllListeners') { win.removeAllListeners(); } } } const allowedUrls = /^(?:https?|mailto|tel|callto):/i; function openExternal(url) { //Only open http(s), mailto, tel, and callto links if (allowedUrls.test(url)) { shell.openExternal(url); return true; } return false; } function watchFile(filePath) { let win = BrowserWindow.getFocusedWindow(); if (win) { fs.watchFile(filePath, (curr, prev) => { try { win.webContents.send('fileChanged', { path: filePath, curr: curr, prev: prev }); } catch (e) {} // Ignore }); } } function unwatchFile(filePath) { fs.unwatchFile(filePath); } ipcMain.on("rendererReq", async (event, args) => { if (!validateSender(event.senderFrame)) return null; try { let ret = null; switch(args.action) { case 'saveFile': ret = await saveFile(args.fileObject, args.data, args.origStat, args.overwrite, args.defEnc); break; case 'writeFile': ret = await writeFile(args.path, args.data, args.enc); break; case 'saveDraft': ret = await saveDraft(args.fileObject, args.data); break; case 'getFileDrafts': ret = await getFileDrafts(args.fileObject); break; case 'getDocumentsFolder': ret = await getDocumentsFolder(); break; case 'checkFileExists': ret = await checkFileExists(args.pathParts); break; case 'showOpenDialog': dialogOpen = true; ret = await showOpenDialog(args.defaultPath, args.filters, args.properties); ret = ret.filePaths; dialogOpen = false; break; case 'showSaveDialog': dialogOpen = true; ret = await showSaveDialog(args.defaultPath, args.filters); ret = ret.canceled? null : ret.filePath; dialogOpen = false; break; case 'installPlugin': ret = await installPlugin(args.filePath); break; case 'uninstallPlugin': ret = await uninstallPlugin(args.plugin); break; case 'getPluginFile': ret = await getPluginFile(args.plugin); break; case 'isPluginsEnabled': ret = enablePlugins; break; case 'dirname': ret = await dirname(args.path); break; case 'readFile': ret = await readFile(args.filename, args.encoding); break; case 'clipboardAction': ret = await clipboardAction(args.method, args.data); break; case 'deleteFile': ret = await deleteFile(args.file); break; case 'fileStat': ret = await fileStat(args.file); break; case 'isFileWritable': ret = await isFileWritable(args.file); break; case 'windowAction': ret = await windowAction(args.method); break; case 'openExternal': ret = await openExternal(args.url); break; case 'watchFile': ret = await watchFile(args.path); break; case 'unwatchFile': ret = await unwatchFile(args.path); break; case 'exit': app.quit(); break; case 'isFullscreen': ret = BrowserWindow.getFocusedWindow().isFullScreen(); break; }; event.reply('mainResp', {success: true, data: ret, reqId: args.reqId}); } catch (e) { event.reply('mainResp', {error: true, msg: e.message, e: e, reqId: args.reqId}); } }); ================================================ FILE: sync.cjs ================================================ const fs = require('fs') const path = require('path') const appjsonpath = path.join(__dirname, 'package.json') const disableUpdatePath = path.join(__dirname, 'src/main', 'disableUpdate.js') const versionPath = path.join(__dirname, 'drawio', 'VERSION') if (!fs.existsSync(versionPath)) { console.error('Error: drawio/VERSION not found. Did you clone with --recursive or run git submodule update --init?') process.exit(1) } let ver = fs.readFileSync(versionPath, 'utf8').trim() //let ver = '14.1.5' // just to test autoupdate if (!/^\d+\.\d+\.\d+$/.test(ver)) { console.error('Error: drawio/VERSION contains invalid version: "' + ver + '"') process.exit(1) } let pj = require(appjsonpath) pj.version = ver fs.writeFileSync(appjsonpath, JSON.stringify(pj, null, 2), 'utf8') //Enable/disable updates fs.writeFileSync(disableUpdatePath, 'export function disableUpdate() { return ' + (process.argv[2] == 'disableUpdate'? 'true' : 'false') + ';}', 'utf8');