From 22f2e4febb7efca947584ffd50d9f17be8a176d6 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Fri, 14 Oct 2022 12:54:08 +1100 Subject: [PATCH 01/31] docker compose --- .gitignore | 3 ++- Dockerfile | 19 +++++-------------- docker-compose.yml | 26 ++++++++++++++++++++++++++ openssl.cnf | 24 ++++++++++++++++++++++++ puml/stackql-docker-compose.puml | 31 +++++++++++++++++++++++++++++++ src/Dockerfile | 13 +++++++++++++ src/README.md | 15 +++++---------- 7 files changed, 106 insertions(+), 25 deletions(-) create mode 100644 docker-compose.yml create mode 100644 openssl.cnf create mode 100644 puml/stackql-docker-compose.puml create mode 100644 src/Dockerfile diff --git a/.gitignore b/.gitignore index 93c1590..c2c5625 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ src/.stackql src/bin/* -src/creds +src/creds/* .stackql/* +creds/* # Logs logs diff --git a/Dockerfile b/Dockerfile index 8c303e6..a9d16aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,8 @@ FROM stackql/stackql:latest +EXPOSE 5444 +WORKDIR /app +USER stackql +RUN deno cache app.ts +CMD ["run", "--allow-env", "--allow-net", "--allow-read", "--unsafely-ignore-certificate-errors=localhost", "app.ts"] -WORKDIR /work -USER root -RUN apt-get update && \ - apt-get upgrade -y && \ - apt-get install -y wget && \ - apt-get install -y unzip -RUN wget --no-verbose https://github.com/denoland/deno/releases/download/v1.26.0/deno-x86_64-unknown-linux-gnu.zip && \ - unzip deno-x86_64-unknown-linux-gnu.zip && \ - mv deno /bin/deno && \ - chmod +x /bin/deno && \ - rm deno-x86_64-unknown-linux-gnu.zip - -# download stackql providers -RUN stackql exec 'registry pull aws v0.1.3' \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b663c44 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,26 @@ +version: "3.9" +services: + playground: + image: stackql/stackql-playground:latest + environment: + MIDDLEWARE_SCHEME: 'http' + MIDDLEWARE_HOST: 'api' + MIDDLEWARE_PORT: '8080' + ports: + - 3000:3000 + api: + build: src/ + environment: + DB_HOST: 'runner' + DB_PORT: 5444 + DB_DEBUG: false + ports: + - 8080:8080 + # runner: + # build: . + # environment: + # PGSSLSRVKEY: 'true' + # PGSSLROOTCERT: 'true' + # CLIENT_CERT: 'true' + cache: + image: redis:alpine \ No newline at end of file diff --git a/openssl.cnf b/openssl.cnf new file mode 100644 index 0000000..9b6f424 --- /dev/null +++ b/openssl.cnf @@ -0,0 +1,24 @@ +[ req ] +default_bits = 4096 +default_md = sha256 +prompt = no +encrypt_key = no +distinguished_name = pg_server +# stackql_ca +[ pg_ca ] +countryName = "AU" # C= +stateOrProvinceName = "VIC" # ST= +localityName = "Melbourne" # L= +organizationName = "StackQL" # O= +organizationalUnitName = "Core Functions" # OU= +commonName = "pg_ca" # CN= +emailAddress = "krimmer@stackql.io" # CN/emailAddress= +# stackql_server +[ pg_server ] +countryName = "AU" # C= +stateOrProvinceName = "VIC" # ST= +localityName = "Melbourne" # L= +organizationName = "StackQL" # O= +organizationalUnitName = "Core Functions" # OU= +commonName = "127.0.0.1" # CN= +emailAddress = "krimmer@stackql.io" # CN/emailAddress= \ No newline at end of file diff --git a/puml/stackql-docker-compose.puml b/puml/stackql-docker-compose.puml new file mode 100644 index 0000000..219e51a --- /dev/null +++ b/puml/stackql-docker-compose.puml @@ -0,0 +1,31 @@ +@startuml +!includeurl https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml + +!define Rel_NoRank(e_from,e_to, e_label=" ") Rel_(e_from,e_to, e_label, "-[norank]->") + +title StackQL Docker Compose Architecture + +Person(user, "User") + +System_Boundary(middleware, "stackql Middleware") { + Container(playground, "playground", "React/NextJS App") + Container(api, "api", "deno Oak") + Container(runner, "runner", "stackql srv") + ContainerDb(cache, "cache", "Redis") +} + +Container_Ext(beapi, "API Provider", "Backend API") + +Lay_R(user, playground) +Lay_D(playground, api) +Lay_R(playground, runner) +Lay_D(runner, cache) + +Rel_R(user, playground, "localhost:3000") +Rel_R(user, api, "localhost:8080") +Rel_D(playground, api, "localhost:8080") +Rel_R(api, runner, "runner:5444") +Rel_R(runner, beapi, ":443") +Rel_D(api, cache, "cache:6379") + +@enduml \ No newline at end of file diff --git a/src/Dockerfile b/src/Dockerfile new file mode 100644 index 0000000..4053dfd --- /dev/null +++ b/src/Dockerfile @@ -0,0 +1,13 @@ +FROM denoland/deno:latest +EXPOSE 8080 +WORKDIR /app +USER deno +# Cache the dependencies as a layer (the following two steps are re-run only when deps.ts is modified). +# Ideally cache deps.ts will download and compile _all_ external files used in main.ts. +# COPY deps.ts . +# RUN deno cache deps.ts +# These steps will be re-run upon each file change in your working directory: +ADD . . +# Compile the main app so that it doesn't need to be compiled each startup/entry. +RUN deno cache app.ts +CMD ["run", "--allow-env", "--allow-net", "--allow-read", "--unsafely-ignore-certificate-errors=localhost", "app.ts"] diff --git a/src/README.md b/src/README.md index 224411b..361a7e7 100644 --- a/src/README.md +++ b/src/README.md @@ -1,10 +1,8 @@ -Make sure you are in the same directory as this README file: ## 1. generate keys -- Move your openssl.cnf file into creds directory + ``` openssl req -x509 -keyout creds/server_key.pem -out creds/server_cert.pem -config creds/openssl.cnf -days 365 openssl req -x509 -keyout creds/client_key.pem -out creds/client_cert.pem -config creds/openssl.cnf -days 365 -chmod 400 creds/client_key.pem ``` ## 2. set env vars @@ -45,15 +43,12 @@ bin/stackql srv --auth="${AUTH}" \ --pgsrv.port=$PGPORT \ --pgsrv.tls='{ "keyFilePath": "'${PGSSLSRVKEY}'", "certFilePath": "'${PGSSLROOTCERT}'", "clientCAs": [ "'${CLIENT_CERT}'" ] }' ``` -### GitHub example -``` +### GitHub export AUTH='{ "github": { "type": "basic", "credentialsenvvar": "GITHUB_CREDS" } }' -stackql srv --auth=$AUTH\ ---pgsrv.address=0.0.0.0 \ ---pgsrv.port=$PGPORT \ ---pgsrv.tls='{ "keyFilePath": "'${PGSSLSRVKEY}'", "certFilePath": "'${PGSSLROOTCERT}'", "clientCAs": [ "'${CLIENT_CERT}'" ] }' -``` + ## 4. start middleware server +change directory into `./src` + ``` # deno run --allow-env --allow-net --allow-read --unsafely-ignore-certificate-errors=localhost app.ts deno run --allow-env --allow-net --allow-read app.ts From 9690022778ad9e7f07931ea28254b4d4236f0fba Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Fri, 14 Oct 2022 13:50:01 +1100 Subject: [PATCH 02/31] docker compose updates --- docker-compose.yml | 2 +- src/db/db.ts | 40 +++++++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b663c44..931c5ad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,7 @@ services: environment: DB_HOST: 'runner' DB_PORT: 5444 - DB_DEBUG: false + DB_DEBUG: 'false' ports: - 8080:8080 # runner: diff --git a/src/db/db.ts b/src/db/db.ts index 7e265a3..982d8ef 100644 --- a/src/db/db.ts +++ b/src/db/db.ts @@ -5,24 +5,30 @@ const DB_HOST = env.DB_HOST || 'localhost' const DB_PORT = env.DB_PORT || 5444 const DB_DEBUG = env.DB_DEBUG || true -const sslrootcert = await Deno.readTextFile('./creds/server_cert.pem'); -const key = await Deno.readTextFile('./creds/client_key.pem'); -const cert = await Deno.readTextFile('./creds/client_cert.pem'); +// const sslrootcert = await Deno.readTextFile('./creds/server_cert.pem'); +// const key = await Deno.readTextFile('./creds/client_key.pem'); +// const cert = await Deno.readTextFile('./creds/client_cert.pem'); export const connect = async () => { - const conn = await pgconnect({ - hostname: DB_HOST, - port: DB_PORT, - _debug: DB_DEBUG, - application_name: 'stackql', - // sslmode: 'require', - // sslrootcert: sslrootcert, - // ssl: { - // ca: sslrootcert.replace(/\n|\r/g, ''), - // key: key.replace(/\n|\r/g, ''), - // cert: cert.replace(/\n|\r/g, ''), - // }, - }); - return conn; + try { + const conn = await pgconnect({ + hostname: DB_HOST, + port: DB_PORT, + _debug: DB_DEBUG, + application_name: 'stackql', + // sslmode: 'require', + // sslrootcert: sslrootcert, + // ssl: { + // ca: sslrootcert.replace(/\n|\r/g, ''), + // key: key.replace(/\n|\r/g, ''), + // cert: cert.replace(/\n|\r/g, ''), + // }, + }); + return conn; + + } catch (error) { + console.log(`Failed to connect to stackql server`); + throw error; + } } \ No newline at end of file From 11693602afbba159431f38fbe3525181f92aa632 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Fri, 14 Oct 2022 18:07:10 +1100 Subject: [PATCH 03/31] docker compose updates --- Dockerfile | 13 +++++++++---- docker-compose.yml | 41 ++++++++++++++++++++++++++++++++++------- src/db/db.ts | 4 ++-- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index a9d16aa..c2be284 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,13 @@ FROM stackql/stackql:latest EXPOSE 5444 WORKDIR /app +RUN adduser --system --uid 1001 stackql +RUN addgroup --system --gid 1001 stackql USER stackql -RUN deno cache app.ts -CMD ["run", "--allow-env", "--allow-net", "--allow-read", "--unsafely-ignore-certificate-errors=localhost", "app.ts"] - - +RUN stackql exec 'registry pull aws v0.1.3' +RUN stackql exec 'registry pull azure v0.3.0' +RUN stackql exec 'registry pull google v1.0.4' +RUN stackql exec 'registry pull github v0.3.6' +RUN stackql exec 'registry pull k8s v0.1.1' +RUN stackql exec 'registry pull netlify v0.2.0' +RUN stackql exec 'registry pull okta v0.1.0' \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 931c5ad..b6bbc02 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,16 @@ version: "3.9" services: + # credentialsgen: + # image: alpine/openssl + # volumes: + # - ./vol/srv/credentials:/srv:rw + # command: + # - bash + # - -c + # - | + # wget https://raw.githubusercontent.com/stackql/stackql/main/test/server/mtls/openssl.cnf /srv/openssl.cnf && \ + # openssl req -x509 -keyout /srv/pg_server_key.pem -out /srv/pg_server_cert.pem -config /srv/openssl.cnf -days 365 && \ + # openssl req -x509 -keyout /srv/pg_client_key.pem -out /srv/pg_client_cert.pem -config /srv/openssl.cnf -days 365 playground: image: stackql/stackql-playground:latest environment: @@ -8,19 +19,35 @@ services: MIDDLEWARE_PORT: '8080' ports: - 3000:3000 + runner: + # image: stackql/stackql + build: . + # volumes: + # - ./vol/srv/credentials:/srv:ro + # environment: + # PGSSLSRVKEY: 'true' + # PGSSLROOTCERT: 'true' + # CLIENT_CERT: 'true' + # depends_on: + # - credentialsgen + #command: [ "stackql", "--pgsrv.port=5444", "srv" ] + command: + - /bin/sh + - -c + - | + stackql --version && \ + stackql --pgsrv.loglevel=DEBUG srv api: build: src/ + # volumes: + # - ./vol/srv/credentials:/srv:ro environment: DB_HOST: 'runner' - DB_PORT: 5444 + DB_PORT: 5466 DB_DEBUG: 'false' ports: - 8080:8080 - # runner: - # build: . - # environment: - # PGSSLSRVKEY: 'true' - # PGSSLROOTCERT: 'true' - # CLIENT_CERT: 'true' + # depends_on: + # - runner cache: image: redis:alpine \ No newline at end of file diff --git a/src/db/db.ts b/src/db/db.ts index 982d8ef..f715868 100644 --- a/src/db/db.ts +++ b/src/db/db.ts @@ -3,7 +3,7 @@ import { pgconnect } from 'https://raw.githubusercontent.com/kagis/pgwire/main/m const env = Deno.env.toObject() const DB_HOST = env.DB_HOST || 'localhost' const DB_PORT = env.DB_PORT || 5444 -const DB_DEBUG = env.DB_DEBUG || true +const DB_DEBUG = env.DB_DEBUG || false // const sslrootcert = await Deno.readTextFile('./creds/server_cert.pem'); // const key = await Deno.readTextFile('./creds/client_key.pem'); @@ -28,7 +28,7 @@ export const connect = async () => { return conn; } catch (error) { - console.log(`Failed to connect to stackql server`); + console.log(`Failed to connect to stackql server at ${DB_HOST}:${DB_PORT}`); throw error; } } \ No newline at end of file From f37b2b3d7371c12ec3a8404a2792019940443936 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 08:50:47 +1100 Subject: [PATCH 04/31] updated Dockerfile and compose --- Dockerfile | 4 +++- docker-compose.yml | 14 +++++++++----- src/db/db.ts | 6 ++++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index c2be284..d93de8c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,10 @@ FROM stackql/stackql:latest EXPOSE 5444 -WORKDIR /app +WORKDIR /home/stackql RUN adduser --system --uid 1001 stackql RUN addgroup --system --gid 1001 stackql +RUN chown stackql:stackql /home/stackql +RUN chown stackql:stackql /srv USER stackql RUN stackql exec 'registry pull aws v0.1.3' RUN stackql exec 'registry pull azure v0.3.0' diff --git a/docker-compose.yml b/docker-compose.yml index b6bbc02..44c8547 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,8 +20,11 @@ services: ports: - 3000:3000 runner: - # image: stackql/stackql - build: . + build: + context: . + cache_from: + - stackql/stackql + working_dir: /home/stackql # volumes: # - ./vol/srv/credentials:/srv:ro # environment: @@ -30,20 +33,21 @@ services: # CLIENT_CERT: 'true' # depends_on: # - credentialsgen - #command: [ "stackql", "--pgsrv.port=5444", "srv" ] + expose: + - 5444 command: - /bin/sh - -c - | stackql --version && \ - stackql --pgsrv.loglevel=DEBUG srv + stackql --pgsrv.port=5444 srv api: build: src/ # volumes: # - ./vol/srv/credentials:/srv:ro environment: DB_HOST: 'runner' - DB_PORT: 5466 + DB_PORT: 5444 DB_DEBUG: 'false' ports: - 8080:8080 diff --git a/src/db/db.ts b/src/db/db.ts index f715868..663309d 100644 --- a/src/db/db.ts +++ b/src/db/db.ts @@ -1,8 +1,9 @@ -import { pgconnect } from 'https://raw.githubusercontent.com/kagis/pgwire/main/mod.js'; +import { pgconnect } from 'https://raw.githubusercontent.com/kagis/pgwire/v0.7.0/mod.js'; const env = Deno.env.toObject() const DB_HOST = env.DB_HOST || 'localhost' -const DB_PORT = env.DB_PORT || 5444 +//const DB_PORT = env.DB_PORT || 5444 +const DB_PORT = 5444 const DB_DEBUG = env.DB_DEBUG || false // const sslrootcert = await Deno.readTextFile('./creds/server_cert.pem'); @@ -16,6 +17,7 @@ export const connect = async () => { hostname: DB_HOST, port: DB_PORT, _debug: DB_DEBUG, + //_debug: true, application_name: 'stackql', // sslmode: 'require', // sslrootcert: sslrootcert, From 8c2be82456655ff87f5ba36f467b57521a649a35 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 10:42:24 +1100 Subject: [PATCH 05/31] updated pg lib --- .gitignore | 1 + .stackql/readline/readline.tmp | 10 +++++++ docker-compose.yml | 4 ++- src/README.md | 8 +++-- src/db/db.ts | 36 ---------------------- src/shared/data.ts | 55 ++++++++++++++++++++++++---------- 6 files changed, 60 insertions(+), 54 deletions(-) delete mode 100644 src/db/db.ts diff --git a/.gitignore b/.gitignore index c2c5625..a8fce5d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ src/bin/* src/creds/* .stackql/* creds/* +stackql # Logs logs diff --git a/.stackql/readline/readline.tmp b/.stackql/readline/readline.tmp index 282fa5d..917dee7 100644 --- a/.stackql/readline/readline.tmp +++ b/.stackql/readline/readline.tmp @@ -1 +1,11 @@ registry list aws; +show services in github like 'repo%'; +registry list ; +registry pull github v0.3.6; +show services in github like 'repo%'; +show reosurces in github.repos; +show resources in github.repos; +show resources in github.repos like 'repo%'; +describe github.repos.repos; +show methods in github.repos.repos; +select id, name from github.repos.repos where org = 'stackql'; diff --git a/docker-compose.yml b/docker-compose.yml index 44c8547..7c49be0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -35,12 +35,14 @@ services: # - credentialsgen expose: - 5444 + environment: + - GITHUB_CREDS=${GITHUB_CREDS} command: - /bin/sh - -c - | stackql --version && \ - stackql --pgsrv.port=5444 srv + stackql --auth="${AUTH_STR}" --pgsrv.port=5444 srv api: build: src/ # volumes: diff --git a/src/README.md b/src/README.md index 361a7e7..bdddda3 100644 --- a/src/README.md +++ b/src/README.md @@ -25,9 +25,11 @@ export CLIENT_CERT=$(base64 -b 0 creds/client_cert.pem) ## 3a. start stackql sever with no auth ``` -bin/stackql srv \ +./stackql srv \ --pgsrv.address=0.0.0.0 \ ---pgsrv.port=$PGPORT \ +--pgsrv.port=5444 + +\ --pgsrv.tls='{ "keyFilePath": "'${PGSSLSRVKEY}'", "certFilePath": "'${PGSSLROOTCERT}'", "clientCAs": [ "'${CLIENT_CERT}'" ] }' ``` @@ -54,3 +56,5 @@ change directory into `./src` deno run --allow-env --allow-net --allow-read app.ts ``` +/home/javen/.deno/bin/deno run --allow-env --allow-net --allow-read ./app.ts + diff --git a/src/db/db.ts b/src/db/db.ts deleted file mode 100644 index 663309d..0000000 --- a/src/db/db.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { pgconnect } from 'https://raw.githubusercontent.com/kagis/pgwire/v0.7.0/mod.js'; - -const env = Deno.env.toObject() -const DB_HOST = env.DB_HOST || 'localhost' -//const DB_PORT = env.DB_PORT || 5444 -const DB_PORT = 5444 -const DB_DEBUG = env.DB_DEBUG || false - -// const sslrootcert = await Deno.readTextFile('./creds/server_cert.pem'); -// const key = await Deno.readTextFile('./creds/client_key.pem'); -// const cert = await Deno.readTextFile('./creds/client_cert.pem'); - -export const connect = async () => { - - try { - const conn = await pgconnect({ - hostname: DB_HOST, - port: DB_PORT, - _debug: DB_DEBUG, - //_debug: true, - application_name: 'stackql', - // sslmode: 'require', - // sslrootcert: sslrootcert, - // ssl: { - // ca: sslrootcert.replace(/\n|\r/g, ''), - // key: key.replace(/\n|\r/g, ''), - // cert: cert.replace(/\n|\r/g, ''), - // }, - }); - return conn; - - } catch (error) { - console.log(`Failed to connect to stackql server at ${DB_HOST}:${DB_PORT}`); - throw error; - } -} \ No newline at end of file diff --git a/src/shared/data.ts b/src/shared/data.ts index cabede9..45983a9 100644 --- a/src/shared/data.ts +++ b/src/shared/data.ts @@ -1,6 +1,28 @@ import { generateTypes } from "https://deno.land/x/dts/mod.ts"; +import { Client } from "https://deno.land/x/postgres@v0.16.1/mod.ts"; // import * as logger from "./../shared/logger.ts"; -import * as stackql from "../db/db.ts"; + +// get stackql srv env vars and initiate connection + +const env = Deno.env.toObject() +const DB_HOST = env.DB_HOST || 'localhost' +const DB_PORT = parseInt(env.DB_PORT) || 5444 + +const client = new Client({ + applicationName: 'stackql', + hostname: DB_HOST, + port: DB_PORT, + database: 'stackql', + user: 'stackql', +}); + +try { + console.log(`connecting to stackql server : ${DB_HOST}:${DB_PORT}`); + await client.connect(); +} catch (error) { + console.log(`Error connecting to stackql server ${DB_HOST}:${DB_PORT} : ${error.message}`); + throw error; +} function reType(input: any): any { try { @@ -57,26 +79,29 @@ async function getData(iqlQuery: string, showMetadata: boolean): Promise< { resp } // connect, run query and get results - const stackqlConn = await stackql.connect(); - const iqlResult = await stackqlConn.query(iqlQuery); + //const stackqlConn = await stackql.connect(); + //const data = await stackqlConn.queryObject(iqlQuery); + + const data = await client.queryObject(iqlQuery); // parse results - const data = await parseIqlResults(iqlResult, true); + // const data = await parseIqlResults(iqlResult, true); if (showMetadata){ - metadata.result['rowCount'] = data.length; - metadata.operation['status'] = iqlResult.status; + metadata.result['rowCount'] = data.rows.length; + metadata.operation['status'] = 'OK'; metadata.operation['endTime'] = new Date().toISOString(); metadata.operation['duration'] = `${performance.now() - t0} ms`; } let respData = { - data: data, + data: data.rows, metadata : showMetadata ? metadata : null } - stackqlConn.end(); - stackqlConn.destroy(); + //await stackqlConn.end(); + // stackqlConn.destroy(); + //await client.end(); return { respStatus: 200, respType: 'application/json', respBody: `${JSON.stringify(respData)}\n` }; } catch (error) { @@ -93,17 +118,17 @@ async function getTypes(iqlQuery: string): Promise< { respStatus: number; respTy try { // connect, run query and get results - const stackqlConn = await stackql.connect(); - const iqlResult = await stackqlConn.query(iqlQuery); + const stackqlConn = await client.connect(); + const data = await stackqlConn.queryObject(iqlQuery); // parse results - const data = await parseIqlResults(iqlResult, false); + // const data = await parseIqlResults(iqlResult, false); // get types - const result = await generateTypes(data[0]); + const result = await generateTypes(data.rows[0]); - stackqlConn.end(); - stackqlConn.destroy(); + await stackqlConn.end(); + // stackqlConn.destroy(); return { respStatus: 200, respType: 'application/text', respBody: result }; } catch (error) { From 7b203488f35387b8d45481e4ae6a573642d01a23 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 10:50:28 +1100 Subject: [PATCH 06/31] minor updates --- src/README.md | 11 +++-------- src/shared/data.ts | 48 ++++++---------------------------------------- 2 files changed, 9 insertions(+), 50 deletions(-) diff --git a/src/README.md b/src/README.md index bdddda3..0c880f6 100644 --- a/src/README.md +++ b/src/README.md @@ -25,11 +25,9 @@ export CLIENT_CERT=$(base64 -b 0 creds/client_cert.pem) ## 3a. start stackql sever with no auth ``` -./stackql srv \ +stackql srv \ --pgsrv.address=0.0.0.0 \ ---pgsrv.port=5444 - -\ +--pgsrv.port=5444 \ --pgsrv.tls='{ "keyFilePath": "'${PGSSLSRVKEY}'", "certFilePath": "'${PGSSLROOTCERT}'", "clientCAs": [ "'${CLIENT_CERT}'" ] }' ``` @@ -54,7 +52,4 @@ change directory into `./src` ``` # deno run --allow-env --allow-net --allow-read --unsafely-ignore-certificate-errors=localhost app.ts deno run --allow-env --allow-net --allow-read app.ts -``` - -/home/javen/.deno/bin/deno run --allow-env --allow-net --allow-read ./app.ts - +``` \ No newline at end of file diff --git a/src/shared/data.ts b/src/shared/data.ts index 45983a9..4f7332f 100644 --- a/src/shared/data.ts +++ b/src/shared/data.ts @@ -2,7 +2,9 @@ import { generateTypes } from "https://deno.land/x/dts/mod.ts"; import { Client } from "https://deno.land/x/postgres@v0.16.1/mod.ts"; // import * as logger from "./../shared/logger.ts"; -// get stackql srv env vars and initiate connection +/* +* get stackql srv env vars and initiate connection +*/ const env = Deno.env.toObject() const DB_HOST = env.DB_HOST || 'localhost' @@ -34,29 +36,6 @@ function reType(input: any): any { } } -async function parseIqlResults(iqlResult: any, allRows: boolean): Promise< any[] > { - - const cols : string[] = []; - for (const column of iqlResult.columns) { - cols.push(column.name); - } - - const rows : any[] = []; - for (const sub of iqlResult.results) { - for (const row of sub.rows) { - const rowobj : any = {}; - for (let i = 0; i < row.length; i++) { - rowobj[cols[i]] = reType(row[i]); - } - rows.push(rowobj); - if (!allRows) { - break; - } - } - } - return rows; -} - async function getData(iqlQuery: string, showMetadata: boolean): Promise< { respStatus: number; respType: string; respBody: string; } > { // run query @@ -79,14 +58,8 @@ async function getData(iqlQuery: string, showMetadata: boolean): Promise< { resp } // connect, run query and get results - //const stackqlConn = await stackql.connect(); - //const data = await stackqlConn.queryObject(iqlQuery); - const data = await client.queryObject(iqlQuery); - // parse results - // const data = await parseIqlResults(iqlResult, true); - if (showMetadata){ metadata.result['rowCount'] = data.rows.length; metadata.operation['status'] = 'OK'; @@ -99,11 +72,8 @@ async function getData(iqlQuery: string, showMetadata: boolean): Promise< { resp metadata : showMetadata ? metadata : null } - //await stackqlConn.end(); - // stackqlConn.destroy(); - //await client.end(); - return { respStatus: 200, respType: 'application/json', respBody: `${JSON.stringify(respData)}\n` }; + } catch (error) { const errResp = { error: error.message.replace(/\n/g, ""), @@ -118,19 +88,13 @@ async function getTypes(iqlQuery: string): Promise< { respStatus: number; respTy try { // connect, run query and get results - const stackqlConn = await client.connect(); - const data = await stackqlConn.queryObject(iqlQuery); - - // parse results - // const data = await parseIqlResults(iqlResult, false); + const data = await client.queryObject(iqlQuery); // get types const result = await generateTypes(data.rows[0]); - await stackqlConn.end(); - // stackqlConn.destroy(); - return { respStatus: 200, respType: 'application/text', respBody: result }; + } catch (error) { const errResp = { error: error.message.replace(/\n/g, ""), From 6cb7c4e5c15eb645f93d4e47933cc03556c2c95a Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 11:09:57 +1100 Subject: [PATCH 07/31] updated gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a8fce5d..5d84ede 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ src/creds/* .stackql/* creds/* stackql +*.tmp # Logs logs From fcb3f9e238de12ed1b6cc851b4ed3eb3bd158f3e Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 12:22:11 +1100 Subject: [PATCH 08/31] demo docs --- README.md | 2 +- quickstart.md | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 quickstart.md diff --git a/README.md b/README.md index 9090368..64b69ae 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ If there are errors in the execution of a query, a response similar to the follo ## Quickstart -Here is a quick start guide to get you up and running with the StackQL middleware server. +Here is a [quick start guide](quickstart.md) to get you up and running with the StackQL middleware server. ## Generating a Provider diff --git a/quickstart.md b/quickstart.md new file mode 100644 index 0000000..3706bd5 --- /dev/null +++ b/quickstart.md @@ -0,0 +1,32 @@ +# StackQL Middleware Quickstart + +Use the [docker-compose.yml](docker-compose.yml) file included with this repository to get up and running quickly with the following architecture: + +
+StackQL Middleware Docker Compose Environment +
+ +The quickstart includes the following components: + +- [StackQL Server]() +- [StackQL Playground]() +- [StackQL Middleware Server]() + +## Providers + +Using this quickstart example you can connect to and query any of the following StackQL public cloud/SaaS providers available from the [`stackql-provider-registry`](https://github.com/stackql/stackql-provider-registry): + +- [AWS]() +- [Microsoft Azure]() +- [Google Cloud Platform]() +- [Kubernetes]() +- [GitHub]() +- [Okta]() +- [Netlify]() + +## Steps + +1. Populate Environment Variables for Provider Authentication +2. Start Environment +3. Use the Playground +4. Use the Middleware API \ No newline at end of file From 6cb5b3a0df15c50fbf86ce0a059297936182d741 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 12:27:49 +1100 Subject: [PATCH 09/31] demo docs --- quickstart.md | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/quickstart.md b/quickstart.md index 3706bd5..e682510 100644 --- a/quickstart.md +++ b/quickstart.md @@ -3,30 +3,49 @@ Use the [docker-compose.yml](docker-compose.yml) file included with this repository to get up and running quickly with the following architecture:
-StackQL Middleware Docker Compose Environment +StackQL Middleware Docker Compose Environment
The quickstart includes the following components: -- [StackQL Server]() -- [StackQL Playground]() -- [StackQL Middleware Server]() +- [StackQL Server](https://github.com/stackql/stackql) +- [StackQL Playground](https://github.com/stackql/stackql-playground) +- [StackQL Middleware Server](README.md) ## Providers Using this quickstart example you can connect to and query any of the following StackQL public cloud/SaaS providers available from the [`stackql-provider-registry`](https://github.com/stackql/stackql-provider-registry): -- [AWS]() -- [Microsoft Azure]() -- [Google Cloud Platform]() -- [Kubernetes]() -- [GitHub]() -- [Okta]() -- [Netlify]() +- [AWS](https://registry.stackql.io/providers/aws/) +- [Microsoft Azure](https://registry.stackql.io/providers/azure/) +- [Google Cloud Platform](https://registry.stackql.io/providers/google/) +- [Kubernetes](https://registry.stackql.io/providers/k8s/) +- [GitHub](https://registry.stackql.io/providers/github/) +- [Okta](https://registry.stackql.io/providers/okta/) +- [Netlify](https://registry.stackql.io/providers/netlify/) ## Steps -1. Populate Environment Variables for Provider Authentication -2. Start Environment -3. Use the Playground -4. Use the Middleware API \ No newline at end of file +1. __Populate Environment Variables for Provider Authentication__ + +something + +2. __Start Environment__ + +something + +3. __Use the Playground__ + +something + +4. __Use the Middleware API__ + +something + +5. __Stop the Environment__ + +something + +6. __Remove Containers__ + +something \ No newline at end of file From 957da56706a1c83c7903355a95e5e9755271ce96 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 12:28:38 +1100 Subject: [PATCH 10/31] demo docs --- quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstart.md b/quickstart.md index e682510..903d1c2 100644 --- a/quickstart.md +++ b/quickstart.md @@ -3,7 +3,7 @@ Use the [docker-compose.yml](docker-compose.yml) file included with this repository to get up and running quickly with the following architecture:
-StackQL Middleware Docker Compose Environment +StackQL Middleware Docker Compose Environment
The quickstart includes the following components: From a79a8e3ad58978162c52c0950eae64a56441bbc3 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 12:29:34 +1100 Subject: [PATCH 11/31] demo docs --- quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstart.md b/quickstart.md index 903d1c2..9ab88d8 100644 --- a/quickstart.md +++ b/quickstart.md @@ -10,7 +10,7 @@ The quickstart includes the following components: - [StackQL Server](https://github.com/stackql/stackql) - [StackQL Playground](https://github.com/stackql/stackql-playground) -- [StackQL Middleware Server](README.md) +- [StackQL Middleware Server](./README.md) ## Providers From d2be4be7cb94f0f7d2c1eb2b89ffa76f3fac0e0e Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 12:34:12 +1100 Subject: [PATCH 12/31] demo docs --- quickstart.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/quickstart.md b/quickstart.md index 9ab88d8..34d85c8 100644 --- a/quickstart.md +++ b/quickstart.md @@ -26,13 +26,19 @@ Using this quickstart example you can connect to and query any of the following ## Steps +This quick start uses [docker compose v2](https://docs.docker.com/compose/). + 1. __Populate Environment Variables for Provider Authentication__ something 2. __Start Environment__ -something +Run the following command in the same environment you used in Step 1 to populate yor environment variables: + +```bash +docker compose up --build +``` 3. __Use the Playground__ @@ -44,8 +50,12 @@ something 5. __Stop the Environment__ -something +Use `ctrl-c` to stop the environment. 6. __Remove Containers__ -something \ No newline at end of file +Run the following command to remove the containers created in Step 2: + +```bash +docker compose down +``` \ No newline at end of file From 7ab78772a7e06f6c1d93b412114ec405ac015791 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 13:57:08 +1100 Subject: [PATCH 13/31] demo docs --- README.md | 2 +- docs/images/playground-query.png | Bin 0 -> 132567 bytes docs/images/playground-types.png | Bin 0 -> 65547 bytes quickstart.md => docs/quickstart.md | 18 +++++++++++++++--- 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 docs/images/playground-query.png create mode 100644 docs/images/playground-types.png rename quickstart.md => docs/quickstart.md (70%) diff --git a/README.md b/README.md index 64b69ae..24cd0e2 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ If there are errors in the execution of a query, a response similar to the follo ## Quickstart -Here is a [quick start guide](quickstart.md) to get you up and running with the StackQL middleware server. +Here is a [quick start guide](docs/quickstart.md) to get you up and running with the StackQL middleware server. ## Generating a Provider diff --git a/docs/images/playground-query.png b/docs/images/playground-query.png new file mode 100644 index 0000000000000000000000000000000000000000..d4a1039b6a765a40c8afcd7bada28fdeb0c91e88 GIT binary patch literal 132567 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

BMy<0*sFsIKayG{ro_buUJa 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 literal 0 HcmV?d00001 diff --git a/docs/images/playground-types.png b/docs/images/playground-types.png new file mode 100644 index 0000000000000000000000000000000000000000..7da6ca5f6f9b54068dabdbca5835620c52e56915 GIT binary patch literal 65547 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 StackQL Middleware Docker Compose Environment @@ -10,7 +10,7 @@ The quickstart includes the following components: - [StackQL Server](https://github.com/stackql/stackql) - [StackQL Playground](https://github.com/stackql/stackql-playground) -- [StackQL Middleware Server](./README.md) +- [StackQL Middleware Server](../README.md) ## Providers @@ -42,7 +42,19 @@ docker compose up --build 3. __Use the Playground__ -something +Use the Playground __Explorer__ pane to discover and describe available service and resources. + +Enter a StackQL query in the __Query__ pane, then.. + +Use the __*Run Query*__ button to run the query and see the results in the __Results__ pane; and/or + +[![StackQL Playground Query](playground-query.png)](playground-query.png) + +Use the __*Get Types*__ button to get the TypeScript types for the result set. + +[![StackQL Playground Types](playground-types.png)](playground-types.png) + +Use the query and the types in your application. 4. __Use the Middleware API__ From beaf1620270ce9ac88f58b7a0c07096ee7d0f6d8 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 13:58:19 +1100 Subject: [PATCH 14/31] demo docs --- docs/quickstart.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/quickstart.md b/docs/quickstart.md index d2e0426..745db84 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -48,11 +48,11 @@ Enter a StackQL query in the __Query__ pane, then.. Use the __*Run Query*__ button to run the query and see the results in the __Results__ pane; and/or -[![StackQL Playground Query](playground-query.png)](playground-query.png) +[![StackQL Playground Query](images/playground-query.png)](images/playground-query.png) Use the __*Get Types*__ button to get the TypeScript types for the result set. -[![StackQL Playground Types](playground-types.png)](playground-types.png) +[![StackQL Playground Types](images/playground-types.png)](images/playground-types.png) Use the query and the types in your application. From 5d5dfa5bd2ba0687382d316f96303669be8c45f9 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 15:17:45 +1100 Subject: [PATCH 15/31] doc updates --- docs/images/stackql-postman-meta-queries.png | Bin 0 -> 103999 bytes docs/images/stackql-postman-queries.png | Bin 0 -> 110015 bytes docs/quickstart.md | 34 +++++++++++++++++-- src/controllers/query.ts | 8 ++++- 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 docs/images/stackql-postman-meta-queries.png create mode 100644 docs/images/stackql-postman-queries.png diff --git a/docs/images/stackql-postman-meta-queries.png b/docs/images/stackql-postman-meta-queries.png new file mode 100644 index 0000000000000000000000000000000000000000..7169463489b18269eb3f4ecb608bc28c1452d0f8 GIT binary patch literal 103999 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�SJCG)E5(9ZP;IZfbk=d7UHM!Ox!3fo~rUpLvJN zTP7sWwzIk;%8{Wi7DsB8r51!UI|jc9pX~fW>WzsVGRU7fy*uuZ*u!x;D!luN-}iff z@=!^uaeS;KX^{}VV#x>|Vw=!buODHbzZ^%Ks-9-tnwIjEz=5tq1_{|_gOd`2KBS6j z55|<)#8@B{>iYEaNl<Wz6hAT|8dm_XG7MMJ zyWs>gTzF@AtMv<9Kzp$gZj`wlO4*{ovsg1wEi3b#SG;6rArb;NETHbejDAR-O{Q;IjI>Yjp7fXdzvJD9nzw2lk z=7uu?&P1#fN)GW@Sy6CWltscy>PPj0#!mIFX|yinL_!AiU1NfxTThRSj;T1N_T8#& z-D40mb`TNtpoeN6h5dVr>$mdj!)bjSirwfSKtOmR2Kq-7+`5=0GyZ(+y%odaWKUp# z>`_+HxM~v&0cSDR43_LzoP^cnPqJFhbfhJw#tNVNn+m*ovEq zau!*KjTK<*IbBl-BlvglG)HPM&pxaZdvK*LK-W1oEia&MPhIX4mdw-lZx^MDJC5$V z^mSxSgnMZ&%=6Ze+t^~qYrh@X&WP=j>#GLM>DlVxO^w~&|9omctA~|w;r$3XmB8wGBQYEDN5aKBvmwIGVKo1GLzn$;ixx5|o-gOgd$4@K z@y!#;v5RPOVW`7qqJc~?IC}XcsU${$WtI7TLl1IJSf5=wiVAc-i~79zpnyGl0u7x= z@-~^7YRM=CFS5Fz3BlDh^~#^yU8aw2GL0vGTsor=t7ULgcST+9@AD=GX&1b9OoZKF zO3SAp?EB}R-9Zf>4~#XF;R@FyfSZ@Re7o_nKv^RE&w0q~IuV|J4ghd^;=DZ(5HYbu zaTZNvYRTE&J$*yO%0SZk;O18Vad&@Qfs3th(qodWuz1@dp+y9-ltoh!4jZ$gN&m>>~ahQ|;`zY0dd-)$2+W&V}3O!z5iGO%#YZx})&fWfN zQx=AL_@sT+r{4K6hbDN>uc{{YDIP$P*KPI(=jXWovZrpt^;@GuP-FYZ7BeeYj}- z{D0=)+V-t!0U$>_vFB1dqS>Ug#b;k0HNa;E1T%csGj1f5JROcH(f0cNgr~1<vN`hCM+g3Ot`(e8a_IT>icPpqnoA)sw z?-N z<+S>_nefN&KA!dYWQknQxRLj+8BB~$NviT-M;(h{!e~! zARn++M|4s%Y!{VOrm~j6fq{EN|1{c~%{b@%clH{wNyj&5-X~od>wb3<8p>8WW%Ron z#JRs4w@*ZQ-J#BkMgZr|*}w}>5?+fsjb179&;IMYMOV~t!#jE&dq(FMs9H$M78WCK znuMmk9r9btcHSIWkjWK7VOC<{&xg-&zMtIc7WeWOG$*Y?3L{2#&8>or3Dn@%iq(Vy z8zx)Vw1tRy;EO%9NC)+l>RWt2rfxc!AwrlED^jZ*rLqkUoJeXd>HrTb4?x9%~44y z&KxF4-bB3|&NTEn@RS)gVShH=-^1=!nni|{LH}h0fcZyr*_S4Mzrfx$EK6z!M##Zw z0)1}E{2Q^o>OR=a+b@P$>U)*?KzOxesMd&}hkLylLCI0+5MDia!lDEhb)>Kz88Bej z>Ao0Js-u5tYgo*G`=vcMhyIM?N;EUwZ6iq}c&GZ7?3~d0qwhwUl7QrNglMZiap`Fc zO}Kh(YK_b>-_iV{V@Gq~d}3_RuI9rF$KF{%Pbg^vn7-aaC)8Wa-M)OgVW#%{TFz$+ zVXM<4&a!SKqdIsjJ>KCtI3TW579bi@B$yjPo7~cO{`~vov0_OE)V=34IMT>i{w;89 zObk~4T^Mehm~V|Q9D)|<&EDGH3lT5=If8)PJ440xf5wu;rXizB3J`u) z6e}Kn`?EDxZk#u?$F{1iiNJ`Y0y!WCf1Ec4tv1$0RNUtA$D_?LAIBDP8#hh)Fe8WP z>u6e`Uv9A!e_qM^VTM@gsp_BO_>lgK9qkQdRr|4=uS2D$g(~G0x^it!GGN|$CBANq zz}fEyC8LaTPxsFrGMxD=(o0lNZ_gDEaU)Is@(s<4fZr|dKKu6N?BEI%4ho({`?WE)_Ft^eQ&W{u`yDe60NKPf-8-95!1fA<&{DUSzhe zOe^dVH^AIcDTfRtzjXIR#Y7Qy=NDI$CFjBEzsj0Nec}z|BTh>h?{S`)0#xEJX%ZtlDy8i7=-(+wET#J6}dLO#I8f9fh)cc9jrZf#hEKZ!8Qu-BFSG&`h2ekDlLeTW(w}*rs`oB1O?`$Sad8>Ld4`!|Q zovbrfa3|G^5ke#>n&^sClYJR@)!1x1W{uB~iSOr5?TRW#&x~RCiwp#?Y-oeVi^4xK zOPjsD4A#bDM&%9#cBS0$0nq}=1eRJr2uhg`MLbfUnlgF!iO_;4EhLn&eK=9<n+5|uP zCTG@Ado`?VW+4i0<3ZWqOFE#rHRH1N>9^a>OuG^GpAH8I6hYr6eO0s;?54d~)e&5s z@j`S#aX0i8FX$UyhWoCUP8jaj3R9{k=h>Wf?}kW=Iebd_>AAr6ya~&q0c`MZACxZp zpU6c6)+Rnb#`N>#^FaNj|A*~y#vU*q!{6A^%(H!l`F)0IR(akPDqzc+Vt8td(Qx-= zJ+Q_KTF^Y#=GA5$1WM=Gc(PWGU;vz-;G*SoE{xx#Pf+?pI|(F zH@6qgzq}ixWjUrlm91g8<^9u7189SCiJ_GT#kbd)+cC>C*opFmExN5Uco|#WYu$(o z!#?Mfe;}9QyELwN8r{X$niS7nt{u~n+L5jZfbr3yosRd*c9~5fL1+h8e{RE^q`F!8 zcKW#X2-4g~P?4C^XkyYpPV~*Ahyf_ezOsi6TI7gSi#or7&l$cB_W86Y6|fXf+`WF1 z>vh3ie?w5a5O4FnQ!o?5>ynZ^y5k)cio76sVm^O>lQF)6LO7JXW>$C*5mO( z`0GEKs_>0%JHDkzk6hnAA%~;*KIQOlXghL`ql79&LmA+V%uKG{qOxu>L_^}lL&1dq zRs0`eMZB+oL&e(_Bv_sj|13|z2FyR6$jW`2)|Th4^c?-`&OksE@=N4G?q1oScKcBZjKj^lC`&$B#bdGu)`|tU5@Pd=1+hYVOFpwL z7npiM>>+7@v+s|#I9>m~`3I$+{8MWr^&As!eX(ODpV4vWUA~E%I;PzVXo#>zzkPT3 zORv?`kbq{X`8l9^|D|*g$9yx|zYCn_UG71jM~xR{P9fGqe+U0A=Q_xMOQiF0==?L8 zTPFtLC6SYAj$r_Y3G-MP{WZqR!3@lcZFXuTag;`JR|AGdTs;HW2qo*V4a0riWNpR- zo<8w+VD#w89rKSJZ(KX+P+h-_SWc2D`iDgT^0KKRO$^ z-QIBw@ME6k%vOwTJqVTX3V$OZ#{-`(EIOZjdpTo!FI`7@lmYdcu&>r< zRxx5s26cikQ7*hsGF+ibn43^w{a0tlt>K?rVlFxJ^~L4Tidfd|y8no3MB>z0)qT5y z|4UpJD>9K5EK{85X)YwRv~MH2zAL63I~MeMe53@h)=yGhR1uk0AurZT5tTRr4#d78 zMXbcPEETcS-*#L(QWy-$zF1_#1leuW`N`LQl~L%DPf6`FDE0PA$%`zXcn9cw;z1ZJ z4GV8f44Weag=u`YQm_$wHQ4VuF55LTvTg0^vrtZ5u%O@q>OUWlE@>|PEtKsCY@gqe ziXr(3D*w!#oTh91P#sL?=a{kG@8_*r374>Hgga@F0CXlvx4KTWXZ4Cz*b%gcepW`$ z@{}@kg_NHc{K31VTmhmI(v_^R`mPyD<(~WFVVj;@@6;mYZWv@N99r}d>6Cr6%&ZG!@%mey+4q^d*mgJq@!_M9d<5@k)_e0U;%o05^oKU!*pcN16PaOvx zi^dj*&sP;x%*>tz5N3|7Zqi9MBgyHq+~e$N6)cq-CI7FZ)r>1(-szczy%5T|f1I@_ z@}GgRb@lnUDfxSs!7GA(^v0}(ZNnv;!+@OgvA|!xUnUln%jkJ3691U}j=*zncDXG{ zwzeu~B6WWJ%pP36Y>EH2vsvcs07+Xq>FJY{IW{J^;5^vURAueil*j2BS|g|9+^sh=&1XOM?Dc3j0P zhU6VwwPNLCZ}5@M4Xyt5Nm;h;@j^>O#>gVtF**9Hkz?Y%mq>uYS9D2@R(NS`@>j*p z^K38H-~a$j`SKZP_Nl%ULZk_O*1J_sY<;zJLB59nk@$5DV3S;j2`JXBSVC9l?rcVm z#s|W_{5D|a&Ry}`VaW?yhTH5iEowqP10aMhcRe*$AZeFX`_Otf4>sGROD+?6MXNin!Q? zz8SC3v4-2Z|l$=unfH6YS{BIVM%icZwO={AU8Z8X|>86hPf8H7X*;R zCDlgCph{*Q2}v+^lhPyC;u3KHbjG@=ycpEVd%Zc@^A>{9P6>9TRoX9XK65x!iqv|f zFy=97H|Mcyk4|qjTu96K0X{{%D+r8TJo>nnBO`CnE`m>cyOM(HkBg!l0=_5`Y$NLtyn=#sIp9#KCMk@TwD*X z^5YKDZX!SUR2i*Hpz7dY#mO{izS$yMGHZ=<6ND|h(sMn-6*152;O8kR$d6@`ZheGT zb&6(JoPU{b^Oy8R&#J9mRiMRQX7s$!UU>LK^4w9*&<(SpP=e^4Y~MmR!iB7r@@y$$ zf`2XE!O!d1Ui00EZ^DN6;jeZymz8HUi4}i;)E6E6g>sYgWM0A1rLGH7a~^{l6R{7a z-sO$ObkcVLM)cmWkwrht4-9!T$wS3?KCxxq<}Zs{C3f3U%OL#~NXK}O5`3yX)}wKN z3k=b38h)T*YKEr!^M!Q?D>9{QO?RTSo%Ebc^JEaDEb&1j&AYR?f-0?(9 zjcj{YR@IfN8qox3uItb8V-bPzM&PiQ>beX-gE=LWGUc1vrDC~gO)cekRp!uw-n}-+ z99K0{Lg8zMt<NeZaUu@F49?1Zm^>Htp>^ZRt4QSoxu{1YSqjYd zot`nekPybl??H85nf*!;j{r950%ADNL3z82qlt(MmRx;rb3eG)u`7~?1k-Rf&A+#T z$0^!g_|S->Xe=JlVF7>=yHzHPi-IM$iERP86GyIlAXN_opjz}vd)4Jd%md+CtLPgT z?K!1V?qkof`aeLPec>|-1RZnt0w{1PD-YhGA4Q5mJ0HQxj&Ec!MsZ_$;w*=Yor`}2 z%_`ghL{*qG(I39%XL&dnSbF-pvHjEpeMVmNyIrwN9QgI4-*b;Ss;EE>=3YC0R}L|G z114`SAhait3cu?1=lQvTvBc?-mp{BK=Ek+~0uJ8{DZfmn+eum7(~*7&2r5zRquWer zp^9^=a(T%gK3kYrW9}f8SVQ@qzL}l5cX}6~*NEPU@~+pe>5ju5WX*PYGDFNA635qE zAN0-R&0+_|*8cdTxmVhA&8n+0cQ)uK%!$UfG>5r$*UD=Gf=PW!!iWIXaH|{@)^%@5uZ)RW*a<}gW zkL}i+pr48t5ms>PHNx#vhA6$A0rx~QL8$_VA)ULF1sLoO6wfNZJ_+B5m0e%(r8+zQ zHmYk^?ha-fxGO{ekD%GU&^+WO^jV}WYfmivkpc9%bV~M8m3_aYdnAB z-oV{W#PjiP=gm>LQnY=-?T{MWdj@LA$C@K|K6FM!hy6y(oA18=Y8Df4_Q`vg{55p8>|`{}TgP{A#X+ zrzaBXO9eUZ-}t>?t(k2%kI{H8_wwUYyUlz04Ksef>8`NjpKQs2txUt_lNJ6^EO3zK z2XE}H+ceQnOPgD5N=4tK%D;LY2mfxJ@c(vz{XjTvbb0T|()fQjf<5w4{|>{&UH`q& zH-yfm2L63#2J_FO7a@bDp0bH@z?jYt|6_I`4r&eOJWa8n{cFa{>=6N3v3X`>#IgVR zCw`DFhlhr){gG-B@UQQbVrn<=n`x1M$K?TUe&>h}hK7fWZ6ja#2TI>v^wpX7xDfLL z&ajs`1fdwNNzd}eh|=1>SB8t%7F3XXGJ47}T)3ibM?hd8Ywy|8c|lq013{+evxC;3 zR6_(VfWwICEdF91t@+27rg1K~Yx~ys|49+;0W=@Kr7*E%6>InPX%M!b^G{;u%0GIE z=f2N5DgGJ%)jBetQAZ6_^5deh|C#*xN744_pQJkFD-Sm^$8KfK|Did~0vGG6{JzUS zH2!z>(EfeB&G-MyZMgp*xrA^-@XSj~Yq(R9>Rnlr+&6SGj;nWTZ@14#-R+Hq@eQT= z4pDZG;eXZh8fYf;7TlWYH`QMVcWiig!fft0GBhDb0!~7c4iD8VY|pCu=+LTSUiVWM z6g?v3%`U(-X~G2U#BGHt$3xf-{;0#Z@xIzc#`=0qSIVTukGJX2Pb>Ov>|ANr%qRDK za-~Wq!>&CobIw<|hOe)B_lz~!nOh4EBU$@ZuT4J&cXYagtn^Flo{W{)%0KA9fx@>w31*xf43w?FyOGR3<517Nk!X1%q*<43f$6@J|=v zEPtL^85>v3EP#LxWT^A$)%+%0i1$G6INvx_Qq_XTaS$&P$&u+KmRPv0hWyugIhda3 zs3eQ}J@l~!5KF6qF~^>9TF`JM4>zAREyyeuXfwg+Fbn3M^Yee3x@ z-hiNXc6>Fovwb48=?qD0R2?q>Y{X7x1q%J&$h^o7iQsOx`8FRocA^t z`Te)SV}G40@@rMq9Hc=?94RtXa;oKgT0Z>HE{a-UyTvV9~b`@b?+V3)Yh(xFR-8@prC?O6%~;tA{`PdsIQN`>&#WXGqEB*6AKY)rE9uPDX1LqqQ9pWurKc zG=jWDm92K=8BA8geD&y51cTAcb3I~J1B+gBTgQAxAgazaLE4b& zKk|h*CMNkqC$Vt<8HO)+%WiNlIDJIC=93DSiSUVB>ouH@MQjO!gj@XKMOjJ$tpv5; zeNsu`DuQm%Uxj-(=VqvFK}{`O#aBHTNJN2Ge zUC3q}we_c7qq%Z%K4@il-hfn%CWsoPe&%3|Bd)Gi(g$&$9lIA(Pse$r;-YVVAwbV` z*We`<8D4Y9B`E)YvK*>%A^=s7V7ni%7G+zw>oNbK%B0NL{}1n*-e1$7Ol_}y+J3L! zpD|qc{@sX%$LjqjxfN9F8$KU3dLWLmepg~1%%ip6;l9tB-74)sP=zILv_t?<K@~3E)-2G~rxj?w)g0{AxrJaKg*wE+wcqv1L8V3TNId^} z+GhN`6992`_%WNEK{|9b`%{wNDb zw%N%CAa^nNV7!d|u+p5USJ_H@LJwkl?bhJ`1}!ID91yij9C_uFC8K|Xa6K)-{m9-K zz_{GMQ1>)r($q4%(uYBr7(PMnBt|g=YDt#V)#;XdJ%=^uanPVQ0a1Z zaeC0jh{ILqBjU44;wfT88A&Ns>D~v7K?T`M^C$ z?nSr)e@k`O%~t7Hn4OBW2rM4Qv5(CuLikiPHLzORed_4e49=ef55|GAkA9poNz+X# zH>TtBhFz9y@-^pY{`6W`4xP;5gzF57_;j8>3baLmC5ZQa%lnIa%;|gXn^EhLmKk|X zsXw$j`#5y6+iHpkY+R1F@uH`IpIP!7e)wyo=RpnGc;K72R%i`*`+};@`=UJi*hhz^ zM<|6FEBtag!|n>K)IK=I*Qrd=SlHLmRd%69%|0P_?YpkPk?pnR-(_C$J#YS5GCw8% zYc34dT#mlRSyor6fLi^@N2b#%lk31n_YiYQ!y5YQDl-G+Z(Da9QDAj{_d$hkP49d3 zeG~h^fae&HZ}RA_KBpVVRWyrOzZ;UPdVYm->z=bedo-0{1&ZUELVGsXCMh-vuZSaHMRW%uU^XU^;jaLvK*X#9OhSHdOM zWnpQHA$V@@);~#}cfkpLn^ru#oI*_xI#j#W+5 zYItkp^X8{=-MiBO7Mus`rF6lufx7MD>e80BCk^4_BX$_{qThaq& z-2V4q00I?SxLmHdIQ}KHC(X|h6;(N62cjCW5+jF~l_`T#^J^bJ@=Tz_{Ekp_t+yt! z8px7v7n!8E=4z7i=TOX1Kp$KS?tOsu?qBP0MBNS0u=)Nj?6w*+X6AXw4{zb?8j0>T zC~a9Y+8qGauq1EWUVG=_=J|%8Ym2zgw$O{AlhY?Dg66DvLF1A8)rPu;#a`Qp>yc}q zdtCy>0bp~A{k>%NlQD zl`V^J`gMx;MoPyNQoC*OjD$IjPOB-!O`MVEKT^e59?)@V(GU@D1#)Dy`E5 zv7-;9cv{3TA0&qDhNTJqI0s2{ubzX42HBkY*NScj`1r54-|tpvnfQE7vXrQwL+DxlG@(<(a))JUly*6qz5zFZflW_sx7h<;!Dgl*msAy~a)zF|1pD zVi?EsMG9jf4wY3G*&V&5%s*IGkOL`n1O46@@8^zoiw6%b_5+)t;ORmKKby3DNkM#g zYK|VsF=_}F5y>)&h`q)5pvL=$7Kn%}MNMQpU59wD7^;%3lq)H;OGPVeKpZ9@JGb5`G*|g6Zq6ZQuUWr|)j4b{6t#^8H z)h;|NnHW{9OnBj#_>EFKID72ghs??_`l5l-XDP+3jOrYnie|sf^}73wWiy_BIebTL z1IIQVBK3hE7~lu(kvI}48&7*sI2}v~R@8UYB`X4@xNw+7@fW2)w?V|nvB`#mXBUY- z1#0!dvzc5>{28I{g|F|V`w*y$t!Ogi+!uvN!i#O4GV1)ECVN|C9y7|cQoQb6y5A4; z_eIi7iP|nh!zHYw8F*Bw8_OxZcDZShP-=|ldMEKd4S5N-;Y{}dgWi!(&~`}6gl}_=&PT97*U?S0q3vx2U}OpO z_0&*B2w^?)+Jo*p)31sO36C}B!6@rO`>TgQuHT3>HRNQ=0JYmC?*YQ#OUj*-+Gm~a z9F7N!SF5h{$o3s!P$iaCsu@0wvZ@Q^CaF)wK3~(C_CVQ&f*1_+b8#yVH zZ1ECli;WYDEQ-sSHE6o^S*lycC8PIi7f*Qpkoc#-Vexjtoa4(a$Z^%E5ZHXfbptvS zS%G1}`J0uwt3+_k$j2U^+a%-xpqynaHUfnH3qaVLH2oAYCEXeZ_4ek;lpuW3`G;o~ zIIA!7>iKicqe4)H$gQ0P1Bk6S1MFsN7=X)f_)+xqH*}d`|Nk2@*qs0W-oQ0>x!=Ud zQ1ngbO!LnrB7d~lt9Eo!{V4L5Y|>Gx2z>qLw*D*zqtjxQ7^(DSfG+yBn*RZgAT^OM zYMK^XtyM!?(elcuxKh#D<<~<^nDezqmVB)|TaaR66#9~1yO)e=>S@NT(_a@;5^+{$ zFH73LaFfE94M4-K1Bry6y0;fJ(v1gr@J_>rEC# zs4uUq3P*dr*C}77%l7>OvFANm;l_n`&aIa0qkBP{@Z^Fhz?1xuAAlo@uhh_DC=YPB zhkuRtaj#BAo=&HQcqK=SaNdCUgp1HU$cgT4mpMl*%3UVng(*9$dn!;-M!DNY!nY*t zSN~TzY7x~14O=q`Gkz)q;7cxbl#_W=Nun`E{)Jlp72VthT^)X14ok_ve4sddw9?f^#Fosnwly?)VNn;V+9RPWsO z!?~;86IEA(n4C2`wZfC!EkqWOIV29q_}69#+adpJ_L(V`w4 zSlkX5kn@Q!J7}BUm!jh`TGDjC8!Puhd<6eg=A^WYxB2_n@1Ivi75ZEEWQoP<-Ljrs z<6llUO-(I{qt@G~&QkE0HS083OnBNm>A}bGj!}g=-PE$mF5O4bM*atogp~nzmpE_QSBv$k-2v9V z$LD*B)?btWDry!)o*pF~bi(G#FTg!kGEX#H)j;Qqm5y$**pOqPoin@kMCZ$=0lP4e*J>nJM3rQ%~tbhv#k-f!hL zGSaNR!)tz2%}vM3AoQ*_ZP6@xXYKO`R5(5sE~Tj#^ombMH1<}z9Xv0xIwC`=J+Ucp zttts$Gl(MvHcgX-CQ!KL#z6G#mQl(B>*JDoM}cM8G`X`PK$2`K87v!0b6?aYtJX0; z5d(%M;P>a5t~X5Sjv}I9h}sC5K5MuWw8I{Imw~?B9#Xbx7qYs$7omBF;Kv839a4oe zc-+MJif%W4=PL1R@T_0&WAjR|G{2%G_F95BqqDcPWm?B*(&oLFZ6Q$RUh;AV=Ud@a zS{dcR(e_Y8FRtxR@(p)1c4?m~OdJ|CeW+iQKxxSraeJ0gz~+>DrWm-5I@dD5FqS~5 zQN>k}OGaB@pZgkK5@C*s%|ZRoO-_ z;GZtm8T5RX;ux09-tAQ+zw?7>Y!lD}ew#Gr%;(K4Zh#XD8eR$lgM^&eLnO~58@m3- zt^gkv7W)&@;g!?v?NK;KO78UF95wQ-w9%I?0s3aAx{F+1|CGO@IHtN_Wko?GGkcGK1vQ+bBVjYIJ(4i2UZbnF{XVAax$NGKb+=fyYphV z9Y<~E30JK;o6YcYgSi12J5P{HC>`)~S&HxyxCduj?^fK_PmcpsOam_h!iN>mGw+iv zR0kBaP|og^c7ntYb_P;xU@b457F~>RpkrJ2c*a!00-FHQT(%Ex-7WQEc`-X$hYMXl z3a(BKwoV0~k`kadQwzH)#d3*%Nu_H*4(r1**+)?)?^F(2XCX%3K_q^ihVwV5W=!4_ zB@$~iB^yhPz1h;C-=#R8=aDUCeiDWxmfm#hi`ltnL)gLrWBRJ+f z{Kq}-kSXog=A&|4T68P@QCja)JatdQsfyiPdjj&mJn6?4#g^k@id@z?eP;67+rLQ2 z%}#Sp7{9f64Spj5^Fz97}7ZE;`DOvsIe^_Gt&JOT06vU0Pm0niUs~AWsT1z^|it+Jq00(-arK zg7Kn!Fc_!e#ntam7<_jT^MRGtbG`T1(RUm;1*3PUB^dWh8zskn1=*m=6x#Xa)%Ex- zLg3UEw}{*c;7^ zJ78aptKpF^N}!3-w_dfn3~S_zNV+ucSk77bR$6^qh7?S=f-7hEEIM>NRGn;o`LyvU zYOVh3BQs5lldq!O*In;Wmu6j#I2ds+1IBrOIsC|})K0k%-!Y#k|?ln6cn(0(MuyoA{fPq2OP&>4V&)#MhSlG?3GIsBiR%*A56qvo$g@OVc0R7dAvM+Lqg-foTsca0xp4O( zo?x*9!pX@1f*+oKy147^-jB5c&)GDR+vjIc zfhj2|+L=D@oATq9Ze_mD0sn{vtN|v6peD!8olgIAb zehDDbTDjt_)qJQkt}3HowAFR`YrzSi_giypS^kgdz9fAX{X8Vgrb695N}OqY=IPhp z8L#1ZC)XPzfmB`IJ}Sr?z=VZrCa``F5qmg!|j@fI_EEJt_OjWro%vH4I$V%Gs40_5;>hP#(9SzAwDRe9YA zYATXLPm?l#G`Fj^#Q9-2wgKip`|Rh6AzY1vDb%CjkT#Y>nWLv^LRGFYMhaa&D`qD1 zm6|Tajj52vCl{Ubr|YXZhJhV)iZu1CpQ)i^lrLYpbWfvNuA0SJ-~D_0=p0`_Q-bSY zY{P`AjwO-Md05#zh^t+(VFET6TA;yg44}e8g{vV6OY zPH4tf#bffsk)oXJPWH!pff|Alij5Vdgt2zQd1}Tqhl9J;prql4o454Fq%z4hk5+QB ztO%2Ctc9*UwJ)H^01$PA*hH$5)}T9X$W&cQB^teSf(b)&7BDE>E^38_Sfu_GfOIq2V=v{z;6!k6+g8Gwmw- zLWGF=>5 z#d0w@lit)0uP=A&FE|1i8RP?1v%xENpXU0ElVuOHpJB?xnH#J-bRmFISd~QDs^HkpFMsmT;q}xp+w$owq$CzVD7HYCc5=mv$&GmU+-+IP#<}ycZ zvGN;$t1E5kM+5l$NS7Yg!T!R5?L_>oBLMcZ8xPlO?yLjJT)qd8=~3hD!)Ay`fh~Gzb^D9D!-x_m9OC%|dzPMyTVY zgBvh9*7yHrZSZnGk)Nx`%IeyR4ELt62}u5u(hZSBhZ9e1{qkT-KbgYO;76n})>G5o zy!kP;vc`$r6g?-?Ev*HI#4$>LzB%%+ms{Fz6uH@SGl|u7OE91a5)D*=C0`-v2hPXu zQIOCog`ZbrbKDUBN%_J)YFS%bH>{!+0xuDSl9^VkTZsL`J%PY~{_Ph1HQWtle-rWV zO#{<-ZrBuv&$6A`D|@mV*QobEK6BU4uM6hc0+BCAlvP;P;L@f@+g$i%ApZNBJT)qu zk1o?^LslC3K=svk_-e{afuJEu!VK4n+P?h(IcW~t7EC$QyvFKO;%R=~dbtTJf6PIU zn2eh6RnpoK6Kiz+dJ^Qb!94YWj_%6j8yYrM^tt87@3F>CM^-B-bmk=QPO!WXlCxly zAAAmd#&i8?&a*qIZVf+-;u?^yv5jMtJw=TnfSCxpQ{%4M!$(-6e)B0)uRTd0BUY%Y zdXJY*xt~o;eH@~0Bzi5YDe%9%ysfd!wXM+DT^3n0ZI-*{WvFYhq=nDlun3@~kY{(= zxr?QA-A9<{X2iExj{Z16JOI<-aTX~m#O~xCMge?3I9r}mE^V5m^weiM`a|HULrc96 z8<*R3I$~rE-R9>|ee}L<9cm}gx`jhnjeSWyqQN@T^E>7XRN;eD>)MvMrJ=RVA^s$6 zg{jeu=Ud}TYoSjap_m*G2pKi}iaifv&%6U$3P*r1;hDnpra_A4+nJR$(ccI@Ly zUAQsOEC9@zuxydO#pA)4Bvv|eVBoX2Y+H?#B6Adwi$$Z*Xdt&j4*K(|J*?n6(IR}I6 zl&%i7{1Ycz2M;3oV~p}7DzMOfoHa1|3R5(1#xNzU%uP`rZ?PYtm?e3Vzp1^n{>R<} zyliD^5D~VrqBJE)m|2V=CklF$EeCSzXGJfWH*-t5`whYo~gL zwuBO%E2Jew=aWcC$J+UGh@vI>4kHh_&%=%n=W+(~V_TdHa-?B!c)gXO=~#j0Q{Q{O zzNZfPR-S;6zSC7kY!9OM2V^+}xvy_uz^~iOXWxj2lt|%`6~_+MxK*Z%QP;ECcdsl7v{PfL^{yxp>PFl_4 z1+?e&sjBO2D?Rho+ZKZR)<^3ft;eBBhSd`W1Pytmd4sH`XLZ>z92(|}t!d7bmkro@ z`|YCyTu+=nrH7B2=rWs(74@S!Ra6T#eQHQ!qOw8*rb|jz?O(RkO({~d$alKenU*gb z-c0JzZVGp66xbJ#a|x)K9HR4EjW78eLm)>itkT)aKG_;qhL3u(<^(s^wF7SZ+~$Evfqq+`t=k!6O`0`wyR2VT~Pe;N~+@}e@nYqSFd zqD_BnbHaWzb+YN6-#$77eb|oWYmKZC9G?|RPyIINdP+23Ai!sAC9`C8h1%J%m?Ir` z{nKJy#81D2Kg0_bK1S^v4GOKa2)@SS5UwA$#w^JbFl3d-^7S@i*osk-`Y zf4G;h0WSO|+{bFjPy5n2-zkoQY{C_XoQaFY>&2eioz`GsZVdV5d7H=+q_w~S{5DXT zvZX9PK6x_c__0Am$g=Z$cfmsKv%0Vp&hp;7_6{STw>c3jKEc=B+Vke;%Y~b;L%bA5 zWN9B{4>ix~2kz~gH%B29sCuU=bBA8?F$0!Jh?<~~No-TK!8tIBdPeL{&5xLZcM2#3 zf(U0{fTJoJ;hf7Dz= zbbSR|Mp^Up^f%N^i4h{j)+<|#?0*iu?kIW*^uFKi0e{ByEtTm;6-LO|{cE09{4&pQ)Gwu2p;5g&am$#Dx|5Nl{V;*2>~5D7YT>zJK`swK0*%jQXJQgKuZX5<&y}n zQw-$|F+bnKijmb35fQN&{~6AjOd82H*bkJaOf~9C9PlrG10TSE>p0+zSKfoBN|h>4$A)+EVs`Wuzf!DHNUqp z{ju$MhB*Ho1ypK8sdWt5A-oM@e}{!3XIN2@Cy8FV(wKarUx5cryJn;pbzE1?d=nLtnX$8HvMSpC1(001NvXJp%>uL^IR*Y>!$cGRHzSata|(%= zDwQuho=`NSp>Kr(`;zBldCp+E~m6*YgiK`ZL3?KUY^$>#6qTUY2=QEj(%K*^v+?va$KoO z53Tj(P@&;lG9fk0524FH{UDyLtWsPM-B|ViTkJ%g}E`;UDUBUx2=O#^33_e zn4)=?@j#i15)>_^pApxFKOqLbJQ1E`P(Nv~rwHZe`}V`gbj!GB2KD$()%UBP@``-y zZR@*LO586LPfg9^4|;Uj`!08T=9JAz#Jw#drVOp~U$#a>LT`5Os=XAI!du=RRXR=6 z_BdehYKR&%1UEIR|9fc3$|riT3mC$^8`xjrdE6qgmlwWXY*jzo!ZFnEvxfp*^B#IN z*wapP)rLIeXI~gFhC|BtGbM?>sZu!0Pj55hH4yGq^b01>Ak!hA@(Dqya;>e5)rcWp zD{TN3K@<%u;J<<%V230>6QiQye|6b(=Z1Kyg5dy=`(JGj5IrN&HKcp4hm zV0}-xP5{_8@(ZRrXpCkBG)v9peU;uDOlI?bj2_X5L1^srpq zCQqK)h7XmGDS6)#pxukgaoUf0=ld~75+&Lql&MPHb&p?&nekB&Yks8xxbFxeu*htMN_IOM7+K=xml1m6S8CfE@-An5aCY%z~{fOq?0>2Y5?t z1Wq(bXL4S*GcK7wZFL<4d0@b3HN-KR{50I~?dr5Sh*55V=NoAFE?3hXR^PcDa6~wl zpuwX>8rrfRHh#%QqhyBGe%AF-MgT?6*B~oMcb**F)1J0e>MR`472rcyEB+fU7Sxng zQvcVsjOU}7QRv&fK*Tt)^OKDH541{V$;%PU0`A+NxW~lc;njT0??883bH$~ zuwS#MlouZ^G6i{<`UTSYOgw=9rp7H-M&O}<7V~nqV`@TTK~s`N<9U0ug>l0@`)f1W ztu#15cs8h1|Mzov191pDOdYiBd}^9j)GHa!slCG>9-9IUcX1@t|Mgggm5FXwR7~R zO{8`vD(IPZg%!0fcBQURe3}bA@oAyh$kJzZ_65dbA<(!Ny_W}ti!5;HdJ}D^m*pMN z7(J-MUgmj#WaT59rEo)2+wuoU3L@>BOF~(Qg%uHb-VVc%KnUHTp@LW1h$E(V)$W%t z0T)R-H7p#4_tPA`k=5f5hCxc|9%5AodON-17-dpQ28bg{^Y7f=;qS7o+;D@q8~7vD zv1FFaVd>`FT$M;7nESRuVA?lR?RLf8na)aE%dS@Yb>Cu0g^C)r>gBj5fKxiE zS_iiQnU9;8t`x#4f*B!a+7(*d^Q3X}Ew1teb13AAt?XHrq%x>4uG2J#_n28zBM5B^%{B5hiuM2(eKAU_HKhB`VA#2{+Y zoL&-$GQ@6GJz_b(`mu6Br=x&eC>Jh9XoCUN%wQ`cO=c5Q8TpNUE=$JwD@l8|c8JL{ zk9xZ$v6YQwr`cWxnfFe>cWtboub1{{XdNa9Myh8XVoq*O9L?m_%S5>pfjH;w3k%;} z0e=d^=M;Sm!>He1yP+LG?K@`T0Huv$Gvg!sbB*RR>NcHFKnH8#B0+Mo*&g0@M>Gj~ zJxj+e*Dj$=X~#Z*lBF#saT9Y_~Zit`R?^Gq{OjiG(EZP z>aYrLXsS)fb2#j(br=`8*w?o$Oovj(${8d3QW2Iq!cxJQEmB;asgJWA;AY{5W?RPE zyjtF_R-@{|Y^}%04|J>+X<$Mj?Tl?MIEXHF0N03;7%O5t_OO#g#tDH5ng%`jv^Pfu z1v8rlpcy3QWP#I6hlS#NZuK!4G$^ddiVhc z-(&tB4ktw$s`59%>f=)SRDLQ3P#`I$%PIV0#%ip5_cyU$vG7Jxg`xoF1FVR3MuL`W z6`|9t9O!w*FH7aEb%+HRfI$8KNz(w@flDH+A&UPRBJ2NTovprDMrtN*E9PgFLH#dh zA=#b6-9Rs>i8#!~#iiWjmuKB6#Cn95*2W{tQijU*<;$6Z2IJghBa`ojU89J-_4>2W z>}-#=wwg~am~ZXu7f7}BR9nuBVGTEp$(WT{45{!X#ceQjAPPyE1=G&Mpn-rYHy}ej z>cO|Z`2w`xp|&j$U_q5T?lSMZ`;wUg>wPL@y%9vN{<1Splpiar278E<35or<(%rS< zx3F0OBZr_>gh9S&>in%CdPl9@18g3J3j(0f^P=V&$50R$O!D^UFUg<`i540Ecr zKR0_~chdU~_Ci2~A4a&tHF^`;Sc_Pu$Flxc0aWlBW~WpANR#f@Wbw^kPbRMc|Tctl{9m7^M~h~bRjFD20O zXIvbT*|d3Sx?8eqJ87J|{u~n)7#Nr|zOknEteJ}c%D1!r|9?)}%hYBbV_2mqzdHq4 zV%9SJUrB)dI}O68r4_t+z>LjY%86+wh)ygU2idT3?*;){Pu-)GvNPN#5vdk@wkIJV zJBf45cC?~bL4tbvWt@R|k-bP#@SRpm7d zz<2zSbPDzWTz25lb2;*XDRVW!*3f7#^|6WYy4(UVPtMA6rLf?|8CD$quX;=0w$P1M zZiKa(iVDeQD1_+Sh5CS5>c9T9I}choW)~pj1z387WW}X4p-Fy|I;ja3sYvP&D(P`+=l|BR2f>j zsa*#c#aU8Fc_kK$x^j2C{*i-SB$JZC(tPod^6C86uz6(MG0l!uz1}u_$b6*czC1&h zmg6n!t=kG7&qw|A`@`4Au5Gx~ixJhQs)??Vq%=&SQH_&N>=b)&F%G1b!)wz^1XmH($G{@sI8V=KE{j?v)%Q)bs%T@;Shk^}WejnMd2%%4{i% zU@?}Loh($*EgW=|f1=qugBICVviZ|o8U1C^sji9<`D+&E41AAxh_kf`KHrrKedmH(gW5_T^G-RsDBJ3&Q#D&!xRpjq4hsNix zi%H>_nFE151I(eUPFdQIkBS9E+wvw8(~6O(!|Q;?9kJnb<{`ZcrAP;HL} zbY@AtxVr2Ff41GDD7Vj90sj67J7_e-qWxJPz2%_%Jrh$qg6!8XLLPv{ehTLMeruG3 zLGEVu4a*xdHIE5TOJsU87Rb>4#8o>iLY%0YSZcRQ1?yjCR@}CaMjuInAM@}}+vlM} zHmf)g*M$jhJaVK_o_OX@8EWe6d zP0MdGVn)`TkC|34kQqsU08IjbGma+mgIPCIZtecv_Dvw`Ba#{d4E3exA4G-^cS*Gp zq{Q4pv+lR$90+h69#IEUgNAwZ!@&Jehj#1Gm)iKOy6A2dBXf?kP(W_(^LlscpAh!4 zcJDn|_wkAda0Ha9zxK>Bb3u2FSq7lvk8KOuj!o@|&I1(GS1pF<-tDFf%SCtT}`$+RnORVRj%lP;ygc$5M!~(+37kilu>SHF;=ci zuY#pvrd09GE=@MOyuiNDjV)&WUa~vc999`arp7O|lsapWf zNMA~hD1DY+AN|yPI_!<$Q^5DWt?#{=8PDw8Pq3kaH>tp!U@ddqS^0Uh$env?!9e1|Jxs0cWO#r-EspS&L8ATbd z%!8B)ZQYsXU0AKzvF@*}k&*=R68S+?*i4Xua-1fZMrI1K*j=B%_u_&KTRho@31y3z zV~3phH;&o~!fj-cc?JY$_nPIIR@S$rd_B}^y%!?3I!p2=KIto7y}VQ(+(&tImhh&} zPwkFPJevxU7}eLSqF{oFH+A$Mrqm~HsBzjt$=Qc&WjMFuwo3OkT$0s5NE!Si>L*Rb zT-MpcUv#Uv&#E6WazPS5Cdz$$rJh=k*OeMCB>5f*4nVPzl?uxhh89c5&FlO2=78E+k z0l*COxvGzyTrU>4=}((&tjPlFc8+G|7r{4HBf#J{Qs-ui|KS5N{OnXOMV%-%@Y> z7^r}2GV~uMPgYnBT5%D}8LF`oUCb&u0rmfQxA-El!x(-4lJBHgNH0z=KTm!3l`(iK zBi4}hhW$b|lhR~H9$O)739~%p|Dh%`gDq~+HPOZDPOe&9n;fO1qwiaxM$KB<{qmue zj%ZI$@}M(5W@&kYkkB69If_1{MXG=1d}fuplxVC#+z>iMOPP~p_oZ^2@`)a>cB3u( zRZ)S@TD@^m=|YN1pNf2<&>#uX`}K*8{Jj~l`h?~OiW}73zIX(0T8w+zNAC9tvVCxG>HyI1{JmTGt(iglzTUE1;x{uFu4V! z>gK8b34;+Z(Ju@pc7LJBa*|_>34K*=k9AWp5Va9AECQgv6Q82JldP$5(-y9Ixid`X zxz$!E)4a)+fVd=S`)J4BTCw^HFOWVSLH(@qlu;h$8z#W($FUBN zpYupmQ%frKu~v=0M$fw26|nroVGt_&Rj>d|4=-E0&L+nC;IpFb@tc)qn+cjN4n_Z(BVHuukjBO|e*>wPlkU)xxgXG$-+9f4AyAy?88h>v7RiB0E18lz_ zEWYAskGXEv^V#p}9e4b(q1178uu#MlgC_(HzXA0v=QjTsf%;TLPnuZZpjS znM}sG@b$^#20^ARF?7dgqxKQa?KXp;@ZO1Fxi%-RktLK2M+?$DUjDOk)_ zBvN&z!?S%4=s6f@^XkZ9&?l7+5{!mW-zO;+;jNJ){CS3*R9dTFK@G7RGOJmnq&iQ^ zBP;RnmdI6`uEnQD_Gt5KTc^eq3b+|eqzsN3laxW+rytydL7ZJ)mp4z3ySH-`AMuE` zDAMt5A&&U8G)nZk>BCcOW!N;h&s$Okm@ds;f4m^Gz4ObTZm$Qme%?Gf0;xfy8}Z{K z=G&)Ar^P^O|ET$OV^-9`N+dXG3O)pC)-L#HsA42*i22&%HfoL=yvYU-yDHmIqs_@y z1lN)J>IfFjbWQ(dXp7-*HLT%R=dlQ(y|TY%L%1m$xQil)ADh27Mte?T_pxXRx;P%m20&P zuJj*}UnIMiG>MnbQ`<_RTGq20YC5z$nF*yv+IM&tOPMpjy#XJ^tG7 z=kj$UO#lCoYQqc~)VDc;kOwy+8~Qo;qM1GD_J0zD#>`yOo%{EHys}MnRP`?4uWmsF zYs4_wbNj}Uv6^uBIq0%U^YVdG=gEBi^sek7(y)rNN3`bPX&PYrAD@b;Dtu zlRIMRvnA6N6)+9GS!AHko}W6}R^6Q$#B$t7P)tTvwCFZaGr`h7v%Qr`9@ss|RYMts ztJlku9VzRaZ@tFmJc}F+Ws-NUepGZmjjTDLS>bW(j+uJA))$jlBw75Tp;>!>B;A>j&rS=b+V6sEMpS+Doy|+iQBUGGebH#^&Wv%N`pA zjH}-*6SYHrl~Tr?p3-0Fgh+RxZeteS)Iu6+SM z+_Dip!3K?{*Bo2LG}RTBU-_kTY6EibJl{{zxnzL2N|))&Zc31St%eVqObLP0w-^ zy*s2HRVm!ajYZ-^N**}$@3~kd+V&gNGHNT2aruxQZ1+B|N1FB+F6NP z#s~;8Al0`C^^zTG?hoxo+>Xm;p(VJL4&`&2Jzfegwf4aEsII4&w)hfLjIk>=w3=K= z9uJYRR>urZP(~_GDh&_yv}@0%g{Bp?>!^-^Seh?d+&8PV{%?eI@}7#fDLj@`9icH4 z$DTjon}BFtOi%qPpkE{RU*zddH(~2X*;Jfm+N#PGYe+oP-dTA;KKxap)HVvnf@#OR zf1^`k_SRbj@l3XqiP5*p^G$xk_W!;n7HJ2}{IyZZ&SE-&cbwkX(an4z@LKk#-&4L# z`aPiHHHAxmlj-|!xykmbNAy3d^*4+6|746Cx^HK_!~)cMZY6(!Fuu)93Q()Eh5!GT z8+k^nDI=kJNlIivW*`HcF`I17RuQPVk7jCGpyo}mTaJ+QOCrr`h3Rfh5_108_bWVo z3Wq1rJX34ampZ`XGrfc%e7!Nx9Fl{Pp{ccns>UXb`%9I%CoP`S zaId*NvCI{)%IhQ)Upjorg{&)ln$cRbel@wuOb#;^k!NWr*nEoKGt$xVCvmxxn1rRB zl(on;->&95rQ0f26#a3esbRe<^}ZO-YSEcJ(M?hw-A_uT%JWuKMLb+3olV(1KZNV< zE!HJoyMKk)AS!*G$GzOedSD7iFmk4Ox=zG6_O=->U3Kv8Xk)XQ{^s6DDknn`N07o& z94YOZ?KoG{E)1R0{xu#m_J`TEI3ata+=S@(vnQouA4qOK@qXnc#;$?zQ#_aSWrUn4Wl6tLn79wbJ_pDr~^IWQ5(R|Ew~qDM2~5 zK6l9V(a@jBG?`~rBO$3zClJpS0!dzF(LT`Q`O|zY1LL~Q`$u{W2;n%~ltpB}T+^G= zVyk|YRgO%9QgD-I?ok#lc9sk>FqW<(hddukJ7F+EUC0> zTh3I|L1)S|^T3oA6)J;Po@Hj5@>FUku@r68a%NId%)|rGOxei;si`rdR%-U9X=sXg z04on6im8*NAef?vD5NNeoZek?z1Q{q|Mt(l|Lpy&=UHp*d)@0^8D>G|6*3j4DH4ZH zHO`FmG@#H759x)`xrySJ-N2jY*FfSm$0X7!;p7L-{D4+YcH)Pbx8U~p(TYlL?h4BR zP>T#P3U1WRD%?KvYi##21U%`rV8miPJGS$htfrgSnXiR0Vul!2${{~<7aZ+H%$}Ms z(cPMtFj#*n3#4c$wBfS7A@wTx{M_cbpCoc7#t?OuzcP zb~~_Vb+#0s{jiCK@{V=SB0FdXXiJKfQ&zJU?Al)tbs^gRy5WFVeHRZruM)s&!)(;k z_?as)c*+TRB22AO(RHb<+EuZVzKy|WwEj}pd!d&3LskB%&G_}atTrAl}wAeLM9 z{JAaYat5mu4oa2J-3imJvdPJ^X^gDTak7ly;e%?cNTWs;BWii0ytLDS@AJH4})LYD=v11OtWm=x~h-5P9BE^8YH`>)I#v*`BbQ<(2TO}+R%qUw-Z+< z(o)KQlf=iyGPy^|vMVX6e!JeyXR$6Oq(T+{EQVG-nc22jV}3UuZf8?O`WqurF#O6L6JvIcaANz8xX9Z znj#_dVgdGj=wjGcMxot(Q5JK& zO1VH8RBW&>qeY_q#>XheHC|^)~2%_>D9Fcr{k6Oz*?K*&HcY&^s%Bcz1h5O75kyl}qOYD+tkyc|VUnGp17@ixQmIYqcj5hNR}Czu*D z(i#`o`=HG&ySyK+GxU=HBNoF^T(^f*2*tn0@5F!#^h8V*ap8OG3p;oTj*4R>?mbSU zr}3D&mN?PF3(B37`iQkhQ-6gU#JkpCDlcUUJT%y0UyI-()q3SEF~A{ke|lH7>Q(K_ zONH|=4ie)~DRH5<3XGx=T1GeNoD_FXJ;@zR7K~b^OE&7p|1Y`dt+lel2gKXE(BPGM-1Dk zQ|rVQN-FdS2N~f)LIW5-?ZU$U$KZV@vVf2*pZ-QC*;#oXvZE^5ADHd9<)6wTtkmI^!qD<>x}%G< z9RPC+`;CxxJQsRj?UZCAw`00fxF&KYs*+HwTMRQwWg1qsHXSP2pInpveUtSl(_a~f zNtS@FQOR~1gISf~&@xx+rL*xV)iF^fdu1FKh$5}0phYX0#w3rhUc=8E;j*gt>ujvU zY&6)LzIzm=J!qu{nQ~C^{i3RQP>ew%J!<4BZK@kn4&;UZaMcqkCxcEVq4zd8bY3%4 zVe%F{0vZQ@pvgsQc-``Hz zgY6}&-91Lwo$QCBYcLAQSQ}1i>4p9URhNdQKh|GwAfWvIunYsRG;d5N2=79JeyTgc zXx!339IFvvN&9dHKA!QoczglBBs#+WE;I1-;tu_`n$Gzd6cJ|Ft}*?M7>TpJDhV)3 z`V_}|@McW=^LTV-K7%^L>>?Mjduo=_gFarNDxvKY>ZP4jUyjUi8J&o-VZ=-Z(73q? zOC~j-)saE3c&S?NPwM)FBLRZB+z#o=-fpWP{X z$M743LYl%1 zkxw69$E`g|7k-nRI~Ddn`E3ZkqMLte-xta2(0cqQ>mkt{dY=3uN$(Z-2@ui3))U1*}2?#!x(sl*UCzVf;Zg-Drp6_XE(Q3h^w9m z+8+F03-$WTlj2AI*l9CvOabD%&@ses4Kn;iaY)Tlvcb_>XeBO7u!-!3&Ogw>TB9Gw zIE0EygFEk55`*f(lWmm0GF)!eS%~24wu7olp>wCwHK$X)`o#D^QWv`TS7$^_>Fx=gBbQVFt+jP;h3UT-y%@5^EkXX#A4E~_yq1<|bYHw;20gU^sNmJvIxow% zVY68lGm4RCUyZBnMW~g0TwctmsWNOF7{apCN4^}iZd`D%j}c*g(vf-$RTolM0@sNA zl~c^?G3dxRbkB^SneJ`vCs6>Yl6*Qv4AU#LJDo{B_YFYA({Csg$Y1eH@}0iEawihJ zm*em*+wMSYD!%`D?(Em&x8)U74Gn`@a(+R-9Hsqj=+Cur+6*fD5Ng}SUD5kE@n!Cy zKoyC$t1>QT94MOBUF4ncV{=tIpDBmj+!|n%bbThgHtMhmP2gMMdD)m!&xRit{ce?l z)E&yv9zk#k8i{o4k+IMIC&Xa6%|p*e3JyBD$byDwBg@NP+=x=>GKSw;eNd^ILMRt!OXLVwW)-T zO7Xdu;~t8aYPiO&MX9YrrdaY9Y^nL|YOo}3vy#Ha;h<1;7f%qN>S|2?>v#xEI2~((+sT6aumt6}nHW*JhcZ5N+yV*_N(C+>8#9uL6V|}*^O|HlI z`}=F(@`ox@5z7LjcR(~|M1bpdT!VPar+!q`2d-&46}2CjT!YXyM&bi=xnOGBiq;e; z&;K>Jfs`59ZS1+w_~^z28b}l4mjhZ!YJ{VIoB2Grwj&>cm=Mt0%>8?d-$OzI(b1jN z4`5ZW!!%Ale0E_~X+=&R;68wHFY5_I@Tw{Gq&vCV-7l0C(>;|pK%2Ysz|~c;!)jx@ zvj}cap}oym6Mr%qr%2OML!Aqw6VNg2;E#5onG($Il6_;~^?_Xu`k^FkP<8Ko_qk1u zT{!~KZ8P?yx}_*$fXlV7P?1-{oGZjM+_FzBH8DMrGA%=~-ZeU0UZ)B%hMRPrR8N== z3qSfqxs}e*iLwY~qg8xe6@&$X8wD2$yL-7Qm!?7qMY|d%XsouqKojS`yu$W?uE}9r^>kLfpg@i^IoKW#cf%9dCW;| z(r8iC_W3U-Cus?=Bru#P%fj_)M~QptqNhGs;SMM|;CKbL!GJV|BR|a{Gm+> zHB&}dl=)n*)pJW@T(u^gO#>P2VORT2gDW|92rlgvZ=2@3YpRpn#>Jc){E1CxLN2|) z2Ap}XM{?p@GBenVC%XRq75ZZo(CPq~nyy9Dyk@?YLs`6UYP8Lks5c+7W%Eo_=n+R# z236kw5}|!<_g<%^S{6g^9~}~dBg7L_Wl&HWi3ktbT14QvXzRY68J+CSJ_=LhOrRYi zB%4y#)0{M-V#n(!TpAsAm|~*!tq4_-#R1i7Z-$ojyhZ(5ab$#5Z7LGlQ~Lwpo05^9 z;Rz!&;(|uGpl*!7WrpR4V zg7hqj<lUY1gYS-yk4@k|b?b>Mt4M*)yV~(MOrjym8X! zO6mBU6?gn*YkCo4)^{rR;wE7;Z@p3rI5!rf1VFtQH1pr^#=&0C z?>82HM!am#Jvn7#na$bQerLkKoZ)p?ef6*hBv*Kf>G;i&)5_ZcHy^9(UGBpyJ(yqO z#PX9tX@h19eR7zm)u>Ps)t@)nQJ7pi1kKRbvkso|UBjSPEGVN9k;V-d*v3ZL-<9Ph zQ^bw>KYYz7N{{~TU##{TdFkUV5N~s~ewMWnm}!5I;Q?7Ul#?B45%FkAb1&Kx02_zO z-kW`Wq3e0gT?S0ssKm zG}Ip(007Jp0Kl>RlPBm;pln5+^nVP#25Juh)q|ID^qb>O4|E;?0JVv%`_Gu@_ouwn z&3yp?ZlT|Q3>pU4w*i2o5{<_XjDl=74#K@S_wood=oScLNUl-{&uuj>KhX2X8#%{) z)ZeWNk`3fL;>c;mH}>JB(^3dNx28(cL%PhPPF^~v-_K%q&2_4$@>%UfQ_pjI_xSXS zmX%+V0;3$RaCA?woaFvwR_PXZ^X!9H%-mP)wrMnqU%0YV0ggi2e+Mq+!BNVSmAJYC`}}#(bd^IgXKho{ z69o8phUpId7ZD#nKTvzvWA%hUpVO;h?6*OVJ4KJvmBlIaw6( z;^QNR)AS|_U4ETO<)F8D9KfxJK_p!-NS2<(OKhCfkOV6p(>MNG`bKP+2a@!f;s9m~ zCor7B0gXM=uxN*vL(^~=RB&NNHhI~w?ysk6>Me|gAN2vp=oOdoA|mZyot3=6P!qv7 zxhSFNM%vuox}>oqlI58rRD7A?f2q5WbP@y_=3oxth>%CBW#Aez%pX2w9|1}Sx%)Q(pep9r5siEU< z_%AAZE!;ngIXHQ>gz3J2-B(=wkn*L_s+1DVY6dq@41{f0dO+y!$)GfuKJ4QF7)SkC zBKOC)`L0{`*OtJ%8xQA?MM&LCp`#$b$3@s2wbl)PR?OO- z@2CIlk#66nvxZLTb^oqV0q7* z*v{aSq3#A3XBbMrEUjkHcQZo&nNUaigw~X`6cm&=UL7vzt*0ClgE>EsaVyW|8khN zPBGO)t4cB4{ATOhJhzJK6DOa)W7M{YF7-+U;eLfOAje+5p07N&J%`EhDCQ21s< z%0mV#6G4e_4V?i<9X>v5A$u!B*fJgBpK&^;*Zjoi5AG|6J7aX4k;!2QK)Y|Izpy)Y zn0t|U^z@PW@1=CBfN*8%c^uy`zD*3|cB(SY4znpW@CD~FMTv}Fs2w%0f7*mp7CoO& zxqYj9W^BhJX)Anh*5vUZ5+OwMpSkCj>TVq=X|r{0zwfbGGtEQr4KrQmm@EB5nbxiN zUWr9p^S8CjQ2MO)$f`@X5l&rj&s=xm8}k_{-C%pnR=`x?T3PPptp0p#U*X0u(#g#& zW9j@L$!GO*&1GPKk%QSc2s}exh{)wHHGsJnx8H8MydSe3Qw&<(;>*jYNm1eIJ*Vhk#3=y=b5&S`|`Q(tKa3!fu)qby#= z3}J-3f$*f|V})ScwK4wY0QUB2XN?ObQqMBJj$rT(VgXa6eXxyUIH^&XzNm78h3&Uj zw)dDiDm{2Dc6)2YLR5^9uE$5w8d&GOLkI0`+KaG33MF1F3s!bpKK$Cwd~+vCPGICbHSgOo^+P=#jJw*)F@=d2=Iuk(JAj@B7T7k@m+`vO^-dUBjRJ zM`~3>U;3gNIB-E`b7)zGAYr_s^tFRLa9)!pL2Yq>!m{vYbWwfq{Tj7BFFDE1dZfC* z5~WvfIlD&628N#VBeP%J@inMI1k*-fWw~FOL7HA%hRJ5qDy8f z;juG_RV@vs?FQ}KQ}B{!n2qyYi?0`@&f_?`=q1MP)$8fg-jHZqZHKI!ou>}ki_@Cf z7yyM7y7ejT_anhB0U71WpLTW^z%r=*A@<*;M*O!0CNvJRW#nyop^>`9fL+Ydeg(Bj zr;cE?<*pIM802xRkcvAtLiHU3ek)`DHb`cey4j&Lyb?Qt^2jh&8**i@p{)gz>{fH2 zMhM7~w(p^>Z%rt*^6HGu)~Tb{>)-jOM$V>plG_qWhrI3{q8{+pERvt3srXFWmsLf|HfNJSN+ES)rgyh9bj>0HTwE@VZk^TG2%Ixl4@Bj4s6z5Vnp!)@x~O>^P3GVT!3b4fjJJ+!+!R{}`PIUO~7& z^#t7p@%GwC2+4)*H&Z^=7_8h5dqNM!K&VNzr+Z*LVwx2-Bms6_AV_7clV=I2y_QpI?GGU>3uv}P?-|LLf|u_ z=bgAZQ+9qP=}zq~x7vQu>)M0&G-V|Ab*F48J^Q9dR<}ewaW*T;FM5{eMtKUoeDED8 zw%on5T7Su52^A@Ms0+Op4l0PA7PE^B61M~-#-nV}GE<~XW!vE^c#GY~`KW?WrtQXX zLb}*`Fr3`VTv?w{epvfM{(WVW9og z0wuJd;wZkweEN*>Cmho0EFevdP_)C9OKn=at9sCgC@5j?8SH*wo*@=U_Ms$%PdiN1 zqFj+fvdDaxB&#h^@s-85)kjIs1A_|OSZpkFF0+NjWTu{iL?`89M5=q2dwL7y_%HLb z_xQ3fjP(1QWHYkV$LBE|?)(LQ(E$1lcLMS64LaGTWUd8j_% z3014>%Jr}q3cMrv`ByOc*ZN*|=a@5=k{dj-XF5c-BTH@0r%N0e0&Q%qmf@=?VmP4y z4H5IK2xdW~dn6Tn5z~6nU5A&ZS_HVgZVw~F4iR0I^?WXK`0jm5{zkW`BVRhNsKS<$ z&fPa*=~ILYk~Cg2@+rk5hc%Z`L8M+Z0?M4@kd+!2y;N$r+@}hjLS3Z`fmD)|ES+*AM+n72Y z;_mWHB9wCHS35p#SV36C(DHY*z26&)QWJ;5KUW| zVYb)4U<8Mb3VwtzdAU(SLd*hil3NvQBM@a@t#xfRvn>a%$x=X=ZIiFtLUMrx&N;cNSE{v5+4)U;cUTX=q!oh&2((5SLT&9^yPhx95`wITt!RBXwZ zJKdqn_`NlG(-BQ@)5GMBEv=nKw(9~XxN%Cxvt_wN7=Bopt!{Z21_EYKt3b1{j1!(DSD6UD2R^*ZzIw%B?m5;ytcC5M?U4_t7EqP1i6kg>!i zxWA^}tS=LDkZkW@UXBmevfgn1mRHp$1J;E}^wB|6C7xFoG0LC&5WG}Rdr3*)pT9AK zgssjr=tW052xL5y?tr=%f!p0j%CYh?naU^m;`=?Og=b_ulAF*N76S4qvedl}E6`L% zcCm3q2TYZ*I+B|SIoLB3c=quIs{cskM7i~#4j3WOA(G{KHJgn2kdLhuTO?k_Ck=9U z=!|I*KM@@fQRe|^ssdIMv`c)TUflfFV9}935>7N`3@Mz100Sr+pZqd924utK&&ber z-%7<90tEIaecN)DMoL#v)b@kr_I8T)uVA|(iMH+Z!+k@LXYgF;iK%OQ6!`KlkAtkN zEaZD3T3}-3GG}K%FuX@E(O;{cucWfxv8X`+9d64N9B*FyXPveO3Wet4d=K#lh`VJT zG^3SANhah2Z!#u3nh{qIPy{Ms!wKC|3-4vOZugX>J zXDJ9tl`UL_@6~RV?bVg}%XQff57SxgE<~wXMn?(#gqWB7_`bX5n)#JF zudu*Z%PSUPhXM__-A3Sf67$wF787SfG8xS}N>@M4I_2~Kbw)R&qkUB5&|__MJwOBL zR7}{`g@`SyKb>n)3f*TITB<2nRhD z_9e%*iW;(A8cBdEU|4SWA;~SCHVb`b--!=_ciQi&}qqduJ zV<}D3rfYS98Y%YkU=TwtX-Eq@yGV=2Kr8zL2CgN=6DV} zjAJe+>@LoGfCA-z(bva7Z-(28ONYQ-A_I z{(2YvcBYv4-EyQuv0XQOB6Ro*cjx*ZAKC1afDhmFjhO+$eGSmghd=9L^27E+dy=Qs z?8wuMwq4%(HY2xQ3ZA}WGZ>n|vs6%Qr1#)aL@_c!G34=?k2LFpd%2EkJjn8`kY4T4 zuk~S-vN>Hd8@P|;1HCdFp^T;-mBMl%cU^k^E|LG}e3F>UVFbAP2-lBAq>srHE&6@h zpk2BJ3YG`72jRPQ`z85LIl0>S5un7I`_RlW1It$JvK zPRPMyk3h?5k{3ntSm!1WHXYoz8bNp`eoMNtmr&uTH{(w?f>!OCQZ#HRrIri_44R`?0buY!R%TM4dv~5QB6lnGtvNA^ zObEsdB3pagtj75PX^+AuCL>X;oovb>Mxlbw+&A{q`VriF{+t#8Ap)qqKcNDrTs`IV zqN5riVq2s}m!bPeioau$I>Y`O>O5zMA}vqFBs)ke;2T$GQa$+eQ4tT@28HjMdOl;& z=#@2i#q4XL3khxmDSiy0s>P#OVc$}-&v#4_XK+on6Hws^ z=-aRX&H@G4ROIM-?dClU*%iJa%T(Pukl;6vU7cUirA=Jf^aTs60`=}pn**a^0640$ zKoNM$Vt`gFVx%&=qy*hbkmsw{rKV0VU27ZL+roRPnW=#=+AIs_2Z_5=XvchXhbQSS zU0=obTM8iD=MKP{@(2%=kWFklg7DDt24xa$xemUaA%8n!GcMo#R=SvJ!A8cI{VioD z1^cM{A+ZS7)Hv`Lt2-ajVz>>+7(&s~nW+Y-y3u#Tvc$jbMk3y)yuolReN;b=f525O z1>9$?IFSBSKB^{pjd~^uU#pwl6usg(aI`5fcQHHtecozzv({Ep>$uK{x0m{p_D9cj z7}}*ho^3WJ`Cz^d`TyfEk;n24rAr0o*uc4%I8U*pgm@(8XB70yRTsWTu{DhmR!UxjTm+ z8VUtfH@lv1J9TE8`egfCYDv;7rb_eb$})6Iz1n=>6Ui0pQaiAG?r@{vE-9G`{-Rhy zBp1ymjR&(X$(1l&h7EHyZun5TOH&?pGR705^ zDUe!}ekpZou<*SHN+d$C;00KhKH%U2yZkHGzs?1IPS_Of_P$n>|Z@-=rKiyrn#K$0S>!;Z38P z_!c|87uL%P8W|JoEfDD7nPhD3hdqfFfXV1)nM8|r93`OVr@!f;fJrT`GY8W;YiGhiT zzS-R0@{dfh##~h#sVj9X7Y)DH-n3q~c~>yv?VC^H&NdyQqVYQE%G1|7%pLMX{vx`W zE{de*Idt3=-NZCFc)lGAQ$@y9lsJdP__>4Lm&!BM@V&LNpK?UcjWGMblPcTK2DgvB zCLzCHK_Ne|?t8WPQ95>_7TfV7(n!2%k`;YPb`P+CdDylbSen4TSxI3vTMXkqo=hE#5kssNs9W@6EQ?1aVih*#g zHVGQD&}9vUB!n)gYp;u<2nyFa5u+Ck<*sgKlv7{~nhjw=wWF3T6K-Qye&O@#>V*u$ zJVSQ}He7`=iU9d?;+s_Pr_xXl%$&$v46{SfO(kPlraKW7Zd0#moQ%f{WG;_h&$r1%ZcDcB+m=6&SoB^*yTdZ_JWmfC{wbs3h0b9RZUPt>-i-JZ^v zc1LUX;>2zRmJzyoYd7{=e>FH%mFn3k8QU|s6(|BgB$uI7-Pt)h^kQzsoN?{ZyK4g*2eHcQ2yMy>cadTl*zw>Yr z`e=M3fF}evcfRVAIw_6$2kXL@aGT`GXaFEC`?t&0NB6hf)Q*G=03dmZ$nJ!`1@(UE zaJ|42=*fEK$C0C#L-ZKR=PK{YR^Bao%rm&gqsKcs8{e0A^mftn-m!Yu8r zmY&wHc|$-(reBi0_)a@^cg;CvDONM&*2-RX9n|To$YYgRiMmG@s$IaX?S6empkQb0 zXp#SB!*inNI+^RamI=**RGvTAJz4vp_)!M}i^Pf6gRMgPR<5ke029RqmiY1E`AxE~ zFou94M%;m=NWqP`M!E+4m%mXj5}{LWPFs!$zqhQ$S7(LU5_#)n3BbF)S%3Pfg8f^n z;;Fn+S^2D&AGI>tw8rr9;zcdOIEXvnBH6oW#qk4PG1ahg{$lcKVWHt@C=@e}+AxQA zDR$vk99a|%zl%F3GhjaJ2B2IZAyjE_pPZVU!n9a~;RtO`DNzL|{HXhc{X)BWWK#r& z#}_!+y!llY=rrY|N6^Ol##l(!Tc=q7V$cU{C|}?QnVa4~bUzy$#cMu~o8b+e$$|cM zx*bY?`vlQ{@&Wt|l}Cc|Dd)^Eo=t+UM{CgwGn91gAP<2s)r{-_5?v+u&9NQxTg{gV z(>H)!ON)En=;B6bsOSek)6jT8e~V1v;FqV)v`n#C% z(ohtCMhXnBh2^MMcB^g|QXH2oVRxx`HH0*ruS4IH$%cyEwRkI zh`u2EOdtE|kySB;F7iy|?$}j+x(jGW0DJxEIl{r4rU|7m^vwP`%^bbRr!vC5|H*LU zt7V6yYZ=-mFDZIm$9%8 z>ey%!MJ%QNSf_+t(mkU_JcKxQv=oKRJ(tDUm2}%>CZSc}s6rcf2jVBu1u{j}V~7tf z-198C>=~#MzJXR?%{ma>t%8Qa2cqbE8gfqF<69GMEVg8gVWf!Tm$gkJYE$LYPz|om zfa{BYIdLmn=UNZvRbGG@u)@6 zHBG9m|FsR-X7YMo!jaH5M9Pa{Jlmz{Z)3H`qe~V~~&-hM9epLGrh-?-4>m~Sz ztPm#(<=3cU{o>%#_F8;+@;24Kyj#W5a~LmU_3g}%3f9uWaPA}~W$4ugJ``N45JvNYb#*2z$! z8rcBpn9?A?pPop@C97OchX>$;^PZDZ9!%Bi4(xU5%7=+7mF#psnyZ5>DVRf{7YqTk zeEjTFXSCpJ^hPRNxIfg_9MFdHyKZH=giX+L(u&NU5S_zuzylDDQ?ev)IZVur5?Ypj z%aC-j)(Uv4p-nA;Ur|ILCvu@)fyqzb2(3j#b+14UW|ss|y=XY<8=-O_?2tOXGL;bG*m*(7|F07~9WuD|);k^5E-lsaaRBt@=bG)c-Mq{7nIGP%~ z@vIo1H`cC+8Zp^bSF>%pKdOJ zbLFq-ZgL=qH=f=KDFoFA%vE+}advv+y-GiQD57g~YKC`#DXZ~aCeORXR91S@)zKJm z`$C%od9JmrJSF-2 zk*G(D0WA-+EyrZuham#_`mK+qN~&Q1lXHi`BL4K`Lgxy7w{+1?kEzOV&2Mn4{cAtS zLU`pM+&M*TmA4T`&za`I3bYgZG_Wa&D{CrlNzs+`cw4@mcko~G zNlbd;If`lP)+O5sK}5&@WFJ?S1Vijmc3DF?SLBh8mbp6>mZ0F`12xOfKblK)z`A-~ zYztG4Ln^WR6Wl2YpuO1rw^AT0hDu^P_O9Ox>R_TI(U0uJV!1iUm82{!R>-e-5R~{P zbfYrSkAZq){pVPyhxx|?6R|`B=Y&GQt6F9M21NyVK62)+(LliCYC@xSMR#x)&s9FS zr~qLoEWf#X-S^2|JgFSLz)hffZ&33!=&zJBP8UTL=v#43?{byE4af%8c%(oz?Q@vN zh59hfELn{|F?z9x#<6z|u+|$l@B0OxTi#k3X$Zd#kI<n=2!|8R7Q2IN=H@v> z?n8!AOORZZr=w)MvSucFY8a*p+CvA1oNW_bZAH!p8^wY})3B^cy5(=IV}wq`B^+pr zq#r0*l$F4wQyvBi?`4UxENI@#OCBp8R7$mz-SCClgKJaoaCIQ^7$-BucMn>C)(f>j z%?>^ATw0S-`5Nx^Q*Qb2Oj`_WOtgty9B!jIMc?%5|BcUN;kiF~xc$782f~;noXdO{ zbs3OWG8x(LA#Z^bsBc z^`{2V-QZiyu7j8w&2A6=8Oa}V$><)7ZU1FDT4sB7hwr+eRHAseNW>`-aXM2X9_hbWag zeU?g|8bwwbjqZ&;IeFEW17NoC5BYO@{pA0Oa@9=!!)5(fqjY)<@R7dD z{hQ0Ot^J4af|UvWuh>}UbL<}g?QgOEF92G^*TH`ns1FJMNoAe9YA?a4-w8iXAn8bD_P5Bt}Mr38onqwvQ&R60SI@r)z^u-~RvDp@gf=?O!MPxLVI zzVU~@5kKRt*_N(PbZRj7F~OCj%nUgDW3Oh%exg7&BV6^AcHj99YuqO5zlp#!lE{u6 zK!ZLPBt+Dx^0E6$VeDGMZ^Gx-MoH_Rs~2s;v((h@4$macC&+C|>5u=vqA!2z008ix zyyp*AGz@g%;mND7&i;>&@dAl`DjLcCKOX)mGhU$T&$5O&+=Z{+2E-ZH2>co(a6IJp z7QS&~fd3Cz8qwET>k7D^OdqKz9SVGPHca48+eW;HFcyINIeK_QRp=rGEAr~()wmn` z%74BrySESG0=&CUcaGy&XbgZ2=0A_qqK_&V0m+Z)@9?M3Q~(jKe^5xkEw=7T06>F2 zV>M+p0)Wo2KZW(3e<5!Hu4vF5C~mGNhYSmQfBJL3Wbx=DAmTb5a56KRWCz%){I4zM zp8BT}IY*{{dKq;90POx|F98vnT}Q?Y|Fn2#haG@q|5N%F+mR^~;QAZJi=7`n(|bYh zIsN+278kVt6sA{l_x8U8Lmwc$=fAK2E|;jJaKJCfpU3}WH1uB3d;a_S&la5+|2#J0 zO)zKpZ-S!toPHIKY=;~FtHt>JW1WQmHkv}o-^As}=xB=Bs-`*1Lb1t{kzZ$-ehc%z z4?{oL&(s_QD)`GUM&ZIai3o^mQk103&`&zztOu z6ZsRJ)aw?28LmZF*rxke#GQkS-igwNp|2U~^0!6o9{U>?jgY%s&lu6S#NCOg7ijwc zZ>hC*8o$u#O?oh7pgC7;dYs-+^NBlvzk${JC0PVJH2hnPgV%PhRg0bQV;xZH;-?2Z z9WIE1sO^>$c9OS5q(BCxgMJ#QCUKs8$@73hbq|6wGGHloe)U^G-WGaA2Fg@pqIoKp z6ia8He~gQcD&wRrg@Zpec_g)$d%ekJ9Xd{1n&rTcsP>%p<|fNWB%`j1DXiSegAhvqQ9 z&CTTb0yfmzxaDd(iy!vG<=|@7>G=f8_Y>UjqpSeXLAIXGmg1u)l02gaItE0qnD|VB zSRl1s;%NEx>C2aT_tTt7G|l34?={<)2E=!v18BEBwJD3=Kg8mj?w%H!b#r7~R@83P z5o`oTnBe5(t_xC5^v__oHqze{DH8^>DFXu4f7n|<*}XIa02(dZ`+|MovFQ&cuN_s- zc1ubBj+co`8B@J;>ySBMpz9?w^_vlIpPRn2WW>|H2;sQyR-V zsF$z|2+Z_bC=+RuXMd=M;E+UryYW+-~%k zq~4T64&o;E171z6E2@6c*D9ViLkUGCk$*WNMvHvDLMmYxV&aA!>-4O~nDdS6kLCt3o`O$=|dG3Ut}9-~uwZ^xA77vfv;=m1`$ z0r7tQ=}8kx6ZI?7A!{tuxTA>_Pv@EQvkAl2k{g^ocCgCSX*$~QGbyVukMM3~y~Pyq zgR@JZ+}%mzZRIS%e5YO_TO!trV)|@~mWLs#VM?)CLM#hEa2Pa65|8O6A%{U@WPB(6@=6U7~Ol@gG*A)!uxcuEaT5;X`v!mjiL$YB2CCHoJxPuo|A3o%CN0v-SYpITHSC%~5aM7j0O{ z6aG3Mmr5q%OCaAtKXv&$4N)$7Z#fQ)-|k5`_k(8bF~y}T6xMPQ=sd1Y{#V=;2*>`9 z0>J}Q1M?jvXh%3nc^6jR4}YH-{DMWM{vblcQBPrDEwAF53N5y0(R5(1=o$pXDgSZT ze2cv=>&D}Gv-e?(k{BcmK{$98;H}i8H9)*@tss+7RZx!IpNgQA-htoGJN(P+L;~A# ze)eAUbYL#-9hda&;-z>hSduGWM$V&EvT9Fu6|3YQrViYC7q6YV9T|>zwC<8!tOCyH zAx+Y8--l05Fpm+>pv?UID)8SjPgkIo?#Ny9j*|u6z4pkPNY4f3b?bi3b8N|6X$Oj( z|D~lSN;BIUyQW1EQ>{@~|Tdpl-E_SBt zn(|-p#H-HLKRKJ>%s!>~r!&%t0qTBM+h$mwa>}|mPeNru_))KHzo}}E>EZNRu;UxX zX1U$KyL@dMTZG`t|QnnpDqBC+|-%$(Mn!yY#H(rcVR1C?`UH-4A-NoYsVJU#(m5D6&A~ z#*6qXRCQbxu559I%QM~U69H@YKr@4HrCA5)2oOdvZQiP$zIJhh7AtnTA$8S&z0L}I zeL}GZ3ifB>d<2;UK9#_S`-uPY_~k&py7z@aTH11b(}bLDQ9P8d`+4tz!CS@Up5_+o zQ~9*7ks}p>v(y0M1LIlWOk}dcvS{!p>}i4>NNX+q^qOIKvp}{5>5)Jg;~TEd=`>T- zd3~DFfz|{MnSk6dLGDM(I#A#$=j6e1`(SlQp5gkuQ5%PU$TcP}BsDN=&2Ue=!x941 z8@0sbDNB3aNz6{ykozI)(c1IMuc|UB4R%^R5E7)h5JD1pHLf%T-Io?r&v1KZL(_tC z$bOVo0Kx(J=}CjzMqSi~FMG#fP?Pm0cKeJP_>JOl*SxWH%9aUHY?z4djpm1bX#bt} z97B2PT3&9Cc9B;i~}_+FlGMbw<^xdG?4N=OFwu-+?PrR9K#0t}KRGc)1f4)*EUaq5QQTwoP_OhenE{ zr6b&jc`~+rl?-2hD>0ZnhdzAif`lV;T0pK_I~Q6deyi;jOChe#Ypd~@m&W#*dfxK0 zp3yY2{Gw3GT%vQKbn7ne^>z!%f%{U)-DEybP_1tilUKuRht$nY7kP{M)7Un0g1DCD z%4=VxTXF$g>4o!*K^3HFhD!{@&>?n5l>(o|M&WW$(UxZdjj4OXH(>yj8VN4mv5{Jz z4B41f>W-U&_M&X|7M0!}aRPTdZ8A1R`j@crVflV!o3b-()CAgcTNUr* zie8^pH7m=)%g;XWpX0N9)viIX={M7Po+OEQ#w6qu&7-KX2Q9XV6`0m59W!KR*HvED zPlM)1(!&+lI+&DIzi%dc94W>WpnUv^)xbfLX?jl3wZpsn`hP{-j!O(7BUK!?a9SD~7f1V)E9>EC?oOaNwH5LED35r=rDE9%%h6Hb*AGtM20;FnXYzEm!^l{M zc>qvTUT(a`@P0yjgB6g_XS-aN23h~%OrF##S$!dl3$&Rr!)p4gKx^ohps}t2q4i`V zOkDbU8^3>_c}eriY4j4rGSA@GH+`?Z)s;bo?evwDj*&vv1%e}sZ5DsBi9g0cZx@wm zBLl4a)etslVIF+Nmq0&Y(!SEho%(gq{XFxS!YKY{LvZ>fyOE=1$;NpLDQK*2xx>>L z!!2Apmm#;)TsqiLCak=Nqw{P0VPn?H%>|zW=(LzOWEhEF`{m(lD6&EDA3lc;6R@_~ z+v|L|_xr3Sz`mlA9!}>^2VSD@SmGiVonr)}9KB9cdLtKqZi_nJd7A(EZfLa$j(5zd zy?=1KS?r!*chjiu2_`Rat4QvspdH~fGci|xBTLhkXJg-l* znZV2%(Ge~PY?WX%Ssq!@QKVmg9C{X^ z7m#-sW0{YeVyY3zudjBx#G)(RUThximjn(`&-NeA_T8L1g$sXgtT2M@e2P?26X?n1 zZy~>;%v%D~)EYjb-Jgs{6S-P)UA9abbL9n{+Sn;FemPh7=4Ej5&9^4j-y z^|jRUyyN(}n`R{+D;kkzYroNi*lzasl2^lu=33lk@>(W4+=Xw-^MzSXFit9=r`cMH zin{zX?p*Go{h~+MR+B<1dk$K&r_k?lOBTD0Q@_?Iv%zyq&xQ#o`U|=68tZ~=cHQ9* z5jnBPt!KG4_&jShE%E0N@XoEXw)jn1<60kt0Y4=QyMgYxODhfqG1 zM-TX%0Kwi>ui>JfYwKmZQusICtrDW4Z*?=W<{2l&)Y$^TwWxBntDYcX>ev|DOk430 z$qby@RI$c5nX3!N$p&h`!IfiQIe6A)ulUo?ig{r5TjRye020p9Fg=L^3jylbRNgU3 zpSwbK&^Ct*W%nlKmBu+?`ko|@qsJ-#C_6N`jS#NO&)LbParDrI)#|{Lbis($R)7$r zDq6m${fSga-l_wbJOPbERXoxJo$6Re7J{0w=c2%O9(twsDMi_hFx6O6Pjrvw;c+ME zH4l`R`0AEdGN}fY8i~0wxTSX~o|{r-h-Yy~Avv$vhe%D=v&5KWBwZ1im2(Tv1+Vm4JrQhk|o@EFJl-kr+`4u$tz zQn`l-+V8$^b`vQO+|P0=!dGqbRxqkl-z$5O6Rl{`%Z@~Dd(ZNt_!lq7&j!Fw zZDg(`RK{`OLP^NJ(QYLowSQ5h5arLd@Q@?{R`_i_0gsJc7(@fb`yN0-L%YDkMK4AL z?IV}E@Fm1b%DkjgPQR?z&7X{uR^Mt@1`xL24OUNQJ-N$Nlleozg8%lXS|6t?Cg!ZR zzPTXwp4j{z;*Ti?c_+Oj9s1;yhIF)uE22s!=SK&f;%pSpK0I>u)M}-l#$#+g`RU{& z*@gLX;OP*TPTyxC(06PB-=+kjhdH{ucL=#em6(J3wJ75a-xDv{V`X@n{T^H7eK3_s zRNnNf(cN&Cj<_XR!6*l2`3v2{u6hP|bw^;8){t|pd+VHhwPk0;wMSLg1XN>ffE^&< zp~SUB&;ur~&E45X z6JX+7NQr}vnT@?}k{in?n_}_a23J-#LdfvK35TH+7mHB_p11k9K@R1NBi_!)$fDIu zUlFDndCO9pZ@;$`Ky5=KhRRGs8`(|1R93WSZ&mqipRMl+wiaHzZbj`(H9y4FTr^8d z4SW{!fFs2=AZqeEA;P@CY4^-iQ8Ka&N^C@F%HJDij` zJHIxAA6t+IjW;uW0}=xbB%3Wa?~gNUk)~VW32>%xo-rsauR@trH>l5>oBl!LOz2+- zc&XY-@!>nE@E*f8nD36V8tGA85B79s92O3Q3*s%#d?Eseh27`bL4`X)V73KOy4~C5 zN(!gE?|CH>1bw1<;!wTVRHy#y_PfKwQyQS-ss$|6c&aiu_OGg!EDMEz_;?w<;NFgJ zRcaqic|)O230e6axr>c)uE?1jVvKN?BEgrX_jh!G*PI)uO5S|teB_vSkF1-CUg0ST zvAEDcKgC3!V0wyj7A?`0l=Tw5!HJ-+HNlaeUIE^@0fiL z+L6mYVNOlMVLF}uQ(w!gT^Y~Y0vA`u_`a<((Luv;mF~bRMNA6cwp%3kdK0XpM_3kW z&Pqp?e25i`NE^e6Pf?rem0T~C90cu-$D?cjx8+f_j#X}uVEyXJ=N+#Y%}S$7@a2t* zOKV!d>|OxN?XeK5CY|m5CiZgEeb}e@^3902dnEz6RG7zv^0)}ZNkaXWzv>g_kP_ge zceSZNXuh7b;fHmkk_%W2%FuhrT3#-al`VIpL(wm5_Lf?8v@h4K2%^gGIc&zBo=bj# z9cy2gmPM@RPRNv~9mnHzd`_KBpl>&e5%V6Aq!W;%*9|I#HeG?^J9vVp9_kfU2;B9ku^xG%#-!gT z`J0RJ`&D-LW*?azRS2IjT(D$O>Y zE|OgFH|Gm&pyJQeat*@Vj{5qkPl-%0>jBfYkBWx(F#PG(;OR$~iXQ>tVM-9|#lub1 zIHVp8pS_su2qd5_9To%+X6+=;_QSO;^d>2OSFHp=A<7u04?yvwTj8fFJx7WC^km6z zOHGeW2Qnz#hL>JX)9g+4{Z%+U*P3qtb9R|WjgWknd7fHVS{n8$ovF#>TnCcfhi8hI zyhuR{R(yi{FDbGdtSx{E11z{?^As^dQrIUvQ6!sk#LKIfDVI(-&jM;L`7z z`-R=!Pcz~ea%L)m*y-NhM0Tp^Q&u-JoFRD&p~$Q2Nl0)$V>pL-><3m`hf1gakGuDd zYHI7+M*|+@2$rKF9*W=*K>-1!ca9b50wPjERGM_9N+5uGtTgFTqe6((Na!uWN+;4w zfPj<`0t8YBNeKKlmh*bv@BO|z?j7TfalgwS5jT79>^0X~bI&!O`8?}>pMqtt6w;zA zTSB-=o*Cb=EGX~d5sNW%ZPn}fto0@4&wi=vK|J0jwu}b67h<4V_ja#dd%AYFqCEDM z#GpQ9tQ}En5E8yH^j5}B!f{F?Mp3!GOKX!{^I1#?L&5{W4-aSsN|Zs$I3?xk}IA(1cB{D?FkG0V3BVG<{6^aGO` zz!)1nd0M69cM+EllUo2x&JCyqtU;-CE-0Rlou6X;itmk2Ws+t{C9D{Tj(IMZutZt5 zjX*-9Ofk^p{d=<>$=X?;g}@WXo%zM`mRdK8_qM0}MfeGS`*Y?=+-&S8YD!aStzu;5 zIl*h4ut}q%Mqjal);8_DDS6*1YrKYJ;70ICSNwq0}o)<_42`mGKDP$7I#bF9Y}DW2{AhpTLq z{DE(H(|>~Qq&7jzobQ+Zgm(Qm_!@wVb^Y@7?ANLQ^7KDLcfYgvqkcBT|BSBz-*`*r z>#YI&59o;RK;(Y|-L)8i{_jDbDqo?+|Ib069^D53h?n=;ZQA0&pJ8N|mw)YT`f81@ zABDUy$n|gU!fyxv*Bpo*CBh?pF}!kO|7gJpD|iIEV6^7;*-~)*h1rwPY;q7~Dl<~i zpUY;@{Zn#xD%u*-hTY+O?Yeq;X0x(TE}40~^fU9og>NVvV1}k60mQCDPYD8#Blgh4 zCaIkogXtL=#tolM>T+dG{r%f}V9RvTJ7@f6&S4KK5_D;M!Mw-p zW~IlvFKt|LqjRi$>97Y|Iv(GC-aMYW_sMoGffenL!SaQpjsm9+ch7aVVyKoDsA(?| zvTL-%>Vsr|`0fl0>f|?wb?Z{$y%#pGIE`91Vemxx?(Wv|1Q)|8F|I@FN55pJfjO#D zUUHbw$$y&T2(oiUj@-av`=*B_wl#FqN=RsEXm zLHm~6sP-oq)Eg~@sGt=9i^dtlV6bPkig$+(f4>f>MnO$W(IneL@ZmDDGjdTy*&KUe ztG2IK$wvhZlZCO}6e6$KH^%@}NtDr2!d*6;0m?h>=mXv%985t_cIF(xb|_1zscNA= zH6=$E z_*oS|qGdGz(tgHRtNWkB;>&-&)jzrj(rW7o=qE|@?-qY<86IzVJj&#h?Rn?o&9$Q) ze){VB-MU~3Dy@zYmZwcR@&<-_ta z0i=~wCNQa1&VttnJ}OTlit{e;q*+TdVbIN0dap$$WflimKlRX#1vkYD8-Tpe$Bfjw z*n*_GM`SH6ueb#Z5#xiHb&y?xHnHftylj z?!?t+s!HAM_@mrzq9qD(1)FNdedU)igjEjrk*{|-lI5IJ;JRlZC{}gPLuCQ=(-v{YF=)f(>FR*N^;CkG7kZ?mFhIVBw7QpNYC z%hY6I#d-`)b5aFgsvnL-3e!gGgUK}PD_C?Geb+yIC%DGwOC2e-o5 zEG%BWyYzO=B4&am27TuMtV=BCIqD@oy$yUMEMHRk&i3dU+#aq(;EZXV1sFTeK zGFrcs-KUo<8HcT(Y}{>0G>^9YaoULgWA8`WY`q=#k@dz`NN93ox5Z;plPxW zus3SDW$#B0DG&`-2-TuDzWM-!r{Fb*jgfPP?0KuJ7VtlqmC2$Io?@($bT`Ke#2GFZ zC&~vh7VCbgqBlTC9CLOJ%bDBUhdF60rJ8DwjL*iC&q6Qn$DpY2NnD?+A8a!c5bI(U^&u~o-%>s8xN}GwFBu{N| z`D2vfOMc3T+xO}Dk}}d`jLCq3()q+wI@)VhBf?kG_r7I}X+<8Nz+ZU^lsIXj^Zw)X=QOI`~3U%qJwFvt7 zb$%M#06fVAY}G=g^c!x(!`w)<@2y9s>|H zjOL+g5v8Dw;ljtfYo8tm`q=M{d(jYVc7W2fakQ+_rp{bP=Y2Fd9~760+_(|=TDtUcP@4lWe#Z@h3W1i7bWLly8@RF{8>)vl zKCE_POrZ#&$dwpy-P|c;56Q42PU2dv>{dIsdr-vMB`UpzA|$zd%XCt(T}fn)gp;Bf ztefbRGaiw#8sAc3H(U1z-=F*7hqu1e8ZHfyEkl%0s?yIHq(+z$eA30!)O*FIQyZp~ zYp~#vkm_~|f(XtOzJ4_h(_mH=ZXhl_y3AETFV0j?b9V%An*G|$^`5TrJGc;@rMm?{ z;oduZ@iKawzDSF`M% z-^jQ4)BtXxY8DG}QrJc4#KaYvFBbY*?{jT?T|7rs1b=XC7QRb*=W#wsRWCyaGT;%l zD4Sz*MdERvbuYIk&yNFu=ITi&^v+x+5HVF93gfTZwLZS->ZyN^wm`1FydvT+h;M1| zMPJCOqmho_WOtNXJjrsHa~&|duX-m(9@;i_N-dH-Qe%?ZX2sD}GjV0yJ*AT7U#0`| zbaA*m;%d*<3t%raP%;(pHmR=%Ul0d<_q3Oy=1B>An`Cu(@1$42ReD{{X-n*ubp9yc zg%$}`4Y{({D;nSO>%?Wa2+#VTVNfT4bYtN3dyDKee-F7%*1zl~q3THQ*&ffq$mz>H zm3u1N-$bnQ;#n1JI{`zr%%G*5d2Iscd5Wti{!PHFuTr|T(_kSnXrLfWZXvKwSD_Pq zWKCP;9sEc5l+s~KO-W?QMm=&R?0Lsqv+;-{kXE|C8L`N5+fdu}mh?(&;5h|LP`qzT z51;Dk-DmE=>}f6L?7^Z>WmO{#Ki&7(@4wCpnp91BNbyS!+BLf}plZUrIEztq7LeD1Nt1(nt&DB z)EqvX?^f2_db!#r->ujaVQ9!FdT^wU^n0b@dvakFi>Bs0*@{{8fQp@YhU;;SH{kC@ z-g>n6NeA^rd@?QXLvN?~9Xh#RdEsKO8!>b6aPkzSM2c!{7-;leBvY zp~pI>qZ@mKgkGduABsQZ{cHQXltbpS#S$vYka6CtX+cWq-Jbz0ebXpxY*faGnMUHZ z>Ld#lk{C64r=gwxBVMEP3Du;%*waQuhP)aVLx7>M0(7=)?}M_JhA$otu7l;;CH+zd zN_L?~!{Ih(>QNd@g=j7A8USQnD`kZ-{XK?8h?eBIG%r?^Nk#z(rp z_c#3kTL;&cQWRdQXXB>kz8W=f+b6xH=Ya+iao&*Obh`}FT{qxG+f`6hKHj`HefM|( zLxt%~gZ4yD{5I^AWuV%E3HCRJV%<0HOz~7U<{4frV(M@W`F^aNUhn=Iu~_hk*KWTB zyI&mUpIH&aXlV`DuPlmfk!@==L2R}`#I}ITYYj?=2Eva6XVfcW21)Grb=u<7%xi@Qk@S4or|uH%Ar6=!rW8T@gj-I{QG}%v*eJMcD>;1W`13lY6aG$P#NK zDv~!@=LpwKhDy;35~~$8W?(Xv5TzxdPaeRi&}-0FqYmcgc6+(927E=jm>X_S!oV9o z(qI7EdbTttn_Dh)6=I2Ki0}1moL}?|dlZVxVhj?Ku>^9bz8)0n(0OPvYrOP(?H}lp z^j9D3`s%9>zEbvadaXdhBTP;g5pYG_H*KkR|2W6R-zj25s0%y8piNfD`?YpWoKkPY zTvs8~!qBqM2Ttf6q*oYe)yX#yKG{C(bWYEsV9my}W(r;aVb_C1)I?{9!zm+U8z9_r z-0<8Ayy}W$0U|o*%xz*wu3s)_cZxE=vn0X6Rlk^{IWcE>bPwJzuBoB=Ug3L#yd^r~ z`xHYj$e$YO-4Rwwf&!IKy76#Y11TXbr}?pP5Nno^E}n3gyVz5VswL;}+9O``YS#Jc z;v}(4=eJi~@Qu#er&%MjG7wA>6&Ezj%1^m^vo7}%cJPn0l8B>fS~6#|#X3mw&gRz_ z#CUX{)i1i5=QfzC2kvei%7d=QKg^p7b2~@h=IIpRIY+Of#er52EE{)J?b92p)_*{o zH!JDs*4S5jA!vh za?FlLsdzuKGv#rdqvHk~<9HQKc*GTa7=mcC+AxO#8gAf*LR7DmjbMsp)wDnApx00{ zDomD>nnmoiO+N3}uHpAr*y7*>yNuxdZ1!NVQBv*3qN7mLI9_qLk!`zYLD=DdZ0GC| zRCW6;fYD{oqdNeoB4s_oyB-B}a49q9I`czu-U6UseWz1{0L)Xo| z7p5I56uRMAi~9J-nSU!HfeXcS*@H3^hdbe1}Jc ziF{Nq1xwWKAPs);Hd%$%*S2RRF0q%(JbNjPU6+}A32a0lCe92FPep<0s6Tv`2VCwXyx=+YepUw7D?mp-y5^5&&Xm?)iI zWuM6?FRYcW1-Jk0&|S71`p}K;>{UR@I4^$j;8Q>d29Upnv@y5h3PPaO3 z4JT^%VoW>b6#VEWNwRyApXGQnP)Zp?2CGUWHs=zkHY2 zu`Btma}SpL#^gsHW-UVP*;sdpW3bry=M03C`x+E&C`IN~7dLbKz`02@Q-TDBS+>`X z#VB{#Z>GCG^(|U-gIRq~uD!5dGsakb0oK0EkIAtr7|L2E+N={v9HZ}Pb`4h!z^@g+ zdc4gk;==XETyb^FoGRxoXH$UmUq0JDs=l^|e2+xNNNzY_$*--&i-?+i;^vzXnd0yk zQ>^;Bwa386z;=Btl5D=olbQOGzBz_n2glMh(JBG(PH8{FFxCONyFg?@b4ijrYdHLD@J7}d?fg0aryoXu8tVK-Gc;A+tu_~UbvLvlCRh5c+=*t8 z=wSQpIjX%&PA?@;Hun9_r8QycCsYQL&5A(-eAn2j?@e4;Q=L8QYg9VaaUfAv>DcaK z)sIsEaAu@rU8D-@%@Tkb-KU#ph#c7D%*J#%^<)gIk9y50)*ie1aKNm{HC;>ZcIQ4= zBs2R~+HeE2OEz`PbzrpDgP$B;WWUs(?t@r;309sSf7>`vrq8Xi-{?S}8^`J5+W=8V zx};Pe%(hXc5|e>-a8K=3C~zJar2kpB3}JWXPi&NAUTNv!?+gB|Lu^xD(P8ZHEghkHTe|8)sx=Eh<`1=}M5wZ{VD9{8glL3jV#t)N>Ztws(YFtP^Cc8KMj9w2>T zoZ>V(bh(w19SCpE2QT@it&Zuqn!MMxb2mS5NFfTfYpFF$*&eZ26Oh?;3|MPFT0N!F zR;A8(-ow-EzJ$91 zc1Fc$A=Q!J_dEDg?Q0$jBXAA85E1SY?|s{ZaCjH`wtID!c*tz_@5x=^)2a5x$l`P*gfM9sy*piRT{`WnN0lBI}&3zt2$8{hEvQrqANzAvrG{AxOc}rF? z{NXfpL%b8nyIuOFA{iB$!SrQd;)(LzlCIZNC}@2ynMg{`vr5N@Kj@|BWgJ^_H`S}+ z(A+8TfTuSYHzy1H$azx@>6Zl>vskI`Z8{n>-i7AFq+LaRA)j2*yJd=e>R8$WM6d~) zE71|&3PWygCnGKWF1gvQ)6(9QJZF|o^s)!itQI&oQnVxgcsn(0Q23a;?HeTw^g@{h zcq8RVzFRU$`=^xkOI7|z3T?C1A^a84HfKjnGD?4gTdapY1R|YI_e87Pe779m>OA_^ ztN;M6cu^61!9q#Z!tr?2)Op;EVkY>3`KDu+iX`zYPs5)bz8_xd9RQRck(0afpor53 zOSU0KZsJEL%C1&_-$(!;v59O&XMi4-)8p^oa)57H{Hw2W+Xo)1D?4AR7~#X>WD?e8 z-1Q-&U+z@NB8}%bPXPxO{tD!DSaasYNsGU;9IjgtHXvYb0R#|RS;)&g>ymJnr%v3; zjSz`8NGD9e=&1G=+cYeO)t2pF_!ovkLIQbNaLQBOJ9jVc`X=MODBgxiJrPA^zt&hE z#*fQSrab+Ip+&XL%Cn4H3#^g%zDTuR0s%5QHwMn<0$Tvg@dD{R=Or&Axuq5eVKE@V zzc3kNftoTt|09(KfHpvO-Z)m#JL#!nG7MKX^gTuRO5j>&+(!1Jp1~PRDgdhd7r^6R z&;>BC1%M!XSN;WpARPIYw_vdR zE0T>1OI~&tzhVhLx(fuldhRDwL)MmO9RR-43;GR}>i_3vwgLD=r&Xs@t-!TxPjSA6 zXNH^e|K(9Nd`Fj4VJ;i52>aVZIN=|`rNhSPTowQd1PC;H%H2H(Wfc+N|8DSeX(||W zJU~x**8yB4-Fif+HBM%!uN4ZFKKK?oEKK!)`?SIAeF045r*^pf&gZE0Bo58!RFT}m z;wntd>T*|Nd1YvD|M-pme_AM^Hh{QW`WD|gEI+&P7Hc+>JV(_aS!Nl9sMclW|592! z$8=V_aIN>B;0{7i?CC^pyc6-Zlr)TnJ6{UH<~Wu5C*PTwzZqz0wpSP1O~wLR^TGcB zg#ct+?jPXc|NaA2a{|}?onU;Cv7L45$2%8DUjJ$H;%DIS|M`L96MW13lHrH-^z_Qj zdxj2wON;}bQS$)4dKF+n0+`a2Q!>)-pM|ADE3KsI;(pg0$!2}1lA~}hzFR=%aBVkYEq4I!cqEuuMtB69z+wHUR zcnOmEnS7q8RP{>^>Eg9ELYr|VAi+}ii(=5xuTN_8E_{3^?RH+zl>Yf#E7Rjq2QM6t+IybI5#%abQ1zzsAH6Os187A^2{k=_1yYPs zj=k(K7>{TCJen_WVH<;w-}Cw~62XE)C9G@Lxc6Z0A<5K^$85Z-S~R|h7z@qc^X2SH%b zQib?nGq*bY0wfdt$G==r$?SPt?Z{7RiNLxia5Zbx<4+qpMsnqVV`^_$fZ@J(g=8rw@@?8w)=!|OY`&jNq>D=a94ydMwe#iXQ&-T{-L8Mnx!`veTQUz8po}9fM9D8dUe`| zH60iF8$IQf;w%e88Q9iX;+o<~zbU}#k7SEGp52>&j2Q@XTsn)cO8mHhx z60x-qxGs$dNgXNX^tGjJu8WYwRyyEJ{rc&lJ8qcnI6tjwV!NBxtiFE1+EE*jB>vU- zrr%PECC*3d)PwBm;(ArZsj0L8J4ygxHE3Jh2Gv%e!B5tK4v+L7Er@_tb+@8 zy}TM>t$Xrw4?&$}!xX^J|LxDcu#NnK;G?-vc5Jp&~j$P@tGd=Zaua9ZUG=SU=!5l~4h@NOsxAZm!8>pCRRdq{c_Cr~z z3$dJz!~dFq(b_4FAU|=|sBZ3UVn8h`oi)N_Y9UhoUE&0*aaE!ZU8 zS<~aY6>jXPLD^X3dO~hvRfDq=E%m6u3&r$G-6NHrBfSRg<4RzCwB3>|r^e8pJzbn$ zP2`{C=F;LeE1dKmj!14So>HN_ZoseHxwSc`PaWwmM>BE#`YT@X?c-Cqr%&rZ*FRp9 zyviYRZVWiPWFA)!s9a2*3Oye6FCTL;2goWl5Up9Cb>S_F{HU`k{T($i2{$S?ZR^_cusXE7kz zvpi3|g5xwRwGGqhmcvY<=ZJGcsLeeXUh*|JL&ayE(Tu2?-5a`caG2(#-(a@{WWqja z=;e0h;?I?(7x^H?ac6l<|23bec{c3d_`Lk#w%mPNj?V}~P^ zg9N_VfP;@_%0l{7A+2Gn4CD++IAu^ail~e`4+tg0TAmo(H`m5 z2^D~OBd>b@i@q29_nbC7_?WsoGh7PoCz>|6p-goo{S|Lb4$aE)IpbbMHiYjEb8ifn z(u}^R-~L{1c$DG0q+V=wi}Pgo0&XMENsl5Is!jIiNt;O??^>YgizEe9ilHd6^;$=5jTG?QZr2>*LYT%(pBXK7Y8K%U`k^tt zO{&?i{n+ek3~pxOGtveE+9cGYLXjL`f2s#o-#yInFhHrlQ-W?FAGYbR#%+w`_^vjX z_vFHQa~C@*6&MvLHDikcevWL^{&>YeGMPNnba&f0ehk=pslh0@>4|XDW{IWfCjPz^ zHULg<9F_{J{%a5xWEdC+pG(4&c2ZwtVCJS=lbEYdza-^A(1k)kkw}wZO@Jq7cN+tjb?e9yQytzX>#F+5ra0gq2n&Oof z*XpKshOvk2YMbVS0d{Irl1!dZ{cvbF^2FYpwyO&Gr=4gfoZ&St&4_%R+OAbu7Xjwb zJ)U?0!%!g%Vc3|T6W2+7thkQ8@adCK)A?e*Lt*wa{G0x^HBO7@6PBFkOcffqKHM~C zw-aHC`pU_T@mxti7;BH|Xc-=2S`Z@F&WD~e*o?%JWBLxI!RGZkBlP6b-l^;w#j2F= zir<)an6I6mQG=ZFA;iB=_n=gb7Yz_qsHF}$8Qt$H<7;sTZkAw z=OvUy>*kto{VtS1RT4+4{Yu~J)bIrcBZ*>*@13$6w8a!VltJLrF%$Pq zsQ^hN2*VmCzJ=)<6|nqVAdzeDA)4pi<7wg}u{v)9UY{4Tj8BLtlsgd>^sP4~s-niD;367|Tu8=~#@{Z^OU|rp8tK{=|GNja1o zdXDTR*T(y`cXj}SpuJ2O96SaO%O=!Vv$yA7mXfjvNbMGC&q-LNR232(UODCJaoIDN zYkgdVLFy!+djw{j(t{ce+rIUTjfF$;yI7#Qm)sNL?9sXQL z2~rZ+OVkxI!0iuP9lbxynY~dBZ=tQVLsDKm$8n|jxU?67VLx}KmA70K=t`)|TyVZ= zrRiyWq`&cop#xoi(1mb7hj3_ka3+fy$_WaE^^6BQTC1VYPw&OCXnS-%*uv(L>nw zaN)Egqe)d_7w5*5=AuEUI^||p4CcOsazS%a~g9q6ei}BY9_T$ zO(`$w*wkn4ufMl9FP*W~M`akALi?Hpx!=d!ZoM4Y53R9P$C3;XLE53?1_UTpeWP>% zj50JXa;>s^WvFOqzGwWE;o0UzYhCG5{cL|P&3P?u&D-OHFuRY`%5K7A00oP5tL(pR6(vqmkD)3?k)_R>Qfs zdzZo$-7U2Fid8(aA%V9J zK(=W@-a5olZIMDkO+fwh!Dm3Fs>Nb1uBD#jpZj5N6XxAT;=HR?ScBneRbRUlTeSGC z^SF}5=84%;_Y?mF!T`s(wWs6$$zM&4@hZ;nkuKWVZvAXVAu5xd<&pkDKjg~0-kiaz zX(zJU@s^EIz1RxlKoMFhbh2P*(V2LtRWz163={-;JJEK9zENzz++Nj=1}KPE3887y zHTic+*jgF{h@LzLQ-a!Cgo0!eV?d#U=Z~&dw8rZzz|0FYBY;?~;*CyQWyRj6S^6*} zOqVR$kw%~-T;PUBVr;we)9UGao5p>PJYfU`Ihr3DKBiQqs}LKRQ0w%@p-#Aw`i(^~nNZULQFGrP(Qy}D?D*t89qPAVpI=E+ML*1usH zc5WY*vvD)C$b@h=U+b>j>CFnYpx}Hkt1rOVlej9U7!?$L-mkU|lKsOmq4|~@sU?!S z3KrGR7sih@N9;Wmns4%(o?q-JejbZKm@lbC(au56s?;cY`|{k{&>qZhwK@KPO;ex=GxBv!D#()qxmPHg(H9s27?afv+9@qW zdv`HW&YEW-%&hL2KH4_e=c@Fc2!#_m3^ibXJ^x=qR40#58BTwk9L2wqf&^SRTEC;s zlc>cHPY5eF=Pn-o{q$lEMhlQ)8dZzpWV|9PyJdb(?_{4szALq(x`w)Rx-lZK$2sHS zwp|i!ieM9kD2Cbt4Gow{_~5I7RwgaMI>P#&=FH&Ll!v#BsDvoHq7>Z6dbJKdyU4Sk zaOa>oPw|v6X68g>knw3A$KQbkSSzqW&7r>x>K!07>oic8+Ql)=K{mMGRbaY%aC)VV zf97qS4SLYJ<1fUY;U0hT=xUUG{A%n%xu{LNlUAl0xH;=n)n`eKUmmh}8Y;2r-iT2w@;TD58bt5dHA!Q4ZCo1={I|(%4>Aay zt;%Z5qZR0qYPkk_x6iVBcP;x2=OVR`kPVlk_OqW{)cKZU9nk7t5h;u5y_b{#N@TMz z*8Zol))X$(v?^3oM=#*M@9a^@(poc!2uJDq`WCT9RH(k}%ZTfwmq-F9jWd0Dpwi;K z_3Q2N2UWf#^4?jxv876Ca)f3F;+Q)~=$dy0LCtsy4HGxsWtYC%Y&xxXg&i*zSn8Cz zva-;;+dPPDhnavDVaU0&$#MTNDi_RK#hD|h*hU$~TSBBTmuSwQreHbBYQkV6dwyINrWX>Mx@1i??#D< z%sa-vUr5;>Z0R;()Jc;IS0X!46}^eRm5C7 z2t&))EG=;p_SQnDtD%%s-PZ%R;aNSDM^G^AQ0B~DMuZDw+trV$xh4_`$W2x<6z1OV zB}k|rX_;H8@wrh&c5m>qS=JV&P?R5&TQtaBx7rU_rONUdVGL+YuJ=Z=tjRqAH9e=;ZQxD z7?3^r;4%nz{)dyJ*?{;(fHk7;opTtW(LtBiv>6A7)zH<5R;|MJN6vL%ZL@+~q7^hdyJH*tjZT|vST4IC}unDlYlCRDQ z_Ist7&n#tb<)(DTJHdW(xsTvR232v9b~dGP#t^Sn?cJ%>l@=HD;>AuFLh(JUL|ycC zh|9TeRwSCWk~ zG5J0j4;Lu=RMm>d0K2s>sX!FTtoJoYKWRY&T4SeETvnmhA($wU{(Af(PoZBg-ivNu z=$o~usfqCGbR$Lk;@_&d3p#GokV$KfUJos67iDS(JxxFMM2Mpsj5*>2>EfjMZR~@% zzln>^*0?%;WDst*o8l$!mifGs-Cf4PhvQLZPsqjBIs))ByEmRi8BG6_Rz9Ea4{Trd zHA`7bF9^Lc2*eosgWiv*eVsgf)R4PKi!C@xK~}eF)4vqvyraLK?g_* zOeFqTLBCGseg5o*^&!0X(yv2SR9|wV)&4^%h5ND+nR{{)LZo_IzjWTf1G|g=l-!an zSm4!6B5-ftVG|Fd9NQIdJJX)%-k{LX`ex;RId=Jr_Mwv4mhbszfooPic3Y6d2g!dd z4~zjyj1226Pt0*3|8+dds1l)FHGEsEisKQ=W|ZgPfBi$Hb9k^HXVdQGKM)}HQ`@_L z%5HDn{eN3_`#T=+wcWiJD|I&kiUehK~CK5n{lmIknGfg4MjV!ktfXe_(5kOnE6`)XX8z>aokt^*kBlf{B zf+kiAWfX=qU%V*&koWmN?D^8v+`J88l4dGq)c`<$GYTs$>xdD-iLgz5*Q(MlKsw+` zD(@Nq%;1K{^0SJ!6#JpvbimT+=&CI-X@88&}pP@o0rB4>5{u|8JdT=ast{b~Wn)Ntq z{Qmevo3Yx#rajm|Get1gxvF^U`BDLzhy^$6!yMRw_n1e%*atufyhr*Z^1e)p#LsgI z$hBeSdiC*C+Ym_=H8x%+x#>W%C&2$?aZpm#9an600VEEqw^&g9jGUTx?!Vq_z;EH*A5r>?G*iQk3#8uDc<#sY@yH43g1K{YDLfAlvV)G zW&njEC%OTt#ww%FgZN6i^N$+CEkGCmzl*;JOjM6UO)#7>%Jv_6BHzGbRiJi3uJAjY zDrvG=g#A$#_4Qhye&Exu*S?*)^|=K=zd-}U$?)twgMZg~fIwRW%Y0jUmyKM8IZ-OoOv9vaP-YLiRi66gSL=y zz)};QP20cK<7^$gtn`mU4B!CY|Njr%l~WG7erfx5rIut?gd$i=@9;Ka>2pfd4aWrA z$aN%o35*M-4I}*-?8?I$l;<9$MUPy^R1BWkDrHi5PIv>d!k6WwWwQ$$+-|&Ea!iqbGuUnk>#6gaP`F3PTwDOkR4$amV?TlKCJ% zJ)zCrk2rT(4oYv;ufC+TckWl9eoP(nKjH;hD_EyOA`WBgXB1iQ+>#U`<;dG3Tzzqx zE70ulGTQS|Rf27HG#HJ}zu@VQzMNVzF1>BP8|G*_(XkdQzQ;*#Ej-6CzeS<$Xnnx> z?T~RfuR#~AtrvVg`R!lPBMy{`2l3djhhZI75PU<;@kR?*lu2Y8t#&VyW7S`$d_23; zON#9KO;xAkj=?@!eX6ifr?qFC_dzEwfgBwIMe3^o1%k{j-*J%-Sm1x=;A-R6Io zl)I7=$9qROLb`r)Rgsk&*{T?9NN|#ZjIM`K4f)4Yy087RjGA61Z=(8Md&tLKs6s`9 zsfL-Grop!46<_O513rtXcb&JTi+iW_@9DePxvfMwnJ&q;1o3Z~&kZ{q(H0ILOdfeu zVhit&MNd^G`TubM*b4pDeAL3tKKP`M^0R3%MEmUE?v945iloZUGzb3`)74-?f8oH) z{>2`mshGI94OT(guQXCgu1J=l)4iPm6%A>*Ykjce*9k#?YUQDx*PGWSYwwCI8GeZz ze9Fzf;dz-@_vZSJPB4wGI z%eqogMdEzRC;sC1SkFDBgn8-bmALI-$1fe(g8X>}7^e|HbWHrUPni3vl%*U3q=;R+ zpBTN5Z@D9zpb+A-VLiOKw9No!n=|B}Hd;v;%YxiA7Z1OTd4o8=JJM6;mkX{;70-=9 zTn44c6r;Qv{^*2lwHo8tC@AeENI#t&!unJo%p&aB+??LzpyIc0&Qln4g zm9PsLW8E0&<>h$X^CN3|p|c%60cX>Nz#v=xuN5rre-L=w!k)ch_z+*rW+!Lqj4CR` zP8LiL_zuaHaJJ7p#aoz*Cmga+H6A1-?<6M}dr9&4_<|GO!b;FV_d{bo340iXD{=x; zS5I}Bw$8m&_kcR;eHvl(+_11kTDVu2oYEY7<@B)X{Xu_owKVO)V~cJQFhU8Aai#P1 z{R!33w=IwW(GNua04F#`os@v}O8x|^MLw1oN9J#i?NxhpW59J;zt~PbcAos{Slx$l zdDsgTwG;eR8i+yLH>G-w<$jGh(GpDkUPO-bBXJSzVHhsGSru8-VXv<6+*T<`DSf8T z*KDWp;A%(kGtgIjY#H&H%@XT0w7F&~Qu zxU%5;9bs2GWQX9(9EYN%qc#{n%N$@;ov`$ zt>|Hf^1@+0g+i>5^&L~%92G*C!@D=N`}xV!f5C z?i&Pl8f?gR$KEc~dp-zxo#Dl6h^uzIWk*}U`#WK2!@}#n(+et6NC72QrOmT52=6ku zZD^#%iDixzJwWzOj$QVJ+Vyof>Ql*bMpJF3`$mw+X8pjMKoV*Zcje7S7JPCJ7YKF0 zNFUr?osRPiGT_oC)=l$Cdq2z*KVb~a-i8r3#}p}?ue9^yokOp6g#g&dm5U31?}2Kw z*pO@BhU9Ekrst2P7EvOPb{d2$>H1VisI9*b@Sot4XM=4MXi&jxDkDq|rIjm&YkfI! zsaZPIJQ7764SQ>PVLEh!s%M8;Y-nI);yM-w-2GS9LRno9t#+C%r9FVM78leh4n)sF zP34#DdBQEB4)oL6j2?8g?e^{bt`nE)RY~{d@$oL^@7)EF$f~xHWA?7Nm--}FfMx>> zdUbWqy1T?9@eqo^hg>#+cTtZK@742nI9GW4rF`-Mzm?r&(-{nUc)bn+b{5!(PxKO# zlGKHKcRzjU_^<<#`AhupS_uEW8S(XDp5d49YEo3pmF2s2pS4Ji@Y+>B%`>?+anlP9 zrdkWNyRQx0?IA@g7Z03XCGA&1n(ds0q0L5eypsoDY(0@@<71O`aXF&5<}ZiUI61s$ zx-8#HtJsdL@lF`Ot&$`x{+r)rd=u0TKPtn&o7s9d_quaxz;DbcDYQE!XJNsTQXjFA z+7Z60R}$&}2&&5!W#@U}+1J7rRPW3C#qKF0d8X5qF~9pl?n`Rp{Q_a6dtkp_uj-6N zS=vas1G%r*2VjRL zmAsv#Ht!6ZzLo(tsoh`V4>2oI-IGD71hl{^3$J)CIsMVe;kZs*#RgUuKSRu)O0C>! zG;sAgn66lmF!D$=k2?{ylV0HC%}}v_&hw(}&@!?|bWW^7-0wFbrG z8sj1a!t%=XL!Fa`=@W;EZst6AIq<4`MWtmY)@j5d<@4idj<*t9>kD(+qS8Fv!rkDv z1{oY#qdmcRL z*{w}8=9w=TxI-%&-IsUQ7n5*@2Y0WJ6-r#NhhGJJiX9@)&?-#zTCCDnGkiTg zc;z(pKocUu>Enj))d?md+Ajl#Nb95=e8l_T_-hEHPT14vdnbfOIF?p zDM^kgL~)$@@a1f~odbk7juko^bGVA(R0f6Z1@}yI;;Iznpw45Dv6;q9cLFUSV1kn2 z;uAfx1i##yO;{}CY;L`tL6<@=Kn(V$mhK`t^Vf`ub1EAcT{R7i@jNZBFFqo$skC(K zbCH~ib;-JmY6O(Fsz}EHx$EOuyhF8=>PT4wR?4Bf>s}t}Oh0p_z*X9MSIBr02fII_ z#862?hxin8=ePRON3>+kcax&7rR=?J|yVjd{5xGXsS63&_YAqyC2@YPc4~p*tf;W!cs4!F0@|y zAmeo=@d!Q{Mq$=T8JK^{NVS%w}LddfdJ-oBrF;if1 zYGxU@%z7Z9G!>mwF&8{rqy;YWs2d(GiY@6lX(y`%udzv5Q;9T6jSu8?0NBE9u5^)G zTkKYViVwDNeKymI4{jFH9x7$Lsn<)6Sd^#pnp`$#gF<-tR|rzx84%SI8T#_vQ8(1^ zw)EyYl(F435fjJj=P6@mUp--FX_MyV|RCtKapo2khq@nQ$swK9~NRO`wN&AN>Fnx5|Zus`0H7HfSw z+<3Nw)!jm}kuy}G)40#isZ0y?UgXRwr1))Cfoes4WF9-iVaKQGgW0x#)P}o@N2l++ zFl{?3$wBFq;obe?ixUAp1-{+%TFM22A!bKmsa%n?f?@Q4ael?g*O5Ca;GF?^`fSkZ0VKkz6Kej3LYF5d!7|uGT$h2}#k0`MaAm{4M&G2$C6X5F z0s&|R3u3lfqQOIx**w*}gBkG@pC?jQs?k)osJZwaCJLY0*AY524)wF{hH6!Q_u$gL zTKXW$%WY=W0?4s+C}>l5&kWw1i8##}6%jJB6Mvn6a4_(ORx4~ch|;~eGJ@kU^s`Br zWJNfY8QKGN-scY%w^izSoCY(NME(xeXV6r*#YeBuf>JfY!?@Y*PW-l%w@Hz zw(68-t>Q-@3h(To(q_gzi@+9sCnX8p(7z+ociPOD=TFMir`Z0&moSMPd34-n(RodP zt2bS}xMC`Lcua20Qkd`w-Vemw-nS{+0y$73uRh4u)c%%57jXvXNw7sJ~_9u?MR!#r@GOBD{WDaWQ*8L2;67b~QH)WD~&nuHb%V3u0MgP9t*KU7cB zzTU~Rx#^)11vT_Ppl-UQGn^>3IyDnwR)169Bf^pg$mRj~Odv=dObmKtI6yB%ac6d) zs^ekpXHvp9$qqI_fkFos`~$R-#F;tZEJ@#pIR+sqP1LmQ>@NG!2Y-%y?nrZI9x?b? zleN&So$TZ^==JKELa4OFyi8@5u)oL}`=(~+ci0G>LkxSzRb5-AwOh|YklYZ!2Jw&9 zXk>fCY9>9#{kXt0X78bL>PVN>T?xeM5nHmczM}QsCe2tST-|68ofP`h8eI=sR0S_T z8XOdO5yy%wA(SMjSop`QT%loax&@&&DZTMZr}~Eam~SKSErHh9dqF-!X!9NoqL<=4 zhSl_O#$+Lv{?y^?n5w4N56LeT7x%wiZ0@o}M#KDOn=Gnaq>T^NjN~ORg z9l9{)tvJ-e*Ku(z%%vU0%fj1krPWIClCZ8!StkU9f8sNjM1PYY_Fhk8R8+oRpLE8e zLyEB5gobj4{?kL}%On%+JmT@Z5vCIP281aSyBsg;hofitr&mdP0$fZsLc6mj_E}Z^ zhYP1>CY|opQ?V3iFQMIUgbe$2wtsmh3aHThDkeU#W^Do}CaVp~U{aVrVeZ1#-SpP{ z8XTx}&XP(VGvOM&Romy{JKe#TuX{LCI-Q`N#?{qadMfM>zH`6b@3WlQ?<4N2?5jrS z$5beq)Az7H17=Xw7bbou%eGa!I)`~?;X&;y=B~sbTL_W!V^fQV`_^kW`rxmNy|UNV zWDO*s&oww#PpK?r-q(sm?|~KFHB?QNoe^1z=5M=KRfim$kFmo7M&WXEOt0G1;no3A z=9kRNb^|1Vjb_AoiXV~eoUR?>Kpuy*v~*?mOmIVX#IpO%Vrfi=ZDh?v=v;~JZKb$I zT+aDK(ya|I`vJ5CiLrRYE2+}`kF|J%HOhHPlfc09;g&|6adt0dl7DKcKFeo1;fJ6y zRPq|VnPXfrky#z(99JUxJxr)y8^k67^U!0;@YiQT%Jb{XYqQA7-ogz-)5~BdUkC=A zYd+LMr93R$QA%) zzn}WcvEEiqse$-Ms73fWE(zY;s6@QQ-nN#1W=~_X<1h^C@Gj7=Pj`rFJ7a_VQTrsK zHZMLLQk)}_*QcJrgj{a#t#s-32|J*)qta)* z4Ey_8cIYmkl-pRITFH6spjp1J>sVAb@y4TO4{hYw{n$x^zU zs|V^^d0&P8n-?403$6bm;Iit#v}7hM1}#>HfOz{`zVFzLeOByxgWJ9+cl!doai0kl z?A#d#pKvb?)_>l^cQ>VeA=RTyzUQJ;v={VYFZ(q@7<7;`dWGJkXu#mYDwU>0Cw$OKDwbiAMdB7yR5JPS>i+6oV)U>ITxB| zA?xyItZL>k37fVU@aiiMBU|i#Kh+A_v!a%@&B`UEh0Rv&$9P_AIJ54~yiWE6T%72t4P@=r5<3cmOOW zD^aQ!Nq@OeC(X5Yd=V<1Qa1ZnUDVm5#7zg~+)qd3QVh#WFIatemBV(uEZs)XM z+zp;Avd#uqo1=^Nv5F@MZwlp+9nM{d(Skrp#$WicRJFPfWB&5)uOo?$jV&%jZGS(l z72Wekds_GQeE9785mt2;M%M659FjiT%<5R4RNn7onQiPgXV#oB>1qT>M8Xah^wHKc zJ|5;I>6XArT1l#m(?F1V@ML@nns@OBkm)&+U#&aEG0u1XujsyuW~ug=^sFZqq>&yJ zdKhF6AKux0%5mX?@$_1|dS~4eNVb4)IMNS2U3grd^3@@}P0-wR#u4Fp0{e-Xj%R|b zamD*+yDdWULlM@3!$+lh^jKO8K?)ye+9dJWBY7JoI5O9D@;k|om3c*8r~^EONjw%l zWbfPOa0cttBNgtsL9;uXFyf7+1ifWuJ`NlHDD~_z?5^BjMzmi;Nkv;sJD4lqBYP+8 zq}RUs5Dl1OTz>^WG~sCTPfreMKGsmd zzL)Y7p|FT(Ao_~zHe#}sU;Qp|1L+aFd5~X;sIbLYSjlP2HDquvRbSHP55a54kdjID z7L39;3jvqPB2A8-EAJ)A3ZeH`krXeAtxU&F6O(HV(m~YeZU$|@;Mjj3e zCY2;#yD_kqP~!7^EYteOwllb(m6cFuA7QTzhi=gKnK3B-&`6D$=7_?6xl4x$eb6e!eQk{|3;mPj-#4~>R>;oDF*^4a z82a{W6bH__-Qk$XYw}~?Z#FOFCVPkKVJeu=`e&iBaG)jxTm#QglTkgv z+>z;j#_)M>C z&5fuQMqh|pXRx;EtX)^7##0VpMfhPZ8PF7EV{quTehQt`{&>U;qU+$?Lq2?{QHY@Z zc=D|=LSL}OG~l2dC)8B^p=wAGEn1=`jp=`Ja(cKf@Wx5dl=C}M*j;?mycp)+dI)ziG%K=}`$ zLcHFPo^=9Z2uKzt`L0=GaM81&zSH-vtO8|n3iaCJ`v3;BAoto_n`%#6sxIcM_8`_H z9qLTBebG)Ml{DSY@sXpY|CRH(D+2wtkgfi6NUoE_D~6OnM)!xX_+q=$^6(S%Uvcr` z`Isx8yPq!*LNbC@Ns0Qswu$?)w?<2?*STBIg^(*B!D`aG!TTF4FUGPmfX^emp~V9X z)LPbsRI-dSL+%4K2<09xR(U!Jhr#~LA2HiZ=NV<^xP|N_V<07|>u1c5-pPuj>VAvc z9OqYB!}F^E*&yAtd% z2ruPH-7q<3AmD6j?}l{Xvte@?pUCrf9_de}?q@s&K2bRxKF)PKA!W2daXcB_HI5yB z^Smd?r;zZM|FGq363-=n@lt`CVVu};l0xo%J)c(-Qe#!?VN%uvyZs<6Z2k0Sz8BN4 zXo{#1o44-1*=405?+olj-XaozIm&i?Iw7QoFCB)>kL)>$D(#}77#(eg6&;l)`<@{-N{4w_Uy`uBK~sFnoyJM?KWhLTR8 ze0OG^LJkS2`4M3;T4tD1AiXYaMU-`78HK1l4HR<4c_5yDD77mD?HmJ7(U~j9rXvP4Y=_S?#;B zQmB4<4WQn&<%AP)4OV*!=?)B<-re@HE>Q3^bn)?7k`Fen6r`6sjP>-*cr~~OMu;Tu zwwgR_>i5oB#{N0Re4G-t>_5{5Tzy21A&*D0Qqx**Z|p-U)tgsK@|DiXdF2WqjyA*H zd!nz#A1jW+Na>)&!CfRXKiXpA3366TY0}laB=G%yW)SQC zPAc%xB%xpwbH>u&yo(BbR6Nf+o?W`k9Je1O4Si_DEzi~>PTI~i=``HAfzDZ?nyRKm z&q9fWhI^tSP;t64Z&j+ zeWlgB)P5&rz+sNh{*WaN8Oww5UP1@2vLT}iqvr2E?Z*iOEY^fIZK>|3S&$(>GMhXO zZK5@(i-`_QxY3{0J(JM3_?ZG*U`tr!eIUZ)x#m~-$FEe5NrTwM!>80;L&ue&rF*&O z5A3$e`$bc%i%-F=3P#airjhw$5ju5Q=`QIgTrqCdXT*cGa%D0(Iof!DIp#7v_XBM5 z`}an4{sFEcmh}D5nu!M@_C%&u~x?o}u(P345d71eJ^BmdP6lxye`URx{Q$9Nkp#*sfag2mgo;|7*AR z<_;4TdX3lmU7q*jH}p^WDNNRzeQjz#^w;UZ>3^l#Y-MQsM^*GR)!fiC0OpDR!hX{w zO2dmDys9^w00m#hpehW0K4HQj&kbxAD^BHWxZ8IEMDq;6cancAy;-K#&9o%9q`UX? zVfSv*qz=JM_o)3&QLK+`t6cw?x+MG&0-PI!HY{2EwWcqFo?VjAtnOenuIX;hvw8ep zqtOhD5V~t)vlbVpRhi948jt?s>%(ZV5Ot(>viY&A!^?-`M;jJ>S7e;i@TW>HZZtUG z`xWTMMf|2>c$j1o69^mQX$Y}({nS&4@7g$KD$?w>V#wxW7d$N6s1}bJ?&_ji+VEdG ze`+S_GpOyx-Dv?qa@BBnaRv5c)2-JT?61qkWOS>WBHUWe_5SKyhx0Gsib2^etC{xV z!Fq(Qbc9a{V;J4+*8y4JhUQ#n-GcZjrA}A45m?dC!(ax8CtSdx_fMdK4~bL~T6ksA z_fGumD^vRaKgy4vV6h-(xsU1T>4v;^|AScCqOEOek{h`B{>)#5;()kc%mA($9)RfK zc|(2G2zP+3s=R_$q;>hfu|EI?NqHbLZXrMOZ;t-oJRHC394J%z@Pg^TbO{1Avjg}j z$38&&7wQ21nt*}@0TovJzZxx=0F0A3FI^cT-6h{z2%s{|*p&IDF>0Vo;4aZWO3@qG}4>DW&Rb4h>BD#QYE1sY?%p zJFgGp5_FyNSz9*m)c~uSlW_kFm8!^~mG0`Z>^6tbc>TAc)bBUE1DM)UBM7x4BfkH4 zjR6qo=PRTn(2n+DBZ#}7{w2P+FkP9RTDj`Kbg_2SKRrdS=r*-~sGqZKyGqKyd*x`s zRpg0!qaTgyG-{%ErMIReZ;gGEM6ww`N;~V%qxzB^!phHxGq+tnT@fGt>}ybU4PD!b zPuGs!_^Ke#Q~77Gli{0y=93o!qpYtaT|0h);m$TSZ3ya{o0n(ntB`y}T@|mtZ)^h~ z9Bs(TqSPdhzB0Pz{A>RZc;*_OQ33Q9k2&zt*DiEW-dNuUp)AR(Kg3@-Vss?CZ~Wu= z%qS9F_bX7*$`A3FIOVnf)Q$jvcCUZ7yarnI8lDuZRox)I4Ef7UfInYD8-)$@XlMMs zGyRQ8d&}x$ewWtb@25UJoMsIJUH)qT~L@=x0wYKwD1!t`Yz1skgL0yO?3$ z19({$_qOKUH)kG=!Cf+R$r#_{Cg!BpdW9QnY@h>AFE3?PRn^J5N18*V>r#Ei`|sC( zFDwNS+8K-E&4!*UgFI56%OBUK8YJvifDd~w%b>*0zrcWI6hj)M&k`PR)vESCIm;gD z;o$$W;n&~+0|6kQrmSoHGU{S|bui|s1agotc*D}wy}E?bzZU0}!)VoVaNZC->X3UQ z!;PIOYvWeFZ@v+slrA^f)->Yg<((FU+mg|Z%l|5^l zmVR{Wz_X&rL2RhCs8A*M3+cY~(2P*3F{=t;?)rR1LVu*-8&ugXra97;bunHuWh5OX1)`ngOp7*Px> zz4L=$gvX=VZn!x^cA-)nG=-ZIV*HG$V$ZnG zbkBlYiFUl8%nftz{!;tNui6#ZNvuuomv^k|6y(9AogMPUt$MKxk#0$zGdAacD)6n! z!UKIj=>EA~>T0iMPJd4_*NJR=#Syb_8s7CDX299xV;6Q3kNZ-zA5$kBc@{*^4eEQN zQ$MY$LoQb`EkSvyj;(7+mMA4FXa$8_H~m&6`~yp%dlu0;I|OjUg;jy>3m$LIzw++d zQ}E&%xCf4?QWBCCeeNtn2J5ZBaCZKL2;xR&CCpi!8>CmyhU%<;C&N7NeoY@n=+o1T zbNRAP2&aT*uQv0oH2n~mayp}>D>IfZSFF&-G;fgx%k!^Y58gT%^~`_q|EZImEiO9nLkB?#CX? zd|IZWEKLZo*-w@gYs(i!;ex(f*Zh4h{a&Xpu%`mrdqptCI^iBr*fv$}z9Uc!`U=HM z-M6w`O;k==pfX+RR;71?8NOV6KYmwk7~HgEwju@Q>!)>Mqj3e+>ggfVm3>na)x3%k z^*N=OZm%@&(CE9DTWIdK&u*?x-{&E`c#(J(lxK7K%>{fS65m+&{S;&|3cnZMq}f03 zA7<9}DlWyt!I$Q)`<_HUd*ys6o1ZZ`T^D;;9&BmdMx4d%UQg?Hm>MDPMkIVbk%4~j zL*UGJX?9|2cPl%nLFk!G#Sk@JK7qJuiP{mC8RmziPMel^cHHsUn(NktE4R|=J77H0 zw05eX7*6p}rujK&{rR=t2agM$PxLi60w!r$$NL&9jL?J2ZRAU_*$! zXk`jUcdlhzq>aqw{^Qq{wtTo8_QL7Yxz4hf_5gxqF_9{@yX;=Kj*U1$~JO z3ff8I8rrCQ+qF1E=m?T^L-)vi#pUC9gy0e4I?*eIq+KNuXK9=kxg)Z3SU|F*y67&J zXg;t@3zhCu>Gi9`B;UR5zM)OoDaiMgXBWUU*#_!Vuj)?;=ZOn`>;(I_t~D$U#&&gk zzrTZ-^d6-kjMD4YQ`x#w)(JUYjgp_9yaA0;r+3Rmt7~t~*1f!oCH~PptYw71RL!)z zRfzuNFm>xxfHw57s_&8E9GWa)xQB~PZ>Q8+6$h|n;GNti9v_8!2|NF2_a-hbOs<{^ z$bzx%Vxsf4s@7w%jaR8`t4g@bDl2&19Vy?Dx=uOqwfP3HOB7ywpdQ})jC4_1C9m&# zSFiUuJHtVt|+Cb265AQPAei`6ZC#HeHi0(L`d19l_O|ES6_AmOM1K zFuR_jep@C>_v%4SoxnAJSKBJKtx=G{NGfr(B-6w7`V0K~{vPC;9MNBO<_*r%H5+}! z%VemcTf}`9lCne;rj8aBBf5fw)1&77k!5mdKH)pEx8O;$5NF8J+s0=wx!jA+=nWR{ z?s-gVTw;RjMo~|N(ansH;~oPO8aOLzBiXIed&2ziWx|j^HS+n9|71Ga*VzH!6mGiJ zi+teR-%#=7rR74mR>Pp#hAB=?e5fMw*OB|q$C&j@u9lstmFY~f%oCeQu}3zII^1XI zi7F#=%BbM#tsM1xtd(T8P%FP#gQU$@b;InhKE88WB#t`G=PK!jBq>)u4($|~A7F^` zAvyC$E0gEO(s%|J%$DPB@zq!UxXNAZmtwROc$H5-veHQF{;kH?_~%lFXsT_Fa&d?| z?u|_p;*jZnry=2zwkaG%B(GdZa>v50yAHgxDxK1X4Ozn)a_m3UyChG?Yp;9NImM}= zUJRx^t+3w$id@vH5DTo)MP&{8>9TP}?;5w&o&K z-Y(r_TT|pwQ`b%nLn&8;tEahi5UblZ@<<&bC}v zDX&Z&XA+;*Ni%68q?Mg;SF~7Hu4kDO`}FZgeY%5l1o(uec6ldFVsu z>W2e}{TR6|K>EapZ`xTF&J-#@SCz&%1y2}bEni<0{)pJ%P+spQAIz?=PHyxWBHClc z%}P@TDXVh~tM}|-D9XD6Z5wJfSSb0Lc5YaLi+t_F^-!^jl0K%^ENqjqR+U}pcm}%D z(cy}y)yM}v5&r@yux?L019?)+E$#Koo$S=jW{919iEbqetyVFUN5jEqHTt^Us2Z!m1uaNgKNw}&1bt5cqCMte?QTj z-<0Rs_h@W*aPYiG7)~giN^6eX_NFgRh*O#)AjTt$E``_|YY3LZlZ;rOl13>m3o;^a zEgwv{dpL{Hlu6g*`VD!pCknl5$61W_Trm_bL4D2VdXj&L5b1w`NLLnl(rcU*0milS z*qokIzBpakV`wPxT=teCjO1Qvs?k}WQQ#G0)4g_`i}?dWJv4i{#YM4C-Pd@fU&Rt{ zbdj(>oDL4WlgN(5e|w8?!U0u`9Mvwbx0Bh{52i-GvV)HDP5mvJnvWV+Q+M{l``O$c z@vAdpT#ASEPamBAqjfsRmfQT0d#G#NDyi<3YYOCwAya@?W?=%-b%NJM<)tsDtnl@_ zKmEe0o2LWlvw@UwqIc&NeWk1NHzQd#{AWMS-;?EC`SjXZlwkN`{mw4TgHj{LrTBQJ zM531<;~^~$A~w}@tdF`I(Y6cmj%!KQ^pN0L8t5Oq*(hjB7V?RW;ZS5(MHZjgg?`X4 z5Bf@t3q}sZ=&%xNrf?QVt3SK0HGGzZUa56%qBwNtOrIMHbB(d>V%K`8?5Ej>p+$o< zC6u}Bi$>r2Cos=$!V6cPMit&)^|?egSpcV-o8RtkaZ4}sDmKJTu${^&cV1s#WQ|B+ z>`o6&8#HpJ&vrVli}eEjF6m-fyYUA ztv^U_Otut4x2C4fch=uspB9GTtlnKrEtvlSbu?zJcS+Dy>~X@;danh$2$-N~Lel%+ zQi=YbiT!qBcEOjMOdm4OnOtDo8BMk1BVUaZfLPZgn};CsOeiIl7$4)gTl0`2f%mjC z<;;5D;azYuB+jQ75($ylzdC1>kOOg!G+#1<$UX?Pkj7Daq?59Vp?uTvSo@=-Y;-Aw zns<;sC`E6bAaPSQXSY;)TCchDYsEJ##mp{WDEf-P96V_nmZzhLZq1Bbzti1YH*&l= zIA(2{$z%;MXjPwVFV8n1$vDf~i%9)Gj2)i&*8NHt1orA>L=GK&Bjus@f_p)QQjJP-L2;eOx0_bCuUpG{@()%U-URt?SvpMKrhNVW+|av+-B0Qj&D!yX&c`!4 zOTS`5^C-ND;v!bS%SFYzS6I$IxY{!PIR@OPD13SK8Tyol*C+(#cU12twau~K9mO?5 zRNB>Q2;R(IC7>=8-XxlN}+dktz4Fw*NLAq?6xYdu_JTc6DpN(F@MT^_8%Pg*lgI;r)+W! z;9i+os4Ypf+Y-z8IAumB-_2-rb%NZONsK8kVML+m))M0p(|5<3WGx|~)$$5PoXPQj z-kaEeLvH0F`F}3<6GMU|sU8DwYc~}M^6_dG3#S6_EJ=PSsq~kcU_TmXOYT>wNy3zu z@SFlZRSrs@ANI$mUqZL#>+^m~?G|-&#^cxH%vfr2E2oRmb9OY&m9W?u|06zRURY|7 zNGrswc54~4{|@1wgY}XZAKSmawJ%3Q;ASHoI+S8s*eAvS-@H&Ned-aMyX2RZ1zX z;SC`i&Kmx90wXP~8S!>+Y9cqcM*ejlc9tn14#@oO_37>Ja}!y;!PFUvyv5fGA<_e& z+S_B9x^k>^FKI1ErI@txHy&p}4xO}SU(J6;cu%4;b&GYGIifP!J=Z6NA$sE^YUZl8 zXz!m@sk>EQcFDI7A53o^Z~ojgpTu=Z7=O1oDhu(1XX6q7gOdS4=Rmdw&h@jRthIiR zPvL|4k=Jg0&QiI>8WDFM`!#}eL;o%Gp16B?x5)vyEsf+8AB zIywksrrg9$&Knz1GD*~L&c;YfZc*&#KiahlXv(CfO-d*D(c9-a3f)TO$I2Ids6@*w z%Ny;n0OL$T%BIO|L(g&C5Kr1}`kst6krnN(<*yk8>`w0`Zg$&)QY~cdsT_g;v3_0b zo%HK5Bjk#E8Qt+_m7cvdsf~E!?q2Wm zp!K(cpUwc`4omx!3J>kBep@FP+Pk_&dvj~v>BU;=kh|CP)v9LDsMAB=X|J}#K~piD z9YTwm+64WhY1jU9=6#FP7Q7&ooV1|41ncn+X7^2l7O#O&lYzpsKjWN$FePFd@P$>B zb2Qf&)KFcC6ExxV*uJ=}a?6qq_X%QV0RGBkO1KV+Csf!(Ac{UO(Ksw~6+%{})(4%J zIxhY`V2A)=KH1DbHE&1cO}1~KXo-WaMB#&PufVU}SQWWtUSRH;coJj&p6k#Az=3OU zC|Z;(?s%CPnlXTV6&>vsyk!~8e}?ZwGmy=AT;vO#b~|4j|Bm5t=ADkkrcaoZ>SDd3 z=qvRNR`|=o`DGD&Qw9AiAI2Po9mvNG!8dEfGE=5RYL$|WvRa(1$eL*7(2=+zjK6(| zine&#hZ8C#D~!aN(c)1*<5?aotF+CMN$j#gmn&#(Xz#eFVA44w|q$9B(y0O$-rz5><%wK|$E^h*J6q zN9DdbHpxc%C8S@c!8_@rKiXWp-!ow17A7zV(|)5?@o!;4az8UW^I4YhkaivPwjgK& zd94@k-IWfOkM{;M-|Q2vFg4#x5$FjH-qsjWPv{QUNOI}rTHmgNR@R-|{K1gFJFyh? zjP$2WEg?GT%VE_XU30y_vP5Kqe|3p~1h63-N7kQ&{d7)F8xC?!nSJcaTgP*GkNO(g zCnQfGHTQzYmy9;9+7?;#V)t*ftPkZ`2I=#D>@@9I* zGe15(X<|id@li*00JG2*O1w8QCsek=NVd#zovVNKV;1W8R${GEc=Nl-eUGXU<^9|f zQYl%ElB_r*f+@zXXyWaJs(PnA$Wh336-%s9bK+xjF+CkF7XtetK(!~68cQ+h=!wVO z!h1t&D|L(k)st&%Q(A;fM6qW6t^=aqO)l{9HHdsIb>ND9L&Gr+2syhm#@g|7X8X9l zbHbI#0<1Sz3~EPN#HYd+>fc`Qvf43O{E1CiC2{}8bXFsVZPTM4>_YBD zou`tf8n}|t355i`Yx=Hih>tT@!RQe&kACO8#r1oJDE2ds#cqLxsjeumz|12{KHo_* zVuEe8%KBL0Qbd0ab`+o=og@Xfk9aIQBTpZJ3~=wO_-h2ffLT@jy3z=^u6hB4SxzV+ z>kYMPc`Bu)r`hbKwvUi96S?r|@$|dQUI|s*Zn6$H8=a~f^u@`Ct~WLwq@>%x;L`k0 z@vHG|UAqLWEBn)nTp&pMbxt)9yU&qmL}zy18rCR=qI&&!Gv75JN3EJ5^gUcGQDvol zxjpv=aPlNWqo9pF)5ABWSbcNgxY*%4sHu(cgwG1-@Aos>$Nk>4SQc6}CW{|-dJTFi z2x<$G9OtEzpn25#6GLYjH?AfNR@e^kn3bL0EUAnX1ms`%qpvwbm+Yxz7}NF)ce!IHVoRm09*VQYpam?Rq>T`ZNUk zV|xXapIAUM(%Y$tndMq6&QC=3)<)@n!pOb3@}tMV;R#!0MR7Np`Lhx0ce)PiMh=>l z*11?V_@WR?_<^xwJR+T^xTdh^7W(G=BZLYMNDszbqh4L3Jjtx&ev=hOsPeDo+})BP zmR!+lQm0Z~9`Fd#+h-p-&y_6KbsqYC?$_7OZu2rzYoa2s zYyM(LxybN1hRAr;-oRUSQiC@k=I%8)B=-D7kE6HW#Rgp;Qo}d(97-ZP13OBKy~0zx z?%Vi%$w1fpj}^DidC`|KPYAwgPtt3wFS_U3yJm#RCn^b;V|@2&bzm1LkFL9cioOtz zxT6*q#eZ9S*!$zn?{VGzY4P5?-@IU4kiA41EpL^0L3z%7Iq!+91k)m<_EL(SWx8FQ zwZo2Idr?W|`m-@=*3@z%iXiIJ@yZ9PC{R>q^t}76kbZJso8ENL7V(JcjQfXNjY32YTKs&DL&s0K3E^8y9(jGybK>ETMWTx2acKX{5`fxsaf}x$=WQy90_g*m4~@fJEdHf(;eP zEhG3r>qUKQI2&p3YN3RWl1<1r;_D`7J#=CxF~PsVVWqZ2PhA3Ud5kvl45NMH&QY8CC#xNK=L#J5{7i|6YFjp7jxy1h#&RekHn5Q95|7xuk>kkz~p4*D9( zBPI_z%CQ_SX~+7=&O^h~G4b0{x4RFFXaJ&J8C)5uEemEFcL;}1*ycr7AC8>Qz>i!d z98Mi9S@Fq#M)|x6a09Z}@zx}KNu~K0s&fP6Xqyst?=5K5_GtGA5@!TjtE$mFuuNO) z-tcx?(aN~Uc~FCs`Lvo6W7U#-X=V4|)oqscpvtgH4ttJ(ELtT09X*P1a2Yz(F@hDWb4i$U7DqNdU^N>;N) zkn%`ZwV|5%fP1{M&>7Q&4bV}M7iSS^Vm=*|nr56v6*q2B&+SuOq8D?Ux_~v%I9igz zIsYktz$nex_{ka7$Gt=-qDrgbENo?Fp6!{CeT7x~7j;nKNfL|uV%U2c`ab~21xNr+ zEyIzaJXGhnB~qzCLQX%MB<~=MCmbKB%WywP*24t#uw za7{#u+gpyn@G4eqGGMDtOckgVo2c>iUD z2142pxO{H(v%G71#Ld%s=`Wg_1R(D}%;aC}yIiZ|f8TFv0zer2LIY&QGl7kbjOL6~ zR_%@>l}e1SqGFYl?cNtXcqo%3Xp0+`E_rperabOfS}6d<4dK`5tPm>@2P;AFn-NY5 z|Ibhc7C+Vb`{(~DP{HCq9e_apUv>E^)~Eh0Ud4IPgJRh35sNYp$lHj9*H}Y(hw0Jt3s3+3tMi(%(;9f@&4iT}LqN3- zR+aAGeTiHJJrMMonv&bd zr7VoDS$c2eQL(l(NaNDBG~swS9{090srlcp76ztSX9|p|-t;mep6FHl$50Qs0i6wi z3_KpsSbZvKT@jKVJIEIjxcEP62kSj6~>V`p^}&EP}jH*P7l{PN(NZ3gt#Pr5Py zn$y|N1ylR?^Z^s9^C3r6Jgs`A$Egg+z@6#7+^oT9!LcVT80hh$?7_F@=74HZ;?7P- zwF7!V7`7i;NB`epAM$&)z-&!W?pX|89vEfbhyd_9$@teQ(lyD=jn|3F7=pQLe>1b`|hA)ra>;jR7I)Ho4^kz)-Fy~DGtEFiS-$5Pgwc&9!m z?SG8C9|V$QKN)cBtrTeEH6-i6wXb{IPc=&>qo2lA`~BoUuwoz4Cj(joL6Q#*j?F|M zF1m*@!I((}#_ih=K!*!nK08Q%QyaV^@89sP4q%+whamQAu{4|2Ooqrw23WNWbAWC& zK2;DyP8q9M=l+MH{r&*4GaYZH`8rN(;GB45ye$vfShGvmJu>BJW zDC8K8Yru~a&G#PvpxukaEq*%M5==tyj-R>z54|4(YNMx}0Ud81`_ww+L^ze5*<5mT z$jsbX;M?{OLG^zN3c$M_%o%}@`a;Nql!@#w>Hip#>)fv)fxEA@%@fV_HL{(T|DL}6 z55JXo7G$ev0y=2d-L5<$dl^1twD`{q2Q>cmdH^PiTO1^Jv+xic=;tskZWpQc55!vs z@86QVq@A%WT;Qc6Df<}TKj8U?xWa$wwTQ-*@GefoMkCs&M)RF0Qv^c*sVDwO>#lK4 z-B=FwPvXuz)1uIso9xe`Evs0LJ&z27ZdK2AcGE)&)DnWM^hx(*iXA z=RcGHz@UEW{ihQCJQF|-{YTSZQ}VOv|6sfS7;yG4c>rYu{i6?)-v$PvarItym58JL zkAM&Tf6#2cWnd98I^LY52x9*^PkJRLd=%n(3?r-1v;RE{u77zF!qge*zmpYqiNjG1UHK779YfB*gBdhz$7`9HSDF$GX_nR8AChyqZApQ6?49$x3^z}$#!I;usLq1C#psIX$1=-dAc**SP0JfZs+?4DMC>0Md z`~;?05#l{ivRQ4EoQlI-EvbT|sX9Y(%#Nzm54))t?hK{HwKMMhM9m^&dh_vX=6?C# z$zW6(#CT&r$yZKas+1ecgn!nLe9AA{MA_|Zi6cTFO9(kp!Ha_12d*WN=Wg z{nD>QAO%p^nlTsEgt{~a(+T*u1BBW>;kinCBz3>dOy6+y(oZ#>)%x3*@e>!ftEGgy zEAd{+M`y%l6_B2daAp55xw07d@9B1zfh9QniYdVIw8xAxNal^{$MNq)sn5__x0{lPe&wa<7YC*U|W}z4HUIHGUjeFJp2m;@a;RX++uGVhSUsK5d8|bJ8N-rMatck9Gz?6Y*el zu{WS{S0f(YH@I|ot7<)Nt98ep;TOWy!s@Tx>Jw7{^uB&^>^(+@#l$+m-}VOiJ&!2y zRpUoOV~UV=sXB**O7|J7La`%qw1Q})jj*u)l?|+$cDG=Lpe}|jFTOB-7eTS2#OsNP zp$5)V8wUovk$&!#jz`#up8G5_UFXL3sVP=CZ~XbH*U-NfEsHHlf>5*1zh+X> z95PFiv&05_%VsRH0lTaBe&sA=MqA2Y|J@{&k#bmi@G?fG z4x#RQAnwGk=5PlmcI!(=O?ZmFlK|D%?0r-J=(?+V{q)4e2AA*aAxpI2Av>R^NGwDm zAKP#T+TLsMjpP(nf%2?B4%TjO86c0&&qRg0_t)&PDB90Uj+csg%W2lN((!^04N9{F ziT)17LEwcdTgX^H7ZPtgWJw$P3N$%%!4%%-e|J>OI^^7vtR%kGqwzcYJl{r06e%ZS zNDC{2U8B!PO1d#j9BhxTMCkCyahb(4dlwQ=PX>IDhtI-gkdV#xHzbp6k~PjCvXQf& z_#D>`4a0dnT7gUxp4CqXgnL=kw8-{tujv-_xrbnS}3m3DnZ zXDt!(=mN{>NpIRal^F&TdKp;$NQ!e%>>lGI^j2u$b zhMt)_iszh_&aL3`g%@gmKU#N%zI(pAd!<@yYzcUbZ8`2qN){!snrpS+B;6y-D-3eX zVwY62!%!X0+Qb1d(nAx?PHC^sXcpJ#4wd0nXl8` z=%~4U_qtanqZYitOm0;o##G~=oulILNassVd%f?Bk0ETx(WhUSP2d-sOZ>z=By#vpa z?GY$ysx17c|BVrXcn3g`$U_e?Dcy||)MG3#F}YAJ#F?-WC#&8^Tos-F?i{TzSAi{0 zi__;EyN01UReG9A2$W-MV+-ue-RSNlSNHfVeXYD$2CRw~92TdQG^uR%WB(UEKsrj3-a7#l6&0ix=_(*nLTI4`LJ=i&5J(~= ziAo6<E{V5V#BUx3~BE?iuIYamM-Q-t`A#kgWCQE%Tl8UGtgqnOo~i6^ag_K|YfdryelQ~YRe*KLcqoz4 zj}RQEuQ5!|mr=F&uSw#>St(C<9@&&gqKGPixkaVq4{9y`QSLVRYuhyREsq4%?hLNU zb68|SyUjHx#lc9kYSZbl3WZc* zg7lEwJiW_iNj2M$bLHMeWV>$DbO@t>op36Uu1BhORlb?9;x;_8Ri|e*vV>pSd883K zAx;SxDjwipP*DwojVWbTckWs`kq=)L71QG-c3G6Jynz31D6Pk zAmTVv^Gri-kojWyK7&gWjzkSkOi-G3(Q})3287hT?$I^U)dZRLtmEH5Peg6E4o6Mk ztc2}PdZo>3*e3Pn{KW^dggiiYQ<-tK6wR^S1OQ=!Tn(J8S#7C@nT9>Ri}jCLtj%5z z{mQhwrG-y@64pYVqR$K^`&370Bdp|%KfWhGcvm=OSj%_c4fKd#lJCMowWNyq!069? z(o*4~vmYJrUIk4C-OFnXidNaIQ^=~%CwtlWyc)!=#cwY-^A)W(5FWddT{hdukDJo_ zkK~}Mxem51v~0XFnRiPU_49o@!4`$MKkX7S^POE5sO_LmeC75OO{-f{n>aCd0WB+h z<{iRA_))Cr^HJ{4t-jFEX4<{&4>n8GiFg-X1(3mN&I_t!qY&x{DqjJyZfGe5%fp=sqg;+LD$vDQQ@~6wOck~fla8# zBSD9a-U@h}sFKSVvPmyPedt(VG3_TVvM@u8wqn^=%dj|-tWb;%VC~}AeAQsoGxz}Y zM7v16SaTq^vwh(Mz7$P~+iFOkM8jX02f4UIYtfIgXe|ek3wD@C6z1bKoE)_uT7{Jh zx76#e4|piG#VPKZBV89G%5x*E5zrVET&A9tUN4nGzrWB2r-tbxgSzn_Fvdj8A98cy zujj&7?t>S7jw(fe26-lYlq}bym;UegV9i^`Z=m7@vF;aa&bZ91W%$ zAzm@H0_swNwY%owytVLfDTE-bXJtz87Ck>@Fca6zR4$dwfZve6zbM4~tzh@P0DamZ zUkD=sRJh`^>8}M*0Z{P{hgxYmi6d-x`@OsVsSD1A3ls8(1QC+7xs$hN`d8Zgcu``lqt)9XMczeJS34!xa?2{|88O(NJxf@vS zN;M-&M%k(hops@!ds+fl^VhGH=%i~$=a$WbBAC3VKL+a^RTN@1D-BVV%yM_)-|+Xy z>7l=@#_Q@3heM@bQ13Y7S6kKPUsH}m6-S!MHdxg+Bao)Qz_Jb*lc)vKhpZRP#=)KZQCD(Ye%l znl%EMQe=D~-+T9Y`{yT?Up&DhUu|3<(Q0AJDjUz5eK*Pt@6C#STYJUoJnV zik45P3W^=%azD5wJR;Xu8(#p!yVcY;fWtZ zdc`#fc6$ors_(Dk^fuFSl>cHyqUEgFt^T7mnR>h>Ox`pqvic|}8(HeYChpY8!39D} zs;6VIYk<}WAqtw}2osY2b$i)h1N`Y`I&Kclm(*que2&|flndeg0Y0Pf+aH#6@4b-v z`&=u?#kOJHGSB!+Y}N~D-*ZWwhX(Xm+F}5B9R9TrFxCr9l_7br z9YZcG!NknjqqxY*-Bd}Us@Bq4v-6-YWaiHcpp)}sW(D!;`BHBLC(pzrPq(r~Pn^d;wG^tEAw-mS2KO|)l!^JlWMCO2nQYXDJ-Hqxv z+(6+xSMCilq^5>OT)B_H9i*3s!R2fhw_ZTbk`;e0m2fwni_2;Ymtkjpo&6pY9Ocni zeB_~*+1#D`e?+DE(>m@Ru*>&(%H@IiDtKJPxxZ}Z9Px~7kBu39V^F>n^Ov9n=hoWI zWc&Suw?xHX3pL5Kd_u9#@m08Fg2j%~O?U30F?XhIuUE-9$B&~2?2?45*XRn}Xi{jK zEv;2688GgP<%=OMDd8(Pg?A7Si0K{6aLX_eZf~YxSEihD5u>|xmY`zE?i=f=(S;H^ zfLq5Ub)Hs=xjV)?abVIJTOy^nl*Nc7A&Nc_9=YVqh!XbPj?qBV`3!g_=%bDS$a^a6Jz_tZgB%p;~s zafyVu709Nbu1h@#J!KGC*z~NW+_Q{ur@l;;(3d)BX~Uz$x(`ew|9WkE%O2(BuZ``M z?tQKDXC!RTc49?~l~^kI>r5eQwJ=13u_WM>*;%U?tKOkYcd_{?%ayRSeKBn)sw`{`ps@*w5wgi(O3y}&cBhM~|3>*{ zy_USR_qnF$p0Cz2SnWZ`LyBtLMO+YJ@tlO*yiicNycvUU^#u5>@>6}~D;n(?y0^c{ z6v{*u^y&*7IJD7lCoen#dU`?M@2SXPPy4fM)YC5jr4>1c?unQxvCw#K3(6tMM5UCk z`BOEOZ>_LN#aw2oR9YMaKM2rWbX3JBVlO4xPcsRv{c;}yCw-feunB)CbwcBf~%d9P_*DYRgQUG;#Odd;=FZVyjGM~psT zVXYeRWrX66|IWW^tr|ZQmg|ILnkTxX^+ZmbrFp56_`DCYw7K#W*AqQG@rgRcL`#^$ z`aIgFM!x$Jxj`Du(e<`R-xW9hP&b>H-_wp6tqsE`szzwk32@0;a$iZYxxRb7l=5_3 zG_bo}pvK9cI}7TbL_TLO7+6_%=5yt_##ClI@h4_bZGaE1uFPgv(x@p6I!QJUnm^b! z@Ogo}Gcn=&0jcy6Rom;kh2Zxc6oyqhfAG5a^qctK7ni+BmIfKc6;iJ`Z&D$PhuTaP z@^;a$-zZO>H98z6eT(#I9Ttj*lK3jVQ|_F0FRVg2fglLmtxkd}+<0o8RE7Vpvkzg3_EDG$CG& zoWmI){;+27>^SG+dxYLJ*lHhQ!7D8jP06=(*!FUpiSVk-`*!-MAc%9x%laIxqjvqn z8V&5q-?Eg`N>OtoThhD?hZdBV!#7GO9T_VpqFpj`TUlU&)Kb4(dJef`>(LFpps|Io zrRoxCEs@cv#tr=XW}yv<)oG_?#E9YL%5!PK{xP-zbng-YM=qVYN$Y3_%rEUC%B78xnWSgoF_~?9$HU|fL9;HCktgpH) zg_tlp?5o#u6&%B?K;^I@k8o4;FU=UWxv#S z>QiaUz7wITpKz@y0?{;WHgGQt9sIc|**}G@?XHmiKH0iYzY{J*G&ikP;WkotOX(Tb zPx1+9bwdnHKiYWf8-{bny@({t1NOvpYaEv@noEJA=NV}bSFCM%^b8g5hc>fds&wkS z**p;!wxHbNZ?Q;-tMD^yluj>32zHV!_gq4X9M#+)VudpVgktcTfM>X~9k!ehs_zzu zE=1TAZ&S%FXoPP9&zh`}53yJD&s#^21=DyC6|Uk4vO2t#a`^@Z5@BfQNmFj|01N>o zYteDjWO60#N5m;MW|WV`LJlE^A+*GLZlQU`hP8BEriGBhMw?_&OH$2~xwh;25*)94 ze1r8+8<0PEIY6ycs_aEvSn1#z?NfkE-V#;Eo_~FOkR11@oJhQcORT1`aPL@@3vPUH zY_#;;(jPhYBrk%gGJO~immtNs7!%Qq`kQ3SA{-@ac5~=(J9xH+I#F*tZ=hmWgb<{f zs~>zBt|oh;#)A?F772A{poF(#uDfb&Zt!oW<;^m(-yqN6Z1}L8>s51p@hj|6C!8lf z9o!a+z@6&DbL?r%wxM4zhc`S9G$37!(XWL+qWa%r|1*irRu-p!el<_P ztHwW8Wj9ZOGz!_|o$0o9Pn@R|%y_jeYaeHc7uZoh+J1h`yezf9OvZi?KA*l5c7v1i zj(jyQYr^gBNbh}ij4t+nai)W9o1Fp)!9;58tbF1bX35pQLEr_^k}J+RE{QnDvH8-r zOuyH$tapfPn%v;P#{_sdM}3y_yW^R|;-=>*OyC+}&Z9p)K5GABFu)nYmL>j|MXf?; zGi%cBBjR?=U)|*lakqM6FsQsL4t}d9%Te2%kIvY9<|Hjg=m+Zd>wC&*{zu|!&fk5YyB9IrWgQiP!}`h<@$9BB6omh3$d_Wu4a z5C7h;9+moahOU*2QYRM2)`1PY#LKF~<2XSM%m3!uq+{o23&Gp4xLpp7*fMe3~ED(o{~k!M5p?u8}L#?W|v zcO<>|*w`2J&xoe|hZ2i_9g@B>+m-ba6ayKgRSOp?#}O61NhWV+!=}?#yB{W3@JIH5 z%rWJkz`_2Lt871UtWz?QQC{o1T5Ix~$W7_q>U43ZAImuPSjYrp&7OjTCuU?!W+GSMmH$ z0JNRM<#)swh#J}xS;;hPcUE(c8V;@0<4h|yZH&83dzmq-35Vki$9@cV5k ze}gN3-vpkPm9J!eo6Y0@Ac^q}C)?D13lKY z4(+KcyMNmL|7VxraQM$ql|%nbM4SN-EfR1tgX3p7i5g?wxG|8F)%ZWYgT8oaetur2 z{+}kIzKHQLRSx_Z238aZ<2y9Jv-;0>pi?f@e}Rf)_d`hzv#_xAwf^&6)R!0gCSl}F z_8TI)E%f3-g8I(u|B8tN5c!AWy3X!OZn{9!sKS0X|7ikr?NPJzso%sQ>h}K=rOGZ>Y_0&&FqyH1X|GzbaCkM@0Zz{(>`h6nK zXrLc`iMJQ}Z91>sN(`{8ojUc$Z-F;Qk2&z4B3)s5{Li35W`U4DQxAL#c1s-u;;80` z3p~x-{vXpHrShf&hu@*r%X*Ao#t+lxLqMPczW?&`Z5M|n!*jo3Hd~eF0u0x1te{ii zE~Sg(K7Sq*26ZM{w~mV=5b%l~3ZK&hfyVJK=hZ9 zONq_6yGat_COYD9B1Ro0`wAyf#Nb1jrcH6LGk8K557ia^gC**VldOW5#`Pq!Y$ha~J05m{Cq>R0COMZdLm%$lpoM;|`U(e+FL)BTL5o><}L6slD2 z*eq&^vv5RIVA=AZQ-TCR=(0cq}vZ_#vu6FeiVMR*}t|8jmTcrt{_6c9&s zSibGodv9Yepu0KLs#DefddqUzL-1zO)au9Yy-x2{M#C@6Qs8crIi@8lNk}L^&o3nw zcuHC0Wu4rujz;>_j<6Z3R)Vkw{j|x=1EXBlL}a1p4`OQC`Q8X zESO5CBiGl90*2E_N3Rrt?txFaOo*VG*3LfX{qw-LGjoX;s(z}rmQtU`RL@_VG*vFg zJ~h~GMEHO!Q}}Ej%VtKds|6VHY0)Tuw5u>Tp~p>;!PFiwuXK`rqonjYWU9Cq#p+4( zUz-u@C?{>^C_U>ZIV^hE{%s-yEj!~Y_1a|2b@ud4;I$Bcd2ju@WW0232!VeCAB$+X!IhCI&4ogAZ%%e(MQbED$7VAXZFH3s;eRm!YK zYhrdjBYv9#C8sE->!*Hn_DcGg;aY_CgOrgsE;QPIk@WRT$|I|7x-rNzWkq9j@zoaf zo@Codt-~j=F8x7TNjo&@!fA(v?%Vhnlhw8#mW5XlCyAQ?flg~A;#OU7OIr{ryJAT^ zjm1y-$E0Uw-CfmL^}0?(#+j;$FY`p^?w%IUQOnjzIHFmN&+PIu9S>2M0VR}z{sh*( z_PJfH!UHzx+E1u~JR5nnHoUxQ<)*AEZ^^&5(2(z#%RJk&3jUG{0Z&QD4N8=_0?7VT zKfr19R?)_+B37A$Zcve)-w= z>c=nP8qNxT$GkdXw3#D*B{$%1#PaB!M$&!f@jGI!)Y|lJ?h4R`JSB@l+-Vp7LQBT{ zD@olSzZydgjA)XH2p)r|H6_qap~1^y!xZx}KCtB$RX*MFyLWesL}a3_42VPZz_)f{ zu!-k{qKVB~IsB5AK$&) zzq6c1WAG^ggsrbLG>7hC%jtB??%d(9iteSC`=qh#}DKr)BfC; zG|eo}C!!$3i!GCA`lIrQ`9QIIm#yU+u1VlQ_hN>WwkbzGT#}emLQ#6n)@lxI7F#<0 zsNpI+i@oZ1F`;SYQR)Yh577uFIBgD^tO|Ifmu(|~f>h*^ZbEB4#Y`sx9^KWd$hOWX z6Qc@cNP=TxXPg3>)fg?}4;7H#`_srb5<1*mcg>LAeJi0;&F;|GLWf#Qk^?VkS0F?U ziT04ytF)>Yna@gdwbM-53j+vnAoQKj;PxZay~n-l-?1o9`J zz`a&*<+TUbM=TU|!GD}jdGb~(%2X`W@IucR+*!X>bDx! z>z0yNi~MF}C?fXb_B9SGM*@y1lzD-|O*kO75`Nqg8E{S#r;sEcp=UCUE<&XRVrI6R zOpI11C7M33E`Bzuu9BJUjgt&)aWU*m`$2JS(c96H?E;dbUsFEV(if~(h<6%s*z+bu zvHj3Zfs{twUdIe_UE>8(Q*Tjl-6o8D0LDHsszhUFGB!sN9CvkKVEMXRlQf8>JBCb~<<4ec4b8M;8z&5_L0>lyEsqP&)`|Eb^LDEs)KYM- zy=}edB20j={Q$e29MDMTZj2yYfaUKU46dG2WUA=kJ18n1bhSLAKwLa|d!vQM>6k>e zLEpXxK~-Ok(S$7E5oR-?eXtawFRTEyB)1S9|Mh!t-%(X|=~5c?L3C(&X!E5GN*T3! z(ee(%6|N9$)C<^x&!O??_;%K~eiT0G@r>ovwP-4wUT8Oi?xOjMFRrjXS-k4{-rYy4 z?B4fpLDTacc|7_<>sK|Cmx?4a9C~%@?+ubBTxmC(%6Iw!75n+ot*=oITq}5o-k%gWuU~lwYD-EqMR=8j3~KEGVWg4q770S_cQ^7*1k05?|l%4v&ocB83`ktauw7 zKS<1=RFTapNFEMO+1AMCyla|lx>{+I-^T-0$$iEX z_DSwEsoSj7&)o@Tc+l5(@vSrUU6K=O7wazxbA30%WFwEU7C8^}RLd3L&3%O+TNO7~ zuHP$6TlN^tN#tHY?L1ss8pF8OcY@zrXQ@swHfHUqVBNv%P@e^<58?)0g-Fs2kPc|| zGB7Weh4SL;;V4*;Wj`2MG>+&G8`P%6B84TNLNF0S#ms@uYHL}YDiL=D!hxKvAjfIz zCd04f83pH}G8&L=)qRJ@zCTRQ2{BLGVl5aasFI?o-*lbV<(uK5OBb1cSsq!oZ&QU;i*;MTBlW(dsRl zy&AoUz5BN@`LwjLK+e&%97Y)ThlvyiEDt^KQ)Yl{N#$)PciItRwFcvDq|%p|sIwIU z$-a!x3*}iFIR*taHR%e$I{Sl;b zxYbD&Q;E;$U|7{){0z4&vB)X$qOhF7X zz?C%vD18{fR`c=YLvECZ2^yAQ&S(7a2s%hRwBnP(8W4D|ad@Wyty0XEC*R_Xed$Ar z0_uC7%mm03Iyh2wiq1&=IV2g4lC^4wNOK8ED|&j;=iH=B2W1TFvQM8m_ZJ={0Vk^7w^kxrK*XeoAu-bN0{9&0rVj@~`pWSE%nAF(`O42-O~((Or4l$VRSz z?G}Nqn%a7+mCCScK{h8{0eNPidOeer7mTj#7M=k#176VJ^_%q%eNaw;7jS?KbkeEc zi}kts>!KYmPki01J>4qsdz{L{^v1>4l#5fw=4+{{MaSX}X<_prr| zUvWy1NxlRqelke!Lhh^0FD?M}%0Lx|Ef&hSu{I8iz_^9pLugU5aw_S)HRFH34Lqw7 zx%H$k%YGIhgp+l=I*wNn2vK8f+vi~3EwqmxaZ>vnLNct^Nh%BTEN*FDclYmGK5koP z@nv}Voy!-9PRyqy&lW)?sWibN!2`srX6g~&)btd|%%*e%G{t_M7pcZ8x+z*8 zK}?>apP34cy*qdNy?^B8xR-2Ej1F5#sj~}1t+!rr<`wy6Q=S$C*RTC)UG4D}uws&) zm<0EfRmiKA*1GPKYd0RYr<>;64vnGUH&_cQIMD;4cLme!(VeK9V);eyp+Vy}Z8D^= zJ*!W@F6-}x*6Oe_ppD}Z=PbO6N%Jy;`JGC2YNtaxz(DEBj5`7~TPQVSV<{9l@J597 z>#xAOPcGL?-8n-{zhHXrDgN0yOixGCxt@$bM(iYv5CO2_(9KKc<<}YmJkpy+8M|t6 zOm-hZSB}vAJ`z^%M|J~+-GfYcZH6Z5^mudEjGx)My~FSv2U%{vcQJj4xLWslF~Pce z7Y1Vsli1tHQT`%_Jt&t&7b#OJ1ImU&Q!J#LO?Qc8=Pl$|?K|yIXHQa-?3cBu&gOgc;^Z z1+wY~x?SB}u_jd_8wU@^gPBFJhcDNeR0%3u>ES5l+l{8@)WdYoo{eX@gVDpls;sX& zTW&E`j+;trHSwtL#>h5ReVp`l@uz0n`04io2PX=pa{hC5|N4OsP`-f0^LG*g7^hTU zd3ZtU-({})f0i!yaiDBKp7y?U)C^lS9iLZSYIfgDAa_af>C-*|lr8MgNG+21!s{3Q zy6&v>ryA-)r=FCN)6Lc2y>6S=iqUgy6GqjX78fkpxT2r6RY0=`-x5@4{IqEwGc!7^x&fC?_a9L%ty!vUk+ zqqQacw(ta1sp-0x^V!jGhoEG8={umsrIyf}*_SQ3!T^5Xu*`bIS00btFf`lKfO{UT z_&n^n1S;9^8#j77rD_^muwt!{hfdBXVf9DA_M3>6de0KaUu_Ut;za<-?oxXiw(qSC6Kx$IV#d&CNL zQhwgs;7v#SL6fZx@70$P->NYMyI;%D^n8;u-Rjq@)1J+^X5uLF)~Ycy=0poix~_e` zIwiop<&T!3qr3O3n+9+gSEXZ-LwY?NQKI$1E#GsbGNeh{qC7Qgw$m@BDm>pvD|EM# zGtb+O8%xC?i29L9M!i`vctFZu-EB-&@z_n~C%MIH-OLQ>E_|+=>=aUsExETsN1vnn~gJy3OPrTW$jNXwR;~b3l=*^FoS} z4=GpPCb|6`nJU88Au?h#^u&lAD$4QdSpBIu9Y+BIMK27=p}UBbNET7rHW?AVZy#R> z@Rrc{nwVY&Wp`S!HoTp^GXdTdY{neuAM(e6#SZm*;Y5QZvc+_%{E4#_y2ChAaS?GZ zGotr{;T7;mNRH=U5j9InlVd_+huQ*%craU+H4FnYhr$Y#d_9o7dC*#&K(MzOmDd_D z%2v|ho|d&=v`^M$BA|vDCW7#YGvEC~1df90%aFM3MQI0ESn8D#-{1!xVSO?qEr99J z0hQ0LprN{sK_`7nch~!y8TMo_O~IeIm|_ zl~sEj7Rv$s`Q_$+|D9lXQV$+&gmtVgxz%fGq7IcyP@9knG9NMM5*Q4?Q!gkV4EVTk z>%$g6MWmLoAp{5;CoD9bhdsNsdDhR2fv%B8F#99PF*Hw{z54*p{aGvTuQTw%0r>7d>xz7xiI-WLo)|y| z{q>n!r+G=1)p>i}>~c%0Z|tX*6TJ$j)v9$orE`RcIh-6GM2BnNN!1se!u#E8)T4?{ zfJ6^lNW3q~cX7#DXMX4M7cY;^>UroFA7+ z*?w%Z7q}`Oa}2WUzBt%j2g{IyI@{JDm!#4?@=n(LXAgYibIrF}h~u=9aO5KvuGDTl z=32kcy=R<;-*i}z8xWdoQIyNH;E(1$j8gybO5IZ1^YYj$gK4lBYmIn{YVWQV1Kj|{ zQa38tVJ1e@oE_W=W$6BHSPpOr(WhN>=9EMwqG8cOFD!;wSlblLicf*0EgUUAZ0d@E zT2}H@AT|K`x5wq@S?6_e5^0uzV^6Qb@bnW$3&0Wu+3XS%WH3wyX1$XxensKMsQI%@u#$+67%@-I7MV$6OmA`yiSe$KR2!KMvIeiYx~7j%Md0tk0R=?M~++4X2df z2xhTX$4k9}xfMA)YBa6B3o#?`YA1uf@*e1$n6j0x%d`MOB8TtONvkPxMMl*=dD{*v zlDVZx=Np(y+P|vp31~N%;aoU%V?<~6jJ+*SD(+9nwu56IrkEV*NP2F${)fy zlLLYZPLE)Hts3~)ZwQW&)=dOGP7pb~A--_Ah*|$1;EyLjNR%ehp(SiWd94(4d`$)3 z7u;qW{Ds2}fi;?dyff_1+A`D^x3vTa*F#?QyY)@w*C3TVg8|E#C;Z?lZ;uM?1}>xC z&5Z&tpZ@~70>kiH)8HnRG{%IrXHy+kXyXuKj3ZL+mv=~>rE8i zNmf~lJEw%;yRQY2LuKG;!_T_jR(xDVueuB8C^db2cR6>x@m^GG0aUJiUG{L)>KcKg+aL*9UK zaF`hH&BFNgQJ2u_Jwr(Q#jT!oH~n>`sR7{#!W#!d5g(?A=$(5Paa+RAIh*0RnFX#R9iuDs>MVy7I;v$W8`zN&As z!9e~rMz<=m@Vi1_Aif*5nsQ_3JG6j28CDJK2Pf0io>FjRYQtbgh>Tb|zs`!a#Db~#V4(<2@+YmfRy`u*bgUddR)KLxBU z&hlrEYzCJ(}z6l6g1$eM%^3a&A7Yd+SW-J2C`bwEEpujOPdKit=UsNmuB7 z`^TnlO}VS_Ng|?sBw?j**EjSHFVwD0y>gM8jMDPr{1qYH zhyrT+pD`~@-55CBLC9QxqR)WOLOm&zs{5h^yH#sN06+ihlUKy|XJ<9^;*lLdxm{2y?-TK5-`QQ*^&7sLu@R><+bE1w}NQ_8G&B8}nkuR00piA)fF*ZA@LGEk8Q1gQ^#e8DwTZDdg7@c#Y}wBBeG^e zM3p-4 z$TqU@Llb;UTzT&LO9P=r-nI4y*He znbqrn@{e05EIzZ&2407r9=DKeGRQWZW>}jNJCw-bra>YlhqQR^w@4Imfs~0~r2W0{ zW+DOo*0Y-T9!nwUD1XL{ZWykjwX7Z`A?CGy{qw-iw}_p)m@13Vcc6{XV$V%WQAi%R za{}xCK-I`t{Z7kzAj0ahu{*{Que^KKcHCCjS*2GE7;@)gv+XD$`V?3+QrLD}(ag1) zt{_{|!1$W%_g68UvMH1e6a(H@(i(&XqwE=@$~POM;JERrq}}YhSK-} z-{>%1Bexv;^@B}P_GXgiyVxUpO8w#=@FNd{6ow2EvvnGq!qB_aK+#+=G-pV0hITZ~ zZ0aSJoRU8gYaq)Q-fcvf8bCK&E`+u*=AK1m}PUCzu|M5vGTcs5@V7Hj6FBh^in ztH0G=hNIZmPwGz^DSt*<({E+j!&&4_l#M;aM?99h6SnL7U+E4DuQd0tuY{-5SVXZn;37NwI>+Z)>0pD!F>7+tc-pL*=r_Hi?-o`< z!2oAgXT9o$`b^K41VR6LQ}|hw?&5qsVs6PPw9OUlerUvmaLlXhpoU9+mS^igLG|Km zwuh7Uq?Y-Xwy+!2<`0_7_Oh)uUXyOaRz7{9OWMRq=={sk^sfm)os?Gx+wvS22(A5k z3C;L|0l4yo8~tXBE;{};{H571!~lxGRaa=@l=IrK!oxaQ1tv22Fhpls#I@kaZgnYTM{1|^e9 zv9E?#HOgu)FC~{A3+qFhFEEGo1x0iEFBiO*hNhrBRXs@|E_iFt0H*0&%$Bc=N4f;m zBW*1-Zel5Lj8bh=QA|AAD*ab(fT`KpCCARlZ{##ak?Z*Sp=v58DT(kfSU*O)B5K6t z^A$_*m-!*6xrtUmIm-Uzppl@btiREpmtTYKy(mXQVhS}|sW=YB+JHtF|2w88HUcVa zGGMEjs5+2lzJ)-RD-@@}EWF5p_tx^%v3C8IR*US8##YGC%oi3QWqMyM`z(c~gKTnh zd^FZl5`I=?4Oy~Ulsj`Q0~LhnX+dy)q93JZD-kIjM%Fyv8lg zSHl}IN@9^qGUk^uz#!#NVHjOxU#iDs9 z(cix;B;e|s_mXA_ww3TZ@bw@?tdbeH-nJZhlxj6nRbk&(4K>Um%iuZbd_{WdyY3VO z**hjj9eWJ9u{CvT|WgiEgQd4{g%|cZlxyOPxtpet&XceWo?YTkoCZ`4hL)|`@=k7k3VGZ z7N7}XEu4hLlUUJ9_)x?6-Oc26f3T1xE(h=k4EK)laz%+8ez#>%u5)F{<=o6!km=tT z>29|_l8v~B1iKgTb0jN~ey3%8O9k_4EiR_nT8A@}$9MuRHEm_=U%^yLAuoYtoF=SI zCbZN&AC+Ud)jPeKLXt9ZPE<}Y&m>E6H`3IPRjq1EDE-DRFW-+W!K=r&;rHZEQw1;! zuYIMe@ek|K0qw&N#)jV}5CJ_EoQ84)7`T&L1?UZH@l4x!N(RmrgjCD=&#>pGlH;D( zs@ZofT>T=zjjp)Wz{7)~J&y}{Z;}pC6zNSDtbv~hyw(RuI!oau>S4y06-mdm1OqLL zviOjNCw*qUIk4LZ4x)@!(VTbkk!7~%;fEQ>rKL=4`(ne>ElT}Oq*4UHtC!6~=g=b1 zHL4hD1a84s&F4h#0$w~r{*zl5oH_+ z@tt~nSIv2l_B1A;Ti7vlfXB=4^9Q9Py~PgrGx}kNK2f5;cjfL2A>0Hu}PqK z&_u9OWdcbTps3K{gTVCaEnWK_knzPJ_fVars{U z-8)@@2Dr4~AE0}=!hM`K9z={~e#eCF*fsVAQ2zoL@xy3ZKvV{409pDs9W&YGwyx}X zEVpcLx7$6;xr$-)j)waM4rWu9F%7sX{8kl&!srsCFv=X^hXlhb=B+%EE)YU&9zH+VYc^3@G|jdaOktEelx^Y&Tk)rZ`dzZN1nOJv3@Aef zH!5m8;b3{4cp+BCH2z^MLm_zy1aP!an1pf9dp5qsggrnIWXe}^vGPOdqrv^6kJqA zg5?R9IsW)Dr_|E;5MHk2(>+`4oNa zaZ7>6>YCOALW#Gi5!#PW z#w_W;E4?2r>fguZG(@0w4t?1DcGRcB7TtQf=>jI&K*Fi-#S{B}hsSHDwU`%Nq?GO8JB&7Q8EDumz3NVOMC!))W6cC? zspWGHnK05wZ$mNyq!4b@)S1ZP=02uTKGm)!$d7{0%MFB@An$fUIcEmtb@|Lt1~BTE1!ZpL;>SZr;zk-~aG`wa~2HKTUxCPw}_@mXiefACvzbPI&91; zAfbELMI|7q1X#j1OJyPL-B?*q<4B0FpgJeo!h|60xN{iY4B0ojonXXR98f|7uI2G?2> z_;$L+Q|RzaecZ(pKS!Gg&|~iP`qzDr{y%@utT?Dd4 zqHK?9vm0(&3jxU#ydG&%t&X?9m-%l>3hVt8u#3m$g#yNFU81G$qc#Ue9ftUTTye9#F-F3FLIIp#X*-Zf`@YcgB-t0#i zflj@cJoA5X_vZ0X|6kwu8AJkRTWPR5zI z5-RLB4bJfqQIsNe#n0FJGi5vVO~H@iz?BNN!}Hy9cRx(nF4JRk{mm!V{d>FUQfK_) zAl~#(s#8qxXZDy7p>F5qOJM_t|1{$6@(6M9+cZT~+_MODSeNuw(4vMeLgU-npjV7- zVn5PI2mN%7MTIk93EZE3JW1+v@a)DOYh!8;qWz?baPGqe<4eK^AI`UjjxW`jAV=Oj_nVD@6 z)Rh`56K`3Rj(~ zX{4j}_vK;Pn5~rScJ@A3$%Ctw(*-%22F;~o_uV9B`94jvnn0ZVEm1xEd{ubLE@l9+ zcTB!oj7i8==`g(*tLcun)?%$1r~SV0>@BsX}%8#j%&O~<&UCJH~JCL17ehDD% zx&V7%1!_XpV*sB!k6Bsw1RoK&9`JMWZbjJ zpeFPBesr*gpTXk-jB;Jgs)gRRtDi#+UZip44B%J112SJVqdTtW%XAgv%$=m4=5#AroTf+4nm4c2bglBcb1xCX>l0EPU^5p4?SHGK zcWr;=ot+7jGM=-taub_3g{GmJp3jTb>|>GmRTi|6Tlc9YUwu?Pigm0<0H4cIMuVv-qh@fN|Q z`dEk*SK7o)8I~tO(C00PpgdV#2g1N~ZjKUbqREB!IJL3vx(%>8c)UP8oof&mrJ>9} z#e4M}P^vedQp!RyI_AAVzXw*KT7adsO1Vw$M$j?(pWo-TM@F>!bE|MNn5zq0PeJNSSarm*#hEU_7dh`q3eI)h*6Os+D9 z)Ym{HX4AOi(v_XFo-8ClMi~rb&(%T%U$b)`TBMyjgRB-Ki3>` zp#}Mb;81GmPIv={7M7@>2oH-i^e!omr5Vd4hfU|7ldPy^>Vaf`1I}oncJJ72R7d()$)QXP5d|8&%zjw=%`6345eZ z)jbo9zzY&uQyJVFW=4M$(iLF+B|`kOhS1nKHGy93Uj0`n+qc75>AY;Yo|ut{TpR}M zl=AvVq*{K7+;ZB;^r}Z>Bkoc{>D8A{0hWqQl`>8K5rh=F!}==(yuQ4t-b0`F6jbJ# zU-g+XIB|4gK$KRQ)N<`9M!hKyxfZv|I4s8Lt<=oov~$5e0I&)T(&j@gwp;B=z(%K+r*4#Z-$GolNZdxo*{w}U7lKOMg#DKC@$D>~ z<>FBlu#26LO zMW)euXLIi(UQpNuxJSHbgi0CA1VVd*0*;jBz@Jqd`-?-S;N6i*q4>736H7A;ZclqJ zmV&f~!;-z0w)T4e48K%RoCxzJ+Z|sc<-oUi1(QBhdHk*Pa&R^~5`4Zz6L17ec zWr-o$+28js>~th7x%GHm0!11_f-@x87c&LuU}~F{Cmbdn{5!NmA$&YW5D7hkQJ|&e zJAGfwmL$^pu`ZvAJ~DSR?3rI_9KV?nW#zeU(Ux9?-Vk%mviz)erM$5KUytSKWVm0Z zv0T_Qh-YoVEE`2J)-R(5ZK1ceVf&34h|kJlD>Z9>S9IqAYss+A%fhz;lJbIoIrxt3=|)`vS+6@>F96@Q$vQUtmCu3b38+? z*Pf2c^}LukX15$`20Se&RIPtZ^VKr<)1 zFCFJ;Tad9M`%M!`%9H9l89KHHXR~Jkm_&cROeG%C$#~G(_mWP{~ z9SbRQR&!fTCI8rlcdO|0MI*!dJb#<^El-8{Af~NDQ>CP#VPRGw(~r55dZi3d8Tpih z{-C#I9@LR35S|MacyB4N$>Kxn-RlWWVnY?gj`z~40LP|YqOOQ-6St= zBWwjGmhqA9^w)7aHb&x_=B-&iFOlVfC3od6Nf1)AJvBaW0y^5c-XgufQCYj&@8Ik< z?6oO#fd_NFV(cNB?5xTqxYKwGlXBaRy~GDKkZ*c~&EV&koGJdM>J${S_-&`J z*WH^dJja+SoSsn3)~+Y5%p4z?2_xoNi)5~-KE<_l@7f=MGgp2bx*wa1(Rm!L%SkQ8 zx7|~~(EaQ)gGs2OOQ&PHjm2jv*UZ5Ppy7=PwkzGyshD?p5^Luu@=c3Z=gfz$cB6Q% z#*tpiqC7qR74%DGCIA7SvJPccmv~;{UQqJFk@C@iHF}e3Fj7%#<$7-x*lbXa-RAHU zM_waX%zz7XvaCvBTmu-0xY9N+p3-t;#F$7#hBeO(@gwH(ag0fM#zB_X^{)9h2JtRN zR5AqkoTn;U{}Mu&bAog0Wftnc?U=F-2}^0pd1b>yku6k%a_ciqZNt;&X_5_y3{Wt6 zFEzic6yH<65X)XQ4oN6Tl^zwqrk=!#zshR=G*HayQ64tXZ6pu2%2Wk18wAFiWLFTp zpg&xvDRy`Mr@ZH|o7c4i;Wq-NJZaMlC>>=?(pqHB|E&R8FTfggnhD;^!!yH|gz<$m zX7Nl<0n3_=&abFrK3@3=-<--V!O-hZWB9StW#2xU+ntjzF-`=Ra;IU^sFq4olbsQW z{_@0W#{CM@X}Oe^UT(ikqA|t@;af2Uh*pOMAEPvcv0fc_#T91W^qS^3+4Rw|0nGg7 z!Oq$1VN%;*!1I909kKujK>6D~2^q`9|!#$uOd4NLbJ2{2y# zW?p`%GK$VqT|bT_Ob?dlI550&l!HMk^$2?B8XCvR!I>AjtITZ-bnvkU)TLDD6HEZ1o3(c5mFpQ2_RX7Pq7`>J&VF_qv7O5e)22nbyQeA zY|AxRX?=;#uA~K>+7iA>(_z%tF8|Q@GT>Mf8xUB55A^URReW)94lIKA+0*C38u* z;@&l_iKUa%bmA$Jy$j!Y@biV7)~tH^7NyI<1$-rNQ-?-N1b@L#6J7_0rZKBiEJ9LE zfDT`U$-Ai03nY=0wto7&-QcAjUfyesW*3S>;gPNmtWF9;oTUtlfkVxbt+_1}?Js;M zeDTFdw+FK{Jse0kj3rwn zWm9Vby|%6I=UfuA9yLD*Gb)_goZK#aVt{nHzswpSUBfS7R#3z3IoP?9E#|*#RYSP} zE#rGv@Z!JdT$FIXRFEI1`Ph3dJ%V9E1R^+u;?>%RO0okAqWozC5}zrkTDfPRU9Nu! zWY$~!l(0$((P9lbqb1VDHEgJv-YMwT8n!}om4LwsPd58J8y1cM5{`9hcs0Ab#ZxzX z7plUfEZj28g&LCjnU6zIn)p;bcqwHQjh3SIW(2xz9M`n;FkMcF4w3O@9qHs26}Bj( zJ$CWHPLopZ)brm2)tc9X=Njn`7KSLQEOlI&}HZCi=$PM@}kMpUhRKjv~S6xl^^pozN(Zd(w} zav;0`R44HE?@YO+2Iw4tCG%e!R1o9*1kc^rwFNtD4@8(XP7Y;5nbDP!2736eN~g?s7Ar8@tkWSZpPM&TBN*I7oerRCin|NH{AGR&t@C+l!s)(TKxHbW-oj`03T( zuh6+>at@o5zu?X9r*po3jkB?dY_uB{>Mg#SRc*5&ebeaK+gogNhss}3*e=#yC}*(0 zo?6Uq@^$AtLK+8ml9gJY+}a6u ze6itxFsV}#-adg7kIn1B(>nbDMB85WmUz90yC16nl464T$}0q1TR8t0GFP%Ok*(o} zY_5ofJ@-K>`JwKje!57{xJP=jl37){LBwR*;E)!x5YC;?=)X%@ymi|vp4O(Dq5MwPuzrm zvjlbA8pSf@cWj5Vd6>$dZynCC&?oa@mVR0wCMz7>QoZHGu|55!!pCY8v3u7EFuZm2xSo2tPEMMA3ZLN(K}oOrB6`RBcKJk*i`LpPxnJtno;^7J zs_;x*DpO$eYN zp!d9M2bLe-e^ax?$57JNL(fIh_Wk1(w{;Dy=cBnw!7cmu#PgRn3ftWGk+}T%&gAXs z5Nis_F6(&wp3!C+&+cH2qf7CX09#gHvgJ1bBYrZAJ)D+VWmA_scCP;Wm{vV=`UlOJ zxBr5iO=&pxYH53u$i7!G>cctl8?2Ti323W~m#ePij#QwwrT^vuL;4*G9|;QH9^3dL zF_(dI_X`pLct_^&!97%~Quk#1Ylo57+cC2mD?4Xdr!_GfzF%Cb_`k+916Th49run| z#Cqk(KB>GX1VIF>BRtk#K4j`H=Jyy0>(7{o(+A%Vq% zcK+MT6;S}^f14d<>1R@ab=|Obf^3t6-it?Fpu1T|IZ?d-;Y+qF3O0G)95<0~txD;a zHpycQ9rg-ERdRnV#a=zyyxrEz{TY98Y~8VCah)vgm39A5H*5SaB>N0^cYF7LJh~O0 zm<}w~B){$MziVNsaNDZq$~tML#Vpz9-<9JEISGu(>?eSCp2KqqX!bf(x%z23mE}r2nZL~TVJS;>xxFHWno?b%N(^MGnK=sO1nEGA$f~W?iyEm`= zT|4X!SZofQ>tJxoOvH8G+^T`V7TFS~F?-;8+g80w(qJ6zy+a4}?>>T4USOw~J=)$| z_K0}%*%oTp3&?cORv>cgT&5k}Ezz_) zZvG5~?G^{X_Iq9$EXNQ$n)~kM!lvH%5vKj8Tx>bDJGE2%0${g0TEUzzcaCS4+~-7f z@#&{DSnLl2h6TuL{r>jrVcV*T?FYwGZNk}vjvWkG1uL$BdmCi?^*q%|zV#`P&-we` zz{@FsKi1|k~)uZGi{m=g9tF1lqfQOs=FXR|gBWC}- z7vuLtd0Z{J!!qq7doz^BXf!Pf%1Lh{%5CK_y7lZV7AS%>2pDftMJFo`I9F(32Q;q9 zBi+;to3?j4wpr7+wSJ0DKwY};yI3yxk`?+k_uIPI zty#gPyt}to5g?Qh#}}y z?I>^SpAGimS7N*)bA@hAZ+_owqZ(}B5@}fWDu0ak`kcAF9Ar$$kel$V6#&Y)QwzfD zv0f`-QZtVSKGn-ZKi!|ZzB3S>`5anXS*<0eGasSh+1qD>@pYY8>uVegHURpr z>ZP1jxcjZ?rF=Koo^1SY>^e$MRzHPBwzQ8o7p^5W_X;}%z7+EO3 zZL42mkLnFXtj7h=c*Db+88Oe?y)c%g6P(=zElGuJJOLCN-LiB1SkEof5s&R^I*Gq! z`1{^TJ9wDB*qjfYucEEJ!aiRS%nU>mqZFB%tinTT0qc;GXzNc+dK)+u1&ZwW4Y)V_>-SC*jSc#gqX2$)C&zhfjv0ZwGXdBHQ3Uqg8^H`5!Hk2JD*U3M>Y^r zBG08TQq*NkZq>CT+1^TEX;RR3aCCA}8#n*iFkdBnIh^gN+VA!fY{X?45VMkZfvQXJ z$GJ+cejdHr^jehE=?gwx_x|pC`SB7N!VXQ!sPb-$3T%IeT3rdEaDU#($`eQt!#xfX zl;C%mXAWVgW+YYqE+8rh79HJ{_Ee`j`mtft6-2-=pd&sI(lk`_sMG6~9Awade57_y zX$DDS;(XrIJUHp~CxJv)^<~KzQ9yc*-RTM#>=Hw)QV!3?%YZT<-OD{=1LcSoIt@7e z4C8sL_QW=?Pt~zciCO$V?*1)4J>$lh&_@=CThY3HRe#ZWhwjUDrkzv8rcrlEhHA;c z96QxY<@a@PH;0nuzY4$nBeb+aQcPA*Ss*Bs*r!^qM>;hQs)<<;vCreY`mAz`H~xAW z<|($;`wp95LTdWpbMIi$m1gq0+8V6RAqB{-{Rb)EK_uUB27vMG53D`ysKGw=d{o)P z%J=*JHwfot|A+o|O^M>hGvWPL-vPhW2TlEdhLs11|3AUh|LVBr;Bph5RlBce&z^l? z@!UAP_{{!93~kBY!9$1i#}>CWK$+QbQZ$+bKKqHV1`}JFHmm*uMCIv1>-Y}un6E?o zKdd`MMv%6r7GYuw+V%9%ey&=6x~_J9w$F^77`5^O_jrfCY%W?x%0U(}G=%t%n%Nij z(Dh6I5VCEQ)>WmWemg2pEetHj;s=_%z{TmXRGV_yFqSEygNXvZdq)2petj1KLy99&MZ1cuFBYiUJY=dqTTQvcr7J4eX7ddl=pNwiZ#9-@Bu9DXD(1I4Gq5wyMamxIKs*&CqK z5nOZirTw?l<~Kwr_E#2MXF!@Je`a1BNB{G(1G=Z&p_jlnV4cUSu zm9}yUTsPS9s(Nf2l~|;~cb)11RyNgiz0}iLI=6{^*Q0ILl3B*{iI2vsa9-(bLdv%* zw!TJwdM}s0V|dG|O9PvKzM@WO4+`tMLQrHvdW|)LU0r$73v4UF}Nxp@}IUh}y< zat9G2U36DUxl@tPB%z^_D|alEX_dG=(7(AYXUD#_HNd{Y_;KZ1g~n`^)FaO#)x?a@ zB5{i(ji%6*SKK;&8Gk)Expa+%NtyC^k>An80(IZrFf>HSS8w0P0?&uEjla?Y$?m4Cvu2yA3-6N|{S8n+s#ni5`MNh*w(6QYIdnyL^~>ibypa7?WXRA)w=5{$N?F#gw1X8OJ{j~ePuotu~}e=Xc(XuUntV`06DS7#u^=F-I&3I0Gd z9V?%Dd!~hQ&f`bKG~?7#HXBE?4pwGU{{1_kz}b_OwkxN+Y5E4a*v%(w2upPT=;9Suj9_TP_TG7wWS#Yz* zc4%w|tyv>oR(pGv`7-8I&Rxw7gfMtx06rfT9n9s|xnhkxhb+Wy#tGFwLqhF+-oIzo z5VNgiW#}|>^AFP-vdCJkCpx1FG7GQ-Je`w1pAn;`iIukMBR}7E*}<;tYfuFCeXbF9 zOM$@~2^aNHYS6|)T9z_yH2^Hrq9({fG<4wVe(Cx<;)e!jIRM67LMqytAU(a=kT&Tl z55)0dg#r7cmGUOWv!Kb8Dys&zZvuF)eiO}X3@ z<0)U5BInYWU(F{zA!EE!FS~SASrm)Z*3yDCrIr^lNu^F#ce*Aw1yra%pG0J8wz`eE zn_jNH<+zo=f7RE(O&_6Y!G8YTb0+DYFR}!cw3dFxcNAT&TkV{DLUW`BJA$2;BgKkA zMF9$lt!a1aSfZfV$Go;nfFC;D5^IM?sQ>6(KwcB!mvb0ZGP87?69SGLd#Px5eM%zV8!vn>(hCnOaSsO-g1Eqv3Aw zt!S6ym8}NTTXUynFAuac^Zk4WS2j6ywpLkWwVC*s!CO6G;fnN_Z|eyP=bAhdR6gvj zFn-y3ApQID@{8k@Le%Q(*GEH_GRpo0M*QhZEKJM9iTR7_a|f={*q@{5Dv!@bmo+pK zj#lmg&PO&1(T$^(Z@GIA(C`q#fOwf=_G$02*KpeO52nWlp5PEFla(!`$v+}z1jPhy z+uetjZGW;*J2I$SFAFqdF$PvVj{K@q4;kEsjK-3qAbh!OHaT95MeX4ZrO(>mrJD;- zNU7gqWqxA(uGq`Q#+{pWrd5uBp5Uj56$4ZTe4J&Qyl2!}>BiVFkE42)CMa!VE>LE> z$voTM3>G@F4~x!?r@X6zfTy-wSmf)n zFm2P^f{A%)=W~s^?Q`|_ zqLs@JpZ4CfAQz>`=+OA1I&tkMHppQxSK_-I5J!U*PBJOe$ai}*A-c0<_LwIU9`Byl zHd2Th{JBsmr)1>A+A|M9zE^VB*GKU+`7l|-+7dz^Tg+J}M%NE(#`Zx`#ua9o;U14H z;=79Yg$vE9A!i&A=qae4hR_O{$w?8} zGhCLGtNKoFd=AXi1bHW)Y^BgUg%P-DeTYW%6wdrQxR3QGy|*{ENHjM9day9r#?|+% z>6Eq^c5zBAt3}}t_+4k7&g&LE$~1?fQ)12IYDUhIXq35n5PVx^63z-B!em%p{OvF# zf4tJEV?GN_;na%%zXrzir37C){ityU-?cPLztgLI?W61vgFgk0e0(>e2;FEAboy z1AF_=9}R*~GM3$}S_)6}nO?pcj03B=^>yJaEQu=89HO_=-d|_|$`OiiTCBKm+9>4S zChLrL)5KYuVNeC0Mvmq-c?P-D4|a%B9YE6Vnpbk}ki|gokl}=HiGhb2wP(3DV@2f0 zp8+}VnAiSnhHD71Q;7B;@G=Go4~N}c6R!@%T2g%^erm>b>ZlwwkQceC94an82zWq6Qe30^72=8)y`*;$w9o`K{JyELOw^Ev`l|1%mCXZL@*R1MT zaX=Fl(}KzGek$kIwX>vi$|2x+XX-LvK1GPoP4(3yitg=JozdQIfuR4b#MckRx@vR3 zA!yMVCejfHlUj>TN%Oe%atqI5?Xil;RK+`EvOvL)EW!)p&ta&7IH)c%0Zn_&ido5C zWq_K=%BI!6x)Y)bw-f(S^UmBdThBOo$+bSJx%}4rBm|?@ic}mj|ARu)@r`hv#380O ziX;Ss(NlTTJ-HaIhDOP0I1*PA1)6GH$Y$FiLy5tX1x2yOlTKs80BNf2)58af1!!YC z7300h9|ge{w9luw6D+LHx&lY$JI$JC-am-L5~ZE?qn}~1zsH>Peq}q^$EG^GN+0U1 zx6g2bWa^GBeZ0S!{?I)r|8B_`@MWX)yMTH0tg5ic0g3__kN%q< z?oG=3;>jJ@`fz7g&=2^(*LQYo!wpJVjV9Uyg8>|+{J;IdwiG4ZTFJ?J4eE5so5Tk+ zZ_=WeU6{QqxZ7V<8;jd`mb>csF;*mj>3Y-o-q$ubcxRa|QnLv+Ew9h60c)iea$iZL z%ILCuT-YYkxEK`z-iVBsPg(67|CRB^90QMI9D^WTZl`h12KnY~j}>eSW*4Sv>JzKV zPEF&MJF#0j_=K!93G2WqBQavc&(E87)#6xxgyy2FpD$iD=!e(!uK2{aqRnJXo-Mk( zi#Y(TXReAOLZB$<`&)3nhXz0XtO6t*OCI_6PyI?;clK=Ld?Wrl0*IlY5N$TIr=sZE zP}<{e?^GVG{4Edg-@$Z_92#_~EIHy0#Bk)%S2`+j04--IZBNc$16oA(kMP{d-2*&a zcWBVd`n&`CTbf-FxpW_JjveGeNd$F0a!c_4ZgOQf9zI|&YDhH7k&Cy zMzQKR#mWY;T0FZ{-f8=#PSf_h2SFG+6mQ-3v)qQkK6OsAs5R@eo)%*C5sXO)zpaBD z^`-D2NY9M7+7XI}@KkG-vBDKx&|h-`oDQT7dGQS@g0PJ9Bd!*eqV^IZZ5oWk*%>j0 zAK9L0q?NLb4;0#Q3cHb};SbL0F8fB+_5}xBi3XeJoQQ_j1i9x?U``VG0zRqpuU zJzqvfUw${))WTV4PVmH*-Q46CB}_=in{Z2wDO>)ifu|!iQDu^w8}rj#e?~8uZX{e& zBrIv<2uvyWA%i-KvoyTFNCDvRlc!R}K zk+i5>S3aS3$ogPtl>e~>MNb>Wmg-x}Bkv}Re_%|p_Iq}-Z$f>BYNn{fq6O9jG3`k; zfT<3J{xCPS6ELfCWnZIXZ$Iu72i974Ahb!5R?p@ht8D#d9cqn&FNX>zdDs{gc4*ow zAvS8ijT&W$t{>gL_^g0b#OBnmy`7^OX1#jIkgUnqFOuzh^W)CV=0k%O6W_Pf+vpYR z(GIX;&y`-+PTFmJtjX__n)VzvRJLJLK-mz-5`5s7hg;(tU&2;6-E{+Gi|^E_K(}d& zt#6;jH~dhGO)@d6BtPlaV0HoQSDB~F)z7&A_N-D%>ONk$z(i$Oki(V$C$|?uz){ki z4~5qc8;KL%RAEGz;Nl&sr@s%x$YdtUpu;)`<7fIBy?{7O<0X+p6rvVV6pO)kn(a_F7;^GiR;YJ5XOEP>{QaB zOE5%zrwX9Whk;Sb?YMFyl|K*riQ`{{@b5ETz0qN5pAA03u!?&&p8@Gdps|EEYa7(z z7^zx~Ry<18js3@2OyBQDQXQ`O)}xrs660;2(A#bVR-4Sth%g3`w3n55UmcCaX+DT` z0HS!*>lL#%$%!!Bk?-U%PX*KWN0Kg9ZF&gBzxCAS8bD~NJ}O{iXgitgo3Z zdHrGIS?@&b7HIXfdV5jVEM~GKn&&>{>#M>xGp(E#LeTCrqJKdUzrF?#VCdxaFd<^F z^PFVUoD>!jU{@Qq)NerOTwcN!jovG|zQ;NpKStKt+GCZx*C3rPcs@;fxlWgH4yhb? z{PI@y1@se8E9aaK8A3mz^|7V`;?Hmb%hQD=gsrIyTU9jTvw!Z=mIkFZ16$uc%;IzO zCS!777p$BgQDa%--baPQv&VP??#U z-PLd4=h?AW1&+G)0Ws$xeuPQ%c;|A`Q2XyGoGIwZ)*gFKbxjY3)QgreWF{`x9M&-{ zjYBBvsMT*W2p9nc{k=QU+fBRL{_`<(-+5lpRYDQ-Xba@Sr`od9T`b$ukaa_Nl#xIf zaWD$0L?ODFGcp|=W=Fb7)`^ppWOw1VoWo$@2xM)YpKq8{2O3W2>y)!ZHd64IZ*!)i zuyiD=14dD>SMBiN#MltktZ}SvsgCgWI`6tF%ldq?e`nvcbhFV{`pQ<%^{L*GnF0i% zo;5(W-R~QZ?%_cVHDm)A&LXiwn&$T`VkV~9q`_zw>4FrESv!F@^D9=d3wzblA9ri! zZqLa{%Z6ov_BV|U)2_`^i7=v3{P1due}qt(QQkWT8jrVXYPmBJwbNC!-ivB5csX?$a11_(h$GiZj(v?xPD_7 z3fMV7qW~#Mlx6IzrFpe$Sj=42j-JMV0i+vNk~eBG#%V@(;A92AZsx#Qr&52!w4#Kz zmhL+DL~d2!hf_kWphKHaakEPLOgb$HYg@|yS+^2A+q(U{fpImz`Xs-y7MIvyg+CCuh;=Z zRCUYb_*_E?p`WTNB1p))Y4bIW?&!y8=>lUtjFVCK|K@hZP9)b8&)t%jSiXI%Ja}fe>*hT#TU@8 z%Y?V3BmSR<)H9|I|FV`|RW6Si@f8289SkfI{cCDTE zDXu^3T}-`41c1FdcjN2PQj|tX-cyx|ffO1i&KSErj8RofPKj<#dwXxk70f2I$rCSB ziZ~3g-TWFoww+X7vQjD03uL-s7iB!u{Q6-y29gm&^oo|3wX?dPr`?k(Vo~w?rDsNZDpOk7v8o7C)_+1(bmtQ%#qgHQqI_hf= z(ZQlKr#-XyqlMlG9X9me?wZFgK~M#HwOSiA%nIHrOAzg05j=G z2ionkg{NT?E{?PyUN*uJ8}A3@rD5=%<}MV(e`HZk-1Ac!7sw=KSkw>OsUMXc3;9R3 z^NAx?>dL0RMTY0wy9^5z3UQM>XJVTcOjs3ECWdK6`Z?Q#+hm-ubme+P!OiDe38IAKwKM2Xm%NDKwSX+b2XsbO`D&qz|*375y#O2!*@r&r{nrOa+&fZodmD7LX&{vmV;SHUL(t8ca`1JZTBQDh2`|csmD&k-!B8yW=Rl%2af6O z9!JSr3;?rf#D1}#k$}4YRh=E6s zQQF%2Zq2^F+~SpXY2TKEskcOOxO7tAy4_!|0Zr5pDNC9=%v-#pFI7c>ENl?G5pP!0~R6nDv9}E2HF1dplanzuAj@iE%Y~z_`_N zcXN240o~!cQ8j=?5G!i%@6ORth@MY`%e0fQ?rHscs!j*da%Cc!Jo*(Qk&vt>(}to) zPj)OFGwqY9f&cz|ZO2XXbZTWSymPej?mLULIqkLhZN7wuKQ1`Ji&YMGxA7F&%^Nk* z3k|bI{_2-0TwE#-4H|x6#ecbq=pQ>_xWCOeP~>gCp$teTG@m7Hv#t)w zFWX~?LvO(#-nSUMx$QN`R=Gdi(38xr8FH4VwXk?Q<&VGKv8>)cHz5nJFU#~LHmj|%@x|$`gr`QIiTzi*cz&EV#eXR2C1+}G&zdSX1c=;(0vX`S|Q*ziW38|nm zm5ECySWj-&7V*1358zE#YkzFoaqkj9on})QXOIgURrCxJhTXrC@bE<}lXdaX{tN-N zi@Ra*#cGE9(# z6}-Ll1ILp?gV`6_{90u5v%rMH!Rhbu(?`$#f1sNO!t&pu>Hp$sq8CAC-*e0D{e#Qu zRW!nh#LowNW`CcYFDNE6Eba6a63A#`KFuqD2)u z&jnIilJF0yl;6!<%o_c<=kYcytOK#|O5*t|P=wD+_aw7#+J=kIlyK}%1YjepRge!g zW)1$Rc&pg6k~Ig!|GV!qT#OzFbbKfYI@kv`+Fcb4dNn6Rjdmc&i`zD_=6D~i{PvDc zgb=X3#W6kkTkzNZqYXXDzTfO#c;OjdgTG1h4osuR+Q^@MCt4+gbiUu|@nf&J3s`o= zi>#^+Ue>KLHhegg8&}^cu%Q=A%y{wz&H4La5ev12V`MI;TYZ%VIy1bt-1bbZz{5K36JCbv7 z|MU+mmkl#TFhiI5pugiDb+Hi7u{r0{_Q$QJQB^3Os`;TC(hzwLJv&tXZ z7KvCEGS|;?`{~;BS^TL}H|ysBHdbhvjvw=BQY&q&u87nYnbWJ?61y=5L7N#PN*Y^4 z#PcnTeJo5|d5yq89cqPXW|AIvl6QU1#5|=nu?*o8YSF9OX7A_p7fk;cz_b{T*ti36VTC!MQv*1H9 z*>XlcpH6JAom%3P!XermD0VV9Ug*(PSA?=_Lp%!@Yna5I4xc#?>irC(Synu@r7#S! z7_;tN{})}EdKMSmRo_pBAcH?-cl_UH!=D45hSZ%2toV5m-KxNvYV1q3xGq<1{Shp| zaoMcVApQq@1rmzVgvsKw*SqZH10*t*l#*vi3MGJKe_{adnG{T07K4c%KWA2m&;Wyc zxg)#cK~jp_ZSGB+Zg)~mI&Gl&%0H6eYk=j`;?+0SB?DlP6W4-_KS#IANel6W08=rC*Bhxf-$P`$s13ER7thN{sKs}~ zL`_L0Ey>3#mt7;rr=*uJZ02A3o!Q?}(-W1sibc%7m-zm?!qHfD?)Q2DU!IJu{vT9yKNFjX`8QI>Q(k2xQ?_a z*9Q+`|91U#f=5t)dY+-sp~15;T|G(XQ2wrc>&H}L@zK|SRHm_?i+yLuPW+KQX380K zyXB;JYV(!md?ZhtKg}R`vtc>%XJ=1;>>uLy1IP&?XNYKi)usEmidRc{$8R;ME~SiL zxC_FHT>p{5;yUM)Sz0(|Es1W!9mVe{bm=pN(HW7&>UDv1PGcZ08RQBqi%H{n=e0nI z=eH@kij#6Z-kCamsKUh0uAP}&h%$fwh42O<;u=V@NJO*AR){7mj^;>tpcSUy$NPFj zj-I^>ul%6mb!>bBU}3it=YhQX z910+7>#eWBLg=;MV3u{scc5VMJ7q1@XBSlE|6`Kej@Vi{-b4otX_N+{8)O(kh89e0 zn!#tdp1L-Z8lGiQh)!fs#qHefK#oD6FXH|@ZF6m1JBNO1kGte3?-B2qwx|!==vX#6 z2z=<~x>QMPrte3-+A?FdMUT5hh~Se#0=zQnvCdCw8(&ih*gQuM*EG z$Q0Si!uo(fB_Nsh9^{Io8SYC79UcU)9a(nTBM9n0pyrwQ7>2&2BwpRrqm?|hE`m~~ z7o^o}qy~~|bf4brl{V@=G{Z~$>qD=2yJv(kP(X{A@3derwsYLSW-4h-R+1Y#4CC%q z2kGU~UAGXS5kC3Tn>-70)|^XO<_C3igs%#F`%92b{W*uTZJvBAg_`&#MIiawr;q3U zIAV2Svm;8y4zbo(YxkULIkHT4Ce~l3LG-g5b~#H$QfOCymmZb)<=CkvgDKku^O8!5 za4-Wjk{=$rcURTBmK?_&_7(CTqX%zYL=q|7Jy90N=h-ULlOz_Fveq&tHA60KnS{)L z=tpU;LeN?rAT2KC)KQcOY0*gGt_m}A^2e|lGv<|jwVn!7F4soL5a$DiH96onI$l4ln6CRd4t)PEURZNrW`v4 zzsvrBN@f7zKcH0SPWgOKDNUsR4Q{ldKl_A<1JI20&V=F`C`Z%P*x2=xI19IR zP1$KyH+c{6-irW-mHnUD1YA#OM1cDIADbNX6fFI9j$6y0om70J*YDHniy)_zS|(Wl zT?12z1=T$%7RW9y<;2fKK`;r=n5-Y9%LK#vKKvnWf=&M&Cb35y1M}y1J>a+FrFVrj z**o6vIv7G5!%j=$wsV0J-@ac0QRXYP;aFR+`mg)P@DBJFr%U}uI)n5q)S!c_qod6CRb8&<01vA$Y!vDyG3ed}d*vUC0&jH`B%*9%TdS~Kl! zu}k7`kM9?jg6#BHl0b4oGNC_B$l~iRQn7$HUxu%a6@k~a==Z~l;|yd)7==U|^zFto zpqG-ELTXq#a0tNs#Lf?sPaYaPd>4qjx1W0K?aqL3f~vEJG1qf;ePV%_$I;ukwmXdE&D3( za(KMc;&{}5%x$MA}2ZvVyfdoRG!-WATZ zSl_@|r-?AL!W7)1pHwTc6_(yfi%V%vDOF63aE8V{KI2g%kdb@Kv!|`#ZZ-66|GS4j zf7h{xyIYeG3Hf&$v?Ugv=9g$8cKGCgH%^ysXDM1C)q9P7M|xGRsF*%toS2&1x#{XL z6?yX=8`f3W1NeNjW840nMGRwe}PY zt)Vm%Z!CZ#6r=gDp7!yiE7QFi4Ysi`cmW~K{(4WZ@ia=?g5To0UAgXpw1D<>OH~xQ zSzK}n;?IP-QbxTz&#duzg@Dx)Abq{rOS&lDg;axy&j_jKV|%jRTkA8CY`PZRLMHQ~ z-NXH;nWQA7@E!A;3;8&_hji1&RVl8$fOOwp-tsbUl`$kz^YRQiKp%6U?KH%ZuoG)SLmS=(O#m7M0$?|4jF^Y`(8y;{?#DS2L^C- zMcR`FZLj#)CpMr;Pqwt6Q_gJ=gVNIL4N|bRcz&&>ESZV-y>BbTymaKfEcg)LWCn^O zw}F^gFreXs>LLQHs^0f7&)qSin(mpWu@5tGZ*0>+fmI!`U`QmAU%h*oi-5FiItE|w z7qbeA#zxLW{jso;^r(&dant|Hd2|gDor2666`LT={nVR;NvDhu^c>m>2Yl&quwdb= zk*MgZ=T04(<^jCYDW8x1<|6=8rqp>x*N`yHCT}k{$>Q#;ZrcKc7UG(lutf{53_7N< z=8Ar=P@-;wD?2hsu(+O%6*878ACahSn9rav{S;#I*E?c4YMdA!H#0)F-UR`DDbpxj z`|#olJuVEXUED<3)6j$NJ(5%j)inJd&3$=T()qtHW}_`GHP$$4YK^6>T9GR*?N)AO zTJBmVsJP}riinMsS*h9Lu2iPxZldCbSe8z?P@=e?V4;!=prW86a=&iPoO^!fKKGpG zIp<#f@d4qxeAf5-wY(QoSL<8W9_dYZOAyX_L~Ah z9@rb;da#9d*O-x-n0cPPDN1u@|ApCu)18_&^nxI>8EKKyy7j9T0Hsx=DlOHs_wq`@ zS#6)Uc%*1^j`ZT`>(U{n~wcEHhyTR_&2rP+wlnXk%D*Ms^{+{ZNKd7 zR`?t9#}&)C+FK`y1zwiTm3*CsGN2Ik7H-QQd+nNS6ZY5IHiLx^5m#OPVPdMuH-5eSPsgg>qH$fy^Y32v{9g&=>Kv~U&hHVVJEwtWMV>^l=r?+P8K~R~ zf6L%|BHLldAZ05uF;I%XpmG`C`OwC2f8HCk-Y*z;#i zBZ``=H)L?`N&PjL!*&JI-6Ei8>y1f|stJACW)F2q3kjK{wFWQnkk2zjK<0UR^HL%Z zcLqf5ryEZ7eMt_=ZB)ZX79q|%&_n?H<3yBR%jb*6^AO{wW`3fbe> z!g>GP=qwPZTElxY_Z7LOZ+n#Hak(*TH+I7VfVMCA{*$(cAwvc`np2P<^R3+MLBE=D zH%Q`8y1ZopteSa&;M1rtHgJGx7q8QHG~i9EDkvv}VEG8Af%f6X`<}}{RJ&z&Q*Ffu z4$>kIkQslaeXJ#1P4uy8x{c7f^+bYw>3#JXNUUw#W#t@h`1znPnN>{a@h{8yg|du{ zbH`Y8q4G$*CgQ_7AeLGo@!|pl`#Gg-l7e=NCI~`OCHjWy^gWK^Qw<@9gWOG|uFAc7 zsqiQp(|p+bNgzp&{`8NIHHw}kuqwPZ2WW$4rxGBy$1*e>&pgctU=OA2Tg-YG$ejgv zWb1CupnDDU+LcNF&%oVvM|>vd)U6L(aC;!r>I-T!->|O4pPshAxq!}|LkB%P0%vI)j%7oy6*e zE|jvWc_6J}x`ayrVc`7}!}Y3BnaM;DbukN(axJzEkhg|9qKs3gTRz)an>zLl#M%X4 zfqzZS>Che~nEQ>oWj(yXoqe&+@6|JkCIlNBSFt2aC|B~HySp)_tz>C)sgP84ys1xh z-4Q_tR6V?M^YDwlw3^WQU&ngH2LLT>I9_GW)N5@+FI}ZFkhhF;^0*!&Z7QR!3x&v? z%NSko?kK0G=hem=>&ePk0dcHe!|2jAftWu_RDRGPLNo9Z%AYr^c(JE<8_x-lhc|xM zu)QYhD`nq>1O*bHL6YI=>?`^>UvBVm_AP0cn*WLSjG13raji{6M;5qx^RP5F5=6XS z6L=M+Y1Z4Gumsnn?wdw+L3q$9D^I`!t64|90N)+@ErAik)`g!+}tJ{Z* z$Vy`ISM995Wma`hxHv{-xw&i9QG*#GVW)V^tuoaiix#8#52b6dlJ(UvGa*SW=m$R7 z(cdC7&MYk7NV_)o6hY_BH)H*B!(OaCQ9XKZ>A0k(nl-5}8W5jPJumO=)+%_@e_v^d zjJFTJl)8h|7+UThwBiKG03Os%8@>aM6p(rog{T)lF5Gx)uNgLVaUG8H#w->E$#y{(Vu zj*9%;TdYTFd?jx{$=gmoqJR$Z9uwr{UR}WrU|VYFJM78&HI~0Ho*h{YChxC!C0@?^ zTok8jbhW3KdsYvlQfnucM^8pD7Fis-FwHMz6Zw&yo`&JJM;xzoX|z@*1~&RU#{vTv zFA~J0zD`lL;gmB3wNk!w=NOD{U7t_>;v#b&@B_WP>ZCQ9XLklZR-P4dF|qw)+2o1N zXPsmFWQ+?(TKAxu+p;$XohNB^b23J4GP(~1S!;RBdD8R=;}t}5Ox#6swN!9^Ad=ak z-)dla^;t&yCxwmilTHhznEkq0bx3l!VOJibrSeX_oZ|SGgsyBhK&TX)I;2T9oDg^6 zwVXp%<=*??p7M~HayNHpXpOTQxt59CTtf-or@o*Y5B9NNICXtJF|>x2Hzukkp(fRg z!;QWcvfI75%#-3S4Fn5d4dTj-&byklPhrv0kAPSRc|k$jf{6IKs-*UZwOSa@TVeWN z6B7++BO}=f%Gwr$H;VUj$nO-}#a4@&=qLP*oC7k`-|NTq?Y5u-zdp<>(>LcB4DmrOW`7D@0Y`ePh0khTX@WUcJ(|TwDCF+POl{D z5qFn+^Jk7jxGPzIWX3uL`HOOD9k1X}_K)s}{U%5Iqkd0b@dvvI?~%YHLN*pnn5u2N?{ zq&1Ly(eh>--|l=FObEk*L=nwRR9t+=JyDCv4Kss)@%0(lp}^B==k+ zD2!wEJY#Qe`)$G_h>Fr9y>GW*57qSp&mP(a9OfsK406d>UK!J*m16To1UDgz!Qn6i z7SR66)1zH`hURBv(Fo&8B`J4yEI{lJ1Ayl>fF}e`N6BsrSv)0K^$+TACEp8i`F=B% zENF}&oXrMuF5U-nq#ny`jD&pSV8RP4D!Uph1p-*DhR*q(QcP}W_un+|Vd>=|(k8oT zq7Bgmq8VM`qo)$7xDrJH0W*j#WVG+%PmY06+hme`p*aqbTn4HKCOof;GC|3 z)j`|OFxg*LRBaNuOK1Bt(2f`Jp7*1N=Zoe=?8adz(RC zGz}eqaOG9~%|5rUO?43C3WG9i*+wlnO-u-GyLH8v5e)BT7-@SU zMj9A@*mda)8~*g-pNm_XD*y%g(H5d-R*3#KS?PYE z_R(|^ui5N9AfjWPxXZr0;h3%Xi{R0}2f?jl%M<`3GkIMJ;F4lZElLc0gW@M?=+}-0 z4u986YLQ-P2SEL>W$yO~2rYK+um1PYc9Zw=`1c8GZM_Oxrp0Zjzx@{<9HF7<-XM+X zg)IM*EjqEJ!~&!?fIf5W42LaNSGn~A z#|IH0CF`Y`Jsq4=37Gg+Ur8D(x1_QTSa0+|asQ#Zfb;&B=RSarM53Wu3nxa?FAUn3 z!IRDsw7p&yp=3DP{kk+&cdZ?`KJ4f06CeDSnv*3>&kKp%Z$s>Tzebx%E~!C?Yg`Mc zWkn70KO*c2h_v~sqWW_=Q~4R5tlrK48}k+8X%r$b&l8j2a|m~DiK}f=17cvaPVt$i zXl;^h1L5kA&QW#Av;7R&EdVt(r3FG?$`*at97tUVn<LtDos$%UK)3g}% z>vuz#YJ~=dOB5Ac;~Chg75;1u2t zks?P1Q#_i)J8izc9?I_@Dk|zc@SJf>J^+JT!kt+hk9&agtKTDLC0KRNw~ps8TrMtu z1NG}eQQ4~+g&anC80Uy}SV%L<@SOv7`Ki`GkL=yKGG-q}W$M-WViH&Yo{Tka7axd< z?5zPr)Z-qcyT1K@PBC9djUS<#!v|lkfzA3)Pj0F|BH7gm{|av^8=4s%1nK*oY`%I0 zZq^^sIPNSWeN5|1k>*Fh0&*u^f!UehB?=t}yex&CuV%>A6{$gO6V+Zhins(qwOuof zd6CvF3hV1W^W2tVZPotrTkeMO^#ikija4tP_DG|djE5sn%F#=T>QHXpE2z@jH}@#9 zw)`x>f63B&+5@=UOUc;E6VF8veU~o9RN%V#esm8+8W2pcjJtZ**p&!v!q3W#ok*F) zaUg)p9blCvJ1+@J24AGq1sUH`$9VwCg6FCk2Y){dNMZENMQ-_Q+6!_9lREOe2J!-~ zcsYQ=Uld7uT9;+oyRv?dQ;d07I5bNvXq|sV&-d)RcBpxMzdu}ztCthf@0G0yJAfg) zFNad?oU=_4E>ZD#*Sh9Op$T+AfjyrO8P|KpXO zZNlNgsI?t(;K)kirj%6KmmNg#rx(ZX0#Pi}hxjk95~y}XLEa-y+a#97J21<=BD2-< zCV4YUl7rC1Gv?Ln%l0JLSY^34y&c>F*C;-JD7Wa*xD39pNR!|fSror(v<=!@Ha?Sg zWki?fuQzPj4F{}#)T(WXICJvM?Q+6GVntnlp{7TItA%}Eo*{2?+Zq@V(X?ZkUYL8Y z90c1`pWCW^}iGJ^1JM?h(~xyD)P25}<2%|073| zeDl}q?71u3Lz*+9jR1Rc5De_S2@r6=@uSuu9~I;8fgKA!tE-B$Z!B4BKG=+}9}I*6 zF5Tue76P=YIN*HUv2J2EInvJV=EWu%4N1kNjvfRY6A%BL3*YwezjWbqX^Fv0dV>Z3 zuWcE#CZ~``ICgOrKwXLA=j4*=E5%ma8lJSdtJWpN6%n26ALUNo&d!C~HATT`onubz zbLGL3HLmRs`Y$;N~A&Isg{()k#qO z!C_H%#3$kQ3K6>%OWeC;cI(@k5gn|U9tWy*Vddr5YAsHE#BQh`o+6(4D4BO&B86dR zT~=`-3nNwejtA(2^ve8E4{XM@X(HYDL9F77t7K2WbPslJpIas|3GE5DifJBPx3vB_ zL+hIt9QWl1o4U$cbaSS%9j60i9w=85*AgtCoB`n4Y%|6JW~X1<4V%<{VaXUJWk1L?;l=BM8F2t_P>S-6x1Gs~%#F2tvU+iTcPq8|T6y>uAm3 z>}3{cc&ah_D|j*P=f+fUj)+HnssfW4`- zcJ#5ysP39@W4y)a!b8bpYdc>YAVmZm(ws|LBD0~16)Xv2GC^s1aw^^p5%VKl5G1OZ zgFiI2FRKZro?{^#!~=y0T;OY6yjGV;H)Z&kKeC|kQwj{fzqnGR^jL4-7Myw;{YsFo zG`(lc(VJ=XQ%+ugc3I78n6e9Gu~2nJBjJw5qWs?&X7*0DNZN&Ja0ENAIFDL)hx2F> zQR^Jj{|Ppy2Wy1huiyZ6ONP4A%qPzRax;U4 zz1j*e8?6q@RYiQ8aq_x}r94kFZL(|Uzt9E*)^&f7L`^Q5Vp1-fwkvT!V;*fPbb3G4P=%FMD@L zZ!XG(Nh#y+w0CXo-4bon)UqV^Y+4PCjw>ze-T#?D1;9%bqb^&}mqK&XswGerfN#31 z$~fQ48YVURHpU=D^{}qxo*Bo8C}&MVUp|M{LfZ3!vlE0sxx|1IEzGq)m^pUISmpyVHAPP~o61IqMm(4(msgdLPbwolS$pE|CwReAF+a6Q z>y~e589!Q5H|%tdA=kb*_isew$1_&Gv)Y#c4CC|yC>OW3(*Pgu)cC@Op8Z?z33@F1 z0|i$3Ta*g=Yx8v7PfTg)K!d-8(pvtJyMdT(fgWU*8UG;Ko*8 z*yr78wIWy;mvT>1LCM4B4T?R}#G@jKO0_{pB13!(^({eK2jcfXX@hQ1!J1K}EHv)~ z;cw3!?INzpm3G=-1%|TkW`|RKv-MK6UxymCJl07MIdl|^SC{dnWxH}YrkuZi!J0ey zPOmGGW3ZnjlOgtT+akbc+P%cVafc__w>ZQ6d)Tpf_z1vL)Xe|$zH-S|{YQ@z_7rKQdd9*5NEIO-W z6`}K}0YnX)P?7A~AKIU-jq~8B@)$VjJVpiN(tZEF)o!&pM@3X&qfa~0{uFLd$MU-U-o_b9kl(BF5NWsZdKy z@n|W-G9QO?ev7~>jwnkAk43l4?nJOmp;$xe?RX!GrT;qE@CMJ+%3?l;Yukzgr5$c< zI3E-4^s<$#HEx)miaoS3WU`icdrsIRft}Ou!^MhoGU}{5GcVEPs86p#%F(Ga;k9#b z=L5oqd70lUSC_z&$G{^RVF$+8H~T?p-Lfsb%I&^BU+$I8>BSe8Bxejdw)ZTIOGhj= zQTJqm=f<3cc~8|W_RGgqyZ#9jt}yz-H^@o)J>t0=&nw_;dS8lJCendfjy zoW-?$zYL=ca*3l#eA60jpD%3*cbZ=iONw)7>=8ja*WeStj9g186S*}SFo+UcZ7`R` zp@o{hV$wTNk}$104W?ic|H(cOkH;Hp)*y5g+T*5sV3^#jtdFtf85Epv zerDz=O!$0mtg=xN7DgPcVb=v<(i3#jlNldAOvlcwE7?d!FLE$U@RQb3JqYA-o5oeB z9=ElwrOXJgo&+D6&y@3(&*asmdbAM3M;c*~CdX@rOVz2V3CvicIw)>*mQpwCCj7HM zw~-VzO>UIzot{@kCM#(9keV3ZIX!~SQDvmMM=VwEa8gQJMmG2%D9l+<4k`cCf*?V? zDZ>X{IT^%bqaQyPbg6_paotcjR6!k4c@L=OZEKBbg+ImMa)(`8N3|CvlUP(uvu^%-!hJNHS5<=plh0W-eaUq> zn#G?+Yx)3rCMT0qouW$ygW4E$@oIDHqW?^wJ_t=Ve8O7HaaNto)809XMJz+z1xV z{iCodtW3^yw-$+?Sr}d8w4?6k&;x^XTPg#CE)thkGBqRh_U088sRtnt@EbQyi;9W{ zZ_{e7L$EUp9E*~9?T7h?{13O(O|vb80r%#5QjOJ zp=E6Hd8%T}9AbGOWK)JhA7QB8hkUVI3yas2!fDowUKdEeNQO}E#7-Ak@H-ddYa2(? z&D+XWPPZAmS?h(>stvg)%HmSceg#85d{j=hxw{gMd;WdazVE`rW_EFfMykG7-f)IH zs9(-KE%#C2nF`>l{cNkdJ+$0m0bdDb1g*-r2JRweg_un4PChi@o zQ@WU`%cUCXZAYZ@kWZ;|H*SpTD6#z)-&|eD(QcdzOUB0GiP0=x51Ue2g`FqxZikGnCTfVUEa(%n7kG|Ea)~4SUN1s(>$Zp{3ia(U7$xS% z73og#$);WtcL}&jycA=K?okj5YTVv@JLKIx8yoAyZ8Y_K9fZ^J?JkH+?7MWic^b`7 zK8P*G$37badA0Rw@_ykWXD41Rju943WYrzMEUgAa#RHIz6re0cNmEP1>F?+Tx-#o` zcvoB;rFbU6V_k_Yv97MJaxNJhWu~vBq!ipVn1C2h4VsJ%@ttTy@<~Q9vbK>D^cZoGkcpVfJH(Yq&^V zCS5x{O2xRqIWSc^&uG_v^TnKKOE3W3nrX++J|x=4Nm>iq8Vbm+AEYu;r7Me*kLG63 zQt5xBg1iL3R)i-fIq&8A1)NK_CRf-JN{kjiJ5~sq(Q$e*7Wq3MFA-ss(e>{(&FprX z`u6_Bm~_3CW;G%5$x^TL8w6kJKEftvU1?@ezn8bg`@pA(v19Z+Vw#baZ4s<{cld8D z8VP}zYet+DuWT$2C-h>;b@TN)`8w_HO`VlI$i9Pdqd%nJwTK=0&dR=hFK~v@&ecM( zIjkME!=E1JRMEKy##|Ilg_Yx1ck0J6fsPH2IMUIQ4Ud|KYx;84C#u*G{v<_ye!-P5 zL2b1bTt1>ThYWW0!8gqLpynZA#2;#^v*8E%6lxTz*SD}CgD69YKv?YMkUu&OpA1*_ z<(Bi52K7J~-2hbeO zdpz9tkQpMvr+`<)3F#iN51D%}bCGU2^LLZJ->l+l9QUn7#`U2LxR?D^^{lTIx@r;nS~Ta=`Qn(1^t%2w z+ZunuZkUaL0QhV(-A08ZxZ$PFkr00>g^i4Lz^j2I; zLe76Bn`Kligejy z0&AJ6htx%wV3N7{Ag#^ogW%=`xH@5rj7lO#1_G2#q#5{X*ZQ=b3pd_gE^a+}fToYN zmFC5r`0SQ7cbCZ+R~E|EtLXVGX0-uJ?FB%7KqF|*nRI*YULC9jo$tchL1xBjW3b$Swsnn5Ja(<@j7$L2t(sZj1g%~F=^ev0Mdk5Qjxw)*k zpV5a!f(7Dd`(~r)^6r#kL?6;I6+4Av8Wio~D?e!U4`IFarGfQ6BJs?tQEBKklL3gc zyAx4$kAsKJv*Ak(&!>{mViV^cR!wv4&%+qd`EV^Yk?xE}fs|1vqI3xJX;I9u|ETB< z?#xLsmw;p_RzfDI)gZJr5Ne3?=`YQ(kf<1LaS8b39zb)JiEbUMTbOFj1>{^Ht_A&L zcgcDejzc#0dIn}?N8%@?yOY&OvD{l@89;3N$q|$g%C+UAd~=?d11;8KNI3?uqv#_| z{T%YS4cB@Kni`ZK1*(p9@4ojb=%g+Mzk33zhG&s)dJ{vs{X6U$TE>~7j7p9Pm1tm3 zvL{v=nX=qezO#g$mFOR}f}~(H|3*#5wWqUHEnFMoJjX@YT+m9cGsW@F2EA&T7j^7} zv1!x%(BtCTInr~nrYE|NhB&J*`-+*ZnHf|tEFO2ykWfggJ6UvKFqMfVCJCYU8I|5 z&t|j2(=ExEuJsP<^lr=E274#ssL2md`>Q1CxsqMlS9bUNlB>2Nvq5R9j}69gu3a6o z1>^>N#Uj=GWAQymxH_<5@v0`o*s{a|Lunqrj5ba%g9Md$A6KE%s}1^! zWyFI$pK4-S$^0YREibd+V+Kd)Ved479{QTOi6_C{3gE4Lf!QtEaJ4?qD~R8%tldPZ z8icN~R4}(^}PdzwnS(X-ow*A?frt$==$WODGkbW(Vnw0VLRy zQG9b-#G$t5#@cX;<_I5(!S@O=J8n0PWbSBv3|LqOg-WPh>n1*YxMPknER2nn;(NJp zdV$Aib<^$a?dj_#da$q=Abd>TF{JC(5A=Y?t|bg9iYo;WJ;785A4ohd z9IPlavL%8vK?VZjZ(Yd9S`TQict)C-3q3eaDwH>+*-&9HKc0v5=#>z$kv5*OovRq> z^6q=xUud8=DhIKm&OLyfH;9l;quBAq@f3(iTTym)~_MInfH~25khZ2b4IvKyO-swpcNo zev8icA}^<*$BI93u`UYAUncLMu-|6VdudwF0)O+)LmANd?j{@R6Zny&6SUN;?R>4K zp%`?~IfygQ$yJgJ+vh=D-9QgZ*B*cN`}3p8)>ao3BCzi2tfb(eUg?zao09g&If#`)4J65WP<#bo>dgO-eji1+ok z(NBi!2-Gq)^R)XAWD-bUJ6mI3A+sq>Kj|-1dis66s{o>eziaf_Wq2zTs>Y8xJv?xP z591^wj*s)PkcaA?CWS|LwMPb$+LRmr<%f zC;nqCxB%9jMAx4TNMRn%A--#{-Ep92eC(hZRg=w@;H1!}(n9Q;q`t|n-0^X#toaPB z)LpO^9{x63+VCNpBO5VC)wg!Oa3lMZ8~iAbqj|eaVwhoSdRprQ?_H!gD`_HmL`RE% zl(aZ)ckbc>a}OyrnbC4A_xhyQ6698^sFV1vU^cTL%qGcuY5~-5C~pJ9r4)2VoU7E&1n7?qa?w|nGUPSknml-88`=xsn9VG zG2dD_-Ww%dP{TE;-|lSw8|OUu+P7{Fx?cw>Z@O2D^alir33(S-6q(#~aza@eYETRE zQX*dU-3`igiIL{LfpymiSGyYcb8+^c5bMRA|LyO#ycR0w$=4MI8w{=BJBJ Iy8QXS06Drig8%>k literal 0 HcmV?d00001 diff --git a/docs/quickstart.md b/docs/quickstart.md index 745db84..c41b51a 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -30,7 +30,21 @@ This quick start uses [docker compose v2](https://docs.docker.com/compose/). 1. __Populate Environment Variables for Provider Authentication__ -something +Populate the following environment variables where required (for a provider for which you have credentials and want to query): + +- `GITHUB_CREDS` (base64 encoded value of the GitHub username and Personal Acces Token) + +Then export a variable named `AUTH_STR` which will be passed to the stackql server. A complete example using GitHub credentials is shown here: + +```bash +export GITHUB_CREDS=$(echo -n 'yourusername:ghp_YOURPERSONALACCESSTOKEN' | base64) +export AUTH_STR='{ "github": { "type": "basic", "credentialsenvvar": "GITHUB_CREDS" }}' +``` + +```powershell +$Env:GITHUB_CREDS = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("yourusername:ghp_YOURPERSONALACCESSTOKEN")) +$Env:AUTH_STR = "{ 'github': { 'type': 'basic', 'credentialsenvvar': 'GITHUB_CREDS' } }" +``` 2. __Start Environment__ @@ -58,7 +72,23 @@ Use the query and the types in your application. 4. __Use the Middleware API__ -something +The middleware API is accessible through port `8080`, you can use Postman, `curl`, or any other client library such as `node-fetch` or `axios` to run StackQL queries against this endpoint and return results as `application/json` responses. + +Meta routes such as: + +- `/providers` +- `/providers/{providerName}/services` +- `/providers/{providerName}/services/{serviceName}/resources` +- `/providers/{providerName}/services/{serviceName}/resources/{resourceName}` +- `/providers/{providerName}/services/{serviceName}/resources/{resourceName}/methods` + +are accessible using `GET` requests as shown here: + +[![StackQL Meta Queries](images/stackql-postman-meta-queries.png)](images/stackql-postman-meta-queries.png) + +You can run a StackQL (`SELECT`) query against a `provider`, `service`, `resource` using a `POST` request as shown here: + +[![StackQL Queries](images/stackql-postman-queries.png)](images/stackql-postman-queries.png) 5. __Stop the Environment__ diff --git a/src/controllers/query.ts b/src/controllers/query.ts index 6be5983..5d46336 100644 --- a/src/controllers/query.ts +++ b/src/controllers/query.ts @@ -17,9 +17,15 @@ async function parseReqBody(body: any): Promise<{ queryOrError: string; showMeta let respStatus = 200; let queryOrError = ""; let showMetadata = false; + // try to parse the request body try { - inputData = JSON.parse(await body.value); + const bodyData = await body.value; + if (typeof bodyData === "object") { + inputData = bodyData; + } else { + inputData = JSON.parse(await bodyData); + } } catch(err) { respStatus = 400; queryOrError = "Bad Request"; From 6d1bc1fdf2704e513591a2508800c26f4c65a4cc Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 15:19:23 +1100 Subject: [PATCH 16/31] doc updates --- docs/quickstart.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/quickstart.md b/docs/quickstart.md index c41b51a..e6fcc97 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -36,11 +36,15 @@ Populate the following environment variables where required (for a provider for Then export a variable named `AUTH_STR` which will be passed to the stackql server. A complete example using GitHub credentials is shown here: +__MacOS/Linux__ + ```bash export GITHUB_CREDS=$(echo -n 'yourusername:ghp_YOURPERSONALACCESSTOKEN' | base64) export AUTH_STR='{ "github": { "type": "basic", "credentialsenvvar": "GITHUB_CREDS" }}' ``` +__Windows/PowerShell__ + ```powershell $Env:GITHUB_CREDS = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("yourusername:ghp_YOURPERSONALACCESSTOKEN")) $Env:AUTH_STR = "{ 'github': { 'type': 'basic', 'credentialsenvvar': 'GITHUB_CREDS' } }" From 56066884bfa51a1dca58a2613b26bfff891f41ff Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sat, 15 Oct 2022 15:26:24 +1100 Subject: [PATCH 17/31] doc updates --- docs/quickstart.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/quickstart.md b/docs/quickstart.md index e6fcc97..f5353a2 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -33,6 +33,10 @@ This quick start uses [docker compose v2](https://docs.docker.com/compose/). Populate the following environment variables where required (for a provider for which you have credentials and want to query): - `GITHUB_CREDS` (base64 encoded value of the GitHub username and Personal Acces Token) +- `AZ_ACCESS_TOKEN` (Azure access token) +- `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` (AWS API credentials) +- `OKTA_SECRET_KEY` (Okta API key) +- `NETLIFY_TOKEN` (Netlify API key) Then export a variable named `AUTH_STR` which will be passed to the stackql server. A complete example using GitHub credentials is shown here: From 4ebd6d52f7a29934626f09b595036ae2238a0910 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Sun, 16 Oct 2022 11:51:20 +1100 Subject: [PATCH 18/31] added demo scripts, allowed show and describe as queries --- .gitignore | 3 +++ .stackql/readline/readline.tmp | 1 + demo.ps1 | 26 ++++++++++++++++++++++++++ demo.sh | 28 ++++++++++++++++++++++++++++ docker-compose.yml | 6 ++++++ docs/quickstart.md | 7 +++++++ src/controllers/query.ts | 4 ++-- 7 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 demo.ps1 create mode 100644 demo.sh diff --git a/.gitignore b/.gitignore index 5d84ede..596a5e2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ src/creds/* creds/* stackql *.tmp +.demo-creds.sh +.demo-creds.ps1 +.demo-queries.sql # Logs logs diff --git a/.stackql/readline/readline.tmp b/.stackql/readline/readline.tmp index 917dee7..047af7e 100644 --- a/.stackql/readline/readline.tmp +++ b/.stackql/readline/readline.tmp @@ -9,3 +9,4 @@ show resources in github.repos like 'repo%'; describe github.repos.repos; show methods in github.repos.repos; select id, name from github.repos.repos where org = 'stackql'; +describe github.repos.repos; diff --git a/demo.ps1 b/demo.ps1 new file mode 100644 index 0000000..53b4dcf --- /dev/null +++ b/demo.ps1 @@ -0,0 +1,26 @@ +## credentials +$Env:AWS_ACCESS_KEY_ID = "YOURAWSACCESSKEYID" +$Env:AWS_SECRET_ACCESS_KEY = "YOURAWSSECRETACCESSKEY" +$Env:AZ_ACCESS_TOKEN = "$(az account get-access-token --query accessToken --output tsv)".Trim("`r") +$Env:GITHUB_CREDS = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("yourusername:ghp_YOURPERSONALACCESSTOKEN")) +$Env:OKTA_SECRET_KEY = "YOUROKTASECRETKEY" +$Env:NETLIFY_TOKEN = "YOURAPITOKEN" + +# auth objects +$aws = "{ 'type': 'aws_signing_v4', 'credentialsenvvar': 'AWS_SECRET_ACCESS_KEY', 'keyIDenvvar': 'AWS_ACCESS_KEY_ID' }" +$azure = "{ 'type': 'bearer', 'credentialsenvvar': 'AZ_ACCESS_TOKEN' }" +$github = "{ 'type': 'basic', 'credentialsenvvar': 'GITHUB_CREDS' }" +$okta = "{ 'type': 'api_key', 'credentialsenvvar': 'OKTA_SECRET_KEY' }" +$netlify = "{ 'type': 'bearer', 'credentialsenvvar': 'NETLIFY_TOKEN' }" + +## auth struct +$Env:AUTH_STR = "{ 'aws': $($aws), 'azure': $($azure), 'github': $($github), 'okta': $($okta), 'netlify': $($netlify) }" + +## build and run env +docker compose up --build + +## demo playground @ localhost:3000 +## demo API using Postman or curl @ localhost:8080 + +## remove containers +docker compose down \ No newline at end of file diff --git a/demo.sh b/demo.sh new file mode 100644 index 0000000..56d427d --- /dev/null +++ b/demo.sh @@ -0,0 +1,28 @@ +## credentials +export AWS_ACCESS_KEY_ID=YOURAWSACCESSKEYID +export AWS_SECRET_ACCESS_KEY=YOURAWSSECRETACCESSKEY +AZ_ACCESS_TOKEN_RAW=$(az account get-access-token --query accessToken --output tsv) +export AZ_ACCESS_TOKEN=`echo $AZ_ACCESS_TOKEN_RAW | tr -d '\r'` +export GITHUB_CREDS=$(echo -n 'yourusername:ghp_YOURPERSONALACCESSTOKEN' | base64) +export OKTA_SECRET_KEY=YOUROKTASECRETKEY # Okta API Token +export NETLIFY_TOKEN=YOURAPITOKEN + +# auth objects +AWS_AUTH='{ "type": "aws_signing_v4", "credentialsenvvar": "AWS_SECRET_ACCESS_KEY", "keyIDenvvar": "AWS_ACCESS_KEY_ID" }' +AZURE_AUTH='{ "type": "bearer", "credentialsenvvar": "AZ_ACCESS_TOKEN" }' +GITHUB_AUTH='{ "type": "basic", "credentialsenvvar": "GITHUB_CREDS" }' +OKTA_AUTH='{ "type": "api_key", "credentialsenvvar": "OKTA_SECRET_KEY" }' +NETLIFY_AUTH='{ "type": "bearer", "credentialsenvvar": "NETLIFY_TOKEN" }' + +## auth struct +template='{ "aws": %s, "azure": %s, "github": %s, "okta": %s, "netlify": %s }' +export AUTH_STR=$(printf "$template" "$AWS_AUTH","$AZURE_AUTH","$GITHUB_AUTH","$OKTA_AUTH","$NETLIFY_AUTH") + +## build and run env +docker compose up --build + +## demo playground @ localhost:3000 +## demo API using Postman or curl @ localhost:8080 + +## remove containers +docker compose down \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 7c49be0..eb51205 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,7 +36,13 @@ services: expose: - 5444 environment: + - AUTH_STR=${AUTH_STR} + - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} + - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} + - AZ_ACCESS_TOKEN=${AZ_ACCESS_TOKEN} - GITHUB_CREDS=${GITHUB_CREDS} + - OKTA_SECRET_KEY=${OKTA_SECRET_KEY} + - NETLIFY_TOKEN=${NETLIFY_TOKEN} command: - /bin/sh - -c diff --git a/docs/quickstart.md b/docs/quickstart.md index f5353a2..fb66167 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -54,6 +54,13 @@ $Env:GITHUB_CREDS = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF $Env:AUTH_STR = "{ 'github': { 'type': 'basic', 'credentialsenvvar': 'GITHUB_CREDS' } }" ``` +> for additional provider support, add their authentication objects to the `auth` struct as shown below, for more information about authentication, check the documentation for the respective provider, see [here](https://registry.stackql.io/) + +```bash +export GITHUB_CREDS=$(echo -n 'yourusername:ghp_YOURPERSONALACCESSTOKEN' | base64) +export AUTH_STR='{ "github": { "type": "basic", "credentialsenvvar": "GITHUB_CREDS" }, "aws": { "type": "aws_signing_v4", "credentialsenvvar": "AWS_SECRET_ACCESS_KEY", "keyIDenvvar": "AWS_ACCESS_KEY_ID" }}' +``` + 2. __Start Environment__ Run the following command in the same environment you used in Step 1 to populate yor environment variables: diff --git a/src/controllers/query.ts b/src/controllers/query.ts index 5d46336..9b7aa0c 100644 --- a/src/controllers/query.ts +++ b/src/controllers/query.ts @@ -43,9 +43,9 @@ async function parseReqBody(body: any): Promise<{ queryOrError: string; showMeta queryOrError = "Malformed Request - no query field"; } // is the query valid? - else if(!inputData.query.toLowerCase().startsWith("select")){ + else if(!inputData.query.toLowerCase().startsWith("select") && !inputData.query.toLowerCase().startsWith("show") && !inputData.query.toLowerCase().startsWith("describe")){ respStatus = 405; - queryOrError = "Method Not Allowed - methods other than SELECT are not supported in middleware server mode"; + queryOrError = "Method Not Allowed - methods other than SELECT, SHOW and DESCRIBE are not supported in middleware server mode"; } // looks good, return the query From 5b83c1476361aaca2c106f923ad9a1c8a5975a15 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Mon, 17 Oct 2022 10:17:51 +1100 Subject: [PATCH 19/31] added templates --- .github/CONTRIBUTING.md | 6 ++++ .github/ISSUE_TEMPLATE/bug_report.md | 38 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++ .stackql/readline/readline.tmp | 2 ++ 4 files changed, 66 insertions(+) create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..ec71840 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,6 @@ + +## Pull Requests + +Please fork our repository and then raise a Pull Request (PR) against our `dev` branch. Please add a fulsome description in the Pull Request comment. We will attend to it and work with you as soon as possible. + +Once the PR is approved, we will sign any changed files, package for distribution and squash / merge the combined change set into the `dev` branch. Once merged into `dev`, changes will instantly be available to `stackql` applications configured to integrate the `dev` registry. After an additional period of monitoring from the team, it will be promoted to our main / production branch. This equates to publication for default configured instances of `stackql`. diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..71a231a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[FEATURE]" +labels: enhancement +assignees: '' + +--- + +**Feature Description** +A clear and concise description of what you want to happen. + +**Example(s)** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Possible Approaches or Libraries to Consider** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.stackql/readline/readline.tmp b/.stackql/readline/readline.tmp index 047af7e..acf83d9 100644 --- a/.stackql/readline/readline.tmp +++ b/.stackql/readline/readline.tmp @@ -10,3 +10,5 @@ describe github.repos.repos; show methods in github.repos.repos; select id, name from github.repos.repos where org = 'stackql'; describe github.repos.repos; +select c.id, m.login, c.type, c.url from github.repos.contributors c inner join github.orgs.members m where m.org = 'stackql' and c.repo = 'stackql-playground' AND c.owner = 'stackql'; +select c.id, m.login, c.type, c.url from github.repos.contributors c inner join github.orgs.members m on m.id = c.id where m.org = 'stackql' and c.repo = 'stackql-playground' AND c.owner = 'stackql'; From fc2472571d79be50599192e0a55e8f976c883450 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Thu, 20 Oct 2022 08:12:55 +1100 Subject: [PATCH 20/31] added additional logging --- .gitignore | 1 + .stackql/readline/readline.tmp | 20 +++++++ docker-compose.yml | 1 + src/app.ts | 9 ++- src/controllers/meta.ts | 104 +++++++++++++++++---------------- src/controllers/query.ts | 20 ++++--- src/routes/meta.routes.ts | 11 ++++ src/routes/query.routes.ts | 7 +++ src/shared/data.ts | 12 +++- src/shared/logger.ts | 44 +++++++------- src/shared/params.ts | 16 ++++- 11 files changed, 160 insertions(+), 85 deletions(-) diff --git a/.gitignore b/.gitignore index 596a5e2..8753049 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ src/creds/* .stackql/* creds/* stackql +stackql.exe *.tmp .demo-creds.sh .demo-creds.ps1 diff --git a/.stackql/readline/readline.tmp b/.stackql/readline/readline.tmp index acf83d9..cc4c48f 100644 --- a/.stackql/readline/readline.tmp +++ b/.stackql/readline/readline.tmp @@ -12,3 +12,23 @@ select id, name from github.repos.repos where org = 'stackql'; describe github.repos.repos; select c.id, m.login, c.type, c.url from github.repos.contributors c inner join github.orgs.members m where m.org = 'stackql' and c.repo = 'stackql-playground' AND c.owner = 'stackql'; select c.id, m.login, c.type, c.url from github.repos.contributors c inner join github.orgs.members m on m.id = c.id where m.org = 'stackql' and c.repo = 'stackql-playground' AND c.owner = 'stackql'; +select * from azure.compute.virtual_machines WHERE subscriptionId = '631d1c6d-2a65-43e7-93c2-688bfe4e1468'; +registry list; +registry pull azure v0.3.0; +select * from azure.compute.virtual_machines WHERE subscriptionId = '631d1c6d-2a65-43e7-93c2-688bfe4e1468'; +select id, name, properties from azure.compute.virtual_machines WHERE subscriptionId = '631d1c6d-2a65-43e7-93c2-688bfe4e1468'; +SELECT instanceState, COUNT(*) as num_instances FROM aws.ec2.instances WHERE region = 'ap-southeast-2' GROUP BY instanceState; +registry list; +registry pull aws v0.1.3; +SELECT instanceState, COUNT(*) as num_instances FROM aws.ec2.instances WHERE region = 'ap-southeast-2' GROUP BY instanceState; +select id, name from azure.compute.virtual_machines WHERE subscriptionId = '631d1c6d-2a65-43e7-93c2-688bfe4e1468'; +SELECT instanceState, COUNT(*) as num_instances FROM aws.ec2.instances WHERE region = 'ap-southeast-2' GROUP BY instanceState; +show services in aws; +show resources in aws.cloud_control; +show methds in aws.cloud_control.resources; +show methods in aws.cloud_control.resources; +describe aws.cloud_control.resources; +select * from aws.cloud_control.resources where data__TypeName = 'AWS::Logs::LogGroup'; +select * from aws.cloud_control.resources where data__TypeName = 'AWS::Logs::LogGroup' and region = 'ap-southeast2'; +select * from aws.cloud_control.resources where data__TypeName = 'AWS::Logs::LogGroup' and region = 'ap-southeast-2'; +select * from aws.cloud_control.resources where data__TypeName = 'AWS::EC2::Instance' and region = 'ap-southeast-2'; diff --git a/docker-compose.yml b/docker-compose.yml index eb51205..25aad96 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -57,6 +57,7 @@ services: DB_HOST: 'runner' DB_PORT: 5444 DB_DEBUG: 'false' + LOGLEVEL: ${LOGLEVEL} ports: - 8080:8080 # depends_on: diff --git a/src/app.ts b/src/app.ts index cc74b04..16975a7 100644 --- a/src/app.ts +++ b/src/app.ts @@ -3,15 +3,18 @@ import { oakCors } from "https://deno.land/x/cors/mod.ts"; import { router } from "./routes/routes.ts"; import _404 from "./controllers/404.ts"; import { Context } from "./types/context.ts"; -import * as logger from "./shared/logger.ts"; +import { logger, + formatDetailedLogMessage, +} from "./shared/logger.ts"; const env = Deno.env.toObject() const HOST = env.HOST || '0.0.0.0' const PORT = env.PORT || 8080 -const LOGLEVEL = env.LOGLEVEL || 'info' const app = new Application(); +const fileName = 'app.ts'; + app.use(oakCors()); app.use(router.routes()); app.use(router.allowedMethods()); @@ -23,7 +26,7 @@ app.addEventListener("listen", ({ hostname, port, serverType }) => { app.addEventListener( "error", - (e) => logger.error(`Server error : ${e.message}`) + (e: any) => logger.error(formatDetailedLogMessage(`Server error : ${e.message}`, fileName, 'app.addEventListener')), ); await app.listen({ hostname: HOST, port: PORT }); \ No newline at end of file diff --git a/src/controllers/meta.ts b/src/controllers/meta.ts index 7f88bcd..ae6a675 100644 --- a/src/controllers/meta.ts +++ b/src/controllers/meta.ts @@ -1,30 +1,35 @@ // import * as logger from "./../shared/logger.ts"; import { Context } from "./../types/context.ts"; import { + getPathParams, getQueryParams, getQueryFilter } from "./../shared/params.ts"; import { getData } from "../shared/data.ts"; +import { + logger, + formatDetailedLogMessage, +} from "./../shared/logger.ts"; + +const fileName = 'controllers/meta.ts'; /** * return all providers installed */ const showProviders = async (ctx: Context) => { - // parse query params - const queryParams = await getQueryParams(ctx); + const functionName = 'showProviders'; - // showMetadata - const showMetadata = queryParams.showMetadata || false; - - // dts - const dts = queryParams.dts || false; + // parse query params + const queryParams = await getQueryParams(ctx, fileName, functionName); - // run query + // set query const iqlQuery = `SHOW PROVIDERS`; + logger.debug(formatDetailedLogMessage(`iqlQuery: ${iqlQuery}`, fileName, functionName)); // return results - const respData = await getData(iqlQuery, showMetadata, dts); + const respData = await getData(iqlQuery, queryParams.showMetadata); + logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); ctx.response.status = respData.respStatus; ctx.response.type = respData.respType; ctx.response.body = respData.respBody; @@ -35,26 +40,26 @@ const showProviders = async (ctx: Context) => { */ const showServices = async (ctx: Context) => { + const functionName = 'showServices'; + // get path params - const providerName = ctx.params.providerName; + const pathParams = await getPathParams(ctx, fileName, functionName); + const providerName = pathParams.providerName; // parse query params - const queryParams = await getQueryParams(ctx); + const queryParams = await getQueryParams(ctx, fileName, functionName); // filter param? const filterParam = await getQueryFilter(ctx); - - // showMetadata - const showMetadata = queryParams.showMetadata || false; - - // dts - const dts = queryParams.dts || false; + logger.debug(formatDetailedLogMessage(`filterParam: ${filterParam}`, fileName, functionName)); // run query const iqlQuery = `SHOW EXTENDED SERVICES IN ${providerName}${filterParam}`; + logger.debug(formatDetailedLogMessage(`iqlQuery: ${iqlQuery}`, fileName, functionName)); // return results - const respData = await getData(iqlQuery, showMetadata, dts); + const respData = await getData(iqlQuery, queryParams.showMetadata); + logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); ctx.response.status = respData.respStatus; ctx.response.type = respData.respType; ctx.response.body = respData.respBody; @@ -65,27 +70,26 @@ const showServices = async (ctx: Context) => { */ const showResources = async (ctx: Context) => { - // get path params - const providerName = ctx.params.providerName; - const serviceName = ctx.params.serviceName; + const functionName = 'showResources'; + // get path params + const pathParams = await getPathParams(ctx, fileName, functionName); + const providerName = pathParams.providerName; + const serviceName = pathParams.serviceName; + // parse query params - const queryParams = await getQueryParams(ctx); + const queryParams = await getQueryParams(ctx, fileName, functionName); // filter param? const filterParam = await getQueryFilter(ctx); - // showMetadata - const showMetadata = queryParams.showMetadata || false; - - // dts - const dts = queryParams.dts || false; - // run query const iqlQuery = `SHOW EXTENDED RESOURCES IN ${providerName}.${serviceName}${filterParam}`; + logger.debug(formatDetailedLogMessage(`iqlQuery: ${iqlQuery}`, fileName, functionName)); // return results - const respData = await getData(iqlQuery, showMetadata, dts); + const respData = await getData(iqlQuery, queryParams.showMetadata); + logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); ctx.response.status = respData.respStatus; ctx.response.type = respData.respType; ctx.response.body = respData.respBody; @@ -96,25 +100,24 @@ const showServices = async (ctx: Context) => { */ const describeResource = async (ctx: Context) => { + const functionName = 'describeResource'; + // get path params - const providerName = ctx.params.providerName; - const serviceName = ctx.params.serviceName; - const resourceName = ctx.params.resourceName; + const pathParams = await getPathParams(ctx, fileName, functionName); + const providerName = pathParams.providerName; + const serviceName = pathParams.serviceName; + const resourceName = pathParams.resourceName; // parse query params - const queryParams = await getQueryParams(ctx); - - // showMetadata - const showMetadata = queryParams.showMetadata || false; - - // dts - const dts = queryParams.dts || false; + const queryParams = await getQueryParams(ctx, fileName, functionName); // run query const iqlQuery = `DESCRIBE EXTENDED ${providerName}.${serviceName}.${resourceName}`; + logger.debug(formatDetailedLogMessage(`iqlQuery: ${iqlQuery}`, fileName, functionName)); // return results - const respData = await getData(iqlQuery, showMetadata, dts); + const respData = await getData(iqlQuery, queryParams.showMetadata); + logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); ctx.response.status = respData.respStatus; ctx.response.type = respData.respType; ctx.response.body = respData.respBody; @@ -125,25 +128,24 @@ const showServices = async (ctx: Context) => { */ const showMethods = async (ctx: Context) => { + const functionName = 'showMethods'; + // get path params - const providerName = ctx.params.providerName; - const serviceName = ctx.params.serviceName; - const resourceName = ctx.params.resourceName; + const pathParams = await getPathParams(ctx, fileName, functionName); + const providerName = pathParams.providerName; + const serviceName = pathParams.serviceName; + const resourceName = pathParams.resourceName; // parse query params - const queryParams = await getQueryParams(ctx); - - // showMetadata - const showMetadata = queryParams.showMetadata || false; - - // dts - const dts = queryParams.dts || false; + const queryParams = await getQueryParams(ctx, fileName, functionName); // run query const iqlQuery = `SHOW EXTENDED METHODS IN ${providerName}.${serviceName}.${resourceName}`; + logger.debug(formatDetailedLogMessage(`iqlQuery: ${iqlQuery}`, fileName, functionName)); // return results - const respData = await getData(iqlQuery, showMetadata, dts); + const respData = await getData(iqlQuery, queryParams.showMetadata); + logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); ctx.response.status = respData.respStatus; ctx.response.type = respData.respType; ctx.response.body = respData.respBody; diff --git a/src/controllers/query.ts b/src/controllers/query.ts index 9b7aa0c..04caee3 100644 --- a/src/controllers/query.ts +++ b/src/controllers/query.ts @@ -5,6 +5,12 @@ import { getData, getTypes, } from "../shared/data.ts"; + import { + logger, + formatDetailedLogMessage, +} from "./../shared/logger.ts"; + +const fileName = 'controllers/query.ts'; export interface RespData { respStatus: number; @@ -59,6 +65,8 @@ async function parseReqBody(body: any): Promise<{ queryOrError: string; showMeta */ export const runQuery = async (ctx: Context) => { + const functionName = 'runQuery'; + // exit if body is empty if (!ctx.request.hasBody) { ctx.response.status = 400; @@ -67,10 +75,11 @@ export const runQuery = async (ctx: Context) => { } // parse query params - const queryParams = await getQueryParams(ctx); + const queryParams = await getQueryParams(ctx, fileName, functionName); // parse body - const bodyObj = await parseReqBody(await ctx.request.body()); + const bodyObj = await parseReqBody(await ctx.request.body()); + logger.debug(formatDetailedLogMessage(`bodyObj: ${JSON.stringify(bodyObj)}`, fileName, functionName)); if(bodyObj.respStatus != 200){ // something went wrong, get out @@ -79,9 +88,6 @@ export const runQuery = async (ctx: Context) => { return; } - // get types? - const dts = queryParams.dts || false; - // show metadata? (ignored if dts is specified) let showMetadata = false; @@ -97,14 +103,14 @@ export const runQuery = async (ctx: Context) => { respBody: 'Something went wrong', }; - if(dts){ + if(queryParams.dts){ // get types respData = await getTypes(iqlQuery); } else { // get data respData = await getData(iqlQuery, showMetadata); } - + logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); ctx.response.status = respData.respStatus; ctx.response.type = respData.respType; ctx.response.body = respData.respBody; diff --git a/src/routes/meta.routes.ts b/src/routes/meta.routes.ts index 5ebdc6e..2eb3223 100644 --- a/src/routes/meta.routes.ts +++ b/src/routes/meta.routes.ts @@ -1,5 +1,11 @@ import { Context } from "./../types/context.ts"; import * as metaController from "./../controllers/meta.ts"; +import { + logger, + formatDetailedLogMessage, +} from "./../shared/logger.ts"; + +const fileName = 'routes/meta.routes.ts'; /** * show all providers installed @@ -8,6 +14,7 @@ import * as metaController from "./../controllers/meta.ts"; const getProviders = [ // userGuard(UserRole.ADMIN), async (ctx: Context) => { + logger.debug(formatDetailedLogMessage(`getProviders route invoked`, fileName, 'getProviders')); await metaController.showProviders(ctx); }, ]; @@ -19,6 +26,7 @@ const getProviders = [ const getServices = [ // userGuard(UserRole.ADMIN), async (ctx: Context) => { + logger.debug(formatDetailedLogMessage(`getServices route invoked, context: ${JSON.stringify(ctx)}`, fileName, 'getServices')); await metaController.showServices(ctx); }, ]; @@ -30,6 +38,7 @@ const getProviders = [ const getResources = [ // userGuard(UserRole.ADMIN), async (ctx: Context) => { + logger.debug(formatDetailedLogMessage(`getResources route invoked, context: ${JSON.stringify(ctx)}`, fileName, 'getResources')); await metaController.showResources(ctx); }, ]; @@ -41,6 +50,7 @@ const getProviders = [ const getResourceFields = [ // userGuard(UserRole.ADMIN), async (ctx: Context) => { + logger.debug(formatDetailedLogMessage(`getResourceFields route invoked, context: ${JSON.stringify(ctx)}`, fileName, 'getResourceFields')); await metaController.describeResource(ctx); }, ]; @@ -52,6 +62,7 @@ const getProviders = [ const getResourceMethods = [ // userGuard(UserRole.ADMIN), async (ctx: Context) => { + logger.debug(formatDetailedLogMessage(`getResourceMethods route invoked, context: ${JSON.stringify(ctx)}`, fileName, 'getResourceMethods')); await metaController.showMethods(ctx); }, ]; diff --git a/src/routes/query.routes.ts b/src/routes/query.routes.ts index 94d03a5..92ded80 100644 --- a/src/routes/query.routes.ts +++ b/src/routes/query.routes.ts @@ -1,5 +1,11 @@ import { Context } from "./../types/context.ts"; import * as queryController from "./../controllers/query.ts"; +import { + logger, + formatDetailedLogMessage, +} from "./../shared/logger.ts"; + +const fileName = 'routes/query.routes.ts'; /** * run a stackql SELECT query @@ -8,6 +14,7 @@ import * as queryController from "./../controllers/query.ts"; const runQuery = [ // userGuard(UserRole.ADMIN), async (ctx: Context) => { + logger.debug(formatDetailedLogMessage(`runQuery route invoked, context: ${JSON.stringify(ctx)}`, fileName, 'runQuery')); await queryController.runQuery(ctx); }, ]; diff --git a/src/shared/data.ts b/src/shared/data.ts index 4f7332f..e6bfb42 100644 --- a/src/shared/data.ts +++ b/src/shared/data.ts @@ -1,6 +1,11 @@ import { generateTypes } from "https://deno.land/x/dts/mod.ts"; import { Client } from "https://deno.land/x/postgres@v0.16.1/mod.ts"; -// import * as logger from "./../shared/logger.ts"; +import { + logger, + formatDetailedLogMessage, +} from "./logger.ts"; + +const fileName = 'shared/data.ts'; /* * get stackql srv env vars and initiate connection @@ -38,6 +43,8 @@ function reType(input: any): any { async function getData(iqlQuery: string, showMetadata: boolean): Promise< { respStatus: number; respType: string; respBody: string; } > { + const functionName = 'getData'; + // run query try { @@ -72,9 +79,12 @@ async function getData(iqlQuery: string, showMetadata: boolean): Promise< { resp metadata : showMetadata ? metadata : null } + logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); + return { respStatus: 200, respType: 'application/json', respBody: `${JSON.stringify(respData)}\n` }; } catch (error) { + logger.debug(formatDetailedLogMessage(`error: ${JSON.stringify(error)}`, fileName, functionName)); const errResp = { error: error.message.replace(/\n/g, ""), }; diff --git a/src/shared/logger.ts b/src/shared/logger.ts index 6aa17ba..eadd7ec 100644 --- a/src/shared/logger.ts +++ b/src/shared/logger.ts @@ -1,29 +1,29 @@ -import { - bold, - cyan, - green, - yellow, - } from "https://deno.land/std@0.152.0/fmt/colors.ts"; +import * as log from "https://deno.land/std@0.160.0/log/mod.ts"; -function getDateTime(){ - const now = new Date(); - return `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()} ${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`; -} +const env = Deno.env.toObject() +const LOGLEVEL = env.LOGLEVEL || 'INFO' + +console.log(`LOGLEVEL: ${LOGLEVEL}`); -const info = (message: string) => { - console.log(`${bold(green(getDateTime()))} ${bold(green('INFO'))} ${bold(message)}`); -}; +await log.setup({ + handlers: { + console: new log.handlers.ConsoleHandler(LOGLEVEL), + }, + loggers: { + default: { + level: LOGLEVEL, + handlers: ["console"], + }, + } +}); -const error = (message: string) => { - console.log(`${bold(cyan(getDateTime()))} ${bold(cyan('ERROR'))} ${bold(message)}`); -}; +const logger = log.getLogger(); -const debug = (message: string) => { - console.log(`${bold(yellow(getDateTime()))} ${bold(yellow('DEBUG'))} ${bold(message)}`); -}; +const formatDetailedLogMessage = (msg: string, fileName: string, functionName: string): string => { + return `${msg} (${fileName}, ${functionName})`; +} export { - info, - error, - debug, + logger, + formatDetailedLogMessage, } \ No newline at end of file diff --git a/src/shared/params.ts b/src/shared/params.ts index 4ec1127..c1e5a56 100644 --- a/src/shared/params.ts +++ b/src/shared/params.ts @@ -1,13 +1,26 @@ import { Context } from "./../types/context.ts"; +import { + logger, + formatDetailedLogMessage, +} from "./logger.ts"; + +/** + * return values for specified path params + */ + async function getPathParams(ctx: Context, fileName: string, functionName: string): Promise< Record >{ + logger.debug(formatDetailedLogMessage(`pathParams: ${JSON.stringify(ctx.params)}`, fileName, functionName)); + return ctx.params; +} /** * return state for known query params */ -async function getQueryParams(ctx: Context): Promise<{ showMetadata: boolean; dts: boolean; }>{ +async function getQueryParams(ctx: Context, fileName: string, functionName: string): Promise<{ showMetadata: boolean; dts: boolean; }>{ let showMetadata = false; let dts = false; ctx.request.url.searchParams.get('showMetadata') === '' ? showMetadata = true : showMetadata = false; ctx.request.url.searchParams.get('dts') === '' ? dts = true : dts = false; + logger.debug(formatDetailedLogMessage(`searchParams: ${JSON.stringify(Array.from(ctx.request.url.searchParams.values()))}`, fileName, functionName)); return { showMetadata: showMetadata, dts: dts }; } @@ -25,6 +38,7 @@ async function getQueryFilter(ctx: Context): Promise{ } export { + getPathParams, getQueryParams, getQueryFilter, } \ No newline at end of file From fd52edb093f8f187de4f84157da0d2ed67c07684 Mon Sep 17 00:00:00 2001 From: jeffreyaven Date: Thu, 20 Oct 2022 16:16:42 +1100 Subject: [PATCH 21/31] fix type generation for nested objects --- src/shared/data.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/shared/data.ts b/src/shared/data.ts index e6bfb42..9e56fe6 100644 --- a/src/shared/data.ts +++ b/src/shared/data.ts @@ -99,9 +99,16 @@ async function getTypes(iqlQuery: string): Promise< { respStatus: number; respTy // connect, run query and get results const data = await client.queryObject(iqlQuery); + const firstRow = data.rows[0]; + + // parse each field + const castedFields = {}; + Object.keys(firstRow).forEach(k => { + castedFields[k] = reType(firstRow[k]); + }); // get types - const result = await generateTypes(data.rows[0]); + const result = await generateTypes(castedFields); return { respStatus: 200, respType: 'application/text', respBody: result }; From 21ad10fdf8ee4c266675551a25da82543e9e2f47 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Thu, 6 Feb 2025 10:30:32 +1100 Subject: [PATCH 22/31] updates --- .vscode/settings.json | 3 + Dockerfile | 15 -- README.md | 23 ++- docker-compose.yml | 75 +++----- ...stackql-middleware.postman_collection.json | 111 ++++++++++++ runner.Dockerfile | 15 ++ src/Dockerfile | 16 +- src/README.md | 132 +++++++++------ src/README_old.md | 55 ++++++ src/app.ts | 79 +++++---- src/config/environment.ts | 16 ++ src/controllers/404.ts | 4 - src/controllers/auth.ts | 0 src/controllers/health.controller.ts | 6 + src/controllers/meta.controller.ts | 75 ++++++++ src/controllers/meta.ts | 160 ------------------ src/controllers/misc.ts | 6 - src/controllers/query.controller.ts | 64 +++++++ src/controllers/query.ts | 118 ------------- src/deps.ts | 6 + src/middleware/error.middleware.ts | 18 ++ src/routes/auth.routes.ts | 0 src/routes/health.routes.ts | 6 + src/routes/meta.routes.ts | 86 ++-------- src/routes/misc.routes.ts | 16 -- src/routes/query.routes.ts | 28 +-- src/routes/routes.ts | 22 --- src/services/database.service.ts | 35 ++++ src/services/logger.service.ts | 17 ++ src/shared/data.ts | 126 -------------- src/shared/logger.ts | 29 ---- src/shared/params.ts | 44 ----- src/tests/api.test.ts | 77 +++++++++ src/types/api.types.ts | 29 ++++ src/types/auth.ts | 15 -- src/types/context.ts | 9 - src/types/context.types.ts | 9 + src/utils/query.utils.ts | 15 ++ 38 files changed, 749 insertions(+), 811 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 Dockerfile create mode 100644 postman/stackql-middleware.postman_collection.json create mode 100644 runner.Dockerfile create mode 100644 src/README_old.md create mode 100644 src/config/environment.ts delete mode 100644 src/controllers/404.ts delete mode 100644 src/controllers/auth.ts create mode 100644 src/controllers/health.controller.ts create mode 100644 src/controllers/meta.controller.ts delete mode 100644 src/controllers/meta.ts delete mode 100644 src/controllers/misc.ts create mode 100644 src/controllers/query.controller.ts delete mode 100644 src/controllers/query.ts create mode 100644 src/deps.ts create mode 100644 src/middleware/error.middleware.ts delete mode 100644 src/routes/auth.routes.ts create mode 100644 src/routes/health.routes.ts delete mode 100644 src/routes/misc.routes.ts delete mode 100644 src/routes/routes.ts create mode 100644 src/services/database.service.ts create mode 100644 src/services/logger.service.ts delete mode 100644 src/shared/data.ts delete mode 100644 src/shared/logger.ts delete mode 100644 src/shared/params.ts create mode 100644 src/tests/api.test.ts create mode 100644 src/types/api.types.ts delete mode 100644 src/types/auth.ts delete mode 100644 src/types/context.ts create mode 100644 src/types/context.types.ts create mode 100644 src/utils/query.utils.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..04cf127 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "deno.enable": true +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index d93de8c..0000000 --- a/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM stackql/stackql:latest -EXPOSE 5444 -WORKDIR /home/stackql -RUN adduser --system --uid 1001 stackql -RUN addgroup --system --gid 1001 stackql -RUN chown stackql:stackql /home/stackql -RUN chown stackql:stackql /srv -USER stackql -RUN stackql exec 'registry pull aws v0.1.3' -RUN stackql exec 'registry pull azure v0.3.0' -RUN stackql exec 'registry pull google v1.0.4' -RUN stackql exec 'registry pull github v0.3.6' -RUN stackql exec 'registry pull k8s v0.1.1' -RUN stackql exec 'registry pull netlify v0.2.0' -RUN stackql exec 'registry pull okta v0.1.0' \ No newline at end of file diff --git a/README.md b/README.md index 24cd0e2..2f9029d 100644 --- a/README.md +++ b/README.md @@ -41,10 +41,27 @@ The StackQL middleware server enables clients to query api backends using a natu Results can be operated on using SQL functions and operators (including grouping, windowing, and aggregation functions) and then returned to the client as a JSON response. The following architecture diagram illustrates the StackQL middleware server's components. +### Context Diagram -

-StackQL Middleware Context -
+```mermaid +C4Context + Person(user, "User or UserAgent") + + Boundary(b0, "stackql Middleware") { + Container(api, "stackql API", "Deno Oak", "accepts http requests with stackql queries") + Container(runner, "stackql runner", "stackql srv", "runs stackql queries against providers") + } + + System_Ext(cloudprovider, "Cloud or Data Provider", "cloud or data resources") + + Rel(user, api, "submits stackql queries", "POST /stackql") + BiRel(api, runner, "via pgwire") + BiRel(runner, cloudprovider, "makes api calls", "HTTP/HTTPS") + + UpdateRelStyle(api, runner, $offsetX="-20", $offsetY="-15") + UpdateRelStyle(runner, cloudprovider, $offsetX="10", $offsetY="-40") + UpdateRelStyle(user, api, $offsetX="0", $offsetY="-40") +``` Detailed design documentation can be found [here](docs/detailed-design.md). diff --git a/docker-compose.yml b/docker-compose.yml index 25aad96..92f2a2a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,16 +1,4 @@ -version: "3.9" services: - # credentialsgen: - # image: alpine/openssl - # volumes: - # - ./vol/srv/credentials:/srv:rw - # command: - # - bash - # - -c - # - | - # wget https://raw.githubusercontent.com/stackql/stackql/main/test/server/mtls/openssl.cnf /srv/openssl.cnf && \ - # openssl req -x509 -keyout /srv/pg_server_key.pem -out /srv/pg_server_cert.pem -config /srv/openssl.cnf -days 365 && \ - # openssl req -x509 -keyout /srv/pg_client_key.pem -out /srv/pg_client_cert.pem -config /srv/openssl.cnf -days 365 playground: image: stackql/stackql-playground:latest environment: @@ -18,49 +6,40 @@ services: MIDDLEWARE_HOST: 'api' MIDDLEWARE_PORT: '8080' ports: - - 3000:3000 + - "3000:3000" + depends_on: + - api + runner: build: context: . - cache_from: - - stackql/stackql - working_dir: /home/stackql - # volumes: - # - ./vol/srv/credentials:/srv:ro - # environment: - # PGSSLSRVKEY: 'true' - # PGSSLROOTCERT: 'true' - # CLIENT_CERT: 'true' - # depends_on: - # - credentialsgen + dockerfile: runner.Dockerfile + working_dir: /home/stackql expose: - 5444 environment: - - AUTH_STR=${AUTH_STR} - - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} - - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} - - AZ_ACCESS_TOKEN=${AZ_ACCESS_TOKEN} - - GITHUB_CREDS=${GITHUB_CREDS} - - OKTA_SECRET_KEY=${OKTA_SECRET_KEY} - - NETLIFY_TOKEN=${NETLIFY_TOKEN} - command: - - /bin/sh - - -c - - | - stackql --version && \ - stackql --auth="${AUTH_STR}" --pgsrv.port=5444 srv + - AWS_ACCESS_KEY_ID + - AWS_SECRET_ACCESS_KEY + - GITHUB_CREDS + - OKTA_SECRET_KEY + - NETLIFY_TOKEN + healthcheck: + test: ["CMD", "stackql", "--version"] + interval: 10s + timeout: 5s + retries: 3 + command: stackql --pgsrv.port=5444 srv + api: - build: src/ - # volumes: - # - ./vol/srv/credentials:/srv:ro + build: + context: ./src + dockerfile: Dockerfile environment: - DB_HOST: 'runner' + DB_HOST: runner DB_PORT: 5444 - DB_DEBUG: 'false' - LOGLEVEL: ${LOGLEVEL} + LOGLEVEL: ${LOGLEVEL:-INFO} ports: - - 8080:8080 - # depends_on: - # - runner - cache: - image: redis:alpine \ No newline at end of file + - "8080:8080" + depends_on: + runner: + condition: service_healthy \ No newline at end of file diff --git a/postman/stackql-middleware.postman_collection.json b/postman/stackql-middleware.postman_collection.json new file mode 100644 index 0000000..75af184 --- /dev/null +++ b/postman/stackql-middleware.postman_collection.json @@ -0,0 +1,111 @@ +{ + "info": { + "name": "StackQL Middleware", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Health", + "request": { + "method": "GET", + "url": { + "raw": "{{base_url}}/health" + } + } + }, + { + "name": "Execute Query", + "request": { + "method": "POST", + "url": { + "raw": "{{base_url}}/stackql" + }, + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"query\": \"SELECT name, region FROM aws.s3.buckets LIMIT 5\",\n \"showMetadata\": true\n}" + } + } + }, + { + "name": "List Providers", + "request": { + "method": "GET", + "url": { + "raw": "{{base_url}}/providers" + } + } + }, + { + "name": "List AWS Services", + "request": { + "method": "GET", + "url": { + "raw": "{{base_url}}/providers/aws/services" + } + } + }, + { + "name": "List S3 Resources", + "request": { + "method": "GET", + "url": { + "raw": "{{base_url}}/providers/aws/services/s3/resources" + } + } + }, + { + "name": "S3 Bucket Resource Details", + "request": { + "method": "GET", + "url": { + "raw": "{{base_url}}/providers/aws/services/s3/resources/buckets" + } + } + }, + { + "name": "S3 Bucket Methods", + "request": { + "method": "GET", + "url": { + "raw": "{{base_url}}/providers/aws/services/s3/resources/buckets/methods" + } + } + } + ], + "variable": [ + { + "key": "base_url", + "value": "http://localhost:8080" + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response is JSON\", function () {", + " pm.response.to.be.json;", + "});" + ] + } + } + ] +} \ No newline at end of file diff --git a/runner.Dockerfile b/runner.Dockerfile new file mode 100644 index 0000000..1a76123 --- /dev/null +++ b/runner.Dockerfile @@ -0,0 +1,15 @@ +FROM stackql/stackql:latest +EXPOSE 5444 +WORKDIR /home/stackql +RUN adduser --system --uid 1001 stackql +RUN addgroup --system --gid 1001 stackql +RUN chown stackql:stackql /home/stackql +RUN chown stackql:stackql /srv +USER stackql +RUN stackql exec 'registry pull aws' +RUN stackql exec 'registry pull azure' +RUN stackql exec 'registry pull google' +RUN stackql exec 'registry pull github' +RUN stackql exec 'registry pull k8s' +RUN stackql exec 'registry pull netlify' +RUN stackql exec 'registry pull okta' \ No newline at end of file diff --git a/src/Dockerfile b/src/Dockerfile index 4053dfd..b06ae31 100644 --- a/src/Dockerfile +++ b/src/Dockerfile @@ -1,13 +1,7 @@ +# src/Dockerfile FROM denoland/deno:latest -EXPOSE 8080 WORKDIR /app -USER deno -# Cache the dependencies as a layer (the following two steps are re-run only when deps.ts is modified). -# Ideally cache deps.ts will download and compile _all_ external files used in main.ts. -# COPY deps.ts . -# RUN deno cache deps.ts -# These steps will be re-run upon each file change in your working directory: -ADD . . -# Compile the main app so that it doesn't need to be compiled each startup/entry. -RUN deno cache app.ts -CMD ["run", "--allow-env", "--allow-net", "--allow-read", "--unsafely-ignore-certificate-errors=localhost", "app.ts"] +COPY . . +RUN deno cache --reload --unstable app.ts +EXPOSE 8080 +CMD ["run", "--allow-net", "--allow-env", "--watch", "app.ts"] \ No newline at end of file diff --git a/src/README.md b/src/README.md index 0c880f6..1d0bb4b 100644 --- a/src/README.md +++ b/src/README.md @@ -1,55 +1,77 @@ -## 1. generate keys - -``` -openssl req -x509 -keyout creds/server_key.pem -out creds/server_cert.pem -config creds/openssl.cnf -days 365 -openssl req -x509 -keyout creds/client_key.pem -out creds/client_cert.pem -config creds/openssl.cnf -days 365 -``` - -## 2. set env vars - -``` -export PGPORT=5444 -export PGSSLCERT=creds/client_cert.pem -export PGSSLKEY=creds/client_key.pem -export PGSSLROOTCERT=creds/server_cert.pem -export PGSSLSRVKEY=creds/server_key.pem -export CLIENT_CERT=$(base64 -w 0 creds/client_cert.pem) -export PGSSLMODE=allow -``` - -For MacOS -``` -export CLIENT_CERT=$(base64 -b 0 creds/client_cert.pem) -``` - -## 3a. start stackql sever with no auth - -``` -stackql srv \ ---pgsrv.address=0.0.0.0 \ ---pgsrv.port=5444 \ ---pgsrv.tls='{ "keyFilePath": "'${PGSSLSRVKEY}'", "certFilePath": "'${PGSSLROOTCERT}'", "clientCAs": [ "'${CLIENT_CERT}'" ] }' -``` - -## 3b. start stackql server with auth - -### Azure example - -``` -export AZ_ACCESS_TOKEN=$(az account get-access-token --query accessToken --output tsv | tr -d '\r') -AUTH='{ "azure": { "type": "api_key", "valuePrefix": "Bearer ", "credentialsenvvar": "AZ_ACCESS_TOKEN" } }' -bin/stackql srv --auth="${AUTH}" \ ---pgsrv.address=0.0.0.0 \ ---pgsrv.port=$PGPORT \ ---pgsrv.tls='{ "keyFilePath": "'${PGSSLSRVKEY}'", "certFilePath": "'${PGSSLROOTCERT}'", "clientCAs": [ "'${CLIENT_CERT}'" ] }' -``` -### GitHub -export AUTH='{ "github": { "type": "basic", "credentialsenvvar": "GITHUB_CREDS" } }' - -## 4. start middleware server -change directory into `./src` - -``` -# deno run --allow-env --allow-net --allow-read --unsafely-ignore-certificate-errors=localhost app.ts -deno run --allow-env --allow-net --allow-read app.ts -``` \ No newline at end of file +# StackQL Middleware + +REST API middleware server that enables SQL-based queries against cloud provider APIs using [StackQL](https://github.com/stackql/stackql). + +## Features + +- SQL query execution against cloud services +- Provider/service/resource discovery +- Query result type generation +- Response metadata +- CORS support + +## Quick Start + +```bash +# Start dependencies +docker compose up -d runner + +# Start server +cd src +deno run --allow-net --allow-env app.ts +``` + +## API Endpoints + +### Query Execution +```http +POST /stackql +Content-Type: application/json + +{ + "query": "SELECT name, id FROM google.compute.instances", + "showMetadata": true +} +``` + +### Provider Discovery +```http +GET /providers +GET /providers/{provider}/services +GET /providers/{provider}/services/{service}/resources +GET /providers/{provider}/services/{service}/resources/{resource} +GET /providers/{provider}/services/{service}/resources/{resource}/methods +``` + +## Development + +```bash +# Install Deno +curl -fsSL https://deno.land/x/install/install.sh | sh + +# Development with hot reload +deno run --allow-net --allow-env --watch app.ts +``` + +## Docker + +```bash +# Build and start all services +docker compose up --build +``` + +## Environment Variables + +- `HOST` - Server host (default: 0.0.0.0) +- `PORT` - Server port (default: 8080) +- `DB_HOST` - StackQL server host (default: localhost) +- `DB_PORT` - StackQL server port (default: 5444) +- `LOGLEVEL` - Logging level (default: INFO) + +## Architecture + +- Oak-based HTTP server (Deno) +- PostgreSQL wire protocol client for StackQL communication +- Modular routing and controller structure +- Centralized error handling +- TypeScript throughout \ No newline at end of file diff --git a/src/README_old.md b/src/README_old.md new file mode 100644 index 0000000..0c880f6 --- /dev/null +++ b/src/README_old.md @@ -0,0 +1,55 @@ +## 1. generate keys + +``` +openssl req -x509 -keyout creds/server_key.pem -out creds/server_cert.pem -config creds/openssl.cnf -days 365 +openssl req -x509 -keyout creds/client_key.pem -out creds/client_cert.pem -config creds/openssl.cnf -days 365 +``` + +## 2. set env vars + +``` +export PGPORT=5444 +export PGSSLCERT=creds/client_cert.pem +export PGSSLKEY=creds/client_key.pem +export PGSSLROOTCERT=creds/server_cert.pem +export PGSSLSRVKEY=creds/server_key.pem +export CLIENT_CERT=$(base64 -w 0 creds/client_cert.pem) +export PGSSLMODE=allow +``` + +For MacOS +``` +export CLIENT_CERT=$(base64 -b 0 creds/client_cert.pem) +``` + +## 3a. start stackql sever with no auth + +``` +stackql srv \ +--pgsrv.address=0.0.0.0 \ +--pgsrv.port=5444 \ +--pgsrv.tls='{ "keyFilePath": "'${PGSSLSRVKEY}'", "certFilePath": "'${PGSSLROOTCERT}'", "clientCAs": [ "'${CLIENT_CERT}'" ] }' +``` + +## 3b. start stackql server with auth + +### Azure example + +``` +export AZ_ACCESS_TOKEN=$(az account get-access-token --query accessToken --output tsv | tr -d '\r') +AUTH='{ "azure": { "type": "api_key", "valuePrefix": "Bearer ", "credentialsenvvar": "AZ_ACCESS_TOKEN" } }' +bin/stackql srv --auth="${AUTH}" \ +--pgsrv.address=0.0.0.0 \ +--pgsrv.port=$PGPORT \ +--pgsrv.tls='{ "keyFilePath": "'${PGSSLSRVKEY}'", "certFilePath": "'${PGSSLROOTCERT}'", "clientCAs": [ "'${CLIENT_CERT}'" ] }' +``` +### GitHub +export AUTH='{ "github": { "type": "basic", "credentialsenvvar": "GITHUB_CREDS" } }' + +## 4. start middleware server +change directory into `./src` + +``` +# deno run --allow-env --allow-net --allow-read --unsafely-ignore-certificate-errors=localhost app.ts +deno run --allow-env --allow-net --allow-read app.ts +``` \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index 16975a7..57da775 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,32 +1,47 @@ -import { Application } from "https://deno.land/x/oak/mod.ts"; -import { oakCors } from "https://deno.land/x/cors/mod.ts"; -import { router } from "./routes/routes.ts"; -import _404 from "./controllers/404.ts"; -import { Context } from "./types/context.ts"; -import { logger, - formatDetailedLogMessage, -} from "./shared/logger.ts"; - -const env = Deno.env.toObject() -const HOST = env.HOST || '0.0.0.0' -const PORT = env.PORT || 8080 - -const app = new Application(); - -const fileName = 'app.ts'; - -app.use(oakCors()); -app.use(router.routes()); -app.use(router.allowedMethods()); -app.use(_404); - -app.addEventListener("listen", ({ hostname, port, serverType }) => { - logger.info(`Server started on ${hostname}:${port} using ${serverType}`); -}); - -app.addEventListener( - "error", - (e: any) => logger.error(formatDetailedLogMessage(`Server error : ${e.message}`, fileName, 'app.addEventListener')), -); - -await app.listen({ hostname: HOST, port: PORT }); \ No newline at end of file +// app.ts +import { Application } from "./deps.ts"; +import { oakCors } from "./deps.ts"; +import { Context } from "./types/context.types.ts"; +import { config } from "./config/environment.ts"; +import { logger } from "./services/logger.service.ts"; +import { db } from "./services/database.service.ts"; +import { errorHandler } from "./middleware/error.middleware.ts"; +import { healthRouter } from "./routes/health.routes.ts"; +import { queryRouter } from "./routes/query.routes.ts"; +import { metaRouter } from "./routes/meta.routes.ts"; + +const app = new Application(); + +// Debug logging middleware +app.use(async (ctx, next) => { + logger.debug(`Request: ${ctx.request.method} ${ctx.request.url}`); + logger.debug('Headers:', ctx.request.headers); + const start = Date.now(); + await next(); + const ms = Date.now() - start; + logger.debug(`Response: ${ctx.response.status} in ${ms}ms`); +}); + +app.use(oakCors()); +app.use(errorHandler); + +app.use(healthRouter.routes()); +app.use(queryRouter.routes()); +app.use(metaRouter.routes()); + +app.use(healthRouter.allowedMethods()); +app.use(queryRouter.allowedMethods()); +app.use(metaRouter.allowedMethods()); + +app.addEventListener("error", (evt) => { + logger.error(`Uncaught error: ${evt.error}`); +}); + +logger.debug('Config:', config); +await db.connect(); +logger.info(`Starting server on ${config.server.host}:${config.server.port}`); + +await app.listen({ + port: config.server.port, + hostname: config.server.host, +}); \ No newline at end of file diff --git a/src/config/environment.ts b/src/config/environment.ts new file mode 100644 index 0000000..760ebfa --- /dev/null +++ b/src/config/environment.ts @@ -0,0 +1,16 @@ +// config/environment.ts +export const config = { + server: { + host: Deno.env.get('HOST') || '0.0.0.0', + port: Number(Deno.env.get('PORT')) || 8080, + }, + database: { + host: Deno.env.get('DB_HOST') || 'localhost', + port: Number(Deno.env.get('DB_PORT')) || 5444, + name: 'stackql', + user: 'stackql', + }, + logging: { + level: Deno.env.get('LOGLEVEL') || 'DEBUG' + } + }; diff --git a/src/controllers/404.ts b/src/controllers/404.ts deleted file mode 100644 index 0356fce..0000000 --- a/src/controllers/404.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default ({ response }) => { - response.status = 404; - response.body = { msg: "Not Found" }; -}; \ No newline at end of file diff --git a/src/controllers/auth.ts b/src/controllers/auth.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/controllers/health.controller.ts b/src/controllers/health.controller.ts new file mode 100644 index 0000000..e1f7b16 --- /dev/null +++ b/src/controllers/health.controller.ts @@ -0,0 +1,6 @@ +// controllers/health.controller.ts +import { Context } from "../types/context.types.ts"; + +export async function healthCheck(ctx: Context) { + ctx.response.body = { status: "healthy" }; +} \ No newline at end of file diff --git a/src/controllers/meta.controller.ts b/src/controllers/meta.controller.ts new file mode 100644 index 0000000..590c680 --- /dev/null +++ b/src/controllers/meta.controller.ts @@ -0,0 +1,75 @@ +// controllers/meta.controller.ts +import { Context } from "../types/context.types.ts"; +import { db } from "../services/database.service.ts"; +import { logger } from "../services/logger.service.ts"; + +export async function getProviders(ctx: Context) { + try { + const rows = await db.query('SHOW PROVIDERS'); + ctx.response.body = { data: rows }; + } catch (error) { + logger.error(`Failed to get providers: ${error.message}`); + ctx.response.status = 400; + ctx.response.body = { error: error.message }; + } +} + +export async function getServices(ctx: Context) { + try { + const { provider } = ctx.params; + const filter = ctx.request.url.searchParams.get('name') ? + ` LIKE '${ctx.request.url.searchParams.get('name')}'` : ''; + + const rows = await db.query(`SHOW EXTENDED SERVICES IN ${provider}${filter}`); + ctx.response.body = { data: rows }; + } catch (error) { + logger.error(`Failed to get services: ${error.message}`); + ctx.response.status = 400; + ctx.response.body = { error: error.message }; + } +} + +export async function getResources(ctx: Context) { + try { + const { provider, service } = ctx.params; + const filter = ctx.request.url.searchParams.get('name') ? + ` LIKE '${ctx.request.url.searchParams.get('name')}'` : ''; + + const rows = await db.query( + `SHOW EXTENDED RESOURCES IN ${provider}.${service}${filter}` + ); + ctx.response.body = { data: rows }; + } catch (error) { + logger.error(`Failed to get resources: ${error.message}`); + ctx.response.status = 400; + ctx.response.body = { error: error.message }; + } +} + +export async function getResourceDetails(ctx: Context) { + try { + const { provider, service, resource } = ctx.params; + const rows = await db.query( + `DESCRIBE EXTENDED ${provider}.${service}.${resource}` + ); + ctx.response.body = { data: rows }; + } catch (error) { + logger.error(`Failed to get resource details: ${error.message}`); + ctx.response.status = 400; + ctx.response.body = { error: error.message }; + } +} + +export async function getResourceMethods(ctx: Context) { + try { + const { provider, service, resource } = ctx.params; + const rows = await db.query( + `SHOW EXTENDED METHODS IN ${provider}.${service}.${resource}` + ); + ctx.response.body = { data: rows }; + } catch (error) { + logger.error(`Failed to get resource methods: ${error.message}`); + ctx.response.status = 400; + ctx.response.body = { error: error.message }; + } +} \ No newline at end of file diff --git a/src/controllers/meta.ts b/src/controllers/meta.ts deleted file mode 100644 index ae6a675..0000000 --- a/src/controllers/meta.ts +++ /dev/null @@ -1,160 +0,0 @@ -// import * as logger from "./../shared/logger.ts"; -import { Context } from "./../types/context.ts"; -import { - getPathParams, - getQueryParams, - getQueryFilter -} from "./../shared/params.ts"; -import { getData } from "../shared/data.ts"; -import { - logger, - formatDetailedLogMessage, -} from "./../shared/logger.ts"; - -const fileName = 'controllers/meta.ts'; - -/** - * return all providers installed - */ -const showProviders = async (ctx: Context) => { - - const functionName = 'showProviders'; - - // parse query params - const queryParams = await getQueryParams(ctx, fileName, functionName); - - // set query - const iqlQuery = `SHOW PROVIDERS`; - logger.debug(formatDetailedLogMessage(`iqlQuery: ${iqlQuery}`, fileName, functionName)); - - // return results - const respData = await getData(iqlQuery, queryParams.showMetadata); - logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); - ctx.response.status = respData.respStatus; - ctx.response.type = respData.respType; - ctx.response.body = respData.respBody; -}; - -/** - * return all services available in a provider - */ -const showServices = async (ctx: Context) => { - - const functionName = 'showServices'; - - // get path params - const pathParams = await getPathParams(ctx, fileName, functionName); - const providerName = pathParams.providerName; - - // parse query params - const queryParams = await getQueryParams(ctx, fileName, functionName); - - // filter param? - const filterParam = await getQueryFilter(ctx); - logger.debug(formatDetailedLogMessage(`filterParam: ${filterParam}`, fileName, functionName)); - - // run query - const iqlQuery = `SHOW EXTENDED SERVICES IN ${providerName}${filterParam}`; - logger.debug(formatDetailedLogMessage(`iqlQuery: ${iqlQuery}`, fileName, functionName)); - - // return results - const respData = await getData(iqlQuery, queryParams.showMetadata); - logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); - ctx.response.status = respData.respStatus; - ctx.response.type = respData.respType; - ctx.response.body = respData.respBody; -}; - -/** - * return all resources available in a service - */ - const showResources = async (ctx: Context) => { - - const functionName = 'showResources'; - - // get path params - const pathParams = await getPathParams(ctx, fileName, functionName); - const providerName = pathParams.providerName; - const serviceName = pathParams.serviceName; - - // parse query params - const queryParams = await getQueryParams(ctx, fileName, functionName); - - // filter param? - const filterParam = await getQueryFilter(ctx); - - // run query - const iqlQuery = `SHOW EXTENDED RESOURCES IN ${providerName}.${serviceName}${filterParam}`; - logger.debug(formatDetailedLogMessage(`iqlQuery: ${iqlQuery}`, fileName, functionName)); - - // return results - const respData = await getData(iqlQuery, queryParams.showMetadata); - logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); - ctx.response.status = respData.respStatus; - ctx.response.type = respData.respType; - ctx.response.body = respData.respBody; -}; - -/** - * return all fields available in a resource - */ - const describeResource = async (ctx: Context) => { - - const functionName = 'describeResource'; - - // get path params - const pathParams = await getPathParams(ctx, fileName, functionName); - const providerName = pathParams.providerName; - const serviceName = pathParams.serviceName; - const resourceName = pathParams.resourceName; - - // parse query params - const queryParams = await getQueryParams(ctx, fileName, functionName); - - // run query - const iqlQuery = `DESCRIBE EXTENDED ${providerName}.${serviceName}.${resourceName}`; - logger.debug(formatDetailedLogMessage(`iqlQuery: ${iqlQuery}`, fileName, functionName)); - - // return results - const respData = await getData(iqlQuery, queryParams.showMetadata); - logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); - ctx.response.status = respData.respStatus; - ctx.response.type = respData.respType; - ctx.response.body = respData.respBody; -}; - -/** - * return all methods available on a resource - */ - const showMethods = async (ctx: Context) => { - - const functionName = 'showMethods'; - - // get path params - const pathParams = await getPathParams(ctx, fileName, functionName); - const providerName = pathParams.providerName; - const serviceName = pathParams.serviceName; - const resourceName = pathParams.resourceName; - - // parse query params - const queryParams = await getQueryParams(ctx, fileName, functionName); - - // run query - const iqlQuery = `SHOW EXTENDED METHODS IN ${providerName}.${serviceName}.${resourceName}`; - logger.debug(formatDetailedLogMessage(`iqlQuery: ${iqlQuery}`, fileName, functionName)); - - // return results - const respData = await getData(iqlQuery, queryParams.showMetadata); - logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); - ctx.response.status = respData.respStatus; - ctx.response.type = respData.respType; - ctx.response.body = respData.respBody; -}; - -export { - showProviders, - showServices, - showResources, - describeResource, - showMethods, -} \ No newline at end of file diff --git a/src/controllers/misc.ts b/src/controllers/misc.ts deleted file mode 100644 index 3399a1a..0000000 --- a/src/controllers/misc.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * return if server is running - */ - export const ping = async () => { - return "pong"; - }; \ No newline at end of file diff --git a/src/controllers/query.controller.ts b/src/controllers/query.controller.ts new file mode 100644 index 0000000..230e7a1 --- /dev/null +++ b/src/controllers/query.controller.ts @@ -0,0 +1,64 @@ +// controllers/query.controller.ts +import { Context } from "../types/context.types.ts"; +import { QueryRequest, QueryResponse, ErrorResponse } from "../types/api.types.ts"; +import { db } from "../services/database.service.ts"; +import { logger } from "../services/logger.service.ts"; +import { validateQuery } from "../utils/query.utils.ts"; + +export async function executeQuery(ctx: Context) { + if (!ctx.request.hasBody) { + ctx.response.status = 400; + ctx.response.body = { error: "Request body required" }; + return; + } + + try { + // const body = await ctx.request.body.value; + const body = await ctx.request.body.json(); + logger.info(`Request body: ${JSON.stringify(body)}`); + + const reqData: QueryRequest = typeof body === "string" ? JSON.parse(body) : body; + logger.info(`Request data: ${JSON.stringify(reqData)}`); + + const validationError = validateQuery(reqData.query); + if (validationError) { + ctx.response.status = 405; + ctx.response.body = { error: validationError }; + return; + } + + const startTime = new Date().toISOString(); + const t0 = performance.now(); + + const rows = await db.query(reqData.query); + + const response: QueryResponse = { + data: rows, + ...(reqData.showMetadata && { + metadata: { + operation: { + startTime, + endTime: new Date().toISOString(), + duration: `${performance.now() - t0} ms`, + status: 'OK' + }, + result: { + rowCount: rows.length + }, + request: { + query: reqData.query + } + } + }) + }; + + ctx.response.body = response; + } catch (error) { + logger.error(`Query execution failed: ${error.message}`); + ctx.response.status = 400; + const errorResponse: ErrorResponse = { + error: error.message.replace(/\n/g, "") + }; + ctx.response.body = errorResponse; + } +} \ No newline at end of file diff --git a/src/controllers/query.ts b/src/controllers/query.ts deleted file mode 100644 index 04caee3..0000000 --- a/src/controllers/query.ts +++ /dev/null @@ -1,118 +0,0 @@ -// import * as logger from "./../shared/logger.ts"; -import { Context } from "./../types/context.ts"; -import { getQueryParams } from "./../shared/params.ts"; -import { - getData, - getTypes, - } from "../shared/data.ts"; - import { - logger, - formatDetailedLogMessage, -} from "./../shared/logger.ts"; - -const fileName = 'controllers/query.ts'; - -export interface RespData { - respStatus: number; - respType: string; - respBody: string; -} - -async function parseReqBody(body: any): Promise<{ queryOrError: string; showMetadata: boolean; respStatus: number; }> { - let inputData : any; - let respStatus = 200; - let queryOrError = ""; - let showMetadata = false; - - // try to parse the request body - try { - const bodyData = await body.value; - if (typeof bodyData === "object") { - inputData = bodyData; - } else { - inputData = JSON.parse(await bodyData); - } - } catch(err) { - respStatus = 400; - queryOrError = "Bad Request"; - return { queryOrError: queryOrError, respStatus: respStatus, showMetadata: showMetadata }; - } - // post body is not json - if(typeof inputData != "object") { - respStatus = 400; - queryOrError = "Bad Request - invalid request body"; - } - - // does a query field exist? - else if (inputData.query === undefined) { - respStatus = 400; - queryOrError = "Malformed Request - no query field"; - } - // is the query valid? - else if(!inputData.query.toLowerCase().startsWith("select") && !inputData.query.toLowerCase().startsWith("show") && !inputData.query.toLowerCase().startsWith("describe")){ - respStatus = 405; - queryOrError = "Method Not Allowed - methods other than SELECT, SHOW and DESCRIBE are not supported in middleware server mode"; - } - - // looks good, return the query - queryOrError = inputData.query; - showMetadata = inputData.showMetadata; - return { queryOrError: queryOrError, respStatus: respStatus, showMetadata: showMetadata }; -} - -/** - * return results from query - */ -export const runQuery = async (ctx: Context) => { - - const functionName = 'runQuery'; - - // exit if body is empty - if (!ctx.request.hasBody) { - ctx.response.status = 400; - ctx.response.body = { error: "Bad Request - no body" }; - return; - } - - // parse query params - const queryParams = await getQueryParams(ctx, fileName, functionName); - - // parse body - const bodyObj = await parseReqBody(await ctx.request.body()); - logger.debug(formatDetailedLogMessage(`bodyObj: ${JSON.stringify(bodyObj)}`, fileName, functionName)); - - if(bodyObj.respStatus != 200){ - // something went wrong, get out - ctx.response.status = bodyObj.respStatus; - ctx.response.body = { error: bodyObj.queryOrError }; - return; - } - - // show metadata? (ignored if dts is specified) - let showMetadata = false; - - if (queryParams.showMetadata || bodyObj.showMetadata) { - showMetadata = true; - } - - const iqlQuery = bodyObj.queryOrError; - - let respData: RespData = { - respStatus: 500, - respType: 'application/text', - respBody: 'Something went wrong', - }; - - if(queryParams.dts){ - // get types - respData = await getTypes(iqlQuery); - } else { - // get data - respData = await getData(iqlQuery, showMetadata); - } - logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); - ctx.response.status = respData.respStatus; - ctx.response.type = respData.respType; - ctx.response.body = respData.respBody; - -}; diff --git a/src/deps.ts b/src/deps.ts new file mode 100644 index 0000000..de7a06d --- /dev/null +++ b/src/deps.ts @@ -0,0 +1,6 @@ +// src/deps.ts +export { Application } from "jsr:@oak/oak"; +export { Router } from "jsr:@oak/oak/router"; +export { oakCors } from "https://deno.land/x/cors@v1.2.2/mod.ts"; +export { Client } from "https://deno.land/x/postgres@v0.17.0/mod.ts"; +export * as log from "https://deno.land/std@0.208.0/log/mod.ts"; \ No newline at end of file diff --git a/src/middleware/error.middleware.ts b/src/middleware/error.middleware.ts new file mode 100644 index 0000000..c3f6d76 --- /dev/null +++ b/src/middleware/error.middleware.ts @@ -0,0 +1,18 @@ +// middleware/error.middleware.ts +import { Context } from "../types/context.types.ts"; +import { logger } from "../services/logger.service.ts"; + +export async function errorHandler( + ctx: Context, + next: () => Promise +) { + try { + await next(); + } catch (err) { + logger.error(`Unhandled error: ${err.message}`); + ctx.response.status = err.status || 500; + ctx.response.body = { + error: err.message || 'Internal server error' + }; + } +} diff --git a/src/routes/auth.routes.ts b/src/routes/auth.routes.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/routes/health.routes.ts b/src/routes/health.routes.ts new file mode 100644 index 0000000..a550689 --- /dev/null +++ b/src/routes/health.routes.ts @@ -0,0 +1,6 @@ +// routes/health.routes.ts +import { Router } from "../deps.ts"; +import * as healthController from "../controllers/health.controller.ts"; + +export const healthRouter = new Router() + .get("/health", healthController.healthCheck); \ No newline at end of file diff --git a/src/routes/meta.routes.ts b/src/routes/meta.routes.ts index 2eb3223..9562b80 100644 --- a/src/routes/meta.routes.ts +++ b/src/routes/meta.routes.ts @@ -1,76 +1,10 @@ -import { Context } from "./../types/context.ts"; -import * as metaController from "./../controllers/meta.ts"; -import { - logger, - formatDetailedLogMessage, -} from "./../shared/logger.ts"; - -const fileName = 'routes/meta.routes.ts'; - -/** - * show all providers installed - * call by USER - */ -const getProviders = [ - // userGuard(UserRole.ADMIN), - async (ctx: Context) => { - logger.debug(formatDetailedLogMessage(`getProviders route invoked`, fileName, 'getProviders')); - await metaController.showProviders(ctx); - }, -]; - -/** - * show all services in a specified provider - * call by USER - */ - const getServices = [ - // userGuard(UserRole.ADMIN), - async (ctx: Context) => { - logger.debug(formatDetailedLogMessage(`getServices route invoked, context: ${JSON.stringify(ctx)}`, fileName, 'getServices')); - await metaController.showServices(ctx); - }, -]; - -/** - * show all resources in a specified service - * call by USER - */ - const getResources = [ - // userGuard(UserRole.ADMIN), - async (ctx: Context) => { - logger.debug(formatDetailedLogMessage(`getResources route invoked, context: ${JSON.stringify(ctx)}`, fileName, 'getResources')); - await metaController.showResources(ctx); - }, -]; - -/** - * show all fields in a specified resource - * call by USER - */ - const getResourceFields = [ - // userGuard(UserRole.ADMIN), - async (ctx: Context) => { - logger.debug(formatDetailedLogMessage(`getResourceFields route invoked, context: ${JSON.stringify(ctx)}`, fileName, 'getResourceFields')); - await metaController.describeResource(ctx); - }, -]; - -/** - * show all methods for a specified resource - * call by USER - */ - const getResourceMethods = [ - // userGuard(UserRole.ADMIN), - async (ctx: Context) => { - logger.debug(formatDetailedLogMessage(`getResourceMethods route invoked, context: ${JSON.stringify(ctx)}`, fileName, 'getResourceMethods')); - await metaController.showMethods(ctx); - }, -]; - -export { - getProviders, - getServices, - getResources, - getResourceFields, - getResourceMethods, - }; \ No newline at end of file +// routes/meta.routes.ts +import { Router } from "../deps.ts"; +import * as metaController from "../controllers/meta.controller.ts"; + +export const metaRouter = new Router() + .get("/providers", metaController.getProviders) + .get("/providers/:provider/services", metaController.getServices) + .get("/providers/:provider/services/:service/resources", metaController.getResources) + .get("/providers/:provider/services/:service/resources/:resource", metaController.getResourceDetails) + .get("/providers/:provider/services/:service/resources/:resource/methods", metaController.getResourceMethods); diff --git a/src/routes/misc.routes.ts b/src/routes/misc.routes.ts deleted file mode 100644 index a53062d..0000000 --- a/src/routes/misc.routes.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Context } from "./../types/context.ts"; -import * as miscController from "./../controllers/misc.ts"; - -/** - * check if server is up - * call by USER - */ -const ping = [ - // userGuard(UserRole.ADMIN), - async (ctx: Context) => { - const pingResp = await miscController.ping(); - ctx.response.body = pingResp; - }, -]; - -export { ping }; \ No newline at end of file diff --git a/src/routes/query.routes.ts b/src/routes/query.routes.ts index 92ded80..08220ef 100644 --- a/src/routes/query.routes.ts +++ b/src/routes/query.routes.ts @@ -1,22 +1,6 @@ -import { Context } from "./../types/context.ts"; -import * as queryController from "./../controllers/query.ts"; -import { - logger, - formatDetailedLogMessage, -} from "./../shared/logger.ts"; - -const fileName = 'routes/query.routes.ts'; - -/** - * run a stackql SELECT query - * call by USER - */ -const runQuery = [ - // userGuard(UserRole.ADMIN), - async (ctx: Context) => { - logger.debug(formatDetailedLogMessage(`runQuery route invoked, context: ${JSON.stringify(ctx)}`, fileName, 'runQuery')); - await queryController.runQuery(ctx); - }, -]; - -export { runQuery }; \ No newline at end of file +// routes/query.routes.ts +import { Router } from "../deps.ts"; +import * as queryController from "../controllers/query.controller.ts"; + +export const queryRouter = new Router() + .post("/stackql", queryController.executeQuery); \ No newline at end of file diff --git a/src/routes/routes.ts b/src/routes/routes.ts deleted file mode 100644 index 450c2e6..0000000 --- a/src/routes/routes.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Router } from "https://deno.land/x/oak/mod.ts"; - -import * as miscRoutes from "./misc.routes.ts"; -import * as queryRoutes from "./query.routes.ts"; -import * as metaRoutes from "./meta.routes.ts"; - -const router: Router = new Router(); - -router - .get("/ping", ...miscRoutes.ping); - -router - .post("/stackql", ...queryRoutes.runQuery); - -router - .get("/providers", ...metaRoutes.getProviders) - .get("/providers/:providerName/services", ...metaRoutes.getServices) - .get("/providers/:providerName/services/:serviceName/resources", ...metaRoutes.getResources) - .get("/providers/:providerName/services/:serviceName/resources/:resourceName", ...metaRoutes.getResourceFields) - .get("/providers/:providerName/services/:serviceName/resources/:resourceName/methods", ...metaRoutes.getResourceMethods); - -export { router }; \ No newline at end of file diff --git a/src/services/database.service.ts b/src/services/database.service.ts new file mode 100644 index 0000000..37c2091 --- /dev/null +++ b/src/services/database.service.ts @@ -0,0 +1,35 @@ +// services/database.service.ts +import { Client } from "https://deno.land/x/postgres@v0.17.0/mod.ts"; +import { config } from "../config/environment.ts"; +import { logger } from "./logger.service.ts"; + +class DatabaseService { + private client: Client; + + constructor() { + this.client = new Client({ + applicationName: 'stackql', + hostname: config.database.host, + port: config.database.port, + database: config.database.name, + user: config.database.user, + }); + } + + async connect(): Promise { + try { + await this.client.connect(); + logger.info(`Connected to stackql server at ${config.database.host}:${config.database.port}`); + } catch (error) { + logger.error(`Failed to connect to stackql server: ${error.message}`); + throw error; + } + } + + async query(sql: string): Promise { + const result = await this.client.queryObject(sql); + return result.rows; + } +} + +export const db = new DatabaseService(); \ No newline at end of file diff --git a/src/services/logger.service.ts b/src/services/logger.service.ts new file mode 100644 index 0000000..85443fb --- /dev/null +++ b/src/services/logger.service.ts @@ -0,0 +1,17 @@ +// services/logger.service.ts +import * as log from "https://deno.land/std@0.208.0/log/mod.ts"; +import { config } from "../config/environment.ts"; + +await log.setup({ + handlers: { + console: new log.handlers.ConsoleHandler(config.logging.level), + }, + loggers: { + default: { + level: config.logging.level, + handlers: ["console"], + }, + } +}); + +export const logger = log.getLogger(); \ No newline at end of file diff --git a/src/shared/data.ts b/src/shared/data.ts deleted file mode 100644 index 9e56fe6..0000000 --- a/src/shared/data.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { generateTypes } from "https://deno.land/x/dts/mod.ts"; -import { Client } from "https://deno.land/x/postgres@v0.16.1/mod.ts"; -import { - logger, - formatDetailedLogMessage, -} from "./logger.ts"; - -const fileName = 'shared/data.ts'; - -/* -* get stackql srv env vars and initiate connection -*/ - -const env = Deno.env.toObject() -const DB_HOST = env.DB_HOST || 'localhost' -const DB_PORT = parseInt(env.DB_PORT) || 5444 - -const client = new Client({ - applicationName: 'stackql', - hostname: DB_HOST, - port: DB_PORT, - database: 'stackql', - user: 'stackql', -}); - -try { - console.log(`connecting to stackql server : ${DB_HOST}:${DB_PORT}`); - await client.connect(); -} catch (error) { - console.log(`Error connecting to stackql server ${DB_HOST}:${DB_PORT} : ${error.message}`); - throw error; -} - -function reType(input: any): any { - try { - // its an object - return JSON.parse(input); - } catch (error) { - // its a primitive - return input; - } -} - -async function getData(iqlQuery: string, showMetadata: boolean): Promise< { respStatus: number; respType: string; respBody: string; } > { - - const functionName = 'getData'; - - // run query - try { - - // init metadata - - // get operation start time - const t0 = performance.now(); - - let metadata = { - operation: {}, - result: {}, - request: {}, - }; - - if (showMetadata){ - metadata.operation['startTime'] = new Date().toISOString();; - metadata.request['query'] = iqlQuery; - } - - // connect, run query and get results - const data = await client.queryObject(iqlQuery); - - if (showMetadata){ - metadata.result['rowCount'] = data.rows.length; - metadata.operation['status'] = 'OK'; - metadata.operation['endTime'] = new Date().toISOString(); - metadata.operation['duration'] = `${performance.now() - t0} ms`; - } - - let respData = { - data: data.rows, - metadata : showMetadata ? metadata : null - } - - logger.debug(formatDetailedLogMessage(`respData: ${JSON.stringify(respData)}`, fileName, functionName)); - - return { respStatus: 200, respType: 'application/json', respBody: `${JSON.stringify(respData)}\n` }; - - } catch (error) { - logger.debug(formatDetailedLogMessage(`error: ${JSON.stringify(error)}`, fileName, functionName)); - const errResp = { - error: error.message.replace(/\n/g, ""), - }; - return { respStatus: 400, respType: 'application/json', respBody: `${JSON.stringify(errResp)}\n` }; - } -} - -async function getTypes(iqlQuery: string): Promise< { respStatus: number; respType: string; respBody: string; } > { - - // run query and get types - try { - - // connect, run query and get results - const data = await client.queryObject(iqlQuery); - const firstRow = data.rows[0]; - - // parse each field - const castedFields = {}; - Object.keys(firstRow).forEach(k => { - castedFields[k] = reType(firstRow[k]); - }); - - // get types - const result = await generateTypes(castedFields); - - return { respStatus: 200, respType: 'application/text', respBody: result }; - - } catch (error) { - const errResp = { - error: error.message.replace(/\n/g, ""), - }; - return { respStatus: 400, respType: 'application/json', respBody: `${JSON.stringify(errResp)}\n` }; - } -} - -export { - getData, - getTypes, -} \ No newline at end of file diff --git a/src/shared/logger.ts b/src/shared/logger.ts deleted file mode 100644 index eadd7ec..0000000 --- a/src/shared/logger.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as log from "https://deno.land/std@0.160.0/log/mod.ts"; - -const env = Deno.env.toObject() -const LOGLEVEL = env.LOGLEVEL || 'INFO' - -console.log(`LOGLEVEL: ${LOGLEVEL}`); - -await log.setup({ - handlers: { - console: new log.handlers.ConsoleHandler(LOGLEVEL), - }, - loggers: { - default: { - level: LOGLEVEL, - handlers: ["console"], - }, - } -}); - -const logger = log.getLogger(); - -const formatDetailedLogMessage = (msg: string, fileName: string, functionName: string): string => { - return `${msg} (${fileName}, ${functionName})`; -} - -export { - logger, - formatDetailedLogMessage, -} \ No newline at end of file diff --git a/src/shared/params.ts b/src/shared/params.ts deleted file mode 100644 index c1e5a56..0000000 --- a/src/shared/params.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Context } from "./../types/context.ts"; -import { - logger, - formatDetailedLogMessage, -} from "./logger.ts"; - -/** - * return values for specified path params - */ - async function getPathParams(ctx: Context, fileName: string, functionName: string): Promise< Record >{ - logger.debug(formatDetailedLogMessage(`pathParams: ${JSON.stringify(ctx.params)}`, fileName, functionName)); - return ctx.params; -} - -/** - * return state for known query params - */ -async function getQueryParams(ctx: Context, fileName: string, functionName: string): Promise<{ showMetadata: boolean; dts: boolean; }>{ - let showMetadata = false; - let dts = false; - ctx.request.url.searchParams.get('showMetadata') === '' ? showMetadata = true : showMetadata = false; - ctx.request.url.searchParams.get('dts') === '' ? dts = true : dts = false; - logger.debug(formatDetailedLogMessage(`searchParams: ${JSON.stringify(Array.from(ctx.request.url.searchParams.values()))}`, fileName, functionName)); - return { showMetadata: showMetadata, dts: dts }; -} - -async function getQueryFilter(ctx: Context): Promise{ - // exact match - if (ctx.request.url.searchParams.get('name')){ - return ` LIKE '${ctx.request.url.searchParams.get('name')}'`; - } - // fuzzy match - if (ctx.request.url.searchParams.get('like')) { - return ` LIKE '%${ctx.request.url.searchParams.get('like')}%'` - } - // no filters - return ''; -} - -export { - getPathParams, - getQueryParams, - getQueryFilter, -} \ No newline at end of file diff --git a/src/tests/api.test.ts b/src/tests/api.test.ts new file mode 100644 index 0000000..97ef3be --- /dev/null +++ b/src/tests/api.test.ts @@ -0,0 +1,77 @@ +// tests/api.test.ts +import { assertEquals, assertExists } from "https://deno.land/std@0.208.0/assert/mod.ts"; + +const controllers: AbortController[] = []; + +async function makeRequest(url: string, options?: RequestInit) { + const controller = new AbortController(); + controllers.push(controller); + + try { + const response = await fetch(url, { + ...options, + signal: controller.signal + }); + const text = await response.text(); + try { + return { response, data: JSON.parse(text) }; + } catch { + return { response, data: text }; + } + } catch (e) { + if (controller.signal.aborted) throw e; + throw e; + } +} + +Deno.test("API Integration Tests", async (t) => { + try { + await t.step("Health check returns 200", async () => { + const { response, data } = await makeRequest("http://localhost:8080/health"); + assertEquals(response.status, 200); + assertExists(data.status); + }); + + await t.step("Query execution - valid SELECT", async () => { + const { response, data } = await makeRequest("http://localhost:8080/stackql", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + query: "SELECT * FROM github.repos.contributors WHERE repo = 'stackql' and owner = 'stackql'", + showMetadata: true + }) + }); + assertEquals(response.status, 200); + assertExists(data.data); + assertExists(data.metadata); + }); + + await t.step("Query execution - invalid query type", async () => { + const { response, data } = await makeRequest("http://localhost:8080/stackql", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + query: "INSERT INTO aws.s3.buckets VALUES ('test')" + }) + }); + assertEquals(response.status, 405); + assertExists(data.error); + }); + + await t.step("Provider discovery", async () => { + const { response, data } = await makeRequest("http://localhost:8080/providers"); + assertEquals(response.status, 200); + assertExists(data.data); + }); + + await t.step("Service discovery", async () => { + const { response, data } = await makeRequest("http://localhost:8080/providers/github/services"); + assertEquals(response.status, 200); + assertExists(data.data); + }); + } finally { + // Clean up all fetch requests + controllers.forEach(controller => controller.abort()); + await t.step("cleanup", () => {}); + } +}); \ No newline at end of file diff --git a/src/types/api.types.ts b/src/types/api.types.ts new file mode 100644 index 0000000..a6bd290 --- /dev/null +++ b/src/types/api.types.ts @@ -0,0 +1,29 @@ +// types/api.types.ts +export interface QueryRequest { + query: string; + showMetadata?: boolean; + } + +export interface QueryResponse { + data: unknown[]; + metadata?: { + operation: { + startTime?: string; + endTime?: string; + duration?: string; + status?: string; + }; + result: { + rowCount?: number; + }; + request: { + query?: string; + }; + }; +} + +export interface ErrorResponse { + error: string; +} + + \ No newline at end of file diff --git a/src/types/auth.ts b/src/types/auth.ts deleted file mode 100644 index 7025c7a..0000000 --- a/src/types/auth.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Authenticated user info - * user as JWT access token payload - */ - export type AuthUser = { - /** user id */ - id: number; - /** user email address */ - email: string; - /** user name */ - name: string; - /** user roles */ - roles: string; - }; - \ No newline at end of file diff --git a/src/types/context.ts b/src/types/context.ts deleted file mode 100644 index ec55d0d..0000000 --- a/src/types/context.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Context as OakContext } from "https://deno.land/x/oak/mod.ts"; -import { AuthUser } from "./../types/auth.ts"; - -/** - * Custom appilication context - */ -export class Context extends OakContext { - user?: AuthUser; -} diff --git a/src/types/context.types.ts b/src/types/context.types.ts new file mode 100644 index 0000000..c713951 --- /dev/null +++ b/src/types/context.types.ts @@ -0,0 +1,9 @@ +// types/context.types.ts +import { Context as OakContext } from "jsr:@oak/oak/context"; + +export interface Context extends OakContext { + user?: { + id: string; + [key: string]: unknown; + }; +} \ No newline at end of file diff --git a/src/utils/query.utils.ts b/src/utils/query.utils.ts new file mode 100644 index 0000000..98ece20 --- /dev/null +++ b/src/utils/query.utils.ts @@ -0,0 +1,15 @@ +// utils/query.utils.ts +const ALLOWED_QUERY_TYPES = ['select', 'show', 'describe']; + +export function validateQuery(query: string): string | null { + if (!query) { + return 'Query is required'; + } + + const queryType = query.trim().toLowerCase().split(' ')[0]; + if (!ALLOWED_QUERY_TYPES.includes(queryType)) { + return `Query type '${queryType}' not allowed. Only SELECT, SHOW, and DESCRIBE are supported`; + } + + return null; +} From a62bfc053daa82f0d3c255fd4b38429145180f25 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Thu, 6 Feb 2025 10:33:22 +1100 Subject: [PATCH 23/31] updates --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 2f9029d..d30a69a 100644 --- a/README.md +++ b/README.md @@ -46,18 +46,14 @@ Results can be operated on using SQL functions and operators (including grouping ```mermaid C4Context Person(user, "User or UserAgent") - Boundary(b0, "stackql Middleware") { Container(api, "stackql API", "Deno Oak", "accepts http requests with stackql queries") Container(runner, "stackql runner", "stackql srv", "runs stackql queries against providers") } - System_Ext(cloudprovider, "Cloud or Data Provider", "cloud or data resources") - Rel(user, api, "submits stackql queries", "POST /stackql") BiRel(api, runner, "via pgwire") BiRel(runner, cloudprovider, "makes api calls", "HTTP/HTTPS") - UpdateRelStyle(api, runner, $offsetX="-20", $offsetY="-15") UpdateRelStyle(runner, cloudprovider, $offsetX="10", $offsetY="-40") UpdateRelStyle(user, api, $offsetX="0", $offsetY="-40") From cf72c3bfba15d5ff2f96880829b3aabb5be4de08 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Thu, 6 Feb 2025 11:17:41 +1100 Subject: [PATCH 24/31] updates --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index d30a69a..8d87516 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,6 @@ The StackQL middleware server enables clients to query api backends using a natu Results can be operated on using SQL functions and operators (including grouping, windowing, and aggregation functions) and then returned to the client as a JSON response. The following architecture diagram illustrates the StackQL middleware server's components. -### Context Diagram - ```mermaid C4Context Person(user, "User or UserAgent") From 34f8481f24d2cb95fceee799b041601ad845c6ee Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Thu, 6 Feb 2025 11:52:49 +1100 Subject: [PATCH 25/31] updates --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d87516..c00c76e 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ The StackQL middleware server is built on top of the [StackQL core](https://gith The StackQL middleware server enables clients to query api backends using a natural SQL language for providers installed with authentication configured in the StackQL server. The StackQL server includes a front-end parser and query planner, which translates the SQL query into one or more REST and/or GraphQL requests and then executes the queries against the backends. -Results can be operated on using SQL functions and operators (including grouping, windowing, and aggregation functions) and then returned to the client as a JSON response. The following architecture diagram illustrates the StackQL middleware server's components. +Results can be operated on using SQL functions and operators (including grouping, windowing, and aggregation functions) and then returned to the client as a JSON response. The following architecture diagram illustrates the StackQL middleware server's components. ```mermaid C4Context From 450a4b123c5b3bcda13f5bd307868c57e335d4be Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Thu, 6 Feb 2025 12:12:17 +1100 Subject: [PATCH 26/31] updates --- README.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index c00c76e..c530096 100644 --- a/README.md +++ b/README.md @@ -42,19 +42,17 @@ The StackQL middleware server enables clients to query api backends using a natu Results can be operated on using SQL functions and operators (including grouping, windowing, and aggregation functions) and then returned to the client as a JSON response. The following architecture diagram illustrates the StackQL middleware server's components. ```mermaid -C4Context - Person(user, "User or UserAgent") - Boundary(b0, "stackql Middleware") { - Container(api, "stackql API", "Deno Oak", "accepts http requests with stackql queries") - Container(runner, "stackql runner", "stackql srv", "runs stackql queries against providers") - } - System_Ext(cloudprovider, "Cloud or Data Provider", "cloud or data resources") - Rel(user, api, "submits stackql queries", "POST /stackql") - BiRel(api, runner, "via pgwire") - BiRel(runner, cloudprovider, "makes api calls", "HTTP/HTTPS") - UpdateRelStyle(api, runner, $offsetX="-20", $offsetY="-15") - UpdateRelStyle(runner, cloudprovider, $offsetX="10", $offsetY="-40") - UpdateRelStyle(user, api, $offsetX="0", $offsetY="-40") +graph LR; + user["User or UserAgent"] -->|submits queries| api["stackql API (Deno Oak)"]; + api --> |gets results| user + + subgraph middleware["stackql Middleware"] + direction TB + api <-.-> |via pgwire| runner["stackql runner (stackql srv)"]; + end + + runner -->|API calls| cloudprovider["Cloud Provider"]; + cloudprovider --> |data| runner ``` Detailed design documentation can be found [here](docs/detailed-design.md). From b9b47f856c713f70642d91afaf3a6da4802922c5 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Thu, 6 Feb 2025 12:13:37 +1100 Subject: [PATCH 27/31] updates --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c530096..c9bba88 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ The StackQL middleware server enables clients to query api backends using a natu Results can be operated on using SQL functions and operators (including grouping, windowing, and aggregation functions) and then returned to the client as a JSON response. The following architecture diagram illustrates the StackQL middleware server's components. ```mermaid -graph LR; +flowchart TB; user["User or UserAgent"] -->|submits queries| api["stackql API (Deno Oak)"]; api --> |gets results| user From 494d0034d39feae60177ceb743c4e02b172d46c5 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Thu, 6 Feb 2025 12:14:35 +1100 Subject: [PATCH 28/31] updates --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c9bba88..013c557 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ The StackQL middleware server enables clients to query api backends using a natu Results can be operated on using SQL functions and operators (including grouping, windowing, and aggregation functions) and then returned to the client as a JSON response. The following architecture diagram illustrates the StackQL middleware server's components. +### Context Diagram + ```mermaid flowchart TB; user["User or UserAgent"] -->|submits queries| api["stackql API (Deno Oak)"]; From e90abe7536d2a039ddf54bf428f6ac8176597c61 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Thu, 6 Feb 2025 16:43:58 +1100 Subject: [PATCH 29/31] refactor --- .gitignore | 3 +- README.md | 31 ++++++++++----- demo.ps1 | 26 ------------ demo.sh | 40 +++++++++---------- docker-compose.yml | 18 +++++++-- docs/detailed-design.md | 11 ------ docs/quickstart.md | 46 ++++++--------------- puml/stackql-docker-compose.puml | 31 --------------- puml/stackql-middleware-container.puml | 45 --------------------- puml/stackql-middleware-context.puml | 40 ------------------- runner.Dockerfile | 7 +++- src/README_old.md | 55 -------------------------- src/config/environment.ts | 2 +- src/controllers/query.controller.ts | 49 ++++++++++++++++++----- src/types/api.types.ts | 36 ++++++++++------- src/utils/query.utils.ts | 29 ++++++++++---- 16 files changed, 159 insertions(+), 310 deletions(-) delete mode 100644 demo.ps1 delete mode 100644 docs/detailed-design.md delete mode 100644 puml/stackql-docker-compose.puml delete mode 100644 puml/stackql-middleware-container.puml delete mode 100644 puml/stackql-middleware-context.puml delete mode 100644 src/README_old.md diff --git a/.gitignore b/.gitignore index 8753049..931f20a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ src/.stackql src/bin/* src/creds/* -.stackql/* +.stackql creds/* stackql stackql.exe @@ -9,6 +9,7 @@ stackql.exe .demo-creds.sh .demo-creds.ps1 .demo-queries.sql +.env # Logs logs diff --git a/README.md b/README.md index 013c557..44583ab 100644 --- a/README.md +++ b/README.md @@ -57,12 +57,9 @@ flowchart TB; cloudprovider --> |data| runner ``` -Detailed design documentation can be found [here](docs/detailed-design.md). - ## Example Usage - -## Request Structure +### Request Structure StackQL queries are sent to the server using the `POST` method and the `application/json` content type. The request body should contain a JSON object with the following properties: @@ -81,11 +78,25 @@ StackQL queries are sent to the server using the `POST` method and the `applicat `showMetadata` is an optional property that, if set to `true`, will cause the server to return metadata about the query execution. This includes the query plan, the number of rows returned, and the time to execute the query. The default value is `false`. -## Response Structure +An example is shown here: + +```bash +curl -X POST http://localhost:8080/stackql \ + -H "Content-Type: application/json" \ + -d '{ + "query": "SELECT COUNT(*) FROM aws.ec2.instances_list_only WHERE region = '\''ap-southeast-2'\''", + "params": { + "region": "ap-southeast-2" + }, + "showMetadata": true + }' +``` + +### Response Structure Responses can include metadata and the results of a query or will return information about errors if they occur. -### Without Metadata +#### Without Metadata If the `showMetadata` option is not set or set to `false`, the response will be a JSON array containing the query results. The following example shows the response to a query that returns a single row with two columns: @@ -100,7 +111,7 @@ If the `showMetadata` option is not set or set to `false`, the response will be } ``` -### With Metadata +#### With Metadata If the query was submitted with the `showMetadata` option set, additional information about the request and response will be returned. An example is shown here: @@ -132,7 +143,7 @@ If the query was submitted with the `showMetadata` option set, additional inform } ``` -### With Errors +#### With Errors If there are errors in the execution of a query, a response similar to the following will be returned: @@ -155,12 +166,12 @@ Here is a [quick start guide](docs/quickstart.md) to get you up and running with ## Generating a Provider -Providers for any API backend can be generated using StackQL tools, including [stackql/openapi-doc-util](https://github.com/stackql/openapi-doc-util). +Providers for any API backend can be generated using StackQL tools, including [stackql/openapisaurus](https://github.com/stackql/openapisaurus). ## Acknowledgements This project is made possible by the following open source projects: - [StackQL](https://github.com/stackql/stackql) -- [Deno Oak](https://deno.land/x/oak@v11.1.0) +- [Oak Server](https://oakserver.org/) - [Deno Postgres Driver](https://github.com/denodrivers/postgres) diff --git a/demo.ps1 b/demo.ps1 deleted file mode 100644 index 53b4dcf..0000000 --- a/demo.ps1 +++ /dev/null @@ -1,26 +0,0 @@ -## credentials -$Env:AWS_ACCESS_KEY_ID = "YOURAWSACCESSKEYID" -$Env:AWS_SECRET_ACCESS_KEY = "YOURAWSSECRETACCESSKEY" -$Env:AZ_ACCESS_TOKEN = "$(az account get-access-token --query accessToken --output tsv)".Trim("`r") -$Env:GITHUB_CREDS = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("yourusername:ghp_YOURPERSONALACCESSTOKEN")) -$Env:OKTA_SECRET_KEY = "YOUROKTASECRETKEY" -$Env:NETLIFY_TOKEN = "YOURAPITOKEN" - -# auth objects -$aws = "{ 'type': 'aws_signing_v4', 'credentialsenvvar': 'AWS_SECRET_ACCESS_KEY', 'keyIDenvvar': 'AWS_ACCESS_KEY_ID' }" -$azure = "{ 'type': 'bearer', 'credentialsenvvar': 'AZ_ACCESS_TOKEN' }" -$github = "{ 'type': 'basic', 'credentialsenvvar': 'GITHUB_CREDS' }" -$okta = "{ 'type': 'api_key', 'credentialsenvvar': 'OKTA_SECRET_KEY' }" -$netlify = "{ 'type': 'bearer', 'credentialsenvvar': 'NETLIFY_TOKEN' }" - -## auth struct -$Env:AUTH_STR = "{ 'aws': $($aws), 'azure': $($azure), 'github': $($github), 'okta': $($okta), 'netlify': $($netlify) }" - -## build and run env -docker compose up --build - -## demo playground @ localhost:3000 -## demo API using Postman or curl @ localhost:8080 - -## remove containers -docker compose down \ No newline at end of file diff --git a/demo.sh b/demo.sh index 56d427d..580988c 100644 --- a/demo.sh +++ b/demo.sh @@ -1,28 +1,24 @@ -## credentials -export AWS_ACCESS_KEY_ID=YOURAWSACCESSKEYID -export AWS_SECRET_ACCESS_KEY=YOURAWSSECRETACCESSKEY -AZ_ACCESS_TOKEN_RAW=$(az account get-access-token --query accessToken --output tsv) -export AZ_ACCESS_TOKEN=`echo $AZ_ACCESS_TOKEN_RAW | tr -d '\r'` -export GITHUB_CREDS=$(echo -n 'yourusername:ghp_YOURPERSONALACCESSTOKEN' | base64) -export OKTA_SECRET_KEY=YOUROKTASECRETKEY # Okta API Token -export NETLIFY_TOKEN=YOURAPITOKEN +LOGLEVEL=DEBUG docker compose up --build -# auth objects -AWS_AUTH='{ "type": "aws_signing_v4", "credentialsenvvar": "AWS_SECRET_ACCESS_KEY", "keyIDenvvar": "AWS_ACCESS_KEY_ID" }' -AZURE_AUTH='{ "type": "bearer", "credentialsenvvar": "AZ_ACCESS_TOKEN" }' -GITHUB_AUTH='{ "type": "basic", "credentialsenvvar": "GITHUB_CREDS" }' -OKTA_AUTH='{ "type": "api_key", "credentialsenvvar": "OKTA_SECRET_KEY" }' -NETLIFY_AUTH='{ "type": "bearer", "credentialsenvvar": "NETLIFY_TOKEN" }' +docker compose exec api deno test --allow-net tests/api.test.ts -## auth struct -template='{ "aws": %s, "azure": %s, "github": %s, "okta": %s, "netlify": %s }' -export AUTH_STR=$(printf "$template" "$AWS_AUTH","$AZURE_AUTH","$GITHUB_AUTH","$OKTA_AUTH","$NETLIFY_AUTH") +curl -X POST http://localhost:8080/stackql \ + -H "Content-Type: application/json" \ + -d '{ + "query": "SELECT COUNT(*) FROM aws.ec2.instances_list_only WHERE region = '\''$region'\''", + "params": { + "region": "ap-southeast-2" + }, + "showMetadata": true + }' -## build and run env -docker compose up --build +curl -X POST http://localhost:8080/stackql \ + -H "Content-Type: application/json" \ + -d '{ + "query": "SELECT COUNT(*) FROM aws.ec2.instances_list_only WHERE region = '\''ap-southeast-2'\''", + "showMetadata": true + }' -## demo playground @ localhost:3000 -## demo API using Postman or curl @ localhost:8080 +# SELECT COUNT(*) FROM aws.ec2.instances_list_only WHERE region = 'ap-southeast-2'; -## remove containers docker compose down \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 92f2a2a..9bede20 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,11 +18,23 @@ services: expose: - 5444 environment: + - STACKQL_GITHUB_USERNAME + - STACKQL_GITHUB_PASSWORD + - AZURE_TENANT_ID + - AZURE_CLIENT_ID + - AZURE_CLIENT_SECRET - AWS_ACCESS_KEY_ID - AWS_SECRET_ACCESS_KEY - - GITHUB_CREDS - - OKTA_SECRET_KEY - - NETLIFY_TOKEN + - GOOGLE_CREDENTIALS + - DIGITALOCEAN_ACCESS_TOKEN + - LINODE_TOKEN + - DATABRICKS_ACCOUNT_ID + - DATABRICKS_CLIENT_ID + - DATABRICKS_CLIENT_SECRET + - CONFLUENT_CLOUD_API_KEY + - CONFLUENT_CLOUD_API_SECRET + - OKTA_API_TOKEN + - NETLIFY_AUTH_TOKEN healthcheck: test: ["CMD", "stackql", "--version"] interval: 10s diff --git a/docs/detailed-design.md b/docs/detailed-design.md deleted file mode 100644 index 6de287b..0000000 --- a/docs/detailed-design.md +++ /dev/null @@ -1,11 +0,0 @@ -# StackQL Middleware Detailed Design - -A high level overview of the StackQL Middleware design can be found [here](../README.md). - -## Container Diagram - -The following diagram shows the components of the StackQL Middleware solution and how they interact with each other. - -
-StackQL Middleware Container -
\ No newline at end of file diff --git a/docs/quickstart.md b/docs/quickstart.md index fb66167..ea101c5 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -1,12 +1,6 @@ # StackQL Middleware Quickstart -Use the [docker-compose.yml](../docker-compose.yml) file included with this repository to get up and running quickly with the following architecture: - -
-StackQL Middleware Docker Compose Environment -
- -The quickstart includes the following components: +Use the [docker-compose.yml](../docker-compose.yml) file included with this repository which contains a quick start to get up and running quickly. This includes the following components: - [StackQL Server](https://github.com/stackql/stackql) - [StackQL Playground](https://github.com/stackql/stackql-playground) @@ -30,36 +24,22 @@ This quick start uses [docker compose v2](https://docs.docker.com/compose/). 1. __Populate Environment Variables for Provider Authentication__ -Populate the following environment variables where required (for a provider for which you have credentials and want to query): +(Optional) Populate the following environment variables where required (for a provider for which you have credentials and want to query): -- `GITHUB_CREDS` (base64 encoded value of the GitHub username and Personal Acces Token) -- `AZ_ACCESS_TOKEN` (Azure access token) +- `STACKQL_GITHUB_USERNAME` and `STACKQL_GITHUB_PASSWORD` (GitHub Username and Personal Access Token) +- `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET` (for Azure access) - `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` (AWS API credentials) -- `OKTA_SECRET_KEY` (Okta API key) -- `NETLIFY_TOKEN` (Netlify API key) - -Then export a variable named `AUTH_STR` which will be passed to the stackql server. A complete example using GitHub credentials is shown here: - -__MacOS/Linux__ - -```bash -export GITHUB_CREDS=$(echo -n 'yourusername:ghp_YOURPERSONALACCESSTOKEN' | base64) -export AUTH_STR='{ "github": { "type": "basic", "credentialsenvvar": "GITHUB_CREDS" }}' -``` - -__Windows/PowerShell__ - -```powershell -$Env:GITHUB_CREDS = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("yourusername:ghp_YOURPERSONALACCESSTOKEN")) -$Env:AUTH_STR = "{ 'github': { 'type': 'basic', 'credentialsenvvar': 'GITHUB_CREDS' } }" -``` +- `GOOGLE_CREDENTIALS` (Google service account) +- `DIGITALOCEAN_ACCESS_TOKEN` +- `LINODE_TOKEN` +- `DATABRICKS_ACCOUNT_ID`, `DATABRICKS_CLIENT_ID`, `DATABRICKS_CLIENT_SECRET` (for `databricks_account` or `databricks_workspace`) +- `CONFLUENT_CLOUD_API_KEY`, `CONFLUENT_CLOUD_API_SECRET` (for Confluent cloud access) +- `OKTA_API_TOKEN` +- `NETLIFY_AUTH_TOKEN` -> for additional provider support, add their authentication objects to the `auth` struct as shown below, for more information about authentication, check the documentation for the respective provider, see [here](https://registry.stackql.io/) +> for additional provider support, export their authentication environment variables and add them to the `environment` section of the `runner` in [docker-compose.yml](../docker-compose.yml), for more information about authentication, check the documentation for the respective provider, see [here](https://registry.stackql.io/) -```bash -export GITHUB_CREDS=$(echo -n 'yourusername:ghp_YOURPERSONALACCESSTOKEN' | base64) -export AUTH_STR='{ "github": { "type": "basic", "credentialsenvvar": "GITHUB_CREDS" }, "aws": { "type": "aws_signing_v4", "credentialsenvvar": "AWS_SECRET_ACCESS_KEY", "keyIDenvvar": "AWS_ACCESS_KEY_ID" }}' -``` +> ℹ️ To bring your own custom provider, add the provider dirctory to the `.stackql/src` directory on the runner image, then export a variable named `AUTH_STR` and pass this to the the stackql server as an argument in the `runner` section of the `docker-compose.yml` (`stackql --auth="${AUTH_STR}" --pgsrv.port=5444 srv`). The `AUTH_STR` should map to the authentication method and variable names in your custom `provider.yaml` definition, e.g. `'{"my_provider": { "type": "api_key", "credentialsenvvar": "MY_KEY_VAR" }}'`. 2. __Start Environment__ diff --git a/puml/stackql-docker-compose.puml b/puml/stackql-docker-compose.puml deleted file mode 100644 index 219e51a..0000000 --- a/puml/stackql-docker-compose.puml +++ /dev/null @@ -1,31 +0,0 @@ -@startuml -!includeurl https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml - -!define Rel_NoRank(e_from,e_to, e_label=" ") Rel_(e_from,e_to, e_label, "-[norank]->") - -title StackQL Docker Compose Architecture - -Person(user, "User") - -System_Boundary(middleware, "stackql Middleware") { - Container(playground, "playground", "React/NextJS App") - Container(api, "api", "deno Oak") - Container(runner, "runner", "stackql srv") - ContainerDb(cache, "cache", "Redis") -} - -Container_Ext(beapi, "API Provider", "Backend API") - -Lay_R(user, playground) -Lay_D(playground, api) -Lay_R(playground, runner) -Lay_D(runner, cache) - -Rel_R(user, playground, "localhost:3000") -Rel_R(user, api, "localhost:8080") -Rel_D(playground, api, "localhost:8080") -Rel_R(api, runner, "runner:5444") -Rel_R(runner, beapi, ":443") -Rel_D(api, cache, "cache:6379") - -@enduml \ No newline at end of file diff --git a/puml/stackql-middleware-container.puml b/puml/stackql-middleware-container.puml deleted file mode 100644 index d7bc679..0000000 --- a/puml/stackql-middleware-container.puml +++ /dev/null @@ -1,45 +0,0 @@ -@startuml -!includeurl https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml - -!define Rel_NoRank(e_from,e_to, e_label=" ") Rel_(e_from,e_to, e_label, "-[norank]->") - -title StackQL Middleware Container Diagram - -Person(admin, "Middleware Admin") -Container(app, "App or Playground", "JAMStack App") - -System_Boundary(middleware, "stackql Middleware") { - Container(lb, "FE LB", "Load Balancer") - Container(feapi, "Front End API", "Oak") - Container(adminapi, "Admin API", "Oak") - Container(stackql, "Runner", "stackql srv") - ContainerDb(cache, "Results Cache", "Redis") - ContainerQueue(config, "Shared Config", "Message Queue") -} - -Container_Ext(beapi, "API Provider", "REST or GraphQL") - -Lay_D(admin, app) -Lay_R(app, lb) -Lay_R(lb, feapi) -Lay_R(feapi, stackql) -Lay_R(stackql, beapi) -Lay_D(adminapi, feapi) -Lay_R(adminapi, config) -Lay_D(feapi, cache) - -Rel_Neighbor(admin, adminapi, "updates config") -Rel_Neighbor(adminapi, config, "config") -Rel_R(app, lb, "submits query") -Rel_R(lb, feapi, " ") -Rel_U(cache, feapi, "gets") -Rel_D(feapi, cache, "stores") -Rel_R(feapi, stackql, "submits") -Rel_L(stackql, feapi, "returns") -Rel_R(stackql, beapi, "request") -Rel_L(beapi, stackql, "response") -Rel_D(config, feapi, "config") -Rel_D(config, stackql, "config") -Rel_L(feapi, app, " ") - -@enduml \ No newline at end of file diff --git a/puml/stackql-middleware-context.puml b/puml/stackql-middleware-context.puml deleted file mode 100644 index a4892da..0000000 --- a/puml/stackql-middleware-context.puml +++ /dev/null @@ -1,40 +0,0 @@ -@startuml -!includeurl https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml -!define FONTAWESOME5 https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/font-awesome-5 -!define FONTAWESOME https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/font-awesome - -!include FONTAWESOME5/users.puml -!include FONTAWESOME5/code.puml -!include FONTAWESOME5/cloud.puml -!include FONTAWESOME/gear.puml - -!define Rel_NoRank(e_from,e_to, e_label=" ") Rel_(e_from,e_to, e_label, "-[norank]->") - -title StackQL Middleware Context Diagram - -Person(users, "Users", $sprite="users") - -System_Boundary(middleware, "stackql Middleware") { - Container(restApi, "stackql API", "Deno Oak", $sprite="code") - Container(stackQLServer, "stackql server", "stackql srv", $sprite="gear") - -} - -System(apiProvider, "API Provider\n(REST)", $sprite="cloud") -System(graphqlProvider, "API Provider\n(GraphQL)", $sprite="cloud") - -Lay_R(users, restApi) -Lay_R(restApi, stackQLServer) -Lay_R(stackQLServer, apiProvider) -Lay_D(graphqlProvider, apiProvider) - -Rel_R(users, restApi, "POST request", "body: StackQL query") -Rel_L(restApi, users, " ") -Rel_R(restApi, stackQLServer, "PG wire protocol") -Rel_L(stackQLServer, restApi, " ") -Rel_R(stackQLServer, apiProvider, " ") -Rel_L(apiProvider, stackQLServer, " ") -Rel_NoRank(graphqlProvider, stackQLServer, " ") -Rel_NoRank(stackQLServer, graphqlProvider, " ") - -@enduml \ No newline at end of file diff --git a/runner.Dockerfile b/runner.Dockerfile index 1a76123..410a35e 100644 --- a/runner.Dockerfile +++ b/runner.Dockerfile @@ -12,4 +12,9 @@ RUN stackql exec 'registry pull google' RUN stackql exec 'registry pull github' RUN stackql exec 'registry pull k8s' RUN stackql exec 'registry pull netlify' -RUN stackql exec 'registry pull okta' \ No newline at end of file +RUN stackql exec 'registry pull okta' +RUN stackql exec 'registry pull digitalocean' +RUN stackql exec 'registry pull linode' +RUN stackql exec 'registry pull confluent' +RUN stackql exec 'registry pull databricks_account' +RUN stackql exec 'registry pull databricks_workspace' diff --git a/src/README_old.md b/src/README_old.md deleted file mode 100644 index 0c880f6..0000000 --- a/src/README_old.md +++ /dev/null @@ -1,55 +0,0 @@ -## 1. generate keys - -``` -openssl req -x509 -keyout creds/server_key.pem -out creds/server_cert.pem -config creds/openssl.cnf -days 365 -openssl req -x509 -keyout creds/client_key.pem -out creds/client_cert.pem -config creds/openssl.cnf -days 365 -``` - -## 2. set env vars - -``` -export PGPORT=5444 -export PGSSLCERT=creds/client_cert.pem -export PGSSLKEY=creds/client_key.pem -export PGSSLROOTCERT=creds/server_cert.pem -export PGSSLSRVKEY=creds/server_key.pem -export CLIENT_CERT=$(base64 -w 0 creds/client_cert.pem) -export PGSSLMODE=allow -``` - -For MacOS -``` -export CLIENT_CERT=$(base64 -b 0 creds/client_cert.pem) -``` - -## 3a. start stackql sever with no auth - -``` -stackql srv \ ---pgsrv.address=0.0.0.0 \ ---pgsrv.port=5444 \ ---pgsrv.tls='{ "keyFilePath": "'${PGSSLSRVKEY}'", "certFilePath": "'${PGSSLROOTCERT}'", "clientCAs": [ "'${CLIENT_CERT}'" ] }' -``` - -## 3b. start stackql server with auth - -### Azure example - -``` -export AZ_ACCESS_TOKEN=$(az account get-access-token --query accessToken --output tsv | tr -d '\r') -AUTH='{ "azure": { "type": "api_key", "valuePrefix": "Bearer ", "credentialsenvvar": "AZ_ACCESS_TOKEN" } }' -bin/stackql srv --auth="${AUTH}" \ ---pgsrv.address=0.0.0.0 \ ---pgsrv.port=$PGPORT \ ---pgsrv.tls='{ "keyFilePath": "'${PGSSLSRVKEY}'", "certFilePath": "'${PGSSLROOTCERT}'", "clientCAs": [ "'${CLIENT_CERT}'" ] }' -``` -### GitHub -export AUTH='{ "github": { "type": "basic", "credentialsenvvar": "GITHUB_CREDS" } }' - -## 4. start middleware server -change directory into `./src` - -``` -# deno run --allow-env --allow-net --allow-read --unsafely-ignore-certificate-errors=localhost app.ts -deno run --allow-env --allow-net --allow-read app.ts -``` \ No newline at end of file diff --git a/src/config/environment.ts b/src/config/environment.ts index 760ebfa..7f4f0f2 100644 --- a/src/config/environment.ts +++ b/src/config/environment.ts @@ -11,6 +11,6 @@ export const config = { user: 'stackql', }, logging: { - level: Deno.env.get('LOGLEVEL') || 'DEBUG' + level: Deno.env.get('LOGLEVEL') || 'INFO' } }; diff --git a/src/controllers/query.controller.ts b/src/controllers/query.controller.ts index 230e7a1..5c6ec2e 100644 --- a/src/controllers/query.controller.ts +++ b/src/controllers/query.controller.ts @@ -1,9 +1,28 @@ // controllers/query.controller.ts import { Context } from "../types/context.types.ts"; -import { QueryRequest, QueryResponse, ErrorResponse } from "../types/api.types.ts"; +import { QueryRequest, QueryResponse, ErrorResponse, RespData } from "../types/api.types.ts"; import { db } from "../services/database.service.ts"; import { logger } from "../services/logger.service.ts"; -import { validateQuery } from "../utils/query.utils.ts"; +import { validateQuery, substituteParams } from "../utils/query.utils.ts"; +import { generateTypes } from "https://deno.land/x/dts/mod.ts"; + +async function getTypes(renderedQuery: string): Promise { + const firstRow = (await db.query(renderedQuery))[0]; + if (!firstRow) { + return { + status: 400, + type: 'application/json', + body: { error: "No data returned to generate types" } + }; + } + + const typeDef = await generateTypes(firstRow); + return { + status: 200, + type: 'text/plain', + body: typeDef + }; + } export async function executeQuery(ctx: Context) { if (!ctx.request.hasBody) { @@ -12,13 +31,21 @@ export async function executeQuery(ctx: Context) { return; } + const queryParams = new URLSearchParams(ctx.request.url.search); + const dts = queryParams.has('dts'); + let respData: RespData; + try { - // const body = await ctx.request.body.value; const body = await ctx.request.body.json(); - logger.info(`Request body: ${JSON.stringify(body)}`); + logger.debug(`Request body: ${JSON.stringify(body)}`); const reqData: QueryRequest = typeof body === "string" ? JSON.parse(body) : body; - logger.info(`Request data: ${JSON.stringify(reqData)}`); + logger.debug(`Request data: ${JSON.stringify(reqData)}`); + + const renderedQuery = substituteParams(reqData.query, reqData.params); + if(renderedQuery !== reqData.query) { + logger.debug(`Rendered query: ${renderedQuery}`); + } const validationError = validateQuery(reqData.query); if (validationError) { @@ -30,11 +57,11 @@ export async function executeQuery(ctx: Context) { const startTime = new Date().toISOString(); const t0 = performance.now(); - const rows = await db.query(reqData.query); + const rows = await db.query(renderedQuery); const response: QueryResponse = { data: rows, - ...(reqData.showMetadata && { + ...((reqData.showMetadata !== false) && { // Only exclude if explicitly false metadata: { operation: { startTime, @@ -46,11 +73,15 @@ export async function executeQuery(ctx: Context) { rowCount: rows.length }, request: { - query: reqData.query + query: reqData.query, + ...(reqData.params && { + params: reqData.params, + renderedQuery: renderedQuery + }) } } }) - }; + }; ctx.response.body = response; } catch (error) { diff --git a/src/types/api.types.ts b/src/types/api.types.ts index a6bd290..21715cb 100644 --- a/src/types/api.types.ts +++ b/src/types/api.types.ts @@ -1,29 +1,37 @@ // types/api.types.ts +export interface RespData { + status: number; + type: 'application/json' | 'text/plain'; + body: unknown; +} + export interface QueryRequest { query: string; + params?: Record; showMetadata?: boolean; - } +} export interface QueryResponse { data: unknown[]; metadata?: { - operation: { - startTime?: string; - endTime?: string; - duration?: string; - status?: string; - }; - result: { - rowCount?: number; - }; - request: { - query?: string; - }; + operation: { + startTime: string; + endTime: string; + duration: string; + status: string; + }; + result: { + rowCount: number; + }; + request: { + query: string; + params?: Record; + renderedQuery: string; + }; }; } export interface ErrorResponse { error: string; } - \ No newline at end of file diff --git a/src/utils/query.utils.ts b/src/utils/query.utils.ts index 98ece20..ea0b9d9 100644 --- a/src/utils/query.utils.ts +++ b/src/utils/query.utils.ts @@ -2,14 +2,27 @@ const ALLOWED_QUERY_TYPES = ['select', 'show', 'describe']; export function validateQuery(query: string): string | null { - if (!query) { - return 'Query is required'; - } + if (!query) { + return 'Query is required'; + } - const queryType = query.trim().toLowerCase().split(' ')[0]; - if (!ALLOWED_QUERY_TYPES.includes(queryType)) { - return `Query type '${queryType}' not allowed. Only SELECT, SHOW, and DESCRIBE are supported`; - } + const queryType = query.trim().toLowerCase().split(' ')[0]; + if (!ALLOWED_QUERY_TYPES.includes(queryType)) { + return `Query type '${queryType}' not allowed. Only SELECT, SHOW, and DESCRIBE are supported`; + } - return null; + return null; +} + +export function substituteParams(query: string, params?: Record): string { + if (!params) return query; + + let substitutedQuery = query; + for (const [key, value] of Object.entries(params)) { + substitutedQuery = substitutedQuery.replace( + new RegExp(`'\\$${key}'`, 'g'), + `'${value}'` + ); + } + return substitutedQuery; } From a266a633244fe38ca8cf4b3903354b51be2df704 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Thu, 6 Feb 2025 19:37:08 +1100 Subject: [PATCH 30/31] refactor --- src/controllers/query.controller.ts | 156 ++++++++++++++-------------- src/tests/api.test.ts | 36 +++++++ src/utils/query.utils.ts | 4 +- 3 files changed, 116 insertions(+), 80 deletions(-) diff --git a/src/controllers/query.controller.ts b/src/controllers/query.controller.ts index 5c6ec2e..efa33d4 100644 --- a/src/controllers/query.controller.ts +++ b/src/controllers/query.controller.ts @@ -1,95 +1,95 @@ // controllers/query.controller.ts import { Context } from "../types/context.types.ts"; -import { QueryRequest, QueryResponse, ErrorResponse, RespData } from "../types/api.types.ts"; +import { QueryRequest, QueryResponse, ErrorResponse } from "../types/api.types.ts"; import { db } from "../services/database.service.ts"; import { logger } from "../services/logger.service.ts"; import { validateQuery, substituteParams } from "../utils/query.utils.ts"; import { generateTypes } from "https://deno.land/x/dts/mod.ts"; -async function getTypes(renderedQuery: string): Promise { - const firstRow = (await db.query(renderedQuery))[0]; - if (!firstRow) { - return { - status: 400, - type: 'application/json', - body: { error: "No data returned to generate types" } - }; - } - - const typeDef = await generateTypes(firstRow); - return { - status: 200, - type: 'text/plain', - body: typeDef - }; - } - export async function executeQuery(ctx: Context) { - if (!ctx.request.hasBody) { - ctx.response.status = 400; - ctx.response.body = { error: "Request body required" }; - return; - } + if (!ctx.request.hasBody) { + ctx.response.status = 400; + ctx.response.type = 'application/json'; + ctx.response.body = { error: "Request body required" }; + return; + } - const queryParams = new URLSearchParams(ctx.request.url.search); - const dts = queryParams.has('dts'); - let respData: RespData; + try { + // Parse request + const body = await ctx.request.body.json(); + const reqData: QueryRequest = typeof body === "string" ? JSON.parse(body) : body; + logger.debug(`Request data: ${JSON.stringify(reqData)}`); - try { - const body = await ctx.request.body.json(); - logger.debug(`Request body: ${JSON.stringify(body)}`); + // Validate query + const validationError = validateQuery(reqData.query); + if (validationError) { + ctx.response.status = 405; + ctx.response.type = 'application/json'; + ctx.response.body = { error: validationError }; + return; + } - const reqData: QueryRequest = typeof body === "string" ? JSON.parse(body) : body; - logger.debug(`Request data: ${JSON.stringify(reqData)}`); + // Process query + const renderedQuery = substituteParams(reqData.query, reqData.params); + if(renderedQuery !== reqData.query) { + logger.debug(`Rendered query: ${renderedQuery}`); + } - const renderedQuery = substituteParams(reqData.query, reqData.params); - if(renderedQuery !== reqData.query) { - logger.debug(`Rendered query: ${renderedQuery}`); - } + // Generate types or execute query + const dts = new URLSearchParams(ctx.request.url.search).has('dts'); + if (dts) { + const firstRow = (await db.query(renderedQuery))[0]; + if (!firstRow) { + ctx.response.status = 400; + ctx.response.type = 'application/json'; + ctx.response.body = { error: "No data returned to generate types" }; + return; + } + ctx.response.type = 'text/plain'; + ctx.response.status = 200; + ctx.response.body = await generateTypes(firstRow); + return; + } - const validationError = validateQuery(reqData.query); - if (validationError) { - ctx.response.status = 405; - ctx.response.body = { error: validationError }; - return; - } + // Execute query and return data + const startTime = new Date().toISOString(); + const t0 = performance.now(); + const rows = await db.query(renderedQuery); - const startTime = new Date().toISOString(); - const t0 = performance.now(); + const response: QueryResponse = { + data: rows, + ...((reqData.showMetadata !== false) && { + metadata: { + operation: { + startTime, + endTime: new Date().toISOString(), + duration: `${performance.now() - t0} ms`, + status: 'OK' + }, + result: { + rowCount: rows.length + }, + request: { + query: reqData.query, + ...(reqData.params && { + params: reqData.params, + renderedQuery + }) + } + } + }) + }; - const rows = await db.query(renderedQuery); - - const response: QueryResponse = { - data: rows, - ...((reqData.showMetadata !== false) && { // Only exclude if explicitly false - metadata: { - operation: { - startTime, - endTime: new Date().toISOString(), - duration: `${performance.now() - t0} ms`, - status: 'OK' - }, - result: { - rowCount: rows.length - }, - request: { - query: reqData.query, - ...(reqData.params && { - params: reqData.params, - renderedQuery: renderedQuery - }) - } - } - }) - }; + ctx.response.type = 'application/json'; + ctx.response.status = 200; + ctx.response.body = response; - ctx.response.body = response; - } catch (error) { - logger.error(`Query execution failed: ${error.message}`); - ctx.response.status = 400; - const errorResponse: ErrorResponse = { - error: error.message.replace(/\n/g, "") - }; - ctx.response.body = errorResponse; - } + } catch (error) { + logger.error(`Query execution failed: ${error.message}`); + ctx.response.type = 'application/json'; + ctx.response.status = 400; + ctx.response.body = { + error: error.message.replace(/\n/g, "") + }; + } } \ No newline at end of file diff --git a/src/tests/api.test.ts b/src/tests/api.test.ts index 97ef3be..44c88d6 100644 --- a/src/tests/api.test.ts +++ b/src/tests/api.test.ts @@ -69,6 +69,42 @@ Deno.test("API Integration Tests", async (t) => { assertEquals(response.status, 200); assertExists(data.data); }); + + await t.step("Query execution - DTS generation", async () => { + const { response, data } = await makeRequest( + "http://localhost:8080/stackql?dts=true", + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + query: "DESCRIBE EXTENDED aws.ec2.instances" + }) + } + ); + assertEquals(response.status, 200); + assertEquals(response.headers.get("content-type"), "text/plain; charset=UTF-8"); + assertExists(data.includes("declare module namespace")); + assertExists(data.includes("IRootObject")); + assertExists(data.includes("name: string")); + }); + + await t.step("Query execution - metadata disabled", async () => { + const { response, data } = await makeRequest( + "http://localhost:8080/stackql", + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + query: "SELECT * FROM github.repos.contributors WHERE repo = 'stackql' and owner = 'stackql'", + showMetadata: false + }) + } + ); + assertEquals(response.status, 200); + assertExists(data.data); + assertEquals(data.metadata, undefined); + }); + } finally { // Clean up all fetch requests controllers.forEach(controller => controller.abort()); diff --git a/src/utils/query.utils.ts b/src/utils/query.utils.ts index ea0b9d9..cfca0c6 100644 --- a/src/utils/query.utils.ts +++ b/src/utils/query.utils.ts @@ -1,5 +1,5 @@ // utils/query.utils.ts -const ALLOWED_QUERY_TYPES = ['select', 'show', 'describe']; +const ALLOWED_QUERY_TYPES = ['select', 'show', 'describe', 'registry']; export function validateQuery(query: string): string | null { if (!query) { @@ -8,7 +8,7 @@ export function validateQuery(query: string): string | null { const queryType = query.trim().toLowerCase().split(' ')[0]; if (!ALLOWED_QUERY_TYPES.includes(queryType)) { - return `Query type '${queryType}' not allowed. Only SELECT, SHOW, and DESCRIBE are supported`; + return `Query type '${queryType}' not allowed. Only SELECT, SHOW, DESCRIBE and REGISTRY are supported`; } return null; From 4e6552ec5e59c6f28609f14b9be419b0df84e170 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Wed, 12 Feb 2025 11:29:52 +1100 Subject: [PATCH 31/31] added duckdb runner, route and controller --- README.md | 2 +- demo.sh | 10 +++- docker-compose.yml | 27 ++++++++++- duckdb.Dockerfile | 25 ++++++++++ scripts/healthcheck.sh | 2 + scripts/startup.sh | 4 ++ src/Dockerfile | 22 +++++++-- src/app.ts | 3 ++ src/config/environment.ts | 4 ++ src/controllers/duckdb.controller.ts | 61 +++++++++++++++++++++++++ src/routes/duckdb.routes.ts | 6 +++ src/services/duckdb.service.ts | 68 ++++++++++++++++++++++++++++ src/tests/duckdb.test.ts | 41 +++++++++++++++++ 13 files changed, 268 insertions(+), 7 deletions(-) create mode 100644 duckdb.Dockerfile create mode 100644 scripts/healthcheck.sh create mode 100644 scripts/startup.sh create mode 100644 src/controllers/duckdb.controller.ts create mode 100644 src/routes/duckdb.routes.ts create mode 100644 src/services/duckdb.service.ts create mode 100644 src/tests/duckdb.test.ts diff --git a/README.md b/README.md index 44583ab..aefaefb 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ An example is shown here: curl -X POST http://localhost:8080/stackql \ -H "Content-Type: application/json" \ -d '{ - "query": "SELECT COUNT(*) FROM aws.ec2.instances_list_only WHERE region = '\''ap-southeast-2'\''", + "query": "SELECT COUNT(*) as count FROM aws.ec2.instances_list_only WHERE region = '\''ap-southeast-2'\''", "params": { "region": "ap-southeast-2" }, diff --git a/demo.sh b/demo.sh index 580988c..669548f 100644 --- a/demo.sh +++ b/demo.sh @@ -1,11 +1,12 @@ LOGLEVEL=DEBUG docker compose up --build docker compose exec api deno test --allow-net tests/api.test.ts +docker compose exec api deno test --allow-net tests/duckdb.test.ts curl -X POST http://localhost:8080/stackql \ -H "Content-Type: application/json" \ -d '{ - "query": "SELECT COUNT(*) FROM aws.ec2.instances_list_only WHERE region = '\''$region'\''", + "query": "SELECT COUNT(*) as count FROM aws.ec2.instances_list_only WHERE region = '\''$region'\''", "params": { "region": "ap-southeast-2" }, @@ -15,10 +16,15 @@ curl -X POST http://localhost:8080/stackql \ curl -X POST http://localhost:8080/stackql \ -H "Content-Type: application/json" \ -d '{ - "query": "SELECT COUNT(*) FROM aws.ec2.instances_list_only WHERE region = '\''ap-southeast-2'\''", + "query": "SELECT COUNT(*) as count FROM aws.ec2.instances_list_only WHERE region = '\''ap-southeast-2'\''", "showMetadata": true }' # SELECT COUNT(*) FROM aws.ec2.instances_list_only WHERE region = 'ap-southeast-2'; +export SQL_QUERY="SELECT country_region AS country, CAST(SUM(confirmed) AS INTEGER) AS total_confirmed, CAST(SUM(deaths) AS INTEGER) AS total_deaths, COUNT(*) AS record_count FROM read_csv_auto('s3://covid19-lake/archived/enigma-jhu/csv/Enigma-JHU.csv.gz') GROUP BY country_region ORDER BY total_confirmed DESC LIMIT 5" +curl -X POST http://localhost:8080/duckdb \ + -H "Content-Type: application/json" \ + -d "{\"query\": \"${SQL_QUERY}\", \"showMetadata\": true}" + docker compose down \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 9bede20..812711c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,6 +42,24 @@ services: retries: 3 command: stackql --pgsrv.port=5444 srv + duckdb: + build: + context: . + dockerfile: duckdb.Dockerfile + expose: + - 5433 + environment: + - AWS_ACCESS_KEY_ID + - AWS_SECRET_ACCESS_KEY + - AWS_REGION + volumes: + - duckdb-data:/app/data + healthcheck: + test: ["CMD", "/app/healthcheck.sh"] + interval: 10s + timeout: 5s + retries: 3 + api: build: context: ./src @@ -49,9 +67,16 @@ services: environment: DB_HOST: runner DB_PORT: 5444 + DUCKDB_HOST: duckdb + DUCKDB_PORT: 5433 LOGLEVEL: ${LOGLEVEL:-INFO} ports: - "8080:8080" depends_on: runner: - condition: service_healthy \ No newline at end of file + condition: service_healthy + duckdb: + condition: service_healthy + +volumes: + duckdb-data: diff --git a/duckdb.Dockerfile b/duckdb.Dockerfile new file mode 100644 index 0000000..d34874b --- /dev/null +++ b/duckdb.Dockerfile @@ -0,0 +1,25 @@ +FROM debian:bullseye-slim + +RUN apt-get update && apt-get install -y wget \ + && wget https://github.com/duckdb/duckdb/releases/download/v1.2.0/duckdb_cli-linux-amd64.zip \ + && apt-get install -y unzip \ + && unzip duckdb_cli-linux-amd64.zip \ + && rm duckdb_cli-linux-amd64.zip \ + && apt-get remove -y wget unzip \ + && apt-get autoremove -y \ + && apt-get clean + +WORKDIR /app + +COPY scripts/startup.sh /app/ +COPY scripts/healthcheck.sh /app/ + +RUN chmod +x /app/startup.sh /app/healthcheck.sh && \ + mv /duckdb /app/duckdb + +EXPOSE 5433 + +HEALTHCHECK --interval=10s --timeout=5s --start-period=5s --retries=3 \ + CMD ["/app/healthcheck.sh"] + +CMD ["/app/startup.sh"] \ No newline at end of file diff --git a/scripts/healthcheck.sh b/scripts/healthcheck.sh new file mode 100644 index 0000000..4427e73 --- /dev/null +++ b/scripts/healthcheck.sh @@ -0,0 +1,2 @@ +#!/bin/sh +test -f /app/healthy && ./duckdb mydatabase.db ".databases" > /dev/null 2>&1 \ No newline at end of file diff --git a/scripts/startup.sh b/scripts/startup.sh new file mode 100644 index 0000000..d84d543 --- /dev/null +++ b/scripts/startup.sh @@ -0,0 +1,4 @@ +#!/bin/sh +./duckdb mydatabase.db ".databases" > /dev/null 2>&1 || ./duckdb mydatabase.db +touch /app/healthy +tail -f /dev/null \ No newline at end of file diff --git a/src/Dockerfile b/src/Dockerfile index b06ae31..20bff00 100644 --- a/src/Dockerfile +++ b/src/Dockerfile @@ -1,7 +1,23 @@ # src/Dockerfile FROM denoland/deno:latest + +# Install DuckDB dependencies +RUN apt-get update && apt-get install -y \ + wget \ + unzip \ + && rm -rf /var/lib/apt/lists/* + +# Install DuckDB shared library +RUN wget https://github.com/duckdb/duckdb/releases/download/v1.2.0/libduckdb-linux-amd64.zip \ + && unzip libduckdb-linux-amd64.zip \ + && mv libduckdb.so /usr/lib/ \ + && rm libduckdb-linux-amd64.zip + WORKDIR /app + COPY . . -RUN deno cache --reload --unstable app.ts -EXPOSE 8080 -CMD ["run", "--allow-net", "--allow-env", "--watch", "app.ts"] \ No newline at end of file + +# Cache the dependencies +RUN deno cache deps.ts + +CMD ["deno", "run", "--allow-net", "--allow-env", "--allow-read", "--allow-write", "--allow-ffi", "--unstable", "--watch", "app.ts"] \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index 57da775..3bd922a 100644 --- a/src/app.ts +++ b/src/app.ts @@ -9,6 +9,7 @@ import { errorHandler } from "./middleware/error.middleware.ts"; import { healthRouter } from "./routes/health.routes.ts"; import { queryRouter } from "./routes/query.routes.ts"; import { metaRouter } from "./routes/meta.routes.ts"; +import { duckdbRouter } from "./routes/duckdb.routes.ts"; const app = new Application(); @@ -28,10 +29,12 @@ app.use(errorHandler); app.use(healthRouter.routes()); app.use(queryRouter.routes()); app.use(metaRouter.routes()); +app.use(duckdbRouter.routes()); app.use(healthRouter.allowedMethods()); app.use(queryRouter.allowedMethods()); app.use(metaRouter.allowedMethods()); +app.use(duckdbRouter.allowedMethods()); app.addEventListener("error", (evt) => { logger.error(`Uncaught error: ${evt.error}`); diff --git a/src/config/environment.ts b/src/config/environment.ts index 7f4f0f2..1fd5eca 100644 --- a/src/config/environment.ts +++ b/src/config/environment.ts @@ -10,6 +10,10 @@ export const config = { name: 'stackql', user: 'stackql', }, + duckdb: { + host: Deno.env.get('DUCKDB_HOST') || 'localhost', + port: Number(Deno.env.get('DUCKDB_PORT')) || 5433, + }, logging: { level: Deno.env.get('LOGLEVEL') || 'INFO' } diff --git a/src/controllers/duckdb.controller.ts b/src/controllers/duckdb.controller.ts new file mode 100644 index 0000000..4487d8b --- /dev/null +++ b/src/controllers/duckdb.controller.ts @@ -0,0 +1,61 @@ +// controllers/duckdb.controller.ts +import { Context } from "../types/context.types.ts"; +import { QueryRequest, QueryResponse } from "../types/api.types.ts"; +import { duckdb } from "../services/duckdb.service.ts"; +import { logger } from "../services/logger.service.ts"; + +export async function executeQuery(ctx: Context) { + if (!ctx.request.hasBody) { + ctx.response.status = 400; + ctx.response.body = { error: "Request body required" }; + return; + } + + try { + const body = await ctx.request.body.json(); + const reqData: QueryRequest = typeof body === "string" ? JSON.parse(body) : body; + logger.debug(`DuckDB request: ${JSON.stringify(reqData)}`); + + const startTime = new Date().toISOString(); + const t0 = performance.now(); + + const rows = duckdb.query(reqData.query); + logger.debug('DuckDB raw result:', JSON.stringify(rows)); + + // Try wrapping result in a more basic structure + const data = Array.isArray(rows) ? rows : [rows]; + logger.debug('Processed result:', JSON.stringify(data)); + + const response: QueryResponse = { + data, + ...((reqData.showMetadata !== false) && { + metadata: { + operation: { + startTime, + endTime: new Date().toISOString(), + duration: `${performance.now() - t0} ms`, + status: 'OK' + }, + result: { + rowCount: data.length + }, + request: { + query: reqData.query + } + } + }) + }; + + logger.debug('Final response:', JSON.stringify(response)); + + ctx.response.type = 'application/json'; + ctx.response.status = 200; + ctx.response.body = response; + + } catch (error) { + logger.error(`DuckDB query execution failed: ${error.message}`); + logger.error(`Stack trace: ${error.stack}`); + ctx.response.status = 400; + ctx.response.body = { error: error.message }; + } +} \ No newline at end of file diff --git a/src/routes/duckdb.routes.ts b/src/routes/duckdb.routes.ts new file mode 100644 index 0000000..c5393fd --- /dev/null +++ b/src/routes/duckdb.routes.ts @@ -0,0 +1,6 @@ +// routes/duckdb.routes.ts +import { Router } from "../deps.ts"; +import * as duckdbController from "../controllers/duckdb.controller.ts"; + +export const duckdbRouter = new Router() + .post("/duckdb", duckdbController.executeQuery); \ No newline at end of file diff --git a/src/services/duckdb.service.ts b/src/services/duckdb.service.ts new file mode 100644 index 0000000..c752b21 --- /dev/null +++ b/src/services/duckdb.service.ts @@ -0,0 +1,68 @@ +// services/duckdb.service.ts +import { open } from "https://deno.land/x/duckdb/mod.ts"; +import { config } from "../config/environment.ts"; +import { logger } from "./logger.service.ts"; + +class DuckDBService { + private db; + private connection; + + constructor() { + this.db = open(":memory:"); + this.connection = this.db.connect(); + this.init(); + } + + private async init() { + try { + // Install and load httpfs extension for S3 access + this.connection.query("INSTALL httpfs;"); + this.connection.query("LOAD httpfs;"); + + // Configure S3 credentials if available + const awsAccessKey = Deno.env.get("AWS_ACCESS_KEY_ID"); + const awsSecretKey = Deno.env.get("AWS_SECRET_ACCESS_KEY"); + const awsRegion = Deno.env.get("AWS_REGION"); + + if (awsAccessKey && awsSecretKey && awsRegion) { + this.connection.query( + `SET s3_access_key_id='${awsAccessKey}'; + SET s3_secret_access_key='${awsSecretKey}'; + SET s3_region='${awsRegion}';` + ); + } + logger.info("DuckDB initialized successfully"); + } catch (error) { + logger.error(`DuckDB initialization failed: ${error.message}`); + throw error; + } + } + + query(sql: string): T[] { + try { + logger.debug(`Executing query: ${sql}`); + const results: T[] = []; + + for (const row of this.connection.stream(sql)) { + logger.debug('Row:', row); + results.push(row as T); + } + + return results; + } catch (error) { + logger.error(`DuckDB query failed: ${error.message}`); + throw error; + } + } + + close() { + try { + this.connection.close(); + this.db.close(); + } catch (error) { + logger.error(`DuckDB closing failed: ${error.message}`); + } + } +} + +export const duckdb = new DuckDBService(); \ No newline at end of file diff --git a/src/tests/duckdb.test.ts b/src/tests/duckdb.test.ts new file mode 100644 index 0000000..8be4dd6 --- /dev/null +++ b/src/tests/duckdb.test.ts @@ -0,0 +1,41 @@ +// tests/duckdb.test.ts +import { assertEquals, assertExists } from "https://deno.land/std@0.208.0/assert/mod.ts"; + +const SQL_QUERY = ` + SELECT country_region AS country, + CAST(SUM(confirmed) AS INTEGER) AS total_confirmed, + CAST(SUM(deaths) AS INTEGER) AS total_deaths, + COUNT(*) AS record_count + FROM read_csv_auto('s3://covid19-lake/archived/enigma-jhu/csv/Enigma-JHU.csv.gz') + GROUP BY country_region + ORDER BY total_confirmed DESC + LIMIT 5 +`; + +Deno.test("DuckDB Integration Tests", async (t) => { + await t.step("Query execution - COVID-19 Dataset", async () => { + const response = await fetch("http://localhost:8080/duckdb", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + query: SQL_QUERY, + showMetadata: true + }) + }); + + assertEquals(response.status, 200); + + const data = await response.json(); + assertExists(data.data); + assertExists(data.metadata); + assertEquals(Array.isArray(data.data), true); + + if (data.data.length > 0) { + const firstRow = data.data[0]; + assertExists(firstRow.country); + assertExists(firstRow.total_confirmed); + assertExists(firstRow.total_deaths); + assertExists(firstRow.record_count); + } + }); +});