@dbx-tools/core 0.6.82 → 0.6.86

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