From ad2feb4bcf44e6a78321000298e480a37acfa9c2 Mon Sep 17 00:00:00 2001 From: IZUMI-Zu <274620705z@gmail.com> Date: Sun, 20 Oct 2024 23:28:24 +0800 Subject: [PATCH] feat: add initial docs (#2) * feat: init doc page * feat: move to yarn --- .github/workflows/docs-links-check-pr.yml | 33 + .github/workflows/docs-links-check.yml | 23 + .../workflows/docs.links.check.config.json | 43 + .github/workflows/markdownlint.yml | 26 + .github/workflows/master.yml | 47 + .github/workflows/pr_ci.yml | 26 + .gitignore | 2 + .husky/pre-commit | 1 + .stylelintignore | 3 + .stylelintrc.json | 8 + README.md | 41 +- babel.config.js | 3 + blog/2024-10-18.mdx | 51 + docs/basic/getting-started.md | 35 + docs/basic/usage.md | 45 + docs/build/configuration.md | 43 + docs/build/process.md | 85 + docs/configuration/connect-casdoor-server.md | 59 + .../import-from-other-authenticators.md | 49 + docs/overview.md | 54 + docusaurus.config.js | 184 + eslint.config.mjs | 169 + netlify.toml | 5 + package.json | 70 + sidebars.js | 47 + src/components/AdditionalFeatures/index.js | 91 + .../AdditionalFeatures/styles.module.css | 46 + src/components/DownloadSection/index.js | 31 + .../DownloadSection/styles.module.css | 64 + src/components/HomepageFeatures/index.js | 78 + .../HomepageFeatures/styles.module.css | 11 + src/components/NavbarItems/Casdoor.js | 50 + src/components/NavbarItems/Community.js | 84 + src/components/Screenshots/index.js | 42 + src/components/Screenshots/styles.module.css | 17 + src/components/TOTPIntro/index.js | 30 + src/components/TOTPIntro/styles.module.css | 22 + src/css/custom.css | 321 + src/pages/help.js | 53 + src/pages/index.js | 62 + src/pages/index.module.css | 56 + src/theme/NavbarItem/ComponentTypes.js | 10 + static/fonts/FiraCode-VF.woff | Bin 0 -> 138576 bytes static/fonts/FiraCode-VF.woff2 | Bin 0 -> 113088 bytes static/fonts/Inter-italic.var.woff2 | Bin 0 -> 245036 bytes static/fonts/Inter-roman.var.woff2 | Bin 0 -> 227180 bytes static/img/casbin.svg | 10 + static/img/casdoor.png | Bin 0 -> 38624 bytes .../connect-casdoor-server/manual-config.png | Bin 0 -> 21312 bytes .../mfa-account-setting.png | Bin 0 -> 84332 bytes .../connect-casdoor-server/qr-code-scan.png | Bin 0 -> 14120 bytes .../google-export.png | Bin 0 -> 117098 bytes .../import-google-totp.gif | Bin 0 -> 2691102 bytes .../import-totp.gif | Bin 0 -> 918476 bytes static/img/favicon.png | Bin 0 -> 10731 bytes static/img/home/Android.jpg | Bin 0 -> 347510 bytes static/img/home/connection.svg | 1 + static/img/home/devices.svg | 1 + static/img/home/iOS.png | Bin 0 -> 230124 bytes static/img/home/security.svg | 1 + static/img/home/totp.svg | 1 + webpack.config.js | 9 + yarn.lock | 9396 +++++++++++++++++ 63 files changed, 11638 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/docs-links-check-pr.yml create mode 100644 .github/workflows/docs-links-check.yml create mode 100644 .github/workflows/docs.links.check.config.json create mode 100644 .github/workflows/markdownlint.yml create mode 100644 .github/workflows/master.yml create mode 100644 .github/workflows/pr_ci.yml create mode 100755 .husky/pre-commit create mode 100644 .stylelintignore create mode 100644 .stylelintrc.json create mode 100644 babel.config.js create mode 100644 blog/2024-10-18.mdx create mode 100644 docs/basic/getting-started.md create mode 100644 docs/basic/usage.md create mode 100644 docs/build/configuration.md create mode 100644 docs/build/process.md create mode 100644 docs/configuration/connect-casdoor-server.md create mode 100644 docs/configuration/import-from-other-authenticators.md create mode 100644 docs/overview.md create mode 100644 docusaurus.config.js create mode 100644 eslint.config.mjs create mode 100644 netlify.toml create mode 100644 package.json create mode 100644 sidebars.js create mode 100644 src/components/AdditionalFeatures/index.js create mode 100644 src/components/AdditionalFeatures/styles.module.css create mode 100644 src/components/DownloadSection/index.js create mode 100644 src/components/DownloadSection/styles.module.css create mode 100644 src/components/HomepageFeatures/index.js create mode 100644 src/components/HomepageFeatures/styles.module.css create mode 100644 src/components/NavbarItems/Casdoor.js create mode 100644 src/components/NavbarItems/Community.js create mode 100644 src/components/Screenshots/index.js create mode 100644 src/components/Screenshots/styles.module.css create mode 100644 src/components/TOTPIntro/index.js create mode 100644 src/components/TOTPIntro/styles.module.css create mode 100644 src/css/custom.css create mode 100644 src/pages/help.js create mode 100644 src/pages/index.js create mode 100644 src/pages/index.module.css create mode 100644 src/theme/NavbarItem/ComponentTypes.js create mode 100644 static/fonts/FiraCode-VF.woff create mode 100644 static/fonts/FiraCode-VF.woff2 create mode 100644 static/fonts/Inter-italic.var.woff2 create mode 100644 static/fonts/Inter-roman.var.woff2 create mode 100644 static/img/casbin.svg create mode 100644 static/img/casdoor.png create mode 100644 static/img/configuration/connect-casdoor-server/manual-config.png create mode 100644 static/img/configuration/connect-casdoor-server/mfa-account-setting.png create mode 100644 static/img/configuration/connect-casdoor-server/qr-code-scan.png create mode 100644 static/img/configuration/import-from-other-authenticators/google-export.png create mode 100644 static/img/configuration/import-from-other-authenticators/import-google-totp.gif create mode 100644 static/img/configuration/import-from-other-authenticators/import-totp.gif create mode 100644 static/img/favicon.png create mode 100644 static/img/home/Android.jpg create mode 100644 static/img/home/connection.svg create mode 100644 static/img/home/devices.svg create mode 100644 static/img/home/iOS.png create mode 100644 static/img/home/security.svg create mode 100644 static/img/home/totp.svg create mode 100644 webpack.config.js create mode 100644 yarn.lock diff --git a/.github/workflows/docs-links-check-pr.yml b/.github/workflows/docs-links-check-pr.yml new file mode 100644 index 0000000..ae97d77 --- /dev/null +++ b/.github/workflows/docs-links-check-pr.yml @@ -0,0 +1,33 @@ +name: Check links for modified docs + +on: + pull_request: + paths: + - 'docs/**' + +jobs: + docs-links-check: + runs-on: ubuntu-latest + steps: + - name: Checkout 🛎️ + uses: actions/checkout@master + + - name: Check links for mdx files 🔎 + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-quiet-mode: 'yes' # only show errors in output. + # use-verbose-mode: 'yes' # show detailed HTTP status for checked links. + # refer to https://github.com/tcort/markdown-link-check#config-file-format + config-file: '.github/workflows/docs.links.check.config.json' + check-modified-files-only: 'yes' + file-extension: '.mdx' + + - name: Check links for markdown files 🔎 + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-quiet-mode: 'yes' # only show errors in output. + # use-verbose-mode: 'yes' # show detailed HTTP status for checked links. + # refer to https://github.com/tcort/markdown-link-check#config-file-format + config-file: '.github/workflows/docs.links.check.config.json' + check-modified-files-only: 'yes' + file-extension: '.md' diff --git a/.github/workflows/docs-links-check.yml b/.github/workflows/docs-links-check.yml new file mode 100644 index 0000000..8c22b25 --- /dev/null +++ b/.github/workflows/docs-links-check.yml @@ -0,0 +1,23 @@ +name: Docs Links Check + +on: + workflow_dispatch: + schedule: + - cron: "0 12 * * 6" # runs every saturday at 12:00 UTC + +jobs: + docs-links-check: + runs-on: ubuntu-latest + steps: + - name: Checkout 🛎️ + uses: actions/checkout@master + + - name: Check Links 🔎 + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-quiet-mode: 'yes' # only show errors in output. + # use-verbose-mode: 'yes' # show detailed HTTP status for checked links. + folder-path: 'docs/' # only check the docs/ folder + # refer to https://github.com/tcort/markdown-link-check#config-file-format + config-file: '.github/workflows/docs.links.check.config.json' + file-extension: '.md*' # .md or .mdx diff --git a/.github/workflows/docs.links.check.config.json b/.github/workflows/docs.links.check.config.json new file mode 100644 index 0000000..b5654f2 --- /dev/null +++ b/.github/workflows/docs.links.check.config.json @@ -0,0 +1,43 @@ +{ + "ignorePatterns": [ + { + "pattern": "^(?!https?:\/\/)" + }, + { + "pattern": "^http://localhost" + }, + { + "pattern": "^https?://your-casdoor-url.com" + }, + { + "pattern": "^https?://[a-z]*.?your-site-url.com" + }, + { + "pattern": "^https://flarum.org/" + }, + { + "pattern": "^https://dash.cloudflare.com/" + }, + { + "pattern": "^https://developer.android.com/guide/topics/manifest/manifest-element#package" + }, + { + "pattern": "^https://developer.twitter.com/en/portal/dashboard" + }, + { + "pattern": "^https://www.epis2048.net/2022/modify-cloudreve-to-support-casdoor/index.html" + }, + { + "pattern": "^https://www.epis2048.net/2022/modify-kodexplorer-to-support-casdoor/index.html" + }, + { + "pattern": "^https://help.brevo.com/hc/en-us/articles/7924908994450" + }, + { + "pattern": "^https://opendocs.alipay.com\\S+" + }, + { + "pattern": "^https://www.bytebase.com/docs" + } + ] +} \ No newline at end of file diff --git a/.github/workflows/markdownlint.yml b/.github/workflows/markdownlint.yml new file mode 100644 index 0000000..360e31e --- /dev/null +++ b/.github/workflows/markdownlint.yml @@ -0,0 +1,26 @@ +name: Markdown Lint + +on: + workflow_dispatch: + pull_request: + paths: + - 'docs/**' + +jobs: + markdownlint: + name: Markdown Lint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: '18.x' + + - name: Install markdownlint + run: npm install -g markdownlint-cli@0.35.0 + + - name: Run markdownlint + run: markdownlint 'docs/**/*.{md,mdx}' --config .markdownlint.jsonc diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml new file mode 100644 index 0000000..0a2c575 --- /dev/null +++ b/.github/workflows/master.yml @@ -0,0 +1,47 @@ +name: Build and Deploy +on: + push: + branches: + - master +jobs: + build-and-deploy: + # env: + # CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} + runs-on: ubuntu-latest + steps: + - name: Free Disk Space + uses: jlumbroso/free-disk-space@main + with: + tool-cache: true + android: true + dotnet: true + haskell: true + large-packages: true + swap-storage: true + + - name: Checkout 🛎️ + uses: actions/checkout@v3 + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ~/.cache/yarn + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install and Build 🔧 + run: | + yarn install + # yarn crowdin:sync + yarn build + + - name: Deploy 🚀 + uses: JamesIves/github-pages-deploy-action@v4 + with: + ssh-key: ${{ secrets.DEPLOY_KEY }} + git-config-name: ${{ secrets.GH_NAME }} + git-config-email: ${{ secrets.GH_EMAIL }} + repository-name: casdoor/casdoorapp.github.io + branch: master # The deploy branch. + folder: build # The deploy folder. diff --git a/.github/workflows/pr_ci.yml b/.github/workflows/pr_ci.yml new file mode 100644 index 0000000..772a008 --- /dev/null +++ b/.github/workflows/pr_ci.yml @@ -0,0 +1,26 @@ +name: Node.js CI + +on: + pull_request + +jobs: + deploy: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [ 18.x ] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: yarn install + + - name: Build website + run: yarn build --locale en diff --git a/.gitignore b/.gitignore index c6bba59..96e545b 100644 --- a/.gitignore +++ b/.gitignore @@ -128,3 +128,5 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* + +build diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..3723623 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +yarn lint-staged diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000..d6fb34a --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,3 @@ +node_modules +build +.docusaurus \ No newline at end of file diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 0000000..6e8c774 --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,8 @@ +{ + "extends": [ + "stylelint-config-standard" + ], + "rules": { + "selector-class-pattern": null + } +} \ No newline at end of file diff --git a/README.md b/README.md index 9376fbd..94557b0 100644 --- a/README.md +++ b/README.md @@ -1 +1,40 @@ -# casdoorapp-website \ No newline at end of file +# Casdoor Authenticator App Documentation + +This repository contains the documentation website for the Casdoor Authenticator App. The website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. + +## Getting Started + +### Prerequisites + +- [Node.js](https://nodejs.org/en/download/) version 18 or above +- [Yarn](https://classic.yarnpkg.com/en/docs/install): please use Yarn 1 + +### Installation + +```bash +$ yarn install +``` + +### Local Development + +```bash +$ yarn start +``` + +This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. + +### Build + +```bash +$ yarn build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. + +## Contributing + +We welcome contributions to improve the documentation for the Casdoor Authenticator App. Please feel free to submit issues or pull requests. + +## License + +This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details. diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..bfd75db --- /dev/null +++ b/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve("@docusaurus/core/lib/babel/preset")], +}; diff --git a/blog/2024-10-18.mdx b/blog/2024-10-18.mdx new file mode 100644 index 0000000..26fac9c --- /dev/null +++ b/blog/2024-10-18.mdx @@ -0,0 +1,51 @@ +--- +slug: welcome +title: Welcome +author: IZUMI-Zu +authorTitle: Casdoor App Contributor +authorURL: https://github.com/IZUMI-Zu +authorImageURL: https://avatars.githubusercontent.com/u/23271676?s=100 +tags: [Casdoor, Authenticator, Totp] +--- + +Welcome to the official website of the Casdoor Authenticator App! 👋 + +## What is Casdoor Authenticator App? + +The Casdoor Authenticator App is a mobile application designed to enhance the security of your online accounts by providing Time-based One-Time Passwords (TOTP) for multi-factor authentication. It's an integral part of the Casdoor ecosystem, which is a comprehensive Identity Access Management (IAM) and Single-Sign-On (SSO) platform. + +## Key Features + +1. **TOTP Support**: Generates secure, time-based one-time passwords that change every 30 seconds. +2. **Cross-Platform**: Available for both Android and iOS devices. +3. **Seamless Integration**: Works perfectly with the Casdoor platform and other TOTP-compatible services. +4. **Offline Functionality**: Provides TOTP codes without requiring an internet connection. +5. **Secure Backup**: Supports syncing TOTP data to the Casdoor server for secure backups. +6. **User-Friendly Interface**: Offers a simple and intuitive mobile app interface for managing 2FA. + +## Why use Casdoor Authenticator App? + +* 🔐 **Enhanced Security**: Protect your accounts with an additional layer of security using time-based one-time passwords. +* 🌐 **Versatility**: Compatible with any service that supports TOTP-based two-factor authentication. +* 💼 **Business Integration**: Seamlessly integrates with Casdoor's IAM platform for enterprise-level security. +* 🔄 **Easy Migration**: Supports importing TOTP data from other authenticator apps like Google Authenticator. + +## Getting Started + +To begin using the Casdoor Authenticator App: + +1. Download the app from the official sources. +2. Set up your Casdoor account (if using server-side storage). +3. Start adding and managing your TOTP codes for various accounts. + +For detailed instructions on setup, usage, and migration from other authenticator apps, please refer to our [comprehensive documentation](/docs/basic/getting-started). + +## Join Our Community + +We welcome contributions and feedback from our users. Join our community to stay updated on the latest developments, share your experiences, and contribute to making Casdoor Authenticator even better! + +* [GitHub Repository](https://github.com/casdoor/casdoor-app) +* [Discord Channel](https://discord.gg/5rPsrAzK7S) +* [QQ Group](https://cdn.casdoor.com/casdoor/resource/built-in/admin/qq_casdoor.png) + +Thank you for choosing Casdoor Authenticator App. Let's make online authentication more secure together! diff --git a/docs/basic/getting-started.md b/docs/basic/getting-started.md new file mode 100644 index 0000000..8dd0176 --- /dev/null +++ b/docs/basic/getting-started.md @@ -0,0 +1,35 @@ +--- +title: Getting Started +description: Casdoor App Getting Started +keywords: [casdoor, authenticator] +authors: [IZUMI-Zu] +--- + +## Introduction + +The Casdoor Authenticator App is a mobile application designed to enhance the security of your online accounts by providing Time-based One-Time Passwords (TOTP) for multi-factor authentication. This guide will help you get started with the app quickly and easily. + +## Prerequisites + +Before you begin, ensure you have the following prerequisites: + +- A Casdoor server (optional) +- A compatible mobile device (iOS or Android) + +## Installation + +1. For iOS users: + - Currently, the app is not available on the App Store. + - You can build the app from source code. See [here](../build/configuration.md) for more details. + +2. For Android users: + - You can download the app from the [GitHub Releases page](https://github.com/casdoor/casdoor-app/releases). + - Install the APK file on your device. + +## Initial Setup + +1. Open the Casdoor Authenticator App after installation +2. If you have a Casdoor account and want to use server-side synchronization: + - Tap "Log in with Casdoor" + - Enter your Casdoor credentials +3. Use the app to scan the QR code to add your Multi-factor authentication. diff --git a/docs/basic/usage.md b/docs/basic/usage.md new file mode 100644 index 0000000..e9a4c16 --- /dev/null +++ b/docs/basic/usage.md @@ -0,0 +1,45 @@ +--- +title: Basic Usage +description: Casdoor App Basic Usage +keywords: [casdoor, authenticator] +authors: [IZUMI-Zu] +--- + +## Using the Casdoor Authenticator App + +The Casdoor Authenticator App provides a secure and convenient way to manage your two-factor authentication (2FA) needs. Here's how to use the app effectively: + +### Adding an Account + +1. Open the Casdoor Authenticator App on your mobile device. +2. Tap the "+" button to add a new account. +3. Choose one of the following methods to add an account: + - Scan QR Code: Use your device's camera to scan the QR code provided by the service you're setting up 2FA for. + - Manual Entry: If a QR code is not available, you can manually enter the account details and secret key. + +### Generating TOTP Codes + +1. Open the Casdoor Authenticator App. +2. Locate the account you need a code for in the list. +3. The current TOTP code will be displayed next to the account name. +4. Use this code when prompted during the login process on the service you're accessing. + +### Managing Accounts + +- To edit an account, tap on the account and select the edit option. +- To remove an account, swipe left on the account and tap the delete button. + +### Syncing with Casdoor Server + +If you've enabled server-side synchronization: + +1. Ensure you're logged in to your Casdoor account within the app. +2. Your accounts will automatically sync with the Casdoor server. +3. To manually trigger a sync, pull down on the account list to refresh. + +### Security Tips + +- Regularly back up your accounts to prevent loss of access. +- When adding accounts manually, double-check the secret key to ensure accuracy. + +By following these steps, you can effectively use the Casdoor Authenticator App to secure your online accounts with two-factor authentication. diff --git a/docs/build/configuration.md b/docs/build/configuration.md new file mode 100644 index 0000000..a496f4c --- /dev/null +++ b/docs/build/configuration.md @@ -0,0 +1,43 @@ +--- +title: Build Configuration +description: Casdoor App Build Configuration +keywords: [casdoor, authenticator, configuration, build, android, ios] +authors: [IZUMI-Zu] +--- + +## Build Configuration for Casdoor Authenticator App + +This guide provides instructions on how to configure and build the Casdoor Authenticator App for both Android and iOS platforms. + +### Prerequisites + +Before you begin, ensure you have the following installed: + +- [Node.js](https://nodejs.org/) +- [npm](https://www.npmjs.com/) +- [Xcode](https://developer.apple.com/xcode/) (for iOS development, macOS only) +- [Android Studio](https://developer.android.com/studio) (for Android development) + - Make sure to install the Android NDK (Native Development Kit) through the SDK Manager + +### General Configuration + +1. Clone the Casdoor Authenticator App repository: + + ```bash + git clone https://github.com/casdoor/casdoor-app.git + cd casdoor-app + ``` + +2. Install dependencies: + + ```bash + npm install + ``` + +### Troubleshooting + +- If you encounter any build errors, ensure all dependencies are up to date and compatible. +- For iOS, try cleaning the build folder in Xcode (Product > Clean Build Folder) if you face any issues. +- For Android, you can try cleaning the project with `./gradlew clean` in the `android` directory. + +By following these configuration steps, you should be able to successfully build the Casdoor Authenticator App for both Android and iOS platforms. diff --git a/docs/build/process.md b/docs/build/process.md new file mode 100644 index 0000000..571eb73 --- /dev/null +++ b/docs/build/process.md @@ -0,0 +1,85 @@ +--- +title: Build Process +description: Casdoor App Build Process +keywords: [casdoor, authenticator, build, process] +authors: [IZUMI-Zu] +--- + +## Introduction + +This document outlines the process for building the Casdoor Authenticator App from source code. Before starting, ensure you have completed the [configuration](/docs/build/configuration) step. + +## Prerequisites + +Before building the app, make sure you have the following installed: + +- Node.js (LTS version recommended) +- npm (comes with Node.js) +- For Android: Android Studio and Android SDK +- For iOS: Xcode (Mac only) + +## Building the App + +### For Development (React Native App) + +We use Expo to develop and test the React Native app: + +```bash +npm install +npx expo start --clear +``` + +This will start the Expo development server. You can then run the app on: + +- An iOS simulator (Mac only) +- An Android emulator +- Your physical device using the Expo Go app + +### For Android + +To build the Android App APK: + +```bash +npm install +npx expo prebuild --platform android +cd android && ./gradlew assembleRelease +``` + +The APK file will be in the `android/app/build/outputs/apk/release/` directory. + +For debugging the native Android App: + +```bash +npx expo prebuild --platform android +cd android && ./gradlew assembleDebug +``` + +Find the debug APK in the `android/app/build/outputs/apk/debug/` directory. + +To run the development version: + +1. Install the APK on your Android device +2. Start the JS server with: + + ```bash + npx expo start --android + ``` + +### For iOS + +To build the iOS app: + +```bash +npm install +npx expo prebuild --platform ios +npx expo run:ios --configuration Release +``` + +Note: iOS builds require a Mac with Xcode installed. + +## Troubleshooting + +- If you encounter "Command not found" errors, ensure that Node.js and npm are correctly installed and added to your system's PATH. +- For Android build issues, make sure your ANDROID_HOME environment variable is set correctly. + +For more detailed troubleshooting, refer to the [React Native documentation](https://reactnative.dev/docs/troubleshooting) and [Expo documentation](https://docs.expo.dev/guides/adopting-prebuild/#prebuild). diff --git a/docs/configuration/connect-casdoor-server.md b/docs/configuration/connect-casdoor-server.md new file mode 100644 index 0000000..ec288da --- /dev/null +++ b/docs/configuration/connect-casdoor-server.md @@ -0,0 +1,59 @@ +--- +title: Connect Casdoor Server +description: How to connect Casdoor Server to the Casdoor Authenticator App +keywords: [casdoor, authenticator, connect, server] +authors: [IZUMI-Zu] +--- + +## Introduction + +Casdoor is an open-source identity management platform that provides authentication, authorization, and user management services. It supports various protocols like OAuth, SAML, and OpenID Connect, making it a versatile choice for securing your applications. + +## Prerequisites + +Before proceeding, ensure you have the following: + +- A Casdoor server instance +- The Casdoor Authenticator App installed on your device +- The Casdoor server URL and credentials + +## Step 1: Enable Totp Account storage in Casdoor Server + +Before using the Casdoor Authenticator App, you need to make sure that the MFA accounts setting is enabled in the Casdoor server. + +![Server MFA Setting](/img/configuration/connect-casdoor-server/mfa-account-setting.png) + +## Step 2: Configuring the Casdoor Authenticator App + +1. Open the Casdoor Authenticator App on your device. +2. On the main screen, tap the "Login" button. +3. You will be presented with three options to connect to your Casdoor server: + + a. Manually enter server details: + - Tap "Enter Server Manually" + - Input the Casdoor server URL and other required information + - Log in with your Casdoor account + + ![Manual Configuration](/img/configuration/connect-casdoor-server/manual-config.png) + + b. Scan QR code: + - Tap "Scan QR Code" + - Use your device's camera to scan the QR code provided by your Casdoor server + - The QR code is located in the "My Account" -> "MFA accounts" table section of the Casdoor server + - The app will automatically connect to the server + + ![QR Code Scan](/img/configuration/connect-casdoor-server/qr-code-scan.png) + + c. Try demo server: + - Tap "Try Demo Server" to connect to a pre-configured demo instance + - This option is useful for testing the app's functionality without setting up your own server + +4. Now, you can view your TOTP codes and manage your 2FA settings directly from the Casdoor Authenticator App like other authenticator apps. + +## Troubleshooting + +If you encounter any issues while connecting: + +- Ensure your Casdoor server is running and accessible +- Double-check the server URL and your credentials +- Verify that your device has an active internet connection diff --git a/docs/configuration/import-from-other-authenticators.md b/docs/configuration/import-from-other-authenticators.md new file mode 100644 index 0000000..c30057b --- /dev/null +++ b/docs/configuration/import-from-other-authenticators.md @@ -0,0 +1,49 @@ +--- +title: Import from other authenticators +description: How to import your TOTP codes from other authenticators +keywords: [casdoor, authenticator, import, other, authenticators, Google Authenticator, Microsoft Authenticator] +authors: [IZUMI-Zu] +--- + +## Introduction + +The Casdoor Authenticator App supports importing TOTP codes from other authenticators such as Google Authenticator and Microsoft Authenticator. This feature allows you to seamlessly transfer your existing 2FA settings to the Casdoor Authenticator App, ensuring a smooth transition and continued security. + +## Migration from Google Authenticator + +If you are currently using Google Authenticator for your TOTP codes, you can easily migrate your TOTP data to the Casdoor Authenticator App. To do this, follow these steps: + +### Step 1: Export TOTP data from Google Authenticator + +Select the "Transfer Accounts" option in the menu of Google Authenticator and choose the accounts you want to transfer. Then, click the "Export" button to generate a QR code. + +![Google Authenticator Export](/img/configuration/import-from-other-authenticators/google-export.png) + +### Step 2: Import TOTP data to the Casdoor Authenticator App + +In the Casdoor Authenticator App, scan the QR code generated by Google Authenticator to import your TOTP data. The app will automatically add the accounts to your Casdoor Authenticator App, allowing you to manage your TOTP codes securely. + +![Import to Casdoor Authenticator](/img/configuration/import-from-other-authenticators/import-google-totp.gif) + +## Migration from Microsoft Authenticators + +If you are currently using Microsoft Authenticator for your TOTP codes, you can easily migrate your TOTP data to the Casdoor Authenticator App. To do this, follow these steps: + +### Step 1: Export TOTP data from Microsoft Authenticator + +The Microsoft Authenticator app does not provide an export feature. If you want to export your TOTP data, you can use the following steps to export the SQLite database and then import it to the Casdoor Authenticator App. + +1. Export the SQLite database (required root access) + + - The database is located at `/data/data/com.azure.authenticator/databases/PhoneFactor`. + - Copy the database file to your device's storage. + +2. Import the SQLite database to the Casdoor Authenticator App + + - Open the Casdoor Authenticator App. + - Click the "+" button to add a new account. + - Select "Import from other app" and then select Microsoft Authenticator. + - There will be a pop-up file picker. Select the database file you exported in Step 1. + - The app will automatically add the accounts to your Casdoor Authenticator App, allowing you to manage your TOTP codes securely. + +![Import to Casdoor Authenticator](/img/configuration/import-from-other-authenticators/import-totp.gif) diff --git a/docs/overview.md b/docs/overview.md new file mode 100644 index 0000000..44e9bc9 --- /dev/null +++ b/docs/overview.md @@ -0,0 +1,54 @@ +--- +title: Overview +description: Casdoor App Overview +keywords: [casdoor, authenticator] +authors: [IZUMI-Zu] +--- + +## Introduction + +The Casdoor Authenticator App is a mobile application designed to enhance the security and user experience of the Casdoor ecosystem. As part of Casdoor's comprehensive Identity Access Management (IAM) and Single-Sign-On (SSO) platform, this app provides a convenient and secure way to manage Two-Factor Authentication (2FA) for Casdoor users. + +## What is Casdoor? + +Casdoor is a UI-first IAM/SSO platform that supports various authentication protocols and methods, including OAuth 2.0, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA, RADIUS, Google Workspace, Active Directory, and Kerberos. It offers a web-based UI for management and supports localization in 10+ languages. + +## What is Casdoor Authenticator App? + +The Casdoor Authenticator App is a dedicated mobile application that complements the Casdoor platform by providing robust Two-Factor Authentication capabilities. It serves as a secure, user-friendly tool for generating Time-based One-Time Passwords (TOTP), enabling users to add an extra layer of security to their Casdoor-managed accounts. This app is designed to work seamlessly with the Casdoor ecosystem while also offering flexibility for use with other TOTP-compatible services. + +## Casdoor Authenticator App Features + +1. **TOTP Support**: Generates Time-based One-Time Passwords (TOTP) for enhanced login security. +2. **Offline Functionality**: Provides TOTP codes without requiring an internet connection. +3. **Secure Backup**: Supports syncing TOTP data to the Casdoor server for secure backups. +4. **User-Friendly Interface**: Offers a simple and intuitive mobile app interface for managing 2FA. +5. **Cross-Platform**: Available for both Android and iOS devices. +6. **Migration Support**: Allows easy migration of TOTP data from other authenticator apps like Google Authenticator. + +## How It Works + +1. **Installation**: Users download the Casdoor Authenticator App from official sources or app stores. +2. **Server Configuration**: (Optional) Administrators enable TOTP account storage in the Casdoor server. +3. **Login**: Users log in to the app using their Casdoor account credentials. +4. **TOTP Management**: Users can add, view, and manage their TOTP codes directly from the app. +5. **Authentication**: During login to Casdoor-enabled applications, users can use the app to generate TOTP codes for 2FA. + +## Integration with Casdoor Ecosystem + +The Casdoor Authenticator App seamlessly integrates with the broader Casdoor platform, providing: + +- Enhanced security for Casdoor-managed applications +- Consistent user experience across web and mobile interfaces +- Centralized management of authentication methods for administrators + +## Getting Started + +To begin using the Casdoor Authenticator App: + +1. Download the app from the official sources or app stores. +2. Ensure your Casdoor server has MFA accounts enabled (if using server-side storage). +3. Log in to the app using your Casdoor credentials. +4. Start adding and managing your TOTP codes for various accounts. + +For detailed instructions on setup, usage, and migration from other authenticator apps, please refer to our comprehensive documentation. diff --git a/docusaurus.config.js b/docusaurus.config.js new file mode 100644 index 0000000..2ddc6ae --- /dev/null +++ b/docusaurus.config.js @@ -0,0 +1,184 @@ +// @ts-check +// `@type` JSDoc annotations allow editor autocompletion and type checking +// (when paired with `@ts-check`). +// There are various equivalent ways to declare your Docusaurus config. +// See: https://docusaurus.io/docs/api/docusaurus-config + +const lightCodeTheme = require("prism-react-renderer/themes/github"); +const darkCodeTheme = require("prism-react-renderer/themes/dracula"); + +/** @type {import('@docusaurus/types').DocusaurusConfig} */ +module.exports = { + title: "Casdoor App", + tagline: "A mobile app for iOS and Android providing multi-factor authentication with TOTP, built using React Native.", + favicon: "img/favicon.png", + + url: "https://casdoorapp.github.io", + baseUrl: "/", + + organizationName: "casdoor", + projectName: "casdoorapp-website", + + onBrokenLinks: "throw", + onBrokenMarkdownLinks: "warn", + + i18n: { + defaultLocale: "en", + locales: ["en", "zh", "ko", "ru", "fr", "de", "ja", "es", "pt", "uk", "th", "ar"], + }, + + presets: [ + [ + "classic", + ({ + docs: { + sidebarPath: "./sidebars.js", + editUrl: + "https://github.com/casdoor/casdoor-app/tree/main/docs/", + }, + blog: { + showReadingTime: true, + editUrl: + "https://github.com/casdoor/casdoorapp-website/", + }, + theme: { + customCss: "./src/css/custom.css", + }, + }), + ], + ], + + themeConfig: + ({ + image: "img/casdoor.png", + navbar: { + title: "Casdoor", + logo: { + alt: "Casdoor Logo", + src: "img/casdoor.png", + }, + items: [ + { + type: "docSidebar", + sidebarId: "tutorialSidebar", + position: "left", + label: "Docs", + }, + {to: "/blog", label: "Blog", position: "left"}, + {to: "/help", label: "Help", position: "left"}, + { + type: "localeDropdown", + position: "right", + dropdownItemsAfter: [ + { + type: "html", + value: "
+
{description}
+
+
+
9KF3k(L{4yN~Sxn7IlUQu> z`%$(9$lxeQ2ypq3@^Z_iZUMDTvI9n+u{n_yi%l*i>NKATtN=*@wjVNH&bTx!7_>=u zFzYil$5mso$^0{czJGNo@PKWTJ0V|XHuzU;v%#1hrrg5ZD7eE z;^op!;R1n|d BHx2U8E`B52DF>u0JcNwfp!olVEcy}+RY*Xy{99AXVdaP@0n5H*$gAl z8&VEDgIEE*XODnqvxLCsX%IUaD0-obOJiJukgl052JbqYHvCitYe2AA4hTPO%B}*6 zTnOa)G5$TB)(u?=k0_4-2tTXH&IC$cr~x&nPH@Sb*mG%C7I*@~AU<`ZEa(E6xRJM( zzZNhWwQNKcz*n)AXHf!jW0Bhi3TMo}k{hG&W!mKn2~KHg#oHAMVNWRrXS!*w=sGEW z-Q5)9SC{-oXkF8@C4{X;X^+s5Mwx7%)}nUw%Pgi0yB6lcqsh!EDe?%s_CJjB2)>rN zQF?hNiS-MgTKIOO@X})->W`@z@ J zu`Lm^EJ%P98i8>IRgh4jux2TNJESF2k_7>f#SO5fxU=`x?0&Wve}GR-dYf$09^%iQ zeC_K(TwKq2$fan(Tfhl!D&!n!%54BQ N6VKw<-2PT>kv*KR|M%I*@nlKV)>IIwW-LKhSY}pLX3Kv7MShSpat_^C~RF z+5K_=tTJwrx1n@ctV*`YtiZHsuBf-6JugBD1q9o~ktWxQ2vKf|da3vI-r%=Rtyp;> zl`LK#5I9yGXgeMs@?}~KO(VAsSBtSlR4B3qyNiGQX^`abwUfdQt&_oyx0A+>t&_?Q zuaoHvzccLlB=QD|v~Kpm1W{&&4)ZEn2?e9*+@ow4{2Zx)V-H;wN_f)5rPC41CEdZo zh3k0o%w^EA%!MI$($1ybA;5+6V(_NGrQb2nrQ6}vs2&t|px}{qJ#?dgnO#B_#rvBF zw % zB}^If9Vv_P&5Ymh<=7?gLGuuJ>3LqF?Pvjlb+oYLzBDZ424@vOwz}oF(Wf3g)2YuW zmGHXb%_G|-qXzs#{DSQtUk&ruH{I_Va8KD4r{ECtFG|~k>ud-9lOmi>{coaBm00!a zXjlRq57zWO5R^NVjzbqnB4uzx5>oa-6Eg525)$))7y9OdCxl4Xa9>mselDScv#zXy zwJxWEx30uCgmVIY=-T?r_lvKL4V15@jqoc%WfJ z1X}LM)&wZ>LC|VTzbxv$m?B#~BfMm~cq^$ftrfDj#c5gY0jq@d99A49FoAw9(Exs) zvAKjxr^^;a2K$vr0sSGsOTR|F4rE(VCO6(CZ6D!N$~(GKM&VF5EHWkdaLw7kEm)WM z1u~af4?YsgJ6;mTJ0=oZ1I4f?_gpIQ*nw=F;fLdgb?Ne8Y7^~X(5E+$!i#DtPyjE_ zK!ZzWp$9A=!46;ALrH@q7EKO~zh>%-$D!wl#bM_tO<@{Ju%YKjvtj2buwmv%u;Cht zvtc~P7%&>hvSArYvf !>V?A3SvEo8vViOJ*4_xpbKPh^w$NWR3^SXW{D78o$}F+S2eukuqvX zpkZam$6+6 s4bY3MJVO6YA8um zqS;bvC}cz`eS})v**&1ew0hkLmy!*+5}rV^c{qs#=K$O+bKNGFt_}4B29cQaKqy48 zj)u$d#8iizCmS~sC07b)0;*exXoM*`iD*=`L1MuZNY@C@Qf3;6E%*VH05xfe=upk4 z%tx{mxdJ6DJMr&(+F&kgK>3pP>C|uBO3C LV$C*sTM1EEkN#2O>O#7pY=WVW>I zDLg3$D&Gf03N10SKy8vl=@gJC^GJWi25SCkn+OdqnS8nlocHiOIh%q z4Ur{bK|G3P9)cN>*Qox2tV3HDmaI@&f`e&mSp-(rp@F1nDA*KnV-{FeJ)|@$19_`b zv=oS_b!Md_NE$;VWtP-{oVGOVk OkX5XWd8-u}4OW%N>PN^Zm zZn*E6ZomHH*qMt~sd*r0nARY)2%N?eu;h{g5aE>Njp3AvJ^L<6OZr*vB>$C0V-^bY z^guM?)FmEl%C7~)A)#asMNQID43l%o>!;zF!N6oXl#P&c`3;uk*8%dAP(hMnlTyWo z 6vi&a4`eRM4>c~$4{R>6 z4^u9zdv*Q=*8}hW@z1X)`qXdG`k!NKWQ!FBKF&&e*l{9ULLLlViX=JP KB zGZOM9YZC(!uF|t7*(Ick^D2zz>r&%>EDEj Fb zsc|8`)K4?MG@+1Ja82R!_LsYm8;47xLyRrnX{v#m5}61?nK<0;WKt?W6d{clE3eE4 zr5lgT;jXxBYCjwyg8h2?;{CvGO|BBn!1ez1f`8%N3N<+I0c+&n jg^h6-M|6DS2-gDcpk}t9$bGLaz_cFHk$At+? zrE{Fl6hJl9C8ZD=Uaeu#zfI{oB5#qU=sg?1H<5RFq<<6sctDJ2 m% L|M0EA;|Hp3oJ z-o(h| IK3Xv?u`Qz72@zW$V60LXWq|_l=Tntq*bkmD21go<5)7v+goyRoy9G;$? zVr%l}l;4^0m_`|Emu#SPCz|VmPd>L#7F_IfkhAqyTub{PkWE=!7WqK0PsCkDy`cI} ziXc)Zgx^r6&@(cI-vLuo>G#5Sfr(!!SfjkRiXIrn3*#ZCeZw?n0)Gt75@dE^J#~c> z$#xCbud~+wl5N;ul0DkLl0khAA~#oMO(m-QoL%9;STve{RiRd1Zk4N3VRzK{ly7}( z-d1o{B6HOARO| z`Frf->JO=1Ez!Pt8`fDAvI!z701Oud0L<^vct>abe-7bom)+hi{PMrbiW4GzgZoW{ zB55-1awF|jSUy8<8RnwJPq&)j%9ob;ZITKvg=yq^*W}7Q90l_r9#3A>tQ4Ll5BVnS z+ZPnvKEkgs_Zu`my%0yr%ugwOKOCV~2;KWlE?hbgY6fa9c`*~IDS|wxSw`d{ NNK}rWZatfFG%u)u~=j*7`O%Lo1iUv-(?K#r|Jqav5hiawRO;(j}Bdi z_^_;x#9bi2#DvqtPfOBsL?Y$Kf>`+@x`02m2p&6Ht0jM^G14SCj>7&ZHTxTJWPaO{ zY%o^MJ)>jU*<`#VXj|f@ZQ&)=S-d7`U!(HxobX!=3> k!7O!{dCh3 zKEY!}dPj#rGji?+07Na8?`oFXC`+hq&Ht}`*^`-HcM_?8qEUszDT4b(RO&rPmY$a} zLvpZoW8_8bo7p9~US#-XAeCAgNL) 5f0TGkwHlbNzs7PUkiLXgdtC~qA zaestqm*tA2s20e`UX;M0v{-oZ `IWLnfH70c|RU&B*ZcW8?HkmNd1sZPAY~5~|Y`Gf|XkpC%L@`!az=#dN+W6cG zSo?{#sqjElB(bQ9x%Dena1PKUN;3VS*Q>prj&h17Br=XPdT1?u`j-Gf0{dR?3mK7* zBPb^SO8;s9UH_|hIGqhR{UG7qHY0Zj%2rH4gf$pLS*wIBY+6J~YSi9BLQC1D_%l;< z0tNH<0aKDix!8oL9ac{{;e_sY#2|RUxY!p!uEl>eqO|zV-uKex|0+jE*jAo8JrU#2 z(L9}DDWoPzeTXO*?u4WQM7j|#OHvaeafAB`u5;kXMBMK$a^P0{vQgYhbru}9J>ns3 z5Yw{V{~*{Ele0ZVjU*>J6Hi=-P$p`Hl|nz0;6ejEqQ#NOOhYtc;FO?8gEpdjH5+M0 z)4-wqSgEF=avXm<&uVdB+p?^Zb)xKA(#g53eM0Ou+p4WMMzV3{CgQ2x!N2BUpK%|A zo40Gpa-=Gj0f}uyBT=S<{BeO5lFxY>d0`a3>m}RHx$Krgk|dOFhPw>n?|s;?Ock=h znnc12spwPMWJyjiGk(-&&`6@dtqrY2Ii7^8tFwXA9iOigI>B!5&8}lZCrJ=Dr$^Y$ zV^y7=#%vSy$A|rH3{@Fw>wrGl 1Li*@ZHh{rZ!?GVSiL*n5t96PmZ{b1)8 zX}F8_VEv{fiG?Ud_)8xf(@YA*7!e(L09jkcOKk+VzTt#UW|YCHOOK{y6#A;MgO+TR z_o_Xz8ndjCF^sWtv@G2!(kuTLs*A*`wEMr{8!aITw)x{5WnW3d>HAxO*MHPp1d4v& zC+E2HEX~`}yUa_|%#z 866d zIiw?G{g^Z9xB|`Tf2kdcO424g>@o{0HY#p#-U*$3yStH2#QRQ6t$02hT|DbKIpf{v zk%+rLt%8^;aoob?z+6BXj3|?Vsx5eiDs@e#BFK!HENmJD8g_`2DhZ*e!U0UD7z~c$ z0dl{Q;CMhtEfP;Z=~txv4SvCZlnc37Cc4DgF}|HGC#tmJ65k}B4*L?3!0wcH5V^G| zsve34s@-=+29w_;qhh I!(L b$(Rt;c6jQ;>=4QBguze<(kV%_fLQ2 zB4H7&fS|g}DO>W^l6XhGPRbqsc1jm0=UnGI(sMc!uzx!pbZu`BURgaex$jIFuGr#=my$iz$Ob9MZ_g6lqjo%}Xm8?wLAPt9j3_k^BxL$f`sSRZRc z2S1GH6u3f;HjI1~_yR;C1?YuA0RsH~kBKhn*&nqfrRXNG?6&+jY4STqP7JpkZZs}t z-{{8Jqs|Dg8g&B>H88gS5*l1H7YQ;YCmDvj3Iyij;lm6DF!aD!^lq1OeRKT-qi0vm z`Y+DeIjVJbCFMX3Qddn~y;hA=-F~Ka#%edv3Gtow{rfueI*>TSIoi;>+$S*Z4b~jy z?X`GNzAAel_MzzdY?x?2qOxJ;$Iu=1zBP4Hb4GT)zALid&4!KXg}fc&8AQp9-i&}3 zQWE$OI3BnK#SVhgguRDlgUyLR1TzDT>k<}J_2});RTM@Fy=JH_16|}%M~-*0u562H zC>hnY3r;j9nQ}g&gRW~Xzs%pizDE{S$vo1!dA2imR& kXxcuWnu^5vot =Q8`!r&f4E}MD(<5o= z6}r?CMB!YB`q6=4KLmeCm5^FU<0|LR5!o6pH=o$Q!|zElNm@;GMsOF(8(Jg7A+;n~ zEHgh_*obQ@FEG94f}bV3ugaT5UyQ0R#{23Qu?9Il(v5DE_AKbeFwx^CB|IOe-b1+l z`4@a-8Po7pp~X#G^Yp75L3@_aOl&iXcUIy;*`dQEZ}kSlwB5(wXb%4CknjBd8?-xZ z?SAnnr3vDsef-?r>wN!OGxgBypy2 9{E1{j>CcY zBSg6m#<&HYE)&lV0WCy?oP{2WF<9A%OAF>JI<&Y0Ne6(ew+0jfIz9lG68kdmVGKnM zfsfVT$|AXBb=b6L^ba#K)mWL`f5VSn@33&td0#=(q|Iojl~tF$hPnZ7xeo7j)K*ESM3?b4_}f7W0gylZ-p= z!F^{p)RL;a(qOXA=N{6rvu&hIHve`UraxzAqSENT)FW)s?V=_ykjbj-FXP0#ADc18 za^&W=-(I12&~^r|7Q{tMA}7KTq)4SOOzRXN8KH##N1ik>j*DSJ5qajSk=0hod#2Zg zQeUzKvW@*cZY{sYL;+kQzmOw})#ZWH;kSl_<{8(S ^?O9WkTQSD=#_IoP9;b62|F~x(86gBmDpr%g*ppP*)TZ} zM=|W}E~U2$Y|D!Pu`I<*7QhdS{W?HV4o2Q!Y=tHb-QTEs;PMM6cnk1P ?6Ya&^n|tVX5Ru;dJxaZFy=lDHz3ZrB-Ad|0 ze%# ^O$olzM%Io;hkH5qGCRKG-gUtfLUmY0_ot*F;DU;oCYD&e;A zzJpVmUa(T`>zWU )mGyTmCOEKZG- k#=5G!_Dc8EY zG_w7RPQ~UZbGC??lrA|Zt^4A#X}$W}qTJG6MFpIv`t#>MN$AoBNd$pwuan^0i$p_; z9K9w?L!s!JsuaA968{aFQQW^Qc3ZFoznW)XCjU@GqtD3VF=G@cMe__t%O^+AQzY85 z6j;C}vY6j=L|BdDcZ!!`mRZ>sCAbh;{~8(kV(vRKKIALShK%4i2rqg}@n$#N#_eY@ zvN*UH>(jfg7lE19g^}X8ZiN%&l38Oj(lZiSl0Rhm>`-2>#AV8u#kp&d_8`ng5Hm+M zqF|AK_=)jnj^NX$)(Q~7DoQYy&XAW^NWE{vAvSFDpS3UC^YVg@<4-=vFGqwU5!>!V z*ec(%P1fjy*tv3DPO(hRbn#4@)rT0u>I~IAdmHQ0FtD2OFUpH5I(F?(KkYlaU*j@$ zCNqgIO@4KUOj`i`ob=}LE2^nPVWcx+RDM#kL*E98z%2{N+F7lN8P4BLdj|x=F-|01 zUpKk!zI9exU4e&f6E)U`wI6FLaoS&G;CZpnHM7qbqomlWfFPTA&2-?)6S9;x|BAK7 zMq}{Top$)I9%MUdcj6pIf71geN~sLut{61o%F1>ANVlbfD`^zW^-FX(+15GyP;G;9 zh|5D>P{Ur_#A2=7I{6Z29awwjBkAOtT3Ys0rWUj~_ErWiX^4t(V<%W&jq06 M#T>{^3t>u14fi9Nw1w$N(0Dcw$hNP}C${UN5iz+7z0-BWeyYAhM zVS7aiGA=8Kl2UVtD+>w4bL-Gc^SmWuZldg=;URW~q3HACo-=HS-2<)({`&^@>`rlw zeOLpO-`^Y~Kw4H@Gq_-Tw5Q)s6w(>^wg+MSwN>|~>h-3Llaky`(b*(M`Rg2Blae&! z2cDeE9MUza<&xzXnDW`6#$?Ge)cG#-KT^6oUfgH*t#4No#9d4 5-=u7S5? zcayoRqn=An?TBCc!xpwcHwSg>d4Uv=>$X^3EFTU9Em09i!f@5Ls{P$GKS_xI7+4 zZ4Mng`O=q=@>s}KUbyE&GQ?SeLbZwU!NR2@tI29ySjXZasO*n0Zwm6%F6uBGgj~~M z){s~=2MVfQUF@X2%yXuJhf 6^O( zuV3Yx*12TgQBpNB$$aj&MKr26MHi9a8UIO2SUGE0mDdX6oOlzqBk d_+>uvb(H0yacJnP1}U2bP6)Hj6i@v&5w@rsN$eiACQ zP>aj939 !A`8zpQH7`;(CY?x;$LuT%HC=<%sRu#ZoXAaC>7ir$E zpn#U<3>7|)3RloKh8w6gd?C(JQ)?q(M#m08B48?Vhm7uLp0fogEZFD%)|Rl*^-_+D zca@%Y6c$f)RB5W*0icfYg7lR4^;rig&-bHPIs0uB6RMl^)=8Oo7*eA3Z+_rU=SjSm z^Y& ud6FBb98p`F9NvK z?EBajQ?B*H7{bTd9iHznk2upiHl5dJgl9w^pO&*J63P&C8d|Az-ZNDnk(*?sr^pje zKU^hm;$NjSr8!p#R`jN_fEOR5lAd=dwtJWHt+n74>8CKXDV96?8vV4>)&6M-Ucar_ ziHxhuu2_l9X<+Iv>2QMS0#vWYT`n*Fl=AOoO>-pWsk3e^cLX*p(X#E|-7f5OmR5t! z+-G=5+Z;Ak2M({_HyGaw=CVo$^T>F&!qZLUSLs^m?!H$u+$X`0%6OoI<)6tt3I5*w z *60mc+Ne+b z7nsS^_W=N6axqGqzmVGbCnr0-ac_4u3W}rq_OGY6a-B*2S<;=tdA!-v4I4I#twI%( z$uVmz=B0@2D$`YKkz4D;cyGB=HT^$PBCdZQkM=JQx(K4*KYVspC{y#bZl-;u(Y-J8 zYp(D`y|HG8p1Uvb7Fw8F>US5gSkO#3KY9?OMs>k2^XO<%ktD0uV|vFGuErwGn?p(r zb*69vo!1KItSAe%So*#dcLd#vF@d9%vpA`8vd20KqbC~=qES5VpozU4LasVza`n{w z`d7&rnJZyvw8Ujo5t6JUP7bS6&Rk!iZN!2N^b6pSeSCdJPV7ap{K@k`+i2}pR~N%{ z3$Y?8X=K!Rk2uxK{(k8%QJ_}TACF8PMDS~El<=-XR|L!pO^>~EY{bP5gS;YJlSE|a z57h8A58K*KmU_V;51;L|t}(~a^L#Oel-c0s%Bm&Aw>|o>pE2 l zZOZ**PT+%|Nao&$R9~m>-O b`#-qZnWr6gm)7IVRsA)_WPUcQ|w;X zMrO1Bp5rd>@y@bM=*~AVcRTYpx5`@PhYk0|g;Z+_<@2?YUXtdi#CO@$VWYD>QN^bz zOG)U4Bk+C z-4BzX)!Ek9pPR7m!F(nEzmMjh$r {I@`S)4|Y~QwRJO43wrap*@d2KbxXcMCiGNY0uqjkt+Tg&KK!DNdWJ#R+m zF$(iM^H9d<6>6(Qs?jle`jpATFh(y4CJ*;1WxKnfkl`he9}Pl%$<>JuHxuv3Rh-k6 zK844H_g@@<55Z17@2J0afj@XX5C42@$ZqApH}yv Ig7>^Vj zoBu1+LeI1<$=^~_{wS3!8HG$S+ge5;Q_L1KdY)*X2sDxI?QMK8-8;g+%w2da9$Ta= z!xwicMaqUkd=_?*x4Bo t+QZMQ_JYtt|nW|==rXyiUUBk^kmo<7CArctUej; zT$8rtF!#MYlXuU|OcT~*E&&h3mT1VP8U~{dXnj8u{g%;l{Y|$LJiC3kj;@<_ZG_WZ z+x1|!HWNCE(nvNZ5gJG7IMyGb*_1AZ=vr17pYY#6bPnX{GhNfbBk0_E4(7%#oIE(z z+tq#L*sRKCcXA|#^4UCfxUKbUo8E7%;g#0IF~ZI7xB9c|z#o}S+IefShe@TquNP!$ zK^!W96Nw^tq2B0K$h<9C4cw_KxVQ9az0-6jD}^0a&)e`fEERlNe{YvigH6DD3-)~Y z#}9koT Y)xY>4k#T>cN9ytEukR*x B(Di!5 zm{_u6)|hcA{$0D{#H6Hda2$vcyp-=B2D+aAuz$aK0|IByPm4XW^ s};D`|yr|-J8WXY{}6Dr3H z8&x=J%eknx4Za@JgCjQlR<`H&&7mQ&g9hFGa@)C?FlN-Z#ttHTn?@G%3!_~bJw~ZA zNY%k;%|z6JZMDgRc%RYAm|q}cyMW$;j9H^TkTD0X-o1S+eQ6-%{t5; i869VgP^AXH?qlb2yl?>t+lr8JB80A40|88-GlCN>Ji`7 D`j;cUMmwmH*Yaqw+8Mu- L?Lr@`HlvtQr;nWz7jz_z;xzxH?O>bqjak-yE@QRth4DszOKA?(DNp3io#ZCW2f z?8nD$jhgoQsE9GAqPN^gOTW54?_?r}l_j~Aow*r8DZaD*@Z^Dm;se8>viChJ%xWsp zd3MKN9j`ro!f2$uktb?Dtvd(AsKn@TGpb|sSckOQM8!r%E6nIqMk~!cSTI^;W?RGP zDF^k$d{l`f*|9?dQ2;!Lk`>oFFG+2)m;e7v8gFB{DAmm?qEDbl_ufGsX|GK?qI~c_ z^4P80pvfa#Jbg8tmTNktjgDA072kb%W)VhL5E6z!4fQa83u0#nn+Lj|R(0_~<8wm2 z1}zO=wh}Mws+46ZEm%nYhj{Z9$7BbGS+gE5YB|KmEow@5V-!@zJBmRVC9FbWXbkvN z!!sQn=mSIJ6iC=Uw(K;er-=z@O-48;w$0}7q0rNN)H_kJF>!}ig^bnr)JIIKPkt{^ zF*cRdPFd=+e$A@Aliy9L&siB16dg71 1+GyL! LlP3(2+l` zRw+?#S7o*L3Xl5x9XJNnM4z+-R9Cm|sgn_hH9(ExQ)EH*P3#UFlee>U2)RZ)NS5$; z wD$lE(00K)amIlJ!Fxw_$TD<<;G zT24doqvo43*7lRBu3`F4QPoPMSuAc43pvOA!xU#TYjILgYv%?;v Vih9y`1c-<8 z`_q8(i*_qt|I_Z>XT?eoK0YugXrLF7J8$3J{62{e$;S%#fOaEG{ldt0{gYR7Pk(j* zD%Ey^9T~YgvWKij`AF6I5Fue6S?i!yEI7Rd2L&zkQ!p2HOumYr%FnU{N2RY^$A#g0 zxb{VVu>rh2l)q40fwu dalfzy;xN;oPY{ zR%jzREi@o)2d9PhCk3TeY-sjm#{^*^iHx+D{ta5LkjRc0FW|#%Tr}}oRD}{%E`Oo+ zM>x@*-RecS%qYA$;3Rnw;+Q&~Je3aE{jVDNP9gFyp?FF=rF>nCayFJ9(O$0_?=r|z z7_4D>vND*a63P4*9|yMgUhX+-=<1$B{TB|{)N^Ry`~fTHNgk +w%ngYSiW)kpZ7w7$Ch}?XO1o^GzV0lr4F6Zm{(>yWs97V|#Onmd zT~p)KIg4Aia_5M!*jHO#ptd=S%o6{hvxHF{aShNW@pELQ-fYqbRFd>`rLpO-yS4oS zZCs~Li?DVGE&5Z>;^+PzHenO06|IN8r|*k?f2%~tlpHe>3Zn{fGFr|vTd|qZlSZ;W zD2XH|z0@-$h$4>=Q>bUU`Okw_B@P-9>)A8fK<0E1e05f7k=vVxlD*=bN3C7O%>ZR& zVs8}-IXMKCWC`BYTYWmhW; g}(;{Oq&4_ijTh#4j0vn{)&aVpL-ExEa+kT5Y0YBcl~&wib+5nbFmZ z9vyG;P{Zgc_|Bt4iV>&-dyny_nCW{A-rYuhk3r&ZO#oz|;Nm>UKtcWdqy{{CX>1SW znbU-f_} F%GiBsMeMCso}>1?Z Pe4DLkwBp&_lMRd1({04W+v-6Vwe`c!(qyk= z-WP7y4{W3M&17BSQd2+TP5IpT$)>)fWCi`Hr$exg-GYed85B|*;G=cdnm;J!XDe>t z-0cBY3$nuYPAmRkZ0ym}&BejXXC`g-?*FFXHD+Yii{V;MA2acd-wwi=YB8Ls>gJ}< z6BT^}Vl50n4(iF>hyEu42lGQa FTjWY?t>4or9*h-HjfBbz246y_rt)?%RA** zE#Sv2Y{}cw#Uj(vqVkN=V*&Tkf3lU6MkDo2s;!Au+fc-)j?rV3%3r8DTB#(J8&{y# zyKnw8$b=`kSLpEVN9)TEvlj)NSN<;N)QpVx;^tJQt~nJR9Q;;lVR}H$;`#4JWnWrU zcwxwd@B{Jlr~6I_)4ei0ZD#bEh+zX}dHBaf`bPTn(v4r8xMV}f)PR}3LqHi(K%%%$ zqv(Pd)iHXEQe}{;meHDL9obe>TltH2w&mmv$Srv4CPR${v{kYdZ)fYo|M@M5x8Uas z8$e(4HzCt!?}!>Wdi22QS=rO)9hyBk$1m7@;h>EC@WhnFaNh|NeEY^vUsI6vk$7`t z&h*e3L;Qo>{Kt=qT|akO$rM+8w1d-Yt0E1fhK!7l2$>KxINZxEddSA|=IcWLn>STu z6%a*>s6!4g5_ENkTJiA<(5k04y6W>SzT1bC9{c_GEWA{!?46StI o4tbZ;T!(5^WfEg6})@;*wI~UdHa?}&}J|{ zx}}D1gq~?Tl0joz1{u{cT5Y0YBcl~&wib+55$)@MdV!wKsveBlD;WE2xJW7Ag)MRS z9m+vmxL>)>dEy_Hh4^j7LB4@+Lfc{`L2!n)-PE|PICZBKK*M)d3S8zM+F+lSJ?a$? z<&Ati4iAMq+)J!l)jh>_a@Gt8ZZdxqR1qI)Tv%+2i%}h;)g~%7GFo9~Yr$w0`#)o9 z)wX{pvxbYak$Z8m@FuBY*|IrPWIIf!GoamTmW3jOrLYW}@O#M&Xu<+?hTW1`1wn zH-fMVs&DZB{z7nJ3g_+V(toUP=a=0FLXtl4kLWa0^XkZf9bXB8BHA}mZ`Jk=f>DXl z<7QOHXtjxojf_^9*;+7KWoBE$=qXASZ#8~G=~Hyy_?Y>KV%8_jd^9t9@<) K|4666c~48p8nU7|-fObcxRr@R7Ekj0yVM??QM71O z-@&7uXY>kn_ne+HZCS@j2E{}h$z~7pY!a$twAzeDP)hEjO5r|=eIh<(_LZtV{t1FV zPpA{6YW;GKKzBm@^7PFnw=;{*BWjC{P=mwCh&!2{85{z1nMPvtIH4{;i#0k%s|g(p zbdA`^Xa(v}386V)>#4C|w2IK_Kx4%kMo$rHr$jOj +N}3RMk`*XiFvSKw93r3hEbLW=AolJ7)c&{&GOI% z_I`6oiy^enNC=%$$V10BK#lG0RUk1p*^LT!F@<^6=$Y3ektQlJdfbfa7_Bx@v60b= z$d{;P9xNEGGPA8=^c1B^r0PM<&CiH^1{q>4ni)MA$z}zy!E9C#8(xF~fEL>zr<2s1 zE2FA UCCf~f@+Ot0w%jwk}f>YQ2yEzF;`v3Rc1hsZvhLUdCrqI*XB+eFfuar4_m z)hp$u+eB40qf9l^z@yGoHC1A|LnL~bbgHWDJ|Eh> +k)bl2u8Q5*X7 zHviN~>1)!b5BR4(Dy!{*(rUXFMpo%f5y$+%>I%{Z+5qzl g`u=)NDC@tZo14y>GwQviEfT z=f@6ED*<~@Jw8g0s^ lxfS=i ztd?m8Z5`9RvyK&C?i{bW=|}+)5#RE+*SB%+LSJ2Y |;MA#D^L>d|(zkdlqwyV%r9kIDV$(=AA5cY5L8q1-Cel&z z`NOPMd(^Z&yit%DHL-l&xZt(m+pgDeV#S8q_;AO9@#5RfB{+>@(!fyd88c?gZpf>u zb_?;*H;x%=^!nY(N@iWK_W}%YVSa9qTNupGU_7ePz43S2zxusHNa2x1F-HmtkH*Fx z2c2D=puC`=p`c*pO7ZQaOEu+JGEy&BRa{CZy|6#;XlvWOyRB`9BDa-h3Icj}_%lHk zNSr*4a= ?A2*-QE0Okl0GFl#jT~ z#oP%`O9Tr6qt_ClbwvefuT_G690p|QM@okLJ$fwkgHH>r7Z?)@zCSo3(b%jX{E)QD zL3uzwhkZ;N5gDw*y%h4Tlqer<#Y{nG(19-*9ny@6$<78{d?QwL5yh~MG{#zjSC9oA zmqo998}-#G$M=AQ<_=x%s6X^o%e(pWz!#;}6%{7}nEB`a#X`x-dc~@x-iY 35m#vNBgzKSQibIOT r~$S_ce|I0}5cU=>x+wgrg z`l0rNhK7c7D}F#Lzo~D4O z z=l*~e!fRHapjl>ElqPa<&t4@InGr6-bRc`6AUi$RL{elDiVl>Oy#ubTLxZ8g zUbu-%z~qiXZ!&RYOtc-{?RETaw kcEq`wCK%f 8uZF+7iPUpvwH3Lu zQa*2%nZ^D}HapGN k+CIi-Tvxgvjp{(cdq>W+V3z^?@WbQm?%wE($}_K0tc z)k`c39&d+aRiF)2;BEKFeMzw0;Orr@mn>p_=vvCGz*H#}lKBAE@|h31WbQ|If5 SvNAASop3c7z_h|EDgr2=-a$CF) zoZNo$fOm^{ZHfe4L3hv%bbVk(Mn5nE|8G37lcanP 0Zl zq >sap@;V&LITmx|rOb3Et>}mK z>e8 O=%?>Bt#+(qO9? z2o#`Una*OgmT){99Rm6aj(LBVb)dYG3^( eq!)yk@zYCGJwGp3kIPk^C>rbL(40Z|>^) IaRhqUW2;-VBe+r2~t9rXA`RoMu*||xXRjq=R03? zf7kZ;^dV+bW{>kT7;iFa&|IiBcGRMk9@|I{SHJr03i~tH(EighH)+HOr>qaw!N0gl zZk=Uy)uBq#8}@f;Z$m{RNN=XREu~6xm*9W&`OeM&@I3$as>A5q>eayEl(~6itw#&) z ks+>hC?m-L^+xys5*jfJ=v5KUBEQ z(Z~IBaTYp^_WX|C-xKTQ<>CT#fN>!(e7L~c-!Va%rA~MI#Q(^W7qZr&7R@*Z-LJ6h z7t@)hww`9Jr8bZ7Owd8cY}YM5d8j(0I=OPf3WO&s7wOD!|L{E02cNaB^fTv5*hjf! zF5~fN%kgN3iA;t3+95RS(n2_Jh7L7Q)g~Egjk8l3t;RiW$F4Q)abeapHm-Z?;H7{# z%PDdGUU4#6yf|wIy8I9iyy*~_dWl 6 zJC^VcOaQUSO=SjxHy|a4({A+f8Zd8Z0bu_5^y$I9%?)4_%_6tuuEH?+)%^A^(reZ? zHxub}Yf q$BgflDbu~FVQsH z)F(F_=qp8*OID*P-fa!ImudKmzA_`3dN!6cT~#jA(t^Upj3P |hV>_nT)g?2X1dMl?ojkSrkw+mgn*ulcpX0*A}Byr@dyXd3K_tDGjw8Vt;nRQQ( zUIwzev$CF|m#t^Ni%e+%m(ZNLY}16RyLJGb-!iZ~hY4##Uo@PrAfOCywpK=|0BfmK z54e=>PTm`RZs+GWHvUvx_k26|5wHT6ureKLy|V0ZWqR1jl`ZE&*ohe#bid;@(jv~H zm6M1T)T4R6TI#9jy|?5~_wQG;bEmJ!YreN^`Oi)9g)@Dp_`59J7&jEWKw1N1wnPUl z9w(0A_7`z^;)vJ(PModSgOetPjT{;ET}R=CKhmv?M2xaFl9p%yu?J){zYmz<0Rp+y zU=}Tov<~H>9N<)sGRHyp@zj3#uyZ %N`ENT-0W9OnU|>lJu^XZ>eP5xn zkRj$$BBdrb(ZT>&lS^ei04$_>(f6R+^@_I2rsW5~NOUz3OWrmToj_iC@F9G_8Nm#$ ziGEhVf@rQ5=0|fiFf}z5lPB@k>>qRt643~v4GGgy1F5dTn|hnP1{NA{nKS-{qwlRe znbewe8W^J=l7Su=8G}ATi-*8d5D%)hfLjB5^qv<(dXM4iU}9z_>HR2*V35|ocywb$ z6KK8)?>@`%+Qt=lAfIbs0JNu5hrmYPOt^9e24WL4xdAwmy2NvRX37S?YWvKMVad6c z^W5Ob>I1v4 T51Bi1q) zKi0y-1n%s&r#hYaAw3IpFUjF8P`|(e=lLtL*?|QXAP@5~IuQ8gu9z`n zMQ(Pron3Wy>>T^Wi|4q2n?nN=^yVC{sm^cMKh(E;*dAc_!?$40!F}k`y`RzLU0Glx zAiF|}zQuF;G5Qt3BK?{gKER;!yUd*gSs#ThvkTNR8?N-;`}7gn3&cj_P;XC>H`n0E zzWqfkk6>g){6#E}Dn<4;?)gjHb1m(8sIq5ue}=6k9U^meuSV#~OvASke4=_xi)Jne zM3jUuRd6Y(swyeP4rDf<6!88!lr9HTKs=X%$(#ZaXg8ck`CW%L3%T5t6mihSn$21! z)nn8d3)=;jcw(*&gB|OT9Q?7D9iE+ymi6Rmq)_iihw2o1z6b>1%;q|Tz^e7&5DpIj zuMWZuToSR~PCyU7H56UO(karkn6=fa46#K-IP-;4L%djWdR83Tia9t!>}48 7N2=@Yv#MJ%63ZnU>TS^e`Be4;JT=c)h^Ce z*D43R`~I%rAg7E<2i=`u=KVuJ``ysl_R%&|>{i@s`?xz79gjS6_( `X5i;1b_Dp#t3nilQLGv^mBH?gOKu4J?iH=R*>{4BOljCl>G+b4Ngn2DbDq|Hw3 zIu8QDV<78`I$xV_2CZI1B+& u>YEavl7TzVd{Nf0Y3V*! z#{R^QrOZnr6LqSs0Z}|vLD)pbEIzN3#94U!Ce*^l0q5#op6Vn8)ZVm&U^@Mk-Y}U= z5C5J`f{>fShOY@s$erSD)lyRXRdL=Yl{xKcC^o3de;`~iV17Z@L;0vhlHtia>nkhZ zjX{%)&pt_>IVNPB{{~=n{~mBXvIgA(o;ix 0*TEiZan%6 zhVQrr*k4e$8oZ6Q_ rRSe^4dFwu34JR(UW 4Qq&SplPrQS~U(fDB6kn zUP5hZUCr8ia-M4k?ng{zbm?)*s`{bE rY#ph`#!c)r#^w} zp~w_-xS#r5BUE+JDDFb5pee+A!@Ck!6JlBT%f`O|!?5h6a_=v``4pUL%yb+JgqmpE zR!56*HJaP~6Pi^u(F94WDyJf4<<#HaT)$OOPZerm*{SXekn$Gcw~1u#67gPhpmmo< zW69usq(V1jO6&sy0(=bBPlOEPHQ?N?_zmuE^Us&Q1fqiPHa34(41RApsmo2)ISSVf zvN8gu&*xhE&k02P(Se^)`#WpFWOM{DU?{rx5_3y?B;0~;d2atv?iTvAQZ)wt_JKaF z;-88Ml<|9x9H+JddGgzS<#bB9$u~UBG)D+R%DoV~*U_ZEf*^eH-e!MFE*7Z-wQ3 ziS~lexCTa-dl0NU#@;g2((zzz_41;GBbntLiOhI#3;Pt$Y?ZeLyXpOaP_IV$w4FZf zQSXdCZB#rJF=`du^hG0k*Kp&7J5(|j;!GK+S;Y-WPV5$Qj#~SV9^5kswh!FhtD0Na z&tL@5Mz7J&>?ZVgXD1k-!N)IZ+)-Rhi})(L`KK>gB?i7*iGg1+6e*v!E1#ZGJ=Km^ zK0UXDJk3?gVk7^zf03sYJEc!sm9k((WhjPv@{Hn6%?zt-riaepZwG~&!Y@iom#e7_ z_zt-&1efT|VNQ;Q_R!+54-uQ4P2_Hl`$`x3!aYeb?Vj36!?plv8hW)Wy| ~v^qdGD;2NYOnNI$w3!~}XDp9&ku$(ds;elC5ncCV70~_lpHfr` zVE4|mk=sH~)L#Dyj(EK@6E0rgmQgOpBhu~umH4>S3X$= COBO!Br8i#M?1@HNAO->q7E zJA28yr`H$fWtJ{UWgdWLl-@PGwHYFAd|Hmnk?n4I4t7hOKX{aa$0)~Zq>ysP`@I(U zh|%xWH^!rsz!XbT%H+)0!q&M*o7Pyzd)Y KZ|THaeIW?{RvsbH0P!GSVr`%_!TjswnfqiDMs(>PIxhW~`HaFb}-Gm(m`nmycC~ zpeK0yWHSi)2Z%^zx3=vl3*81bJC5x>gc_I={B6j&Q;O 7|<*iaINKBL#|vbU$Dl z)kbOEmxRse`6|_=I6TXEz;ef3+IwirePj7lhs6#TWjUnNM^imhM+GxgkkuA)yuq>x~>*@ zX=24;tD)OMdUT$F&RvhV?ejP1_2xraAD80tCe+@S;_r#XZ>0AQ)MJp+{^|bG>|Y0h zwWywH)j=^Q{Og0tV#A!u7l_5>tk`E+6C49C6c=;$+=sqfv%lQj+ThlHaCWwXU4ebm zM`g1_Kvao)3KedmHEZ6 WT-TgQ==HEm=RU2AxXe}bd9QqBYxa5eBATvpBfMOTyw zzshiLWmto)rfYi?u~3y>vx&75PR2mJoG8w+J9QW0-HW#crzQu~2kxp2fzQ#pX~3}= ztpM2EOnW~sd1v~JB{S-lZeHIhfvpQ+EEmDK678&~#7qpxT9N^U2IC=2nV=8>jf3KA zZ0mucl||`aZTq%qPbV1K5Zkn)88C2`E{X>Z=p48J!=_&@E<6@1+zh-6XRcngb|r@~ z*?cs(fO|o!chX9ebOi^h>a @@?KFITV@YhmDtPPB5nsBn+@jf0A0bO ziN6B=2hIc3(WK&)yVmqZd)912I)ZljFSrM@vRk2PsD)3g*R;OwEQqdF-dV_`c=Ai{ z(K`$D42U=Jw-!&o1ogcxEheR !`>P1hXPb(;H9f~WT-o0`1 z=(?)kS`>v(JGf?;P*97DpEe$@?^r}?pWYC`?l=^s@^}7AQZv-;mX8$vPL#U8vqQt* z(dvGPPp(S>S}_>&J(jE;MwfUeQhZ)v>097pA98*znMvsdFR<2xZ*>j7Gn_ga4jMCc z*!OFVE^*`g>6)2I2bq9s z(Or9$LKn$=*Ehv<`Yu&@zp)hP7Niti?PgVQzy- FtkC(jHxl4@ z>V7f5lfyXQ{3?h9{lHoroxrA|Uw%cmPbIQ9e#>ffS_1q&*wxh^`(vPv9? wzhWHm5@cj{zgmP5+de_0PrLA6ZxDasR>cu;G<%A zZV2}wYn)E}Q2Kk4i2{W@Lw`J5{8O=!A`%f>>a;CWUB{gfnh(P1ASC%Ko&G&~OnXs9 zBFYVD3z(N~>?|3=w@E`KKtC;wZ$n~0SwGx{rEgdvC37TvCvR~bSBv=;FeodFJ3tz+ zqOb5Ne+~cr5PF|C4v&W_NY!l8O|EN!LDHUqiJr*;Ne#0m%1)I9)cSF{n0VCS1cf&6 zEM5zW@)jq#y9SiatBpbVG*tUYQqt=qmWCnv#_s+bSJ%`KZ)p}Dr2)y`q^o!ojX;#* zt85a0NS2vYDl<^*COPw&3uo&pbDlKF0E$uCp#H`a9H+v_uD?!8oQ>0&Z-`v*g-}3R z+QhPlSHObIyBj{P4j!9^cTEMAld`55UE4cE8kNVOuCnr2pS8 ePveD`AI-4gH;4TRIdedG@g(~mLtA$dmVmEd@2#Ap2jB3e!1 z59>1!(ZmGQe~?*KU*U7aV~*!niRmZOau+xjcouw8wfVN&9JkXYEiLQnKZdc99uXn3 zseX1Y_9cr#(v7rcC(cjb;2CZgWaFH>C^}40BkKzxvsVcCBbps|445y Ne#In<;QhLIvp7vKhJxp=In|P+(w6I@6;|+WC zhdbm^B%m2@$g~&rW06H$kyd{ed ~;Wi%3lC00u?*gX@ zjTjOch-nPt(KT!(l2BU{edSvQfLDo?wsyat*LU}WVzEhyNBh4I=$NPa9Zcp%!k_&v zcyf3jbEDu-YO~t&T^^wv!rK%UgP+kzJU$z6qw~Hp!-npN+amQ *LEOte8}R}ga`6Sop_%b^w!t7UmZ zWtR67j;tL=+*byUZI|Lm`DWnizkJZI@uH@$Ra22^Yr)koaSz6=>qoHcuyMVX5||?PkehA63wu#d9icX-*tAg z(2!wJJln4B?_E1z)J&bhUVrrXrkyQZC9}4%=JMsUKDqzsIvxkjx2NM`sWi^vVVqG^ zS1_U6QU_LGk~vd6`{?5J8;T
7wlHlv)ZIQKc=8xsA8cMz5xAKwUs za6>V#8U0E)tr92#=DZFhrwA4?uk?T@19RhuTlS1`bnLP$0TU|01Z9f@PDIP!j_AB&r(z^e!j(`kz@hSA6_Ucu?dD_eMCp0u$P^?PU43`S=GrG-5((Y 96jE0 zd3_b`Vc(A9?;mB}Mt2W>Ul(c-YB)RdVhcEgW+UT-HDv^++ee~0sLmOs$-h!zs00K* z8(DENHT7)CLG)ndN?^3#)Y7kTZZ+;EefFxtqK4T}%KbpTfo8-YKcn!N@(^W?9@Pjq zM^CMG?kF{UgGN*7_k=az?#M%)j`J#gOFQ(zb2Q+sb2a`o^JdRG X>H4-o(U|5s7@A5NlO|Oj_>-1cO-AV*frakvY~S!PUwwWWu5}T2<}vVeuyi z^3gZmLAco4h{bi0uF^2+yvibYD`hcXTkUZE7J3(i<(5M hwxbBMQ8$e1-|q^a&X-P z|9mtfqbm^laqoaH@i+V->uEPyh!dlR<6SvXi2fsvEQM=?P(R@i5kdhKfqzHK3l5*o z+TxQEh<1SE+*-y2jXkjYdd9_N=>=0F1Hl|e8t~`(94)l1@{Wt|uWh!#GbK0!q~yk< zlDcj2HSYbijmD3$^q;65=lbK1uE)u04@Z$~3SI3^A`M#&=1`qlOQNFKLOQcTgr90@ z0?>`>s=-V!+{8C{l;c<%0$Nz;BE0sx5||lr;d;Zo`)N&{*5!jKQ%a }FS{1X)`L1lq|_RDon}Zj=zk_s{b7WKhmmz~ig^m40&Ti%&nj^VuhOW~i@tfO=oU z-{gPsmI}7+{hG@7DO4nS&lTh A9Fl-w-B?cg|O r_oMuLkq}qCnp#~$h-~Gmu`zhfgW<)W1Me+pIXJTi z6@5~SUV#c$Ynb}LurWjEoX3)i)3h5kBK_ispwa|KM39h%KZ0p|gn2oNY0yYNy4BUa znEDd1vmc5_w#CKZYB8>klG^3plftJYrh;-YNP`RfVV6)2s5>L{uk>ngkM<~r-Gy5U zQGzm|Rqq=Rjh9a7+QXtov=erC60F!+=H#_%<6HAx!gFVet?JUUo2UkD>!Nod(fUU7 zgKMfAR)SWrGaxk7D=Ki&x+Tbi@Lhys{p{(RE-=y{Ru%wMMD(e47gjsUnt(EGHOGgk zY z4{a+8Z!7mmirOCSw>UY_r}a`TYd%a5zn9>AbW+J5Z|{FqV>E_FaZaYTl|(eP@Ay9X zf4&hRuSa;F)0^Iq&@;C04R1`q95vy2o~Sv`3SX0%L*^Om;XO`;gTnircn?-%y*eJZ zBpZ^C-2=LCI7%%C0l;%PN=1?22J@_|fywR~gxqmo$`&l`OAnt05=BEM^$t3GSJilR zQ4#lX&-N9V*AUH}Ay%uz#)eQ8lHa=?o3KiIlw}j*{=9|JE93s8!trjvYr;eQ(eq05 z8{=2S&8h rui+Vc}M&SALA$Ou@i~zV!|`R(i&|i*&MA{{Wd2q zhQTXRG9z4*Di1Ys_2P4bUt5V7>P;8Wy6$?aF>CihjV&N!PSqqSOiG`W4e=R0kDi(1 z$xe|dV)yj<;5~64uO=9(_GSXZ>7&Dk4Y!&8c707LsA7Wa1H6)EyV~szskxb%)KS|0 zIRvOEzjY9_WNYAI`xwh9<6X_C+ot3dmF@MLXcl2f-bH}VPV~nU;avnL-@_-HA#!5p z(UUEbkLjcD4H7C_W3S{2wJ#{bNfEtaYWT}j6vMp38uyCnBO471Og^oTn7*gQbzpom z+CBJda5JlBz=8AVwHiE(we<{e4KcIPm`C-=1v?I*zfp_^HVj1xc!pdlwq~G-t|=q> z-YZ6BBL`d92HM-0&LS8a?4k%^pHQ0s2=cf@48 cRb%GYCIbX$Cd`8pjG4WfubKV z*B+Smo8tK#(FlBU{ZiaOIaO~QqU7%!dMuztMsL82C@PLoqglse>84rmo~(|d;1oOh zWCqzZ8&H0BoVz{v8YAN9F`-+GdE3SsQ> YYYV`R1V~Pv7|dBgOlO@akKuhQ&iA z7XO4mqSWT?$4=JtlOeIov6(Y$m{8KfTIJchZND6me!cd>J;=Z(T;ry?^;@)?H~Lh% z*t@i`lPh2Bd*^v682r2OI7x=MpVom>?T-iCzcFFvB3n`im-a?Dg{eHJuax_OJ{_i3 zlak{1;?I@V;=zAeEajEh^M6fooH2BDX@K{=qxWP{n~P PNM?52klIe9UB2{r}a*uzFNIg`jqmk z-?Pd$eL7n4RKzHJ3L$#0cjXY?zvZ=)X1#K7h&%UIV^tN_H8pGcK}YQ-%`)BG;mhsq zu j@jd{(j??o4RFQ9b!wVn9DlXejc?h~(t4-|eA=P| zSy`BN2JXd{@8ykgfoc{3lYRB7gIXtCWN+J`S8qM71gKW|b+BgbS2MEw^eN3PpdZlL zz|;H~MKd;(ObFOV$viZSq3_8T-WY{ Sa{ePeKDQPb_jPA0Z(+sVYX zJ+W g1HyB9wxE9Lw6RumqkCOKtJ z1+$aQba<~ri&inijh*vIzmC{6A)hSr3ZMNJu!7l5etWXW-fqct@VM5UrZ&;FQGqPm zsX!u{srR+!Pfw{j1cG)N73mY5$Bh1l5c*VjKE>U?M5nrqlhntaox0pXhDP4UIOoJT z%Mtc8D=PjV-Dl!Wcgv~M=D_A+*&w~ne1=>tW5$7(3#A#tM8xp9oN-L@+}b!aKOFTA z;SVRG(&rJzJ_z^uXb!MAr=v{X8&EixcC^XT7Gka>DwjIHD PkyPOF@#2yK*+z^ ze%(`Fi8>~@n`kI__B}niBP0_u !Kz7uR|sBzM-mdc}4C#3xiKQ1fPl!LR#f#wTcjfLYX?1iI@%Ra^4jTK$d;F zi|A^J_GDKJiUtd@cXd}fb|U>jav!ZF;l~{^ZJ*?a=l>$Zy_n-~!h!H08}R+iGCD{r zl;V!B*Ft$1J`AB?1et)^+2k_i9-5)6yW6SW(62(v3ilq_;dRS6^?NUYv?~89s$h|K zkkU5AOV}jB_^VoxCXyFl|6a@6wl^KK*f)}vAn9U7?A{0^H0;v*i&-`Hbe -NO8X_@ zyB{;_Pm75f=GN^RE)&UZp~#-=_O}7o90#4PXe1F%xdfW@m{Lh3 vK}e_}*&?jxU?ZGJXD9A}>wEg&M1h}7CIkolfKDNNKJ!3h_p zht+B2E$suxq7(tYOweh7f%HKs>?=lC4C2)_+h(TXS%N;bq*^q#ze5?tP%~1wk4O9^ z7vZWLQAg(K5Tp8k4UMZ8J(VmFT_w7##iy|{Plg7N(}e|6-DoTm6Z2pIpP7yO znD-H!&{Nm)eYLd)14FpY$yb-Kn-+d$=X`$!-+((o0dr`7TH%oI$EFDU^2ZRB?c&cU z?7-)s6mtrciz53}-hg#Ve(SEsDw5U0?c9b8!Z-QKH(^s>_%Q#EAT+EW)O^r2uKHja zUyAfT0~(ezXH{2v2J#*U%wPKRl?AC@zy!l|)EQY>=d^b}c0pGB_8_;s%A66^-h<0E zeA`l9w}FI;J_2mnTob#aQ&_JMg2LGT#~vqY|3bCI(HHDAQX%K41S$TXN8N-3wi4vh zqSP||S}d9Z51+jk$=vgE&3ij9r40)uj#xz~WN#J+f3kpj)wk5C2!t1|zN$(}AgRlX zePTyP8EVsP P;!URRJZo|)aZ)$bDPj(1Ow zg*Wat4e+tmnO`+-bFaY9IbA}^>S)zQ4~6F`*1{{qZD#D2~nLnFV?O*v8)^%*@Tx znCVQ Q Kd&FJN0B)i#4p8*i#9=A0)l`J zHn<0FCjra{QQdBno?pXj7iqmi&4!byV{e>k{(a53lfFlvjFbFrJVQQ-S*3 ~HIy0TaJPdupbi<~-^rhgG-bsUKUT^7K)sdya&iKCLstei^CA_J zxo_AWMTvO{&3IhQY8PjD*e6fa)C%EFH65Ubm3P5)IqQ+w#)c6zEBNdjG(c6Nag&tr zx$^len(%tuu5O)EYX}01^HB9BEa&@-z%O@kZ<&2SZ+=)m7D*VfJ=>pjIfXn&{!*$z z^V%WJL@cILTD$-_W~!@VT(+U@tv`&2<=KP#WBF0i8n)F`?bM=*Q)Za|s(y6Qx%N7| z@I}uR$kie7WLf;K7&P;A5q5Z1CxGDkMrX~sA+UrStu9ldOcdjoVu!g4SP9Iv4^d-0 zsgpFFPHR@02{@0F5G%g>L!=nZyP1X%QUdDCu-&i4lmT{S*bmC%*Yh}Hb36RgbtpKB zzQwU{G<#ga{~!$5fi(h?7S?$BV;vIdgXB@vA6&({gZf}jXZHiv;*Fz@Ccq>bT{9wV zh!b8y^tGw7_|e+V{DfK7h-1uj_Lx5Isw1rcqagOABylpMR BR7`nasWA8Q3tq(fm lJ~ogG+XZMhO`T1zI)Osw=6gRmRf;)nv-@%>92ZtO^F+-Il;S) zghcn$uCV5jPvmdO(AN4LC%hhjC* R5MkdpCQoT)mfX?Po2^?LfVHpPF1Gge?Nlc&=L5ShKag8Jv}tjBo*pj_rN4rHo&{aG-;r?r)L9uUC2(u zdf?YWD0pFs-jm%O_2z3A8hRuseIA!6h )q6bL#FeNB5d4y-uC~`WHzYKbiO8PWKB2jm zocleWJOukmm+A7m<}_luB@^*52lCahH->V|JGK8{HK!S<|AU2cd`8oi={kJHE*JVz z=cmcZj;cXhgs4z{dv$56^;>+kunqCLHHNPWYOtQbq7cT1b6*na&rI@z*;^ZFFCxFf z+ecl>?HlT=-@i`7-BcLPoW2DZ1FpbQWIGWq0X4i29CMK@-kb}qKHE&}@p}Vk^ZoP^ z {en*k6~e4q$Bf^Itb2iw7sk5F2@qfgE@Yr`yLO&9Wlu=%VOY@ocacnnmjMf zKkT0&Uf&8#JBC;j{>p%D6oP;~B7SZqe=L1LxnmCHo(Xu4g=d0nheSl9ek0l^J3aa( zvo## Ko$ rMHH(2&<6*`UUgyuP8u~EM zx(^3{iWO-c+D5p@TC^eGpNCiOWU>v_#jl{R3^e5B0~$%YSm;gc|Bg_Ak?C)d d2q*jR0Z$sv4-Y5(6Q{=YjDNp_>9yF2j~}uR{@w$;O0`YH85_0i8u(6xe4)}1 zQ*<+c@G7HM9{u3&_`}*cd-$9*V(%V0S+fZ;6wWpZ63t4gK`X~0Z%a`K %mn%}iELa*p&!ML}z^g00)-KMM`>(-ZM zSw|RKS~Ayj7BtFIvtYmwU$5P-%YWmQ)T3f}H*t_=!zYSvLO=4d1UpK=s>_Od_@41m z$Et*^-9$IR0{En8@|0eZsKW@RL&f`s7$>aTx88-Eu^QHm)tl=Bw2+Zlcj15nJZsuA zcyfI*yN#C;dp7j0OgA=Y2~|I0xIsRV?p$rFsEQ1<`<|%e;9&Lip^M}n26SML53d;z zb1qb=BC3#VsPteu$J5&_ZR5S(I;^D;(SgvFyNS)ubA3OPe5so`_lHj_nR0;fyc6?r z)ihsonsy_aPP}s^k$w~W gLVRV|^ii zeess5dF6LFtDco7x>?kP!`l_HwFa{iOdiElr4I0e0jh0xv<;vG2!0om^&ro%FJIph zU^(0>Xj@|7$Gh8Fhe&9*%rdW(UXlYlNmA>QQy@ICO{a`dz7skO^FtMMg#@fR%mj=$ zFla->DTLoXq)jeJ=-J` !s}Co68&+iz zd=!Bc9uybh8@DpGd5m_h-3b7;?;kPUJf{T5;~5%)G=_4y6NH<)2WmN3-K>sk63)ZR zaW(i1FqtVS7}9{S6_Umu6H9XwsT2m5Q)Rm5w%55RSqlg0#u%t(mYvdV#s}1Qqpg|4 zR|_O*Lwu}jdghsM^k&MxZ_!~XGE|hV#0u|jdu;FbtaAIebAZ3TA8*GOt*`JIOOyG9 z%!yozLFBMUvMl^x`-5WvJB=%vKJJHuJM^}_H-x}?Bk2JfJ1PiPus1Pxy25HPPY^ zzwlmNpxFWZDiiMGIl#{i8|w& +K;@G>coOCtNdkm`fuy(7dcaEy;;hg z+5RMk1rx>(xq$bKSv>zAB&YhS*SLt|w0rG!eVb*jr%jIncopG{SmRjW$oal$4;w zChv>&gZ%dFMZB74b!Y81T^vsvkOWvSlksl~##f`&+PADU0I0Gp`fAz}`c;aw)cfb2 z;r )DwdH&r_##ZiMUcTI^eSJf?LUYsQHV^~;|>7#VxtvLC+qx CJ+KNd>MLmWUz)DAoj zq6Gt0 r3-Qa zW3ZwVvCmCYGGVG3Rp>DsbS8}*b42BrYSJMsUfs?NS1mv1VH_jztE&`tls9_L=%L*9 z5~t8~i30RijQh3k`jVL=o`-VnCKh i! znWD{5SPS$OPt9%O`%cG}C6=>xB%qU&X5F0NX5{shg~XNXYpv_6g{|p;a6f vG@=hO3nJw!i9c_i^Y8XVliHHeoRG zuQIO?52P ?YU24YbN|^k$rj1NQon?76+2H|C3oY=@*IFPoUv3DfnwQmV7rrWE zS+KCc$u+yeIXly*tXCIauinBx<^O%~-Rb|mSNJlgVjnv9=vx9=s|G&kYCkU%m?HLG zYB>Wq+)J7SGSz-%!}wlwx^tCadZ~wmAufTF#U_QOzGkqnv))_rA;4$LJT%a*Fc|En z;N+}bWVf+R@2ss&&d&0i*o(adMss^nOmOcY<$)cft*v&BD`IqJRSBbw&?F(Xnf%yN z`CGZt6j(_Sxb48+c7hwG`|$8LK|;nQy=C7FbJ=FNiq9A9+SV80?2!^Ex(%Ox1WpJg zhwPy5Y2kAK_cT|lTSibptT175G%v`q)9lV3Hh0`~+*tMYuJNlfhW)-dTAj~2??O)< zAM`ryZ`xpzk$2M5{Pa9~5)I-dLCm@w(MY zzQ=&!xEX#Hj0X`FjzAcUA%>)YX`6@J#paOC-c)YdCrdfSlLm!OU+)e=tEjUF|Mx?y zs0&SBMWZ1i7X*p7Cwwh-3CoOABe+etG3y*qwofYrT1+UfJhl^resJrDAsC-_Uc^aC z)Tgp6K1O?$!}HlX ZngK&<&E;w>p;itNv`cM2sHF4a1^Tr8nFYy8!5kG7|2I zX{le-bgw#SKp4AFGfGz|iC;>MvS(11n2ugK4;5S;v;VQYadbVk{UPEp+4m4%FX5zX zrGi4HALZQ8O#}My>iKf>e!qi2;}}Uei7boM=|=Tw=)9`5`#gqV=*my-%-ePMg?W1u zw5m6z^ XJCt5P@wLyU$yYDnSOE_Jz=QhOiLq>ch1?lYq*s)WkevRu9X0*LpSMYLQv Y7 JO#JdFYAm*A7*ewjc5RHx2H#oAD2CS=Tu6Rl0(^5AbcC ;i*fpjbrcw(Sw#luRbZ**hrRyoaU^OETF8Fxi^O5_<<0N) aTlm4((aXmWN zF#sHj7+KGn#PqV@$WqDf_7Z*l(GT%49|*yf7A-=uGzq^ h-!h;n3z^M9LQ{>JRcS?EjGje?IEqE-5IyV62+7e<1d53;j#6FjJ#)a= zQjsQYPKh+$JTFW@QY1%6V$VM YDO-xE*&wr>)@IdD3FI(nmQ;?aKQK*g&7FB)7 zEU~~)U%UwwM+-`ipQFz( UNSV;oE*F3Qxh<=9UB8d W>jTyvkaUNOC*m; z
@EayfcVD{nXzvG) zJtW`(U`$4B-pQ% u-$)7S-NJUa10V>JSm<~Cj4@REpapH1RN#g4JSI+It)oN|> z5b=ChaB=-1-TsfB*2&Qw)ic%x6BYgb336r9o#SFRH<@@-?oqV$b=Wz^W{&=CjFM$% zV>y-XD=>aKjH(PmQrT}cHREGA+&yKTjbf3^JO990uO;b9bi0eH>QpW5>L){Y8aRb# zD+gTngk~QN*QTq6pbXS?U^dVCT?)_oS>b=^6^;HMO7TIkle&Pbbcx20JI9Y*lmc41 zrQJ%ITq$Qtr0*J$tpL=X9BPrda>@JVq^gosUK}F-T#EZ2P7=`nBLmu5;Q!a70biEP z `TFFzL(^e!sqO1Mioyc0W z<_AebU(G2i(u*kEq5YpY36{9TNN-OYuc8 GT1<+Rq@LgZ$F0mn=_x7d z`SX9vPL(9LcUcDX1m&VDsbb@Q1QaM&6_NICQk9M{yQ`Ac!p$Rmo`oCEIZ?++^dA9= zT%Xp)%uxzxmxATh!s%j#&v8bUQTmv)q+Xd~NFoI$nwT7B_B@_US`w^-JDhkC&GRRc z&A4=;&44*zIqIn_CR^yNQF{9}-2@6^tFZh 17K4ECA#zdcFlkb;i$2YI7v>bN}XYbjd}`SENJCwfs$hr-bisWAN{J)}$vVJjX{ z{g_#Nwk*|%J})#U;aFyCffjPlSf9taM2iZ1LR(&*JeafSc~bR6wVbZaE${P+GhJj| zBLDuoZFCy`j{hegs|R*S2wpd@HO&qAz{UV-)q~+$Fmw8k#Ly;EEY3?_oVVeROF4K8 zHfb1c%u-Rs0v$NKzC1r$ip6p$h12d^>^49yksg#E1SW7hccKYkcX(c^b?h5*kUaGl zMq{b*sh`rF1QenGjU86I+tuQmjD`ZM16#}*dxki~^S9rcmf)|1{q# V8JFn0}xg!YKB?~B( zu%crds$5~OY~ot6;;MeoM*}butIY%hq8}nO=fFaVm!0p^!WZ0d%nwY+LALkyrPOp0 zZ*M>5%ixhc=2fWsKFB(P!y{ty?uLiP>YgQ`i)-6FwayB?jIhE(=l(`u+{t>17B}=1 zcR1JiGlqv4c!x0IgapDX{qbmJy+6R}#3>$9^U=5A)!X?H*r2?pjF?duR=teAS0y z&3m_0WihYjabr)xO9azR{fP5zP)zp#vy@LG&FSdaz*`139O&90vv06*fV-cIGIT|y zo{v9*G}l}`DiyTecLR&dF@#XbSOjHv4|5((-@B0Y $95Sx`W%X8)MHhDPV zsPk!V*rm5Vxjwms@k32(k^wZ_)49Uw+JVN|P4;0ROX0DQ^Mhykinfj&TG(57duI;L z+Uh0ONZk6w**P0vS|wWI_s}Wj&(nBsS*{VXv-9#mqKE~Wi=ZXkmvCjYQ^Ccpi*D|w z`zHFG6Bn`R^sa_Vh|E~C8Y )O*DrsHhq*&I(>Wi8WW`|{Vt(gkl4B)d3d}&9vCf~~WpoF8ydYyr z`8I?j?a 15Ro=GNsz&8?W^1JgXPJq&r|9wrjDZK_4y;a zH>sFCFikjExx-07;Pw0dmvz>(YD%^ot#`V??0AkJl%Hq$GVzq *=kc zsFC&Nah1kKOLxL#CKK%BkyaTt#N!`9q-r*9jc7=EsLxE3gUrvbjD37CFnqDVKm}~1 z>pns2_Pbq%G<7fy@U^I*V6kUmK54BW>YLi@obUeb;o(typR=1$K9l`KLEfWmb~V7z zl2k&S#oc6j6lQwHOqL~(Q1U7B!O;99uJJ+9{3MT+^CaOUyNIoia+RbCOX_4e=>V0l zaZLTss*S{%gKS9n>2!GWe)!dCuPf3yfSEdn{&NQ$7A| zZZB+E*ubjJOm=TO!}W87e;0neaXZ^M`qFS~)(KG}pJxbAAD)pb2xOKqnPsf-X0CGw z5Im3V=~?!bBLpfa-oQXa%Es>*;#S_BRC2TZcw||jF7bZ&iL})d6xgtuzgzalTGn&& z+NE={poG-ZG?e`Wmu27fVG!sDLY>a?-SYNGUxJrwBA=Wo8X_3?!LQ?Oqvx-#>MPWr zX* kYN?y!;FVl>rZcVV0jslaL&lO@`4OW;wUZ6{S zBm_*ln>W7TIr(tLkYV&}YdV|RmPxpaj{u1rPcyhSNGPZ=YqTtqoZ9Pw%|VLauKG2U zh^cIUfVu5A0a5#}1Uu<#{A?U?G&Hc#;Y5F$3SlHQ6qU~A#T1J;aSIAap6%EQn5|Ic z*qABi9xV!}hYvH;?k6~zyD9xtqM2!0oxeFdy+;U$(hS~wfcx9m)6-oq$5WG;oc3nh z@Qp*(-~Ne{wYXWMl*(UwarDLw={_P*8ihAQZ$5jUh??Eb1(6@U@zbVJ?+MeUodb*W zYxd@Pe%2N0|Ndfn*D_sNNP9)zI@60-p--5z)ONE?A4(d qg zRPiJ41)J;k#@e51ZxO5?6?|lNdf1A&Al~x*NEQ6KKFVV{0ZH^*s!W(!>aAUU$EtC$ zdpug9oF)jleNs2CEL!AAe?JZxP(b+#TvC57Tj@w+S_ZPN7-+#H82?R1r>(7mk(Y%> zl$M3h{Oa3mN19CWdkb4i>KP0f!Wr!C3xUYy;%2fKPs-~Xqe4F%CjB0VXm|X?KZaAM zuY6BZJ#JfhiENaP88u|ulOpm;#?vq%+(9Lr3~jB^&~Nk9)b?tNxx-=^G_kq)e4X-N z+9$6D0;^>(YVQRXLzRb+h?jTIzkA1F+l8yG{$`ryDo_cj1*`EH2L(OO *QHOYW5k)^PSh6F>1wpoT3YKI?6r@tH#fbxL)M8iTiQaKz0GOisxy1h z1zec%V#dXL)y(lQGeNLn1G%08HuMQt$9=&$#%%heBaL60^E&$XDJ61p@KBNK41J#G zO(xc7Sra3pOvasMaLfQN3o%GB8`?9w)bzjRGG)W#o>m#LIzt 3Z7hI)kq6ds|e=Dp-#9*i{e zKYv_wZyJtaIuf}+J`Wl|0S0Zy^32u&c+&ozHuY`w9UVOQ-JCfb0zeP)qDXLUYlo=A zz1gf^#ZW)YR;9Bj*~2dqTNSbd-1JAA&Js<+W*q2$eP1iY@=iJBtT+|dFLTmN|0U&M z;Ttrg8rQ5d8l7cPuZhN_?~6jt3b!QelHRZUQtcG_rZ%BiwqyN_Jo&j(fsIOgP+FVD zVs9dHc^tV*4sxTBg7hpMnZ`j26Tu-mK{N6mGbJsXg_+gZOXMo?{AUi5VTOE~m)Ovl z>X3fjAx3o 2HzsqIy~`JQ~D|iqDUAOG4W4j#-Vyu5g(!@8tOr5n7e|h zpT=;+qRDZRe^f~O>(z^`;+5B^i07IzR3#m4lH-(qnrEVoOoMwOuMvf=(h}RflFn18 zPOu%+Vo$v~8`GkVvK`D|PyI8S#G0Y?ry?9QBl#!eCwB-NQ^x;e^c5ep)NP#YfHvCf zPorF ~xk8m*nFg1f3}=QET^Ub@{5RU*8pTjOt8fiuhG*!%aYPX}d61V9+b7Tu z)Ipc!6lpIoA_$&o6DFnKg^+bV=nf%g`^&d_apcyBQN@BZ5gOe0-4xU^MEE1Qs> z2WP+iA^*2D~}(Uj?I+)! t*B|4Zbywn-SV SEF*X=AK=(_dsa*pxew zzi75g8r~#5>(=x1T*X@$dtkP`q$_W$0F69fa$pQ1x+y=X{QW$3*3P;GRCkEY&56x> z;Sk~)^EbhZ_0v{n1z4EWXhQ2N-XjFB6E&+V+#)l*YpD6m5t?jO&Z|-$I8#&I%X`SB zK7D2Fb}v5Ek0!0}G`cTbVPmdPVi >4+{O_muyD6`r?vOKiQ^YeA_I1jGRPX$c^VpY`yuZk=7yLwo6 zbkuwgau44q4&S2VR+^V-NNfGmIJJI#=S43w`M17#XyUA#^|tE_s1>@Jxz|B)&vvIk zp7&{MMhHx%Ul{4nY!~U=9$!v;zJepUW^-rGq{k$ote%STBN`FEI 4CtNV5icD-JqG#?vhO`Wndo#gM& zt_{;d;jVvj2fcns4I~UEBWCtcvHD$4qV3!zil7ERR*q#wsEAO8Q_jdp-AB;$`$K%F z$|EVj5SF`ENE9}a?$syFF@^huOIW&5RZ^|$lg4y6Xa5#xRpub9_mu((V2i6(X#n)u zsDXSTocxhEw?ZC{*D^}Pt2|%*xb*cD6-m|5U_`==R=oE8E!u82l9eWMuC&GF5@2@? zf3A|G$mcgi@^~AP^s|(NQg0mmaeqMkC6m<%9SP$FC+k*HuH`aTu?}?8K?{t-k&(N` zKk-z6;d`B=Yj63EC+arygnob Oy;ZPlD|!bB<;(&M4tzx zh}?;h$2qa)8FooyZjQeHz&W#GHIKvf?`l_fs5OpJhkp;laJx6ZlpodCr_{qs{_aWY zar2yiZNa&rRUsi&BcY!N2yyl<%0r)9X-@k@_o^FA-gvtG-tT};AJ^+LdC28f+Uyja z>F01_9}}{sCwtFr%!iJE%|GgvpGPYOevwNY@osK6rKBRRp4ol0vNUJ=^z@h)X-K%l zT6o8w=SR?+x?t61+5AgKe+0b^l^L!FFaCIjukFWf#CVux7DPj{t7&J6tXFM%zKRbg z69>mEBLl#uoIfQ|vxTVM)yebiP%k;+DiM~2Q4DH$2;zNcSU)0jH#crqkQlI&Tra@w zuXG+g9&MTaHsNfBHhhvwG5v>r>RQt<`mgr2(K{0mrj2LyH+snXKEsT*_~g0$n}hXs zof2!jz18YyMBy3iqA@Bv1zqx5h<+&Emk1Dy+bM2*bw`qZgTcy6xVA)GR$3+#E&iN< zRozb$J0%?(BRxkx%u~FxR9tp)GQ{Z{Ew3Gvjo!cpI)zK4$~|t}7bD3#{PXCh8gJwp zpV|ptot0~9ij5)a_rscUyN*nyzR04fKjrxKW8m+d9(oJA9gOVG_?qtqow#!SS-Ulq z6BoFBkNATgV$3mwQ0)_W>CkI%Z0e3x$CTJ}E?SQ1$gHFc9%`o)@1}oAp%i}XJ4R&( zquTm8ZQDo9u;{<1KlsU#=ZU73^aiQ|mX>ItOXZ|HN6uF}K4+UEhVcq^qwADV_0E)= zrmej^ApNw*2Y!vhL6N)R5KWMC7~BvgkNA`yLUTfxnai{h7OUmg;FYQzO O=KV4z?E_C*6OVF%Iik(XuS4-L_w0* zm+TRulKvAo9IXeKsa$blol=$Q7zkO>8`MZRXu5$>*SVL*wV&xMT`O7FAP*dk>B&k;WFtsI+>UL)VS^lyQ97ODf! +^u3t0{9CgkH@gUngA zWLGX#+wq-aaMWiWFGdYDq;LJ(k{ppj4fl2y1Dk3YVnCAIdTpbgg6$0C#U*yES&ToN z;DaMjKPt>1zJXMI23p>1oQ}d;ByW?NE0%TK+wxv%*B@*abFGprkTDRWSpCGR!3=Sd z4KdB-HRfms{{*&CDW{_VIfMiPgnH1qg!uf7vcS+$U5FO}!oQ4(@3z*QaDl5jIv0O3 z)$4}c`1A_IZ2gmgcM@j?WpXm9x1TK9O-^?#@2V)$`IL!@_YFg|b0B%;2b=*W5DrbB z`v8pP%=@UFz}sHI!);2LP!nYjSe%h-|CvOxLu0A&1HedI{BO!{+ESyQqUv~h*k7Yl zxd94LzXRhi+RsAZS(LtM{0ts3Xx(%QaC4djGn%7& D3~zj8c!Dz7&>rzenoxw^$s*s4(k z`~jrkk52^5JTh1infVFd!joo=;VdVZuP)%*lqFA+5b|dp>J$erv*%ElA%sAqu>?ZI za18;~;*0D$1%iS{0|nEeT5-|Y=o^0_*4a3 L_s> z#QM89h`BzdMT{^5o(rNnLx_RH&XhI@A&$Jh+)HlU6`spt8)ySLz4)@bYfchkIyy%W zL3_D@@$z~d4EYZ8tWf8T8odi~o#+d}az`0Luo#00ak+>BW+`$bu;M+{$s%fbQ-G4| znuUUkk)e{1Fxz^n8s^cc6YN2O>Ox!DO%_dIbtg@N{oKdn&+&`wRRD))8RWbJ>29oY zS63&CRh*zBxx (Sq{4^@Sok(ozrTXd`Y0GyJ3s5)1%25B4n z5whH7ZF0AZV7^BQFONz1=mq0}g@dhsr4t@0T&0ZKa||WT;>E>#bcJD;ZkVbEsZ$=O zur2{}H3|g7SDIZ9{g|5uKN~-aE)0H8T#0ht1?oraJ?%y6|2 tfXJ#BN@|+?4O)>KTa5d8)kiKg51Pof%1{ELdHQ96T^4%{Y`d zSnMidBtdu3nyvgdJ70UGhUK>kz%Re$lBQH6UXFqemS1~#*)HI4{VydLJ!!GZbzc3m zWC(5N<}R+U$g2BA>KcF2Q)8d0Hl5?c45Uvz6a#&LJK(cB{+c-aAI*k|!WMdvvVzRY zE@e@yx6onyai5S7x{P+9@V^kP%&xi>IeN|>Bu >z9=eQ1@1$ zS2^fZ^(K@Ss(Qh&CcmyyE-skf+LJ*~_~ %QwqhI)ORG1B;Iu2)h0d^`GFlBBQ=jfjmQTlzLVo?oY4BSNosDU{au z4Vql3hbdNJA3F^Xkg^n9FrOGyrCn6lbO(REn p%Q70X?W1$N+Uqh>3St z$*`WF+?S9H-e`xG24sMNNKmdITh+%?=%Jqr_w){S!4wAcZPLY`8b;~XKV?g2N6s;*2vG3 zXMP&fL~PxEt;U=%joLqwaN~N7=EskC*J;4}h@7^r&|c}@kk0!h?{INTjlaBSWnx!G zIq(44CBqCXz-8jS(hXepwaHOWTFFE=IGe$DcSY28i-w2vOG>>52=zo~pWh?g=jG#B zj#Y|QDZ(M!9Bl_PV`yWURWaFP8;Of<{}fY$RD$OzWhIfM5de-N9g)v5XV(kvIab g z+tl(FyiF{kHl?UGS{(&H+s*Kjjs#5g<~o1gC!@_Xg!jF2q-FJu JITKnG3y@n?9F6KuckX63_t5n16#lues>w1>L06q48SqQ zfxe!VAG#W{ZNOrLS-nj&;}{;DcrHlsiT*b5E`lqmX~D=;DV2}+dPNpgPS?1-Io=&R z(W|1ta;hSre6(ZaB&3{mS5zg_i{SWbtPcu$=z^hK5c3{9vl)y~pFQU_77Khwx`wP~ zp-|qt(u3mIQ!6L>#-a?Ir`t2nuu)K!`*j%v91M$ropXH$V->)TlK#xm%890)*&!zX zb_|F5uFrW)OPF9+h)|`zqs59Uyi4V$IN}}XS57H!Nh)7JY2z6f+wk)LtdxE1?Eq`v zQYaAtt6Nm9^RlT8a))X={IPtoHAcx<>J}VZ;XUy8f>8bTQL@pcoA~eL=}h02*E8T( z@T8$vvXNrxBvqa_4i4ARgy&OgY%-&+;|ZqqtFn#s-z(-{ch4CfCW77Opy|i8cQ}65 zf9Nmdj1m6c!VO^Fx}rgCML{T9kxw0u-7BY0Bo;BYi@v6NJ^HG>2UgSP-%Y^b$>3Ki zEY8^M^ia_CP#|neBP~DPUqL}lnLOhs?l&9^D-hl=_ZWL^UbaQF_t*jD9HO-q^6@CC zI5gGLGi gZ-Yg#Hl!R=8>*6J<_3Njs;#8#ZP7Px zRkz^lJe4yMrdc^Id@|@bu+#Wdbh5eswFR#>O5}472KH|vI9&@AgJkRoT{E>0GoCaJ z(62?3Z6;Jnt`PA_cqE0g(xP-uWaK)?)RTOXX~p;Kv1J7ti=D?t2ns(38TKbJ6}dVu zxUR>m!)y8>d9h{STVu;DTx$sgl#CRdSol<}C;ZA4@m~Or7Cf(9ER_jfA=&$D7<@OU zD4iFqCI+B1^GnVBAyly(j0=D2Nhm(#ZBT9$O~`_AH>a*Ay4Sb19+E8}7x xnLSVyY zn7fi>P<%d4IO-LYkhA6BWz?{+XBX0dqwEoaQ G2 b}%#gOW4_W6xxUdsT$V|m#733#JH#5)m!6GzCrprj?lC{ zcyB^hApPJs|GbtZy-&k-;AffpYHu#E#b2<`8>v;;51Smb4Xp(SXPZ; MHE;ddeyf~Ge{SF$4*WJ&?ZmKr)zk+*Oge!y&jg~kOcZ)v2LPg_(z;ACF zk}u>KtjPqHZPkVP1K8T!pEfp@Z-`j#RmSo;`XZC!<4@+(AH0 m0y{dU zO!yTyLf8*h{05=A8n??dx?V*?w&h2M8TrV+@`T%#v@V|vGj>r)nF2V_NKm*!OKMTg zV>VM1FGn-SUH)K-6taBG!jfoE9Cex&k*H}kOp9Wh1C?bRrtK3d6ZAi(+G5Q5`h@vo z95n%bmo8z*KV<^EsQL#IK~M%Q+W51U_Oc-Q>spOT*X(`4m6Q7yOKQ-MJW+Fxjd#XJ{+ppk{SvT#7w}~ez#rIKv41Q4 zPHPWiJAt9E>#=4IgLD`jzj1-(zwIRW^|Tch<~}$3ReIKLeX;ycm8g^*vHCmTK8r`} zUr03H>$Ckt?|Gx35dyo0kflh2`K--On{9NV1V(*igUDbn`| rdA_ncS&;Iu(DN9(6rJD`UkCrY-43HODhq=eXy z8%y^9@j)ZZ-WZ>sC-30DSYEp21iwEkRHin?c32l`r4mx5>_X0`P(q9XmQpwrGJSf8 zgO|k2!9gr%XSg-w20xsWP6~IESH&UuhD)ZhE_*8d0Uw)6+fgw*o$*6^icq^BEur&F zkKN!Pq+>QYqTKT7_ft_ZZJ%1t9zYM6il?Ld{Ah8J1jO{n5^e-IV;CG0HDpWzeH_h5 zpw~`%Nf^h`f-W%?e0U%IBauxVCIb9}<0PP797Z|hb&@K)s#tA^zx0QeI6X7+)sbhM z$m>W?d3G^CB6%G@#p22_vE#@yBjp&-J|LH0KrS0VE_86&X776TjyA&k80lT?@=m#I z4spNJLh=&$4|g^@%f{9jR