@decohere/scaffold 0.0.1-dev.18 → 0.0.1-dev.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commonjs/src/add-api.action.js +39 -0
- package/commonjs/src/add-api.command.js +41 -0
- package/commonjs/src/add.command.js +24 -0
- package/commonjs/src/add.module.js +26 -0
- package/commonjs/src/cli.js +9 -0
- package/commonjs/src/create.command.js +24 -0
- package/commonjs/src/create.module.js +26 -0
- package/commonjs/src/domain/prompt.js +64 -0
- package/commonjs/src/index.js +38 -0
- package/commonjs/src/models/compose.model.js +150 -0
- package/commonjs/src/models/config-yaml.model.js +88 -0
- package/commonjs/src/models/const.js +32 -0
- package/commonjs/src/models/dev-container.model.js +116 -0
- package/commonjs/src/models/docker-image.model.js +259 -0
- package/commonjs/src/models/env-file.model.js +50 -0
- package/commonjs/src/models/gitignore.model.js +43 -0
- package/commonjs/src/models/launch-json.model.js +74 -0
- package/commonjs/src/models/package-json.model.js +149 -0
- package/commonjs/src/models/project.model.js +134 -0
- package/commonjs/src/models/source-file.js +6 -0
- package/commonjs/src/models/tsconfig.model.js +34 -0
- package/commonjs/src/models/vitest-config.model.js +35 -0
- package/commonjs/src/models/vscode-settings.model.js +31 -0
- package/commonjs/src/program.js +57 -0
- package/commonjs/src/resolve-target-dir.js +19 -0
- package/commonjs/src/services/scaffold.service.js +62 -0
- package/commonjs/src/version.js +57 -0
- package/commonjs/src/webapi/api-name.js +95 -0
- package/commonjs/src/webapi/cli-options.js +101 -0
- package/commonjs/src/webapi/const.js +50 -0
- package/commonjs/src/webapi/create-api.js +237 -0
- package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.js +166 -0
- package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
- package/commonjs/src/webapi/devcontainer/host-scripts.js +52 -0
- package/commonjs/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
- package/commonjs/src/webapi/devcontainer/templates/initialize.sh +169 -0
- package/commonjs/src/webapi/devcontainer/templates/post-create.sh +35 -0
- package/commonjs/src/webapi/devcontainer/templates/post-start.sh +65 -0
- package/commonjs/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
- package/commonjs/src/webapi/features/auth.feature.js +441 -0
- package/commonjs/src/webapi/features/auth0-cli.js +435 -0
- package/commonjs/src/webapi/features/biome-format.js +49 -0
- package/commonjs/src/webapi/features/database.feature.js +433 -0
- package/commonjs/src/webapi/features/finalize.feature.js +95 -0
- package/commonjs/src/webapi/features/postman.feature.js +324 -0
- package/commonjs/src/webapi/models/api-package-json.model.js +60 -0
- package/commonjs/src/webapi/models/auth-config.model.js +26 -0
- package/commonjs/src/webapi/models/controller-source-file.model.js +193 -0
- package/commonjs/src/webapi/models/github-ci.model.js +193 -0
- package/commonjs/src/webapi/models/main-source-file.model.js +167 -0
- package/commonjs/src/webapi/models/production-dockerfile.model.js +157 -0
- package/commonjs/src/webapi/models/sample-files.model.js +60 -0
- package/commonjs/src/webapi/models/webapi-image.model.js +27 -0
- package/commonjs/src/webapi/postman/hello-openapi.js +175 -0
- package/commonjs/src/webapi/postman/local-view.js +184 -0
- package/commonjs/src/webapi/postman/openapi-to-postman.js +202 -0
- package/commonjs/src/webapi/workspace-readme.js +110 -0
- package/commonjs/src/webapi.action.js +30 -0
- package/commonjs/src/webapi.command.js +45 -0
- package/es6/src/add-api.action.js +29 -0
- package/es6/src/add-api.command.js +31 -0
- package/es6/src/add.command.js +14 -0
- package/es6/src/add.module.js +16 -0
- package/es6/src/cli.js +5 -0
- package/es6/src/create.command.js +14 -0
- package/es6/src/create.module.js +16 -0
- package/es6/src/domain/prompt.js +43 -0
- package/es6/src/index.js +8 -0
- package/es6/src/models/compose.model.js +144 -0
- package/es6/src/models/config-yaml.model.js +76 -0
- package/es6/src/models/const.js +22 -0
- package/es6/src/models/dev-container.model.js +106 -0
- package/es6/src/models/docker-image.model.js +217 -0
- package/es6/src/models/env-file.model.js +46 -0
- package/es6/src/models/gitignore.model.js +33 -0
- package/es6/src/models/launch-json.model.js +64 -0
- package/es6/src/models/package-json.model.js +137 -0
- package/es6/src/models/project.model.js +119 -0
- package/es6/src/models/source-file.js +3 -0
- package/es6/src/models/tsconfig.model.js +24 -0
- package/es6/src/models/vitest-config.model.js +25 -0
- package/es6/src/models/vscode-settings.model.js +21 -0
- package/es6/src/program.js +39 -0
- package/es6/src/resolve-target-dir.js +9 -0
- package/es6/src/services/scaffold.service.js +52 -0
- package/es6/src/version.js +36 -0
- package/es6/src/webapi/api-name.js +59 -0
- package/es6/src/webapi/cli-options.js +36 -0
- package/es6/src/webapi/const.js +20 -0
- package/es6/src/webapi/create-api.js +217 -0
- package/es6/src/webapi/devcontainer/codebase-rag-mcp.js +156 -0
- package/es6/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
- package/es6/src/webapi/devcontainer/host-scripts.js +31 -0
- package/es6/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
- package/es6/src/webapi/devcontainer/templates/initialize.sh +169 -0
- package/es6/src/webapi/devcontainer/templates/post-create.sh +35 -0
- package/es6/src/webapi/devcontainer/templates/post-start.sh +65 -0
- package/es6/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
- package/es6/src/webapi/features/auth.feature.js +390 -0
- package/es6/src/webapi/features/auth0-cli.js +375 -0
- package/es6/src/webapi/features/biome-format.js +42 -0
- package/es6/src/webapi/features/database.feature.js +423 -0
- package/es6/src/webapi/features/finalize.feature.js +85 -0
- package/es6/src/webapi/features/postman.feature.js +258 -0
- package/es6/src/webapi/models/api-package-json.model.js +55 -0
- package/es6/src/webapi/models/auth-config.model.js +22 -0
- package/es6/src/webapi/models/controller-source-file.model.js +184 -0
- package/es6/src/webapi/models/github-ci.model.js +186 -0
- package/es6/src/webapi/models/main-source-file.model.js +163 -0
- package/es6/src/webapi/models/production-dockerfile.model.js +148 -0
- package/es6/src/webapi/models/sample-files.model.js +42 -0
- package/es6/src/webapi/models/webapi-image.model.js +20 -0
- package/es6/src/webapi/postman/hello-openapi.js +168 -0
- package/es6/src/webapi/postman/local-view.js +169 -0
- package/es6/src/webapi/postman/openapi-to-postman.js +179 -0
- package/es6/src/webapi/workspace-readme.js +89 -0
- package/es6/src/webapi.action.js +20 -0
- package/es6/src/webapi.command.js +35 -0
- package/package.json +8 -8
- package/types/src/add-api.action.d.ts +13 -0
- package/types/src/add-api.command.d.ts +7 -0
- package/types/src/add.command.d.ts +6 -0
- package/types/src/add.module.d.ts +14 -0
- package/types/src/cli.d.ts +2 -0
- package/types/src/create.command.d.ts +6 -0
- package/types/src/create.module.d.ts +14 -0
- package/types/src/domain/prompt.d.ts +4 -0
- package/types/src/models/compose.model.d.ts +64 -0
- package/types/src/models/config-yaml.model.d.ts +27 -0
- package/types/src/models/const.d.ts +20 -0
- package/types/src/models/dev-container.model.d.ts +37 -0
- package/types/src/models/docker-image.model.d.ts +84 -0
- package/types/src/models/env-file.model.d.ts +16 -0
- package/types/src/models/gitignore.model.d.ts +7 -0
- package/types/src/models/launch-json.model.d.ts +7 -0
- package/types/src/models/package-json.model.d.ts +35 -0
- package/types/src/models/project.model.d.ts +60 -0
- package/{src/models/source-file.ts → types/src/models/source-file.d.ts} +4 -6
- package/types/src/models/tsconfig.model.d.ts +5 -0
- package/types/src/models/vitest-config.model.d.ts +5 -0
- package/types/src/models/vscode-settings.model.d.ts +7 -0
- package/types/src/program.d.ts +3 -0
- package/{src/resolve-target-dir.ts → types/src/resolve-target-dir.d.ts} +1 -4
- package/types/src/services/scaffold.service.d.ts +22 -0
- package/types/src/version.d.ts +6 -0
- package/types/src/webapi/api-name.d.ts +14 -0
- package/types/src/webapi/cli-options.d.ts +6 -0
- package/{src/webapi/const.ts → types/src/webapi/const.d.ts} +7 -21
- package/types/src/webapi/create-api.d.ts +15 -0
- package/types/src/webapi/devcontainer/codebase-rag-mcp.d.ts +32 -0
- package/types/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
- package/types/src/webapi/devcontainer/host-scripts.d.ts +7 -0
- package/types/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
- package/types/src/webapi/devcontainer/templates/initialize.sh +169 -0
- package/types/src/webapi/devcontainer/templates/post-create.sh +35 -0
- package/types/src/webapi/devcontainer/templates/post-start.sh +65 -0
- package/types/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
- package/types/src/webapi/features/auth.feature.d.ts +10 -0
- package/types/src/webapi/features/auth0-cli.d.ts +80 -0
- package/types/src/webapi/features/biome-format.d.ts +5 -0
- package/types/src/webapi/features/database.feature.d.ts +7 -0
- package/types/src/webapi/features/finalize.feature.d.ts +2 -0
- package/types/src/webapi/features/postman.feature.d.ts +16 -0
- package/types/src/webapi/models/api-package-json.model.d.ts +18 -0
- package/types/src/webapi/models/auth-config.model.d.ts +26 -0
- package/types/src/webapi/models/controller-source-file.model.d.ts +46 -0
- package/types/src/webapi/models/github-ci.model.d.ts +9 -0
- package/types/src/webapi/models/main-source-file.model.d.ts +54 -0
- package/types/src/webapi/models/production-dockerfile.model.d.ts +23 -0
- package/types/src/webapi/models/sample-files.model.d.ts +7 -0
- package/types/src/webapi/models/webapi-image.model.d.ts +12 -0
- package/types/src/webapi/postman/hello-openapi.d.ts +19 -0
- package/types/src/webapi/postman/local-view.d.ts +17 -0
- package/types/src/webapi/postman/openapi-to-postman.d.ts +62 -0
- package/types/src/webapi/workspace-readme.d.ts +18 -0
- package/types/src/webapi.action.d.ts +14 -0
- package/types/src/webapi.command.d.ts +11 -0
- package/src/add-api.action.ts +0 -25
- package/src/add-api.command.ts +0 -31
- package/src/add.command.ts +0 -20
- package/src/add.module.ts +0 -11
- package/src/cli.ts +0 -4
- package/src/create.command.ts +0 -20
- package/src/create.module.ts +0 -11
- package/src/domain/prompt.ts +0 -50
- package/src/models/compose.model.ts +0 -205
- package/src/models/config-yaml.model.ts +0 -83
- package/src/models/const.ts +0 -20
- package/src/models/dev-container.model.ts +0 -136
- package/src/models/docker-image.model.ts +0 -343
- package/src/models/env-file.model.ts +0 -45
- package/src/models/gitignore.model.ts +0 -35
- package/src/models/launch-json.model.ts +0 -60
- package/src/models/package-json.model.ts +0 -169
- package/src/models/project.model.ts +0 -141
- package/src/models/tsconfig.model.ts +0 -29
- package/src/models/vitest-config.model.ts +0 -26
- package/src/models/vscode-settings.model.ts +0 -24
- package/src/program.ts +0 -63
- package/src/services/scaffold.service.ts +0 -89
- package/src/version.ts +0 -56
- package/src/webapi/api-name.ts +0 -73
- package/src/webapi/cli-options.ts +0 -56
- package/src/webapi/create-api.ts +0 -275
- package/src/webapi/devcontainer/host-scripts.ts +0 -35
- package/src/webapi/features/auth.feature.ts +0 -454
- package/src/webapi/features/auth0-cli.ts +0 -421
- package/src/webapi/features/biome-format.ts +0 -34
- package/src/webapi/features/database.feature.ts +0 -522
- package/src/webapi/features/finalize.feature.ts +0 -112
- package/src/webapi/features/postman.feature.ts +0 -287
- package/src/webapi/models/api-package-json.model.ts +0 -60
- package/src/webapi/models/auth-config.model.ts +0 -36
- package/src/webapi/models/controller-source-file.model.ts +0 -232
- package/src/webapi/models/github-ci.model.ts +0 -188
- package/src/webapi/models/main-source-file.model.ts +0 -208
- package/src/webapi/models/production-dockerfile.model.ts +0 -162
- package/src/webapi/models/sample-files.model.ts +0 -45
- package/src/webapi/models/webapi-image.model.ts +0 -21
- package/src/webapi/postman/hello-openapi.ts +0 -92
- package/src/webapi/postman/local-view.ts +0 -195
- package/src/webapi/postman/openapi-to-postman.ts +0 -208
- package/src/webapi/workspace-readme.ts +0 -192
- package/src/webapi.action.ts +0 -22
- package/src/webapi.command.ts +0 -41
- package/tests/auth-postman.wiring.spec.ts +0 -263
- package/tests/auth0-cli.spec.ts +0 -232
- package/tests/biome-format.spec.ts +0 -49
- package/tests/cli.integration.spec.ts +0 -658
- package/tests/compose.model.spec.ts +0 -51
- package/tests/container-image.model.spec.ts +0 -162
- package/tests/dev-container.model.spec.ts +0 -29
- package/tests/devcontainer-base-image.spec.ts +0 -32
- package/tests/hello-di-inject.scaffold.spec.ts +0 -18
- package/tests/hello-route.contract.spec.ts +0 -94
- package/tests/package-json.order.spec.ts +0 -59
- package/tests/postman-from-openapi.spec.ts +0 -197
- package/tests/seed-devcontainer-templates.ts +0 -40
- package/tests/webapi/devcontainer/codebase-rag-mcp.spec.ts +0 -96
- /package/{src/index.ts → types/src/index.d.ts} +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { resolveTargetDir } from "../resolve-target-dir.js";
|
|
2
|
+
import { parseApiNames } from "./api-name.js";
|
|
3
|
+
import { scaffoldApi } from "./create-api.js";
|
|
4
|
+
export function collectName(value, previous) {
|
|
5
|
+
previous.push(value);
|
|
6
|
+
return previous;
|
|
7
|
+
}
|
|
8
|
+
export function addWebapiFeatureOptions(cmd) {
|
|
9
|
+
return cmd.option("--database <provider>", "Database provider: none | postgres/typeorm").option("--auth <provider>", "Auth provider: none | auth0").option("--postman <provider>", "Postman provider: none | local | api").option("-y, --yes", "Install dependencies without prompting").option("--install <mode>", "Dependency install mode: ask | yes | no", "ask");
|
|
10
|
+
}
|
|
11
|
+
export function toApiOptions(directory, opts, extra = {}) {
|
|
12
|
+
const installMode = String(opts.install ?? "ask").toLowerCase();
|
|
13
|
+
const names = Array.isArray(opts.name) ? opts.name : typeof opts.name === "string" ? [
|
|
14
|
+
opts.name
|
|
15
|
+
] : extra.names;
|
|
16
|
+
return {
|
|
17
|
+
d: resolveTargetDir(directory, typeof opts.d === "string" ? opts.d : undefined),
|
|
18
|
+
databaseProvider: opts.database,
|
|
19
|
+
authProvider: opts.auth,
|
|
20
|
+
postmanProvider: opts.postman,
|
|
21
|
+
installDependencies: opts.yes === true ? "yes" : installMode === "yes" || installMode === "no" ? installMode : undefined,
|
|
22
|
+
names,
|
|
23
|
+
...extra
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export async function runScaffoldApi(normalized) {
|
|
27
|
+
parseApiNames(normalized.names);
|
|
28
|
+
const { closePrompt } = await import("../domain/prompt.js");
|
|
29
|
+
try {
|
|
30
|
+
await scaffoldApi(normalized);
|
|
31
|
+
} finally{
|
|
32
|
+
closePrompt();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjYWZmb2xkL3NyYy93ZWJhcGkvY2xpLW9wdGlvbnMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiO1xuaW1wb3J0IHsgcmVzb2x2ZVRhcmdldERpciB9IGZyb20gXCIuLi9yZXNvbHZlLXRhcmdldC1kaXIuanNcIjtcbmltcG9ydCB7IHBhcnNlQXBpTmFtZXMgfSBmcm9tIFwiLi9hcGktbmFtZS5qc1wiO1xuaW1wb3J0IHR5cGUgeyBBcGlPcHRpb25zIH0gZnJvbSBcIi4vY3JlYXRlLWFwaS5qc1wiO1xuaW1wb3J0IHsgc2NhZmZvbGRBcGkgfSBmcm9tIFwiLi9jcmVhdGUtYXBpLmpzXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBjb2xsZWN0TmFtZSh2YWx1ZTogc3RyaW5nLCBwcmV2aW91czogc3RyaW5nW10pOiBzdHJpbmdbXSB7XG5cdHByZXZpb3VzLnB1c2godmFsdWUpO1xuXHRyZXR1cm4gcHJldmlvdXM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhZGRXZWJhcGlGZWF0dXJlT3B0aW9ucyhjbWQ6IENvbW1hbmQpOiBDb21tYW5kIHtcblx0cmV0dXJuIGNtZFxuXHRcdC5vcHRpb24oXCItLWRhdGFiYXNlIDxwcm92aWRlcj5cIiwgXCJEYXRhYmFzZSBwcm92aWRlcjogbm9uZSB8IHBvc3RncmVzL3R5cGVvcm1cIilcblx0XHQub3B0aW9uKFwiLS1hdXRoIDxwcm92aWRlcj5cIiwgXCJBdXRoIHByb3ZpZGVyOiBub25lIHwgYXV0aDBcIilcblx0XHQub3B0aW9uKFwiLS1wb3N0bWFuIDxwcm92aWRlcj5cIiwgXCJQb3N0bWFuIHByb3ZpZGVyOiBub25lIHwgbG9jYWwgfCBhcGlcIilcblx0XHQub3B0aW9uKFwiLXksIC0teWVzXCIsIFwiSW5zdGFsbCBkZXBlbmRlbmNpZXMgd2l0aG91dCBwcm9tcHRpbmdcIilcblx0XHQub3B0aW9uKFwiLS1pbnN0YWxsIDxtb2RlPlwiLCBcIkRlcGVuZGVuY3kgaW5zdGFsbCBtb2RlOiBhc2sgfCB5ZXMgfCBub1wiLCBcImFza1wiKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRvQXBpT3B0aW9ucyhcblx0ZGlyZWN0b3J5OiBzdHJpbmcgfCB1bmRlZmluZWQsXG5cdG9wdHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuXHRleHRyYTogUGFydGlhbDxBcGlPcHRpb25zPiA9IHt9LFxuKTogQXBpT3B0aW9ucyB7XG5cdGNvbnN0IGluc3RhbGxNb2RlID0gU3RyaW5nKG9wdHMuaW5zdGFsbCA/PyBcImFza1wiKS50b0xvd2VyQ2FzZSgpO1xuXHRjb25zdCBuYW1lcyA9IEFycmF5LmlzQXJyYXkob3B0cy5uYW1lKVxuXHRcdD8gKG9wdHMubmFtZSBhcyBzdHJpbmdbXSlcblx0XHQ6IHR5cGVvZiBvcHRzLm5hbWUgPT09IFwic3RyaW5nXCJcblx0XHRcdD8gW29wdHMubmFtZV1cblx0XHRcdDogZXh0cmEubmFtZXM7XG5cdHJldHVybiB7XG5cdFx0ZDogcmVzb2x2ZVRhcmdldERpcihkaXJlY3RvcnksIHR5cGVvZiBvcHRzLmQgPT09IFwic3RyaW5nXCIgPyBvcHRzLmQgOiB1bmRlZmluZWQpLFxuXHRcdGRhdGFiYXNlUHJvdmlkZXI6IG9wdHMuZGF0YWJhc2UgYXMgQXBpT3B0aW9uc1tcImRhdGFiYXNlUHJvdmlkZXJcIl0sXG5cdFx0YXV0aFByb3ZpZGVyOiBvcHRzLmF1dGggYXMgQXBpT3B0aW9uc1tcImF1dGhQcm92aWRlclwiXSxcblx0XHRwb3N0bWFuUHJvdmlkZXI6IG9wdHMucG9zdG1hbiBhcyBBcGlPcHRpb25zW1wicG9zdG1hblByb3ZpZGVyXCJdLFxuXHRcdGluc3RhbGxEZXBlbmRlbmNpZXM6XG5cdFx0XHRvcHRzLnllcyA9PT0gdHJ1ZVxuXHRcdFx0XHQ/IFwieWVzXCJcblx0XHRcdFx0OiBpbnN0YWxsTW9kZSA9PT0gXCJ5ZXNcIiB8fCBpbnN0YWxsTW9kZSA9PT0gXCJub1wiXG5cdFx0XHRcdFx0PyBpbnN0YWxsTW9kZVxuXHRcdFx0XHRcdDogdW5kZWZpbmVkLFxuXHRcdG5hbWVzLFxuXHRcdC4uLmV4dHJhLFxuXHR9O1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuU2NhZmZvbGRBcGkobm9ybWFsaXplZDogQXBpT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuXHRwYXJzZUFwaU5hbWVzKG5vcm1hbGl6ZWQubmFtZXMpO1xuXHRjb25zdCB7IGNsb3NlUHJvbXB0IH0gPSBhd2FpdCBpbXBvcnQoXCIuLi9kb21haW4vcHJvbXB0LmpzXCIpO1xuXHR0cnkge1xuXHRcdGF3YWl0IHNjYWZmb2xkQXBpKG5vcm1hbGl6ZWQpO1xuXHR9IGZpbmFsbHkge1xuXHRcdGNsb3NlUHJvbXB0KCk7XG5cdH1cbn1cbiJdLCJuYW1lcyI6WyJyZXNvbHZlVGFyZ2V0RGlyIiwicGFyc2VBcGlOYW1lcyIsInNjYWZmb2xkQXBpIiwiY29sbGVjdE5hbWUiLCJ2YWx1ZSIsInByZXZpb3VzIiwicHVzaCIsImFkZFdlYmFwaUZlYXR1cmVPcHRpb25zIiwiY21kIiwib3B0aW9uIiwidG9BcGlPcHRpb25zIiwiZGlyZWN0b3J5Iiwib3B0cyIsImV4dHJhIiwiaW5zdGFsbE1vZGUiLCJTdHJpbmciLCJpbnN0YWxsIiwidG9Mb3dlckNhc2UiLCJuYW1lcyIsIkFycmF5IiwiaXNBcnJheSIsIm5hbWUiLCJkIiwidW5kZWZpbmVkIiwiZGF0YWJhc2VQcm92aWRlciIsImRhdGFiYXNlIiwiYXV0aFByb3ZpZGVyIiwiYXV0aCIsInBvc3RtYW5Qcm92aWRlciIsInBvc3RtYW4iLCJpbnN0YWxsRGVwZW5kZW5jaWVzIiwieWVzIiwicnVuU2NhZmZvbGRBcGkiLCJub3JtYWxpemVkIiwiY2xvc2VQcm9tcHQiXSwibWFwcGluZ3MiOiJBQUNBLFNBQVNBLGdCQUFnQixRQUFRLDJCQUEyQjtBQUM1RCxTQUFTQyxhQUFhLFFBQVEsZ0JBQWdCO0FBRTlDLFNBQVNDLFdBQVcsUUFBUSxrQkFBa0I7QUFFOUMsT0FBTyxTQUFTQyxZQUFZQyxLQUFhLEVBQUVDLFFBQWtCO0lBQzVEQSxTQUFTQyxJQUFJLENBQUNGO0lBQ2QsT0FBT0M7QUFDUjtBQUVBLE9BQU8sU0FBU0Usd0JBQXdCQyxHQUFZO0lBQ25ELE9BQU9BLElBQ0xDLE1BQU0sQ0FBQyx5QkFBeUIsOENBQ2hDQSxNQUFNLENBQUMscUJBQXFCLCtCQUM1QkEsTUFBTSxDQUFDLHdCQUF3Qix3Q0FDL0JBLE1BQU0sQ0FBQyxhQUFhLDBDQUNwQkEsTUFBTSxDQUFDLG9CQUFvQiwyQ0FBMkM7QUFDekU7QUFFQSxPQUFPLFNBQVNDLGFBQ2ZDLFNBQTZCLEVBQzdCQyxJQUE2QixFQUM3QkMsUUFBNkIsQ0FBQyxDQUFDO0lBRS9CLE1BQU1DLGNBQWNDLE9BQU9ILEtBQUtJLE9BQU8sSUFBSSxPQUFPQyxXQUFXO0lBQzdELE1BQU1DLFFBQVFDLE1BQU1DLE9BQU8sQ0FBQ1IsS0FBS1MsSUFBSSxJQUNqQ1QsS0FBS1MsSUFBSSxHQUNWLE9BQU9ULEtBQUtTLElBQUksS0FBSyxXQUNwQjtRQUFDVCxLQUFLUyxJQUFJO0tBQUMsR0FDWFIsTUFBTUssS0FBSztJQUNmLE9BQU87UUFDTkksR0FBR3RCLGlCQUFpQlcsV0FBVyxPQUFPQyxLQUFLVSxDQUFDLEtBQUssV0FBV1YsS0FBS1UsQ0FBQyxHQUFHQztRQUNyRUMsa0JBQWtCWixLQUFLYSxRQUFRO1FBQy9CQyxjQUFjZCxLQUFLZSxJQUFJO1FBQ3ZCQyxpQkFBaUJoQixLQUFLaUIsT0FBTztRQUM3QkMscUJBQ0NsQixLQUFLbUIsR0FBRyxLQUFLLE9BQ1YsUUFDQWpCLGdCQUFnQixTQUFTQSxnQkFBZ0IsT0FDeENBLGNBQ0FTO1FBQ0xMO1FBQ0EsR0FBR0wsS0FBSztJQUNUO0FBQ0Q7QUFFQSxPQUFPLGVBQWVtQixlQUFlQyxVQUFzQjtJQUMxRGhDLGNBQWNnQyxXQUFXZixLQUFLO0lBQzlCLE1BQU0sRUFBRWdCLFdBQVcsRUFBRSxHQUFHLE1BQU0sTUFBTSxDQUFDO0lBQ3JDLElBQUk7UUFDSCxNQUFNaEMsWUFBWStCO0lBQ25CLFNBQVU7UUFDVEM7SUFDRDtBQUNEIn0=
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Default API project slug when `--name` is omitted. */ export const DEFAULT_WEBAPI_NAME = "api";
|
|
2
|
+
/** Relative path of an API project inside the monorepo. */ export function webapiProjectDir(name) {
|
|
3
|
+
return `projects/${name}`;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Forge release entry for a scaffolded API (`pack: true` → per-target outDir).
|
|
7
|
+
* Keep in sync with root `package.json` `"start"` / `"start:<name>"` and Dockerfiles.
|
|
8
|
+
*/ export function webapiReleaseEntry(name) {
|
|
9
|
+
return `dist/release/${webapiProjectDir(name)}/es6/src/main.js`;
|
|
10
|
+
}
|
|
11
|
+
/** npm package name for a scaffolded API (`flux serve --project`). */ export function webapiPackageName(workspaceName, apiName) {
|
|
12
|
+
return `@${workspaceName}/${apiName}`;
|
|
13
|
+
}
|
|
14
|
+
/** Local listen port for the nth API (0-based). Production uses `PORT`. */ export function webapiPort(index) {
|
|
15
|
+
return 3000 + index;
|
|
16
|
+
}
|
|
17
|
+
/** @deprecated Use `webapiProjectDir(name)`. Default path for the first API. */ export const WEBAPI_PROJECT_DIR = webapiProjectDir(DEFAULT_WEBAPI_NAME);
|
|
18
|
+
/** @deprecated Use `webapiReleaseEntry(name)`. Default start entry for the first API. */ export const WEBAPI_RELEASE_ENTRY = webapiReleaseEntry(DEFAULT_WEBAPI_NAME);
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjYWZmb2xkL3NyYy93ZWJhcGkvY29uc3QudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqIERlZmF1bHQgQVBJIHByb2plY3Qgc2x1ZyB3aGVuIGAtLW5hbWVgIGlzIG9taXR0ZWQuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9XRUJBUElfTkFNRSA9IFwiYXBpXCI7XG5cbi8qKiBSZWxhdGl2ZSBwYXRoIG9mIGFuIEFQSSBwcm9qZWN0IGluc2lkZSB0aGUgbW9ub3JlcG8uICovXG5leHBvcnQgZnVuY3Rpb24gd2ViYXBpUHJvamVjdERpcihuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRyZXR1cm4gYHByb2plY3RzLyR7bmFtZX1gO1xufVxuXG4vKipcbiAqIEZvcmdlIHJlbGVhc2UgZW50cnkgZm9yIGEgc2NhZmZvbGRlZCBBUEkgKGBwYWNrOiB0cnVlYCDihpIgcGVyLXRhcmdldCBvdXREaXIpLlxuICogS2VlcCBpbiBzeW5jIHdpdGggcm9vdCBgcGFja2FnZS5qc29uYCBgXCJzdGFydFwiYCAvIGBcInN0YXJ0OjxuYW1lPlwiYCBhbmQgRG9ja2VyZmlsZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3ZWJhcGlSZWxlYXNlRW50cnkobmFtZTogc3RyaW5nKTogc3RyaW5nIHtcblx0cmV0dXJuIGBkaXN0L3JlbGVhc2UvJHt3ZWJhcGlQcm9qZWN0RGlyKG5hbWUpfS9lczYvc3JjL21haW4uanNgO1xufVxuXG4vKiogbnBtIHBhY2thZ2UgbmFtZSBmb3IgYSBzY2FmZm9sZGVkIEFQSSAoYGZsdXggc2VydmUgLS1wcm9qZWN0YCkuICovXG5leHBvcnQgZnVuY3Rpb24gd2ViYXBpUGFja2FnZU5hbWUod29ya3NwYWNlTmFtZTogc3RyaW5nLCBhcGlOYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRyZXR1cm4gYEAke3dvcmtzcGFjZU5hbWV9LyR7YXBpTmFtZX1gO1xufVxuXG4vKiogTG9jYWwgbGlzdGVuIHBvcnQgZm9yIHRoZSBudGggQVBJICgwLWJhc2VkKS4gUHJvZHVjdGlvbiB1c2VzIGBQT1JUYC4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3ZWJhcGlQb3J0KGluZGV4OiBudW1iZXIpOiBudW1iZXIge1xuXHRyZXR1cm4gMzAwMCArIGluZGV4O1xufVxuXG4vKiogQGRlcHJlY2F0ZWQgVXNlIGB3ZWJhcGlQcm9qZWN0RGlyKG5hbWUpYC4gRGVmYXVsdCBwYXRoIGZvciB0aGUgZmlyc3QgQVBJLiAqL1xuZXhwb3J0IGNvbnN0IFdFQkFQSV9QUk9KRUNUX0RJUiA9IHdlYmFwaVByb2plY3REaXIoREVGQVVMVF9XRUJBUElfTkFNRSk7XG5cbi8qKiBAZGVwcmVjYXRlZCBVc2UgYHdlYmFwaVJlbGVhc2VFbnRyeShuYW1lKWAuIERlZmF1bHQgc3RhcnQgZW50cnkgZm9yIHRoZSBmaXJzdCBBUEkuICovXG5leHBvcnQgY29uc3QgV0VCQVBJX1JFTEVBU0VfRU5UUlkgPSB3ZWJhcGlSZWxlYXNlRW50cnkoREVGQVVMVF9XRUJBUElfTkFNRSk7XG4iXSwibmFtZXMiOlsiREVGQVVMVF9XRUJBUElfTkFNRSIsIndlYmFwaVByb2plY3REaXIiLCJuYW1lIiwid2ViYXBpUmVsZWFzZUVudHJ5Iiwid2ViYXBpUGFja2FnZU5hbWUiLCJ3b3Jrc3BhY2VOYW1lIiwiYXBpTmFtZSIsIndlYmFwaVBvcnQiLCJpbmRleCIsIldFQkFQSV9QUk9KRUNUX0RJUiIsIldFQkFQSV9SRUxFQVNFX0VOVFJZIl0sIm1hcHBpbmdzIjoiQUFBQSx1REFBdUQsR0FDdkQsT0FBTyxNQUFNQSxzQkFBc0IsTUFBTTtBQUV6Qyx5REFBeUQsR0FDekQsT0FBTyxTQUFTQyxpQkFBaUJDLElBQVk7SUFDNUMsT0FBTyxDQUFDLFNBQVMsRUFBRUEsTUFBTTtBQUMxQjtBQUVBOzs7Q0FHQyxHQUNELE9BQU8sU0FBU0MsbUJBQW1CRCxJQUFZO0lBQzlDLE9BQU8sQ0FBQyxhQUFhLEVBQUVELGlCQUFpQkMsTUFBTSxnQkFBZ0IsQ0FBQztBQUNoRTtBQUVBLG9FQUFvRSxHQUNwRSxPQUFPLFNBQVNFLGtCQUFrQkMsYUFBcUIsRUFBRUMsT0FBZTtJQUN2RSxPQUFPLENBQUMsQ0FBQyxFQUFFRCxjQUFjLENBQUMsRUFBRUMsU0FBUztBQUN0QztBQUVBLHlFQUF5RSxHQUN6RSxPQUFPLFNBQVNDLFdBQVdDLEtBQWE7SUFDdkMsT0FBTyxPQUFPQTtBQUNmO0FBRUEsOEVBQThFLEdBQzlFLE9BQU8sTUFBTUMscUJBQXFCUixpQkFBaUJELHFCQUFxQjtBQUV4RSx1RkFBdUYsR0FDdkYsT0FBTyxNQUFNVSx1QkFBdUJQLG1CQUFtQkgscUJBQXFCIn0=
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { basename, join, resolve } from "node:path";
|
|
3
|
+
import { DockerCompose } from "../models/compose.model.js";
|
|
4
|
+
import { ConfigYaml } from "../models/config-yaml.model.js";
|
|
5
|
+
import { WELL_KNOWN_FILES } from "../models/const.js";
|
|
6
|
+
import { DevContainer } from "../models/dev-container.model.js";
|
|
7
|
+
import { commandHistory } from "../models/docker-image.model.js";
|
|
8
|
+
import { EnvFile } from "../models/env-file.model.js";
|
|
9
|
+
import { Gitignore } from "../models/gitignore.model.js";
|
|
10
|
+
import { LaunchJson } from "../models/launch-json.model.js";
|
|
11
|
+
import { PackageJson } from "../models/package-json.model.js";
|
|
12
|
+
import { MonoRepoScaffold, ProjectScaffold } from "../models/project.model.js";
|
|
13
|
+
import { TsConfig } from "../models/tsconfig.model.js";
|
|
14
|
+
import { VitestConfig } from "../models/vitest-config.model.js";
|
|
15
|
+
import { VSCodeSettings } from "../models/vscode-settings.model.js";
|
|
16
|
+
import { ScaffoldService } from "../services/scaffold.service.js";
|
|
17
|
+
import { CreateCliError, isDecohereWorkspace, listExistingApiNames, parseApiNames } from "./api-name.js";
|
|
18
|
+
import { DEFAULT_WEBAPI_NAME, webapiPackageName, webapiPort, webapiProjectDir, webapiReleaseEntry } from "./const.js";
|
|
19
|
+
import { DevContainerHostScripts } from "./devcontainer/host-scripts.js";
|
|
20
|
+
import { AuthFeature } from "./features/auth.feature.js";
|
|
21
|
+
import { DatabaseFeature } from "./features/database.feature.js";
|
|
22
|
+
import { FinalizeFeature } from "./features/finalize.feature.js";
|
|
23
|
+
import { PostmanFeature } from "./features/postman.feature.js";
|
|
24
|
+
import { ApiPackageJson } from "./models/api-package-json.model.js";
|
|
25
|
+
import { ControllerSourceFile } from "./models/controller-source-file.model.js";
|
|
26
|
+
import { GithubCiWorkflows } from "./models/github-ci.model.js";
|
|
27
|
+
import { MainSourceFile } from "./models/main-source-file.model.js";
|
|
28
|
+
import { WebapiProductionDockerfile } from "./models/production-dockerfile.model.js";
|
|
29
|
+
import { SampleConfigModel, SampleServiceModel } from "./models/sample-files.model.js";
|
|
30
|
+
import { WebapiDevContainer } from "./models/webapi-image.model.js";
|
|
31
|
+
export { WEBAPI_PROJECT_DIR, WEBAPI_RELEASE_ENTRY } from "./const.js";
|
|
32
|
+
const features = [
|
|
33
|
+
DatabaseFeature,
|
|
34
|
+
AuthFeature,
|
|
35
|
+
PostmanFeature,
|
|
36
|
+
FinalizeFeature
|
|
37
|
+
];
|
|
38
|
+
export async function scaffoldApi(cliOptions) {
|
|
39
|
+
const targetDir = resolve(cliOptions.d ?? ".");
|
|
40
|
+
const projectName = cliOptions.projectName?.trim() || process.env.DECOHERE_PROJECT_NAME?.trim() || basename(targetDir);
|
|
41
|
+
const names = parseApiNames(cliOptions.names);
|
|
42
|
+
const workspace = cliOptions.add ? createAddWorkspace(targetDir, projectName, names) : createWorkspace(targetDir, projectName, names);
|
|
43
|
+
await ScaffoldService.scaffold(workspace, {
|
|
44
|
+
...cliOptions,
|
|
45
|
+
names
|
|
46
|
+
}, features);
|
|
47
|
+
}
|
|
48
|
+
function createWorkspace(targetDir, projectName, apiNames) {
|
|
49
|
+
const monoRepo = new MonoRepoScaffold();
|
|
50
|
+
monoRepo.targetDir = targetDir;
|
|
51
|
+
monoRepo.setName(projectName);
|
|
52
|
+
const name = monoRepo.name;
|
|
53
|
+
const compose = new DockerCompose().setProjectName(name).addHeaderComment("Merge .cursor/mcp.json in the service command. postStartCommand runs after Cursor's first MCP snapshot.").addNetwork(name, {
|
|
54
|
+
name: `samples-${name}`
|
|
55
|
+
}).addService("devcontainer", {
|
|
56
|
+
build: ".",
|
|
57
|
+
volumes: [
|
|
58
|
+
// Workspace-local (created by initialize.sh as the host user).
|
|
59
|
+
// Do NOT bind ${HOME}/.npm/... — Docker creates missing host paths as root.
|
|
60
|
+
"./npm-auth:/home/node/.npm-config",
|
|
61
|
+
"./gh-auth:/home/node/.config/gh",
|
|
62
|
+
"webapi-node-modules:/workspace/node_modules",
|
|
63
|
+
// Named volume (not a Cursor-only mount) so CLI recreates keep Up-arrow history.
|
|
64
|
+
`${commandHistory.volumeName}:${commandHistory.dir}`
|
|
65
|
+
],
|
|
66
|
+
env_file: [
|
|
67
|
+
"./gh.env"
|
|
68
|
+
],
|
|
69
|
+
environment: {
|
|
70
|
+
NPM_CONFIG_USERCONFIG: "/home/node/.npm-config/.npmrc"
|
|
71
|
+
},
|
|
72
|
+
command: "'bash -c \"CODEBASE_RAG_WORKSPACE=/workspace node --experimental-strip-types /workspace/.devcontainer/codebase-rag-mcp.ts merge || true && exec sleep infinity\"'",
|
|
73
|
+
networks: [
|
|
74
|
+
name
|
|
75
|
+
]
|
|
76
|
+
}).addVolume("webapi-node-modules").addVolume(commandHistory.volumeName);
|
|
77
|
+
const installCmd = "bash .devcontainer/post-create.sh";
|
|
78
|
+
const devContainer = new DevContainer().addExtension("biomejs.biome", "vitest.explorer").setInitializeCommand("bash .devcontainer/initialize.sh").setPostCreateCommand(installCmd).setUpdateContentCommand(installCmd).setPostStartCommand("bash .devcontainer/post-start.sh").useCompose();
|
|
79
|
+
for (const [index, apiName] of apiNames.entries()){
|
|
80
|
+
const port = webapiPort(index);
|
|
81
|
+
devContainer.forwardPort(port);
|
|
82
|
+
devContainer.setPortAttributes(port, {
|
|
83
|
+
label: apiName === DEFAULT_WEBAPI_NAME ? "API" : apiName,
|
|
84
|
+
requireLocalPort: true
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// Workspace-level models (repo root)
|
|
88
|
+
monoRepo.addModel(compose);
|
|
89
|
+
monoRepo.addModel(devContainer);
|
|
90
|
+
monoRepo.addModel(new WebapiDevContainer());
|
|
91
|
+
monoRepo.addModel(new WebapiProductionDockerfile(apiNames));
|
|
92
|
+
monoRepo.addModel(new GithubCiWorkflows());
|
|
93
|
+
monoRepo.addModel(new VSCodeSettings(name));
|
|
94
|
+
monoRepo.addModel(new LaunchJson(apiNames));
|
|
95
|
+
monoRepo.addModel(new TsConfig());
|
|
96
|
+
monoRepo.addModel(new VitestConfig());
|
|
97
|
+
monoRepo.addModel(new PackageJson(`${name}.api`, {
|
|
98
|
+
apiNames,
|
|
99
|
+
workspaceName: name
|
|
100
|
+
}));
|
|
101
|
+
monoRepo.addModel(new ConfigYaml(WELL_KNOWN_FILES.CONFIG_YAML, "config/config.yaml", ""));
|
|
102
|
+
monoRepo.addModel(new ConfigYaml(WELL_KNOWN_FILES.CONFIG_DEV_YAML, "config/config.dev.yaml", ""));
|
|
103
|
+
monoRepo.addModel(new Gitignore());
|
|
104
|
+
monoRepo.addModel(new EnvFile());
|
|
105
|
+
monoRepo.addFile(new DevContainerHostScripts());
|
|
106
|
+
// Biome formatter/linter config
|
|
107
|
+
monoRepo.addFile({
|
|
108
|
+
files: ()=>[
|
|
109
|
+
{
|
|
110
|
+
filePath: "biome.json",
|
|
111
|
+
content: JSON.stringify({
|
|
112
|
+
$schema: "https://biomejs.dev/schemas/2.0.0/schema.json",
|
|
113
|
+
files: {
|
|
114
|
+
includes: [
|
|
115
|
+
"**/*.ts",
|
|
116
|
+
"**/*.js",
|
|
117
|
+
"**/*.json",
|
|
118
|
+
"**/*.yml",
|
|
119
|
+
"**/*.yaml"
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
assist: {
|
|
123
|
+
actions: {
|
|
124
|
+
source: {
|
|
125
|
+
organizeImports: "on"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
vcs: {
|
|
130
|
+
enabled: true,
|
|
131
|
+
clientKind: "git",
|
|
132
|
+
useIgnoreFile: true
|
|
133
|
+
},
|
|
134
|
+
formatter: {
|
|
135
|
+
enabled: true,
|
|
136
|
+
formatWithErrors: true,
|
|
137
|
+
indentStyle: "tab",
|
|
138
|
+
lineWidth: 95
|
|
139
|
+
},
|
|
140
|
+
javascript: {
|
|
141
|
+
parser: {
|
|
142
|
+
unsafeParameterDecoratorsEnabled: true
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
linter: {
|
|
146
|
+
rules: {
|
|
147
|
+
style: {
|
|
148
|
+
useConsistentMemberAccessibility: {
|
|
149
|
+
level: "error",
|
|
150
|
+
options: {
|
|
151
|
+
accessibility: "explicit"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
overrides: [
|
|
158
|
+
{
|
|
159
|
+
includes: [
|
|
160
|
+
"**/*.json"
|
|
161
|
+
],
|
|
162
|
+
formatter: {
|
|
163
|
+
indentStyle: "space",
|
|
164
|
+
indentWidth: 2
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
}, null, 2)
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
});
|
|
172
|
+
for (const apiName of apiNames){
|
|
173
|
+
addApiProject(monoRepo, name, apiName);
|
|
174
|
+
}
|
|
175
|
+
return monoRepo;
|
|
176
|
+
}
|
|
177
|
+
function createAddWorkspace(targetDir, projectName, apiNames) {
|
|
178
|
+
if (!isDecohereWorkspace(targetDir)) {
|
|
179
|
+
throw new CreateCliError(`Not a Decohere workspace: ${targetDir}. Scaffold one first with \`npx @decohere/create webapi\`.`);
|
|
180
|
+
}
|
|
181
|
+
const existing = listExistingApiNames(targetDir);
|
|
182
|
+
for (const apiName of apiNames){
|
|
183
|
+
if (existing.includes(apiName)) {
|
|
184
|
+
throw new CreateCliError(`API "${apiName}" already exists at ${webapiProjectDir(apiName)}.`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const monoRepo = new MonoRepoScaffold();
|
|
188
|
+
monoRepo.targetDir = targetDir;
|
|
189
|
+
monoRepo.setName(projectName);
|
|
190
|
+
const name = monoRepo.name;
|
|
191
|
+
const pkg = PackageJson.fromFile(join(targetDir, "package.json"));
|
|
192
|
+
monoRepo.addModel(pkg);
|
|
193
|
+
monoRepo.addModel(existsSync(join(targetDir, ".env")) ? EnvFile.fromFile(join(targetDir, ".env")) : new EnvFile());
|
|
194
|
+
monoRepo.addModel(existsSync(join(targetDir, "config/config.yaml")) ? ConfigYaml.fromFile(WELL_KNOWN_FILES.CONFIG_YAML, "config/config.yaml", join(targetDir, "config/config.yaml")) : new ConfigYaml(WELL_KNOWN_FILES.CONFIG_YAML, "config/config.yaml", ""));
|
|
195
|
+
monoRepo.addModel(existsSync(join(targetDir, "config/config.dev.yaml")) ? ConfigYaml.fromFile(WELL_KNOWN_FILES.CONFIG_DEV_YAML, "config/config.dev.yaml", join(targetDir, "config/config.dev.yaml")) : new ConfigYaml(WELL_KNOWN_FILES.CONFIG_DEV_YAML, "config/config.dev.yaml", ""));
|
|
196
|
+
for (const [offset, apiName] of apiNames.entries()){
|
|
197
|
+
const port = webapiPort(existing.length + offset);
|
|
198
|
+
pkg.addScript(`start:${apiName}`, `node ${webapiReleaseEntry(apiName)}`);
|
|
199
|
+
pkg.addScript(`dev:${apiName}`, `PORT=${port} flux serve --project ${webapiPackageName(name, apiName)}`);
|
|
200
|
+
addApiProject(monoRepo, name, apiName);
|
|
201
|
+
}
|
|
202
|
+
monoRepo.addModel(new WebapiProductionDockerfile(apiNames, {
|
|
203
|
+
namedOnly: true
|
|
204
|
+
}));
|
|
205
|
+
return monoRepo;
|
|
206
|
+
}
|
|
207
|
+
function addApiProject(monoRepo, workspaceName, apiName) {
|
|
208
|
+
const apiProject = new ProjectScaffold(webapiProjectDir(apiName));
|
|
209
|
+
apiProject.addModel(new ApiPackageJson(workspaceName, apiName));
|
|
210
|
+
apiProject.addModel(new MainSourceFile(`${workspaceName}.${apiName}`));
|
|
211
|
+
apiProject.addModel(new ControllerSourceFile());
|
|
212
|
+
apiProject.addFile(new SampleConfigModel());
|
|
213
|
+
apiProject.addFile(new SampleServiceModel());
|
|
214
|
+
monoRepo.addProject(apiProject);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjYWZmb2xkL3NyYy93ZWJhcGkvY3JlYXRlLWFwaS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBleGlzdHNTeW5jIH0gZnJvbSBcIm5vZGU6ZnNcIjtcbmltcG9ydCB7IGJhc2VuYW1lLCBqb2luLCByZXNvbHZlIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgRG9ja2VyQ29tcG9zZSB9IGZyb20gXCIuLi9tb2RlbHMvY29tcG9zZS5tb2RlbC5qc1wiO1xuaW1wb3J0IHsgQ29uZmlnWWFtbCB9IGZyb20gXCIuLi9tb2RlbHMvY29uZmlnLXlhbWwubW9kZWwuanNcIjtcbmltcG9ydCB7IFdFTExfS05PV05fRklMRVMgfSBmcm9tIFwiLi4vbW9kZWxzL2NvbnN0LmpzXCI7XG5pbXBvcnQgeyBEZXZDb250YWluZXIgfSBmcm9tIFwiLi4vbW9kZWxzL2Rldi1jb250YWluZXIubW9kZWwuanNcIjtcbmltcG9ydCB7IGNvbW1hbmRIaXN0b3J5IH0gZnJvbSBcIi4uL21vZGVscy9kb2NrZXItaW1hZ2UubW9kZWwuanNcIjtcbmltcG9ydCB7IEVudkZpbGUgfSBmcm9tIFwiLi4vbW9kZWxzL2Vudi1maWxlLm1vZGVsLmpzXCI7XG5pbXBvcnQgeyBHaXRpZ25vcmUgfSBmcm9tIFwiLi4vbW9kZWxzL2dpdGlnbm9yZS5tb2RlbC5qc1wiO1xuaW1wb3J0IHsgTGF1bmNoSnNvbiB9IGZyb20gXCIuLi9tb2RlbHMvbGF1bmNoLWpzb24ubW9kZWwuanNcIjtcbmltcG9ydCB7IFBhY2thZ2VKc29uIH0gZnJvbSBcIi4uL21vZGVscy9wYWNrYWdlLWpzb24ubW9kZWwuanNcIjtcbmltcG9ydCB7IE1vbm9SZXBvU2NhZmZvbGQsIFByb2plY3RTY2FmZm9sZCB9IGZyb20gXCIuLi9tb2RlbHMvcHJvamVjdC5tb2RlbC5qc1wiO1xuaW1wb3J0IHsgVHNDb25maWcgfSBmcm9tIFwiLi4vbW9kZWxzL3RzY29uZmlnLm1vZGVsLmpzXCI7XG5pbXBvcnQgeyBWaXRlc3RDb25maWcgfSBmcm9tIFwiLi4vbW9kZWxzL3ZpdGVzdC1jb25maWcubW9kZWwuanNcIjtcbmltcG9ydCB7IFZTQ29kZVNldHRpbmdzIH0gZnJvbSBcIi4uL21vZGVscy92c2NvZGUtc2V0dGluZ3MubW9kZWwuanNcIjtcbmltcG9ydCB7IFNjYWZmb2xkU2VydmljZSB9IGZyb20gXCIuLi9zZXJ2aWNlcy9zY2FmZm9sZC5zZXJ2aWNlLmpzXCI7XG5pbXBvcnQge1xuXHRDcmVhdGVDbGlFcnJvcixcblx0aXNEZWNvaGVyZVdvcmtzcGFjZSxcblx0bGlzdEV4aXN0aW5nQXBpTmFtZXMsXG5cdHBhcnNlQXBpTmFtZXMsXG59IGZyb20gXCIuL2FwaS1uYW1lLmpzXCI7XG5pbXBvcnQge1xuXHRERUZBVUxUX1dFQkFQSV9OQU1FLFxuXHR3ZWJhcGlQYWNrYWdlTmFtZSxcblx0d2ViYXBpUG9ydCxcblx0d2ViYXBpUHJvamVjdERpcixcblx0d2ViYXBpUmVsZWFzZUVudHJ5LFxufSBmcm9tIFwiLi9jb25zdC5qc1wiO1xuaW1wb3J0IHsgRGV2Q29udGFpbmVySG9zdFNjcmlwdHMgfSBmcm9tIFwiLi9kZXZjb250YWluZXIvaG9zdC1zY3JpcHRzLmpzXCI7XG5pbXBvcnQgeyBBdXRoRmVhdHVyZSB9IGZyb20gXCIuL2ZlYXR1cmVzL2F1dGguZmVhdHVyZS5qc1wiO1xuaW1wb3J0IHsgRGF0YWJhc2VGZWF0dXJlIH0gZnJvbSBcIi4vZmVhdHVyZXMvZGF0YWJhc2UuZmVhdHVyZS5qc1wiO1xuaW1wb3J0IHsgRmluYWxpemVGZWF0dXJlIH0gZnJvbSBcIi4vZmVhdHVyZXMvZmluYWxpemUuZmVhdHVyZS5qc1wiO1xuaW1wb3J0IHsgUG9zdG1hbkZlYXR1cmUgfSBmcm9tIFwiLi9mZWF0dXJlcy9wb3N0bWFuLmZlYXR1cmUuanNcIjtcbmltcG9ydCB7IEFwaVBhY2thZ2VKc29uIH0gZnJvbSBcIi4vbW9kZWxzL2FwaS1wYWNrYWdlLWpzb24ubW9kZWwuanNcIjtcbmltcG9ydCB7IENvbnRyb2xsZXJTb3VyY2VGaWxlIH0gZnJvbSBcIi4vbW9kZWxzL2NvbnRyb2xsZXItc291cmNlLWZpbGUubW9kZWwuanNcIjtcbmltcG9ydCB7IEdpdGh1YkNpV29ya2Zsb3dzIH0gZnJvbSBcIi4vbW9kZWxzL2dpdGh1Yi1jaS5tb2RlbC5qc1wiO1xuaW1wb3J0IHsgTWFpblNvdXJjZUZpbGUgfSBmcm9tIFwiLi9tb2RlbHMvbWFpbi1zb3VyY2UtZmlsZS5tb2RlbC5qc1wiO1xuaW1wb3J0IHsgV2ViYXBpUHJvZHVjdGlvbkRvY2tlcmZpbGUgfSBmcm9tIFwiLi9tb2RlbHMvcHJvZHVjdGlvbi1kb2NrZXJmaWxlLm1vZGVsLmpzXCI7XG5pbXBvcnQgeyBTYW1wbGVDb25maWdNb2RlbCwgU2FtcGxlU2VydmljZU1vZGVsIH0gZnJvbSBcIi4vbW9kZWxzL3NhbXBsZS1maWxlcy5tb2RlbC5qc1wiO1xuaW1wb3J0IHsgV2ViYXBpRGV2Q29udGFpbmVyIH0gZnJvbSBcIi4vbW9kZWxzL3dlYmFwaS1pbWFnZS5tb2RlbC5qc1wiO1xuXG5leHBvcnQgeyBXRUJBUElfUFJPSkVDVF9ESVIsIFdFQkFQSV9SRUxFQVNFX0VOVFJZIH0gZnJvbSBcIi4vY29uc3QuanNcIjtcblxuZXhwb3J0IHR5cGUgQXBpT3B0aW9ucyA9IHtcblx0ZD86IHN0cmluZztcblx0LyoqIEhvc3QgcHJvamVjdCBuYW1lIChkaXJlY3RvcnkgYmFzZW5hbWUpLiBSZXF1aXJlZCB3aGVuIHNjYWZmb2xkaW5nIGludG8gYC93b3Jrc3BhY2VgLiAqL1xuXHRwcm9qZWN0TmFtZT86IHN0cmluZztcblx0LyoqIEFQSSBzbHVncyB1bmRlciBgcHJvamVjdHMvYC4gRGVmYXVsdCBgW1wiYXBpXCJdYC4gUmVwZWF0YWJsZSBgLS1uYW1lYC4gKi9cblx0bmFtZXM/OiBzdHJpbmdbXTtcblx0LyoqIEFkZCBBUElzIHRvIGFuIGV4aXN0aW5nIERlY29oZXJlIHdvcmtzcGFjZSBpbnN0ZWFkIG9mIGNyZWF0aW5nIGEgbmV3IG9uZS4gKi9cblx0YWRkPzogYm9vbGVhbjtcblx0YXV0aFByb3ZpZGVyPzogXCJhdXRoMFwiIHwgXCJub25lXCI7XG5cdGRhdGFiYXNlUHJvdmlkZXI/OiBcIm5vbmVcIiB8IFwicG9zdGdyZXMvdHlwZW9ybVwiO1xuXHRwb3N0bWFuUHJvdmlkZXI/OiBcImFwaVwiIHwgXCJsb2NhbFwiIHwgXCJub25lXCI7XG5cdGluc3RhbGxEZXBlbmRlbmNpZXM/OiBcInllc1wiIHwgXCJub1wiO1xufTtcblxuY29uc3QgZmVhdHVyZXMgPSBbRGF0YWJhc2VGZWF0dXJlLCBBdXRoRmVhdHVyZSwgUG9zdG1hbkZlYXR1cmUsIEZpbmFsaXplRmVhdHVyZV07XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzY2FmZm9sZEFwaShjbGlPcHRpb25zOiBBcGlPcHRpb25zKSB7XG5cdGNvbnN0IHRhcmdldERpciA9IHJlc29sdmUoY2xpT3B0aW9ucy5kID8/IFwiLlwiKTtcblx0Y29uc3QgcHJvamVjdE5hbWUgPVxuXHRcdGNsaU9wdGlvbnMucHJvamVjdE5hbWU/LnRyaW0oKSB8fFxuXHRcdHByb2Nlc3MuZW52LkRFQ09IRVJFX1BST0pFQ1RfTkFNRT8udHJpbSgpIHx8XG5cdFx0YmFzZW5hbWUodGFyZ2V0RGlyKTtcblx0Y29uc3QgbmFtZXMgPSBwYXJzZUFwaU5hbWVzKGNsaU9wdGlvbnMubmFtZXMpO1xuXHRjb25zdCB3b3Jrc3BhY2UgPSBjbGlPcHRpb25zLmFkZFxuXHRcdD8gY3JlYXRlQWRkV29ya3NwYWNlKHRhcmdldERpciwgcHJvamVjdE5hbWUsIG5hbWVzKVxuXHRcdDogY3JlYXRlV29ya3NwYWNlKHRhcmdldERpciwgcHJvamVjdE5hbWUsIG5hbWVzKTtcblx0YXdhaXQgU2NhZmZvbGRTZXJ2aWNlLnNjYWZmb2xkKHdvcmtzcGFjZSwgeyAuLi5jbGlPcHRpb25zLCBuYW1lcyB9LCBmZWF0dXJlcyk7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVdvcmtzcGFjZShcblx0dGFyZ2V0RGlyOiBzdHJpbmcsXG5cdHByb2plY3ROYW1lOiBzdHJpbmcsXG5cdGFwaU5hbWVzOiByZWFkb25seSBzdHJpbmdbXSxcbik6IE1vbm9SZXBvU2NhZmZvbGQge1xuXHRjb25zdCBtb25vUmVwbyA9IG5ldyBNb25vUmVwb1NjYWZmb2xkKCk7XG5cdG1vbm9SZXBvLnRhcmdldERpciA9IHRhcmdldERpcjtcblx0bW9ub1JlcG8uc2V0TmFtZShwcm9qZWN0TmFtZSk7XG5cdGNvbnN0IG5hbWUgPSBtb25vUmVwby5uYW1lO1xuXG5cdGNvbnN0IGNvbXBvc2UgPSBuZXcgRG9ja2VyQ29tcG9zZSgpXG5cdFx0LnNldFByb2plY3ROYW1lKG5hbWUpXG5cdFx0LmFkZEhlYWRlckNvbW1lbnQoXG5cdFx0XHRcIk1lcmdlIC5jdXJzb3IvbWNwLmpzb24gaW4gdGhlIHNlcnZpY2UgY29tbWFuZC4gcG9zdFN0YXJ0Q29tbWFuZCBydW5zIGFmdGVyIEN1cnNvcidzIGZpcnN0IE1DUCBzbmFwc2hvdC5cIixcblx0XHQpXG5cdFx0LmFkZE5ldHdvcmsobmFtZSwgeyBuYW1lOiBgc2FtcGxlcy0ke25hbWV9YCB9KVxuXHRcdC5hZGRTZXJ2aWNlKFwiZGV2Y29udGFpbmVyXCIsIHtcblx0XHRcdGJ1aWxkOiBcIi5cIixcblx0XHRcdHZvbHVtZXM6IFtcblx0XHRcdFx0Ly8gV29ya3NwYWNlLWxvY2FsIChjcmVhdGVkIGJ5IGluaXRpYWxpemUuc2ggYXMgdGhlIGhvc3QgdXNlcikuXG5cdFx0XHRcdC8vIERvIE5PVCBiaW5kICR7SE9NRX0vLm5wbS8uLi4g4oCUIERvY2tlciBjcmVhdGVzIG1pc3NpbmcgaG9zdCBwYXRocyBhcyByb290LlxuXHRcdFx0XHRcIi4vbnBtLWF1dGg6L2hvbWUvbm9kZS8ubnBtLWNvbmZpZ1wiLFxuXHRcdFx0XHRcIi4vZ2gtYXV0aDovaG9tZS9ub2RlLy5jb25maWcvZ2hcIixcblx0XHRcdFx0XCJ3ZWJhcGktbm9kZS1tb2R1bGVzOi93b3Jrc3BhY2Uvbm9kZV9tb2R1bGVzXCIsXG5cdFx0XHRcdC8vIE5hbWVkIHZvbHVtZSAobm90IGEgQ3Vyc29yLW9ubHkgbW91bnQpIHNvIENMSSByZWNyZWF0ZXMga2VlcCBVcC1hcnJvdyBoaXN0b3J5LlxuXHRcdFx0XHRgJHtjb21tYW5kSGlzdG9yeS52b2x1bWVOYW1lfToke2NvbW1hbmRIaXN0b3J5LmRpcn1gLFxuXHRcdFx0XSxcblx0XHRcdGVudl9maWxlOiBbXCIuL2doLmVudlwiXSxcblx0XHRcdGVudmlyb25tZW50OiB7IE5QTV9DT05GSUdfVVNFUkNPTkZJRzogXCIvaG9tZS9ub2RlLy5ucG0tY29uZmlnLy5ucG1yY1wiIH0sXG5cdFx0XHRjb21tYW5kOlxuXHRcdFx0XHRcIidiYXNoIC1jIFxcXCJDT0RFQkFTRV9SQUdfV09SS1NQQUNFPS93b3Jrc3BhY2Ugbm9kZSAtLWV4cGVyaW1lbnRhbC1zdHJpcC10eXBlcyAvd29ya3NwYWNlLy5kZXZjb250YWluZXIvY29kZWJhc2UtcmFnLW1jcC50cyBtZXJnZSB8fCB0cnVlICYmIGV4ZWMgc2xlZXAgaW5maW5pdHlcXFwiJ1wiLFxuXHRcdFx0bmV0d29ya3M6IFtuYW1lXSxcblx0XHR9KVxuXHRcdC5hZGRWb2x1bWUoXCJ3ZWJhcGktbm9kZS1tb2R1bGVzXCIpXG5cdFx0LmFkZFZvbHVtZShjb21tYW5kSGlzdG9yeS52b2x1bWVOYW1lKTtcblxuXHRjb25zdCBpbnN0YWxsQ21kID0gXCJiYXNoIC5kZXZjb250YWluZXIvcG9zdC1jcmVhdGUuc2hcIjtcblx0Y29uc3QgZGV2Q29udGFpbmVyID0gbmV3IERldkNvbnRhaW5lcigpXG5cdFx0LmFkZEV4dGVuc2lvbihcImJpb21lanMuYmlvbWVcIiwgXCJ2aXRlc3QuZXhwbG9yZXJcIilcblx0XHQuc2V0SW5pdGlhbGl6ZUNvbW1hbmQoXCJiYXNoIC5kZXZjb250YWluZXIvaW5pdGlhbGl6ZS5zaFwiKVxuXHRcdC5zZXRQb3N0Q3JlYXRlQ29tbWFuZChpbnN0YWxsQ21kKVxuXHRcdC5zZXRVcGRhdGVDb250ZW50Q29tbWFuZChpbnN0YWxsQ21kKVxuXHRcdC5zZXRQb3N0U3RhcnRDb21tYW5kKFwiYmFzaCAuZGV2Y29udGFpbmVyL3Bvc3Qtc3RhcnQuc2hcIilcblx0XHQudXNlQ29tcG9zZSgpO1xuXG5cdGZvciAoY29uc3QgW2luZGV4LCBhcGlOYW1lXSBvZiBhcGlOYW1lcy5lbnRyaWVzKCkpIHtcblx0XHRjb25zdCBwb3J0ID0gd2ViYXBpUG9ydChpbmRleCk7XG5cdFx0ZGV2Q29udGFpbmVyLmZvcndhcmRQb3J0KHBvcnQpO1xuXHRcdGRldkNvbnRhaW5lci5zZXRQb3J0QXR0cmlidXRlcyhwb3J0LCB7XG5cdFx0XHRsYWJlbDogYXBpTmFtZSA9PT0gREVGQVVMVF9XRUJBUElfTkFNRSA/IFwiQVBJXCIgOiBhcGlOYW1lLFxuXHRcdFx0cmVxdWlyZUxvY2FsUG9ydDogdHJ1ZSxcblx0XHR9KTtcblx0fVxuXG5cdC8vIFdvcmtzcGFjZS1sZXZlbCBtb2RlbHMgKHJlcG8gcm9vdClcblx0bW9ub1JlcG8uYWRkTW9kZWwoY29tcG9zZSk7XG5cdG1vbm9SZXBvLmFkZE1vZGVsKGRldkNvbnRhaW5lcik7XG5cdG1vbm9SZXBvLmFkZE1vZGVsKG5ldyBXZWJhcGlEZXZDb250YWluZXIoKSk7XG5cdG1vbm9SZXBvLmFkZE1vZGVsKG5ldyBXZWJhcGlQcm9kdWN0aW9uRG9ja2VyZmlsZShhcGlOYW1lcykpO1xuXHRtb25vUmVwby5hZGRNb2RlbChuZXcgR2l0aHViQ2lXb3JrZmxvd3MoKSk7XG5cdG1vbm9SZXBvLmFkZE1vZGVsKG5ldyBWU0NvZGVTZXR0aW5ncyhuYW1lKSk7XG5cdG1vbm9SZXBvLmFkZE1vZGVsKG5ldyBMYXVuY2hKc29uKGFwaU5hbWVzKSk7XG5cdG1vbm9SZXBvLmFkZE1vZGVsKG5ldyBUc0NvbmZpZygpKTtcblx0bW9ub1JlcG8uYWRkTW9kZWwobmV3IFZpdGVzdENvbmZpZygpKTtcblx0bW9ub1JlcG8uYWRkTW9kZWwobmV3IFBhY2thZ2VKc29uKGAke25hbWV9LmFwaWAsIHsgYXBpTmFtZXMsIHdvcmtzcGFjZU5hbWU6IG5hbWUgfSkpO1xuXHRtb25vUmVwby5hZGRNb2RlbChuZXcgQ29uZmlnWWFtbChXRUxMX0tOT1dOX0ZJTEVTLkNPTkZJR19ZQU1MLCBcImNvbmZpZy9jb25maWcueWFtbFwiLCBcIlwiKSk7XG5cdG1vbm9SZXBvLmFkZE1vZGVsKFxuXHRcdG5ldyBDb25maWdZYW1sKFdFTExfS05PV05fRklMRVMuQ09ORklHX0RFVl9ZQU1MLCBcImNvbmZpZy9jb25maWcuZGV2LnlhbWxcIiwgXCJcIiksXG5cdCk7XG5cdG1vbm9SZXBvLmFkZE1vZGVsKG5ldyBHaXRpZ25vcmUoKSk7XG5cdG1vbm9SZXBvLmFkZE1vZGVsKG5ldyBFbnZGaWxlKCkpO1xuXHRtb25vUmVwby5hZGRGaWxlKG5ldyBEZXZDb250YWluZXJIb3N0U2NyaXB0cygpKTtcblxuXHQvLyBCaW9tZSBmb3JtYXR0ZXIvbGludGVyIGNvbmZpZ1xuXHRtb25vUmVwby5hZGRGaWxlKHtcblx0XHRmaWxlczogKCkgPT4gW1xuXHRcdFx0e1xuXHRcdFx0XHRmaWxlUGF0aDogXCJiaW9tZS5qc29uXCIsXG5cdFx0XHRcdGNvbnRlbnQ6IEpTT04uc3RyaW5naWZ5KFxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdCRzY2hlbWE6IFwiaHR0cHM6Ly9iaW9tZWpzLmRldi9zY2hlbWFzLzIuMC4wL3NjaGVtYS5qc29uXCIsXG5cdFx0XHRcdFx0XHRmaWxlczoge1xuXHRcdFx0XHRcdFx0XHRpbmNsdWRlczogW1wiKiovKi50c1wiLCBcIioqLyouanNcIiwgXCIqKi8qLmpzb25cIiwgXCIqKi8qLnltbFwiLCBcIioqLyoueWFtbFwiXSxcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRhc3Npc3Q6IHsgYWN0aW9uczogeyBzb3VyY2U6IHsgb3JnYW5pemVJbXBvcnRzOiBcIm9uXCIgfSB9IH0sXG5cdFx0XHRcdFx0XHR2Y3M6IHsgZW5hYmxlZDogdHJ1ZSwgY2xpZW50S2luZDogXCJnaXRcIiwgdXNlSWdub3JlRmlsZTogdHJ1ZSB9LFxuXHRcdFx0XHRcdFx0Zm9ybWF0dGVyOiB7XG5cdFx0XHRcdFx0XHRcdGVuYWJsZWQ6IHRydWUsXG5cdFx0XHRcdFx0XHRcdGZvcm1hdFdpdGhFcnJvcnM6IHRydWUsXG5cdFx0XHRcdFx0XHRcdGluZGVudFN0eWxlOiBcInRhYlwiLFxuXHRcdFx0XHRcdFx0XHRsaW5lV2lkdGg6IDk1LFxuXHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdGphdmFzY3JpcHQ6IHsgcGFyc2VyOiB7IHVuc2FmZVBhcmFtZXRlckRlY29yYXRvcnNFbmFibGVkOiB0cnVlIH0gfSxcblx0XHRcdFx0XHRcdGxpbnRlcjoge1xuXHRcdFx0XHRcdFx0XHRydWxlczoge1xuXHRcdFx0XHRcdFx0XHRcdHN0eWxlOiB7XG5cdFx0XHRcdFx0XHRcdFx0XHR1c2VDb25zaXN0ZW50TWVtYmVyQWNjZXNzaWJpbGl0eToge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRsZXZlbDogXCJlcnJvclwiLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRvcHRpb25zOiB7IGFjY2Vzc2liaWxpdHk6IFwiZXhwbGljaXRcIiB9LFxuXHRcdFx0XHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdG92ZXJyaWRlczogW1xuXHRcdFx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRcdFx0aW5jbHVkZXM6IFtcIioqLyouanNvblwiXSxcblx0XHRcdFx0XHRcdFx0XHRmb3JtYXR0ZXI6IHsgaW5kZW50U3R5bGU6IFwic3BhY2VcIiwgaW5kZW50V2lkdGg6IDIgfSxcblx0XHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdF0sXG5cdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRudWxsLFxuXHRcdFx0XHRcdDIsXG5cdFx0XHRcdCksXG5cdFx0XHR9LFxuXHRcdF0sXG5cdH0pO1xuXG5cdGZvciAoY29uc3QgYXBpTmFtZSBvZiBhcGlOYW1lcykge1xuXHRcdGFkZEFwaVByb2plY3QobW9ub1JlcG8sIG5hbWUsIGFwaU5hbWUpO1xuXHR9XG5cblx0cmV0dXJuIG1vbm9SZXBvO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVBZGRXb3Jrc3BhY2UoXG5cdHRhcmdldERpcjogc3RyaW5nLFxuXHRwcm9qZWN0TmFtZTogc3RyaW5nLFxuXHRhcGlOYW1lczogcmVhZG9ubHkgc3RyaW5nW10sXG4pOiBNb25vUmVwb1NjYWZmb2xkIHtcblx0aWYgKCFpc0RlY29oZXJlV29ya3NwYWNlKHRhcmdldERpcikpIHtcblx0XHR0aHJvdyBuZXcgQ3JlYXRlQ2xpRXJyb3IoXG5cdFx0XHRgTm90IGEgRGVjb2hlcmUgd29ya3NwYWNlOiAke3RhcmdldERpcn0uIFNjYWZmb2xkIG9uZSBmaXJzdCB3aXRoIFxcYG5weCBAZGVjb2hlcmUvY3JlYXRlIHdlYmFwaVxcYC5gLFxuXHRcdCk7XG5cdH1cblxuXHRjb25zdCBleGlzdGluZyA9IGxpc3RFeGlzdGluZ0FwaU5hbWVzKHRhcmdldERpcik7XG5cdGZvciAoY29uc3QgYXBpTmFtZSBvZiBhcGlOYW1lcykge1xuXHRcdGlmIChleGlzdGluZy5pbmNsdWRlcyhhcGlOYW1lKSkge1xuXHRcdFx0dGhyb3cgbmV3IENyZWF0ZUNsaUVycm9yKFxuXHRcdFx0XHRgQVBJIFwiJHthcGlOYW1lfVwiIGFscmVhZHkgZXhpc3RzIGF0ICR7d2ViYXBpUHJvamVjdERpcihhcGlOYW1lKX0uYCxcblx0XHRcdCk7XG5cdFx0fVxuXHR9XG5cblx0Y29uc3QgbW9ub1JlcG8gPSBuZXcgTW9ub1JlcG9TY2FmZm9sZCgpO1xuXHRtb25vUmVwby50YXJnZXREaXIgPSB0YXJnZXREaXI7XG5cdG1vbm9SZXBvLnNldE5hbWUocHJvamVjdE5hbWUpO1xuXHRjb25zdCBuYW1lID0gbW9ub1JlcG8ubmFtZTtcblxuXHRjb25zdCBwa2cgPSBQYWNrYWdlSnNvbi5mcm9tRmlsZShqb2luKHRhcmdldERpciwgXCJwYWNrYWdlLmpzb25cIikpO1xuXHRtb25vUmVwby5hZGRNb2RlbChwa2cpO1xuXHRtb25vUmVwby5hZGRNb2RlbChcblx0XHRleGlzdHNTeW5jKGpvaW4odGFyZ2V0RGlyLCBcIi5lbnZcIikpXG5cdFx0XHQ/IEVudkZpbGUuZnJvbUZpbGUoam9pbih0YXJnZXREaXIsIFwiLmVudlwiKSlcblx0XHRcdDogbmV3IEVudkZpbGUoKSxcblx0KTtcblx0bW9ub1JlcG8uYWRkTW9kZWwoXG5cdFx0ZXhpc3RzU3luYyhqb2luKHRhcmdldERpciwgXCJjb25maWcvY29uZmlnLnlhbWxcIikpXG5cdFx0XHQ/IENvbmZpZ1lhbWwuZnJvbUZpbGUoXG5cdFx0XHRcdFx0V0VMTF9LTk9XTl9GSUxFUy5DT05GSUdfWUFNTCxcblx0XHRcdFx0XHRcImNvbmZpZy9jb25maWcueWFtbFwiLFxuXHRcdFx0XHRcdGpvaW4odGFyZ2V0RGlyLCBcImNvbmZpZy9jb25maWcueWFtbFwiKSxcblx0XHRcdFx0KVxuXHRcdFx0OiBuZXcgQ29uZmlnWWFtbChXRUxMX0tOT1dOX0ZJTEVTLkNPTkZJR19ZQU1MLCBcImNvbmZpZy9jb25maWcueWFtbFwiLCBcIlwiKSxcblx0KTtcblx0bW9ub1JlcG8uYWRkTW9kZWwoXG5cdFx0ZXhpc3RzU3luYyhqb2luKHRhcmdldERpciwgXCJjb25maWcvY29uZmlnLmRldi55YW1sXCIpKVxuXHRcdFx0PyBDb25maWdZYW1sLmZyb21GaWxlKFxuXHRcdFx0XHRcdFdFTExfS05PV05fRklMRVMuQ09ORklHX0RFVl9ZQU1MLFxuXHRcdFx0XHRcdFwiY29uZmlnL2NvbmZpZy5kZXYueWFtbFwiLFxuXHRcdFx0XHRcdGpvaW4odGFyZ2V0RGlyLCBcImNvbmZpZy9jb25maWcuZGV2LnlhbWxcIiksXG5cdFx0XHRcdClcblx0XHRcdDogbmV3IENvbmZpZ1lhbWwoV0VMTF9LTk9XTl9GSUxFUy5DT05GSUdfREVWX1lBTUwsIFwiY29uZmlnL2NvbmZpZy5kZXYueWFtbFwiLCBcIlwiKSxcblx0KTtcblxuXHRmb3IgKGNvbnN0IFtvZmZzZXQsIGFwaU5hbWVdIG9mIGFwaU5hbWVzLmVudHJpZXMoKSkge1xuXHRcdGNvbnN0IHBvcnQgPSB3ZWJhcGlQb3J0KGV4aXN0aW5nLmxlbmd0aCArIG9mZnNldCk7XG5cdFx0cGtnLmFkZFNjcmlwdChgc3RhcnQ6JHthcGlOYW1lfWAsIGBub2RlICR7d2ViYXBpUmVsZWFzZUVudHJ5KGFwaU5hbWUpfWApO1xuXHRcdHBrZy5hZGRTY3JpcHQoXG5cdFx0XHRgZGV2OiR7YXBpTmFtZX1gLFxuXHRcdFx0YFBPUlQ9JHtwb3J0fSBmbHV4IHNlcnZlIC0tcHJvamVjdCAke3dlYmFwaVBhY2thZ2VOYW1lKG5hbWUsIGFwaU5hbWUpfWAsXG5cdFx0KTtcblx0XHRhZGRBcGlQcm9qZWN0KG1vbm9SZXBvLCBuYW1lLCBhcGlOYW1lKTtcblx0fVxuXHRtb25vUmVwby5hZGRNb2RlbChuZXcgV2ViYXBpUHJvZHVjdGlvbkRvY2tlcmZpbGUoYXBpTmFtZXMsIHsgbmFtZWRPbmx5OiB0cnVlIH0pKTtcblxuXHRyZXR1cm4gbW9ub1JlcG87XG59XG5cbmZ1bmN0aW9uIGFkZEFwaVByb2plY3QoXG5cdG1vbm9SZXBvOiBNb25vUmVwb1NjYWZmb2xkLFxuXHR3b3Jrc3BhY2VOYW1lOiBzdHJpbmcsXG5cdGFwaU5hbWU6IHN0cmluZyxcbik6IHZvaWQge1xuXHRjb25zdCBhcGlQcm9qZWN0ID0gbmV3IFByb2plY3RTY2FmZm9sZCh3ZWJhcGlQcm9qZWN0RGlyKGFwaU5hbWUpKTtcblx0YXBpUHJvamVjdC5hZGRNb2RlbChuZXcgQXBpUGFja2FnZUpzb24od29ya3NwYWNlTmFtZSwgYXBpTmFtZSkpO1xuXHRhcGlQcm9qZWN0LmFkZE1vZGVsKG5ldyBNYWluU291cmNlRmlsZShgJHt3b3Jrc3BhY2VOYW1lfS4ke2FwaU5hbWV9YCkpO1xuXHRhcGlQcm9qZWN0LmFkZE1vZGVsKG5ldyBDb250cm9sbGVyU291cmNlRmlsZSgpKTtcblx0YXBpUHJvamVjdC5hZGRGaWxlKG5ldyBTYW1wbGVDb25maWdNb2RlbCgpKTtcblx0YXBpUHJvamVjdC5hZGRGaWxlKG5ldyBTYW1wbGVTZXJ2aWNlTW9kZWwoKSk7XG5cdG1vbm9SZXBvLmFkZFByb2plY3QoYXBpUHJvamVjdCk7XG59XG4iXSwibmFtZXMiOlsiZXhpc3RzU3luYyIsImJhc2VuYW1lIiwiam9pbiIsInJlc29sdmUiLCJEb2NrZXJDb21wb3NlIiwiQ29uZmlnWWFtbCIsIldFTExfS05PV05fRklMRVMiLCJEZXZDb250YWluZXIiLCJjb21tYW5kSGlzdG9yeSIsIkVudkZpbGUiLCJHaXRpZ25vcmUiLCJMYXVuY2hKc29uIiwiUGFja2FnZUpzb24iLCJNb25vUmVwb1NjYWZmb2xkIiwiUHJvamVjdFNjYWZmb2xkIiwiVHNDb25maWciLCJWaXRlc3RDb25maWciLCJWU0NvZGVTZXR0aW5ncyIsIlNjYWZmb2xkU2VydmljZSIsIkNyZWF0ZUNsaUVycm9yIiwiaXNEZWNvaGVyZVdvcmtzcGFjZSIsImxpc3RFeGlzdGluZ0FwaU5hbWVzIiwicGFyc2VBcGlOYW1lcyIsIkRFRkFVTFRfV0VCQVBJX05BTUUiLCJ3ZWJhcGlQYWNrYWdlTmFtZSIsIndlYmFwaVBvcnQiLCJ3ZWJhcGlQcm9qZWN0RGlyIiwid2ViYXBpUmVsZWFzZUVudHJ5IiwiRGV2Q29udGFpbmVySG9zdFNjcmlwdHMiLCJBdXRoRmVhdHVyZSIsIkRhdGFiYXNlRmVhdHVyZSIsIkZpbmFsaXplRmVhdHVyZSIsIlBvc3RtYW5GZWF0dXJlIiwiQXBpUGFja2FnZUpzb24iLCJDb250cm9sbGVyU291cmNlRmlsZSIsIkdpdGh1YkNpV29ya2Zsb3dzIiwiTWFpblNvdXJjZUZpbGUiLCJXZWJhcGlQcm9kdWN0aW9uRG9ja2VyZmlsZSIsIlNhbXBsZUNvbmZpZ01vZGVsIiwiU2FtcGxlU2VydmljZU1vZGVsIiwiV2ViYXBpRGV2Q29udGFpbmVyIiwiV0VCQVBJX1BST0pFQ1RfRElSIiwiV0VCQVBJX1JFTEVBU0VfRU5UUlkiLCJmZWF0dXJlcyIsInNjYWZmb2xkQXBpIiwiY2xpT3B0aW9ucyIsInRhcmdldERpciIsImQiLCJwcm9qZWN0TmFtZSIsInRyaW0iLCJwcm9jZXNzIiwiZW52IiwiREVDT0hFUkVfUFJPSkVDVF9OQU1FIiwibmFtZXMiLCJ3b3Jrc3BhY2UiLCJhZGQiLCJjcmVhdGVBZGRXb3Jrc3BhY2UiLCJjcmVhdGVXb3Jrc3BhY2UiLCJzY2FmZm9sZCIsImFwaU5hbWVzIiwibW9ub1JlcG8iLCJzZXROYW1lIiwibmFtZSIsImNvbXBvc2UiLCJzZXRQcm9qZWN0TmFtZSIsImFkZEhlYWRlckNvbW1lbnQiLCJhZGROZXR3b3JrIiwiYWRkU2VydmljZSIsImJ1aWxkIiwidm9sdW1lcyIsInZvbHVtZU5hbWUiLCJkaXIiLCJlbnZfZmlsZSIsImVudmlyb25tZW50IiwiTlBNX0NPTkZJR19VU0VSQ09ORklHIiwiY29tbWFuZCIsIm5ldHdvcmtzIiwiYWRkVm9sdW1lIiwiaW5zdGFsbENtZCIsImRldkNvbnRhaW5lciIsImFkZEV4dGVuc2lvbiIsInNldEluaXRpYWxpemVDb21tYW5kIiwic2V0UG9zdENyZWF0ZUNvbW1hbmQiLCJzZXRVcGRhdGVDb250ZW50Q29tbWFuZCIsInNldFBvc3RTdGFydENvbW1hbmQiLCJ1c2VDb21wb3NlIiwiaW5kZXgiLCJhcGlOYW1lIiwiZW50cmllcyIsInBvcnQiLCJmb3J3YXJkUG9ydCIsInNldFBvcnRBdHRyaWJ1dGVzIiwibGFiZWwiLCJyZXF1aXJlTG9jYWxQb3J0IiwiYWRkTW9kZWwiLCJ3b3Jrc3BhY2VOYW1lIiwiQ09ORklHX1lBTUwiLCJDT05GSUdfREVWX1lBTUwiLCJhZGRGaWxlIiwiZmlsZXMiLCJmaWxlUGF0aCIsImNvbnRlbnQiLCJKU09OIiwic3RyaW5naWZ5IiwiJHNjaGVtYSIsImluY2x1ZGVzIiwiYXNzaXN0IiwiYWN0aW9ucyIsInNvdXJjZSIsIm9yZ2FuaXplSW1wb3J0cyIsInZjcyIsImVuYWJsZWQiLCJjbGllbnRLaW5kIiwidXNlSWdub3JlRmlsZSIsImZvcm1hdHRlciIsImZvcm1hdFdpdGhFcnJvcnMiLCJpbmRlbnRTdHlsZSIsImxpbmVXaWR0aCIsImphdmFzY3JpcHQiLCJwYXJzZXIiLCJ1bnNhZmVQYXJhbWV0ZXJEZWNvcmF0b3JzRW5hYmxlZCIsImxpbnRlciIsInJ1bGVzIiwic3R5bGUiLCJ1c2VDb25zaXN0ZW50TWVtYmVyQWNjZXNzaWJpbGl0eSIsImxldmVsIiwib3B0aW9ucyIsImFjY2Vzc2liaWxpdHkiLCJvdmVycmlkZXMiLCJpbmRlbnRXaWR0aCIsImFkZEFwaVByb2plY3QiLCJleGlzdGluZyIsInBrZyIsImZyb21GaWxlIiwib2Zmc2V0IiwibGVuZ3RoIiwiYWRkU2NyaXB0IiwibmFtZWRPbmx5IiwiYXBpUHJvamVjdCIsImFkZFByb2plY3QiXSwibWFwcGluZ3MiOiJBQUFBLFNBQVNBLFVBQVUsUUFBUSxVQUFVO0FBQ3JDLFNBQVNDLFFBQVEsRUFBRUMsSUFBSSxFQUFFQyxPQUFPLFFBQVEsWUFBWTtBQUNwRCxTQUFTQyxhQUFhLFFBQVEsNkJBQTZCO0FBQzNELFNBQVNDLFVBQVUsUUFBUSxpQ0FBaUM7QUFDNUQsU0FBU0MsZ0JBQWdCLFFBQVEscUJBQXFCO0FBQ3RELFNBQVNDLFlBQVksUUFBUSxtQ0FBbUM7QUFDaEUsU0FBU0MsY0FBYyxRQUFRLGtDQUFrQztBQUNqRSxTQUFTQyxPQUFPLFFBQVEsOEJBQThCO0FBQ3RELFNBQVNDLFNBQVMsUUFBUSwrQkFBK0I7QUFDekQsU0FBU0MsVUFBVSxRQUFRLGlDQUFpQztBQUM1RCxTQUFTQyxXQUFXLFFBQVEsa0NBQWtDO0FBQzlELFNBQVNDLGdCQUFnQixFQUFFQyxlQUFlLFFBQVEsNkJBQTZCO0FBQy9FLFNBQVNDLFFBQVEsUUFBUSw4QkFBOEI7QUFDdkQsU0FBU0MsWUFBWSxRQUFRLG1DQUFtQztBQUNoRSxTQUFTQyxjQUFjLFFBQVEscUNBQXFDO0FBQ3BFLFNBQVNDLGVBQWUsUUFBUSxrQ0FBa0M7QUFDbEUsU0FDQ0MsY0FBYyxFQUNkQyxtQkFBbUIsRUFDbkJDLG9CQUFvQixFQUNwQkMsYUFBYSxRQUNQLGdCQUFnQjtBQUN2QixTQUNDQyxtQkFBbUIsRUFDbkJDLGlCQUFpQixFQUNqQkMsVUFBVSxFQUNWQyxnQkFBZ0IsRUFDaEJDLGtCQUFrQixRQUNaLGFBQWE7QUFDcEIsU0FBU0MsdUJBQXVCLFFBQVEsaUNBQWlDO0FBQ3pFLFNBQVNDLFdBQVcsUUFBUSw2QkFBNkI7QUFDekQsU0FBU0MsZUFBZSxRQUFRLGlDQUFpQztBQUNqRSxTQUFTQyxlQUFlLFFBQVEsaUNBQWlDO0FBQ2pFLFNBQVNDLGNBQWMsUUFBUSxnQ0FBZ0M7QUFDL0QsU0FBU0MsY0FBYyxRQUFRLHFDQUFxQztBQUNwRSxTQUFTQyxvQkFBb0IsUUFBUSwyQ0FBMkM7QUFDaEYsU0FBU0MsaUJBQWlCLFFBQVEsOEJBQThCO0FBQ2hFLFNBQVNDLGNBQWMsUUFBUSxxQ0FBcUM7QUFDcEUsU0FBU0MsMEJBQTBCLFFBQVEsMENBQTBDO0FBQ3JGLFNBQVNDLGlCQUFpQixFQUFFQyxrQkFBa0IsUUFBUSxpQ0FBaUM7QUFDdkYsU0FBU0Msa0JBQWtCLFFBQVEsaUNBQWlDO0FBRXBFLFNBQVNDLGtCQUFrQixFQUFFQyxvQkFBb0IsUUFBUSxhQUFhO0FBZ0J0RSxNQUFNQyxXQUFXO0lBQUNiO0lBQWlCRDtJQUFhRztJQUFnQkQ7Q0FBZ0I7QUFFaEYsT0FBTyxlQUFlYSxZQUFZQyxVQUFzQjtJQUN2RCxNQUFNQyxZQUFZM0MsUUFBUTBDLFdBQVdFLENBQUMsSUFBSTtJQUMxQyxNQUFNQyxjQUNMSCxXQUFXRyxXQUFXLEVBQUVDLFVBQ3hCQyxRQUFRQyxHQUFHLENBQUNDLHFCQUFxQixFQUFFSCxVQUNuQ2hELFNBQVM2QztJQUNWLE1BQU1PLFFBQVEvQixjQUFjdUIsV0FBV1EsS0FBSztJQUM1QyxNQUFNQyxZQUFZVCxXQUFXVSxHQUFHLEdBQzdCQyxtQkFBbUJWLFdBQVdFLGFBQWFLLFNBQzNDSSxnQkFBZ0JYLFdBQVdFLGFBQWFLO0lBQzNDLE1BQU1uQyxnQkFBZ0J3QyxRQUFRLENBQUNKLFdBQVc7UUFBRSxHQUFHVCxVQUFVO1FBQUVRO0lBQU0sR0FBR1Y7QUFDckU7QUFFQSxTQUFTYyxnQkFDUlgsU0FBaUIsRUFDakJFLFdBQW1CLEVBQ25CVyxRQUEyQjtJQUUzQixNQUFNQyxXQUFXLElBQUkvQztJQUNyQitDLFNBQVNkLFNBQVMsR0FBR0E7SUFDckJjLFNBQVNDLE9BQU8sQ0FBQ2I7SUFDakIsTUFBTWMsT0FBT0YsU0FBU0UsSUFBSTtJQUUxQixNQUFNQyxVQUFVLElBQUkzRCxnQkFDbEI0RCxjQUFjLENBQUNGLE1BQ2ZHLGdCQUFnQixDQUNoQiwyR0FFQUMsVUFBVSxDQUFDSixNQUFNO1FBQUVBLE1BQU0sQ0FBQyxRQUFRLEVBQUVBLE1BQU07SUFBQyxHQUMzQ0ssVUFBVSxDQUFDLGdCQUFnQjtRQUMzQkMsT0FBTztRQUNQQyxTQUFTO1lBQ1IsK0RBQStEO1lBQy9ELDRFQUE0RTtZQUM1RTtZQUNBO1lBQ0E7WUFDQSxpRkFBaUY7WUFDakYsR0FBRzdELGVBQWU4RCxVQUFVLENBQUMsQ0FBQyxFQUFFOUQsZUFBZStELEdBQUcsRUFBRTtTQUNwRDtRQUNEQyxVQUFVO1lBQUM7U0FBVztRQUN0QkMsYUFBYTtZQUFFQyx1QkFBdUI7UUFBZ0M7UUFDdEVDLFNBQ0M7UUFDREMsVUFBVTtZQUFDZDtTQUFLO0lBQ2pCLEdBQ0NlLFNBQVMsQ0FBQyx1QkFDVkEsU0FBUyxDQUFDckUsZUFBZThELFVBQVU7SUFFckMsTUFBTVEsYUFBYTtJQUNuQixNQUFNQyxlQUFlLElBQUl4RSxlQUN2QnlFLFlBQVksQ0FBQyxpQkFBaUIsbUJBQzlCQyxvQkFBb0IsQ0FBQyxvQ0FDckJDLG9CQUFvQixDQUFDSixZQUNyQkssdUJBQXVCLENBQUNMLFlBQ3hCTSxtQkFBbUIsQ0FBQyxvQ0FDcEJDLFVBQVU7SUFFWixLQUFLLE1BQU0sQ0FBQ0MsT0FBT0MsUUFBUSxJQUFJNUIsU0FBUzZCLE9BQU8sR0FBSTtRQUNsRCxNQUFNQyxPQUFPaEUsV0FBVzZEO1FBQ3hCUCxhQUFhVyxXQUFXLENBQUNEO1FBQ3pCVixhQUFhWSxpQkFBaUIsQ0FBQ0YsTUFBTTtZQUNwQ0csT0FBT0wsWUFBWWhFLHNCQUFzQixRQUFRZ0U7WUFDakRNLGtCQUFrQjtRQUNuQjtJQUNEO0lBRUEscUNBQXFDO0lBQ3JDakMsU0FBU2tDLFFBQVEsQ0FBQy9CO0lBQ2xCSCxTQUFTa0MsUUFBUSxDQUFDZjtJQUNsQm5CLFNBQVNrQyxRQUFRLENBQUMsSUFBSXREO0lBQ3RCb0IsU0FBU2tDLFFBQVEsQ0FBQyxJQUFJekQsMkJBQTJCc0I7SUFDakRDLFNBQVNrQyxRQUFRLENBQUMsSUFBSTNEO0lBQ3RCeUIsU0FBU2tDLFFBQVEsQ0FBQyxJQUFJN0UsZUFBZTZDO0lBQ3JDRixTQUFTa0MsUUFBUSxDQUFDLElBQUluRixXQUFXZ0Q7SUFDakNDLFNBQVNrQyxRQUFRLENBQUMsSUFBSS9FO0lBQ3RCNkMsU0FBU2tDLFFBQVEsQ0FBQyxJQUFJOUU7SUFDdEI0QyxTQUFTa0MsUUFBUSxDQUFDLElBQUlsRixZQUFZLEdBQUdrRCxLQUFLLElBQUksQ0FBQyxFQUFFO1FBQUVIO1FBQVVvQyxlQUFlakM7SUFBSztJQUNqRkYsU0FBU2tDLFFBQVEsQ0FBQyxJQUFJekYsV0FBV0MsaUJBQWlCMEYsV0FBVyxFQUFFLHNCQUFzQjtJQUNyRnBDLFNBQVNrQyxRQUFRLENBQ2hCLElBQUl6RixXQUFXQyxpQkFBaUIyRixlQUFlLEVBQUUsMEJBQTBCO0lBRTVFckMsU0FBU2tDLFFBQVEsQ0FBQyxJQUFJcEY7SUFDdEJrRCxTQUFTa0MsUUFBUSxDQUFDLElBQUlyRjtJQUN0Qm1ELFNBQVNzQyxPQUFPLENBQUMsSUFBSXRFO0lBRXJCLGdDQUFnQztJQUNoQ2dDLFNBQVNzQyxPQUFPLENBQUM7UUFDaEJDLE9BQU8sSUFBTTtnQkFDWjtvQkFDQ0MsVUFBVTtvQkFDVkMsU0FBU0MsS0FBS0MsU0FBUyxDQUN0Qjt3QkFDQ0MsU0FBUzt3QkFDVEwsT0FBTzs0QkFDTk0sVUFBVTtnQ0FBQztnQ0FBVztnQ0FBVztnQ0FBYTtnQ0FBWTs2QkFBWTt3QkFDdkU7d0JBQ0FDLFFBQVE7NEJBQUVDLFNBQVM7Z0NBQUVDLFFBQVE7b0NBQUVDLGlCQUFpQjtnQ0FBSzs0QkFBRTt3QkFBRTt3QkFDekRDLEtBQUs7NEJBQUVDLFNBQVM7NEJBQU1DLFlBQVk7NEJBQU9DLGVBQWU7d0JBQUs7d0JBQzdEQyxXQUFXOzRCQUNWSCxTQUFTOzRCQUNUSSxrQkFBa0I7NEJBQ2xCQyxhQUFhOzRCQUNiQyxXQUFXO3dCQUNaO3dCQUNBQyxZQUFZOzRCQUFFQyxRQUFRO2dDQUFFQyxrQ0FBa0M7NEJBQUs7d0JBQUU7d0JBQ2pFQyxRQUFROzRCQUNQQyxPQUFPO2dDQUNOQyxPQUFPO29DQUNOQyxrQ0FBa0M7d0NBQ2pDQyxPQUFPO3dDQUNQQyxTQUFTOzRDQUFFQyxlQUFlO3dDQUFXO29DQUN0QztnQ0FDRDs0QkFDRDt3QkFDRDt3QkFDQUMsV0FBVzs0QkFDVjtnQ0FDQ3ZCLFVBQVU7b0NBQUM7aUNBQVk7Z0NBQ3ZCUyxXQUFXO29DQUFFRSxhQUFhO29DQUFTYSxhQUFhO2dDQUFFOzRCQUNuRDt5QkFDQTtvQkFDRixHQUNBLE1BQ0E7Z0JBRUY7YUFDQTtJQUNGO0lBRUEsS0FBSyxNQUFNMUMsV0FBVzVCLFNBQVU7UUFDL0J1RSxjQUFjdEUsVUFBVUUsTUFBTXlCO0lBQy9CO0lBRUEsT0FBTzNCO0FBQ1I7QUFFQSxTQUFTSixtQkFDUlYsU0FBaUIsRUFDakJFLFdBQW1CLEVBQ25CVyxRQUEyQjtJQUUzQixJQUFJLENBQUN2QyxvQkFBb0IwQixZQUFZO1FBQ3BDLE1BQU0sSUFBSTNCLGVBQ1QsQ0FBQywwQkFBMEIsRUFBRTJCLFVBQVUsMERBQTBELENBQUM7SUFFcEc7SUFFQSxNQUFNcUYsV0FBVzlHLHFCQUFxQnlCO0lBQ3RDLEtBQUssTUFBTXlDLFdBQVc1QixTQUFVO1FBQy9CLElBQUl3RSxTQUFTMUIsUUFBUSxDQUFDbEIsVUFBVTtZQUMvQixNQUFNLElBQUlwRSxlQUNULENBQUMsS0FBSyxFQUFFb0UsUUFBUSxvQkFBb0IsRUFBRTdELGlCQUFpQjZELFNBQVMsQ0FBQyxDQUFDO1FBRXBFO0lBQ0Q7SUFFQSxNQUFNM0IsV0FBVyxJQUFJL0M7SUFDckIrQyxTQUFTZCxTQUFTLEdBQUdBO0lBQ3JCYyxTQUFTQyxPQUFPLENBQUNiO0lBQ2pCLE1BQU1jLE9BQU9GLFNBQVNFLElBQUk7SUFFMUIsTUFBTXNFLE1BQU14SCxZQUFZeUgsUUFBUSxDQUFDbkksS0FBSzRDLFdBQVc7SUFDakRjLFNBQVNrQyxRQUFRLENBQUNzQztJQUNsQnhFLFNBQVNrQyxRQUFRLENBQ2hCOUYsV0FBV0UsS0FBSzRDLFdBQVcsV0FDeEJyQyxRQUFRNEgsUUFBUSxDQUFDbkksS0FBSzRDLFdBQVcsV0FDakMsSUFBSXJDO0lBRVJtRCxTQUFTa0MsUUFBUSxDQUNoQjlGLFdBQVdFLEtBQUs0QyxXQUFXLHlCQUN4QnpDLFdBQVdnSSxRQUFRLENBQ25CL0gsaUJBQWlCMEYsV0FBVyxFQUM1QixzQkFDQTlGLEtBQUs0QyxXQUFXLHlCQUVoQixJQUFJekMsV0FBV0MsaUJBQWlCMEYsV0FBVyxFQUFFLHNCQUFzQjtJQUV2RXBDLFNBQVNrQyxRQUFRLENBQ2hCOUYsV0FBV0UsS0FBSzRDLFdBQVcsNkJBQ3hCekMsV0FBV2dJLFFBQVEsQ0FDbkIvSCxpQkFBaUIyRixlQUFlLEVBQ2hDLDBCQUNBL0YsS0FBSzRDLFdBQVcsNkJBRWhCLElBQUl6QyxXQUFXQyxpQkFBaUIyRixlQUFlLEVBQUUsMEJBQTBCO0lBRy9FLEtBQUssTUFBTSxDQUFDcUMsUUFBUS9DLFFBQVEsSUFBSTVCLFNBQVM2QixPQUFPLEdBQUk7UUFDbkQsTUFBTUMsT0FBT2hFLFdBQVcwRyxTQUFTSSxNQUFNLEdBQUdEO1FBQzFDRixJQUFJSSxTQUFTLENBQUMsQ0FBQyxNQUFNLEVBQUVqRCxTQUFTLEVBQUUsQ0FBQyxLQUFLLEVBQUU1RCxtQkFBbUI0RCxVQUFVO1FBQ3ZFNkMsSUFBSUksU0FBUyxDQUNaLENBQUMsSUFBSSxFQUFFakQsU0FBUyxFQUNoQixDQUFDLEtBQUssRUFBRUUsS0FBSyxzQkFBc0IsRUFBRWpFLGtCQUFrQnNDLE1BQU15QixVQUFVO1FBRXhFMkMsY0FBY3RFLFVBQVVFLE1BQU15QjtJQUMvQjtJQUNBM0IsU0FBU2tDLFFBQVEsQ0FBQyxJQUFJekQsMkJBQTJCc0IsVUFBVTtRQUFFOEUsV0FBVztJQUFLO0lBRTdFLE9BQU83RTtBQUNSO0FBRUEsU0FBU3NFLGNBQ1J0RSxRQUEwQixFQUMxQm1DLGFBQXFCLEVBQ3JCUixPQUFlO0lBRWYsTUFBTW1ELGFBQWEsSUFBSTVILGdCQUFnQlksaUJBQWlCNkQ7SUFDeERtRCxXQUFXNUMsUUFBUSxDQUFDLElBQUk3RCxlQUFlOEQsZUFBZVI7SUFDdERtRCxXQUFXNUMsUUFBUSxDQUFDLElBQUkxRCxlQUFlLEdBQUcyRCxjQUFjLENBQUMsRUFBRVIsU0FBUztJQUNwRW1ELFdBQVc1QyxRQUFRLENBQUMsSUFBSTVEO0lBQ3hCd0csV0FBV3hDLE9BQU8sQ0FBQyxJQUFJNUQ7SUFDdkJvRyxXQUFXeEMsT0FBTyxDQUFDLElBQUkzRDtJQUN2QnFCLFNBQVMrRSxVQUFVLENBQUNEO0FBQ3JCIn0=
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function loadDotenv(path, env) {
|
|
8
|
+
let raw;
|
|
9
|
+
try {
|
|
10
|
+
raw = readFileSync(path, "utf8");
|
|
11
|
+
} catch {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
for (const line of raw.split(/\r?\n/)){
|
|
15
|
+
const trimmed = line.trim();
|
|
16
|
+
if (!trimmed || trimmed.startsWith("#") || !trimmed.includes("=")) continue;
|
|
17
|
+
const eq = trimmed.indexOf("=");
|
|
18
|
+
const key = trimmed.slice(0, eq).trim();
|
|
19
|
+
const value = trimmed.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
20
|
+
if (key && env[key] === undefined) env[key] = value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function seedFromMcpJson(raw) {
|
|
24
|
+
let data;
|
|
25
|
+
try {
|
|
26
|
+
data = JSON.parse(raw);
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
if (!isRecord(data)) return null;
|
|
31
|
+
const servers = data.mcpServers;
|
|
32
|
+
if (!isRecord(servers)) return null;
|
|
33
|
+
const server = servers["codebase-rag"];
|
|
34
|
+
if (!isRecord(server)) return null;
|
|
35
|
+
const url = typeof server.url === "string" ? server.url.trim() : "";
|
|
36
|
+
const headers = isRecord(server.headers) ? server.headers : {};
|
|
37
|
+
const auth = typeof headers.Authorization === "string" ? headers.Authorization.trim() : "";
|
|
38
|
+
const token = auth.toLowerCase().startsWith("bearer ") ? auth.slice(7).trim() : "";
|
|
39
|
+
if (!url.startsWith("http") || token.length === 0) return null;
|
|
40
|
+
return {
|
|
41
|
+
url,
|
|
42
|
+
token
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function mergeIntoMcpJson(input) {
|
|
46
|
+
const { mcpPath, url, token, hostRoot } = input;
|
|
47
|
+
if (!url || !token) {
|
|
48
|
+
return {
|
|
49
|
+
skipped: "no URL/token"
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const xRoot = hostRoot || "${workspaceFolder}";
|
|
53
|
+
mkdirSync(dirname(mcpPath), {
|
|
54
|
+
recursive: true
|
|
55
|
+
});
|
|
56
|
+
let data = {
|
|
57
|
+
mcpServers: {}
|
|
58
|
+
};
|
|
59
|
+
try {
|
|
60
|
+
if (statSync(mcpPath).size > 0) {
|
|
61
|
+
const loaded = JSON.parse(readFileSync(mcpPath, "utf8"));
|
|
62
|
+
if (isRecord(loaded)) data = loaded;
|
|
63
|
+
}
|
|
64
|
+
} catch (err) {
|
|
65
|
+
const code = isRecord(err) && typeof err.code === "string" ? err.code : "";
|
|
66
|
+
if (code !== "ENOENT") {
|
|
67
|
+
console.log("codebase-rag MCP: existing mcp.json is invalid JSON; replacing rag entry only after backup");
|
|
68
|
+
renameSync(mcpPath, `${mcpPath}.bak`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const servers = isRecord(data.mcpServers) ? data.mcpServers : {};
|
|
72
|
+
data.mcpServers = servers;
|
|
73
|
+
servers["codebase-rag"] = {
|
|
74
|
+
url,
|
|
75
|
+
headers: {
|
|
76
|
+
Authorization: `Bearer ${token}`,
|
|
77
|
+
"X-Codebase-Root": xRoot
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
writeFileSync(mcpPath, `${JSON.stringify(data, null, 2)}\n`, "utf8");
|
|
81
|
+
try {
|
|
82
|
+
chmodSync(mcpPath, 0o600);
|
|
83
|
+
} catch {
|
|
84
|
+
// memfs and some hosts omit chmod
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
path: mcpPath,
|
|
88
|
+
root: xRoot
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function workspaceRoot(env = process.env) {
|
|
92
|
+
const fromEnv = env.CODEBASE_RAG_WORKSPACE?.trim();
|
|
93
|
+
if (fromEnv) return fromEnv;
|
|
94
|
+
// Scaffolded copy lives at <repo>/.devcontainer/codebase-rag-mcp.ts
|
|
95
|
+
return dirname(dirname(fileURLToPath(import.meta.url)));
|
|
96
|
+
}
|
|
97
|
+
function mergeFromEnv(env = process.env) {
|
|
98
|
+
const root = workspaceRoot(env);
|
|
99
|
+
const cursorDir = join(root, ".cursor");
|
|
100
|
+
loadDotenv(join(cursorDir, "codebase-rag.env"), env);
|
|
101
|
+
const url = (env.CODEBASE_RAG_MCP_URL ?? "").trim();
|
|
102
|
+
const token = (env.CODEBASE_RAG_MCP_TOKEN ?? "").trim();
|
|
103
|
+
const hostRoot = (env.CODEBASE_RAG_MCP_ROOT ?? "").trim() || root;
|
|
104
|
+
const result = mergeIntoMcpJson({
|
|
105
|
+
mcpPath: join(cursorDir, "mcp.json"),
|
|
106
|
+
url,
|
|
107
|
+
token,
|
|
108
|
+
hostRoot
|
|
109
|
+
});
|
|
110
|
+
if (result.skipped != null) {
|
|
111
|
+
console.log(`codebase-rag MCP: skipped (${result.skipped})`);
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
console.log(`codebase-rag MCP: wrote ${result.path} url=${url} root=${result.root}`);
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
function seedPrint(mcpPath) {
|
|
118
|
+
let raw;
|
|
119
|
+
try {
|
|
120
|
+
raw = readFileSync(mcpPath, "utf8");
|
|
121
|
+
} catch {
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
const creds = seedFromMcpJson(raw);
|
|
125
|
+
if (creds == null) return 1;
|
|
126
|
+
console.log(creds.url);
|
|
127
|
+
console.log(creds.token);
|
|
128
|
+
return 0;
|
|
129
|
+
}
|
|
130
|
+
function main(argv = process.argv.slice(2)) {
|
|
131
|
+
const command = argv[0] ?? "merge";
|
|
132
|
+
if (command === "seed-print") {
|
|
133
|
+
const mcpPath = argv[1];
|
|
134
|
+
if (mcpPath == null || mcpPath.length === 0) return 1;
|
|
135
|
+
return seedPrint(mcpPath);
|
|
136
|
+
}
|
|
137
|
+
if (command === "merge") {
|
|
138
|
+
return mergeFromEnv();
|
|
139
|
+
}
|
|
140
|
+
console.error(`codebase-rag MCP: unknown command ${command}`);
|
|
141
|
+
return 1;
|
|
142
|
+
}
|
|
143
|
+
const invoked = (process.argv[1] ?? "").replaceAll("\\", "/");
|
|
144
|
+
if (invoked.endsWith("/codebase-rag-mcp.ts") || invoked.endsWith("/codebase-rag-mcp.js")) {
|
|
145
|
+
process.exit(main());
|
|
146
|
+
}
|
|
147
|
+
export const codebaseRagMcp = {
|
|
148
|
+
loadDotenv,
|
|
149
|
+
seedFromMcpJson,
|
|
150
|
+
mergeIntoMcpJson,
|
|
151
|
+
mergeFromEnv,
|
|
152
|
+
seedPrint,
|
|
153
|
+
main
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjYWZmb2xkL3NyYy93ZWJhcGkvZGV2Y29udGFpbmVyL2NvZGViYXNlLXJhZy1tY3AudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0Y2htb2RTeW5jLFxuXHRta2RpclN5bmMsXG5cdHJlYWRGaWxlU3luYyxcblx0cmVuYW1lU3luYyxcblx0c3RhdFN5bmMsXG5cdHdyaXRlRmlsZVN5bmMsXG59IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBkaXJuYW1lLCBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gXCJub2RlOnVybFwiO1xuXG5leHBvcnQgdHlwZSBDb2RlYmFzZVJhZ0NyZWRlbnRpYWxzID0ge1xuXHR1cmw6IHN0cmluZztcblx0dG9rZW46IHN0cmluZztcbn07XG5cbmV4cG9ydCB0eXBlIE1jcEpzb24gPSB7XG5cdG1jcFNlcnZlcnM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcblx0W2tleTogc3RyaW5nXTogdW5rbm93bjtcbn07XG5cbmZ1bmN0aW9uIGlzUmVjb3JkKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuXHRyZXR1cm4gdmFsdWUgIT0gbnVsbCAmJiB0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIgJiYgIUFycmF5LmlzQXJyYXkodmFsdWUpO1xufVxuXG5mdW5jdGlvbiBsb2FkRG90ZW52KHBhdGg6IHN0cmluZywgZW52OiBOb2RlSlMuUHJvY2Vzc0Vudik6IHZvaWQge1xuXHRsZXQgcmF3OiBzdHJpbmc7XG5cdHRyeSB7XG5cdFx0cmF3ID0gcmVhZEZpbGVTeW5jKHBhdGgsIFwidXRmOFwiKTtcblx0fSBjYXRjaCB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cdGZvciAoY29uc3QgbGluZSBvZiByYXcuc3BsaXQoL1xccj9cXG4vKSkge1xuXHRcdGNvbnN0IHRyaW1tZWQgPSBsaW5lLnRyaW0oKTtcblx0XHRpZiAoIXRyaW1tZWQgfHwgdHJpbW1lZC5zdGFydHNXaXRoKFwiI1wiKSB8fCAhdHJpbW1lZC5pbmNsdWRlcyhcIj1cIikpIGNvbnRpbnVlO1xuXHRcdGNvbnN0IGVxID0gdHJpbW1lZC5pbmRleE9mKFwiPVwiKTtcblx0XHRjb25zdCBrZXkgPSB0cmltbWVkLnNsaWNlKDAsIGVxKS50cmltKCk7XG5cdFx0Y29uc3QgdmFsdWUgPSB0cmltbWVkXG5cdFx0XHQuc2xpY2UoZXEgKyAxKVxuXHRcdFx0LnRyaW0oKVxuXHRcdFx0LnJlcGxhY2UoL15bXCInXXxbXCInXSQvZywgXCJcIik7XG5cdFx0aWYgKGtleSAmJiBlbnZba2V5XSA9PT0gdW5kZWZpbmVkKSBlbnZba2V5XSA9IHZhbHVlO1xuXHR9XG59XG5cbmZ1bmN0aW9uIHNlZWRGcm9tTWNwSnNvbihyYXc6IHN0cmluZyk6IENvZGViYXNlUmFnQ3JlZGVudGlhbHMgfCBudWxsIHtcblx0bGV0IGRhdGE6IHVua25vd247XG5cdHRyeSB7XG5cdFx0ZGF0YSA9IEpTT04ucGFyc2UocmF3KTtcblx0fSBjYXRjaCB7XG5cdFx0cmV0dXJuIG51bGw7XG5cdH1cblx0aWYgKCFpc1JlY29yZChkYXRhKSkgcmV0dXJuIG51bGw7XG5cdGNvbnN0IHNlcnZlcnMgPSBkYXRhLm1jcFNlcnZlcnM7XG5cdGlmICghaXNSZWNvcmQoc2VydmVycykpIHJldHVybiBudWxsO1xuXHRjb25zdCBzZXJ2ZXIgPSBzZXJ2ZXJzW1wiY29kZWJhc2UtcmFnXCJdO1xuXHRpZiAoIWlzUmVjb3JkKHNlcnZlcikpIHJldHVybiBudWxsO1xuXHRjb25zdCB1cmwgPSB0eXBlb2Ygc2VydmVyLnVybCA9PT0gXCJzdHJpbmdcIiA/IHNlcnZlci51cmwudHJpbSgpIDogXCJcIjtcblx0Y29uc3QgaGVhZGVycyA9IGlzUmVjb3JkKHNlcnZlci5oZWFkZXJzKSA/IHNlcnZlci5oZWFkZXJzIDoge307XG5cdGNvbnN0IGF1dGggPSB0eXBlb2YgaGVhZGVycy5BdXRob3JpemF0aW9uID09PSBcInN0cmluZ1wiID8gaGVhZGVycy5BdXRob3JpemF0aW9uLnRyaW0oKSA6IFwiXCI7XG5cdGNvbnN0IHRva2VuID0gYXV0aC50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoXCJiZWFyZXIgXCIpID8gYXV0aC5zbGljZSg3KS50cmltKCkgOiBcIlwiO1xuXHRpZiAoIXVybC5zdGFydHNXaXRoKFwiaHR0cFwiKSB8fCB0b2tlbi5sZW5ndGggPT09IDApIHJldHVybiBudWxsO1xuXHRyZXR1cm4geyB1cmwsIHRva2VuIH07XG59XG5cbmZ1bmN0aW9uIG1lcmdlSW50b01jcEpzb24oaW5wdXQ6IHtcblx0bWNwUGF0aDogc3RyaW5nO1xuXHR1cmw6IHN0cmluZztcblx0dG9rZW46IHN0cmluZztcblx0aG9zdFJvb3Q6IHN0cmluZztcbn0pOiB7IHNraXBwZWQ/OiBzdHJpbmc7IHBhdGg/OiBzdHJpbmc7IHJvb3Q/OiBzdHJpbmcgfSB7XG5cdGNvbnN0IHsgbWNwUGF0aCwgdXJsLCB0b2tlbiwgaG9zdFJvb3QgfSA9IGlucHV0O1xuXHRpZiAoIXVybCB8fCAhdG9rZW4pIHtcblx0XHRyZXR1cm4geyBza2lwcGVkOiBcIm5vIFVSTC90b2tlblwiIH07XG5cdH1cblxuXHRjb25zdCB4Um9vdCA9IGhvc3RSb290IHx8IFwiJHt3b3Jrc3BhY2VGb2xkZXJ9XCI7XG5cdG1rZGlyU3luYyhkaXJuYW1lKG1jcFBhdGgpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuXHRsZXQgZGF0YTogTWNwSnNvbiA9IHsgbWNwU2VydmVyczoge30gfTtcblx0dHJ5IHtcblx0XHRpZiAoc3RhdFN5bmMobWNwUGF0aCkuc2l6ZSA+IDApIHtcblx0XHRcdGNvbnN0IGxvYWRlZDogdW5rbm93biA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1jcFBhdGgsIFwidXRmOFwiKSk7XG5cdFx0XHRpZiAoaXNSZWNvcmQobG9hZGVkKSkgZGF0YSA9IGxvYWRlZCBhcyBNY3BKc29uO1xuXHRcdH1cblx0fSBjYXRjaCAoZXJyKSB7XG5cdFx0Y29uc3QgY29kZSA9IGlzUmVjb3JkKGVycikgJiYgdHlwZW9mIGVyci5jb2RlID09PSBcInN0cmluZ1wiID8gZXJyLmNvZGUgOiBcIlwiO1xuXHRcdGlmIChjb2RlICE9PSBcIkVOT0VOVFwiKSB7XG5cdFx0XHRjb25zb2xlLmxvZyhcblx0XHRcdFx0XCJjb2RlYmFzZS1yYWcgTUNQOiBleGlzdGluZyBtY3AuanNvbiBpcyBpbnZhbGlkIEpTT047IHJlcGxhY2luZyByYWcgZW50cnkgb25seSBhZnRlciBiYWNrdXBcIixcblx0XHRcdCk7XG5cdFx0XHRyZW5hbWVTeW5jKG1jcFBhdGgsIGAke21jcFBhdGh9LmJha2ApO1xuXHRcdH1cblx0fVxuXG5cdGNvbnN0IHNlcnZlcnMgPSBpc1JlY29yZChkYXRhLm1jcFNlcnZlcnMpID8gZGF0YS5tY3BTZXJ2ZXJzIDoge307XG5cdGRhdGEubWNwU2VydmVycyA9IHNlcnZlcnM7XG5cdHNlcnZlcnNbXCJjb2RlYmFzZS1yYWdcIl0gPSB7XG5cdFx0dXJsLFxuXHRcdGhlYWRlcnM6IHtcblx0XHRcdEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHt0b2tlbn1gLFxuXHRcdFx0XCJYLUNvZGViYXNlLVJvb3RcIjogeFJvb3QsXG5cdFx0fSxcblx0fTtcblx0d3JpdGVGaWxlU3luYyhtY3BQYXRoLCBgJHtKU09OLnN0cmluZ2lmeShkYXRhLCBudWxsLCAyKX1cXG5gLCBcInV0ZjhcIik7XG5cdHRyeSB7XG5cdFx0Y2htb2RTeW5jKG1jcFBhdGgsIDBvNjAwKTtcblx0fSBjYXRjaCB7XG5cdFx0Ly8gbWVtZnMgYW5kIHNvbWUgaG9zdHMgb21pdCBjaG1vZFxuXHR9XG5cdHJldHVybiB7IHBhdGg6IG1jcFBhdGgsIHJvb3Q6IHhSb290IH07XG59XG5cbmZ1bmN0aW9uIHdvcmtzcGFjZVJvb3QoZW52OiBOb2RlSlMuUHJvY2Vzc0VudiA9IHByb2Nlc3MuZW52KTogc3RyaW5nIHtcblx0Y29uc3QgZnJvbUVudiA9IGVudi5DT0RFQkFTRV9SQUdfV09SS1NQQUNFPy50cmltKCk7XG5cdGlmIChmcm9tRW52KSByZXR1cm4gZnJvbUVudjtcblx0Ly8gU2NhZmZvbGRlZCBjb3B5IGxpdmVzIGF0IDxyZXBvPi8uZGV2Y29udGFpbmVyL2NvZGViYXNlLXJhZy1tY3AudHNcblx0cmV0dXJuIGRpcm5hbWUoZGlybmFtZShmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybCkpKTtcbn1cblxuZnVuY3Rpb24gbWVyZ2VGcm9tRW52KGVudjogTm9kZUpTLlByb2Nlc3NFbnYgPSBwcm9jZXNzLmVudik6IG51bWJlciB7XG5cdGNvbnN0IHJvb3QgPSB3b3Jrc3BhY2VSb290KGVudik7XG5cdGNvbnN0IGN1cnNvckRpciA9IGpvaW4ocm9vdCwgXCIuY3Vyc29yXCIpO1xuXHRsb2FkRG90ZW52KGpvaW4oY3Vyc29yRGlyLCBcImNvZGViYXNlLXJhZy5lbnZcIiksIGVudik7XG5cdGNvbnN0IHVybCA9IChlbnYuQ09ERUJBU0VfUkFHX01DUF9VUkwgPz8gXCJcIikudHJpbSgpO1xuXHRjb25zdCB0b2tlbiA9IChlbnYuQ09ERUJBU0VfUkFHX01DUF9UT0tFTiA/PyBcIlwiKS50cmltKCk7XG5cdGNvbnN0IGhvc3RSb290ID0gKGVudi5DT0RFQkFTRV9SQUdfTUNQX1JPT1QgPz8gXCJcIikudHJpbSgpIHx8IHJvb3Q7XG5cdGNvbnN0IHJlc3VsdCA9IG1lcmdlSW50b01jcEpzb24oe1xuXHRcdG1jcFBhdGg6IGpvaW4oY3Vyc29yRGlyLCBcIm1jcC5qc29uXCIpLFxuXHRcdHVybCxcblx0XHR0b2tlbixcblx0XHRob3N0Um9vdCxcblx0fSk7XG5cdGlmIChyZXN1bHQuc2tpcHBlZCAhPSBudWxsKSB7XG5cdFx0Y29uc29sZS5sb2coYGNvZGViYXNlLXJhZyBNQ1A6IHNraXBwZWQgKCR7cmVzdWx0LnNraXBwZWR9KWApO1xuXHRcdHJldHVybiAwO1xuXHR9XG5cdGNvbnNvbGUubG9nKGBjb2RlYmFzZS1yYWcgTUNQOiB3cm90ZSAke3Jlc3VsdC5wYXRofSB1cmw9JHt1cmx9IHJvb3Q9JHtyZXN1bHQucm9vdH1gKTtcblx0cmV0dXJuIDA7XG59XG5cbmZ1bmN0aW9uIHNlZWRQcmludChtY3BQYXRoOiBzdHJpbmcpOiBudW1iZXIge1xuXHRsZXQgcmF3OiBzdHJpbmc7XG5cdHRyeSB7XG5cdFx0cmF3ID0gcmVhZEZpbGVTeW5jKG1jcFBhdGgsIFwidXRmOFwiKTtcblx0fSBjYXRjaCB7XG5cdFx0cmV0dXJuIDE7XG5cdH1cblx0Y29uc3QgY3JlZHMgPSBzZWVkRnJvbU1jcEpzb24ocmF3KTtcblx0aWYgKGNyZWRzID09IG51bGwpIHJldHVybiAxO1xuXHRjb25zb2xlLmxvZyhjcmVkcy51cmwpO1xuXHRjb25zb2xlLmxvZyhjcmVkcy50b2tlbik7XG5cdHJldHVybiAwO1xufVxuXG5mdW5jdGlvbiBtYWluKGFyZ3YgPSBwcm9jZXNzLmFyZ3Yuc2xpY2UoMikpOiBudW1iZXIge1xuXHRjb25zdCBjb21tYW5kID0gYXJndlswXSA/PyBcIm1lcmdlXCI7XG5cdGlmIChjb21tYW5kID09PSBcInNlZWQtcHJpbnRcIikge1xuXHRcdGNvbnN0IG1jcFBhdGggPSBhcmd2WzFdO1xuXHRcdGlmIChtY3BQYXRoID09IG51bGwgfHwgbWNwUGF0aC5sZW5ndGggPT09IDApIHJldHVybiAxO1xuXHRcdHJldHVybiBzZWVkUHJpbnQobWNwUGF0aCk7XG5cdH1cblx0aWYgKGNvbW1hbmQgPT09IFwibWVyZ2VcIikge1xuXHRcdHJldHVybiBtZXJnZUZyb21FbnYoKTtcblx0fVxuXHRjb25zb2xlLmVycm9yKGBjb2RlYmFzZS1yYWcgTUNQOiB1bmtub3duIGNvbW1hbmQgJHtjb21tYW5kfWApO1xuXHRyZXR1cm4gMTtcbn1cblxuY29uc3QgaW52b2tlZCA9IChwcm9jZXNzLmFyZ3ZbMV0gPz8gXCJcIikucmVwbGFjZUFsbChcIlxcXFxcIiwgXCIvXCIpO1xuaWYgKGludm9rZWQuZW5kc1dpdGgoXCIvY29kZWJhc2UtcmFnLW1jcC50c1wiKSB8fCBpbnZva2VkLmVuZHNXaXRoKFwiL2NvZGViYXNlLXJhZy1tY3AuanNcIikpIHtcblx0cHJvY2Vzcy5leGl0KG1haW4oKSk7XG59XG5cbmV4cG9ydCBjb25zdCBjb2RlYmFzZVJhZ01jcCA9IHtcblx0bG9hZERvdGVudixcblx0c2VlZEZyb21NY3BKc29uLFxuXHRtZXJnZUludG9NY3BKc29uLFxuXHRtZXJnZUZyb21FbnYsXG5cdHNlZWRQcmludCxcblx0bWFpbixcbn07XG4iXSwibmFtZXMiOlsiY2htb2RTeW5jIiwibWtkaXJTeW5jIiwicmVhZEZpbGVTeW5jIiwicmVuYW1lU3luYyIsInN0YXRTeW5jIiwid3JpdGVGaWxlU3luYyIsImRpcm5hbWUiLCJqb2luIiwiZmlsZVVSTFRvUGF0aCIsImlzUmVjb3JkIiwidmFsdWUiLCJBcnJheSIsImlzQXJyYXkiLCJsb2FkRG90ZW52IiwicGF0aCIsImVudiIsInJhdyIsImxpbmUiLCJzcGxpdCIsInRyaW1tZWQiLCJ0cmltIiwic3RhcnRzV2l0aCIsImluY2x1ZGVzIiwiZXEiLCJpbmRleE9mIiwia2V5Iiwic2xpY2UiLCJyZXBsYWNlIiwidW5kZWZpbmVkIiwic2VlZEZyb21NY3BKc29uIiwiZGF0YSIsIkpTT04iLCJwYXJzZSIsInNlcnZlcnMiLCJtY3BTZXJ2ZXJzIiwic2VydmVyIiwidXJsIiwiaGVhZGVycyIsImF1dGgiLCJBdXRob3JpemF0aW9uIiwidG9rZW4iLCJ0b0xvd2VyQ2FzZSIsImxlbmd0aCIsIm1lcmdlSW50b01jcEpzb24iLCJpbnB1dCIsIm1jcFBhdGgiLCJob3N0Um9vdCIsInNraXBwZWQiLCJ4Um9vdCIsInJlY3Vyc2l2ZSIsInNpemUiLCJsb2FkZWQiLCJlcnIiLCJjb2RlIiwiY29uc29sZSIsImxvZyIsInN0cmluZ2lmeSIsInJvb3QiLCJ3b3Jrc3BhY2VSb290IiwicHJvY2VzcyIsImZyb21FbnYiLCJDT0RFQkFTRV9SQUdfV09SS1NQQUNFIiwibWVyZ2VGcm9tRW52IiwiY3Vyc29yRGlyIiwiQ09ERUJBU0VfUkFHX01DUF9VUkwiLCJDT0RFQkFTRV9SQUdfTUNQX1RPS0VOIiwiQ09ERUJBU0VfUkFHX01DUF9ST09UIiwicmVzdWx0Iiwic2VlZFByaW50IiwiY3JlZHMiLCJtYWluIiwiYXJndiIsImNvbW1hbmQiLCJlcnJvciIsImludm9rZWQiLCJyZXBsYWNlQWxsIiwiZW5kc1dpdGgiLCJleGl0IiwiY29kZWJhc2VSYWdNY3AiXSwibWFwcGluZ3MiOiJBQUFBLFNBQ0NBLFNBQVMsRUFDVEMsU0FBUyxFQUNUQyxZQUFZLEVBQ1pDLFVBQVUsRUFDVkMsUUFBUSxFQUNSQyxhQUFhLFFBQ1AsVUFBVTtBQUNqQixTQUFTQyxPQUFPLEVBQUVDLElBQUksUUFBUSxZQUFZO0FBQzFDLFNBQVNDLGFBQWEsUUFBUSxXQUFXO0FBWXpDLFNBQVNDLFNBQVNDLEtBQWM7SUFDL0IsT0FBT0EsU0FBUyxRQUFRLE9BQU9BLFVBQVUsWUFBWSxDQUFDQyxNQUFNQyxPQUFPLENBQUNGO0FBQ3JFO0FBRUEsU0FBU0csV0FBV0MsSUFBWSxFQUFFQyxHQUFzQjtJQUN2RCxJQUFJQztJQUNKLElBQUk7UUFDSEEsTUFBTWQsYUFBYVksTUFBTTtJQUMxQixFQUFFLE9BQU07UUFDUDtJQUNEO0lBQ0EsS0FBSyxNQUFNRyxRQUFRRCxJQUFJRSxLQUFLLENBQUMsU0FBVTtRQUN0QyxNQUFNQyxVQUFVRixLQUFLRyxJQUFJO1FBQ3pCLElBQUksQ0FBQ0QsV0FBV0EsUUFBUUUsVUFBVSxDQUFDLFFBQVEsQ0FBQ0YsUUFBUUcsUUFBUSxDQUFDLE1BQU07UUFDbkUsTUFBTUMsS0FBS0osUUFBUUssT0FBTyxDQUFDO1FBQzNCLE1BQU1DLE1BQU1OLFFBQVFPLEtBQUssQ0FBQyxHQUFHSCxJQUFJSCxJQUFJO1FBQ3JDLE1BQU1WLFFBQVFTLFFBQ1pPLEtBQUssQ0FBQ0gsS0FBSyxHQUNYSCxJQUFJLEdBQ0pPLE9BQU8sQ0FBQyxnQkFBZ0I7UUFDMUIsSUFBSUYsT0FBT1YsR0FBRyxDQUFDVSxJQUFJLEtBQUtHLFdBQVdiLEdBQUcsQ0FBQ1UsSUFBSSxHQUFHZjtJQUMvQztBQUNEO0FBRUEsU0FBU21CLGdCQUFnQmIsR0FBVztJQUNuQyxJQUFJYztJQUNKLElBQUk7UUFDSEEsT0FBT0MsS0FBS0MsS0FBSyxDQUFDaEI7SUFDbkIsRUFBRSxPQUFNO1FBQ1AsT0FBTztJQUNSO0lBQ0EsSUFBSSxDQUFDUCxTQUFTcUIsT0FBTyxPQUFPO0lBQzVCLE1BQU1HLFVBQVVILEtBQUtJLFVBQVU7SUFDL0IsSUFBSSxDQUFDekIsU0FBU3dCLFVBQVUsT0FBTztJQUMvQixNQUFNRSxTQUFTRixPQUFPLENBQUMsZUFBZTtJQUN0QyxJQUFJLENBQUN4QixTQUFTMEIsU0FBUyxPQUFPO0lBQzlCLE1BQU1DLE1BQU0sT0FBT0QsT0FBT0MsR0FBRyxLQUFLLFdBQVdELE9BQU9DLEdBQUcsQ0FBQ2hCLElBQUksS0FBSztJQUNqRSxNQUFNaUIsVUFBVTVCLFNBQVMwQixPQUFPRSxPQUFPLElBQUlGLE9BQU9FLE9BQU8sR0FBRyxDQUFDO0lBQzdELE1BQU1DLE9BQU8sT0FBT0QsUUFBUUUsYUFBYSxLQUFLLFdBQVdGLFFBQVFFLGFBQWEsQ0FBQ25CLElBQUksS0FBSztJQUN4RixNQUFNb0IsUUFBUUYsS0FBS0csV0FBVyxHQUFHcEIsVUFBVSxDQUFDLGFBQWFpQixLQUFLWixLQUFLLENBQUMsR0FBR04sSUFBSSxLQUFLO0lBQ2hGLElBQUksQ0FBQ2dCLElBQUlmLFVBQVUsQ0FBQyxXQUFXbUIsTUFBTUUsTUFBTSxLQUFLLEdBQUcsT0FBTztJQUMxRCxPQUFPO1FBQUVOO1FBQUtJO0lBQU07QUFDckI7QUFFQSxTQUFTRyxpQkFBaUJDLEtBS3pCO0lBQ0EsTUFBTSxFQUFFQyxPQUFPLEVBQUVULEdBQUcsRUFBRUksS0FBSyxFQUFFTSxRQUFRLEVBQUUsR0FBR0Y7SUFDMUMsSUFBSSxDQUFDUixPQUFPLENBQUNJLE9BQU87UUFDbkIsT0FBTztZQUFFTyxTQUFTO1FBQWU7SUFDbEM7SUFFQSxNQUFNQyxRQUFRRixZQUFZO0lBQzFCN0MsVUFBVUssUUFBUXVDLFVBQVU7UUFBRUksV0FBVztJQUFLO0lBRTlDLElBQUluQixPQUFnQjtRQUFFSSxZQUFZLENBQUM7SUFBRTtJQUNyQyxJQUFJO1FBQ0gsSUFBSTlCLFNBQVN5QyxTQUFTSyxJQUFJLEdBQUcsR0FBRztZQUMvQixNQUFNQyxTQUFrQnBCLEtBQUtDLEtBQUssQ0FBQzlCLGFBQWEyQyxTQUFTO1lBQ3pELElBQUlwQyxTQUFTMEMsU0FBU3JCLE9BQU9xQjtRQUM5QjtJQUNELEVBQUUsT0FBT0MsS0FBSztRQUNiLE1BQU1DLE9BQU81QyxTQUFTMkMsUUFBUSxPQUFPQSxJQUFJQyxJQUFJLEtBQUssV0FBV0QsSUFBSUMsSUFBSSxHQUFHO1FBQ3hFLElBQUlBLFNBQVMsVUFBVTtZQUN0QkMsUUFBUUMsR0FBRyxDQUNWO1lBRURwRCxXQUFXMEMsU0FBUyxHQUFHQSxRQUFRLElBQUksQ0FBQztRQUNyQztJQUNEO0lBRUEsTUFBTVosVUFBVXhCLFNBQVNxQixLQUFLSSxVQUFVLElBQUlKLEtBQUtJLFVBQVUsR0FBRyxDQUFDO0lBQy9ESixLQUFLSSxVQUFVLEdBQUdEO0lBQ2xCQSxPQUFPLENBQUMsZUFBZSxHQUFHO1FBQ3pCRztRQUNBQyxTQUFTO1lBQ1JFLGVBQWUsQ0FBQyxPQUFPLEVBQUVDLE9BQU87WUFDaEMsbUJBQW1CUTtRQUNwQjtJQUNEO0lBQ0EzQyxjQUFjd0MsU0FBUyxHQUFHZCxLQUFLeUIsU0FBUyxDQUFDMUIsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDLEVBQUU7SUFDN0QsSUFBSTtRQUNIOUIsVUFBVTZDLFNBQVM7SUFDcEIsRUFBRSxPQUFNO0lBQ1Asa0NBQWtDO0lBQ25DO0lBQ0EsT0FBTztRQUFFL0IsTUFBTStCO1FBQVNZLE1BQU1UO0lBQU07QUFDckM7QUFFQSxTQUFTVSxjQUFjM0MsTUFBeUI0QyxRQUFRNUMsR0FBRztJQUMxRCxNQUFNNkMsVUFBVTdDLElBQUk4QyxzQkFBc0IsRUFBRXpDO0lBQzVDLElBQUl3QyxTQUFTLE9BQU9BO0lBQ3BCLG9FQUFvRTtJQUNwRSxPQUFPdEQsUUFBUUEsUUFBUUUsY0FBYyxZQUFZNEIsR0FBRztBQUNyRDtBQUVBLFNBQVMwQixhQUFhL0MsTUFBeUI0QyxRQUFRNUMsR0FBRztJQUN6RCxNQUFNMEMsT0FBT0MsY0FBYzNDO0lBQzNCLE1BQU1nRCxZQUFZeEQsS0FBS2tELE1BQU07SUFDN0I1QyxXQUFXTixLQUFLd0QsV0FBVyxxQkFBcUJoRDtJQUNoRCxNQUFNcUIsTUFBTSxBQUFDckIsQ0FBQUEsSUFBSWlELG9CQUFvQixJQUFJLEVBQUMsRUFBRzVDLElBQUk7SUFDakQsTUFBTW9CLFFBQVEsQUFBQ3pCLENBQUFBLElBQUlrRCxzQkFBc0IsSUFBSSxFQUFDLEVBQUc3QyxJQUFJO0lBQ3JELE1BQU0wQixXQUFXLEFBQUMvQixDQUFBQSxJQUFJbUQscUJBQXFCLElBQUksRUFBQyxFQUFHOUMsSUFBSSxNQUFNcUM7SUFDN0QsTUFBTVUsU0FBU3hCLGlCQUFpQjtRQUMvQkUsU0FBU3RDLEtBQUt3RCxXQUFXO1FBQ3pCM0I7UUFDQUk7UUFDQU07SUFDRDtJQUNBLElBQUlxQixPQUFPcEIsT0FBTyxJQUFJLE1BQU07UUFDM0JPLFFBQVFDLEdBQUcsQ0FBQyxDQUFDLDJCQUEyQixFQUFFWSxPQUFPcEIsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUMzRCxPQUFPO0lBQ1I7SUFDQU8sUUFBUUMsR0FBRyxDQUFDLENBQUMsd0JBQXdCLEVBQUVZLE9BQU9yRCxJQUFJLENBQUMsS0FBSyxFQUFFc0IsSUFBSSxNQUFNLEVBQUUrQixPQUFPVixJQUFJLEVBQUU7SUFDbkYsT0FBTztBQUNSO0FBRUEsU0FBU1csVUFBVXZCLE9BQWU7SUFDakMsSUFBSTdCO0lBQ0osSUFBSTtRQUNIQSxNQUFNZCxhQUFhMkMsU0FBUztJQUM3QixFQUFFLE9BQU07UUFDUCxPQUFPO0lBQ1I7SUFDQSxNQUFNd0IsUUFBUXhDLGdCQUFnQmI7SUFDOUIsSUFBSXFELFNBQVMsTUFBTSxPQUFPO0lBQzFCZixRQUFRQyxHQUFHLENBQUNjLE1BQU1qQyxHQUFHO0lBQ3JCa0IsUUFBUUMsR0FBRyxDQUFDYyxNQUFNN0IsS0FBSztJQUN2QixPQUFPO0FBQ1I7QUFFQSxTQUFTOEIsS0FBS0MsT0FBT1osUUFBUVksSUFBSSxDQUFDN0MsS0FBSyxDQUFDLEVBQUU7SUFDekMsTUFBTThDLFVBQVVELElBQUksQ0FBQyxFQUFFLElBQUk7SUFDM0IsSUFBSUMsWUFBWSxjQUFjO1FBQzdCLE1BQU0zQixVQUFVMEIsSUFBSSxDQUFDLEVBQUU7UUFDdkIsSUFBSTFCLFdBQVcsUUFBUUEsUUFBUUgsTUFBTSxLQUFLLEdBQUcsT0FBTztRQUNwRCxPQUFPMEIsVUFBVXZCO0lBQ2xCO0lBQ0EsSUFBSTJCLFlBQVksU0FBUztRQUN4QixPQUFPVjtJQUNSO0lBQ0FSLFFBQVFtQixLQUFLLENBQUMsQ0FBQyxrQ0FBa0MsRUFBRUQsU0FBUztJQUM1RCxPQUFPO0FBQ1I7QUFFQSxNQUFNRSxVQUFVLEFBQUNmLENBQUFBLFFBQVFZLElBQUksQ0FBQyxFQUFFLElBQUksRUFBQyxFQUFHSSxVQUFVLENBQUMsTUFBTTtBQUN6RCxJQUFJRCxRQUFRRSxRQUFRLENBQUMsMkJBQTJCRixRQUFRRSxRQUFRLENBQUMseUJBQXlCO0lBQ3pGakIsUUFBUWtCLElBQUksQ0FBQ1A7QUFDZDtBQUVBLE9BQU8sTUFBTVEsaUJBQWlCO0lBQzdCakU7SUFDQWdCO0lBQ0FjO0lBQ0FtQjtJQUNBTTtJQUNBRTtBQUNELEVBQUUifQ==
|