From 44706167751d5b37271cbfced5aec32c991e56a8 Mon Sep 17 00:00:00 2001 From: Maurus Decimus <11444311+mdecimus@users.noreply.github.com> Date: Mon, 20 Apr 2026 15:02:57 +0200 Subject: [PATCH] Initial commit --- .env.development | 8 + .github/workflows/build.yml | 40 + .gitignore | 46 +- .prettierrc | 5 + README.md | 151 +- build.sh | 9 + eslint.config.js | 31 + img/logo-red.svg | 25 + img/screencast-setup.gif | Bin 0 -> 265840 bytes index.html | 17 + package-lock.json | 7160 +++++++++++++++++ package.json | 69 + public/favicon.svg | Bin 0 -> 15406 bytes public/icons.svg | 24 + src/App.tsx | 18 + src/components/bootstrap/BootstrapWizard.tsx | 532 ++ src/components/common/EnterpriseUpsell.tsx | 47 + src/components/common/GlobalSearch.tsx | 240 + src/components/common/Logo.tsx | 81 + src/components/common/ObjectPicker.tsx | 135 + .../expression/ExpressionEditor.tsx | 175 + src/components/forms/DynamicForm.tsx | 1126 +++ src/components/forms/FieldWidget.tsx | 2331 ++++++ src/components/forms/FormEditionContext.ts | 18 + src/components/forms/OtpAuthField.tsx | 233 + src/components/layout/ErrorBoundary.tsx | 62 + src/components/layout/MainContent.tsx | 98 + src/components/layout/ProtectedRoute.tsx | 19 + src/components/layout/Sidebar.tsx | 354 + src/components/layout/TopBar.tsx | 155 + src/components/lists/DynamicList.tsx | 1356 ++++ src/components/ui/alert-dialog.tsx | 110 + src/components/ui/badge.tsx | 35 + src/components/ui/button.tsx | 52 + src/components/ui/card.tsx | 49 + src/components/ui/chart.tsx | 60 + src/components/ui/checkbox.tsx | 32 + src/components/ui/collapsible.tsx | 15 + src/components/ui/combobox.tsx | 142 + src/components/ui/command.tsx | 131 + src/components/ui/dialog.tsx | 101 + src/components/ui/dropdown-menu.tsx | 186 + src/components/ui/input.tsx | 28 + src/components/ui/label.tsx | 23 + src/components/ui/popover.tsx | 37 + src/components/ui/scroll-area.tsx | 44 + src/components/ui/select.tsx | 148 + src/components/ui/separator.tsx | 26 + src/components/ui/switch.tsx | 33 + src/components/ui/tabs.tsx | 59 + src/components/ui/textarea.tsx | 27 + src/components/ui/toast.tsx | 94 + src/components/ui/toaster.tsx | 30 + src/components/ui/tooltip.tsx | 36 + src/components/views/DynamicView.tsx | 543 ++ src/components/views/DynamicViewPage.tsx | 111 + src/features/actions/ActionPage.tsx | 483 ++ .../dashboard/components/DashboardChart.tsx | 252 + .../dashboard/components/DashboardView.tsx | 157 + .../dashboard/components/PeriodSelector.tsx | 119 + .../dashboard/components/StatCard.tsx | 122 + src/features/dashboard/helpers.ts | 246 + .../dashboard/stores/dashboardStore.ts | 30 + .../dashboard/stores/historyMetricsStore.ts | 109 + .../dashboard/stores/liveMetricsStore.ts | 169 + src/features/dashboard/types/metrics.ts | 48 + src/features/dashboard/types/schema.ts | 44 + .../tracing/components/LiveTracingPage.tsx | 351 + .../tracing/components/TraceDetailView.tsx | 208 + .../tracing/components/TraceTimeline.tsx | 348 + src/features/tracing/types.ts | 33 + .../troubleshoot/DeliveryTracePage.tsx | 678 ++ src/features/troubleshoot/types.ts | 73 + src/hooks/use-toast.ts | 187 + src/hooks/usePermissions.ts | 67 + src/i18n/en.json | 364 + src/i18n/index.ts | 27 + src/index.css | 141 + src/lib/basePath.ts | 15 + src/lib/debug.ts | 108 + src/lib/durationFormat.test.ts | 229 + src/lib/durationFormat.ts | 96 + src/lib/jmapErrors.ts | 48 + src/lib/jmapPatch.test.ts | 513 ++ src/lib/jmapPatch.ts | 91 + src/lib/jmapUtils.ts | 15 + src/lib/layout.ts | 195 + src/lib/objectOptions.ts | 161 + src/lib/schemaResolver.test.ts | 867 ++ src/lib/schemaResolver.ts | 268 + src/lib/utils.ts | 12 + src/main.tsx | 74 + src/pages/AdminPanel.tsx | 260 + src/pages/LoginPage.tsx | 89 + src/pages/NotFound.tsx | 24 + src/pages/OAuthCallback.tsx | 99 + src/services/api.ts | 129 + src/services/auth/oauth.test.ts | 104 + src/services/auth/oauth.ts | 182 + src/services/jmap/client.ts | 239 + src/stores/accountStore.test.ts | 109 + src/stores/accountStore.ts | 37 + src/stores/authStore.test.ts | 180 + src/stores/authStore.ts | 129 + src/stores/cacheStore.test.ts | 94 + src/stores/cacheStore.ts | 78 + src/stores/schemaStore.ts | 176 + src/stores/uiStore.ts | 77 + src/types/jmap.ts | 65 + src/types/schema.ts | 393 + src/vite-env.d.ts | 20 + tsconfig.app.json | 29 + tsconfig.json | 7 + tsconfig.node.json | 24 + vite.config.ts | 19 + 115 files changed, 26207 insertions(+), 21 deletions(-) create mode 100644 .env.development create mode 100644 .github/workflows/build.yml create mode 100644 .prettierrc create mode 100755 build.sh create mode 100644 eslint.config.js create mode 100644 img/logo-red.svg create mode 100644 img/screencast-setup.gif create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/favicon.svg create mode 100644 public/icons.svg create mode 100644 src/App.tsx create mode 100644 src/components/bootstrap/BootstrapWizard.tsx create mode 100644 src/components/common/EnterpriseUpsell.tsx create mode 100644 src/components/common/GlobalSearch.tsx create mode 100644 src/components/common/Logo.tsx create mode 100644 src/components/common/ObjectPicker.tsx create mode 100644 src/components/expression/ExpressionEditor.tsx create mode 100644 src/components/forms/DynamicForm.tsx create mode 100644 src/components/forms/FieldWidget.tsx create mode 100644 src/components/forms/FormEditionContext.ts create mode 100644 src/components/forms/OtpAuthField.tsx create mode 100644 src/components/layout/ErrorBoundary.tsx create mode 100644 src/components/layout/MainContent.tsx create mode 100644 src/components/layout/ProtectedRoute.tsx create mode 100644 src/components/layout/Sidebar.tsx create mode 100644 src/components/layout/TopBar.tsx create mode 100644 src/components/lists/DynamicList.tsx create mode 100644 src/components/ui/alert-dialog.tsx create mode 100644 src/components/ui/badge.tsx create mode 100644 src/components/ui/button.tsx create mode 100644 src/components/ui/card.tsx create mode 100644 src/components/ui/chart.tsx create mode 100644 src/components/ui/checkbox.tsx create mode 100644 src/components/ui/collapsible.tsx create mode 100644 src/components/ui/combobox.tsx create mode 100644 src/components/ui/command.tsx create mode 100644 src/components/ui/dialog.tsx create mode 100644 src/components/ui/dropdown-menu.tsx create mode 100644 src/components/ui/input.tsx create mode 100644 src/components/ui/label.tsx create mode 100644 src/components/ui/popover.tsx create mode 100644 src/components/ui/scroll-area.tsx create mode 100644 src/components/ui/select.tsx create mode 100644 src/components/ui/separator.tsx create mode 100644 src/components/ui/switch.tsx create mode 100644 src/components/ui/tabs.tsx create mode 100644 src/components/ui/textarea.tsx create mode 100644 src/components/ui/toast.tsx create mode 100644 src/components/ui/toaster.tsx create mode 100644 src/components/ui/tooltip.tsx create mode 100644 src/components/views/DynamicView.tsx create mode 100644 src/components/views/DynamicViewPage.tsx create mode 100644 src/features/actions/ActionPage.tsx create mode 100644 src/features/dashboard/components/DashboardChart.tsx create mode 100644 src/features/dashboard/components/DashboardView.tsx create mode 100644 src/features/dashboard/components/PeriodSelector.tsx create mode 100644 src/features/dashboard/components/StatCard.tsx create mode 100644 src/features/dashboard/helpers.ts create mode 100644 src/features/dashboard/stores/dashboardStore.ts create mode 100644 src/features/dashboard/stores/historyMetricsStore.ts create mode 100644 src/features/dashboard/stores/liveMetricsStore.ts create mode 100644 src/features/dashboard/types/metrics.ts create mode 100644 src/features/dashboard/types/schema.ts create mode 100644 src/features/tracing/components/LiveTracingPage.tsx create mode 100644 src/features/tracing/components/TraceDetailView.tsx create mode 100644 src/features/tracing/components/TraceTimeline.tsx create mode 100644 src/features/tracing/types.ts create mode 100644 src/features/troubleshoot/DeliveryTracePage.tsx create mode 100644 src/features/troubleshoot/types.ts create mode 100644 src/hooks/use-toast.ts create mode 100644 src/hooks/usePermissions.ts create mode 100644 src/i18n/en.json create mode 100644 src/i18n/index.ts create mode 100644 src/index.css create mode 100644 src/lib/basePath.ts create mode 100644 src/lib/debug.ts create mode 100644 src/lib/durationFormat.test.ts create mode 100644 src/lib/durationFormat.ts create mode 100644 src/lib/jmapErrors.ts create mode 100644 src/lib/jmapPatch.test.ts create mode 100644 src/lib/jmapPatch.ts create mode 100644 src/lib/jmapUtils.ts create mode 100644 src/lib/layout.ts create mode 100644 src/lib/objectOptions.ts create mode 100644 src/lib/schemaResolver.test.ts create mode 100644 src/lib/schemaResolver.ts create mode 100644 src/lib/utils.ts create mode 100644 src/main.tsx create mode 100644 src/pages/AdminPanel.tsx create mode 100644 src/pages/LoginPage.tsx create mode 100644 src/pages/NotFound.tsx create mode 100644 src/pages/OAuthCallback.tsx create mode 100644 src/services/api.ts create mode 100644 src/services/auth/oauth.test.ts create mode 100644 src/services/auth/oauth.ts create mode 100644 src/services/jmap/client.ts create mode 100644 src/stores/accountStore.test.ts create mode 100644 src/stores/accountStore.ts create mode 100644 src/stores/authStore.test.ts create mode 100644 src/stores/authStore.ts create mode 100644 src/stores/cacheStore.test.ts create mode 100644 src/stores/cacheStore.ts create mode 100644 src/stores/schemaStore.ts create mode 100644 src/stores/uiStore.ts create mode 100644 src/types/jmap.ts create mode 100644 src/types/schema.ts create mode 100644 src/vite-env.d.ts create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..dcf8960 --- /dev/null +++ b/.env.development @@ -0,0 +1,8 @@ +VITE_API_BASE_URL=http://localhost:8080 +VITE_OAUTH_CLIENT_ID=stalwart-webui +#VITE_ACCESS_TOKEN=OPEN_SESAME +VITE_OAUTH_SCOPES= + +# Dev-only debug logging (any non-empty value enables; only active when DEV=true) +VITE_DEBUG_JMAP=true +VITE_DEBUG_FORMS=true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..5434166 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,40 @@ +name: Build and Release + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-node@v6 + with: + node-version: 22 + cache: npm + + - run: npm ci + + - run: npm run typecheck + + - run: npx eslint src/ + + - run: npx vitest run + + - run: npm run build + + - name: Create webui.zip + working-directory: dist + run: zip -r ../webui.zip . + + - name: Upload release asset + uses: softprops/action-gh-release@v3 + with: + files: webui.zip diff --git a/.gitignore b/.gitignore index ad67955..4d704be 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,29 @@ -# Generated by Cargo -# will have compiled files and executables -debug -target +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* -# These are backup files generated by rustfmt -**/*.rs.bk +node_modules +dist +dist-ssr +*.local -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb - -# Generated by cargo mutants -# Contains mutation testing data -**/mutants.out*/ - -# RustRover -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.ignore +scripts/ +*.md +!README.md +/SPEC-* diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..9db28a2 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "printWidth": 120 +} diff --git a/README.md b/README.md index 449b42b..2d0adbb 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,149 @@ -# webui -Stalwart WebUI +
+
+
+
+
+
+## Get Started
+
+Stalwart WebUI is included with Stalwart Mail Server, to install Stalwart Mail Server on your server by following the instructions for your platform:
+
+- [Linux / MacOS](https://stalw.art/docs/install/linux)
+- [Windows](https://stalw.art/docs/install/windows)
+- [Docker](https://stalw.art/docs/install/docker)
+
+All documentation is available at [stalw.art/docs/get-started](https://stalw.art/docs/get-started).
+
+## Getting started
+
+Prerequisites:
+
+- Node.js 18 or later
+- A running Stalwart instance (for JMAP API calls)
+
+Install dependencies:
+
+```
+npm install
+```
+
+### Environment variables
+
+Configuration is done through Vite environment variables. Copy or edit `.env.development` in the project root:
+
+```
+VITE_API_BASE_URL=http://localhost:443
+VITE_OAUTH_CLIENT_ID=stalwart-webui
+VITE_ACCESS_TOKEN=
+VITE_OAUTH_SCOPES=
+```
+
+| Variable | Description |
+|---|---|
+| `VITE_API_BASE_URL` | URL of the Stalwart server. Used for all API requests during development. In production builds (when empty or unset) requests are relative to the current origin. |
+| `VITE_OAUTH_CLIENT_ID` | OAuth 2.0 client ID. Defaults to `stalwart-webui`. |
+| `VITE_ACCESS_TOKEN` | When set, skips the OAuth flow entirely and uses this token for all requests. Useful for local development and testing. |
+| `VITE_OAUTH_SCOPES` | Optional OAuth scopes. Omitted from the authorization request when empty. |
+
+### Bypassing OAuth for development
+
+Set `VITE_ACCESS_TOKEN` to a valid bearer token to skip the login page and go straight to the admin panel. You can obtain a token from the Stalwart server's token endpoint or use an API key:
+
+```
+VITE_ACCESS_TOKEN=your-bearer-token-here
+```
+
+### Running the dev server
+
+```
+npm run dev
+```
+
+This starts Vite's development server with hot module replacement, typically at `http://localhost:5173`.
+
+## Testing
+
+Run the unit tests (Vitest):
+
+```
+npm test
+```
+
+Run tests in watch mode:
+
+```
+npm run test:watch
+```
+
+## Building for production
+
+```
+npm run build
+```
+
+This runs the TypeScript compiler followed by Vite's production build. Output
+goes to the `dist/` directory.
+
+To preview the production build locally:
+
+```
+npm run preview
+```
+
+## Support
+
+If you are having problems running Stalwart Mail Server, you found a bug or just have a question,
+do not hesitate to reach us on [Github Discussions](https://github.com/stalwartlabs/mail-server/discussions),
+[Reddit](https://www.reddit.com/r/stalwartlabs), [Discord](https://discord.gg/aVQr3jF8jd) or [Matrix](https://matrix.to/#/#stalwart:matrix.org).
+Additionally you may purchase a subscription to obtain priority support from Stalwart Labs LLC
+
+## License
+
+This project is dual-licensed under the **GNU Affero General Public License v3.0** (AGPL-3.0; as published by the Free Software Foundation) and the **Stalwart Enterprise License v1 (SELv1)**:
+
+- The [GNU Affero General Public License v3.0](./LICENSES/AGPL-3.0-only.txt) is a free software license that ensures your freedom to use, modify, and distribute the software, with the condition that any modified versions of the software must also be distributed under the same license.
+- The [Stalwart Enterprise License v1 (SELv1)](./LICENSES/LicenseRef-SEL.txt) is a proprietary license designed for commercial use. It offers additional features and greater flexibility for businesses that do not wish to comply with the AGPL-3.0 license requirements.
+
+Each file in this project contains a license notice at the top, indicating the applicable license(s). The license notice follows the [REUSE guidelines](https://reuse.software/) to ensure clarity and consistency. The full text of each license is available in the [LICENSES](./LICENSES/) directory.
+
+## Copyright
+
+Copyright (C) 2024, Stalwart Labs LLC
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..2febeec
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+set -euo pipefail
+
+npm ci
+npm run build
+
+mkdir -p .ignore
+rm -f .ignore/webui.zip
+cd dist && zip -r ../.ignore/webui.zip .
diff --git a/eslint.config.js b/eslint.config.js
new file mode 100644
index 0000000..aafe486
--- /dev/null
+++ b/eslint.config.js
@@ -0,0 +1,31 @@
+import js from '@eslint/js'
+import globals from 'globals'
+import reactHooks from 'eslint-plugin-react-hooks'
+import reactRefresh from 'eslint-plugin-react-refresh'
+import tseslint from 'typescript-eslint'
+import prettierConfig from 'eslint-config-prettier'
+import { defineConfig, globalIgnores } from 'eslint/config'
+
+export default defineConfig([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{ts,tsx}'],
+ extends: [
+ js.configs.recommended,
+ tseslint.configs.recommended,
+ reactHooks.configs.flat.recommended,
+ reactRefresh.configs.vite,
+ prettierConfig,
+ ],
+ languageOptions: {
+ ecmaVersion: 2020,
+ globals: globals.browser,
+ },
+ },
+ {
+ files: ['src/components/ui/**/*.{ts,tsx}'],
+ rules: {
+ 'react-refresh/only-export-components': 'off',
+ },
+ },
+])
diff --git a/img/logo-red.svg b/img/logo-red.svg
new file mode 100644
index 0000000..eb8888a
--- /dev/null
+++ b/img/logo-red.svg
@@ -0,0 +1,25 @@
+
\ No newline at end of file
diff --git a/img/screencast-setup.gif b/img/screencast-setup.gif
new file mode 100644
index 0000000000000000000000000000000000000000..3d79f0170fdad8f10b725dc8c322b0fe9ed867dd
GIT binary patch
literal 265840
zcmdSV$cmiE2!Wr)7*$O9`dN9=jIhvelBF_MVo&%(45MKwejcEWI>?$1$r(By06;~g&saRt4QV6K)ptMeyC zdZ}4+PzfSKo%2^&ko2g9kTQqlzy?(-0193h+Q^xpC7KLt2#w`T*Ko?} B>pz0dbChg^Qb;3as-2DwCW(4Qu9q**{RE^>!Q=OFb(s=4CWW#slLthL# z9@*rJDKmt(OQ)y}kaUIR8hJznW@20xQyh#e@|_Y3rFmjt7(G$Bun4*MiYQ-3?u;8i zP8X6$nKxd$NtFVR(j)QK?ugeo2URL*aYbUBxw9gNU)1a)SEDdu?WoUJxqN=HA3Cg@ zjPhP fRIuC3$so>p8CBvtrxnoEUX*JdH+?_Vnleeg1?m{Vl zR4yj(;g_(FMm*jmPv3K+st{0(4G2sUHBOx5YJ_5s0ql055Kbj(14WuQA@NyWVfraP zC(<6L9rjss0Cmo+$O+`GV}bg>vz!SezcZ%1?B5ECKBt#JI!lD5-%#tliSWQt`WKmT z>Szq%jEf^PZ1qi2(qxs&CTUSA&KTdt+=#4KnjXYmsiwD+FdyaPVFZv`F>#jy8Edxl zM+a1&k&mP^rph_JW;v@ahC$O1?*2nztpl}kpy0KH>UG9sE>~xcS7=ZLWzj?$Hr3+3 zgk)E`lh_#!BN8%OfLdD>=`^p|{ZlnKGc)ySo~9(MWP37@yn!0?-jb@*)vi;U_0kB- zeo7^88U~{rMd24-8E-{r(d0Hq=W7iRb 8> J zHf1O@Xj8$t8GuPYkp)_*O0j_Tdni)n#GnAh*Rk9RGLR=ss2(k-B5gEaS0z3tdq@?k z)fqkWwnHza!e#>bJrXc{fc!~XPhdtdOZsz8lxg3jq@?e3r_Z$-WMOt<0XDyoiPbtr z%qU~WrzehGPdUlDhB|9IyD)QIKE=uy8IqSj48$Ss4*J2Q#6@!WZo}dl#WBpvCn63f zO!hNd(zhOrRhYw1$iR(`&>uYx%&4!Os-F%pL0d#PEYI7m7oq%|;wdtE-J4^~T@h zM|EE}KaNYUReK93ZVMr&R~VNlijR~fjYB=S@5h{ED ykJ8T1*%rR=10LNRcQ;MK1sucsRJ?DS+4#lmKuy-mR{^lK0GfSsdsx5WjZ`3(ibGF7!8I?Y%$_PhQ zb%m2Rv Xerh>H1`efe8mJVud!9KP^DrHc(LQPpcNYW{)p8!2K4HG{tJyp$L zhP+qvAVZ@GrkSR#= Zn?FdD(lV79PYR=vgwf?bl~0=TqQx#jLs dZ=UB`fdLX{L@>!ojOE zf;1o0S6|tzek7+^x~X0D8C+dGrd}ssbGx&)Jw^T5Wz8vc?Vy(WaB9tZd+lpH^_k$h ziTwIE7wYfv>v|>YztpM!9Ivy|Y{Z7IKu#V3UTlbnY>@QIMNDm&ZEoB$ze_2!X(GEx zJ1s_*uqjxy$!sphda}t6+~Uwsq}SMbYPH2ZEqbSJi>H4}@R0;B#kL;Dw%Cb?@QZC! z@V4}{$o=W 4~s< z-Dl?h&t}uY78JXT9J@B=!geoq>4SHj{z@86?>^bwb)6P^CbUN*yZ5qA$R}Zss%S4j zNGRxJ4*}c{rVt9f(b%W3+K)^SjIP^<_wUEQ5KN>vAmuo~X-K=jICva Xywv!zfUUZbTMxAQQr| zn#S?^+Q#NzBtQ#fkpetTIML}n*`VP5DugO@3oAE+_sM ( z%9`!F?fX5J`U}+bh4rm-wSmh@9e|Z9K-L28N;voGyR>?bv?=%=()&HIfC?fEfVlmD zV4?X40Ff4m7y-!Cg1Z3#L|7mY0kE(*^SSjSLhJ`7`2h;?tLgPcK0Am34az4V^AW!? zlYR{2p^}M2JJU!*OOhJ4A9aZ|_6ne9Ur7L1qEXG=l!D(6PrjQBKml$*Ms`5_4ci}P z%|DYae@v`NP% Q}vRucYBmi#@uMRol3ufO$G%%hvjMD8oi{p*4oZxEu% z19-=fupt{pLMvpuNZ6E*qC{zw8qRDf#xdS~v9ma{{UnJ)Y&S)JatD*jt6yikH2YaK zQ^an%)ab*mdam@#lbxjxdz!f*MGBPh+`e`xCQZn0dG0_dMW#%n%y|BbevMJEQb>By6&zlT{wg$3ny}!EnhliWy#jtuP%Q(EGd37P<~?;@J)aI z?aQybt2xa_1#R}L=VmLuMw@L_yN}jZet7P4246rV$QYcDmRfb|UYYS->~9VyawocV zPFps=t#?>|bW&rvPMrS6V!ij`LVCVyZ+-po{GV5#ua7`v;%?2qUx1W4ZkW7I`?I3J z&Ui3?%c)!oRZC_1HT&i1;H}U~yMZ5Q@iPUQ{@I3dfUMV<;$P#P=mDB%EoVw`2BjE5 zhJZ`T`?mv%DW7o0il4KyI*^_};mXN 0R39 Xz)M{%tJoHlhI)+MP- y*t&~&B| zs?^^#J>IAJS~t&{IjssR)qKX1#dK_7ainA4?@56qNC0Xi67Ad8GQf@a2%Fv`t4_}H zYx~@sCPS3QdntA!z`fge6Py7m7=RN10#b2}`bz*xwJIp!M&9nNv1m4?RobDh>$dY= zDoqd=Kq*kE7@9!BuvrSv7Gyst%emcd30@Gg|58=Iz}) ZvJutFHT9XqHcg%;#Wr_vf8NU?50 zWRhjZ0?Q%eev$>%TNvV3zE`qre@ZXkXS{B?R<~{m`tA8@{qK)okqv*XSA<`KQy2e& z_8&w35@SI~OR$ff41h~3#KUOgCyTGFxvX0V^NPj|RODLrk6=>h9ff#eS>FLrOi~zs zsl~e1^#CzQOG%*A%F2EpMK+)nX(`Gc>3l6e5H%KlAGwteZ)a!cqC`_sX;H*p4>2<~ zFi7fI)3(VC=b{lYCf!Li)i#P~kKudgo7Rk#NX4^wk+^5M@l279N>a wxGlN@Vndx!Ohva*s+3a-=^CFqAyv)93eA*1xK z_n&A<5GOrHexA%_P|@4s4k@!OvwM`KVz_LdT3d?B&|p+G{bHZqx`TqcW~o~C+Gq42 z?M=)X)oib-GT*h#3*&yM*@^0A%Xn~!*WN5;T50I!*mm1XDz;9zM0h67U)oDwq^P@> z B~7G*=N`W7E1p2LNGftu3t#0S!5(k*yMN?4%8_U4srpXnIQ_ zV<~h;7O)@@VrwSjVuRvWn) 9v2}4h#zt(19}1^m8WOipGq- 6WfPWE$H$j9(f9 zqyVOSCKk`q3L$U0u(QsT%SKRaAYkJ*`nf|2IH|20eqY#MGiD(TUI=gi3@>(*8n4nF z`8$lci74Sk1mfZ$L_8zimWt9Dtn`3TQOqjcbMw)A4DFP0&MI%8^@I&ulYveX-g>Xt zR3(rDGSLm#*i9p$%o|(tOl9|2%u3U0Z)U$py1Tzq?m}v50)!s@1tvp@1zXCt(GWFf z0^Nwtpd0l|Odd1)F^ej9I~Z*414xL_=DeC669EyGdT$ZEsc2!a5ySejK=50*-Z6n* z`4ZEfv?Kj&5ozL>^UYZsR8I${NR (>jXBxk z8irs=G|7eh A?t~wa-G?ej5Ix6VMTLu>hW<%{it@;y zW_sXZTvyxpzkmo;< io 5^kcMrFCPXopa#(v(?xFbbmF%#d zTB^S7@TU9lQ?F#5)M1*cVZKg9Q*nCZImKI>!{(EP5g;Wu$`Px%Gz)PhV%ZT}NSd9k z5;SJm;dhQ>>d0TW5ofQ|XG2Qg2_r5$xEGfr_M}h5n4WkXu{(>8B2-3Sm^|_BX7uuU z;v6$7nEk~60l8bt6OsPWKraU0ol(!T(buH~Seh{pj $3S|(0x<+o06-+g08|Tjpw^(GoYO*y2aN}Vk38s8D>4KS!N_e8C3_2QF{DkP zKzrp$DUzyehq1gS6_-@q%h$b;BbGS?$Up+Xum|GR;d3*9c`GI`0t*}iSd#$Y2tX-s z7N8yAXvA!}s7B5M0B+<{A+P{;Y+EP>+zzm21UN=#&(UD#pHDrdnY`(bE9MVlE7!}R zL;znfrWzIs;wowk8JIr{bkoIVQ!)VJ8L<^hlayKMIZX{IR*eDC(7qHFa7FsS<^&Gi z;LIBVvShg>pMCbc@f%zX2iLg6r195jeEK=_3!@yr{*Wj9ESj-7 vjU%OzdaN`&)c!+fJAvagz5C zBCN<%)&M|?fmv@;2q&dAovRHW)9B(22BM>3f)j@%nNvI37Yf;WGpvd3guZ(^xBpE2 zRG5*})}EDCO9f;aGvtI 0>Rf;SY#E)#}H3(EAD-zjdie=6(l8gJ8lqo~)2YNC^ng?=i{jqKC^A z4svQ_tDWQEXLJMtmf$lTo!G tRyx~ny80+~gZbXP)3ER?lFy=YZQ#kS ze#ncSXk)-rGqriARzzMLNxt~R75by+!=yXLAG;V;y#I{w27TmhRF2bw#n*hi>3AA= zH$^%|`SqWVSeIdIfyLYIA46Mjh3hR&0T&}^HEyEjSt9Zl&wUqT;$vfn7taWb@j Q^=J~RB*s}4GQRQm OhlfFMDcyiNzR?`7N)4_+PLusF6 z@z8R+Pr(pwlYJm{rs+hj>AN1&$tlyRRnzHX)AxT&3FKxotY)) U{IpH!?Z1zcA*|7>Qy>tena zv^M)NSbKwOD`>0$5kZSJKVCIIIX3_L$9&2RXtlWf w!>q@C!@gR~tkcmQXrF zq6kZ}UQ0NU1xdc;K+OjHuO))QYHih$qI|IcVMU{1MJr@RCA7&TQb?O%#hAZ2;bKMq zmg-iy73}WpN5*7gvGP_}e5t-~;|C+KEyiF}+Z?pFYn8pC5CIE3#HnU~h zmPy-JFSjMV7p1PYKi>_rhK18e0q>!sS(Jg&QQ(Qs!R#Bsv>U-J=wOyY+uKoKw)Pd~ zq)>Kru*!5W3oL|;j*iyhf#R+|8wy3p zWv*Ehf~|!j9@XvYz}BoYL!Dl%IYii>MQ!<-uRT(hHqi=pk=W76G}UEyuzX}oEwf?0 zZ#!|<-j;%B`C+(qLui2c+KpfN-hRVgl*StMMzAz&-)C(Xt7Jia4GvDQyO(K-li45F z-?v7GkLQ^u_3p3bImRRyIYk`I--Vj-9E`s-lUcMkrwC8KePB)aS2NptDMV!L?Ua*n z@H@werE$M(#LS!`Li#%R- X4{bnA2= IA5HDk0 ^+eo%Ly)bj%9dV~;tP)sL(m#Pu<4>ZUx29=rt}eDxmueI5dmE5k0PT&^Ci zJ=E35=f%pOg!`gz(DWDe9Lu5~M>iEc19UF#5-Uq4?n>3;#0oAF*)Q((VII6Wc=!Z& z|Ep&L;o@;5gKWK{l(5$X>{4EnOz|U?lIvwG`{k3bESRTdD&L1B`n<{tFV&v1X*e8e zau2KDdKtm=jV; zF&=n8!3BxugBX<`uM)5c=_hL|LC$o7Szb_J5{f;QKnDuSD&@^ z@2?A>5w5 {%tXJe0>A8fznnh5-1mNY>wfuP{R(dU3UB!rvH2HkUdb+dr)m0^S@@T` z`oDSYUy Rt)?_b^LU-RC-cHO`3tAG8Cf5WYSMz(+^;eh7H0WF#Vtrh`qT?5)) z2ec;!bQA=1)(3R;1$4g;=vfcw{Tk4B6M(-J*v}R?ARIXOIB-ZaaM&Vn#5HjAb>LWH z;CMmcM1A19zQD=%fm7>&(_aJM-vknF1 HT;|5HPgk&*q=&@3!0Y`l_p?%eqYqS<*RIR&J-&<}Y;9{=BPv?3!thV>tg zX4B+g(?W7+^Kl#ekB{aTmlKjw{HLVR_mspQVE$QYX-VsUP+CGpO |5V`aSuDyIJcwY @&~c7rqg0t_f~F!CwAh zo`KQ6uOfV3#r}t5`=kc=rF&!J147~g!joS`rT$~rE22jKG1rf5*5vHgm7M-#u2o$& zb-n(9>z)4r*LESFog;QV;`V)#_x*AIoHaHgAtWmCpSH$Eq=bg#hQ{E+; gl~ Qmz4A?GWo=7UZD&nGYfV$ `~E*@Xc <^9q zmxg}Y5%HY#pN0;W`1*fpXvK*?%E!+)2KCAA{I7;Kp}1lYZ2Fv*Cj37dx){1OC;~ zqT~{x{$CCKEU`#ZB|tr3^Jw|M8e00T(t7t(@U8!9Xv0WX#S>%c|7z&H{Xpw)2XXZ_ z|1@-f*D<0$;D-3&e>C*y@O{0++d{vtPPh5H!^`7xozFk?T8uq15;pJeenT!?(a^*u z_nzTSia6 Nvq8yyF&MOi3Z;s5xxYiV$ztI=TtEYW^vkC60wFe z>`z2q*g|>N9c`fe>ks71LzT-riUjNtS!As8Z~N602C(iSP+CJg_|6B|6$wie{*A5d zhD&jb?DF#gG6m}pUV@kb%g=bxA~nuRnJO9U1I5w@%^0+ue^V59^RQzacRD=Oktg0a zWKw1ndt*IbENv{SEL>zb0}~xD)ZyZtiEBD2DGHoWjbE=gA4B#?NmOJLw$fFZ=(0I% z89g _4C`2%rZ)zBnHANk5Mpq-mmJs z&R`SH5MtOrDzW~+dic)k{h#W>1~nC=qJJc;73o)e2a4Iv9E}JJ#%jfpququgO8p^$ zxH5)(aRH*>`{^~q40i&~$%l u>=6(nC z=cWj1_>8!uvC0}G_)jH~4vj`rydI399iAgE&$Rt=tv;R(Lq;&H|89gD4jNi{(gnW8 zVJ2j6)pmM)oTKFapkkw{CE3_wRK(PQ3=3};&7E}+jZ sU7gNPHx3zn|7_g`-dL zhH!~Ti&8 {_9r=VvL`vJ&W;Dxnb2Wx{#t#HZ$Y=5GrqL4BodhRk4KoVZB147}oFJ7Wt$aH~4(xo- z$TNdwORc(zWU%6>umXj}v Q% zjs{YNu(J)#%|8zD!mxk6qsR3Y&uN~j2AA6zEbiUun;4!XZEI8j{@_j$TvTH&L4adt zGw#7UMWo~>v}A>%5H9*KXXuac_IvJ0x>1KTAWV^5;Tb%THY|MNSCmA4@L*K8*7Nsd zx0Wep$(ZgztXufD*_iGk^w>*m3x5(JQyrmP#a}sX7)Gf3C>6i0k~8@uLh+7e$k0GSlwGh%zThIcc5llh fJ zWFXcpZ-aR}D&&;nEWYY4HrglJN w>}^TmUS-T=cj4o3U-2;ss!xDhfdffIBGv75Y0>W5 zmPBZPmGwH)Q}w9oWNX@we6X!)H&zuUpJ9Huz1F~QIs?-mE_mzeg~iSX5}e(IVRqb& z(KZa*O;p-S=s4{etBpg3vlyiUr6_oh=ni8K{zx)G8y<)W6^~bl5-~?1L^bX((0MO- zI80_c>GRVuiAJ&Vhlz)`q&YKQ135)82-#WwM#Sl^lMlDhm2qt^IRPSjg%%P<>`;HV zebZhJ& AKak($0s7_5xlePlLw;ii_YZkECwQGa47sNme3X%(yzlr^Sr(`4P)Y zb#SM#RhhcReo@<(?12(vx93z^NqmcvmFQp$JI@e)o%-(te-qsrfI>rjElpY2VPtQx zTJ9*(8s|S>AL_>0_p zf3-LJtFYev_F_ekd8!z zh!*rf2=?2WJ^8N^(ZFzMs2Vs-W7^A4UAf+^Ow80x c!^kjq!fCWDLrKg+e z-Y0;o?P>0z|I^{D5W2C1Sej9m*Cj7$<*wx7lB0!7eM~7FwMrW~gp}FC>N$p5&g)o( zOkqR$ $F_Af#jK38BPM07=AlxeeCC4+uAoT`t~9P&5I|K30Jb|e=ofohavp7 zM8*gtbM)T`u`M^xTeri)X_d!J1<}{LPV%O4GRh0MH5WIFW}v~}5t@P4nEqG4nbRr0 z$u^jJ)W3dol)!rb3#$3gNgIl}j$!tOY1bTadJA(xDm&y$2?|a6p3nX}RhGO_&^@H3 z4;WX`Iov1ffv)HS%5ke~ZTWc2` u z*Ktvm0E4-MndA(^^sF5FB@oV%$ofJu8fy;UCy3`MW)SU{$)hlGYj^ bywY&yy9D;`U{`ijDXSu6}K zqd|>;l5)aVE} +a%sE`Y-c%s$L}I0vaF0l+g&n9>MN$=vQkDEtm9tV+iV_|#rD}`^X)>niNT;C{ z(hU643@hnMGtx|#(#*%%EEv |iH!$YNi)7^f$a?FSGZL25*^#rT zozwjz2j4;0%a}W4l DOCXzd`lsg?wHTffVRywaiHgCZ%Zz(cwxg*b!GH>Na z-o`=R#*K9TB5(eVU;eC9{(eXPcxC?4kNp0F{8Q C~ zEQ@AdZh&$CimoDxn0^-1a6lvr;SY-7lI)N;D$w&(T`qw51OXOgDMf#mBpzVZqi>Q! zAjaVp7R2Cz8^u^)8Twusc`}ULzsxWjhOh$Nb>oCm!jS|prwRl_2@;V3*;<0E+@v_r zDA~etNlQ@G?7vqx*sYwY$Wn@cDGThRM-qs~@zkRL@_sxq5 @Qy}X+K$`3PREnx{Lr#$&*wS*R7*TxBxH-EhSkrqQ_F~VuGmzQ3KJgBDSTP z>#W!FuMO^`4mGa0Tt+O*fbSAWKNP|ZvLESNf|2tuj)sPa8!$O7AEE*QlAwlj;fdeA zY$`7z^>@BgEJeje)+8L${EC~ro~gR|Ct?HvAy)xafXU_Xg`B4k;lIe+CTI;N3NZjW zdNM&wbqf<;(^6-x+#!Np$qHHo7r8 TI~*^@F3UC7^5Hs;j-LYptlO`&ZY8%`W`??n#dBp@8lotM0L` z?vA4F$zR=5z@E}~ +L zzE2))X>}3+jxQWC{oSLsGW7H3P#V*)ZcUGds)AAXuvz!W@~>gb?kY{SRvbWIM{RhS zK#C<0bIXw%_(MwwFgh;scs!|AD+xCzc|rp;=!QV1HB6R6AhSt=8>@}RpVB^`9C`73 zB 3OGm+6NT =1FSDmq$_LJ|a#2dM!}z3Xo7CV-=5Ac0AQ0d5BD_W)oCWtH)qsl=IK~5Hz`@8(9A3 ztV-@IUwk1f-WZ+@pFw~z_(+T;XckS*!49(kzPG9VcPt;4*@s);aOa6B`9D)80@Xo< zbE;+p^@nAeE^~G(q=Bknu3B;h1SlHKK3PMq!B1Ew5R iBsWB+OCGV32{9_yIQs z_1qFz)i7IKHtQjdTkXB+SzTUTUHh}TVYYI4f9?NZ>O6y*`oeC1QVG=%TIhj<5PB%m zOA;W2B7`cP(1X%M<&OxMgb+iOs)&jK5m8Z*q6iA1h^Q!4#YR=cj)01aa=CZzyz_oJ zGyBWgd(NEMv!C^>_1l}bUcKG*a@1gE`R~k-^y?M7+2LKYKO}2@o|(0+pWRfw^Y`y; zqsA;?KetYqgI`qy=ge*W?R+&hC-rX*sWy+YpO+1vm(Q6;*Ul^T%&W}ItNokDs4ZyP zFW|x#@Hq>F+6CR71^t-?MbA?Q$LGG?m@x}qG|yT5D7l#2C;6>$F5;pOq-O4##(Bw- z3VYA0AxxdD5?KBPvSfrsf3Qf+dE=W hT5G*V#}rgcuF4wvl9=NC`xA>ZNrtIF?cD%M4s39V*Hkb4hC zz{c>bwzrXK53NJmS~8nwF<>hUa(5}T?v%WY?T5&q%Quz40!;*dMY6n$;HL+#Yl&<% zyqF!XX)SiS!x_>vAQIXW3e)}2|F~*a>FOTqC=H<)2MGZiOBRzll=MC_44^Ar(Aud> zm&2`J{QJn1UY;$f0*8cr)b+O_!l(a9nont8Ec(*wd9}R%;(g$ SFHBWHD5=xY#LH60K1d(?8s+^>{z#SYR!B!vg>RKL zQZ=Pf0G5!jjuN-7>uFv6e$^6{a*_#JGd@z4QfM?KxPC+-icl}9oNhWue4E*L*0gp# z`o4Hn%f*lU@AUKEqg)~QREti;j{u_|@RA>Uwmv7${y6vVN9vBHG>4xq;Xl)_&1IbZ zx%ceX$kCtnJwI7H<~R-;f5SF-*Jk-=H-6sPDDs*u+1gl9{Z)Q!rZVE!O!lv8qt`XP zzXo3asy*^jp#J-^-EZrBiD5?kg}mRsJ7fxDZsLtGw}C$mXK&@4{ei3#gOUIdmUovI zz!f4-q>A>CP~4V3gm==lsiN_%!6V0Xy45#3j+|;di|q9RNJM0>(O=Om4asgJEOy@} zv~*LI4NN;Am(KpZkNP{gLvE-vN@Ako$uZ RJqW+&7+Lh@L zlstK3-+5iIt7s9LUkTK)C#o5kQdYjRzg2lMa-zvu+#RyFeb{(xVs|*?7YmaLaMd}r zJ#YwzAzRk~E_*9v4+QozEYX^PCh^16rQN-fGUe+Wq )>o{0$uT9;R{O9i?COgUj+ATP&+S8 zTr6lf)?<|?_L(!$pd_&C_r&;3U}uYTB*kzS+fxj>WQ4{@BetaL*QKhV<17Jp2p#3c z`gH31mv+7LHU?ei2s%xtUl{2?H{Ex1|6SQwI{C5124nEnWGdBB%4XXQU74x3T n<4;J1qQ<^7{>;FhU!)|O3U3=QUA>K*It-{_QTeSWYrCa*#4*U-cJ8^}dg15Os_ z%f#LCarN`{Kj `HBkgvz@RNh zip%iP1TLC3=U9boo*UrmhJH`S;VTZ5YklCjx=H9NPOt @MZZ;~lcZ^3>7s!@mHBFWnl8GYvEDf4{rK+^eXd8b z3K0FMg%R-*Bm~||2}%DITOA!B`jj0LyYEy=fizfYo`1>-8VeVzf9XV_xpz`~?nmac zd7_}sFlnV+-WEGhniAJ6BBn67?^w;$1BenCsdU~xB(>&0aaBZR!yDc87*BQHH4JaN zytW&8_0iKhuXErkY-BiY#q@k*-Npi2w{iXA-MR (ph{=I>R;w(hTe2m?ZLmzi^rzcM^ z(U(e*G3eWKhnCN~h7_`!K>kIeHC}=lag;W| {2`_d4FRqqxb^KFv0tcsdBw0zdZ z>)QafenO|G@Y@FD8NwPr)#2=^GbIxalFT4Mzd#SP{-){) g84}s53eKYYt6D3t)E5qlicQ% zzT07S_GIqRL#(RdkPk$~p2PGwkww%wjLzJtdFSN|oqwF;F~6}abWfxjm@({EwFcA6 zWEZ*8;2@otXyw-%Lmd4Td=v97DWlJ3DoFzYeGiL6mG!YlJS{OQ2ra%GSen;QtR*U` zklXvEI*?jMo4jna$QcNOry%i5Xfbia7@a9mv`=Z<%%%xVuyri>X?0fmJC(&CMLY0B z&+gT)m*lZ_RMfm__!-E!9$}um@7G$OM)@kp)vSJJ)x(PS8#k#gRNtD(tRTeIEu>iD z3tB+7fNavU&&59#3(X&c>rz-J8P%*EcfoHg;(iwEP6LWB7~>kw8F?y#qh;20jXcbK z4cA(3x#}rDqe}3lhR}rr)886zy^wzZp`Xi?>wgSK`V3;1-YVyyqbR@M)J!Di(?t9W zC 62-CPj<`=IuAXUE&Ep$hcSyV@Bzp zT^jnt0*1}CCJ=C)ER9zwZ_G7b&KZ!aU%o7%K@`_i<{RMklHo=53d3iT{=4%hY$dJZ zhGJJz#%>e=yv$M%uw)*N{0ZL}+T8 G92tdTr^}F5UY}lu= zczz^IVH%La9A+R~0{dlnqU_>mhFE;yfbvr6QOBtH1;+FM7QZil*QW^NSL&d4+`huF z&8URNKnp$IzT%{;Xq9e{p<8wPO0qYjF(N@0Hbc9P a-w6}up<26>3if+dcT!J3B zCATKk+Q#a~2R$^nnwE6+b}aE|& 7U%iH~o`S>6kJT$0$9IAa@c z`z~m-=5ibT%k6lQNbp$Ghc&N%woE7O;PG2J?OsxMm^7E*3B!Z~UTSs;9`V7Gsu#_? z4DTe+k6KTjnYn+#IeU-aj+!ZB diDD;1=S_!bEtzzT3+Yj&QGx? zcD?XzO}7pC`#EFgw?&tI>3N00#pGw*US&Ah-gD5E{f*Qyk!wr+ZG= };)>t#&+Sehn?)sUfHm&@y>F-=fr=qn{CcUL_T-uuDgpP>>BX~BbH1^}y3FDq zLAJen0f-fr1p%sr20+1hIZT%Q=a13jRrj>_-U%g=%NnJOyoS2sXaUp>kr#k~!P;$B z_ViYb!97UFw&TEmqVs)LVE;an-mLT-M+iA+VQD91<)kEv4C4|{r`2$y3WeYQz&(Ue zZvqFO0gqsE@Wa9sB3F|DcH|e>w(!Mqd^bctn*g&x^W8Sc9`s`EX@rNM*M|s=Ab<;z zdHCVnuoegW0Sdv1hbM4+O5rv{@NZ>)7?HE3kik*B$n{z7^FhL}8Q|Bte7rtK`!v$R z4D3C8Qkw~mXo9M(lN>z|TUb#52Y_%SQY6@(CY6){#Upb!7GWx#z$W3$t}zaYaK&{D zY|wNm1__Pngcu+UDPx@5zmEA=LZ3~*-Il9H=&&d>!cV|OztR!)Kqw#qP%0ZBumBo+ zJLktGasUEY0RaAPOAdPd> J0!O8VIr-$_fPFokBw=wx%VOJKUQR$co-{jxpo^_h~4F00S(kmV@_X znfJ(+P6cNCEhm+H=Qk(o$KVpn8qu9B=`k>p4s2O+#D~Fa0L%*wf?8HX8N^XWK?WHx zumnQ`HGQg!R2Z(vK+tzIDy9=a(!mmR&~r_Am =9Zo>EB?ulo?0Van%HWWp4$9cHNRNvF8 ze7H}A_IEEh@zaA1nPC_bC}a#<;t;o;+&f}ufB(QC3;+*hH8&3z+@_TU4t`(OzyNHy zDL`w32VoVa408^e^s#9yX%fQsTcbFkY~%&2ElR63A0a1D!_Yz83^+9P^j2fg ^799Lz(-#D_Qa@39#V z6%X}BZ9HD#K0b5+2@L15Y3yDno?8YdTi@ev2up!425dNT7^5wNP~L5aq*Cg`L64EC zk ;AJ^SJZSuZW@?fc;G+Ce+ z>3+jcU0uuNYK+f2iHA|d(T}Kyhy2dAZNh(V^4e7Zg)!>ZUlm%)I&N7XVPvOzJ%(0@ zd3bk|2XuPCb~?df`Ob-hDNLR1y7a$!h=Meq{`rs @Ez z3M^2Wo>J+|<)Gp7e&o}W<6{fnoX&|Q6~wIuG7vbTNt<9o-M2jMIY52BzwZyLzNcu+ z+Ly)AKjR{`$vdPE5Ak>05T9hDCru<-|2E;FFc0(ZqjoC%sDl9;=O$ySM&G!N+1U-+ z|K&TV_NjFN_kZ(xSa1qyM*;xu_V%M{u_BkzyEThnG*7u7 ;s`K(>?@70BA+K7}!T6Eb|&Pa~_|PUk^cipE1>E3ld;lgV#; zQ@-<4V^63paG=EcT^QD`QXXWb{-8fQWiD5I<(RW7pZdAlWen~`VtuKbVz*4O8RHqZ zSmD!fQ&8TyQ+L^jysm+}4P3Vp(i1ntg#TZ-EC6JAxF}>eNZlsM1_IdA?i?XEeefP5 z8??RK$|8a|1Q-Z-rMW^GDh`!O42o5C!N5Xo(7-!0kJDG4Ya&={iLbzOq{K6&y BXZ@#joWR~uLIJl)`aPcl9TmWd6js{z zv#xY u?3~S za1KURN~%;6I2%_O#De&Th-l#*=A2<(2JdqhBAQNuA0WA9kZ)H>CLv*;^)YY)D~iCA zwH)4j67hQAwYiDIx-$HGuF= T)LfT|`M$)yBN;459 z4 6sAU*y^Pd(yrA_XvS_c3!M}ym z^-*~(QD!psMEk`pou#Ov3XEBDv;}JMZT~{Z!*GkM(NIowE@n~BJlbZaC33%L^z_}L zQggWc4Ten2wSj0U@0fSx(czPp?2pk>5Y Gb86eo<)Hj?tm}sp5RSjVm z-c}qM7nd9tpA*L{iA$)B+jBK;Z% xiUh7`Tz3aX(gX?^s$T&mF83(4*3ev^`F6^#HP%=q?5P;oU>4O9|M;~LYT zuXW3}u!?oqNT|faD&Mj~lgGN} =s3r*5N|;=gz~d>Fa2Wwe4+%oi zYUs-X9I-B- h*^NC8NO&O{->_MITX zFJ6rrhll_ff#0S~gO!k=>yP)iY^Z7wHB`>GdE*mq+GEDvLuBY@F`Y_!ogglP*RTMW zA?i*)OmKRUaQh#8)*HUxtuSdAbk3a5L~x{j+h0&aG{x17U1xu!;F1GDdUIXKIe5#z z*ex1-CZD%YiT@&GuO&F4ENAc2 99&Rl()(!xH?NbnK^3I9oN$ykyu+>*Ye z$af7) PuUGRGXpP2PV?IKU!X4MA%%Am#*)s|?ve5CH11TI$A4i1P#NNB9FnaJa0^qD zo8a(J{SSI$w{5H+kIsDh64y|SUjCM|c!QcEc~o&snxlu|U;M>GPwO_YKTLO?dp(oz zT!l%{OlBJM^%%)}=*Jte2 -SAvKfCvwBt=abIkNX^#z4tZ97=Gb>?pBO|i(L7dV!79^l;=&< zSn}j6kA71d){ad*qan&sq4VN9*_WkPzdVI2(YBjxu#TC9)$}yyYmL*BXRaFRo*w5# zJeF6Y)x?zQqMGc&JHN`!zV#w%R0r%&BI$0U4HAu0t+YWL(w+eZOnODfzVuQw4PM^` zN&&CG)+uAq+?Ts1nMNrZ11i0(ne z_=g=_wLvf#cKgMCJPJzNr=Gsw3uVk_Ge|t+;XO(iP7Fh0!k2FYzT=Gqy?BhA?*zvJ zJZ1hGQ}gG3^^B8caGzd~#Pfq^H95cca1Wb;w*1~9{fBi?Eu6G>Z4%lU#VK;xre6!s z79UgpSu~qbzB`I-bg1LWS3%<6a9@DTk`J=1z=u#TS|f_56<;`d97Od8Z>btim_d zMww;RzYLe6&qZXGkTN;GnT^LX^HMXzA=Vdrf0NaI1?Ofq-^;vobEnal% DrvIjO_i@O>hs26Vlue{=){mD(hzZI&P^ 8R#a#&dzx+U@uYVtFH*vGqk8LgIzOpf3fzePK1dvh*2N3~B#J@h-Y$86pgk+@h z{nQh$s;hZ$FV^Pqo*B8R@Gr%RU+rGCNKp1bU)_a1Wz$@e03VUMp|RcnFmeBi#)5a@ z_)3K8 ~+vQHb;TGOY=~L5M8_@C_at|6T`pqmwUE=ilN$c?oQ0`~l zPM9QpSl5|4KUHp>Z48{#0J_E8Ucv-^ePqBS3Opx1Sy+?~& 4@>^TIC2)2oGodTUe^=CUv_X^POa4mmbyp-lX? z3(U>h!m65`bv~d7o }hRPaHdY<$uBxIghn+IEQz~w*9}p*CsX&*E_U@EGIsSz zbs;-z5-iiVO-si97fL)wRz{9-d}vvv(q P;~Q>l(5LM;oQkINcP z7Xd4}P6nKa@cd8Y+U)7&!c;|&)X@V|?G#UUJfndZ%eY?M!B?lK 1KqN#6(<%%{^oG;yzE7YIA)ZEpj&>UQ}wITsJ zKmDT6{CbDLS?X=ng*+bvVBS~UHD>*!NmfzmIAZK7@cCS;=ut aHyC!mK>7@TpqQ}I(~2D&G5 DEVwzva)Q_`)UT3eBqkBCYSJCWNJ`1lyt?Q3Dv7Vq5iq zy)^(K2&FnSq3gk7icTb+9+x38J581H!0=S~7{vyYK2$jpjCNgwn;{$}nJsrf<#d0P zjcRn@2|Rf2Q|#G8TyxvLGbw}t^I3WyTpoLd>fva4K4adTQ>OGn;tIyuePSi%oTS8? zxeyZIX*`IRq$2_9#WHwxq82;}6Ac~i3NM{L58wzqQ8A(
Tp9d l9-!?niZH7xFTr2tFV6eIZ~Z1Co=vTXM?~DS1)_@KhX^2T85m_iaUqB!OzB z^X^sYW#=j=G0ww>Vnm@WC{GUzAR~mL;!q6O%fn7LTkaVuwwi#>=nWg=+2% uR(arle)^=cpez3LyQrzdXQ;Jh5XV7-&qfUNV~$#g=XL|%DnX|`+3HAL*t zt?|qwwcK#7+G_-R`L6!pjj20^>0VV5(WPIp!{|D*rf;=RNzO`r)v@Wua$)YfEbdr$ zTs^#~H~VYC!bIE8BfGm`c60S+@4w>DnR-uVwvN-4hqZ_tndZ4e@C+|VI1v~ZpBMG* z?BBaLm9Lf<*?025fZ9JI|0g$c$5w*npe*)6zHjq_oWfF1OzgKoy2PU5WakjRC@?>% zStrf&T(|W<<5IHig4A2f;o}qVoek2GOyaHko;fC!=k(v|_}+RD&|`AEt@*9N{#y^j z|Cv+|=r0*p+#2yUZ=K_f)M=i( mH@Ddl`(`sDp5raLCRIP~9ewxeLypC5 zheuxqI&Eft{Af4cR){llu!>mwA@*xc$ufCv1AP2vPlWyl#%%X||5Nz>lY8%{AlVYB zk)fgH(%`cm(YdqB&V!B^urn`XhI{emfbUf%-(n%;ehV0 |ZVPwQ-B4w DIb-6fQb!0FW zdg{n}uLQo4TN|OK6fuYr7V5M$2a(Jart|LIS*zn^4F91c8{Y}zXIVT1O1c=y4>$Yw zD)IIE^TlY(73DNlUg!=qxA;iIVpK}9CbW)x6nrA #1hg zoJ9=d%`d2~3eqTaYnGcYh$t0^+Rq;$hoS{wT`m}+gPIHiNv1x-!UoL80BNTI<3Sc9 z@|B&Aj}+#t`IM>|E=-*XA!a>TOb~djZ{yirP(x6zab$$0hU~w{Y 0O_IF QJr*r(S zetgpwM>q5}p}p9o`HWfUYux%G4#@SzK}go9fA?X=LK?C3m4#u<{pV3(BT`1Txh5_B zVwL$^Gz3)13+u#&W>N6%-cfHD_$ t_R2VxDboLx`Hj4UGg#>OAXAD z`hVZ @As)%XWet2v6#Z7jG21RLY~kQisEo>_2rl=tt#oX%5MfINZ>nekc)2*J5qF6Z z%kgf0?c#^9;8Gl(PT>fS#F&2E+#qh5MjT!w(EIVJkewc2t)e$L+GC3;S>4qBh@63V z`~c2&k?F}i@);Mt-XK56MzeNdui#HN2~+J|nW111q92ZVSjHVHBaOZp^CUCfKbn=u z6Ij&Pm~uj&1rY>hvKBEc^VB{V{ec+p(9{|Ft#peb70N1UUJ773N(# Tm zykfxgBu?g#= 3*OL2s5*QODrzq*D3N zPZ-_j&N^_l$f~OW?uq=iD1H{ciSi@9rQ|)4S>hJkPmmy3>wGkudxsbFQ|=~E8@xLj zn-7QW4U4(#lX{t4?LtjtH7P;BQ=YxyEHnlP`@Ph4<8tbtu1PbuQGO8C#G29 @=!5ATsUKUf^cJz-NBA)Xtg2d0f6!lEk^BeOgS9yo9y(mLg^( z_U+;vdLK)!)Nl9f-*u^Z=0m;X#NC7*{VK*NTsGIdp)vUlU0y}VV}d{!(s0vWa{I>$ zBHNtcC@xWa(+%uyyCw73gQ6$LJvPGA#ju)5pNY -*=>%_Lvg)k{NE!vvQPKis6B=%Jdc5}gb|sS^YopvM+|D*_q}<1 P zjNJ&Cx-q^ZUm{7lt9!01UzSsNn5Qrb11FLq%g6B5-&~5o+WIuTSKpLHT0QUX3mv(R zQ8&p$nS`QEG%ZX#byq`(tynJ;BBhnTuBjEjiVI2eqqX9Xtg5G(_+^+7PNZ$+ulkm@ z>Rd~ESJ>WTJPk^}($)Utz2MZ0ntI6W?hQ!=Gtg?^k_RT8(z>?*z5^AWV(5_jf3^ zd12a298BAc*QBFO%yzGZ6Q6gwnnHZrcK&Dj-i)G^UhsEUjd>IJ-k$wgb!(7)Z5B7z z?v-w_{(htMbbu`@gf?Ay#%58;
2As*YG3=M&iV zX_BfXxZPRAjCy1}is?wmdcZ$Pk`z2rn*~G>@;K-Td;mz2{eY$i5k-L1U$GF0UZ|%e zxdR27ifRj=D|NFfl $W+MT1< z z1&ok$C|M``wD2$&@O;AxIWzz1$;{{XQ!#bdhsf^(7u$mln^G&-Ry)CprCVgIKvFTW zJ#?LdWzrD@X!u@vzKSZS=bRZAj1z_uVj`%C0TWfTPdXT$2`cyJe`J*&q QAIa`F zQg)kCk5cxTp7{G(hNq?Rd nf?aok~6W}@HsJt2}P z;pkmgr_>s`I}aRaqkKrc)8t%7u#taAZ%2G@p7E#f3#FvWEJy9+Efu0!{e?hkdJ001 zPr9%|_EvQ?tIk01`@VZeU8olRSJ8N@YG-kXX-JT{F5^bresjvhyQb^?)RRN(&mqz0 zZ(Tb6TK(W@wHr|>YYHj<-3n?0+gkLeDnsm)zuUPZq+gMGvNO(Lr_U@N@^o~}EZmO` zOf%WYKyIcwDs|RlI}Oz{|0UgOjOe;B8(e>+tI1`p=vddq-r%OQU6+0aU%J+H`DO6s z-mc~g!Of#xS8{`|%ywOk2)_EY>zYmQwXLoe<)D@w-Pd0RURUpKZ3}EQ>TcU@eZir- zeKN4ktGnY_{rQOQ8<4PzDcv`p?d~|z-5Ij?rcIuCwPM$W?(J7}-`wi%?zOpnulx3> z&7Ei6cM6}c<^AdW+I^|YrgzIG>Aj6`hwWZb+dlQpC`H?Tqs<^4+X077%paRUFIzh+ z+q+wu3I{W<25sJ*)ieu?z$e!jw?rHCu7s%!NLl2a@>RI^pDo57A_-;dN;pgLOG95( zFdXi>uI?HchdIg)(q5|E!3;2?cR%d5l?^6K;S`(J`+e@`F%{mpK-tUEcISIx;V;8k zMzAN!gM{kTA8|Glg^gx}FtROVsmv`UdL7$QyErEI{i?YnqK|;g*7E=>TBfTD-N}F> z0qwX_=0p?8c9eB8s&1zoZ-3F@Oc?q5?4iM}RggO1Z|^p+G`M9Mp!#?EtckrG6eK^! zx1t~{&5${cQtdMf61kXamZTYY{Myc6a!yF%&+Twp$tGsOY$i^rg8}<%CrL(o-1-cA zh8|=&Udj0=bB8h&h9=UPrDEtkr2_#EcI!D4_&XWQe@hOt3xO%|#rC1oEXI9*kJJA$ zxvY`{cH_^~)CXBu|Bg?l-|v<}A7(o~J!WRn4ER<#AyNnA0jKJeS-(8~4+GlSlwk_g zRK9;w=&DhEU95~LDAj;irLS*D$I!~KA|+ziFD^DB&(Uri_$B$m{iJDv)T_o_A-m4l z9Qv{TONL3WbIh0DnJJs#bKd==`9WQu;1Y~l$LmfL)2%?h{cW*i#cId-n=u+Z4Zq=* zszKyz^VIZu`u!J9#+Eb4b%XI@HXg4kF8yGsjXi9>^MSNxTz{UV=@nJW^h)Pg$e%YE zZoXO%Qcj*4y8UV`?(yh3*AwR1N(c8mxg2ye-Ogl>R05<}%dsk#$2b{HS^sfHMn9=F zPC?nXaBL9u*8S4l6PvNCYj-L#B)?8;bBl>lNSSzabD3z#3rz6ozgJfGmYlTuFF@U7 z{qV1~_s?z~Q9qLN*E)Lixcs1n@#Dj;$};`G@t65&=yMJ8veCnxDfr)Ug%{x;wCZnv z=yD%O+2AB%0?Ju IF-Mptbl04t_3{_76q6q01M NYiu*z|&6^de>kXccDK`U_u zVZ-DZ*ICRwsNo|Fv}7X%PFe1n7o>XgrK)FaPdhbRI(BL(-p<5EqGV{LL@xcPW8Nfk z5Akumd@l$}cS&$7w|A_{mVd!Kf9Cj$GdMe56>%8#xhbaTEng{_T!TlyrcNw{l++q4 zG)BWG_6t%kYBoOIb0{j^KK}FT6SFyg|K7CULLGg+z=MG71MyjJCl%&-syXNden@${ zMXuKI!1 HHS*r~Ss;9_6pMzo&n-@BaBuc|{0I$xoi#R8#pjD0iZJ zWkM=KWp!BVTGze_wX-T~BRlWiS{*l>RaqZ%?(JL~wHI+!jww}KIi+9L=lXp*)&*Yk zJbv_k`aVaW^U@ADQ9L0bV?OWuc(Fsy>V%QaU+h*m0>jELfgZ{!_pa?#I}A=8wm{|2j$6dXEs`e=COhbtmmhh9Q3pxYLt z@GPj3LZ=$|>N9Y1sgu&^WIsuh#uDv62CQD5g lhq)N8p$^raRK~EbdIctriWi$!NPZ^|5Pg% zWFvp{HF8U_*iW;fHmm%1uis+BaR6F`GoUUNqcr+b=+eGo8 ~1 z$Rgb|0aYWg{up$cg%lVU$hWiPX3@@Dl6wSV7z_Zi1k_+ M7=1ZEBU ziWC>-uy;G-Hrk0j?2(pQTE>iO?R@?_5Ls?`MH>WMDvpUuJvnN_!suUTze||lVvtVq zSK~DeZPyjEXz> e=t)OMhAN34BCOQ^~!CkYEti6$(FH+1$zy0Yz8LI>o=7zUCoJQVtkaB(GJ~7x% z{tbauN3 9=c?DR9D5BSRXjVAih_AiCl!2ezS!ROSg|^eGGZ~;t5uF_0WH@ zb4ntVf_LNBrHOZD!bC$tUVgaO;zHIJ6^Wu;ZJfdi{|*_1XbSJAa@m=70GVv^qVxCq zp$i=!EgD>b*RSR~W~X6#Dia70XYR(l+_kK f38!8NtAAOqSjKtXo(w2h2RKtpVd%{Wij#JE7&ZUBAPl(( y~=&KHCsLgu#K4wc1y{J?LFUzK>06pbO{Sa=<@gwMu8{(*p<-c29@62Xy(5qcsx z#L1KBtz5Xq_W2v$nupBD!|pKVOJ@0ga?Plp?y~> f;gh+E8iC8}GwzyjHxpS31=lc_$yf?IA5XpnUH23sO398+{QDoqxsLn@+DSCPs|x z&!3jh@ZqK^oE}uto<$C3$5Lv`DFaZ}bMW;b6Qt6c- gBC4W&i^TD>lOz2iD>5Fr84D5Zkj}i$=2><}ZuYzzq>P zq5({&Sm~#=KWvLXoEF(!en_p=C?zAMAKy1+*g+rmIw_t4zLP2=!R(FG1_8qbNd;H; zS>o@+e7Yz-o9cIPLjCOXUc95!9*k1b6h I2ItS*ld~aSF(NC2DIpT82u6 z?M5ouwoGRBp`E =-&voEZyXc5St>4iJ_XexK0ue)r?);dCNWB6JU~i5E0x?05s#&a zzobjOE5**NXf2dVt))tS9@AQ(@7SVC{A$tKL?Xq<#b9MP#5hvnx~TL%oNSpib{wke zjl=9aupaZeh%RGMCSx-$;~*{T=q>9~ChI;f>m@Dc>n*ptOfF u6Wn6iiZo)2-?=4d)u1DJ~ptW7XAC##cTTrplRMm=CeOacKx1egJsfLYL z`&g!actI^GN<}YG{ZAR@gqDg?A|?#-gb7xJ)0JmjCK~F{%zlL%`*hOhi*+ZkS&@KE zl!9B`WP3gq=YuOCE7eA7z8k >ZW>_|0upZwl>*KQIm`1 z^*LmeYZtOZ%+71Iv(fx=w7yRi$|R#!fK31cx@^3U0AXK`5@TRK0We(<5Jyo07z$KJ zSvWZiEYP?=frVpsI4y_*LLhDdMrUZ$VzfW8^tK%9bx$!2|Eoter|F0ZrE2G32kH?% zLhPk9d@aN1a1>C>B0OIGkZf|=Ozf~93CGqH4g6?~AfbBL$kulNjhRVXKoi&~N}U{q zyz}+lSOJPq00L$%XruSzL$`HxiiJoNXmy)FL(+e~YPwmD4WA=+Y_Bg3^U4QD7aG2w zFm&D?MkD1(I4DWBXuozS$@oMR2u@Z41Gt2G(NH0_z0Fv?LR+(f&}k~aqg8tY08L-K zXrDl^Zo`&?%$zHLlE| yneze~&wkfa=iCmG!-ELBspd9d8MiuA0ZCUR3Yis& z#H}gA>kvf%?tC8t5FobjtBMk96p?z_qB+=D8YZ3Xyhbuhoy69XWhwoX4)^U_KY<6U ziol#=I@|8aTdG5p{=-$}RiX2Lb)q!_TM>|qC0Hi3{nn}wfp51x+b31TK&I8pqDcTw zMsd%63~OCEYhJWgsBn7CuvmzMgJr~oz>J^r>YU>_zwS>gti(L^BT6wG0BYtGbv3NX z^+5F$kX0v2s>CwZVKM7rpXOjStZZT*AO;wm1r%+kq?{a;KFv8kY?GDfQz#N5O6$1B4#e2Yn~uh0S~LnxB8~q2RZgO6cH+m17(X2GM-b(;_a-vGv}q-1=7vl z4ptlo$Ngq^VIX`H$@?gZ9$DeXM#I5!ggzZrJjDv^AtHorV?UwM02~91$-uyKFdqO| zol~R(09_zkKn5fP2r&{cGmHdSAYi9n9|{&Oh<@ltv;)iZqi{8Vfqy!Nvmdhx*c5_n z92R0v6&m=GfNAX=00u?~FiA+?rlaba?uujwL@7`Ju{juA2sA|MshhjznI?49$pQkv z2LtE^bb}e7P!fP9DSsjXa3P`x#FUW%)( `ud)Ow z;hVXeOL~%n{NDI_M9`Rag9Ziu2rK)!lR$vmfEA^#X!Y_!L~dyH?5r}J;{-4u?E*OR zgR~SNT0IvYA_6sMiJG(8Y&F9jD#ArsA(d?4g?@ws2MzsUOsxxVXQTdA#fqh4wl!zy zq9Rz3q#QsDzhPU90dU10z5*bPq6D9VZMBnu9#g~fWI$@o0|Xev?skj3fh${w9hZl# z`{6R5(m(=P*70ooH1FsS#V&bV_i=x_euR9w1~5nT6#@ZXiMQIAcKtx+Pv!6*29g-- zY!FZ{3u{H?6;8oEr6sF(CSPc?j;I%%E_eB6k|#nb6p8eJO~S?|Y(n&-MKle2+0njf zpjMOOhbaBoH2o{6!q*vv7N1M^ck&%HX|ZE@->UWO&|K#YWeG;S%MZmGjCDer{?TXH zp>-RPI`g9er&vFfsoSxUHLXC6z=B6mRD!nBqT*r5aUCqQT!3BRJhRk%R&YgZ_-4Y; ze*`nJ^5c3SXf)aoL-Av9w)OzEJ)lyg2P7_9$&B ^$Es{7qvvd1KQ$C#SoGG3s cs;Rl#InolTU!2r2QhWwK-+a>2x{>W6X>18}N8W~B*}G6j4{=OiNm z*$SJ3C+ZW-fK`Tm1m?WXhH_Um)~(MCLMn=^20hqNZZgfXsTXa(QC`fdu;L_j^hFi| zGEV18swVxtZ{Bt4^K`AO?MPQR-sTY-oWHj#$%d0>w;+K065PKjD`idJQ4_{GcvfTq zR%4lLMLAVkhuW%T?1Ke|I9Qe4n?UwwcwOEf pP5oHC9vx34?Fhf!& zuq_s~0}D48F(n`rg(UroTAjzScV){`*hnG+l15RcvXSiosC7;mZYH8eK1CJ4aD6v+ zlR|AMqPD)LB4f?ifM_X31j&F#QBK=Lp_{)dXGZo|*2_)ZikUtMI&L0teSc5{tKfUJ z{@O{w#dcBnT&+$0UgwGPu_vrSz@2d$fL1U2^iSo{O6+5sJ0Rg59mIA71OydYn{HD! z <`W0|+@Hi@Q(QXv?(bJk_vH_<8q1LDGCTWOa&E=FnJ?pK)PeLmbX{?a@`Gx4yB zm&UDbtA*}+2ZmFA^n@{-Yz|$!V (tsN!`6vl7zXiqnC_&`~lIU0WufTinur7 z6meMrwkY!dkayotO@wXV@Hdqtv`|7Xp?3&~G(i)3mC&mgsvsSaqNoWqG!0cy)X d+vFBkIymlr^v@wP4~(X z<)?-OM`$m>vX}E^?bUk?hG2E4LVJ#1Zcf0Ha3NTzfMc?&qqJ!C$y5stSs2_{K4w<# zv9sXgJzV1 BY6>WH0&1+mf}b#Jd$x=j$Qm!!>2x=q{x<|Qa$!sv6YF9 z|7_isPQ&wA1=b7T_~8OKNzrS6MTO{zUJ{N@Kd8^m9&eOCKGt=+@`hZ^g*RS*t%Q3N zJtaLY{?<9+4I^iTt^bByc>TmI!2U#up4}2G;k)>k*)fhPhSf4|n9TJ!T40oXq|icf z@Xt$A*4=$9qM0>*FHP)j>Q$LOJXs^4Vn?njO6(!J%&O{{{t$H-3woCJ{9z@ZqO