From e991e00f325d003d68e8ac710c4ee8dfb4bdca4c Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Fri, 28 Oct 2022 15:25:58 +1100 Subject: [PATCH] Move src-slowcord to own repo https://github.com/MaddyUnderStars/slowcord-services --- src-slowcord/README.md | 1 - src-slowcord/bot/.vscode/launch.json | 12 -- src-slowcord/bot/.vscode/tasks.json | 13 -- src-slowcord/bot/package-lock.json | Bin 28273 -> 0 bytes src-slowcord/bot/package.json | 18 --- src-slowcord/bot/src/Bot.ts | 50 ------- src-slowcord/bot/src/commands/index.ts | 36 ----- src-slowcord/bot/src/commands/instance.ts | 56 ------- src-slowcord/bot/src/index.ts | 24 --- src-slowcord/bot/tsconfig.json | 103 ------------- src-slowcord/login/.env.template | 5 - src-slowcord/login/package-lock.json | Bin 98411 -> 0 bytes src-slowcord/login/package.json | 35 ----- src-slowcord/login/public/css/index.css | 113 -------------- src-slowcord/login/public/js/handler.js | 40 ----- src-slowcord/login/public/login.html | 127 ---------------- src-slowcord/login/public/register.html | 88 ----------- src-slowcord/login/src/index.ts | 171 ---------------------- src-slowcord/login/tsconfig.json | 99 ------------- src-slowcord/nginx/fosscord | 54 ------- src-slowcord/nginx/voice | 35 ----- src-slowcord/rules.md | 22 --- src-slowcord/status/.env.template | 6 - src-slowcord/status/package-lock.json | Bin 33113 -> 0 bytes src-slowcord/status/package.json | 31 ---- src-slowcord/status/src/gateway.ts | 99 ------------- src-slowcord/status/src/index.ts | 159 -------------------- src-slowcord/status/tsconfig.json | 99 ------------- src/api/middlewares/Authentication.ts | 2 + src/api/routes/oauth2/callback.ts | 38 +++++ src/api/routes/policies/instance/stats.ts | 21 +++ src/api/util/handlers/Oauth.ts | 83 +++++++++++ src/api/util/index.ts | 3 +- src/util/entities/Config.ts | 12 +- src/util/interfaces/Event.ts | 49 ++++--- 35 files changed, 185 insertions(+), 1519 deletions(-) delete mode 100644 src-slowcord/README.md delete mode 100644 src-slowcord/bot/.vscode/launch.json delete mode 100644 src-slowcord/bot/.vscode/tasks.json delete mode 100644 src-slowcord/bot/package-lock.json delete mode 100644 src-slowcord/bot/package.json delete mode 100644 src-slowcord/bot/src/Bot.ts delete mode 100644 src-slowcord/bot/src/commands/index.ts delete mode 100644 src-slowcord/bot/src/commands/instance.ts delete mode 100644 src-slowcord/bot/src/index.ts delete mode 100644 src-slowcord/bot/tsconfig.json delete mode 100644 src-slowcord/login/.env.template delete mode 100644 src-slowcord/login/package-lock.json delete mode 100644 src-slowcord/login/package.json delete mode 100644 src-slowcord/login/public/css/index.css delete mode 100644 src-slowcord/login/public/js/handler.js delete mode 100644 src-slowcord/login/public/login.html delete mode 100644 src-slowcord/login/public/register.html delete mode 100644 src-slowcord/login/src/index.ts delete mode 100644 src-slowcord/login/tsconfig.json delete mode 100644 src-slowcord/nginx/fosscord delete mode 100644 src-slowcord/nginx/voice delete mode 100644 src-slowcord/rules.md delete mode 100644 src-slowcord/status/.env.template delete mode 100644 src-slowcord/status/package-lock.json delete mode 100644 src-slowcord/status/package.json delete mode 100644 src-slowcord/status/src/gateway.ts delete mode 100644 src-slowcord/status/src/index.ts delete mode 100644 src-slowcord/status/tsconfig.json create mode 100644 src/api/routes/oauth2/callback.ts create mode 100644 src/api/routes/policies/instance/stats.ts create mode 100644 src/api/util/handlers/Oauth.ts diff --git a/src-slowcord/README.md b/src-slowcord/README.md deleted file mode 100644 index ac42117a..00000000 --- a/src-slowcord/README.md +++ /dev/null @@ -1 +0,0 @@ -Additional resources/services for [Slowcord](https://slowcord.maddy.k.vu/login) diff --git a/src-slowcord/bot/.vscode/launch.json b/src-slowcord/bot/.vscode/launch.json deleted file mode 100644 index c1c765a8..00000000 --- a/src-slowcord/bot/.vscode/launch.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "configurations": [ - { - "name": "Slowcord Bot", - "program": "${workspaceFolder}/build/index.js", - "request": "launch", - "skipFiles": ["/**"], - "type": "node", - "preLaunchTask": "npm: build" - } - ] -} diff --git a/src-slowcord/bot/.vscode/tasks.json b/src-slowcord/bot/.vscode/tasks.json deleted file mode 100644 index be345ecd..00000000 --- a/src-slowcord/bot/.vscode/tasks.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "build", - "group": "build", - "problemMatcher": [], - "label": "npm: build", - "detail": "tsc -b" - } - ] -} diff --git a/src-slowcord/bot/package-lock.json b/src-slowcord/bot/package-lock.json deleted file mode 100644 index 7d1c59ed1bf67b73fe2b78be16eb0a9b232fc6b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28273 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 a(hJw0?(+DGjU7ptyrVhL-0;&sfBGK?h2-}D diff --git a/src-slowcord/bot/package.json b/src-slowcord/bot/package.json deleted file mode 100644 index 454f84cb..00000000 --- a/src-slowcord/bot/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "bot", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "build": "tsc -b", - "start": "node build/index.js" - }, - "author": "", - "license": "ISC", - "dependencies": { - "fosscord-server": "file:../..", - "fosscord-gopnik": "^1.0.0", - "mysql": "^2.18.1", - "typescript": "^4.7.4" - } -} diff --git a/src-slowcord/bot/src/Bot.ts b/src-slowcord/bot/src/Bot.ts deleted file mode 100644 index cf3ff09f..00000000 --- a/src-slowcord/bot/src/Bot.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Message } from "discord.js"; -import { Client } from "fosscord-gopnik/build/lib"; // huh? oh well. some bugs in my lib Ig - -import { Command, getCommands } from "./commands/index.js"; - -export default class Bot { - client: Client; - commands: { [key: string]: Command } = {}; - - constructor(client: Client) { - this.client = client; - } - - onReady = async () => { - this.commands = await getCommands(); - - console.log(`Logged in as ${this.client.user!.tag}`); - - this.client.user!.setPresence({ - activities: [ - { - name: "EVERYTHING", - type: "WATCHING", - }, - ], - }); - }; - - onMessageCreate = async (msg: Message) => { - const prefix = process.env.PREFIX as string; - if (msg.author.bot) return; - if (!msg.content || msg.content.indexOf(prefix) === -1) return; - - const content = msg.content.slice(prefix.length).split(" "); - const cmd = content.shift(); - if (!cmd) return; - const args = content; - - const command = this.commands[cmd]; - if (!command) return; - - await command.exec({ - user: msg.author, - member: msg.member, - guild: msg.guild, - message: msg, - args: args, - }); - }; -} diff --git a/src-slowcord/bot/src/commands/index.ts b/src-slowcord/bot/src/commands/index.ts deleted file mode 100644 index 0130b2bc..00000000 --- a/src-slowcord/bot/src/commands/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Message, GuildMember, Guild, User } from "discord.js"; -import fs from "fs"; - -export type CommandContext = { - user: User; - guild: Guild | null; - member: GuildMember | null; - message: Message; - args: string[]; -}; - -export type Command = { - name: string; - exec: (ctx: CommandContext) => any; -}; - -const walk = async (path: string) => { - const files = fs.readdirSync(path); - const out = []; - for (var file of files) { - if (fs.statSync(`${path}/${file}`).isDirectory()) continue; - if (file.indexOf("index") !== -1) continue; - if (file.indexOf(".js") !== file.length - 3) continue; - var imported = (await import(`./${file}`)).default; - out.push(imported); - } - return out; -}; - -export const getCommands = async () => { - const map: { [key: string]: Command } = {}; - for (var cmd of await walk("./build/commands")) { - map[cmd.name] = cmd; - } - return map; -}; diff --git a/src-slowcord/bot/src/commands/instance.ts b/src-slowcord/bot/src/commands/instance.ts deleted file mode 100644 index 170d8f76..00000000 --- a/src-slowcord/bot/src/commands/instance.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Command } from "./index.js"; -import { User, Guild, Message } from "@fosscord/util"; - -const cache: { [key: string]: number } = { - users: 0, - guilds: 0, - messages: 0, - lastChecked: 0, -}; - -export default { - name: "instance", - exec: async ({ message }) => { - if ( - Date.now() > - cache.lastChecked + parseInt(process.env.CACHE_TTL as string) - ) { - cache.users = await User.count(); - cache.guilds = await Guild.count(); - cache.messages = await Message.count(); - cache.lastChecked = Date.now(); - } - - return message.reply({ - embeds: [ - { - title: "Instance Stats", - description: - "For more indepth information, check out https://grafana.understars.dev", - footer: { - text: `Last checked: ${Math.floor( - (Date.now() - cache.lastChecked) / (1000 * 60), - )} minutes ago`, - }, - fields: [ - { - inline: true, - name: "Total Users", - value: cache.users.toString(), - }, - { - inline: true, - name: "Total Guilds", - value: cache.guilds.toString(), - }, - { - inline: true, - name: "Total Messages", - value: cache.messages.toString(), - }, - ], - }, - ], - }); - }, -} as Command; diff --git a/src-slowcord/bot/src/index.ts b/src-slowcord/bot/src/index.ts deleted file mode 100644 index fa97313f..00000000 --- a/src-slowcord/bot/src/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -import "dotenv/config"; -import Fosscord from "fosscord-gopnik"; -import Bot from "./Bot.js"; // huh? -import { initDatabase } from "fosscord-server/src/util"; - -const client = new Fosscord.Client({ - intents: ["GUILD_MESSAGES"], - - http: { - api: process.env.ENDPOINT_API, - cdn: process.env.ENDPOINT_CDN, - invite: process.env.ENDPOINT_INV, - }, -}); - -const bot = new Bot(client); - -client.on("ready", bot.onReady); -client.on("messageCreate", bot.onMessageCreate); - -(async () => { - await initDatabase(); - await client.login(process.env.TOKEN); -})(); diff --git a/src-slowcord/bot/tsconfig.json b/src-slowcord/bot/tsconfig.json deleted file mode 100644 index f055681a..00000000 --- a/src-slowcord/bot/tsconfig.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - - /* Projects */ - // "incremental": true, /* Enable incremental compilation */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "ES6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - "lib": [ - "ES2021" - ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, - // "jsx": "preserve", /* Specify what JSX code is generated. */ - "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */, - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ - // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - - /* Modules */ - "module": "CommonJS" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "resolveJsonModule": true, /* Enable importing .json files */ - // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ - - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - "sourceMap": true /* Create source map files for emitted JavaScript files. */, - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./build" /* Specify an output folder for all emitted files. */, - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ - // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ - "strictPropertyInitialization": false /* Check for class properties that are declared but not set in the constructor. */, - // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ - // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } -} diff --git a/src-slowcord/login/.env.template b/src-slowcord/login/.env.template deleted file mode 100644 index 34f6abeb..00000000 --- a/src-slowcord/login/.env.template +++ /dev/null @@ -1,5 +0,0 @@ -DATABASE=../bundle/database.db -PORT=3010 -DISCORD_CLIENT_ID= -DISCORD_SECRET= -DISCORD_REDIRECT= \ No newline at end of file diff --git a/src-slowcord/login/package-lock.json b/src-slowcord/login/package-lock.json deleted file mode 100644 index 72c8c2572156f0b907de59a3839a852bab0477e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98411 zcmd>nXS3?alHli_U(s|riHDK!R``kS4LKx%95R5kyYIJeRtX7#ggLi+ zCSqoy-@E4=OsXm~D}81DpMU!8hr#L6kAM07hohNi!L-FM&6HK+$Nzx0PLl1Yrh(oi zf98MY@r#-%9CoTEE#o%}=(DzT^i*4N;KQ!%N$4eu6Aqk=U;01)^xJPg;4Sp?)g$4} ztcSwOnkqB=D;cNobqY2}MsG+L3$}vx^5c)vPqKP@XJKrxIm5TU{GCZ{U18v~{McX*FGI#QK*S92x$lg#fdhYd8 z56iFoBp*M47Km2>dqaf9OMrjyGJfFAz}q3Uo)ARgoUY-xoTjmYty(U8{z~{?r53jj zX;J-2{VYUVf)~Gbrmb^sNRGl!@jperzGR9>gMFh=S-XlKNSWc87NMC2}r@ zzf;1rz?|^g50$JM(gmUQ#~%gqXYGcP>pNeH>snvBDvFwP=In4qh}B{=L>~;<(fQ)x zK*A}xu8;f~bA_tIIsJ0fAlg>`_O!iY8ehB$G9g?`ED6xDLvNlX-ZcR(23!4EzCB;# zbY8OEuiIIH^9SpT5vrS_2bkeBm5ZobxII}nZJ7(f0?n`T2R&8yG&gac%U_!7+@6Ye zTiAstMP!J#`EV@ZQ2wk$l)&$q&X?z^TDTU#&+TnX6->d@Ognlnu^h`bFa8%`@QNYC zida^nwK@uCTNpL45WrpZyn8W_;AzArz!lL~VB^tOun53s?F$pd0XEmeZRUTL6YPHu z7g+_SxgPD$qzk7Xt%!d?Fx@C|l`9X&Ene8Sgws2wjJfv;HH-hUK9gd@T7W2{!yW-WX>mAi|fyx#~#*De|@R3<2>#B-TJW zS0lB2r*+#fQlX82}xj_zeHDXtkxCCJFABF1cK+LqQBC z%$<8-TKHLvSCTp!rJK0Bz4uJee#2zD=i9{Lyq@SxlE%Dn{m=s`;$0*}OL$_yTCMzi zlzb`S1UfpV*j{q3Mn(mWTWkcm&R2Y*;jkgA;@(I^@BZ&lfjh+CWzHr*59+F;?)>=t z-5s&m-T+_0F}0I~4H0C-IR8Qrwj`?#$dR9hrSF}ep!y$x5?{9md;yI?JG*ia^6C#T zP9)h@UG!+Aa?51l>rj~cWKUR{`+bi&1H8G?R}0?0S6Pn+8;)s@8U(+Z*Us%(&SZzZ z&X6mgbIrw(vIuKw_odNDu2-z)krwu>(OH_u-jq52?QhpdMzRy0h@?a;hVJpAa~5x2 zuyFhWpW;jQkui{ISYN63F?KRQ1CB7QuTKIr<-rDcjV7+e6xpKPuT2ZGn^k| zD|)T28fv%?|)HFQ!(^sN{^NW1L z8!P;PH}8n{@|b1O{Ep%7wx43N1U5cpvm3yOxiE6SFsL`IwcQUV482=k%KMyO@R?${ zA6&`~Q#rJPi`Uvyf!ZlC3_rH2m7w3+jxJT7zVy0$zC3O-rIF^=x*euFY#e4+})v;5`R$P5Vm!aE~aGQgEd1_{s((ML-^FTela|NHyD{tbl!?!IDy zH<@iBLBPQjBeMpno|oSnf}*-HLgKraP~a@2WeT|Duf#6!E*NLT4yo@HwULm#YS~Yz z{r4CkPRV-B$T3sFmg7_P4Seed z5W%5yi||~E49Aq@#CQ%V_w@Mv>)*iBeMJ!0G*Pq(Y*&de4dE{%$Rk`J2m=2REoOYs zJ87dppB>9Wah$I$R7>*KhFNm!Btui`VZ6U=`+3*9EKkJ}S!$}^J|FEIE!^%{dXhRBd=5nhK_2fT{;5KmIx5j|Z#upFddi4NPjmMQ|{RS1tS(EI3jJpRMXXzMNVc z3O8TTc{k}weX1wmt16}}*h9!6Bc#l&vs zl{=2uC4J->97?=G2zlzI$iNK$>gm~-DMYsTpXdJ@J7M|v+mDyqgUAB}VsH71PspsR zIDwPe3G$F4<@9DBfWt8Ik5+qg>aZUi1$NT#!_+~fkY5Ulmk+>{PJySubGiDt?-=wY z^aqrto`WLNSIzaOp7X$&8P9>RSQN~C_oN7^nO06nmMhu8#Q7Dm%JIC7WqZ~-ziTyy zz(8+?zkFmhf>x*zU3E$*L08#Ome?}*h8t8``^mg-Z}RyG5u7HhUbe=}L8C5S+in|c zgIK!r(P%ev>$`1@AZME>OwrkPbRG#BQ^^fkqRO}AN}ki@VnOt!ZF_rBTi#UPUiyQ& zHr?CBecK;ga;5&^P_8bsit*1c4B!oRC$kmP@z_OCYPr+itpxSS+$p)vAoVz+Qg|j8Yz-;zU&U~ zu&ZNsM%-NZ5WRri4U<$I^s@hr=X^~I$3$E{tQ}0QJ*Po(SxSx#rtx5O)5`)d%b_&*wOCF{e+wLr!R}Q$TLO3wAw7k_Cy=Q>GsT!R&7fadZY^ zpph(yUjU9pn0Sqctx*!rg%N!ebG4nyE>}ZGF!uhGLXO{0^G>o;!EL2y;V^f!u)#369S z(>Vi@-(Ml~he_%rPrs7aSp^h#W)$Ys7?1bd8Z9%$u>TbVOs4mm?JWMMk~&XmiFqqU z$^@%@8YDt&idBUreiVkNNcv>1Q7y})db9O-y&udj!Xd|KgW0-VEmed;pEkgx8q{T> zC>NCZb}QRCsU#Fm)YM}2fy7LTM%iDOm7Pm*r$(PB?{AtSlaQ~@#3we)6D$2vMZbQwSd@edqZuwIu$F&@tCh!Vow_`XrNiFW?!7_*EoWd9Umt+ zlK4qb>0|t0Ul5ok z!xndrQtJ`>$z;v1^DbSx)C8?ind@FzmW$H`zp$qpj_`B+ac6??@`NWKpL+%$P?6vl zUqUg?)RFy_oj-s@ICyyJBWyHP;z*D5bH{KtX6@4N3X9&TJdj#_u}96wExE5PiC+2a zAFGB!=$i>`b^ATOv0b~{eLG+3sQpT?BrIy_)N19z&>l*Q?kzT*t;j`5!$J&u5jgu2 z=UHtDsx){g_k;5(abba55j^8N@8JdSy-p8sw$1rpJB@RprZ~mb@5*hW0vxW-7 zfz3=@4}$!+mk$Pl-$D8Pf(QL;l{l(1|CVuq1} z_1ljyR1JCmM6IdKouQsh#0w}Si(*mq?n@1WMkH+GR&V7Q7G#frcdymV1wgz`pQEtldZSkp#MF!;5_ z$SbF;%;%LcD@bx@sSlK1cUE2Oj)$Vkw5U3@FRSdD?0b#*ZbY9-uGm}Ag-KASx=Y3t z2F=QDR6F0Sl?UTGH1o1)daG_o(=&Q6&c(+ciR0^nVxEn##^+AdK%ImRqQT;>H%9K> zlr=NF5C9dAQOFP^jj@yLF8~*pu_w~!n(ci>g!}PF7`(h5@Vn@52K>n2rd#W2~x_E3n)WQjH8C-ap7|k`vC~ovLn1Ez(QE= z6jf8os;hYXPr=j)$Aao!xVJ!Pd$@|ghgf+cFCqp{Z8X8sA4>}i3<(ST%SR?F-!*l& z#gzMPOEl%fK&&kt>%;_yT7PHxep_R!8)muHD)aWF(HWE-qdPV(lB1lL^2C*COoTslGbefmHY(l~ z2OrhO{$TOL!I@Fy;d>EtzZ~v(phxkvZ`PrLP|muAWFCB(K0tM6Q5sYS(ZMGMH0{K&*4M z>_0wu+0a9*WIY$N)4K!d`owN79W1L=*mcjdld-KYMQN*^sxZ0mP%wpN6I`jRC4VERY>O7A;L|&4pf^>IObb%uaJ)qnp zlOx-<%r=u8ZU=X9yd9V*h+E4bkUmzXZz8|Z!jTh{wPK{`qGF6ph5AAYfi?U_5TRnN ztfwM8MQrr%^VC~OPX-UiHZz;xd`Ri#Ex8OvP1^1j_i8(EsZM)S9WT30rymt7)v**zDjfHjmEPVG5q`95&YM~CS(vZEMP>amHK zRW_AhADBNK5xT#ilUg3a%2noks(2F+F)zdyfUsxqE(TPhil^dM>e|A}73Ho>ox0R| zVFnOiNLLd}v->S->N23GZy zy9KjfVDn|lBkmxP!Vui@zo96>I1RS-RrqRZoCg(LZ#n3-jF6DqYvb#C>F3`(%0~vu zmUxnG?q8(1lEt1Mp8W(wpm^f1FAVIB)j4GMn?P8N#`U~(u6H2dH@sLI=5&@RfA5o{ zcJbm$<}sj3rDfA3W)s=4Nuu3$bE;5Od-GsgrM==@9FirLI~&V|-li$!<2>0uy2&Gj zZgd7RGT)N$U6Aha8c;HC1{@S$X8rV>Meq>HueX!H%13bCAe^2zIL|zj^I~~J zthU30YS#AZFuyHd_MML2E3NhYc6=l?LR<$$%`P}IqgpX~ejz{etRt(COhGSpIuq8a zvPyR{?b*HJ8>cc`SKY_q{{ZVHDn@%jJ4pH7TO)T+QY1w{zv*?}00M4re*ks?)EnfM zcFjYjc6OAZ7!0j~-N{qOmEEIDs;M0ZN^{Z4ja9EJFLJqABcH3m<+s+LN^NhTPqB+wiW6kffQ){%( z9a(8}5`3NT=K0>Gzz-p-K5$u|-0A~wd12{(-#2YyRQ8pVMQqhJY0||Oy&1C1Q}XuO{@aho6gZ?2;lC(1c%R0F_ikxh)F>-VyWR&Bz_pA62)EB%eRuTm z*jbNSZH4}5>`g~6-#KSEyBYTxi2R%nQo2~3T~&1W^f&VcSoILwi-xZzDOad3(RVIY3WtK6|J*>H0Qvd*|c&$Ukw!ca^AXj7q> zVwCuW$3>KRm0HGEfv&-QOzn7ANVFpF6c;63laOR|V+NY9h1cgr5pNEzC**JMW#_B! zZyv$JVhIghjIu&P_;A2`*OpSSRTMgiUxof?s89>8dLga=PE4?cBe}3Z*F?Nz;ydNqJ^NrGT(Y3@|zUJT1(|^MshN}1IEQR@+EABqZ=Im8n_o3~Vi%Q)v%&>)A3be)f zP$&KjbolO1T_Q37BC!7}6oHv?FHP{b_Jw>Yo_hlRS*;~yPUcV}*eoYQMJuA0z z65#vTR{KPwy>xj|cOo1eOAs!FPZSu7@49`1ckWKqk3YiVh|kU|=7-39g|B4Xor0yq zi4k!HPio1i?kWmyWv=)sD}n_b2Uwpy__1qb`1qtF9X4HzPMd)`U_I|E6X~anUBvn- zo00#_F7E0aQjbPnM1;WP#-f~bMu(q7r-4_*&20`^UBZ;s59wO)uR5LOSxTp*m_=L_*fBYQedO!xBPVknwggg;5Y4Wp*QX&B3=5Em zf1=K_ASzz7X0F_$;7Vk9eQ=uI`k2dk%*-(sVr6{t$hBnflGpV{v)*O1+RIaZ;xWpc zENS(Vv)UbZb=^2?-i{ofhx?#d>+E-fi4fjy4Ot+YHN#42%$SH@im3eWzOzy)6a7bM z5n-suU4w~V8LEX*OPYv5Q#dfaA?@@0jsD^@!4E`=?=bIUf^E4V18>(SF zP%6HY-%RMoo1KZ5`H?00zAorm!A7QVlbpoV>lW9JU(i>QD+G-z%IC2V4Y;KLz^m>m0cs`JJ1a2CC=6d6A8siL`dj0idJ zSJ**yI8Jz3oFbzl-kqm?Ww)Ke7e&8m2qZuv?zlZ5ymtD|5~wwN#c^hZ-DK&Ew);{A z?m{p4{!Sm{b8flOTKaodasBOf0CyU;t$N*Nn4M|)6%$Lt}!R<{{r(RO$hOyQP z8*_3Re=}MY9@x|w!IC(n?O!1s5@-FjB?lIG=;&sv$9qZg{Z+qtc+$uI6()Qylh6ik zDk!yqMAYC@(UgD)Jec_FqXcDjwySNb#ZhA>4UJ1)W`cUP*VU)>rsFm@tA(XWR*S1a zIPiRSb(!8Sn7l%$h?|Hf!hoW$iFf`SH+shDT zK`J4I2c&wxc^0!kBZQ!C;}1`S(~0=|wJjuY_T-=m3#Bp}uV(#9^HiwJCa$P#l!YT{ z9N|f2V&4z;lDs^vTgPFcJD{N(WutA>dfT2t%GHWsl_|#~7=w?tUV^!>8+1iXrGlPA88O1l$U0N}>z;g@4xCYUxr;GG%;Dp6?bV?prJ z?Z8C6h6=C!%Tvg~zWh~!edv2Uf{oZG@g!g!*v1>yIphOzBp+AvcAes+?rdqDc1x2l z?FQw7INx!S;%jn#Q(Bx@pFNF_#3t7m`x9HX7IwYT@wMY=Q9X6HZD;1Kb;oiJ%l!Q2 z;XSaG8-{*0)_YK&L|d@LBId}y-L18si@HD z^GNT*6~zCb1}3R9au=}tZ+i_Mp#_4%cg=rOER8Qoe_tfs!M)0)yVpLteJwIVeQ(XD zjBE~uL9?(tFLF(y$+H!2Hppu${nF~r^`l;C<|<4c`k(G8r>0SywiT#4JyPJ1k_3mf-*Gd8nT&3~MPxkJc*BN3C0_y0`N~|E2 z%U9SOCkq2@ zV79X&QR>P&Z7BB#W9Kw!+3jZUhKg*{;o778A-sFGIm-&$QoKHnaTFniI23M(I4KdW z=(0@&F(dD-KAAZJ^-$k4qE!oF-U6JXQmWVLZ{pFH$!4K?)N$CD@+B=#NrFzzDQ_Pr zx{@18Jz-TlbJg0!tOsT5B$k4SJSwkxOEO>5d5SH}$@+QJt#ge^zBjT5)0Oh{=sw#x z2L({*u4P7O49(Pw41xq2Z+%N%2m)Lj^pbvPw34RbL>8{+ggTdSf?kT8i3Hfk=O7z8 zB2M-@IBEG#*ap6?mvdguX*%r6Z`F!EsaA^M zh3E=lV=?m1q6;d`A&d>O>Cv&QGL2f}Xi}y1f!fp@IVV|1Qun)p*x}j+50%E_%PDYZ zSKJ(@3twwg2GD)=B-{3WQY_4=%~?>Pz<$wvYSBGmX-B$bUSdoHAwOp$fQ7LDKXH`% z9gEC5m*K#wX-2=(?#v9iHf5AqbI5P%!qPIRnxnIA;aJ=ismoqoE?0A9UpgKK{Cofk zn05BmMsC-glC;;P+g&IxaQvy1=qdGJ)?{NK*&ZWxm=fJGKE*-|4=@q`j@uuFo0o4*qOu>)?DZdXYE+5#f!nwZ8nKeclb)=F#$oc(( zF6Mg#be!Fh4oB8o%KE65bLR3q9uiXfc1;V&F{#V>~RDhE(%>SylHPLc7ph*>0FEX>s<-ozDD5 ztGgBo@n-S3tnjZlEfg@;!g@jlOs?#va9{y^7gZ^^5sxRI^@RbyL0~R0t#iw-v_=O* zKToERBGk)TeY+;4<~U$a>}VvgeZ4F#&-25$5ts*;-mM+3HYgN(M7ujvE;EO_1cwQ& zz*QoPE-+Ae71uUA2-8;qg8LT5SJ4u8<$%JVxRDfCv#1}ymA!uZfuq4w59&Y)z4eWT%Bc;%2-i}W^zpHTcT9Q+#{lj35UsFLrKj!E$-Z&a#rSKEQQK0({T zZ+29QlY;ky0tnH;s~^O;;#)M6#q@VoYSH7>8G(|WKiF2}+kKN)P^kQ>cOER`K5~juGD(h z+u2R?QXaH=YX8_RObhCHJQ(+FP49B!mdZ}qsz_G%oW@XopYqB`5%RS#9^))v;k4293rq#}*+^^3G zv&9aYflD?vGiAES6H3c<8l<<|?r1s~Zfjh9sXL8xHOH)+?pkYVtG|NYpVl_RMXS$F zTB3t#2J&z7-oA_c2yPPp(Q7~g)D-%)&wTN^$BNJ$yZPE|0uvKzvZ$8$+)N#vTFgc& z_c}RQ9-SJ;_R*TI1=}l5gqc3xdYwjp)hFkdT`ea}bDiOGR1&G6L=Co+%73h|`-}q7 zam_$~e0o0((8UJ|15M%{zkqrFT|a{%f0#}S&AHkbYV|@(C(6PmS7TQUJ*rwk0Bs*A zTN{?wmt%f&gjjQVJN0YMqEhClN|B*!FvE50@HVw6s}strL7$@azqTdQ@4E_%hh*$H-9sa-iJ2iBXc za>tV;R`$%SqgTYiWxQV;NV-#R_6X%N*iLD4KX5n5`5Yx|S<0xWQ(_=q-oY8pmeW2qwN#93H#p z?YJhK%T>R7tZ$X^2nJ{H_Qu~x#W`pvx2ul5`Fg21ZO*GIf~_cL)@k81)e{P2-1kqR z0-cNq6}Jl^|AuU}RL6pU$7TqxLI0^{2ruF-&_@FGzQBg*3miW64YQ zD1*dhJ^U4P{V%=&kxG`}k0i1#FtY>}hhIfS-Lc;XlT0)dckQ_!fbeu+fTTlfC=90p zA~GIoa2pvA+dyzvSW)pnpYY=HT|<~V-4{_4frU3hSqvooTm?cb9lXU4&OYK9^tgER z?BmEMSVKyvhB1mz1bnDp9>D^mKECu(tw_GTvQFjvhJ~==nj29BQ}1tzr`?R#wDoFP zxSV!%!tD1Lu&x#ZzL(er6P0#sM|O`Gw)9{~pNM!xK7dagl_%KL*1 z9UXSty(X#RepH55c;q^#Pnc<;)ysP)a#^gI%|VlQ+7h(c4^x@|HY9-J&155L~CtL)r`v z5d4d}5R^X(iN9htEEhk}VfO+gmY^xIfl`Fu^an#=NULGF{Lyf5;?y_=Wr!oz#5ut+ zD>2V>XS>{-m=;zIXF!j98PwR~=(tD67xZm?Lcm?^6Vsdb^Cy+j*~LX&^yhGMcIB5( zZq7dSyO&?%xrgz2m>m+r^IhkQ1XD%FIJAReri8nl$cPdS(csC?Ly>=u@>qAKD4bBG zp9Wcw8pc+O<>FgV@2WrM{GO`VyWLTcq=6;O*7m$|>eolr=6N@fx(#_)p((X-(EEdB zg{OySt1WK^P$;;sHx~}wTC_TZ`3r*muY_QPs}Aw%ps|Mn2X{ zV$DFlS}rdKvy0Z^$u61CF`Y(xxOON`opu7Dk73m~+*i zQ%iPH3|d8JrF)dKRl1I}sV>*K_6&l$6jNcmTyNAe*Smv8Yy6$%e*Kn z`&>g<+@#$L?-IB#4xqop7|fHh!pUGMl%bqPtP?T=B`N>x!2|oXiBtD2?^4T3Oj*pX zH^}DNL|=5&cM_NZYtPV7et}6SQFs|-y;k(6mWh&WQE=l!I~;*RdyK1w zTN?)BvUnmpRij)b+VsFGCi>rJMrG}M?k zHjQ$_q^0&!;;N#4>hJ}<)*kpIU0aokzU1#F)O6b1wwV!^Th9ckM|-UX6&&rH+_$=Q zT^mUJ(DDywVt7+T-!X0PXKg2}jL+CFikF6b`YQ+S(~8nWSJ@QNP=(vouE{=gf8qdT z^ftgs5@?=ixQ5jzmwthC4Vk1dIhP*AF0xb<=9$X&+qmUIpL}n-#*Ug zj=tV;U3F*~cDbdslwEJ^4fZv5S1WHP%T|3M*{vOYs8)v)eIivB&Cf1CyqDp4L&JQS0+YclC3fX&&l_qEsyJY0;DvqWBau zp*YIc5K&KgEb9<1u6`woy+lQ;z(DZMhblOdfltYC@xRcWt}I?f&%gTcj|bq@9+F*Q zq2oDPEB-iC99y^RV_-<2>tdft^0(K+a0l)bGbJZTCwG8m#uV>o#$=PjK}`?^Xliaq zVLxSbd_QeI6Zf$Fb^Y_cZI{j6wHZ&L02NV0@+Q*`eXV_7x^Rh++^Od#Msz1Jf4dBr zjqqr!^ZgKWTofO7n}W{vu^9wB1@WtAGsbTnn-SeUJu>gC)^rp!wfiDWF!`pT_5c;+ z*uyIjMn-|A*Jf>FsdoIzpfAmXk~uOC!l0Mamh6B!St=u~DMEx{_nm6cTvZmANde4d zxMz5pw;N=sc=4Ehhb@ZITt4*8_1f3hM_*UF;;kMgn`p@nUAQU2EsTQ$fB##QP-oLH zn-KaBSApO`lX>XzZ`l&e{>FXgac9Pl#lma$yh_Xzb*=(5JeD8&7m;!al}ZTV4J~Se zgE~L&7Yb$1%jI&*rEB(loon3zY}Z}ZyagB@^liACSEu=9m3o{9N?{8{7rq(Y41pmQR&|@(;RMLL zN|)aD&>L=I|W2 z`-5Bv@@9uXX*ce1jhH*u&-dX%*l=8+0S?E#Wr=10#ik@m={-)ANs#^pDUop%Sz^x) zlOf(`-kvwxdJH!H;xja(_-M#{3{3lb(p{uEsBz$G!84Em&NlM`WF?j|L zJnseb;38%Kyp}F!X{ z=F(w$)NK%CYX7K^D`KrrZGi+xgn-1K5X(pB^|d=#D=GbaN2%JA<5VkL)}Iz%n+a-Vw(j5T zf^WMZ$bpUd7&5>}M?qn5n83th?g?tq)$GWcNDg#G!@IxfoZxHT2$}f0HwN$qi$QCv zbd>FEQ=437wl^EjDu-4PC}zI75YNALzoMJUhQ_yP9xVB zaii5MhM~22etwz+wN_QWxh9!d%$5qc@f14G@gy`*773<6_{1YVK8|&udOARV6ruYr zP2M$@1?t4%r%!qQ@fvLaijLB@pbUaA%OD%WWo1Bc%rqUA*l1uLMZh7pD9VVDe0!KQu%7v{4BPn)F zcS5Vqd424jI;-}wGnUu6N}D(}M?Q)KG+wzu=qjU}gjm|Swp{m|9x)Noy>nDr9VU}%^tw%wN4()uX1$Lr>as=D*s zo-dvb#LVaVt4V$`@B1rPAF#tbpX0>EoIddmIia~u;c3+CiMlvysw)+<6b7mc`eu_p zCxnK?Q1~0J=X%$!Z&!dx6+G+ng%){a7~$AmPj=8Nao|pt<5kZtxAjG^x$H`-T>dC& zUU|5(XE~-mrAe{eUDRz_a~pQRwl1yltX-WD-NVtpaWfQSb`5aCG>ydrQem&}D$)P0 za~5x2@R0|(Eqy^vEfz;%a2#_kDj!F4pAxrlB875&KUn}y-UVtSJ=V&+^qZ{xuKv8d zIxP|1u8X-Y^Uarr;5%o25eqX2QANwUVhWws-~Jyyvrm{P?Ddk8h2Xw^TcrUg#6Iu? zZZE*s-zctH1*X3TK3P}&%V{#|9tJD3?QxZhISqozewy#pJEcb6UiHliyQLOz3sA5Z zYMrsqPJYp;&TM|A%g5qiI3M%Mq}$>7hIHed2TX(_E8F0BxC;1<(w~=wKZ)o;3ctvz z{Sz6hH_x@9pfr(>NIf0-;omjV?~)vd&UY_BZXVgUuT2%@Fk4p_&sjRhz=)3FKtq+=-lVCd*vB`IQ))bu@!{qRJ-FgM;Z zc?>s2BV>C<$Lkw33ISdz6#jvW*58S;O|iP1upQxeVC<&F7}MIxW7qo8^G;=RJ?>j= zX-;u%+b){Lwot2UOOEO_b_;ggH26!qy=8Jl9=exQ`u4-@szsiiej z>Wrqff}m7d6m+3gb_9K13>rddDKD*qCo|=0KG&KWRjJOfzBzUCZeYAaqo9~)Bh1<& zp&WB~Vy-Oa>bo}|G)CfU=$%As5u{75Cn3D5jbR~MBo0si@^$mq2?O_j091;eXbllL zGedSSPG(&6k!@7Cc8P+0rXC4sinje}=oNuNECfHGgFbxy4GWEmtD)l^mlUPVi}|L# z9`W@4Qfkv@%{&)Rlx>&vrf{Mx+t{5IHc#3I*=NN4WYpM*HQufato4%2(Ylf+cOBzc zXp6Fq4D%;Dg-P^KFqpMjl$9VOBRmtq*y!tjMX{YYv=0vZwg}DXYkWb2msn^TKGB1jpcR>xyE)d+V`JVs)D5`>4LcOW>;)}; z-am6=dz)kD?q&2#rs8$=j^>5eOhc)FDUi(}_g_e%6n+1jerf{Z4V`E~I2ZA*0wFM0 zc5Tdam-?VpY>g+o{e(SU+|th2sw-Z*bh@&%Iwu#e{E{ozr?D%ia}2rK)!_ zpZ;AM-jxI)GTyy_D_!4FlAg56N77sS%%x{F?Sau0NCQMxQ66(t3ueX$^{(12%sIAM zuPmEAa?xuIIk_2h59^V$*z8)Q$n^nIIdX+dG`lXth50Vj;N2b<*`YimaB7NO523DYo z8nntY;Fh|hLhVTQ^KXj$L#dnw3@n&_5$B)Y$>u_@ZWM!ReMZ^)ewEd$raf!IkWyaI zh}LmXac2{;y)AXg=3ZoSG&daRn@gkPuf6`DTB=E&FkzHa!@LY3i?AE>)x(9uZhW>p zJu94hmcPPMoD?mP5&TWZ_688)Acp?Ybw-Dy%N4`3E(hvV>}-nV+&*ZWH(cKCvwnU( ztM=H-c5;>ncExw{-A16aPimbc=8JZ3ptH-P0~Z8pb>q}+u4!-F8Cdov(abvAK)700 zKmL(0r=UAQ7O$Yz90(yVPFB>_Ace|b&`cN>#v*h|_(&Ty2HoOZBj>B)^Y{N}P+mbWwdfsNz>WI_Rt|a?Sre@RhlJF;&_U=46%uMl2%j$5k zSkEtz5V^ptmi+m0DHqw?NM3ZfNyRS?+geM17kCIGONop0NVgPF69xQF5&ibkP>64! zWuWid=2i#{p$^aB`A9WuCDtNZGY49}*3JWpJ}nC{yKQPvMR9nT?6-tt)z$}DnbZ8T z*4HL1d09ByqE{ih({bs1aRsJP;$>?(nF+Jvw0V+(2_9aYEfa4ZWNO2|aGCB34R(C} z?V}5I#k1H}#jSrVPa64ZX+5CX^4uD;vwHEoU)QznY6zq73Wu3+B1$A{6eN9`7ky#6 zDtX)WK-!=CCm8&)U^!`p{s= z0u5-v!tk18!3U%E#*yP%Opz_xeHhd&OFprxyY52kvZB}OxHb7utxhQiZIzy zo*ROnZd#7wYW=x?xXeb~2EB#a1a4b5czar!y8U*d0gNpjJr%YTu>s0EyKs5=3px=B z@M0v~uMwFK#s@@GH1L-bBTcSZo2dC#n7@u&fxPWb6b9?A%eWO@V|9JCXOrcme?09@ zbf28cI3SP{!c>Y@in#$^yjqlKUnun+EgfCKf<`H)uxl6AyjrbsJ3WkB*xB#961FR(3R$W{`>L^^9EPQSE!wEz0mY4EA=NEjYSndaxvcpsk zt>EId_EeyDN({q~t!gFcx3;58)u%7LE}t)t+e~Ssxiz@H)*UtuGp$4}#gi}+`PiX{ zho(3IUb`80n3|!jh*b79MfR8|`#bCwI^+|(n4gkZ!*Ppmo}w5a;0)r67{m=%nV72f z+vQm+-(F5izDNf%gXoqTqn3ARxyL0BbAqc>r93ay#@#kCYAaknZ|x`R%2sG;r~Zbo z=REDS>=y%fComz`EvSB%19NWBAK3`cCTSBq6iZH30r!c|< z1jrCeH(%~UCQQKvyvEPK=zZrzlk8$gH044&Xt#WBN0zx+jdg4DmB#1RCw{wLS*=TT z(|0PvK``tPjizK;r<`9q1$H1GcK!i+y|2a^>lO8_vM=PAsbJp>oJ<2WjoydQaNJ8T zB^e&jnlWDfFG1@gTtMr!=KzrC4a3g(pm)+nfj&Eyh2l70Td0=gtqrr})=37syBx;* z3pB=cz02}cERh9`DrsexT$QbTDQEYNwUc$wiNjf)Mt6_jBaqAYQj(?L=$xWh*jVlfe<&L%347jKm1Vdg}^{6hrfJeNPq~d5nXjk zC_z`*P?p#-_=X!)T6-u-vp4ztga}R(Rxev)=Agm-|F+#W)&{Y3=cCbX?6vMR zh2BIN>Zi8t4In}>uEa&qKk8pM+m6m7L1QYpAxl*GmR!kmx?C)XzO-#`FKWx1>f1|y zP}in=ySQ)rgG;W|KOD-{#kkTcK;LqvJ8ha!Kj3X?){v-K8|IZ97-)24;umm*)4MFf)+h<* z!iYYKxf)F5TtXIKF!uhGV>pwqV*;a{NgM@l{y3+BU=v+Q*=Wqc2Qu6p{H|D>mhxG%mw!q5atlp zuXjWL8=t`kD?L1A*cOeIfOdNvQkdMKllCp$`? znO3Xa(XqygIYX=zg5%6*HM`c(TlMNiqkGh;H?%k37FmKOaR%h6IpKi37u=a77F=+% z5?#p&6Ds)aFdy)MWL9CL{#2MvL)IuKxhi?r%2@MpDv*lv5!Ok;H_R*vH_U$exXHeAqv z`a3ffg86)0MV}1mB})80-YN!$wuyiF=sK{rkxK1LWjfCd`)$7E)N|XMA`vTB+T|PS zxi!}M#QM;%#hs(ndc=M*S@Y{WG*-FP1g%h+>t0!wi_-4`9)@A71(h0Zo-S(j)!cF`SKAyY#!z)nrs2NUgruqh{om+}D;wuYC58RYM{4 z&4jkP{T|=guHEgvoiBA%XfD1aENbc0YURSv9zw&mTYe-ezKfYU5?M z_nRbwfhRtU?B!fHdnj}m4~{?2a~cP2I>j%YgIO6_mKM%xUc(|ET3Yu&0sZ$cfI@@x z<{PmEt&ya~I6ogQsfscp>pH)7`X!$`E-LO`?P&aE*4mD(P9Clm=9<#F#Lw#7I$t*~ zP)>URWLq<9b)IsQa~CoeF;yn3dJ~d+=6J(s zBHhsPGFh#7J2Mcuj=bs%8-}OIV_Ur`$qe>+Ja=KHB36mONYI4~P9?q-28~klUKz83BzKnjK1{^r_^Ey%k-U1a+#rWL#m; ztn5a$b8MYH+NRia%Q&=AA_k|*9xxug7bj*ACu1QT$IgDK2LGHRHn2W=D1SmZ>cA6?H;V2v=9pY7|Qb*T)-VJw;KONrrc(}8D zEi_J4grj{S%-l<$WEYS0Q9vpw)^d-+9$It=E)ph*CLjsaKWhT=@cifoN9y4T$^Y>& z#K6!g#J_xG&+uJScUw%k-?l_kJ`BX#(y>lVaH#cnmhZPUwz^@KTdgv0Pa2&;*)h6f z;{xrD&P#dXO4Ax&qJ2@zSxdg_(_~9HHCOVTL3eNEXY3Pp8YB6m{Cxr<+U(7XfE^>W zz43iSwOQ+Mb2`_b)rTvkrP%E;-IQ0`iz%IkLV2zo#{BR&Vx8rJDoj8`Z3%Wb-v@rX z&M@T0bL2}~U{`Z`-B7H2b8?=NH?f}f46h>B)J*#;>Wh{Uy+Z66rJ6ppsbEUj4JJZG z@^7r<-j(|t)yDo{@x#HG=nSZ;pVO4mF;9%i;g;DKW@~Cq^z|WE%*nl0G03gXU2+?= zI=*u{cG_%FpHO;WOoW5A*3YETtqHxoKSMd>SS8<rYb`B^HV1&!``3LA>KgCE_bK z?^HU$+NYA}oc-yju``vn71T^>!x!5@k+m1CW1~~H=bqA@RXC{I;WvF_c{vyOCNrFA zd#+xg*Bx%Xt)88ZXo}2V=nk^HFdVF1=NMYV3Q&lH^A;O;d_5Tf^dNf9^1g zWuNNI_bWD7mbj{OF9WV7u&6qg>8MC-f*wg>1WgURYQqdg{csyLY_a$tPVY_a)B}*3 z!MTR$Orn(Yvz6dN+T;h{PvBG=K7_pPm}sw!pF%V za1>5OF4jF=lOxYkKoQEmd5&UuaB||`u?za{tngxCKvk-qx~k8IlwRJF%V5-`?QU_e zwgZ>yv^Ul9vfFe@`QG$Mbn1g0?~i(L32f2g4)msE4Tsz)Kk&<@PBh46m&jdqcW345 z`lYrR8U(Riy*Y!aPlBl*VlbjcvW_tIX$1FbOnqu-Bq|dz0%Q2tjRUc7$v?oN5?)5)TO57l?# zmO7v@@fYqv@s1OR?0ypntI@cgm(KMLc&5XPwP8+Y8RppeO?n zHf)k;x80m76xH55m{w`8I2VUxiRI45a-p|r3fVC+8k2n!Q~O1yF5yw)&xW(WQXd8W zx>eD9iW?Y#Dgr!&nCq{g;SroS<{gYh;XLz9&Wq&@vDyv~s#)8s!~C{<*>^g6ue8?p z+wqaq2yq=0HM`)UZD5Xnd6HsDdE$hCa?3-GBlvZ+`$b0oVogHN;21Bc0 zck#s`MUJUvkQ8ib0Xv@J$gI!@~@E z0@J`%Q2!;gpx6FKP9e3!ps#F)^UdCrVIZZ|8?`H=ZEq!bLZQ_<5J%_8&S$gcc&!fh z(v%cQ!V~R9TR9Fd3%RbH`=f1M*cH4ZXO!Cmk1af9(A#0QZHNNkiocBgfBSNKGzSB1 z{|Xrk{{%;6)&v)LU7J~>e&aGHnlpVe*8DCzwMP5gk(D+l!Pg0Ip6^`>{19>p1DEy5 ztv>LU7nbh#ebXjJWnVd2#8z#SCS7dNn<2}5uzN?~;JUlw>Y4W-kubxhIag8da_EY5 z3Qr`o#!V`ZxVA9$NwD(JN1us@Te(r#ST-*A;~qlw5H^MXu1EgIeRLY$`~U5ITa&uV zvgh+YpW?*-)#&8~MVY6K0^U&Zf}#(50t5sF6%Y~Poc-A+t586pTYEjt#GF`{?iMJi ztgOtey!O8nHJw>3RGM7j{;q z#NVEHqO_+aiZ4Ed-Jfr8mrZDC3e7)MEB2VhhEFU){^+1-ehJEq3WTBCfrkORPA+z+ zA=XG1z}7CtNyVRoqZ_{Nu`)lo(!Ylh&b2rK!Y3__{_zJqWoh%5KLDAKz_b42PqBag zsnrM~VItRJ>6wC`{>dQJqjHTWJmWhBU-AzTFG581F=c=fh8Mh?5HFo{#7$4+&mc%a zupmQ2bpJQOf~PWV%wq}V?^V=jPKfLv*06++_iJ3faqsD#+l$B}n${h@sFk?FL_OKs z4P^kv2h$fXFx00ORa3_ms;?P+`ZG`F-X=q&f+JAzR{FcU=I?Rkw=0(hb6^$nhcsv_ zWaH!FPZj6rq?n|v=1XD21 zfBp4W`LDmemDc~11MkaI58!GvaZUn(xE;M*6RiHne)uPBBB(RMg=P3UN*&K%zCbAI z(KGkujyOG6ww*K7eBmJw7JDLN?peCZ)(zu^um6h6fbP5Xe)%q~lR5&#%SqmRl22|{ zTSx77`9e9;Ur^4YKn})T20$7{M&;Z`-Fw*4y@P@%{9;d1F>?=WmCFf6!Z)=*^&}C^ z`%N}M=2wF%lUp?yrccs5!bw2tfAUa5y~ zIeA|g65>9U>?*|rL8+G;Lob3|0CRo$o*)jjp!uZ}2>pY3kRhi|IbFaevd)jRmM2=t zd)&?UUoCthxGx=i_=R?lj5CnYi)U8gnI8ZSIQhyKPDo_s*3dN9JS7WN`Es|=lI$^w zVh%~Q`Qz{moRdjF{>LBfX6j!Gpi-WW*mwZOf-UeEH7%n+@t)NB`Ntn!_AXx;T&avM zK$|a#i^I1iVJAe5FCxKL4-0c^XVvASnNnCxm#qJQU_Xjfj0PRfR3VZ?HJ<%d@`ax{7;fr+;n#t7g ze#Z9P7hW(AHisRP04(DSD<*q7LE=x2P7h16K-+*7mHJDbVb^kZqg{PxkWU?LnGxZj zmH7+KT8Pv?pEMy6X*U5_-+5_9F1Jp_vpT-4typ#3Ax=JH4MyX>CvSVT<%Q-=pR$*A zUT}Nc1{7en4h=aV2d#auTdmIK;?$U}4Z9y*(*nV~_I?D5@iG*_cj(?xm9`P|GqifVIm^{bM0R5ZWuk7tA1dbQt8 z6~X6>MYV3xS8t^|I&B{V%h#)uV6=}2s<+p9VH+3PV2My*@5ZTzm|qY-V|;^ z@#VFw6EaY9Zv!^jL-c;kq%aiXQTXwNAAcj%j@+yg@n^BN?#Q!SaOw=MJSko~z1n~a zxn=(vEO@W4*Q&JNvqs*5t{TQdJ(PHBJ-AG)^@X~U>eY*wTDv=Q+I-2J0;IzaMM}>y z>*Z*eOJd0+^B7=+#Rgr%tw=yVk}BiVO~PZSNcp}P8G96a2r^xrljVAiknK>0o9NZ~~T^em>8SdxC zCERRyNQvDrH0^SnemaMf#lAACGy=AE83?9F*UiQ8C|R}jNw`kld-`IY&T%G|F0s%k z5JTVXlV`4f-WlI~MPfCeyHkOayF23(`E;vfMuY{){Pj`Ttu@oBb&D9cXWHm^tL(Ul zZVmeO6j1Olo%KpQTiThCDe!3q!3EmOZ$u8D(9FhdPLs7p)GqglCVO$cU_M`v6X_Pn za)0m?xx{uiWB?jqGJ}zIyqMc>nDN(!P|?tc2A9kE>*X7PJKvi|TiF#3)>br{v&m{U zY<8}-=1jP##@Y})&63N$)+q0X(O%mvuM*>oYJHvs^RujC5MV#5W+K3{eR-1$Bps8d@8VyRQ^DD$R2<15z6zA^oU?byvusmWCUKWI;Slts$cW=qm6 zFB#A-U^l9DwAEbdbtkG+TVI0IV#x8#pa0o}AM|B{&61klh?d7W z@?$eE9T9D%^e=E}Ah*xYP9F}iNU!UQM{`QKQz3=LoKgW$xoH}*4?vD(X52ZHCt=Uf z*nsZq2}~5Js-UYn(vffEQ{|a`Df!H zO+hIVKqz?;aN)lj_ooz)m!RM?Mt5#u!1ebqmOfpW%!sfsnZIym(!1_y16vwx$iTlc zHgEP=+oHll2~Y=!?r84W3@A57#loK$FS)&dR~9m>nO5Q32LKIFc{}x zEX3Ws#)~zfmrA#ng#nt!vC-E$+8iM=&h?K8k*&=|q{#k_O|*B1Lsn&&jbEp0ldwN* z@-9FibW1^FZ!7+x$}HPQHkh%~Ydi8F|L@RY6=2TpO{`iwW4)ETgU)fbGL=0eSx&P_ zN!4=LxCP&uXc=N;D{OM4K<9>(_dc>&Gc`My5Xt!1|M-q4`WllYG;?T8a2{)4^x$@tU__vH>!-@p4N;J zbWBa08Q=3nQhHNJgEW)*QySn(o|pjmS3G<2ji@?MwSHNtw48cyg~n@Ahrc?y*Xy`@ zmurTmFje_ z>rb(dC4t-p>-S4F=9mC&tJDSZnfO8Q z=Xm1q6T8CRE%2;&8}Vn#Iu3i?-t4%erkpYBjFdIKU7n95<=OM@)**C)yzO_(yE=K3m(+X+}pR>CA~kbvVMo{_91-ag;On4#Q&Yx&6aTHCXPbwznpk79!x&@9V30c zBf#K9s)I_sW6$?~bPNXbIdK-Xm93V068$#{DTB>qIh7SA{1nWpditHG1r%5*amcYu|=I5`cONtHM=~9#_p%> zWa;`-ZeA^4wb4$Epate}G9v0DvJ>1^t$nX--B`Kdwoi;E27aU0!|fvwU%a|5@EXRc zVTOE$dZ;4F0cz(l`A@}WZrlgIWWVbR51bODkQ}AxbPkxX$&3$2I}oPeOt%{ry^+dV zXA;e?^YM5)AKDFV87vNyc62&iSY7gDimwraa<@M-ZZl85MF)X3AiMs|);I_+f2WDR zJ00a9(r_xyBO(XszcTifV|Ig7PLQ>aFlvz_9p8qX=}&h(dywMooVYb}&LBLm1D|-?pOGH#^&WVca2l@-EjpmzA*2W5nIR>YOgh&iIzRcR!uQw6-*eNoob*Jg zGMS7>+yv<*$2s>*Y=I=oI?Z}6xbyC9jSrjO1Gd6qrsfX@%~T5`$dIaw*fRa@Y}>fp z*CTfb@qKP@`aKZFc#NCL8_tGfb7Ld5lSbA*5~ay_NRB*0y;$+QL$(<-&m>{YOnM(w z#|#?;)m76Znx%HwcPFb!Lz+(MXhSR~TfQQULnS!t_Od*#G$M|Uf+;1=Lv|~X7ebtr zh7H+iPbdA}Pm1RS5e4%cI&w5$jzACIhZ_ngl;CcDEOGDK_)Z|a>j>b`w+CfvB`B*N z0G78_CGt>(@{hCNSGtGOunk#Z2Yop9X|6qYQ8%nh8jL$0pZkbFP z(<#VlJBotYP1{T6PxN_fu-qq-kvcj0pl$RwI0zF3(q1gU?atEa{t-6o-|-Wi0j*x8 z*P3*x1Nh9#1Dm|4(4|#5?Yfj!x$wL5nzYY`G`Gt%<+sL8)eYO-($qVfzC!W)mDLtJ zVNP6D({lTCaq66UOOMts7VdZYD8oE)vV2Z(?uNcrtU`aLQi@$N(p%S?voopSh6#zIatB~Dv?V1H(k zJrQ}HvT?s(l)E}CWb9Pxek>YO9s9H>=vy#Tzw78Uu&49&`Yec!)EI=vsx8U0V4})Z zf7yVDH)iqnwa=^}-`d9zk~sqe`Ovyyr&;S-fpFVd}g zw|OuQb6;4MoaFGF=qeTK_9~=F+dH_7aP$49r&7y6J0NQ`)+j<@pi1_>g1eu<^6orTK zCgHJEi4bLez2Z(A8aPnHfXfMzC&+}$rws+6?Yx3HDUqs@zOUZ z{z6(BURU;8#@02AVD2&4x0%ujl~27C59Y{)SSNF$c`CNZ-Hhr~((ucxyQmP2<>67g z^LT9J+>0UOB-7-WT2!KUKf%9R0r)j{VPROK^?Rf2G2CM%VPrtLK;DJK(^R;ICu=d7 z?ZgYMl#Pkht*{gkY#6VxHV4*Dk#37%N^`w%Y|T7rdR#}M%+=)X&fjm8pk&NiGFRVp z%kF&9Xez7Gim8%&=xdk=j}KK!nHhmE5@OsB$A>Oq3 zfuF#9Uvt@>%0%GlOgbBi=RY?5#{_>a6~RNK8xzJaaslgSUrHGrm3+Q)NK0~F+PsY{=Z6eSbKp6@8We=$NK z(d+P~zaZ_~IuaPJxRT`IN5nV$R7(Qub$1BDt(oL&yqH;!9$YRe7wnB8@qkE#V?p%VR0h7Gh)>Gb z_BCq2p_x(_Wtm&46|O(iON;WfwrYDkI}UdswMECfI9|B5H?&ZO`hY7pSPUyyle6dI z%@l_VNKjvejq9c4UWfhL-{q4R%x}DSPa+C~WWbSD1J4fBbDyj`1U)jF;_{gc8$7mQ ztV6Ras9nB51#b_JQt!mTdPFx~V;pyhpEC$DzVlCyIA|!WXU~_9T7fT=J=t`1-Pvjy zf8Nd{chS5K>2a$Q=z`X7??z4Neb+wNLw?y**imrq?$$iSy7zQP^w^Fpm#_X!sPy+N zkc{+gb+o&rG2omi{F5}4%4J+Uvuu`O|3+r&E4$($Qn6OZthBSaFyd-58hX`kxn%{R zwcNYvdgst}l{z9zuvFPavzx^z)qb^7;(G1wNb*S8oc1`iBZ`*Oqo|QM@_9X4F=OVU zXIcOj(4vSVV{W+{bU&B4rDEw%%8gl$h8W|wya?Ti?`dMM6>vE|M5fv=9dS=%0z*Fi zjmtFNS%20~UXW*kCxhChA24m(V z=?9Co6n-#2ZV67D_Lk7oL~I!QQhO^R(eXNO^XQ%9Hi@~3Bd;5X%Jhlj7hrsto>APOk=h25$~R5{RNOZYCme&rm9O3DC*0`uS7}prH`a;RhT&kxKvB(zeF(VAn6z zrVVj6Z6CHxL2jLuuCrKpwxr8_b96qs4aQ;& zeK7I)JvG;<#zt5&w5Yj^&K_E=kzfm2Q|vsaUE$ZdoFEdr1GoxM=(*{mx5Oc^*tG$% zZXCMJlzHYJ!BhL))_ffnQS9ZLKB5>It%Q)BaPqW0SZ}){aL+D=1Hva4ZSOeZCjHG^ zCbwEuD{oxan^?!*tf$DzXwRGN_3&Ie*6R`l{YS{9D9HYyBlY}lJ+Z7_?e9baKHl{a z(9V%0V-0`IMECjQF*EeQe}7cp7?xH;&T50Fu?vlN#}+i%?g|?_WOT^f8=ZJV)-C!N zZgxx3?Lv>p(jd^h#i=%>W~3CX?Ta1IT<1U^2#sj$S@onDW#U_6d?(Z%V0g)?;9+C~ zAs*p>U^1Z4i{uBQreI%%6uloH3SRnoy|Bp-wMA4v zjgN;dKPXwtIZs~CCZ|bcS%v;Ny;js&HN~4y1H%AvRj-R~yILo1KDY192~}I{4#Sfq zg|_5`w%J$Hm~Y;6&DNe`r_tj8bU)z!Z&gEZ3lD&s#C`-K1JWBLp+IY9XlU{%dq;}r z*&2FmnH-JpJLs_qKZ-y;Bugw&;t}3Zl;RKOBG`)t=`I?L1_OPp+=WzX58I)jyQ7Gu zFGmZ~VcEbX#s^&wOw(|*nzEvqU1>6%?Jv~MBKsZHZkIP4)9KQe`RQBdW4d!p+m#Wb zUT)sVuK#7!CiV>?mcpZAx7oXh&0upFj5Y_l%W;BGTRYN55)|l8*4}xyh;8+GuWpU{ zQn_}j@RZmNs7ZNEoXCI+$|kkur?t6|V z2@ZU$vR^8Ma<|8UuY}gm>6F<6C-Ru4BKIQ}drhUpL%iX!skL7CTX8+n0fH<#tMTH^Qf`FcxJ^>c}_`(ssaLe~S)JT46Vx(WR%VU4NDx+*cZORG~^ z1eH{6<#%mSlHK#RyQ4woNC$f+!MiKa3dPukg;nb*csVGgjJo=}K!@MJgZ>@?6tc~b zLPJfg5^a&z6({oTCt$@Fz4wa3d66%^hoSuMu$Y+ku_PO;zN8o6&fG$R zBnDqdVzcHBsR(de^IfdlG1OyX#QX@-nmLM~S);SZ-3)ob7ky>7C;vq5ZILyZzU+q^ zF&z>_U)BTiQGvkF9Jc2z`nc+{As?M|PPeZ^Xx1o1ju}=-{yNo%M0hRh%U-j+uM*|J zA_ntWbx?Bk-HfH2=1m+7>&|sIZ@Kb(qVb}J(|rd` zYVFFq)ty4@t)>}Fja_i2l`cBOrwd}s0O61yQD|1H~QhD3AD{0W{5v=4r^ z0I9k$tn`eQD>zfDc9XV5&y(Ayi8Nf+Dx<|oIBcbBp!DY}p7ly(-D^9I1GhWY4g;pA zR0TJrLRYA$H@DNLX0xr?oJqq}m%Ml`Qc8fI`44zW@}2g&0OfgH)|e7#!)BwErapub3&(P+EzbyZ`WxYj?F-rj5G6%4t^zYpE zK~zYcil2!{mfM|3GFnyC9+K%SDR|sZgrdILBJEc9k{~$ zMKq*$9i@4>C|2O85v7m1P#d=h37?Btq2A(XkK*_~Z`l!Jv9-a#SWac>Z}`Iy^sXX% z@o^y=ze;;(0`h29>)iSBfdq>Q|C6SDSTLCW&+#%e@UNq)cs!sx{)tmoGWkE>M9YNP zitG8{<<^+XbRb-h<8^ZY;JlaWzH(_y{E5d!f)IJyfoaq>7JzE$Twh>KFOWV1b0}hH zc$b`^2%n{vPn-_$8esg%GI=PFkAsWu`)jUr(`t@P+#yE5d3H{Q4FEq zQ*ORJ%9}O-`X!Yui-H$BJk4(;L}ES z;LqB|ILxG$SY7Q0oZ8|&W>5>K&D)Py0bFiG0seQjq zilKJpOBczXH~^H?+LyPt;bIl8#Naw#xTd*@%BiiFr&Fds72eO8hF6gHQCx11Z$xW; zXQXfNQ1iq-f1ysz@OX~YNb&!6w*#r;0q=y4|G?=h?{@y0Xf1_#Z|fX5w{zx>Q|ju^ zCEM}+YvUwMhUc!fAmy&>5+|a&rD$s@lY_P{&L^Fta_e?CT&Y}v!kgyM6?}0XT|`xE z{KSrE-f@5m6E9ACcqULRB?~Bnh33OT{fG-;D4+@aABcgTezQ5{V|lolMpN;y=^XqM zO_OzFMAf8<=qlv$JTqv{vY05U*TtH>Wg6brUJy}xTVL*$=YzlF8m&r+nI2mj&CSEp z6xy;!$DgS2x4J8TpZ|@nWNKev#t+T&T@&MX8RM5{xWwF|#L+=mzt}r@aqDCeSHli@ zcuPJNAZRGGcJKrDK7A)J#>8sm`OcCgtp!o(xYAf*_qTeN4Xjf@TuIlh+nw!|JiA9d zFy@u2d)S4Xx);XnwMr>&lRrz#YKgUtN>%S2omyAjxlgI(2x~p=>{396v@3j(X46zt z#*F}Qupq8ky_*WSh!exOqYd$I?7w}DHRanq7ra5T+MiPRWmF*c%O{}F&_6#bv?cU@ z-1pBl>qs=jh2*>8bsrt}T@|o?D5Yk>M{~e%5$tHTwFr*6tQ|U-92bKFecUlnRbm`Z zgNRWU!$6+6o6>x7xs88qJKW#gv-~)JICiQ%%a!MQauh_5{PHxP88M|EdI#)-Bfq%2~B;P0?W@_R?dge6%-fTYs>gavhNz z+NXhen5^lIg^W+!O$ute5pdWm2Q z3w-6Mj2`$cm7k(%h|o_T;8cQlv}OgS;Z%Jo3}<~eBt`@?+BH# zPw)Mn3dn=%mJ)gTO>3syV{!YB>|>^Cp$yM^N^GI~3K=fHG&SITUIvEc$bX1knC}Ef zZ9pH1s7236cRy^+?bgYibpVoC*;-}B;hUG4pmsO)ezmh#xe_anczb}Z@~t|h z`CEZAuIG8`0K#&ZGrk(upQ5LEvvyJA_ zKi>}ImFTUBMrj|lgSA|7hx4!^&02%`Z6gFb-ff0nrQeQ>?$xBL<%QTC@b-M^c#tGS z(Z_4QBeDLZ$DiFbMilvOW8Zc0pMPhRFJxEeRuHKjX!dm9#~Ih%qhcaQxxXPP@mQE> z=GOQ~I=1;fv9PL(6(L*!^U)$ghgg$!vm^&+@CA9@_Ih-c(Xs?87rD09#-nr?{cQYf{Tos(Ox0NO%6Sj5r+- z(F%n`phwQ`h!yd>@?nh`O=fFZ7;oy{wD0?Cf$6E!t6txQ9gcEYc3BRETUQT+!|bF6 z?9LpCqO`by`|bu%YL(!2YY_9&cqjH`p&1gRuEp3totScI{#dsE=YRdzf7a0daI=e7 zO_C%<7EtTgiXk2hQ3?=x&f!Oj0J<-q%goFJR0S&FN%p#|0c_~>ND}JkAnZ3~?@URD zov~n*B{j5!dG#iG8^Ujv`_oB1xLvkfyRPicQ(?B95!239iv)~}o=Bb4q|VLpZ{&C0 zM}tY;fBPuMlL*wVscu52A+#&4y2P{d#^OAg&uAjpOSIKrjR1JHc9?Ci<$85~tZDYN qqK4b)s_t(jUfT!5D*(HBS4Fj!e2H7L+Y7FMMzj16`1im6 { - const failureMessage = document.getElementById("failure"); - - var response = await fetch(path, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(body), - }); - - const json = await response.json(); - if (json.token) { - window.localStorage.setItem("token", `"${json.token}"`); - window.location.href = "/app"; - return; - } - - if (json.ticket) { - // my terrible solution to 2fa - const twoFactorForm = document.forms["2fa"]; - const loginForm = document.forms["login"]; - - twoFactorForm.style.display = "flex"; - loginForm.style.display = "none"; - - twoFactorForm.ticket.value = json.ticket; - return; - } - - // Very fun error message here lol - const error = json.errors - ? Object.values(json.errors)[0]._errors[0].message - : json.captcha_key - ? "Captcha required" - : json.message; - - failureMessage.innerHTML = error; - failureMessage.style.display = "block"; -}; diff --git a/src-slowcord/login/public/login.html b/src-slowcord/login/public/login.html deleted file mode 100644 index fa367b70..00000000 --- a/src-slowcord/login/public/login.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - Slowcord - - - - - - - - - - -
- -
- - - - diff --git a/src-slowcord/login/public/register.html b/src-slowcord/login/public/register.html deleted file mode 100644 index 30b560a4..00000000 --- a/src-slowcord/login/public/register.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - Slowcord - - - - - - - - - - -
- -
- - - - diff --git a/src-slowcord/login/src/index.ts b/src-slowcord/login/src/index.ts deleted file mode 100644 index ced35dcf..00000000 --- a/src-slowcord/login/src/index.ts +++ /dev/null @@ -1,171 +0,0 @@ -import "dotenv/config"; -import express, { Request, Response } from "express"; -import cookieParser from "cookie-parser"; -import { - initDatabase, - generateToken, - User, - Config, - handleFile, -} from "fosscord-server/src/util"; -import path from "path"; -import fetch from "node-fetch"; - -// apparently dirname doesn't exist in modules, nice -/* https://stackoverflow.com/a/62892482 */ -import { fileURLToPath } from "url"; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const app = express(); -app.use(cookieParser()); -const port = process.env.PORT; - -// ip -> unix epoch that requests will be accepted again -const rateLimits: { [ip: string]: number } = {}; -const allowRequestsEveryMs = 0.5 * 1000; // every half second - -const allowedRequestsPerSecond = 50; -let requestsThisSecond = 0; -setInterval(() => { - requestsThisSecond = 0; -}, 1000); - -const toDataURL = async (url: string) => { - const response = await fetch(url); - const blob = await response.blob(); - const buffer = Buffer.from(await blob.text()); - return `data:${blob.type};base64,${buffer.toString("base64")}`; -}; - -class Discord { - static getAccessToken = async (req: Request, res: Response) => { - const { code } = req.query; - - const body = new URLSearchParams( - Object.entries({ - client_id: process.env.DISCORD_CLIENT_ID as string, - client_secret: process.env.DISCORD_SECRET as string, - redirect_uri: process.env.DISCORD_REDIRECT as string, - code: code as string, - grant_type: "authorization_code", - }), - ).toString(); - - const resp = await fetch("https://discord.com/api/oauth2/token", { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - body: body, - }); - - const json = (await resp.json()) as any; - if (json.error) return null; - - return { - access_token: json.access_token, - token_type: json.token_type, - expires_in: json.expires_in, - refresh_token: json.refresh_token, - scope: json.scope, - }; - }; - - static getUserDetails = async (token: string) => { - const resp = await fetch("https://discord.com/api/users/@me", { - headers: { - Authorization: `Bearer ${token}`, - }, - }); - - const json = (await resp.json()) as any; - if (!json.username || !json.email) return null; // eh, deal with bad code later - - return { - id: json.id, - email: json.email, - username: json.username, - avatar_url: json.avatar - ? `https://cdn.discordapp.com/avatars/${json.id}/${json.avatar}?size=2048` - : null, - }; - }; -} - -const handlers: { [key: string]: any } = { - discord: Discord, -}; - -app.get("/oauth/:type", async (req, res) => { - requestsThisSecond++; - if (requestsThisSecond > allowedRequestsPerSecond) - return res.sendStatus(429); - - const ip = - (req.headers["x-forwarded-for"] as string) || - (req.socket.remoteAddress as string); - console.log(`${ip}`); - if (!rateLimits[ip]) { - rateLimits[ip] = Date.now() + allowRequestsEveryMs; - } else if (rateLimits[ip] > Date.now()) { - rateLimits[ip] += allowRequestsEveryMs; - console.log( - `${new Date()} : user ${ip} was timed out for ${ - (rateLimits[ip] - Date.now()) / 1000 - }s`, - ); - return res.sendStatus(429); - } else { - delete rateLimits[ip]; - } - - const { type } = req.params; - const handler = handlers[type]; - if (!type || !handler) return res.sendStatus(400); - - const data = await handler.getAccessToken(req, res); - if (!data) return res.sendStatus(500); - - const details = await handler.getUserDetails(data.access_token); - if (!details) return res.sendStatus(500); - - let user = await User.findOne({ where: { email: details.email } }); - if (!user) { - user = await User.register({ - email: details.email, - username: details.username, - req, - }); - - if (details.avatar_url) { - try { - const avatar = await handleFile( - `/avatars/${user.id}`, - (await toDataURL(details.avatar_url)) as string, - ); - user.avatar = avatar; - await user.save(); - } catch (e) { - console.error(e); - } - } - } - - const token = await generateToken(user.id); - - res.cookie("token", token); - - res.sendFile(path.join(__dirname, "../public/login.html")); -}); - -app.use(express.static("public", { extensions: ["html"] })); - -(async () => { - await initDatabase(); - await Config.init(); - - app.listen(port, () => { - console.log(`Listening on port ${port}`); - }); -})(); diff --git a/src-slowcord/login/tsconfig.json b/src-slowcord/login/tsconfig.json deleted file mode 100644 index 4d96714c..00000000 --- a/src-slowcord/login/tsconfig.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "exclude": ["node_modules"], - "include": ["src/**/*.ts"], - "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - /* Projects */ - // "incremental": true, /* Enable incremental compilation */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "ES6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - "lib": [ - "ES2021" - ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, - // "jsx": "preserve", /* Specify what JSX code is generated. */ - "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */, - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ - // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - /* Modules */ - "module": "ES2020" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ - "types": [ - "node" - ] /* Specify type package names to be included without being referenced in a source file. */, - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "resolveJsonModule": true, /* Enable importing .json files */ - // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - "sourceMap": true /* Create source map files for emitted JavaScript files. */, - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./build" /* Specify an output folder for all emitted files. */, - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ - // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ - "strictPropertyInitialization": false /* Check for class properties that are declared but not set in the constructor. */, - // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ - // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } -} diff --git a/src-slowcord/nginx/fosscord b/src-slowcord/nginx/fosscord deleted file mode 100644 index f1d53de1..00000000 --- a/src-slowcord/nginx/fosscord +++ /dev/null @@ -1,54 +0,0 @@ -server { - server_name slowcord.understars.dev; - - client_max_body_size 150M; - - add_header Last-Modified $date_gmt; - proxy_set_header Host $host; - proxy_pass_request_headers on; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Proto https; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Host $remote_addr; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - - location / { - proxy_pass http://127.0.0.1:3001; - } - - location /api { - proxy_pass http://127.0.0.1:3001; - add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; - - # TODO: This is a bad solution. Why does proxy_pass not forward all upstream errors to client? - # Or is it just that the server is not actually responding? - proxy_no_cache 1; - proxy_cache_bypass 1; - proxy_connect_timeout 1; - proxy_send_timeout 1; - proxy_read_timeout 1; - send_timeout 1; - } - - # TODO: Make the login service not suck - location ~ ^/(login|register|oauth/discord|css/index.css|js/handler.js) { - proxy_pass http://127.0.0.1:3010; - } - - listen 443 ssl; - ssl_certificate /etc/letsencrypt/live/slowcord.understars.dev/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/slowcord.understars.dev/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; -} - -server { - if ($host = slowcord.understars.dev) { - return 301 https://$host$request_uri; - } - - listen 80; - server_name slowcord.understars.dev; - return 404; -} \ No newline at end of file diff --git a/src-slowcord/nginx/voice b/src-slowcord/nginx/voice deleted file mode 100644 index b2b18c40..00000000 --- a/src-slowcord/nginx/voice +++ /dev/null @@ -1,35 +0,0 @@ -server { - server_name voice.slowcord.understars.dev; - - client_max_body_size 50M; - - add_header Last-Modified $date_gmt; - proxy_set_header Host $host; - proxy_pass_request_headers on; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-Proto https; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Host $remote_addr; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - - location / { - proxy_pass http://127.0.0.1:3004; - } - - listen 443 ssl; - ssl_certificate /etc/letsencrypt/live/voice.slowcord.understars.dev/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/voice.slowcord.understars.dev/privkey.pem; - include /etc/letsencrypt/options-ssl-nginx.conf; - ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; -} - -server { - if ($host = voice.slowcord.understars.dev) { - return 301 https://$host$request_uri; - } - - listen 80; - server_name voice.slowcord.understars.dev; - return 404; -} \ No newline at end of file diff --git a/src-slowcord/rules.md b/src-slowcord/rules.md deleted file mode 100644 index 1097060a..00000000 --- a/src-slowcord/rules.md +++ /dev/null @@ -1,22 +0,0 @@ -# Hi, welcome to Slowcord! - -Slowcord is a heavily modded Fosscord instance. You can browse it's source here: https://github.com/MaddyUnderStars/fosscord-server/tree/slowcord - -## Here are some general instance-wide rules: - -- **Harassment, homophobia, transphobia, etc, violence, and hate speech are forbidden.** -- Behaviour that harms the service - be it malicious/intentional or not - is strictly forbidden. This may include API abuse/spam, exploits, etc. -- - If you do discover an exploit/bug, it would be greatly appreciated if you could create an issue in the above repo, or DM @MaddyUnderStars#0000. -- Any content that would be considered illegal in Australia is also forbidden. Additionally, if it is illegal in your own country, it shouldn't be here. -- Bots/selfbots are allowed. If you would like an account to be given bot status, DM @MaddyUnderStars#0000. - -These rules are non-exhaustive, but should give a good idea of what will be enforced. - -Permanent Slowcord guild invite: https://slowcord.understars.dev/invite/slowcord - -### If a message or user breaks these rules, you can report it here: https://forms.gle/sd6RkdM7gRgJLV368 - -#### Lastly ( and not rules ): - -- If you use BetterDiscord or Powercord, and want an easier time accessing Slowcord and other Fosscord instances, check out https://github.com/maddyunderstars/fosscord-bd! -- Also, if you're on Android, you can download the mobile client at https://slowcord.understars.dev/assets/slowcord.apk diff --git a/src-slowcord/status/.env.template b/src-slowcord/status/.env.template deleted file mode 100644 index e15dc56a..00000000 --- a/src-slowcord/status/.env.template +++ /dev/null @@ -1,6 +0,0 @@ -DATABASE= -INSTANCE_API= -INSTANCE_CDN= -INSTANCE_TOKEN= -MEASURE_INTERVAL=1000 -RETENTION_DAYS=30 \ No newline at end of file diff --git a/src-slowcord/status/package-lock.json b/src-slowcord/status/package-lock.json deleted file mode 100644 index a4f449ab15a1e6e37b61c801386d471ed581ca3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33113 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 EFSGv(RsaA1 diff --git a/src-slowcord/status/package.json b/src-slowcord/status/package.json deleted file mode 100644 index ccec4f55..00000000 --- a/src-slowcord/status/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "slowcord-status", - "version": "1.0.0", - "description": "Slowcord status service", - "main": "build/index.js", - "scripts": { - "build": "tsc -b", - "start": "node build/index.js", - "start:gateway": "node build/gateway.js" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/maddyunderstars/fosscord-server.git" - }, - "bugs": { - "url": "https://github.com/maddyunderstars/fosscord-server/issues" - }, - "homepage": "https://github.com/maddyunderstars/fosscord-server#readme", - "author": "MaddyUnderStars", - "license": "AGPL-3.0-only", - "devDependencies": { - "@types/node": "^18.0.6" - }, - "dependencies": { - "dotenv": "^16.0.1", - "fosscord-gopnik": "^1.0.0", - "mysql2": "^2.3.3", - "node-fetch": "^3.2.9" - }, - "type": "module" -} diff --git a/src-slowcord/status/src/gateway.ts b/src-slowcord/status/src/gateway.ts deleted file mode 100644 index bc00c2d4..00000000 --- a/src-slowcord/status/src/gateway.ts +++ /dev/null @@ -1,99 +0,0 @@ -import "dotenv/config"; -import Fosscord from "fosscord-gopnik"; -import Discord from "discord.js"; -import mysql from "mysql2"; -import fetch from "node-fetch"; - -const dbConn = mysql.createConnection(process.env.DATABASE as string); -const executePromise = (sql: string, args: any[]) => - new Promise((resolve, reject) => - dbConn.execute(sql, args, (err, res) => { - if (err) reject(err); - else resolve(res); - }), - ); -const savePerf = async (time: number, name: string, error?: string | Error) => { - if (error && typeof error != "string") error = error.message; - try { - await executePromise( - "INSERT INTO performance (value, endpoint, timestamp, error) VALUES (?, ?, ?, ?)", - [time ?? 0, name, new Date(), error ?? null], - ); - // await executePromise("DELETE FROM performance WHERE DATE(timestamp) < now() - interval ? DAY", [process.env.RETENTION_DAYS]); - } catch (e) { - console.error(e); - } -}; - -var timestamp: number | undefined; - -const doMeasurements = async (channel: Discord.TextChannel) => { - timestamp = Date.now(); - await channel.send("hello this is a special message kthxbye"); - - setTimeout( - doMeasurements, - parseInt(process.env.MEASURE_INTERVAL as string), - channel, - ); -}; - -const instance = { - app: process.env.INSTANCE_WEB_APP as string, - api: process.env.INSTANCE_API as string, - cdn: process.env.INSTANCE_CDN as string, - token: process.env.INSTANCE_TOKEN as string, -}; - -const client = new Fosscord.Client({ - intents: [], - http: { - api: instance.api, - cdn: instance.cdn, - }, -}); - -client.on("ready", async () => { - console.log(`Ready on gateway as ${client.user!.tag}`); - - const channel = await client.channels.fetch("1019955729054267764"); - if (!channel) return; - - doMeasurements(channel as Discord.TextChannel); -}); - -client.on("messageCreate", async (msg: Discord.Message) => { - if (!timestamp) return; - if ( - msg.author.id != "992745947417141682" || - msg.channel.id != "1019955729054267764" || - msg.content != "hello this is a special message kthxbye" - ) - return; - await savePerf(Date.now() - timestamp, "messageCreate", undefined); - timestamp = undefined; - - await fetch( - `${instance.api}/channels/1019955729054267764/messages/${msg.id}`, - { - method: "DELETE", - headers: { - authorization: instance.token, - }, - }, - ); -}); - -client.on("error", (error: any) => { - console.log(`Gateway error`, error); -}); - -client.on("warn", (msg: any) => { - console.log(`Gateway warning:`, msg); -}); - -(async () => { - await new Promise((resolve) => dbConn.connect(resolve)); - console.log("Connected to db"); - await client.login(instance.token); -})(); diff --git a/src-slowcord/status/src/index.ts b/src-slowcord/status/src/index.ts deleted file mode 100644 index 979469b6..00000000 --- a/src-slowcord/status/src/index.ts +++ /dev/null @@ -1,159 +0,0 @@ -import "dotenv/config"; -import https from "https"; -import mysql from "mysql2"; -import fetch from "node-fetch"; - -const dbConn = mysql.createConnection(process.env.DATABASE as string); -const executePromise = (sql: string, args: any[]) => - new Promise((resolve, reject) => - dbConn.execute(sql, args, (err, res) => { - if (err) reject(err); - else resolve(res); - }), - ); - -const instance = { - app: process.env.INSTANCE_WEB_APP as string, - api: process.env.INSTANCE_API as string, - cdn: process.env.INSTANCE_CDN as string, - token: process.env.INSTANCE_TOKEN as string, -}; - -const savePerf = async (time: number, name: string, error?: string | Error) => { - if (error && typeof error != "string") error = error.message; - try { - await executePromise( - "INSERT INTO performance (value, endpoint, timestamp, error) VALUES (?, ?, ?, ?)", - [time ?? 0, name, new Date(), error ?? null], - ); - // await executePromise("DELETE FROM performance WHERE DATE(timestamp) < now() - interval ? DAY", [process.env.RETENTION_DAYS]); - } catch (e) { - console.error(e); - } -}; - -const saveSystemUsage = async ( - load: number, - procUptime: number, - sysUptime: number, - ram: number, - sessions: number, -) => { - try { - await executePromise( - "INSERT INTO monitor (time, cpu, procUp, sysUp, ram, sessions) VALUES (?, ?, ?, ?, ?, ?)", - [new Date(), load, procUptime, sysUptime, ram, sessions], - ); - } catch (e) { - console.error(e); - } -}; - -const makeTimedRequest = (path: string, body?: object): Promise => - new Promise((resolve, reject) => { - const opts = { - hostname: new URL(path).hostname, - port: 443, - path: new URL(path).pathname, - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: instance.token, - }, - timeout: 1000, - }; - - let start: number, end: number; - const req = https.request(opts, (res) => { - if (res.statusCode! < 200 || res.statusCode! > 300) { - return reject(`${res.statusCode} ${res.statusMessage}`); - } - - res.on("data", (data) => {}); - - res.on("end", () => { - end = Date.now(); - resolve(end - start); - }); - }); - - req.on("finish", () => { - if (body) req.write(JSON.stringify(body)); - start = Date.now(); - }); - - req.on("error", (error) => { - reject(error); - }); - - req.end(); - }); - -const measureApi = async (name: string, path: string, body?: object) => { - let error, - time = -1; - try { - time = await makeTimedRequest(path, body); - } catch (e) { - error = e as Error | string; - } - - console.log( - `${name} took ${time}ms ${error ? "with error" : ""}`, - error ?? "", - ); - - await savePerf(time, name, error); -}; - -interface monitorzSchema { - load: number[]; - procUptime: number; - sysUptime: number; - memPercent: number; - sessions: number; -} - -const app = async () => { - await new Promise((resolve) => dbConn.connect(resolve)); - console.log("Connected to db"); - // await client.login(instance.token); - - console.log( - `Monitoring performance for instance at ${ - new URL(instance.api).hostname - }`, - ); - - const doMeasurements = async () => { - await measureApi("ping", `${instance.api}/ping`); - await measureApi("users/@me", `${instance.api}/users/@me`); - await measureApi("login", `${instance.app}/login`); - // await gatewayMeasure("websocketPing"); - - try { - const res = await fetch(`${instance.api}/-/monitorz`, { - headers: { - Authorization: process.env.INSTANCE_TOKEN as string, - }, - }); - const json = (await res.json()) as monitorzSchema; - await saveSystemUsage( - json.load[1], - json.procUptime, - json.sysUptime, - json.memPercent, - json.sessions, - ); - } catch (e) {} - - setTimeout( - doMeasurements, - parseInt(process.env.MEASURE_INTERVAL as string), - ); - }; - - doMeasurements(); -}; - -app(); diff --git a/src-slowcord/status/tsconfig.json b/src-slowcord/status/tsconfig.json deleted file mode 100644 index 4d96714c..00000000 --- a/src-slowcord/status/tsconfig.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "exclude": ["node_modules"], - "include": ["src/**/*.ts"], - "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - /* Projects */ - // "incremental": true, /* Enable incremental compilation */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "ES6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - "lib": [ - "ES2021" - ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, - // "jsx": "preserve", /* Specify what JSX code is generated. */ - "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */, - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ - // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - /* Modules */ - "module": "ES2020" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ - "types": [ - "node" - ] /* Specify type package names to be included without being referenced in a source file. */, - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "resolveJsonModule": true, /* Enable importing .json files */ - // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - "sourceMap": true /* Create source map files for emitted JavaScript files. */, - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./build" /* Specify an output folder for all emitted files. */, - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ - // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ - "strictPropertyInitialization": false /* Check for class properties that are declared but not set in the constructor. */, - // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ - // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } -} diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts index ecde7fb4..ec2c42e5 100644 --- a/src/api/middlewares/Authentication.ts +++ b/src/api/middlewares/Authentication.ts @@ -25,6 +25,8 @@ export const NO_AUTHORIZATION_ROUTES = [ "/track", // Public policy pages "/policies/instance", + // Oauth callback + "/oauth2/callback", // Asset delivery /\/guilds\/\d+\/widget\.(json|png)/, ]; diff --git a/src/api/routes/oauth2/callback.ts b/src/api/routes/oauth2/callback.ts new file mode 100644 index 00000000..3c7fb777 --- /dev/null +++ b/src/api/routes/oauth2/callback.ts @@ -0,0 +1,38 @@ +import { Router, Request, Response } from "express"; +import { route, OauthCallbackHandlers } from "@fosscord/api"; +import { FieldErrors, generateToken, User } from "@fosscord/util"; +const router = Router(); + +router.get("/:type", route({}), async (req: Request, res: Response) => { + const { type } = req.params; + const handler = OauthCallbackHandlers[type]; + if (!handler) throw FieldErrors({ + type: { + code: "BASE_TYPE_CHOICES", + message: `Value must be one of (${Object.keys(OauthCallbackHandlers).join(", ")}).`, + } + }); + + const { code } = req.query; + if (!code || typeof code !== "string") throw FieldErrors({ code: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED"), } }); + const access = await handler.getAccessToken(code); + + const oauthUser = await handler.getUserDetals(access.access_token); + + let user = await User.findOne({ where: { email: oauthUser.email } }); + if (!user) { + user = await User.register({ + email: oauthUser.email, + username: oauthUser.username, + req + }); + + // TODO: upload pfp, banner? + } + + const token = await generateToken(user.id); + + return { token }; +}); + +export default router; \ No newline at end of file diff --git a/src/api/routes/policies/instance/stats.ts b/src/api/routes/policies/instance/stats.ts new file mode 100644 index 00000000..fb8c386a --- /dev/null +++ b/src/api/routes/policies/instance/stats.ts @@ -0,0 +1,21 @@ +import { Router, Request, Response } from "express"; +import { route } from "@fosscord/api"; +import { Attachment, Config, Guild, Message, RateLimit, Session, User } from "@fosscord/util"; +const router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + res.json({ + all_time: { + users: await User.count(), + guilds: await Guild.count(), + messages: await Message.count(), + attachments: await Attachment.count(), + }, + now: { + sessions: await Session.count(), + rate_limits: await RateLimit.count(), + } + }); +}); + +export default router; diff --git a/src/api/util/handlers/Oauth.ts b/src/api/util/handlers/Oauth.ts new file mode 100644 index 00000000..cc662161 --- /dev/null +++ b/src/api/util/handlers/Oauth.ts @@ -0,0 +1,83 @@ +// TODO: Puyo's connections PR would replace this file + +import { Config } from "@fosscord/util"; +import fetch from "node-fetch"; + +export interface OauthAccessToken { + access_token: string; + token_type: string; + expires_in: string; + refresh_token: string; + scope: string; +}; + +export interface OauthUserDetails { + id: string; + email: string; + username: string; + avatar_url: string | null; +} + +interface Connection { + getAccessToken: (code: string) => Promise; + getUserDetals: (token: string) => Promise; +} + +const DiscordConnection: Connection = { + getAccessToken: async (code) => { + const { external } = Config.get(); + const { discord } = external; + + if (!discord.id || !discord.secret || !discord.redirect) + throw new Error("Discord Oauth has not been configured.") + + const body = new URLSearchParams( + Object.entries({ + client_id: discord.id as string, + client_secret: discord.secret as string, + redirect_uri: discord.redirect as string, + code: code as string, + grant_type: "authorization_code", + }) + ).toString(); + + const resp = await fetch("https://discord.com/api/oauth2/token", { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: body, + }); + if (resp.status !== 200) throw new Error(`Failed to get access token.`,); + + const json = await resp.json(); + + return json; + }, + + getUserDetals: async (token) => { + const resp = await fetch("https://discord.com/api/users/@me", { + headers: { + Authorization: `Bearer ${token}` + }, + }); + + const json = await resp.json(); + if (!json.username || !json.email) throw new Error("Failed to get user details via oauth"); + + return { + id: json.id, + email: json.email, + username: json.username, + avatar_url: json.avatar + ? `https://cdn.discordapp.com/avatars/${json.id}/${json.avatar}?size=2048` + : null, + }; + } +}; + +const OauthCallbackHandlers: { [key: string]: Connection; } = { + discord: DiscordConnection +}; + +export { OauthCallbackHandlers }; \ No newline at end of file diff --git a/src/api/util/index.ts b/src/api/util/index.ts index ffad0607..49542ceb 100644 --- a/src/api/util/index.ts +++ b/src/api/util/index.ts @@ -7,4 +7,5 @@ export * from "./handlers/route"; export * from "./utility/String"; export * from "./handlers/Voice"; export * from "./utility/captcha"; -export * from "./utility/EmbedHandlers"; \ No newline at end of file +export * from "./utility/EmbedHandlers"; +export * from "./handlers/Oauth"; \ No newline at end of file diff --git a/src/util/entities/Config.ts b/src/util/entities/Config.ts index 5035f552..9b25795d 100644 --- a/src/util/entities/Config.ts +++ b/src/util/entities/Config.ts @@ -211,7 +211,12 @@ export interface ConfigValue { }; external: { twitter: string | null; - } + discord: { + id: string | null; + secret: string | null; + redirect: string | null; + }; + }; } export const DefaultConfigOptions: ConfigValue = { @@ -423,5 +428,10 @@ export const DefaultConfigOptions: ConfigValue = { }, external: { twitter: null, + discord: { + id: null, + secret: null, + redirect: null, + } } }; diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts index 8048250c..5e474d9e 100644 --- a/src/util/interfaces/Event.ts +++ b/src/util/interfaces/Event.ts @@ -1,19 +1,26 @@ -import { PublicUser, User, UserSettings } from "../entities/User"; -import { Channel } from "../entities/Channel"; -import { Guild } from "../entities/Guild"; -import { Member, PublicMember, UserGuildSettings } from "../entities/Member"; -import { Emoji } from "../entities/Emoji"; -import { Role } from "../entities/Role"; -import { Invite } from "../entities/Invite"; -import { Message, PartialEmoji } from "../entities/Message"; -import { VoiceState } from "../entities/VoiceState"; -import { ApplicationCommand } from "../entities/Application"; -import { Interaction } from "./Interaction"; -import { ConnectedAccount } from "../entities/ConnectedAccount"; -import { Relationship, RelationshipType } from "../entities/Relationship"; -import { Presence } from "./Presence"; -import { Sticker } from ".."; -import { Activity, Status } from "."; +import { + RelationshipType, + ConnectedAccount, + Interaction, + ApplicationCommand, + VoiceState, + Message, + PartialEmoji, + Invite, + Role, + Emoji, + PublicMember, + UserGuildSettings, + Guild, + Channel, + PublicUser, + User, + Sticker, + Activity, + Status, + Presence, + UserSettings, +} from "@fosscord/util"; export interface Event { guild_id?: string; @@ -73,9 +80,9 @@ export interface ReadyEventData { number, null, number, - [[number, { e: number; s: number }[]]], + [[number, { e: number; s: number; }[]]], [number, [[number, [number, number]]]], - { b: number; k: bigint[] }[], + { b: number; k: bigint[]; }[], ][]; guild_join_requests?: any[]; // ? what is this? this is new shard?: [number, number]; @@ -473,7 +480,7 @@ export interface SessionsReplace extends Event { export interface GuildMemberListUpdate extends Event { event: "GUILD_MEMBER_LIST_UPDATE"; data: { - groups: { id: string; count: number }[]; + groups: { id: string; count: number; }[]; guild_id: string; id: string; member_count: number; @@ -481,8 +488,8 @@ export interface GuildMemberListUpdate extends Event { ops: { index: number; item: { - member?: PublicMember & { presence: Presence }; - group?: { id: string; count: number }[]; + member?: PublicMember & { presence: Presence; }; + group?: { id: string; count: number; }[]; }; }[]; };