From 7e6d0d4ab4022a5b6cdb227a6ab43a634c4b6b90 Mon Sep 17 00:00:00 2001 From: Boban Blaskovic Date: Fri, 22 May 2026 21:36:04 +0200 Subject: [PATCH] =?UTF-8?q?feat(ui):=20dashboard=20MVP=20=E2=80=94=20featu?= =?UTF-8?q?re-folders,=20lazy=20skeletons,=20wire-elements=20modals,=20bra?= =?UTF-8?q?nd=20logos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major refactor + UX polish for authenticated dashboard MVP. Architecture: - Feature-based folder structure: app/Livewire//{Index, Modals/*} Dashboard, Subjects, Tasks, PhotoHelp, Rewards, Progress, Notifications, Settings - Matching view structure: resources/views/livewire//{index, modals/*}.blade.php - Removed legacy Pages/ and Modals/ top-level folders Modals (wire-elements/modal v3): - 7 modal components extending LivewireUI\Modal\ModalComponent - Vendor view override: z-50 (above sidebar z-20), items-center justify-center, bg-bg-soft surface, role=dialog + aria-modal, design-token-driven backdrop - Server-side dispatch uses ->to('livewire-ui-modal') for cross-component routing URL state + skeleton: - Tasks + Notifications + Settings use #[Url(as, keep:true)] with allowlist validation in mount()/setSection()/setFilter() to block injection - Tasks startTask + repeatTask actions dispatch openModal targeted at modal - All 8 main pages declare #[Lazy] + placeholder() returning a page-level skeleton (animate-pulse, bg-bg-soft container, bg-line bars) so first paint is structured instead of blank Skeleton/no-jump: - Skeleton container uses bg-bg-soft (matches table card surface) — no color jump between skeleton and resolved table - Settings sub-nav renders active state server-side (no Alpine :class flicker) with @if-server-render instead of x-show - Font flicker eliminated: font-display: block + on both layouts for Plus Jakarta Sans + JetBrains Mono Logos / PWA: - public/logo/, public/icons/, public/manifest.webmanifest deployed per Logos/DEPLOY.md - Brand component (default / wordmark / icon-only variants) with href prop - Favicon SVG/ICO + apple-touch-icon + manifest tags in dashboard + guest layouts - Sidebar brand wires to route('dashboard') Layout / a11y: - Sidebar fixed left (top-0, h-screen, w-60) with header+footer shrink-0 and scrollable content - Topbar sticky with z-10 - Sidebar uses x-layout.brand :href="route('dashboard')" - Logout: POST /logout route + sidebar-user widget with @csrf form button Bug fixes: - Tasks rows are passive divs (not buttons) with explicit info-icon + Start button — eliminates nested-button invalid HTML - Tasks Start/Wiederholen buttons wire:click to startTask/repeatTask actions (previously did nothing) - Modals centered + above sidebar z-index - Settings section sub-nav no longer flickers on hydration - public/hot cleanup: Vite runs as docker compose service with auto-restart Test infrastructure: - Pest beforeEach calls Livewire::withoutLazyLoading() so #[Lazy] components hydrate fully under test - 157 tests passing, 0 skipped, 0 failed (411 assertions) - New test files: AssetReachabilityTest, BrandAssetsTest, FontLoadingTest, LazySkeletonTest, LogoutTest, ModalLayoutTest, ModalsTest, NoNestedButtonsTest, SettingsNavTest, SidebarPagesTest, TasksStartButtonTest, UrlStateTest Config: - config/sidebar.php as single source of truth for sidebar nav items - config/reverb.php allowed_origins set - Test DB isolated: phpunit.xml DB_DATABASE=lernschiff_test + tests/TestCase.php refreshApplication override Co-Authored-By: Claude Opus 4.7 --- .env.testing | 8 + app/Livewire/Dashboard/Index.php | 68 ++++++ app/Livewire/Notifications/Index.php | 96 ++++++++ app/Livewire/Notifications/Modals/Detail.php | 26 +++ app/Livewire/PhotoHelp/Index.php | 23 ++ app/Livewire/PhotoHelp/Modals/Result.php | 19 ++ app/Livewire/Progress/Index.php | 23 ++ app/Livewire/Rewards/Index.php | 23 ++ app/Livewire/Rewards/Modals/Purchase.php | 45 ++++ app/Livewire/Settings/Index.php | 45 ++++ app/Livewire/Settings/Modals/Delete.php | 29 +++ app/Livewire/Settings/Modals/LogoutAll.php | 26 +++ app/Livewire/Subjects/Index.php | 23 ++ app/Livewire/Subjects/Modals/Detail.php | 26 +++ app/Livewire/Tasks/Index.php | 105 +++++++++ app/Livewire/Tasks/Modals/Detail.php | 26 +++ app/Models/User.php | 10 + composer.json | 3 +- composer.lock | 127 ++++++++++- config/reverb.php | 2 +- config/sidebar.php | 80 +++++++ database/seeders/MusterschuleSeeder.php | 5 +- docker-compose.yml | 19 +- docker/nginx/default.conf | 29 +++ ...026-05-22-button-spinner-overlay-design.md | 86 +++++++ package-lock.json | 128 ++++++++++- package.json | 4 + public/favicon.ico | Bin 0 -> 15086 bytes public/icons/apple-touch-icon.png | Bin 0 -> 11761 bytes public/icons/favicon-16.png | Bin 0 -> 1208 bytes public/icons/favicon-32.png | Bin 0 -> 2407 bytes public/icons/icon-192.png | Bin 69 -> 12480 bytes public/icons/icon-512-maskable.png | Bin 0 -> 30904 bytes public/icons/icon-512.png | Bin 69 -> 43603 bytes public/icons/icon-source.svg | 9 + public/logo/favicon.ico | Bin 0 -> 15086 bytes public/logo/favicon.svg | 9 + public/logo/lernschiff-icon-monochrome.svg | 8 + public/logo/lernschiff-icon.svg | 9 + public/logo/lernschiff-wordmark.svg | 10 + public/manifest.webmanifest | 50 +++-- resources/css/app.css | 76 ++++++- resources/css/safelist-tailwindcss.txt | 5 + resources/js/app.js | 2 +- resources/js/auth.js | 1 + resources/js/echo.js | 15 ++ .../components/auth-session-status.blade.php | 2 +- resources/views/components/btn.blade.php | 30 +++ resources/views/components/card.blade.php | 18 ++ .../views/components/input-error.blade.php | 2 +- .../views/components/input-label.blade.php | 2 +- .../views/components/layout/brand.blade.php | 55 +++++ .../layout/gamification-chip.blade.php | 9 + .../components/layout/nav-item.blade.php | 27 +++ .../components/layout/search-input.blade.php | 9 + .../components/layout/sidebar-user.blade.php | 31 +++ .../views/components/layout/sidebar.blade.php | 49 ++++ .../views/components/layout/topbar.blade.php | 22 ++ .../views/components/layouts/app.blade.php | 2 +- .../views/components/layouts/auth.blade.php | 2 +- resources/views/components/pill.blade.php | 18 ++ .../views/components/primary-button.blade.php | 2 +- .../views/components/reward-row.blade.php | 20 ++ .../views/components/skeleton/page.blade.php | 32 +++ .../views/components/stat-tile.blade.php | 18 ++ .../views/components/subject-card.blade.php | 36 +++ resources/views/components/task-row.blade.php | 37 +++ .../views/components/text-input.blade.php | 2 +- resources/views/dashboard.blade.php | 4 +- resources/views/layouts/app.blade.php | 2 +- resources/views/layouts/auth.blade.php | 2 +- resources/views/layouts/dashboard.blade.php | 35 +++ resources/views/layouts/guest.blade.php | 22 +- .../views/livewire/dashboard/index.blade.php | 110 +++++++++ .../views/livewire/dev-quick-login.blade.php | 26 +-- .../livewire/notifications/index.blade.php | 86 +++++++ .../notifications/modals/detail.blade.php | 20 ++ .../pages/auth/confirm-password.blade.php | 30 +-- .../pages/auth/forgot-password.blade.php | 15 +- .../views/livewire/pages/auth/login.blade.php | 45 ++-- .../pages/auth/reset-password.blade.php | 52 ++--- .../pages/auth/verify-email.blade.php | 22 +- .../views/livewire/photo-help/index.blade.php | 111 +++++++++ .../photo-help/modals/result.blade.php | 50 +++++ .../views/livewire/progress/index.blade.php | 117 ++++++++++ .../views/livewire/rewards/index.blade.php | 57 +++++ .../rewards/modals/purchase.blade.php | 76 +++++++ .../views/livewire/settings/index.blade.php | 210 ++++++++++++++++++ .../livewire/settings/modals/delete.blade.php | 21 ++ .../settings/modals/logout-all.blade.php | 11 + .../views/livewire/subjects/index.blade.php | 45 ++++ .../livewire/subjects/modals/detail.blade.php | 56 +++++ .../views/livewire/tasks/index.blade.php | 119 ++++++++++ .../livewire/tasks/modals/detail.blade.php | 38 ++++ resources/views/lizenz-abgelaufen.blade.php | 6 +- .../wire-elements-modal/modal.blade.php | 57 +++++ routes/web.php | 16 +- tests/Feature/Auth/AuthenticationTest.php | 3 +- tests/Feature/Auth/LogoutTest.php | 74 ++++++ tests/Feature/Auth/RegistrationTest.php | 12 +- .../Frontend/AssetReachabilityTest.php | 55 +++++ tests/Feature/Frontend/BrandAssetsTest.php | 72 ++++++ tests/Feature/Frontend/FontLoadingTest.php | 28 +++ tests/Feature/Livewire/DashboardTest.php | 63 ++++++ tests/Feature/Livewire/LazySkeletonTest.php | 59 +++++ tests/Feature/Livewire/ModalLayoutTest.php | 93 ++++++++ tests/Feature/Livewire/ModalsTest.php | 170 ++++++++++++++ .../Feature/Livewire/NoNestedButtonsTest.php | 94 ++++++++ tests/Feature/Livewire/SettingsNavTest.php | 84 +++++++ tests/Feature/Livewire/SidebarPagesTest.php | 127 +++++++++++ .../Feature/Livewire/TasksStartButtonTest.php | 99 +++++++++ tests/Feature/Livewire/UrlStateTest.php | 129 +++++++++++ tests/Feature/Wire/WireModalDeleteTest.php | 65 +++++- tests/Pest.php | 5 + tests/TestCase.php | 6 +- vite.config.js | 11 +- 116 files changed, 4266 insertions(+), 167 deletions(-) create mode 100644 .env.testing create mode 100644 app/Livewire/Dashboard/Index.php create mode 100644 app/Livewire/Notifications/Index.php create mode 100644 app/Livewire/Notifications/Modals/Detail.php create mode 100644 app/Livewire/PhotoHelp/Index.php create mode 100644 app/Livewire/PhotoHelp/Modals/Result.php create mode 100644 app/Livewire/Progress/Index.php create mode 100644 app/Livewire/Rewards/Index.php create mode 100644 app/Livewire/Rewards/Modals/Purchase.php create mode 100644 app/Livewire/Settings/Index.php create mode 100644 app/Livewire/Settings/Modals/Delete.php create mode 100644 app/Livewire/Settings/Modals/LogoutAll.php create mode 100644 app/Livewire/Subjects/Index.php create mode 100644 app/Livewire/Subjects/Modals/Detail.php create mode 100644 app/Livewire/Tasks/Index.php create mode 100644 app/Livewire/Tasks/Modals/Detail.php create mode 100644 config/sidebar.php create mode 100644 docs/superpowers/specs/2026-05-22-button-spinner-overlay-design.md create mode 100644 public/icons/apple-touch-icon.png create mode 100644 public/icons/favicon-16.png create mode 100644 public/icons/favicon-32.png create mode 100644 public/icons/icon-512-maskable.png create mode 100644 public/icons/icon-source.svg create mode 100644 public/logo/favicon.ico create mode 100644 public/logo/favicon.svg create mode 100644 public/logo/lernschiff-icon-monochrome.svg create mode 100644 public/logo/lernschiff-icon.svg create mode 100644 public/logo/lernschiff-wordmark.svg create mode 100644 resources/css/safelist-tailwindcss.txt create mode 100644 resources/js/echo.js create mode 100644 resources/views/components/btn.blade.php create mode 100644 resources/views/components/card.blade.php create mode 100644 resources/views/components/layout/brand.blade.php create mode 100644 resources/views/components/layout/gamification-chip.blade.php create mode 100644 resources/views/components/layout/nav-item.blade.php create mode 100644 resources/views/components/layout/search-input.blade.php create mode 100644 resources/views/components/layout/sidebar-user.blade.php create mode 100644 resources/views/components/layout/sidebar.blade.php create mode 100644 resources/views/components/layout/topbar.blade.php create mode 100644 resources/views/components/pill.blade.php create mode 100644 resources/views/components/reward-row.blade.php create mode 100644 resources/views/components/skeleton/page.blade.php create mode 100644 resources/views/components/stat-tile.blade.php create mode 100644 resources/views/components/subject-card.blade.php create mode 100644 resources/views/components/task-row.blade.php create mode 100644 resources/views/layouts/dashboard.blade.php create mode 100644 resources/views/livewire/dashboard/index.blade.php create mode 100644 resources/views/livewire/notifications/index.blade.php create mode 100644 resources/views/livewire/notifications/modals/detail.blade.php create mode 100644 resources/views/livewire/photo-help/index.blade.php create mode 100644 resources/views/livewire/photo-help/modals/result.blade.php create mode 100644 resources/views/livewire/progress/index.blade.php create mode 100644 resources/views/livewire/rewards/index.blade.php create mode 100644 resources/views/livewire/rewards/modals/purchase.blade.php create mode 100644 resources/views/livewire/settings/index.blade.php create mode 100644 resources/views/livewire/settings/modals/delete.blade.php create mode 100644 resources/views/livewire/settings/modals/logout-all.blade.php create mode 100644 resources/views/livewire/subjects/index.blade.php create mode 100644 resources/views/livewire/subjects/modals/detail.blade.php create mode 100644 resources/views/livewire/tasks/index.blade.php create mode 100644 resources/views/livewire/tasks/modals/detail.blade.php create mode 100644 resources/views/vendor/wire-elements-modal/modal.blade.php create mode 100644 tests/Feature/Auth/LogoutTest.php create mode 100644 tests/Feature/Frontend/AssetReachabilityTest.php create mode 100644 tests/Feature/Frontend/BrandAssetsTest.php create mode 100644 tests/Feature/Frontend/FontLoadingTest.php create mode 100644 tests/Feature/Livewire/DashboardTest.php create mode 100644 tests/Feature/Livewire/LazySkeletonTest.php create mode 100644 tests/Feature/Livewire/ModalLayoutTest.php create mode 100644 tests/Feature/Livewire/ModalsTest.php create mode 100644 tests/Feature/Livewire/NoNestedButtonsTest.php create mode 100644 tests/Feature/Livewire/SettingsNavTest.php create mode 100644 tests/Feature/Livewire/SidebarPagesTest.php create mode 100644 tests/Feature/Livewire/TasksStartButtonTest.php create mode 100644 tests/Feature/Livewire/UrlStateTest.php diff --git a/.env.testing b/.env.testing new file mode 100644 index 0000000..15722e3 --- /dev/null +++ b/.env.testing @@ -0,0 +1,8 @@ +APP_ENV=testing +APP_KEY=base64:olpsnUi1o5DBLbA0lK2LCJiCnhMPldp7Pl3kuj1Iz7A= +DB_CONNECTION=mysql +DB_HOST=mysql +DB_PORT=3306 +DB_DATABASE=lernschiff_test +DB_USERNAME=lernschiff +DB_PASSWORD=secret diff --git a/app/Livewire/Dashboard/Index.php b/app/Livewire/Dashboard/Index.php new file mode 100644 index 0000000..88dd339 --- /dev/null +++ b/app/Livewire/Dashboard/Index.php @@ -0,0 +1,68 @@ + 'dashboard'])] +#[Lazy] +class Index extends Component +{ + public static function placeholder(array $params = []): View + { + return view('components.skeleton.page', ['rows' => 5]); + } + + + public int $totalPoints = 2480; + public int $streakDays = 7; + public int $weekMinutes = 86; + public string $testRatio = '18 / 24'; + + public function render(): View + { + $user = auth()->user(); + $firstName = $user ? explode(' ', $user->name)[0] : 'Lina'; + + return view('livewire.dashboard.index', [ + 'firstName' => $firstName, + 'today' => Carbon::now()->locale('de')->isoFormat('dddd · D. MMMM'), + 'subjects' => $this->subjects(), + 'tasks' => $this->tasks(), + 'rewards' => $this->rewards(), + ]); + } + + protected function subjects(): array + { + return [ + ['name' => 'Mathematik', 'icon' => '∑', 'color' => 'primary', 'lessons' => '18 / 24', 'progress' => 75, 'next' => 'Schriftliches Multiplizieren'], + ['name' => 'Deutsch', 'icon' => 'A', 'color' => 'rose', 'lessons' => '13 / 20', 'progress' => 65, 'next' => 'Wortarten erkennen'], + ['name' => 'Englisch', 'icon' => 'E', 'color' => 'violet', 'lessons' => '8 / 16', 'progress' => 50, 'next' => 'Past Simple üben'], + ['name' => 'Sachkunde', 'icon' => '🌱', 'color' => 'green', 'lessons' => '14 / 18', 'progress' => 78, 'next' => 'Wasserkreislauf'], + ]; + } + + protected function tasks(): array + { + return [ + ['title' => 'Multiplikation bis 100', 'meta' => 'Mathematik · 12 Aufgaben · 15 Min.', 'icon' => '∑', 'color' => 'primary', 'points' => 120], + ['title' => 'Wortarten: Nomen & Verben', 'meta' => 'Deutsch · Lese-Aufgabe · 10 Min.', 'icon' => 'A', 'color' => 'rose', 'points' => 80], + ['title' => 'Vocab Review: Animals', 'meta' => 'Englisch · Karteikarten · 8 Min.', 'icon' => 'E', 'color' => 'violet', 'points' => 60], + ['title' => 'Kreislauf des Wassers', 'meta' => 'Sachkunde · Video + Quiz · 12 Min.', 'icon' => '🌱', 'color' => 'green', 'points' => 100], + ]; + } + + protected function rewards(): array + { + return [ + ['title' => 'Avatar-Brille (gold)', 'emoji' => '🎨', 'status' => 'Verfügbar', 'price' => 800, 'available' => true], + ['title' => 'Einhorn-Begleiter', 'emoji' => '🦄', 'status' => 'Verfügbar', 'price' => 1500, 'available' => true], + ['title' => 'Raketen-Theme', 'emoji' => '🚀', 'status' => 'Noch 720 Pkt. nötig', 'price' => 3200, 'available' => false], + ]; + } +} diff --git a/app/Livewire/Notifications/Index.php b/app/Livewire/Notifications/Index.php new file mode 100644 index 0000000..3dbff69 --- /dev/null +++ b/app/Livewire/Notifications/Index.php @@ -0,0 +1,96 @@ + 'notifications'])] +#[Lazy] +class Index extends Component +{ + public static function placeholder(array $params = []): View + { + return view('components.skeleton.page', ['rows' => 4]); + } + + + #[Url(as: 'filter', keep: true)] + public string $filter = 'all'; + + /** @var array */ + protected array $allowedFilters = ['all', 'unread']; + + public array $readKeys = []; + + public function mount(): void + { + if (! in_array($this->filter, $this->allowedFilters, true)) { + $this->filter = 'all'; + } + } + + public function setFilter(string $filter): void + { + if (in_array($filter, $this->allowedFilters, true)) { + $this->filter = $filter; + } + } + + public function markRead(string $key): void + { + if (! in_array($key, $this->readKeys, true)) { + $this->readKeys[] = $key; + } + } + + public function markAllRead(): void + { + $this->readKeys = array_column($this->notifications(), 'key'); + } + + #[Computed] + public function notifications(): array + { + $items = [ + ['key' => 'n1', 'title' => 'Heutige Aufgaben warten', 'body' => 'Du hast noch 4 offene Aufgaben für heute. Streak nicht brechen!', 'time' => 'vor 10 Min.', 'icon' => 'clock', 'color' => 'primary', 'baseRead' => false], + ['key' => 'n2', 'title' => 'Neuer Rekord erreicht!', 'body' => 'Du hast 7 Tage am Stück gelernt — neuer persönlicher Rekord.', 'time' => 'vor 2 Std.', 'icon' => 'trophy', 'color' => 'amber', 'baseRead' => false], + ['key' => 'n3', 'title' => 'Nachricht von Frau Müller', 'body' => 'Hallo Lina, super Arbeit gestern! Schau dir die Zusatzaufgabe an.', 'time' => 'vor 4 Std.', 'icon' => 'chat-bubble-left-right', 'color' => 'rose', 'baseRead' => false], + ['key' => 'n4', 'title' => 'Neues Foto-Hilfe-Feature', 'body' => 'Du kannst jetzt Aufgaben fotografieren und die KI erklärt den Weg.', 'time' => 'gestern', 'icon' => 'sparkles', 'color' => 'violet', 'baseRead' => true], + ['key' => 'n5', 'title' => 'Mathematik: 75% erreicht', 'body' => 'Du hast 18 von 24 Lektionen geschafft. Noch 6 bis zum Abschluss.', 'time' => '2 Tage', 'icon' => 'check-badge', 'color' => 'green', 'baseRead' => true], + ['key' => 'n6', 'title' => 'Wochenende Übung', 'body' => 'Auch am Wochenende lernen hilft beim Streak. Heute 10 Minuten.', 'time' => '3 Tage', 'icon' => 'calendar-days', 'color' => 'primary', 'baseRead' => true], + ]; + + return array_map(function ($n) { + $n['read'] = $n['baseRead'] || in_array($n['key'], $this->readKeys, true); + return $n; + }, $items); + } + + #[Computed] + public function filteredNotifications(): array + { + if ($this->filter === 'unread') { + return array_values(array_filter($this->notifications, fn($n) => ! $n['read'])); + } + return $this->notifications; + } + + #[Computed] + public function counts(): array + { + return [ + 'all' => count($this->notifications), + 'unread' => count(array_filter($this->notifications, fn($n) => ! $n['read'])), + ]; + } + + public function render(): View + { + return view('livewire.notifications.index'); + } +} diff --git a/app/Livewire/Notifications/Modals/Detail.php b/app/Livewire/Notifications/Modals/Detail.php new file mode 100644 index 0000000..08d5356 --- /dev/null +++ b/app/Livewire/Notifications/Modals/Detail.php @@ -0,0 +1,26 @@ +notification = $notification; + } + + public static function modalMaxWidth(): string + { + return 'lg'; + } + + public function render(): View + { + return view('livewire.notifications.modals.detail'); + } +} diff --git a/app/Livewire/PhotoHelp/Index.php b/app/Livewire/PhotoHelp/Index.php new file mode 100644 index 0000000..d524d61 --- /dev/null +++ b/app/Livewire/PhotoHelp/Index.php @@ -0,0 +1,23 @@ + 'photo'])] +#[Lazy] +class Index extends Component +{ + public static function placeholder(array $params = []): View + { + return view('components.skeleton.page', ['rows' => 3]); + } + + public function render(): View + { + return view('livewire.photo-help.index'); + } +} diff --git a/app/Livewire/PhotoHelp/Modals/Result.php b/app/Livewire/PhotoHelp/Modals/Result.php new file mode 100644 index 0000000..14d0802 --- /dev/null +++ b/app/Livewire/PhotoHelp/Modals/Result.php @@ -0,0 +1,19 @@ + 'progress'])] +#[Lazy] +class Index extends Component +{ + public static function placeholder(array $params = []): View + { + return view('components.skeleton.page', ['rows' => 4]); + } + + public function render(): View + { + return view('livewire.progress.index'); + } +} diff --git a/app/Livewire/Rewards/Index.php b/app/Livewire/Rewards/Index.php new file mode 100644 index 0000000..67bdd0f --- /dev/null +++ b/app/Livewire/Rewards/Index.php @@ -0,0 +1,23 @@ + 'rewards'])] +#[Lazy] +class Index extends Component +{ + public static function placeholder(array $params = []): View + { + return view('components.skeleton.page', ['rows' => 4]); + } + + public function render(): View + { + return view('livewire.rewards.index'); + } +} diff --git a/app/Livewire/Rewards/Modals/Purchase.php b/app/Livewire/Rewards/Modals/Purchase.php new file mode 100644 index 0000000..b1b31e0 --- /dev/null +++ b/app/Livewire/Rewards/Modals/Purchase.php @@ -0,0 +1,45 @@ +item = $item; + $this->balance = $balance; + } + + public function confirm(): void + { + $this->confirming = true; + } + + public function purchase(): void + { + if (($this->item['price'] ?? 0) > $this->balance) { + return; + } + $this->balance -= (int) $this->item['price']; + $this->purchased = true; + $this->confirming = false; + } + + public static function modalMaxWidth(): string + { + return 'md'; + } + + public function render(): View + { + return view('livewire.rewards.modals.purchase'); + } +} diff --git a/app/Livewire/Settings/Index.php b/app/Livewire/Settings/Index.php new file mode 100644 index 0000000..b5f5862 --- /dev/null +++ b/app/Livewire/Settings/Index.php @@ -0,0 +1,45 @@ + 'settings'])] +#[Lazy] +class Index extends Component +{ + public static function placeholder(array $params = []): View + { + return view('components.skeleton.page', ['rows' => 4]); + } + + + #[Url(as: 'section', keep: true)] + public string $section = 'profile'; + + /** @var array */ + protected array $allowedSections = ['profile', 'language', 'security', 'notifications', 'danger']; + + public function mount(): void + { + if (! in_array($this->section, $this->allowedSections, true)) { + $this->section = 'profile'; + } + } + + public function setSection(string $section): void + { + if (in_array($section, $this->allowedSections, true)) { + $this->section = $section; + } + } + + public function render(): View + { + return view('livewire.settings.index'); + } +} diff --git a/app/Livewire/Settings/Modals/Delete.php b/app/Livewire/Settings/Modals/Delete.php new file mode 100644 index 0000000..9166b9a --- /dev/null +++ b/app/Livewire/Settings/Modals/Delete.php @@ -0,0 +1,29 @@ +confirmText !== 'LÖSCHEN') { + return; + } + $this->closeModal(); + } + + public static function modalMaxWidth(): string + { + return 'md'; + } + + public function render(): View + { + return view('livewire.settings.modals.delete'); + } +} diff --git a/app/Livewire/Settings/Modals/LogoutAll.php b/app/Livewire/Settings/Modals/LogoutAll.php new file mode 100644 index 0000000..b7ba56e --- /dev/null +++ b/app/Livewire/Settings/Modals/LogoutAll.php @@ -0,0 +1,26 @@ +closeModal(); + } + + public static function modalMaxWidth(): string + { + return 'md'; + } + + public function render(): View + { + return view('livewire.settings.modals.logout-all'); + } +} diff --git a/app/Livewire/Subjects/Index.php b/app/Livewire/Subjects/Index.php new file mode 100644 index 0000000..1afc2eb --- /dev/null +++ b/app/Livewire/Subjects/Index.php @@ -0,0 +1,23 @@ + 'subjects'])] +#[Lazy] +class Index extends Component +{ + public static function placeholder(array $params = []): View + { + return view('components.skeleton.page', ['rows' => 4]); + } + + public function render(): View + { + return view('livewire.subjects.index'); + } +} diff --git a/app/Livewire/Subjects/Modals/Detail.php b/app/Livewire/Subjects/Modals/Detail.php new file mode 100644 index 0000000..53987f1 --- /dev/null +++ b/app/Livewire/Subjects/Modals/Detail.php @@ -0,0 +1,26 @@ +subject = $subject; + } + + public static function modalMaxWidth(): string + { + return 'xl'; + } + + public function render(): View + { + return view('livewire.subjects.modals.detail'); + } +} diff --git a/app/Livewire/Tasks/Index.php b/app/Livewire/Tasks/Index.php new file mode 100644 index 0000000..6b6c35d --- /dev/null +++ b/app/Livewire/Tasks/Index.php @@ -0,0 +1,105 @@ + 'tasks'])] +#[Lazy] +class Index extends Component +{ + public static function placeholder(array $params = []): View + { + return view('components.skeleton.page', ['rows' => 5]); + } + + + #[Url(as: 'filter', keep: true)] + public string $filter = 'open'; + + /** @var array */ + protected array $allowedFilters = ['open', 'done', 'all']; + + public function mount(): void + { + if (! in_array($this->filter, $this->allowedFilters, true)) { + $this->filter = 'open'; + } + } + + public function setFilter(string $filter): void + { + if (in_array($filter, $this->allowedFilters, true)) { + $this->filter = $filter; + } + } + + /** @var array */ + public array $startedKeys = []; + + public function startTask(string $key): void + { + $task = collect($this->tasks)->firstWhere('key', $key); + if ($task === null) { + return; + } + + if (! in_array($key, $this->startedKeys, true)) { + $this->startedKeys[] = $key; + } + + // Future: redirect to a real lesson runner. For now open detail modal. + // Must target wire-elements modal component explicitly — Livewire 4 + // server-side dispatch does not auto-broadcast to other components. + $this->dispatch('openModal', component: 'tasks.modals.detail', arguments: ['task' => $task]) + ->to('livewire-ui-modal'); + } + + public function repeatTask(string $key): void + { + $this->startTask($key); + } + + #[Computed] + public function tasks(): array + { + return [ + ['key' => 't1', 'title' => 'Multiplikation bis 100', 'meta' => 'Mathematik · 12 Aufgaben · 15 Min.', 'icon' => '∑', 'color' => 'primary', 'points' => 120, 'status' => 'open', 'due' => 'Heute'], + ['key' => 't2', 'title' => 'Wortarten: Nomen & Verben', 'meta' => 'Deutsch · Lese-Aufgabe · 10 Min.', 'icon' => 'A', 'color' => 'rose', 'points' => 80, 'status' => 'open', 'due' => 'Heute'], + ['key' => 't3', 'title' => 'Vocab Review: Animals', 'meta' => 'Englisch · Karteikarten · 8 Min.', 'icon' => 'E', 'color' => 'violet', 'points' => 60, 'status' => 'open', 'due' => 'Heute'], + ['key' => 't4', 'title' => 'Kreislauf des Wassers', 'meta' => 'Sachkunde · Video + Quiz · 12 Min.', 'icon' => '🌱', 'color' => 'green', 'points' => 100, 'status' => 'open', 'due' => 'Heute'], + ['key' => 't5', 'title' => 'Geometrie: Flächen', 'meta' => 'Mathematik · Übung · 20 Min.', 'icon' => '∑', 'color' => 'primary', 'points' => 150, 'status' => 'open', 'due' => 'Morgen'], + ['key' => 't6', 'title' => 'Gedicht lernen', 'meta' => 'Deutsch · Lese-Aufgabe · 15 Min.', 'icon' => 'A', 'color' => 'rose', 'points' => 90, 'status' => 'done', 'due' => 'Gestern'], + ['key' => 't7', 'title' => 'Past Simple Übung', 'meta' => 'Englisch · Übung · 10 Min.', 'icon' => 'E', 'color' => 'violet', 'points' => 70, 'status' => 'done', 'due' => 'Gestern'], + ]; + } + + #[Computed] + public function filteredTasks(): array + { + if ($this->filter === 'all') { + return $this->tasks; + } + return array_values(array_filter($this->tasks, fn($t) => $t['status'] === $this->filter)); + } + + #[Computed] + public function counts(): array + { + return [ + 'open' => count(array_filter($this->tasks, fn($t) => $t['status'] === 'open')), + 'done' => count(array_filter($this->tasks, fn($t) => $t['status'] === 'done')), + 'all' => count($this->tasks), + ]; + } + + public function render(): View + { + return view('livewire.tasks.index'); + } +} diff --git a/app/Livewire/Tasks/Modals/Detail.php b/app/Livewire/Tasks/Modals/Detail.php new file mode 100644 index 0000000..d70a90b --- /dev/null +++ b/app/Livewire/Tasks/Modals/Detail.php @@ -0,0 +1,26 @@ +task = $task; + } + + public static function modalMaxWidth(): string + { + return 'lg'; + } + + public function render(): View + { + return view('livewire.tasks.modals.detail'); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index c75b55e..f2a5e9f 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -31,6 +31,16 @@ class User extends Authenticatable return $this->role->contains('name', $role); } + public function hasAnyRole(array $roles): bool + { + foreach ($roles as $role) { + if ($this->hasRole($role)) { + return true; + } + } + return false; + } + public function tenant() { return $this->belongsTo(Tenant::class); diff --git a/composer.json b/composer.json index f930236..c8db371 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "laravel/reverb": "^1.10", "laravel/tinker": "^3.0", "livewire/livewire": "^4.0", - "livewire/volt": "^1.7.0" + "livewire/volt": "^1.7.0", + "wire-elements/modal": "*" }, "require-dev": { "fakerphp/faker": "^1.23", diff --git a/composer.lock b/composer.lock index 37595d7..b6b19a9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bdd78351d73171465c3922dafb001ba4", + "content-hash": "eac2e89f7c819b5d6fbfe22b5c260f04", "packages": [ { "name": "blade-ui-kit/blade-heroicons", @@ -4503,6 +4503,67 @@ ], "time": "2024-06-11T12:45:25+00:00" }, + { + "name": "spatie/laravel-package-tools", + "version": "1.93.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-package-tools.git", + "reference": "d5552849801f2642aea710557463234b59ef65eb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/d5552849801f2642aea710557463234b59ef65eb", + "reference": "d5552849801f2642aea710557463234b59ef65eb", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^10.0|^11.0|^12.0|^13.0", + "php": "^8.1" + }, + "require-dev": { + "mockery/mockery": "^1.5", + "orchestra/testbench": "^8.0|^9.2|^10.0|^11.0", + "pestphp/pest": "^2.1|^3.1|^4.0", + "phpunit/php-code-coverage": "^10.0|^11.0|^12.0", + "phpunit/phpunit": "^10.5|^11.5|^12.5", + "spatie/pest-plugin-test-time": "^2.2|^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\LaravelPackageTools\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Tools for creating Laravel packages", + "homepage": "https://github.com/spatie/laravel-package-tools", + "keywords": [ + "laravel-package-tools", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-package-tools/issues", + "source": "https://github.com/spatie/laravel-package-tools/tree/1.93.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2026-05-19T14:06:37+00:00" + }, { "name": "symfony/clock", "version": "v8.0.8", @@ -7177,6 +7238,70 @@ } ], "time": "2026-04-26T05:33:54+00:00" + }, + { + "name": "wire-elements/modal", + "version": "3.0.4", + "source": { + "type": "git", + "url": "https://github.com/wire-elements/modal.git", + "reference": "3c17ed4e5d1506773db37dbbfdcacff12b037317" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wire-elements/modal/zipball/3c17ed4e5d1506773db37dbbfdcacff12b037317", + "reference": "3c17ed4e5d1506773db37dbbfdcacff12b037317", + "shasum": "" + }, + "require": { + "livewire/livewire": "^3.2.3|^4.0", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.9" + }, + "require-dev": { + "orchestra/testbench": "^8.5", + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LivewireUI\\Modal\\LivewireModalServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LivewireUI\\Modal\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Philo Hermans", + "email": "me@philohermans.com" + } + ], + "description": "Laravel Livewire modal component", + "keywords": [ + "laravel", + "livewire", + "modal" + ], + "support": { + "issues": "https://github.com/wire-elements/modal/issues", + "source": "https://github.com/wire-elements/modal/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/PhiloNL", + "type": "github" + } + ], + "time": "2026-01-23T11:08:48+00:00" } ], "packages-dev": [ diff --git a/config/reverb.php b/config/reverb.php index e4dff40..dab0c3d 100644 --- a/config/reverb.php +++ b/config/reverb.php @@ -82,7 +82,7 @@ return [ 'scheme' => env('REVERB_SCHEME', 'https'), 'useTLS' => env('REVERB_SCHEME', 'https') === 'https', ], - 'allowed_origins' => ['https://app.dev.lernschiff.com'], + 'allowed_origins' => ['app.dev.lernschiff.com'], 'ping_interval' => env('REVERB_APP_PING_INTERVAL', 60), 'activity_timeout' => env('REVERB_APP_ACTIVITY_TIMEOUT', 30), 'max_connections' => env('REVERB_APP_MAX_CONNECTIONS'), diff --git a/config/sidebar.php b/config/sidebar.php new file mode 100644 index 0000000..6fd1dd9 --- /dev/null +++ b/config/sidebar.php @@ -0,0 +1,80 @@ + [ + [ + 'label' => 'Hauptmenü', + 'items' => [ + [ + 'key' => 'dashboard', + 'route' => 'dashboard', + 'label' => 'Startseite', + 'icon' => 'home', + ], + [ + 'key' => 'subjects', + 'route' => 'subjects', + 'label' => 'Meine Fächer', + 'icon' => 'book-open', + ], + [ + 'key' => 'tasks', + 'route' => 'tasks', + 'label' => 'Aufgaben', + 'icon' => 'clipboard-document-check', + 'badge' => 4, + ], + [ + 'key' => 'photo', + 'route' => 'photo', + 'label' => 'Foto-Hilfe', + 'icon' => 'camera', + ], + [ + 'key' => 'rewards', + 'route' => 'rewards', + 'label' => 'Belohnungen', + 'icon' => 'trophy', + ], + [ + 'key' => 'progress', + 'route' => 'progress', + 'label' => 'Fortschritt', + 'icon' => 'chart-bar', + ], + ], + ], + [ + 'label' => 'Mehr', + 'items' => [ + [ + 'key' => 'notifications', + 'route' => 'notifications', + 'label' => 'Mitteilungen', + 'icon' => 'bell', + ], + [ + 'key' => 'settings', + 'route' => 'settings', + 'label' => 'Einstellungen', + 'icon' => 'cog-6-tooth', + ], + ], + ], + ], +]; diff --git a/database/seeders/MusterschuleSeeder.php b/database/seeders/MusterschuleSeeder.php index c43858b..7616cc9 100644 --- a/database/seeders/MusterschuleSeeder.php +++ b/database/seeders/MusterschuleSeeder.php @@ -26,8 +26,9 @@ class MusterschuleSeeder extends Seeder $users = [ ['email' => 'schuladmin@musterschule.at', 'name' => 'Schuladmin Muster', 'role' => 'school-admin'], ['email' => 'lehrer@musterschule.at', 'name' => 'Lehrerin Muster', 'role' => 'teacher'], - ['email' => 'kind1@musterschule.at', 'name' => 'Kind 1', 'role' => 'child'], - ['email' => 'kind2@musterschule.at', 'name' => 'Kind 2', 'role' => 'child'], + ['email' => 'eltern@musterschule.at', 'name' => 'Elternteil Muster', 'role' => 'parent'], + ['email' => 'leon@musterschule.at', 'name' => 'Leon Muster', 'role' => 'child'], + ['email' => 'mia@musterschule.at', 'name' => 'Mia Muster', 'role' => 'child'], ]; foreach ($users as $data) { diff --git a/docker-compose.yml b/docker-compose.yml index d372505..7b48950 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,6 +30,21 @@ services: depends_on: [app] networks: [lernschiff_net] + vite: + build: + context: . + dockerfile: docker/app/Dockerfile + args: + UID: 1000 + GID: 1000 + working_dir: /var/www/html + command: sh -c "[ -d node_modules ] || npm install --silent; npm run dev -- --host 0.0.0.0" + volumes: + - .:/var/www/html + env_file: .env + networks: [lernschiff_net] + restart: unless-stopped + queue: build: context: . @@ -77,9 +92,9 @@ services: args: UID: 1000 GID: 1000 - command: php artisan reverb:start --host=0.0.0.0 --port=8081 + command: php artisan reverb:start --host=0.0.0.0 --port=8080 ports: - - "8080:8081" + - "8080:8080" volumes: - .:/var/www/html - app_storage:/var/www/html/storage/app diff --git a/docker/nginx/default.conf b/docker/nginx/default.conf index 82a7a4a..5a33eaf 100644 --- a/docker/nginx/default.conf +++ b/docker/nginx/default.conf @@ -5,6 +5,35 @@ server { root /var/www/html/public; index index.php; + # Vite HMR WebSocket + location /vite-hmr { + proxy_pass http://vite:5173/vite-hmr; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_read_timeout 86400; + } + + # Vite dev asset paths — prefix locations with ^~ to skip regex eval + location ^~ /resources/ { + proxy_pass http://vite:5173; + proxy_http_version 1.1; + proxy_set_header Host $host; + } + + location ^~ /node_modules/ { + proxy_pass http://vite:5173; + proxy_http_version 1.1; + proxy_set_header Host $host; + } + + location ~ ^/(@vite|@id|@fs|@react-refresh)/ { + proxy_pass http://vite:5173; + proxy_http_version 1.1; + proxy_set_header Host $host; + } + location / { try_files $uri $uri/ /index.php?$query_string; } diff --git a/docs/superpowers/specs/2026-05-22-button-spinner-overlay-design.md b/docs/superpowers/specs/2026-05-22-button-spinner-overlay-design.md new file mode 100644 index 0000000..b434354 --- /dev/null +++ b/docs/superpowers/specs/2026-05-22-button-spinner-overlay-design.md @@ -0,0 +1,86 @@ +# Button Spinner Overlay — Design + +**Datum:** 2026-05-22 +**Scope:** Auth-Page Buttons (Login, Confirm-Password, Forgot-Password, Reset-Password, Verify-Email) + +## Problem + +Aktuelles Loading-Pattern der Auth-Buttons: +- Text + Icon werden via `wire:loading.remove` ausgeblendet +- Spinner + "Wird geladen…"-Text werden via `wire:loading` eingeblendet +- Button-Größe ist stabil, aber UX wirkt unruhig (Text wechselt komplett) +- Spinner steht links neben Loading-Text, nicht zentriert + +## Anforderungen + +1. **Spinner zentriert als Overlay** über dem Button-Inhalt +2. **Button-Größe stabil** beim Wechsel Loading/Idle +3. **Text bekommt `opacity-50`** beim Laden, damit Spinner besser sichtbar ist +4. **Konsistentes Pattern** über alle Auth-Buttons + +## Lösungsansatz + +`relative`/`absolute` Positionierung — Text bleibt im Document-Flow, Spinner wird darüber gelegt. + +### Markup-Pattern + +```html + + + + + Button-Text + + + + + + + + + +``` + +### Key-Mechanismen + +| Aspekt | Implementierung | +|--------|-----------------| +| Button-Größe stabil | Text-Span bleibt immer im Flow (kein `display:none`) | +| Spinner zentriert | `absolute inset-0 flex items-center justify-center` | +| Text dimmt | `wire:loading.class="opacity-50"` + `transition-opacity` | +| Spinner über Text | `absolute` positioniert auf `relative` Button | +| Disabled-State | `wire:loading.attr="disabled"` (unverändert) | + +## Scope — 5 Dateien + +| Datei | Aktion | +|-------|--------| +| `livewire/pages/auth/login.blade.php` | Pattern umbauen | +| `livewire/pages/auth/confirm-password.blade.php` | Pattern umbauen | +| `livewire/pages/auth/forgot-password.blade.php` | Pattern umbauen | +| `livewire/pages/auth/reset-password.blade.php` | Pattern umbauen | +| `livewire/pages/auth/verify-email.blade.php` | Spinner neu hinzufügen (gleiches Pattern) | + +`primary-button.blade.php` bleibt unverändert (Slot-basiert). + +## Nicht im Scope + +- Andere Buttons im Codebase (z.B. Dashboard, Settings) — nur Auth-Pages +- Änderungen an `primary-button.blade.php` selbst — Pattern wird per Page erstellt +- Backend-Logic, Routes, Auth-Flow — reine UI-Änderung + +## Testing + +- Bestehende 46 Tests (Pest) laufen unverändert durch +- Keine neuen Tests nötig (UI-only) +- Manuelle Verifikation: Login-Button im Browser, Submit auslösen, Spinner-Position prüfen + +## Verifikation nach Implementation + +1. Curl: Login-HTML enthält `relative` + `absolute inset-0` Klassen +2. Browser: Spinner mittig sichtbar beim Submit, Text dimmt, Button springt nicht +3. `php artisan test`: 46 passed diff --git a/package-lock.json b/package-lock.json index 59d38c1..2374e6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,13 @@ { - "name": "lernschiff", + "name": "html", "lockfileVersion": 3, "requires": true, "packages": { "": { + "dependencies": { + "laravel-echo": "^2.3.4", + "pusher-js": "^8.5.0" + }, "devDependencies": { "@tailwindcss/vite": "^4.0.0", "concurrently": "^9.0.1", @@ -2440,6 +2444,13 @@ "win32" ] }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT", + "peer": true + }, "node_modules/@tailwindcss/node": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", @@ -3299,7 +3310,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -3414,6 +3424,30 @@ "dev": true, "license": "MIT" }, + "node_modules/engine.io-client": { + "version": "6.6.5", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.5.tgz", + "integrity": "sha512-QCwxUDULPlXv8F6tqMMKx5dNkTe6OaBYRMPYeXKBlyOoKvAmE0ac6pW7fFhSscJ/5SI7666/U/B+MElbsrJlIg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.20.1", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz", @@ -4600,6 +4634,19 @@ "node": ">=0.10.0" } }, + "node_modules/laravel-echo": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-2.3.4.tgz", + "integrity": "sha512-rpALCIK1uw2SrttcK9P5JzItt5I85RcfXQKUNnkcorzhtKeXi5GS0PVFFBH8ppNo8wnbdBKuD1EtIHgTbXo9FQ==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "pusher-js": "*", + "socket.io-client": "*" + } + }, "node_modules/laravel-vite-plugin": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-3.1.0.tgz", @@ -4972,7 +5019,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -5199,6 +5245,15 @@ "node": ">=6" } }, + "node_modules/pusher-js": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.5.0.tgz", + "integrity": "sha512-V7uzGi9bqOOOyM/6IkJdpFyjGZj7llz1v0oWnYkZKcYLvbz6VcHVLmzKqkvegjuMumpfIEKGLmWHwFb39XFCpw==", + "license": "MIT", + "dependencies": { + "tweetnacl": "^1.0.3" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -5698,6 +5753,36 @@ "node": ">=20.0.0" } }, + "node_modules/socket.io-client": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", + "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.6.tgz", + "integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/source-map": { "version": "0.8.0-beta.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", @@ -6039,6 +6124,12 @@ "dev": true, "license": "0BSD" }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "license": "Unlicense" + }, "node_modules/type-fest": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", @@ -6753,6 +6844,37 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/ws": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 2b924d3..bc74577 100644 --- a/package.json +++ b/package.json @@ -13,5 +13,9 @@ "tailwindcss": "^4.0.0", "vite": "^8.0.0", "vite-plugin-pwa": "^1.3.0" + }, + "dependencies": { + "laravel-echo": "^2.3.4", + "pusher-js": "^8.5.0" } } diff --git a/public/favicon.ico b/public/favicon.ico index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b3c8a772311b49ff2bf8614efd272d9afb99bf22 100644 GIT binary patch literal 15086 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 ajg#yDod)3(bN4_4P*-{Vyi^Gq{67F5PD}9s literal 0 HcmV?d00001 diff --git a/public/icons/favicon-16.png b/public/icons/favicon-16.png new file mode 100644 index 0000000000000000000000000000000000000000..ec161854e51b1473488c07b8194b7cf7c0176f96 GIT binary patch literal 1208 zcmeAS@N?(olHy`uVBq!ia0vp^0w65F1SAhIZYc#)3dtTpz6=aiY77hwEes65fIk)0a2`4R&IbF-(5V~EA+tyA)Su9V6gzd!%|`|<)A@q+pp z7fv)eHe7nU=*YhvhjNaJ8qZz3c9zoOn_hP(d^s2z=5s>o8uQymU6~yRn@v(h7iw=z z=$Pa9b2*#r^i&RYxjE%`} z!Xl~B%@fdg@V}-pLx7cug4XgRmBu_-1;+-Z(u+>-Hup48FDk7d_=>)7-Dp8lS2wcXw9 z=GDckLd3$C9p0fBoDt<$_CHE`?KXZ(^J8no*6*~r*&u(Cnfbs}bJhdx3XdMG*s!3h z`OSe@3-3*AuKWGo>UsCXy33oNExvg^nNc^_cFu3_mUr1D`4U zyd@_Toy)e?&3{$$EvdHq&5>}6KKnqAn-c{5Q)-G2gjNVF{hZPI@?G}LohLV@S{JD^ zF<1WHYC3swpQTdA9u}Ao<#B8fKACL2_Gpk?rYwrWAE6cR+ zT}klS*<$|D^3MgQ+T{5^rC9{s=GZN@(h{inOgx3paU`el_Eg3-1<@X92ZajOWyQnqPYur@4J~oxtlK%<~*qb>+h$od&HJsDqr$$ z`d;3p>qVZFuC<7MgTe~DWM4f7TXK~ literal 0 HcmV?d00001 diff --git a/public/icons/favicon-32.png b/public/icons/favicon-32.png new file mode 100644 index 0000000000000000000000000000000000000000..b847e612a5b670a2f92a449b3920319116a30c6d GIT binary patch literal 2407 zcmZ{mX*kpi8^-^PnK8Dp6()_zexhTV=u8-fEF)Qx7^iG8WEloysWWNpQA&v{LsOQq zMz2J&wjdE^hN&#!c~JF{k?b*9BcsKhB^Sy;{jm%AfnFzKsXuz<~#sEKMMflD2#>+h6e}8 zRclMLwY8r=mzJ^ylhqCq7=_>x1^|M@|0=h=x#l2*Qmt&vp>yEFGO|ZAF4V9AKp10X zX5x5lbTRu6YN|6L=}F|RGa7zba3v#0Q6O5|=92S1S+}msclV z4R<{&(vCc(pE%1#h)*C-E>$*&D?gL6VoaV7lQ}a@`<`$7Fw2E}_neH&DbDv>-?s)w zr$>7C79*E;qaBD@PnN0vJ^Q7O;ZXaLZ7}|CE5ib!qIl&(q!H?-nuQ>6r|hFf(e62e z}jx1*+ci&vBhRUya>lj{0;6|I3hFhmzK5Co7+s$# zZaEgH5~*8IU;F{;Ju;P~FCqO3S(VNQ2japhj4NRu~6KDe}&4Hn^~+$X9poG^6$UgY_L+@Vn?G-15ugAcjY*+iQ^ z86d8yvsL?2aJ%ntaO=evG5a*=j{UF0*U~gGx4{DhaWB;?KYJM$8il4Rhq2@B_%C{M z#F1f&{0-b^k(Btf!^e`FldB{9Uw>Firp(^y#udwS6XvrzhgGN#>ehx#}9&OsZ)JCe8PJb}@P58piXI`dtpo^)dUWk%u)r@|o z{yDEed?j09@KVhiMfnrUVV+V9%b4@m zQo#_Y91aHO_kVsN9LwIhQ99_sADuy^<>3#grVkIXw}}^) z=^N-7_ZH4N9lPn;#pFEYj4_Nx16eu?{>|Z=#Zgh?gdtVF#O*ES7K9IrntVV%&p{Lg68KDt3?uTal%Op1(HM! z)WF`EK=__|-w2E$1%?e?p|p6|dK@RF>*_0Xs-&H7b$vbV)C>|66C!lPh<2ZJs#pTR zGAW2$nendMt8#Y?(~NX=+Nyr5x8TPokW9DjSv`sp=H!u)a4qz1rDPtUnx616PbHL8 zK3CU<+IbPvo&FmP>ZdGTsHS?FfBH=Dp~+yqm7BgXqi5l4lhgv82oy6VD8pExwI#^w z*e0DjRY(Ol5H1VieXOk$>Gf*v+n_a=B;D1Utwb4X-TO0WAV}doKv2j%*)|~WZ>02% z!+|g8HTK@v5^!CWmdKQ`yS+N8E~%;!b%V1I-7_ItYumx0<2Y%2;NtwGBVbv zvdSKx9M|>r>aqwka4eJ5)Zs|E_t|~s8{8*{#KM)FW@jz8{fJl!So*iez)OdU=O}Bg zFoIr@?%cI_v-tcm7!{$irc1F4A^)U_l_mUcalD#f$=>Pcp&I13!k)9PB&kX(#x*Zb ztw0YI>6BfmZlAl1#p^w4q6rI>2dI6!+Io#__E32HuI>t|-nhWDW6UhlVAM`NPNRQVqi|ZNDVf8&;%>0Zy#Zb1X z1L#yBs#srJBgRQri?`z(G6D6kGEA0htWn*f7siAT%sGM;gHD-9cyFU@?brSL=;wYd zt<^yuLWs&o?!UZW4OQQMe#x`k+tT?lmva5cLo3$ILo~Ibt!`vlzwL@}+ zytuv2L2s;-JV?zkBn!uI&q&SM!(p5#FrLfgJIk)`h}6_=LDM)K*K^RwiBdZ?xxO1YH5SrMn{UA2r7NqX0v(B;2B0} zUR2V26ZMGPVPXvx5y0eEtn)yIl5Z+gn_dZ)zi|5)SmH50zenm26_~ek5-VVOg?x(K zxrcx9+KvRd5oh$?CDg>7_jTWIjMT7kn&@ve;%qnIJN6X5AU6&h)-f|pGHr#(s&}A zD*RTW4r_?NhjDzRy5OJKP1pHTqQkc?*6u#-`gprM`bgGvxE!;_?BW|~fh+y9vI4g< zH~a+7@*-MX>yC*wWN(zGfHsx-b)K}B8PMkjjRnGy z{&$6&BGL~Y3N@-Zk?QS9CFy&Gk`4^OpfRUUp!H5*FpekB=ws0Om@`^vv_2Z0h?dR! xKY$$U?dNm-pMec>#jyiG^M4IgKQbwd>Pe>jGsBEZ-8*0aD|1`3=cXR9{{aPtP_Y02 literal 0 HcmV?d00001 diff --git a/public/icons/icon-192.png b/public/icons/icon-192.png index 2542f79af8f6dc3ba8117c7893869c4a7827b0d6..1e684ea9b3ace831afb1a6a54994df867c9a97d6 100644 GIT binary patch literal 12480 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 literal 69 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2ryJf1F&Ar-fhe|&hS%D_64=>+$e RN@k!qgQu&X%Q~loCIH@95Y+$x diff --git a/public/icons/icon-512-maskable.png b/public/icons/icon-512-maskable.png new file mode 100644 index 0000000000000000000000000000000000000000..5532028f5ded1d30d24d14fadb94c54d570a411f GIT binary patch literal 30904 zcmeEthd0~*_kRdt&(_|pQCsb;XiLq~7PW%b-XnG-Hf?E3Yp+(Rwun)CB($hql-N<5 zAXaRC(f9YS_?^$|oSfvm5>NMe?|nY**?Hi z6g-KY2?~GwcoM%eH(64o!1!R5tB8Wql!Spq419-PC5h`HwuK*WTdDBq5rRL7l3$m> zBy?NurlxL13HIRPO@aELicE@3wBWq;+@P}{Z7SA(JL0Buh5MYlxS6%JMMkQlIRAf_ zAKLFrBY@$*>v-c9fd0Rai2zD~&VLs_jQIb4@P@nqp!wg;o5aHZ`|1BQ@IMXwPXqtc z06_!C&SK2S(c6i^sA;zWnFEx8f^k+Ycs=7<_+y)*1l>jH#2;YfOPP*Dkbmu(-u`wZ z6n9vckZ@*v1+y0vW^<#RbX#g$%Eg*`4ileol-(&3(3`Sc9*t_b0$>SQp)6Ts3Z2=X z$1f5%?4| zNvYW|Hl4Zcw&>$`T_T^?QyCaa)vo~vo0KtH+WQ#NY!KEhd25U3f@oIa=wvEl4mp~# ztoDA2wj3JbGT7+cv11pYq%6%f>?A06kPL_f+IjkmnLJREKm%)G^lpZP9nFa}l^AF} zr;1EU?0}n8<7Nz^qV9YO-1M-Jb2Hx_qCIk(7>@7Fk8d`6!0n$OL)CRqeqDw=!vUX4 z-6vH3#aK_LNZHgsEus7JXFLcP{(L2s3NOR4?5_AaJ<`%gNwx2XFPqIg_TyHV_XttO zX>U?!?4YKt>%78z6K{>s8Lcz1K-xUYAeqtC49l-17CABj;Q7roJS=GC-Sho3vgugh7vzIYh`A56ZwD(Kv1rPhB_z4 zcJ`S<3~=i!KDgT}Hz)|_P%r1G)x`C^uy@e&?LrkMt8O5?cJ`Uefpv%X$2oY$$cHSI z9q^X4I2+kb#?vllbA~q^PoBGLJSRbbdzD_a&nk9^jo84yBy{JO&=MTw@;#3vS^XOpG?9Q!&$i!q$DpUV zo!vgK^>I7XxR=`XJa>5k!3}M+@5HQ7k8zCVA%;Z3yv8Qc0*SSxj_88cNCXacqJNtvNu+Kz!t ziX%%n_1WluGWPt2+374wejxCz#R>>cUjDrcCq{HRl}f;>=fyN{8bn0nmm&PLuI;>KaX8l_3t6WrnU8X6BWz2c=;dy1tTrBl$e8~ zT+=iWcZ1c8I|hWRcxVsfDmuluEG{@bG!SzR!b^csNZGfyKp(y<5`1Lt zj@cDdd4Ue=y!3z{;QSAK3o#$xlFmQHZIEtgNHlVH%7>Is;TeO!U4pQ`;>x7MdV2F= zxMMGcWHM$%7C&^Z+~jIAKA5&-YAwvH)1b3Db|!thJ`9uk@^1S3TskIvzssXgbq^mI z4T?Ex0aEysCl^@slpJ`VhdS=q(a~A-F3i5i@aD^tiFLOV-)o8V;WB4=ui(?^l!CF! z?JR?X?(g?xt*4I)Rcf&@3Mxh%2yb$1MLrAVE3$!kTX~{}Ym6Tpw#vLp?=G4s9!(V` z+!piU$u}V(ZTMuh86@TS^UEkw0rxDW!aQx7V$U0G!F_g(@^q=`xm|G0`nQJ7FS~{j$!)!0<-H6u`@GYV(*D z-7i30EYDi;%bE9D&XZ~WW}@9}W~KQ;Twi}GPq!*XtIUh0#e=99D*0!Yn@@($&mad2 zEbvQtyEpzc=uo_DQ%n*^SS%6$?tPHT8(W3+RPsXO4x3=0eEC4L(iwU9<=7XtB{Tc` zUDz!z1>tF%lPVQpJxcYiSjJAyT~(hdXj4MMBj>A#=9XmgbNzBzW{-gQp*T| z`8=e6IBNX9nWTz1Zkp+KAeF2{iv5KbY)Vd& zBNzFOsWvRC+^zg)qPVwZJ8_1TyE^4~y>XRt$>bTt| zCB&roY{niRRG+-$Fl}?R8r>e(V(Y^I?bQbsbDk^p!xy+^(UB)x?sRp_hKg=oB~s^2 zu^W3;ysTX74u?@IhM+y-j1xf`ji)M_ManAZ;e0JlT1C;^8-^<6;*{Gc==4$@Jks*j)r6Flm#w5YC>aA(W4%9by&fS^rqe4?T7PyBd3ku*)`K$ z%kZ7K0H-*am!TM1AB{@yol{8kWS7mK9o7^}7E&4+O}a!WzDa$&XqDS-)1H+6)#EAT)8wLd z)5mvL-O!N*7`{5%G!h_DHXyHZz_Jgx623qWOfxGghBCbAF1(V=^sxlLOJ~;nD9~Hn znBTuZ_Dgtr6ZzQ7NeJZE>FeVTI32P3{P^McoJli#vU|wlVvL-R*ABAGRi+S+EaGmh zrRQX8{T+w2b>gYEf(eIbxd`sseX)Mg@lqO?NIK|KlB+~RN%p=NJt5^h+^Dt`0bau8 zmc;Jz`rFU?&wnh$Yz?2(lB-tdOeu1!8Y>6AA*Nno6?5BUVMsK&LWv@+rAI{3$8SHP z6ne9r&R$37(M8X$LF|St=~KDC z4_Fe-n@{&*cfci6v5PyWX+#XiE3^Yk+a6gM(iJip)P9WSlU2?z@w45t_sOU-1U7e5 zEy@f$)2ikiN2WP@^w$V4jm!BPt_Nt=&y`eU>Mk~4V!AM;Il8N(Lj)u6R!2|?WzI9q zO`O7x+OrS5L1y!aA<82>>TYF7g#BjbRM>kck^ZT-i{;s^oN&mX|63K5G+o{KtqW!! zFMo(M`Skb<9#4xnzUB&)esd|n&O??{kwaEY^V)l^03e@}+Mu>Ce>UvCaRdfgq&BGt z%3j0M-Rk!H$gA2Bk&%x&ZEzM(2U?0DNvrOZo%8eWwq2EH-e@?3EYqS#kRj1lC}jhC z29Jo~L8|Aeyn7#kgJgK*`d)3hs3ol$SxwNwcAU(XnwMAEV1c2-LbYRZ+z{0~!jou= zHR#Pby^rieO@5QlemkvXPK|n?lt4;W61J|DS{lhHQaf)|K}DXih{hGXi5+@LLu#mn zzQ-{-XyOfKN748iX{+EP9#rkxm9O&H^zjO>{D> zST#IN6BRkb7~sBJPS178zKLR?-xzDRyxVF89(NFEeC$$cP%}dg$lZJkDjxtmJK3t; zi*~;Ad$H->dSJIQI>(;cXVjMvoGTZMwl?vG=Fxj>t7o=UN;8#p7s4}JO= zb#JT5DWnAAt1!s{Nca0Q5zv{qp^YkdIqS(XxleqE>$7930&1?`3u?9S~oo^wbNz&Giih20--Nnos9{wiI^ju&4K zK`a!1JK7DwdF8ILY3Nm%U^y9WCV=`?YeBu|v5 zvt4CH)Qsz)sqG&jp*I6X^zlF^grzfk^zn4x2c>5<1Gi{2fNkn6oA1C}794G-o48Yi z0MxE!NRqyMd(56pQMA7zfH?URjXJL#7eTPy@rMNN!ylOfUV<)1E5_Z#9dSu+!&>{dgoX)Q^!FHDY*Ai59s`6&G>$INOSkXEb$AxcL+Z#jn&w8i=rym z`^dHqCQjPIi21q(h8*z$if1tYQl-3)aPU$dE8pfTK7w#+WzAyz{Eu&#u#r!D35+(~lQg(D0~Sk((@l6=h0<}zTp{(RkHzelgnict2yerlF89Q4l zb*?HG(~0M}-m0=Xk|}stVZS3Vm@$`LD2h#w$KfafbEQB9QxE~_9?`vfah@60FU%e_ zxWf)a7to|q@Ra8q`{Msd4c1i|&pTMKG%X~hWezz%E}5XPDctKV+e*l#dzgM4s+K;65K<797%F$L1*1(C$ z>+?FUUDU#bgO3Xbr=FL=ON@_#J&WmPXH;6&F76>N;JGsT@$iTq=rb9Vf09hsOW?>H z=Ux8E$C?)PAo*#6z_w_ z=!Bt6(4Df=%Fj&SR6~2G1b_u4o{?_txjxfH1D;HgQE|qjwrktKWx|ObM%lVJPaLAW z5KY3Qsvrfg)Q(9MxU^NTlPGl{z>G)OnV*?f)ieOE0(ioVo#b2xZrpcn=1~SRSIkr? zTY&mzmZi6VgF*w^oHVk8`pj!1zsLDm1faXTdlkJ#b&GGU>A*|gteC2U2BEtK^u^;g zXjw_>kpVj?L2njo+*rXIS8dEuSfh0Ynld@G;6TN9if?J_$HlBYcoLCHjj+U%tFU+w z3B=s-McTJN!H508bip$1w`6aDv-W_#CIOF*Exl+xpl;q$XENVHU005VvYM59zkEF`wW5vEQz1Ixd8Mo?{crz9QAK?@dp|xL+*`ZQ!y8E z-sjC>H=3vRrl<~iDD*izGORd30+MNxKK{rZCF4vEWVlCX<`d0&zb~+2s!;<_{{9@; zh>tnPy^m;wn)rqGC%iJcDrEaj;U`>2&7Tr7Nc(B;@^|4dDyN7>K?M`C+0H!U23FO~ z0SPidpx&@e>J<-PzY3}ysUSMC@RYD^S!TS%fFVuj{IP$DYT9?!Wgd%nPZb&C0@ea8 zA4IGMdd3%0j1;&!oUlCXM@5zgm4?tyBU)mekw#T>Qy#pOZDdh@OqRZ!6sNdG)Ab2p zr49M^W5Pb2li&{q>0;)h0w=wY{`SH)|#{dO93oGi;#f>U&7_)?CYc z3V(W}UwAQHLo!G0Bd;=^^&1>N>5Xjyk56u<5zi(S+_`W9v243PGxbH*EZ-jiOpk1i zK-4%9Ke-Qe(feShC!a~h)>=HRR<(`5TD)KV-a%W^2{DS* z>zXz3$hf#ce>TYtukA>~bz`5-FAKJ%2f~~? zZcGkIe4j$JB8+7f#rxz(xIAh%T~?yRi%3|?xNzo5is>4SeiD~-*Zq&zG;dgu#In2> z_g6rbuL5nRsq70U!teU<^hsDYDfx&7PldMrHNy4dsEfpXn2xh%2_XCCp5aS=e#VKa zUqU2#7X#E=(HWqR+`hG_mANxn@e;Y|+bf^UATQxTt>?w37lw%Cm!2hQt-zn~s*(=L zs5K9K78A1B)k~qjH28KIe5ugiN8*xICc#1~yMIKGriX{Nw${0Qpc$(&1DBHV47>-v z-du_6!Vb?!)pecR2L?rH^ftZkLLE zpMp|AvT}_jFdbiKVH$jol+xR>UEwSS8Ha{8DL0OS2`wJ*v#6w?7co7 z)RB5cmvwDxXf)F{uP9F)Gpc?XkoX{)vhw6WFYyZQ|8@5+-uOjXNGW7h>w)ZED)cBK zpmWJ3`YBOiU9BMh|v*K1F9$d*2VH?F$K*Y1LHy z))=tTU#O3iLCK^oAj4YxZ~G$2wJe}ijD+suVo(+_!NGQ&(@c}8mi1)f1Tm4nRl4_M zV(rQ!zPj9aDQzq{2jPFYaWb|(;|V^V?*IMM{LXAQf8?r?&*3Dbk94mrq=%E}2YqbE zw*Sn5=mV8W(-UI<<`5m?-5%G zFTWRlL~R^255$7Yop>uX3;eDECI4lbG9hKrxnM#i5tXoMNtz;gcH<1`G6H*s^(nWa zuX89IO8Cx?7IrD$qOm{9K8K95lhT}&%&ghbRhItNOJ-TU3rYn*s&b#xJvz`kKcMv* z>7uRjEevm1yYj5nexg?p3z66 zrdj zuDDXK1GptwtI|{$9_qtehssm%Z=+}<%ddSJZhO3m*g5IT)*g(q^g8(qlF4KE0sNk6 zz(9Zh5zS@@;ry54udgGbYf48`#7x8@uE*p#oJxU`{CnP8vM_ti49lX4mvg@3*EIoEb=Qg~zM{C?HEOcq z&~Pn@>&8cFk0bsNJeNQ9b`U{^bqwYaTr?!A4Aa>lvl;SwX8>x)OFj51XIRah{bklZ zE?Jxms<=H~dn{gfR5Q#PBvzk_{XI>S#-v!pMfC2)@r0-cMRtLhV13dZ#91$wP+V(N zNku+X>sJZxc%)5MEb=;DLAZIKjBd;5wA_YFb-?`E$1y13Kf7sOwO#oC{6>`$=TE*q zXD43J`si`%Duqs6QfSX*t0+S&F|mt(OJxldoDS;xJkB0YvS}r|&7(pTo;b@@%$HH@ zQ7lQXJ({0%t{p?P`ty8IbJa0O&dlC970Wlj05+{Vc22V)4pU*y+2n>HQwy!wKzK$g z7X>2m&-%E+hJb0wdd zph3GjN8#zcjg302G9#pK@PULkMd1%0*fLVv;3klq@r36EC{Fa0RDFS^2h}o~*J+JD z48P;4Ks5UzPo)y87koUNdF#_5vfS8z)~6zN_d9A2+W_vG5N;xMxvQpnRx4aU@XbdW z{~}c>1ugC5$DIY3(mO{zqHNdvYDsOpTnGzjqdn-?i~L>^7f~ORjaAvkjHmWuRmh7Etd=FcDMISfun?ZO zVMDmL2NTA!bLSdPU?L6Zdeh|!Axvfd&A2FW9_=_FsXuV&Y4Xuku_bYfWU{I=BvCym ziLdKO9gGMFS=J>K6C<*ifQ8aE0d9BZ4?eli#DX_WQqIBmc9}^vgP#8Vx}JJff7iZq z#kafXh2a*eU~W0{->lvI*)u)`HJC3Z=IBHFJ2h6cv!Sh>eWdN|vCa3Z z5ODopB;ZV*PI7|!v$yEM(HkFp$vR%MB%iB3C;egl*H~KN&f$#s>|QMI3G-Zwle!PJ zIF87E`inX#VJu6j=KucQPxvNvUZ9cC9<6Nn7s!oBVnuOu=Z>cIr+RRn0?QkK>ztri zAe3n3=?duxu)ElV;h%f{%L=>gyS>1mPZ*7kx-o0Yh;o(N;yboD>+O)iGZJ*trQ&Iy zZ$Jz!>fT_m_>tt{%LQBT^(OMi2bKi!y9gT z$FhiKLCp%;Qee^dC;r@0Olzbq%r&7y<8%(g=ax>_U+ajG8Ilshq0-BLgJViL&)yo+ ztF8_FT$a)0Nrj|u3*f#5Deux|1PtRkyhYE27^8`tzpojneExF_TDr%l=&fvK$io|L zElw$XWdoD{Y*4vpX~?G&h}QtyMme4age%Om_;3gA_K#eit@K$si5eEn^wMw+YT<-} z{evkpx zQEsoSsLNdD0ahMgSQ!YSH=i-xGb6h4O5lG)3MIF5dFK6#H><{vEdSGr17xaHV84R4iK%`e(1)kYQO*EB>}q9+ffkus4?8V!>gI7wO*PP}ZuEza@SrsX3%{tl6CCx}_@8o1f7#aBAy^#b?~6ky3)}~5FOH^A zoKkZ`?;4@~kFOhvW!dp!7hQbY)iiyBugjH{Ty`FToO zwI8CJ#Ss*@qNunr0o8X`qZ<(Mk8Su%NN_R-Jc~59Pdq<_*WC#}U+ovJ8~{DI)kUgx zxl|kh%EuWy@jV}M@XBRTy{|bcXcy5+bb8ay%=!<@9fE!@xc*y&cPh!>g7z27P1UUs z(m0#ZprCa&u(izizG95z=$p>qd9 zjG2L;AB&3=)%a+(X0Xd;A)hv>3q86;67c%yx2A$h~jox>zW zmGQED{IW;l6KCk`pV0aWmTzKn@3`4%?;bC)#LtmBzT{)uq`ea6)j!T&M24WUxXTbM zvD56~bmyt%u!R#Yvqo2;-PxHi`*oz`kN0BO=Mm%Fv`NP+-y?848 zMZ^*srD`M*z%zZjcO`yN&R0lD0XE}tS{*+ZMNC+w6#CyPju39qTO{84DaU)!XKtq{h^p<8Yqb&s6C@mWo5iF0m6D%gH-#H^f@qf3+7+$N+p#{QXB zov~HGfkfOjA&G$yVyx`c``k16z$*v-LKmUcu_j{_?6U7huEx%7e+rP+dAwEm-*=dBWqA&Dt_Lng%;?FYf`D2!26_r1=_Mm{w zi2%f*y>1zkM(;5It1th`^O3=GLQs0+c88~jprt~qh%wW#or`J$}^~{T|LjS=hKPx4p z&u8!LZ00MzHmi)_omso1;Nu1HQZSD$c~O^M!Vo;S2i=OG4_`T|*!@mAr)(GJO&J^) zDv5)TuBflvS-Dq`t~9m}peEZBS|6+`c}>yJGWKh4G-@=NLP4b(sg%zpOZ24L>OWDQ z1iJAP?3QSKu*oI{k702T3T4*%2oF@>wWA{RQ0zRYcwgNNzr?IqTeoXEEBoJ6T*!&< z^VFohyByrzqFxv2#rVvyuc!Znv1+gvx{kCaZ)FVt4&E94{CVZ$ZXx8}=H7@`?0)XS z_GblhH?`C%UICVF+3bE|AIX{(v^(rBq|nCTZdVi`?;!M^;67)}=H;_5$to%jCfx)pJk=T^AY zUqg&C={>SRdV9mki; z!-#6fW~)3lG`sUtFSSwEbQM+R3y;o+cK1y z+9+j?4Uf+)6n$TpePy_@pCD;mG&&5imvkk8Z~E&v3R_&!)2SpIUC+vWwqieIKHunw z#bi4Btd%mzXrec1gF%nR5D_r%2F&I zW?}Db$efx>osCFV$X95~;rF&jT{-3G8xP!1!>3J!RRmspo|?DDr6j>40ew1q>fYM* zP(=YwIx8sJZ=g2YzVp|dnv@Ksdg-}d*PwD#%a9SG0?y=T>*I$~8aW;cVQX$_iEif6 z`t?VEP?w2cy4#y ziAerVGpat(WkyDLWsZ(m22lW#PL`LH?z$Q0m0C2e2JLhfc_|~_mbn*WB(K63P zt+)O205?r0?W~i(mP0KabYvF*LA_~t3Q3IMi4ux8Mtnjt+oHO>%Py8f{eg~rvU2;r z!NeZ7vu)?X0kci3GgNbfu-GzY?zSUN+}3_vOD}w*{)NmX>iByxO&PLJwz_W|lew0; zbbLaWd;T-#R-Ex^q~95fLi^TClaNzD{6lfc3B_Gsm!>k$!!c*rA>Ve#>?vy2dHeeU z{OON*IL>A(KAg5pqN47X3`<|&O&pM9EZ(bDK{I4!i0Wk&qw#TzJVTPC*kCQUaD*g! z2oFcLnvf~n33fiZcgj#NIZ=xx@lRzl;LOOJ)}zFwHNb)~B1XK-eH4U2qN_&K({K}l zF6pk~pYAhq`X5nOd=i#|rQ-x_Ek1_8)&9(Oh9Ux4+Zizer%GX{HB57lIL3V?;*V_n zD#Jyd5$%r<$K)XHm>;daA$d-(aYhD?gTx7zJO@$!5@5nGChWWGR4_G7r(u7v)~pzscaD+4T{^b zY0{C;U3)C%n=NiWJ~i*+h}9yk(q&f?h-BJT%v0rkC2M;5V&nRKPG3yRAC-YHc`>NV zZ?(2oqKnK6t8=pQM#ufwbUWayYW5X{W)c^ttPyIoYY>8|eZ0P7Q*|}O^y~8rFCXmc zn4>G1leqEjtu$(iqN&c;$ELQmr=-}-R4Yy>Q&rcsJZx?Jndk%VDg~{z9*ibO6moG$ zf*U@(N4$xBW5Q_HIwhz*@c|P8p(nw|D*LO%Yz5@k^1xeW|qt-aOGYzTigZltG2Qxg>{IF+PB{_zk@WZiPkPwTj^JH=9Y5k@Is6kq_s_4 z&UU0zBec(Nq2=&IPVknTv2XE6CX^n88PgRH^ms;GvUiG{bMQrdljG>46b^5|;XiER zMh^XNFGrB?C1+1LT~Ol)?WlzYu7q~Jb$VOpk`HUM{%tD{2VF8$c1luK2IFc=@8?V| zGq6rNuF8}|P$tU%x|u^a_PzYOX6R4O$e`HMw>HFEkKc7sF_PhE4qElD$y(;%3(Tmp zvL?M%T*1&K_EZw;f&@h=jV$PB+^%;N5KG>DA`zM1#B{rJ5lfyD8xeF(HgJJ=JK-(e z<}DLb(~B?Xw8SfM?f6h(6>%5E>kphk&>F)+F%iYtJR&0RRgW#WPqPZjh^(%~rZa19 zLw?YgfdX0PMDB}J+UI9C@P4`g$};5u;THagkP&#W*%c{&^W}LZAk8G13c@vYi?p>? zBbBNdDfA590w>I6<5j~nvXP^LY&?o)xmtNdcId;ZQqaTfv((%=K8W6^)d0EfDo0qN z5T!$$j$EJv-?HAN$BK+@qcF5^#o_Z|K-qSLxmK#)!O7k0?F@tRGn{6$ujWcQSOQ6P z=nm_Ao<_Z@%7kd3EBhQ&(5KjUIh67qj=@~4USYn}B*pR2+80DT)w-psU5tp<|M_mvMW+7E9TWJm?G z2R{uF3vWHF#+K?AOnvsMyl+Ro$sv&I`vZ*NdDsP|;pEK*USbqM`3U3cUg46z{evV{ zy|jW%^<-Gpg3r6BsrB5*y_gaTu&GgrXL5-2aBHbLKM`N#<7E;D*vQ%g*^I3k zpxtAVn8?~Bx9?{2`pqJ>iWTBh*AmOl; z?!eJZ^01A(-}dvR!RXJSt;*sX4smxnLcjCu1Oc|6ZA+PvSUcuBaiGIzSKKiUQ|aPh z)yIfRDs~+eV_NTbPhn7PNN>Sf# z!YaK!U|&?t7`ZJ(niEjcx?sXkgl?PP+;l$4ZuLQ?=Ryl^Vb?N!A1#*+?S6XSpOp@~ zd~#WK!2tHIuA6M4Ls5l_0;AtSg!m9$01))DNBxuta2Ra^_$J7MR020*G+U+@Q*$gn zAG+`U9PpB=8|vL4y_ZoPOj94zDo8fHF_XIa__d8m@Vh2@h=jUN;uPKOw(e6T7r7Gr zL;04a3HlQj8b(QyOwsBf3D>OlarTO@5`;_Rb%ed?L&t0>P&^%TJBl$2(}UO*%-@S{ z5wM6T1z^Qj>^CxG+2R9=`kOTtL1nn}P+FjnU+VL!)Dg$56`?qF_HV*Y`)ie4J{7AD zJE0<&C$A7y7wcRZM*rs!L*(>_|k-H3rvk%M7>UIH*q@6Gd27J%B@0bG2#ydi$2y#u{h*>gn<&Nrt!g z`DW5ZE^VvTJLBa|8@yu@%%FfA`|A3XWK=F4G6)<=#Qie`UIR_s%-J+K9sU6wxQ~3= z$VmF~6ActOL{EqIUegj>l$U6nu7z_QK96K6rwcm^>6oFKM;gYSPj8v{M66}j-b$Ne z$#II;!c^lTAgXEOG|4Oc zth`8j(uzX57cr2WQcG5|XY`5D0=UpRO6XXK922Yz%LnjkR!L@o@x3FZE)6E8rX~Sv zEsYZ=!INlX*=1kfR>;b(r|scLi)3ac36mUfYYbw|a9WlnGl!1MiU?!xc{zw-Z5o2s zFJ?`~+OW&J6W}f9=;LcxO+?4nll5~7(4~#A0F1P?viBB9gNNu^a~YUQ~NS+d?zC$nT( z)>!k3!QLWmYZPj4g~oEtsPOsR`~0rudSBr6DSkrbx~mA6?BpAHiU>6}hxj}7DN_^Y z)WK0M$)F=~+)jmc%r+m<&8S-DCKt=A1Sy67*F@(2k}hWuz( z$MzIWu`~cA{DGQkoQb}dl72HN!Sd^L2a&~vv&$uIHI+hufgWS{jJX@~koJAtD@ zq#y%!3PsJ^m8^)l$|OL{Mx$pYMIq5Vu`SGG4yUU^(SFNI%?Y+KSz$r3^-~^suUqZo zs`BA&^o2dXY<`^2(RhF`B!;*wj1rv*eI4nz*0SX!tRiHgYe%l}SI|#l=zX>aAG#Ay zv5RaN^5E^>cIUgQ?y>xHvcjdWIbYAzUi<>RcvUqAKk!$8HSwn*nY;Bx!bJkO76T2*>j%43ltN6`IgS7OXf#lh@sq<_+0>oG%fdf0ta$_tj}3Kcb! z)!#(vFr?V+iV-5Tw)`F56fG_A;Y4!}z@CQ)EZIPEd`cYswV@|DHe)|S;&+91>b~H( zf-MQ2y%P-qJ4GGudWT1fmYAT+@xoIaSsq?*{~QS=Y%;3II?4IO(M*oRWG??IUmU_( z{g6gkN{X#RB3&xB3`PJ+pQCN-{g_&(B4PnDU}^qRiBMU84DWu#9lNA#nBNF zLWci7;JxD1QCod@$yiPrmbJvq1;J=OntvKbb*G|y=pW(G6n&o zf$!ibcZ26V79Ns#xZw)LDI=oI?@>g=&vcWIK2a^89!VNnUw7>buAimzw1|&3W8zEa z;Q1OkAf+>GuQgG6Jj%bpEI*!4c`|Dwm{&fSS$J-241+FMaZs?@L7(6ta;# zdu*iV<6EhjAoYF@7^S&nUg!7yqy_t&XDD-klVVM>$hg#;xa56)?Q@*^(SD|J-o;sn zR8VG9|7K*zlxbJ-q@d5FXo-e;u$=6^g2ybz8Kb0}?F`GrTb=qZsgSpMQ>~R*=U-x& zHlu;((O>cA>V4T&B;LXCA*QV_Tg`pkry+Ga%}l?k^1e)eiCG>TZ+93x&gvl zhT`t%m*>C+Lil5m0j&$Zn7tmMeH;lu1=(s18OkEgL=wosQr!MXKX*E=a&(CuUd>j1F)YB8+l?` z#AeXI+DuVYCibk4Bw=!y2eTiuDDNAs)=_ACIm&^I+_}PEY#XlB4>p>wGa}CRVDjYB z-O390-K`kfE{0yTw#;Wcx3va@QVF|TJ^4BfBB5YBqbhe-4_VaibCv$+s5;~w92q&c zY$B?0keucVuA924@Fof4Btvh$vp74p;D(RRcGP&LR3A2dXhF91sW#yiczmMunF#|m zt8gZBhPOLv%gm1~ZX3o`fz4-y0;+0P@|Pu|bAI0)td}-XZBgyGr!6INCL$Dd3Ol{= z5%nFybU!L$T)oE!A- z{rnjltE5!RE)jN<-}HN*>|VVqkT8VjMOP8;J$pHktw6dZ5gxH7fi#dy87}_vHLdOC zxgE`^*HZouhF75aJciNJ2oc!cC$_%380tXiG7&CKIl3<% zwzQ)?^DV6;;`flO&^caMl2f{HZ7gGXsMLOM#j%?AythX3d^=jat_vsA*59H~l7Y%0 zfm6WmN6ocY__ocqEP4bhZlXd`C&H?|E`B})>0a6bKT z%#MAG7pMHv_<%5IrTuT*=`!KiPW!&`Qa)$S#wGc7CFq-b**R;weG@0IYA?->3<)sY zlLM%JW=-|eF+)$Sd*jg~p>SfX(IgL7J@b2w+FNalY#Aq*W;=hLn1$@1%=a$#)+zdJ zZozah?_*DWMcRUh!@b)a1&^vCCR$Y$8#jJaC5ym(RXXiLwi$yj>YaJQcWBT-Bdy%0 z9rRBbvUqyP%I&Gg_Xbr+nuB+UQ+5>>P}%FA>;3SW;_s3VIA|318w)X6-UZcdy=J-L z7><>&*&s5hiO#7#B7GR3P3<_S%7ABts8!NduF>PV*w?1>gdrwOave3!`80(AfP_|lupA1D|G zEal^4)YRt35@Yc}^s=bkD!dBSx(pK{cygPF1|DL4mr_K8yM@mXcBeQevScVyD<<^})#f9-u|I9yS*_8>?QL=6T>^r+E0AzBh8i4t9O zg28AL(TOC2D8c9wA-d>&Mg-A`ZuDM8XY_H;$o=l~-5>Y=_k7Rw!#s1Gea_x%t-bcz zd%f!g>|U>*&z1d7>C*_GqIN$GV-0LHU-X7TGY=Y&k|<(Xwp8NU8}C;{$!P0UtwBsL z$!o zfW+Os0H%MrvcSC8BkthE06h=Q)%#;L-bbW1DS=-aoQd!Sq^cfJa-J*r@65X3!>!Bc zeL||cc`2uO>kJOu-^<^tGd&RcA(o|Y*16DcZ4);fX&b`TEHdH*g67>wif)F&R}A_h zXPrDSk`YLGn@~$RGi@!3*e8k1h1eHqiy}aN zni0Rp_x(V72+=C5%!r2Z*{K}U{?QQVbY*rmum1M(TJKL=cGLXR`#?JIk+|3#4hc^D zb5o+yjsDX`zhmvG`eiEsahTW4_K>X0EhO8Xd=93kgIwKVx6%l8oKO=!@%mR$9o5 zTWJJ8bzccbgik(DVezI5J*#0mzLiQgm=L9B`W?_h;1!%ZKk>&$Q~Xa4_SbHlNiUI; zc!fx5bgj^NTpJvvdGI4Y;yg|2S9ca(p;75swhpDc1TCaeBG9naD*NG*88KjY&u{*~ z0gkh!^PILN+PZUzX&OwyWZL1w1=X4YF#J^hW#d7*Ny^qL23qKbChZVI{#YauHuyVb zq*O$qJ|u-$Wjg_3^Q1Y|1`|g@_IDqM_+!?U{()3KOGQp+D{^yyt9o8-C#9y&J|0Ve zpO}r430d{HuIs(>tA-E04=Ef!fo}=?fn^^nA30v%_Aa_0mrQ5d(L2=pzY^rkDhus+ z{-S+@72_BGL@qSX6Y z5QMW=)_>`GHsc2j$ik##-=;-)I-pf_2}pi8?jNFoFPR%` z0Z#mT-5sAWP5GzL%D7D;O?DuI%W2H%(HE=q6-%mDdL^dBN>VyIejQI`Zgy*uagtYJ zaVc@De*-HId4VSmk6t4Sd&Z$LCthlO{0`HKYTixes=;%`&cCWQeipv}B@Z%zTn;jP zq6E!6UQ%RD0WHfwWq5uZ0{Fyi#;e1K=LAX32kZ>NePQP1&pvzp3aUXuKmUYX4g|fl zP=H;#{Dr?B7fe8mp=q2a4@_-ry+EH(HnE*oUXT@?;-IMn|4=zMEbr&wCp`o!Q!V-% zdIb28b@P~ERUR5!Fr;vwkeXk<9As1|taCIl`2iwXc+55S1*s@aMfhm$#Rjf8?J(yb zZc4Id7@g9d4u7bGMCcYmLjus zAS@_CL$Ls-{GmHn%6Gg21*d5Q&N64U7ZTJfOl8o3$^?5is2T`-5<0B0^n#_yQ=xY* z)Bn59f~p6K0t#VPqn$eUXehX&%lz+TJU96#7J`2mpAY0(gg)J$avsE^xn+7U z7?zidR*iOqXA8iY?YH(JeiLT^%EhEz<9Bm%wO7dv4yAG5pp`X(WwUow(MFd5X70ZL zd{Xb&-iOSF?ih$V8=fD#{a|zDr5-zhfL-ZcUsoLXT1Hb(ifN}aTh38l zr8-hRyU`zJJE5!&*t6|F&_kTcTsvOQ#L1%4KsiTs81b)jCjE5t8rI3WEh|i`LV%=k zc)=L)YqQ=Ou_2Pjj9(D;8w5|rR4L#8lZ+;g9{~W2x>hngHs$W&(RO7{GHv3kzQgMD zK&>3~o{g~&aSRJsLi*dP5F_(>z0Bw)uGx%UdkvLN>RMBC(#yyO%<$id=X)^GQ{UuU zq*<+VgyOVbG}g?f(>M0GXj68GEXcIWH_gGbPZD&V>_PtU$Iq@@~$Ry(@YupW$+{Ct8tGN|yfh|3G*iNHMa^qUYWz8Afxr6-W z+3Pm9Ie#5#8H>$Z778o$oyU#Jz<3@x@?FIm;c?A5^gKFrC}ye-Z%+Wu5& z#|r@GC?$L4Iiyl`tJYD*Nl0?;bW`b0KN`BUM$F{bjJv68O;+Jp?B>>;`Vi03xgXu) zbI)`p1cZ<*gikGqzF+yUMWKHf2qA0ff#8?iT*v9Yyxo$QiCuf;cSQwcyD>SI1|Z_e zcV2h}uhy0~Jwu`&B5#N-(q;1Y?CAe@fUs^j&0ESk>B&B?aQ+36gapr!zm-dP5@eX$ zZDoY`3ZZ*w&(E-ct(#kRl)c_^7@0e1G*|u@Y<3kNfukC}M4Xv+vN;8P?fG6EmhsMf z+SmYb{OCHE!NiH*$s~RpV55moX9nBU6D*vh-b3cj0j}ZCoaz-0|5Z0GL3(XZX=R*e z=c20hV&5!m&#l>RGqKcqq6!*3`p{Ktm6nBwF)km*DGyqzcaA$TqZT zeP@pHtNOpBlV^9VbhSSE3IYMd6gpaw#H~&S2V<69V>83q_HuJGi2gykrcQr(cC8FG zr-a#9Qy~wHIG^umF%gT+eU3nbBOt?ZFPzu!4=(Hq780QQMS&tkQ%exQpu7t{~F5i&S|3&)>SE?}>L0|JsdL&0xDIc82aZ(_&LW(cOL( z#E-ezOomldS@y*M_aPaPX4P#kq_M2RLPWA7Ql4J`6kzHqlAg&V`C3y> zgwDwnichF#YJKe^8zY6#U-@4~rA3l60@q}^1lTBc=2~?lmxE z2WtSi-=7Sc%v8!9>O+U?Iq=%Pr^JI}kKne74Btr@zqe_KwseHg6WWOUvbwW!5!{p` zb!>3@&Yi$D@#0#59z6pL?b~f3c+85iOU#XemW~RKA6T=DzZuCUQqWq<_`e6 z&z7zUeeqPfhIDdnE3LHRFo*Qxo0fB51G(gCf^)kQPANgWl#a~o{D{aqDYc*Ogiezn zEMGT^V+zU1KpDHtr6EDu$D!Z<^_BfSX|Hm6&{pKY5M6K?;x!wq#q#_UIe|3E$(1o4S z6fmB^N0z&a$LdEizEndLIV{v-x1-)>wKncjBNMkSh8960hMg~v@ACy-vb)3Q=YRc5 z1s72G#^lrdcu9bSb*woRhyJRF9sD(D;f{^2Mn4Ia=sRf}FJ}pcDp#Vdg`(lS4$p>F z)F_FGN!dRu-d4XGW}!#VvB!Ep_tTv*37-#;peZkUB3CytE(1q)QV)stzqg+HMrBJ; zYLfZW*k5R(BfaobnkCxLQl*Fl7-4@~*6e=O@?0bioe)vcw?*#AU*D42(#8-XqYa+K zMCjfGX8W)PIpMYD(J9|hjWEw>bdv5KLxbe%elbJzFYSyH@aIv=^B0W-Jw1v<vwZz+CeDn^? z>)ajk;9$CccO~1b^x#7zD?MFvL;rf+39319{)2?soy2=edZrD4^8_c5d);@Tu$fSj zTn-^;rd9}RSZlPU^{^TczV@ zxVW0=8yQ=o&_1uTIHlHN(3@`V=lnoqn1_c>^lIuMg5FJ5tWAujA^66 z^(FZQv@rodL6ExUY;$wqSw4RmtK#3IU4#$ws$6kPy$18#kLDtT=1W2s35mgU{6`C; zGcGv&mgowIgT?2hsw6y4N|zdU4IXa0Fr(Phh*^`< zV89AIWGz64EP|NNKD0kqO>-I0ZvLak6;st75QF3UzElRNJdn_maYxQyKNhrli;j3bWNTp>=W(-W zXq0F<(%(KnrwgIp1B4lit~&7Fs1Xc)JtY;Yy=lRZI%)&DnA?HM9AxGfZ-ao&1ZH9l zhg$(eg1V=rc3E{9l{Cw!EZ3IX>e-{*!bK%@e|fA3gyChhTr>84`gsJH2#^3+3kO8x zUwP>tNW}IcAnKG{Kou3yrSV7vc zBER{recj!t20|?mGZ>U%uTF8qngYp{^5@>1TZxL!$Rod|MWqgHLVCh*-b`lU0V*?v-~AD(|>pe zM#Ed>0ZuXMe85x|O8_ab;{&NM+LKwouKmc4cU1}!X4EK>Vxin=^BID4lw1isO_6WF zC%?`Jn88xnUw7sLp%LZN4Wx4h!DGQ66Xcv_4u z3Jh{?g^hoj|aW}2)`#cKqb~?&J zoB+131Tg;Hi!E%{uk$2{PjY^t?Wi>}w5uT`?Z9o8c|&SYR2fAG80yfYocVo}NPq2k zVc3%=T5Hb`5*7889j9Z%vxmNK+bFyeOl_f8K0pR=yB{7Ad*8^MC%Rkp>flLlgzJ2~ z)pBr&?nrr~Y8>D}okPhVRIN?rS>rjtZ> z9`&A!FnOeG?%Ghe8lQ?TX0U9r*1P~}LIAo926F){pdeL(L)NB`U zicMnCMkxUz0Rj2E!fEDN<2B~B$(z=nHDP-6|D3=Qqr!B!Y$9CT^%;U1qRvXj9AJ;} zIJe(<>e^(@I@anX7j`bLqWI_@j@B2?cpNmA{O-3>cfm6WX;X_oBk8_>dxNUf#F}JB zg3EgxtZeaH<8KwOe+AsuJrf&Jgvj5M@dolD8L>BlUYulWL*=mbO3HeHH}U(Rq<7i3 z2x}0Ucr-EBaYqCG21-(|gqV8HJi;p`G&-6%UB`o)1#`3sFKM=SmsLvzcNppi?gatX zpqI6Gqv;|!3=D$!Y3F|cIG!10>#zXSX>)N4yK5l?U8N8&`HI_}1ADpi0H+)|MNq2I zG7n2oZ;SCXeFpwYnz)7P6!&|7l*AMd&UwXz83B}+kFey##8`!&!LmCNhfVXcq$|#n zbARi6v-YWrRNJHRS9sg|=q)71r{V+UzpE_X0V1!xKF=K58-j(Gnz1I)PN1MP# zxe{;gdP)0idrt#Lq*@q9XB^c6VhnHZMsT~^Dg310QLQD~vN%+PWz7#ZVMPf|MkEg2 zmP{6B-#MdExD|t&Yl|7Al)nl0b85d->BvZ(7|f^$t-p_}{w^4}3J%CxAU5s-APztX zsLcTE1<4->vXG56W61TDbosXjmo;h@58{;9cr&+l;#n`ugAE~^f0?_4ni6nkN;xJz4DKnLs4{qj#noKztyF%!`(W0) zfg(xm)!2p~q8Q3qVK%cGJEk$)v$uGg6k{N+qjR-j47oCmtK9H`>^4|>DRq%Dl7C{j z)&g0V`HHckwDI%nxi_nBL}d=#s;-HvR>3yhxyzSiR>5^^-9OgyoOCXDfIz$C2>hE? z#rxJN4esH!}{w-o*=??!|SD#Bdk%4FBz30?`bBeh%xlK>%)nux|lCAy3@3+FW zUavD|gClkIhC41n-oiDot)59dcIs%H{()jdTdMc11Q?$q()4%7y$_0HZ_c7uPW_DR zB!@B*rTNxjLgYjQq1RuBDEzD4jkz?-v~&g?=^pu>$%02u|4771AU|Ze_&E-Thu(T{ zAzRdZF(mzz=wVCyD*i`y#GBq`tYT z)I5Yg=aVbW35mg7npGD2^Cr*xe1liGUl8{)j0fnXsby^%YM!>GlTCZ3GjoExgv-Yb zuIxpZUnUKh`F+&s(N8%mwgz{~lg3@AtEh|f>nQ+Ij@DitMN5_NK!D-#31H`7cZ{`f ziYeYr5=ZZd2_j`R%!m97wjrZf*YqPd*KIc@H@we}?=|HY>jOb2BtZ$^%r&uQ#Z8VK zK_}6}6ezOkb~HLodUI;RMfXYR!serT=KGwJAKsrI0rAV9td+b~LRXm@8MKD$uW{4m zY;-vGEUHexhJpPpoyhbc(`2|a(e@6?OAT;Z;gy{{u3Nerb|k;eS@yHJNKZGnggH)l zZqLe1yx0I=510jNi!y@{K$q*5=wc9`dWy%=|J1j}y;5>@Im4nhu%JyQ38q^s!AE>6 z{^fY+M@?J>SK-0Q>v8Rq4;Qn}=ubijB@~27fdw!Z2=PJDC~ZUEo8kwXfzLbL3V;<~ z3hW@~a_eM6xA?|v@lVZ7QTup9F1F5JpDp@y9G{FCRvn#{S&j{ED%zg#%&sl7!)X=8 zPbNlR0v?8`@_tT3?NO~}4al+Nsly_4ZYbRMQ2TzHUYfBL5O#ZyMUu;^~hKySu&zgv5vjwBz1{>`5;?frttJFxp zDY|hA(8_GK6yX08uAbjY9YU$?MqpGH87%1wZB1GeUP@MUuzsI`lb&jxwB0|d#Z7+cRxjOp* zf8~2!2ALkLQ+YEAH8_ynJZ^X7o7sCu^0Y?W>eAfTo25$6bj9r)s=!OJQ4T75$x}na z6Y-uhIGB5DE;i?j)tdE0d`@DO$qUWoCn;ZStL$sD#g<}|9i$y2^xrKfe9yCSByr*X z{CsEf2!aK{YjX-5k`tIDOGXhp?MEg1a(!pmH0Zknc7CoA@t#*2C#p?}xyf?;p!4lc z+FA~6F8=nRQ+IXY6VH?$hV#0`o1@(*zi(=>7-Lj#agTauXiLsUZ8hs^POAh1?|_ksX03 z8I~Wzad2pLo%>iw2TOflO%=r9?`7Aim5sxQKP_>lp-FI{r>fL96Mg@birme!%99Q} z#Ki7=3_XX4I9$kaHJJU(Cj66nXQg2hM^8FkU_P(JVlGUe!wjZ*8tV{J)!@16(6KS| z;OJ9~FZ(7}Wn=*}Jiadx@`Vc!X&?wx_+$k9-f4)5m77()O%uHTrTBGRt%0_D<(YEF zmC-yh^LUzHLYM?=~K2jW_STpZ-*1REsPy~w)Us#Ddx%huEFuI;!Jb9hyLwb=Npz26aatWPJjoly;5 z*3WI@t5UTn=u(1pRq`9ID&S- z8|(jqat}!0u(8JUP{hHz%r3TGDQKBV*tK`CO=o!c|MY`(NyNE3NfpSB0k>mcZUT&f zg63t}@wOEBJGnz64W_k4-z)Vu)QhE8)g%;T#H3bo3c}?dJbQrffgqh55*Sg7sGKiv(};_=@y?_W%L)PPM&C*;q-} z8_1d8$$rn}(@RzcvORMXc=zGf;VoQKBNx_X8wrEtYg4j$mzi$1RhV#v(k*IG;Grtq zJW9};i$K1A_j^KX$7_0*%hNf8x>p^f^OYQFTw7e^xBY2$isjuxdrSqW@Q9_8+Av0x zP9mz;HoICrSxbF; zE6H#92Og+0ix{T~kyp;cy_T)u++JLKk>wYNfl-otpY-Jm6T9d6ZK| zAi2Wx2x+|!6_?N2KxTisZt(U>14lW0S*2d@PzJqkCX%U@s0OzUy94o?2YqYhN5;Z z7)+}4{Kt3;{`t~1kVT`OefK;k5S#)w7)6*8mk+Gbm=?i}hI{aR$51Kc%7nJ^e2_3(vkzZ%td{)ci$&Cqok2{dZM} zZ^>gX8Si@PQ!Onbzs!xUq9?I?>SlVy9TR>8rA>gxzNrcm=o-w3k4^v(>B3w21N9z$ z^5bhVC^EEzX4|yFTa%RwjfIP)thagNgZTYUkyf3JCziseDSrFX3NhWUXOR-Cq1Wd%c`$Pf|IX<2Y!LCk~pR9p5 zqd*|1(oPW@Lw$~=9AUmhu9S4q^-?@v_WkM%FT?G)jwIA6`IaoN10NsLQm3spDRRbm z!T7sKBKtR&Rk=p!!?La{lo!S%=F{bT(v0T?AI}Uohq-p=piN$1J3iAroM-1NlTK+rPW8pi@#Ze%pz+#Uajx|W$=;Hw4 z%M<75?F(30SMiJ7LzXXOa^C%<&ZAsQv+htSUX7J?KfKZ`_YVa3zsbHx@9WGS>OxP( zH_VSRIZMsXS@$v7k*zT$e0rn3-JDh)C*0IO!b`6>37 ztpNo~2Kwj&Gbb5B&QR+6<-EK52nz$Dg`9}A-hTpta9!wvq>iIhHIxalg z=)8m0fYUBu>!UNvrJnm>ns?J~tpR%xwGnyI6nv4w@QZ4BF43&^o3%fe8iy^NZ5^q1 zno^}#0Q7jc`z}mX7fsStYpdW>M2gz#qUR^h8WnkmX zY<&!_I%V3Ig{SY?Vk7kryVrfVdAOE-o#z0PZ)YW5xs#_>kU=VQB|b`!i!>cBW^<2u^ng^C!EzFrJ&In7j;fB%nkw#57#Zn1b*wx1y*ZR_Q-B!y7fkTo1ay`TZey$ zZGiP}k&gW6A|u^i4Pi-B2WLz_=sZTu+|97o;gY`VLx(&?pONf&zx7|b1qz1A^a{Vi zP3KAj&ZXJCxxM|uMl6ADBnVWx{Kp>ly0-DH0K;Aj@Q;lAB*$$K&Kr%198m2k+x;yF z*P)}hrzq}*6|C86WUV>`Y(qiJ*0m!4xvgs8D`b0GUEzd0|f zwy;o|l7Nnla}Nv1!gTjuyvyWCmvCKC1`C+&+hjNNs6Y67boQHKe znF}B&TFlgBoLZcl@2Baq*Y(x~;|mi+K>TDiVLOD;VuUgoBxtwB1O$q`B?QfC|G3$K ztl(VIl;Swz;8i;c$ayPtG9@NBZFK1wyG54p3@>>VE1OIo*Bnw`XXG0f#j{C2+WXki zU@89T)6TyQpRu+SH%hlCK_G0r>f^`HePPblMC`TFxx<{Cl`D=0c3x$t=6LqWiCQj^ zd}oUZ?Db1iOIz8pCUiC`4dsNh0YFO-C=(y(3-EJa5%)WgKUyk>q6W*9>9<|JXBtKSikbHk+yQT0X{&&Lc-$wLSp>F!nzNnq=ki~ zg{63fgrtRp-U-p9{kI0r5Niip*#F$%$hq(?(182D-r(WjYy-cj12&Q5Iz7PDi#1Z!{3V91OWUc0D!+x06-xN0ATdWYk8=I z{{xY&p0?J}(ZRv?cGh&_E&Lr4FP$g8_$AH%{p9v_)ZuSJ{B#ZOLjDpm(A{8v_pt6e zeno(;minWhIrM^K9=&PH<;BwHxnf`5jl8!}(L6;TnE*G7Y{%rcvTi$$(DaIY{Fqf2 zZAZhq!N$6o*S*;4qAcDrnSD?wIX=SH0PE=RlsPM|cx)=$dff8Y>iCYm{jFQ4r_((D zyKtiAjS#N?{Sv7{2>9Py|0ocE=HHd3pazUe_;=~B7Xj3?{#_-MMu7i)%orj7p#JaK zPv9GX{~k^F0VDc<}9sMFF^I#PEtYw+Qe@v`Yw9O0x7C;nV ziwlCM21@=;eM>mcK4iGb6WJl5&bF*2IZ)EQEqdCob+BA6O=iZh^TP1nxX559WS>Lu zGbfI+?f%Zqdoh+SvPNS&hQ|0Ez&d#NFT2;d0Xa^NXM<$aehW?l`n$iQn#NK_Ulcl4 zdeSGutG45)PK6PXGmCvn%a334e{B@k(84<6gWB5o#-m6so@6c1^5{`K3J3i)^JK|% z0YtZidp*y?6napxP{+h51iF`^A2vAF%`6$QI8T`f&b z`KI!m5m~BNxc6LbS3N0Ki=ZI;HAjkC)z}p4LT~TOKdG&iyOWz!%Wl#$xx?HOGwp+6 zz;zeN?@}P!pwINwG-;~O=x>W;ZA-hJrraJjAS0IYe&$R5sO;_x@`KInEfnqZ-raXi z%{6}ovO4+%wAG;Zm+#WOfIozN(B~F$Yj^N?Lfh7MbPyUi9>4K4{P3{q#V$s-vr?di zB13;cqAHAjEl^xVdK!Rc%XR34Y$%j}k|!B?xUOalGdg<9+(3JSChbbc;P+gC^eNv` zn;Q#&B=)vZa8UgaWen!qXk6kIKU_KE3LWi&1X=%(Y+a$KRF3M#PAMTJ9Fozd>;93%6@f& zq2?fbKg-ePw_~nnr8#h%FCx8ui#lu3+1u2ck}cSAY4KC{a*Ze??A;rXpdsJl3d^#z zhqOCFrnVnt?TY)XrDa$B%hYgqRA(whu1N5Y9QE)~-!6A$Zf8a2G0S<#Mp@rv64ZaH z@;#DIprt7+E1X2AGnvC)JLY08z@9a0p)3_(^n~3jDFH2tPZb6hD-w*ABnor2{}2So zvkJx!`KM)E7S~{6(4KAm#X-TdY&&eo(`Sp8ll(T9?@f<04C1&CaIq#;af_$yo;v3@ z{x%tilE04K3|wrIp+GO8jd3c-9klojU}BG}O?tvWgxh%49rb5`x>=>?e`8vI&i2q4 zNh_VbQD$#Mk6EJq<9qqt1e3qS7`WCN9)%#rJjoo-sMIcT_H-9KUShJ0-&yk>tUq}P zCzovhn8J67SEeyO?+NYv{P%nKRDnYe3=zZzE?$R8>Jtw=_!8C?$-xlbf-R~os9763 zs?La{XgymmWMrpsMR{(S2CE(hHM>9Tnw;>r*b=7oc=1F0ZHLb|p<~HuT*xv6gTV^c zn4takVekTqe7vd)Z+!9i>^PVE*Z6#P-u(_dc(~*{@H0muwyp`DAxl<%R)}~(7swdO zh$!omuTz3BwAaWhhKQ$+d}MPy;G*{9+hrlB@_Jn^4IKb3d$j#%nI@!P*{;}d0_g^y+r}6WV_qwYm$DKEpMKKu9K+k3S;dlx;3PS8e@N0FAA^WT z{S80L`)sS`jk~mn^WYfhTVD=bJ|Bm4=3oFAKL!(W7{=pAWsG#DTkHE(^&qDq)InWA z9ImnLt9}2YEc=WX_cJv1PVEgtDNhtHlF%QZI}O!!>;fM^R9?r2aSSwR?L#{|S3gCu zk8ARokTDqZeQuv%w1wCUOw7T(kd5wi;q~~6g7_xK5tpZXLLwgRxAISi zVB41ZUGAUv=e*S=c%JRV65Y8F0cAw2@8_vlfz7`MZQ;K9+WhQdFAUDE3AISuu~(n% z`z+;(=p2d|zqPDnGserj`BZZ6>LM)UJ6?-~*P-AFWmWeGnx6Qa37MU41hN-@Ou5(J z^|H-iRH#uMi;m9QG^zO#fn6TZtZ^HD!8u$A)8s&_a0hevW&d>1IRBY?=J7ofrcN!4 z4L~|T`%y|bL1ZC@^gb-8>vJ_N%_$g@9WfJI6!utMqIwYSt3ZbM_A`BwD9?8ks<4a08*AD{ zI=&G3q&W1c2Qn4^ns@q<-)opxJM=S&+QSHE!=2|@lYV=_y_sF(6p!;P=fE=7EnBCb zm6%dz!VUHnHWjLl)?>Nqo9k9?7MpQ>b$-SgNS(En{~{JK_SG31T0@3m83LG%65Q3g zycyc~+f|K}((5hr15nljhZbkjNs6z7Sm}X?$`i*>8aIp7!06)}l@?zsz8!Onw7Oit z(on_A@9sQbiiVq)vxaj|Airhu!Ld2x@SCn>xSW$D9rj{;y~LZzV+)m#+@wO>hE?k` zBTXf!PjiH{R*it-N2}Gm}CS=5M>~SokbqIEC)Z!#qgl)jb2WvnJ_Smg41HiyY#5 z2iO%;O(pwkX~mdJei;)W1-991-+G)O3xnMBl%AUew79t)LC-C{_H(+eMm8zhU!n{Q z!kB11l5i8BAoWGX7u!40Q8|2ZE<(3>jGr4iM{4*VM<`j{rhrq;6=U6z7p{{@5#$cr z=HWi|fawNQgD95Bj{ipHsZ9dM&bv8BM40V17lnRk6+ffX-SB9&*sQX19-iw`^3vLB zlt4M(4g_V$o%sXwc<0>fYxMQg&#p7ez79E4-0<}DIX)A}2$JbLKTa+KRTD##oC z?fY8Jv|4R@vJ!Gn3*qCbRM}>u9b?XFe&Ia*YjL*5{_a@fqMATkr_$gKnN@fwzy#4g zqGS+Rl#Z%V+sHX^UKQurr@AhM&s!gV%_jA_lgIdt1U)nIf%@gP2x_gJpiVM_A-$xl z%tNu?G#{M%80}`^f2&e46t_0C;svk5Zqb!%ZfzUP#izh}_*eTBqK-cWN@~Lv)U_4C zXoc3~`&?Q^h^PcKqs#s6QQ>tBWBA^P#1y#g&eaW^^qPpk_DVl=YFK_eNU#QbmQVln zj`_jQvA6BNY(g*24HlQ+-}>^@SS2t9%KMi#tJTtY6<-lu7wK1@?g;I|+3r)lK|n*i z#A1JGFtUKZStLcgT1S|Pk7JC3gwKD3tu(GKdVME}aj@5qQ)dkoHH=_Wu=>9G_oR;N zp!i2IOp;qkQm)Gxur7H(ya%^`RhJ9jZY0!F&!v1hVC6YJca~!uF*Q@q4QLy?#YeBS z#g7s%3Ud9~eR;D6m-&9-GP5S+(R8qt%*a`U0q;J*Zd?p|AwV#vfXXI+8so8L1RDXZzSHLWo?c zw*2iIGR8b*bn;nu(ZW&=eLp*ux1xq594wpW-=#7s5WF;QNggVN6oaIr8 zFx4gObH)?j3tzNFs_chDw@%5CZ($hz$tMyQ<)*6lUPK4hTMtN5J2SEliBbm*1t-VB z2M@W)o2BU@4Y2soVpwm|kTAe0s!t3Vk)Y&ecYFR|*-Rj^^v>cH%S&q^;p4|$Xu8Ze zy&QyQ>(Zx@5O9G~*uGvXWgI<8?j7L*q8-*N%GbaqB)ctNwEPmeB*jNc0yelArz_1T z`_L9_)14!4#Ob25y#lasU)a=0qV13)lsgQ!_5Dd&{PKeMI)PAA7dpT-^7Vu0)fwRj z^{SeuZ94D(pl50L;3erZ_(~7h`zh%yo_%d&LOgmGmPQMONh~;Nf|&9i=21O>O(A&I z_Rec97mdxET?}IGKpMZyg**P#KpvS`alL_DY;XBIFcv%f_U+fllH!TIstibfH~`k` z!GFMltUGsZ17DKox^;rP2F= zW#4@CbM?!Kt&^X@ddc#$1XtFxxnM}!_yug9kbK3ZmDcUGC@(32*Aan%)}^r3XzUfO zFTo!4!R;*ryj>T z^7ER=I{x7FYBnFq`Jbdh?&z)THidW^J|X?G<8~f)!mFcnv*Rl(FtD!ft&l{x0lzW4 zs)kh%@?ILn`ZD3%(tx})S0rvA-U^JO+3$b1y<3j>i>qVk>w_O6 zD#l)SkSdnlKx0{=>w3bpLcP9^JV6t^6zB)tbp4w?l(>1JqqSCDj)w<3&$svP0C&sh z&d!Pb8hoFCdViOC_LgJ{roRNCWd4#mBNGw z#QfrO3Gu;vVZ_tbAMX)n(zlC6i^$2=L!Qz`y$==YL#5b6I6bf1{JlG6B5eJ-KK}FP z&D)1jwUegaG6d(Nl%)h{p}w#5a(O-)YH9}O_!^$*8WgZHR!7=il37+I0L+L3CFIKV z&IxeeQ{01DILiE`?05(Hl4mxjSPQ5&hH$4(s2CUHey=Z*P*a=jhX_W&$rt)IscV?a zD?7B{6M^TKD-b_m93>bai{u$fc(`D1K?BoSs3{M&hD;>@vVNCk{sGA>7U;>`ShC!E zrAo*^F|Qp`dfq&)leutI$;o>dz zr1ltTW`(cm(peO}@qO|ULAHDMMm@~w;Fw>2Qi-X`70c6_>{fr_XnF;r!9LDL-izYiX{qrn8l{Zo#Pm5mnI29w>);+NT7zaWfMJ7 z0vdD;ul_Qf6Iyfu}fK&Wh8 z^8EppcPRNc#BUuUuADtAPL7VGsWQGq-)zA;=d-*}_r$gce4~C^4kOi|Lyp9y)Y zxr>4it}E3n%~3B!h4)4{)WJx3PKwR|Y2iAfe8uZrQyE;l^0GNnHRY%cw2VNf%zlw* zTwA%G_@N=JK^*;zaf>R6!M#IVhG9Ab%|aVW(DvZc)h>E!X=KBe_|W?)9e{jssZbkl z9~A#2_NTEmm-ynO&s4K+-xAY0IeJIW#y38H)--APsJdg{r>vWiVtw93g6sjOm)&rP zVfTt}=#Gv&c}{~XHHm-Ba{IQR10YM774lqmHKEl!YbbDQpjaM!0 zi?;n(ep?q97@x1bcI#dtk>e{}iEc!2H?!LqU}~!VCTs}=p_wJ?ak-C^)ae2q)W|3E zdRhCc$byT*G=IKp*!-JzT#b-0<>d&8#XJkCH6`dg4fqXIjh)!f-uNLys3;WAdRo&04 zGIuoodlmgm=(zfra@?P<_cuFA4Xn;LB)oja)6>a{2b)98VxMX(KRMR6f_PS_!suWm zSh8G-#@IVb@JU->nrg1IBg<;^Xpn+{O;OX`4 zIhs(g%qwI=Pbh6dHmeRKuqHSk1!s0Ccu%tnJPlH_9Zd}Td4U($@H#j6LEk#SPr7d9 z%RR~+mGp!hR^?Hu8}-E#(^2u)8+mHJh)MIVsoBekS$$)3oOiA=$vhFLT@KTw(rgXQ z^?%jM#Bz9F7Um>uC$LK5|9&0vaJ zF1j?f2%SDu?S3P`U!-Np0+{Q#{%p0h`+Se}!&g|%@65c7wnd|Cw(xPW7`X1X))=sA zm709{_GOdr=VogyyUy!)TT*3#;2YxhDs5dnCusbp94q0b;85hqN!f$^OPGrUeqngBuBl#&K9W$b_5Sg!G>Wa#4p`POj2PC_{00o4*xA%LsWtu0)m zl1z&eYgNYy=1 zV@ypNrK+5$#0^ej7qY#kzHexIek1C*Jle>Q3r;1>e@YKsA8;y{k{9H?F5jZD_S=aplrwNE5Vd z8{s7kOMxRrj$_B;c>RuBE|J_88`of=wL|fdR}Pxn2XW!H zh8i=1Us`)R3BoDSa^ia|A03SyA-I^g+pkwZyN3Ho&1`7?fU;2to>PQ0(57G9A3a3X zOJp}g#rXT{i58_k5fttJ*5Op7m0?di_`n!#(7E2WLkRs@tXP#qXfylToxkrjVF0p0 z1ai#mNUg20Ea7;26jn9zG5c>haIVS_U!DnG*AM%JvqK)A;cn8$Q^07>mi{arVwnI> zX^agf5T#PZMrcunerhdEs377|z#6HPmwxBt!?R2;crW{+P8&mx|0mTuH>d=C>9kwq zp`@d->uSqN9Cl!26Q)Tf{;%}#OOTy)oug?Uz>ZI;chP?PW=g;fJQM7S zwkAdmx?-$Jd}qG2-mYbvwnvA|g;EW@sTit^gFoy4EyWd+$i&s)Kyk(JqwQK~_iK1q zOZoa%iD!9TPB{o{+Zp8Rrfjb4x0OP#jcD#)WPcniez-k9Y3N4M-NMGEqew^8h>@2o zl`SdbQ&}wlAZB97MvIq!$T|}s7-o%?KIdk9N_c_|2wnZ0V<~|)xDNS8*pxNBj|##$ zo0(l@aq=_453^<*y62o|MO-_iS#UH$GIvFe5GtN@n8#l63ggBAUOMZk2J2BAUbfCM z(@eZx`&~4YHO{fTOQDEXI0q3u#pjl@#F~?Nf7SGS^6`SpNvhVlt}kHgvw*Ez5=R4Z zo;Q>Ud)tSrc7+h9^SZL)uwcYI^r=amC->7~k%GqG{#u7 zQnnz!=$4gtyV}rHJPY4{mU$-${e%88i3ADYYFyrbA*fDT8hk*A%Fi7Hf7dZ0e1$J? zA3g$d@$f`e3fvZ%$Rmn{x7lwOv1g@{OmGa1eazeG1mCrOSGCWgzCC+a^m(GurID%Y zl~z_x-R{P!jTiD=dtYgKH(YHzd$5A*gW=Gc+MS?_^Wp$jb+#%}nSk|~ANE+|_uuH>{#Vm{q9n?j8RZ&_GOAd% zryh3KAp@vkZd?Y>Tm zPpq`sElF^BMD{3jw*q~H)vZxQ(We(-Aiq<-;w?7(Z8Vr~1X4!hrBp$px%SiCH&onB zI!-;3!HqRjc3$trZ&~*%nQ7wn2CGP&AB3Ur4QwfzMe~T=xshG&y`%8ZwH2VH%b3}d z17BghHSqsyzBfFVZ2btrGuwKM#2l-XQm54QRnkW`lfSkW#aM~9JdhEQy>go&&@Bg& zz^+fO@nP>y$^9a~V0vQ1KF-`adI2}3zOrhDKOu8SXSQtt9+*4pA*$+7AGOq@&K*}t zY~XAjEz}^Ew=W=R)$L}O7^9Yw+TsOZs{PsUH8G6ruXB!FI6e# zh1v8JBmkRNf&EJ_bB+`7?X3sb!vko``M(;M$|%am`V}Jw!qCA=f7hYHcz;#5ooB&B zhl;HS5Z$|8^Z5{Q-CRP5=N8sr-#yic<8p$TaExrsB>>DFUGlK~9_l>@Xuldm^70>V zdn*7iOC3JGg%Ga6RJNHe>h2ErQMkT8vKhRvDDP>}+?)EXh*73i{NCBS9`h}OX$yvs zR`r}4*1)HQpzD3N+cBQnTFM)}{R0vS$5_bN9yz{S(=;o?lAQ~lDNS(-kx4;w3fNJ zrc5HwN>=wg7rJFOi@GUx!(Y^L$3Lo2vC7FLM2_uyGmdqTeK~3hb*!I7DY(I36-b8| zKH&EuMQURh6baFR0V;RZKsM5J^Hi8W-hxj&uW5*v2rjgra-0U!$65GjZ z7sKBFr|Kmm6Xu$Y;Pzh%Dc`BZe$mU&oiGFVeAwX3SO3y@4_xQ7!$ujvWC#piY10lxD$`DKd@+txfpqhlSUc@@SCbtu8(}C zLpGtE7c=#hh=PWn-4ogsrpn^#scoCYQVfvLZ=4O=Y=p-#;_0x;$;NkIeV5A_gw5{q zsiD0ic|D_W$=SU(sqd48Y2D-+(mjC}OK%958Yk)DO~ms$71P4HKUt#%N>08iWhdZk z*`>$lW3zmqx@zm``ZZqjw9Y?c`@=mR@oeyO>K2zTnyzeiMJe55-Qp zD%@3xDmC;#-LRk{938%c9)%lL+Hn&&C_3ID)mif=HzJzL!h;yr^q+>We!MP=MHHer z?RH|j`t@3RAHaeg?%o?DHt!6=WekB=mQ5E5^jb(>3vSJ*xN{$Vnz@~h{PU8wIL2S-@Gr$$iPhmv*mKhX-r>fC%JpS4Ccl$w_RJBPsnl@ z@i8%4#uQqXi_l-qw$K^Y(Mb z$+!mAwRZ`}ZJyEWZiD7O@fiCKOuJ=7pKR&W3aeWrFC~k8Kvusd&(%d}UgSO+{PNR8 z;5~e{PI{d>@))(-!TV)S-J64#UdXRJ8)-Tg0`8_A#m%HL=jlh`zsYPL0GgAl|4agM zdt3^PW10FCH6MJ7>de5#JAO3x{SLg=9o6wFoI zDkqkU#l}YIjP_W+jl_@O{nO)>vHZJ}VAQkc0c`YuH3C!kZ7Un7nwKjXa_Xt;I7{*FM&4XP2$x?4^(s|0re zM0PxQp$FPuh4xR=K>m>38vMLtGx@P0@SQTDV*GCgtq0Lo~R|5@Ur;z*Y z(aTSXJ&E%%Z6pzikn%IO+c7a2fv*i)Snqibb%U*9tOqb&4I;3c5(!%qvM@`dIjbjBE^aJPK0GJL$Ea4-!bYunQ9))xS z@}!49JN4<+OFh<~4E@?rb2^s4@|o$-dJ^-dgqZx<>~o#_cj_a{gZrD)psU&A+{^v5 zUzNbvJBni-tH-xMk)~=j8=qQDE^MFXoHawYWp7V0jL_xj-nlVvE;HRp_Lv-5!0t*Z z>^V1iJAl-!h0ifR6YnG$|5mJ=Df>x~k?_%x$s2w=C?FB&)#m?*Egp_ z)wc7Ht=oxMTkZ4Y9eyvuGHi&dL zwK+!C2SZ)Q;*$WsIEa4CeL2RUX5$UTA`=dFLH$zv zFMWGI)QkfTE62T)95@1Us79=g<}M|Q#q1X4hGWXWEJekQy$PhOy zS=!Aa>!mSI-f#$nWA=2a#IWeJfg;~XdpSH;jr`m;lsP3TagR-1A|+c_D*BDbyLU2x zt&}ByH8h<$UDJVNwRB~E(?PVkl3lWp`R{U#-xQNE1(WA5u(lmM#_^<^Ke z@k1YY`Ck2#FC1olP}xzY!G#=F9$1SC{KtYB!~|@AYyrs_B7c7TOfcQBfc3HGaq|h} zc=nT&((UJIZ;xW$v(PpR&ep@&*4;eD@C$GSvhe=>t)P_qA4nY{nBGOoql&GoQ)8 z^GJPFtOB3&(q-7YS+H#pKBzs7?Sod=W$uy^_~d&B!CR%3LD&hC>)i=|VS)nVla4f1 zH2|aL(RUaVGU$Z_)rb?FEtA{REPt(^rxM(l;gD~rR?9U}ODdy?W4 z*>~L@pjEA^5#?ptCAU5#cbGT;G&%tPf>D2o*JYug(SPRA3I7o0FbogwCCT9(kdt-J zp8~o~gn!p6^6~PERpuDcs^V&Bgy0Dyo=BqqZP@1oTf~yf(sTL}HrmKH@>F9lIYQLu zMJFO`K8PGk?RxC0{JIJ6uEua*Z(8BMO&f?9v2rZ5ktE0@D$8a_~nEE%dk|Pw*>Q#gLE}=j0a_&1CQC%kk7ikDU(D(@kEjqD0c&HassMcv^ z*~ga;^frutD)+Xy)LI;>8a)~yinrWiYRS4;m&CrK`Qh9xCm$-kVWUZ=DF&h=y zk)b2HOnIxC*tE+=_4tzONJ2;dRp_uY7-J@VCN{zFbm?(tu>~o4$xZbll|lS0dv&Au zT|C}gGJU?z{Aa0VXV95zYF!B@QX6(U3+c_sFR>HKFn0$EiJ04dM1gHnnU~bo9124s zFM9O46<i%LH~(emY$%F75Togx`|x0WLVRdoQGHiS!GYe?HD10R%X zRX;vC=yXJ>hDKcxRjZZfWmx>Ol;f(}C zx*}d|Zk~mzfw-Kfo@m9UWuza??|b$lPT)Im)K zwO-Q};;I?@)}KcyxYXyE+YM)5mXYa(t8_W0|HPVJTmIF5uyug|V+{hLrbhMGWt?U@ zW*NQjPC#wu%n;Ua)ulp&Rz&XZRT&?3jRpFlo%;MMsFJnD!M$wMLL#*ldvk#-TmefS zFoV7O|FdHFlT-ka8~EO?aI^X`?|}-r)5OK*nvj#(54UIYl)Hs{s9B54x@MRhXoIqQ3Z_sF8)1QF%(+5LN#s=!mRqHieEw#>#UHZKnCyzYCT@TCE(u?D zizk~PStwpMJmPdvceif44kxnzg_9Wcjk32?4>Ejff?2;`Wt_V# zOK(mT^#b=CHKXZ{i>DyxP43Lr=lJx*GqQv&Ps5RTp?H$t*?Sv0aH8;sLlQX8zd$D+ zx70*;xa*3u!mm8gseKJg11bafR;Q}wenzapwvW@U?O7tiXV>%C3^}+Q>2BEpeEL0M zH_~f4NP`KQy>O5G9EEujAj7N7838X*yT5c2lm83Q#0L=I-&d7kz&le~`}NQ&-sw{@ z>zyOR6HX3&>WIq;%(M)DZwmOB=h$A7g2}?W02Ni-i!!kLwTF9yUyf$h^g6TcpqbPbe{>La;-Rp=+|BrycMf2QG1bQ6(#St-<1yZi7^^pn2fR7NYJC;sV z5XD^kbbxNpuS?*D!N+ZqW#w(_zGuX(i2hNOQMJgoktgKazsIJ^RFVCsZ}#UpbgyGx z^}iE_vk)Zv8a42ZE4Ny7SdWMr{s5BDiks zgsNV-*CbBxqQ$qF8m*3fu&=A^ zzYG%9cNvi(=evQCS5)inO`dc3`10_+BR^4ldA$NpkZSA;2uqG5{2spLnLY6@ZSnsAB%fs_@Es@C zi`PBb^X~(I_#_T?TMgtLIgoR8Wk8h3RO5+ScO%-+*zi76@Am&xkrzT;$fEEgjH+Zd z=`wXa=31TcWIwRi;;t2b{Da*wtV;}o6vu-q^2V3p9~7E&gkUe2nSUd|2*p7Tn`$sm z*vO`8qK_0RNU(n8I`#Uwg9ZC(%cq7srBP^lsG(@NmK8#zJTERKNOna z2MO`VI|K@8m1;&YgCemfnX7$rqtJn##s2bVz)@8XYKmk)XJ=C)*=38(X*H_M?L~7^ zw5$XjW%K)={s=v;=dP<2W4Ta96wnPKl;HID8uS7m{#({+pumySPC1r{2vi0xk=1V* z59e65Cg1UiAaZP|8&m>Xm8$kLfFA8o?v`5&iz!KtJoK@5dK)-3j+h3V~k)~nrhkogYo|@%$SKORpkx3_m-l~~er?({o-(7^#^D`e7i2_5U zB`W4J@^oe{%aY2#aO`BV9ju^=Jk&aVE|Hmw@5mg_38ot_{K5mPmP=d&2|n@tQD!`} z2aDO%rzLpp%OSC(fm%1H`_&O$CHZvxWheDWaT$`0FyLkWSJ{A>raE`dM)jB}6B)U? z6D`&kj`Lgu~QyWf;Um4YfgfAPtd{q$6X|$d8Qu{IeZO{*-pJJR%*>fM@#iG za`GE<+wpnFJTToDHtyLf|^C}T(0{CwfVh;FKkKt#MRkl?9;jW0P8a++Q{ z$5Dx2b)n>1wIwp`4xPNLBdB#RUp_y%vQtU#_9AZ|hnX*OMsT<07@&T*hS$35*F=YFRu@Y-bhavyfI`s0=tQg@x5vSvxK#I1>@ zYJjH3exYjy{a^I{L>NGnBuM02H26zLM^37$fbIn)zbq@~5-ZEmNEW>t!DVRU8*$gr z`YVLLdz1EC!acHR>s-Q#^P!Ql?f6urNLZ>jTwmts5AldS`{W$Qm+SBU&kIUq$ZIm| zK+zAN@0>x&W20HL3Sf{4*fU#eHzY_{p33QdxJH9A@=8t9*c<-X>*WGro?Br(-d82} zR5l(bu(Gi|j{t>MhR1gOPpki}%5Y*h#~wybV)g>3$UO1uV}R@}zZXB$6XiWzcX6mD zOza%T@5pg0sC6;Z{Jq!DU&AtFr(1`fP&v==_hjqAI}BZAX0QU+#>()|SR+dT9{x>X zop0OejazP21?D1dJ8~X6&uLG<^{nZhQ7%%eCMCIs)?6v)4iVaELSLh@T$iJ~zi<#+ zQ6?|mR~*Fv76UJ1M&jFjw8414`gbx0PdBB8CmJFtV1Kq5>d1}zdB;fe$VNA$p3#Qf zSXCi22ndK-@KBWawIt8QKqe=R0tb|`TEY)yAlYKemuqAGWoo;X%l5Et?vuxxb<6D3 zD)N5bA4y`rYq)E=a+$OFMf<|pIpls~fcQqd@K`te$vT@P(XQ)Q-A33|q*c?@CjkG9 z{40;tQ}g}uF*Y61l&iixLPYDrGcho!z!j$X8V$<-qxl(YS>0G8qSsCc#uoqvDiz1h zo9s}6rWzu&dq7-1dHws_E0NwsLZ3f^@J*O;35kn5U>T#FqvA&PLnD7T)50MX7w#iE zHm|p48|PnM70I4KZXp%=hi+G|-+KGWa#wYrII@1z&s^HWzUwcSon`G!-wh@K%coe~ zCy`K!iYH`aM2;18fRP3KC}97R^~BYk4*ZNXG{aK!#yR7KD`q_PTr;eZnf%i?l0rF0 zfZpu=8wsm|AbbsY>Pz_VyeE%;bc*$XPhB`Ei_BP%LXhwwd1I@X4KKl>7pEk!M*McP zH8AT!JSC9&Vw3E0;gbFGCbhEYnZF-@x{{fX!yg5t_fPD!qA~R7YlU`oBK&0@y=-*| zy9{URCzpd{qcC@G=e=X<4vBM(lTfFE?@CRxGMg=R7A3=G6PWVtg_bt5F9mL<^FB9A z^3$fd+?8VWy0zoCLHxbC-o{ZrL-_gco`k)tj6*ZpUeGl%Ih|?t(QTJbtSuhawKEpi z*q>^2l8&&~^XeR76N*ZK_|1s~{b!snlnv{i_tdDV^!C8Fmc`fEoWeDKHFeE&r`-x~ zDqAF75k$OL=dLjcOSuiddw$-@F%@-?d=PU$bAv*}sphtTNBP^?twq+N=yyE zXuX|j5=W>w7NO4UcTzUVcl>xj<@3oZ987*AhX9@@(3EPy+3}kGS^)Y!YUBYSE^1*w8(Qba?*JGcwK$BO zcn-U1psJI{I&nr+4Qq z94chMmxUT(Unkmi#MPY>8a;XVu(MYB5n3d&eD!vXIEoSdWjPRwI*o^$Rdli)jp_`f z{O&C51Q6L%gd9yA7lrDkY_+t55Fy1-D96b#esYnrNPg6rw38m|d6SBB6&G*oKwo0T zrrMW>KN4Lnt62P5B7`=Ed#(>>= zd1K^L5Ix`vCp~H%ZXj4Xp9T+{1lLAX+nHo)sE%<6ct{xL;b;O-g6E^3v|#siy-GF z{&uz?dgF1!oSgzlBD1%gAhip9GvY9I_qh0N9;DcDJRqM=Ax3tfa3C4lS>r2E(qarJ z6#7^M(vSOeCvJJ+_X1j(L~(J>`@ytY7PhY*Tuv3`Tv1+T7|Gl?HXG74{hGR2enQlX zi@-qQRx|TJd6dSo>7w1j(n4lqeJMp&-KhLJxkOfEo?vSUFg3oExY1)V1l9ORV8Lpx z@=!t`{NrJ9?Kt;2bRJUdKhbD{nn9sso87(1esuslVM}mTGGaPDg3!O9w$KaCEYK0B z;p}Q2D1LFt+j8^i$1s7js&;Z)vtaLMVAH!_7qCJConKrk3}U}i35B=b7>c2JzNK#e zLB~2&?h!@e=qe~-VI%OXc+6FFq_k>G{xIo#=;Ci7V}ytdRT{}UdleUb^U^CGl8+>m zBP)K~1oiJ#D1W{qeo1*v!2ByCupXg9iyyAc?|U{)>u+Y(CHg>LTRsrnW$!d14!C17 z2$rdd`76C%JwcOq$1(jI%lz%J-Y^i124-1yE7pTTU%E-{WO(`U208H(Tg#6&iehP) zWL`Jd8iX|`m&@Dy+08(y5()#Asc;6Cwzo2Za;!OvkFVy8Zq)~O4A!k27yVXFRv{ga zIlMin3EGJ!$tH3m>S$CoArFxF)l7p%V2v|op3N*7%2BOTpP6>fT^ijfE72Z&lqKWz zxB1VO&0LBJT|^57b?_~{IZq1jqJhGh<)vTGmTs^_si)P*@<4iQo0&MmE-@z-FyGD`M%-95yT#) z_AaHZU3*h)jao%fGd8VFW5h_z(iSbXXRAil-nD|-yOh|mix4w5PxSqH#`j-%{E{E! zb>F$K`#Q&Up2u;V%b2Kx(nGcBmm@wNU7UREX(a>FN{PVRpKy4+RMA;NI@>Rq8zc=3 zNwa^Cqi}1!aMT)_A=)W?CYX!*Sh*1_cTXW_-&T(NfvlQk)eNU8s(B!t`Wg1=j1-st zl0xTKY6ax^Z$)4QJZtsMuHr7sE|Z_y36U6)%K$yH2Fx7+UJm=O6FetsofxLcQ#@(At znnQMDjgZ&{GMUbg<6G@4}b2?G{Jur88c&f3vpv)?B>v!|c8kf+AM~;{qWd3n=}}w>!G{<;-=Fg)$v7_E$o` z`?oVJA+4@Zcp6cu4N$yKD}7BM3`CVLzwCz!aaeF9Iq9v1jUi$y6}BbIzoKv54rQ~Y zLOI-HH~Q$59c2-BdvIT>eMpM5vPooRR(~HJbeps;QTq@R_Nn$o5ro=M=iSACEqn?PCukoGAZHdZkfvd5v1Ug@5dF zY;(-m^Pu-k%G>Wfsaq`oLo&{nv3k?_w>5FHxj@-3~CpCNZ{K{dKUJ^&zk_Qec#DeM_-si8Psk{ zAW%eQEcA?8dWhVC(W7AbA@ji9rpG`%C(1kI=WGHzfBr%Tw1;^`s&dcau zqic#zbH!J2JED3L4~?9&BmP#*->Uj@yQh9{%gH_J6VZdUX*@koTe})pvX4d;ZCLtU@9jnbVC3&ik(7uvm4`6j z`V2!6Dvt*mh)xG$5^!uT5myeaHVHsOVup|T4>hg?!l8RpVZ4Ce`E&OK@^ub`}6Bbwg}IkUKdeCcl3QOJ^;BJ!Z_)6WfEYshL-Lf`*P`&ZM#L}MrC_g# zN1Nz8yq(ebTRN7k_rlH!3Uo=X$TuuLK?y+0f8T-4##mg$pfprKGv^K_aPpLQDhSIC zEzQKoLZKuJq1WYtDCXVtQ!^9dt7w6BZO&LLPuP|Q0hrqn&*S;v7CWsBX`$s$!1Xol zHM2vx%zKq;kKRKoo7`E)-Pv&r}htre)lfE_|Aerp+&e*PBDyU3|Fj)&!5Vq zbPp`Aser``yhwjE+YheP*jjh^vq0Q73GgYUeGc3D+k*Nt|0;sahgQuARz8`Ht?Xud zdjd?H>uB+z+K~R+MnAG&&cKYnLmlVBU^@#}a=8x0Wu+f~+6*67;n=t3twy>%rvpP@0DiG?NJ1% z120rq#pCmW_oZoo&t}O6#feLat0kH_g~WU+{n?f{NRGYqxi;V@t2-U>KE4;;JK}GT z+pVM{RbEJ{IoDJ_cOi2SIDRwW-$ zUQ3eScR6b5F;;CRq$4_k04934`l#Fj%>*GqlAg1XwN2DfoRYXW9Nn&XrM5x>Ws6rM zCaQnWeU%Lz$7j?(SZ7U}XeuS-EM42WauF8ITF*Ib{GF^h44*ysvT0aQof5S7?*9pI zo}G773nfV@FB-gap!Kj9(6aQbC1PK4Hv}X=@I(3>&H%oLB@MkM)ib_j( z9ZNQGSpt@JMb?Q-7`#4W}|I$Asb>YV5C)!NZ2ec=VqeheEq zT{E}6B-8haUu)C1sAYJQy0)q1#-J(2ZCg9Of`dZuk1})_ zscYUl0IA8KVXbfk_fA7TDUhRqFD;+?q_??aMa2W0lW-pv4qr6OycG}8{0%y$DO}*& zK0`@6ojt#lQk@z(``bm^u9~~;Ie6Adr`l2W8w&E~@`IpMtLUZ2vJkq6&-q+qFgJO` zOB`@&a`e`~Q{DsGlm^}fpRk_E3Ytbz;$0HZz0%aere9mXCe3ZHTN~%oL(a$QS}!-s zQV`c1soxwLPU%Q_S2)bd0g%i3;-eh{ICY8h<2MPdw6M676Dn8iarXC@G|F$ORXkce zTD*B5S#PzMJeev#KxXoxH-V{fb`JK5q2AI_V#Mg}nxLp_hTOE_$1JXr?8rrBJd;A4 zjf~CPtzXV9v}TrFFK!7JUu}3TNG;ro7=R{p%POg?J?q8DJprp?ErvjrD`tv>jqyI; zVe)5Q5=b5>`$3M~GkZjB_}p#w9o?u*cZT`xIe<)ElEB__?(VlrAxR3&mLId$YAW`S zL%v3K8-*qvd8+v*SJZNBO+~?U3ozfWtub+kY`64Ezy*(7!XGfvlvg7KS_Q)BkDwCZ zYsV-s<5KX}n^Ij~ERNFoltfxM-A)X+RMp|E!^Cr}!H70gS-VKw2fua-e7;84CYJle zv!kkmEN8oUke$*!DnEJRHESA4bf+g(eH}d2)slyJh@S5QK9@*m^DqJD$;a~y5)~)Y z-G}Sy#1^-!9mol4e;#Ow?#d**#Z%jpBtbwZxv1)+bdh)hovTo=(A<5zMnq};-SSM< zI~Vf?U?qD+(d=}pTqosGrYFLxZpE{M{5s%FB!{VIn=+t06}Z6pL4sS5bHMA8SXf8l43BtAt|OHeHX2YY`J z>g3Z>j^qR!ybT$g1aH)naMS0vR86W zi&9O}v-r$B`4+T(jGu&b>*o~6^&RhCF*^}P6LtFf>fj$g;OholWkPD230%moNrXVx z4`!xYh-x$EI@)>$kZFvC-q?AhdCZ3(!zZbu&^hiG>PTBj!v@#e5||UmZxCIsyCWrBkggA z)(=lQ)%&mhOxOkO_DdUsM}+hyuj***ITTR+nj7 z0&f~38c^&P7HbrEns(*5^rECNjx7H^lQhb;Zf_vGr`<$~J+x=IqI1u}I6F4B_sep$@2B!eWQW=6=NYV(zaO%bZdYXHw96D|4pf4cMd`lcrn!Go)m%PZ+q zVhPQ9+;+QWtdPWzq$4B<@^!o2t(>AEJP;)>7fq9s(eNwhaQAysEls5y{hQsOo(KFU z7>Nk9XD7pXnMzxNz4!L2US-KXWh3!}p?8N>M9POj7`}6+lh+rj}bDz zZyNw2{O>*&1~y^@P6jdvSPUwk8h;3{_uLZl7J{F6w@>Mi@{oU++4PCfbKYh0rVc*{ zi<4PU)gL}_%uMIp-pRWQm&$3o+@K9DP#vo|$|kc{+1l^&jZ}j3jxXG1rn=9-ld)k4 zYo1o@bU-NtS2ut;R$L(f24obH7%Nh0a~Ej@;dzI!wBfMj7RmmTsNYQADCtWko%R*& zq5e8;;$98i_<7M)S?V$Da_Z`p8O*|(0f|9m*gQ>NhS6w#uWLAe*HB-teCx^WuW0`R?8_x!h4I;xHL_^i|>ogDM zAM33Faue-Nz|mVksea&lb0qMWuh_Y0?~IzLLb-3VT0%;jDIjwOe(*X1udZaRy6xQE zflA)1OudI?`_zr(54^a`rh}g{mQ18k8LP2J|^ zoDqKHt?tS9aBuq4P4T{{*3l;Z(H)@_d?(#IFqxt=IwxXrB3U@oFc;vx6bA5ThWrei zT%P5%Yq_U3{gk><`gez0c%S798G(o|>Kh`$R2T4x8VoFmsDm6#c#uK@r<&d4C23b9 zh!g+7Wo?A?R0>~#N7u>DaBjEd&EOBKG=Caj2Cl1|rL0WAHR3%U&&KH}5oghvpbx{s zKka_j;ZWa6J&7;_GLiHuH5}vwTTX|yb&fchuXUlk<6AgS+Yx-!0bCw=GK?;@+wEHA zUm5#N%eB!Y0tAh1wY5rcHur;5To=lfGCOn|tm`OR9xdXa)P$7MAZsZ?f#y+zy1(i+ha&EwBY3CFbjah-2U}4%fZZPv6Y(`Up%qh z0SyI0Ln=G%DFSqG`v?)(^&v0J|E+-rkT;EAgAkf82o_AFGqP|H%iTp*QeJKA?Y=&> z#^T+3Y3iA2LA>f{NKxLaC-Z>0x?2^k(lW2@Z+e0L{uv5DO;UcM zmmGbVx3gfY@V?Sf7pTDFve-<=VIqvlwdE$9?G;Bpwcn(9uQ&M1iszk_hBbCbm`voe z1^}Zq3J*_tKHNqUB8b_AuBP~y!6kdCq2Jbq*ona67b03ZX980!@j--LV9RPlPAb<0ag;P|x zG!9D2qpRbxxD%eZOcU@^hT53!tn-3^cT7MGzir;x%9=$a*4LFD`L39s98F#7K!@|X z(qu5z2AtA{RgG2rAf}nD@7`C|3-(~)YicL)Z+m4Qexu&j#rm!8@|N$7QG`j(fxamv z2OC2aq)Rd;bojwy>BtL)z-+M|PJEZwGoeG^#;GB!i}cA)RnRd9*_{5*WJohBqpRAK z7~DXe`}3yjzI^b4P+5Vq24G;@P8q-hPOe>4c?2`%a1&qcW=p&m1vci8G9> z!tKgNj{U)WT$8Oq&PDY1nMcXF*l7p6{qhrkpeysA#d^5gWwTQ;>x}0j; zRl7zSuPpx4Q7fW`sk>~KYPll0KO%x|YdRXY*iI^+e*Oqdr}$`Wqm3R$DJ_Kqo>>E{HzlRpE6r_PH|yhI{Hn!b>LrO?H#-H!To!UlqJj{hoaM|aeTKWpEMXrx<4yL zTQ*QZTb4(F*c}qXS@Q67M44CIPq0KKhdhn_Wr(Gde03^vrK_GSchFOtSP6Kvpk>C` z#0X^C+2ds!&^k~ofL9?a@+AmLy|(sf37CJXY8epc6In_{se&V*-+O_M6(p(e;Oc`k zg6o_~Y4nAqLIQawlnmOafc4DQ*WEU}4Q{n!`mGe zi3d1bW&kLz1pssk|AbiJ8r#?Z#ulJwu;{OrkC@oYQ-FQ24S_F==;o#&N-%!IV?@?6 zrkWNm<5EE5!AOZ}#Spnd-{w8duK1c`=i|?hQS8~wp#5M@+^;l^thEs%s3VYMaC}s5 zmNSbhwm9zaj8V6@jrgx=tH;DCAv1}Ymh~;E%tOyPE2a@@ViuS&P0iA&1nnIbg!xFEaV&4TtrYwl-aLb|Z@Ubp0?N z{6$*lga_#l!<4&~vz2Me(_Z|*`|>z?KZFYCGRWrk)H@B1IsY6iD?a2bQ-QphDRAMN`xu%P?P?ESr)LBe_i+Wu-Vi2phg~H zX?*lxBbbjzODiKC2||NdYMvvCWrni=U-C(;P%P_SV$8La{jM}}%)x;nofaSG^k_=` zCa~c#D}TLfi3}S?eV~$$ISzLmX@5=o`A%z~LU3qEMWiQ0vOCn-NymX_7jH72c+Fa8 z*##UWllBZA%=(x$C2C5ONhEaB!9SVi7l8ZqIT21LX{GF6V|cR`e3W1@7VGc}5A82e zHby=0l4lfOU2IqscyC1n&|>r9Wjij$Jl!Kx;KI6~Uo=vDQMH-$`Lb1jSb+t$EYn6F zrEJehlR~VJ!M-Qits#xjq2AQt&6#|q_-v7LFV_;88)27z~`Q) zQGUs7oA{MU-A18oHjbV=DH^<~h9d8rbmVt4G*E;h$yMPGJV0qIf5`?Ol6k;r8(3h` z5(~p?fn*n!q1T>+*X~v`N=`U8RP(R@(-X2Bf)$ef%-usElF&m?l@@#m6rszYRE~H_ zB5B7$O*EyW66GXi0vV31U6t|JRh`SyAXT0F-Btz$7sUrbI z>8e^vf4u@HoimA4w=`V!O*6@gsm$3-&hK6LVUE>wTuIHcrevMAp1!S)wtE~)h%t0; zmP)%WYd(*S`>u7abk#6CuEpCt0>u!kV>m+zUDTi7ZY(V>{aIUMBU~)>(+1NFRwI<7 zr>-FTEf<~^erV?~ba~FLa_kSuzI+MOc(`z^bg*<}6S+km?>%&Ee*DIke>?D8F(qLT zFh(N3rEu)$5W29OzA8um&~h*%X^;1PfWzV8E!W&h)#fhj1<6AqyXN#!DjPPNuvy04 zrl6sgcHx;@ppbcRrK$E-lT5}u0cV+2+g?R7xPO5x7UBr+6|-QX7-AL6c2j<>(}ibR zK?9?zXB|lhz(IPN|M~i!;1!vfm)35Pf{xqf#uB9T6qg&tpD0Gwe^TD%;={^|?EfEL2$C#Z+Wq7ur&#>e!F^%uhRqDE$NF>S}XR^N_w zc3t+-`+;~BdWQ!lin~mA% zVIk_mdCR>8G*hsNNwY(?f0N@H?3foLm<4S!Ug6){2?vXxIDqNHwfkZcol)#7^B?8# zGU_r#9Y~}XWLX9oJ=Xl!pgVXNKi$*CoEHx>bBtCq95(m3 z>W5GKIOQATu|*8nk}>H~3n)xvf==xxq^%F41-^rqN5e?dm&DPp!q{i z>Y$Z+6jEX5k!9E)BG*>VTJn9R`x}3CfUg{Y7k$#WBMVNJDAVUALKZLz(Pv;X$E4Z% zCcXm9UoUcou>kGh#iLw3M7qU4Z8MT(49 zl-vyJyd=6!#g`PHUPWF>aN$!uerH~mNhYT#w7Kk{JjL=^4e29dHlVQb>wg#Jg5eyT zCpgybUMje1+gl!Zm#i<&V;v#uyT$!^EO*dRyOc^OYMi&XUqQ94v{LZ&-u#Q}nB{4= z9d4ort#Mj5q%O^kBN#0F(^r08q$0H(qQvID-=o;<+`Up97@eo0@J3sZhh1O23vYTP z1@J4f+jPopcaEi4Q3%R7q0~_GqmoJ5N`}wVwCUaDQ3k(ugERi!!3SN_Y~@YH^TrkZ zIr2t-h9E=-)iUYgoDn%)S2)8$TiqlekC)m?rg$-?-VX*53Vkh|w7bjeuhSAggi&y~ zXTR{5^3%aFl+sV^)8)?(K(Lx;;f%0U_vzmxnncF36GX*B)3V}cG=?oKZ2deUssoea zVX~4_xF4Hm`48w#qvpVhs#AyDO_ zW*;MklVIOhy! zAV!T%->|q({sXma47<)O*Iqi1RT#{}6|FYI<3{ zS=e%&{5DuBbirGqr^R=yRHlYv!sdh#L*@MbBm*j}>H(}Oks4Xc4Xm;q}KyB2gNwI{ig{W!n3D{A}^@9|rsR+YN{Xn+m zfhMxh?SXx%+*g{1Pvkf(hobv2K12u9 zooMtm4x4=D!VL1KSWBrIW`-W_h=C-@Hz|r!5@d)zAI~gBL-k^ zy3z8&6Tp~KK@J-wqM=347?`>Ko6lUhbA039aRJ;1i_D*rgZ$*Fp?ihzpRm_4bhO7M zyWIC@-lv@Ve5-*a!yxnSTGyp<(uTF7n0Bt0ice@J`LhD|()UMUUp7|7W|I*E5AmjR zCvJAGsrrArz`q+}2(9(!EJdvhj@{s%oa9ng|m?!l7+msR3Q zX!T3hqrK&>I>F~XpnJ@E*klvB6r8wHrL~oUuM}14m`23+aVHk&t=qFkkZ?Kt7|p)P z8GmYut}B;pptpn??f-f0X@P{>P2dGv(MB$#%@!xVcG5;qi_@xd$XHVMgLS-j{%=ds zRTEI}pHrIr$V-pY1MC}lQQ{<;as(!BVS%%u9ixm=XQ^Y3N`7_8WTU%oK@kX~I86aa)+jb0(wDi9JZw1;Uw)$@dXuG%X zW4Bj?MC1nXS9T91BXJ9$fBqjAgzTY4Cz;``w)Qn$-|FxCZ4=t3Qcu@l-pMlYy~>gs zC$M`J&0hTMC0PRCorj9kDpP0Qyf-1|QXtK8vbLQtlDKj#$iGCsf_<;-myK3l( zCkz)m`<@!lZ~R|PeVA5~lZxMhL(Atvkv`15){q+cJV&^j3whIbIr z5G#Q6@lf1ZEnh@uy4qgCA>zNt#JTW^N-lAdBSrX4dqTM2^Eg;eZ2Yzuh*atRDd#ky zqfNHDwSTa*`FgEwC=lysw@`}HNmm88Nv&BOGt50GCUOQ{L7Ny<59&FmcB6SF~D!{*LmZ=wD2G6R^6i7 z(HJJ!^eUij=ky!Jm)DE^OiIrmvc|9rl)M!rEEs7B^$x!5PHRlnc~IZsVx<`Rg2UxC zjRm<}tKj?!1XPM5{&amrv3GR`_v9=8<}%&UXZV8#p;lxVyd@Kn`<*-DCafkCH9qvW z=Sqp7!VP#hiVVJvA{GT4$TEDQtSFmnJSClIs=B;Hf{+pwcFj;}X{uC_ z?WLey+@9Ts{z>uxGE=_nIs`IEhYO;?qyneRzk&)B|Z*{BeD4e*Zo8irR-~t z?#tSmTxS74;(~}FnHKUx+f?@1hB`H=;FgC{@pPE4H_YpWf9eYAYz|!`$>JXFwOc6^ z_V#qNvz_HXH`bohC4kqTG+utJL!{aPS+Q1%1>^FXLWV|p zU@R47`)nfd*psE8e-aA+`?>w?Jd3c@0jEl?GjsG^mdLUY(_lwu0!e{|pGB`^rMcEQ z%y&aV-g|$%|F9&t+RXmjQG4Y#GsxqDM^os&4j1N>qctHf7e#jU+8Bd>h!N0)Co?aqbcxyT(P_yrI3W#v5kx>GFUz`5k<;f9-e+-i*~f zBy}oKu5~KN>5%L#EA_TrD}kvu!B+&q-ZH+?D7{jBccU6oHy54WH-x=~d=nDA%uYBu zW@C$X61gkhj_(t5{P8B_V7^h_us+T>aefiOAE>4H*fP4=!2ql}U0dC!)G^I>5Mb(={g9^5vu$AMk!f4ZjMTijCtsja$R8!mWV~*VyZmrGA8x{oE$v^`5!+QULLU9# zRb8{mryOA>M0E-neB60C6sG$xn!ou^2kR`4msrGNz~O0oSIvy0u_B;Y&Yj6hhEB^j zp<5j#td++lEtt7+7#{Ex#Kwx1B|SH8gu=94Zs`JUqw22A9CR9k+Cy8LAEm3@(y-+J=7Azbwmuinc+pFiJcj~y~ z0hS7}=hN%av=F?x5|!+?n;@X}p|_0+^3AnZt=x8g=h>aQj^AXHS%!*~XVRIwO(dsb z{X*+m8TivXQQup90gpv=#+o<9YSEm^da175F7gQ^ky4Mjo+vZ>&M9m zr-jMjk!B0C-GY)P`OYJ2me}70ZGg}u<+duL_z)4asaaDS8)1{H5Ep(*7s_u^2xrOA zWZ8c|q3U>0OIGD`H0vu&xGNc1(i8S@`*n9kMP_)@Z2OxE;ao4{LoFz43JFe+9P=&i&eec_DuQZ>6hYJ(t8{)-c)bn=i`hz%#YzlqUHQwXY=FZcx_Tp zeR@NpiohRN@B)70Y%Ex8XlbD_JEeFwM^Sig|HeRnv!+{d(9eLSS_}9xXHu)GBV8o&>gJrHw?>;@o zscbB@+ojwN#5n|NpzQD2aAl>7&7x(-4+aO*04G~es!L8N{h?Y2=FXi@j5ZQd!5@0t zsT^2?dI`pUz2{-@OAyn>7cm%gf^;{UOl`?Cl9#7i7y=h6`jTLSRXEM&FF5@r_Shap z9QX$tm&SL++n=`>))(3nfi2U6s6Tmv=DfFHB7@8%7w3uspq}qo3>zv<-IL(%4c#VU zsE!FFzFU@*ZbEE=fL7z5=Uu+fSN^(5#(it*or5Po1)#%gj3I+QKii)`E7!Z$6DGLx zK8;M*A|M9MJybXJ;7s|?P+|Al)$do{2%lsB6gc!W~x+i3LCGxHlpj0u>qvCm7No8Ar z`0kJ{_t^@sg{b)jmP@2A<$k>~DVO}7kZE3U1rt4v6C#1>+zDR-J;|!X>aCWYjmxp4 z39Fj zMb^S;_HAbj3_F%SMDZakmmf;5Nu`VeEs&T496qMHP!S?Kn*EJzsllN}ah(f&wi!HoBp${Vm z62LnvlI*w`qsk_I=e$Sc=_tMp(XWTIkKQIeS$j$aI?h10xiO*-A<~#c^ z4&UWoy59Qs3ufk*bVQ9_bzc{U?Uj+Ue!is0sIhNHcX6ov?LzSm^P?_$^Ta67QCJqz zr66j3tNVcX%VJ()k9ps&^aE?#sBJz&MGEgSb8*+ng5AT9n9kagu%$PvY_`Lp-l@** zKAa!yj*7>*?Gu;q8{cj7;76eEXua902xi7D{tLrfgkwpR;&_T8R;e=x)^_VW{GvSl zr$-_W1cB63QWpffp_$!g0-(|wVQ(Z1#HM$Cc5h5N$cSH zcx7x?68ZI7)W=chfsgade!U$`tv)=~P#8`Qcp-sdn8JbZJxAUrrAB{qnMYC%y} zIks1dNyQ5HhskjSRRr4Nn?PnGNA1&dzJ$DBm?YD2uZq~iZ8|J76}tecJI?Ijd-kI{ z=Sf8`=d4r+Um(1aDoN08q|tan6=@s%q)U&nbY_>W{dw_^h@F(VAHqe7!cSJOi^iR? z=1>OyHt!#fkuNDf5ZSpNXA>2$2Rbcu`L_M_4&eCg$#o*Mr{g&t8Z;m5REKA8i2CwU zpi*}u^*h>1LJ2pLOm0pHxB#73O6SNqwP=VV)P;8lG4E<(9gtHk9;Wk)<=BW44x@o6 zWfm)1F%pwOhrZiwwBx7Ijf@7{P5ZUSZkL3NJAHo_;)R}@F{b8RAv5BlQZTa3It zX&VQ+rfNwV@?c!Xcw4SPAW_|K3E1W>Hf6Ka?Gw111_2v4l)ni91^?aYu;< zQor80`sJj4gl&r!b7`ca(d@q6?E4G}4Tr{$ID>9#{- zf~LswUp4xZnKO2AF>B>wq5d(4_Cm{M-F_#0w{K7xW0-{<%RckSdvoBPBJsa)%NQIe zt<2t782bJ5M}xV895c6oL0`eQDoG6LT-v&*ZXaD>F&~u?W&>cenuVjX6J8uE{M-8MozQF zYf=8QMdHGEmw&aGZw763HU@lrMGDA+c)dyjRaa0US-6h2S3Kv7bJZ3k9V1jnF3U=i zd4~`fk)e5xZFgdQM{ya`9et~*&$WW?Dkwp#PY3iq%)jp_od*0}t!|WDwRO5Z z7`PAuM4Gu~1+jW~zJ`?16iMLLu*9LYg8x3=+6-oj!dWRi9ZHW7rH!N-Y6eX=%_0-3 z$-mFP%da2C?d6G)?==ir}a^(6W zKd)WWVP217G#!={5ofG>`K|UhQoM-PC2O#NREucrz4}zh>fcIcHTHM3J1E;9dM3gV*O5A;Z@5To5O3SnNxEtGAdvVIQx&5(5WxNaI zQ95iQvaf-8O$=U528bc>-ED-?v_#@W(@Wgr>E~Bh*GnrcyyDX=N@&818zw*BAja;(ID8=PxX$qcr+%Q_%Y~~qfWc0!JHy|~;G-o_ zsi71~UYmJa>GF3rUzGFKg6_P*WynQiXh*v#V@`j&UEr|k-^#+(N?gT?D@3mhofQ8$ z4N~Y%_gMD>+beIF;isD28)JGLoTN!CT+e{y@CP(qZBmYjHlAfm;lGnWQt_@k;viM_TWNp5y z?5@2EO8$Co$e~3Z6Cwfdnn>-^c=SI1oax<6W{zEUQXhYPGMZyze!U}9^OdXFRkNXvjojtWD!iH_ zXADL!_bD5e_$1d?;X1r${4c2-&-{~j7owYh_%p7@04n6MOH3w3mVta-+8>Xe{!4|I zy(8zNl$bmS2!ode;Z4}QG{014`dt4%&x@5h2Xa)fW!Mk(;*`4f48n}s{)p_=E;_Ew zlcWykbp;-9$%;WJ1>ts|c7HX#`l$32xAFKPaEnK`QmDz8C^lpkNwQW&9(fK z9vR9>t*S8YK22uP7Y2r;Va&W4%ai0OfsKRodM^%`0>C_PGGqaH!BbTsukYS6FBg>? z4+boL(}?r$R-Rld@k)s5D9=*R(RK&HI|98kiMS+x3sy$q3py!_{NFd#rY|}{u-lfc zsd-5K3|X@IEAiv9|Ng?G>n}s!ioSAfZHylWvWt)n3Iv2TFSJ-oebsqhWQ_BOm-MBU z#dOVl*cb~k?KB5na+jzMDt42!OI~q~)bjuo+pg8d>zxeB33sX`?qCv{e?G%)-_UAw zN^F}=fXFf9AgO_<^1Q$o`zBme`%IuW@HSTpl> zsJs!WO@QVy?>mk^3a6MG`Ig&|2Av~D2$pMTK-w4s2pm*|ez_P&^{jPUp`h5t}U&oba=ibfvM2&kY z8x5{-B6I{K$%1evFx}Y-KEJU|^=z+gM6L1oSqMv-(C`$a6S>Y?!uKF(R&)AiC&3h4 zTv2yj9-sZ0{9J{6Rt^oxg8g_>L=p5ZM^_^%W_(fP0-dF1mx13ldPSB=hZ?G$L-#6E zZs4kk)OXIK-0XQoKO01oiQjn#@T>DDeIL<6hsXlBB`5Y|8I$d*p_(O>L?4Dn^H(?6f+6z#a z1rDYyH{bd0rYXxKI+Zq=W+W^(%qzyiY?W9uaLsi%_h&D3JT7$^q$)V{n$%IE zzStEyAA_@1++Sr>5KL+cI3%^^=PfFJE_s}by8SoE@Vr>xD|gv{@R~`JP%O%=CCCz9bOTR;5J~s6iN;WY;CspXsn~S&)umN0+zx zlpRguSuy_-U>Xy-w0Huy?@)d*n2tCf0a2NJxvK-{@akDqNWM4`ZYB=oz!xzte{w%3 z{I75;y#^1izykQK-bGfS^JfN-Z%&i8v`vXW{5S2>84tO1RsYF&0#||a8O=g3_10$T zIx57!RR>qy!j*#52DSK(RgZ~>;3J31BQkUWY*Sa4iFZZp^o}i@sZ*oH<5vhblzHrz`{89;vTZZ8v0xDyN9E!4nao>Rlv#%Bdi1;f zA6iX&Zj2a9CYOGS28jJeuibOne>$`d_et@Yd0WzuI)bjr*a}kvc8g?~muF97Y9_4m z(tv=EAvNofR~}amtwg%{Vp$O*6|WDBa&t#s>okTLIH*?jdlwL@;kTt(;6cjM)tlbo zDt5PuuF(ruvp`y6cEEv0S^-DHO5{0hXX6X#l-fkX??I~jHz4Ml4vNx|{F34~? zGS~1DCQ92O@nvV=JgnOhDB@xmNA}ySWA~3jwoWUZ4clA|D>+vG98e4=*Wc}G!~uYC zj^0kUKUllY{?Esc$8$5e2A1!pa=jPdriKmowotT}Bry9k18Er_>kKAdfAM1w#`O%1 zo~$VCEw#Z0>z+J@3FvR*k4Ouje?ZWQIB6R53I1R0eQ7w<{oA*tG1eIovSrBI=C&Qf@Iu8C5Ahj;s;bJ9k0Lu9&67EpH&#cb12n=P7IiM4orfnsVb&;ipWRJ6 z@Bz#rhO4q|Z_v9PIkhGpc6~E&Ll?jE@k@qGF$c!gUsG=hWD%uQ_^k*UNWk2`gMaFD zd?>$>Fvn6dPLHyuSFG((x<c=d^l_NObtClQ$8>IcYoY>xjXb6c{k$+ISrj&JL z!Wh>V1ly96VM3JCgpfwPFDMvdz4DKelLE`>ar`Yyfn16Sgn{*@W@hd&A_LvPyDVSt zvwxz#9U(YNgoXq+Y{_4Zb|a|2Ybe1f3~ibi#?f-gAFGU{{|3;)&GJA%MzHA|?#JT` zJxjhk-##8y=*ywts6NBv&*pJ^6&d!$3O_OZsX&kW#q*wusY?fMS!%qS=_L4r10}a7 z6eBf#{$_rmnY>>w=HhX&r+49041Th?LuZ>GXloO=)4@)?-acWFUU86iK%cc018(nG zf5EeA7Lv``X^L6$X6M8-MrAin;%kj7&)VZM->Pl5A~`8~j$@!3y)1y!!vI@ZkUeS_ zE`BiyPK_<{D8)4{YbKj0uV-}%__#oSq~QiIjPpEEhSgYLPIH)x^yV}`#O~=+Nj#L~ zKQrqm+D7v|;f)$=ligCQC_kFBy^v{(T#bIeD)s<=MjeGsuNU~Gz%3a^Ps@M{1a2rA4q!8D%=YFuS+f9EOW<1yp)jYd7 z4Hq`bGIX~YZ~|s+ym0KXuCscTGFEJY?Izf2k?s&M$Sv*4PiMi3Tv}yh(H z-0IVy8MWfqt-#ng+k3E5)iZ6Q55F@i|01}Zz2{@JPYo{B^&PI27sj>h$ z>))pTXm6eq>8g&z5%^G=-lANlRvCgn=1itq`mHb=ackQ5zremu>B$3u=J=yLPo=jJ z8pZN;0i?SZl5S}(`pqROfBK;=c~;=&^d(1G467xEiCoA6E0{`+=Kt4^Q^j<#uEWsz z*`NKIMrF<_Bb1CJx0=YSmO&>(I|ILHHRk=a?gs{au)D^rx1P$H0|cCX#P8K;uK7-{ zM5;OE_b-FR8D@nxH7&UtoM+p1{GSyI#=Um0RLPUAV9f!C?3B|p=O z!F^yx)?bNrFX3y{dYqd}rlN`#*5tsH;OugL8^zY38(pZZ;ug?&V{DcokaYKT zW?IS{1ba~Z-kg~8C3>og_7;6sQeP9*g2lAA+YKk$KJV7?;UQ=`bt{%6uqx_cfpWD4 z#)C#sy}{YZNE975gZ~OkIGCo0FRF9 z1Ne|;5G=XCBt7A2im5=vK9+!^LHZ6j9<`FTh0W zvVljGY2{hx4<;?$Qo8rT1EGBwagWp>MXe1Tw=EWmV^pmRA5c5_DGPXXnjL`qVN;_? zQp!GgY9V@|2Je<$e6KAn{-GwR&hU6twTr!w9Z*xVZ)p((sdvBhw1?AukzvWJ$f3?Z zNn+=c23PEo_q~lWWTzaGHI2JyI(+}ECw1RF6b2^cUG;8YBUvMOQvpD*lTANURV32c zf9SB8%1*0u;pksW6xHV_xqPpn-i@Q|((g!p6i0YxSbiR|8#CG5BFjXEU$N_e0%HNq zzH9bLfy4;3@S-8^KN`)W{6!Obz1vs_MMI2*P=AZL(3E3X&YMQ3m!;@po?XcYsXx!LH60^0Ru155Q*4So2gbE>p zggo_voMldB2JZAOOsp|zN@2cZ{n5o0<1snyub@}3pDtxcb@+)PCI33LT{gmHf4LC` zVZtS^j%uLbd~#3edc*yDbt@sz^AZQ9qc<}I(#eL=QS0sat>S`I8O_5hRgRska)XCoUgn4alk7F#Hl| z&O(or#}!MMjk^0q4ovYs z`E}_g(poKu5P7H4){BAOlc{{Xy_0k{2TIIE>8V)_SVBTijA)Jg<1I&6B<~=6fy}`2 z>Xehc6xzK1VuDxz#Ov54e3j8d88D&A8-2qPtW4 z!6AYlKQjS6Z@rm~>6@aemyKDLCccW*$F}Kf3Es0;S>6|mi&@j@dZNL|k`uP4LbkWq zJR!0o5^RI84>${xs5;d{6F1|@MoT;#XKK#mdC_eVnZ-y<)Bjz-rA)c6h#Ms)nL1K~ z3Z8M4CNfE*ePPSNs-g^n#y-iCig@!0M&*@8`)sw4Vi)&dC<3*bgjFNQ}3A z^ueX;SXuqwi4o(s{B+`7;Lm^d-j?bF3ijhBh;%N3K&j=W;e~iTAg-iL+vOY477JqX z8@UhkqiuAKPPE{uZmu2Ge89QP+zpq&>{x&G+FWD2US^aBMSFFkW|mhjtrWL5#8j$2 zAMGm>a*|@SL-9D7Y6w_HQ|2+?RMw8hVe#HK7lpGsf(L21&VGH!6DTWs*@>;bxnAbW zz{s5qz}n5Id6zsF!0klD_kdur=6|TZTC0x@JX8!*;=!Slg$QW4;no4{Q#WTB_y>R| zBzZQznV+B^!`k>jYn}+7p5zq|GlRGM_FOHRaEpE@mOS@)>;ASuW ztu%k-e@=G@IWMjazRagFn`hTO!|JzYGa`~{%xaMM4di?%fF0?#NM9z zHr!F+SOu0fHJAow*6>RqK)a`V$3B#s&>Hely!$+nv16TDFcG+;2D2^6cCW30ECDI>o#V(c+vvSS$dBRV$*!yxLh@jX2Q0}to!`?PeQNTC+G)n+PNW;Oi(1Hh#X<<_ z4dj?iIDFjYor7oBuw$v;nzonh8ZYf%Qtu>PY!5)>e}MT2~){^x{ysXwMAwl4H(pVuFXy%^4-<5M8kjSld6 zD+yo{;5`cPHe85e$2O`~Yn`(5PP!SP7>9i}E9sl^zMG>>(Q<%!V;Ze=^;UBpT|7>O$Js5_+o3~EZr+JXBo}zE@f=k5OqLF~f=i^KY+(hzk!t;S)gHI@ z#mHXDu{k8ry-#u!gZtuNh43rDMQBzkb*B#y~Q)4 zn+^aNNWVHTiN8Ht9wrQOFrGKQT@?XJ=3M;>wXp7^h;p(`B9RyT#?IYhSXW1gX2j{w5ph?< zpLy;u1ITGS#Cj;kPey`R9UA6u)}fPsNr?cDPG2V7C0!jj2TzR9}J89*i)s6Bbe^H=1+?1jp*h) z#~OHeP@TlBpzLNp>4A7>k{9u2mi^GYlV!Lazu2ZBjH`x?2ApkP_BPu6r(BST1zI|z zKY-x;bg>G`Aq41Z_v@r?ccc3GA&Fqh8hBrYSy}$e9rz_k()nyj^eGs~W>gHA0Q@W& zoHnjB#bR4-khb8CO&VlU6>_ht&kS>0${A|^#E%oT!6?HQZ75?3Yg?a&TMjXs^iN!~Ra2!ppGn55%vYq4yPwZlZHZMyok6 z^a@{H0QoLL!q(hD^YCAEXqNexPE7F8_lk>b2?kwX*>J`qB3e>gysHr&)AqPAiJHrs z_UOyqIfR&wk0YiDp~r%wlyN-oQIksG6bxsIpxkkDz=6BeCJbG3RIK# zX>nU+Kim}=X+@ZsK&HU*gc|_cl7+HVWiaEh9LhAzzVpiYVD{(j%hstxzt}j=QBraJY^jp`}ZbtEDm817Xia%C}GED3NU2b#@Ye|T>jNBXwDFJSXn*9}I> z1n=+SBp*LF+MUId(QfmFKsR7{0*$28G5XRSnLuO-x^$lyK=_68ZmRE$$#q?&7l3$IzNF%%8 zLu{wtEZ|_Y=v2|$)Eb&{+-^p$fj^>G+2 zi+xCA87&%p>QcwdR@Gg39d|Z z8Y;zm-&$-*5bMTQMsZrlg4=$>w>-lcTdRTILtxSb^;$bWYj*k8I}3OEmqCPgh^$$V zHzp#T5g&ae(S~UQ_kHD(YaUHpO+RjUeRS=bO8onS-3acrtq3~?|DlO ziEDFRm5;1sv&YcpI`K1!;@KB|E;SKbb{_Vu5O0r*NS<|89rmD-Uw7#x--B(C9n9d^n1kq`@+FO@% zeYOTQ<#4)aQdfOTi&YvF7`lEU`@_m3ruH~#QaW-6@K`%n`A%Lig#Ox5+@4w6PGNQp zj0)Jb3Eq7fZ$24hvb#I~7_DGrsFTG`J>Q=2jqc@|=;Hl7WE5J>;X0JZGPp}%M$ zmk+10T*zrDKmC(QicvUjymCvUkCx8=$-FoR=&~=&Q{5?J@-(?V^>}OqTlnhQr zu3l8YuxS+xPA;=6pVf-vtTTVgL$7q%3FnQDe*1P1ePnT_5fUIDfm#o|y>(Gezrr zw^-ue9hzH%IAz*ty&L3?iO_Kc>V+uq`RCmoAnM z-gtW_{PfMDamwVpXYMxPLEt+#3tg$`W~Bay!=KjQLdBB@Bu~|)_0?7g0_H)B_yvn| znW#yz=G`h2oAsL5SCZ^X z&0zqP)B+L@L2oU3z#>7A7ZRcQijc#g16e8ue$)i8&$AjEpI7Q??C@`@HO&ek;5qu}ZiYTZd^4kI= z4E-aat~qoL?%YLy`#`o#ew1j6+T(?giBPo0XU>l@CuM7jjwM#6~y~Qr6fF+$aF^E%{yW&k<&iWJ=~N= zQjGc0&3kh1F_2~U5qV|Upk@JsQ}Xa#)Ur@4zsM|*!_64rzi$?%Fhjy!!#bAv>b`DC ztsSH8zC$lDA4O;EjIU0JP&qNbV?q}U+2J}}G{GJ@7`T|UC7yqZgK*l`T3S(vDk~XF zp9(uklet^t!h}ZZr&+P7<>xQ$+-CY{U>JR4U1c@gd27Yw9k;O1np^f~iX`x$IMr>| zJ!;$s$nd_^;klDA2$g%>N5%CIqRu`kXMCmvd$=neR&#ribSj0MR~5c0*J z2eApdvo7!r#^~^1{8f6lsp3t7IbW{GR*fLDb$p0~W4xS)A}%gRO{!06n)DEeTR^Jq zc~rG$>7kSFofOyqNbOzsXHIEwUE2&0q$3BN#}=rd37cIp_w*s=c7kFV>r1HwbK}+r zq~qSMbZP{UYd13jxQPDy|5lj|T+_e5|FPQi|Gk0#*BhW5F|6s<_%Q}2k1#MWNQau= z2=#Oe_0sXU=LP&Rs3@ywC@8BdsHiwx)Yef^)=|+uudJ-2temWTs_6e(5D?_)>mBi* r7yJ%*EdeYz_kVT>^$qX}33Uqy{?BVl!XF<3YZxret+$e RN@k!qgQu&X%Q~loCIH@95Y+$x diff --git a/public/icons/icon-source.svg b/public/icons/icon-source.svg new file mode 100644 index 0000000..f4c132b --- /dev/null +++ b/public/icons/icon-source.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/logo/favicon.ico b/public/logo/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b3c8a772311b49ff2bf8614efd272d9afb99bf22 GIT binary patch literal 15086 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 b{St`gs*s + + + + + + + + diff --git a/public/logo/lernschiff-icon-monochrome.svg b/public/logo/lernschiff-icon-monochrome.svg new file mode 100644 index 0000000..6e0172c --- /dev/null +++ b/public/logo/lernschiff-icon-monochrome.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/logo/lernschiff-icon.svg b/public/logo/lernschiff-icon.svg new file mode 100644 index 0000000..48fdc63 --- /dev/null +++ b/public/logo/lernschiff-icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/logo/lernschiff-wordmark.svg b/public/logo/lernschiff-wordmark.svg new file mode 100644 index 0000000..130bd1d --- /dev/null +++ b/public/logo/lernschiff-wordmark.svg @@ -0,0 +1,10 @@ + + + + + + + + + Lernschiff + diff --git a/public/manifest.webmanifest b/public/manifest.webmanifest index 350fe4a..84f17d2 100644 --- a/public/manifest.webmanifest +++ b/public/manifest.webmanifest @@ -1,22 +1,32 @@ { - "name": "Lernschiff", - "short_name": "Lernschiff", - "description": "Kinderlernplattform für 3–14 Jahre", - "start_url": "/", - "display": "standalone", - "background_color": "#f0eee9", - "theme_color": "#f0eee9", - "lang": "de", - "icons": [ - { - "src": "/icons/icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/icons/icon-512.png", - "sizes": "512x512", - "type": "image/png" - } - ] + "name": "Lernschiff", + "short_name": "Lernschiff", + "description": "Kinderlernplattform für 3–14 Jahre", + "lang": "de", + "start_url": "/", + "scope": "/", + "display": "standalone", + "orientation": "portrait-primary", + "background_color": "#f5f3ee", + "theme_color": "#f5f3ee", + "icons": [ + { + "src": "/icons/icon-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/icon-512-maskable.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] } diff --git a/resources/css/app.css b/resources/css/app.css index d14f83c..26f7a31 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,7 +1,47 @@ @import "tailwindcss"; @theme { - --color-bg-base: #f0eee9; + /* === Background-Layers === */ + --color-bg-base: #f5f3ee; + --color-bg-soft: #ffffff; + --color-bg-elev: #fafaf7; + --color-bg-tint: #f0eee9; + + /* === Ink-Hierarchie === */ + --color-ink-1: oklch(0.22 0.015 270); + --color-ink-2: oklch(0.42 0.012 270); + --color-ink-3: oklch(0.58 0.01 270); + --color-ink-4: oklch(0.72 0.008 270); + + /* === Lines / Borders === */ + --color-line: oklch(0.92 0.006 85); + --color-line-strong: oklch(0.85 0.008 85); + + /* === Brand / Primary === */ + --color-primary: oklch(0.50 0.18 255); + --color-primary-soft: oklch(0.95 0.04 255); + --color-primary-ink: oklch(0.42 0.22 255); + --color-primary-hover: oklch(0.45 0.20 255); + + /* === Subject-Color-Tokens === */ + --color-rose-soft: oklch(0.95 0.04 25); + --color-rose-ink: oklch(0.50 0.16 25); + + --color-violet-soft: oklch(0.95 0.04 295); + --color-violet-ink: oklch(0.50 0.16 295); + + --color-green-soft: oklch(0.95 0.04 155); + --color-green-ink: oklch(0.50 0.14 155); + + --color-amber-soft: oklch(0.95 0.05 75); + --color-amber-ink: oklch(0.55 0.14 75); + + /* === Feedback === */ + --color-success: oklch(0.55 0.16 155); + --color-warning: oklch(0.65 0.16 75); + --color-danger: oklch(0.55 0.20 25); + + /* === Legacy-Tokens (Auth-Pages) === */ --color-text-primary: oklch(0.22 0.015 270); --color-text-secondary: oklch(0.42 0.012 270); --color-text-muted: oklch(0.58 0.01 270); @@ -10,10 +50,24 @@ --color-accent: oklch(0.42 0.22 255); --color-accent-hover: oklch(0.36 0.24 255); --color-accent-muted: oklch(0.96 0.04 255); - --color-success: oklch(0.52 0.18 155); - --color-danger: oklch(0.50 0.22 25); - --font-display: 'Plus Jakarta Sans', sans-serif; + + /* === Fonts === */ + --font-display: 'Plus Jakarta Sans', system-ui, sans-serif; --font-mono: 'JetBrains Mono', monospace; + + /* === Radii === */ + --radius-sm: 6px; + --radius-md: 10px; + --radius-lg: 14px; + --radius-xl: 18px; + + /* === Shadows === */ + --shadow-sm: 0 1px 2px rgba(20, 20, 30, 0.04); + --shadow-md: 0 4px 12px rgba(20, 20, 30, 0.06); + + /* === Layout-Spacing === */ + --spacing-sb: 240px; + --spacing-tb: 56px; } @font-face { @@ -21,7 +75,7 @@ src: url('/fonts/PlusJakartaSans-VariableFont_wght.woff2') format('woff2'); font-weight: 100 900; font-style: normal; - font-display: swap; + font-display: block; } @font-face { @@ -29,11 +83,19 @@ src: url('/fonts/JetBrainsMono-Regular.woff2') format('woff2'); font-weight: 400; font-style: normal; - font-display: swap; + font-display: block; } body { background-color: var(--color-bg-base); - color: var(--color-text-primary); + color: var(--color-ink-1); font-family: var(--font-display); + font-feature-settings: 'cv11','ss01'; } + +.font-mono, .mono { + font-family: var(--font-mono); + font-feature-settings: 'tnum','zero'; +} + +[x-cloak] { display: none !important; } diff --git a/resources/css/safelist-tailwindcss.txt b/resources/css/safelist-tailwindcss.txt new file mode 100644 index 0000000..c99c89b --- /dev/null +++ b/resources/css/safelist-tailwindcss.txt @@ -0,0 +1,5 @@ +sm:max-w-md +md:max-w-xl +lg:max-w-3xl +xl:max-w-5xl +2xl:max-w-7xl diff --git a/resources/js/app.js b/resources/js/app.js index 8337712..fe59342 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -1 +1 @@ -// +import './echo'; diff --git a/resources/js/auth.js b/resources/js/auth.js index d49d29a..fcd0dda 100644 --- a/resources/js/auth.js +++ b/resources/js/auth.js @@ -1 +1,2 @@ // Auth entry point +import './echo'; diff --git a/resources/js/echo.js b/resources/js/echo.js new file mode 100644 index 0000000..41ce403 --- /dev/null +++ b/resources/js/echo.js @@ -0,0 +1,15 @@ +import Echo from 'laravel-echo'; +import Pusher from 'pusher-js'; + +if (!window.Echo) { + window.Pusher = Pusher; + window.Echo = new Echo({ + broadcaster: 'reverb', + key: import.meta.env.VITE_REVERB_APP_KEY, + wsHost: import.meta.env.VITE_REVERB_HOST, + wsPort: import.meta.env.VITE_REVERB_PORT ?? 80, + wssPort: import.meta.env.VITE_REVERB_PORT ?? 443, + forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https', + enabledTransports: ['ws', 'wss'], + }); +} diff --git a/resources/views/components/auth-session-status.blade.php b/resources/views/components/auth-session-status.blade.php index 59ba268..6009ada 100644 --- a/resources/views/components/auth-session-status.blade.php +++ b/resources/views/components/auth-session-status.blade.php @@ -2,7 +2,7 @@ @if ($status)
merge([ - 'class' => 'flex items-center gap-2 text-sm font-medium text-[--color-success] bg-[oklch(0.96_0.05_155)] border border-[oklch(0.88_0.10_155)] rounded-lg px-4 py-3' + 'class' => 'flex items-center gap-2 text-sm font-medium text-success bg-[oklch(0.96_0.05_155)] border border-[oklch(0.88_0.10_155)] rounded-lg px-4 py-3' ]) }}> {{ $status }} diff --git a/resources/views/components/btn.blade.php b/resources/views/components/btn.blade.php new file mode 100644 index 0000000..795d79c --- /dev/null +++ b/resources/views/components/btn.blade.php @@ -0,0 +1,30 @@ +@props([ + 'variant' => 'default', + 'size' => 'md', + 'as' => 'button', +]) + +@php + $base = 'inline-flex items-center justify-center gap-2 rounded-lg font-semibold cursor-pointer transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed'; + + $variants = [ + 'default' => 'border border-line bg-bg-soft text-ink-1 hover:bg-bg-tint hover:border-line-strong focus-visible:ring-line-strong', + 'primary' => 'bg-ink-1 text-bg-base border border-ink-1 hover:bg-ink-2 hover:border-ink-2 focus-visible:ring-ink-1', + 'accent' => 'bg-primary text-white border border-primary hover:bg-primary-hover hover:border-primary-hover focus-visible:ring-primary', + 'ghost' => 'bg-transparent text-ink-2 hover:bg-bg-tint border border-transparent focus-visible:ring-line-strong', + ]; + + $sizes = [ + 'sm' => 'px-2.5 py-1.5 text-xs', + 'md' => 'px-3.5 py-2 text-sm', + 'lg' => 'px-5 py-2.5 text-sm', + ]; + + $classes = "{$base} {$variants[$variant]} {$sizes[$size]}"; +@endphp + +@if($as === 'a') + merge(['class' => $classes]) }}>{{ $slot }} +@else + +@endif diff --git a/resources/views/components/card.blade.php b/resources/views/components/card.blade.php new file mode 100644 index 0000000..22917ec --- /dev/null +++ b/resources/views/components/card.blade.php @@ -0,0 +1,18 @@ +@props([ + 'variant' => 'default', +]) + +@php + $base = 'rounded-xl p-5 border'; + + $variants = [ + 'default' => 'bg-bg-soft border-line', + 'gradient-primary' => 'bg-primary-soft border-primary-soft', + 'gradient-violet' => 'bg-violet-soft border-violet-soft', + 'tint' => 'bg-bg-tint border-line', + ]; +@endphp + +
merge(['class' => "{$base} {$variants[$variant]}"]) }}> + {{ $slot }} +
diff --git a/resources/views/components/input-error.blade.php b/resources/views/components/input-error.blade.php index 850fad8..2474a9c 100644 --- a/resources/views/components/input-error.blade.php +++ b/resources/views/components/input-error.blade.php @@ -1,7 +1,7 @@ @props(['messages']) @if ($messages) -