mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-15 10:14:47 +00:00
Merge branch 'next' into improve-scheduled-tasks
This commit is contained in:
13 files changed
+77
-76
No files matched your search
@@ -10,6 +10,7 @@ use App\Models\Server;
|
|||||||
use App\Models\ServiceDatabase;
|
use App\Models\ServiceDatabase;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
class GetContainersStatus
|
class GetContainersStatus
|
||||||
@@ -376,6 +377,10 @@ class GetContainersStatus
|
|||||||
if (isset($this->applicationContainerRestartCounts) && $this->applicationContainerRestartCounts->has($applicationId)) {
|
if (isset($this->applicationContainerRestartCounts) && $this->applicationContainerRestartCounts->has($applicationId)) {
|
||||||
$containerRestartCounts = $this->applicationContainerRestartCounts->get($applicationId);
|
$containerRestartCounts = $this->applicationContainerRestartCounts->get($applicationId);
|
||||||
$maxRestartCount = $containerRestartCounts->max() ?? 0;
|
$maxRestartCount = $containerRestartCounts->max() ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap all database updates in a transaction to ensure consistency
|
||||||
|
DB::transaction(function () use ($application, $maxRestartCount, $containerStatuses) {
|
||||||
$previousRestartCount = $application->restart_count ?? 0;
|
$previousRestartCount = $application->restart_count ?? 0;
|
||||||
|
|
||||||
if ($maxRestartCount > $previousRestartCount) {
|
if ($maxRestartCount > $previousRestartCount) {
|
||||||
@@ -398,18 +403,18 @@ class GetContainersStatus
|
|||||||
$url = null;
|
$url = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Aggregate status after tracking restart counts
|
// Aggregate status after tracking restart counts
|
||||||
$aggregatedStatus = $this->aggregateApplicationStatus($application, $containerStatuses, $maxRestartCount);
|
$aggregatedStatus = $this->aggregateApplicationStatus($application, $containerStatuses, $maxRestartCount);
|
||||||
if ($aggregatedStatus) {
|
if ($aggregatedStatus) {
|
||||||
$statusFromDb = $application->status;
|
$statusFromDb = $application->status;
|
||||||
if ($statusFromDb !== $aggregatedStatus) {
|
if ($statusFromDb !== $aggregatedStatus) {
|
||||||
$application->update(['status' => $aggregatedStatus]);
|
$application->update(['status' => $aggregatedStatus]);
|
||||||
} else {
|
} else {
|
||||||
$application->update(['last_online_at' => now()]);
|
$application->update(['last_online_at' => now()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,22 +20,23 @@ class StartService
|
|||||||
}
|
}
|
||||||
$service->saveComposeConfigs();
|
$service->saveComposeConfigs();
|
||||||
$service->isConfigurationChanged(save: true);
|
$service->isConfigurationChanged(save: true);
|
||||||
$commands[] = 'cd '.$service->workdir();
|
$workdir = $service->workdir();
|
||||||
$commands[] = "echo 'Saved configuration files to {$service->workdir()}.'";
|
// $commands[] = "cd {$workdir}";
|
||||||
// Ensure .env file exists before docker compose tries to load it
|
$commands[] = "echo 'Saved configuration files to {$workdir}.'";
|
||||||
|
// Ensure .env exists in the correct directory before docker compose tries to load it
|
||||||
// This is defensive programming - saveComposeConfigs() already creates it,
|
// This is defensive programming - saveComposeConfigs() already creates it,
|
||||||
// but we guarantee it here in case of any edge cases or manual deployments
|
// but we guarantee it here in case of any edge cases or manual deployments
|
||||||
$commands[] = 'touch .env';
|
$commands[] = "touch {$workdir}/.env";
|
||||||
if ($pullLatestImages) {
|
if ($pullLatestImages) {
|
||||||
$commands[] = "echo 'Pulling images.'";
|
$commands[] = "echo 'Pulling images.'";
|
||||||
$commands[] = 'docker compose pull';
|
$commands[] = "docker compose --project-directory {$workdir} pull";
|
||||||
}
|
}
|
||||||
if ($service->networks()->count() > 0) {
|
if ($service->networks()->count() > 0) {
|
||||||
$commands[] = "echo 'Creating Docker network.'";
|
$commands[] = "echo 'Creating Docker network.'";
|
||||||
$commands[] = "docker network inspect $service->uuid >/dev/null 2>&1 || docker network create --attachable $service->uuid";
|
$commands[] = "docker network inspect $service->uuid >/dev/null 2>&1 || docker network create --attachable $service->uuid";
|
||||||
}
|
}
|
||||||
$commands[] = 'echo Starting service.';
|
$commands[] = 'echo Starting service.';
|
||||||
$commands[] = 'docker compose up -d --remove-orphans --force-recreate --build';
|
$commands[] = "docker compose --project-directory {$workdir} -f {$workdir}/docker-compose.yml --project-name {$service->uuid} up -d --remove-orphans --force-recreate --build";
|
||||||
$commands[] = "docker network connect $service->uuid coolify-proxy >/dev/null 2>&1 || true";
|
$commands[] = "docker network connect $service->uuid coolify-proxy >/dev/null 2>&1 || true";
|
||||||
if (data_get($service, 'connect_to_docker_network')) {
|
if (data_get($service, 'connect_to_docker_network')) {
|
||||||
$compose = data_get($service, 'docker_compose', []);
|
$compose = data_get($service, 'docker_compose', []);
|
||||||
|
|||||||
@@ -222,9 +222,14 @@ class CleanupStuckedResources extends Command
|
|||||||
try {
|
try {
|
||||||
$scheduled_backups = ScheduledDatabaseBackup::all();
|
$scheduled_backups = ScheduledDatabaseBackup::all();
|
||||||
foreach ($scheduled_backups as $scheduled_backup) {
|
foreach ($scheduled_backups as $scheduled_backup) {
|
||||||
if (! $scheduled_backup->server()) {
|
try {
|
||||||
echo "Deleting stuck scheduledbackup: {$scheduled_backup->name}\n";
|
$server = $scheduled_backup->server();
|
||||||
$scheduled_backup->delete();
|
if (! $server) {
|
||||||
|
echo "Deleting stuck scheduledbackup: {$scheduled_backup->name}\n";
|
||||||
|
$scheduled_backup->delete();
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
echo "Error checking server for scheduledbackup {$scheduled_backup->id}: {$e->getMessage()}\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
@@ -416,7 +421,7 @@ class CleanupStuckedResources extends Command
|
|||||||
foreach ($serviceApplications as $service) {
|
foreach ($serviceApplications as $service) {
|
||||||
if (! data_get($service, 'service')) {
|
if (! data_get($service, 'service')) {
|
||||||
echo 'ServiceApplication without service: '.$service->name.'\n';
|
echo 'ServiceApplication without service: '.$service->name.'\n';
|
||||||
DeleteResourceJob::dispatch($service);
|
$service->forceDelete();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -429,7 +434,7 @@ class CleanupStuckedResources extends Command
|
|||||||
foreach ($serviceDatabases as $service) {
|
foreach ($serviceDatabases as $service) {
|
||||||
if (! data_get($service, 'service')) {
|
if (! data_get($service, 'service')) {
|
||||||
echo 'ServiceDatabase without service: '.$service->name.'\n';
|
echo 'ServiceDatabase without service: '.$service->name.'\n';
|
||||||
DeleteResourceJob::dispatch($service);
|
$service->forceDelete();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ class Init extends Command
|
|||||||
$this->call('cleanup:stucked-resources');
|
$this->call('cleanup:stucked-resources');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
echo "Error in cleanup:stucked-resources command: {$e->getMessage()}\n";
|
echo "Error in cleanup:stucked-resources command: {$e->getMessage()}\n";
|
||||||
|
echo "Continuing with initialization - cleanup errors will not prevent Coolify from starting\n";
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$updatedCount = ApplicationDeploymentQueue::whereIn('status', [
|
$updatedCount = ApplicationDeploymentQueue::whereIn('status', [
|
||||||
|
|||||||
@@ -275,16 +275,6 @@ class Github extends Controller
|
|||||||
instant_remote_process(["docker rm -f {$deployment_uuid}"], $server);
|
instant_remote_process(["docker rm -f {$deployment_uuid}"], $server);
|
||||||
$activeDeployment->addLogEntry('Deployment container stopped.');
|
$activeDeployment->addLogEntry('Deployment container stopped.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kill running process if process ID exists
|
|
||||||
if ($activeDeployment->current_process_id) {
|
|
||||||
try {
|
|
||||||
$processKillCommand = "kill -9 {$activeDeployment->current_process_id}";
|
|
||||||
instant_remote_process([$processKillCommand], $server);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
// Process might already be gone
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
// Silently handle errors during deployment cancellation
|
// Silently handle errors during deployment cancellation
|
||||||
}
|
}
|
||||||
@@ -555,15 +545,6 @@ class Github extends Controller
|
|||||||
$activeDeployment->addLogEntry('Deployment container stopped.');
|
$activeDeployment->addLogEntry('Deployment container stopped.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kill running process if process ID exists
|
|
||||||
if ($activeDeployment->current_process_id) {
|
|
||||||
try {
|
|
||||||
$processKillCommand = "kill -9 {$activeDeployment->current_process_id}";
|
|
||||||
instant_remote_process([$processKillCommand], $server);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
// Process might already be gone
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
// Silently handle errors during deployment cancellation
|
// Silently handle errors during deployment cancellation
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1173,7 +1173,10 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
if ($this->build_pack !== 'dockercompose') {
|
if ($this->build_pack !== 'dockercompose') {
|
||||||
$detectedPort = $this->application->detectPortFromEnvironment(false);
|
$detectedPort = $this->application->detectPortFromEnvironment(false);
|
||||||
if ($detectedPort && ! empty($ports) && ! in_array($detectedPort, $ports)) {
|
if ($detectedPort && ! empty($ports) && ! in_array($detectedPort, $ports)) {
|
||||||
ray()->orange("PORT environment variable ({$detectedPort}) does not match configured ports_exposes: ".implode(',', $ports));
|
$this->application_deployment_queue->addLogEntry(
|
||||||
|
"Warning: PORT environment variable ({$detectedPort}) does not match configured ports_exposes: ".implode(',', $ports).'. It could case "bad gateway" or "no server" errors. Check the "General" page to fix it.',
|
||||||
|
'stderr'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3062,7 +3065,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
|||||||
{
|
{
|
||||||
// Ensure .env file exists before docker compose tries to load it (defensive programming)
|
// Ensure .env file exists before docker compose tries to load it (defensive programming)
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
["touch {$this->workdir}/.env", 'hidden' => true],
|
|
||||||
["touch {$this->configuration_dir}/.env", 'hidden' => true],
|
["touch {$this->configuration_dir}/.env", 'hidden' => true],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -145,25 +145,17 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
|
|
||||||
// Check if helper container exists and kill it
|
// Check if helper container exists and kill it
|
||||||
$deployment_uuid = $activeDeployment->deployment_uuid;
|
$deployment_uuid = $activeDeployment->deployment_uuid;
|
||||||
$checkCommand = "docker ps -a --filter name={$deployment_uuid} --format '{{.Names}}'";
|
$escapedDeploymentUuid = escapeshellarg($deployment_uuid);
|
||||||
|
$checkCommand = "docker ps -a --filter name={$escapedDeploymentUuid} --format '{{.Names}}'";
|
||||||
$containerExists = instant_remote_process([$checkCommand], $server);
|
$containerExists = instant_remote_process([$checkCommand], $server);
|
||||||
|
|
||||||
if ($containerExists && str($containerExists)->trim()->isNotEmpty()) {
|
if ($containerExists && str($containerExists)->trim()->isNotEmpty()) {
|
||||||
instant_remote_process(["docker rm -f {$deployment_uuid}"], $server);
|
instant_remote_process(["docker rm -f {$escapedDeploymentUuid}"], $server);
|
||||||
$activeDeployment->addLogEntry('Deployment container stopped.');
|
$activeDeployment->addLogEntry('Deployment container stopped.');
|
||||||
} else {
|
} else {
|
||||||
$activeDeployment->addLogEntry('Helper container not yet started. Deployment will be cancelled when job checks status.');
|
$activeDeployment->addLogEntry('Helper container not yet started. Deployment will be cancelled when job checks status.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kill running process if process ID exists
|
|
||||||
if ($activeDeployment->current_process_id) {
|
|
||||||
try {
|
|
||||||
$processKillCommand = "kill -9 {$activeDeployment->current_process_id}";
|
|
||||||
instant_remote_process([$processKillCommand], $server);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
// Process might already be gone
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
// Silently handle errors during deployment cancellation
|
// Silently handle errors during deployment cancellation
|
||||||
}
|
}
|
||||||
@@ -171,7 +163,8 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if ($server->isSwarm()) {
|
if ($server->isSwarm()) {
|
||||||
instant_remote_process(["docker stack rm {$application->uuid}-{$pull_request_id}"], $server);
|
$escapedStackName = escapeshellarg("{$application->uuid}-{$pull_request_id}");
|
||||||
|
instant_remote_process(["docker stack rm {$escapedStackName}"], $server);
|
||||||
} else {
|
} else {
|
||||||
$containers = getCurrentApplicationContainerStatus($server, $application->id, $pull_request_id)->toArray();
|
$containers = getCurrentApplicationContainerStatus($server, $application->id, $pull_request_id)->toArray();
|
||||||
$this->stopPreviewContainers($containers, $server);
|
$this->stopPreviewContainers($containers, $server);
|
||||||
|
|||||||
@@ -94,14 +94,6 @@ class Heading extends Component
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset restart count on deployment
|
|
||||||
$this->application->update([
|
|
||||||
'restart_count' => 0,
|
|
||||||
'last_restart_at' => null,
|
|
||||||
'last_restart_type' => null,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->setDeploymentUuid();
|
$this->setDeploymentUuid();
|
||||||
$result = queue_application_deployment(
|
$result = queue_application_deployment(
|
||||||
application: $this->application,
|
application: $this->application,
|
||||||
@@ -109,11 +101,18 @@ class Heading extends Component
|
|||||||
force_rebuild: $force_rebuild,
|
force_rebuild: $force_rebuild,
|
||||||
);
|
);
|
||||||
if ($result['status'] === 'skipped') {
|
if ($result['status'] === 'skipped') {
|
||||||
$this->dispatch('success', 'Deployment skipped', $result['message']);
|
$this->dispatch('error', 'Deployment skipped', $result['message']);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset restart count on successful deployment
|
||||||
|
$this->application->update([
|
||||||
|
'restart_count' => 0,
|
||||||
|
'last_restart_at' => null,
|
||||||
|
'last_restart_type' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
return $this->redirectRoute('project.application.deployment.show', [
|
return $this->redirectRoute('project.application.deployment.show', [
|
||||||
'project_uuid' => $this->parameters['project_uuid'],
|
'project_uuid' => $this->parameters['project_uuid'],
|
||||||
'application_uuid' => $this->parameters['application_uuid'],
|
'application_uuid' => $this->parameters['application_uuid'],
|
||||||
@@ -146,13 +145,6 @@ class Heading extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset restart count on manual restart
|
|
||||||
$this->application->update([
|
|
||||||
'restart_count' => 0,
|
|
||||||
'last_restart_at' => now(),
|
|
||||||
'last_restart_type' => 'manual',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->setDeploymentUuid();
|
$this->setDeploymentUuid();
|
||||||
$result = queue_application_deployment(
|
$result = queue_application_deployment(
|
||||||
application: $this->application,
|
application: $this->application,
|
||||||
@@ -165,6 +157,13 @@ class Heading extends Component
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset restart count on manual restart
|
||||||
|
$this->application->update([
|
||||||
|
'restart_count' => 0,
|
||||||
|
'last_restart_at' => now(),
|
||||||
|
'last_restart_type' => 'manual',
|
||||||
|
]);
|
||||||
|
|
||||||
return $this->redirectRoute('project.application.deployment.show', [
|
return $this->redirectRoute('project.application.deployment.show', [
|
||||||
'project_uuid' => $this->parameters['project_uuid'],
|
'project_uuid' => $this->parameters['project_uuid'],
|
||||||
'application_uuid' => $this->parameters['application_uuid'],
|
'application_uuid' => $this->parameters['application_uuid'],
|
||||||
|
|||||||
@@ -149,9 +149,10 @@ class StackForm extends Component
|
|||||||
$this->service->save();
|
$this->service->save();
|
||||||
$this->service->saveExtraFields($this->fields);
|
$this->service->saveExtraFields($this->fields);
|
||||||
$this->service->parse();
|
$this->service->parse();
|
||||||
$this->service->refresh();
|
|
||||||
$this->service->saveComposeConfigs();
|
|
||||||
});
|
});
|
||||||
|
// Refresh and write files after a successful commit
|
||||||
|
$this->service->refresh();
|
||||||
|
$this->service->saveComposeConfigs();
|
||||||
|
|
||||||
$this->dispatch('refreshEnvs');
|
$this->dispatch('refreshEnvs');
|
||||||
$this->dispatch('refreshServices');
|
$this->dispatch('refreshServices');
|
||||||
|
|||||||
@@ -1302,7 +1302,13 @@ function applicationParser(Application $resource, int $pull_request_id = 0, ?int
|
|||||||
}
|
}
|
||||||
// Auto-inject .env file so Coolify environment variables are available inside containers
|
// Auto-inject .env file so Coolify environment variables are available inside containers
|
||||||
// This makes Applications behave consistently with manual .env file usage
|
// This makes Applications behave consistently with manual .env file usage
|
||||||
$payload['env_file'] = ['.env'];
|
$existingEnvFiles = data_get($service, 'env_file');
|
||||||
|
$envFiles = collect(is_null($existingEnvFiles) ? [] : (is_array($existingEnvFiles) ? $existingEnvFiles : [$existingEnvFiles]))
|
||||||
|
->push('.env')
|
||||||
|
->unique()
|
||||||
|
->values();
|
||||||
|
|
||||||
|
$payload['env_file'] = $envFiles;
|
||||||
if ($isPullRequest) {
|
if ($isPullRequest) {
|
||||||
$serviceName = addPreviewDeploymentSuffix($serviceName, $pullRequestId);
|
$serviceName = addPreviewDeploymentSuffix($serviceName, $pullRequestId);
|
||||||
}
|
}
|
||||||
@@ -2284,7 +2290,13 @@ function serviceParser(Service $resource): Collection
|
|||||||
}
|
}
|
||||||
// Auto-inject .env file so Coolify environment variables are available inside containers
|
// Auto-inject .env file so Coolify environment variables are available inside containers
|
||||||
// This makes Services behave consistently with Applications
|
// This makes Services behave consistently with Applications
|
||||||
$payload['env_file'] = ['.env'];
|
$existingEnvFiles = data_get($service, 'env_file');
|
||||||
|
$envFiles = collect(is_null($existingEnvFiles) ? [] : (is_array($existingEnvFiles) ? $existingEnvFiles : [$existingEnvFiles]))
|
||||||
|
->push('.env')
|
||||||
|
->unique()
|
||||||
|
->values();
|
||||||
|
|
||||||
|
$payload['env_file'] = $envFiles;
|
||||||
|
|
||||||
$parsedServices->put($serviceName, $payload);
|
$parsedServices->put($serviceName, $payload);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ services:
|
|||||||
openpanel-worker:
|
openpanel-worker:
|
||||||
image: lindesvard/openpanel-worker:latest
|
image: lindesvard/openpanel-worker:latest
|
||||||
environment:
|
environment:
|
||||||
|
- DISABLE_BULLBOARD=${DISABLE_BULLBOARD:-1}
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- NEXT_PUBLIC_SELF_HOSTED=true
|
- NEXT_PUBLIC_SELF_HOSTED=true
|
||||||
- SERVICE_URL_OPBULLBOARD
|
- SERVICE_URL_OPBULLBOARD
|
||||||
|
|||||||
@@ -3039,7 +3039,7 @@
|
|||||||
"openpanel": {
|
"openpanel": {
|
||||||
"documentation": "https://openpanel.dev/docs?utm_source=coolify.io",
|
"documentation": "https://openpanel.dev/docs?utm_source=coolify.io",
|
||||||
"slogan": "Open source alternative to Mixpanel and Plausible for product analytics",
|
"slogan": "Open source alternative to Mixpanel and Plausible for product analytics",
|
||||||
"compose": "c2VydmljZXM6CiAgb3BlbnBhbmVsLWRhc2hib2FyZDoKICAgIGltYWdlOiAnbGluZGVzdmFyZC9vcGVucGFuZWwtZGFzaGJvYXJkOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIE5PREVfRU5WPXByb2R1Y3Rpb24KICAgICAgLSBORVhUX1BVQkxJQ19TRUxGX0hPU1RFRD10cnVlCiAgICAgIC0gU0VSVklDRV9VUkxfT1BEQVNIQk9BUkRfMzAwMAogICAgICAtICdORVhUX1BVQkxJQ19BUElfVVJMPSR7U0VSVklDRV9VUkxfT1BBUEl9JwogICAgICAtICdORVhUX1BVQkxJQ19EQVNIQk9BUkRfVVJMPSR7U0VSVklDRV9VUkxfT1BEQVNIQk9BUkR9JwogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXM6Ly8ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU306JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfUBwb3N0Z3Jlczo1NDMyLyR7T1BFTlBBTkVMX1BPU1RHUkVTX0RCOi1vcGVucGFuZWwtZGJ9P3NjaGVtYT1wdWJsaWMnCiAgICAgIC0gJ1JFRElTX1VSTD1yZWRpczovL2RlZmF1bHQ6JHtTRVJWSUNFX1BBU1NXT1JEX1JFRElTfUByZWRpczo2Mzc5JwogICAgICAtICdDTElDS0hPVVNFX1VSTD1odHRwOi8vY2xpY2tob3VzZTo4MTIzL29wZW5wYW5lbCcKICAgIGRlcGVuZHNfb246CiAgICAgIG9wZW5wYW5lbC1hcGk6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgb3BlbnBhbmVsLXdvcmtlcjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBjbGlja2hvdXNlOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2N1cmwgLWYgaHR0cDovL2xvY2FsaG9zdDozMDAwL2FwaS9oZWFsdGhjaGVjayB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQogICAgICBzdGFydF9wZXJpb2Q6IDE1cwogIG9wZW5wYW5lbC1hcGk6CiAgICBpbWFnZTogJ2xpbmRlc3ZhcmQvb3BlbnBhbmVsLWFwaTpsYXRlc3QnCiAgICBjb21tYW5kOiAic2ggLWMgXCJcbiAgZWNobyAnUnVubmluZyBtaWdyYXRpb25zLi4uJ1xuICBDST10cnVlIHBucG0gLXIgcnVuIG1pZ3JhdGU6ZGVwbG95XG5cbiAgcG5wbSBzdGFydFxuXCJcbiIKICAgIGVudmlyb25tZW50OgogICAgICAtIE5PREVfRU5WPXByb2R1Y3Rpb24KICAgICAgLSBORVhUX1BVQkxJQ19TRUxGX0hPU1RFRD10cnVlCiAgICAgIC0gU0VSVklDRV9VUkxfT1BBUEkKICAgICAgLSAnTkVYVF9QVUJMSUNfQVBJX1VSTD0ke1NFUlZJQ0VfVVJMX09QQVBJfScKICAgICAgLSAnTkVYVF9QVUJMSUNfREFTSEJPQVJEX1VSTD0ke1NFUlZJQ0VfVVJMX09QREFTSEJPQVJEfScKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdEQVRBQkFTRV9VUkxfRElSRUNUPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly9kZWZhdWx0OiR7U0VSVklDRV9QQVNTV09SRF9SRURJU31AcmVkaXM6NjM3OScKICAgICAgLSAnQ0xJQ0tIT1VTRV9VUkw9aHR0cDovL2NsaWNraG91c2U6ODEyMy9vcGVucGFuZWwnCiAgICAgIC0gJ0NPT0tJRV9TRUNSRVQ9JHtTRVJWSUNFX0JBU0U2NF9DT09LSUVTRUNSRVR9JwogICAgICAtICdBTExPV19SRUdJU1RSQVRJT049JHtPUEVOUEFORUxfQUxMT1dfUkVHSVNUUkFUSU9OOi1mYWxzZX0nCiAgICAgIC0gJ0FMTE9XX0lOVklUQVRJT049JHtPUEVOUEFORUxfQUxMT1dfSU5WSVRBVElPTjotZmFsc2V9JwogICAgICAtICdFTUFJTF9TRU5ERVI9JHtPUEVOUEFORUxfRU1BSUxfU0VOREVSfScKICAgICAgLSAnUkVTRU5EX0FQSV9LRVk9JHtSRVNFTkRfQVBJX0tFWX0nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBjbGlja2hvdXNlOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHJlZGlzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2N1cmwgLWYgaHR0cDovL2xvY2FsaG9zdDozMDAwL2hlYWx0aGNoZWNrIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgb3BlbnBhbmVsLXdvcmtlcjoKICAgIGltYWdlOiAnbGluZGVzdmFyZC9vcGVucGFuZWwtd29ya2VyOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIE5PREVfRU5WPXByb2R1Y3Rpb24KICAgICAgLSBORVhUX1BVQkxJQ19TRUxGX0hPU1RFRD10cnVlCiAgICAgIC0gU0VSVklDRV9VUkxfT1BCVUxMQk9BUkQKICAgICAgLSAnTkVYVF9QVUJMSUNfQVBJX1VSTD0ke1NFUlZJQ0VfVVJMX09QQVBJfScKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdEQVRBQkFTRV9VUkxfRElSRUNUPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly9kZWZhdWx0OiR7U0VSVklDRV9QQVNTV09SRF9SRURJU31AcmVkaXM6NjM3OScKICAgICAgLSAnQ0xJQ0tIT1VTRV9VUkw9aHR0cDovL2NsaWNraG91c2U6ODEyMy9vcGVucGFuZWwnCiAgICBkZXBlbmRzX29uOgogICAgICBvcGVucGFuZWwtYXBpOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHBvc3RncmVzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHJlZGlzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIGNsaWNraG91c2U6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnY3VybCAtZiBodHRwOi8vbG9jYWxob3N0OjMwMDAvaGVhbHRoY2hlY2sgfHwgZXhpdCAxJwogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDUKICAgICAgc3RhcnRfcGVyaW9kOiA1cwogIHBvc3RncmVzOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoxNi1hbHBpbmUnCiAgICB2b2x1bWVzOgogICAgICAtICdvcGVucGFuZWxfcG9zdGdyZXNfZGF0YTovdmFLine truncated
|
"compose": "c2VydmljZXM6CiAgb3BlbnBhbmVsLWRhc2hib2FyZDoKICAgIGltYWdlOiAnbGluZGVzdmFyZC9vcGVucGFuZWwtZGFzaGJvYXJkOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIE5PREVfRU5WPXByb2R1Y3Rpb24KICAgICAgLSBORVhUX1BVQkxJQ19TRUxGX0hPU1RFRD10cnVlCiAgICAgIC0gU0VSVklDRV9VUkxfT1BEQVNIQk9BUkRfMzAwMAogICAgICAtICdORVhUX1BVQkxJQ19BUElfVVJMPSR7U0VSVklDRV9VUkxfT1BBUEl9JwogICAgICAtICdORVhUX1BVQkxJQ19EQVNIQk9BUkRfVVJMPSR7U0VSVklDRV9VUkxfT1BEQVNIQk9BUkR9JwogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXM6Ly8ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU306JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfUBwb3N0Z3Jlczo1NDMyLyR7T1BFTlBBTkVMX1BPU1RHUkVTX0RCOi1vcGVucGFuZWwtZGJ9P3NjaGVtYT1wdWJsaWMnCiAgICAgIC0gJ1JFRElTX1VSTD1yZWRpczovL2RlZmF1bHQ6JHtTRVJWSUNFX1BBU1NXT1JEX1JFRElTfUByZWRpczo2Mzc5JwogICAgICAtICdDTElDS0hPVVNFX1VSTD1odHRwOi8vY2xpY2tob3VzZTo4MTIzL29wZW5wYW5lbCcKICAgIGRlcGVuZHNfb246CiAgICAgIG9wZW5wYW5lbC1hcGk6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgb3BlbnBhbmVsLXdvcmtlcjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBjbGlja2hvdXNlOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2N1cmwgLWYgaHR0cDovL2xvY2FsaG9zdDozMDAwL2FwaS9oZWFsdGhjaGVjayB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQogICAgICBzdGFydF9wZXJpb2Q6IDE1cwogIG9wZW5wYW5lbC1hcGk6CiAgICBpbWFnZTogJ2xpbmRlc3ZhcmQvb3BlbnBhbmVsLWFwaTpsYXRlc3QnCiAgICBjb21tYW5kOiAic2ggLWMgXCJcbiAgZWNobyAnUnVubmluZyBtaWdyYXRpb25zLi4uJ1xuICBDST10cnVlIHBucG0gLXIgcnVuIG1pZ3JhdGU6ZGVwbG95XG5cbiAgcG5wbSBzdGFydFxuXCJcbiIKICAgIGVudmlyb25tZW50OgogICAgICAtIE5PREVfRU5WPXByb2R1Y3Rpb24KICAgICAgLSBORVhUX1BVQkxJQ19TRUxGX0hPU1RFRD10cnVlCiAgICAgIC0gU0VSVklDRV9VUkxfT1BBUEkKICAgICAgLSAnTkVYVF9QVUJMSUNfQVBJX1VSTD0ke1NFUlZJQ0VfVVJMX09QQVBJfScKICAgICAgLSAnTkVYVF9QVUJMSUNfREFTSEJPQVJEX1VSTD0ke1NFUlZJQ0VfVVJMX09QREFTSEJPQVJEfScKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdEQVRBQkFTRV9VUkxfRElSRUNUPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly9kZWZhdWx0OiR7U0VSVklDRV9QQVNTV09SRF9SRURJU31AcmVkaXM6NjM3OScKICAgICAgLSAnQ0xJQ0tIT1VTRV9VUkw9aHR0cDovL2NsaWNraG91c2U6ODEyMy9vcGVucGFuZWwnCiAgICAgIC0gJ0NPT0tJRV9TRUNSRVQ9JHtTRVJWSUNFX0JBU0U2NF9DT09LSUVTRUNSRVR9JwogICAgICAtICdBTExPV19SRUdJU1RSQVRJT049JHtPUEVOUEFORUxfQUxMT1dfUkVHSVNUUkFUSU9OOi1mYWxzZX0nCiAgICAgIC0gJ0FMTE9XX0lOVklUQVRJT049JHtPUEVOUEFORUxfQUxMT1dfSU5WSVRBVElPTjotZmFsc2V9JwogICAgICAtICdFTUFJTF9TRU5ERVI9JHtPUEVOUEFORUxfRU1BSUxfU0VOREVSfScKICAgICAgLSAnUkVTRU5EX0FQSV9LRVk9JHtSRVNFTkRfQVBJX0tFWX0nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBjbGlja2hvdXNlOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHJlZGlzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2N1cmwgLWYgaHR0cDovL2xvY2FsaG9zdDozMDAwL2hlYWx0aGNoZWNrIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgb3BlbnBhbmVsLXdvcmtlcjoKICAgIGltYWdlOiAnbGluZGVzdmFyZC9vcGVucGFuZWwtd29ya2VyOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtICdESVNBQkxFX0JVTExCT0FSRD0ke0RJU0FCTEVfQlVMTEJPQVJEOi0xfScKICAgICAgLSBOT0RFX0VOVj1wcm9kdWN0aW9uCiAgICAgIC0gTkVYVF9QVUJMSUNfU0VMRl9IT1NURUQ9dHJ1ZQogICAgICAtIFNFUlZJQ0VfVVJMX09QQlVMTEJPQVJECiAgICAgIC0gJ05FWFRfUFVCTElDX0FQSV9VUkw9JHtTRVJWSUNFX1VSTF9PUEFQSX0nCiAgICAgIC0gJ0RBVEFCQVNFX1VSTD1wb3N0Z3JlczovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QHBvc3RncmVzOjU0MzIvJHtPUEVOUEFORUxfUE9TVEdSRVNfREI6LW9wZW5wYW5lbC1kYn0/c2NoZW1hPXB1YmxpYycKICAgICAgLSAnREFUQUJBU0VfVVJMX0RJUkVDVD1wb3N0Z3JlczovLyR7U0VSVklDRV9VU0VSX1BPU1RHUkVTfToke1NFUlZJQ0VfUEFTU1dPUkRfUE9TVEdSRVN9QHBvc3RncmVzOjU0MzIvJHtPUEVOUEFORUxfUE9TVEdSRVNfREI6LW9wZW5wYW5lbC1kYn0/c2NoZW1hPXB1YmxpYycKICAgICAgLSAnUkVESVNfVVJMPXJlZGlzOi8vZGVmYXVsdDoke1NFUlZJQ0VfUEFTU1dPUkRfUkVESVN9QHJlZGlzOjYzNzknCiAgICAgIC0gJ0NMSUNLSE9VU0VfVVJMPWh0dHA6Ly9jbGlja2hvdXNlOjgxMjMvb3BlbnBhbmVsJwogICAgZGVwZW5kc19vbjoKICAgICAgb3BlbnBhbmVsLWFwaToKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBjbGlja2hvdXNlOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2N1cmwgLWYgaHR0cDovL2xvY2FsaG9zdDozMDAwL2hlYWx0aGNoZWNrIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgICAgIHN0YXJ0X3BlcmlvZDogNXMKICBwb3N0Z3JlczoKICAgIGltYWdlOiAncG9zdGdyZXM6MTYtYWxwaW5Line truncated
|
||||||
"tags": [
|
"tags": [
|
||||||
"analytics",
|
"analytics",
|
||||||
"insights",
|
"insights",
|
||||||
|
|||||||
@@ -3039,7 +3039,7 @@
|
|||||||
"openpanel": {
|
"openpanel": {
|
||||||
"documentation": "https://openpanel.dev/docs?utm_source=coolify.io",
|
"documentation": "https://openpanel.dev/docs?utm_source=coolify.io",
|
||||||
"slogan": "Open source alternative to Mixpanel and Plausible for product analytics",
|
"slogan": "Open source alternative to Mixpanel and Plausible for product analytics",
|
||||||
"compose": "c2VydmljZXM6CiAgb3BlbnBhbmVsLWRhc2hib2FyZDoKICAgIGltYWdlOiAnbGluZGVzdmFyZC9vcGVucGFuZWwtZGFzaGJvYXJkOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIE5PREVfRU5WPXByb2R1Y3Rpb24KICAgICAgLSBORVhUX1BVQkxJQ19TRUxGX0hPU1RFRD10cnVlCiAgICAgIC0gU0VSVklDRV9GUUROX09QREFTSEJPQVJEXzMwMDAKICAgICAgLSAnTkVYVF9QVUJMSUNfQVBJX1VSTD0ke1NFUlZJQ0VfRlFETl9PUEFQSX0nCiAgICAgIC0gJ05FWFRfUFVCTElDX0RBU0hCT0FSRF9VUkw9JHtTRVJWSUNFX0ZRRE5fT1BEQVNIQk9BUkR9JwogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXM6Ly8ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU306JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfUBwb3N0Z3Jlczo1NDMyLyR7T1BFTlBBTkVMX1BPU1RHUkVTX0RCOi1vcGVucGFuZWwtZGJ9P3NjaGVtYT1wdWJsaWMnCiAgICAgIC0gJ1JFRElTX1VSTD1yZWRpczovL2RlZmF1bHQ6JHtTRVJWSUNFX1BBU1NXT1JEX1JFRElTfUByZWRpczo2Mzc5JwogICAgICAtICdDTElDS0hPVVNFX1VSTD1odHRwOi8vY2xpY2tob3VzZTo4MTIzL29wZW5wYW5lbCcKICAgIGRlcGVuZHNfb246CiAgICAgIG9wZW5wYW5lbC1hcGk6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgb3BlbnBhbmVsLXdvcmtlcjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBjbGlja2hvdXNlOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2N1cmwgLWYgaHR0cDovL2xvY2FsaG9zdDozMDAwL2FwaS9oZWFsdGhjaGVjayB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQogICAgICBzdGFydF9wZXJpb2Q6IDE1cwogIG9wZW5wYW5lbC1hcGk6CiAgICBpbWFnZTogJ2xpbmRlc3ZhcmQvb3BlbnBhbmVsLWFwaTpsYXRlc3QnCiAgICBjb21tYW5kOiAic2ggLWMgXCJcbiAgZWNobyAnUnVubmluZyBtaWdyYXRpb25zLi4uJ1xuICBDST10cnVlIHBucG0gLXIgcnVuIG1pZ3JhdGU6ZGVwbG95XG5cbiAgcG5wbSBzdGFydFxuXCJcbiIKICAgIGVudmlyb25tZW50OgogICAgICAtIE5PREVfRU5WPXByb2R1Y3Rpb24KICAgICAgLSBORVhUX1BVQkxJQ19TRUxGX0hPU1RFRD10cnVlCiAgICAgIC0gU0VSVklDRV9GUUROX09QQVBJCiAgICAgIC0gJ05FWFRfUFVCTElDX0FQSV9VUkw9JHtTRVJWSUNFX0ZRRE5fT1BBUEl9JwogICAgICAtICdORVhUX1BVQkxJQ19EQVNIQk9BUkRfVVJMPSR7U0VSVklDRV9GUUROX09QREFTSEJPQVJEfScKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdEQVRBQkFTRV9VUkxfRElSRUNUPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly9kZWZhdWx0OiR7U0VSVklDRV9QQVNTV09SRF9SRURJU31AcmVkaXM6NjM3OScKICAgICAgLSAnQ0xJQ0tIT1VTRV9VUkw9aHR0cDovL2NsaWNraG91c2U6ODEyMy9vcGVucGFuZWwnCiAgICAgIC0gJ0NPT0tJRV9TRUNSRVQ9JHtTRVJWSUNFX0JBU0U2NF9DT09LSUVTRUNSRVR9JwogICAgICAtICdBTExPV19SRUdJU1RSQVRJT049JHtPUEVOUEFORUxfQUxMT1dfUkVHSVNUUkFUSU9OOi1mYWxzZX0nCiAgICAgIC0gJ0FMTE9XX0lOVklUQVRJT049JHtPUEVOUEFORUxfQUxMT1dfSU5WSVRBVElPTjotZmFsc2V9JwogICAgICAtICdFTUFJTF9TRU5ERVI9JHtPUEVOUEFORUxfRU1BSUxfU0VOREVSfScKICAgICAgLSAnUkVTRU5EX0FQSV9LRVk9JHtSRVNFTkRfQVBJX0tFWX0nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBjbGlja2hvdXNlOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHJlZGlzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2N1cmwgLWYgaHR0cDovL2xvY2FsaG9zdDozMDAwL2hlYWx0aGNoZWNrIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgb3BlbnBhbmVsLXdvcmtlcjoKICAgIGltYWdlOiAnbGluZGVzdmFyZC9vcGVucGFuZWwtd29ya2VyOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIE5PREVfRU5WPXByb2R1Y3Rpb24KICAgICAgLSBORVhUX1BVQkxJQ19TRUxGX0hPU1RFRD10cnVlCiAgICAgIC0gU0VSVklDRV9GUUROX09QQlVMTEJPQVJECiAgICAgIC0gJ05FWFRfUFVCTElDX0FQSV9VUkw9JHtTRVJWSUNFX0ZRRE5fT1BBUEl9JwogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXM6Ly8ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU306JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfUBwb3N0Z3Jlczo1NDMyLyR7T1BFTlBBTkVMX1BPU1RHUkVTX0RCOi1vcGVucGFuZWwtZGJ9P3NjaGVtYT1wdWJsaWMnCiAgICAgIC0gJ0RBVEFCQVNFX1VSTF9ESVJFQ1Q9cG9zdGdyZXM6Ly8ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU306JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfUBwb3N0Z3Jlczo1NDMyLyR7T1BFTlBBTkVMX1BPU1RHUkVTX0RCOi1vcGVucGFuZWwtZGJ9P3NjaGVtYT1wdWJsaWMnCiAgICAgIC0gJ1JFRElTX1VSTD1yZWRpczovL2RlZmF1bHQ6JHtTRVJWSUNFX1BBU1NXT1JEX1JFRElTfUByZWRpczo2Mzc5JwogICAgICAtICdDTElDS0hPVVNFX1VSTD1odHRwOi8vY2xpY2tob3VzZTo4MTIzL29wZW5wYW5lbCcKICAgIGRlcGVuZHNfb246CiAgICAgIG9wZW5wYW5lbC1hcGk6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgcG9zdGdyZXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgcmVkaXM6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgY2xpY2tob3VzZToKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgaGVhbHRoY2hlY2s6CiAgICAgIHRlc3Q6CiAgICAgICAgLSBDTUQtU0hFTEwKICAgICAgICAtICdjdXJsIC1mIGh0dHA6Ly9sb2NhbGhvc3Q6MzAwMC9oZWFsdGhjaGVjayB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQogICAgICBzdGFydF9wZXJpb2Q6IDVzCiAgcG9zdGdyZXM6CiAgICBpbWFnZTogJ3Bvc3RncmVzOjE2LWFscGluZScKICAgIHZvbHVtZXM6CiAgICAgIC0gJ29wZW5wYW5lbF9wb3N0Z3Jlc19Line truncated
|
"compose": "c2VydmljZXM6CiAgb3BlbnBhbmVsLWRhc2hib2FyZDoKICAgIGltYWdlOiAnbGluZGVzdmFyZC9vcGVucGFuZWwtZGFzaGJvYXJkOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtIE5PREVfRU5WPXByb2R1Y3Rpb24KICAgICAgLSBORVhUX1BVQkxJQ19TRUxGX0hPU1RFRD10cnVlCiAgICAgIC0gU0VSVklDRV9GUUROX09QREFTSEJPQVJEXzMwMDAKICAgICAgLSAnTkVYVF9QVUJMSUNfQVBJX1VSTD0ke1NFUlZJQ0VfRlFETl9PUEFQSX0nCiAgICAgIC0gJ05FWFRfUFVCTElDX0RBU0hCT0FSRF9VUkw9JHtTRVJWSUNFX0ZRRE5fT1BEQVNIQk9BUkR9JwogICAgICAtICdEQVRBQkFTRV9VUkw9cG9zdGdyZXM6Ly8ke1NFUlZJQ0VfVVNFUl9QT1NUR1JFU306JHtTRVJWSUNFX1BBU1NXT1JEX1BPU1RHUkVTfUBwb3N0Z3Jlczo1NDMyLyR7T1BFTlBBTkVMX1BPU1RHUkVTX0RCOi1vcGVucGFuZWwtZGJ9P3NjaGVtYT1wdWJsaWMnCiAgICAgIC0gJ1JFRElTX1VSTD1yZWRpczovL2RlZmF1bHQ6JHtTRVJWSUNFX1BBU1NXT1JEX1JFRElTfUByZWRpczo2Mzc5JwogICAgICAtICdDTElDS0hPVVNFX1VSTD1odHRwOi8vY2xpY2tob3VzZTo4MTIzL29wZW5wYW5lbCcKICAgIGRlcGVuZHNfb246CiAgICAgIG9wZW5wYW5lbC1hcGk6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgICAgb3BlbnBhbmVsLXdvcmtlcjoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICByZWRpczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBjbGlja2hvdXNlOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2N1cmwgLWYgaHR0cDovL2xvY2FsaG9zdDozMDAwL2FwaS9oZWFsdGhjaGVjayB8fCBleGl0IDEnCiAgICAgIGludGVydmFsOiAxMHMKICAgICAgdGltZW91dDogNXMKICAgICAgcmV0cmllczogNQogICAgICBzdGFydF9wZXJpb2Q6IDE1cwogIG9wZW5wYW5lbC1hcGk6CiAgICBpbWFnZTogJ2xpbmRlc3ZhcmQvb3BlbnBhbmVsLWFwaTpsYXRlc3QnCiAgICBjb21tYW5kOiAic2ggLWMgXCJcbiAgZWNobyAnUnVubmluZyBtaWdyYXRpb25zLi4uJ1xuICBDST10cnVlIHBucG0gLXIgcnVuIG1pZ3JhdGU6ZGVwbG95XG5cbiAgcG5wbSBzdGFydFxuXCJcbiIKICAgIGVudmlyb25tZW50OgogICAgICAtIE5PREVfRU5WPXByb2R1Y3Rpb24KICAgICAgLSBORVhUX1BVQkxJQ19TRUxGX0hPU1RFRD10cnVlCiAgICAgIC0gU0VSVklDRV9GUUROX09QQVBJCiAgICAgIC0gJ05FWFRfUFVCTElDX0FQSV9VUkw9JHtTRVJWSUNFX0ZRRE5fT1BBUEl9JwogICAgICAtICdORVhUX1BVQkxJQ19EQVNIQk9BUkRfVVJMPSR7U0VSVklDRV9GUUROX09QREFTSEJPQVJEfScKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdEQVRBQkFTRV9VUkxfRElSRUNUPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly9kZWZhdWx0OiR7U0VSVklDRV9QQVNTV09SRF9SRURJU31AcmVkaXM6NjM3OScKICAgICAgLSAnQ0xJQ0tIT1VTRV9VUkw9aHR0cDovL2NsaWNraG91c2U6ODEyMy9vcGVucGFuZWwnCiAgICAgIC0gJ0NPT0tJRV9TRUNSRVQ9JHtTRVJWSUNFX0JBU0U2NF9DT09LSUVTRUNSRVR9JwogICAgICAtICdBTExPV19SRUdJU1RSQVRJT049JHtPUEVOUEFORUxfQUxMT1dfUkVHSVNUUkFUSU9OOi1mYWxzZX0nCiAgICAgIC0gJ0FMTE9XX0lOVklUQVRJT049JHtPUEVOUEFORUxfQUxMT1dfSU5WSVRBVElPTjotZmFsc2V9JwogICAgICAtICdFTUFJTF9TRU5ERVI9JHtPUEVOUEFORUxfRU1BSUxfU0VOREVSfScKICAgICAgLSAnUkVTRU5EX0FQSV9LRVk9JHtSRVNFTkRfQVBJX0tFWX0nCiAgICBkZXBlbmRzX29uOgogICAgICBwb3N0Z3JlczoKICAgICAgICBjb25kaXRpb246IHNlcnZpY2VfaGVhbHRoeQogICAgICBjbGlja2hvdXNlOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHJlZGlzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICBoZWFsdGhjaGVjazoKICAgICAgdGVzdDoKICAgICAgICAtIENNRC1TSEVMTAogICAgICAgIC0gJ2N1cmwgLWYgaHR0cDovL2xvY2FsaG9zdDozMDAwL2hlYWx0aGNoZWNrIHx8IGV4aXQgMScKICAgICAgaW50ZXJ2YWw6IDEwcwogICAgICB0aW1lb3V0OiA1cwogICAgICByZXRyaWVzOiA1CiAgb3BlbnBhbmVsLXdvcmtlcjoKICAgIGltYWdlOiAnbGluZGVzdmFyZC9vcGVucGFuZWwtd29ya2VyOmxhdGVzdCcKICAgIGVudmlyb25tZW50OgogICAgICAtICdESVNBQkxFX0JVTExCT0FSRD0ke0RJU0FCTEVfQlVMTEJPQVJEOi0xfScKICAgICAgLSBOT0RFX0VOVj1wcm9kdWN0aW9uCiAgICAgIC0gTkVYVF9QVUJMSUNfU0VMRl9IT1NURUQ9dHJ1ZQogICAgICAtIFNFUlZJQ0VfRlFETl9PUEJVTExCT0FSRAogICAgICAtICdORVhUX1BVQkxJQ19BUElfVVJMPSR7U0VSVklDRV9GUUROX09QQVBJfScKICAgICAgLSAnREFUQUJBU0VfVVJMPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdEQVRBQkFTRV9VUkxfRElSRUNUPXBvc3RncmVzOi8vJHtTRVJWSUNFX1VTRVJfUE9TVEdSRVN9OiR7U0VSVklDRV9QQVNTV09SRF9QT1NUR1JFU31AcG9zdGdyZXM6NTQzMi8ke09QRU5QQU5FTF9QT1NUR1JFU19EQjotb3BlbnBhbmVsLWRifT9zY2hlbWE9cHVibGljJwogICAgICAtICdSRURJU19VUkw9cmVkaXM6Ly9kZWZhdWx0OiR7U0VSVklDRV9QQVNTV09SRF9SRURJU31AcmVkaXM6NjM3OScKICAgICAgLSAnQ0xJQ0tIT1VTRV9VUkw9aHR0cDovL2NsaWNraG91c2U6ODEyMy9vcGVucGFuZWwnCiAgICBkZXBlbmRzX29uOgogICAgICBvcGVucGFuZWwtYXBpOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHBvc3RncmVzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIHJlZGlzOgogICAgICAgIGNvbmRpdGlvbjogc2VydmljZV9oZWFsdGh5CiAgICAgIGNsaWNraG91c2U6CiAgICAgICAgY29uZGl0aW9uOiBzZXJ2aWNlX2hlYWx0aHkKICAgIGhlYWx0aGNoZWNrOgogICAgICB0ZXN0OgogICAgICAgIC0gQ01ELVNIRUxMCiAgICAgICAgLSAnY3VybCAtZiBodHRwOi8vbG9jYWxob3N0OjMwMDAvaGVhbHRoY2hlY2sgfHwgZXhpdCAxJwogICAgICBpbnRlcnZhbDogMTBzCiAgICAgIHRpbWVvdXQ6IDVzCiAgICAgIHJldHJpZXM6IDUKICAgICAgc3RhcnRfcGVyaW9kOiA1cwogIHBvc3RncmVzOgogICAgaW1hZ2U6ICdwb3N0Z3JlczoLine truncated
|
||||||
"tags": [
|
"tags": [
|
||||||
"analytics",
|
"analytics",
|
||||||
"insights",
|
"insights",
|
||||||
|
|||||||
Reference in new issue
Block a user