@decohere/create 0.0.1-dev.17 → 0.0.1-dev.19
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/cli.js +30 -5
- package/commonjs/src/domain/prompt.js +55 -0
- package/commonjs/src/models/compose.model.js +82 -0
- package/commonjs/src/models/config-yaml.model.js +34 -0
- package/commonjs/src/models/const.js +29 -0
- package/commonjs/src/models/container-image.model.js +88 -0
- package/commonjs/src/models/dev-container.model.js +73 -0
- package/commonjs/src/models/env-file.model.js +33 -0
- package/commonjs/src/models/gitignore.model.js +32 -0
- package/commonjs/src/models/launch-json.model.js +52 -0
- package/commonjs/src/models/package-json.model.js +64 -0
- package/commonjs/src/models/project.model.js +126 -0
- package/commonjs/src/models/source-file.js +6 -0
- package/commonjs/src/models/tsconfig.model.js +34 -0
- package/commonjs/src/models/vscode-settings.model.js +31 -0
- package/commonjs/src/runner.js +56 -0
- package/commonjs/src/services/scaffold.service.js +62 -0
- package/commonjs/src/version.js +32 -0
- package/commonjs/src/webapi/create-api.js +169 -0
- package/commonjs/src/webapi/features/auth.feature.js +166 -0
- package/commonjs/src/webapi/features/auth0-cli.js +151 -0
- package/commonjs/src/webapi/features/database.feature.js +151 -0
- package/commonjs/src/webapi/features/finalize.feature.js +51 -0
- package/commonjs/src/webapi/features/postman.feature.js +309 -0
- package/commonjs/src/webapi/models/api-package-json.model.js +57 -0
- package/commonjs/src/webapi/models/auth-config.model.js +23 -0
- package/commonjs/src/webapi/models/controller-source-file.model.js +180 -0
- package/commonjs/src/webapi/models/main-source-file.model.js +132 -0
- package/commonjs/src/webapi/models/sample-files.model.js +60 -0
- package/es6/src/cli.js +30 -5
- package/es6/src/domain/prompt.js +37 -0
- package/es6/src/models/compose.model.js +77 -0
- package/es6/src/models/config-yaml.model.js +30 -0
- package/es6/src/models/const.js +19 -0
- package/es6/src/models/container-image.model.js +84 -0
- package/es6/src/models/dev-container.model.js +68 -0
- package/es6/src/models/env-file.model.js +29 -0
- package/es6/src/models/gitignore.model.js +22 -0
- package/es6/src/models/launch-json.model.js +42 -0
- package/es6/src/models/package-json.model.js +60 -0
- package/es6/src/models/project.model.js +111 -0
- package/es6/src/models/source-file.js +3 -0
- package/es6/src/models/tsconfig.model.js +24 -0
- package/es6/src/models/vscode-settings.model.js +21 -0
- package/es6/src/runner.js +55 -0
- package/es6/src/services/scaffold.service.js +52 -0
- package/es6/src/version.js +22 -0
- package/es6/src/webapi/create-api.js +151 -0
- package/es6/src/webapi/features/auth.feature.js +115 -0
- package/es6/src/webapi/features/auth0-cli.js +116 -0
- package/es6/src/webapi/features/database.feature.js +141 -0
- package/es6/src/webapi/features/finalize.feature.js +41 -0
- package/es6/src/webapi/features/postman.feature.js +258 -0
- package/es6/src/webapi/models/api-package-json.model.js +52 -0
- package/es6/src/webapi/models/auth-config.model.js +19 -0
- package/es6/src/webapi/models/controller-source-file.model.js +171 -0
- package/es6/src/webapi/models/main-source-file.model.js +128 -0
- package/es6/src/webapi/models/sample-files.model.js +42 -0
- package/package.json +2 -2
- package/types/src/domain/prompt.d.ts +2 -0
- package/types/src/models/compose.model.d.ts +32 -0
- package/types/src/models/config-yaml.model.d.ts +16 -0
- package/types/src/models/const.d.ts +17 -0
- package/types/src/models/container-image.model.d.ts +15 -0
- package/types/src/models/dev-container.model.d.ts +21 -0
- package/types/src/models/env-file.model.d.ts +14 -0
- package/types/src/models/gitignore.model.d.ts +6 -0
- package/types/src/models/launch-json.model.d.ts +5 -0
- package/types/src/models/package-json.model.d.ts +18 -0
- package/types/src/models/project.model.d.ts +55 -0
- package/types/src/models/source-file.d.ts +11 -0
- package/types/src/models/tsconfig.model.d.ts +5 -0
- package/types/src/models/vscode-settings.model.d.ts +7 -0
- package/types/src/runner.d.ts +13 -0
- package/types/src/services/scaffold.service.d.ts +22 -0
- package/types/src/version.d.ts +2 -0
- package/types/src/webapi/create-api.d.ts +7 -0
- package/types/src/webapi/features/auth.feature.d.ts +7 -0
- package/types/src/webapi/features/auth0-cli.d.ts +22 -0
- package/types/src/webapi/features/database.feature.d.ts +5 -0
- package/types/src/webapi/features/finalize.feature.d.ts +2 -0
- package/types/src/webapi/features/postman.feature.d.ts +7 -0
- package/types/src/webapi/models/api-package-json.model.d.ts +17 -0
- package/types/src/webapi/models/auth-config.model.d.ts +18 -0
- package/types/src/webapi/models/controller-source-file.model.d.ts +42 -0
- package/types/src/webapi/models/main-source-file.model.d.ts +36 -0
- package/types/src/webapi/models/sample-files.model.d.ts +7 -0
- package/commonjs/src/scaffold.js +0 -89
- package/commonjs/src/templates.js +0 -306
- package/es6/src/scaffold.js +0 -79
- package/es6/src/templates.js +0 -246
- package/types/src/scaffold.d.ts +0 -6
- package/types/src/templates.d.ts +0 -20
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run the scaffold inside a pre-built Docker builder image.
|
|
3
|
+
*
|
|
4
|
+
* Called when `DECOHERE_BUILDER` is not set — i.e. the CLI is running on the
|
|
5
|
+
* host, outside the container. Mounts the target directory as `/workspace` so
|
|
6
|
+
* the scaffolded files are written back to the host filesystem.
|
|
7
|
+
*
|
|
8
|
+
* If `~/.config/auth0` exists on the host the directory is also mounted so
|
|
9
|
+
* the auth0 CLI inside the container can reuse existing credentials silently.
|
|
10
|
+
*/
|
|
11
|
+
export declare function runInBuilder(opts: {
|
|
12
|
+
d?: string;
|
|
13
|
+
}): never;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { WorkspaceScaffold } from "../models/project.model.js";
|
|
2
|
+
/**
|
|
3
|
+
* A feature has three responsibilities:
|
|
4
|
+
* 1. `getOptions` — resolve provider selection and any follow-up questions.
|
|
5
|
+
* Receives the options collected so far; returns only the keys it owns.
|
|
6
|
+
* Short-circuits if the caller already supplied those keys via CLI flags.
|
|
7
|
+
* 2. `scaffold` — mutate the workspace models and/or write files using the
|
|
8
|
+
* fully-resolved options. Called after ALL features have gathered options
|
|
9
|
+
* but BEFORE files are written to disk.
|
|
10
|
+
* 3. `finalize` (optional) — run post-write actions (e.g. install dependencies).
|
|
11
|
+
* Called after workspace.scaffold() has flushed all files to disk.
|
|
12
|
+
*/
|
|
13
|
+
export interface Feature<TOptions extends object = object> {
|
|
14
|
+
getOptions(workspace: WorkspaceScaffold, cliOptions: Partial<TOptions>): Promise<Partial<TOptions>>;
|
|
15
|
+
scaffold(workspace: WorkspaceScaffold, options: TOptions): Promise<void> | void;
|
|
16
|
+
finalize?(workspace: WorkspaceScaffold, options: TOptions): Promise<void> | void;
|
|
17
|
+
}
|
|
18
|
+
declare function scaffold(workspace: WorkspaceScaffold, cliOptions: object, features: Feature[]): Promise<void>;
|
|
19
|
+
export declare const ScaffoldService: {
|
|
20
|
+
scaffold: typeof scaffold;
|
|
21
|
+
};
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
declare const REQUIRED_SCOPES = "create:clients";
|
|
2
|
+
export declare class Auth0AuthError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export interface Auth0Tenant {
|
|
6
|
+
name: string;
|
|
7
|
+
active?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function isInstalled(): boolean;
|
|
10
|
+
export declare function listTenants(): Auth0Tenant[];
|
|
11
|
+
export declare function login(): boolean;
|
|
12
|
+
export declare function listApis(): Array<{
|
|
13
|
+
identifier: string;
|
|
14
|
+
name: string;
|
|
15
|
+
}>;
|
|
16
|
+
export declare function createApi(name: string, identifier: string): {
|
|
17
|
+
identifier: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function createSpaApp(name: string, callbackUrl: string): {
|
|
20
|
+
client_id: string;
|
|
21
|
+
};
|
|
22
|
+
export { REQUIRED_SCOPES };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { KeyedModel, SourceFile } from "../../models/source-file.js";
|
|
2
|
+
/**
|
|
3
|
+
* Builder for `projects/api/package.json`.
|
|
4
|
+
*
|
|
5
|
+
* Starts with the core cortex + crucible deps. Features can call
|
|
6
|
+
* `addDependency` / `addDevDependency` to extend.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ApiPackageJson implements KeyedModel {
|
|
9
|
+
private readonly projectName;
|
|
10
|
+
readonly key: string;
|
|
11
|
+
private readonly _dependencies;
|
|
12
|
+
private readonly _devDependencies;
|
|
13
|
+
constructor(projectName: string);
|
|
14
|
+
addDependency(name: string, version: string): this;
|
|
15
|
+
addDevDependency(name: string, version: string): this;
|
|
16
|
+
files(): SourceFile[];
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { KeyedModel, SourceFile } from "../../models/source-file.js";
|
|
2
|
+
export type AuthConfig = {
|
|
3
|
+
issuerBaseUrl: string;
|
|
4
|
+
audience: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Data-carrier model for auth configuration.
|
|
8
|
+
*
|
|
9
|
+
* Registered by AuthFeature when auth0 is configured. Other features (e.g.
|
|
10
|
+
* PostmanFeature) retrieve it via workspace.getModel(WELL_KNOWN_FILES.AUTH_CONFIG).
|
|
11
|
+
* Produces no files — exists solely so features can communicate auth details.
|
|
12
|
+
*/
|
|
13
|
+
export declare class AuthConfigModel implements KeyedModel {
|
|
14
|
+
readonly config: AuthConfig;
|
|
15
|
+
readonly key: string;
|
|
16
|
+
constructor(config: AuthConfig);
|
|
17
|
+
files(): SourceFile[];
|
|
18
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { KeyedModel, SourceFile } from "../../models/source-file.js";
|
|
2
|
+
/**
|
|
3
|
+
* A controller method. Features call `addDecorator()` to prepend decorators
|
|
4
|
+
* before the HTTP verb decorator (e.g. `@AllowAnonymous` before `@Get()`).
|
|
5
|
+
*/
|
|
6
|
+
export declare class ControllerMethod {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
private readonly _httpDecorator;
|
|
9
|
+
private readonly _params;
|
|
10
|
+
private readonly _isAsync;
|
|
11
|
+
private readonly _body;
|
|
12
|
+
private readonly _extraDecorators;
|
|
13
|
+
constructor(name: string, _httpDecorator: string, _params: string, _isAsync: boolean, _body: string[]);
|
|
14
|
+
addDecorator(decorator: string): this;
|
|
15
|
+
render(): string[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Model for `projects/api/src/controllers/hello.controller.ts`.
|
|
19
|
+
*
|
|
20
|
+
* Pre-initialised with all routes and their HTTP decorators. Features mutate
|
|
21
|
+
* the model via `getMethod(name).addDecorator(...)`, `addDecorator(...)` (class
|
|
22
|
+
* level), `addCortexImport(...)`, `addImport(...)`, and `addConstructorParam(...)`.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ControllerSourceFile implements KeyedModel {
|
|
25
|
+
readonly key: string;
|
|
26
|
+
private readonly _cortexImports;
|
|
27
|
+
private readonly _extraImportGroups;
|
|
28
|
+
private readonly _classDecorators;
|
|
29
|
+
private readonly _ctorParams;
|
|
30
|
+
private readonly _methods;
|
|
31
|
+
/** Retrieve a method by name to mutate its decorators. */
|
|
32
|
+
getMethod(name: string): ControllerMethod;
|
|
33
|
+
/** Add a class-level decorator (e.g. `@Authorize`). */
|
|
34
|
+
addDecorator(decorator: string): this;
|
|
35
|
+
/** Add a named import from `@decohere/cortex`. */
|
|
36
|
+
addCortexImport(name: string, typeOnly?: boolean): this;
|
|
37
|
+
/** Add a named import from any other module. */
|
|
38
|
+
addImport(name: string, from: string, typeOnly?: boolean): this;
|
|
39
|
+
/** Add a constructor parameter (e.g. an injected dependency). */
|
|
40
|
+
addConstructorParam(param: string): this;
|
|
41
|
+
files(): SourceFile[];
|
|
42
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { KeyedModel, SourceFile } from "../../models/source-file.js";
|
|
2
|
+
export type TypeOrmImport = {
|
|
3
|
+
className: string;
|
|
4
|
+
importPath: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Model for `projects/api/src/main.ts`.
|
|
8
|
+
*
|
|
9
|
+
* Starts with the minimal HTTP + YAML config setup. Features mutate the model
|
|
10
|
+
* by calling addSideEffectImport / addImport / addBuilderCall / addEntity /
|
|
11
|
+
* addRepository. files() renders whatever has been accumulated.
|
|
12
|
+
*/
|
|
13
|
+
export declare class MainSourceFile implements KeyedModel {
|
|
14
|
+
private readonly appName;
|
|
15
|
+
readonly key: string;
|
|
16
|
+
private readonly _sideEffectImports;
|
|
17
|
+
private readonly _extraImports;
|
|
18
|
+
private readonly _builderCalls;
|
|
19
|
+
private readonly _entities;
|
|
20
|
+
private readonly _repositories;
|
|
21
|
+
constructor(appName: string);
|
|
22
|
+
/** Adds a bare side-effect import, e.g. `@decohere/cortex/auth`. */
|
|
23
|
+
addSideEffectImport(path: string): this;
|
|
24
|
+
/** Adds a named import, e.g. `import { Foo } from "bar"`. */
|
|
25
|
+
addImport(name: string, from: string, typeOnly?: boolean): this;
|
|
26
|
+
/**
|
|
27
|
+
* Adds a builder call inserted after `.withConfiguration()` and before
|
|
28
|
+
* `.withServices()`. Pass the call without leading dot, e.g. `.withAuth()`.
|
|
29
|
+
*/
|
|
30
|
+
addBuilderCall(call: string): this;
|
|
31
|
+
/** Adds a TypeORM entity — import and entry in `withTypeOrm({ entities })`. */
|
|
32
|
+
addEntity(entity: TypeOrmImport): this;
|
|
33
|
+
/** Adds a TypeORM repository — import and entry in `withTypeOrm({ repositories })`. */
|
|
34
|
+
addRepository(repo: TypeOrmImport): this;
|
|
35
|
+
files(): SourceFile[];
|
|
36
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SourceFile, SourceFileProvider } from "../../models/source-file.js";
|
|
2
|
+
export declare class SampleConfigModel implements SourceFileProvider {
|
|
3
|
+
files(): SourceFile[];
|
|
4
|
+
}
|
|
5
|
+
export declare class SampleServiceModel implements SourceFileProvider {
|
|
6
|
+
files(): SourceFile[];
|
|
7
|
+
}
|
package/commonjs/src/scaffold.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "scaffold", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return scaffold;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _nodefs = require("node:fs");
|
|
12
|
-
const _promises = require("node:fs/promises");
|
|
13
|
-
const _nodepath = require("node:path");
|
|
14
|
-
const _promises1 = require("node:readline/promises");
|
|
15
|
-
const _interop = require("@decohere/nexus/interop");
|
|
16
|
-
const _templates = require("./templates.js");
|
|
17
|
-
async function scaffold(targetDir, opts) {
|
|
18
|
-
const name = (0, _nodepath.basename)(targetDir);
|
|
19
|
-
if ((0, _nodefs.existsSync)(targetDir) && (0, _nodefs.readdirSync)(targetDir).length > 0 && !opts.yes) {
|
|
20
|
-
const rl = (0, _promises1.createInterface)({
|
|
21
|
-
input: process.stdin,
|
|
22
|
-
output: process.stdout
|
|
23
|
-
});
|
|
24
|
-
const answer = await rl.question(`Directory "${name}" is not empty. Continue? [y/N] `);
|
|
25
|
-
rl.close();
|
|
26
|
-
if (!answer.trim().toLowerCase().startsWith("y")) {
|
|
27
|
-
console.log("Aborted.");
|
|
28
|
-
process.exit(0);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (opts.template === "webapi") {
|
|
32
|
-
const dbOpts = opts.database ? {
|
|
33
|
-
database: opts.database
|
|
34
|
-
} : undefined;
|
|
35
|
-
await (0, _promises.mkdir)((0, _nodepath.join)(targetDir, "projects", "api", "src", "controllers"), {
|
|
36
|
-
recursive: true
|
|
37
|
-
});
|
|
38
|
-
await (0, _promises.mkdir)((0, _nodepath.join)(targetDir, "config"), {
|
|
39
|
-
recursive: true
|
|
40
|
-
});
|
|
41
|
-
const writes = [
|
|
42
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "package.json"), (0, _templates.WEB_API_ROOT_PACKAGE_JSON)(name, dbOpts)),
|
|
43
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "tsconfig.json"), _templates.WEB_API_TSCONFIG),
|
|
44
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "projects", "api", "package.json"), (0, _templates.WEB_API_APP_PACKAGE_JSON)(name)),
|
|
45
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "projects", "api", "src", "main.ts"), (0, _templates.WEB_API_MAIN_TS)(name, dbOpts)),
|
|
46
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "projects", "api", "src", "controllers", "hello.controller.ts"), _templates.HELLO_CONTROLLER_TS),
|
|
47
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "projects", "api", "src", "sample.config.ts"), _templates.SAMPLE_CONFIG_TS),
|
|
48
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "projects", "api", "src", "sample.service.ts"), _templates.SAMPLE_SERVICE_TS),
|
|
49
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "config", "config.yaml"), (0, _templates.CONFIG_YAML)(name, dbOpts)),
|
|
50
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "config", "config.dev.yaml"), _templates.CONFIG_DEV_YAML)
|
|
51
|
-
];
|
|
52
|
-
if (opts.database === "typeorm") {
|
|
53
|
-
await (0, _promises.mkdir)((0, _nodepath.join)(targetDir, "projects", "api", "src", "entities"), {
|
|
54
|
-
recursive: true
|
|
55
|
-
});
|
|
56
|
-
await (0, _promises.mkdir)((0, _nodepath.join)(targetDir, "projects", "api", "src", "repositories"), {
|
|
57
|
-
recursive: true
|
|
58
|
-
});
|
|
59
|
-
writes.push((0, _promises.writeFile)((0, _nodepath.join)(targetDir, "projects", "api", "src", "entities", "sample.entity.ts"), _templates.SAMPLE_ENTITY_TS), (0, _promises.writeFile)((0, _nodepath.join)(targetDir, "projects", "api", "src", "repositories", "sample.repository.ts"), _templates.SAMPLE_REPOSITORY_TS), (0, _promises.writeFile)((0, _nodepath.join)(targetDir, "config", "config.prod.yaml"), _templates.CONFIG_PROD_YAML));
|
|
60
|
-
}
|
|
61
|
-
await Promise.all(writes);
|
|
62
|
-
} else {
|
|
63
|
-
await (0, _promises.mkdir)((0, _nodepath.join)(targetDir, "projects", "app", "src"), {
|
|
64
|
-
recursive: true
|
|
65
|
-
});
|
|
66
|
-
await Promise.all([
|
|
67
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "package.json"), (0, _templates.ROOT_PACKAGE_JSON)(name)),
|
|
68
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "tsconfig.json"), _templates.TSCONFIG),
|
|
69
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "projects", "app", "package.json"), (0, _templates.APP_PACKAGE_JSON)(name)),
|
|
70
|
-
(0, _promises.writeFile)((0, _nodepath.join)(targetDir, "projects", "app", "src", "main.ts"), _templates.MAIN_TS)
|
|
71
|
-
]);
|
|
72
|
-
}
|
|
73
|
-
console.log(`\nScaffolded ${name}. Installing dependencies...\n`);
|
|
74
|
-
let pm = (0, _interop.detectPackageManager)(targetDir);
|
|
75
|
-
if (pm == null) {
|
|
76
|
-
pm = await (0, _interop.promptForPackageManager)();
|
|
77
|
-
}
|
|
78
|
-
await pm.install({
|
|
79
|
-
cwd: targetDir
|
|
80
|
-
});
|
|
81
|
-
console.log(`\nDone! Next steps:\n`);
|
|
82
|
-
if ((0, _nodepath.basename)(targetDir) !== targetDir) {
|
|
83
|
-
console.log(` cd ${name}`);
|
|
84
|
-
}
|
|
85
|
-
console.log(" pnpm build # forge build");
|
|
86
|
-
console.log(" pnpm dev # flux serve\n");
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvc2NhZmZvbGQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZGRpclN5bmMgfSBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHsgbWtkaXIsIHdyaXRlRmlsZSB9IGZyb20gXCJub2RlOmZzL3Byb21pc2VzXCI7XG5pbXBvcnQgeyBiYXNlbmFtZSwgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGNyZWF0ZUludGVyZmFjZSB9IGZyb20gXCJub2RlOnJlYWRsaW5lL3Byb21pc2VzXCI7XG5pbXBvcnQgeyBkZXRlY3RQYWNrYWdlTWFuYWdlciwgcHJvbXB0Rm9yUGFja2FnZU1hbmFnZXIgfSBmcm9tIFwiQGRlY29oZXJlL25leHVzL2ludGVyb3BcIjtcbmltcG9ydCB7XG5cdEFQUF9QQUNLQUdFX0pTT04sXG5cdENPTkZJR19ERVZfWUFNTCxcblx0Q09ORklHX1BST0RfWUFNTCxcblx0Q09ORklHX1lBTUwsXG5cdEhFTExPX0NPTlRST0xMRVJfVFMsXG5cdE1BSU5fVFMsXG5cdFJPT1RfUEFDS0FHRV9KU09OLFxuXHRTQU1QTEVfQ09ORklHX1RTLFxuXHRTQU1QTEVfRU5USVRZX1RTLFxuXHRTQU1QTEVfUkVQT1NJVE9SWV9UUyxcblx0U0FNUExFX1NFUlZJQ0VfVFMsXG5cdFRTQ09ORklHLFxuXHRXRUJfQVBJX0FQUF9QQUNLQUdFX0pTT04sXG5cdFdFQl9BUElfTUFJTl9UUyxcblx0V0VCX0FQSV9ST09UX1BBQ0tBR0VfSlNPTixcblx0V0VCX0FQSV9UU0NPTkZJRyxcbn0gZnJvbSBcIi4vdGVtcGxhdGVzLmpzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2NhZmZvbGRPcHRpb25zIHtcblx0eWVzPzogYm9vbGVhbjtcblx0dGVtcGxhdGU/OiBcImJhc2ljXCIgfCBcIndlYmFwaVwiO1xuXHRkYXRhYmFzZT86IFwidHlwZW9ybVwiO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2NhZmZvbGQodGFyZ2V0RGlyOiBzdHJpbmcsIG9wdHM6IFNjYWZmb2xkT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuXHRjb25zdCBuYW1lID0gYmFzZW5hbWUodGFyZ2V0RGlyKTtcblxuXHRpZiAoZXhpc3RzU3luYyh0YXJnZXREaXIpICYmIHJlYWRkaXJTeW5jKHRhcmdldERpcikubGVuZ3RoID4gMCAmJiAhb3B0cy55ZXMpIHtcblx0XHRjb25zdCBybCA9IGNyZWF0ZUludGVyZmFjZSh7XG5cdFx0XHRpbnB1dDogcHJvY2Vzcy5zdGRpbixcblx0XHRcdG91dHB1dDogcHJvY2Vzcy5zdGRvdXQsXG5cdFx0fSk7XG5cdFx0Y29uc3QgYW5zd2VyID0gYXdhaXQgcmwucXVlc3Rpb24oYERpcmVjdG9yeSBcIiR7bmFtZX1cIiBpcyBub3QgZW1wdHkuIENvbnRpbnVlPyBbeS9OXSBgKTtcblx0XHRybC5jbG9zZSgpO1xuXHRcdGlmICghYW5zd2VyLnRyaW0oKS50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoXCJ5XCIpKSB7XG5cdFx0XHRjb25zb2xlLmxvZyhcIkFib3J0ZWQuXCIpO1xuXHRcdFx0cHJvY2Vzcy5leGl0KDApO1xuXHRcdH1cblx0fVxuXG5cdGlmIChvcHRzLnRlbXBsYXRlID09PSBcIndlYmFwaVwiKSB7XG5cdFx0Y29uc3QgZGJPcHRzID0gb3B0cy5kYXRhYmFzZSA/IHsgZGF0YWJhc2U6IG9wdHMuZGF0YWJhc2UgfSA6IHVuZGVmaW5lZDtcblx0XHRhd2FpdCBta2Rpcihqb2luKHRhcmdldERpciwgXCJwcm9qZWN0c1wiLCBcImFwaVwiLCBcInNyY1wiLCBcImNvbnRyb2xsZXJzXCIpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblx0XHRhd2FpdCBta2Rpcihqb2luKHRhcmdldERpciwgXCJjb25maWdcIiksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuXHRcdGNvbnN0IHdyaXRlcyA9IFtcblx0XHRcdHdyaXRlRmlsZShqb2luKHRhcmdldERpciwgXCJwYWNrYWdlLmpzb25cIiksIFdFQl9BUElfUk9PVF9QQUNLQUdFX0pTT04obmFtZSwgZGJPcHRzKSksXG5cdFx0XHR3cml0ZUZpbGUoam9pbih0YXJnZXREaXIsIFwidHNjb25maWcuanNvblwiKSwgV0VCX0FQSV9UU0NPTkZJRyksXG5cdFx0XHR3cml0ZUZpbGUoXG5cdFx0XHRcdGpvaW4odGFyZ2V0RGlyLCBcInByb2plY3RzXCIsIFwiYXBpXCIsIFwicGFja2FnZS5qc29uXCIpLFxuXHRcdFx0XHRXRUJfQVBJX0FQUF9QQUNLQUdFX0pTT04obmFtZSksXG5cdFx0XHQpLFxuXHRcdFx0d3JpdGVGaWxlKFxuXHRcdFx0XHRqb2luKHRhcmdldERpciwgXCJwcm9qZWN0c1wiLCBcImFwaVwiLCBcInNyY1wiLCBcIm1haW4udHNcIiksXG5cdFx0XHRcdFdFQl9BUElfTUFJTl9UUyhuYW1lLCBkYk9wdHMpLFxuXHRcdFx0KSxcblx0XHRcdHdyaXRlRmlsZShcblx0XHRcdFx0am9pbih0YXJnZXREaXIsIFwicHJvamVjdHNcIiwgXCJhcGlcIiwgXCJzcmNcIiwgXCJjb250cm9sbGVyc1wiLCBcImhlbGxvLmNvbnRyb2xsZXIudHNcIiksXG5cdFx0XHRcdEhFTExPX0NPTlRST0xMRVJfVFMsXG5cdFx0XHQpLFxuXHRcdFx0d3JpdGVGaWxlKFxuXHRcdFx0XHRqb2luKHRhcmdldERpciwgXCJwcm9qZWN0c1wiLCBcImFwaVwiLCBcInNyY1wiLCBcInNhbXBsZS5jb25maWcudHNcIiksXG5cdFx0XHRcdFNBTVBMRV9DT05GSUdfVFMsXG5cdFx0XHQpLFxuXHRcdFx0d3JpdGVGaWxlKFxuXHRcdFx0XHRqb2luKHRhcmdldERpciwgXCJwcm9qZWN0c1wiLCBcImFwaVwiLCBcInNyY1wiLCBcInNhbXBsZS5zZXJ2aWNlLnRzXCIpLFxuXHRcdFx0XHRTQU1QTEVfU0VSVklDRV9UUyxcblx0XHRcdCksXG5cdFx0XHR3cml0ZUZpbGUoam9pbih0YXJnZXREaXIsIFwiY29uZmlnXCIsIFwiY29uZmlnLnlhbWxcIiksIENPTkZJR19ZQU1MKG5hbWUsIGRiT3B0cykpLFxuXHRcdFx0d3JpdGVGaWxlKGpvaW4odGFyZ2V0RGlyLCBcImNvbmZpZ1wiLCBcImNvbmZpZy5kZXYueWFtbFwiKSwgQ09ORklHX0RFVl9ZQU1MKSxcblx0XHRdO1xuXHRcdGlmIChvcHRzLmRhdGFiYXNlID09PSBcInR5cGVvcm1cIikge1xuXHRcdFx0YXdhaXQgbWtkaXIoam9pbih0YXJnZXREaXIsIFwicHJvamVjdHNcIiwgXCJhcGlcIiwgXCJzcmNcIiwgXCJlbnRpdGllc1wiKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cdFx0XHRhd2FpdCBta2Rpcihqb2luKHRhcmdldERpciwgXCJwcm9qZWN0c1wiLCBcImFwaVwiLCBcInNyY1wiLCBcInJlcG9zaXRvcmllc1wiKSwge1xuXHRcdFx0XHRyZWN1cnNpdmU6IHRydWUsXG5cdFx0XHR9KTtcblx0XHRcdHdyaXRlcy5wdXNoKFxuXHRcdFx0XHR3cml0ZUZpbGUoXG5cdFx0XHRcdFx0am9pbih0YXJnZXREaXIsIFwicHJvamVjdHNcIiwgXCJhcGlcIiwgXCJzcmNcIiwgXCJlbnRpdGllc1wiLCBcInNhbXBsZS5lbnRpdHkudHNcIiksXG5cdFx0XHRcdFx0U0FNUExFX0VOVElUWV9UUyxcblx0XHRcdFx0KSxcblx0XHRcdFx0d3JpdGVGaWxlKFxuXHRcdFx0XHRcdGpvaW4odGFyZ2V0RGlyLCBcInByb2plY3RzXCIsIFwiYXBpXCIsIFwic3JjXCIsIFwicmVwb3NpdG9yaWVzXCIsIFwic2FtcGxlLnJlcG9zaXRvcnkudHNcIiksXG5cdFx0XHRcdFx0U0FNUExFX1JFUE9TSVRPUllfVFMsXG5cdFx0XHRcdCksXG5cdFx0XHRcdHdyaXRlRmlsZShqb2luKHRhcmdldERpciwgXCJjb25maWdcIiwgXCJjb25maWcucHJvZC55YW1sXCIpLCBDT05GSUdfUFJPRF9ZQU1MKSxcblx0XHRcdCk7XG5cdFx0fVxuXHRcdGF3YWl0IFByb21pc2UuYWxsKHdyaXRlcyk7XG5cdH0gZWxzZSB7XG5cdFx0YXdhaXQgbWtkaXIoam9pbih0YXJnZXREaXIsIFwicHJvamVjdHNcIiwgXCJhcHBcIiwgXCJzcmNcIiksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuXHRcdGF3YWl0IFByb21pc2UuYWxsKFtcblx0XHRcdHdyaXRlRmlsZShqb2luKHRhcmdldERpciwgXCJwYWNrYWdlLmpzb25cIiksIFJPT1RfUEFDS0FHRV9KU09OKG5hbWUpKSxcblx0XHRcdHdyaXRlRmlsZShqb2luKHRhcmdldERpciwgXCJ0c2NvbmZpZy5qc29uXCIpLCBUU0NPTkZJRyksXG5cdFx0XHR3cml0ZUZpbGUoam9pbih0YXJnZXREaXIsIFwicHJvamVjdHNcIiwgXCJhcHBcIiwgXCJwYWNrYWdlLmpzb25cIiksIEFQUF9QQUNLQUdFX0pTT04obmFtZSkpLFxuXHRcdFx0d3JpdGVGaWxlKGpvaW4odGFyZ2V0RGlyLCBcInByb2plY3RzXCIsIFwiYXBwXCIsIFwic3JjXCIsIFwibWFpbi50c1wiKSwgTUFJTl9UUyksXG5cdFx0XSk7XG5cdH1cblxuXHRjb25zb2xlLmxvZyhgXFxuU2NhZmZvbGRlZCAke25hbWV9LiBJbnN0YWxsaW5nIGRlcGVuZGVuY2llcy4uLlxcbmApO1xuXHRsZXQgcG0gPSBkZXRlY3RQYWNrYWdlTWFuYWdlcih0YXJnZXREaXIpO1xuXHRpZiAocG0gPT0gbnVsbCkge1xuXHRcdHBtID0gYXdhaXQgcHJvbXB0Rm9yUGFja2FnZU1hbmFnZXIoKTtcblx0fVxuXHRhd2FpdCBwbS5pbnN0YWxsKHsgY3dkOiB0YXJnZXREaXIgfSk7XG5cblx0Y29uc29sZS5sb2coYFxcbkRvbmUhIE5leHQgc3RlcHM6XFxuYCk7XG5cdGlmIChiYXNlbmFtZSh0YXJnZXREaXIpICE9PSB0YXJnZXREaXIpIHtcblx0XHRjb25zb2xlLmxvZyhgICBjZCAke25hbWV9YCk7XG5cdH1cblx0Y29uc29sZS5sb2coXCIgIHBucG0gYnVpbGQgICAgICMgZm9yZ2UgYnVpbGRcIik7XG5cdGNvbnNvbGUubG9nKFwiICBwbnBtIGRldiAgICAgICAjIGZsdXggc2VydmVcXG5cIik7XG59XG4iXSwibmFtZXMiOlsic2NhZmZvbGQiLCJ0YXJnZXREaXIiLCJvcHRzIiwibmFtZSIsImJhc2VuYW1lIiwiZXhpc3RzU3luYyIsInJlYWRkaXJTeW5jIiwibGVuZ3RoIiwieWVzIiwicmwiLCJjcmVhdGVJbnRlcmZhY2UiLCJpbnB1dCIsInByb2Nlc3MiLCJzdGRpbiIsIm91dHB1dCIsInN0ZG91dCIsImFuc3dlciIsInF1ZXN0aW9uIiwiY2xvc2UiLCJ0cmltIiwidG9Mb3dlckNhc2UiLCJzdGFydHNXaXRoIiwiY29uc29sZSIsImxvZyIsImV4aXQiLCJ0ZW1wbGF0ZSIsImRiT3B0cyIsImRhdGFiYXNlIiwidW5kZWZpbmVkIiwibWtkaXIiLCJqb2luIiwicmVjdXJzaXZlIiwid3JpdGVzIiwid3JpdGVGaWxlIiwiV0VCX0FQSV9ST09UX1BBQ0tBR0VfSlNPTiIsIldFQl9BUElfVFNDT05GSUciLCJXRUJfQVBJX0FQUF9QQUNLQUdFX0pTT04iLCJXRUJfQVBJX01BSU5fVFMiLCJIRUxMT19DT05UUk9MTEVSX1RTIiwiU0FNUExFX0NPTkZJR19UUyIsIlNBTVBMRV9TRVJWSUNFX1RTIiwiQ09ORklHX1lBTUwiLCJDT05GSUdfREVWX1lBTUwiLCJwdXNoIiwiU0FNUExFX0VOVElUWV9UUyIsIlNBTVBMRV9SRVBPU0lUT1JZX1RTIiwiQ09ORklHX1BST0RfWUFNTCIsIlByb21pc2UiLCJhbGwiLCJST09UX1BBQ0tBR0VfSlNPTiIsIlRTQ09ORklHIiwiQVBQX1BBQ0tBR0VfSlNPTiIsIk1BSU5fVFMiLCJwbSIsImRldGVjdFBhY2thZ2VNYW5hZ2VyIiwicHJvbXB0Rm9yUGFja2FnZU1hbmFnZXIiLCJpbnN0YWxsIiwiY3dkIl0sIm1hcHBpbmdzIjoiOzs7OytCQThCc0JBOzs7ZUFBQUE7Ozt3QkE5QmtCOzBCQUNQOzBCQUNGOzJCQUNDO3lCQUM4QjsyQkFrQnZEO0FBUUEsZUFBZUEsU0FBU0MsU0FBaUIsRUFBRUMsSUFBcUI7SUFD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
|