UNPKG

forest-cli

Version:

The Lumberjacks' toolbelt is the Forest CLI which makes easy to manage your back office application directly from the terminal.

218 lines 17.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const languages_1 = __importDefault(require("../../utils/languages")); const abstract_dumper_1 = __importDefault(require("./abstract-dumper")); class AgentNodeJs extends abstract_dumper_1.default { constructor(context) { const { assertPresent, env, isLinuxOs, buildDatabaseUrl, isDatabaseLocal, lodash, strings, toValidPackageName, logger, } = context; assertPresent({ env, isLinuxOs, buildDatabaseUrl, isDatabaseLocal, lodash, strings, toValidPackageName, logger, }); super(context); this.DEFAULT_PORT = 3310; this.templateFolder = 'agent-nodejs'; this.env = env; this.isLinuxOs = isLinuxOs; this.buildDatabaseUrl = buildDatabaseUrl; this.isDatabaseLocal = isDatabaseLocal; this.lodash = lodash; this.strings = strings; this.toValidPackageName = toValidPackageName; } writePackageJson(language, dbDialect, appName, isDemo = false) { const dependencies = { dotenv: '^16.0.1', '@forestadmin/agent': '^1.0.0', }; if (isDemo) { dependencies['@forestadmin/datasource-demo-fintech'] = '^1.0.1'; } else if (dbDialect === 'mongodb') { dependencies['@forestadmin/datasource-mongo'] = '^1.0.0'; } else { dependencies['@forestadmin/datasource-sql'] = '^1.0.0'; } // The embedded workflow executor runs Forest Admin workflows in-process. It uses an in-memory // run store, so it ships with every project regardless of the datasource and needs no config. dependencies['@forestadmin/workflow-executor'] = '^1.0.0'; if (!isDemo && dbDialect) { if (dbDialect.includes('postgres')) { dependencies.pg = '^8.8.0'; } else if (dbDialect === 'mysql') { dependencies.mysql2 = '^3.0.1'; } else if (dbDialect === 'mariadb') { dependencies.mariadb = '^3.0.2'; } else if (dbDialect === 'mssql') { dependencies.tedious = '^18.6.1'; } } let scripts = { start: 'node ./index.js', 'start:watch': 'nodemon ./index.js', }; const devDependencies = { nodemon: '^3.1.10', }; const nodemonConfig = { ignore: ['./forestadmin-schema.json'], }; if (language === languages_1.default.Typescript) { scripts = { build: 'tsc', start: 'node ./dist/index.js', 'start:watch': 'nodemon ./index.ts', }; devDependencies.typescript = '^4.9.4'; devDependencies['ts-node'] = '^10.9.1'; nodemonConfig.ignore.push('./typings.ts'); } const pkg = { name: this.toValidPackageName(appName), version: '0.0.1', private: true, scripts, nodemonConfig, dependencies, devDependencies, }; this.writeFile('package.json', `${JSON.stringify(pkg, null, 2)}\n`); } writeTsConfigJson() { this.writeFile('tsconfig.json', `${JSON.stringify({ compilerOptions: { experimentalDecorators: true, target: 'ES2020', module: 'CommonJS', moduleResolution: 'Node', esModuleInterop: true, declaration: true, declarationMap: true, inlineSourceMap: true, noImplicitOverride: true, stripInternal: true, outDir: 'dist', skipLibCheck: true, }, 'ts-node': { transpileOnly: true, }, }, null, 2)}\n`); } writeIndex(language, dbDialect, dbSchema, isDemo = false) { const isMongo = dbDialect === 'mongodb'; const context = { isDemo, isMongo, isMySQL: dbDialect === 'mysql', isMSSQL: dbDialect === 'mssql', isMariaDB: dbDialect === 'mariadb', dbSchema, forestServerUrl: this.env.FOREST_URL_IS_DEFAULT ? false : this.env.FOREST_SERVER_URL, }; this.copyHandleBarsTemplate(`${language.name}/index.hbs`, `index.${language.fileExtension}`, context); } writeDotEnv(dbConfig, appPort, forestEnvSecret, forestAuthSecret, isDemo = false) { const context = { isDemo, isMongo: dbConfig.dbDialect === 'mongodb', dbUrl: '', dbSchema: dbConfig.dbSchema, dbSslMode: dbConfig.dbSslMode ?? 'disabled', appPort, forestServerUrl: this.env.FOREST_URL_IS_DEFAULT ? false : this.env.FOREST_SERVER_URL, forestEnvSecret, forestAuthSecret, hasDockerDbUrl: false, dockerDbUrl: '', }; // Demo runs on an in-memory dummy datasource: no DATABASE_URL. if (!isDemo) { const dbUrl = this.buildDatabaseUrl(dbConfig); context.dbUrl = dbUrl; if (!this.isLinuxOs) { context.hasDockerDbUrl = true; context.dockerDbUrl = dbUrl.replace('localhost', 'host.docker.internal'); } } this.copyHandleBarsTemplate('common/env.hbs', '.env', context); } writeGitignore(language) { this.writeFile('.gitignore', `node_modules\n.env\n${language === languages_1.default.Typescript ? 'dist\n' : ''}`); } writeTypings() { this.writeFile('typings.ts', '/* eslint-disable */\nexport type Schema = any;\n'); } writeDockerignore(language) { this.writeFile('.dockerignore', `node_modules\nnpm-debug.log\n.env\n${language === languages_1.default.Typescript ? 'dist\n' : ''}`); } writeDockerfile(language) { this.copyHandleBarsTemplate(`${language.name}/Dockerfile.hbs`, 'Dockerfile'); } writeDockerCompose(config) { const forestServerUrl = this.env.FOREST_URL_IS_DEFAULT ? false : `\${FOREST_SERVER_URL}`; let forestExtraHost = ''; if (forestServerUrl) { try { forestExtraHost = new URL(this.env.FOREST_SERVER_URL).hostname; } catch (error) { throw new Error(`Invalid value for FOREST_SERVER_URL: "${this.env.FOREST_SERVER_URL}"`); } } this.copyHandleBarsTemplate(`${config.language.name}/docker-compose.hbs`, 'docker-compose.yml', { containerName: this.lodash.snakeCase(config.appConfig.appName), forestExtraHost, isLinuxOs: this.isLinuxOs, network: this.isLinuxOs && this.isDatabaseLocal(config.dbConfig) ? 'host' : null, }); } // Demo projects ship a pre-configured forest-layout.json so the panel is curated // out of the box. This only writes the file; applying it (via the `forest layout` // commands) is a separate onboarding step. writeLayoutFile() { this.copyHandleBarsTemplate('common/forest-layout.json', 'forest-layout.json'); this.copyWorkflowBpmnSidecars(); } // The curated workflows ship their compiled BPMN as portable sidecar files // (workflows/<id>.bpmn). `forest layout apply --with-workflows` re-uploads each // one to the target environment's own S3 bucket and links the fresh version, so // the layout file carries no (non-portable) bpmnAwsS3Identifier of its own. copyWorkflowBpmnSidecars() { this.copyTemplateDirectory('common/workflows', 'workflows'); } async createFiles(dumpConfig) { const { isDemo } = dumpConfig; this.writePackageJson(dumpConfig.language, dumpConfig.dbConfig.dbDialect, dumpConfig.appConfig.appName, isDemo); if (dumpConfig.language === languages_1.default.Typescript) { this.writeTsConfigJson(); } this.writeIndex(dumpConfig.language, dumpConfig.dbConfig.dbDialect, dumpConfig.dbConfig.dbSchema, isDemo); this.writeDotEnv(dumpConfig.dbConfig, dumpConfig.appConfig.appPort || this.DEFAULT_PORT, dumpConfig.forestEnvSecret, dumpConfig.forestAuthSecret, isDemo); this.writeTypings(); this.writeGitignore(dumpConfig.language); this.writeDockerignore(dumpConfig.language); this.writeDockerfile(dumpConfig.language); // The demo project has no database, so no docker-compose DB service is needed. if (!isDemo) this.writeDockerCompose(dumpConfig); // Demo projects also get a pre-configured layout file. if (isDemo) this.writeLayoutFile(); } } exports.default = AgentNodeJs; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQtbm9kZWpzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NlcnZpY2VzL2R1bXBlcnMvYWdlbnQtbm9kZWpzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBS0Esc0VBQThDO0FBQzlDLHdFQUErQztBQVcvQyxNQUFxQixXQUFZLFNBQVEseUJBQWM7SUFtQnJELFlBQVksT0FBTztRQUNqQixNQUFNLEVBQ0osYUFBYSxFQUNiLEdBQUcsRUFDSCxTQUFTLEVBQ1QsZ0JBQWdCLEVBQ2hCLGVBQWUsRUFDZixNQUFNLEVBQ04sT0FBTyxFQUNQLGtCQUFrQixFQUNsQixNQUFNLEdBQ1AsR0FBRyxPQUFPLENBQUM7UUFFWixhQUFhLENBQUM7WUFDWixHQUFHO1lBQ0gsU0FBUztZQUNULGdCQUFnQjtZQUNoQixlQUFlO1lBQ2YsTUFBTTtZQUNOLE9BQU87WUFDUCxrQkFBa0I7WUFDbEIsTUFBTTtTQUNQLENBQUMsQ0FBQztRQUVILEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQXhDQSxpQkFBWSxHQUFHLElBQUksQ0FBQztRQWNsQixtQkFBYyxHQUFHLGNBQWMsQ0FBQztRQTRCakQsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7UUFDZixJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztRQUMzQixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsZ0JBQWdCLENBQUM7UUFDekMsSUFBSSxDQUFDLGVBQWUsR0FBRyxlQUFlLENBQUM7UUFDdkMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGtCQUFrQixDQUFDO0lBQy9DLENBQUM7SUFFRCxnQkFBZ0IsQ0FBQyxRQUFrQixFQUFFLFNBQWlCLEVBQUUsT0FBZSxFQUFFLE1BQU0sR0FBRyxLQUFLO1FBQ3JGLE1BQU0sWUFBWSxHQUErQjtZQUMvQyxNQUFNLEVBQUUsU0FBUztZQUNqQixvQkFBb0IsRUFBRSxRQUFRO1NBQy9CLENBQUM7UUFFRixJQUFJLE1BQU0sRUFBRTtZQUNWLFlBQVksQ0FBQyxzQ0FBc0MsQ0FBQyxHQUFHLFFBQVEsQ0FBQztTQUNqRTthQUFNLElBQUksU0FBUyxLQUFLLFNBQVMsRUFBRTtZQUNsQyxZQUFZLENBQUMsK0JBQStCLENBQUMsR0FBRyxRQUFRLENBQUM7U0FDMUQ7YUFBTTtZQUNMLFlBQVksQ0FBQyw2QkFBNkIsQ0FBQyxHQUFHLFFBQVEsQ0FBQztTQUN4RDtRQUVELDhGQUE4RjtRQUM5Riw4RkFBOEY7UUFDOUYsWUFBWSxDQUFDLGdDQUFnQyxDQUFDLEdBQUcsUUFBUSxDQUFDO1FBRTFELElBQUksQ0FBQyxNQUFNLElBQUksU0FBUyxFQUFFO1lBQ3hCLElBQUksU0FBUyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRTtnQkFDbEMsWUFBWSxDQUFDLEVBQUUsR0FBRyxRQUFRLENBQUM7YUFDNUI7aUJBQU0sSUFBSSxTQUFTLEtBQUssT0FBTyxFQUFFO2dCQUNoQyxZQUFZLENBQUMsTUFBTSxHQUFHLFFBQVEsQ0FBQzthQUNoQztpQkFBTSxJQUFJLFNBQVMsS0FBSyxTQUFTLEVBQUU7Z0JBQ2xDLFlBQVksQ0FBQyxPQUFPLEdBQUcsUUFBUSxDQUFDO2FBQ2pDO2lCQUFNLElBQUksU0FBUyxLQUFLLE9BQU8sRUFBRTtnQkFDaEMsWUFBWSxDQUFDLE9BQU8sR0FBRyxTQUFTLENBQUM7YUFDbEM7U0FDRjtRQUVELElBQUksT0FBTyxHQUErQjtZQUN4QyxLQUFLLEVBQUUsaUJBQWlCO1lBQ3hCLGFBQWEsRUFBRSxvQkFBb0I7U0FDcEMsQ0FBQztRQUNGLE1BQU0sZUFBZSxHQUErQjtZQUNsRCxPQUFPLEVBQUUsU0FBUztTQUNuQixDQUFDO1FBQ0YsTUFBTSxhQUFhLEdBQUc7WUFDcEIsTUFBTSxFQUFFLENBQUMsMkJBQTJCLENBQUM7U0FDdEMsQ0FBQztRQUVGLElBQUksUUFBUSxLQUFLLG1CQUFTLENBQUMsVUFBVSxFQUFFO1lBQ3JDLE9BQU8sR0FBRztnQkFDUixLQUFLLEVBQUUsS0FBSztnQkFDWixLQUFLLEVBQUUsc0JBQXNCO2dCQUM3QixhQUFhLEVBQUUsb0JBQW9CO2FBQ3BDLENBQUM7WUFDRixlQUFlLENBQUMsVUFBVSxHQUFHLFFBQVEsQ0FBQztZQUN0QyxlQUFlLENBQUMsU0FBUyxDQUFDLEdBQUcsU0FBUyxDQUFDO1lBQ3ZDLGFBQWEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1NBQzNDO1FBRUQsTUFBTSxHQUFHLEdBQUc7WUFDVixJQUFJLEVBQUUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQztZQUN0QyxPQUFPLEVBQUUsT0FBTztZQUNoQixPQUFPLEVBQUUsSUFBSTtZQUNiLE9BQU87WUFDUCxhQUFhO1lBQ2IsWUFBWTtZQUNaLGVBQWU7U0FDaEIsQ0FBQztRQUVGLElBQUksQ0FBQyxTQUFTLENBQUMsY0FBYyxFQUFFLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBRUQsaUJBQWlCO1FBQ2YsSUFBSSxDQUFDLFNBQVMsQ0FDWixlQUFlLEVBQ2YsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUNmO1lBQ0UsZUFBZSxFQUFFO2dCQUNmLHNCQUFzQixFQUFFLElBQUk7Z0JBQzVCLE1BQU0sRUFBRSxRQUFRO2dCQUNoQixNQUFNLEVBQUUsVUFBVTtnQkFDbEIsZ0JBQWdCLEVBQUUsTUFBTTtnQkFDeEIsZUFBZSxFQUFFLElBQUk7Z0JBQ3JCLFdBQVcsRUFBRSxJQUFJO2dCQUNqQixjQUFjLEVBQUUsSUFBSTtnQkFDcEIsZUFBZSxFQUFFLElBQUk7Z0JBQ3JCLGtCQUFrQixFQUFFLElBQUk7Z0JBQ3hCLGFBQWEsRUFBRSxJQUFJO2dCQUNuQixNQUFNLEVBQUUsTUFBTTtnQkFDZCxZQUFZLEVBQUUsSUFBSTthQUNuQjtZQUNELFNBQVMsRUFBRTtnQkFDVCxhQUFhLEVBQUUsSUFBSTthQUNwQjtTQUNGLEVBQ0QsSUFBSSxFQUNKLENBQUMsQ0FDRixJQUFJLENBQ04sQ0FBQztJQUNKLENBQUM7SUFFRCxVQUFVLENBQUMsUUFBa0IsRUFBRSxTQUFpQixFQUFFLFFBQWdCLEVBQUUsTUFBTSxHQUFHLEtBQUs7UUFDaEYsTUFBTSxPQUFPLEdBQUcsU0FBUyxLQUFLLFNBQVMsQ0FBQztRQUV4QyxNQUFNLE9BQU8sR0FBRztZQUNkLE1BQU07WUFDTixPQUFPO1lBQ1AsT0FBTyxFQUFFLFNBQVMsS0FBSyxPQUFPO1lBQzlCLE9BQU8sRUFBRSxTQUFTLEtBQUssT0FBTztZQUM5QixTQUFTLEVBQUUsU0FBUyxLQUFLLFNBQVM7WUFDbEMsUUFBUTtZQUNSLGVBQWUsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsaUJBQWlCO1NBQ3JGLENBQUM7UUFFRixJQUFJLENBQUMsc0JBQXNCLENBQ3pCLEdBQUcsUUFBUSxDQUFDLElBQUksWUFBWSxFQUM1QixTQUFTLFFBQVEsQ0FBQyxhQUFhLEVBQUUsRUFDakMsT0FBTyxDQUNSLENBQUM7SUFDSixDQUFDO0lBRU8sV0FBVyxDQUNqQixRQUFrQixFQUNsQixPQUFlLEVBQ2YsZUFBdUIsRUFDdkIsZ0JBQXdCLEVBQ3hCLE1BQU0sR0FBRyxLQUFLO1FBRWQsTUFBTSxPQUFPLEdBQUc7WUFDZCxNQUFNO1lBQ04sT0FBTyxFQUFFLFFBQVEsQ0FBQyxTQUFTLEtBQUssU0FBUztZQUN6QyxLQUFLLEVBQUUsRUFBRTtZQUNULFFBQVEsRUFBRSxRQUFRLENBQUMsUUFBUTtZQUMzQixTQUFTLEVBQUUsUUFBUSxDQUFDLFNBQVMsSUFBSSxVQUFVO1lBQzNDLE9BQU87WUFDUCxlQUFlLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLGlCQUFpQjtZQUNwRixlQUFlO1lBQ2YsZ0JBQWdCO1lBQ2hCLGNBQWMsRUFBRSxLQUFLO1lBQ3JCLFdBQVcsRUFBRSxFQUFFO1NBQ2hCLENBQUM7UUFFRiwrREFBK0Q7UUFDL0QsSUFBSSxDQUFDLE1BQU0sRUFBRTtZQUNYLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUM5QyxPQUFPLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztZQUV0QixJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRTtnQkFDbkIsT0FBTyxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7Z0JBQzlCLE9BQU8sQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsc0JBQXNCLENBQUMsQ0FBQzthQUMxRTtTQUNGO1FBRUQsSUFBSSxDQUFDLHNCQUFzQixDQUFDLGdCQUFnQixFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNqRSxDQUFDO0lBRU8sY0FBYyxDQUFDLFFBQWtCO1FBQ3ZDLElBQUksQ0FBQyxTQUFTLENBQ1osWUFBWSxFQUNaLHVCQUF1QixRQUFRLEtBQUssbUJBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQzNFLENBQUM7SUFDSixDQUFDO0lBRU8sWUFBWTtRQUNsQixJQUFJLENBQUMsU0FBUyxDQUFDLFlBQVksRUFBRSxtREFBbUQsQ0FBQyxDQUFDO0lBQ3BGLENBQUM7SUFFTyxpQkFBaUIsQ0FBQyxRQUFrQjtRQUMxQyxJQUFJLENBQUMsU0FBUyxDQUNaLGVBQWUsRUFDZixzQ0FBc0MsUUFBUSxLQUFLLG1CQUFTLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUMxRixDQUFDO0lBQ0osQ0FBQztJQUVPLGVBQWUsQ0FBQyxRQUFrQjtRQUN4QyxJQUFJLENBQUMsc0JBQXNCLENBQUMsR0FBRyxRQUFRLENBQUMsSUFBSSxpQkFBaUIsRUFBRSxZQUFZLENBQUMsQ0FBQztJQUMvRSxDQUFDO0lBRU8sa0JBQWtCLENBQUMsTUFBYztRQUN2QyxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLHVCQUF1QixDQUFDO1FBRXpGLElBQUksZUFBZSxHQUFHLEVBQUUsQ0FBQztRQUN6QixJQUFJLGVBQWUsRUFBRTtZQUNuQixJQUFJO2dCQUNGLGVBQWUsR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFDLENBQUMsUUFBUSxDQUFDO2FBQ2hFO1lBQUMsT0FBTyxLQUFLLEVBQUU7Z0JBQ2QsTUFBTSxJQUFJLEtBQUssQ0FBQyx5Q0FBeUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLENBQUM7YUFDekY7U0FDRjtRQUVELElBQUksQ0FBQyxzQkFBc0IsQ0FDekIsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUkscUJBQXFCLEVBQzVDLG9CQUFvQixFQUNwQjtZQUNFLGFBQWEsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQztZQUM5RCxlQUFlO1lBQ2YsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTO1lBQ3pCLE9BQU8sRUFBRSxJQUFJLENBQUMsU0FBUyxJQUFJLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUk7U0FDakYsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVELGlGQUFpRjtJQUNqRixrRkFBa0Y7SUFDbEYsMkNBQTJDO0lBQ25DLGVBQWU7UUFDckIsSUFBSSxDQUFDLHNCQUFzQixDQUFDLDJCQUEyQixFQUFFLG9CQUFvQixDQUFDLENBQUM7UUFDL0UsSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7SUFDbEMsQ0FBQztJQUVELDJFQUEyRTtJQUMzRSxnRkFBZ0Y7SUFDaEYsZ0ZBQWdGO0lBQ2hGLDRFQUE0RTtJQUNwRSx3QkFBd0I7UUFDOUIsSUFBSSxDQUFDLHFCQUFxQixDQUFDLGtCQUFrQixFQUFFLFdBQVcsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFUyxLQUFLLENBQUMsV0FBVyxDQUFDLFVBQWtCO1FBQzVDLE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxVQUFVLENBQUM7UUFFOUIsSUFBSSxDQUFDLGdCQUFnQixDQUNuQixVQUFVLENBQUMsUUFBUSxFQUNuQixVQUFVLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFDN0IsVUFBVSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQzVCLE1BQU0sQ0FDUCxDQUFDO1FBQ0YsSUFBSSxVQUFVLENBQUMsUUFBUSxLQUFLLG1CQUFTLENBQUMsVUFBVSxFQUFFO1lBQ2hELElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1NBQzFCO1FBQ0QsSUFBSSxDQUFDLFVBQVUsQ0FDYixVQUFVLENBQUMsUUFBUSxFQUNuQixVQUFVLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFDN0IsVUFBVSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQzVCLE1BQU0sQ0FDUCxDQUFDO1FBQ0YsSUFBSSxDQUFDLFdBQVcsQ0FDZCxVQUFVLENBQUMsUUFBUSxFQUNuQixVQUFVLENBQUMsU0FBUyxDQUFDLE9BQU8sSUFBSSxJQUFJLENBQUMsWUFBWSxFQUNqRCxVQUFVLENBQUMsZUFBZSxFQUMxQixVQUFVLENBQUMsZ0JBQWdCLEVBQzNCLE1BQU0sQ0FDUCxDQUFDO1FBQ0YsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3BCLElBQUksQ0FBQyxjQUFjLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDNUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUMsK0VBQStFO1FBQy9FLElBQUksQ0FBQyxNQUFNO1lBQUUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2pELHVEQUF1RDtRQUN2RCxJQUFJLE1BQU07WUFBRSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDckMsQ0FBQztDQUNGO0FBM1NELDhCQTJTQyJ9