@dbx-tools/shared-fs 0.6.10
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 +56 -0
- package/index.ts +14 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +10 -0
- package/lib/src/base-fs.d.ts +268 -0
- package/lib/src/base-fs.js +622 -0
- package/lib/src/fs.d.ts +110 -0
- package/lib/src/fs.js +2 -0
- package/lib/src/memory-fs.d.ts +46 -0
- package/lib/src/memory-fs.js +131 -0
- package/lib/src/posix-path.d.ts +80 -0
- package/lib/src/posix-path.js +208 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +53 -0
- package/src/base-fs.ts +882 -0
- package/src/fs.ts +142 -0
- package/src/memory-fs.ts +174 -0
- package/src/posix-path.ts +219 -0
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract {@link FileSystem} base: lifecycle, rooted POSIX paths, encoding, and
|
|
3
|
+
* portable fallbacks so a concrete backend only implements low-level I/O.
|
|
4
|
+
*
|
|
5
|
+
* A new adapter typically overrides:
|
|
6
|
+
* - {@link onInit} / {@link onClose} (optional)
|
|
7
|
+
* - {@link createRootDirectory} when {@link BaseFileSystemOptions.createRoot} is set
|
|
8
|
+
* - {@link toBackendPath} when the backend needs non-POSIX separators
|
|
9
|
+
* - {@link preparePath} for post-resolve checks (e.g. symlink containment)
|
|
10
|
+
* - the `*At` primitives and {@link isNotFoundError}
|
|
11
|
+
* - optional `try*` hooks for native append / copy / move
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { error, functionModule, hash, object } from "@dbx-tools/shared-core";
|
|
16
|
+
import * as posixPath from "./posix-path.js";
|
|
17
|
+
/**
|
|
18
|
+
* Characters no backend accepts inside a single path component: a separator
|
|
19
|
+
* (which would silently deepen the path) or a NUL / control character.
|
|
20
|
+
*
|
|
21
|
+
* This is a DENY-list on purpose. Spaces, `@`, `&`, `#`, parentheses and
|
|
22
|
+
* non-ASCII are all legal directory names on POSIX and in a Databricks
|
|
23
|
+
* workspace, and replacing one with a hash points the filesystem at a
|
|
24
|
+
* directory that does not exist - a failure that is silent and very hard to
|
|
25
|
+
* trace back. Only reject what genuinely cannot be a component.
|
|
26
|
+
*/
|
|
27
|
+
const UNSAFE_PATH_SEGMENT = /[\\/\u0000-\u001F\u007F]/;
|
|
28
|
+
/**
|
|
29
|
+
* Turn {@link root} into a POSIX filesystem root:
|
|
30
|
+
*
|
|
31
|
+
* 1. Expand one-or-many input segments
|
|
32
|
+
* 2. Strings split on `/` (and `\`); objects/arrays FNV-hash as one piece
|
|
33
|
+
* 3. Each resulting component that cannot be a path component - see
|
|
34
|
+
* {@link UNSAFE_PATH_SEGMENT} - is replaced with {@link hash.fnvHash}
|
|
35
|
+
* 4. Join with `/` and run {@link posixPath.normalizeRoot}
|
|
36
|
+
*
|
|
37
|
+
* Defaults to `/`. A leading `/` on the first string segment is preserved.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* normalizeFileSystemRoot("/cool/wow"); // "/cool/wow"
|
|
41
|
+
* normalizeFileSystemRoot("/Users/me@corp.com/My Notes"); // unchanged
|
|
42
|
+
* normalizeFileSystemRoot(["/path", { user: 1 }, true]); // "/path/<hash>/true"
|
|
43
|
+
*/
|
|
44
|
+
export function normalizeFileSystemRoot(root) {
|
|
45
|
+
if (root === undefined)
|
|
46
|
+
return "/";
|
|
47
|
+
const segments = object.toOneOrMany(root);
|
|
48
|
+
const absolute = isAbsoluteRootStart(segments[0]);
|
|
49
|
+
const parts = [];
|
|
50
|
+
for (const segment of segments) {
|
|
51
|
+
if (segment === null || segment === undefined) {
|
|
52
|
+
throw new TypeError("Filesystem root segments must be non-null");
|
|
53
|
+
}
|
|
54
|
+
appendRootParts(parts, segment);
|
|
55
|
+
}
|
|
56
|
+
if (parts.length === 0)
|
|
57
|
+
return "/";
|
|
58
|
+
const joined = parts.join("/");
|
|
59
|
+
return posixPath.normalizeRoot(absolute ? `/${joined}` : joined);
|
|
60
|
+
}
|
|
61
|
+
function isAbsoluteRootStart(segment) {
|
|
62
|
+
return typeof segment === "string" && posixPath.isAbsolute(segment.trim());
|
|
63
|
+
}
|
|
64
|
+
function appendRootParts(parts, segment) {
|
|
65
|
+
switch (typeof segment) {
|
|
66
|
+
case "string":
|
|
67
|
+
for (const piece of splitPathPieces(segment)) {
|
|
68
|
+
parts.push(sanitizePathSegment(piece));
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
71
|
+
case "number":
|
|
72
|
+
case "boolean":
|
|
73
|
+
case "bigint":
|
|
74
|
+
parts.push(sanitizePathSegment(String(segment)));
|
|
75
|
+
return;
|
|
76
|
+
default:
|
|
77
|
+
parts.push(hash.fnvHash(segment));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Split on `/` (after `\` → `/`); drop empty pieces from
|
|
82
|
+
* leading/trailing/double slashes and no-op `.` pieces.
|
|
83
|
+
*/
|
|
84
|
+
function splitPathPieces(input) {
|
|
85
|
+
return posixPath
|
|
86
|
+
.toPosix(input.trim())
|
|
87
|
+
.split("/")
|
|
88
|
+
.filter((piece) => piece.length > 0 && piece !== ".");
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Keep a usable path component verbatim; FNV-hash one that cannot be used.
|
|
92
|
+
*
|
|
93
|
+
* `..` is hashed rather than dropped so a root can never traverse above
|
|
94
|
+
* itself while the offending segment stays visible in the resolved root.
|
|
95
|
+
*/
|
|
96
|
+
function sanitizePathSegment(segment) {
|
|
97
|
+
if (segment === ".." || UNSAFE_PATH_SEGMENT.test(segment)) {
|
|
98
|
+
return hash.fnvHash(segment);
|
|
99
|
+
}
|
|
100
|
+
return segment;
|
|
101
|
+
}
|
|
102
|
+
export class FileSystemError extends Error {
|
|
103
|
+
code;
|
|
104
|
+
path;
|
|
105
|
+
name = "FileSystemError";
|
|
106
|
+
constructor(code, message, path, options) {
|
|
107
|
+
super(message, options?.cause !== undefined ? { cause: error.toError(options.cause) } : undefined);
|
|
108
|
+
this.code = code;
|
|
109
|
+
this.path = path;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Infer a {@link FileSystemErrorCode} from HTTP status / message tokens on an
|
|
114
|
+
* unknown thrown value (via {@link error.errorContext}).
|
|
115
|
+
*
|
|
116
|
+
* Covers common SDK / REST wording so adapters do not reimplement the same
|
|
117
|
+
* "not found" / "already exists" checks. Returns undefined when nothing matches.
|
|
118
|
+
*/
|
|
119
|
+
export function inferFileSystemErrorCode(err) {
|
|
120
|
+
const ctx = error.errorContext(err);
|
|
121
|
+
if (ctx.hasStatusCode(404) || ctx.hasMessage("not", "found") || ctx.hasMessage("not", "exist")) {
|
|
122
|
+
return "NOT_FOUND";
|
|
123
|
+
}
|
|
124
|
+
if (ctx.hasStatusCode(409) || ctx.hasMessage("already", "exists")) {
|
|
125
|
+
return "ALREADY_EXISTS";
|
|
126
|
+
}
|
|
127
|
+
// Before "not"+"directory": "directory not empty" contains both of those tokens.
|
|
128
|
+
if (ctx.hasMessage("not", "empty")) {
|
|
129
|
+
return "DIRECTORY_NOT_EMPTY";
|
|
130
|
+
}
|
|
131
|
+
if (ctx.hasMessage("not", "directory")) {
|
|
132
|
+
return "NOT_DIRECTORY";
|
|
133
|
+
}
|
|
134
|
+
if (ctx.hasMessage("is", "directory") || ctx.hasMessage("not", "file")) {
|
|
135
|
+
return "IS_DIRECTORY";
|
|
136
|
+
}
|
|
137
|
+
if (ctx.hasStatusCode(401, 403) ||
|
|
138
|
+
ctx.hasMessage("permission", "denied") ||
|
|
139
|
+
ctx.hasMessage("access", "denied")) {
|
|
140
|
+
return "PERMISSION_DENIED";
|
|
141
|
+
}
|
|
142
|
+
if (ctx.hasMessage("read", "only")) {
|
|
143
|
+
return "READ_ONLY";
|
|
144
|
+
}
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Map an unknown backend failure into a {@link FileSystemError}.
|
|
149
|
+
*
|
|
150
|
+
* Prefer a backend-specific {@link codeOf} classifier (errno, SDK code). When
|
|
151
|
+
* it returns undefined, falls back to {@link inferFileSystemErrorCode}. Message
|
|
152
|
+
* and cause always go through `@dbx-tools/shared-core` {@link error} helpers.
|
|
153
|
+
*/
|
|
154
|
+
export function mapFileSystemError(err, filePath, codeOf) {
|
|
155
|
+
if (err instanceof FileSystemError)
|
|
156
|
+
return err;
|
|
157
|
+
const message = error.errorMessage(err);
|
|
158
|
+
return new FileSystemError(codeOf?.(err) ?? inferFileSystemErrorCode(err) ?? "IO_ERROR", message || `Filesystem operation failed: ${filePath}`, filePath, { cause: error.toError(err) });
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Base implementation for local, remote, and virtual filesystems.
|
|
162
|
+
*
|
|
163
|
+
* Subclasses implement the low-level `*At` primitives. This class provides:
|
|
164
|
+
*
|
|
165
|
+
* - Memoized {@link _init} (so an explicit {@link init} call is optional)
|
|
166
|
+
* - Optional root creation via {@link createRootDirectory}
|
|
167
|
+
* - POSIX-only rooted path normalization and traversal protection
|
|
168
|
+
* - {@link toBackendPath} for host/separator conversion at the boundary
|
|
169
|
+
* - Text encoding and decoding
|
|
170
|
+
* - {@link exists}
|
|
171
|
+
* - Parent-directory creation on write / append / copy / move
|
|
172
|
+
* - Append / copy / move fallbacks (override `try*` for native ops)
|
|
173
|
+
* - Recursive mkdir, readdir, and rmdir
|
|
174
|
+
* - Extension filtering for {@link readdir}
|
|
175
|
+
*
|
|
176
|
+
* Namespace paths always use `/`. Host adapters convert with
|
|
177
|
+
* {@link posixPath.toPosix} / {@link posixPath.toHost} in {@link toBackendPath}.
|
|
178
|
+
*/
|
|
179
|
+
export class BaseFileSystem {
|
|
180
|
+
id;
|
|
181
|
+
backend;
|
|
182
|
+
/** POSIX-normalized root (see {@link posixPath.normalizeRoot}). */
|
|
183
|
+
root;
|
|
184
|
+
readOnly;
|
|
185
|
+
createRoot;
|
|
186
|
+
/**
|
|
187
|
+
* Memoized initialization. Every operation that needs a ready backend awaits
|
|
188
|
+
* this, so callers (e.g. Mastra) may call {@link init} every time or never;
|
|
189
|
+
* both are fine.
|
|
190
|
+
*/
|
|
191
|
+
_init;
|
|
192
|
+
initStarted = false;
|
|
193
|
+
constructor(options) {
|
|
194
|
+
this.id = options.id;
|
|
195
|
+
this.backend = options.backend;
|
|
196
|
+
this.root = normalizeFileSystemRoot(options.root);
|
|
197
|
+
this.readOnly = options.readOnly ?? false;
|
|
198
|
+
this.createRoot = options.createRoot ?? false;
|
|
199
|
+
this._init = this.createInit();
|
|
200
|
+
}
|
|
201
|
+
/* ------------------------------------------------------------------ */
|
|
202
|
+
/* Lifecycle */
|
|
203
|
+
/* ------------------------------------------------------------------ */
|
|
204
|
+
createInit() {
|
|
205
|
+
return functionModule.memoize(async () => {
|
|
206
|
+
this.initStarted = true;
|
|
207
|
+
if (this.createRoot) {
|
|
208
|
+
await this.guard(this.root, () => this.createRootDirectory());
|
|
209
|
+
}
|
|
210
|
+
await this.onInit();
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async init() {
|
|
214
|
+
await this._init();
|
|
215
|
+
}
|
|
216
|
+
async close() {
|
|
217
|
+
if (!this.initStarted)
|
|
218
|
+
return;
|
|
219
|
+
try {
|
|
220
|
+
await this._init();
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
this.initStarted = false;
|
|
224
|
+
this._init = this.createInit();
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
await this.onClose();
|
|
228
|
+
this.initStarted = false;
|
|
229
|
+
this._init = this.createInit();
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Ensure {@link root} exists when {@link createRoot} is true.
|
|
233
|
+
*
|
|
234
|
+
* Default is a no-op. Local adapters typically `mkdir -p`; remote adapters
|
|
235
|
+
* leave the default when the root is provisioned out of band.
|
|
236
|
+
*/
|
|
237
|
+
async createRootDirectory() { }
|
|
238
|
+
/** Override when the backend requires connection or validation work. */
|
|
239
|
+
async onInit() { }
|
|
240
|
+
/** Override when the backend owns connections or other resources. */
|
|
241
|
+
async onClose() { }
|
|
242
|
+
assertWritable(operation) {
|
|
243
|
+
if (this.readOnly) {
|
|
244
|
+
throw new FileSystemError("READ_ONLY", `Cannot ${operation}: filesystem is read-only`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/* ------------------------------------------------------------------ */
|
|
248
|
+
/* Paths (POSIX only) */
|
|
249
|
+
/* ------------------------------------------------------------------ */
|
|
250
|
+
/**
|
|
251
|
+
* Normalize an input path into an absolute POSIX path inside the virtual
|
|
252
|
+
* filesystem namespace (`/a/b`). Backslashes are converted; `..` escaping
|
|
253
|
+
* the root throws {@link FileSystemError} `PERMISSION_DENIED`.
|
|
254
|
+
*/
|
|
255
|
+
normalizePath(inputPath) {
|
|
256
|
+
if (inputPath.includes("\0")) {
|
|
257
|
+
throw new FileSystemError("INVALID_PATH", "Paths cannot contain null characters", inputPath);
|
|
258
|
+
}
|
|
259
|
+
const result = posixPath.normalize(inputPath);
|
|
260
|
+
if (!result.ok) {
|
|
261
|
+
throw new FileSystemError("PERMISSION_DENIED", "Path escapes the filesystem root", inputPath);
|
|
262
|
+
}
|
|
263
|
+
return result.path;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Convert a POSIX backend path (under {@link root}) into the form the
|
|
267
|
+
* underlying API expects.
|
|
268
|
+
*
|
|
269
|
+
* Default is identity. Local disk overrides with {@link posixPath.toHost}.
|
|
270
|
+
* Databricks / object-store adapters usually leave the default.
|
|
271
|
+
*/
|
|
272
|
+
toBackendPath(posixBackendPath) {
|
|
273
|
+
return posixBackendPath;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Convert a normalized namespace path (`/a/b`) into a backend path.
|
|
277
|
+
*
|
|
278
|
+
* Joins {@link root} with the namespace using POSIX `/`, then applies
|
|
279
|
+
* {@link toBackendPath}. Override {@link toBackendPath} instead of this
|
|
280
|
+
* method unless the join itself must change.
|
|
281
|
+
*/
|
|
282
|
+
resolveBackendPath(namespacePath) {
|
|
283
|
+
const posix = namespacePath === "/" ? this.root : posixPath.join(this.root, namespacePath.slice(1));
|
|
284
|
+
return this.toBackendPath(posix);
|
|
285
|
+
}
|
|
286
|
+
resolvePath(inputPath) {
|
|
287
|
+
return this.resolveBackendPath(this.normalizePath(inputPath));
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Resolve {@link inputPath}, ensure init, and run {@link preparePath}.
|
|
291
|
+
*/
|
|
292
|
+
async resolveFor(inputPath, options) {
|
|
293
|
+
await this._init();
|
|
294
|
+
return this.resolveNamespaceFor(this.normalizePath(inputPath), options);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* {@link resolveFor} for a path that is ALREADY a normalized namespace path
|
|
298
|
+
* (`/a/b`). The single spelling for "namespace path to prepared backend
|
|
299
|
+
* path", so no call site has to re-derive the chain by hand.
|
|
300
|
+
*/
|
|
301
|
+
resolveNamespaceFor(namespacePath, options) {
|
|
302
|
+
return this.preparePath(this.resolveBackendPath(namespacePath), options);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Hook after lexical resolution. Override for realpath containment or
|
|
306
|
+
* similar backend-specific checks. Default is a no-op.
|
|
307
|
+
*/
|
|
308
|
+
async preparePath(resolvedPath, _options) {
|
|
309
|
+
return resolvedPath;
|
|
310
|
+
}
|
|
311
|
+
joinNamespace(parent, child) {
|
|
312
|
+
return this.normalizePath(posixPath.join(parent, child));
|
|
313
|
+
}
|
|
314
|
+
/** Namespace path without a leading slash (`.` for the root). */
|
|
315
|
+
toRelativePath(namespacePath) {
|
|
316
|
+
return namespacePath === "/" ? "." : namespacePath.slice(1);
|
|
317
|
+
}
|
|
318
|
+
toBytes(content) {
|
|
319
|
+
return typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
320
|
+
}
|
|
321
|
+
/** Create parent directories for {@link inputPath} when it is nested. */
|
|
322
|
+
async ensureParentDirectory(inputPath) {
|
|
323
|
+
const namespacePath = this.normalizePath(inputPath);
|
|
324
|
+
const parent = posixPath.dirname(namespacePath);
|
|
325
|
+
if (parent === "/" || parent === namespacePath)
|
|
326
|
+
return;
|
|
327
|
+
await this.mkdir(parent, { recursive: true });
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Recognize the backend's not-found error.
|
|
331
|
+
*
|
|
332
|
+
* Default accepts {@link FileSystemError} `NOT_FOUND` plus common SDK / HTTP
|
|
333
|
+
* "not found" shapes via {@link inferFileSystemErrorCode}. Override for
|
|
334
|
+
* backend-specific codes (e.g. Node `ENOENT`) that do not carry a message.
|
|
335
|
+
*/
|
|
336
|
+
isNotFoundError(err) {
|
|
337
|
+
if (err instanceof FileSystemError)
|
|
338
|
+
return err.code === "NOT_FOUND";
|
|
339
|
+
return inferFileSystemErrorCode(err) === "NOT_FOUND";
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Normalize a backend failure into a {@link FileSystemError}.
|
|
343
|
+
*
|
|
344
|
+
* Every `*At` / `try*` primitive is invoked through {@link guard}, so an
|
|
345
|
+
* adapter never writes its own try/catch and cannot forget to normalize.
|
|
346
|
+
* Override only to classify backend-specific codes (e.g. Node errno).
|
|
347
|
+
*/
|
|
348
|
+
mapError(err, filePath) {
|
|
349
|
+
return mapFileSystemError(err, filePath);
|
|
350
|
+
}
|
|
351
|
+
/** Run a backend primitive, routing any failure through {@link mapError}. */
|
|
352
|
+
async guard(resolvedPath, operation) {
|
|
353
|
+
try {
|
|
354
|
+
return await operation();
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
throw this.mapError(err, resolvedPath);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/* ------------------------------------------------------------------ */
|
|
361
|
+
/* Optional native-operation hooks */
|
|
362
|
+
/* ------------------------------------------------------------------ */
|
|
363
|
+
/**
|
|
364
|
+
* Override when the backend supports native append.
|
|
365
|
+
*
|
|
366
|
+
* Parent directories are already created by {@link appendFile}. Return true
|
|
367
|
+
* when the operation was performed. The default causes {@link BaseFileSystem}
|
|
368
|
+
* to use read-concatenate-write.
|
|
369
|
+
*/
|
|
370
|
+
async tryAppendFileAt(_resolvedPath, _content) {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Override when the backend supports native server-side copying.
|
|
375
|
+
*
|
|
376
|
+
* Parent directories of the destination are already created by {@link copyFile}.
|
|
377
|
+
*/
|
|
378
|
+
async tryCopyFileAt(_sourcePath, _destinationPath, _options) {
|
|
379
|
+
return false;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Override for native rename or move support.
|
|
383
|
+
*
|
|
384
|
+
* Parent directories of the destination are already created by {@link moveFile}.
|
|
385
|
+
*/
|
|
386
|
+
async tryMoveFileAt(_sourcePath, _destinationPath, _options) {
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
async readFile(inputPath, options) {
|
|
390
|
+
const resolvedPath = await this.resolveFor(inputPath);
|
|
391
|
+
const content = await this.guard(resolvedPath, () => this.readBytesAt(resolvedPath));
|
|
392
|
+
if (options?.encoding) {
|
|
393
|
+
return new TextDecoder(options.encoding).decode(content);
|
|
394
|
+
}
|
|
395
|
+
return content;
|
|
396
|
+
}
|
|
397
|
+
async writeFile(inputPath, content, options = {}) {
|
|
398
|
+
await this._init();
|
|
399
|
+
this.assertWritable("write file");
|
|
400
|
+
const overwrite = await this.resolveOverwrite(inputPath, options, "File");
|
|
401
|
+
await this.ensureParentDirectory(inputPath);
|
|
402
|
+
const resolvedPath = await this.resolveFor(inputPath, { allowMissing: true });
|
|
403
|
+
await this.guard(resolvedPath, () => this.writeBytesAt(resolvedPath, this.toBytes(content), { overwrite }));
|
|
404
|
+
}
|
|
405
|
+
async appendFile(inputPath, content) {
|
|
406
|
+
await this._init();
|
|
407
|
+
this.assertWritable("append file");
|
|
408
|
+
const bytes = this.toBytes(content);
|
|
409
|
+
await this.ensureParentDirectory(inputPath);
|
|
410
|
+
const resolvedPath = await this.resolveFor(inputPath, { allowMissing: true });
|
|
411
|
+
if (await this.guard(resolvedPath, () => this.tryAppendFileAt(resolvedPath, bytes))) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const existing = (await this.exists(inputPath))
|
|
415
|
+
? await this.readFile(inputPath)
|
|
416
|
+
: new Uint8Array();
|
|
417
|
+
const combined = new Uint8Array(existing.byteLength + bytes.byteLength);
|
|
418
|
+
combined.set(existing);
|
|
419
|
+
combined.set(bytes, existing.byteLength);
|
|
420
|
+
await this.writeFile(inputPath, combined, { overwrite: true });
|
|
421
|
+
}
|
|
422
|
+
async deleteFile(inputPath, options = {}) {
|
|
423
|
+
await this._init();
|
|
424
|
+
this.assertWritable("delete file");
|
|
425
|
+
await this.ignoringMissing(options, async () => {
|
|
426
|
+
const entry = await this.stat(inputPath);
|
|
427
|
+
if (entry.type === "directory") {
|
|
428
|
+
throw new FileSystemError("IS_DIRECTORY", `Path is a directory: ${inputPath}`, inputPath);
|
|
429
|
+
}
|
|
430
|
+
const resolvedPath = await this.resolveFor(inputPath);
|
|
431
|
+
await this.guard(resolvedPath, () => this.deleteFileAt(resolvedPath));
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
async copyFile(sourcePath, destinationPath, options = {}) {
|
|
435
|
+
const { source, destination, resolved } = await this.prepareTransfer("copy file", sourcePath, destinationPath, options);
|
|
436
|
+
if (await this.guard(destination, () => this.tryCopyFileAt(source, destination, resolved))) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
await this.writeFile(destinationPath, await this.readFile(sourcePath), resolved);
|
|
440
|
+
}
|
|
441
|
+
async moveFile(sourcePath, destinationPath, options = {}) {
|
|
442
|
+
const { source, destination, resolved } = await this.prepareTransfer("move file", sourcePath, destinationPath, options);
|
|
443
|
+
if (await this.guard(destination, () => this.tryMoveFileAt(source, destination, resolved))) {
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
await this.copyFile(sourcePath, destinationPath, resolved);
|
|
447
|
+
const sourceStat = await this.stat(sourcePath);
|
|
448
|
+
if (sourceStat.type === "directory") {
|
|
449
|
+
await this.rmdir(sourcePath, { recursive: true });
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
await this.deleteFile(sourcePath);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Resolve the effective `overwrite` flag, rejecting when the target exists
|
|
457
|
+
* and overwriting was refused. Shared by write / copy / move so the three
|
|
458
|
+
* cannot disagree about what `overwrite: false` means.
|
|
459
|
+
*/
|
|
460
|
+
async resolveOverwrite(inputPath, options, label) {
|
|
461
|
+
const overwrite = options.overwrite ?? true;
|
|
462
|
+
if (!overwrite && (await this.exists(inputPath))) {
|
|
463
|
+
throw new FileSystemError("ALREADY_EXISTS", `${label} already exists: ${inputPath}`, inputPath);
|
|
464
|
+
}
|
|
465
|
+
return overwrite;
|
|
466
|
+
}
|
|
467
|
+
/** Shared copy / move prologue: writability, overwrite policy, both ends resolved. */
|
|
468
|
+
async prepareTransfer(operation, sourcePath, destinationPath, options) {
|
|
469
|
+
await this._init();
|
|
470
|
+
this.assertWritable(operation);
|
|
471
|
+
const overwrite = await this.resolveOverwrite(destinationPath, options, "Destination");
|
|
472
|
+
await this.ensureParentDirectory(destinationPath);
|
|
473
|
+
return {
|
|
474
|
+
source: await this.resolveFor(sourcePath),
|
|
475
|
+
destination: await this.resolveFor(destinationPath, { allowMissing: true }),
|
|
476
|
+
resolved: { overwrite },
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
/** Run a removal, swallowing a not-found failure when `force` is set. */
|
|
480
|
+
async ignoringMissing(options, operation) {
|
|
481
|
+
try {
|
|
482
|
+
await operation();
|
|
483
|
+
}
|
|
484
|
+
catch (err) {
|
|
485
|
+
if (options.force && this.isNotFoundError(err))
|
|
486
|
+
return;
|
|
487
|
+
throw err;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/* ------------------------------------------------------------------ */
|
|
491
|
+
/* Directory operations */
|
|
492
|
+
/* ------------------------------------------------------------------ */
|
|
493
|
+
async mkdir(inputPath, options = {}) {
|
|
494
|
+
await this._init();
|
|
495
|
+
this.assertWritable("create directory");
|
|
496
|
+
const namespacePath = this.normalizePath(inputPath);
|
|
497
|
+
if (!options.recursive) {
|
|
498
|
+
await this.createDirectory(namespacePath);
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
let currentPath = "";
|
|
502
|
+
for (const segment of namespacePath.split("/").filter(Boolean)) {
|
|
503
|
+
currentPath = `${currentPath}/${segment}`;
|
|
504
|
+
try {
|
|
505
|
+
const entry = await this.stat(currentPath);
|
|
506
|
+
if (entry.type !== "directory") {
|
|
507
|
+
throw new FileSystemError("NOT_DIRECTORY", `Path component is not a directory: ${currentPath}`, currentPath);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
catch (error) {
|
|
511
|
+
if (!this.isNotFoundError(error))
|
|
512
|
+
throw error;
|
|
513
|
+
await this.createDirectory(currentPath);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
async rmdir(inputPath, options = {}) {
|
|
518
|
+
await this._init();
|
|
519
|
+
this.assertWritable("remove directory");
|
|
520
|
+
await this.ignoringMissing(options, async () => {
|
|
521
|
+
const entry = await this.stat(inputPath);
|
|
522
|
+
if (entry.type !== "directory") {
|
|
523
|
+
throw new FileSystemError("NOT_DIRECTORY", `Path is not a directory: ${inputPath}`, inputPath);
|
|
524
|
+
}
|
|
525
|
+
const namespacePath = this.normalizePath(inputPath);
|
|
526
|
+
if (options.recursive) {
|
|
527
|
+
await this.removeDirectoryContents(namespacePath);
|
|
528
|
+
}
|
|
529
|
+
await this.removeDirectory(namespacePath);
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
async removeDirectoryContents(namespacePath) {
|
|
533
|
+
for (const entry of await this.listDirectory(namespacePath)) {
|
|
534
|
+
const childPath = this.joinNamespace(namespacePath, entry.name);
|
|
535
|
+
if (entry.type === "directory") {
|
|
536
|
+
await this.removeDirectoryContents(childPath);
|
|
537
|
+
await this.removeDirectory(childPath);
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
const resolvedPath = await this.resolveNamespaceFor(childPath);
|
|
541
|
+
await this.guard(resolvedPath, () => this.deleteFileAt(resolvedPath));
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
/** {@link createDirectoryAt} for a namespace path, resolved and guarded. */
|
|
546
|
+
async createDirectory(namespacePath) {
|
|
547
|
+
const resolvedPath = await this.resolveNamespaceFor(namespacePath, { allowMissing: true });
|
|
548
|
+
await this.guard(resolvedPath, () => this.createDirectoryAt(resolvedPath));
|
|
549
|
+
}
|
|
550
|
+
/** {@link removeDirectoryAt} for a namespace path, resolved and guarded. */
|
|
551
|
+
async removeDirectory(namespacePath) {
|
|
552
|
+
const resolvedPath = await this.resolveNamespaceFor(namespacePath);
|
|
553
|
+
await this.guard(resolvedPath, () => this.removeDirectoryAt(resolvedPath));
|
|
554
|
+
}
|
|
555
|
+
/** {@link listDirectoryAt} for a namespace path, resolved and guarded. */
|
|
556
|
+
async listDirectory(namespacePath) {
|
|
557
|
+
const resolvedPath = await this.resolveNamespaceFor(namespacePath);
|
|
558
|
+
return this.guard(resolvedPath, () => this.listDirectoryAt(resolvedPath));
|
|
559
|
+
}
|
|
560
|
+
async readdir(inputPath, options = {}) {
|
|
561
|
+
await this._init();
|
|
562
|
+
const namespacePath = this.normalizePath(inputPath);
|
|
563
|
+
if (!options.recursive) {
|
|
564
|
+
return this.filterEntries(await this.listDirectory(namespacePath), options);
|
|
565
|
+
}
|
|
566
|
+
return this.listDirectoryRecursive(namespacePath, options, 0, "");
|
|
567
|
+
}
|
|
568
|
+
async listDirectoryRecursive(namespacePath, options, depth, prefix) {
|
|
569
|
+
const maximumDepth = options.maxDepth ?? Number.POSITIVE_INFINITY;
|
|
570
|
+
const entries = this.filterEntries(await this.listDirectory(namespacePath), options);
|
|
571
|
+
const results = [];
|
|
572
|
+
for (const entry of entries) {
|
|
573
|
+
const relativeName = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
574
|
+
results.push({ ...entry, name: relativeName });
|
|
575
|
+
if (entry.type === "directory" && depth < maximumDepth) {
|
|
576
|
+
results.push(...(await this.listDirectoryRecursive(this.joinNamespace(namespacePath, entry.name), options, depth + 1, relativeName)));
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return results;
|
|
580
|
+
}
|
|
581
|
+
filterEntries(entries, options) {
|
|
582
|
+
if (!options.extension) {
|
|
583
|
+
return entries;
|
|
584
|
+
}
|
|
585
|
+
const extensions = (Array.isArray(options.extension) ? options.extension : [options.extension]).map((extension) => {
|
|
586
|
+
const normalized = extension.toLowerCase();
|
|
587
|
+
return normalized.startsWith(".") ? normalized : `.${normalized}`;
|
|
588
|
+
});
|
|
589
|
+
return entries.filter((entry) => {
|
|
590
|
+
if (entry.type !== "file")
|
|
591
|
+
return true;
|
|
592
|
+
const lower = entry.name.toLowerCase();
|
|
593
|
+
return extensions.some((ext) => lower.endsWith(ext));
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
async exists(inputPath) {
|
|
597
|
+
await this._init();
|
|
598
|
+
try {
|
|
599
|
+
await this.stat(inputPath);
|
|
600
|
+
return true;
|
|
601
|
+
}
|
|
602
|
+
catch (error) {
|
|
603
|
+
if (this.isNotFoundError(error))
|
|
604
|
+
return false;
|
|
605
|
+
if (error instanceof FileSystemError && error.code === "PERMISSION_DENIED") {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
throw error;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
async stat(inputPath) {
|
|
612
|
+
await this._init();
|
|
613
|
+
const namespacePath = this.normalizePath(inputPath);
|
|
614
|
+
const resolvedPath = await this.resolveNamespaceFor(namespacePath);
|
|
615
|
+
const entry = await this.guard(resolvedPath, () => this.statAt(resolvedPath));
|
|
616
|
+
return {
|
|
617
|
+
...entry,
|
|
618
|
+
path: this.toRelativePath(namespacePath),
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1mcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9iYXNlLWZzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFFSCxPQUFPLEVBQUUsS0FBSyxFQUFFLGNBQWMsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFrQixNQUFNLHdCQUF3QixDQUFDO0FBYTdGLE9BQU8sS0FBSyxTQUFTLE1BQU0saUJBQWlCLENBQUM7QUFlN0M7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxtQkFBbUIsR0FBRywwQkFBMEIsQ0FBQztBQUV2RDs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFDSCxNQUFNLFVBQVUsdUJBQXVCLENBQUMsSUFBMEI7SUFDaEUsSUFBSSxJQUFJLEtBQUssU0FBUztRQUFFLE9BQU8sR0FBRyxDQUFDO0lBQ25DLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDMUMsTUFBTSxRQUFRLEdBQUcsbUJBQW1CLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEQsTUFBTSxLQUFLLEdBQWEsRUFBRSxDQUFDO0lBQzNCLEtBQUssTUFBTSxPQUFPLElBQUksUUFBUSxFQUFFLENBQUM7UUFDL0IsSUFBSSxPQUFPLEtBQUssSUFBSSxJQUFJLE9BQU8sS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUM5QyxNQUFNLElBQUksU0FBUyxDQUFDLDJDQUEyQyxDQUFDLENBQUM7UUFDbkUsQ0FBQztRQUNELGVBQWUsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUNELElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQUUsT0FBTyxHQUFHLENBQUM7SUFDbkMsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMvQixPQUFPLFNBQVMsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFD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cmFjdCB7QGxpbmsgRmlsZVN5c3RlbX0gYmFzZTogbGlmZWN5Y2xlLCByb290ZWQgUE9TSVggcGF0aHMsIGVuY29kaW5nLCBhbmRcbiAqIHBvcnRhYmxlIGZhbGxiYWNrcyBzbyBhIGNvbmNyZXRlIGJhY2tlbmQgb25seSBpbXBsZW1lbnRzIGxvdy1sZXZlbCBJL08uXG4gKlxuICogQSBuZXcgYWRhcHRlciB0eXBpY2FsbHkgb3ZlcnJpZGVzOlxuICogLSB7QGxpbmsgb25Jbml0fSAvIHtAbGluayBvbkNsb3NlfSAob3B0aW9uYWwpXG4gKiAtIHtAbGluayBjcmVhdGVSb290RGlyZWN0b3J5fSB3aGVuIHtAbGluayBCYXNlRmlsZVN5c3RlbU9wdGlvbnMuY3JlYXRlUm9vdH0gaXMgc2V0XG4gKiAtIHtAbGluayB0b0JhY2tlbmRQYXRofSB3aGVuIHRoZSBiYWNrZW5kIG5lZWRzIG5vbi1QT1NJWCBzZXBhcmF0b3JzXG4gKiAtIHtAbGluayBwcmVwYXJlUGF0aH0gZm9yIHBvc3QtcmVzb2x2ZSBjaGVja3MgKGUuZy4gc3ltbGluayBjb250YWlubWVudClcbiAqIC0gdGhlIGAqQXRgIHByaW1pdGl2ZXMgYW5kIHtAbGluayBpc05vdEZvdW5kRXJyb3J9XG4gKiAtIG9wdGlvbmFsIGB0cnkqYCBob29rcyBmb3IgbmF0aXZlIGFwcGVuZCAvIGNvcHkgLyBtb3ZlXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGVycm9yLCBmdW5jdGlvbk1vZHVsZSwgaGFzaCwgb2JqZWN0LCB0eXBlIE9uZU9yTWFueSB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgdHlwZSB7XG4gIENvcHlPcHRpb25zLFxuICBGaWxlQ29udGVudCxcbiAgRmlsZUVudHJ5LFxuICBGaWxlU3RhdCxcbiAgRmlsZVN5c3RlbSxcbiAgTGlzdE9wdGlvbnMsXG4gIE1ha2VEaXJlY3RvcnlPcHRpb25zLFxuICBSZWFkRmlsZU9wdGlvbnMsXG4gIFJlbW92ZU9wdGlvbnMsXG4gIFdyaXRlRmlsZU9wdGlvbnMsXG59IGZyb20gXCIuL2ZzLnRzXCI7XG5pbXBvcnQgKiBhcyBwb3NpeFBhdGggZnJvbSBcIi4vcG9zaXgtcGF0aC50c1wiO1xuXG4vKipcbiAqIE9uZSByb290IHBhdGggc2VnbWVudC4gU3RyaW5ncyBhcmUgc3BsaXQgb24gYC9gIGFuZCBzYW5pdGl6ZWQ7IG51bWJlcnMgL1xuICogYm9vbGVhbnMgLyBiaWdpbnRzIHN0cmluZ2lmeSB0aGVuIHNhbml0aXplOyBvYmplY3RzIGFuZCBhcnJheXMgYXJlIEZOVi1oYXNoZWRcbiAqIGFzIGEgc2luZ2xlIHNlZ21lbnQuXG4gKi9cbmV4cG9ydCB0eXBlIEZpbGVTeXN0ZW1Sb290U2VnbWVudCA9IHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4gfCBiaWdpbnQgfCBvYmplY3Q7XG5cbi8qKlxuICogQSBzaW5nbGUge0BsaW5rIEZpbGVTeXN0ZW1Sb290U2VnbWVudH0gb3IgYSBub24tZW1wdHkgbGlzdCBvZiB0aGVtLiBOZXN0ZWRcbiAqIGFycmF5cy9vYmplY3RzIGluc2lkZSB0aGUgbGlzdCBhcmUgb25lIGhhc2hlZCBzZWdtZW50IGVhY2ggKG5vdCBmbGF0dGVuZWQpLlxuICovXG5leHBvcnQgdHlwZSBGaWxlU3lzdGVtUm9vdElucHV0ID0gRmlsZVN5c3RlbVJvb3RTZWdtZW50IHwgT25lT3JNYW55PEZpbGVTeXN0ZW1Sb290U2VnbWVudD47XG5cbi8qKlxuICogQ2hhcmFjdGVycyBubyBiYWNrZW5kIGFjY2VwdHMgaW5zaWRlIGEgc2luZ2xlIHBhdGggY29tcG9uZW50OiBhIHNlcGFyYXRvclxuICogKHdoaWNoIHdvdWxkIHNpbGVudGx5IGRlZXBlbiB0aGUgcGF0aCkgb3IgYSBOVUwgLyBjb250cm9sIGNoYXJhY3Rlci5cbiAqXG4gKiBUaGlzIGlzIGEgREVOWS1saXN0IG9uIHB1cnBvc2UuIFNwYWNlcywgYEBgLCBgJmAsIGAjYCwgcGFyZW50aGVzZXMgYW5kXG4gKiBub24tQVNDSUkgYXJlIGFsbCBsZWdhbCBkaXJlY3RvcnkgbmFtZXMgb24gUE9TSVggYW5kIGluIGEgRGF0YWJyaWNrc1xuICogd29ya3NwYWNlLCBhbmQgcmVwbGFjaW5nIG9uZSB3aXRoIGEgaGFzaCBwb2ludHMgdGhlIGZpbGVzeXN0ZW0gYXQgYVxuICogZGlyZWN0b3J5IHRoYXQgZG9lcyBub3QgZXhpc3QgLSBhIGZhaWx1cmUgdGhhdCBpcyBzaWxlbnQgYW5kIHZlcnkgaGFyZCB0b1xuICogdHJhY2UgYmFjay4gT25seSByZWplY3Qgd2hhdCBnZW51aW5lbHkgY2Fubm90IGJlIGEgY29tcG9uZW50LlxuICovXG5jb25zdCBVTlNBRkVfUEFUSF9TRUdNRU5UID0gL1tcXFxcL1xcdTAwMDAtXFx1MDAxRlxcdTAwN0ZdLztcblxuLyoqXG4gKiBUdXJuIHtAbGluayByb290fSBpbnRvIGEgUE9TSVggZmlsZXN5c3RlbSByb290OlxuICpcbiAqIDEuIEV4cGFuZCBvbmUtb3ItbWFueSBpbnB1dCBzZWdtZW50c1xuICogMi4gU3RyaW5ncyBzcGxpdCBvbiBgL2AgKGFuZCBgXFxgKTsgb2JqZWN0cy9hcnJheXMgRk5WLWhhc2ggYXMgb25lIHBpZWNlXG4gKiAzLiBFYWNoIHJlc3VsdGluZyBjb21wb25lbnQgdGhhdCBjYW5ub3QgYmUgYSBwYXRoIGNvbXBvbmVudCAtIHNlZVxuICogICAge0BsaW5rIFVOU0FGRV9QQVRIX1NFR01FTlR9IC0gaXMgcmVwbGFjZWQgd2l0aCB7QGxpbmsgaGFzaC5mbnZIYXNofVxuICogNC4gSm9pbiB3aXRoIGAvYCBhbmQgcnVuIHtAbGluayBwb3NpeFBhdGgubm9ybWFsaXplUm9vdH1cbiAqXG4gKiBEZWZhdWx0cyB0byBgL2AuIEEgbGVhZGluZyBgL2Agb24gdGhlIGZpcnN0IHN0cmluZyBzZWdtZW50IGlzIHByZXNlcnZlZC5cbiAqXG4gKiBAZXhhbXBsZVxuICogbm9ybWFsaXplRmlsZVN5c3RlbVJvb3QoXCIvY29vbC93b3dcIik7IC8vIFwiL2Nvb2wvd293XCJcbiAqIG5vcm1hbGl6ZUZpbGVTeXN0ZW1Sb290KFwiL1VzZXJzL21lQGNvcnAuY29tL015IE5vdGVzXCIpOyAvLyB1bmNoYW5nZWRcbiAqIG5vcm1hbGl6ZUZpbGVTeXN0ZW1Sb290KFtcIi9wYXRoXCIsIHsgdXNlcjogMSB9LCB0cnVlXSk7IC8vIFwiL3BhdGgvPGhhc2g+L3RydWVcIlxuICovXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplRmlsZVN5c3RlbVJvb3Qocm9vdD86IEZpbGVTeXN0ZW1Sb290SW5wdXQpOiBzdHJpbmcge1xuICBpZiAocm9vdCA9PT0gdW5kZWZpbmVkKSByZXR1cm4gXCIvXCI7XG4gIGNvbnN0IHNlZ21lbnRzID0gb2JqZWN0LnRvT25lT3JNYW55KHJvb3QpO1xuICBjb25zdCBhYnNvbHV0ZSA9IGlzQWJzb2x1dGVSb290U3RhcnQoc2VnbWVudHNbMF0pO1xuICBjb25zdCBwYXJ0czogc3RyaW5nW10gPSBbXTtcbiAgZm9yIChjb25zdCBzZWdtZW50IG9mIHNlZ21lbnRzKSB7XG4gICAgaWYgKHNlZ21lbnQgPT09IG51bGwgfHwgc2VnbWVudCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiRmlsZXN5c3RlbSByb290IHNlZ21lbnRzIG11c3QgYmUgbm9uLW51bGxcIik7XG4gICAgfVxuICAgIGFwcGVuZFJvb3RQYXJ0cyhwYXJ0cywgc2VnbWVudCk7XG4gIH1cbiAgaWYgKHBhcnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFwiL1wiO1xuICBjb25zdCBqb2luZWQgPSBwYXJ0cy5qb2luKFwiL1wiKTtcbiAgcmV0dXJuIHBvc2l4UGF0aC5ub3JtYWxpemVSb290KGFic29sdXRlID8gYC8ke2pvaW5lZH1gIDogam9pbmVkKTtcbn1cblxuZnVuY3Rpb24gaXNBYnNvbHV0ZVJvb3RTdGFydChzZWdtZW50OiBGaWxlU3lzdGVtUm9vdFNlZ21lbnQpOiBib29sZWFuIHtcbiAgcmV0dXJuIHR5cGVvZiBzZWdtZW50ID09PSBcInN0cmluZ1wiICYmIHBvc2l4UGF0aC5pc0Fic29sdXRlKHNlZ21lbnQudHJpbSgpKTtcbn1cblxuZnVuY3Rpb24gYXBwZW5kUm9vdFBhcnRzKHBhcnRzOiBzdHJpbmdbXSwgc2VnbWVudDogRmlsZVN5c3RlbVJvb3RTZWdtZW50KTogdm9pZCB7XG4gIHN3aXRjaCAodHlwZW9mIHNlZ21lbnQpIHtcbiAgICBjYXNlIFwic3RyaW5nXCI6XG4gICAgICBmb3IgKGNvbnN0IHBpZWNlIG9mIHNwbGl0UGF0aFBpZWNlcyhzZWdtZW50KSkge1xuICAgICAgICBwYXJ0cy5wdXNoKHNhbml0aXplUGF0aFNlZ21lbnQocGllY2UpKTtcbiAgICAgIH1cbiAgICAgIHJldHVybjtcbiAgICBjYXNlIFwibnVtYmVyXCI6XG4gICAgY2FzZSBcImJvb2xlYW5cIjpcbiAgICBjYXNlIFwiYmlnaW50XCI6XG4gICAgICBwYXJ0cy5wdXNoKHNhbml0aXplUGF0aFNlZ21lbnQoU3RyaW5nKHNlZ21lbnQpKSk7XG4gICAgICByZXR1cm47XG4gICAgZGVmYXVsdDpcbiAgICAgIHBhcnRzLnB1c2goaGFzaC5mbnZIYXNoKHNlZ21lbnQpKTtcbiAgfVxufVxuXG4vKipcbiAqIFNwbGl0IG9uIGAvYCAoYWZ0ZXIgYFxcYCDihpIgYC9gKTsgZHJvcCBlbXB0eSBwaWVjZXMgZnJvbVxuICogbGVhZGluZy90cmFpbGluZy9kb3VibGUgc2xhc2hlcyBhbmQgbm8tb3AgYC5gIHBpZWNlcy5cbiAqL1xuZnVuY3Rpb24gc3BsaXRQYXRoUGllY2VzKGlucHV0OiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gIHJldHVybiBwb3NpeFBhdGhcbiAgICAudG9Qb3NpeChpbnB1dC50cmltKCkpXG4gICAgLnNwbGl0KFwiL1wiKVxuICAgIC5maWx0ZXIoKHBpZWNlKSA9PiBwaWVjZS5sZW5ndGggPiAwICYmIHBpZWNlICE9PSBcIi5cIik7XG59XG5cbi8qKlxuICogS2VlcCBhIHVzYWJsZSBwYXRoIGNvbXBvbmVudCB2ZXJiYXRpbTsgRk5WLWhhc2ggb25lIHRoYXQgY2Fubm90IGJlIHVzZWQuXG4gKlxuICogYC4uYCBpcyBoYXNoZWQgcmF0aGVyIHRoYW4gZHJvcHBlZCBzbyBhIHJvb3QgY2FuIG5ldmVyIHRyYXZlcnNlIGFib3ZlXG4gKiBpdHNlbGYgd2hpbGUgdGhlIG9mZmVuZGluZyBzZWdtZW50IHN0YXlzIHZpc2libGUgaW4gdGhlIHJlc29sdmVkIHJvb3QuXG4gKi9cbmZ1bmN0aW9uIHNhbml0aXplUGF0aFNlZ21lbnQoc2VnbWVudDogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKHNlZ21lbnQgPT09IFwiLi5cIiB8fCBVTlNBRkVfUEFUSF9TRUdNRU5ULnRlc3Qoc2VnbWVudCkpIHtcbiAgICByZXR1cm4gaGFzaC5mbnZIYXNoKHNlZ21lbnQpO1xuICB9XG4gIHJldHVybiBzZWdtZW50O1xufVxuXG5leHBvcnQgdHlwZSBGaWxlU3lzdGVtRXJyb3JDb2RlID1cbiAgfCBcIk5PVF9GT1VORFwiXG4gIHwgXCJBTFJFQURZX0VYSVNUU1wiXG4gIHwgXCJOT1RfRElSRUNUT1JZXCJcbiAgfCBcIklTX0RJUkVDVE9SWVwiXG4gIHwgXCJESVJFQ1RPUllfTk9UX0VNUFRZXCJcbiAgfCBcIlBFUk1JU1NJT05fREVOSUVEXCJcbiAgfCBcIlJFQURfT05MWVwiXG4gIHwgXCJJTlZBTElEX1BBVEhcIlxuICB8IFwiTk9UX1NVUFBPUlRFRFwiXG4gIHwgXCJJT19FUlJPUlwiO1xuXG5leHBvcnQgY2xhc3MgRmlsZVN5c3RlbUVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICByZWFkb25seSBuYW1lID0gXCJGaWxlU3lzdGVtRXJyb3JcIjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICByZWFkb25seSBjb2RlOiBGaWxlU3lzdGVtRXJyb3JDb2RlLFxuICAgIG1lc3NhZ2U6IHN0cmluZyxcbiAgICByZWFkb25seSBwYXRoPzogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7IGNhdXNlPzogdW5rbm93biB9LFxuICApIHtcbiAgICBzdXBlcihcbiAgICAgIG1lc3NhZ2UsXG4gICAgICBvcHRpb25zPy5jYXVzZSAhPT0gdW5kZWZpbmVkID8geyBjYXVzZTogZXJyb3IudG9FcnJvcihvcHRpb25zLmNhdXNlKSB9IDogdW5kZWZpbmVkLFxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBJbmZlciBhIHtAbGluayBGaWxlU3lzdGVtRXJyb3JDb2RlfSBmcm9tIEhUVFAgc3RhdHVzIC8gbWVzc2FnZSB0b2tlbnMgb24gYW5cbiAqIHVua25vd24gdGhyb3duIHZhbHVlICh2aWEge0BsaW5rIGVycm9yLmVycm9yQ29udGV4dH0pLlxuICpcbiAqIENvdmVycyBjb21tb24gU0RLIC8gUkVTVCB3b3JkaW5nIHNvIGFkYXB0ZXJzIGRvIG5vdCByZWltcGxlbWVudCB0aGUgc2FtZVxuICogXCJub3QgZm91bmRcIiAvIFwiYWxyZWFkeSBleGlzdHNcIiBjaGVja3MuIFJldHVybnMgdW5kZWZpbmVkIHdoZW4gbm90aGluZyBtYXRjaGVzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaW5mZXJGaWxlU3lzdGVtRXJyb3JDb2RlKGVycjogdW5rbm93bik6IEZpbGVTeXN0ZW1FcnJvckNvZGUgfCB1bmRlZmluZWQge1xuICBjb25zdCBjdHggPSBlcnJvci5lcnJvckNvbnRleHQoZXJyKTtcbiAgaWYgKGN0eC5oYXNTdGF0dXNDb2RlKDQwNCkgfHwgY3R4Lmhhc01lc3NhZ2UoXCJub3RcIiwgXCJmb3VuZFwiKSB8fCBjdHguaGFzTWVzc2FnZShcIm5vdFwiLCBcImV4aXN0XCIpKSB7XG4gICAgcmV0dXJuIFwiTk9UX0ZPVU5EXCI7XG4gIH1cbiAgaWYgKGN0eC5oYXNTdGF0dXNDb2RlKDQwOSkgfHwgY3R4Lmhhc01lc3NhZ2UoXCJhbHJlYWR5XCIsIFwiZXhpc3RzXCIpKSB7XG4gICAgcmV0dXJuIFwiQUxSRUFEWV9FWElTVFNcIjtcbiAgfVxuICAvLyBCZWZvcmUgXCJub3RcIitcImRpcmVjdG9yeVwiOiBcImRpcmVjdG9yeSBub3QgZW1wdHlcIiBjb250YWlucyBib3RoIG9mIHRob3NlIHRva2Vucy5cbiAgaWYgKGN0eC5oYXNNZXNzYWdlKFwibm90XCIsIFwiZW1wdHlcIikpIHtcbiAgICByZXR1cm4gXCJESVJFQ1RPUllfTk9UX0VNUFRZXCI7XG4gIH1cbiAgaWYgKGN0eC5oYXNNZXNzYWdlKFwibm90XCIsIFwiZGlyZWN0b3J5XCIpKSB7XG4gICAgcmV0dXJuIFwiTk9UX0RJUkVDVE9SWVwiO1xuICB9XG4gIGlmIChjdHguaGFzTWVzc2FnZShcImlzXCIsIFwiZGlyZWN0b3J5XCIpIHx8IGN0eC5oYXNNZXNzYWdlKFwibm90XCIsIFwiZmlsZVwiKSkge1xuICAgIHJldHVybiBcIklTX0RJUkVDVE9SWVwiO1xuICB9XG4gIGlmIChcbiAgICBjdHguaGFzU3RhdHVzQ29kZSg0MDEsIDQwMykgfHxcbiAgICBjdHguaGFzTWVzc2FnZShcInBlcm1pc3Npb25cIiwgXCJkZW5pZWRcIikgfHxcbiAgICBjdHguaGFzTWVzc2FnZShcImFjY2Vzc1wiLCBcImRlbmllZFwiKVxuICApIHtcbiAgICByZXR1cm4gXCJQRVJNSVNTSU9OX0RFTklFRFwiO1xuICB9XG4gIGlmIChjdHguaGFzTWVzc2FnZShcInJlYWRcIiwgXCJvbmx5XCIpKSB7XG4gICAgcmV0dXJuIFwiUkVBRF9PTkxZXCI7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBNYXAgYW4gdW5rbm93biBiYWNrZW5kIGZhaWx1cmUgaW50byBhIHtAbGluayBGaWxlU3lzdGVtRXJyb3J9LlxuICpcbiAqIFByZWZlciBhIGJhY2tlbmQtc3BlY2lmaWMge0BsaW5rIGNvZGVPZn0gY2xhc3NpZmllciAoZXJybm8sIFNESyBjb2RlKS4gV2hlblxuICogaXQgcmV0dXJucyB1bmRlZmluZWQsIGZhbGxzIGJhY2sgdG8ge0BsaW5rIGluZmVyRmlsZVN5c3RlbUVycm9yQ29kZX0uIE1lc3NhZ2VcbiAqIGFuZCBjYXVzZSBhbHdheXMgZ28gdGhyb3VnaCBgQGRieC10b29scy9zaGFyZWQtY29yZWAge0BsaW5rIGVycm9yfSBoZWxwZXJzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbWFwRmlsZVN5c3RlbUVycm9yKFxuICBlcnI6IHVua25vd24sXG4gIGZpbGVQYXRoOiBzdHJpbmcsXG4gIGNvZGVPZj86IChlcnI6IHVua25vd24pID0+IEZpbGVTeXN0ZW1FcnJvckNvZGUgfCB1bmRlZmluZWQsXG4pOiBGaWxlU3lzdGVtRXJyb3Ige1xuICBpZiAoZXJyIGluc3RhbmNlb2YgRmlsZVN5c3RlbUVycm9yKSByZXR1cm4gZXJyO1xuICBjb25zdCBtZXNzYWdlID0gZXJyb3IuZXJyb3JNZXNzYWdlKGVycik7XG4gIHJldHVybiBuZXcgRmlsZVN5c3RlbUVycm9yKFxuICAgIGNvZGVPZj8uKGVycikgPz8gaW5mZXJGaWxlU3lzdGVtRXJyb3JDb2RlKGVycikgPz8gXCJJT19FUlJPUlwiLFxuICAgIG1lc3NhZ2UgfHwgYEZpbGVzeXN0ZW0gb3BlcmF0aW9uIGZhaWxlZDogJHtmaWxlUGF0aH1gLFxuICAgIGZpbGVQYXRoLFxuICAgIHsgY2F1c2U6IGVycm9yLnRvRXJyb3IoZXJyKSB9LFxuICApO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEJhc2VGaWxlU3lzdGVtT3B0aW9uczxUQmFja2VuZCBleHRlbmRzIHN0cmluZyA9IHN0cmluZz4ge1xuICBpZDogc3RyaW5nO1xuICBiYWNrZW5kOiBUQmFja2VuZDtcbiAgLyoqXG4gICAqIEZpbGVzeXN0ZW0gcm9vdC4gT25lIHNlZ21lbnQgb3IgYSBsaXN0IG9mIHNlZ21lbnRzICh7QGxpbmsgRmlsZVN5c3RlbVJvb3RJbnB1dH0pOlxuICAgKiBwcmltaXRpdmVzIHN0cmluZ2lmeSwgb2JqZWN0cy9hcnJheXMgYXJlIEZOVi1oYXNoZWQsIHRoZW4gam9pbmVkIHdpdGggYC9gXG4gICAqIGFuZCBub3JtYWxpemVkIHZpYSB7QGxpbmsgcG9zaXhQYXRoLm5vcm1hbGl6ZVJvb3R9LiBEZWZhdWx0cyB0byBgL2AuXG4gICAqL1xuICByb290PzogRmlsZVN5c3RlbVJvb3RJbnB1dDtcbiAgcmVhZE9ubHk/OiBib29sZWFuO1xuICAvKipcbiAgICogRW5zdXJlIHtAbGluayByb290fSBleGlzdHMgZHVyaW5nIGluaXQgYnkgY2FsbGluZyB7QGxpbmsgY3JlYXRlUm9vdERpcmVjdG9yeX0uXG4gICAqIERlZmF1bHRzIHRvIGZhbHNlIChyZW1vdGUgcm9vdHMgdXN1YWxseSBhbHJlYWR5IGV4aXN0KS4gTG9jYWwgZGlzayBhZGFwdGVyc1xuICAgKiB0eXBpY2FsbHkgcGFzcyB0cnVlIGFuZCBvdmVycmlkZSB7QGxpbmsgY3JlYXRlUm9vdERpcmVjdG9yeX0uXG4gICAqL1xuICBjcmVhdGVSb290PzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBCYXNlIGltcGxlbWVudGF0aW9uIGZvciBsb2NhbCwgcmVtb3RlLCBhbmQgdmlydHVhbCBmaWxlc3lzdGVtcy5cbiAqXG4gKiBTdWJjbGFzc2VzIGltcGxlbWVudCB0aGUgbG93LWxldmVsIGAqQXRgIHByaW1pdGl2ZXMuIFRoaXMgY2xhc3MgcHJvdmlkZXM6XG4gKlxuICogLSBNZW1vaXplZCB7QGxpbmsgX2luaXR9IChzbyBhbiBleHBsaWNpdCB7QGxpbmsgaW5pdH0gY2FsbCBpcyBvcHRpb25hbClcbiAqIC0gT3B0aW9uYWwgcm9vdCBjcmVhdGlvbiB2aWEge0BsaW5rIGNyZWF0ZVJvb3REaXJlY3Rvcnl9XG4gKiAtIFBPU0lYLW9ubHkgcm9vdGVkIHBhdGggbm9ybWFsaXphdGlvbiBhbmQgdHJhdmVyc2FsIHByb3RlY3Rpb25cbiAqIC0ge0BsaW5rIHRvQmFja2VuZFBhdGh9IGZvciBob3N0L3NlcGFyYXRvciBjb252ZXJzaW9uIGF0IHRoZSBib3VuZGFyeVxuICogLSBUZXh0IGVuY29kaW5nIGFuZCBkZWNvZGluZ1xuICogLSB7QGxpbmsgZXhpc3RzfVxuICogLSBQYXJlbnQtZGlyZWN0b3J5IGNyZWF0aW9uIG9uIHdyaXRlIC8gYXBwZW5kIC8gY29weSAvIG1vdmVcbiAqIC0gQXBwZW5kIC8gY29weSAvIG1vdmUgZmFsbGJhY2tzIChvdmVycmlkZSBgdHJ5KmAgZm9yIG5hdGl2ZSBvcHMpXG4gKiAtIFJlY3Vyc2l2ZSBta2RpciwgcmVhZGRpciwgYW5kIHJtZGlyXG4gKiAtIEV4dGVuc2lvbiBmaWx0ZXJpbmcgZm9yIHtAbGluayByZWFkZGlyfVxuICpcbiAqIE5hbWVzcGFjZSBwYXRocyBhbHdheXMgdXNlIGAvYC4gSG9zdCBhZGFwdGVycyBjb252ZXJ0IHdpdGhcbiAqIHtAbGluayBwb3NpeFBhdGgudG9Qb3NpeH0gLyB7QGxpbmsgcG9zaXhQYXRoLnRvSG9zdH0gaW4ge0BsaW5rIHRvQmFja2VuZFBhdGh9LlxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgQmFzZUZpbGVTeXN0ZW08XG4gIFRCYWNrZW5kIGV4dGVuZHMgc3RyaW5nID0gc3RyaW5nLFxuPiBpbXBsZW1lbnRzIEZpbGVTeXN0ZW08VEJhY2tlbmQ+IHtcbiAgcmVhZG9ubHkgaWQ6IHN0cmluZztcbiAgcmVhZG9ubHkgYmFja2VuZDogVEJhY2tlbmQ7XG4gIC8qKiBQT1NJWC1ub3JtYWxpemVkIHJvb3QgKHNlZSB7QGxpbmsgcG9zaXhQYXRoLm5vcm1hbGl6ZVJvb3R9KS4gKi9cbiAgcmVhZG9ubHkgcm9vdDogc3RyaW5nO1xuICByZWFkb25seSByZWFkT25seTogYm9vbGVhbjtcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGNyZWF0ZVJvb3Q6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIE1lbW9pemVkIGluaXRpYWxpemF0aW9uLiBFdmVyeSBvcGVyYXRpb24gdGhhdCBuZWVkcyBhIHJlYWR5IGJhY2tlbmQgYXdhaXRzXG4gICAqIHRoaXMsIHNvIGNhbGxlcnMgKGUuZy4gTWFzdHJhKSBtYXkgY2FsbCB7QGxpbmsgaW5pdH0gZXZlcnkgdGltZSBvciBuZXZlcjtcbiAgICogYm90aCBhcmUgZmluZS5cbiAgICovXG4gIHByb3RlY3RlZCBfaW5pdDogKCkgPT4gUHJvbWlzZTx2b2lkPjtcblxuICBwcml2YXRlIGluaXRTdGFydGVkID0gZmFsc2U7XG5cbiAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yKG9wdGlvbnM6IEJhc2VGaWxlU3lzdGVtT3B0aW9uczxUQmFja2VuZD4pIHtcbiAgICB0aGlzLmlkID0gb3B0aW9ucy5pZDtcbiAgICB0aGlzLmJhY2tlbmQgPSBvcHRpb25zLmJhY2tlbmQ7XG4gICAgdGhpcy5yb290ID0gbm9ybWFsaXplRmlsZVN5c3RlbVJvb3Qob3B0aW9ucy5yb290KTtcbiAgICB0aGlzLnJlYWRPbmx5ID0gb3B0aW9ucy5yZWFkT25seSA/PyBmYWxzZTtcbiAgICB0aGlzLmNyZWF0ZVJvb3QgPSBvcHRpb25zLmNyZWF0ZVJvb3QgPz8gZmFsc2U7XG4gICAgdGhpcy5faW5pdCA9IHRoaXMuY3JlYXRlSW5pdCgpO1xuICB9XG5cbiAgLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG4gIC8qIExpZmVjeWNsZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqL1xuICAvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuICBwcml2YXRlIGNyZWF0ZUluaXQoKTogKCkgPT4gUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uTW9kdWxlLm1lbW9pemUoYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5pbml0U3RhcnRlZCA9IHRydWU7XG4gICAgICBpZiAodGhpcy5jcmVhdGVSb290KSB7XG4gICAgICAgIGF3YWl0IHRoaXMuZ3VhcmQodGhpcy5yb290LCAoKSA9PiB0aGlzLmNyZWF0ZVJvb3REaXJlY3RvcnkoKSk7XG4gICAgICB9XG4gICAgICBhd2FpdCB0aGlzLm9uSW5pdCgpO1xuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgaW5pdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLl9pbml0KCk7XG4gIH1cblxuICBhc3luYyBjbG9zZSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMuaW5pdFN0YXJ0ZWQpIHJldHVybjtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5faW5pdCgpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdGhpcy5pbml0U3RhcnRlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5faW5pdCA9IHRoaXMuY3JlYXRlSW5pdCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBhd2FpdCB0aGlzLm9uQ2xvc2UoKTtcbiAgICB0aGlzLmluaXRTdGFydGVkID0gZmFsc2U7XG4gICAgdGhpcy5faW5pdCA9IHRoaXMuY3JlYXRlSW5pdCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEVuc3VyZSB7QGxpbmsgcm9vdH0gZXhpc3RzIHdoZW4ge0BsaW5rIGNyZWF0ZVJvb3R9IGlzIHRydWUuXG4gICAqXG4gICAqIERlZmF1bHQgaXMgYSBuby1vcC4gTG9jYWwgYWRhcHRlcnMgdHlwaWNhbGx5IGBta2RpciAtcGA7IHJlbW90ZSBhZGFwdGVyc1xuICAgKiBsZWF2ZSB0aGUgZGVmYXVsdCB3aGVuIHRoZSByb290IGlzIHByb3Zpc2lvbmVkIG91dCBvZiBiYW5kLlxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGNyZWF0ZVJvb3REaXJlY3RvcnkoKTogUHJvbWlzZTx2b2lkPiB7fVxuXG4gIC8qKiBPdmVycmlkZSB3aGVuIHRoZSBiYWNrZW5kIHJlcXVpcmVzIGNvbm5lY3Rpb24gb3IgdmFsaWRhdGlvbiB3b3JrLiAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgb25Jbml0KCk6IFByb21pc2U8dm9pZD4ge31cblxuICAvKiogT3ZlcnJpZGUgd2hlbiB0aGUgYmFja2VuZCBvd25zIGNvbm5lY3Rpb25zIG9yIG90aGVyIHJlc291cmNlcy4gKi9cbiAgcHJvdGVjdGVkIGFzeW5jIG9uQ2xvc2UoKTogUHJvbWlzZTx2b2lkPiB7fVxuXG4gIHByb3RlY3RlZCBhc3NlcnRXcml0YWJsZShvcGVyYXRpb246IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICh0aGlzLnJlYWRPbmx5KSB7XG4gICAgICB0aHJvdyBuZXcgRmlsZVN5c3RlbUVycm9yKFwiUkVBRF9PTkxZXCIsIGBDYW5ub3QgJHtvcGVyYXRpb259OiBmaWxlc3lzdGVtIGlzIHJlYWQtb25seWApO1xuICAgIH1cbiAgfVxuXG4gIC8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuICAvKiBQYXRocyAoUE9TSVggb25seSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKi9cbiAgLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbiAgLyoqXG4gICAqIE5vcm1hbGl6ZSBhbiBpbnB1dCBwYXRoIGludG8gYW4gYWJzb2x1dGUgUE9TSVggcGF0aCBpbnNpZGUgdGhlIHZpcnR1YWxcbiAgICogZmlsZXN5c3RlbSBuYW1lc3BhY2UgKGAvYS9iYCkuIEJhY2tzbGFzaGVzIGFyZSBjb252ZXJ0ZWQ7IGAuLmAgZXNjYXBpbmdcbiAgICogdGhlIHJvb3QgdGhyb3dzIHtAbGluayBGaWxlU3lzdGVtRXJyb3J9IGBQRVJNSVNTSU9OX0RFTklFRGAuXG4gICAqL1xuICBwcm90ZWN0ZWQgbm9ybWFsaXplUGF0aChpbnB1dFBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKGlucHV0UGF0aC5pbmNsdWRlcyhcIlxcMFwiKSkge1xuICAgICAgdGhyb3cgbmV3IEZpbGVTeXN0ZW1FcnJvcihcIklOVkFMSURfUEFUSFwiLCBcIlBhdGhzIGNhbm5vdCBjb250YWluIG51bGwgY2hhcmFjdGVyc1wiLCBpbnB1dFBhdGgpO1xuICAgIH1cblxuICAgIGNvbnN0IHJlc3VsdCA9IHBvc2l4UGF0aC5ub3JtYWxpemUoaW5wdXRQYXRoKTtcbiAgICBpZiAoIXJlc3VsdC5vaykge1xuICAgICAgdGhyb3cgbmV3IEZpbGVTeXN0ZW1FcnJvcihcIlBFUk1JU1NJT05fREVOSUVEXCIsIFwiUGF0aCBlc2NhcGVzIHRoZSBmaWxlc3lzdGVtIHJvb3RcIiwgaW5wdXRQYXRoKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdC5wYXRoO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYSBQT1NJWCBiYWNrZW5kIHBhdGggKHVuZGVyIHtAbGluayByb290fSkgaW50byB0aGUgZm9ybSB0aGVcbiAgICogdW5kZXJseWluZyBBUEkgZXhwZWN0cy5cbiAgICpcbiAgICogRGVmYXVsdCBpcyBpZGVudGl0eS4gTG9jYWwgZGlzayBvdmVycmlkZXMgd2l0aCB7QGxpbmsgcG9zaXhQYXRoLnRvSG9zdH0uXG4gICAqIERhdGFicmlja3MgLyBvYmplY3Qtc3RvcmUgYWRhcHRlcnMgdXN1YWxseSBsZWF2ZSB0aGUgZGVmYXVsdC5cbiAgICovXG4gIHByb3RlY3RlZCB0b0JhY2tlbmRQYXRoKHBvc2l4QmFja2VuZFBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHBvc2l4QmFja2VuZFBhdGg7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydCBhIG5vcm1hbGl6ZWQgbmFtZXNwYWNlIHBhdGggKGAvYS9iYCkgaW50byBhIGJhY2tlbmQgcGF0aC5cbiAgICpcbiAgICogSm9pbnMge0BsaW5rIHJvb3R9IHdpdGggdGhlIG5hbWVzcGFjZSB1c2luZyBQT1NJWCBgL2AsIHRoZW4gYXBwbGllc1xuICAgKiB7QGxpbmsgdG9CYWNrZW5kUGF0aH0uIE92ZXJyaWRlIHtAbGluayB0b0JhY2tlbmRQYXRofSBpbnN0ZWFkIG9mIHRoaXNcbiAgICogbWV0aG9kIHVubGVzcyB0aGUgam9pbiBpdHNlbGYgbXVzdCBjaGFuZ2UuXG4gICAqL1xuICBwcm90ZWN0ZWQgcmVzb2x2ZUJhY2tlbmRQYXRoKG5hbWVzcGFjZVBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgcG9zaXggPVxuICAgICAgbmFtZXNwYWNlUGF0aCA9PT0gXCIvXCIgPyB0aGlzLnJvb3QgOiBwb3NpeFBhdGguam9pbih0aGlzLnJvb3QsIG5hbWVzcGFjZVBhdGguc2xpY2UoMSkpO1xuICAgIHJldHVybiB0aGlzLnRvQmFja2VuZFBhdGgocG9zaXgpO1xuICB9XG5cbiAgcmVzb2x2ZVBhdGgoaW5wdXRQYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnJlc29sdmVCYWNrZW5kUGF0aCh0aGlzLm5vcm1hbGl6ZVBhdGgoaW5wdXRQYXRoKSk7XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSB7QGxpbmsgaW5wdXRQYXRofSwgZW5zdXJlIGluaXQsIGFuZCBydW4ge0BsaW5rIHByZXBhcmVQYXRofS5cbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyByZXNvbHZlRm9yKFxuICAgIGlucHV0UGF0aDogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7IGFsbG93TWlzc2luZz86IGJvb2xlYW4gfSxcbiAgKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBhd2FpdCB0aGlzLl9pbml0KCk7XG4gICAgcmV0dXJuIHRoaXMucmVzb2x2ZU5hbWVzcGFjZUZvcih0aGlzLm5vcm1hbGl6ZVBhdGgoaW5wdXRQYXRoKSwgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICoge0BsaW5rIHJlc29sdmVGb3J9IGZvciBhIHBhdGggdGhhdCBpcyBBTFJFQURZIGEgbm9ybWFsaXplZCBuYW1lc3BhY2UgcGF0aFxuICAgKiAoYC9hL2JgKS4gVGhlIHNpbmdsZSBzcGVsbGluZyBmb3IgXCJuYW1lc3BhY2UgcGF0aCB0byBwcmVwYXJlZCBiYWNrZW5kXG4gICAqIHBhdGhcIiwgc28gbm8gY2FsbCBzaXRlIGhhcyB0byByZS1kZXJpdmUgdGhlIGNoYWluIGJ5IGhhbmQuXG4gICAqL1xuICBwcml2YXRlIHJlc29sdmVOYW1lc3BhY2VGb3IoXG4gICAgbmFtZXNwYWNlUGF0aDogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7IGFsbG93TWlzc2luZz86IGJvb2xlYW4gfSxcbiAgKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gdGhpcy5wcmVwYXJlUGF0aCh0aGlzLnJlc29sdmVCYWNrZW5kUGF0aChuYW1lc3BhY2VQYXRoKSwgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogSG9vayBhZnRlciBsZXhpY2FsIHJlc29sdXRpb24uIE92ZXJyaWRlIGZvciByZWFscGF0aCBjb250YWlubWVudCBvclxuICAgKiBzaW1pbGFyIGJhY2tlbmQtc3BlY2lmaWMgY2hlY2tzLiBEZWZhdWx0IGlzIGEgbm8tb3AuXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgcHJlcGFyZVBhdGgoXG4gICAgcmVzb2x2ZWRQYXRoOiBzdHJpbmcsXG4gICAgX29wdGlvbnM/OiB7IGFsbG93TWlzc2luZz86IGJvb2xlYW4gfSxcbiAgKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gcmVzb2x2ZWRQYXRoO1xuICB9XG5cbiAgcHJvdGVjdGVkIGpvaW5OYW1lc3BhY2UocGFyZW50OiBzdHJpbmcsIGNoaWxkOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLm5vcm1hbGl6ZVBhdGgocG9zaXhQYXRoLmpvaW4ocGFyZW50LCBjaGlsZCkpO1xuICB9XG5cbiAgLyoqIE5hbWVzcGFjZSBwYXRoIHdpdGhvdXQgYSBsZWFkaW5nIHNsYXNoIChgLmAgZm9yIHRoZSByb290KS4gKi9cbiAgcHJvdGVjdGVkIHRvUmVsYXRpdmVQYXRoKG5hbWVzcGFjZVBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIG5hbWVzcGFjZVBhdGggPT09IFwiL1wiID8gXCIuXCIgOiBuYW1lc3BhY2VQYXRoLnNsaWNlKDEpO1xuICB9XG5cbiAgcHJvdGVjdGVkIHRvQnl0ZXMoY29udGVudDogRmlsZUNvbnRlbnQpOiBVaW50OEFycmF5IHtcbiAgICByZXR1cm4gdHlwZW9mIGNvbnRlbnQgPT09IFwic3RyaW5nXCIgPyBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoY29udGVudCkgOiBjb250ZW50O1xuICB9XG5cbiAgLyoqIENyZWF0ZSBwYXJlbnQgZGlyZWN0b3JpZXMgZm9yIHtAbGluayBpbnB1dFBhdGh9IHdoZW4gaXQgaXMgbmVzdGVkLiAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgZW5zdXJlUGFyZW50RGlyZWN0b3J5KGlucHV0UGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbmFtZXNwYWNlUGF0aCA9IHRoaXMubm9ybWFsaXplUGF0aChpbnB1dFBhdGgpO1xuICAgIGNvbnN0IHBhcmVudCA9IHBvc2l4UGF0aC5kaXJuYW1lKG5hbWVzcGFjZVBhdGgpO1xuICAgIGlmIChwYXJlbnQgPT09IFwiL1wiIHx8IHBhcmVudCA9PT0gbmFtZXNwYWNlUGF0aCkgcmV0dXJuO1xuICAgIGF3YWl0IHRoaXMubWtkaXIocGFyZW50LCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgfVxuXG4gIC8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuICAvKiBCYWNrZW5kIHByaW1pdGl2ZXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKi9cbiAgLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbiAgcHJvdGVjdGVkIGFic3RyYWN0IHJlYWRCeXRlc0F0KHJlc29sdmVkUGF0aDogc3RyaW5nKTogUHJvbWlzZTxVaW50OEFycmF5PjtcblxuICBwcm90ZWN0ZWQgYWJzdHJhY3Qgd3JpdGVCeXRlc0F0KFxuICAgIHJlc29sdmVkUGF0aDogc3RyaW5nLFxuICAgIGNvbnRlbnQ6IFVpbnQ4QXJyYXksXG4gICAgb3B0aW9uczogUmVxdWlyZWQ8V3JpdGVGaWxlT3B0aW9ucz4sXG4gICk6IFByb21pc2U8dm9pZD47XG5cbiAgcHJvdGVjdGVkIGFic3RyYWN0IGRlbGV0ZUZpbGVBdChyZXNvbHZlZFBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD47XG5cbiAgcHJvdGVjdGVkIGFic3RyYWN0IGNyZWF0ZURpcmVjdG9yeUF0KHJlc29sdmVkUGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPjtcblxuICAvKipcbiAgICogUmVtb3ZlIGFuIGVtcHR5IGRpcmVjdG9yeS5cbiAgICpcbiAgICogUmVjdXJzaXZlIGRlbGV0aW9uIGlzIGltcGxlbWVudGVkIGJ5IHtAbGluayBCYXNlRmlsZVN5c3RlbX0uXG4gICAqL1xuICBwcm90ZWN0ZWQgYWJzdHJhY3QgcmVtb3ZlRGlyZWN0b3J5QXQocmVzb2x2ZWRQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+O1xuXG4gIC8qKiBSZXR1cm4gb25seSB0aGUgZGlyZWN0IGNoaWxkcmVuIG9mIGEgZGlyZWN0b3J5IChgbmFtZWAgaXMgdGhlIGJhc2VuYW1lKS4gKi9cbiAgcHJvdGVjdGVkIGFic3RyYWN0IGxpc3REaXJlY3RvcnlBdChyZXNvbHZlZFBhdGg6IHN0cmluZyk6IFByb21pc2U8RmlsZUVudHJ5W10+O1xuXG4gIHByb3RlY3RlZCBhYnN0cmFjdCBzdGF0QXQocmVzb2x2ZWRQYXRoOiBzdHJpbmcpOiBQcm9taXNlPE9taXQ8RmlsZVN0YXQsIFwicGF0aFwiPj47XG5cbiAgLyoqXG4gICAqIFJlY29nbml6ZSB0aGUgYmFja2VuZCdzIG5vdC1mb3VuZCBlcnJvci5cbiAgICpcbiAgICogRGVmYXVsdCBhY2NlcHRzIHtAbGluayBGaWxlU3lzdGVtRXJyb3J9IGBOT1RfRk9VTkRgIHBsdXMgY29tbW9uIFNESyAvIEhUVFBcbiAgICogXCJub3QgZm91bmRcIiBzaGFwZXMgdmlhIHtAbGluayBpbmZlckZpbGVTeXN0ZW1FcnJvckNvZGV9LiBPdmVycmlkZSBmb3JcbiAgICogYmFja2VuZC1zcGVjaWZpYyBjb2RlcyAoZS5nLiBOb2RlIGBFTk9FTlRgKSB0aGF0IGRvIG5vdCBjYXJyeSBhIG1lc3NhZ2UuXG4gICAqL1xuICBwcm90ZWN0ZWQgaXNOb3RGb3VuZEVycm9yKGVycjogdW5rbm93bik6IGJvb2xlYW4ge1xuICAgIGlmIChlcnIgaW5zdGFuY2VvZiBGaWxlU3lzdGVtRXJyb3IpIHJldHVybiBlcnIuY29kZSA9PT0gXCJOT1RfRk9VTkRcIjtcbiAgICByZXR1cm4gaW5mZXJGaWxlU3lzdGVtRXJyb3JDb2RlKGVycikgPT09IFwiTk9UX0ZPVU5EXCI7XG4gIH1cblxuICAvKipcbiAgICogTm9ybWFsaXplIGEgYmFja2VuZCBmYWlsdXJlIGludG8gYSB7QGxpbmsgRmlsZVN5c3RlbUVycm9yfS5cbiAgICpcbiAgICogRXZlcnkgYCpBdGAgLyBgdHJ5KmAgcHJpbWl0aXZlIGlzIGludm9rZWQgdGhyb3VnaCB7QGxpbmsgZ3VhcmR9LCBzbyBhblxuICAgKiBhZGFwdGVyIG5ldmVyIHdyaXRlcyBpdHMgb3duIHRyeS9jYXRjaCBhbmQgY2Fubm90IGZvcmdldCB0byBub3JtYWxpemUuXG4gICAqIE92ZXJyaWRlIG9ubHkgdG8gY2xhc3NpZnkgYmFja2VuZC1zcGVjaWZpYyBjb2RlcyAoZS5nLiBOb2RlIGVycm5vKS5cbiAgICovXG4gIHByb3RlY3RlZCBtYXBFcnJvcihlcnI6IHVua25vd24sIGZpbGVQYXRoOiBzdHJpbmcpOiBGaWxlU3lzdGVtRXJyb3Ige1xuICAgIHJldHVybiBtYXBGaWxlU3lzdGVtRXJyb3IoZXJyLCBmaWxlUGF0aCk7XG4gIH1cblxuICAvKiogUnVuIGEgYmFja2VuZCBwcmltaXRpdmUsIHJvdXRpbmcgYW55IGZhaWx1cmUgdGhyb3VnaCB7QGxpbmsgbWFwRXJyb3J9LiAqL1xuICBwcml2YXRlIGFzeW5jIGd1YXJkPFQ+KHJlc29sdmVkUGF0aDogc3RyaW5nLCBvcGVyYXRpb246ICgpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IG9wZXJhdGlvbigpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhyb3cgdGhpcy5tYXBFcnJvcihlcnIsIHJlc29sdmVkUGF0aCk7XG4gICAgfVxuICB9XG5cbiAgLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG4gIC8qIE9wdGlvbmFsIG5hdGl2ZS1vcGVyYXRpb24gaG9va3MgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqL1xuICAvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuICAvKipcbiAgICogT3ZlcnJpZGUgd2hlbiB0aGUgYmFja2VuZCBzdXBwb3J0cyBuYXRpdmUgYXBwZW5kLlxuICAgKlxuICAgKiBQYXJlbnQgZGlyZWN0b3JpZXMgYXJlIGFscmVhZHkgY3JlYXRlZCBieSB7QGxpbmsgYXBwZW5kRmlsZX0uIFJldHVybiB0cnVlXG4gICAqIHdoZW4gdGhlIG9wZXJhdGlvbiB3YXMgcGVyZm9ybWVkLiBUaGUgZGVmYXVsdCBjYXVzZXMge0BsaW5rIEJhc2VGaWxlU3lzdGVtfVxuICAgKiB0byB1c2UgcmVhZC1jb25jYXRlbmF0ZS13cml0ZS5cbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyB0cnlBcHBlbmRGaWxlQXQoX3Jlc29sdmVkUGF0aDogc3RyaW5nLCBfY29udGVudDogVWludDhBcnJheSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPdmVycmlkZSB3aGVuIHRoZSBiYWNrZW5kIHN1cHBvcnRzIG5hdGl2ZSBzZXJ2ZXItc2lkZSBjb3B5aW5nLlxuICAgKlxuICAgKiBQYXJlbnQgZGlyZWN0b3JpZXMgb2YgdGhlIGRlc3RpbmF0aW9uIGFyZSBhbHJlYWR5IGNyZWF0ZWQgYnkge0BsaW5rIGNvcHlGaWxlfS5cbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyB0cnlDb3B5RmlsZUF0KFxuICAgIF9zb3VyY2VQYXRoOiBzdHJpbmcsXG4gICAgX2Rlc3RpbmF0aW9uUGF0aDogc3RyaW5nLFxuICAgIF9vcHRpb25zOiBSZXF1aXJlZDxDb3B5T3B0aW9ucz4sXG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPdmVycmlkZSBmb3IgbmF0aXZlIHJlbmFtZSBvciBtb3ZlIHN1cHBvcnQuXG4gICAqXG4gICAqIFBhcmVudCBkaXJlY3RvcmllcyBvZiB0aGUgZGVzdGluYXRpb24gYXJlIGFscmVhZHkgY3JlYXRlZCBieSB7QGxpbmsgbW92ZUZpbGV9LlxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIHRyeU1vdmVGaWxlQXQoXG4gICAgX3NvdXJjZVBhdGg6IHN0cmluZyxcbiAgICBfZGVzdGluYXRpb25QYXRoOiBzdHJpbmcsXG4gICAgX29wdGlvbnM6IFJlcXVpcmVkPENvcHlPcHRpb25zPixcbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG4gIC8qIEZpbGUgb3BlcmF0aW9ucyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqL1xuICAvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuICBhc3luYyByZWFkRmlsZShpbnB1dFBhdGg6IHN0cmluZyk6IFByb21pc2U8VWludDhBcnJheT47XG4gIGFzeW5jIHJlYWRGaWxlKFxuICAgIGlucHV0UGF0aDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IFJlYWRGaWxlT3B0aW9ucyAmIHsgZW5jb2Rpbmc6IHN0cmluZyB9LFxuICApOiBQcm9taXNlPHN0cmluZz47XG4gIGFzeW5jIHJlYWRGaWxlKGlucHV0UGF0aDogc3RyaW5nLCBvcHRpb25zPzogUmVhZEZpbGVPcHRpb25zKTogUHJvbWlzZTxzdHJpbmcgfCBVaW50OEFycmF5PiB7XG4gICAgY29uc3QgcmVzb2x2ZWRQYXRoID0gYXdhaXQgdGhpcy5yZXNvbHZlRm9yKGlucHV0UGF0aCk7XG4gICAgY29uc3QgY29udGVudCA9IGF3YWl0IHRoaXMuZ3VhcmQocmVzb2x2ZWRQYXRoLCAoKSA9PiB0aGlzLnJlYWRCeXRlc0F0KHJlc29sdmVkUGF0aCkpO1xuICAgIGlmIChvcHRpb25zPy5lbmNvZGluZykge1xuICAgICAgcmV0dXJuIG5ldyBUZXh0RGVjb2RlcihvcHRpb25zLmVuY29kaW5nKS5kZWNvZGUoY29udGVudCk7XG4gICAgfVxuICAgIHJldHVybiBjb250ZW50O1xuICB9XG5cbiAgYXN5bmMgd3JpdGVGaWxlKFxuICAgIGlucHV0UGF0aDogc3RyaW5nLFxuICAgIGNvbnRlbnQ6IEZpbGVDb250ZW50LFxuICAgIG9wdGlvbnM6IFdyaXRlRmlsZU9wdGlvbnMgPSB7fSxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5faW5pdCgpO1xuICAgIHRoaXMuYXNzZXJ0V3JpdGFibGUoXCJ3cml0ZSBmaWxlXCIpO1xuXG4gICAgY29uc3Qgb3ZlcndyaXRlID0gYXdhaXQgdGhpcy5yZXNvbHZlT3ZlcndyaXRlKGlucHV0UGF0aCwgb3B0aW9ucywgXCJGaWxlXCIpO1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUGFyZW50RGlyZWN0b3J5KGlucHV0UGF0aCk7XG4gICAgY29uc3QgcmVzb2x2ZWRQYXRoID0gYXdhaXQgdGhpcy5yZXNvbHZlRm9yKGlucHV0UGF0aCwgeyBhbGxvd01pc3Npbmc6IHRydWUgfSk7XG4gICAgYXdhaXQgdGhpcy5ndWFyZChyZXNvbHZlZFBhdGgsICgpID0+XG4gICAgICB0aGlzLndyaXRlQnl0ZXNBdChyZXNvbHZlZFBhdGgsIHRoaXMudG9CeXRlcyhjb250ZW50KSwgeyBvdmVyd3JpdGUgfSksXG4gICAgKTtcbiAgfVxuXG4gIGFzeW5jIGFwcGVuZEZpbGUoaW5wdXRQYXRoOiBzdHJpbmcsIGNvbnRlbnQ6IEZpbGVDb250ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5faW5pdCgpO1xuICAgIHRoaXMuYXNzZXJ0V3JpdGFibGUoXCJhcHBlbmQgZmlsZVwiKTtcblxuICAgIGNvbnN0IGJ5dGVzID0gdGhpcy50b0J5dGVzKGNvbnRlbnQpO1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUGFyZW50RGlyZWN0b3J5KGlucHV0UGF0aCk7XG4gICAgY29uc3QgcmVzb2x2ZWRQYXRoID0gYXdhaXQgdGhpcy5yZXNvbHZlRm9yKGlucHV0UGF0aCwgeyBhbGxvd01pc3Npbmc6IHRydWUgfSk7XG5cbiAgICBpZiAoYXdhaXQgdGhpcy5ndWFyZChyZXNvbHZlZFBhdGgsICgpID0+IHRoaXMudHJ5QXBwZW5kRmlsZUF0KHJlc29sdmVkUGF0aCwgYnl0ZXMpKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGV4aXN0aW5nID0gKGF3YWl0IHRoaXMuZXhpc3RzKGlucHV0UGF0aCkpXG4gICAgICA/IGF3YWl0IHRoaXMucmVhZEZpbGUoaW5wdXRQYXRoKVxuICAgICAgOiBuZXcgVWludDhBcnJheSgpO1xuICAgIGNvbnN0IGNvbWJpbmVkID0gbmV3IFVpbnQ4QXJyYXkoZXhpc3RpbmcuYnl0ZUxlbmd0aCArIGJ5dGVzLmJ5dGVMZW5ndGgpO1xuICAgIGNvbWJpbmVkLnNldChleGlzdGluZyk7XG4gICAgY29tYmluZWQuc2V0KGJ5dGVzLCBleGlzdGluZy5ieXRlTGVuZ3RoKTtcbiAgICBhd2FpdCB0aGlzLndyaXRlRmlsZShpbnB1dFBhdGgsIGNvbWJpbmVkLCB7IG92ZXJ3cml0ZTogdHJ1ZSB9KTtcbiAgfVxuXG4gIGFzeW5jIGRlbGV0ZUZpbGUoaW5wdXRQYXRoOiBzdHJpbmcsIG9wdGlvbnM6IFJlbW92ZU9wdGlvbnMgPSB7fSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuX2luaXQoKTtcbiAgICB0aGlzLmFzc2VydFdyaXRhYmxlKFwiZGVsZXRlIGZpbGVcIik7XG5cbiAgICBhd2FpdCB0aGlzLmlnbm9yaW5nTWlzc2luZyhvcHRpb25zLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBlbnRyeSA9IGF3YWl0IHRoaXMuc3RhdChpbnB1dFBhdGgpO1xuICAgICAgaWYgKGVudHJ5LnR5cGUgPT09IFwiZGlyZWN0b3J5XCIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEZpbGVTeXN0ZW1FcnJvcihcIklTX0RJUkVDVE9SWVwiLCBgUGF0aCBpcyBhIGRpcmVjdG9yeTogJHtpbnB1dFBhdGh9YCwgaW5wdXRQYXRoKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHJlc29sdmVkUGF0aCA9IGF3YWl0IHRoaXMucmVzb2x2ZUZvcihpbnB1dFBhdGgpO1xuICAgICAgYXdhaXQgdGhpcy5ndWFyZChyZXNvbHZlZFBhdGgsICgpID0+IHRoaXMuZGVsZXRlRmlsZUF0KHJlc29sdmVkUGF0aCkpO1xuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgY29weUZpbGUoXG4gICAgc291cmNlUGF0aDogc3RyaW5nLFxuICAgIGRlc3RpbmF0aW9uUGF0aDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IENvcHlPcHRpb25zID0ge30sXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgc291cmNlLCBkZXN0aW5hdGlvbiwgcmVzb2x2ZWQgfSA9IGF3YWl0IHRoaXMucHJlcGFyZVRyYW5zZmVyKFxuICAgICAgXCJjb3B5IGZpbGVcIixcbiAgICAgIHNvdXJjZVBhdGgsXG4gICAgICBkZXN0aW5hdGlvblBhdGgsXG4gICAgICBvcHRpb25zLFxuICAgICk7XG5cbiAgICBpZiAoYXdhaXQgdGhpcy5ndWFyZChkZXN0aW5hdGlvbiwgKCkgPT4gdGhpcy50cnlDb3B5RmlsZUF0KHNvdXJjZSwgZGVzdGluYXRpb24sIHJlc29sdmVkKSkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBhd2FpdCB0aGlzLndyaXRlRmlsZShkZXN0aW5hdGlvblBhdGgsIGF3YWl0IHRoaXMucmVhZEZpbGUoc291cmNlUGF0aCksIHJlc29sdmVkKTtcbiAgfVxuXG4gIGFzeW5jIG1vdmVGaWxlKFxuICAgIHNvdXJjZVBhdGg6IHN0cmluZyxcbiAgICBkZXN0aW5hdGlvblBhdGg6IHN0cmluZyxcbiAgICBvcHRpb25zOiBDb3B5T3B0aW9ucyA9IHt9LFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IHNvdXJjZSwgZGVzdGluYXRpb24sIHJlc29sdmVkIH0gPSBhd2FpdCB0aGlzLnByZXBhcmVUcmFuc2ZlcihcbiAgICAgIFwibW92ZSBmaWxlXCIsXG4gICAgICBzb3VyY2VQYXRoLFxuICAgICAgZGVzdGluYXRpb25QYXRoLFxuICAgICAgb3B0aW9ucyxcbiAgICApO1xuXG4gICAgaWYgKGF3YWl0IHRoaXMuZ3VhcmQoZGVzdGluYXRpb24sICgpID0+IHRoaXMudHJ5TW92ZUZpbGVBdChzb3VyY2UsIGRlc3RpbmF0aW9uLCByZXNvbHZlZCkpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5jb3B5RmlsZShzb3VyY2VQYXRoLCBkZXN0aW5hdGlvblBhdGgsIHJlc29sdmVkKTtcbiAgICBjb25zdCBzb3VyY2VTdGF0ID0gYXdhaXQgdGhpcy5zdGF0KHNvdXJjZVBhdGgpO1xuICAgIGlmIChzb3VyY2VTdGF0LnR5cGUgPT09IFwiZGlyZWN0b3J5XCIpIHtcbiAgICAgIGF3YWl0IHRoaXMucm1kaXIoc291cmNlUGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IHRoaXMuZGVsZXRlRmlsZShzb3VyY2VQYXRoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSB0aGUgZWZmZWN0aXZlIGBvdmVyd3JpdGVgIGZsYWcsIHJlamVjdGluZyB3aGVuIHRoZSB0YXJnZXQgZXhpc3RzXG4gICAqIGFuZCBvdmVyd3JpdGluZyB3YXMgcmVmdXNlZC4gU2hhcmVkIGJ5IHdyaXRlIC8gY29weSAvIG1vdmUgc28gdGhlIHRocmVlXG4gICAqIGNhbm5vdCBkaXNhZ3JlZSBhYm91dCB3aGF0IGBvdmVyd3JpdGU6IGZhbHNlYCBtZWFucy5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVzb2x2ZU92ZXJ3cml0ZShcbiAgICBpbnB1dFBhdGg6IHN0cmluZyxcbiAgICBvcHRpb25zOiB7IG92ZXJ3cml0ZT86IGJvb2xlYW4gfSxcbiAgICBsYWJlbDogc3RyaW5nLFxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBvdmVyd3JpdGUgPSBvcHRpb25zLm92ZXJ3cml0ZSA/PyB0cnVlO1xuICAgIGlmICghb3ZlcndyaXRlICYmIChhd2FpdCB0aGlzLmV4aXN0cyhpbnB1dFBhdGgpKSkge1xuICAgICAgdGhyb3cgbmV3IEZpbGVTeXN0ZW1FcnJvcihcbiAgICAgICAgXCJBTFJFQURZX0VYSVNUU1wiLFxuICAgICAgICBgJHtsYWJlbH0gYWxyZWFkeSBleGlzdHM6ICR7aW5wdXRQYXRofWAsXG4gICAgICAgIGlucHV0UGF0aCxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBvdmVyd3JpdGU7XG4gIH1cblxuICAvKiogU2hhcmVkIGNvcHkgLyBtb3ZlIHByb2xvZ3VlOiB3cml0YWJpbGl0eSwgb3ZlcndyaXRlIHBvbGljeSwgYm90aCBlbmRzIHJlc29sdmVkLiAqL1xuICBwcml2YXRlIGFzeW5jIHByZXBhcmVUcmFuc2ZlcihcbiAgICBvcGVyYXRpb246IHN0cmluZyxcbiAgICBzb3VyY2VQYXRoOiBzdHJpbmcsXG4gICAgZGVzdGluYXRpb25QYXRoOiBzdHJpbmcsXG4gICAgb3B0aW9uczogQ29weU9wdGlvbnMsXG4gICk6IFByb21pc2U8eyBzb3VyY2U6IHN0cmluZzsgZGVzdGluYXRpb246IHN0cmluZzsgcmVzb2x2ZWQ6IFJlcXVpcmVkPENvcHlPcHRpb25zPiB9PiB7XG4gICAgYXdhaXQgdGhpcy5faW5pdCgpO1xuICAgIHRoaXMuYXNzZXJ0V3JpdGFibGUob3BlcmF0aW9uKTtcblxuICAgIGNvbnN0IG92ZXJ3cml0ZSA9IGF3YWl0IHRoaXMucmVzb2x2ZU92ZXJ3cml0ZShkZXN0aW5hdGlvblBhdGgsIG9wdGlvbnMsIFwiRGVzdGluYXRpb25cIik7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVQYXJlbnREaXJlY3RvcnkoZGVzdGluYXRpb25QYXRoKTtcblxuICAgIHJldHVybiB7XG4gICAgICBzb3VyY2U6IGF3YWl0IHRoaXMucmVzb2x2ZUZvcihzb3VyY2VQYXRoKSxcbiAgICAgIGRlc3RpbmF0aW9uOiBhd2FpdCB0aGlzLnJlc29sdmVGb3IoZGVzdGluYXRpb25QYXRoLCB7IGFsbG93TWlzc2luZzogdHJ1ZSB9KSxcbiAgICAgIHJlc29sdmVkOiB7IG92ZXJ3cml0ZSB9LFxuICAgIH07XG4gIH1cblxuICAvKiogUnVuIGEgcmVtb3ZhbCwgc3dhbGxvd2luZyBhIG5vdC1mb3VuZCBmYWlsdXJlIHdoZW4gYGZvcmNlYCBpcyBzZXQuICovXG4gIHByaXZhdGUgYXN5bmMgaWdub3JpbmdNaXNzaW5nKFxuICAgIG9wdGlvbnM6IFJlbW92ZU9wdGlvbnMsXG4gICAgb3BlcmF0aW9uOiAoKSA9PiBQcm9taXNlPHZvaWQ+LFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgb3BlcmF0aW9uKCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAob3B0aW9ucy5mb3JjZSAmJiB0aGlzLmlzTm90Rm91bmRFcnJvcihlcnIpKSByZXR1cm47XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICB9XG5cbiAgLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG4gIC8qIERpcmVjdG9yeSBvcGVyYXRpb25zICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqL1xuICAvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuICBhc3luYyBta2RpcihpbnB1dFBhdGg6IHN0cmluZywgb3B0aW9uczogTWFrZURpcmVjdG9yeU9wdGlvbnMgPSB7fSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuX2luaXQoKTtcbiAgICB0aGlzLmFzc2VydFdyaXRhYmxlKFwiY3JlYXRlIGRpcmVjdG9yeVwiKTtcblxuICAgIGNvbnN0IG5hbWVzcGFjZVBhdGggPSB0aGlzLm5vcm1hbGl6ZVBhdGgoaW5wdXRQYXRoKTtcblxuICAgIGlmICghb3B0aW9ucy5yZWN1cnNpdmUpIHtcbiAgICAgIGF3YWl0IHRoaXMuY3JlYXRlRGlyZWN0b3J5KG5hbWVzcGFjZVBhdGgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGxldCBjdXJyZW50UGF0aCA9IFwiXCI7XG4gICAgZm9yIChjb25zdCBzZWdtZW50IG9mIG5hbWVzcGFjZVBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKSkge1xuICAgICAgY3VycmVudFBhdGggPSBgJHtjdXJyZW50UGF0aH0vJHtzZWdtZW50fWA7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBlbnRyeSA9IGF3YWl0IHRoaXMuc3RhdChjdXJyZW50UGF0aCk7XG4gICAgICAgIGlmIChlbnRyeS50eXBlICE9PSBcImRpcmVjdG9yeVwiKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEZpbGVTeXN0ZW1FcnJvcihcbiAgICAgICAgICAgIFwiTk9UX0RJUkVDVE9SWVwiLFxuICAgICAgICAgICAgYFBhdGggY29tcG9uZW50IGlzIG5vdCBhIGRpcmVjdG9yeTogJHtjdXJyZW50UGF0aH1gLFxuICAgICAgICAgICAgY3VycmVudFBhdGgsXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzTm90Rm91bmRFcnJvcihlcnJvcikpIHRocm93IGVycm9yO1xuICAgICAgICBhd2FpdCB0aGlzLmNyZWF0ZURpcmVjdG9yeShjdXJyZW50UGF0aCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgcm1kaXIoaW5wdXRQYXRoOiBzdHJpbmcsIG9wdGlvbnM6IFJlbW92ZU9wdGlvbnMgPSB7fSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuX2luaXQoKTtcbiAgICB0aGlzLmFzc2VydFdyaXRhYmxlKFwicmVtb3ZlIGRpcmVjdG9yeVwiKTtcblxuICAgIGF3YWl0IHRoaXMuaWdub3JpbmdNaXNzaW5nKG9wdGlvbnMsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGVudHJ5ID0gYXdhaXQgdGhpcy5zdGF0KGlucHV0UGF0aCk7XG4gICAgICBpZiAoZW50cnkudHlwZSAhPT0gXCJkaXJlY3RvcnlcIikge1xuICAgICAgICB0aHJvdyBuZXcgRmlsZVN5c3RlbUVycm9yKFxuICAgICAgICAgIFwiTk9UX0RJUkVDVE9SWVwiLFxuICAgICAgICAgIGBQYXRoIGlzIG5vdCBhIGRpcmVjdG9yeTogJHtpbnB1dFBhdGh9YCxcbiAgICAgICAgICBpbnB1dFBhdGgsXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG5hbWVzcGFjZVBhdGggPSB0aGlzLm5vcm1hbGl6ZVBhdGgoaW5wdXRQYXRoKTtcbiAgICAgIGlmIChvcHRpb25zLnJlY3Vyc2l2ZSkge1xuICAgICAgICBhd2FpdCB0aGlzLnJlbW92ZURpcmVjdG9yeUNvbnRlbnRzKG5hbWVzcGFjZVBhdGgpO1xuICAgICAgfVxuICAgICAgYXdhaXQgdGhpcy5yZW1vdmVEaXJlY3RvcnkobmFtZXNwYWNlUGF0aCk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJlbW92ZURpcmVjdG9yeUNvbnRlbnRzKG5hbWVzcGFjZVBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGZvciAoY29uc3QgZW50cnkgb2YgYXdhaXQgdGhpcy5saXN0RGlyZWN0b3J5KG5hbWVzcGFjZVBhdGgpKSB7XG4gICAgICBjb25zdCBjaGlsZFBhdGggPSB0aGlzLmpvaW5OYW1lc3BhY2UobmFtZXNwYWNlUGF0aCwgZW50cnkubmFtZSk7XG4gICAgICBpZiAoZW50cnkudHlwZSA9PT0gXCJkaXJlY3RvcnlcIikge1xuICAgICAgICBhd2FpdCB0aGlzLnJlbW92ZURpcmVjdG9yeUNvbnRlbnRzKGNoaWxkUGF0aCk7XG4gICAgICAgIGF3YWl0IHRoaXMucmVtb3ZlRGlyZWN0b3J5KGNoaWxkUGF0aCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCByZXNvbHZlZFBhdGggPSBhd2FpdCB0aGlzLnJlc29sdmVOYW1lc3BhY2VGb3IoY2hpbGRQYXRoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5ndWFyZChyZXNvbHZlZFBhdGgsICgpID0+IHRoaXMuZGVsZXRlRmlsZUF0KHJlc29sdmVkUGF0aCkpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKiB7QGxpbmsgY3JlYXRlRGlyZWN0b3J5QXR9IGZvciBhIG5hbWVzcGFjZSBwYXRoLCByZXNvbHZlZCBhbmQgZ3VhcmRlZC4gKi9cbiAgcHJpdmF0ZSBhc3luYyBjcmVhdGVEaXJlY3RvcnkobmFtZXNwYWNlUGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcmVzb2x2ZWRQYXRoID0gYXdhaXQgdGhpcy5yZXNvbHZlTmFtZXNwYWNlRm9yKG5hbWVzcGFjZVBhdGgsIHsgYWxsb3dNaXNzaW5nOiB0cnVlIH0pO1xuICAgIGF3YWl0IHRoaXMuZ3VhcmQocmVzb2x2ZWRQYXRoLCAoKSA9PiB0aGlzLmNyZWF0ZURpcmVjdG9yeUF0KHJlc29sdmVkUGF0aCkpO1xuICB9XG5cbiAgLyoqIHtAbGluayByZW1vdmVEaXJlY3RvcnlBdH0gZm9yIGEgbmFtZXNwYWNlIHBhdGgsIHJlc29sdmVkIGFuZCBndWFyZGVkLiAqL1xuICBwcml2YXRlIGFzeW5jIHJlbW92ZURpcmVjdG9yeShuYW1lc3BhY2VQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCByZXNvbHZlZFBhdGggPSBhd2FpdCB0aGlzLnJlc29sdmVOYW1lc3BhY2VGb3IobmFtZXNwYWNlUGF0aCk7XG4gICAgYXdhaXQgdGhpcy5ndWFyZChyZXNvbHZlZFBhdGgsICgpID0+IHRoaXMucmVtb3ZlRGlyZWN0b3J5QXQocmVzb2x2ZWRQYXRoKSk7XG4gIH1cblxuICAvKioge0BsaW5rIGxpc3REaXJlY3RvcnlBdH0gZm9yIGEgbmFtZXNwYWNlIHBhdGgsIHJlc29sdmVkIGFuZCBndWFyZGVkLiAqL1xuICBwcml2YXRlIGFzeW5jIGxpc3REaXJlY3RvcnkobmFtZXNwYWNlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxGaWxlRW50cnlbXT4ge1xuICAgIGNvbnN0IHJlc29sdmVkUGF0aCA9IGF3YWl0IHRoaXMucmVzb2x2ZU5hbWVzcGFjZUZvcihuYW1lc3BhY2VQYXRoKTtcbiAgICByZXR1cm4gdGhpcy5ndWFyZChyZXNvbHZlZFBhdGgsICgpID0+IHRoaXMubGlzdERpcmVjdG9yeUF0KHJlc29sdmVkUGF0aCkpO1xuICB9XG5cbiAgYXN5bmMgcmVhZGRpcihpbnB1dFBhdGg6IHN0cmluZywgb3B0aW9uczogTGlzdE9wdGlvbnMgPSB7fSk6IFByb21pc2U8RmlsZUVudHJ5W10+IHtcbiAgICBhd2FpdCB0aGlzLl9pbml0KCk7XG5cbiAgICBjb25zdCBuYW1lc3BhY2VQYXRoID0gdGhpcy5ub3JtYWxpemVQYXRoKGlucHV0UGF0aCk7XG5cbiAgICBpZiAoIW9wdGlvbnMucmVjdXJzaXZlKSB7XG4gICAgICByZXR1cm4gdGhpcy5maWx0ZXJFbnRyaWVzKGF3YWl0IHRoaXMubGlzdERpcmVjdG9yeShuYW1lc3BhY2VQYXRoKSwgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMubGlzdERpcmVjdG9yeVJlY3Vyc2l2ZShuYW1lc3BhY2VQYXRoLCBvcHRpb25zLCAwLCBcIlwiKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbGlzdERpcmVjdG9yeVJlY3Vyc2l2ZShcbiAgICBuYW1lc3BhY2VQYXRoOiBzdHJpbmcsXG4gICAgb3B0aW9uczogTGlzdE9wdGlvbnMsXG4gICAgZGVwdGg6IG51bWJlcixcbiAgICBwcmVmaXg6IHN0cmluZyxcbiAgKTogUHJvbWlzZTxGaWxlRW50cnlbXT4ge1xuICAgIGNvbnN0IG1heGltdW1EZXB0aCA9IG9wdGlvbnMubWF4RGVwdGggPz8gTnVtYmVyLlBPU0lUSVZFX0lORklOSVRZO1xuICAgIGNvbnN0IGVudHJpZXMgPSB0aGlzLmZpbHRlckVudHJpZXMoYXdhaXQgdGhpcy5saXN0RGlyZWN0b3J5KG5hbWVzcGFjZVBhdGgpLCBvcHRpb25zKTtcblxuICAgIGNvbnN0IHJlc3VsdHM6IEZpbGVFbnRyeVtdID0gW107XG5cbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgIGNvbnN0IHJlbGF0aXZlTmFtZSA9IHByZWZpeCA/IGAke3ByZWZpeH0vJHtlbnRyeS5uYW1lfWAgOiBlbnRyeS5uYW1lO1xuICAgICAgcmVzdWx0cy5wdXNoKHsgLi4uZW50cnksIG5hbWU6IHJlbGF0aXZlTmFtZSB9KTtcblxuICAgICAgaWYgKGVudHJ5LnR5cGUgPT09IFwiZGlyZWN0b3J5XCIgJiYgZGVwdGggPCBtYXhpbXVtRGVwdGgpIHtcbiAgICAgICAgcmVzdWx0cy5wdXNoKFxuICAgICAgICAgIC4uLihhd2FpdCB0aGlzLmxpc3REaXJlY3RvcnlSZWN1cnNpdmUoXG4gICAgICAgICAgICB0aGlzLmpvaW5OYW1lc3BhY2UobmFtZXNwYWNlUGF0aCwgZW50cnkubmFtZSksXG4gICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgZGVwdGggKyAxLFxuICAgICAgICAgICAgcmVsYXRpdmVOYW1lLFxuICAgICAgICAgICkpLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgcHJpdmF0ZSBmaWx0ZXJFbnRyaWVzKGVudHJpZXM6IEZpbGVFbnRyeVtdLCBvcHRpb25zOiBMaXN0T3B0aW9ucyk6IEZpbGVFbnRyeVtdIHtcbiAgICBpZiAoIW9wdGlvbnMuZXh0ZW5zaW9uKSB7XG4gICAgICByZXR1cm4gZW50cmllcztcbiAgICB9XG5cbiAgICBjb25zdCBleHRlbnNpb25zID0gKFxuICAgICAgQXJyYXkuaXNBcnJheShvcHRpb25zLmV4dGVuc2lvbikgPyBvcHRpb25zLmV4dGVuc2lvbiA6IFtvcHRpb25zLmV4dGVuc2lvbl1cbiAgICApLm1hcCgoZXh0ZW5zaW9uKSA9PiB7XG4gICAgICBjb25zdCBub3JtYWxpemVkID0gZXh0ZW5zaW9uLnRvTG93ZXJDYXNlKCk7XG4gICAgICByZXR1cm4gbm9ybWFsaXplZC5zdGFydHNXaXRoKFwiLlwiKSA/IG5vcm1hbGl6ZWQgOiBgLiR7bm9ybWFsaXplZH1gO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGVudHJpZXMuZmlsdGVyKChlbnRyeSkgPT4ge1xuICAgICAgaWYgKGVudHJ5LnR5cGUgIT09IFwiZmlsZVwiKSByZXR1cm4gdHJ1ZTtcbiAgICAgIGNvbnN0IGxvd2VyID0gZW50cnkubmFtZS50b0xvd2VyQ2FzZSgpO1xuICAgICAgcmV0dXJuIGV4dGVuc2lvbnMuc29tZSgoZXh0KSA9PiBsb3dlci5lbmRzV2l0aChleHQpKTtcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIGV4aXN0cyhpbnB1dFBhdGg6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGF3YWl0IHRoaXMuX2luaXQoKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5zdGF0KGlucHV0UGF0aCk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKHRoaXMuaXNOb3RGb3VuZEVycm9yKGVycm9yKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRmlsZVN5c3RlbUVycm9yICYmIGVycm9yLmNvZGUgPT09IFwiUEVSTUlTU0lPTl9ERU5JRURcIikge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICBhc3luYyBzdGF0KGlucHV0UGF0aDogc3RyaW5nKTogUHJvbWlzZTxGaWxlU3RhdD4ge1xuICAgIGF3YWl0IHRoaXMuX2luaXQoKTtcbiAgICBjb25zdCBuYW1lc3BhY2VQYXRoID0gdGhpcy5ub3JtYWxpemVQYXRoKGlucHV0UGF0aCk7XG4gICAgY29uc3QgcmVzb2x2ZWRQYXRoID0gYXdhaXQgdGhpcy5yZXNvbHZlTmFtZXNwYWNlRm9yKG5hbWVzcGFjZVBhdGgpO1xuICAgIGNvbnN0IGVudHJ5ID0gYXdhaXQgdGhpcy5ndWFyZChyZXNvbHZlZFBhdGgsICgpID0+IHRoaXMuc3RhdEF0KHJlc29sdmVkUGF0aCkpO1xuICAgIHJldHVybiB7XG4gICAgICAuLi5lbnRyeSxcbiAgICAgIHBhdGg6IHRoaXMudG9SZWxhdGl2ZVBhdGgobmFtZXNwYWNlUGF0aCksXG4gICAgfTtcbiAgfVxufVxuIl19
|