sonamu 0.10.13 → 0.11.1
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/dist/ai/agents/agent.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/error.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
- package/dist/api/base-frame.d.ts.map +1 -1
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +3 -2
- package/dist/api/validator.d.ts.map +1 -1
- package/dist/auth/audit-log/events.d.ts.map +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +3 -3
- package/dist/auth/knex-adapter.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/admin.d.ts +4 -4
- package/dist/auth/plugins/wrappers/admin.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/anonymous.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/api-key.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/jwt.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/organization.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/passkey.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/phone-number.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/sso.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/two-factor.d.ts.map +1 -1
- package/dist/auth/plugins/wrappers/username.d.ts.map +1 -1
- package/dist/bin/build-config.d.ts +10 -0
- package/dist/bin/build-config.d.ts.map +1 -1
- package/dist/bin/build-config.js +130 -6
- package/dist/bin/fixture.d.ts +7 -4
- package/dist/bin/fixture.d.ts.map +1 -1
- package/dist/bin/fixture.js +161 -13
- package/dist/bin/test-command.d.ts +7 -0
- package/dist/bin/test-command.d.ts.map +1 -1
- package/dist/bin/test-command.js +18 -4
- package/dist/bin/typecheck-web.d.ts +2 -0
- package/dist/bin/typecheck-web.d.ts.map +1 -0
- package/dist/bin/typecheck-web.js +36 -0
- package/dist/cache/decorator.d.ts.map +1 -1
- package/dist/cache/drivers.d.ts.map +1 -1
- package/dist/cache-control/cache-control.d.ts.map +1 -1
- package/dist/compress/compress.d.ts.map +1 -1
- package/dist/cone/cone-generator.js +1 -1
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.types.d.ts +0 -1
- package/dist/database/base-model.types.d.ts.map +1 -1
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/puri-subset.types.d.ts +0 -1
- package/dist/database/puri-subset.types.d.ts.map +1 -1
- package/dist/database/puri-wrapper.d.ts +0 -1
- package/dist/database/puri-wrapper.d.ts.map +1 -1
- package/dist/database/puri.d.ts +0 -1
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.types.d.ts +0 -1
- package/dist/database/puri.types.d.ts.map +1 -1
- package/dist/database/transaction-context.d.ts.map +1 -1
- package/dist/database/upsert-builder.d.ts.map +1 -1
- package/dist/dict/en.d.ts +58 -58
- package/dist/dict/en.d.ts.map +1 -1
- package/dist/dict/ko.d.ts +58 -58
- package/dist/dict/ko.d.ts.map +1 -1
- package/dist/dict/rc-keys.d.ts.map +1 -1
- package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
- package/dist/dict/sonamu-dictionary.js +2 -2
- package/dist/dict/utils.d.ts.map +1 -1
- package/dist/entity/entity-manager.d.ts +115 -113
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +25 -19
- package/dist/entity/entity-template-cone.d.ts +4 -4
- package/dist/entity/entity.d.ts +6 -1
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +8 -3
- package/dist/env.d.ts.map +1 -1
- package/dist/exceptions/so-exceptions.d.ts.map +1 -1
- package/dist/filter/types.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/logger/configure.d.ts +10 -1
- package/dist/logger/configure.d.ts.map +1 -1
- package/dist/logger/configure.js +30 -5
- package/dist/migration/migration-set.d.ts.map +1 -1
- package/dist/migration/migration-set.js +17 -6
- package/dist/migration/migrator.d.ts +12 -1
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +77 -30
- package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
- package/dist/migration/slack-confirm.d.ts.map +1 -1
- package/dist/naite/messaging-types.d.ts +0 -1
- package/dist/naite/messaging-types.d.ts.map +1 -1
- package/dist/naite/naite-reporter.d.ts +0 -1
- package/dist/naite/naite-reporter.d.ts.map +1 -1
- package/dist/naite/naite.d.ts.map +1 -1
- package/dist/storage/base-file.d.ts.map +1 -1
- package/dist/storage/buffered-file.d.ts.map +1 -1
- package/dist/storage/drivers.d.ts.map +1 -1
- package/dist/storage/s3-driver.d.ts.map +1 -1
- package/dist/storage/storage-manager.d.ts.map +1 -1
- package/dist/storage/uploaded-file.d.ts.map +1 -1
- package/dist/stream/ws-audience-resolver.d.ts.map +1 -1
- package/dist/stream/ws-audience.d.ts.map +1 -1
- package/dist/stream/ws-cluster-bus.d.ts.map +1 -1
- package/dist/stream/ws-delivery.d.ts.map +1 -1
- package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
- package/dist/stream/ws-presence-store.d.ts.map +1 -1
- package/dist/stream/ws-registry.d.ts.map +1 -1
- package/dist/stream/ws-telemetry-memory.d.ts.map +1 -1
- package/dist/stream/ws-telemetry.d.ts.map +1 -1
- package/dist/stream/ws.d.ts.map +1 -1
- package/dist/syncer/api-parser.js +2 -2
- package/dist/syncer/file-patterns.d.ts +17 -17
- package/dist/syncer/filesystem-dependencies.js +1 -1
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/tasks/step-wrapper.d.ts.map +1 -1
- package/dist/tasks/workflow-manager.d.ts.map +1 -1
- package/dist/template/implementations/entity.template.d.ts +2 -2
- package/dist/template/implementations/entity.template.d.ts.map +1 -1
- package/dist/template/implementations/entry-server.template.d.ts +2 -2
- package/dist/template/implementations/entry-server.template.d.ts.map +1 -1
- package/dist/template/implementations/generated.template.d.ts +2 -2
- package/dist/template/implementations/generated.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_http.template.d.ts +2 -2
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_sso.template.d.ts +2 -2
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
- package/dist/template/implementations/http_validators.template.d.ts +2 -2
- package/dist/template/implementations/http_validators.template.d.ts.map +1 -1
- package/dist/template/implementations/init_types.template.d.ts +2 -2
- package/dist/template/implementations/init_types.template.d.ts.map +1 -1
- package/dist/template/implementations/model.template.d.ts +2 -2
- package/dist/template/implementations/model.template.d.ts.map +1 -1
- package/dist/template/implementations/model_test.template.d.ts +2 -2
- package/dist/template/implementations/model_test.template.d.ts.map +1 -1
- package/dist/template/implementations/queries.template.d.ts +2 -2
- package/dist/template/implementations/queries.template.d.ts.map +1 -1
- package/dist/template/implementations/sd.template.d.ts +2 -2
- package/dist/template/implementations/sd.template.d.ts.map +1 -1
- package/dist/template/implementations/sd.template.js +1 -1
- package/dist/template/implementations/services.template.d.ts +2 -2
- package/dist/template/implementations/services.template.d.ts.map +1 -1
- package/dist/template/implementations/view_form.template.d.ts +3 -3
- package/dist/template/implementations/view_form.template.d.ts.map +1 -1
- package/dist/template/implementations/view_id_all_select.template.d.ts +2 -2
- package/dist/template/implementations/view_id_all_select.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list.template.d.ts +2 -2
- package/dist/template/implementations/view_list.template.d.ts.map +1 -1
- package/dist/template/implementations/view_search_input.template.d.ts +2 -2
- package/dist/template/implementations/view_search_input.template.d.ts.map +1 -1
- package/dist/template/template-manager.d.ts.map +1 -1
- package/dist/template/template.d.ts.map +1 -1
- package/dist/template/zod-converter.d.ts.map +1 -1
- package/dist/testing/_relation-graph.d.ts.map +1 -1
- package/dist/testing/data-explorer.d.ts +2 -2
- package/dist/testing/data-explorer.d.ts.map +1 -1
- package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
- package/dist/testing/faker-mappings.d.ts.map +1 -1
- package/dist/testing/fixture-generator.d.ts.map +1 -1
- package/dist/testing/fixture-generator.js +1 -1
- package/dist/testing/fixture-loader.d.ts.map +1 -1
- package/dist/testing/fixture-manager.d.ts +4 -0
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +99 -25
- package/dist/testing/naite-vitest-reporter.d.ts.map +1 -1
- package/dist/testing/parallel-db-manager.d.ts.map +1 -1
- package/dist/tooling/__tests__/helpers/sonamu-test-root.d.ts +10 -0
- package/dist/tooling/__tests__/helpers/sonamu-test-root.d.ts.map +1 -0
- package/dist/tooling/__tests__/helpers/sonamu-test-root.js +42 -0
- package/dist/tooling/cdd-service.d.ts +87 -0
- package/dist/tooling/cdd-service.d.ts.map +1 -0
- package/dist/tooling/cdd-service.js +215 -0
- package/dist/tooling/cli-tooling.d.ts +11 -0
- package/dist/tooling/cli-tooling.d.ts.map +1 -0
- package/dist/tooling/cli-tooling.js +901 -0
- package/dist/tooling/fixture-service.d.ts +29 -0
- package/dist/tooling/fixture-service.d.ts.map +1 -0
- package/dist/tooling/fixture-service.js +53 -0
- package/dist/tooling/index.d.ts +2 -0
- package/dist/tooling/index.d.ts.map +1 -0
- package/dist/tooling/index.js +2 -0
- package/dist/tooling/test-run-client.d.ts +27 -0
- package/dist/tooling/test-run-client.d.ts.map +1 -0
- package/dist/tooling/test-run-client.js +120 -0
- package/dist/tsdown.api.config.js +48 -0
- package/dist/types/types.d.ts +527 -527
- package/dist/types/types.d.ts.map +1 -1
- package/dist/ui/ai-client.d.ts.map +1 -1
- package/dist/utils/formatter.d.ts +6 -0
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +42 -11
- package/dist/utils/model.d.ts +1 -1
- package/dist/vector/chunking.d.ts.map +1 -1
- package/dist/vector/embedding.d.ts.map +1 -1
- package/package.json +13 -12
- package/src/api/sonamu.ts +2 -1
- package/src/auth/index.ts +1 -1
- package/src/bin/__tests__/zod-compiler-build.test.ts +67 -0
- package/src/bin/build-config.ts +151 -5
- package/src/bin/fixture.ts +204 -21
- package/src/bin/test-command.ts +27 -4
- package/src/bin/typecheck-web.ts +56 -0
- package/src/dict/sonamu-dictionary.ts +1 -1
- package/src/entity/__tests__/entity-manager-autoload.contract.test.ts +55 -0
- package/src/entity/__tests__/entity-manager-explicit-root-registration.contract.test.ts +107 -0
- package/src/entity/entity-manager.ts +31 -19
- package/src/entity/entity.ts +7 -2
- package/src/logger/__tests__/configure.test.ts +33 -0
- package/src/logger/configure.ts +45 -3
- package/src/migration/__tests__/migrator.test.ts +51 -0
- package/src/migration/migration-set.ts +22 -5
- package/src/migration/migrator.ts +103 -34
- package/src/syncer/api-parser.ts +1 -1
- package/src/testing/fixture-manager.ts +124 -32
- package/src/tooling/__tests__/cdd-rule-bootstrap.contract.test.ts +118 -0
- package/src/tooling/__tests__/cli-tooling-auth.contract.test.ts +72 -0
- package/src/tooling/__tests__/cli-tooling-cone-locale.contract.test.ts +150 -0
- package/src/tooling/__tests__/cli-tooling-entity-patch.contract.test.ts +131 -0
- package/src/tooling/__tests__/cli-tooling-fixture-transfer.contract.test.ts +255 -0
- package/src/tooling/__tests__/cli-tooling-i18n-update.contract.test.ts +104 -0
- package/src/tooling/__tests__/cli-tooling-scaffold.contract.test.ts +86 -0
- package/src/tooling/__tests__/cli-tooling-stub-practice.contract.test.ts +147 -0
- package/src/tooling/__tests__/default-cdd-adapter.contract.test.ts +73 -0
- package/src/tooling/__tests__/helpers/sonamu-test-root.ts +42 -0
- package/src/tooling/__tests__/test-run-client-config.contract.test.ts +154 -0
- package/src/tooling/cdd-service.ts +256 -0
- package/src/tooling/cli-tooling.ts +937 -0
- package/src/tooling/fixture-service.ts +72 -0
- package/src/tooling/index.ts +1 -0
- package/src/tooling/test-run-client.ts +196 -0
- package/src/utils/__tests__/formatter-bin.test.ts +99 -0
- package/src/utils/formatter.ts +74 -10
- package/tsdown.api.config.ts +8 -10
- package/bin/cli.js +0 -75
- package/dist/bin/cli.d.ts +0 -2
- package/dist/bin/cli.d.ts.map +0 -1
- package/dist/bin/cli.js +0 -956
- package/src/bin/cli.ts +0 -1166
|
@@ -0,0 +1,901 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/tooling/cli-tooling.ts
|
|
3
|
+
const jsonValueSchema = z.json();
|
|
4
|
+
const MIGRATION_TARGETS = /* @__PURE__ */ new Set([
|
|
5
|
+
"development",
|
|
6
|
+
"staging",
|
|
7
|
+
"production",
|
|
8
|
+
"fixture",
|
|
9
|
+
"test"
|
|
10
|
+
]);
|
|
11
|
+
function assertMigrationTarget(target) {
|
|
12
|
+
if (MIGRATION_TARGETS.has(target)) return;
|
|
13
|
+
throw Object.assign(/* @__PURE__ */ new Error(`Unsupported migration target: ${target}`), {
|
|
14
|
+
code: "INVALID_MIGRATION_TARGET",
|
|
15
|
+
exitCode: 2
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function assertShadowMigrationTarget(target) {
|
|
19
|
+
if (target === "fixture" || target === "test") return;
|
|
20
|
+
throw Object.assign(/* @__PURE__ */ new Error(`Invalid shadow migration target: ${target}`), {
|
|
21
|
+
code: "INVALID_SHADOW_MIGRATION_TARGET",
|
|
22
|
+
target,
|
|
23
|
+
exitCode: 2
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
async function migrationPlan(target, migrations, action = "apply") {
|
|
27
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(JSON.stringify({
|
|
28
|
+
action,
|
|
29
|
+
target,
|
|
30
|
+
migrations
|
|
31
|
+
})));
|
|
32
|
+
return {
|
|
33
|
+
kind: "migration-plan",
|
|
34
|
+
action,
|
|
35
|
+
target,
|
|
36
|
+
migrations,
|
|
37
|
+
fingerprint: Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const REQUIRED_METHODS = {
|
|
41
|
+
core: ["sync"],
|
|
42
|
+
entity: [
|
|
43
|
+
"list",
|
|
44
|
+
"show",
|
|
45
|
+
"search",
|
|
46
|
+
"applyPatch",
|
|
47
|
+
"create",
|
|
48
|
+
"cones"
|
|
49
|
+
],
|
|
50
|
+
scaffold: [
|
|
51
|
+
"model",
|
|
52
|
+
"model_test",
|
|
53
|
+
"view_list",
|
|
54
|
+
"view_form",
|
|
55
|
+
"status",
|
|
56
|
+
"preview",
|
|
57
|
+
"batch"
|
|
58
|
+
],
|
|
59
|
+
migration: [
|
|
60
|
+
"run",
|
|
61
|
+
"generate",
|
|
62
|
+
"status",
|
|
63
|
+
"connections",
|
|
64
|
+
"code",
|
|
65
|
+
"preview",
|
|
66
|
+
"shadow",
|
|
67
|
+
"rollback"
|
|
68
|
+
],
|
|
69
|
+
fixture: [
|
|
70
|
+
"init",
|
|
71
|
+
"import",
|
|
72
|
+
"sync",
|
|
73
|
+
"gen",
|
|
74
|
+
"fetch",
|
|
75
|
+
"explore"
|
|
76
|
+
],
|
|
77
|
+
build: [
|
|
78
|
+
"all",
|
|
79
|
+
"api",
|
|
80
|
+
"web"
|
|
81
|
+
],
|
|
82
|
+
test: ["run", "status"],
|
|
83
|
+
auth: ["generate", "addCompanions"],
|
|
84
|
+
i18n: [
|
|
85
|
+
"list",
|
|
86
|
+
"check",
|
|
87
|
+
"import",
|
|
88
|
+
"export",
|
|
89
|
+
"create",
|
|
90
|
+
"update",
|
|
91
|
+
"remove"
|
|
92
|
+
],
|
|
93
|
+
task: [
|
|
94
|
+
"definitions",
|
|
95
|
+
"runs",
|
|
96
|
+
"show",
|
|
97
|
+
"steps",
|
|
98
|
+
"watch",
|
|
99
|
+
"pause",
|
|
100
|
+
"resume",
|
|
101
|
+
"cancel"
|
|
102
|
+
],
|
|
103
|
+
cdd: [
|
|
104
|
+
"tree",
|
|
105
|
+
"read",
|
|
106
|
+
"rules",
|
|
107
|
+
"showRule",
|
|
108
|
+
"addRule",
|
|
109
|
+
"addAcceptanceCriterion"
|
|
110
|
+
],
|
|
111
|
+
stub: ["practice"]
|
|
112
|
+
};
|
|
113
|
+
let initialization;
|
|
114
|
+
async function ensureSonamu() {
|
|
115
|
+
const { Sonamu } = await import("../api/sonamu.js");
|
|
116
|
+
if (Sonamu.isInitialized) return;
|
|
117
|
+
initialization ??= Sonamu.init(true, false);
|
|
118
|
+
await initialization;
|
|
119
|
+
}
|
|
120
|
+
async function syncOperation(input) {
|
|
121
|
+
await ensureSonamu();
|
|
122
|
+
const { Sonamu } = await import("../api/sonamu.js");
|
|
123
|
+
return input.force === true ? Sonamu.syncer.forceSync() : Sonamu.syncer.sync();
|
|
124
|
+
}
|
|
125
|
+
function text(input, key) {
|
|
126
|
+
const value = z.string().safeParse(input[key]);
|
|
127
|
+
return value.success ? value.data : void 0;
|
|
128
|
+
}
|
|
129
|
+
function strings(input, key) {
|
|
130
|
+
const value = z.array(z.string()).safeParse(input[key]);
|
|
131
|
+
return value.success ? value.data : [];
|
|
132
|
+
}
|
|
133
|
+
function requiredText(input, key) {
|
|
134
|
+
const value = text(input, key);
|
|
135
|
+
if (value !== void 0 && value.length > 0) return value;
|
|
136
|
+
throw Object.assign(/* @__PURE__ */ new Error(`Missing ${key}.`), {
|
|
137
|
+
code: "MISSING_ARGUMENT",
|
|
138
|
+
exitCode: 2
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 생략한 값은 `undefined`로 통과시키되, 값이 있는데 문자열이 아니면 인자 오류로 거절합니다.
|
|
143
|
+
*
|
|
144
|
+
* `text()`처럼 조용히 무시하면 잘못된 타입의 입력이 기본값으로 둔갑합니다.
|
|
145
|
+
*/
|
|
146
|
+
function optionalText(input, key) {
|
|
147
|
+
const value = input[key];
|
|
148
|
+
if (value === void 0 || value === null) return void 0;
|
|
149
|
+
const parsed = z.string().safeParse(value);
|
|
150
|
+
if (parsed.success) return parsed.data;
|
|
151
|
+
throw Object.assign(/* @__PURE__ */ new Error(`Invalid ${key}.`), {
|
|
152
|
+
code: "INVALID_ARGUMENT",
|
|
153
|
+
exitCode: 2
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function parseJson(contents, code, schema) {
|
|
157
|
+
try {
|
|
158
|
+
return schema.parse(JSON.parse(contents));
|
|
159
|
+
} catch (cause) {
|
|
160
|
+
throw Object.assign(/* @__PURE__ */ new Error("Invalid JSON input."), {
|
|
161
|
+
code,
|
|
162
|
+
exitCode: 2,
|
|
163
|
+
cause
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function mutationRequested(input) {
|
|
168
|
+
return input.execute === true || input.dryRun === false;
|
|
169
|
+
}
|
|
170
|
+
function explicitlyDryRun(input) {
|
|
171
|
+
return input.dryRun === true || input.execute === false;
|
|
172
|
+
}
|
|
173
|
+
const entityPatchSchema = z.object({
|
|
174
|
+
entityId: z.string().min(1),
|
|
175
|
+
operations: z.array(z.object({
|
|
176
|
+
op: z.literal("add"),
|
|
177
|
+
path: z.literal("/props/-"),
|
|
178
|
+
value: z.object({
|
|
179
|
+
name: z.string().min(1),
|
|
180
|
+
type: z.string().min(1)
|
|
181
|
+
}).catchall(jsonValueSchema)
|
|
182
|
+
}))
|
|
183
|
+
});
|
|
184
|
+
const i18nEntriesSchema = z.array(z.object({
|
|
185
|
+
key: z.string(),
|
|
186
|
+
values: z.record(z.string(), z.string())
|
|
187
|
+
}));
|
|
188
|
+
const dictionaryValuesSchema = z.record(z.string(), z.string());
|
|
189
|
+
const dictionarySourceSchema = z.enum([
|
|
190
|
+
"entity",
|
|
191
|
+
"project",
|
|
192
|
+
"sonamu"
|
|
193
|
+
]);
|
|
194
|
+
const coneLocaleSchema = z.enum([
|
|
195
|
+
"ko",
|
|
196
|
+
"en",
|
|
197
|
+
"ja"
|
|
198
|
+
]);
|
|
199
|
+
/**
|
|
200
|
+
* cone 생성에 사용할 locale을 결정합니다.
|
|
201
|
+
*
|
|
202
|
+
* 명시한 locale이 최우선이고, 없으면 프로젝트 i18n 기본 locale, 그마저 없으면 "ko"를 사용합니다.
|
|
203
|
+
*/
|
|
204
|
+
async function resolveConeLocale(input) {
|
|
205
|
+
const explicit = coneLocaleSchema.safeParse(input.locale);
|
|
206
|
+
if (explicit.success) return explicit.data;
|
|
207
|
+
const { Sonamu } = await import("../api/sonamu.js");
|
|
208
|
+
let configuredLocale;
|
|
209
|
+
try {
|
|
210
|
+
configuredLocale = Sonamu.config.i18n?.defaultLocale;
|
|
211
|
+
} catch {}
|
|
212
|
+
const configured = coneLocaleSchema.safeParse(configuredLocale);
|
|
213
|
+
return configured.success ? configured.data : "ko";
|
|
214
|
+
}
|
|
215
|
+
async function entityOperation(method, input) {
|
|
216
|
+
await ensureSonamu();
|
|
217
|
+
const { EntityManager } = await import("../entity/entity-manager.js");
|
|
218
|
+
const entities = EntityManager.getAllEntities();
|
|
219
|
+
if (method === "list") return entities.map((entity) => entity.toJson());
|
|
220
|
+
if (method === "show") {
|
|
221
|
+
const entityId = requiredText(input, "entityId");
|
|
222
|
+
if (!EntityManager.exists(entityId)) throw Object.assign(/* @__PURE__ */ new Error(`Entity not found: ${entityId}`), { code: "ENTITY_NOT_FOUND" });
|
|
223
|
+
return EntityManager.get(entityId).toJson();
|
|
224
|
+
}
|
|
225
|
+
if (method === "search") {
|
|
226
|
+
const query = requiredText(input, "query").toLocaleLowerCase();
|
|
227
|
+
return entities.map((entity) => entity.toJson()).filter((entity) => JSON.stringify(entity).toLocaleLowerCase().includes(query));
|
|
228
|
+
}
|
|
229
|
+
if (method === "create") {
|
|
230
|
+
const entityId = requiredText(input, "name");
|
|
231
|
+
const { Sonamu } = await import("../api/sonamu.js");
|
|
232
|
+
await Sonamu.syncer.createEntity({
|
|
233
|
+
entityId,
|
|
234
|
+
title: entityId
|
|
235
|
+
});
|
|
236
|
+
if (input.noCones === true) return {
|
|
237
|
+
entityId,
|
|
238
|
+
cones: "skipped"
|
|
239
|
+
};
|
|
240
|
+
const entity = EntityManager.get(entityId);
|
|
241
|
+
if (input.ai === true) return entity.generateCones({
|
|
242
|
+
preserveExisting: false,
|
|
243
|
+
onlyEmpty: false,
|
|
244
|
+
locale: await resolveConeLocale(input)
|
|
245
|
+
});
|
|
246
|
+
await entity.generateTemplateCones();
|
|
247
|
+
return {
|
|
248
|
+
entityId,
|
|
249
|
+
cones: "template"
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (method === "cones") {
|
|
253
|
+
const entityId = requiredText(input, "entityId");
|
|
254
|
+
const targets = input.all === true || entityId === "all" ? EntityManager.getAllEntities() : EntityManager.exists(entityId) ? [EntityManager.get(entityId)] : [];
|
|
255
|
+
if (targets.length === 0) throw Object.assign(/* @__PURE__ */ new Error(`Entity not found: ${entityId}`), { code: "ENTITY_NOT_FOUND" });
|
|
256
|
+
const regenerate = input.regenerate === true;
|
|
257
|
+
const selectedLocale = await resolveConeLocale(input);
|
|
258
|
+
const settled = await Promise.allSettled(targets.map(async (entity) => ({
|
|
259
|
+
entityId: entity.id,
|
|
260
|
+
...await entity.generateCones({
|
|
261
|
+
preserveExisting: !regenerate,
|
|
262
|
+
onlyEmpty: !regenerate,
|
|
263
|
+
locale: selectedLocale
|
|
264
|
+
})
|
|
265
|
+
})));
|
|
266
|
+
const results = [];
|
|
267
|
+
const failures = [];
|
|
268
|
+
for (const [index, outcome] of settled.entries()) {
|
|
269
|
+
if (outcome.status === "fulfilled") {
|
|
270
|
+
results.push(outcome.value);
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
failures.push({
|
|
274
|
+
entityId: targets[index].id,
|
|
275
|
+
message: outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason)
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
if (failures.length === 0) return results;
|
|
279
|
+
throw Object.assign(/* @__PURE__ */ new Error(`Cone generation failed for ${failures.length} entity(s).`), {
|
|
280
|
+
code: "CONE_GENERATION_FAILED",
|
|
281
|
+
details: {
|
|
282
|
+
results,
|
|
283
|
+
failures
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
const file = requiredText(input, "file");
|
|
288
|
+
const { readFile } = await import("node:fs/promises");
|
|
289
|
+
const patch = parseJson(file === "-" ? await (async () => {
|
|
290
|
+
const chunks = [];
|
|
291
|
+
for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
|
|
292
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
293
|
+
})() : await readFile(file, "utf8"), "INVALID_ENTITY_PATCH", entityPatchSchema);
|
|
294
|
+
if (!EntityManager.exists(patch.entityId)) throw Object.assign(/* @__PURE__ */ new Error(`Entity not found: ${patch.entityId}`), { code: "ENTITY_NOT_FOUND" });
|
|
295
|
+
const target = EntityManager.get(patch.entityId);
|
|
296
|
+
const before = target.toJson();
|
|
297
|
+
const after = structuredClone(before);
|
|
298
|
+
const nextProps = [...after.props, ...patch.operations.map(({ value }) => structuredClone(value))];
|
|
299
|
+
const { EntityJsonSchema } = await import("../types/types.js");
|
|
300
|
+
const validation = EntityJsonSchema.safeParse({
|
|
301
|
+
...after,
|
|
302
|
+
props: nextProps
|
|
303
|
+
});
|
|
304
|
+
if (!validation.success) throw Object.assign(/* @__PURE__ */ new Error("Invalid entity patch."), {
|
|
305
|
+
code: "INVALID_ENTITY_PATCH",
|
|
306
|
+
exitCode: 2,
|
|
307
|
+
cause: validation.error
|
|
308
|
+
});
|
|
309
|
+
after.props = nextProps;
|
|
310
|
+
if (mutationRequested(input)) {
|
|
311
|
+
target.props = after.props;
|
|
312
|
+
await target.save();
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
changed: patch.operations.length > 0,
|
|
316
|
+
before,
|
|
317
|
+
after
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
async function renderScaffolds(input) {
|
|
321
|
+
await ensureSonamu();
|
|
322
|
+
const { renderTemplate } = await import("../syncer/code-generator.js");
|
|
323
|
+
const entities = strings(input, "entities");
|
|
324
|
+
const templates = strings(input, "templates");
|
|
325
|
+
const rendered = [];
|
|
326
|
+
for (const entityId of entities) for (const template of templates) {
|
|
327
|
+
const templateKey = z.enum([
|
|
328
|
+
"model",
|
|
329
|
+
"model_test",
|
|
330
|
+
"view_list",
|
|
331
|
+
"view_form",
|
|
332
|
+
"view_search_input"
|
|
333
|
+
]).parse(template);
|
|
334
|
+
const files = await renderTemplate(templateKey, { entityId });
|
|
335
|
+
rendered.push({
|
|
336
|
+
entityId,
|
|
337
|
+
template: templateKey,
|
|
338
|
+
files
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
return rendered;
|
|
342
|
+
}
|
|
343
|
+
async function scaffoldOperation(method, input) {
|
|
344
|
+
const directTemplate = z.enum([
|
|
345
|
+
"model",
|
|
346
|
+
"model_test",
|
|
347
|
+
"view_list",
|
|
348
|
+
"view_form"
|
|
349
|
+
]).safeParse(method);
|
|
350
|
+
if (directTemplate.success) {
|
|
351
|
+
await ensureSonamu();
|
|
352
|
+
const { Sonamu } = await import("../api/sonamu.js");
|
|
353
|
+
const entityId = requiredText(input, "entityId");
|
|
354
|
+
return directTemplate.data === "view_list" ? Sonamu.syncer.generateTemplate("view_list", {
|
|
355
|
+
entityId,
|
|
356
|
+
extra: input.extra
|
|
357
|
+
}) : Sonamu.syncer.generateTemplate(directTemplate.data, { entityId });
|
|
358
|
+
}
|
|
359
|
+
const rendered = await renderScaffolds(input);
|
|
360
|
+
const { access } = await import("node:fs/promises");
|
|
361
|
+
const path = await import("node:path");
|
|
362
|
+
const { Sonamu } = await import("../api/sonamu.js");
|
|
363
|
+
const items = await Promise.all(rendered.flatMap(({ entityId, template, files }) => files.map(async (file) => {
|
|
364
|
+
const target = path.default.join(Sonamu.appRootPath, file.path.replace("/:target/", "/web/"));
|
|
365
|
+
let exists = true;
|
|
366
|
+
try {
|
|
367
|
+
await access(target);
|
|
368
|
+
} catch {
|
|
369
|
+
exists = false;
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
entityId,
|
|
373
|
+
template,
|
|
374
|
+
target,
|
|
375
|
+
exists,
|
|
376
|
+
content: file.code
|
|
377
|
+
};
|
|
378
|
+
})));
|
|
379
|
+
if (method === "status") return items.map(({ content: _content, ...item }) => item);
|
|
380
|
+
if (method === "preview" || method === "batch" && explicitlyDryRun(input)) return items;
|
|
381
|
+
const results = [];
|
|
382
|
+
for (const item of items) {
|
|
383
|
+
const { content: _content, ...summary } = item;
|
|
384
|
+
if (item.exists && input.overwrite !== true) {
|
|
385
|
+
results.push({
|
|
386
|
+
...summary,
|
|
387
|
+
status: "skipped"
|
|
388
|
+
});
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
await Sonamu.syncer.generateTemplate(item.template, { entityId: item.entityId }, { overwrite: input.overwrite === true });
|
|
392
|
+
results.push({
|
|
393
|
+
...summary,
|
|
394
|
+
status: "written"
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
return { items: results };
|
|
398
|
+
}
|
|
399
|
+
async function migrationOperation(method, input) {
|
|
400
|
+
let shadowTarget;
|
|
401
|
+
if (method === "shadow") {
|
|
402
|
+
const requestedTarget = requiredText(input, "target");
|
|
403
|
+
assertMigrationTarget(requestedTarget);
|
|
404
|
+
assertShadowMigrationTarget(requestedTarget);
|
|
405
|
+
shadowTarget = requestedTarget;
|
|
406
|
+
}
|
|
407
|
+
await ensureSonamu();
|
|
408
|
+
const { Migrator } = await import("../migration/migrator.js");
|
|
409
|
+
const migrator = new Migrator();
|
|
410
|
+
if (method === "status") return migrator.getStatus();
|
|
411
|
+
if (method === "generate") {
|
|
412
|
+
if (!(await migrator.getStatus()).conns.some((connection) => connection.status === 0)) throw Object.assign(/* @__PURE__ */ new Error("Pending migrations must be applied before generation."), { code: "MIGRATION_NOT_READY" });
|
|
413
|
+
return { count: await migrator.generatePreparedCodes() };
|
|
414
|
+
}
|
|
415
|
+
if (method === "run") {
|
|
416
|
+
if (!mutationRequested(input)) return { dryRun: true };
|
|
417
|
+
const { getSonamuEnvironment } = await import("../env.js");
|
|
418
|
+
const environment = getSonamuEnvironment();
|
|
419
|
+
return migrator.apply(environment === "test" ? ["test", "fixture"] : [environment]);
|
|
420
|
+
}
|
|
421
|
+
if (method === "connections") return migrator.getConnections();
|
|
422
|
+
if (method === "apply") {
|
|
423
|
+
const rawTargets = strings(input, "targets");
|
|
424
|
+
if (rawTargets.length === 0) throw Object.assign(/* @__PURE__ */ new Error("Missing targets."), {
|
|
425
|
+
code: "MISSING_ARGUMENT",
|
|
426
|
+
exitCode: 2
|
|
427
|
+
});
|
|
428
|
+
const targets = rawTargets.map((target) => {
|
|
429
|
+
assertMigrationTarget(target);
|
|
430
|
+
return target;
|
|
431
|
+
});
|
|
432
|
+
if (mutationRequested(input)) return migrator.apply(targets);
|
|
433
|
+
return Promise.all(targets.map(async (target) => {
|
|
434
|
+
return migrationPlan(target, (await migrator.getConnectionStatus(target)).pending);
|
|
435
|
+
}));
|
|
436
|
+
}
|
|
437
|
+
if (method === "shadow") {
|
|
438
|
+
if (shadowTarget === void 0) throw new Error("Shadow target validation was skipped.");
|
|
439
|
+
if (mutationRequested(input)) {
|
|
440
|
+
const result = await migrator.runShadowTest({ target: shadowTarget });
|
|
441
|
+
return Array.isArray(result) ? {
|
|
442
|
+
ok: true,
|
|
443
|
+
target: shadowTarget,
|
|
444
|
+
migrations: result.flatMap(({ applied }) => applied)
|
|
445
|
+
} : result;
|
|
446
|
+
}
|
|
447
|
+
const status = await migrator.getConnectionStatus(shadowTarget);
|
|
448
|
+
return migrationPlan(shadowTarget, status.pending);
|
|
449
|
+
}
|
|
450
|
+
const target = requiredText(input, "target");
|
|
451
|
+
assertMigrationTarget(target);
|
|
452
|
+
if (method === "code") return migrator.getPreparedCodes(target);
|
|
453
|
+
const action = method === "rollback" || text(input, "action") === "rollback" ? "rollback" : "apply";
|
|
454
|
+
const plan = await migrationPlan(target, action === "apply" ? (await migrator.getConnectionStatus(target)).pending : (await migrator.getLatestAppliedBatch(target)).files, action);
|
|
455
|
+
if (method !== "rollback" || !mutationRequested(input)) return plan;
|
|
456
|
+
return migrator.rollback([target]);
|
|
457
|
+
}
|
|
458
|
+
async function fixtureOperation(method, input) {
|
|
459
|
+
await ensureSonamu();
|
|
460
|
+
const [fixtureCommands, { FixtureManager }, fixtureService, { Sonamu }] = await Promise.all([
|
|
461
|
+
import("../bin/fixture.js"),
|
|
462
|
+
import("../testing/fixture-manager.js"),
|
|
463
|
+
import("./fixture-service.js"),
|
|
464
|
+
import("../api/sonamu.js")
|
|
465
|
+
]);
|
|
466
|
+
if (method === "init") return mutationRequested(input) ? fixtureCommands.fixtureInitCommand() : { dryRun: true };
|
|
467
|
+
if (method === "import") {
|
|
468
|
+
if (!mutationRequested(input)) return { dryRun: true };
|
|
469
|
+
FixtureManager.init();
|
|
470
|
+
await FixtureManager.importFixture(requiredText(input, "entityId"), z.array(z.number()).parse(input.recordIds));
|
|
471
|
+
await FixtureManager.sync();
|
|
472
|
+
return { imported: true };
|
|
473
|
+
}
|
|
474
|
+
if (method === "sync") {
|
|
475
|
+
if (!mutationRequested(input)) return { dryRun: true };
|
|
476
|
+
FixtureManager.init();
|
|
477
|
+
await FixtureManager.sync();
|
|
478
|
+
return { synced: true };
|
|
479
|
+
}
|
|
480
|
+
const legacyCommand = z.enum([
|
|
481
|
+
"gen",
|
|
482
|
+
"fetch",
|
|
483
|
+
"explore"
|
|
484
|
+
]).parse(method);
|
|
485
|
+
if (![
|
|
486
|
+
"entityId",
|
|
487
|
+
"source",
|
|
488
|
+
"target",
|
|
489
|
+
"field",
|
|
490
|
+
"values",
|
|
491
|
+
"relations",
|
|
492
|
+
"depth"
|
|
493
|
+
].some((key) => input[key] !== void 0)) {
|
|
494
|
+
const options = fixtureService.normalizeLegacyFixtureCommandOptions(legacyCommand, input);
|
|
495
|
+
const strategy = z.enum([
|
|
496
|
+
"sample",
|
|
497
|
+
"ids",
|
|
498
|
+
"query",
|
|
499
|
+
"file",
|
|
500
|
+
"recent",
|
|
501
|
+
"random"
|
|
502
|
+
]).optional().parse(options.strategy);
|
|
503
|
+
const fixtureOptions = {
|
|
504
|
+
...options,
|
|
505
|
+
strategy
|
|
506
|
+
};
|
|
507
|
+
if (legacyCommand !== "explore" && !mutationRequested(input)) return {
|
|
508
|
+
dryRun: true,
|
|
509
|
+
request: fixtureOptions
|
|
510
|
+
};
|
|
511
|
+
if (legacyCommand === "gen") return fixtureCommands.fixtureGenCommand(fixtureOptions);
|
|
512
|
+
if (legacyCommand === "explore") return fixtureCommands.fixtureExploreCommand(fixtureOptions);
|
|
513
|
+
return fixtureCommands.fixtureFetchCommand(fixtureOptions);
|
|
514
|
+
}
|
|
515
|
+
const entityId = requiredText(input, "entityId");
|
|
516
|
+
const source = requiredText(input, "source");
|
|
517
|
+
const target = requiredText(input, "target");
|
|
518
|
+
const field = requiredText(input, "field");
|
|
519
|
+
const values = strings(input, "values");
|
|
520
|
+
const relations = requiredText(input, "relations");
|
|
521
|
+
const depth = z.number().int().nonnegative().safeParse(input.depth);
|
|
522
|
+
if (!Object.hasOwn(Sonamu.dbConfig, source) || !Object.hasOwn(Sonamu.dbConfig, target) || values.length === 0 || ![
|
|
523
|
+
"include",
|
|
524
|
+
"exclude",
|
|
525
|
+
"none"
|
|
526
|
+
].includes(relations) || !depth.success) throw Object.assign(/* @__PURE__ */ new Error("Invalid fixture transfer selector."), {
|
|
527
|
+
code: "INVALID_FIXTURE_TRANSFER",
|
|
528
|
+
exitCode: 2
|
|
529
|
+
});
|
|
530
|
+
const sourceKey = source;
|
|
531
|
+
const targetKey = target;
|
|
532
|
+
const records = (await Promise.all(values.map((value) => FixtureManager.getFixtures(sourceKey, targetKey, {
|
|
533
|
+
entityId,
|
|
534
|
+
field,
|
|
535
|
+
value,
|
|
536
|
+
searchType: "equals"
|
|
537
|
+
}, {
|
|
538
|
+
includeRelations: relations === "include",
|
|
539
|
+
maxDepth: depth.data
|
|
540
|
+
})))).flat();
|
|
541
|
+
if (explicitlyDryRun(input)) return {
|
|
542
|
+
dryRun: true,
|
|
543
|
+
records
|
|
544
|
+
};
|
|
545
|
+
if (records.length > 0) await FixtureManager.insertFixtures(targetKey, records);
|
|
546
|
+
return { records };
|
|
547
|
+
}
|
|
548
|
+
async function buildOperation(method) {
|
|
549
|
+
const { buildApiCommand, buildWebCommand } = await import("../bin/build-config.js");
|
|
550
|
+
if (method === "api") return buildApiCommand();
|
|
551
|
+
if (method === "web") return buildWebCommand();
|
|
552
|
+
await buildApiCommand();
|
|
553
|
+
return buildWebCommand({ skipIfMissing: true });
|
|
554
|
+
}
|
|
555
|
+
async function testOperation(method, input) {
|
|
556
|
+
const { createDefaultTestRunClient } = await import("./test-run-client.js");
|
|
557
|
+
const client = createDefaultTestRunClient();
|
|
558
|
+
if (method === "status") return client.status();
|
|
559
|
+
const request = {
|
|
560
|
+
files: z.array(z.string()).catch([]).parse(input.files),
|
|
561
|
+
pattern: z.string().optional().parse(input.pattern),
|
|
562
|
+
traces: input.traces === true
|
|
563
|
+
};
|
|
564
|
+
return {
|
|
565
|
+
request,
|
|
566
|
+
result: await client.run(request)
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
const betterAuthPluginSchema = z.enum([
|
|
570
|
+
"2fa",
|
|
571
|
+
"admin",
|
|
572
|
+
"anonymous",
|
|
573
|
+
"api-key",
|
|
574
|
+
"audit-log",
|
|
575
|
+
"jwt",
|
|
576
|
+
"organization",
|
|
577
|
+
"passkey",
|
|
578
|
+
"phone-number",
|
|
579
|
+
"sso",
|
|
580
|
+
"username"
|
|
581
|
+
]);
|
|
582
|
+
async function authOperation(method, input) {
|
|
583
|
+
const { addCompanionsToEntities, generateBetterAuthEntities } = await import("../auth/index.js");
|
|
584
|
+
if (method === "addCompanions") return addCompanionsToEntities();
|
|
585
|
+
return generateBetterAuthEntities({ plugins: z.array(betterAuthPluginSchema).parse((optionalText(input, "plugins") ?? "").split(",").map((plugin) => plugin.trim()).filter(Boolean)) });
|
|
586
|
+
}
|
|
587
|
+
async function i18nOperation(method, input) {
|
|
588
|
+
await ensureSonamu();
|
|
589
|
+
const { sonamuDictionary } = await import("../dict/sonamu-dictionary.js");
|
|
590
|
+
if (method === "list") {
|
|
591
|
+
const dictionary = await sonamuDictionary.getDictionary();
|
|
592
|
+
const locale = text(input, "locale");
|
|
593
|
+
return locale === void 0 ? dictionary : {
|
|
594
|
+
...dictionary,
|
|
595
|
+
locales: [locale],
|
|
596
|
+
rows: dictionary.rows.map((row) => ({
|
|
597
|
+
key: row.key,
|
|
598
|
+
source: row.source,
|
|
599
|
+
[locale]: row[locale]
|
|
600
|
+
}))
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
if (method === "check") {
|
|
604
|
+
const dictionary = await sonamuDictionary.getDictionary();
|
|
605
|
+
return sonamuDictionary.checkUsage(dictionary.rows.map((row) => row.key));
|
|
606
|
+
}
|
|
607
|
+
if (method === "export" || method === "import") {
|
|
608
|
+
const file = requiredText(input, "file");
|
|
609
|
+
if (explicitlyDryRun(input)) return {
|
|
610
|
+
operation: method,
|
|
611
|
+
dryRun: true
|
|
612
|
+
};
|
|
613
|
+
const { readFile, writeFile } = await import("node:fs/promises");
|
|
614
|
+
const format = text(input, "format") === "json" ? "json" : "workbook";
|
|
615
|
+
if (method === "export" && format === "workbook") {
|
|
616
|
+
const { buffer } = await sonamuDictionary.exportToExcel();
|
|
617
|
+
await writeFile(file, buffer);
|
|
618
|
+
return { exported: 1 };
|
|
619
|
+
}
|
|
620
|
+
if (method === "import" && format === "workbook") return sonamuDictionary.importFromExcel(await readFile(file));
|
|
621
|
+
if (method === "export") {
|
|
622
|
+
const dictionary = await sonamuDictionary.getDictionary();
|
|
623
|
+
const locale = text(input, "locale");
|
|
624
|
+
const rows = dictionary.rows.map(({ key, source: _source, isFunction: _isFunction, ...values }) => ({
|
|
625
|
+
key,
|
|
626
|
+
values: locale === void 0 ? values : { [locale]: z.string().catch("").parse(values[locale]) }
|
|
627
|
+
}));
|
|
628
|
+
await writeFile(file, JSON.stringify(rows, null, 2));
|
|
629
|
+
return { exported: rows.length };
|
|
630
|
+
}
|
|
631
|
+
const entries = parseJson((await readFile(file)).toString("utf8"), "I18N_INVALID_JSON", i18nEntriesSchema);
|
|
632
|
+
const current = await sonamuDictionary.getDictionary();
|
|
633
|
+
const existingKeys = new Set(current.rows.map(({ key }) => key));
|
|
634
|
+
for (const entry of entries) if (existingKeys.has(entry.key)) await sonamuDictionary.updateEntry({
|
|
635
|
+
oldKey: entry.key,
|
|
636
|
+
newKey: entry.key,
|
|
637
|
+
source: "project",
|
|
638
|
+
values: entry.values
|
|
639
|
+
});
|
|
640
|
+
else await sonamuDictionary.createEntry(entry);
|
|
641
|
+
return { imported: entries.length };
|
|
642
|
+
}
|
|
643
|
+
const key = requiredText(input, "key");
|
|
644
|
+
if (method === "create") {
|
|
645
|
+
if (explicitlyDryRun(input)) return {
|
|
646
|
+
operation: "create",
|
|
647
|
+
input,
|
|
648
|
+
dryRun: true
|
|
649
|
+
};
|
|
650
|
+
return sonamuDictionary.createEntry({
|
|
651
|
+
key,
|
|
652
|
+
values: dictionaryValuesSchema.parse(input.values)
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
if (method === "update") {
|
|
656
|
+
if (explicitlyDryRun(input)) return {
|
|
657
|
+
operation: "update",
|
|
658
|
+
input,
|
|
659
|
+
dryRun: true
|
|
660
|
+
};
|
|
661
|
+
const explicitSource = text(input, "source");
|
|
662
|
+
const resolvedSource = explicitSource === void 0 ? (await sonamuDictionary.getDictionary()).rows.find((row) => row.key === key)?.source ?? "project" : explicitSource;
|
|
663
|
+
return sonamuDictionary.updateEntry({
|
|
664
|
+
oldKey: key,
|
|
665
|
+
newKey: text(input, "newKey") ?? key,
|
|
666
|
+
source: dictionarySourceSchema.parse(resolvedSource),
|
|
667
|
+
values: dictionaryValuesSchema.parse(input.values)
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
if (!mutationRequested(input)) return {
|
|
671
|
+
key,
|
|
672
|
+
operation: "remove",
|
|
673
|
+
dryRun: true
|
|
674
|
+
};
|
|
675
|
+
return sonamuDictionary.deleteEntry(key);
|
|
676
|
+
}
|
|
677
|
+
async function taskOperation(method, input) {
|
|
678
|
+
await ensureSonamu();
|
|
679
|
+
const { Sonamu } = await import("../api/sonamu.js");
|
|
680
|
+
const workflows = Sonamu.workflows;
|
|
681
|
+
const backend = workflows.backend;
|
|
682
|
+
if (method === "definitions") return { definitions: workflows.workflowDefinitions };
|
|
683
|
+
if (method === "runs") return backend.listWorkflowRuns({ limit: 50 });
|
|
684
|
+
const workflowRunId = requiredText(input, "runId");
|
|
685
|
+
if (method === "show") return backend.getWorkflowRun({ workflowRunId });
|
|
686
|
+
if (method === "watch") {
|
|
687
|
+
const { isDeepStrictEqual } = await import("node:util");
|
|
688
|
+
return (async function* watch() {
|
|
689
|
+
let previous;
|
|
690
|
+
while (true) {
|
|
691
|
+
const snapshot = await backend.getWorkflowRun({ workflowRunId });
|
|
692
|
+
if (snapshot === null) throw Object.assign(/* @__PURE__ */ new Error(`Workflow run not found: ${workflowRunId}`), { code: "TASK_RUN_NOT_FOUND" });
|
|
693
|
+
const rawState = snapshot.status === "succeeded" ? "completed" : snapshot.status;
|
|
694
|
+
const state = rawState === "canceled" ? "cancelled" : rawState;
|
|
695
|
+
const current = {
|
|
696
|
+
...snapshot,
|
|
697
|
+
state
|
|
698
|
+
};
|
|
699
|
+
if (!isDeepStrictEqual(current, previous)) {
|
|
700
|
+
previous = structuredClone(current);
|
|
701
|
+
yield current;
|
|
702
|
+
}
|
|
703
|
+
if ([
|
|
704
|
+
"completed",
|
|
705
|
+
"failed",
|
|
706
|
+
"cancelled"
|
|
707
|
+
].includes(state)) return;
|
|
708
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
709
|
+
}
|
|
710
|
+
})();
|
|
711
|
+
}
|
|
712
|
+
if (method === "steps") return backend.listStepAttempts({
|
|
713
|
+
workflowRunId,
|
|
714
|
+
limit: 100
|
|
715
|
+
});
|
|
716
|
+
if (!mutationRequested(input)) return {
|
|
717
|
+
operation: method,
|
|
718
|
+
workflowRunId,
|
|
719
|
+
dryRun: true
|
|
720
|
+
};
|
|
721
|
+
if (method === "pause") return backend.pauseWorkflowRun({ workflowRunId });
|
|
722
|
+
if (method === "resume") return backend.resumeWorkflowRun({ workflowRunId });
|
|
723
|
+
return backend.cancelWorkflowRun({ workflowRunId });
|
|
724
|
+
}
|
|
725
|
+
async function cddRootPath() {
|
|
726
|
+
const [{ Sonamu }, path] = await Promise.all([import("../api/sonamu.js"), import("node:path")]);
|
|
727
|
+
return path.join(Sonamu.appRootPath, "contract");
|
|
728
|
+
}
|
|
729
|
+
const practiceSequencePattern = /^p([0-9]+)-/;
|
|
730
|
+
const practiceNamePattern = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
731
|
+
function invalidPracticeName(name) {
|
|
732
|
+
return Object.assign(/* @__PURE__ */ new Error(`Invalid practice name: ${name}. Use letters, digits, ".", "-", and "_" only, starting with a letter or digit.`), {
|
|
733
|
+
code: "INVALID_PRACTICE_NAME",
|
|
734
|
+
exitCode: 2
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
function invalidPracticeDirectory(directory) {
|
|
738
|
+
return Object.assign(/* @__PURE__ */ new Error(`Practice directory escapes the API root: ${directory}`), {
|
|
739
|
+
code: "INVALID_PRACTICE_PATH",
|
|
740
|
+
exitCode: 2
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* `src/practices` 아래에 다음 시퀀스 번호를 가진 practice 스텁 파일을 만듭니다.
|
|
745
|
+
*
|
|
746
|
+
* 구 CLI(`stub practice`)의 파일명 규칙과 스텁 본문을 그대로 유지합니다.
|
|
747
|
+
*/
|
|
748
|
+
async function stubPracticeOperation(input) {
|
|
749
|
+
const name = requiredText(input, "name");
|
|
750
|
+
if (!practiceNamePattern.test(name)) throw invalidPracticeName(name);
|
|
751
|
+
await ensureSonamu();
|
|
752
|
+
const [{ Sonamu }, { constants }, { mkdir, open, readdir, realpath }, path] = await Promise.all([
|
|
753
|
+
import("../api/sonamu.js"),
|
|
754
|
+
import("node:fs"),
|
|
755
|
+
import("node:fs/promises"),
|
|
756
|
+
import("node:path")
|
|
757
|
+
]);
|
|
758
|
+
const practiceDirectory = path.default.join(Sonamu.apiRootPath, "src", "practices");
|
|
759
|
+
await mkdir(practiceDirectory, { recursive: true });
|
|
760
|
+
const [canonicalApiRoot, canonicalDirectory] = await Promise.all([realpath(Sonamu.apiRootPath), realpath(practiceDirectory)]);
|
|
761
|
+
const directoryRelative = path.default.relative(canonicalApiRoot, canonicalDirectory);
|
|
762
|
+
if (directoryRelative.startsWith("..") || path.default.isAbsolute(directoryRelative)) throw invalidPracticeDirectory(practiceDirectory);
|
|
763
|
+
const fileName = `p${(await readdir(practiceDirectory)).filter((fileName) => fileName.startsWith("p") && fileName.endsWith(".ts")).reduce((largest, fileName) => {
|
|
764
|
+
const matched = practiceSequencePattern.exec(fileName);
|
|
765
|
+
return matched === null ? largest : Math.max(largest, Number.parseInt(matched[1], 10));
|
|
766
|
+
}, 0) + 1}-${name}.ts`;
|
|
767
|
+
const filePath = path.default.resolve(practiceDirectory, fileName);
|
|
768
|
+
const stubCode = [
|
|
769
|
+
`import { Sonamu } from "sonamu";`,
|
|
770
|
+
"",
|
|
771
|
+
`console.clear();`,
|
|
772
|
+
`console.log("${fileName}");`,
|
|
773
|
+
"",
|
|
774
|
+
`Sonamu.runScript(async () => {`,
|
|
775
|
+
` // TODO`,
|
|
776
|
+
`});`,
|
|
777
|
+
""
|
|
778
|
+
].join("\n");
|
|
779
|
+
let handle;
|
|
780
|
+
try {
|
|
781
|
+
handle = await open(filePath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 438);
|
|
782
|
+
await handle.writeFile(stubCode, "utf8");
|
|
783
|
+
} catch (error) {
|
|
784
|
+
const errorCode = error.code;
|
|
785
|
+
if (errorCode === "EEXIST" || errorCode === "ELOOP") throw Object.assign(/* @__PURE__ */ new Error(`Practice file already exists: ${filePath}`), {
|
|
786
|
+
code: "PRACTICE_FILE_EXISTS",
|
|
787
|
+
exitCode: 2,
|
|
788
|
+
cause: error
|
|
789
|
+
});
|
|
790
|
+
throw error;
|
|
791
|
+
} finally {
|
|
792
|
+
await handle?.close();
|
|
793
|
+
}
|
|
794
|
+
return {
|
|
795
|
+
fileName,
|
|
796
|
+
path: filePath
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
async function readCddTree(directory, root) {
|
|
800
|
+
const [{ readdir }, path] = await Promise.all([import("node:fs/promises"), import("node:path")]);
|
|
801
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
802
|
+
const nodes = [];
|
|
803
|
+
for (const entry of entries) {
|
|
804
|
+
if (entry.name === "rules") continue;
|
|
805
|
+
const absolutePath = path.join(directory, entry.name);
|
|
806
|
+
const relativePath = path.relative(root, absolutePath);
|
|
807
|
+
if (entry.isDirectory()) {
|
|
808
|
+
const children = await readCddTree(absolutePath, root);
|
|
809
|
+
if (children.length > 0) nodes.push({
|
|
810
|
+
name: entry.name,
|
|
811
|
+
path: relativePath,
|
|
812
|
+
type: "directory",
|
|
813
|
+
children
|
|
814
|
+
});
|
|
815
|
+
} else if (entry.isFile() && entry.name.endsWith(".contract.md")) nodes.push({
|
|
816
|
+
name: entry.name,
|
|
817
|
+
path: relativePath,
|
|
818
|
+
type: "file",
|
|
819
|
+
fileType: "contract"
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
return nodes;
|
|
823
|
+
}
|
|
824
|
+
async function cddOperation(method, input) {
|
|
825
|
+
await ensureSonamu();
|
|
826
|
+
const [{ access }, { createDefaultCddToolingAdapter }] = await Promise.all([import("node:fs/promises"), import("./cdd-service.js")]);
|
|
827
|
+
const adapter = createDefaultCddToolingAdapter({ contractRoot: await cddRootPath() });
|
|
828
|
+
if (method === "tree") {
|
|
829
|
+
const root = await cddRootPath();
|
|
830
|
+
try {
|
|
831
|
+
await access(root);
|
|
832
|
+
} catch {
|
|
833
|
+
return {
|
|
834
|
+
exists: false,
|
|
835
|
+
tree: []
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
return {
|
|
839
|
+
exists: true,
|
|
840
|
+
tree: await readCddTree(root, root)
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
if (method === "read") {
|
|
844
|
+
const relativePath = requiredText(input, "path");
|
|
845
|
+
return adapter.read({ path: relativePath });
|
|
846
|
+
}
|
|
847
|
+
if (method === "rules") return adapter.rules();
|
|
848
|
+
if (method === "showRule") {
|
|
849
|
+
const ruleId = requiredText(input, "ruleId");
|
|
850
|
+
return adapter.showRule({ ruleId });
|
|
851
|
+
}
|
|
852
|
+
if (method === "addRule") {
|
|
853
|
+
const ruleKey = requiredText(input, "ruleKey");
|
|
854
|
+
const id = requiredText(input, "id");
|
|
855
|
+
const when = requiredText(input, "when");
|
|
856
|
+
const ruleText = text(input, "instruction") ?? requiredText(input, "text");
|
|
857
|
+
return adapter.addRule({
|
|
858
|
+
ruleKey,
|
|
859
|
+
id,
|
|
860
|
+
when,
|
|
861
|
+
text: ruleText,
|
|
862
|
+
examples: strings(input, "examples"),
|
|
863
|
+
dryRun: explicitlyDryRun(input)
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
if (explicitlyDryRun(input)) return {
|
|
867
|
+
operation: "addAcceptanceCriterion",
|
|
868
|
+
input,
|
|
869
|
+
dryRun: true
|
|
870
|
+
};
|
|
871
|
+
const document = requiredText(input, "document");
|
|
872
|
+
const criterion = requiredText(input, "text");
|
|
873
|
+
return adapter.addAcceptanceCriterion({
|
|
874
|
+
document,
|
|
875
|
+
text: criterion,
|
|
876
|
+
dryRun: false
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
async function invokeDefault(group, method, input) {
|
|
880
|
+
if (group === "core") return syncOperation(input);
|
|
881
|
+
if (group === "entity") return entityOperation(method, input);
|
|
882
|
+
if (group === "scaffold") return scaffoldOperation(method, input);
|
|
883
|
+
if (group === "migration") return migrationOperation(method, input);
|
|
884
|
+
if (group === "fixture") return fixtureOperation(method, input);
|
|
885
|
+
if (group === "build") return buildOperation(method);
|
|
886
|
+
if (group === "test") return testOperation(method, input);
|
|
887
|
+
if (group === "auth") return authOperation(method, input);
|
|
888
|
+
if (group === "i18n") return i18nOperation(method, input);
|
|
889
|
+
if (group === "task") return taskOperation(method, input);
|
|
890
|
+
if (group === "stub") return stubPracticeOperation(input);
|
|
891
|
+
return cddOperation(method, input);
|
|
892
|
+
}
|
|
893
|
+
const tooling = Object.fromEntries(Object.entries(REQUIRED_METHODS).map(([group, methods]) => [group, Object.fromEntries(methods.map((method) => [method, (input) => invokeDefault(group, method, input)]))]));
|
|
894
|
+
Object.defineProperty(tooling.migration, "apply", {
|
|
895
|
+
enumerable: false,
|
|
896
|
+
value: (input) => invokeDefault("migration", "apply", input)
|
|
897
|
+
});
|
|
898
|
+
//#endregion
|
|
899
|
+
export { tooling };
|
|
900
|
+
|
|
901
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLXRvb2xpbmcuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rvb2xpbmcvY2xpLXRvb2xpbmcudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcblxuaW1wb3J0IHsgdHlwZSBGaXh0dXJlQ29tbWFuZE9wdGlvbnMgfSBmcm9tIFwiLi4vYmluL2ZpeHR1cmVcIjtcblxuY29uc3QganNvblZhbHVlU2NoZW1hID0gei5qc29uKCk7XG50eXBlIENvbW1hbmRWYWx1ZSA9IHouaW5mZXI8dHlwZW9mIGpzb25WYWx1ZVNjaGVtYT4gfCB1bmRlZmluZWQ7XG50eXBlIENvbW1hbmRJbnB1dCA9IFJlY29yZDxzdHJpbmcsIENvbW1hbmRWYWx1ZT47XG50eXBlIFRvb2xpbmdSZXN1bHQgPSBvYmplY3QgfCBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgbnVsbCB8IHZvaWQgfCBBc3luY0l0ZXJhYmxlPG9iamVjdD47XG50eXBlIFRvb2xpbmdPcGVyYXRpb24gPSAoaW5wdXQ6IENvbW1hbmRJbnB1dCkgPT4gVG9vbGluZ1Jlc3VsdCB8IFByb21pc2U8VG9vbGluZ1Jlc3VsdD47XG50eXBlIFRvb2xpbmdHcm91cCA9IFJlY29yZDxzdHJpbmcsIFRvb2xpbmdPcGVyYXRpb24+O1xuZXhwb3J0IHR5cGUgQ2xpVG9vbGluZ09wZXJhdGlvbnMgPSBSZWNvcmQ8c3RyaW5nLCBUb29saW5nR3JvdXA+O1xuXG50eXBlIE1pZ3JhdGlvblRhcmdldCA9IFwiZGV2ZWxvcG1lbnRcIiB8IFwic3RhZ2luZ1wiIHwgXCJwcm9kdWN0aW9uXCIgfCBcImZpeHR1cmVcIiB8IFwidGVzdFwiO1xuXG5jb25zdCBNSUdSQVRJT05fVEFSR0VUUyA9IG5ldyBTZXQ8c3RyaW5nPihbXG4gIFwiZGV2ZWxvcG1lbnRcIixcbiAgXCJzdGFnaW5nXCIsXG4gIFwicHJvZHVjdGlvblwiLFxuICBcImZpeHR1cmVcIixcbiAgXCJ0ZXN0XCIsXG5dKTtcblxuZnVuY3Rpb24gYXNzZXJ0TWlncmF0aW9uVGFyZ2V0KHRhcmdldDogc3RyaW5nKTogYXNzZXJ0cyB0YXJnZXQgaXMgTWlncmF0aW9uVGFyZ2V0IHtcbiAgLy8gREIg7IOB7YOc66W8IOyhsO2ajO2VmOqxsOuCmCDrs4Dqsr3tlZjquLAg7KCE7JeQIOuqqOuToCDsmbjrtoAg64yA7IOB7J2EIOqygOymne2VqeuLiOuLpC5cbiAgaWYgKE1JR1JBVElPTl9UQVJHRVRTLmhhcyh0YXJnZXQpKSByZXR1cm47XG4gIHRocm93IE9iamVjdC5hc3NpZ24obmV3IEVycm9yKGBVbnN1cHBvcnRlZCBtaWdyYXRpb24gdGFyZ2V0OiAke3RhcmdldH1gKSwge1xuICAgIGNvZGU6IFwiSU5WQUxJRF9NSUdSQVRJT05fVEFSR0VUXCIsXG4gICAgZXhpdENvZGU6IDIsXG4gIH0pO1xufVxuXG5mdW5jdGlvbiBhc3NlcnRTaGFkb3dNaWdyYXRpb25UYXJnZXQoXG4gIHRhcmdldDogTWlncmF0aW9uVGFyZ2V0LFxuKTogYXNzZXJ0cyB0YXJnZXQgaXMgRXh0cmFjdDxNaWdyYXRpb25UYXJnZXQsIFwiZml4dHVyZVwiIHwgXCJ0ZXN0XCI+IHtcbiAgaWYgKHRhcmdldCA9PT0gXCJmaXh0dXJlXCIgfHwgdGFyZ2V0ID09PSBcInRlc3RcIikgcmV0dXJuO1xuXG4gIC8vIFNoYWRvdyBEQuuKlCDsmrTsmIEg6rOE7Je0IOyXsOqysOyXkCDsoJHqt7ztlZjquLAg7KCE7JeQIO2XiOyaqSDrjIDsg4HsnYQg7KCc7ZWc7ZWp64uI64ukLlxuICB0aHJvdyBPYmplY3QuYXNzaWduKG5ldyBFcnJvcihgSW52YWxpZCBzaGFkb3cgbWlncmF0aW9uIHRhcmdldDogJHt0YXJnZXR9YCksIHtcbiAgICBjb2RlOiBcIklOVkFMSURfU0hBRE9XX01JR1JBVElPTl9UQVJHRVRcIixcbiAgICB0YXJnZXQsXG4gICAgZXhpdENvZGU6IDIsXG4gIH0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiBtaWdyYXRpb25QbGFuKFxuICB0YXJnZXQ6IE1pZ3JhdGlvblRhcmdldCxcbiAgbWlncmF0aW9uczogc3RyaW5nW10sXG4gIGFjdGlvbjogXCJhcHBseVwiIHwgXCJyb2xsYmFja1wiID0gXCJhcHBseVwiLFxuKSB7XG4gIGNvbnN0IGRpZ2VzdCA9IGF3YWl0IGNyeXB0by5zdWJ0bGUuZGlnZXN0KFxuICAgIFwiU0hBLTI1NlwiLFxuICAgIG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShKU09OLnN0cmluZ2lmeSh7IGFjdGlvbiwgdGFyZ2V0LCBtaWdyYXRpb25zIH0pKSxcbiAgKTtcbiAgcmV0dXJuIHtcbiAgICBraW5kOiBcIm1pZ3JhdGlvbi1wbGFuXCIgYXMgY29uc3QsXG4gICAgYWN0aW9uLFxuICAgIHRhcmdldCxcbiAgICBtaWdyYXRpb25zLFxuICAgIGZpbmdlcnByaW50OiBBcnJheS5mcm9tKG5ldyBVaW50OEFycmF5KGRpZ2VzdCksIChieXRlKSA9PlxuICAgICAgYnl0ZS50b1N0cmluZygxNikucGFkU3RhcnQoMiwgXCIwXCIpLFxuICAgICkuam9pbihcIlwiKSxcbiAgfTtcbn1cblxuY29uc3QgUkVRVUlSRURfTUVUSE9EUyA9IHtcbiAgY29yZTogW1wic3luY1wiXSxcbiAgZW50aXR5OiBbXCJsaXN0XCIsIFwic2hvd1wiLCBcInNlYXJjaFwiLCBcImFwcGx5UGF0Y2hcIiwgXCJjcmVhdGVcIiwgXCJjb25lc1wiXSxcbiAgc2NhZmZvbGQ6IFtcIm1vZGVsXCIsIFwibW9kZWxfdGVzdFwiLCBcInZpZXdfbGlzdFwiLCBcInZpZXdfZm9ybVwiLCBcInN0YXR1c1wiLCBcInByZXZpZXdcIiwgXCJiYXRjaFwiXSxcbiAgbWlncmF0aW9uOiBbXCJydW5cIiwgXCJnZW5lcmF0ZVwiLCBcInN0YXR1c1wiLCBcImNvbm5lY3Rpb25zXCIsIFwiY29kZVwiLCBcInByZXZpZXdcIiwgXCJzaGFkb3dcIiwgXCJyb2xsYmFja1wiXSxcbiAgZml4dHVyZTogW1wiaW5pdFwiLCBcImltcG9ydFwiLCBcInN5bmNcIiwgXCJnZW5cIiwgXCJmZXRjaFwiLCBcImV4cGxvcmVcIl0sXG4gIGJ1aWxkOiBbXCJhbGxcIiwgXCJhcGlcIiwgXCJ3ZWJcIl0sXG4gIHRlc3Q6IFtcInJ1blwiLCBcInN0YXR1c1wiXSxcbiAgYXV0aDogW1wiZ2VuZXJhdGVcIiwgXCJhZGRDb21wYW5pb25zXCJdLFxuICBpMThuOiBbXCJsaXN0XCIsIFwiY2hlY2tcIiwgXCJpbXBvcnRcIiwgXCJleHBvcnRcIiwgXCJjcmVhdGVcIiwgXCJ1cGRhdGVcIiwgXCJyZW1vdmVcIl0sXG4gIHRhc2s6IFtcImRlZmluaXRpb25zXCIsIFwicnVuc1wiLCBcInNob3dcIiwgXCJzdGVwc1wiLCBcIndhdGNoXCIsIFwicGF1c2VcIiwgXCJyZXN1bWVcIiwgXCJjYW5jZWxcIl0sXG4gIGNkZDogW1widHJlZVwiLCBcInJlYWRcIiwgXCJydWxlc1wiLCBcInNob3dSdWxlXCIsIFwiYWRkUnVsZVwiLCBcImFkZEFjY2VwdGFuY2VDcml0ZXJpb25cIl0sXG4gIHN0dWI6IFtcInByYWN0aWNlXCJdLFxufSBhcyBjb25zdDtcblxubGV0IGluaXRpYWxpemF0aW9uOiBQcm9taXNlPHZvaWQ+IHwgdW5kZWZpbmVkO1xuXG5hc3luYyBmdW5jdGlvbiBlbnN1cmVTb25hbXUoKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHsgU29uYW11IH0gPSBhd2FpdCBpbXBvcnQoXCIuLi9hcGkvc29uYW11XCIpO1xuICBpZiAoU29uYW11LmlzSW5pdGlhbGl6ZWQpIHJldHVybjtcbiAgaW5pdGlhbGl6YXRpb24gPz89IFNvbmFtdS5pbml0KHRydWUsIGZhbHNlKTtcbiAgYXdhaXQgaW5pdGlhbGl6YXRpb247XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN5bmNPcGVyYXRpb24oaW5wdXQ6IENvbW1hbmRJbnB1dCk6IFByb21pc2U8VG9vbGluZ1Jlc3VsdD4ge1xuICBhd2FpdCBlbnN1cmVTb25hbXUoKTtcbiAgY29uc3QgeyBTb25hbXUgfSA9IGF3YWl0IGltcG9ydChcIi4uL2FwaS9zb25hbXVcIik7XG4gIHJldHVybiBpbnB1dC5mb3JjZSA9PT0gdHJ1ZSA/IFNvbmFtdS5zeW5jZXIuZm9yY2VTeW5jKCkgOiBTb25hbXUuc3luY2VyLnN5bmMoKTtcbn1cblxuZnVuY3Rpb24gdGV4dChpbnB1dDogQ29tbWFuZElucHV0LCBrZXk6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHZhbHVlID0gei5zdHJpbmcoKS5zYWZlUGFyc2UoaW5wdXRba2V5XSk7XG4gIHJldHVybiB2YWx1ZS5zdWNjZXNzID8gdmFsdWUuZGF0YSA6IHVuZGVmaW5lZDtcbn1cblxuZnVuY3Rpb24gc3RyaW5ncyhpbnB1dDogQ29tbWFuZElucHV0LCBrZXk6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgY29uc3QgdmFsdWUgPSB6LmFycmF5KHouc3RyaW5nKCkpLnNhZmVQYXJzZShpbnB1dFtrZXldKTtcbiAgcmV0dXJuIHZhbHVlLnN1Y2Nlc3MgPyB2YWx1ZS5kYXRhIDogW107XG59XG5cbmZ1bmN0aW9uIHJlcXVpcmVkVGV4dChpbnB1dDogQ29tbWFuZElucHV0LCBrZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHZhbHVlID0gdGV4dChpbnB1dCwga2V5KTtcbiAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQgJiYgdmFsdWUubGVuZ3RoID4gMCkgcmV0dXJuIHZhbHVlO1xuICB0aHJvdyBPYmplY3QuYXNzaWduKG5ldyBFcnJvcihgTWlzc2luZyAke2tleX0uYCksIHsgY29kZTogXCJNSVNTSU5HX0FSR1VNRU5UXCIsIGV4aXRDb2RlOiAyIH0pO1xufVxuXG4vKipcbiAqIOyDneuete2VnCDqsJLsnYAgYHVuZGVmaW5lZGDroZwg7Ya16rO87Iuc7YKk65CYLCDqsJLsnbQg7J6I64qU642wIOusuOyekOyXtOydtCDslYTri4jrqbQg7J247J6QIOyYpOulmOuhnCDqsbDsoIjtlanri4jri6QuXG4gKlxuICogYHRleHQoKWDsspjrn7wg7KGw7Jqp7Z6IIOustOyLnO2VmOuptCDsnpjrqrvrkJwg7YOA7J6F7J2YIOyeheugpeydtCDquLDrs7jqsJLsnLzroZwg65GU6rCR7ZWp64uI64ukLlxuICovXG5mdW5jdGlvbiBvcHRpb25hbFRleHQoaW5wdXQ6IENvbW1hbmRJbnB1dCwga2V5OiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCB2YWx1ZSA9IGlucHV0W2tleV07XG4gIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSBudWxsKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCBwYXJzZWQgPSB6LnN0cmluZygpLnNhZmVQYXJzZSh2YWx1ZSk7XG4gIGlmIChwYXJzZWQuc3VjY2VzcykgcmV0dXJuIHBhcnNlZC5kYXRhO1xuICB0aHJvdyBPYmplY3QuYXNzaWduKG5ldyBFcnJvcihgSW52YWxpZCAke2tleX0uYCksIHsgY29kZTogXCJJTlZBTElEX0FSR1VNRU5UXCIsIGV4aXRDb2RlOiAyIH0pO1xufVxuXG5mdW5jdGlvbiBwYXJzZUpzb248U2NoZW1hIGV4dGVuZHMgei5ab2RUeXBlPihcbiAgY29udGVudHM6IHN0cmluZyxcbiAgY29kZTogc3RyaW5nLFxuICBzY2hlbWE6IFNjaGVtYSxcbik6IHouaW5mZXI8U2NoZW1hPiB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIHNjaGVtYS5wYXJzZShKU09OLnBhcnNlKGNvbnRlbnRzKSk7XG4gIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgdGhyb3cgT2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoXCJJbnZhbGlkIEpTT04gaW5wdXQuXCIpLCB7IGNvZGUsIGV4aXRDb2RlOiAyLCBjYXVzZSB9KTtcbiAgfVxufVxuXG5mdW5jdGlvbiBtdXRhdGlvblJlcXVlc3RlZChpbnB1dDogQ29tbWFuZElucHV0KTogYm9vbGVhbiB7XG4gIHJldHVybiBpbnB1dC5leGVjdXRlID09PSB0cnVlIHx8IGlucHV0LmRyeVJ1biA9PT0gZmFsc2U7XG59XG5cbmZ1bmN0aW9uIGV4cGxpY2l0bHlEcnlSdW4oaW5wdXQ6IENvbW1hbmRJbnB1dCk6IGJvb2xlYW4ge1xuICByZXR1cm4gaW5wdXQuZHJ5UnVuID09PSB0cnVlIHx8IGlucHV0LmV4ZWN1dGUgPT09IGZhbHNlO1xufVxuXG5jb25zdCBlbnRpdHlQYXRjaFNjaGVtYSA9IHoub2JqZWN0KHtcbiAgZW50aXR5SWQ6IHouc3RyaW5nKCkubWluKDEpLFxuICBvcGVyYXRpb25zOiB6LmFycmF5KFxuICAgIHoub2JqZWN0KHtcbiAgICAgIG9wOiB6LmxpdGVyYWwoXCJhZGRcIiksXG4gICAgICBwYXRoOiB6LmxpdGVyYWwoXCIvcHJvcHMvLVwiKSxcbiAgICAgIHZhbHVlOiB6XG4gICAgICAgIC5vYmplY3QoeyBuYW1lOiB6LnN0cmluZygpLm1pbigxKSwgdHlwZTogei5zdHJpbmcoKS5taW4oMSkgfSlcbiAgICAgICAgLmNhdGNoYWxsKGpzb25WYWx1ZVNjaGVtYSksXG4gICAgfSksXG4gICksXG59KTtcbmNvbnN0IGkxOG5FbnRyaWVzU2NoZW1hID0gei5hcnJheShcbiAgei5vYmplY3QoeyBrZXk6IHouc3RyaW5nKCksIHZhbHVlczogei5yZWNvcmQoei5zdHJpbmcoKSwgei5zdHJpbmcoKSkgfSksXG4pO1xuY29uc3QgZGljdGlvbmFyeVZhbHVlc1NjaGVtYSA9IHoucmVjb3JkKHouc3RyaW5nKCksIHouc3RyaW5nKCkpO1xuY29uc3QgZGljdGlvbmFyeVNvdXJjZVNjaGVtYSA9IHouZW51bShbXCJlbnRpdHlcIiwgXCJwcm9qZWN0XCIsIFwic29uYW11XCJdKTtcbmNvbnN0IGNvbmVMb2NhbGVTY2hlbWEgPSB6LmVudW0oW1wia29cIiwgXCJlblwiLCBcImphXCJdKTtcblxuLyoqXG4gKiBjb25lIOyDneyEseyXkCDsgqzsmqntlaAgbG9jYWxl7J2EIOqysOygle2VqeuLiOuLpC5cbiAqXG4gKiDrqoXsi5ztlZwgbG9jYWxl7J20IOy1nOyasOyEoOydtOqzoCwg7JeG7Jy866m0IO2UhOuhnOygne2KuCBpMThuIOq4sOuzuCBsb2NhbGUsIOq3uOuniOyggCDsl4bsnLzrqbQgXCJrb1wi66W8IOyCrOyaqe2VqeuLiOuLpC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZUNvbmVMb2NhbGUoaW5wdXQ6IENvbW1hbmRJbnB1dCk6IFByb21pc2U8ei5pbmZlcjx0eXBlb2YgY29uZUxvY2FsZVNjaGVtYT4+IHtcbiAgY29uc3QgZXhwbGljaXQgPSBjb25lTG9jYWxlU2NoZW1hLnNhZmVQYXJzZShpbnB1dC5sb2NhbGUpO1xuICBpZiAoZXhwbGljaXQuc3VjY2VzcykgcmV0dXJuIGV4cGxpY2l0LmRhdGE7XG5cbiAgY29uc3QgeyBTb25hbXUgfSA9IGF3YWl0IGltcG9ydChcIi4uL2FwaS9zb25hbXVcIik7XG4gIGxldCBjb25maWd1cmVkTG9jYWxlOiB1bmtub3duO1xuICB0cnkge1xuICAgIGNvbmZpZ3VyZWRMb2NhbGUgPSBTb25hbXUuY29uZmlnLmkxOG4/LmRlZmF1bHRMb2NhbGU7XG4gIH0gY2F0Y2gge1xuICAgIC8vIOyEpOygleydhCDslYTsp4Eg7J297J2EIOyImCDsl4bripQg7Iuk7ZaJIOqyveuhnOyXkOyEnOuKlCDquLDrs7ggbG9jYWxl66GcIO2PtOuwse2VqeuLiOuLpC5cbiAgfVxuICBjb25zdCBjb25maWd1cmVkID0gY29uZUxvY2FsZVNjaGVtYS5zYWZlUGFyc2UoY29uZmlndXJlZExvY2FsZSk7XG4gIHJldHVybiBjb25maWd1cmVkLnN1Y2Nlc3MgPyBjb25maWd1cmVkLmRhdGEgOiBcImtvXCI7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGVudGl0eU9wZXJhdGlvbihtZXRob2Q6IHN0cmluZywgaW5wdXQ6IENvbW1hbmRJbnB1dCk6IFByb21pc2U8VG9vbGluZ1Jlc3VsdD4ge1xuICBhd2FpdCBlbnN1cmVTb25hbXUoKTtcbiAgY29uc3QgeyBFbnRpdHlNYW5hZ2VyIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi9lbnRpdHkvZW50aXR5LW1hbmFnZXJcIik7XG4gIGNvbnN0IGVudGl0aWVzID0gRW50aXR5TWFuYWdlci5nZXRBbGxFbnRpdGllcygpO1xuXG4gIGlmIChtZXRob2QgPT09IFwibGlzdFwiKSByZXR1cm4gZW50aXRpZXMubWFwKChlbnRpdHkpID0+IGVudGl0eS50b0pzb24oKSk7XG4gIGlmIChtZXRob2QgPT09IFwic2hvd1wiKSB7XG4gICAgY29uc3QgZW50aXR5SWQgPSByZXF1aXJlZFRleHQoaW5wdXQsIFwiZW50aXR5SWRcIik7XG4gICAgaWYgKCFFbnRpdHlNYW5hZ2VyLmV4aXN0cyhlbnRpdHlJZCkpIHtcbiAgICAgIHRocm93IE9iamVjdC5hc3NpZ24obmV3IEVycm9yKGBFbnRpdHkgbm90IGZvdW5kOiAke2VudGl0eUlkfWApLCB7XG4gICAgICAgIGNvZGU6IFwiRU5USVRZX05PVF9GT1VORFwiLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBFbnRpdHlNYW5hZ2VyLmdldChlbnRpdHlJZCkudG9Kc29uKCk7XG4gIH1cbiAgaWYgKG1ldGhvZCA9PT0gXCJzZWFyY2hcIikge1xuICAgIGNvbnN0IHF1ZXJ5ID0gcmVxdWlyZWRUZXh0KGlucHV0LCBcInF1ZXJ5XCIpLnRvTG9jYWxlTG93ZXJDYXNlKCk7XG4gICAgcmV0dXJuIGVudGl0aWVzXG4gICAgICAubWFwKChlbnRpdHkpID0+IGVudGl0eS50b0pzb24oKSlcbiAgICAgIC5maWx0ZXIoKGVudGl0eSkgPT4gSlNPTi5zdHJpbmdpZnkoZW50aXR5KS50b0xvY2FsZUxvd2VyQ2FzZSgpLmluY2x1ZGVzKHF1ZXJ5KSk7XG4gIH1cbiAgaWYgKG1ldGhvZCA9PT0gXCJjcmVhdGVcIikge1xuICAgIGNvbnN0IGVudGl0eUlkID0gcmVxdWlyZWRUZXh0KGlucHV0LCBcIm5hbWVcIik7XG4gICAgY29uc3QgeyBTb25hbXUgfSA9IGF3YWl0IGltcG9ydChcIi4uL2FwaS9zb25hbXVcIik7XG4gICAgYXdhaXQgU29uYW11LnN5bmNlci5jcmVhdGVFbnRpdHkoeyBlbnRpdHlJZCwgdGl0bGU6IGVudGl0eUlkIH0pO1xuICAgIGlmIChpbnB1dC5ub0NvbmVzID09PSB0cnVlKSByZXR1cm4geyBlbnRpdHlJZCwgY29uZXM6IFwic2tpcHBlZFwiIH07XG4gICAgY29uc3QgZW50aXR5ID0gRW50aXR5TWFuYWdlci5nZXQoZW50aXR5SWQpO1xuICAgIGlmIChpbnB1dC5haSA9PT0gdHJ1ZSkge1xuICAgICAgcmV0dXJuIGVudGl0eS5nZW5lcmF0ZUNvbmVzKHtcbiAgICAgICAgcHJlc2VydmVFeGlzdGluZzogZmFsc2UsXG4gICAgICAgIG9ubHlFbXB0eTogZmFsc2UsXG4gICAgICAgIGxvY2FsZTogYXdhaXQgcmVzb2x2ZUNvbmVMb2NhbGUoaW5wdXQpLFxuICAgICAgfSk7XG4gICAgfVxuICAgIGF3YWl0IGVudGl0eS5nZW5lcmF0ZVRlbXBsYXRlQ29uZXMoKTtcbiAgICByZXR1cm4geyBlbnRpdHlJZCwgY29uZXM6IFwidGVtcGxhdGVcIiB9O1xuICB9XG4gIGlmIChtZXRob2QgPT09IFwiY29uZXNcIikge1xuICAgIGNvbnN0IGVudGl0eUlkID0gcmVxdWlyZWRUZXh0KGlucHV0LCBcImVudGl0eUlkXCIpO1xuICAgIGNvbnN0IHRhcmdldHMgPVxuICAgICAgaW5wdXQuYWxsID09PSB0cnVlIHx8IGVudGl0eUlkID09PSBcImFsbFwiXG4gICAgICAgID8gRW50aXR5TWFuYWdlci5nZXRBbGxFbnRpdGllcygpXG4gICAgICAgIDogRW50aXR5TWFuYWdlci5leGlzdHMoZW50aXR5SWQpXG4gICAgICAgICAgPyBbRW50aXR5TWFuYWdlci5nZXQoZW50aXR5SWQpXVxuICAgICAgICAgIDogW107XG4gICAgaWYgKHRhcmdldHMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBPYmplY3QuYXNzaWduKG5ldyBFcnJvcihgRW50aXR5IG5vdCBmb3VuZDogJHtlbnRpdHlJZH1gKSwge1xuICAgICAgICBjb2RlOiBcIkVOVElUWV9OT1RfRk9VTkRcIixcbiAgICAgIH0pO1xuICAgIH1cbiAgICBjb25zdCByZWdlbmVyYXRlID0gaW5wdXQucmVnZW5lcmF0ZSA9PT0gdHJ1ZTtcbiAgICBjb25zdCBzZWxlY3RlZExvY2FsZSA9IGF3YWl0IHJlc29sdmVDb25lTG9jYWxlKGlucHV0KTtcbiAgICAvLyDtlZwg7JeU7Yuw7Yuw7J2YIOyLpO2MqOqwgCDrgpjrqLjsp4Ag7JeU7Yuw7Yuw7J2YIGNvbmUg7IOd7ISx7J2EIOy3qOyGjO2VmOyngCDslYrrj4TroZ0g7KCE67aAIOuBneq5jOyngCDsi6Ttlontlanri4jri6QuXG4gICAgY29uc3Qgc2V0dGxlZCA9IGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChcbiAgICAgIHRhcmdldHMubWFwKGFzeW5jIChlbnRpdHkpID0+ICh7XG4gICAgICAgIGVudGl0eUlkOiBlbnRpdHkuaWQsXG4gICAgICAgIC4uLihhd2FpdCBlbnRpdHkuZ2VuZXJhdGVDb25lcyh7XG4gICAgICAgICAgcHJlc2VydmVFeGlzdGluZzogIXJlZ2VuZXJhdGUsXG4gICAgICAgICAgb25seUVtcHR5OiAhcmVnZW5lcmF0ZSxcbiAgICAgICAgICBsb2NhbGU6IHNlbGVjdGVkTG9jYWxlLFxuICAgICAgICB9KSksXG4gICAgICB9KSksXG4gICAgKTtcbiAgICBjb25zdCByZXN1bHRzID0gW107XG4gICAgY29uc3QgZmFpbHVyZXMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IFtpbmRleCwgb3V0Y29tZV0gb2Ygc2V0dGxlZC5lbnRyaWVzKCkpIHtcbiAgICAgIGlmIChvdXRjb21lLnN0YXR1cyA9PT0gXCJmdWxmaWxsZWRcIikge1xuICAgICAgICByZXN1bHRzLnB1c2gob3V0Y29tZS52YWx1ZSk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgZmFpbHVyZXMucHVzaCh7XG4gICAgICAgIGVudGl0eUlkOiB0YXJnZXRzW2luZGV4XS5pZCxcbiAgICAgICAgbWVzc2FnZTogb3V0Y29tZS5yZWFzb24gaW5zdGFuY2VvZiBFcnJvciA/IG91dGNvbWUucmVhc29uLm1lc3NhZ2UgOiBTdHJpbmcob3V0Y29tZS5yZWFzb24pLFxuICAgICAgfSk7XG4gICAgfVxuICAgIGlmIChmYWlsdXJlcy5sZW5ndGggPT09IDApIHJldHVybiByZXN1bHRzO1xuICAgIHRocm93IE9iamVjdC5hc3NpZ24obmV3IEVycm9yKGBDb25lIGdlbmVyYXRpb24gZmFpbGVkIGZvciAke2ZhaWx1cmVzLmxlbmd0aH0gZW50aXR5KHMpLmApLCB7XG4gICAgICBjb2RlOiBcIkNPTkVfR0VORVJBVElPTl9GQUlMRURcIixcbiAgICAgIGRldGFpbHM6IHsgcmVzdWx0cywgZmFpbHVyZXMgfSxcbiAgICB9KTtcbiAgfVxuXG4gIGNvbnN0IGZpbGUgPSByZXF1aXJlZFRleHQoaW5wdXQsIFwiZmlsZVwiKTtcbiAgY29uc3QgeyByZWFkRmlsZSB9ID0gYXdhaXQgaW1wb3J0KFwibm9kZTpmcy9wcm9taXNlc1wiKTtcbiAgY29uc3QgY29udGVudHMgPVxuICAgIGZpbGUgPT09IFwiLVwiXG4gICAgICA/IGF3YWl0IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgY29uc3QgY2h1bmtzID0gW107XG4gICAgICAgICAgZm9yIGF3YWl0IChjb25zdCBjaHVuayBvZiBwcm9jZXNzLnN0ZGluKSBjaHVua3MucHVzaChCdWZmZXIuZnJvbShjaHVuaykpO1xuICAgICAgICAgIHJldHVybiBCdWZmZXIuY29uY2F0KGNodW5rcykudG9TdHJpbmcoXCJ1dGY4XCIpO1xuICAgICAgICB9KSgpXG4gICAgICA6IGF3YWl0IHJlYWRGaWxlKGZpbGUsIFwidXRmOFwiKTtcbiAgY29uc3QgcGF0Y2ggPSBwYXJzZUpzb24oY29udGVudHMsIFwiSU5WQUxJRF9FTlRJVFlfUEFUQ0hcIiwgZW50aXR5UGF0Y2hTY2hlbWEpO1xuICBpZiAoIUVudGl0eU1hbmFnZXIuZXhpc3RzKHBhdGNoLmVudGl0eUlkKSkge1xuICAgIHRocm93IE9iamVjdC5hc3NpZ24obmV3IEVycm9yKGBFbnRpdHkgbm90IGZvdW5kOiAke3BhdGNoLmVudGl0eUlkfWApLCB7XG4gICAgICBjb2RlOiBcIkVOVElUWV9OT1RfRk9VTkRcIixcbiAgICB9KTtcbiAgfVxuICBjb25zdCB0YXJnZXQgPSBFbnRpdHlNYW5hZ2VyLmdldChwYXRjaC5lbnRpdHlJZCk7XG4gIGNvbnN0IGJlZm9yZSA9IHRhcmdldC50b0pzb24oKTtcbiAgY29uc3QgYWZ0ZXIgPSBzdHJ1Y3R1cmVkQ2xvbmUoYmVmb3JlKTtcbiAgY29uc3QgbmV4dFByb3BzID0gW1xuICAgIC4uLmFmdGVyLnByb3BzLFxuICAgIC4uLnBhdGNoLm9wZXJhdGlvbnMubWFwKCh7IHZhbHVlIH0pID0+IHN0cnVjdHVyZWRDbG9uZSh2YWx1ZSkpLFxuICBdO1xuICAvLyDtjIzsnbzsnbTrgpgg65Ox66Gd65CcIOyXlO2LsO2LsOulvCDqsbTrk5zrpqzquLAg7KCE7JeQIHBhdGNoIOyggeyaqSDqsrDqs7wg7KCE7LK066W8IGVudGl0eSDsiqTtgqTrp4jroZwg6rKA7Kad7ZWp64uI64ukLlxuICBjb25zdCB7IEVudGl0eUpzb25TY2hlbWEgfSA9IGF3YWl0IGltcG9ydChcIi4uL3R5cGVzL3R5cGVzXCIpO1xuICBjb25zdCB2YWxpZGF0aW9uID0gRW50aXR5SnNvblNjaGVtYS5zYWZlUGFyc2UoeyAuLi5hZnRlciwgcHJvcHM6IG5leHRQcm9wcyB9KTtcbiAgaWYgKCF2YWxpZGF0aW9uLnN1Y2Nlc3MpIHtcbiAgICB0aHJvdyBPYmplY3QuYXNzaWduKG5ldyBFcnJvcihcIkludmFsaWQgZW50aXR5IHBhdGNoLlwiKSwge1xuICAgICAgY29kZTogXCJJTlZBTElEX0VOVElUWV9QQVRDSFwiLFxuICAgICAgZXhpdENvZGU6IDIsXG4gICAgICBjYXVzZTogdmFsaWRhdGlvbi5lcnJvcixcbiAgICB9KTtcbiAgfVxuICAvLyBTQUZFVFk6IEVudGl0eUpzb25TY2hlbWHqsIAgcGF0Y2gg7KCB7JqpIOqysOqzvCDsoITssrTrpbwg6rKA7Kad7ZaI7Iq164uI64ukLlxuICBhZnRlci5wcm9wcyA9IG5leHRQcm9wcyBhcyB0eXBlb2YgYWZ0ZXIucHJvcHM7XG4gIGlmIChtdXRhdGlvblJlcXVlc3RlZChpbnB1dCkpIHtcbiAgICAvLyBTQUZFVFk6IGFmdGVyLnByb3BzIG9yaWdpbmF0ZXMgZnJvbSB0aGUgY3VycmVudCBlbnRpdHkgcGx1cyBzY2hlbWEtdmFsaWRhdGVkIHByb3AgYWRkaXRpb25zLlxuICAgIHRhcmdldC5wcm9wcyA9IGFmdGVyLnByb3BzIGFzIHR5cGVvZiB0YXJnZXQucHJvcHM7XG4gICAgYXdhaXQgdGFyZ2V0LnNhdmUoKTtcbiAgfVxuICByZXR1cm4geyBjaGFuZ2VkOiBwYXRjaC5vcGVyYXRpb25zLmxlbmd0aCA+IDAsIGJlZm9yZSwgYWZ0ZXIgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVuZGVyU2NhZmZvbGRzKGlucHV0OiBDb21tYW5kSW5wdXQpIHtcbiAgYXdhaXQgZW5zdXJlU29uYW11KCk7XG4gIGNvbnN0IHsgcmVuZGVyVGVtcGxhdGUgfSA9IGF3YWl0IGltcG9ydChcIi4uL3N5bmNlci9jb2RlLWdlbmVyYXRvclwiKTtcbiAgY29uc3QgZW50aXRpZXMgPSBzdHJpbmdzKGlucHV0LCBcImVudGl0aWVzXCIpO1xuICBjb25zdCB0ZW1wbGF0ZXMgPSBzdHJpbmdzKGlucHV0LCBcInRlbXBsYXRlc1wiKTtcbiAgY29uc3QgcmVuZGVyZWQgPSBbXTtcbiAgZm9yIChjb25zdCBlbnRpdHlJZCBvZiBlbnRpdGllcykge1xuICAgIGZvciAoY29uc3QgdGVtcGxhdGUgb2YgdGVtcGxhdGVzKSB7XG4gICAgICBjb25zdCB0ZW1wbGF0ZUtleSA9IHpcbiAgICAgICAgLmVudW0oW1wibW9kZWxcIiwgXCJtb2RlbF90ZXN0XCIsIFwidmlld19saXN0XCIsIFwidmlld19mb3JtXCIsIFwidmlld19zZWFyY2hfaW5wdXRcIl0pXG4gICAgICAgIC5wYXJzZSh0ZW1wbGF0ZSk7XG4gICAgICBjb25zdCBmaWxlcyA9IGF3YWl0IHJlbmRlclRlbXBsYXRlKHRlbXBsYXRlS2V5LCB7IGVudGl0eUlkIH0pO1xuICAgICAgcmVuZGVyZWQucHVzaCh7IGVudGl0eUlkLCB0ZW1wbGF0ZTogdGVtcGxhdGVLZXksIGZpbGVzIH0pO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVuZGVyZWQ7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNjYWZmb2xkT3BlcmF0aW9uKG1ldGhvZDogc3RyaW5nLCBpbnB1dDogQ29tbWFuZElucHV0KTogUHJvbWlzZTxUb29saW5nUmVzdWx0PiB7XG4gIGNvbnN0IGRpcmVjdFRlbXBsYXRlID0gelxuICAgIC5lbnVtKFtcIm1vZGVsXCIsIFwibW9kZWxfdGVzdFwiLCBcInZpZXdfbGlzdFwiLCBcInZpZXdfZm9ybVwiXSlcbiAgICAuc2FmZVBhcnNlKG1ldGhvZCk7XG4gIGlmIChkaXJlY3RUZW1wbGF0ZS5zdWNjZXNzKSB7XG4gICAgYXdhaXQgZW5zdXJlU29uYW11KCk7XG4gICAgY29uc3QgeyBTb25hbXUgfSA9IGF3YWl0IGltcG9ydChcIi4uL2FwaS9zb25hbXVcIik7XG4gICAgY29uc3QgZW50aXR5SWQgPSByZXF1aXJlZFRleHQoaW5wdXQsIFwiZW50aXR5SWRcIik7XG4gICAgcmV0dXJuIGRpcmVjdFRlbXBsYXRlLmRhdGEgPT09IFwidmlld19saXN0XCJcbiAgICAgID8gU29uYW11LnN5bmNlci5nZW5lcmF0ZVRlbXBsYXRlKFwidmlld19saXN0XCIsIHsgZW50aXR5SWQsIGV4dHJhOiBpbnB1dC5leHRyYSB9KVxuICAgICAgOiBTb25hbXUuc3luY2VyLmdlbmVyYXRlVGVtcGxhdGUoZGlyZWN0VGVtcGxhdGUuZGF0YSwgeyBlbnRpdHlJZCB9KTtcbiAgfVxuICBjb25zdCByZW5kZXJlZCA9IGF3YWl0IHJlbmRlclNjYWZmb2xkcyhpbnB1dCk7XG4gIGNvbnN0IHsgYWNjZXNzIH0gPSBhd2FpdCBpbXBvcnQoXCJub2RlOmZzL3Byb21pc2VzXCIpO1xuICBjb25zdCBwYXRoID0gYXdhaXQgaW1wb3J0KFwibm9kZTpwYXRoXCIpO1xuICBjb25zdCB7IFNvbmFtdSB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vYXBpL3NvbmFtdVwiKTtcbiAgY29uc3QgaXRlbXMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICByZW5kZXJlZC5mbGF0TWFwKCh7IGVudGl0eUlkLCB0ZW1wbGF0ZSwgZmlsZXMgfSkgPT5cbiAgICAgIGZpbGVzLm1hcChhc3luYyAoZmlsZSkgPT4ge1xuICAgICAgICBjb25zdCB0YXJnZXQgPSBwYXRoLmRlZmF1bHQuam9pbihcbiAgICAgICAgICBTb25hbXUuYXBwUm9vdFBhdGgsXG4gICAgICAgICAgZmlsZS5wYXRoLnJlcGxhY2UoXCIvOnRhcmdldC9cIiwgXCIvd2ViL1wiKSxcbiAgICAgICAgKTtcbiAgICAgICAgbGV0IGV4aXN0cyA9IHRydWU7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgYWNjZXNzKHRhcmdldCk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIGV4aXN0cyA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IGVudGl0eUlkLCB0ZW1wbGF0ZSwgdGFyZ2V0LCBleGlzdHMsIGNvbnRlbnQ6IGZpbGUuY29kZSB9O1xuICAgICAgfSksXG4gICAgKSxcbiAgKTtcbiAgaWYgKG1ldGhvZCA9PT0gXCJzdGF0dXNcIikgcmV0dXJuIGl0ZW1zLm1hcCgoeyBjb250ZW50OiBfY29udGVudCwgLi4uaXRlbSB9KSA9PiBpdGVtKTtcbiAgaWYgKG1ldGhvZCA9PT0gXCJwcmV2aWV3XCIgfHwgKG1ldGhvZCA9PT0gXCJiYXRjaFwiICYmIGV4cGxpY2l0bHlEcnlSdW4oaW5wdXQpKSkgcmV0dXJuIGl0ZW1zO1xuXG4gIGNvbnN0IHJlc3VsdHMgPSBbXTtcbiAgZm9yIChjb25zdCBpdGVtIG9mIGl0ZW1zKSB7XG4gICAgY29uc3QgeyBjb250ZW50OiBfY29udGVudCwgLi4uc3VtbWFyeSB9ID0gaXRlbTtcbiAgICBpZiAoaXRlbS5leGlzdHMgJiYgaW5wdXQub3ZlcndyaXRlICE9PSB0cnVlKSB7XG4gICAgICByZXN1bHRzLnB1c2goeyAuLi5zdW1tYXJ5LCBzdGF0dXM6IFwic2tpcHBlZFwiIH0pO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGF3YWl0IFNvbmFtdS5zeW5jZXIuZ2VuZXJhdGVUZW1wbGF0ZShcbiAgICAgIGl0ZW0udGVtcGxhdGUsXG4gICAgICB7IGVudGl0eUlkOiBpdGVtLmVudGl0eUlkIH0sXG4gICAgICB7IG92ZXJ3cml0ZTogaW5wdXQub3ZlcndyaXRlID09PSB0cnVlIH0sXG4gICAgKTtcbiAgICByZXN1bHRzLnB1c2goeyAuLi5zdW1tYXJ5LCBzdGF0dXM6IFwid3JpdHRlblwiIH0pO1xuICB9XG4gIHJldHVybiB7IGl0ZW1zOiByZXN1bHRzIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG1pZ3JhdGlvbk9wZXJhdGlvbihtZXRob2Q6IHN0cmluZywgaW5wdXQ6IENvbW1hbmRJbnB1dCk6IFByb21pc2U8VG9vbGluZ1Jlc3VsdD4ge1xuICBsZXQgc2hhZG93VGFyZ2V0OiBFeHRyYWN0PE1pZ3JhdGlvblRhcmdldCwgXCJmaXh0dXJlXCIgfCBcInRlc3RcIj4gfCB1bmRlZmluZWQ7XG4gIGlmIChtZXRob2QgPT09IFwic2hhZG93XCIpIHtcbiAgICBjb25zdCByZXF1ZXN0ZWRUYXJnZXQgPSByZXF1aXJlZFRleHQoaW5wdXQsIFwidGFyZ2V0XCIpO1xuICAgIGFzc2VydE1pZ3JhdGlvblRhcmdldChyZXF1ZXN0ZWRUYXJnZXQpO1xuICAgIGFzc2VydFNoYWRvd01pZ3JhdGlvblRhcmdldChyZXF1ZXN0ZWRUYXJnZXQpO1xuICAgIHNoYWRvd1RhcmdldCA9IHJlcXVlc3RlZFRhcmdldDtcbiAgfVxuXG4gIGF3YWl0IGVuc3VyZVNvbmFtdSgpO1xuICBjb25zdCB7IE1pZ3JhdG9yIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi9taWdyYXRpb24vbWlncmF0b3JcIik7XG4gIGNvbnN0IG1pZ3JhdG9yID0gbmV3IE1pZ3JhdG9yKCk7XG4gIGlmIChtZXRob2QgPT09IFwic3RhdHVzXCIpIHJldHVybiBtaWdyYXRvci5nZXRTdGF0dXMoKTtcbiAgaWYgKG1ldGhvZCA9PT0gXCJnZW5lcmF0ZVwiKSB7XG4gICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgbWlncmF0b3IuZ2V0U3RhdHVzKCk7XG4gICAgaWYgKCFzdGF0dXMuY29ubnMuc29tZSgoY29ubmVjdGlvbikgPT4gY29ubmVjdGlvbi5zdGF0dXMgPT09IDApKSB7XG4gICAgICB0aHJvdyBPYmplY3QuYXNzaWduKG5ldyBFcnJvcihcIlBlbmRpbmcgbWlncmF0aW9ucyBtdXN0IGJlIGFwcGxpZWQgYmVmb3JlIGdlbmVyYXRpb24uXCIpLCB7XG4gICAgICAgIGNvZGU6IFwiTUlHUkFUSU9OX05PVF9SRUFEWVwiLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiB7IGNvdW50OiBhd2FpdCBtaWdyYXRvci5nZW5lcmF0ZVByZXBhcmVkQ29kZXMoKSB9O1xuICB9XG4gIGlmIChtZXRob2QgPT09IFwicnVuXCIpIHtcbiAgICBpZiAoIW11dGF0aW9uUmVxdWVzdGVkKGlucHV0KSkgcmV0dXJuIHsgZHJ5UnVuOiB0cnVlIH07XG4gICAgY29uc3QgeyBnZXRTb25hbXVFbnZpcm9ubWVudCB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vZW52XCIpO1xuICAgIGNvbnN0IGVudmlyb25tZW50ID0gZ2V0U29uYW11RW52aXJvbm1lbnQoKTtcbiAgICByZXR1cm4gbWlncmF0b3IuYXBwbHkoZW52aXJvbm1lbnQgPT09IFwidGVzdFwiID8gW1widGVzdFwiLCBcImZpeHR1cmVcIl0gOiBbZW52aXJvbm1lbnRdKTtcbiAgfVxuICBpZiAobWV0aG9kID09PSBcImNvbm5lY3Rpb25zXCIpIHJldHVybiBtaWdyYXRvci5nZXRDb25uZWN0aW9ucygpO1xuICBpZiAobWV0aG9kID09PSBcImFwcGx5XCIpIHtcbiAgICBjb25zdCByYXdUYXJnZXRzID0gc3RyaW5ncyhpbnB1dCwgXCJ0YXJnZXRzXCIpO1xuICAgIGlmIChyYXdUYXJnZXRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgT2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoXCJNaXNzaW5nIHRhcmdldHMuXCIpLCB7IGNvZGU6IFwiTUlTU0lOR19BUkdVTUVOVFwiLCBleGl0Q29kZTogMiB9KTtcbiAgICB9XG4gICAgY29uc3QgdGFyZ2V0cyA9IHJhd1RhcmdldHMubWFwKCh0YXJnZXQpID0+IHtcbiAgICAgIGFzc2VydE1pZ3JhdGlvblRhcmdldCh0YXJnZXQpO1xuICAgICAgcmV0dXJuIHRhcmdldDtcbiAgICB9KTtcbiAgICBpZiAobXV0YXRpb25SZXF1ZXN0ZWQoaW5wdXQpKSByZXR1cm4gbWlncmF0b3IuYXBwbHkodGFyZ2V0cyk7XG4gICAgcmV0dXJuIFByb21pc2UuYWxsKFxuICAgICAgdGFyZ2V0cy5tYXAoYXN5bmMgKHRhcmdldCkgPT4ge1xuICAgICAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCBtaWdyYXRvci5nZXRDb25uZWN0aW9uU3RhdHVzKHRhcmdldCk7XG4gICAgICAgIHJldHVybiBtaWdyYXRpb25QbGFuKHRhcmdldCwgc3RhdHVzLnBlbmRpbmcpO1xuICAgICAgfSksXG4gICAgKTtcbiAgfVxuICBpZiAobWV0aG9kID09PSBcInNoYWRvd1wiKSB7XG4gICAgaWYgKHNoYWRvd1RhcmdldCA9PT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgRXJyb3IoXCJTaGFkb3cgdGFyZ2V0IHZhbGlkYXRpb24gd2FzIHNraXBwZWQuXCIpO1xuICAgIGlmIChtdXRhdGlvblJlcXVlc3RlZChpbnB1dCkpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IG1pZ3JhdG9yLnJ1blNoYWRvd1Rlc3QoeyB0YXJnZXQ6IHNoYWRvd1RhcmdldCB9KTtcbiAgICAgIHJldHVybiBBcnJheS5pc0FycmF5KHJlc3VsdClcbiAgICAgICAgPyB7XG4gICAgICAgICAgICBvazogdHJ1ZSxcbiAgICAgICAgICAgIHRhcmdldDogc2hhZG93VGFyZ2V0LFxuICAgICAgICAgICAgbWlncmF0aW9uczogcmVzdWx0LmZsYXRNYXAoKHsgYXBwbGllZCB9KSA9PiBhcHBsaWVkKSxcbiAgICAgICAgICB9XG4gICAgICAgIDogcmVzdWx0O1xuICAgIH1cblxuICAgIGNvbnN0IHN0YXR1cyA9IGF3YWl0IG1pZ3JhdG9yLmdldENvbm5lY3Rpb25TdGF0dXMoc2hhZG93VGFyZ2V0KTtcbiAgICByZXR1cm4gbWlncmF0aW9uUGxhbihzaGFkb3dUYXJnZXQsIHN0YXR1cy5wZW5kaW5nKTtcbiAgfVxuXG4gIGNvbnN0IHRhcmdldCA9IHJlcXVpcmVkVGV4dChpbnB1dCwgXCJ0YXJnZXRcIik7XG4gIGFzc2VydE1pZ3JhdGlvblRhcmdldCh0YXJnZXQpO1xuICBpZiAobWV0aG9kID09PSBcImNvZGVcIikgcmV0dXJuIG1pZ3JhdG9yLmdldFByZXBhcmVkQ29kZXModGFyZ2V0KTtcblxuICBjb25zdCBhY3Rpb24gPVxuICAgIG1ldGhvZCA9PT0gXCJyb2xsYmFja1wiIHx8IHRleHQoaW5wdXQsIFwiYWN0aW9uXCIpID09PSBcInJvbGxiYWNrXCIgPyBcInJvbGxiYWNrXCIgOiBcImFwcGx5XCI7XG4gIGNvbnN0IG1pZ3JhdGlvbnMgPVxuICAgIGFjdGlvbiA9PT0gXCJhcHBseVwiXG4gICAgICA/IChhd2FpdCBtaWdyYXRvci5nZXRDb25uZWN0aW9uU3RhdHVzKHRhcmdldCkpLnBlbmRpbmdcbiAgICAgIDogKGF3YWl0IG1pZ3JhdG9yLmdldExhdGVzdEFwcGxpZWRCYXRjaCh0YXJnZXQpKS5maWxlcztcbiAgY29uc3QgcGxhbiA9IGF3YWl0IG1pZ3JhdGlvblBsYW4odGFyZ2V0LCBtaWdyYXRpb25zLCBhY3Rpb24pO1xuICBpZiAobWV0aG9kICE9PSBcInJvbGxiYWNrXCIgfHwgIW11dGF0aW9uUmVxdWVzdGVkKGlucHV0KSkgcmV0dXJuIHBsYW47XG4gIHJldHVybiBtaWdyYXRvci5yb2xsYmFjayhbdGFyZ2V0XSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZpeHR1cmVPcGVyYXRpb24obWV0aG9kOiBzdHJpbmcsIGlucHV0OiBDb21tYW5kSW5wdXQpOiBQcm9taXNlPFRvb2xpbmdSZXN1bHQ+IHtcbiAgYXdhaXQgZW5zdXJlU29uYW11KCk7XG4gIGNvbnN0IFtmaXh0dXJlQ29tbWFuZHMsIHsgRml4dHVyZU1hbmFnZXIgfSwgZml4dHVyZVNlcnZpY2UsIHsgU29uYW11IH1dID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgIGltcG9ydChcIi4uL2Jpbi9maXh0dXJlXCIpLFxuICAgIGltcG9ydChcIi4uL3Rlc3RpbmcvZml4dHVyZS1tYW5hZ2VyXCIpLFxuICAgIGltcG9ydChcIi4vZml4dHVyZS1zZXJ2aWNlXCIpLFxuICAgIGltcG9ydChcIi4uL2FwaS9zb25hbXVcIiksXG4gIF0pO1xuICBpZiAobWV0aG9kID09PSBcImluaXRcIikge1xuICAgIHJldHVybiBtdXRhdGlvblJlcXVlc3RlZChpbnB1dCkgPyBmaXh0dXJlQ29tbWFuZHMuZml4dHVyZUluaXRDb21tYW5kKCkgOiB7IGRyeVJ1bjogdHJ1ZSB9O1xuICB9XG4gIGlmIChtZXRob2QgPT09IFwiaW1wb3J0XCIpIHtcbiAgICBpZiAoIW11dGF0aW9uUmVxdWVzdGVkKGlucHV0KSkgcmV0dXJuIHsgZHJ5UnVuOiB0cnVlIH07XG4gICAgRml4dHVyZU1hbmFnZXIuaW5pdCgpO1xuICAgIGF3YWl0IEZpeHR1cmVNYW5hZ2VyLmltcG9ydEZpeHR1cmUoXG4gICAgICByZXF1aXJlZFRleHQoaW5wdXQsIFwiZW50aXR5SWRcIiksXG4gICAgICB6LmFycmF5KHoubnVtYmVyKCkpLnBhcnNlKGlucHV0LnJlY29yZElkcyksXG4gICAgKTtcbiAgICBhd2FpdCBGaXh0dXJlTWFuYWdlci5zeW5jKCk7XG4gICAgcmV0dXJuIHsgaW1wb3J0ZWQ6IHRydWUgfTtcbiAgfVxuICBpZiAobWV0aG9kID09PSBcInN5bmNcIikge1xuICAgIGlmICghbXV0YXRpb25SZXF1ZXN0ZWQoaW5wdXQpKSByZXR1cm4geyBkcnlSdW46IHRydWUgfTtcbiAgICBGaXh0dXJlTWFuYWdlci5pbml0KCk7XG4gICAgYXdhaXQgRml4dHVyZU1hbmFnZXIuc3luYygpO1xuICAgIHJldHVybiB7IHN5bmNlZDogdHJ1ZSB9O1xuICB9XG4gIGNvbnN0IGxlZ2FjeUNvbW1hbmQgPSB6LmVudW0oW1wiZ2VuXCIsIFwiZmV0Y2hcIiwgXCJleHBsb3JlXCJdKS5wYXJzZShtZXRob2QpO1xuICBjb25zdCBpc1RyYW5zZmVyID0gW1wiZW50aXR5SWRcIiwgXCJzb3VyY2VcIiwgXCJ0YXJnZXRcIiwgXCJmaWVsZFwiLCBcInZhbHVlc1wiLCBcInJlbGF0aW9uc1wiLCBcImRlcHRoXCJdLnNvbWUoXG4gICAgKGtleSkgPT4gaW5wdXRba2V5XSAhPT0gdW5kZWZpbmVkLFxuICApO1xuICBpZiAoIWlzVHJhbnNmZXIpIHtcbiAgICBjb25zdCBvcHRpb25zID0gZml4dHVyZVNlcnZpY2Uubm9ybWFsaXplTGVnYWN5Rml4dHVyZUNvbW1hbmRPcHRpb25zKGxlZ2FjeUNvbW1hbmQsIGlucHV0KTtcbiAgICBjb25zdCBzdHJhdGVneSA9IHpcbiAgICAgIC5lbnVtKFtcInNhbXBsZVwiLCBcImlkc1wiLCBcInF1ZXJ5XCIsIFwiZmlsZVwiLCBcInJlY2VudFwiLCBcInJhbmRvbVwiXSlcbiAgICAgIC5vcHRpb25hbCgpXG4gICAgICAucGFyc2Uob3B0aW9ucy5zdHJhdGVneSk7XG4gICAgY29uc3QgZml4dHVyZU9wdGlvbnMgPSB7IC4uLm9wdGlvbnMsIHN0cmF0ZWd5IH0gc2F0aXNmaWVzIEZpeHR1cmVDb21tYW5kT3B0aW9ucztcbiAgICBpZiAobGVnYWN5Q29tbWFuZCAhPT0gXCJleHBsb3JlXCIgJiYgIW11dGF0aW9uUmVxdWVzdGVkKGlucHV0KSkge1xuICAgICAgcmV0dXJuIHsgZHJ5UnVuOiB0cnVlLCByZXF1ZXN0OiBmaXh0dXJlT3B0aW9ucyB9O1xuICAgIH1cbiAgICBpZiAobGVnYWN5Q29tbWFuZCA9PT0gXCJnZW5cIikgcmV0dXJuIGZpeHR1cmVDb21tYW5kcy5maXh0dXJlR2VuQ29tbWFuZChmaXh0dXJlT3B0aW9ucyk7XG4gICAgaWYgKGxlZ2FjeUNvbW1hbmQgPT09IFwiZXhwbG9yZVwiKSByZXR1cm4gZml4dHVyZUNvbW1hbmRzLmZpeHR1cmVFeHBsb3JlQ29tbWFuZChmaXh0dXJlT3B0aW9ucyk7XG4gICAgcmV0dXJuIGZpeHR1cmVDb21tYW5kcy5maXh0dXJlRmV0Y2hDb21tYW5kKGZpeHR1cmVPcHRpb25zKTtcbiAgfVxuXG4gIGNvbnN0IGVudGl0eUlkID0gcmVxdWlyZWRUZXh0KGlucHV0LCBcImVudGl0eUlkXCIpO1xuICBjb25zdCBzb3VyY2UgPSByZXF1aXJlZFRleHQoaW5wdXQsIFwic291cmNlXCIpO1xuICBjb25zdCB0YXJnZXQgPSByZXF1aXJlZFRleHQoaW5wdXQsIFwidGFyZ2V0XCIpO1xuICBjb25zdCBmaWVsZCA9IHJlcXVpcmVkVGV4dChpbnB1dCwgXCJmaWVsZFwiKTtcbiAgY29uc3QgdmFsdWVzID0gc3RyaW5ncyhpbnB1dCwgXCJ2YWx1ZXNcIik7XG4gIGNvbnN0IHJlbGF0aW9ucyA9IHJlcXVpcmVkVGV4dChpbnB1dCwgXCJyZWxhdGlvbnNcIik7XG4gIC8vIENMSSDrrLjrspXsnbQgaW50ZWdlcih7IG1pbjogMCB9KeydtOuvgOuhnCDqtIDqs4Qg7Iic7ZqM66W8IOuBhOuKlCBkZXB0aCAw7J2EIO2XiOyaqe2VqeuLiOuLpC5cbiAgY29uc3QgZGVwdGggPSB6Lm51bWJlcigpLmludCgpLm5vbm5lZ2F0aXZlKCkuc2FmZVBhcnNlKGlucHV0LmRlcHRoKTtcbiAgaWYgKFxuICAgICFPYmplY3QuaGFzT3duKFNvbmFtdS5kYkNvbmZpZywgc291cmNlKSB8fFxuICAgICFPYmplY3QuaGFzT3duKFNvbmFtdS5kYkNvbmZpZywgdGFyZ2V0KSB8fFxuICAgIHZhbHVlcy5sZW5ndGggPT09IDAgfHxcbiAgICAhW1wiaW5jbHVkZVwiLCBcImV4Y2x1ZGVcIiwgXCJub25lXCJdLmluY2x1ZGVzKHJlbGF0aW9ucykgfHxcbiAgICAhZGVwdGguc3VjY2Vzc1xuICApIHtcbiAgICB0aHJvdyBPYmplY3QuYXNzaWduKG5ldyBFcnJvcihcIkludmFsaWQgZml4dHVyZSB0cmFuc2ZlciBzZWxlY3Rvci5cIiksIHtcbiAgICAgIGNvZGU6IFwiSU5WQUxJRF9GSVhUVVJFX1RSQU5TRkVSXCIsXG4gICAgICBleGl0Q29kZTogMixcbiAgICB9KTtcbiAgfVxuICAvLyBTQUZFVFk6IE9iamVjdC5oYXNPd24gY2hlY2tzIGFib3ZlIGVzdGFibGlzaCBib3RoIGtleXMgYXMgY29uZmlndXJlZCBEQiBwcmVzZXRzLlxuICBjb25zdCBzb3VyY2VLZXkgPSBzb3VyY2UgYXMga2V5b2YgdHlwZW9mIFNvbmFtdS5kYkNvbmZpZztcbiAgLy8gU0FGRVRZOiBPYmplY3QuaGFzT3duIGNoZWNrcyBhYm92ZSBlc3RhYmxpc2ggYm90aCBrZXlzIGFzIGNvbmZpZ3VyZWQgREIgcHJlc2V0cy5cbiAgY29uc3QgdGFyZ2V0S2V5ID0gdGFyZ2V0IGFzIGtleW9mIHR5cGVvZiBTb25hbXUuZGJDb25maWc7XG4gIGNvbnN0IHJlY29yZHMgPSAoXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICB2YWx1ZXMubWFwKCh2YWx1ZSkgPT5cbiAgICAgICAgRml4dHVyZU1hbmFnZXIuZ2V0Rml4dHVyZXMoXG4gICAgICAgICAgc291cmNlS2V5LFxuICAgICAgICAgIHRhcmdldEtleSxcbiAgICAgICAgICB7IGVudGl0eUlkLCBmaWVsZCwgdmFsdWUsIHNlYXJjaFR5cGU6IFwiZXF1YWxzXCIgfSxcbiAgICAgICAgICB7IGluY2x1ZGVSZWxhdGlvbnM6IHJlbGF0aW9ucyA9PT0gXCJpbmNsdWRlXCIsIG1heERlcHRoOiBkZXB0aC5kYXRhIH0sXG4gICAgICAgICksXG4gICAgICApLFxuICAgIClcbiAgKS5mbGF0KCk7XG4gIGlmIChleHBsaWNpdGx5RHJ5UnVuKGlucHV0KSkgcmV0dXJuIHsgZHJ5UnVuOiB0cnVlLCByZWNvcmRzIH07XG4gIGlmIChyZWNvcmRzLmxlbmd0aCA+IDApIGF3YWl0IEZpeHR1cmVNYW5hZ2VyLmluc2VydEZpeHR1cmVzKHRhcmdldEtleSwgcmVjb3Jkcyk7XG4gIHJldHVybiB7IHJlY29yZHMgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gYnVpbGRPcGVyYXRpb24obWV0aG9kOiBzdHJpbmcpOiBQcm9taXNlPFRvb2xpbmdSZXN1bHQ+IHtcbiAgY29uc3QgeyBidWlsZEFwaUNvbW1hbmQsIGJ1aWxkV2ViQ29tbWFuZCB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vYmluL2J1aWxkLWNvbmZpZ1wiKTtcbiAgaWYgKG1ldGhvZCA9PT0gXCJhcGlcIikgcmV0dXJuIGJ1aWxkQXBpQ29tbWFuZCgpO1xuICBpZiAobWV0aG9kID09PSBcIndlYlwiKSByZXR1cm4gYnVpbGRXZWJDb21tYW5kKCk7XG4gIGF3YWl0IGJ1aWxkQXBpQ29tbWFuZCgpO1xuICByZXR1cm4gYnVpbGRXZWJDb21tYW5kKHsgc2tpcElmTWlzc2luZzogdHJ1ZSB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gdGVzdE9wZXJhdGlvbihtZXRob2Q6IHN0cmluZywgaW5wdXQ6IENvbW1hbmRJbnB1dCk6IFByb21pc2U8VG9vbGluZ1Jlc3VsdD4ge1xuICBjb25zdCB7IGNyZWF0ZURlZmF1bHRUZXN0UnVuQ2xpZW50IH0gPSBhd2FpdCBpbXBvcnQoXCIuL3Rlc3QtcnVuLWNsaWVudFwiKTtcbiAgY29uc3QgY2xpZW50ID0gY3JlYXRlRGVmYXVsdFRlc3RSdW5DbGllbnQoKTtcbiAgaWYgKG1ldGhvZCA9PT0gXCJzdGF0dXNcIikgcmV0dXJuIGNsaWVudC5zdGF0dXMoKTtcbiAgY29uc3QgcmVxdWVzdCA9IHtcbiAgICBmaWxlczogei5hcnJheSh6LnN0cmluZygpKS5jYXRjaChbXSkucGFyc2UoaW5wdXQuZmlsZXMpLFxuICAgIHBhdHRlcm46IHouc3RyaW5nKCkub3B0aW9uYWwoKS5wYXJzZShpbnB1dC5wYXR0ZXJuKSxcbiAgICB0cmFjZXM6IGlucHV0LnRyYWNlcyA9PT0gdHJ1ZSxcbiAgfTtcbiAgcmV0dXJuIHsgcmVxdWVzdCwgcmVzdWx0OiBhd2FpdCBjbGllbnQucnVuKHJlcXVlc3QpIH07XG59XG5cbmNvbnN0IGJldHRlckF1dGhQbHVnaW5TY2hlbWEgPSB6LmVudW0oW1xuICBcIjJmYVwiLFxuICBcImFkbWluXCIsXG4gIFwiYW5vbnltb3VzXCIsXG4gIFwiYXBpLWtleVwiLFxuICBcImF1ZGl0LWxvZ1wiLFxuICBcImp3dFwiLFxuICBcIm9yZ2FuaXphdGlvblwiLFxuICBcInBhc3NrZXlcIixcbiAgXCJwaG9uZS1udW1iZXJcIixcbiAgXCJzc29cIixcbiAgXCJ1c2VybmFtZVwiLFxuXSk7XG5cbmFzeW5jIGZ1bmN0aW9uIGF1dGhPcGVyYXRpb24obWV0aG9kOiBzdHJpbmcsIGlucHV0OiBDb21tYW5kSW5wdXQpOiBQcm9taXNlPFRvb2xpbmdSZXN1bHQ+IHtcbiAgY29uc3QgeyBhZGRDb21wYW5pb25zVG9FbnRpdGllcywgZ2VuZXJhdGVCZXR0ZXJBdXRoRW50aXRpZXMgfSA9IGF3YWl0IGltcG9ydChcIi4uL2F1dGhcIik7XG4gIGlmIChtZXRob2QgPT09IFwiYWRkQ29tcGFuaW9uc1wiKSByZXR1cm4gYWRkQ29tcGFuaW9uc1RvRW50aXRpZXMoKTtcbiAgLy8gcGx1Z2luc+uKlCDshKDtg50g7Ji17IWY7J2066+A66GcIOyDneuete2VmOuptCBjb3JlIOyXlO2LsO2LsOunjCDsg53shLHtlanri4jri6QuXG4gIGNvbnN0IHBsdWdpbnMgPSB6LmFycmF5KGJldHRlckF1dGhQbHVnaW5TY2hlbWEpLnBhcnNlKFxuICAgIChvcHRpb25hbFRleHQoaW5wdXQsIFwicGx1Z2luc1wiKSA/PyBcIlwiKVxuICAgICAgLnNwbGl0KFwiLFwiKVxuICAgICAgLm1hcCgocGx1Z2luKSA9PiBwbHVnaW4udHJpbSgpKVxuICAgICAgLmZpbHRlcihCb29sZWFuKSxcbiAgKTtcbiAgcmV0dXJuIGdlbmVyYXRlQmV0dGVyQXV0aEVudGl0aWVzKHsgcGx1Z2lucyB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaTE4bk9wZXJhdGlvbihtZXRob2Q6IHN0cmluZywgaW5wdXQ6IENvbW1hbmRJbnB1dCk6IFByb21pc2U8VG9vbGluZ1Jlc3VsdD4ge1xuICBhd2FpdCBlbnN1cmVTb25hbXUoKTtcbiAgY29uc3QgeyBzb25hbXVEaWN0aW9uYXJ5IH0gPSBhd2FpdCBpbXBvcnQoXCIuLi9kaWN0L3NvbmFtdS1kaWN0aW9uYXJ5XCIpO1xuICBpZiAobWV0aG9kID09PSBcImxpc3RcIikge1xuICAgIGNvbnN0IGRpY3Rpb25hcnkgPSBhd2FpdCBzb25hbXVEaWN0aW9uYXJ5LmdldERpY3Rpb25hcnkoKTtcbiAgICBjb25zdCBsb2NhbGUgPSB0ZXh0KGlucHV0LCBcImxvY2FsZVwiKTtcbiAgICByZXR1cm4gbG9jYWxlID09PSB1bmRlZmluZWRcbiAgICAgID8gZGljdGlvbmFyeVxuICAgICAgOiB7XG4gICAgICAgICAgLi4uZGljdGlvbmFyeSxcbiAgICAgICAgICBsb2NhbGVzOiBbbG9jYWxlXSxcbiAgICAgICAgICByb3dzOiBkaWN0aW9uYXJ5LnJvd3MubWFwKChyb3cpID0+ICh7XG4gICAgICAgICAgICBrZXk6IHJvdy5rZXksXG4gICAgICAgICAgICBzb3VyY2U6IHJvdy5zb3VyY2UsXG4gICAgICAgICAgICBbbG9jYWxlXTogcm93W2xvY2FsZV0sXG4gICAgICAgICAgfSkpLFxuICAgICAgICB9O1xuICB9XG4gIGlmIChtZXRob2QgPT09IFwiY2hlY2tcIikge1xuICAgIGNvbnN0IGRpY3Rpb25hcnkgPSBhd2FpdCBzb25hbXVEaWN0aW9uYXJ5LmdldERpY3Rpb25hcnkoKTtcbiAgICByZXR1cm4gc29uYW11RGljdGlvbmFyeS5jaGVja1VzYWdlKGRpY3Rpb25hcnkucm93cy5tYXAoKHJvdykgPT4gcm93LmtleSkpO1xuICB9XG4gIGlmIChtZXRob2QgPT09IFwiZXhwb3J0XCIgfHwgbWV0aG9kID09PSBcImltcG9ydFwiKSB7XG4gICAgY29uc3QgZmlsZSA9IHJlcXVpcmVkVGV4dChpbnB1dCwgXCJmaWxlXCIpO1xuICAgIGlmIChleHBsaWNpdGx5RHJ5UnVuKGlucHV0KSkgcmV0dXJuIHsgb3BlcmF0aW9uOiBtZXRob2QsIGRyeVJ1bjogdHJ1ZSB9O1xuICAgIGNvbnN0IHsgcmVhZEZpbGUsIHdyaXRlRmlsZSB9ID0gYXdhaXQgaW1wb3J0KFwibm9kZTpmcy9wcm9taXNlc1wiKTtcbiAgICBjb25zdCBmb3JtYXQgPSB0ZXh0KGlucHV0LCBcImZvcm1hdFwiKSA9PT0gXCJqc29uXCIgPyBcImpzb25cIiA6IFwid29ya2Jvb2tcIjtcbiAgICBpZiAobWV0aG9kID09PSBcImV4cG9ydFwiICYmIGZvcm1hdCA9PT0gXCJ3b3JrYm9va1wiKSB7XG4gICAgICBjb25zdCB7IGJ1ZmZlciB9ID0gYXdhaXQgc29uYW11RGljdGlvbmFyeS5leHBvcnRUb0V4Y2VsKCk7XG4gICAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZSwgYnVmZmVyKTtcbiAgICAgIHJldHVybiB7IGV4cG9ydGVkOiAxIH07XG4gICAgfVxuICAgIGlmIChtZXRob2QgPT09IFwiaW1wb3J0XCIgJiYgZm9ybWF0ID09PSBcIndvcmtib29rXCIpIHtcbiAgICAgIHJldHVybiBzb25hbXVEaWN0aW9uYXJ5LmltcG9ydEZyb21FeGNlbChhd2FpdCByZWFkRmlsZShmaWxlKSk7XG4gICAgfVxuXG4gICAgaWYgKG1ldGhvZCA9PT0gXCJleHBvcnRcIikge1xuICAgICAgY29uc3QgZGljdGlvbmFyeSA9IGF3YWl0IHNvbmFtdURpY3Rpb25hcnkuZ2V0RGljdGlvbmFyeSgpO1xuICAgICAgY29uc3QgbG9jYWxlID0gdGV4dChpbnB1dCwgXCJsb2NhbGVcIik7XG4gICAgICBjb25zdCByb3dzID0gZGljdGlvbmFyeS5yb3dzLm1hcChcbiAgICAgICAgKHsga2V5LCBzb3VyY2U6IF9zb3VyY2UsIGlzRnVuY3Rpb246IF9pc0Z1bmN0aW9uLCAuLi52YWx1ZXMgfSkgPT4gKHtcbiAgICAgICAgICBrZXksXG4gICAgICAgICAgdmFsdWVzOlxuICAgICAgICAgICAgbG9jYWxlID09PSB1bmRlZmluZWRcbiAgICAgICAgICAgICAgPyB2YWx1ZXNcbiAgICAgICAgICAgICAgOiB7IFtsb2NhbGVdOiB6LnN0cmluZygpLmNhdGNoKFwiXCIpLnBhcnNlKHZhbHVlc1tsb2NhbGVdKSB9LFxuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgICBhd2FpdCB3cml0ZUZpbGUoZmlsZSwgSlNPTi5zdHJpbmdpZnkocm93cywgbnVsbCwgMikpO1xuICAgICAgcmV0dXJuIHsgZXhwb3J0ZWQ6IHJvd3MubGVuZ3RoIH07XG4gICAgfVxuXG4gICAgY29uc3QgZW50cmllcyA9IHBhcnNlSnNvbihcbiAgICAgIChhd2FpdCByZWFkRmlsZShmaWxlKSkudG9TdHJpbmcoXCJ1dGY4XCIpLFxuICAgICAgXCJJMThOX0lOVkFMSURfSlNPTlwiLFxuICAgICAgaTE4bkVudHJpZXNTY2hlbWEsXG4gICAgKTtcbiAgICBjb25zdCBjdXJyZW50ID0gYXdhaXQgc29uYW11RGljdGlvbmFyeS5nZXREaWN0aW9uYXJ5KCk7XG4gICAgY29uc3QgZXhpc3RpbmdLZXlzID0gbmV3IFNldChjdXJyZW50LnJvd3MubWFwKCh7IGtleSB9KSA9PiBrZXkpKTtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgIGlmIChleGlzdGluZ0tleXMuaGFzKGVudHJ5LmtleSkpIHtcbiAgICAgICAgYXdhaXQgc29uYW11RGljdGlvbmFyeS51cGRhdGVFbnRyeSh7XG4gICAgICAgICAgb2xkS2V5OiBlbnRyeS5rZXksXG4gICAgICAgICAgbmV3S2V5OiBlbnRyeS5rZXksXG4gICAgICAgICAgc291cmNlOiBcInByb2plY3RcIixcbiAgICAgICAgICB2YWx1ZXM6IGVudHJ5LnZhbHVlcyxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhd2FpdCBzb25hbXVEaWN0aW9uYXJ5LmNyZWF0ZUVudHJ5KGVudHJ5KTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgaW1wb3J0ZWQ6IGVudHJpZXMubGVuZ3RoIH07XG4gIH1cbiAgY29uc3Qga2V5ID0gcmVxdWlyZWRUZXh0KGlucHV0LCBcImtleVwiKTtcbiAgaWYgKG1ldGhvZCA9PT0gXCJjcmVhdGVcIikge1xuICAgIGlmIChleHBsaWNpdGx5RHJ5UnVuKGlucHV0KSkgcmV0dXJuIHsgb3BlcmF0aW9uOiBcImNyZWF0ZVwiLCBpbnB1dCwgZHJ5UnVuOiB0cnVlIH07XG4gICAgcmV0dXJuIHNvbmFtdURpY3Rpb25hcnkuY3JlYXRlRW50cnkoe1xuICAgICAga2V5LFxuICAgICAgdmFsdWVzOiBkaWN0aW9uYXJ5VmFsdWVzU2NoZW1hLnBhcnNlKGlucHV0LnZhbHVlcyksXG4gICAgfSk7XG4gIH1cbiAgaWYgKG1ldGhvZCA9PT0gXCJ1cGRhdGVcIikge1xuICAgIGlmIChleHBsaWNpdGx5RHJ5UnVuKGlucHV0KSkgcmV0dXJuIHsgb3BlcmF0aW9uOiBcInVwZGF0ZVwiLCBpbnB1dCwgZHJ5UnVuOiB0cnVlIH07XG4gICAgY29uc3QgZXhwbGljaXRTb3VyY2UgPSB0ZXh0KGlucHV0LCBcInNvdXJjZVwiKTtcbiAgICAvLyBzb3VyY2Xrpbwg7IOd65617ZWY66m0IOyCrOyghOyXkCDrk7HroZ3rkJwg6riw7KG0IHNvdXJjZeulvCDsnKDsp4DtlbQgZW50aXR5IO2VreuqqeydtCBwcm9qZWN0IG92ZXJyaWRl66GcIOuNruydtOyngCDslYrqsowg7ZWp64uI64ukLlxuICAgIGNvbnN0IHJlc29sdmVkU291cmNlID1cbiAgICAgIGV4cGxpY2l0U291cmNlID09PSB1bmRlZmluZWRcbiAgICAgICAgPyAoKGF3YWl0IHNvbmFtdURpY3Rpb25hcnkuZ2V0RGljdGlvbmFyeSgpKS5yb3dzLmZpbmQoKHJvdykgPT4gcm93LmtleSA9PT0ga2V5KT8uc291cmNlID8/XG4gICAgICAgICAgXCJwcm9qZWN0XCIpXG4gICAgICAgIDogZXhwbGljaXRTb3VyY2U7XG4gICAgcmV0dXJuIHNvbmFtdURpY3Rpb25hcnkudXBkYXRlRW50cnkoe1xuICAgICAgb2xkS2V5OiBrZXksXG4gICAgICBuZXdLZXk6IHRleHQoaW5wdXQsIFwibmV3S2V5XCIpID8/IGtleSxcbiAgICAgIHNvdXJjZTogZGljdGlvbmFyeVNvdXJjZVNjaGVtYS5wYXJzZShyZXNvbHZlZFNvdXJjZSksXG4gICAgICB2YWx1ZXM6IGRpY3Rpb25hcnlWYWx1ZXNTY2hlbWEucGFyc2UoaW5wdXQudmFsdWVzKSxcbiAgICB9KTtcbiAgfVxuICBpZiAoIW11dGF0aW9uUmVxdWVzdGVkKGlucHV0KSkgcmV0dXJuIHsga2V5LCBvcGVyYXRpb246IFwicmVtb3ZlXCIsIGRyeVJ1bjogdHJ1ZSB9O1xuICByZXR1cm4gc29uYW11RGljdGlvbmFyeS5kZWxldGVFbnRyeShrZXkpO1xufVxuXG5hc3luYyBmdW5jdGlvbiB0YXNrT3BlcmF0aW9uKG1ldGhvZDogc3RyaW5nLCBpbnB1dDogQ29tbWFuZElucHV0KTogUHJvbWlzZTxUb29saW5nUmVzdWx0PiB7XG4gIGF3YWl0IGVuc3VyZVNvbmFtdSgpO1xuICBjb25zdCB7IFNvbmFtdSB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vYXBpL3NvbmFtdVwiKTtcbiAgY29uc3Qgd29ya2Zsb3dzID0gU29uYW11LndvcmtmbG93cztcbiAgY29uc3QgYmFja2VuZCA9IHdvcmtmbG93cy5iYWNrZW5kO1xuICBpZiAobWV0aG9kID09PSBcImRlZmluaXRpb25zXCIpIHJldHVybiB7IGRlZmluaXRpb25zOiB3b3JrZmxvd3Mud29ya2Zsb3dEZWZpbml0aW9ucyB9O1xuICBpZiAobWV0aG9kID09PSBcInJ1bnNcIikgcmV0dXJuIGJhY2tlbmQubGlzdFdvcmtmbG93UnVucyh7IGxpbWl0OiA1MCB9KTtcbiAgY29uc3Qgd29ya2Zsb3dSdW5JZCA9IHJlcXVpcmVkVGV4dChpbnB1dCwgXCJydW5JZFwiKTtcbiAgaWYgKG1ldGhvZCA9PT0gXCJzaG93XCIpIHJldHVybiBiYWNrZW5kLmdldFdvcmtmbG93UnVuKHsgd29ya2Zsb3dSdW5JZCB9KTtcbiAgaWYgKG1ldGhvZCA9PT0gXCJ3YXRjaFwiKSB7XG4gICAgY29uc3QgeyBpc0RlZXBTdHJpY3RFcXVhbCB9ID0gYXdhaXQgaW1wb3J0KFwibm9kZTp1dGlsXCIpO1xuICAgIHJldHVybiAoYXN5bmMgZnVuY3Rpb24qIHdhdGNoKCkge1xuICAgICAgbGV0IHByZXZpb3VzOiBvYmplY3QgfCB1bmRlZmluZWQ7XG4gICAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICBjb25zdCBzbmFwc2hvdCA9IGF3YWl0IGJhY2tlbmQuZ2V0V29ya2Zsb3dSdW4oeyB3b3JrZmxvd1J1bklkIH0pO1xuICAgICAgICBpZiAoc25hcHNob3QgPT09IG51bGwpIHtcbiAgICAgICAgICB0aHJvdyBPYmplY3QuYXNzaWduKG5ldyBFcnJvcihgV29ya2Zsb3cgcnVuIG5vdCBmb3VuZDogJHt3b3JrZmxvd1J1bklkfWApLCB7XG4gICAgICAgICAgICBjb2RlOiBcIlRBU0tfUlVOX05PVF9GT1VORFwiLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHJhd1N0YXRlID0gc25hcHNob3Quc3RhdHVzID09PSBcInN1Y2NlZWRlZFwiID8gXCJjb21wbGV0ZWRcIiA6IHNuYXBzaG90LnN0YXR1cztcbiAgICAgICAgY29uc3Qgc3RhdGUgPSByYXdTdGF0ZSA9PT0gXCJjYW5jZWxlZFwiID8gXCJjYW5jZWxsZWRcIiA6IHJhd1N0YXRlO1xuICAgICAgICBjb25zdCBjdXJyZW50ID0geyAuLi5zbmFwc2hvdCwgc3RhdGUgfTtcbiAgICAgICAgaWYgKCFpc0RlZXBTdHJpY3RFcXVhbChjdXJyZW50LCBwcmV2aW91cykpIHtcbiAgICAgICAgICBwcmV2aW91cyA9IHN0cnVjdHVyZWRDbG9uZShjdXJyZW50KTtcbiAgICAgICAgICB5aWVsZCBjdXJyZW50O1xuICAgICAgICB9XG4gICAgICAgIGlmIChbXCJjb21wbGV0ZWRcIiwgXCJmYWlsZWRcIiwgXCJjYW5jZWxsZWRcIl0uaW5jbHVkZXMoc3RhdGUpKSByZXR1cm47XG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDFfMDAwKSk7XG4gICAgICB9XG4gICAgfSkoKTtcbiAgfVxuICBpZiAobWV0aG9kID09PSBcInN0ZXBzXCIpIHJldHVybiBiYWNrZW5kLmxpc3RTdGVwQXR0ZW1wdHMoeyB3b3JrZmxvd1J1bklkLCBsaW1pdDogMTAwIH0pO1xuICBpZiAoIW11dGF0aW9uUmVxdWVzdGVkKGlucHV0KSkgcmV0dXJuIHsgb3BlcmF0aW9uOiBtZXRob2QsIHdvcmtmbG93UnVuSWQsIGRyeVJ1bjogdHJ1ZSB9O1xuICBpZiAobWV0aG9kID09PSBcInBhdXNlXCIpIHJldHVybiBiYWNrZW5kLnBhdXNlV29ya2Zsb3dSdW4oeyB3b3JrZmxvd1J1bklkIH0pO1xuICBpZiAobWV0aG9kID09PSBcInJlc3VtZVwiKSByZXR1cm4gYmFja2VuZC5yZXN1bWVXb3JrZmxvd1J1bih7IHdvcmtmbG93UnVuSWQgfSk7XG4gIHJldHVybiBiYWNrZW5kLmNhbmNlbFdvcmtmbG93UnVuKHsgd29ya2Zsb3dSdW5JZCB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gY2RkUm9vdFBhdGgoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgY29uc3QgW3sgU29uYW11IH0sIHBhdGhdID0gYXdhaXQgUHJvbWlzZS5hbGwoW2ltcG9ydChcIi4uL2FwaS9zb25hbXVcIiksIGltcG9ydChcIm5vZGU6cGF0aFwiKV0pO1xuICByZXR1cm4gcGF0aC5qb2luKFNvbmFtdS5hcHBSb290UGF0aCwgXCJjb250cmFjdFwiKTtcbn1cblxuY29uc3QgcHJhY3RpY2VTZXF1ZW5jZVBhdHRlcm4gPSAvXnAoWzAtOV0rKS0vO1xuXG4vLyDsnbTrpoTsnYAg7YyM7J2866qF6rO8IOyKpO2FgSDrs7jrrLjsnZgg66y47J6Q7Je0IOumrO2EsOuftOyXkCDqt7jrjIDroZwg65Ok7Ja06rCA66+A66GcLFxuLy8g6rK966GcIOq1rOu2hOyekC/sg4HsnIQg6rK966GcIOywuOyhsC/rlLDsmLTtkZwv7Jet7Iqs656Y7Iuc66W8IOybkOyynCDssKjri6jtlZjripQg66y47J6Q66eMIO2XiOyaqe2VqeuLiOuLpC5cbmNvbnN0IHByYWN0aWNlTmFtZVBhdHRlcm4gPSAvXltBLVphLXowLTldW0EtWmEtejAtOS5fLV0qJC87XG5cbmZ1bmN0aW9uIGludmFsaWRQcmFjdGljZU5hbWUobmFtZTogc3RyaW5nKTogRXJyb3Ige1xuICByZXR1cm4gT2JqZWN0LmFzc2lnbihcbiAgICBuZXcgRXJyb3IoXG4gICAgICBgSW52YWxpZCBwcmFjdGljZSBuYW1lOiAke25hbWV9LiBVc2UgbGV0dGVycywgZGlnaXRzLCBcIi5cIiwgXCItXCIsIGFuZCBcIl9cIiBvbmx5LCBzdGFydGluZyB3aXRoIGEgbGV0dGVyIG9yIGRpZ2l0LmAsXG4gICAgKSxcbiAgICB7IGNvZGU6IFwiSU5WQUxJRF9QUkFDVElDRV9OQU1FXCIsIGV4aXRDb2RlOiAyIH0sXG4gICk7XG59XG5cbmZ1bmN0aW9uIGludmFsaWRQcmFjdGljZURpcmVjdG9yeShkaXJlY3Rvcnk6IHN0cmluZyk6IEVycm9yIHtcbiAgcmV0dXJuIE9iamVjdC5hc3NpZ24obmV3IEVycm9yKGBQcmFjdGljZSBkaXJlY3RvcnkgZXNjYXBlcyB0aGUgQVBJIHJvb3Q6ICR7ZGlyZWN0b3J5fWApLCB7XG4gICAgY29kZTogXCJJTlZBTElEX1BSQUNUSUNFX1BBVEhcIixcbiAgICBleGl0Q29kZTogMixcbiAgfSk7XG59XG5cbi8qKlxuICogYHNyYy9wcmFjdGljZXNgIOyVhOuemOyXkCDri6TsnYwg7Iuc7YCA7IqkIOuyiO2YuOulvCDqsIDsp4QgcHJhY3RpY2Ug7Iqk7YWBIO2MjOydvOydhCDrp4zrk63ri4jri6QuXG4gKlxuICog6rWsIENMSShgc3R1YiBwcmFjdGljZWAp7J2YIO2MjOydvOuqhSDqt5zsuZnqs7wg7Iqk7YWBIOuzuOusuOydhCDqt7jrjIDroZwg7Jyg7KeA7ZWp64uI64ukLlxuICovXG5hc3luYyBmdW5jdGlvbiBzdHViUHJhY3RpY2VPcGVyYXRpb24oaW5wdXQ6IENvbW1hbmRJbnB1dCk6IFByb21pc2U8VG9vbGluZ1Jlc3VsdD4ge1xuICBjb25zdCBuYW1lID0gcmVxdWlyZWRUZXh0KGlucHV0LCBcIm5hbWVcIik7XG4gIGlmICghcHJhY3RpY2VOYW1lUGF0dGVybi50ZXN0KG5hbWUpKSB0aHJvdyBpbnZhbGlkUHJhY3RpY2VOYW1lKG5hbWUpO1xuICBhd2FpdCBlbnN1cmVTb25hbXUoKTtcbiAgY29uc3QgW3sgU29uYW11IH0sIHsgY29uc3RhbnRzIH0sIHsgbWtkaXIsIG9wZW4sIHJlYWRkaXIsIHJlYWxwYXRoIH0sIHBhdGhdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgIGltcG9ydChcIi4uL2FwaS9zb25hbXVcIiksXG4gICAgaW1wb3J0KFwibm9kZTpmc1wiKSxcbiAgICBpbXBvcnQoXCJub2RlOmZzL3Byb21pc2VzXCIpLFxuICAgIGltcG9ydChcIm5vZGU6cGF0aFwiKSxcbiAgXSk7XG4gIGNvbnN0IHByYWN0aWNlRGlyZWN0b3J5ID0gcGF0aC5kZWZhdWx0LmpvaW4oU29uYW11LmFwaVJvb3RQYXRoLCBcInNyY1wiLCBcInByYWN0aWNlc1wiKTtcbiAgYXdhaXQgbWtkaXIocHJhY3RpY2VEaXJlY3RvcnksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAvLyBjZGQtc2VydmljZeyZgCDqsJnsnbQg7Iuk7KCcIOqyveuhnOq5jOyngCDtmZXsnbjtlbQsIHN5bWxpbmvroZwg7Jew6rKw65CcIHByYWN0aWNlcyDrlJTroInthLDrpqzqsIBcbiAgLy8gYXBpIHJvb3Qg67CW7J2EIOqwgOumrO2CpOuKlCDqsr3smrDrpbwg7LCo64uo7ZWp64uI64ukLlxuICBjb25zdCBbY2Fub25pY2FsQXBpUm9vdCwgY2Fub25pY2FsRGlyZWN0b3J5XSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICByZWFscGF0aChTb25hbXUuYXBpUm9vdFBhdGgpLFxuICAgIHJlYWxwYXRoKHByYWN0aWNlRGlyZWN0b3J5KSxcbiAgXSk7XG4gIGNvbnN0IGRpcmVjdG9yeVJlbGF0aXZlID0gcGF0aC5kZWZhdWx0LnJlbGF0aXZlKGNhbm9uaWNhbEFwaVJvb3QsIGNhbm9uaWNhbERpcmVjdG9yeSk7XG4gIGlmIChkaXJlY3RvcnlSZWxhdGl2ZS5zdGFydHNXaXRoKFwiLi5cIikgfHwgcGF0aC5kZWZhdWx0LmlzQWJzb2x1dGUoZGlyZWN0b3J5UmVsYXRpdmUpKSB7XG4gICAgdGhyb3cgaW52YWxpZFByYWN0aWNlRGlyZWN0b3J5KHByYWN0aWNlRGlyZWN0b3J5KTtcbiAgfVxuICBjb25zdCBmaWxlTmFtZXMgPSBhd2FpdCByZWFkZGlyKHByYWN0aWNlRGlyZWN0b3J5KTtcbiAgY29uc3QgbWF4U2VxdWVuY2UgPSBmaWxlTmFtZXNcbiAgICAuZmlsdGVyKChmaWxlTmFtZSkgPT4gZmlsZU5hbWUuc3RhcnRzV2l0aChcInBcIikgJiYgZmlsZU5hbWUuZW5kc1dpdGgoXCIudHNcIikpXG4gICAgLnJlZHVjZSgobGFyZ2VzdCwgZmlsZU5hbWUpID0+IHtcbiAgICAgIGNvbnN0IG1hdGNoZWQgPSBwcmFjdGljZVNlcXVlbmNlUGF0dGVybi5leGVjKGZpbGVOYW1lKTtcbiAgICAgIHJldHVybiBtYXRjaGVkID09PSBudWxsID8gbGFyZ2VzdCA6IE1hdGgubWF4KGxhcmdlc3QsIE51bWJlci5wYXJzZUludChtYXRjaGVkWzFdLCAxMCkpO1xuICAgIH0sIDApO1xuXG4gIGNvbnN0IGZpbGVOYW1lID0gYHAke21heFNlcXVlbmNlICsgMX0tJHtuYW1lfS50c2A7XG4gIC8vIOydtOumhCDtjKjthLTsnbQg6rK966GcIOq1rOu2hOyekOulvCDssKjri6jtlZjrr4DroZwg7YyM7J2866qF7J2AIO2VreyDgSDsnbQg65SU66CJ7YSw66as7J2YIOyngeqzhCDsnpDsi53snoXri4jri6QuXG4gIC8vIOqyveuhnOuKlCDshKTsoJXrkJwg6rCSIOq3uOuMgOuhnCDrj4zroKTso7zqs6AsIO2DiOy2nCDsl6zrtoDripQg7JyE7J2YIGNhbm9uaWNhbCDqsoDsgqzroZwg7YyQ64uo7ZWp64uI64ukLlxuICBjb25zdCBmaWxlUGF0aCA9IHBhdGguZGVmYXVsdC5yZXNvbHZlKHByYWN0aWNlRGlyZWN0b3J5LCBmaWxlTmFtZSk7XG4gIGNvbnN0IHN0dWJDb2RlID0gW1xuICAgIGBpbXBvcnQgeyBTb25hbXUgfSBmcm9tIFwic29uYW11XCI7YCxcbiAgICBcIlwiLFxuICAgIGBjb25zb2xlLmNsZWFyKCk7YCxcbiAgICBgY29uc29sZS5sb2coXCIke2ZpbGVOYW1lfVwiKTtgLFxuICAgIFwiXCIsXG4gICAgYFNvbmFtdS5ydW5TY3JpcHQoYXN5bmMgKCkgPT4ge2AsXG4gICAgYCAvLyBUT0RPYCxcbiAgICBgfSk7YCxcbiAgICBcIlwiLFxuICBdLmpvaW4oXCJcXG5cIik7XG4gIGxldCBoYW5kbGU7XG4gIHRyeSB7XG4gICAgLy8g6riw7KG0IO2MjOydvOydhCB0cnVuY2F0Ze2VmOyngCDslYrrj4TroZ0g67Cw7YOAIOyDneyEse2VmOqzoCwg7LWc7KKFIOqyveuhnOydmCBzeW1saW5r64qUIOuUsOudvOqwgOyngCDslYrsirXri4jri6QuXG4gICAgaGFuZGxlID0gYXdhaXQgb3BlbihcbiAgICAgIGZpbGVQYXRoLFxuICAgICAgY29uc3RhbnRzLk9fV1JPTkxZIHwgY29uc3RhbnRzLk9fQ1JFQVQgfCBjb25zdGFudHMuT19FWENMIHwgY29uc3RhbnRzLk9fTk9GT0xMT1csXG4gICAgICAwbzY2NixcbiAgICApO1xuICAgIGF3YWl0IGhhbmRsZS53cml0ZUZpbGUoc3R1YkNvZGUsIFwidXRmOFwiKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAvLyBTQUZFVFk6IG5vZGU6ZnMgb3BlbiDsi6TtjKjsnZggY29kZeunjCDsnb3slrQg6riw7KG0IO2MjOydvC9zeW1saW5rIOy2qeuPjOydhCDsoJXqt5ztmZTtlanri4jri6QuXG4gICAgY29uc3QgZXJyb3JDb2RlID0gKGVycm9yIGFzIE5vZGVKUy5FcnJub0V4Y2VwdGlvbikuY29kZTtcbiAgICBpZiAoZXJyb3JDb2RlID09PSBcIkVFWElTVFwiIHx8IGVycm9yQ29kZSA9PT0gXCJFTE9PUFwiKSB7XG4gICAgICB0aHJvdyBPYmplY3QuYXNzaWduKG5ldyBFcnJvcihgUHJhY3RpY2UgZmlsZSBhbHJlYWR5IGV4aXN0czogJHtmaWxlUGF0aH1gKSwge1xuICAgICAgICBjb2RlOiBcIlBSQUNUSUNFX0ZJTEVfRVhJU1RTXCIsXG4gICAgICAgIGV4aXRDb2RlOiAyLFxuICAgICAgICBjYXVzZTogZXJyb3IsXG4gICAgICB9KTtcbiAgICB9XG4gICAgdGhyb3cgZXJyb3I7XG4gIH0gZmluYWxseSB7XG4gICAgYXdhaXQgaGFuZGxlPy5jbG9zZSgpO1xuICB9XG4gIC8vIOyXkOuUlO2EsCDsl7TquLAv7YG066a967O065OcIOuzteyCrCDqsJnsnYAg64yA7ZmU7ZiVIOu2gOyImO2aqOqzvOuKlCDruYTrjIDtmZTtmJUg7Iuk7ZaJ7J2EIOq5qOucqOumrOuvgOuhnCDtmLjstpzsnpDsl5Dqsowg66eh6rmB64uI64ukLlxuICByZXR1cm4geyBmaWxlTmFtZSwgcGF0aDogZmlsZVBhdGggfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVhZENkZFRyZWUoZGlyZWN0b3J5OiBzdHJpbmcsIHJvb3Q6IHN0cmluZyk6IFByb21pc2U8b2JqZWN0W10+IHtcbiAgY29uc3QgW3sgcmVhZGRpciB9LCBwYXRoXSA9IGF3YWl0IFByb21pc2UuYWxsKFtpbXBvcnQoXCJub2RlOmZzL3Byb21pc2VzXCIpLCBpbXBvcnQoXCJub2RlOnBhdGhcIildKTtcbiAgY29uc3QgZW50cmllcyA9IGF3YWl0IHJlYWRkaXIoZGlyZWN0b3J5LCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSk7XG4gIGNvbnN0IG5vZGVzID0gW107XG4gIGZvciAoY29uc3QgZW50cnkgb2YgZW50cmllcykge1xuICAgIGlmIChlbnRyeS5uYW1lID09PSBcInJ1bGVzXCIpIGNvbnRpbnVlO1xuICAgIGNvbnN0IGFic29sdXRlUGF0aCA9IHBhdGguam9pbihkaXJlY3RvcnksIGVudHJ5Lm5hbWUpO1xuICAgIGNvbnN0IHJlbGF0aXZlUGF0aCA9IHBhdGgucmVsYXRpdmUocm9vdCwgYWJzb2x1dGVQYXRoKTtcbiAgICBpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgY29uc3QgY2hpbGRyZW4gPSBhd2FpdCByZWFkQ2RkVHJlZShhYnNvbHV0ZVBhdGgsIHJvb3QpO1xuICAgICAgaWYgKGNoaWxkcmVuLmxlbmd0aCA+IDApIHtcbiAgICAgICAgbm9kZXMucHVzaCh7IG5hbWU6IGVudHJ5Lm5hbWUsIHBhdGg6IHJlbGF0aXZlUGF0aCwgdHlwZTogXCJkaXJlY3RvcnlcIiwgY2hpbGRyZW4gfSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChlbnRyeS5pc0ZpbGUoKSAmJiBlbnRyeS5uYW1lLmVuZHNXaXRoKFwiLmNvbnRyYWN0Lm1kXCIpKSB7XG4gICAgICBub2Rlcy5wdXNoKHsgbmFtZTogZW50cnkubmFtZSwgcGF0aDogcmVsYXRpdmVQYXRoLCB0eXBlOiBcImZpbGVcIiwgZmlsZVR5cGU6IFwiY29udHJhY3RcIiB9KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG5vZGVzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBjZGRPcGVyYXRpb24obWV0aG9kOiBzdHJpbmcsIGlucHV0OiBDb21tYW5kSW5wdXQpOiBQcm9taXNlPFRvb2xpbmdSZXN1bHQ+IHtcbiAgYXdhaXQgZW5zdXJlU29uYW11KCk7XG4gIGNvbnN0IFt7IGFjY2VzcyB9LCB7IGNyZWF0ZURlZmF1bHRDZGRUb29saW5nQWRhcHRlciB9XSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICBpbXBvcnQoXCJub2RlOmZzL3Byb21pc2VzXCIpLFxuICAgIGltcG9ydChcIi4vY2RkLXNlcnZpY2VcIiksXG4gIF0pO1xuICBjb25zdCBhZGFwdGVyID0gY3JlYXRlRGVmYXVsdENkZFRvb2xpbmdBZGFwdGVyKHsgY29udHJhY3RSb290OiBhd2FpdCBjZGRSb290UGF0aCgpIH0pO1xuICBpZiAobWV0aG9kID09PSBcInRyZWVcIikge1xuICAgIGNvbnN0IHJvb3QgPSBhd2FpdCBjZGRSb290UGF0aCgpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBhY2Nlc3Mocm9vdCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4geyBleGlzdHM6IGZhbHNlLCB0cmVlOiBbXSB9O1xuICAgIH1cbiAgICByZXR1cm4geyBleGlzdHM6IHRydWUsIHRyZWU6IGF3YWl0IHJlYWRDZGRUcmVlKHJvb3QsIHJvb3QpIH07XG4gIH1cbiAgaWYgKG1ldGhvZCA9PT0gXCJyZWFkXCIpIHtcbiAgICBjb25zdCByZWxhdGl2ZVBhdGggPSByZXF1aXJlZFRleHQoaW5wdXQsIFwicGF0aFwiKTtcbiAgICByZXR1cm4gYWRhcHRlci5yZWFkKHsgcGF0aDogcmVsYXRpdmVQYXRoIH0pO1xuICB9XG4gIGlmIChtZXRob2QgPT09IFwicnVsZXNcIikgcmV0dXJuIGFkYXB0ZXIucnVsZXMoKTtcbiAgaWYgKG1ldGhvZCA9PT0gXCJzaG93UnVsZVwiKSB7XG4gICAgY29uc3QgcnVsZUlkID0gcmVxdWlyZWRUZXh0KGlucHV0LCBcInJ1bGVJZFwiKTtcbiAgICByZXR1cm4gYWRhcHRlci5zaG93UnVsZSh7IHJ1bGVJZCB9KTtcbiAgfVxuICBpZiAobWV0aG9kID09PSBcImFkZFJ1bGVcIikge1xuICAgIGNvbnN0IHJ1bGVLZXkgPSByZXF1aXJlZFRleHQoaW5wdXQsIFwicnVsZUtleVwiKTtcbiAgICBjb25zdCBpZCA9IHJlcXVpcmVkVGV4dChpbnB1dCwgXCJpZFwiKTtcbiAgICBjb25zdCB3aGVuID0gcmVxdWlyZWRUZXh0KGlucHV0LCBcIndoZW5cIik7XG4gICAgY29uc3QgcnVsZVRleHQgPSB0ZXh0KGlucHV0LCBcImluc3RydWN0aW9uXCIpID8/IHJlcXVpcmVkVGV4dChpbnB1dCwgXCJ0ZXh0XCIpO1xuICAgIHJldHVybiBhZGFwdGVyLmFkZFJ1bGUoe1xuICAgICAgcnVsZUtleSxcbiAgICAgIGlkLFxuICAgICAgd2hlbixcbiAgICAgIHRleHQ6IHJ1bGVUZXh0LFxuICAgICAgZXhhbXBsZXM6IHN0cmluZ3MoaW5wdXQsIFwiZXhhbXBsZXNcIiksXG4gICAgICBkcnlSdW46IGV4cGxpY2l0bHlEcnlSdW4oaW5wdXQpLFxuICAgIH0pO1xuICB9XG4gIGlmIChleHBsaWNpdGx5RHJ5UnVuKGlucHV0KSkge1xuICAgIHJldHVybiB7IG9wZXJhdGlvbjogXCJhZGRBY2NlcHRhbmNlQ3JpdGVyaW9uXCIsIGlucHV0LCBkcnlSdW46IHRydWUgfTtcbiAgfVxuICBjb25zdCBkb2N1bWVudCA9IHJlcXVpcmVkVGV4dChpbnB1dCwgXCJkb2N1bWVudFwiKTtcbiAgY29uc3QgY3JpdGVyaW9uID0gcmVxdWlyZWRUZXh0KGlucHV0LCBcInRleHRcIik7XG4gIHJldHVybiBhZGFwdGVyLmFkZEFjY2VwdGFuY2VDcml0ZXJpb24oeyBkb2N1bWVudCwgdGV4dDogY3JpdGVyaW9uLCBkcnlSdW46IGZhbHNlIH0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiBpbnZva2VEZWZhdWx0KFxuICBncm91cDogc3RyaW5nLFxuICBtZXRob2Q6IHN0cmluZyxcbiAgaW5wdXQ6IENvbW1hbmRJbnB1dCxcbik6IFByb21pc2U8VG9vbGluZ1Jlc3VsdD4ge1xuICBpZiAoZ3JvdXAgPT09IFwiY29yZVwiKSByZXR1cm4gc3luY09wZXJhdGlvbihpbnB1dCk7XG4gIGlmIChncm91cCA9PT0gXCJlbnRpdHlcIikgcmV0dXJuIGVudGl0eU9wZXJhdGlvbihtZXRob2QsIGlucHV0KTtcbiAgaWYgKGdyb3VwID09PSBcInNjYWZmb2xkXCIpIHJldHVybiBzY2FmZm9sZE9wZXJhdGlvbihtZXRob2QsIGlucHV0KTtcbiAgaWYgKGdyb3VwID09PSBcIm1pZ3JhdGlvblwiKSByZXR1cm4gbWlncmF0aW9uT3BlcmF0aW9uKG1ldGhvZCwgaW5wdXQpO1xuICBpZiAoZ3JvdXAgPT09IFwiZml4dHVyZVwiKSByZXR1cm4gZml4dHVyZU9wZXJhdGlvbihtZXRob2QsIGlucHV0KTtcbiAgaWYgKGdyb3VwID09PSBcImJ1aWxkXCIpIHJldHVybiBidWlsZE9wZXJhdGlvbihtZXRob2QpO1xuICBpZiAoZ3JvdXAgPT09IFwidGVzdFwiKSByZXR1cm4gdGVzdE9wZXJhdGlvbihtZXRob2QsIGlucHV0KTtcbiAgaWYgKGdyb3VwID09PSBcImF1dGhcIikgcmV0dXJuIGF1dGhPcGVyYXRpb24obWV0aG9kLCBpbnB1dCk7XG4gIGlmIChncm91cCA9PT0gXCJpMThuXCIpIHJldHVybiBpMThuT3BlcmF0aW9uKG1ldGhvZCwgaW5wdXQpO1xuICBpZiAoZ3JvdXAgPT09IFwidGFza1wiKSByZXR1cm4gdGFza09wZXJhdGlvbihtZXRob2QsIGlucHV0KTtcbiAgaWYgKGdyb3VwID09PSBcInN0dWJcIikgcmV0dXJuIHN0dWJQcmFjdGljZU9wZXJhdGlvbihpbnB1dCk7XG4gIHJldHVybiBjZGRPcGVyYXRpb24obWV0aG9kLCBpbnB1dCk7XG59XG5cbi8vIOq4sOuzuCByZWdpc3RyeeuKlCDtmLjstpwg7Iuc7KCQ6rmM7KeAIFNvbmFtdSDstIjquLDtmZTsmYAg7Jm467aAIOyekeyXheydhCDrqqjrkZAg66+466O564uI64ukLlxuZXhwb3J0IGNvbnN0IHRvb2xpbmc6IENsaVRvb2xpbmdPcGVyYXRpb25zID0gT2JqZWN0LmZyb21FbnRyaWVzKFxuICBPYmplY3QuZW50cmllcyhSRVFVSVJFRF9NRVRIT0RTKS5tYXAoKFtncm91cCwgbWV0aG9kc10pID0+IFtcbiAgICBncm91cCxcbiAgICBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICBtZXRob2RzLm1hcCgobWV0aG9kKSA9PiBbXG4gICAgICAgIG1ldGhvZCxcbiAgICAgICAgKGlucHV0OiBDb21tYW5kSW5wdXQpID0+IGludm9rZURlZmF1bHQoZ3JvdXAsIG1ldGhvZCwgaW5wdXQpLFxuICAgICAgXSksXG4gICAgKSxcbiAgXSksXG4pO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydHkodG9vbGluZy5taWdyYXRpb24sIFwiYXBwbHlcIiwge1xuICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgdmFsdWU6IChpbnB1dDogQ29tbWFuZElucHV0KSA9PiBpbnZva2VEZWZhdWx0KFwibWlncmF0aW9uXCIsIFwiYXBwbHlcIiwgaW5wdXQpLFxufSk7XG4iXSwibWFwcGluZ3MiOiI7O0FBSUEsTUFBTSxrQkFBa0IsRUFBRSxLQUFLO0FBVS9CLE1BQU0sb0NBQW9CLElBQUksSUFBWTtDQUN4QztDQUNBO0NBQ0E7Q0FDQTtDQUNB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
|