@dbx-tools/appkit-mastra 0.3.44 → 0.4.1
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/lib/index.d.ts +71 -0
- package/lib/index.js +56 -0
- package/lib/src/agents.d.ts +347 -0
- package/lib/src/agents.js +554 -0
- package/lib/src/chart.d.ts +192 -0
- package/lib/src/chart.js +638 -0
- package/lib/src/config.d.ts +479 -0
- package/lib/src/config.js +190 -0
- package/lib/src/defaults.d.ts +68 -0
- package/lib/src/defaults.js +107 -0
- package/lib/src/filesystems.d.ts +208 -0
- package/lib/src/filesystems.js +958 -0
- package/lib/src/genie.d.ts +166 -0
- package/lib/src/genie.js +969 -0
- package/lib/src/history.d.ts +97 -0
- package/lib/src/history.js +264 -0
- package/lib/src/mcp.d.ts +66 -0
- package/lib/src/mcp.js +65 -0
- package/lib/src/memory.d.ts +111 -0
- package/lib/src/memory.js +275 -0
- package/lib/src/mlflow.d.ts +63 -0
- package/lib/src/mlflow.js +117 -0
- package/lib/src/model.d.ts +62 -0
- package/lib/src/model.js +168 -0
- package/lib/src/observability.d.ts +81 -0
- package/lib/src/observability.js +98 -0
- package/lib/src/pagination.d.ts +23 -0
- package/lib/src/pagination.js +31 -0
- package/lib/src/plugin.d.ts +352 -0
- package/lib/src/plugin.js +1015 -0
- package/lib/src/processors.d.ts +62 -0
- package/lib/src/processors.js +162 -0
- package/lib/src/rest.d.ts +36 -0
- package/lib/src/rest.js +46 -0
- package/lib/src/server.d.ts +155 -0
- package/lib/src/server.js +336 -0
- package/lib/src/serving-sanitize.d.ts +104 -0
- package/lib/src/serving-sanitize.js +228 -0
- package/lib/src/serving.d.ts +61 -0
- package/lib/src/serving.js +78 -0
- package/lib/src/statement.d.ts +51 -0
- package/lib/src/statement.js +83 -0
- package/lib/src/storage-schema.d.ts +14 -0
- package/lib/src/storage-schema.js +34 -0
- package/lib/src/summarize.d.ts +70 -0
- package/lib/src/summarize.js +142 -0
- package/lib/src/threads.d.ts +109 -0
- package/lib/src/threads.js +301 -0
- package/lib/src/validation.d.ts +19 -0
- package/lib/src/validation.js +17 -0
- package/lib/src/workspaces.d.ts +68 -0
- package/lib/src/workspaces.js +246 -0
- package/lib/src/writer.d.ts +25 -0
- package/lib/src/writer.js +40 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +17 -13
|
@@ -0,0 +1,958 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mastra {@link WorkspaceFilesystem} implementations for Databricks Apps.
|
|
3
|
+
*
|
|
4
|
+
* {@link DatabricksWorkspaceFilesystem} maps a Mastra workspace namespace onto
|
|
5
|
+
* an absolute Databricks path (Unity Catalog volume, workspace object tree, or
|
|
6
|
+
* DBFS). {@link emptyFilesystem} is a read-only no-op mount used when no
|
|
7
|
+
* dynamic mounts resolve for a request.
|
|
8
|
+
*
|
|
9
|
+
* Path helpers ({@link normalizeDatabricksBasePath}, {@link isDbfsPath}, …)
|
|
10
|
+
* are exported for tests and callers that need to reason about Databricks
|
|
11
|
+
* paths without constructing a filesystem.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { posix as path } from "node:path";
|
|
16
|
+
import { ExecutionError, getExecutionContext, ValidationError } from "@databricks/appkit";
|
|
17
|
+
import { error, functionModule, hash, log } from "@dbx-tools/shared-core";
|
|
18
|
+
import { DirectoryNotEmptyError, DirectoryNotFoundError, FileExistsError, FileNotFoundError, IsDirectoryError, MastraFilesystem, NotDirectoryError, PermissionError, WorkspaceReadOnlyError, } from "@mastra/core/workspace";
|
|
19
|
+
/* ------------------------------ constants ------------------------------ */
|
|
20
|
+
const DBFS_READ_CHUNK_BYTES = 1024 * 1024;
|
|
21
|
+
const DBFS_PUT_MAX_BYTES = 1024 * 1024;
|
|
22
|
+
const EMPTY_FILESYSTEM_EPOCH = new Date(0);
|
|
23
|
+
/** Mastra error constructor for a known SDK filesystem failure, if any. */
|
|
24
|
+
function filesystemSdkErrorType(err) {
|
|
25
|
+
if (err) {
|
|
26
|
+
const ctx = error.errorContext(err);
|
|
27
|
+
if (ctx.notAccessible) {
|
|
28
|
+
return FileNotFoundError;
|
|
29
|
+
}
|
|
30
|
+
else if (ctx.hasMessage("already", "exists")) {
|
|
31
|
+
return FileExistsError;
|
|
32
|
+
}
|
|
33
|
+
else if (ctx.hasMessage("not", "directory")) {
|
|
34
|
+
return NotDirectoryError;
|
|
35
|
+
}
|
|
36
|
+
else if (ctx.hasMessage("not", "file")) {
|
|
37
|
+
return IsDirectoryError;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
const logger = log.logger("mastra/filesystems");
|
|
43
|
+
/* ------------------------- exported path helpers ------------------------- */
|
|
44
|
+
/** Normalize a Databricks base path (POSIX, no trailing slash). */
|
|
45
|
+
export function normalizeDatabricksBasePath(basePath) {
|
|
46
|
+
const trimmed = basePath.trim();
|
|
47
|
+
if (!trimmed.startsWith("/")) {
|
|
48
|
+
throw ValidationError.invalidValue("basePath", basePath, "an absolute Databricks path, e.g. /Volumes/catalog/schema/volume");
|
|
49
|
+
}
|
|
50
|
+
return trimmed.replace(/\/+$/, "") || "/";
|
|
51
|
+
}
|
|
52
|
+
/** True when `absolutePath` is served by DBFS rather than the UC Files API. */
|
|
53
|
+
export function isDbfsPath(absolutePath) {
|
|
54
|
+
return absolutePath === "/dbfs" || absolutePath.startsWith("/dbfs/");
|
|
55
|
+
}
|
|
56
|
+
/** True when `absolutePath` is a Databricks workspace object path. */
|
|
57
|
+
export function isWorkspaceFilesPath(absolutePath) {
|
|
58
|
+
return (absolutePath === "/Workspace" ||
|
|
59
|
+
absolutePath.startsWith("/Workspace/") ||
|
|
60
|
+
absolutePath.startsWith("/Users/") ||
|
|
61
|
+
absolutePath.startsWith("/Repos/"));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a workspace-relative path to an absolute Databricks path under
|
|
65
|
+
* `basePath`.
|
|
66
|
+
*/
|
|
67
|
+
export function resolveDatabricksAbsolutePath(basePath, inputPath) {
|
|
68
|
+
const root = normalizeDatabricksBasePath(basePath);
|
|
69
|
+
const trimmed = inputPath.trim();
|
|
70
|
+
if (!trimmed || trimmed === "/")
|
|
71
|
+
return root;
|
|
72
|
+
const normalized = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
73
|
+
if (normalized === root || normalized.startsWith(`${root}/`)) {
|
|
74
|
+
return path.normalize(normalized);
|
|
75
|
+
}
|
|
76
|
+
return path.normalize(path.join(root, normalized));
|
|
77
|
+
}
|
|
78
|
+
/** Map an absolute Databricks path back to the workspace namespace. */
|
|
79
|
+
export function toDatabricksWorkspacePath(basePath, absolutePath) {
|
|
80
|
+
const root = normalizeDatabricksBasePath(basePath);
|
|
81
|
+
const normalized = path.normalize(absolutePath);
|
|
82
|
+
if (normalized === root)
|
|
83
|
+
return "/";
|
|
84
|
+
if (normalized.startsWith(`${root}/`)) {
|
|
85
|
+
return normalized.slice(root.length) || "/";
|
|
86
|
+
}
|
|
87
|
+
return normalized;
|
|
88
|
+
}
|
|
89
|
+
/* ---------------------------- private helpers ---------------------------- */
|
|
90
|
+
/** Pick the Databricks Files API backend for an absolute path. */
|
|
91
|
+
function resolveFilesBackend(absolutePath) {
|
|
92
|
+
if (isDbfsPath(absolutePath))
|
|
93
|
+
return "dbfs";
|
|
94
|
+
if (isWorkspaceFilesPath(absolutePath))
|
|
95
|
+
return "workspace";
|
|
96
|
+
return "uc-files";
|
|
97
|
+
}
|
|
98
|
+
/** Run the handler that matches `absolutePath`'s Databricks backend. */
|
|
99
|
+
async function dispatchFilesBackend(absolutePath, handlers) {
|
|
100
|
+
const backend = resolveFilesBackend(absolutePath);
|
|
101
|
+
if (backend === "dbfs")
|
|
102
|
+
return handlers.dbfs();
|
|
103
|
+
if (backend === "workspace")
|
|
104
|
+
return handlers.workspace();
|
|
105
|
+
return handlers.ucFiles();
|
|
106
|
+
}
|
|
107
|
+
/** Return `buffer` as a string when `encoding` is set, otherwise unchanged. */
|
|
108
|
+
function formatReadResult(buffer, encoding) {
|
|
109
|
+
return encoding ? buffer.toString(encoding) : buffer;
|
|
110
|
+
}
|
|
111
|
+
/** Drain a fetch `ReadableStream` into a single `Buffer`. */
|
|
112
|
+
async function readResponseBody(contents) {
|
|
113
|
+
if (!contents)
|
|
114
|
+
return Buffer.alloc(0);
|
|
115
|
+
const reader = contents.getReader();
|
|
116
|
+
const chunks = [];
|
|
117
|
+
while (true) {
|
|
118
|
+
const { done, value } = await reader.read();
|
|
119
|
+
if (done)
|
|
120
|
+
break;
|
|
121
|
+
if (value)
|
|
122
|
+
chunks.push(value);
|
|
123
|
+
}
|
|
124
|
+
return Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)));
|
|
125
|
+
}
|
|
126
|
+
/** Coerce Mastra {@link FileContent} to a `Buffer`. */
|
|
127
|
+
function toBuffer(content) {
|
|
128
|
+
if (typeof content === "string")
|
|
129
|
+
return Buffer.from(content, "utf8");
|
|
130
|
+
return Buffer.from(content);
|
|
131
|
+
}
|
|
132
|
+
/** Decode a DBFS read payload from base64. */
|
|
133
|
+
function decodeDbfsPayload(data) {
|
|
134
|
+
if (!data)
|
|
135
|
+
return Buffer.alloc(0);
|
|
136
|
+
return Buffer.from(data, "base64");
|
|
137
|
+
}
|
|
138
|
+
/** Wrap a `Buffer` as a one-shot `ReadableStream` for UC file uploads. */
|
|
139
|
+
function bufferToReadableStream(buffer) {
|
|
140
|
+
return new ReadableStream({
|
|
141
|
+
start(controller) {
|
|
142
|
+
controller.enqueue(new Uint8Array(buffer));
|
|
143
|
+
controller.close();
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/** Parse an HTTP date header; returns epoch when missing or invalid. */
|
|
148
|
+
function parseHttpDate(value) {
|
|
149
|
+
if (!value)
|
|
150
|
+
return new Date(0);
|
|
151
|
+
const parsed = Date.parse(value);
|
|
152
|
+
return Number.isFinite(parsed) ? new Date(parsed) : new Date(0);
|
|
153
|
+
}
|
|
154
|
+
/* ---------------- DatabricksWorkspaceFilesystem ---------------- */
|
|
155
|
+
/**
|
|
156
|
+
* Mastra filesystem provider that reads and writes through a Databricks
|
|
157
|
+
* {@link WorkspaceClient}.
|
|
158
|
+
*
|
|
159
|
+
* Workspace paths are absolute within the namespace (`/notes.md` maps to
|
|
160
|
+
* `<basePath>/notes.md`). Unity Catalog volumes use the Files API;
|
|
161
|
+
* `/dbfs/...` paths use DBFS.
|
|
162
|
+
*/
|
|
163
|
+
export class DatabricksWorkspaceFilesystem extends MastraFilesystem {
|
|
164
|
+
id;
|
|
165
|
+
name = "DatabricksWorkspaceFilesystem";
|
|
166
|
+
provider = "databricks";
|
|
167
|
+
basePath;
|
|
168
|
+
status = "pending";
|
|
169
|
+
client;
|
|
170
|
+
mkdirs;
|
|
171
|
+
_readOnly;
|
|
172
|
+
_basePathMissing;
|
|
173
|
+
get readOnly() {
|
|
174
|
+
return this._readOnly;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* @param options.client - Defaults to the AppKit execution-context client.
|
|
178
|
+
* @param options.mkdirs - Default `"try"`; see {@link DatabricksMkdirsMode}.
|
|
179
|
+
* @param options.readOnly - When omitted, {@link init} probes write access.
|
|
180
|
+
*/
|
|
181
|
+
constructor(options) {
|
|
182
|
+
super({ name: "DatabricksWorkspaceFilesystem", ...options });
|
|
183
|
+
this.id = options.id ?? `databricks-fs-${hash.fnvHash(options.basePath)}`;
|
|
184
|
+
this.client = options.client ?? getExecutionContext().client;
|
|
185
|
+
this.basePath = normalizeDatabricksBasePath(options.basePath);
|
|
186
|
+
this.mkdirs = options.mkdirs ?? "try";
|
|
187
|
+
this._readOnly = options.readOnly;
|
|
188
|
+
}
|
|
189
|
+
/* --- path resolution --- */
|
|
190
|
+
/** Resolve and sandbox a workspace-relative path under {@link basePath}. */
|
|
191
|
+
resolvePath(inputPath) {
|
|
192
|
+
const resolved = resolveDatabricksAbsolutePath(this.basePath, inputPath);
|
|
193
|
+
if (resolved !== this.basePath && !resolved.startsWith(`${this.basePath}/`)) {
|
|
194
|
+
throw new PermissionError(inputPath, "access");
|
|
195
|
+
}
|
|
196
|
+
return resolved;
|
|
197
|
+
}
|
|
198
|
+
/** Map a Databricks absolute path back to the workspace namespace. */
|
|
199
|
+
workspacePath(absolutePath) {
|
|
200
|
+
return toDatabricksWorkspacePath(this.basePath, absolutePath);
|
|
201
|
+
}
|
|
202
|
+
/** Throw when the filesystem is read-only. */
|
|
203
|
+
assertWritable(operation) {
|
|
204
|
+
if (this.readOnly) {
|
|
205
|
+
throw new WorkspaceReadOnlyError(operation);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/** Map SDK / HTTP errors to Mastra workspace filesystem errors. */
|
|
209
|
+
rethrow(err, inputPath) {
|
|
210
|
+
const workspacePath = inputPath.startsWith("/")
|
|
211
|
+
? inputPath
|
|
212
|
+
: this.workspacePath(this.resolvePath(inputPath));
|
|
213
|
+
const ErrorType = filesystemSdkErrorType(err);
|
|
214
|
+
if (ErrorType) {
|
|
215
|
+
throw new ErrorType(workspacePath);
|
|
216
|
+
}
|
|
217
|
+
// The upstream message is logged rather than raised: it reaches the model
|
|
218
|
+
// (and from there the chat transcript) as the tool's failure text.
|
|
219
|
+
logger.warn("operation-failed", {
|
|
220
|
+
path: workspacePath,
|
|
221
|
+
error: error.errorMessage(err),
|
|
222
|
+
});
|
|
223
|
+
throw new ExecutionError(`Databricks filesystem operation failed for ${workspacePath}`, {
|
|
224
|
+
cause: error.toError(err),
|
|
225
|
+
context: { path: workspacePath },
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
/* --- lifecycle --- */
|
|
229
|
+
/**
|
|
230
|
+
* Probe whether {@link basePath} exists and cache the result on
|
|
231
|
+
* {@link _basePathMissing}.
|
|
232
|
+
*/
|
|
233
|
+
async resolveBasePathStatus() {
|
|
234
|
+
if (this._basePathMissing !== undefined)
|
|
235
|
+
return;
|
|
236
|
+
try {
|
|
237
|
+
await this.assertAbsoluteReadable(this.basePath);
|
|
238
|
+
this._basePathMissing = false;
|
|
239
|
+
}
|
|
240
|
+
catch (err) {
|
|
241
|
+
if (error.errorContext(err).notAccessible) {
|
|
242
|
+
this._basePathMissing = true;
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
this.rethrow(err, "/");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/** Delegate to {@link emptyFilesystem} when the base path is missing. */
|
|
249
|
+
async emptyFallback() {
|
|
250
|
+
await this.resolveBasePathStatus();
|
|
251
|
+
return this._basePathMissing ? emptyFilesystem() : undefined;
|
|
252
|
+
}
|
|
253
|
+
async init() {
|
|
254
|
+
await this.resolveBasePathStatus();
|
|
255
|
+
if (this._basePathMissing) {
|
|
256
|
+
if (this.mkdirs === false) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
await this.mkdirAbsolute(this.basePath);
|
|
261
|
+
this._basePathMissing = false;
|
|
262
|
+
if (this._readOnly === undefined) {
|
|
263
|
+
this._readOnly = false;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
catch (err) {
|
|
267
|
+
if (this.mkdirs === true) {
|
|
268
|
+
this.rethrow(err, "/");
|
|
269
|
+
}
|
|
270
|
+
logger.debug("mkdirs:try-failed", {
|
|
271
|
+
basePath: this.basePath,
|
|
272
|
+
error: error.errorMessage(err),
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (this._readOnly === undefined) {
|
|
278
|
+
await this.probeReadOnly();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Write and delete a ephemeral probe file to detect read-only access when
|
|
283
|
+
* {@link DatabricksWorkspaceFilesystemOptions.readOnly} was not set.
|
|
284
|
+
*
|
|
285
|
+
* @returns `true` when the probe write (and cleanup) succeeded.
|
|
286
|
+
*/
|
|
287
|
+
async probeReadOnly() {
|
|
288
|
+
const absolutePath = this.resolvePath(`/.__dbx_fs_probe_${hash.id()}`);
|
|
289
|
+
try {
|
|
290
|
+
await this.writeAbsolute(absolutePath, Buffer.from("probe\n"), true);
|
|
291
|
+
this._readOnly = false;
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
this._readOnly = true;
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
await this.deleteAbsoluteFile(absolutePath);
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
// Writable; leave a hidden probe file rather than failing init.
|
|
302
|
+
}
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
async destroy() {
|
|
306
|
+
// Remote filesystem; nothing to tear down locally.
|
|
307
|
+
}
|
|
308
|
+
/* --- backend I/O --- */
|
|
309
|
+
/** Probe that `absolutePath` exists (file or directory metadata). */
|
|
310
|
+
async assertAbsoluteReadable(absolutePath) {
|
|
311
|
+
await dispatchFilesBackend(absolutePath, {
|
|
312
|
+
dbfs: () => this.client.dbfs.getStatus({ path: absolutePath }),
|
|
313
|
+
workspace: () => this.client.workspace.getStatus({ path: absolutePath }),
|
|
314
|
+
ucFiles: () => this.client.files.getDirectoryMetadata({ directory_path: absolutePath }),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
/** Read the full contents of `absolutePath` from the matching backend. */
|
|
318
|
+
async readAbsolute(absolutePath) {
|
|
319
|
+
return dispatchFilesBackend(absolutePath, {
|
|
320
|
+
dbfs: () => this.readDbfsFile(absolutePath),
|
|
321
|
+
workspace: () => this.readWorkspaceFile(absolutePath),
|
|
322
|
+
ucFiles: async () => {
|
|
323
|
+
const response = await this.client.files.download({ file_path: absolutePath });
|
|
324
|
+
return readResponseBody(response.contents);
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
/** Write `buffer` to `absolutePath` on the matching backend. */
|
|
329
|
+
async writeAbsolute(absolutePath, buffer, overwrite) {
|
|
330
|
+
await dispatchFilesBackend(absolutePath, {
|
|
331
|
+
dbfs: () => this.writeDbfsFile(absolutePath, buffer, overwrite),
|
|
332
|
+
workspace: () => this.writeWorkspaceFile(absolutePath, buffer, overwrite),
|
|
333
|
+
ucFiles: () => this.uploadUcFile(absolutePath, buffer, overwrite),
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
/** Upload a buffer to a Unity Catalog Files API path. */
|
|
337
|
+
uploadUcFile(absolutePath, buffer, overwrite) {
|
|
338
|
+
return this.client.files.upload({
|
|
339
|
+
file_path: absolutePath,
|
|
340
|
+
contents: bufferToReadableStream(buffer),
|
|
341
|
+
overwrite,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
/** Delete a single file at `absolutePath` (non-recursive). */
|
|
345
|
+
async deleteAbsoluteFile(absolutePath) {
|
|
346
|
+
await dispatchFilesBackend(absolutePath, {
|
|
347
|
+
dbfs: () => this.client.dbfs.delete({ path: absolutePath, recursive: false }),
|
|
348
|
+
workspace: () => this.client.workspace.delete({ path: absolutePath, recursive: false }),
|
|
349
|
+
ucFiles: () => this.client.files.delete({ file_path: absolutePath }),
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Delete a file or directory at `absolutePath`.
|
|
354
|
+
*
|
|
355
|
+
* DBFS and workspace APIs accept `recursive`; UC volumes recurse manually.
|
|
356
|
+
*/
|
|
357
|
+
async deleteAbsolutePath(absolutePath, recursive) {
|
|
358
|
+
await dispatchFilesBackend(absolutePath, {
|
|
359
|
+
dbfs: async () => {
|
|
360
|
+
await this.client.dbfs.delete({ path: absolutePath, recursive });
|
|
361
|
+
},
|
|
362
|
+
workspace: async () => {
|
|
363
|
+
await this.client.workspace.delete({ path: absolutePath, recursive });
|
|
364
|
+
},
|
|
365
|
+
ucFiles: async () => {
|
|
366
|
+
if (recursive) {
|
|
367
|
+
await this.deleteUcDirectoryRecursive(absolutePath);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const children = await this.listAbsoluteDirectory(absolutePath);
|
|
371
|
+
if (children.length > 0) {
|
|
372
|
+
throw new DirectoryNotEmptyError(this.workspacePath(absolutePath));
|
|
373
|
+
}
|
|
374
|
+
await this.client.files.deleteDirectory({ directory_path: absolutePath });
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
/** Create `absolutePath` and any missing parents on the matching backend. */
|
|
379
|
+
async mkdirAbsolute(absolutePath) {
|
|
380
|
+
await dispatchFilesBackend(absolutePath, {
|
|
381
|
+
dbfs: () => this.client.dbfs.mkdirs({ path: absolutePath }),
|
|
382
|
+
workspace: () => this.client.workspace.mkdirs({ path: absolutePath }),
|
|
383
|
+
ucFiles: () => this.client.files.createDirectory({ directory_path: absolutePath }),
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
async readDbfsFile(absolutePath) {
|
|
387
|
+
const chunks = [];
|
|
388
|
+
let offset = 0;
|
|
389
|
+
while (true) {
|
|
390
|
+
const response = await this.client.dbfs.read({
|
|
391
|
+
path: absolutePath,
|
|
392
|
+
offset,
|
|
393
|
+
length: DBFS_READ_CHUNK_BYTES,
|
|
394
|
+
});
|
|
395
|
+
const chunk = decodeDbfsPayload(response.data);
|
|
396
|
+
if (chunk.length === 0)
|
|
397
|
+
break;
|
|
398
|
+
chunks.push(chunk);
|
|
399
|
+
offset += chunk.length;
|
|
400
|
+
if (chunk.length < DBFS_READ_CHUNK_BYTES)
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
return Buffer.concat(chunks);
|
|
404
|
+
}
|
|
405
|
+
async readWorkspaceFile(absolutePath) {
|
|
406
|
+
const response = await this.client.workspace.export({
|
|
407
|
+
path: absolutePath,
|
|
408
|
+
format: "AUTO",
|
|
409
|
+
});
|
|
410
|
+
return decodeDbfsPayload(response.content);
|
|
411
|
+
}
|
|
412
|
+
async writeDbfsFile(absolutePath, buffer, overwrite) {
|
|
413
|
+
if (buffer.length <= DBFS_PUT_MAX_BYTES) {
|
|
414
|
+
await this.client.dbfs.put({
|
|
415
|
+
path: absolutePath,
|
|
416
|
+
contents: buffer.toString("base64"),
|
|
417
|
+
overwrite,
|
|
418
|
+
});
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const created = await this.client.dbfs.create({ path: absolutePath, overwrite });
|
|
422
|
+
const handle = created.handle;
|
|
423
|
+
if (handle === undefined) {
|
|
424
|
+
throw ExecutionError.missingData("DBFS upload handle");
|
|
425
|
+
}
|
|
426
|
+
for (let offset = 0; offset < buffer.length; offset += DBFS_PUT_MAX_BYTES) {
|
|
427
|
+
const slice = buffer.subarray(offset, offset + DBFS_PUT_MAX_BYTES);
|
|
428
|
+
await this.client.dbfs.addBlock({
|
|
429
|
+
handle,
|
|
430
|
+
data: slice.toString("base64"),
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
await this.client.dbfs.close({ handle });
|
|
434
|
+
}
|
|
435
|
+
async writeWorkspaceFile(absolutePath, buffer, overwrite) {
|
|
436
|
+
await this.client.workspace.import({
|
|
437
|
+
path: absolutePath,
|
|
438
|
+
format: "AUTO",
|
|
439
|
+
content: buffer.toString("base64"),
|
|
440
|
+
overwrite,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
/* --- MastraFilesystem API --- */
|
|
444
|
+
getInfo() {
|
|
445
|
+
return {
|
|
446
|
+
id: this.id,
|
|
447
|
+
name: this.name,
|
|
448
|
+
provider: this.provider,
|
|
449
|
+
status: this.status,
|
|
450
|
+
readOnly: this.readOnly,
|
|
451
|
+
metadata: { basePath: this.basePath },
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
getInstructions() {
|
|
455
|
+
return [
|
|
456
|
+
`Files live in Databricks under ${this.basePath}.`,
|
|
457
|
+
"Workspace paths are absolute within this root (for example `/notes/report.md`).",
|
|
458
|
+
"Workspace paths use `/Workspace/...`, `/Users/...`, or `/Repos/...` base paths.",
|
|
459
|
+
"Unity Catalog volumes use `/Volumes/<catalog>/<schema>/<volume>/...` base paths.",
|
|
460
|
+
].join(" ");
|
|
461
|
+
}
|
|
462
|
+
/** Map a workspace-relative path to the backing Databricks absolute path. */
|
|
463
|
+
resolveAbsolutePath(inputPath) {
|
|
464
|
+
return this.resolvePath(inputPath);
|
|
465
|
+
}
|
|
466
|
+
/** Read file contents from the workspace namespace. */
|
|
467
|
+
async readFile(inputPath, options) {
|
|
468
|
+
await this.ensureReady();
|
|
469
|
+
const empty = await this.emptyFallback();
|
|
470
|
+
if (empty)
|
|
471
|
+
return empty.readFile(inputPath, options);
|
|
472
|
+
const absolutePath = this.resolvePath(inputPath);
|
|
473
|
+
try {
|
|
474
|
+
const buffer = await this.readAbsolute(absolutePath);
|
|
475
|
+
return formatReadResult(buffer, options?.encoding);
|
|
476
|
+
}
|
|
477
|
+
catch (err) {
|
|
478
|
+
this.rethrow(err, inputPath);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
/** Write file contents into the workspace namespace. */
|
|
482
|
+
async writeFile(inputPath, content, options) {
|
|
483
|
+
await this.ensureReady();
|
|
484
|
+
const empty = await this.emptyFallback();
|
|
485
|
+
if (empty)
|
|
486
|
+
return empty.writeFile(inputPath, content, options);
|
|
487
|
+
this.assertWritable("writeFile");
|
|
488
|
+
const absolutePath = this.resolvePath(inputPath);
|
|
489
|
+
const buffer = toBuffer(content);
|
|
490
|
+
const overwrite = options?.overwrite ?? true;
|
|
491
|
+
try {
|
|
492
|
+
if (!overwrite && (await this.exists(inputPath))) {
|
|
493
|
+
throw new FileExistsError(inputPath);
|
|
494
|
+
}
|
|
495
|
+
await this.writeAbsolute(absolutePath, buffer, overwrite);
|
|
496
|
+
}
|
|
497
|
+
catch (err) {
|
|
498
|
+
if (err instanceof FileExistsError)
|
|
499
|
+
throw err;
|
|
500
|
+
this.rethrow(err, inputPath);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
/** Append to an existing file, creating it when missing. */
|
|
504
|
+
async appendFile(inputPath, content) {
|
|
505
|
+
await this.ensureReady();
|
|
506
|
+
const empty = await this.emptyFallback();
|
|
507
|
+
if (empty)
|
|
508
|
+
return empty.appendFile(inputPath, content);
|
|
509
|
+
this.assertWritable("appendFile");
|
|
510
|
+
const existing = (await this.exists(inputPath))
|
|
511
|
+
? await this.readFile(inputPath)
|
|
512
|
+
: Buffer.alloc(0);
|
|
513
|
+
const merged = Buffer.concat([
|
|
514
|
+
Buffer.isBuffer(existing) ? existing : Buffer.from(existing, "utf8"),
|
|
515
|
+
toBuffer(content),
|
|
516
|
+
]);
|
|
517
|
+
await this.writeFile(inputPath, merged, { overwrite: true });
|
|
518
|
+
}
|
|
519
|
+
/** Delete a file in the workspace namespace. */
|
|
520
|
+
async deleteFile(inputPath, options) {
|
|
521
|
+
await this.ensureReady();
|
|
522
|
+
const empty = await this.emptyFallback();
|
|
523
|
+
if (empty)
|
|
524
|
+
return empty.deleteFile(inputPath, options);
|
|
525
|
+
this.assertWritable("deleteFile");
|
|
526
|
+
const absolutePath = this.resolvePath(inputPath);
|
|
527
|
+
try {
|
|
528
|
+
if (!(await this.exists(inputPath))) {
|
|
529
|
+
if (options?.force)
|
|
530
|
+
return;
|
|
531
|
+
throw new FileNotFoundError(inputPath);
|
|
532
|
+
}
|
|
533
|
+
const entry = await this.stat(inputPath);
|
|
534
|
+
if (entry.type === "directory") {
|
|
535
|
+
throw new IsDirectoryError(inputPath);
|
|
536
|
+
}
|
|
537
|
+
await this.deleteAbsoluteFile(absolutePath);
|
|
538
|
+
}
|
|
539
|
+
catch (err) {
|
|
540
|
+
if (err instanceof FileNotFoundError || err instanceof IsDirectoryError)
|
|
541
|
+
throw err;
|
|
542
|
+
this.rethrow(err, inputPath);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
/** Copy a file within the workspace namespace. */
|
|
546
|
+
async copyFile(src, dest, options) {
|
|
547
|
+
await this.ensureReady();
|
|
548
|
+
const empty = await this.emptyFallback();
|
|
549
|
+
if (empty)
|
|
550
|
+
return empty.copyFile(src, dest, options);
|
|
551
|
+
this.assertWritable("copyFile");
|
|
552
|
+
const overwrite = options?.overwrite ?? true;
|
|
553
|
+
if (!overwrite && (await this.exists(dest))) {
|
|
554
|
+
throw new FileExistsError(dest);
|
|
555
|
+
}
|
|
556
|
+
const content = await this.readFile(src);
|
|
557
|
+
await this.writeFile(dest, content, { overwrite: true });
|
|
558
|
+
}
|
|
559
|
+
/** Move or rename a file within the workspace namespace. */
|
|
560
|
+
async moveFile(src, dest, options) {
|
|
561
|
+
await this.ensureReady();
|
|
562
|
+
const empty = await this.emptyFallback();
|
|
563
|
+
if (empty)
|
|
564
|
+
return empty.moveFile(src, dest, options);
|
|
565
|
+
this.assertWritable("moveFile");
|
|
566
|
+
const srcAbsolute = this.resolvePath(src);
|
|
567
|
+
const destAbsolute = this.resolvePath(dest);
|
|
568
|
+
const overwrite = options?.overwrite ?? true;
|
|
569
|
+
try {
|
|
570
|
+
if (!overwrite && (await this.exists(dest))) {
|
|
571
|
+
throw new FileExistsError(dest);
|
|
572
|
+
}
|
|
573
|
+
if (resolveFilesBackend(srcAbsolute) === "dbfs" &&
|
|
574
|
+
resolveFilesBackend(destAbsolute) === "dbfs") {
|
|
575
|
+
await this.client.dbfs.move({
|
|
576
|
+
source_path: srcAbsolute,
|
|
577
|
+
destination_path: destAbsolute,
|
|
578
|
+
});
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
await this.copyFile(src, dest, { overwrite: true });
|
|
582
|
+
await this.deleteFile(src, { force: true });
|
|
583
|
+
}
|
|
584
|
+
catch (err) {
|
|
585
|
+
if (err instanceof FileExistsError)
|
|
586
|
+
throw err;
|
|
587
|
+
this.rethrow(err, dest);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
/** Create a directory in the workspace namespace. */
|
|
591
|
+
async mkdir(inputPath, options) {
|
|
592
|
+
await this.ensureReady();
|
|
593
|
+
const empty = await this.emptyFallback();
|
|
594
|
+
if (empty)
|
|
595
|
+
return empty.mkdir(inputPath, options);
|
|
596
|
+
this.assertWritable("mkdir");
|
|
597
|
+
const absolutePath = this.resolvePath(inputPath);
|
|
598
|
+
try {
|
|
599
|
+
await this.mkdirAbsolute(absolutePath);
|
|
600
|
+
if (!options?.recursive) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
catch (err) {
|
|
605
|
+
this.rethrow(err, inputPath);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
/** Remove a directory from the workspace namespace. */
|
|
609
|
+
async rmdir(inputPath, options) {
|
|
610
|
+
await this.ensureReady();
|
|
611
|
+
const empty = await this.emptyFallback();
|
|
612
|
+
if (empty)
|
|
613
|
+
return empty.rmdir(inputPath, options);
|
|
614
|
+
this.assertWritable("rmdir");
|
|
615
|
+
const absolutePath = this.resolvePath(inputPath);
|
|
616
|
+
try {
|
|
617
|
+
if (!(await this.exists(inputPath))) {
|
|
618
|
+
if (options?.force)
|
|
619
|
+
return;
|
|
620
|
+
throw new DirectoryNotFoundError(inputPath);
|
|
621
|
+
}
|
|
622
|
+
const entry = await this.stat(inputPath);
|
|
623
|
+
if (entry.type !== "directory") {
|
|
624
|
+
throw new NotDirectoryError(inputPath);
|
|
625
|
+
}
|
|
626
|
+
await this.deleteAbsolutePath(absolutePath, options?.recursive ?? false);
|
|
627
|
+
}
|
|
628
|
+
catch (err) {
|
|
629
|
+
if (err instanceof DirectoryNotFoundError ||
|
|
630
|
+
err instanceof NotDirectoryError ||
|
|
631
|
+
err instanceof DirectoryNotEmptyError) {
|
|
632
|
+
throw err;
|
|
633
|
+
}
|
|
634
|
+
this.rethrow(err, inputPath);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Recursively delete a Unity Catalog directory tree.
|
|
639
|
+
*
|
|
640
|
+
* DBFS and workspace trees use native recursive delete via
|
|
641
|
+
* {@link deleteAbsolutePath} instead.
|
|
642
|
+
*/
|
|
643
|
+
async deleteUcDirectoryRecursive(absolutePath) {
|
|
644
|
+
for (const child of await this.listAbsoluteDirectory(absolutePath)) {
|
|
645
|
+
const childAbsolute = path.join(absolutePath, child.name);
|
|
646
|
+
if (child.type === "directory") {
|
|
647
|
+
await this.deleteUcDirectoryRecursive(childAbsolute);
|
|
648
|
+
}
|
|
649
|
+
else {
|
|
650
|
+
await this.deleteAbsoluteFile(childAbsolute);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
await this.client.files.deleteDirectory({ directory_path: absolutePath });
|
|
654
|
+
}
|
|
655
|
+
/* --- directory listing --- */
|
|
656
|
+
/** List entries in a workspace directory. */
|
|
657
|
+
async readdir(inputPath, options) {
|
|
658
|
+
await this.ensureReady();
|
|
659
|
+
const empty = await this.emptyFallback();
|
|
660
|
+
if (empty)
|
|
661
|
+
return empty.readdir(inputPath, options);
|
|
662
|
+
const absolutePath = this.resolvePath(inputPath);
|
|
663
|
+
try {
|
|
664
|
+
const entries = await this.listAbsoluteDirectory(absolutePath);
|
|
665
|
+
const filtered = this.filterEntries(entries, options);
|
|
666
|
+
if (!options?.recursive)
|
|
667
|
+
return filtered;
|
|
668
|
+
return await this.readDirectoryRecursive(absolutePath, options, 0);
|
|
669
|
+
}
|
|
670
|
+
catch (err) {
|
|
671
|
+
this.rethrow(err, inputPath);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
async readDirectoryRecursive(absolutePath, options, depth, relativePrefix = "") {
|
|
675
|
+
const maxDepth = options.maxDepth ?? Number.POSITIVE_INFINITY;
|
|
676
|
+
const entries = this.filterEntries(await this.listAbsoluteDirectory(absolutePath), options);
|
|
677
|
+
const collected = [];
|
|
678
|
+
for (const entry of entries) {
|
|
679
|
+
const relativeName = relativePrefix ? path.join(relativePrefix, entry.name) : entry.name;
|
|
680
|
+
collected.push({ ...entry, name: relativeName });
|
|
681
|
+
if (entry.type !== "directory" || depth >= maxDepth)
|
|
682
|
+
continue;
|
|
683
|
+
collected.push(...(await this.readDirectoryRecursive(path.join(absolutePath, entry.name), options, depth + 1, relativeName)));
|
|
684
|
+
}
|
|
685
|
+
return collected;
|
|
686
|
+
}
|
|
687
|
+
async listAbsoluteDirectory(absolutePath) {
|
|
688
|
+
return dispatchFilesBackend(absolutePath, {
|
|
689
|
+
dbfs: async () => {
|
|
690
|
+
const entries = [];
|
|
691
|
+
for await (const info of this.client.dbfs.list({ path: absolutePath })) {
|
|
692
|
+
entries.push({
|
|
693
|
+
name: path.basename(info.path ?? ""),
|
|
694
|
+
type: info.is_dir ? "directory" : "file",
|
|
695
|
+
size: info.file_size,
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
return entries;
|
|
699
|
+
},
|
|
700
|
+
workspace: async () => {
|
|
701
|
+
const entries = [];
|
|
702
|
+
for await (const info of this.client.workspace.list({ path: absolutePath })) {
|
|
703
|
+
entries.push({
|
|
704
|
+
name: path.basename(info.path ?? ""),
|
|
705
|
+
type: info.object_type === "DIRECTORY" ? "directory" : "file",
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
return entries;
|
|
709
|
+
},
|
|
710
|
+
ucFiles: async () => {
|
|
711
|
+
const entries = [];
|
|
712
|
+
for await (const entry of this.client.files.listDirectoryContents({
|
|
713
|
+
directory_path: absolutePath,
|
|
714
|
+
})) {
|
|
715
|
+
entries.push({
|
|
716
|
+
name: entry.name ?? path.basename(entry.path ?? ""),
|
|
717
|
+
type: entry.is_directory ? "directory" : "file",
|
|
718
|
+
size: entry.file_size,
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
return entries;
|
|
722
|
+
},
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
/** Apply Mastra list filters (`extension`, etc.) to directory entries. */
|
|
726
|
+
filterEntries(entries, options) {
|
|
727
|
+
if (!options?.extension)
|
|
728
|
+
return entries;
|
|
729
|
+
const extensions = Array.isArray(options.extension) ? options.extension : [options.extension];
|
|
730
|
+
const normalized = extensions.map((ext) => ext.startsWith(".") ? ext.toLowerCase() : `.${ext.toLowerCase()}`);
|
|
731
|
+
return entries.filter((entry) => {
|
|
732
|
+
if (entry.type !== "file")
|
|
733
|
+
return true;
|
|
734
|
+
const lower = entry.name.toLowerCase();
|
|
735
|
+
return normalized.some((ext) => lower.endsWith(ext));
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
/* --- metadata --- */
|
|
739
|
+
/** Return whether `inputPath` exists in the workspace namespace. */
|
|
740
|
+
async exists(inputPath) {
|
|
741
|
+
await this.ensureReady();
|
|
742
|
+
const empty = await this.emptyFallback();
|
|
743
|
+
if (empty)
|
|
744
|
+
return empty.exists(inputPath);
|
|
745
|
+
try {
|
|
746
|
+
await this.stat(inputPath);
|
|
747
|
+
return true;
|
|
748
|
+
}
|
|
749
|
+
catch (err) {
|
|
750
|
+
if (err instanceof FileNotFoundError)
|
|
751
|
+
return false;
|
|
752
|
+
throw err;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
/** Return file or directory metadata for `inputPath`. */
|
|
756
|
+
async stat(inputPath) {
|
|
757
|
+
await this.ensureReady();
|
|
758
|
+
const empty = await this.emptyFallback();
|
|
759
|
+
if (empty)
|
|
760
|
+
return empty.stat(inputPath);
|
|
761
|
+
const absolutePath = this.resolvePath(inputPath);
|
|
762
|
+
const workspacePath = this.workspacePath(absolutePath);
|
|
763
|
+
try {
|
|
764
|
+
return await dispatchFilesBackend(absolutePath, {
|
|
765
|
+
dbfs: async () => {
|
|
766
|
+
const info = await this.client.dbfs.getStatus({ path: absolutePath });
|
|
767
|
+
return {
|
|
768
|
+
name: path.basename(info.path ?? absolutePath),
|
|
769
|
+
path: workspacePath,
|
|
770
|
+
type: info.is_dir ? "directory" : "file",
|
|
771
|
+
size: info.file_size ?? 0,
|
|
772
|
+
createdAt: new Date(info.modification_time ?? 0),
|
|
773
|
+
modifiedAt: new Date(info.modification_time ?? 0),
|
|
774
|
+
};
|
|
775
|
+
},
|
|
776
|
+
workspace: async () => {
|
|
777
|
+
const info = await this.client.workspace.getStatus({ path: absolutePath });
|
|
778
|
+
return {
|
|
779
|
+
name: path.basename(info.path ?? absolutePath),
|
|
780
|
+
path: workspacePath,
|
|
781
|
+
type: info.object_type === "DIRECTORY" ? "directory" : "file",
|
|
782
|
+
size: 0,
|
|
783
|
+
createdAt: new Date(info.created_at ?? 0),
|
|
784
|
+
modifiedAt: new Date(info.modified_at ?? 0),
|
|
785
|
+
};
|
|
786
|
+
},
|
|
787
|
+
ucFiles: () => this.statUcAbsolute(absolutePath, workspacePath, inputPath),
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
catch (err) {
|
|
791
|
+
this.rethrow(err, inputPath);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Stat a Unity Catalog path by probing file metadata first, then
|
|
796
|
+
* directory metadata.
|
|
797
|
+
*/
|
|
798
|
+
async statUcAbsolute(absolutePath, workspacePath, inputPath) {
|
|
799
|
+
try {
|
|
800
|
+
const metadata = await this.client.files.getMetadata({
|
|
801
|
+
file_path: absolutePath,
|
|
802
|
+
});
|
|
803
|
+
return {
|
|
804
|
+
name: path.basename(absolutePath),
|
|
805
|
+
path: workspacePath,
|
|
806
|
+
type: "file",
|
|
807
|
+
size: Number(metadata["content-length"] ?? 0),
|
|
808
|
+
createdAt: parseHttpDate(metadata["last-modified"]),
|
|
809
|
+
modifiedAt: parseHttpDate(metadata["last-modified"]),
|
|
810
|
+
mimeType: metadata["content-type"],
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
catch (fileErr) {
|
|
814
|
+
if (!error.errorContext(fileErr).notAccessible) {
|
|
815
|
+
this.rethrow(fileErr, inputPath);
|
|
816
|
+
}
|
|
817
|
+
await this.client.files.getDirectoryMetadata({
|
|
818
|
+
directory_path: absolutePath,
|
|
819
|
+
});
|
|
820
|
+
return {
|
|
821
|
+
name: path.basename(absolutePath),
|
|
822
|
+
path: workspacePath,
|
|
823
|
+
type: "directory",
|
|
824
|
+
size: 0,
|
|
825
|
+
createdAt: new Date(0),
|
|
826
|
+
modifiedAt: new Date(0),
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
/* --------------------------- empty filesystem --------------------------- */
|
|
832
|
+
/** Normalize paths for the in-memory empty filesystem namespace. */
|
|
833
|
+
function normalizeEmptyFilesystemPath(inputPath) {
|
|
834
|
+
const trimmed = inputPath.trim();
|
|
835
|
+
if (!trimmed || trimmed === ".")
|
|
836
|
+
return "/";
|
|
837
|
+
const normalized = trimmed.startsWith("/")
|
|
838
|
+
? path.normalize(trimmed)
|
|
839
|
+
: path.normalize(`/${trimmed}`);
|
|
840
|
+
return normalized === "." ? "/" : normalized;
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Read-only in-memory {@link WorkspaceFilesystem} with a single empty root.
|
|
844
|
+
* Use {@link emptyFilesystem} rather than constructing directly.
|
|
845
|
+
*/
|
|
846
|
+
class EmptyFilesystem extends MastraFilesystem {
|
|
847
|
+
id = "empty-fs";
|
|
848
|
+
name = "EmptyFilesystem";
|
|
849
|
+
provider = "empty";
|
|
850
|
+
readOnly = true;
|
|
851
|
+
status = "pending";
|
|
852
|
+
constructor() {
|
|
853
|
+
super({ name: "EmptyFilesystem" });
|
|
854
|
+
}
|
|
855
|
+
async init() {
|
|
856
|
+
// No remote or on-disk resources to provision.
|
|
857
|
+
}
|
|
858
|
+
async destroy() {
|
|
859
|
+
// Stateless; nothing to release.
|
|
860
|
+
}
|
|
861
|
+
getInfo() {
|
|
862
|
+
return {
|
|
863
|
+
id: this.id,
|
|
864
|
+
name: this.name,
|
|
865
|
+
provider: this.provider,
|
|
866
|
+
status: this.status,
|
|
867
|
+
readOnly: this.readOnly,
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
getInstructions() {
|
|
871
|
+
return "This filesystem is empty and read-only.";
|
|
872
|
+
}
|
|
873
|
+
rootStat() {
|
|
874
|
+
return {
|
|
875
|
+
name: "/",
|
|
876
|
+
path: "/",
|
|
877
|
+
type: "directory",
|
|
878
|
+
size: 0,
|
|
879
|
+
createdAt: EMPTY_FILESYSTEM_EPOCH,
|
|
880
|
+
modifiedAt: EMPTY_FILESYSTEM_EPOCH,
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
assertWritable(operation) {
|
|
884
|
+
throw new WorkspaceReadOnlyError(operation);
|
|
885
|
+
}
|
|
886
|
+
async readFile(inputPath, _options) {
|
|
887
|
+
await this.ensureReady();
|
|
888
|
+
const normalized = normalizeEmptyFilesystemPath(inputPath);
|
|
889
|
+
if (normalized === "/") {
|
|
890
|
+
throw new IsDirectoryError(normalized);
|
|
891
|
+
}
|
|
892
|
+
throw new FileNotFoundError(normalized);
|
|
893
|
+
}
|
|
894
|
+
async writeFile(_inputPath, _content, _options) {
|
|
895
|
+
await this.ensureReady();
|
|
896
|
+
this.assertWritable("writeFile");
|
|
897
|
+
}
|
|
898
|
+
async appendFile(_inputPath, _content) {
|
|
899
|
+
await this.ensureReady();
|
|
900
|
+
this.assertWritable("appendFile");
|
|
901
|
+
}
|
|
902
|
+
async deleteFile(inputPath, options) {
|
|
903
|
+
await this.ensureReady();
|
|
904
|
+
const normalized = normalizeEmptyFilesystemPath(inputPath);
|
|
905
|
+
if (normalized === "/") {
|
|
906
|
+
throw new IsDirectoryError(normalized);
|
|
907
|
+
}
|
|
908
|
+
if (options?.force)
|
|
909
|
+
return;
|
|
910
|
+
throw new FileNotFoundError(normalized);
|
|
911
|
+
}
|
|
912
|
+
async copyFile(src, _dest, _options) {
|
|
913
|
+
await this.ensureReady();
|
|
914
|
+
const normalizedSrc = normalizeEmptyFilesystemPath(src);
|
|
915
|
+
if (normalizedSrc !== "/") {
|
|
916
|
+
throw new FileNotFoundError(normalizedSrc);
|
|
917
|
+
}
|
|
918
|
+
throw new IsDirectoryError(normalizedSrc);
|
|
919
|
+
}
|
|
920
|
+
async moveFile(src, dest, options) {
|
|
921
|
+
await this.copyFile(src, dest, options);
|
|
922
|
+
}
|
|
923
|
+
async mkdir(_inputPath, _options) {
|
|
924
|
+
await this.ensureReady();
|
|
925
|
+
this.assertWritable("mkdir");
|
|
926
|
+
}
|
|
927
|
+
async rmdir(inputPath, options) {
|
|
928
|
+
await this.ensureReady();
|
|
929
|
+
const normalized = normalizeEmptyFilesystemPath(inputPath);
|
|
930
|
+
if (normalized === "/") {
|
|
931
|
+
throw new DirectoryNotEmptyError(normalized);
|
|
932
|
+
}
|
|
933
|
+
if (options?.force)
|
|
934
|
+
return;
|
|
935
|
+
throw new DirectoryNotFoundError(normalized);
|
|
936
|
+
}
|
|
937
|
+
async readdir(inputPath, _options) {
|
|
938
|
+
await this.ensureReady();
|
|
939
|
+
const normalized = normalizeEmptyFilesystemPath(inputPath);
|
|
940
|
+
if (normalized === "/")
|
|
941
|
+
return [];
|
|
942
|
+
throw new DirectoryNotFoundError(normalized);
|
|
943
|
+
}
|
|
944
|
+
async exists(inputPath) {
|
|
945
|
+
await this.ensureReady();
|
|
946
|
+
return normalizeEmptyFilesystemPath(inputPath) === "/";
|
|
947
|
+
}
|
|
948
|
+
async stat(inputPath) {
|
|
949
|
+
await this.ensureReady();
|
|
950
|
+
const normalized = normalizeEmptyFilesystemPath(inputPath);
|
|
951
|
+
if (normalized === "/")
|
|
952
|
+
return this.rootStat();
|
|
953
|
+
throw new FileNotFoundError(normalized);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
/** Memoized singleton empty read-only filesystem for no-op mounts. */
|
|
957
|
+
export const emptyFilesystem = functionModule.memoize(() => new EmptyFilesystem());
|
|
958
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZXN5c3RlbXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmlsZXN5c3RlbXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUVILE9BQU8sRUFBRSxLQUFLLElBQUksSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQzFDLE9BQU8sRUFBRSxjQUFjLEVBQUUsbUJBQW1CLEVBQUUsZUFBZSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFMUYsT0FBTyxFQUFFLEtBQUssRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzFFLE9BQU8sRUFDTCxzQkFBc0IsRUFDdEIsc0JBQXNCLEVBQ3RCLGVBQWUsRUFDZixpQkFBaUIsRUFDakIsZ0JBQWdCLEVBQ2hCLGdCQUFnQixFQUNoQixpQkFBaUIsRUFDakIsZUFBZSxFQUNmLHNCQUFzQixHQUN2QixNQUFNLHdCQUF3QixDQUFDO0FBZWhDLDZFQUE2RTtBQUU3RSxNQUFNLHFCQUFxQixHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFDMUMsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBQ3ZDLE1BQU0sc0JBQXNCLEdBQUcsSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFFM0MsMkVBQTJFO0FBQzNFLFNBQVMsc0JBQXNCLENBQUMsR0FBWTtJQUMxQyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ1IsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNwQyxJQUFJLEdBQUcsQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUN0QixPQUFPLGlCQUFpQixDQUFDO1FBQzNCLENBQUM7YUFBTSxJQUFJLEdBQUcsQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDL0MsT0FBTyxlQUFlLENBQUM7UUFDekIs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QztRQUMvQyxNQUFNLElBQUksaUJBQWlCLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDMUMsQ0FBQztDQUNGO0FBRUQsc0VBQXNFO0FBQ3RFLE1BQU0sQ0FBQyxNQUFNLGVBQWUsR0FBRyxjQUFjLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksZUFBZSxFQUFFLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTWFzdHJhIHtAbGluayBXb3Jrc3BhY2VGaWxlc3lzdGVtfSBpbXBsZW1lbnRhdGlvbnMgZm9yIERhdGFicmlja3MgQXBwcy5cbiAqXG4gKiB7QGxpbmsgRGF0YWJyaWNrc1dvcmtzcGFjZUZpbGVzeXN0ZW19IG1hcHMgYSBNYXN0cmEgd29ya3NwYWNlIG5hbWVzcGFjZSBvbnRvXG4gKiBhbiBhYnNvbHV0ZSBEYXRhYnJpY2tzIHBhdGggKFVuaXR5IENhdGFsb2cgdm9sdW1lLCB3b3Jrc3BhY2Ugb2JqZWN0IHRyZWUsIG9yXG4gKiBEQkZTKS4ge0BsaW5rIGVtcHR5RmlsZXN5c3RlbX0gaXMgYSByZWFkLW9ubHkgbm8tb3AgbW91bnQgdXNlZCB3aGVuIG5vXG4gKiBkeW5hbWljIG1vdW50cyByZXNvbHZlIGZvciBhIHJlcXVlc3QuXG4gKlxuICogUGF0aCBoZWxwZXJzICh7QGxpbmsgbm9ybWFsaXplRGF0YWJyaWNrc0Jhc2VQYXRofSwge0BsaW5rIGlzRGJmc1BhdGh9LCDigKYpXG4gKiBhcmUgZXhwb3J0ZWQgZm9yIHRlc3RzIGFuZCBjYWxsZXJzIHRoYXQgbmVlZCB0byByZWFzb24gYWJvdXQgRGF0YWJyaWNrc1xuICogcGF0aHMgd2l0aG91dCBjb25zdHJ1Y3RpbmcgYSBmaWxlc3lzdGVtLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBwb3NpeCBhcyBwYXRoIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgRXhlY3V0aW9uRXJyb3IsIGdldEV4ZWN1dGlvbkNvbnRleHQsIFZhbGlkYXRpb25FcnJvciB9IGZyb20gXCJAZGF0YWJyaWNrcy9hcHBraXRcIjtcbmltcG9ydCB7IFdvcmtzcGFjZUNsaWVudCB9IGZyb20gXCJAZGF0YWJyaWNrcy9zZGstZXhwZXJpbWVudGFsXCI7XG5pbXBvcnQgeyBlcnJvciwgZnVuY3Rpb25Nb2R1bGUsIGhhc2gsIGxvZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQge1xuICBEaXJlY3RvcnlOb3RFbXB0eUVycm9yLFxuICBEaXJlY3RvcnlOb3RGb3VuZEVycm9yLFxuICBGaWxlRXhpc3RzRXJyb3IsXG4gIEZpbGVOb3RGb3VuZEVycm9yLFxuICBJc0RpcmVjdG9yeUVycm9yLFxuICBNYXN0cmFGaWxlc3lzdGVtLFxuICBOb3REaXJlY3RvcnlFcnJvcixcbiAgUGVybWlzc2lvbkVycm9yLFxuICBXb3Jrc3BhY2VSZWFkT25seUVycm9yLFxufSBmcm9tIFwiQG1hc3RyYS9jb3JlL3dvcmtzcGFjZVwiO1xuaW1wb3J0IHR5cGUge1xuICBDb3B5T3B0aW9ucyxcbiAgRmlsZUNvbnRlbnQsXG4gIEZpbGVFbnRyeSxcbiAgRmlsZVN0YXQsXG4gIEZpbGVzeXN0ZW1JbmZvLFxuICBMaXN0T3B0aW9ucyxcbiAgTWFzdHJhRmlsZXN5c3RlbU9wdGlvbnMsXG4gIFByb3ZpZGVyU3RhdHVzLFxuICBSZWFkT3B0aW9ucyxcbiAgUmVtb3ZlT3B0aW9ucyxcbiAgV3JpdGVPcHRpb25zLFxufSBmcm9tIFwiQG1hc3RyYS9jb3JlL3dvcmtzcGFjZVwiO1xuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gY29uc3RhbnRzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG5jb25zdCBEQkZTX1JFQURfQ0hVTktfQllURVMgPSAxMDI0ICogMTAyNDtcbmNvbnN0IERCRlNfUFVUX01BWF9CWVRFUyA9IDEwMjQgKiAxMDI0O1xuY29uc3QgRU1QVFlfRklMRVNZU1RFTV9FUE9DSCA9IG5ldyBEYXRlKDApO1xuXG4vKiogTWFzdHJhIGVycm9yIGNvbnN0cnVjdG9yIGZvciBhIGtub3duIFNESyBmaWxlc3lzdGVtIGZhaWx1cmUsIGlmIGFueS4gKi9cbmZ1bmN0aW9uIGZpbGVzeXN0ZW1TZGtFcnJvclR5cGUoZXJyOiB1bmtub3duKTogKG5ldyAocGF0aDogc3RyaW5nKSA9PiBFcnJvcikgfCB1bmRlZmluZWQge1xuICBpZiAoZXJyKSB7XG4gICAgY29uc3QgY3R4ID0gZXJyb3IuZXJyb3JDb250ZXh0KGVycik7XG4gICAgaWYgKGN0eC5ub3RBY2Nlc3NpYmxlKSB7XG4gICAgICByZXR1cm4gRmlsZU5vdEZvdW5kRXJyb3I7XG4gICAgfSBlbHNlIGlmIChjdHguaGFzTWVzc2FnZShcImFscmVhZHlcIiwgXCJleGlzdHNcIikpIHtcbiAgICAgIHJldHVybiBGaWxlRXhpc3RzRXJyb3I7XG4gICAgfSBlbHNlIGlmIChjdHguaGFzTWVzc2FnZShcIm5vdFwiLCBcImRpcmVjdG9yeVwiKSkge1xuICAgICAgcmV0dXJuIE5vdERpcmVjdG9yeUVycm9yO1xuICAgIH0gZWxzZSBpZiAoY3R4Lmhhc01lc3NhZ2UoXCJub3RcIiwgXCJmaWxlXCIpKSB7XG4gICAgICByZXR1cm4gSXNEaXJlY3RvcnlFcnJvcjtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuY29uc3QgbG9nZ2VyID0gbG9nLmxvZ2dlcihcIm1hc3RyYS9maWxlc3lzdGVtc1wiKTtcblxuLyoqIEhvdyB7QGxpbmsgRGF0YWJyaWNrc1dvcmtzcGFjZUZpbGVzeXN0ZW0uaW5pdH0gaGFuZGxlcyBhIG1pc3Npbmcge0BsaW5rIGJhc2VQYXRofS4gKi9cbmV4cG9ydCB0eXBlIERhdGFicmlja3NNa2RpcnNNb2RlID0gYm9vbGVhbiB8IFwidHJ5XCI7XG5cbi8qKiBPcHRpb25zIGZvciB7QGxpbmsgRGF0YWJyaWNrc1dvcmtzcGFjZUZpbGVzeXN0ZW19LiAqL1xuZXhwb3J0IGludGVyZmFjZSBEYXRhYnJpY2tzV29ya3NwYWNlRmlsZXN5c3RlbU9wdGlvbnMgZXh0ZW5kcyBNYXN0cmFGaWxlc3lzdGVtT3B0aW9ucyB7XG4gIC8qKiBVbmlxdWUgaWRlbnRpZmllciBmb3IgdGhpcyBmaWxlc3lzdGVtIGluc3RhbmNlLiAqL1xuICBpZD86IHN0cmluZztcbiAgLyoqIEF1dGgtc2NvcGVkIERhdGFicmlja3Mgd29ya3NwYWNlIGNsaWVudC4gKi9cbiAgY2xpZW50PzogV29ya3NwYWNlQ2xpZW50O1xuICAvKipcbiAgICogQWJzb2x1dGUgRGF0YWJyaWNrcyBwYXRoIHRoYXQgcm9vdHMgdGhlIHdvcmtzcGFjZSBuYW1lc3BhY2UsIGUuZy5cbiAgICogYC9Wb2x1bWVzL2NhdGFsb2cvc2NoZW1hL3ZvbHVtZWAgb3IgYC9kYmZzL0ZpbGVTdG9yZS9zaGFyZWRgLlxuICAgKi9cbiAgYmFzZVBhdGg6IHN0cmluZztcbiAgLyoqXG4gICAqIFdoZW4gdGhlIHtAbGluayBiYXNlUGF0aH0gaXMgbWlzc2luZyBhdCB7QGxpbmsgaW5pdH0sIGNyZWF0ZSBpdCB3aXRoIHRoZVxuICAgKiBtYXRjaGluZyBEYXRhYnJpY2tzIGBta2RpcnNgIEFQSS4gYFwidHJ5XCJgIChkZWZhdWx0KSBsb2dzIGF0IGRlYnVnIGFuZFxuICAgKiBmYWxscyBiYWNrIHRvIGFuIGVtcHR5IHJlYWQtb25seSBuYW1lc3BhY2Ugb24gZmFpbHVyZTsgYHRydWVgIGZhaWxzIGluaXQ7XG4gICAqIGBmYWxzZWAgc2tpcHMgY3JlYXRpb24gYW5kIHVzZXMgdGhlIGVtcHR5IG5hbWVzcGFjZS5cbiAgICpcbiAgICogQSBzdWNjZXNzZnVsIG1rZGlyIGFsc28gc2F0aXNmaWVzIHRoZSB3cml0ZS1hY2Nlc3MgcHJvYmUgd2hlblxuICAgKiB7QGxpbmsgcmVhZE9ubHl9IGlzIG9taXR0ZWQuXG4gICAqL1xuICBta2RpcnM/OiBEYXRhYnJpY2tzTWtkaXJzTW9kZTtcbiAgLyoqIEJsb2NrIHdyaXRlcyB3aGlsZSBzdGlsbCBhbGxvd2luZyByZWFkcy4gV2hlbiBvbWl0dGVkLCB7QGxpbmsgaW5pdH0gcHJvYmVzIHdyaXRlIGFjY2Vzcy4gKi9cbiAgcmVhZE9ubHk/OiBib29sZWFuO1xufVxuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIGV4cG9ydGVkIHBhdGggaGVscGVycyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbi8qKiBOb3JtYWxpemUgYSBEYXRhYnJpY2tzIGJhc2UgcGF0aCAoUE9TSVgsIG5vIHRyYWlsaW5nIHNsYXNoKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVEYXRhYnJpY2tzQmFzZVBhdGgoYmFzZVBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHRyaW1tZWQgPSBiYXNlUGF0aC50cmltKCk7XG4gIGlmICghdHJpbW1lZC5zdGFydHNXaXRoKFwiL1wiKSkge1xuICAgIHRocm93IFZhbGlkYXRpb25FcnJvci5pbnZhbGlkVmFsdWUoXG4gICAgICBcImJhc2VQYXRoXCIsXG4gICAgICBiYXNlUGF0aCxcbiAgICAgIFwiYW4gYWJzb2x1dGUgRGF0YWJyaWNrcyBwYXRoLCBlLmcuIC9Wb2x1bWVzL2NhdGFsb2cvc2NoZW1hL3ZvbHVtZVwiLFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIHRyaW1tZWQucmVwbGFjZSgvXFwvKyQvLCBcIlwiKSB8fCBcIi9cIjtcbn1cblxuLyoqIFRydWUgd2hlbiBgYWJzb2x1dGVQYXRoYCBpcyBzZXJ2ZWQgYnkgREJGUyByYXRoZXIgdGhhbiB0aGUgVUMgRmlsZXMgQVBJLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzRGJmc1BhdGgoYWJzb2x1dGVQYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIGFic29sdXRlUGF0aCA9PT0gXCIvZGJmc1wiIHx8IGFic29sdXRlUGF0aC5zdGFydHNXaXRoKFwiL2RiZnMvXCIpO1xufVxuXG4vKiogVHJ1ZSB3aGVuIGBhYnNvbHV0ZVBhdGhgIGlzIGEgRGF0YWJyaWNrcyB3b3Jrc3BhY2Ugb2JqZWN0IHBhdGguICovXG5leHBvcnQgZnVuY3Rpb24gaXNXb3Jrc3BhY2VGaWxlc1BhdGgoYWJzb2x1dGVQYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIChcbiAgICBhYnNvbHV0ZVBhdGggPT09IFwiL1dvcmtzcGFjZVwiIHx8XG4gICAgYWJzb2x1dGVQYXRoLnN0YXJ0c1dpdGgoXCIvV29ya3NwYWNlL1wiKSB8fFxuICAgIGFic29sdXRlUGF0aC5zdGFydHNXaXRoKFwiL1VzZXJzL1wiKSB8fFxuICAgIGFic29sdXRlUGF0aC5zdGFydHNXaXRoKFwiL1JlcG9zL1wiKVxuICApO1xufVxuXG50eXBlIEZpbGVzQmFja2VuZCA9IFwiZGJmc1wiIHwgXCJ3b3Jrc3BhY2VcIiB8IFwidWMtZmlsZXNcIjtcblxuLyoqIFBlci1iYWNrZW5kIGFzeW5jIGhhbmRsZXIgdXNlZCBieSB7QGxpbmsgZGlzcGF0Y2hGaWxlc0JhY2tlbmR9LiAqL1xudHlwZSBGaWxlc0JhY2tlbmRIYW5kbGVyczxUID0gdW5rbm93bj4gPSB7XG4gIGRiZnM6ICgpID0+IFByb21pc2U8VD47XG4gIHdvcmtzcGFjZTogKCkgPT4gUHJvbWlzZTxUPjtcbiAgdWNGaWxlczogKCkgPT4gUHJvbWlzZTxUPjtcbn07XG5cbi8qKlxuICogUmVzb2x2ZSBhIHdvcmtzcGFjZS1yZWxhdGl2ZSBwYXRoIHRvIGFuIGFic29sdXRlIERhdGFicmlja3MgcGF0aCB1bmRlclxuICogYGJhc2VQYXRoYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVEYXRhYnJpY2tzQWJzb2x1dGVQYXRoKGJhc2VQYXRoOiBzdHJpbmcsIGlucHV0UGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3Qgcm9vdCA9IG5vcm1hbGl6ZURhdGFicmlja3NCYXNlUGF0aChiYXNlUGF0aCk7XG4gIGNvbnN0IHRyaW1tZWQgPSBpbnB1dFBhdGgudHJpbSgpO1xuICBpZiAoIXRyaW1tZWQgfHwgdHJpbW1lZCA9PT0gXCIvXCIpIHJldHVybiByb290O1xuICBjb25zdCBub3JtYWxpemVkID0gdHJpbW1lZC5zdGFydHNXaXRoKFwiL1wiKSA/IHRyaW1tZWQgOiBgLyR7dHJpbW1lZH1gO1xuICBpZiAobm9ybWFsaXplZCA9PT0gcm9vdCB8fCBub3JtYWxpemVkLnN0YXJ0c1dpdGgoYCR7cm9vdH0vYCkpIHtcbiAgICByZXR1cm4gcGF0aC5ub3JtYWxpemUobm9ybWFsaXplZCk7XG4gIH1cbiAgcmV0dXJuIHBhdGgubm9ybWFsaXplKHBhdGguam9pbihyb290LCBub3JtYWxpemVkKSk7XG59XG5cbi8qKiBNYXAgYW4gYWJzb2x1dGUgRGF0YWJyaWNrcyBwYXRoIGJhY2sgdG8gdGhlIHdvcmtzcGFjZSBuYW1lc3BhY2UuICovXG5leHBvcnQgZnVuY3Rpb24gdG9EYXRhYnJpY2tzV29ya3NwYWNlUGF0aChiYXNlUGF0aDogc3RyaW5nLCBhYnNvbHV0ZVBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHJvb3QgPSBub3JtYWxpemVEYXRhYnJpY2tzQmFzZVBhdGgoYmFzZVBhdGgpO1xuICBjb25zdCBub3JtYWxpemVkID0gcGF0aC5ub3JtYWxpemUoYWJzb2x1dGVQYXRoKTtcbiAgaWYgKG5vcm1hbGl6ZWQgPT09IHJvb3QpIHJldHVybiBcIi9cIjtcbiAgaWYgKG5vcm1hbGl6ZWQuc3RhcnRzV2l0aChgJHtyb290fS9gKSkge1xuICAgIHJldHVybiBub3JtYWxpemVkLnNsaWNlKHJvb3QubGVuZ3RoKSB8fCBcIi9cIjtcbiAgfVxuICByZXR1cm4gbm9ybWFsaXplZDtcbn1cblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBwcml2YXRlIGhlbHBlcnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKiogUGljayB0aGUgRGF0YWJyaWNrcyBGaWxlcyBBUEkgYmFja2VuZCBmb3IgYW4gYWJzb2x1dGUgcGF0aC4gKi9cbmZ1bmN0aW9uIHJlc29sdmVGaWxlc0JhY2tlbmQoYWJzb2x1dGVQYXRoOiBzdHJpbmcpOiBGaWxlc0JhY2tlbmQge1xuICBpZiAoaXNEYmZzUGF0aChhYnNvbHV0ZVBhdGgpKSByZXR1cm4gXCJkYmZzXCI7XG4gIGlmIChpc1dvcmtzcGFjZUZpbGVzUGF0aChhYnNvbHV0ZVBhdGgpKSByZXR1cm4gXCJ3b3Jrc3BhY2VcIjtcbiAgcmV0dXJuIFwidWMtZmlsZXNcIjtcbn1cblxuLyoqIFJ1biB0aGUgaGFuZGxlciB0aGF0IG1hdGNoZXMgYGFic29sdXRlUGF0aGAncyBEYXRhYnJpY2tzIGJhY2tlbmQuICovXG5hc3luYyBmdW5jdGlvbiBkaXNwYXRjaEZpbGVzQmFja2VuZDxUPihcbiAgYWJzb2x1dGVQYXRoOiBzdHJpbmcsXG4gIGhhbmRsZXJzOiBGaWxlc0JhY2tlbmRIYW5kbGVyczxUPixcbik6IFByb21pc2U8VD4ge1xuICBjb25zdCBiYWNrZW5kID0gcmVzb2x2ZUZpbGVzQmFja2VuZChhYnNvbHV0ZVBhdGgpO1xuICBpZiAoYmFja2VuZCA9PT0gXCJkYmZzXCIpIHJldHVybiBoYW5kbGVycy5kYmZzKCk7XG4gIGlmIChiYWNrZW5kID09PSBcIndvcmtzcGFjZVwiKSByZXR1cm4gaGFuZGxlcnMud29ya3NwYWNlKCk7XG4gIHJldHVybiBoYW5kbGVycy51Y0ZpbGVzKCk7XG59XG5cbi8qKiBSZXR1cm4gYGJ1ZmZlcmAgYXMgYSBzdHJpbmcgd2hlbiBgZW5jb2RpbmdgIGlzIHNldCwgb3RoZXJ3aXNlIHVuY2hhbmdlZC4gKi9cbmZ1bmN0aW9uIGZvcm1hdFJlYWRSZXN1bHQoYnVmZmVyOiBCdWZmZXIsIGVuY29kaW5nPzogQnVmZmVyRW5jb2RpbmcpOiBzdHJpbmcgfCBCdWZmZXIge1xuICByZXR1cm4gZW5jb2RpbmcgPyBidWZmZXIudG9TdHJpbmcoZW5jb2RpbmcpIDogYnVmZmVyO1xufVxuXG4vKiogRHJhaW4gYSBmZXRjaCBgUmVhZGFibGVTdHJlYW1gIGludG8gYSBzaW5nbGUgYEJ1ZmZlcmAuICovXG5hc3luYyBmdW5jdGlvbiByZWFkUmVzcG9uc2VCb2R5KFxuICBjb250ZW50czogZ2xvYmFsVGhpcy5SZWFkYWJsZVN0cmVhbTxVaW50OEFycmF5PiB8IHVuZGVmaW5lZCxcbik6IFByb21pc2U8QnVmZmVyPiB7XG4gIGlmICghY29udGVudHMpIHJldHVybiBCdWZmZXIuYWxsb2MoMCk7XG4gIGNvbnN0IHJlYWRlciA9IGNvbnRlbnRzLmdldFJlYWRlcigpO1xuICBjb25zdCBjaHVua3M6IFVpbnQ4QXJyYXlbXSA9IFtdO1xuICB3aGlsZSAodHJ1ZSkge1xuICAgIGNvbnN0IHsgZG9uZSwgdmFsdWUgfSA9IGF3YWl0IHJlYWRlci5yZWFkKCk7XG4gICAgaWYgKGRvbmUpIGJyZWFrO1xuICAgIGlmICh2YWx1ZSkgY2h1bmtzLnB1c2godmFsdWUpO1xuICB9XG4gIHJldHVybiBCdWZmZXIuY29uY2F0KGNodW5rcy5tYXAoKGNodW5rKSA9PiBCdWZmZXIuZnJvbShjaHVuaykpKTtcbn1cblxuLyoqIENvZXJjZSBNYXN0cmEge0BsaW5rIEZpbGVDb250ZW50fSB0byBhIGBCdWZmZXJgLiAqL1xuZnVuY3Rpb24gdG9CdWZmZXIoY29udGVudDogRmlsZUNvbnRlbnQpOiBCdWZmZXIge1xuICBpZiAodHlwZW9mIGNvbnRlbnQgPT09IFwic3RyaW5nXCIpIHJldHVybiBCdWZmZXIuZnJvbShjb250ZW50LCBcInV0ZjhcIik7XG4gIHJldHVybiBCdWZmZXIuZnJvbShjb250ZW50KTtcbn1cblxuLyoqIERlY29kZSBhIERCRlMgcmVhZCBwYXlsb2FkIGZyb20gYmFzZTY0LiAqL1xuZnVuY3Rpb24gZGVjb2RlRGJmc1BheWxvYWQoZGF0YTogc3RyaW5nIHwgdW5kZWZpbmVkKTogQnVmZmVyIHtcbiAgaWYgKCFkYXRhKSByZXR1cm4gQnVmZmVyLmFsbG9jKDApO1xuICByZXR1cm4gQnVmZmVyLmZyb20oZGF0YSwgXCJiYXNlNjRcIik7XG59XG5cbi8qKiBXcmFwIGEgYEJ1ZmZlcmAgYXMgYSBvbmUtc2hvdCBgUmVhZGFibGVTdHJlYW1gIGZvciBVQyBmaWxlIHVwbG9hZHMuICovXG5mdW5jdGlvbiBidWZmZXJUb1JlYWRhYmxlU3RyZWFtKGJ1ZmZlcjogQnVmZmVyKTogZ2xvYmFsVGhpcy5SZWFkYWJsZVN0cmVhbTxVaW50OEFycmF5PiB7XG4gIHJldHVybiBuZXcgUmVhZGFibGVTdHJlYW08VWludDhBcnJheT4oe1xuICAgIHN0YXJ0KGNvbnRyb2xsZXIpIHtcbiAgICAgIGNvbnRyb2xsZXIuZW5xdWV1ZShuZXcgVWludDhBcnJheShidWZmZXIpKTtcbiAgICAgIGNvbnRyb2xsZXIuY2xvc2UoKTtcbiAgICB9LFxuICB9KTtcbn1cblxuLyoqIFBhcnNlIGFuIEhUVFAgZGF0ZSBoZWFkZXI7IHJldHVybnMgZXBvY2ggd2hlbiBtaXNzaW5nIG9yIGludmFsaWQuICovXG5mdW5jdGlvbiBwYXJzZUh0dHBEYXRlKHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBEYXRlIHtcbiAgaWYgKCF2YWx1ZSkgcmV0dXJuIG5ldyBEYXRlKDApO1xuICBjb25zdCBwYXJzZWQgPSBEYXRlLnBhcnNlKHZhbHVlKTtcbiAgcmV0dXJuIE51bWJlci5pc0Zpbml0ZShwYXJzZWQpID8gbmV3IERhdGUocGFyc2VkKSA6IG5ldyBEYXRlKDApO1xufVxuXG4vKiAtLS0tLS0tLS0tLS0tLS0tIERhdGFicmlja3NXb3Jrc3BhY2VGaWxlc3lzdGVtIC0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqXG4gKiBNYXN0cmEgZmlsZXN5c3RlbSBwcm92aWRlciB0aGF0IHJlYWRzIGFuZCB3cml0ZXMgdGhyb3VnaCBhIERhdGFicmlja3NcbiAqIHtAbGluayBXb3Jrc3BhY2VDbGllbnR9LlxuICpcbiAqIFdvcmtzcGFjZSBwYXRocyBhcmUgYWJzb2x1dGUgd2l0aGluIHRoZSBuYW1lc3BhY2UgKGAvbm90ZXMubWRgIG1hcHMgdG9cbiAqIGA8YmFzZVBhdGg+L25vdGVzLm1kYCkuIFVuaXR5IENhdGFsb2cgdm9sdW1lcyB1c2UgdGhlIEZpbGVzIEFQSTtcbiAqIGAvZGJmcy8uLi5gIHBhdGhzIHVzZSBEQkZTLlxuICovXG5leHBvcnQgY2xhc3MgRGF0YWJyaWNrc1dvcmtzcGFjZUZpbGVzeXN0ZW0gZXh0ZW5kcyBNYXN0cmFGaWxlc3lzdGVtIHtcbiAgcmVhZG9ubHkgaWQ6IHN0cmluZztcbiAgcmVhZG9ubHkgbmFtZSA9IFwiRGF0YWJyaWNrc1dvcmtzcGFjZUZpbGVzeXN0ZW1cIjtcbiAgcmVhZG9ubHkgcHJvdmlkZXIgPSBcImRhdGFicmlja3NcIjtcbiAgcmVhZG9ubHkgYmFzZVBhdGg6IHN0cmluZztcbiAgc3RhdHVzOiBQcm92aWRlclN0YXR1cyA9IFwicGVuZGluZ1wiO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgbWtkaXJzOiBEYXRhYnJpY2tzTWtkaXJzTW9kZTtcbiAgcHJpdmF0ZSBfcmVhZE9ubHk6IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgX2Jhc2VQYXRoTWlzc2luZzogYm9vbGVhbiB8IHVuZGVmaW5lZDtcblxuICBnZXQgcmVhZE9ubHkoKTogYm9vbGVhbiB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuX3JlYWRPbmx5O1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSBvcHRpb25zLmNsaWVudCAtIERlZmF1bHRzIHRvIHRoZSBBcHBLaXQgZXhlY3V0aW9uLWNvbnRleHQgY2xpZW50LlxuICAgKiBAcGFyYW0gb3B0aW9ucy5ta2RpcnMgLSBEZWZhdWx0IGBcInRyeVwiYDsgc2VlIHtAbGluayBEYXRhYnJpY2tzTWtkaXJzTW9kZX0uXG4gICAqIEBwYXJhbSBvcHRpb25zLnJlYWRPbmx5IC0gV2hlbiBvbWl0dGVkLCB7QGxpbmsgaW5pdH0gcHJvYmVzIHdyaXRlIGFjY2Vzcy5cbiAgICovXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IERhdGFicmlja3NXb3Jrc3BhY2VGaWxlc3lzdGVtT3B0aW9ucykge1xuICAgIHN1cGVyKHsgbmFtZTogXCJEYXRhYnJpY2tzV29ya3NwYWNlRmlsZXN5c3RlbVwiLCAuLi5vcHRpb25zIH0pO1xuICAgIHRoaXMuaWQgPSBvcHRpb25zLmlkID8/IGBkYXRhYnJpY2tzLWZzLSR7aGFzaC5mbnZIYXNoKG9wdGlvbnMuYmFzZVBhdGgpfWA7XG4gICAgdGhpcy5jbGllbnQgPSBvcHRpb25zLmNsaWVudCA/PyBnZXRFeGVjdXRpb25Db250ZXh0KCkuY2xpZW50O1xuICAgIHRoaXMuYmFzZVBhdGggPSBub3JtYWxpemVEYXRhYnJpY2tzQmFzZVBhdGgob3B0aW9ucy5iYXNlUGF0aCk7XG4gICAgdGhpcy5ta2RpcnMgPSBvcHRpb25zLm1rZGlycyA/PyBcInRyeVwiO1xuICAgIHRoaXMuX3JlYWRPbmx5ID0gb3B0aW9ucy5yZWFkT25seTtcbiAgfVxuXG4gIC8qIC0tLSBwYXRoIHJlc29sdXRpb24gLS0tICovXG5cbiAgLyoqIFJlc29sdmUgYW5kIHNhbmRib3ggYSB3b3Jrc3BhY2UtcmVsYXRpdmUgcGF0aCB1bmRlciB7QGxpbmsgYmFzZVBhdGh9LiAqL1xuICBwcml2YXRlIHJlc29sdmVQYXRoKGlucHV0UGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCByZXNvbHZlZCA9IHJlc29sdmVEYXRhYnJpY2tzQWJzb2x1dGVQYXRoKHRoaXMuYmFzZVBhdGgsIGlucHV0UGF0aCk7XG4gICAgaWYgKHJlc29sdmVkICE9PSB0aGlzLmJhc2VQYXRoICYmICFyZXNvbHZlZC5zdGFydHNXaXRoKGAke3RoaXMuYmFzZVBhdGh9L2ApKSB7XG4gICAgICB0aHJvdyBuZXcgUGVybWlzc2lvbkVycm9yKGlucHV0UGF0aCwgXCJhY2Nlc3NcIik7XG4gICAgfVxuICAgIHJldHVybiByZXNvbHZlZDtcbiAgfVxuXG4gIC8qKiBNYXAgYSBEYXRhYnJpY2tzIGFic29sdXRlIHBhdGggYmFjayB0byB0aGUgd29ya3NwYWNlIG5hbWVzcGFjZS4gKi9cbiAgcHJpdmF0ZSB3b3Jrc3BhY2VQYXRoKGFic29sdXRlUGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdG9EYXRhYnJpY2tzV29ya3NwYWNlUGF0aCh0aGlzLmJhc2VQYXRoLCBhYnNvbHV0ZVBhdGgpO1xuICB9XG5cbiAgLyoqIFRocm93IHdoZW4gdGhlIGZpbGVzeXN0ZW0gaXMgcmVhZC1vbmx5LiAqL1xuICBwcml2YXRlIGFzc2VydFdyaXRhYmxlKG9wZXJhdGlvbjogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKHRoaXMucmVhZE9ubHkpIHtcbiAgICAgIHRocm93IG5ldyBXb3Jrc3BhY2VSZWFkT25seUVycm9yKG9wZXJhdGlvbik7XG4gICAgfVxuICB9XG5cbiAgLyoqIE1hcCBTREsgLyBIVFRQIGVycm9ycyB0byBNYXN0cmEgd29ya3NwYWNlIGZpbGVzeXN0ZW0gZXJyb3JzLiAqL1xuICBwcml2YXRlIHJldGhyb3coZXJyOiB1bmtub3duLCBpbnB1dFBhdGg6IHN0cmluZyk6IG5ldmVyIHtcbiAgICBjb25zdCB3b3Jrc3BhY2VQYXRoID0gaW5wdXRQYXRoLnN0YXJ0c1dpdGgoXCIvXCIpXG4gICAgICA/IGlucHV0UGF0aFxuICAgICAgOiB0aGlzLndvcmtzcGFjZVBhdGgodGhpcy5yZXNvbHZlUGF0aChpbnB1dFBhdGgpKTtcbiAgICBjb25zdCBFcnJvclR5cGUgPSBmaWxlc3lzdGVtU2RrRXJyb3JUeXBlKGVycik7XG4gICAgaWYgKEVycm9yVHlwZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yVHlwZSh3b3Jrc3BhY2VQYXRoKTtcbiAgICB9XG4gICAgLy8gVGhlIHVwc3RyZWFtIG1lc3NhZ2UgaXMgbG9nZ2VkIHJhdGhlciB0aGFuIHJhaXNlZDogaXQgcmVhY2hlcyB0aGUgbW9kZWxcbiAgICAvLyAoYW5kIGZyb20gdGhlcmUgdGhlIGNoYXQgdHJhbnNjcmlwdCkgYXMgdGhlIHRvb2wncyBmYWlsdXJlIHRleHQuXG4gICAgbG9nZ2VyLndhcm4oXCJvcGVyYXRpb24tZmFpbGVkXCIsIHtcbiAgICAgIHBhdGg6IHdvcmtzcGFjZVBhdGgsXG4gICAgICBlcnJvcjogZXJyb3IuZXJyb3JNZXNzYWdlKGVyciksXG4gICAgfSk7XG4gICAgdGhyb3cgbmV3IEV4ZWN1dGlvbkVycm9yKGBEYXRhYnJpY2tzIGZpbGVzeXN0ZW0gb3BlcmF0aW9uIGZhaWxlZCBmb3IgJHt3b3Jrc3BhY2VQYXRofWAsIHtcbiAgICAgIGNhdXNlOiBlcnJvci50b0Vycm9yKGVyciksXG4gICAgICBjb250ZXh0OiB7IHBhdGg6IHdvcmtzcGFjZVBhdGggfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qIC0tLSBsaWZlY3ljbGUgLS0tICovXG5cbiAgLyoqXG4gICAqIFByb2JlIHdoZXRoZXIge0BsaW5rIGJhc2VQYXRofSBleGlzdHMgYW5kIGNhY2hlIHRoZSByZXN1bHQgb25cbiAgICoge0BsaW5rIF9iYXNlUGF0aE1pc3Npbmd9LlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZXNvbHZlQmFzZVBhdGhTdGF0dXMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuX2Jhc2VQYXRoTWlzc2luZyAhPT0gdW5kZWZpbmVkKSByZXR1cm47XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuYXNzZXJ0QWJzb2x1dGVSZWFkYWJsZSh0aGlzLmJhc2VQYXRoKTtcbiAgICAgIHRoaXMuX2Jhc2VQYXRoTWlzc2luZyA9IGZhbHNlO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgaWYgKGVycm9yLmVycm9yQ29udGV4dChlcnIpLm5vdEFjY2Vzc2libGUpIHtcbiAgICAgICAgdGhpcy5fYmFzZVBhdGhNaXNzaW5nID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgdGhpcy5yZXRocm93KGVyciwgXCIvXCIpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBEZWxlZ2F0ZSB0byB7QGxpbmsgZW1wdHlGaWxlc3lzdGVtfSB3aGVuIHRoZSBiYXNlIHBhdGggaXMgbWlzc2luZy4gKi9cbiAgcHJpdmF0ZSBhc3luYyBlbXB0eUZhbGxiYWNrKCk6IFByb21pc2U8UmV0dXJuVHlwZTx0eXBlb2YgZW1wdHlGaWxlc3lzdGVtPiB8IHVuZGVmaW5lZD4ge1xuICAgIGF3YWl0IHRoaXMucmVzb2x2ZUJhc2VQYXRoU3RhdHVzKCk7XG4gICAgcmV0dXJuIHRoaXMuX2Jhc2VQYXRoTWlzc2luZyA/IGVtcHR5RmlsZXN5c3RlbSgpIDogdW5kZWZpbmVkO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgaW5pdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLnJlc29sdmVCYXNlUGF0aFN0YXR1cygpO1xuXG4gICAgaWYgKHRoaXMuX2Jhc2VQYXRoTWlzc2luZykge1xuICAgICAgaWYgKHRoaXMubWtkaXJzID09PSBmYWxzZSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0aGlzLm1rZGlyQWJzb2x1dGUodGhpcy5iYXNlUGF0aCk7XG4gICAgICAgIHRoaXMuX2Jhc2VQYXRoTWlzc2luZyA9IGZhbHNlO1xuICAgICAgICBpZiAodGhpcy5fcmVhZE9ubHkgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHRoaXMuX3JlYWRPbmx5ID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBpZiAodGhpcy5ta2RpcnMgPT09IHRydWUpIHtcbiAgICAgICAgICB0aGlzLnJldGhyb3coZXJyLCBcIi9cIik7XG4gICAgICAgIH1cbiAgICAgICAgbG9nZ2VyLmRlYnVnKFwibWtkaXJzOnRyeS1mYWlsZWRcIiwge1xuICAgICAgICAgIGJhc2VQYXRoOiB0aGlzLmJhc2VQYXRoLFxuICAgICAgICAgIGVycm9yOiBlcnJvci5lcnJvck1lc3NhZ2UoZXJyKSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX3JlYWRPbmx5ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGF3YWl0IHRoaXMucHJvYmVSZWFkT25seSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBXcml0ZSBhbmQgZGVsZXRlIGEgZXBoZW1lcmFsIHByb2JlIGZpbGUgdG8gZGV0ZWN0IHJlYWQtb25seSBhY2Nlc3Mgd2hlblxuICAgKiB7QGxpbmsgRGF0YWJyaWNrc1dvcmtzcGFjZUZpbGVzeXN0ZW1PcHRpb25zLnJlYWRPbmx5fSB3YXMgbm90IHNldC5cbiAgICpcbiAgICogQHJldHVybnMgYHRydWVgIHdoZW4gdGhlIHByb2JlIHdyaXRlIChhbmQgY2xlYW51cCkgc3VjY2VlZGVkLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwcm9iZVJlYWRPbmx5KCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGFic29sdXRlUGF0aCA9IHRoaXMucmVzb2x2ZVBhdGgoYC8uX19kYnhfZnNfcHJvYmVfJHtoYXNoLmlkKCl9YCk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMud3JpdGVBYnNvbHV0ZShhYnNvbHV0ZVBhdGgsIEJ1ZmZlci5mcm9tKFwicHJvYmVcXG5cIiksIHRydWUpO1xuICAgICAgdGhpcy5fcmVhZE9ubHkgPSBmYWxzZTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHRoaXMuX3JlYWRPbmx5ID0gdHJ1ZTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuZGVsZXRlQWJzb2x1dGVGaWxlKGFic29sdXRlUGF0aCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBXcml0YWJsZTsgbGVhdmUgYSBoaWRkZW4gcHJvYmUgZmlsZSByYXRoZXIgdGhhbiBmYWlsaW5nIGluaXQuXG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgZGVzdHJveSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBSZW1vdGUgZmlsZXN5c3RlbTsgbm90aGluZyB0byB0ZWFyIGRvd24gbG9jYWxseS5cbiAgfVxuXG4gIC8qIC0tLSBiYWNrZW5kIEkvTyAtLS0gKi9cblxuICAvKiogUHJvYmUgdGhhdCBgYWJzb2x1dGVQYXRoYCBleGlzdHMgKGZpbGUgb3IgZGlyZWN0b3J5IG1ldGFkYXRhKS4gKi9cbiAgcHJpdmF0ZSBhc3luYyBhc3NlcnRBYnNvbHV0ZVJlYWRhYmxlKGFic29sdXRlUGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgZGlzcGF0Y2hGaWxlc0JhY2tlbmQoYWJzb2x1dGVQYXRoLCB7XG4gICAgICBkYmZzOiAoKSA9PiB0aGlzLmNsaWVudC5kYmZzLmdldFN0YXR1cyh7IHBhdGg6IGFic29sdXRlUGF0aCB9KSxcbiAgICAgIHdvcmtzcGFjZTogKCkgPT4gdGhpcy5jbGllbnQud29ya3NwYWNlLmdldFN0YXR1cyh7IHBhdGg6IGFic29sdXRlUGF0aCB9KSxcbiAgICAgIHVjRmlsZXM6ICgpID0+IHRoaXMuY2xpZW50LmZpbGVzLmdldERpcmVjdG9yeU1ldGFkYXRhKHsgZGlyZWN0b3J5X3BhdGg6IGFic29sdXRlUGF0aCB9KSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBSZWFkIHRoZSBmdWxsIGNvbnRlbnRzIG9mIGBhYnNvbHV0ZVBhdGhgIGZyb20gdGhlIG1hdGNoaW5nIGJhY2tlbmQuICovXG4gIHByaXZhdGUgYXN5bmMgcmVhZEFic29sdXRlKGFic29sdXRlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICByZXR1cm4gZGlzcGF0Y2hGaWxlc0JhY2tlbmQoYWJzb2x1dGVQYXRoLCB7XG4gICAgICBkYmZzOiAoKSA9PiB0aGlzLnJlYWREYmZzRmlsZShhYnNvbHV0ZVBhdGgpLFxuICAgICAgd29ya3NwYWNlOiAoKSA9PiB0aGlzLnJlYWRXb3Jrc3BhY2VGaWxlKGFic29sdXRlUGF0aCksXG4gICAgICB1Y0ZpbGVzOiBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5jbGllbnQuZmlsZXMuZG93bmxvYWQoeyBmaWxlX3BhdGg6IGFic29sdXRlUGF0aCB9KTtcbiAgICAgICAgcmV0dXJuIHJlYWRSZXNwb25zZUJvZHkoXG4gICAgICAgICAgcmVzcG9uc2UuY29udGVudHMgYXMgZ2xvYmFsVGhpcy5SZWFkYWJsZVN0cmVhbTxVaW50OEFycmF5PiB8IHVuZGVmaW5lZCxcbiAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICAvKiogV3JpdGUgYGJ1ZmZlcmAgdG8gYGFic29sdXRlUGF0aGAgb24gdGhlIG1hdGNoaW5nIGJhY2tlbmQuICovXG4gIHByaXZhdGUgYXN5bmMgd3JpdGVBYnNvbHV0ZShcbiAgICBhYnNvbHV0ZVBhdGg6IHN0cmluZyxcbiAgICBidWZmZXI6IEJ1ZmZlcixcbiAgICBvdmVyd3JpdGU6IGJvb2xlYW4sXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IGRpc3BhdGNoRmlsZXNCYWNrZW5kKGFic29sdXRlUGF0aCwge1xuICAgICAgZGJmczogKCkgPT4gdGhpcy53cml0ZURiZnNGaWxlKGFic29sdXRlUGF0aCwgYnVmZmVyLCBvdmVyd3JpdGUpLFxuICAgICAgd29ya3NwYWNlOiAoKSA9PiB0aGlzLndyaXRlV29ya3NwYWNlRmlsZShhYnNvbHV0ZVBhdGgsIGJ1ZmZlciwgb3ZlcndyaXRlKSxcbiAgICAgIHVjRmlsZXM6ICgpID0+IHRoaXMudXBsb2FkVWNGaWxlKGFic29sdXRlUGF0aCwgYnVmZmVyLCBvdmVyd3JpdGUpLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqIFVwbG9hZCBhIGJ1ZmZlciB0byBhIFVuaXR5IENhdGFsb2cgRmlsZXMgQVBJIHBhdGguICovXG4gIHByaXZhdGUgdXBsb2FkVWNGaWxlKGFic29sdXRlUGF0aDogc3RyaW5nLCBidWZmZXI6IEJ1ZmZlciwgb3ZlcndyaXRlOiBib29sZWFuKTogUHJvbWlzZTx1bmtub3duPiB7XG4gICAgcmV0dXJuIHRoaXMuY2xpZW50LmZpbGVzLnVwbG9hZCh7XG4gICAgICBmaWxlX3BhdGg6IGFic29sdXRlUGF0aCxcbiAgICAgIGNvbnRlbnRzOiBidWZmZXJUb1JlYWRhYmxlU3RyZWFtKGJ1ZmZlcikgYXMgbmV2ZXIsXG4gICAgICBvdmVyd3JpdGUsXG4gICAgfSk7XG4gIH1cblxuICAvKiogRGVsZXRlIGEgc2luZ2xlIGZpbGUgYXQgYGFic29sdXRlUGF0aGAgKG5vbi1yZWN1cnNpdmUpLiAqL1xuICBwcml2YXRlIGFzeW5jIGRlbGV0ZUFic29sdXRlRmlsZShhYnNvbHV0ZVBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IGRpc3BhdGNoRmlsZXNCYWNrZW5kKGFic29sdXRlUGF0aCwge1xuICAgICAgZGJmczogKCkgPT4gdGhpcy5jbGllbnQuZGJmcy5kZWxldGUoeyBwYXRoOiBhYnNvbHV0ZVBhdGgsIHJlY3Vyc2l2ZTogZmFsc2UgfSksXG4gICAgICB3b3Jrc3BhY2U6ICgpID0+IHRoaXMuY2xpZW50LndvcmtzcGFjZS5kZWxldGUoeyBwYXRoOiBhYnNvbHV0ZVBhdGgsIHJlY3Vyc2l2ZTogZmFsc2UgfSksXG4gICAgICB1Y0ZpbGVzOiAoKSA9PiB0aGlzLmNsaWVudC5maWxlcy5kZWxldGUoeyBmaWxlX3BhdGg6IGFic29sdXRlUGF0aCB9KSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgYSBmaWxlIG9yIGRpcmVjdG9yeSBhdCBgYWJzb2x1dGVQYXRoYC5cbiAgICpcbiAgICogREJGUyBhbmQgd29ya3NwYWNlIEFQSXMgYWNjZXB0IGByZWN1cnNpdmVgOyBVQyB2b2x1bWVzIHJlY3Vyc2UgbWFudWFsbHkuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGRlbGV0ZUFic29sdXRlUGF0aChhYnNvbHV0ZVBhdGg6IHN0cmluZywgcmVjdXJzaXZlOiBib29sZWFuKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgZGlzcGF0Y2hGaWxlc0JhY2tlbmQoYWJzb2x1dGVQYXRoLCB7XG4gICAgICBkYmZzOiBhc3luYyAoKSA9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMuY2xpZW50LmRiZnMuZGVsZXRlKHsgcGF0aDogYWJzb2x1dGVQYXRoLCByZWN1cnNpdmUgfSk7XG4gICAgICB9LFxuICAgICAgd29ya3NwYWNlOiBhc3luYyAoKSA9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMuY2xpZW50LndvcmtzcGFjZS5kZWxldGUoeyBwYXRoOiBhYnNvbHV0ZVBhdGgsIHJlY3Vyc2l2ZSB9KTtcbiAgICAgIH0sXG4gICAgICB1Y0ZpbGVzOiBhc3luYyAoKSA9PiB7XG4gICAgICAgIGlmIChyZWN1cnNpdmUpIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLmRlbGV0ZVVjRGlyZWN0b3J5UmVjdXJzaXZlKGFic29sdXRlUGF0aCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNoaWxkcmVuID0gYXdhaXQgdGhpcy5saXN0QWJzb2x1dGVEaXJlY3RvcnkoYWJzb2x1dGVQYXRoKTtcbiAgICAgICAgaWYgKGNoaWxkcmVuLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRGlyZWN0b3J5Tm90RW1wdHlFcnJvcih0aGlzLndvcmtzcGFjZVBhdGgoYWJzb2x1dGVQYXRoKSk7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy5jbGllbnQuZmlsZXMuZGVsZXRlRGlyZWN0b3J5KHsgZGlyZWN0b3J5X3BhdGg6IGFic29sdXRlUGF0aCB9KTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICAvKiogQ3JlYXRlIGBhYnNvbHV0ZVBhdGhgIGFuZCBhbnkgbWlzc2luZyBwYXJlbnRzIG9uIHRoZSBtYXRjaGluZyBiYWNrZW5kLiAqL1xuICBwcml2YXRlIGFzeW5jIG1rZGlyQWJzb2x1dGUoYWJzb2x1dGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCBkaXNwYXRjaEZpbGVzQmFja2VuZChhYnNvbHV0ZVBhdGgsIHtcbiAgICAgIGRiZnM6ICgpID0+IHRoaXMuY2xpZW50LmRiZnMubWtkaXJzKHsgcGF0aDogYWJzb2x1dGVQYXRoIH0pLFxuICAgICAgd29ya3NwYWNlOiAoKSA9PiB0aGlzLmNsaWVudC53b3Jrc3BhY2UubWtkaXJzKHsgcGF0aDogYWJzb2x1dGVQYXRoIH0pLFxuICAgICAgdWNGaWxlczogKCkgPT4gdGhpcy5jbGllbnQuZmlsZXMuY3JlYXRlRGlyZWN0b3J5KHsgZGlyZWN0b3J5X3BhdGg6IGFic29sdXRlUGF0aCB9KSxcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcmVhZERiZnNGaWxlKGFic29sdXRlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICBjb25zdCBjaHVua3M6IEJ1ZmZlcltdID0gW107XG4gICAgbGV0IG9mZnNldCA9IDA7XG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5jbGllbnQuZGJmcy5yZWFkKHtcbiAgICAgICAgcGF0aDogYWJzb2x1dGVQYXRoLFxuICAgICAgICBvZmZzZXQsXG4gICAgICAgIGxlbmd0aDogREJGU19SRUFEX0NIVU5LX0JZVEVTLFxuICAgICAgfSk7XG4gICAgICBjb25zdCBjaHVuayA9IGRlY29kZURiZnNQYXlsb2FkKHJlc3BvbnNlLmRhdGEpO1xuICAgICAgaWYgKGNodW5rLmxlbmd0aCA9PT0gMCkgYnJlYWs7XG4gICAgICBjaHVua3MucHVzaChjaHVuayk7XG4gICAgICBvZmZzZXQgKz0gY2h1bmsubGVuZ3RoO1xuICAgICAgaWYgKGNodW5rLmxlbmd0aCA8IERCRlNfUkVBRF9DSFVOS19CWVRFUykgYnJlYWs7XG4gICAgfVxuICAgIHJldHVybiBCdWZmZXIuY29uY2F0KGNodW5rcyk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJlYWRXb3Jrc3BhY2VGaWxlKGFic29sdXRlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuY2xpZW50LndvcmtzcGFjZS5leHBvcnQoe1xuICAgICAgcGF0aDogYWJzb2x1dGVQYXRoLFxuICAgICAgZm9ybWF0OiBcIkFVVE9cIixcbiAgICB9KTtcbiAgICByZXR1cm4gZGVjb2RlRGJmc1BheWxvYWQocmVzcG9uc2UuY29udGVudCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHdyaXRlRGJmc0ZpbGUoXG4gICAgYWJzb2x1dGVQYXRoOiBzdHJpbmcsXG4gICAgYnVmZmVyOiBCdWZmZXIsXG4gICAgb3ZlcndyaXRlOiBib29sZWFuLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoYnVmZmVyLmxlbmd0aCA8PSBEQkZTX1BVVF9NQVhfQllURVMpIHtcbiAgICAgIGF3YWl0IHRoaXMuY2xpZW50LmRiZnMucHV0KHtcbiAgICAgICAgcGF0aDogYWJzb2x1dGVQYXRoLFxuICAgICAgICBjb250ZW50czogYnVmZmVyLnRvU3RyaW5nKFwiYmFzZTY0XCIpLFxuICAgICAgICBvdmVyd3JpdGUsXG4gICAgICB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgY3JlYXRlZCA9IGF3YWl0IHRoaXMuY2xpZW50LmRiZnMuY3JlYXRlKHsgcGF0aDogYWJzb2x1dGVQYXRoLCBvdmVyd3JpdGUgfSk7XG4gICAgY29uc3QgaGFuZGxlID0gY3JlYXRlZC5oYW5kbGU7XG4gICAgaWYgKGhhbmRsZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBFeGVjdXRpb25FcnJvci5taXNzaW5nRGF0YShcIkRCRlMgdXBsb2FkIGhhbmRsZVwiKTtcbiAgICB9XG4gICAgZm9yIChsZXQgb2Zmc2V0ID0gMDsgb2Zmc2V0IDwgYnVmZmVyLmxlbmd0aDsgb2Zmc2V0ICs9IERCRlNfUFVUX01BWF9CWVRFUykge1xuICAgICAgY29uc3Qgc2xpY2UgPSBidWZmZXIuc3ViYXJyYXkob2Zmc2V0LCBvZmZzZXQgKyBEQkZTX1BVVF9NQVhfQllURVMpO1xuICAgICAgYXdhaXQgdGhpcy5jbGllbnQuZGJmcy5hZGRCbG9jayh7XG4gICAgICAgIGhhbmRsZSxcbiAgICAgICAgZGF0YTogc2xpY2UudG9TdHJpbmcoXCJiYXNlNjRcIiksXG4gICAgICB9KTtcbiAgICB9XG4gICAgYXdhaXQgdGhpcy5jbGllbnQuZGJmcy5jbG9zZSh7IGhhbmRsZSB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgd3JpdGVXb3Jrc3BhY2VGaWxlKFxuICAgIGFic29sdXRlUGF0aDogc3RyaW5nLFxuICAgIGJ1ZmZlcjogQnVmZmVyLFxuICAgIG92ZXJ3cml0ZTogYm9vbGVhbixcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5jbGllbnQud29ya3NwYWNlLmltcG9ydCh7XG4gICAgICBwYXRoOiBhYnNvbHV0ZVBhdGgsXG4gICAgICBmb3JtYXQ6IFwiQVVUT1wiLFxuICAgICAgY29udGVudDogYnVmZmVyLnRvU3RyaW5nKFwiYmFzZTY0XCIpLFxuICAgICAgb3ZlcndyaXRlLFxuICAgIH0pO1xuICB9XG5cbiAgLyogLS0tIE1hc3RyYUZpbGVzeXN0ZW0gQVBJIC0tLSAqL1xuXG4gIGdldEluZm8oKTogRmlsZXN5c3RlbUluZm88eyBiYXNlUGF0aDogc3RyaW5nIH0+IHtcbiAgICByZXR1cm4ge1xuICAgICAgaWQ6IHRoaXMuaWQsXG4gICAgICBuYW1lOiB0aGlzLm5hbWUsXG4gICAgICBwcm92aWRlcjogdGhpcy5wcm92aWRlcixcbiAgICAgIHN0YXR1czogdGhpcy5zdGF0dXMsXG4gICAgICByZWFkT25seTogdGhpcy5yZWFkT25seSxcbiAgICAgIG1ldGFkYXRhOiB7IGJhc2VQYXRoOiB0aGlzLmJhc2VQYXRoIH0sXG4gICAgfTtcbiAgfVxuXG4gIGdldEluc3RydWN0aW9ucygpOiBzdHJpbmcge1xuICAgIHJldHVybiBbXG4gICAgICBgRmlsZXMgbGl2ZSBpbiBEYXRhYnJpY2tzIHVuZGVyICR7dGhpcy5iYXNlUGF0aH0uYCxcbiAgICAgIFwiV29ya3NwYWNlIHBhdGhzIGFyZSBhYnNvbHV0ZSB3aXRoaW4gdGhpcyByb290IChmb3IgZXhhbXBsZSBgL25vdGVzL3JlcG9ydC5tZGApLlwiLFxuICAgICAgXCJXb3Jrc3BhY2UgcGF0aHMgdXNlIGAvV29ya3NwYWNlLy4uLmAsIGAvVXNlcnMvLi4uYCwgb3IgYC9SZXBvcy8uLi5gIGJhc2UgcGF0aHMuXCIsXG4gICAgICBcIlVuaXR5IENhdGFsb2cgdm9sdW1lcyB1c2UgYC9Wb2x1bWVzLzxjYXRhbG9nPi88c2NoZW1hPi88dm9sdW1lPi8uLi5gIGJhc2UgcGF0aHMuXCIsXG4gICAgXS5qb2luKFwiIFwiKTtcbiAgfVxuXG4gIC8qKiBNYXAgYSB3b3Jrc3BhY2UtcmVsYXRpdmUgcGF0aCB0byB0aGUgYmFja2luZyBEYXRhYnJpY2tzIGFic29sdXRlIHBhdGguICovXG4gIHJlc29sdmVBYnNvbHV0ZVBhdGgoaW5wdXRQYXRoOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLnJlc29sdmVQYXRoKGlucHV0UGF0aCk7XG4gIH1cblxuICAvKiogUmVhZCBmaWxlIGNvbnRlbnRzIGZyb20gdGhlIHdvcmtzcGFjZSBuYW1lc3BhY2UuICovXG4gIGFzeW5jIHJlYWRGaWxlKGlucHV0UGF0aDogc3RyaW5nLCBvcHRpb25zPzogUmVhZE9wdGlvbnMpOiBQcm9taXNlPHN0cmluZyB8IEJ1ZmZlcj4ge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKTtcbiAgICBjb25zdCBlbXB0eSA9IGF3YWl0IHRoaXMuZW1wdHlGYWxsYmFjaygpO1xuICAgIGlmIChlbXB0eSkgcmV0dXJuIGVtcHR5LnJlYWRGaWxlKGlucHV0UGF0aCwgb3B0aW9ucyk7XG4gICAgY29uc3QgYWJzb2x1dGVQYXRoID0gdGhpcy5yZXNvbHZlUGF0aChpbnB1dFBhdGgpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBidWZmZXIgPSBhd2FpdCB0aGlzLnJlYWRBYnNvbHV0ZShhYnNvbHV0ZVBhdGgpO1xuICAgICAgcmV0dXJuIGZvcm1hdFJlYWRSZXN1bHQoYnVmZmVyLCBvcHRpb25zPy5lbmNvZGluZyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aGlzLnJldGhyb3coZXJyLCBpbnB1dFBhdGgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBXcml0ZSBmaWxlIGNvbnRlbnRzIGludG8gdGhlIHdvcmtzcGFjZSBuYW1lc3BhY2UuICovXG4gIGFzeW5jIHdyaXRlRmlsZShpbnB1dFBhdGg6IHN0cmluZywgY29udGVudDogRmlsZUNvbnRlbnQsIG9wdGlvbnM/OiBXcml0ZU9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZVJlYWR5KCk7XG4gICAgY29uc3QgZW1wdHkgPSBhd2FpdCB0aGlzLmVtcHR5RmFsbGJhY2soKTtcbiAgICBpZiAoZW1wdHkpIHJldHVybiBlbXB0eS53cml0ZUZpbGUoaW5wdXRQYXRoLCBjb250ZW50LCBvcHRpb25zKTtcbiAgICB0aGlzLmFzc2VydFdyaXRhYmxlKFwid3JpdGVGaWxlXCIpO1xuICAgIGNvbnN0IGFic29sdXRlUGF0aCA9IHRoaXMucmVzb2x2ZVBhdGgoaW5wdXRQYXRoKTtcbiAgICBjb25zdCBidWZmZXIgPSB0b0J1ZmZlcihjb250ZW50KTtcbiAgICBjb25zdCBvdmVyd3JpdGUgPSBvcHRpb25zPy5vdmVyd3JpdGUgPz8gdHJ1ZTtcbiAgICB0cnkge1xuICAgICAgaWYgKCFvdmVyd3JpdGUgJiYgKGF3YWl0IHRoaXMuZXhpc3RzKGlucHV0UGF0aCkpKSB7XG4gICAgICAgIHRocm93IG5ldyBGaWxlRXhpc3RzRXJyb3IoaW5wdXRQYXRoKTtcbiAgICAgIH1cbiAgICAgIGF3YWl0IHRoaXMud3JpdGVBYnNvbHV0ZShhYnNvbHV0ZVBhdGgsIGJ1ZmZlciwgb3ZlcndyaXRlKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBGaWxlRXhpc3RzRXJyb3IpIHRocm93IGVycjtcbiAgICAgIHRoaXMucmV0aHJvdyhlcnIsIGlucHV0UGF0aCk7XG4gICAgfVxuICB9XG5cbiAgLyoqIEFwcGVuZCB0byBhbiBleGlzdGluZyBmaWxlLCBjcmVhdGluZyBpdCB3aGVuIG1pc3NpbmcuICovXG4gIGFzeW5jIGFwcGVuZEZpbGUoaW5wdXRQYXRoOiBzdHJpbmcsIGNvbnRlbnQ6IEZpbGVDb250ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpO1xuICAgIGNvbnN0IGVtcHR5ID0gYXdhaXQgdGhpcy5lbXB0eUZhbGxiYWNrKCk7XG4gICAgaWYgKGVtcHR5KSByZXR1cm4gZW1wdHkuYXBwZW5kRmlsZShpbnB1dFBhdGgsIGNvbnRlbnQpO1xuICAgIHRoaXMuYXNzZXJ0V3JpdGFibGUoXCJhcHBlbmRGaWxlXCIpO1xuICAgIGNvbnN0IGV4aXN0aW5nID0gKGF3YWl0IHRoaXMuZXhpc3RzKGlucHV0UGF0aCkpXG4gICAgICA/IGF3YWl0IHRoaXMucmVhZEZpbGUoaW5wdXRQYXRoKVxuICAgICAgOiBCdWZmZXIuYWxsb2MoMCk7XG4gICAgY29uc3QgbWVyZ2VkID0gQnVmZmVyLmNvbmNhdChbXG4gICAgICBCdWZmZXIuaXNCdWZmZXIoZXhpc3RpbmcpID8gZXhpc3RpbmcgOiBCdWZmZXIuZnJvbShleGlzdGluZywgXCJ1dGY4XCIpLFxuICAgICAgdG9CdWZmZXIoY29udGVudCksXG4gICAgXSk7XG4gICAgYXdhaXQgdGhpcy53cml0ZUZpbGUoaW5wdXRQYXRoLCBtZXJnZWQsIHsgb3ZlcndyaXRlOiB0cnVlIH0pO1xuICB9XG5cbiAgLyoqIERlbGV0ZSBhIGZpbGUgaW4gdGhlIHdvcmtzcGFjZSBuYW1lc3BhY2UuICovXG4gIGFzeW5jIGRlbGV0ZUZpbGUoaW5wdXRQYXRoOiBzdHJpbmcsIG9wdGlvbnM/OiBSZW1vdmVPcHRpb25zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpO1xuICAgIGNvbnN0IGVtcHR5ID0gYXdhaXQgdGhpcy5lbXB0eUZhbGxiYWNrKCk7XG4gICAgaWYgKGVtcHR5KSByZXR1cm4gZW1wdHkuZGVsZXRlRmlsZShpbnB1dFBhdGgsIG9wdGlvbnMpO1xuICAgIHRoaXMuYXNzZXJ0V3JpdGFibGUoXCJkZWxldGVGaWxlXCIpO1xuICAgIGNvbnN0IGFic29sdXRlUGF0aCA9IHRoaXMucmVzb2x2ZVBhdGgoaW5wdXRQYXRoKTtcbiAgICB0cnkge1xuICAgICAgaWYgKCEoYXdhaXQgdGhpcy5leGlzdHMoaW5wdXRQYXRoKSkpIHtcbiAgICAgICAgaWYgKG9wdGlvbnM/LmZvcmNlKSByZXR1cm47XG4gICAgICAgIHRocm93IG5ldyBGaWxlTm90Rm91bmRFcnJvcihpbnB1dFBhdGgpO1xuICAgICAgfVxuICAgICAgY29uc3QgZW50cnkgPSBhd2FpdCB0aGlzLnN0YXQoaW5wdXRQYXRoKTtcbiAgICAgIGlmIChlbnRyeS50eXBlID09PSBcImRpcmVjdG9yeVwiKSB7XG4gICAgICAgIHRocm93IG5ldyBJc0RpcmVjdG9yeUVycm9yKGlucHV0UGF0aCk7XG4gICAgICB9XG4gICAgICBhd2FpdCB0aGlzLmRlbGV0ZUFic29sdXRlRmlsZShhYnNvbHV0ZVBhdGgpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgaWYgKGVyciBpbnN0YW5jZW9mIEZpbGVOb3RGb3VuZEVycm9yIHx8IGVyciBpbnN0YW5jZW9mIElzRGlyZWN0b3J5RXJyb3IpIHRocm93IGVycjtcbiAgICAgIHRoaXMucmV0aHJvdyhlcnIsIGlucHV0UGF0aCk7XG4gICAgfVxuICB9XG5cbiAgLyoqIENvcHkgYSBmaWxlIHdpdGhpbiB0aGUgd29ya3NwYWNlIG5hbWVzcGFjZS4gKi9cbiAgYXN5bmMgY29weUZpbGUoc3JjOiBzdHJpbmcsIGRlc3Q6IHN0cmluZywgb3B0aW9ucz86IENvcHlPcHRpb25zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpO1xuICAgIGNvbnN0IGVtcHR5ID0gYXdhaXQgdGhpcy5lbXB0eUZhbGxiYWNrKCk7XG4gICAgaWYgKGVtcHR5KSByZXR1cm4gZW1wdHkuY29weUZpbGUoc3JjLCBkZXN0LCBvcHRpb25zKTtcbiAgICB0aGlzLmFzc2VydFdyaXRhYmxlKFwiY29weUZpbGVcIik7XG4gICAgY29uc3Qgb3ZlcndyaXRlID0gb3B0aW9ucz8ub3ZlcndyaXRlID8/IHRydWU7XG4gICAgaWYgKCFvdmVyd3JpdGUgJiYgKGF3YWl0IHRoaXMuZXhpc3RzKGRlc3QpKSkge1xuICAgICAgdGhyb3cgbmV3IEZpbGVFeGlzdHNFcnJvcihkZXN0KTtcbiAgICB9XG4gICAgY29uc3QgY29udGVudCA9IGF3YWl0IHRoaXMucmVhZEZpbGUoc3JjKTtcbiAgICBhd2FpdCB0aGlzLndyaXRlRmlsZShkZXN0LCBjb250ZW50LCB7IG92ZXJ3cml0ZTogdHJ1ZSB9KTtcbiAgfVxuXG4gIC8qKiBNb3ZlIG9yIHJlbmFtZSBhIGZpbGUgd2l0aGluIHRoZSB3b3Jrc3BhY2UgbmFtZXNwYWNlLiAqL1xuICBhc3luYyBtb3ZlRmlsZShzcmM6IHN0cmluZywgZGVzdDogc3RyaW5nLCBvcHRpb25zPzogQ29weU9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZVJlYWR5KCk7XG4gICAgY29uc3QgZW1wdHkgPSBhd2FpdCB0aGlzLmVtcHR5RmFsbGJhY2soKTtcbiAgICBpZiAoZW1wdHkpIHJldHVybiBlbXB0eS5tb3ZlRmlsZShzcmMsIGRlc3QsIG9wdGlvbnMpO1xuICAgIHRoaXMuYXNzZXJ0V3JpdGFibGUoXCJtb3ZlRmlsZVwiKTtcbiAgICBjb25zdCBzcmNBYnNvbHV0ZSA9IHRoaXMucmVzb2x2ZVBhdGgoc3JjKTtcbiAgICBjb25zdCBkZXN0QWJzb2x1dGUgPSB0aGlzLnJlc29sdmVQYXRoKGRlc3QpO1xuICAgIGNvbnN0IG92ZXJ3cml0ZSA9IG9wdGlvbnM/Lm92ZXJ3cml0ZSA/PyB0cnVlO1xuICAgIHRyeSB7XG4gICAgICBpZiAoIW92ZXJ3cml0ZSAmJiAoYXdhaXQgdGhpcy5leGlzdHMoZGVzdCkpKSB7XG4gICAgICAgIHRocm93IG5ldyBGaWxlRXhpc3RzRXJyb3IoZGVzdCk7XG4gICAgICB9XG4gICAgICBpZiAoXG4gICAgICAgIHJlc29sdmVGaWxlc0JhY2tlbmQoc3JjQWJzb2x1dGUpID09PSBcImRiZnNcIiAmJlxuICAgICAgICByZXNvbHZlRmlsZXNCYWNrZW5kKGRlc3RBYnNvbHV0ZSkgPT09IFwiZGJmc1wiXG4gICAgICApIHtcbiAgICAgICAgYXdhaXQgdGhpcy5jbGllbnQuZGJmcy5tb3ZlKHtcbiAgICAgICAgICBzb3VyY2VfcGF0aDogc3JjQWJzb2x1dGUsXG4gICAgICAgICAgZGVzdGluYXRpb25fcGF0aDogZGVzdEFic29sdXRlLFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgYXdhaXQgdGhpcy5jb3B5RmlsZShzcmMsIGRlc3QsIHsgb3ZlcndyaXRlOiB0cnVlIH0pO1xuICAgICAgYXdhaXQgdGhpcy5kZWxldGVGaWxlKHNyYywgeyBmb3JjZTogdHJ1ZSB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBGaWxlRXhpc3RzRXJyb3IpIHRocm93IGVycjtcbiAgICAgIHRoaXMucmV0aHJvdyhlcnIsIGRlc3QpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBDcmVhdGUgYSBkaXJlY3RvcnkgaW4gdGhlIHdvcmtzcGFjZSBuYW1lc3BhY2UuICovXG4gIGFzeW5jIG1rZGlyKGlucHV0UGF0aDogc3RyaW5nLCBvcHRpb25zPzogeyByZWN1cnNpdmU/OiBib29sZWFuIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZVJlYWR5KCk7XG4gICAgY29uc3QgZW1wdHkgPSBhd2FpdCB0aGlzLmVtcHR5RmFsbGJhY2soKTtcbiAgICBpZiAoZW1wdHkpIHJldHVybiBlbXB0eS5ta2RpcihpbnB1dFBhdGgsIG9wdGlvbnMpO1xuICAgIHRoaXMuYXNzZXJ0V3JpdGFibGUoXCJta2RpclwiKTtcbiAgICBjb25zdCBhYnNvbHV0ZVBhdGggPSB0aGlzLnJlc29sdmVQYXRoKGlucHV0UGF0aCk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMubWtkaXJBYnNvbHV0ZShhYnNvbHV0ZVBhdGgpO1xuICAgICAgaWYgKCFvcHRpb25zPy5yZWN1cnNpdmUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhpcy5yZXRocm93KGVyciwgaW5wdXRQYXRoKTtcbiAgICB9XG4gIH1cblxuICAvKiogUmVtb3ZlIGEgZGlyZWN0b3J5IGZyb20gdGhlIHdvcmtzcGFjZSBuYW1lc3BhY2UuICovXG4gIGFzeW5jIHJtZGlyKGlucHV0UGF0aDogc3RyaW5nLCBvcHRpb25zPzogUmVtb3ZlT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKTtcbiAgICBjb25zdCBlbXB0eSA9IGF3YWl0IHRoaXMuZW1wdHlGYWxsYmFjaygpO1xuICAgIGlmIChlbXB0eSkgcmV0dXJuIGVtcHR5LnJtZGlyKGlucHV0UGF0aCwgb3B0aW9ucyk7XG4gICAgdGhpcy5hc3NlcnRXcml0YWJsZShcInJtZGlyXCIpO1xuICAgIGNvbnN0IGFic29sdXRlUGF0aCA9IHRoaXMucmVzb2x2ZVBhdGgoaW5wdXRQYXRoKTtcbiAgICB0cnkge1xuICAgICAgaWYgKCEoYXdhaXQgdGhpcy5leGlzdHMoaW5wdXRQYXRoKSkpIHtcbiAgICAgICAgaWYgKG9wdGlvbnM/LmZvcmNlKSByZXR1cm47XG4gICAgICAgIHRocm93IG5ldyBEaXJlY3RvcnlOb3RGb3VuZEVycm9yKGlucHV0UGF0aCk7XG4gICAgICB9XG4gICAgICBjb25zdCBlbnRyeSA9IGF3YWl0IHRoaXMuc3RhdChpbnB1dFBhdGgpO1xuICAgICAgaWYgKGVudHJ5LnR5cGUgIT09IFwiZGlyZWN0b3J5XCIpIHtcbiAgICAgICAgdGhyb3cgbmV3IE5vdERpcmVjdG9yeUVycm9yKGlucHV0UGF0aCk7XG4gICAgICB9XG4gICAgICBhd2FpdCB0aGlzLmRlbGV0ZUFic29sdXRlUGF0aChhYnNvbHV0ZVBhdGgsIG9wdGlvbnM/LnJlY3Vyc2l2ZSA/PyBmYWxzZSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoXG4gICAgICAgIGVyciBpbnN0YW5jZW9mIERpcmVjdG9yeU5vdEZvdW5kRXJyb3IgfHxcbiAgICAgICAgZXJyIGluc3RhbmNlb2YgTm90RGlyZWN0b3J5RXJyb3IgfHxcbiAgICAgICAgZXJyIGluc3RhbmNlb2YgRGlyZWN0b3J5Tm90RW1wdHlFcnJvclxuICAgICAgKSB7XG4gICAgICAgIHRocm93IGVycjtcbiAgICAgIH1cbiAgICAgIHRoaXMucmV0aHJvdyhlcnIsIGlucHV0UGF0aCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlY3Vyc2l2ZWx5IGRlbGV0ZSBhIFVuaXR5IENhdGFsb2cgZGlyZWN0b3J5IHRyZWUuXG4gICAqXG4gICAqIERCRlMgYW5kIHdvcmtzcGFjZSB0cmVlcyB1c2UgbmF0aXZlIHJlY3Vyc2l2ZSBkZWxldGUgdmlhXG4gICAqIHtAbGluayBkZWxldGVBYnNvbHV0ZVBhdGh9IGluc3RlYWQuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGRlbGV0ZVVjRGlyZWN0b3J5UmVjdXJzaXZlKGFic29sdXRlUGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgZm9yIChjb25zdCBjaGlsZCBvZiBhd2FpdCB0aGlzLmxpc3RBYnNvbHV0ZURpcmVjdG9yeShhYnNvbHV0ZVBhdGgpKSB7XG4gICAgICBjb25zdCBjaGlsZEFic29sdXRlID0gcGF0aC5qb2luKGFic29sdXRlUGF0aCwgY2hpbGQubmFtZSk7XG4gICAgICBpZiAoY2hpbGQudHlwZSA9PT0gXCJkaXJlY3RvcnlcIikge1xuICAgICAgICBhd2FpdCB0aGlzLmRlbGV0ZVVjRGlyZWN0b3J5UmVjdXJzaXZlKGNoaWxkQWJzb2x1dGUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYXdhaXQgdGhpcy5kZWxldGVBYnNvbHV0ZUZpbGUoY2hpbGRBYnNvbHV0ZSk7XG4gICAgICB9XG4gICAgfVxuICAgIGF3YWl0IHRoaXMuY2xpZW50LmZpbGVzLmRlbGV0ZURpcmVjdG9yeSh7IGRpcmVjdG9yeV9wYXRoOiBhYnNvbHV0ZVBhdGggfSk7XG4gIH1cblxuICAvKiAtLS0gZGlyZWN0b3J5IGxpc3RpbmcgLS0tICovXG5cbiAgLyoqIExpc3QgZW50cmllcyBpbiBhIHdvcmtzcGFjZSBkaXJlY3RvcnkuICovXG4gIGFzeW5jIHJlYWRkaXIoaW5wdXRQYXRoOiBzdHJpbmcsIG9wdGlvbnM/OiBMaXN0T3B0aW9ucyk6IFByb21pc2U8RmlsZUVudHJ5W10+IHtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZVJlYWR5KCk7XG4gICAgY29uc3QgZW1wdHkgPSBhd2FpdCB0aGlzLmVtcHR5RmFsbGJhY2soKTtcbiAgICBpZiAoZW1wdHkpIHJldHVybiBlbXB0eS5yZWFkZGlyKGlucHV0UGF0aCwgb3B0aW9ucyk7XG4gICAgY29uc3QgYWJzb2x1dGVQYXRoID0gdGhpcy5yZXNvbHZlUGF0aChpbnB1dFBhdGgpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBlbnRyaWVzID0gYXdhaXQgdGhpcy5saXN0QWJzb2x1dGVEaXJlY3RvcnkoYWJzb2x1dGVQYXRoKTtcbiAgICAgIGNvbnN0IGZpbHRlcmVkID0gdGhpcy5maWx0ZXJFbnRyaWVzKGVudHJpZXMsIG9wdGlvbnMpO1xuICAgICAgaWYgKCFvcHRpb25zPy5yZWN1cnNpdmUpIHJldHVybiBmaWx0ZXJlZDtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLnJlYWREaXJlY3RvcnlSZWN1cnNpdmUoYWJzb2x1dGVQYXRoLCBvcHRpb25zLCAwKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMucmV0aHJvdyhlcnIsIGlucHV0UGF0aCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyByZWFkRGlyZWN0b3J5UmVjdXJzaXZlKFxuICAgIGFic29sdXRlUGF0aDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IExpc3RPcHRpb25zLFxuICAgIGRlcHRoOiBudW1iZXIsXG4gICAgcmVsYXRpdmVQcmVmaXggPSBcIlwiLFxuICApOiBQcm9taXNlPEZpbGVFbnRyeVtdPiB7XG4gICAgY29uc3QgbWF4RGVwdGggPSBvcHRpb25zLm1heERlcHRoID8/IE51bWJlci5QT1NJVElWRV9JTkZJTklUWTtcbiAgICBjb25zdCBlbnRyaWVzID0gdGhpcy5maWx0ZXJFbnRyaWVzKGF3YWl0IHRoaXMubGlzdEFic29sdXRlRGlyZWN0b3J5KGFic29sdXRlUGF0aCksIG9wdGlvbnMpO1xuICAgIGNvbnN0IGNvbGxlY3RlZDogRmlsZUVudHJ5W10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgIGNvbnN0IHJlbGF0aXZlTmFtZSA9IHJlbGF0aXZlUHJlZml4ID8gcGF0aC5qb2luKHJlbGF0aXZlUHJlZml4LCBlbnRyeS5uYW1lKSA6IGVudHJ5Lm5hbWU7XG4gICAgICBjb2xsZWN0ZWQucHVzaCh7IC4uLmVudHJ5LCBuYW1lOiByZWxhdGl2ZU5hbWUgfSk7XG4gICAgICBpZiAoZW50cnkudHlwZSAhPT0gXCJkaXJlY3RvcnlcIiB8fCBkZXB0aCA+PSBtYXhEZXB0aCkgY29udGludWU7XG4gICAgICBjb2xsZWN0ZWQucHVzaChcbiAgICAgICAgLi4uKGF3YWl0IHRoaXMucmVhZERpcmVjdG9yeVJlY3Vyc2l2ZShcbiAgICAgICAgICBwYXRoLmpvaW4oYWJzb2x1dGVQYXRoLCBlbnRyeS5uYW1lKSxcbiAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgIGRlcHRoICsgMSxcbiAgICAgICAgICByZWxhdGl2ZU5hbWUsXG4gICAgICAgICkpLFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGNvbGxlY3RlZDtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbGlzdEFic29sdXRlRGlyZWN0b3J5KGFic29sdXRlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxGaWxlRW50cnlbXT4ge1xuICAgIHJldHVybiBkaXNwYXRjaEZpbGVzQmFja2VuZChhYnNvbHV0ZVBhdGgsIHtcbiAgICAgIGRiZnM6IGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgZW50cmllczogRmlsZUVudHJ5W10gPSBbXTtcbiAgICAgICAgZm9yIGF3YWl0IChjb25zdCBpbmZvIG9mIHRoaXMuY2xpZW50LmRiZnMubGlzdCh7IHBhdGg6IGFic29sdXRlUGF0aCB9KSkge1xuICAgICAgICAgIGVudHJpZXMucHVzaCh7XG4gICAgICAgICAgICBuYW1lOiBwYXRoLmJhc2VuYW1lKGluZm8ucGF0aCA/PyBcIlwiKSxcbiAgICAgICAgICAgIHR5cGU6IGluZm8uaXNfZGlyID8gXCJkaXJlY3RvcnlcIiA6IFwiZmlsZVwiLFxuICAgICAgICAgICAgc2l6ZTogaW5mby5maWxlX3NpemUsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVudHJpZXM7XG4gICAgICB9LFxuICAgICAgd29ya3NwYWNlOiBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IGVudHJpZXM6IEZpbGVFbnRyeVtdID0gW107XG4gICAgICAgIGZvciBhd2FpdCAoY29uc3QgaW5mbyBvZiB0aGlzLmNsaWVudC53b3Jrc3BhY2UubGlzdCh7IHBhdGg6IGFic29sdXRlUGF0aCB9KSkge1xuICAgICAgICAgIGVudHJpZXMucHVzaCh7XG4gICAgICAgICAgICBuYW1lOiBwYXRoLmJhc2VuYW1lKGluZm8ucGF0aCA/PyBcIlwiKSxcbiAgICAgICAgICAgIHR5cGU6IGluZm8ub2JqZWN0X3R5cGUgPT09IFwiRElSRUNUT1JZXCIgPyBcImRpcmVjdG9yeVwiIDogXCJmaWxlXCIsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVudHJpZXM7XG4gICAgICB9LFxuICAgICAgdWNGaWxlczogYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zdCBlbnRyaWVzOiBGaWxlRW50cnlbXSA9IFtdO1xuICAgICAgICBmb3IgYXdhaXQgKGNvbnN0IGVudHJ5IG9mIHRoaXMuY2xpZW50LmZpbGVzLmxpc3REaXJlY3RvcnlDb250ZW50cyh7XG4gICAgICAgICAgZGlyZWN0b3J5X3BhdGg6IGFic29sdXRlUGF0aCxcbiAgICAgICAgfSkpIHtcbiAgICAgICAgICBlbnRyaWVzLnB1c2goe1xuICAgICAgICAgICAgbmFtZTogZW50cnkubmFtZSA/PyBwYXRoLmJhc2VuYW1lKGVudHJ5LnBhdGggPz8gXCJcIiksXG4gICAgICAgICAgICB0eXBlOiBlbnRyeS5pc19kaXJlY3RvcnkgPyBcImRpcmVjdG9yeVwiIDogXCJmaWxlXCIsXG4gICAgICAgICAgICBzaXplOiBlbnRyeS5maWxlX3NpemUsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVudHJpZXM7XG4gICAgICB9LFxuICAgIH0pO1xuICB9XG5cbiAgLyoqIEFwcGx5IE1hc3RyYSBsaXN0IGZpbHRlcnMgKGBleHRlbnNpb25gLCBldGMuKSB0byBkaXJlY3RvcnkgZW50cmllcy4gKi9cbiAgcHJpdmF0ZSBmaWx0ZXJFbnRyaWVzKGVudHJpZXM6IEZpbGVFbnRyeVtdLCBvcHRpb25zPzogTGlzdE9wdGlvbnMpOiBGaWxlRW50cnlbXSB7XG4gICAgaWYgKCFvcHRpb25zPy5leHRlbnNpb24pIHJldHVybiBlbnRyaWVzO1xuICAgIGNvbnN0IGV4dGVuc2lvbnMgPSBBcnJheS5pc0FycmF5KG9wdGlvbnMuZXh0ZW5zaW9uKSA/IG9wdGlvbnMuZXh0ZW5zaW9uIDogW29wdGlvbnMuZXh0ZW5zaW9uXTtcbiAgICBjb25zdCBub3JtYWxpemVkID0gZXh0ZW5zaW9ucy5tYXAoKGV4dCkgPT5cbiAgICAgIGV4dC5zdGFydHNXaXRoKFwiLlwiKSA/IGV4dC50b0xvd2VyQ2FzZSgpIDogYC4ke2V4dC50b0xvd2VyQ2FzZSgpfWAsXG4gICAgKTtcbiAgICByZXR1cm4gZW50cmllcy5maWx0ZXIoKGVudHJ5KSA9PiB7XG4gICAgICBpZiAoZW50cnkudHlwZSAhPT0gXCJmaWxlXCIpIHJldHVybiB0cnVlO1xuICAgICAgY29uc3QgbG93ZXIgPSBlbnRyeS5uYW1lLnRvTG93ZXJDYXNlKCk7XG4gICAgICByZXR1cm4gbm9ybWFsaXplZC5zb21lKChleHQpID0+IGxvd2VyLmVuZHNXaXRoKGV4dCkpO1xuICAgIH0pO1xuICB9XG5cbiAgLyogLS0tIG1ldGFkYXRhIC0tLSAqL1xuXG4gIC8qKiBSZXR1cm4gd2hldGhlciBgaW5wdXRQYXRoYCBleGlzdHMgaW4gdGhlIHdvcmtzcGFjZSBuYW1lc3BhY2UuICovXG4gIGFzeW5jIGV4aXN0cyhpbnB1dFBhdGg6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKTtcbiAgICBjb25zdCBlbXB0eSA9IGF3YWl0IHRoaXMuZW1wdHlGYWxsYmFjaygpO1xuICAgIGlmIChlbXB0eSkgcmV0dXJuIGVtcHR5LmV4aXN0cyhpbnB1dFBhdGgpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnN0YXQoaW5wdXRQYXRoKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgaWYgKGVyciBpbnN0YW5jZW9mIEZpbGVOb3RGb3VuZEVycm9yKSByZXR1cm4gZmFsc2U7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICB9XG5cbiAgLyoqIFJldHVybiBmaWxlIG9yIGRpcmVjdG9yeSBtZXRhZGF0YSBmb3IgYGlucHV0UGF0aGAuICovXG4gIGFzeW5jIHN0YXQoaW5wdXRQYXRoOiBzdHJpbmcpOiBQcm9taXNlPEZpbGVTdGF0PiB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpO1xuICAgIGNvbnN0IGVtcHR5ID0gYXdhaXQgdGhpcy5lbXB0eUZhbGxiYWNrKCk7XG4gICAgaWYgKGVtcHR5KSByZXR1cm4gZW1wdHkuc3RhdChpbnB1dFBhdGgpO1xuICAgIGNvbnN0IGFic29sdXRlUGF0aCA9IHRoaXMucmVzb2x2ZVBhdGgoaW5wdXRQYXRoKTtcbiAgICBjb25zdCB3b3Jrc3BhY2VQYXRoID0gdGhpcy53b3Jrc3BhY2VQYXRoKGFic29sdXRlUGF0aCk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBkaXNwYXRjaEZpbGVzQmFja2VuZChhYnNvbHV0ZVBhdGgsIHtcbiAgICAgICAgZGJmczogYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGluZm8gPSBhd2FpdCB0aGlzLmNsaWVudC5kYmZzLmdldFN0YXR1cyh7IHBhdGg6IGFic29sdXRlUGF0aCB9KTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgbmFtZTogcGF0aC5iYXNlbmFtZShpbmZvLnBhdGggPz8gYWJzb2x1dGVQYXRoKSxcbiAgICAgICAgICAgIHBhdGg6IHdvcmtzcGFjZVBhdGgsXG4gICAgICAgICAgICB0eXBlOiBpbmZvLmlzX2RpciA/IChcImRpcmVjdG9yeVwiIGFzIGNvbnN0KSA6IChcImZpbGVcIiBhcyBjb25zdCksXG4gICAgICAgICAgICBzaXplOiBpbmZvLmZpbGVfc2l6ZSA/PyAwLFxuICAgICAgICAgICAgY3JlYXRlZEF0OiBuZXcgRGF0ZShpbmZvLm1vZGlmaWNhdGlvbl90aW1lID8/IDApLFxuICAgICAgICAgICAgbW9kaWZpZWRBdDogbmV3IERhdGUoaW5mby5tb2RpZmljYXRpb25fdGltZSA/PyAwKSxcbiAgICAgICAgICB9O1xuICAgICAgICB9LFxuICAgICAgICB3b3Jrc3BhY2U6IGFzeW5jICgpID0+IHtcbiAgICAgICAgICBjb25zdCBpbmZvID0gYXdhaXQgdGhpcy5jbGllbnQud29ya3NwYWNlLmdldFN0YXR1cyh7IHBhdGg6IGFic29sdXRlUGF0aCB9KTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgbmFtZTogcGF0aC5iYXNlbmFtZShpbmZvLnBhdGggPz8gYWJzb2x1dGVQYXRoKSxcbiAgICAgICAgICAgIHBhdGg6IHdvcmtzcGFjZVBhdGgsXG4gICAgICAgICAgICB0eXBlOiBpbmZvLm9iamVjdF90eXBlID09PSBcIkRJUkVDVE9SWVwiID8gKFwiZGlyZWN0b3J5XCIgYXMgY29uc3QpIDogKFwiZmlsZVwiIGFzIGNvbnN0KSxcbiAgICAgICAgICAgIHNpemU6IDAsXG4gICAgICAgICAgICBjcmVhdGVkQXQ6IG5ldyBEYXRlKGluZm8uY3JlYXRlZF9hdCA/PyAwKSxcbiAgICAgICAgICAgIG1vZGlmaWVkQXQ6IG5ldyBEYXRlKGluZm8ubW9kaWZpZWRfYXQgPz8gMCksXG4gICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgdWNGaWxlczogKCkgPT4gdGhpcy5zdGF0VWNBYnNvbHV0ZShhYnNvbHV0ZVBhdGgsIHdvcmtzcGFjZVBhdGgsIGlucHV0UGF0aCksXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMucmV0aHJvdyhlcnIsIGlucHV0UGF0aCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFN0YXQgYSBVbml0eSBDYXRhbG9nIHBhdGggYnkgcHJvYmluZyBmaWxlIG1ldGFkYXRhIGZpcnN0LCB0aGVuXG4gICAqIGRpcmVjdG9yeSBtZXRhZGF0YS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc3RhdFVjQWJzb2x1dGUoXG4gICAgYWJzb2x1dGVQYXRoOiBzdHJpbmcsXG4gICAgd29ya3NwYWNlUGF0aDogc3RyaW5nLFxuICAgIGlucHV0UGF0aDogc3RyaW5nLFxuICApOiBQcm9taXNlPEZpbGVTdGF0PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IG1ldGFkYXRhID0gYXdhaXQgdGhpcy5jbGllbnQuZmlsZXMuZ2V0TWV0YWRhdGEoe1xuICAgICAgICBmaWxlX3BhdGg6IGFic29sdXRlUGF0aCxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbmFtZTogcGF0aC5iYXNlbmFtZShhYnNvbHV0ZVBhdGgpLFxuICAgICAgICBwYXRoOiB3b3Jrc3BhY2VQYXRoLFxuICAgICAgICB0eXBlOiBcImZpbGVcIiBhcyBjb25zdCxcbiAgICAgICAgc2l6ZTogTnVtYmVyKG1ldGFkYXRhW1wiY29udGVudC1sZW5ndGhcIl0gPz8gMCksXG4gICAgICAgIGNyZWF0ZWRBdDogcGFyc2VIdHRwRGF0ZShtZXRhZGF0YVtcImxhc3QtbW9kaWZpZWRcIl0pLFxuICAgICAgICBtb2RpZmllZEF0OiBwYXJzZUh0dHBEYXRlKG1ldGFkYXRhW1wibGFzdC1tb2RpZmllZFwiXSksXG4gICAgICAgIG1pbWVUeXBlOiBtZXRhZGF0YVtcImNvbnRlbnQtdHlwZVwiXSxcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZmlsZUVycikge1xuICAgICAgaWYgKCFlcnJvci5lcnJvckNvbnRleHQoZmlsZUVycikubm90QWNjZXNzaWJsZSkge1xuICAgICAgICB0aGlzLnJldGhyb3coZmlsZUVyciwgaW5wdXRQYXRoKTtcbiAgICAgIH1cbiAgICAgIGF3YWl0IHRoaXMuY2xpZW50LmZpbGVzLmdldERpcmVjdG9yeU1ldGFkYXRhKHtcbiAgICAgICAgZGlyZWN0b3J5X3BhdGg6IGFic29sdXRlUGF0aCxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbmFtZTogcGF0aC5iYXNlbmFtZShhYnNvbHV0ZVBhdGgpLFxuICAgICAgICBwYXRoOiB3b3Jrc3BhY2VQYXRoLFxuICAgICAgICB0eXBlOiBcImRpcmVjdG9yeVwiIGFzIGNvbnN0LFxuICAgICAgICBzaXplOiAwLFxuICAgICAgICBjcmVhdGVkQXQ6IG5ldyBEYXRlKDApLFxuICAgICAgICBtb2RpZmllZEF0OiBuZXcgRGF0ZSgwKSxcbiAgICAgIH07XG4gICAgfVxuICB9XG59XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBlbXB0eSBmaWxlc3lzdGVtIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKiogTm9ybWFsaXplIHBhdGhzIGZvciB0aGUgaW4tbWVtb3J5IGVtcHR5IGZpbGVzeXN0ZW0gbmFtZXNwYWNlLiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplRW1wdHlGaWxlc3lzdGVtUGF0aChpbnB1dFBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHRyaW1tZWQgPSBpbnB1dFBhdGgudHJpbSgpO1xuICBpZiAoIXRyaW1tZWQgfHwgdHJpbW1lZCA9PT0gXCIuXCIpIHJldHVybiBcIi9cIjtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IHRyaW1tZWQuc3RhcnRzV2l0aChcIi9cIilcbiAgICA/IHBhdGgubm9ybWFsaXplKHRyaW1tZWQpXG4gICAgOiBwYXRoLm5vcm1hbGl6ZShgLyR7dHJpbW1lZH1gKTtcbiAgcmV0dXJuIG5vcm1hbGl6ZWQgPT09IFwiLlwiID8gXCIvXCIgOiBub3JtYWxpemVkO1xufVxuXG4vKipcbiAqIFJlYWQtb25seSBpbi1tZW1vcnkge0BsaW5rIFdvcmtzcGFjZUZpbGVzeXN0ZW19IHdpdGggYSBzaW5nbGUgZW1wdHkgcm9vdC5cbiAqIFVzZSB7QGxpbmsgZW1wdHlGaWxlc3lzdGVtfSByYXRoZXIgdGhhbiBjb25zdHJ1Y3RpbmcgZGlyZWN0bHkuXG4gKi9cbmNsYXNzIEVtcHR5RmlsZXN5c3RlbSBleHRlbmRzIE1hc3RyYUZpbGVzeXN0ZW0ge1xuICByZWFkb25seSBpZCA9IFwiZW1wdHktZnNcIjtcbiAgcmVhZG9ubHkgbmFtZSA9IFwiRW1wdHlGaWxlc3lzdGVtXCI7XG4gIHJlYWRvbmx5IHByb3ZpZGVyID0gXCJlbXB0eVwiO1xuICByZWFkb25seSByZWFkT25seSA9IHRydWU7XG4gIHN0YXR1czogUHJvdmlkZXJTdGF0dXMgPSBcInBlbmRpbmdcIjtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcih7IG5hbWU6IFwiRW1wdHlGaWxlc3lzdGVtXCIgfSk7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBpbml0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIE5vIHJlbW90ZSBvciBvbi1kaXNrIHJlc291cmNlcyB0byBwcm92aXNpb24uXG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBkZXN0cm95KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIFN0YXRlbGVzczsgbm90aGluZyB0byByZWxlYXNlLlxuICB9XG5cbiAgZ2V0SW5mbygpOiBGaWxlc3lzdGVtSW5mbyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiB0aGlzLmlkLFxuICAgICAgbmFtZTogdGhpcy5uYW1lLFxuICAgICAgcHJvdmlkZXI6IHRoaXMucHJvdmlkZXIsXG4gICAgICBzdGF0dXM6IHRoaXMuc3RhdHVzLFxuICAgICAgcmVhZE9ubHk6IHRoaXMucmVhZE9ubHksXG4gICAgfTtcbiAgfVxuXG4gIGdldEluc3RydWN0aW9ucygpOiBzdHJpbmcge1xuICAgIHJldHVybiBcIlRoaXMgZmlsZXN5c3RlbSBpcyBlbXB0eSBhbmQgcmVhZC1vbmx5LlwiO1xuICB9XG5cbiAgcHJpdmF0ZSByb290U3RhdCgpOiBGaWxlU3RhdCB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6IFwiL1wiLFxuICAgICAgcGF0aDogXCIvXCIsXG4gICAgICB0eXBlOiBcImRpcmVjdG9yeVwiLFxuICAgICAgc2l6ZTogMCxcbiAgICAgIGNyZWF0ZWRBdDogRU1QVFlfRklMRVNZU1RFTV9FUE9DSCxcbiAgICAgIG1vZGlmaWVkQXQ6IEVNUFRZX0ZJTEVTWVNURU1fRVBPQ0gsXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYXNzZXJ0V3JpdGFibGUob3BlcmF0aW9uOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aHJvdyBuZXcgV29ya3NwYWNlUmVhZE9ubHlFcnJvcihvcGVyYXRpb24pO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgcmVhZEZpbGUoaW5wdXRQYXRoOiBzdHJpbmcsIF9vcHRpb25zPzogUmVhZE9wdGlvbnMpOiBQcm9taXNlPHN0cmluZyB8IEJ1ZmZlcj4ge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKTtcbiAgICBjb25zdCBub3JtYWxpemVkID0gbm9ybWFsaXplRW1wdHlGaWxlc3lzdGVtUGF0aChpbnB1dFBhdGgpO1xuICAgIGlmIChub3JtYWxpemVkID09PSBcIi9cIikge1xuICAgICAgdGhyb3cgbmV3IElzRGlyZWN0b3J5RXJyb3Iobm9ybWFsaXplZCk7XG4gICAgfVxuICAgIHRocm93IG5ldyBGaWxlTm90Rm91bmRFcnJvcihub3JtYWxpemVkKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIHdyaXRlRmlsZShcbiAgICBfaW5wdXRQYXRoOiBzdHJpbmcsXG4gICAgX2NvbnRlbnQ6IEZpbGVDb250ZW50LFxuICAgIF9vcHRpb25zPzogV3JpdGVPcHRpb25zLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZVJlYWR5KCk7XG4gICAgdGhpcy5hc3NlcnRXcml0YWJsZShcIndyaXRlRmlsZVwiKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIGFwcGVuZEZpbGUoX2lucHV0UGF0aDogc3RyaW5nLCBfY29udGVudDogRmlsZUNvbnRlbnQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZVJlYWR5KCk7XG4gICAgdGhpcy5hc3NlcnRXcml0YWJsZShcImFwcGVuZEZpbGVcIik7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBkZWxldGVGaWxlKGlucHV0UGF0aDogc3RyaW5nLCBvcHRpb25zPzogUmVtb3ZlT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKTtcbiAgICBjb25zdCBub3JtYWxpemVkID0gbm9ybWFsaXplRW1wdHlGaWxlc3lzdGVtUGF0aChpbnB1dFBhdGgpO1xuICAgIGlmIChub3JtYWxpemVkID09PSBcIi9cIikge1xuICAgICAgdGhyb3cgbmV3IElzRGlyZWN0b3J5RXJyb3Iobm9ybWFsaXplZCk7XG4gICAgfVxuICAgIGlmIChvcHRpb25zPy5mb3JjZSkgcmV0dXJuO1xuICAgIHRocm93IG5ldyBGaWxlTm90Rm91bmRFcnJvcihub3JtYWxpemVkKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIGNvcHlGaWxlKHNyYzogc3RyaW5nLCBfZGVzdDogc3RyaW5nLCBfb3B0aW9ucz86IENvcHlPcHRpb25zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRTcmMgPSBub3JtYWxpemVFbXB0eUZpbGVzeXN0ZW1QYXRoKHNyYyk7XG4gICAgaWYgKG5vcm1hbGl6ZWRTcmMgIT09IFwiL1wiKSB7XG4gICAgICB0aHJvdyBuZXcgRmlsZU5vdEZvdW5kRXJyb3Iobm9ybWFsaXplZFNyYyk7XG4gICAgfVxuICAgIHRocm93IG5ldyBJc0RpcmVjdG9yeUVycm9yKG5vcm1hbGl6ZWRTcmMpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgbW92ZUZpbGUoc3JjOiBzdHJpbmcsIGRlc3Q6IHN0cmluZywgb3B0aW9ucz86IENvcHlPcHRpb25zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5jb3B5RmlsZShzcmMsIGRlc3QsIG9wdGlvbnMpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgbWtkaXIoX2lucHV0UGF0aDogc3RyaW5nLCBfb3B0aW9ucz86IHsgcmVjdXJzaXZlPzogYm9vbGVhbiB9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpO1xuICAgIHRoaXMuYXNzZXJ0V3JpdGFibGUoXCJta2RpclwiKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIHJtZGlyKGlucHV0UGF0aDogc3RyaW5nLCBvcHRpb25zPzogUmVtb3ZlT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKTtcbiAgICBjb25zdCBub3JtYWxpemVkID0gbm9ybWFsaXplRW1wdHlGaWxlc3lzdGVtUGF0aChpbnB1dFBhdGgpO1xuICAgIGlmIChub3JtYWxpemVkID09PSBcIi9cIikge1xuICAgICAgdGhyb3cgbmV3IERpcmVjdG9yeU5vdEVtcHR5RXJyb3Iobm9ybWFsaXplZCk7XG4gICAgfVxuICAgIGlmIChvcHRpb25zPy5mb3JjZSkgcmV0dXJuO1xuICAgIHRocm93IG5ldyBEaXJlY3RvcnlOb3RGb3VuZEVycm9yKG5vcm1hbGl6ZWQpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgcmVhZGRpcihpbnB1dFBhdGg6IHN0cmluZywgX29wdGlvbnM/OiBMaXN0T3B0aW9ucyk6IFByb21pc2U8RmlsZUVudHJ5W10+IHtcbiAgICBhd2FpdCB0aGlzLmVuc3VyZVJlYWR5KCk7XG4gICAgY29uc3Qgbm9ybWFsaXplZCA9IG5vcm1hbGl6ZUVtcHR5RmlsZXN5c3RlbVBhdGgoaW5wdXRQYXRoKTtcbiAgICBpZiAobm9ybWFsaXplZCA9PT0gXCIvXCIpIHJldHVybiBbXTtcbiAgICB0aHJvdyBuZXcgRGlyZWN0b3J5Tm90Rm91bmRFcnJvcihub3JtYWxpemVkKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIGV4aXN0cyhpbnB1dFBhdGg6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGF3YWl0IHRoaXMuZW5zdXJlUmVhZHkoKTtcbiAgICByZXR1cm4gbm9ybWFsaXplRW1wdHlGaWxlc3lzdGVtUGF0aChpbnB1dFBhdGgpID09PSBcIi9cIjtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIHN0YXQoaW5wdXRQYXRoOiBzdHJpbmcpOiBQcm9taXNlPEZpbGVTdGF0PiB7XG4gICAgYXdhaXQgdGhpcy5lbnN1cmVSZWFkeSgpO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBub3JtYWxpemVFbXB0eUZpbGVzeXN0ZW1QYXRoKGlucHV0UGF0aCk7XG4gICAgaWYgKG5vcm1hbGl6ZWQgPT09IFwiL1wiKSByZXR1cm4gdGhpcy5yb290U3RhdCgpO1xuICAgIHRocm93IG5ldyBGaWxlTm90Rm91bmRFcnJvcihub3JtYWxpemVkKTtcbiAgfVxufVxuXG4vKiogTWVtb2l6ZWQgc2luZ2xldG9uIGVtcHR5IHJlYWQtb25seSBmaWxlc3lzdGVtIGZvciBuby1vcCBtb3VudHMuICovXG5leHBvcnQgY29uc3QgZW1wdHlGaWxlc3lzdGVtID0gZnVuY3Rpb25Nb2R1bGUubWVtb2l6ZSgoKSA9PiBuZXcgRW1wdHlGaWxlc3lzdGVtKCkpO1xuIl19
|