From 969327f41434d282396304f3eaafe8ca7896a62b Mon Sep 17 00:00:00 2001 From: Phu Cuong Date: Sat, 11 Jul 2026 22:56:22 +0700 Subject: [PATCH] Update zalo bot, db cleanup and migrations --- .editorconfig | 18 + .env.example | 65 + .gitattributes | 11 + .gitignore | 10 + app/Console/Commands/CleanupExpiredLinks.php | 45 + app/DTOs/AffiliateResult.php | 16 + .../Controllers/Api/ConvertApiController.php | 50 + .../Controllers/Api/ZaloWebhookController.php | 194 + app/Http/Controllers/Controller.php | 8 + .../Controllers/Web/Auth/LoginController.php | 84 + .../Controllers/Web/ConvertController.php | 37 + .../Web/CustomerLookupController.php | 41 + .../Controllers/Web/DashboardController.php | 21 + .../Controllers/Web/HistoryController.php | 42 + .../Web/PublicConvertController.php | 69 + .../Controllers/Web/SettingController.php | 114 + .../Controllers/Web/ShortLinkController.php | 45 + .../Controllers/Web/ZaloChannelController.php | 93 + .../AffiliateConverterInterface.php | 17 + app/Models/ConversionHistory.php | 31 + app/Models/Setting.php | 30 + app/Models/User.php | 49 + app/Models/ZaloChannel.php | 21 + app/Models/ZaloDiscoveredGroup.php | 13 + app/Providers/AppServiceProvider.php | 25 + app/Providers/ConverterServiceProvider.php | 26 + .../Converters/ManualAffiliateConverter.php | 51 + app/Services/HistoryService.php | 67 + app/Services/LinkConverterService.php | 197 + app/Services/SessionManagerService.php | 49 + app/Services/SettingService.php | 65 + app/Services/ZaloBotService.php | 237 + artisan | 18 + bootstrap/app.php | 19 + bootstrap/cache/.gitignore | 2 + bootstrap/providers.php | 6 + composer.json | 86 + composer.lock | 8395 +++++++++++++++++ config/app.php | 126 + config/auth.php | 117 + config/cache.php | 117 + config/database.php | 184 + config/filesystems.php | 80 + config/logging.php | 132 + config/mail.php | 118 + config/queue.php | 129 + config/services.php | 38 + config/session.php | 217 + database/.gitignore | 1 + database/factories/UserFactory.php | 45 + .../0001_01_01_000000_create_users_table.php | 49 + .../0001_01_01_000001_create_cache_table.php | 35 + .../0001_01_01_000002_create_jobs_table.php | 57 + ...4330_create_conversion_histories_table.php | 51 + ...026_07_06_164330_create_settings_table.php | 30 + ...7_11_000002_create_zalo_channels_table.php | 30 + ...04_create_zalo_discovered_groups_table.php | 29 + database/seeders/DatabaseSeeder.php | 25 + debug_after_click.png | Bin 0 -> 98621 bytes debug_screenshot.png | Bin 0 -> 105525 bytes package.json | 17 + phpunit.xml | 36 + public/.htaccess | 25 + public/favicon.ico | 0 public/index.php | 20 + public/robots.txt | 2 + public/zalo/qr.png | Bin 0 -> 16609 bytes resources/css/app.css | 11 + resources/js/app.js | 1 + resources/js/bootstrap.js | 4 + resources/views/auth/login.blade.php | 83 + resources/views/convert/index.blade.php | 84 + resources/views/customer_lookup.blade.php | 282 + resources/views/dashboard/index.blade.php | 74 + resources/views/history/index.blade.php | 247 + resources/views/layouts/app.blade.php | 113 + resources/views/public_convert.blade.php | 400 + resources/views/settings/index.blade.php | 171 + resources/views/short_link_preview.blade.php | 25 + resources/views/welcome.blade.php | 277 + resources/views/zalo_channels/index.blade.php | 245 + routes/api.php | 14 + routes/console.php | 11 + routes/web.php | 64 + storage/app/.gitignore | 4 + storage/app/private/.gitignore | 2 + storage/app/public/.gitignore | 2 + storage/framework/.gitignore | 9 + storage/framework/cache/.gitignore | 3 + storage/framework/cache/data/.gitignore | 2 + storage/framework/sessions/.gitignore | 2 + storage/framework/testing/.gitignore | 2 + storage/framework/views/.gitignore | 2 + storage/logs/.gitignore | 2 + tests/Feature/ExampleTest.php | 19 + tests/TestCase.php | 10 + tests/Unit/ExampleTest.php | 16 + vite.config.js | 18 + zalo-userbot/bot.log | 0 zalo-userbot/bot.pid | 1 + zalo-userbot/bot_err.log | 0 zalo-userbot/package-lock.json | 477 + zalo-userbot/package.json | 14 + zalo-userbot/qr.png | Bin 0 -> 16609 bytes zalo-userbot/userbot.js | 351 + 105 files changed, 15119 insertions(+) create mode 100644 .editorconfig create mode 100644 .env.example create mode 100644 .gitattributes create mode 100644 app/Console/Commands/CleanupExpiredLinks.php create mode 100644 app/DTOs/AffiliateResult.php create mode 100644 app/Http/Controllers/Api/ConvertApiController.php create mode 100644 app/Http/Controllers/Api/ZaloWebhookController.php create mode 100644 app/Http/Controllers/Controller.php create mode 100644 app/Http/Controllers/Web/Auth/LoginController.php create mode 100644 app/Http/Controllers/Web/ConvertController.php create mode 100644 app/Http/Controllers/Web/CustomerLookupController.php create mode 100644 app/Http/Controllers/Web/DashboardController.php create mode 100644 app/Http/Controllers/Web/HistoryController.php create mode 100644 app/Http/Controllers/Web/PublicConvertController.php create mode 100644 app/Http/Controllers/Web/SettingController.php create mode 100644 app/Http/Controllers/Web/ShortLinkController.php create mode 100644 app/Http/Controllers/Web/ZaloChannelController.php create mode 100644 app/Interfaces/AffiliateConverterInterface.php create mode 100644 app/Models/ConversionHistory.php create mode 100644 app/Models/Setting.php create mode 100644 app/Models/User.php create mode 100644 app/Models/ZaloChannel.php create mode 100644 app/Models/ZaloDiscoveredGroup.php create mode 100644 app/Providers/AppServiceProvider.php create mode 100644 app/Providers/ConverterServiceProvider.php create mode 100644 app/Services/Converters/ManualAffiliateConverter.php create mode 100644 app/Services/HistoryService.php create mode 100644 app/Services/LinkConverterService.php create mode 100644 app/Services/SessionManagerService.php create mode 100644 app/Services/SettingService.php create mode 100644 app/Services/ZaloBotService.php create mode 100644 artisan create mode 100644 bootstrap/app.php create mode 100644 bootstrap/cache/.gitignore create mode 100644 bootstrap/providers.php create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 config/app.php create mode 100644 config/auth.php create mode 100644 config/cache.php create mode 100644 config/database.php create mode 100644 config/filesystems.php create mode 100644 config/logging.php create mode 100644 config/mail.php create mode 100644 config/queue.php create mode 100644 config/services.php create mode 100644 config/session.php create mode 100644 database/.gitignore create mode 100644 database/factories/UserFactory.php create mode 100644 database/migrations/0001_01_01_000000_create_users_table.php create mode 100644 database/migrations/0001_01_01_000001_create_cache_table.php create mode 100644 database/migrations/0001_01_01_000002_create_jobs_table.php create mode 100644 database/migrations/2026_07_06_164330_create_conversion_histories_table.php create mode 100644 database/migrations/2026_07_06_164330_create_settings_table.php create mode 100644 database/migrations/2026_07_11_000002_create_zalo_channels_table.php create mode 100644 database/migrations/2026_07_11_000004_create_zalo_discovered_groups_table.php create mode 100644 database/seeders/DatabaseSeeder.php create mode 100644 debug_after_click.png create mode 100644 debug_screenshot.png create mode 100644 package.json create mode 100644 phpunit.xml create mode 100644 public/.htaccess create mode 100644 public/favicon.ico create mode 100644 public/index.php create mode 100644 public/robots.txt create mode 100644 public/zalo/qr.png create mode 100644 resources/css/app.css create mode 100644 resources/js/app.js create mode 100644 resources/js/bootstrap.js create mode 100644 resources/views/auth/login.blade.php create mode 100644 resources/views/convert/index.blade.php create mode 100644 resources/views/customer_lookup.blade.php create mode 100644 resources/views/dashboard/index.blade.php create mode 100644 resources/views/history/index.blade.php create mode 100644 resources/views/layouts/app.blade.php create mode 100644 resources/views/public_convert.blade.php create mode 100644 resources/views/settings/index.blade.php create mode 100644 resources/views/short_link_preview.blade.php create mode 100644 resources/views/welcome.blade.php create mode 100644 resources/views/zalo_channels/index.blade.php create mode 100644 routes/api.php create mode 100644 routes/console.php create mode 100644 routes/web.php create mode 100644 storage/app/.gitignore create mode 100644 storage/app/private/.gitignore create mode 100644 storage/app/public/.gitignore create mode 100644 storage/framework/.gitignore create mode 100644 storage/framework/cache/.gitignore create mode 100644 storage/framework/cache/data/.gitignore create mode 100644 storage/framework/sessions/.gitignore create mode 100644 storage/framework/testing/.gitignore create mode 100644 storage/framework/views/.gitignore create mode 100644 storage/logs/.gitignore create mode 100644 tests/Feature/ExampleTest.php create mode 100644 tests/TestCase.php create mode 100644 tests/Unit/ExampleTest.php create mode 100644 vite.config.js create mode 100644 zalo-userbot/bot.log create mode 100644 zalo-userbot/bot.pid create mode 100644 zalo-userbot/bot_err.log create mode 100644 zalo-userbot/package-lock.json create mode 100644 zalo-userbot/package.json create mode 100644 zalo-userbot/qr.png create mode 100644 zalo-userbot/userbot.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a186cd2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 + +[compose.yaml] +indent_size = 4 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c0660ea --- /dev/null +++ b/.env.example @@ -0,0 +1,65 @@ +APP_NAME=Laravel +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_URL=http://localhost + +APP_LOCALE=en +APP_FALLBACK_LOCALE=en +APP_FAKER_LOCALE=en_US + +APP_MAINTENANCE_DRIVER=file +# APP_MAINTENANCE_STORE=database + +# PHP_CLI_SERVER_WORKERS=4 + +BCRYPT_ROUNDS=12 + +LOG_CHANNEL=stack +LOG_STACK=single +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=sqlite +# DB_HOST=127.0.0.1 +# DB_PORT=3306 +# DB_DATABASE=laravel +# DB_USERNAME=root +# DB_PASSWORD= + +SESSION_DRIVER=database +SESSION_LIFETIME=120 +SESSION_ENCRYPT=false +SESSION_PATH=/ +SESSION_DOMAIN=null + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=database + +CACHE_STORE=database +# CACHE_PREFIX= + +MEMCACHED_HOST=127.0.0.1 + +REDIS_CLIENT=phpredis +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=log +MAIL_SCHEME=null +MAIL_HOST=127.0.0.1 +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_FROM_ADDRESS="hello@example.com" +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false + +VITE_APP_NAME="${APP_NAME}" diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..fcb21d3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +* text=auto eol=lf + +*.blade.php diff=html +*.css diff=css +*.html diff=html +*.md diff=markdown +*.php diff=php + +/.github export-ignore +CHANGELOG.md export-ignore +.styleci.yml export-ignore diff --git a/.gitignore b/.gitignore index 9d5dff3..46edd67 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,13 @@ Homestead.json /.vagrant .phpunit.result.cache +# Zalo User-bot temporary files & folders +/zalo-userbot/bot.log +/zalo-userbot/bot_err.log +/zalo-userbot/bot.pid +/zalo-userbot/qr.png +/zalo-userbot/node_modules/ + +# Debug assets +/*.png + diff --git a/app/Console/Commands/CleanupExpiredLinks.php b/app/Console/Commands/CleanupExpiredLinks.php new file mode 100644 index 0000000..2c3a1b5 --- /dev/null +++ b/app/Console/Commands/CleanupExpiredLinks.php @@ -0,0 +1,45 @@ +get('enable_auto_cleanup', '1'); + + if ($enableCleanup !== '1') { + $this->info('Tính năng tự động dọn dẹp link đang bị tắt trong Settings.'); + return; + } + + $this->info('Đang kiểm tra và dọn dẹp các link đã hết hạn...'); + + // Delete records where (created_at + 30 days + clicks * 3 days) < now + $deletedCount = ConversionHistory::whereRaw('DATE_ADD(created_at, INTERVAL (30 + clicks * 3) DAY) < NOW()') + ->delete(); + + $this->info("Đã xóa thành công {$deletedCount} link hết hạn khỏi hệ thống."); + } +} diff --git a/app/DTOs/AffiliateResult.php b/app/DTOs/AffiliateResult.php new file mode 100644 index 0000000..9301e2d --- /dev/null +++ b/app/DTOs/AffiliateResult.php @@ -0,0 +1,16 @@ +linkConverterService = $linkConverterService; + $this->historyService = $historyService; + } + + public function convert(Request $request) + { + $request->validate([ + 'url' => 'required|url', + ]); + + $result = $this->linkConverterService->process($request->input('url')); + + if ($result->isSuccess) { + return response()->json([ + 'success' => true, + 'data' => $result, + ]); + } + + return response()->json([ + 'success' => false, + 'message' => $result->errorMessage, + 'data' => $result, + ], 400); + } + + public function history() + { + return response()->json([ + 'success' => true, + 'data' => $this->historyService->getPaginated(20), + ]); + } +} diff --git a/app/Http/Controllers/Api/ZaloWebhookController.php b/app/Http/Controllers/Api/ZaloWebhookController.php new file mode 100644 index 0000000..ced2762 --- /dev/null +++ b/app/Http/Controllers/Api/ZaloWebhookController.php @@ -0,0 +1,194 @@ +zaloBotService = $zaloBotService; + $this->settingService = $settingService; + } + + /** + * Handle webhook request from Zalo Bot Platform. + */ + public function handle(Request $request): JsonResponse + { + $configuredSecret = $this->settingService->get('zalo_webhook_secret'); + + if (!empty($configuredSecret)) { + $incomingSecret = $request->header('X-Bot-Api-Secret-Token') + ?? $request->header('x-bot-api-secret-token'); + + if ($incomingSecret !== $configuredSecret) { + return response()->json([ + 'ok' => false, + 'error' => 'Unauthorized. Secret token mismatch.' + ], 401); + } + } + + $payload = $request->all(); + + // Pass payload to ZaloBotService + $this->zaloBotService->handleWebhook($payload); + + return response()->json([ + 'ok' => true, + ]); + } + + /** + * Process a Shopee link for the Zalo user-bot (self-bot) and return the formatted reply. + */ + public function processLink(Request $request): JsonResponse + { + $request->validate([ + 'url' => 'required|string', + 'sender_name' => 'nullable|string', + 'thread_id' => 'nullable|string', + 'chat_name' => 'nullable|string' + ]); + + $url = $request->input('url'); + $fromName = $request->input('sender_name') ?? 'Bạn'; + $threadId = $request->input('thread_id'); + $chatName = $request->input('chat_name'); + + // 1. Add/Update this thread into discovered groups pool so Admin can whitelist it + if ($threadId) { + \App\Models\ZaloDiscoveredGroup::updateOrCreate( + ['group_id' => $threadId], + ['name' => $chatName ?: ($fromName ? "Chat với {$fromName}" : "Trò chuyện cá nhân")] + ); + } + + // 2. Whitelist Filtering: Bot is ONLY allowed to respond to whitelisted threads (Default Deny) + $isAllowed = \App\Models\ZaloChannel::where('thread_id', $threadId) + ->where('is_allowed', true) + ->exists(); + + $productTitle = $request->input('product_title'); + $productImage = $request->input('product_image'); + + if (!$isAllowed) { + return response()->json([ + 'success' => false, + 'error' => 'Thread is not whitelisted. Bot response restricted.' + ], 403); + } + + try { + // 1. Resolve redirect if short link + $resolvedUrl = $this->zaloBotService->resolveShortUrl($url); + + // 2. Convert link to short redirect affiliate link and log details + $convertResult = app(\App\Services\LinkConverterService::class)->process( + $resolvedUrl, + $threadId, + $chatName, + 'zalo_bot', + null, + null, + $productTitle, + $productImage + ); + + if ($convertResult && $convertResult->isSuccess) { + $shortLink = $convertResult->affiliateUrl; + + // Fetch the logged history to extract cào details + $history = \App\Models\ConversionHistory::where('original_url', $resolvedUrl) + ->where('zalo_thread_id', $threadId) + ->latest() + ->first(); + + $productName = $history && $history->product_title ? $history->product_title : ($productTitle ?: ($this->zaloBotService->extractProductName($resolvedUrl) ?? 'Sản phẩm Shopee')); + + // 3. Construct the message template + $replyText = "Hi @{$fromName}, Link của bạn đây ạ:\n\n" . + "📦 Tên sản phẩm Shopee:\n{$productName}\n\n" . + "🔗 Link: {$shortLink}\n\n" . + "⚠️ Lưu ý: Để đơn hàng được ghi nhận, KHÔNG mua qua Livestream, KHÔNG xem video/live bất kỳ sau khi click & XÓA sản phẩm ra khỏi giỏ hàng TRƯỚC KHI bấm link!"; + + return response()->json([ + 'success' => true, + 'reply_text' => $replyText, + 'short_link' => $shortLink + ]); + } + + return response()->json([ + 'success' => false, + 'error' => $convertResult->errorMessage ?? 'Conversion failed' + ], 400); + + } catch (\Exception $e) { + return response()->json([ + 'success' => false, + 'error' => $e->getMessage() + ], 500); + } + } + + /** + * Update Zalo user-bot (self-bot) status in settings table. + */ + public function updateStatus(Request $request): JsonResponse + { + $request->validate([ + 'status' => 'required|string', + 'user_name' => 'nullable|string' + ]); + + $this->settingService->set('zalo_bot_status', $request->input('status')); + + if ($request->has('user_name')) { + $this->settingService->set('zalo_bot_user', $request->input('user_name') ?? ''); + } else if ($request->input('status') === 'disconnected') { + $this->settingService->set('zalo_bot_user', ''); + } + + return response()->json(['ok' => true]); + } + + /** + * Sync Zalo groups from userbot into discovered pool. + */ + public function syncGroups(Request $request): JsonResponse + { + $request->validate([ + 'groups' => 'required|array', + 'groups.*.id' => 'required|string', + 'groups.*.name' => 'nullable|string' + ]); + + $groups = $request->input('groups'); + $fetchedIds = array_column($groups, 'id'); + + // Delete groups no longer joined + \App\Models\ZaloDiscoveredGroup::whereNotIn('group_id', $fetchedIds)->delete(); + + // Update or insert current groups + foreach ($groups as $group) { + \App\Models\ZaloDiscoveredGroup::updateOrCreate( + ['group_id' => $group['id']], + ['name' => $group['name'] ?? 'Nhóm Zalo'] + ); + } + + return response()->json(['ok' => true]); + } +} diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php new file mode 100644 index 0000000..8677cd5 --- /dev/null +++ b/app/Http/Controllers/Controller.php @@ -0,0 +1,8 @@ +route('dashboard'); + } + + // If database is empty, allow creating the first admin + $hasUsers = User::exists(); + return view('auth.login', compact('hasUsers')); + } + + /** + * Handle authentication attempt. + */ + public function login(Request $request) + { + $request->validate([ + 'email' => 'required|string', + 'password' => 'required|string', + ]); + + if (Auth::attempt($request->only('email', 'password'), $request->filled('remember'))) { + $request->session()->regenerate(); + return redirect()->intended(route('dashboard')); + } + + return back()->withErrors([ + 'email' => 'Thông tin đăng nhập không chính xác.', + ])->onlyInput('email'); + } + + /** + * Handle first-time registration of the administrator. + */ + public function registerAdmin(Request $request) + { + if (User::exists()) { + return redirect()->route('login')->withErrors(['register' => 'Tài khoản quản trị đã tồn tại.']); + } + + $request->validate([ + 'name' => 'required|string|max:255', + 'email' => 'required|string|max:255|unique:users,email', + 'password' => 'required|string|min:8|confirmed', + ]); + + $user = User::create([ + 'name' => $request->name, + 'email' => $request->email, + 'password' => Hash::make($request->password), + ]); + + Auth::login($user); + + return redirect()->route('dashboard')->with('success', 'Đăng ký tài khoản quản trị thành công!'); + } + + /** + * Log the user out. + */ + public function logout(Request $request) + { + Auth::logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + return redirect()->route('login'); + } +} diff --git a/app/Http/Controllers/Web/ConvertController.php b/app/Http/Controllers/Web/ConvertController.php new file mode 100644 index 0000000..5797bd8 --- /dev/null +++ b/app/Http/Controllers/Web/ConvertController.php @@ -0,0 +1,37 @@ +linkConverterService = $linkConverterService; + } + + public function index() + { + return view('convert.index'); + } + + public function process(Request $request) + { + $request->validate([ + 'url' => 'required|url', + ]); + + $result = $this->linkConverterService->process($request->input('url')); + + if ($result->isSuccess) { + return back()->with('success_result', $result); + } + + return back()->with('error_result', $result); + } +} diff --git a/app/Http/Controllers/Web/CustomerLookupController.php b/app/Http/Controllers/Web/CustomerLookupController.php new file mode 100644 index 0000000..eb34968 --- /dev/null +++ b/app/Http/Controllers/Web/CustomerLookupController.php @@ -0,0 +1,41 @@ +validate([ + 'phone' => 'required|string|max:20', + ]); + + $phone = trim($request->input('phone')); + + $histories = ConversionHistory::where('customer_phone', $phone) + ->where('status', 'success') + ->latest() + ->get(); + + return view('customer_lookup', [ + 'phone' => $phone, + 'histories' => $histories, + 'searched' => true + ]); + } +} diff --git a/app/Http/Controllers/Web/DashboardController.php b/app/Http/Controllers/Web/DashboardController.php new file mode 100644 index 0000000..0d8adc4 --- /dev/null +++ b/app/Http/Controllers/Web/DashboardController.php @@ -0,0 +1,21 @@ +limit(20)->get(); + + return view('dashboard.index', compact( + 'totalConversions', + 'recentConversions' + )); + } +} + diff --git a/app/Http/Controllers/Web/HistoryController.php b/app/Http/Controllers/Web/HistoryController.php new file mode 100644 index 0000000..8112c1d --- /dev/null +++ b/app/Http/Controllers/Web/HistoryController.php @@ -0,0 +1,42 @@ +historyService = $historyService; + } + + public function index() + { + $histories = $this->historyService->getPaginated(20); + $allowedThreadIds = \App\Models\ZaloChannel::pluck('thread_id')->toArray(); + return view('history.index', compact('histories', 'allowedThreadIds')); + } + + public function destroy($id) + { + $history = \App\Models\ConversionHistory::findOrFail($id); + $history->delete(); + + return back()->with('success', 'Đã xoá lịch sử chuyển đổi thành công.'); + } + + public function bulkDestroy(\Illuminate\Http\Request $request) + { + $ids = $request->input('ids', []); + if (!empty($ids)) { + \App\Models\ConversionHistory::whereIn('id', $ids)->delete(); + return back()->with('success', 'Đã xoá thành công ' . count($ids) . ' lịch sử chuyển đổi.'); + } + + return back()->with('error', 'Vui lòng chọn ít nhất một bản ghi để xoá.'); + } +} diff --git a/app/Http/Controllers/Web/PublicConvertController.php b/app/Http/Controllers/Web/PublicConvertController.php new file mode 100644 index 0000000..0c26ab2 --- /dev/null +++ b/app/Http/Controllers/Web/PublicConvertController.php @@ -0,0 +1,69 @@ +linkConverterService = $linkConverterService; + } + + public function index() + { + return view('public_convert'); + } + + public function process(Request $request) + { + $request->validate([ + 'url' => 'required|url', + 'customer_name' => 'nullable|string|max:100', + 'customer_phone' => 'nullable|string|max:20', + ]); + + $url = $request->input('url'); + $customerName = $request->input('customer_name'); + $customerPhone = $request->input('customer_phone'); + + try { + // Process link conversion with source type 'public_web' and customer details + $result = $this->linkConverterService->process( + $url, + null, + null, + 'public_web', + $customerName, + $customerPhone + ); + + if ($result->isSuccess) { + // Find the logged history to get cào details (title, price, estimated_commission) + $history = \App\Models\ConversionHistory::where('original_url', $url) + ->where('converter_type', 'public_web') + ->latest() + ->first(); + + return back()->with([ + 'success' => 'Chuyển đổi link Shopee Affiliate thành công!', + 'original_url' => $url, + 'short_url' => $result->affiliateUrl, + 'product_title' => $history ? $history->product_title : null, + 'product_price' => $history ? $history->product_price : 0.00, + 'estimated_commission' => $history ? $history->estimated_commission : 0.00 + ]); + } + + return back()->withInput()->with('error', $result->errorMessage ?: 'Không thể chuyển đổi link này. Vui lòng kiểm tra lại link Shopee.'); + + } catch (\Exception $e) { + return back()->withInput()->with('error', 'Đã xảy ra lỗi hệ thống: ' . $e->getMessage()); + } + } +} diff --git a/app/Http/Controllers/Web/SettingController.php b/app/Http/Controllers/Web/SettingController.php new file mode 100644 index 0000000..feb42f7 --- /dev/null +++ b/app/Http/Controllers/Web/SettingController.php @@ -0,0 +1,114 @@ +settingService = $settingService; + } + + public function index() + { + $settings = $this->settingService->getAll(); + return view('settings.index', compact('settings')); + } + + public function update(Request $request) + { + $data = $request->except('_token'); + + // Handle auto cleanup checkbox explicitly since unchecked boxes are missing from request payload + $data['enable_auto_cleanup'] = $request->has('enable_auto_cleanup') ? '1' : '0'; + + foreach ($data as $key => $value) { + $type = is_numeric($value) ? 'integer' : 'string'; + $this->settingService->set($key, $value, $type); + } + + return back()->with('success', 'Settings updated successfully.'); + } + + /** + /** + * Start the Zalo user-bot process in the background. + */ + public function startBot() + { + $cwd = base_path('zalo-userbot'); + $pidFile = $cwd . '/bot.pid'; + + // 1. Force kill any existing zombie userbot processes first to prevent session locks + $this->killAllUserbotProcesses(); + + // 2. Clean old files + @unlink($pidFile); + @unlink(public_path('zalo/qr.png')); + + $appUrl = url('/'); + + if (strncasecmp(PHP_OS, 'WIN', 3) === 0) { + $cmd = "set APP_URL=" . escapeshellarg($appUrl) . " && cd /d " . escapeshellarg($cwd) . " && start /B node userbot.js > bot.log 2>&1"; + pclose(popen($cmd, "r")); + } else { + $cmd = "export APP_URL=" . escapeshellarg($appUrl) . " && cd " . escapeshellarg($cwd) . " && node userbot.js > bot.log 2>&1 &"; + exec($cmd); + } + + // Wait a brief moment to let it start and write pid + usleep(500000); + + return back()->with('success', 'Đã gửi lệnh khởi động Bot Zalo. Vui lòng tải lại trang sau vài giây.'); + } + + /** + * Check current Bot status via AJAX polling. + */ + public function checkBotStatus() + { + return response()->json([ + 'status' => $this->settingService->get('zalo_bot_status') ?? 'disconnected', + 'user' => $this->settingService->get('zalo_bot_user') ?? '', + ]); + } + + /** + * Stop the Zalo user-bot process. + */ + public function stopBot() + { + $pidFile = base_path('zalo-userbot/bot.pid'); + + // Force kill all active/zombie userbot processes + $this->killAllUserbotProcesses(); + + @unlink($pidFile); + @unlink(public_path('zalo/qr.png')); + + $this->settingService->set('zalo_bot_status', 'disconnected'); + $this->settingService->set('zalo_bot_user', ''); + + return back()->with('success', 'Đã tắt Bot Zalo thành công.'); + } + + /** + * Kill all running userbot instances globally on the system (Windows/Linux compatible). + */ + private function killAllUserbotProcesses(): void + { + if (strncasecmp(PHP_OS, 'WIN', 3) === 0) { + // Terminate any node.exe process running userbot.js using wmic on Windows + exec('wmic process where "name=\'node.exe\' and CommandLine like \'%userbot.js%\'" call terminate >nul 2>&1'); + } else { + // Terminate on Linux/Unix using pkill -f + exec('pkill -9 -f "node userbot.js" >/dev/null 2>&1'); + } + } +} diff --git a/app/Http/Controllers/Web/ShortLinkController.php b/app/Http/Controllers/Web/ShortLinkController.php new file mode 100644 index 0000000..e9d2005 --- /dev/null +++ b/app/Http/Controllers/Web/ShortLinkController.php @@ -0,0 +1,45 @@ +where('status', 'success') + ->first(); + + if (!$history || !$history->affiliate_url) { + abort(404, 'Short link not found or invalid.'); + } + + // Detect if request is from a crawler bot (Zalo, Facebook, etc.) + $userAgent = strtolower(request()->header('User-Agent', '')); + $bots = ['zalo', 'facebookexternalhit', 'telegrambot', 'twitterbot', 'slackbot', 'googlebot', 'crawler']; + $isBot = false; + + foreach ($bots as $bot) { + if (str_contains($userAgent, $bot)) { + $isBot = true; + break; + } + } + + if ($isBot) { + return view('short_link_preview', compact('history')); + } + + // Increment click count for real users + $history->increment('clicks'); + + return redirect()->away($history->affiliate_url); + } +} diff --git a/app/Http/Controllers/Web/ZaloChannelController.php b/app/Http/Controllers/Web/ZaloChannelController.php new file mode 100644 index 0000000..3efc6f8 --- /dev/null +++ b/app/Http/Controllers/Web/ZaloChannelController.php @@ -0,0 +1,93 @@ +orderBy('name')->paginate(15, ['*'], 'channels_page'); + + $whitelistedIds = ZaloChannel::pluck('thread_id')->toArray(); + $discoveredGroups = \App\Models\ZaloDiscoveredGroup::whereNotIn('group_id', $whitelistedIds) + ->orderBy('name') + ->paginate(15, ['*'], 'groups_page'); + + return view('zalo_channels.index', compact('channels', 'discoveredGroups')); + } + + public function store(Request $request) + { + $request->validate([ + 'thread_id' => 'required|string|unique:zalo_channels,thread_id', + 'name' => 'nullable|string', + ]); + + ZaloChannel::create([ + 'thread_id' => trim($request->input('thread_id')), + 'name' => $request->input('name') ?: 'Kênh chưa đặt tên', + 'is_allowed' => true, + ]); + + return back()->with('success', 'Đã thêm kênh Zalo vào danh sách cho phép.'); + } + + public function toggle($id) + { + $channel = ZaloChannel::findOrFail($id); + $channel->is_allowed = !$channel->is_allowed; + $channel->save(); + + $statusText = $channel->is_allowed ? 'cho phép' : 'chặn'; + return back()->with('success', "Đã thay đổi trạng thái kênh sang {$statusText}."); + } + + public function quickToggle(Request $request) + { + $request->validate([ + 'thread_id' => 'required|string', + 'name' => 'nullable|string', + ]); + + $threadId = $request->input('thread_id'); + $name = $request->input('name'); + + $channel = ZaloChannel::where('thread_id', $threadId)->first(); + + if ($channel) { + $channel->delete(); + return back()->with('success', 'Đã xóa kênh khỏi danh sách cho phép (Bot sẽ KHÔNG phản hồi nhóm này nữa).'); + } else { + ZaloChannel::create([ + 'thread_id' => $threadId, + 'name' => $name ?: 'Kênh Zalo', + 'is_allowed' => true, + ]); + return back()->with('success', 'Đã thêm kênh vào danh sách cho phép (Bot SẼ phản hồi nhóm này).'); + } + } + + public function destroy($id) + { + $channel = ZaloChannel::findOrFail($id); + $channel->delete(); + + return back()->with('success', 'Đã xóa kênh Zalo khỏi danh sách.'); + } + + public function bulkDestroy(Request $request) + { + $request->validate([ + 'ids' => 'required|array', + 'ids.*' => 'exists:zalo_channels,id' + ]); + + ZaloChannel::whereIn('id', $request->input('ids'))->delete(); + + return back()->with('success', 'Đã xóa các kênh Zalo được chọn thành công.'); + } +} diff --git a/app/Interfaces/AffiliateConverterInterface.php b/app/Interfaces/AffiliateConverterInterface.php new file mode 100644 index 0000000..c9e4c37 --- /dev/null +++ b/app/Interfaces/AffiliateConverterInterface.php @@ -0,0 +1,17 @@ +type) { + 'boolean' => filter_var($this->value, FILTER_VALIDATE_BOOLEAN), + 'integer' => (int) $this->value, + 'json' => json_decode($this->value, true), + default => $this->value, + }; + } +} diff --git a/app/Models/User.php b/app/Models/User.php new file mode 100644 index 0000000..68f3a66 --- /dev/null +++ b/app/Models/User.php @@ -0,0 +1,49 @@ + */ + use HasFactory, Notifiable; + + /** + * The attributes that are mass assignable. + * + * @var list + */ + protected $fillable = [ + 'name', + 'email', + 'password', + ]; + + /** + * The attributes that should be hidden for serialization. + * + * @var list + */ + protected $hidden = [ + 'password', + 'remember_token', + ]; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } +} diff --git a/app/Models/ZaloChannel.php b/app/Models/ZaloChannel.php new file mode 100644 index 0000000..9245c6e --- /dev/null +++ b/app/Models/ZaloChannel.php @@ -0,0 +1,21 @@ + 'boolean', + ]; +} diff --git a/app/Models/ZaloDiscoveredGroup.php b/app/Models/ZaloDiscoveredGroup.php new file mode 100644 index 0000000..8d1a7dd --- /dev/null +++ b/app/Models/ZaloDiscoveredGroup.php @@ -0,0 +1,13 @@ +app->bind(AffiliateConverterInterface::class, ManualAffiliateConverter::class); + } + + /** + * Bootstrap services. + */ + public function boot(): void + { + // + } + } diff --git a/app/Services/Converters/ManualAffiliateConverter.php b/app/Services/Converters/ManualAffiliateConverter.php new file mode 100644 index 0000000..0d35c6b --- /dev/null +++ b/app/Services/Converters/ManualAffiliateConverter.php @@ -0,0 +1,51 @@ +settingService = $settingService; + } + + public function convert(string $url, ?string $code = null): AffiliateResult + { + $startTime = microtime(true); + $affiliateId = $this->settingService->get('affiliate_id'); + + if (!$affiliateId) { + return new AffiliateResult( + isSuccess: false, + originalUrl: $url, + errorMessage: 'Vui lòng thiết lập Affiliate ID trong phần Settings để sử dụng chuyển đổi thủ công.', + executionTime: microtime(true) - $startTime, + converterType: 'manual' + ); + } + + // URL encode the original URL + $encodedLink = urlencode($url); + + // Construct the standard manual Shopee redirect URL + $affiliateUrl = "https://s.shopee.vn/an_redir?origin_link={$encodedLink}&affiliate_id={$affiliateId}"; + if ($code) { + $affiliateUrl .= "&sub_id={$code}"; + } + + return new AffiliateResult( + isSuccess: true, + originalUrl: $url, + affiliateUrl: $affiliateUrl, + executionTime: microtime(true) - $startTime, + sessionUsed: 'manual_id_' . $affiliateId, + converterType: 'manual' + ); + } +} diff --git a/app/Services/HistoryService.php b/app/Services/HistoryService.php new file mode 100644 index 0000000..1f2d2d6 --- /dev/null +++ b/app/Services/HistoryService.php @@ -0,0 +1,67 @@ +isSuccess && !$code) { + do { + $code = \Illuminate\Support\Str::random(10); + } while (ConversionHistory::whereRaw('BINARY code = ?', [$code])->exists()); + } + + return ConversionHistory::create([ + 'code' => $code, + 'original_url' => $result->originalUrl, + 'affiliate_url' => $result->affiliateUrl, + 'converter_type' => $result->converterType, + 'session_name' => $result->sessionUsed, + 'status' => $result->isSuccess ? 'success' : 'failed', + 'error_message' => $result->errorMessage, + 'execution_time' => $result->executionTime, + 'zalo_thread_id' => $zaloThreadId, + 'zalo_chat_name' => $zaloChatName, + 'customer_name' => $customerName, + 'customer_phone' => $customerPhone, + 'product_title' => $productTitle, + 'product_image' => $productImage, + 'product_price' => $productPrice, + 'estimated_commission' => $estimatedCommission, + ]); + } + + /** + * Get recent conversion history. + */ + public function getRecent(int $limit = 20) + { + return ConversionHistory::orderByDesc('created_at')->limit($limit)->get(); + } + + /** + * Get paginated history for the UI. + */ + public function getPaginated(int $perPage = 20): LengthAwarePaginator + { + return ConversionHistory::orderByDesc('created_at')->paginate($perPage); + } +} diff --git a/app/Services/LinkConverterService.php b/app/Services/LinkConverterService.php new file mode 100644 index 0000000..9eab09d --- /dev/null +++ b/app/Services/LinkConverterService.php @@ -0,0 +1,197 @@ +converter = $converter; + $this->historyService = $historyService; + $this->settingService = $settingService; + } + + public function process( + string $url, + ?string $zaloThreadId = null, + ?string $zaloChatName = null, + string $sourceType = 'web', + ?string $customerName = null, + ?string $customerPhone = null + ): AffiliateResult + { + // 1. Generate unique code beforehand for tracking + $code = null; + do { + $code = \Illuminate\Support\Str::random(10); + } while (\App\Models\ConversionHistory::whereRaw('BINARY code = ?', [$code])->exists()); + + // 2. Fetch real Shopee product information + $productInfo = $this->fetchShopeeProductInfo($url); + $productTitle = $productInfo['name'] ?? null; + $productImage = $productInfo['image'] ?? null; + $productPrice = $productInfo['price'] ?? 0.00; + + // Determine estimated commission rate and amount + $commissionData = $this->calculateEstimatedCommission($productTitle, $productPrice, $productInfo['is_mall'] ?? false); + $estimatedCommission = $commissionData['amount']; + + $maxRetries = $this->settingService->get('retry_count', 3); + $attempts = 0; + $result = null; + + while ($attempts < $maxRetries) { + $attempts++; + // 3. Convert with the pre-generated code for sub_id mapping + $result = $this->converter->convert($url, $code); + + if ($result->isSuccess) { + break; + } + } + + // Save history regardless of success or failure + if ($result) { + $history = $this->historyService->logConversion( + $result, + $code, + $zaloThreadId, + $zaloChatName, + $customerName, + $customerPhone, + $productTitle, + $productImage, + $productPrice, + $estimatedCommission + ); + + // Override converter type if triggered from external source (like Zalo) + if ($history && $sourceType !== 'web') { + $history->update([ + 'converter_type' => $sourceType + ]); + } + + if ($result->isSuccess && $history->code) { + $domain = $this->settingService->get('short_link_domain'); + if ($domain) { + $domain = rtrim($domain, '/'); + $result->affiliateUrl = $domain . '/aff/s/' . $history->code; + } else { + $result->affiliateUrl = route('short_link.redirect', ['code' => $history->code]); + } + } + } + + return $result; + } + + /** + * Fetch product details (title, image, price) from Shopee internal API. + */ + public function fetchShopeeProductInfo(string $url): ?array + { + if (!preg_match('/i\.(\d+)\.(\d+)/', $url, $matches)) { + return null; + } + + $shopId = $matches[1]; + $itemId = $matches[2]; + $apiUrl = "https://shopee.vn/api/v4/item/get?itemid={$itemId}&shopid={$shopId}"; + + try { + $response = \Illuminate\Support\Facades\Http::timeout(5) + ->withHeaders([ + 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Accept' => 'application/json', + 'Referer' => 'https://shopee.vn/', + ]) + ->get($apiUrl); + + if ($response->successful()) { + $data = $response->json(); + $item = $data['data'] ?? null; + if ($item) { + $price = isset($item['price']) ? $item['price'] / 100000 : 0; + $image = isset($item['image']) ? "https://down-vn.img.susercontent.com/file/" . $item['image'] : null; + return [ + 'name' => $item['name'] ?? null, + 'price' => $price, + 'image' => $image, + 'is_mall' => !empty($item['is_official_shop']), + 'description' => $item['description'] ?? null + ]; + } + } + } catch (\Exception $e) { + \Illuminate\Support\Facades\Log::warning("Shopee internal API lookup failed: " . $e->getMessage()); + } + + return null; + } + + /** + * Calculate estimated commission based on category keywords and Mall status. + */ + protected function calculateEstimatedCommission(?string $title, float $price, bool $isMall): array + { + if (!$title || $price <= 0) { + return ['rate' => 0, 'amount' => 0.00]; + } + + $titleLower = mb_strtolower($title); + + // Define category keywords + $fashionKeywords = ['áo', 'quần', 'váy', 'đầm', 'giày', 'túi', 'kính', 'son', 'kem', 'phấn', 'nước hoa', 'tắm', 'gội', 'phụ kiện', 'trang sức', 'skincare', 'scrub']; + $electronicsKeywords = ['điện thoại', 'laptop', 'tivi', 'loa', 'tai nghe', 'máy ảnh', 'sạc', 'cáp', 'chuột', 'bàn phím', 'camera', 'micro', 'usb', 'thẻ nhớ', 'router', 'wifi', 'pin']; + + $isFashion = false; + foreach ($fashionKeywords as $keyword) { + if (str_contains($titleLower, $keyword)) { + $isFashion = true; + break; + } + } + + $isElectronics = false; + if (!$isFashion) { + foreach ($electronicsKeywords as $keyword) { + if (str_contains($titleLower, $keyword)) { + $isElectronics = true; + break; + } + } + } + + // Apply rates + if ($isFashion) { + $rate = $isMall ? 7.4 : 3.5; + } elseif ($isElectronics) { + $rate = $isMall ? 1.5 : 0.8; + } else { + // General categories + $rate = $isMall ? 5.0 : 2.5; + } + + // Allow admin settings override if configured + $adminOverrideRate = $this->settingService->get('commission_rate_override'); + if ($adminOverrideRate !== null && $adminOverrideRate !== '') { + $rate = (float)$adminOverrideRate; + } + + return [ + 'rate' => $rate, + 'amount' => round($price * ($rate / 100), 2) + ]; + } +} diff --git a/app/Services/SessionManagerService.php b/app/Services/SessionManagerService.php new file mode 100644 index 0000000..9babb63 --- /dev/null +++ b/app/Services/SessionManagerService.php @@ -0,0 +1,49 @@ +orderByDesc('priority') + ->orderBy('last_used_at', 'asc') + ->first(); + } + + /** + * Mark a session as used. + */ + public function markAsUsed(CookieSession $session): void + { + $session->update([ + 'last_used_at' => now(), + ]); + } + + /** + * Mark a session as error. + */ + public function markAsError(CookieSession $session): void + { + $session->update([ + 'status' => 'error', + ]); + } + + /** + * Disable a session. + */ + public function disableSession(CookieSession $session): void + { + $session->update([ + 'status' => 'disabled', + ]); + } +} diff --git a/app/Services/SettingService.php b/app/Services/SettingService.php new file mode 100644 index 0000000..138e9ab --- /dev/null +++ b/app/Services/SettingService.php @@ -0,0 +1,65 @@ +first(); + }); + + if (!$setting) { + return $default; + } + + return $setting->getTypedValue(); + } + + /** + * Set or update a setting. + */ + public function set(string $key, mixed $value, string $type = 'string'): void + { + // Convert array/object to json if necessary + if (is_array($value) || is_object($value)) { + $value = json_encode($value); + $type = 'json'; + } elseif (is_bool($value)) { + $value = $value ? 'true' : 'false'; + $type = 'boolean'; + } + + Setting::updateOrCreate( + ['key' => $key], + [ + 'value' => (string) $value, + 'type' => $type, + ] + ); + + // Invalidate cache + Cache::forget("setting.{$key}"); + } + + /** + * Get all settings as an associative array. + */ + public function getAll(): array + { + $settings = Setting::all(); + $result = []; + foreach ($settings as $setting) { + $result[$setting->key] = $setting->getTypedValue(); + } + return $result; + } +} diff --git a/app/Services/ZaloBotService.php b/app/Services/ZaloBotService.php new file mode 100644 index 0000000..d460c95 --- /dev/null +++ b/app/Services/ZaloBotService.php @@ -0,0 +1,237 @@ +linkConverterService = $linkConverterService; + $this->settingService = $settingService; + } + + /** + * Handle incoming Zalo Bot webhook request. + */ + public function handleWebhook(array $payload): void + { + Log::info('Zalo Webhook payload received', $payload); + + // Check if message structure exists (mimics Telegram format) + $message = $payload['message'] ?? null; + if (!$message) { + return; + } + + $chatId = $message['chat']['id'] ?? null; + $text = $message['text'] ?? ''; + + if (!$chatId || empty($text)) { + return; + } + + // Get sender name (fallback to "Bạn") + $fromName = trim( + ($message['from']['first_name'] ?? '') . ' ' . ($message['from']['last_name'] ?? '') + ); + if (empty($fromName)) { + $fromName = $message['from']['username'] ?? 'Bạn'; + } + + // Find Shopee links + $urls = $this->extractShopeeUrls($text); + if (empty($urls)) { + return; + } + + foreach ($urls as $url) { + $this->processAndReplyLink($chatId, $fromName, $url); + } + } + + /** + * Process a single Shopee link and reply to the chat. + */ + protected function processAndReplyLink(string $chatId, string $fromName, string $url): void + { + try { + // 1. Resolve redirects if it's a short URL (e.g. s.shopee.vn or shp.ee) + $resolvedUrl = $this->resolveShortUrl($url); + + // 2. Extract product name from resolved URL + $productName = $this->extractProductName($resolvedUrl) ?? 'Sản phẩm Shopee'; + + // 3. Estimate commission + $commission = $this->estimateCommission($resolvedUrl); + + // 4. Convert link to our local affiliate short link + $convertResult = $this->linkConverterService->process($resolvedUrl); + + if ($convertResult && $convertResult->isSuccess) { + $shortLink = $convertResult->affiliateUrl; + + // 5. Construct the message template matching competitor's chatbot + $replyText = "Hi @{$fromName}, Link của bạn đây ạ:\n\n" . + "📦 {$productName}\n" . + "🔗 Link: {$shortLink}\n" . + "💵 Hoa hồng ước tính: {$commission}\n\n" . + "⚠️ Lưu ý: Để hoa hồng hợp lệ, KHÔNG mua qua Livestream, KHÔNG xem video/live bất kỳ sau khi click & XÓA sản phẩm ra khỏi giỏ hàng TRƯỚC KHI bấm link!"; + + // 6. Send reply message + $this->sendMessage($chatId, $replyText); + } else { + Log::error("Failed to convert Shopee URL via Zalo: " . ($convertResult->errorMessage ?? 'Unknown error')); + } + } catch (\Exception $e) { + Log::error("Error processing link in ZaloBotService: " . $e->getMessage()); + } + } + + /** + * Extract all Shopee URLs from text. + */ + public function extractShopeeUrls(string $text): array + { + $pattern = '/(?:https?:\/\/)?(?:[a-zA-Z0-9-]+\.)?shopee\.vn\/[^\s]+|(?:https?:\/\/)?shp\.ee\/[^\s]+/i'; + if (preg_match_all($pattern, $text, $matches)) { + $urls = []; + foreach ($matches[0] as $url) { + if (!str_starts_with(strtolower($url), 'http://') && !str_starts_with(strtolower($url), 'https://')) { + $url = 'https://' . $url; + } + $urls[] = $url; + } + return $urls; + } + return []; + } + + /** + * Resolve short URLs (s.shopee.vn or shp.ee) to get the final redirected URL. + */ + public function resolveShortUrl(string $url): string + { + if (str_contains($url, '/an_redir') || (!str_contains($url, 's.shopee.vn') && !str_contains($url, 'shp.ee'))) { + return $url; + } + + try { + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HEADER, true); + curl_setopt($ch, CURLOPT_NOBODY, true); // Get headers only + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); // Check redirect location manually + curl_setopt($ch, CURLOPT_TIMEOUT, 5); + curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); + + $response = curl_exec($ch); + $info = curl_getinfo($ch); + curl_close($ch); + + if ($info['http_code'] >= 300 && $info['http_code'] < 400) { + if (preg_match('/[Ll]ocation:\s*(.+)/', $response, $matches)) { + $resolvedUrl = trim($matches[1]); + // Recursively resolve redirect if it's still a redirect link + return $this->resolveShortUrl($resolvedUrl); + } + } + } catch (\Exception $e) { + Log::warning("Could not resolve short URL redirect: " . $e->getMessage()); + } + + return $url; + } + + /** + * Extract product/shop name from Shopee URL. + */ + public function extractProductName(string $url): ?string + { + $parsedUrl = parse_url($url); + if (!isset($parsedUrl['path'])) { + return null; + } + + $path = urldecode($parsedUrl['path']); + $path = trim($path, '/'); + + // Match typical Shopee product paths ending with -i.SHOP_ID.ITEM_ID + if (preg_match('/^(.*?)-i\.\d+\.\d+$/', $path, $matches)) { + $slug = $matches[1]; + $name = str_replace(['-', '_'], ' ', $slug); + return trim($name); + } + + // Shop pages / Usernames + if (!str_contains($path, '/')) { + $name = str_replace(['-', '_'], ' ', $path); + return trim($name); + } + + return null; + } + + /** + * Predictable estimate of product commission based on the item ID. + */ + public function estimateCommission(string $url): string + { + $itemId = 0; + if (preg_match('/-i\.\d+\.(\d+)$/', $url, $matches)) { + $itemId = (int)$matches[1]; + } + + if ($itemId === 0) { + $itemId = crc32($url); + } + + // Predictable single estimate between 4.0% and 7.5% based on itemId or crc32 + $rate = 4.0 + (abs($itemId) % 36) / 10.0; + return number_format($rate, 1) . '%'; + } + + /** + * Send message using Zalo Bot Creator HTTP API. + */ + public function sendMessage(string $chatId, string $text): bool + { + $token = $this->settingService->get('zalo_bot_token') ?? env('ZALO_BOT_TOKEN'); + + if (!$token) { + Log::error('Zalo Bot Token is not configured. Cannot send message.'); + return false; + } + + $apiUrl = "https://bot-api.zaloplatforms.com/bot{$token}/sendMessage"; + + Log::info('Sending message to Zalo Bot', [ + 'chat_id' => $chatId, + 'url' => "https://bot-api.zaloplatforms.com/bot[HIDDEN]/sendMessage" + ]); + + $response = Http::timeout(10)->post($apiUrl, [ + 'chat_id' => $chatId, + 'text' => $text, + ]); + + if ($response->successful()) { + Log::info('Message sent successfully to Zalo Bot'); + return true; + } + + Log::error('Failed to send message to Zalo Bot', [ + 'status' => $response->status(), + 'body' => $response->body() + ]); + + return false; + } +} diff --git a/artisan b/artisan new file mode 100644 index 0000000..c35e31d --- /dev/null +++ b/artisan @@ -0,0 +1,18 @@ +#!/usr/bin/env php +handleCommand(new ArgvInput); + +exit($status); diff --git a/bootstrap/app.php b/bootstrap/app.php new file mode 100644 index 0000000..c3928c5 --- /dev/null +++ b/bootstrap/app.php @@ -0,0 +1,19 @@ +withRouting( + web: __DIR__.'/../routes/web.php', + api: __DIR__.'/../routes/api.php', + commands: __DIR__.'/../routes/console.php', + health: '/up', + ) + ->withMiddleware(function (Middleware $middleware): void { + // + }) + ->withExceptions(function (Exceptions $exceptions): void { + // + })->create(); diff --git a/bootstrap/cache/.gitignore b/bootstrap/cache/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/bootstrap/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/bootstrap/providers.php b/bootstrap/providers.php new file mode 100644 index 0000000..7cc2a8a --- /dev/null +++ b/bootstrap/providers.php @@ -0,0 +1,6 @@ +=5.0.0" + }, + "require-dev": { + "doctrine/dbal": "^4.0.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Types to use Carbon in Doctrine", + "keywords": [ + "carbon", + "date", + "datetime", + "doctrine", + "time" + ], + "support": { + "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2024-02-09T16:56:22+00:00" + }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3" + }, + "time": "2024-07-08T12:26:09+00:00" + }, + { + "name": "doctrine/inflector", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^12.0 || ^13.0", + "phpstan/phpstan": "^1.12 || ^2.0", + "phpstan/phpstan-phpunit": "^1.4 || ^2.0", + "phpstan/phpstan-strict-rules": "^1.6 || ^2.0", + "phpunit/phpunit": "^8.5 || ^12.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.1.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2025-08-10T19:31:58+00:00" + }, + { + "name": "doctrine/lexer", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2024-02-05T11:56:58+00:00" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/d61a8a9604ec1f8c3d150d09db6ce98b32675013", + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013", + "shasum": "" + }, + "require": { + "php": "^8.2|^8.3|^8.4|^8.5" + }, + "replace": { + "mtdowling/cron-expression": "^1.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.32|^2.1.31", + "phpunit/phpunit": "^8.5.48|^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "time": "2025-10-31T18:51:33+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2025-03-06T22:45:56+00:00" + }, + { + "name": "fruitcake/php-cors", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/fruitcake/php-cors.git", + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", + "shasum": "" + }, + "require": { + "php": "^8.1", + "symfony/http-foundation": "^5.4|^6.4|^7.3|^8" + }, + "require-dev": { + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^9", + "squizlabs/php_codesniffer": "^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Fruitcake\\Cors\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fruitcake", + "homepage": "https://fruitcake.nl" + }, + { + "name": "Barryvdh", + "email": "barryvdh@gmail.com" + } + ], + "description": "Cross-origin resource sharing library for the Symfony HttpFoundation", + "homepage": "https://github.com/fruitcake/php-cors", + "keywords": [ + "cors", + "laravel", + "symfony" + ], + "support": { + "issues": "https://github.com/fruitcake/php-cors/issues", + "source": "https://github.com/fruitcake/php-cors/tree/v1.4.0" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2025-12-03T09:33:47+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.4", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:43:20+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.13.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "bcd989ad36c92d42a3715379af91f2defee5b8dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/bcd989ad36c92d42a3715379af91f2defee5b8dd", + "reference": "bcd989ad36c92d42a3715379af91f2defee5b8dd", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^2.5", + "guzzlehttp/psr7": "^2.12.3", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.5 || ^3.0", + "symfony/polyfill-php80": "^1.25" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.3", + "guzzlehttp/test-server": "^0.6", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.52 || ^9.6.34", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.13.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2026-07-05T19:00:11+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "4360e982f87f5f258bf872d094647791db2f4c8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/4360e982f87f5f258bf872d094647791db2f4c8e", + "reference": "4360e982f87f5f258bf872d094647791db2f4c8e", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/deprecation-contracts": "^2.5 || ^3.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.52 || ^9.6.34" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.5.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2026-06-02T12:23:43+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.12.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "7ec62dc3f44aa218487dbed81a9bf9bc647be55d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/7ec62dc3f44aa218487dbed81a9bf9bc647be55d", + "reference": "7ec62dc3f44aa218487dbed81a9bf9bc647be55d", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0", + "symfony/deprecation-contracts": "^2.5 || ^3.0", + "symfony/polyfill-php80": "^1.25" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "1.1.0", + "jshttp/mime-db": "1.54.0.1", + "phpunit/phpunit": "^8.5.52 || ^9.6.34" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.12.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2026-06-23T15:21:08+00:00" + }, + { + "name": "guzzlehttp/uri-template", + "version": "v1.0.8", + "source": { + "type": "git", + "url": "https://github.com/guzzle/uri-template.git", + "reference": "9c19128923b05a5d7355e5d2318d7808b7e33bbd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/9c19128923b05a5d7355e5d2318d7808b7e33bbd", + "reference": "9c19128923b05a5d7355e5d2318d7808b7e33bbd", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-php80": "^1.25" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.52 || ^9.6.34", + "uri-template/tests": "1.0.0" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\UriTemplate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + } + ], + "description": "A polyfill class for uri_template of PHP", + "keywords": [ + "guzzlehttp", + "uri-template" + ], + "support": { + "issues": "https://github.com/guzzle/uri-template/issues", + "source": "https://github.com/guzzle/uri-template/tree/v1.0.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/uri-template", + "type": "tidelift" + } + ], + "time": "2026-06-23T13:02:23+00:00" + }, + { + "name": "laravel/framework", + "version": "v12.62.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "f7e61eb1e0e06a38996802b769bce9127aec227c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/f7e61eb1e0e06a38996802b769bce9127aec227c", + "reference": "f7e61eb1e0e06a38996802b769bce9127aec227c", + "shasum": "" + }, + "require": { + "brick/math": "^0.11|^0.12|^0.13|^0.14", + "composer-runtime-api": "^2.2", + "doctrine/inflector": "^2.0.5", + "dragonmantank/cron-expression": "^3.4", + "egulias/email-validator": "^3.2.1|^4.0", + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-session": "*", + "ext-tokenizer": "*", + "fruitcake/php-cors": "^1.3", + "guzzlehttp/guzzle": "^7.8.2", + "guzzlehttp/uri-template": "^1.0", + "laravel/prompts": "^0.3.0", + "laravel/serializable-closure": "^1.3|^2.0", + "league/commonmark": "^2.8.1", + "league/flysystem": "^3.25.1", + "league/flysystem-local": "^3.25.1", + "league/uri": "^7.5.1", + "monolog/monolog": "^3.0", + "nesbot/carbon": "^3.8.4", + "nunomaduro/termwind": "^2.0", + "php": "^8.2", + "psr/container": "^1.1.1|^2.0.1", + "psr/log": "^1.0|^2.0|^3.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "ramsey/uuid": "^4.7", + "symfony/console": "^7.2.0", + "symfony/error-handler": "^7.2.0", + "symfony/finder": "^7.2.0", + "symfony/http-foundation": "^7.2.0", + "symfony/http-kernel": "^7.2.0", + "symfony/mailer": "^7.2.0", + "symfony/mime": "^7.2.0", + "symfony/polyfill-php83": "^1.33", + "symfony/polyfill-php84": "^1.34", + "symfony/polyfill-php85": "^1.34", + "symfony/process": "^7.2.0", + "symfony/routing": "^7.2.0", + "symfony/uid": "^7.2.0", + "symfony/var-dumper": "^7.2.0", + "tijsverkoyen/css-to-inline-styles": "^2.2.5", + "vlucas/phpdotenv": "^5.6.1", + "voku/portable-ascii": "^2.0.2" + }, + "conflict": { + "tightenco/collect": "<5.5.33" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "psr/log-implementation": "1.0|2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0" + }, + "replace": { + "illuminate/auth": "self.version", + "illuminate/broadcasting": "self.version", + "illuminate/bus": "self.version", + "illuminate/cache": "self.version", + "illuminate/collections": "self.version", + "illuminate/concurrency": "self.version", + "illuminate/conditionable": "self.version", + "illuminate/config": "self.version", + "illuminate/console": "self.version", + "illuminate/container": "self.version", + "illuminate/contracts": "self.version", + "illuminate/cookie": "self.version", + "illuminate/database": "self.version", + "illuminate/encryption": "self.version", + "illuminate/events": "self.version", + "illuminate/filesystem": "self.version", + "illuminate/hashing": "self.version", + "illuminate/http": "self.version", + "illuminate/json-schema": "self.version", + "illuminate/log": "self.version", + "illuminate/macroable": "self.version", + "illuminate/mail": "self.version", + "illuminate/notifications": "self.version", + "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", + "illuminate/process": "self.version", + "illuminate/queue": "self.version", + "illuminate/redis": "self.version", + "illuminate/reflection": "self.version", + "illuminate/routing": "self.version", + "illuminate/session": "self.version", + "illuminate/support": "self.version", + "illuminate/testing": "self.version", + "illuminate/translation": "self.version", + "illuminate/validation": "self.version", + "illuminate/view": "self.version", + "spatie/once": "*" + }, + "require-dev": { + "ably/ably-php": "^1.0", + "aws/aws-sdk-php": "^3.322.9", + "ext-gmp": "*", + "fakerphp/faker": "^1.24", + "guzzlehttp/promises": "^2.0.3", + "guzzlehttp/psr7": "^2.4", + "laravel/pint": "^1.18", + "league/flysystem-aws-s3-v3": "^3.25.1", + "league/flysystem-ftp": "^3.25.1", + "league/flysystem-path-prefixing": "^3.25.1", + "league/flysystem-read-only": "^3.25.1", + "league/flysystem-sftp-v3": "^3.25.1", + "mockery/mockery": "^1.6.10", + "opis/json-schema": "^2.4.1", + "orchestra/testbench-core": "^10.9.0", + "pda/pheanstalk": "^5.0.6|^7.0.0", + "php-http/discovery": "^1.15", + "phpstan/phpstan": "^2.1.41", + "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", + "predis/predis": "^2.3|^3.0", + "resend/resend-php": "^0.10.0|^1.0", + "symfony/cache": "^7.2.0", + "symfony/http-client": "^7.2.0", + "symfony/psr-http-message-bridge": "^7.2.0", + "symfony/translation": "^7.2.0" + }, + "suggest": { + "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.322.9).", + "brianium/paratest": "Required to run tests in parallel (^7.0|^8.0).", + "ext-apcu": "Required to use the APC cache driver.", + "ext-fileinfo": "Required to use the Filesystem class.", + "ext-ftp": "Required to use the Flysystem FTP driver.", + "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", + "ext-memcached": "Required to use the memcache cache driver.", + "ext-pcntl": "Required to use all features of the queue worker and console signal trapping.", + "ext-pdo": "Required to use all database features.", + "ext-posix": "Required to use all features of the queue worker.", + "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0|^6.0).", + "fakerphp/faker": "Required to generate fake data using the fake() helper (^1.23).", + "filp/whoops": "Required for friendly error pages in development (^2.14.3).", + "laravel/tinker": "Required to use the tinker console command (^2.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).", + "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.25.1).", + "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.25.1).", + "league/flysystem-read-only": "Required to use read-only disks (^3.25.1)", + "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.25.1).", + "mockery/mockery": "Required to use mocking (^1.6).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", + "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", + "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.5.3|^12.0.1).", + "predis/predis": "Required to use the predis connector (^2.3|^3.0).", + "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", + "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0|^1.0).", + "symfony/cache": "Required to PSR-6 cache bridge (^7.2).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).", + "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.2).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.2).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.2).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.2)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "12.x-dev" + } + }, + "autoload": { + "files": [ + "src/Illuminate/Collections/functions.php", + "src/Illuminate/Collections/helpers.php", + "src/Illuminate/Events/functions.php", + "src/Illuminate/Filesystem/functions.php", + "src/Illuminate/Foundation/helpers.php", + "src/Illuminate/Log/functions.php", + "src/Illuminate/Reflection/helpers.php", + "src/Illuminate/Support/functions.php", + "src/Illuminate/Support/helpers.php" + ], + "psr-4": { + "Illuminate\\": "src/Illuminate/", + "Illuminate\\Support\\": [ + "src/Illuminate/Macroable/", + "src/Illuminate/Collections/", + "src/Illuminate/Conditionable/", + "src/Illuminate/Reflection/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Laravel Framework.", + "homepage": "https://laravel.com", + "keywords": [ + "framework", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2026-06-09T13:50:13+00:00" + }, + { + "name": "laravel/prompts", + "version": "v0.3.21", + "source": { + "type": "git", + "url": "https://github.com/laravel/prompts.git", + "reference": "7753c65c281c2550c7c183f14e18062073b7d821" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/prompts/zipball/7753c65c281c2550c7c183f14e18062073b7d821", + "reference": "7753c65c281c2550c7c183f14e18062073b7d821", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.2", + "ext-mbstring": "*", + "php": "^8.1", + "symfony/console": "^6.2|^7.0|^8.0" + }, + "conflict": { + "illuminate/console": ">=10.17.0 <10.25.0", + "laravel/framework": ">=10.17.0 <10.25.0" + }, + "require-dev": { + "illuminate/collections": "^10.0|^11.0|^12.0|^13.0", + "mockery/mockery": "^1.5", + "pestphp/pest": "^2.3|^3.4|^4.0", + "phpstan/phpstan": "^1.12.28", + "phpstan/phpstan-mockery": "^1.1.3" + }, + "suggest": { + "ext-pcntl": "Required for the spinner to be animated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.3.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Laravel\\Prompts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Add beautiful and user-friendly forms to your command-line applications.", + "support": { + "issues": "https://github.com/laravel/prompts/issues", + "source": "https://github.com/laravel/prompts/tree/v0.3.21" + }, + "time": "2026-06-26T00:11:25+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v2.0.13", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "b566ee0dd251f3c4078bed003a7ce015f5ea6dce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b566ee0dd251f3c4078bed003a7ce015f5ea6dce", + "reference": "b566ee0dd251f3c4078bed003a7ce015f5ea6dce", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0|^11.0|^12.0|^13.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0|^4.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0|^8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2026-04-16T14:03:50+00:00" + }, + { + "name": "laravel/tinker", + "version": "v2.11.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/c9f80cc835649b5c1842898fb043f8cc098dd741", + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741", + "shasum": "" + }, + "require": { + "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "php": "^7.2.5|^8.0", + "psy/psysh": "^0.11.1|^0.12.0", + "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0|^8.0" + }, + "require-dev": { + "mockery/mockery": "~1.3.3|^1.4.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.5.8|^9.3.3|^10.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0)." + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Tinker\\TinkerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Tinker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Powerful REPL for the Laravel framework.", + "keywords": [ + "REPL", + "Tinker", + "laravel", + "psysh" + ], + "support": { + "issues": "https://github.com/laravel/tinker/issues", + "source": "https://github.com/laravel/tinker/tree/v2.11.1" + }, + "time": "2026-02-06T14:12:35+00:00" + }, + { + "name": "league/commonmark", + "version": "2.8.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "59fb075d2101740c337c7216e3f32b36c204218b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/59fb075d2101740c337c7216e3f32b36c204218b", + "reference": "59fb075d2101740c337c7216e3f32b36c204218b", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.31.1", + "commonmark/commonmark.js": "0.31.1", + "composer/package-versions-deprecated": "^1.8", + "embed/embed": "^4.4", + "erusev/parsedown": "^1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "^1.4 || ^2.0", + "nyholm/psr7": "^1.5", + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", + "scrutinizer/ocular": "^1.8.1", + "symfony/finder": "^5.3 | ^6.0 | ^7.0 || ^8.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0 || ^8.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0 || ^8.0", + "unleashedtech/php-coding-standard": "^3.1.1", + "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.9-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "support": { + "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", + "issues": "https://github.com/thephpleague/commonmark/issues", + "rss": "https://github.com/thephpleague/commonmark/releases.atom", + "source": "https://github.com/thephpleague/commonmark" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/commonmark", + "type": "tidelift" + } + ], + "time": "2026-03-19T13:16:38+00:00" + }, + { + "name": "league/config", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/config.git", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/config/zipball/754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "time": "2022-12-11T20:36:23+00:00" + }, + { + "name": "league/flysystem", + "version": "3.35.2", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "b277b5dc3d56650b68904117124e79c851e12376" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/b277b5dc3d56650b68904117124e79c851e12376", + "reference": "b277b5dc3d56650b68904117124e79c851e12376", + "shasum": "" + }, + "require": { + "league/flysystem-local": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "async-aws/core": "<1.19.0", + "async-aws/s3": "<1.14.0", + "aws/aws-sdk-php": "3.209.31 || 3.210.0", + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1", + "phpseclib/phpseclib": "3.0.15", + "symfony/http-client": "<5.2" + }, + "require-dev": { + "async-aws/s3": "^1.5 || ^2.0", + "async-aws/simple-s3": "^1.1 || ^2.0", + "aws/aws-sdk-php": "^3.295.10", + "composer/semver": "^3.0", + "ext-fileinfo": "*", + "ext-ftp": "*", + "ext-mongodb": "^1.3|^2", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.5", + "google/cloud-storage": "^1.23", + "guzzlehttp/psr7": "^2.6", + "microsoft/azure-storage-blob": "^1.1", + "mongodb/mongodb": "^1.2|^2", + "phpseclib/phpseclib": "^3.0.36", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.11|^10.0", + "sabre/dav": "^4.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "File storage abstraction for PHP", + "keywords": [ + "WebDAV", + "aws", + "cloud", + "file", + "files", + "filesystem", + "filesystems", + "ftp", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/3.35.2" + }, + "time": "2026-07-06T14:42:07+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.31.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/2f669db18a4c20c755c2bb7d3a7b0b2340488079", + "reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "source": "https://github.com/thephpleague/flysystem-local/tree/3.31.0" + }, + "time": "2026-01-23T15:30:45+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.16.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2024-09-21T08:32:55+00:00" + }, + { + "name": "league/uri", + "version": "7.8.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "08cf38e3924d4f56238125547b5720496fac8fd4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/08cf38e3924d4f56238125547b5720496fac8fd4", + "reference": "08cf38e3924d4f56238125547b5720496fac8fd4", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.8.1", + "php": "^8.1", + "psr/http-factory": "^1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-dom": "to convert the URI into an HTML anchor tag", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "ext-uri": "to use the PHP native URI class", + "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain", + "league/uri-components": "to provide additional tools to manipulate URI objects components", + "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP", + "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "URN", + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc2141", + "rfc3986", + "rfc3987", + "rfc6570", + "rfc8141", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri/tree/7.8.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2026-03-15T20:22:25+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "7.8.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/85d5c77c5d6d3af6c54db4a78246364908f3c928", + "reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.1", + "psr/http-message": "^1.1 || ^2.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common tools for parsing and resolving RFC3987/RFC3986 URI", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2026-03-08T20:05:35+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.10.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8 || ^2.0", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", + "predis/predis": "^1.1 || ^2", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/3.10.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2026-01-02T08:56:05+00:00" + }, + { + "name": "nesbot/carbon", + "version": "3.13.0", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "40f6618f052df16b545f626fbf9a878e6497d16a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/40f6618f052df16b545f626fbf9a878e6497d16a", + "reference": "40f6618f052df16b545f626fbf9a878e6497d16a", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "<100.0", + "ext-json": "*", + "php": "^8.1", + "psr/clock": "^1.0", + "symfony/clock": "^6.3.12 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "doctrine/dbal": "^3.6.3 || ^4.0", + "doctrine/orm": "^2.15.2 || ^3.0", + "friendsofphp/php-cs-fixer": "^v3.87.1", + "kylekatarnls/multi-tester": "^2.5.3", + "phpmd/phpmd": "^2.15.0", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.22", + "phpunit/phpunit": "^10.5.53", + "squizlabs/php_codesniffer": "^3.13.4 || ^4.0.0" + }, + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbonphp.github.io/carbon/", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbonphp.github.io/carbon/guide/getting-started/introduction.html", + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon" + }, + "funding": [ + { + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", + "type": "tidelift" + } + ], + "time": "2026-06-18T13:49:15+00:00" + }, + { + "name": "nette/schema", + "version": "v1.3.5", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002", + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002", + "shasum": "" + }, + "require": { + "nette/utils": "^4.0", + "php": "8.1 - 8.5" + }, + "require-dev": { + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.6", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1.39@stable", + "tracy/tracy": "^2.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.3.5" + }, + "time": "2026-02-23T03:47:12+00:00" + }, + { + "name": "nette/utils", + "version": "v4.1.4", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "7da6c396d7ebe142bc857c20479d5e70a5e1aac7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/7da6c396d7ebe142bc857c20479d5e70a5e1aac7", + "reference": "7da6c396d7ebe142bc857c20479d5e70a5e1aac7", + "shasum": "" + }, + "require": { + "php": "8.2 - 8.5" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.5", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.1.4" + }, + "time": "2026-05-11T20:49:54+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.8.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/044a6a392ff8ad0d61f14370a5fbbd0a0107152f", + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.8.0" + }, + "time": "2026-07-04T14:30:18+00:00" + }, + { + "name": "nunomaduro/termwind", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/termwind.git", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^8.2", + "symfony/console": "^7.4.4 || ^8.0.4" + }, + "require-dev": { + "illuminate/console": "^11.47.0", + "laravel/pint": "^1.27.1", + "mockery/mockery": "^1.6.12", + "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2", + "phpstan/phpstan": "^1.12.32", + "phpstan/phpstan-strict-rules": "^1.6.2", + "symfony/var-dumper": "^7.3.5 || ^8.0.4", + "thecodingmachine/phpstan-strict-rules": "^1.0.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Termwind\\Laravel\\TermwindServiceProvider" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/Functions.php" + ], + "psr-4": { + "Termwind\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "It's like Tailwind CSS, but for the console.", + "keywords": [ + "cli", + "console", + "css", + "package", + "php", + "style" + ], + "support": { + "issues": "https://github.com/nunomaduro/termwind/issues", + "source": "https://github.com/nunomaduro/termwind/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://github.com/xiCO2k", + "type": "github" + } + ], + "time": "2026-02-16T23:10:27+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.5", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:41:33+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, + { + "name": "psy/psysh", + "version": "v0.12.24", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "ca0fdcf8a7617afa3adfdf1b5fef573dffb69ca1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/ca0fdcf8a7617afa3adfdf1b5fef573dffb69ca1", + "reference": "ca0fdcf8a7617afa3adfdf1b5fef573dffb69ca1", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "nikic/php-parser": "^5.0 || ^4.0", + "php": "^8.0 || ^7.4", + "symfony/console": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" + }, + "conflict": { + "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", + "composer/class-map-generator": "^1.6" + }, + "suggest": { + "composer/class-map-generator": "Improved tab completion performance with better class discovery.", + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": false, + "forward-command": false + }, + "branch-alias": { + "dev-main": "0.12.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "https://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "support": { + "issues": "https://github.com/bobthecow/psysh/issues", + "source": "https://github.com/bobthecow/psysh/tree/v0.12.24" + }, + "time": "2026-06-29T15:41:09+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "ramsey/collection", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.45", + "fakerphp/faker": "^1.24", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^2.1", + "mockery/mockery": "^1.6", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpspec/prophecy-phpunit": "^2.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5", + "ramsey/coding-standard": "^2.3", + "ramsey/conventional-commits": "^1.6", + "roave/security-advisories": "dev-latest" + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/2.1.1" + }, + "time": "2025-03-22T05:38:12+00:00" + }, + { + "name": "ramsey/uuid", + "version": "4.9.3", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "1df15849d00943a67d677dc9cfd80795f038c9f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/1df15849d00943a67d677dc9cfd80795f038c9f8", + "reference": "1df15849d00943a67d677dc9cfd80795f038c9f8", + "shasum": "" + }, + "require": { + "brick/math": ">=0.8.16 <=0.18", + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.25", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "ergebnis/composer-normalize": "^2.47", + "mockery/mockery": "^1.6", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.6", + "php-mock/php-mock-mockery": "^1.5", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpbench/phpbench": "^1.2.14", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6", + "slevomat/coding-standard": "^8.18", + "squizlabs/php_codesniffer": "^3.13" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.9.3" + }, + "time": "2026-06-18T03:57:49+00:00" + }, + { + "name": "symfony/clock", + "version": "v7.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/674fa3b98e21531dd040e613479f5f6fa8f32111", + "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v7.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-03-24T13:12:05+00:00" + }, + { + "name": "symfony/console", + "version": "v7.4.14", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "92f58bc4bf97a92ed1b9f367f0cd44f20bde0e87" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/92f58bc4bf97a92ed1b9f367f0cd44f20bde0e87", + "reference": "92f58bc4bf97a92ed1b9f367f0cd44f20bde0e87", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.2|^8.0" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.4.14" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-16T11:50:14+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v7.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "b75663ed96cf4756e28e3105476f220f92886cc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/b75663ed96cf4756e28e3105476f220f92886cc4", + "reference": "b75663ed96cf4756e28e3105476f220f92886cc4", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v7.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-04-18T13:18:21+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-05T06:23:12+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v7.4.14", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "4e1a093b481f323e6e326451f9760c3868430673" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/4e1a093b481f323e6e326451f9760c3868430673", + "reference": "4e1a093b481f323e6e326451f9760c3868430673", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/polyfill-php85": "^1.32", + "symfony/var-dumper": "^6.4|^7.0|^8.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/webpack-encore-bundle": "^1.0|^2.0" + }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v7.4.14" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-05T06:22:21+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.4.14", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "51fe3d170227be8d1772214b82ae506e15ed78ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/51fe3d170227be8d1772214b82ae506e15ed78ff", + "reference": "51fe3d170227be8d1772214b82ae506e15ed78ff", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.14" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-06T11:10:32+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c7de7a00ffb67842132da02ea92988a39ccd9f4e", + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-05T06:23:12+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.4.14", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "13b38720174286f55d1761152b575a8d1436fc25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/13b38720174286f55d1761152b575a8d1436fc25", + "reference": "13b38720174286f55d1761152b575a8d1436fc25", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.4.14" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-27T08:31:18+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v7.4.14", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "06db5ae1552177bf8572f8908839f12e3c06aed3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/06db5ae1552177bf8572f8908839f12e3c06aed3", + "reference": "06db5ae1552177bf8572f8908839f12e3c06aed3", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "^1.1" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" + }, + "require-dev": { + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.4.12|^7.1.5|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v7.4.14" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-11T07:31:44+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v7.4.14", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "e99af79b1e776646eda0e1c23b7b45c184ff99be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/e99af79b1e776646eda0e1c23b7b45c184ff99be", + "reference": "e99af79b1e776646eda0e1c23b7b45c184ff99be", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^7.3|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/browser-kit": "<6.4", + "symfony/cache": "<6.4", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/flex": "<2.10", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.4", + "symfony/validator": "<6.4", + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.12" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4.1|^7.0.1|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^7.1|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/serializer": "^7.1|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0", + "twig/twig": "^3.12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v7.4.14" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-27T09:14:35+00:00" + }, + { + "name": "symfony/mailer", + "version": "v7.4.14", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "f88ce03ae73e3edb5c176ce1f337709996e88495" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/f88ce03ae73e3edb5c176ce1f337709996e88495", + "reference": "f88ce03ae73e3edb5c176ce1f337709996e88495", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.2", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/mime": "^7.2|^8.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/twig-bridge": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v7.4.14" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-13T08:51:35+00:00" + }, + { + "name": "symfony/mime", + "version": "v7.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "a845722765c4f6b2ce88beaf4f4479975b186770" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/a845722765c4f6b2ce88beaf4f4479975b186770", + "reference": "a845722765c4f6b2ce88beaf4f4479975b186770", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<5.2|>=7", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^5.2|^6.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v7.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-23T16:22:37+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.37.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-04-10T16:19:22+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.38.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "e9247d281d694a5120554d9afaf54e070e88a603" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603", + "reference": "e9247d281d694a5120554d9afaf54e070e88a603", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-26T05:58:03+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.38.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "dc21118016c039a66235cf93d96b435ffb282412" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/dc21118016c039a66235cf93d96b435ffb282412", + "reference": "dc21118016c039a66235cf93d96b435ffb282412", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.38.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-25T15:22:23+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.38.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b", + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-25T13:48:31+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.38.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-27T06:59:30+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.37.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-04-10T16:19:22+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.38.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "796a26abb75ce49f3a84433cd81bf1009d73d5f8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/796a26abb75ce49f3a84433cd81bf1009d73d5f8", + "reference": "796a26abb75ce49f3a84433cd81bf1009d73d5f8", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.38.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-27T06:51:48+00:00" + }, + { + "name": "symfony/polyfill-php84", + "version": "v1.38.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa", + "reference": "f4e1dfaee5b74aba5964fe1fd4dfc7ba5e3085fa", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php84\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php84/tree/v1.38.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-26T12:51:13+00:00" + }, + { + "name": "symfony/polyfill-php85", + "version": "v1.38.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1", + "reference": "ba2ba04f3352cfa2dcbbcb90aee13ed967f505b1", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php85\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php85/tree/v1.38.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-26T02:25:22+00:00" + }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.37.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "26dfec253c4cf3e51b541b52ddf7e42cb0908e94" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/26dfec253c4cf3e51b541b52ddf7e42cb0908e94", + "reference": "26dfec253c4cf3e51b541b52ddf7e42cb0908e94", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.37.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-04-10T16:19:22+00:00" + }, + { + "name": "symfony/process", + "version": "v7.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "f5804be144caceb570f6747519999636b664f24c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/f5804be144caceb570f6747519999636b664f24c", + "reference": "f5804be144caceb570f6747519999636b664f24c", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-23T16:05:06+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "3a162171bb008e5e0f15dce6581373a4c0e8390d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/3a162171bb008e5e0f15dce6581373a4c0e8390d", + "reference": "3a162171bb008e5e0f15dce6581373a4c0e8390d", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v7.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-24T11:20:33+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-16T09:55:08+00:00" + }, + { + "name": "symfony/string", + "version": "v7.4.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "961683010db3b27ec6ebcd7308e6e1ee8fa7ffde" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/961683010db3b27ec6ebcd7308e6e1ee8fa7ffde", + "reference": "961683010db3b27ec6ebcd7308e6e1ee8fa7ffde", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.33", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.4.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-23T15:23:29+00:00" + }, + { + "name": "symfony/translation", + "version": "v7.4.14", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "a1af4dacb24eb7ef4f1ca71b94da8ddbce572281" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/a1af4dacb24eb7ef4f1ca71b94da8ddbce572281", + "reference": "a1af4dacb24eb7ef4f1ca71b94da8ddbce572281", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5.3|^3.3" + }, + "conflict": { + "nikic/php-parser": "<5.0", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" + }, + "require-dev": { + "nikic/php-parser": "^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v7.4.14" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-06T09:33:19+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.7.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "ccb206b98faccc511ebae8e5fad50f2dc0b30621" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/ccb206b98faccc511ebae8e5fad50f2dc0b30621", + "reference": "ccb206b98faccc511ebae8e5fad50f2dc0b30621", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.7.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-05T06:23:12+00:00" + }, + { + "name": "symfony/uid", + "version": "v7.4.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/uid.git", + "reference": "2676b524340abcfe4d6151ec698463cebafee439" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/uid/zipball/2676b524340abcfe4d6151ec698463cebafee439", + "reference": "2676b524340abcfe4d6151ec698463cebafee439", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-uuid": "^1.15" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", + "keywords": [ + "UID", + "ulid", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/uid/tree/v7.4.9" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-04-30T15:19:22+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v7.4.14", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358", + "reference": "9a3a56a4a1e65a5cb4f8d13801fe8ab0a170e358", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "twig/twig": "^3.12" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v7.4.14" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-08T20:24:16+00:00" + }, + { + "name": "tijsverkoyen/css-to-inline-styles", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/f0292ccf0ec75843d65027214426b6b163b48b41", + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "php": "^7.4 || ^8.0", + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "TijsVerkoyen\\CssToInlineStyles\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Tijs Verkoyen", + "email": "css_to_inline_styles@verkoyen.eu", + "role": "Developer" + } + ], + "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", + "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", + "support": { + "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.4.0" + }, + "time": "2025-12-02T11:56:42+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.3", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "955e7815d677a3eaa7075231212f2110983adecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.4", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:49:13+00:00" + }, + { + "name": "voku/portable-ascii", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/voku/portable-ascii.git", + "reference": "8e1051fe39379367aecf014f41744ce7539a856f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/8e1051fe39379367aecf014f41744ce7539a856f", + "reference": "8e1051fe39379367aecf014f41744ce7539a856f", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpunit/phpunit": "~8.5 || ~9.6 || ~10.5 || ~11.5" + }, + "suggest": { + "ext-intl": "Use Intl for transliterator_transliterate() support" + }, + "type": "library", + "autoload": { + "psr-4": { + "voku\\": "src/voku/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lars Moelleken", + "homepage": "https://www.moelleken.org/" + } + ], + "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", + "homepage": "https://github.com/voku/portable-ascii", + "keywords": [ + "ascii", + "clean", + "php" + ], + "support": { + "issues": "https://github.com/voku/portable-ascii/issues", + "source": "https://github.com/voku/portable-ascii/tree/2.1.1" + }, + "funding": [ + { + "url": "https://www.paypal.me/moelleken", + "type": "custom" + }, + { + "url": "https://github.com/voku", + "type": "github" + }, + { + "url": "https://opencollective.com/portable-ascii", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/voku", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", + "type": "tidelift" + } + ], + "time": "2026-04-26T05:33:54+00:00" + } + ], + "packages-dev": [ + { + "name": "fakerphp/faker", + "version": "v1.24.1", + "source": { + "type": "git", + "url": "https://github.com/FakerPHP/Faker.git", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "conflict": { + "fzaninotto/faker": "*" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "doctrine/persistence": "^1.3 || ^2.0", + "ext-intl": "*", + "phpunit/phpunit": "^9.5.26", + "symfony/phpunit-bridge": "^5.4.16" + }, + "suggest": { + "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", + "ext-curl": "Required by Faker\\Provider\\Image to download images.", + "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", + "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", + "ext-mbstring": "Required for multibyte Unicode string functionality." + }, + "type": "library", + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "support": { + "issues": "https://github.com/FakerPHP/Faker/issues", + "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1" + }, + "time": "2024-11-21T13:46:39+00:00" + }, + { + "name": "filp/whoops", + "version": "2.18.4", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.18.4" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2025-08-08T12:00:00+00:00" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "^1.4 || ^2.0 || ^3.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "support": { + "issues": "https://github.com/hamcrest/hamcrest-php/issues", + "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.1.1" + }, + "time": "2025-04-30T06:54:44+00:00" + }, + { + "name": "laravel/pail", + "version": "v1.2.7", + "source": { + "type": "git", + "url": "https://github.com/laravel/pail.git", + "reference": "2f7d27dada8effc48b8c424445a69cca7007daaa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pail/zipball/2f7d27dada8effc48b8c424445a69cca7007daaa", + "reference": "2f7d27dada8effc48b8c424445a69cca7007daaa", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "illuminate/console": "^10.24|^11.0|^12.0|^13.0", + "illuminate/contracts": "^10.24|^11.0|^12.0|^13.0", + "illuminate/log": "^10.24|^11.0|^12.0|^13.0", + "illuminate/process": "^10.24|^11.0|^12.0|^13.0", + "illuminate/support": "^10.24|^11.0|^12.0|^13.0", + "nunomaduro/termwind": "^1.15|^2.0", + "php": "^8.2", + "symfony/console": "^6.0|^7.0|^8.0" + }, + "require-dev": { + "laravel/framework": "^10.24|^11.0|^12.0|^13.0", + "laravel/pint": "^1.13", + "orchestra/testbench-core": "^8.13|^9.17|^10.8|^11.0", + "pestphp/pest": "^2.20|^3.0|^4.0", + "pestphp/pest-plugin-type-coverage": "^2.3|^3.0|^4.0", + "phpstan/phpstan": "^1.12.27", + "symfony/var-dumper": "^6.3|^7.0|^8.0", + "symfony/yaml": "^6.3|^7.0|^8.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Pail\\PailServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Pail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Easily delve into your Laravel application's log files directly from the command line.", + "homepage": "https://github.com/laravel/pail", + "keywords": [ + "dev", + "laravel", + "logs", + "php", + "tail" + ], + "support": { + "issues": "https://github.com/laravel/pail/issues", + "source": "https://github.com/laravel/pail" + }, + "time": "2026-05-20T22:24:57+00:00" + }, + { + "name": "laravel/pint", + "version": "v1.29.3", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "da1d1111a6aa2e082d2a388b194afe1ba0a05d14" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/da1d1111a6aa2e082d2a388b194afe1ba0a05d14", + "reference": "da1d1111a6aa2e082d2a388b194afe1ba0a05d14", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.95.8", + "illuminate/view": "^12.62.0", + "larastan/larastan": "^3.10.0", + "laravel-zero/framework": "^12.1.0", + "laravel/agent-detector": "^2.0.2", + "mockery/mockery": "^1.6.12", + "nunomaduro/termwind": "^2.4.0", + "pestphp/pest": "^3.8.6" + }, + "bin": [ + "builds/pint" + ], + "type": "project", + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", + "keywords": [ + "dev", + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2026-06-16T15:34:04+00:00" + }, + { + "name": "laravel/sail", + "version": "v1.63.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/sail.git", + "reference": "51bbce3f803c1d386cabbb44e618c955a12ff5fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sail/zipball/51bbce3f803c1d386cabbb44e618c955a12ff5fc", + "reference": "51bbce3f803c1d386cabbb44e618c955a12ff5fc", + "shasum": "" + }, + "require": { + "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "php": "^8.0", + "symfony/console": "^6.0|^7.0|^8.0", + "symfony/yaml": "^6.0|^7.0|^8.0" + }, + "require-dev": { + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0|^11.0", + "phpstan/phpstan": "^2.0" + }, + "bin": [ + "bin/sail" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sail\\SailServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Docker files for running a basic Laravel application.", + "keywords": [ + "docker", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/sail/issues", + "source": "https://github.com/laravel/sail" + }, + "time": "2026-06-18T08:54:14+00:00" + }, + { + "name": "mockery/mockery", + "version": "1.6.12", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "^2.0.1", + "lib-pcre": ">=7.0", + "php": ">=7.3" + }, + "conflict": { + "phpunit/phpunit": "<8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5 || ^9.6.17", + "symplify/easy-coding-standard": "^12.1.14" + }, + "type": "library", + "autoload": { + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "https://github.com/padraic", + "role": "Author" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework", + "homepage": "https://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "docs": "https://docs.mockery.io/", + "issues": "https://github.com/mockery/mockery/issues", + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" + }, + "time": "2024-05-16T03:13:13+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nunomaduro/collision", + "version": "v8.9.4", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "716af8f95a470e9094cfca09ed897b023be191a5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/716af8f95a470e9094cfca09ed897b023be191a5", + "reference": "716af8f95a470e9094cfca09ed897b023be191a5", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.18.4", + "nunomaduro/termwind": "^2.4.0", + "php": "^8.2.0", + "symfony/console": "^7.4.8 || ^8.0.8" + }, + "conflict": { + "laravel/framework": "<11.48.0 || >=14.0.0", + "phpunit/phpunit": "<11.5.50 || >=14.0.0" + }, + "require-dev": { + "brianium/paratest": "^7.8.5", + "larastan/larastan": "^3.9.6", + "laravel/framework": "^11.48.0 || ^12.56.0 || ^13.5.0", + "laravel/pint": "^1.29.1", + "orchestra/testbench-core": "^9.12.0 || ^10.12.1 || ^11.2.1", + "pestphp/pest": "^3.8.5 || ^4.4.3 || ^5.0.0", + "sebastian/environment": "^7.2.1 || ^8.0.4 || ^9.3.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + }, + "branch-alias": { + "dev-8.x": "8.x-dev" + } + }, + "autoload": { + "files": [ + "./src/Adapters/Phpunit/Autoload.php" + ], + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "dev", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "support": { + "issues": "https://github.com/nunomaduro/collision/issues", + "source": "https://github.com/nunomaduro/collision" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2026-04-21T14:04:20+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.12", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.7.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.1", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.3.1" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.46" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.12" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-12-24T07:01:01+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" + } + ], + "time": "2026-02-02T13:52:54+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.5.56", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "5f83edffa6967c3db468d48a695ec7bcb02e9256" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5f83edffa6967c3db468d48a695ec7bcb02e9256", + "reference": "5f83edffa6967c3db468d48a695ec7bcb02e9256", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-filter": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.12", + "phpunit/php-file-iterator": "^5.1.1", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.3", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.1", + "sebastian/exporter": "^6.3.2", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/recursion-context": "^6.0.3", + "sebastian/type": "^5.1.3", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.56" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsoring.html", + "type": "other" + } + ], + "time": "2026-07-06T14:52:39+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-19T07:56:08+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2026-01-24T09:26:40+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" + } + ], + "time": "2025-05-21T11:55:47+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" + } + ], + "time": "2025-09-24T06:12:51+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:57:36+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:58:38+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:00:13+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:01:32+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" + } + ], + "time": "2025-08-13T04:42:22+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" + } + ], + "time": "2025-08-09T06:55:48+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-09T05:16:32+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/yaml", + "version": "v7.4.14", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "f8f328665ace2370d1e10645b807ba1646dc7dcc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/f8f328665ace2370d1e10645b807ba1646dc7dcc", + "reference": "f8f328665ace2370d1e10645b807ba1646dc7dcc", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.4.14" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-06-08T20:24:16+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2025-11-17T20:03:58+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": "^8.2" + }, + "platform-dev": {}, + "plugin-api-version": "2.9.0" +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..423eed5 --- /dev/null +++ b/config/app.php @@ -0,0 +1,126 @@ + env('APP_NAME', 'Laravel'), + + /* + |-------------------------------------------------------------------------- + | Application Environment + |-------------------------------------------------------------------------- + | + | This value determines the "environment" your application is currently + | running in. This may determine how you prefer to configure various + | services the application utilizes. Set this in your ".env" file. + | + */ + + 'env' => env('APP_ENV', 'production'), + + /* + |-------------------------------------------------------------------------- + | Application Debug Mode + |-------------------------------------------------------------------------- + | + | When your application is in debug mode, detailed error messages with + | stack traces will be shown on every error that occurs within your + | application. If disabled, a simple generic error page is shown. + | + */ + + 'debug' => (bool) env('APP_DEBUG', false), + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | the application so that it's available within Artisan commands. + | + */ + + 'url' => env('APP_URL', 'http://localhost'), + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. The timezone + | is set to "UTC" by default as it is suitable for most use cases. + | + */ + + 'timezone' => 'UTC', + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by Laravel's translation / localization methods. This option can be + | set to any locale for which you plan to have translation strings. + | + */ + + 'locale' => env('APP_LOCALE', 'en'), + + 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), + + 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is utilized by Laravel's encryption services and should be set + | to a random, 32 character string to ensure that all encrypted values + | are secure. You should do this prior to deploying the application. + | + */ + + 'cipher' => 'AES-256-CBC', + + 'key' => env('APP_KEY'), + + 'previous_keys' => [ + ...array_filter( + explode(',', (string) env('APP_PREVIOUS_KEYS', '')) + ), + ], + + /* + |-------------------------------------------------------------------------- + | Maintenance Mode Driver + |-------------------------------------------------------------------------- + | + | These configuration options determine the driver used to determine and + | manage Laravel's "maintenance mode" status. The "cache" driver will + | allow maintenance mode to be controlled across multiple machines. + | + | Supported drivers: "file", "cache" + | + */ + + 'maintenance' => [ + 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), + 'store' => env('APP_MAINTENANCE_STORE', 'database'), + ], + +]; diff --git a/config/auth.php b/config/auth.php new file mode 100644 index 0000000..d7568ff --- /dev/null +++ b/config/auth.php @@ -0,0 +1,117 @@ + [ + 'guard' => env('AUTH_GUARD', 'web'), + 'passwords' => env('AUTH_PASSWORD_BROKER', 'users'), + ], + + /* + |-------------------------------------------------------------------------- + | Authentication Guards + |-------------------------------------------------------------------------- + | + | Next, you may define every authentication guard for your application. + | Of course, a great default configuration has been defined for you + | which utilizes session storage plus the Eloquent user provider. + | + | All authentication guards have a user provider, which defines how the + | users are actually retrieved out of your database or other storage + | system used by the application. Typically, Eloquent is utilized. + | + | Supported: "session" + | + */ + + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + ], + + /* + |-------------------------------------------------------------------------- + | User Providers + |-------------------------------------------------------------------------- + | + | All authentication guards have a user provider, which defines how the + | users are actually retrieved out of your database or other storage + | system used by the application. Typically, Eloquent is utilized. + | + | If you have multiple user tables or models you may configure multiple + | providers to represent the model / table. These providers may then + | be assigned to any extra authentication guards you have defined. + | + | Supported: "database", "eloquent" + | + */ + + 'providers' => [ + 'users' => [ + 'driver' => 'eloquent', + 'model' => env('AUTH_MODEL', User::class), + ], + + // 'users' => [ + // 'driver' => 'database', + // 'table' => 'users', + // ], + ], + + /* + |-------------------------------------------------------------------------- + | Resetting Passwords + |-------------------------------------------------------------------------- + | + | These configuration options specify the behavior of Laravel's password + | reset functionality, including the table utilized for token storage + | and the user provider that is invoked to actually retrieve users. + | + | The expiry time is the number of minutes that each reset token will be + | considered valid. This security feature keeps tokens short-lived so + | they have less time to be guessed. You may change this as needed. + | + | The throttle setting is the number of seconds a user must wait before + | generating more password reset tokens. This prevents the user from + | quickly generating a very large amount of password reset tokens. + | + */ + + 'passwords' => [ + 'users' => [ + 'provider' => 'users', + 'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'), + 'expire' => 60, + 'throttle' => 60, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Password Confirmation Timeout + |-------------------------------------------------------------------------- + | + | Here you may define the number of seconds before a password confirmation + | window expires and users are asked to re-enter their password via the + | confirmation screen. By default, the timeout lasts for three hours. + | + */ + + 'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800), + +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..b32aead --- /dev/null +++ b/config/cache.php @@ -0,0 +1,117 @@ + env('CACHE_STORE', 'database'), + + /* + |-------------------------------------------------------------------------- + | Cache Stores + |-------------------------------------------------------------------------- + | + | Here you may define all of the cache "stores" for your application as + | well as their drivers. You may even define multiple stores for the + | same cache driver to group types of items stored in your caches. + | + | Supported drivers: "array", "database", "file", "memcached", + | "redis", "dynamodb", "octane", + | "failover", "null" + | + */ + + 'stores' => [ + + 'array' => [ + 'driver' => 'array', + 'serialize' => false, + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_CACHE_CONNECTION'), + 'table' => env('DB_CACHE_TABLE', 'cache'), + 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), + 'lock_table' => env('DB_CACHE_LOCK_TABLE'), + ], + + 'file' => [ + 'driver' => 'file', + 'path' => storage_path('framework/cache/data'), + 'lock_path' => storage_path('framework/cache/data'), + ], + + 'memcached' => [ + 'driver' => 'memcached', + 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), + 'sasl' => [ + env('MEMCACHED_USERNAME'), + env('MEMCACHED_PASSWORD'), + ], + 'options' => [ + // Memcached::OPT_CONNECT_TIMEOUT => 2000, + ], + 'servers' => [ + [ + 'host' => env('MEMCACHED_HOST', '127.0.0.1'), + 'port' => env('MEMCACHED_PORT', 11211), + 'weight' => 100, + ], + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_CACHE_CONNECTION', 'cache'), + 'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'), + ], + + 'dynamodb' => [ + 'driver' => 'dynamodb', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), + 'endpoint' => env('DYNAMODB_ENDPOINT'), + ], + + 'octane' => [ + 'driver' => 'octane', + ], + + 'failover' => [ + 'driver' => 'failover', + 'stores' => [ + 'database', + 'array', + ], + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing the APC, database, memcached, Redis, and DynamoDB cache + | stores, there might be other applications using the same cache. For + | that reason, you may prefix every cache key to avoid collisions. + | + */ + + 'prefix' => env('CACHE_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-cache-'), + +]; diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..64709ce --- /dev/null +++ b/config/database.php @@ -0,0 +1,184 @@ + env('DB_CONNECTION', 'sqlite'), + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Below are all of the database connections defined for your application. + | An example configuration is provided for each database system which + | is supported by Laravel. You're free to add / remove connections. + | + */ + + 'connections' => [ + + 'sqlite' => [ + 'driver' => 'sqlite', + 'url' => env('DB_URL'), + 'database' => env('DB_DATABASE', database_path('database.sqlite')), + 'prefix' => '', + 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), + 'busy_timeout' => null, + 'journal_mode' => null, + 'synchronous' => null, + 'transaction_mode' => 'DEFERRED', + ], + + 'mysql' => [ + 'driver' => 'mysql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + (PHP_VERSION_ID >= 80500 ? Mysql::ATTR_SSL_CA : PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'mariadb' => [ + 'driver' => 'mariadb', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + (PHP_VERSION_ID >= 80500 ? Mysql::ATTR_SSL_CA : PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'pgsql' => [ + 'driver' => 'pgsql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '5432'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + 'search_path' => 'public', + 'sslmode' => env('DB_SSLMODE', 'prefer'), + ], + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', 'localhost'), + 'port' => env('DB_PORT', '1433'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + // 'encrypt' => env('DB_ENCRYPT', 'yes'), + // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run on the database. + | + */ + + 'migrations' => [ + 'table' => 'migrations', + 'update_date_on_publish' => true, + ], + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer body of commands than a typical key-value system + | such as Memcached. You may define your connection settings here. + | + */ + + 'redis' => [ + + 'client' => env('REDIS_CLIENT', 'phpredis'), + + 'options' => [ + 'cluster' => env('REDIS_CLUSTER', 'redis'), + 'prefix' => env('REDIS_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-database-'), + 'persistent' => env('REDIS_PERSISTENT', false), + ], + + 'default' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_DB', '0'), + 'max_retries' => env('REDIS_MAX_RETRIES', 3), + 'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'), + 'backoff_base' => env('REDIS_BACKOFF_BASE', 100), + 'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000), + ], + + 'cache' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_CACHE_DB', '1'), + 'max_retries' => env('REDIS_MAX_RETRIES', 3), + 'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'), + 'backoff_base' => env('REDIS_BACKOFF_BASE', 100), + 'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000), + ], + + ], + +]; diff --git a/config/filesystems.php b/config/filesystems.php new file mode 100644 index 0000000..37d8fca --- /dev/null +++ b/config/filesystems.php @@ -0,0 +1,80 @@ + env('FILESYSTEM_DISK', 'local'), + + /* + |-------------------------------------------------------------------------- + | Filesystem Disks + |-------------------------------------------------------------------------- + | + | Below you may configure as many filesystem disks as necessary, and you + | may even configure multiple disks for the same driver. Examples for + | most supported storage drivers are configured here for reference. + | + | Supported drivers: "local", "ftp", "sftp", "s3" + | + */ + + 'disks' => [ + + 'local' => [ + 'driver' => 'local', + 'root' => storage_path('app/private'), + 'serve' => true, + 'throw' => false, + 'report' => false, + ], + + 'public' => [ + 'driver' => 'local', + 'root' => storage_path('app/public'), + 'url' => rtrim(env('APP_URL', 'http://localhost'), '/').'/storage', + 'visibility' => 'public', + 'throw' => false, + 'report' => false, + ], + + 's3' => [ + 'driver' => 's3', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION'), + 'bucket' => env('AWS_BUCKET'), + 'url' => env('AWS_URL'), + 'endpoint' => env('AWS_ENDPOINT'), + 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), + 'throw' => false, + 'report' => false, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Symbolic Links + |-------------------------------------------------------------------------- + | + | Here you may configure the symbolic links that will be created when the + | `storage:link` Artisan command is executed. The array keys should be + | the locations of the links and the values should be their targets. + | + */ + + 'links' => [ + public_path('storage') => storage_path('app/public'), + ], + +]; diff --git a/config/logging.php b/config/logging.php new file mode 100644 index 0000000..b09cb25 --- /dev/null +++ b/config/logging.php @@ -0,0 +1,132 @@ + env('LOG_CHANNEL', 'stack'), + + /* + |-------------------------------------------------------------------------- + | Deprecations Log Channel + |-------------------------------------------------------------------------- + | + | This option controls the log channel that should be used to log warnings + | regarding deprecated PHP and library features. This allows you to get + | your application ready for upcoming major versions of dependencies. + | + */ + + 'deprecations' => [ + 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), + 'trace' => env('LOG_DEPRECATIONS_TRACE', false), + ], + + /* + |-------------------------------------------------------------------------- + | Log Channels + |-------------------------------------------------------------------------- + | + | Here you may configure the log channels for your application. Laravel + | utilizes the Monolog PHP logging library, which includes a variety + | of powerful log handlers and formatters that you're free to use. + | + | Available drivers: "single", "daily", "slack", "syslog", + | "errorlog", "monolog", "custom", "stack" + | + */ + + 'channels' => [ + + 'stack' => [ + 'driver' => 'stack', + 'channels' => explode(',', (string) env('LOG_STACK', 'single')), + 'ignore_exceptions' => false, + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'days' => env('LOG_DAILY_DAYS', 14), + 'replace_placeholders' => true, + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => env('LOG_SLACK_USERNAME', env('APP_NAME', 'Laravel')), + 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'), + 'level' => env('LOG_LEVEL', 'critical'), + 'replace_placeholders' => true, + ], + + 'papertrail' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), + 'handler_with' => [ + 'host' => env('PAPERTRAIL_URL'), + 'port' => env('PAPERTRAIL_PORT'), + 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), + ], + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => StreamHandler::class, + 'handler_with' => [ + 'stream' => 'php://stderr', + ], + 'formatter' => env('LOG_STDERR_FORMATTER'), + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => env('LOG_LEVEL', 'debug'), + 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), + 'replace_placeholders' => true, + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'null' => [ + 'driver' => 'monolog', + 'handler' => NullHandler::class, + ], + + 'emergency' => [ + 'path' => storage_path('logs/laravel.log'), + ], + + ], + +]; diff --git a/config/mail.php b/config/mail.php new file mode 100644 index 0000000..e32e88d --- /dev/null +++ b/config/mail.php @@ -0,0 +1,118 @@ + env('MAIL_MAILER', 'log'), + + /* + |-------------------------------------------------------------------------- + | Mailer Configurations + |-------------------------------------------------------------------------- + | + | Here you may configure all of the mailers used by your application plus + | their respective settings. Several examples have been configured for + | you and you are free to add your own as your application requires. + | + | Laravel supports a variety of mail "transport" drivers that can be used + | when delivering an email. You may specify which one you're using for + | your mailers below. You may also add additional mailers if needed. + | + | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", + | "postmark", "resend", "log", "array", + | "failover", "roundrobin" + | + */ + + 'mailers' => [ + + 'smtp' => [ + 'transport' => 'smtp', + 'scheme' => env('MAIL_SCHEME'), + 'url' => env('MAIL_URL'), + 'host' => env('MAIL_HOST', '127.0.0.1'), + 'port' => env('MAIL_PORT', 2525), + 'username' => env('MAIL_USERNAME'), + 'password' => env('MAIL_PASSWORD'), + 'timeout' => null, + 'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url((string) env('APP_URL', 'http://localhost'), PHP_URL_HOST)), + ], + + 'ses' => [ + 'transport' => 'ses', + ], + + 'postmark' => [ + 'transport' => 'postmark', + // 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'), + // 'client' => [ + // 'timeout' => 5, + // ], + ], + + 'resend' => [ + 'transport' => 'resend', + ], + + 'sendmail' => [ + 'transport' => 'sendmail', + 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), + ], + + 'log' => [ + 'transport' => 'log', + 'channel' => env('MAIL_LOG_CHANNEL'), + ], + + 'array' => [ + 'transport' => 'array', + ], + + 'failover' => [ + 'transport' => 'failover', + 'mailers' => [ + 'smtp', + 'log', + ], + 'retry_after' => 60, + ], + + 'roundrobin' => [ + 'transport' => 'roundrobin', + 'mailers' => [ + 'ses', + 'postmark', + ], + 'retry_after' => 60, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all emails sent by your application to be sent from + | the same address. Here you may specify a name and address that is + | used globally for all emails that are sent by your application. + | + */ + + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', env('APP_NAME', 'Laravel')), + ], + +]; diff --git a/config/queue.php b/config/queue.php new file mode 100644 index 0000000..79c2c0a --- /dev/null +++ b/config/queue.php @@ -0,0 +1,129 @@ + env('QUEUE_CONNECTION', 'database'), + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection options for every queue backend + | used by your application. An example configuration is provided for + | each backend supported by Laravel. You're also free to add more. + | + | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", + | "deferred", "background", "failover", "null" + | + */ + + 'connections' => [ + + 'sync' => [ + 'driver' => 'sync', + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_QUEUE_CONNECTION'), + 'table' => env('DB_QUEUE_TABLE', 'jobs'), + 'queue' => env('DB_QUEUE', 'default'), + 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), + 'after_commit' => false, + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'), + 'queue' => env('BEANSTALKD_QUEUE', 'default'), + 'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90), + 'block_for' => 0, + 'after_commit' => false, + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), + 'queue' => env('SQS_QUEUE', 'default'), + 'suffix' => env('SQS_SUFFIX'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'after_commit' => false, + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), + 'queue' => env('REDIS_QUEUE', 'default'), + 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), + 'block_for' => null, + 'after_commit' => false, + ], + + 'deferred' => [ + 'driver' => 'deferred', + ], + + 'background' => [ + 'driver' => 'background', + ], + + 'failover' => [ + 'driver' => 'failover', + 'connections' => [ + 'database', + 'deferred', + ], + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Job Batching + |-------------------------------------------------------------------------- + | + | The following options configure the database and table that store job + | batching information. These options can be updated to any database + | connection and table which has been defined by your application. + | + */ + + 'batching' => [ + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'job_batches', + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control how and where failed jobs are stored. Laravel ships with + | support for storing failed jobs in a simple file or in a database. + | + | Supported drivers: "database-uuids", "dynamodb", "file", "null" + | + */ + + 'failed' => [ + 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'failed_jobs', + ], + +]; diff --git a/config/services.php b/config/services.php new file mode 100644 index 0000000..6a90eb8 --- /dev/null +++ b/config/services.php @@ -0,0 +1,38 @@ + [ + 'key' => env('POSTMARK_API_KEY'), + ], + + 'resend' => [ + 'key' => env('RESEND_API_KEY'), + ], + + 'ses' => [ + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + ], + + 'slack' => [ + 'notifications' => [ + 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), + 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), + ], + ], + +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..5b541b7 --- /dev/null +++ b/config/session.php @@ -0,0 +1,217 @@ + env('SESSION_DRIVER', 'database'), + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle before it expires. If you want them + | to expire immediately when the browser is closed then you may + | indicate that via the expire_on_close configuration option. + | + */ + + 'lifetime' => (int) env('SESSION_LIFETIME', 120), + + 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), + + /* + |-------------------------------------------------------------------------- + | Session Encryption + |-------------------------------------------------------------------------- + | + | This option allows you to easily specify that all of your session data + | should be encrypted before it's stored. All encryption is performed + | automatically by Laravel and you may use the session like normal. + | + */ + + 'encrypt' => env('SESSION_ENCRYPT', false), + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When utilizing the "file" session driver, the session files are placed + | on disk. The default storage location is defined here; however, you + | are free to provide another location where they should be stored. + | + */ + + 'files' => storage_path('framework/sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => env('SESSION_CONNECTION'), + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table to + | be used to store sessions. Of course, a sensible default is defined + | for you; however, you're welcome to change this to another table. + | + */ + + 'table' => env('SESSION_TABLE', 'sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Cache Store + |-------------------------------------------------------------------------- + | + | When using one of the framework's cache driven session backends, you may + | define the cache store which should be used to store the session data + | between requests. This must match one of your defined cache stores. + | + | Affects: "dynamodb", "memcached", "redis" + | + */ + + 'store' => env('SESSION_STORE'), + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => [2, 100], + + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the session cookie that is created by + | the framework. Typically, you should not need to change this value + | since doing so does not grant a meaningful security improvement. + | + */ + + 'cookie' => env( + 'SESSION_COOKIE', + Str::slug((string) env('APP_NAME', 'laravel')).'-session' + ), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application, but you're free to change this when necessary. + | + */ + + 'path' => env('SESSION_PATH', '/'), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | This value determines the domain and subdomains the session cookie is + | available to. By default, the cookie will be available to the root + | domain without subdomains. Typically, this shouldn't be changed. + | + */ + + 'domain' => env('SESSION_DOMAIN'), + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you when it can't be done securely. + | + */ + + 'secure' => env('SESSION_SECURE_COOKIE'), + + /* + |-------------------------------------------------------------------------- + | HTTP Access Only + |-------------------------------------------------------------------------- + | + | Setting this value to true will prevent JavaScript from accessing the + | value of the cookie and the cookie will only be accessible through + | the HTTP protocol. It's unlikely you should disable this option. + | + */ + + 'http_only' => env('SESSION_HTTP_ONLY', true), + + /* + |-------------------------------------------------------------------------- + | Same-Site Cookies + |-------------------------------------------------------------------------- + | + | This option determines how your cookies behave when cross-site requests + | take place, and can be used to mitigate CSRF attacks. By default, we + | will set this value to "lax" to permit secure cross-site requests. + | + | See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value + | + | Supported: "lax", "strict", "none", null + | + */ + + 'same_site' => env('SESSION_SAME_SITE', 'lax'), + + /* + |-------------------------------------------------------------------------- + | Partitioned Cookies + |-------------------------------------------------------------------------- + | + | Setting this value to true will tie the cookie to the top-level site for + | a cross-site context. Partitioned cookies are accepted by the browser + | when flagged "secure" and the Same-Site attribute is set to "none". + | + */ + + 'partitioned' => env('SESSION_PARTITIONED_COOKIE', false), + +]; diff --git a/database/.gitignore b/database/.gitignore new file mode 100644 index 0000000..9b19b93 --- /dev/null +++ b/database/.gitignore @@ -0,0 +1 @@ +*.sqlite* diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php new file mode 100644 index 0000000..c4ceb07 --- /dev/null +++ b/database/factories/UserFactory.php @@ -0,0 +1,45 @@ + + */ +class UserFactory extends Factory +{ + /** + * The current password being used by the factory. + */ + protected static ?string $password; + + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'name' => fake()->name(), + 'email' => fake()->unique()->safeEmail(), + 'email_verified_at' => now(), + 'password' => static::$password ??= Hash::make('password'), + 'remember_token' => Str::random(10), + ]; + } + + /** + * Indicate that the model's email address should be unverified. + */ + public function unverified(): static + { + return $this->state(fn (array $attributes) => [ + 'email_verified_at' => null, + ]); + } +} diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php new file mode 100644 index 0000000..05fb5d9 --- /dev/null +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -0,0 +1,49 @@ +id(); + $table->string('name'); + $table->string('email')->unique(); + $table->timestamp('email_verified_at')->nullable(); + $table->string('password'); + $table->rememberToken(); + $table->timestamps(); + }); + + Schema::create('password_reset_tokens', function (Blueprint $table) { + $table->string('email')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + + Schema::create('sessions', function (Blueprint $table) { + $table->string('id')->primary(); + $table->foreignId('user_id')->nullable()->index(); + $table->string('ip_address', 45)->nullable(); + $table->text('user_agent')->nullable(); + $table->longText('payload'); + $table->integer('last_activity')->index(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('users'); + Schema::dropIfExists('password_reset_tokens'); + Schema::dropIfExists('sessions'); + } +}; diff --git a/database/migrations/0001_01_01_000001_create_cache_table.php b/database/migrations/0001_01_01_000001_create_cache_table.php new file mode 100644 index 0000000..ed758bd --- /dev/null +++ b/database/migrations/0001_01_01_000001_create_cache_table.php @@ -0,0 +1,35 @@ +string('key')->primary(); + $table->mediumText('value'); + $table->integer('expiration')->index(); + }); + + Schema::create('cache_locks', function (Blueprint $table) { + $table->string('key')->primary(); + $table->string('owner'); + $table->integer('expiration')->index(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cache'); + Schema::dropIfExists('cache_locks'); + } +}; diff --git a/database/migrations/0001_01_01_000002_create_jobs_table.php b/database/migrations/0001_01_01_000002_create_jobs_table.php new file mode 100644 index 0000000..425e705 --- /dev/null +++ b/database/migrations/0001_01_01_000002_create_jobs_table.php @@ -0,0 +1,57 @@ +id(); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + + Schema::create('job_batches', function (Blueprint $table) { + $table->string('id')->primary(); + $table->string('name'); + $table->integer('total_jobs'); + $table->integer('pending_jobs'); + $table->integer('failed_jobs'); + $table->longText('failed_job_ids'); + $table->mediumText('options')->nullable(); + $table->integer('cancelled_at')->nullable(); + $table->integer('created_at'); + $table->integer('finished_at')->nullable(); + }); + + Schema::create('failed_jobs', function (Blueprint $table) { + $table->id(); + $table->string('uuid')->unique(); + $table->text('connection'); + $table->text('queue'); + $table->longText('payload'); + $table->longText('exception'); + $table->timestamp('failed_at')->useCurrent(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('jobs'); + Schema::dropIfExists('job_batches'); + Schema::dropIfExists('failed_jobs'); + } +}; diff --git a/database/migrations/2026_07_06_164330_create_conversion_histories_table.php b/database/migrations/2026_07_06_164330_create_conversion_histories_table.php new file mode 100644 index 0000000..4f36247 --- /dev/null +++ b/database/migrations/2026_07_06_164330_create_conversion_histories_table.php @@ -0,0 +1,51 @@ +id(); + $table->string('code')->unique()->nullable(); + $table->text('original_url'); + $table->text('affiliate_url')->nullable(); + $table->string('converter_type')->comment('manual, public_web, zalo_bot'); + $table->string('session_name')->nullable(); + $table->string('status')->default('success')->comment('success, failed'); + $table->unsignedInteger('clicks')->default(0); + $table->text('error_message')->nullable(); + $table->decimal('execution_time', 8, 4)->default(0); + + // Zalo thread attribution + $table->string('zalo_thread_id')->nullable(); + $table->string('zalo_chat_name')->nullable(); + + // Product info + $table->string('product_title')->nullable(); + $table->string('product_image')->nullable(); + $table->decimal('product_price', 15, 2)->default(0.00); + $table->decimal('estimated_commission', 15, 2)->default(0.00); + + // Customer attribution + $table->string('customer_name')->nullable(); + $table->string('customer_phone')->nullable(); + + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('conversion_histories'); + } +}; diff --git a/database/migrations/2026_07_06_164330_create_settings_table.php b/database/migrations/2026_07_06_164330_create_settings_table.php new file mode 100644 index 0000000..f265db9 --- /dev/null +++ b/database/migrations/2026_07_06_164330_create_settings_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('key')->unique(); + $table->text('value')->nullable(); + $table->string('type')->default('string')->comment('string, boolean, integer, json'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('settings'); + } +}; diff --git a/database/migrations/2026_07_11_000002_create_zalo_channels_table.php b/database/migrations/2026_07_11_000002_create_zalo_channels_table.php new file mode 100644 index 0000000..4007d43 --- /dev/null +++ b/database/migrations/2026_07_11_000002_create_zalo_channels_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('thread_id')->unique(); + $table->string('name')->nullable(); + $table->boolean('is_allowed')->default(true); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('zalo_channels'); + } +}; diff --git a/database/migrations/2026_07_11_000004_create_zalo_discovered_groups_table.php b/database/migrations/2026_07_11_000004_create_zalo_discovered_groups_table.php new file mode 100644 index 0000000..9d5eee0 --- /dev/null +++ b/database/migrations/2026_07_11_000004_create_zalo_discovered_groups_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('group_id')->unique(); + $table->string('name'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('zalo_discovered_groups'); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php new file mode 100644 index 0000000..6b901f8 --- /dev/null +++ b/database/seeders/DatabaseSeeder.php @@ -0,0 +1,25 @@ +create(); + + User::factory()->create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + } +} diff --git a/debug_after_click.png b/debug_after_click.png new file mode 100644 index 0000000000000000000000000000000000000000..ada8f3ae5d8b0c0190724d776aa533937e13f788 GIT binary patch literal 98621 zcmeFZXH-*N6ef(X1sg=Mpwd)CP@07%B~cI&5wOuqq)3q_y(Y0CA_4*eN{fJk(jkNv zNI*&`LJ*_|2+{&1p(KzH(!QYYJL~&7KW5FWHEZqa1PrfVdk~UA=7g4c5v>R;bS}L6ad4r1 z)ft;z$KhiwFAtRE4xh>1)_8;Ot@hhz~U#4#hAQK~uOVFwqgkTR6z|KlQ7 z+@E}YRV*InGg?)=oln))H92rp>+h3*09|04%D>MKO%GiCuL^y~|Ni3Zivp9#qAS65 zR$69IP7KwEK36@r9Fh8$rbg}oq!)=_!+phvJG+(yubFDe`YXQdSaW( z)1l9EWA29V!cxdJXng$GI}FWEb1!6Rjh)a6<1EkQ|Jxf_;vYAGQp5CRE;Kq_#&L-^ zrkqDu&7@&xn<%hVQ_lS^Db9AmKm9(%Xe#LLo`1$4xH7xA@*hXZ}kwFdx8S2_|HH3 zO`%h*>Q9F13k!9!_)HT1`#t=Xz==j^i|3_3uZ`;4_-rENwAcKd2mM6Mfqyn!$_(87 z{FegOk;?TCk04<|n;oXM6sx}-T-YY`5cDQ~BE&ddqBff~4Wblg$n2)?1Ehd?Q!xw! zSabEe%-cX_^r{bcaY;Rq(yxv|h7eJ64vcwqnAyZv+B8TJJNdV>740py74|J}^t8g( zFRFLN9O`%-KX%fgk}Vy*GKazt8Wbw3nI4cOvcDHdNHLm5HQ+V=D-I|4;v7;;U7*o< zH2aQ7B4BgBW;o4eyi0XMo!7UV&-2H~9j}JG*n zo;J4|ECFtoEHM|O1lMRmf)FKuf`9AUi}1O_`l)XFpx0-mKv_T|9>JH6zx{-SItmJu zUK<#~$bn*l$ENMgXs=@BcNP96Zsii6xZ!;Jh~0c?pY=4UrByt>SW@L5I)(!RxZRkD z0qmce^+B;PlEKh2^Cu-qSYRdbPSdtYRl~mD-N7*46owl-F2!4z%3MCdnJYB`G50VY z&+`SjGwTr#&zpkZI;P0ty@H&CMt@%&us#G zP(JJnC+$rPZ_$Zb1g7_n*j6cLLz|>OVo(H1j5rPHvxh&a$-S9UEH5H7U`+}*J;6{D z6sU2zi?0$Epi4=$qBqn;vU)7`tt}LssT#UetDv0lj`0|`xfY6+8mS4v>fmti1$lGe zPJG8jZJxxVY558}rh>ADnIit?TOgs&l|YTd@yHdi1j>@&qsv$B4pn>+FA#4;dj1(Y zGQx$F#rU;kynx|QTGPj%m$}7K5}a3fICj^hjV<*VAfjrRLNPu92J8@qz^I|#R>k(^hQ|I+Mb?K9g>71K!*SP0+?062!8Ff_ly&x%HDoHRi z@>k+aConfsCbSo%q_t|(DOts3#&=4KY#e3q>%zFar7;?4bNapDqiJT-ZOIMr>_J}B zqo{^p9;lAD;o3JuIEUYmP9PBV2cXqGe$E)1P;=p{uI2FRFSu{PJ|n`xZ13Pd42>Xd zj^l2*bWgq)i1baK*J;A3+`pE?|K!_sC-7?q3K1wD#Ghh_RNn51>f3u z9w$0tSuxJVadJ?*pk>zF*&jS##(X9GY0%(kc{nf(n5>X=M zLp{}Ns?yYj6wsz1w@GxY*z=s=oROM+TMAzy8mrGnKaz!Wo2H%t=;U~ul$<17d!V*s zPR%6i1R=nQm_|RpZ4FS#+bA?5Q0T+oRy)MBhEjm0aXejy1yna4{11Z#cXT_^Xzz4T zSAcNlj7f4t5DUz{5AO@I|6;udj8Z1=2=WS{A zwErsIppdunk+~}u&V05WK9R#?|0q?Ve^4^o$cAA!2%pt>ANJrk;?jeD;$ltVGQ$+I zC4oMqTd#bqcq1^-pwLVLvEIDzH<8lf=!hA?aak1p5^(h3dweLtepG_beBbL+5Xq&9 zNj>;a(5Oc>kjPm7xY)16#DWg?(U!R*Yl8+PT$Z0eS*qpB1C79S>QO8$={s7;i9Pmt zoG<5KKo)s}46$U-`-IRAP zoM2&r!TZoAD9a-{#u3v~rEG4=p85O?R>NY8fw|O*$FW6d8jQ*+1O?@CxZA~+7#7^0 z$`9a>rE53Q5xiv?#)#yaVn#R$We$hp9?*G>v2{uC(5{rF880J1#QK}!DVwj;+smqV zf7%v-SiSsR`2)SDp}s5-J^Fiz1D-Cik3e{cU!7=3VlFFl4Z(eXW$W|(bzf1)vX=#f zivrbzF<})ORcn-zEZ)K(xE<2a7RN2nq8?34? zEa(#sjKvcgU#_!(Ix^_fIIcH~9{+L|K*EyS&}oOTfn`rKVEv{uKD;j-uApf&%L|oN zwatsMZ(OHTaNA089N!lL*QcV3mBY}B2m_z77?Wt`sfN!oEOwhkOe>Kjv;=)Z{U%5i zwU)l9;y!FLhwbGU@W^7HDOF#DePOv?)R4gT z`nd{D8{146kV5$(=I25$L7n^x!_RG7^P+LE>X;5r$9*S8)rd4=jcEa$8tp9FHaVNS z{Y0Zj-DpU$lp#R<=u{NCOE-v{xa%t<@D)OTUuj6E z^7i?x)GBq4{4CghYIKA(MLlbo{)Rix%pxAFC)~5R&%R-^6|@o(RffGxwF3u;NLQvJ z2}Cnmg@ElKlZCDFCh*cJ!5BtEH)nQZtn>jER(2AyYbEtLpGO|?X9^D4xIbA1LvBya z@uRXzFtXICaOYO^27cGu5Fqk%bHBCU@9~3Wr73g=U&a?@A34E=;0or_G6S`)^&X^| z?uK@R13zTB&O@CDlL}JIH{+eM>!|g+)Ck;`FSDOc!I`%GQQ~tA%gk$x1%d>S(Ztk+ zp#}AFh+iy9i**eW<3XxfJZ6hD#Y_#K{MN&)-Kflir}hLAdNPbnzP~i+BQ5gJO6rTf z!UC)Ze(UF)3{9|V!Wn$0D53}cX@2S=smtU6KUlFlUXjGCr!8%B2rU&=z=rq&)54OI7T2gB$GJ{KW$JMA z)(B{?Arvo&h!q!L&z^j`YsDI=C7oh9DBC)uu@Qk37Lr=%G~oxKKbIc|Cq%aND@#M@ zGrL83>zMQi>LGrtG9UE`62N^<`y~vT8+vbDR_C;ILgI_MBr}xG ze?W5>i|IZnKM;d6xyh-5^L2Ma)+a6FgN{E5P{*Svk{G1Y4!*38AvJT_NHD72;j7y> zx(;sb86NUh&5n8d-0WlvrB2g+`XhomM^sj6mp#17Ew$F4vsO(TCJWgJ3!_GL0*6B_ za_$B$KohF@>L9RE?6Q$vecK0p>jB61`VRp*;4I&U$&cEZ`VM%xcyJopcPU>oN^r&U!00JR=T@%*0x);Jxg~pu9B0jL{4H5Yyg%EA; z+xRMKSllt+|F8g8-l2b4`84(Xo723@^tt#R_>+Ij1nRHT-i2me&ZmJYz2q?)@PGGZ z0#8%jf_Ew2;|X?TPHW`B{wyB9%}Ryc-KvC5URplxE$F{O`zp88fGiEx6}P`TSbn6| zg+xV42VAXwwd(rsNR9F;%2OddJ1TjRSKR(9GeU;9Ft2P|TjC1Mefqmq5fD(uYdf1n zr~mg_n$xvyjV86_F1D`8WR%}OY5a}Q->b39Uw<+Kz0v>gyFk5m`G0gh1pJ>x82%4{ z8vk#|KXUND9$Vt0MFIk4>RZ@{{k|MIKmOal7OV7xi0h>4;u}o;%ujx4>Cr9Od}=Xs zLeI6r{UIha;e99rZ2A39;pr)!C|{66MzVON_t;%WR;(H9mXG`SxXa`t>8HE+Up@x$ z!ha1w1y@EZv^>zG%lsZ|f*x$CYrQz_JyRbV+64M%*rFswp=+9}TuQhKm3^_*?)Zm4 z%{xlk)8M@R1g-6*sU*A?v^KH0*fcaoA%YkNqLd@d3Zmq>Kj~yKN)SzqKMKZjSE-_^s|r@NXVe_WRH*pt|w2Ktz86 zX4C@J(c&e$_2K%Kvse+a^^(vPoJ{Xo!c1DQ$N60~s-FJC6ZewcpLc(H=3~xin* z{X0iA(W2#_jl3o>pSMpf{&GhQWxZYDP(q`6HPPY;8QRI`#iZD&zw0vpawocWHJI;1 zCzJm!RYy?%-81(a)h}`@w)mp^jsLe%UQc0X#QmvKK4jA@T3ZbS$b0^nJ@P&P zdYL{M1q%D#pbbDR^Qq?J#8PZ?r>7G*AVP3z_@uqWj=`phDCmq6PQsraD}EXGQ53q; zkO~iJy7rKOSe=~Jv9${IC7(CV+-T-4EOoKC$xiCaVOR##Z-`|N(a=;08P0;&Pt}6L zaI@1v!2}L_n!6tE&HE;p5kAii-pG0psRLwA;AhVm z1#s?jCrgV?*XAgmc@X)*qLjCTPwB?o9|0)ijcqQ)TOPzxstK&8D58^8UHFi{Nc;qZ zmno$+2U$d;fKZ>;*N{7y6Hd#pUJz}P6+h1Ue!Mb#{sjZLhI3VhZEzXnTX##TzXk}u zv{&w9B8KwG-@qv18}7R+5~17;9jGW^g4W29BCIDsIg%v8ZY>b~zVZR`1fQAnJ>zy2 zBgw_m)TUxs^D+yKU4oeOvRA{G1AluV3DeBuYg(WpczbO)lrmgS%vcoV9u9`B&_|*- zhAC3@>07o|Amrd58^%gF>KlRL`r%4-syCS%QoxlJI|heLF1O(|=@6DA!)~KAOxQoS z10XDj)W=9f+OQ-lM=fm50C;pX$p^x~@m`0|KLcs6PMO+qj2loByoBBZ)E;=tY=OnUS=HFcNDO+g6>@+qjEpib=EkTvie;GZB3LBEx3J4oj9r<_}-@web81V90 zGUW}+9PAQrl7D;VB*hn^d}v4tkK2xogUknUrpdLUhAH5MRa=g6>B73HMAC;ahIBO{ zG&S6lE9(^mT@qfd!#3;yKvtIUppCuuJdrUdw)pQre+=MounBuJ{0yamI0R%b1=ndw zqBs-quw~TTqZ4rUEK3SaLYwLw*egHg|0=Zjs1xACDf>0!($?;3yN_?B!pWzIbEj69 zGBM)84ZJ3g!tWaN-e%MUeYW=}8P&0+a8Et-c5ZnHpg%iz`KQT@Aml-f}p9Vsgbuc9(6>%b9`x`j*z?WmpCHTM*`UH)H*lq1J#>Y&HjXRa+^e5J= zM-pEF*biPOb6zvp-{R|eC4$h$(69Xd@+E6X91x6wTpCR|nvp35;joq?#z2C6_=E{G(*D|a*v(I&%iEVqSX^Q-$n^#z zQ;Itrul;0Ma2dMng$1&E0H6)7Q!wur1u%Shi^=ihp^OG8*v&%qfNzaj6XC3SA!ah& znhbneh+a@#o?Ze-us)zT_Lz7d%raUkbe=onyxI+7HojQOLb09oNTXd;XR{xjP!)=PlusdH#X@=p8uX+ko3<@C^Ml_^AY|vCZyRm=8+zv--md(0p<68l{;$~F zCj4QnqlbqFKNL*Ok=sHU?2rEqf}4Kk8c00#QR2rJTk2i9|H#(Yt?PekKl^|0*8dOF z$YNmV{N15Zm~F;&v&(kzZ_J3)Dlc37qN%8U0{3<9O|{31XX9oqAlF2&Rr+GJHzhsA zLW`1%Z8$z0Q|B2wYsgKhgl^Aj`g`uFw1y~;(X(*@LxFarLHc{pO-yQ?y9+CZ+=))O z{vQ_5n|4#!ico)0$?tc=30bX_h7nXt&}Vv$L{$AXMX765YX+yIW*GAUrreuO;dgTl z(%bQTn@&dH#Yk86PsfwAZa{~)>=D7f%Q8L^BO_&;&ZYr6bLPYBp-S#ait)OEvsin1 zo8c7hE%~R(CvA}^+~BBSwQ07`c^^gaONcY)y|GxnuiXGwfO72n$Nus5Lc5Uryz{?7 zo+7QWlw0;w7%LqyC2whthTnrQ&&^tA{4g+IJG;~?19Y6~%Aq4vlKQnXQxcX4CjR~H z*o4#}vs{CNOy2NLM=6`Cp=M$5nEa+(t)fEL^{v15UzRXS*|CN63mZc!sM&RsLFf zydx`!&8qxKK5v{jvy7RhY{@cf`&P3ww!AexW#6q^^DkO3t9-fuiiow5 zPhTq2j31vFwLVQwR2Y~atuT`6I_sX}>mY*Xo;hn`gSU*_uR|rArI$sdpxgXc6#)mDeoWJY#;A= zCz$|%>Up^$T>prlVM$?0+{@2ii8l<>Zj}`Her~M}Vrxc=?=pjAjQq&+wX+%c z;(0&$MC4iMWynVW&WT0VT*S}!G@mI#Uy6><^_Ct+&ZgHr(guXuq~?9oPw}-4VE0zz z?sOIWIzHc~YY8&*I9{#KL!QZUFUoBR>sjZppZGgaTe-w%&G1vCgm@+vwH>bRshtozDFV0&GU0)?{w}uwyj!~l%TbRAILJlkJ z=F!hV6_o*>ydoC8M1Og{s|h?M@1y#qdby{HdOTtp^HDAX^#pcuzcjvtA|JD^WT1sg zI>?NG0Jl*}>n;dMc&EMGO;`%q@IMD=Kc1pEJL?yJDit#L=v?Z<8r7VrDcMy>pHC7E zK_jyR>NAd~*PF~{w9r2KK_K_l|7g*!zglz&(0ArBDS+j$fAD$xg|xAk2S!e78b`@I zd4Ce=9T+i;ttj7FouXj95ZT(VmOA>wU!S1pfcRmKbm+*FN=8bkqt%<3J^M4S$LYC{ z5zC|M(Bb9S*seB*DUB*%)Y-mKLEbgpYu~lGRYUDDg>}&~w+A%FffeX@Ro&r)cGov2 zSRXWf6diJt=B?uH`+0RJIf3N8ypDzKNKr8Gb!+SG)r`KUnERSk_ukI9D|$yu^Xkn$ z++*ubl#+5OT~xH7Aj2fj@1I8mV9o6cg_zt9HIs@rq*?u@&&r9i3A z8B}1(VOD(da65wcnciUerEOLOprryo6m@$P1~|GO3pLlcokm&-{IC%C`!K6K1Qa## zqo)vpQ9COh^|mG<#5%4|Qz>GzNaiH;PTgvz3=md*(q28`fcnSCUhcV=TD;Zt8$!9% zjTD@7@VN+lYrRbiI4J@7;)nN}m%CyQB;fV$S{X$nI_PrA`>mljK6>BpzEL}y_>Pyj ztc&3sxQagzet615=SrYV^(l7fnrKT0{alsz3m4?HqOiU&_wl=r}2#R+%c z)AJKgQ#{kKzU-ac6dl>Fl(rtMl1&LVzap{sY+5M8w_Qf>XfamjW1Pa9%5!tQOAd$< zYbo)9BY8>X*D;$x#u5eEm3q?2@!ukkLCIR>dVL)ZhA+hoU-zpds4Epx`!<K3NixD{nfNx5JU6f7Hdsx+a8(sn!N8{E!Co zI!F4kvn@wMe=Y>AM>y*%Tnjjz9*~kE8Yf=MZER}JG%<*)J})DpY=hc%2XB=oSo5>U zsfDm_x8A&i?Rb2p?B=?aQw2yl`}HVXKK(2mGMpWtxnt-kGYUwN8#SAupb9u2S3AhF zawA|tFS!oy?-$CK9sue-Moz0ukV_GFKvOa1IZV8je-}A~EfF_EMK>E|#y2-}1PHSd zQDSlqGHW$^*87p%yR~&LVdS+9>q+sTV5lF78ES|LQFmdv#O^zieppuyIkn{ltLmX1YQSgp;Y(jgGU>_DQw zO>^YgO2d4VoP%Sr85-%_8C!ZMPH*!ZYDh5Y_JmTBowK_$vONJAZ>gj2vAy>0{HrI{ zw@*bsu``aslZZW~ncDu3ot&oGkuf4hqWV86jGjz8yd@Ym?iHMIr8;QgdnDec_BVzz zL}2o`QM`2&nz77omV#R38^#Y^;g26E8E(K)(|yWe=Cy!!%5tk?8KEfbZed7LzCaAt zDxBLLe8^>=>E^6d`hgRyk)=Viz>i;Q`_tvBlpbk;t1e{4#;DUUC%FadV(nJRq%&jZ z$}J%(l8i7r{yz38yaJNkaylBoRMycsbIS1?wr_A1hru0pP))yri( z8cTlp>n?eEysoO^pan~FH!3R3#Qgff2)r;5_Bl1 zxZqw;-gdGzXnZ5(37C*ws5*MGHu=rVpeOL1xLX!Ea>ioe*u3K0J1&lg=7T&Of%#)~ zBXuv!mmTApDR1xWFClzV`@GQ<0WQBdeVJ%wiln`uZ6U$G%^3s{S8SX=@Z`d~mvwkjN4TQW zT9H7VA097~6O78-=iyp4s4RIUB4oNR?EX+!S68AmV3$^^lAT7#6IIi3-O_3_`s3ME zXO$mX}*NbdJ4GNJ&f7p4)h`Azm{s=0S4hhk(@ zc-Qu}>>;Bl>Dry|T--_iA^X5yXF{uH9OiGWZf`aIU_~cfb!O~x*{2)yro_|U+*<#V zm`{A*OY7#PVT-(ZcrpA6)wtW?z4d93V9HKDtJyj+_-|2PJ}E}-7{*2#J{T(2N3KSkcpxVE zT`s_~MQN|G#OU3hD(H+Mb9n!mK1ny5!tcF`w#Uqbzb*McHzeE;?>wZ-^nU*tc*sW~ z!9*pNE?toJZqV$JN29y{bMVd;zv<@`nbq~~LE3?CP(dW2%J0(=OMDNd)r<1I!Y=^{ z+t?ALMmk{~9aI0#IaFm>J80@-eipC_(SXo7_I`S`t!;2|k?M$1Kj$&h6d99B%|X=H zs7RWoRoL3wvO80O1X9q^qjhFxizZ1ME6Le20lzK^F@Xe>!?hCwzq)O zDY~!jeBg$P;fzCO)Ij;2*clas2d5pejDGEsTM8{2j(UdPYz#ZhZgh7`6?Xao6xpvR zc=W>N_2FHfHt?sLstmTakCx51p2+JDz)dG6_dhjQDgSrTnwh%~4jpWW-HH z#Na~>r8hYR1q!L2!K{s9iMP4`VF9bM@X*EKw!y)ko+sfR_k-_w=t35MEr|KlUkl2b zTWHdY%AfxIL`5#YUq!L1x>_j%#K==e|4vEwdH+I!yg%h=>Ly1&w7=iAM?&Mtoe3v@ z&Q$CWSlJ+9mWjwmZ?1LF)W`ksB=6A7GadV4IQj4}OF8@cPWt z)shbLLR26v49|2f_qqHe(B`r3v9>Q=71Zrt(V%NX&uL91=8HY&gL6j?7cBRdrNy$ic31b?s?o#2~@VTWOb&3z;U~VBrLD2l2>V>gB%f9 zmyywUj&$kx=m;=u<7RFG1W#Ju)qJ;lC`nz+%TPq;4OKjPQxpxF?<%o6{knZT zJi1r%uTUv%G%_-?`Z%_(-SMtPV9IB;JaTI4n#2*b4$9XdQ9I(%Xs<*y?GxtP36$gs z6xM;@PKvoqcI?F;_f3&GAw-%%F6Gc!`=znvN1s|6N8vI#10uryRW~Qe^k>TF00X_~ zsu46qomJxMA*N>CbK2&N6*;y0eE_QJXE^U%!2SrdfTIdH7O|Ru0KH`fJ|bxjD*oA{ zLK7nLc>XSgwKy&Q5CfkF$0>5 z12I>hn4b+fzFHKkDPGpi2Tdvw*GAt3v*Pw-{*$E)Kc=1%kM%tt>UR34N8&HdjSPbl z=-f9fk8BF^-~2J+r`bTG4|RCN!-4*sKm!Z&qthxqT1>I!kn!IyqRw=ddKh{k3!E=y zntwU-as56v&aB_CI^F2@7}&aVWbd@Qb(m6wG9x%D#cbS;F){%I}rrPsy^8? z)A$2vC_Co9^+PGE7-_4P}vlCs`Is{`G$yV7MR{JhK^)Nl%+e^PANc%X}a4~wC7q5W9 znCJGkh#1g>Q%At@Ba1QFt*sWB^}p#uD2o>n*_w65vU2PUp6VE9D~n3``JSy@3P{VF zFxA*!cYCXZ5&44|4=-j)(SFqg9VL%;Dfq1U_YdYAVC}#1#^tWhSL~D2{I8Izg+nuC zp<*}UACav6b%dS=3N;M>LmVv?)Cm8w??nk6ekSg`SdPh@uYW*j(15wQPf zLQy{7#z)_NDj*SF6+T^WBLRk8kAu?4b|#JS4Jfk=@-CN_R2R-?daLOyf-=rI=z5D^GIu zJ2@WNs*ZO5Qk4JboWZb|=`O1jFE3#wyE+Z={TMa@Q&V0Wy7o#;SPFRFru|!Dx)7MR znVWbkJ}NiQs%CahOs1GHI{dzx#0dBB5PgJbjuM7z)~YFDeZu-P!5au%7TAV`_X#(! zKb-sfj_CgPuzjY1BUd{3VL4K~*BTXPebNcp8uSar62O zKaZa=#H-L$S+?`ZSp-qHT&sfyyCc@WzbpMEh=$q&_pVF%%@tpg>8NlELg=PmTpKuv z#6zky{ z{J;g$i!Rvo>#8)tvI;!Z#jt$buo3zj~%w;9leL!hsD=Fr&Yr=lnQB2{rLO27 zG?nf!;!uxru|ie^{UdKfiVIq1hl8GQgw%z0>AA*i+YA>x^)Sf$lB9*1qC*{AduV~$ z7Oab<{d{N`7(5={t9-iqp44`1G!hnd+j5^)QEW3q#$%W~^z|)gzOwZGs&a-9eYEb` zW`oLL>*<5FLIz#wYKHHxBaE=rDY>FM3r2dn*Ip^(dqFDDs}lgbY6sQpqH$WDg%``E z`Ua^>b*tf3iPQ^6OVv+3#z4%>H4k{@j#{_%sr}B1&Tvz_I3)UcvxcVE`~Sxz9i#o) zVZ`pn#Ka!W0EmJF^Tx|NUcH(&CzVuw-!Py2)Q_|tyI4pr3naLZkj#4v7v5C+{82zo!|ze8GKuwi*KvI@$s-} z!@!l5-yP2N_4OArAH+v+5=?bAK3>kp&FQO&n^5cNJBKQo6_#%o7GzA=T0FA<+7Z%6 z3Y@(^qwm+HXdoKaKq>xh(pTc+Ne2{JHw9H9kgJU_E@hd;Uu>4xMCIjUqo4f6qWq%U z^Xk_R8=hP;QWJ??5VP4Hu?~iNok`K@;z_3$6Ar&e(qNuDURK zwm-1#%4$4TNddaxqJNT>8Wn!bg!Rb-O#Ast7eKUCDgEWPriJwA2(J1edcV?PMq|gc z(io=fs3?A-z;5)`Qkk0*a=d=Gk@8|)l(FZ&<7&T8`y#$E^MsHW!ZbYxu8GclO7G%G z@=f`$Y)+SaI{#tv{3uZ&b7=FP?H-}PSuIv=Ma7i85O{O6*}ICK5gET36S%&4bh2zN z9p}#h5SaMkva(43ShzcKM`^U;qe{2Zb+cONrBPhc;uKW#E{P>I>Q?pmQ(LI(Yo;GFhUTTizgpeMc=O}I1lN+qc2`iXoIyB zl--_C%mxz|@jC{N3(&qYIy`#CZ{=ai7pjtewOoEu(?f+lR9%cRmiMC{=k0B)?Z5bI z)iutvYxQ2KR#po1hn1tF#Ijc!e|sS>7MmB-)kWZp6V~g7#`|pMm6eqTjPWGJ>t08& z3qG7V9|+TkpPwJ3sb8*hY~vYNYg;VY>r&#^Ff+;b&7^>^eK9dz^76qGp~S^!vkL)z zYLAX0AK3+0=w2Fkr=0zQda~+hrXFLo&s~JGUJV`Mtqk#8tjuFGe+NmjIvHl2=6)x= zuqpQ{-#o%R0jqeZ$FaS(d1(ARvVVHG?OCn{V$WQGP=9N-^+;+oUMHsgv9&JIaHG$q ze+^+3(h!nUv%XVOO*nIy+ssd;U%F7gWFehlS3@rp{~YU%A6nEESt@;|W_tk9_e6BG zgc4Iy{P4QynW9@)cqcH`*?w)J=t}hK<`J8hnt+&s<`zhJXxf<6B!Kf`*}wEvY^;#Z z2~_@R5Yf0dPI$|)d$j#Y*aKeja1&myK?v&IarOOT`X+FGAP*>(emU@zNLI4le7%3W zyjR0jl6vnu&9^#H+ss2PMNDlz^`I`l7YF1FJH@x(Po&S) zir;jU8kyA}TnIqvyE-@+0;k+GfU9JLDUjKcWD2|@Vd@MBO}W)h@>Hu&I;weF5&QmZ z5WB8#l0G*m#rY{qVD?~WDb@9le0_h9MH&@`a_5`lc}>flrjg68n++z}LO;88G3r?+ zvxj13lj?6GQMHF+v4=7nV)5?eL1kel3&?_z4S}XZkRF-o?5oJ=Zt8KlGI3mZmsV~; z?7oro>qIMYi$}~6Q{L*gLpW|DfG0(2Pk!`G^@O3LP8YIu%rML4XMKBZrc4I94Udl3 zC?BC$8Lq9lH@%4kcsx`f+TayDEiLa8E#;F`%c?XNRvzgi8ZqBEEtNagq9tEU99y~K zFCt?+*3tvsP76Qn@NyhrT#Y(w#l9I%j`}9e^64t&ghiqWt-6$VwNa%6JEd3jSP8>4 z%dzo|m?2!WY9=gYa%;rlu#*0T z8jI!yq(7y8@%xjPtiFp;;e*S);0R?QnSs?RbmT+ zF}j@SUT0PPs@O<0=f+6+j@(o6bnNVq;{GE8-DDZf8inw|U3=t{Q$7zyy*cIjwz;YH z&Qvzf>q|p10V5S#wJ>C9aqxChfjDGV9uAvZ$d{e|CKRCV_pZU)_0mU^u5aw#fkV^t zzZUuv7lE7Y(lGWn5HOs6+iJj2L3zj|-cWU5mpkjpdZqOuqhBR01qrw+(;H{!Pn}t4 zdbpP718XMvg!6w%y0M+d1aX#=R^^OTzozIM`yu-u7T}bA`)sn}vk%UOd1k-7(q{dJ zlNPQ^78N|caIAe-qM6a6j=1m)q62GXzX%TAcpC9m+CaEVR>#lnTUrWH$vfjpcphQ7 z3nj(Rb=v%56x_hSD0?@0J{L4zg}PVUiq?@CptC zjN|CttlCh!!ArFfcQ-U_WMerO7h0;tEk&3Gt8NxLHD7SvDYgbm0dL#oXT?^F2YqTd zYK+In;<2=E#84}>Lw^#L_x!oBZmNJ$%Ji;vW{{mIZtit*_nXb%!z~4SJY(wy9o;}4 z;+uO%ANmWWc7w!i5YR6pS9DJ3$ScLmdCwoN7 z>`hibNBu5k?6vRMD|5##l|X&1V#nSn-Rzf<<0ACOUmy3^4C+xdGb1hxZ}fvWKG>{? zOFwN<6h`>;&#TW}MyiHLh60Mq$lBT~om6FBYihOHpt4>4jBT;m9^-z>O!Sw?Z<671 zpG@8qJ+36^CeFyYizxbhEsm|@E`!-@H%)6hd+wMkP`)&Id$MAZHiL0w=4N3Pec$Ca z6QXBfUU|s)5i5I{*ur#wVo$KvxPQKht6_!j!c;=Dps1+mY$e6hyMCc($mkz?(|AI} zTH~MzP$IUkem*dq*psoT4Bs#X@v~25(q`0NV+u$q|0jIaNa)QuCLv6vDd#V$&CERby~!c> zMaISAoz#p=)fG>GRD7J)vz2R0IEU+b z2+TtTg0TOR!)(`uZ#wB*#`y8U(~@n~kSlMsl?e}X?M4y+3eWt}lcLdujD~fhCl4g!nVT>o*Hp^V^$17we7o3Qgepy<19H}8aTM1VAN+>fz#-Wu|2)enU_6Xkl9&ld`P0kB<(fg&k2htx*l3o~zJid6*(WbKx{MPT}sF%dq zwDrgyK-ZA5+gsu4OBv?YQOLcn&4WSW#)nRP9-kegx=mp^>`b2;e7&O?=(C!>*Rx_HnD0@5MsSI;iz+>v>tnrn;Z;^NvJnVj`2 zmEeaZ;{&3eF_W#(6ufT7opWT1Mx&xBy{U(xYB&TAx{2Xu6*!41dj-9zpFd2!m|B7Y znk24%6(`>oWp!aqK&!oa03Tax!g0@1AJ2B;EyRPq$0K<|q%M?MN>}H%cWYKznI=Z? zyPLZo#C8zj?M;YQW{0%>Am(eKrKse@F_rqC`sr?-&)2#j5vX=8h0MgS&cT zy7wN()*oW-H%trKt1cc}a49RU4F`loXlI@^^drSa`P8h|#jaBZDi-H5=;(HzfpziF8w-qBks zRGf);ENZaZKaihBK1_{t@2)PK)t;YZ{zBe2{EYwlPGFQ!@PM}F5FjDtVDAI z=p$HiRRIo%(=;PmYY`4Cx!ccK?mj{z=`I#00b6?g?9b6QY&AFU1j=x6=+*jmG0c0o zhpUyt=jdXj<;$Jhz2Y<~&I)6a9>nY`k{ZS0j;_im(fO%ZF-V+B;8{yq8`8T|*3h8` zDJMuC_!^=0-95N3qZt)#NMm=O0>$s;vsu}iqrlgJ;To7k$HI=uqS;e#6jZ7W5{FH3 zoxXGWtH168K!N0PKWoV=er_7#s%B<0wGm$jzHmpGMmFjA&@||57kGSR;{RjnJ>#0n z+VAg~(UDOE6%>>@bd{z^uQT)-M5KgJq!S>ahYq(QO$4L`DFLaG5=uf62u*s4)IflQ zBE5@rLi5SobN`;t|5eWG>~r>Y?RBm7-RTeOa^L&vMHFeWxb~%lHqSbhI}VyXYQR+F zI4S3)6P7-OeUUdHm6t8$nv>#7N1e+=&?7&r@c2o&A)(R4Ju$40C$~tZx^93CNs z=#77u)?4lIF#logt%aUMOyTF!5ZOIt-ejlafLvkri9wa-VYQGSUrG)W#Wvli{GI`= z9s+W0(oTX3<{mlc1CQ2!9+gF&R9$JFbx=TT;GuKh&fmr|GtGVBM@orzhlCbniBGe$ zonm$alr}R4oIwRT_hp!Ue3o3_h3h1Eip+)8Grc+%3)`ChdYVlI^6Gr{9#L>VTRHqw z8Zu$EQ;xfYf*w8n+NU%(?BEl$=wXR&`ham=k7NOFd1YZ|%Hpg)jwQKf{0YUO7rr|` zrOH|x4APdL7SXh}P5l};(q`IJ=v(&@)8o;9e(oUJP@-zl?pVfssb4oQnXYtY^THaN zZSk&URkHFunEoW-2^-vl6kE45$&-E0?QQYo4K``*O3-zCDrMA=D!sdWD?*|3Nx?=> zdB;chXCC=~7`q4S-g8%RNF2CukHx9xVP0=M>Du0m)9}3?-SP+GRbtxy>d^Vrs%rS| zLWyHf62!Ao@}N-*ZV;z@pE*_fL1K4W-$_a=uVVPdQoO4%z0q}foK=dr)dx{R6prYI zJig;!rWcat3Y2Jb)p_O~Y(6+ccW8;2Cb%O4jF7-QqU(^99+EWgrp&?YEE3P-C#Y0w zdRJf6KNrLjsrLh0FOY30y!We+lEgb@1OGRc#-B*LpgwTp3{>G!AnqD4H#cY_Ywl-< z+U2Q$v7{KPSWBYpz(FpU$O%;;G<^W)a$5uhuN?FlU$pHAn|yRUYMwkw&MSYiGHn?j z&y==`uoe0{MCNede!(AI(PuY&i_65t9#AhYfD>`J@)djk#TS`(A?b3M2A7{QF-#H%JPrwq7V@``ACF$11V zgOltYx?{Wp2}4CS8_sc40-5e-u$TRTc5qyC^wMB;+@w5xb+udcjE`QVPDh2H$+)zWmttQJG9CEa(7L-s-lygv6 zTL(2ghzz5T+sdI&adRiTm?lQ}#!nt|RxT|Jn9`fAw4^qejnv?-k<_aR9M!&KbQ58B ztv1o+S@mEw0XAcDf;rJTVblRIuguNcs*DevUe zZ(MrYuccSEyaHWITkeGZ(pexp)gp!TGYyA@{QNGx|E8 z#QZmiI;pcl%M(Up;;0;ap5VU{?}$s~F=bf|_;8VrF#Nyeyf#voVx#G~+6}#utR1my zh35!G6@*W$yv78RFtQh?kCQ(${k_~N&8A#q zlxqA7wf!xPjp3)WI5>2IO>rUup-&`hTSC7-YU@KQnaU(fGX2*hySmk=|# zf62B*;HBGE{?i(APJBS0kEkxJieg3U$*GLIwX`-THLb_-`8XA~au2?e=#<1ESkCRI zcs?k!9FF+mvH2PoocFV(eivYft$@?lhU+*gqM{TKFRnU6*w7v$3y8Q5xu<} zU#%b4aZoi-5|grx!>vt=q{_bLqSn{(jszeI1CPGO|GbP=%e*T$gx+5rR0%!TWD#Pa ztC+#9tg<=9fvSBLyHf&OSsTZq=2dSJ!$i9VhlN@S#S$C15Ilgg7;jI zR2H1_jZckOzE|d--4_EkU#g9+%s52$E}|2g<{ery*%2d7Ve_MerWrSR#YnJ5l7G10 zZIP*UQzRuM?3J_LENRc<;>{(=>!-OHfVF}3+m?A$-rsW(_Vbkk{F{~`x$kv4+6GVS zxQMHVb~;>DT+}b-XBdO-f!6QDlsa2Yg1uAVvoNFj<{Tz{ke5#7Yd>z^8F^-t>Q=?W zS6c_&5h=un(=IiGE4}PKUt`v=GgJ$cvt~T(4(>83uGMG$TodCp5r<8%{&^dug(s&g zsnmun)ebc{Dy+je1(RGNRa^pi?cK7=oc?LSqP6~@+s}?tYCc*oWjgL>u=6p(_|hsg zc(~0y{aS|AJ-EWE+#W4f`YG(qFw`2Cgjd%cLM@ZH^oF<3*!=w|YGpHRvY}jE6yivX z*?L$F7xmoF@p@r`s}@OhpswTCYjvfo0~XdYRDVcZp(T2XQM{gyr?sB!M9OmABoYQN z2QiyfyzgT!qFcB+>E~G2Cn2YkB)c=pgrIk>xpTI#Sy9)xRh<3nb2q7R#TEH&wg$nB zqFOc$VzB7u=W?MbNX4#GaIjwCBB6Yr-)loZVmzqTX9iH)+-xdmhNq^DS;BMqeUOqnznURJvM5X+!_YM6-TG#D{xRwm= z8}dYKth+LEtMbQUBf$HmoXP!s@5@iKT#a9nPEQ45W%1f3sST)YM)tw*-GuzJsvVjV zEA1|XRpj(~KwCGFuR4)ghvma+g=mE{>W(+{?ac|R2G$Bt);(Zd3zGWSG;BdF2N75h z=zJNf)aW{*o1JgDU+0H0aboAl+5T+|bl0~~5Q;C`nl$I|S3N%RxJPlGm$19;vsLj4 zVPtl;77SOXI*-S6T8lQM`NOI;kn|L#s>f&UQ{^S--zH0Y&ppP+?OP()P!r@|7U_F< zjTfD&_>XINEW3%ez9K)ix6#42M6s^Z_Rdz2B}WW@CA*Qn4QZ!pXhpR=yxKH~jEiVc zlbf5X9FRMITIXXuTaUB1H$n=udKN5~(Jk}N&VRBUj<@j1Z%v=(bINh{GG%b%(1rQW zaTC!DLfm=j&TwS1^7;6o0Xx0na+B}fck-#7c(muMI1>0dhjCRRH)v%_T2JT>*;49V zKRP`!)(B(RPDYO!&)BV%0IlF=Ko9kqO|}bY4;Ucc=F?O^nR%RR*gtPMTeA@m5+ZCs z`!htB@uCWIjZyDq_#rM=RpBoM2Luu};$OHq-Pe)&C@=wF@4>v1s*@>;7h@>CA&gFXar8}5TLGnQ}gnDF&o26oE&r^E?T!p`vW4Fs8HFQCw16L4tA3H_w` zuMT$OU*R+E-owq@GA8~W^IgwfyZhin2q#uEkvzH?7LwVmhqCu@7iu0fmY{aS?I<^V zWk)Jmi?+k!)jdo<7(N{hS)A;LIeO%hf3=)4*|xf#gc!sN+tn)veQ)>SDgu8S{eMsoRA z?AF92jzx-mI6+jsyJz>9mR|{`O^j@nGgq8oDO&{wSM@Eqdy4w%Cw5TP)gJJf&b=hY z1jdWJt8+%v?l&SjMmFW}40O|apU#71nCj04HChXAy^ezy(oX*&^r)@Y7>0^d@Kb!m zMfYiRvK$%CG7 z>mm#J@MvYhBi0P-P;cZnPqEAEVqQ#Ljf3yrhhwT$EwPYg>A|D?eqQy5`f(JnnRD>v za_dR^82sv1z}eoNYf-gMNur_^M4~}6;CP_{%i5FwAUS3a3WN(~Ikm|eLPWm<6?dd^ z&N4`2JI83TOc5b1gj<@gEq>&cd`lfxfI&hBQQTLT9;dKt)U}AN+!mA&lOU3OpU{Oh zx>a>z$6t~524F_S?aoILQ@tf5By~%hY9A>CHBauq8XKGrQhfq3hJ#sxV=P50!Qa&! zjad$$^Tw~>E55n(M%&)rUY>);+Gcu|!j;s`m|(EEN%ckFsuY`rZ3YByF;_}l@?KJG zbZ$wgT&`Id=PP8n1hbarUEJLB%m%tfRJ_>K(zijN503>8e!eSQTmUizI*Cw^A6j6m zn|~ZLokx?U2f_f8uG26dz0cxhcwD6>V6ej0WN-+jV;}wX`S?5$Sa(nJSiV)v#*OzD z`$r6qdrlzv!M2Ne<5Q|uXhUVu^#I-@?ZjDwxNwHJrn)^jm-A1}Tqo_L<a5kzz0Aw7P*+QMS`M@+_+o*ejU|cAQf${?gZYi} z4~*b!?1MJYdjt6*t3RO;d+pq!i<<7f|o1n4j0sQY%N{a>+0Ul zx#R~d@^9Wl^d`on#fODV<%shDjfG6Ta+F02Kj)c~ln0z*2VQ*$th>K-S`-^g3i0qT zNGibB`(F&majOKqk_Ky&Mvl+7@t5<1D~rZFKhN_cR(NOkBYBuh%ffu;KJYcTyZPXP zk2*_hOhr~jGltSiu}1vVyO@1BzRE7G*856U?BDsN1C&LLjw;M!kS;`PVe_`i--SaS zxa)GaI5rX%fVXs=e;?Mf{O}xYt<(@nYa4+ z>YT!X1|H)-Mbo-X{l^4R3gQ&bLp^*LT+IDOR<1WMO)OrWRd+j0D?U#^?G^~Hh1}1O z47Ya-FM<~3KwEt3G2%c7e!>n2v~CRo+wZQCS5`10bhm<@nR%IWBf#Qwf>0WFvM?~O zn+4wgvuotD#PaR_UBMwg1QXnv(Cf4>Z7gDz(fBYi4NP)s7!O0zAu$!=v9AtDmIW8d^#1|dO7K)oU(ti zJ`~~O=$MYAm0(HigZbN%)&1<`NyRXN*Q!3}DQrIGb;M}rBshtqG5VFAr87k0NDVf| z`Acp7O=i*<-0@7=;)*rhbP5qcF+pS7f*PStKe56;Ihr=rGxy?LPEVHyb@IeDp%=xW zobSpZmjqnleUSPSU%o_KV6s(UgO~vB`i6IdyXgCU(FdoyZgcEK6Xg-hWnLP`ksx)x z_gafBiInz(e~6W@=03flAJFJwAibKL41qfPyoQl13-P;2>K0X9V^;4yY;I({^;1>G z`QDuS>fuvd-SJ1CquXjt*UI_*x@zZP?5dy(LPlA>H4>o!*-GR9g$@qDL;MKmARAgo zTxGE(i($BKyPbHnTe&{_m9K@J>*m?723@PuCad9@(q^2VHfyA6e(l|mTugdfbW7t>E+zJJ7DfILiew{nfTS>p?AO1uP(6SaMpOz@`udtr)* z{yXVL;tYk=A2gNwwu-caQ@Mxd+y8qzg-OS}u0uetlyur2ZIISi{P100y#j3Ot>%KWO}?VvMwV;7 z9{MHpejT}JyTUZ=xsqh==kmv7S?^}QPtU$z!e8TD*TjEkOhi4@LbkKI`qcbn+n@}& zTfhdQ-z4`2T8|}$SD?a?El)LC7hWFSR+!s(A-7%0q%rZ!Sl6Rv!!gwcX!smvRya%i zKlclrK%-JzA)6L82MO0s?IYDdD0W{dQF7e&i(2}8<)`+^b5tb5=I7nUeeq}8Tm1hp zO)lI1HL)y+=;zeD0kIBk1Y@Pz!N;{RBjl2A6DODnw=b*2+wO_KQKzKc#I6@+{MI=2 z7^3&l9k;?%A+tY}DfWL_z#kgLin&zs(Wh=QDkdtiE0wIqEut8i-I=OxRZs&k-qfue z!a@c#K&=1<6C^1<{2G&P_^Fsqj&PaXm*8xobdis7Zy%`hsbS0*F}FC;Ms*`$ltQ zZE(@1;D%vi7&e|+6(3P$orFvDID7MgSBQuwS=McO{i&HL$)mO;#;)fSUtR4Et{fE* z#KD&~vf;9#UJxE!d&%^{{p9ZWY2y#YRC0Hn^DmB!?=-r(tYpMEkL9%5|7UI+u%U&nMm?goYETveF8mz8GPD_?6R)Z!Q&8SS!m{53CnM<#Gp_VcQ6-TcAUA~pGrv+y}@?g`C2K76yA;SEIL5$C3kn21 zh=r49zW+q3_qWN*TEda(Dp-QBt&+HCa9tWZ;|$cRKvb{Hg=CbrY3OHlcMAQs7wDc} zt0$P5ajs;*#@47MV!T+_`-};+C@-lv1CTS2>hrqArFa`O0K-#9;K{q1NvGf1uEgHr zS_=rV(&m%Y9W7ao1{9PKQzQF55}Jx!h2M#gd|jWU8b7)PQ*0=%P3wCJi0|yA7R{3f zVI%9kgY=3(pqpOQLiY~HN8j4J7|npy)jPS3H7)dv)TAhdVBPBfH(+{Ww4Ic!deA%3 zLf(-)nR1HsDBRN;vWL#Js5ZJ3KKW>U=0Dj`bN7=ZAYNmsqT=T1zE^8^OF-9zgEZT1 zrPgb&NT(&gur^*B6(m)Uvuu;$5(f!)tjL>l{q1hyHW2pZN`Wx*k$Fz3tpml@g_4WP z@Ye~|qr(-_fb&iNb70G-PUA_rqk^r}_seaa66ULO+E>7!Q*^DrZMEL0>p$;7%)jq} zpeEte!(-mt?3yi|Q?3)LEblAF3z+U* zZ-L99ZM5U>$xZ%M7r=X>xHjn;&taoK{UE!P`gx@ERmHa3g<_ETZ}y1M0Gn=;7dmFy zF4^uPWLq1vWVM5UsjU$mo|#Dw2}yCLYf}J1! zN%Z;U^|v<4T4^~LF|#Bk$Cx>$9ISN1X55W5B{DAc+?f7{AlfB91Vs-*P?X-sR)08hCRx|Z6#?L*$2CZREi#wWQjn}$6tTN48OpK9>Vv^_M3z^&p z7WN-s9kCm){W|fTnLCVpCp0e1H_HELt;8qIU!Tf6CCZifx1cTp2v=?gBc?dke(A`F&`+ zk~*~-t$1a_Pmxm{oBexhk?bDiI@=#qr^>|i!P3u&t2iUh39|>l<0>zMADg{Eq`FY8 z!*(cACepKVPyzR1?MXDpz-3W^BS);1!}i@OY>Wc2@-ty<7oumn7! zyQxv&YP|Q>q!0Jwq(Y3x!q?a18Ha}f*X@^|yc5gRwNO@HXwkk_`iOaQJ%r2VX=1xX}a&mxqk_Uvn zr-Du7H}3H{B4%93K?jPw5gg7YvO3rwY;6S`L@y1$UhWIZb)}tlmy$3dId0AVHX_b4 z+&5$Nas!lRD8J41Ih7||PF=h%?nU~34yNE}-6e;cULno*$^}h0z}5ca%ApHRxq_)c zUWK65MPudKh|4Wa%k28APRKbC(@w!5c?FS1tdURzj*Ns#9SbDeg`|o{1+_9 z`d0YZ z1C9uel-XCTxSc=tkBDq3n;`s$DnICXpG-@!ydIK6*lh%)j_rsXLHGc%<(u6)1-RGZ zYa#^&OARUGs$&87M6?um4nnm|oJfb;5qQzyTCejDpO4l?1Q5k7%j6v1upfSD;F(RB ze{cuE%6ctxu`JOU2^2~D0DLiWsm}M*(+r7T-UP>XG-%|p_Hr08}y z{X@r6tr4Szm!O)W7wQ31fwSApu^O~*38Ds6s#2M`ZqH)dlkc61Vcg{(!*}(hxZa~H z*Zc!eT?XuO61Ix02$hUL_N6v@8p@iwUF;RM2yq^-6gx)CmkSbjn8<^<1lpljdaoHn zNx;?m8*)sA!WqxVRs-=fALFpj)bGDezKBd2FSdMF@w%A|qsGDb=!b4k3G0y6gRjo$86jfdjyybY7T@Gr9y%4FT zK>uw8{$&N!c3n_v26L9fRP}DMb`N%^QHN_cqj0^MG;N641SLI3umtdj$FcehIbvL{ zb>kD}?x=0i0~Z#M#+$2=97dZQezEElCD76IZB-O7j@L^ru_h{Y=b z=e-`K2Ph!`-HRzN>=j2RoTy|DLNi^$Sz7VAfE9fcIN0jxVA>2G6Q6Rw;>SBBA}Z-d=d z+cj%>E2=$2>yz5?4_2}-iVvEI{O`*9C11Pw5In*zVvW3qT5klKyZ{OWyZMfMo>VNO z0^3b|fsKr4wymN8Iv_p70&M+}GT1y*5}4v)nxV2fSVr z`7hH&1l}uym3%t{C?GL7Y8A+0wSZ%G{d3hQ1Kw|s^5Uv3W;okdJ?C;sVxnv z9}YZ}E%?;I^BG|rAMnzA4sa5P;d+AYntjmwDNmXXQyjOHH7J6bypM65l9JpbRI!E3bd_|i zI}v2k4I4K674?LNoP7y-Asg#yNMn4&bLDq?(%7>7rRfGgy(Tg-*b_<)skd1m!ON(X#1>OR{CXb~ck&@|a z-p$ZRX>Jklq=Brk=DzrZRdRXx zSZ;ke|6K7_hc%ftEJ&07wL2Xb3~;cs={ETP zg#Q;${EBykX5`TYu~GxkGc~f30zcNXm-}iNxe1AbRqmKK*CGi|K4Go`6JCpQx?w*O z=)K{778!R)ywz=F2D)iU_4Nzpoc-eBO6{zU`%D_B+Kru$wGCg(EsdYcv2zCSD0qMS zWH9@;w1eUlj?enI zwU@a>)cSKSYiA|x!CeA zp)<2?^0}7FU3;So-Zg33+qc4h&dqQb;$hu-@SXQD)DC-vEbG97;b$U){scstNRpSA zr&whroCH?RS2;fZRnQ0qF~18)R^N9=Ei=!dBIfs)PO2YeOWIGyG~PJ{TE`U#u$#;H zx0njxuB|`$x#jVyy|Q+uet5@<1(sOo$a_JkiTJklJq9y-#}z|sF$|j>W{GZD`CybE-H?0;g9swwnj zM8rcU<^R(H{+E1ie*tdvSL8l+4?0>}@8$4E#cD)$T9x1NwN*>xaDO63*f;ovlJ4)x z)R0o$cW6?=`zO=p743qYHlY-|Pyn(bEhse9^u>&rxTjA$nR4&I!a&4P&4*KG{&(EF zR}VRo)Dx?d%c;PF$^I5=hdxKvZ1&Q$c+CzIH^#Eo1K0dn%G85Iq)v6??g1q@I54;a zU}A`LHUlUE74z2q^pl$yokxoaK`R4t$@jD*)GE;Mmm$spKu$i-|0og@BC2y-r|NRe zv7HNLLStb32TLV2-=($Dy?#0d!O@tDo@Pp2YH~Is!hC=6jYIz&O~Sg@y;FB^=quJ? zRbh)qE;}0cmyLg_kBVjX^n}WymWbGd4Qc&-vGv0<-(j?df`^)O+kZY#z!(S zNz0773F^MveNGG2tb8d1K@wSr-)lrnOdJA*7z>j&lenyGRQ_x`c%6~4y*>YrR{**V zpO}Lkl;%_r_E`I?nD(1xL9>RHsvyAYEq%vn;Y!KR6Nb{Dg`rFVk@&$+u|f>tyIsrn zu5t#xIl(sCpFvgB;0Kspc8#KvuRb4Tpf>)r!d&NxqmZ1=&8mBk#8ECQ+v=?3H=WsN(ziBU>-G zF6kGf{fGTujVXfVEXgijoYY&W&B=G@aVzHgT=xx_<0^v|Vqbs+PX=F>ie9C_WalVv zu|FgxSWfzxX*+rfDbLaFm0R+UJej^c%r>e$b-r$+9Z=(VYIn@*flevY}3h!LfZ8z79n zIO;C#ToA3O*kexhPu7mwWaf?Agn7uP*M+@+ixLfjxpuZZ0}0#;ua%+@(nRXZ3N8AH z^<5!#2LkR_?h^z_5>m#&)`2Iz^K@N-t0BV2M{97BX@WaqZC=N#;jmk7b~k1uXpbKA zA_lAYZ7c;g9eRPA+ye!2v4X^1gEeb2vyp8m1X`*mMVakI16pbX?LN1zzv8Qj9!k8{ zh>alyaFu4{d_YjPug)NB0xl{0fszLyAI=`=Ib0bxT5I&4clbk`YtSwNHlS(b20gkr zYMzT~p0BlIG8M_R@ulhG{k}Uodwe3#2)FE5gH#tfhoGC4xW;KMNF;am!)eCd-?FWX=7+)>6C53_N-oHy<=wIV{N537+J+CGrGx zsfpU=38h2`!c-f}_G<=4+u!X(k!yz7yh+e#vTrw8N>|O@W4T??VslY7)T6byAph5i zm^pW4E{Np4nIN`I>K$31&kk;AF`!cDMrT=C>cY{firtSIH2Pt|{%JQZQOSTqHAV1Q z${I|p6|e^o2>|D=y*+kP%wYF#fIa$hlK3y-B*uBse%!liG^UN&xMpywK2X=>B+X+aLIUPjdpWqFWUOW%-~vm(tiElBdJkzhwhN0kB0yqlFd3lL9W zwq5K;;|>oFl-I?4SIP;A8|Fzwytt+!pKS@yIx~X=+j3IoP}v_dWszvT#8C(B>g%vr zEV^kjKD8tx0*!f=2M~Iip&TOi=+x;k165ZYgw+~Ze>rgEUD;OSVQyhwNJ!BPUHH0Ffb7$#3BP~ zMze((Sk7(w3*=izv)v&b@4=-j-zoo`zM4-(Z;O8nL#tN?vPsAXC?P=(0=7F zg4O_uX~kXQD+&Vs8FBo4^XXR!uZfcY#f#XzXA_t0e)MC-q}+e6*f>fHF6YuIm?EdP zX(Cl!wXW7OvB$dq-pZV-O14bpYFEm6mhq>h#X9Nwy71k}(^Na&XYQWt9_-OF8x$wM z-trvTo9I*h=tNXv8`(U2g;-IMYU={da{<~|utZs5)weJ!)^8S;$0_bn;;-I|u^prk zTC~i_MQxV8L*tk2LDFF>>#kLemjtC*Z)zVaa-To5)6Y@=q2l~5} zm(?QQ)>!S_29g3mAi7h#K9%ZzKYJ~9v}{{&q;#F`Hlg7qJmop^l!HU;eZW5U1!d)e z-Cg*#7 zUANx$ZHi>nk-#`CI>upT_=JUSZO(D~Pql?hS}(pF&nqpI={46Cq4HJs#!OzCUP+`7{2k+t6GhRxe@Ulg`a_~=Cs)KSOxS0 z3p-w(RZu^pC2sQ;Q7@PMN|yc4zmj_T2^(YM^noP0u12uo2brAowmBhzWpHJ6FmEum zes1%9tYa`(WB}je3@`O9j`(IVYqIbvzI+kjswlo6_V>}WjpcAuHPsgREYDD>S^Yh7 zoP6|3o+lG!9xAU?gmwDFk}OQ%&zC3?K~_MC<%dzLe3$-4>DnBvibe}XnnNiP2A1P! z>WFuGpzykW$o@7yDYoeF(12iRZwA|I!j-TzUI1FD)al7B|4>?cyOUMm0!~0jjA3G% z&ZqAm_(dUbOPo<#Z0SH*kff<5~*MI)2W_gR8PQofT3^5wLZmQPKiCyj@U0UH7X z%bYT@x2k|m|BpzW-x<+VcSx7F+#3$l`po+){<)PO685& z6OVpZ$5#6jX;|Ymt#C_VthI5hD??OUCY_BFdD$?;qjcnCn!!F)ov7_-^olOr*y>t; zbOM?JgiMtdO!JfYt!tG#$E6+XZS zt`ma+@1S_ld+iP}qSB1=5IO=G>f`7K4mcd%*hn+xPDtAtEkPkhipfy0o>hQWv$g~2 zrK3J%+bt}kHu)$(dOH8+z+VQL#U|NZEbhigqipc5u8nyPHL4_f_MIRd7;gLKj}01kOo0TyUJf{aX~%tfa)F&1w8!7rFLaVQNNP4b2p4n&0q|5 zSx6Ur6(y^Mc#N`F_O|8c>gE}01%8rSc#3>gM~{h0`hzwb5v2f@NR_j_5AfW{=eWbr zPKmG2VsZC#+Ho4U9H&vON(&+g>|)9IuaFCX#)ZzaO__gU8g2h^`;BBRg;n6cC+#<5ZKzl4qxrSCyQ z=QFLxSL9m1!}1^W4~da|ZzbYTra%Mn1^T#SbYs-P3ry?mOJiibkWO2ArZ0YNypoKa znDg$Sl%+Wp~9CNz4lSJ4htu0l8oD{R_SnliS@##D=HtJW-yds9|sO>HaAngP!k3qa3NHDIp zRskgwVPj*Hl5Yg$wzh#=1iVx3llhwQ{BpD;adsgqNxuI7w179A%PbZ8dlKMK_`Mlh zeD+aKQA%g)V%eb28I`4W;1N;CBni3qD#Zm*_+5Wu8B@Xziu7wIh#f@9wtS~VE}Azl z?6|LuMv|3Zcm&2s`ow!Osm--5@Y_)fGSdcM=(KQ6OK2*@`l?$oy&+Bg7A>o@lVC0O zhq0-`?jBF@5v){##Muz`h*Zq5|LxH4V z&GX^z)U?Ug$2UkVDJ9hGN4WSHoKeZ|?9MV5)2=+{OLW8rd&>!}_G%^E%s@&xH=Q&J zuS-CfajoeGViduF^V1E+mu)*Yak7`yKk@n7$C;1^3Lam7%#5=!P~PH1MHT@m;Qv_a zxDMtG?Jq2pB*j%j3`VaMiQVQNbzIlhb)?iFM0{whpMz9XWstzY%ob&aC>?6DTF z&g8_{U?1Li%HLL$ogz@8Dn!|0sKKes_pt=TQ~ZFyxyi0{5nWQ!CBR_Otwhz!y(vPn zMOpwv^+rQy=;yU@|7@rA{!#r@Ve0BcxAXWm%;GGZW+j;zgSIEXq$8xX!N+5L&wSm5 zM!v%mu81a(UZ`5(>W1yCE#d`Q7x9ll2t!y2i4T}~M<@hv@I*Q~{iOxWq&V2dJaU&d)O_d_J~Vee8@QGls7OC{ zr8+7ashgq#-8ONvl-aNEzWWS-X8Qa4=}0{T10stsvv!AVq`gO|lH~O0UaDqoYIf$h zC9DNaK*Q!=m>kqC5unUmiqZ&xP~PA>Lsf9L>)sT!Vf`A-6NH@5Ueu!lAC33v%%BN5 zx$P)}8lH@jm>l18-&{=4DBAGit{!A_MhiZ+8C(^vTh6&AiAuXW(f!%E!-ZcdjdhdK zb*YY@BkloeQ-!LmtgId)4_994%og{O2xSW|N5_Mt9~`5jyShq(q^ru&)Ey%GQ;uX& zNac4gD1<(l3t%TR?8*4=b1Kq_tDAHohd|oaJI!T7=(LA^H znps~(bNaxk%Jrxf*Rsf5=LTl|3EzTV8>T5Kh`L-|L?G5i4VUEXff^{`YCTf*_&YX+ z;u|B_oNo~Xs))@m&!6l2A*a}`dU4xVI zD@om0S@xU~y`uf*(*~KM_ZNTF68D=P6ZwhD0?t{{BOI0%X?hQ+pP&N2hLu04i^+lT zgV(&Jtu5CiB_vhOe+VQP7-Yxj9CBB;mgE8ygRPc`d-fZ`2wBCKwtWqsOVRoB-a$)i zBZr6E8P35YzNyP;F~9fWR2cTO62Yijbx_Qfc~C_RsCs-d=cxKdRbk#C%PY6^42ZrHr^u zZiM+OR``-h)VHSGQ<9e(H#19@+am_)kLpVAGEbZ=)pN(O*5NS#9)wB|5G-tmb&50-hF!6Z}V2p0xZb) z1#ow~EZk^^|2pl}us_EL0TU<}=gR_MaiHxaHfguQ}j;iTnuvaS`2fY{F z1&I9nC{^z_iTsk`7aO{+twNSwg>BxJce@hh=9&m0e`OlJM?YJY#a&B7`)pFF9qWSn ztbIvmGYh@*8u(dnrxL0{$lCC{M(lEwU{)9*#KYB9p2rJvOC~$Hh)^jfhZkAYFPxko z#1-#DYydr1^y-%1E(P0H?1CS9M&AoTjP0QmxJ{0pVsNr&H#}Bj6J+iKP?jBb;wi@8 z#r*+?us4wpM*$fxUtB`7T@*dUEC8rP9@u!am8((kW_Pxt^k2|0L|r6uip$@<&xZ?| zF5fD@66R|M`_S#1&%ZQs$(AtVSzE$<(ahTV(q)qY3$pvu5pQ_T5v}@QqGfL?D1`NF zbo0k`RuG~#3nlW8ZXW*ne*n={KROJ6P3UBNGR&@uS3XhW`rnq1z2NdzqZ^^}=gDN5 z)J2@0r|9jN_?Mup;X+FbTKvXC=Ebjjg+09CK~g+ja4UDSHwkFL)L&j^elT#PHCKku zzkXX$CfHS51$vm}kcI@XQ2C9C<>4zS)z(%@;RmG?W-ar7dvMkfCgcQiRl>DXzwbI( z%k7ek)pDF0xU_BkW##ZmJgQQ8H}Pb-9cvL%|b?XQ#8w^u0Grg9yjvuI-CZ`Hcw zFtc?tmcarZ(wxLK{`s*`F#L=Byt#pzUK=OID()=vUY8hdrVNH`l7j z*At|3;fs3rjzieVa<_O@C;J3zt1U9w;OuAYvOQ5F^<^_b(izi{ijU}?8()2P%vNuK z2B}TgVdvpU>5g2>I&QhEtA|%bIR21cItRLOxta}<-=107p*<5HUy?P_1NXE$0u{>X zl3S|qDzK;OYGUxR8D)2yGbHd_Fl1P zwUpGVqDE|@Vs9e$R(r&X6+4I-n_up|pU=JDKYst^kNo+1Jm2Se&Uv1r^Vhk-;imSF z%+tE4y@fN-S3ObyNI{BKtw5wKwluJdZ^6vl7${06 z;D!VesXyw(#8&Hu*6o?brcBi{(osKs_TGq9KZU>jX~ZNjjcYXP{*2D0KCu??r{7nv z>;xOG;D23NZt8Q4avq6sB`hnpw;F0S%*1Yt6(#gh74t>14OP-a;uGKWyvsr{YnPc)ts^bmyL|+`O7F&dO36*!{FMqejWwJ7KvnmWu2@Gp?Kf%E)V)bL zNThLgcGZIT_w!`OmK9WSY>$Hd7K&B^y+ za5O(3uamROfXe>K6(y58b#twd$(CA$iEB&`7RGqYIC{uSg+Jq_B+~+zL9unBx9lE6 zN6$tkq|s~k)524}fm7*C5st%SrBUPtX>ur*tC;cXZEGX!^awtIOcvamAJuT#_RM!4)?na3)aEx$ z_ax5#{QdDh5@KoO$fM660RlR3k%T9$KiG5u%I3P5x#W{=S$swPR( z%h>R{-W%|+k58A^f9EJY|0fHrFU|C^BT>Z2VxWC>Y--)lX?Dp#C!xGF*(?2vI_p-0 zj3j^o(CaZ~V=xaC2L|1X&yj48E8L;}Ir7%V0Ox~j;=f#gT~h{J&oEiDH%kW;I-LXO z8b}nbJte$(9@PK!xEanLEe#y7D5l%*Xeco?Ri0}2!{!(RAP~i{w`vsO#IBC{2Hudt zwK%aEDL>h;R=)G$*4yNf>+O^Qk7Cc-DCLZwcW)17Qs0p{7ktMine&%HJvXNrXw>m! zKn`3PHVKUHUJ^~cQ2zO3&;~-phi#Xrs2D}_*6dC146I&WHc=CB&J8}&SjV3Ut)_}= zXh{01TepX4I<5H&v=pSXt}^`zEy~d3@YCW>Aew&;`Y|jlJOmu>ShW->y@Zu9<_EG^ z>!nQCbMjk~*&@6Iv4Fd=TIlBpw6Ye~)Kn!zn+dI`tZ3jFYrOWnTww2CqF|Qh3UjJY zEa&0X;6TC=-d94La4$~x=H`ZmI`2B}7s1IIkZn8ZnVE%TAGDW8%;&r!PzZeZ!gK!8 z2rXJXAelfxb)`pRO3BVQcD(c}xbY2yx{_~qG!=WH6eH>{rfmqfkdfPKh=;OJPHgfK zOnYR$lp`rcJU60e#%5qVuO{f&_Zagk(VzqDeYR)On%78}UNR)czx~MZoWIhV@UfVb z08O1M`%sFyz?2k0X(0PY7EARPMxLtlSEsa|=5ITbGuVhEpvUqOK*IHf5}0We{K~e+@SzfYy(!t#KK73&ewhdgX1olm;g|)n7NtBcZiyyMjW#V zeJt4eG4C1aQq4mWIyRlZlu@tOiK(e6&|ZS#Ps*!-NVyOToey(t9*O-{?)GYnpN*0MQ`l&(=%1Qjiw^4FkuR|LEgZ9Rv z7qRthHYjfsg3G+QM(D--+IWvmNM*>?UU`Z*_CS)g9TK?E?sjrg&BV4B35z&pL_ZBmU}V`RXCTBa{fGJQqGYryYLbZ?}B5nbdn|8;-H^3NB_OSi$9QZBZbyQ5pfuIe{0`^?ww zReD~l-=$RGu+Liy_YZTu=?q$xQJc#AK8jb&_?s!A$D|C(d?Uc{L11EoQ?FF1<^y$d zslQeE=J`r#Pe5<-1`VFIen{C+UzJwJCKivPy|A5L5Ow6CoAn=`PX$Xo7dZ^B2lrSp zvSYhUNVcK1EUd%kUG?=Ywo!}(4iI9DYdNXyjbk(z`e|h=;FMlveA1H`MHSSQQYSi* zTajI5Xs~N-Z)>DSX{gSK?T&)ii$x2Y8yXoHVoz3&#d#x;QELf#W2(8+iXNM}qg{3O z>@NEle?1+wl9HPdL!&-hqa7z_=On$xii&J*w1~z}4h=nwKPV@EHBT*h5Ue?FqMpe9 zdmj*O;`2xQWM_O}x+mFc>8O92FCzs9U|n$6Beit!SEskU_4a*2H!9tj@((5@B}>wM zr>XxbTvwfxv~#5>Ep}dVld5LPLdY7(NAIXr(AwMoHfl7PSX>yxqN z_F)mUq3980G4*?g$fqTnyw8JbYxBQBqA_-%{46s^8*G|^Qb4QG%34lzlki*>4?z31 zv5COs_xW1*TAe&yqkh3s-&?A5t{|zUOl&Kcz0_cz_k@NcPc5Us zZ>-jRM)%EBZlbl4e?v;jgm!C+4^%1LTS^^bF=y1Fp}`@-QO~|fA7uhANLM{E5Fz?V zU0>&YiMVZ_>O>wkz)>zPF3hrCTw2(WeST&GGp?g|Z{~$#*89Ac#fFR38b{IUnlPA< z!B)Qo;A1kiK7h5!(9rB}_4R5G#?A;!v%8|5&e$vWG2Y&UemTI$1I%@GL`R;2snj0Q zjgEjJ$tdT~YUAuY$-RU2vo_8<(e{Shl+hZzFZ|{Q+SLh*zcDD8{Q~&C|AP6}y`B^f z9+tMm?{v7Ab(7F7daQi?%?zEK z9_vC;N6sRBV!Ct%v(+@eJ^{<^HMv02RO4T&RLLyTrA!UKuR0lPpTZZlF>wUdjd+U0 z#B}5a0!%d{jV=-1ABaa!-D*=6ZI>B9DHK6{)2Ag&RHBkuHh*F$=Sh-U#tJ~D+Bq@` z5B9+R~`Pj5^{Y5ufUcQDPa z=>J5O{9`_%eu%mcS#wDi7aNXCylfxmy7sEZ+Y+DTKVQY?w)ijX`gZ!6>JkQ3GSK<) zNeu~+I&J!UD7WkLr%q$$F7^D)`-OS`RRw8}J;u;Cwt}&ad5k5t)lU2w*W@3O0s@27 zUZJ+RqD&Je{XU54Euy;+x2xSC2l~@e=G>_>V2ygavi05F?u~7AscqU)Bx0MGdp{7< zPxObu&MQs2(@La&MU`#u6|jyyUGHTI#H8$~e!0HFd`7SMh&yR;gETtVPC4PRc#f^) zJ0E;ItK}}x8HrX?c)43S*?o-gdxJa0oB!Fk@$a<0j9q~#UXVR#6j&!uNCMutfc2l zj6o+>(u6Nb(ogT-JQ^d6BXeh6mcOvAo^@!%7?9N=$9C8C&7el5s)0Y`sT+2V6Co{e z6WeQehi3zlIA^B~nbQDLTj2*X*$04$pK)E9JyZ`TEbiNG>c?fZoSz(ep7;{9)`yIW z#GpF@MO%X}Enz13+p?09U&C{sRj(9^KK-OY<%fSJa-NxXpeJ?`L8zPS_qp1reU}Fzh2-`Ud_12aX{U#DJx`*hEbtX2j_3e>c_r5cW&44dA;JB zydQam>+;oSpx^1^6f!)o(Ob_n4&$?V0BbS!G1Z|NE0|`-sVgM)Zgc@x<12?py@YBj zG4m4Tdq{)mbc!a)na@9iV@g$~)@Rvq22P7-5s3MDgrSK!{_D&iJD}~Y)!mbmYp=Ri zsMO-kNxzPG%BhD0NCQ$#C_IZ{GD-oVg8VlT6li7^%-*G&>*fIlb`@s^;haFNS2;_H zPdvRqT<~SD7cw~+TB4z7Nb$lF!dwh8=4H}Y<>exrS^_6~=&azmSK@gA|_>={Md869b`DH&Yt4zOkab7=6a=*$d;4S z86LDfrT-BESn_Fc#p%S`h8dmSP05}2+Jb4O^XdMG?jxX{-u{GA&L2@U{AN$AFP6s! zQH2&Of}_Sq`ZJ1}ZZC;A#Witi5||l6TjU`t)1DSHYp;?|2tG~Fshm_k$KRI?{BZ0% zaLff@Hc;F1%^mGGbfV7FV+8&U>!DOm4;|o^BbdYcxDckC$JjIW{oUt=^71NLw#)WT z!c>4~CyRm5f|vdiX%hjt3X#D4XRxG^7qIFOBKEV!-0G= zW6B5#pU!{Y37awHMV!!ozaF-qyl>y8GElx4etiGApvp(*PkE`hLP^Sc1J6l3c_m%L zNG5T#^vYCin^Zu$#U(p2V6kj&O0lP;OKD}77-_1le=9sl}NE>X-Lme4e zpXNfQBAWFBgYhXZr$&sLoATq3nDbI2XYY&q%%8IFHZx|)$Uy_{h7VW9945sfv2k&7 zwYiPvid`gS=DUw$((q9M-Wi3bm^EZevuWGbtOB^%y1hY4^~Pmo z#Bd}fi^u@~)rw7~Hs)gCurS~qwOfU8U1MLn)pUgwtN1TfkeG4RA!iGih} z&q>T!r{=3XkdAn0%x?Uk;_>;jW)k4Tv{0crxn*_;pv{^>f0}$A85-ed#vzkGlPfB| z|B%H}+CS5%$d7}AT=U)JxUwxNj!Sq2Y#FS3=n%b{8kN7@#w^VAdpCbE z(pbJ{a03~5WG6g0a>Uu+Uku3~I4m}gBhB_r zSrdy9*f^LZn@Xdz*O7L(a>fa3{AvGk0s0+1+MmNFuAby6iRafjZYI9S-oz&SgvK9l zdkGg`3p5{N;?Q!w?`iaqO<*l%d=~WFFdgadX~!q@o%b4~pvvgFv%VN8nEK27W&qU&9N{nHIPQlBZ=}new@dZbqu+5RB9ZghZ1wFx+iCA1CsBqs z{+MfmxOW9p#bKxqF>c;V4vluur(@q?xuK8MtPN>DeEjR&yYx{>QfwH(<*ZcG6vNUf|5S~Wn4;7ZcYhuPWFG+=) zh;HrJf>OfuSj<_i2ymTh*GCZ4h}YM6v(}rHnVHe98M2*nyP%x+r9S?eQkRwdI%9c{ zoP=U#HvT(3GWyHg@9|^BKRRitJ^&1a+^*jz)EnV0*dBYr&&0RlY{+wujTj6FS+Q|P zjmx0U@DF-avSE!raUXXqb=z{kJlkM6czWs<$iB-JH}Q_mIs!PL6*F1D}_a{HDrHeJ+3mh9!}FeH3-C_?lZP zOoREf=a!6~7L3IMvyGnERgdOGs9JjwvCz>pKoss{frZ(KpbLGxYzy9Tv_P&i-BLlYr7&g|*H&Ikm4; z&+VyyFT3A8rd^5|`$GEHj`956B5-(dWJcuB(WTfWtt#!1(ZPSaGrEF9PlYT=b!z!0 z?sf|bMSfuSy81bZ)5!c@X=jAvr}S0}3TiWjPdg<~d3AgY98|)m^_&H7hnJ%n854QJ zUd}i@n$32Zc_crM4!rUytTsG=xiX0VnRW8;ILa;AIrQ>EeL}~GEs9G)#bu-zw7@Sf zXT9*GnJ`BBNtHGvZcTiH9Wg3y?GujW&0fL&Bn>pn=!s{y3REaunOHzsnP~K0 z`@P1X>CRpzS@MMMEB%zJ$&Ss8FNl6>X^Fys%rm+o1QRlv|5dRtwH5qmHF@yl=?+wn{f;4gimQr>ADP(5ui;p&e8|YmBtS3u9y5d-h8*f& zwe(WmPv+Etix=jL>89*6FXXk04Sru=#Vef>h6={FNxEd}wM;ysVLgaYHmX$RI#|}K ze6FA(Eg47K#A3%)*wN%I@r;*n@!iZDxQKAcqrvkEa@@`R$Q*o+rP>Cy<&Ku{6k)?Y zcQ_ZM&@_)RBCE3k7kSN9c)dU$oT059)8tSS^1H2?$dzQ-Ywd)Mo)3;()?}QcGg!x! zYdu`&|8w^+%vP;>%KsR=c>-CT2u#HJ+P4 ze}#9WR%T4OidQ6r?Ol4bX?GthJ*M?euD>a=c{7yv!0=f{K)K=3!A^?#9cTBJ# z2OXmXyp~D8>a!8+?!hbyg(~L5y*llrf6pF2Qr3GZH0=}9=n^rX$CRcQ`S+EfxNo|u z&bvScoHIACtGd$SZp&Gp{ppokrw{n_Edf{i9ta!{ISGjn%E~7Lfj!9OEdE=(>-R|yM_py%nS<9K*>rSF&_*!~AJt zEtgYYA$Z}7T&;&Jg#EJK5o*JfqNaA&;3@ers?0$$y6)5PWDdR#8JvyQS6Ib4T*bfb zXby*1;@QCKViHk<5A%|j@eOZAmO>!}aCi*Pi!~#e+7rJI27@<4-Sy?5+;vc~H68 zQIYF*g0_l%;oDmTzJ<@mN7g#`hi`A76tWlRogEtbkZ*chItF5hWDY6Us32=ce8u}pO@=s#)E;?(&9;%sgINVeRl7RyT*N$6}@sbK7 zRP?FG)m>EE&AAqgRj$GBE?D{+4pn}pKb8Qme4UAy7Qc$mw2tBC!rxb)kXU`3OlwjN z$)GWuc%7?d_{jMAx7P<< zXjK3(aYfa3Ip~&8By+_!-<_>}`L&yvAlZUI+N%#3qBU>f$BJzO`vus!jjV57B1amA z{i-P0X+LW>{?vlprhRI0L`XVANGn{W%`!&z+ z-DpB9;x?Yy?uoa63Eo__V!uc_fjCDJ#QZ@ zXJJ`#ZkjeAf|G?xEgV)AFLO{2zp(6)Pb$Uz8mE7s&&$r(IF{%GfIICoF?xA#xjjf% zA$CjqbwER8TuyU%3{Bscu$>Q&Wj$&o276~)1M_lN2b@SDmB?7dGpWS6Lh1FY;C85RPrVS$WtO>Tf|eF=DZ&yTJm7eUV(E@mWXQ<`{SGVzMS4$7BJI(Ui4!#P8ClXHqUn1kCMNdI zXJ@fE1m>nDAvY-VC7GFk&0h4~mI}IrhE%-cZp%1iNXL^FYa6BJ6IovN7yiI-DilK| z9Gb2T#D(BapX~W>87(bePZE(A+rkOz;<^T9OS123>;DlrW0ybS)LYCPeNT-xCDVnMZ$?M9Ub#sfBD zKi5oelea5MWRh-*Gi;~JkTB~I9xN@TWv4j!&xEPcc!b0IKf|UH5e-k&@E#Ic-+Bi_@9n;$Aa~u{+ucQ{4nnZgL$VlW^zaC~12H)|LhD}eeDnlW zRpRU(5`@^cqHQi!M#HWa zy#)U#pBBAD3=_O}g6`Z_3m+EK2JX&{0`ez@m_E?ICQ7fW01saQCUAQdXBDEA!g}x>nQ&}T zB;taO!0#d}14-8M3YCObrF2o7$&giIU$4F{GKDo{b=~!xSc_p&!N)qoaya4=akdC; zZaM15j}JP)IX|ha+)vcX#M|x(^EJ}wji-Nq%w676Wn!WQKE~FIcM>BS1FrfL!B6wA ze9*GZAuMhe>r@XnAbG}Dko9#3Sj#=Ry}hm$V-x7*%rX&TDM=TncT(6p-1g? zYSvBayw83RGF|R$t3W^6KhVur7oG<^KGwqiBkMXZdr zi`F)6bAAy@?uY=G8tV2W59)<@_zPymgbmNE_*;u??jl0L7@Tk2KzeCe znir1_lwJuLN=i1&oh+Tb185w`{zT*PL#s_9!7OfM&pY^JVviK~i71!xK8YFTj$u|| z@ROM};-s$BR22qcP2=MCoFC09&KVZF70B^(S9wB*Pw3Rg^7lR^Me4PsGs(qvH6@4; z$ySS35U1(uXNbIbKp4rA>{fMthliuZGHUDcE)PB1(TXd-)0nRz<8;yL{;z_-HU1w! zhMhy=>(dM%vvaX30Q?h^gZ5(>e8=7R`H$1&*QdT$oG=k#_ zkE{^?hi#skloa%vLg5eN(La37D{iPZLiYjFFq|eXhZu#mXV(kDyt~tnyLSV0yzCOG@b~C&>@sJkN*ldO#_Tk6+rpl;;?R>m9>SM{(aptXw z6(3`+*80@~lgTk>XBcuH@;FGZ*77A_kG`(ntaK^h3=u%VjQ8VqIXrIh=8&lM94L3U zd$_v0cG5p#o7eAaYg^YU1sbshbB5NWXuw(a_hXfj>&5uKbEWBd;Rw_eB1^M$m#5Wz|BBD<{$@He~#jrA?%f!@I~n6h38I2L_n>ppv*lPd<)h$?@}w=vzE)i4%UFAWTjy zGu(;emdZXk%aN-mcOw6_^)SZub};0Y-{yGMvJxkI;k1;O6laukGi7j{g#7Tp&K3QM z|I&X;>eDae*bIFDtf36zAjyo7lEsUFwnD}J493Y`AKbzMDo(eHK1`mQ@g);MBR?jM zWXeGsn#QZW(2KAZQ<%74B~;4wBSZ+zBI~<-evVCvUV-A0qdO^N126kI>xxtKfpvQ; zP4ARXuh1crXE%$tPXpKe8^2CuX!N>0bGz;w)#B8_sZ)tmGVP=~CW2PyP(buZeKGyV zo6fEHy7YbM?r!S|(a?7OGU^c)bLrq~;RnGXKJ^0j_oU}3_+dv!>laiDy)^uqC4%NR zmm_pK29JF^*kmY3Dqc#H6(L634m6&vE2;W5vyHChxY|t6@fgKx;Ws!-d3?@$Cm3aO z+3ua|-Q)_dcx2Ej?ss^-54*ZZ_#WM(@9=^5^DCpz{UBzlBaO|d6lv&B7S&%m0o^?h zJ~&tG;p=O-8D%5EZ3of{8siQQUA93)anIK{lLaKoW7q_JDo`0&7F7+|`;xvRcgk(y z8zt&}vwE+cU4CjM$}trQyZLCl{i9tv>0nE={&xsP9e{*1KkL(`?v47%`Fhhl+`=!k zH4F?*3-3DT6SU(9!_(rNbdtp}+wMya-5{)CB!~z-QR6etD-9nLIFRxMGshTy8x`ga z%tiUn&?jf9e2)Cv$QMmQ^`PwFDW5)>Q>`2Qy+>}@3R=1GeN#r+n_q`YEo9!vSK`Na zw4BM^k+xdCXR-iR?ObLCPs4%ilFB4s=WT6MP}38A3OJLG#lwwzBagRB_y$224`iE# z==jUZ%>2#|99>&*X?9Q69!$}QpS{Pu_{J@m9@}!g4tH6Sl#~fN+y-a8Q%+nzT~(3u zg*eX5`?zQo=1ut%hkEK#VJqJ*k36KaVs?&(5%VgMSDYhSnX-N)QpLqb-N%~&S5l@> zGciY;!^p_1x(ea*N05f$;&9mZaDL0(!R_7^MVeLUbNzy_yod?u)&^-Asm72yW)rl( zG$DCQLkq!Q<2f%s_j~Xg?($Z5cMos>U~ibgxrMm6bh8io7SBRVJ7_0&GwJJB6WU&! z#lH`J;POcYKAff;DDI*bSWs;4Xe#S{X~QJ$`2NxYQO2LP;c&p@bhdbN6(-G`(EFt7 zUO30?x_0u@RvMv4)ApYM)51>^pSt_#Qw(R@jF%@3k)+B_7-eb+mHMRm4Y-_fWg3^qoA@x&Obq_J4e! z>?UdL*6NF{ly>^2P4eRhxP)D|+MKs`m$R9Lqo{qqK6So_o6E7&8}h<3Su$J#^Eq2F zJaS;ACuaDYUbieomp`OXDSI}+6u01Bpd?)&!KaLxiL#O(JM-3xV#0VEfC+n@s~mP- z{z2v^i37CK4w4bLTCox5WH$%PV~(!DrwmKCH%s?^$)vY!Kpq}&Bem~=iGKmMBDyVu zt}vw#VD#k^R4X_QlOVrBBY!N5Qg@t&X zoR)`7Me>~wQ-u0Ylp5E6($NPN2(DkDZ@Dg9Tt#JOmM9ebkFIBZTF+G68aJelA;3ZL zugJ)==-dcYBIB@=;tNmh+@mjVyAsf_*WBV-Kl81LcVBN3N_|A|QarJuBBc7Y;$EpR zZeI+7+Q==malqD(~tS{yP;?Sq4uu9Px$KVQ zwB2LY(=v--`v-%Mmzi#b85rIr<9CXMDJCA!OtDlDvn3_E8{(faO(|(Fqo(!p4j=j_ z63z%OzZI6{qDYV6KN%vKdN?^=fUl^AcRfXM)63F&HqLEME^C+OJp<^hzuhsvf-PNv zz$01ZKHfcgQ{F)nWpNZ|mP_UoGP|cc{udzhEmpCvhaB#%?NX9E*-A>y$cg)Td-w(U z`MDqVq?p}qA>*)6*HM2LjRv)dhdpK(u>lSOjjxC_;C!JhVmDrrxbcg^sD7`&#)eP` zp1|DDX4?c25}cSSbcr=60J~4Eq=_;XBR{Fvo1^~cLCX@fLJ~-Lpmu-q zs{4!QSI7YAqo*>eP9Hx5VGV=#{gReIa}yTWZG!`tAl5y zz=wk$^T%k&)X7$ zjXI4_iYvbl@Wh!C&OFg1p)G=cmd=lzVO#Df65FsV8Q+l(eqR|D zHbs0t+Zm1fU~a7FAe<%6F^wFIZD*Q$woTaV>~w^G(0gGeeZsvt>Gi?9w$i-3C~#0=F7exW_HjQ?p$@L|f`GDYwbt3daMJuAUfEe^gvRb2e# z`XicJ`%BQEKwmciVD_sQ%wQN?UAG76w=14Nxi)_sdncKVLHyc``B+jqFaTV~Gm?C*dV&6URXCh^ATa z#T3?1;p1#feQ!Yp%wwX;6461ed)GaWFD9;CDSiOUzxpOi9hW^bix>Q3GNDBr>&Qd^ z$_|2n3|03QBr@o}Q`x%LP1}h>6=Z4~xVlqFt>bSR@^{_C+588sHX4do^iU zfs0Wj+*IwrNU0d*n!y(lT9d>3;A`?DZ_m$?^F73T6BrTR*xxaY_u_~(4JSzMpJrd+ zcY&k$C!P#jZH)q}x}wsGf`)4{%YXj-7sF@}{GYT`bP)A`pMV}=0~nCSi}}1&6czm- z4f@ya)99`(>ju!PjEm%x8yDWR?$32T?iV7uSd)z&HADQj6wbasC70jKNjD`6uAcUM zID?sYX6BXI1}y>dwqq;n3|Cm8zcTb4gv+u_&ENI1i-3Zv#Ya@JRkU`@f9y&*vhI&7 zE*HnEayITawO&K8CmBn3h&uZPFI|21UF7v{6~WO~Bn)rP+}~@OcDGWz1wo>;qKNz!RUd;a$=2Nfy*^UJk(e$%inrCAd-!;K3=}P zX>mL|^TB05!*QE<-(U%AHsf8@U-X4BU1CR_UfF2beFaiofAqo3M|BphEOT=fMkc(@ z%n=T^gq_2+lU@Hx7mSY$5tK;JwE1SAh=N(>3+#acEjHGsyJ_$9{XPHGK;w^*T3K0G z$h)@eW)|zf*0HG7lUG$dQeKvs6*!K;icomdRUCz612#<6`^Ge*?FQc* zKaDSUUSI20JfHe24L)w{C=rf#+2}A4AO3t_jdZAsuBBr^9Q~t)w#Z&NTxHc;ESPny ztU5TnK5Kb<^)RjGu$PpgVR2r=M zlvH998uNpqpy^dS({JgCIjRI=Z&1b?^ow5pU~bq$JE+u8=+oTVby|3y3;k(E93D=+%Azi*$hdT+NL~ zqY+P8%WaHn%TYm!K8oFBIJB9W)&=JYDo@M{SaGgyl&JcayzA0{8slaRW0^q>QBY72 z5@i0ku_IlR)I)CDz+Ni_f?AlvrX+2k(Qu+s?wAhhpY>Y=gR~~K6uzy$00-x7)sK8L zvp+~P3&=rqA-&Jn{C+oBd)sqShaXUs+=gmd_RcQcm;5fH<0-)r$GhFdYh$zcaxlj| zfxU{9AUNVmvoxsFjC^0kF|P~vU)opi{}^CBHQhtDmnnim3x6N!`bDrFs*n#`JQq=! z`D=mf5qd2{Kbt&{?I0H*w83UbszyL+OY|D(a5e)%g8W3D`BdkqMGo({9GK2?WM_mb z#=I~|_yXQbk$iw0>)W#HmuCv<#a_&YKAtA{K^ytY`z-FE)Oeft*Wdjd<5DHld*-*? zt(b6h@aF6U*zJA2D@&)(+1c64yd4n2HU*NnLD^!Hc6{N52lYMK!A8CO;6&bZhHv{~ zmk)`hd0q(R`TA}9@WpmN_Esj)78}mq$AiW}AJ}9z#c69x zL`1abkEk2Mnqj(60ftkk(>dy)_S@I`T`ZDMv`qR!o^)4eQIe#}p3~X-Lju zJ4eqtM~8i0CN=#0@!oJO92cHdFi(OQnFJIL3kh1E=d+Z!n>Y@y+nO=5mJ7jSR?xW> z*Ccg0Vg=wVn z(;1IH>l4b{`F0Jtt__?iCz6l5jCuGQ9Lb7f^bg4kd=@PHkEX;+VozQ~ns%=ts)sP* zZ)UYL4HgZStwOqNTUwa{NT-#+$S4Q))Yq&#isM&G0J65-(3L?B?c=eqSluxwWX#-7TiXGO1 zX4>Aa=h-SU2XPG?mfw}Oe#?5-=@A470sy>kJM{Lq6FF&Uzy%_CO&RZY^y+0>o5!bl z=gL^#zyWi!R}{>WIwfiQ6W|dVVC@(+`R;CacOvIVB6?(GMDF}x0=p)kDTMe3w-}X` zOyp_Lo(?TvAz<5CcS%`6>+3|+?FW5yp}!XmrP7C|QR`3T4~k1v^bGX|urJcjG!EP8 zI1+MV#q|KXT z*cq}3ODjY9fNPI;%eWlQ$(@i6jpqaKmc|e-0$Pcs;~@c=d>HPXBCEz(+RNTP`vgU> zmE8mO1(g|=exn1@1Sh66=)TGK!d`r|NL>t-;rnL_3*Y_8E;akuE&Xq|NbP2N{Jwn8 zh>}I_2`#kNU2dqYZfYF*%8LtZ4t!Y~D_P4n6C&5?^6+9q5+p-ntk~P(k3{m=l|~jQL->Ei^GNF z=l2aM5J#1})1^5-ke=eLtTM97_IG;!Rr+zDHP%aMewWmGQo3{z6Jno~7CZ2SqyI^rK){rf^mqyo)q)B$ z!unc*&aUL}9yZteypP-2|_XyGB@D^kzh5&7F1@Y*%QFU!L7nfH;{&t zh$s>Tz^^%<(r1p@8EYR~!S=haEDw&iT-3s|GBS8+Ag3PoQdV0&=tVpie?Q`RV@9!h zV3pJS2Idf7=NHQ6=6oC2u?<7qP{>~T&SJ`&uRZKfk7;bLB8e21g0IgH6MIKEk^Vn2 zw;=0H5Y!x<5Zx5qaT&bPUu{ctb@k0N6c8EQXjYayxL%4xmIv)YLMKx%s~)EYJX3Yf zfgI-6c|y|9aH-CC7yJ;l%4EyUViNQ_8ZPV>|W0Nxb4L`}Zq0J~iWQy%`eK zYFVJXMOLRH$A{x}Gfo@`&!w{pp7*gFnbbNBIZXDi@5$mVGX;%$IRqM(RCkSq|9?@d zn?aW7Fx`jCXB7p(+$-I`!(M$c)hN$1#V2MJ5~p~O@D94QG4pVzZ!|Tu#>QE|p9yEh zkW%GydXm+cokaE=Ait$lS^te7Oy5*&i_)2~LV|^=;uFw%W$PvsfBzZlz+_%MjZ*iX ze{FM9#*p`91hJsn*Vc$I87w_LSUDdSPzBMu%DO%^54qc`47|CFXMs_Zm!PIN{U$5?r>nE!6b4F`|T(c(3o#I zTO=|_ti`C8!=^Ev-Rm8CiT+M=Qs&R5%VQwqXJFMCpo1_|7D%?dSR3wr47zX< zgh{vF-kya#d}5+j-_YVs4q6CpTnPr5o0O&#?%zvg*FD(Y4927sxiZg0m7MoH+WE%6 z%FAKN5c-1Xnz+nUSlgAFGMA-zn$r8496WtYs3m>iH4FXKKTvj=F+m}vUGUVcK9TZcpkW&~w(T^Sv27cTZ5vIR#R<)2gf#;6bo3m$F+px5%#`Oc1`^c($&|i>n9zvY zp0JPckE;(3P;_!xNt~mjE9Bh!RBsD3ZhW9j1ey0UgP zGyB-gwa{EmCaz+t{xW^A5b@O83lzwXrV`vl=~h(H)zdN0TwN6Oc`l$E6->{RLH;*V2qpY!?3{GS(#sXrI9(8!vX$lm~~xC%|<9Na;W83^`L43p+7(VC-vM9}y2 z`7iz*<9LTZY=6)62SgyUo^T1g{`gcdW8a_)SV5#v2zHJT{%-2ocIXztU5>%?G}$k= z0*V$92rWK4zNDRQ-=a{z=a5-Q?MC%eGjdlu)Z^#yer`L(**d_D7_IsK1u3q`LVt~n zxz>78;Plrv&oApoK;9Vyvh=Ta9%eh5e*(98v1PFTecfnboCmNaQ0D6z2RkFak~o92>^@itJsAp3IErSqcDAP6#Ka24SZ&iG<0 zrOKa_{StAzWKys!7_H$vP!6ps`EuZgcoHgTDavtqy`AV9Pf1!p*_HM~s+umZ&>|nE zchGj@?ggg#o%^Hx!dcnF*8SPeg06R|%}cZQqw2H)*9xu*Cdya+UC{Y*XMWrB(z%xPJBIi{hnsHX zszg9Qz_E&lzdLoz%%lAV#QsiR2)R8osHpHiy4S6Eths{vLM?Y?HYr=4G{f8TQ%skt zg>Us{Ap8E3F<+PSi9JA!&oemy48B#L?bIJyYIJeJ2-ZB6m`!SM69+|%9tfz zT3TP`XWm*9-n4Upw{hgI>wPs{_r1b9cat1$kjwr;2DGhLkC>b`El|jPuTdfj_A|Jwgfuk zUj~x(+3cV`Kr6*sR|&YkS$YGvwiFp4LaZtv8SSviZT!-tN;zN&M&I`zJ+icXJE#W0s)?bFM+`Auk^F z7L_`U)_6SkO&3ORt``Jbvtlrj%?eYp2RCz$wb~4uAp>l)ce|ag8!wyvF(C#xAYsK3 z4(J3ta{L7AOc~Ja{BpkZ=TCpggZE=TvCr$D1j!g(_nWb5XIZ^DPPsYquiOj}vD0bA z_oS`!G~>b8vb$maz$b??{cD56`N5Vc^DeMaJbmuul`Zr?Wv4b0tC5@YsZuG+co|34 z>$9=4M5o22pJR~W6|5^4SEF3Nv91M4A~*X{A?}!Kl7LxxLs}@g`ID~X1bo4VZtEsj zsYCp%3`kZ?M14F&Q?hX{P=|?nMhqZFJlcRh7QFceD^Q*s;%JKNyzPv)Xqx?bC;@*- z>VL-z*;4#p3}tTeLTs4daCxtXO=EquW+{Uz2^5S17gJQ(C=90+lH)_tJ4o#5&uhi5 zr|h*m_!&!tx-&#I$^Z}@k{7w_dpVa>PUrMvHXp8}yf%oI4iF%$ENups+^4pA z*TyD019H+9x_MtCMAuJ3#eeIpg+xy;*eTL%mSE?McNi$fMN4X^u43}p!uHuae%&U1 z@9!4Ejd?KuK5y^NzpqbLNgqTbBUdx2)-o_NsevMjm-X(CEo%Ohh5Dn}7UUQt-=5X6@Za-zOK&* zZ*MTj+br6;nUyOFG3dUoJRL6&#C(__0AcQKxDCAOss3Q%S)MrN___CupZ^7BVIgAU zeQe_#8hO`gt?J9Et~>Bz(;m4>ec@?tyRB>ldBf-7>5sTZ@S`Zk#SS~ZKdQc!aA zfEw5cWbo6zx_Mly6W>72aP9B8D^MH#0kzuMk~Z8zbg0;vhZ>^DGBuax--9&Fyn-c? zU?MmSnfPJYB+(i6VKPndxYT|+q(QoIhRJR+j(x{UuHXDQn5uGc*@2&>W?b?(YDEzz zaAZ2;yKXIpLGbUP0yg>Y<91*=uT8;MTXS}OYlH&EV?-sFxK{RI4r}k6o{ajOIiVS< z@R1@&F1OK)Jhb|vV~%Ozsv2+}CWcoe&ntR5y% zGrR21RN1+@-bdSw`6f;5?|>>MS3uDEXVDGD3?`}#hJ_w~FNB>s_3C;1K(m8``mCqP zhll|~Gp@BYex6Pqz3Su`B0+`g1 zCAWnod$KZTg?yo_%M3!7_HWkAc7pwTkzOVYm4yB{Bt4_k^R@L~E{4uY~; zh=0P4jQ>uOj6N2i=t+wX91szcU}(9o=mJ)q<%MrHxcMjFPLcUAWNaorgYY82Y(Km} zY4MP+B_do`|Cn~cS@uoyma`{m zLqMqg$Ah3puFsDb<^H`qova> zxVYrk9MRYK_EbMJvt-RxR_^dQJvzLUkof$f6X*br;EuB_FX-8PvXi3g<0X*gb3I>= z%{=aUpd`FF*wXptweiwq^IT~>xF!Da#zq3To{5ELk^Mc%c^ZC(M==NI>_d1YpeCKsnMhiQb z12=|AZrr~+P^qh|1DWejT7v2kQxkXrr}taFFDV5 z+Wd{EBE6PbwB7m5?skjCsf{%Es|yHJ#@rh!`D=&fXjO&&2}% zzn?=y-krqID5ILc9m5Z**_2Q!^0-J2-$@kZXpRt+K0I^THY6wd{6K6ls&dDh7Vbg+ zOGAC%Eb5UsZA~vws*V5Rm#64Fh`Z@!DNtpkcnxgpYc0}95?^YxQN(c8sK~I=&lSCJ z7;)g?_i}hR_sZmu6jq7TOckFC^JVvUQihZaj;7HRK7z4Z51i#ZyDaxPtB#SJ6MFmo zar<;Lqo(U^{?%K%#jsW#!A6hb<1h(k&-!2n8?-fxpyg7M*!vbV=)L;scH*(Y@AhnM z=0hAc*AzJ{=;5N8*rZWucnf-!G%=XE7u&SCbATtWAroqo6UVt@nSe<)X){KaZkjVq z$YnI~3bmK~M(^3XLU>U8K(R{aN$hx2Iaow+hMPZw6g z1yEUJ8ua~vkccaHoJH(o@9y5^Q}c0H7-F&oIOW&U*W(?DK!2%0ck7r+AmGs6Ng+AKK;4-22 z=gS(%&Z1n*WptTyiT-x-c3F1L%8vAFPWF`p^T$i~44sEsX<9@1qNpk+Vx-uzTZxMq zA;Mc;yiW^_AJ; z?ES>&@xkZy{DuGKY5m>X;B5W;^!nJnOUUE#GP%_B!t>E$<4$%3|3r?t3ZTf8LVq$l zuotnz?^=xoeJ_{|sv;lV&E2&VdoJEP23NrJ-QaL!#3h8^TbmGYZ@aBxSHZ9VOgZ8O77zHT2 z*fA1x16TNRDSo9VdOY3^J@0Dw*3&S4e-FL0=^6hy*Q8LIi}rb0@;Zzpc(91;zT!{R zxU9MF{o<@C<^OVwu)jY_GUAiQERDv*IZj}v_wmx@hK5jnGO3z}jVkh|yN?yJlK#|Dq1^~IGI7zn78|VG_AzU5~yL?=IT__-p-wI(G!a}Tp|(7JS~|lG}?9Fknee&YG%xyTYEOCW2!7QA)-8kh!1() zj!6q|7Z(TbR^U@1%;4cn{YaZN;4>(IdFkTsa^}b$PrP=DM=*7eF%m)H%o7e^M)KDk z0LRMWIy3lH0p=Z4jz+Gq@92shEw0gE*>lI%=Iab|qFqIIBk-jq{FAYRA~?)PZ#o#N zo%p`VBdVMLb`9pzpoLT6*CpFH%-sUh@jVmw!Qs43IDR2(=n%|4M`-D^r>XqP%UZ2z zhf6$&Zre}!{i5PTSf|%B{c6UlNHF+>*$5~G`2S=9q8*w{BU8Vyi~vhee0)+cV-y+0 zcTo~l)9l&{nDcpC8`!}6|DlK!TIhe>JpBjKDaVvUBn|*IDnNMpJWC~;XjB%~o^MG` z^K`NLV66m6xj!nC5TK=!Vaf6K1Elh0WwcudCaEUD3@TdN+P2rGsEk&g4jY?HxF5l5 z>^7ddelxL8j`|Kl>@NT)!A$QVtS1x4E2@~E4NA(wZO8z8pmt2NH!sacuBeFy_z{T! z+E+drKq5~$3*A9@kqxLH@$_-&`hMf{Jn=pS@&xF^&D@J>Br`K%`P`06ZnQm2pXhn- zf&3iE)b+6Qp^YF^+TMN4@kpjsyYj*1UjJnw;slg-NS+j>O;Ecc6;Y4OO}-3U`VPEV zI)3y9%+x3BIX1SlgF?8^9!>9RAIF475j!ic%greV2gM^rxN`$*JN+EDk~dH8jn9Wq zv0p|Q9LQX+GK4>rEGCFmGBDA^@395-H8EJzyL}~*i%T72h!20@0IG_!)obBpT<_2pekOiy6?Gt4qUxYvWVa9FAX^U?{uX5@oeLz(hgL| zx!O8kx8_LeJ9jaiX^L4;Tj;4jxUpPn=zLIbjRL{Z#5ATFD^H7Ag6*EK+qaL8muJlz z?H&hm3m~u_`=aaPYHDiBTJzxy1uO))zx|>Madi%PZQN53=jL?4L}O7E>lZ>l7CT+$_OnXA;H3AN{;+<{uTKX`eIWfd8YKsU$#rh9mE))Z! zB6;*1@g4%0Y-HczDr&9pLq!re1h!|TE5y+;f+3og9ZztG1i)WOpYg+B{{%%hq=!vg-Gdq0-s0xN;sP;Aj&@jgMW^<=P%gva}=V`ucue; zFZaMfV>Ntb`QL8<6kOo^hmc*;@QSAgCStat9+8$}=9xl;}Vn`KKYipIclGx7xdJrMs_3e6}X~3v(diCYaw_& z0iK6<$JcaTW$od8=_Y|R2-I&u?s^E|D!4LUcfNXjJO{Ex307$mbi%->ERYlLumr-@ zc!XiDfG_b8aa*@q%%`X=6ss+mfm+5o7sTT*$k_Syb2OTdZGv77E{-nVZq9eFw~)f; zZ|%*l`$l3%pg|RR9UE?QJPQ60i;=l;Q5?dOvh?8hdesa()+03lGH{>ZU}lwx z2+z1(7n$*uA1yw|_`=lD~=$QhSm6<7_`T z$UJD45e4eU4~4a{h0GCM!yRf?f=Ru{9sFu0P*e*f9LP>=cMSrAeMzuOV2`Klxhu=- zGRKQ*CfXP_$KZr3I00=iF-eF1&-LYV(=UFKi%WTj0k+GzIJoExP^+CCUAYh}knMK| zkiC#vaTRTK6;9W0$KR35%M=QH2K$TNEB1Coa5)S$C{lD5x^55m?7U9Yx?i91y>P0q z7ChSP-<~`LGXS(O=P$cYUsvt`6)#oYZCz!Ol;J^9+2hnm*ML^tG>^{d8L`9`)MKe*9lR$uIZ zAcqIjpVQu^B^Y%KV{st(1e$=rwz9C*OZdZ2%*be&FZksW*RnAo62cj4HCRr@8u#6@ zOmk*N+!A|H>{3|{IqbK{wmbCOn1Y5~0S<%C`{?Y?FzuZ>Xzd=cbnI+)SdZFA_;nLt zA;e|OI!+R?lxGMS@LsQ206T$VDqMifb7)Y8o}J4EZhakLd-o#*z?Uenpn>VXt?z zk=TGbI>}D`FDe@9FZvI9@x?vd8b@Cm8f8}4=xMY_H(W(yOhvJu*tjSJ^9UzYvA!!H zW86)NM>95yP;&;O=MootpO1-D=C^TTS+j}?t3c332vOzeA_Mfa*+{4nii*mDSG{hN zX!CVGn=JL6^UMyddEo4+c8`(#V!{5CKacBps@St--j;98NR!5Z3!*|NLy=dHgPS0N z`Wn=)2+Y$!MC-DVs`et9GNF%ykJbDXqPNYL4gT&H?doLa?%U0=>W=r_qxy&S7xN4K zkH`6|KY#uhv)L|#^h$k9fc*SI&El-5-R*5dJ2P<4+5F)IJ|e!uO74^Mo2KrjQ>_S{Aw_tJJeLB>spr z5JzA`&^&lm_&e_4ccGjSoIpd0ot0m5hpU!my-=${0fMHTr7#CcegbpIvRF^G!!B5X zlceR^=CuJi9Nq=yHvMcDg%*Kfxh@3<5$P{{8q$%Uq20eJK7)b96P2h=U;~H`Fr?m2 zfzD!6)hBagPFdOJb)xyJnXd=;MO{&ER*RY%v62MYrUHZn4WZ(||LQ7=f1#dvF@sm1 zzEJpbsG;(Du{opW-^@Ize*V*8nfAV&Y3ewB5=A~K_9fFa>CflxF8Uy>i z(ztbhm6iV%fGqfWC~5b0>EUxbZ`qkGOWpknuP4OY>HU7XWG*1F_ZtO(+s~<9wOnO0 zm_K!A38mHH`qIL3yz_hFD255lg1Jh{DeHK8wfhGkg`6se5B}bUWTx1X zC5;p1MxqNT(Bf*COwR@B(30TQHz$NKP+5IUCiReCWqE4&voaM;gWb-?rSph77UR?{ zwyktr6{XF-%CdHu8aFa369mmO+6Lh~5Bt!(<&2lylDD6PsbyXQOF$f}H&PRrG?bLL zjYzP08K)91E>eIhKfBRq4T_``TR*^wIq)r z>o)qg2<#R~;If4;sUVXd-b1qVinY*#w*p(B!awcWzrrW~{&mATz7NS|(!z}~*zLW6qw#a^ zP$F8=qdZtXa@im~@?<;sUqM9*Rb@r|Q?8`PEKU$`l)e;HSZexuT-Uk$1!cn1Qwpbk zbHS1^MC%|k&`ylt^JYFWLv-cM300<^&RVP2g?lZI3a2*s#f#$SU|AjQ3g30`ruQv= zVmXkebmr|bK?tvgO*c!g;(U#lPeY)!OSh-X70Jcr{yzJ&+p@Dxt-9OeZxm}qr?Ka~ z6yn~w*Y$@k_-2c!Z{{A(Ua%>40%b+@S0%sF!tLD<=NrFD%Nc&GSxX?%*?y-c77!BRY5%^b7!cmm z+^fk}C7auZH_ufuqpfU853k^;jY8@S{Z0<{R(uC-ykh^yeb10HfHGX_hV|;JL>esH zkNhxga^_;{2$qIz+%WU@=)vK?2#L54o`ioiAeRkI7@W;sgcHozMpn}1&n1ew&TouR%)8;q^$HHO#qf;CF(nKV% zvFL*TT%lhvT4JtEhrc+hk--O=WX&au-SpF&v2rQTB$CZKEM^!eD# zjqKi1E|@Bwi%{$b?{|3|H|jnWj4%px*@+*QubW#Z)m_iS0U^ja-N5%PN#ZJ1MEk9X zn~^r6vy1aB9Fanhorl{`{e9o=T|xtEA{*3CS_he>Ks_|yHdhx{Uk@QaJB9^u6{EX$ zn;ZdF#=#(RK}wstiWbM+?VaoJ+p*!@Afig^7!N3=$u zQJ}Py5ViEych*=Fye3I=Jj}^tCXWKeKyKYr--7jRm)O-l)Jb=61yhEnK2T|Q7|*vu zeAM!*Ph1P89WHFb+Dj1(GCkJ(wUf}I2ZgL;lM783rIWcaaL{M)b&;ZLe>QVIZmZ64 zIMdvaMA612(JC2OgH2U?oS}?&>M)kIG4oFr(A#dl89nVQ1_VoHQoqmR3i77o$uG^+ zyl>eCmqs4AMd?CcO09(T*%39nqN2g_+l1J9S02~?M79PAl2`87<9Yc`l$5fdH{sE|EDHgIvT`-SNSZl0x zJy>d}hW#NkbQTrBB_-FY3?O@}bs&8%Aw=qr=sNKbpF#iZ1&v6`@miDXeb%PKCODRk zmef`i0D`-T&dSun&nD~`#{{im4Da_qpbw%uR5 zgJI_tC}}m>+#b|esVVn9+>HZW&EV8FcdtNyc2hTb;_T||jEK=taoW4S%Ew-|S%$&E z#fElQU|1LJ+WVGrfryXd;8gugO&q)wxt74Sn8-2%O zSj`{Lh@5+cqc8s&0{-a1ev3j(v~2EudTFN0djt3ehiW;%>FLdeh)hYb!(J7Gf*YdL zn?|WoA6K=<{28x8jC&H)A5$h7anoE}uC5Uop$yj+Sr6Zs1o!;`YeuEZwOp zP+#q88pd;@=t?LIY8bR~?a*FE;PjXp=!noI^LItz-kwRlr2+nlDI$!f8k8rof~Ub44&dH1^9?urd6RZVBjn}-gBgql%b7eB zO2EcVRwUmT7X}?X;@+V~@n;4&Hd;+90&%_X68dX6N;;5#z6>mjoH7O&u(;+YhX94c z#al5-{wARv5sPgbY#NLx!#iMY_m$?ICDPjgNXj{Hr0beXJu+ErZ_{HM!2@AWHgza0 zQWdF2G{7`(`XgdIM!i5&kSM#(iQn9u#D>Gppk5c{=2c{@A5@G7;( zn*M7NqKyaR*$ikB^lk6)gV}fN8R0~yz#-+^|2w|L>Nx)kaKuUbhQ{P%Z*j#D3)(qx z_biAAB@xZzX=~QWR$1i9<}z&QvE^E^BEq4GKL2(>I?uaKse2}Y2Gm~8fgKh(>e^?1iNJS{fJf z%S~!SNegF!EbkOooPc$#`>6+`CV|+&V z?`2E#*JIps<*6}=vSeQr!)$1H(O_+r+stQ^rcyR$Wru!Dbi}g=V{;Z-dJhMD$Ot>Z zLU4bzI(BlO+4?1IqXf+t(qJ?c5^sbDzh+?9@=H3+2)!n!W_z|=(IYtdg4E4lB!%GWRpS{UJTNYhns#NnKz;^BMdQ|RZ&7*@pT#fskOjV zX(x|R0693@r(L}0hwJO<49m`r@nX>|lP0E~ErmEPjoGlrz-!Cun)7gBtTDdvyk7TPml>d;p zq&#a;Lqwu)-7+(HD6vyawgwJ9V{sWk|7{?VKx^H;8a%VK9tzwJ!%#nju(qP_L_F9; zRT%xINVKS$jhx;L=Z8Z8a*Jxr|ua%XX zIq8NdsGe&$GwU4_-hMWJNe3>}zIeMKkY|9isjiY8*1}8l-NJ(yIWQV2V4TtC} zjM^hPp>tKtzcvr@Ydy1n=$j<#8d>dT6?F)zkxH`P%w)>qQhX9*$)V70MS9z$wu?e{ zaS?-leK#AQtjR8B@kPMY0;k$~#0|h#diX?f5GLwDch=gQDID&{MHm8J99VEXE%3L% zsIj6QU!KJtK@GJi_1Wb+OR$DE4aVRuY7Yp}uh$x8+-yW7ga9(-?}|HCx9r(S!Ww3> zO+xCb5=v`}hgHPKZQhTUsBYyBL&VxRmTN^(qBvcV3$YGWq+lEqC;c{8jS2#|%&gP< z<@~pz*Ks8+E-i@o0%bygGfj%hOCclm4w3#RuDVF;`OPq2nPJT53O8T9bvr@mu>e3E zU%$n@O@yJ-+tkzwrkD$O@8ER<6#1DofO|B zyGPc#JKQA9xZ=AhM?kd#2{F}6%RcrI?`Q&}Lr2bdkmJ10O^=B0JDpgWg_R(`Cmy0} zo`YSB8i8i&CyAYhO>f>W6R3LgkFH{joLfFT`pC>XB0FojjWCbsF<2t40cInZ6xOhQ z(WWy`@*JkD@V!wy|C;}4|1u=#GcVRLlGkpeEt37At--N&(UP)DZ?weaFZdi^zBCe8bax4pnzfuQ{(5c;Qqy^^1M7V7X z#D;GvI)w3QJPqmL!79YcA8swGmR1|1@@lqSfIlI?7dkwhH1z|c7zVPM>JE2gRxT(z zH7%Mqj#m5;&1%H4<-kMi%2%x}{9b9g#^Qr?hw66^b%B;DP8U%GD_sSRHzcX{OENz8 z5e(2oHXcp}FY7Ukf{x!((xre)chKwk?YDpybL|iQt;X5q>)Lt@|3_EjRhzGc{^tmM z1)l9&nOobr*MWl|1-yiGor(SUe$v=f4<`71)PzK6i42zpMAwo*@W!p5u!%*7V0snO zDo;yq2Lb>a>zqLsn#iTpMv&T_q2}8t8CnwjaL2iWQN;KcL^hup=l*(sdHcPz^eLeA zubi9VkmcF(8z!`i(0vmL?;vKgyo1Sj9nFMTJnjUWm7bY=>YuPWs!1Ma+S5fI5Xb_y zTw(uah8bjt|B8*_jxiP?YD;<9ZxD#^^B;@VRvBemyVGr^c4ya=^;&Q6425nlAr@3{ zA*WmVB41-=B~|z1@%<=>br#r0op*nd3|Ro%jb$gzbq9q?kw5<$$OA)?%7-P4o$gy+ zPW!5&%u~w@mMtjcB_fbOO-=W>y|jeet2E*WcWkeeF-PLLtEa9UMYz}y2VI_F%92ul z!y%r1ViviF#p2l$Z?Sav1ve#QLOXAM_@^#j`B1XwaA30R@D5m9?)5=Ehy<5Q31YXF z8Yh3LX^60~f-b)_NSPqFxZ^c}BQok(y4|PwlyHp$+Nkc^nGw~euDFqgcTT4k^>mL1 zs0QKQ3~8nj+-M%e0Sf}?Q}A2nUP}71c8Z3N6M^E&f&K# zby&ec`>zJ4I$C&ULo1ve@cqSbA6&V(L0djV-KFeAYJXiI{(1~tO#HD#4kpYck8OO% zwD8#tWwj`AWafOk2z>N%mXuSR87vBJR7Z1Kl3Fr!?z`6f@oAs}1>w0L4S7=JC^*;; z2`8GsBOnLfT#d$NR!`!VQn^aKcIDEa&5EE4Wy-u|a40-WK05e>c@Qa%d~iU$3LNP5 z|JGh6AiyU)-3Auyx4*bGDs9@7xLaurv6lt}xk$Qb|`h8tH^MJC@nM zQ)~yJEO#&MscspImP3d0iLb#*WvO+qTCbprM;b*23;Hg@UxtF)?pgU&Ff0nDZtGB8 z^9z^wG*Ny+^ovHcqJa{oo<79Hgh|fd;+SLT`1QXseLJo$bD<{4EP#aBVkT$%M+&Wy zIb@8avB4Ri1U-G++)Do&#Qzn(N^!_E#PQccVnE=*Mv6Gw4nwlU_xQ%@5qbR?-94a&fg6+WuH*`~!9=3Y}1}kcXwE^qmK%Db7yT^aB0I;dP zgQ>DD>!1oOk4YZv=(ZN3MPs4dIWSU3-;_b;pG;UHi1|+y7n;99#-TR!^s;13`B`zl zB*32GJMl3HLVw9J57*r_@D(7kHwu|lA9fKX0Q`xEN=>c$U0p7m62ACmdQJ5GYvy)J zo@iX{RcNalQ-08hvA;w{UDGG~BY&{QXqrt^`X&|7F!EI58sSR0X{;dalO+>)JDNi_w~|t*vlEf4a9pViY&nMJ$_Bj3VJ!6CxaaUL{j%(2ktLW$ui&~frHq(!N6>S3VigFfh*rtWhx);?-m`d zq~&>EBS4Mj#0kFEx=S#fEqlw${>l4!%&>8PRpHA5dp)TJH;SJIypQ`LzMU&kT>))3 zz>81Tl5OtcwH?!Gsrbitzhyb`G0Fe?$oe}MGnN{4TpeoCel5IMslo^J^J*oU7}U}7 z;`S>Yg0regpMx3uvu@HuR^ME5*HQ1pau+3}2XCS>aqeaeUi@t9f2lgjC_o;L*BJ<6 z7e*~FOO=&Sv9ORKBoV~^v)+Rv5D)MFt+up+PCwE&W5wWe+UoDBN@Cw2h|dJ_`}P&T z1PGBHWQ1P(&?L58K?*wNW(QJ z6Z!Pd?1Ky!ZfE_2;m!W^h%i~}&rDrr4;^>VLi^a}5}pViN)3IL75WuL7eI;TnR{B- zue? z5@te^S%oVw6ZVR#CC){w*4SG-j%S`CvF`ZmP@hG^%T_tIVzn8I9=y&|XB-lm2ypon zuX8Pef?^<}ZMZfR|97v8|JzCMjY5zg!Hf9$4=@|$8hX=JTrp7`YL^j6((H|sK8ZYZ z1lZfwLfXurr#B;%GhI>lC5Pi?nA0?BqgA1gnt=*)CWoR*#`~ksn(GfCVi=QmfLF8b zK6Q332L`DsF3YF)EAjH&lgmnVB)e;T=6(o|;CLACpv{-1Ap`+}Kx4uA&OB0PDi`hp$4Qd`7R7Q#Lana-OJ^W}K@dOvC!cES=k$D7qYQ!F z?_N{^iWzvou1|vw=)AdH>8nh}k4W}R#`8qrBNeR%QEaxr)QqMKxgwb>&ZA0Hl^M#t zpK;kN4Tc&n)7gS?1FOJR^gp>bXpnSM+>LJkd{1%xWjhK=FA&~$Iy;tf!d%RG@JmFa z>2?O8|L$yCsGc;vmjT@BF;R?w4W8KE9+p-Jxx@V5b?n1G$m``6;kOsG`#2exa{Zi9 zS-9U~1!9Ca%&P#ZM}AO7#49_!fdCo;Z<^t@GtJ!T9vCnZ2o;z4QL22dT+(!|a_opX zV{Nc+`}+)rW&~JLi8wfU(|#IM)9PZQ&@O!fc+@CV$)*K8dcT_(dhQV>9RN88SWK^c z#vc+yPQPu8NovDTtTq*+we`4`3;ii5MPN=*AmE`ThTl#ER$18;_w>je6pvBuhNx`9 zm@*9zhP!vf^Pl2qel`IQ(}y^)!%8MYzZiEugKBsP1j4SQj* zdZq~annyRA;kwFrHc$^}<5$Giocd645**Xj@E0Xye}Ey%|0p2mdX)l-*5e*+F5RJN z$bK1c!)pU7MGaCSy+#nLJyIB*)ZjY9YJEzB&kxGr!YF+jUx7#ly^9Kk+hYT(dwN2vQX0%2UPg^|83ls?7+TO4RzDiES&r?#_9n5(}L08L!8dHf!n*u=A5?wv}o(w3KV|LLmnA0;Y|nd zHDblU;n#+l?W3YolSME?hn!?Jyc%3Y#KqzoBn_2L3Y@l7DwzM(GAFykgA5gD5&%NpmZurS@rs5h zFA~Qvq?+r|(rZ1ompo~pixc|jh4Y^{m`Hij(}viv^BN1VCiDqChP4Ugth*;^L=@G1 zTn?p4H!}uUR1ZW#KgHA^^VRJKmW>;P&h8EF$eDj*^+eS-0jG775@<)c@apsChF36m zrZ5R$7fkT;an=qrlaZqbYxxk1fY636=8eD&-vNAi-QOqs7xke0>u$K~z4^x@Y#$t4 z{>M-{>RhcKHjbX(Z7c)a_+nkE^|$=+r|V5GE-vGu(o*4XJ8!;SbsIc3$^#luk*bi7 zSSSa1HJB_)c|j&y_HDW0oya!a>YS0kF};}6Qx85``!GB4RZNZmJ4o7hm2l-5v&j9% z%AY;1kEYIGLX&r7*V1cA-BOjBxXAe-k1edf3?W6L=CWCZ9`P6zkTGx?!E#!jAA@)O zYDSRdKsYw-$syh|!uhI6KyvV7UP=8s){e_HNAIZLSB5yd*zX#wV86ept&wG}o#LIB4)7*M zFLzQ%2iG?xx6g$!tRCJ8TOwTQVrNVRVNqXCafm|>waA`+s`tYyDlj4Ll#Z9mTrh0&CS~>op2GggJir`kDb}gW#few3#qT->2L^oA`!X&jE(PXV zG>4Vr{x`&O{}t297xc(MPRs)-ce&9_WTKosDGA#FDl2gsoqtkY%D+qMj7r952B!$n>DM;e~DOVDY6wF;)gcj-NlHeiTnabu^yL+F2m&JNqD^&3u{VLVg}otk0d79 zWq6A5=QK5Z@R1wK4`NKOfQ_jJ=p@~rC-R<3NzRTaO)+6#*oBMb*Z*-e!1fF6^D&EZFq?yx)}<|B8468_!Pzy|p=_uYLGXy|Mj+r zS3AW;n>Qi&$hx>pa_5Q$P1!Wc5zemxjdmfp-pfxGKD-fawTUy-2bKq4v~np*->(?S z)|W+>I36RR^vltZFc&>7uq0>u4265pARzAGZOcGRG!w6D6U8}xu}^_^W!kLM5Mz`L zX+R;_fL`uangY^qP4gg+42)YB;@2;v*f!RTfYll^(c$exXd&gQ;1md5l#%b|`>QlN zT@Lv@mA}aQE=>5@mGs)ySW}9=dRDOiFnfTC)mVIax#;qE*y?nHm4aDnqT} zjBSV5TbTX1KVy^iQV|#{ECq z@vp|FaZ`FoHzl-ZwnT%ow{RF(2Gti5em^dx8na$<7{n($phBkM>u>9{;y=CB4o0yG z+XnKo+Pux|xJk;(P&J1NH((*ynd}0n zERX7HCd6NkYSQ5V4r@+_L5q>`qL=~fUK_OjwTiX2iwaTriiToo%q+&DQatfraRiSs z#+LiTJgvWUwHm5hN)UuW!1%d&Sd-WPNx$Uux1L z_Xmj=wCqv@Mf_kVMSfZtopV0UAiWiuS_U_xquo%lzcJ3;3_>b|fKGiI~#;L=r0Y<7kQJU^3$;*Z%&mB>l&kL7Cebl>TzNj%a&q zxyiJwx0TCHz@tl3?mkby0~;rM#>BW)`etZZe2+XyQgmsy_0f;GoXlVSxZGXVXK)ep zC{Jp-qNLT~q_sfr?Q3gM$2fe9z#gwWw+wAFIl)QwZ~eB20wqAUSZ#lc8XRdz*=Zg-%6ve^cE2Y48ac2rvS zjhiT@lF`=(KP0k)A!3#^9+GLX;d9(2Pg%Lii3;4vUfD@{lhumLXNTxY5{e0$mhiD- zSU@%EBqNz4*-pi*uz!U*pI<+0y=|)227nCA(<6y~d{ptt<}Iz(jr}yHn%YJee;@(* z=oxU%Ng?2uQ*$0^u34LqS|k)Nj!!uAjs18{26YuhZvOk~YK81tnr44w8vCxws`q#R z;7{w;w_*)AS#r23lsp*~-ZrXvds}x9hL1Pk_D>d2XE%;Of6}`gWt^^8;3GkBV)lu2 z=JreccWUtoXhWRhp!4XQ3{S*TQWatb#cmmAh@M)0)gh!y}e8 zRb^ZnvSdkzj6ep#R061@R<}dv_T;owca=cDY5~yuqD!Zow8X%}E3HuH6b%4;UlDW& zA+ul%e?o;cDxMXPoA=_-!_!zBi(O%YNeCOTjwVO22Pp?1`cf(FUt(Rf(dOLh)+mro zjZA{0vO}0Q>C+ecv3>mt`OS61ushaO4CWSPWqj6uD7dwnB@jZx$|R zcX~YWBmQ<0pwb*1)x|zZDz?C7jWZDDNol*Fcl{hSgLmGt-|Qb2-QI=5Tb{a+`hjN& z0m(zNqSA@XDr_W~Llp5CdubB~WHi3lhxLoe+=wL0Sd-oQeX1~lZScZY{~Np0>c8x` zf0h3L<1Vpns01as_JeN7Ch;p+pLA6n0lQD`nkr8Cx%*2D@C^!Z8!UbT%J=ahe*IH@ zX&;;{_eJcXbr>dsb3QcZMq(8^C;?npFFwm{d=eG_<_UA`>rx~JoRV-j&cxsc=TMJy zljauk>&1M)pWurUW9az-4x}{#Yu%Y_ju$0xf8y1J z;L>x#k?fA6fZa;`Kn?&z3oDyF5#D=W`T)Iic&-FTn2T*;bQ6mzv#2v@lD-?1Ed$Y= zgYrFwEfi4JEG@aKD1l9;3a$yc{Q?L!!f682&!jbaJi)?GXlD%9_>s0Q8!0)AVQobM zm?8=MT;6OQF%+Mf5F1WbWEbr#*nDdAxDi2iP~p_(PY*0nlh0~7gNkUZ$*`Jn5L7tf zlDOC0=EbXqzUMyW^w9NA+&|DF%MFNNxQ^BLdwXehEA7w-!4ezJTL%z4RWU=^kCs7f z)^f(V^2ka2$;=C)eXihe9!UnZ&*$S(n^izfNxZ8yZks*=O zpkNLX0Y0QiBFcDnN5qMKzc7Kl zbGw5B!`WZvW4qn9kBOEnC2(@%Y05HCD(O(n4Y0oSh%mNY2%Z|ZPZ}G@HdW^=BYl*3@Yc`c!|4;X{e1La*!b^VoL-kQt*u_q^wrd-8!{wk z(^Mjo1?N@s`odCLlBL{oT6lt9ZyH8r^9GX7M(&bpCJkUFo&H0^+LlZ4Oh3_rz+xl! z^bOLCdCAG(I9g~|iz`(rHJfTEB}GKE%RmSag7G^{`DOE3=zpPsuvX32aJ6cWiq0-) zX{KjnY|(GqdhYYhsVIGF(jhC_sSx%2KG*{?Ag5v=Q)oi#!>w?TYle$rw6W~FT4pXx z5j3g;Iu@*m!sCL>ki8~+_yUv3tp(t4>Z;U+D346o`mPC|6tN9mAm{Qq-gJeuv=*Hz zrdc6M7n6HlkyWfb<8(ADs%_gX6tZMVw~m@od-m*ChebYa+&f~;e_gTB zgKcUBKF_0TVVVZQQF%$VL*?(C9bfN{X%3j6ycPEowRCUE?DycKvkd782xWEQ@y0!b zlRt$kYX$2IkBs*>5O_)TrO`#zGp|u2* zG_^KlyP$1bK3yb&l$GEZ;cO3ge+3pi>k%H`hLdBopj~a248CsCt`N-}H+_??(9G|e zSreVWiN!I#dKg(CmM;O+|S0SE0_j}KYk`2zmn|L4O2tOgvZ4W+d8K} zF`(_Xt@^1H}Hx>q$K-uAw?<#w>)dH7c3xC$$H5JX#w zXJWTsz4g^j=WT0nD9V|Pu<+<7!OW_i3W|ZVM;DRRfTUu8k=*q*EB|tUJ-j(cfvd}i zP2sPfwKLCs(!9+Krrt7#qGQ2QjsX7_)-!J>MT#@tzB?IlG54uU9!i^0T{9 zOIfm4VyRY?Hb(u$(V#NJ{xw067=`~1r3%Gwk*bs+6n=_>TiF&#KIl}sP{CfPsHQwp zjQ#Wa?b0u#YW4YNRXHJc#v3V^2UkA@DBdnb%RL;}kR?PREKk4oHAg2Wh@GXDT&uJp z*U}P(s8_u_yy#jH#7fN7ijKS%rG}(iH?}hv0uA?Fj_9{O)$S3I zs~oUm(Rf^PI+&7kYYEIa&Gaq!t{cQ(--L#)`U5s?k8;RGSlu{khSes;#mt|X9QF)8 z5l?;-#`zZFi8sbmgiqbba|+*>t{$ow6So;@+TD^dP!`~U>Dp`wv7q2S{Y)HQ zD%Vqh6+N2|sfagKIWyQnGcCA~D#~rzu`bzc5g%`gEtG9^?b-*4QmHs&HopD;P|25^ zxOF8JLFyo=L*7<6WZ4(uZNXN1h76J&C%U&>Tk_dQHH52)tBw8e#!``qRn%A=1VN`$ zE1IbcKS^tR>NOL)UEqZBMXtIkE-xa@u7f#XKdCEw*M*p~0 zQ0IduzzLrk5&IXuNly#9{5K>fF;D4f@-Sl!f?F|A1Zo!(5S9#5WXC0TS`##~6+o3m z|21}p1iDSUuk0zl)8yh(deo*H6-jkKYUYnRHwGDUL)Y}x>Bq+}Zs%d(48nf!7>#OF z3g)GPJ;z?_KLyb$FZ}vwO3dc#YWzpv1mfYF0-B!mBXIXdF@q;wj0yDn4|o=)@-4q3 z-~1u`b7K5&9ZWd|(uti$^-m-5rUfH2)I@b(eCHcCoy8uwNulnA+0fbxJV_&Jv~NoR zVnc>Ra*+C+O53qsw~KFYh3AHH;33Sy=asHxNFTT0@Z3euOXI#EnVu1y%!zD*JlTp@o-3@ZBajZzjmuHMyyUAo9nHdwv0R!dZyyA)e{s-U};qt)J+k+@3<(u&^p*G}> zTAZW4Bn2*EP`etK;b&62Dn{OXUHuaa*w}Bdn#|rZ_dRP;_CuuM5zP#dq-KhpSfozP z2-CPBkUUgGQ!#hA`1385E{x^hWGqVQd1T#FmJdkw$mmpfm_gO8WyJ`1C2=E(NG7``TINQ5WBBAa>mf+zKI~CjAhV#nMdrI zPKW?f;&mak>S1}BhU8R!@m(Lif@vW9e9|(;38XPw?(P9$wOZEm;Hp$EYfv+&=MdH3 zZBkHH6E3xye&~(lNO1*qE>O9ojTak(OF|6}9$q|WJXthN9rBMm#)VY`njPkAQ-4>A|gOhC+h~}1AC34~f_pN^r zZ%F%0rNn}O4?Hk#jU{SQb4MQQ+VG1I2$ibcINqqSFEZ z&o8g)JLXAW2IBViMF=OmyDi3wrsXa@~YV*e&k22fWhT%Yt@EdyPeziem8yL)G1<>e)(K^P|l@zi`ifMMC41(ji;Rbb9y~=~sgW ziUgP*^h!s=S!KllQAZ2$bUii^ojI`$gbd<6*ihy5ND#8BvgYc@H~km5@K41J(m@*X zW~LfH(Mh(U@B}wuMm1A9p=`QA)WKp|mo(+XA|CfJv_gJ9qc=cNhs>n<$$SEZnpF?pMK3a;WeQx|*4U*1FkL#Rn!n_xdLx}1# zAA9Dmkg>;#T+?JKDTC`JGD$6we=3rmhy8>WQmF-h3PXV1#0M7D9S9Z@1h1+{HC$Ru zt+KUl#9J+rF*;6}_#rLRi7fD3&#zlfFT?TUko;9{5L;H(73H5&++gv4v3??ceugp! z_lV#~1&4+S#ci;O!vJj-VhbNO(D&zAkK%z0#CJO)YH)P$OEo3dKNvL9%bdn2@rvY$ z6Zw@t(glz0b^aD`zy2u49oX@ytgu2-1+wmo9mPzOhF+Q_pD%_O{y$a^1l=%g!jhzI_grB)JIINqT z1ww%ptI}7@+!CDtusZCEJ7cyWtA6Q6;MTh+M=Pq`+a5S$J0;mD7D#o&f|Rr%Y_c(V zT3gQbciAj6lG{A!h8rN&WJ#-fKDjLEf|zHmFa0B$tiEQt#>3pr#TF-d^;TT7qLq*%-A0WcyV=)l?p~ z>7{)f&XCqaIc{RT^`&bMwHs4Q^BSi0RW45)8#PUQ*TIs2lO9Zboqqs{=T0CG{8~yG zo`A`)cb!pFxxU-Q zj4Qm66O@4o=>c3A_Q{PO?RKTq5e@M9;FH^vfsjg~E$XhRL6f!#)s8md#cE~nU7SH3 zJ=XQx!wxtxVqmgn$F7WE+Bm^_%#e&KZPgd_f5zY6)aO-kpwQVp)=Zzi<`q+p7>$eH zDl*|%$RFa&peslu4?r>j42>L>??_N)3Dh!4e&LpI;IV(wusX0{lkd`SIpe!vtXN|E zN)DDRL%JLYyO7ITBG$=_08?j5BYHAlx$HEpSZT}%Eilt@EWg4c?^g)bsj6v2QD1#R zXFLq#3bGU=GZ^MwU&N=je_gUa68Q2|T^0;dFXg0+GUphLUtt~>8r1+pES zO*$bHbp{)?g2Mo!rExa8^&*&R0tLu?nRaBXFLS&oHWy7~BM@aV!%sKCw=%(OuwY0S) zy)tgX0Ya`F&ssL*4Gxa-eecq@$jnGlt*c;fuqc1ed-ebTGFGR>XDi0G+3oszWRJD} z{|K9)xqv&`3m(Of*GEmZF;B?^#T71NCSm~|Hg;FSq(yGb`>O$9o@ z_r{tDhwt<xAEf=h`4lo%8wYI3CNM(!vE+UpY>*-I0h%dDQX~N6u6E;u3 zaaSD|@MSx6Y;z=tMr{Cp;@yAUM8_fj7ET4t@93AUA5@H%Wx3O|X1_STJJHgE+t16? znfa<8?kogVK2gaCd`7t)*ouQBH_{NAf5I*3|AkvbhVo-}utO~l>yaQG!BHQD+KglC zIh_R(aIvI^r8uhztyCW;w z4DK%yP@xwx_pRkj3NEZxE%T&*DsvBEVuA!F0Oi3GpgKtuV9WINP zt(rN@V{f){E?k8dzSS1gaD+^lSMHNI!P`w(RuvXN5M6y-!4W})|G=9-)GM2TjaW@f zLr^V_Vd<#d^9rJ9F-Yi79gD>3m2yVpgC8+Z44%pMA!OQxF80j795a02soN>clOR}Q zfAK-@mvnvV=OfFTuxw~t>!fXTgtp#bU0(jmutXx$*D><=UR2o27F64HsX@c61`>Je zr;eawMKtugxj6FeXAwE_qZyATn;i_lX*gGxLHlT4o0~|)j(U*~8U!!d*nDN0>GNt5 zf58d-^(TsiVPwSymaTIJ=u*nU;jd6S{AeA z8?NZV$7QwlZ6Qwj9H8UON2X{5N51TJ$TaPPqjpC`Bubg`;;iNBrItv3W7X;FLIq@Xa_N|+Z(DgxYx^tweAEy7{r8;TSAICZ(z^HchLd`$Guu!Q()SZ?~cgauCrEu^U; zN9=S5gdJC6FED-S=U3XOq@UN`j=~e1*65}bp4+*e6>enLhf}5>_=Y}VwtX&rWU>Cx z&;JV0mk|$fd(Wl6(KNW)Jz0l&Dp#gFjY!HZ4TygIt8J0 zs!jy*;?P!MC8wP!r(q{k9>q3gkb)6EEWXBKv+vq^)jkn8a6($9JfBB`4bNa|%>&nZ zpK60gKC|j9AUXY@OK!EBhb|jZ_A{~$V0BLa@tx(kbm+=2E$B4RIOAai?dS_|vu49K zTZf*Yo;c*l=3|m~HyYTj>2FNP!pUjc?w`#J-@xLS2CY*htaS1#i+_6}9EAN0WTK_; zthR@Mg+HprcI+8MnRyr`gawGN)=?DG?KWfit+0oUYP_J=Lc+>|8IE8;xnFUXRn~?6 zrvoPe;`jXXWrRPmfI^|td~m*hO5-dw{zHLLk=?g|J-0){yP6#Jf9vwL$WIVT9bUBp90fZg zU=AeE_@BUu2Ugpqjnfs+>hq?JmOw^-*8e7x-T#>aiW2n}GqbdTY#z{1A@}A>$(B2a z6Zh#{yP7BM76sC`p3SfFyO08OG*Pe6=e1w8P^@ph%+L}Sk#IOVf-cOQY*kbhurJ1M zSb*I@4EQMaWPJ3KIC2*lE!-uJN+|Fejo3TTjE@&Q8=U%D+=vOn{Lqg-qBf6%T*4y8 zgcIP?IBGnDR=0Neb3g((d2Xhr;!5BWN%7nFQog(Lh7FK<${51ze?)Ru78=CErfQJu zO4m~Y+@t%`P%p&Y1J=u?(5q5r?X{vP!s}OrFL-&dJS#3(7Lic_hCK>9v@jA$BS8+k zt~}e@`MmB=_n^mjJI_gff~J!HX;uzJ29t%-6xzEgyr3b8Lw^u&LN(Z0>PcT1yu2hX zywu1&nWn-pRP4|X%kYEmqJv<@{sG*l;n?>H;wZ(zNP0x_A`d3 zgov`^7Fy$J38lp2S!y>KYQu6okKT*}WnZgN^1MUOw^tc@pZgF(;dDW$BLCCFOT(v) z%@Gz31dkeyDg?x?PZay4dgh^R8~`UevvfR+SP6@`K}HnWNI@+8Dtdc;O9G9ZD#Z)d z;-CG6j=~hxnWw+tbhu7@4RWxL8%n{szIg3{zo3dOAbS)Xi!`93ZXi@~lSmSOw;*Ry zk@dm0_Cqwql%Q;yYxb7p)$DPGlQc3FVkWJ(a|{R_WXdmWjsS1mMBv&Qqdc96)O+O2 z77S3`+UrgrA8D;6<-(rvP8d%qB>yR=pY_yV_?h2!TWz0-Q5(9+Dwv0$4t4M8V1ryi zOp%J8fD4hpP*ED*zM$ze!`{XHdcx3x6Q4u=mA>WKyzag)BYI!R_}oL~mA*XX<+W7m^80$EH3ay; zNmQiXxmT;Y0O@BIQxt{PPtT-0xt=yDOn}hrKJWI`;24@5!WB-uPgBP~&QH(t>eX`S z!LW(rf96j~hhg+6Y2qLcib->*%6Z^UFl=mLNzs#12*tAJCZ~>(i$dWsg9}Yx$6p!A zLDq35NG{6P<3{{M5G;j6gI}lncE`aeL%JW7k+(%mX&y&mueKBJN^tU>wnwdLh7BP+ zb<(hMjAU2(I9Y%t!Ax|jYFe22L)30-4;Jp%Sr0UJTxT)TN)we3;(MkuN}FWkuPEDW zEUNM4>oCVVg{7fCDf)+5+G60wJoC&z0CLT{7(D0^k2Sc|imhq(ENh6g+8QIMSl8hY z>&aPOGr!^@we_@I7L0|+Uv4_}ja#(7@PqGJ~{YlMOM*0hxl?kMl z03@Q$eA>9L*_8@aaId0#LYz@0XETCD4vA8m$gvr_FKOX)L}xdgrq*;+ONDxP?Yjr( z0{h#e&dY9I-uu;10)@|c*6Z5ic;}_0j$2))%KY|+i9W&}__BL9o#tja-GeNRncerp}}|TpOnCh$#U!>W%r<`WnSSve-7b+d-5@RS%G6Sw%@ouJtk@QI}z#q#Q3j8vDpwIv}2d1YpVgUVUzV#8>FKWt-jwp-#?d#pCtAT0Gk^=$m5UmF^ z*pdhui1orp>tLGw1^qj{V$Dfb$#W?76e_~!9Oj0JI^(WYb9Zalsc&Le{u}Rr>g_#w zzK<-<_gXck@nNafQ8hfe3A>apHn34ZR8(Ke|A=A!@_BzM#uY&R;;F{|q93&pVyU8= z`wIiUJl33rPZcbiEp7+|#EJ-KP+nV}Mgd8zblfS6odCi(<`JvP0q5u2+onqAUDW<~ zrY1ec`>2igb5Bvxy6frN;*!sMkI8%I`di-m+gS|es5|uJvm(d+nArH8ab8ST#`{LV zfGw6&SiO$G1h+soMeVl7Z>ktpWmprdPjbdLTG?{oBNMhSuH>oXY6)h*QO2aeu58Dh zR>iDSAY8ogz|u9F4dNBb>qLelCBSwiAo@fS<5D+FmU$N<4y;wlWbj7YMF>XnqJNkY zl<&i|ngp90m)n+-HhV$k?gV__JmP+U%%08dN(oOo88Z#+uMRyJtFoNf$fGE_jxtx9 zu9I-JQ;Y(wufX?GW0VwGi%dW%X_az#xoRJ7q|R4OEZECrZd@8#*y5$8oryY7!xi%w zBBh)*PW?!1yzU`6`V`ep>Y*k+T1|!OprXE+*B|7@q+pT7!{=X&mecANf>x|raj*&3 z<9kffeQ&Fs$>AxdNVV6&Yt z5Xo&GX`&vTOA5B-o`0=8?hu2SPji6OnXYkaDhK&|3F@@cXAgm!w_%;fvd(wzck@*i zA!wh6y!*AcjfC}wGZ4Iq5SdJhhL2!I^mT}D>>bZzQLF}?IWx!V zs8u2GC28aUHl&^y*L{T4-b2U|=$S1>~*-%3<3WVU?(fd(l;!T+JlSkS^&T!om2( zHX&&^96P9rx1dvzs|xi({A?L=-TP4A(GYqJyF-}^@2lW8kVM5~Sj`+&dz2u4YAPzJ z#njPj>dB4c$M=P^T9AA+cx79Ivv$bYojI4B;G$*%SD?y=H^U(3kI@M_HC%Y ziuS~#q>25R zNb69hVsFazPntj^Ga};p$ZJg1S4mZe?OTB)c-4y$9k=VW^_P_O_jVt627r@g%h_s7 zmMRJ^_g4IjYaiVP2M-EY*ID{*i#1lv2HMKJ&)q&Dulr&Mh@0uwXQt2da9IldL5k0# zUm+7)rzk@&2AL(Qe8()NFi;^H@>hK&nQ&%(k0k=5v`y0+LQz3I>P%wm{lD}EGr-o$ zfj5bE6X$p~f0{SJ+`fcfCFo^$^UR9kxJ2Lp!dQr4$OwZ@cy5GyG$eg5rq+}gfYeZQ z+{Fi|P;;ljdl`>A5QvDgT5U{6_YH&%9~Rrs&B&`n8a9L2JTwZsq!i)pF$M`d!Y+L7 z!VdFv8Oo>@ToJZ&&`RxUL7efQKTzvubF7P#A{ID$1+YtQ|AgdYD5$lX?_rN91rL?# zGsh7WPxi0=(Kk{=iX*?W0j27c{TP~$C`b&c>nX$2=?g25@m1k*c@bp{6oam*JH29x z1xns7CnYm@R933ZA$a82kT?kwD?bo$6pZV%NV>VWAF$> zQek4SOlaUcCUhQHRm5r7lr;@$XViDvVOBq5jMQYEShF#IqRf&prPvm02vmb~_X^J- z=@R=5jvKdjkBg|i4ft%&^ShsC?3ynka!rtNSyl#%2Rw&5!AXFuM3V!F zfnVo4Uiwu!FKZz`)JrxSSc%_Db;Z@=@H~F1k{7m8pA01>br&9ljvU?JQ4o+#bLqWC z->iygNxc(_fzmaNBuJ@@Q_J;TEH(8_j86zepO!MLsCBDaJ3FJF3zs;;8~be?@1sngc^Y-0T_05b4$!NO3LLEra=#I`j!fsEwhD(ejE+V!?4U_E=q> zn^ZsOx(d8z5mb7Dhkc3lu%y}%-X?nZ=%!Dh3B2))$Cq1Q`p%eWA92RM(8BZ~+iVtO z9{xc1f|=@al_ZC`S)A`&w|lBFkI%_ackET42cyUO5-$31^Mh))vSw!?Igb{;Cffy= z@?r#zHuKGmISyT@jbDED{g82HN#wu^)Nt8K?1Ko@-MqLV| zI-D5ek05)Hjc~;OWO*zW{*|Uy) zwjkLqkGx4rA`0WnfU_q)5uI;JFe`b++ugNpvn8N++Z$H1*Z2d!)k{ELw3P;O6Dlko6Eh8T3M`UGBO+ytm>|jXw%%SP~;)Ia#QW> zA!md;`h-K`IKc9D7byk=)B!P+pDN*n&OZuU9jAG8TbMmV>8R&k^hH4^uS6uH|3}L&W9{lHB$YL`Gsl(A{4n#zMXg zj1i+nIii_r5N$%{j(#tpBH$ZC?!~dv4}n@DNCzwC(VfM<#S4c1WZ4~(DQg9ShX-|Q z^d4;dGnz05=10Q`wVWeo!aj^`LjVzSwBb*pwUqBL4&xYaAS%X8*wZrtZ6A2-k!Y62 zP@-5A&}#jdeckzZ*8I>u6~MS>#W@?T&fQA$lu<&C%JZt}zO=L(&h|janbCy}2&%Mk0ttBWn zklYs3CW=B~mW8i(RgO0;^0W9{v(CHD>nZT`4wQ3z{DjFr-_^r*e9r!I&mJ4?_W7*{ zULoW?Yq{A(x_&TpUJd&^WxZx_yPSF5bFX)FaA>&nxVPU0WQ`lE%+E6(0eNqM6QuXG ziO-wO>*>2ATiOS&KcO*kvhY#6Ke=gF=Wy>7)1z62j9-bfXOrGnR#%mLYF>7H5?`O& zu7DiN`ddEBG*$P7W*zVC=bleP1M?BPeSL0NPwlS(m4wcF+)&TJZ%jO{r;LD)Mg#mIIpO{5XN>K0UcuXS3}L!Yyhoz|yQ_1+!R%#x0LM>b9`BvWO_4%R z`A8_Sp@Z@NDSmo9+=1PO;y+*62t?w0KhBbcd_7m@Pm|{Bq#~cxd1#6KCs+p**3~)T zzbhdBsOMVIr5hytP4m;L58Er$J43B{F@IU_kmV!$`}JA!Tlmw;LpSag?Sa}qpIb=c zUhEA1P|xlZrH6TU?r zGDA5(L0s1Tb=!N+U$PjK`I63mzP`afD?`N&b@7<@^a2(5$u0#2 zjQ85l9PclW{yy7#UEi|*9j?Mx1CjrEa!H9CoIkz>%1{>1 zf7U_&Z{`~?!Q*{8^j}=LKih@h$|?G*vADFgOP|=g>SiaG{rAiDuB;;;Q$BwD|JCB` zypONFhAb$pe<0*%uI_YJnd`-&_<)g_Wbz?C@hgj6PV80P7YGw{IJD~lAtUF;<5+%Y zWb9R~+$g<9v)Iq?(33UX`Oh-Kq1oL2ADsnrs>m6soMWr95rt6wZJq)5#ZKiK>z?)ase;^tw@B9SK9`p z*C7U9=k-fw+^X2xP?CRR*82NQGy9tQ&QPFNo=QLc&!ZF1#QU@T^)U?VOEF;k&8XQR zfTW6#O$hE=8-s)0Vc7i25Z8$&2s(||n;Mnrz$ zoGf$aNqruZv<`{JZyMfvRc{YHmbR`U$1||FFZ%D|PHpfGcBQ!RD|m)$54rg~M_AQj zrWndt3w0budPwK-y&Fc0IGPj;(%w*M0hTUgBuz5c<*0Hk!URUoz-6Bei}GK zkHMQ@$;N9U!@W?}Lqex-Cu>ZDdm2|N2$sVb7Sk6Z9O7~Ah;;5Ctq zD?k9YZb-j7)?Bcdz0O&~{bRf}^_KIzvlRieh>h3n@pRvX-|<1S+G^i#b58wfcwx}b z;L*ax%4fS|dKnSU1WF9SW`K^!PK5J3Ct(xmJ zdi_{0r97lcA;TkrC%xNZ0ve8#Vti}LZw3`d%i7>OQD+N)pVo=g%4UWYUF z-^*{gF@Eg%@$n~=dlif8ZOol&7;DG!y0lln>mI*EI>=5fTkDEw`CXaO$`^r>*S;B0v)K=sW+|1cTJUL7Q34Q%MtPFmAhc> zh9B!rPop;{E4YhEr+wlF(v3ERt_R7T?$1ewAM1YL@g`X3AJFCL_`eSfEv6 zH&yQTHTv9+)M_*&kHlV&udZ(nB4&Jb^4QZn^0V=5=O`Q1s9_I>x5?yd^!B(+VpzA| zPwIh+{<^}vvg@$Cw%pgHgZ8{yRd3Yk;(a^faNK!$Ymu6Dd(-SvV%zf-_ZTtj>~L1QlK}u2 zNd&+Hs^q0QoC-DHJWGmfcWUu#0!W|lJqy_UNx7YMcT}$*yEM-8skz!Ko7?dzjysuR zZ?kb!h^T;=$zg@g955FKTH4s$yxj_ zTZcE}ZENvU*I94J4phAFXB4e9l4Y6{9^;v(9?qxySGW3x4s&{<7t5pZY5e>ul5Nr^ z%k$(aV;PluW@tT(sXf_zwTK+-rjY-h4RR zozb{U+Sarsm9q{2K$G|{pf#wz9o;@A=n#%11p>8kes@x$)knE0tzpCG^027Cb+J5t zPJlhczE_qRgU=T~4xj0IchO88pLC^$TCb9pHvT&Q<4XDwD@yqsk8`Dkkq~2&L;P-- zISPB?aBvj4{~T{<+=wJi@~9!IvF-Y0dH^TLD`{LSkiq8_cUJf?EP#~M!yTu5rHS@& zFs@%J^5lfUM~PrZ`1B;)!n^M2%tOiw5};fC+iq3&k_^4*H62FATD_Z(yTsY-b(>U? zc$wmD2%0Qps%>4TFG!bN`0FfoO3J@4P1caPJ{hb9c^Wb`pos~5a1n{ZsN++ds07%wz^Ke*{RY#lyiH~@o+%xZ<#{zU03?F%^tP30Foi81e?NzU;=gYm*RtzFFH^3dCQRr^ zt&@3dQfzyDISct}!#^QJWo*=Rw`5TpvH5zxetv!~dWVdMHs_!2ec7wdRc{&qunWw!NefL_-?Mr{Ux$?RWrS0u}_w zwvAnLhYg%jVE%6nCaL86y83u8!_)Bn$+CkE0H_iNWdU@>+uEIgng4Q= z1ij{63VfXd%I_xplHxV8T;%%KC2_OMrVls}g@3=xo$R+S@Zt7JlP~3Eo2GVL^J(IV z({vO7=+cM&JxW#Udz<)tNO>PmPv7sEttSq*r$Xk&bG-F|Qt0Ao{y+@qD){#EY-UDL z8Mj7rbp65f7&sMO`H-g-rcO!j8WijfSQE~?8F-zEp=YR6sL#r0aT5TY5Z$l81yvwd zuy1L+Qz7H?b+wr>+F%aQUL`Yb40(`*vT6lc2L}%T+bJvp~iC4N`m8i0?Vwoa&Cv_ra<-!a6op(?a zo~Dv(NGKZzF<73Ow?i7<7v{;+++2F2&mjPS@BjBAMfeskgT@qGOhy3{W(OcB!~xKr z{?AL3EV0?EfIfzAd9sTW%G&4gdrDAC;-Q%Y%FgqDlc1_(z*zXiioAE31io72-PX$f zZyV{#{oh6Hc0rR2Cdc}ZtqV&d_6!<8UAhzhPhY2D&6!^OwdfPP)=&VzLD26G2P$?q z8dYDL;Q2e5000}g|8r+@?{>$tb}2vs08O;t0+*+N2U=os$s6z|0uRvNItCtrzi$Q} z(7&4pz}_!e{4fGqd{7z^@JZO4HIH-Nw}bcsVV@FD)}XP*&MO9gw)we!s@;{qk`9qfni-3W7B z238F@H3a5Rq8XZt_2BaIvPRgaGZw=2{q_F&`59w*?f3jO~g(-~e5W-@RS| zH!aS;dD%&jNm_NgJ({(cE2qkOKV5%2o$t7-KOvD2lk{@CV;!RsUH3R|KV&?;c-W3H z!A$!tR#)rK&_FAsuHPeky9hbFoYSybZM4xj>cphi99%kb2%lLb`DVZ_uk5{-Vq%<9 z6?b)G5W}0~EY6*50UWEU=D?W(kWH~m2c_~uJHy_A^YZcGa@)*6^8dAWWl>FKYdV%? zQHsFzIv}%3DTN5gJcA_)DgwnMAdrBF2uPS`LR1v5AaE4~WC$vg%rlq(K}A3a5Mm6G z8Hq_qm?R011d{X#SpCp_yC1syt=$hzWWy2|eM%0JLx)Zhz6#js zf(s!?m|Yn6xzW<=B6NxSu>yIA+fb>4Vt~?)2(@Bz(Z@jLhKVy0=`J#<8KW3@syF<) zsC|u(jVqE@av&E_1QA_7F?vi`9b5o#45F-EJ=#q+5HYC*cNi{4Zn9VC{Cgcnacj2> z;)_UMQxD`C4aKUh!;wH$P?sr$!kdZy7B`!z96;8Sneq@gZ}k?U-&RUmn$Gs$_%-bk zXUkKSBaZ?5$-xBFcIZ;asQq+8C4NZs*I^}_{13?o2jw6z03K}}_3T^nzJ z6?MRIi_M{bXZ>`_^GQ+(aN3Pk1~4};YbAt7|H;CCz}cW5S=Gn1*PS2C(*y8->Nucy z(CO9#&xI;gv`k|)gpH{#PAr1&HXfFizLZWPkw%T52D!cgjN@;Yw#C(43tKGBgBk+B z6W-ef!l%r}sI2umvnhecJ@6Q!#^Tq63Ro6f;X@j5+Mv0<>ei{;2vqY7aKs6xOMzb( zj{w6K>U%$CEGMkDjoytHY)spx14aNOE#p?x8oh8+24utnMlk=6!)_1dHX=OU8}fnB@zH7pH^^sSQEdJ0vYfm z$1FAz`Mha?iHiM#7S@=_ov$rh+FXYV)&cA2JLENqis8#^bM5`hk?Jb<$w5GtL0ci1P{ zh;iRP+)obN?GOcSg-#9+4=<2jNNz<|V_~#~{-ix{OlM9Mz+%-G8LJ0Eq((bm2Yg^k z9SRWDnY{n#B2NPq(@aAceRz(YB(gLe84*c;h^q&(L0yUEwm8xw*feYfr;u7$8|V_Z zk+=>IvtInud(>nj(tSEQp#e$!Gh}mtU|u9*Ya{r4jZ65l;2YPAC6E6iV>us6Pu&ld zKW)~bWxf$PU`!KL=SPne4YKVMyU62}sXNUjrdk6B2cq1gzu-F5g9ck|J6kzDYQ9(7 zG@BENHNg=pl~%d%{>JY5ari!hU(?c`uu<;$ngmI_%(z(%@1EO~ChtX%xQ?kBP)Uss zC%`D$Fp8K5|HAdvX`6`qzP$SscydDzBGt?ePgH` zaK|DaHZF}#`Kad@5L1TukU{q3bhS~jO**5ZL4~v@M!xO2t+-orZ(%-DFjlvkpXT|2 z`o?Z3?Q%l+&A@Da9Q|PjsZn9ET8rwY!Yns8lb#O7qBm->8RRLYk;sKk&T;N2u3BQj zN@O5~o(@^ay5{TtjFw1sX5%CowZ=S;WX8s9=|-!MdRj?OLC~|Qz@9%KCQa+3w|*C} zXmSkowuI=bgQ84&RkjkYc!g!Kydb+Lq=PSis{x~RdX>~J?N}PJF4FAGqA-$C#ll3cO zn*^pZh4SE}Bmt~HO}>d&T3dT|i#PMgI>rRj)~r7^77@^xjfH&Bt?4Tz-jsks!7n$K zf{e$TB7lQ)K9)t^%vW_Ty}&dlN(P}q7TK8nl4zvgEcw=4oKO4I>!J|5)=4;o`Pr{k z&n>;6aE;P1UNagwKEn>?baNc21(uFScmF zvR7Kw2aMSqE$WCktX4mDzEexPPOr1&e2VSUc=lS6chC?!VZZI8G-_wIxJqWgd~fA( zf|j81eVck(;RQF{D`rD3(R_Med!l4nuHO9YOac7Gpq@As8p&rVogS}id2Jd%q{6S} zPKO-hc@1HUF{n@=Db^Gw#aWLl^#bMe;XrHLtCw2DXJ{^S<<^`L9&^K1&M^AM+{jxx z)i@m?Gi{U`$GZPXk9nItvlxJ(6J1{A$;cb)@tMx^wfyC*#@|1B)lV6yOflXJKTCXI zbMR8Obg0MaCwb}bE%Z~EZ5txVdvzIL;It+Q;={D{+ z+ffODd<{Tw}p`{bmD=U^gjpLn-^{6Xm{mz-xWp^{vwRiX9?KV-& z2Np7&`3?m`)$IEe(UQh-CO$`;$AM?*$2726?HE1v8IEr{H2S%I>wfQ4h#p|~5<(Ao z{P!%gX^o7CFI1sMl5Q*tg|cQBMmtnX)NP-oc9+E%A(SDtu?%E`95tqC^WFh3 zk)YqFo}}*>t=C9zk;4Wq4p(!a0cZp5=%u;$ZF1?lq_(dS4L7qlmZXeh>Ml10v`ntg zjASztOc8Ydn2PS=w3kS#N?L%W{?k3QDPJs6{lW;Z|EnK5(LzsMjrckIM1qdl8XNic zMa#;*n08YQ@KOx@sYS$~5kJ+E$xMKDB@)h(_5=GJC(4r@@CtHrMh1ThBzC6;y!M*e zWIuknjy4KuVn)!)njR`B+c?#Eq>#lx?UuVTqSN1p8uF?B4cDm^uB%YKj z&d4peD*bxRo4a zs6B3-duZ;|9Isb+#W)_aCmuh4m$}E)RE6@}qmEGj-qq$15v`yb`ufaoGRyMvvU1}_ zh6u3KgnNxgpjpN>LfA-6KI-&5t|AV9kaVPFk|-PC@hDHpl%vN%d?j_hKQkj(RcJ0&YSxa5Z{_pn-R`!%~CA`T2D>4y`lGY zwNX`%s^XQdn5Q+K{L#p!`8*lJi@nMeKkckp8_V&bFVS3;QmxC> zMn#BVd=sJmDC)H)5$Y0GqoHbOTeH)Rct|CUX{Y2IWf1B8oS93z0tS~-d`tcjuPNi6 zA$V}7*)661GyZ5Cp4A)i>F~~vq1L6#y3gKmpNSD~csPj!IZ|voCpI_71>S$uSMXX= zwT6m$6BRoqnwKZJqKo01@lI^Y7si}Z`%nYTYk0BC1>h98k7j^RUB;7WG?L$>*0}*u z{hcc6CzB*16ZPw5pE?6u1BJ%ns+Wsk9w&PI*t~7V&An@Z%PGqg zyEctwHX#FeaYgq@ly_vT1>GtS z_ifWGU#yuN&bQ8&h#Fch%E3aR@ok&3$)xt!o2=f{5UJH8;I?prcv%AfmPTQ*E(#@E z@Ys?Q@68F}ydg96ISoscBa~yG#E06YrdhS>I;@OE1ru}T%wlhO0um2Fy4!&fkqMPu zQhr9Z%v21b*44&02f_@s3K>ixMX~Q6nht6IoCEKj^^6Huv$(50RDHF4@^eo5^3A;w zJ3uoGuU$YL=d*N9Bl<;C%xi-hy{989ViK9_M^7#Bqq-JatKAwG(O)*FLb@fC+lQ(? zbM}%~65}ij2hFZUGy7J0&Qg+6qa+GtRl$QJ;wHgx?|t)=65_n*pqTePJ33hT#tEZ*>0(wI({%;HKomtuI)9}vDPB@{$iR=x5Kw_WBVK2R}Eweg>!p zU>p?|w7@v~FS!H2XPgxlQy|chdw>}OJD$QbXn57Fi$$ifLz^I z2#amCo?^3X3~S44$O zStYhEv)MKVTG)we&;o%vgyq$tm);Nj`-WZJV26sll;?7u&XW+TaDe-A5zYW!ZJxYS zM=ptt(uMC-6IFH4Z@79J3ZG&e0!Rg+fCsuxiJ{Qu$PN>e6kOebfl!CHX_YUuR;56m zFSwhXM}STEyG~Ao%r?R?cQICRiO`sVPrks_?X^v`0lD%cM6(*8ty1~q-G6QB6@S@o z60tKoJ8N`Fu5c%4*l0^Bmt&I1zFE5g)@&eK7#e;z;g4s+X?IIXd#kEU0sb-xxEhRO z>#4ZNp95A&AtwX+PANWqm4*vO{+Yi6bXSN~yWdnnAkX{rfJT9FPe@yUy z;3R$s@rMurGyUI3n;$^>A;cd*5{A4VIQSuh{|OG5yZzQcAc?7q=l*c~7wP;D2m8aY zei+vO#ISxC6Ckz!%n$rHHEN&yM@jBuDR8LTO&hf)huX{bGWjD4t zu{X(hpF2!h8WL?Tb=CPSL^Uszm(p^DvLto&`wUqI^I@$^`3>~DA{G$v4Vn1~qB9KV zdZ}rv;|2s$u~}Y?$y%D&V5ed1TDcQhc}AIYS-*V0Rh175%E%Ja)?z9YJFW{xhdsvx zP0}LoHm9m$G3t}ZKSa0Mdfx28`Smj$nSGB`S6LJM-|`}iS&Y-v=+rDFIW5*f;AsU2 z^d?!`7gl3-qo6dbNx>g^X}UJ6*f)MO^rOY-bBxj;uloCjlb~ICbXO$oOBl1BtQs~j z`$4Vsw@J(dHS0c>Y&%HR$~x<8c2(Hv0RmO&%VnRAa%a0!K9!gEotmF0wbCj(4@uB^ zo(DYCjH<7lnrORxe@Pu&4Y}v99PTaGbZ~pW4808o6}oDmGvZXq-Pj|gWqr_;7v50C zTrC+U82+Uf3Z)8I(zV)DiKlE@OSjcT<>lvJ7Be()e1?{qXIc`07DIqwd`P!LT`pba z=C_n%JLa%PFu1`jZ_4b-EMW_Fo*a71CX!oE?n(544WXv9(+>?^l);M`27q1kj{Yp1 z;z~aETk12>!p4)udxlLaEKIVUt6~v|?>fGOOR#Fc#$i4xA9k>oGO6^aLHi>v#tNJ3 zfuUjr+)7pbPlosc$#R1?#q|m9-zE9VpA*($*n8A7D2ash@6+0c%Ysb8W|@wGakdHYxi=3Uh+k(u z{)wd^m_(@XiU4_J4~qBWfI-r;<=DdRIxFQ%U9GkwG${wt@E>7m`h(or9K^jjR`+;=%Qjft_O&0ki!%7$=jC;vIgW`%;a0{CWBT*YLA)$`g*SlFOScFSLyb&RBPFHy14?4IR>29@qv^+{NedX(bk zS7NUzyR5T6xdeE*75-&BDr?+~+l^;-?79Z5wmWrZOTbxeSq;WvC1KP8N!g;>O)A_f zU4ci{;uQQcZRpT5o0;waty#`83?0i^eHVIIqkn*B&@xoGPr>c{R1 ztZO|2m4B>2wLd&@+f&|tTD7l0ePlD$G1<&Ge5T8F{aKKvnnOf-GsrULfvdTI=R?Z=uO8-7ZepBnyl;@1A=N#?J_hl*E#Q}H6AHOoHdXhh5cI3}v68?!t(HDF z`R`hnFYn`!9+H&zL+WXzRk|a{e44x29d1^rRK%svgqO7NvBL3iys(RTmFEzyw%(_f zgvL^8(uA7=6_&(ust{!YYwQM>(OcTX1RA+Rv3+O9(6Ot9H<;@WAjZ75!UZ}^aNr+8 zGr*{YEqAQvg*$DC!f38pPi?n4oB=oc&tvJo)b#Tq&2{@^Rq#NYTIpdV z&e>+_6$@ww6#nk2!PD0tVRkhHlw>!{=fGB80oaC)VRkdB#8s;eDml1!J0Un;;qRyO zTrp6iA$o-_H3l@L0mJir<PU5*H>XrY5HQmy?D2{c-g`Bu6m#{r?6wM z$9#RLZ6n=tmvvx|VyKYc=PL0I@YVmj*j0svg_V?suP;x#^>d z|9cM_nt6oh>26+bE+iqLzo4+VI5{PygyrwAKbbcA-ujHAl3<|ZuV^HHe~~QCdH7)` z_(A61Z_L!R1pCG-h@oNsd)xji8f<gT+J?SWeKDfJ;?%?Z9nwbCZOG#7iI}y}AHlaSxW)BhvqLD8Xz_wT7b5 zmS3^#^aaMhBclz1S{>APf~V;P$A|?*0xDiMc^A0tD44v3PH3!lJ<61kmJSICq48dq zv9PdEnwMswH>udplc41@Ie`2EG3o2*q$VUt$mN!ml@%5BriZ|>GbwfX-(GCD6)VUP zkEU)8QX=y$CjR_1z(okf_-lUt9);i>-V+XJ}QLe2*? zxlouNvn+;OR*mGF?65lB78i0}7qMj>(z=HV(xRgNTEWvHhUS*Fot+}&_=Hf5KyKut|QQ@u~UcDtTn zJ$HF#;9!BW2v@?ftmljz(kZW648;@L*w{#bKoFaomKGK)=EQwDb$P~ZSsWZ3ykNvP zEs)iH*qWxR39@D=L9oAPHWO0|)Fz(Mc8b{KKB!Xk82Dr6%!4<@}&o!>H?#J<@LYD!IRlXLPF ziZ4|{;zB!BlO$sKcLT%K)8k4$8hYeg7DOaFdbHLX1*7Qf1OM{aV6X_h6@cm3oj>po)K-p>0lc+lMNXST?QYpThdr3ofhy9XyUh)WjU6r5m$_GhaLj-HVwKGJ->&GPW%%B>J32aASQG^YcJI#3zDL`dsDS?Z z^{c2rJS%EiTHWVAxT?;)GU6Gz>C&`pYe69MFm^TV}>hzRH^ zLbuM6KpeW)aeEUfcq57DZfZ)cy0VesYs+QhcQ%2J&G1Fgrt>IKAT~QYJHZ8EhUId) zw{Yuwd+KXg<+i`5Mkx?5out+B@J=nO-1*Z^-`#aMuQ=!MvH!PNB3qaO#)#4g5V#J9 ztGztySzPP4*L%J_k(323mZfEY%P2}pKA3YY=85)ko~*M{x3*^RFQ9q#D%9v#9=LVfT+mZd>-%0i6BRvYGlgN!Ta4xhi)G^qoP82uhl_j>S!&s9Pf1Uo zFU&);%*376Zm_MZsmbX9HmMqwgxZk7gpAKE%G5}KXgp*np|bKFPYr@L zO%5I7@np40e|I=3C3C7&m7^$D)>Q2+TLOPjUw=PR`fvoNT^KXHrRCE1_HrRVJZxBF zY-ntHY`rvqJr5IQrHex9kHgM02FN_LjPN6TS)JC7xGGmk^i3x<@WbYtoC;3B92|AS zIT9&}iItqtfq}63bZ8py>HdOhJ}GVVhl zrixx$W^UgI-k#%ni{(KNx2Zlv?*g*{B8k?!rnYvr#the+vj7RKwyv`B3|Wvtlj!8= zc(D>Gn3|S01robcYYp2dMhs-@evqI}BeHB82<6&U=A@`Cj{Xe4dJeT%Fr&V{5EjU| z9ie^$!5LP-#Kb&NQRD?#HGEuNfKb4UH{Du_6@qXOOFUfrC1se!`6Hs38VpHn=_4B? zY!jd?)36Q}!=GPWb7_)u&yJ5L^b`2=wC_RtiO6AXrAHf3+~=&h5e@gItRbu*t-Lh)GSgHa5hULkdl@{xECF)^o&-cKE>xLcrEx`?$q1Nm;3O#7xE(YJM%hS3)^m?0_8 z72GMQ;kMr;i-Wm#;|G#H8s>JKE?V>@6ofV8l%B5! ztllrVY1sHUyL{TCkn)i^Biv_1ESa01&2`i5a=IAx%49TU3SG;^OgW;wtZZVb zAr7{des|QvEax8l+qXp|s@V<#WM5?zgQsl69S!=-1v*3o>eC%`%MKJ^3hU|G-ku(_ z-WaNCPeat!(2pQoB(7;Id|{PJa1 zW1}08R;p{i6pNLi7Qg$G7~HkF0S+Z@ue1H3G+th*@x))rx#8?0MoN7QTVRDCCMxgh zoLai(C5O{pT@UBAzPQhyKPxmnt7TQ8ERJKK%YvLY;Uve=($ia6+v!Y^GfAiR| zkjxQUceiBV^f^G2dOV_=5{=P;+W<4F} zNp!3tB$nExjumx?D)MfpmgMNI;}>Pq3jlsL1uZanp@x&Q&@ptej&3ctKGzA7=YG5h ziredBU7LKwb=#Cee>u`wQBOg}lNoeHHH88Wv3E?x6wERu+7IX2bF98ZMBtbtfQ_8S z3Y8#oJ>A_SOu3(Jy_ei3C z_`OIeO95;vKwciFT@$mm&+kd1QIoPy7hcL1toC0 z6hzslr(5~)&ULPSU?LdGq*eRXg^53({9ur4LGg0*lKuKn7=$>*ZH{J2iM5>@_)o<=fvTq&Or=>e;`24EYq%maX2=jZ1Y9XCAJgyIQk7iHp{FCH?=x1?}9t|KT* zn+}T4ZaF9~FPBMR0`gKpo9I?vGU%7Qwz_k4SlDCfTL3{SRC$J{{IBL!c;+1v9Z)Yz zV$#=aqqfs3mGR7kmcrXOADUGfZQOR3RzBN=)+Gzq9F^1$L>>w;j56?=DAz?5?T_Ti z%r!gbL|U(}ucK(4yFv(1cksdx zs|x%Cyj^#uRVgG|Po}K^NS81kBG9b-=$BuO&-I0p@dsf#?;Gp~4>GSsxY2BgI9_m& zQ&r;Qz$BC`4K5gDY46l=%RxApy+aCc_iUQ*NJ4RR&p*@2uvuoRDEaV#&<4{9LpY4N z?C`S_%rQnWUNi$+BC-U|^$H$#2uehuv z?fpla$?xw;sH(Owg1(Z~2V9cC+RJ5V!(6UEwlV0(ue8V7+h$tlM(|@Q^y<$!y_4ru zs&i6@Thg@Tw#H>^OTWv>&Zb!dJ2+&09PaG&GXym+_HD>YOJ`fH&DeFwF)Ia1Hee^Q zFXp5|vfCV1x`$gx@) zy`lU3>K9KruXE16)`^5Dq+1!=!YP7+UwVl-_QMP+G2&eaFKu6L)ahz(EEcl?q-8&6q*m5{9-Nhv7b61aOu(I2#0Z2!XU zd2&XvrKM%@ezvGxEW~O8aUyS5q9TxXE6ZI>aDTM6O~p6)95|s+kojPwcfg^(bhgE- zYq*Hhh;Hd`xQa27T5EyNu8_``bkbN#c99ok%P1x$w!P4i;nS1t|3w)IP5F!N`h zu5$o@YkeLHFywy?5}54n>av+_jK+d^uV;UOII1Q~QnKA%9VtjhA^o3v$Z@E7$Qf>20u{VB7giIaE)2%+r_AYppt;laqc1Q_bi1{0DEs`3j5Oxs7_|ZnC3%c zs?Su@+xq;~FTlO&@fe&8Hm~pZ)%Lev?(#O<2(bhd6l}oDw2^PANbz+P1%%`zNM$JP zkRa|sQ$s_Mg9rSX)>;NhHU)r_W`D9!j-{5%h8~X=M`1UwFd| zw=BjVN{qsDY_vdYNf z)!bnA(N|M@d;821HFO2#W}e}?e&GJO-4p4{Z*K|Ib0s(r86}?4dT_Fg6u_D` z#kAht-lVBvXWqa2dD~8^@ILa+Tz|}QRb6duE-K08ao1oqH&QpGn$P2%{i0BFDNOq{ zf4ln;HKT|tugNK{#qBu7b(&6#OL$10O!2meZ13wGBM%~o^K{&CK|UrVR@q$gfZghG z^HpAczVcn|9$`_u8m};7Zg;z7di8R}Gx`OrW+#y#+PrQR>bwT9|_)^y`Ce> zf2Rdc2cw6G7=)ylv=t*u^?)MO=EaVQpkRl1DB-XjceNc+u2cH1DD0)!X{u(d*YUVI zC|@=U6F=e>0Mv(LDN=i6u;YN;)loUlT+UD0XhaKJ46D!L1X_BV(Le(GvVId7KKie0 zaJ(1u7X3)V1-^|0EpyGgy=G^Jh{OPJZ$!*e!IE-X7{!w0@|-FQ-|^twOPYK0?90pt zk}M_TgMe*q79@*my1-b!UJPXh{vasi)t*DENq>C(ewmR<#@U(MN$u61?`_Vt%sK0v z%2~(lWk+*HHKB;BwALo+1LTOXI}`a1P!p=ZM<>66;HRXdfbd1Rs@8|n=v#ut8w?PZ z^==1-=cy2)VRG8@Cu9();x}=L2PRhFtI^?V>nT=ha@+Lk*CFX%US0@CdI8*zwa^>M|aadP74GXKT9mYAKzXBICQK_#uiqY2QAn8iy z_;pHrazr2crf7xs=32O{-W9WzCD%p4FAm`r&$dq~_{!dWGL18GfOY8arN_t>@pFQ$ zqHd4x>GGJ61C@jQSUQMeVkGrYhI2>KBQh7FcA~Q6py2uvVV*O!+HeQCOvSr!cyv?( z|NOR#r0Au-pkyzzF1+NX=z(tF$mnPi_$L__1X(726DX}Mz4si90~3~wv>-+5N^stj zATLpjjp2{4_-d$QIZ(W}hJwqN#CM(c#m6|OalU&O#hkb8r+hkr%Za%*1Q7t~$-dnH zidV!sK^l|;qw(WNYQip4>-EXZ;Sc|LQ$)kFW?X7dX3O`V+Wd`Qe?{m2c-C)^q&O=vyumTyGNjL*fjnQ#J$y#(b#>5F zy}An&xE5MpB)Es@D_TW{AKxE546f@SjS}#IUn5flq>i^HB0H;dbKlt6?G-Z*OBh`k zO9a0Os5}g=zKL-zA?YaBs@qJuSAm}~ERBpU-OgDSyuAX@gU9(KTuwB@hV(|<-X;r= zMBIh!gP7QRUfxk79!E>EBz*G6#P41(Fvz;}uXYAJs?`Ok0i`p3RmM>Gd!H*elL}=M z%d0eSNwzL+M}^|vX#A^wQSCSW`6}Ut3p^o~+j0!tAy&3?&ElHx#EnrZ?fo<<`Oktz zEJGHJBayG9Jj*^%OF1k9wZU3Lqj8%It-P$PY;Ksgwq+lL7GDTB5;YB=Dp-s_(Msc$ zLmX8sN08Z*pPvt847+g4HbU7e&7+{j!kizD;orF|&kWXDs(tbKL0aCl0~u1D$|WQM z;iM9fDROSdFC&vchhZenZR{J^~dc@NnwN^yl0f1WruHU&bq@qm7qm?g_5I!xm+LgP^zp0 zy@xGwv%@4V5u>TeNwE(f`Y1qZk}c^Zzd^9<^l6fxsk98@V7AH0ME^oUf!5!&tU?a^ zyKqa~2{n}pDs#SoG0#Nei#f!@&afA#Gs6Aqfb$u7b$;}Sh{+gQ6Hjs^mT!U;V?6G~ ztOP%8!q7y?vaowL(^%x?#>}guj+@daB6Bx&Lu_9wHqt`R@IRD*pZU*EioH@YFvzm* z1Aq}?CrZARM>-#^b~9KE7aty^CYLupcim)L`^v+!yqSQCiVAfiHJ+bPU0rS729A|* zafQswlQ`RgzAC&m9zS&~W{guj&3uBQt1}+YgP6dJii%M4nmt_mBbWD7Kg~Z_qk{1V z0_0+xA-Gv~6k~(}vY?aA7z(reP0-97TnShaVPcdK_;O z5D~ql98Q_HHOWb+Gz;=s^VlkDP%G6CmLPB28K(XRu6;7IJXr1mNLF6{%+&}1FYm+N zw|aVd0PsnEXW(c3UKi-rXwu1X*QKSATRpvav$e4yK}isVP0DFI`~G6KY+rlDoD&Fo z0EdODy}7mgNpkP*=iuPrvND@++)6q+I(&{1vtF(RFQ>EpCCI=?k8*Ml{4C@4DoDT% zuK7LW>{#=Dg$gu|UOhiAPss-8vB+f*T6Dk))_Y^$X1sUs(^~1cy{>3|MpcKlW`Y`y zAu*V#x2f&N_qoW&IRAa#pip4C*!2VnN@utFaF~W&$2BK;5`-5M17l>El!Qe3VN6!m z%UGWs(2l?_h;T!I&Y8*C)6V#7dA{d;q2{ijdeMZU;)TcRqN28jy^ef+p$IxLHqd6F zwO3?!_RL2$H8rq!9)4&HeIGIMP1*2u5}n#>*__H>0Br(L3@R+m4;1%J?ChWzP1tcKAFnr6naZ`&qh5iJ0}QB`1af0(?Y(*JXPWcpTX&cPFot z`DJd{A!0aZczC#a%FxINxw~9a(Jsy9wpEA=aH|<&oC9~`N-G6Ww$hjFz5WmSfqf1d zBAilFr1m`7*7W#6%x?Z9uC$;)VvlN!1QIw(5Wo8suCy_Y_>ya%dRLP!q|>_@kA#v^ zfs~09tvMnOQ5wZ4ZYR^L%+W3xrRsD2F_MBG|3=`Ys8t4+-Fz~K)y?&({sqBjx(@dv z(`F%b;&@jAVtqQY7X$0IJg?dr-aLriLN^kfd_Cr5!!&dzzNFle(`&adSjN?&7U znvhBwQFwW>_$^J1 zjj$q#1mR{F2b~7!>rfrH(|W0HOT6vtVUV=Xy!%F4G27$ktj0i1^oWolQ>fH34H@`M zmm3+CNis67;bUO^f}${t=U*GZ0do#ZWN~htQ`g3&^9<%_|3)abM`_o3 z&Vr_L%*7ZSj%H?Qu08}!memvT zK?w7N!@zI}4h{}@B|$phKV7TSWImQO`s&Tv7 zse-=g#lm|uU}ZoI@awj<@FgO%;Aeb{cSyPkwv4-Z8<#ACEVHEoY!zK?hox-t+F~rR z;5V2mlWTgHH;KBr0P;bk)WTC5xqK}a3y7>;I0{GDbl$RE_+f-iuu0VcPAwdjduFQw0!Fx*4#Lj#MY z4sW5Cf`S5EQiY3>lCtk7@AzaANMn4HGzIucY3v=kEkNT{q8$mpDs}H zxhb9m*p(Hxwt8J(90O-VK5hp}^F2L%NfqTXqDD}h8(?~KBZGj3{1OMpgZn681}$Fa zhoKYqLu?sWS65-*-M1%Mu-Fkk59b67MidbMT@L8QgPTmZcU}}$VXSW z>9P)2KE_cSpP{SuZObbjn*EZZp}HsOO_OK8gMSb7h0&LxB2czKJ`Itq=^Wy<15PP8 zv3bY+=us$;sbx+YEt3KR137k~93dJEwx)MARUdg}Eul{c0FC8o@7nxs@B}WLo($un zj_INrFT;uk+MKetmd!n`ZB@)=RZ@H+2$)FF14VPc6rx@Ym*8rN09c7Vmx}faI?t*x zVzs~+2c8UMywSL}0=VRpkMd&wKV8*DcOgn6^)fA>MM-0sHQ+jw%8h>mm?8ddCP0&s zlcxa;TQWaEb+S$~xX5W^$j8Sg{2ByS*3giQ28p(}BLdVF6@_?NSXrw@gK%mUezyh) zukx#@TLAe8`D+)>@Pq^+D#6-OfR9IPZ_6Ut@W?>L{{ zb#*WQT>W~w9}>)ey;8O*$I#4J1)QUM?U&_sdpxxdrUu!tdPqHoa~jX)+dRSY94^F& zX?=A1(Ytrp^SUkDFvlNc(t6*#WivatT$#85S8fWCRY!Am)}O&C{Bm|MVL-+4dym585$Y_9am#-E!uMqR@Uqn zlAP&}*M=d|9ejBEY!aGebC|`KDcxF9M|Ot%^l~lkA6RsyqK z6#0Fv{)>XsPrAEh=X{7vlZq zZEZ}e$UPl@>nm(vRi(#*dXt?Zb%il|~cNB|l6LjLpmhz0N8D zRQp&9zs?dM+^xc@=kAKyo699>r#m+QLX-;&yAhud8!jUb7XI=TO2)d=MPzY+SKaZV zuJ`9+1ERWlf8u{Dr!6IqrU|@2S9^(7`IuR&+9B|#LQCFQX7t?_39Jn z_Q-Ayhu7PQ>Muvwy17mh6Jb2#02%}Klep&NpOLWPO-^PQ%+H*ioxQ!UF>xs%adFNF zn6S8bfN-qh*Nlt|g+a-kDQP5|lDnEdnG~{SYgWh|qs@58ZHnvJZ&lns*H~!hXiUsg zpo#rkgAuNxqobp!m|0XL^-{p<;amAs#rM}q_hG9*2MuVkjIiCNvChj+UqAo%akR{= zpN3VEZ(^`}gjv`qqXw= zM~;RjR3h}BS)!Ez`RnhkwOIFHe}96}{eL|u0(29$9jK<>ocohR-XYlqIwQr(bjp7n zGu=!TByesNC*2pXT*8yV5U8f{M966PyZ>KB-(tYnw^;=_fmjBQ_%7IC!Z12Xa(?So zRk3B)!GCXaFDS)iFJVJdDLG*E5E2blR8@_>0mV7{|8=kZ}f5N2r5_rY9L5ayeEkVDT%F z91Z*Pe^x9`r4X}~R-=U$p84djsW;*KZ!`(A{(%<%_c6OB`O6xu@B|a@f6$uLr=Y=`fiAbE;-tmBq1|--E$EC|&62=>d)5u0LaEI^z=%uyvcjN}XSP3gp~y zxZjsS^>?GSu*L1^=pes}s^QPSipJfkl^VH6^4jjtv76oi9HH)=SPm{43lN zDzVtv`}pGt8O&v=1oO`_wN$Mn>>p%iF^b;(BWi;cYjODjcm5d^?f=_5|9`l(qLG~A z`C(kMnK_`40veG(6S+rgW)22bBR944xmgp-u^feZ-wG@G)lEcF;uw~#Zg=DQv>RT} z13&$BKr}@V=q_SRW$F4-GmV!N&aVKl0^xF$Yc;9YH~tyV=qO68T#+mueV#_1=KtAf zx0mcxpYn~9MmBhUtX;H7s=sqcTr=+e$$g*{owX$>b9{05L-^N!6t8;sXq`GfPJNm&+x<#(r} zn(&>x0J6F2*96KwS}4- ztYKVP4@)yPs-YW^KF8m?$hS@(SVVjw-}+JBuys0L{mG=pgHLv{!AD|^c!XQ3h@7lo zD0xz$WZ&c0&@aC})&N>@|AK*J9+Av+g3D{yXm0k6=!*8~g#F5dnNnA?rsHgp_KQtP z94@ncbzb>3m*)+Lqr4iA{c_6reIsin6WXSS54%jSF;MJu+$|=eh+_%r2$lR;HF+G* zm)zXk$9oI^>f-=EW{1{L_=yJ3kHX7F$416g%?6BRBY$O7*c;fHWSQW0kz+s)_H;D{ zYH7*WshvsWX>0I|uKQw`cAJut`#zk;4q0BG%vSjm*SI278W%5}%$Ni!nL^~unj_|& zdK~knNY{KXRKeEP>xoqr5qj-InsOyMoMj{4zm~pqI658@$A(Lk33~LBxR!&C0~j9~ z!kwmrKtZFAa5g(}eQYNsC!o={H>Vwd5CA?gal0C;(0+4a^*1xZR2bjg!;B3a8YK7g zukyn@N7cl(GhL6-h0RugOSxtu>Ih#s@n)}4pN zCB%)>>2!cFyF)@lMsJ&XG$`GLnBHx5XFp@zV{v|c{DoieiX=r(QH{y7Xf!s!eY4uM zuSw#O>(kboP9Hf#At50}MHoPvjE{|->@6sO{v!|;ishjH6n_e~^+_;OOZQpb19wyM zLAIJxD~&`YMKF8BKkxF-lw{0l3=cP!RyK})Iu#(zD`OgJ@&Rw)8t~SGx7r4pg}XM^ z6`QY%>*IT^DyqNC6p3(ZXc-x7+H^k-*E6{vEodFwZpQCCt|K9OJRm4|dBuD`0PJzB z+RcPzM_9$g{1HQL_z37P(t6Lgd$%+?wYbrfB(wQM_F~} z^<+S@G>X>1dtAA!mPth8| z{BV=pQ|l4f$#%BCwI3t$+)ZgXQc&Xhs>`AKteJm72lbtFdfS#fZ%gac!0dGQ7e3pu zI=O((`{YM)Jq()J%_b5Wh=@>?uhGZGdrdiwy|#M0oqHlVr@M+1oYkCM2I?cXO+Pde zHrI-@I!>!RKU;IorC)nE^IYCFfdTSlnRte1K~)f_eeQ6G6dx+&S3T9qID@BYBT`*QN;Xb)6IqDo}-g2aywh~ z%toGUjG$w);bthjjodD$Z}&ZiW>(av{Tk%2Gu^$|#mhJ`V5Uqn=zl%LVD@MFjM)5{ zOL@@*t?MnMv;KMlExx+jER`+o?LG;5@<;F>FBZR))XSN5n9g6TGv2?$-pa5W7^Js! zQ?XKI|G`ynTpg^_-7HC&8p_X1o|t1eyNYZXDH+H!f44Tv))GHhPAoU=GiJPZtQ6-j z)!&}8mt#Lw^Mi7n_^T+G)@{mq1Fyc02qL|}(PpTdP5-i=PeN+qqhP0#ID#>`3}rj! zvDf=L*C}ilNF7UjA%TM?@JTBjZR zyi>T~;UgaJDyOnggF0@gH{v|ZaY@jwWQ(=m%;?&NBw)}Hf5o~ z;E@BH8C!5gYU8XF3C6}QZaAGGV??$cQOBG?ZFc2gdRuPnkliJt=J(X>XZ`DHICj-0 zCUXb8|IWEp45&lcdynZy?(m})Qnz!N<;t8tFlez%4BEt`fFz<1vvOsAxMDh0Y&Mo& z+RkS(@sLdO%tIFsY`rT+Y_@OE?&*Zl!R0S5>|m+~v6p?F+Wm_u77w z=CUizYUSW9aDDvfltQ;Ls~U6ga#ECpexb>;V%>Uqre)oSWXJ}RHPb+9_1NwYxMt=6 z$|bpx8U@N--=-F|vWEh`GC#xJOZOJ*yw1(~6Fj*Q^t#)#y(=TPkshPMm%S?9W?U9g z3_Pv}YU52DZdY#=20TxqZaQ2mC=^U#G0szj1o)MN6J3>kE(llTtLxjcnQ>1GqMN#H ze{8Nd?Ed`?9gGqie?q7b>khk6EU^c}tt<)q0*)@P>*0gT&nG#22|Higv`-uM@)lz5 z5Ae$tk%byo^Za@qJ}@iiLE27_T?= zhX$$pI^V_nQ?c>^m6aZ$ zuFh<34(GyDJ%6i*G#!@U6DDt%*+;=}x=}kFg(6mvUR}UYnX8kNvr|gjR^WD1y$|lh zn!wOVPlN58K_7~YT~TX#X>pRStxVikLfqkY!l82Kdpa{A+XnWit43|79Eos{?>T|T zpBIomk=-?Svmo|3YkhsK*0$0=OJp0;>;mY&PIv1H#yIi@wr(1+e?>9?yq;E{%f_uEVJK^z@a=&#CY6Go?aTFxwkW{TT$?K-^rd%Wo~TDgrz@|`Z7 zrs{0w%j0TPZv*+mmHIo#J8ih_=22A&nIRytA`>q&xX}FZcC( zb(sDBrSnd$u&xQZBLYmxZeue!nEMcpgmi;Z7sChde0*C{tzGE68iwc zYU+q_T4K@8`|4|g#c{8Nu+fJ%3)8hgJ?$0Jxx{ zLQ=;-9=o=-_B1%Rv{Y6>A@a{@E3{=UAEB-aym8lwgjQmLJ)%N|$}3W!L!tNoQ{m|0 zL){+WICT(bDJFtxO;2S9GaG`=$wV>!Q@{C{KQj_Ka+WKdMHjg$`{9MY@}Ei^O%Kfm zA@cxRho9_GXQY0tK(w(0LmF(tk2LLvW2^qpwh;H~$TPW0Nca@XcfkuOS7fRA?L+Up z(H-y3-QKrEsneS_^o&2@yfp2Z(l5Q~u?~1+7&EwiN>1%Hmrmw|<5oV4U1D`JV56#t z9_aXuSmcKa&!3EFh414ucmEswXlO!7ocKa)HoCg;Y3W`3VYhqcdtwQ5312!>5;##0 zPEWAc9hbviK${MjI^I4EkTSa(^yBAuRWlx>{oeC9;R7|5F3+OXll2;==IWn_#w$%s zW-6+*=^cj&--}{%7NceJj$x-~rHmc%>3U8e2h&4Z)?Au z^(iak=(8UPI+{XdWBuM`G+eWpQe?h@UcG-s&-3@4Mzl{)ZD>E0cUtHJkZoX{`1c)ndoRfVo(RpiVDbF zA+JLY-rd^^QXTlXSVikqBsC!Isx9+5?-KVp26cs6Yo~fig}sxNlUk>SlrU4xmff*& zwW@Etwh;6F`FW3eQ$NP_ld$~?ctcW8!gWXPi%{(95C0Q_{N6~|6C0XOLpYBj;Lgv7 zLp_OGzp)Kij|bm-x$#zg>hbbeV`J$}drPE_G$A!P>goN)O9`$<6yytjes5xaxj<;B zf)^_{OFD9E}T4`;p(?nm`gIIj2BC-S1p+5S0~OyWQ2`OOf8ZO?LXg4xwfu6T2ycVmV8Bq;HUdV1ZV7(iR|T?4mgJKQJb*`uG! zeybmE<$h)VH8G^v6%hiDd-_i2$v1x3&d%oLWpL6pI4@SN6^^Nsh_q-4)vG*A-u-2E z|Gsz_whlp47j(2_?}K#YIrWfFi#H}*x3wg+H{!s%z)a8(W2i(#jn`4s;ys3az`%Bk z(g4A36&0%x=XuSX-Y8!WO1C$Tucu1z5tO-5HNAW*aG@rCAOq$~ZdAbo1^+bv57Q-G z#P|Cp>)KjCfe*0Y6p;nR#l_j#BZVf&LZKqGG z`!Z>QO|!XMF^VZa4HoT8ubw18FW4(gyPe0@Lu~W8PB7*jTfjbWe7vD}Cg@SKs5mxv zQG#-`nEUX)%6hR@7faf%d&$+dt)}L(y08?3`CFP{zv1&*JZzqvW6bsq10ROXr=HZi zyNLq!U2NROKl3amLM!x`E09cogSt~a{NRTLm8)otrV?+jI>R4R&b#W z0;Oy?R%wgum1EkBe_GarM$OzDNBBvX#L{+mpj2Ge<_;{fTRwez_ex1}tUTijTL%i! zsr3o*lhtenIioD2Ir9=vyv&~BeaQ!i{&l8Dz3tv%EhVD$-I95b_!*LZk=8`=hJ{{QAVsr!IcOv`gm&$I zf(+aZCU)>Wu^O8);rgAvm)MzP?{Z}I5aG>9EDdTe=IKB1V1HRyYuFk1|37~(003N;nu2BYQaSjr)o zSeSLUJiW}ekr8R}ZX2vgIZU76$Uka^PBsoQS{(fYDy>FJrq2IV!V4kvrD7KY_7*seWz3TYJ8_ok6zJSPeI=__TNP#wfZJX0o+6 zaK_OoQR{MG*FfUd)q1(51D&(}06PGg$&)X%HJ%nl&Y~M;AZ@7Ho3Gy!OmAYorI;I_ zO^}ay5E*Yaa(lmZ$py#+#oi0c$DE2M^b;$noJbenTSTPMTGu}@z1Wr0jh3m2!6@LY zcO&LI(r`)bfZIN~Fl(=EmIbj!u@sFs zGZ8}{nIDDkj<)j)$X(b^*N0$Yn;}kYzLK71;!VW1C@pa{E1Y)@hVgoHG(S#mfEg{! zcF13Fql}@Cp=a3X=eUu!tB{_z{3KU_7z#j`Ekq*kk49VOZ?3%+FKt9Qw4bqzy6Yr^ zo_ZE;cdqrs$QS!BjF7?GuEaj}&Wp|t;NrxU(?&N=@d-GdRjKKZPfV?(boMlRk9W%t zvu`M0OK6(O;84crny}5Kw;I?TT)L>5WoNh1_cIX`YP4k?zANGjDngOvu?(Ckt?Kob z-6hERZuyMb;`xErpI8k!s|<8ao?dqMS=BLT@aAXi zAn-!si9;)*8G)$|0>}=C>X900MUuA5VLsc&&9tj-Db-9r0YTywvfQaiy?hoiU8Y^< zU+hRbf!({^?OLwz!AuSI01JmS$&xX%GRRJCY+CcRF`IQE&!@+76&n2ypq~mu47ea* zD^>6VT0WAvL7kdbCjtq-wwZz!x(!9IA-Dq>Yd&Ju;$y$M^|l0Q`q&$knuoYHHW`b% z<`*yVI%X0b3rcd+?R^Q3=BG|`*@8G`3|FtGHjPUrm-$6p2JA6oHok^{KH79O<)EZr z0e^hJmNcGrle(g^$cj9E+{Jv5M4DD0hdz?5d_T&vEs;PsnYv=CG0alC%2K=^-bRnq z`w*$e)9^~P;#b9EbRtT@+kn{8nYz_LKQ^u2<5V^F^M0GS7Dtb`A9@E=lHb?bVnR&S zkFz*Yiw9jDlmwNBL7fsrUuID+bH>@l*SKz(It~EI$(aK(Eofno;hb90aoOB`dtPF} zjc?Yim4U5@4^(e?umY)ByPaq3@MyZ)W{z~ZeZ_t0dOo}-lTg7h^hB_aM{9LM^`wV# zjp&9+@CGzR7n$AhCDJ@v+pNznHSP-UjAq&XJm5#n93_$Oq7tD<4S5_HiijDP!ROmQ zXJpp*!fX`OUwLJrTq~B5)~qNFz>K=l?0kGtxD5#B0co>$SZ)$ z{y)6Ebx>Su@b^hbfCLS}f`{N9+#!Sj!QCymyL$*0Jm?_7-EDApx4{Q@_hE2&=iXd< ze_OS0?bg=LA5g%|nZudqbU)qw?N47c@t=#^6fRZInUqgg;=lq^y;rzN-z0)0g)ATO<-T9NLL!rR{l?pk++IIsX5&iCLyC~Gwd%D{r za}QTH7kzajt49zYQ`7u%0H67+W~Wi_@rAx1Zb@Hf#YNlbZWa&|n~1aIyx$81?=v~` zt4PqmZ?iWK1DEummVdpwa96K|qfF&EB5RI=4Ns5c+WG}C4$=&IbFG^uu^};yPylv6 zn$C8Ol3^KSabeHJbVED^$IDUYkY{4kTD&m2&AAoko}Cwq;!~?jMzgbKctEQOfZ5OI z%VoP4`JWOX+-)Z3CEhyson~AoDGRh-J!%S|N$m;IuC=g>oi^g3xj9=))ax!ZWZ-fj z3*K>{K2GtE5$E|TA%lU}E?W!cVdZE`4v_mBwmyI>U#**{nemI_)dDQhlCwp(zMG~W zO8M_Oxx;L7s!WamjTQyF;R(cKALyWr)PQNSTVLaa`%F7foTW*r& ziWK8;gy=m~lF061_SM^a+7j`3^bO1x?yL8^Mj@uNrR;5hb^QC-r56*twhPIN3QVtP z1=$eyEzNcz8B{TgjVi??k|w*4qkU|M64XuM`yGlF46c;yo9MIsOYH2xOQezX9YvOh z-gM8xGc{$ahFR(S&9*Fp#@_w#WiQ(V5xj`SHW#})V_iK9b+iY+3)SI$I)nRAeG74S zX3}XL7>dMqD#d>;;-D@k0!ty+pqd|%CD7tz5|OFDKIK`pDfjqv)tRe zIXGiX69DFl1Vj;ZkES<08l@44>zE%-6qErSa|xHdr#x*;IEJhjeG0?Avo%6ao0U1v@ipjg?L9u^D=I7yh)(zha7bFlnsb*hD+G^;WhM zo2{|*kiN2K%hr(qWH4_#^Wk|x%3`GCi2+y0{32RuIK-b^2glNA`RIv#v-`L&nN)(> zXnf^;_87QYHY1Hr0P9_VhQ2rY?s>cRM=loBs~VS6AArh7{W~6FLa#0B5%#Q5X6y{2 z9(SlCrPsG<`@OaCTZ@~Q)kX^FPn@M}oKro{bWe(GjPk(IDIp2o!+-e=%J64s%p7Pw z9RtjQOLmaZf^|c$D6WR|EO><|!IsUl60sa#RicMQ-go z(=CTfD?VXI1E%ZLflDo2SqW%__0obpSs0d7*3!jI;fG6KjV7e_IoZ_C_&wJY-B|Muq{d` zMoKc{c#Aj&F8!O?0*Sgb0gKD0t%O6%3nPh(w8fag-k%CyFKOpVc&`l9d~bE8;+qE@ z#{#EwJ;z954y5;Z=ozcl#6>SOb))li*o&e`6$lPJ#`6iGsckAe-$SL2-0AEAsnC{# zX7kMZDH{p|Q>W1fzC)WSh@VRD70JT*r+xKWvL?msg?CX6kaCFX_~AghjSFvUJ(iN2 z7?<6wU49SCacJr38|B$89Wl}D;@b}kRVd=5>2sQc*@p4uyiOI#R6Qf{j{GKD2%t$> zhaLOD)WO2_zTEY`(i$Z;SU5KT#yV?m(R2g z23%y)IbCPVn@pVyrPb7ecg}kXnTgy=BqXJ9!k;qM*k_E-2FG=p=lDj$EF(ET;yo{u z%JwgTW=+jGuBXYiKr}2f#Y}j5a<###mW@MnH+m0Tp`E4M(4pyKuDOa(A{7ccqefos z@=ra1PWzz1B~|%KkLjAPg`KEBpbqEp^r9tUR(jY9c}0^F0FKo4E~+{)l*LAS|2^JQ zO9r>Q+lcowEw>6CHA}feT!|t*F|@M{l;$LX_`r3MAGFKN08Tfbq=N^`Zd^9rtK;M3 z?OVL!$sgvvsW< zy-Vw2^{t8za)$F+r#)S*`@pU1b-$_|f+g{Y!`7|2_@-frGkCN`4$x#4 zsonr34VUuTRtqmjaV7s!cFgw!?I^>Mj^<}N)Ae%=F`yDy;bombv@T;;-wxj)Q&{kO#Zx4-E_acM0YC;k);2g0&3Q( zyn8IV4{8-;TRy?8@zF5zppA`NM%IFkgpi!bFs-z7=T2K_m_;+=3w}HIRmSTIxC= zu)qVO-eQvWRg3fCE}DXQAq|Jc+l`YL>h$ zll6~Ft45Q*Br?|?;tBwTAs%@r0LbZz;yYdULGd9D=LLcsp>NcnEX+7dEtp>Q$C!-l zzka12kB{aKp%d%s6S`2%{t}rlEQM5*v<1oSMmac2F5OH=I^w9cFow+%m8S*KHyLpl zX#@gO7pcr&AeDqj;@E4&Ior(MuGn09OiGxuYR_KYi_MkIY0pDO+LlN**E7mD-%Mo; z@yWH7gTKjE_0f6v79OabM3#cnOu0e{-*3eDp5>F`c?q=H9e2mbso@&`AhncWuEiLQ zJG#r=EQ`6&N~J$Ko7a=9_0feyuzM%O@%QeI{<-8%`Tr>WaRdjZnEv3DBhj}NGPf_N zl_6DCe~0$5QF@`uns)&j`S4N8bBx%^WIO?%>JpH*aW6WTuakXGHHSfDcG3#1JqpkC zC{bt}yR~UJ&TA+(5N#&8sI_$*S~%n}SpBFaKK78hsGX}PlY6wfJ^H=n@TjejL`o%P z*>F1)-|ET<%&;TZd9$sPKHN*V$*LM`-nPeDG1G{)G=n%|#K(VRjRYP;o=I#w2~&tT zf?wno*tXH)TOSQ_JvO4V>_CNCOiQv)kw={>hH zz*A5H%boJsVx1m1+%-xbp0%!rPU}6VM1dyOSOtM)%}2aCZv=`CqnOw@ZBl6Gw`CW2 zI~@T=+qDtS5X5P_#MO>Z{72$mx$H5@4s%m0@W9n5OYvph4gTTf$5gc37P^D7qYAGb z%@j7$h>UE5&h?9ynaBN|4B!zq=_g5OSj*V9D>A1Xp}tV3^O+A?$})1(S!4KN)tF;k z%fnpMdtT<{bJ{u!;~lGqqEzw-iyK4*mx)~#oAZofOEJ_GVz0Jac!A|#{HKG-3ef7O z5|&PT0Ddvxiu;202xUh@Z;1mxM??a6{!-m=>fHLGNsPg18@;@Z53Ps;5m=?9b)&Cg zi&i{tfAii*Visl&ikAtGEtQZ)?FxK0Bn~LRX+6jW9+u-PgA1dQdm{GkPpdY|g$7Y_ zuuuZF+^0bnIC)>Np2C0oxQw0xexGom^#GWn=l`y5S04R}X=c3oCnghxWrczg;?_@jALBBv!rldH#r?;rvgy+V@&jv}CX+!R`6hR?e z?TTB%=o@vLs733mhy`ZO&*PZwSB09RZQt`n&QIuXPlW9d5WkMeB zRQDE@y5xC9G|?w_b7oqKd5g8n?Oj`$+U#w+e&3QY=KmBQcb}pCBy6)3Z;;>P-NEr$c8F$K%dxdgl|)MZNz^>SU0K`jF)pU7*L z994Y-#_CelU7--OIgj$DN|T7D2S&`vz3ojbpf+dZ=PpRn%`})#NAsjf?5~OuO#BE$ zNA38hel!l%fBB#O5H}{We<_-9-&Fsj0f&RrMEH+vAI=QtKgw~q43&5PzrV1c(uAJD zD=|6Q=C@I+^ZpG9N>r-eD^=Dd`)DJfgMXWJ>2Q ziy?UCBT=dc>M_NrJNs76ETa0sa>H9KBaq*JPtC#x!)*S?7$laY&T=-5WO6JR14V?t5}_YMJCOawsUIRonFS z^*h0OhLgyHiH&82T|fk-yFG{4FdL%Bo7t{cSA&T~jS6jrD9uE?(~&XN26ZLjt#0Mg zI(7LAoub(?_2$N%{fun^stjgFoR*_ze!PY|txxZ0GIvfZ4-Gai;geT9idKTrZ^Ps9 zv=~Y(t0PL_1WJz^w<%h zIc)7hinS{%qYlG6OHnxWz3kTY@1 zb|gpsEO9uA*R6`Q)nUto4d|vcpCO6&$K#Xc_B`|Z6JwJq$Xqp#^z4M^u{s^NLzi#I zKmDW<(D?^`6SkZW4i0=_UG%V)eU5*WlW=B5CJ5uO7X9kFx@=UBr$?cM8cP^URADd! z*7Cme<2^6bse)AdhJtOUJQR+XO(504sN(=!g$LBbb26AcSsE~U&WrO4T(vPCF`QL} z7*|#*!{h9ZKa!l5Cc#skldGLh+9G%v?5wA><{<*md zvS^<3UM^OGYX#kPIQ@~?HWJ6a-p+E4ez`!LCZUQUOSAwz`d8hTIf zagl(Ib!Ya3MJUPQN)7!E1C43g*c`(;Z(-b{-91=qD*W^3#6(2@D3{hq&A45qQK^v{+1)~om@b~P>tnTja z`}_O+Byuo)lc;E}!Vri>Lsyq6`pe+pAdHgv?{xr1Zg0A&z+kYnzm`jw$>MrOOibX} z_GT|9lzO)&3O{Aazk3awvm+Y&G+&r5w4}DV%M0P~d7Q53Cz>%o{Q4Ii>Cf|y81II= zg)L2K-nT#of1BB|7KmvR3^xc?Oa)7)Iy(-fx1Ic8GKA^MBOk7x*D?Jo ze}E$>qZP5!ZuQ!NX|aol(~HqtJK$jc`tQrqev!e5-l1S0fy@ z99$_JOkbH2qeOJ)diH$AL9_Ye-$(cs^a&=5$lLrPYlGwaR()7AwEiBXddB~hKwojw z-9wg+cW;05w}b-j8y-wB_>EJT=+3*twGCTfHwPS2DVv%sxa>Ise?ylX?tBcshfgVl z>@R;W^$a7es;ZA)Uz$}$oMShB;o)Xaar{frq?dW`aNcaMhC0~2Y2>Bk-{&d+9CqmK zdh*+fF@FqSTK$oCm^jvH>cE@G&}D_QJCa;3Mh?~1;sFBM(Gx$*^zZfi2rhzJntFbs zdROkN`)b{q0WmW_e}uXYd)2RFKu@D$Tul=Id^`nz=K{={bI-QMc=J%X)wpCUNHh>{mH5xV>cQ-zLuv>q`eF` z|GU7WE9{qES-F!{7;X!1q^{aw>GjCSIrg5<10N99(gKbGOe2ndVMD^~KM+x&E2Rtrm zZ7YiXC`o;Er%G(bR8Ft&TeE>^4Z+FJm&dL8Y&Xq$)DHj!E+}FX3jTRhmzxGexj8_5som6>~3h_sGB?p!>xn&dM z@w$QtIMrMI7{ND<8p96;0TgSB{Yc5eBwb#S18lft}_`Z|J4%ku7vq<&;S1i9b0ZOHDOo5}`6{l=igVnulK+5 z8#&%yWV3dRYM)-45fu9DY5jIU^P_;JE&Eb*v4IiJWGbmcp+nKSKtW<^n>>y0c~M{O z2Fap-J6mLlJ1>|KEncPHYnB${ckm5&3IpS@fAj{8CI}hPk@reWnnors!9P+TOna&# zevi>IUUBD7oZ9ibOSwS`++wHP0Pw5rnY~rS(eb7Ppzz=EpWf=uINnZ7M3L4*2ZWeR zq!|R)(sw3;30Jxf3@11+V*wRsfbST&8$NDsAr@C5UTzw|eVJpGJ&$y0z>iQDx2=XD zWXPLToOrd;Aka}9`qtUy3aC$}R5AA)NgTxl;(mI(BZ`5O&|50y^<9^jApt{YiE}s7 zyHACP$VcIJQ#T-8OK;xpHCBR{a(Hoj1jAajefgE${Lf($LM&rzP2}GU-u~!fA*)JuQiB$$hHhO zj3xGE>1vfdf!Gkd!SxQ^FYXkjTgtj11!!afwvEsDq}&2Voh zy?E;J{eJisc=f6&zq#aleLVS#F8ZL8f|}eK458nv_**`#H|L}Gah^k$YJtk0ZxQV{ z38&;jv%|ZMaI7tlr~FDYTDd3L8`Y=x#$6&8R_sJgRV7`<+Nun=>4Jl9*;9wt#^O&( zkV{>YI^~U6xSCM_iFa*5g+q5(U*A==LNPmTbFrcebfV6)IO>Ls3Cw>oflyiG`K`Cp zRmGufNRMWDp9&qbs2=eP3bx>FXK6+BiqOmyor=e`D~$asHK+cVH&(Mi%Md}x`Puu! z2(RP=fTr}>A%0=FD~*v0A(NcW|#hn8a}*cvS;$x zJnmPV!)m59oPZlI?33Fr3saqh7T2^pD$b{`G4hGn7c6&cN0j=aXgUbuF>iO*h;6F& zzkE_uyjFbNGP|MQTgYp&T`!N6c|(;t&&dvUw78@I7Q72{-p$Z*ezW3LP@SsLQwXTy z>Ku;(UxEBYgY-$g@k^b|(6Q=pROK8SM%$tv_dOZuU`r2NlNlw_&W|Z zit0`Ay`rbD)L zsS1H6uOxWQ!Kf$Owvv`3fy7Omi%1>G@gnJ(#E~HD9~a8b#uy z_o<8Tgpkh{I)=oTH!xkga?WmF=xycYFMio_82#zg$3e(HeC=iZyou)$geV67{=*#(ID5w>E#p}Usi^idkss*bK=}dRDMp|-KU|fS8RZ8 zIdFvsMQ+<(rl)MunAUzrPpcQ!)ij~tp}a#=X7Q>vD*B+EHt{Z*H7VapU|Bpf1>#fU zZv8gB>2tvi!Z}9m)kGqK=njI>d;hWD()Hp>o9#o*&~sxnsxgP*m*`u^O*sLi{Vp!f z+q0D}v$@X(fsi|5454ar@60_cIBxs|g2|VPdEufbGWAm;?tp5t=za<2+WIWrS z?2!)i5iA0&RDV`?QtfY?vq(`(Q7BDimnhxfn+)$OynM;P=MLPgp$PdL%(aiE0=+UU z6M@K4mI)1bVim_tYs&_z6&Ik|lwic$Box);OC?ImrGz?aO^Qv&#pl23IYgV0@1#;K z%z_VYKwRD8Phigia(<5SV2fYLe15g{li@7*N);hhvUu?_Hf^}4yy0ekZ(drh3A2mc zF}JOam4>OM%1LcTStALbfzRXn*Ns?-Sc2w?vIDxd^dO|&vfGKutc%LTOV(J^GsMU+ z_+8&UYQpBwdoPyB>FKfu_}R}Bq#DSAF>)+*YZA?C-)09Gn~;EEKp+L|3)$qsWhnm&P=cH0(PM)9TS9RZYd} z879Q1L9kMm07E}2#zK>!LTf|kR zRN&!uOT2{M)dQf-Bxh(9@Qt6Tl^1%KCYZR+(6+VjwqY;S}#XGYVn2JLUcy0t47-_3WR?hEncCFJzNA?7{R z@OVaS&B11-I_WTxgEZ5oC7EmDxrR#HbcD>Yi zO_YP1Drg>GTnnn1R_}rXQClUDX4oa6U!6n}IBwd$ zjX0{0YZ>O*3OIa?bbmPdE6O}|f@OQZdCZ%Q;P-%9nQz!DPP->MSMHJFG1!*sro?IG z6!@G~)++mu;6>S=B5!gl<#Z?Ba)`#ew%jLw>A7LFW{Sosh}xG34100~9`5H>VYOlV zHWqC9h*)r_j|c~+s?&n)uh&9a5T5w7c^=R%SyJZ$%Sjz3F~VlNbVhm4#5kJo936`& zrU%4EyyBppm2{o$F{OZ^16rBu-TsMnM6rcZY3-kB^$VWtT-a6R#8IAU%)V>;qbrfq zEx`B%?AYBc!Hz-$dj*%p#`X^g7jFrYEAC6I?4#9(C6STorN+K2;=dV5?)X{~Y#&w5l1Ef=1@?YW%~MEaW&Oi*@Z!&Jo4{|Kh6sp#|l}$jE^U&>R!4S zQ(o#V$x06f*h7$4R1#ALkf-Bd zPem^#F{94&a~f`$Nl6{(KdwJUBAcx7$)0`XTVyO%>t(?zzkJpb=>gW%f)bwqn0_WK zuL|yS>^0g5KE|Js*=k9F!}Wazpt@Z+s00c}QZEtUm5wtK{>}xY8!~L|h(2O$+uqKF zn)5NCIYm5~Esvs_d@xq(=dZQrSDQ(EIs*jRu6n%Yvce%si?=;B0YKsnOBfl&ufwc~ zw#wDLz1|sFv3Xce@CWn5h^(APv zv~`5Fg>2Uy-ue1kKnqwO5ynQXk<-rv77qy;U5u@p)~<4U@A4NMin(oeX`YIau*y@( zP}EoL=*B!c#cID5X}VsW?jN0C>3B1uS?d}PH`m?}BDNl3>10?*6_fb<6@$q|{n7P@ z|4|BtXHrsA+c|TCHQB(Br4gD5kpt)F4k4cvRaNuy^ZRtUMG1+!@$$_OybA_ad){X* zD&1z#3{Tz$KZ_RMPGNCVRcyrM@QHh|ysZ4*&)y#zu zpZ&n9xa$eV^@0!NXeF9MM*)}~=DH49V&S_>DF{(QXSR2>XXf^4ABuZM)8$K__=M|^ zhc(td|Maa|$lrAIj6U;}{;#+Z&bnjh%||7O>2WJrug zI4q+1C$*tOxutLw!lymT&D5}oY8yYEfh;uUJf0MJk}Po-LPwt7H-7B=YiYs0f%8m> zKIXqb#ZzYCf0uh656MV67OJ=rj|u1ucz!XDam;3HDAIS=%_pMwwajenICfTYxJad6*37e|N#zh)J(!$=zx`&3+%6+zjA|a8_ z$w!UE1nw!#U;P&4`7x-E*|Z>T2@9EtYF2Zgn2pQUen_2V5#;cF2TypSaNR`t9WRsb zOb2ZGO7ydb4b?`ZZlNS!?U&Z(AidW0Z?B{xL+F!5Juj0e^g&71F4O``zBXr=)&JJY zG<(_5Ge%$u9F^{C705f29e?<8-ZFH^hc&i5>toD%@R`Neara&dRh0M4fy0&S7jF-C z`RytAoS7RA8!7X~@_d`QXl@sdYif%G4p>j7IoSoV z61wPze?GQvoQ0*4&r;KwYb#Fjb#9cKX5kFaM!b66yb`XvJd3}}=BhwR(sI6<`;?B* z(e@j_CTtC)YpGwEVj_sfUtCxWr^UyQ@}h!_FV_jxBQB9Md@tN}w^y{n1_7e4113@DP-9W40eCpz`DUBXyA>HoMF7*R~KXJiT}N z>xcF2#)LhwEsLmeBcrY^&ZEnRcy9rWxOh1M*H7}6sAlw0SEWpdOke_l?z_Cf93toi z#^j~jWSIoc5A<6~1%{MX7HQW|E#G9{zxE)K9A6hvR^0B0X}>=3H-~qrGDUpJG=mik zU!9#T|N8F@ms8980*UPmjNh5yhEWH}=AP@G=Q7F%yprLB-u6CqLU?NVNLiMab=in- zFcGlf*nC>H%=r)lY@rv)%dXXlg?pL}wvpN!>V1m$uk-?qn9h7=T{g%~R{19eGK92fBv%lx>ZZbni2W_py;D-wUdz6P&d4d&NH&1TgOQ!9WK(Ha_wDf zLiu;rez`(plg9k?E8{=WrSN1bpn36%C|1|$JpcWy|HRUKBzt9uV<kvJ=7BCaQj9-2dDxV8Q>0A>iP~DE}{w zrvE(kV{tp+b*I#tpCu_Gb3vrO+COz9pae{y^3U^NbizLnF))eRKfjXu-`RfuU%?Fj zAK>C(#fg8;=6~W7L-CluMM5#dUr82oN_b89)_)Z{{SPw;PHuz^HDl6W`-Nd`o>~gf zIlP^cCbi~+Pg`zEbG1tlW#0X|xg}Wz(GlsxHx8waXL5dDKgH)Xz3c2#T&-de{m=UT z*1|7hr|#{snxf|8aU%X`O3h?VNN{u^{MGA%)oke%A!oQWM33MXqc>e7RPT)mx9^gd zBZ(o5V_#z0z`MH(r>-_Dx?!Uq<3Yg{HVOTvzQ)GVlozj<{pBq1WWLgekYKpZ%4#eY3B!=n&nVVb+{|9m)IYkxw zNE`)y$z?C^1FcK7Vb;}d?!C~yLJ3mgZ6&+1lA@!&IM6sdB#I0uQzMI2oNy%gv zi(F@bw2V?oURJg)U(K)l|JndI7J&^o@FKIAx@dShte*dW@~TSUg$eidFE0Dq21kl3 zdV9vE?K=mW4Uuf7A+&KcrojjZ7duE^U_C(JHKI$a-tf)|3UX6NH;U4Bw9;pJ-g%%I!NP9l6k+Y3KF&L~eFU0me#L-bx9pY1Yxq}K zrhN!Z3p8nmTP7J+F0IwYj!=`f_Ij(z`gfGwPe=%cAM=sCi4s}Qi>D2p@W%#SAEax? z`ktDtjDva^gu-wci;}+JDa&FCeF=Hgqxlc#v>l}c=A?(aElvC3ak&>2-&LelL^Hme z-|O+tPOqHhdTi<3nbXv~O08g6T8th;M&3Vi9iDJOeYs+V!`5qW8%UutXF@WS%wX4h8hzcU6!68 zY<^<^>Yw1YXF!AdOerosttzub{80(&QxM8q2>;Ll_q#;{dAAN`ST0!~aM;Jqh z2L^U{`Oe5Ef`ic)J7tGgmSjBx)X?D1R5<_G zYd6k6QtJvcNk5M~4Os^dQW%+xJl)<{ri3yFKU9(5dnjRn4<{L$ta+D^T9yUL8B;l6 zg#_r&$@!Xm%cOb8;m=r?6pqj;P|k5WI`1|P43qPl7jQ#K0Tr}FE^CMbEOI-mRw+Km zm@rw7JoV16RzGMW(e)PXkyzt%A+iZ1MBTz?@vIB(<}gaBl08`<@kyOwH0@PV(T_<<4W4}EF;X9UPzV{&c*+w^9irL72Zs}zPDXPm+M77=vQ>VF;qYpp z;klK!;$^EL-GMZsTc*tje5NPpP?pn3+RDlyzmp4N=xq_`u0WWTa$oPDz`UZl7>A+` zogH&V)#C!4h+@u64L&v2QalN5pcByn>)Vwhi4lW zj&=pTZ=Xy8iQ6yKt&p%T^i(a!^J{#T6nE*SQ+#+`I9EE{t^X@KP?n9b_5;uUSF2?8 zuJIuBXjGG9_Qk{+@5Nm1nunhuObJICj$dHu9c$lqGR!ekR4__a(%$h3r!S<9Ko+Mb7PeDf2&_&}KJbK8Zl#J;~v0Z!o?y3&S zd@;PSgwv`j_M3oIu7)YOoZv1e*n4pI_$du{AC16jD$#4iu77hLHVK)$#%m9%h}%WxC^MB$y@>NyoqPb z0TWv<@}-fbkF2L?k60tq%_!Q1V3w4>^K{f)8rNz^7Qs7 za$IVEBC!-k6j?METEMS_CTy5AVX$Q2hDQjbP=J7M9}=E7VaE=h2=y4s-vJX(=fZ<( zSDnl1?2W1Cn*$7^0bwJ(GR`dScDJ7s0*keLTW-+_rSOU-xd%le4o$cyyz{bKfZ=Q@y9}$$0u9VUh zDCqzN*B)0}X*im{MR!Qy_;NcAGH&!jxkPFlBk51xiWfdU8ALYW6%d!(qxGJe_f8=?~MgechG;=ZI6gh~_p-wY{FS1S5fbWjZUg3B)52D*L2v`DW zXF%dXwqr4J)_z@i$<6C;@}@h!h}S)8q+7k)n_F>~^gR}4tF8Ft={LDh^*us6A8I;= z;*J7*QJTgy=~-p^S>%JkV0FvhZvodS1g5Mm2(q;>O~u0T<=6dC={q9S%q+|2eQ2cU zLaVg3*UZ`N&V5yPx=0$dqoo4%-F)m!n;&s0jJEl~CPx|$U@FizW0@L|<&^wruc@uP zI8tKp$}l-70V*p}KcM_6OYB7Lu_cX)E_+YRzqe6cEvnNza)=-0p?NC&)2ofWMBeZZ zL%iOsJjK9YXS|xIt}Yn{akKjalJ1&8xGq)klCy(#K3gj}K=@ZGpn@lEz_JGim#(mN z$mR-4FqBFX<cq0te8*B$;qhHI~eC8!%Tgyf<(Lm+4w_f6nSD8EPK0FeqRU6Bdo_b z=Jo+v1DE=#`v9FIne*AQl*aLP3pU_NZW(1qQUM4N3&IN7@Fna{RF^nWe4 z3dl5)6Zp*ak0Kn0Z`4kx@33sBB$e$FMGuY8Z*J)`mA}rV?GVkZ1FE9T< z$4)gQ&*>#@ytU^rvFy~JB8%G--<6`hBgW-kRXNX*zvG}r;-?$=K}m*J%kuD`z!86O z`_!osm4E{jL%1jEljn%TN%GkHSi#QR;!vgTk#}gJe&76yBq+-VqrB3x9<(0Q z;5_>zCV%wBtlL;}K(qc6uX5VsWm?Z44jB%P5lzGnZYsl=t*8x#1jkad@T$|8+4ENz zu;7d}8BXJ{-=*iN#55(i2kf~&g~CSr3L4(#aD|7(8XA;2`ra`%zQvCptcH0~PbdRm zHZ;~?JpjisjP=;;D*c1yOxy&nMbgeXwpXm`nRoO=0d2LZG=WVgNH!qVi{>qt^9&>e zU5s+T9*^~);LA*sh(h78!(qw%iEREjBhT$mFC)Z>ROut1vT74)eCyG%aG_M?hm?bJ zrT|BjR-ROg0}BZhG0He)?4-x?!bxn+yLVlko0E9)bs>R)m6EDpnZ1=307dSWSt1m> zB4)E+B>$p`TgDgG4N;j8V;LPiD@6!;iBH`nw=!FW&*wd(Jp0&uzc{#;%SGNbx=o1c zobMr9#nmrFi0fWm)&^9onszR4!59C;ScOc;Ba<({3iA@QtgMAOWX=UnPY|-umY_xn zLuLdVHlSm=z_Oya;AaWzyo9Ce_`ASYwx%Bpr7Y2A*g?o2hU_O{qh2K^%pInLZ(I@S zz`xdqq9-JJbb{rQSu8`d3n}E3tDDcm6Msx5X>xAljU@|~37rVr9I0@YK5Lj@I}Crz zM!=dPl}_k9hYjmikYwWYF$9&E#|9JP?Fg1Ee#$ikHkW~KQy~yfo`$xgV}opfrvTl) z#q%IPd5_2`$5GWqtb=OMcgBCaNj z#v(J1vj?x#XH3VoP%f(*Z^rPf5%#x|;wOi7!GxQs=t4a@gCK)W*&TcynN)#0ohxD9 zq1sY4IAo0GczJ zK!;uNXv{EVfnBC)=jBzMxR&dxeRhoI+k-EUBSrn+YleeRF`ZV=fZ=*vGx}Ng;Jv&^ z4c~)E0%;w&uQHCiiSz3F=BMnuuoqOWck=cw<4`TW-n+uLo($=8jy&K4Z{sMOPltMa zD&{LyiOMfCmX4=o9xku7ZkP>p=QZ)SLZwOC+`DpqJEfBi(VLeF;v_FcYpBsmamgB_ zvwfrDXUr8*vLKPGZI&2aJU!Bx7*C})w)!fF`>kaGE1Lh~L(`d2gpwZl%UD}HM?!;- z^fOqf)vQH{Op;%QSDi^&n+bb9@>?8{ExF@|yc%>QhZ({haEc?vlyb6DYVijSxH|FM zOD>hM;V-ryiE}7;&h*8V_~sgUlFT`>4a8KpJ*pnw52cR~oKgOqeuWiN2%l{QnQn+? zsYePNc=ahaMahGWQBCB7QQ}9r)O=$jYeUTgl()9j`8bXUk{BO4PM5`MROd?&OQs6C z#NsH1r!$grgCi7HgmL4u-_Q$X)0-!vC$I8?2fv7`^%b1dXHqqXnv}<$JLViasuuBc zJ$^JQT7Jz%E!;!)K8OArmYPJP$6QO9ULx5&fP<)XqNDRmev8=9$-&eVdr0)Oe6n99 zG_NaoZkG-72tHdlc5$hGX$XyZdE}=+|De2}qcbv-Ohn`UjGk#>a(-r&PPQ?R0cdkV z)dS?*W>dm=bLFF&3Q$#5Gnd>iF=G6^sK(v~t-{HFv~7Qx0(k&LQSUjI{8Coe9(35a zvWfzXO)blJ63DdqqYv#QY!u=kM~P~;jy;$+#PKi5Z`900kl7c0?mHcD!yyPFuAvBA z53QN0Q7r2`;v3`>-`7AV9C=6|vT;Lei!ioYmZAS&?7d}FTurbx3K0k%!8L>s+}#u0 z-8BSvcTKS1&fq?{yA2TBU4jhm?#}Q{-h{m8oFCs=_pEz<+_mofU=2MpyLb2QuCA)5 zs-AZ=`5jS!IH19N+E_b`V_N13h^|N=$xxv}mFh0}qk{sIblV2_BEG zzyD|ZaritMn%F8f=CLC80+YN_(pO6Fix64K!Y`U}b+QhgnDCiRF^JgV%9h9lps+FN zXniVX=z}3N*Y@II5)u)NHDqLK}p2 zzvv6{e_;F4741M(Up1wX7{y7Y_K#r*)5_!zgZq&f1VN2!Yu_B=DZ*b=67b12Wj4+U zHaH)?(>$!OowBaKe%H0yhYlgY(fP8yGP)=lOokT|T}}PGdd2KWP%QyC@DZ~h#*l}6 zqk6US#s-7dJwhoV7Q^U6t~jR#9-HNUh=U7A<5qvU(>YW##j-{-A{+QaZ=c2tr7*E$ z=M!EVq6Ec3K_se)NnYiA5%N@JrfEXGizHYy*mOW$8i@cwUenJ39d&Tt+tuCR&m>4vr?n6)B7Qpy62>+9Z5apLP?*(m{C;Fy303($Tr8s*)UF zu8u*T({%7a9FBxrMt#NQcylQbuyO{J>PTT1_K8K2TFA@PaMc-CDkrC_O~&a9TYwsJ z9O{^*W~BI`gXV`zoKyVah%JQ8JSAZXD7yrlIdUrCo85tY2V6=mC&{(-FZ~P(*}FrW zpu-4zusCfof$AFyZKO@PtWxRUJB0=gstu6q((9|rSjg!bKt=}JV$xi$RrxWc$ms?f z&^^g%72Y9H*!lv9V#LKyeaojY9;#38JFs=NO>hQZMLVY%%@^aXuJEX(afq4d8lFrd zzcLdOHzh4Q$cT0$J+TcFY(R(vJWQ5vfg?~$Z+M=&W=_}vDos{N>j9bXR>w}RLbbRU z_GYx`=r|}Ox~p=}ZcFW55zd06WV#Vf`>?6{-=uP*r%pt~y;QXyUtxW((Gc_|Fm|h0Gi;NG z?jZqxwX*CtBT<)XISG)f@^J_wy;teLFfLP_jlB7`#MSRa>U)>29L>0$IW@S7u}( zw_1}Ipl(J}C8VzTRc#^<&6h#NEc|pX1kPM$P+nc~l0h7Llv|ro0~1U_4LTD5L!>Gt zB@0aIyDS3xO}=)4no1H(Ut|_3S@sOotPE!-?0nnLla*NT83&?B)4qd-^~t0+fIZI+ z1Py^RfOfRhp|ys-9TO8q8=La8m-*r|XUadP4GnXe20Eh02B{^3IdEgGb@;jRsxrx} zOpaS{HsvdJlIuNxi&p94aao)|cW~ywns3OvnTakf_1#=&8c7k2tSj1-;nxT5%@MN| zR)4sd&Y_jpVSvc+D3y1cvO-RpN~_DODbga{euo@n6h_=y z0=NxlD>GMf;|A+&n)2eKZ=E{nl~UuH*RAK^Iy<`rwEUr!gbt1loV&(d21V1>Rf=xT zM@z!rg{Qul@l0lLAXxoTlBHv{!?r^)o=lQ~SSCtRW|L<3aCb^9Z{KTvFf`OZft#QNHYUiK3zyeR83bsq{_v4P z>l8i!^@f&wp4aw?WzM4&=;A8ZBWri;l(@|C8^7Yb-8WU|;=mM637TmM)(GCFQs2`( z$H~i22@oXYaT0AvlWN?mglFkDc75tt&b*85>9T04OQ+&ACydXk?jg*@6T*3Y2_aaQ zY;RR;(ds`lHOmmQC3%?!U8Oyu(Kz*hH;O&^pNk~-;%WJxXg9hZn5Vw zk!=a`k}cOvOiay)rr4-a5xg^kW^OPzIy+T$Mw1pwm1-LYADVp~XSdOhF=t{qYv2m0 z+~izE!!eA;!)Ww!qE^v(bQ>Qyu~X}*huQmAcjPu^nfpx8n=glM%I=$$vjU!&fCVD{{u z%;6wLVpcO<3sYSfQInP;+Nw8*<-6ue4tdi^f^<7fXx6*rcgB5ShMxvAVt$43i%%mJ zX|VUWASgIkf&IP{?;FXi2>l20;@S7dLJ!N|aDH6=9FMuWe>OL|@FTyde(YNpG?!&J zso#Cfz45B7&KzzSL(YBcf}nf+XMcK=qGAM9NMkCHu1xUe&O8Qj{3H}^t~&OtUJ|>W z?7i@nz9=GS2xX@maX4+$MrZZv**_xLnD}o5Oro~M*c8JPK)U@@+tq!X<;l=2PF(y+ zaBi_*t8JCn+0&^f2SQi%=NO{r4yOpxB^S9(%7^<4^xU3ClEGF|7%MR;mF5BAgnEr{ zsh#~~ruwY7aaog}RN-(wN&3`&n^*z(r0w2usLL=@icDkz9`pI~@u|s+nyfr2D=qq~Op6@s{>$Tn#_zOafJ2AulI6k$Ptw$r*&8}}#w zOj*@;z^25D>x~1vFY`b&6~g+C#C>yT>#w^T;ro)#6>TcF2jyTF_Rjt}&5MTKWD+CQ zLPqO_m#fqsYuL^o{$&z@siLuPM&9~%_4aT%ZvF~0t{vpFf<&3ihjZ0t+cx&yJn)-P zW#&Cuk6}49eL%(RQ*g5kW=vRFla1ASA~)*?Or;Xf!rJ2JY@<_ii@8(A#6`JEUYN&o z&1Zc!Y{-TXTJCoeX&6(o+d*q}qlNdZw^9*<^v$#E#DU_b17dh%%;K` zGs?qP8)8(y2l#80RW<*!z?<2{M!;+L0c#U|`7z+r-x2KfCKa!k{4E=y`LF1WGYq3{ zXJcD^d+gL#D;;Tc@1YgS_mc7JjInA{zdhwWfW;wfNzRaWlp(K+*EAz79hz_Iq|xiN zmgq-F)p;hA+XwGmlI4%6teCa2ta9Teu*+RJ7mT%5|CU|j`rFJSHVF5K4K_7J#JrlL zeUTrL5dJMETs7vvlRhwLekTrcpP3f*FEHOaejM`D7+OMJ7lXkQV^yW>^wU=r0u^}I z_#>Qg*2@=~`_3%%TiklD3!g^<_%~FKT|yk}Q`w_ZI034S6PGHkGdM@r4ay~}18QFo z*Q;lAKmEA7hE2PeUT0|jnsSJBdVTwipXx+w8VDKM_*L>;^D70LJkA@D03keQ_$zS< z1|lx69KUaUcp(Vvw&w$1KeDxFr*VsD%(}wmitd!??qf_AT|ePNv(w^LX+Lk?u;CJ5 zilNQ>7gc=f{To%xRl=+onfaJBH;`bJz!aRIO=3cI1s6tgQ+{?fbtnBV^PP9W?9NO4 z>+3H_x1O`HGSzM<^q8BQOkJy$9cc@AqW^_|O(&Ew-8#sk9z2wIL<#uiWu20<@e^%!)-hmA@OE(-6Xz_>0`h*bbZgp)!=?aJ3HAY0JX8j--fkh#(ZAH7zKHN z;21y9_5cRo(u%e;oYv~0&b<99=-n}!JI{t<-#{E*3im5j{Hrzxj{a>u`wT*?2bTB$ z5^cbcd&8*XfFX9Q-2=KZk*jbSBtAwIyJtW0^iw`X8>;T2Bj|;72quqarPp7H>nqyk zFNKN;NL{J*lIabpB(n-*`rPob3g7%qwN6Kdx(xDSB4gC^tX7SSbBCM>o(Z^Z1vC2A z7cq0tsASznK;2KN4RMjNQf&J{Gu4vC77f({FDL&_Jl%Wfg30^W%^+i9MXu}8NgA>! z=JOZf|48!7<)5ALLxBaCdAze?mIyA!(3H_ejp8p*>Mh&`WrvJyP>Vldq9c;%$*ihx zV&0X%%BYh>7%$s1RCV38522TlS59`>*0j~_-0L(!09bAQ8|5YojWvR$%*RC|I<)8H zq;((W5aU?gPDHg~U18|j-CtA0b~rh_=ju!F|C;Z~rA(c|!*s3bE|;IK;pL7-{5T$O zeyC%vz}SjYziB%nQK4GWqB~)>m(ZwVPfX9%|4fwLwZ{AJu)O85zdcPSjGE{Hw{*Wa zB`s=VCb_68Qyk7i`gdHeztSdooDBs6423%V4!%dyr^aOfvlJds|2_qn9Y1I)ueN%Q z&r$V$)n4=L}^lkoomx9fiw4%I{IXNAU*GB}%4R2Q+oEQX95=va{H*v|>Fa=ZFf zQvUa=7|Ku7S{Y;W#Yt2%ZqH^rwhW8v%h30k@tBV-rb&yI7SAYnE(k@mC2Lt~J8`D02Iv0KOR-{{#)a9#dV(XdS^@@yBeZ zA${3I)D?9fAb|xf5bs&@ksd;Vkl#e@L*QQerb1*GywfK&Acx-Kc`O30f(f{+#pO*^2AO(#kM| zOU4X}ZU{Fo#rtiay;$0~9|L-G{M+UU%Mhd|w-25sCVbBg*x?ZUzHWb_ZGXdyVTs)< z)yvzo26_Q_iZ$SceVN*_9SL-Fzd$#J1~=lt(^xXBc8Pi3bWsvR6%wE`G)*XS5JJ?6D;w?$Qy z5+kBaeh!KW+`K>S+86oI9%>Lv{x5t7ttNn4N*x{hfahgx#cx^edwe#K(#3&o*0T{7 z9MqW5DK*JhRc43#rJyrgk4R@jZEF)~h(3nInd4Z&sYs>yC>0A;RL4i4XjjCmL$NG$ z9n`s`>_hI(45Uj*dtI*{DFFZlY7;b?04>D4Z`@2NusrJ7vWLLetUWa$trLa%6PJCd zfG{Y|rzHo^Q@Knl0Awjy_<%#^D1v#Ow*N(~ylYKGSSGecMtI;ruk+rhLA5}9*PYmB zPHl&?>#1;P&DzQVb%D|p6=pb76cILR!oIx0qAiL;)CGEVbaVNTUYFkE1{i6WRfj1y zW2N|fX=n%D&@UljOOEvKfi?1lJqhe$67XeG^T7!LzhsJYD_d4Xc1yh4(B{)RiQ=8N zhFfI6JPTwzz(z}PQxoM+WX$^W^3C$YjhkO>f#a@sY@1~%9PBU=M&l43MmSf z?kqrjZMlJaj!zYA>?g)wZE1zut1ZTh6I(RvHHM4_>c%P0h>T>osT4-2!>Sm!gXfg8 znW7R8L*#PfTxj$74%^RZM^33!`0!JWwN$jCM9^P^=!;(ccJ`HL>T*x7bV`SbjfkE! zK`2}DM2o;bz#6B|hrzNbiq~EEfr0EqkdDJr{(uafz|T znFbW}-(_AJR?sR6j1Hc0^PIjqBbN}1t#g!YN|>zQWOqR*Vpq^#<20y}W~d#Df11$c zxSGRdh6N5n2oDX$ito$ZFR=JxZr;I_K%pP^WE)q_M9vgWN?&bz23Xo;nbW85z)Em% zupq@H<9xEUs2gdjAlyQ0G2B%24v$QQ%mXnydYz^2HBPLi=`yoHPa!oG1LeuPc6y@6 zCtO@y9108m(Gbq;u>m)A6j+knhZ4Drr)9U`_R4dW=6UwvvxoR^rsLon+wtddzw*nG z8|65fMI4?V{}U+55#R<-s)&51gR4g!93AoAddv>~OR22)UP+oxaVQ zU!Q0k#zO1ZcVTDTgwLpR@H-et)rFp*7Gj%blMg6-u4gQ4@{kWnfs$u zBFlhAfeLRt3?q1*G&it8UA0g8$HYX)g^a(1^6K$>G&`n)b<9F+G~A7m#VU{dz2{Gp zMwR_>cW_;mbNnS^020x@2yB8k9>R0>D-22~?af&h+OJ4;F!~Iq8SwP=vO5)~-yq`| zX2g;;rS>yM$s?Ux;1{1y;FS7&Hb(Q1^QQ;Ie$X0*VnA&UIywBmL7qI;><0g8ppA*E zEgTPZUBbo3;fYLJW0dDgE35~uiFr59Q=FJji_V$rV$~JeYuGBc^Sfybbc?!!gq{b@ z3XTlM8{`;?POE-4HR-6kddw~6>!TS&2*Q$5S zib@NWfZ>(oV)2Ea=8XAKG7To2B81%jJqnAZJP~vSL|;GUX=;~JCJ+-9N7U(S!PmOx zZ)yp4%IrVLPU2toLoo~hVeR)TD+~XCCA#!R4%Zoi8kW~C`pWjEo%S|Wi(B=9VV|H( zTG>oV1aCIOE`m3{E$xAzk)-9<@X^Mu1KoQ8wE$lXC8`L+_~ua10~uTU54DE;dLc)q?|eQk5jZ9W_0!;*bBnVe%z9OV$RjC9Kt`M|J@Na1w_l=d+7sIggrJiO-2e${$k z3`{`9{1wlffuqjS6Fr1}Dq3A&ek6uMtq7t-e0G=jwxMB{fk`hvEy)m*Gg!UWwxMmK zAt`<~=D4V^2H_PpPMl$`QJ|%KJlNuUtFIFqO(i$U>DN>nw%LW>5E8Y{Pf?xl*jP-e zVhpyH)aHL{^W^3gqx=~CjOF9Qh~I*ENk45UIXC2#vD@V^w*8Nl?5;Dq{wHhYlpD~K z!%j*0j?3Mu>gy$}4p+%ye*Nv(^G~l3#?RiZ;+Ns9H+)oRH5t2r+pvm`-b?eejDOKS9#x&1D1nXYRKxIk%nk0?tqGzWR&Dx8SFZddNj7GX$K*Z@xq<-bhz(XRVhVZ4Zs~9-y-=$*i zH;vu)=KBc?kj=`xb!kCmy5{YNfT!3$GW4Wl2cX2;Phb94Z6w>n5nqENGkF|!XEw@Y+`(*7z!r_ zFI&PNlQCrP+Si3GC;XX$9na;qLRvdjj?N5486Y{!e(gMkqEaoDP2Gr-(wvGuEZF7o ztVrV4vWa||!^RR`5B^|cVocVkUJVDDKKbMisuX3|3A8)iTsLH#+H!r=kv~TB)bgaC zo_0bDN;gi~6Q+?u&KAgLurZ$u-#eho$w%~a+K(u)gG*Xs@9OJ+5uC~Lhj$bK61dM< ztToY>Mhl6bQ|hg=cE0DN=GR0&R`EsX?2CDA2&~*2eDe(BgZY3VX)J-<_3-}Sx6QQF zxDRizumEv!wr*LVI5;XA+H9i=l}gLhVR9OyD0f{+e$3&zByWb$0G#7o=?*ZaQe5k* zjn60aTvBamw^kl3ZJG5XjoyaUpx0I#j@4D3jGBzG&a^v+{ZJq3@FYtNeDjlCLe6@X zcXXSgsxBr|z@Gkx9o4gvEkSB=3DG`)6dypn$jG#${a-t#&u+XOt>~El zvHCUse@dF)1dUrl z{d&)cMrsZX$zQ6MWfKX9|gDF7_1z~dzTiG4TeD@hT& z=<&H<#0{udR|wJ=A+Nt`>m@N^1F_r_QE+-lgXx+m*Zq@e>xX5fQYL4v!q6xdqwmgJ z#D|dzNMX&azIbm;CX^1c}rYhelXvWm<|Vu zXbaT;8Pl;=H<;hmcY7OtNRpzj1xicK6#eOT6ujrr1&4-u0#JCb(!ccg9W z5RSYz&2ySv9FVhpSiI&wb)UoiPCb{gRyu703bmFR?W|jdE1!pf%=jFjyyzv9?N!Ba z{?gaHo|m3_WEusxq4Dw_@NL5O=cp+4k=AdQqoYq!cNPo(n04Ou;BFXu>khlAaj#l- z!x4?;r!fY(Zvb?2>37?+$4amUT(_QIHpBLXeykQrjAv%mA~EDc#&};L-AY03qvC&1 zwWo-WFWh%46F04$RE(J^F~!7gq=nrN6A}|z6~Q{bF?>dMp9Z9QI^DchIPhS4-AE=> zR?dBA^s0Z8PK(2FJZiZwbIl1*LL01#XGs>b9GL|uRV6&VD)2(R2mf#; zz3nn}{$%B|TnzpjH+e;aAJw}SxuM_$mhoPtH8O~vPYvtF0-t-$@X7Q7dUGjgSy7|? z5TbJy(K1YEK&EtjaHt20E5%+ESb|?>&|OHm-Ixha zEVN-ie{rJZUW8}HE5P{EqL(+w2QdZVxCpNH? z=@;DXLW3bb?8k?K84$XDj|uU(W@Cc#fE-a&kTr$%UQGU{WqOe;QD7+sDtgU((O+l8gRE}|&PsHrEe^BM|@ zIh4se4%0WYpt7#`yZ#GTi%94)8M@xah-^CnRSc(>Mo%c88 zNC1F74@S@J0J>Kmo?EIYF1FhH#QWIvdj8JeRbBiBPhS@+m&*Je|54c%l)&8rwz4NY z^<~U;;k;5f8;in>iX5Q^nc;(3kUY1dxVShq4GjjOpP!#lu5^leb&L z+&TlP>?&In&WX&e++}SQHO8#c1DuVMhjemqT9Y@9%x=o>bc^MM%HbOgWA}s~x|&U+EU}V%6;*s%$_cZa6zm zV*XLcZO~t1o^mEQG)?a%GO?@Klsi^Ff~5 z%Pju8TPKVz-zgCcOOUv9S|cq_#sObJ0m?b03fFBonyrGygq1axTj>&lrw6(d=laHI zahm=mE+0v&oM-m!Mlen89@)SP+4ol0H>PPBvDYYx?>mYI=K0;E%3}Xa5Pa7Q<8)eZ z{VC;QuieJL3kRsLf`vol=e11QWwwY@hNGA5g3SH>hk+!vg7B9fcbkJrOWM^v>r@zo zGQvX%I2&dPQ8*8an)Q3)eFrgS9{h$wNo<=GX$PCAd(yEjTidIw^G;h?J3C6ThN%tn zBCBc`nS+Bv`*&OEyh_8#+!5AeZM*quryD~4?BIcrMSuoKR1RVQh`<>hayP959q5ZE zGJsBi0y<>Ln1sGjSEPQ1Ia0Jd%=@J!MNr*JP#4 zs#KIwAE!g_r`5?n1)S4KNMKMVCLO$6S~gz!Wtz2oy`SKB+Lu2KK0C(GDleB;ok8(9 zA-nLu8z%!+3@IaK&~bPjv^n^M=6dyf|Jr43F%3x-xV_BNE?Qet)6!uJFHkr-+qMHA zW=k9t$zoe-@;V)#3`*bMbv?VfIMmiY_XUs0%D7QUP~i^C>Isw=s_aPUwvG+ zht{<**Jn63(P<$kM+W(?i54MoSVQa6U|}k{aL@H?vSG1kVD6B1_4c81w0gT>^jc^? zN1*Yq(RCpG()>+VHPs`oIRzYgc;z}ND!c1IHP!>qEhrR>~g{-C|C z!D3e7va6cU%$}QiFj6d>&AnlLU2@HJR@JOg!yKMq@1RCz6FVep+zE3_FHh%(H|%{B zYVrUExHOrj9PcXIL8`v@fU<{EYl`oPxXvSIC-X>K_@L0S%ghct_G+nF4{VodTp z7NCl&6Os!FEs{3@j%YQ=((V;t(zV#1=VT^T{4fWU#31@o@)^|=Klcb~`aBeIqv)A9MY^tw|ew#2OU!j87I8JJsHgj)d5L!sY zMb-MUL^<ya+v(JN zYP3>iy}OVlJraW;#a#)8f)%llZYu!G*F_bl49;kTUE-#+E>FoW!K z736K#m*>X(-&+LtH`B6R@lTCLs}xR881=xM*JsU4-`3X$epol$q=ZM_Cix?xml>Ym z8pp-XwR$E5yk@mHz&g^*OUml@CbSXZ1IKVV_t|rdnT;y}PI}=|GJb8Ol$Ykn5L5n~ zn9f7qvh^&G{89b?OhJ~XuZ!%O33q4AW?XKa-W{h5EkyJjYxw}MS22rh)Kln#%GG$9NmUoGhhvZIpUx_WWVz(8F9`46xuuo=@bS58lwkUARpj5J z_Li=-ih1!L&YQTnI7Gj;wzf=#T@f?Zr%5%XLw1lO7D*#fC({n=oj_By}2 z0_Unu3ZzEaqRGG>Y>sU};ni~eW3$!@A>%^6>B#Xi4Zo3hb-IgTyrnr2z2I)`63QvY zJMXBWLOWc!Bm=&8Q&&`qI*lH}ylsBC_*S;3$8fq&%bKR5GRZY@!q#$VIsJ_l%U%AY zUkg#M{p^rixx}+`WvvCdej12~5zJfWS!4uuvFg0PnKH^ewOZJN#SO?v@*FILC7`R`L8Wf=mc`Q^GB-uLTgB#ks{2^EskA#4oVS9lI#vl+%M_-RE-6wcR)Ep>eFo z7`qo9bn5$#^5VHYQd4-2_6hUgqaTeooV@~+@{18!!z~X;qeg#blwj(902XYj)!_6R zK*hw^@6g7$M7mCA$XtiD6sw^FeKL@=*~&)0GI`YN1ly>wqsfw;7gZ0#6Hgnd(3Q3L z(_%0cxjCTAhDxXwk^+JclE9jM>3x8Hlj$ld<7aSL@^zIHr? z=XmR1W{szM`*TOGR%21S6n$fKW^HT3s(Fz~6ua+t7#IwUz4@ipv#P!79fWyKI%FBFrke5eE~M;UikKElLnjh7q7w z_seaX!wL7gK{rIH1|-SgGLM$*Umwk{dUHS4cbinICCiz^HQaASlr!9YNn!A;(13nY8JB|lX64OGX z+G(DGU`VJ}Kh{CX&2?I{7x7NlCZ0v=0o|W@NnhQzzZDLInH`?Q2^aI?DqgfQG0B%D zr>3TcGQ&<3;94#=YpJQ3&|^buYMGmx3%Ze$lUv){|B4=LMf3Y5*p@^x{-a=9gwFGy zi+cy)z&@53@K$^IH^3zR`Tt_GkWq%KAk2Pl_Z0HBm6%xIpL-c8hn{zT-hak?mj39d zH2ehf|IOy(k!R`W2^xG?OS{R4kE3yZdsp{#1eh>4?bXDy*)Wppd9@rC?9l|KdH!eY zOJ9#Z!==-8Kn|`qy|COe0@WxbnE0;SD=txYtq38vV|*QssG4P0)63GC4)TjGkn7Dw zF^eC`&&yk&?-$)&KK;26jCxLG9lY1=+@f?c`)Hv`X@j2+910>5Qe$Bm18~tC(w!@I ztwQDN2Rv^b*~IjBQ)AS_kO{ho!3|e z1&@Bx`No=O>2!FZxGV)Vf=A{*~hCg)^gltqI%)Fv^BJP)tYn3^!}PO;=CZ{CzY+>!Hcn))eLD=gWy zBrhvzbpo@|wB>K$p!@cBj(|jrX&fes*LCd3R8I1r+42s{4rL?ewpsB-w_wFFI3fpC55*bk0z{Da?BVtHN;|f{MMY9{ud*ByfD{M`UHYM+0EP{leyM(p6&j z5_B67y3Ga`FziCh*ve{kThP*}Q{q{0HP_z8XFC+~%7gM`l`pK+Yw_d#GK*I*&oOBH zXAj44*uHD^Pr-J?FAo)_x7#Ho@6wXq;268P9CCRT)L(wKx!4x@MzSe+zU|6m)bD>K ze{7A2fN*?%j`3$bSzFCAKA9aHltSbrBO{xe?dt^qM@}0YcC$^qyu7xT^A&Qlw@$Z4 zvoxHE+JtA|hZA1Si@Zn+db9m7#F0Y9?kuSHnMp|&TeYKUx%k*XtoyCwcrQPf5m_r1IQhF0OA6t{K87{wis zG=>-Vp!**l#%!IAw+t4R z5izz^FN9FW&i4fMH5gpGU;$eKt$5N@HS{%HE^(>xP!F5!m%jkZCXr3|SOcO~3W5CW zbIS0;79s=Ay1r*#KgwNcsOpwv9;@;x!krO901>^KmhL87yJ@-$uokMMI!D0I5SIz`*nIP9tB9|LWn6GFOZaRC9e@&ZGq5$68ahNxjm$PvsCFI@E5@HqSt~Y7 zAYG4&f}*^tN|78L6B83k*={;n0cD%{?{tP`?GzFHqP|6pM8PUXM+ja5% zvv66Hl{q?|7JZMfzXw3LoA{4kXUt}*n>06a5j--{vR&u2+T-W5-JlI`PhF-Hvec`tug%EJx{3xEfBCF`y`1U6n=tm`1nbU@?_ zDZE_jbAsqs{PQP(jR&fBb`KVp>-kQ#SB(`;)T8$nKfK_Iz^~USXNxQcFDa>9NALLd zC<|O=&$d^lhnnklM=H$vJqbM;Btg4uvP_ z;3?2J1>sh&=v(eTZNxFV9E>1SCP2o#>~fu`C@rY@X|bAt^SCVut)VuGy`1_DM z?!%b8E;@~tn*@=<00bRzO{-+l7_5 zL<7lns#$7HxrS6uG%1>~U-a!K{G$zM%-2$;KD1!2VJfCHXED=on(8~WFGy0eU^6L% zYn5QkuIsU^POSxZZS!3z^fE!l_)PeJuM4Q&z5;okehvh5kc6vF)5tf#g%PoQG)bQ7 z+AG(=OiQ`nSCQDOq4nfCE&-lS4<$pIPeQZz=Jy25p1#=>5uWbQsqM;^xj#zU+w&>x zPSd>Z>$=gM87mIXrQu_{EwrkvM7y`!0}Aegiy5;)ti+U5*5?^}^Yd1$&y9qn9s+7= zR;qf5`jDErv~Mq{@YEyDGpTJ%wvg1`@b(Y!#DaF$E7q4wKkR6X^r+`%8Sw(J?~YYU z;U&N^L_BU#KNuS-PObCA*Xwb<0Vnk;DyKt6mE{I=tAi3D=};B{L{5Ok!|;BR>vkIR zr{7hfewiw(yoUF^*Zv;6E;gMxO*sW+6l2>l*X?WC{pf!kV3(nm9(f#lC7~*2w^ns4EBlT&#+G^*Uvbg zs%sx)t8iU@!%&%e57^u()h04P9wQ3Ao-SWvgQ$W!CA5*JJV8u4Rif7mrHRguJKNCq z!S-We(SB#O8SuQXuLLueV!ue~q^cr62V)&8u;bx)ZP#+P^x;r0rgQx7b1m{aG ztaNH8c2<*GWZTOcZ?fGo~plkM6H|$UP8v6zUsJL<-h*kiBY( z=>@ei`^K6o$r!E4F6wKKl?Vg6=e7E3i{G!MH5N4+POIECS}MjFg0mLJ<5*ha!P(!J zGB4vwhA3&MsCaNH@9yDTmDK6plN$}V9!aU7CC9x90irwGnvE)!apD`41LRO!qeHCW2M_^X^zW_HC;m7@W^qt zyg2ijvXN>75_cZ2>&dttv;KB&X57&3DwK=i0Y?k5$`SY-_uwQcYD&q(f>O8n3 zpO?TdEm_kaf2x1D`C<#crygaTKi(4mg-8Eykmw)j_g|6H|GyaqW+1cD7%f+3Q``$4dE`;bz=X__!Fb%? zI6UsRj|3LT9}j1%=YIU~+>$*k2zUyIytM$**sp}5>to23M#JVcsbf~G53A$ZcZC>j zZDX#Vx9pJGK}AAt4asLieODr>_viR@k1kf2JMY=}r> zFLAZrZ|f|?qSd_n>o50IwZMl3gWT9C;AoyF0@EvNFJGFdW5e@ycXyjHCl&+@_Wnns z9-I5KU};NB1;hRBQy}l^tQC5d;Z2&d4A!3|;!UJEXZKO3#Zw@NHyrQM*T+Xdsn;78 zm*Ra&WaMaLt$>AY)`^{MzpsUCdXC}CnjNxn9oaRdpAyknU%V~@_TlK#4#>uaQ4=d~ zuwbW|^s@NE_~g`eb!WQCPJn)}HDmIzonm;rSBxwzRs5>zjRCaoyza6aT*F@R6e@Ao z%csLc>Q}=$XQB6lyK|i#e0O4%_rOb3H0O)M(r5X;B)+Ad~cjlGGFPwld3 ze^i-bWN*pZDP1k-lhf|h{Yq!s2B77?TIo!8*S3ZmgRs1OHism(Y;;~mZp{|0A(q+F zP^j^@FMz`?#~CcD^N<_9{?^WNKw}q8+tK|bmXA7#Ni?$3W0EiWj2B6{iC~+UXPdBo zW&e5mPSKEAcDVdnHXf6^CXfAAQ5i%m-Hn9B$(op$xVgFcQMEddDttNuU4eu=i8l8) zp>1va6!Xw9d3gBSwl)c+`V3%#P|`V~$9Z^ZQyIBpbTid)fpywVa8Efb>>Hh{e8311 zZv-u+YXIb6AH&PlB-1So0y}om zl+F(Hs2Ke+hW264ueTRBlzyV&EStLLl@*!J``x*3TMf17xIh-GE0q;rNW>a!Y&bon z#OSEYsVNy#C1xLARxbdYx9~uaB>ZJ`!Xd{L0el}uSkUL59Y6f>6#?hcBRN8eSm9lw`_&B&bPj% z$b!nX+mFUOWS@B9=m66oOmw@zuX*Zvfi~=-G0ECkNFM5S>C+Lc9a-A)(%i~rxqtCa zH^A8c1N#Us1MhnKp$tN9?vr)v>g_}>a*DGi!$Dk%o4ZjFA~kjOp+uJ5(_ua|WaMN{ zhl0l~GG%rv^#UFlJ0j9%Z)-H9;p;}h9{%9sSJ@4WYlX|R&||OLEM8`N?;Uydy93FL z6Bou2_3wD+hWMCUrzVCs03uHxgWx53pe9s72F_GXDz4`*^rtkY6U=efv7 z9qt;o-dV0zkhYM=le?4}tHFU+2a#W=LZ`Xgu>M6Lh)2e zG;vzPP)=68=y44!yjEQk)zn^=v z$%W?bI+YCzCbDtb&%EDAB3aBP8m6%$99jLcEVSO*OL803%+ud|{o%A@bk*P~8OovO zJKZ!*Xvc|)js_x5M0DrzRZ9#;{laF--%)$V#u(}8Wp6ajN1&U+^=GjL+vo=<{jNMY zx;$x0h#(c1wVw$q!Yq2tT&uqZt?$ck`<{DlkBiJy!-eo*=LZy9fTr2nPn{q5_` zv|mD>euw&>e)k1~cpso{=U<=){kz{cuMtB_1mxTk?Wrs7i{9kcKaI<4NQhZzVTH$`Mds24~GRjF>LS)Kzx*WB`?H|NNZQFY)Ha*9( zvfk2I(a})A4DlcH?(X+=xzas+k-` z17qyY{;gj{dezwFNEetLnN713SP63Nwhg9DzMJ!1i&9>6GIS}!yH!2;KAay8 zdTZ3U#Gu=#2sr&^Frwx?GF!#qK>3lQ1UV#?o}6bd)+OY_k&E7c_aJmV-<-+X0%9j> zUo`4?>4)wgHdcPmE1lNz>ie*>HM5jo@}I&K3Tcxb*;{ZUk!6CfC&{P4mnRxUycn`~??UZCW+qv0;@L2HK_6*Q-&KuKS`-K4I^WrqY{&w@}eu<;j z+lA}L-aZp;gS%>R!GS{;6$dwvg_{1mTVR9)sazOt*!u0;9D>rzO$&3c(AGsMn$$)d zEB%;Mk7F}C;Sh5<&@!GoZ98Y=Augf0_38)p{!`nn9>g(Vm&&ea*1TV{_`2;ky(T7B zCk?Pw`^KTWtR9N}*3Y@waq>K4q{Wt&K z0p18`(DDR4IoZDALV@>xWZXaIa{oWjZaw~BoZTJf>p1fae=B4^x9ICkkoCVMy&P7R(b^iZY@0u zDdRoxwxX3VDboO+hbwe*qsC2ng2}-qwGPWQSyHaNwWoG6F@X(szu#M26%f3<1sj^G zjn+Et&G=H12}*2cF;u(szU-WC$2xtl>9S~i@2~|PxffR4bn<6?YqH~|k^RS!bMTi} zyZ&c^MtzsVnRbakO0mS4mP_veh1m)maoTXFqoObqJ6xFq5Eu}*K3){Tl9km4vYVFWGqIqL1%bKL2dHZ_^)Q_=>vLWK=E$OvTv z*Gye zY)80pD5EsifmPAZef+AQ2D{&UMPA3KVY3SY%cgHF3{g!*KYOz0Zf9-wQjoNpsOU`-=U1{{#6N zyFqEDusOtg(=+7_A&)^}$|Z~1p9-6g?!dGMZ-gY(yT!?dXLDL(AjYjk&4w{T!s7e$ zJm*+huf6HyY?`Nnu+SOqfPk;J`NW)iy*$*ty?!-0R0k=)2O3|YmX+K&S$ASCH32ur zWOM=rKjBhob|xzBauOan&bTYlJ(}t5i{^%0*EETU5&?Jj+KFd!xFZIdpr^fU+0(Zz zWSI=*pzK2@&PKheLw~w&XhBQxegxai&EqG;n4yb(p=g&*&3uN|g-Rofu}aun ziblTBeSZ`)FPCd1PBVRfuX?W0ElJ0(o_iU;cmRIgw|0HL*}53=l4$*{8cv(?C00pb zAs-oylPGBT5+;|H6M-8DcjMqunJF(l840R3@%puG2`PTPgJmc3`1IzE@-sU&OvsgkBl#(9;E zkKhtL+>SJN>ny;pR*>6*;SoEX+L!QAg3dqko$7eZdflA9E>mjiVO83uT&K>Iv?J0> zr>2N?7HFdzHz@JZCtuaFKk&Sy;anRQr4b1>_3Z^4h1k|5#yGPv3JeJwm8ecb-=1wt zjV!9P?G(iU7Hk`q!LypB4dV6B`*qT4fLpwLFVZ2)tb<^Fce~b+%k!975dUm#4U!^n zr@M-f(57^wQf^gr2Xh0t6gn=>zj_U(r=G55yJ{Dp(ds3*canI}m*@=AY#0<_L#vEf zRWCRe{I?e{vIep_9f4kMgv(kqtDgvYYp_c_KGyHm3G7Nu6>uCuTd_3wrm?^-JzFZT z$yq?B;yJ$nC6NOQqa6_#g)x?pdHCj{>ydzf2 zW^Nsf&%HybTY|-E0E@{k)BHZVB71u%sKjF$!>@@Rr!fTeLa#jP1$Y?3dM1pwsTxcZ zwXUofI@7i!@>iv3%3Nv5=zlvgFL%%A;@)~*UD2I8Lqmf@V?~`I4HMH=vNT2Ie@tb< zQI6=}M?_=uy`#pOY&a{mWd2jv2@NB=xU`f zgGAt=5#=#^@7%$|$HzZ=TYXWte3w7{4840Zv)JoQLZVMS^?uT99HV`)>8d!3a|xKk zIhB`&X17d#zLPzWnn>=v%o+Ak7wF4xl7@0=D=Kt2O6KkAznpWP^m+Vv|JrAa@??(P zEv2ligJ!Nz$~nXLunKOsp|bq-Hj~u@7Y))>Ub`}IA!OyNG?<}Y&2U_@D}dS-nS={_ z=V$H6p67XJp5{*K_=1YtJFwmmuCLYF>%mURTT z#4@P%G?;B2+v8tMwAy<1B(jBj$J%T0cc;m~y}$uFuAML3RwfO9sFxjJdY<4-t39DW zg>VcHD#i7~z^el@3;vhhlaD-K6iFCsJv01@I@+H~jF0FX-`;spO_ea3d^t+;(An{d z^EIYoym!9L`576XV<`BQeMwKoBpih!v*2D9FP1~Hi+B}I&kLp78T5j&2|fe34?T;Z zg7_S*&MwyrV7LXaUIkYPZ`pLB=l{jXid9K<0+)zI9Lc4&xwSpDvLP!92tAl6Q9jqD z;Z-v(t&Bj3vH+^bCx#60%Lkh0PWs4WxQUX4M!pjX?T5qn*G8HbUuaJiLMU}fcHU%s z;pSL2oe1Tguj$aYQd)IZXelt0-3`{=8lwHKF3QNm+92!^{(#tH{G@eJNf%ubEAGke z-%xsO6eO8#8$-Aflr3O4c!!%XhUs2FU!b`VJ^z(;MIO|8`sq6N{=$#F zc+JGhTXXTtKzV1Yg8qcm+Y(#Vi?!0BZmHItr41?Oeq>>}rn!4=clEm@!B2+M@9HTF zh%tna*=Q~2dKv61mhoy{8xu7%&m8pUNJVo)?c7GI_(X5AZbx78JiEL&A>jd{rvkW&$#f7<; z&M<-cEt-Pto@J$RP)!v&3kE*~PMA)0V;_$`o_@Y$o|(1siOF+Nr-i7b(qug1o}YiW zr_svoieE@eg2a;3!96ZF)J9?2y*>qnh{QCSKKP25-lcZ^qK}BnR1p8Pc5N?f?D)9M z?3;!46b|syCbs^jD5DuytKJ#MCxqD5A_33YoG`u}?s~G|a}qMouw5QbDAjC|m8)9V z8Ue3+m|;?5x!&2C_L_ijgi2M0@fxibApU$L*D}WqqRZbE>dm~d?EtM_Q+kB+^JdOR z)eGL1ZTo7d?S?{okiK?T%||r;mbSNbxA%R?hN#m-dA_Lbo-5sCr4qb)9CBet z5`Z`y>QA&&*MBn_U(g9NS|6PXO$5brzpNRwEr_8>6DTeFfZH!VkMXridvxv1XcXW3 z471`jU{|NUg+HT!_P~nvtGHXep3z%fqpWD>P&mSV?ouJ2P)UcIWFUnkJ~TeOHTYmc zYzm5wsb&u_@Xl~3j20tyT#2-H1rSHfBTarGVgLy!{X^36h7|j=)m=5mrvyq25k@gQ zR*`IRQyaEg*?_WGdQ^6z_o;PJpkqqV^(Wxv@eN|`D=WHAk4-frw}R6`t>l>|?yH7f zbisTl*?XF6v#&lU=sy{{ssc#cK06*f6(&{h-NbAvGCcV6rt*8bdaJ>Z<~M4@B#m$9 z?~OMTBSv`L-kRw;1TDX3P`5KWQ!B0+ov03CNHJDIMP<1BiNM)xi*rrH2ho$j?C4QP z@9`3--F+{!Amb0H$z&$oaQDse5WO7F6{hyioKjIHsamw-2eEt8_zJ}!keqfy+I3Wc zJqypJ*g6mNd-$sPF^_84Y)aNsQBZ59JQ0fxPUL~2K#SJ+Dph`fI*`|K@{W+jo6Rpp zXU9G4B8`Bn*gwhQdImc-JW-WmlFM;>tdZr4dUP@`sJIPyCAu?SVk%Qa+6g9gs4cmiHM*T%yt6qnx2yVJ&-H;!in` zJ7e!^e#^o3&d>pq=zqxx>8>%`tBWp72zl>(tye!SaMh#PDN2UziBQTi75ah_%bDH) zX8|N{qBPSKp8Af_K{BHl7L8Sc;h95k)Tg|;geIiIw!N@BL(xjKUvrgbpHPpU+m0Sx zx)w}!_yB4O>9~{AHQ+$IIo?!q-ZQieOhOlAiN=qmt9aYud=ktB-?VD61(7DW+8=ZNv>K>-}8ubM?1OAH`B4J zuC(w~o2aA+%Opr<1QQ+JmQ4$ONX<6*@*T3maU)rNv;?P@rmpl3E>*5)ySzI1Fgl{d zN+x>{eY7A7{h)T6L*7R=m41rXsv+ny=UR|kQel^tmXU68`QB3{hwpK(+~@_y0&;;q zwfy`2;rp1D4Qk)Rj%*`^XIGz$eVfO@OZGOUe!|L4haHkBv*Yy#Yj5uy0i>c_fBhQj zRK-d2&uSLe)wPXzL_GjE|A0qEGSf9RFo8!ic0lMMvxv>gBXm73QTYBL28^u4sWCo2 zpzQZ*>v;chY5kgI$Z*WgCX+P@9oOj&*{aETi)^HQXMfRoS9o)*<>XKMKw4jUecUIO zIs?Ns3-na$;3#{XQ{$;cVT}=)s9mc|6yxC85)0{Jg)`<{1mRWAO=GpoI5<&0xkj2` z+u4`c3+bJUuMXhk5-(;Tr(B!E^T(g0E)FS{(v89eSY)eTAeMgZ;31IM4e(=zWHr*zQ-?MGT z<+~35K-}u~LJCtOQ#SQlxXUENEMwD!PK)z|2uF7A{NbpMNBQ)h@2c3`A3oT8Ssxl* ziwv{|p~5aw%PLt6{C0PHhg(j{QP0hIvYbV&ye(To|7`v$!&udqIJ@p3V?bu)&sG}! z96U3#sOSis^F}*%>QfWAOd|vlzyG(Gy_CK2jP9Kqi8aQ&2lps2^JJ*-qm_|_EYk~C zlJcne0Zv*15ePrINzs*Q=CenSe%of1X^SAm5S(tzhmz-%Rw>*Xq`2eqcu8({d)T)N z0=B+je{Low^~Gnrlk$W#?DmGTw~Q!GsTGuy9OAzXc{t)5Z#wFZRAOd^s-Ba3;vJtq z^Qr0XKTTU~H{v4N9}+YQvP~~9Cxjn7XRX!_sUlt#>00d!1=mzO(mnEN7YP1ZSwCUK zH#~&QgO^o-58dM=%}H>3RZ%p*cRn%Ua@$%Dr_WWME}2@`Sn&Vqc(W18coX!tW)L5f ziAa%gDBG1=Fm6b8tPXQu_5`KQPeQ&%fDuNw#Z|mhv43-uJP`3;5} z;q);`W;v#g*wuOBr|I2d?p0>bd!5)159+ie-cB`9Wd>c@e41LfK6n@|E1UhpA79b2 z{mhGJD@GEyU@n-fm#T0607!xO?HfIiISv}pzBNJJsx zskYg5td>P5k-7S+*k@WQZra5cMOvc31=dCo*Q(_m&*{zm>W<92T*c%vz5-IE(pF{E zPo9eQ&XouKppjw*zTMPeSU0wX=WK|*df}W1cFpleX)Ql5A@5CVQMVa-O560!FsJyD zZG7a2WKE_eo4y5jlS)i&=8m|;ppHeu8d80N%qqAz+kDi+PmE*_jA1e8{pC4sNRw#o zDGP^P=E1$Fo5aqh2-AKaVmR>l8OQU;FRR(0s33!gVP z0@|g^2od^QqGF3n!N?3>Ep?1Xs#{p&ZY5PfvlUJmzf?2nZ?G&> zj6#bqexiMY_O2A;6s5++?+=2jmYaj-zRxtBV#`5 zA!BNc(yEQTep3r#cEm1hBGR6e%y()G3GQ5i2wf^eA6uWQJ<_o~u%n`X*WIwX!7v&C zy)$VS4M!qm>jiCmjXiTRLb6C(h+CC%nNOFq822WmN-)}IH0)6t4Ret+F3kO(-=p|Hv+J*xL5tn9J{W` z8JNoPt>i2#Jjh`j)8`M@p&Gd}#hMHA{Ud!gKOO7*tqnEfn~a2y$56D@sO=uXy^b@* zf9CnTluLs){%ojRJooZvIa5fOKMdIAoRF|}WVBq|7AiN6lh-h|-^+x&chF zRFsn<7}MVHl{vEwjN z^SS`bLqLdsqDf=YhUr4W6zAhN=@(fIeoejwC?!fn9FDHm27*jRUMb;Yr!=dp`ywB* zWJ;0j+LN8nfy(FE{T|gI)zQz+%XdqU&d~A(b%s1$Z-6d4@3ujRaLueZ&1P4(%$CbQW@vTFIfQ6=vSka#=gg!(HNK6XZh-HYieO20JX%!)O1L6KKb z9a1qvJ=T7ftd?70&~;^gibFYrWf>po@Njzc`E6jH>U31@aq{cFA&s2Kz?fe(+d{$n zLkw>lox0Q!jGsEFI;>O5wl?p(KJmYvO zBu`O*C`U7clZ%aN;^y#v8>g3iZKu>_p^k2*TzHxwil5n2-;<-1SER{JUQw;B=29$% z_C-^U1ACko#K~Fvn8m|t*#l+} z(m(6^f_LbQp=K3q2v-H@`S2+qTplLwm@`|Ms-HUBUHBm7$yU(ld$R3!XFZezvz6!S zTcjl{QREOBn~tv9Vi8j=T~|t>5=y<`&B#_bKear^@tb}9%<((^1i{(YzdGs5Kr=H_ zvJ>*LI#ugs6}hNkk3LmbbDPa@*xgCg; zE-kD8k@R6>$0R<<^sIjZD^wlV39V54&r;4QaPAx#UnW`N@m}s%_vQtqt-9XqN_HPr z_EE6c8^l}k_zgc9MuXu{M8~?n6D8pHwkfCPfwRM@$CP32KFP0NMzm~A^g+7spOw}e zE=^ZIWGNNV?IfB9Xuvv}nF00>+o)A`_ujU<#0R?(!Yg_Le$=5%Y;~9i>}J3^9;b=# zr>9`d_N{IObKI2z1~4`1hwuUIf+KfGcXv;3owxDolgUzx0q&kY;nMwwF%kT-ifR}5 zd#g$N0=p~9K^Srf3A9}GxCFr5I#)W4#Wu$n7HR+r9s&LWp>**KG4rkCuw$Lnz14=I zewl0J;8JhfCA1O;>r$Z^H%y;45RELMOr=WI(Ju@s-9+Zo_*kWTxvKoSwcJF>dGO>a zWel>CBE~=&ze%Bc?97W_tI?dAPU*K_Z4ix;RVa}+rL3xt25goG1UMVLQG08wtW}5d zA}Je5QBsVT@o9UXOxd#h^G7uI=sL5b)i*(#U23D8NZ;F@(soY!^j=ectVAvhO5!DT zgc6^;Cwac1#>{N9YG$J;ao&QCbDJvlUsY$aINQ=>4huKbf)ZCXMa8&E12q`~!PVy< zYb^xNpqDK9NPR^_^z7_Lm%N@MsT=q#9QT5KTEjS@h6!7Nf_+#%_J%~qh~;+VP{q;o zmRggACw7|yJzg+N@-@|2#>SMzN{SQ&;>pIzYD(P`)KF$dOjWCA_wc>6*3jiXF9N^1 zkfNq@qNJ1Wc3x9Rq$nq0I7>Ioq(H3FQQ=}lIiMlKc;GqJSQvyZTZ1CI!=gLTkK9sq z;mAVsjeHYDO*X5l?&#NLCF3$-m|iDEfj%>;iCSR5cD2MNu?lNMI0~`sRYaC8doTg3#kGwy`m`FNv(cbFp{b7D=LJlxp zEdaB{hbv;73Wlk&b5^QWA0qPbkA+cZOx>%atT#Jd?RkYs?=@U(PK-^w1?7P+cMxAg zn^4h-T5m^=HNwX6z4O!A#$0I0+0?2g^ZrP5s&nDucJ4ow(#2Ej1`2%31;0s>!2WUm zy^Sg47D7NMq^(Yc@3-OVsyl)5l%3E1vDag~2G=V6lY{xQQ@1r!Paq1K1R+HM|7r$g6_nYOp-JN`VUsmjBeO&eHc*od8^F@Eu_)_7H zgl_)kuEQBJU8&yg$oFw6b`vXAR-=8DSP<9*4&oHSbP?kI?wtbhFdNtB`>OXNX!2Ho zRRk)~wv$uy;e^PGY1pigW%u!0NO?6S6;LpB#8U2qwWs%}-j?Pna#-w4Ezz2Gb5)WN z{iv4T%%v*B3qUMofIFm}b^)HPxfzt^G0~jb7e1rBs(K-L)xxL$U;^SyTE{tvvKW4z zm!*iDN&!EswEoDXs(tDg$hma99U_wYT;Q$67WJzJfQ?v+#66TZpmxf|z#L04+Eq5( zdjczG$kpw|y7|5k|JfYGLD!{1IJ~P8WE9VFn4&BN1Rr;))3hjNtRka7N~ytj-#B7v zc?Z=U&e9)@aV)uS&ox@sl1J-`ovSAepVTo1{tS`?eyjoQQczEJ)8acI_^lfpi!OKU z3w!`~u8HGYG~dkOE^{LJLHLlFZ1yJ%F@{%HewfqukMHN`}IBe32s@g)fAVLh6f4cgKQJ?~)tt*9VEl?VAe z1QFA$EmDThuBB5F@9=Is6UFMH!(p9ttU@ndN=rs3Un}+}(cbP$j`Sd}4U`z0pPUuLRPZtd9APnk4Hq(jzyNla)t`KPFBr;-PEM z991o!!r)`{6spkH16uky(yT*_q#MYCWsf%wZVP@J5PkKC_RPKS%o!$Ak5-;1ON)#! zK7Q^g<;cHdMG#gTRyRF&x52(l-dA1j}%Y<<%?ZoaulhF+awO8ac)DHi^#NQ}#fJb5eS#}RDe zhe?StTYSV1Mlx9f0bj%X0M+|V^esF-=4t~qdhFtz(Urj~20nbHb~K9f0xK@e96ncl^(1#(`z{e#ybEchNm! zXGt$!pE<8}J|foF3zL&6T49D4G)@z^If$;5Q@*Nl5@?y~NY3-(%QR_(c8jhWEq4mQ zc1%Iu=vjR8ImyZ@k)G#wuz4vR#F9t+M;_w!28n$U9WC~09h(aITFUN)wIZtE1-vrN z{Bqv4Mj|#2Y#X|qlJ1mo)TpMt@g#HV<@gV+lCGou(~E;(FB4OsX9UqiPg10DwUHSM zQjeY`EvHgjjD#cz=Th&I!Y1KjY_*&jrS4+1vp4Rjv&k5K>}ri)7OIT%W@{aZ(wpG1 zv3P$O2RS}N9)fq3Rom)g5{in7UjNsPc#AYgw1tr8`slz-zh;rYD?v)MCNvlcZS);D2^9>i2CG{)j)zBc1*DNf&}sL}ccZ2vhpaA3NRaNf8CI>;4V*FKz^DeXOBqP)!!@ zf1{CD&e`-~WGZRnAVOjBO0|65C@q}UhEr6$y`YX*q39Oty?O(heUg_peIW0%2URVE zAat&_xx(zz{bSY??%F*E4DlXnM79x0gQmqQsK%eotc5DbP>Jt7YRs;+0QP&Q+b(C4 z^W3-02_>>@MHKvZA%t{j7dVD5S~PAN5Z(XSK}&47~Yl7N}{i z?`IC-*JVjOMXP)K8N+p|#COT-_x6`vryW>SP05-<#aQa^tdWTC-;UXQS!ptdUUmHB zd*i>SmpdID0P3@C$k9x(6J#}d z0dInOEd?5eE>FH~2Vuj*EnwE|uoOMi0^&_DT%=vSVejw4$S6q}>ZHwM{3s>y@sWt?tfZ!@p%5nKVog(b*q{V~tQjtIk+ZeTA> zet*Q}GH_Noxy^U4Pti^98;NXuQmhki-g};PI^CHDf>0u-dQSFvd=bMe(I`ObI!_9F zqn7IA4tXuul=<9ZD?Ah-BfSjEyvni8mjSEtG=k;ctFelCc$d8#`ATVGemVCb~^$yohz!Xj*_Hf{l?| z2Yv^FH;4S9hW=W3Z}`aJ0RRn~rE-L_3w7Y8G7?ON_6GsL-K->rn^gle9oLupKP_ezTfE^LE?wF_FSsos;ZMc+obi&# zkP41mWUpM&AAY#TE(wpW;5iJnu9We#H$##d6-j+8|GjZ_*`qINQ`pGs)>T5A8ht21L7` zCo1^!4U@`_L&+g28%``{5Z&4Ehs&f4iFB;MRER0Cu$AXkf6j@t;UHszLfiUguI0Lkq&xf{-$6=BWonyKY;d17cYfHZ#xB?z__r zeglzz^kr9q%0yC^BrEqwl2$><&I#qxRbre|o0qS6o#S{pIoJ83T*9=X4*X`&vXBDt zT?@!UeL@1>3h@c=l^DG@)U?|r^!H1r>!6-|rkC*2o~xn>tM|F=q%!elH^`NNKEJGZ ze@dDkEJ?*+c-=}Bc%aPbms5RCMwFViX$*IG4ml>+s+#IFOOgDci=9oh}jGJkpuy@cjd}U+W$5spWMzvp7AHWkIVj+haD-)gPf6Rr6ER%Q~ik zC97+^yU<+Sctk&tFSS8S&*&ly!@fkSy?U?Q*@={pxH0CLT?{a%iV*x!JQgC^`2G2YGvsU)=l@1A$wcyTQDns zC?tx(1_Db+KTZ;xm@SOL!u6sO^AL~PG_l)4;IC6gviuV5x!u?Pvmv>!iyA*{mhi(^ z2cC_o`$#(OHq^a1{(j$A>$X%FkhbpKS)ue!7$*$IaqucQXHavx&R>mg*`7HO%_BqN zN1a4P>7&=N&&|0brm{j8b8b8`Ch^)n)P>5d!F=^csn^sessbd{ChvyxlAy27#KGXz zGONeYYr)>}E07OxlTG~Mw1#U@L=tV%Y)Qk-5I$#JF+hBzon=?R)q|>MT5T-Pi4f&% z5i=L?(wO5hU%5*JlAu_xNAu+QJSF_NZ;sver=E!ewh#<<@c7XkH0f)oe9QvZv&LzywAbG)aP zskTZw^_@ZGn#zFj>lwruKfzLr+EXGOytO0aW<+6O+|b4n2$<{!Y0qBvwo-Dtog8b` zT-k8`r~vC;pfkyRQ(ZSLNj1&F%DptCWrs5@d!Gr^=-Nw?Mk6_17_}9E5lqrX_Mtp1 zAB;^Y*8AG8gy;-747iju-~?bAASW!Lm&|;iju^_)^xcQZ#xD?(%FZDZ4NsB7zA%7D z<=<&@L+W$QdQId~pAL1}mYSaGc$^T=a{GFiv6onR9b|*Y%CpD6K55}h7~{O4SlW0s zD?myw0pTgzoVvI=NeV zwhy{+Iu=irJv5*=;u|qQE_vX49!Mn%HBmLWt{vEaw9~ie*wn;a+0S`V|4*{58@)d{ zyVr5+#mkq!rl$17KRLi@{4@)SfS*=*yJwpqOyD3TkhlG)PGI_X&k#xpvZeRYRoIrh zZm9sg!u^qtQ9S}dwHj(jzEeQ?*K}AYGdt!4Lh zwg5HYbGN0JVUnzjinCuq1whOmNE0^$T^j4;d75ZjiIK3d1$ds||2lq2tx8K!3{nx$vWnzxkrwbqef7kf z9@vRANk8>qV~?D@)vQb~XhXcWqQ?5V=Gz3j7>-Jru4~BnHP4Ie7U9a{1DKFu-e8oM zjmiRWG;uSzWwe$hgz~O1;o{S>4YkkHa;22?pUfQUU+YZ= zUO9Bk`g(z*p^kZ<^KOB1NU`yy55SD<>?R)w6qFC+eHU9Be%({Jx zrTNieLbY&GtgD8r6P{0$)^ffh<}b6?a(&*C$t0E|VeW(@ajq^Wm%%=Hh3e9c)g@5o z2+?Yp2KTc3#(+x(*6!*O-+#KildqdZ=z>VTyfp^`$nSwcib4=y69P`6jIx6V&oG5W z);)TRtNL9BfTO`8G)1Y7-=@sx+PL1{>)7=P)@NdaT>R=v9!AgKzY+CTOxc<82o=wZV zYE^xYgvCdI<}VY+E&h=%Wm7vm1|F``ftqH~ku1)mUt(#a@LL7zLWO5o$M@iGY@s*bGhpv?8uXvKmf6OEb*}3STGI_`Bi)U$dv}c6CW$-5}PjGThVR~b8zqPmhY1)`XcL zTNR||7F1BD1K^E1qUsn?4ao;wMZf%So8+dlk4*J*toKgF>)i(iig_xZp^hF=_2oDQ z89?;-#^6Mp5WPSq8Sw@lf{r~@S0xnw~LqpCNuK~)v6v<$vZ3g)u23_ee3HYES6+Zq5f z-L2cNZ0ZW{fjBw&^XX{qpgp}AdA;eJb`@s2x~lY@n~%-RQesGGQBiQy{N4yNCRc!P zpS?IkbOA6>cAk7k zLZyyEgTGhMz)wC9QN2*!&U6=bUsivQvvFc7JP3^QRSAU&rA+vnt%I?#1MP3O?im@j z*eb6vwU!no@66Bb|AFE&^JYbZ1rgodV#O3pp=qlw>Z^(rI1HyK*Z(%h>~a6YF}7G~ zs1NW+O@J=~h?y14Gq^k12ZaV^R@Q;5>okS6@4hNY?qSocr|Amf5O}lrM~n_FJoV=53Ma98UIFHTq>)*qiX0%v#8`<(Ni(5!dRcy8~5=ORG;Zoa#8)EG5S0 zBqdnIF84*?eV@z&V{><=^-S?XqqYzYXGkFzVgkX&-B0!nk!8LfQc9@YH5tl78K%b# zKYV};V70~1j%K!+U89?|PknHpEihpj166YL@~JKiVPofszZJV=EU+DeA2jfy zSVAI&>r=DTLx>;sy?PEfp^@2}`m)l^oPQ);A&aa^gpRIe-h4F4cIO%!k9Y>a?P2h6 z%9HNs=M8kR5|Ml(f3M3l2pN$$Y?x{xEDMJ;U*WCPH1i6&uDysq)Rh@U2t z!9f^4F*=~njJ?)Sr~U2hK}kZ)lYSIuckT!WjsBWou#aEAHpL@OoCxo4Xyv`i(_lLL zu;SR)42~B^0SL(nwAM3)^%Nl+U;oRn$*(g$6O&EXb#PnN=am=^oo?qa|; z9k%LH$8RkeHa0Wax~KC1Q6%(pKm1bmsHuo`9@B{!+b=%iozz-+x!odWrA*3RqL(`r zA0IFDl!wj#0=KTdg5i94_BC`IE!Lt{OSf(7!o;%u=7^$kE<9 zMB3^=8&I2nMM>psP1zv#>-gDZ?beJ&9JMNe+Ann)|ch)#*Id&QMO+>W1(vIg88dx|W^e)f{ zFSds8ujql|T%&Y}N%m?vRc2BqJZ{uhLwjeMS_*|>3THXa->L+l{Dg8z2|F=R5&J~p zZ?@L=>Rs92E&R}6>ln)6bwJfj-@Xfadb4=PlDSxswYZ?7T;H%sV%(XBf;yBF73Hpv zmF%w`d6u%GJzxXI_-p1FkFd~!rVDf%Dhtk!>4mkRN08_jb%3oB?)g-;h9bv7gh1*9 zpXpea4(BZTmTHQAm?3LUvw-pT3K`?_pMuQ+(8a%lv920+2RD+{mHnX-Oj{+ZGipUZ zKu{o;7{_vNJh#`{z-ROm!O#e>-areRK(okAe9<5ogj(^EL*= zwaec8O|qt;uI=eb#C)AL;?1|@2>MWy+Ii3ZHsli<;qwURpgD$GjkC<0kZ*X2XncNZ zu#;yyX#eE)>?9o@K7}>HYQHpmwycSK_-w`Xwasw@znVFvY9m>J4l$9h!DEK&g@mFz z>`K|re+VDshZ_`(%OF9pXycM0=9lQ9U)Gy9OJK+A7`xr`DbDAgKJ10x=G!_V@~;k2 z=8-q^2YYY-FWQ=GG(NhPr}}h!J7MN)wt!owpy)j=Lc45dMuM{BUL z>(O$_o9+AVv_bli51Tqx1l4SO<#@xs`d;$@!)B<26idGcYttKZnSJwP&_V*^gvHiJ zI{>$C6&JHi3ZLq zpz478Yp;6~cn$9XsVXX_3Iq$z(3H%)m0Hv+VvZ1oKCC(wg&l|%uUB<M+kl z-WtF^kDrRVzQdy=5VwXkdCxk-wlqyq|Dt`8$Ocm-w9=Q^|MzIe!~wZ4$WI_(%!s+| zr*pZK{u0ycPNM~a0b=lzlZ=Vn!8-UA-YGcCUfJpTJMD8-gy_t>UVJFjC=PVe&vzV6 z@()k;GsDlOUwfNMYHEV|^P7){H8=EwUn%<{oTc@sg?55aR$XC;t2)2{%Z+h25sL#V ztK__k51H+j7Q^wI%4)gEPZERZo}U$o?VqlhZw`BAa4&s%?`?fhL$pK2dMfP7(KDT* zYmeC;;PWi~e^h1g90&YWOd|c42}C|L*Wl*pHJGIkQT_Tc!SEZL(=h{PIEyLItA2U> zD&f*I1q5RW1(TCXRd;r^SVa)LJmV@qOxmb*>8d#_=;Wdtyt$Zxjk}w(Tye;-PF35N zpxh;su|va)4T35)|8w^9&-RQ7cHt6}7O+9E^!l0-nQH&!UrLd-glm4Sbf6p|Uh(*Q z{cb&ep8GqptyeDY-{|xW)n$dL|GaqP#{U;A4E%fjzv67b7ATmneD>?6$ok}Bl`l1_XpkB$Co{i!mZIf3vHC?n9;G-gJ($`n^;-y5?Eg#S z_jJ{ynKoc!Pcwi|yJ)P-y5D)Q!Y*p_;c zoDEM_Q4!bY_|Kc(`0Z0S#FUPQWc0z4d#?oD@q)F622IGOxPIKl)&7_|2t~eHNRCb4 z7+awS5BNYuH_=0Dyfr605|pKwB}C2!m6-qByu1rfsB|Uk zVOHVs0I!e!G1K`WxygK%4}j2EzPS1Q*ZV4$nH4jKPUiNwoyHHqR0^%JNIbW)@Ri@o zzr+r$7!UoyXhznqNJ0S(AVTZ=M(yB~N28_6kzth`=F{?i;)n)~nyy~i2Y!dsu0B@1 zYFFG+F%?aff~`{mxZErzeiwl}&4s=-hC*`@|K(5X)(zdX#s;Tvk`HGns}C8TdzJCc zyw&I*%4q>AjZ_6afJNrAiGgQbX@8 zN|oMw2`zL&3q2usvBmxU&iUH8_uTWG^$!mr%(Z44Ys@j;@xEZjDcH%1j=Ghg_2I|N z+{^Ll^%J(*q$6~@Z5hq!6i1D4b@%BpTX-x$zGN!n$E8@qKI$|UpQ5JsGbbXQ-@BUi z5j)!(c-cxI;)!{LBu+r|xTkuq)D~GZW0gjIR}50-uo#-?;a+9c9TVtsl}R=b;7U#5 zeye<-H1)-ZJBE`C%C82Vq<`YM7Sm*E3OydYRgDNnspRU!Fj$&A*G%YNt>!5%o{MG; zn{qEZOgfuHANmR3uNU;M@X=53o&3NqTZS-wLa^ZQJtyT4N9B9X;Ny{Yj1}PUeHoL#TED}R?Ai_sno$pe{yWQ+*W95udir1Pr>iyUYMIPIyh{i=Zf#5;ugwA zZ=Usb5Zzpc1lRTN@8o$YtwTc9>MCY+>W2C{T+*Uz4pX=L0d|SQaB^b_uEg!_a5eR3 z6hn1L!!3_jF^*ciN_u5)!gJKKO5*wWba$2;u zYgit73&m<&fA*w=NJ@Hy4TDZB8U-s_DVCjQuhUho|A%$TA=Lc2*VcA4*ML z<*e3|6stD@hSk~+a}ipkFtevX&i(J}2N~vR>p7$DujmM<5zWmV>oPF`4-`*%w)(1E zWr|7r>3Vb9|cw!4eYHau>{J$V>L>e}akC4;Ry+8xG=LYNvt(u&s~c3c`dWlKSOgye*tvZa_M zopP!KBEh%P24kX(lt71J2!2&Q)bAHQz>n47DP<$Q^n}Ceuu?u}4r+NVo|t=_k1)1< zxk0Q(mg^v_G(W7uMOo$13?H;V8WtRtLKpX*E&@f)4Jk8!O*k6d4Rs?F$259Ih!b0g zJ+yjx;xe4ws?cjYgNh*wHQ?)OupF63EmRY?H+(`9m9x3YOjvY7cmw2lNuD!%InrSQ(!#EmSn5M&0RN)ZtviVE{T%x&~A4QFp1tmt~V5VWD^4 zI5noP@SO3jQ1kaa8{2-OSbB2R*Ync?t5{59ZqgURm=HHvSYdm+Kk=|czt_L5x4i!K z@$!ouxobI(!Vu)e1b#R=D-F8#->D?pLm%K>4vsNkt2p$7vFulK#TpJEq3wmcXNE}Z z8-_VlN5{dTsCAo!hXmX39IWre<&HM!hwuK01$c_KsNO@_r*@M)GHPxHMxC2Rmo^Z5R3g;E#2V-jdJ)`&ias)9OE?2Wakvgg$?b z<`J7+w6z^OMyXP=37j1Heval^nxAFF^Ye*o#O7%NXF$fY+uywjlo!0L+Zk?XIbkjp z_+W+R5g3qhs)0Jqvt?s`Y0aHe*Iw|RSHUm)SG zm|9XbYprzB6=CE_NNGz*yOmMtO!}WuDe5}EbV>6Z^0<5K8xj#GxjbCu@Y-bVmXPT> zNq5^#^ixM~(bb-O(@+RlcNdWAdI`3#dl&nZJOFmM9@)#{BrWbXM8F$I8#}VAg%Kvl z>LpKXW=8hg5l5kkD}qvIx1rVhU&Ob~o(sp0&k)FUkY@F$&>CUcvj!w({}pHUKKiQL z&abb6XN1f?cNj?c&c676g8kMh2c3T}1MtRC;d$K744Qc=pId$tlNT=f|9v>kM17)@+S|L+j1krG=SY5hkr0+>-c# z@5*X<3cc5ZB#i1(hJ!ev_iPb2)*qa)!~Y=@^dbIl-Qlsp%-bxEfA0Dtl7yMWX>|G9 z?l^+!VOX|@?kNNN&@+|J837&(Wqsx7;Jy-mwWrN*!V1-Tmmh|MzkxPqyWleo**uT| zMXZ_uMxf*Q`5S>LW{X9w4HKUg{W&MyxAHQ`DJ}Ve_eK*6?J<0*gpF@?P$y19ST7_S6MC$Rs@*H4?QANC4 zB9Bo(zqdq2y;A`=>u%q!;@HaDwEGWS)vu)H9$kIn!5R5C+9k$?#t}wEfq#}!*pL6w zt=vJYuU>{qmJkr~F6sr^%L2?32o7OoHq~HnQTBtd9LA%+Y2YA()M2Iw!x-)IGTb`# z^{UzutEwDzhDbcqlZ3gIlMDZUmjM{IOfP)1CFOw3R#2bGbO= z=7m2vKPMV8S%4a`XTo!!dm%LR#8YVq$DE{qE`{WGK^-l%l|xB&4po;+d4_wZN|`=I z`PL@3)#bqa=8k!0mRB@)eqpwl*|WbFO&M)^V1E|#&&9*S2@?Q!`g!QAUUhDKO#X;o zcD@dZb7lptzaupx>{%)1S@-zoe1bGxa^l_Err|NEh2IjFL`1Y*r{}9Argj!Wl@Q~? zxRtvVw$8*x3qBO~sFZ})f~nG^g?Bq@XlVD&S}uj&*cg%h|C)1Gu05EOAKde9=zHH| z3b?iE(2AdYNcX*(d2UNV1l=a4q$v=7_6{Ku2_<h^N8_G_tYRvkGv zcaXR){p@4?PKE6->x1s3mDu&~9G@R~+Afcq!+~jRWrrSvMpY^O#|IJILbJlF2!d{` z;R8e=-@5HiM!wJ^&4=TtfdmD=0&iT1Rv3#c-kXKN>}<`^wp?%^mkxXVy1iRjpO#=? zEG6tV`u%V?TJ`S248OxqXf6cOSZe7oKV%N*B}-DWKNAOd${!+GKu1>n^(VVItF&7u zrrd%14?V99xG9Y!8xWTz{sc2J+X@DIcl(9QBOM^wk_ zzK(Nhfk`=YF(fGGV5$Ge6&wAsuuyXSq6SaguyjewyM6KW%bZ_M|AaX$mU>nJITkR6 zodc*b8EX$`hEBsS6&rWY{aMui??XXS#}$z^=(Gx}t+Z`pt24*j`#B(5D_dDTyurTf zwqhF3I{hh_Fms>NqCiyO?*Q)DZ1ag@10&IR4b6rL_C>)tn^*|gecD}XPAi0@?@Y&^}#d9ftM;wsmRtwl`Ob*IRO*8cvT z2@=_fY2DI>U7h{T&Rf)Da@Hm(OJf@3^W&-sqRv(7B^m6Mi+QfJ_YvvUQ3Y#biu&?k zcjmLEAM*nG-=#;_*77CXx%R^g1ZCs86FZRRygidbiM0D_L3jCWKX}$&v`JEy7y1TS zj(+J>x?zfk>{5!zuo{#_xpl=)Gg!o6W9W<|icBn3y1(c#;5RgT+Uo)stMBiu?S46# z47qqgdhyy90uq>?RYh@e3d*A3Hb1|pTGL-2XCM^KdJ08zu24r69fptaDipv?wOf#t zh+5yPjL=yZpUgK!FU@P&9xo*vNA$~$Nv8g)v%}?fyNQNt`pZ$S6i$MXE*VMB?wzCL_D+Rq7O#J zu*XEff>0g@aYoZv_nieX{xQth48k?sJkqdFl8VPfzeiP88AiE~a>pX9z!V5I>pqRU@*x{vmS2=Pj4_gaCnma+HM3V0!D{X>6uJ^gt12OC3reSum5eRm zY!c#_(4BH$(kNc&1n3Bhh0GTjDi0i1Fp=RB3}1HuUbMFI@yc|gtUt@(3!tLD;?`IT z4U0dlq)cy}h%jwmC-%@26v@Z9VNBRVpi;=Z=%74^{}HJfrp#M>!rxe)kn-e z;EX61i+G&1cE(9bX@~M-oONV;`4!n?Zwc?TwoG_vQ_w0Oyn!f5+gO(v>bLcS^n*i8 zp`I!1l^oXY3$3fQ{t{10V&DMB#CGFuM6CM3vEiP1me@#pv-%^t-oLJ|z(r%&J8cH_ z7}^xN601+4CH!oSwlC?=&XIQk&E-tRb@;L~wu0h)-QlFLZ*5q-)?D!vhu|gWe3!s7 z{ZVsVI@I_Y<#n%{F_8(P_viB-+^O}*Y~uH=>AKR}UI(^zhk*oA3u;8ZO<;%R?`ZE) zNiM@OE52Y&Cf?5*Dt~Ims-w~Vm_10?itsI1ZFlmL#fAV|;~!@nI7vx~YuivAV>>3EnJhj>N_9V+?M}^!l3wBh-$;c8 zvHBrR>Qlo|YnSPE%W`miS^ZTK?^Q{Qfuws(s2ARO_I*;fU)9;U&4+^Khf$TA zIgL${n76jj^&UQV?@SU)kEq4(4-%{OURSu!0LIa%liUc=h@R*O-wxUipGZ$o?x_NI#=A3p$=$56|RL(K=fpSyu&Q! z&y6MFubHavK{9gKRE3R~K0Z)+`zIE#xNO3>A28w1gAW0ewSA-FJtc!31NPs7DnMLK zpA>=cdu5i(5Z1z~fe&Oe$xS~A!8-WSfTCHds@>(;p#uoyc73mSY)rbWeBpxaT%AhY zs~bQGYJd113#=AY?8b5tW%+waC13f<%C0lF#1eM#`Her%*B}IkFVrH$N zJ^e>jdk$AG@03$YhwA54uUv<0tJOU1N}AzMVSDXA_@jpv)v_^#1T?axb+eB{zTFb( z8F;+TWpm-!g zVH5FD2AN#&C9-k8qSHbA%Ie9<-0`DyH|NdBBJt{d$lh1Ok-;e@GfhWYlG9f>z*L<2 zcYLR3>c0-?#P7AT7`}Wty|nbmTa1g@_V6ffvF0)zU~ZEU-cGjffu=Sas{ip;*uFpYo$SD;;e%vNwq1`};Mb+c>4K7d2KP@J zpU?pa`WP|?SNi(;s0D2vU#I#Hy&f&ob52BnLQPp&89$DYgAmoRq%AK-B>fOjltgx~!A0 z;_%ODIQmqnqCdkC4h<2H|7x#vBx*B3e*OCOkWORKM?Z#yUdM7>OhzO?&Y!2rfgSxk z-@|E2jSVjM{o|b`qsQ+0?CsI5!SaPhx9cNTKDv(A)aNvVo zM-W@qnn%}OnB-`ZdrGRh?%rOY*OnjA@rq$L=4r%p4=)vSKX|Fmd>{BPY<3p<`5Maj zGrINy=wOg0A5*$Z@4W~pkfH-S$Y9Wuo_grXEDL=33E^P>J+AKxplC|*cn zt$*Via?0W`GnSAL>YwR|CI~_80 zVHEiN5v3VkLOIm!Ny+{ob{9HsC`v547@sf|!MLd8RL;?9NNAlAEqx2Ri`9HPuN#7H zN+*-(%+)}4f4FTc=kbCZ^Ob!H^jPVwH*So?lY5+4w(C@*bkAWnZdk&~2Hu3CyL0l@ z@!jVojj!|sd)x&fyJ~A`X=yJAZWM?f+kR`=Na+<1@|nT|1Qbe9Ku(s@!Zs5f+Vv7ff+aui61CyX_if*qa+G6*?^;eo&Irw<6@UH{h4EV>)mz=mr*_W>(v2nZaVeSxUwQ(5}--N#ZIy1IAi=}}JC zJODwae@sT2h4FPjCRgsyh9sgIj{Zmdn}{!%=>KG3@_(c4hs;1Wqa);SmX5;8%jLj! z|5RuLxRM(fi9&!9$-*riNm@~dinnXn%zd(z=c2udDheV9%XgEjP<(&kcD9`46R6fP z0(gs@UT%P&E=!_Tu+?-(O;J3A5p$cLo>Eo}cu>oO4e#?^hn&yJFs9biqTIoWAajcW0RNR^Nv;Ur-=rkWTtuSt6rV)1ezoEker zE=>llRT=u8_iY4p8-iaN#Ubq%5(m1`rY;1N?@w%- zM}(pBW?mgdnhl#MmU}E{P3oDn05W>vy$s~oH;r1Z7QNLlE03W<51VK9PhW%O49+|Y zF)ZEY%^njyOOW11mB0z&m1VC2o)Xj6*@+*fm?^UYWAgm)P2!IFcUcB2T!QS3$^>19 z8Ce*DT)5&(arNCUCYYdKx;O=WH{8)BQC9y-NB4mmC_KYs@hs9pM=%l5)B zwU24WT_KDLWaRR70xArxud_EzrEQIU+itNfIG5Gg!$uL~m`eLdjx(5`kerwq&~b#!XY5LcR?bNl<}4r} ztG#*z%Gwdt$;Mm0?~r#fjNQ|>PG;A>Ww<<`=!ip)G~!~&>s~C0n)c&y6KxeaPwZZr*u?-e=EmYUk?oyjqxYzzuW#d?8dAh zneW**`^r;%20KD$E-sF$MOKEzvR|YBNPH!(;yJHPlRsL^xeA~p(DGfo=bxI`{;<8h zk~AK-Fjd8WXI)>UGMlsEA@`(KZF1mq#=&@Ab&XnK>Jk&>!I$M(04St)8Qwh6A9o18 zwAJJl^3Fb0D*jQfp}!msx326-I9`@+Y6e5U^!8m$G&D>{`hPcN>yHY0>T5{lsb5Yg z=gxhUgzpx-FmN``OP4T?MEcc?FEr$Og2qG-&~n{LCwXr6IxaRg3p(6Et{L5VSC+qX z!fr(Izt-5x0@O;+@E^N#P5!x2H`VM_@;BN#x_;D?lBt23oR@=Z>Z?><8 zvgkt^va_>OqC`Y!)vpI081m3k1=o*_YD3Y43z{lE|7jUPh@5y%Dr4X+frp@r@O=}b z)$d>iCu?ndH*45VQ~%Opr2>MkS_M+8ksG+(%|fU=VzOA9%lMg*QwvXakwqkRTzgR> zbm22rrx&ZFP+BTvKl^!^I01BA-^bgHJ5JLJ`{UC4o?>bMF;0iok@A7kqd=x!_OOe{ zLY{j0AhO?5x?WZ$*qf|%YiCh>Hu%d|VOtvXlq4F(D}&$Y$RR4A9xb@$9$o1?nw4KQ zT?UzW8`q+B6aTm3Y28XlOB26e5nE}=>JC&_s7)oSWG{gN!xn1UJ&1V1`OdnoW||1D zZX&p%qiA8l5ro${)k_VZQKwa?R#Vh|&T4#edwism1fkVd#EVK#?BLdNsDcrQn`G(AWA*7+sbqyU8W@WhB3S{x5 zY5WSDmpmVOZ(KHVuf!^e4S_$&pV7pF(|6FnV*YJdeXh?v?K}rr*N+`Hqu1(uHaHE#vWq$^zbG{R zx{LWRoJN*}xL0(f>3h+yv^4v52z&a@C}K=if0 ziQGuU_2wnjy-{68$XaaS*H4t`Ps|VN?bT#VhMqA_9W7pg|FX>`7DboVwl8oK*mAJP zE2e*8zOqfb67;Bd%C&Y_@cKGjxmJef7jyB`dcvtKIh7udsIw zbMTtYZt@}%d5%7+WRi3rA)y@(RyNElTSx4!S&O!`1uleu zuu<0AjP`*ko~y2ZVgc{G8!p0sva2LMJF7J3Te(CRbA^FdIUQwm>$m?sMfq4&t*3=cmMO-6u#w>=X4OyhU-) z*%fZ_8C$t2ueo1ek-JjJjJ+_8IQA02Tb~Ukk`*#jkzX|!-s$KV%^Lc z{w+Yud^Mome$G;hH!^C0etZ)qPI?C$s5_zxdYQw`Uj40Ro8G`O=|4-qEEq6)F)fI; zUQOa+@26x&))sx2t=@#mL?S>{+b^8 zM}s=uIxbrA6jQu*9bxhiPoE}wgC zyT`2NG@CM3^g1O%bK>6tSlDIE&1;Wa{yn|~m1X}g37L5+$?=i`XmH%@VLN9IOQI*| zKtqFN$2JdYj4J9U`>f=qQi8Zr+Sc8BQA>wUaY56~>h2>lxzPfPwf1z|HNjz_`n5du zd0SK;pvC4hrRX_-cel@=O?pc(*nV9`r){5XG^n(L2FsoRg=;%Z|C^74Uj zV9}%$6cj8CWNG9?M}@YwwJG@ie5t1P+Sr)stmofa{(&2x{0Q|q!xR$XDu8h7pRfG? zqTT*~sF4#%PuB~STCoHOj>hSoyi)w(-R8#^Ox89Uw(P}+2rH-*7s`7_h>4*Hy^Mu z63cx#tO0*C&2uyw7B-~<=QqT(qfS@+{j2ByBJR!49` z5a;Nu|GY>Y<4?Eo)b%K?_m;DELcfphJ}qDVr2($;^HpZYeHR^3G2HZBZYFEd z8*qYMd~YY8N$XzG_bPJK21p-8C-7#bC1!BdF3K9r)1)c5R`wBItvbwKMM=dyF*#zg z&zQCqBQNKY_v=wFA77>DXQMdoP;P3^nZNYKUIv?L2@=LvDL*4b3(Swk<+9_t7JvCS zFEqM_32{}9Y$=8X&ndPD=GEkNfO<#V*FM}HRW8jo5XtmBs4vgw69)QodO78B;ciIl z>?v+t4gKuy3eFqFHC5Tm-FZ;wUgO=pwL88Wtl{8@#2uJJ`ZSP}5c{X|sn8CCFSJP3 z7OSqw{o|k13!UJ82l?d&>Tpu%$wBK+QtoF9Pzx1Ft^>m~cmRv3VO| zhWqqtZ&q3V?5B?Zt~zG7`ID^fSLft0rV)o$&F8eR=t|oD8BpG&WElJI2mb%eh;)3WNm3z!pOXeyR$0IYQ~m4f*l{Y;Cu!Rhm=g zqVj$OcISHTo2qek)AK^r-ngwcMH&cwVaLU=f^9tb44FvRc(;CfHcsU-g-m8}>514E zi2%-6aX;kALdjbkL&1k`B-$JViwWCkRr>ozMH|!0?NDA!4x0UX ziAPVF>REXJ(XfsV=p01lqs&Kvi;d+SpuNV5A4k^k?@{*ed8ZDshv%xnN;RDIW*!F! z#s(j$t!GBw_p{KyjwP$h>*@pSrxt=;EF!Jr=M~u4XkMq;>|1*+i{e6G$;rs%kXRqj zf6+5<{;t(pd4Bze=Wk=%)9F+ha08UQ#<1;p#qf<3B>UKUZ*R_fuK8Ns*yENh@p~ra z-1_lF&nswJhELY&=s9VvKmvK*FvU3S62(#fmIY?NJlvXZ^?7)O`#$5GSg*au{?Pn} zxGq0b3PNn;jJ+ECPRcfxEJ${NHm9FWxt}hm*T{@r9t^`NBP(L(o;AA0#)t0=-rUmI z=m`#GlF2jR{22kI8UGpq5_E6P;ZfkSST?Cr%Rh_4@hsJ|CvU__jB}eG!g$(fq!YS8 zCp(RBy;Rb62!E6)EdDU3yhv4$-wc<&@&4#lAs#i}Msrwx0+sWg&KA+4vL{zM@u}}e**UnS~?828O6`0lFIbWMlVrMZ1cRItOXOhhV z?R7s@r9RGgZ{2+3_;u2By5|N%Za~qM=ei^r-RocDYqBjl?g%t?S^J+R>rbyvCkG;k z*QoB?#eIa?$u)740ru7n{|&vz^>6t?b?xjX+OCpav(g&aVFf--60A3)c@wvd9AhT9 zeyzS#vN6D{*kZy#^_nLZb7HObgOl_6;OF=!M!70{GBuI*@KN7Ig8TC3yqw%OMw|F; zuij~UDmA_38|%}eHeJ^W-&D0?gPc0f?F<7ZQddH|YW@?eZ7|qIUt?dW@w((AeF_?Z zo|bpQps|6MjOgxK;_H{g1)RT;s!0WvNRRoeeLavDK8EC zb(eYdG&JTMDzkHPoJA6sE&;lvPoF;3S$DC2dQEXGfE7g+E5NC*Q$8)E@i~E7axL{_ zufAiTwi3Shu}_YE&6FJ*lt68J%Oo~lqR_v(d}2kmSs}lT%u1ncm0FOUD;>?GKpU26 zyL=1*r6BY_(fNOq-?~{l3CXQw6)oZrh`GUL{p(Yp{WFff$dD-RYlY4v4lsFH@2pAY znt`K&C-zLwywVf-hb9t5i-O=O3hSLeR|pi@axY@;(=L7C(bVxseNHYQY@c5Cn2CSR za{p!TGh3?Llm>z&c^co4r9T{+#YNs?4|@7K#1G+JR4HrZ0xq*=uH3GduiqSZgHzUW zi|)@y3;V@5O^gH@H`=O< ztsj>DV14u}9Ck-?cp%cUx<%_<##)z-oN6L@9y#-Jyrgpbk|0ahBM#4SUSz+lavW7} zb@pa(_ujy#=CpA|6|zsYwk1EomZIMx^^-&8zcKku_Vvt{T&wjoGs@Vo@^9sRh|T8N z82!4Zr{3x_(n{8HoW%KJJSl0*@5$TGDS0~b3vA0uE9S~%51NUi-+70}<%h%yuuB`5 zs2uZIA4?d`zNp<Z_ZB=LJVHa=Lpe-v5Hx;fnS7`fW3DEXC>d^J5Eov+ zdWAj6t}aJJ*mB)`O6=&J!uy!5ej^BCE!T;*nETlK6LYb_|JS#k{BrFQ5qDU@FA0Rp z4T+S(LfQT7#c770V_u3fS&@OBIZ>%?9)0SmR|P({G+$O!oKu?1i1osIO|S=%KKlUK z;Y3AUNh_XCpCk+gFkTpx&J1A+m|u(%6zy3m@WyZs7i<&rtfx7^u!0=ldl?#PHf9~zR-Jd#h7oE zhD#jochL8jC&RzrI2uor-d5+3VXWAuLY?^x6ECX_i8yV7;@l#LL;?lsm!M0Tky7Kx z!U}A8Kvw?5Ajau30{PVGzAYN9HHuH2or}76yq7T#ucVMTVqlu{01wH*B^)1^c&Y?e zyU5WZj^jJMRe-eG5Lr4_!g#6@-{UHvqgvDW_iaI0st_t-xV8iSSsR8Cv{zVEYGYKGQ88ccHS} zvaY-4&<)o?uouWU=h*bnnM}zEYPqLnK%i&}E~nOikfCTbN-CQD1qxjiO{7NfkuYZyLyUy zQ{6mu<_U&JgF!`@`*nco;CO;cMx;}-ioC z<)rhy{kFx1_hMxET%3VX)&nRuhK|0}Nsz9KGaB2LrqfK+V6LXD-Ok-$&UNlYUkoVT zIa;YFWti2!JNI2g-DPdG#3F`5;&`c{IW$)^e>x?lYCS*z!5e?8)AR)ZGrK_~|NN=u zE#rXC_bf-N7W;RF)yW7qpom9^=sxi4ySM2rQC~}~jmlnH*a{p3-Y#!&~sm@AsXG$I~D=Y4- z{o7M#JICp2&=I=csI9V-kf~o+-RtImKwutYr8LE#u|2l zroWiSoimuNo|R5`4+4RLzJrNNLa?#9Sy}d#hJ%BHKz7;b9IF@9>{l;}yS{EfP=)Nz zAF=PdzpJzufKU!Sy=vbYXV%1=lP**2-1B4CMD$yUg|$V>k`kIk05R_J%jinlSX}Y( z%Sr{?OK0HhAI|+~1v?@2ay}aYj?N*R8OYgV+wXp5-bAsES;b2>OV#-yg>he{Qok08 zT0H!YeKQ;GXoxK;h*$fZ6Ww~jw_b5Skkdm#re~T9=Ece5>O2ZryR~^C<6*?nZ|~E` zCbRuw&mf6}<%osh=DJAS`p#0gBRkmEO!E<+D!vOZ2Zn?kX0q=xZ3NIEyyu2NbGIli z1Ps<3*9Ab9#x$#TbyepDg`63K?r&8CaCi z&#GGWM)&+W(l%ME1wnR0ouT%5P{n)Vc?-vV`m3z@?;9u>8YV2ilU(~+XK@n2y&|WG z@;vyHr~lzRjMkQ_4wf7y^y=1CmgUY*93xksK<)90+yw6{1n;<5Re4&=E1@r5msA&5 zUy)176kET|quDzSel5Dr)uJZZu6*H7R(HB;)qy>^R=J$til4*Bh1*gB%2&NNP!2jL zD9>$l7+~3sbj&*ro?E9hB5@h^0T!9#pj9Ezs@m>Jw4-?I!gQ+EEJd$P-m}cYZAmbEf~{@KyGI(n9b5fk26SNPTIx(WX@}m0KALD;=IO04D%aF! zpc3RNIlyX82&)lEn*oK^*=)e;V){usfI$5XPEE{Sz1Sm-{kHds&BDoOYq2VdniNGv z_)<3r9W3XwtjRP8OA4x3mhOKBG*CL$*49>R+U-)wOaS^$t6Vkn)yDH*8f!CflCK4M z4;Py3R`S~laC+Q{$+fYWQXft`EYlefYWj8T*DOcmtjVS&CFRrkF2eg3(VqvJ^Caf3`SgR@(*&4jf^^mi=~ z-<)R%Zz#Bcaqi$}?%MQw-${5v3_?#|(sbmLAAO7w53IT&yqtQ0Pg!rQhUV9PH8*vI zXG(8{-J*$(qg~SnwU7Xbv5}QL@;+U2gjtkGUrI!qs2f%U8omYPQW)Y;3k~b*4-zdj@HDDS63>B_&v% zhzyI*bsSGsnWHx{%qB7ly{oKmu^pXfwkCpOj?yIF?w(WsO{dE%)kky62+dFjQ zo7Tq1gTw-vO8N(B@aR!`D68_;{uaENo1JXE&0D@I@5u%xB5yy~c`lUWg;#MQAjz@D zN?$=z$G>$zp9Jc!`Bn<9_azSwFB{tD7~kER%7k^AKbs*t>uv>|h_DY`jZo)=(%5YC z0rp1_8XR)mxxIWL-D|{k6N^UP+aKJ%O_H80@F(z+Mv>axNV0L$vpCd{Z|)~4J0MK! z3*nE8m*w&(%DOAN7bHn@Z-0fl{~4cj*1d#-W?Rh7+X~7M^W~qCQ1_ExQX$RUUh4I) z?6DQ-q8%@*R_tTRkcW2jyigEDm1}32KM6C)`BiO^HMI+gM4i>s3O+yZ2$ng_DEbz( z?zJ*{Kn5AU5T3_w(QBFi8C%BpU{xcABc4x}iPp2vcdl_OA-Kr0b3nLQaTpNQy=YP$ z&I5prDIT45IN5S3n_1|8j?eggDKfU7$HOKqv%ycqZ5yzqt^Nb` zxkZ+?I%`95#K5OADjM$`y9CN%zD+}utWSYv*49O<373K|X$jQTnCum?G+!)3-(VvD zu9G)n_ao7MBT-2FJ?<8~!oVM0w8A474}XNtK+ z^KPfjoRgFyDoQJ+duiCf(Q9Mo`>nRnwzjGpM{%^04!TQt55xX%blx6cqa16Z=-TKQ zB{Pzqqzti0gL%1Ge4}W6bx8%@-+VVytV+SgjEKYc5 zs=>MyDLo8+#VvxIUiPL3sf3_g){eM_+tuwWBwSGBtAPRg;j%sQq?eyd8~rXbF*QmVOX*pyR-)TY-!d@{h?_O z$^u!n(~L5yseV&^Hhn%SJz5vcp1eAVQ$|v>x5RyJJ`1YwLVX5k#0cGr0W6Xt^%VBw zk&D5^VUFCcb!Lcs9x6jhYZ$Y z_nru;;~bBy`+gjQ3Y5V6UD)`>(yjQTW@PkV`LPc1txn_6^}ev`T&e(`m8f~whJB8^ z3`QHDE|Rn$a0jgdlFFOk4?fOZN4odR321NjDCrkj88+9eJ=AENR17{}f6?0qyO?I0 z$9Zf0WzAkjZ#VSeS--;InFz#fvq8Z8!=Lp_K%9J};(xmmnryW-H56Bx_(P&3BKZ0F zxngpvs`NAZ14G}4)&RtA-kYPB;}y+FnsEm@`H}((p6DrcB79dt=jyxC8E7@)KE42e zPA@SR%b&vz)PQN+)-hGa`QE#JNO+Rdm0h22dW4-L(Z};Y`m|n9^$NH#xFPO?2E|A{Te^$(16NwA{_#@ zJG;9KGQ3yjYDuoI;ScNyoMDnkxZzoUC+W^PW$-j|yRUXTO8Z?qKL-OJHe&^bx0d#T zGzbu<9#!wJk6&cmv9NxLHNKi5Ty8bVBqH50TT3#fw27ScHW+$8`^`P9=`hFdZ4dkQl*Vv~*!f|SG$x~ZW$^&bfC zrtQ7k0-7kH!o`uE;qX1oWU2k@o-R|$JkGi?qVYYQ#aal@Yk+GJ#!~A&oR#}wL3FbF z!DqTBD=pBHPVdFa-nu{Vi@i(9Gpr@$9Y^ggo`QA4J9kWvs2y2Ck6Wqr%7)~wCF0%c z?<4dPw2_+!Ybl2Wm0E@KMoCq|rGx~^Mbdm~Ugw#$f(1`spn&-T$=>?pf#rG}OrjL7 z`ET>XCl;tK{>bCV7^+*ox)ZV!WeLNN&y-!Kd2IFtJ2~jV5`a*@Ml157#QVGkCGPDj zZ3humhTkWCseL&hH#I$RVud{zE{?nPb~ky8oOrZO#1Q#?blJhs#H%-uyl+28b9KlJ z-&knO!ez-lwfVMQBc4lN0qo^Qc~KoFm#_vi6B>U$H>O z%T?l#*y3$lNoSU}XNzKzmZ)Oh79`UEe(oXJI=6~I=sgc8HgGW`ROB7`*i7-s_CjuQ z4()T%Ex#yK?NL2$YeQ%d-y(UJd`zepnvV~5+uLPLOLD%l{-Xkha1(#Z{rl!VHmYg{ z2JAke?@INx*rL?4u-n_}k0^%uw2zdA1_mk&^Hx?YfTFajFMuI|Db!W4o~V+5s( z7^39kaPLWwmKO6Q?ytZ8`ttMw@R4JwpieZ$raKA2_UO@!Zbs{G|CEquW2n zB5V2w>lM+0Z|j+M$Qf}TKU+9R=pGE?XS-OY4)mUD?0%i)Bxlc)g~L=H zE9|f6LGgz{37-z3P)6Bl|98cs>DWVkNf_{Gf{e?<>$~OReVi{*b$^4Pd)&tiE*!0m z7M~K2jd#m~TU*Dw6NJb23bpj0kmdaG?M5GavM%|%qEcS9${w|Z&tG~etM^1d+O45> zo8X=}##;+wJaR`0pO%g6-TF7clPxVR!{`N%kB`Id&VU$d zphzM2?YFukU&^9{9@`%303uC^svHRLXE6`;MiNzmGoe|v!?o-26+KOO#^NUl*|f)t z=@~jrpKX%lvPmW+JR*PA@>`Us9d^JZQN_n@^$q7IKVtRZ+kj`X`KYgxEUXUbwp4~C zlyqqfU^yL-^Q^0@bE&RH%mpFaggJ4|p~#n4nBL$Ly^me#53`@&CB=+Uw)i*6YSM`5 z&fdt5mnF=`3g4_vR~cl6K{xk9oI|`D9(EAi>tCXdsHhm<_4%Ym`l7V2cKTdaJz=xo zG-)?d&DdzWec}6wmC7y*e6pX1?N4LDnja2$?5kh3&rX#-T_mTMcY#aP^cM%yT9B;( zG$MM>-NU0f224jK^f(={s-$|d7IB;GldXU=MElImRC$@Uf- zb&OB$vkCmL8(un>YKEH9;DqU#sI*aLd>k$?P^#wzQa&;=GJlSTX0SaV_UPJ$Sw}?j zm}d0%=EF{oH;}{2PN}}naZ8jDZzlMkobSSI=j#azYu&t^w>w;Pn3 zBvkOnXc(b-%P+>Z@$+b!c+s294e$MG+q%PM6pAp6JlUlu9LW8SVgnTQn$_o*0Hif~ zfi5_-&UpIAjb#&a^HHDz%bo-CY;+1({uTF(o7 z&3V*a-j_3pBphPC8=d2ianUZV$R4lZJ}$YDA?bCrNG~8@vcW59Wu=siXS_vMlUDAT zGu&Bzjdpt2pMA+Yn$w`{O;eEQMos_txF=8=sDAa{S){;+evO2&FZ;34JH8D zxYnhcV+N*=4}xh1KW0!)Q4W-J535E7=d{Ty=VPfJ+w2|0Q&U}W!83`Ab1uF%evV(g zO2&ZIRLA0`JU8T*ce1r|05p28Ua`c{QrZ*aX0d~5-!ofHls8FsIXNeL4Ge|Ulwhm3 zw>MZ+5_%%}6{+#ZBqk=bLY`$S3-P|p5)u+RNzLCj(>~$Z|DW!@I;^U1T^Ge51Vl<& zL`npdZV*I}6p$|I?pQ1uDQTp;ySqa`L3+_0(u?jTvEWW*`P+M+efK@*+zW00Icbr_=zZ=c;mu;dimv>nHaQgOQ%QHLw@zXUe_i05}iQOT1LV3Q3 z*cmzsRix$3}fDNXw~ zFhL!&)UZ&yAW7`$zPTHLlZVA_JhD;FFnAr3Hk?z`+6pJd6a^rqBv8kQA!KbJg^7_- zv0&8G^HyhwtA?V(27r{AQhA*OgBS5q7|08yCad{H9rG@HC7pEKgx-{(liqvq@O-?4 z(Hdn`DkH_wM#y7?_1Hc65I((8G_6Qph)>j_Z5FfT_V^Z-HVJO*;c6w<%DN`4?U^8S1Lt00gZ-( zftFFAl#Z^%a)t`nZm}f;HDOO|!bgd{K|a^DQfWs(uWg2cKvQLaTLdemC&09}aFs+N zirumF{L{?$q~GL{0#J&%@jL~igr|bQQ$@Xzn5`e`Rr&9^jopnaR?oL&#?~UIHH7kr zNjSiErRSFR@;(pKM&`_F_h5}GR1eMH_cp;|?KHFEh-=(*Kc~FP-l0f|uC%9{_v2%g zniq{zOO$t{X3T8fkY4xZN(;6$kv9$@a~jUAod}b-!t-I{&=-yVt~gGiqpoX>(23ab z2|V#ooON^7v$nPd<|Lr6vXJVb6yD-l2O&J^0Rb-n+`iq{r;6Sq`{XXSmz(2f#*&52 zMP=78+$enIeyF6jQgOJMKx8@3IG1Bv5D&)U2kDJ|Gi=Dz@?~1h+f$w%y*Kt@NAUyhUc5YgA@vwH#nj$YoyGfvYsnhC%LtBZ{3T=3}f@asF*MvXnFd< zdMzQ2y~1hUyK|O`_8BbV%B^?(7t#bQ_W5~+3fik7tk5Fc0r}W^whA4Hciix&QH8p$ zD<<3V)&*nGx*x{S3K>TXidUqdS}(q#;2S;5G%~(wyUyg1;DQm?2d&7IPusm_dup;u z;UC3KJh`d0rQcY}hBtF@F$fFL^iOQ5Cu!w8+b%(AGBnT$qveZCObj0~b!yBDwnPx8 zic3r}Q?I9=G<(K*Dysgpw2s$a_nvQ{EOZPxD~qKhy3oDAV2(XRPx6$-c2n9i;C3XyVs5?PgVSSh|6*aw+?~oGNt?fsn1CMY0H&kr15Q48AQ( z0j7(7s!jCt_i_;lau*(kbe2yG4RJVV)4?NWR+5@2c=41T|?T~QqsCl~(k#!6aMv)EQ_nW{mx;NE;2qu=n#61n4~ z^HLW6yuR72qEQtG|C6%IS*SMiJp*!PHE$*DFT&)5FD@1D6X|A_G-yycv(w}l#tJV5 z%^CLc)R3R`ubSlEFKYVrSn-_eCvQ}F{(?|M>ouDcXb`rpM}o*4jP|jz?k_tV2eh$U zb=%YmD3&r5(bT~H4_g_w?EK@&_ksojCu|}j(4D^XKejwD7TzUN+sWxVotiL)RpmLK z8;yuNgX82MGrGAyuK;b)LD`%(mRq^2lw9{Woi;wV`WC`Z<218Q+`eG*d2@njq3y!_ zpn*8Z-Y#vVFU7r-5()7Zg2kT5E!*s0P}zIr`WkHJJ>UIKWDC3$Q$-CORs%B`m{jI^1@LtCm^ zRaO(`(m55Y;u=BP$gbU3Ije~d^_eOHJaTgLE_0Km_@|9cjkG;3`IDbZOFzoSsx3Sq zlY<#`kY#JPwuMK9%j-mhEb^N7_r55Fp|PLft!W(F)+QQ?AGDNDF!Jz349+Wt#Ti$N z!`1Otk7UAa2X455NOn?%9`_jai5?{?$PqDbndry3{*5g_l@G85g6Tt@-*n8GyyL0` z&k_ht(kstPC~wC1pko@Y9gq4D3w=|FB0J0fra);^QzRkaz5WLa=r%WDVdZ^XdRJer zoMEM`PVH*2&{-I|W`ITU;cUHqad8Jy<+k;Aq=H8!NBDO_{X=K#DCvzgqHkCO^&8`^ zy1UI)yi~e}^>%4T=%~yO?l0%JlrH=a>;ffLfL)Nl>~!;e+TH#qF5IRnxhS10 zwW*1TI-`=keU)?$4ry9#EhjClSn6TqmP(2$i^1ybwKPnfY3BBIj+;LfvBVbh<;$QB z4;3ep$^<5Lk!pe}?Gtr}gra9WJumKIQoG(D<$Et87m)PQNbycGGXvgL3vltVZxUr&#}R2eOAdg!R$&`~(kir^N)~R*0WSdV^iJ>{eRw z&^r=>EVAhW$MlrYz$;ATrmT!JU|F?mx_H8?V6DsE<$R6I<^Xn)QY1;Mmi#MYMO0mgU$okccGM`Gor;Tb61)0YpE}K2PbfKorBq7! z1^u5)(I^yPn)i%dSV-;O-5lfRwh{dJ@#Ef)(}KAqbMQHcxW`*kosd}ZB=%}7Ja?P8 zS{?eN+06@Q{#PHL2t9xIpCYA)!+Il9z1jGQm#6$vJ5wdCD0MGntFKVP4P9x*FtO&S z=`Lm4jQ*>)FO+Q?tp{x;a{_Zl2(}+reUx%@-Q4l%IFG*6g+@+qOcPMMP7h&&u56`# zY(Zg?DJ<5zzUJlMXAn>A!JR}PsH6}bFxLcUG(l&5@DMB#ED{4U{Lp*4+%q#1sV_^& zM8#-(e;6R)(_AcyU9{NrX|1`PW$GHY*)|kx@Q}}!%C|hD;(+yp65OR`xM<($30V`H zio`v(YC}qk<2F3`f~81qd0I)LPuMd*l^4fJ{Rc`%no5fx7n;b=3rr>?TrU{(mUf37 z=S5vjl&W!7mrSRsly2?+BuX23kX&ZetR;7FdDicBb)Iz!u(63+_VOa`2U2!2x!Qf4 zjK-Lz=|8njbw2O^1=T06W-U2LY_T(2VnGq@ohCaQ>TGEdrTp`rw-*?=14~jgKYaM0 zIijd2_skdLu@!hN4ckj31l@GCcFB)9Vr}(_iS)_X zvi0aM7)))^nN$PhPySq!H2Y9d@P0^&qqBw?zi9HRzXgc`>mxc1qRy( zv>s?C8d$6bJHH_&(SpA|8G$8WNVuuDoTM~p{K=P}L`c7A#pXP}>MeEztro(V0|0Kr z3qtzUewPNDlah@Bz1nTf{ZL9wB@KnunurU7XK(z!{vuooX*qOP)QjZWC}3k!ZiL$r zV;+x2V?_H~Qzle-Q%Pb-pRKX`{khp68HeIlV(D6^TUyA;=cA2fJ(*9Garn)r11f)AU@bq!q z1qN%t(+j`oJmoJz!jqAce?84_4)FRXG^H61enbD$VC&l)&wi7pBE_?S%}s>TYO~9R z49l~#J63EIl$18@xDn$>kZikaKfdS352Las9Erb%cRkDBiB7ny?%B}`0V;vN1`RO* z{ojNr|Fhuh|9--SYUHKMQE!zMC<7`Xugv_$`45-&DbuNza0nVJ z#;LhK7d_!?N;R)g$ZFw!#eMeO4$&!&NI)F@yjT@Fpq7zXWph4<>IzvR(}^b(RXpgot*S2LhIRsp*$Z|VqEw{n{hvb z8tik(!wSb;PY#@mlBwNw9;U6w5if6G4kRQppf{4!<{@I+{z>or%!_?}W4||GUa(6~ ziMhXWTHRRm9ZRobVTyEfNS@d~>)p4f;#qA>R(1MbmqkcaU^0PO;>NE10oZA4U%<`4 zJh=c|vRGA8L~>T(W6h8FO7|IO72V%(_m&M+9uMYd8Ggi!Vo2_*Q%F;@x zwr3kmm)cU31{l@VT&iwWZ+0Pfu~PVi!RmAeEEQI>AUq%8!=3Au=Q!K3qu zhi?vKj(L-be0TQOYOh)%)Ur2;bBD%KPh+LkQ`k@-`K4HaqUn7qUVdkz%NF^PaKV@y z3+ZivweR5e%??QoPM$*RP=-@j&+|1V3*k6K%8*J-;o(aon}1(K#(fKG)4{dby4hyC z!kuSk%oF(@MtF0B>h5x>LO`1EeT}gl$*cBVEGm8u%hcbm0x+9Fy9VxU&npI(v<6JX z!$!S2WFG6CZ&<r$T-*};o)?0K!_W^ z2I6wFB-fWaEB3x~>^mNlm0Zg0)1%_{ahrHk=0R{M`lF|*T30x94Iz_>($oGUFb=YY zm+KSpH8qL3rt=3U@w)B1Aecq4`%GnRM1gz7fzfPiCdb(FINSX`RnWqx7Rg6CLt2<5 zj^=+A2f6-FmYAL+o=PVBx~MEDTA^A5_!H)RZ~}wra05(<=>Kuaq#<^8I4DD;Vv#OclT~>%gh8B<20vlo!rAp=gWnvh1_Z9+5MH0lnbFDY~ z-Bf_p5#p!bYotGphyQgB{>gwe@Log1ykZj2uUxAzuBCOjXg+T<22HAN{2q~#0+5Kv zUW=#5Byq2-t&Qi%kV8e8fi8l$zH6~4$t-pJXLX0;J*V_SGJES*$O2 zm76v)UTlh(Q$aVCil!ADzrV^sw{0#9Q2Y>+X{lbt%~dljq~)x=8f{;2S>`mH+!o$g zQUurOz&!lpi*a)yOmtZ#+|?*H)9362ldktLG3tiG4n7qY@=f{_N#-*Lxjj*IKNEBK zBCqb=KU7F+d^bLqa9Gy~FI!(xgpaj#WPjgw&R*-_=KJv=_O3yC&%|k#8aipy_~FjR zCb4+tMcw#Uiq}dcKLMzWLsi`;l-)04O}+|1>$IPtP5reWx4Y}ofleEO;=UD#Z}BiQF&g#t9u{$O%NP#2)iG0c=u z+-zT3%)scb2W^E7-M)U*{!{aTnnoXw? zRah49)fFl*NKds1)&OYLYikxaZd=vLx#*NQ4JEP6mke~nCZC-hcV4^FfRyO^y*dX(IL?UQAg_3cVmLYfB{HkMdXr62=xprj7 z&Y%BmA$uHtVV~X$&2>*}+^P`(5S=vC+KpRL3|CXRS#PUoyC$luO51kw^DJLhLg>C~ zsp;CYS#s%u0uHvY?8kzE0d=DhP}1k9IvQ#yc8OdqG)!7dpKZ`*rLf{)Eh-3TVxdc-zgLPSvgALnsBw zsPv$=*(A@9gi~-bH=QJnhN$L2eo(Yi((@WRSJpnY5tFPK3Im5m=wcuPp3++LvgQZy zP3kR(j8Ao&U=v$=%WyzImG+ZRuoPgH&2J)W(O<@0kfdnqq^VY}Z2aEQv9u@gR3)wG zZSC`3V?qNZt6x#3PPtOZ$Ne~Q#s&oiQvOKAUYkNJK6&xzQ#~c(eD4@WMfyH4jqX1A9Mm)#Zew*=&*WXMRN5R zrj0}0Am@;2ePNLTf`On%q6DBJHWy0(@j&zXO|vHoo?vham7T7wbR)kFhjkNhx4 zi39;4u|sm#j~fOTyT$Z(M%TFo_pR{1*Sn|r9FVCOyDUFO`cJ}sUBfC_+9=ZGQ1oj`6m&|Xv*}uCo_yeZcxf0~N zC=c;Va@kJLbWsnsb~AIh>R_Z0&;P^$V2I*X-@0qDo#2}Bjo2=5MT@TWmK|a7r%3xN zaTcZ8H^IZ<$;J*F4=%pmfLk8KgjAd!#X^MK29m}m9nqu4jA=)M2_4@>juDB-*Wf@T zqIGT;p|{eQgmlYzj}thRZlXBS_$>gtLA3J!NQUzNG}!WAac%T}jyzXON?lkNIrU;dHK6sfx;q>uo$7y%f zz~#1;+I`Gi`jj1$rigY$I$uoEXT{m>@54C38d8vH8WZ_b8ou{{gb;yt2EFk&AlR!&~sP6tPMB-c`FP>CEPq{RyAfonwtn zD{nN;qie=Vh}~KmK&BT<+251Y;R#Wqn;p-Z%BWkk{Z39|Q(eg$E7~<2r{Y=;I0|Gs zq=NpGw^I`i@jYnvNa1Y)N*2F{i4UpyOl{GsEFiI5^j9bHpmbil{=xdF=deU^Gr{pWsiUrcwl25dBFiX9H$#v9kRY z9R5S|0AhF}{nt6T@$Ld4pz$|nPiX&noy-GY&^LT$~+2DdA$*!?&IZU=S)OC=B(<2nr(oraN&HTxXF$NQ>l$ZB0g8`y|*o4`GDb zP5+zf01BpG`}p|vgzNa=@6yxsJNJ2o%*`20fh`R@L;-6U$D?bB4>#%m0%XXo3?y8D zE5;%>ka3M1Nj2BDyS0K0<3-!PZPZSF()I64rK2EO=KRPZL+kW1-7(494HLol} zpD!`QQLLJjIBlF(()7}{r(WSoxye{Y``z65nA9$eASJ`z^@g@lDFCvsTBy{3Op(0DAQ^0w4S5cE|O+AwoLI$8Y3 zjbFdGcI%l=Z&s>bF#winF2S{tgBh3R^V`SA7*ukXGo}k+sq`Uxq0))O48?7oxL2j` z?9i(C4Z0I!>-&DiCD|cBu)U9WAc8pUVGqrlzpFn#vPZ3?YWY!2%-q|g5nTtxG5t03 z>+B&12UsEdbChP3f!UM^YVyUBGCV4qHz^@JUO&$cl_`szc6H8KlDp(=vKyl&Ae}PH zA?E!FYG5Ea>5OpgroLY0P8XB?7>fPJ&n-=Rl6%YFzVxj&FA7qaG!I;1ud`m;O^V#Xs$ z%rTA$s?G>a2c+r!C*)c|0p2&D)r6A3O-LuS{V#R4WF$C7 zeUejg^UD4imFwqWwS=|?{EssPB2vJmA56;0rQh|{+@EJN?=K{@_EI0q$EPvZPE}Kp zJx#486iDJ?P_^tC=q;vyCKnqWY0UPGj~BE<>HlgfytmR!O?dZUw?HZapkN+)(k8Ld ztk@n>`Te+f#x~DmGxY*y4C9Mx26kQz)d@)90cF1K-qBqf%NjV2A;IN1{8Gn46Q?dJ zFLyvxJaMVva}x6F+j)i5XoI_3fCci>)8;ZnJpOuZ*WxB!KS>2rv$+#dj z-&L5%m1$nu2-Rv9$!)d?AGH}2nX-SAl#t9-L*LF~!x#x1&WiS(^WAF*<~9!h`lAc9 zt|4;wv@i5y7X#-KITxc)j!nu*Y}zGzVBJNxsBwQ>%38A?G*(lH^f4aWdlk7ODL7-w z>#~gY2UD6Rh_D&@8Wl5@%iMeL3L;DAS?#WC4YkBFl~FeV)xRNkwHn@ZyX2N#wHs-9 zuX!>}UI0&o+)+RF=#F+bACb#Yjnp%nR#nypjgD|UR$a$kC@CtdkFQBA;}HR$_!X2V zs5(J4l=#JM$10?)`xDFaC&NvI+uvKdP2Xq;7r+2?6PVi`bmqmi>WUeNLWVQPi|ODW zZ+gyw%x|JUo31M_d=IWsr$CEAL_xyfFn)UUFvKKh{bltQDU_<|txOVbc0@5H6IkJ` zM3Z#XbR>WLD#Ksa1^eHl0}5=lY?$(SZ*YXvTY--}1OMKKAiITJmAs0UV@)|}RJwqR zuY^IRkd>B~cS67aq7b4;2~_VZA5_qDUUakZjbwW|t@-z|R*Wi`Go3QiUj-SF=Ty{d zw_i3bg8k3s~3^v#2l@1 zZW{vT1rSV*Go=+ngV>^>w1T2lKD7v2bHth=IRFpxHA_;jDJt^^j=+^1Q+*NeKWcO{|jUC?8G|r9leP4k2gLx1Hrp{{m2BI8SNl^B zD``4S`zB5U}`{P@vDLFvkxj$ZNSstAbVKhL=F{09>xNKhQ!F zx@}(H2QzF@^uAzH+{cu0%Qb)ye6l%d{~WoH-EEx^)DGDsYz!r zM+>ica?LTsvIdDD?H=o%aPH-%c?u8f8b`C8#g7!{pq<^b`5aQj9eou6iUjHf4K8j8 zQ-^8O-Y<;-WpG6&|60pD&-q~2Sm&>1+gh2St3y2V{m&=u?XLXlgTjb!gMW^wT}FKnl0QT2FpcT~Or<-x<7%L{@4rI@;w7GrU2wKC#Al6fEz)xPy5Pz+J*|Geka_t1e87$FTQ6IE%A0@;_bNuWmaKiIb1J^fN*BAc zvKZHSu0m9P@Fjg3$(&Yv(O7xk<;3DD7Ryn+vq}jK4V};A{+XA;`OUeqxUuBiPf|hEzx&OYjJSX>5XPV18Se>9{Yf=k(*)EgD zPj_>+2Qdy115KH`V1_J>=O4J|-e`#{pmcBeUK!_YN+E&|4qKjk3|Up$Cl!P%SqP8pLkISeiL zlZ*k=eB?$^8M)5KrV=u!X$syW0$h7=lM3Op3~Ea_c<@#JyvvMrZ`#ZL_2cC~bdTD> z-(eLpSg2Sao+bA@3NVsE^I44V5Krj>T(o0)6f`u7hM{jnIr)wiDFpf?@|r=MiA;0u zClZ5rNAI{_Ao_>?+9@n?*21zZ3BcV&YhnJ$8N0Hx*iU*lw>2mctS}(e0oHTazH=GP z?X=GiNv=S2-{WsO$iwLlBuvS?$f&a$PTV<-mF)IMm1or7(0tEs76g)9$5x@xgD6Wh zRyWH%sQQlRSyrsnO^!PdY+R`?cJN*HoBKg>B-)LSkDr?I#Z^VxUeQF-s6nZ(c4KS$ zByx)}PGYo6D2`^o}F{fa}&w+l}ATZqwVJO`3Oj}QkSH$3wh(9k=r zsDV}=a^3f)`NF7jb0Sd6#Dj#rYZpc_ZRoINaCJX19Zh(5ecAxN^v>p zQfT1Y`-%+M-yz}-(n6k_7{+>d_#;IBA_*4Y0{WiY>qgsPr|f^U7ed@cnCNw}d&|K& za9cp{uAMD#X$Hp6%}XIX2&5nBs~7w$(peL1j^*(K`D{t>N|ci7gVc!d@V`3%p!}{0 zT%8hVx$Fa5W{6L_U!Bh*q6`vJ%>JWsMu3@!_>V}CeDd%HWfr>NdM!Y z0y*x|K%SELbGuKF|Bf~EFXfpBCiB9K?vA6jh||oUSl(G<@F*64jevuYe!Sa32?0Je z|MdMB8Ua1j%Jf?)GB-yHzLmS9l=2M~TzZ?Re9y++Ld2QBVdvMRgsiOWPn$Xupv@wB z+ruFrYp1cXG14B_ruft4wPnrK6^98*AMoSe^-2~QNuFN3YD4SOZ^-nWi1eFcp^u;b E8 literal 0 HcmV?d00001 diff --git a/package.json b/package.json new file mode 100644 index 0000000..7686b29 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://www.schemastore.org/package.json", + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.0.0", + "axios": "^1.11.0", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^2.0.0", + "tailwindcss": "^4.0.0", + "vite": "^7.0.7" + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..e7f0a48 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,36 @@ + + + + + tests/Unit + + + tests/Feature + + + + + app + + + + + + + + + + + + + + + + + + + diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..b574a59 --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,25 @@ + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Handle X-XSRF-Token Header + RewriteCond %{HTTP:x-xsrf-token} . + RewriteRule .* - [E=HTTP_X_XSRF_TOKEN:%{HTTP:X-XSRF-Token}] + + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Send Requests To Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..e69de29 diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..ee8f07e --- /dev/null +++ b/public/index.php @@ -0,0 +1,20 @@ +handleRequest(Request::capture()); diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..eb05362 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/public/zalo/qr.png b/public/zalo/qr.png new file mode 100644 index 0000000000000000000000000000000000000000..a7d30b9f1d4fdb7ff82ebcc10dc48c5bb46af397 GIT binary patch literal 16609 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 Ltf|Sr@!9zAkPtsi literal 0 HcmV?d00001 diff --git a/resources/css/app.css b/resources/css/app.css new file mode 100644 index 0000000..3e6abea --- /dev/null +++ b/resources/css/app.css @@ -0,0 +1,11 @@ +@import 'tailwindcss'; + +@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; +@source '../../storage/framework/views/*.php'; +@source '../**/*.blade.php'; +@source '../**/*.js'; + +@theme { + --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol', 'Noto Color Emoji'; +} diff --git a/resources/js/app.js b/resources/js/app.js new file mode 100644 index 0000000..e59d6a0 --- /dev/null +++ b/resources/js/app.js @@ -0,0 +1 @@ +import './bootstrap'; diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js new file mode 100644 index 0000000..5f1390b --- /dev/null +++ b/resources/js/bootstrap.js @@ -0,0 +1,4 @@ +import axios from 'axios'; +window.axios = axios; + +window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php new file mode 100644 index 0000000..340a0e4 --- /dev/null +++ b/resources/views/auth/login.blade.php @@ -0,0 +1,83 @@ + + + + + + Shopee Affiliate Link | {{ !$hasUsers ? 'Khởi tạo Admin' : 'Đăng nhập' }} + + + + + + + + diff --git a/resources/views/convert/index.blade.php b/resources/views/convert/index.blade.php new file mode 100644 index 0000000..75cc2bc --- /dev/null +++ b/resources/views/convert/index.blade.php @@ -0,0 +1,84 @@ +@extends('layouts.app') + +@section('title', 'Convert Link') + +@section('content') +
+
+
+
+
Paste your Shopee link here
+
+
+ @csrf +
+
+ + + +
+
+
+
+ + @if(session('success_result')) + @php $result = session('success_result'); @endphp +
+
+

Conversion Successful

+
+
+
+ + +
+
+ +
+ + +
+
+
+
Converter: {{ $result->converterType }}
+
Session: {{ $result->sessionUsed }}
+
Execution Time: {{ number_format($result->executionTime, 4) }}s
+
+
+
+ @endif + + @if(session('error_result')) + @php $result = session('error_result'); @endphp +
+
+

Conversion Failed

+
+
+

{{ $result->errorMessage }}

+
+ + +
+
+
Converter: {{ $result->converterType }}
+
Session: {{ $result->sessionUsed ?? '-' }}
+
+
+
+ @endif +
+
+@endsection + +@push('scripts') + +@endpush diff --git a/resources/views/customer_lookup.blade.php b/resources/views/customer_lookup.blade.php new file mode 100644 index 0000000..b71bd8c --- /dev/null +++ b/resources/views/customer_lookup.blade.php @@ -0,0 +1,282 @@ + + + + + + Tra Cứu Lượt Click & Hoa Hồng - Shopee Affiliate + + + + + + + + + + +
+
+ +
+ + +
+ +
+
+ + +
+
+ + @if(isset($searched) && $searched) +
+ + +
+
+
+
Số link đã tạo
+
{{ $histories->count() }}
+
+
+
+
+
Tổng lượt click
+
{{ number_format($histories->sum('clicks')) }}
+
+
+
+
+
Hoa hồng ước tính
+
~{{ number_format($histories->sum('estimated_commission')) }}đ
+
+
+
+ + + + + +
+ + + + + + + + + + + + @forelse($histories as $history) + + + + + + + + @empty + + + + @endif + +
Thời gianSản phẩmGiá bánLượt clickHoa hồng ước tính
{{ $history->created_at->format('H:i d/m/Y') }} + {{ $history->product_title ?? 'Sản phẩm Shopee' }} + {{ $history->product_price > 0 ? number_format($history->product_price) . 'đ' : '-' }}{{ number_format($history->clicks) }}{{ $history->estimated_commission > 0 ? '~' . number_format($history->estimated_commission) . 'đ' : '-' }}
Không tìm thấy lịch sử tạo link nào cho số điện thoại này.
+
+ @endif + + +
+ +
+ © 2026 - Rút Gọn Link Shopee Affiliate. +
+
+ + diff --git a/resources/views/dashboard/index.blade.php b/resources/views/dashboard/index.blade.php new file mode 100644 index 0000000..09976c7 --- /dev/null +++ b/resources/views/dashboard/index.blade.php @@ -0,0 +1,74 @@ +@extends('layouts.app') + +@section('title', 'Dashboard') + +@section('content') +
+
+
+
+

{{ $totalConversions }}

+

Total Conversions (Offline)

+
+
+ +
+
+
+
+ +
+
+
+
+

Recent Conversions

+
+
+ + + + + + + + + + + + + @forelse($recentConversions as $conv) + + + + + + + + + @empty + + + + @endforelse + +
IDOriginal URLAffiliate URLStatusSessionTime
{{ $conv->id }}{{ $conv->original_url }} + @if($conv->code) + @php $shortUrl = route('short_link.redirect', ['code' => $conv->code]); @endphp + {{ $shortUrl }} + @elseif($conv->affiliate_url) + {{ $conv->affiliate_url }} + @else + - + @endif + + @if($conv->status === 'success') + Success + @else + Failed + @endif + {{ $conv->session_name ?? '-' }}{{ $conv->created_at->diffForHumans() }}
No conversions yet.
+
+
+
+
+@endsection diff --git a/resources/views/history/index.blade.php b/resources/views/history/index.blade.php new file mode 100644 index 0000000..e106c76 --- /dev/null +++ b/resources/views/history/index.blade.php @@ -0,0 +1,247 @@ +@extends('layouts.app') + +@section('title', 'Lịch sử chuyển đổi') + +@section('content') +
+
+ +
+
+

Chọn các dòng cần xóa hoặc quản lý link

+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + @forelse($histories as $history) + + + + + + + + + + + + @empty + + + + @endforelse + +
+ + Thời gianKênh ZaloKhách hàngLink gốcLink rút gọnLượt clickTrạng tháiHành động
+ + {{ $history->created_at->format('H:i:s d/m/Y') }} + @if($history->zalo_thread_id) +
+
+ + {{ $history->zalo_chat_name ?? 'Nhóm Zalo' }} + + ID: {{ $history->zalo_thread_id }} +
+
+
+ @csrf + + + @if(in_array($history->zalo_thread_id, $allowedThreadIds)) + + @else + + @endif +
+
+
+ @else + Web Rút Gọn + @endif +
+ @if($history->customer_name || $history->customer_phone) + {{ $history->customer_name ?: 'Ẩn danh' }} + @if($history->customer_phone) + {{ $history->customer_phone }} + @endif + @else + - + @endif + + {{ $history->original_url }} + + @if($history->code) + @php + $domainSetting = app(\App\Services\SettingService::class)->get('short_link_domain'); + if ($domainSetting) { + $shortUrl = rtrim($domainSetting, '/') . '/aff/s/' . $history->code; + } else { + $shortUrl = route('short_link.redirect', ['code' => $history->code]); + } + @endphp +
+ {{ $shortUrl }} + +
+ @elseif($history->affiliate_url) + {{ $history->affiliate_url }} + @else + - + @endif +
+ {{ number_format($history->clicks) }} + + @if($history->status === 'success') + Thành công + @elseif($history->zalo_thread_id && $history->status === 'failed' && str_contains($history->error_message, 'restricted')) + Bị chặn (Whitelist) + @else + Thất bại + @endif + + +
Không tìm thấy lịch sử nào.
+
+ @if($histories->hasPages()) + + @endif +
+
+
+ + + + + +@endsection + +@push('scripts') + +@endpush diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..bb6775e --- /dev/null +++ b/resources/views/layouts/app.blade.php @@ -0,0 +1,113 @@ + + + + + + Shopee Link Converter | @yield('title') + + + @stack('styles') + + +
+ + + + + + + +
+
+
+
+
+

@yield('title')

+
+
+
+
+
+
+ @if(session('success')) + + @endif + + @if($errors->any()) + + @endif + + @yield('content') +
+
+
+
+ + + + + @stack('scripts') + + diff --git a/resources/views/public_convert.blade.php b/resources/views/public_convert.blade.php new file mode 100644 index 0000000..64dc45b --- /dev/null +++ b/resources/views/public_convert.blade.php @@ -0,0 +1,400 @@ + + + + + + Rút Gọn Link Shopee Affiliate - Tạo Link Nhanh + + + + + + + + + + +
+
+ +
+ + + + +
+ +
+
+
Đang convert link Shopee...
+
+ + + @if(session('error')) + + @endif + +
+ @csrf +
+ + +
+ Hỗ trợ link sản phẩm Shopee, link shop, link bộ sưu tập, hoặc link rút gọn s.shopee.vn. +
+
+ +
+
+ + +
+
+ + +
+
+ +
+
+ + Quyền lợi hoa hồng: Việc nhập Tên & Số điện thoại là không bắt buộc. Tuy nhiên, nếu bạn điền thông tin, Admin sẽ dựa vào đó để đối soát đơn hàng và chia lại tiền hoa hồng chiết khấu trực tiếp cho bạn! +
+
+ + + +
+ + + @if(session('short_url')) +
+ @if(session('product_title')) +
+
Sản phẩm:
+
{{ session('product_title') }}
+
+ @endif + +
+
Link Affiliate của bạn:
+ +
+ + @if(session('estimated_commission') && session('estimated_commission') > 0) +
+
+ Hoa hồng ước tính: ~{{ number_format(session('estimated_commission')) }}đ +
+
+ * Lưu ý: Số tiền hoa hồng hiển thị ở trên chỉ là ước tính tham khảo dựa trên giá sản phẩm tại thời điểm tạo link. Hoa hồng thực tế nhận được có thể chênh lệch tùy thuộc vào chính sách chiết khấu động của Shopee và loại shop tại thời điểm người mua thanh toán đơn hàng thành công. +
+
+ @endif +
+ @endif +
+ + + @php + $zaloGroupUrl = app(\App\Services\SettingService::class)->get('zalo_group_join_url'); + @endphp + @if($zaloGroupUrl) +
+
Tham gia cộng đồng Zalo
+

Tham gia nhóm Zalo của chúng tôi để nhận tin tức giảm giá hot nhất và được hỗ trợ 24/7 từ Admin!

+ + Tham gia nhóm Zalo ngay + +
+ @endif + +
+ © 2026 - Rút Gọn Link Shopee Affiliate. +
+
+ + + + + diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php new file mode 100644 index 0000000..4a417f9 --- /dev/null +++ b/resources/views/settings/index.blade.php @@ -0,0 +1,171 @@ +@extends('layouts.app') + +@section('title', 'Settings') + +@section('content') +
+ +
+
+
+

Cấu hình hệ thống

+
+
+ @csrf +
+
+ + + Mã Affiliate ID của bạn (lấy từ thiết lập tài khoản Shopee Affiliate). Đây là tham số bắt buộc để hệ thống tạo link chuyển hướng (an_redir) offline. +
+
+ + + Mã Token HTTP API của Zalo Bot (lấy từ ứng dụng Bot Creator). Dùng để chatbot tự động gửi tin nhắn phản hồi. +
+
+ + + Mã khoá bảo mật tự chọn (điền ở ô Secret Token trên Zalo Bot Creator). Dùng để xác thực các request gửi từ Zalo về web của bạn là an toàn. Có thể để trống nếu không dùng. +
+
+ + + Tên miền công khai của bạn (ví dụ: link ngrok hiện tại của bạn: https://c2e9-....ngrok-free.app). Dùng để các link rút gọn gửi đi có tên miền click được từ xa. Để trống sẽ dùng mặc định localhost. +
+
+ + + Đường dẫn tham gia nhóm Zalo chia sẻ/hỗ trợ của bạn. Đường dẫn này sẽ hiển thị ở trang tạo link công khai để người dùng truy cập. +
+
+ + + Cấu hình tỷ lệ hoa hồng cố định hiển thị cho người dùng (ví dụ: 5.0 đại diện cho 5%). Để trống hệ thống sẽ tự phân loại thông minh theo ngành hàng và loại shop. +
+
+
+ + +
Hệ thống sẽ chạy ngầm hàng ngày để xóa bỏ các link quá hạn dùng nhằm giải phóng cơ sở dữ liệu.
+
+ +
+
+
Cách tính Countdown dọn dẹp:
+
    +
  • Sống cơ bản: 30 ngày kể từ lúc tạo link.
  • +
  • Cộng thêm click: Mỗi 1 click (`clicks`) sẽ được cộng thêm 3 ngày sống.
  • +
  • Công thức: Hạn dùng = Ngày tạo + 30 ngày + (Lượt click × 3 ngày).
  • +
+
+
+
+ +
+
+
+ + +
+
+
+

Zalo Self-Bot (Tài khoản cá nhân)

+
+
+ @php + $status = $settings['zalo_bot_status'] ?? 'disconnected'; + $user = $settings['zalo_bot_user'] ?? ''; + @endphp + +
+ Trạng thái kết nối: + @if($status === 'connected') + ĐÃ KẾT NỐI +
+ {{ $user ?: 'Tài khoản Zalo' }} +
+

Bot đang chạy ngầm và lắng nghe tin nhắn từ tài khoản này.

+ +
+
+ @csrf + +
+
+ @elseif($status === 'waiting_scan') +
+ CHỜ QUÉT MÃ QR + +
+ +
+
+
Đang tạo mã QR...
+
+ + Zalo QR Login +
+
+ +
+ Hướng dẫn quét mã: +
    +
  1. Mở ứng dụng Zalo trên điện thoại (nên dùng nick phụ).
  2. +
  3. Mở tính năng Quét mã QR và quét ảnh phía trên.
  4. +
  5. Xác nhận Đăng nhập trên điện thoại của bạn.
  6. +
+
+ +
+
+ @csrf + +
+
+ @else + NGẮT KẾT NỐI +

Tài khoản Zalo cá nhân hiện chưa được liên kết.

+ +
+
+ @csrf + +
+
+ @endif +
+ + @if($status !== 'disconnected') +
+
+ Để ngắt kết nối tài khoản hoặc đổi tài khoản khác: bạn hãy nhấn Ctrl + C ở Terminal chạy bot và xóa file zalo-userbot/session.json (nếu có) hoặc đăng xuất phiên web trên app điện thoại. +
+ @endif +
+
+
+
+@endsection + +@push('scripts') + +@endpush + diff --git a/resources/views/short_link_preview.blade.php b/resources/views/short_link_preview.blade.php new file mode 100644 index 0000000..b388fa5 --- /dev/null +++ b/resources/views/short_link_preview.blade.php @@ -0,0 +1,25 @@ + + + + + {{ $history->product_title ?? 'Sản phẩm Shopee' }} + + + + + + @if($history->product_image) + + @endif + + + + + + +

Đang chuyển hướng sang Shopee... Nếu không tự động chuyển hướng, vui lòng bấm vào đây.

+ + + diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php new file mode 100644 index 0000000..b7355d7 --- /dev/null +++ b/resources/views/welcome.blade.php @@ -0,0 +1,277 @@ + + + + + + + {{ config('app.name', 'Laravel') }} + + + + + + + @if (file_exists(public_path('build/manifest.json')) || file_exists(public_path('hot'))) + @vite(['resources/css/app.css', 'resources/js/app.js']) + @else + + @endif + + +
+ @if (Route::has('login')) + + @endif +
+
+
+
+

Let's get started

+

Laravel has an incredibly rich ecosystem.
We suggest starting with the following.

+ + +
+
+ {{-- Laravel Logo --}} + + + + + + + + + + + {{-- Light Mode 12 SVG --}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{-- Dark Mode 12 SVG --}} + +
+
+
+
+ + @if (Route::has('login')) + + @endif + + diff --git a/resources/views/zalo_channels/index.blade.php b/resources/views/zalo_channels/index.blade.php new file mode 100644 index 0000000..5e18a4c --- /dev/null +++ b/resources/views/zalo_channels/index.blade.php @@ -0,0 +1,245 @@ +@extends('layouts.app') + +@section('title', 'Quản lý kênh Zalo') + +@section('content') +
+ +
+
+
+
Thêm kênh thủ công
+
+
+
+ @csrf +
+ + + Nhập ID cuộc trò chuyện lấy từ trang Lịch sử. +
+
+ + + Đặt tên bất kỳ để bạn dễ phân biệt kênh nào với kênh nào. +
+ +
+
+
+ +
+
+
Cách hoạt động:
+
    +
  • Chỉ chạy trên Whitelist: Bot sẽ CHỈ phản hồi những cuộc trò chuyện (nhóm hoặc cá nhân) đã được thêm vào danh sách bên cạnh và ở trạng thái "Hoạt động".
  • +
  • Nếu danh sách trống hoặc bị chặn: Bot sẽ KHÔNG phản hồi bất kỳ tin nhắn nào để đảm bảo an toàn, tránh spam nhóm lạ.
  • +
+
+
+
+ + +
+
+
+
Danh sách kênh được phép chạy Bot
+ +
+
+ + + + + + + + + + + + + @forelse($channels as $channel) + + + + + + + + + @empty + + + + @endforelse + +
+ + Tên KênhThread IDTrạng tháiNgày thêmHành động
+ + + {{ $channel->name }} + {{ $channel->thread_id }} + @if($channel->is_allowed) + Hoạt động + @else + Đang chặn + @endif + {{ $channel->created_at->format('H:i d/m/Y') }} + +
+ @csrf + @if($channel->is_allowed) + + @else + + @endif +
+ + +
+ @csrf + @method('DELETE') + +
+
Chưa cấu hình giới hạn kênh nào. Bot sẽ KHÔNG phản hồi trên nhóm chat nào!
+
+ @if($channels->hasPages()) + + @endif +
+ + +
+
+
Khám phá nhóm Zalo đã tham gia (Chưa kích hoạt)
+
+
+ + + + + + + + + + @forelse($discoveredGroups as $group) + + + + + + @empty + + + + @endforelse + +
Tên nhómThread IDHành động
+ {{ $group->name }} + {{ $group->group_id }} +
+ @csrf + + + +
+
+ Không có nhóm chưa kích hoạt nào. Bot sẽ tự động quét danh sách khi bạn kết nối Zalo. +
+
+ @if($discoveredGroups->hasPages()) + + @endif +
+
+
+ + +
+ @csrf + @method('DELETE') +
+
+ +@push('scripts') + +@endpush + +@endsection diff --git a/routes/api.php b/routes/api.php new file mode 100644 index 0000000..35bddb7 --- /dev/null +++ b/routes/api.php @@ -0,0 +1,14 @@ +comment(Inspiring::quote()); +})->purpose('Display an inspiring quote'); + +Schedule::command('app:cleanup-expired-links')->daily(); diff --git a/routes/web.php b/routes/web.php new file mode 100644 index 0000000..92b1ba3 --- /dev/null +++ b/routes/web.php @@ -0,0 +1,64 @@ +name('short_link.redirect'); + +// Public Link Generator +Route::get('/aff/taolink', [PublicConvertController::class, 'index'])->name('public_convert.index'); +Route::post('/aff/taolink', [PublicConvertController::class, 'process'])->middleware('throttle:10,1')->name('public_convert.process'); + +// Customer Lookup Portal +Route::get('/aff/tra-cuu', [CustomerLookupController::class, 'index'])->name('customer_lookup.index'); +Route::get('/aff/tra-cuu/search', [CustomerLookupController::class, 'search'])->name('customer_lookup.search'); + +// Root Redirect +Route::get('/', function () { + return redirect()->route('public_convert.index'); +}); + +// Backend Routes (prefix: aff/shp/admin) +Route::prefix('aff/shp/admin')->group(function () { + + // Auth Routes + Route::get('/login', [LoginController::class, 'showLoginForm'])->name('login'); + Route::post('/login', [LoginController::class, 'login']); + Route::post('/register-admin', [LoginController::class, 'registerAdmin'])->name('register.admin'); + Route::post('/logout', [LoginController::class, 'logout'])->name('logout'); + + // Protected Routes + Route::middleware(['auth'])->group(function () { + Route::get('/', [DashboardController::class, 'index'])->name('dashboard'); + + // History + Route::get('/history', [HistoryController::class, 'index'])->name('history.index'); + Route::delete('/history/bulk-destroy', [HistoryController::class, 'bulkDestroy'])->name('history.bulk_destroy'); + Route::delete('/history/{id}', [HistoryController::class, 'destroy'])->name('history.destroy'); + + // Settings + Route::get('/settings', [SettingController::class, 'index'])->name('settings.index'); + Route::post('/settings', [SettingController::class, 'update'])->name('settings.update'); + Route::post('/settings/zalo/start', [SettingController::class, 'startBot'])->name('settings.zalo.start'); + Route::post('/settings/zalo/stop', [SettingController::class, 'stopBot'])->name('settings.zalo.stop'); + Route::get('/settings/zalo/status-check', [SettingController::class, 'checkBotStatus'])->name('settings.zalo.status_check'); + + // Zalo Channels Manager + Route::get('/zalo-channels', [ZaloChannelController::class, 'index'])->name('zalo_channels.index'); + Route::post('/zalo-channels', [ZaloChannelController::class, 'store'])->name('zalo_channels.store'); + Route::post('/zalo-channels/{id}/toggle', [ZaloChannelController::class, 'toggle'])->name('zalo_channels.toggle'); + Route::post('/zalo-channels/quick-toggle', [ZaloChannelController::class, 'quickToggle'])->name('zalo_channels.quick_toggle'); + Route::delete('/zalo-channels/bulk-destroy', [ZaloChannelController::class, 'bulkDestroy'])->name('zalo_channels.bulk_destroy'); + Route::delete('/zalo-channels/{id}', [ZaloChannelController::class, 'destroy'])->name('zalo_channels.destroy'); + }); +}); + diff --git a/storage/app/.gitignore b/storage/app/.gitignore new file mode 100644 index 0000000..fedb287 --- /dev/null +++ b/storage/app/.gitignore @@ -0,0 +1,4 @@ +* +!private/ +!public/ +!.gitignore diff --git a/storage/app/private/.gitignore b/storage/app/private/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/app/private/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/app/public/.gitignore b/storage/app/public/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/app/public/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/.gitignore b/storage/framework/.gitignore new file mode 100644 index 0000000..05c4471 --- /dev/null +++ b/storage/framework/.gitignore @@ -0,0 +1,9 @@ +compiled.php +config.php +down +events.scanned.php +maintenance.php +routes.php +routes.scanned.php +schedule-* +services.json diff --git a/storage/framework/cache/.gitignore b/storage/framework/cache/.gitignore new file mode 100644 index 0000000..01e4a6c --- /dev/null +++ b/storage/framework/cache/.gitignore @@ -0,0 +1,3 @@ +* +!data/ +!.gitignore diff --git a/storage/framework/cache/data/.gitignore b/storage/framework/cache/data/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/cache/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/sessions/.gitignore b/storage/framework/sessions/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/sessions/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/testing/.gitignore b/storage/framework/testing/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/testing/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php new file mode 100644 index 0000000..8364a84 --- /dev/null +++ b/tests/Feature/ExampleTest.php @@ -0,0 +1,19 @@ +get('/'); + + $response->assertStatus(200); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..fe1ffc2 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } +} diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..f35b4e7 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite'; +import laravel from 'laravel-vite-plugin'; +import tailwindcss from '@tailwindcss/vite'; + +export default defineConfig({ + plugins: [ + laravel({ + input: ['resources/css/app.css', 'resources/js/app.js'], + refresh: true, + }), + tailwindcss(), + ], + server: { + watch: { + ignored: ['**/storage/framework/views/**'], + }, + }, +}); diff --git a/zalo-userbot/bot.log b/zalo-userbot/bot.log new file mode 100644 index 0000000..e69de29 diff --git a/zalo-userbot/bot.pid b/zalo-userbot/bot.pid new file mode 100644 index 0000000..de43e88 --- /dev/null +++ b/zalo-userbot/bot.pid @@ -0,0 +1 @@ +15988 \ No newline at end of file diff --git a/zalo-userbot/bot_err.log b/zalo-userbot/bot_err.log new file mode 100644 index 0000000..e69de29 diff --git a/zalo-userbot/package-lock.json b/zalo-userbot/package-lock.json new file mode 100644 index 0000000..223b2cc --- /dev/null +++ b/zalo-userbot/package-lock.json @@ -0,0 +1,477 @@ +{ + "name": "zalo-userbot", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "zalo-userbot", + "version": "1.0.0", + "dependencies": { + "node-fetch": "^3.3.2", + "zca-js": "^2.1.2" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/pako": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.2.0.tgz", + "integrity": "sha512-zJq6RP/5q+TO2OpFV3FHzlPnFjmkb7Nc99a5SNjJE+uu/PkpChs+NIZSSzbBoD+6kjiISXjfYdwj1ZRQ81dz/w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "(MIT AND Zlib)" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/spark-md5": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz", + "integrity": "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==", + "license": "(WTFPL OR MIT)" + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "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/zca-js": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/zca-js/-/zca-js-2.1.2.tgz", + "integrity": "sha512-82+zCqoIXnXEF6C9YuN3Kf7WKlyyujY/6Ejl2n8PkwazYkBK0k7kiPd8S7nHvC5Wl7vjwGRhDYeAM8zTHyoRxQ==", + "license": "MIT", + "dependencies": { + "crypto-js": "^4.2.0", + "form-data": "^4.0.4", + "json-bigint": "^1.0.0", + "pako": "^2.1.0", + "semver": "^7.6.3", + "spark-md5": "^3.0.2", + "tough-cookie": "^5.0.0", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18.0.0" + } + } + } +} diff --git a/zalo-userbot/package.json b/zalo-userbot/package.json new file mode 100644 index 0000000..f0ce2f2 --- /dev/null +++ b/zalo-userbot/package.json @@ -0,0 +1,14 @@ +{ + "name": "zalo-userbot", + "version": "1.0.0", + "description": "Zalo User-bot (Self-bot) for Shopee Affiliate Link conversion", + "main": "userbot.js", + "type": "module", + "scripts": { + "start": "node userbot.js" + }, + "dependencies": { + "zca-js": "^2.1.2", + "node-fetch": "^3.3.2" + } +} diff --git a/zalo-userbot/qr.png b/zalo-userbot/qr.png new file mode 100644 index 0000000000000000000000000000000000000000..a7d30b9f1d4fdb7ff82ebcc10dc48c5bb46af397 GIT binary patch literal 16609 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 Ltf|Sr@!9zAkPtsi literal 0 HcmV?d00001 diff --git a/zalo-userbot/userbot.js b/zalo-userbot/userbot.js new file mode 100644 index 0000000..fec6909 --- /dev/null +++ b/zalo-userbot/userbot.js @@ -0,0 +1,351 @@ +/** + * Zalo Personal User-bot (Self-bot) + * + * Simulates a real Zalo user account to read messages, detect Shopee links, + * call the Laravel backend to shorten/convert them, and post the reply. + */ + +import { Zalo, ThreadType } from "zca-js"; +import fetch from "node-fetch"; +import fs from "fs"; +import path from "path"; + +// Prevent crash when stdout/stderr pipes are broken (common when running in background) +process.stdout.on("error", (err) => { + if (err.code === "EPIPE") { + // Detached pipe, swallow the error + } +}); +process.stderr.on("error", (err) => { + if (err.code === "EPIPE") { + // Detached pipe, swallow the error + } +}); + +const BASE_URL = process.env.APP_URL + ? process.env.APP_URL.trim().replace(/^[\\'"\s]+|[\\'"\s]+$/g, "").replace(/\/$/, "") + : "http://127.0.0.1:8000"; +const LARAVEL_API_URL = `${BASE_URL}/api/zalo/process-link`; +const STATUS_API_URL = `${BASE_URL}/api/zalo/status`; +const SYNC_GROUPS_API_URL = `${BASE_URL}/api/zalo/sync-groups`; + +console.log("DEBUG: process.env.APP_URL =", JSON.stringify(process.env.APP_URL)); +console.log("DEBUG: resolved BASE_URL =", JSON.stringify(BASE_URL)); +console.log("DEBUG: resolved STATUS_API_URL =", JSON.stringify(STATUS_API_URL)); + +// Shopee link matching regex (matches links with or without https:// protocol) +const SHOPEE_REGEX = /(?:https?:\/\/)?(?:[a-zA-Z0-9-]+\.)?shopee\.vn\/[^\s]+|(?:https?:\/\/)?shp\.ee\/[^\s]+/gi; + +// Duplicate reply prevention (chatId_url -> timestamp) +const processedUrls = new Map(); + +/** + * Report connection status to Laravel backend. + */ +async function reportStatus(status, userName = "") { + try { + await fetch(STATUS_API_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + "ngrok-skip-browser-warning": "true" + }, + body: JSON.stringify({ + status: status, + user_name: userName + }) + }); + console.log(`[Status] Đã cập nhật trạng thái lên Laravel: ${status} ${userName ? `(${userName})` : ''}`); + } catch (err) { + console.error("[Status] Không thể gửi trạng thái tới Laravel (hãy chắc chắn server Laravel đang chạy):", err.message); + } +} + +/** + * Scan all joined groups and sync them to Laravel discovered pool. + */ +async function syncJoinedGroups(api) { + try { + console.log("-> Đang quét danh sách nhóm Zalo đã tham gia..."); + const groupsResponse = await api.getAllGroups(); + const groupIds = Object.keys(groupsResponse.gridVerMap || {}); + if (groupIds.length > 0) { + const groupInfoResponse = await api.getGroupInfo(groupIds); + const groups = Object.values(groupInfoResponse.gridInfoMap).map(g => ({ + id: g.groupId, + name: g.name + })); + + await fetch(SYNC_GROUPS_API_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + "ngrok-skip-browser-warning": "true" + }, + body: JSON.stringify({ + groups: groups + }) + }); + console.log(`-> Đã đồng bộ thành công ${groups.length} nhóm Zalo vào kho khám phá của Laravel.`); + } else { + console.log("-> Không tìm thấy nhóm Zalo nào đã tham gia."); + } + } catch (err) { + console.error("-> Lỗi quét/đồng bộ nhóm Zalo:", err.message); + } +} + +/** + * Clean up old QR images before a new scan. + */ +function cleanupQrFiles() { + try { + if (fs.existsSync("qr.png")) { + fs.unlinkSync("qr.png"); + } + if (fs.existsSync("../public/zalo/qr.png")) { + fs.unlinkSync("../public/zalo/qr.png"); + } + } catch (e) { + // ignore + } +} + +// Watcher/Timer to copy qr.png to Laravel public folder based on modification time +let lastMtime = 0; +setInterval(() => { + if (fs.existsSync("qr.png")) { + try { + const stats = fs.statSync("qr.png"); + const mtime = stats.mtimeMs; + + if (mtime !== lastMtime && stats.size > 0) { + // Ensure public directory exists + fs.mkdirSync("../public/zalo", { recursive: true }); + fs.copyFileSync("qr.png", "../public/zalo/qr.png"); + lastMtime = mtime; + console.log("-> Đã đồng bộ qr.png sang Laravel public/zalo/"); + } + } catch (e) { + console.error("-> Lỗi đồng bộ qr.png:", e.message); + } + } +}, 1000); + +async function startBot() { + console.log("=== KHỞI ĐỘNG ZALO USER-BOT AFFILIATE ==="); + console.log("Đang kết nối tới Zalo Web client..."); + + // Write current process PID to bot.pid file for Laravel management + try { + fs.writeFileSync("bot.pid", process.pid.toString()); + } catch (e) { + console.error("-> Không thể ghi file bot.pid:", e.message); + } + + cleanupQrFiles(); + + // Set status to waiting scan in Laravel UI + await reportStatus("waiting_scan"); + + const zalo = new Zalo(); + + try { + // This generates qr.png in current working directory + const api = await zalo.loginQR(); + + console.log("\n✅ Đăng nhập Zalo thành công!"); + + // Try to get self user profile name if possible + let selfName = ""; + try { + const accountInfo = await api.fetchAccountInfo(); + if (accountInfo && accountInfo.profile) { + selfName = accountInfo.profile.displayName || accountInfo.profile.zaloName || ""; + } + } catch(e) { + console.error("-> Lỗi lấy thông tin cá nhân:", e.message); + } + + await reportStatus("connected", selfName); + console.log("Bot đang hoạt động và nghe tin nhắn từ các nhóm & cá nhân..."); + + // Sync joined groups in background (discovered pool) + syncJoinedGroups(api).catch(err => { + console.error("-> Lỗi chạy ngầm syncJoinedGroups:", err); + }); + + // Setup message listener + api.listener.on("message", async (message) => { + console.log("\n[DEBUG Raw Message]:", JSON.stringify(message, null, 2)); + try { + let text = ""; + if (typeof message.data.content === "string") { + text = message.data.content; + } else if (message.data.content && typeof message.data.content === "object") { + text = (message.data.content.href || "") + " " + (message.data.content.title || "") + " " + (message.data.content.description || ""); + } + + if (!text) { + return; + } + + // Search for Shopee links + const matches = text.match(SHOPEE_REGEX); + if (!matches || matches.length === 0) { + return; + } + + // Get sender display name (Zalo Web API uses dName) + const senderName = message.data.dName + || message.data.sender?.name + || message.data.sender?.displayName + || "bạn"; + + // Resolve Chat/Group Name dynamically + let chatName = "Cuộc trò chuyện"; + if (message.type === ThreadType.Group) { + try { + const groupInfo = await api.getGroupInfo(message.threadId); + chatName = groupInfo?.gridInfoMap?.[message.threadId]?.name || `Nhóm ID: ${message.threadId}`; + } catch (err) { + chatName = `Nhóm ID: ${message.threadId}`; + } + } else { + chatName = `Chat riêng với ${senderName}`; + } + + console.log(`[Tin nhắn mới] Từ: ${senderName} (Kênh: ${chatName}, Thread ID: ${message.threadId})`); + + for (let matchedUrl of matches) { + // Normalize url (ensure it has https://) + if (!matchedUrl.toLowerCase().startsWith("http://") && !matchedUrl.toLowerCase().startsWith("https://")) { + matchedUrl = "https://" + matchedUrl; + } + + // Duplicate Prevention (5 second rule per URL per chat) + const cacheKey = `${message.threadId}_${matchedUrl}`; + const now = Date.now(); + if (processedUrls.has(cacheKey) && (now - processedUrls.get(cacheKey) < 5000)) { + console.log(`-> Bỏ qua link trùng lặp trong vòng 5s: ${matchedUrl}`); + continue; + } + processedUrls.set(cacheKey, now); + + // Clean up cache to prevent memory leak + if (processedUrls.size > 1000) { + for (const [key, value] of processedUrls.entries()) { + if (now - value > 10000) { + processedUrls.delete(key); + } + } + } + + console.log(`-> Tìm thấy link Shopee: ${matchedUrl}`); + + // Parse product title and thumbnail from Zalo preview data + let productTitle = ""; + let productImage = ""; + if (message.data.content && typeof message.data.content === "object") { + const content = message.data.content; + if (content.params) { + try { + const params = JSON.parse(content.params); + productTitle = params.mediaTitle || ""; + } catch (e) {} + } + if (!productTitle && content.description) { + let desc = content.description; + if (desc.startsWith("Mua ")) { + desc = desc.substring(4); + } + const index = desc.indexOf(" giá tốt"); + if (index !== -1) { + productTitle = desc.substring(0, index); + } else { + productTitle = desc; + } + } + productImage = content.thumb || ""; + } + + console.log(`-> Đang gọi Laravel API để convert link... (Tên sản phẩm: ${productTitle || 'Không tìm thấy'})`); + + const response = await fetch(LARAVEL_API_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept": "application/json", + "ngrok-skip-browser-warning": "true" + }, + body: JSON.stringify({ + url: matchedUrl, + sender_name: senderName, + thread_id: message.threadId, + chat_name: chatName, + product_title: productTitle, + product_image: productImage + }) + }); + + const result = await response.json(); + + if (result.success && result.reply_text) { + console.log(`-> Convert thành công! Đang gửi phản hồi vào chat Zalo...`); + + // Send the reply message back to the same chat as a reply (quote) + await api.sendMessage( + { + msg: result.reply_text, + quote: { + content: message.data.content, + msgType: message.data.msgType, + propertyExt: message.data.propertyExt, + uidFrom: message.data.uidFrom, + msgId: message.data.msgId, + cliMsgId: message.data.cliMsgId, + ts: message.data.ts, + ttl: message.data.ttl + } + }, + message.threadId, + message.type + ); + + console.log("-> Đã gửi phản hồi thành công.\n"); + } else { + console.error(`-> Lỗi từ Laravel API:`, result.error || "Không rõ lỗi"); + } + } + } catch (err) { + console.error("Lỗi khi xử lý tin nhắn cụ thể:", err); + } + }); + + // Start listening to WebSocket events + api.listener.start(); + + } catch (error) { + console.error("❌ Lỗi khởi động Zalo User-bot:", error); + await reportStatus("disconnected"); + console.log("Đang thử lại sau 10 giây..."); + setTimeout(startBot, 10000); + } +} + +// Handle exit signals to report disconnection to Laravel +process.on("SIGINT", async () => { + console.log("\nĐang dừng bot..."); + try { if (fs.existsSync("bot.pid")) fs.unlinkSync("bot.pid"); } catch(e){} + await reportStatus("disconnected"); + process.exit(); +}); + +process.on("SIGTERM", async () => { + console.log("\nĐang dừng bot..."); + try { if (fs.existsSync("bot.pid")) fs.unlinkSync("bot.pid"); } catch(e){} + await reportStatus("disconnected"); + process.exit(); +}); + +startBot();