From 2475031f8851e3570683615403bf3a52e68fefd2 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Sun, 27 Mar 2022 22:03:21 +0200 Subject: [PATCH] feat: Ghost service --- .../20220327180323_ghost/migration.sql | 19 +++ prisma/schema.prisma | 17 +++ src/lib/components/svg/services/Ghost.svelte | 9 ++ src/lib/database/common.ts | 19 +++ src/lib/database/services.ts | 39 +++++ src/lib/letsencrypt/index.ts | 85 +++++------ .../destinations/[id]/_LocalDocker.svelte | 2 +- .../destinations/[id]/_RemoteDocker.svelte | 2 +- .../services/[id]/_Services/_Ghost.svelte | 90 ++++++++++++ .../services/[id]/_Services/_Services.svelte | 3 + src/routes/services/[id]/__layout.svelte | 1 + .../services/[id]/configuration/type.svelte | 3 + src/routes/services/[id]/ghost/index.json.ts | 23 +++ src/routes/services/[id]/ghost/start.json.ts | 134 ++++++++++++++++++ src/routes/services/[id]/ghost/stop.json.ts | 39 +++++ src/routes/services/[id]/index.json.ts | 9 +- src/routes/services/[id]/index.svelte | 5 + .../services/[id]/languagetool/start.json.ts | 16 +-- src/routes/services/[id]/minio/start.json.ts | 10 +- src/routes/services/[id]/n8n/start.json.ts | 5 + src/routes/services/[id]/nocodb/start.json.ts | 5 + .../[id]/plausibleanalytics/start.json.ts | 16 +-- .../services/[id]/uptimekuma/start.json.ts | 5 + .../services/[id]/vaultwarden/start.json.ts | 14 +- .../services/[id]/vscodeserver/start.json.ts | 23 +-- .../services/[id]/wordpress/start.json.ts | 27 ++-- static/ghost.png | Bin 0 -> 40603 bytes 27 files changed, 509 insertions(+), 111 deletions(-) create mode 100644 prisma/migrations/20220327180323_ghost/migration.sql create mode 100644 src/lib/components/svg/services/Ghost.svelte create mode 100644 src/routes/services/[id]/_Services/_Ghost.svelte create mode 100644 src/routes/services/[id]/ghost/index.json.ts create mode 100644 src/routes/services/[id]/ghost/start.json.ts create mode 100644 src/routes/services/[id]/ghost/stop.json.ts create mode 100644 static/ghost.png diff --git a/prisma/migrations/20220327180323_ghost/migration.sql b/prisma/migrations/20220327180323_ghost/migration.sql new file mode 100644 index 000000000..3c1cec36f --- /dev/null +++ b/prisma/migrations/20220327180323_ghost/migration.sql @@ -0,0 +1,19 @@ +-- CreateTable +CREATE TABLE "Ghost" ( + "id" TEXT NOT NULL PRIMARY KEY, + "defaultEmail" TEXT NOT NULL, + "defaultPassword" TEXT NOT NULL, + "mariadbUser" TEXT NOT NULL, + "mariadbPassword" TEXT NOT NULL, + "mariadbRootUser" TEXT NOT NULL, + "mariadbRootUserPassword" TEXT NOT NULL, + "mariadbDatabase" TEXT, + "mariadbPublicPort" INTEGER, + "serviceId" TEXT NOT NULL, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "Ghost_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "Service" ("id") ON DELETE RESTRICT ON UPDATE CASCADE +); + +-- CreateIndex +CREATE UNIQUE INDEX "Ghost_serviceId_key" ON "Ghost"("serviceId"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 95310d2aa..a849ae36f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -278,6 +278,7 @@ model Service { minio Minio? vscodeserver Vscodeserver? wordpress Wordpress? + ghost Ghost? serviceSecret ServiceSecret[] } @@ -332,3 +333,19 @@ model Wordpress { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } + +model Ghost { + id String @id @default(cuid()) + defaultEmail String + defaultPassword String + mariadbUser String + mariadbPassword String + mariadbRootUser String + mariadbRootUserPassword String + mariadbDatabase String? + mariadbPublicPort Int? + serviceId String @unique + service Service @relation(fields: [serviceId], references: [id]) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} diff --git a/src/lib/components/svg/services/Ghost.svelte b/src/lib/components/svg/services/Ghost.svelte new file mode 100644 index 000000000..2e77177da --- /dev/null +++ b/src/lib/components/svg/services/Ghost.svelte @@ -0,0 +1,9 @@ + + +ghost logo diff --git a/src/lib/database/common.ts b/src/lib/database/common.ts index 19922cece..e89105f05 100644 --- a/src/lib/database/common.ts +++ b/src/lib/database/common.ts @@ -107,6 +107,7 @@ export const supportedServiceTypesAndVersions = [ name: 'plausibleanalytics', fancyName: 'Plausible Analytics', baseImage: 'plausible/analytics', + images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'], versions: ['latest'], ports: { main: 8000 @@ -143,6 +144,7 @@ export const supportedServiceTypesAndVersions = [ name: 'wordpress', fancyName: 'Wordpress', baseImage: 'wordpress', + images: ['bitnami/mysql:5.7'], versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'], ports: { main: 80 @@ -183,6 +185,16 @@ export const supportedServiceTypesAndVersions = [ ports: { main: 3001 } + }, + { + name: 'ghost', + fancyName: 'Ghost', + baseImage: 'bitnami/ghost', + images: ['bitnami/mariadb'], + versions: ['latest'], + ports: { + main: 2368 + } } ]; @@ -207,6 +219,13 @@ export function getServiceImage(type) { } return ''; } +export function getServiceImages(type) { + const found = supportedServiceTypesAndVersions.find((t) => t.name === type); + if (found) { + return found.images; + } + return []; +} export function generateDatabaseConfiguration(database) { const { id, diff --git a/src/lib/database/services.ts b/src/lib/database/services.ts index daec2a5da..a5c2ee9ea 100644 --- a/src/lib/database/services.ts +++ b/src/lib/database/services.ts @@ -1,3 +1,4 @@ +import { asyncExecShell, getEngine } from '$lib/common'; import { decrypt, encrypt } from '$lib/crypto'; import cuid from 'cuid'; import { generatePassword } from '.'; @@ -20,6 +21,7 @@ export async function getService({ id, teamId }) { minio: true, vscodeserver: true, wordpress: true, + ghost: true, serviceSecret: true } }); @@ -43,12 +45,18 @@ export async function getService({ id, teamId }) { if (body.wordpress?.mysqlRootUserPassword) body.wordpress.mysqlRootUserPassword = decrypt(body.wordpress.mysqlRootUserPassword); + if (body.ghost?.mariadbPassword) body.ghost.mariadbPassword = decrypt(body.ghost.mariadbPassword); + if (body.ghost?.mariadbRootUserPassword) + body.ghost.mariadbRootUserPassword = decrypt(body.ghost.mariadbRootUserPassword); + if (body.ghost?.defaultPassword) body.ghost.defaultPassword = decrypt(body.ghost.defaultPassword); + if (body?.serviceSecret.length > 0) { body.serviceSecret = body.serviceSecret.map((s) => { s.value = decrypt(s.value); return s; }); } + return { ...body }; } @@ -133,6 +141,30 @@ export async function configureServiceType({ id, type }) { type } }); + } else if (type === 'ghost') { + const defaultEmail = `${cuid()}@coolify.io`; + const defaultPassword = encrypt(generatePassword()); + const mariadbUser = cuid(); + const mariadbPassword = encrypt(generatePassword()); + const mariadbRootUser = cuid(); + const mariadbRootUserPassword = encrypt(generatePassword()); + + await prisma.service.update({ + where: { id }, + data: { + type, + ghost: { + create: { + defaultEmail, + defaultPassword, + mariadbUser, + mariadbPassword, + mariadbRootUser, + mariadbRootUserPassword + } + } + } + }); } } export async function setServiceVersion({ id, version }) { @@ -174,8 +206,15 @@ export async function updateWordpress({ id, fqdn, name, mysqlDatabase, extraConf export async function updateMinioService({ id, publicPort }) { return await prisma.minio.update({ where: { serviceId: id }, data: { publicPort } }); } +export async function updateGhostService({ id, fqdn, name, mariadbDatabase }) { + return await prisma.service.update({ + where: { id }, + data: { fqdn, name, ghost: { update: { mariadbDatabase } } } + }); +} export async function removeService({ id }) { + await prisma.ghost.deleteMany({ where: { serviceId: id } }); await prisma.plausibleAnalytics.deleteMany({ where: { serviceId: id } }); await prisma.minio.deleteMany({ where: { serviceId: id } }); await prisma.vscodeserver.deleteMany({ where: { serviceId: id } }); diff --git a/src/lib/letsencrypt/index.ts b/src/lib/letsencrypt/index.ts index e85f539de..eb74aa252 100644 --- a/src/lib/letsencrypt/index.ts +++ b/src/lib/letsencrypt/index.ts @@ -104,32 +104,34 @@ export async function generateSSLCerts() { }); for (const application of applications) { try { - const { - fqdn, - id, - destinationDocker: { engine, network }, - settings: { previews } - } = application; - const isRunning = await checkContainer(engine, id); - const domain = getDomain(fqdn); - const isHttps = fqdn.startsWith('https://'); - if (isRunning) { - if (isHttps) ssls.push({ domain, id, isCoolify: false }); - } - if (previews) { - const host = getEngine(engine); - const { stdout } = await asyncExecShell( - `DOCKER_HOST=${host} docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"` - ); - const containers = stdout - .trim() - .split('\n') - .filter((a) => a) - .map((c) => c.replace(/"/g, '')); - if (containers.length > 0) { - for (const container of containers) { - let previewDomain = `${container.split('-')[1]}.${domain}`; - if (isHttps) ssls.push({ domain: previewDomain, id, isCoolify: false }); + if (application.fqdn && application.destinationDockerId) { + const { + fqdn, + id, + destinationDocker: { engine, network }, + settings: { previews } + } = application; + const isRunning = await checkContainer(engine, id); + const domain = getDomain(fqdn); + const isHttps = fqdn.startsWith('https://'); + if (isRunning) { + if (isHttps) ssls.push({ domain, id, isCoolify: false }); + } + if (previews) { + const host = getEngine(engine); + const { stdout } = await asyncExecShell( + `DOCKER_HOST=${host} docker container ls --filter="status=running" --filter="network=${network}" --filter="name=${id}-" --format="{{json .Names}}"` + ); + const containers = stdout + .trim() + .split('\n') + .filter((a) => a) + .map((c) => c.replace(/"/g, '')); + if (containers.length > 0) { + for (const container of containers) { + let previewDomain = `${container.split('-')[1]}.${domain}`; + if (isHttps) ssls.push({ domain: previewDomain, id, isCoolify: false }); + } } } } @@ -143,26 +145,29 @@ export async function generateSSLCerts() { minio: true, plausibleAnalytics: true, vscodeserver: true, - wordpress: true + wordpress: true, + ghost: true }, orderBy: { createdAt: 'desc' } }); for (const service of services) { try { - const { - fqdn, - id, - type, - destinationDocker: { engine } - } = service; - const found = db.supportedServiceTypesAndVersions.find((a) => a.name === type); - if (found) { - const domain = getDomain(fqdn); - const isHttps = fqdn.startsWith('https://'); - const isRunning = await checkContainer(engine, id); - if (isRunning) { - if (isHttps) ssls.push({ domain, id, isCoolify: false }); + if (service.fqdn && service.destinationDockerId) { + const { + fqdn, + id, + type, + destinationDocker: { engine } + } = service; + const found = db.supportedServiceTypesAndVersions.find((a) => a.name === type); + if (found) { + const domain = getDomain(fqdn); + const isHttps = fqdn.startsWith('https://'); + const isRunning = await checkContainer(engine, id); + if (isRunning) { + if (isHttps) ssls.push({ domain, id, isCoolify: false }); + } } } } catch (error) { diff --git a/src/routes/destinations/[id]/_LocalDocker.svelte b/src/routes/destinations/[id]/_LocalDocker.svelte index bf4d8447a..329d23c2f 100644 --- a/src/routes/destinations/[id]/_LocalDocker.svelte +++ b/src/routes/destinations/[id]/_LocalDocker.svelte @@ -103,7 +103,7 @@ } async function forceRestartProxy() { const sure = confirm( - 'Are you sure you want to restart the proxy? Everyting will be reconfigured in ~10 sec.' + 'Are you sure you want to restart the proxy? Everything will be reconfigured in ~10 secs.' ); if (sure) { try { diff --git a/src/routes/destinations/[id]/_RemoteDocker.svelte b/src/routes/destinations/[id]/_RemoteDocker.svelte index 9c13cf465..4de1b82ce 100644 --- a/src/routes/destinations/[id]/_RemoteDocker.svelte +++ b/src/routes/destinations/[id]/_RemoteDocker.svelte @@ -106,7 +106,7 @@ } async function forceRestartProxy() { const sure = confirm( - 'Are you sure you want to restart the proxy? Everyting will be reconfigured in ~10 sec.' + 'Are you sure you want to restart the proxy? Everything will be reconfigured in ~10 secs.' ); if (sure) { try { diff --git a/src/routes/services/[id]/_Services/_Ghost.svelte b/src/routes/services/[id]/_Services/_Ghost.svelte new file mode 100644 index 000000000..8a6154ac9 --- /dev/null +++ b/src/routes/services/[id]/_Services/_Ghost.svelte @@ -0,0 +1,90 @@ + + +
+
Ghost
+
+
+ + +
+
+ + +
+
+
MariaDB
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
diff --git a/src/routes/services/[id]/_Services/_Services.svelte b/src/routes/services/[id]/_Services/_Services.svelte index 896953cc4..6a54d9b98 100644 --- a/src/routes/services/[id]/_Services/_Services.svelte +++ b/src/routes/services/[id]/_Services/_Services.svelte @@ -10,6 +10,7 @@ import Setting from '$lib/components/Setting.svelte'; import { errorNotification } from '$lib/form'; import { toast } from '@zerodevx/svelte-toast'; + import Ghost from './_Ghost.svelte'; import MinIo from './_MinIO.svelte'; import PlausibleAnalytics from './_PlausibleAnalytics.svelte'; import VsCodeServer from './_VSCodeServer.svelte'; @@ -142,6 +143,8 @@ {:else if service.type === 'wordpress'} + {:else if service.type === 'ghost'} + {/if} diff --git a/src/routes/services/[id]/__layout.svelte b/src/routes/services/[id]/__layout.svelte index fffce0007..362f89786 100644 --- a/src/routes/services/[id]/__layout.svelte +++ b/src/routes/services/[id]/__layout.svelte @@ -35,6 +35,7 @@ } if (service.plausibleAnalytics?.email && service.plausibleAnalytics.username) readOnly = true; if (service.wordpress?.mysqlDatabase) readOnly = true; + if (service.ghost?.mariadbDatabase && service.ghost.mariadbDatabase) readOnly = true; return { props: { diff --git a/src/routes/services/[id]/configuration/type.svelte b/src/routes/services/[id]/configuration/type.svelte index 6a56354be..bf8575065 100644 --- a/src/routes/services/[id]/configuration/type.svelte +++ b/src/routes/services/[id]/configuration/type.svelte @@ -40,6 +40,7 @@ import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte'; import N8n from '$lib/components/svg/services/N8n.svelte'; import UptimeKuma from '$lib/components/svg/services/UptimeKuma.svelte'; + import Ghost from '$lib/components/svg/services/Ghost.svelte'; const { id } = $page.params; const from = $page.url.searchParams.get('from'); @@ -83,6 +84,8 @@ {:else if type.name === 'uptimekuma'} + {:else if type.name === 'ghost'} + {/if}{type.fancyName} diff --git a/src/routes/services/[id]/ghost/index.json.ts b/src/routes/services/[id]/ghost/index.json.ts new file mode 100644 index 000000000..81ca8ade1 --- /dev/null +++ b/src/routes/services/[id]/ghost/index.json.ts @@ -0,0 +1,23 @@ +import { getUserDetails } from '$lib/common'; +import * as db from '$lib/database'; +import { ErrorHandler } from '$lib/database'; +import type { RequestHandler } from '@sveltejs/kit'; + +export const post: RequestHandler = async (event) => { + const { status, body } = await getUserDetails(event); + if (status === 401) return { status, body }; + const { id } = event.params; + + let { + name, + fqdn, + ghost: { mariadbDatabase } + } = await event.request.json(); + if (fqdn) fqdn = fqdn.toLowerCase(); + try { + await db.updateGhostService({ id, fqdn, name, mariadbDatabase }); + return { status: 201 }; + } catch (error) { + return ErrorHandler(error); + } +}; diff --git a/src/routes/services/[id]/ghost/start.json.ts b/src/routes/services/[id]/ghost/start.json.ts new file mode 100644 index 000000000..f1f2250bd --- /dev/null +++ b/src/routes/services/[id]/ghost/start.json.ts @@ -0,0 +1,134 @@ +import { + asyncExecShell, + createDirectories, + getDomain, + getEngine, + getUserDetails +} from '$lib/common'; +import * as db from '$lib/database'; +import { promises as fs } from 'fs'; +import yaml from 'js-yaml'; +import type { RequestHandler } from '@sveltejs/kit'; +import { ErrorHandler, getServiceImage } from '$lib/database'; +import { makeLabelForServices } from '$lib/buildPacks/common'; + +export const post: RequestHandler = async (event) => { + const { teamId, status, body } = await getUserDetails(event); + if (status === 401) return { status, body }; + + const { id } = event.params; + + try { + const service = await db.getService({ id, teamId }); + const { + type, + version, + destinationDockerId, + destinationDocker, + serviceSecret, + fqdn, + ghost: { + defaultEmail, + defaultPassword, + mariadbRootUser, + mariadbRootUserPassword, + mariadbDatabase, + mariadbPassword, + mariadbUser + } + } = service; + const network = destinationDockerId && destinationDocker.network; + const host = getEngine(destinationDocker.engine); + + const { workdir } = await createDirectories({ repository: type, buildId: id }); + const image = getServiceImage(type); + const domain = getDomain(fqdn); + const config = { + ghost: { + image: `${image}:${version}`, + volume: `${id}-ghost:/bitnami/ghost`, + environmentVariables: { + GHOST_HOST: domain, + GHOST_EMAIL: defaultEmail, + GHOST_PASSWORD: defaultPassword, + GHOST_DATABASE_HOST: `${id}-mariadb`, + GHOST_DATABASE_USER: mariadbUser, + GHOST_DATABASE_PASSWORD: mariadbPassword, + GHOST_DATABASE_NAME: mariadbDatabase, + GHOST_DATABASE_PORT_NUMBER: 3306 + } + }, + mariadb: { + image: `bitnami/mariadb:latest`, + volume: `${id}-mariadb:/bitnami/mariadb`, + environmentVariables: { + MARIADB_USER: mariadbUser, + MARIADB_PASSWORD: mariadbPassword, + MARIADB_DATABASE: mariadbDatabase, + MARIADB_ROOT_USER: mariadbRootUser, + MARIADB_ROOT_PASSWORD: mariadbRootUserPassword + } + } + }; + if (serviceSecret.length > 0) { + serviceSecret.forEach((secret) => { + config.ghost.environmentVariables[secret.name] = secret.value; + }); + } + const composeFile = { + version: '3.8', + services: { + [id]: { + container_name: id, + image: config.ghost.image, + networks: [network], + volumes: [config.ghost.volume], + environment: config.ghost.environmentVariables, + restart: 'always', + labels: makeLabelForServices('ghost'), + depends_on: [`${id}-mariadb`] + }, + [`${id}-mariadb`]: { + container_name: `${id}-mariadb`, + image: config.mariadb.image, + networks: [network], + volumes: [config.mariadb.volume], + environment: config.mariadb.environmentVariables, + restart: 'always' + } + }, + networks: { + [network]: { + external: true + } + }, + volumes: { + [config.ghost.volume.split(':')[0]]: { + name: config.ghost.volume.split(':')[0] + }, + [config.mariadb.volume.split(':')[0]]: { + name: config.mariadb.volume.split(':')[0] + } + } + }; + console.log(JSON.stringify(composeFile.volumes)); + const composeFileDestination = `${workdir}/docker-compose.yaml`; + await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); + + try { + if (version === 'latest') { + await asyncExecShell( + `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull` + ); + } + await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); + return { + status: 200 + }; + } catch (error) { + return ErrorHandler(error); + } + } catch (error) { + return ErrorHandler(error); + } +}; diff --git a/src/routes/services/[id]/ghost/stop.json.ts b/src/routes/services/[id]/ghost/stop.json.ts new file mode 100644 index 000000000..478f5b946 --- /dev/null +++ b/src/routes/services/[id]/ghost/stop.json.ts @@ -0,0 +1,39 @@ +import { getUserDetails, removeDestinationDocker } from '$lib/common'; +import * as db from '$lib/database'; +import { ErrorHandler } from '$lib/database'; +import { checkContainer } from '$lib/haproxy'; +import type { RequestHandler } from '@sveltejs/kit'; + +export const post: RequestHandler = async (event) => { + const { teamId, status, body } = await getUserDetails(event); + if (status === 401) return { status, body }; + + const { id } = event.params; + + try { + const service = await db.getService({ id, teamId }); + const { destinationDockerId, destinationDocker, fqdn } = service; + if (destinationDockerId) { + const engine = destinationDocker.engine; + + try { + let found = await checkContainer(engine, id); + if (found) { + await removeDestinationDocker({ id, engine }); + } + found = await checkContainer(engine, `${id}-mariadb`); + if (found) { + await removeDestinationDocker({ id: `${id}-mariadb`, engine }); + } + } catch (error) { + console.error(error); + } + } + + return { + status: 200 + }; + } catch (error) { + return ErrorHandler(error); + } +}; diff --git a/src/routes/services/[id]/index.json.ts b/src/routes/services/[id]/index.json.ts index d712c1c72..676ff6405 100644 --- a/src/routes/services/[id]/index.json.ts +++ b/src/routes/services/[id]/index.json.ts @@ -4,7 +4,8 @@ import { generateDatabaseConfiguration, getServiceImage, getVersions, - ErrorHandler + ErrorHandler, + getServiceImages } from '$lib/database'; import { dockerInstance } from '$lib/docker'; import type { RequestHandler } from '@sveltejs/kit'; @@ -23,7 +24,13 @@ export const get: RequestHandler = async (event) => { const host = getEngine(destinationDocker.engine); const docker = dockerInstance({ destinationDocker }); const baseImage = getServiceImage(type); + const images = getServiceImages(type); docker.engine.pull(`${baseImage}:${version}`); + if (images?.length > 0) { + for (const image of images) { + docker.engine.pull(`${image}:latest`); + } + } try { const { stdout } = await asyncExecShell( `DOCKER_HOST=${host} docker inspect --format '{{json .State}}' ${id}` diff --git a/src/routes/services/[id]/index.svelte b/src/routes/services/[id]/index.svelte index bcc69b8a7..ada5c0d9e 100644 --- a/src/routes/services/[id]/index.svelte +++ b/src/routes/services/[id]/index.svelte @@ -41,6 +41,7 @@ import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte'; import N8n from '$lib/components/svg/services/N8n.svelte'; import UptimeKuma from '$lib/components/svg/services/UptimeKuma.svelte'; + import Ghost from '$lib/components/svg/services/Ghost.svelte'; export let service; export let isRunning; @@ -119,6 +120,10 @@ + {:else if service.type === 'ghost'} + + + {/if} diff --git a/src/routes/services/[id]/languagetool/start.json.ts b/src/routes/services/[id]/languagetool/start.json.ts index 4666fea79..a6a81d475 100644 --- a/src/routes/services/[id]/languagetool/start.json.ts +++ b/src/routes/services/[id]/languagetool/start.json.ts @@ -41,7 +41,7 @@ export const post: RequestHandler = async (event) => { networks: [network], environment: config.environmentVariables, restart: 'always', - volumes: [`${id}-ngrams:/ngrams`], + volumes: [config.volume], labels: makeLabelForServices('languagetool') } }, @@ -51,20 +51,20 @@ export const post: RequestHandler = async (event) => { } }, volumes: { - [`${id}-ngrams`]: { - external: true + [config.volume.split(':')[0]]: { + name: config.volume.split(':')[0] } } }; const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - try { - await asyncExecShell(`DOCKER_HOST=${host} docker volume create ${id}-ngrams`); - } catch (error) { - console.log(error); - } try { + if (version === 'latest') { + await asyncExecShell( + `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull` + ); + } await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); return { status: 200 diff --git a/src/routes/services/[id]/minio/start.json.ts b/src/routes/services/[id]/minio/start.json.ts index 99665dfca..bcffd9e8f 100644 --- a/src/routes/services/[id]/minio/start.json.ts +++ b/src/routes/services/[id]/minio/start.json.ts @@ -76,19 +76,13 @@ export const post: RequestHandler = async (event) => { }, volumes: { [config.volume.split(':')[0]]: { - external: true + name: config.volume.split(':')[0] } } }; const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - try { - await asyncExecShell( - `DOCKER_HOST=${host} docker volume create ${config.volume.split(':')[0]}` - ); - } catch (error) { - console.log(error); - } + try { await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); await db.updateMinioService({ id, publicPort }); diff --git a/src/routes/services/[id]/n8n/start.json.ts b/src/routes/services/[id]/n8n/start.json.ts index 6c9f63b76..4a04917c7 100644 --- a/src/routes/services/[id]/n8n/start.json.ts +++ b/src/routes/services/[id]/n8n/start.json.ts @@ -59,6 +59,11 @@ export const post: RequestHandler = async (event) => { await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); try { + if (version === 'latest') { + await asyncExecShell( + `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull` + ); + } await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); return { status: 200 diff --git a/src/routes/services/[id]/nocodb/start.json.ts b/src/routes/services/[id]/nocodb/start.json.ts index 1088bf817..ebc59ce97 100644 --- a/src/routes/services/[id]/nocodb/start.json.ts +++ b/src/routes/services/[id]/nocodb/start.json.ts @@ -52,6 +52,11 @@ export const post: RequestHandler = async (event) => { await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); try { + if (version === 'latest') { + await asyncExecShell( + `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull` + ); + } await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); return { status: 200 diff --git a/src/routes/services/[id]/plausibleanalytics/start.json.ts b/src/routes/services/[id]/plausibleanalytics/start.json.ts index 4b635264b..836bd0178 100644 --- a/src/routes/services/[id]/plausibleanalytics/start.json.ts +++ b/src/routes/services/[id]/plausibleanalytics/start.json.ts @@ -158,29 +158,21 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`; }, volumes: { [config.postgresql.volume.split(':')[0]]: { - external: true + name: config.postgresql.volume.split(':')[0] }, [config.clickhouse.volume.split(':')[0]]: { - external: true + name: config.clickhouse.volume.split(':')[0] } } }; const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - try { - await asyncExecShell( - `DOCKER_HOST=${host} docker volume create ${config.postgresql.volume.split(':')[0]}` - ); - await asyncExecShell( - `DOCKER_HOST=${host} docker volume create ${config.clickhouse.volume.split(':')[0]}` - ); - } catch (error) { - console.log(error); + if (version === 'latest') { + await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`); } await asyncExecShell( `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up --build -d` ); - return { status: 200 }; diff --git a/src/routes/services/[id]/uptimekuma/start.json.ts b/src/routes/services/[id]/uptimekuma/start.json.ts index 961a546c4..845873bb0 100644 --- a/src/routes/services/[id]/uptimekuma/start.json.ts +++ b/src/routes/services/[id]/uptimekuma/start.json.ts @@ -59,6 +59,11 @@ export const post: RequestHandler = async (event) => { await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); try { + if (version === 'latest') { + await asyncExecShell( + `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull` + ); + } await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); return { status: 200 diff --git a/src/routes/services/[id]/vaultwarden/start.json.ts b/src/routes/services/[id]/vaultwarden/start.json.ts index 703a71473..f977adda3 100644 --- a/src/routes/services/[id]/vaultwarden/start.json.ts +++ b/src/routes/services/[id]/vaultwarden/start.json.ts @@ -52,20 +52,18 @@ export const post: RequestHandler = async (event) => { }, volumes: { [config.volume.split(':')[0]]: { - external: true + name: config.volume.split(':')[0] } } }; const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); try { - await asyncExecShell( - `DOCKER_HOST=${host} docker volume create ${config.volume.split(':')[0]}` - ); - } catch (error) { - console.log(error); - } - try { + if (version === 'latest') { + await asyncExecShell( + `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull` + ); + } await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); return { status: 200 diff --git a/src/routes/services/[id]/vscodeserver/start.json.ts b/src/routes/services/[id]/vscodeserver/start.json.ts index be43cb2a7..6f51fcf2a 100644 --- a/src/routes/services/[id]/vscodeserver/start.json.ts +++ b/src/routes/services/[id]/vscodeserver/start.json.ts @@ -61,29 +61,20 @@ export const post: RequestHandler = async (event) => { }, volumes: { [config.volume.split(':')[0]]: { - external: true + name: config.volume.split(':')[0] } } }; const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - try { - await asyncExecShell( - `DOCKER_HOST=${host} docker volume create ${config.volume.split(':')[0]}` - ); - } catch (error) { - console.log(error); - } - - try { - await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); - return { - status: 200 - }; - } catch (error) { - return ErrorHandler(error); + if (version === 'latest') { + await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`); } + await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); + return { + status: 200 + }; } catch (error) { return ErrorHandler(error); } diff --git a/src/routes/services/[id]/wordpress/start.json.ts b/src/routes/services/[id]/wordpress/start.json.ts index d1685d8b1..98e7d6aab 100644 --- a/src/routes/services/[id]/wordpress/start.json.ts +++ b/src/routes/services/[id]/wordpress/start.json.ts @@ -72,6 +72,7 @@ export const post: RequestHandler = async (event) => { container_name: id, image: config.wordpress.image, environment: config.wordpress.environmentVariables, + volumes: [config.wordpress.volume], networks: [network], restart: 'always', depends_on: [`${id}-mysql`], @@ -80,6 +81,7 @@ export const post: RequestHandler = async (event) => { [`${id}-mysql`]: { container_name: `${id}-mysql`, image: config.mysql.image, + volumes: [config.mysql.volume], environment: config.mysql.environmentVariables, networks: [network], restart: 'always' @@ -91,29 +93,22 @@ export const post: RequestHandler = async (event) => { } }, volumes: { - [config.mysql.volume.split(':')[0]]: { - external: true - }, [config.wordpress.volume.split(':')[0]]: { - external: true + name: config.wordpress.volume.split(':')[0] + }, + [config.mysql.volume.split(':')[0]]: { + name: config.mysql.volume.split(':')[0] } } }; const composeFileDestination = `${workdir}/docker-compose.yaml`; await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); - - try { - await asyncExecShell( - `DOCKER_HOST=${host} docker volume create ${config.mysql.volume.split(':')[0]}` - ); - await asyncExecShell( - `DOCKER_HOST=${host} docker volume create ${config.wordpress.volume.split(':')[0]}` - ); - } catch (error) { - console.log(error); - } - try { + if (version === 'latest') { + await asyncExecShell( + `DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull` + ); + } await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); return { status: 200 diff --git a/static/ghost.png b/static/ghost.png new file mode 100644 index 0000000000000000000000000000000000000000..f4e300654755c1be032d48b50b31b97773898982 GIT binary patch literal 40603 zcmeFZbx@qmwmv$zyF+j%xHGuByXzpq8C(Yq7Tnz-XmAT|A-D$%1b4S!xqRQ=`<#95 z{Z-vMRrmh4r)sL+clBD&TI=c6{dP~kHBo9RvS`S}$N&HUODl zoEq?iz6(5s`OaK@J^rO4WlbuYY6HdzObj@i40_o(e#J0tPCIb3)A6gxt6Kxdhtltf znr^?KiuB~4zdx_D`L(}fTy3gK9UnDv^E-55%JSjvaS5SYIHIrdY9QPp;Kls)`D31F z{7hi`^wOs!8C;)+9@hCD)|9P%j9{I)f$JhDn7gL9_AI?`c*shMx z+p)Tgy*Y-wHRSU0IhJhz@_&jHL+PXPIe2~&YV7&Q-311cAVK}s%;^sDka6dke;(m` zNl87Q3LIUGGUa&WF%$^wqJ6>Md3?Eyuj^EM%}FJABtIVMP9IgRi^nC=gR;h zU(S77zeS_~8NsM_tn1K?3AfwQwnF~%C8?9c=W=B-OM?>O%MZ^YX%|kbFK*{f!?|9Y zH5@MW1sxBo&iAe4ZMrp>Ar?L&MAk+eOg~U1Gv`!)%E`O9HKX=!XPFf=md!WIW@D zJiG*>E7!LS&B~qOBBu#i18?U~v{wz=9=)+jDO#G;e8Ol+so=su1Ktm|DOzrfrD;0V zH=G|T+tUo}tDuKwG{$OEbqwtneM!=o4eLKljCXt@^MmGAtn2bP?uzddM$jem_q~YV zu+FjD(_gD@RL%~Flm1=(^?PL%i($YgQm>WGk=jnj)qpvSj~c+=DVnN+o{vQ78l9u- z{$n+*#+@&5=lV|y$Icr;iOmYZ(&7@pl~%K(VNMI2P@{49|?7t+X+Yoks8QsevbjY@s2 zKcZ=sF|z|6L#A28x>RF8YuGpY69y+um3fj?PeqC}ca&dlamR#^q=P48u{>$`_j7Pu z&I=PuQ=6}F=f?;nvHPfsRM12vYKqL1abKNP1 z8y+ehT{Q+Wd#WDlB5O2fsUgu0vc&LO1?OCSck~_vrP!<9xA<&m?HReJnu5-yD{SjB zh3`oKa6?4$zWf2ydcQ=a2A7h1{DcIS$avW^f*lGP`GZx;BWZz1&EdsA)NY?R z*X#KNYJ=6AkM2!&nvADxEWXm#BrJlis(5Ah4B7*$eAJe?KGtVV;8bDxh?T|;?>M*0 zzm)6YaE8mka%Qa45S%it#;MrQ@b+dC6An1&a7yF2k*Zk&sA(^_x90C}WkxGeU)m#N z;%~$bX@-AGqhG@=Jkz4V&LwL~n$3iSY{OK%P%4FEA1ndqJ0vHTmsxytZ)TXDWRRgZ zVM4YR2WP5U!&l{1;2e;Pj%yWAg6nPc4H+g)Aiw43LS8oW=k-pn(R?T2v07pbEb)bB zJL@`+%zX_RynT#~b$D-w*+wdplPHJFM04hm`-&c^U(!}eHHb+iOhdO*eqR2jWu;->q@|X?G z{6_lH{cTa$?{kygY_kG@LY3_!esr?RD(?6ipSD3h-A4Tn=y~*Sum?1)Zd~q`J-x4G ztG(RF3B1eXM)E1Rv_EV`#d6;(t9A6weAt})nnv$g+$JroQ}MeRpBK-tFC9<3*C#67 zhL8_1)6112GX<4hs`B|Rk%PH_7Ss`(m~DAf2x+Q_MC1U7P?%rZKxnu&X4<7}%$ll9 z6^P%dLGpHps8n_wF8Jn}5ZwNZb+horx7hL(iHb%-#U`8xgF!UH5irt{Kj_6Aph&wP zu3^h(H;1{AgcSszgnT|u*rq;nEf}vu&K>I3$HrlvQ5e`W@ED07r>ZI|_vJrl=E1{1gtm@Jr{)?HqJSHJ8!%VX10(YLc2u?n| zNR(P-cm|CH=2YL$yHeM(d6<Lamxe z`KE|gRbIUqQhGnoa25C|6!+KsTtJ52jzH!mvxp}=LO`v63Mh$73|M!Mbu7}q$z+0B zQgSW&9K{&4m)nBeq>%jHf5eSncMFCG_uVJt@M=<610@)=Z_;9ldmr>S;agN0iV+`s zg@Wv^NGmX=lPtc?0|%ppB0MLl76kJG3PF`-G~Xz^aDVm(z(rr86LDCrk&Gt?9J1VTk5LaB*TN+t&%t!s5Q#dCBLP3lQlJ-nw*>ao3Eollr8N@Hp-R5|n} ztKpF6n#rLh!5i1)f6pxPqf={UbbkEgpa%v1JRny&*qoIlFF$oUI6(5Td`?I1m*7ZA za4^m2veFiYFJI+&D33=!Wdx;Q3d1lW)d^xFp3O*su{Dgt!8QwvEg4*NwIL^le-#WH z^{jI*cjB0R=kMY8XtO(|z}TmytJ9g_)hoJhAUTw>L0J4~;GK|q{iaoLQ8~WLfoX?@ zquUy+jAFsdbi`mccJ~h-V;J%oHMfIwHjKP^Ishv2Ii~>7@(LU_;``;z{>(#jkw>D0jH> zq*Bqv0S#8y|Lac<>(3#zr7S6&3H1Vxt= z$Zr}-FUcGdf{B06E@Y;&3v(3KK8E0+UP^JaqD;|{5rQJ3^+fa?1_!JDc92G@w^9&Omsy4&?_XD8|8Q9P0nQi&@ z(X#sJzuYXdW17X;`B?~XZ?;>N2)p5q@_kWdxG5dNu|ngPy(hZzBaXxQv=!=!t8_q< z5D9+GAS*)pn7mb^MsfFEWX%RaAQqaTEPMsNP~5+Qj@Fm!t2CSgQk1R66ek&4d^dIu zG+}uQ7KMmcSo_$if-(Fp@w0CdOE9bVjn~l5>u)r?Z?LS$y8~)heTRwW2`Qp9X9_lb zLgJ|Y*b?snF~(VZ>UMHCu|q}TFkIPk@6~Q7dMOfdTHb9OVl7zmt4N;BmXXeIgh*y3 zW_2$1&VFq@OuB4W`Vl_~48|yleW8Kj+)*OCDrs!#di;b@Fr=);(^cp zsDC0OJF}p-kd?mIG1a{Cz5jSVGxX;dT2JsT%`=&uOnV_uGvtSEkR}N#1~lRR)cM1m zO>MBzdNKDrc64K5OpNmvBx^d=B_(0ENm9TMx0T75Be3td<}tzOiMcqi z;sQJX3>s+#*c(b#7qZHvj(%iK4>-DOakOL{j_A1s%=3A-}mTGUOy)3{jD!Yw7k zg)M`HyK$wAg;FG$uZn$YzhIYoJ*Z8aoDy4$X-}I6Sk}c5S3+!MYThYG7RaSQwS8ks zL{lAmc90j1KU*Sr-Ix77tLeAH6sQ*bBmV5d@QHD253V=S9h(L(Nq2I6UaXk^Xk=+3-MLEcq{CAyd;PS2ckbf@Y-e*AA25V34@0# z*I~pw^hdm&;)sTps;{+ZWV&&qzUNjx=_)kQFmx}ZMeZCj9mN%#qKK%OyZxY*qNJD` zl(rppn+h#%LLnV(_xz(%bUtnn2pyV8+gD=Jyb9g1*+@juA91{Zxf}SClax#9>Sv_I z^`B+pV>Wxfu3vGLZRY*lNnvoBo$8w;!{-JMW3ij3t{KcvWkudP2WD_h9)skFM*}Vd z>(S_&;9~)Eif(ta!ma5QJEWQCGy!nJjjEAUFVMnY@uh4*lb<;YWlEi+{~`Q`7UE){ zxYVHcynghmPdHEbCb9UG`tXDVKmC9)QL=w$yA961mw z80G+_pU^%s&zk18N5f z@O)}{)lKdDU>n;WcnVC-xq4`9*uD***kU|KdgA+|7$lZ7SLxswEkPgNKUif%a;`&g zGTd=|9RZ8p@HL;c%izUj9D~M)f2&6h49inAHFaC>?nJotXR}Bkjwz#L`%da$;V245 z(v&#BBSKmNY~uq55!da!%DcIv!b$6S~ZJ|Fs$c#9J<=1yJ)a}`7&Nx9{NxI zN2(~pnOejKZJPGX7@ZP2vH-;F^epsji*G6eox}e0+p8<}+fyT8`g=ijqxmXfFedcx zTXF(}JKt4vD2IIQsSFlI2S%pP1EkE-F(&BYazzZmn}OXF1Q?K6d0Q2J_?+=#dNZL9 zg6*1lAzxz$t{s81A<9FfYNJ;$KQKbjjwuSNTOyx(#nevpG8g-xYmU0Xw7|{R1v==&k4lqhE_ScMvlO@SP%{_Rrv=n5TJf*TtYhbU|7c2ho z=5|iuob3|0K;s=;z}YD*>rhCy+rEHyy)Y~BIN7MqaW2!)yJUNn?uMifd5H_0pB#iK zBf}_HMdb<+%XMh1U|M){zYTxrO1@oIh^ICF?)JD@a2+FK;PQK6xbiN@J&bN_AJYN0 z1Q!T82v&4ellcYj{G}j4qRM$C$_4mbY|ZX}`cMzvH;@vreWA5C9pr>#7q^S0NM+Eg zG>C>eoEM*jcEYSiG>AmfT}d9aTeh-?`5c=ugAqDe#G4_Y5GrD_l_t$Aqan}BJebVr zjhT!rBWYm<#P`b+*C9y&X|LtC`#Ck6fn72b?bTlr=2E)LHeZQqD=0#gu+(_8Wa!^# zC`+VWfv;nfyg6aYi(1!4e8d984ab@izBHUTcSUeaLh(q}Aw{OA$r1$fe^E|ic=*6e z8udFNy+t{;BfO*us{Ay($j9#74FXx=MY(WRIPb-Uc~@hPbuTiPW;6mbXgmd2b{#Ju z)ZpE_;4vih2Rl-aD2Mtm(Ct+Z`oii%I2)9dm zQo3_KC4*YpKt&L~eXJ76yUQX4RGhtNBrK|vpeEBeL*xF)I7tOkSonS?Zl4Z(!gD7Q zmuq&qbO5QsCnF3~Rua5u{C z9Kl`(5S@)foWi{_Xq;LUO5qnQYYp`6u&f6BIP$5y>4eA6>#k{-G8pB(k7`~NY!idC7f|Ne^BlC;2P%Cw{9Pb z`+LRZYT|jkh~E*-X%;sAw4(qX<1?SuDNTy3^|GkGPpW0~Wuv@4HW~CSxUjQ1V$uc* zks>Z3Qk6BOyf?+<3A+9&`g|ID(Axt7Z>&Sd66^g7Xz+u4MU|gi^ob<1Eyy~vkx{FF zb%S&}tRIpVKS8dmt9Rh838ZY9?G*(u;qtuMOr=2(#zk^*JRYO>y zZ&5c&ee`lufkcu9Sn?PJ`}+-g~lqX*&Z~L;8z{OTv>d&Lkv|hsnP>MM4hU< z=_vsmdvT6mKN`;G$;sr8u?=!nCCEf}<#=(K$cw?k26VG-Si+iK^M^S&-r110jL8y0 zY`k67PoMj{xYGb08O1S8s^!!YEI6LOt1~^jGGPnuJ%;gaM-iYLb~?F*jPvFet*ct> znh7(KCE16+q8YN#tK4#!6fCjMhc;lPT=dW8HR1a%32s1oMuC%I?*_4^^^XFXWlIZD zRxoeH$O{Uazc)1LFrJKIHz_|zZ_G!`M2t&$7}LY4^#FPF-tiihf7q2fh&oQ#+P;vjwWu#n(#1e}6cr4i(apBMx>=#lA|1q5w^f7@6MU7T&3s(?oWwLf zoGS*WzJKANBcZ2^R}$U2&~l+MKvpAjya{ztT4Tl?j{e1VitJK=*+-Z1(-U{V(oak7 zEX$cGL=?UIQD#SDbbT;!>b`QP@5c{J!#i%GNqjTwz-CFIEbp8#E|uuC{=7ze0u+Sh z`7R>|80!*N6c)yV*>jA*<(H37j7h?PTu%rlX-fRSbdMv)soQB>iJ6n`qbaVpN1WEH zF3B%coJ;xgh);4!KNc2^f7T!KhlUQ(t(U{V098UM7vw9JHz?889&L$GKa;;NXdDMZ zVsZ-zY+>pKh*4NgotS>L0ZMcbXm(JVDK$uHGn@;QfX>Vv%tNg1b27rVdQJVoQqwmT zB2rN}3fbz1nRh+rOF_$>MK2CWipu zsJW#u!^QAOWHNrhl5Smo%}cOp{(e85cUco(jBXpk!X|-0vtHuQvJ9h?;q#8*DiPh1 zNe{E3M-I^wU*Q`}u4^}%EeZ6;&m0Bx`GlCjnqFA0Z+FNW?iW>63dNO)1}ZH9r7s2{ zv`P3A@zqe=X6SY^y=67V(S-w&3@tEO!BC0F?5Fl+lOz4=R!!i{sX%)6m==J}qROZ( zI_HwXJC&+!R&05Lx+F^OZAV}kadZCR9R3$0WH?=J`co{AZa_NXQ(f3q-NQ1itA(vl zYzl7{ZGS1Z2PBwG<7u8IJGNE%ilE}TtZ}RmK39EWC1f#L0!zQN=FjIM?cDv}tErm@ zuXiwiVhCmhde+zfzzpB_tyIBOyq#L15!<~TPU$Ht0WF;!SwrOTttuIwTSvbB@*bpvVos%TmI+FJ@(QHhEm z3wZ zuz-D>+|9jNoWRt7LHq+l3Iw)vvvYB`b9SQm3)9@f*~49!it4SM;$QJOx+p9E7rYbr zpDeub!RBr5!p6bM&gSUI_U{&8cWKWzkbegBf3yH=y`Ax~X@J1a9&VN(X-|-oJN3Uq zSXus;y^DvN!{6yxS+ao~K#p&!;5V-v|HGxMyt3MVS^PzTjh&;*-&SvA{|`-fJL~@@ z>wm=dSIgh&{Cgm8=KqEJKeYdq``^lMTFS~mDQ8QMzrvH35~ljgKhVnA(#{I__azS> zCy%A26(0*XCy1Yg8^p!OV$RKD&cbVD$;ZPfz-`IR&hc+h@=joPb0) zS@Lsnnsf4SvRGSMzd`Zw@v{i<2=KC4S_)WL@mh0Qb8}n#4P|8slyP=*G=J+(J4bUH z5SxpW&EE}w5e^hrlNYAqWM%(viJF7CyY-uaFqM*>lZW?zH)z>8f;8RD|6-Gamz$r9 zpNm`I&98s}57&Py>44n8Zq!C;#6qe{~D+EtxlB&Ht*?H-Nw8Z@B;^-9YB< z&Td-H&JMy}|Kv$L}Z z2yj`lfY{9~_}DGYxveb!Z|GoWYj-bmH;}l^Tc&T>ycN*j*-$Y2O(o<1jK#|q^cPR; zZ)2OCi-nU1`F{^|qZU(ndXbd!H}NPEt}$UQ+U3ukZl?42c1W!g2#*?}kh@ zOR4bS1S5e~6)N~r((ZFixP=lGcm^Kq?KhIPvk4__{K&O%2%`8^=&X|+z&7NNO@zqe zi`vHJ1~ z{a*g-)V)icgi}|d_xlGLV0;*8s!LQZrEKq9Z?`#K{&O5zJ$0R^sVG^c4vI_aCA|0z zegY$WZ|gy&^1VpvL5srhRD5e`P3k;~xXLV*-x9-?sn_^6HCpDM{H_Qhz>inhOLpi~ z!EnqHA&78z4h66z90nd5%q6y>XWQpqFWBw4ZjO*dOEQpcg0biW`SaQ0_xN}p`Ct6g zuUq`&l47<56}qJRPd{9b=*2FG+Gev~-Ow@~X}VVCi)6*_d0kxB=Tn3?-4G7^IIT22 zODU8o^AUbd9b`9%owH20AKfng7&(MVD6384>+PdtH!3*c$@lVVy1P5ilnD}zGjVGm zS1P7`+nT~#D9TC!t^lq8%GuLOzc&ezi<~|f06@X{>k9?Q${~CcBDl*dOC#*Tkf36t z8_*l|0RR*Lc`0!%@0F7-pB#{`{@EYn{dpnx+l(_6j7%H}Xn6{A8BCB2rW%nnTlB!x zFCaL#7Ut*JLX1hBiTXL7v@{l+7A};y8YWy4AUMG%uR~B+*GqfJee(6CK5yye%;T>1 zjAlU|?fAuivb=KA$gl49WIs2LpaC?N#$wpwu>AjWahk%iBbngHSj`a4%MM=+BNL3) z%g+vtdejY7VA={8hcSK;LRW&JhZOf>ZDs_Dl1VUJsZXYfbFC`C4C8;n`T?DTk%Qs@ z$BV*_5R9*eh`1jN_mYDn_LyDMljamKT2s123UdeT1+@fo4=u};U_Dll=_mlT!|(;B z4Yv)zFAESj(%W+77_c*g&rpUmP`jManAw@>(%8>9Ij%nrDtv^Pj~I3KzVs3VPr=+< z11A3RT?`i|K7Q%2Dc?)mi!(^p2|Zlgp)3H&!IATXO+q=lS3#>PfoIQ#)M~>Nz!$+l zPjdu6(3z26P;PEWA|hPr{|%x6*yi07+Eg;*`$F1==$*56-d5-%Q#51JfMJ8{Bg2tVNv1GUY{F?bCz9{jN# z-m4O&msDX4#Wa7(#!mgUNf}>MI4Y0O;-m%L}YeCOB7y4}j2<+r1?) zbNay*w4Ntj0nZJz7sN}BU4e1x*0WEy?JNk7`-Q&8TO?N4t6V*eNdCffCfW;_;XvD}U=_+Lyxqh<< zpVM(n1wo-lV8-pIrm}?Y9YKE=Q*!%?>P>cmo6BYyu*d6_J7zFVqMGAX0K33%zS{nc zj2n$TV9!@e)bPx@_Ql-do%?J+D|dGHW+&rKx*Aiw>{N8U&cq7z6 zk)l!Bp(U4H$1(`!tP2QzZTXn@5w>KmV?yBKZrqEb_k^{pjEsTo_1u;?U5Kx~}&oEkrf9N%_gF1wG62ESG`TrXPy z@r0n@)Qdtu(Yerfq`O;%Byyc7Cm+1_JSjc?$Mw}1E9YbKl2aY?3!>lP!Y3X1>Jj0xgmp zVJ@b6MGrgCfPnRa?K}S9GY^Y`r7+C1$try|l`G?HL)YC7)_y+w}i8e|wL0V(ns z6qxO)KSH}q>$06AaeNCLpwe-+OKf6BPhrR~8GLlIhslKXB*3R2b(jokG{bk)i-{&w zWu3<7!n>uG={K62f~>4WqcavnS%YW4!^j#sbMzfz&i2uA=lV z;ovA_57C^vR?m0-yuQJ&D5qF+1dMj{-zsFG8QlX>0BGV783# z75c%a-P4b8%ndbVC1rWN7P3jVDboIBZ+LP60$M4uEx7UMJsylW!+9Vp$kMyYeCW87 zC5AL0@gEb~^ldpN(_DVP4z7ZXpnM%SzL&2E`9MEiO}Ig7QJhz^)PCaV%XKmg9D$4I zyy@=wrDtQX$bG=-LIRtYe&qMcd(lc6ChS9CH9hWm1o`dJtICLfSMXz|8m1%|mcbd{ zFKcdME2i7AUK7SD&s-!bBX~nRMXgiUOhA$cYfjlBZAj9kuahUX;gBQgT=vS_7$HGe zL`I3hxWKYaJ3hA{%g0$AzkLc>=v*!KN9S2h7Qf9=!xQQg(c^d!?5oDP?uecyZJA>V zON}Y)EBQs@8cM!6mm!y49@I1cg<~`k*{rq6bOh-P{3^AK&qoNLGMC%KEVE-2o*k$6 zIGBLR#BP*wgJs?>QWw8`GmtOXvNhP)Qx!U6{>ykuaM>}~NX$JB;{H)=EG`qT90Tdw z-SNYj$H-4WQysj}Dzpl?Pg%()`{#YvpwtX=OgcYW`%+#xiax>v^=1HNSeH-w8!tK@ zLqYN+w)wn`w-WKk_s79(@5}63#FpigLqH#gl37*Z0=0rRm~{Q4f4UWx@q>_^lrKk} zu=D*HSb;nR#Cl(0zBLXOS+AobZc`T zyz0a;lWXBeC(|HSP1vTnUtZz5v8v^_7N9#51_47j zw}Tp4L--D;1WtdBHR@Z|Wk<@_l{29~1wmBzOdj4Imq^UA5I$(p!cXpU*Je752vLzIW*O5^VNyKgbzp4ls@@e zG!**G4ZJV=4?8ip$?+X(A5$@J>Bn6|^X#F??*5SByZCY>FK3~^Oy;)k%!P@JV7ogC zpYzuPf6>)X3;S;HE}Z-+=w1Rz83!ZaalO1?_8a}wCgRrRGCP9})U57HVu4v<;DcUb zs!cOk8e-YERk@nyP>OVO5iObO)X(QQ-6|_f6_9O)Zv-bjSl9x_bkGu-KZtR21CA|3 zW3rYou*QNWaT^7%wahok_E_oqvA*GH!LPiZdW;M*1&curyIsfR39a2JltGPwl zBeTWlsW4WNHp~z^o0U_3?Y?w~daqKFFw_AJeG|63 zHu(Y`3ViFM%d#{p4KR2VuFQ$wkeFC67Oq?@&ggY4YUn6{$JPAL&&4>qUm+sGY+ZV# zmll3!>%H`ND8hSdui~WX1mFCALtpT2z9$mmvaQwX^~b-cTG1Pp>lQnK6)+mu8Q*&+ znN{aXlns~*B!>$8l(E((&OEmlM)EDEAj`wqw`UrYuNquu$bGC^w#&;XRtC474VREj zDkvzioa??8Y-#MJvCe_aQ~NsF52wt$9Oy)`7?xN1q@s4Z&xQ^EL20?4^YxFMbQ;>1 zPsU_4o}>XLkk#|JWpsAerV4d}huNqjNwTQN|jx@xW1q&V$*vM1HcOiPWl zVghOGRvWqVrMmB%3LZmCeJ{wpChj0DS6JF@k0B&9id~;8x8Kbd-Dw+DIEy`XQAe*po07_6i4dwcQJ$ zXE3j@4@{uKE{@y%!#j@6bVsqoXtMDBu**U zKL1GG}LuBtr(){32VBDn$6n3s5L6rVz- zgZATMpvsvPrTc#Zwdk!p*IX}a0}Vbblpw7*BHG{r$yMk6@GCEy&!@l3Zh^VLNvUbf zC04up8ATxfN_D~7ehw4YSN0{`ahpkzLhkPzn@DP4|4cZxR*~A)b zEEs+B6uM!v`{~^RGuYT+mVRKiWx{FV{FVO+oZ_jyfRs1?avEO~(Ao&GiH0JZ`C}cA z(GfFBxZ8$_B0o<52W*V(q*iwhIEQ%+*5F?0NUo*w%nN{j=)>%v`D)2!E0Simtm+W@ zOv%yNL%nD;+16&5{<9=>Dz3aaeMk~8-WX*}1;;@WBv>DK9tM*aZe{r~d64ax*OpZ6 zjEat8l18D#(e=#fi1S_(@1A8a_E`>Xis{(mlgIMY{HKUVk$YT*&QVu+eNgMKdzDYe zYq*-t`?v2GA8@-~<@)JPLo9*0g6@CR7390!(MqcW<$C>K)H&=hw23-vdaEK!4MZ^| z9`?Wby#xRG~_{0wd3fh`{L|d12wl_EYbNw>7(hoFKhv&p?hdp0OtDZ>X$$ipHuVL)C%rm*+>J5U$|!_Mr5>`p~u4vA(v8IZxQ< zUW^jf*Io&IM-KM!QbH4&()M3F62s7#lr(S|>3{WN)8>QsNAmvobEEUv2J03f4r+ry zqV4_p0cut`4zpqJSQJPY0}v!Ru99C7)meHeu~F8hw%xrnaa#t@?}aTW#>?R8%eSCW z#BH)K-kA#c;^n8D?1rFjyszQN{j|}+Q|k-7UmIb*N0}C7Y@I1nATwoE*gab0bRkWD zIvPN;!Bi|9W>5@s2>D+$lGvLjgyJ_37bQfS4LI{uW3BYSLYD1a6s3SQwKD{v#e%4vg2c8z9ztQWRL@&^T*Kj=In0L%d ztpbJd;x3r0Sf)uCtcss<;pFRx=$o>(IU;kFnoyFqf(lOi8Atd>*nr!sJCx?6TCS$*LXC_ycb;&tC}nIoYMH6W6Hir-nuu{gaN06ak5y z2`reMU3AGAEb?vrD{2Jpfg+OnbL}PtFT@sHgZDM5;B@ip8>iTbUUH`48?4|3*H);b zFtQNvuJyrbzkan?rwYE~`+8du1{xO(P`$4)J*xaT)`*1X7|Yk`p)uw>Yv$6Lr#sEK zliV3U@0xFDg9h{W(D{gz<9nDY9B&(#RJWQb0?bJ!DUL&HKGnIYM z&Yz9SnVF&z0*Xv%SU!vG`UGuk*fCr89sK(`9FrUto-ZA!UPRpFXYfDZpWE>lWf|Z? zyM9`!bnnLeQbAIo!Y(b7&${z5lEw;`bKgkwp)L zzxc5LKYe0ao@?HY#qw8PdP8JcyRgUGf-(5f>w|btd`4-$JfN+%b)|a@@dDMc0qyKb zZ+)jpuZq0FdXD7D_}M=9$2Y|KrlToHb_3$sKy1)#!MV6`#d%pZoN)nhC+|W9DX`p>+B4~NM%ss(1M0zHGbkMMXX=yz{Dh|Q z8UYOXw8dkSQRd+wZ5>IF8VxEq5G!K2MAxpjT^kila$#=4vd4YPl9{L7(nOh8g~px( zc@nq4dVYz{otP19=mTog-3UJh_rSkGw+SxYv)CQ%XAb&Y?+fZa5q25ClE5|C9CtHz z?V$=US--nI7FNm)%Bx(NEm#~u|86kdL#HEv+i@;rp+B1s-9s#qF=g{Ubk73i_h>Xp zptM-?6bGa%O%7(9$X7dBBLe9bB>l4m3nifyGxe*el)zq*A=spv!rzGGf~hiK7g#T!@77qN!k;V;eB*qbn1Rw zTZ01nsPTD&&+q}ggbOYylnU{D{+b?F#=HLKcBcg5+;3*kbhTj{8(wFpff?xW6Bubg z$udG3jY}>jCtGH*4B~^&p%_?3SU53lQsC3JgbuZvY7tZR#XUPPPY$s7fq7L+cG`gM zIWTxvGz_!sYBoq~Y4gig{)Pmz(?u*qroHk{=3;=vz-y=Sx6NHn>U+unhyO zS^sd5q?Rl({jf!kN&Zs}W!S)PRM7NI%Ug8KPz7Toiyd+xDOMx9HwqVGM@0&l8QbM>&zl1=VE_LfT^ za`}vk?p;oeMed5}GE`pyK>O)K!iH|k`O?ht4YiH^Lmc}%b`Q-~pAe}#)SMQtW#Jlv zq%tRh(iXp0UA?0?77;HpH527g6WzRFF7_ht?FqSK ziXN;t?+4lI)E&w{qjTXUvPTFkVGi67oryVTCX&vf^{z&N#EmVUe(fhuH4Ch#N9mK{ zRdG+K9B3=wgPQ{A)`sQ$;U9u1!wj#kOt9=dk|Ecn27>q4$+B~k14IZWYz3hW7X7fX z^v%|BM}da#2U0Ww@9r7uYp>tv5tU|rvX?;Q+vRG27jI;U-jA9INagR@5B$FPjayL# zT5ge8z;HXs%eHnvDRYhA6>){@Hj5;x(Tw?ZzHaD=UwEINL*4@hB%G(Kcz^BnmEkl@ zjDX{41Br4iGyOK&sMQ8h$h4N{0Z`hnEvt0B3k@`c2|O^7wLgIJ>fxCDWbj^Rn7dGI z;i-as|fkwn~sXfl#xyIrHw(OeTFYHV$8G}*Kx*!D1RCdd8U7EO5UuZ;Ms#h-2wV2dy9 z3Rkb^A8!$Sug3IoYHpSIaDBZAf6fb@g|0g>#2Uq$>p~{jSv)0EuwbY&Q7@xg+RO(9 zw4TcWV`^xp)EA%jqx$+zz5SQhF6irr%zX^N6qa8T=G<4p!>~ndMW-j`kX*&Iwb`a=JPevw zu?*tYXF*QG9jzDBy< zYqw37E0sI7MOzWo!c0kn{o+C3n(O!9QcIXP1@L9?ImIbkES4P^K?Veuio2CTvWUMP z{o!>e|KbAc?EyvI`!!U9aOpns>CbYbQnJK#*M5w0tdd{W7&S>avnrl;2$2rX$Z9%QR=m_EDZQE$)_`K4t`l#3Eo%JA(;7}^@ z?(jw`lIY5G=^B2>yGKq-ZbNz8;irmz{Qhz&+^urq8oZn1?AEKj1#Rys5%ZFew+dhb z<7?!P5?3+STkG#C#c(yJT#PnC>q@cU71#;Nni_M2oMPYCi9x1##hrD3OR}{V1u;$C zjeD%!>29f$lx0N^sW9EXJNbN(EWhvBz`!i46<*9_)narxQPmXa_pp2S>S-K!NP3Tl z;k<1Ajbitwz3E_6?-r|5QM3p3n$!Td&m(X-X^yh?A6m&)WvkbX3s&kxPFObw1|JSS zxt->hyxgo*`!)l`u5$-Hzf?sL4Io6i_7hb`y*p1@)ow1`&*g_}eV1jK@iGW~b$uI% zW04w9aQuP|>TCEshpLgw)Hca6#xAvp(7K?U5W1i0z#zAre2=0aR-4YGCmS zsEX_>--*(X1?L84-SbrL|5P|B^24w9Kli)#HR>zS#~s1|h*HXU36|>YxNli(uephO zdd5}u&sab*S#dFPHdGy=1k0+rk*NLko#JTyfM-W%T)%Kqx_*fRo@>`g@=hsF!rup* z&PaQwFIFvh5xcU>_knMo2nK~hP5AQIRk8)#vkCVbgE7J|U;RY377C5tgA%_YJ}_Do z?TSF9a*Q{vClW7xRdn{VGEV!7#D4mcCy6?4SmtkXc1wUO3OwmfZWq}LaaJEcd}k4V zxzIZ%iP)10#kDGFAxvo`d4m5~xpqxy-20JnHAETX4!?f9-2P?xAk8u*t2T{LSnR~F zM{H*YOC{p$R1+1MvM&}6bc&r+v|pIc4FbrAjfbk?QJ zf0sPy%a@!R+Q7Evb>WbR;*RS5UfqYGQ)HR!bLVSrFGe&i89`=-3ZYHDn8(M+k<+-S zI6>V2u^?w`TQVB!g$+W9hqnbyYCQulPA5S~ZRP#gP)3Qa&pMagd&2W_T;E&Q@o?e- zBc(k@)Cbxkg^5`Ff}!ZMd5h-3Pv>YG6knR$5_(_)fp32&V)%Ay@~-`uKy$L-z81KG zLx z<8SVuEyk9sd%q}-E38zz#h4Q7IpM11DJv09z=%RW2NAJ1=E8fum`0-EFC9vp;t0zm z;qUCOy}y6DObJ=-W_C)`xV~<8`vY@vowb)G4klXl!U8qbQm5gO)|zK{)GJ|RHBOSM zrp9QvRFl}kyZY|lf51XJjt)R8T`WZyM{1Y1VdQN}W`KPtH5OZ3w41Giu zm`$^%vrfRrtB`9l3x^kES!O!M&V>`_$OR@-%EgFokP-Z%#3b+_>%>df6sfA~j z7i(0Vx-9Tvavkfq_eI&|H=5)8s;+BE(gRe8b#+>>_^LMb2ejEKiTLrVW%7;zuuo>; zF|vWRorGU^Qk=q_Q;rL_EM7g0@$_9S)D@N>X?v2NlzAWMKaYz?1bE3b~XT#*0 zeTvG(Oh)HEwoWme$fOM_`@Cqi$T2arc16+pYy;O_41I>7$z;>Y*y+;}ZSF*$M*bpq zwmor2cvdV5ZBqD>{GFy{ZDqaY#iM5NIRkwDQhghLbooh2yM$+fqiHR3&(I_M>w5c+ zNSuDT$d2FGDmR9dJ@hEB)kj#})!HPcoWdG6Uah4@zs!}Oe%iYn@W+tL%-S#Z6af-% z9}p+tJlgkRkLX|T0ub(p+${ujOp69LSWez$H@_pNUvxZM5_uXu$z#i}+HM7GFx=lm zw%EG2={*`>%$izaHXizH85>Vnx8j~M4q8$8Ys6mQheGff;4sHYd$e@-$)N+eF>1fJ zpc>uUg{Remd*4nbsFANzMhhFGmc6Q$o1zm0UPR<@3x6|RToo~NQ-@sP$PM*rwoXgL#xzF7~{pJTY1M0yU$l)~x zC!*qUQtLI*`G3*$7JgBF&-*ZqNOwpoDc#*7(kar&!tT<&Ah8I7l7bRTr*!AS(r=_2 zmXKPIZjf41pZ$D)ujd~)_dO@(%v^I_bBKO6WeMV(!WQ`G=4wO(?#V<4u^*wGU0K*W zWZ~PN`(#z@*wk*^gv=)4B;glf^A`feH9KL;k|LD@#_VJzv-2z zj~Bvx#nF@U$?EHP2i655G5l+?&f|oFaNxwW{G0I&nSw9Cpb|!!=Tk2706MQffp zZi^1FEB%>k&tXdQ7|b1kv->Uvk}V|#j5hA$cIqCBb!UBE0dYq{39=iPl5N(xUfE~T zWA{OlK+%nj#3>C2)6V_oztOb8S6R({cpM)vndDlWTG6CXT6?dEXg4Z?!N&*CY1=K`OB ztipR_)sH;dlZ|PI+xOv#3Dlpx2{fL2o!q7jjbqi%Y>)QD#TB-)N9^o_GaP!zsXqsk z?>QDBIgoA$@D~EVxPGyA9&GK8?eV;5&q+*_rJR;7`G9xUK+%ipcxw)hsOSN^XAp{TS)6B%BrVY5gA;X6%;J`QdYqTawNL4JB+E7wd}z-%Vn= zQ$g}!@3Ye@o8b#qik}K>HxBDpfgalMw>a5(++;^q2Ju#zStnM4;F!fr2TTaWl49Xk z=_ae1Jsc`sXVccgC}BW7s*qNO`=Qcz)V;`K$trh%2YOzbXls;^jQGu|jB6x*CN@IX zSYw?=9QKbz?WSI#k!Sg3;~G}iYgxDPr9|S9o1La1^)&MvCH>|v7wNYD1OR&n!Lfx5 z6ZweCFvjTWqdTXiR)-@)Gw zNhM-+v*R@6GIUF@ST+&vZsRNQ8g{0LiArcJhWX%cI~{mVV#f6^_6U$^34tB##kLt2 z`1vEQ(xnmS5I5w%e*~F{JluhDWFqpfjz`xfm-&}p5=20o$~pWDcC#Kq*!X6i3rk9pHN!{a-nIF zMkSBi?(4zXR;ZcXkKiZ2I|HqNR=C%reKQ>V>Ic5T{b3i8E0?kW=nmb;Ip=7ZCp9(n z8?Ql{s&C9uVBc?jv~16%N1)tUl~&4++Hhb=nAW*cb!4-x?osI3$(`M2iobHF#cr;V z?kM61#Pu|0tk99(0J|?ub|00)eNy5TrSxWZ6mUAqcw^l$u!-y_GkXQrs#?Z_s3?|j z-E=v&61fXhs3u9fAM(sL`R~7-jqdqXdOXzWuod4jQ)581792m@S*mk$<*Jz@pYIw%*faW;dLvzA@f zlq?@Tl=|X4!*Vu_g^Vua+L3RMg^X8|+nrS5#xyf9`nXkL*na)?PBCKVr(?#CKB^zV zePUm2ED?rFx5;9!$kW{`>UC?A_x}^4<<)n{SSw6^#+&+EnORLHx5Wr9>2ylVi_$!z zWAd@h5e`y*T@}LDCsm-!U=e?@_?%-6Zux7+;XjEyt=WrZOkikdhe&_k{^-^&qm%Pe z{*pWKfB~HK>-UAg>c@EVYW~Jnf+<(pfQp z(8%GsiX@Xf2be(Z+Hz9JG}@HaFCs6IST9od%<)g#SX)d|E)d=?WT(e>?j2E6=G#Mm zaXk$Ga*X?&Jb;SFB4K7ZtBbuSMCIOHT=Yn4msMF!Krb^{6N3$MEYTMJ38wDR)jXW1 ztq+Ddi^4t=gjEN-^Lw8zzZ(8qi@aaamz6j^py)M4NiWWeEU&0%JIcN~I$PXZ@e|j1 z%0ernmZIAfNtyB@Y?8nh6BxfD7>@$2Jzc4dP|(ZZtHsr0%hGN4zsuoYE4IKc*XKcE zT_|kyl&h^d=dnI}F~KtlbFW@*j}aaJiPH};mH#}(FEPE55C);2)9=#y{+(zYv+WI5 zCD$~@43*chkS^`|+>d6Q0!Z+9JCFBp!Mi!=Gow`?h61wND;RCC^Oz*qIPOI#s@t6K z>$kYTyVVsxyHAeISyD?a$JfX4VFA=wja_vf%-7-=+7f%q#w54!2I`tjbtIC2-|mT06! zb$iXX0B4(5!ejY?J}_Br8phBtpMf_>1s^B6JrSbT=h#ba^|a+WYut1PmZnDzOO zJ66@OyFVQU4ZwTycKv%tMNz({eCW*Sbs^;G_>i8b(M#^d+~#oipFLT#uX9v=DT5P~ z4k@<7B{x^wbb;_)=`V#YLE0>3hQ9sTEDCm?Ho#m}{PrSzVFmo{0T$p207MKhyB zmd(X+pHx3I1^C*G;n2pH4qH`t%4o_u({$kv(pYyV3NK!j$0N!3Q%!MlupS-51gv`S zgrG}J_l$%}^P21shEu9no;?da#LtALAO#Y!YI$P;z69ez!3AN?NiH7|!r~j8J^Qpv z0$9$_fgc@5=Qj(5vHragP-aTWg0^E#j}Ai0 zVeGU^5e`8t6Q4b)2O;1oU2~9CJ#idMiAUgqs3z6?-bZx)zUqAY1*HE_5Mc9blev}E zIQ{(qVy9&5Jf=gV0a)4mk#3k_I`lT_diTj(o8HCq#26zwoN@b>kEJp7<1JNvkyHDi z%q%=}a^rcBrBP5O)0`MQC`1KUOoZHDQ zR_71lncW-jE~~J-soll7qcCD>hS8&B*T1!ac9<#HE2KZ~<7Rg4(7Jb>4fGFXSf;@w z0BTh<74_rN;Hj#mg}5&UMuOtn%WMT*vqOX2_vLxPw&)dXz~~MGPEGIgIY z@;HQHtv1?JLf!H$u>QS{hmcM2?}+jU`{w$<+d4h;@Bi>=7`ct)6VYhY>+AX|&)sf^ z3I&=_27eFHbp2>O21QS{$MS~A)h5ddzq6l#ru8Crq9Ai){~MKs>t(nFPFdnFBWbQr zGbPepfuF>ZJqp=AU#LXI+_f=E#JIesmYZrMYIn=rMizCPT!|M1sATplEX#>{PVHL2 zLtfV)z!{%?$7@MBm?wgtTfvjt_VP-y*&O?i?Pj2l9?Ew`Q>u?jWxE-1O8oSX#f%a^ z7T*{1RRCW@d_45jp2?^*dAH4Cl_mnaQh0~#YaRsZp-A(ReiK1`IkFHL<Bw{b8lr zM;D=>XRWE}jx5D3IzxR5x-Q<&fSp(IzjibnIb`9_wT(yIL9N$g z|K`q2(pNiA%?f-Y?vtp#;2F=PFMX2DAuH>g_HFep?44}>Dv#lc&SDp09rY6jDIFaH z8igItT3>!F7BFuy?y+jhi()DN@A#IFGEL=ZN_{eq>&uy~HI0TV7jp#iifeL#b}$V+ zi_J|YVA8T2@gtQa5R}3FF_*8zS?E8Tw!-6L%QR;JUzI5Ei^Ww?iQd! z)K;Ang-3rgek?UG`f;tWFN6qrMz}4qHrNPGNvsmYIiR*q$P?HzN(0rpJ?A!wCp5Y- zr0jZ0!b}Y#lBZ21b#%;%o>b3lbv2PSfD#(Tb&tnB)H!L;5pmElBOn`T>iVicz{xJn z<^nS){INasu9drwEFWt6S%E~xy<D;WWQ#O`ih9U3!P&L~S3=`$zC$>u;CD&T zxT%gWJNATlzYE8F?5bL}D!@S?#HQrbo{gIN(bD#Qu|ZLwJ_<}TEO9yvN-15dx8nhe*k=gm&!X>1wr>m_GJJ_fC3;q| zLY@eZF!r73)gK3{|QIW(mZ_GYa1UIKoZv?6}TeqkWXy#3U9WX4Ya z^D*iQ(Q#G896|ar^XP;0XWR)Sn5|^#^yJ@~sttbQx)o{Mi0rYzcnovb{J;d2QJ(jiOWX!#v#iWWiNHsW$H%XCfw-c{grcw@`nh?% zJS>;P5gCK*-E0hXUXvgb&bAyg_~8Yx63EY?Ly&ILbDdFyXd0E(vU4C?RaUL}c-e($;X2`7Q05gYsz@uRBjzKiornt}#5`NmoTHI9L5L zekR0(Uas#|b+c8;h$gq`3J140r4t#E%mSX1E$4MwEU9$;__r{S4c+Pp6)Pu9T#qUa z{1s@cPx7V|l7W(J`LI(~6OU0vV62U5uo9mAmTSeEWo(R1?mJf+gZOrpg7`MN@YKoU zh5yC}M!4xTFDU~(k9`5O@Fc2Ftd?g$$Y771oLU?re(BE=Sj<`Zr-Q#1bK+oQWRmY= zj@PsT^Sb1D=YFKm*skhZ{0#hUi9PPyhlTtA3ZTp{`u%?S6dcEu%XJXiuH^7V#(2}V z;`z_NFG2r)^o!$)UT0wTU2(nEv9vJdu9jh%`5d5F)AqKkvb)r8jjnSNr+x@(5lba} zl_r;E-1XNqcFANx0fJoa%dCc3Ut~dmS@XUD#1dfFUhHezTp(SBGiVg(4gNaGz`^jF<#AKxPu_|1Auxnw?v>p1YaBz0?hl5{&CILj69#A1~y6z4G>l z33ZE;_IVN3LEeS&Al+%fSo$Q@{luxCfH-9Qxaf-7RlGXe{$=eS%y6^UCi8%K$|6SW zLyEap(C^Te>`1VvRt4C?PujoED)2hcYb-obNRBWwH_cejrAY70md-t)>E14 z2oIwCQo{+$+)D59V~CXUkYy9->H#B@5zNt>mKT-M+e7KSRhwwvHQVxtm>0-~3%E+A zQAtFV`{U4(9+B&#eE;GB1dxua`q8MoDOF`FZ>lwi6Xij2`)36-ICcM1+`#B02whIl zZ^ffDK7@3Zu=&d*uPkuur`gQqFXq*Cojk7zxC^j6`}Dwg8jb|`Ue1H=J`^u1?GD^4 zU8-cf5@P;PbCUF8B;KFLKBJu2c2MT{`c>gk7VQw4j}GuIFD~ZdBZ#_(Q7O&vj|p)~W3@(}aM?JuM?V*R<8ROE*3C;MM=-)D_x&mvB6Fti zM12)$;Y{yP8<~FM)`)w_0mAE8H~N6Z~o zBAdSO0q$1HqF~Y^v3(t3O8ooL6;ys*GKn*3F`h50;#(VNLR`EmtvZ&u+#0Kjy=gQe zvroO1Svp*jvSS4WvCYxxjOJo=0GQtpgiIE6;q8avj?Zpp>s((5c>VEt2Cbjf`i_|n z9t4x(yD$*$q7=nkJSf{rQH^HV+&t3x?nBAde_8yVix&kQT^Jv0{45`_IhnZeg#oE6 z`d=kWAae$X*_eX2VAzg&U?`hW`sOz>%kQl_7Z{<-o_mIFR2}|quCPqcTM;hggWkr+^YOXfL1 zzgL6q9?{{eb@##bbb4&a>>n>9SG;RJVvdbIIa2pe{{nCcrL0{$B5(RRrhta0%T2cb zf9FsBQq?|%!U;}RhmJTtkg zeJJJ*`o?1snn$oZGD%IyZ(GNt>Z=rEl3g{`JQcoI%6z}f1)3o@dP#MgF#?h3N^t(d zRN_42^?y#YNou2`$FPxJoz&@WKQ&Z%5^+z0dl!@Qsgg_rOwBZ*wQ{L4+n=p#4pat) z2fxb?R3luB$X6zEMi{;P;#QmWVo;(HD9@5FYqx20H-=cNM3V8Vsa4Qjrep8K|5b98 z{It{b<9ET%`W#}RsT6q;`HQrgQUC^pNXVpxSn$og+5R~Uxsy$DEzWZ=2Q1hG# z19xb-uTZk(DSA%JQxBzsjBrbKa;+R<1EY@TNHTGWj>$;Z3F?s3p1v&$MxbHR%P%Y8 zRX_f55_V~L&aa5=Ui3`)9EuFV+&?b|RcxS8f~N-8Zohy1cqiW*?v!S_Hp z-&vqW1FG}(0G_7_c^yRIq~BJlJ8Anampy?&h{o zN$r1@&FuAu>B{Y_Kwjm-G`2^LKka0zH0E>!P=}qAxMlT)?+^vx+~u^d?raqf_*2bL z_72Dh{>BMI{uPQ%_Fwh!R*FuW#nyz{E@D9Qs*{ho3ULkFb9oiMkp zgp_uM=2?D5+YTh~tJEBm9$P|IK-KK^b%pOF`jCw^zpJh}HRMEv3KMh6X+pZ9jqa7` z@;nx|+Jfn!s;AwewO9WOCL|4jC;{x*HLUb?4XM%b2A|6YTiuPqmC)5jA4)L~8@}6& zxlWRP=?8k^&waX5YS}f0FIqoYDzIFA#m=)g03-N-wgXI5^DP}bpX4g)-5sQFh9Nh1y zy^b4NeU@VJ$2$uTp{6`)^Y!C_6?*qwdJSIdOmy~D5Oxb5Bk-v+3&EzTBvvEF#IvK2 z5r!gcP~LKPc`%B{%gt!q<}$`>_0`eS%dcWG!rpV?JCA)N@49iv%zo}Nmu9-x#=V;z ze`&CpI@`L*hrFz5=i}L~r^f{6KJC%Q8AD03&`YWG4<)i{o;*`wC;zB`%S~(OlKS=o zl?#4=cf=+4r6>)wk5!N_kSMjxwbH1zk z*1Ew*te0B&IDWS}IXtR_$wVB%E_ngW$fHuZAraaaQo_QVHMb02)wTh>_L|Gb7cVL) zB~Gc|lgVHIDtXBWZdrac2qo!TJ8B;{o)5-9XotoU1mq{AP8`PihyK4jL_X1F2U9U$ z{Cg>MpO34%oCi&zm6kSs8l8+eI2C@A7?JFiLE^l~xW7-`$-L@ib(#iF`d-Cm252<^ zt+J#A;N_e0zsjZGlFY-bXaj$9nu5$c(dQOsr)zoiDwU=~&+&7cl41-|$bS};Iv`=B z+uMLdUFnN2Y0~^)@FoK zb0&SMWZ~-3o=STyE5brU5P~`mPWHaEG(ujo!Hh1b}Y8*{zp8Qc|^Az{S0>;I=aoK%#t6Nj3Ga;q+st> zl;#KKg6})Ld%FneRIb+UY-DHQHrC(j)(smdl~{-kj6he zaN=_a!mfU1B{atGBsh-3KUrT;t}`yFU!)j&un=Zvw`qDAlTnOU6roQe@MlG<^=F8BLL-22CEiNVSuOIVb8-(^|g1U>$-Tb1YWIj2xJxARRjuvX3|ID*&7GG2q-i z&2low7xtO%ny?e=ab4N%p_GCbmL*V>*@uaAJ;P+ z|82$p!C&n=1_ZXcB-JdXat$SKR(zhlmpNr!u2Kw5wmvbfTk&W#J#6u`IL^oLTz|>0 zGi+f2r4;p^JQ4$~ee=I~`{P&qoK2%teQb^6Mz18PHue+;@;i?Dk6f<;(locK$C1mL z9v-(M!1F-@u9F$pzcHwK$y|!@_JuLu^Q51&Jx&e zGGY>HBr!HGN-WcUh^#jiO=AH=eBVaw9JeujHFQs|igPWz85+F$u=L59Jy>3JIft&g z6wsIJOc2yB?T;&4A5A5Efq-S@`qi%>n zLD8mM8J#^_N;YM0xQE2oceCsaAEbV}KJMf;F=0Wb%r zg1j0d4M(I(`?-&wrivMd3FEYvyZA}fkCSz7u? zK*&4H*#iNbA=OAprQS>^|JlkKo~9w!q-ceywG zNS>v2N|1fMbh`1J1>hx{Q%TmzMPgI&bAD!`06!<4hgM^HB$&$zl+nM~lj!#mlSm2=Xze_<=1SPgOFY_KA)}-=Wq>j}}8RvrHcUL-Y8bw(WL8S5iTP z4ztZ~?*!zAHwm(%!fHo@xtEzh8T3@HVyA_cwzGQHVCu~?lE&i`jGRKod#N)Ku~Xg~ zJR%WQHt)u2p+C4kjWrJKli6Yb@_g&={nf)&IjEp-Vd?jVrxz4|b9yfd$PZ%oMw*;8 zCC?Tkrl7XmyUL&n~V^UvQW;3#V``+z#P_n*X>o>ylbZC)*Pqqy=4ESEF<_XCfu zYrlY40m}7ezQ=;f5pRY6p` z>aJg%aUSGFvq1GaYrZb;_|_hMTmGK3ei*=;^9Z*n?3=|mJya>MsP5FM?M=$b4y@k* zZ$DzzqJB&~rgK}#3RPek2$=DBaU#mw9{$O^!ub`$&ul%c#@_OkP`G0)I0J5nuGN?d zQCXK(tF0;SmxAi;d`)qHg8Am6XN1@*7p*ltxpSD-1zd7B2k%(%g@j@Ot|;xr`6ut; z;nJ?2%>L}VslV=Rq6NOHT8b^4lOV|ipzh#IQM7ot!h3ib-296qQ6@*E?0REgk^aXG z{eUumtjoAR<0elb%mhMI%a{4+u$lz$^m1dS<%k4S`V)3(s)i%I;<9Bu53X>*7;Mte z-S^T)8A>*$s|nCOX=MBOn_8Jz@^{0x)@^r80;b__si?=A7L)HMyn(or-cD!wTDN0j;FY}X=r1(WRDo`88jv11kv|ZfAu^C zm=Nv6%nn)xU$S;ZcUo;`-n04&OPyGWk~SSbE^s=bgfkWOWnqnnSfh~&M_9Hz?C$b) z!IWMgoJ?tA)5)R$-7f|>zgHst@V+R5ZL6+l3VG*u-BaCDmwm(I@U_d!>JZ!Nk{*a{ z4vOLQD(o?`PM6nwKXnJM{rB~lSe|hBr6E;=XH`u8-GF2854#Lkk$*ULOYBb5!37bE z&*|2ZTG4sWL4T`$4)H|J{OMu|TIPe&tqvsZsG;2|Gk|1R$}blJlEkb|qVhAWl+v+E zj;9~{6ndI)S3lzkbgIb@-+x%>*j@=FuR{y8IG~--mUeoJM2?bKUE+gFb$2l_KNuf9 z)@2A4Xg}c0-E4miLP-q*a660NpxzoZV!~J_;j@O0=7wrOFsWh8etYMVL zV_3C%WH$o!zaFVZUjJ)zYwJ$Bi~I)8^tF6LuVWx$1)m!b(+roU$a+)tb|$f=Zfi2~ z1xJ_F;K)US(M!Z6k5FI~%F>y<3$D4G0Q9GxI>NHEIn<>_%p8`(=s#pg@g}QDA80T5 zC$bPuaD!SE*+aF$5UV-gQta>eEtwp&8uv8A>30QT?zBsX(ZC>-Ao}@lf(bKRKUtLiaaoMQc6JVIutI}dhhGG&$W4W)(k zq|(!U`9Cw9Zu#**f96USd=DayZ1anJJ`MCoF78MH?_?aafUz6o!Dy z`q9aQfIKZ8@5zFtWAL^ky(M|gG8lnHM}u9MtRZgtAm8=|X!X#9 zBS9|v4<~oEm)4=IJA5iFZ4*1B>Q#Vp0j`v;r*IpWL%cg`D}A%WR{2LVS^;rK5bv9! z#`@KyzLkA*d{>UoGF77=l!dX! z^j}ctU+ap@5WVBn@SVu1&~@jRlNdCocp2>sHJHhI5N%m$;ml(2QU=-~VghGVY3E|R z7`&aOk5uhIj?fcoK(n;qV8o4iLcmSBif>AVOkKZJDde9hVniM1Cr4+fS)yX{uh;vV zFaABTev_eP&>o%N!j^+4qbKCS+$wO|;>Mp1^xzs0LmTO*N|4l1y+Ho#3*Td}*O;kn zE#21W+N=@s(Avn2BIs%I>Uj;I`tZ+30hY+6Wi1i# zSFTyJQyZ06&nbmFfiVx84xqaw3Zm9OUH+cShp6z7Si63C6iAm#A ze0QO6g&gihiLU2!5oan(1(w4zGXd#XN{!jvhC=ih|Mm{Ur-;Ut@=es!X=JZJSbbYu z`K&f6E5O}4`e-1y9?_SfoaIvEWjJ24z!E34T{Hrw(-4KBZQ!&cVgZJrG4Os4+94>N zds60=>|h96u@cBqXR#pj!5O)1nq*dcb6)g0vZtxpuDwTDU}5t%9TQal4h68lz**tO zYd)4O)O{xr*sIFFbHRxp#eoCDPT?W1!{nOYSbyGn87+_S1!SuC2^G05niW3g&!3Bq za8r_}I|!u!KUy*SCi(1OXbG#4z%P+n@G?)Zlv-Y_JoXUm48v*VUJ7JjT!Fv4P&c) zj{6Y_7)Vw+UkoP8o)+?|Xw#7NeTf=#u2<3aD`)G*H@`~I=S$BGz*uY+H8rr29^CS53iH3pwi&$*5ve zr68@E#WDD&BSMVwCs5GBM8vYRQ|y&&{u#EWaXb+73a?1Nis##>mr`*>jcpHyOLsyg z$@iM0kNI%ebigfPPTwCUxU<_SmRHuvn#$rA=T#L=$eFOd{z|s~z}t!D)6y0^KKIk} z*psLj{0sW+PK<4JV?5OIJ8o@TICG2J4t>A2DMU3zigsCj1blOC@n5h}S5wnmkBQL^ zYw4s`ok6MVOc?5fBX-Ig#~=G{Ha&Jrma$vrN7Q{6QDZj&Il&7xa|2BMM{VY2TD00SWdA@J?o+&-fZQuCpC{R)s6E zdp^=yb*9{j6&ddV4QTgpP9=jc<+4Tm84>iJdA?NZ#SEuVldLQGHX ziAfJztcJeffFP+1*sr&C0V-dXFlnBjz4`EUn07+{Zz&`dnnY)){8ppL|7(`V={@_l z=@b6tc{j&^)1b9DT?54(bA>N;RHO)96|54lg$f{y6;hAb?g$%EK& z*$WPV`QDeo>cqEk*#cZ`-@ zH=undn`Nw8o_NQ4RfBuvyz#0Vg9*C!kn~LQyFpB=rtzSJ_$gM9cG}i2=6xu7Pp z*&ar5xU8dl(8O%jG)T|8%x|aDY}zY6`G~Vy>J(1OlfR$m3e?lQy5~R7#b{?5#>RUR zsi{-AALolrMV1J%aaTwluRjgai9KRC!vBl)A=A8?ue+(7 z?J8KUAmS909?5vFxg~z@)GOepW`GYT{p@S#93&D^=JR=9P+an-y~~mln30o=Rl>vR zJ}45^RGRxFgy<$GHKfOie>?6Ag%V*%dOGA;K+hrvs7bk`az{wpU4N1UO%1`ncZM~z z(cfU5nTDT!(+{#c@2J7u6fJz|k0BRHjfQ+z$WctuwssoN)tl97&EjqLk8CI!!Ug2K z2HChZ=+vf*NUl4FE&2=iD%KNwl6`P}V$Y3{SAf}OQx5#BhuDaPi_!`kb1D}C|X|R29ZUh70X!13KFirD> zIJm7)1{SSKSy+x0Uo95;P0~mzvIz0!d^$t5J1633uJ1lm^yctC{;K7jGQ~b(qdpX$ zr1!eJ*(r^&`0s*uG-WA)krk&aJYAx~cbZhelN0W%l+)0IYB=c9ACFzdqyxLv*~dmW zW0>wnmWhO09$7MIWVGm*y5�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 literal 0 HcmV?d00001