@dbx-tools/core 0.6.81 → 0.6.85
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/README.md +22 -0
- package/index.ts +3 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -1
- package/lib/src/config.d.ts +147 -0
- package/lib/src/config.js +416 -0
- package/lib/src/project.js +12 -32
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -3
- package/src/config.ts +507 -0
- package/src/project.ts +15 -30
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layered configuration lookup: environment, `.env`, Databricks bundle.
|
|
3
|
+
*
|
|
4
|
+
* Every package resolves settings the same way: take the caller's value, else
|
|
5
|
+
* an environment variable, else a default. Local development adds two fallback
|
|
6
|
+
* locations: `.env` files and `resources.apps.<app>.config.env` or root
|
|
7
|
+
* `variables` in `databricks.yml`.
|
|
8
|
+
*
|
|
9
|
+
* Two things make it cheap to call from a hot path:
|
|
10
|
+
*
|
|
11
|
+
* - {@link values} is LAZY (an `object.Sequence`), so `databricks bundle
|
|
12
|
+
* validate` is only spawned when the environment and `.env` both missed.
|
|
13
|
+
* - the parsed `.env` and bundle are cached through {@link context.cached}, so
|
|
14
|
+
* the spawn happens once per working directory and a `cwd` change misses
|
|
15
|
+
* rather than returning another project's config.
|
|
16
|
+
*
|
|
17
|
+
* Inside a deployed Databricks App both file sources are skipped outright
|
|
18
|
+
* ({@link isDatabricksAppEnv}): the platform has already turned them into real
|
|
19
|
+
* environment variables, there is no bundle to validate, and the `databricks`
|
|
20
|
+
* CLI is not on the image.
|
|
21
|
+
*
|
|
22
|
+
* Node-only (`child_process`, `fs`, `process`).
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
import { spawnSync } from "node:child_process";
|
|
27
|
+
import { readFileSync } from "node:fs";
|
|
28
|
+
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
29
|
+
import { parseEnv } from "node:util";
|
|
30
|
+
import { context, json, log, object, string as stringModule } from "@dbx-tools/shared-core";
|
|
31
|
+
import { z } from "zod";
|
|
32
|
+
import { statSync } from "./file.js";
|
|
33
|
+
import { root as resolveProjectRoot } from "./project.js";
|
|
34
|
+
const logger = log.logger("config");
|
|
35
|
+
const DEFAULT_SCOPE = "DBX_TOOLS";
|
|
36
|
+
const DEFAULT_SOURCES = ["env", "dotenv", "bundle"];
|
|
37
|
+
const BUNDLE_FILE_NAMES = ["databricks.yml", "databricks.yaml"];
|
|
38
|
+
const DOTENV_FILE_NAME = ".env";
|
|
39
|
+
const NODE_ENV_ALTERNATIVES = {
|
|
40
|
+
production: ["prod"],
|
|
41
|
+
development: ["dev"],
|
|
42
|
+
};
|
|
43
|
+
/** Highest valid TCP port number. */
|
|
44
|
+
export const MAX_TCP_PORT = 65_535;
|
|
45
|
+
/** Exact process-environment lookup for callers that do not read local config files. */
|
|
46
|
+
export const ENV_ONLY = { scope: [], sources: "env" };
|
|
47
|
+
export const bundleValue = z
|
|
48
|
+
.string()
|
|
49
|
+
.transform((value) => value.trim())
|
|
50
|
+
.refine((value) => value.length > 0)
|
|
51
|
+
.refine((value) => !/\$\{[^}]+\}/.test(value), {
|
|
52
|
+
message: "Interpolated values are not allowed",
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* The GENERIC shape of a bundle resource: a name, and whatever else the resource
|
|
56
|
+
* type carries. Deliberately unopinionated and `passthrough()` - the concrete
|
|
57
|
+
* resource kinds (`sql_warehouse`, `genie_space`, `postgres`, ...) are
|
|
58
|
+
* Databricks-App concepts that belong to the package that resolves them, so
|
|
59
|
+
* node-appkit `.extend()`s this rather than this module knowing about them.
|
|
60
|
+
*/
|
|
61
|
+
export const bundleResourceSchema = z.object({ name: bundleValue.optional() }).passthrough();
|
|
62
|
+
export const bundleEnvEntrySchema = z.object({
|
|
63
|
+
name: bundleValue.optional(),
|
|
64
|
+
value: z.string().optional(),
|
|
65
|
+
value_from: bundleValue.optional(),
|
|
66
|
+
});
|
|
67
|
+
const bundleVariableSchema = z.object({
|
|
68
|
+
default: z.string().optional(),
|
|
69
|
+
value: z.string().optional(),
|
|
70
|
+
});
|
|
71
|
+
export const bundleAppSchema = z.object({
|
|
72
|
+
name: bundleValue.optional(),
|
|
73
|
+
source_code_path: z.string().optional(),
|
|
74
|
+
config: z.object({ env: z.array(bundleEnvEntrySchema).optional() }).optional(),
|
|
75
|
+
resources: z.array(bundleResourceSchema).optional(),
|
|
76
|
+
});
|
|
77
|
+
const bundleAppsSchema = z.object({
|
|
78
|
+
resources: z.object({ apps: z.record(z.string(), bundleAppSchema).optional() }).optional(),
|
|
79
|
+
});
|
|
80
|
+
const bundleVariablesSchema = z.object({
|
|
81
|
+
variables: z.record(z.string(), bundleVariableSchema).optional(),
|
|
82
|
+
});
|
|
83
|
+
/**
|
|
84
|
+
* Detect a Databricks App runtime from its required name, host, and port.
|
|
85
|
+
*/
|
|
86
|
+
export function isDatabricksAppEnv(source = process.env) {
|
|
87
|
+
const appName = source.DATABRICKS_APP_NAME?.trim();
|
|
88
|
+
const host = source.DATABRICKS_HOST?.trim();
|
|
89
|
+
const port = source.DATABRICKS_APP_PORT?.trim();
|
|
90
|
+
if (!appName || !host || !port)
|
|
91
|
+
return false;
|
|
92
|
+
try {
|
|
93
|
+
if (!["http:", "https:"].includes(new URL(host).protocol))
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
const portNumber = object.toNumber(port);
|
|
100
|
+
return (portNumber !== undefined &&
|
|
101
|
+
Number.isInteger(portNumber) &&
|
|
102
|
+
portNumber >= 1 &&
|
|
103
|
+
portNumber <= MAX_TCP_PORT);
|
|
104
|
+
}
|
|
105
|
+
/** Candidate names in scope, prefix, and input precedence order. */
|
|
106
|
+
function keys(input, options = {}) {
|
|
107
|
+
const scopes = object.sequence(options.scope ?? DEFAULT_SCOPE).toArray();
|
|
108
|
+
const prefixes = options.prefix === undefined ? [] : object.sequence(options.prefix).toArray();
|
|
109
|
+
return [
|
|
110
|
+
...object
|
|
111
|
+
.sequence(input)
|
|
112
|
+
.flatMap((key) => {
|
|
113
|
+
const prefixed = prefixes.length > 0 ? prefixes.map((prefix) => join(prefix, key)) : [key];
|
|
114
|
+
return [
|
|
115
|
+
...scopes.flatMap((scope) => prefixed.map((key) => join(scope, key))),
|
|
116
|
+
...prefixed,
|
|
117
|
+
key,
|
|
118
|
+
];
|
|
119
|
+
})
|
|
120
|
+
.filter((key) => key.length > 0)
|
|
121
|
+
.distinct(),
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Every value that resolves for `input`, in source-then-key precedence order,
|
|
126
|
+
* as a LAZY sequence: nothing past the first consumed element is read, so
|
|
127
|
+
* `values(key).first()` never spawns the Databricks CLI when the environment
|
|
128
|
+
* already answered.
|
|
129
|
+
*
|
|
130
|
+
*/
|
|
131
|
+
function values(input, options = {}) {
|
|
132
|
+
const candidates = keys(input, options);
|
|
133
|
+
const sources = object.sequence(options.sources ?? DEFAULT_SOURCES);
|
|
134
|
+
return object.sequence({
|
|
135
|
+
*[Symbol.iterator]() {
|
|
136
|
+
for (const source of sources) {
|
|
137
|
+
for (const map of read(source, options.cwd)) {
|
|
138
|
+
for (const key of candidates) {
|
|
139
|
+
const value = stringModule.trimToNull(map[key]);
|
|
140
|
+
if (value !== null)
|
|
141
|
+
yield { key, source, value };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The first value that resolves for `input`, or `undefined`.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* const domain = config.text(["TUNNEL_PUBLIC_DOMAIN", "PUBLIC_DOMAIN"]);
|
|
153
|
+
*/
|
|
154
|
+
export function text(input, options = {}) {
|
|
155
|
+
return values(input, options).at(0)?.value;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The PRIMARY (fully-scoped) name for `input` - what to print in a log line or an
|
|
159
|
+
* error, so the message names the variable a reader should set. Do not index
|
|
160
|
+
* `keys(...)[0]` for this if `input` may be a bare string.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* logger.warn(`${config.name(JWT_SECRET_ENV)} is not set`);
|
|
164
|
+
*/
|
|
165
|
+
export function name(input, options = {}) {
|
|
166
|
+
return keys(input, options)[0] ?? "";
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Safe `.env.<name>` suffixes for a Node environment, exact spelling first.
|
|
170
|
+
* Known long and short names are interchangeable; unknown names pass through.
|
|
171
|
+
*/
|
|
172
|
+
function nodeEnvNames(nodeEnv) {
|
|
173
|
+
const name = stringModule.trimToNull(nodeEnv)?.toLowerCase();
|
|
174
|
+
if (!name || !/^[a-z0-9_-]+$/.test(name))
|
|
175
|
+
return [];
|
|
176
|
+
for (const [canonical, alternatives] of Object.entries(NODE_ENV_ALTERNATIVES)) {
|
|
177
|
+
const names = alternatives;
|
|
178
|
+
if (name === canonical || names.includes(name)) {
|
|
179
|
+
return [...object.sequence(name, canonical, alternatives).distinct()];
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return [name];
|
|
183
|
+
}
|
|
184
|
+
function join(...parts) {
|
|
185
|
+
return parts
|
|
186
|
+
.map((part) => part.trim())
|
|
187
|
+
.filter(Boolean)
|
|
188
|
+
.join("_");
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Resolve a string: `configured` when non-empty, else {@link text}, else `undefined`.
|
|
192
|
+
*
|
|
193
|
+
* The coercion rules are deliberately loose (`on` / `yes` / `1` are all
|
|
194
|
+
* `true`) because values may come from a file a human typed.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* config.string(options.host, "SMTP_HOST");
|
|
198
|
+
*/
|
|
199
|
+
export function string(configured, input, options) {
|
|
200
|
+
return stringModule.trimToNull(configured) ?? text(input, options);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Resolve a boolean through `object.toBoolean`. `undefined` when neither source
|
|
204
|
+
* is interpretable, so the caller picks a default with `??`.
|
|
205
|
+
*/
|
|
206
|
+
export function boolean(configured, input, options) {
|
|
207
|
+
return object.toBoolean(configured) ?? object.toBoolean(text(input, options));
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Resolve a positive number that may be fractional (a score threshold, a ratio).
|
|
211
|
+
* Use {@link positiveInt} for a count, port, or timeout.
|
|
212
|
+
*/
|
|
213
|
+
export function positiveNumber(configured, input, fallback, options) {
|
|
214
|
+
return toPositiveNumber(configured) ?? toPositiveNumber(text(input, options)) ?? fallback;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Resolve a positive integer (a port, a timeout, a page size), floored. A
|
|
218
|
+
* non-numeric or non-positive value is treated as ABSENT rather than fatal -
|
|
219
|
+
* these are ceilings where a sane default beats a boot failure.
|
|
220
|
+
*/
|
|
221
|
+
export function positiveInt(configured, input, fallback, options) {
|
|
222
|
+
const resolved = positiveNumber(configured, input, fallback, options);
|
|
223
|
+
return Math.floor(resolved);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Resolve a list through `string.parseList`, so an array from typed config and a
|
|
227
|
+
* `"a, b c"` string normalize identically. `[]` when neither source has entries.
|
|
228
|
+
*/
|
|
229
|
+
export function list(configured, input, transform, options) {
|
|
230
|
+
const fromConfig = stringModule.parseList(configured, transform);
|
|
231
|
+
return fromConfig.length > 0
|
|
232
|
+
? fromConfig
|
|
233
|
+
: stringModule.parseList(text(input, options), transform);
|
|
234
|
+
}
|
|
235
|
+
function toPositiveNumber(value) {
|
|
236
|
+
const parsed = object.toNumber(value);
|
|
237
|
+
return parsed !== undefined && parsed > 0 ? parsed : undefined;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* The Databricks bundle output for `cwd` - `databricks bundle validate --output
|
|
241
|
+
* json` run from the directory holding `databricks.yml`, with the config file's
|
|
242
|
+
* path. A non-zero validation may still return partial JSON with usable
|
|
243
|
+
* variables. `undefined` when there is no bundle, the CLI produces no JSON, or
|
|
244
|
+
* this process is a deployed Databricks App.
|
|
245
|
+
*
|
|
246
|
+
* Cached per working directory and `DATABRICKS_CONFIG_PROFILE` through
|
|
247
|
+
* {@link context.cached}, so changing either cannot return another context's
|
|
248
|
+
* bundle. A lookup for some other directory is not cached at all.
|
|
249
|
+
*/
|
|
250
|
+
export function bundleFile(cwd) {
|
|
251
|
+
const profile = stringModule.trimToNull(process.env.DATABRICKS_CONFIG_PROFILE);
|
|
252
|
+
return context.cached(["config", "bundle", profile ?? ""], (resolved) => loadBundleFile(resolved ?? ".", profile), cwd);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* The single App's literal `config.env` entries, flattened to `name -> value`.
|
|
256
|
+
*
|
|
257
|
+
* A `value_from` entry names a bundle resource whose id is known after
|
|
258
|
+
* deployment, and reading it needs the resource vocabulary this module
|
|
259
|
+
* deliberately does not have - node-appkit resolves those against its extended
|
|
260
|
+
* {@link bundleResourceSchema}. An `apps` block with more than one app is
|
|
261
|
+
* ambiguous (nothing here says which app this process is), so it yields nothing
|
|
262
|
+
* rather than a guess.
|
|
263
|
+
*/
|
|
264
|
+
function bundleApp(input) {
|
|
265
|
+
const parsed = bundleAppsSchema.safeParse(input);
|
|
266
|
+
if (!parsed.success)
|
|
267
|
+
return {};
|
|
268
|
+
const apps = parsed.data.resources?.apps;
|
|
269
|
+
if (!apps)
|
|
270
|
+
return {};
|
|
271
|
+
const names = Object.keys(apps);
|
|
272
|
+
if (names.length !== 1)
|
|
273
|
+
return {};
|
|
274
|
+
const entries = apps[names[0]]?.config?.env ?? [];
|
|
275
|
+
const result = {};
|
|
276
|
+
for (const entry of entries) {
|
|
277
|
+
if (!entry.name)
|
|
278
|
+
continue;
|
|
279
|
+
const value = resolvedString(entry.value);
|
|
280
|
+
if (value !== null)
|
|
281
|
+
result[entry.name] = value;
|
|
282
|
+
}
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Root bundle variables flattened to environment-style `NAME -> value` entries.
|
|
287
|
+
*
|
|
288
|
+
* `databricks bundle validate` resolves each variable to `value`; `default` is
|
|
289
|
+
* retained as a fallback for parsed bundle data that has not been fully
|
|
290
|
+
* resolved. Names are normalized so a bundle variable such as
|
|
291
|
+
* `tunnel_public_domain` answers a lookup for `TUNNEL_PUBLIC_DOMAIN`.
|
|
292
|
+
*/
|
|
293
|
+
function bundleVariables(input) {
|
|
294
|
+
const parsed = bundleVariablesSchema.safeParse(input);
|
|
295
|
+
if (!parsed.success)
|
|
296
|
+
return {};
|
|
297
|
+
const result = {};
|
|
298
|
+
for (const [name, variable] of Object.entries(parsed.data.variables ?? {})) {
|
|
299
|
+
const key = [...stringModule.tokenize(name)].join("_").toUpperCase();
|
|
300
|
+
const value = resolvedString(variable.value) ?? resolvedString(variable.default);
|
|
301
|
+
if (key && value !== null)
|
|
302
|
+
result[key] = value;
|
|
303
|
+
}
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
/** A non-empty bundle value with every `${...}` interpolation resolved. */
|
|
307
|
+
function resolvedString(value) {
|
|
308
|
+
const parsed = bundleValue.safeParse(value);
|
|
309
|
+
return parsed.success ? parsed.data : null;
|
|
310
|
+
}
|
|
311
|
+
/** Parsed `.env` for `cwd`, or `{}`. Cached per working directory. */
|
|
312
|
+
function dotenv(cwd) {
|
|
313
|
+
const environments = nodeEnvNames(process.env.NODE_ENV);
|
|
314
|
+
return context.cached(["config", "dotenv", ...environments], (resolved) => loadDotenv(resolved ?? ".", environments), cwd);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Maps for one source in precedence order. Bundle App config and root variables
|
|
318
|
+
* stay separate so a first-match lookup does not parse variables after an App
|
|
319
|
+
* value resolves.
|
|
320
|
+
*/
|
|
321
|
+
function read(source, cwd) {
|
|
322
|
+
return object.sequence({
|
|
323
|
+
*[Symbol.iterator]() {
|
|
324
|
+
switch (source) {
|
|
325
|
+
case "env":
|
|
326
|
+
yield process.env;
|
|
327
|
+
break;
|
|
328
|
+
case "dotenv":
|
|
329
|
+
yield dotenv(cwd);
|
|
330
|
+
break;
|
|
331
|
+
case "bundle": {
|
|
332
|
+
const bundle = bundleFile(cwd);
|
|
333
|
+
if (bundle) {
|
|
334
|
+
yield bundleApp(bundle.data);
|
|
335
|
+
yield bundleVariables(bundle.data);
|
|
336
|
+
}
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Locate `names` from `cwd` outward. `cwd` itself is checked before the
|
|
345
|
+
* discovered project roots so a package-local file wins over the workspace's.
|
|
346
|
+
*/
|
|
347
|
+
function findConfigFile(cwd, names) {
|
|
348
|
+
if (isDatabricksAppEnv())
|
|
349
|
+
return undefined;
|
|
350
|
+
const start = resolve(cwd);
|
|
351
|
+
const root = resolveProjectRoot(start);
|
|
352
|
+
const pathFromRoot = root ? relative(root, start) : undefined;
|
|
353
|
+
const boundary = root &&
|
|
354
|
+
pathFromRoot !== undefined &&
|
|
355
|
+
!isAbsolute(pathFromRoot) &&
|
|
356
|
+
pathFromRoot !== ".." &&
|
|
357
|
+
!pathFromRoot.startsWith(`..${sep}`)
|
|
358
|
+
? root
|
|
359
|
+
: undefined;
|
|
360
|
+
for (let dir = start;; dir = dirname(dir)) {
|
|
361
|
+
for (const name of names) {
|
|
362
|
+
const path = resolve(dir, name);
|
|
363
|
+
if (statSync(path)?.isFile())
|
|
364
|
+
return path;
|
|
365
|
+
}
|
|
366
|
+
if (boundary === undefined || dir === boundary)
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
function loadDotenv(cwd, environments) {
|
|
372
|
+
const names = [...environments.map((name) => `${DOTENV_FILE_NAME}.${name}`), DOTENV_FILE_NAME];
|
|
373
|
+
const path = findConfigFile(cwd, names);
|
|
374
|
+
if (!path)
|
|
375
|
+
return {};
|
|
376
|
+
try {
|
|
377
|
+
return parseEnv(readFileSync(path, "utf8"));
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
logger.warn("failed to read dotenv file", { path });
|
|
381
|
+
return {};
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
function loadBundleFile(cwd, profile) {
|
|
385
|
+
const path = findConfigFile(cwd, BUNDLE_FILE_NAMES);
|
|
386
|
+
if (!path)
|
|
387
|
+
return undefined;
|
|
388
|
+
const args = [
|
|
389
|
+
"bundle",
|
|
390
|
+
"validate",
|
|
391
|
+
"--output",
|
|
392
|
+
"json",
|
|
393
|
+
...(profile === null ? [] : ["--profile", profile]),
|
|
394
|
+
];
|
|
395
|
+
const result = spawnSync("databricks", args, {
|
|
396
|
+
cwd: resolve(path, ".."),
|
|
397
|
+
encoding: "utf8",
|
|
398
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
399
|
+
});
|
|
400
|
+
const output = stringModule.trimToNull(result.stdout);
|
|
401
|
+
const error = stringModule.trimToNull(result.stderr);
|
|
402
|
+
if (output === null) {
|
|
403
|
+
logger.debug("bundle validate produced no JSON", { path, status: result.status, error });
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
406
|
+
const data = json.parseRecord(output);
|
|
407
|
+
if (!data) {
|
|
408
|
+
logger.warn("failed to parse bundle validate output", { path, status: result.status });
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
411
|
+
if (result.status !== 0) {
|
|
412
|
+
logger.debug("using partial bundle output", { path, status: result.status, error });
|
|
413
|
+
}
|
|
414
|
+
return { path, data };
|
|
415
|
+
}
|
|
416
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBRUgsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDdkMsT0FBTyxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDeEUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNyQyxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sSUFBSSxZQUFZLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM1RixPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBQ3hCLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDckMsT0FBTyxFQUFFLElBQUksSUFBSSxrQkFBa0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUUxRCxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBaUNwQyxNQUFNLGFBQWEsR0FBRyxXQUFXLENBQUM7QUFDbEMsTUFBTSxlQUFlLEdBQTRCLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQztBQUM3RSxNQUFNLGlCQUFpQixHQUFHLENBQUMsZ0JBQWdCLEVBQUUsaUJBQWlCLENBQVUsQ0FBQztBQUN6RSxNQUFNLGdCQUFnQixHQUFHLE1BQU0sQ0FBQztBQUNoQyxNQUFNLHFCQUFxQixHQUFHO0lBQzVCLFVBQVUsRUFBRSxDQUFDLE1BQU0sQ0FBQztJQUNwQixXQUFXLEVBQUUsQ0FBQyxLQUFLLENBQUM7Q0FD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UyxDQUFDO0lBQ25CLENBQUM7SUFDRCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3RDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNWLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0NBQXdDLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZGLE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFDRCxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDeEIsTUFBTSxDQUFDLEtBQUssQ0FBQyw2QkFBNkIsRUFBRSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO0lBQ3RGLENBQUM7SUFDRCxPQUFPLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDO0FBQ3hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIExheWVyZWQgY29uZmlndXJhdGlvbiBsb29rdXA6IGVudmlyb25tZW50LCBgLmVudmAsIERhdGFicmlja3MgYnVuZGxlLlxuICpcbiAqIEV2ZXJ5IHBhY2thZ2UgcmVzb2x2ZXMgc2V0dGluZ3MgdGhlIHNhbWUgd2F5OiB0YWtlIHRoZSBjYWxsZXIncyB2YWx1ZSwgZWxzZVxuICogYW4gZW52aXJvbm1lbnQgdmFyaWFibGUsIGVsc2UgYSBkZWZhdWx0LiBMb2NhbCBkZXZlbG9wbWVudCBhZGRzIHR3byBmYWxsYmFja1xuICogbG9jYXRpb25zOiBgLmVudmAgZmlsZXMgYW5kIGByZXNvdXJjZXMuYXBwcy48YXBwPi5jb25maWcuZW52YCBvciByb290XG4gKiBgdmFyaWFibGVzYCBpbiBgZGF0YWJyaWNrcy55bWxgLlxuICpcbiAqIFR3byB0aGluZ3MgbWFrZSBpdCBjaGVhcCB0byBjYWxsIGZyb20gYSBob3QgcGF0aDpcbiAqXG4gKiAgIC0ge0BsaW5rIHZhbHVlc30gaXMgTEFaWSAoYW4gYG9iamVjdC5TZXF1ZW5jZWApLCBzbyBgZGF0YWJyaWNrcyBidW5kbGVcbiAqICAgICB2YWxpZGF0ZWAgaXMgb25seSBzcGF3bmVkIHdoZW4gdGhlIGVudmlyb25tZW50IGFuZCBgLmVudmAgYm90aCBtaXNzZWQuXG4gKiAgIC0gdGhlIHBhcnNlZCBgLmVudmAgYW5kIGJ1bmRsZSBhcmUgY2FjaGVkIHRocm91Z2gge0BsaW5rIGNvbnRleHQuY2FjaGVkfSwgc29cbiAqICAgICB0aGUgc3Bhd24gaGFwcGVucyBvbmNlIHBlciB3b3JraW5nIGRpcmVjdG9yeSBhbmQgYSBgY3dkYCBjaGFuZ2UgbWlzc2VzXG4gKiAgICAgcmF0aGVyIHRoYW4gcmV0dXJuaW5nIGFub3RoZXIgcHJvamVjdCdzIGNvbmZpZy5cbiAqXG4gKiBJbnNpZGUgYSBkZXBsb3llZCBEYXRhYnJpY2tzIEFwcCBib3RoIGZpbGUgc291cmNlcyBhcmUgc2tpcHBlZCBvdXRyaWdodFxuICogKHtAbGluayBpc0RhdGFicmlja3NBcHBFbnZ9KTogdGhlIHBsYXRmb3JtIGhhcyBhbHJlYWR5IHR1cm5lZCB0aGVtIGludG8gcmVhbFxuICogZW52aXJvbm1lbnQgdmFyaWFibGVzLCB0aGVyZSBpcyBubyBidW5kbGUgdG8gdmFsaWRhdGUsIGFuZCB0aGUgYGRhdGFicmlja3NgXG4gKiBDTEkgaXMgbm90IG9uIHRoZSBpbWFnZS5cbiAqXG4gKiBOb2RlLW9ubHkgKGBjaGlsZF9wcm9jZXNzYCwgYGZzYCwgYHByb2Nlc3NgKS5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgc3Bhd25TeW5jIH0gZnJvbSBcIm5vZGU6Y2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSBcIm5vZGU6ZnNcIjtcbmltcG9ydCB7IGRpcm5hbWUsIGlzQWJzb2x1dGUsIHJlbGF0aXZlLCByZXNvbHZlLCBzZXAgfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgeyBwYXJzZUVudiB9IGZyb20gXCJub2RlOnV0aWxcIjtcbmltcG9ydCB7IGNvbnRleHQsIGpzb24sIGxvZywgb2JqZWN0LCBzdHJpbmcgYXMgc3RyaW5nTW9kdWxlIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5pbXBvcnQgeyBzdGF0U3luYyB9IGZyb20gXCIuL2ZpbGUudHNcIjtcbmltcG9ydCB7IHJvb3QgYXMgcmVzb2x2ZVByb2plY3RSb290IH0gZnJvbSBcIi4vcHJvamVjdC50c1wiO1xuXG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwiY29uZmlnXCIpO1xuXG50eXBlIENvbmZpZ0tleSA9IHN0cmluZyB8IHJlYWRvbmx5IHN0cmluZ1tdO1xuXG4vKiogV2hlcmUgYSB2YWx1ZSBtYXkgY29tZSBmcm9tLCBjb25zdWx0ZWQgaW4gdGhlIG9yZGVyIGdpdmVuLiAqL1xudHlwZSBDb25maWdTb3VyY2UgPSBcImVudlwiIHwgXCJkb3RlbnZcIiB8IFwiYnVuZGxlXCI7XG5cbmludGVyZmFjZSBDb25maWdPcHRpb25zIHtcbiAgLyoqXG4gICAqIE91dGVybW9zdCBuYW1lc3BhY2VzIHRyaWVkIGJlZm9yZSBlYWNoIGtleS4gRGVmYXVsdHMgdG8gYERCWF9UT09MU2AuXG4gICAqL1xuICBzY29wZT86IHN0cmluZyB8IHJlYWRvbmx5IHN0cmluZ1tdO1xuICAvKiogQ2FwYWJpbGl0eSBuYW1lc3BhY2VzIGluc2VydGVkIGFmdGVyIHRoZSBzY29wZSBhbmQgYmVmb3JlIGVhY2gga2V5LiAqL1xuICBwcmVmaXg/OiBzdHJpbmcgfCByZWFkb25seSBzdHJpbmdbXTtcbiAgLyoqIERpcmVjdG9yeSB0byByZXNvbHZlIGAuZW52YCBhbmQgdGhlIGJ1bmRsZSBmcm9tLiBEZWZhdWx0OiBgcHJvY2Vzcy5jd2QoKWAuICovXG4gIGN3ZD86IHN0cmluZztcbiAgLyoqIFNvdXJjZXMgaW4gcHJlY2VkZW5jZSBvcmRlci4gRGVmYXVsdDogYGVudmAsIGBkb3RlbnZgLCBgYnVuZGxlYC4gKi9cbiAgc291cmNlcz86IENvbmZpZ1NvdXJjZSB8IHJlYWRvbmx5IENvbmZpZ1NvdXJjZVtdO1xufVxuXG4vKiogT25lIHJlc29sdmVkIHZhbHVlLCB0YWdnZWQgd2l0aCB0aGUga2V5IGFuZCBzb3VyY2UgaXQgY2FtZSBmcm9tLiAqL1xuaW50ZXJmYWNlIENvbmZpZ1ZhbHVlIHtcbiAga2V5OiBzdHJpbmc7XG4gIHNvdXJjZTogQ29uZmlnU291cmNlO1xuICB2YWx1ZTogc3RyaW5nO1xufVxuXG4vKiogQSBjb25maWcgZmlsZSBmb3VuZCBvbiBkaXNrLCB3aXRoIGl0cyBwYXJzZWQgY29udGVudHMuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbmZpZ0ZpbGUge1xuICBwYXRoOiBzdHJpbmc7XG4gIGRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xufVxuXG5jb25zdCBERUZBVUxUX1NDT1BFID0gXCJEQlhfVE9PTFNcIjtcbmNvbnN0IERFRkFVTFRfU09VUkNFUzogcmVhZG9ubHkgQ29uZmlnU291cmNlW10gPSBbXCJlbnZcIiwgXCJkb3RlbnZcIiwgXCJidW5kbGVcIl07XG5jb25zdCBCVU5ETEVfRklMRV9OQU1FUyA9IFtcImRhdGFicmlja3MueW1sXCIsIFwiZGF0YWJyaWNrcy55YW1sXCJdIGFzIGNvbnN0O1xuY29uc3QgRE9URU5WX0ZJTEVfTkFNRSA9IFwiLmVudlwiO1xuY29uc3QgTk9ERV9FTlZfQUxURVJOQVRJVkVTID0ge1xuICBwcm9kdWN0aW9uOiBbXCJwcm9kXCJdLFxuICBkZXZlbG9wbWVudDogW1wiZGV2XCJdLFxufSBhcyBjb25zdCBzYXRpc2ZpZXMgUmVjb3JkPHN0cmluZywgcmVhZG9ubHkgc3RyaW5nW10+O1xuXG4vKiogSGlnaGVzdCB2YWxpZCBUQ1AgcG9ydCBudW1iZXIuICovXG5leHBvcnQgY29uc3QgTUFYX1RDUF9QT1JUID0gNjVfNTM1O1xuXG4vKiogRXhhY3QgcHJvY2Vzcy1lbnZpcm9ubWVudCBsb29rdXAgZm9yIGNhbGxlcnMgdGhhdCBkbyBub3QgcmVhZCBsb2NhbCBjb25maWcgZmlsZXMuICovXG5leHBvcnQgY29uc3QgRU5WX09OTFkgPSB7IHNjb3BlOiBbXSBhcyBjb25zdCwgc291cmNlczogXCJlbnZcIiBhcyBjb25zdCB9O1xuXG5leHBvcnQgY29uc3QgYnVuZGxlVmFsdWUgPSB6XG4gIC5zdHJpbmcoKVxuICAudHJhbnNmb3JtKCh2YWx1ZTogc3RyaW5nKSA9PiB2YWx1ZS50cmltKCkpXG4gIC5yZWZpbmUoKHZhbHVlOiBzdHJpbmcpID0+IHZhbHVlLmxlbmd0aCA+IDApXG4gIC5yZWZpbmUoKHZhbHVlOiBzdHJpbmcpID0+ICEvXFwkXFx7W159XStcXH0vLnRlc3QodmFsdWUpLCB7XG4gICAgbWVzc2FnZTogXCJJbnRlcnBvbGF0ZWQgdmFsdWVzIGFyZSBub3QgYWxsb3dlZFwiLFxuICB9KTtcblxuLyoqXG4gKiBUaGUgR0VORVJJQyBzaGFwZSBvZiBhIGJ1bmRsZSByZXNvdXJjZTogYSBuYW1lLCBhbmQgd2hhdGV2ZXIgZWxzZSB0aGUgcmVzb3VyY2VcbiAqIHR5cGUgY2Fycmllcy4gRGVsaWJlcmF0ZWx5IHVub3BpbmlvbmF0ZWQgYW5kIGBwYXNzdGhyb3VnaCgpYCAtIHRoZSBjb25jcmV0ZVxuICogcmVzb3VyY2Uga2luZHMgKGBzcWxfd2FyZWhvdXNlYCwgYGdlbmllX3NwYWNlYCwgYHBvc3RncmVzYCwgLi4uKSBhcmVcbiAqIERhdGFicmlja3MtQXBwIGNvbmNlcHRzIHRoYXQgYmVsb25nIHRvIHRoZSBwYWNrYWdlIHRoYXQgcmVzb2x2ZXMgdGhlbSwgc29cbiAqIG5vZGUtYXBwa2l0IGAuZXh0ZW5kKClgcyB0aGlzIHJhdGhlciB0aGFuIHRoaXMgbW9kdWxlIGtub3dpbmcgYWJvdXQgdGhlbS5cbiAqL1xuZXhwb3J0IGNvbnN0IGJ1bmRsZVJlc291cmNlU2NoZW1hID0gei5vYmplY3QoeyBuYW1lOiBidW5kbGVWYWx1ZS5vcHRpb25hbCgpIH0pLnBhc3N0aHJvdWdoKCk7XG5cbmV4cG9ydCBjb25zdCBidW5kbGVFbnZFbnRyeVNjaGVtYSA9IHoub2JqZWN0KHtcbiAgbmFtZTogYnVuZGxlVmFsdWUub3B0aW9uYWwoKSxcbiAgdmFsdWU6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgdmFsdWVfZnJvbTogYnVuZGxlVmFsdWUub3B0aW9uYWwoKSxcbn0pO1xuXG5jb25zdCBidW5kbGVWYXJpYWJsZVNjaGVtYSA9IHoub2JqZWN0KHtcbiAgZGVmYXVsdDogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICB2YWx1ZTogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxufSk7XG5cbmV4cG9ydCBjb25zdCBidW5kbGVBcHBTY2hlbWEgPSB6Lm9iamVjdCh7XG4gIG5hbWU6IGJ1bmRsZVZhbHVlLm9wdGlvbmFsKCksXG4gIHNvdXJjZV9jb2RlX3BhdGg6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgY29uZmlnOiB6Lm9iamVjdCh7IGVudjogei5hcnJheShidW5kbGVFbnZFbnRyeVNjaGVtYSkub3B0aW9uYWwoKSB9KS5vcHRpb25hbCgpLFxuICByZXNvdXJjZXM6IHouYXJyYXkoYnVuZGxlUmVzb3VyY2VTY2hlbWEpLm9wdGlvbmFsKCksXG59KTtcblxuY29uc3QgYnVuZGxlQXBwc1NjaGVtYSA9IHoub2JqZWN0KHtcbiAgcmVzb3VyY2VzOiB6Lm9iamVjdCh7IGFwcHM6IHoucmVjb3JkKHouc3RyaW5nKCksIGJ1bmRsZUFwcFNjaGVtYSkub3B0aW9uYWwoKSB9KS5vcHRpb25hbCgpLFxufSk7XG5cbmNvbnN0IGJ1bmRsZVZhcmlhYmxlc1NjaGVtYSA9IHoub2JqZWN0KHtcbiAgdmFyaWFibGVzOiB6LnJlY29yZCh6LnN0cmluZygpLCBidW5kbGVWYXJpYWJsZVNjaGVtYSkub3B0aW9uYWwoKSxcbn0pO1xuXG4vKipcbiAqIERldGVjdCBhIERhdGFicmlja3MgQXBwIHJ1bnRpbWUgZnJvbSBpdHMgcmVxdWlyZWQgbmFtZSwgaG9zdCwgYW5kIHBvcnQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0RhdGFicmlja3NBcHBFbnYoXG4gIHNvdXJjZTogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPiA9IHByb2Nlc3MuZW52LFxuKTogYm9vbGVhbiB7XG4gIGNvbnN0IGFwcE5hbWUgPSBzb3VyY2UuREFUQUJSSUNLU19BUFBfTkFNRT8udHJpbSgpO1xuICBjb25zdCBob3N0ID0gc291cmNlLkRBVEFCUklDS1NfSE9TVD8udHJpbSgpO1xuICBjb25zdCBwb3J0ID0gc291cmNlLkRBVEFCUklDS1NfQVBQX1BPUlQ/LnRyaW0oKTtcbiAgaWYgKCFhcHBOYW1lIHx8ICFob3N0IHx8ICFwb3J0KSByZXR1cm4gZmFsc2U7XG4gIHRyeSB7XG4gICAgaWYgKCFbXCJodHRwOlwiLCBcImh0dHBzOlwiXS5pbmNsdWRlcyhuZXcgVVJMKGhvc3QpLnByb3RvY29sKSkgcmV0dXJuIGZhbHNlO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY29uc3QgcG9ydE51bWJlciA9IG9iamVjdC50b051bWJlcihwb3J0KTtcbiAgcmV0dXJuIChcbiAgICBwb3J0TnVtYmVyICE9PSB1bmRlZmluZWQgJiZcbiAgICBOdW1iZXIuaXNJbnRlZ2VyKHBvcnROdW1iZXIpICYmXG4gICAgcG9ydE51bWJlciA+PSAxICYmXG4gICAgcG9ydE51bWJlciA8PSBNQVhfVENQX1BPUlRcbiAgKTtcbn1cblxuLyoqIENhbmRpZGF0ZSBuYW1lcyBpbiBzY29wZSwgcHJlZml4LCBhbmQgaW5wdXQgcHJlY2VkZW5jZSBvcmRlci4gKi9cbmZ1bmN0aW9uIGtleXMoaW5wdXQ6IENvbmZpZ0tleSwgb3B0aW9uczogUGljazxDb25maWdPcHRpb25zLCBcInNjb3BlXCIgfCBcInByZWZpeFwiPiA9IHt9KTogc3RyaW5nW10ge1xuICBjb25zdCBzY29wZXMgPSBvYmplY3Quc2VxdWVuY2Uob3B0aW9ucy5zY29wZSA/PyBERUZBVUxUX1NDT1BFKS50b0FycmF5KCk7XG4gIGNvbnN0IHByZWZpeGVzID0gb3B0aW9ucy5wcmVmaXggPT09IHVuZGVmaW5lZCA/IFtdIDogb2JqZWN0LnNlcXVlbmNlKG9wdGlvbnMucHJlZml4KS50b0FycmF5KCk7XG4gIHJldHVybiBbXG4gICAgLi4ub2JqZWN0XG4gICAgICAuc2VxdWVuY2UoaW5wdXQpXG4gICAgICAuZmxhdE1hcCgoa2V5KSA9PiB7XG4gICAgICAgIGNvbnN0IHByZWZpeGVkID0gcHJlZml4ZXMubGVuZ3RoID4gMCA/IHByZWZpeGVzLm1hcCgocHJlZml4KSA9PiBqb2luKHByZWZpeCwga2V5KSkgOiBba2V5XTtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAuLi5zY29wZXMuZmxhdE1hcCgoc2NvcGUpID0+IHByZWZpeGVkLm1hcCgoa2V5KSA9PiBqb2luKHNjb3BlLCBrZXkpKSksXG4gICAgICAgICAgLi4ucHJlZml4ZWQsXG4gICAgICAgICAga2V5LFxuICAgICAgICBdO1xuICAgICAgfSlcbiAgICAgIC5maWx0ZXIoKGtleSkgPT4ga2V5Lmxlbmd0aCA+IDApXG4gICAgICAuZGlzdGluY3QoKSxcbiAgXTtcbn1cblxuLyoqXG4gKiBFdmVyeSB2YWx1ZSB0aGF0IHJlc29sdmVzIGZvciBgaW5wdXRgLCBpbiBzb3VyY2UtdGhlbi1rZXkgcHJlY2VkZW5jZSBvcmRlcixcbiAqIGFzIGEgTEFaWSBzZXF1ZW5jZTogbm90aGluZyBwYXN0IHRoZSBmaXJzdCBjb25zdW1lZCBlbGVtZW50IGlzIHJlYWQsIHNvXG4gKiBgdmFsdWVzKGtleSkuZmlyc3QoKWAgbmV2ZXIgc3Bhd25zIHRoZSBEYXRhYnJpY2tzIENMSSB3aGVuIHRoZSBlbnZpcm9ubWVudFxuICogYWxyZWFkeSBhbnN3ZXJlZC5cbiAqXG4gKi9cbmZ1bmN0aW9uIHZhbHVlcyhpbnB1dDogQ29uZmlnS2V5LCBvcHRpb25zOiBDb25maWdPcHRpb25zID0ge30pOiBvYmplY3QuU2VxdWVuY2U8Q29uZmlnVmFsdWU+IHtcbiAgY29uc3QgY2FuZGlkYXRlcyA9IGtleXMoaW5wdXQsIG9wdGlvbnMpO1xuICBjb25zdCBzb3VyY2VzID0gb2JqZWN0LnNlcXVlbmNlPENvbmZpZ1NvdXJjZT4ob3B0aW9ucy5zb3VyY2VzID8/IERFRkFVTFRfU09VUkNFUyk7XG4gIHJldHVybiBvYmplY3Quc2VxdWVuY2Uoe1xuICAgICpbU3ltYm9sLml0ZXJhdG9yXSgpOiBHZW5lcmF0b3I8Q29uZmlnVmFsdWU+IHtcbiAgICAgIGZvciAoY29uc3Qgc291cmNlIG9mIHNvdXJjZXMpIHtcbiAgICAgICAgZm9yIChjb25zdCBtYXAgb2YgcmVhZChzb3VyY2UsIG9wdGlvbnMuY3dkKSkge1xuICAgICAgICAgIGZvciAoY29uc3Qga2V5IG9mIGNhbmRpZGF0ZXMpIHtcbiAgICAgICAgICAgIGNvbnN0IHZhbHVlID0gc3RyaW5nTW9kdWxlLnRyaW1Ub051bGwobWFwW2tleV0pO1xuICAgICAgICAgICAgaWYgKHZhbHVlICE9PSBudWxsKSB5aWVsZCB7IGtleSwgc291cmNlLCB2YWx1ZSB9O1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gIH0pO1xufVxuXG4vKipcbiAqIFRoZSBmaXJzdCB2YWx1ZSB0aGF0IHJlc29sdmVzIGZvciBgaW5wdXRgLCBvciBgdW5kZWZpbmVkYC5cbiAqXG4gKiBAZXhhbXBsZVxuICogY29uc3QgZG9tYWluID0gY29uZmlnLnRleHQoW1wiVFVOTkVMX1BVQkxJQ19ET01BSU5cIiwgXCJQVUJMSUNfRE9NQUlOXCJdKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRleHQoaW5wdXQ6IENvbmZpZ0tleSwgb3B0aW9uczogQ29uZmlnT3B0aW9ucyA9IHt9KTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIHZhbHVlcyhpbnB1dCwgb3B0aW9ucykuYXQoMCk/LnZhbHVlO1xufVxuXG4vKipcbiAqIFRoZSBQUklNQVJZIChmdWxseS1zY29wZWQpIG5hbWUgZm9yIGBpbnB1dGAgLSB3aGF0IHRvIHByaW50IGluIGEgbG9nIGxpbmUgb3IgYW5cbiAqIGVycm9yLCBzbyB0aGUgbWVzc2FnZSBuYW1lcyB0aGUgdmFyaWFibGUgYSByZWFkZXIgc2hvdWxkIHNldC4gRG8gbm90IGluZGV4XG4gKiBga2V5cyguLi4pWzBdYCBmb3IgdGhpcyBpZiBgaW5wdXRgIG1heSBiZSBhIGJhcmUgc3RyaW5nLlxuICpcbiAqIEBleGFtcGxlXG4gKiBsb2dnZXIud2FybihgJHtjb25maWcubmFtZShKV1RfU0VDUkVUX0VOVil9IGlzIG5vdCBzZXRgKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5hbWUoXG4gIGlucHV0OiBDb25maWdLZXksXG4gIG9wdGlvbnM6IFBpY2s8Q29uZmlnT3B0aW9ucywgXCJzY29wZVwiIHwgXCJwcmVmaXhcIj4gPSB7fSxcbik6IHN0cmluZyB7XG4gIHJldHVybiBrZXlzKGlucHV0LCBvcHRpb25zKVswXSA/PyBcIlwiO1xufVxuXG4vKipcbiAqIFNhZmUgYC5lbnYuPG5hbWU+YCBzdWZmaXhlcyBmb3IgYSBOb2RlIGVudmlyb25tZW50LCBleGFjdCBzcGVsbGluZyBmaXJzdC5cbiAqIEtub3duIGxvbmcgYW5kIHNob3J0IG5hbWVzIGFyZSBpbnRlcmNoYW5nZWFibGU7IHVua25vd24gbmFtZXMgcGFzcyB0aHJvdWdoLlxuICovXG5mdW5jdGlvbiBub2RlRW52TmFtZXMobm9kZUVudjogdW5rbm93bik6IHN0cmluZ1tdIHtcbiAgY29uc3QgbmFtZSA9IHN0cmluZ01vZHVsZS50cmltVG9OdWxsKG5vZGVFbnYpPy50b0xvd2VyQ2FzZSgpO1xuICBpZiAoIW5hbWUgfHwgIS9eW2EtejAtOV8tXSskLy50ZXN0KG5hbWUpKSByZXR1cm4gW107XG4gIGZvciAoY29uc3QgW2Nhbm9uaWNhbCwgYWx0ZXJuYXRpdmVzXSBvZiBPYmplY3QuZW50cmllcyhOT0RFX0VOVl9BTFRFUk5BVElWRVMpKSB7XG4gICAgY29uc3QgbmFtZXM6IHJlYWRvbmx5IHN0cmluZ1tdID0gYWx0ZXJuYXRpdmVzO1xuICAgIGlmIChuYW1lID09PSBjYW5vbmljYWwgfHwgbmFtZXMuaW5jbHVkZXMobmFtZSkpIHtcbiAgICAgIHJldHVybiBbLi4ub2JqZWN0LnNlcXVlbmNlKG5hbWUsIGNhbm9uaWNhbCwgYWx0ZXJuYXRpdmVzKS5kaXN0aW5jdCgpXTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIFtuYW1lXTtcbn1cblxuZnVuY3Rpb24gam9pbiguLi5wYXJ0czogc3RyaW5nW10pOiBzdHJpbmcge1xuICByZXR1cm4gcGFydHNcbiAgICAubWFwKChwYXJ0KSA9PiBwYXJ0LnRyaW0oKSlcbiAgICAuZmlsdGVyKEJvb2xlYW4pXG4gICAgLmpvaW4oXCJfXCIpO1xufVxuXG4vKipcbiAqIFJlc29sdmUgYSBzdHJpbmc6IGBjb25maWd1cmVkYCB3aGVuIG5vbi1lbXB0eSwgZWxzZSB7QGxpbmsgdGV4dH0sIGVsc2UgYHVuZGVmaW5lZGAuXG4gKlxuICogVGhlIGNvZXJjaW9uIHJ1bGVzIGFyZSBkZWxpYmVyYXRlbHkgbG9vc2UgKGBvbmAgLyBgeWVzYCAvIGAxYCBhcmUgYWxsXG4gKiBgdHJ1ZWApIGJlY2F1c2UgdmFsdWVzIG1heSBjb21lIGZyb20gYSBmaWxlIGEgaHVtYW4gdHlwZWQuXG4gKlxuICogQGV4YW1wbGVcbiAqIGNvbmZpZy5zdHJpbmcob3B0aW9ucy5ob3N0LCBcIlNNVFBfSE9TVFwiKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN0cmluZyhcbiAgY29uZmlndXJlZDogdW5rbm93bixcbiAgaW5wdXQ6IENvbmZpZ0tleSxcbiAgb3B0aW9ucz86IENvbmZpZ09wdGlvbnMsXG4pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICByZXR1cm4gc3RyaW5nTW9kdWxlLnRyaW1Ub051bGwoY29uZmlndXJlZCkgPz8gdGV4dChpbnB1dCwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhIGJvb2xlYW4gdGhyb3VnaCBgb2JqZWN0LnRvQm9vbGVhbmAuIGB1bmRlZmluZWRgIHdoZW4gbmVpdGhlciBzb3VyY2VcbiAqIGlzIGludGVycHJldGFibGUsIHNvIHRoZSBjYWxsZXIgcGlja3MgYSBkZWZhdWx0IHdpdGggYD8/YC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJvb2xlYW4oXG4gIGNvbmZpZ3VyZWQ6IHVua25vd24sXG4gIGlucHV0OiBDb25maWdLZXksXG4gIG9wdGlvbnM/OiBDb25maWdPcHRpb25zLFxuKTogYm9vbGVhbiB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiBvYmplY3QudG9Cb29sZWFuKGNvbmZpZ3VyZWQpID8/IG9iamVjdC50b0Jvb2xlYW4odGV4dChpbnB1dCwgb3B0aW9ucykpO1xufVxuXG4vKipcbiAqIFJlc29sdmUgYSBwb3NpdGl2ZSBudW1iZXIgdGhhdCBtYXkgYmUgZnJhY3Rpb25hbCAoYSBzY29yZSB0aHJlc2hvbGQsIGEgcmF0aW8pLlxuICogVXNlIHtAbGluayBwb3NpdGl2ZUludH0gZm9yIGEgY291bnQsIHBvcnQsIG9yIHRpbWVvdXQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwb3NpdGl2ZU51bWJlcihcbiAgY29uZmlndXJlZDogdW5rbm93bixcbiAgaW5wdXQ6IENvbmZpZ0tleSxcbiAgZmFsbGJhY2s6IG51bWJlcixcbiAgb3B0aW9ucz86IENvbmZpZ09wdGlvbnMsXG4pOiBudW1iZXIge1xuICByZXR1cm4gdG9Qb3NpdGl2ZU51bWJlcihjb25maWd1cmVkKSA/PyB0b1Bvc2l0aXZlTnVtYmVyKHRleHQoaW5wdXQsIG9wdGlvbnMpKSA/PyBmYWxsYmFjaztcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgcG9zaXRpdmUgaW50ZWdlciAoYSBwb3J0LCBhIHRpbWVvdXQsIGEgcGFnZSBzaXplKSwgZmxvb3JlZC4gQVxuICogbm9uLW51bWVyaWMgb3Igbm9uLXBvc2l0aXZlIHZhbHVlIGlzIHRyZWF0ZWQgYXMgQUJTRU5UIHJhdGhlciB0aGFuIGZhdGFsIC1cbiAqIHRoZXNlIGFyZSBjZWlsaW5ncyB3aGVyZSBhIHNhbmUgZGVmYXVsdCBiZWF0cyBhIGJvb3QgZmFpbHVyZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBvc2l0aXZlSW50KFxuICBjb25maWd1cmVkOiB1bmtub3duLFxuICBpbnB1dDogQ29uZmlnS2V5LFxuICBmYWxsYmFjazogbnVtYmVyLFxuICBvcHRpb25zPzogQ29uZmlnT3B0aW9ucyxcbik6IG51bWJlciB7XG4gIGNvbnN0IHJlc29sdmVkID0gcG9zaXRpdmVOdW1iZXIoY29uZmlndXJlZCwgaW5wdXQsIGZhbGxiYWNrLCBvcHRpb25zKTtcbiAgcmV0dXJuIE1hdGguZmxvb3IocmVzb2x2ZWQpO1xufVxuXG4vKipcbiAqIFJlc29sdmUgYSBsaXN0IHRocm91Z2ggYHN0cmluZy5wYXJzZUxpc3RgLCBzbyBhbiBhcnJheSBmcm9tIHR5cGVkIGNvbmZpZyBhbmQgYVxuICogYFwiYSwgYiBjXCJgIHN0cmluZyBub3JtYWxpemUgaWRlbnRpY2FsbHkuIGBbXWAgd2hlbiBuZWl0aGVyIHNvdXJjZSBoYXMgZW50cmllcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxpc3QoXG4gIGNvbmZpZ3VyZWQ6IHN0cmluZyB8IHJlYWRvbmx5IHN0cmluZ1tdIHwgdW5kZWZpbmVkIHwgbnVsbCxcbiAgaW5wdXQ6IENvbmZpZ0tleSxcbiAgdHJhbnNmb3JtPzogKGVudHJ5OiBzdHJpbmcpID0+IHN0cmluZyxcbiAgb3B0aW9ucz86IENvbmZpZ09wdGlvbnMsXG4pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IGZyb21Db25maWcgPSBzdHJpbmdNb2R1bGUucGFyc2VMaXN0KGNvbmZpZ3VyZWQsIHRyYW5zZm9ybSk7XG4gIHJldHVybiBmcm9tQ29uZmlnLmxlbmd0aCA+IDBcbiAgICA/IGZyb21Db25maWdcbiAgICA6IHN0cmluZ01vZHVsZS5wYXJzZUxpc3QodGV4dChpbnB1dCwgb3B0aW9ucyksIHRyYW5zZm9ybSk7XG59XG5cbmZ1bmN0aW9uIHRvUG9zaXRpdmVOdW1iZXIodmFsdWU6IHVua25vd24pOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICBjb25zdCBwYXJzZWQgPSBvYmplY3QudG9OdW1iZXIodmFsdWUpO1xuICByZXR1cm4gcGFyc2VkICE9PSB1bmRlZmluZWQgJiYgcGFyc2VkID4gMCA/IHBhcnNlZCA6IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBUaGUgRGF0YWJyaWNrcyBidW5kbGUgb3V0cHV0IGZvciBgY3dkYCAtIGBkYXRhYnJpY2tzIGJ1bmRsZSB2YWxpZGF0ZSAtLW91dHB1dFxuICoganNvbmAgcnVuIGZyb20gdGhlIGRpcmVjdG9yeSBob2xkaW5nIGBkYXRhYnJpY2tzLnltbGAsIHdpdGggdGhlIGNvbmZpZyBmaWxlJ3NcbiAqIHBhdGguIEEgbm9uLXplcm8gdmFsaWRhdGlvbiBtYXkgc3RpbGwgcmV0dXJuIHBhcnRpYWwgSlNPTiB3aXRoIHVzYWJsZVxuICogdmFyaWFibGVzLiBgdW5kZWZpbmVkYCB3aGVuIHRoZXJlIGlzIG5vIGJ1bmRsZSwgdGhlIENMSSBwcm9kdWNlcyBubyBKU09OLCBvclxuICogdGhpcyBwcm9jZXNzIGlzIGEgZGVwbG95ZWQgRGF0YWJyaWNrcyBBcHAuXG4gKlxuICogQ2FjaGVkIHBlciB3b3JraW5nIGRpcmVjdG9yeSBhbmQgYERBVEFCUklDS1NfQ09ORklHX1BST0ZJTEVgIHRocm91Z2hcbiAqIHtAbGluayBjb250ZXh0LmNhY2hlZH0sIHNvIGNoYW5naW5nIGVpdGhlciBjYW5ub3QgcmV0dXJuIGFub3RoZXIgY29udGV4dCdzXG4gKiBidW5kbGUuIEEgbG9va3VwIGZvciBzb21lIG90aGVyIGRpcmVjdG9yeSBpcyBub3QgY2FjaGVkIGF0IGFsbC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1bmRsZUZpbGUoY3dkPzogc3RyaW5nIHwgbnVsbCk6IENvbmZpZ0ZpbGUgfCB1bmRlZmluZWQge1xuICBjb25zdCBwcm9maWxlID0gc3RyaW5nTW9kdWxlLnRyaW1Ub051bGwocHJvY2Vzcy5lbnYuREFUQUJSSUNLU19DT05GSUdfUFJPRklMRSk7XG4gIHJldHVybiBjb250ZXh0LmNhY2hlZChcbiAgICBbXCJjb25maWdcIiwgXCJidW5kbGVcIiwgcHJvZmlsZSA/PyBcIlwiXSxcbiAgICAocmVzb2x2ZWQpID0+IGxvYWRCdW5kbGVGaWxlKHJlc29sdmVkID8/IFwiLlwiLCBwcm9maWxlKSxcbiAgICBjd2QsXG4gICk7XG59XG5cbi8qKlxuICogVGhlIHNpbmdsZSBBcHAncyBsaXRlcmFsIGBjb25maWcuZW52YCBlbnRyaWVzLCBmbGF0dGVuZWQgdG8gYG5hbWUgLT4gdmFsdWVgLlxuICpcbiAqIEEgYHZhbHVlX2Zyb21gIGVudHJ5IG5hbWVzIGEgYnVuZGxlIHJlc291cmNlIHdob3NlIGlkIGlzIGtub3duIGFmdGVyXG4gKiBkZXBsb3ltZW50LCBhbmQgcmVhZGluZyBpdCBuZWVkcyB0aGUgcmVzb3VyY2Ugdm9jYWJ1bGFyeSB0aGlzIG1vZHVsZVxuICogZGVsaWJlcmF0ZWx5IGRvZXMgbm90IGhhdmUgLSBub2RlLWFwcGtpdCByZXNvbHZlcyB0aG9zZSBhZ2FpbnN0IGl0cyBleHRlbmRlZFxuICoge0BsaW5rIGJ1bmRsZVJlc291cmNlU2NoZW1hfS4gQW4gYGFwcHNgIGJsb2NrIHdpdGggbW9yZSB0aGFuIG9uZSBhcHAgaXNcbiAqIGFtYmlndW91cyAobm90aGluZyBoZXJlIHNheXMgd2hpY2ggYXBwIHRoaXMgcHJvY2VzcyBpcyksIHNvIGl0IHlpZWxkcyBub3RoaW5nXG4gKiByYXRoZXIgdGhhbiBhIGd1ZXNzLlxuICovXG5mdW5jdGlvbiBidW5kbGVBcHAoaW5wdXQ6IHVua25vd24pOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgY29uc3QgcGFyc2VkID0gYnVuZGxlQXBwc1NjaGVtYS5zYWZlUGFyc2UoaW5wdXQpO1xuICBpZiAoIXBhcnNlZC5zdWNjZXNzKSByZXR1cm4ge307XG4gIGNvbnN0IGFwcHMgPSBwYXJzZWQuZGF0YS5yZXNvdXJjZXM/LmFwcHM7XG4gIGlmICghYXBwcykgcmV0dXJuIHt9O1xuICBjb25zdCBuYW1lcyA9IE9iamVjdC5rZXlzKGFwcHMpO1xuICBpZiAobmFtZXMubGVuZ3RoICE9PSAxKSByZXR1cm4ge307XG4gIGNvbnN0IGVudHJpZXMgPSBhcHBzW25hbWVzWzBdIV0/LmNvbmZpZz8uZW52ID8/IFtdO1xuICBjb25zdCByZXN1bHQ6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgZm9yIChjb25zdCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgaWYgKCFlbnRyeS5uYW1lKSBjb250aW51ZTtcbiAgICBjb25zdCB2YWx1ZSA9IHJlc29sdmVkU3RyaW5nKGVudHJ5LnZhbHVlKTtcbiAgICBpZiAodmFsdWUgIT09IG51bGwpIHJlc3VsdFtlbnRyeS5uYW1lXSA9IHZhbHVlO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogUm9vdCBidW5kbGUgdmFyaWFibGVzIGZsYXR0ZW5lZCB0byBlbnZpcm9ubWVudC1zdHlsZSBgTkFNRSAtPiB2YWx1ZWAgZW50cmllcy5cbiAqXG4gKiBgZGF0YWJyaWNrcyBidW5kbGUgdmFsaWRhdGVgIHJlc29sdmVzIGVhY2ggdmFyaWFibGUgdG8gYHZhbHVlYDsgYGRlZmF1bHRgIGlzXG4gKiByZXRhaW5lZCBhcyBhIGZhbGxiYWNrIGZvciBwYXJzZWQgYnVuZGxlIGRhdGEgdGhhdCBoYXMgbm90IGJlZW4gZnVsbHlcbiAqIHJlc29sdmVkLiBOYW1lcyBhcmUgbm9ybWFsaXplZCBzbyBhIGJ1bmRsZSB2YXJpYWJsZSBzdWNoIGFzXG4gKiBgdHVubmVsX3B1YmxpY19kb21haW5gIGFuc3dlcnMgYSBsb29rdXAgZm9yIGBUVU5ORUxfUFVCTElDX0RPTUFJTmAuXG4gKi9cbmZ1bmN0aW9uIGJ1bmRsZVZhcmlhYmxlcyhpbnB1dDogdW5rbm93bik6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4ge1xuICBjb25zdCBwYXJzZWQgPSBidW5kbGVWYXJpYWJsZXNTY2hlbWEuc2FmZVBhcnNlKGlucHV0KTtcbiAgaWYgKCFwYXJzZWQuc3VjY2VzcykgcmV0dXJuIHt9O1xuICBjb25zdCByZXN1bHQ6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgZm9yIChjb25zdCBbbmFtZSwgdmFyaWFibGVdIG9mIE9iamVjdC5lbnRyaWVzKHBhcnNlZC5kYXRhLnZhcmlhYmxlcyA/PyB7fSkpIHtcbiAgICBjb25zdCBrZXkgPSBbLi4uc3RyaW5nTW9kdWxlLnRva2VuaXplKG5hbWUpXS5qb2luKFwiX1wiKS50b1VwcGVyQ2FzZSgpO1xuICAgIGNvbnN0IHZhbHVlID0gcmVzb2x2ZWRTdHJpbmcodmFyaWFibGUudmFsdWUpID8/IHJlc29sdmVkU3RyaW5nKHZhcmlhYmxlLmRlZmF1bHQpO1xuICAgIGlmIChrZXkgJiYgdmFsdWUgIT09IG51bGwpIHJlc3VsdFtrZXldID0gdmFsdWU7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqIEEgbm9uLWVtcHR5IGJ1bmRsZSB2YWx1ZSB3aXRoIGV2ZXJ5IGAkey4uLn1gIGludGVycG9sYXRpb24gcmVzb2x2ZWQuICovXG5mdW5jdGlvbiByZXNvbHZlZFN0cmluZyh2YWx1ZTogdW5rbm93bik6IHN0cmluZyB8IG51bGwge1xuICBjb25zdCBwYXJzZWQgPSBidW5kbGVWYWx1ZS5zYWZlUGFyc2UodmFsdWUpO1xuICByZXR1cm4gcGFyc2VkLnN1Y2Nlc3MgPyBwYXJzZWQuZGF0YSA6IG51bGw7XG59XG5cbi8qKiBQYXJzZWQgYC5lbnZgIGZvciBgY3dkYCwgb3IgYHt9YC4gQ2FjaGVkIHBlciB3b3JraW5nIGRpcmVjdG9yeS4gKi9cbmZ1bmN0aW9uIGRvdGVudihjd2Q/OiBzdHJpbmcgfCBudWxsKTogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IGVudmlyb25tZW50cyA9IG5vZGVFbnZOYW1lcyhwcm9jZXNzLmVudi5OT0RFX0VOVik7XG4gIHJldHVybiBjb250ZXh0LmNhY2hlZChcbiAgICBbXCJjb25maWdcIiwgXCJkb3RlbnZcIiwgLi4uZW52aXJvbm1lbnRzXSxcbiAgICAocmVzb2x2ZWQpID0+IGxvYWREb3RlbnYocmVzb2x2ZWQgPz8gXCIuXCIsIGVudmlyb25tZW50cyksXG4gICAgY3dkLFxuICApO1xufVxuXG4vKipcbiAqIE1hcHMgZm9yIG9uZSBzb3VyY2UgaW4gcHJlY2VkZW5jZSBvcmRlci4gQnVuZGxlIEFwcCBjb25maWcgYW5kIHJvb3QgdmFyaWFibGVzXG4gKiBzdGF5IHNlcGFyYXRlIHNvIGEgZmlyc3QtbWF0Y2ggbG9va3VwIGRvZXMgbm90IHBhcnNlIHZhcmlhYmxlcyBhZnRlciBhbiBBcHBcbiAqIHZhbHVlIHJlc29sdmVzLlxuICovXG5mdW5jdGlvbiByZWFkKFxuICBzb3VyY2U6IENvbmZpZ1NvdXJjZSxcbiAgY3dkPzogc3RyaW5nLFxuKTogb2JqZWN0LlNlcXVlbmNlPFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHVuZGVmaW5lZD4+IHtcbiAgcmV0dXJuIG9iamVjdC5zZXF1ZW5jZSh7XG4gICAgKltTeW1ib2wuaXRlcmF0b3JdKCk6IEdlbmVyYXRvcjxSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+PiB7XG4gICAgICBzd2l0Y2ggKHNvdXJjZSkge1xuICAgICAgICBjYXNlIFwiZW52XCI6XG4gICAgICAgICAgeWllbGQgcHJvY2Vzcy5lbnY7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJkb3RlbnZcIjpcbiAgICAgICAgICB5aWVsZCBkb3RlbnYoY3dkKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcImJ1bmRsZVwiOiB7XG4gICAgICAgICAgY29uc3QgYnVuZGxlID0gYnVuZGxlRmlsZShjd2QpO1xuICAgICAgICAgIGlmIChidW5kbGUpIHtcbiAgICAgICAgICAgIHlpZWxkIGJ1bmRsZUFwcChidW5kbGUuZGF0YSk7XG4gICAgICAgICAgICB5aWVsZCBidW5kbGVWYXJpYWJsZXMoYnVuZGxlLmRhdGEpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gIH0pO1xufVxuXG4vKipcbiAqIExvY2F0ZSBgbmFtZXNgIGZyb20gYGN3ZGAgb3V0d2FyZC4gYGN3ZGAgaXRzZWxmIGlzIGNoZWNrZWQgYmVmb3JlIHRoZVxuICogZGlzY292ZXJlZCBwcm9qZWN0IHJvb3RzIHNvIGEgcGFja2FnZS1sb2NhbCBmaWxlIHdpbnMgb3ZlciB0aGUgd29ya3NwYWNlJ3MuXG4gKi9cbmZ1bmN0aW9uIGZpbmRDb25maWdGaWxlKGN3ZDogc3RyaW5nLCBuYW1lczogcmVhZG9ubHkgc3RyaW5nW10pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBpZiAoaXNEYXRhYnJpY2tzQXBwRW52KCkpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IHN0YXJ0ID0gcmVzb2x2ZShjd2QpO1xuICBjb25zdCByb290ID0gcmVzb2x2ZVByb2plY3RSb290KHN0YXJ0KTtcbiAgY29uc3QgcGF0aEZyb21Sb290ID0gcm9vdCA/IHJlbGF0aXZlKHJvb3QsIHN0YXJ0KSA6IHVuZGVmaW5lZDtcbiAgY29uc3QgYm91bmRhcnkgPVxuICAgIHJvb3QgJiZcbiAgICBwYXRoRnJvbVJvb3QgIT09IHVuZGVmaW5lZCAmJlxuICAgICFpc0Fic29sdXRlKHBhdGhGcm9tUm9vdCkgJiZcbiAgICBwYXRoRnJvbVJvb3QgIT09IFwiLi5cIiAmJlxuICAgICFwYXRoRnJvbVJvb3Quc3RhcnRzV2l0aChgLi4ke3NlcH1gKVxuICAgICAgPyByb290XG4gICAgICA6IHVuZGVmaW5lZDtcbiAgZm9yIChsZXQgZGlyID0gc3RhcnQ7IDsgZGlyID0gZGlybmFtZShkaXIpKSB7XG4gICAgZm9yIChjb25zdCBuYW1lIG9mIG5hbWVzKSB7XG4gICAgICBjb25zdCBwYXRoID0gcmVzb2x2ZShkaXIsIG5hbWUpO1xuICAgICAgaWYgKHN0YXRTeW5jKHBhdGgpPy5pc0ZpbGUoKSkgcmV0dXJuIHBhdGg7XG4gICAgfVxuICAgIGlmIChib3VuZGFyeSA9PT0gdW5kZWZpbmVkIHx8IGRpciA9PT0gYm91bmRhcnkpIGJyZWFrO1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIGxvYWREb3RlbnYoXG4gIGN3ZDogc3RyaW5nLFxuICBlbnZpcm9ubWVudHM6IHJlYWRvbmx5IHN0cmluZ1tdLFxuKTogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IG5hbWVzID0gWy4uLmVudmlyb25tZW50cy5tYXAoKG5hbWUpID0+IGAke0RPVEVOVl9GSUxFX05BTUV9LiR7bmFtZX1gKSwgRE9URU5WX0ZJTEVfTkFNRV07XG4gIGNvbnN0IHBhdGggPSBmaW5kQ29uZmlnRmlsZShjd2QsIG5hbWVzKTtcbiAgaWYgKCFwYXRoKSByZXR1cm4ge307XG4gIHRyeSB7XG4gICAgcmV0dXJuIHBhcnNlRW52KHJlYWRGaWxlU3luYyhwYXRoLCBcInV0ZjhcIikpO1xuICB9IGNhdGNoIHtcbiAgICBsb2dnZXIud2FybihcImZhaWxlZCB0byByZWFkIGRvdGVudiBmaWxlXCIsIHsgcGF0aCB9KTtcbiAgICByZXR1cm4ge307XG4gIH1cbn1cblxuZnVuY3Rpb24gbG9hZEJ1bmRsZUZpbGUoY3dkOiBzdHJpbmcsIHByb2ZpbGU6IHN0cmluZyB8IG51bGwpOiBDb25maWdGaWxlIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcGF0aCA9IGZpbmRDb25maWdGaWxlKGN3ZCwgQlVORExFX0ZJTEVfTkFNRVMpO1xuICBpZiAoIXBhdGgpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IGFyZ3MgPSBbXG4gICAgXCJidW5kbGVcIixcbiAgICBcInZhbGlkYXRlXCIsXG4gICAgXCItLW91dHB1dFwiLFxuICAgIFwianNvblwiLFxuICAgIC4uLihwcm9maWxlID09PSBudWxsID8gW10gOiBbXCItLXByb2ZpbGVcIiwgcHJvZmlsZV0pLFxuICBdO1xuICBjb25zdCByZXN1bHQgPSBzcGF3blN5bmMoXCJkYXRhYnJpY2tzXCIsIGFyZ3MsIHtcbiAgICBjd2Q6IHJlc29sdmUocGF0aCwgXCIuLlwiKSxcbiAgICBlbmNvZGluZzogXCJ1dGY4XCIsXG4gICAgc3RkaW86IFtcImlnbm9yZVwiLCBcInBpcGVcIiwgXCJwaXBlXCJdLFxuICB9KTtcbiAgY29uc3Qgb3V0cHV0ID0gc3RyaW5nTW9kdWxlLnRyaW1Ub051bGwocmVzdWx0LnN0ZG91dCk7XG4gIGNvbnN0IGVycm9yID0gc3RyaW5nTW9kdWxlLnRyaW1Ub051bGwocmVzdWx0LnN0ZGVycik7XG4gIGlmIChvdXRwdXQgPT09IG51bGwpIHtcbiAgICBsb2dnZXIuZGVidWcoXCJidW5kbGUgdmFsaWRhdGUgcHJvZHVjZWQgbm8gSlNPTlwiLCB7IHBhdGgsIHN0YXR1czogcmVzdWx0LnN0YXR1cywgZXJyb3IgfSk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICBjb25zdCBkYXRhID0ganNvbi5wYXJzZVJlY29yZChvdXRwdXQpO1xuICBpZiAoIWRhdGEpIHtcbiAgICBsb2dnZXIud2FybihcImZhaWxlZCB0byBwYXJzZSBidW5kbGUgdmFsaWRhdGUgb3V0cHV0XCIsIHsgcGF0aCwgc3RhdHVzOiByZXN1bHQuc3RhdHVzIH0pO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgaWYgKHJlc3VsdC5zdGF0dXMgIT09IDApIHtcbiAgICBsb2dnZXIuZGVidWcoXCJ1c2luZyBwYXJ0aWFsIGJ1bmRsZSBvdXRwdXRcIiwgeyBwYXRoLCBzdGF0dXM6IHJlc3VsdC5zdGF0dXMsIGVycm9yIH0pO1xuICB9XG4gIHJldHVybiB7IHBhdGgsIGRhdGEgfTtcbn1cbiJdfQ==
|