@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.
@@ -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