@dbx-tools/core 0.9.5 → 0.9.6
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 +13 -13
- package/index.ts +9 -9
- package/lib/index.d.ts +9 -9
- package/lib/index.js +7 -7
- package/lib/src/bin.js +3 -3
- package/lib/src/{brand.d.ts → brand-files.d.ts} +6 -6
- package/lib/src/brand-files.js +66 -0
- package/lib/src/bundle.js +6 -6
- package/lib/src/{config.d.ts → config-utils.d.ts} +1 -1
- package/lib/src/config-utils.js +583 -0
- package/lib/src/file-lock.js +7 -7
- package/lib/src/process-lock.js +3 -3
- package/lib/src/{project.d.ts → project-utils.d.ts} +1 -0
- package/lib/src/project-utils.js +296 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +27 -2
- package/src/bin.ts +2 -2
- package/src/{brand.ts → brand-files.ts} +11 -11
- package/src/bundle.ts +5 -5
- package/src/{config.ts → config-utils.ts} +27 -44
- package/src/file-lock.ts +6 -6
- package/src/process-lock.ts +2 -2
- package/src/{project.ts → project-utils.ts} +5 -4
- package/lib/src/brand.js +0 -66
- package/lib/src/config.js +0 -595
- package/lib/src/project.js +0 -295
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layered configuration lookup: environment, `.env`, bundle, and `app.yaml`.
|
|
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, one App's `resources.apps.<app>.config.env` in
|
|
7
|
+
* `databricks.yml`, and literal env values in `app.yaml` / `app.yml`.
|
|
8
|
+
*
|
|
9
|
+
* {@link values} is LAZY (an `object.Sequence`), so `databricks bundle validate`
|
|
10
|
+
* is only spawned when the environment and `.env` both missed; app YAML is only
|
|
11
|
+
* read after the bundle source also missed.
|
|
12
|
+
*
|
|
13
|
+
* Inside a deployed Databricks App all three file sources are skipped by default
|
|
14
|
+
* ({@link isDatabricksAppEnv}): the platform has already turned them into real
|
|
15
|
+
* environment variables, there is no bundle to validate, and the `databricks`
|
|
16
|
+
* CLI is not on the image. Boolean environment overrides can force either file
|
|
17
|
+
* source on or off when a tool needs different behavior.
|
|
18
|
+
*
|
|
19
|
+
* Only the single bundle app's `config.env` and literal app YAML `env[].value`
|
|
20
|
+
* entries are consulted. Root bundle `variables` are not: they are authoring
|
|
21
|
+
* inputs for the bundle itself (interpolated into targets, resources, and paths),
|
|
22
|
+
* so treating one as a process setting resolves names the deployed app never sees.
|
|
23
|
+
*
|
|
24
|
+
* Node-only (`child_process`, `fs`, `process`).
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
27
|
+
*/
|
|
28
|
+
import { spawnSync } from "node:child_process";
|
|
29
|
+
import { readFileSync } from "node:fs";
|
|
30
|
+
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
31
|
+
import { parseEnv } from "node:util";
|
|
32
|
+
import { isDatabricksAppEnvironment } from "@dbx-tools/core-rs";
|
|
33
|
+
import { json, log, object, stringUtils } from "@dbx-tools/shared-core";
|
|
34
|
+
import { parse as parseYaml } from "yaml";
|
|
35
|
+
import { z } from "zod";
|
|
36
|
+
import { cachedRecord, statSync } from "./file.js";
|
|
37
|
+
import { resolveWorkingDirectory, root as resolveProjectRoot } from "./project-utils.js";
|
|
38
|
+
const logger = log.logger("config");
|
|
39
|
+
const configFileCache = new Map();
|
|
40
|
+
const DEFAULT_SCOPE = "DBX_TOOLS";
|
|
41
|
+
const DEFAULT_SOURCES = ["config", "env", "dotenv", "bundle", "app"];
|
|
42
|
+
const BUNDLE_FILE_NAMES = ["databricks.yml", "databricks.yaml"];
|
|
43
|
+
const APP_FILE_NAMES = ["app.yaml", "app.yml"];
|
|
44
|
+
const DOTENV_FILE_NAME = ".env";
|
|
45
|
+
const NODE_ENV_ALTERNATIVES = {
|
|
46
|
+
production: ["prod"],
|
|
47
|
+
development: ["dev"],
|
|
48
|
+
};
|
|
49
|
+
/** Highest valid TCP port number. */
|
|
50
|
+
export const MAX_TCP_PORT = 65_535;
|
|
51
|
+
/** Boolean environment override for project `.env` reads. */
|
|
52
|
+
const CONFIG_DOTENV_KEY = "DBX_TOOLS_CONFIG_DOTENV";
|
|
53
|
+
/** Boolean environment override for Databricks bundle reads. */
|
|
54
|
+
const CONFIG_BUNDLE_KEY = "DBX_TOOLS_CONFIG_BUNDLE";
|
|
55
|
+
/** Boolean environment override for Databricks App YAML reads. */
|
|
56
|
+
const CONFIG_APP_KEY = "DBX_TOOLS_CONFIG_APP";
|
|
57
|
+
/** Exact process-environment lookup for callers that do not read local config files. */
|
|
58
|
+
export const ENV_ONLY = { scope: [], sources: "env" };
|
|
59
|
+
export const valueSchema = z
|
|
60
|
+
.string()
|
|
61
|
+
.trim()
|
|
62
|
+
.min(1)
|
|
63
|
+
.refine((value) => !/\$\{[^}]+\}/.test(value), {
|
|
64
|
+
message: "Interpolated values are not allowed",
|
|
65
|
+
});
|
|
66
|
+
const portValueSchema = z.preprocess((input) => {
|
|
67
|
+
if (typeof input === "number")
|
|
68
|
+
return input;
|
|
69
|
+
if (typeof input !== "string" || !/^\d+$/.test(input.trim()))
|
|
70
|
+
return Number.NaN;
|
|
71
|
+
return Number(input.trim());
|
|
72
|
+
}, z.number().int().min(1).max(MAX_TCP_PORT));
|
|
73
|
+
const positiveNumberValue = z.preprocess((input) => object.toNumber(input), z.number().positive());
|
|
74
|
+
const positiveIntValue = positiveNumberValue.transform(Math.floor);
|
|
75
|
+
/** A named bundle or App resource; concrete resource fields pass through. */
|
|
76
|
+
export const bundleResourceSchema = z.object({ name: valueSchema.optional() }).passthrough();
|
|
77
|
+
export const bundleEnvEntrySchema = z.object({
|
|
78
|
+
name: valueSchema.optional(),
|
|
79
|
+
value: z.string().optional(),
|
|
80
|
+
value_from: valueSchema.optional(),
|
|
81
|
+
});
|
|
82
|
+
export const bundleAppSchema = z.object({
|
|
83
|
+
name: valueSchema.optional(),
|
|
84
|
+
config: z.object({ env: z.array(bundleEnvEntrySchema).optional() }).optional(),
|
|
85
|
+
resources: z.array(bundleResourceSchema).optional(),
|
|
86
|
+
});
|
|
87
|
+
export const appEnvEntrySchema = z.object({
|
|
88
|
+
name: valueSchema,
|
|
89
|
+
value: z.string().optional(),
|
|
90
|
+
valueFrom: valueSchema.optional(),
|
|
91
|
+
});
|
|
92
|
+
export const appSchema = z.object({
|
|
93
|
+
env: z.array(appEnvEntrySchema).optional(),
|
|
94
|
+
resources: z.array(bundleResourceSchema).optional(),
|
|
95
|
+
});
|
|
96
|
+
const bundleConfigSchema = z.object({
|
|
97
|
+
resources: z.object({ apps: z.record(z.string(), bundleAppSchema).optional() }).optional(),
|
|
98
|
+
});
|
|
99
|
+
/** Flatten the single bundle App's `config.env`, resolving resource references. */
|
|
100
|
+
export function flattenBundleEnv(data) {
|
|
101
|
+
const parsed = bundleConfigSchema.safeParse(data);
|
|
102
|
+
if (!parsed.success)
|
|
103
|
+
return {};
|
|
104
|
+
const apps = Object.values(parsed.data.resources?.apps ?? {});
|
|
105
|
+
if (apps.length !== 1)
|
|
106
|
+
return {};
|
|
107
|
+
const app = apps[0];
|
|
108
|
+
const resources = new Map((app?.resources ?? [])
|
|
109
|
+
.filter((resource) => resource.name)
|
|
110
|
+
.map((resource) => [resource.name, resource]));
|
|
111
|
+
const result = {};
|
|
112
|
+
for (const entry of app?.config?.env ?? []) {
|
|
113
|
+
if (!entry.name)
|
|
114
|
+
continue;
|
|
115
|
+
const literal = valueSchema.safeParse(entry.value);
|
|
116
|
+
if (literal.success) {
|
|
117
|
+
result[entry.name] = literal.data;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const referenced = entry.value_from
|
|
121
|
+
? resourceValue(resources.get(entry.value_from))
|
|
122
|
+
: undefined;
|
|
123
|
+
if (referenced)
|
|
124
|
+
result[entry.name] = referenced;
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
/** Flatten `app.yaml` env entries, resolving `valueFrom` resource references. */
|
|
129
|
+
export function flattenAppEnv(data) {
|
|
130
|
+
const parsed = appSchema.safeParse(data);
|
|
131
|
+
if (!parsed.success)
|
|
132
|
+
return {};
|
|
133
|
+
const resources = new Map((parsed.data.resources ?? [])
|
|
134
|
+
.filter((resource) => resource.name)
|
|
135
|
+
.map((resource) => [resource.name, resource]));
|
|
136
|
+
const result = {};
|
|
137
|
+
for (const entry of parsed.data.env ?? []) {
|
|
138
|
+
const literal = valueSchema.safeParse(entry.value);
|
|
139
|
+
if (literal.success) {
|
|
140
|
+
result[entry.name] = literal.data;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const referenced = entry.valueFrom ? resourceValue(resources.get(entry.valueFrom)) : undefined;
|
|
144
|
+
if (referenced)
|
|
145
|
+
result[entry.name] = referenced;
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
function resourceValue(resource) {
|
|
150
|
+
for (const path of [
|
|
151
|
+
["sql_warehouse", "id"],
|
|
152
|
+
["genie_space", "space_id"],
|
|
153
|
+
["postgres", "endpoint"],
|
|
154
|
+
["postgres", "database"],
|
|
155
|
+
["postgres", "branch"],
|
|
156
|
+
]) {
|
|
157
|
+
let value = resource;
|
|
158
|
+
for (const part of path)
|
|
159
|
+
value = object.isRecord(value) ? value[part] : undefined;
|
|
160
|
+
const parsed = valueSchema.safeParse(value);
|
|
161
|
+
if (parsed.success)
|
|
162
|
+
return parsed.data;
|
|
163
|
+
}
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
/** Walk a dot-separated path through parsed bundle data. */
|
|
167
|
+
export function getBundlePath(data, path) {
|
|
168
|
+
const parts = path.split(".").filter(Boolean);
|
|
169
|
+
if (parts.length === 0)
|
|
170
|
+
return undefined;
|
|
171
|
+
let current = data;
|
|
172
|
+
for (let index = 0; index < parts.length; index++) {
|
|
173
|
+
if (!object.isRecord(current))
|
|
174
|
+
return undefined;
|
|
175
|
+
const next = current[parts[index]];
|
|
176
|
+
if (index === parts.length - 1) {
|
|
177
|
+
const direct = valueSchema.safeParse(next);
|
|
178
|
+
if (direct.success)
|
|
179
|
+
return direct.data;
|
|
180
|
+
if (object.isRecord(next)) {
|
|
181
|
+
const nested = valueSchema.safeParse(next.value);
|
|
182
|
+
return nested.success ? nested.data : undefined;
|
|
183
|
+
}
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
current = next;
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Detect a Databricks App runtime from its required name, host, and port.
|
|
192
|
+
*
|
|
193
|
+
* `DBX_TOOLS_DATABRICKS_APP_ENV` takes precedence when it contains a recognized
|
|
194
|
+
* boolean value. This lets local tools emulate the deployed runtime (`true`) or
|
|
195
|
+
* lets unusual deployed processes retain local config lookup (`false`). An
|
|
196
|
+
* absent or unrecognized override falls back to structural detection.
|
|
197
|
+
*/
|
|
198
|
+
export function isDatabricksAppEnv(source = process.env) {
|
|
199
|
+
return isDatabricksAppEnvironment(new Map(Object.entries(source).filter((entry) => entry[1] !== undefined)));
|
|
200
|
+
}
|
|
201
|
+
/** Exact, uppercase, and tokenized-uppercase names for a human-friendly key. */
|
|
202
|
+
export function environmentKeys(name) {
|
|
203
|
+
const trimmed = name.trim();
|
|
204
|
+
if (!trimmed)
|
|
205
|
+
return [];
|
|
206
|
+
return object
|
|
207
|
+
.sequence(trimmed, trimmed.toUpperCase(), Array.from(stringUtils.tokenize(trimmed)).join("_").toUpperCase())
|
|
208
|
+
.filter(Boolean)
|
|
209
|
+
.distinct()
|
|
210
|
+
.toArray();
|
|
211
|
+
}
|
|
212
|
+
/** Candidate names in scope, prefix, and input precedence order. */
|
|
213
|
+
function keys(input, options = {}) {
|
|
214
|
+
const scopes = object
|
|
215
|
+
.sequence(options.scope ?? DEFAULT_SCOPE)
|
|
216
|
+
.map(stringUtils.trimToEmpty)
|
|
217
|
+
.filter(Boolean)
|
|
218
|
+
.distinct()
|
|
219
|
+
.toArray();
|
|
220
|
+
const prefixes = options.prefix === undefined
|
|
221
|
+
? []
|
|
222
|
+
: object
|
|
223
|
+
.sequence(options.prefix)
|
|
224
|
+
.map(stringUtils.trimToEmpty)
|
|
225
|
+
.filter(Boolean)
|
|
226
|
+
.distinct()
|
|
227
|
+
.toArray();
|
|
228
|
+
return object
|
|
229
|
+
.sequence(input)
|
|
230
|
+
.map(stringUtils.trimToEmpty)
|
|
231
|
+
.filter(Boolean)
|
|
232
|
+
.distinct()
|
|
233
|
+
.flatMap((key) => {
|
|
234
|
+
const prefixed = prefixes.length > 0 ? prefixes.map((prefix) => `${prefix}_${key}`) : [key];
|
|
235
|
+
return [
|
|
236
|
+
...scopes.flatMap((scope) => prefixed.map((name) => `${scope}_${name}`)),
|
|
237
|
+
...prefixed,
|
|
238
|
+
key,
|
|
239
|
+
];
|
|
240
|
+
})
|
|
241
|
+
.distinct()
|
|
242
|
+
.toArray();
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Every value that resolves for `input`, in source-then-key precedence order,
|
|
246
|
+
* as a LAZY sequence: nothing past the first consumed element is read, so
|
|
247
|
+
* `values(key).at(0)` never spawns the Databricks CLI when the environment
|
|
248
|
+
* already answered.
|
|
249
|
+
*
|
|
250
|
+
*/
|
|
251
|
+
function values(input, options = {}) {
|
|
252
|
+
const candidates = keys(input, options);
|
|
253
|
+
const sources = configSources(options);
|
|
254
|
+
return object.sequence({
|
|
255
|
+
*[Symbol.iterator]() {
|
|
256
|
+
for (const source of sources) {
|
|
257
|
+
for (const map of read(source, options)) {
|
|
258
|
+
for (const key of candidates) {
|
|
259
|
+
const value = configMapValue(map[key]);
|
|
260
|
+
if (value !== null)
|
|
261
|
+
yield { key, source, value };
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
function configSources(options) {
|
|
269
|
+
const sources = [
|
|
270
|
+
...object.sequence(options.sources ?? DEFAULT_SOURCES).distinct(),
|
|
271
|
+
];
|
|
272
|
+
if (options.data !== undefined && options.sources !== undefined && !sources.includes("config")) {
|
|
273
|
+
sources.push("config");
|
|
274
|
+
}
|
|
275
|
+
return sources;
|
|
276
|
+
}
|
|
277
|
+
function configMapValue(value) {
|
|
278
|
+
if (Array.isArray(value)) {
|
|
279
|
+
for (const entry of value) {
|
|
280
|
+
const resolved = stringUtils.trimToNull(entry);
|
|
281
|
+
if (resolved !== null)
|
|
282
|
+
return resolved;
|
|
283
|
+
}
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
return stringUtils.trimToNull(value);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* The first value that resolves for `input`, or `undefined`.
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* const domain = config.text(["TUNNEL_PUBLIC_DOMAIN", "PUBLIC_DOMAIN"]);
|
|
293
|
+
*/
|
|
294
|
+
export function text(input, options = {}) {
|
|
295
|
+
return values(input, options).at(0)?.value;
|
|
296
|
+
}
|
|
297
|
+
/** Resolve a human-friendly name through {@link environmentKeys} and {@link text}. */
|
|
298
|
+
export function resolveValue(name, options = {}) {
|
|
299
|
+
return text(environmentKeys(name), options);
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* The PRIMARY (fully-scoped) name for `input` - what to print in a log line or an
|
|
303
|
+
* error, so the message names the variable a reader should set. Do not index
|
|
304
|
+
* `keys(...)[0]` for this if `input` may be a bare string.
|
|
305
|
+
*
|
|
306
|
+
* @example
|
|
307
|
+
* logger.warn(`${config.name(JWT_SECRET_ENV)} is not set`);
|
|
308
|
+
*/
|
|
309
|
+
export function name(input, options = {}) {
|
|
310
|
+
return keys(input, options)[0] ?? "";
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Safe `.env.<name>` suffixes for a Node environment, exact spelling first.
|
|
314
|
+
* Known long and short names are interchangeable; unknown names pass through.
|
|
315
|
+
*/
|
|
316
|
+
function nodeEnvNames(nodeEnv) {
|
|
317
|
+
const name = stringUtils.trimToNull(nodeEnv)?.toLowerCase();
|
|
318
|
+
if (!name || !/^[a-z0-9_-]+$/.test(name))
|
|
319
|
+
return [];
|
|
320
|
+
for (const [canonical, alternatives] of Object.entries(NODE_ENV_ALTERNATIVES)) {
|
|
321
|
+
const names = alternatives;
|
|
322
|
+
if (name === canonical || names.includes(name)) {
|
|
323
|
+
return [...object.sequence(name, canonical, alternatives).distinct()];
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return [name];
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Resolve a string: `configured` when non-empty, else {@link text}, else `undefined`.
|
|
330
|
+
*
|
|
331
|
+
* The coercion rules are deliberately loose (`on` / `yes` / `1` are all
|
|
332
|
+
* `true`) because values may come from a file a human typed.
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* config.string(options.host, "SMTP_HOST");
|
|
336
|
+
*/
|
|
337
|
+
export function string(configured, input, options) {
|
|
338
|
+
return stringUtils.trimToNull(configured) ?? text(input, options);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Resolve a boolean through `object.toBoolean`. `undefined` when neither source
|
|
342
|
+
* is interpretable, so the caller picks a default with `??`.
|
|
343
|
+
*/
|
|
344
|
+
export function boolean(configured, input, options) {
|
|
345
|
+
return object.toBoolean(configured) ?? object.toBoolean(text(input, options));
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Resolve a positive number that may be fractional (a score threshold, a ratio).
|
|
349
|
+
* Use {@link positiveInt} for a count, port, or timeout.
|
|
350
|
+
*/
|
|
351
|
+
export function positiveNumber(configured, input, fallback, options) {
|
|
352
|
+
const fromConfig = positiveNumberValue.safeParse(configured);
|
|
353
|
+
if (fromConfig.success)
|
|
354
|
+
return fromConfig.data;
|
|
355
|
+
const fromSources = positiveNumberValue.safeParse(text(input, options));
|
|
356
|
+
return fromSources.success ? fromSources.data : fallback;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Resolve a positive integer (a port, a timeout, a page size), floored. A
|
|
360
|
+
* non-numeric or non-positive value is treated as ABSENT rather than fatal -
|
|
361
|
+
* these are ceilings where a sane default beats a boot failure.
|
|
362
|
+
*/
|
|
363
|
+
export function positiveInt(configured, input, fallback, options) {
|
|
364
|
+
const fromConfig = positiveIntValue.safeParse(configured);
|
|
365
|
+
if (fromConfig.success)
|
|
366
|
+
return fromConfig.data;
|
|
367
|
+
const fromSources = positiveIntValue.safeParse(text(input, options));
|
|
368
|
+
return fromSources.success ? fromSources.data : Math.floor(fallback);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Resolve a TCP port between 1 and {@link MAX_TCP_PORT}. Invalid configured or
|
|
372
|
+
* sourced values fall back to the caller's default, which may be a sentinel
|
|
373
|
+
* such as `0` when the caller uses one.
|
|
374
|
+
*/
|
|
375
|
+
export function port(configured, input, fallback, options) {
|
|
376
|
+
const fromConfig = portValueSchema.safeParse(configured);
|
|
377
|
+
if (fromConfig.success)
|
|
378
|
+
return fromConfig.data;
|
|
379
|
+
const fromSources = portValueSchema.safeParse(text(input, options));
|
|
380
|
+
return fromSources.success ? fromSources.data : fallback;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Resolve a list through `stringUtils.parseList`, so an array from typed config and a
|
|
384
|
+
* `"a, b c"` string normalize identically. `[]` when neither source has entries.
|
|
385
|
+
*/
|
|
386
|
+
export function list(configured, input, transform, options) {
|
|
387
|
+
const fromConfig = stringUtils.parseList(configured, transform);
|
|
388
|
+
return fromConfig.length > 0
|
|
389
|
+
? fromConfig
|
|
390
|
+
: stringUtils.parseList(text(input, options), transform);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* The Databricks bundle output for `cwd` - `databricks bundle validate --output
|
|
394
|
+
* json` run from the directory holding `databricks.yml`, with the config file's
|
|
395
|
+
* path. A non-zero validation may still return partial JSON with usable App
|
|
396
|
+
* config. `undefined` when bundle reads are disabled, the process is production
|
|
397
|
+
* or a deployed App without an explicit override, there is no bundle, or the
|
|
398
|
+
* CLI produces no JSON.
|
|
399
|
+
*
|
|
400
|
+
* Parsed validation output is cached by bundle path and Databricks profile.
|
|
401
|
+
*
|
|
402
|
+
*/
|
|
403
|
+
export function bundleFile(cwd) {
|
|
404
|
+
const override = object.toBoolean(process.env[CONFIG_BUNDLE_KEY]);
|
|
405
|
+
if (override === false)
|
|
406
|
+
return undefined;
|
|
407
|
+
if (override === undefined &&
|
|
408
|
+
(process.env.NODE_ENV?.trim().toLowerCase() === "production" || isDatabricksAppEnv())) {
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
411
|
+
const resolved = resolveWorkingDirectory(cwd);
|
|
412
|
+
return loadBundleFile(resolved, stringUtils.trimToNull(process.env.DATABRICKS_CONFIG_PROFILE));
|
|
413
|
+
}
|
|
414
|
+
/** The parsed `app.yaml` / `app.yml` for `cwd`, when local App config reads are enabled. */
|
|
415
|
+
export function appFile(cwd) {
|
|
416
|
+
const enabled = object.toBoolean(process.env[CONFIG_APP_KEY]) ?? !isDatabricksAppEnv();
|
|
417
|
+
if (!enabled)
|
|
418
|
+
return undefined;
|
|
419
|
+
return loadAppFile(resolveWorkingDirectory(cwd));
|
|
420
|
+
}
|
|
421
|
+
/** The single bundle App's resolved environment, when available. */
|
|
422
|
+
function bundleEnvironment(options) {
|
|
423
|
+
const data = sourceData(options.bundleData) ?? bundleFile(options.cwd)?.data;
|
|
424
|
+
return data ? flattenBundleEnv(data) : undefined;
|
|
425
|
+
}
|
|
426
|
+
function appEnvironment(options) {
|
|
427
|
+
const data = sourceData(options.appData) ?? appFile(options.cwd)?.data;
|
|
428
|
+
return data ? flattenAppEnv(data) : undefined;
|
|
429
|
+
}
|
|
430
|
+
function sourceData(source) {
|
|
431
|
+
if (!source)
|
|
432
|
+
return undefined;
|
|
433
|
+
if ("path" in source && typeof source.path === "string" && object.isRecord(source.data)) {
|
|
434
|
+
return source.data;
|
|
435
|
+
}
|
|
436
|
+
return source;
|
|
437
|
+
}
|
|
438
|
+
/** Parsed `.env` for `cwd`, or `{}`; parsed file data is cached by path. */
|
|
439
|
+
function dotenv(cwd) {
|
|
440
|
+
const enabled = object.toBoolean(process.env[CONFIG_DOTENV_KEY]) ?? !isDatabricksAppEnv();
|
|
441
|
+
if (!enabled)
|
|
442
|
+
return {};
|
|
443
|
+
const resolved = resolveWorkingDirectory(cwd);
|
|
444
|
+
return loadDotenv(resolved, nodeEnvNames(process.env.NODE_ENV));
|
|
445
|
+
}
|
|
446
|
+
/** Maps for one source in precedence order. */
|
|
447
|
+
function read(source, options) {
|
|
448
|
+
return object.sequence({
|
|
449
|
+
*[Symbol.iterator]() {
|
|
450
|
+
switch (source) {
|
|
451
|
+
case "config": {
|
|
452
|
+
const data = options.data;
|
|
453
|
+
if (Array.isArray(data)) {
|
|
454
|
+
yield* data;
|
|
455
|
+
}
|
|
456
|
+
else if (data !== undefined) {
|
|
457
|
+
yield data;
|
|
458
|
+
}
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
case "env":
|
|
462
|
+
yield process.env;
|
|
463
|
+
break;
|
|
464
|
+
case "dotenv":
|
|
465
|
+
yield dotenv(options.cwd);
|
|
466
|
+
break;
|
|
467
|
+
case "bundle": {
|
|
468
|
+
const environment = bundleEnvironment(options);
|
|
469
|
+
if (environment)
|
|
470
|
+
yield environment;
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
case "app": {
|
|
474
|
+
const environment = appEnvironment(options);
|
|
475
|
+
if (environment)
|
|
476
|
+
yield environment;
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
default:
|
|
480
|
+
throw new TypeError(`Unknown config source: ${source}`);
|
|
481
|
+
}
|
|
482
|
+
},
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Locate `names` from `cwd` outward. `cwd` itself is checked before the
|
|
487
|
+
* discovered project roots so a package-local file wins over the workspace's.
|
|
488
|
+
*/
|
|
489
|
+
function findConfigFile(cwd, names) {
|
|
490
|
+
const start = resolve(cwd);
|
|
491
|
+
const key = JSON.stringify([start, ...names]);
|
|
492
|
+
if (configFileCache.has(key))
|
|
493
|
+
return configFileCache.get(key);
|
|
494
|
+
const root = resolveProjectRoot(start);
|
|
495
|
+
const pathFromRoot = root ? relative(root, start) : undefined;
|
|
496
|
+
const boundary = root &&
|
|
497
|
+
pathFromRoot !== undefined &&
|
|
498
|
+
!isAbsolute(pathFromRoot) &&
|
|
499
|
+
pathFromRoot !== ".." &&
|
|
500
|
+
!pathFromRoot.startsWith(`..${sep}`)
|
|
501
|
+
? root
|
|
502
|
+
: undefined;
|
|
503
|
+
for (let dir = start;; dir = dirname(dir)) {
|
|
504
|
+
for (const name of names) {
|
|
505
|
+
const path = resolve(dir, name);
|
|
506
|
+
if (statSync(path)?.isFile()) {
|
|
507
|
+
configFileCache.set(key, path);
|
|
508
|
+
return path;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if (boundary === undefined || dir === boundary)
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
configFileCache.set(key, undefined);
|
|
515
|
+
return undefined;
|
|
516
|
+
}
|
|
517
|
+
function loadDotenv(cwd, environments) {
|
|
518
|
+
const names = [...environments.map((name) => `${DOTENV_FILE_NAME}.${name}`), DOTENV_FILE_NAME];
|
|
519
|
+
const path = findConfigFile(cwd, names);
|
|
520
|
+
if (!path)
|
|
521
|
+
return {};
|
|
522
|
+
return (cachedRecord(JSON.stringify(["dotenv", path]), () => {
|
|
523
|
+
try {
|
|
524
|
+
return parseEnv(readFileSync(path, "utf8"));
|
|
525
|
+
}
|
|
526
|
+
catch {
|
|
527
|
+
logger.warn("failed to read dotenv file", { path });
|
|
528
|
+
return {};
|
|
529
|
+
}
|
|
530
|
+
}) ?? {});
|
|
531
|
+
}
|
|
532
|
+
function loadBundleFile(cwd, profile) {
|
|
533
|
+
const path = findConfigFile(cwd, BUNDLE_FILE_NAMES);
|
|
534
|
+
if (!path)
|
|
535
|
+
return undefined;
|
|
536
|
+
const data = cachedRecord(JSON.stringify(["bundle", path, profile]), () => {
|
|
537
|
+
const args = [
|
|
538
|
+
"bundle",
|
|
539
|
+
"validate",
|
|
540
|
+
"--output",
|
|
541
|
+
"json",
|
|
542
|
+
...(profile === null ? [] : ["--profile", profile]),
|
|
543
|
+
];
|
|
544
|
+
const result = spawnSync("databricks", args, {
|
|
545
|
+
cwd: resolve(path, ".."),
|
|
546
|
+
encoding: "utf8",
|
|
547
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
548
|
+
});
|
|
549
|
+
const output = stringUtils.trimToNull(result.stdout);
|
|
550
|
+
const error = stringUtils.trimToNull(result.stderr);
|
|
551
|
+
if (output === null) {
|
|
552
|
+
logger.debug("bundle validate produced no JSON", { path, status: result.status, error });
|
|
553
|
+
return undefined;
|
|
554
|
+
}
|
|
555
|
+
const parsed = json.parseRecord(output);
|
|
556
|
+
if (!parsed) {
|
|
557
|
+
logger.warn("failed to parse bundle validate output", { path, status: result.status });
|
|
558
|
+
return undefined;
|
|
559
|
+
}
|
|
560
|
+
if (result.status !== 0) {
|
|
561
|
+
logger.debug("using partial bundle output", { path, status: result.status, error });
|
|
562
|
+
}
|
|
563
|
+
return parsed;
|
|
564
|
+
});
|
|
565
|
+
return data === undefined ? undefined : { path, data };
|
|
566
|
+
}
|
|
567
|
+
function loadAppFile(cwd) {
|
|
568
|
+
const path = findConfigFile(cwd, APP_FILE_NAMES);
|
|
569
|
+
if (!path)
|
|
570
|
+
return undefined;
|
|
571
|
+
const data = cachedRecord(JSON.stringify(["app", path]), () => {
|
|
572
|
+
try {
|
|
573
|
+
const parsed = parseYaml(readFileSync(path, "utf8"));
|
|
574
|
+
return object.isRecord(parsed) ? parsed : undefined;
|
|
575
|
+
}
|
|
576
|
+
catch {
|
|
577
|
+
logger.warn("failed to parse app yaml", { path });
|
|
578
|
+
return undefined;
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
return data === undefined ? undefined : { path, data };
|
|
582
|
+
}
|
|
583
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLXV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy11dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EwQkc7QUFFSCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDL0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUN2QyxPQUFPLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUN4RSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3JDLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN4RSxPQUFPLEVBQUUsS0FBSyxJQUFJLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMxQyxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBQ3hCLE9BQU8sRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ25ELE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxJQUFJLElBQUksa0JBQWtCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUV6RixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ3BDLE1BQU0sZUFBZSxHQUFHLElBQUksR0FBRyxFQUE4QixDQUFDO0FBMEM5RCxNQUFNLGFBQWEsR0FBRyxXQUFXLENBQUM7QUFDbEMsTUFBTSxlQUFlLEdBQTRCLENBQUMsUUFBUSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO0FB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SUFBSSxFQUFFLENBQUM7QUFDekQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTGF5ZXJlZCBjb25maWd1cmF0aW9uIGxvb2t1cDogZW52aXJvbm1lbnQsIGAuZW52YCwgYnVuZGxlLCBhbmQgYGFwcC55YW1sYC5cbiAqXG4gKiBFdmVyeSBwYWNrYWdlIHJlc29sdmVzIHNldHRpbmdzIHRoZSBzYW1lIHdheTogdGFrZSB0aGUgY2FsbGVyJ3MgdmFsdWUsIGVsc2VcbiAqIGFuIGVudmlyb25tZW50IHZhcmlhYmxlLCBlbHNlIGEgZGVmYXVsdC4gTG9jYWwgZGV2ZWxvcG1lbnQgYWRkcyB0d28gZmFsbGJhY2tcbiAqIGxvY2F0aW9uczogYC5lbnZgIGZpbGVzLCBvbmUgQXBwJ3MgYHJlc291cmNlcy5hcHBzLjxhcHA+LmNvbmZpZy5lbnZgIGluXG4gKiBgZGF0YWJyaWNrcy55bWxgLCBhbmQgbGl0ZXJhbCBlbnYgdmFsdWVzIGluIGBhcHAueWFtbGAgLyBgYXBwLnltbGAuXG4gKlxuICoge0BsaW5rIHZhbHVlc30gaXMgTEFaWSAoYW4gYG9iamVjdC5TZXF1ZW5jZWApLCBzbyBgZGF0YWJyaWNrcyBidW5kbGUgdmFsaWRhdGVgXG4gKiBpcyBvbmx5IHNwYXduZWQgd2hlbiB0aGUgZW52aXJvbm1lbnQgYW5kIGAuZW52YCBib3RoIG1pc3NlZDsgYXBwIFlBTUwgaXMgb25seVxuICogcmVhZCBhZnRlciB0aGUgYnVuZGxlIHNvdXJjZSBhbHNvIG1pc3NlZC5cbiAqXG4gKiBJbnNpZGUgYSBkZXBsb3llZCBEYXRhYnJpY2tzIEFwcCBhbGwgdGhyZWUgZmlsZSBzb3VyY2VzIGFyZSBza2lwcGVkIGJ5IGRlZmF1bHRcbiAqICh7QGxpbmsgaXNEYXRhYnJpY2tzQXBwRW52fSk6IHRoZSBwbGF0Zm9ybSBoYXMgYWxyZWFkeSB0dXJuZWQgdGhlbSBpbnRvIHJlYWxcbiAqIGVudmlyb25tZW50IHZhcmlhYmxlcywgdGhlcmUgaXMgbm8gYnVuZGxlIHRvIHZhbGlkYXRlLCBhbmQgdGhlIGBkYXRhYnJpY2tzYFxuICogQ0xJIGlzIG5vdCBvbiB0aGUgaW1hZ2UuIEJvb2xlYW4gZW52aXJvbm1lbnQgb3ZlcnJpZGVzIGNhbiBmb3JjZSBlaXRoZXIgZmlsZVxuICogc291cmNlIG9uIG9yIG9mZiB3aGVuIGEgdG9vbCBuZWVkcyBkaWZmZXJlbnQgYmVoYXZpb3IuXG4gKlxuICogT25seSB0aGUgc2luZ2xlIGJ1bmRsZSBhcHAncyBgY29uZmlnLmVudmAgYW5kIGxpdGVyYWwgYXBwIFlBTUwgYGVudltdLnZhbHVlYFxuICogZW50cmllcyBhcmUgY29uc3VsdGVkLiBSb290IGJ1bmRsZSBgdmFyaWFibGVzYCBhcmUgbm90OiB0aGV5IGFyZSBhdXRob3JpbmdcbiAqIGlucHV0cyBmb3IgdGhlIGJ1bmRsZSBpdHNlbGYgKGludGVycG9sYXRlZCBpbnRvIHRhcmdldHMsIHJlc291cmNlcywgYW5kIHBhdGhzKSxcbiAqIHNvIHRyZWF0aW5nIG9uZSBhcyBhIHByb2Nlc3Mgc2V0dGluZyByZXNvbHZlcyBuYW1lcyB0aGUgZGVwbG95ZWQgYXBwIG5ldmVyIHNlZXMuXG4gKlxuICogTm9kZS1vbmx5IChgY2hpbGRfcHJvY2Vzc2AsIGBmc2AsIGBwcm9jZXNzYCkuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IHNwYXduU3luYyB9IGZyb20gXCJub2RlOmNoaWxkX3Byb2Nlc3NcIjtcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBkaXJuYW1lLCBpc0Fic29sdXRlLCByZWxhdGl2ZSwgcmVzb2x2ZSwgc2VwIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgcGFyc2VFbnYgfSBmcm9tIFwibm9kZTp1dGlsXCI7XG5pbXBvcnQgeyBpc0RhdGFicmlja3NBcHBFbnZpcm9ubWVudCB9IGZyb20gXCJAZGJ4LXRvb2xzL2NvcmUtcnNcIjtcbmltcG9ydCB7IGpzb24sIGxvZywgb2JqZWN0LCBzdHJpbmdVdGlscyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgeyBwYXJzZSBhcyBwYXJzZVlhbWwgfSBmcm9tIFwieWFtbFwiO1xuaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcbmltcG9ydCB7IGNhY2hlZFJlY29yZCwgc3RhdFN5bmMgfSBmcm9tIFwiLi9maWxlLnRzXCI7XG5pbXBvcnQgeyByZXNvbHZlV29ya2luZ0RpcmVjdG9yeSwgcm9vdCBhcyByZXNvbHZlUHJvamVjdFJvb3QgfSBmcm9tIFwiLi9wcm9qZWN0LXV0aWxzLnRzXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJjb25maWdcIik7XG5jb25zdCBjb25maWdGaWxlQ2FjaGUgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPigpO1xuXG50eXBlIENvbmZpZ0tleSA9IHN0cmluZyB8IHJlYWRvbmx5IHN0cmluZ1tdO1xuXG5leHBvcnQgdHlwZSBDb25maWdNYXBWYWx1ZSA9IHN0cmluZyB8IHJlYWRvbmx5IHN0cmluZ1tdIHwgbnVsbCB8IHVuZGVmaW5lZDtcbmV4cG9ydCB0eXBlIENvbmZpZ0RhdGEgPSBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCBDb25maWdNYXBWYWx1ZT4+O1xuXG4vKiogV2hlcmUgYSB2YWx1ZSBtYXkgY29tZSBmcm9tLCBjb25zdWx0ZWQgaW4gdGhlIG9yZGVyIGdpdmVuLiAqL1xuZXhwb3J0IHR5cGUgQ29uZmlnU291cmNlID0gXCJjb25maWdcIiB8IFwiZW52XCIgfCBcImRvdGVudlwiIHwgXCJidW5kbGVcIiB8IFwiYXBwXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29uZmlnT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBPdXRlcm1vc3QgbmFtZXNwYWNlcyB0cmllZCBiZWZvcmUgZWFjaCBrZXkuIERlZmF1bHRzIHRvIGBEQlhfVE9PTFNgLlxuICAgKi9cbiAgc2NvcGU/OiBzdHJpbmcgfCByZWFkb25seSBzdHJpbmdbXTtcbiAgLyoqIENhcGFiaWxpdHkgbmFtZXNwYWNlcyBpbnNlcnRlZCBhZnRlciB0aGUgc2NvcGUgYW5kIGJlZm9yZSBlYWNoIGtleS4gKi9cbiAgcHJlZml4Pzogc3RyaW5nIHwgcmVhZG9ubHkgc3RyaW5nW107XG4gIC8qKiBDb25zdGFudCBjb25maWcgbWFwcyByZWFkIGJ5IHRoZSBgY29uZmlnYCBzb3VyY2UuICovXG4gIGRhdGE/OiBDb25maWdEYXRhIHwgcmVhZG9ubHkgQ29uZmlnRGF0YVtdO1xuICAvKiogUGFyc2VkIGJ1bmRsZSBkYXRhIHVzZWQgaW5zdGVhZCBvZiBsb2FkaW5nIGBkYXRhYnJpY2tzLnltbGAuICovXG4gIGJ1bmRsZURhdGE/OiBDb25maWdGaWxlIHwgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIC8qKiBQYXJzZWQgYXBwIFlBTUwgZGF0YSB1c2VkIGluc3RlYWQgb2YgbG9hZGluZyBgYXBwLnlhbWxgLiAqL1xuICBhcHBEYXRhPzogQ29uZmlnRmlsZSB8IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAvKiogU291cmNlcyBpbiBwcmVjZWRlbmNlIG9yZGVyLiBEZWZhdWx0OiBgY29uZmlnYCwgYGVudmAsIGBkb3RlbnZgLCBgYnVuZGxlYCwgYGFwcGAuICovXG4gIHNvdXJjZXM/OiBDb25maWdTb3VyY2UgfCByZWFkb25seSBDb25maWdTb3VyY2VbXTtcbiAgLyoqIERpcmVjdG9yeSB0byByZXNvbHZlIGAuZW52YCBhbmQgdGhlIGJ1bmRsZSBmcm9tLiBEZWZhdWx0OiBgcHJvY2Vzcy5jd2QoKWAuICovXG4gIGN3ZD86IHN0cmluZztcbn1cblxuLyoqIE9uZSByZXNvbHZlZCB2YWx1ZSwgdGFnZ2VkIHdpdGggdGhlIGtleSBhbmQgc291cmNlIGl0IGNhbWUgZnJvbS4gKi9cbmludGVyZmFjZSBDb25maWdWYWx1ZSB7XG4gIGtleTogc3RyaW5nO1xuICBzb3VyY2U6IENvbmZpZ1NvdXJjZTtcbiAgdmFsdWU6IHN0cmluZztcbn1cblxuLyoqIEEgY29uZmlnIGZpbGUgZm91bmQgb24gZGlzaywgd2l0aCBpdHMgcGFyc2VkIGNvbnRlbnRzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb25maWdGaWxlIHtcbiAgcGF0aDogc3RyaW5nO1xuICBkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuY29uc3QgREVGQVVMVF9TQ09QRSA9IFwiREJYX1RPT0xTXCI7XG5jb25zdCBERUZBVUxUX1NPVVJDRVM6IHJlYWRvbmx5IENvbmZpZ1NvdXJjZVtdID0gW1wiY29uZmlnXCIsIFwiZW52XCIsIFwiZG90ZW52XCIsIFwiYnVuZGxlXCIsIFwiYXBwXCJdO1xuY29uc3QgQlVORExFX0ZJTEVfTkFNRVMgPSBbXCJkYXRhYnJpY2tzLnltbFwiLCBcImRhdGFicmlja3MueWFtbFwiXSBhcyBjb25zdDtcbmNvbnN0IEFQUF9GSUxFX05BTUVTID0gW1wiYXBwLnlhbWxcIiwgXCJhcHAueW1sXCJdIGFzIGNvbnN0O1xuY29uc3QgRE9URU5WX0ZJTEVfTkFNRSA9IFwiLmVudlwiO1xuY29uc3QgTk9ERV9FTlZfQUxURVJOQVRJVkVTID0ge1xuICBwcm9kdWN0aW9uOiBbXCJwcm9kXCJdLFxuICBkZXZlbG9wbWVudDogW1wiZGV2XCJdLFxufSBhcyBjb25zdCBzYXRpc2ZpZXMgUmVjb3JkPHN0cmluZywgcmVhZG9ubHkgc3RyaW5nW10+O1xuXG4vKiogSGlnaGVzdCB2YWxpZCBUQ1AgcG9ydCBudW1iZXIuICovXG5leHBvcnQgY29uc3QgTUFYX1RDUF9QT1JUID0gNjVfNTM1O1xuXG4vKiogQm9vbGVhbiBlbnZpcm9ubWVudCBvdmVycmlkZSBmb3IgcHJvamVjdCBgLmVudmAgcmVhZHMuICovXG5jb25zdCBDT05GSUdfRE9URU5WX0tFWSA9IFwiREJYX1RPT0xTX0NPTkZJR19ET1RFTlZcIjtcblxuLyoqIEJvb2xlYW4gZW52aXJvbm1lbnQgb3ZlcnJpZGUgZm9yIERhdGFicmlja3MgYnVuZGxlIHJlYWRzLiAqL1xuY29uc3QgQ09ORklHX0JVTkRMRV9LRVkgPSBcIkRCWF9UT09MU19DT05GSUdfQlVORExFXCI7XG5cbi8qKiBCb29sZWFuIGVudmlyb25tZW50IG92ZXJyaWRlIGZvciBEYXRhYnJpY2tzIEFwcCBZQU1MIHJlYWRzLiAqL1xuY29uc3QgQ09ORklHX0FQUF9LRVkgPSBcIkRCWF9UT09MU19DT05GSUdfQVBQXCI7XG5cbi8qKiBFeGFjdCBwcm9jZXNzLWVudmlyb25tZW50IGxvb2t1cCBmb3IgY2FsbGVycyB0aGF0IGRvIG5vdCByZWFkIGxvY2FsIGNvbmZpZyBmaWxlcy4gKi9cbmV4cG9ydCBjb25zdCBFTlZfT05MWSA9IHsgc2NvcGU6IFtdIGFzIGNvbnN0LCBzb3VyY2VzOiBcImVudlwiIGFzIGNvbnN0IH07XG5cbmV4cG9ydCBjb25zdCB2YWx1ZVNjaGVtYSA9IHpcbiAgLnN0cmluZygpXG4gIC50cmltKClcbiAgLm1pbigxKVxuICAucmVmaW5lKCh2YWx1ZTogc3RyaW5nKSA9PiAhL1xcJFxce1tefV0rXFx9Ly50ZXN0KHZhbHVlKSwge1xuICAgIG1lc3NhZ2U6IFwiSW50ZXJwb2xhdGVkIHZhbHVlcyBhcmUgbm90IGFsbG93ZWRcIixcbiAgfSk7XG5cbmNvbnN0IHBvcnRWYWx1ZVNjaGVtYSA9IHoucHJlcHJvY2VzcygoaW5wdXQpID0+IHtcbiAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gXCJudW1iZXJcIikgcmV0dXJuIGlucHV0O1xuICBpZiAodHlwZW9mIGlucHV0ICE9PSBcInN0cmluZ1wiIHx8ICEvXlxcZCskLy50ZXN0KGlucHV0LnRyaW0oKSkpIHJldHVybiBOdW1iZXIuTmFOO1xuICByZXR1cm4gTnVtYmVyKGlucHV0LnRyaW0oKSk7XG59LCB6Lm51bWJlcigpLmludCgpLm1pbigxKS5tYXgoTUFYX1RDUF9QT1JUKSk7XG5cbmNvbnN0IHBvc2l0aXZlTnVtYmVyVmFsdWUgPSB6LnByZXByb2Nlc3MoKGlucHV0KSA9PiBvYmplY3QudG9OdW1iZXIoaW5wdXQpLCB6Lm51bWJlcigpLnBvc2l0aXZlKCkpO1xuY29uc3QgcG9zaXRpdmVJbnRWYWx1ZSA9IHBvc2l0aXZlTnVtYmVyVmFsdWUudHJhbnNmb3JtKE1hdGguZmxvb3IpO1xuXG4vKiogQSBuYW1lZCBidW5kbGUgb3IgQXBwIHJlc291cmNlOyBjb25jcmV0ZSByZXNvdXJjZSBmaWVsZHMgcGFzcyB0aHJvdWdoLiAqL1xuZXhwb3J0IGNvbnN0IGJ1bmRsZVJlc291cmNlU2NoZW1hID0gei5vYmplY3QoeyBuYW1lOiB2YWx1ZVNjaGVtYS5vcHRpb25hbCgpIH0pLnBhc3N0aHJvdWdoKCk7XG5cbmV4cG9ydCBjb25zdCBidW5kbGVFbnZFbnRyeVNjaGVtYSA9IHoub2JqZWN0KHtcbiAgbmFtZTogdmFsdWVTY2hlbWEub3B0aW9uYWwoKSxcbiAgdmFsdWU6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgdmFsdWVfZnJvbTogdmFsdWVTY2hlbWEub3B0aW9uYWwoKSxcbn0pO1xuXG5leHBvcnQgY29uc3QgYnVuZGxlQXBwU2NoZW1hID0gei5vYmplY3Qoe1xuICBuYW1lOiB2YWx1ZVNjaGVtYS5vcHRpb25hbCgpLFxuICBjb25maWc6IHoub2JqZWN0KHsgZW52OiB6LmFycmF5KGJ1bmRsZUVudkVudHJ5U2NoZW1hKS5vcHRpb25hbCgpIH0pLm9wdGlvbmFsKCksXG4gIHJlc291cmNlczogei5hcnJheShidW5kbGVSZXNvdXJjZVNjaGVtYSkub3B0aW9uYWwoKSxcbn0pO1xuXG5leHBvcnQgY29uc3QgYXBwRW52RW50cnlTY2hlbWEgPSB6Lm9iamVjdCh7XG4gIG5hbWU6IHZhbHVlU2NoZW1hLFxuICB2YWx1ZTogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICB2YWx1ZUZyb206IHZhbHVlU2NoZW1hLm9wdGlvbmFsKCksXG59KTtcblxuZXhwb3J0IGNvbnN0IGFwcFNjaGVtYSA9IHoub2JqZWN0KHtcbiAgZW52OiB6LmFycmF5KGFwcEVudkVudHJ5U2NoZW1hKS5vcHRpb25hbCgpLFxuICByZXNvdXJjZXM6IHouYXJyYXkoYnVuZGxlUmVzb3VyY2VTY2hlbWEpLm9wdGlvbmFsKCksXG59KTtcblxuY29uc3QgYnVuZGxlQ29uZmlnU2NoZW1hID0gei5vYmplY3Qoe1xuICByZXNvdXJjZXM6IHoub2JqZWN0KHsgYXBwczogei5yZWNvcmQoei5zdHJpbmcoKSwgYnVuZGxlQXBwU2NoZW1hKS5vcHRpb25hbCgpIH0pLm9wdGlvbmFsKCksXG59KTtcblxuLyoqIEZsYXR0ZW4gdGhlIHNpbmdsZSBidW5kbGUgQXBwJ3MgYGNvbmZpZy5lbnZgLCByZXNvbHZpbmcgcmVzb3VyY2UgcmVmZXJlbmNlcy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmbGF0dGVuQnVuZGxlRW52KGRhdGE6IHVua25vd24pOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgY29uc3QgcGFyc2VkID0gYnVuZGxlQ29uZmlnU2NoZW1hLnNhZmVQYXJzZShkYXRhKTtcbiAgaWYgKCFwYXJzZWQuc3VjY2VzcykgcmV0dXJuIHt9O1xuICBjb25zdCBhcHBzID0gT2JqZWN0LnZhbHVlcyhwYXJzZWQuZGF0YS5yZXNvdXJjZXM/LmFwcHMgPz8ge30pO1xuICBpZiAoYXBwcy5sZW5ndGggIT09IDEpIHJldHVybiB7fTtcbiAgY29uc3QgYXBwID0gYXBwc1swXTtcbiAgY29uc3QgcmVzb3VyY2VzID0gbmV3IE1hcChcbiAgICAoYXBwPy5yZXNvdXJjZXMgPz8gW10pXG4gICAgICAuZmlsdGVyKChyZXNvdXJjZSkgPT4gcmVzb3VyY2UubmFtZSlcbiAgICAgIC5tYXAoKHJlc291cmNlKSA9PiBbcmVzb3VyY2UubmFtZSEsIHJlc291cmNlXSBhcyBjb25zdCksXG4gICk7XG4gIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGFwcD8uY29uZmlnPy5lbnYgPz8gW10pIHtcbiAgICBpZiAoIWVudHJ5Lm5hbWUpIGNvbnRpbnVlO1xuICAgIGNvbnN0IGxpdGVyYWwgPSB2YWx1ZVNjaGVtYS5zYWZlUGFyc2UoZW50cnkudmFsdWUpO1xuICAgIGlmIChsaXRlcmFsLnN1Y2Nlc3MpIHtcbiAgICAgIHJlc3VsdFtlbnRyeS5uYW1lXSA9IGxpdGVyYWwuZGF0YTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBjb25zdCByZWZlcmVuY2VkID0gZW50cnkudmFsdWVfZnJvbVxuICAgICAgPyByZXNvdXJjZVZhbHVlKHJlc291cmNlcy5nZXQoZW50cnkudmFsdWVfZnJvbSkpXG4gICAgICA6IHVuZGVmaW5lZDtcbiAgICBpZiAocmVmZXJlbmNlZCkgcmVzdWx0W2VudHJ5Lm5hbWVdID0gcmVmZXJlbmNlZDtcbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKiogRmxhdHRlbiBgYXBwLnlhbWxgIGVudiBlbnRyaWVzLCByZXNvbHZpbmcgYHZhbHVlRnJvbWAgcmVzb3VyY2UgcmVmZXJlbmNlcy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmbGF0dGVuQXBwRW52KGRhdGE6IHVua25vd24pOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgY29uc3QgcGFyc2VkID0gYXBwU2NoZW1hLnNhZmVQYXJzZShkYXRhKTtcbiAgaWYgKCFwYXJzZWQuc3VjY2VzcykgcmV0dXJuIHt9O1xuICBjb25zdCByZXNvdXJjZXMgPSBuZXcgTWFwKFxuICAgIChwYXJzZWQuZGF0YS5yZXNvdXJjZXMgPz8gW10pXG4gICAgICAuZmlsdGVyKChyZXNvdXJjZSkgPT4gcmVzb3VyY2UubmFtZSlcbiAgICAgIC5tYXAoKHJlc291cmNlKSA9PiBbcmVzb3VyY2UubmFtZSEsIHJlc291cmNlXSBhcyBjb25zdCksXG4gICk7XG4gIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICBmb3IgKGNvbnN0IGVudHJ5IG9mIHBhcnNlZC5kYXRhLmVudiA/PyBbXSkge1xuICAgIGNvbnN0IGxpdGVyYWwgPSB2YWx1ZVNjaGVtYS5zYWZlUGFyc2UoZW50cnkudmFsdWUpO1xuICAgIGlmIChsaXRlcmFsLnN1Y2Nlc3MpIHtcbiAgICAgIHJlc3VsdFtlbnRyeS5uYW1lXSA9IGxpdGVyYWwuZGF0YTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBjb25zdCByZWZlcmVuY2VkID0gZW50cnkudmFsdWVGcm9tID8gcmVzb3VyY2VWYWx1ZShyZXNvdXJjZXMuZ2V0KGVudHJ5LnZhbHVlRnJvbSkpIDogdW5kZWZpbmVkO1xuICAgIGlmIChyZWZlcmVuY2VkKSByZXN1bHRbZW50cnkubmFtZV0gPSByZWZlcmVuY2VkO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmZ1bmN0aW9uIHJlc291cmNlVmFsdWUocmVzb3VyY2U6IHVua25vd24pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBmb3IgKGNvbnN0IHBhdGggb2YgW1xuICAgIFtcInNxbF93YXJlaG91c2VcIiwgXCJpZFwiXSxcbiAgICBbXCJnZW5pZV9zcGFjZVwiLCBcInNwYWNlX2lkXCJdLFxuICAgIFtcInBvc3RncmVzXCIsIFwiZW5kcG9pbnRcIl0sXG4gICAgW1wicG9zdGdyZXNcIiwgXCJkYXRhYmFzZVwiXSxcbiAgICBbXCJwb3N0Z3Jlc1wiLCBcImJyYW5jaFwiXSxcbiAgXSBhcyBjb25zdCkge1xuICAgIGxldCB2YWx1ZSA9IHJlc291cmNlO1xuICAgIGZvciAoY29uc3QgcGFydCBvZiBwYXRoKSB2YWx1ZSA9IG9iamVjdC5pc1JlY29yZCh2YWx1ZSkgPyB2YWx1ZVtwYXJ0XSA6IHVuZGVmaW5lZDtcbiAgICBjb25zdCBwYXJzZWQgPSB2YWx1ZVNjaGVtYS5zYWZlUGFyc2UodmFsdWUpO1xuICAgIGlmIChwYXJzZWQuc3VjY2VzcykgcmV0dXJuIHBhcnNlZC5kYXRhO1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8qKiBXYWxrIGEgZG90LXNlcGFyYXRlZCBwYXRoIHRocm91Z2ggcGFyc2VkIGJ1bmRsZSBkYXRhLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEJ1bmRsZVBhdGgoZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIHBhdGg6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHBhcnRzID0gcGF0aC5zcGxpdChcIi5cIikuZmlsdGVyKEJvb2xlYW4pO1xuICBpZiAocGFydHMubGVuZ3RoID09PSAwKSByZXR1cm4gdW5kZWZpbmVkO1xuICBsZXQgY3VycmVudDogdW5rbm93biA9IGRhdGE7XG4gIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCBwYXJ0cy5sZW5ndGg7IGluZGV4KyspIHtcbiAgICBpZiAoIW9iamVjdC5pc1JlY29yZChjdXJyZW50KSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBjb25zdCBuZXh0ID0gY3VycmVudFtwYXJ0c1tpbmRleF0hXTtcbiAgICBpZiAoaW5kZXggPT09IHBhcnRzLmxlbmd0aCAtIDEpIHtcbiAgICAgIGNvbnN0IGRpcmVjdCA9IHZhbHVlU2NoZW1hLnNhZmVQYXJzZShuZXh0KTtcbiAgICAgIGlmIChkaXJlY3Quc3VjY2VzcykgcmV0dXJuIGRpcmVjdC5kYXRhO1xuICAgICAgaWYgKG9iamVjdC5pc1JlY29yZChuZXh0KSkge1xuICAgICAgICBjb25zdCBuZXN0ZWQgPSB2YWx1ZVNjaGVtYS5zYWZlUGFyc2UobmV4dC52YWx1ZSk7XG4gICAgICAgIHJldHVybiBuZXN0ZWQuc3VjY2VzcyA/IG5lc3RlZC5kYXRhIDogdW5kZWZpbmVkO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgY3VycmVudCA9IG5leHQ7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBEZXRlY3QgYSBEYXRhYnJpY2tzIEFwcCBydW50aW1lIGZyb20gaXRzIHJlcXVpcmVkIG5hbWUsIGhvc3QsIGFuZCBwb3J0LlxuICpcbiAqIGBEQlhfVE9PTFNfREFUQUJSSUNLU19BUFBfRU5WYCB0YWtlcyBwcmVjZWRlbmNlIHdoZW4gaXQgY29udGFpbnMgYSByZWNvZ25pemVkXG4gKiBib29sZWFuIHZhbHVlLiBUaGlzIGxldHMgbG9jYWwgdG9vbHMgZW11bGF0ZSB0aGUgZGVwbG95ZWQgcnVudGltZSAoYHRydWVgKSBvclxuICogbGV0cyB1bnVzdWFsIGRlcGxveWVkIHByb2Nlc3NlcyByZXRhaW4gbG9jYWwgY29uZmlnIGxvb2t1cCAoYGZhbHNlYCkuIEFuXG4gKiBhYnNlbnQgb3IgdW5yZWNvZ25pemVkIG92ZXJyaWRlIGZhbGxzIGJhY2sgdG8gc3RydWN0dXJhbCBkZXRlY3Rpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0RhdGFicmlja3NBcHBFbnYoXG4gIHNvdXJjZTogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPiA9IHByb2Nlc3MuZW52LFxuKTogYm9vbGVhbiB7XG4gIHJldHVybiBpc0RhdGFicmlja3NBcHBFbnZpcm9ubWVudChcbiAgICBuZXcgTWFwKFxuICAgICAgT2JqZWN0LmVudHJpZXMoc291cmNlKS5maWx0ZXIoKGVudHJ5KTogZW50cnkgaXMgW3N0cmluZywgc3RyaW5nXSA9PiBlbnRyeVsxXSAhPT0gdW5kZWZpbmVkKSxcbiAgICApLFxuICApO1xufVxuXG4vKiogRXhhY3QsIHVwcGVyY2FzZSwgYW5kIHRva2VuaXplZC11cHBlcmNhc2UgbmFtZXMgZm9yIGEgaHVtYW4tZnJpZW5kbHkga2V5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVudmlyb25tZW50S2V5cyhuYW1lOiBzdHJpbmcpOiByZWFkb25seSBzdHJpbmdbXSB7XG4gIGNvbnN0IHRyaW1tZWQgPSBuYW1lLnRyaW0oKTtcbiAgaWYgKCF0cmltbWVkKSByZXR1cm4gW107XG4gIHJldHVybiBvYmplY3RcbiAgICAuc2VxdWVuY2UoXG4gICAgICB0cmltbWVkLFxuICAgICAgdHJpbW1lZC50b1VwcGVyQ2FzZSgpLFxuICAgICAgQXJyYXkuZnJvbShzdHJpbmdVdGlscy50b2tlbml6ZSh0cmltbWVkKSkuam9pbihcIl9cIikudG9VcHBlckNhc2UoKSxcbiAgICApXG4gICAgLmZpbHRlcihCb29sZWFuKVxuICAgIC5kaXN0aW5jdCgpXG4gICAgLnRvQXJyYXkoKTtcbn1cblxuLyoqIENhbmRpZGF0ZSBuYW1lcyBpbiBzY29wZSwgcHJlZml4LCBhbmQgaW5wdXQgcHJlY2VkZW5jZSBvcmRlci4gKi9cbmZ1bmN0aW9uIGtleXMoXG4gIGlucHV0OiBDb25maWdLZXksXG4gIG9wdGlvbnM6IFBpY2s8Q29uZmlnT3B0aW9ucywgXCJzY29wZVwiIHwgXCJwcmVmaXhcIj4gPSB7fSxcbik6IHJlYWRvbmx5IHN0cmluZ1tdIHtcbiAgY29uc3Qgc2NvcGVzID0gb2JqZWN0XG4gICAgLnNlcXVlbmNlKG9wdGlvbnMuc2NvcGUgPz8gREVGQVVMVF9TQ09QRSlcbiAgICAubWFwKHN0cmluZ1V0aWxzLnRyaW1Ub0VtcHR5KVxuICAgIC5maWx0ZXIoQm9vbGVhbilcbiAgICAuZGlzdGluY3QoKVxuICAgIC50b0FycmF5KCk7XG4gIGNvbnN0IHByZWZpeGVzID1cbiAgICBvcHRpb25zLnByZWZpeCA9PT0gdW5kZWZpbmVkXG4gICAgICA/IFtdXG4gICAgICA6IG9iamVjdFxuICAgICAgICAgIC5zZXF1ZW5jZShvcHRpb25zLnByZWZpeClcbiAgICAgICAgICAubWFwKHN0cmluZ1V0aWxzLnRyaW1Ub0VtcHR5KVxuICAgICAgICAgIC5maWx0ZXIoQm9vbGVhbilcbiAgICAgICAgICAuZGlzdGluY3QoKVxuICAgICAgICAgIC50b0FycmF5KCk7XG4gIHJldHVybiBvYmplY3RcbiAgICAuc2VxdWVuY2UoaW5wdXQpXG4gICAgLm1hcChzdHJpbmdVdGlscy50cmltVG9FbXB0eSlcbiAgICAuZmlsdGVyKEJvb2xlYW4pXG4gICAgLmRpc3RpbmN0KClcbiAgICAuZmxhdE1hcCgoa2V5KSA9PiB7XG4gICAgICBjb25zdCBwcmVmaXhlZCA9IHByZWZpeGVzLmxlbmd0aCA+IDAgPyBwcmVmaXhlcy5tYXAoKHByZWZpeCkgPT4gYCR7cHJlZml4fV8ke2tleX1gKSA6IFtrZXldO1xuICAgICAgcmV0dXJuIFtcbiAgICAgICAgLi4uc2NvcGVzLmZsYXRNYXAoKHNjb3BlKSA9PiBwcmVmaXhlZC5tYXAoKG5hbWUpID0+IGAke3Njb3BlfV8ke25hbWV9YCkpLFxuICAgICAgICAuLi5wcmVmaXhlZCxcbiAgICAgICAga2V5LFxuICAgICAgXTtcbiAgICB9KVxuICAgIC5kaXN0aW5jdCgpXG4gICAgLnRvQXJyYXkoKTtcbn1cblxuLyoqXG4gKiBFdmVyeSB2YWx1ZSB0aGF0IHJlc29sdmVzIGZvciBgaW5wdXRgLCBpbiBzb3VyY2UtdGhlbi1rZXkgcHJlY2VkZW5jZSBvcmRlcixcbiAqIGFzIGEgTEFaWSBzZXF1ZW5jZTogbm90aGluZyBwYXN0IHRoZSBmaXJzdCBjb25zdW1lZCBlbGVtZW50IGlzIHJlYWQsIHNvXG4gKiBgdmFsdWVzKGtleSkuYXQoMClgIG5ldmVyIHNwYXducyB0aGUgRGF0YWJyaWNrcyBDTEkgd2hlbiB0aGUgZW52aXJvbm1lbnRcbiAqIGFscmVhZHkgYW5zd2VyZWQuXG4gKlxuICovXG5mdW5jdGlvbiB2YWx1ZXMoaW5wdXQ6IENvbmZpZ0tleSwgb3B0aW9uczogQ29uZmlnT3B0aW9ucyA9IHt9KTogb2JqZWN0LlNlcXVlbmNlPENvbmZpZ1ZhbHVlPiB7XG4gIGNvbnN0IGNhbmRpZGF0ZXMgPSBrZXlzKGlucHV0LCBvcHRpb25zKTtcbiAgY29uc3Qgc291cmNlcyA9IGNvbmZpZ1NvdXJjZXMob3B0aW9ucyk7XG4gIHJldHVybiBvYmplY3Quc2VxdWVuY2Uoe1xuICAgICpbU3ltYm9sLml0ZXJhdG9yXSgpOiBHZW5lcmF0b3I8Q29uZmlnVmFsdWU+IHtcbiAgICAgIGZvciAoY29uc3Qgc291cmNlIG9mIHNvdXJjZXMpIHtcbiAgICAgICAgZm9yIChjb25zdCBtYXAgb2YgcmVhZChzb3VyY2UsIG9wdGlvbnMpKSB7XG4gICAgICAgICAgZm9yIChjb25zdCBrZXkgb2YgY2FuZGlkYXRlcykge1xuICAgICAgICAgICAgY29uc3QgdmFsdWUgPSBjb25maWdNYXBWYWx1ZShtYXBba2V5XSk7XG4gICAgICAgICAgICBpZiAodmFsdWUgIT09IG51bGwpIHlpZWxkIHsga2V5LCBzb3VyY2UsIHZhbHVlIH07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGNvbmZpZ1NvdXJjZXMob3B0aW9uczogQ29uZmlnT3B0aW9ucyk6IHJlYWRvbmx5IENvbmZpZ1NvdXJjZVtdIHtcbiAgY29uc3Qgc291cmNlczogQ29uZmlnU291cmNlW10gPSBbXG4gICAgLi4ub2JqZWN0LnNlcXVlbmNlPENvbmZpZ1NvdXJjZT4ob3B0aW9ucy5zb3VyY2VzID8/IERFRkFVTFRfU09VUkNFUykuZGlzdGluY3QoKSxcbiAgXTtcbiAgaWYgKG9wdGlvbnMuZGF0YSAhPT0gdW5kZWZpbmVkICYmIG9wdGlvbnMuc291cmNlcyAhPT0gdW5kZWZpbmVkICYmICFzb3VyY2VzLmluY2x1ZGVzKFwiY29uZmlnXCIpKSB7XG4gICAgc291cmNlcy5wdXNoKFwiY29uZmlnXCIpO1xuICB9XG4gIHJldHVybiBzb3VyY2VzO1xufVxuXG5mdW5jdGlvbiBjb25maWdNYXBWYWx1ZSh2YWx1ZTogQ29uZmlnTWFwVmFsdWUgfCB1bmtub3duKTogc3RyaW5nIHwgbnVsbCB7XG4gIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgIGZvciAoY29uc3QgZW50cnkgb2YgdmFsdWUpIHtcbiAgICAgIGNvbnN0IHJlc29sdmVkID0gc3RyaW5nVXRpbHMudHJpbVRvTnVsbChlbnRyeSk7XG4gICAgICBpZiAocmVzb2x2ZWQgIT09IG51bGwpIHJldHVybiByZXNvbHZlZDtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgcmV0dXJuIHN0cmluZ1V0aWxzLnRyaW1Ub051bGwodmFsdWUpO1xufVxuXG4vKipcbiAqIFRoZSBmaXJzdCB2YWx1ZSB0aGF0IHJlc29sdmVzIGZvciBgaW5wdXRgLCBvciBgdW5kZWZpbmVkYC5cbiAqXG4gKiBAZXhhbXBsZVxuICogY29uc3QgZG9tYWluID0gY29uZmlnLnRleHQoW1wiVFVOTkVMX1BVQkxJQ19ET01BSU5cIiwgXCJQVUJMSUNfRE9NQUlOXCJdKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRleHQoaW5wdXQ6IENvbmZpZ0tleSwgb3B0aW9uczogQ29uZmlnT3B0aW9ucyA9IHt9KTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIHZhbHVlcyhpbnB1dCwgb3B0aW9ucykuYXQoMCk/LnZhbHVlO1xufVxuXG4vKiogUmVzb2x2ZSBhIGh1bWFuLWZyaWVuZGx5IG5hbWUgdGhyb3VnaCB7QGxpbmsgZW52aXJvbm1lbnRLZXlzfSBhbmQge0BsaW5rIHRleHR9LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVWYWx1ZShuYW1lOiBzdHJpbmcsIG9wdGlvbnM6IENvbmZpZ09wdGlvbnMgPSB7fSk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiB0ZXh0KGVudmlyb25tZW50S2V5cyhuYW1lKSwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogVGhlIFBSSU1BUlkgKGZ1bGx5LXNjb3BlZCkgbmFtZSBmb3IgYGlucHV0YCAtIHdoYXQgdG8gcHJpbnQgaW4gYSBsb2cgbGluZSBvciBhblxuICogZXJyb3IsIHNvIHRoZSBtZXNzYWdlIG5hbWVzIHRoZSB2YXJpYWJsZSBhIHJlYWRlciBzaG91bGQgc2V0LiBEbyBub3QgaW5kZXhcbiAqIGBrZXlzKC4uLilbMF1gIGZvciB0aGlzIGlmIGBpbnB1dGAgbWF5IGJlIGEgYmFyZSBzdHJpbmcuXG4gKlxuICogQGV4YW1wbGVcbiAqIGxvZ2dlci53YXJuKGAke2NvbmZpZy5uYW1lKEpXVF9TRUNSRVRfRU5WKX0gaXMgbm90IHNldGApO1xuICovXG5leHBvcnQgZnVuY3Rpb24gbmFtZShcbiAgaW5wdXQ6IENvbmZpZ0tleSxcbiAgb3B0aW9uczogUGljazxDb25maWdPcHRpb25zLCBcInNjb3BlXCIgfCBcInByZWZpeFwiPiA9IHt9LFxuKTogc3RyaW5nIHtcbiAgcmV0dXJuIGtleXMoaW5wdXQsIG9wdGlvbnMpWzBdID8/IFwiXCI7XG59XG5cbi8qKlxuICogU2FmZSBgLmVudi48bmFtZT5gIHN1ZmZpeGVzIGZvciBhIE5vZGUgZW52aXJvbm1lbnQsIGV4YWN0IHNwZWxsaW5nIGZpcnN0LlxuICogS25vd24gbG9uZyBhbmQgc2hvcnQgbmFtZXMgYXJlIGludGVyY2hhbmdlYWJsZTsgdW5rbm93biBuYW1lcyBwYXNzIHRocm91Z2guXG4gKi9cbmZ1bmN0aW9uIG5vZGVFbnZOYW1lcyhub2RlRW52OiB1bmtub3duKTogc3RyaW5nW10ge1xuICBjb25zdCBuYW1lID0gc3RyaW5nVXRpbHMudHJpbVRvTnVsbChub2RlRW52KT8udG9Mb3dlckNhc2UoKTtcbiAgaWYgKCFuYW1lIHx8ICEvXlthLXowLTlfLV0rJC8udGVzdChuYW1lKSkgcmV0dXJuIFtdO1xuICBmb3IgKGNvbnN0IFtjYW5vbmljYWwsIGFsdGVybmF0aXZlc10gb2YgT2JqZWN0LmVudHJpZXMoTk9ERV9FTlZfQUxURVJOQVRJVkVTKSkge1xuICAgIGNvbnN0IG5hbWVzOiByZWFkb25seSBzdHJpbmdbXSA9IGFsdGVybmF0aXZlcztcbiAgICBpZiAobmFtZSA9PT0gY2Fub25pY2FsIHx8IG5hbWVzLmluY2x1ZGVzKG5hbWUpKSB7XG4gICAgICByZXR1cm4gWy4uLm9iamVjdC5zZXF1ZW5jZShuYW1lLCBjYW5vbmljYWwsIGFsdGVybmF0aXZlcykuZGlzdGluY3QoKV07XG4gICAgfVxuICB9XG4gIHJldHVybiBbbmFtZV07XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhIHN0cmluZzogYGNvbmZpZ3VyZWRgIHdoZW4gbm9uLWVtcHR5LCBlbHNlIHtAbGluayB0ZXh0fSwgZWxzZSBgdW5kZWZpbmVkYC5cbiAqXG4gKiBUaGUgY29lcmNpb24gcnVsZXMgYXJlIGRlbGliZXJhdGVseSBsb29zZSAoYG9uYCAvIGB5ZXNgIC8gYDFgIGFyZSBhbGxcbiAqIGB0cnVlYCkgYmVjYXVzZSB2YWx1ZXMgbWF5IGNvbWUgZnJvbSBhIGZpbGUgYSBodW1hbiB0eXBlZC5cbiAqXG4gKiBAZXhhbXBsZVxuICogY29uZmlnLnN0cmluZyhvcHRpb25zLmhvc3QsIFwiU01UUF9IT1NUXCIpO1xuICovXG5leHBvcnQgZnVuY3Rpb24gc3RyaW5nKFxuICBjb25maWd1cmVkOiB1bmtub3duLFxuICBpbnB1dDogQ29uZmlnS2V5LFxuICBvcHRpb25zPzogQ29uZmlnT3B0aW9ucyxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiBzdHJpbmdVdGlscy50cmltVG9OdWxsKGNvbmZpZ3VyZWQpID8/IHRleHQoaW5wdXQsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFJlc29sdmUgYSBib29sZWFuIHRocm91Z2ggYG9iamVjdC50b0Jvb2xlYW5gLiBgdW5kZWZpbmVkYCB3aGVuIG5laXRoZXIgc291cmNlXG4gKiBpcyBpbnRlcnByZXRhYmxlLCBzbyB0aGUgY2FsbGVyIHBpY2tzIGEgZGVmYXVsdCB3aXRoIGA/P2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBib29sZWFuKFxuICBjb25maWd1cmVkOiB1bmtub3duLFxuICBpbnB1dDogQ29uZmlnS2V5LFxuICBvcHRpb25zPzogQ29uZmlnT3B0aW9ucyxcbik6IGJvb2xlYW4gfCB1bmRlZmluZWQge1xuICByZXR1cm4gb2JqZWN0LnRvQm9vbGVhbihjb25maWd1cmVkKSA/PyBvYmplY3QudG9Cb29sZWFuKHRleHQoaW5wdXQsIG9wdGlvbnMpKTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgcG9zaXRpdmUgbnVtYmVyIHRoYXQgbWF5IGJlIGZyYWN0aW9uYWwgKGEgc2NvcmUgdGhyZXNob2xkLCBhIHJhdGlvKS5cbiAqIFVzZSB7QGxpbmsgcG9zaXRpdmVJbnR9IGZvciBhIGNvdW50LCBwb3J0LCBvciB0aW1lb3V0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcG9zaXRpdmVOdW1iZXIoXG4gIGNvbmZpZ3VyZWQ6IHVua25vd24sXG4gIGlucHV0OiBDb25maWdLZXksXG4gIGZhbGxiYWNrOiBudW1iZXIsXG4gIG9wdGlvbnM/OiBDb25maWdPcHRpb25zLFxuKTogbnVtYmVyIHtcbiAgY29uc3QgZnJvbUNvbmZpZyA9IHBvc2l0aXZlTnVtYmVyVmFsdWUuc2FmZVBhcnNlKGNvbmZpZ3VyZWQpO1xuICBpZiAoZnJvbUNvbmZpZy5zdWNjZXNzKSByZXR1cm4gZnJvbUNvbmZpZy5kYXRhO1xuICBjb25zdCBmcm9tU291cmNlcyA9IHBvc2l0aXZlTnVtYmVyVmFsdWUuc2FmZVBhcnNlKHRleHQoaW5wdXQsIG9wdGlvbnMpKTtcbiAgcmV0dXJuIGZyb21Tb3VyY2VzLnN1Y2Nlc3MgPyBmcm9tU291cmNlcy5kYXRhIDogZmFsbGJhY2s7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhIHBvc2l0aXZlIGludGVnZXIgKGEgcG9ydCwgYSB0aW1lb3V0LCBhIHBhZ2Ugc2l6ZSksIGZsb29yZWQuIEFcbiAqIG5vbi1udW1lcmljIG9yIG5vbi1wb3NpdGl2ZSB2YWx1ZSBpcyB0cmVhdGVkIGFzIEFCU0VOVCByYXRoZXIgdGhhbiBmYXRhbCAtXG4gKiB0aGVzZSBhcmUgY2VpbGluZ3Mgd2hlcmUgYSBzYW5lIGRlZmF1bHQgYmVhdHMgYSBib290IGZhaWx1cmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwb3NpdGl2ZUludChcbiAgY29uZmlndXJlZDogdW5rbm93bixcbiAgaW5wdXQ6IENvbmZpZ0tleSxcbiAgZmFsbGJhY2s6IG51bWJlcixcbiAgb3B0aW9ucz86IENvbmZpZ09wdGlvbnMsXG4pOiBudW1iZXIge1xuICBjb25zdCBmcm9tQ29uZmlnID0gcG9zaXRpdmVJbnRWYWx1ZS5zYWZlUGFyc2UoY29uZmlndXJlZCk7XG4gIGlmIChmcm9tQ29uZmlnLnN1Y2Nlc3MpIHJldHVybiBmcm9tQ29uZmlnLmRhdGE7XG4gIGNvbnN0IGZyb21Tb3VyY2VzID0gcG9zaXRpdmVJbnRWYWx1ZS5zYWZlUGFyc2UodGV4dChpbnB1dCwgb3B0aW9ucykpO1xuICByZXR1cm4gZnJvbVNvdXJjZXMuc3VjY2VzcyA/IGZyb21Tb3VyY2VzLmRhdGEgOiBNYXRoLmZsb29yKGZhbGxiYWNrKTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgVENQIHBvcnQgYmV0d2VlbiAxIGFuZCB7QGxpbmsgTUFYX1RDUF9QT1JUfS4gSW52YWxpZCBjb25maWd1cmVkIG9yXG4gKiBzb3VyY2VkIHZhbHVlcyBmYWxsIGJhY2sgdG8gdGhlIGNhbGxlcidzIGRlZmF1bHQsIHdoaWNoIG1heSBiZSBhIHNlbnRpbmVsXG4gKiBzdWNoIGFzIGAwYCB3aGVuIHRoZSBjYWxsZXIgdXNlcyBvbmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwb3J0KFxuICBjb25maWd1cmVkOiB1bmtub3duLFxuICBpbnB1dDogQ29uZmlnS2V5LFxuICBmYWxsYmFjazogbnVtYmVyLFxuICBvcHRpb25zPzogQ29uZmlnT3B0aW9ucyxcbik6IG51bWJlciB7XG4gIGNvbnN0IGZyb21Db25maWcgPSBwb3J0VmFsdWVTY2hlbWEuc2FmZVBhcnNlKGNvbmZpZ3VyZWQpO1xuICBpZiAoZnJvbUNvbmZpZy5zdWNjZXNzKSByZXR1cm4gZnJvbUNvbmZpZy5kYXRhO1xuICBjb25zdCBmcm9tU291cmNlcyA9IHBvcnRWYWx1ZVNjaGVtYS5zYWZlUGFyc2UodGV4dChpbnB1dCwgb3B0aW9ucykpO1xuICByZXR1cm4gZnJvbVNvdXJjZXMuc3VjY2VzcyA/IGZyb21Tb3VyY2VzLmRhdGEgOiBmYWxsYmFjaztcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgbGlzdCB0aHJvdWdoIGBzdHJpbmdVdGlscy5wYXJzZUxpc3RgLCBzbyBhbiBhcnJheSBmcm9tIHR5cGVkIGNvbmZpZyBhbmQgYVxuICogYFwiYSwgYiBjXCJgIHN0cmluZyBub3JtYWxpemUgaWRlbnRpY2FsbHkuIGBbXWAgd2hlbiBuZWl0aGVyIHNvdXJjZSBoYXMgZW50cmllcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxpc3QoXG4gIGNvbmZpZ3VyZWQ6IHN0cmluZyB8IHJlYWRvbmx5IHN0cmluZ1tdIHwgdW5kZWZpbmVkIHwgbnVsbCxcbiAgaW5wdXQ6IENvbmZpZ0tleSxcbiAgdHJhbnNmb3JtPzogKGVudHJ5OiBzdHJpbmcpID0+IHN0cmluZyxcbiAgb3B0aW9ucz86IENvbmZpZ09wdGlvbnMsXG4pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IGZyb21Db25maWcgPSBzdHJpbmdVdGlscy5wYXJzZUxpc3QoY29uZmlndXJlZCwgdHJhbnNmb3JtKTtcbiAgcmV0dXJuIGZyb21Db25maWcubGVuZ3RoID4gMFxuICAgID8gZnJvbUNvbmZpZ1xuICAgIDogc3RyaW5nVXRpbHMucGFyc2VMaXN0KHRleHQoaW5wdXQsIG9wdGlvbnMpLCB0cmFuc2Zvcm0pO1xufVxuXG4vKipcbiAqIFRoZSBEYXRhYnJpY2tzIGJ1bmRsZSBvdXRwdXQgZm9yIGBjd2RgIC0gYGRhdGFicmlja3MgYnVuZGxlIHZhbGlkYXRlIC0tb3V0cHV0XG4gKiBqc29uYCBydW4gZnJvbSB0aGUgZGlyZWN0b3J5IGhvbGRpbmcgYGRhdGFicmlja3MueW1sYCwgd2l0aCB0aGUgY29uZmlnIGZpbGUnc1xuICogcGF0aC4gQSBub24temVybyB2YWxpZGF0aW9uIG1heSBzdGlsbCByZXR1cm4gcGFydGlhbCBKU09OIHdpdGggdXNhYmxlIEFwcFxuICogY29uZmlnLiBgdW5kZWZpbmVkYCB3aGVuIGJ1bmRsZSByZWFkcyBhcmUgZGlzYWJsZWQsIHRoZSBwcm9jZXNzIGlzIHByb2R1Y3Rpb25cbiAqIG9yIGEgZGVwbG95ZWQgQXBwIHdpdGhvdXQgYW4gZXhwbGljaXQgb3ZlcnJpZGUsIHRoZXJlIGlzIG5vIGJ1bmRsZSwgb3IgdGhlXG4gKiBDTEkgcHJvZHVjZXMgbm8gSlNPTi5cbiAqXG4gKiBQYXJzZWQgdmFsaWRhdGlvbiBvdXRwdXQgaXMgY2FjaGVkIGJ5IGJ1bmRsZSBwYXRoIGFuZCBEYXRhYnJpY2tzIHByb2ZpbGUuXG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gYnVuZGxlRmlsZShjd2Q/OiBzdHJpbmcgfCBudWxsKTogQ29uZmlnRmlsZSB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IG92ZXJyaWRlID0gb2JqZWN0LnRvQm9vbGVhbihwcm9jZXNzLmVudltDT05GSUdfQlVORExFX0tFWV0pO1xuICBpZiAob3ZlcnJpZGUgPT09IGZhbHNlKSByZXR1cm4gdW5kZWZpbmVkO1xuICBpZiAoXG4gICAgb3ZlcnJpZGUgPT09IHVuZGVmaW5lZCAmJlxuICAgIChwcm9jZXNzLmVudi5OT0RFX0VOVj8udHJpbSgpLnRvTG93ZXJDYXNlKCkgPT09IFwicHJvZHVjdGlvblwiIHx8IGlzRGF0YWJyaWNrc0FwcEVudigpKVxuICApIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZVdvcmtpbmdEaXJlY3RvcnkoY3dkKTtcbiAgcmV0dXJuIGxvYWRCdW5kbGVGaWxlKHJlc29sdmVkLCBzdHJpbmdVdGlscy50cmltVG9OdWxsKHByb2Nlc3MuZW52LkRBVEFCUklDS1NfQ09ORklHX1BST0ZJTEUpKTtcbn1cblxuLyoqIFRoZSBwYXJzZWQgYGFwcC55YW1sYCAvIGBhcHAueW1sYCBmb3IgYGN3ZGAsIHdoZW4gbG9jYWwgQXBwIGNvbmZpZyByZWFkcyBhcmUgZW5hYmxlZC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcHBGaWxlKGN3ZD86IHN0cmluZyB8IG51bGwpOiBDb25maWdGaWxlIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgZW5hYmxlZCA9IG9iamVjdC50b0Jvb2xlYW4ocHJvY2Vzcy5lbnZbQ09ORklHX0FQUF9LRVldKSA/PyAhaXNEYXRhYnJpY2tzQXBwRW52KCk7XG4gIGlmICghZW5hYmxlZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIGxvYWRBcHBGaWxlKHJlc29sdmVXb3JraW5nRGlyZWN0b3J5KGN3ZCkpO1xufVxuXG4vKiogVGhlIHNpbmdsZSBidW5kbGUgQXBwJ3MgcmVzb2x2ZWQgZW52aXJvbm1lbnQsIHdoZW4gYXZhaWxhYmxlLiAqL1xuZnVuY3Rpb24gYnVuZGxlRW52aXJvbm1lbnQob3B0aW9uczogQ29uZmlnT3B0aW9ucyk6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gfCB1bmRlZmluZWQge1xuICBjb25zdCBkYXRhID0gc291cmNlRGF0YShvcHRpb25zLmJ1bmRsZURhdGEpID8/IGJ1bmRsZUZpbGUob3B0aW9ucy5jd2QpPy5kYXRhO1xuICByZXR1cm4gZGF0YSA/IGZsYXR0ZW5CdW5kbGVFbnYoZGF0YSkgOiB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIGFwcEVudmlyb25tZW50KG9wdGlvbnM6IENvbmZpZ09wdGlvbnMpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgZGF0YSA9IHNvdXJjZURhdGEob3B0aW9ucy5hcHBEYXRhKSA/PyBhcHBGaWxlKG9wdGlvbnMuY3dkKT8uZGF0YTtcbiAgcmV0dXJuIGRhdGEgPyBmbGF0dGVuQXBwRW52KGRhdGEpIDogdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiBzb3VyY2VEYXRhKFxuICBzb3VyY2U6IENvbmZpZ0ZpbGUgfCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZCxcbik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkIHtcbiAgaWYgKCFzb3VyY2UpIHJldHVybiB1bmRlZmluZWQ7XG4gIGlmIChcInBhdGhcIiBpbiBzb3VyY2UgJiYgdHlwZW9mIHNvdXJjZS5wYXRoID09PSBcInN0cmluZ1wiICYmIG9iamVjdC5pc1JlY29yZChzb3VyY2UuZGF0YSkpIHtcbiAgICByZXR1cm4gc291cmNlLmRhdGE7XG4gIH1cbiAgcmV0dXJuIHNvdXJjZSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuLyoqIFBhcnNlZCBgLmVudmAgZm9yIGBjd2RgLCBvciBge31gOyBwYXJzZWQgZmlsZSBkYXRhIGlzIGNhY2hlZCBieSBwYXRoLiAqL1xuZnVuY3Rpb24gZG90ZW52KGN3ZD86IHN0cmluZyB8IG51bGwpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgY29uc3QgZW5hYmxlZCA9IG9iamVjdC50b0Jvb2xlYW4ocHJvY2Vzcy5lbnZbQ09ORklHX0RPVEVOVl9LRVldKSA/PyAhaXNEYXRhYnJpY2tzQXBwRW52KCk7XG4gIGlmICghZW5hYmxlZCkgcmV0dXJuIHt9O1xuICBjb25zdCByZXNvbHZlZCA9IHJlc29sdmVXb3JraW5nRGlyZWN0b3J5KGN3ZCk7XG4gIHJldHVybiBsb2FkRG90ZW52KHJlc29sdmVkLCBub2RlRW52TmFtZXMocHJvY2Vzcy5lbnYuTk9ERV9FTlYpKTtcbn1cblxuLyoqIE1hcHMgZm9yIG9uZSBzb3VyY2UgaW4gcHJlY2VkZW5jZSBvcmRlci4gKi9cbmZ1bmN0aW9uIHJlYWQoXG4gIHNvdXJjZTogQ29uZmlnU291cmNlLFxuICBvcHRpb25zOiBDb25maWdPcHRpb25zLFxuKTogb2JqZWN0LlNlcXVlbmNlPFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIHVua25vd24+Pj4ge1xuICByZXR1cm4gb2JqZWN0LnNlcXVlbmNlKHtcbiAgICAqW1N5bWJvbC5pdGVyYXRvcl0oKTogR2VuZXJhdG9yPFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIHVua25vd24+Pj4ge1xuICAgICAgc3dpdGNoIChzb3VyY2UpIHtcbiAgICAgICAgY2FzZSBcImNvbmZpZ1wiOiB7XG4gICAgICAgICAgY29uc3QgZGF0YSA9IG9wdGlvbnMuZGF0YTtcbiAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShkYXRhKSkge1xuICAgICAgICAgICAgeWllbGQqIGRhdGE7XG4gICAgICAgICAgfSBlbHNlIGlmIChkYXRhICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHlpZWxkIGRhdGEgYXMgQ29uZmlnRGF0YTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgY2FzZSBcImVudlwiOlxuICAgICAgICAgIHlpZWxkIHByb2Nlc3MuZW52O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiZG90ZW52XCI6XG4gICAgICAgICAgeWllbGQgZG90ZW52KG9wdGlvbnMuY3dkKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcImJ1bmRsZVwiOiB7XG4gICAgICAgICAgY29uc3QgZW52aXJvbm1lbnQgPSBidW5kbGVFbnZpcm9ubWVudChvcHRpb25zKTtcbiAgICAgICAgICBpZiAoZW52aXJvbm1lbnQpIHlpZWxkIGVudmlyb25tZW50O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGNhc2UgXCJhcHBcIjoge1xuICAgICAgICAgIGNvbnN0IGVudmlyb25tZW50ID0gYXBwRW52aXJvbm1lbnQob3B0aW9ucyk7XG4gICAgICAgICAgaWYgKGVudmlyb25tZW50KSB5aWVsZCBlbnZpcm9ubWVudDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoYFVua25vd24gY29uZmlnIHNvdXJjZTogJHtzb3VyY2V9YCk7XG4gICAgICB9XG4gICAgfSxcbiAgfSk7XG59XG5cbi8qKlxuICogTG9jYXRlIGBuYW1lc2AgZnJvbSBgY3dkYCBvdXR3YXJkLiBgY3dkYCBpdHNlbGYgaXMgY2hlY2tlZCBiZWZvcmUgdGhlXG4gKiBkaXNjb3ZlcmVkIHByb2plY3Qgcm9vdHMgc28gYSBwYWNrYWdlLWxvY2FsIGZpbGUgd2lucyBvdmVyIHRoZSB3b3Jrc3BhY2Uncy5cbiAqL1xuZnVuY3Rpb24gZmluZENvbmZpZ0ZpbGUoY3dkOiBzdHJpbmcsIG5hbWVzOiByZWFkb25seSBzdHJpbmdbXSk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHN0YXJ0ID0gcmVzb2x2ZShjd2QpO1xuICBjb25zdCBrZXkgPSBKU09OLnN0cmluZ2lmeShbc3RhcnQsIC4uLm5hbWVzXSk7XG4gIGlmIChjb25maWdGaWxlQ2FjaGUuaGFzKGtleSkpIHJldHVybiBjb25maWdGaWxlQ2FjaGUuZ2V0KGtleSk7XG4gIGNvbnN0IHJvb3QgPSByZXNvbHZlUHJvamVjdFJvb3Qoc3RhcnQpO1xuICBjb25zdCBwYXRoRnJvbVJvb3QgPSByb290ID8gcmVsYXRpdmUocm9vdCwgc3RhcnQpIDogdW5kZWZpbmVkO1xuICBjb25zdCBib3VuZGFyeSA9XG4gICAgcm9vdCAmJlxuICAgIHBhdGhGcm9tUm9vdCAhPT0gdW5kZWZpbmVkICYmXG4gICAgIWlzQWJzb2x1dGUocGF0aEZyb21Sb290KSAmJlxuICAgIHBhdGhGcm9tUm9vdCAhPT0gXCIuLlwiICYmXG4gICAgIXBhdGhGcm9tUm9vdC5zdGFydHNXaXRoKGAuLiR7c2VwfWApXG4gICAgICA/IHJvb3RcbiAgICAgIDogdW5kZWZpbmVkO1xuICBmb3IgKGxldCBkaXIgPSBzdGFydDsgOyBkaXIgPSBkaXJuYW1lKGRpcikpIHtcbiAgICBmb3IgKGNvbnN0IG5hbWUgb2YgbmFtZXMpIHtcbiAgICAgIGNvbnN0IHBhdGggPSByZXNvbHZlKGRpciwgbmFtZSk7XG4gICAgICBpZiAoc3RhdFN5bmMocGF0aCk/LmlzRmlsZSgpKSB7XG4gICAgICAgIGNvbmZpZ0ZpbGVDYWNoZS5zZXQoa2V5LCBwYXRoKTtcbiAgICAgICAgcmV0dXJuIHBhdGg7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChib3VuZGFyeSA9PT0gdW5kZWZpbmVkIHx8IGRpciA9PT0gYm91bmRhcnkpIGJyZWFrO1xuICB9XG4gIGNvbmZpZ0ZpbGVDYWNoZS5zZXQoa2V5LCB1bmRlZmluZWQpO1xuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiBsb2FkRG90ZW52KFxuICBjd2Q6IHN0cmluZyxcbiAgZW52aXJvbm1lbnRzOiByZWFkb25seSBzdHJpbmdbXSxcbik6IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICBjb25zdCBuYW1lcyA9IFsuLi5lbnZpcm9ubWVudHMubWFwKChuYW1lKSA9PiBgJHtET1RFTlZfRklMRV9OQU1FfS4ke25hbWV9YCksIERPVEVOVl9GSUxFX05BTUVdO1xuICBjb25zdCBwYXRoID0gZmluZENvbmZpZ0ZpbGUoY3dkLCBuYW1lcyk7XG4gIGlmICghcGF0aCkgcmV0dXJuIHt9O1xuICByZXR1cm4gKFxuICAgIGNhY2hlZFJlY29yZChKU09OLnN0cmluZ2lmeShbXCJkb3RlbnZcIiwgcGF0aF0pLCAoKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gcGFyc2VFbnYocmVhZEZpbGVTeW5jKHBhdGgsIFwidXRmOFwiKSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oXCJmYWlsZWQgdG8gcmVhZCBkb3RlbnYgZmlsZVwiLCB7IHBhdGggfSk7XG4gICAgICAgIHJldHVybiB7fTtcbiAgICAgIH1cbiAgICB9KSA/PyB7fVxuICApO1xufVxuXG5mdW5jdGlvbiBsb2FkQnVuZGxlRmlsZShjd2Q6IHN0cmluZywgcHJvZmlsZTogc3RyaW5nIHwgbnVsbCk6IENvbmZpZ0ZpbGUgfCB1bmRlZmluZWQge1xuICBjb25zdCBwYXRoID0gZmluZENvbmZpZ0ZpbGUoY3dkLCBCVU5ETEVfRklMRV9OQU1FUyk7XG4gIGlmICghcGF0aCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgZGF0YSA9IGNhY2hlZFJlY29yZChKU09OLnN0cmluZ2lmeShbXCJidW5kbGVcIiwgcGF0aCwgcHJvZmlsZV0pLCAoKSA9PiB7XG4gICAgY29uc3QgYXJncyA9IFtcbiAgICAgIFwiYnVuZGxlXCIsXG4gICAgICBcInZhbGlkYXRlXCIsXG4gICAgICBcIi0tb3V0cHV0XCIsXG4gICAgICBcImpzb25cIixcbiAgICAgIC4uLihwcm9maWxlID09PSBudWxsID8gW10gOiBbXCItLXByb2ZpbGVcIiwgcHJvZmlsZV0pLFxuICAgIF07XG4gICAgY29uc3QgcmVzdWx0ID0gc3Bhd25TeW5jKFwiZGF0YWJyaWNrc1wiLCBhcmdzLCB7XG4gICAgICBjd2Q6IHJlc29sdmUocGF0aCwgXCIuLlwiKSxcbiAgICAgIGVuY29kaW5nOiBcInV0ZjhcIixcbiAgICAgIHN0ZGlvOiBbXCJpZ25vcmVcIiwgXCJwaXBlXCIsIFwicGlwZVwiXSxcbiAgICB9KTtcbiAgICBjb25zdCBvdXRwdXQgPSBzdHJpbmdVdGlscy50cmltVG9OdWxsKHJlc3VsdC5zdGRvdXQpO1xuICAgIGNvbnN0IGVycm9yID0gc3RyaW5nVXRpbHMudHJpbVRvTnVsbChyZXN1bHQuc3RkZXJyKTtcbiAgICBpZiAob3V0cHV0ID09PSBudWxsKSB7XG4gICAgICBsb2dnZXIuZGVidWcoXCJidW5kbGUgdmFsaWRhdGUgcHJvZHVjZWQgbm8gSlNPTlwiLCB7IHBhdGgsIHN0YXR1czogcmVzdWx0LnN0YXR1cywgZXJyb3IgfSk7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBjb25zdCBwYXJzZWQgPSBqc29uLnBhcnNlUmVjb3JkKG91dHB1dCk7XG4gICAgaWYgKCFwYXJzZWQpIHtcbiAgICAgIGxvZ2dlci53YXJuKFwiZmFpbGVkIHRvIHBhcnNlIGJ1bmRsZSB2YWxpZGF0ZSBvdXRwdXRcIiwgeyBwYXRoLCBzdGF0dXM6IHJlc3VsdC5zdGF0dXMgfSk7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBpZiAocmVzdWx0LnN0YXR1cyAhPT0gMCkge1xuICAgICAgbG9nZ2VyLmRlYnVnKFwidXNpbmcgcGFydGlhbCBidW5kbGUgb3V0cHV0XCIsIHsgcGF0aCwgc3RhdHVzOiByZXN1bHQuc3RhdHVzLCBlcnJvciB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHBhcnNlZDtcbiAgfSk7XG4gIHJldHVybiBkYXRhID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiB7IHBhdGgsIGRhdGEgfTtcbn1cblxuZnVuY3Rpb24gbG9hZEFwcEZpbGUoY3dkOiBzdHJpbmcpOiBDb25maWdGaWxlIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcGF0aCA9IGZpbmRDb25maWdGaWxlKGN3ZCwgQVBQX0ZJTEVfTkFNRVMpO1xuICBpZiAoIXBhdGgpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IGRhdGEgPSBjYWNoZWRSZWNvcmQoSlNPTi5zdHJpbmdpZnkoW1wiYXBwXCIsIHBhdGhdKSwgKCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXJzZWQgPSBwYXJzZVlhbWwocmVhZEZpbGVTeW5jKHBhdGgsIFwidXRmOFwiKSk7XG4gICAgICByZXR1cm4gb2JqZWN0LmlzUmVjb3JkKHBhcnNlZCkgPyBwYXJzZWQgOiB1bmRlZmluZWQ7XG4gICAgfSBjYXRjaCB7XG4gICAgICBsb2dnZXIud2FybihcImZhaWxlZCB0byBwYXJzZSBhcHAgeWFtbFwiLCB7IHBhdGggfSk7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgfSk7XG4gIHJldHVybiBkYXRhID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiB7IHBhdGgsIGRhdGEgfTtcbn1cbiJdfQ==
|