@dbx-tools/appkit-lakebox 0.0.0-stage → 0.9.131
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/LICENSE +202 -0
- package/README.md +104 -2
- package/index.ts +32 -0
- package/lib/index.d.ts +28 -0
- package/lib/index.js +26 -0
- package/lib/src/_package.d.ts +2 -0
- package/lib/src/_package.js +11 -0
- package/lib/src/_resource-registry.d.ts +41 -0
- package/lib/src/_resource-registry.js +128 -0
- package/lib/src/_service-snapshots.d.ts +55 -0
- package/lib/src/_service-snapshots.js +65 -0
- package/lib/src/config.d.ts +40 -0
- package/lib/src/config.js +86 -0
- package/lib/src/desktop.d.ts +6 -0
- package/lib/src/desktop.js +88 -0
- package/lib/src/metrics.d.ts +59 -0
- package/lib/src/metrics.js +151 -0
- package/lib/src/plugin.d.ts +259 -0
- package/lib/src/plugin.js +329 -0
- package/lib/src/routes.d.ts +75 -0
- package/lib/src/routes.js +441 -0
- package/lib/src/runtime.d.ts +154 -0
- package/lib/src/runtime.js +760 -0
- package/lib/src/services.d.ts +101 -0
- package/lib/src/services.js +188 -0
- package/lib/src/skills.d.ts +5 -0
- package/lib/src/skills.js +21 -0
- package/lib/src/user.d.ts +46 -0
- package/lib/src/user.js +76 -0
- package/lib/src/workspace.d.ts +43 -0
- package/lib/src/workspace.js +138 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +167 -4
- package/scripts/desktop-prerequisites.sh +66 -0
- package/scripts/desktop-session.sh +307 -0
- package/scripts/lakebox-admin.sh +234 -0
- package/scripts/lakebox-service.py +449 -0
- package/skills/html-page/SKILL.md +40 -0
- package/skills/jupyter-lab/SKILL.md +32 -0
- package/skills/lakebox-showcase/SKILL.md +66 -0
- package/skills/network-speed-test/SKILL.md +29 -0
- package/skills/realtime-whiteboard/SKILL.md +28 -0
- package/src/_package.ts +11 -0
- package/src/_resource-registry.ts +160 -0
- package/src/_service-snapshots.ts +84 -0
- package/src/config.ts +128 -0
- package/src/desktop.ts +97 -0
- package/src/metrics.ts +178 -0
- package/src/plugin.ts +446 -0
- package/src/routes.ts +524 -0
- package/src/runtime.ts +952 -0
- package/src/services.ts +239 -0
- package/src/skills.ts +23 -0
- package/src/user.ts +88 -0
- package/src/workspace.ts +185 -0
|
@@ -0,0 +1,760 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { exec } from "@dbx-tools/core";
|
|
3
|
+
import { SshKeyStore } from "@dbx-tools/lakebox/key-store";
|
|
4
|
+
import { ensureLakeboxRunning, ensureLakeboxStopped, lakeboxIdleTimeoutSeconds, normalizeLakeboxStatus, } from "@dbx-tools/lakebox/lifecycle";
|
|
5
|
+
import { isLakeboxUnavailable, LakeboxApiError, LakeboxClient, } from "@dbx-tools/lakebox/rest";
|
|
6
|
+
import { SshCommand, SshSession } from "@dbx-tools/lakebox/session";
|
|
7
|
+
import { errorUtils, log } from "@dbx-tools/shared-core";
|
|
8
|
+
import { LAKEBOX_BUILT_IN_SERVICES, lakeboxBuiltInServiceNameSchema, lakeboxCommandRequestSchema, lakeboxServiceLogsRequestSchema, } from "@dbx-tools/shared-lakebox";
|
|
9
|
+
import { readPackageResource } from "./_package.js";
|
|
10
|
+
import { stoppedSnapshotServices } from "./_service-snapshots.js";
|
|
11
|
+
import { LakeboxMetrics } from "./metrics.js";
|
|
12
|
+
import { LakeboxRouteRegistry } from "./routes.js";
|
|
13
|
+
import { builtInDefinition, idleBuiltInService, imageDefinition, LakeboxControllerServiceSchema, serviceRoute, toLakeboxService, } from "./services.js";
|
|
14
|
+
import { LAKEBOX_RUNTIME_ROOT, lakeboxUser } from "./user.js";
|
|
15
|
+
const ADMIN_SCRIPT = readPackageResource("scripts", "lakebox-admin.sh");
|
|
16
|
+
const HELPERS = {
|
|
17
|
+
"lakebox-service": readPackageResource("scripts", "lakebox-service.py"),
|
|
18
|
+
"desktop-session": readPackageResource("scripts", "desktop-session.sh"),
|
|
19
|
+
"desktop-prerequisites": readPackageResource("scripts", "desktop-prerequisites.sh"),
|
|
20
|
+
};
|
|
21
|
+
const CONTROLLER = `${LAKEBOX_RUNTIME_ROOT}/bin/lakebox-service`;
|
|
22
|
+
const ENTRY_TTL_MS = 5_000;
|
|
23
|
+
const SETUP_TIMEOUT_MS = 600_000;
|
|
24
|
+
const METRICS_LEASE_MS = 60_000;
|
|
25
|
+
const IDLE_CHECK_MS = 30_000;
|
|
26
|
+
const SSH_KEY_OWNER = "app-service-principal";
|
|
27
|
+
const LEGACY_NAME = /^dbx-(?!lakebox-)[a-z]+-[a-z]+-[0-9a-f]{8}(?:_uid_[A-Za-z0-9_-]+_exp_[0-9]+)?$/;
|
|
28
|
+
const LEGACY_SCHEMA_PREFIX = "dbx_tools_databricks_sandbox";
|
|
29
|
+
const logger = log.logger("appkit-lakebox:runtime");
|
|
30
|
+
/**
|
|
31
|
+
* Owns the single lazily created Lakebox of one application.
|
|
32
|
+
*
|
|
33
|
+
* Every Databricks Lakebox REST call uses the app service principal supplied
|
|
34
|
+
* through {@link initialize}; request identity only selects the internal Linux
|
|
35
|
+
* account. Each authenticated identity maps through one FNV-1a hash to a locked
|
|
36
|
+
* account, persistent home, route segment, and service ports. Lifecycle and
|
|
37
|
+
* per-boot bootstrap are serialized in-process; the persistent resource
|
|
38
|
+
* registry serializes first creation across replicas.
|
|
39
|
+
*/
|
|
40
|
+
export class LakeboxRuntime {
|
|
41
|
+
config;
|
|
42
|
+
routes;
|
|
43
|
+
metrics;
|
|
44
|
+
keys;
|
|
45
|
+
stopParentTerminationSignal;
|
|
46
|
+
shutdownController = new AbortController();
|
|
47
|
+
api;
|
|
48
|
+
identity = () => undefined;
|
|
49
|
+
/** In-memory identities of routed users; never persisted. */
|
|
50
|
+
routedIdentities = new Map();
|
|
51
|
+
cached;
|
|
52
|
+
boot;
|
|
53
|
+
/** Last boot that completed runtime bootstrap and produced a metrics sample. */
|
|
54
|
+
readyBootKey;
|
|
55
|
+
converging;
|
|
56
|
+
waking;
|
|
57
|
+
metricsLease;
|
|
58
|
+
idleTimer;
|
|
59
|
+
lastActivity = Date.now();
|
|
60
|
+
activeCommands = 0;
|
|
61
|
+
/** Last service states per user hash, kept after an idle session release. */
|
|
62
|
+
lastServices = new Map();
|
|
63
|
+
lastServicesObservedAt = new Map();
|
|
64
|
+
resourceRegistry;
|
|
65
|
+
serviceSnapshots;
|
|
66
|
+
closing;
|
|
67
|
+
/** Creates a runtime from resolved plugin configuration. */
|
|
68
|
+
constructor(config) {
|
|
69
|
+
this.config = config;
|
|
70
|
+
this.keys = new SshKeyStore(config.keyDirectory);
|
|
71
|
+
this.routes = new LakeboxRouteRegistry(config.routePrefix, {
|
|
72
|
+
user: (headers) => {
|
|
73
|
+
const identity = this.identity(headers);
|
|
74
|
+
if (!identity)
|
|
75
|
+
return undefined;
|
|
76
|
+
const user = this.user(identity);
|
|
77
|
+
this.routedIdentities.set(user.hash, identity);
|
|
78
|
+
return user;
|
|
79
|
+
},
|
|
80
|
+
resolve: (user, service) => this.resolveRoute(user, service),
|
|
81
|
+
unavailable: (user, service) => this.markUnavailable(user, service),
|
|
82
|
+
});
|
|
83
|
+
this.metrics = new LakeboxMetrics((signal) => this.readMetrics(signal), config.metricsIntervalSeconds * 1_000);
|
|
84
|
+
this.stopParentTerminationSignal = exec.onParentTerminationSignal(() => this.routes.beginShutdown());
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Supplies app service-principal credentials and the request identity
|
|
88
|
+
* resolver used by routes.
|
|
89
|
+
*/
|
|
90
|
+
initialize(auth, identity, serviceSnapshots, resourceRegistry) {
|
|
91
|
+
this.api = new LakeboxClient(auth);
|
|
92
|
+
if (identity)
|
|
93
|
+
this.identity = identity;
|
|
94
|
+
if (serviceSnapshots)
|
|
95
|
+
this.serviceSnapshots = serviceSnapshots;
|
|
96
|
+
if (resourceRegistry)
|
|
97
|
+
this.resourceRegistry = resourceRegistry;
|
|
98
|
+
}
|
|
99
|
+
/** Derives the Lakebox account for one authenticated identity. */
|
|
100
|
+
user(identity) {
|
|
101
|
+
return lakeboxUser(identity, this.config.routePrefix);
|
|
102
|
+
}
|
|
103
|
+
/** Summarizes the app Lakebox for one user without creating it. */
|
|
104
|
+
async summary(identity, signal) {
|
|
105
|
+
const user = this.user(identity);
|
|
106
|
+
const base = { auto: this.config.auto, name: "Lakebox", user };
|
|
107
|
+
let entry;
|
|
108
|
+
try {
|
|
109
|
+
entry = await this.entry(signal, true);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (isLakeboxUnavailable(error)) {
|
|
113
|
+
return {
|
|
114
|
+
...base,
|
|
115
|
+
supported: false,
|
|
116
|
+
status: "missing",
|
|
117
|
+
services: [],
|
|
118
|
+
servicesStale: false,
|
|
119
|
+
canStart: false,
|
|
120
|
+
canStop: false,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
const platformStatus = entry ? normalizeLakeboxStatus(entry.status) : "missing";
|
|
126
|
+
const status = this.productStatus(entry, platformStatus);
|
|
127
|
+
if (entry && platformStatus === "running" && status === "starting") {
|
|
128
|
+
this.wake(() => this.ready());
|
|
129
|
+
}
|
|
130
|
+
const listing = await this.serviceListing(identity, user, entry, status, signal);
|
|
131
|
+
return {
|
|
132
|
+
...base,
|
|
133
|
+
supported: true,
|
|
134
|
+
status,
|
|
135
|
+
...(entry ? { id: entry.sandboxId } : {}),
|
|
136
|
+
...(lakeboxIdleTimeoutSeconds(entry?.idleTimeout) !== undefined
|
|
137
|
+
? { idleTimeoutSeconds: lakeboxIdleTimeoutSeconds(entry?.idleTimeout) }
|
|
138
|
+
: {}),
|
|
139
|
+
services: listing.services,
|
|
140
|
+
servicesStale: listing.stale,
|
|
141
|
+
...(listing.observedAt ? { servicesObservedAt: listing.observedAt } : {}),
|
|
142
|
+
canStart: status !== "running" && status !== "starting",
|
|
143
|
+
canStop: status === "running" || status === "starting",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/** Creates the Lakebox when needed, starts it, and restores saved services. */
|
|
147
|
+
async start(signal) {
|
|
148
|
+
await this.ready(signal, true);
|
|
149
|
+
}
|
|
150
|
+
/** Stops the shared Lakebox for every user. Files and saved services persist. */
|
|
151
|
+
async stop(signal) {
|
|
152
|
+
const entry = await this.entry(signal, true);
|
|
153
|
+
if (!entry)
|
|
154
|
+
return;
|
|
155
|
+
await this.discardBoot();
|
|
156
|
+
await ensureLakeboxStopped(this.client(), entry, signal);
|
|
157
|
+
this.cached = undefined;
|
|
158
|
+
}
|
|
159
|
+
/** Permanently deletes the managed Lakebox and every user's files. */
|
|
160
|
+
async delete(signal) {
|
|
161
|
+
const entry = await this.entry(signal, true);
|
|
162
|
+
if (!entry)
|
|
163
|
+
return false;
|
|
164
|
+
await this.discardBoot();
|
|
165
|
+
await this.client().delete(entry.sandboxId, signal);
|
|
166
|
+
await this.resources().clear(this.client());
|
|
167
|
+
this.readyBootKey = undefined;
|
|
168
|
+
this.cached = { at: Date.now() };
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Runs one command as the user's account, creating or starting the Lakebox
|
|
173
|
+
* when `auto` is enabled.
|
|
174
|
+
*/
|
|
175
|
+
execute(identity, input, signal) {
|
|
176
|
+
const request = lakeboxCommandRequestSchema.parse(input);
|
|
177
|
+
const timeoutMs = request.timeoutMs ?? this.config.commandTimeoutMs;
|
|
178
|
+
const user = this.user(identity);
|
|
179
|
+
return new SshCommand(request.command, request.args, { timeoutMs, signal }, async (execution) => {
|
|
180
|
+
const boot = await this.readyUser(user, identity, execution.signal);
|
|
181
|
+
this.activeCommands += 1;
|
|
182
|
+
try {
|
|
183
|
+
return await execution.follow(boot.session.execute(request.command, request.args, {
|
|
184
|
+
user,
|
|
185
|
+
...(request.cwd ? { cwd: request.cwd } : {}),
|
|
186
|
+
...(request.env ? { env: request.env } : {}),
|
|
187
|
+
timeoutMs,
|
|
188
|
+
signal: execution.signal,
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
this.activeCommands -= 1;
|
|
193
|
+
this.touch();
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/** Lists the user's services, including idle built-ins. Never creates the Lakebox. */
|
|
198
|
+
async listServices(identity, signal) {
|
|
199
|
+
const user = this.user(identity);
|
|
200
|
+
const entry = await this.entry(signal);
|
|
201
|
+
const status = entry ? normalizeLakeboxStatus(entry.status) : "missing";
|
|
202
|
+
return (await this.serviceListing(identity, user, entry, status, signal)).services;
|
|
203
|
+
}
|
|
204
|
+
/** Creates or replaces one image service and waits until it is ready or failed. */
|
|
205
|
+
async createService(identity, input, signal) {
|
|
206
|
+
const user = this.user(identity);
|
|
207
|
+
const definition = imageDefinition(input, user);
|
|
208
|
+
const boot = await this.readyUser(user, identity, signal);
|
|
209
|
+
await this.controller(boot, user, "put", [encode(definition)], signal);
|
|
210
|
+
return this.runService(boot, user, definition, signal);
|
|
211
|
+
}
|
|
212
|
+
/** Starts a saved service or a built-in and waits until it is ready or failed. */
|
|
213
|
+
async startService(identity, name, signal) {
|
|
214
|
+
const user = this.user(identity);
|
|
215
|
+
const boot = await this.readyUser(user, identity, signal);
|
|
216
|
+
const builtIn = lakeboxBuiltInServiceNameSchema.safeParse(name);
|
|
217
|
+
if (builtIn.success) {
|
|
218
|
+
const definition = builtInDefinition(builtIn.data, user);
|
|
219
|
+
await this.controller(boot, user, "put", [encode(definition)], signal);
|
|
220
|
+
return this.runService(boot, user, definition, signal);
|
|
221
|
+
}
|
|
222
|
+
const saved = (await this.refreshServices(boot, user, identity, signal)).get(name);
|
|
223
|
+
if (!saved)
|
|
224
|
+
throw new Error(`Lakebox service ${name} does not exist`);
|
|
225
|
+
return this.runService(boot, user, saved.definition, signal);
|
|
226
|
+
}
|
|
227
|
+
/** Stops one running service without removing its definition. */
|
|
228
|
+
async stopService(identity, name, signal) {
|
|
229
|
+
const user = this.user(identity);
|
|
230
|
+
const boot = await this.readyUser(user, identity, signal);
|
|
231
|
+
const stopped = LakeboxControllerServiceSchema.parse(await this.controller(boot, user, "stop", [name], signal));
|
|
232
|
+
this.cacheService(boot, user, stopped);
|
|
233
|
+
return toLakeboxService(stopped, user, this.config.routePrefix);
|
|
234
|
+
}
|
|
235
|
+
/** Stops and deletes one saved service. Mounted home directories are preserved. */
|
|
236
|
+
async removeService(identity, name, signal) {
|
|
237
|
+
const user = this.user(identity);
|
|
238
|
+
const boot = await this.readyUser(user, identity, signal);
|
|
239
|
+
const result = (await this.controller(boot, user, "remove", [name], signal));
|
|
240
|
+
if (result.removed === true)
|
|
241
|
+
await this.refreshServices(boot, user, identity, signal);
|
|
242
|
+
return result.removed === true;
|
|
243
|
+
}
|
|
244
|
+
/** Reads a bounded tail of one service log. */
|
|
245
|
+
async serviceLogs(identity, input, signal) {
|
|
246
|
+
const request = lakeboxServiceLogsRequestSchema.parse(input);
|
|
247
|
+
const user = this.user(identity);
|
|
248
|
+
const entry = await this.entry(signal);
|
|
249
|
+
if (!entry || normalizeLakeboxStatus(entry.status) !== "running")
|
|
250
|
+
return { log: "" };
|
|
251
|
+
const boot = await this.readyUser(user, identity, signal);
|
|
252
|
+
const result = (await this.controller(boot, user, "logs", [request.name, String(request.maxLines), String(request.maxChars)], signal));
|
|
253
|
+
return { log: result.log ?? "" };
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Returns recent metrics and keeps sampling for one lease interval. Sampling
|
|
257
|
+
* runs only while the Lakebox runs and a caller is watching, so metrics never
|
|
258
|
+
* keep an otherwise idle Lakebox awake.
|
|
259
|
+
*/
|
|
260
|
+
async metricsResponse(signal) {
|
|
261
|
+
const entry = await this.entry(signal);
|
|
262
|
+
const platformStatus = entry ? normalizeLakeboxStatus(entry.status) : "missing";
|
|
263
|
+
if (platformStatus !== "running") {
|
|
264
|
+
this.metrics.stop();
|
|
265
|
+
return { status: platformStatus, series: [] };
|
|
266
|
+
}
|
|
267
|
+
if (!entry || !this.boot || this.boot.key !== this.bootKey(entry)) {
|
|
268
|
+
this.metrics.stop();
|
|
269
|
+
this.wake(() => this.ready());
|
|
270
|
+
return { status: "starting", series: [] };
|
|
271
|
+
}
|
|
272
|
+
this.leaseMetrics();
|
|
273
|
+
return {
|
|
274
|
+
status: this.productStatus(entry, platformStatus),
|
|
275
|
+
series: [...this.metrics.series()],
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
/** Subscribes to metrics snapshots while the Lakebox runs. */
|
|
279
|
+
subscribeMetrics(listener) {
|
|
280
|
+
this.metrics.on("snapshot", listener);
|
|
281
|
+
if (this.boot?.key === this.readyBootKey)
|
|
282
|
+
this.metrics.start();
|
|
283
|
+
return () => {
|
|
284
|
+
this.metrics.off("snapshot", listener);
|
|
285
|
+
this.leaseMetrics();
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Deletes legacy per-user Lakeboxes and drops legacy ownership schemas.
|
|
290
|
+
*
|
|
291
|
+
* There is no migration: the earlier one-machine-per-user model is removed.
|
|
292
|
+
* The managed app Lakebox and Lakeboxes with other names are never touched.
|
|
293
|
+
*/
|
|
294
|
+
async cleanupLegacy(pool, signal) {
|
|
295
|
+
try {
|
|
296
|
+
const entries = await this.client().list(signal);
|
|
297
|
+
await Promise.all(entries
|
|
298
|
+
.filter((entry) => entry.name && LEGACY_NAME.test(entry.name))
|
|
299
|
+
.map(async (entry) => {
|
|
300
|
+
await this.client().delete(entry.sandboxId, signal);
|
|
301
|
+
logger.info("deleted legacy per-user Lakebox", {
|
|
302
|
+
id: entry.sandboxId,
|
|
303
|
+
name: entry.name,
|
|
304
|
+
});
|
|
305
|
+
}));
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
if (!isLakeboxUnavailable(error)) {
|
|
309
|
+
logger.warn("legacy Lakebox cleanup failed", { error: errorUtils.toError(error) });
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (!pool)
|
|
313
|
+
return;
|
|
314
|
+
try {
|
|
315
|
+
const schemas = await pool.query("SELECT nspname FROM pg_namespace WHERE nspname = $1 OR starts_with(nspname, $2)", [LEGACY_SCHEMA_PREFIX, `${LEGACY_SCHEMA_PREFIX}_`]);
|
|
316
|
+
for (const row of schemas.rows) {
|
|
317
|
+
const schema = String(row.nspname);
|
|
318
|
+
await pool.query(`DROP SCHEMA IF EXISTS "${schema.replaceAll('"', '""')}" CASCADE`);
|
|
319
|
+
logger.info("dropped legacy Lakebox ownership schema", { schema });
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
logger.warn("legacy ownership schema cleanup failed", { error: errorUtils.toError(error) });
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/** Cancels in-flight work before teardown. */
|
|
327
|
+
abortActiveOperations() {
|
|
328
|
+
if (!this.shutdownController.signal.aborted)
|
|
329
|
+
this.shutdownController.abort();
|
|
330
|
+
}
|
|
331
|
+
/** Closes routes, metrics, and the SSH session without changing the Lakebox. */
|
|
332
|
+
close() {
|
|
333
|
+
this.abortActiveOperations();
|
|
334
|
+
this.routes.beginShutdown();
|
|
335
|
+
this.closing ??= (async () => {
|
|
336
|
+
try {
|
|
337
|
+
if (this.metricsLease)
|
|
338
|
+
clearTimeout(this.metricsLease);
|
|
339
|
+
this.metrics.stop();
|
|
340
|
+
await this.routes.close();
|
|
341
|
+
await this.boot?.session.close();
|
|
342
|
+
this.boot = undefined;
|
|
343
|
+
}
|
|
344
|
+
finally {
|
|
345
|
+
this.stopParentTerminationSignal();
|
|
346
|
+
}
|
|
347
|
+
})();
|
|
348
|
+
return this.closing;
|
|
349
|
+
}
|
|
350
|
+
client() {
|
|
351
|
+
if (!this.api)
|
|
352
|
+
throw new Error("The Lakebox runtime has no app service-principal credentials");
|
|
353
|
+
return this.api;
|
|
354
|
+
}
|
|
355
|
+
resources() {
|
|
356
|
+
if (!this.resourceRegistry)
|
|
357
|
+
throw new Error("The Lakebox runtime has no resource registry");
|
|
358
|
+
return this.resourceRegistry;
|
|
359
|
+
}
|
|
360
|
+
/** Returns the managed Lakebox entry, cached briefly to keep routes cheap. */
|
|
361
|
+
async entry(signal, fresh = false) {
|
|
362
|
+
if (!fresh && this.cached && Date.now() - this.cached.at < ENTRY_TTL_MS) {
|
|
363
|
+
return this.cached.entry;
|
|
364
|
+
}
|
|
365
|
+
const entry = await this.resources().read(this.client(), signal);
|
|
366
|
+
this.cached = { ...(entry ? { entry } : {}), at: Date.now() };
|
|
367
|
+
if (!entry || normalizeLakeboxStatus(entry.status) !== "running") {
|
|
368
|
+
this.readyBootKey = undefined;
|
|
369
|
+
}
|
|
370
|
+
if (this.boot && (!entry || this.bootKey(entry) !== this.boot.key))
|
|
371
|
+
await this.discardBoot();
|
|
372
|
+
return entry;
|
|
373
|
+
}
|
|
374
|
+
bootKey(entry) {
|
|
375
|
+
return `${entry.sandboxId}\0${entry.lastStartTime ?? ""}`;
|
|
376
|
+
}
|
|
377
|
+
productStatus(entry, status) {
|
|
378
|
+
return entry && status === "running" && this.readyBootKey !== this.bootKey(entry)
|
|
379
|
+
? "starting"
|
|
380
|
+
: status;
|
|
381
|
+
}
|
|
382
|
+
/** Serializes create, start, connect, and bootstrap for the current boot. */
|
|
383
|
+
ready(signal, explicit = false) {
|
|
384
|
+
const current = this.boot;
|
|
385
|
+
if (current && this.cached?.entry && this.bootKey(this.cached.entry) === current.key) {
|
|
386
|
+
if (Date.now() - this.cached.at < ENTRY_TTL_MS)
|
|
387
|
+
return Promise.resolve(current);
|
|
388
|
+
}
|
|
389
|
+
this.converging ??= this.converge(signal, explicit).finally(() => {
|
|
390
|
+
this.converging = undefined;
|
|
391
|
+
});
|
|
392
|
+
return this.converging;
|
|
393
|
+
}
|
|
394
|
+
async converge(signal, explicit) {
|
|
395
|
+
const operationSignal = signal
|
|
396
|
+
? AbortSignal.any([signal, this.shutdownController.signal])
|
|
397
|
+
: this.shutdownController.signal;
|
|
398
|
+
let entry = await this.entry(operationSignal, true);
|
|
399
|
+
if (!entry || normalizeLakeboxStatus(entry.status) !== "running") {
|
|
400
|
+
if (!this.config.auto && !explicit) {
|
|
401
|
+
throw new Error(`Lakebox is ${entry ? entry.status : "not created"}; start it explicitly because auto is false`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
entry ??= await this.resources().getOrCreate(this.client(), operationSignal);
|
|
405
|
+
if (lakeboxIdleTimeoutSeconds(entry.idleTimeout) !== this.config.idleTimeoutSeconds) {
|
|
406
|
+
entry = await this.client().setIdleTimeout(entry.sandboxId, this.config.idleTimeoutSeconds, operationSignal);
|
|
407
|
+
}
|
|
408
|
+
entry = await ensureLakeboxRunning(this.client(), entry, operationSignal);
|
|
409
|
+
this.cached = { entry, at: Date.now() };
|
|
410
|
+
const key = this.bootKey(entry);
|
|
411
|
+
if (this.boot?.key === key)
|
|
412
|
+
return this.boot;
|
|
413
|
+
await this.discardBoot();
|
|
414
|
+
const session = await this.connect(entry, operationSignal);
|
|
415
|
+
const boot = {
|
|
416
|
+
key,
|
|
417
|
+
entry,
|
|
418
|
+
session,
|
|
419
|
+
users: new Map(),
|
|
420
|
+
services: new Map(),
|
|
421
|
+
starting: new Map(),
|
|
422
|
+
};
|
|
423
|
+
try {
|
|
424
|
+
const restored = await this.bootstrap(session, operationSignal);
|
|
425
|
+
this.metrics.stop();
|
|
426
|
+
this.metrics.seed((await this.admin(session, ["metrics"], operationSignal)).stdout);
|
|
427
|
+
this.boot = boot;
|
|
428
|
+
this.readyBootKey = key;
|
|
429
|
+
this.watchIdle();
|
|
430
|
+
if (this.metrics.listenerCount("snapshot") > 0)
|
|
431
|
+
this.metrics.start();
|
|
432
|
+
for (const hash of restored)
|
|
433
|
+
void this.restoreUser(boot, hash);
|
|
434
|
+
return boot;
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
await session.close();
|
|
438
|
+
throw error;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
async connect(entry, signal) {
|
|
442
|
+
const api = this.client();
|
|
443
|
+
const scope = await api.workspaceScope();
|
|
444
|
+
const key = await this.keys.ensureRegistered(api, SSH_KEY_OWNER, signal);
|
|
445
|
+
const gatewayHost = entry.gatewayHost ?? key.gatewayHost;
|
|
446
|
+
if (!gatewayHost)
|
|
447
|
+
throw new Error("Databricks Lakebox did not return an SSH gateway host");
|
|
448
|
+
const port = this.config.gatewayPort;
|
|
449
|
+
const knownHost = await this.keys.knownHost(scope, SSH_KEY_OWNER, gatewayHost, port);
|
|
450
|
+
const session = new SshSession({
|
|
451
|
+
host: gatewayHost,
|
|
452
|
+
port,
|
|
453
|
+
username: entry.sandboxId,
|
|
454
|
+
privateKey: key.privateKey,
|
|
455
|
+
privateKeyPath: key.privateKeyPath,
|
|
456
|
+
knownHostsPath: this.keys.knownHostsPath(scope, SSH_KEY_OWNER, gatewayHost, port),
|
|
457
|
+
connectTimeoutMs: this.config.connectTimeoutMs,
|
|
458
|
+
sshTransport: this.config.sshTransport,
|
|
459
|
+
ssh2Patch: this.config.ssh2Patch,
|
|
460
|
+
...(knownHost ? { knownHost } : {}),
|
|
461
|
+
rememberHost: (fingerprint, hostKey) => this.keys.rememberHost(scope, SSH_KEY_OWNER, gatewayHost, port, fingerprint, hostKey),
|
|
462
|
+
});
|
|
463
|
+
try {
|
|
464
|
+
await session.connect();
|
|
465
|
+
return session;
|
|
466
|
+
}
|
|
467
|
+
catch (error) {
|
|
468
|
+
await session.close();
|
|
469
|
+
throw error;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/** Runs the fixed privileged bootstrap and returns the restored user hashes. */
|
|
473
|
+
async bootstrap(session, signal) {
|
|
474
|
+
const helpers = Object.entries(HELPERS).map(([name, content]) => `${name}=${Buffer.from(content).toString("base64")}`);
|
|
475
|
+
const result = await this.admin(session, ["bootstrap", ...helpers], signal);
|
|
476
|
+
return result.stdout
|
|
477
|
+
.split("\n")
|
|
478
|
+
.filter((line) => line.startsWith("__LAKEBOX_USER__="))
|
|
479
|
+
.map((line) => line.slice("__LAKEBOX_USER__=".length).trim());
|
|
480
|
+
}
|
|
481
|
+
async admin(session, args, signal) {
|
|
482
|
+
const encoded = Buffer.from(ADMIN_SCRIPT).toString("base64");
|
|
483
|
+
const result = await session.executePrivileged("sh", ["-c", `printf %s '${encoded}' | base64 -d | sh -s -- ${args.map(shellQuote).join(" ")}`], { timeoutMs: SETUP_TIMEOUT_MS, ...(signal ? { signal } : {}) }).result;
|
|
484
|
+
if (!result.success) {
|
|
485
|
+
throw new Error(`Lakebox ${args[0]} failed: ${result.stderr.trim() || result.stdout.trim() || `exit ${result.exitCode}`}`);
|
|
486
|
+
}
|
|
487
|
+
return result;
|
|
488
|
+
}
|
|
489
|
+
/** Marks activity, readies the current boot, and converges the user's account. */
|
|
490
|
+
async readyUser(user, identity, signal) {
|
|
491
|
+
this.touch();
|
|
492
|
+
const boot = await this.ready(signal);
|
|
493
|
+
await this.convergeUser(boot, user, identity, signal);
|
|
494
|
+
return boot;
|
|
495
|
+
}
|
|
496
|
+
/** Creates or verifies the user's account once per boot. */
|
|
497
|
+
convergeUser(boot, user, identity, signal) {
|
|
498
|
+
let converged = boot.users.get(user.hash);
|
|
499
|
+
if (!converged) {
|
|
500
|
+
const digest = createHash("sha256").update(identity.trim().toLowerCase()).digest("hex");
|
|
501
|
+
converged = this.admin(boot.session, ["ensure-user", user.hash, String(user.uid), digest], signal).then(() => undefined);
|
|
502
|
+
boot.users.set(user.hash, converged);
|
|
503
|
+
converged.catch(() => boot.users.delete(user.hash));
|
|
504
|
+
}
|
|
505
|
+
return converged;
|
|
506
|
+
}
|
|
507
|
+
async restoreUser(boot, hash) {
|
|
508
|
+
const user = { name: `lakebox-${hash}`, home: `/home/lakebox-${hash}` };
|
|
509
|
+
boot.users.set(hash, Promise.resolve());
|
|
510
|
+
try {
|
|
511
|
+
const result = await boot.session.execute("python3", [CONTROLLER, "start-all"], {
|
|
512
|
+
user,
|
|
513
|
+
timeoutMs: SETUP_TIMEOUT_MS,
|
|
514
|
+
signal: this.shutdownController.signal,
|
|
515
|
+
}).result;
|
|
516
|
+
if (!result.success)
|
|
517
|
+
throw new Error(result.stderr.trim() || `exit ${result.exitCode}`);
|
|
518
|
+
}
|
|
519
|
+
catch (error) {
|
|
520
|
+
if (this.shutdownController.signal.aborted)
|
|
521
|
+
return;
|
|
522
|
+
logger.warn("Lakebox service restore failed", {
|
|
523
|
+
user: hash,
|
|
524
|
+
error: errorUtils.toError(error),
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
async controller(boot, user, command, args, signal) {
|
|
529
|
+
const result = await boot.session.execute("python3", [CONTROLLER, command, ...args], {
|
|
530
|
+
user,
|
|
531
|
+
timeoutMs: SETUP_TIMEOUT_MS,
|
|
532
|
+
...(signal ? { signal } : {}),
|
|
533
|
+
}).result;
|
|
534
|
+
if (!result.success) {
|
|
535
|
+
throw new Error(`Lakebox service ${command} failed: ${result.stderr.trim() || `exit ${result.exitCode}`}`);
|
|
536
|
+
}
|
|
537
|
+
return JSON.parse(result.stdout);
|
|
538
|
+
}
|
|
539
|
+
async runService(boot, user, definition, signal) {
|
|
540
|
+
const key = `${user.hash}\0${definition.name}`;
|
|
541
|
+
const pending = boot.starting.get(key);
|
|
542
|
+
if (pending)
|
|
543
|
+
return pending;
|
|
544
|
+
const operation = (async () => {
|
|
545
|
+
if (definition.kind === "desktop") {
|
|
546
|
+
boot.desktop ??= this.admin(boot.session, ["desktop-prerequisites"], signal).then(() => undefined);
|
|
547
|
+
boot.desktop.catch(() => {
|
|
548
|
+
boot.desktop = undefined;
|
|
549
|
+
});
|
|
550
|
+
await boot.desktop;
|
|
551
|
+
}
|
|
552
|
+
await this.admin(boot.session, ["allow-port", String(user.uid), String(definition.port)], signal);
|
|
553
|
+
const started = LakeboxControllerServiceSchema.parse(await this.controller(boot, user, "start", [definition.name], signal));
|
|
554
|
+
this.cacheService(boot, user, started);
|
|
555
|
+
return toLakeboxService(started, user, this.config.routePrefix);
|
|
556
|
+
})().finally(() => boot.starting.delete(key));
|
|
557
|
+
boot.starting.set(key, operation);
|
|
558
|
+
return operation;
|
|
559
|
+
}
|
|
560
|
+
async refreshServices(boot, user, identity, signal) {
|
|
561
|
+
await this.convergeUser(boot, user, identity, signal);
|
|
562
|
+
const response = (await this.controller(boot, user, "list", [], signal));
|
|
563
|
+
const services = new Map((response.services ?? []).map((service) => {
|
|
564
|
+
const parsed = LakeboxControllerServiceSchema.parse(service);
|
|
565
|
+
return [parsed.name, parsed];
|
|
566
|
+
}));
|
|
567
|
+
boot.services.set(user.hash, services);
|
|
568
|
+
this.lastServices.set(user.hash, services);
|
|
569
|
+
const observedAt = new Date().toISOString();
|
|
570
|
+
this.lastServicesObservedAt.set(user.hash, observedAt);
|
|
571
|
+
await this.persistServiceSnapshot(boot.entry, user, services, observedAt);
|
|
572
|
+
return services;
|
|
573
|
+
}
|
|
574
|
+
cacheService(boot, user, service) {
|
|
575
|
+
const services = boot.services.get(user.hash) ?? new Map();
|
|
576
|
+
services.set(service.name, service);
|
|
577
|
+
boot.services.set(user.hash, services);
|
|
578
|
+
this.lastServices.set(user.hash, services);
|
|
579
|
+
const observedAt = new Date().toISOString();
|
|
580
|
+
this.lastServicesObservedAt.set(user.hash, observedAt);
|
|
581
|
+
void this.persistServiceSnapshot(boot.entry, user, services, observedAt);
|
|
582
|
+
}
|
|
583
|
+
async serviceListing(identity, user, entry, status, signal) {
|
|
584
|
+
if (!entry || status === "missing") {
|
|
585
|
+
return { services: this.idleServices(user), stale: false };
|
|
586
|
+
}
|
|
587
|
+
if (status === "running" && this.boot?.key === this.bootKey(entry)) {
|
|
588
|
+
const services = await this.refreshServices(this.boot, user, identity, signal);
|
|
589
|
+
return { services: this.withBuiltIns(user, services), stale: false };
|
|
590
|
+
}
|
|
591
|
+
const memory = this.lastServices.get(user.hash);
|
|
592
|
+
if (memory) {
|
|
593
|
+
const observedAt = this.lastServicesObservedAt.get(user.hash);
|
|
594
|
+
const services = status === "running"
|
|
595
|
+
? memory
|
|
596
|
+
: stoppedSnapshotServices({
|
|
597
|
+
observedAt: observedAt ?? new Date().toISOString(),
|
|
598
|
+
definitions: [...memory.values()].map((service) => service.definition),
|
|
599
|
+
});
|
|
600
|
+
return {
|
|
601
|
+
services: this.withBuiltIns(user, services),
|
|
602
|
+
stale: true,
|
|
603
|
+
...(observedAt ? { observedAt } : {}),
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
const snapshot = await this.serviceSnapshots?.read(entry.sandboxId, user.hash);
|
|
607
|
+
return snapshot
|
|
608
|
+
? {
|
|
609
|
+
services: this.withBuiltIns(user, stoppedSnapshotServices(snapshot)),
|
|
610
|
+
stale: true,
|
|
611
|
+
observedAt: snapshot.observedAt,
|
|
612
|
+
}
|
|
613
|
+
: { services: this.idleServices(user), stale: true };
|
|
614
|
+
}
|
|
615
|
+
async persistServiceSnapshot(entry, user, services, observedAt) {
|
|
616
|
+
await this.serviceSnapshots?.write(entry.sandboxId, user.hash, {
|
|
617
|
+
observedAt,
|
|
618
|
+
definitions: [...services.values()].map((service) => service.definition),
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
withBuiltIns(user, services) {
|
|
622
|
+
const builtIns = LAKEBOX_BUILT_IN_SERVICES.map(({ name }) => {
|
|
623
|
+
const saved = services.get(name);
|
|
624
|
+
return saved
|
|
625
|
+
? toLakeboxService(saved, user, this.config.routePrefix)
|
|
626
|
+
: idleBuiltInService(name, user, this.config.routePrefix);
|
|
627
|
+
});
|
|
628
|
+
const custom = [...services.values()]
|
|
629
|
+
.filter((service) => !LAKEBOX_BUILT_IN_SERVICES.some(({ name }) => name === service.name))
|
|
630
|
+
.map((service) => toLakeboxService(service, user, this.config.routePrefix));
|
|
631
|
+
return [...builtIns, ...custom];
|
|
632
|
+
}
|
|
633
|
+
idleServices(user) {
|
|
634
|
+
return LAKEBOX_BUILT_IN_SERVICES.map(({ name }) => idleBuiltInService(name, user, this.config.routePrefix));
|
|
635
|
+
}
|
|
636
|
+
/** Resolves one routed request, waking the Lakebox or service in the background. */
|
|
637
|
+
async resolveRoute(user, name) {
|
|
638
|
+
this.touch();
|
|
639
|
+
const entry = await this.entry();
|
|
640
|
+
const running = entry && normalizeLakeboxStatus(entry.status) === "running";
|
|
641
|
+
const boot = this.boot;
|
|
642
|
+
if (!running || !boot || boot.key !== this.bootKey(entry)) {
|
|
643
|
+
if (!this.config.auto)
|
|
644
|
+
return { kind: "missing" };
|
|
645
|
+
this.wake(() => this.ready());
|
|
646
|
+
return { kind: "loading" };
|
|
647
|
+
}
|
|
648
|
+
const identity = this.routedIdentities.get(user.hash);
|
|
649
|
+
if (!identity)
|
|
650
|
+
return { kind: "missing" };
|
|
651
|
+
let service = boot.services.get(user.hash)?.get(name);
|
|
652
|
+
if (!service)
|
|
653
|
+
service = (await this.refreshServices(boot, user, identity)).get(name);
|
|
654
|
+
const builtIn = lakeboxBuiltInServiceNameSchema.safeParse(name);
|
|
655
|
+
if (!service && !builtIn.success)
|
|
656
|
+
return { kind: "missing" };
|
|
657
|
+
if (service?.state === "ready") {
|
|
658
|
+
return { kind: "ready", session: boot.session, route: serviceRoute(service.definition) };
|
|
659
|
+
}
|
|
660
|
+
if (service?.state === "error" && !boot.starting.has(`${user.hash}\0${name}`)) {
|
|
661
|
+
return { kind: "failed", message: service.error ?? "the service failed to start" };
|
|
662
|
+
}
|
|
663
|
+
const definition = service?.definition ?? builtInDefinition(builtIn.data, user);
|
|
664
|
+
this.wake(async () => {
|
|
665
|
+
if (!service)
|
|
666
|
+
await this.controller(boot, user, "put", [encode(definition)]);
|
|
667
|
+
await this.runService(boot, user, definition);
|
|
668
|
+
});
|
|
669
|
+
return { kind: "loading" };
|
|
670
|
+
}
|
|
671
|
+
markUnavailable(user, name) {
|
|
672
|
+
this.boot?.services.get(user.hash)?.delete(name);
|
|
673
|
+
this.cached = undefined;
|
|
674
|
+
}
|
|
675
|
+
wake(action) {
|
|
676
|
+
if (this.waking)
|
|
677
|
+
return;
|
|
678
|
+
this.waking = action()
|
|
679
|
+
.catch((error) => logger.warn("Lakebox wake failed", { error: errorUtils.toError(error) }))
|
|
680
|
+
.finally(() => {
|
|
681
|
+
this.waking = undefined;
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
async readMetrics(signal) {
|
|
685
|
+
const boot = this.boot;
|
|
686
|
+
if (!boot)
|
|
687
|
+
throw new Error("Lakebox is not running");
|
|
688
|
+
try {
|
|
689
|
+
return (await this.admin(boot.session, ["metrics"], signal)).stdout;
|
|
690
|
+
}
|
|
691
|
+
catch (error) {
|
|
692
|
+
this.cached = undefined;
|
|
693
|
+
throw error;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
leaseMetrics() {
|
|
697
|
+
if (!this.boot)
|
|
698
|
+
return;
|
|
699
|
+
this.metrics.start();
|
|
700
|
+
if (this.metricsLease)
|
|
701
|
+
clearTimeout(this.metricsLease);
|
|
702
|
+
this.metricsLease = setTimeout(() => {
|
|
703
|
+
if (this.metrics.listenerCount("snapshot") === 0)
|
|
704
|
+
this.metrics.stop();
|
|
705
|
+
}, METRICS_LEASE_MS);
|
|
706
|
+
this.metricsLease.unref?.();
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Releases the SSH session after the idle timeout without commands, service
|
|
710
|
+
* operations, routed traffic, open streams, or metrics watchers. An open
|
|
711
|
+
* session counts as activity for the platform watchdog, so releasing it lets
|
|
712
|
+
* the platform stop the Lakebox after its own idle timeout. The next request
|
|
713
|
+
* reconnects.
|
|
714
|
+
*/
|
|
715
|
+
watchIdle() {
|
|
716
|
+
if (this.idleTimer)
|
|
717
|
+
clearInterval(this.idleTimer);
|
|
718
|
+
this.idleTimer = setInterval(() => {
|
|
719
|
+
const idleMs = Date.now() - this.lastActivity;
|
|
720
|
+
if (!this.boot ||
|
|
721
|
+
this.converging ||
|
|
722
|
+
idleMs < this.config.idleTimeoutSeconds * 1_000 ||
|
|
723
|
+
this.activeCommands > 0 ||
|
|
724
|
+
this.boot.starting.size > 0 ||
|
|
725
|
+
this.routes.activeConnections() > 0 ||
|
|
726
|
+
this.metrics.listenerCount("snapshot") > 0) {
|
|
727
|
+
if (this.routes.activeConnections() > 0 || this.activeCommands > 0)
|
|
728
|
+
this.touch();
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
logger.info("releasing idle Lakebox session", { idleSeconds: Math.round(idleMs / 1_000) });
|
|
732
|
+
void this.discardBoot();
|
|
733
|
+
}, IDLE_CHECK_MS);
|
|
734
|
+
this.idleTimer.unref?.();
|
|
735
|
+
}
|
|
736
|
+
touch() {
|
|
737
|
+
this.lastActivity = Date.now();
|
|
738
|
+
}
|
|
739
|
+
async discardBoot() {
|
|
740
|
+
if (this.idleTimer)
|
|
741
|
+
clearInterval(this.idleTimer);
|
|
742
|
+
this.idleTimer = undefined;
|
|
743
|
+
const boot = this.boot;
|
|
744
|
+
this.boot = undefined;
|
|
745
|
+
this.metrics.stop();
|
|
746
|
+
await this.routes.closeBridges();
|
|
747
|
+
await boot?.session.close().catch(() => undefined);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
function encode(definition) {
|
|
751
|
+
return Buffer.from(JSON.stringify(definition)).toString("base64");
|
|
752
|
+
}
|
|
753
|
+
function shellQuote(value) {
|
|
754
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
755
|
+
}
|
|
756
|
+
/** Returns whether an error means the managed Lakebox no longer exists. */
|
|
757
|
+
export function isLakeboxMissing(error) {
|
|
758
|
+
return error instanceof LakeboxApiError && error.status === 404;
|
|
759
|
+
}
|
|
760
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFekMsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMzRCxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLG9CQUFvQixFQUNwQix5QkFBeUIsRUFDekIsc0JBQXNCLEdBQ3ZCLE1BQU0sOEJBQThCLENBQUM7QUFDdEMsT0FBTyxFQUNMLG9CQUFvQixFQUNwQixlQUFlLEVBQ2YsYUFBYSxHQUdkLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNwRSxPQUFPLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3pELE9BQU8sRUFDTCx5QkFBeUIsRUFDekIsK0JBQStCLEVBQy9CLDJCQUEyQixFQUMzQiwrQkFBK0IsR0FXaEMsTUFBTSwyQkFBMkIsQ0FBQztBQUNuQyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFcEQsT0FBTyxFQUEyQix1QkFBdUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRTNGLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDOUMsT0FBTyxFQUFFLG9CQUFvQixFQUErQixNQUFNLGFBQWEsQ0FBQztBQUNoRixPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLGtCQUFrQixFQUNsQixlQUFlLEVBQ2YsOEJBQThCLEVBQzlCLFlBQVksRUFDWixnQkFBZ0IsR0FHakIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLG9CQUFvQixFQUFFLFdBQVcsRUFBRSxNQUFNLFdBQVcs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VUFBVSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDcEUsQ0FBQztBQUVELFNBQVMsVUFBVSxDQUFDLEtBQWE7SUFDL0IsT0FBTyxJQUFJLEtBQUssQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUM7QUFDL0MsQ0FBQztBQUVELDJFQUEyRTtBQUMzRSxNQUFNLFVBQVUsZ0JBQWdCLENBQUMsS0FBYztJQUM3QyxPQUFPLEtBQUssWUFBWSxlQUFlLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxHQUFHLENBQUM7QUFDbEUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0ZUhhc2ggfSBmcm9tIFwibm9kZTpjcnlwdG9cIjtcbmltcG9ydCB0eXBlIHsgSW5jb21pbmdIdHRwSGVhZGVycyB9IGZyb20gXCJub2RlOmh0dHBcIjtcbmltcG9ydCB7IGV4ZWMgfSBmcm9tIFwiQGRieC10b29scy9jb3JlXCI7XG5pbXBvcnQgeyBTc2hLZXlTdG9yZSB9IGZyb20gXCJAZGJ4LXRvb2xzL2xha2Vib3gva2V5LXN0b3JlXCI7XG5pbXBvcnQge1xuICBlbnN1cmVMYWtlYm94UnVubmluZyxcbiAgZW5zdXJlTGFrZWJveFN0b3BwZWQsXG4gIGxha2Vib3hJZGxlVGltZW91dFNlY29uZHMsXG4gIG5vcm1hbGl6ZUxha2Vib3hTdGF0dXMsXG59IGZyb20gXCJAZGJ4LXRvb2xzL2xha2Vib3gvbGlmZWN5Y2xlXCI7XG5pbXBvcnQge1xuICBpc0xha2Vib3hVbmF2YWlsYWJsZSxcbiAgTGFrZWJveEFwaUVycm9yLFxuICBMYWtlYm94Q2xpZW50LFxuICB0eXBlIExha2Vib3hBdXRoLFxuICB0eXBlIExha2Vib3hFbnRyeSxcbn0gZnJvbSBcIkBkYngtdG9vbHMvbGFrZWJveC9yZXN0XCI7XG5pbXBvcnQgeyBTc2hDb21tYW5kLCBTc2hTZXNzaW9uIH0gZnJvbSBcIkBkYngtdG9vbHMvbGFrZWJveC9zZXNzaW9uXCI7XG5pbXBvcnQgeyBlcnJvclV0aWxzLCBsb2cgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHtcbiAgTEFLRUJPWF9CVUlMVF9JTl9TRVJWSUNFUyxcbiAgbGFrZWJveEJ1aWx0SW5TZXJ2aWNlTmFtZVNjaGVtYSxcbiAgbGFrZWJveENvbW1hbmRSZXF1ZXN0U2NoZW1hLFxuICBsYWtlYm94U2VydmljZUxvZ3NSZXF1ZXN0U2NoZW1hLFxuICB0eXBlIENyZWF0ZUxha2Vib3hTZXJ2aWNlUmVxdWVzdCxcbiAgdHlwZSBMYWtlYm94QnVpbHRJblNlcnZpY2VOYW1lLFxuICB0eXBlIExha2Vib3hDb21tYW5kUmVxdWVzdCxcbiAgdHlwZSBMYWtlYm94TWV0cmljc1Jlc3BvbnNlLFxuICB0eXBlIExha2Vib3hNZXRyaWNzU25hcHNob3QsXG4gIHR5cGUgTGFrZWJveFNlcnZpY2UsXG4gIHR5cGUgTGFrZWJveFNlcnZpY2VMb2dzUmVxdWVzdCxcbiAgdHlwZSBMYWtlYm94U3RhdHVzLFxuICB0eXBlIExha2Vib3hTdW1tYXJ5LFxuICB0eXBlIExha2Vib3hVc2VyLFxufSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtbGFrZWJveFwiO1xuaW1wb3J0IHsgcmVhZFBhY2thZ2VSZXNvdXJjZSB9IGZyb20gXCIuL19wYWNrYWdlLnRzXCI7XG5pbXBvcnQgeyBMYWtlYm94UmVzb3VyY2VSZWdpc3RyeSB9IGZyb20gXCIuL19yZXNvdXJjZS1yZWdpc3RyeS50c1wiO1xuaW1wb3J0IHsgTGFrZWJveFNlcnZpY2VTbmFwc2hvdHMsIHN0b3BwZWRTbmFwc2hvdFNlcnZpY2VzIH0gZnJvbSBcIi4vX3NlcnZpY2Utc25hcHNob3RzLnRzXCI7XG5pbXBvcnQgdHlwZSB7IFJlc29sdmVkTGFrZWJveFBsdWdpbkNvbmZpZyB9IGZyb20gXCIuL2NvbmZpZy50c1wiO1xuaW1wb3J0IHsgTGFrZWJveE1ldHJpY3MgfSBmcm9tIFwiLi9tZXRyaWNzLnRzXCI7XG5pbXBvcnQgeyBMYWtlYm94Um91dGVSZWdpc3RyeSwgdHlwZSBMYWtlYm94Um91dGVSZXNvbHV0aW9uIH0gZnJvbSBcIi4vcm91dGVzLnRzXCI7XG5pbXBvcnQge1xuICBidWlsdEluRGVmaW5pdGlvbixcbiAgaWRsZUJ1aWx0SW5TZXJ2aWNlLFxuICBpbWFnZURlZmluaXRpb24sXG4gIExha2Vib3hDb250cm9sbGVyU2VydmljZVNjaGVtYSxcbiAgc2VydmljZVJvdXRlLFxuICB0b0xha2Vib3hTZXJ2aWNlLFxuICB0eXBlIExha2Vib3hDb250cm9sbGVyRGVmaW5pdGlvbixcbiAgdHlwZSBMYWtlYm94Q29udHJvbGxlclNlcnZpY2UsXG59IGZyb20gXCIuL3NlcnZpY2VzLnRzXCI7XG5pbXBvcnQgeyBMQUtFQk9YX1JVTlRJTUVfUk9PVCwgbGFrZWJveFVzZXIgfSBmcm9tIFwiLi91c2VyLnRzXCI7XG5cbmNvbnN0IEFETUlOX1NDUklQVCA9IHJlYWRQYWNrYWdlUmVzb3VyY2UoXCJzY3JpcHRzXCIsIFwibGFrZWJveC1hZG1pbi5zaFwiKTtcbmNvbnN0IEhFTFBFUlMgPSB7XG4gIFwibGFrZWJveC1zZXJ2aWNlXCI6IHJlYWRQYWNrYWdlUmVzb3VyY2UoXCJzY3JpcHRzXCIsIFwibGFrZWJveC1zZXJ2aWNlLnB5XCIpLFxuICBcImRlc2t0b3Atc2Vzc2lvblwiOiByZWFkUGFja2FnZVJlc291cmNlKFwic2NyaXB0c1wiLCBcImRlc2t0b3Atc2Vzc2lvbi5zaFwiKSxcbiAgXCJkZXNrdG9wLXByZXJlcXVpc2l0ZXNcIjogcmVhZFBhY2thZ2VSZXNvdXJjZShcInNjcmlwdHNcIiwgXCJkZXNrdG9wLXByZXJlcXVpc2l0ZXMuc2hcIiksXG59IGFzIGNvbnN0O1xuY29uc3QgQ09OVFJPTExFUiA9IGAke0xBS0VCT1hfUlVOVElNRV9ST09UfS9iaW4vbGFrZWJveC1zZXJ2aWNlYDtcbmNvbnN0IEVOVFJZX1RUTF9NUyA9IDVfMDAwO1xuY29uc3QgU0VUVVBfVElNRU9VVF9NUyA9IDYwMF8wMDA7XG5jb25zdCBNRVRSSUNTX0xFQVNFX01TID0gNjBfMDAwO1xuY29uc3QgSURMRV9DSEVDS19NUyA9IDMwXzAwMDtcbmNvbnN0IFNTSF9LRVlfT1dORVIgPSBcImFwcC1zZXJ2aWNlLXByaW5jaXBhbFwiO1xuY29uc3QgTEVHQUNZX05BTUUgPVxuICAvXmRieC0oPyFsYWtlYm94LSlbYS16XSstW2Etel0rLVswLTlhLWZdezh9KD86X3VpZF9bQS1aYS16MC05Xy1dK19leHBfWzAtOV0rKT8kLztcbmNvbnN0IExFR0FDWV9TQ0hFTUFfUFJFRklYID0gXCJkYnhfdG9vbHNfZGF0YWJyaWNrc19zYW5kYm94XCI7XG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwiYXBwa2l0LWxha2Vib3g6cnVudGltZVwiKTtcblxuLyoqIFJlc29sdmVzIHRoZSBhdXRoZW50aWNhdGVkIGlkZW50aXR5IGZvciByYXcgcmVxdWVzdCBoZWFkZXJzLiAqL1xuZXhwb3J0IHR5cGUgTGFrZWJveElkZW50aXR5UmVzb2x2ZXIgPSAoaGVhZGVyczogSW5jb21pbmdIdHRwSGVhZGVycykgPT4gc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4vKiogTWluaW1hbCBMYWtlYmFzZSBwb29sIHVzZWQgdG8gZHJvcCBsZWdhY3kgb3duZXJzaGlwIHNjaGVtYXMuICovXG5leHBvcnQgaW50ZXJmYWNlIExha2Vib3hMZWdhY3lQb29sIHtcbiAgcXVlcnkoc3FsOiBzdHJpbmcsIHZhbHVlcz86IHVua25vd25bXSk6IFByb21pc2U8eyByb3dzOiBBcnJheTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4gfT47XG59XG5cbmludGVyZmFjZSBCb290IHtcbiAga2V5OiBzdHJpbmc7XG4gIGVudHJ5OiBMYWtlYm94RW50cnk7XG4gIHNlc3Npb246IFNzaFNlc3Npb247XG4gIHVzZXJzOiBNYXA8c3RyaW5nLCBQcm9taXNlPHZvaWQ+PjtcbiAgc2VydmljZXM6IE1hcDxzdHJpbmcsIE1hcDxzdHJpbmcsIExha2Vib3hDb250cm9sbGVyU2VydmljZT4+O1xuICBzdGFydGluZzogTWFwPHN0cmluZywgUHJvbWlzZTxMYWtlYm94U2VydmljZT4+O1xuICBkZXNrdG9wPzogUHJvbWlzZTx2b2lkPjtcbn1cblxuaW50ZXJmYWNlIFNlcnZpY2VMaXN0aW5nIHtcbiAgc2VydmljZXM6IExha2Vib3hTZXJ2aWNlW107XG4gIHN0YWxlOiBib29sZWFuO1xuICBvYnNlcnZlZEF0Pzogc3RyaW5nO1xufVxuXG4vKipcbiAqIE93bnMgdGhlIHNpbmdsZSBsYXppbHkgY3JlYXRlZCBMYWtlYm94IG9mIG9uZSBhcHBsaWNhdGlvbi5cbiAqXG4gKiBFdmVyeSBEYXRhYnJpY2tzIExha2Vib3ggUkVTVCBjYWxsIHVzZXMgdGhlIGFwcCBzZXJ2aWNlIHByaW5jaXBhbCBzdXBwbGllZFxuICogdGhyb3VnaCB7QGxpbmsgaW5pdGlhbGl6ZX07IHJlcXVlc3QgaWRlbnRpdHkgb25seSBzZWxlY3RzIHRoZSBpbnRlcm5hbCBMaW51eFxuICogYWNjb3VudC4gRWFjaCBhdXRoZW50aWNhdGVkIGlkZW50aXR5IG1hcHMgdGhyb3VnaCBvbmUgRk5WLTFhIGhhc2ggdG8gYSBsb2NrZWRcbiAqIGFjY291bnQsIHBlcnNpc3RlbnQgaG9tZSwgcm91dGUgc2VnbWVudCwgYW5kIHNlcnZpY2UgcG9ydHMuIExpZmVjeWNsZSBhbmRcbiAqIHBlci1ib290IGJvb3RzdHJhcCBhcmUgc2VyaWFsaXplZCBpbi1wcm9jZXNzOyB0aGUgcGVyc2lzdGVudCByZXNvdXJjZVxuICogcmVnaXN0cnkgc2VyaWFsaXplcyBmaXJzdCBjcmVhdGlvbiBhY3Jvc3MgcmVwbGljYXMuXG4gKi9cbmV4cG9ydCBjbGFzcyBMYWtlYm94UnVudGltZSB7XG4gIHJlYWRvbmx5IHJvdXRlczogTGFrZWJveFJvdXRlUmVnaXN0cnk7XG4gIHJlYWRvbmx5IG1ldHJpY3M6IExha2Vib3hNZXRyaWNzO1xuICBwcml2YXRlIHJlYWRvbmx5IGtleXM6IFNzaEtleVN0b3JlO1xuICBwcml2YXRlIHJlYWRvbmx5IHN0b3BQYXJlbnRUZXJtaW5hdGlvblNpZ25hbDogKCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSByZWFkb25seSBzaHV0ZG93bkNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gIHByaXZhdGUgYXBpPzogTGFrZWJveENsaWVudDtcbiAgcHJpdmF0ZSBpZGVudGl0eTogTGFrZWJveElkZW50aXR5UmVzb2x2ZXIgPSAoKSA9PiB1bmRlZmluZWQ7XG4gIC8qKiBJbi1tZW1vcnkgaWRlbnRpdGllcyBvZiByb3V0ZWQgdXNlcnM7IG5ldmVyIHBlcnNpc3RlZC4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSByb3V0ZWRJZGVudGl0aWVzID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTtcbiAgcHJpdmF0ZSBjYWNoZWQ/OiB7IGVudHJ5PzogTGFrZWJveEVudHJ5OyBhdDogbnVtYmVyIH07XG4gIHByaXZhdGUgYm9vdD86IEJvb3Q7XG4gIC8qKiBMYXN0IGJvb3QgdGhhdCBjb21wbGV0ZWQgcnVudGltZSBib290c3RyYXAgYW5kIHByb2R1Y2VkIGEgbWV0cmljcyBzYW1wbGUuICovXG4gIHByaXZhdGUgcmVhZHlCb290S2V5Pzogc3RyaW5nO1xuICBwcml2YXRlIGNvbnZlcmdpbmc/OiBQcm9taXNlPEJvb3Q+O1xuICBwcml2YXRlIHdha2luZz86IFByb21pc2U8dW5rbm93bj47XG4gIHByaXZhdGUgbWV0cmljc0xlYXNlPzogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD47XG4gIHByaXZhdGUgaWRsZVRpbWVyPzogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0SW50ZXJ2YWw+O1xuICBwcml2YXRlIGxhc3RBY3Rpdml0eSA9IERhdGUubm93KCk7XG4gIHByaXZhdGUgYWN0aXZlQ29tbWFuZHMgPSAwO1xuICAvKiogTGFzdCBzZXJ2aWNlIHN0YXRlcyBwZXIgdXNlciBoYXNoLCBrZXB0IGFmdGVyIGFuIGlkbGUgc2Vzc2lvbiByZWxlYXNlLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGxhc3RTZXJ2aWNlcyA9IG5ldyBNYXA8c3RyaW5nLCBNYXA8c3RyaW5nLCBMYWtlYm94Q29udHJvbGxlclNlcnZpY2U+PigpO1xuICBwcml2YXRlIHJlYWRvbmx5IGxhc3RTZXJ2aWNlc09ic2VydmVkQXQgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuICBwcml2YXRlIHJlc291cmNlUmVnaXN0cnk/OiBMYWtlYm94UmVzb3VyY2VSZWdpc3RyeTtcbiAgcHJpdmF0ZSBzZXJ2aWNlU25hcHNob3RzPzogTGFrZWJveFNlcnZpY2VTbmFwc2hvdHM7XG4gIHByaXZhdGUgY2xvc2luZz86IFByb21pc2U8dm9pZD47XG5cbiAgLyoqIENyZWF0ZXMgYSBydW50aW1lIGZyb20gcmVzb2x2ZWQgcGx1Z2luIGNvbmZpZ3VyYXRpb24uICovXG4gIGNvbnN0cnVjdG9yKHJlYWRvbmx5IGNvbmZpZzogUmVzb2x2ZWRMYWtlYm94UGx1Z2luQ29uZmlnKSB7XG4gICAgdGhpcy5rZXlzID0gbmV3IFNzaEtleVN0b3JlKGNvbmZpZy5rZXlEaXJlY3RvcnkpO1xuICAgIHRoaXMucm91dGVzID0gbmV3IExha2Vib3hSb3V0ZVJlZ2lzdHJ5KGNvbmZpZy5yb3V0ZVByZWZpeCwge1xuICAgICAgdXNlcjogKGhlYWRlcnMpID0+IHtcbiAgICAgICAgY29uc3QgaWRlbnRpdHkgPSB0aGlzLmlkZW50aXR5KGhlYWRlcnMpO1xuICAgICAgICBpZiAoIWlkZW50aXR5KSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICBjb25zdCB1c2VyID0gdGhpcy51c2VyKGlkZW50aXR5KTtcbiAgICAgICAgdGhpcy5yb3V0ZWRJZGVudGl0aWVzLnNldCh1c2VyLmhhc2gsIGlkZW50aXR5KTtcbiAgICAgICAgcmV0dXJuIHVzZXI7XG4gICAgICB9LFxuICAgICAgcmVzb2x2ZTogKHVzZXIsIHNlcnZpY2UpID0+IHRoaXMucmVzb2x2ZVJvdXRlKHVzZXIsIHNlcnZpY2UpLFxuICAgICAgdW5hdmFpbGFibGU6ICh1c2VyLCBzZXJ2aWNlKSA9PiB0aGlzLm1hcmtVbmF2YWlsYWJsZSh1c2VyLCBzZXJ2aWNlKSxcbiAgICB9KTtcbiAgICB0aGlzLm1ldHJpY3MgPSBuZXcgTGFrZWJveE1ldHJpY3MoXG4gICAgICAoc2lnbmFsKSA9PiB0aGlzLnJlYWRNZXRyaWNzKHNpZ25hbCksXG4gICAgICBjb25maWcubWV0cmljc0ludGVydmFsU2Vjb25kcyAqIDFfMDAwLFxuICAgICk7XG4gICAgdGhpcy5zdG9wUGFyZW50VGVybWluYXRpb25TaWduYWwgPSBleGVjLm9uUGFyZW50VGVybWluYXRpb25TaWduYWwoKCkgPT5cbiAgICAgIHRoaXMucm91dGVzLmJlZ2luU2h1dGRvd24oKSxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFN1cHBsaWVzIGFwcCBzZXJ2aWNlLXByaW5jaXBhbCBjcmVkZW50aWFscyBhbmQgdGhlIHJlcXVlc3QgaWRlbnRpdHlcbiAgICogcmVzb2x2ZXIgdXNlZCBieSByb3V0ZXMuXG4gICAqL1xuICBpbml0aWFsaXplKFxuICAgIGF1dGg6IExha2Vib3hBdXRoLFxuICAgIGlkZW50aXR5PzogTGFrZWJveElkZW50aXR5UmVzb2x2ZXIsXG4gICAgc2VydmljZVNuYXBzaG90cz86IExha2Vib3hTZXJ2aWNlU25hcHNob3RzLFxuICAgIHJlc291cmNlUmVnaXN0cnk/OiBMYWtlYm94UmVzb3VyY2VSZWdpc3RyeSxcbiAgKTogdm9pZCB7XG4gICAgdGhpcy5hcGkgPSBuZXcgTGFrZWJveENsaWVudChhdXRoKTtcbiAgICBpZiAoaWRlbnRpdHkpIHRoaXMuaWRlbnRpdHkgPSBpZGVudGl0eTtcbiAgICBpZiAoc2VydmljZVNuYXBzaG90cykgdGhpcy5zZXJ2aWNlU25hcHNob3RzID0gc2VydmljZVNuYXBzaG90cztcbiAgICBpZiAocmVzb3VyY2VSZWdpc3RyeSkgdGhpcy5yZXNvdXJjZVJlZ2lzdHJ5ID0gcmVzb3VyY2VSZWdpc3RyeTtcbiAgfVxuXG4gIC8qKiBEZXJpdmVzIHRoZSBMYWtlYm94IGFjY291bnQgZm9yIG9uZSBhdXRoZW50aWNhdGVkIGlkZW50aXR5LiAqL1xuICB1c2VyKGlkZW50aXR5OiBzdHJpbmcpOiBMYWtlYm94VXNlciB7XG4gICAgcmV0dXJuIGxha2Vib3hVc2VyKGlkZW50aXR5LCB0aGlzLmNvbmZpZy5yb3V0ZVByZWZpeCk7XG4gIH1cblxuICAvKiogU3VtbWFyaXplcyB0aGUgYXBwIExha2Vib3ggZm9yIG9uZSB1c2VyIHdpdGhvdXQgY3JlYXRpbmcgaXQuICovXG4gIGFzeW5jIHN1bW1hcnkoaWRlbnRpdHk6IHN0cmluZywgc2lnbmFsPzogQWJvcnRTaWduYWwpOiBQcm9taXNlPExha2Vib3hTdW1tYXJ5PiB7XG4gICAgY29uc3QgdXNlciA9IHRoaXMudXNlcihpZGVudGl0eSk7XG4gICAgY29uc3QgYmFzZSA9IHsgYXV0bzogdGhpcy5jb25maWcuYXV0bywgbmFtZTogXCJMYWtlYm94XCIsIHVzZXIgfTtcbiAgICBsZXQgZW50cnk6IExha2Vib3hFbnRyeSB8IHVuZGVmaW5lZDtcbiAgICB0cnkge1xuICAgICAgZW50cnkgPSBhd2FpdCB0aGlzLmVudHJ5KHNpZ25hbCwgdHJ1ZSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmIChpc0xha2Vib3hVbmF2YWlsYWJsZShlcnJvcikpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAuLi5iYXNlLFxuICAgICAgICAgIHN1cHBvcnRlZDogZmFsc2UsXG4gICAgICAgICAgc3RhdHVzOiBcIm1pc3NpbmdcIixcbiAgICAgICAgICBzZXJ2aWNlczogW10sXG4gICAgICAgICAgc2VydmljZXNTdGFsZTogZmFsc2UsXG4gICAgICAgICAgY2FuU3RhcnQ6IGZhbHNlLFxuICAgICAgICAgIGNhblN0b3A6IGZhbHNlLFxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICAgIGNvbnN0IHBsYXRmb3JtU3RhdHVzOiBMYWtlYm94U3RhdHVzID0gZW50cnkgPyBub3JtYWxpemVMYWtlYm94U3RhdHVzKGVudHJ5LnN0YXR1cykgOiBcIm1pc3NpbmdcIjtcbiAgICBjb25zdCBzdGF0dXMgPSB0aGlzLnByb2R1Y3RTdGF0dXMoZW50cnksIHBsYXRmb3JtU3RhdHVzKTtcbiAgICBpZiAoZW50cnkgJiYgcGxhdGZvcm1TdGF0dXMgPT09IFwicnVubmluZ1wiICYmIHN0YXR1cyA9PT0gXCJzdGFydGluZ1wiKSB7XG4gICAgICB0aGlzLndha2UoKCkgPT4gdGhpcy5yZWFkeSgpKTtcbiAgICB9XG4gICAgY29uc3QgbGlzdGluZyA9IGF3YWl0IHRoaXMuc2VydmljZUxpc3RpbmcoaWRlbnRpdHksIHVzZXIsIGVudHJ5LCBzdGF0dXMsIHNpZ25hbCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLmJhc2UsXG4gICAgICBzdXBwb3J0ZWQ6IHRydWUsXG4gICAgICBzdGF0dXMsXG4gICAgICAuLi4oZW50cnkgPyB7IGlkOiBlbnRyeS5zYW5kYm94SWQgfSA6IHt9KSxcbiAgICAgIC4uLihsYWtlYm94SWRsZVRpbWVvdXRTZWNvbmRzKGVudHJ5Py5pZGxlVGltZW91dCkgIT09IHVuZGVmaW5lZFxuICAgICAgICA/IHsgaWRsZVRpbWVvdXRTZWNvbmRzOiBsYWtlYm94SWRsZVRpbWVvdXRTZWNvbmRzKGVudHJ5Py5pZGxlVGltZW91dCkgfVxuICAgICAgICA6IHt9KSxcbiAgICAgIHNlcnZpY2VzOiBsaXN0aW5nLnNlcnZpY2VzLFxuICAgICAgc2VydmljZXNTdGFsZTogbGlzdGluZy5zdGFsZSxcbiAgICAgIC4uLihsaXN0aW5nLm9ic2VydmVkQXQgPyB7IHNlcnZpY2VzT2JzZXJ2ZWRBdDogbGlzdGluZy5vYnNlcnZlZEF0IH0gOiB7fSksXG4gICAgICBjYW5TdGFydDogc3RhdHVzICE9PSBcInJ1bm5pbmdcIiAmJiBzdGF0dXMgIT09IFwic3RhcnRpbmdcIixcbiAgICAgIGNhblN0b3A6IHN0YXR1cyA9PT0gXCJydW5uaW5nXCIgfHwgc3RhdHVzID09PSBcInN0YXJ0aW5nXCIsXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBDcmVhdGVzIHRoZSBMYWtlYm94IHdoZW4gbmVlZGVkLCBzdGFydHMgaXQsIGFuZCByZXN0b3JlcyBzYXZlZCBzZXJ2aWNlcy4gKi9cbiAgYXN5bmMgc3RhcnQoc2lnbmFsPzogQWJvcnRTaWduYWwpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLnJlYWR5KHNpZ25hbCwgdHJ1ZSk7XG4gIH1cblxuICAvKiogU3RvcHMgdGhlIHNoYXJlZCBMYWtlYm94IGZvciBldmVyeSB1c2VyLiBGaWxlcyBhbmQgc2F2ZWQgc2VydmljZXMgcGVyc2lzdC4gKi9cbiAgYXN5bmMgc3RvcChzaWduYWw/OiBBYm9ydFNpZ25hbCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGVudHJ5ID0gYXdhaXQgdGhpcy5lbnRyeShzaWduYWwsIHRydWUpO1xuICAgIGlmICghZW50cnkpIHJldHVybjtcbiAgICBhd2FpdCB0aGlzLmRpc2NhcmRCb290KCk7XG4gICAgYXdhaXQgZW5zdXJlTGFrZWJveFN0b3BwZWQodGhpcy5jbGllbnQoKSwgZW50cnksIHNpZ25hbCk7XG4gICAgdGhpcy5jYWNoZWQgPSB1bmRlZmluZWQ7XG4gIH1cblxuICAvKiogUGVybWFuZW50bHkgZGVsZXRlcyB0aGUgbWFuYWdlZCBMYWtlYm94IGFuZCBldmVyeSB1c2VyJ3MgZmlsZXMuICovXG4gIGFzeW5jIGRlbGV0ZShzaWduYWw/OiBBYm9ydFNpZ25hbCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGVudHJ5ID0gYXdhaXQgdGhpcy5lbnRyeShzaWduYWwsIHRydWUpO1xuICAgIGlmICghZW50cnkpIHJldHVybiBmYWxzZTtcbiAgICBhd2FpdCB0aGlzLmRpc2NhcmRCb290KCk7XG4gICAgYXdhaXQgdGhpcy5jbGllbnQoKS5kZWxldGUoZW50cnkuc2FuZGJveElkLCBzaWduYWwpO1xuICAgIGF3YWl0IHRoaXMucmVzb3VyY2VzKCkuY2xlYXIodGhpcy5jbGllbnQoKSk7XG4gICAgdGhpcy5yZWFkeUJvb3RLZXkgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5jYWNoZWQgPSB7IGF0OiBEYXRlLm5vdygpIH07XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogUnVucyBvbmUgY29tbWFuZCBhcyB0aGUgdXNlcidzIGFjY291bnQsIGNyZWF0aW5nIG9yIHN0YXJ0aW5nIHRoZSBMYWtlYm94XG4gICAqIHdoZW4gYGF1dG9gIGlzIGVuYWJsZWQuXG4gICAqL1xuICBleGVjdXRlKGlkZW50aXR5OiBzdHJpbmcsIGlucHV0OiBMYWtlYm94Q29tbWFuZFJlcXVlc3QsIHNpZ25hbD86IEFib3J0U2lnbmFsKTogU3NoQ29tbWFuZCB7XG4gICAgY29uc3QgcmVxdWVzdCA9IGxha2Vib3hDb21tYW5kUmVxdWVzdFNjaGVtYS5wYXJzZShpbnB1dCk7XG4gICAgY29uc3QgdGltZW91dE1zID0gcmVxdWVzdC50aW1lb3V0TXMgPz8gdGhpcy5jb25maWcuY29tbWFuZFRpbWVvdXRNcztcbiAgICBjb25zdCB1c2VyID0gdGhpcy51c2VyKGlkZW50aXR5KTtcbiAgICByZXR1cm4gbmV3IFNzaENvbW1hbmQoXG4gICAgICByZXF1ZXN0LmNvbW1hbmQsXG4gICAgICByZXF1ZXN0LmFyZ3MsXG4gICAgICB7IHRpbWVvdXRNcywgc2lnbmFsIH0sXG4gICAgICBhc3luYyAoZXhlY3V0aW9uKSA9PiB7XG4gICAgICAgIGNvbnN0IGJvb3QgPSBhd2FpdCB0aGlzLnJlYWR5VXNlcih1c2VyLCBpZGVudGl0eSwgZXhlY3V0aW9uLnNpZ25hbCk7XG4gICAgICAgIHRoaXMuYWN0aXZlQ29tbWFuZHMgKz0gMTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICByZXR1cm4gYXdhaXQgZXhlY3V0aW9uLmZvbGxvdyhcbiAgICAgICAgICAgIGJvb3Quc2Vzc2lvbi5leGVjdXRlKHJlcXVlc3QuY29tbWFuZCwgcmVxdWVzdC5hcmdzLCB7XG4gICAgICAgICAgICAgIHVzZXIsXG4gICAgICAgICAgICAgIC4uLihyZXF1ZXN0LmN3ZCA/IHsgY3dkOiByZXF1ZXN0LmN3ZCB9IDoge30pLFxuICAgICAgICAgICAgICAuLi4ocmVxdWVzdC5lbnYgPyB7IGVudjogcmVxdWVzdC5lbnYgfSA6IHt9KSxcbiAgICAgICAgICAgICAgdGltZW91dE1zLFxuICAgICAgICAgICAgICBzaWduYWw6IGV4ZWN1dGlvbi5zaWduYWwsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIHRoaXMuYWN0aXZlQ29tbWFuZHMgLT0gMTtcbiAgICAgICAgICB0aGlzLnRvdWNoKCk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBMaXN0cyB0aGUgdXNlcidzIHNlcnZpY2VzLCBpbmNsdWRpbmcgaWRsZSBidWlsdC1pbnMuIE5ldmVyIGNyZWF0ZXMgdGhlIExha2Vib3guICovXG4gIGFzeW5jIGxpc3RTZXJ2aWNlcyhpZGVudGl0eTogc3RyaW5nLCBzaWduYWw/OiBBYm9ydFNpZ25hbCk6IFByb21pc2U8TGFrZWJveFNlcnZpY2VbXT4ge1xuICAgIGNvbnN0IHVzZXIgPSB0aGlzLnVzZXIoaWRlbnRpdHkpO1xuICAgIGNvbnN0IGVudHJ5ID0gYXdhaXQgdGhpcy5lbnRyeShzaWduYWwpO1xuICAgIGNvbnN0IHN0YXR1czogTGFrZWJveFN0YXR1cyA9IGVudHJ5ID8gbm9ybWFsaXplTGFrZWJveFN0YXR1cyhlbnRyeS5zdGF0dXMpIDogXCJtaXNzaW5nXCI7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLnNlcnZpY2VMaXN0aW5nKGlkZW50aXR5LCB1c2VyLCBlbnRyeSwgc3RhdHVzLCBzaWduYWwpKS5zZXJ2aWNlcztcbiAgfVxuXG4gIC8qKiBDcmVhdGVzIG9yIHJlcGxhY2VzIG9uZSBpbWFnZSBzZXJ2aWNlIGFuZCB3YWl0cyB1bnRpbCBpdCBpcyByZWFkeSBvciBmYWlsZWQuICovXG4gIGFzeW5jIGNyZWF0ZVNlcnZpY2UoXG4gICAgaWRlbnRpdHk6IHN0cmluZyxcbiAgICBpbnB1dDogQ3JlYXRlTGFrZWJveFNlcnZpY2VSZXF1ZXN0LFxuICAgIHNpZ25hbD86IEFib3J0U2lnbmFsLFxuICApOiBQcm9taXNlPExha2Vib3hTZXJ2aWNlPiB7XG4gICAgY29uc3QgdXNlciA9IHRoaXMudXNlcihpZGVudGl0eSk7XG4gICAgY29uc3QgZGVmaW5pdGlvbiA9IGltYWdlRGVmaW5pdGlvbihpbnB1dCwgdXNlcik7XG4gICAgY29uc3QgYm9vdCA9IGF3YWl0IHRoaXMucmVhZHlVc2VyKHVzZXIsIGlkZW50aXR5LCBzaWduYWwpO1xuICAgIGF3YWl0IHRoaXMuY29udHJvbGxlcihib290LCB1c2VyLCBcInB1dFwiLCBbZW5jb2RlKGRlZmluaXRpb24pXSwgc2lnbmFsKTtcbiAgICByZXR1cm4gdGhpcy5ydW5TZXJ2aWNlKGJvb3QsIHVzZXIsIGRlZmluaXRpb24sIHNpZ25hbCk7XG4gIH1cblxuICAvKiogU3RhcnRzIGEgc2F2ZWQgc2VydmljZSBvciBhIGJ1aWx0LWluIGFuZCB3YWl0cyB1bnRpbCBpdCBpcyByZWFkeSBvciBmYWlsZWQuICovXG4gIGFzeW5jIHN0YXJ0U2VydmljZShcbiAgICBpZGVudGl0eTogc3RyaW5nLFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbiAgKTogUHJvbWlzZTxMYWtlYm94U2VydmljZT4ge1xuICAgIGNvbnN0IHVzZXIgPSB0aGlzLnVzZXIoaWRlbnRpdHkpO1xuICAgIGNvbnN0IGJvb3QgPSBhd2FpdCB0aGlzLnJlYWR5VXNlcih1c2VyLCBpZGVudGl0eSwgc2lnbmFsKTtcbiAgICBjb25zdCBidWlsdEluID0gbGFrZWJveEJ1aWx0SW5TZXJ2aWNlTmFtZVNjaGVtYS5zYWZlUGFyc2UobmFtZSk7XG4gICAgaWYgKGJ1aWx0SW4uc3VjY2Vzcykge1xuICAgICAgY29uc3QgZGVmaW5pdGlvbiA9IGJ1aWx0SW5EZWZpbml0aW9uKGJ1aWx0SW4uZGF0YSwgdXNlcik7XG4gICAgICBhd2FpdCB0aGlzLmNvbnRyb2xsZXIoYm9vdCwgdXNlciwgXCJwdXRcIiwgW2VuY29kZShkZWZpbml0aW9uKV0sIHNpZ25hbCk7XG4gICAgICByZXR1cm4gdGhpcy5ydW5TZXJ2aWNlKGJvb3QsIHVzZXIsIGRlZmluaXRpb24sIHNpZ25hbCk7XG4gICAgfVxuICAgIGNvbnN0IHNhdmVkID0gKGF3YWl0IHRoaXMucmVmcmVzaFNlcnZpY2VzKGJvb3QsIHVzZXIsIGlkZW50aXR5LCBzaWduYWwpKS5nZXQobmFtZSk7XG4gICAgaWYgKCFzYXZlZCkgdGhyb3cgbmV3IEVycm9yKGBMYWtlYm94IHNlcnZpY2UgJHtuYW1lfSBkb2VzIG5vdCBleGlzdGApO1xuICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UoYm9vdCwgdXNlciwgc2F2ZWQuZGVmaW5pdGlvbiwgc2lnbmFsKTtcbiAgfVxuXG4gIC8qKiBTdG9wcyBvbmUgcnVubmluZyBzZXJ2aWNlIHdpdGhvdXQgcmVtb3ZpbmcgaXRzIGRlZmluaXRpb24uICovXG4gIGFzeW5jIHN0b3BTZXJ2aWNlKGlkZW50aXR5OiBzdHJpbmcsIG5hbWU6IHN0cmluZywgc2lnbmFsPzogQWJvcnRTaWduYWwpOiBQcm9taXNlPExha2Vib3hTZXJ2aWNlPiB7XG4gICAgY29uc3QgdXNlciA9IHRoaXMudXNlcihpZGVudGl0eSk7XG4gICAgY29uc3QgYm9vdCA9IGF3YWl0IHRoaXMucmVhZHlVc2VyKHVzZXIsIGlkZW50aXR5LCBzaWduYWwpO1xuICAgIGNvbnN0IHN0b3BwZWQgPSBMYWtlYm94Q29udHJvbGxlclNlcnZpY2VTY2hlbWEucGFyc2UoXG4gICAgICBhd2FpdCB0aGlzLmNvbnRyb2xsZXIoYm9vdCwgdXNlciwgXCJzdG9wXCIsIFtuYW1lXSwgc2lnbmFsKSxcbiAgICApO1xuICAgIHRoaXMuY2FjaGVTZXJ2aWNlKGJvb3QsIHVzZXIsIHN0b3BwZWQpO1xuICAgIHJldHVybiB0b0xha2Vib3hTZXJ2aWNlKHN0b3BwZWQsIHVzZXIsIHRoaXMuY29uZmlnLnJvdXRlUHJlZml4KTtcbiAgfVxuXG4gIC8qKiBTdG9wcyBhbmQgZGVsZXRlcyBvbmUgc2F2ZWQgc2VydmljZS4gTW91bnRlZCBob21lIGRpcmVjdG9yaWVzIGFyZSBwcmVzZXJ2ZWQuICovXG4gIGFzeW5jIHJlbW92ZVNlcnZpY2UoaWRlbnRpdHk6IHN0cmluZywgbmFtZTogc3RyaW5nLCBzaWduYWw/OiBBYm9ydFNpZ25hbCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHVzZXIgPSB0aGlzLnVzZXIoaWRlbnRpdHkpO1xuICAgIGNvbnN0IGJvb3QgPSBhd2FpdCB0aGlzLnJlYWR5VXNlcih1c2VyLCBpZGVudGl0eSwgc2lnbmFsKTtcbiAgICBjb25zdCByZXN1bHQgPSAoYXdhaXQgdGhpcy5jb250cm9sbGVyKGJvb3QsIHVzZXIsIFwicmVtb3ZlXCIsIFtuYW1lXSwgc2lnbmFsKSkgYXMge1xuICAgICAgcmVtb3ZlZD86IGJvb2xlYW47XG4gICAgfTtcbiAgICBpZiAocmVzdWx0LnJlbW92ZWQgPT09IHRydWUpIGF3YWl0IHRoaXMucmVmcmVzaFNlcnZpY2VzKGJvb3QsIHVzZXIsIGlkZW50aXR5LCBzaWduYWwpO1xuICAgIHJldHVybiByZXN1bHQucmVtb3ZlZCA9PT0gdHJ1ZTtcbiAgfVxuXG4gIC8qKiBSZWFkcyBhIGJvdW5kZWQgdGFpbCBvZiBvbmUgc2VydmljZSBsb2cuICovXG4gIGFzeW5jIHNlcnZpY2VMb2dzKFxuICAgIGlkZW50aXR5OiBzdHJpbmcsXG4gICAgaW5wdXQ6IExha2Vib3hTZXJ2aWNlTG9nc1JlcXVlc3QsXG4gICAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4gICk6IFByb21pc2U8eyBsb2c6IHN0cmluZyB9PiB7XG4gICAgY29uc3QgcmVxdWVzdCA9IGxha2Vib3hTZXJ2aWNlTG9nc1JlcXVlc3RTY2hlbWEucGFyc2UoaW5wdXQpO1xuICAgIGNvbnN0IHVzZXIgPSB0aGlzLnVzZXIoaWRlbnRpdHkpO1xuICAgIGNvbnN0IGVudHJ5ID0gYXdhaXQgdGhpcy5lbnRyeShzaWduYWwpO1xuICAgIGlmICghZW50cnkgfHwgbm9ybWFsaXplTGFrZWJveFN0YXR1cyhlbnRyeS5zdGF0dXMpICE9PSBcInJ1bm5pbmdcIikgcmV0dXJuIHsgbG9nOiBcIlwiIH07XG4gICAgY29uc3QgYm9vdCA9IGF3YWl0IHRoaXMucmVhZHlVc2VyKHVzZXIsIGlkZW50aXR5LCBzaWduYWwpO1xuICAgIGNvbnN0IHJlc3VsdCA9IChhd2FpdCB0aGlzLmNvbnRyb2xsZXIoXG4gICAgICBib290LFxuICAgICAgdXNlcixcbiAgICAgIFwibG9nc1wiLFxuICAgICAgW3JlcXVlc3QubmFtZSwgU3RyaW5nKHJlcXVlc3QubWF4TGluZXMpLCBTdHJpbmcocmVxdWVzdC5tYXhDaGFycyldLFxuICAgICAgc2lnbmFsLFxuICAgICkpIGFzIHsgbG9nPzogc3RyaW5nIH07XG4gICAgcmV0dXJuIHsgbG9nOiByZXN1bHQubG9nID8/IFwiXCIgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHJlY2VudCBtZXRyaWNzIGFuZCBrZWVwcyBzYW1wbGluZyBmb3Igb25lIGxlYXNlIGludGVydmFsLiBTYW1wbGluZ1xuICAgKiBydW5zIG9ubHkgd2hpbGUgdGhlIExha2Vib3ggcnVucyBhbmQgYSBjYWxsZXIgaXMgd2F0Y2hpbmcsIHNvIG1ldHJpY3MgbmV2ZXJcbiAgICoga2VlcCBhbiBvdGhlcndpc2UgaWRsZSBMYWtlYm94IGF3YWtlLlxuICAgKi9cbiAgYXN5bmMgbWV0cmljc1Jlc3BvbnNlKHNpZ25hbD86IEFib3J0U2lnbmFsKTogUHJvbWlzZTxMYWtlYm94TWV0cmljc1Jlc3BvbnNlPiB7XG4gICAgY29uc3QgZW50cnkgPSBhd2FpdCB0aGlzLmVudHJ5KHNpZ25hbCk7XG4gICAgY29uc3QgcGxhdGZvcm1TdGF0dXM6IExha2Vib3hTdGF0dXMgPSBlbnRyeSA/IG5vcm1hbGl6ZUxha2Vib3hTdGF0dXMoZW50cnkuc3RhdHVzKSA6IFwibWlzc2luZ1wiO1xuICAgIGlmIChwbGF0Zm9ybVN0YXR1cyAhPT0gXCJydW5uaW5nXCIpIHtcbiAgICAgIHRoaXMubWV0cmljcy5zdG9wKCk7XG4gICAgICByZXR1cm4geyBzdGF0dXM6IHBsYXRmb3JtU3RhdHVzLCBzZXJpZXM6IFtdIH07XG4gICAgfVxuICAgIGlmICghZW50cnkgfHwgIXRoaXMuYm9vdCB8fCB0aGlzLmJvb3Qua2V5ICE9PSB0aGlzLmJvb3RLZXkoZW50cnkpKSB7XG4gICAgICB0aGlzLm1ldHJpY3Muc3RvcCgpO1xuICAgICAgdGhpcy53YWtlKCgpID0+IHRoaXMucmVhZHkoKSk7XG4gICAgICByZXR1cm4geyBzdGF0dXM6IFwic3RhcnRpbmdcIiwgc2VyaWVzOiBbXSB9O1xuICAgIH1cbiAgICB0aGlzLmxlYXNlTWV0cmljcygpO1xuICAgIHJldHVybiB7XG4gICAgICBzdGF0dXM6IHRoaXMucHJvZHVjdFN0YXR1cyhlbnRyeSwgcGxhdGZvcm1TdGF0dXMpLFxuICAgICAgc2VyaWVzOiBbLi4udGhpcy5tZXRyaWNzLnNlcmllcygpXSxcbiAgICB9O1xuICB9XG5cbiAgLyoqIFN1YnNjcmliZXMgdG8gbWV0cmljcyBzbmFwc2hvdHMgd2hpbGUgdGhlIExha2Vib3ggcnVucy4gKi9cbiAgc3Vic2NyaWJlTWV0cmljcyhsaXN0ZW5lcjogKHNuYXBzaG90OiBMYWtlYm94TWV0cmljc1NuYXBzaG90KSA9PiB2b2lkKTogKCkgPT4gdm9pZCB7XG4gICAgdGhpcy5tZXRyaWNzLm9uKFwic25hcHNob3RcIiwgbGlzdGVuZXIpO1xuICAgIGlmICh0aGlzLmJvb3Q/LmtleSA9PT0gdGhpcy5yZWFkeUJvb3RLZXkpIHRoaXMubWV0cmljcy5zdGFydCgpO1xuICAgIHJldHVybiAoKSA9PiB7XG4gICAgICB0aGlzLm1ldHJpY3Mub2ZmKFwic25hcHNob3RcIiwgbGlzdGVuZXIpO1xuICAgICAgdGhpcy5sZWFzZU1ldHJpY3MoKTtcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZXMgbGVnYWN5IHBlci11c2VyIExha2Vib3hlcyBhbmQgZHJvcHMgbGVnYWN5IG93bmVyc2hpcCBzY2hlbWFzLlxuICAgKlxuICAgKiBUaGVyZSBpcyBubyBtaWdyYXRpb246IHRoZSBlYXJsaWVyIG9uZS1tYWNoaW5lLXBlci11c2VyIG1vZGVsIGlzIHJlbW92ZWQuXG4gICAqIFRoZSBtYW5hZ2VkIGFwcCBMYWtlYm94IGFuZCBMYWtlYm94ZXMgd2l0aCBvdGhlciBuYW1lcyBhcmUgbmV2ZXIgdG91Y2hlZC5cbiAgICovXG4gIGFzeW5jIGNsZWFudXBMZWdhY3kocG9vbD86IExha2Vib3hMZWdhY3lQb29sLCBzaWduYWw/OiBBYm9ydFNpZ25hbCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBlbnRyaWVzID0gYXdhaXQgdGhpcy5jbGllbnQoKS5saXN0KHNpZ25hbCk7XG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgZW50cmllc1xuICAgICAgICAgIC5maWx0ZXIoKGVudHJ5KSA9PiBlbnRyeS5uYW1lICYmIExFR0FDWV9OQU1FLnRlc3QoZW50cnkubmFtZSkpXG4gICAgICAgICAgLm1hcChhc3luYyAoZW50cnkpID0+IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuY2xpZW50KCkuZGVsZXRlKGVudHJ5LnNhbmRib3hJZCwgc2lnbmFsKTtcbiAgICAgICAgICAgIGxvZ2dlci5pbmZvKFwiZGVsZXRlZCBsZWdhY3kgcGVyLXVzZXIgTGFrZWJveFwiLCB7XG4gICAgICAgICAgICAgIGlkOiBlbnRyeS5zYW5kYm94SWQsXG4gICAgICAgICAgICAgIG5hbWU6IGVudHJ5Lm5hbWUsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICghaXNMYWtlYm94VW5hdmFpbGFibGUoZXJyb3IpKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKFwibGVnYWN5IExha2Vib3ggY2xlYW51cCBmYWlsZWRcIiwgeyBlcnJvcjogZXJyb3JVdGlscy50b0Vycm9yKGVycm9yKSB9KTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKCFwb29sKSByZXR1cm47XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHNjaGVtYXMgPSBhd2FpdCBwb29sLnF1ZXJ5KFxuICAgICAgICBcIlNFTEVDVCBuc3BuYW1lIEZST00gcGdfbmFtZXNwYWNlIFdIRVJFIG5zcG5hbWUgPSAkMSBPUiBzdGFydHNfd2l0aChuc3BuYW1lLCAkMilcIixcbiAgICAgICAgW0xFR0FDWV9TQ0hFTUFfUFJFRklYLCBgJHtMRUdBQ1lfU0NIRU1BX1BSRUZJWH1fYF0sXG4gICAgICApO1xuICAgICAgZm9yIChjb25zdCByb3cgb2Ygc2NoZW1hcy5yb3dzKSB7XG4gICAgICAgIGNvbnN0IHNjaGVtYSA9IFN0cmluZyhyb3cubnNwbmFtZSk7XG4gICAgICAgIGF3YWl0IHBvb2wucXVlcnkoYERST1AgU0NIRU1BIElGIEVYSVNUUyBcIiR7c2NoZW1hLnJlcGxhY2VBbGwoJ1wiJywgJ1wiXCInKX1cIiBDQVNDQURFYCk7XG4gICAgICAgIGxvZ2dlci5pbmZvKFwiZHJvcHBlZCBsZWdhY3kgTGFrZWJveCBvd25lcnNoaXAgc2NoZW1hXCIsIHsgc2NoZW1hIH0pO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIud2FybihcImxlZ2FjeSBvd25lcnNoaXAgc2NoZW1hIGNsZWFudXAgZmFpbGVkXCIsIHsgZXJyb3I6IGVycm9yVXRpbHMudG9FcnJvcihlcnJvcikgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqIENhbmNlbHMgaW4tZmxpZ2h0IHdvcmsgYmVmb3JlIHRlYXJkb3duLiAqL1xuICBhYm9ydEFjdGl2ZU9wZXJhdGlvbnMoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLnNodXRkb3duQ29udHJvbGxlci5zaWduYWwuYWJvcnRlZCkgdGhpcy5zaHV0ZG93bkNvbnRyb2xsZXIuYWJvcnQoKTtcbiAgfVxuXG4gIC8qKiBDbG9zZXMgcm91dGVzLCBtZXRyaWNzLCBhbmQgdGhlIFNTSCBzZXNzaW9uIHdpdGhvdXQgY2hhbmdpbmcgdGhlIExha2Vib3guICovXG4gIGNsb3NlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuYWJvcnRBY3RpdmVPcGVyYXRpb25zKCk7XG4gICAgdGhpcy5yb3V0ZXMuYmVnaW5TaHV0ZG93bigpO1xuICAgIHRoaXMuY2xvc2luZyA/Pz0gKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGlmICh0aGlzLm1ldHJpY3NMZWFzZSkgY2xlYXJUaW1lb3V0KHRoaXMubWV0cmljc0xlYXNlKTtcbiAgICAgICAgdGhpcy5tZXRyaWNzLnN0b3AoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5yb3V0ZXMuY2xvc2UoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5ib290Py5zZXNzaW9uLmNsb3NlKCk7XG4gICAgICAgIHRoaXMuYm9vdCA9IHVuZGVmaW5lZDtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIHRoaXMuc3RvcFBhcmVudFRlcm1pbmF0aW9uU2lnbmFsKCk7XG4gICAgICB9XG4gICAgfSkoKTtcbiAgICByZXR1cm4gdGhpcy5jbG9zaW5nO1xuICB9XG5cbiAgcHJpdmF0ZSBjbGllbnQoKTogTGFrZWJveENsaWVudCB7XG4gICAgaWYgKCF0aGlzLmFwaSkgdGhyb3cgbmV3IEVycm9yKFwiVGhlIExha2Vib3ggcnVudGltZSBoYXMgbm8gYXBwIHNlcnZpY2UtcHJpbmNpcGFsIGNyZWRlbnRpYWxzXCIpO1xuICAgIHJldHVybiB0aGlzLmFwaTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzb3VyY2VzKCk6IExha2Vib3hSZXNvdXJjZVJlZ2lzdHJ5IHtcbiAgICBpZiAoIXRoaXMucmVzb3VyY2VSZWdpc3RyeSkgdGhyb3cgbmV3IEVycm9yKFwiVGhlIExha2Vib3ggcnVudGltZSBoYXMgbm8gcmVzb3VyY2UgcmVnaXN0cnlcIik7XG4gICAgcmV0dXJuIHRoaXMucmVzb3VyY2VSZWdpc3RyeTtcbiAgfVxuXG4gIC8qKiBSZXR1cm5zIHRoZSBtYW5hZ2VkIExha2Vib3ggZW50cnksIGNhY2hlZCBicmllZmx5IHRvIGtlZXAgcm91dGVzIGNoZWFwLiAqL1xuICBwcml2YXRlIGFzeW5jIGVudHJ5KHNpZ25hbD86IEFib3J0U2lnbmFsLCBmcmVzaCA9IGZhbHNlKTogUHJvbWlzZTxMYWtlYm94RW50cnkgfCB1bmRlZmluZWQ+IHtcbiAgICBpZiAoIWZyZXNoICYmIHRoaXMuY2FjaGVkICYmIERhdGUubm93KCkgLSB0aGlzLmNhY2hlZC5hdCA8IEVOVFJZX1RUTF9NUykge1xuICAgICAgcmV0dXJuIHRoaXMuY2FjaGVkLmVudHJ5O1xuICAgIH1cbiAgICBjb25zdCBlbnRyeSA9IGF3YWl0IHRoaXMucmVzb3VyY2VzKCkucmVhZCh0aGlzLmNsaWVudCgpLCBzaWduYWwpO1xuICAgIHRoaXMuY2FjaGVkID0geyAuLi4oZW50cnkgPyB7IGVudHJ5IH0gOiB7fSksIGF0OiBEYXRlLm5vdygpIH07XG4gICAgaWYgKCFlbnRyeSB8fCBub3JtYWxpemVMYWtlYm94U3RhdHVzKGVudHJ5LnN0YXR1cykgIT09IFwicnVubmluZ1wiKSB7XG4gICAgICB0aGlzLnJlYWR5Qm9vdEtleSA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgaWYgKHRoaXMuYm9vdCAmJiAoIWVudHJ5IHx8IHRoaXMuYm9vdEtleShlbnRyeSkgIT09IHRoaXMuYm9vdC5rZXkpKSBhd2FpdCB0aGlzLmRpc2NhcmRCb290KCk7XG4gICAgcmV0dXJuIGVudHJ5O1xuICB9XG5cbiAgcHJpdmF0ZSBib290S2V5KGVudHJ5OiBMYWtlYm94RW50cnkpOiBzdHJpbmcge1xuICAgIHJldHVybiBgJHtlbnRyeS5zYW5kYm94SWR9XFwwJHtlbnRyeS5sYXN0U3RhcnRUaW1lID8/IFwiXCJ9YDtcbiAgfVxuXG4gIHByaXZhdGUgcHJvZHVjdFN0YXR1cyhlbnRyeTogTGFrZWJveEVudHJ5IHwgdW5kZWZpbmVkLCBzdGF0dXM6IExha2Vib3hTdGF0dXMpOiBMYWtlYm94U3RhdHVzIHtcbiAgICByZXR1cm4gZW50cnkgJiYgc3RhdHVzID09PSBcInJ1bm5pbmdcIiAmJiB0aGlzLnJlYWR5Qm9vdEtleSAhPT0gdGhpcy5ib290S2V5KGVudHJ5KVxuICAgICAgPyBcInN0YXJ0aW5nXCJcbiAgICAgIDogc3RhdHVzO1xuICB9XG5cbiAgLyoqIFNlcmlhbGl6ZXMgY3JlYXRlLCBzdGFydCwgY29ubmVjdCwgYW5kIGJvb3RzdHJhcCBmb3IgdGhlIGN1cnJlbnQgYm9vdC4gKi9cbiAgcHJpdmF0ZSByZWFkeShzaWduYWw/OiBBYm9ydFNpZ25hbCwgZXhwbGljaXQgPSBmYWxzZSk6IFByb21pc2U8Qm9vdD4ge1xuICAgIGNvbnN0IGN1cnJlbnQgPSB0aGlzLmJvb3Q7XG4gICAgaWYgKGN1cnJlbnQgJiYgdGhpcy5jYWNoZWQ/LmVudHJ5ICYmIHRoaXMuYm9vdEtleSh0aGlzLmNhY2hlZC5lbnRyeSkgPT09IGN1cnJlbnQua2V5KSB7XG4gICAgICBpZiAoRGF0ZS5ub3coKSAtIHRoaXMuY2FjaGVkLmF0IDwgRU5UUllfVFRMX01TKSByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGN1cnJlbnQpO1xuICAgIH1cbiAgICB0aGlzLmNvbnZlcmdpbmcgPz89IHRoaXMuY29udmVyZ2Uoc2lnbmFsLCBleHBsaWNpdCkuZmluYWxseSgoKSA9PiB7XG4gICAgICB0aGlzLmNvbnZlcmdpbmcgPSB1bmRlZmluZWQ7XG4gICAgfSk7XG4gICAgcmV0dXJuIHRoaXMuY29udmVyZ2luZztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY29udmVyZ2Uoc2lnbmFsOiBBYm9ydFNpZ25hbCB8IHVuZGVmaW5lZCwgZXhwbGljaXQ6IGJvb2xlYW4pOiBQcm9taXNlPEJvb3Q+IHtcbiAgICBjb25zdCBvcGVyYXRpb25TaWduYWwgPSBzaWduYWxcbiAgICAgID8gQWJvcnRTaWduYWwuYW55KFtzaWduYWwsIHRoaXMuc2h1dGRvd25Db250cm9sbGVyLnNpZ25hbF0pXG4gICAgICA6IHRoaXMuc2h1dGRvd25Db250cm9sbGVyLnNpZ25hbDtcbiAgICBsZXQgZW50cnkgPSBhd2FpdCB0aGlzLmVudHJ5KG9wZXJhdGlvblNpZ25hbCwgdHJ1ZSk7XG4gICAgaWYgKCFlbnRyeSB8fCBub3JtYWxpemVMYWtlYm94U3RhdHVzKGVudHJ5LnN0YXR1cykgIT09IFwicnVubmluZ1wiKSB7XG4gICAgICBpZiAoIXRoaXMuY29uZmlnLmF1dG8gJiYgIWV4cGxpY2l0KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgTGFrZWJveCBpcyAke2VudHJ5ID8gZW50cnkuc3RhdHVzIDogXCJub3QgY3JlYXRlZFwifTsgc3RhcnQgaXQgZXhwbGljaXRseSBiZWNhdXNlIGF1dG8gaXMgZmFsc2VgLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgICBlbnRyeSA/Pz0gYXdhaXQgdGhpcy5yZXNvdXJjZXMoKS5nZXRPckNyZWF0ZSh0aGlzLmNsaWVudCgpLCBvcGVyYXRpb25TaWduYWwpO1xuICAgIGlmIChsYWtlYm94SWRsZVRpbWVvdXRTZWNvbmRzKGVudHJ5LmlkbGVUaW1lb3V0KSAhPT0gdGhpcy5jb25maWcuaWRsZVRpbWVvdXRTZWNvbmRzKSB7XG4gICAgICBlbnRyeSA9IGF3YWl0IHRoaXMuY2xpZW50KCkuc2V0SWRsZVRpbWVvdXQoXG4gICAgICAgIGVudHJ5LnNhbmRib3hJZCxcbiAgICAgICAgdGhpcy5jb25maWcuaWRsZVRpbWVvdXRTZWNvbmRzLFxuICAgICAgICBvcGVyYXRpb25TaWduYWwsXG4gICAgICApO1xuICAgIH1cbiAgICBlbnRyeSA9IGF3YWl0IGVuc3VyZUxha2Vib3hSdW5uaW5nKHRoaXMuY2xpZW50KCksIGVudHJ5LCBvcGVyYXRpb25TaWduYWwpO1xuICAgIHRoaXMuY2FjaGVkID0geyBlbnRyeSwgYXQ6IERhdGUubm93KCkgfTtcbiAgICBjb25zdCBrZXkgPSB0aGlzLmJvb3RLZXkoZW50cnkpO1xuICAgIGlmICh0aGlzLmJvb3Q/LmtleSA9PT0ga2V5KSByZXR1cm4gdGhpcy5ib290O1xuICAgIGF3YWl0IHRoaXMuZGlzY2FyZEJvb3QoKTtcbiAgICBjb25zdCBzZXNzaW9uID0gYXdhaXQgdGhpcy5jb25uZWN0KGVudHJ5LCBvcGVyYXRpb25TaWduYWwpO1xuICAgIGNvbnN0IGJvb3Q6IEJvb3QgPSB7XG4gICAgICBrZXksXG4gICAgICBlbnRyeSxcbiAgICAgIHNlc3Npb24sXG4gICAgICB1c2VyczogbmV3IE1hcCgpLFxuICAgICAgc2VydmljZXM6IG5ldyBNYXAoKSxcbiAgICAgIHN0YXJ0aW5nOiBuZXcgTWFwKCksXG4gICAgfTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdG9yZWQgPSBhd2FpdCB0aGlzLmJvb3RzdHJhcChzZXNzaW9uLCBvcGVyYXRpb25TaWduYWwpO1xuICAgICAgdGhpcy5tZXRyaWNzLnN0b3AoKTtcbiAgICAgIHRoaXMubWV0cmljcy5zZWVkKChhd2FpdCB0aGlzLmFkbWluKHNlc3Npb24sIFtcIm1ldHJpY3NcIl0sIG9wZXJhdGlvblNpZ25hbCkpLnN0ZG91dCk7XG4gICAgICB0aGlzLmJvb3QgPSBib290O1xuICAgICAgdGhpcy5yZWFkeUJvb3RLZXkgPSBrZXk7XG4gICAgICB0aGlzLndhdGNoSWRsZSgpO1xuICAgICAgaWYgKHRoaXMubWV0cmljcy5saXN0ZW5lckNvdW50KFwic25hcHNob3RcIikgPiAwKSB0aGlzLm1ldHJpY3Muc3RhcnQoKTtcbiAgICAgIGZvciAoY29uc3QgaGFzaCBvZiByZXN0b3JlZCkgdm9pZCB0aGlzLnJlc3RvcmVVc2VyKGJvb3QsIGhhc2gpO1xuICAgICAgcmV0dXJuIGJvb3Q7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGF3YWl0IHNlc3Npb24uY2xvc2UoKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgY29ubmVjdChlbnRyeTogTGFrZWJveEVudHJ5LCBzaWduYWw6IEFib3J0U2lnbmFsKTogUHJvbWlzZTxTc2hTZXNzaW9uPiB7XG4gICAgY29uc3QgYXBpID0gdGhpcy5jbGllbnQoKTtcbiAgICBjb25zdCBzY29wZSA9IGF3YWl0IGFwaS53b3Jrc3BhY2VTY29wZSgpO1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IHRoaXMua2V5cy5lbnN1cmVSZWdpc3RlcmVkKGFwaSwgU1NIX0tFWV9PV05FUiwgc2lnbmFsKTtcbiAgICBjb25zdCBnYXRld2F5SG9zdCA9IGVudHJ5LmdhdGV3YXlIb3N0ID8/IGtleS5nYXRld2F5SG9zdDtcbiAgICBpZiAoIWdhdGV3YXlIb3N0KSB0aHJvdyBuZXcgRXJyb3IoXCJEYXRhYnJpY2tzIExha2Vib3ggZGlkIG5vdCByZXR1cm4gYW4gU1NIIGdhdGV3YXkgaG9zdFwiKTtcbiAgICBjb25zdCBwb3J0ID0gdGhpcy5jb25maWcuZ2F0ZXdheVBvcnQ7XG4gICAgY29uc3Qga25vd25Ib3N0ID0gYXdhaXQgdGhpcy5rZXlzLmtub3duSG9zdChzY29wZSwgU1NIX0tFWV9PV05FUiwgZ2F0ZXdheUhvc3QsIHBvcnQpO1xuICAgIGNvbnN0IHNlc3Npb24gPSBuZXcgU3NoU2Vzc2lvbih7XG4gICAgICBob3N0OiBnYXRld2F5SG9zdCxcbiAgICAgIHBvcnQsXG4gICAgICB1c2VybmFtZTogZW50cnkuc2FuZGJveElkLFxuICAgICAgcHJpdmF0ZUtleToga2V5LnByaXZhdGVLZXksXG4gICAgICBwcml2YXRlS2V5UGF0aDoga2V5LnByaXZhdGVLZXlQYXRoLFxuICAgICAga25vd25Ib3N0c1BhdGg6IHRoaXMua2V5cy5rbm93bkhvc3RzUGF0aChzY29wZSwgU1NIX0tFWV9PV05FUiwgZ2F0ZXdheUhvc3QsIHBvcnQpLFxuICAgICAgY29ubmVjdFRpbWVvdXRNczogdGhpcy5jb25maWcuY29ubmVjdFRpbWVvdXRNcyxcbiAgICAgIHNzaFRyYW5zcG9ydDogdGhpcy5jb25maWcuc3NoVHJhbnNwb3J0LFxuICAgICAgc3NoMlBhdGNoOiB0aGlzLmNvbmZpZy5zc2gyUGF0Y2gsXG4gICAgICAuLi4oa25vd25Ib3N0ID8geyBrbm93bkhvc3QgfSA6IHt9KSxcbiAgICAgIHJlbWVtYmVySG9zdDogKGZpbmdlcnByaW50LCBob3N0S2V5KSA9PlxuICAgICAgICB0aGlzLmtleXMucmVtZW1iZXJIb3N0KHNjb3BlLCBTU0hfS0VZX09XTkVSLCBnYXRld2F5SG9zdCwgcG9ydCwgZmluZ2VycHJpbnQsIGhvc3RLZXkpLFxuICAgIH0pO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBzZXNzaW9uLmNvbm5lY3QoKTtcbiAgICAgIHJldHVybiBzZXNzaW9uO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBhd2FpdCBzZXNzaW9uLmNsb3NlKCk7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICAvKiogUnVucyB0aGUgZml4ZWQgcHJpdmlsZWdlZCBib290c3RyYXAgYW5kIHJldHVybnMgdGhlIHJlc3RvcmVkIHVzZXIgaGFzaGVzLiAqL1xuICBwcml2YXRlIGFzeW5jIGJvb3RzdHJhcChzZXNzaW9uOiBTc2hTZXNzaW9uLCBzaWduYWw6IEFib3J0U2lnbmFsKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIGNvbnN0IGhlbHBlcnMgPSBPYmplY3QuZW50cmllcyhIRUxQRVJTKS5tYXAoXG4gICAgICAoW25hbWUsIGNvbnRlbnRdKSA9PiBgJHtuYW1lfT0ke0J1ZmZlci5mcm9tKGNvbnRlbnQpLnRvU3RyaW5nKFwiYmFzZTY0XCIpfWAsXG4gICAgKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmFkbWluKHNlc3Npb24sIFtcImJvb3RzdHJhcFwiLCAuLi5oZWxwZXJzXSwgc2lnbmFsKTtcbiAgICByZXR1cm4gcmVzdWx0LnN0ZG91dFxuICAgICAgLnNwbGl0KFwiXFxuXCIpXG4gICAgICAuZmlsdGVyKChsaW5lKSA9PiBsaW5lLnN0YXJ0c1dpdGgoXCJfX0xBS0VCT1hfVVNFUl9fPVwiKSlcbiAgICAgIC5tYXAoKGxpbmUpID0+IGxpbmUuc2xpY2UoXCJfX0xBS0VCT1hfVVNFUl9fPVwiLmxlbmd0aCkudHJpbSgpKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgYWRtaW4oXG4gICAgc2Vzc2lvbjogU3NoU2Vzc2lvbixcbiAgICBhcmdzOiByZWFkb25seSBzdHJpbmdbXSxcbiAgICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbiAgKTogUHJvbWlzZTx7IHN0ZG91dDogc3RyaW5nIH0+IHtcbiAgICBjb25zdCBlbmNvZGVkID0gQnVmZmVyLmZyb20oQURNSU5fU0NSSVBUKS50b1N0cmluZyhcImJhc2U2NFwiKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBzZXNzaW9uLmV4ZWN1dGVQcml2aWxlZ2VkKFxuICAgICAgXCJzaFwiLFxuICAgICAgW1wiLWNcIiwgYHByaW50ZiAlcyAnJHtlbmNvZGVkfScgfCBiYXNlNjQgLWQgfCBzaCAtcyAtLSAke2FyZ3MubWFwKHNoZWxsUXVvdGUpLmpvaW4oXCIgXCIpfWBdLFxuICAgICAgeyB0aW1lb3V0TXM6IFNFVFVQX1RJTUVPVVRfTVMsIC4uLihzaWduYWwgPyB7IHNpZ25hbCB9IDoge30pIH0sXG4gICAgKS5yZXN1bHQ7XG4gICAgaWYgKCFyZXN1bHQuc3VjY2Vzcykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgTGFrZWJveCAke2FyZ3NbMF19IGZhaWxlZDogJHtyZXN1bHQuc3RkZXJyLnRyaW0oKSB8fCByZXN1bHQuc3Rkb3V0LnRyaW0oKSB8fCBgZXhpdCAke3Jlc3VsdC5leGl0Q29kZX1gfWAsXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqIE1hcmtzIGFjdGl2aXR5LCByZWFkaWVzIHRoZSBjdXJyZW50IGJvb3QsIGFuZCBjb252ZXJnZXMgdGhlIHVzZXIncyBhY2NvdW50LiAqL1xuICBwcml2YXRlIGFzeW5jIHJlYWR5VXNlcihcbiAgICB1c2VyOiBMYWtlYm94VXNlcixcbiAgICBpZGVudGl0eTogc3RyaW5nLFxuICAgIHNpZ25hbD86IEFib3J0U2lnbmFsLFxuICApOiBQcm9taXNlPEJvb3Q+IHtcbiAgICB0aGlzLnRvdWNoKCk7XG4gICAgY29uc3QgYm9vdCA9IGF3YWl0IHRoaXMucmVhZHkoc2lnbmFsKTtcbiAgICBhd2FpdCB0aGlzLmNvbnZlcmdlVXNlcihib290LCB1c2VyLCBpZGVudGl0eSwgc2lnbmFsKTtcbiAgICByZXR1cm4gYm9vdDtcbiAgfVxuXG4gIC8qKiBDcmVhdGVzIG9yIHZlcmlmaWVzIHRoZSB1c2VyJ3MgYWNjb3VudCBvbmNlIHBlciBib290LiAqL1xuICBwcml2YXRlIGNvbnZlcmdlVXNlcihcbiAgICBib290OiBCb290LFxuICAgIHVzZXI6IExha2Vib3hVc2VyLFxuICAgIGlkZW50aXR5OiBzdHJpbmcsXG4gICAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxldCBjb252ZXJnZWQgPSBib290LnVzZXJzLmdldCh1c2VyLmhhc2gpO1xuICAgIGlmICghY29udmVyZ2VkKSB7XG4gICAgICBjb25zdCBkaWdlc3QgPSBjcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShpZGVudGl0eS50cmltKCkudG9Mb3dlckNhc2UoKSkuZGlnZXN0KFwiaGV4XCIpO1xuICAgICAgY29udmVyZ2VkID0gdGhpcy5hZG1pbihcbiAgICAgICAgYm9vdC5zZXNzaW9uLFxuICAgICAgICBbXCJlbnN1cmUtdXNlclwiLCB1c2VyLmhhc2gsIFN0cmluZyh1c2VyLnVpZCksIGRpZ2VzdF0sXG4gICAgICAgIHNpZ25hbCxcbiAgICAgICkudGhlbigoKSA9PiB1bmRlZmluZWQpO1xuICAgICAgYm9vdC51c2Vycy5zZXQodXNlci5oYXNoLCBjb252ZXJnZWQpO1xuICAgICAgY29udmVyZ2VkLmNhdGNoKCgpID0+IGJvb3QudXNlcnMuZGVsZXRlKHVzZXIuaGFzaCkpO1xuICAgIH1cbiAgICByZXR1cm4gY29udmVyZ2VkO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyByZXN0b3JlVXNlcihib290OiBCb290LCBoYXNoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB1c2VyID0geyBuYW1lOiBgbGFrZWJveC0ke2hhc2h9YCwgaG9tZTogYC9ob21lL2xha2Vib3gtJHtoYXNofWAgfTtcbiAgICBib290LnVzZXJzLnNldChoYXNoLCBQcm9taXNlLnJlc29sdmUoKSk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJvb3Quc2Vzc2lvbi5leGVjdXRlKFwicHl0aG9uM1wiLCBbQ09OVFJPTExFUiwgXCJzdGFydC1hbGxcIl0sIHtcbiAgICAgICAgdXNlcixcbiAgICAgICAgdGltZW91dE1zOiBTRVRVUF9USU1FT1VUX01TLFxuICAgICAgICBzaWduYWw6IHRoaXMuc2h1dGRvd25Db250cm9sbGVyLnNpZ25hbCxcbiAgICAgIH0pLnJlc3VsdDtcbiAgICAgIGlmICghcmVzdWx0LnN1Y2Nlc3MpIHRocm93IG5ldyBFcnJvcihyZXN1bHQuc3RkZXJyLnRyaW0oKSB8fCBgZXhpdCAke3Jlc3VsdC5leGl0Q29kZX1gKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKHRoaXMuc2h1dGRvd25Db250cm9sbGVyLnNpZ25hbC5hYm9ydGVkKSByZXR1cm47XG4gICAgICBsb2dnZXIud2FybihcIkxha2Vib3ggc2VydmljZSByZXN0b3JlIGZhaWxlZFwiLCB7XG4gICAgICAgIHVzZXI6IGhhc2gsXG4gICAgICAgIGVycm9yOiBlcnJvclV0aWxzLnRvRXJyb3IoZXJyb3IpLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjb250cm9sbGVyKFxuICAgIGJvb3Q6IEJvb3QsXG4gICAgdXNlcjogTGFrZWJveFVzZXIsXG4gICAgY29tbWFuZDogc3RyaW5nLFxuICAgIGFyZ3M6IHJlYWRvbmx5IHN0cmluZ1tdLFxuICAgIHNpZ25hbD86IEFib3J0U2lnbmFsLFxuICApOiBQcm9taXNlPHVua25vd24+IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBib290LnNlc3Npb24uZXhlY3V0ZShcInB5dGhvbjNcIiwgW0NPTlRST0xMRVIsIGNvbW1hbmQsIC4uLmFyZ3NdLCB7XG4gICAgICB1c2VyLFxuICAgICAgdGltZW91dE1zOiBTRVRVUF9USU1FT1VUX01TLFxuICAgICAgLi4uKHNpZ25hbCA/IHsgc2lnbmFsIH0gOiB7fSksXG4gICAgfSkucmVzdWx0O1xuICAgIGlmICghcmVzdWx0LnN1Y2Nlc3MpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYExha2Vib3ggc2VydmljZSAke2NvbW1hbmR9IGZhaWxlZDogJHtyZXN1bHQuc3RkZXJyLnRyaW0oKSB8fCBgZXhpdCAke3Jlc3VsdC5leGl0Q29kZX1gfWAsXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gSlNPTi5wYXJzZShyZXN1bHQuc3Rkb3V0KSBhcyB1bmtub3duO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBydW5TZXJ2aWNlKFxuICAgIGJvb3Q6IEJvb3QsXG4gICAgdXNlcjogTGFrZWJveFVzZXIsXG4gICAgZGVmaW5pdGlvbjogTGFrZWJveENvbnRyb2xsZXJEZWZpbml0aW9uLFxuICAgIHNpZ25hbD86IEFib3J0U2lnbmFsLFxuICApOiBQcm9taXNlPExha2Vib3hTZXJ2aWNlPiB7XG4gICAgY29uc3Qga2V5ID0gYCR7dXNlci5oYXNofVxcMCR7ZGVmaW5pdGlvbi5uYW1lfWA7XG4gICAgY29uc3QgcGVuZGluZyA9IGJvb3Quc3RhcnRpbmcuZ2V0KGtleSk7XG4gICAgaWYgKHBlbmRpbmcpIHJldHVybiBwZW5kaW5nO1xuICAgIGNvbnN0IG9wZXJhdGlvbiA9IChhc3luYyAoKSA9PiB7XG4gICAgICBpZiAoZGVmaW5pdGlvbi5raW5kID09PSBcImRlc2t0b3BcIikge1xuICAgICAgICBib290LmRlc2t0b3AgPz89IHRoaXMuYWRtaW4oYm9vdC5zZXNzaW9uLCBbXCJkZXNrdG9wLXByZXJlcXVpc2l0ZXNcIl0sIHNpZ25hbCkudGhlbihcbiAgICAgICAgICAoKSA9PiB1bmRlZmluZWQsXG4gICAgICAgICk7XG4gICAgICAgIGJvb3QuZGVza3RvcC5jYXRjaCgoKSA9PiB7XG4gICAgICAgICAgYm9vdC5kZXNrdG9wID0gdW5kZWZpbmVkO1xuICAgICAgICB9KTtcbiAgICAgICAgYXdhaXQgYm9vdC5kZXNrdG9wO1xuICAgICAgfVxuICAgICAgYXdhaXQgdGhpcy5hZG1pbihcbiAgICAgICAgYm9vdC5zZXNzaW9uLFxuICAgICAgICBbXCJhbGxvdy1wb3J0XCIsIFN0cmluZyh1c2VyLnVpZCksIFN0cmluZyhkZWZpbml0aW9uLnBvcnQpXSxcbiAgICAgICAgc2lnbmFsLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHN0YXJ0ZWQgPSBMYWtlYm94Q29udHJvbGxlclNlcnZpY2VTY2hlbWEucGFyc2UoXG4gICAgICAgIGF3YWl0IHRoaXMuY29udHJvbGxlcihib290LCB1c2VyLCBcInN0YXJ0XCIsIFtkZWZpbml0aW9uLm5hbWVdLCBzaWduYWwpLFxuICAgICAgKTtcbiAgICAgIHRoaXMuY2FjaGVTZXJ2aWNlKGJvb3QsIHVzZXIsIHN0YXJ0ZWQpO1xuICAgICAgcmV0dXJuIHRvTGFrZWJveFNlcnZpY2Uoc3RhcnRlZCwgdXNlciwgdGhpcy5jb25maWcucm91dGVQcmVmaXgpO1xuICAgIH0pKCkuZmluYWxseSgoKSA9PiBib290LnN0YXJ0aW5nLmRlbGV0ZShrZXkpKTtcbiAgICBib290LnN0YXJ0aW5nLnNldChrZXksIG9wZXJhdGlvbik7XG4gICAgcmV0dXJuIG9wZXJhdGlvbjtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcmVmcmVzaFNlcnZpY2VzKFxuICAgIGJvb3Q6IEJvb3QsXG4gICAgdXNlcjogTGFrZWJveFVzZXIsXG4gICAgaWRlbnRpdHk6IHN0cmluZyxcbiAgICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbiAgKTogUHJvbWlzZTxNYXA8c3RyaW5nLCBMYWtlYm94Q29udHJvbGxlclNlcnZpY2U+PiB7XG4gICAgYXdhaXQgdGhpcy5jb252ZXJnZVVzZXIoYm9vdCwgdXNlciwgaWRlbnRpdHksIHNpZ25hbCk7XG4gICAgY29uc3QgcmVzcG9uc2UgPSAoYXdhaXQgdGhpcy5jb250cm9sbGVyKGJvb3QsIHVzZXIsIFwibGlzdFwiLCBbXSwgc2lnbmFsKSkgYXMge1xuICAgICAgc2VydmljZXM/OiB1bmtub3duW107XG4gICAgfTtcbiAgICBjb25zdCBzZXJ2aWNlcyA9IG5ldyBNYXAoXG4gICAgICAocmVzcG9uc2Uuc2VydmljZXMgPz8gW10pLm1hcCgoc2VydmljZSkgPT4ge1xuICAgICAgICBjb25zdCBwYXJzZWQgPSBMYWtlYm94Q29udHJvbGxlclNlcnZpY2VTY2hlbWEucGFyc2Uoc2VydmljZSk7XG4gICAgICAgIHJldHVybiBbcGFyc2VkLm5hbWUsIHBhcnNlZF0gYXMgY29uc3Q7XG4gICAgICB9KSxcbiAgICApO1xuICAgIGJvb3Quc2VydmljZXMuc2V0KHVzZXIuaGFzaCwgc2VydmljZXMpO1xuICAgIHRoaXMubGFzdFNlcnZpY2VzLnNldCh1c2VyLmhhc2gsIHNlcnZpY2VzKTtcbiAgICBjb25zdCBvYnNlcnZlZEF0ID0gbmV3IERhdGUoKS50b0lTT1N0cmluZygpO1xuICAgIHRoaXMubGFzdFNlcnZpY2VzT2JzZXJ2ZWRBdC5zZXQodXNlci5oYXNoLCBvYnNlcnZlZEF0KTtcbiAgICBhd2FpdCB0aGlzLnBlcnNpc3RTZXJ2aWNlU25hcHNob3QoYm9vdC5lbnRyeSwgdXNlciwgc2VydmljZXMsIG9ic2VydmVkQXQpO1xuICAgIHJldHVybiBzZXJ2aWNlcztcbiAgfVxuXG4gIHByaXZhdGUgY2FjaGVTZXJ2aWNlKGJvb3Q6IEJvb3QsIHVzZXI6IExha2Vib3hVc2VyLCBzZXJ2aWNlOiBMYWtlYm94Q29udHJvbGxlclNlcnZpY2UpOiB2b2lkIHtcbiAgICBjb25zdCBzZXJ2aWNlcyA9IGJvb3Quc2VydmljZXMuZ2V0KHVzZXIuaGFzaCkgPz8gbmV3IE1hcDxzdHJpbmcsIExha2Vib3hDb250cm9sbGVyU2VydmljZT4oKTtcbiAgICBzZXJ2aWNlcy5zZXQoc2VydmljZS5uYW1lLCBzZXJ2aWNlKTtcbiAgICBib290LnNlcnZpY2VzLnNldCh1c2VyLmhhc2gsIHNlcnZpY2VzKTtcbiAgICB0aGlzLmxhc3RTZXJ2aWNlcy5zZXQodXNlci5oYXNoLCBzZXJ2aWNlcyk7XG4gICAgY29uc3Qgb2JzZXJ2ZWRBdCA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcbiAgICB0aGlzLmxhc3RTZXJ2aWNlc09ic2VydmVkQXQuc2V0KHVzZXIuaGFzaCwgb2JzZXJ2ZWRBdCk7XG4gICAgdm9pZCB0aGlzLnBlcnNpc3RTZXJ2aWNlU25hcHNob3QoYm9vdC5lbnRyeSwgdXNlciwgc2VydmljZXMsIG9ic2VydmVkQXQpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzZXJ2aWNlTGlzdGluZyhcbiAgICBpZGVudGl0eTogc3RyaW5nLFxuICAgIHVzZXI6IExha2Vib3hVc2VyLFxuICAgIGVudHJ5OiBMYWtlYm94RW50cnkgfCB1bmRlZmluZWQsXG4gICAgc3RhdHVzOiBMYWtlYm94U3RhdHVzLFxuICAgIHNpZ25hbD86IEFib3J0U2lnbmFsLFxuICApOiBQcm9taXNlPFNlcnZpY2VMaXN0aW5nPiB7XG4gICAgaWYgKCFlbnRyeSB8fCBzdGF0dXMgPT09IFwibWlzc2luZ1wiKSB7XG4gICAgICByZXR1cm4geyBzZXJ2aWNlczogdGhpcy5pZGxlU2VydmljZXModXNlciksIHN0YWxlOiBmYWxzZSB9O1xuICAgIH1cbiAgICBpZiAoc3RhdHVzID09PSBcInJ1bm5pbmdcIiAmJiB0aGlzLmJvb3Q/LmtleSA9PT0gdGhpcy5ib290S2V5KGVudHJ5KSkge1xuICAgICAgY29uc3Qgc2VydmljZXMgPSBhd2FpdCB0aGlzLnJlZnJlc2hTZXJ2aWNlcyh0aGlzLmJvb3QsIHVzZXIsIGlkZW50aXR5LCBzaWduYWwpO1xuICAgICAgcmV0dXJuIHsgc2VydmljZXM6IHRoaXMud2l0aEJ1aWx0SW5zKHVzZXIsIHNlcnZpY2VzKSwgc3RhbGU6IGZhbHNlIH07XG4gICAgfVxuICAgIGNvbnN0IG1lbW9yeSA9IHRoaXMubGFzdFNlcnZpY2VzLmdldCh1c2VyLmhhc2gpO1xuICAgIGlmIChtZW1vcnkpIHtcbiAgICAgIGNvbnN0IG9ic2VydmVkQXQgPSB0aGlzLmxhc3RTZXJ2aWNlc09ic2VydmVkQXQuZ2V0KHVzZXIuaGFzaCk7XG4gICAgICBjb25zdCBzZXJ2aWNlcyA9XG4gICAgICAgIHN0YXR1cyA9PT0gXCJydW5uaW5nXCJcbiAgICAgICAgICA/IG1lbW9yeVxuICAgICAgICAgIDogc3RvcHBlZFNuYXBzaG90U2VydmljZXMoe1xuICAgICAgICAgICAgICBvYnNlcnZlZEF0OiBvYnNlcnZlZEF0ID8/IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgICAgICAgZGVmaW5pdGlvbnM6IFsuLi5tZW1vcnkudmFsdWVzKCldLm1hcCgoc2VydmljZSkgPT4gc2VydmljZS5kZWZpbml0aW9uKSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc2VydmljZXM6IHRoaXMud2l0aEJ1aWx0SW5zKHVzZXIsIHNlcnZpY2VzKSxcbiAgICAgICAgc3RhbGU6IHRydWUsXG4gICAgICAgIC4uLihvYnNlcnZlZEF0ID8geyBvYnNlcnZlZEF0IH0gOiB7fSksXG4gICAgICB9O1xuICAgIH1cbiAgICBjb25zdCBzbmFwc2hvdCA9IGF3YWl0IHRoaXMuc2VydmljZVNuYXBzaG90cz8ucmVhZChlbnRyeS5zYW5kYm94SWQsIHVzZXIuaGFzaCk7XG4gICAgcmV0dXJuIHNuYXBzaG90XG4gICAgICA/IHtcbiAgICAgICAgICBzZXJ2aWNlczogdGhpcy53aXRoQnVpbHRJbnModXNlciwgc3RvcHBlZFNuYXBzaG90U2VydmljZXMoc25hcHNob3QpKSxcbiAgICAgICAgICBzdGFsZTogdHJ1ZSxcbiAgICAgICAgICBvYnNlcnZlZEF0OiBzbmFwc2hvdC5vYnNlcnZlZEF0LFxuICAgICAgICB9XG4gICAgICA6IHsgc2VydmljZXM6IHRoaXMuaWRsZVNlcnZpY2VzKHVzZXIpLCBzdGFsZTogdHJ1ZSB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBwZXJzaXN0U2VydmljZVNuYXBzaG90KFxuICAgIGVudHJ5OiBMYWtlYm94RW50cnksXG4gICAgdXNlcjogTGFrZWJveFVzZXIsXG4gICAgc2VydmljZXM6IFJlYWRvbmx5TWFwPHN0cmluZywgTGFrZWJveENvbnRyb2xsZXJTZXJ2aWNlPixcbiAgICBvYnNlcnZlZEF0OiBzdHJpbmcsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuc2VydmljZVNuYXBzaG90cz8ud3JpdGUoZW50cnkuc2FuZGJveElkLCB1c2VyLmhhc2gsIHtcbiAgICAgIG9ic2VydmVkQXQsXG4gICAgICBkZWZpbml0aW9uczogWy4uLnNlcnZpY2VzLnZhbHVlcygpXS5tYXAoKHNlcnZpY2UpID0+IHNlcnZpY2UuZGVmaW5pdGlvbiksXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHdpdGhCdWlsdElucyhcbiAgICB1c2VyOiBMYWtlYm94VXNlcixcbiAgICBzZXJ2aWNlczogUmVhZG9ubHlNYXA8c3RyaW5nLCBMYWtlYm94Q29udHJvbGxlclNlcnZpY2U+LFxuICApOiBMYWtlYm94U2VydmljZVtdIHtcbiAgICBjb25zdCBidWlsdElucyA9IExBS0VCT1hfQlVJTFRfSU5fU0VSVklDRVMubWFwKCh7IG5hbWUgfSkgPT4ge1xuICAgICAgY29uc3Qgc2F2ZWQgPSBzZXJ2aWNlcy5nZXQobmFtZSk7XG4gICAgICByZXR1cm4gc2F2ZWRcbiAgICAgICAgPyB0b0xha2Vib3hTZXJ2aWNlKHNhdmVkLCB1c2VyLCB0aGlzLmNvbmZpZy5yb3V0ZVByZWZpeClcbiAgICAgICAgOiBpZGxlQnVpbHRJblNlcnZpY2UobmFtZSwgdXNlciwgdGhpcy5jb25maWcucm91dGVQcmVmaXgpO1xuICAgIH0pO1xuICAgIGNvbnN0IGN1c3RvbSA9IFsuLi5zZXJ2aWNlcy52YWx1ZXMoKV1cbiAgICAgIC5maWx0ZXIoKHNlcnZpY2UpID0+ICFMQUtFQk9YX0JVSUxUX0lOX1NFUlZJQ0VTLnNvbWUoKHsgbmFtZSB9KSA9PiBuYW1lID09PSBzZXJ2aWNlLm5hbWUpKVxuICAgICAgLm1hcCgoc2VydmljZSkgPT4gdG9MYWtlYm94U2VydmljZShzZXJ2aWNlLCB1c2VyLCB0aGlzLmNvbmZpZy5yb3V0ZVByZWZpeCkpO1xuICAgIHJldHVybiBbLi4uYnVpbHRJbnMsIC4uLmN1c3RvbV07XG4gIH1cblxuICBwcml2YXRlIGlkbGVTZXJ2aWNlcyh1c2VyOiBMYWtlYm94VXNlcik6IExha2Vib3hTZXJ2aWNlW10ge1xuICAgIHJldHVybiBMQUtFQk9YX0JVSUxUX0lOX1NFUlZJQ0VTLm1hcCgoeyBuYW1lIH0pID0+XG4gICAgICBpZGxlQnVpbHRJblNlcnZpY2UobmFtZSBhcyBMYWtlYm94QnVpbHRJblNlcnZpY2VOYW1lLCB1c2VyLCB0aGlzLmNvbmZpZy5yb3V0ZVByZWZpeCksXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBSZXNvbHZlcyBvbmUgcm91dGVkIHJlcXVlc3QsIHdha2luZyB0aGUgTGFrZWJveCBvciBzZXJ2aWNlIGluIHRoZSBiYWNrZ3JvdW5kLiAqL1xuICBwcml2YXRlIGFzeW5jIHJlc29sdmVSb3V0ZSh1c2VyOiBMYWtlYm94VXNlciwgbmFtZTogc3RyaW5nKTogUHJvbWlzZTxMYWtlYm94Um91dGVSZXNvbHV0aW9uPiB7XG4gICAgdGhpcy50b3VjaCgpO1xuICAgIGNvbnN0IGVudHJ5ID0gYXdhaXQgdGhpcy5lbnRyeSgpO1xuICAgIGNvbnN0IHJ1bm5pbmcgPSBlbnRyeSAmJiBub3JtYWxpemVMYWtlYm94U3RhdHVzKGVudHJ5LnN0YXR1cykgPT09IFwicnVubmluZ1wiO1xuICAgIGNvbnN0IGJvb3QgPSB0aGlzLmJvb3Q7XG4gICAgaWYgKCFydW5uaW5nIHx8ICFib290IHx8IGJvb3Qua2V5ICE9PSB0aGlzLmJvb3RLZXkoZW50cnkpKSB7XG4gICAgICBpZiAoIXRoaXMuY29uZmlnLmF1dG8pIHJldHVybiB7IGtpbmQ6IFwibWlzc2luZ1wiIH07XG4gICAgICB0aGlzLndha2UoKCkgPT4gdGhpcy5yZWFkeSgpKTtcbiAgICAgIHJldHVybiB7IGtpbmQ6IFwibG9hZGluZ1wiIH07XG4gICAgfVxuICAgIGNvbnN0IGlkZW50aXR5ID0gdGhpcy5yb3V0ZWRJZGVudGl0aWVzLmdldCh1c2VyLmhhc2gpO1xuICAgIGlmICghaWRlbnRpdHkpIHJldHVybiB7IGtpbmQ6IFwibWlzc2luZ1wiIH07XG4gICAgbGV0IHNlcnZpY2UgPSBib290LnNlcnZpY2VzLmdldCh1c2VyLmhhc2gpPy5nZXQobmFtZSk7XG4gICAgaWYgKCFzZXJ2aWNlKSBzZXJ2aWNlID0gKGF3YWl0IHRoaXMucmVmcmVzaFNlcnZpY2VzKGJvb3QsIHVzZXIsIGlkZW50aXR5KSkuZ2V0KG5hbWUpO1xuICAgIGNvbnN0IGJ1aWx0SW4gPSBsYWtlYm94QnVpbHRJblNlcnZpY2VOYW1lU2NoZW1hLnNhZmVQYXJzZShuYW1lKTtcbiAgICBpZiAoIXNlcnZpY2UgJiYgIWJ1aWx0SW4uc3VjY2VzcykgcmV0dXJuIHsga2luZDogXCJtaXNzaW5nXCIgfTtcbiAgICBpZiAoc2VydmljZT8uc3RhdGUgPT09IFwicmVhZHlcIikge1xuICAgICAgcmV0dXJuIHsga2luZDogXCJyZWFkeVwiLCBzZXNzaW9uOiBib290LnNlc3Npb24sIHJvdXRlOiBzZXJ2aWNlUm91dGUoc2VydmljZS5kZWZpbml0aW9uKSB9O1xuICAgIH1cbiAgICBpZiAoc2VydmljZT8uc3RhdGUgPT09IFwiZXJyb3JcIiAmJiAhYm9vdC5zdGFydGluZy5oYXMoYCR7dXNlci5oYXNofVxcMCR7bmFtZX1gKSkge1xuICAgICAgcmV0dXJuIHsga2luZDogXCJmYWlsZWRcIiwgbWVzc2FnZTogc2VydmljZS5lcnJvciA/PyBcInRoZSBzZXJ2aWNlIGZhaWxlZCB0byBzdGFydFwiIH07XG4gICAgfVxuICAgIGNvbnN0IGRlZmluaXRpb24gPSBzZXJ2aWNlPy5kZWZpbml0aW9uID8/IGJ1aWx0SW5EZWZpbml0aW9uKGJ1aWx0SW4uZGF0YSEsIHVzZXIpO1xuICAgIHRoaXMud2FrZShhc3luYyAoKSA9PiB7XG4gICAgICBpZiAoIXNlcnZpY2UpIGF3YWl0IHRoaXMuY29udHJvbGxlcihib290LCB1c2VyLCBcInB1dFwiLCBbZW5jb2RlKGRlZmluaXRpb24pXSk7XG4gICAgICBhd2FpdCB0aGlzLnJ1blNlcnZpY2UoYm9vdCwgdXNlciwgZGVmaW5pdGlvbik7XG4gICAgfSk7XG4gICAgcmV0dXJuIHsga2luZDogXCJsb2FkaW5nXCIgfTtcbiAgfVxuXG4gIHByaXZhdGUgbWFya1VuYXZhaWxhYmxlKHVzZXI6IExha2Vib3hVc2VyLCBuYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmJvb3Q/LnNlcnZpY2VzLmdldCh1c2VyLmhhc2gpPy5kZWxldGUobmFtZSk7XG4gICAgdGhpcy5jYWNoZWQgPSB1bmRlZmluZWQ7XG4gIH1cblxuICBwcml2YXRlIHdha2UoYWN0aW9uOiAoKSA9PiBQcm9taXNlPHVua25vd24+KTogdm9pZCB7XG4gICAgaWYgKHRoaXMud2FraW5nKSByZXR1cm47XG4gICAgdGhpcy53YWtpbmcgPSBhY3Rpb24oKVxuICAgICAgLmNhdGNoKChlcnJvcikgPT4gbG9nZ2VyLndhcm4oXCJMYWtlYm94IHdha2UgZmFpbGVkXCIsIHsgZXJyb3I6IGVycm9yVXRpbHMudG9FcnJvcihlcnJvcikgfSkpXG4gICAgICAuZmluYWxseSgoKSA9PiB7XG4gICAgICAgIHRoaXMud2FraW5nID0gdW5kZWZpbmVkO1xuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJlYWRNZXRyaWNzKHNpZ25hbDogQWJvcnRTaWduYWwpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IGJvb3QgPSB0aGlzLmJvb3Q7XG4gICAgaWYgKCFib290KSB0aHJvdyBuZXcgRXJyb3IoXCJMYWtlYm94IGlzIG5vdCBydW5uaW5nXCIpO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gKGF3YWl0IHRoaXMuYWRtaW4oYm9vdC5zZXNzaW9uLCBbXCJtZXRyaWNzXCJdLCBzaWduYWwpKS5zdGRvdXQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMuY2FjaGVkID0gdW5kZWZpbmVkO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBsZWFzZU1ldHJpY3MoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmJvb3QpIHJldHVybjtcbiAgICB0aGlzLm1ldHJpY3Muc3RhcnQoKTtcbiAgICBpZiAodGhpcy5tZXRyaWNzTGVhc2UpIGNsZWFyVGltZW91dCh0aGlzLm1ldHJpY3NMZWFzZSk7XG4gICAgdGhpcy5tZXRyaWNzTGVhc2UgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIGlmICh0aGlzLm1ldHJpY3MubGlzdGVuZXJDb3VudChcInNuYXBzaG90XCIpID09PSAwKSB0aGlzLm1ldHJpY3Muc3RvcCgpO1xuICAgIH0sIE1FVFJJQ1NfTEVBU0VfTVMpO1xuICAgIHRoaXMubWV0cmljc0xlYXNlLnVucmVmPy4oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWxlYXNlcyB0aGUgU1NIIHNlc3Npb24gYWZ0ZXIgdGhlIGlkbGUgdGltZW91dCB3aXRob3V0IGNvbW1hbmRzLCBzZXJ2aWNlXG4gICAqIG9wZXJhdGlvbnMsIHJvdXRlZCB0cmFmZmljLCBvcGVuIHN0cmVhbXMsIG9yIG1ldHJpY3Mgd2F0Y2hlcnMuIEFuIG9wZW5cbiAgICogc2Vzc2lvbiBjb3VudHMgYXMgYWN0aXZpdHkgZm9yIHRoZSBwbGF0Zm9ybSB3YXRjaGRvZywgc28gcmVsZWFzaW5nIGl0IGxldHNcbiAgICogdGhlIHBsYXRmb3JtIHN0b3AgdGhlIExha2Vib3ggYWZ0ZXIgaXRzIG93biBpZGxlIHRpbWVvdXQuIFRoZSBuZXh0IHJlcXVlc3RcbiAgICogcmVjb25uZWN0cy5cbiAgICovXG4gIHByaXZhdGUgd2F0Y2hJZGxlKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlkbGVUaW1lcikgY2xlYXJJbnRlcnZhbCh0aGlzLmlkbGVUaW1lcik7XG4gICAgdGhpcy5pZGxlVGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICBjb25zdCBpZGxlTXMgPSBEYXRlLm5vdygpIC0gdGhpcy5sYXN0QWN0aXZpdHk7XG4gICAgICBpZiAoXG4gICAgICAgICF0aGlzLmJvb3QgfHxcbiAgICAgICAgdGhpcy5jb252ZXJnaW5nIHx8XG4gICAgICAgIGlkbGVNcyA8IHRoaXMuY29uZmlnLmlkbGVUaW1lb3V0U2Vjb25kcyAqIDFfMDAwIHx8XG4gICAgICAgIHRoaXMuYWN0aXZlQ29tbWFuZHMgPiAwIHx8XG4gICAgICAgIHRoaXMuYm9vdC5zdGFydGluZy5zaXplID4gMCB8fFxuICAgICAgICB0aGlzLnJvdXRlcy5hY3RpdmVDb25uZWN0aW9ucygpID4gMCB8fFxuICAgICAgICB0aGlzLm1ldHJpY3MubGlzdGVuZXJDb3VudChcInNuYXBzaG90XCIpID4gMFxuICAgICAgKSB7XG4gICAgICAgIGlmICh0aGlzLnJvdXRlcy5hY3RpdmVDb25uZWN0aW9ucygpID4gMCB8fCB0aGlzLmFjdGl2ZUNvbW1hbmRzID4gMCkgdGhpcy50b3VjaCgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBsb2dnZXIuaW5mbyhcInJlbGVhc2luZyBpZGxlIExha2Vib3ggc2Vzc2lvblwiLCB7IGlkbGVTZWNvbmRzOiBNYXRoLnJvdW5kKGlkbGVNcyAvIDFfMDAwKSB9KTtcbiAgICAgIHZvaWQgdGhpcy5kaXNjYXJkQm9vdCgpO1xuICAgIH0sIElETEVfQ0hFQ0tfTVMpO1xuICAgIHRoaXMuaWRsZVRpbWVyLnVucmVmPy4oKTtcbiAgfVxuXG4gIHByaXZhdGUgdG91Y2goKTogdm9pZCB7XG4gICAgdGhpcy5sYXN0QWN0aXZpdHkgPSBEYXRlLm5vdygpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBkaXNjYXJkQm9vdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5pZGxlVGltZXIpIGNsZWFySW50ZXJ2YWwodGhpcy5pZGxlVGltZXIpO1xuICAgIHRoaXMuaWRsZVRpbWVyID0gdW5kZWZpbmVkO1xuICAgIGNvbnN0IGJvb3QgPSB0aGlzLmJvb3Q7XG4gICAgdGhpcy5ib290ID0gdW5kZWZpbmVkO1xuICAgIHRoaXMubWV0cmljcy5zdG9wKCk7XG4gICAgYXdhaXQgdGhpcy5yb3V0ZXMuY2xvc2VCcmlkZ2VzKCk7XG4gICAgYXdhaXQgYm9vdD8uc2Vzc2lvbi5jbG9zZSgpLmNhdGNoKCgpID0+IHVuZGVmaW5lZCk7XG4gIH1cbn1cblxuZnVuY3Rpb24gZW5jb2RlKGRlZmluaXRpb246IExha2Vib3hDb250cm9sbGVyRGVmaW5pdGlvbik6IHN0cmluZyB7XG4gIHJldHVybiBCdWZmZXIuZnJvbShKU09OLnN0cmluZ2lmeShkZWZpbml0aW9uKSkudG9TdHJpbmcoXCJiYXNlNjRcIik7XG59XG5cbmZ1bmN0aW9uIHNoZWxsUXVvdGUodmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgJyR7dmFsdWUucmVwbGFjZUFsbChcIidcIiwgXCInXFxcXCcnXCIpfSdgO1xufVxuXG4vKiogUmV0dXJucyB3aGV0aGVyIGFuIGVycm9yIG1lYW5zIHRoZSBtYW5hZ2VkIExha2Vib3ggbm8gbG9uZ2VyIGV4aXN0cy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0xha2Vib3hNaXNzaW5nKGVycm9yOiB1bmtub3duKTogYm9vbGVhbiB7XG4gIHJldHVybiBlcnJvciBpbnN0YW5jZW9mIExha2Vib3hBcGlFcnJvciAmJiBlcnJvci5zdGF0dXMgPT09IDQwNDtcbn1cbiJdfQ==
|