diff --git a/README.md b/README.md index 8868bcea6..0a3ce0132 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # About the Project -Coolify is an open-source & self-hostable alternative to Heroku / Netlify / Vercel / etc. +Coolify is an open-source & self-hostable alternative to Heroku / Netlify / Vercel / etc. It helps you manage your servers, applications, and databases on your own hardware; you only need an SSH connection. You can manage VPS, Bare Metal, Raspberry PIs, and anything else. @@ -40,21 +40,20 @@ Special thanks to our biggest sponsors! ### Special Sponsors - + * [CCCareers](https://cccareers.org/) - A career development platform connecting coding bootcamp graduates with job opportunities in the tech industry. * [Hetzner](http://htznr.li/CoolifyXHetzner) - A German web hosting company offering affordable dedicated servers, cloud services, and web hosting solutions. * [Logto](https://logto.io/?ref=coolify) - An open-source authentication and authorization solution for building secure login systems and managing user identities. +* [Tolgee](https://tolgee.io/?ref=coolify) - Developer & translator friendly web-based localization platform. * [BC Direct](https://bc.direct/?ref=coolify.io) - A digital marketing agency specializing in e-commerce solutions and online business growth strategies. * [QuantCDN](https://www.quantcdn.io/?ref=coolify.io) - A content delivery network (CDN) optimizing website performance through global content distribution. * [Arcjet](https://arcjet.com/?ref=coolify.io) - A cloud-based platform providing real-time protection against API abuse and bot attacks. * [SupaGuide](https://supa.guide/?ref=coolify.io) - A comprehensive resource hub offering guides and tutorials for web development using Supabase. * [Tigris](https://tigrisdata.com/?ref=coolify.io) - A fully managed serverless object storage service compatible with Amazon S3 API. Offers high performance, scalability, and built-in search capabilities for efficient data management. -* [Fractal Networks](https://fractalnetworks.co/?ref=coolify.io) - A decentralized network infrastructure company focusing on secure and private communication solutions. * [Advin](https://coolify.ad.vin/?ref=coolify.io) - A digital advertising agency specializing in programmatic advertising and data-driven marketing strategies. * [Treive](https://trieve.ai/?ref=coolify.io) - An AI-powered search and discovery platform for enhancing information retrieval in large datasets. * [Blacksmith](https://blacksmith.sh/?ref=coolify.io) - A cloud-native platform for automating infrastructure provisioning and management across multiple cloud providers. -* [Latitude](https://latitude.sh/?ref=coolify.io) - A cloud computing platform offering bare metal servers and cloud instances for developers and businesses. * [Brand Dev](https://brand.dev/?ref=coolify.io) - A web development agency specializing in creating custom digital experiences and brand identities. * [Jobscollider](https://jobscollider.com/remote-jobs?ref=coolify.io) - A job search platform connecting professionals with remote work opportunities across various industries. * [Hostinger](https://www.hostinger.com/vps/coolify-hosting?ref=coolify.io) - A web hosting provider offering affordable hosting solutions, domain registration, and website building tools. @@ -63,6 +62,7 @@ Special thanks to our biggest sponsors! * [Juxtdigital](https://juxtdigital.dev/?ref=coolify.io) - A digital agency offering web development, design, and digital marketing services for businesses. * [Saasykit](https://saasykit.com/?ref=coolify.io) - A Laravel-based boilerplate providing essential components and features for building SaaS applications quickly. * [Massivegrid](https://massivegrid.com/?ref=coolify.io) - A cloud hosting provider offering scalable infrastructure solutions for businesses of all sizes. +* [LiquidWeb](https://liquidweb.com/?utm_source=coolify.io) - Fast web hosting provider. ## Github Sponsors ($40+) @@ -91,6 +91,11 @@ Special thanks to our biggest sponsors! + + + + + ## Organizations diff --git a/app/Actions/Application/StopApplication.php b/app/Actions/Application/StopApplication.php index cab7e45f0..642b4ba45 100644 --- a/app/Actions/Application/StopApplication.php +++ b/app/Actions/Application/StopApplication.php @@ -10,6 +10,8 @@ class StopApplication { use AsAction; + public string $jobQueue = 'high'; + public function handle(Application $application, bool $previewDeployments = false, bool $dockerCleanup = true) { try { diff --git a/app/Actions/CoolifyTask/PrepareCoolifyTask.php b/app/Actions/CoolifyTask/PrepareCoolifyTask.php index 6676b7937..3f76a2e3c 100644 --- a/app/Actions/CoolifyTask/PrepareCoolifyTask.php +++ b/app/Actions/CoolifyTask/PrepareCoolifyTask.php @@ -3,7 +3,6 @@ namespace App\Actions\CoolifyTask; use App\Data\CoolifyTaskArgs; -use App\Enums\ActivityTypes; use App\Jobs\CoolifyTask; use Spatie\Activitylog\Models\Activity; @@ -47,11 +46,7 @@ class PrepareCoolifyTask call_event_on_finish: $this->remoteProcessArgs->call_event_on_finish, call_event_data: $this->remoteProcessArgs->call_event_data, ); - if ($this->remoteProcessArgs->type === ActivityTypes::COMMAND->value) { - dispatch($job)->onQueue('high'); - } else { - dispatch($job); - } + dispatch($job); $this->activity->refresh(); return $this->activity; diff --git a/app/Actions/Database/StartDatabase.php b/app/Actions/Database/StartDatabase.php index 869a88521..e2fa6fc87 100644 --- a/app/Actions/Database/StartDatabase.php +++ b/app/Actions/Database/StartDatabase.php @@ -16,6 +16,8 @@ class StartDatabase { use AsAction; + public string $jobQueue = 'high'; + public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $database) { $server = $database->destination->server; @@ -49,7 +51,7 @@ class StartDatabase break; } if ($database->is_public && $database->public_port) { - StartDatabaseProxy::dispatch($database)->onQueue('high'); + StartDatabaseProxy::dispatch($database); } return $activity; diff --git a/app/Actions/Database/StartDatabaseProxy.php b/app/Actions/Database/StartDatabaseProxy.php index d7a3bc697..3ddf6c036 100644 --- a/app/Actions/Database/StartDatabaseProxy.php +++ b/app/Actions/Database/StartDatabaseProxy.php @@ -18,6 +18,8 @@ class StartDatabaseProxy { use AsAction; + public string $jobQueue = 'high'; + public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse|ServiceDatabase $database) { $internalPort = null; diff --git a/app/Actions/Database/StopDatabaseProxy.php b/app/Actions/Database/StopDatabaseProxy.php index 0a166d24a..9ee794351 100644 --- a/app/Actions/Database/StopDatabaseProxy.php +++ b/app/Actions/Database/StopDatabaseProxy.php @@ -18,6 +18,8 @@ class StopDatabaseProxy { use AsAction; + public string $jobQueue = 'high'; + public function handle(StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|ServiceDatabase|StandaloneDragonfly|StandaloneClickhouse $database) { $server = data_get($database, 'destination.server'); diff --git a/app/Actions/Docker/GetContainersStatus.php b/app/Actions/Docker/GetContainersStatus.php index a08056837..8aae910a9 100644 --- a/app/Actions/Docker/GetContainersStatus.php +++ b/app/Actions/Docker/GetContainersStatus.php @@ -7,7 +7,6 @@ use App\Actions\Shared\ComplexStatusCheck; use App\Models\ApplicationPreview; use App\Models\Server; use App\Models\ServiceDatabase; -use App\Notifications\Container\ContainerRestarted; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Lorisleiva\Actions\Concerns\AsAction; @@ -16,6 +15,8 @@ class GetContainersStatus { use AsAction; + public string $jobQueue = 'high'; + public $applications; public ?Collection $containers; diff --git a/app/Actions/Proxy/CheckProxy.php b/app/Actions/Proxy/CheckProxy.php index 51303d87a..6c8dd5234 100644 --- a/app/Actions/Proxy/CheckProxy.php +++ b/app/Actions/Proxy/CheckProxy.php @@ -30,7 +30,7 @@ class CheckProxy if (is_null($proxyType) || $proxyType === 'NONE' || $server->proxy->force_stop) { return false; } - ['uptime' => $uptime, 'error' => $error] = $server->validateConnection(false); + ['uptime' => $uptime, 'error' => $error] = $server->validateConnection(); if (! $uptime) { throw new \Exception($error); } diff --git a/app/Actions/Server/CleanupDocker.php b/app/Actions/Server/CleanupDocker.php index 1b8e6c9a6..0349ead89 100644 --- a/app/Actions/Server/CleanupDocker.php +++ b/app/Actions/Server/CleanupDocker.php @@ -9,6 +9,8 @@ class CleanupDocker { use AsAction; + public string $jobQueue = 'high'; + public function handle(Server $server) { $settings = instanceSettings(); diff --git a/app/Actions/Server/ServerCheck.php b/app/Actions/Server/ServerCheck.php index 1dae03fd9..5f9a1e357 100644 --- a/app/Actions/Server/ServerCheck.php +++ b/app/Actions/Server/ServerCheck.php @@ -130,10 +130,10 @@ class ServerCheck if ($foundLogDrainContainer) { $status = data_get($foundLogDrainContainer, 'State.Status'); if ($status !== 'running') { - StartLogDrain::dispatch($this->server)->onQueue('high'); + StartLogDrain::dispatch($this->server); } } else { - StartLogDrain::dispatch($this->server)->onQueue('high'); + StartLogDrain::dispatch($this->server); } } diff --git a/app/Actions/Server/StartLogDrain.php b/app/Actions/Server/StartLogDrain.php index 1997b58d6..0d28a0099 100644 --- a/app/Actions/Server/StartLogDrain.php +++ b/app/Actions/Server/StartLogDrain.php @@ -9,6 +9,8 @@ class StartLogDrain { use AsAction; + public string $jobQueue = 'high'; + public function handle(Server $server) { if ($server->settings->is_logdrain_newrelic_enabled) { diff --git a/app/Actions/Server/UpdateCoolify.php b/app/Actions/Server/UpdateCoolify.php index d57a4fe46..53c443778 100644 --- a/app/Actions/Server/UpdateCoolify.php +++ b/app/Actions/Server/UpdateCoolify.php @@ -29,7 +29,7 @@ class UpdateCoolify if (! $this->server) { return; } - CleanupDocker::dispatch($this->server)->onQueue('high'); + CleanupDocker::dispatch($this->server); $this->latestVersion = get_latest_version_of_coolify(); $this->currentVersion = config('version'); if (! $manual_update) { diff --git a/app/Actions/Server/ValidateServer.php b/app/Actions/Server/ValidateServer.php index d0a4cd6be..55b37a77c 100644 --- a/app/Actions/Server/ValidateServer.php +++ b/app/Actions/Server/ValidateServer.php @@ -9,6 +9,8 @@ class ValidateServer { use AsAction; + public string $jobQueue = 'high'; + public ?string $uptime = null; public ?string $error = null; diff --git a/app/Actions/Service/RestartService.php b/app/Actions/Service/RestartService.php index 1b6a5c32c..4151ea947 100644 --- a/app/Actions/Service/RestartService.php +++ b/app/Actions/Service/RestartService.php @@ -9,6 +9,8 @@ class RestartService { use AsAction; + public string $jobQueue = 'high'; + public function handle(Service $service) { StopService::run($service); diff --git a/app/Actions/Service/StartService.php b/app/Actions/Service/StartService.php index 82de066d7..1dfaf6c49 100644 --- a/app/Actions/Service/StartService.php +++ b/app/Actions/Service/StartService.php @@ -10,6 +10,8 @@ class StartService { use AsAction; + public string $jobQueue = 'high'; + public function handle(Service $service) { $service->saveComposeConfigs(); diff --git a/app/Actions/Service/StopService.php b/app/Actions/Service/StopService.php index 046d94ced..95b08b437 100644 --- a/app/Actions/Service/StopService.php +++ b/app/Actions/Service/StopService.php @@ -10,6 +10,8 @@ class StopService { use AsAction; + public string $jobQueue = 'high'; + public function handle(Service $service, bool $isDeleteOperation = false, bool $dockerCleanup = true) { try { diff --git a/app/Console/Commands/CleanupRedis.php b/app/Console/Commands/CleanupRedis.php index 5fc2b4e61..e16a82be4 100644 --- a/app/Console/Commands/CleanupRedis.php +++ b/app/Console/Commands/CleanupRedis.php @@ -13,7 +13,6 @@ class CleanupRedis extends Command public function handle() { - echo "Cleanup Redis keys.\n"; $prefix = config('database.redis.options.prefix'); $keys = Redis::connection()->keys('*:laravel*'); diff --git a/app/Console/Commands/CleanupStuckedResources.php b/app/Console/Commands/CleanupStuckedResources.php index 9d36ce9b8..def3d5a2c 100644 --- a/app/Console/Commands/CleanupStuckedResources.php +++ b/app/Console/Commands/CleanupStuckedResources.php @@ -30,7 +30,6 @@ class CleanupStuckedResources extends Command public function handle() { - echo "Running cleanup stucked resources.\n"; $this->cleanup_stucked_resources(); } diff --git a/app/Console/Commands/Horizon.php b/app/Console/Commands/Horizon.php index 8ae165c59..655729ec9 100644 --- a/app/Console/Commands/Horizon.php +++ b/app/Console/Commands/Horizon.php @@ -13,7 +13,7 @@ class Horizon extends Command public function handle() { if (config('constants.horizon.is_horizon_enabled')) { - $this->info('Horizon is enabled. Starting.'); + $this->info('[x]: Horizon is enabled. Starting.'); $this->call('horizon'); exit(0); } else { diff --git a/app/Console/Commands/Init.php b/app/Console/Commands/Init.php index bbf1dc093..57bbe896b 100644 --- a/app/Console/Commands/Init.php +++ b/app/Console/Commands/Init.php @@ -2,9 +2,9 @@ namespace App\Console\Commands; -use App\Actions\Server\StopSentinel; use App\Enums\ActivityTypes; use App\Enums\ApplicationDeploymentStatus; +use App\Jobs\CheckHelperImageJob; use App\Models\ApplicationDeploymentQueue; use App\Models\Environment; use App\Models\ScheduledDatabaseBackup; @@ -12,6 +12,7 @@ use App\Models\Server; use App\Models\StandalonePostgresql; use App\Models\User; use Illuminate\Console\Command; +use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Http; @@ -25,6 +26,8 @@ class Init extends Command public function handle() { + $this->optimize(); + if (isCloud() && ! $this->option('force-cloud')) { echo "Skipping init as we are on cloud and --force-cloud option is not set\n"; @@ -39,7 +42,6 @@ class Init extends Command } // Backward compatibility - // $this->disable_metrics(); $this->replace_slash_in_environment_name(); $this->restore_coolify_db_backup(); $this->update_user_emails(); @@ -53,9 +55,18 @@ class Init extends Command } else { $this->cleanup_in_progress_application_deployments(); } + echo "[3]: Cleanup Redis keys.\n"; $this->call('cleanup:redis'); + + echo "[4]: Cleanup stucked resources.\n"; $this->call('cleanup:stucked-resources'); + try { + $this->pullHelperImage(); + } catch (\Throwable $e) { + // + } + if (isCloud()) { try { $this->pullTemplatesFromCDN(); @@ -87,6 +98,11 @@ class Init extends Command } } + private function pullHelperImage() + { + CheckHelperImageJob::dispatch(); + } + private function pullTemplatesFromCDN() { $response = Http::retry(3, 1000)->get(config('constants.services.official')); @@ -95,19 +111,13 @@ class Init extends Command File::put(base_path('templates/service-templates.json'), json_encode($services)); } } - // private function disable_metrics() - // { - // if (version_compare('4.0.0-beta.312', config('version'), '<=')) { - // foreach ($this->servers as $server) { - // if ($server->settings->is_metrics_enabled === true) { - // $server->settings->update(['is_metrics_enabled' => false]); - // } - // if ($server->isFunctional()) { - // StopSentinel::dispatch($server)->onQueue('high'); - // } - // } - // } - // } + + private function optimize() + { + echo "[1]: Optimizing Laravel (caching config, routes, views).\n"; + Artisan::call('optimize:clear'); + Artisan::call('optimize'); + } private function update_user_emails() { @@ -222,15 +232,15 @@ class Init extends Command $settings = instanceSettings(); $do_not_track = data_get($settings, 'do_not_track'); if ($do_not_track == true) { - echo "Skipping alive as do_not_track is enabled\n"; + echo "[2]: Skipping sending live signal as do_not_track is enabled\n"; return; } try { Http::get("https://undead.coolify.io/v4/alive?appId=$id&version=$version"); - echo "I am alive!\n"; + echo "[2]: Sending live signal!\n"; } catch (\Throwable $e) { - echo "Error in alive: {$e->getMessage()}\n"; + echo "[2]: Error in sending live signal: {$e->getMessage()}\n"; } } diff --git a/app/Console/Commands/Scheduler.php b/app/Console/Commands/Scheduler.php index 9b6ca5324..9ee7b06e6 100644 --- a/app/Console/Commands/Scheduler.php +++ b/app/Console/Commands/Scheduler.php @@ -13,7 +13,7 @@ class Scheduler extends Command public function handle() { if (config('constants.horizon.is_scheduler_enabled')) { - $this->info('Scheduler is enabled. Starting.'); + $this->info('[x]: Scheduler is enabled. Starting.'); $this->call('schedule:work'); exit(0); } else { diff --git a/app/Console/Commands/ServicesDelete.php b/app/Console/Commands/ServicesDelete.php index 1e5d5808c..b5a74166a 100644 --- a/app/Console/Commands/ServicesDelete.php +++ b/app/Console/Commands/ServicesDelete.php @@ -96,7 +96,7 @@ class ServicesDelete extends Command if (! $confirmed) { break; } - DeleteResourceJob::dispatch($toDelete)->onQueue('high'); + DeleteResourceJob::dispatch($toDelete); } } } @@ -122,7 +122,7 @@ class ServicesDelete extends Command if (! $confirmed) { return; } - DeleteResourceJob::dispatch($toDelete)->onQueue('high'); + DeleteResourceJob::dispatch($toDelete); } } } @@ -148,7 +148,7 @@ class ServicesDelete extends Command if (! $confirmed) { return; } - DeleteResourceJob::dispatch($toDelete)->onQueue('high'); + DeleteResourceJob::dispatch($toDelete); } } } diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index e113dbe9a..832dcf58b 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -50,7 +50,7 @@ class Kernel extends ConsoleKernel $this->instanceTimezone = config('app.timezone'); } - $this->scheduleInstance->job(new CleanupStaleMultiplexedConnections)->hourly(); + // $this->scheduleInstance->job(new CleanupStaleMultiplexedConnections)->hourly(); if (isDev()) { // Instance Jobs @@ -154,7 +154,7 @@ class Kernel extends ConsoleKernel } // Cleanup multiplexed connections every hour - $this->scheduleInstance->job(new ServerCleanupMux($server))->hourly()->onOneServer(); + // $this->scheduleInstance->job(new ServerCleanupMux($server))->hourly()->onOneServer(); // Temporary solution until we have better memory management for Sentinel if ($server->isSentinelEnabled()) { diff --git a/app/Helpers/SshMultiplexingHelper.php b/app/Helpers/SshMultiplexingHelper.php index 0e840c3ce..8da476b9e 100644 --- a/app/Helpers/SshMultiplexingHelper.php +++ b/app/Helpers/SshMultiplexingHelper.php @@ -21,17 +21,14 @@ class SshMultiplexingHelper ]; } - public static function ensureMultiplexedConnection(Server $server) + public static function ensureMultiplexedConnection(Server $server): bool { if (! self::isMultiplexingEnabled()) { - return; + return false; } $sshConfig = self::serverSshConfiguration($server); $muxSocket = $sshConfig['muxFilename']; - $sshKeyLocation = $sshConfig['sshKeyLocation']; - - self::validateSshKey($sshKeyLocation); $checkCommand = "ssh -O check -o ControlPath=$muxSocket "; if (data_get($server, 'settings.is_cloudflare_tunnel')) { @@ -41,16 +38,17 @@ class SshMultiplexingHelper $process = Process::run($checkCommand); if ($process->exitCode() !== 0) { - self::establishNewMultiplexedConnection($server); + return self::establishNewMultiplexedConnection($server); } + + return true; } - public static function establishNewMultiplexedConnection(Server $server) + public static function establishNewMultiplexedConnection(Server $server): bool { $sshConfig = self::serverSshConfiguration($server); $sshKeyLocation = $sshConfig['sshKeyLocation']; $muxSocket = $sshConfig['muxFilename']; - $connectionTimeout = config('constants.ssh.connection_timeout'); $serverInterval = config('constants.ssh.server_interval'); $muxPersistTime = config('constants.ssh.mux_persist_time'); @@ -60,15 +58,14 @@ class SshMultiplexingHelper if (data_get($server, 'settings.is_cloudflare_tunnel')) { $establishCommand .= ' -o ProxyCommand="cloudflared access ssh --hostname %h" '; } - $establishCommand .= self::getCommonSshOptions($server, $sshKeyLocation, $connectionTimeout, $serverInterval); $establishCommand .= "{$server->user}@{$server->ip}"; - $establishProcess = Process::run($establishCommand); - if ($establishProcess->exitCode() !== 0) { - throw new \RuntimeException('Failed to establish multiplexed connection: '.$establishProcess->errorOutput()); + return false; } + + return true; } public static function removeMuxFile(Server $server) @@ -97,9 +94,8 @@ class SshMultiplexingHelper if ($server->isIpv6()) { $scp_command .= '-6 '; } - if (self::isMultiplexingEnabled()) { + if (self::isMultiplexingEnabled() && self::ensureMultiplexedConnection($server)) { $scp_command .= "-o ControlMaster=auto -o ControlPath=$muxSocket -o ControlPersist={$muxPersistTime} "; - self::ensureMultiplexedConnection($server); } if (data_get($server, 'settings.is_cloudflare_tunnel')) { @@ -120,6 +116,9 @@ class SshMultiplexingHelper $sshConfig = self::serverSshConfiguration($server); $sshKeyLocation = $sshConfig['sshKeyLocation']; + + self::validateSshKey($server->privateKey); + $muxSocket = $sshConfig['muxFilename']; $timeout = config('constants.ssh.command_timeout'); @@ -127,9 +126,8 @@ class SshMultiplexingHelper $ssh_command = "timeout $timeout ssh "; - if (self::isMultiplexingEnabled()) { + if (self::isMultiplexingEnabled() && self::ensureMultiplexedConnection($server)) { $ssh_command .= "-o ControlMaster=auto -o ControlPath=$muxSocket -o ControlPersist={$muxPersistTime} "; - self::ensureMultiplexedConnection($server); } if (data_get($server, 'settings.is_cloudflare_tunnel')) { @@ -154,13 +152,14 @@ class SshMultiplexingHelper return config('constants.ssh.mux_enabled') && ! config('constants.coolify.is_windows_docker_desktop'); } - private static function validateSshKey(string $sshKeyLocation): void + private static function validateSshKey(PrivateKey $privateKey): void { - $checkKeyCommand = "ls $sshKeyLocation 2>/dev/null"; + $keyLocation = $privateKey->getKeyLocation(); + $checkKeyCommand = "ls $keyLocation 2>/dev/null"; $keyCheckProcess = Process::run($checkKeyCommand); if ($keyCheckProcess->exitCode() !== 0) { - throw new \RuntimeException("SSH key file not accessible: $sshKeyLocation"); + $privateKey->storeInFileSystem(); } } diff --git a/app/Http/Controllers/Api/ApplicationsController.php b/app/Http/Controllers/Api/ApplicationsController.php index 500db3922..c69640970 100644 --- a/app/Http/Controllers/Api/ApplicationsController.php +++ b/app/Http/Controllers/Api/ApplicationsController.php @@ -1224,7 +1224,7 @@ class ApplicationsController extends Controller $service->name = "service-$service->uuid"; $service->parse(isNew: true); if ($instantDeploy) { - StartService::dispatch($service)->onQueue('high'); + StartService::dispatch($service); } return response()->json(serializeApiResponse([ @@ -1379,7 +1379,7 @@ class ApplicationsController extends Controller deleteVolumes: $request->query->get('delete_volumes', true), dockerCleanup: $request->query->get('docker_cleanup', true), deleteConnectedNetworks: $request->query->get('delete_connected_networks', true) - )->onQueue('high'); + ); return response()->json([ 'message' => 'Application deletion request queued.', @@ -2523,7 +2523,7 @@ class ApplicationsController extends Controller if (! $application) { return response()->json(['message' => 'Application not found.'], 404); } - StopApplication::dispatch($application)->onQueue('high'); + StopApplication::dispatch($application); return response()->json( [ diff --git a/app/Http/Controllers/Api/DatabasesController.php b/app/Http/Controllers/Api/DatabasesController.php index eaa542a83..ce658d2a2 100644 --- a/app/Http/Controllers/Api/DatabasesController.php +++ b/app/Http/Controllers/Api/DatabasesController.php @@ -497,9 +497,9 @@ class DatabasesController extends Controller $database->update($request->all()); if ($whatToDoWithDatabaseProxy === 'start') { - StartDatabaseProxy::dispatch($database)->onQueue('high'); + StartDatabaseProxy::dispatch($database); } elseif ($whatToDoWithDatabaseProxy === 'stop') { - StopDatabaseProxy::dispatch($database)->onQueue('high'); + StopDatabaseProxy::dispatch($database); } return response()->json([ @@ -1151,7 +1151,7 @@ class DatabasesController extends Controller } $database = create_standalone_postgresql($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); $payload = [ @@ -1206,7 +1206,7 @@ class DatabasesController extends Controller } $database = create_standalone_mariadb($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1264,7 +1264,7 @@ class DatabasesController extends Controller } $database = create_standalone_mysql($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1320,7 +1320,7 @@ class DatabasesController extends Controller } $database = create_standalone_redis($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1357,7 +1357,7 @@ class DatabasesController extends Controller removeUnnecessaryFieldsFromRequest($request); $database = create_standalone_dragonfly($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } return response()->json(serializeApiResponse([ @@ -1406,7 +1406,7 @@ class DatabasesController extends Controller } $database = create_standalone_keydb($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1442,7 +1442,7 @@ class DatabasesController extends Controller removeUnnecessaryFieldsFromRequest($request); $database = create_standalone_clickhouse($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1500,7 +1500,7 @@ class DatabasesController extends Controller } $database = create_standalone_mongodb($environment->id, $destination->uuid, $request->all()); if ($instantDeploy) { - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); } $database->refresh(); @@ -1593,7 +1593,7 @@ class DatabasesController extends Controller deleteVolumes: $request->query->get('delete_volumes', true), dockerCleanup: $request->query->get('docker_cleanup', true), deleteConnectedNetworks: $request->query->get('delete_connected_networks', true) - )->onQueue('high'); + ); return response()->json([ 'message' => 'Database deletion request queued.', @@ -1666,7 +1666,7 @@ class DatabasesController extends Controller if (str($database->status)->contains('running')) { return response()->json(['message' => 'Database is already running.'], 400); } - StartDatabase::dispatch($database)->onQueue('high'); + StartDatabase::dispatch($database); return response()->json( [ @@ -1742,7 +1742,7 @@ class DatabasesController extends Controller if (str($database->status)->contains('stopped') || str($database->status)->contains('exited')) { return response()->json(['message' => 'Database is already stopped.'], 400); } - StopDatabase::dispatch($database)->onQueue('high'); + StopDatabase::dispatch($database); return response()->json( [ @@ -1815,7 +1815,7 @@ class DatabasesController extends Controller if (! $database) { return response()->json(['message' => 'Database not found.'], 404); } - RestartDatabase::dispatch($database)->onQueue('high'); + RestartDatabase::dispatch($database); return response()->json( [ diff --git a/app/Http/Controllers/Api/DeployController.php b/app/Http/Controllers/Api/DeployController.php index 59b199d87..666dc55a5 100644 --- a/app/Http/Controllers/Api/DeployController.php +++ b/app/Http/Controllers/Api/DeployController.php @@ -307,7 +307,7 @@ class DeployController extends Controller break; default: // Database resource - StartDatabase::dispatch($resource)->onQueue('high'); + StartDatabase::dispatch($resource); $resource->update([ 'started_at' => now(), ]); diff --git a/app/Http/Controllers/Api/ServersController.php b/app/Http/Controllers/Api/ServersController.php index cbee00642..3f0f4d2c3 100644 --- a/app/Http/Controllers/Api/ServersController.php +++ b/app/Http/Controllers/Api/ServersController.php @@ -550,7 +550,7 @@ class ServersController extends Controller 'is_build_server' => $request->is_build_server, ]); if ($request->instant_validate) { - ValidateServer::dispatch($server)->onQueue('high'); + ValidateServer::dispatch($server); } return response()->json([ @@ -675,7 +675,7 @@ class ServersController extends Controller ]); } if ($request->instant_validate) { - ValidateServer::dispatch($server)->onQueue('high'); + ValidateServer::dispatch($server); } return response()->json([ @@ -813,7 +813,7 @@ class ServersController extends Controller if (! $server) { return response()->json(['message' => 'Server not found.'], 404); } - ValidateServer::dispatch($server)->onQueue('high'); + ValidateServer::dispatch($server); return response()->json(['message' => 'Validation started.']); } diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php index bdb5612ad..bf90322e2 100644 --- a/app/Http/Controllers/Api/ServicesController.php +++ b/app/Http/Controllers/Api/ServicesController.php @@ -342,7 +342,7 @@ class ServicesController extends Controller } $service->parse(isNew: true); if ($instantDeploy) { - StartService::dispatch($service)->onQueue('high'); + StartService::dispatch($service); } $domains = $service->applications()->get()->pluck('fqdn')->sort(); $domains = $domains->map(function ($domain) { @@ -487,7 +487,7 @@ class ServicesController extends Controller deleteVolumes: $request->query->get('delete_volumes', true), dockerCleanup: $request->query->get('docker_cleanup', true), deleteConnectedNetworks: $request->query->get('delete_connected_networks', true) - )->onQueue('high'); + ); return response()->json([ 'message' => 'Service deletion request queued.', @@ -1076,7 +1076,7 @@ class ServicesController extends Controller if (str($service->status())->contains('running')) { return response()->json(['message' => 'Service is already running.'], 400); } - StartService::dispatch($service)->onQueue('high'); + StartService::dispatch($service); return response()->json( [ @@ -1154,7 +1154,7 @@ class ServicesController extends Controller if (str($service->status())->contains('stopped') || str($service->status())->contains('exited')) { return response()->json(['message' => 'Service is already stopped.'], 400); } - StopService::dispatch($service)->onQueue('high'); + StopService::dispatch($service); return response()->json( [ @@ -1229,7 +1229,7 @@ class ServicesController extends Controller if (! $service) { return response()->json(['message' => 'Service not found.'], 404); } - RestartService::dispatch($service)->onQueue('high'); + RestartService::dispatch($service); return response()->json( [ diff --git a/app/Http/Controllers/Webhook/Stripe.php b/app/Http/Controllers/Webhook/Stripe.php index e94209b23..83ba16699 100644 --- a/app/Http/Controllers/Webhook/Stripe.php +++ b/app/Http/Controllers/Webhook/Stripe.php @@ -3,21 +3,26 @@ namespace App\Http\Controllers\Webhook; use App\Http\Controllers\Controller; -use App\Jobs\ServerLimitCheckJob; -use App\Jobs\SubscriptionInvoiceFailedJob; -use App\Models\Subscription; -use App\Models\Team; +use App\Jobs\StripeProcessJob; use App\Models\Webhook; use Exception; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; -use Illuminate\Support\Str; class Stripe extends Controller { + protected $webhook; + public function events(Request $request) { try { + $webhookSecret = config('subscription.stripe_webhook_secret'); + $signature = $request->header('Stripe-Signature'); + $event = \Stripe\Webhook::constructEvent( + $request->getContent(), + $signature, + $webhookSecret + ); if (app()->isDownForMaintenance()) { $epoch = now()->valueOf(); $data = [ @@ -33,241 +38,17 @@ class Stripe extends Controller $json = json_encode($data); Storage::disk('webhooks-during-maintenance')->put("{$epoch}_Stripe::events_stripe", $json); - return; + return response('Webhook received. Cool cool cool cool cool.', 200); } - $webhookSecret = config('subscription.stripe_webhook_secret'); - $signature = $request->header('Stripe-Signature'); - $excludedPlans = config('subscription.stripe_excluded_plans'); - $event = \Stripe\Webhook::constructEvent( - $request->getContent(), - $signature, - $webhookSecret - ); - $webhook = Webhook::create([ + $this->webhook = Webhook::create([ 'type' => 'stripe', 'payload' => $request->getContent(), ]); - $type = data_get($event, 'type'); - $data = data_get($event, 'data.object'); - switch ($type) { - case 'radar.early_fraud_warning.created': - $stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key')); - $id = data_get($data, 'id'); - $charge = data_get($data, 'charge'); - if ($charge) { - $stripe->refunds->create(['charge' => $charge]); - } - $pi = data_get($data, 'payment_intent'); - $piData = $stripe->paymentIntents->retrieve($pi, []); - $customerId = data_get($piData, 'customer'); - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if ($subscription) { - $subscriptionId = data_get($subscription, 'stripe_subscription_id'); - $stripe->subscriptions->cancel($subscriptionId, []); - $subscription->update([ - 'stripe_invoice_paid' => false, - ]); - send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}"); - } else { - send_internal_notification("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}"); + StripeProcessJob::dispatch($event); - return response("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}", 400); - } - break; - case 'checkout.session.completed': - $clientReferenceId = data_get($data, 'client_reference_id'); - if (is_null($clientReferenceId)) { - send_internal_notification('Checkout session completed without client reference id.'); - break; - } - $userId = Str::before($clientReferenceId, ':'); - $teamId = Str::after($clientReferenceId, ':'); - $subscriptionId = data_get($data, 'subscription'); - $customerId = data_get($data, 'customer'); - $team = Team::find($teamId); - $found = $team->members->where('id', $userId)->first(); - if (! $found->isAdmin()) { - send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); - - return response("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}.", 400); - } - $subscription = Subscription::where('team_id', $teamId)->first(); - if ($subscription) { - // send_internal_notification('Old subscription activated for team: '.$teamId); - $subscription->update([ - 'stripe_subscription_id' => $subscriptionId, - 'stripe_customer_id' => $customerId, - 'stripe_invoice_paid' => true, - ]); - } else { - // send_internal_notification('New subscription for team: '.$teamId); - Subscription::create([ - 'team_id' => $teamId, - 'stripe_subscription_id' => $subscriptionId, - 'stripe_customer_id' => $customerId, - 'stripe_invoice_paid' => true, - ]); - } - break; - case 'invoice.paid': - $customerId = data_get($data, 'customer'); - $planId = data_get($data, 'lines.data.0.plan.id'); - if (Str::contains($excludedPlans, $planId)) { - // send_internal_notification('Subscription excluded.'); - break; - } - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if ($subscription) { - $subscription->update([ - 'stripe_invoice_paid' => true, - ]); - } else { - return response("No subscription found for customer: {$customerId}", 400); - } - break; - case 'invoice.payment_failed': - $customerId = data_get($data, 'customer'); - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - // send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: '.$customerId); - - return response('No subscription found in Coolify.'); - } - $team = data_get($subscription, 'team'); - if (! $team) { - // send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: '.$customerId); - - return response('No team found in Coolify.'); - } - if (! $subscription->stripe_invoice_paid) { - SubscriptionInvoiceFailedJob::dispatch($team); - // send_internal_notification('Invoice payment failed: '.$customerId); - } else { - // send_internal_notification('Invoice payment failed but already paid: '.$customerId); - } - break; - case 'payment_intent.payment_failed': - $customerId = data_get($data, 'customer'); - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - // send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: '.$customerId); - - return response('No subscription found in Coolify.'); - } - if ($subscription->stripe_invoice_paid) { - // send_internal_notification('payment_intent.payment_failed but invoice is active for customer: '.$customerId); - - return; - } - send_internal_notification('Subscription payment failed for customer: '.$customerId); - break; - case 'customer.subscription.created': - $customerId = data_get($data, 'customer'); - $subscriptionId = data_get($data, 'id'); - $teamId = data_get($data, 'metadata.team_id'); - $userId = data_get($data, 'metadata.user_id'); - if (! $teamId || ! $userId) { - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if ($subscription) { - return response("Subscription already exists for customer: {$customerId}", 200); - } - - return response('No team id or user id found', 400); - } - $team = Team::find($teamId); - $found = $team->members->where('id', $userId)->first(); - if (! $found->isAdmin()) { - send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}."); - - return response("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}.", 400); - } - $subscription = Subscription::where('team_id', $teamId)->first(); - if ($subscription) { - return response("Subscription already exists for team: {$teamId}", 200); - } else { - Subscription::create([ - 'team_id' => $teamId, - 'stripe_subscription_id' => $subscriptionId, - 'stripe_customer_id' => $customerId, - 'stripe_invoice_paid' => false, - ]); - - return response('Subscription created'); - } - case 'customer.subscription.updated': - $teamId = data_get($data, 'metadata.team_id'); - $userId = data_get($data, 'metadata.user_id'); - $customerId = data_get($data, 'customer'); - $status = data_get($data, 'status'); - $subscriptionId = data_get($data, 'items.data.0.subscription'); - $planId = data_get($data, 'items.data.0.plan.id'); - if (Str::contains($excludedPlans, $planId)) { - // send_internal_notification('Subscription excluded.'); - break; - } - $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); - if (! $subscription) { - if ($status === 'incomplete_expired') { - return response('Subscription incomplete expired', 200); - } - if ($teamId) { - $subscription = Subscription::create([ - 'team_id' => $teamId, - 'stripe_subscription_id' => $subscriptionId, - 'stripe_customer_id' => $customerId, - 'stripe_invoice_paid' => false, - ]); - } else { - return response('No subscription and team id found', 400); - } - } - $cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end'); - $feedback = data_get($data, 'cancellation_details.feedback'); - $comment = data_get($data, 'cancellation_details.comment'); - $lookup_key = data_get($data, 'items.data.0.price.lookup_key'); - if (str($lookup_key)->contains('dynamic')) { - $quantity = data_get($data, 'items.data.0.quantity', 2); - $team = data_get($subscription, 'team'); - if ($team) { - $team->update([ - 'custom_server_limit' => $quantity, - ]); - } - ServerLimitCheckJob::dispatch($team); - } - $subscription->update([ - 'stripe_feedback' => $feedback, - 'stripe_comment' => $comment, - 'stripe_plan_id' => $planId, - 'stripe_cancel_at_period_end' => $cancelAtPeriodEnd, - ]); - if ($status === 'paused' || $status === 'incomplete_expired') { - $subscription->update([ - 'stripe_invoice_paid' => false, - ]); - } - if ($feedback) { - $reason = "Cancellation feedback for {$customerId}: '".$feedback."'"; - if ($comment) { - $reason .= ' with comment: \''.$comment."'"; - } - } - break; - case 'customer.subscription.deleted': - // End subscription - $customerId = data_get($data, 'customer'); - $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); - $team = data_get($subscription, 'team'); - $team?->subscriptionEnded(); - break; - default: - // Unhandled event type - } + return response('Webhook received. Cool cool cool cool cool.', 200); } catch (Exception $e) { - if ($type !== 'payment_intent.payment_failed') { - send_internal_notification("Subscription webhook ($type) failed: ".$e->getMessage()); - } - $webhook->update([ + $this->webhook->update([ 'status' => 'failed', 'failure_reason' => $e->getMessage(), ]); diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index cd89f55f3..270243eaf 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -166,6 +166,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue public function __construct(int $application_deployment_queue_id) { + $this->onQueue('high'); + $this->application_deployment_queue = ApplicationDeploymentQueue::find($application_deployment_queue_id); $this->application = Application::find($this->application_deployment_queue->application_id); $this->build_pack = data_get($this->application, 'build_pack'); @@ -349,8 +351,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue private function post_deployment() { if ($this->server->isProxyShouldRun()) { - GetContainersStatus::dispatch($this->server)->onQueue('high'); - // dispatch(new ContainerStatusJob($this->server)); + GetContainersStatus::dispatch($this->server); } $this->next(ApplicationDeploymentStatus::FINISHED->value); if ($this->pull_request_id !== 0) { diff --git a/app/Jobs/ApplicationPullRequestUpdateJob.php b/app/Jobs/ApplicationPullRequestUpdateJob.php index 2eefc4dd2..ef8e6efb6 100755 --- a/app/Jobs/ApplicationPullRequestUpdateJob.php +++ b/app/Jobs/ApplicationPullRequestUpdateJob.php @@ -25,7 +25,9 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue public ApplicationPreview $preview, public ProcessStatus $status, public ?string $deployment_uuid = null - ) {} + ) { + $this->onQueue('high'); + } public function handle() { diff --git a/app/Jobs/CoolifyTask.php b/app/Jobs/CoolifyTask.php index c3692c30b..49a5ba8dd 100755 --- a/app/Jobs/CoolifyTask.php +++ b/app/Jobs/CoolifyTask.php @@ -23,7 +23,10 @@ class CoolifyTask implements ShouldBeEncrypted, ShouldQueue public bool $ignore_errors, public $call_event_on_finish, public $call_event_data, - ) {} + ) { + + $this->onQueue('high'); + } /** * Execute the job. diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php index 94f185882..d213959e4 100644 --- a/app/Jobs/DatabaseBackupJob.php +++ b/app/Jobs/DatabaseBackupJob.php @@ -60,6 +60,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue public function __construct($backup) { + $this->onQueue('high'); $this->backup = $backup; } @@ -197,8 +198,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue $databaseType = $this->database->type(); $databasesToBackup = data_get($this->backup, 'databases_to_backup'); } - - if (is_null($databasesToBackup)) { + if (blank($databasesToBackup)) { if (str($databaseType)->contains('postgres')) { $databasesToBackup = [$this->database->postgres_db]; } elseif (str($databaseType)->contains('mongodb')) { @@ -319,12 +319,10 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue 'filename' => null, ]); } - send_internal_notification('DatabaseBackupJob failed with: '.$e->getMessage()); $this->team?->notify(new BackupFailed($this->backup, $this->database, $this->backup_output, $database)); } } } catch (\Throwable $e) { - send_internal_notification('DatabaseBackupJob failed with: '.$e->getMessage()); throw $e; } finally { if ($this->team) { diff --git a/app/Jobs/DeleteResourceJob.php b/app/Jobs/DeleteResourceJob.php index 2442d5b06..8b9228e5f 100644 --- a/app/Jobs/DeleteResourceJob.php +++ b/app/Jobs/DeleteResourceJob.php @@ -35,7 +35,9 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue public bool $deleteVolumes = true, public bool $dockerCleanup = true, public bool $deleteConnectedNetworks = true - ) {} + ) { + $this->onQueue('high'); + } public function handle() { @@ -87,7 +89,6 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue $this->resource?->delete_connected_networks($this->resource->uuid); } } catch (\Throwable $e) { - send_internal_notification('ContainerStoppingJob failed with: '.$e->getMessage()); throw $e; } finally { $this->resource->forceDelete(); diff --git a/app/Jobs/PullHelperImageJob.php b/app/Jobs/PullHelperImageJob.php index cfc0c5a94..b92886d38 100644 --- a/app/Jobs/PullHelperImageJob.php +++ b/app/Jobs/PullHelperImageJob.php @@ -16,7 +16,10 @@ class PullHelperImageJob implements ShouldBeEncrypted, ShouldQueue public $timeout = 1000; - public function __construct(public Server $server) {} + public function __construct(public Server $server) + { + $this->onQueue('high'); + } public function handle(): void { diff --git a/app/Jobs/PullTemplatesFromCDN.php b/app/Jobs/PullTemplatesFromCDN.php index bde5e6c7a..45c536e06 100644 --- a/app/Jobs/PullTemplatesFromCDN.php +++ b/app/Jobs/PullTemplatesFromCDN.php @@ -17,7 +17,10 @@ class PullTemplatesFromCDN implements ShouldBeEncrypted, ShouldQueue public $timeout = 10; - public function __construct() {} + public function __construct() + { + $this->onQueue('high'); + } public function handle(): void { diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 9822ca071..24f8d1e6b 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -360,7 +360,7 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue private function checkLogDrainContainer() { if ($this->server->isLogDrainEnabled() && $this->foundLogDrainContainer === false) { - StartLogDrain::dispatch($this->server)->onQueue('high'); + StartLogDrain::dispatch($this->server); } } } diff --git a/app/Jobs/ScheduledTaskJob.php b/app/Jobs/ScheduledTaskJob.php index 7bfc29af3..00575e187 100644 --- a/app/Jobs/ScheduledTaskJob.php +++ b/app/Jobs/ScheduledTaskJob.php @@ -40,6 +40,8 @@ class ScheduledTaskJob implements ShouldQueue public function __construct($task) { + $this->onQueue('high'); + $this->task = $task; if ($service = $task->service()->first()) { $this->resource = $service; diff --git a/app/Jobs/SendMessageToDiscordJob.php b/app/Jobs/SendMessageToDiscordJob.php index 5b406f50f..99aeaeea2 100644 --- a/app/Jobs/SendMessageToDiscordJob.php +++ b/app/Jobs/SendMessageToDiscordJob.php @@ -32,7 +32,9 @@ class SendMessageToDiscordJob implements ShouldBeEncrypted, ShouldQueue public function __construct( public DiscordMessage $message, public string $webhookUrl - ) {} + ) { + $this->onQueue('high'); + } /** * Execute the job. diff --git a/app/Jobs/SendMessageToTelegramJob.php b/app/Jobs/SendMessageToTelegramJob.php index bf52b782f..85f4fc934 100644 --- a/app/Jobs/SendMessageToTelegramJob.php +++ b/app/Jobs/SendMessageToTelegramJob.php @@ -33,7 +33,9 @@ class SendMessageToTelegramJob implements ShouldBeEncrypted, ShouldQueue public string $token, public string $chatId, public ?string $topicId = null, - ) {} + ) { + $this->onQueue('high'); + } /** * Execute the job. @@ -70,7 +72,7 @@ class SendMessageToTelegramJob implements ShouldBeEncrypted, ShouldQueue } $response = Http::post($url, $payload); if ($response->failed()) { - throw new \Exception('Telegram notification failed with '.$response->status().' status code.'.$response->body()); + throw new \RuntimeException('Telegram notification failed with '.$response->status().' status code.'.$response->body()); } } } diff --git a/app/Jobs/ServerCheckJob.php b/app/Jobs/ServerCheckJob.php index 0d5e2fd36..9818d5c6a 100644 --- a/app/Jobs/ServerCheckJob.php +++ b/app/Jobs/ServerCheckJob.php @@ -94,10 +94,10 @@ class ServerCheckJob implements ShouldBeEncrypted, ShouldQueue if ($foundLogDrainContainer) { $status = data_get($foundLogDrainContainer, 'State.Status'); if ($status !== 'running') { - StartLogDrain::dispatch($this->server)->onQueue('high'); + StartLogDrain::dispatch($this->server); } } else { - StartLogDrain::dispatch($this->server)->onQueue('high'); + StartLogDrain::dispatch($this->server); } } } diff --git a/app/Jobs/ServerFilesFromServerJob.php b/app/Jobs/ServerFilesFromServerJob.php index 769dfc004..58455df2f 100644 --- a/app/Jobs/ServerFilesFromServerJob.php +++ b/app/Jobs/ServerFilesFromServerJob.php @@ -16,7 +16,10 @@ class ServerFilesFromServerJob implements ShouldBeEncrypted, ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - public function __construct(public ServiceApplication|ServiceDatabase|Application $resource) {} + public function __construct(public ServiceApplication|ServiceDatabase|Application $resource) + { + $this->onQueue('high'); + } public function handle() { diff --git a/app/Jobs/ServerStorageCheckJob.php b/app/Jobs/ServerStorageCheckJob.php index 0723ffcee..9a8d86be1 100644 --- a/app/Jobs/ServerStorageCheckJob.php +++ b/app/Jobs/ServerStorageCheckJob.php @@ -25,7 +25,7 @@ class ServerStorageCheckJob implements ShouldBeEncrypted, ShouldQueue return isDev() ? 1 : 3; } - public function __construct(public Server $server, public ?int $percentage = null) {} + public function __construct(public Server $server, public int|string|null $percentage = null) {} public function handle() { diff --git a/app/Jobs/ServerStorageSaveJob.php b/app/Jobs/ServerStorageSaveJob.php index 526cd5375..17a293f94 100644 --- a/app/Jobs/ServerStorageSaveJob.php +++ b/app/Jobs/ServerStorageSaveJob.php @@ -14,7 +14,10 @@ class ServerStorageSaveJob implements ShouldBeEncrypted, ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - public function __construct(public LocalFileVolume $localFileVolume) {} + public function __construct(public LocalFileVolume $localFileVolume) + { + $this->onQueue('high'); + } public function handle() { diff --git a/app/Jobs/StripeProcessJob.php b/app/Jobs/StripeProcessJob.php new file mode 100644 index 000000000..2a1a5313c --- /dev/null +++ b/app/Jobs/StripeProcessJob.php @@ -0,0 +1,242 @@ +onQueue('high'); + } + + public function handle(): void + { + $excludedPlans = config('subscription.stripe_excluded_plans'); + + $type = data_get($this->event, 'type'); + $this->type = $type; + $data = data_get($this->event, 'data.object'); + switch ($type) { + case 'radar.early_fraud_warning.created': + $stripe = new \Stripe\StripeClient(config('subscription.stripe_api_key')); + $id = data_get($data, 'id'); + $charge = data_get($data, 'charge'); + if ($charge) { + $stripe->refunds->create(['charge' => $charge]); + } + $pi = data_get($data, 'payment_intent'); + $piData = $stripe->paymentIntents->retrieve($pi, []); + $customerId = data_get($piData, 'customer'); + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if ($subscription) { + $subscriptionId = data_get($subscription, 'stripe_subscription_id'); + $stripe->subscriptions->cancel($subscriptionId, []); + $subscription->update([ + 'stripe_invoice_paid' => false, + ]); + send_internal_notification("Early fraud warning created Refunded, subscription canceled. Charge: {$charge}, id: {$id}, pi: {$pi}"); + } else { + send_internal_notification("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}"); + throw new \Exception("Early fraud warning: subscription not found. Charge: {$charge}, id: {$id}, pi: {$pi}"); + } + break; + case 'checkout.session.completed': + $clientReferenceId = data_get($data, 'client_reference_id'); + if (is_null($clientReferenceId)) { + send_internal_notification('Checkout session completed without client reference id.'); + break; + } + $userId = Str::before($clientReferenceId, ':'); + $teamId = Str::after($clientReferenceId, ':'); + $subscriptionId = data_get($data, 'subscription'); + $customerId = data_get($data, 'customer'); + $team = Team::find($teamId); + $found = $team->members->where('id', $userId)->first(); + if (! $found->isAdmin()) { + send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); + throw new \Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}, subscriptionid: {$subscriptionId}."); + } + $subscription = Subscription::where('team_id', $teamId)->first(); + if ($subscription) { + send_internal_notification('Old subscription activated for team: '.$teamId); + $subscription->update([ + 'stripe_subscription_id' => $subscriptionId, + 'stripe_customer_id' => $customerId, + 'stripe_invoice_paid' => true, + ]); + } else { + send_internal_notification('New subscription for team: '.$teamId); + Subscription::create([ + 'team_id' => $teamId, + 'stripe_subscription_id' => $subscriptionId, + 'stripe_customer_id' => $customerId, + 'stripe_invoice_paid' => true, + ]); + } + break; + case 'invoice.paid': + $customerId = data_get($data, 'customer'); + $planId = data_get($data, 'lines.data.0.plan.id'); + if (Str::contains($excludedPlans, $planId)) { + send_internal_notification('Subscription excluded.'); + break; + } + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if ($subscription) { + $subscription->update([ + 'stripe_invoice_paid' => true, + ]); + } else { + throw new \Exception("No subscription found for customer: {$customerId}"); + } + break; + case 'invoice.payment_failed': + $customerId = data_get($data, 'customer'); + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if (! $subscription) { + send_internal_notification('invoice.payment_failed failed but no subscription found in Coolify for customer: '.$customerId); + throw new \Exception("No subscription found for customer: {$customerId}"); + } + $team = data_get($subscription, 'team'); + if (! $team) { + send_internal_notification('invoice.payment_failed failed but no team found in Coolify for customer: '.$customerId); + throw new \Exception("No team found in Coolify for customer: {$customerId}"); + } + if (! $subscription->stripe_invoice_paid) { + SubscriptionInvoiceFailedJob::dispatch($team); + send_internal_notification('Invoice payment failed: '.$customerId); + } else { + send_internal_notification('Invoice payment failed but already paid: '.$customerId); + } + break; + case 'payment_intent.payment_failed': + $customerId = data_get($data, 'customer'); + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if (! $subscription) { + send_internal_notification('payment_intent.payment_failed, no subscription found in Coolify for customer: '.$customerId); + throw new \Exception("No subscription found in Coolify for customer: {$customerId}"); + } + if ($subscription->stripe_invoice_paid) { + send_internal_notification('payment_intent.payment_failed but invoice is active for customer: '.$customerId); + + return; + } + send_internal_notification('Subscription payment failed for customer: '.$customerId); + break; + case 'customer.subscription.created': + $customerId = data_get($data, 'customer'); + $subscriptionId = data_get($data, 'id'); + $teamId = data_get($data, 'metadata.team_id'); + $userId = data_get($data, 'metadata.user_id'); + if (! $teamId || ! $userId) { + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if ($subscription) { + throw new \Exception("Subscription already exists for customer: {$customerId}"); + } + throw new \Exception('No team id or user id found'); + } + $team = Team::find($teamId); + $found = $team->members->where('id', $userId)->first(); + if (! $found->isAdmin()) { + send_internal_notification("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}."); + throw new \Exception("User {$userId} is not an admin or owner of team {$team->id}, customerid: {$customerId}."); + } + $subscription = Subscription::where('team_id', $teamId)->first(); + if ($subscription) { + send_internal_notification("Subscription already exists for team: {$teamId}"); + throw new \Exception("Subscription already exists for team: {$teamId}"); + } else { + Subscription::create([ + 'team_id' => $teamId, + 'stripe_subscription_id' => $subscriptionId, + 'stripe_customer_id' => $customerId, + 'stripe_invoice_paid' => false, + ]); + } + case 'customer.subscription.updated': + $teamId = data_get($data, 'metadata.team_id'); + $userId = data_get($data, 'metadata.user_id'); + $customerId = data_get($data, 'customer'); + $status = data_get($data, 'status'); + $subscriptionId = data_get($data, 'items.data.0.subscription'); + $planId = data_get($data, 'items.data.0.plan.id'); + if (Str::contains($excludedPlans, $planId)) { + send_internal_notification('Subscription excluded.'); + break; + } + $subscription = Subscription::where('stripe_customer_id', $customerId)->first(); + if (! $subscription) { + if ($status === 'incomplete_expired') { + send_internal_notification('Subscription incomplete expired'); + throw new \Exception('Subscription incomplete expired'); + } + if ($teamId) { + $subscription = Subscription::create([ + 'team_id' => $teamId, + 'stripe_subscription_id' => $subscriptionId, + 'stripe_customer_id' => $customerId, + 'stripe_invoice_paid' => false, + ]); + } else { + send_internal_notification('No subscription and team id found'); + throw new \Exception('No subscription and team id found'); + } + } + $cancelAtPeriodEnd = data_get($data, 'cancel_at_period_end'); + $feedback = data_get($data, 'cancellation_details.feedback'); + $comment = data_get($data, 'cancellation_details.comment'); + $lookup_key = data_get($data, 'items.data.0.price.lookup_key'); + if (str($lookup_key)->contains('dynamic')) { + $quantity = data_get($data, 'items.data.0.quantity', 2); + $team = data_get($subscription, 'team'); + if ($team) { + $team->update([ + 'custom_server_limit' => $quantity, + ]); + } + ServerLimitCheckJob::dispatch($team); + } + $subscription->update([ + 'stripe_feedback' => $feedback, + 'stripe_comment' => $comment, + 'stripe_plan_id' => $planId, + 'stripe_cancel_at_period_end' => $cancelAtPeriodEnd, + ]); + if ($status === 'paused' || $status === 'incomplete_expired') { + $subscription->update([ + 'stripe_invoice_paid' => false, + ]); + } + if ($feedback) { + $reason = "Cancellation feedback for {$customerId}: '".$feedback."'"; + if ($comment) { + $reason .= ' with comment: \''.$comment."'"; + } + } + break; + case 'customer.subscription.deleted': + // End subscription + $customerId = data_get($data, 'customer'); + $subscription = Subscription::where('stripe_customer_id', $customerId)->firstOrFail(); + $team = data_get($subscription, 'team'); + $team?->subscriptionEnded(); + break; + default: + // Unhandled event type + } + } +} diff --git a/app/Jobs/SubscriptionInvoiceFailedJob.php b/app/Jobs/SubscriptionInvoiceFailedJob.php index aabeecef5..dc511f445 100755 --- a/app/Jobs/SubscriptionInvoiceFailedJob.php +++ b/app/Jobs/SubscriptionInvoiceFailedJob.php @@ -15,7 +15,10 @@ class SubscriptionInvoiceFailedJob implements ShouldBeEncrypted, ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - public function __construct(protected Team $team) {} + public function __construct(protected Team $team) + { + $this->onQueue('high'); + } public function handle() { diff --git a/app/Jobs/UpdateCoolifyJob.php b/app/Jobs/UpdateCoolifyJob.php index 1e5197b6f..f0e43cbc0 100644 --- a/app/Jobs/UpdateCoolifyJob.php +++ b/app/Jobs/UpdateCoolifyJob.php @@ -18,6 +18,11 @@ class UpdateCoolifyJob implements ShouldBeEncrypted, ShouldQueue public $timeout = 600; + public function __construct() + { + $this->onQueue('high'); + } + public function handle(): void { try { diff --git a/app/Livewire/NavbarDeleteTeam.php b/app/Livewire/NavbarDeleteTeam.php index cc5d78f60..e97cceb0d 100644 --- a/app/Livewire/NavbarDeleteTeam.php +++ b/app/Livewire/NavbarDeleteTeam.php @@ -3,7 +3,6 @@ namespace App\Livewire; use App\Models\InstanceSettings; -use Illuminate\Container\Attributes\Auth as AttributesAuth; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; @@ -32,7 +31,7 @@ class NavbarDeleteTeam extends Component $currentTeam->delete(); $currentTeam->members->each(function ($user) use ($currentTeam) { - if ($user->id === AttributesAuth::id()) { + if ($user->id === Auth::id()) { return; } $user->teams()->detach($currentTeam); diff --git a/app/Livewire/Notifications/Email.php b/app/Livewire/Notifications/Email.php index 56f07f3a9..fcedf1305 100644 --- a/app/Livewire/Notifications/Email.php +++ b/app/Livewire/Notifications/Email.php @@ -73,6 +73,9 @@ class Email extends Component #[Validate(['nullable', 'string'])] public ?string $resendApiKey = null; + #[Validate(['required', 'email'])] + public string $testEmailAddress = ''; + public function mount() { try { @@ -132,14 +135,21 @@ class Email extends Component } } - public function sendTestNotification() + public function sendTestEmail() { try { + $this->validate([ + 'testEmailAddress' => 'required|email', + ], [ + 'testEmailAddress.required' => 'Test email address is required.', + 'testEmailAddress.email' => 'Please enter a valid email address.', + ]); + $executed = RateLimiter::attempt( 'test-email:'.$this->team->id, $perMinute = 0, function () { - $this->team?->notify(new Test($this->emails)); + $this->team?->notify(new Test($this->testEmailAddress)); $this->dispatch('success', 'Test Email sent.'); }, $decaySeconds = 10, diff --git a/app/Livewire/Project/Application/Heading.php b/app/Livewire/Project/Application/Heading.php index 1082b48cd..19a6145b7 100644 --- a/app/Livewire/Project/Application/Heading.php +++ b/app/Livewire/Project/Application/Heading.php @@ -36,7 +36,11 @@ class Heading extends Component public function mount() { - $this->parameters = get_route_parameters(); + $this->parameters = [ + 'project_uuid' => $this->application->project()->uuid, + 'environment_name' => $this->application->environment->name, + 'application_uuid' => $this->application->uuid, + ]; $lastDeployment = $this->application->get_last_successful_deployment(); $this->lastDeploymentInfo = data_get_str($lastDeployment, 'commit')->limit(7).' '.data_get($lastDeployment, 'commit_message'); $this->lastDeploymentLink = $this->application->gitCommitLink(data_get($lastDeployment, 'commit')); @@ -45,13 +49,11 @@ class Heading extends Component public function check_status($showNotification = false) { if ($this->application->destination->server->isFunctional()) { - GetContainersStatus::dispatch($this->application->destination->server)->onQueue('high'); + GetContainersStatus::dispatch($this->application->destination->server); } if ($showNotification) { $this->dispatch('success', 'Success', 'Application status updated.'); } - // Removed because it caused flickering - // $this->dispatch('configurationChanged'); } public function force_deploy_without_cache() diff --git a/app/Livewire/Project/Database/CreateScheduledBackup.php b/app/Livewire/Project/Database/CreateScheduledBackup.php index 0903efdfd..01108c290 100644 --- a/app/Livewire/Project/Database/CreateScheduledBackup.php +++ b/app/Livewire/Project/Database/CreateScheduledBackup.php @@ -21,8 +21,8 @@ class CreateScheduledBackup extends Component public bool $enabled = true; - #[Validate(['required', 'integer'])] - public int $s3StorageId; + #[Validate(['nullable', 'integer'])] + public ?int $s3StorageId = null; public Collection $definedS3s; @@ -49,6 +49,7 @@ class CreateScheduledBackup extends Component return; } + $payload = [ 'enabled' => true, 'frequency' => $this->frequency, @@ -58,6 +59,7 @@ class CreateScheduledBackup extends Component 'database_type' => $this->database->getMorphClass(), 'team_id' => currentTeam()->id, ]; + if ($this->database->type() === 'standalone-postgresql') { $payload['databases_to_backup'] = $this->database->postgres_db; } elseif ($this->database->type() === 'standalone-mysql') { @@ -72,11 +74,11 @@ class CreateScheduledBackup extends Component } else { $this->dispatch('refreshScheduledBackups'); } + } catch (\Throwable $e) { return handleError($e, $this); } finally { $this->frequency = ''; - $this->saveToS3 = true; } } } diff --git a/app/Livewire/Project/New/Select.php b/app/Livewire/Project/New/Select.php index 2dc9abbf1..3dedc11af 100644 --- a/app/Livewire/Project/New/Select.php +++ b/app/Livewire/Project/New/Select.php @@ -91,9 +91,12 @@ class Select extends Component { $services = get_service_templates(true); $services = collect($services)->map(function ($service, $key) { + $logo = data_get($service, 'logo', 'svgs/coolify.png'); + return [ 'name' => str($key)->headline(), - 'logo' => asset(data_get($service, 'logo', 'svgs/coolify.png')), + 'logo' => asset($logo), + 'logo_github_url' => 'https://raw.githubusercontent.com/coollabsio/coolify/refs/heads/main/public/a'.$logo, ] + (array) $service; })->all(); $gitBasedApplications = [ diff --git a/app/Livewire/Project/Shared/Tags.php b/app/Livewire/Project/Shared/Tags.php index dca6180ff..811859cb8 100644 --- a/app/Livewire/Project/Shared/Tags.php +++ b/app/Livewire/Project/Shared/Tags.php @@ -37,6 +37,7 @@ class Tags extends Component $this->validate(); $tags = str($this->newTags)->trim()->explode(' '); foreach ($tags as $tag) { + $tag = strip_tags($tag); if (strlen($tag) < 2) { $this->dispatch('error', 'Invalid tag.', "Tag $tag is invalid. Min length is 2."); @@ -65,6 +66,7 @@ class Tags extends Component public function addTag(string $id, string $name) { try { + $name = strip_tags($name); if ($this->resource->tags()->where('id', $id)->exists()) { $this->dispatch('error', 'Duplicate tags.', "Tag $name already added."); diff --git a/app/Livewire/Server/New/ByIp.php b/app/Livewire/Server/New/ByIp.php index f80152435..5f60c5db5 100644 --- a/app/Livewire/Server/New/ByIp.php +++ b/app/Livewire/Server/New/ByIp.php @@ -6,64 +6,60 @@ use App\Enums\ProxyTypes; use App\Models\Server; use App\Models\Team; use Illuminate\Support\Collection; +use Livewire\Attributes\Locked; +use Livewire\Attributes\Validate; use Livewire\Component; class ByIp extends Component { + #[Locked] public $private_keys; + #[Locked] public $limit_reached; + #[Validate('nullable|integer', as: 'Private Key')] public ?int $private_key_id = null; + #[Validate('nullable|string', as: 'Private Key Name')] public $new_private_key_name; + #[Validate('nullable|string', as: 'Private Key Description')] public $new_private_key_description; + #[Validate('nullable|string', as: 'Private Key Value')] public $new_private_key_value; + #[Validate('required|string', as: 'Name')] public string $name; + #[Validate('nullable|string', as: 'Description')] public ?string $description = null; + #[Validate('required|string', as: 'IP Address/Domain')] public string $ip; + #[Validate('required|string', as: 'User')] public string $user = 'root'; + #[Validate('required|integer|between:1,65535', as: 'Port')] public int $port = 22; + #[Validate('required|boolean', as: 'Swarm Manager')] public bool $is_swarm_manager = false; + #[Validate('required|boolean', as: 'Swarm Worker')] public bool $is_swarm_worker = false; + #[Validate('nullable|integer', as: 'Swarm Cluster')] public $selected_swarm_cluster = null; + #[Validate('required|boolean', as: 'Build Server')] public bool $is_build_server = false; + #[Locked] public Collection $swarm_managers; - protected $rules = [ - 'name' => 'required|string', - 'description' => 'nullable|string', - 'ip' => 'required', - 'user' => 'required|string', - 'port' => 'required|integer', - 'is_swarm_manager' => 'required|boolean', - 'is_swarm_worker' => 'required|boolean', - 'is_build_server' => 'required|boolean', - ]; - - protected $validationAttributes = [ - 'name' => 'Name', - 'description' => 'Description', - 'ip' => 'IP Address/Domain', - 'user' => 'User', - 'port' => 'Port', - 'is_swarm_manager' => 'Swarm Manager', - 'is_swarm_worker' => 'Swarm Worker', - 'is_build_server' => 'Build Server', - ]; - public function mount() { $this->name = generate_random_name(); @@ -88,6 +84,12 @@ class ByIp extends Component { $this->validate(); try { + if (Server::where('team_id', currentTeam()->id) + ->where('ip', $this->ip) + ->exists()) { + return $this->dispatch('error', 'This IP/Domain is already in use by another server in your team.'); + } + if (is_null($this->private_key_id)) { return $this->dispatch('error', 'You must select a private key'); } diff --git a/app/Livewire/Server/Show.php b/app/Livewire/Server/Show.php index 5a1743f96..a5544489d 100644 --- a/app/Livewire/Server/Show.php +++ b/app/Livewire/Server/Show.php @@ -107,6 +107,15 @@ class Show extends Component { if ($toModel) { $this->validate(); + + if (Server::where('team_id', currentTeam()->id) + ->where('ip', $this->ip) + ->where('id', '!=', $this->server->id) + ->exists()) { + $this->ip = $this->server->ip; + throw new \Exception('This IP/Domain is already in use by another server in your team.'); + } + $this->server->name = $this->name; $this->server->description = $this->description; $this->server->ip = $this->ip; diff --git a/app/Models/PrivateKey.php b/app/Models/PrivateKey.php index 065746ede..80015d87f 100644 --- a/app/Models/PrivateKey.php +++ b/app/Models/PrivateKey.php @@ -218,10 +218,12 @@ class PrivateKey extends BaseModel private static function fingerprintExists($fingerprint, $excludeId = null) { - $query = self::where('fingerprint', $fingerprint); + $query = self::query() + ->where('fingerprint', $fingerprint) + ->where('id', '!=', $excludeId); - if (! is_null($excludeId)) { - $query->where('id', '!=', $excludeId); + if (currentTeam()) { + $query->where('team_id', currentTeam()->id); } return $query->exists(); diff --git a/app/Models/Server.php b/app/Models/Server.php index 3df156a78..e6e2ffbe1 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -988,7 +988,7 @@ $schema://$host { public function status(): bool { - ['uptime' => $uptime] = $this->validateConnection(false); + ['uptime' => $uptime] = $this->validateConnection(); if ($uptime === false) { foreach ($this->applications() as $application) { $application->status = 'exited'; @@ -1051,18 +1051,14 @@ $schema://$host { $this->team->notify(new Unreachable($this)); } - public function validateConnection(bool $isManualCheck = true, bool $justCheckingNewKey = false) + public function validateConnection(bool $justCheckingNewKey = false) { - config()->set('constants.ssh.mux_enabled', ! $isManualCheck); + config()->set('constants.ssh.mux_enabled', false); if ($this->skipServer()) { return ['uptime' => false, 'error' => 'Server skipped.']; } try { - // Make sure the private key is stored - if ($this->privateKey) { - $this->privateKey->storeInFileSystem(); - } instant_remote_process(['ls /'], $this); if ($this->settings->is_reachable === false) { $this->settings->is_reachable = true; diff --git a/app/Notifications/Application/DeploymentFailed.php b/app/Notifications/Application/DeploymentFailed.php index dc6b93aad..12bcce626 100644 --- a/app/Notifications/Application/DeploymentFailed.php +++ b/app/Notifications/Application/DeploymentFailed.php @@ -35,6 +35,7 @@ class DeploymentFailed extends Notification implements ShouldQueue public function __construct(Application $application, string $deployment_uuid, ?ApplicationPreview $preview = null) { + $this->onQueue('high'); $this->application = $application; $this->deployment_uuid = $deployment_uuid; $this->preview = $preview; diff --git a/app/Notifications/Application/DeploymentSuccess.php b/app/Notifications/Application/DeploymentSuccess.php index e11d6db1c..29934dab1 100644 --- a/app/Notifications/Application/DeploymentSuccess.php +++ b/app/Notifications/Application/DeploymentSuccess.php @@ -34,6 +34,7 @@ class DeploymentSuccess extends Notification implements ShouldQueue public function __construct(Application $application, string $deployment_uuid, ?ApplicationPreview $preview = null) { + $this->onQueue('high'); $this->application = $application; $this->deployment_uuid = $deployment_uuid; $this->preview = $preview; diff --git a/app/Notifications/Application/StatusChanged.php b/app/Notifications/Application/StatusChanged.php index c7445cb70..1f57aeeda 100644 --- a/app/Notifications/Application/StatusChanged.php +++ b/app/Notifications/Application/StatusChanged.php @@ -27,6 +27,7 @@ class StatusChanged extends Notification implements ShouldQueue public function __construct(public Application $resource) { + $this->onQueue('high'); $this->resource_name = data_get($resource, 'name'); $this->project_uuid = data_get($resource, 'environment.project.uuid'); $this->environment_name = data_get($resource, 'environment.name'); diff --git a/app/Notifications/Channels/DiscordChannel.php b/app/Notifications/Channels/DiscordChannel.php index 86276fec9..df7040f8f 100644 --- a/app/Notifications/Channels/DiscordChannel.php +++ b/app/Notifications/Channels/DiscordChannel.php @@ -17,6 +17,6 @@ class DiscordChannel if (! $webhookUrl) { return; } - dispatch(new SendMessageToDiscordJob($message, $webhookUrl))->onQueue('high'); + SendMessageToDiscordJob::dispatch($message, $webhookUrl); } } diff --git a/app/Notifications/Channels/TelegramChannel.php b/app/Notifications/Channels/TelegramChannel.php index b3d4e384b..958c46c21 100644 --- a/app/Notifications/Channels/TelegramChannel.php +++ b/app/Notifications/Channels/TelegramChannel.php @@ -41,6 +41,6 @@ class TelegramChannel if (! $telegramToken || ! $chatId || ! $message) { return; } - dispatch(new SendMessageToTelegramJob($message, $buttons, $telegramToken, $chatId, $topicId))->onQueue('high'); + SendMessageToTelegramJob::dispatch($message, $buttons, $telegramToken, $chatId, $topicId); } } diff --git a/app/Notifications/Container/ContainerRestarted.php b/app/Notifications/Container/ContainerRestarted.php index 40bd9b7ee..d1642bc5d 100644 --- a/app/Notifications/Container/ContainerRestarted.php +++ b/app/Notifications/Container/ContainerRestarted.php @@ -17,6 +17,7 @@ class ContainerRestarted extends Notification implements ShouldQueue public function __construct(public string $name, public Server $server, public ?string $url = null) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Container/ContainerStopped.php b/app/Notifications/Container/ContainerStopped.php index 9b3824624..a5d812bf1 100644 --- a/app/Notifications/Container/ContainerStopped.php +++ b/app/Notifications/Container/ContainerStopped.php @@ -17,6 +17,7 @@ class ContainerStopped extends Notification implements ShouldQueue public function __construct(public string $name, public Server $server, public ?string $url = null) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Database/BackupFailed.php b/app/Notifications/Database/BackupFailed.php index 137a6d730..22e5cea25 100644 --- a/app/Notifications/Database/BackupFailed.php +++ b/app/Notifications/Database/BackupFailed.php @@ -23,6 +23,7 @@ class BackupFailed extends Notification implements ShouldQueue public function __construct(ScheduledDatabaseBackup $backup, public $database, public $output, public $database_name) { + $this->onQueue('high'); $this->name = $database->name; $this->frequency = $backup->frequency; } diff --git a/app/Notifications/Database/BackupSuccess.php b/app/Notifications/Database/BackupSuccess.php index 76ddc9221..6f7b32b42 100644 --- a/app/Notifications/Database/BackupSuccess.php +++ b/app/Notifications/Database/BackupSuccess.php @@ -23,6 +23,7 @@ class BackupSuccess extends Notification implements ShouldQueue public function __construct(ScheduledDatabaseBackup $backup, public $database, public $database_name) { + $this->onQueue('high'); $this->name = $database->name; $this->frequency = $backup->frequency; } diff --git a/app/Notifications/Internal/GeneralNotification.php b/app/Notifications/Internal/GeneralNotification.php index 4dd925159..699291d16 100644 --- a/app/Notifications/Internal/GeneralNotification.php +++ b/app/Notifications/Internal/GeneralNotification.php @@ -19,6 +19,7 @@ class GeneralNotification extends Notification implements ShouldQueue public function __construct(public string $message) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/ScheduledTask/TaskFailed.php b/app/Notifications/ScheduledTask/TaskFailed.php index 99d83fdf6..67f77ff71 100644 --- a/app/Notifications/ScheduledTask/TaskFailed.php +++ b/app/Notifications/ScheduledTask/TaskFailed.php @@ -21,6 +21,7 @@ class TaskFailed extends Notification implements ShouldQueue public function __construct(public ScheduledTask $task, public string $output) { + $this->onQueue('high'); if ($task->application) { $this->url = $task->application->failedTaskLink($task->uuid); } elseif ($task->service) { diff --git a/app/Notifications/Server/DockerCleanup.php b/app/Notifications/Server/DockerCleanup.php index eb4498835..979672cfd 100644 --- a/app/Notifications/Server/DockerCleanup.php +++ b/app/Notifications/Server/DockerCleanup.php @@ -19,6 +19,7 @@ class DockerCleanup extends Notification implements ShouldQueue public function __construct(public Server $server, public string $message) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Server/ForceDisabled.php b/app/Notifications/Server/ForceDisabled.php index 969f60d79..053ea6e7f 100644 --- a/app/Notifications/Server/ForceDisabled.php +++ b/app/Notifications/Server/ForceDisabled.php @@ -22,6 +22,7 @@ class ForceDisabled extends Notification implements ShouldQueue public function __construct(public Server $server) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Server/ForceEnabled.php b/app/Notifications/Server/ForceEnabled.php index e24136c81..1c7086dfd 100644 --- a/app/Notifications/Server/ForceEnabled.php +++ b/app/Notifications/Server/ForceEnabled.php @@ -22,6 +22,7 @@ class ForceEnabled extends Notification implements ShouldQueue public function __construct(public Server $server) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Server/HighDiskUsage.php b/app/Notifications/Server/HighDiskUsage.php index a780d9d15..6c38b8418 100644 --- a/app/Notifications/Server/HighDiskUsage.php +++ b/app/Notifications/Server/HighDiskUsage.php @@ -18,6 +18,7 @@ class HighDiskUsage extends Notification implements ShouldQueue public function __construct(public Server $server, public int $disk_usage, public int $server_disk_usage_notification_threshold) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/Server/Reachable.php b/app/Notifications/Server/Reachable.php index 6ca4170f5..3e49fea8d 100644 --- a/app/Notifications/Server/Reachable.php +++ b/app/Notifications/Server/Reachable.php @@ -24,6 +24,7 @@ class Reachable extends Notification implements ShouldQueue public function __construct(public Server $server) { + $this->onQueue('high'); $this->isRateLimited = isEmailRateLimited( limiterKey: 'server-reachable:' . $this->server->id, ); diff --git a/app/Notifications/Server/Unreachable.php b/app/Notifications/Server/Unreachable.php index cdb18b1bd..e0f58787d 100644 --- a/app/Notifications/Server/Unreachable.php +++ b/app/Notifications/Server/Unreachable.php @@ -24,6 +24,7 @@ class Unreachable extends Notification implements ShouldQueue public function __construct(public Server $server) { + $this->onQueue('high'); $this->isRateLimited = isEmailRateLimited( limiterKey: 'server-unreachable:' . $this->server->id, ); diff --git a/app/Notifications/Test.php b/app/Notifications/Test.php index 6aae641c4..ce998d9f6 100644 --- a/app/Notifications/Test.php +++ b/app/Notifications/Test.php @@ -18,6 +18,7 @@ class Test extends Notification implements ShouldQueue public function __construct(public ?string $emails = null) { + $this->onQueue('high'); } public function via(object $notifiable): array diff --git a/app/Notifications/TransactionalEmails/InvitationLink.php b/app/Notifications/TransactionalEmails/InvitationLink.php index 6da2a6fcc..eef7ba0e5 100644 --- a/app/Notifications/TransactionalEmails/InvitationLink.php +++ b/app/Notifications/TransactionalEmails/InvitationLink.php @@ -22,7 +22,10 @@ class InvitationLink extends Notification implements ShouldQueue return [TransactionalEmailChannel::class]; } - public function __construct(public User $user) {} + public function __construct(public User $user) + { + $this->onQueue('high'); + } public function toMail(): MailMessage { diff --git a/app/Notifications/TransactionalEmails/Test.php b/app/Notifications/TransactionalEmails/Test.php index 64883a58e..b3cc79604 100644 --- a/app/Notifications/TransactionalEmails/Test.php +++ b/app/Notifications/TransactionalEmails/Test.php @@ -14,7 +14,10 @@ class Test extends Notification implements ShouldQueue public $tries = 5; - public function __construct(public string $emails) {} + public function __construct(public string $emails) + { + $this->onQueue('high'); + } public function via(): array { diff --git a/app/View/Components/Forms/Checkbox.php b/app/View/Components/Forms/Checkbox.php index 414dbf2ae..0bdebe7e4 100644 --- a/app/View/Components/Forms/Checkbox.php +++ b/app/View/Components/Forms/Checkbox.php @@ -17,11 +17,14 @@ class Checkbox extends Component public ?string $value = null, public ?string $label = null, public ?string $helper = null, + public string|bool|null $checked = false, public string|bool $instantSave = false, public bool $disabled = false, public string $defaultClass = 'dark:border-neutral-700 text-coolgray-400 focus:ring-warning dark:bg-coolgray-100 rounded cursor-pointer dark:disabled:bg-base dark:disabled:cursor-not-allowed', ) { - // + if ($this->disabled) { + $this->defaultClass .= ' opacity-40'; + } } /** diff --git a/bootstrap/helpers/applications.php b/bootstrap/helpers/applications.php index eb331f8c2..73d5389ae 100644 --- a/bootstrap/helpers/applications.php +++ b/bootstrap/helpers/applications.php @@ -44,13 +44,13 @@ function queue_application_deployment(Application $application, string $deployme ]); if ($no_questions_asked) { - dispatch(new ApplicationDeploymentJob( + ApplicationDeploymentJob::dispatch( application_deployment_queue_id: $deployment->id, - ))->onQueue('high'); + ); } elseif (next_queuable($server_id, $application_id)) { - dispatch(new ApplicationDeploymentJob( + ApplicationDeploymentJob::dispatch( application_deployment_queue_id: $deployment->id, - ))->onQueue('high'); + ); } } function force_start_deployment(ApplicationDeploymentQueue $deployment) @@ -59,9 +59,9 @@ function force_start_deployment(ApplicationDeploymentQueue $deployment) 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value, ]); - dispatch(new ApplicationDeploymentJob( + ApplicationDeploymentJob::dispatch( application_deployment_queue_id: $deployment->id, - ))->onQueue('high'); + ); } function queue_next_deployment(Application $application) { @@ -72,9 +72,9 @@ function queue_next_deployment(Application $application) 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value, ]); - dispatch(new ApplicationDeploymentJob( + ApplicationDeploymentJob::dispatch( application_deployment_queue_id: $next_found->id, - ))->onQueue('high'); + ); } } @@ -113,9 +113,9 @@ function next_after_cancel(?Server $server = null) 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value, ]); - dispatch(new ApplicationDeploymentJob( + ApplicationDeploymentJob::dispatch( application_deployment_queue_id: $next->id, - ))->onQueue('high'); + ); } break; } diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index 302193131..da99c5cbd 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -227,13 +227,17 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource) $MINIO_BROWSER_REDIRECT_URL = $variables->where('key', 'MINIO_BROWSER_REDIRECT_URL')->first(); $MINIO_SERVER_URL = $variables->where('key', 'MINIO_SERVER_URL')->first(); - if (str($MINIO_BROWSER_REDIRECT_URL->value)->isEmpty()) { - $MINIO_BROWSER_REDIRECT_URL?->update([ + if (is_null($MINIO_BROWSER_REDIRECT_URL) || is_null($MINIO_SERVER_URL)) { + return collect([]); + } + + if (str($MINIO_BROWSER_REDIRECT_URL->value ?? '')->isEmpty()) { + $MINIO_BROWSER_REDIRECT_URL->update([ 'value' => generateFqdn($server, 'console-'.$uuid, true), ]); } - if (str($MINIO_SERVER_URL->value)->isEmpty()) { - $MINIO_SERVER_URL?->update([ + if (str($MINIO_SERVER_URL->value ?? '')->isEmpty()) { + $MINIO_SERVER_URL->update([ 'value' => generateFqdn($server, 'minio-'.$uuid, true), ]); } @@ -246,13 +250,17 @@ function generateServiceSpecificFqdns(ServiceApplication|Application $resource) $LOGTO_ENDPOINT = $variables->where('key', 'LOGTO_ENDPOINT')->first(); $LOGTO_ADMIN_ENDPOINT = $variables->where('key', 'LOGTO_ADMIN_ENDPOINT')->first(); - if (str($LOGTO_ENDPOINT?->value)->isEmpty()) { - $LOGTO_ENDPOINT?->update([ + if (is_null($LOGTO_ENDPOINT) || is_null($LOGTO_ADMIN_ENDPOINT)) { + return collect([]); + } + + if (str($LOGTO_ENDPOINT->value ?? '')->isEmpty()) { + $LOGTO_ENDPOINT->update([ 'value' => generateFqdn($server, 'logto-'.$uuid), ]); } - if (str($LOGTO_ADMIN_ENDPOINT?->value)->isEmpty()) { - $LOGTO_ADMIN_ENDPOINT?->update([ + if (str($LOGTO_ADMIN_ENDPOINT->value ?? '')->isEmpty()) { + $LOGTO_ADMIN_ENDPOINT->update([ 'value' => generateFqdn($server, 'logto-admin-'.$uuid), ]); } diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 7602d3066..7fb9b6e08 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -4081,7 +4081,7 @@ function defaultNginxConfiguration(): string location / { root /usr/share/nginx/html; index index.html index.htm; - try_files $uri $uri/index.html =404; + try_files $uri $uri.html $uri/index.html $uri/index.htm $uri/ /index.html /index.htm =404; } error_page 500 502 503 504 /50x.html; diff --git a/composer.json b/composer.json index 9e34e8b23..694bad882 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,7 @@ "socialiteproviders/microsoft-azure": "^5.1", "spatie/laravel-activitylog": "^4.7.3", "spatie/laravel-data": "^4.11", + "spatie/laravel-ray": "^1.37", "spatie/laravel-schemaless-attributes": "^2.4", "spatie/url": "^2.2", "stripe/stripe-php": "^16.2.0", @@ -63,7 +64,6 @@ "phpunit/phpunit": "^11.4", "serversideup/spin": "^2.3", "spatie/laravel-ignition": "^2.1.0", - "spatie/laravel-ray": "^1.37", "symfony/http-client": "^7.1" }, "minimum-stability": "stable", diff --git a/composer.lock b/composer.lock index 63d070405..8ea0d9a5a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c19f791a42f2d1458409e399ff7d28ec", + "content-hash": "f50de759f43a3eefb58ce9ebbb02d33b", "packages": [ { "name": "3sidedcube/laravel-redoc", @@ -979,16 +979,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.325.7", + "version": "3.327.1", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "55852104253172e66c3358bf4c35281bbd8622b2" + "reference": "3d52ec587989b136e486f94eff3dd316465aeb42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/55852104253172e66c3358bf4c35281bbd8622b2", - "reference": "55852104253172e66c3358bf4c35281bbd8622b2", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3d52ec587989b136e486f94eff3dd316465aeb42", + "reference": "3d52ec587989b136e486f94eff3dd316465aeb42", "shasum": "" }, "require": { @@ -1071,9 +1071,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.325.7" + "source": "https://github.com/aws/aws-sdk-php/tree/3.327.1" }, - "time": "2024-11-12T19:27:31+00:00" + "time": "2024-11-15T01:53:30+00:00" }, { "name": "bacon/bacon-qr-code", @@ -5473,6 +5473,134 @@ }, "time": "2024-09-04T12:51:01+00:00" }, + { + "name": "php-di/invoker", + "version": "2.3.4", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", + "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "psr/container": "^1.0|^2.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "support": { + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + } + ], + "time": "2023-09-08T09:24:21+00:00" + }, + { + "name": "php-di/php-di", + "version": "7.0.7", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "e87435e3c0e8f22977adc5af0d5cdcc467e15cf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/e87435e3c0e8f22977adc5af0d5cdcc467e15cf1", + "reference": "e87435e3c0e8f22977adc5af0d5cdcc467e15cf1", + "shasum": "" + }, + "require": { + "laravel/serializable-closure": "^1.0", + "php": ">=8.0", + "php-di/invoker": "^2.0", + "psr/container": "^1.1 || ^2.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3", + "friendsofphp/proxy-manager-lts": "^1", + "mnapoli/phpunit-easymock": "^1.3", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^4.6" + }, + "suggest": { + "friendsofphp/proxy-manager-lts": "Install it if you want to use lazy injection (version ^1)" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "DI\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The dependency injection container for humans", + "homepage": "https://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "support": { + "issues": "https://github.com/PHP-DI/PHP-DI/issues", + "source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.7" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", + "type": "tidelift" + } + ], + "time": "2024-07-21T15:55:45+00:00" + }, { "name": "phpdocumentor/reflection", "version": "6.0.0", @@ -5947,6 +6075,64 @@ }, "time": "2024-10-13T11:29:49+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.12.10", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "fc463b5d0fe906dcf19689be692c65c50406a071" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fc463b5d0fe906dcf19689be692c65c50406a071", + "reference": "fc463b5d0fe906dcf19689be692c65c50406a071", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2024-11-11T15:37:09+00:00" + }, { "name": "pion/laravel-chunk-upload", "version": "v1.5.4", @@ -6983,6 +7169,65 @@ ], "time": "2024-04-27T21:32:50+00:00" }, + { + "name": "rector/rector", + "version": "1.2.10", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "40f9cf38c05296bd32f444121336a521a293fa61" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/40f9cf38c05296bd32f444121336a521a293fa61", + "reference": "40f9cf38c05296bd32f444121336a521a293fa61", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0", + "phpstan/phpstan": "^1.12.5" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], + "support": { + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/1.2.10" + }, + "funding": [ + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2024-11-08T13:59:10+00:00" + }, { "name": "resend/resend-laravel", "version": "v0.15.0", @@ -7484,6 +7729,69 @@ }, "time": "2024-03-15T03:02:10+00:00" }, + { + "name": "spatie/backtrace", + "version": "1.6.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/backtrace.git", + "reference": "1a9a145b044677ae3424693f7b06479fc8c137a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/backtrace/zipball/1a9a145b044677ae3424693f7b06479fc8c137a9", + "reference": "1a9a145b044677ae3424693f7b06479fc8c137a9", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "ext-json": "*", + "laravel/serializable-closure": "^1.3", + "phpunit/phpunit": "^9.3", + "spatie/phpunit-snapshot-assertions": "^4.2", + "symfony/var-dumper": "^5.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Backtrace\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van de Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "A better backtrace", + "homepage": "https://github.com/spatie/backtrace", + "keywords": [ + "Backtrace", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/backtrace/tree/1.6.2" + }, + "funding": [ + { + "url": "https://github.com/sponsors/spatie", + "type": "github" + }, + { + "url": "https://spatie.be/open-source/support-us", + "type": "other" + } + ], + "time": "2024-07-22T08:21:24+00:00" + }, { "name": "spatie/laravel-activitylog", "version": "4.9.0", @@ -7719,6 +8027,93 @@ ], "time": "2024-08-27T18:56:10+00:00" }, + { + "name": "spatie/laravel-ray", + "version": "1.37.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-ray.git", + "reference": "c2bedfd1172648df2c80aaceb2541d70f1d9a5b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/c2bedfd1172648df2c80aaceb2541d70f1d9a5b9", + "reference": "c2bedfd1172648df2c80aaceb2541d70f1d9a5b9", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/contracts": "^7.20|^8.19|^9.0|^10.0|^11.0", + "illuminate/database": "^7.20|^8.19|^9.0|^10.0|^11.0", + "illuminate/queue": "^7.20|^8.19|^9.0|^10.0|^11.0", + "illuminate/support": "^7.20|^8.19|^9.0|^10.0|^11.0", + "php": "^7.4|^8.0", + "rector/rector": "^0.19.2|^1.0", + "spatie/backtrace": "^1.0", + "spatie/ray": "^1.41.1", + "symfony/stopwatch": "4.2|^5.1|^6.0|^7.0", + "zbateson/mail-mime-parser": "^1.3.1|^2.0|^3.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.3", + "laravel/framework": "^7.20|^8.19|^9.0|^10.0|^11.0", + "orchestra/testbench-core": "^5.0|^6.0|^7.0|^8.0|^9.0", + "pestphp/pest": "^1.22|^2.0", + "phpstan/phpstan": "^1.10.57", + "phpunit/phpunit": "^9.3|^10.1", + "spatie/pest-plugin-snapshots": "^1.1|^2.0", + "symfony/var-dumper": "^4.2|^5.1|^6.0|^7.0.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + }, + "laravel": { + "providers": [ + "Spatie\\LaravelRay\\RayServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\LaravelRay\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Easily debug Laravel apps", + "homepage": "https://github.com/spatie/laravel-ray", + "keywords": [ + "laravel-ray", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-ray/issues", + "source": "https://github.com/spatie/laravel-ray/tree/1.37.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/spatie", + "type": "github" + }, + { + "url": "https://spatie.be/open-source/support-us", + "type": "other" + } + ], + "time": "2024-07-12T12:35:17+00:00" + }, { "name": "spatie/laravel-schemaless-attributes", "version": "2.5.0", @@ -7925,6 +8320,91 @@ ], "time": "2024-08-29T10:43:45+00:00" }, + { + "name": "spatie/ray", + "version": "1.41.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/ray.git", + "reference": "c44f8cfbf82c69909b505de61d8d3f2d324e93fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/ray/zipball/c44f8cfbf82c69909b505de61d8d3f2d324e93fc", + "reference": "c44f8cfbf82c69909b505de61d8d3f2d324e93fc", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "php": "^7.3|^8.0", + "ramsey/uuid": "^3.0|^4.1", + "spatie/backtrace": "^1.1", + "spatie/macroable": "^1.0|^2.0", + "symfony/stopwatch": "^4.0|^5.1|^6.0|^7.0", + "symfony/var-dumper": "^4.2|^5.1|^6.0|^7.0.3" + }, + "require-dev": { + "illuminate/support": "6.x|^8.18|^9.0", + "nesbot/carbon": "^2.63", + "pestphp/pest": "^1.22", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.19.2", + "spatie/phpunit-snapshot-assertions": "^4.2", + "spatie/test-time": "^1.2" + }, + "bin": [ + "bin/remove-ray.sh" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Spatie\\Ray\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Debug with Ray to fix problems faster", + "homepage": "https://github.com/spatie/ray", + "keywords": [ + "ray", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/ray/issues", + "source": "https://github.com/spatie/ray/tree/1.41.2" + }, + "funding": [ + { + "url": "https://github.com/sponsors/spatie", + "type": "github" + }, + { + "url": "https://spatie.be/open-source/support-us", + "type": "other" + } + ], + "time": "2024-04-24T14:21:46+00:00" + }, { "name": "spatie/url", "version": "2.4.0", @@ -9141,6 +9621,86 @@ ], "time": "2024-09-09T11:45:10+00:00" }, + { + "name": "symfony/polyfill-iconv", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-iconv.git", + "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/48becf00c920479ca2e910c22a5a39e5d47ca956", + "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-iconv": "*" + }, + "suggest": { + "ext-iconv": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Iconv\\": "" + } + }, + "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 Iconv extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "iconv", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, { "name": "symfony/polyfill-intl-grapheme", "version": "v1.31.0", @@ -10006,6 +10566,68 @@ ], "time": "2024-04-18T09:32:20+00:00" }, + { + "name": "symfony/stopwatch", + "version": "v7.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "8b4a434e6e7faf6adedffb48783a5c75409a1a05" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/8b4a434e6e7faf6adedffb48783a5c75409a1a05", + "reference": "8b4a434e6e7faf6adedffb48783a5c75409a1a05", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/service-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "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 way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v7.1.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, { "name": "symfony/string", "version": "v7.1.8", @@ -10930,6 +11552,214 @@ }, "time": "2018-08-08T15:08:14+00:00" }, + { + "name": "zbateson/mail-mime-parser", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/zbateson/mail-mime-parser.git", + "reference": "e0d4423fe27850c9dd301190767dbc421acc2f19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zbateson/mail-mime-parser/zipball/e0d4423fe27850c9dd301190767dbc421acc2f19", + "reference": "e0d4423fe27850c9dd301190767dbc421acc2f19", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^2.5", + "php": ">=8.0", + "php-di/php-di": "^6.0|^7.0", + "psr/log": "^1|^2|^3", + "zbateson/mb-wrapper": "^2.0", + "zbateson/stream-decorators": "^2.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "monolog/monolog": "^2|^3", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^9.6" + }, + "suggest": { + "ext-iconv": "For best support/performance", + "ext-mbstring": "For best support/performance" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZBateson\\MailMimeParser\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Zaahid Bateson" + }, + { + "name": "Contributors", + "homepage": "https://github.com/zbateson/mail-mime-parser/graphs/contributors" + } + ], + "description": "MIME email message parser", + "homepage": "https://mail-mime-parser.org", + "keywords": [ + "MimeMailParser", + "email", + "mail", + "mailparse", + "mime", + "mimeparse", + "parser", + "php-imap" + ], + "support": { + "docs": "https://mail-mime-parser.org/#usage-guide", + "issues": "https://github.com/zbateson/mail-mime-parser/issues", + "source": "https://github.com/zbateson/mail-mime-parser" + }, + "funding": [ + { + "url": "https://github.com/zbateson", + "type": "github" + } + ], + "time": "2024-08-10T18:44:09+00:00" + }, + { + "name": "zbateson/mb-wrapper", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/zbateson/mb-wrapper.git", + "reference": "9e4373a153585d12b6c621ac4a6bb143264d4619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zbateson/mb-wrapper/zipball/9e4373a153585d12b6c621ac4a6bb143264d4619", + "reference": "9e4373a153585d12b6c621ac4a6bb143264d4619", + "shasum": "" + }, + "require": { + "php": ">=8.0", + "symfony/polyfill-iconv": "^1.9", + "symfony/polyfill-mbstring": "^1.9" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "<10.0" + }, + "suggest": { + "ext-iconv": "For best support/performance", + "ext-mbstring": "For best support/performance" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZBateson\\MbWrapper\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Zaahid Bateson" + } + ], + "description": "Wrapper for mbstring with fallback to iconv for encoding conversion and string manipulation", + "keywords": [ + "charset", + "encoding", + "http", + "iconv", + "mail", + "mb", + "mb_convert_encoding", + "mbstring", + "mime", + "multibyte", + "string" + ], + "support": { + "issues": "https://github.com/zbateson/mb-wrapper/issues", + "source": "https://github.com/zbateson/mb-wrapper/tree/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/zbateson", + "type": "github" + } + ], + "time": "2024-03-20T01:38:07+00:00" + }, + { + "name": "zbateson/stream-decorators", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/zbateson/stream-decorators.git", + "reference": "32a2a62fb0f26313395c996ebd658d33c3f9c4e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/32a2a62fb0f26313395c996ebd658d33c3f9c4e5", + "reference": "32a2a62fb0f26313395c996ebd658d33c3f9c4e5", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^2.5", + "php": ">=8.0", + "zbateson/mb-wrapper": "^2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^9.6|^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZBateson\\StreamDecorators\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Zaahid Bateson" + } + ], + "description": "PHP psr7 stream decorators for mime message part streams", + "keywords": [ + "base64", + "charset", + "decorators", + "mail", + "mime", + "psr7", + "quoted-printable", + "stream", + "uuencode" + ], + "support": { + "issues": "https://github.com/zbateson/stream-decorators/issues", + "source": "https://github.com/zbateson/stream-decorators/tree/2.1.1" + }, + "funding": [ + { + "url": "https://github.com/zbateson", + "type": "github" + } + ], + "time": "2024-04-29T21:42:39+00:00" + }, { "name": "zircote/swagger-php", "version": "4.11.1", @@ -11015,16 +11845,16 @@ "packages-dev": [ { "name": "barryvdh/laravel-debugbar", - "version": "v3.14.6", + "version": "v3.14.7", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-debugbar.git", - "reference": "14e4517bd49130d6119228107eb21ae47ae120ab" + "reference": "f484b8c9124de0b163da39958331098ffcd4a65e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/14e4517bd49130d6119228107eb21ae47ae120ab", - "reference": "14e4517bd49130d6119228107eb21ae47ae120ab", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/f484b8c9124de0b163da39958331098ffcd4a65e", + "reference": "f484b8c9124de0b163da39958331098ffcd4a65e", "shasum": "" }, "require": { @@ -11083,7 +11913,7 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-debugbar/issues", - "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.14.6" + "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.14.7" }, "funding": [ { @@ -11095,7 +11925,7 @@ "type": "github" } ], - "time": "2024-10-18T13:15:12+00:00" + "time": "2024-11-14T09:12:35+00:00" }, { "name": "brianium/paratest", @@ -12393,134 +13223,6 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "php-di/invoker", - "version": "2.3.4", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/Invoker.git", - "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/33234b32dafa8eb69202f950a1fc92055ed76a86", - "reference": "33234b32dafa8eb69202f950a1fc92055ed76a86", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "psr/container": "^1.0|^2.0" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "mnapoli/hard-mode": "~0.3.0", - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Invoker\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Generic and extensible callable invoker", - "homepage": "https://github.com/PHP-DI/Invoker", - "keywords": [ - "callable", - "dependency", - "dependency-injection", - "injection", - "invoke", - "invoker" - ], - "support": { - "issues": "https://github.com/PHP-DI/Invoker/issues", - "source": "https://github.com/PHP-DI/Invoker/tree/2.3.4" - }, - "funding": [ - { - "url": "https://github.com/mnapoli", - "type": "github" - } - ], - "time": "2023-09-08T09:24:21+00:00" - }, - { - "name": "php-di/php-di", - "version": "7.0.7", - "source": { - "type": "git", - "url": "https://github.com/PHP-DI/PHP-DI.git", - "reference": "e87435e3c0e8f22977adc5af0d5cdcc467e15cf1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/e87435e3c0e8f22977adc5af0d5cdcc467e15cf1", - "reference": "e87435e3c0e8f22977adc5af0d5cdcc467e15cf1", - "shasum": "" - }, - "require": { - "laravel/serializable-closure": "^1.0", - "php": ">=8.0", - "php-di/invoker": "^2.0", - "psr/container": "^1.1 || ^2.0" - }, - "provide": { - "psr/container-implementation": "^1.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3", - "friendsofphp/proxy-manager-lts": "^1", - "mnapoli/phpunit-easymock": "^1.3", - "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^4.6" - }, - "suggest": { - "friendsofphp/proxy-manager-lts": "Install it if you want to use lazy injection (version ^1)" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "DI\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "The dependency injection container for humans", - "homepage": "https://php-di.org/", - "keywords": [ - "PSR-11", - "container", - "container-interop", - "dependency injection", - "di", - "ioc", - "psr11" - ], - "support": { - "issues": "https://github.com/PHP-DI/PHP-DI/issues", - "source": "https://github.com/PHP-DI/PHP-DI/tree/7.0.7" - }, - "funding": [ - { - "url": "https://github.com/mnapoli", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", - "type": "tidelift" - } - ], - "time": "2024-07-21T15:55:45+00:00" - }, { "name": "php-webdriver/webdriver", "version": "1.15.1", @@ -12587,64 +13289,6 @@ }, "time": "2023-10-20T12:21:20+00:00" }, - { - "name": "phpstan/phpstan", - "version": "1.12.10", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "fc463b5d0fe906dcf19689be692c65c50406a071" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fc463b5d0fe906dcf19689be692c65c50406a071", - "reference": "fc463b5d0fe906dcf19689be692c65c50406a071", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - } - ], - "time": "2024-11-11T15:37:09+00:00" - }, { "name": "phpunit/php-code-coverage", "version": "11.0.7", @@ -13068,65 +13712,6 @@ ], "time": "2024-10-28T13:07:50+00:00" }, - { - "name": "rector/rector", - "version": "1.2.10", - "source": { - "type": "git", - "url": "https://github.com/rectorphp/rector.git", - "reference": "40f9cf38c05296bd32f444121336a521a293fa61" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/40f9cf38c05296bd32f444121336a521a293fa61", - "reference": "40f9cf38c05296bd32f444121336a521a293fa61", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0", - "phpstan/phpstan": "^1.12.5" - }, - "conflict": { - "rector/rector-doctrine": "*", - "rector/rector-downgrade-php": "*", - "rector/rector-phpunit": "*", - "rector/rector-symfony": "*" - }, - "suggest": { - "ext-dom": "To manipulate phpunit.xml via the custom-rule command" - }, - "bin": [ - "bin/rector" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Instant Upgrade and Automated Refactoring of any PHP code", - "keywords": [ - "automation", - "dev", - "migration", - "refactoring" - ], - "support": { - "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/1.2.10" - }, - "funding": [ - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2024-11-08T13:59:10+00:00" - }, { "name": "sebastian/cli-parser", "version": "3.0.2", @@ -14095,69 +14680,6 @@ ], "time": "2024-10-15T15:12:28+00:00" }, - { - "name": "spatie/backtrace", - "version": "1.6.2", - "source": { - "type": "git", - "url": "https://github.com/spatie/backtrace.git", - "reference": "1a9a145b044677ae3424693f7b06479fc8c137a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/backtrace/zipball/1a9a145b044677ae3424693f7b06479fc8c137a9", - "reference": "1a9a145b044677ae3424693f7b06479fc8c137a9", - "shasum": "" - }, - "require": { - "php": "^7.3|^8.0" - }, - "require-dev": { - "ext-json": "*", - "laravel/serializable-closure": "^1.3", - "phpunit/phpunit": "^9.3", - "spatie/phpunit-snapshot-assertions": "^4.2", - "symfony/var-dumper": "^5.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Spatie\\Backtrace\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van de Herten", - "email": "freek@spatie.be", - "homepage": "https://spatie.be", - "role": "Developer" - } - ], - "description": "A better backtrace", - "homepage": "https://github.com/spatie/backtrace", - "keywords": [ - "Backtrace", - "spatie" - ], - "support": { - "source": "https://github.com/spatie/backtrace/tree/1.6.2" - }, - "funding": [ - { - "url": "https://github.com/sponsors/spatie", - "type": "github" - }, - { - "url": "https://spatie.be/open-source/support-us", - "type": "other" - } - ], - "time": "2024-07-22T08:21:24+00:00" - }, { "name": "spatie/error-solutions", "version": "1.1.1", @@ -14475,178 +14997,6 @@ ], "time": "2024-06-12T15:01:18+00:00" }, - { - "name": "spatie/laravel-ray", - "version": "1.37.1", - "source": { - "type": "git", - "url": "https://github.com/spatie/laravel-ray.git", - "reference": "c2bedfd1172648df2c80aaceb2541d70f1d9a5b9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/c2bedfd1172648df2c80aaceb2541d70f1d9a5b9", - "reference": "c2bedfd1172648df2c80aaceb2541d70f1d9a5b9", - "shasum": "" - }, - "require": { - "ext-json": "*", - "illuminate/contracts": "^7.20|^8.19|^9.0|^10.0|^11.0", - "illuminate/database": "^7.20|^8.19|^9.0|^10.0|^11.0", - "illuminate/queue": "^7.20|^8.19|^9.0|^10.0|^11.0", - "illuminate/support": "^7.20|^8.19|^9.0|^10.0|^11.0", - "php": "^7.4|^8.0", - "rector/rector": "^0.19.2|^1.0", - "spatie/backtrace": "^1.0", - "spatie/ray": "^1.41.1", - "symfony/stopwatch": "4.2|^5.1|^6.0|^7.0", - "zbateson/mail-mime-parser": "^1.3.1|^2.0|^3.0" - }, - "require-dev": { - "guzzlehttp/guzzle": "^7.3", - "laravel/framework": "^7.20|^8.19|^9.0|^10.0|^11.0", - "orchestra/testbench-core": "^5.0|^6.0|^7.0|^8.0|^9.0", - "pestphp/pest": "^1.22|^2.0", - "phpstan/phpstan": "^1.10.57", - "phpunit/phpunit": "^9.3|^10.1", - "spatie/pest-plugin-snapshots": "^1.1|^2.0", - "symfony/var-dumper": "^4.2|^5.1|^6.0|^7.0.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - }, - "laravel": { - "providers": [ - "Spatie\\LaravelRay\\RayServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "Spatie\\LaravelRay\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://spatie.be", - "role": "Developer" - } - ], - "description": "Easily debug Laravel apps", - "homepage": "https://github.com/spatie/laravel-ray", - "keywords": [ - "laravel-ray", - "spatie" - ], - "support": { - "issues": "https://github.com/spatie/laravel-ray/issues", - "source": "https://github.com/spatie/laravel-ray/tree/1.37.1" - }, - "funding": [ - { - "url": "https://github.com/sponsors/spatie", - "type": "github" - }, - { - "url": "https://spatie.be/open-source/support-us", - "type": "other" - } - ], - "time": "2024-07-12T12:35:17+00:00" - }, - { - "name": "spatie/ray", - "version": "1.41.2", - "source": { - "type": "git", - "url": "https://github.com/spatie/ray.git", - "reference": "c44f8cfbf82c69909b505de61d8d3f2d324e93fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/ray/zipball/c44f8cfbf82c69909b505de61d8d3f2d324e93fc", - "reference": "c44f8cfbf82c69909b505de61d8d3f2d324e93fc", - "shasum": "" - }, - "require": { - "ext-curl": "*", - "ext-json": "*", - "php": "^7.3|^8.0", - "ramsey/uuid": "^3.0|^4.1", - "spatie/backtrace": "^1.1", - "spatie/macroable": "^1.0|^2.0", - "symfony/stopwatch": "^4.0|^5.1|^6.0|^7.0", - "symfony/var-dumper": "^4.2|^5.1|^6.0|^7.0.3" - }, - "require-dev": { - "illuminate/support": "6.x|^8.18|^9.0", - "nesbot/carbon": "^2.63", - "pestphp/pest": "^1.22", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.19.2", - "spatie/phpunit-snapshot-assertions": "^4.2", - "spatie/test-time": "^1.2" - }, - "bin": [ - "bin/remove-ray.sh" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "files": [ - "src/helpers.php" - ], - "psr-4": { - "Spatie\\Ray\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://spatie.be", - "role": "Developer" - } - ], - "description": "Debug with Ray to fix problems faster", - "homepage": "https://github.com/spatie/ray", - "keywords": [ - "ray", - "spatie" - ], - "support": { - "issues": "https://github.com/spatie/ray/issues", - "source": "https://github.com/spatie/ray/tree/1.41.2" - }, - "funding": [ - { - "url": "https://github.com/sponsors/spatie", - "type": "github" - }, - { - "url": "https://spatie.be/open-source/support-us", - "type": "other" - } - ], - "time": "2024-04-24T14:21:46+00:00" - }, { "name": "symfony/http-client", "version": "v7.1.8", @@ -14819,148 +15169,6 @@ ], "time": "2024-04-18T09:32:20+00:00" }, - { - "name": "symfony/polyfill-iconv", - "version": "v1.31.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-iconv.git", - "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/48becf00c920479ca2e910c22a5a39e5d47ca956", - "reference": "48becf00c920479ca2e910c22a5a39e5d47ca956", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "provide": { - "ext-iconv": "*" - }, - "suggest": { - "ext-iconv": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Iconv\\": "" - } - }, - "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 Iconv extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "iconv", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-iconv/tree/v1.31.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-09T11:45:10+00:00" - }, - { - "name": "symfony/stopwatch", - "version": "v7.1.6", - "source": { - "type": "git", - "url": "https://github.com/symfony/stopwatch.git", - "reference": "8b4a434e6e7faf6adedffb48783a5c75409a1a05" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/8b4a434e6e7faf6adedffb48783a5c75409a1a05", - "reference": "8b4a434e6e7faf6adedffb48783a5c75409a1a05", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/service-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Stopwatch\\": "" - }, - "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 way to profile code", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.1.6" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-25T14:20:29+00:00" - }, { "name": "ta-tikoma/phpunit-architecture-test", "version": "0.8.4", @@ -15069,214 +15277,6 @@ } ], "time": "2024-03-03T12:36:25+00:00" - }, - { - "name": "zbateson/mail-mime-parser", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/zbateson/mail-mime-parser.git", - "reference": "e0d4423fe27850c9dd301190767dbc421acc2f19" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zbateson/mail-mime-parser/zipball/e0d4423fe27850c9dd301190767dbc421acc2f19", - "reference": "e0d4423fe27850c9dd301190767dbc421acc2f19", - "shasum": "" - }, - "require": { - "guzzlehttp/psr7": "^2.5", - "php": ">=8.0", - "php-di/php-di": "^6.0|^7.0", - "psr/log": "^1|^2|^3", - "zbateson/mb-wrapper": "^2.0", - "zbateson/stream-decorators": "^2.1" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "*", - "monolog/monolog": "^2|^3", - "phpstan/phpstan": "*", - "phpunit/phpunit": "^9.6" - }, - "suggest": { - "ext-iconv": "For best support/performance", - "ext-mbstring": "For best support/performance" - }, - "type": "library", - "autoload": { - "psr-4": { - "ZBateson\\MailMimeParser\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Zaahid Bateson" - }, - { - "name": "Contributors", - "homepage": "https://github.com/zbateson/mail-mime-parser/graphs/contributors" - } - ], - "description": "MIME email message parser", - "homepage": "https://mail-mime-parser.org", - "keywords": [ - "MimeMailParser", - "email", - "mail", - "mailparse", - "mime", - "mimeparse", - "parser", - "php-imap" - ], - "support": { - "docs": "https://mail-mime-parser.org/#usage-guide", - "issues": "https://github.com/zbateson/mail-mime-parser/issues", - "source": "https://github.com/zbateson/mail-mime-parser" - }, - "funding": [ - { - "url": "https://github.com/zbateson", - "type": "github" - } - ], - "time": "2024-08-10T18:44:09+00:00" - }, - { - "name": "zbateson/mb-wrapper", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/zbateson/mb-wrapper.git", - "reference": "9e4373a153585d12b6c621ac4a6bb143264d4619" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zbateson/mb-wrapper/zipball/9e4373a153585d12b6c621ac4a6bb143264d4619", - "reference": "9e4373a153585d12b6c621ac4a6bb143264d4619", - "shasum": "" - }, - "require": { - "php": ">=8.0", - "symfony/polyfill-iconv": "^1.9", - "symfony/polyfill-mbstring": "^1.9" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "*", - "phpstan/phpstan": "*", - "phpunit/phpunit": "<10.0" - }, - "suggest": { - "ext-iconv": "For best support/performance", - "ext-mbstring": "For best support/performance" - }, - "type": "library", - "autoload": { - "psr-4": { - "ZBateson\\MbWrapper\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Zaahid Bateson" - } - ], - "description": "Wrapper for mbstring with fallback to iconv for encoding conversion and string manipulation", - "keywords": [ - "charset", - "encoding", - "http", - "iconv", - "mail", - "mb", - "mb_convert_encoding", - "mbstring", - "mime", - "multibyte", - "string" - ], - "support": { - "issues": "https://github.com/zbateson/mb-wrapper/issues", - "source": "https://github.com/zbateson/mb-wrapper/tree/2.0.0" - }, - "funding": [ - { - "url": "https://github.com/zbateson", - "type": "github" - } - ], - "time": "2024-03-20T01:38:07+00:00" - }, - { - "name": "zbateson/stream-decorators", - "version": "2.1.1", - "source": { - "type": "git", - "url": "https://github.com/zbateson/stream-decorators.git", - "reference": "32a2a62fb0f26313395c996ebd658d33c3f9c4e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/32a2a62fb0f26313395c996ebd658d33c3f9c4e5", - "reference": "32a2a62fb0f26313395c996ebd658d33c3f9c4e5", - "shasum": "" - }, - "require": { - "guzzlehttp/psr7": "^2.5", - "php": ">=8.0", - "zbateson/mb-wrapper": "^2.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "*", - "phpstan/phpstan": "*", - "phpunit/phpunit": "^9.6|^10.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "ZBateson\\StreamDecorators\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Zaahid Bateson" - } - ], - "description": "PHP psr7 stream decorators for mime message part streams", - "keywords": [ - "base64", - "charset", - "decorators", - "mail", - "mime", - "psr7", - "quoted-printable", - "stream", - "uuencode" - ], - "support": { - "issues": "https://github.com/zbateson/stream-decorators/issues", - "source": "https://github.com/zbateson/stream-decorators/tree/2.1.1" - }, - "funding": [ - { - "url": "https://github.com/zbateson", - "type": "github" - } - ], - "time": "2024-04-29T21:42:39+00:00" } ], "aliases": [], diff --git a/config/constants.php b/config/constants.php index 532feb56c..b29adfff3 100644 --- a/config/constants.php +++ b/config/constants.php @@ -2,9 +2,9 @@ return [ 'coolify' => [ - 'version' => '4.0.0-beta.368', + 'version' => '4.0.0-beta.372', 'self_hosted' => env('SELF_HOSTED', true), - 'autoupdate' => env('AUTOUPDATE', false), + 'autoupdate' => env('AUTOUPDATE'), 'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'), 'helper_image' => env('HELPER_IMAGE', 'ghcr.io/coollabsio/coolify-helper'), 'is_windows_docker_desktop' => env('IS_WINDOWS_DOCKER_DESKTOP', false), diff --git a/config/version.php b/config/version.php index ddb1cb354..21119de4a 100644 --- a/config/version.php +++ b/config/version.php @@ -1,3 +1,3 @@ getMessage()); + } + } + + public function down() + { + try { + DB::statement('DROP INDEX IF EXISTS idx_activity_type_uuid'); + DB::statement('ALTER TABLE activity_log ALTER COLUMN properties TYPE json USING properties::json'); + } catch (\Exception $e) { + Log::error('Error dropping index from activity_log: '.$e->getMessage()); + } + } +} diff --git a/database/seeders/ProductionSeeder.php b/database/seeders/ProductionSeeder.php index 8144a8b1a..7acdef548 100644 --- a/database/seeders/ProductionSeeder.php +++ b/database/seeders/ProductionSeeder.php @@ -22,9 +22,9 @@ class ProductionSeeder extends Seeder public function run(): void { if (isCloud()) { - echo "Running in cloud mode.\n"; + echo "[x]: Running in cloud mode.\n"; } else { - echo "Running in self-hosted mode.\n"; + echo "[x]: Running in self-hosted mode.\n"; } // Fix for 4.0.0-beta.37 diff --git a/docker/coolify-helper/Dockerfile b/docker/coolify-helper/Dockerfile index c375db5f8..741fff764 100644 --- a/docker/coolify-helper/Dockerfile +++ b/docker/coolify-helper/Dockerfile @@ -1,4 +1,5 @@ # Versions + # https://hub.docker.com/_/alpine ARG BASE_IMAGE=alpine:3.20 # https://download.docker.com/linux/static/stable/ diff --git a/docker/coolify-realtime/Dockerfile b/docker/coolify-realtime/Dockerfile index 9f94518f5..b9f3c1e62 100644 --- a/docker/coolify-realtime/Dockerfile +++ b/docker/coolify-realtime/Dockerfile @@ -1,5 +1,6 @@ FROM quay.io/soketi/soketi:1.6-16-alpine + ARG TARGETPLATFORM # https://github.com/cloudflare/cloudflared/releases ARG CLOUDFLARED_VERSION=2024.4.1 diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile index ca34bb05b..36be6cf06 100644 --- a/docker/prod/Dockerfile +++ b/docker/prod/Dockerfile @@ -57,13 +57,6 @@ RUN composer dump-autoload COPY --from=static-assets --chown=9999:9999 /app/public/build ./public/build COPY --chmod=755 docker/prod/etc/s6-overlay/ /etc/s6-overlay/ -RUN php artisan route:clear -RUN php artisan view:clear -RUN php artisan config:clear -RUN php artisan route:cache -RUN php artisan view:cache -RUN php artisan config:cache - RUN echo "alias ll='ls -al'" >>/etc/bash.bashrc RUN echo "alias a='php artisan'" >>/etc/bash.bashrc RUN echo "alias logs='tail -f storage/logs/laravel.log'" >>/etc/bash.bashrc @@ -86,4 +79,4 @@ RUN { \ } > /etc/php/current_version/cli/conf.d/upload-limits.ini COPY --from=minio-client /usr/bin/mc /usr/bin/mc -RUN chmod +x /usr/bin/mc \ No newline at end of file +RUN chmod +x /usr/bin/mc diff --git a/other/nightly/install.sh b/other/nightly/install.sh index 876e8c6e2..4a03a5c98 100755 --- a/other/nightly/install.sh +++ b/other/nightly/install.sh @@ -9,7 +9,7 @@ CDN="https://cdn.coollabs.io/coolify-nightly" DATE=$(date +"%Y%m%d-%H%M%S") VERSION="1.6" -DOCKER_VERSION="27.3" +DOCKER_VERSION="27.0" # TODO: Ask for a user CURRENT_USER=$USER diff --git a/resources/views/components/forms/checkbox.blade.php b/resources/views/components/forms/checkbox.blade.php index ef4d5a7f3..fb244962d 100644 --- a/resources/views/components/forms/checkbox.blade.php +++ b/resources/views/components/forms/checkbox.blade.php @@ -5,6 +5,7 @@ 'disabled' => false, 'instantSave' => false, 'value' => null, + 'checked' => false, 'hideLabel' => false, 'fullWidth' => false, ]) @@ -14,7 +15,9 @@ 'w-full' => $fullWidth, ])> @if (!$hideLabel) - $disabled])> + @if ($label) {!! $label !!} @@ -26,9 +29,10 @@ @endif @endif - merge(['class' => $defaultClass]) }} - @if ($instantSave) wire:loading.attr="disabled" wire:click='{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}' - wire:model={{ $id }} @else wire:model={{ $value ?? $id }} @endif /> + merge(['class' => $defaultClass]) }} + @if ($instantSave) wire:loading.attr="disabled" wire:click='{{ $instantSave === 'instantSave' || $instantSave == '1' ? 'instantSave' : $instantSave }}' + @if ($checked) checked @endif + wire:model={{ $id }} @else wire:model={{ $value ?? $id }} @endif /> @if (!$hideLabel) @endif diff --git a/resources/views/components/modal-input.blade.php b/resources/views/components/modal-input.blade.php index f396f399d..c090037d5 100644 --- a/resources/views/components/modal-input.blade.php +++ b/resources/views/components/modal-input.blade.php @@ -9,7 +9,7 @@ 'closeOutside' => true, ]) + class="relative w-auto h-auto" wire:ignore> @if ($content) {{ $content }} @@ -27,7 +27,7 @@ @endif + class="fixed top-0 left-0 lg:px-0 px-4 z-[99] flex items-center justify-center w-screen h-screen"> + href="{{ route('project.show', ['project_uuid' => data_get($resource, 'environment.project.uuid')]) }}"> {{ data_get($resource, 'environment.project.name', 'Undefined Name') }} @@ -21,7 +21,7 @@ {{ $this->parameters['environment_name'] }} + href="{{ route('project.resource.index', ['environment_name' => data_get($resource, 'environment.name'), 'project_uuid' => data_get($resource, 'environment.project.uuid')]) }}">{{ data_get($resource, 'environment.name') }} Private Key + @if (!$server->isLocalhost()) + Cloudflare + Tunnels + @endif @if ($server->isFunctional()) - @if (!$server->isLocalhost()) - Cloudflare - Tunnels - @endif Destinations diff --git a/resources/views/layouts/base.blade.php b/resources/views/layouts/base.blade.php index 8c5017e03..57f1807c8 100644 --- a/resources/views/layouts/base.blade.php +++ b/resources/views/layouts/base.blade.php @@ -34,11 +34,13 @@ @if (config('app.name') == 'Coolify Cloud') + @endif @auth + @endauth @section('body') diff --git a/resources/views/livewire/notifications/email.blade.php b/resources/views/livewire/notifications/email.blade.php index a2e5326c6..182c73d6a 100644 --- a/resources/views/livewire/notifications/email.blade.php +++ b/resources/views/livewire/notifications/email.blade.php @@ -16,9 +16,9 @@ @endif @if (isEmailEnabled($team) && auth()->user()->isAdminFromSession() && isTestEmailEnabled($team)) - - - + + + Send Email diff --git a/resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php b/resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php index d1f5d1bef..9d3af0b28 100644 --- a/resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php +++ b/resources/views/livewire/project/new/github-private-repository-deploy-key.blade.php @@ -8,7 +8,7 @@ @forelse ($private_keys as $key) @if ($private_key_id == $key->id) + wire:click="setPrivateKey('{{ $key->id }}')" wire:key="{{ $key->id }}"> {{ $key->name }} @@ -21,7 +21,7 @@ @else + wire:click="setPrivateKey('{{ $key->id }}')" wire:key="{{ $key->id }}"> {{ $key->name }} diff --git a/resources/views/livewire/project/new/select.blade.php b/resources/views/livewire/project/new/select.blade.php index bd9f0c627..78d3a3443 100644 --- a/resources/views/livewire/project/new/select.blade.php +++ b/resources/views/livewire/project/new/select.blade.php @@ -101,7 +101,11 @@ + :src='service.logo' + x-on:error.window="$event.target.src = service.logo_github_url" + onerror="this.onerror=null; this.src=this.getAttribute('data-fallback');" + x-on:error="$event.target.src = '/svgs/coolify.png'" + :data-fallback='service.logo_github_url' /> @@ -205,7 +209,7 @@ } } - @endif + @endif @if ($current_step === 'servers') Select a server diff --git a/resources/views/livewire/server/show.blade.php b/resources/views/livewire/server/show.blade.php index dcad8ac37..5aed0b4e2 100644 --- a/resources/views/livewire/server/show.blade.php +++ b/resources/views/livewire/server/show.blade.php @@ -219,12 +219,12 @@ + helper="Interval used for gathering metrics. Lower values result in more disk space usage." /> + required helper="Number of days to retain metrics data for." /> + helper="Interval at which metrics data is sent to the collector." /> @endif diff --git a/resources/views/livewire/settings/index.blade.php b/resources/views/livewire/settings/index.blade.php index 3d399c93f..888f11ffc 100644 --- a/resources/views/livewire/settings/index.blade.php +++ b/resources/views/livewire/settings/index.blade.php @@ -103,7 +103,7 @@ @if (!is_null(config('constants.coolify.autoupdate', null))) + disabled checked="{{ config('constants.coolify.autoupdate') }}" label="Auto Update Enabled" /> @else diff --git a/resources/views/livewire/upgrade.blade.php b/resources/views/livewire/upgrade.blade.php index 009eb2293..6e71ebbc0 100644 --- a/resources/views/livewire/upgrade.blade.php +++ b/resources/views/livewire/upgrade.blade.php @@ -54,6 +54,10 @@ Are you sure you would like to upgrade your instance to {{ $latestVersion }}? + + + Warning: Any deployments running during the update process will fail. Please ensure no deployments are in progress on any server before continuing. + You can review the changelogs here. diff --git a/scripts/install.sh b/scripts/install.sh index 1c031d2c5..3f1bec0c4 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -9,10 +9,54 @@ CDN="https://cdn.coollabs.io/coolify" DATE=$(date +"%Y%m%d-%H%M%S") VERSION="1.6" -DOCKER_VERSION="27.3" +DOCKER_VERSION="27.0" # TODO: Ask for a user CURRENT_USER=$USER +if [ $EUID != 0 ]; then + echo "Please run this script as root or with sudo" + exit +fi + +echo -e "Welcome to Coolify Installer!" +echo -e "This script will install everything for you. Sit back and relax." +echo -e "Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh\n" + +TOTAL_SPACE=$(df -BG / | awk 'NR==2 {print $2}' | sed 's/G//') +AVAILABLE_SPACE=$(df -BG / | awk 'NR==2 {print $4}' | sed 's/G//') +REQUIRED_TOTAL_SPACE=30 +REQUIRED_AVAILABLE_SPACE=20 +WARNING_SPACE=false + +if [ "$TOTAL_SPACE" -lt "$REQUIRED_TOTAL_SPACE" ]; then + WARNING_SPACE=true + cat << 'EOF' +WARNING: Insufficient total disk space! + +Total disk space: ${TOTAL_SPACE}GB +Required disk space: ${REQUIRED_TOTAL_SPACE}GB + +================== +EOF +fi + +if [ "$AVAILABLE_SPACE" -lt "$REQUIRED_AVAILABLE_SPACE" ]; then + cat << 'EOF' +WARNING: Insufficient available disk space! + +Available disk space: ${AVAILABLE_SPACE}GB +Required available space: ${REQUIRED_AVAILABLE_SPACE}GB + +================== +EOF + WARNING_SPACE=true +fi + +if [ "$WARNING_SPACE" = true ]; then + echo "Sleeping for 5 seconds." + sleep 5 +fi + mkdir -p /data/coolify/{source,ssh,applications,databases,backups,services,proxy,webhooks-during-maintenance,sentinel} mkdir -p /data/coolify/ssh/{keys,mux} mkdir -p /data/coolify/proxy/dynamic @@ -83,11 +127,6 @@ if [ -z "$LATEST_REALTIME_VERSION" ]; then fi -if [ $EUID != 0 ]; then - echo "Please run as root" - exit -fi - case "$OS_TYPE" in arch | ubuntu | debian | raspbian | centos | fedora | rhel | ol | rocky | sles | opensuse-leap | opensuse-tumbleweed | almalinux | amzn | alpine) ;; *) @@ -103,21 +142,8 @@ if [ "$1" != "" ]; then LATEST_VERSION="${LATEST_VERSION#v}" fi -echo -e "\033[0;35m" -cat << "EOF" - _____ _ _ __ - / ____| | (_)/ _| - | | ___ ___ | |_| |_ _ _ - | | / _ \ / _ \| | | _| | | | - | |___| (_) | (_) | | | | | |_| | - \_____\___/ \___/|_|_|_| \__, | - __/ | - |___/ -EOF -echo -e "\033[0m" -echo -e "Welcome to Coolify Installer!" -echo -e "This script will install everything for you. Sit back and relax." -echo -e "Source code: https://github.com/coollabsio/coolify/blob/main/scripts/install.sh\n" + + echo -e "---------------------------------------------" echo "| Operating System | $OS_TYPE $OS_VERSION" echo "| Docker | $DOCKER_VERSION" @@ -125,24 +151,24 @@ echo "| Coolify | $LATEST_VERSION" echo "| Helper | $LATEST_HELPER_VERSION" echo "| Realtime | $LATEST_REALTIME_VERSION" echo -e "---------------------------------------------\n" -echo -e "1. Installing required packages (curl, wget, git, jq). " +echo -e "1. Installing required packages (curl, wget, git, jq, openssl). " case "$OS_TYPE" in arch) - pacman -Sy --noconfirm --needed curl wget git jq >/dev/null || true + pacman -Sy --noconfirm --needed curl wget git jq openssl >/dev/null || true ;; alpine) sed -i '/^#.*\/community/s/^#//' /etc/apk/repositories apk update >/dev/null - apk add curl wget git jq >/dev/null + apk add curl wget git jq openssl >/dev/null ;; ubuntu | debian | raspbian) apt-get update -y >/dev/null - apt-get install -y curl wget git jq >/dev/null + apt-get install -y curl wget git jq openssl >/dev/null ;; centos | fedora | rhel | ol | rocky | almalinux | amzn) if [ "$OS_TYPE" = "amzn" ]; then - dnf install -y wget git jq >/dev/null + dnf install -y wget git jq openssl >/dev/null else if ! command -v dnf >/dev/null; then yum install -y dnf >/dev/null @@ -150,12 +176,12 @@ centos | fedora | rhel | ol | rocky | almalinux | amzn) if ! command -v curl >/dev/null; then dnf install -y curl >/dev/null fi - dnf install -y wget git jq >/dev/null + dnf install -y wget git jq openssl >/dev/null fi ;; sles | opensuse-leap | opensuse-tumbleweed) zypper refresh >/dev/null - zypper install -y curl wget git jq >/dev/null + zypper install -y curl wget git jq openssl >/dev/null ;; *) echo "This script only supports Debian, Redhat, Arch Linux, or SLES based operating systems for now." @@ -300,6 +326,22 @@ if ! [ -x "$(command -v docker)" ]; then exit 1 fi ;; + "fedora") + if [ -x "$(command -v dnf5)" ]; then + # dnf5 is available + dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo --overwrite >/dev/null 2>&1 + else + # dnf5 is not available, use dnf + dnf config-manager --add-repo=https://download.docker.com/linux/fedora/docker-ce.repo >/dev/null 2>&1 + fi + dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null 2>&1 + if ! [ -x "$(command -v docker)" ]; then + echo " - Docker could not be installed automatically. Please visit https://docs.docker.com/engine/install/ and install Docker manually to continue." + exit 1 + fi + systemctl start docker >/dev/null 2>&1 + systemctl enable docker >/dev/null 2>&1 + ;; *) if [ "$OS_TYPE" = "ubuntu" ] && [ "$OS_VERSION" = "24.10" ]; then echo "Docker automated installation is not supported on Ubuntu 24.10 (non-LTS release)." @@ -490,7 +532,21 @@ echo -e "\033[0;35m \____\___/|_| |_|\__, |_| \__,_|\__|\__,_|_|\__,_|\__|_|\___/|_| |_|___(_) |___/ \033[0m" -echo -e "\nYour instance is ready to use." -echo -e "Please visit http://$(curl -4s https://ifconfig.io):8000 to get started.\n" -echo -e "WARNING: We recommend you to backup your /data/coolify/source/.env file to a safe location, outside of this server." +echo -e "\nYour instance is ready to use!\n" +echo -e "You can access Coolify through your Public IP: http://$(curl -4s https://ifconfig.io):8000" + +set +e +DEFAULT_PRIVATE_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p') +PRIVATE_IPS=$(hostname -I) +set -e + +if [ -n "$PRIVATE_IPS" ]; then + echo -e "\nIf your Public IP is not accessible, you can use the following Private IPs:\n" + for IP in $PRIVATE_IPS; do + if [ "$IP" != "$DEFAULT_PRIVATE_IP" ]; then + echo -e "http://$IP:8000" + fi + done +fi +echo -e "\nWARNING: It is highly recommended to backup your Environment variables file (/data/coolify/source/.env) to a safe location, outside of this server (e.g. into a Password Manager).\n" cp /data/coolify/source/.env /data/coolify/source/.env.backup diff --git a/templates/compose/appwrite.yaml b/templates/compose/appwrite.yaml index 039d5b8ec..20d1f8f1f 100644 --- a/templates/compose/appwrite.yaml +++ b/templates/compose/appwrite.yaml @@ -47,7 +47,6 @@ services: - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} - _APP_DB_USER=$SERVICE_USER_MARIADB - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - - _APP_DB_ROOT_PASS=$SERVICE_PASSWORD_MARIADBROOT - _APP_SMTP_HOST=${_APP_SMTP_HOST} - _APP_SMTP_PORT=${_APP_SMTP_PORT} - _APP_SMTP_SECURE=${_APP_SMTP_SECURE} @@ -88,7 +87,6 @@ services: - _APP_FUNCTIONS_RUNTIMES=${_APP_FUNCTIONS_RUNTIMES:-node-20.0,php-8.2,python-3.11,ruby-3.2} - _APP_EXECUTOR_SECRET=$SERVICE_PASSWORD_64_APPWRITE - _APP_EXECUTOR_HOST=${_APP_EXECUTOR_HOST:-http://appwrite-executor/v1} - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - _APP_MAINTENANCE_INTERVAL=${_APP_MAINTENANCE_INTERVAL:-86400} - _APP_MAINTENANCE_DELAY=${_APP_MAINTENANCE_DELAY} @@ -112,13 +110,6 @@ services: - _APP_MIGRATIONS_FIREBASE_CLIENT_ID=${_APP_MIGRATIONS_FIREBASE_CLIENT_ID} - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET=${_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET} - _APP_ASSISTANT_OPENAI_API_KEY=${_APP_ASSISTANT_OPENAI_API_KEY} - - _APP_MESSAGE_SMS_TEST_DSN=${_APP_MESSAGE_SMS_TEST_DSN} - - _APP_MESSAGE_EMAIL_TEST_DSN=${_APP_MESSAGE_EMAIL_TEST_DSN} - - _APP_MESSAGE_PUSH_TEST_DSN=${_APP_MESSAGE_PUSH_TEST_DSN} - - _APP_CONSOLE_COUNTRIES_DENYLIST=${_APP_CONSOLE_COUNTRIES_DENYLIST} - - _APP_EXPERIMENT_LOGGING_PROVIDER=${_APP_EXPERIMENT_LOGGING_PROVIDER} - - _APP_EXPERIMENT_LOGGING_CONFIG=${_APP_EXPERIMENT_LOGGING_CONFIG} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-console: image: appwrite/console:5.0.12 @@ -149,9 +140,7 @@ services: - _APP_DB_USER=$SERVICE_USER_MARIADB - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - _APP_USAGE_STATS=${_APP_USAGE_STATS:-enabled} - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-worker-audits: image: appwrite/appwrite:1.6.0 @@ -173,9 +162,7 @@ services: - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} - _APP_DB_USER=$SERVICE_USER_MARIADB - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-worker-webhooks: image: appwrite/appwrite:1.6.0 @@ -189,14 +176,17 @@ services: - _APP_WORKER_PER_CORE=${_APP_WORKER_PER_CORE:-6} - _APP_OPENSSL_KEY_V1=$SERVICE_PASSWORD_64_APPWRITE - _APP_EMAIL_SECURITY=${_APP_EMAIL_SECURITY:-certs@appwrite.io} + - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS=${_APP_SYSTEM_SECURITY_EMAIL_ADDRESS} + - _APP_DB_HOST=${_APP_DB_HOST:-appwrite-mariadb} + - _APP_DB_PORT=${_APP_DB_PORT:-3306} + - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} + - _APP_DB_USER=$SERVICE_USER_MARIADB + - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - _APP_REDIS_HOST=${_APP_REDIS_HOST:-appwrite-redis} - _APP_REDIS_PORT=${_APP_REDIS_PORT:-6379} - _APP_REDIS_USER=${_APP_REDIS_USER} - _APP_REDIS_PASS=${_APP_REDIS_PASS} - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - - _APP_WEBHOOK_MAX_FAILED_ATTEMPTS=${_APP_WEBHOOK_MAX_FAILED_ATTEMPTS:-3} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-worker-deletes: image: appwrite/appwrite:1.6.0 @@ -245,11 +235,12 @@ services: - _APP_STORAGE_WASABI_SECRET=${_APP_STORAGE_WASABI_SECRET} - _APP_STORAGE_WASABI_REGION=${_APP_STORAGE_WASABI_REGION:-eu-central-1} - _APP_STORAGE_WASABI_BUCKET=${_APP_STORAGE_WASABI_BUCKET} - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - _APP_EXECUTOR_SECRET=$SERVICE_PASSWORD_64_APPWRITE - _APP_EXECUTOR_HOST=${_APP_EXECUTOR_HOST:-http://appwrite-executor/v1} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} + - _APP_MAINTENANCE_RETENTION_ABUSE=${_APP_MAINTENANCE_RETENTION_ABUSE:-86400} + - _APP_MAINTENANCE_RETENTION_AUDIT=${_APP_MAINTENANCE_RETENTION_AUDIT:-1209600} + - _APP_MAINTENANCE_RETENTION_EXECUTION=${_APP_MAINTENANCE_RETENTION_EXECUTION:-1209600} appwrite-worker-databases: image: appwrite/appwrite:1.6.0 @@ -271,11 +262,7 @@ services: - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} - _APP_DB_USER=$SERVICE_USER_MARIADB - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - - _APP_WORKERS_NUM=${_APP_WORKERS_NUM:-1} - - _APP_QUEUE_NAME=${_APP_QUEUE_NAME:-appwrite} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-worker-builds: image: appwrite/appwrite:1.6.0 @@ -302,7 +289,6 @@ services: - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} - _APP_DB_USER=$SERVICE_USER_MARIADB - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - _APP_VCS_GITHUB_APP_NAME=${_APP_VCS_GITHUB_APP_NAME} - _APP_VCS_GITHUB_PRIVATE_KEY=${_APP_VCS_GITHUB_PRIVATE_KEY} @@ -311,7 +297,9 @@ services: - _APP_FUNCTIONS_BUILD_TIMEOUT=${_APP_FUNCTIONS_BUILD_TIMEOUT:-900} - _APP_FUNCTIONS_CPUS=${_APP_FUNCTIONS_CPUS:-0} - _APP_FUNCTIONS_MEMORY=${_APP_FUNCTIONS_MEMORY:-0} + - _APP_FUNCTIONS_SIZE_LIMIT=${_APP_FUNCTIONS_SIZE_LIMIT:-30000000} - _APP_OPTIONS_FORCE_HTTPS=${_APP_OPTIONS_FORCE_HTTPS:-disabled} + - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS=${_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS:-disabled} - _APP_DOMAIN=$SERVICE_URL_APPWRITE - _APP_STORAGE_DEVICE=${_APP_STORAGE_DEVICE:-local} - _APP_STORAGE_S3_ACCESS_KEY=${_APP_STORAGE_S3_ACCESS_KEY:-local} @@ -334,7 +322,6 @@ services: - _APP_STORAGE_WASABI_SECRET=${_APP_STORAGE_WASABI_SECRET} - _APP_STORAGE_WASABI_REGION=${_APP_STORAGE_WASABI_REGION:-eu-central-1} - _APP_STORAGE_WASABI_BUCKET=${_APP_STORAGE_WASABI_BUCKET} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-worker-certificates: image: appwrite/appwrite:1.6.0 @@ -364,9 +351,7 @@ services: - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} - _APP_DB_USER=$SERVICE_USER_MARIADB - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-worker-functions: image: appwrite/appwrite:1.6.0 @@ -400,10 +385,7 @@ services: - _APP_USAGE_STATS=${_APP_USAGE_STATS:-enabled} - _APP_DOCKER_HUB_USERNAME=${_APP_DOCKER_HUB_USERNAME} - _APP_DOCKER_HUB_PASSWORD=${_APP_DOCKER_HUB_PASSWORD} - - _APP_DOCKER_HUB_EMAIL=${_APP_DOCKER_HUB_EMAIL} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-worker-mails: image: appwrite/appwrite:1.6.0 @@ -417,6 +399,11 @@ services: - _APP_OPENSSL_KEY_V1=$SERVICE_PASSWORD_64_APPWRITE - _APP_SYSTEM_EMAIL_NAME=${_APP_SYSTEM_EMAIL_NAME:-Appwrite} - _APP_SYSTEM_EMAIL_ADDRESS=${_APP_SYSTEM_EMAIL_ADDRESS:-team@appwrite.io} + - _APP_DB_HOST=${_APP_DB_HOST:-appwrite-mariadb} + - _APP_DB_PORT=${_APP_DB_PORT:-3306} + - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} + - _APP_DB_USER=$SERVICE_USER_MARIADB + - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - _APP_REDIS_HOST=${_APP_REDIS_HOST:-appwrite-redis} - _APP_REDIS_PORT=${_APP_REDIS_PORT:-6379} - _APP_REDIS_USER=${_APP_REDIS_USER} @@ -426,11 +413,8 @@ services: - _APP_SMTP_SECURE=${_APP_SMTP_SECURE} - _APP_SMTP_USERNAME=${_APP_SMTP_USERNAME} - _APP_SMTP_PASSWORD=${_APP_SMTP_PASSWORD} - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - _APP_DOMAIN=$SERVICE_URL_APPWRITE - - _APP_OPTIONS_FORCE_HTTPS=${_APP_OPTIONS_FORCE_HTTPS:-disabled} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-worker-messaging: image: appwrite/appwrite:1.6.0 @@ -453,11 +437,9 @@ services: - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} - _APP_DB_USER=$SERVICE_USER_MARIADB - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - _APP_SMS_FROM=${_APP_SMS_FROM} - _APP_SMS_PROVIDER=${_APP_SMS_PROVIDER} - - _APP_SMS_PROJECTS_DENY_LIST=${_APP_SMS_PROJECTS_DENY_LIST} - _APP_STORAGE_DEVICE=${_APP_STORAGE_DEVICE:-local} - _APP_STORAGE_S3_ACCESS_KEY=${_APP_STORAGE_S3_ACCESS_KEY} - _APP_STORAGE_S3_SECRET=${_APP_STORAGE_S3_SECRET} @@ -479,7 +461,6 @@ services: - _APP_STORAGE_WASABI_SECRET=${_APP_STORAGE_WASABI_SECRET} - _APP_STORAGE_WASABI_REGION=${_APP_STORAGE_WASABI_REGION:-eu-central-1} - _APP_STORAGE_WASABI_BUCKET=${_APP_STORAGE_WASABI_BUCKET} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-worker-migrations: image: appwrite/appwrite:1.6.0 @@ -503,16 +484,14 @@ services: - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} - _APP_DB_USER=$SERVICE_USER_MARIADB - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - _APP_MIGRATIONS_FIREBASE_CLIENT_ID=${_APP_MIGRATIONS_FIREBASE_CLIENT_ID} - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET=${_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} - appwrite-maintenance: + appwrite-task-maintenance: image: appwrite/appwrite:1.6.0 entrypoint: maintenance - container_name: appwrite-maintenance + container_name: appwrite-task-maintenance depends_on: - appwrite-redis environment: @@ -538,8 +517,6 @@ services: - _APP_MAINTENANCE_RETENTION_AUDIT=${_APP_MAINTENANCE_RETENTION_AUDIT:-1209600} - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY=${_APP_MAINTENANCE_RETENTION_USAGE_HOURLY:-8640000} - _APP_MAINTENANCE_RETENTION_SCHEDULES=${_APP_MAINTENANCE_RETENTION_SCHEDULES:-86400} - - _APP_MAINTENANCE_DELAY=${_APP_MAINTENANCE_DELAY} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-worker-usage: image: appwrite/appwrite:1.6.0 @@ -563,10 +540,8 @@ services: - _APP_REDIS_USER=${_APP_REDIS_USER} - _APP_REDIS_PASS=${_APP_REDIS_PASS} - _APP_USAGE_STATS=${_APP_USAGE_STATS:-enabled} - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - _APP_USAGE_AGGREGATION_INTERVAL=${_APP_USAGE_AGGREGATION_INTERVAL:-30} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-worker-usage-dump: image: appwrite/appwrite:1.6.0 @@ -589,10 +564,8 @@ services: - _APP_REDIS_USER=${_APP_REDIS_USER} - _APP_REDIS_PASS=${_APP_REDIS_PASS} - _APP_USAGE_STATS=${_APP_USAGE_STATS:-enabled} - - _APP_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - _APP_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - _APP_USAGE_AGGREGATION_INTERVAL=${_APP_USAGE_AGGREGATION_INTERVAL:-30} - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-task-scheduler-functions: image: appwrite/appwrite:1.6.0 @@ -614,7 +587,6 @@ services: - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} - _APP_DB_USER=$SERVICE_USER_MARIADB - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-task-scheduler-executions: image: appwrite/appwrite:1.6.0 @@ -636,7 +608,6 @@ services: - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} - _APP_DB_USER=$SERVICE_USER_MARIADB - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-task-scheduler-messages: image: appwrite/appwrite:1.6.0 @@ -658,13 +629,12 @@ services: - _APP_DB_SCHEMA=${_APP_DB_SCHEMA:-appwrite} - _APP_DB_USER=$SERVICE_USER_MARIADB - _APP_DB_PASS=$SERVICE_PASSWORD_MARIADB - - _APP_DATABASE_SHARED_TABLES=${_APP_DATABASE_SHARED_TABLES} appwrite-assistant: image: appwrite/assistant:0.4.0 container_name: appwrite-assistant environment: - - _APP_ASSISTANT_OPENAI_API_KEY + - _APP_ASSISTANT_OPENAI_API_KEY=${_APP_ASSISTANT_OPENAI_API_KEY} openruntimes-executor: container_name: openruntimes-executor @@ -687,8 +657,6 @@ services: - OPR_EXECUTOR_ENV=${_APP_ENV:-production} - OPR_EXECUTOR_RUNTIMES=${_APP_FUNCTIONS_RUNTIMES} - OPR_EXECUTOR_SECRET=$SERVICE_PASSWORD_64_APPWRITE - - OPR_EXECUTOR_RUNTIME_VERSIONS=v2,v4 - - OPR_EXECUTOR_LOGGING_PROVIDER=${_APP_LOGGING_PROVIDER} - OPR_EXECUTOR_LOGGING_CONFIG=${_APP_LOGGING_CONFIG} - OPR_EXECUTOR_STORAGE_DEVICE=${_APP_STORAGE_DEVICE:-local} - OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=${_APP_STORAGE_S3_ACCESS_KEY:-local} @@ -712,25 +680,6 @@ services: - OPR_EXECUTOR_STORAGE_WASABI_REGION=${_APP_STORAGE_WASABI_REGION} - OPR_EXECUTOR_STORAGE_WASABI_BUCKET=${_APP_STORAGE_WASABI_BUCKET} - openruntimes-proxy: - container_name: openruntimes-proxy - hostname: proxy - stop_signal: SIGINT - image: openruntimes/proxy:0.5.5 - networks: - - runtimes - environment: - - OPR_PROXY_WORKER_PER_CORE=${OPR_PROXY_WORKER_PER_CORE:-1} - - OPR_PROXY_ENV=${_APP_ENV:-production} - - OPR_PROXY_EXECUTOR_SECRET=$SERVICE_PASSWORD_64_APPWRITE - - OPR_PROXY_SECRET=$SERVICE_PASSWORD_64_APPWRITE - - OPR_PROXY_LOGGING_CONFIG=$_APP_LOGGING_CONFIG - - OPR_PROXY_ALGORITHM=random - - OPR_PROXY_EXECUTORS=exc1 - - OPR_PROXY_HEALTHCHECK_INTERVAL=10000 - - OPR_PROXY_MAX_TIMEOUT=600 - - OPR_PROXY_HEALTHCHECK=enabled - appwrite-mariadb: image: mariadb:10.11 container_name: appwrite-mariadb diff --git a/templates/compose/browserless.yaml b/templates/compose/browserless.yaml index 4be039afc..703aac636 100644 --- a/templates/compose/browserless.yaml +++ b/templates/compose/browserless.yaml @@ -9,7 +9,7 @@ services: image: ghcr.io/browserless/chromium environment: - SERVICE_FQDN_BROWSERLESS_3000 - - TOKEN=$SERVICE_BASE64_BROWSERLESS_TOKEN + - TOKEN=$SERVICE_PASSWORD_BROWSERLESS expose: - 3000 healthcheck: diff --git a/templates/compose/embystat.yaml b/templates/compose/embystat.yaml index 75d3484ed..e86052c1e 100644 --- a/templates/compose/embystat.yaml +++ b/templates/compose/embystat.yaml @@ -1,5 +1,5 @@ # documentation: https://github.com/mregni/EmbyStat -# slogan: EmnyStat is a web analytics tool, designed to provide insight into website traffic and user behavior. +# slogan: EmbyStat is a web analytics tool, designed to provide insight into website traffic and user behavior. # tags: media, server, movies, tv, music # port: 6555 diff --git a/templates/compose/heyform.yaml b/templates/compose/heyform.yaml index a92f14109..980671031 100644 --- a/templates/compose/heyform.yaml +++ b/templates/compose/heyform.yaml @@ -22,6 +22,7 @@ services: - MONGO_URI=mongodb://mongo:27017/heyform - REDIS_HOST=keydb - REDIS_PORT=6379 + - REDIS_PASSWORD=${SERVICE_PASSWORD_KEYDB} healthcheck: test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8000 || exit 1"] interval: 5s diff --git a/templates/compose/hoarder.yaml b/templates/compose/hoarder.yaml index 89002d759..4ce1c433f 100644 --- a/templates/compose/hoarder.yaml +++ b/templates/compose/hoarder.yaml @@ -16,6 +16,8 @@ services: - NEXTAUTH_URL=${SERVICE_FQDN_HOARDER} - MEILI_ADDR=http://meilisearch:7700 - BROWSER_WEB_URL=http://chrome:9222 + - OPENAI_API_KEY=${SERVICE_OPENAI_API_KEY} + - DISABLE_SIGNUPS=${SERVICE_DISABLE_SIGNUPS} - DATA_DIR=/data chrome: @@ -41,4 +43,4 @@ services: test: ["CMD", "curl", "-f", "http://127.0.0.1:7700/health"] interval: 2s timeout: 10s - retries: 15 \ No newline at end of file + retries: 15 diff --git a/templates/compose/mailpit.yaml b/templates/compose/mailpit.yaml index 96aacd7bc..c136696a9 100644 --- a/templates/compose/mailpit.yaml +++ b/templates/compose/mailpit.yaml @@ -7,6 +7,8 @@ services: mailpit: image: axllent/mailpit + ports: + - 1025:1025 volumes: - "mailpit-data:/data" - type: bind diff --git a/templates/service-templates.json b/templates/service-templates.json index fc3cbe452..974af5eee 100644 --- a/templates/service-templates.json +++ b/templates/service-templates.json @@ -79,7 +79,7 @@ "appwrite": { "documentation": "https://appwrite.io?utm_source=coolify.io", "slogan": "A backend-as-a-service platform that simplifies the web & mobile app development.", - "compose": "c2VydmljZXM6CiAgYXBwd3JpdGU6CiAgICBpbWFnZTogJ2FwcHdyaXRlL2FwcHdyaXRlOjEuNi4wJwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlCiAgICB2b2x1bWVzOgogICAgICAtICdhcHB3cml0ZS11cGxvYWRzOi9zdG9yYWdlL3VwbG9hZHM6cncnCiAgICAgIC0gJ2FwcHdyaXRlLWNhY2hlOi9zdG9yYWdlL2NhY2hlOnJ3JwogICAgICAtICdhcHB3cml0ZS1jb25maWc6L3N0b3JhZ2UvY29uZmlnOnJ3JwogICAgICAtICdhcHB3cml0ZS1jZXJ0aWZpY2F0ZXM6L3N0b3JhZ2UvY2VydGlmaWNhdGVzOnJ3JwogICAgICAtICdhcHB3cml0ZS1mdW5jdGlvbnM6L3N0b3JhZ2UvZnVuY3Rpb25zOnJ3JwogICAgZGVwZW5kc19vbjoKICAgICAgLSBhcHB3cml0ZS1tYXJpYWRiCiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9BUFBXUklURT0vCiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSAnX0FQUF9MT0NBTEU9JHtfQVBQX0xPQ0FMRTotZW59JwogICAgICAtICdfQVBQX0NPTlNPTEVfV0hJVEVMSVNUX1JPT1Q9JHtfQVBQX0NPTlNPTEVfV0hJVEVMSVNUX1JPT1Q6LWVuYWJsZWR9JwogICAgICAtICdfQVBQX0NPTlNPTEVfV0hJVEVMSVNUX0VNQUlMUz0ke19BUFBfQ09OU09MRV9XSElURUxJU1RfRU1BSUxTfScKICAgICAgLSAnX0FQUF9DT05TT0xFX1dISVRFTElTVF9JUFM9JHtfQVBQX0NPTlNPTEVfV0hJVEVMSVNUX0lQU30nCiAgICAgIC0gJ19BUFBfQ09OU09MRV9IT1NUTkFNRVM9JHtfQVBQX0NPTlNPTEVfSE9TVE5BTUVTOi1sb2NhbGhvc3QsYXBwd3JpdGUuaW8sKi5hcHB3cml0ZS5pb30nCiAgICAgIC0gJ19BUFBfU1lTVEVNX0VNQUlMX05BTUU9JHtfQVBQX1NZU1RFTV9FTUFJTF9OQU1FOi1BcHB3cml0ZX0nCiAgICAgIC0gJ19BUFBfU1lTVEVNX0VNQUlMX0FERFJFU1M9JHtfQVBQX1NZU1RFTV9FTUFJTF9BRERSRVNTOi10ZWFtQGFwcHdyaXRlLmlvfScKICAgICAgLSAnX0FQUF9TWVNURU1fVEVBTV9FTUFJTD0ke19BUFBfU1lTVEVNX1RFQU1fRU1BSUw6LXRlYW1AYXBwd3JpdGUuaW99JwogICAgICAtICdfQVBQX0VNQUlMX1NFQ1VSSVRZPSR7X0FQUF9FTUFJTF9TRUNVUklUWTotY2VydHNAYXBwd3JpdGUuaW99JwogICAgICAtICdfQVBQX1NZU1RFTV9SRVNQT05TRV9GT1JNQVQ9JHtfQVBQX1NZU1RFTV9SRVNQT05TRV9GT1JNQVR9JwogICAgICAtICdfQVBQX09QVElPTlNfQUJVU0U9JHtfQVBQX09QVElPTlNfQUJVU0U6LWVuYWJsZWR9JwogICAgICAtICdfQVBQX09QVElPTlNfUk9VVEVSX1BST1RFQ1RJT049JHtfQVBQX09QVElPTlNfUk9VVEVSX1BST1RFQ1RJT046LWRpc2FibGVkfScKICAgICAgLSAnX0FQUF9PUFRJT05TX0ZPUkNFX0hUVFBTPSR7X0FQUF9PUFRJT05TX0ZPUkNFX0hUVFBTOi1kaXNhYmxlZH0nCiAgICAgIC0gJ19BUFBfT1BUSU9OU19GVU5DVElPTlNfRk9SQ0VfSFRUUFM9JHtfQVBQX09QVElPTlNfRlVOQ1RJT05TX0ZPUkNFX0hUVFBTOi1kaXNhYmxlZH0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOPSRTRVJWSUNFX1VSTF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOX1RBUkdFVD0kU0VSVklDRV9VUkxfQVBQV1JJVEUKICAgICAgLSBfQVBQX0RPTUFJTl9GVU5DVElPTlM9JFNFUlZJQ0VfVVJMX0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gX0FQUF9EQl9ST09UX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQlJPT1QKICAgICAgLSAnX0FQUF9TTVRQX0hPU1Q9JHtfQVBQX1NNVFBfSE9TVH0nCiAgICAgIC0gJ19BUFBfU01UUF9QT1JUPSR7X0FQUF9TTVRQX1BPUlR9JwogICAgICAtICdfQVBQX1NNVFBfU0VDVVJFPSR7X0FQUF9TTVRQX1NFQ1VSRX0nCiAgICAgIC0gJ19BUFBfU01UUF9VU0VSTkFNRT0ke19BUFBfU01UUF9VU0VSTkFNRX0nCiAgICAgIC0gJ19BUFBfU01UUF9QQVNTV09SRD0ke19BUFBfU01UUF9QQVNTV09SRH0nCiAgICAgIC0gJ19BUFBfVVNBR0VfU1RBVFM9JHtfQVBQX1VTQUdFX1NUQVRTOi1lbmFibGVkfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTUlUPSR7X0FQUF9TVE9SQUdFX0xJTUlUOi0zMDAwMDAwMH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9QUkVWSUVXX0xJTUlUPSR7X0FQUF9TVE9SQUdFX1BSRVZJRVdfTElNSVQ6LTIwMDAwMDAwfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0FOVElWSVJVUz0ke19BUFBfU1RPUkFHRV9BTlRJVklSVVM6LWRpc2FibGVkfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0FOVElWSVJVU19IT1NUPSR7X0FQUF9TVE9SQUdFX0FOVElWSVJVU19IT1NUOi1hcHB3cml0ZS1jbGFtYXZ9JwogICAgICAtICdfQVBQX1NUT1JBR0VfQU5USVZJUlVTX1BPUlQ9JHtfQVBQX1NUT1JBR0VfQU5USVZJUlVTX1BPUlQ6LTMzMTB9JwogICAgICAtICdfQVBQX1NUT1JBR0VfREVWSUNFPSR7X0FQUF9TVE9SQUdFX0RFVklDRTotbG9jYWx9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUzNfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9TM19BQ0NFU1NfS0VZfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9TM19TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUzNfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX1MzX1JFR0lPTjotdXMtZWFzdC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9TM19CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19SRUdJT049JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1JFR0lPTjotdXMtZWFzdC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfUkVHSU9OOi11cy13ZXN0LTAwNH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfTElOT0RFX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9MSU5PREVfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9SRUdJT049JHtfQVBQX1NUT1JBR0VfTElOT0RFX1JFR0lPTjotZXUtY2VudHJhbC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfTElOT0RFX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9XQVNBQklfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9XQVNBQklfUkVHSU9OOi1ldS1jZW50cmFsLTF9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9XQVNBQklfQlVDS0VUfScKICAgICAgLSAnX0FQUF9GVU5DVElPTlNfU0laRV9MSU1JVD0ke19BUFBfRlVOQ1RJT05TX1NJWkVfTElNSVQ6LTMwMDAwMDAwfScKICAgICAgLSAnX0FQUF9GVU5DVElPTlNfVElNRU9VVD0ke19BUFBfRlVOQ1RJT05TX1RJTUVPVVQ6LTkwMH0nCiAgICAgIC0gJ19BUFBfRlVOQ1RJT05TX0JVSUxEX1RJTUVPVVQ9JHtfQVBQX0ZVTkNUSU9OU19CVUlMRF9USU1FT1VUOi05MDB9JwogICAgICAtICdfQVBQX0ZVTkNUSU9OU19DUFVTPSR7X0FQUF9GVU5DVElPTlNfQ1BVUzotMH0nCiAgICAgIC0gJ19BUFBfRlVOQ1RJT05TX01FTU9SWT0ke19BUFBfRlVOQ1RJT05TX01FTU9SWTotMH0nCiAgICAgIC0gJ19BUFBfRlVOQ1RJT05TX1JVTlRJTUVTPSR7X0FQUF9GVU5DVElPTlNfUlVOVElNRVM6LW5vZGUtMjAuMCxwaHAtOC4yLHB5dGhvbi0zLjExLHJ1YnktMy4yfScKICAgICAgLSBfQVBQX0VYRUNVVE9SX1NFQ1JFVD0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX0VYRUNVVE9SX0hPU1Q9JHtfQVBQX0VYRUNVVE9SX0hPU1Q6LWh0dHA6Ly9hcHB3cml0ZS1leGVjdXRvci92MX0nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19QUk9WSURFUj0ke19BUFBfTE9HR0lOR19QUk9WSURFUn0nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19DT05GSUc9JHtfQVBQX0xPR0dJTkdfQ09ORklHfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9JTlRFUlZBTD0ke19BUFBfTUFJTlRFTkFOQ0VfSU5URVJWQUw6LTg2NDAwfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9ERUxBWT0ke19BUFBfTUFJTlRFTkFOQ0VfREVMQVl9JwogICAgICAtICdfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9FWEVDVVRJT049JHtfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9FWEVDVVRJT046LTEyMDk2MDB9JwogICAgICAtICdfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9DQUNIRT0ke19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX0NBQ0hFOi0yNTkyMDAwfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQUJVU0U9JHtfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9BQlVTRTotODY0MDB9JwogICAgICAtICdfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9BVURJVD0ke19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX0FVRElUOi0xMjA5NjAwfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fVVNBR0VfSE9VUkxZPSR7X0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fVVNBR0VfSE9VUkxZOi04NjQwMDAwfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fU0NIRURVTEVTPSR7X0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fU0NIRURVTEVTOi04NjQwMH0nCiAgICAgIC0gJ19BUFBfU01TX1BST1ZJREVSPSR7X0FQUF9TTVNfUFJPVklERVJ9JwogICAgICAtICdfQVBQX1NNU19GUk9NPSR7X0FQUF9TTVNfRlJPTX0nCiAgICAgIC0gJ19BUFBfR1JBUEhRTF9NQVhfQkFUQ0hfU0laRT0ke19BUFBfR1JBUEhRTF9NQVhfQkFUQ0hfU0laRTotMTB9JwogICAgICAtICdfQVBQX0dSQVBIUUxfTUFYX0NPTVBMRVhJVFk9JHtfQVBQX0dSQVBIUUxfTUFYX0NPTVBMRVhJVFk6LTI1MH0nCiAgICAgIC0gJ19BUFBfR1JBUEhRTF9NQVhfREVQVEg9JHtfQVBQX0dSQVBIUUxfTUFYX0RFUFRIOi0zfScKICAgICAgLSAnX0FQUF9WQ1NfR0lUSFVCX0FQUF9OQU1FPSR7X0FQUF9WQ1NfR0lUSFVCX0FQUF9OQU1FfScKICAgICAgLSAnX0FQUF9WQ1NfR0lUSFVCX1BSSVZBVEVfS0VZPSR7X0FQUF9WQ1NfR0lUSFVCX1BSSVZBVEVfS0VZfScKICAgICAgLSAnX0FQUF9WQ1NfR0lUSFVCX0FQUF9JRD0ke19BUFBfVkNTX0dJVEhVQl9BUFBfSUR9JwogICAgICAtICdfQVBQX1ZDU19HSVRIVUJfV0VCSE9PS19TRUNSRVQ9JHtfQVBQX1ZDU19HSVRIVUJfV0VCSE9PS19TRUNSRVR9JwogICAgICAtICdfQVBQX1ZDU19HSVRIVUJfQ0xJRU5UX1NFQ1JFVD0ke19BUFBfVkNTX0dJVEhVQl9DTElFTlRfU0VDUkVUfScKICAgICAgLSAnX0FQUF9WQ1NfR0lUSFVCX0NMSUVOVF9JRD0ke19BUFBfVkNTX0dJVEhVQl9DTElFTlRfSUR9JwogICAgICAtICdfQVBQX01JR1JBVElPTlNfRklSRUJBU0VfQ0xJRU5UX0lEPSR7X0FQUF9NSUdSQVRJT05TX0ZJUkVCQVNFX0NMSUVOVF9JRH0nCiAgICAgIC0gJ19BUFBfTUlHUkFUSU9OU19GSVJFQkFTRV9DTElFTlRfU0VDUkVUPSR7X0FQUF9NSUdSQVRJT05TX0ZJUkVCQVNFX0NMSUVOVF9TRUNSRVR9JwogICAgICAtICdfQVBQX0FTU0lTVEFOVF9PUEVOQUlfQVBJX0tFWT0ke19BUFBfQVNTSVNUQU5UX09QRU5BSV9BUElfS0VZfScKICAgICAgLSAnX0FQUF9NRVNTQUdFX1NNU19URVNUX0RTTj0ke19BUFBfTUVTU0FHRV9TTVNfVEVTVF9EU059JwogICAgICAtICdfQVBQX01FU1NBR0VfRU1BSUxfVEVTVF9EU049JHtfQVBQX01FU1NBR0VfRU1BSUxfVEVTVF9EU059JwogICAgICAtICdfQVBQX01FU1NBR0VfUFVTSF9URVNUX0RTTj0ke19BUFBfTUVTU0FHRV9QVVNIX1RFU1RfRFNOfScKICAgICAgLSAnX0FQUF9DT05TT0xFX0NPVU5UUklFU19ERU5ZTElTVD0ke19BUFBfQ09OU09MRV9DT1VOVFJJRVNfREVOWUxJU1R9JwogICAgICAtICdfQVBQX0VYUEVSSU1FTlRfTE9HR0lOR19QUk9WSURFUj0ke19BUFBfRVhQRVJJTUVOVF9MT0dHSU5HX1BST1ZJREVSfScKICAgICAgLSAnX0FQUF9FWFBFUklNRU5UX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9FWFBFUklNRU5UX0xPR0dJTkdfQ09ORklHfScKICAgICAgLSAnX0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTPSR7X0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTfScKICBhcHB3cml0ZS1jb25zb2xlOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9jb25zb2xlOjUuMC4xMicKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS1jb25zb2xlCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fQVBQV1JJVEU9L2NvbnNvbGUKICBhcHB3cml0ZS1yZWFsdGltZToKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiByZWFsdGltZQogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXJlYWx0aW1lCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLW1hcmlhZGIKICAgICAgLSBhcHB3cml0ZS1yZWRpcwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0FQUFdSSVRFPS92MS9yZWFsdGltZQogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gJ19BUFBfT1BUSU9OU19BQlVTRT0ke19BUFBfT1BUSU9OU19BQlVTRTotZW5hYmxlZH0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtICdfQVBQX1VTQUdFX1NUQVRTPSR7X0FQUF9VU0FHRV9TVEFUUzotZW5hYmxlZH0nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19QUk9WSURFUj0ke19BUFBfTE9HR0lOR19QUk9WSURFUn0nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19DT05GSUc9JHtfQVBQX0xPR0dJTkdfQ09ORklHfScKICAgICAgLSAnX0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTPSR7X0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTfScKICBhcHB3cml0ZS13b3JrZXItYXVkaXRzOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHdvcmtlci1hdWRpdHMKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS13b3JrZXItYXVkaXRzCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICAgIC0gYXBwd3JpdGUtbWFyaWFkYgogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gJ19BUFBfTE9HR0lOR19QUk9WSURFUj0ke19BUFBfTE9HR0lOR19QUk9WSURFUn0nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19DT05GSUc9JHtfQVBQX0xPR0dJTkdfQ09ORklHfScKICAgICAgLSAnX0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTPSR7X0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTfScKICBhcHB3cml0ZS13b3JrZXItd2ViaG9va3M6CiAgICBpbWFnZTogJ2FwcHdyaXRlL2FwcHdyaXRlOjEuNi4wJwogICAgZW50cnlwb2ludDogd29ya2VyLXdlYmhvb2tzCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtd29ya2VyLXdlYmhvb2tzCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICAgIC0gYXBwd3JpdGUtbWFyaWFkYgogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfRU1BSUxfU0VDVVJJVFk9JHtfQVBQX0VNQUlMX1NFQ1VSSVRZOi1jZXJ0c0BhcHB3cml0ZS5pb30nCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0xPR0dJTkdfUFJPVklERVI9JHtfQVBQX0xPR0dJTkdfUFJPVklERVJ9JwogICAgICAtICdfQVBQX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgICAgIC0gJ19BUFBfV0VCSE9PS19NQVhfRkFJTEVEX0FUVEVNUFRTPSR7X0FQUF9XRUJIT09LX01BWF9GQUlMRURfQVRURU1QVFM6LTN9JwogICAgICAtICdfQVBQX0RBVEFCQVNFX1NIQVJFRF9UQUJMRVM9JHtfQVBQX0RBVEFCQVNFX1NIQVJFRF9UQUJMRVN9JwogIGFwcHdyaXRlLXdvcmtlci1kZWxldGVzOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHdvcmtlci1kZWxldGVzCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtd29ya2VyLWRlbGV0ZXMKICAgIGRlcGVuZHNfb246CiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgICAgLSBhcHB3cml0ZS1tYXJpYWRiCiAgICB2b2x1bWVzOgogICAgICAtICdhcHB3cml0ZS11cGxvYWRzOi9zdG9yYWdlL3VwbG9hZHM6cncnCiAgICAgIC0gJ2FwcHdyaXRlLWNhY2hlOi9zdG9yYWdlL2NhY2hlOnJ3JwogICAgICAtICdhcHB3cml0ZS1mdW5jdGlvbnM6L3N0b3JhZ2UvZnVuY3Rpb25zOnJ3JwogICAgICAtICdhcHB3cml0ZS1idWlsZHM6L3N0b3JhZ2UvYnVpbGRzOnJ3JwogICAgICAtICdhcHB3cml0ZS1jZXJ0aWZpY2F0ZXM6L3N0b3JhZ2UvY2VydGlmaWNhdGVzOnJ3JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9ERVZJQ0U9JHtfQVBQX1NUT1JBR0VfREVWSUNFOi1sb2NhbH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9TM19BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX1MzX0FDQ0VTU19LRVk6LWxvY2FsfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9TM19TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUzNfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX1MzX1JFR0lPTjotdXMtZWFzdC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9TM19CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19SRUdJT049JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1JFR0lPTjotdXMtZWFzdC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfUkVHSU9OOi11cy13ZXN0LTAwNH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfTElOT0RFX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9MSU5PREVfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9SRUdJT049JHtfQVBQX1NUT1JBR0VfTElOT0RFX1JFR0lPTjotZXUtY2VudHJhbC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfTElOT0RFX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9XQVNBQklfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9XQVNBQklfUkVHSU9OOi1ldS1jZW50cmFsLTF9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9XQVNBQklfQlVDS0VUfScKICAgICAgLSAnX0FQUF9MT0dHSU5HX1BST1ZJREVSPSR7X0FQUF9MT0dHSU5HX1BST1ZJREVSfScKICAgICAgLSAnX0FQUF9MT0dHSU5HX0NPTkZJRz0ke19BUFBfTE9HR0lOR19DT05GSUd9JwogICAgICAtIF9BUFBfRVhFQ1VUT1JfU0VDUkVUPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfRVhFQ1VUT1JfSE9TVD0ke19BUFBfRVhFQ1VUT1JfSE9TVDotaHR0cDovL2FwcHdyaXRlLWV4ZWN1dG9yL3YxfScKICAgICAgLSAnX0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTPSR7X0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTfScKICBhcHB3cml0ZS13b3JrZXItZGF0YWJhc2VzOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHdvcmtlci1kYXRhYmFzZXMKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS13b3JrZXItZGF0YWJhc2VzCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICAgIC0gYXBwd3JpdGUtbWFyaWFkYgogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gJ19BUFBfTE9HR0lOR19QUk9WSURFUj0ke19BUFBfTE9HR0lOR19QUk9WSURFUn0nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19DT05GSUc9JHtfQVBQX0xPR0dJTkdfQ09ORklHfScKICAgICAgLSAnX0FQUF9XT1JLRVJTX05VTT0ke19BUFBfV09SS0VSU19OVU06LTF9JwogICAgICAtICdfQVBQX1FVRVVFX05BTUU9JHtfQVBQX1FVRVVFX05BTUU6LWFwcHdyaXRlfScKICAgICAgLSAnX0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTPSR7X0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTfScKICBhcHB3cml0ZS13b3JrZXItYnVpbGRzOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHdvcmtlci1idWlsZHMKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS13b3JrZXItYnVpbGRzCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICAgIC0gYXBwd3JpdGUtbWFyaWFkYgogICAgdm9sdW1lczoKICAgICAgLSAnYXBwd3JpdGUtZnVuY3Rpb25zOi9zdG9yYWdlL2Z1bmN0aW9uczpydycKICAgICAgLSAnYXBwd3JpdGUtYnVpbGRzOi9zdG9yYWdlL2J1aWxkczpydycKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtIF9BUFBfRVhFQ1VUT1JfU0VDUkVUPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfRVhFQ1VUT1JfSE9TVD0ke19BUFBfRVhFQ1VUT1JfSE9TVDotaHR0cDovL2FwcHdyaXRlLWV4ZWN1dG9yL3YxfScKICAgICAgLSAnX0FQUF9SRURJU19IT1NUPSR7X0FQUF9SRURJU19IT1NUOi1hcHB3cml0ZS1yZWRpc30nCiAgICAgIC0gJ19BUFBfUkVESVNfUE9SVD0ke19BUFBfUkVESVNfUE9SVDotNjM3OX0nCiAgICAgIC0gJ19BUFBfUkVESVNfVVNFUj0ke19BUFBfUkVESVNfVVNFUn0nCiAgICAgIC0gJ19BUFBfUkVESVNfUEFTUz0ke19BUFBfUkVESVNfUEFTU30nCiAgICAgIC0gJ19BUFBfREJfSE9TVD0ke19BUFBfREJfSE9TVDotYXBwd3JpdGUtbWFyaWFkYn0nCiAgICAgIC0gJ19BUFBfREJfUE9SVD0ke19BUFBfREJfUE9SVDotMzMwNn0nCiAgICAgIC0gJ19BUFBfREJfU0NIRU1BPSR7X0FQUF9EQl9TQ0hFTUE6LWFwcHdyaXRlfScKICAgICAgLSBfQVBQX0RCX1VTRVI9JFNFUlZJQ0VfVVNFUl9NQVJJQURCCiAgICAgIC0gX0FQUF9EQl9QQVNTPSRTRVJWSUNFX1BBU1NXT1JEX01BUklBREIKICAgICAgLSAnX0FQUF9MT0dHSU5HX1BST1ZJREVSPSR7X0FQUF9MT0dHSU5HX1BST1ZJREVSfScKICAgICAgLSAnX0FQUF9MT0dHSU5HX0NPTkZJRz0ke19BUFBfTE9HR0lOR19DT05GSUd9JwogICAgICAtICdfQVBQX1ZDU19HSVRIVUJfQVBQX05BTUU9JHtfQVBQX1ZDU19HSVRIVUJfQVBQX05BTUV9JwogICAgICAtICdfQVBQX1ZDU19HSVRIVUJfUFJJVkFURV9LRVk9JHtfQVBQX1ZDU19HSVRIVUJfUFJJVkFURV9LRVl9JwogICAgICAtICdfQVBQX1ZDU19HSVRIVUJfQVBQX0lEPSR7X0FQUF9WQ1NfR0lUSFVCX0FQUF9JRH0nCiAgICAgIC0gJ19BUFBfRlVOQ1RJT05TX1RJTUVPVVQ9JHtfQVBQX0ZVTkNUSU9OU19USU1FT1VUOi05MDB9JwogICAgICAtICdfQVBQX0ZVTkNUSU9OU19CVUlMRF9USU1FT1VUPSR7X0FQUF9GVU5DVElPTlNfQlVJTERfVElNRU9VVDotOTAwfScKICAgICAgLSAnX0FQUF9GVU5DVElPTlNfQ1BVUz0ke19BUFBfRlVOQ1RJT05TX0NQVVM6LTB9JwogICAgICAtICdfQVBQX0ZVTkNUSU9OU19NRU1PUlk9JHtfQVBQX0ZVTkNUSU9OU19NRU1PUlk6LTB9JwogICAgICAtICdfQVBQX09QVElPTlNfRk9SQ0VfSFRUUFM9JHtfQVBQX09QVElPTlNfRk9SQ0VfSFRUUFM6LWRpc2FibGVkfScKICAgICAgLSBfQVBQX0RPTUFJTj0kU0VSVklDRV9VUkxfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RFVklDRT0ke19BUFBfU1RPUkFHRV9ERVZJQ0U6LWxvY2FsfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfUzNfQUNDRVNTX0tFWTotbG9jYWx9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUzNfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX1MzX1NFQ1JFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9TM19SRUdJT049JHtfQVBQX1NUT1JBR0VfUzNfUkVHSU9OOi11cy1lYXN0LTF9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUzNfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX1MzX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9ET19TUEFDRVNfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9ET19TUEFDRVNfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX0RPX1NQQUNFU19TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfUkVHSU9OOi11cy1lYXN0LTF9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfQlVDS0VUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9BQ0NFU1NfS0VZfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX1NFQ1JFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9SRUdJT046LXVzLXdlc3QtMDA0fScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9MSU5PREVfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9MSU5PREVfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9MSU5PREVfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX0xJTk9ERV9TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9MSU5PREVfUkVHSU9OOi1ldS1jZW50cmFsLTF9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9MSU5PREVfQlVDS0VUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1dBU0FCSV9BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9BQ0NFU1NfS0VZfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1dBU0FCSV9TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfV0FTQUJJX1NFQ1JFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9SRUdJT046LWV1LWNlbnRyYWwtMX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9CVUNLRVR9JwogICAgICAtICdfQVBQX0RBVEFCQVNFX1NIQVJFRF9UQUJMRVM9JHtfQVBQX0RBVEFCQVNFX1NIQVJFRF9UQUJMRVN9JwogIGFwcHdyaXRlLXdvcmtlci1jZXJ0aWZpY2F0ZXM6CiAgICBpbWFnZTogJ2FwcHdyaXRlL2FwcHdyaXRlOjEuNi4wJwogICAgZW50cnlwb2ludDogd29ya2VyLWNlcnRpZmljYXRlcwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXdvcmtlci1jZXJ0aWZpY2F0ZXMKICAgIGRlcGVuZHNfb246CiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgICAgLSBhcHB3cml0ZS1tYXJpYWRiCiAgICB2b2x1bWVzOgogICAgICAtICdhcHB3cml0ZS1jb25maWc6L3N0b3JhZ2UvY29uZmlnOnJ3JwogICAgICAtICdhcHB3cml0ZS1jZXJ0aWZpY2F0ZXM6L3N0b3JhZ2UvY2VydGlmaWNhdGVzOnJ3JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gX0FQUF9ET01BSU49JFNFUlZJQ0VfVVJMX0FQUFdSSVRFCiAgICAgIC0gX0FQUF9ET01BSU5fVEFSR0VUPSRTRVJWSUNFX1VSTF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOX0ZVTkNUSU9OUz0kU0VSVklDRV9VUkxfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9FTUFJTF9DRVJUSUZJQ0FURVM9JHtfQVBQX0VNQUlMX0NFUlRJRklDQVRFUzotZW5hYmxlZH0nCiAgICAgIC0gJ19BUFBfRU1BSUxfU0VDVVJJVFk9JHtfQVBQX0VNQUlMX1NFQ1VSSVRZOi1jZXJ0c0BhcHB3cml0ZS5pb30nCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gJ19BUFBfTE9HR0lOR19QUk9WSURFUj0ke19BUFBfTE9HR0lOR19QUk9WSURFUn0nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19DT05GSUc9JHtfQVBQX0xPR0dJTkdfQ09ORklHfScKICAgICAgLSAnX0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTPSR7X0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTfScKICBhcHB3cml0ZS13b3JrZXItZnVuY3Rpb25zOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHdvcmtlci1mdW5jdGlvbnMKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS13b3JrZXItZnVuY3Rpb25zCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICAgIC0gYXBwd3JpdGUtbWFyaWFkYgogICAgICAtIG9wZW5ydW50aW1lcy1leGVjdXRvcgogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gX0FQUF9ET01BSU49JFNFUlZJQ0VfVVJMX0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfT1BUSU9OU19GT1JDRV9IVFRQUz0ke19BUFBfT1BUSU9OU19GT1JDRV9IVFRQUzotZGlzYWJsZWR9JwogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtICdfQVBQX0ZVTkNUSU9OU19USU1FT1VUPSR7X0FQUF9GVU5DVElPTlNfVElNRU9VVDotOTAwfScKICAgICAgLSAnX0FQUF9GVU5DVElPTlNfQlVJTERfVElNRU9VVD0ke19BUFBfRlVOQ1RJT05TX0JVSUxEX1RJTUVPVVQ6LTkwMH0nCiAgICAgIC0gJ19BUFBfRlVOQ1RJT05TX0NQVVM9JHtfQVBQX0ZVTkNUSU9OU19DUFVTOi0wfScKICAgICAgLSAnX0FQUF9GVU5DVElPTlNfTUVNT1JZPSR7X0FQUF9GVU5DVElPTlNfTUVNT1JZOi0wfScKICAgICAgLSBfQVBQX0VYRUNVVE9SX1NFQ1JFVD0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX0VYRUNVVE9SX0hPU1Q9JHtfQVBQX0VYRUNVVE9SX0hPU1Q6LWh0dHA6Ly9hcHB3cml0ZS1leGVjdXRvci92MX0nCiAgICAgIC0gJ19BUFBfVVNBR0VfU1RBVFM9JHtfQVBQX1VTQUdFX1NUQVRTOi1lbmFibGVkfScKICAgICAgLSAnX0FQUF9ET0NLRVJfSFVCX1VTRVJOQU1FPSR7X0FQUF9ET0NLRVJfSFVCX1VTRVJOQU1FfScKICAgICAgLSAnX0FQUF9ET0NLRVJfSFVCX1BBU1NXT1JEPSR7X0FQUF9ET0NLRVJfSFVCX1BBU1NXT1JEfScKICAgICAgLSAnX0FQUF9ET0NLRVJfSFVCX0VNQUlMPSR7X0FQUF9ET0NLRVJfSFVCX0VNQUlMfScKICAgICAgLSAnX0FQUF9MT0dHSU5HX0NPTkZJRz0ke19BUFBfTE9HR0lOR19DT05GSUd9JwogICAgICAtICdfQVBQX0xPR0dJTkdfUFJPVklERVI9JHtfQVBQX0xPR0dJTkdfUFJPVklERVJ9JwogICAgICAtICdfQVBQX0RBVEFCQVNFX1NIQVJFRF9UQUJMRVM9JHtfQVBQX0RBVEFCQVNFX1NIQVJFRF9UQUJMRVN9JwogIGFwcHdyaXRlLXdvcmtlci1tYWlsczoKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiB3b3JrZXItbWFpbHMKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS13b3JrZXItbWFpbHMKICAgIGRlcGVuZHNfb246CiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX1NZU1RFTV9FTUFJTF9OQU1FPSR7X0FQUF9TWVNURU1fRU1BSUxfTkFNRTotQXBwd3JpdGV9JwogICAgICAtICdfQVBQX1NZU1RFTV9FTUFJTF9BRERSRVNTPSR7X0FQUF9TWVNURU1fRU1BSUxfQUREUkVTUzotdGVhbUBhcHB3cml0ZS5pb30nCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX1NNVFBfSE9TVD0ke19BUFBfU01UUF9IT1NUfScKICAgICAgLSAnX0FQUF9TTVRQX1BPUlQ9JHtfQVBQX1NNVFBfUE9SVH0nCiAgICAgIC0gJ19BUFBfU01UUF9TRUNVUkU9JHtfQVBQX1NNVFBfU0VDVVJFfScKICAgICAgLSAnX0FQUF9TTVRQX1VTRVJOQU1FPSR7X0FQUF9TTVRQX1VTRVJOQU1FfScKICAgICAgLSAnX0FQUF9TTVRQX1BBU1NXT1JEPSR7X0FQUF9TTVRQX1BBU1NXT1JEfScKICAgICAgLSAnX0FQUF9MT0dHSU5HX1BST1ZJREVSPSR7X0FQUF9MT0dHSU5HX1BST1ZJREVSfScKICAgICAgLSAnX0FQUF9MT0dHSU5HX0NPTkZJRz0ke19BUFBfTE9HR0lOR19DT05GSUd9JwogICAgICAtIF9BUFBfRE9NQUlOPSRTRVJWSUNFX1VSTF9BUFBXUklURQogICAgICAtICdfQVBQX09QVElPTlNfRk9SQ0VfSFRUUFM9JHtfQVBQX09QVElPTlNfRk9SQ0VfSFRUUFM6LWRpc2FibGVkfScKICAgICAgLSAnX0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTPSR7X0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTfScKICBhcHB3cml0ZS13b3JrZXItbWVzc2FnaW5nOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHdvcmtlci1tZXNzYWdpbmcKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS13b3JrZXItbWVzc2FnaW5nCiAgICB2b2x1bWVzOgogICAgICAtICdhcHB3cml0ZS11cGxvYWRzOi9zdG9yYWdlL3VwbG9hZHM6cncnCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnX0FQUF9FTlY9JHtfQVBQX0VOVjotcHJvZHVjdGlvbn0nCiAgICAgIC0gJ19BUFBfV09SS0VSX1BFUl9DT1JFPSR7X0FQUF9XT1JLRVJfUEVSX0NPUkU6LTZ9JwogICAgICAtIF9BUFBfT1BFTlNTTF9LRVlfVjE9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9SRURJU19IT1NUPSR7X0FQUF9SRURJU19IT1NUOi1hcHB3cml0ZS1yZWRpc30nCiAgICAgIC0gJ19BUFBfUkVESVNfUE9SVD0ke19BUFBfUkVESVNfUE9SVDotNjM3OX0nCiAgICAgIC0gJ19BUFBfUkVESVNfVVNFUj0ke19BUFBfUkVESVNfVVNFUn0nCiAgICAgIC0gJ19BUFBfUkVESVNfUEFTUz0ke19BUFBfUkVESVNfUEFTU30nCiAgICAgIC0gJ19BUFBfREJfSE9TVD0ke19BUFBfREJfSE9TVDotYXBwd3JpdGUtbWFyaWFkYn0nCiAgICAgIC0gJ19BUFBfREJfUE9SVD0ke19BUFBfREJfUE9SVDotMzMwNn0nCiAgICAgIC0gJ19BUFBfREJfU0NIRU1BPSR7X0FQUF9EQl9TQ0hFTUE6LWFwcHdyaXRlfScKICAgICAgLSBfQVBQX0RCX1VTRVI9JFNFUlZJQ0VfVVNFUl9NQVJJQURCCiAgICAgIC0gX0FQUF9EQl9QQVNTPSRTRVJWSUNFX1BBU1NXT1JEX01BUklBREIKICAgICAgLSAnX0FQUF9MT0dHSU5HX1BST1ZJREVSPSR7X0FQUF9MT0dHSU5HX1BST1ZJREVSfScKICAgICAgLSAnX0FQUF9MT0dHSU5HX0NPTkZJRz0ke19BUFBfTE9HR0lOR19DT05GSUd9JwogICAgICAtICdfQVBQX1NNU19GUk9NPSR7X0FQUF9TTVNfRlJPTX0nCiAgICAgIC0gJ19BUFBfU01TX1BST1ZJREVSPSR7X0FQUF9TTVNfUFJPVklERVJ9JwogICAgICAtICdfQVBQX1NNU19QUk9KRUNUU19ERU5ZX0xJU1Q9JHtfQVBQX1NNU19QUk9KRUNUU19ERU5ZX0xJU1R9JwogICAgICAtICdfQVBQX1NUT1JBR0VfREVWSUNFPSR7X0FQUF9TVE9SQUdFX0RFVklDRTotbG9jYWx9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUzNfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9TM19BQ0NFU1NfS0VZfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9TM19TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUzNfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX1MzX1JFR0lPTjotdXMtZWFzdC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9TM19CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19SRUdJT049JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1JFR0lPTjotdXMtZWFzdC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfUkVHSU9OOi11cy13ZXN0LTAwNH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfTElOT0RFX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9MSU5PREVfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9SRUdJT049JHtfQVBQX1NUT1JBR0VfTElOT0RFX1JFR0lPTjotZXUtY2VudHJhbC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfTElOT0RFX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9XQVNBQklfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9XQVNBQklfUkVHSU9OOi1ldS1jZW50cmFsLTF9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9XQVNBQklfQlVDS0VUfScKICAgICAgLSAnX0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTPSR7X0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTfScKICBhcHB3cml0ZS13b3JrZXItbWlncmF0aW9uczoKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiB3b3JrZXItbWlncmF0aW9ucwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXdvcmtlci1taWdyYXRpb25zCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLW1hcmlhZGIKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOPSRTRVJWSUNFX1VSTF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOX1RBUkdFVD0kU0VSVklDRV9VUkxfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9FTUFJTF9TRUNVUklUWT0ke19BUFBfRU1BSUxfU0VDVVJJVFk6LWNlcnRzQGFwcHdyaXRlLmlvfScKICAgICAgLSAnX0FQUF9SRURJU19IT1NUPSR7X0FQUF9SRURJU19IT1NUOi1hcHB3cml0ZS1yZWRpc30nCiAgICAgIC0gJ19BUFBfUkVESVNfUE9SVD0ke19BUFBfUkVESVNfUE9SVDotNjM3OX0nCiAgICAgIC0gJ19BUFBfUkVESVNfVVNFUj0ke19BUFBfUkVESVNfVVNFUn0nCiAgICAgIC0gJ19BUFBfUkVESVNfUEFTUz0ke19BUFBfUkVESVNfUEFTU30nCiAgICAgIC0gJ19BUFBfREJfSE9TVD0ke19BUFBfREJfSE9TVDotYXBwd3JpdGUtbWFyaWFkYn0nCiAgICAgIC0gJ19BUFBfREJfUE9SVD0ke19BUFBfREJfUE9SVDotMzMwNn0nCiAgICAgIC0gJ19BUFBfREJfU0NIRU1BPSR7X0FQUF9EQl9TQ0hFTUE6LWFwcHdyaXRlfScKICAgICAgLSBfQVBQX0RCX1VTRVI9JFNFUlZJQ0VfVVNFUl9NQVJJQURCCiAgICAgIC0gX0FQUF9EQl9QQVNTPSRTRVJWSUNFX1BBU1NXT1JEX01BUklBREIKICAgICAgLSAnX0FQUF9MT0dHSU5HX1BST1ZJREVSPSR7X0FQUF9MT0dHSU5HX1BST1ZJREVSfScKICAgICAgLSAnX0FQUF9MT0dHSU5HX0NPTkZJRz0ke19BUFBfTE9HR0lOR19DT05GSUd9JwogICAgICAtICdfQVBQX01JR1JBVElPTlNfRklSRUJBU0VfQ0xJRU5UX0lEPSR7X0FQUF9NSUdSQVRJT05TX0ZJUkVCQVNFX0NMSUVOVF9JRH0nCiAgICAgIC0gJ19BUFBfTUlHUkFUSU9OU19GSVJFQkFTRV9DTElFTlRfU0VDUkVUPSR7X0FQUF9NSUdSQVRJT05TX0ZJUkVCQVNFX0NMSUVOVF9TRUNSRVR9JwogICAgICAtICdfQVBQX0RBVEFCQVNFX1NIQVJFRF9UQUJMRVM9JHtfQVBQX0RBVEFCQVNFX1NIQVJFRF9UQUJMRVN9JwogIGFwcHdyaXRlLW1haW50ZW5hbmNlOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IG1haW50ZW5hbmNlCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtbWFpbnRlbmFuY2UKICAgIGRlcGVuZHNfb246CiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9ET01BSU49JFNFUlZJQ0VfVVJMX0FQUFdSSVRFCiAgICAgIC0gX0FQUF9ET01BSU5fVEFSR0VUPSRTRVJWSUNFX1VSTF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOX0ZVTkNUSU9OUz0kU0VSVklDRV9VUkxfQVBQV1JJVEUKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfSU5URVJWQUw9JHtfQVBQX01BSU5URU5BTkNFX0lOVEVSVkFMfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fRVhFQ1VUSU9OPSR7X0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fRVhFQ1VUSU9OfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQ0FDSEU9JHtfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9DQUNIRTotMjU5MjAwMH0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX0FCVVNFPSR7X0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQUJVU0U6LTg2NDAwfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQVVESVQ9JHtfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9BVURJVDotMTIwOTYwMH0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1VTQUdFX0hPVVJMWT0ke19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1VTQUdFX0hPVVJMWTotODY0MDAwMH0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1NDSEVEVUxFUz0ke19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1NDSEVEVUxFUzotODY0MDB9JwogICAgICAtICdfQVBQX01BSU5URU5BTkNFX0RFTEFZPSR7X0FQUF9NQUlOVEVOQU5DRV9ERUxBWX0nCiAgICAgIC0gJ19BUFBfREFUQUJBU0VfU0hBUkVEX1RBQkxFUz0ke19BUFBfREFUQUJBU0VfU0hBUkVEX1RBQkxFU30nCiAgYXBwd3JpdGUtd29ya2VyLXVzYWdlOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHdvcmtlci11c2FnZQogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXdvcmtlci11c2FnZQogICAgcmVzdGFydDogdW5sZXNzLXN0b3BwZWQKICAgIGRlcGVuZHNfb246CiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgICAgLSBhcHB3cml0ZS1tYXJpYWRiCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnX0FQUF9FTlY9JHtfQVBQX0VOVjotcHJvZHVjdGlvbn0nCiAgICAgIC0gJ19BUFBfV09SS0VSX1BFUl9DT1JFPSR7X0FQUF9XT1JLRVJfUEVSX0NPUkU6LTZ9JwogICAgICAtIF9BUFBfT1BFTlNTTF9LRVlfVjE9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9VU0FHRV9TVEFUUz0ke19BUFBfVVNBR0VfU1RBVFM6LWVuYWJsZWR9JwogICAgICAtICdfQVBQX0xPR0dJTkdfUFJPVklERVI9JHtfQVBQX0xPR0dJTkdfUFJPVklERVJ9JwogICAgICAtICdfQVBQX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgICAgIC0gJ19BUFBfVVNBR0VfQUdHUkVHQVRJT05fSU5URVJWQUw9JHtfQVBQX1VTQUdFX0FHR1JFR0FUSU9OX0lOVEVSVkFMOi0zMH0nCiAgICAgIC0gJ19BUFBfREFUQUJBU0VfU0hBUkVEX1RBQkxFUz0ke19BUFBfREFUQUJBU0VfU0hBUkVEX1RBQkxFU30nCiAgYXBwd3JpdGUtd29ya2VyLXVzYWdlLWR1bXA6CiAgICBpbWFnZTogJ2FwcHdyaXRlL2FwcHdyaXRlOjEuNi4wJwogICAgZW50cnlwb2ludDogd29ya2VyLXVzYWdlLWR1bXAKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS13b3JrZXItdXNhZ2UtZHVtcAogICAgZGVwZW5kc19vbjoKICAgICAgLSBhcHB3cml0ZS1yZWRpcwogICAgICAtIGFwcHdyaXRlLW1hcmlhZGIKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX1VTQUdFX1NUQVRTPSR7X0FQUF9VU0FHRV9TVEFUUzotZW5hYmxlZH0nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19QUk9WSURFUj0ke19BUFBfTE9HR0lOR19QUk9WSURFUn0nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19DT05GSUc9JHtfQVBQX0xPR0dJTkdfQ09ORklHfScKICAgICAgLSAnX0FQUF9VU0FHRV9BR0dSRUdBVElPTl9JTlRFUlZBTD0ke19BUFBfVVNBR0VfQUdHUkVHQVRJT05fSU5URVJWQUw6LTMwfScKICAgICAgLSAnX0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTPSR7X0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTfScKICBhcHB3cml0ZS10YXNrLXNjaGVkdWxlci1mdW5jdGlvbnM6CiAgICBpbWFnZTogJ2FwcHdyaXRlL2FwcHdyaXRlOjEuNi4wJwogICAgZW50cnlwb2ludDogc2NoZWR1bGUtZnVuY3Rpb25zCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtdGFzay1zY2hlZHVsZXItZnVuY3Rpb25zCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLW1hcmlhZGIKICAgICAgLSBhcHB3cml0ZS1yZWRpcwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gJ19BUFBfREFUQUJBU0VfU0hBUkVEX1RBQkxFUz0ke19BUFBfREFUQUJBU0VfU0hBUkVEX1RBQkxFU30nCiAgYXBwd3JpdGUtdGFzay1zY2hlZHVsZXItZXhlY3V0aW9uczoKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiBzY2hlZHVsZS1leGVjdXRpb25zCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtdGFzay1zY2hlZHVsZXItZXhlY3V0aW9ucwogICAgZGVwZW5kc19vbjoKICAgICAgLSBhcHB3cml0ZS1tYXJpYWRiCiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtICdfQVBQX0RBVEFCQVNFX1NIQVJFRF9UQUJMRVM9JHtfQVBQX0RBVEFCQVNFX1NIQVJFRF9UQUJMRVN9JwogIGFwcHdyaXRlLXRhc2stc2NoZWR1bGVyLW1lc3NhZ2VzOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHNjaGVkdWxlLW1lc3NhZ2VzCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtdGFzay1zY2hlZHVsZXItbWVzc2FnZXMKICAgIGRlcGVuZHNfb246CiAgICAgIC0gYXBwd3JpdGUtbWFyaWFkYgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnX0FQUF9FTlY9JHtfQVBQX0VOVjotcHJvZHVjdGlvbn0nCiAgICAgIC0gJ19BUFBfV09SS0VSX1BFUl9DT1JFPSR7X0FQUF9XT1JLRVJfUEVSX0NPUkU6LTZ9JwogICAgICAtIF9BUFBfT1BFTlNTTF9LRVlfVjE9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9SRURJU19IT1NUPSR7X0FQUF9SRURJU19IT1NUOi1hcHB3cml0ZS1yZWRpc30nCiAgICAgIC0gJ19BUFBfUkVESVNfUE9SVD0ke19BUFBfUkVESVNfUE9SVDotNjM3OX0nCiAgICAgIC0gJ19BUFBfUkVESVNfVVNFUj0ke19BUFBfUkVESVNfVVNFUn0nCiAgICAgIC0gJ19BUFBfUkVESVNfUEFTUz0ke19BUFBfUkVESVNfUEFTU30nCiAgICAgIC0gJ19BUFBfREJfSE9TVD0ke19BUFBfREJfSE9TVDotYXBwd3JpdGUtbWFyaWFkYn0nCiAgICAgIC0gJ19BUFBfREJfUE9SVD0ke19BUFBfREJfUE9SVDotMzMwNn0nCiAgICAgIC0gJ19BUFBfREJfU0NIRU1BPSR7X0FQUF9EQl9TQ0hFTUE6LWFwcHdyaXRlfScKICAgICAgLSBfQVBQX0RCX1VTRVI9JFNFUlZJQ0VfVVNFUl9NQVJJQURCCiAgICAgIC0gX0FQUF9EQl9QQVNTPSRTRVJWSUNFX1BBU1NXT1JEX01BUklBREIKICAgICAgLSAnX0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTPSR7X0FQUF9EQVRBQkFTRV9TSEFSRURfVEFCTEVTfScKICBhcHB3cml0ZS1hc3Npc3RhbnQ6CiAgICBpbWFnZTogJ2FwcHdyaXRlL2Fzc2lzdGFudDowLjQuMCcKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS1hc3Npc3RhbnQKICAgIGVudmlyb25tZW50OgogICAgICAtIF9BUFBfQVNTSVNUQU5UX09QRU5BSV9BUElfS0VZCiAgb3BlbnJ1bnRpbWVzLWV4ZWN1dG9yOgogICAgY29udGFpbmVyX25hbWU6IG9wZW5ydW50aW1lcy1leGVjdXRvcgogICAgaG9zdG5hbWU6IGFwcHdyaXRlLWV4ZWN1dG9yCiAgICBzdG9wX3NpZ25hbDogU0lHSU5UCiAgICBpbWFnZTogJ29wZW5ydW50aW1lcy9leGVjdXRvcjowLjYuMTEnCiAgICBuZXR3b3JrczoKICAgICAgLSBydW50aW1lcwogICAgdm9sdW1lczoKICAgICAgLSAnL3Zhci9ydW4vZG9ja2VyLnNvY2s6L3Zhci9ydW4vZG9ja2VyLnNvY2snCiAgICAgIC0gJ2FwcHdyaXRlLWJ1aWxkczovc3RvcmFnZS9idWlsZHM6cncnCiAgICAgIC0gJ2FwcHdyaXRlLWZ1bmN0aW9uczovc3RvcmFnZS9mdW5jdGlvbnM6cncnCiAgICAgIC0gJy90bXA6L3RtcDpydycKICAgIGVudmlyb25tZW50OgogICAgICAtICdPUFJfRVhFQ1VUT1JfSU5BQ1RJVkVfVFJFU0hPTEQ9JHtfQVBQX0ZVTkNUSU9OU19JTkFDVElWRV9USFJFU0hPTER9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfTUFJTlRFTkFOQ0VfSU5URVJWQUw9JHtfQVBQX0ZVTkNUSU9OU19NQUlOVEVOQU5DRV9JTlRFUlZBTH0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9ORVRXT1JLPSR7X0FQUF9GVU5DVElPTlNfUlVOVElNRVNfTkVUV09SSzotcnVudGltZXN9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfRE9DS0VSX0hVQl9VU0VSTkFNRT0ke19BUFBfRE9DS0VSX0hVQl9VU0VSTkFNRX0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9ET0NLRVJfSFVCX1BBU1NXT1JEPSR7X0FQUF9ET0NLRVJfSFVCX1BBU1NXT1JEfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1JVTlRJTUVTPSR7X0FQUF9GVU5DVElPTlNfUlVOVElNRVN9JwogICAgICAtIE9QUl9FWEVDVVRPUl9TRUNSRVQ9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSAnT1BSX0VYRUNVVE9SX1JVTlRJTUVfVkVSU0lPTlM9djIsdjQnCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9MT0dHSU5HX1BST1ZJREVSPSR7X0FQUF9MT0dHSU5HX1BST1ZJREVSfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX0RFVklDRT0ke19BUFBfU1RPUkFHRV9ERVZJQ0U6LWxvY2FsfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfUzNfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9TM19BQ0NFU1NfS0VZOi1sb2NhbH0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX1MzX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9TM19TRUNSRVR9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfU1RPUkFHRV9TM19SRUdJT049JHtfQVBQX1NUT1JBR0VfUzNfUkVHSU9OfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfUzNfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX1MzX0JVQ0tFVH0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX0RPX1NQQUNFU19BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX0RPX1NQQUNFU19BQ0NFU1NfS0VZfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfRE9fU1BBQ0VTX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfU0VDUkVUfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfRE9fU1BBQ0VTX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfUkVHSU9OfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfRE9fU1BBQ0VTX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfQlVDS0VUfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfQkFDS0JMQVpFX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX0FDQ0VTU19LRVl9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfU1RPUkFHRV9CQUNLQkxBWkVfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9TRUNSRVR9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfU1RPUkFHRV9CQUNLQkxBWkVfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9SRUdJT059JwogICAgICAtICdPUFJfRVhFQ1VUT1JfU1RPUkFHRV9CQUNLQkxBWkVfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9CVUNLRVR9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfU1RPUkFHRV9MSU5PREVfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9MSU5PREVfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX0xJTk9ERV9TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfTElOT0RFX1NFQ1JFVH0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX0xJTk9ERV9SRUdJT049JHtfQVBQX1NUT1JBR0VfTElOT0RFX1JFR0lPTn0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX0xJTk9ERV9CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfTElOT0RFX0JVQ0tFVH0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX1dBU0FCSV9BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9BQ0NFU1NfS0VZfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfV0FTQUJJX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9XQVNBQklfU0VDUkVUfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfV0FTQUJJX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9XQVNBQklfUkVHSU9OfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfV0FTQUJJX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9XQVNBQklfQlVDS0VUfScKICBvcGVucnVudGltZXMtcHJveHk6CiAgICBjb250YWluZXJfbmFtZTogb3BlbnJ1bnRpbWVzLXByb3h5CiAgICBob3N0bmFtZTogcHJveHkKICAgIHN0b3Bfc2lnbmFsOiBTSUdJTlQKICAgIGltYWdlOiAnb3BlbnJ1bnRpbWVzL3Byb3h5OjAuNS41JwogICAgbmV0d29ya3M6CiAgICAgIC0gcnVudGltZXMKICAgIGVudmlyb25tZW50OgogICAgICAtICdPUFJfUFJPWFlfV09SS0VSX1BFUl9DT1JFPSR7T1BSX1BST1hZX1dPUktFUl9QRVJfQ09SRTotMX0nCiAgICAgIC0gJ09QUl9QUk9YWV9FTlY9JHtfQVBQX0VOVjotcHJvZHVjdGlvbn0nCiAgICAgIC0gT1BSX1BST1hZX0VYRUNVVE9SX1NFQ1JFVD0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtIE9QUl9QUk9YWV9TRUNSRVQ9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSBPUFJfUFJPWFlfTE9HR0lOR19DT05GSUc9JF9BUFBfTE9HR0lOR19DT05GSUcKICAgICAgLSBPUFJfUFJPWFlfQUxHT1JJVEhNPXJhbmRvbQogICAgICAtIE9QUl9QUk9YWV9FWEVDVVRPUlM9ZXhjMQogICAgICAtIE9QUl9QUk9YWV9IRUFMVEhDSEVDS19JTlRFUlZBTD0xMDAwMAogICAgICAtIE9QUl9QUk9YWV9NQVhfVElNRU9VVD02MDAKICAgICAgLSBPUFJfUFJPWFlfSEVBTFRIQ0hFQ0s9ZW5hYmxlZAogIGFwcHdyaXRlLW1hcmlhZGI6CiAgICBpbWFnZTogJ21hcmlhZGI6MTAuMTEnCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtbWFyaWFkYgogICAgdm9sdW1lczoKICAgICAgLSAnYXBwd3JpdGUtbWFyaWFkYjovdmFyL2xpYi9teXNxbDpydycKICAgIGVudmlyb25tZW50OgogICAgICAtIE1ZU1FMX1JPT1RfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQlJPT1QKICAgICAgLSAnTVlTUUxfREFUQUJBU0U9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIE1ZU1FMX1VTRVI9JFNFUlZJQ0VfVVNFUl9NQVJJQURCCiAgICAgIC0gTVlTUUxfUEFTU1dPUkQ9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtIE1BUklBREJfQVVUT19VUEdSQURFPTEKICAgIGNvbW1hbmQ6ICdteXNxbGQgLS1pbm5vZGItZmx1c2gtbWV0aG9kPWZzeW5jJwogIGFwcHdyaXRlLXJlZGlzOgogICAgaW1hZ2U6ICdyZWRpczo3LjIuNC1hbHBpbmUnCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtcmVkaXMKICAgIGNvbW1hbmQ6ICJyZWRpcy1zZXJ2ZXIgLS1tYXhtZW1vcnkgICAgICAgICAgICA1MTJtYiAtLW1heG1lbW9yeS1wb2xpY3kgICAgIGFsbGtleXMtbHJ1IC0tbWF4bWVtb3J5LXNhbXBsZXMgICAgNVxuIgogICAgdm9sdW1lczoKICAgICAgLSAnYXBwd3JpdGUtcmVkaXM6L2RhdGE6cncnCm5ldHdvcmtzOgogIHJ1bnRpbWVzOgogICAgbmFtZTogcnVudGltZXMKdm9sdW1lczoKICBhcHB3cml0ZS1tYXJpYWRiOiBudWxsCiAgYXBwd3JpdGUtcmVkaXM6IG51bGwKICBhcHB3cml0ZS1jYWNoZTogbnVsbAogIGFwcHdyaXRlLXVwbG9hZHM6IG51bGwKICBhcHB3cml0ZS1jZXJ0aWZpY2F0ZXM6IG51bGwKICBhcHB3cml0ZS1mdW5jdGlvbnM6IG51bGwKICBhcHB3cml0ZS1idWlsZHM6IG51bGwKICBhcHB3cml0ZS1jb25maWc6IG51bGwK", + "compose": "c2VydmljZXM6CiAgYXBwd3JpdGU6CiAgICBpbWFnZTogJ2FwcHdyaXRlL2FwcHdyaXRlOjEuNi4wJwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlCiAgICB2b2x1bWVzOgogICAgICAtICdhcHB3cml0ZS11cGxvYWRzOi9zdG9yYWdlL3VwbG9hZHM6cncnCiAgICAgIC0gJ2FwcHdyaXRlLWNhY2hlOi9zdG9yYWdlL2NhY2hlOnJ3JwogICAgICAtICdhcHB3cml0ZS1jb25maWc6L3N0b3JhZ2UvY29uZmlnOnJ3JwogICAgICAtICdhcHB3cml0ZS1jZXJ0aWZpY2F0ZXM6L3N0b3JhZ2UvY2VydGlmaWNhdGVzOnJ3JwogICAgICAtICdhcHB3cml0ZS1mdW5jdGlvbnM6L3N0b3JhZ2UvZnVuY3Rpb25zOnJ3JwogICAgZGVwZW5kc19vbjoKICAgICAgLSBhcHB3cml0ZS1tYXJpYWRiCiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9BUFBXUklURT0vCiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSAnX0FQUF9MT0NBTEU9JHtfQVBQX0xPQ0FMRTotZW59JwogICAgICAtICdfQVBQX0NPTlNPTEVfV0hJVEVMSVNUX1JPT1Q9JHtfQVBQX0NPTlNPTEVfV0hJVEVMSVNUX1JPT1Q6LWVuYWJsZWR9JwogICAgICAtICdfQVBQX0NPTlNPTEVfV0hJVEVMSVNUX0VNQUlMUz0ke19BUFBfQ09OU09MRV9XSElURUxJU1RfRU1BSUxTfScKICAgICAgLSAnX0FQUF9DT05TT0xFX1dISVRFTElTVF9JUFM9JHtfQVBQX0NPTlNPTEVfV0hJVEVMSVNUX0lQU30nCiAgICAgIC0gJ19BUFBfQ09OU09MRV9IT1NUTkFNRVM9JHtfQVBQX0NPTlNPTEVfSE9TVE5BTUVTOi1sb2NhbGhvc3QsYXBwd3JpdGUuaW8sKi5hcHB3cml0ZS5pb30nCiAgICAgIC0gJ19BUFBfU1lTVEVNX0VNQUlMX05BTUU9JHtfQVBQX1NZU1RFTV9FTUFJTF9OQU1FOi1BcHB3cml0ZX0nCiAgICAgIC0gJ19BUFBfU1lTVEVNX0VNQUlMX0FERFJFU1M9JHtfQVBQX1NZU1RFTV9FTUFJTF9BRERSRVNTOi10ZWFtQGFwcHdyaXRlLmlvfScKICAgICAgLSAnX0FQUF9TWVNURU1fVEVBTV9FTUFJTD0ke19BUFBfU1lTVEVNX1RFQU1fRU1BSUw6LXRlYW1AYXBwd3JpdGUuaW99JwogICAgICAtICdfQVBQX0VNQUlMX1NFQ1VSSVRZPSR7X0FQUF9FTUFJTF9TRUNVUklUWTotY2VydHNAYXBwd3JpdGUuaW99JwogICAgICAtICdfQVBQX1NZU1RFTV9SRVNQT05TRV9GT1JNQVQ9JHtfQVBQX1NZU1RFTV9SRVNQT05TRV9GT1JNQVR9JwogICAgICAtICdfQVBQX09QVElPTlNfQUJVU0U9JHtfQVBQX09QVElPTlNfQUJVU0U6LWVuYWJsZWR9JwogICAgICAtICdfQVBQX09QVElPTlNfUk9VVEVSX1BST1RFQ1RJT049JHtfQVBQX09QVElPTlNfUk9VVEVSX1BST1RFQ1RJT046LWRpc2FibGVkfScKICAgICAgLSAnX0FQUF9PUFRJT05TX0ZPUkNFX0hUVFBTPSR7X0FQUF9PUFRJT05TX0ZPUkNFX0hUVFBTOi1kaXNhYmxlZH0nCiAgICAgIC0gJ19BUFBfT1BUSU9OU19GVU5DVElPTlNfRk9SQ0VfSFRUUFM9JHtfQVBQX09QVElPTlNfRlVOQ1RJT05TX0ZPUkNFX0hUVFBTOi1kaXNhYmxlZH0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOPSRTRVJWSUNFX1VSTF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOX1RBUkdFVD0kU0VSVklDRV9VUkxfQVBQV1JJVEUKICAgICAgLSBfQVBQX0RPTUFJTl9GVU5DVElPTlM9JFNFUlZJQ0VfVVJMX0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gJ19BUFBfU01UUF9IT1NUPSR7X0FQUF9TTVRQX0hPU1R9JwogICAgICAtICdfQVBQX1NNVFBfUE9SVD0ke19BUFBfU01UUF9QT1JUfScKICAgICAgLSAnX0FQUF9TTVRQX1NFQ1VSRT0ke19BUFBfU01UUF9TRUNVUkV9JwogICAgICAtICdfQVBQX1NNVFBfVVNFUk5BTUU9JHtfQVBQX1NNVFBfVVNFUk5BTUV9JwogICAgICAtICdfQVBQX1NNVFBfUEFTU1dPUkQ9JHtfQVBQX1NNVFBfUEFTU1dPUkR9JwogICAgICAtICdfQVBQX1VTQUdFX1NUQVRTPSR7X0FQUF9VU0FHRV9TVEFUUzotZW5hYmxlZH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9MSU1JVD0ke19BUFBfU1RPUkFHRV9MSU1JVDotMzAwMDAwMDB9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUFJFVklFV19MSU1JVD0ke19BUFBfU1RPUkFHRV9QUkVWSUVXX0xJTUlUOi0yMDAwMDAwMH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9BTlRJVklSVVM9JHtfQVBQX1NUT1JBR0VfQU5USVZJUlVTOi1kaXNhYmxlZH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9BTlRJVklSVVNfSE9TVD0ke19BUFBfU1RPUkFHRV9BTlRJVklSVVNfSE9TVDotYXBwd3JpdGUtY2xhbWF2fScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0FOVElWSVJVU19QT1JUPSR7X0FQUF9TVE9SQUdFX0FOVElWSVJVU19QT1JUOi0zMzEwfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RFVklDRT0ke19BUFBfU1RPUkFHRV9ERVZJQ0U6LWxvY2FsfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfUzNfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9TM19TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfUzNfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9TM19SRUdJT046LXVzLWVhc3QtMX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9TM19CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfUzNfQlVDS0VUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX0RPX1NQQUNFU19BQ0NFU1NfS0VZfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1NFQ1JFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9ET19TUEFDRVNfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX0RPX1NQQUNFU19SRUdJT046LXVzLWVhc3QtMX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9ET19TUEFDRVNfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX0RPX1NQQUNFU19CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9SRUdJT049JHtfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX1JFR0lPTjotdXMtd2VzdC0wMDR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQlVDS0VUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX0xJTk9ERV9BQ0NFU1NfS0VZfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfTElOT0RFX1NFQ1JFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9MSU5PREVfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX0xJTk9ERV9SRUdJT046LWV1LWNlbnRyYWwtMX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9MSU5PREVfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX0xJTk9ERV9CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfV0FTQUJJX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9XQVNBQklfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1dBU0FCSV9SRUdJT049JHtfQVBQX1NUT1JBR0VfV0FTQUJJX1JFR0lPTjotZXUtY2VudHJhbC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1dBU0FCSV9CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfV0FTQUJJX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfRlVOQ1RJT05TX1NJWkVfTElNSVQ9JHtfQVBQX0ZVTkNUSU9OU19TSVpFX0xJTUlUOi0zMDAwMDAwMH0nCiAgICAgIC0gJ19BUFBfRlVOQ1RJT05TX1RJTUVPVVQ9JHtfQVBQX0ZVTkNUSU9OU19USU1FT1VUOi05MDB9JwogICAgICAtICdfQVBQX0ZVTkNUSU9OU19CVUlMRF9USU1FT1VUPSR7X0FQUF9GVU5DVElPTlNfQlVJTERfVElNRU9VVDotOTAwfScKICAgICAgLSAnX0FQUF9GVU5DVElPTlNfQ1BVUz0ke19BUFBfRlVOQ1RJT05TX0NQVVM6LTB9JwogICAgICAtICdfQVBQX0ZVTkNUSU9OU19NRU1PUlk9JHtfQVBQX0ZVTkNUSU9OU19NRU1PUlk6LTB9JwogICAgICAtICdfQVBQX0ZVTkNUSU9OU19SVU5USU1FUz0ke19BUFBfRlVOQ1RJT05TX1JVTlRJTUVTOi1ub2RlLTIwLjAscGhwLTguMixweXRob24tMy4xMSxydWJ5LTMuMn0nCiAgICAgIC0gX0FQUF9FWEVDVVRPUl9TRUNSRVQ9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9FWEVDVVRPUl9IT1NUPSR7X0FQUF9FWEVDVVRPUl9IT1NUOi1odHRwOi8vYXBwd3JpdGUtZXhlY3V0b3IvdjF9JwogICAgICAtICdfQVBQX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfSU5URVJWQUw9JHtfQVBQX01BSU5URU5BTkNFX0lOVEVSVkFMOi04NjQwMH0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfREVMQVk9JHtfQVBQX01BSU5URU5BTkNFX0RFTEFZfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fRVhFQ1VUSU9OPSR7X0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fRVhFQ1VUSU9OOi0xMjA5NjAwfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQ0FDSEU9JHtfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9DQUNIRTotMjU5MjAwMH0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX0FCVVNFPSR7X0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQUJVU0U6LTg2NDAwfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQVVESVQ9JHtfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9BVURJVDotMTIwOTYwMH0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1VTQUdFX0hPVVJMWT0ke19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1VTQUdFX0hPVVJMWTotODY0MDAwMH0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1NDSEVEVUxFUz0ke19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1NDSEVEVUxFUzotODY0MDB9JwogICAgICAtICdfQVBQX1NNU19QUk9WSURFUj0ke19BUFBfU01TX1BST1ZJREVSfScKICAgICAgLSAnX0FQUF9TTVNfRlJPTT0ke19BUFBfU01TX0ZST019JwogICAgICAtICdfQVBQX0dSQVBIUUxfTUFYX0JBVENIX1NJWkU9JHtfQVBQX0dSQVBIUUxfTUFYX0JBVENIX1NJWkU6LTEwfScKICAgICAgLSAnX0FQUF9HUkFQSFFMX01BWF9DT01QTEVYSVRZPSR7X0FQUF9HUkFQSFFMX01BWF9DT01QTEVYSVRZOi0yNTB9JwogICAgICAtICdfQVBQX0dSQVBIUUxfTUFYX0RFUFRIPSR7X0FQUF9HUkFQSFFMX01BWF9ERVBUSDotM30nCiAgICAgIC0gJ19BUFBfVkNTX0dJVEhVQl9BUFBfTkFNRT0ke19BUFBfVkNTX0dJVEhVQl9BUFBfTkFNRX0nCiAgICAgIC0gJ19BUFBfVkNTX0dJVEhVQl9QUklWQVRFX0tFWT0ke19BUFBfVkNTX0dJVEhVQl9QUklWQVRFX0tFWX0nCiAgICAgIC0gJ19BUFBfVkNTX0dJVEhVQl9BUFBfSUQ9JHtfQVBQX1ZDU19HSVRIVUJfQVBQX0lEfScKICAgICAgLSAnX0FQUF9WQ1NfR0lUSFVCX1dFQkhPT0tfU0VDUkVUPSR7X0FQUF9WQ1NfR0lUSFVCX1dFQkhPT0tfU0VDUkVUfScKICAgICAgLSAnX0FQUF9WQ1NfR0lUSFVCX0NMSUVOVF9TRUNSRVQ9JHtfQVBQX1ZDU19HSVRIVUJfQ0xJRU5UX1NFQ1JFVH0nCiAgICAgIC0gJ19BUFBfVkNTX0dJVEhVQl9DTElFTlRfSUQ9JHtfQVBQX1ZDU19HSVRIVUJfQ0xJRU5UX0lEfScKICAgICAgLSAnX0FQUF9NSUdSQVRJT05TX0ZJUkVCQVNFX0NMSUVOVF9JRD0ke19BUFBfTUlHUkFUSU9OU19GSVJFQkFTRV9DTElFTlRfSUR9JwogICAgICAtICdfQVBQX01JR1JBVElPTlNfRklSRUJBU0VfQ0xJRU5UX1NFQ1JFVD0ke19BUFBfTUlHUkFUSU9OU19GSVJFQkFTRV9DTElFTlRfU0VDUkVUfScKICAgICAgLSAnX0FQUF9BU1NJU1RBTlRfT1BFTkFJX0FQSV9LRVk9JHtfQVBQX0FTU0lTVEFOVF9PUEVOQUlfQVBJX0tFWX0nCiAgYXBwd3JpdGUtY29uc29sZToKICAgIGltYWdlOiAnYXBwd3JpdGUvY29uc29sZTo1LjAuMTInCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtY29uc29sZQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0FQUFdSSVRFPS9jb25zb2xlCiAgYXBwd3JpdGUtcmVhbHRpbWU6CiAgICBpbWFnZTogJ2FwcHdyaXRlL2FwcHdyaXRlOjEuNi4wJwogICAgZW50cnlwb2ludDogcmVhbHRpbWUKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS1yZWFsdGltZQogICAgZGVwZW5kc19vbjoKICAgICAgLSBhcHB3cml0ZS1tYXJpYWRiCiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9BUFBXUklURT0vdjEvcmVhbHRpbWUKICAgICAgLSAnX0FQUF9FTlY9JHtfQVBQX0VOVjotcHJvZHVjdGlvbn0nCiAgICAgIC0gJ19BUFBfV09SS0VSX1BFUl9DT1JFPSR7X0FQUF9XT1JLRVJfUEVSX0NPUkU6LTZ9JwogICAgICAtICdfQVBQX09QVElPTlNfQUJVU0U9JHtfQVBQX09QVElPTlNfQUJVU0U6LWVuYWJsZWR9JwogICAgICAtIF9BUFBfT1BFTlNTTF9LRVlfVjE9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9SRURJU19IT1NUPSR7X0FQUF9SRURJU19IT1NUOi1hcHB3cml0ZS1yZWRpc30nCiAgICAgIC0gJ19BUFBfUkVESVNfUE9SVD0ke19BUFBfUkVESVNfUE9SVDotNjM3OX0nCiAgICAgIC0gJ19BUFBfUkVESVNfVVNFUj0ke19BUFBfUkVESVNfVVNFUn0nCiAgICAgIC0gJ19BUFBfUkVESVNfUEFTUz0ke19BUFBfUkVESVNfUEFTU30nCiAgICAgIC0gJ19BUFBfREJfSE9TVD0ke19BUFBfREJfSE9TVDotYXBwd3JpdGUtbWFyaWFkYn0nCiAgICAgIC0gJ19BUFBfREJfUE9SVD0ke19BUFBfREJfUE9SVDotMzMwNn0nCiAgICAgIC0gJ19BUFBfREJfU0NIRU1BPSR7X0FQUF9EQl9TQ0hFTUE6LWFwcHdyaXRlfScKICAgICAgLSBfQVBQX0RCX1VTRVI9JFNFUlZJQ0VfVVNFUl9NQVJJQURCCiAgICAgIC0gX0FQUF9EQl9QQVNTPSRTRVJWSUNFX1BBU1NXT1JEX01BUklBREIKICAgICAgLSAnX0FQUF9VU0FHRV9TVEFUUz0ke19BUFBfVVNBR0VfU1RBVFM6LWVuYWJsZWR9JwogICAgICAtICdfQVBQX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgYXBwd3JpdGUtd29ya2VyLWF1ZGl0czoKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiB3b3JrZXItYXVkaXRzCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtd29ya2VyLWF1ZGl0cwogICAgZGVwZW5kc19vbjoKICAgICAgLSBhcHB3cml0ZS1yZWRpcwogICAgICAtIGFwcHdyaXRlLW1hcmlhZGIKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtICdfQVBQX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgYXBwd3JpdGUtd29ya2VyLXdlYmhvb2tzOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHdvcmtlci13ZWJob29rcwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXdvcmtlci13ZWJob29rcwogICAgZGVwZW5kc19vbjoKICAgICAgLSBhcHB3cml0ZS1yZWRpcwogICAgICAtIGFwcHdyaXRlLW1hcmlhZGIKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX0VNQUlMX1NFQ1VSSVRZPSR7X0FQUF9FTUFJTF9TRUNVUklUWTotY2VydHNAYXBwd3JpdGUuaW99JwogICAgICAtICdfQVBQX1NZU1RFTV9TRUNVUklUWV9FTUFJTF9BRERSRVNTPSR7X0FQUF9TWVNURU1fU0VDVVJJVFlfRU1BSUxfQUREUkVTU30nCiAgICAgIC0gJ19BUFBfREJfSE9TVD0ke19BUFBfREJfSE9TVDotYXBwd3JpdGUtbWFyaWFkYn0nCiAgICAgIC0gJ19BUFBfREJfUE9SVD0ke19BUFBfREJfUE9SVDotMzMwNn0nCiAgICAgIC0gJ19BUFBfREJfU0NIRU1BPSR7X0FQUF9EQl9TQ0hFTUE6LWFwcHdyaXRlfScKICAgICAgLSBfQVBQX0RCX1VTRVI9JFNFUlZJQ0VfVVNFUl9NQVJJQURCCiAgICAgIC0gX0FQUF9EQl9QQVNTPSRTRVJWSUNFX1BBU1NXT1JEX01BUklBREIKICAgICAgLSAnX0FQUF9SRURJU19IT1NUPSR7X0FQUF9SRURJU19IT1NUOi1hcHB3cml0ZS1yZWRpc30nCiAgICAgIC0gJ19BUFBfUkVESVNfUE9SVD0ke19BUFBfUkVESVNfUE9SVDotNjM3OX0nCiAgICAgIC0gJ19BUFBfUkVESVNfVVNFUj0ke19BUFBfUkVESVNfVVNFUn0nCiAgICAgIC0gJ19BUFBfUkVESVNfUEFTUz0ke19BUFBfUkVESVNfUEFTU30nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19DT05GSUc9JHtfQVBQX0xPR0dJTkdfQ09ORklHfScKICBhcHB3cml0ZS13b3JrZXItZGVsZXRlczoKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiB3b3JrZXItZGVsZXRlcwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXdvcmtlci1kZWxldGVzCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICAgIC0gYXBwd3JpdGUtbWFyaWFkYgogICAgdm9sdW1lczoKICAgICAgLSAnYXBwd3JpdGUtdXBsb2Fkczovc3RvcmFnZS91cGxvYWRzOnJ3JwogICAgICAtICdhcHB3cml0ZS1jYWNoZTovc3RvcmFnZS9jYWNoZTpydycKICAgICAgLSAnYXBwd3JpdGUtZnVuY3Rpb25zOi9zdG9yYWdlL2Z1bmN0aW9uczpydycKICAgICAgLSAnYXBwd3JpdGUtYnVpbGRzOi9zdG9yYWdlL2J1aWxkczpydycKICAgICAgLSAnYXBwd3JpdGUtY2VydGlmaWNhdGVzOi9zdG9yYWdlL2NlcnRpZmljYXRlczpydycKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtICdfQVBQX1NUT1JBR0VfREVWSUNFPSR7X0FQUF9TVE9SQUdFX0RFVklDRTotbG9jYWx9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUzNfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9TM19BQ0NFU1NfS0VZOi1sb2NhbH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9TM19TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfUzNfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9TM19SRUdJT046LXVzLWVhc3QtMX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9TM19CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfUzNfQlVDS0VUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX0RPX1NQQUNFU19BQ0NFU1NfS0VZfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1NFQ1JFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9ET19TUEFDRVNfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX0RPX1NQQUNFU19SRUdJT046LXVzLWVhc3QtMX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9ET19TUEFDRVNfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX0RPX1NQQUNFU19CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9SRUdJT049JHtfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX1JFR0lPTjotdXMtd2VzdC0wMDR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQlVDS0VUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX0xJTk9ERV9BQ0NFU1NfS0VZfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfTElOT0RFX1NFQ1JFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9MSU5PREVfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX0xJTk9ERV9SRUdJT046LWV1LWNlbnRyYWwtMX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9MSU5PREVfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX0xJTk9ERV9CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfV0FTQUJJX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9XQVNBQklfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1dBU0FCSV9SRUdJT049JHtfQVBQX1NUT1JBR0VfV0FTQUJJX1JFR0lPTjotZXUtY2VudHJhbC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1dBU0FCSV9CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfV0FTQUJJX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19DT05GSUc9JHtfQVBQX0xPR0dJTkdfQ09ORklHfScKICAgICAgLSBfQVBQX0VYRUNVVE9SX1NFQ1JFVD0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX0VYRUNVVE9SX0hPU1Q9JHtfQVBQX0VYRUNVVE9SX0hPU1Q6LWh0dHA6Ly9hcHB3cml0ZS1leGVjdXRvci92MX0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX0FCVVNFPSR7X0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQUJVU0U6LTg2NDAwfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQVVESVQ9JHtfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9BVURJVDotMTIwOTYwMH0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX0VYRUNVVElPTj0ke19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX0VYRUNVVElPTjotMTIwOTYwMH0nCiAgYXBwd3JpdGUtd29ya2VyLWRhdGFiYXNlczoKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiB3b3JrZXItZGF0YWJhc2VzCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtd29ya2VyLWRhdGFiYXNlcwogICAgZGVwZW5kc19vbjoKICAgICAgLSBhcHB3cml0ZS1yZWRpcwogICAgICAtIGFwcHdyaXRlLW1hcmlhZGIKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtICdfQVBQX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgYXBwd3JpdGUtd29ya2VyLWJ1aWxkczoKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiB3b3JrZXItYnVpbGRzCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtd29ya2VyLWJ1aWxkcwogICAgZGVwZW5kc19vbjoKICAgICAgLSBhcHB3cml0ZS1yZWRpcwogICAgICAtIGFwcHdyaXRlLW1hcmlhZGIKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2FwcHdyaXRlLWZ1bmN0aW9uczovc3RvcmFnZS9mdW5jdGlvbnM6cncnCiAgICAgIC0gJ2FwcHdyaXRlLWJ1aWxkczovc3RvcmFnZS9idWlsZHM6cncnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnX0FQUF9FTlY9JHtfQVBQX0VOVjotcHJvZHVjdGlvbn0nCiAgICAgIC0gJ19BUFBfV09SS0VSX1BFUl9DT1JFPSR7X0FQUF9XT1JLRVJfUEVSX0NPUkU6LTZ9JwogICAgICAtIF9BUFBfT1BFTlNTTF9LRVlfVjE9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSBfQVBQX0VYRUNVVE9SX1NFQ1JFVD0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX0VYRUNVVE9SX0hPU1Q9JHtfQVBQX0VYRUNVVE9SX0hPU1Q6LWh0dHA6Ly9hcHB3cml0ZS1leGVjdXRvci92MX0nCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gJ19BUFBfTE9HR0lOR19DT05GSUc9JHtfQVBQX0xPR0dJTkdfQ09ORklHfScKICAgICAgLSAnX0FQUF9WQ1NfR0lUSFVCX0FQUF9OQU1FPSR7X0FQUF9WQ1NfR0lUSFVCX0FQUF9OQU1FfScKICAgICAgLSAnX0FQUF9WQ1NfR0lUSFVCX1BSSVZBVEVfS0VZPSR7X0FQUF9WQ1NfR0lUSFVCX1BSSVZBVEVfS0VZfScKICAgICAgLSAnX0FQUF9WQ1NfR0lUSFVCX0FQUF9JRD0ke19BUFBfVkNTX0dJVEhVQl9BUFBfSUR9JwogICAgICAtICdfQVBQX0ZVTkNUSU9OU19USU1FT1VUPSR7X0FQUF9GVU5DVElPTlNfVElNRU9VVDotOTAwfScKICAgICAgLSAnX0FQUF9GVU5DVElPTlNfQlVJTERfVElNRU9VVD0ke19BUFBfRlVOQ1RJT05TX0JVSUxEX1RJTUVPVVQ6LTkwMH0nCiAgICAgIC0gJ19BUFBfRlVOQ1RJT05TX0NQVVM9JHtfQVBQX0ZVTkNUSU9OU19DUFVTOi0wfScKICAgICAgLSAnX0FQUF9GVU5DVElPTlNfTUVNT1JZPSR7X0FQUF9GVU5DVElPTlNfTUVNT1JZOi0wfScKICAgICAgLSAnX0FQUF9GVU5DVElPTlNfU0laRV9MSU1JVD0ke19BUFBfRlVOQ1RJT05TX1NJWkVfTElNSVQ6LTMwMDAwMDAwfScKICAgICAgLSAnX0FQUF9PUFRJT05TX0ZPUkNFX0hUVFBTPSR7X0FQUF9PUFRJT05TX0ZPUkNFX0hUVFBTOi1kaXNhYmxlZH0nCiAgICAgIC0gJ19BUFBfT1BUSU9OU19GVU5DVElPTlNfRk9SQ0VfSFRUUFM9JHtfQVBQX09QVElPTlNfRlVOQ1RJT05TX0ZPUkNFX0hUVFBTOi1kaXNhYmxlZH0nCiAgICAgIC0gX0FQUF9ET01BSU49JFNFUlZJQ0VfVVJMX0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9ERVZJQ0U9JHtfQVBQX1NUT1JBR0VfREVWSUNFOi1sb2NhbH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9TM19BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX1MzX0FDQ0VTU19LRVk6LWxvY2FsfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9TM19TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUzNfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX1MzX1JFR0lPTjotdXMtZWFzdC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1MzX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9TM19CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19SRUdJT049JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1JFR0lPTjotdXMtZWFzdC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0RPX1NQQUNFU19CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfUkVHSU9OOi11cy13ZXN0LTAwNH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9CVUNLRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfTElOT0RFX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9MSU5PREVfU0VDUkVUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9SRUdJT049JHtfQVBQX1NUT1JBR0VfTElOT0RFX1JFR0lPTjotZXUtY2VudHJhbC0xfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0xJTk9ERV9CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfTElOT0RFX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9XQVNBQklfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9XQVNBQklfUkVHSU9OOi1ldS1jZW50cmFsLTF9JwogICAgICAtICdfQVBQX1NUT1JBR0VfV0FTQUJJX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9XQVNBQklfQlVDS0VUfScKICBhcHB3cml0ZS13b3JrZXItY2VydGlmaWNhdGVzOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHdvcmtlci1jZXJ0aWZpY2F0ZXMKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS13b3JrZXItY2VydGlmaWNhdGVzCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICAgIC0gYXBwd3JpdGUtbWFyaWFkYgogICAgdm9sdW1lczoKICAgICAgLSAnYXBwd3JpdGUtY29uZmlnOi9zdG9yYWdlL2NvbmZpZzpydycKICAgICAgLSAnYXBwd3JpdGUtY2VydGlmaWNhdGVzOi9zdG9yYWdlL2NlcnRpZmljYXRlczpydycKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOPSRTRVJWSUNFX1VSTF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOX1RBUkdFVD0kU0VSVklDRV9VUkxfQVBQV1JJVEUKICAgICAgLSBfQVBQX0RPTUFJTl9GVU5DVElPTlM9JFNFUlZJQ0VfVVJMX0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfRU1BSUxfQ0VSVElGSUNBVEVTPSR7X0FQUF9FTUFJTF9DRVJUSUZJQ0FURVM6LWVuYWJsZWR9JwogICAgICAtICdfQVBQX0VNQUlMX1NFQ1VSSVRZPSR7X0FQUF9FTUFJTF9TRUNVUklUWTotY2VydHNAYXBwd3JpdGUuaW99JwogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtICdfQVBQX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgYXBwd3JpdGUtd29ya2VyLWZ1bmN0aW9uczoKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiB3b3JrZXItZnVuY3Rpb25zCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtd29ya2VyLWZ1bmN0aW9ucwogICAgZGVwZW5kc19vbjoKICAgICAgLSBhcHB3cml0ZS1yZWRpcwogICAgICAtIGFwcHdyaXRlLW1hcmlhZGIKICAgICAgLSBvcGVucnVudGltZXMtZXhlY3V0b3IKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOPSRTRVJWSUNFX1VSTF9BUFBXUklURQogICAgICAtICdfQVBQX09QVElPTlNfRk9SQ0VfSFRUUFM9JHtfQVBQX09QVElPTlNfRk9SQ0VfSFRUUFM6LWRpc2FibGVkfScKICAgICAgLSAnX0FQUF9SRURJU19IT1NUPSR7X0FQUF9SRURJU19IT1NUOi1hcHB3cml0ZS1yZWRpc30nCiAgICAgIC0gJ19BUFBfUkVESVNfUE9SVD0ke19BUFBfUkVESVNfUE9SVDotNjM3OX0nCiAgICAgIC0gJ19BUFBfUkVESVNfVVNFUj0ke19BUFBfUkVESVNfVVNFUn0nCiAgICAgIC0gJ19BUFBfUkVESVNfUEFTUz0ke19BUFBfUkVESVNfUEFTU30nCiAgICAgIC0gJ19BUFBfREJfSE9TVD0ke19BUFBfREJfSE9TVDotYXBwd3JpdGUtbWFyaWFkYn0nCiAgICAgIC0gJ19BUFBfREJfUE9SVD0ke19BUFBfREJfUE9SVDotMzMwNn0nCiAgICAgIC0gJ19BUFBfREJfU0NIRU1BPSR7X0FQUF9EQl9TQ0hFTUE6LWFwcHdyaXRlfScKICAgICAgLSBfQVBQX0RCX1VTRVI9JFNFUlZJQ0VfVVNFUl9NQVJJQURCCiAgICAgIC0gX0FQUF9EQl9QQVNTPSRTRVJWSUNFX1BBU1NXT1JEX01BUklBREIKICAgICAgLSAnX0FQUF9GVU5DVElPTlNfVElNRU9VVD0ke19BUFBfRlVOQ1RJT05TX1RJTUVPVVQ6LTkwMH0nCiAgICAgIC0gJ19BUFBfRlVOQ1RJT05TX0JVSUxEX1RJTUVPVVQ9JHtfQVBQX0ZVTkNUSU9OU19CVUlMRF9USU1FT1VUOi05MDB9JwogICAgICAtICdfQVBQX0ZVTkNUSU9OU19DUFVTPSR7X0FQUF9GVU5DVElPTlNfQ1BVUzotMH0nCiAgICAgIC0gJ19BUFBfRlVOQ1RJT05TX01FTU9SWT0ke19BUFBfRlVOQ1RJT05TX01FTU9SWTotMH0nCiAgICAgIC0gX0FQUF9FWEVDVVRPUl9TRUNSRVQ9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9FWEVDVVRPUl9IT1NUPSR7X0FQUF9FWEVDVVRPUl9IT1NUOi1odHRwOi8vYXBwd3JpdGUtZXhlY3V0b3IvdjF9JwogICAgICAtICdfQVBQX1VTQUdFX1NUQVRTPSR7X0FQUF9VU0FHRV9TVEFUUzotZW5hYmxlZH0nCiAgICAgIC0gJ19BUFBfRE9DS0VSX0hVQl9VU0VSTkFNRT0ke19BUFBfRE9DS0VSX0hVQl9VU0VSTkFNRX0nCiAgICAgIC0gJ19BUFBfRE9DS0VSX0hVQl9QQVNTV09SRD0ke19BUFBfRE9DS0VSX0hVQl9QQVNTV09SRH0nCiAgICAgIC0gJ19BUFBfTE9HR0lOR19DT05GSUc9JHtfQVBQX0xPR0dJTkdfQ09ORklHfScKICBhcHB3cml0ZS13b3JrZXItbWFpbHM6CiAgICBpbWFnZTogJ2FwcHdyaXRlL2FwcHdyaXRlOjEuNi4wJwogICAgZW50cnlwb2ludDogd29ya2VyLW1haWxzCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtd29ya2VyLW1haWxzCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnX0FQUF9FTlY9JHtfQVBQX0VOVjotcHJvZHVjdGlvbn0nCiAgICAgIC0gJ19BUFBfV09SS0VSX1BFUl9DT1JFPSR7X0FQUF9XT1JLRVJfUEVSX0NPUkU6LTZ9JwogICAgICAtIF9BUFBfT1BFTlNTTF9LRVlfVjE9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9TWVNURU1fRU1BSUxfTkFNRT0ke19BUFBfU1lTVEVNX0VNQUlMX05BTUU6LUFwcHdyaXRlfScKICAgICAgLSAnX0FQUF9TWVNURU1fRU1BSUxfQUREUkVTUz0ke19BUFBfU1lTVEVNX0VNQUlMX0FERFJFU1M6LXRlYW1AYXBwd3JpdGUuaW99JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX1NNVFBfSE9TVD0ke19BUFBfU01UUF9IT1NUfScKICAgICAgLSAnX0FQUF9TTVRQX1BPUlQ9JHtfQVBQX1NNVFBfUE9SVH0nCiAgICAgIC0gJ19BUFBfU01UUF9TRUNVUkU9JHtfQVBQX1NNVFBfU0VDVVJFfScKICAgICAgLSAnX0FQUF9TTVRQX1VTRVJOQU1FPSR7X0FQUF9TTVRQX1VTRVJOQU1FfScKICAgICAgLSAnX0FQUF9TTVRQX1BBU1NXT1JEPSR7X0FQUF9TTVRQX1BBU1NXT1JEfScKICAgICAgLSAnX0FQUF9MT0dHSU5HX0NPTkZJRz0ke19BUFBfTE9HR0lOR19DT05GSUd9JwogICAgICAtIF9BUFBfRE9NQUlOPSRTRVJWSUNFX1VSTF9BUFBXUklURQogIGFwcHdyaXRlLXdvcmtlci1tZXNzYWdpbmc6CiAgICBpbWFnZTogJ2FwcHdyaXRlL2FwcHdyaXRlOjEuNi4wJwogICAgZW50cnlwb2ludDogd29ya2VyLW1lc3NhZ2luZwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXdvcmtlci1tZXNzYWdpbmcKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2FwcHdyaXRlLXVwbG9hZHM6L3N0b3JhZ2UvdXBsb2FkczpydycKICAgIGRlcGVuZHNfb246CiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtICdfQVBQX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgICAgIC0gJ19BUFBfU01TX0ZST009JHtfQVBQX1NNU19GUk9NfScKICAgICAgLSAnX0FQUF9TTVNfUFJPVklERVI9JHtfQVBQX1NNU19QUk9WSURFUn0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9ERVZJQ0U9JHtfQVBQX1NUT1JBR0VfREVWSUNFOi1sb2NhbH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9TM19BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX1MzX0FDQ0VTU19LRVl9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUzNfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX1MzX1NFQ1JFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9TM19SRUdJT049JHtfQVBQX1NUT1JBR0VfUzNfUkVHSU9OOi11cy1lYXN0LTF9JwogICAgICAtICdfQVBQX1NUT1JBR0VfUzNfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX1MzX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9ET19TUEFDRVNfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9ET19TUEFDRVNfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX0RPX1NQQUNFU19TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfUkVHSU9OOi11cy1lYXN0LTF9JwogICAgICAtICdfQVBQX1NUT1JBR0VfRE9fU1BBQ0VTX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfQlVDS0VUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9BQ0NFU1NfS0VZfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX1NFQ1JFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9CQUNLQkxBWkVfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9SRUdJT046LXVzLXdlc3QtMDA0fScKICAgICAgLSAnX0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX0JVQ0tFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9MSU5PREVfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9MSU5PREVfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9MSU5PREVfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX0xJTk9ERV9TRUNSRVR9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9MSU5PREVfUkVHSU9OOi1ldS1jZW50cmFsLTF9JwogICAgICAtICdfQVBQX1NUT1JBR0VfTElOT0RFX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9MSU5PREVfQlVDS0VUfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1dBU0FCSV9BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9BQ0NFU1NfS0VZfScKICAgICAgLSAnX0FQUF9TVE9SQUdFX1dBU0FCSV9TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfV0FTQUJJX1NFQ1JFVH0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9SRUdJT046LWV1LWNlbnRyYWwtMX0nCiAgICAgIC0gJ19BUFBfU1RPUkFHRV9XQVNBQklfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9CVUNLRVR9JwogIGFwcHdyaXRlLXdvcmtlci1taWdyYXRpb25zOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHdvcmtlci1taWdyYXRpb25zCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtd29ya2VyLW1pZ3JhdGlvbnMKICAgIGRlcGVuZHNfb246CiAgICAgIC0gYXBwd3JpdGUtbWFyaWFkYgogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gX0FQUF9ET01BSU49JFNFUlZJQ0VfVVJMX0FQUFdSSVRFCiAgICAgIC0gX0FQUF9ET01BSU5fVEFSR0VUPSRTRVJWSUNFX1VSTF9BUFBXUklURQogICAgICAtICdfQVBQX0VNQUlMX1NFQ1VSSVRZPSR7X0FQUF9FTUFJTF9TRUNVUklUWTotY2VydHNAYXBwd3JpdGUuaW99JwogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtICdfQVBQX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgICAgIC0gJ19BUFBfTUlHUkFUSU9OU19GSVJFQkFTRV9DTElFTlRfSUQ9JHtfQVBQX01JR1JBVElPTlNfRklSRUJBU0VfQ0xJRU5UX0lEfScKICAgICAgLSAnX0FQUF9NSUdSQVRJT05TX0ZJUkVCQVNFX0NMSUVOVF9TRUNSRVQ9JHtfQVBQX01JR1JBVElPTlNfRklSRUJBU0VfQ0xJRU5UX1NFQ1JFVH0nCiAgYXBwd3JpdGUtdGFzay1tYWludGVuYW5jZToKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiBtYWludGVuYW5jZQogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXRhc2stbWFpbnRlbmFuY2UKICAgIGRlcGVuZHNfb246CiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9ET01BSU49JFNFUlZJQ0VfVVJMX0FQUFdSSVRFCiAgICAgIC0gX0FQUF9ET01BSU5fVEFSR0VUPSRTRVJWSUNFX1VSTF9BUFBXUklURQogICAgICAtIF9BUFBfRE9NQUlOX0ZVTkNUSU9OUz0kU0VSVklDRV9VUkxfQVBQV1JJVEUKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfSU5URVJWQUw9JHtfQVBQX01BSU5URU5BTkNFX0lOVEVSVkFMfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fRVhFQ1VUSU9OPSR7X0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fRVhFQ1VUSU9OfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQ0FDSEU9JHtfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9DQUNIRTotMjU5MjAwMH0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX0FCVVNFPSR7X0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQUJVU0U6LTg2NDAwfScKICAgICAgLSAnX0FQUF9NQUlOVEVOQU5DRV9SRVRFTlRJT05fQVVESVQ9JHtfQVBQX01BSU5URU5BTkNFX1JFVEVOVElPTl9BVURJVDotMTIwOTYwMH0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1VTQUdFX0hPVVJMWT0ke19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1VTQUdFX0hPVVJMWTotODY0MDAwMH0nCiAgICAgIC0gJ19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1NDSEVEVUxFUz0ke19BUFBfTUFJTlRFTkFOQ0VfUkVURU5USU9OX1NDSEVEVUxFUzotODY0MDB9JwogIGFwcHdyaXRlLXdvcmtlci11c2FnZToKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiB3b3JrZXItdXNhZ2UKICAgIGNvbnRhaW5lcl9uYW1lOiBhcHB3cml0ZS13b3JrZXItdXNhZ2UKICAgIHJlc3RhcnQ6IHVubGVzcy1zdG9wcGVkCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICAgIC0gYXBwd3JpdGUtbWFyaWFkYgogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfREJfSE9TVD0ke19BUFBfREJfSE9TVDotYXBwd3JpdGUtbWFyaWFkYn0nCiAgICAgIC0gJ19BUFBfREJfUE9SVD0ke19BUFBfREJfUE9SVDotMzMwNn0nCiAgICAgIC0gJ19BUFBfREJfU0NIRU1BPSR7X0FQUF9EQl9TQ0hFTUE6LWFwcHdyaXRlfScKICAgICAgLSBfQVBQX0RCX1VTRVI9JFNFUlZJQ0VfVVNFUl9NQVJJQURCCiAgICAgIC0gX0FQUF9EQl9QQVNTPSRTRVJWSUNFX1BBU1NXT1JEX01BUklBREIKICAgICAgLSAnX0FQUF9SRURJU19IT1NUPSR7X0FQUF9SRURJU19IT1NUOi1hcHB3cml0ZS1yZWRpc30nCiAgICAgIC0gJ19BUFBfUkVESVNfUE9SVD0ke19BUFBfUkVESVNfUE9SVDotNjM3OX0nCiAgICAgIC0gJ19BUFBfUkVESVNfVVNFUj0ke19BUFBfUkVESVNfVVNFUn0nCiAgICAgIC0gJ19BUFBfUkVESVNfUEFTUz0ke19BUFBfUkVESVNfUEFTU30nCiAgICAgIC0gJ19BUFBfVVNBR0VfU1RBVFM9JHtfQVBQX1VTQUdFX1NUQVRTOi1lbmFibGVkfScKICAgICAgLSAnX0FQUF9MT0dHSU5HX0NPTkZJRz0ke19BUFBfTE9HR0lOR19DT05GSUd9JwogICAgICAtICdfQVBQX1VTQUdFX0FHR1JFR0FUSU9OX0lOVEVSVkFMPSR7X0FQUF9VU0FHRV9BR0dSRUdBVElPTl9JTlRFUlZBTDotMzB9JwogIGFwcHdyaXRlLXdvcmtlci11c2FnZS1kdW1wOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHdvcmtlci11c2FnZS1kdW1wCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtd29ya2VyLXVzYWdlLWR1bXAKICAgIGRlcGVuZHNfb246CiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgICAgLSBhcHB3cml0ZS1tYXJpYWRiCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnX0FQUF9FTlY9JHtfQVBQX0VOVjotcHJvZHVjdGlvbn0nCiAgICAgIC0gJ19BUFBfV09SS0VSX1BFUl9DT1JFPSR7X0FQUF9XT1JLRVJfUEVSX0NPUkU6LTZ9JwogICAgICAtIF9BUFBfT1BFTlNTTF9LRVlfVjE9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9VU0FHRV9TVEFUUz0ke19BUFBfVVNBR0VfU1RBVFM6LWVuYWJsZWR9JwogICAgICAtICdfQVBQX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgICAgIC0gJ19BUFBfVVNBR0VfQUdHUkVHQVRJT05fSU5URVJWQUw9JHtfQVBQX1VTQUdFX0FHR1JFR0FUSU9OX0lOVEVSVkFMOi0zMH0nCiAgYXBwd3JpdGUtdGFzay1zY2hlZHVsZXItZnVuY3Rpb25zOgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hcHB3cml0ZToxLjYuMCcKICAgIGVudHJ5cG9pbnQ6IHNjaGVkdWxlLWZ1bmN0aW9ucwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXRhc2stc2NoZWR1bGVyLWZ1bmN0aW9ucwogICAgZGVwZW5kc19vbjoKICAgICAgLSBhcHB3cml0ZS1tYXJpYWRiCiAgICAgIC0gYXBwd3JpdGUtcmVkaXMKICAgIGVudmlyb25tZW50OgogICAgICAtICdfQVBQX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnX0FQUF9XT1JLRVJfUEVSX0NPUkU9JHtfQVBQX1dPUktFUl9QRVJfQ09SRTotNn0nCiAgICAgIC0gX0FQUF9PUEVOU1NMX0tFWV9WMT0kU0VSVklDRV9QQVNTV09SRF82NF9BUFBXUklURQogICAgICAtICdfQVBQX1JFRElTX0hPU1Q9JHtfQVBQX1JFRElTX0hPU1Q6LWFwcHdyaXRlLXJlZGlzfScKICAgICAgLSAnX0FQUF9SRURJU19QT1JUPSR7X0FQUF9SRURJU19QT1JUOi02Mzc5fScKICAgICAgLSAnX0FQUF9SRURJU19VU0VSPSR7X0FQUF9SRURJU19VU0VSfScKICAgICAgLSAnX0FQUF9SRURJU19QQVNTPSR7X0FQUF9SRURJU19QQVNTfScKICAgICAgLSAnX0FQUF9EQl9IT1NUPSR7X0FQUF9EQl9IT1NUOi1hcHB3cml0ZS1tYXJpYWRifScKICAgICAgLSAnX0FQUF9EQl9QT1JUPSR7X0FQUF9EQl9QT1JUOi0zMzA2fScKICAgICAgLSAnX0FQUF9EQl9TQ0hFTUE9JHtfQVBQX0RCX1NDSEVNQTotYXBwd3JpdGV9JwogICAgICAtIF9BUFBfREJfVVNFUj0kU0VSVklDRV9VU0VSX01BUklBREIKICAgICAgLSBfQVBQX0RCX1BBU1M9JFNFUlZJQ0VfUEFTU1dPUkRfTUFSSUFEQgogIGFwcHdyaXRlLXRhc2stc2NoZWR1bGVyLWV4ZWN1dGlvbnM6CiAgICBpbWFnZTogJ2FwcHdyaXRlL2FwcHdyaXRlOjEuNi4wJwogICAgZW50cnlwb2ludDogc2NoZWR1bGUtZXhlY3V0aW9ucwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXRhc2stc2NoZWR1bGVyLWV4ZWN1dGlvbnMKICAgIGRlcGVuZHNfb246CiAgICAgIC0gYXBwd3JpdGUtbWFyaWFkYgogICAgICAtIGFwcHdyaXRlLXJlZGlzCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnX0FQUF9FTlY9JHtfQVBQX0VOVjotcHJvZHVjdGlvbn0nCiAgICAgIC0gJ19BUFBfV09SS0VSX1BFUl9DT1JFPSR7X0FQUF9XT1JLRVJfUEVSX0NPUkU6LTZ9JwogICAgICAtIF9BUFBfT1BFTlNTTF9LRVlfVjE9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSAnX0FQUF9SRURJU19IT1NUPSR7X0FQUF9SRURJU19IT1NUOi1hcHB3cml0ZS1yZWRpc30nCiAgICAgIC0gJ19BUFBfUkVESVNfUE9SVD0ke19BUFBfUkVESVNfUE9SVDotNjM3OX0nCiAgICAgIC0gJ19BUFBfUkVESVNfVVNFUj0ke19BUFBfUkVESVNfVVNFUn0nCiAgICAgIC0gJ19BUFBfUkVESVNfUEFTUz0ke19BUFBfUkVESVNfUEFTU30nCiAgICAgIC0gJ19BUFBfREJfSE9TVD0ke19BUFBfREJfSE9TVDotYXBwd3JpdGUtbWFyaWFkYn0nCiAgICAgIC0gJ19BUFBfREJfUE9SVD0ke19BUFBfREJfUE9SVDotMzMwNn0nCiAgICAgIC0gJ19BUFBfREJfU0NIRU1BPSR7X0FQUF9EQl9TQ0hFTUE6LWFwcHdyaXRlfScKICAgICAgLSBfQVBQX0RCX1VTRVI9JFNFUlZJQ0VfVVNFUl9NQVJJQURCCiAgICAgIC0gX0FQUF9EQl9QQVNTPSRTRVJWSUNFX1BBU1NXT1JEX01BUklBREIKICBhcHB3cml0ZS10YXNrLXNjaGVkdWxlci1tZXNzYWdlczoKICAgIGltYWdlOiAnYXBwd3JpdGUvYXBwd3JpdGU6MS42LjAnCiAgICBlbnRyeXBvaW50OiBzY2hlZHVsZS1tZXNzYWdlcwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXRhc2stc2NoZWR1bGVyLW1lc3NhZ2VzCiAgICBkZXBlbmRzX29uOgogICAgICAtIGFwcHdyaXRlLW1hcmlhZGIKICAgICAgLSBhcHB3cml0ZS1yZWRpcwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gJ19BUFBfRU5WPSR7X0FQUF9FTlY6LXByb2R1Y3Rpb259JwogICAgICAtICdfQVBQX1dPUktFUl9QRVJfQ09SRT0ke19BUFBfV09SS0VSX1BFUl9DT1JFOi02fScKICAgICAgLSBfQVBQX09QRU5TU0xfS0VZX1YxPSRTRVJWSUNFX1BBU1NXT1JEXzY0X0FQUFdSSVRFCiAgICAgIC0gJ19BUFBfUkVESVNfSE9TVD0ke19BUFBfUkVESVNfSE9TVDotYXBwd3JpdGUtcmVkaXN9JwogICAgICAtICdfQVBQX1JFRElTX1BPUlQ9JHtfQVBQX1JFRElTX1BPUlQ6LTYzNzl9JwogICAgICAtICdfQVBQX1JFRElTX1VTRVI9JHtfQVBQX1JFRElTX1VTRVJ9JwogICAgICAtICdfQVBQX1JFRElTX1BBU1M9JHtfQVBQX1JFRElTX1BBU1N9JwogICAgICAtICdfQVBQX0RCX0hPU1Q9JHtfQVBQX0RCX0hPU1Q6LWFwcHdyaXRlLW1hcmlhZGJ9JwogICAgICAtICdfQVBQX0RCX1BPUlQ9JHtfQVBQX0RCX1BPUlQ6LTMzMDZ9JwogICAgICAtICdfQVBQX0RCX1NDSEVNQT0ke19BUFBfREJfU0NIRU1BOi1hcHB3cml0ZX0nCiAgICAgIC0gX0FQUF9EQl9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIF9BUFBfREJfUEFTUz0kU0VSVklDRV9QQVNTV09SRF9NQVJJQURCCiAgYXBwd3JpdGUtYXNzaXN0YW50OgogICAgaW1hZ2U6ICdhcHB3cml0ZS9hc3Npc3RhbnQ6MC40LjAnCiAgICBjb250YWluZXJfbmFtZTogYXBwd3JpdGUtYXNzaXN0YW50CiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnX0FQUF9BU1NJU1RBTlRfT1BFTkFJX0FQSV9LRVk9JHtfQVBQX0FTU0lTVEFOVF9PUEVOQUlfQVBJX0tFWX0nCiAgb3BlbnJ1bnRpbWVzLWV4ZWN1dG9yOgogICAgY29udGFpbmVyX25hbWU6IG9wZW5ydW50aW1lcy1leGVjdXRvcgogICAgaG9zdG5hbWU6IGFwcHdyaXRlLWV4ZWN1dG9yCiAgICBzdG9wX3NpZ25hbDogU0lHSU5UCiAgICBpbWFnZTogJ29wZW5ydW50aW1lcy9leGVjdXRvcjowLjYuMTEnCiAgICBuZXR3b3JrczoKICAgICAgLSBydW50aW1lcwogICAgdm9sdW1lczoKICAgICAgLSAnL3Zhci9ydW4vZG9ja2VyLnNvY2s6L3Zhci9ydW4vZG9ja2VyLnNvY2snCiAgICAgIC0gJ2FwcHdyaXRlLWJ1aWxkczovc3RvcmFnZS9idWlsZHM6cncnCiAgICAgIC0gJ2FwcHdyaXRlLWZ1bmN0aW9uczovc3RvcmFnZS9mdW5jdGlvbnM6cncnCiAgICAgIC0gJy90bXA6L3RtcDpydycKICAgIGVudmlyb25tZW50OgogICAgICAtICdPUFJfRVhFQ1VUT1JfSU5BQ1RJVkVfVFJFU0hPTEQ9JHtfQVBQX0ZVTkNUSU9OU19JTkFDVElWRV9USFJFU0hPTER9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfTUFJTlRFTkFOQ0VfSU5URVJWQUw9JHtfQVBQX0ZVTkNUSU9OU19NQUlOVEVOQU5DRV9JTlRFUlZBTH0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9ORVRXT1JLPSR7X0FQUF9GVU5DVElPTlNfUlVOVElNRVNfTkVUV09SSzotcnVudGltZXN9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfRE9DS0VSX0hVQl9VU0VSTkFNRT0ke19BUFBfRE9DS0VSX0hVQl9VU0VSTkFNRX0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9ET0NLRVJfSFVCX1BBU1NXT1JEPSR7X0FQUF9ET0NLRVJfSFVCX1BBU1NXT1JEfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX0VOVj0ke19BUFBfRU5WOi1wcm9kdWN0aW9ufScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1JVTlRJTUVTPSR7X0FQUF9GVU5DVElPTlNfUlVOVElNRVN9JwogICAgICAtIE9QUl9FWEVDVVRPUl9TRUNSRVQ9JFNFUlZJQ0VfUEFTU1dPUkRfNjRfQVBQV1JJVEUKICAgICAgLSAnT1BSX0VYRUNVVE9SX0xPR0dJTkdfQ09ORklHPSR7X0FQUF9MT0dHSU5HX0NPTkZJR30nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX0RFVklDRT0ke19BUFBfU1RPUkFHRV9ERVZJQ0U6LWxvY2FsfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfUzNfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9TM19BQ0NFU1NfS0VZOi1sb2NhbH0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX1MzX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9TM19TRUNSRVR9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfU1RPUkFHRV9TM19SRUdJT049JHtfQVBQX1NUT1JBR0VfUzNfUkVHSU9OfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfUzNfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX1MzX0JVQ0tFVH0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX0RPX1NQQUNFU19BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX0RPX1NQQUNFU19BQ0NFU1NfS0VZfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfRE9fU1BBQ0VTX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfU0VDUkVUfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfRE9fU1BBQ0VTX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfUkVHSU9OfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfRE9fU1BBQ0VTX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9ET19TUEFDRVNfQlVDS0VUfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfQkFDS0JMQVpFX0FDQ0VTU19LRVk9JHtfQVBQX1NUT1JBR0VfQkFDS0JMQVpFX0FDQ0VTU19LRVl9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfU1RPUkFHRV9CQUNLQkxBWkVfU0VDUkVUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9TRUNSRVR9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfU1RPUkFHRV9CQUNLQkxBWkVfUkVHSU9OPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9SRUdJT059JwogICAgICAtICdPUFJfRVhFQ1VUT1JfU1RPUkFHRV9CQUNLQkxBWkVfQlVDS0VUPSR7X0FQUF9TVE9SQUdFX0JBQ0tCTEFaRV9CVUNLRVR9JwogICAgICAtICdPUFJfRVhFQ1VUT1JfU1RPUkFHRV9MSU5PREVfQUNDRVNTX0tFWT0ke19BUFBfU1RPUkFHRV9MSU5PREVfQUNDRVNTX0tFWX0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX0xJTk9ERV9TRUNSRVQ9JHtfQVBQX1NUT1JBR0VfTElOT0RFX1NFQ1JFVH0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX0xJTk9ERV9SRUdJT049JHtfQVBQX1NUT1JBR0VfTElOT0RFX1JFR0lPTn0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX0xJTk9ERV9CVUNLRVQ9JHtfQVBQX1NUT1JBR0VfTElOT0RFX0JVQ0tFVH0nCiAgICAgIC0gJ09QUl9FWEVDVVRPUl9TVE9SQUdFX1dBU0FCSV9BQ0NFU1NfS0VZPSR7X0FQUF9TVE9SQUdFX1dBU0FCSV9BQ0NFU1NfS0VZfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfV0FTQUJJX1NFQ1JFVD0ke19BUFBfU1RPUkFHRV9XQVNBQklfU0VDUkVUfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfV0FTQUJJX1JFR0lPTj0ke19BUFBfU1RPUkFHRV9XQVNBQklfUkVHSU9OfScKICAgICAgLSAnT1BSX0VYRUNVVE9SX1NUT1JBR0VfV0FTQUJJX0JVQ0tFVD0ke19BUFBfU1RPUkFHRV9XQVNBQklfQlVDS0VUfScKICBhcHB3cml0ZS1tYXJpYWRiOgogICAgaW1hZ2U6ICdtYXJpYWRiOjEwLjExJwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLW1hcmlhZGIKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2FwcHdyaXRlLW1hcmlhZGI6L3Zhci9saWIvbXlzcWw6cncnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBNWVNRTF9ST09UX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX01BUklBREJST09UCiAgICAgIC0gJ01ZU1FMX0RBVEFCQVNFPSR7X0FQUF9EQl9TQ0hFTUE6LWFwcHdyaXRlfScKICAgICAgLSBNWVNRTF9VU0VSPSRTRVJWSUNFX1VTRVJfTUFSSUFEQgogICAgICAtIE1ZU1FMX1BBU1NXT1JEPSRTRVJWSUNFX1BBU1NXT1JEX01BUklBREIKICAgICAgLSBNQVJJQURCX0FVVE9fVVBHUkFERT0xCiAgICBjb21tYW5kOiAnbXlzcWxkIC0taW5ub2RiLWZsdXNoLW1ldGhvZD1mc3luYycKICBhcHB3cml0ZS1yZWRpczoKICAgIGltYWdlOiAncmVkaXM6Ny4yLjQtYWxwaW5lJwogICAgY29udGFpbmVyX25hbWU6IGFwcHdyaXRlLXJlZGlzCiAgICBjb21tYW5kOiAicmVkaXMtc2VydmVyIC0tbWF4bWVtb3J5ICAgICAgICAgICAgNTEybWIgLS1tYXhtZW1vcnktcG9saWN5ICAgICBhbGxrZXlzLWxydSAtLW1heG1lbW9yeS1zYW1wbGVzICAgIDVcbiIKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2FwcHdyaXRlLXJlZGlzOi9kYXRhOnJ3JwpuZXR3b3JrczoKICBydW50aW1lczoKICAgIG5hbWU6IHJ1bnRpbWVzCnZvbHVtZXM6CiAgYXBwd3JpdGUtbWFyaWFkYjogbnVsbAogIGFwcHdyaXRlLXJlZGlzOiBudWxsCiAgYXBwd3JpdGUtY2FjaGU6IG51bGwKICBhcHB3cml0ZS11cGxvYWRzOiBudWxsCiAgYXBwd3JpdGUtY2VydGlmaWNhdGVzOiBudWxsCiAgYXBwd3JpdGUtZnVuY3Rpb25zOiBudWxsCiAgYXBwd3JpdGUtYnVpbGRzOiBudWxsCiAgYXBwd3JpdGUtY29uZmlnOiBudWxsCg==", "tags": [ "backend-as-a-service", "platform" @@ -192,7 +192,7 @@ "browserless": { "documentation": "https://docs.browserless.io/?utm_source=coolify.io", "slogan": "A headless Chrome browser as a service .", - "compose": "c2VydmljZXM6CiAgYnJvd3Nlcmxlc3M6CiAgICBpbWFnZTogZ2hjci5pby9icm93c2VybGVzcy9jaHJvbWl1bQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0JST1dTRVJMRVNTXzMwMDAKICAgICAgLSBUT0tFTj0kU0VSVklDRV9CQVNFNjRfQlJPV1NFUkxFU1NfVE9LRU4KICAgIGV4cG9zZToKICAgICAgLSAzMDAwCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6MzAwMC9kb2NzJwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1Cg==", + "compose": "c2VydmljZXM6CiAgYnJvd3Nlcmxlc3M6CiAgICBpbWFnZTogZ2hjci5pby9icm93c2VybGVzcy9jaHJvbWl1bQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0JST1dTRVJMRVNTXzMwMDAKICAgICAgLSBUT0tFTj0kU0VSVklDRV9QQVNTV09SRF9CUk9XU0VSTEVTUwogICAgZXhwb3NlOgogICAgICAtIDMwMDAKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTozMDAwL2RvY3MnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK", "tags": [ "chrome", "headless", @@ -642,7 +642,7 @@ }, "embystat": { "documentation": "https://github.com/mregni/EmbyStat?utm_source=coolify.io", - "slogan": "EmnyStat is a web analytics tool, designed to provide insight into website traffic and user behavior.", + "slogan": "EmbyStat is a web analytics tool, designed to provide insight into website traffic and user behavior.", "compose": "c2VydmljZXM6CiAgZW1ieXN0YXQ6CiAgICBpbWFnZTogJ2xzY3IuaW8vbGludXhzZXJ2ZXIvZW1ieXN0YXQ6bGF0ZXN0JwogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0VNQllTVEFUXzY1NTUKICAgICAgLSBQVUlEPTEwMDAKICAgICAgLSBQR0lEPTEwMDAKICAgICAgLSBUWj1FdXJvcGUvTWFkcmlkCiAgICB2b2x1bWVzOgogICAgICAtICdlbWJ5c3RhdC1jb25maWc6L2NvbmZpZycKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTo2NTU1JwogICAgICBpbnRlcnZhbDogMnMKICAgICAgdGltZW91dDogMTBzCiAgICAgIHJldHJpZXM6IDE1Cg==", "tags": [ "media", @@ -1131,7 +1131,7 @@ "heyform": { "documentation": "https://docs.heyform.net/open-source/self-hosting?utm_source=coolify.io", "slogan": "Allows anyone to create engaging conversational forms for surveys, questionnaires, quizzes, and polls. No coding skills required.", - "compose": "c2VydmljZXM6CiAgaGV5Zm9ybToKICAgIGltYWdlOiAnaGV5Zm9ybS9jb21tdW5pdHktZWRpdGlvbjpsYXRlc3QnCiAgICB2b2x1bWVzOgogICAgICAtICdoZXlmb3JtLWFzc2V0czovYXBwL3N0YXRpYy91cGxvYWQnCiAgICBkZXBlbmRzX29uOgogICAgICBtb25nbzoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBrZXlkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0hFWUZPUk1fODAwMAogICAgICAtICdBUFBfSE9NRVBBR0VfVVJMPSR7U0VSVklDRV9GUUROX0hFWUZPUk19JwogICAgICAtICdTRVNTSU9OX0tFWT0ke1NFUlZJQ0VfQkFTRTY0XzY0X1NFU1NJT059JwogICAgICAtICdGT1JNX0VOQ1JZUFRJT05fS0VZPSR7U0VSVklDRV9CQVNFNjRfNjRfRk9STX0nCiAgICAgIC0gJ01PTkdPX1VSST1tb25nb2RiOi8vbW9uZ286MjcwMTcvaGV5Zm9ybScKICAgICAgLSBSRURJU19IT1NUPWtleWRiCiAgICAgIC0gUkVESVNfUE9SVD02Mzc5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3dnZXQgLXFPLSBodHRwOi8vMTI3LjAuMC4xOjgwMDAgfHwgZXhpdCAxJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogMwogIG1vbmdvOgogICAgaW1hZ2U6ICdwZXJjb25hL3BlcmNvbmEtc2VydmVyLW1vbmdvZGI6bGF0ZXN0JwogICAgdm9sdW1lczoKICAgICAgLSAnaGV5Zm9ybS1tb25nby1kYXRhOi9kYXRhL2RiJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICJlY2hvICdvaycgPiAvZGV2L251bGwgMj4mMSIKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgICAgIHN0YXJ0X3BlcmlvZDogNXMKICBrZXlkYjoKICAgIGltYWdlOiAnZXFhbHBoYS9rZXlkYjpsYXRlc3QnCiAgICBjb21tYW5kOiAna2V5ZGItc2VydmVyIC0tYXBwZW5kb25seSB5ZXMnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnS0VZREJfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX0tFWURCfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2hleWZvcm0ta2V5ZGItZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSBrZXlkYi1jbGkKICAgICAgICAtICctLXBhc3MnCiAgICAgICAgLSAnJHtTRVJWSUNFX1BBU1NXT1JEX0tFWURCfScKICAgICAgICAtIHBpbmcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgICAgIHN0YXJ0X3BlcmlvZDogNXMK", + "compose": "c2VydmljZXM6CiAgaGV5Zm9ybToKICAgIGltYWdlOiAnaGV5Zm9ybS9jb21tdW5pdHktZWRpdGlvbjpsYXRlc3QnCiAgICB2b2x1bWVzOgogICAgICAtICdoZXlmb3JtLWFzc2V0czovYXBwL3N0YXRpYy91cGxvYWQnCiAgICBkZXBlbmRzX29uOgogICAgICBtb25nbzoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBrZXlkYjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgZW52aXJvbm1lbnQ6CiAgICAgIC0gU0VSVklDRV9GUUROX0hFWUZPUk1fODAwMAogICAgICAtICdBUFBfSE9NRVBBR0VfVVJMPSR7U0VSVklDRV9GUUROX0hFWUZPUk19JwogICAgICAtICdTRVNTSU9OX0tFWT0ke1NFUlZJQ0VfQkFTRTY0XzY0X1NFU1NJT059JwogICAgICAtICdGT1JNX0VOQ1JZUFRJT05fS0VZPSR7U0VSVklDRV9CQVNFNjRfNjRfRk9STX0nCiAgICAgIC0gJ01PTkdPX1VSST1tb25nb2RiOi8vbW9uZ286MjcwMTcvaGV5Zm9ybScKICAgICAgLSBSRURJU19IT1NUPWtleWRiCiAgICAgIC0gUkVESVNfUE9SVD02Mzc5CiAgICAgIC0gJ1JFRElTX1BBU1NXT1JEPSR7U0VSVklDRV9QQVNTV09SRF9LRVlEQn0nCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ3dnZXQgLXFPLSBodHRwOi8vMTI3LjAuMC4xOjgwMDAgfHwgZXhpdCAxJwogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogMwogIG1vbmdvOgogICAgaW1hZ2U6ICdwZXJjb25hL3BlcmNvbmEtc2VydmVyLW1vbmdvZGI6bGF0ZXN0JwogICAgdm9sdW1lczoKICAgICAgLSAnaGV5Zm9ybS1tb25nby1kYXRhOi9kYXRhL2RiJwogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICJlY2hvICdvaycgPiAvZGV2L251bGwgMj4mMSIKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgICAgIHN0YXJ0X3BlcmlvZDogNXMKICBrZXlkYjoKICAgIGltYWdlOiAnZXFhbHBoYS9rZXlkYjpsYXRlc3QnCiAgICBjb21tYW5kOiAna2V5ZGItc2VydmVyIC0tYXBwZW5kb25seSB5ZXMnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnS0VZREJfUEFTU1dPUkQ9JHtTRVJWSUNFX1BBU1NXT1JEX0tFWURCfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2hleWZvcm0ta2V5ZGItZGF0YTovZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSBrZXlkYi1jbGkKICAgICAgICAtICctLXBhc3MnCiAgICAgICAgLSAnJHtTRVJWSUNFX1BBU1NXT1JEX0tFWURCfScKICAgICAgICAtIHBpbmcKICAgICAgaW50ZXJ2YWw6IDVzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDEwCiAgICAgIHN0YXJ0X3BlcmlvZDogNXMK", "tags": [ "form", "builder", @@ -1149,7 +1149,7 @@ "hoarder": { "documentation": "https://docs.hoarder.app/?utm_source=coolify.io", "slogan": "an open source \"Bookmark Everything\" app that uses AI for automatically tagging the content you throw at it.", - "compose": "c2VydmljZXM6CiAgd2ViOgogICAgaW1hZ2U6ICdnaGNyLmlvL2hvYXJkZXItYXBwL2hvYXJkZXI6cmVsZWFzZScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2hvYXJkZXItZGF0YTovZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9IT0FSREVSCiAgICAgIC0gJ05FWFRBVVRIX1NFQ1JFVD0ke1NFUlZJQ0VfUEFTU1dPUkRfSE9BUkRFUk5FWFRBVVRIfScKICAgICAgLSAnTUVJTElfTUFTVEVSX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfTUVJTEl9JwogICAgICAtICdORVhUQVVUSF9VUkw9JHtTRVJWSUNFX0ZRRE5fSE9BUkRFUn0nCiAgICAgIC0gJ01FSUxJX0FERFI9aHR0cDovL21laWxpc2VhcmNoOjc3MDAnCiAgICAgIC0gJ0JST1dTRVJfV0VCX1VSTD1odHRwOi8vY2hyb21lOjkyMjInCiAgICAgIC0gREFUQV9ESVI9L2RhdGEKICBjaHJvbWU6CiAgICBpbWFnZTogJ2djci5pby96ZW5pa2EtaHViL2FscGluZS1jaHJvbWU6MTI0JwogICAgY29tbWFuZDoKICAgICAgLSAnLS1uby1zYW5kYm94JwogICAgICAtICctLWRpc2FibGUtZ3B1JwogICAgICAtICctLWRpc2FibGUtZGV2LXNobS11c2FnZScKICAgICAgLSAnLS1yZW1vdGUtZGVidWdnaW5nLWFkZHJlc3M9MC4wLjAuMCcKICAgICAgLSAnLS1yZW1vdGUtZGVidWdnaW5nLXBvcnQ9OTIyMicKICAgICAgLSAnLS1oaWRlLXNjcm9sbGJhcnMnCiAgbWVpbGlzZWFyY2g6CiAgICBpbWFnZTogJ2dldG1laWxpL21laWxpc2VhcmNoOnYxLjYnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSAnTUVJTElfTk9fQU5BTFlUSUNTPSR7TUVJTElfTk9fQU5BTFlUSUNTOi10cnVlfScKICAgICAgLSAnTkVYVEFVVEhfU0VDUkVUPSR7U0VSVklDRV9QQVNTV09SRF9IT0FSREVSTkVYVEFVVEh9JwogICAgICAtICdNRUlMSV9NQVNURVJfS0VZPSR7U0VSVklDRV9QQVNTV09SRF9NRUlMSX0nCiAgICAgIC0gJ05FWFRBVVRIX1VSTD0ke1NFUlZJQ0VfRlFETl9IT0FSREVSfScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2hvYXJkZXItbWVpbGlzZWFyY2g6L21laWxpX2RhdGEnCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gY3VybAogICAgICAgIC0gJy1mJwogICAgICAgIC0gJ2h0dHA6Ly8xMjcuMC4wLjE6NzcwMC9oZWFsdGgnCiAgICAgIGludGVydmFsOiAycwogICAgICB0aW1lb3V0OiAxMHMKICAgICAgcmV0cmllczogMTUK", + "compose": "c2VydmljZXM6CiAgd2ViOgogICAgaW1hZ2U6ICdnaGNyLmlvL2hvYXJkZXItYXBwL2hvYXJkZXI6cmVsZWFzZScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ2hvYXJkZXItZGF0YTovZGF0YScKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9IT0FSREVSCiAgICAgIC0gJ05FWFRBVVRIX1NFQ1JFVD0ke1NFUlZJQ0VfUEFTU1dPUkRfSE9BUkRFUk5FWFRBVVRIfScKICAgICAgLSAnTUVJTElfTUFTVEVSX0tFWT0ke1NFUlZJQ0VfUEFTU1dPUkRfTUVJTEl9JwogICAgICAtICdORVhUQVVUSF9VUkw9JHtTRVJWSUNFX0ZRRE5fSE9BUkRFUn0nCiAgICAgIC0gJ01FSUxJX0FERFI9aHR0cDovL21laWxpc2VhcmNoOjc3MDAnCiAgICAgIC0gJ0JST1dTRVJfV0VCX1VSTD1odHRwOi8vY2hyb21lOjkyMjInCiAgICAgIC0gJ09QRU5BSV9BUElfS0VZPSR7U0VSVklDRV9PUEVOQUlfQVBJX0tFWX0nCiAgICAgIC0gJ0RJU0FCTEVfU0lHTlVQUz0ke1NFUlZJQ0VfRElTQUJMRV9TSUdOVVBTfScKICAgICAgLSBEQVRBX0RJUj0vZGF0YQogIGNocm9tZToKICAgIGltYWdlOiAnZ2NyLmlvL3plbmlrYS1odWIvYWxwaW5lLWNocm9tZToxMjQnCiAgICBjb21tYW5kOgogICAgICAtICctLW5vLXNhbmRib3gnCiAgICAgIC0gJy0tZGlzYWJsZS1ncHUnCiAgICAgIC0gJy0tZGlzYWJsZS1kZXYtc2htLXVzYWdlJwogICAgICAtICctLXJlbW90ZS1kZWJ1Z2dpbmctYWRkcmVzcz0wLjAuMC4wJwogICAgICAtICctLXJlbW90ZS1kZWJ1Z2dpbmctcG9ydD05MjIyJwogICAgICAtICctLWhpZGUtc2Nyb2xsYmFycycKICBtZWlsaXNlYXJjaDoKICAgIGltYWdlOiAnZ2V0bWVpbGkvbWVpbGlzZWFyY2g6djEuNicKICAgIGVudmlyb25tZW50OgogICAgICAtICdNRUlMSV9OT19BTkFMWVRJQ1M9JHtNRUlMSV9OT19BTkFMWVRJQ1M6LXRydWV9JwogICAgICAtICdORVhUQVVUSF9TRUNSRVQ9JHtTRVJWSUNFX1BBU1NXT1JEX0hPQVJERVJORVhUQVVUSH0nCiAgICAgIC0gJ01FSUxJX01BU1RFUl9LRVk9JHtTRVJWSUNFX1BBU1NXT1JEX01FSUxJfScKICAgICAgLSAnTkVYVEFVVEhfVVJMPSR7U0VSVklDRV9GUUROX0hPQVJERVJ9JwogICAgdm9sdW1lczoKICAgICAgLSAnaG9hcmRlci1tZWlsaXNlYXJjaDovbWVpbGlfZGF0YScKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSBjdXJsCiAgICAgICAgLSAnLWYnCiAgICAgICAgLSAnaHR0cDovLzEyNy4wLjAuMTo3NzAwL2hlYWx0aCcKICAgICAgaW50ZXJ2YWw6IDJzCiAgICAgIHRpbWVvdXQ6IDEwcwogICAgICByZXRyaWVzOiAxNQo=", "tags": [ "media", "read-it-later", @@ -1568,7 +1568,7 @@ "mailpit": { "documentation": "https://mailpit.axllent.org/docs/?utm_source=coolify.io", "slogan": "Email & SMTP testing tool with API for developers", - "compose": "c2VydmljZXM6CiAgbWFpbHBpdDoKICAgIGltYWdlOiBheGxsZW50L21haWxwaXQKICAgIHZvbHVtZXM6CiAgICAgIC0gJ21haWxwaXQtZGF0YTovZGF0YScKICAgICAgLQogICAgICAgIHR5cGU6IGJpbmQKICAgICAgICBzb3VyY2U6IC4vaHRwYXNzd2QKICAgICAgICB0YXJnZXQ6IC9kYXRhL2h0cGFzc3dkCiAgICAgICAgaXNEaXJlY3Rvcnk6IGZhbHNlCiAgICAgICAgY29udGVudDogJycKICAgIGVudmlyb25tZW50OgogICAgICAtIFNFUlZJQ0VfRlFETl9NQUlMUElUXzgwMjUKICAgICAgLSBNUF9NQVhfTUVTU0FHRVM9NTAwMAogICAgICAtIE1QX0RBVEFCQVNFPS9kYXRhL21haWxwaXQuZGIKICAgICAgLSBNUF9TTVRQX0FVVEhfQUNDRVBUX0FOWT0xCiAgICAgIC0gTVBfU01UUF9BVVRIX0FMTE9XX0lOU0VDVVJFPTEKICAgICAgLSBNUF9VSV9BVVRIX0ZJTEU9L2RhdGEvaHRwYXNzd2QKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ECiAgICAgICAgLSAvbWFpbHBpdAogICAgICAgIC0gcmVhZHl6CiAgICAgIGludGVydmFsOiA1cwogICAgICB0aW1lb3V0OiAyMHMKICAgICAgcmV0cmllczogMTAK", + "compose": "c2VydmljZXM6CiAgbWFpbHBpdDoKICAgIGltYWdlOiBheGxsZW50L21haWxwaXQKICAgIHBvcnRzOgogICAgICAtICcxMDI1OjEwMjUnCiAgICB2b2x1bWVzOgogICAgICAtICdtYWlscGl0LWRhdGE6L2RhdGEnCiAgICAgIC0KICAgICAgICB0eXBlOiBiaW5kCiAgICAgICAgc291cmNlOiAuL2h0cGFzc3dkCiAgICAgICAgdGFyZ2V0OiAvZGF0YS9odHBhc3N3ZAogICAgICAgIGlzRGlyZWN0b3J5OiBmYWxzZQogICAgICAgIGNvbnRlbnQ6ICcnCiAgICBlbnZpcm9ubWVudDoKICAgICAgLSBTRVJWSUNFX0ZRRE5fTUFJTFBJVF84MDI1CiAgICAgIC0gTVBfTUFYX01FU1NBR0VTPTUwMDAKICAgICAgLSBNUF9EQVRBQkFTRT0vZGF0YS9tYWlscGl0LmRiCiAgICAgIC0gTVBfU01UUF9BVVRIX0FDQ0VQVF9BTlk9MQogICAgICAtIE1QX1NNVFBfQVVUSF9BTExPV19JTlNFQ1VSRT0xCiAgICAgIC0gTVBfVUlfQVVUSF9GSUxFPS9kYXRhL2h0cGFzc3dkCiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRAogICAgICAgIC0gL21haWxwaXQKICAgICAgICAtIHJlYWR5egogICAgICBpbnRlcnZhbDogNXMKICAgICAgdGltZW91dDogMjBzCiAgICAgIHJldHJpZXM6IDEwCg==", "tags": [ "mailpit", "email", diff --git a/versions.json b/versions.json index daf0da74b..20b06b4de 100644 --- a/versions.json +++ b/versions.json @@ -1,16 +1,16 @@ { "coolify": { "v4": { - "version": "4.0.0-beta.368" + "version": "4.0.0-beta.372" }, "nightly": { - "version": "4.0.0-beta.369" + "version": "4.0.0-beta.373" }, "helper": { - "version": "1.0.3" + "version": "1.0.4" }, "realtime": { - "version": "1.0.4" + "version": "1.0.5" }, "sentinel": { "version": "0.0.15"
Are you sure you would like to upgrade your instance to {{ $latestVersion }}?
Warning: Any deployments running during the update process will fail. Please ensure no deployments are in progress on any server before continuing.
You can review the changelogs here.