@@ -0,0 +1,9 @@ | |||||
{ | |||||
"root": true, | |||||
"extends": [ | |||||
"lxsmnsyc/typescript" | |||||
], | |||||
"parserOptions": { | |||||
"project": "./tsconfig.eslint.json" | |||||
} | |||||
} |
@@ -0,0 +1,107 @@ | |||||
# Logs | |||||
logs | |||||
*.log | |||||
npm-debug.log* | |||||
yarn-debug.log* | |||||
yarn-error.log* | |||||
lerna-debug.log* | |||||
# Diagnostic reports (https://nodejs.org/api/report.html) | |||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json | |||||
# Runtime data | |||||
pids | |||||
*.pid | |||||
*.seed | |||||
*.pid.lock | |||||
# Directory for instrumented libs generated by jscoverage/JSCover | |||||
lib-cov | |||||
# Coverage directory used by tools like istanbul | |||||
coverage | |||||
*.lcov | |||||
# nyc test coverage | |||||
.nyc_output | |||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) | |||||
.grunt | |||||
# Bower dependency directory (https://bower.io/) | |||||
bower_components | |||||
# node-waf configuration | |||||
.lock-wscript | |||||
# Compiled binary addons (https://nodejs.org/api/addons.html) | |||||
build/Release | |||||
# Dependency directories | |||||
node_modules/ | |||||
jspm_packages/ | |||||
# TypeScript v1 declaration files | |||||
typings/ | |||||
# TypeScript cache | |||||
*.tsbuildinfo | |||||
# Optional npm cache directory | |||||
.npm | |||||
# Optional eslint cache | |||||
.eslintcache | |||||
# Microbundle cache | |||||
.rpt2_cache/ | |||||
.rts2_cache_cjs/ | |||||
.rts2_cache_es/ | |||||
.rts2_cache_umd/ | |||||
# Optional REPL history | |||||
.node_repl_history | |||||
# Output of 'npm pack' | |||||
*.tgz | |||||
# Yarn Integrity file | |||||
.yarn-integrity | |||||
# dotenv environment variables file | |||||
.env | |||||
.env.production | |||||
.env.development | |||||
# parcel-bundler cache (https://parceljs.org/) | |||||
.cache | |||||
# Next.js build output | |||||
.next | |||||
# Nuxt.js build / generate output | |||||
.nuxt | |||||
dist | |||||
# Gatsby files | |||||
.cache/ | |||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js | |||||
# https://nextjs.org/blog/next-9-1#public-directory-support | |||||
# public | |||||
# vuepress build output | |||||
.vuepress/dist | |||||
# Serverless directories | |||||
.serverless/ | |||||
# FuseBox cache | |||||
.fusebox/ | |||||
# DynamoDB Local files | |||||
.dynamodb/ | |||||
# TernJS port file | |||||
.tern-port | |||||
.npmrc |
@@ -0,0 +1,72 @@ | |||||
{ | |||||
"name": "@modal-sh/cli", | |||||
"version": "0.0.0", | |||||
"files": [ | |||||
"dist", | |||||
"src" | |||||
], | |||||
"engines": { | |||||
"node": ">=12" | |||||
}, | |||||
"license": "UNLICENSED", | |||||
"keywords": [ | |||||
"pridepack" | |||||
], | |||||
"devDependencies": { | |||||
"@types/node": "^18.14.1", | |||||
"@types/yargs": "^17.0.24", | |||||
"eslint": "^8.35.0", | |||||
"eslint-config-lxsmnsyc": "^0.5.0", | |||||
"pridepack": "2.4.4", | |||||
"tslib": "^2.5.0", | |||||
"typescript": "^4.9.5", | |||||
"vitest": "^0.28.1" | |||||
}, | |||||
"scripts": { | |||||
"prepublishOnly": "pridepack clean && pridepack build", | |||||
"build": "pridepack build", | |||||
"type-check": "pridepack check", | |||||
"lint": "pridepack lint", | |||||
"clean": "pridepack clean", | |||||
"watch": "pridepack watch", | |||||
"start": "pridepack start", | |||||
"dev": "pridepack dev", | |||||
"test": "vitest" | |||||
}, | |||||
"private": true, | |||||
"description": "CLI app.", | |||||
"repository": { | |||||
"url": "", | |||||
"type": "git" | |||||
}, | |||||
"homepage": "", | |||||
"bugs": { | |||||
"url": "" | |||||
}, | |||||
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | |||||
"publishConfig": { | |||||
"access": "restricted" | |||||
}, | |||||
"types": "./dist/types/index.d.ts", | |||||
"main": "./dist/cjs/production/index.js", | |||||
"module": "./dist/esm/production/index.js", | |||||
"exports": { | |||||
".": { | |||||
"development": { | |||||
"require": "./dist/cjs/development/index.js", | |||||
"import": "./dist/esm/development/index.js" | |||||
}, | |||||
"require": "./dist/cjs/production/index.js", | |||||
"import": "./dist/esm/production/index.js", | |||||
"types": "./dist/types/index.d.ts" | |||||
} | |||||
}, | |||||
"typesVersions": { | |||||
"*": {} | |||||
}, | |||||
"dependencies": { | |||||
"@clack/core": "^0.3.2", | |||||
"@modal-sh/core": "workspace:*", | |||||
"yargs": "^17.7.2" | |||||
} | |||||
} |
@@ -0,0 +1,3 @@ | |||||
{ | |||||
"target": "es2018" | |||||
} |
@@ -0,0 +1,5 @@ | |||||
import yargs from 'yargs'; | |||||
export const createCli = (argv: typeof process.argv) => { | |||||
return yargs(argv); | |||||
}; |
@@ -0,0 +1,15 @@ | |||||
import yargs from 'yargs'; | |||||
import { AdderController, AdderControllerImpl } from './modules/adder'; | |||||
export const addCommands = (cli: yargs.Argv) => { | |||||
const adderController: AdderController = new AdderControllerImpl(); | |||||
cli.command({ | |||||
aliases: ['a'], | |||||
command: 'add <a> <b>', | |||||
describe: 'Add two numbers', | |||||
handler: adderController.addNumbers, | |||||
}); | |||||
return cli; | |||||
}; |
@@ -0,0 +1,9 @@ | |||||
import { addCommands } from '@/commands'; | |||||
import { createCli } from '@/cli'; | |||||
import { hideBin } from 'yargs/helpers'; | |||||
const args = createCli(hideBin(process.argv)); | |||||
addCommands(args); | |||||
args.parse(); |
@@ -0,0 +1,42 @@ | |||||
import { ArgumentsCamelCase } from 'yargs'; | |||||
import { | |||||
AdderService, | |||||
AdderServiceImpl, | |||||
ArgumentOutOfRangeError, | |||||
InvalidArgumentTypeError, | |||||
} from './adder.service'; | |||||
export interface AdderController { | |||||
addNumbers: (args: ArgumentsCamelCase<{ a: number, b: number }>) => void | Promise<void>; | |||||
} | |||||
export class AdderControllerImpl implements AdderController { | |||||
constructor( | |||||
private readonly adderService: AdderService = new AdderServiceImpl(), | |||||
) { | |||||
// noop | |||||
} | |||||
readonly addNumbers = async (args: ArgumentsCamelCase<{ a: number, b: number }>) => { | |||||
const { a, b } = args; | |||||
try { | |||||
const response = this.adderService.addNumbers({a, b}); | |||||
process.stdout.write(`${response}\n`); | |||||
process.exit(0); | |||||
} catch (errorRaw) { | |||||
const error = errorRaw as Error; | |||||
if (error instanceof InvalidArgumentTypeError) { | |||||
process.stderr.write(`${error.message}\n`); | |||||
process.exit(-1); | |||||
return; | |||||
} | |||||
if (error instanceof ArgumentOutOfRangeError) { | |||||
process.stderr.write(`${error.message}\n`); | |||||
process.exit(-2); | |||||
return; | |||||
} | |||||
process.stderr.write(`${error.message}\n`); | |||||
process.exit(-3); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,21 @@ | |||||
import { | |||||
add, | |||||
AddFunctionOptions, | |||||
ArgumentOutOfRangeError, | |||||
InvalidArgumentTypeError, | |||||
} from '@modal-sh/core'; | |||||
export interface AdderService { | |||||
addNumbers(options: AddFunctionOptions): number; | |||||
} | |||||
export class AdderServiceImpl implements AdderService { | |||||
addNumbers(options: AddFunctionOptions) { | |||||
return add(options); | |||||
} | |||||
} | |||||
export { | |||||
ArgumentOutOfRangeError, | |||||
InvalidArgumentTypeError, | |||||
}; |
@@ -0,0 +1,2 @@ | |||||
export * from './adder.controller'; | |||||
export * from './adder.service'; |
@@ -0,0 +1,64 @@ | |||||
import {describe, it, expect, vi, beforeAll, afterAll} from 'vitest'; | |||||
import { createCli } from '../src/cli'; | |||||
import { addCommands } from '../src/commands'; | |||||
import yargs from 'yargs'; | |||||
import { AdderServiceImpl, InvalidArgumentTypeError, ArgumentOutOfRangeError } from '../src/modules/adder'; | |||||
vi.mock('process'); | |||||
describe('blah', () => { | |||||
let cli: yargs.Argv; | |||||
let exit: vi.Mock<typeof process.exit>; | |||||
let exitReal: typeof process.exit; | |||||
beforeAll(() => { | |||||
exitReal = process.exit.bind(process); | |||||
const processMut = process as unknown as Record<string, unknown>; | |||||
processMut.exit = exit = vi.fn(); | |||||
}); | |||||
afterAll(() => { | |||||
process.exit = exitReal = process.exit.bind(process); | |||||
}); | |||||
it('returns result when successful', async () => { | |||||
cli = createCli(['add', '1', '2']); | |||||
addCommands(cli); | |||||
await cli.parse(); | |||||
expect(exit).toHaveBeenCalledWith(0); | |||||
}); | |||||
it('returns error when given invalid inputs', async () => { | |||||
vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { | |||||
throw new InvalidArgumentTypeError('Invalid input'); | |||||
}); | |||||
cli = createCli(['add', '1', '2']); | |||||
addCommands(cli); | |||||
await cli.parse(); | |||||
expect(exit).toHaveBeenCalledWith(-1); | |||||
}); | |||||
it('returns error when given out-of-range inputs', async () => { | |||||
vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { | |||||
throw new ArgumentOutOfRangeError('Out of range'); | |||||
}); | |||||
cli = createCli(['add', '1', '2']); | |||||
addCommands(cli); | |||||
await cli.parse(); | |||||
expect(exit).toHaveBeenCalledWith(-2); | |||||
}); | |||||
it('returns error when an unexpected error occurs', async () => { | |||||
vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { | |||||
throw new Error('Unexpected error'); | |||||
}); | |||||
cli = createCli(['add', '1', '2']); | |||||
addCommands(cli); | |||||
await cli.parse(); | |||||
expect(exit).toHaveBeenCalledWith(-2); | |||||
}); | |||||
}); |
@@ -0,0 +1,24 @@ | |||||
{ | |||||
"exclude": ["node_modules"], | |||||
"include": ["src", "types", "test"], | |||||
"compilerOptions": { | |||||
"module": "ESNext", | |||||
"lib": ["ESNext"], | |||||
"importHelpers": true, | |||||
"declaration": true, | |||||
"sourceMap": true, | |||||
"rootDir": "./", | |||||
"strict": true, | |||||
"noUnusedLocals": true, | |||||
"noUnusedParameters": true, | |||||
"noImplicitReturns": true, | |||||
"noFallthroughCasesInSwitch": true, | |||||
"moduleResolution": "node", | |||||
"jsx": "react", | |||||
"esModuleInterop": true, | |||||
"target": "es2018", | |||||
"paths": { | |||||
"@/*": ["./src/*"], | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,24 @@ | |||||
{ | |||||
"exclude": ["node_modules"], | |||||
"include": ["src", "types"], | |||||
"compilerOptions": { | |||||
"module": "ESNext", | |||||
"lib": ["ESNext"], | |||||
"importHelpers": true, | |||||
"declaration": true, | |||||
"sourceMap": true, | |||||
"rootDir": "./src", | |||||
"strict": true, | |||||
"noUnusedLocals": true, | |||||
"noUnusedParameters": true, | |||||
"noImplicitReturns": true, | |||||
"noFallthroughCasesInSwitch": true, | |||||
"moduleResolution": "node", | |||||
"jsx": "react", | |||||
"esModuleInterop": true, | |||||
"target": "es2018", | |||||
"paths": { | |||||
"@/*": ["./src/*"], | |||||
} | |||||
} | |||||
} |
@@ -7,16 +7,27 @@ export interface AddFunction { | |||||
(options: AddFunctionOptions): number; | (options: AddFunctionOptions): number; | ||||
} | } | ||||
export class InvalidArgumentTypeError extends TypeError { | |||||
constructor(message: string) { | |||||
super(message); | |||||
this.name = 'InvalidArgumentTypeError'; | |||||
} | |||||
} | |||||
export class ArgumentOutOfRangeError extends RangeError { | |||||
constructor(message: string) { | |||||
super(message); | |||||
this.name = 'ArgumentOutOfRangeError'; | |||||
} | |||||
} | |||||
export const add: AddFunction = (options: AddFunctionOptions): number => { | export const add: AddFunction = (options: AddFunctionOptions): number => { | ||||
if (process.env.NODE_ENV !== 'production') { | |||||
console.log('This code would not appear on production builds'); | |||||
} | |||||
const { a, b } = options as unknown as Record<string, unknown>; | const { a, b } = options as unknown as Record<string, unknown>; | ||||
if (typeof a !== 'number' || typeof b !== 'number') { | if (typeof a !== 'number' || typeof b !== 'number') { | ||||
throw new TypeError('a and b must be numbers'); | |||||
throw new InvalidArgumentTypeError('a and b must be numbers'); | |||||
} | } | ||||
if (!Number.isFinite(a) || !Number.isFinite(b)) { | if (!Number.isFinite(a) || !Number.isFinite(b)) { | ||||
throw new RangeError('a and b must be finite numbers'); | |||||
throw new ArgumentOutOfRangeError('a and b must be finite numbers'); | |||||
} | } | ||||
return a + b; | return a + b; | ||||
@@ -2,7 +2,15 @@ import { describe, it, expect } from 'vitest'; | |||||
import { add } from '../src'; | import { add } from '../src'; | ||||
describe('blah', () => { | describe('blah', () => { | ||||
it('works', () => { | |||||
it('returns result', () => { | |||||
expect(add({ a: 1, b: 1 })).toEqual(2); | expect(add({ a: 1, b: 1 })).toEqual(2); | ||||
}); | }); | ||||
it('throws when given invalid argument types', () => { | |||||
expect(() => add({ a: '1' as unknown as number, b: 1 })).toThrow(TypeError); | |||||
}); | |||||
it('throws when given out-of-range arguments', () => { | |||||
expect(() => add({ a: Infinity, b: 1 })).toThrow(RangeError); | |||||
}); | |||||
}); | }); |
@@ -50,5 +50,22 @@ | |||||
"author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | "author": "TheoryOfNekomata <allan.crisostomo@outlook.com>", | ||||
"publishConfig": { | "publishConfig": { | ||||
"access": "restricted" | "access": "restricted" | ||||
} | |||||
}, | |||||
"types": "./dist/types/index.d.ts", | |||||
"main": "./dist/cjs/production/index.js", | |||||
"module": "./dist/esm/production/index.js", | |||||
"exports": { | |||||
".": { | |||||
"development": { | |||||
"require": "./dist/cjs/development/index.js", | |||||
"import": "./dist/esm/development/index.js" | |||||
}, | |||||
"require": "./dist/cjs/production/index.js", | |||||
"import": "./dist/esm/production/index.js", | |||||
"types": "./dist/types/index.d.ts" | |||||
} | |||||
}, | |||||
"typesVersions": { | |||||
"*": {} | |||||
} | |||||
} | } |
@@ -1,5 +1,6 @@ | |||||
export namespace meta { | export namespace meta { | ||||
export const host = process.env.HOST ?? '0.0.0.0'; | export const host = process.env.HOST ?? '0.0.0.0'; | ||||
export const port = Number(process.env.PORT ?? 8080); | export const port = Number(process.env.PORT ?? 8080); | ||||
export const env = process.env.NODE_ENV ?? 'development'; | export const env = process.env.NODE_ENV ?? 'development'; | ||||
@@ -2,10 +2,8 @@ import { createServer } from '@/server'; | |||||
import { addRoutes } from '@/routes'; | import { addRoutes } from '@/routes'; | ||||
import * as config from '@/config'; | import * as config from '@/config'; | ||||
const logger = config.meta.env !== 'test'; | |||||
const server = createServer({ | const server = createServer({ | ||||
logger, | |||||
logger: config.meta.env !== 'test', | |||||
}); | }); | ||||
addRoutes(server); | addRoutes(server); | ||||
@@ -0,0 +1,39 @@ | |||||
import { RouteHandlerMethod } from 'fastify'; | |||||
import { | |||||
AdderService, | |||||
AdderServiceImpl, | |||||
ArgumentOutOfRangeError, | |||||
InvalidArgumentTypeError, | |||||
} from '@/modules/adder/adder.service'; | |||||
import { constants } from 'http2'; | |||||
export interface AdderController { | |||||
addNumbers: RouteHandlerMethod; | |||||
} | |||||
export class AdderControllerImpl implements AdderController { | |||||
constructor( | |||||
private readonly adderService: AdderService = new AdderServiceImpl(), | |||||
) { | |||||
// noop | |||||
} | |||||
readonly addNumbers: RouteHandlerMethod = async (request, reply) => { | |||||
const { a, b } = request.body as { a: number; b: number }; | |||||
try { | |||||
const response = this.adderService.addNumbers({a, b}); | |||||
reply.send(response); | |||||
} catch (errorRaw) { | |||||
if (errorRaw instanceof InvalidArgumentTypeError) { | |||||
reply.status(constants.HTTP_STATUS_BAD_REQUEST).send(errorRaw.message); | |||||
return; | |||||
} | |||||
if (errorRaw instanceof ArgumentOutOfRangeError) { | |||||
reply.status(constants.HTTP_STATUS_BAD_REQUEST).send(errorRaw.message); | |||||
return; | |||||
} | |||||
const error = errorRaw as Error; | |||||
reply.status(constants.HTTP_STATUS_INTERNAL_SERVER_ERROR).send(error.message); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,21 @@ | |||||
import { | |||||
add, | |||||
AddFunctionOptions, | |||||
ArgumentOutOfRangeError, | |||||
InvalidArgumentTypeError, | |||||
} from '@modal-sh/core'; | |||||
export interface AdderService { | |||||
addNumbers(options: AddFunctionOptions): number; | |||||
} | |||||
export class AdderServiceImpl implements AdderService { | |||||
addNumbers(options: AddFunctionOptions) { | |||||
return add(options); | |||||
} | |||||
} | |||||
export { | |||||
ArgumentOutOfRangeError, | |||||
InvalidArgumentTypeError, | |||||
}; |
@@ -0,0 +1,2 @@ | |||||
export * from './adder.controller'; | |||||
export * from './adder.service'; |
@@ -1,22 +1,13 @@ | |||||
import { FastifyInstance } from 'fastify'; | import { FastifyInstance } from 'fastify'; | ||||
import { add, AddFunctionOptions } from '@modal-sh/core'; | |||||
import { AdderController, AdderControllerImpl } from '@/modules/adder'; | |||||
export const addRoutes = (server: FastifyInstance) => { | export const addRoutes = (server: FastifyInstance) => { | ||||
server.post('/', async (request, reply) => { | |||||
const { a, b } = request.body as AddFunctionOptions; | |||||
try { | |||||
const response = add({a, b}); | |||||
reply.send(response); | |||||
} catch (errorRaw) { | |||||
if (errorRaw instanceof TypeError) { | |||||
reply.status(400).send(errorRaw.message); | |||||
} else if (errorRaw instanceof RangeError) { | |||||
reply.status(400).send(errorRaw.message); | |||||
} else { | |||||
const error = errorRaw as Error; | |||||
reply.status(500).send(error.message); | |||||
} | |||||
} | |||||
const adderController: AdderController = new AdderControllerImpl(); | |||||
server.route({ | |||||
method: 'POST', | |||||
url: '/', | |||||
handler: adderController.addNumbers, | |||||
}); | }); | ||||
return server; | return server; | ||||
@@ -5,30 +5,83 @@ import { | |||||
expect, | expect, | ||||
beforeAll, | beforeAll, | ||||
afterAll, | afterAll, | ||||
vi, | |||||
} from 'vitest'; | } from 'vitest'; | ||||
import { constants } from 'http2'; | |||||
import { createServer } from '../src/server'; | import { createServer } from '../src/server'; | ||||
import { addRoutes } from '../src/routes'; | import { addRoutes } from '../src/routes'; | ||||
import { | |||||
AdderServiceImpl, | |||||
ArgumentOutOfRangeError, | |||||
InvalidArgumentTypeError, | |||||
} from '../src/modules/adder'; | |||||
describe('Example', () => { | describe('Example', () => { | ||||
let SERVER: FastifyInstance; | |||||
let server: FastifyInstance; | |||||
const body = { a: 1, b: 2 }; | |||||
beforeAll(() => { | beforeAll(() => { | ||||
SERVER = createServer(); | |||||
addRoutes(SERVER); | |||||
server = createServer(); | |||||
addRoutes(server); | |||||
}); | }); | ||||
afterAll(async () => { | afterAll(async () => { | ||||
await SERVER.close(); | |||||
await server.close(); | |||||
}); | }); | ||||
it('should have the expected content', async () => { | |||||
const response = await SERVER | |||||
it('returns result when successful', async () => { | |||||
const response = await server | |||||
.inject() | .inject() | ||||
.post('/') | .post('/') | ||||
.body({ a: 1, b: 2 }) | |||||
.body(body) | |||||
.headers({ | .headers({ | ||||
'Accept': 'application/json', | 'Accept': 'application/json', | ||||
}); | }); | ||||
expect(response.statusCode).toBe(200); | |||||
expect(response.statusCode).toBe(constants.HTTP_STATUS_OK); | |||||
}); | }); | ||||
it('returns error when given invalid inputs', async () => { | |||||
vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { | |||||
throw new InvalidArgumentTypeError('Invalid input'); | |||||
}); | |||||
const response = await server | |||||
.inject() | |||||
.post('/') | |||||
.body(body) | |||||
.headers({ | |||||
'Accept': 'application/json', | |||||
}); | |||||
expect(response.statusCode).toBe(constants.HTTP_STATUS_BAD_REQUEST); | |||||
}); | |||||
it('returns error when given out-of-range inputs', async () => { | |||||
vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { | |||||
throw new ArgumentOutOfRangeError('Out of range'); | |||||
}); | |||||
const response = await server | |||||
.inject() | |||||
.post('/') | |||||
.body(body) | |||||
.headers({ | |||||
'Accept': 'application/json', | |||||
}); | |||||
expect(response.statusCode).toBe(constants.HTTP_STATUS_BAD_REQUEST); | |||||
}); | |||||
it('returns error when an unexpected error occurs', async () => { | |||||
vi.spyOn(AdderServiceImpl.prototype, 'addNumbers').mockImplementationOnce(() => { | |||||
throw new Error('Unexpected error'); | |||||
}); | |||||
const response = await server | |||||
.inject() | |||||
.post('/') | |||||
.body({ a: 1, b: 2 }) | |||||
.headers({ | |||||
'Accept': 'application/json', | |||||
}); | |||||
expect(response.statusCode).toBe(constants.HTTP_STATUS_INTERNAL_SERVER_ERROR); | |||||
}); | |||||
}); | }); |
@@ -6,6 +6,43 @@ settings: | |||||
importers: | importers: | ||||
packages/cli: | |||||
dependencies: | |||||
'@clack/core': | |||||
specifier: ^0.3.2 | |||||
version: 0.3.2 | |||||
'@modal-sh/core': | |||||
specifier: workspace:* | |||||
version: link:../core | |||||
yargs: | |||||
specifier: ^17.7.2 | |||||
version: 17.7.2 | |||||
devDependencies: | |||||
'@types/node': | |||||
specifier: ^18.14.1 | |||||
version: 18.14.1 | |||||
'@types/yargs': | |||||
specifier: ^17.0.24 | |||||
version: 17.0.24 | |||||
eslint: | |||||
specifier: ^8.35.0 | |||||
version: 8.35.0 | |||||
eslint-config-lxsmnsyc: | |||||
specifier: ^0.5.0 | |||||
version: 0.5.0(eslint@8.35.0)(typescript@4.9.5) | |||||
pridepack: | |||||
specifier: 2.4.4 | |||||
version: 2.4.4(eslint@8.35.0)(tslib@2.5.0)(typescript@4.9.5) | |||||
tslib: | |||||
specifier: ^2.5.0 | |||||
version: 2.5.0 | |||||
typescript: | |||||
specifier: ^4.9.5 | |||||
version: 4.9.5 | |||||
vitest: | |||||
specifier: ^0.28.1 | |||||
version: 0.28.1 | |||||
packages/core: | packages/core: | ||||
devDependencies: | devDependencies: | ||||
'@types/node': | '@types/node': | ||||
@@ -332,6 +369,13 @@ packages: | |||||
to-fast-properties: 2.0.0 | to-fast-properties: 2.0.0 | ||||
dev: true | dev: true | ||||
/@clack/core@0.3.2: | |||||
resolution: {integrity: sha512-FZnsNynwGDIDktx6PEZK1EuCkFpY4ldEX6VYvfl0dqeoLPb9Jpw1xoUXaVcGR8ExmYNm1w2vdGdJkEUYD/2pqg==} | |||||
dependencies: | |||||
picocolors: 1.0.0 | |||||
sisteransi: 1.0.5 | |||||
dev: false | |||||
/@esbuild/android-arm64@0.17.19: | /@esbuild/android-arm64@0.17.19: | ||||
resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} | resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} | ||||
engines: {node: '>=12'} | engines: {node: '>=12'} | ||||
@@ -727,6 +771,16 @@ packages: | |||||
resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} | resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} | ||||
dev: true | dev: true | ||||
/@types/yargs-parser@21.0.0: | |||||
resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} | |||||
dev: true | |||||
/@types/yargs@17.0.24: | |||||
resolution: {integrity: sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==} | |||||
dependencies: | |||||
'@types/yargs-parser': 21.0.0 | |||||
dev: true | |||||
/@typescript-eslint/eslint-plugin@5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.35.0)(typescript@4.9.5): | /@typescript-eslint/eslint-plugin@5.60.1(@typescript-eslint/parser@5.60.1)(eslint@8.35.0)(typescript@4.9.5): | ||||
resolution: {integrity: sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw==} | resolution: {integrity: sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw==} | ||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} | ||||
@@ -964,7 +1018,6 @@ packages: | |||||
/ansi-regex@5.0.1: | /ansi-regex@5.0.1: | ||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} | ||||
engines: {node: '>=8'} | engines: {node: '>=8'} | ||||
dev: true | |||||
/ansi-regex@6.0.1: | /ansi-regex@6.0.1: | ||||
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} | resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} | ||||
@@ -983,7 +1036,6 @@ packages: | |||||
engines: {node: '>=8'} | engines: {node: '>=8'} | ||||
dependencies: | dependencies: | ||||
color-convert: 2.0.1 | color-convert: 2.0.1 | ||||
dev: true | |||||
/ansi-styles@5.2.0: | /ansi-styles@5.2.0: | ||||
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} | resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} | ||||
@@ -1280,7 +1332,6 @@ packages: | |||||
string-width: 4.2.3 | string-width: 4.2.3 | ||||
strip-ansi: 6.0.1 | strip-ansi: 6.0.1 | ||||
wrap-ansi: 7.0.0 | wrap-ansi: 7.0.0 | ||||
dev: true | |||||
/clone@1.0.4: | /clone@1.0.4: | ||||
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} | resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} | ||||
@@ -1298,7 +1349,6 @@ packages: | |||||
engines: {node: '>=7.0.0'} | engines: {node: '>=7.0.0'} | ||||
dependencies: | dependencies: | ||||
color-name: 1.1.4 | color-name: 1.1.4 | ||||
dev: true | |||||
/color-name@1.1.3: | /color-name@1.1.3: | ||||
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} | ||||
@@ -1306,7 +1356,6 @@ packages: | |||||
/color-name@1.1.4: | /color-name@1.1.4: | ||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} | ||||
dev: true | |||||
/concat-map@0.0.1: | /concat-map@0.0.1: | ||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} | ||||
@@ -1500,7 +1549,6 @@ packages: | |||||
/emoji-regex@8.0.0: | /emoji-regex@8.0.0: | ||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} | ||||
dev: true | |||||
/emoji-regex@9.2.2: | /emoji-regex@9.2.2: | ||||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} | ||||
@@ -1611,7 +1659,6 @@ packages: | |||||
/escalade@3.1.1: | /escalade@3.1.1: | ||||
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} | ||||
engines: {node: '>=6'} | engines: {node: '>=6'} | ||||
dev: true | |||||
/escape-string-regexp@1.0.5: | /escape-string-regexp@1.0.5: | ||||
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} | ||||
@@ -2268,7 +2315,6 @@ packages: | |||||
/get-caller-file@2.0.5: | /get-caller-file@2.0.5: | ||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} | ||||
engines: {node: 6.* || 8.* || >= 10.*} | engines: {node: 6.* || 8.* || >= 10.*} | ||||
dev: true | |||||
/get-func-name@2.0.0: | /get-func-name@2.0.0: | ||||
resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} | resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} | ||||
@@ -2567,7 +2613,6 @@ packages: | |||||
/is-fullwidth-code-point@3.0.0: | /is-fullwidth-code-point@3.0.0: | ||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} | ||||
engines: {node: '>=8'} | engines: {node: '>=8'} | ||||
dev: true | |||||
/is-fullwidth-code-point@4.0.0: | /is-fullwidth-code-point@4.0.0: | ||||
resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} | resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} | ||||
@@ -3181,7 +3226,6 @@ packages: | |||||
/picocolors@1.0.0: | /picocolors@1.0.0: | ||||
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} | ||||
dev: true | |||||
/picomatch@2.3.1: | /picomatch@2.3.1: | ||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} | ||||
@@ -3383,7 +3427,6 @@ packages: | |||||
/require-directory@2.1.1: | /require-directory@2.1.1: | ||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} | ||||
engines: {node: '>=0.10.0'} | engines: {node: '>=0.10.0'} | ||||
dev: true | |||||
/require-from-string@2.0.2: | /require-from-string@2.0.2: | ||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} | resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} | ||||
@@ -3555,7 +3598,6 @@ packages: | |||||
/sisteransi@1.0.5: | /sisteransi@1.0.5: | ||||
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} | resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} | ||||
dev: true | |||||
/slash@3.0.0: | /slash@3.0.0: | ||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} | ||||
@@ -3625,7 +3667,6 @@ packages: | |||||
emoji-regex: 8.0.0 | emoji-regex: 8.0.0 | ||||
is-fullwidth-code-point: 3.0.0 | is-fullwidth-code-point: 3.0.0 | ||||
strip-ansi: 6.0.1 | strip-ansi: 6.0.1 | ||||
dev: true | |||||
/string-width@5.1.2: | /string-width@5.1.2: | ||||
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} | ||||
@@ -3685,7 +3726,6 @@ packages: | |||||
engines: {node: '>=8'} | engines: {node: '>=8'} | ||||
dependencies: | dependencies: | ||||
ansi-regex: 5.0.1 | ansi-regex: 5.0.1 | ||||
dev: true | |||||
/strip-ansi@7.1.0: | /strip-ansi@7.1.0: | ||||
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} | ||||
@@ -4131,7 +4171,6 @@ packages: | |||||
ansi-styles: 4.3.0 | ansi-styles: 4.3.0 | ||||
string-width: 4.2.3 | string-width: 4.2.3 | ||||
strip-ansi: 6.0.1 | strip-ansi: 6.0.1 | ||||
dev: true | |||||
/wrap-text@1.0.9: | /wrap-text@1.0.9: | ||||
resolution: {integrity: sha512-NWfjspSgMDXQIMpKM56AwCQPI01OMFRYYJBh6dGNCfH7AOl+j/VqqbiopgJ4VuQfSluqLc+2ekqaPNpYAGZ/Vg==} | resolution: {integrity: sha512-NWfjspSgMDXQIMpKM56AwCQPI01OMFRYYJBh6dGNCfH7AOl+j/VqqbiopgJ4VuQfSluqLc+2ekqaPNpYAGZ/Vg==} | ||||
@@ -4167,7 +4206,6 @@ packages: | |||||
/y18n@5.0.8: | /y18n@5.0.8: | ||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} | ||||
engines: {node: '>=10'} | engines: {node: '>=10'} | ||||
dev: true | |||||
/yallist@3.1.1: | /yallist@3.1.1: | ||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} | ||||
@@ -4187,7 +4225,6 @@ packages: | |||||
/yargs-parser@21.1.1: | /yargs-parser@21.1.1: | ||||
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} | resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} | ||||
engines: {node: '>=12'} | engines: {node: '>=12'} | ||||
dev: true | |||||
/yargs@15.4.1: | /yargs@15.4.1: | ||||
resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} | resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} | ||||
@@ -4217,7 +4254,6 @@ packages: | |||||
string-width: 4.2.3 | string-width: 4.2.3 | ||||
y18n: 5.0.8 | y18n: 5.0.8 | ||||
yargs-parser: 21.1.1 | yargs-parser: 21.1.1 | ||||
dev: true | |||||
/yocto-queue@0.1.0: | /yocto-queue@0.1.0: | ||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} | ||||