@dbx-tools/appkit-lakebox 0.0.0-stage → 0.9.132
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 +197 -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,329 @@
|
|
|
1
|
+
import { createWorkspaceClient, lakebase, toPlugin, } from "@databricks/appkit";
|
|
2
|
+
import { executeFromRegistry, } from "@databricks/appkit/beta";
|
|
3
|
+
import { USER_EMAIL_HEADER, USER_ID_HEADER, appkit, lakebaseResolver, pluginRegistry, toolkitEntries, toolOperations, ToolRegistryPlugin, } from "@dbx-tools/appkit";
|
|
4
|
+
import { createLakeboxServiceOperationSchema, executeLakeboxCommandOperationSchema, getLakeboxOperationSchema, getLakeboxServiceLogsOperationSchema, LAKEBOX_PLUGIN_NAME, LAKEBOX_ROUTES, lakeboxCommandRequestSchema, lakeboxServiceActionSchema, lakeboxServiceLogsRequestSchema, listLakeboxServicesOperationSchema, removeLakeboxServiceOperationSchema, startLakeboxServiceOperationSchema, stopLakeboxServiceOperationSchema, } from "@dbx-tools/shared-lakebox";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { LakeboxResourceRegistry } from "./_resource-registry.js";
|
|
7
|
+
import { LakeboxServiceSnapshots } from "./_service-snapshots.js";
|
|
8
|
+
import { LakeboxPluginConfigSchema, resolveLakeboxPluginConfig, } from "./config.js";
|
|
9
|
+
import { LakeboxRuntime } from "./runtime.js";
|
|
10
|
+
import { withServiceOrigin } from "./services.js";
|
|
11
|
+
const CONFIG_SCHEMA = z.toJSONSchema(LakeboxPluginConfigSchema);
|
|
12
|
+
/**
|
|
13
|
+
* AppKit plugin for the single app Lakebox.
|
|
14
|
+
*
|
|
15
|
+
* Registers user-scoped REST routes, agent tools, the deterministic service
|
|
16
|
+
* proxy, and WebSocket upgrade handling. Every Lakebox lifecycle call uses the
|
|
17
|
+
* app service principal; the authenticated request identity only selects the
|
|
18
|
+
* user's Lakebox account and authorizes that user's routes.
|
|
19
|
+
*/
|
|
20
|
+
export class AppKitLakeboxPlugin extends ToolRegistryPlugin {
|
|
21
|
+
static manifest = {
|
|
22
|
+
name: LAKEBOX_PLUGIN_NAME,
|
|
23
|
+
displayName: "Lakebox",
|
|
24
|
+
description: "Runs per-user services, terminals, desktops, and commands in one lazily created Databricks Lakebox.",
|
|
25
|
+
stability: "beta",
|
|
26
|
+
resources: { required: [], optional: [] },
|
|
27
|
+
config: { schema: CONFIG_SCHEMA },
|
|
28
|
+
};
|
|
29
|
+
runtime;
|
|
30
|
+
mounted = false;
|
|
31
|
+
httpServer;
|
|
32
|
+
upgradeAttachTimer;
|
|
33
|
+
upgradeIdentityGate;
|
|
34
|
+
upgradeHandler = (request, socket, head) => {
|
|
35
|
+
void this.handleUpgrade(request, socket, head);
|
|
36
|
+
};
|
|
37
|
+
/** Creates a plugin with a supplied shared runtime or one from resolved config. */
|
|
38
|
+
constructor(config = {}) {
|
|
39
|
+
super(config);
|
|
40
|
+
this.runtime = config.runtime ?? new LakeboxRuntime(resolveLakeboxPluginConfig(config));
|
|
41
|
+
}
|
|
42
|
+
get toolRegistry() {
|
|
43
|
+
return this.createToolRegistry();
|
|
44
|
+
}
|
|
45
|
+
async setup() {
|
|
46
|
+
this.context?.onLifecycle("setup:complete", async () => {
|
|
47
|
+
const pool = lakebaseResolver.captureServicePrincipalPool(pluginRegistry.require(this.context, lakebase, "appkit-lakebox").exports().pool);
|
|
48
|
+
this.runtime.initialize(createWorkspaceClient().config, (headers) => this.requestIdentity(headers), new LakeboxServiceSnapshots(), new LakeboxResourceRegistry(this.runtime.config.application, pool));
|
|
49
|
+
void this.runtime.cleanupLegacy(pool);
|
|
50
|
+
const server = this.context?.getPlugins().get("server");
|
|
51
|
+
if (!server || this.mounted)
|
|
52
|
+
return;
|
|
53
|
+
this.upgradeIdentityGate = resolveUpgradeIdentityGate(this.context?.getPlugins().get("authGate"));
|
|
54
|
+
server.addExtension((application) => application.use(this.runtime.routes.middleware()));
|
|
55
|
+
this.mounted = true;
|
|
56
|
+
this.attachUpgradeHandler(server);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
injectRoutes(router) {
|
|
60
|
+
const json = (name, method, path, handler) => this.route(router, {
|
|
61
|
+
name,
|
|
62
|
+
method,
|
|
63
|
+
path,
|
|
64
|
+
handler: async (req, res) => {
|
|
65
|
+
res.json(await handler(this.resolveUserId(req), req));
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
json("status", "get", LAKEBOX_ROUTES.status, (identity) => this.runtime.summary(identity));
|
|
69
|
+
json("start", "post", LAKEBOX_ROUTES.start, async (identity) => {
|
|
70
|
+
await this.runtime.start();
|
|
71
|
+
return this.runtime.summary(identity);
|
|
72
|
+
});
|
|
73
|
+
json("stop", "post", LAKEBOX_ROUTES.stop, async (identity) => {
|
|
74
|
+
await this.runtime.stop();
|
|
75
|
+
return this.runtime.summary(identity);
|
|
76
|
+
});
|
|
77
|
+
json("executeCommand", "post", LAKEBOX_ROUTES.commands, (identity, req) => this.runtime.execute(identity, lakeboxCommandRequestSchema.parse(req.body ?? {})).result);
|
|
78
|
+
json("services", "get", LAKEBOX_ROUTES.services, async (identity) => ({
|
|
79
|
+
services: await this.runtime.listServices(identity),
|
|
80
|
+
}));
|
|
81
|
+
json("createService", "post", LAKEBOX_ROUTES.services, async (identity, req) => ({
|
|
82
|
+
service: await this.runtime.createService(identity, req.body ?? {}),
|
|
83
|
+
}));
|
|
84
|
+
json("startService", "post", LAKEBOX_ROUTES.serviceStart, async (identity, req) => ({
|
|
85
|
+
service: await this.runtime.startService(identity, serviceName(req)),
|
|
86
|
+
}));
|
|
87
|
+
json("stopService", "post", LAKEBOX_ROUTES.serviceStop, async (identity, req) => ({
|
|
88
|
+
service: await this.runtime.stopService(identity, serviceName(req)),
|
|
89
|
+
}));
|
|
90
|
+
json("removeService", "delete", LAKEBOX_ROUTES.service, async (identity, req) => ({
|
|
91
|
+
removed: await this.runtime.removeService(identity, serviceName(req)),
|
|
92
|
+
}));
|
|
93
|
+
json("serviceLogs", "get", LAKEBOX_ROUTES.serviceLogs, (identity, req) => this.runtime.serviceLogs(identity, lakeboxServiceLogsRequestSchema.parse({
|
|
94
|
+
name: req.params.name,
|
|
95
|
+
maxLines: req.query.maxLines,
|
|
96
|
+
maxChars: req.query.maxChars,
|
|
97
|
+
})));
|
|
98
|
+
json("metrics", "get", LAKEBOX_ROUTES.metrics, () => this.runtime.metricsResponse());
|
|
99
|
+
this.route(router, {
|
|
100
|
+
name: "metricsStream",
|
|
101
|
+
method: "get",
|
|
102
|
+
path: LAKEBOX_ROUTES.metricsStream,
|
|
103
|
+
handler: async (req, res) => this.streamMetrics(req, res),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/** Returns browser-safe route defaults published through AppKit client config. */
|
|
107
|
+
clientConfig() {
|
|
108
|
+
return { routePrefix: this.runtime.config.routePrefix };
|
|
109
|
+
}
|
|
110
|
+
/** Returns selected AppKit toolkit entries backed by this plugin's agent tools. */
|
|
111
|
+
toolkit(options) {
|
|
112
|
+
return toolkitEntries.entries(LAKEBOX_PLUGIN_NAME, this.getAgentTools(), {
|
|
113
|
+
...options,
|
|
114
|
+
prefix: options?.prefix ?? "",
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/** Executes one registered agent tool for the current execution identity. */
|
|
118
|
+
executeAgentTool(name, args, signal, context) {
|
|
119
|
+
return executeFromRegistry(this.createToolRegistry(context?.resourceId, context?.origin), name, args, signal);
|
|
120
|
+
}
|
|
121
|
+
/** Returns the typed sibling-plugin API. */
|
|
122
|
+
exports() {
|
|
123
|
+
return {
|
|
124
|
+
summary: (identity) => this.runtime.summary(identity),
|
|
125
|
+
start: () => this.runtime.start(),
|
|
126
|
+
stop: () => this.runtime.stop(),
|
|
127
|
+
delete: () => this.runtime.delete(),
|
|
128
|
+
executeCommand: (identity, input) => this.runtime.execute(identity, input).result,
|
|
129
|
+
listServices: (identity) => this.runtime.listServices(identity),
|
|
130
|
+
createService: (identity, input) => this.runtime.createService(identity, input),
|
|
131
|
+
startService: (identity, name) => this.runtime.startService(identity, name),
|
|
132
|
+
stopService: (identity, name) => this.runtime.stopService(identity, name),
|
|
133
|
+
removeService: (identity, name) => this.runtime.removeService(identity, name),
|
|
134
|
+
serviceLogs: (identity, input) => this.runtime.serviceLogs(identity, input),
|
|
135
|
+
operations: (identity) => this.operations(identity),
|
|
136
|
+
toolkit: (options) => this.toolkit(options),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/** Cancels in-flight work before shutdown tears down resources. */
|
|
140
|
+
abortActiveOperations() {
|
|
141
|
+
this.runtime.abortActiveOperations();
|
|
142
|
+
}
|
|
143
|
+
/** Detaches WebSocket handling and closes the shared runtime. */
|
|
144
|
+
async shutdown() {
|
|
145
|
+
if (this.upgradeAttachTimer)
|
|
146
|
+
clearTimeout(this.upgradeAttachTimer);
|
|
147
|
+
this.upgradeAttachTimer = undefined;
|
|
148
|
+
this.httpServer?.off("upgrade", this.upgradeHandler);
|
|
149
|
+
this.httpServer = undefined;
|
|
150
|
+
await this.runtime.close();
|
|
151
|
+
}
|
|
152
|
+
/** Returns the Zod-owned operation contracts used by agent tools. */
|
|
153
|
+
operations(identity, origin) {
|
|
154
|
+
const user = () => identity ?? this.executionIdentity();
|
|
155
|
+
const presentService = (value) => omitLog(withServiceOrigin(value, origin));
|
|
156
|
+
return toolOperations.defineOperations({
|
|
157
|
+
get_lakebox: {
|
|
158
|
+
schema: getLakeboxOperationSchema,
|
|
159
|
+
execute: async (_input, signal) => {
|
|
160
|
+
const summary = await this.runtime.summary(user(), signal);
|
|
161
|
+
return { ...summary, services: summary.services.map(presentService) };
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
execute_lakebox_command: {
|
|
165
|
+
schema: executeLakeboxCommandOperationSchema,
|
|
166
|
+
execute: (input, signal) => this.runtime.execute(user(), input, signal).result,
|
|
167
|
+
},
|
|
168
|
+
list_lakebox_services: {
|
|
169
|
+
schema: listLakeboxServicesOperationSchema,
|
|
170
|
+
execute: async (_input, signal) => ({
|
|
171
|
+
services: (await this.runtime.listServices(user(), signal)).map(presentService),
|
|
172
|
+
}),
|
|
173
|
+
},
|
|
174
|
+
create_lakebox_service: {
|
|
175
|
+
schema: createLakeboxServiceOperationSchema,
|
|
176
|
+
execute: async (input, signal) => ({
|
|
177
|
+
service: presentService(await this.runtime.createService(user(), input, signal)),
|
|
178
|
+
}),
|
|
179
|
+
},
|
|
180
|
+
start_lakebox_service: {
|
|
181
|
+
schema: startLakeboxServiceOperationSchema,
|
|
182
|
+
execute: async (input, signal) => ({
|
|
183
|
+
service: presentService(await this.runtime.startService(user(), input.name, signal)),
|
|
184
|
+
}),
|
|
185
|
+
},
|
|
186
|
+
stop_lakebox_service: {
|
|
187
|
+
schema: stopLakeboxServiceOperationSchema,
|
|
188
|
+
execute: async (input, signal) => ({
|
|
189
|
+
service: presentService(await this.runtime.stopService(user(), input.name, signal)),
|
|
190
|
+
}),
|
|
191
|
+
},
|
|
192
|
+
remove_lakebox_service: {
|
|
193
|
+
schema: removeLakeboxServiceOperationSchema,
|
|
194
|
+
execute: async (input, signal) => ({
|
|
195
|
+
removed: await this.runtime.removeService(user(), input.name, signal),
|
|
196
|
+
}),
|
|
197
|
+
},
|
|
198
|
+
get_lakebox_service_logs: {
|
|
199
|
+
schema: getLakeboxServiceLogsOperationSchema,
|
|
200
|
+
execute: (input, signal) => this.runtime.serviceLogs(user(), input, signal),
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
createToolRegistry(identity, origin) {
|
|
205
|
+
return toolOperations.toolRegistryFromOperations(this.operations(identity, origin));
|
|
206
|
+
}
|
|
207
|
+
executionIdentity() {
|
|
208
|
+
const context = appkit.tryGetExecutionContext();
|
|
209
|
+
if (!context)
|
|
210
|
+
throw new Error("Lakebox tools require an AppKit execution context");
|
|
211
|
+
return "userId" in context ? context.userId : context.serviceUserId;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Resolves route identity with the same rules as REST: the forwarded user,
|
|
215
|
+
* or AppKit's development user for direct loopback navigation outside
|
|
216
|
+
* production. Everything else is anonymous and fails closed.
|
|
217
|
+
*/
|
|
218
|
+
requestIdentity(headers) {
|
|
219
|
+
const forwarded = headerValue(headers[USER_ID_HEADER])?.trim();
|
|
220
|
+
if (forwarded)
|
|
221
|
+
return forwarded;
|
|
222
|
+
if (process.env.NODE_ENV !== "development" || !isLoopbackHost(headerValue(headers.host))) {
|
|
223
|
+
return undefined;
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
return this.resolveUserId({
|
|
227
|
+
header: (name) => headerValue(headers[name.toLowerCase()]),
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
async streamMetrics(req, res) {
|
|
235
|
+
const initial = await this.runtime.metricsResponse();
|
|
236
|
+
res.statusCode = 200;
|
|
237
|
+
res.setHeader("content-type", "text/event-stream; charset=utf-8");
|
|
238
|
+
res.setHeader("cache-control", "no-cache, no-transform");
|
|
239
|
+
res.setHeader("connection", "keep-alive");
|
|
240
|
+
res.setHeader("x-accel-buffering", "no");
|
|
241
|
+
res.flushHeaders?.();
|
|
242
|
+
res.write(`data: ${JSON.stringify(initial)}\n\n`);
|
|
243
|
+
const unsubscribe = this.runtime.subscribeMetrics((snapshot) => {
|
|
244
|
+
res.write(`data: ${JSON.stringify({ status: "running", series: [snapshot] })}\n\n`);
|
|
245
|
+
});
|
|
246
|
+
req.once("close", unsubscribe);
|
|
247
|
+
}
|
|
248
|
+
attachUpgradeHandler(server) {
|
|
249
|
+
if (this.httpServer || this.upgradeAttachTimer)
|
|
250
|
+
return;
|
|
251
|
+
try {
|
|
252
|
+
this.httpServer = server.getServer();
|
|
253
|
+
this.httpServer.on("upgrade", this.upgradeHandler);
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
this.upgradeAttachTimer = setTimeout(() => {
|
|
257
|
+
this.upgradeAttachTimer = undefined;
|
|
258
|
+
this.attachUpgradeHandler(server);
|
|
259
|
+
}, 10);
|
|
260
|
+
this.upgradeAttachTimer.unref?.();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async handleUpgrade(request, socket, head) {
|
|
264
|
+
const path = new URL(request.url ?? "/", "http://localhost").pathname;
|
|
265
|
+
if (!this.runtime.routes.canHandleUpgrade(path))
|
|
266
|
+
return;
|
|
267
|
+
const gate = this.upgradeIdentityGate;
|
|
268
|
+
if (gate) {
|
|
269
|
+
const headers = requestHeaders(request);
|
|
270
|
+
if (gate.isProtectedHost(headers)) {
|
|
271
|
+
delete request.headers[USER_ID_HEADER];
|
|
272
|
+
delete request.headers[USER_EMAIL_HEADER];
|
|
273
|
+
const userId = await gate.session(headers);
|
|
274
|
+
if (!userId) {
|
|
275
|
+
socket.destroy();
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
request.headers[USER_ID_HEADER] = userId;
|
|
279
|
+
request.headers[USER_EMAIL_HEADER] = userId;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (!(await this.runtime.routes.handleUpgrade(request, socket, head)))
|
|
283
|
+
socket.destroy();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function serviceName(req) {
|
|
287
|
+
return lakeboxServiceActionSchema.parse({ name: req.params.name }).name;
|
|
288
|
+
}
|
|
289
|
+
function omitLog({ log: _log, ...value }) {
|
|
290
|
+
return value;
|
|
291
|
+
}
|
|
292
|
+
function headerValue(value) {
|
|
293
|
+
return Array.isArray(value) ? value[0] : value;
|
|
294
|
+
}
|
|
295
|
+
function isLoopbackHost(host) {
|
|
296
|
+
if (!host)
|
|
297
|
+
return false;
|
|
298
|
+
try {
|
|
299
|
+
const hostname = new URL(`http://${host}`).hostname.toLowerCase();
|
|
300
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
function resolveUpgradeIdentityGate(plugin) {
|
|
307
|
+
const exports = plugin?.exports?.();
|
|
308
|
+
if (typeof exports?.isProtectedHost !== "function" ||
|
|
309
|
+
typeof exports?.session !== "function") {
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
return exports;
|
|
313
|
+
}
|
|
314
|
+
function requestHeaders(request) {
|
|
315
|
+
const headers = new Headers();
|
|
316
|
+
for (const [name, value] of Object.entries(request.headers)) {
|
|
317
|
+
if (Array.isArray(value)) {
|
|
318
|
+
for (const item of value)
|
|
319
|
+
headers.append(name, item);
|
|
320
|
+
}
|
|
321
|
+
else if (value !== undefined) {
|
|
322
|
+
headers.set(name, value);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return headers;
|
|
326
|
+
}
|
|
327
|
+
/** AppKit plugin factory for {@link AppKitLakeboxPlugin}. */
|
|
328
|
+
export const lakebox = toPlugin(AppKitLakeboxPlugin);
|
|
329
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQ0wscUJBQXFCLEVBQ3JCLFFBQVEsRUFDUixRQUFRLEdBR1QsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QixPQUFPLEVBQ0wsbUJBQW1CLEdBSXBCLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixjQUFjLEVBQ2QsTUFBTSxFQUNOLGdCQUFnQixFQUNoQixjQUFjLEVBQ2QsY0FBYyxFQUNkLGNBQWMsRUFDZCxrQkFBa0IsR0FFbkIsTUFBTSxtQkFBbUIsQ0FBQztBQUMzQixPQUFPLEVBQ0wsbUNBQW1DLEVBQ25DLG9DQUFvQyxFQUNwQyx5QkFBeUIsRUFDekIsb0NBQW9DLEVBQ3BDLG1CQUFtQixFQUNuQixjQUFjLEVBQ2QsMkJBQTJCLEVBQzNCLDBCQUEwQixFQUMxQiwrQkFBK0IsRUFDL0Isa0NBQWtDLEVBQ2xDLG1DQUFtQyxFQUNuQyxrQ0FBa0MsRUFDbEMsaUNBQWlDLEdBTWxDLE1BQU0sMkJBQTJCLENBQUM7QUFHbkMsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUN4QixPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNsRSxPQUFPLEVBQ0wseUJBQXlCLEVBQ3pCLDBCQUEwQixHQUUzQixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsY0FBYyxFQUEwQixNQUFNLGNBQWMsQ0FBQztBQUN0RSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFZbEQsTUFBTSxhQUFhLEdBQUcsQ0FBQyxDQUFDLFlBQVksQ0FBQyx5QkFBeUIsQ0FBZ0IsQ0FBQztBQUUvRTs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxPQUFP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Q0FBQztZQUN6QixLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUs7Z0JBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDdkQsQ0FBQzthQUFNLElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQy9CLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzNCLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQztBQUVELDZEQUE2RDtBQUM3RCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLG1CQUFtQixDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IEluY29taW5nSHR0cEhlYWRlcnMsIEluY29taW5nTWVzc2FnZSwgU2VydmVyIGFzIEh0dHBTZXJ2ZXIgfSBmcm9tIFwibm9kZTpodHRwXCI7XG5pbXBvcnQgdHlwZSB7IFNvY2tldCB9IGZyb20gXCJub2RlOm5ldFwiO1xuaW1wb3J0IHtcbiAgY3JlYXRlV29ya3NwYWNlQ2xpZW50LFxuICBsYWtlYmFzZSxcbiAgdG9QbHVnaW4sXG4gIHR5cGUgSUFwcFJvdXRlcixcbiAgdHlwZSBQbHVnaW5NYW5pZmVzdCxcbn0gZnJvbSBcIkBkYXRhYnJpY2tzL2FwcGtpdFwiO1xuaW1wb3J0IHtcbiAgZXhlY3V0ZUZyb21SZWdpc3RyeSxcbiAgdHlwZSBUb29sa2l0RW50cnksXG4gIHR5cGUgVG9vbGtpdE9wdGlvbnMsXG4gIHR5cGUgVG9vbFJlZ2lzdHJ5LFxufSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0L2JldGFcIjtcbmltcG9ydCB7XG4gIFVTRVJfRU1BSUxfSEVBREVSLFxuICBVU0VSX0lEX0hFQURFUixcbiAgYXBwa2l0LFxuICBsYWtlYmFzZVJlc29sdmVyLFxuICBwbHVnaW5SZWdpc3RyeSxcbiAgdG9vbGtpdEVudHJpZXMsXG4gIHRvb2xPcGVyYXRpb25zLFxuICBUb29sUmVnaXN0cnlQbHVnaW4sXG4gIHR5cGUgQWdlbnRUb29sRXhlY3V0aW9uQ29udGV4dCxcbn0gZnJvbSBcIkBkYngtdG9vbHMvYXBwa2l0XCI7XG5pbXBvcnQge1xuICBjcmVhdGVMYWtlYm94U2VydmljZU9wZXJhdGlvblNjaGVtYSxcbiAgZXhlY3V0ZUxha2Vib3hDb21tYW5kT3BlcmF0aW9uU2NoZW1hLFxuICBnZXRMYWtlYm94T3BlcmF0aW9uU2NoZW1hLFxuICBnZXRMYWtlYm94U2VydmljZUxvZ3NPcGVyYXRpb25TY2hlbWEsXG4gIExBS0VCT1hfUExVR0lOX05BTUUsXG4gIExBS0VCT1hfUk9VVEVTLFxuICBsYWtlYm94Q29tbWFuZFJlcXVlc3RTY2hlbWEsXG4gIGxha2Vib3hTZXJ2aWNlQWN0aW9uU2NoZW1hLFxuICBsYWtlYm94U2VydmljZUxvZ3NSZXF1ZXN0U2NoZW1hLFxuICBsaXN0TGFrZWJveFNlcnZpY2VzT3BlcmF0aW9uU2NoZW1hLFxuICByZW1vdmVMYWtlYm94U2VydmljZU9wZXJhdGlvblNjaGVtYSxcbiAgc3RhcnRMYWtlYm94U2VydmljZU9wZXJhdGlvblNjaGVtYSxcbiAgc3RvcExha2Vib3hTZXJ2aWNlT3BlcmF0aW9uU2NoZW1hLFxuICB0eXBlIENyZWF0ZUxha2Vib3hTZXJ2aWNlUmVxdWVzdCxcbiAgdHlwZSBMYWtlYm94Q2xpZW50Q29uZmlnSW5wdXQsXG4gIHR5cGUgTGFrZWJveENvbW1hbmRSZXF1ZXN0LFxuICB0eXBlIExha2Vib3hTZXJ2aWNlLFxuICB0eXBlIExha2Vib3hTZXJ2aWNlTG9nc1JlcXVlc3QsXG59IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1sYWtlYm94XCI7XG5pbXBvcnQgdHlwZSB7IEFwcGxpY2F0aW9uLCBSZXF1ZXN0LCBSZXNwb25zZSB9IGZyb20gXCJleHByZXNzXCI7XG5pbXBvcnQgdHlwZSB7IEpTT05TY2hlbWE3IH0gZnJvbSBcImpzb24tc2NoZW1hXCI7XG5pbXBvcnQgeyB6IH0gZnJvbSBcInpvZFwiO1xuaW1wb3J0IHsgTGFrZWJveFJlc291cmNlUmVnaXN0cnkgfSBmcm9tIFwiLi9fcmVzb3VyY2UtcmVnaXN0cnkudHNcIjtcbmltcG9ydCB7IExha2Vib3hTZXJ2aWNlU25hcHNob3RzIH0gZnJvbSBcIi4vX3NlcnZpY2Utc25hcHNob3RzLnRzXCI7XG5pbXBvcnQge1xuICBMYWtlYm94UGx1Z2luQ29uZmlnU2NoZW1hLFxuICByZXNvbHZlTGFrZWJveFBsdWdpbkNvbmZpZyxcbiAgdHlwZSBMYWtlYm94UGx1Z2luQ29uZmlnLFxufSBmcm9tIFwiLi9jb25maWcudHNcIjtcbmltcG9ydCB7IExha2Vib3hSdW50aW1lLCB0eXBlIExha2Vib3hMZWdhY3lQb29sIH0gZnJvbSBcIi4vcnVudGltZS50c1wiO1xuaW1wb3J0IHsgd2l0aFNlcnZpY2VPcmlnaW4gfSBmcm9tIFwiLi9zZXJ2aWNlcy50c1wiO1xuXG5pbnRlcmZhY2UgU2VydmVyRXh0ZW5zaW9uIHtcbiAgYWRkRXh0ZW5zaW9uKGZuOiAoYXBwbGljYXRpb246IEFwcGxpY2F0aW9uKSA9PiB2b2lkKTogdm9pZDtcbiAgZ2V0U2VydmVyKCk6IEh0dHBTZXJ2ZXI7XG59XG5cbmludGVyZmFjZSBVcGdyYWRlSWRlbnRpdHlHYXRlIHtcbiAgaXNQcm90ZWN0ZWRIb3N0KGhlYWRlcnM6IEhlYWRlcnMpOiBib29sZWFuO1xuICBzZXNzaW9uKGhlYWRlcnM6IEhlYWRlcnMpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD47XG59XG5cbmNvbnN0IENPTkZJR19TQ0hFTUEgPSB6LnRvSlNPTlNjaGVtYShMYWtlYm94UGx1Z2luQ29uZmlnU2NoZW1hKSBhcyBKU09OU2NoZW1hNztcblxuLyoqXG4gKiBBcHBLaXQgcGx1Z2luIGZvciB0aGUgc2luZ2xlIGFwcCBMYWtlYm94LlxuICpcbiAqIFJlZ2lzdGVycyB1c2VyLXNjb3BlZCBSRVNUIHJvdXRlcywgYWdlbnQgdG9vbHMsIHRoZSBkZXRlcm1pbmlzdGljIHNlcnZpY2VcbiAqIHByb3h5LCBhbmQgV2ViU29ja2V0IHVwZ3JhZGUgaGFuZGxpbmcuIEV2ZXJ5IExha2Vib3ggbGlmZWN5Y2xlIGNhbGwgdXNlcyB0aGVcbiAqIGFwcCBzZXJ2aWNlIHByaW5jaXBhbDsgdGhlIGF1dGhlbnRpY2F0ZWQgcmVxdWVzdCBpZGVudGl0eSBvbmx5IHNlbGVjdHMgdGhlXG4gKiB1c2VyJ3MgTGFrZWJveCBhY2NvdW50IGFuZCBhdXRob3JpemVzIHRoYXQgdXNlcidzIHJvdXRlcy5cbiAqL1xuZXhwb3J0IGNsYXNzIEFwcEtpdExha2Vib3hQbHVnaW4gZXh0ZW5kcyBUb29sUmVnaXN0cnlQbHVnaW48TGFrZWJveFBsdWdpbkNvbmZpZz4ge1xuICBzdGF0aWMgbWFuaWZlc3QgPSB7XG4gICAgbmFtZTogTEFLRUJPWF9QTFVHSU5fTkFNRSxcbiAgICBkaXNwbGF5TmFtZTogXCJMYWtlYm94XCIsXG4gICAgZGVzY3JpcHRpb246XG4gICAgICBcIlJ1bnMgcGVyLXVzZXIgc2VydmljZXMsIHRlcm1pbmFscywgZGVza3RvcHMsIGFuZCBjb21tYW5kcyBpbiBvbmUgbGF6aWx5IGNyZWF0ZWQgRGF0YWJyaWNrcyBMYWtlYm94LlwiLFxuICAgIHN0YWJpbGl0eTogXCJiZXRhXCIsXG4gICAgcmVzb3VyY2VzOiB7IHJlcXVpcmVkOiBbXSwgb3B0aW9uYWw6IFtdIH0sXG4gICAgY29uZmlnOiB7IHNjaGVtYTogQ09ORklHX1NDSEVNQSB9LFxuICB9IHNhdGlzZmllcyBQbHVnaW5NYW5pZmVzdDx0eXBlb2YgTEFLRUJPWF9QTFVHSU5fTkFNRT47XG5cbiAgcmVhZG9ubHkgcnVudGltZTogTGFrZWJveFJ1bnRpbWU7XG4gIHByaXZhdGUgbW91bnRlZCA9IGZhbHNlO1xuICBwcml2YXRlIGh0dHBTZXJ2ZXI/OiBIdHRwU2VydmVyO1xuICBwcml2YXRlIHVwZ3JhZGVBdHRhY2hUaW1lcj86IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+O1xuICBwcml2YXRlIHVwZ3JhZGVJZGVudGl0eUdhdGU/OiBVcGdyYWRlSWRlbnRpdHlHYXRlO1xuICBwcml2YXRlIHJlYWRvbmx5IHVwZ3JhZGVIYW5kbGVyID0gKHJlcXVlc3Q6IEluY29taW5nTWVzc2FnZSwgc29ja2V0OiBTb2NrZXQsIGhlYWQ6IEJ1ZmZlcikgPT4ge1xuICAgIHZvaWQgdGhpcy5oYW5kbGVVcGdyYWRlKHJlcXVlc3QsIHNvY2tldCwgaGVhZCk7XG4gIH07XG5cbiAgLyoqIENyZWF0ZXMgYSBwbHVnaW4gd2l0aCBhIHN1cHBsaWVkIHNoYXJlZCBydW50aW1lIG9yIG9uZSBmcm9tIHJlc29sdmVkIGNvbmZpZy4gKi9cbiAgY29uc3RydWN0b3IoY29uZmlnOiBMYWtlYm94UGx1Z2luQ29uZmlnID0ge30pIHtcbiAgICBzdXBlcihjb25maWcpO1xuICAgIHRoaXMucnVudGltZSA9IGNvbmZpZy5ydW50aW1lID8/IG5ldyBMYWtlYm94UnVudGltZShyZXNvbHZlTGFrZWJveFBsdWdpbkNvbmZpZyhjb25maWcpKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXQgdG9vbFJlZ2lzdHJ5KCk6IFRvb2xSZWdpc3RyeSB7XG4gICAgcmV0dXJuIHRoaXMuY3JlYXRlVG9vbFJlZ2lzdHJ5KCk7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBzZXR1cCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmNvbnRleHQ/Lm9uTGlmZWN5Y2xlKFwic2V0dXA6Y29tcGxldGVcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcG9vbCA9IGxha2ViYXNlUmVzb2x2ZXIuY2FwdHVyZVNlcnZpY2VQcmluY2lwYWxQb29sKFxuICAgICAgICBwbHVnaW5SZWdpc3RyeS5yZXF1aXJlKHRoaXMuY29udGV4dCwgbGFrZWJhc2UsIFwiYXBwa2l0LWxha2Vib3hcIikuZXhwb3J0cygpLnBvb2wsXG4gICAgICApO1xuICAgICAgdGhpcy5ydW50aW1lLmluaXRpYWxpemUoXG4gICAgICAgIGNyZWF0ZVdvcmtzcGFjZUNsaWVudCgpLmNvbmZpZyxcbiAgICAgICAgKGhlYWRlcnMpID0+IHRoaXMucmVxdWVzdElkZW50aXR5KGhlYWRlcnMpLFxuICAgICAgICBuZXcgTGFrZWJveFNlcnZpY2VTbmFwc2hvdHMoKSxcbiAgICAgICAgbmV3IExha2Vib3hSZXNvdXJjZVJlZ2lzdHJ5KHRoaXMucnVudGltZS5jb25maWcuYXBwbGljYXRpb24sIHBvb2wpLFxuICAgICAgKTtcbiAgICAgIHZvaWQgdGhpcy5ydW50aW1lLmNsZWFudXBMZWdhY3kocG9vbCBhcyBMYWtlYm94TGVnYWN5UG9vbCk7XG4gICAgICBjb25zdCBzZXJ2ZXIgPSB0aGlzLmNvbnRleHQ/LmdldFBsdWdpbnMoKS5nZXQoXCJzZXJ2ZXJcIikgYXMgU2VydmVyRXh0ZW5zaW9uIHwgdW5kZWZpbmVkO1xuICAgICAgaWYgKCFzZXJ2ZXIgfHwgdGhpcy5tb3VudGVkKSByZXR1cm47XG4gICAgICB0aGlzLnVwZ3JhZGVJZGVudGl0eUdhdGUgPSByZXNvbHZlVXBncmFkZUlkZW50aXR5R2F0ZShcbiAgICAgICAgdGhpcy5jb250ZXh0Py5nZXRQbHVnaW5zKCkuZ2V0KFwiYXV0aEdhdGVcIiksXG4gICAgICApO1xuICAgICAgc2VydmVyLmFkZEV4dGVuc2lvbigoYXBwbGljYXRpb24pID0+IGFwcGxpY2F0aW9uLnVzZSh0aGlzLnJ1bnRpbWUucm91dGVzLm1pZGRsZXdhcmUoKSkpO1xuICAgICAgdGhpcy5tb3VudGVkID0gdHJ1ZTtcbiAgICAgIHRoaXMuYXR0YWNoVXBncmFkZUhhbmRsZXIoc2VydmVyKTtcbiAgICB9KTtcbiAgfVxuXG4gIG92ZXJyaWRlIGluamVjdFJvdXRlcyhyb3V0ZXI6IElBcHBSb3V0ZXIpOiB2b2lkIHtcbiAgICBjb25zdCBqc29uID0gKFxuICAgICAgbmFtZTogc3RyaW5nLFxuICAgICAgbWV0aG9kOiBcImdldFwiIHwgXCJwb3N0XCIgfCBcImRlbGV0ZVwiLFxuICAgICAgcGF0aDogc3RyaW5nLFxuICAgICAgaGFuZGxlcjogKGlkZW50aXR5OiBzdHJpbmcsIHJlcTogUmVxdWVzdCkgPT4gUHJvbWlzZTx1bmtub3duPixcbiAgICApID0+XG4gICAgICB0aGlzLnJvdXRlKHJvdXRlciwge1xuICAgICAgICBuYW1lLFxuICAgICAgICBtZXRob2QsXG4gICAgICAgIHBhdGgsXG4gICAgICAgIGhhbmRsZXI6IGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICAgICAgICAgIHJlcy5qc29uKGF3YWl0IGhhbmRsZXIodGhpcy5yZXNvbHZlVXNlcklkKHJlcSksIHJlcSkpO1xuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAganNvbihcInN0YXR1c1wiLCBcImdldFwiLCBMQUtFQk9YX1JPVVRFUy5zdGF0dXMsIChpZGVudGl0eSkgPT4gdGhpcy5ydW50aW1lLnN1bW1hcnkoaWRlbnRpdHkpKTtcbiAgICBqc29uKFwic3RhcnRcIiwgXCJwb3N0XCIsIExBS0VCT1hfUk9VVEVTLnN0YXJ0LCBhc3luYyAoaWRlbnRpdHkpID0+IHtcbiAgICAgIGF3YWl0IHRoaXMucnVudGltZS5zdGFydCgpO1xuICAgICAgcmV0dXJuIHRoaXMucnVudGltZS5zdW1tYXJ5KGlkZW50aXR5KTtcbiAgICB9KTtcbiAgICBqc29uKFwic3RvcFwiLCBcInBvc3RcIiwgTEFLRUJPWF9ST1VURVMuc3RvcCwgYXN5bmMgKGlkZW50aXR5KSA9PiB7XG4gICAgICBhd2FpdCB0aGlzLnJ1bnRpbWUuc3RvcCgpO1xuICAgICAgcmV0dXJuIHRoaXMucnVudGltZS5zdW1tYXJ5KGlkZW50aXR5KTtcbiAgICB9KTtcbiAgICBqc29uKFxuICAgICAgXCJleGVjdXRlQ29tbWFuZFwiLFxuICAgICAgXCJwb3N0XCIsXG4gICAgICBMQUtFQk9YX1JPVVRFUy5jb21tYW5kcyxcbiAgICAgIChpZGVudGl0eSwgcmVxKSA9PlxuICAgICAgICB0aGlzLnJ1bnRpbWUuZXhlY3V0ZShpZGVudGl0eSwgbGFrZWJveENvbW1hbmRSZXF1ZXN0U2NoZW1hLnBhcnNlKHJlcS5ib2R5ID8/IHt9KSkucmVzdWx0LFxuICAgICk7XG4gICAganNvbihcInNlcnZpY2VzXCIsIFwiZ2V0XCIsIExBS0VCT1hfUk9VVEVTLnNlcnZpY2VzLCBhc3luYyAoaWRlbnRpdHkpID0+ICh7XG4gICAgICBzZXJ2aWNlczogYXdhaXQgdGhpcy5ydW50aW1lLmxpc3RTZXJ2aWNlcyhpZGVudGl0eSksXG4gICAgfSkpO1xuICAgIGpzb24oXCJjcmVhdGVTZXJ2aWNlXCIsIFwicG9zdFwiLCBMQUtFQk9YX1JPVVRFUy5zZXJ2aWNlcywgYXN5bmMgKGlkZW50aXR5LCByZXEpID0+ICh7XG4gICAgICBzZXJ2aWNlOiBhd2FpdCB0aGlzLnJ1bnRpbWUuY3JlYXRlU2VydmljZShpZGVudGl0eSwgcmVxLmJvZHkgPz8ge30pLFxuICAgIH0pKTtcbiAgICBqc29uKFwic3RhcnRTZXJ2aWNlXCIsIFwicG9zdFwiLCBMQUtFQk9YX1JPVVRFUy5zZXJ2aWNlU3RhcnQsIGFzeW5jIChpZGVudGl0eSwgcmVxKSA9PiAoe1xuICAgICAgc2VydmljZTogYXdhaXQgdGhpcy5ydW50aW1lLnN0YXJ0U2VydmljZShpZGVudGl0eSwgc2VydmljZU5hbWUocmVxKSksXG4gICAgfSkpO1xuICAgIGpzb24oXCJzdG9wU2VydmljZVwiLCBcInBvc3RcIiwgTEFLRUJPWF9ST1VURVMuc2VydmljZVN0b3AsIGFzeW5jIChpZGVudGl0eSwgcmVxKSA9PiAoe1xuICAgICAgc2VydmljZTogYXdhaXQgdGhpcy5ydW50aW1lLnN0b3BTZXJ2aWNlKGlkZW50aXR5LCBzZXJ2aWNlTmFtZShyZXEpKSxcbiAgICB9KSk7XG4gICAganNvbihcInJlbW92ZVNlcnZpY2VcIiwgXCJkZWxldGVcIiwgTEFLRUJPWF9ST1VURVMuc2VydmljZSwgYXN5bmMgKGlkZW50aXR5LCByZXEpID0+ICh7XG4gICAgICByZW1vdmVkOiBhd2FpdCB0aGlzLnJ1bnRpbWUucmVtb3ZlU2VydmljZShpZGVudGl0eSwgc2VydmljZU5hbWUocmVxKSksXG4gICAgfSkpO1xuICAgIGpzb24oXCJzZXJ2aWNlTG9nc1wiLCBcImdldFwiLCBMQUtFQk9YX1JPVVRFUy5zZXJ2aWNlTG9ncywgKGlkZW50aXR5LCByZXEpID0+XG4gICAgICB0aGlzLnJ1bnRpbWUuc2VydmljZUxvZ3MoXG4gICAgICAgIGlkZW50aXR5LFxuICAgICAgICBsYWtlYm94U2VydmljZUxvZ3NSZXF1ZXN0U2NoZW1hLnBhcnNlKHtcbiAgICAgICAgICBuYW1lOiByZXEucGFyYW1zLm5hbWUsXG4gICAgICAgICAgbWF4TGluZXM6IHJlcS5xdWVyeS5tYXhMaW5lcyxcbiAgICAgICAgICBtYXhDaGFyczogcmVxLnF1ZXJ5Lm1heENoYXJzLFxuICAgICAgICB9KSxcbiAgICAgICksXG4gICAgKTtcbiAgICBqc29uKFwibWV0cmljc1wiLCBcImdldFwiLCBMQUtFQk9YX1JPVVRFUy5tZXRyaWNzLCAoKSA9PiB0aGlzLnJ1bnRpbWUubWV0cmljc1Jlc3BvbnNlKCkpO1xuICAgIHRoaXMucm91dGUocm91dGVyLCB7XG4gICAgICBuYW1lOiBcIm1ldHJpY3NTdHJlYW1cIixcbiAgICAgIG1ldGhvZDogXCJnZXRcIixcbiAgICAgIHBhdGg6IExBS0VCT1hfUk9VVEVTLm1ldHJpY3NTdHJlYW0sXG4gICAgICBoYW5kbGVyOiBhc3luYyAocmVxLCByZXMpID0+IHRoaXMuc3RyZWFtTWV0cmljcyhyZXEsIHJlcyksXG4gICAgfSk7XG4gIH1cblxuICAvKiogUmV0dXJucyBicm93c2VyLXNhZmUgcm91dGUgZGVmYXVsdHMgcHVibGlzaGVkIHRocm91Z2ggQXBwS2l0IGNsaWVudCBjb25maWcuICovXG4gIGNsaWVudENvbmZpZygpOiBMYWtlYm94Q2xpZW50Q29uZmlnSW5wdXQge1xuICAgIHJldHVybiB7IHJvdXRlUHJlZml4OiB0aGlzLnJ1bnRpbWUuY29uZmlnLnJvdXRlUHJlZml4IH07XG4gIH1cblxuICAvKiogUmV0dXJucyBzZWxlY3RlZCBBcHBLaXQgdG9vbGtpdCBlbnRyaWVzIGJhY2tlZCBieSB0aGlzIHBsdWdpbidzIGFnZW50IHRvb2xzLiAqL1xuICB0b29sa2l0KG9wdGlvbnM/OiBUb29sa2l0T3B0aW9ucyk6IFJlY29yZDxzdHJpbmcsIFRvb2xraXRFbnRyeT4ge1xuICAgIHJldHVybiB0b29sa2l0RW50cmllcy5lbnRyaWVzKExBS0VCT1hfUExVR0lOX05BTUUsIHRoaXMuZ2V0QWdlbnRUb29scygpLCB7XG4gICAgICAuLi5vcHRpb25zLFxuICAgICAgcHJlZml4OiBvcHRpb25zPy5wcmVmaXggPz8gXCJcIixcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBFeGVjdXRlcyBvbmUgcmVnaXN0ZXJlZCBhZ2VudCB0b29sIGZvciB0aGUgY3VycmVudCBleGVjdXRpb24gaWRlbnRpdHkuICovXG4gIG92ZXJyaWRlIGV4ZWN1dGVBZ2VudFRvb2woXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIGFyZ3M6IHVua25vd24sXG4gICAgc2lnbmFsPzogQWJvcnRTaWduYWwsXG4gICAgY29udGV4dD86IEFnZW50VG9vbEV4ZWN1dGlvbkNvbnRleHQsXG4gICk6IFByb21pc2U8dW5rbm93bj4ge1xuICAgIHJldHVybiBleGVjdXRlRnJvbVJlZ2lzdHJ5KFxuICAgICAgdGhpcy5jcmVhdGVUb29sUmVnaXN0cnkoY29udGV4dD8ucmVzb3VyY2VJZCwgY29udGV4dD8ub3JpZ2luKSxcbiAgICAgIG5hbWUsXG4gICAgICBhcmdzLFxuICAgICAgc2lnbmFsLFxuICAgICk7XG4gIH1cblxuICAvKiogUmV0dXJucyB0aGUgdHlwZWQgc2libGluZy1wbHVnaW4gQVBJLiAqL1xuICBleHBvcnRzKCkge1xuICAgIHJldHVybiB7XG4gICAgICBzdW1tYXJ5OiAoaWRlbnRpdHk6IHN0cmluZykgPT4gdGhpcy5ydW50aW1lLnN1bW1hcnkoaWRlbnRpdHkpLFxuICAgICAgc3RhcnQ6ICgpID0+IHRoaXMucnVudGltZS5zdGFydCgpLFxuICAgICAgc3RvcDogKCkgPT4gdGhpcy5ydW50aW1lLnN0b3AoKSxcbiAgICAgIGRlbGV0ZTogKCkgPT4gdGhpcy5ydW50aW1lLmRlbGV0ZSgpLFxuICAgICAgZXhlY3V0ZUNvbW1hbmQ6IChpZGVudGl0eTogc3RyaW5nLCBpbnB1dDogTGFrZWJveENvbW1hbmRSZXF1ZXN0KSA9PlxuICAgICAgICB0aGlzLnJ1bnRpbWUuZXhlY3V0ZShpZGVudGl0eSwgaW5wdXQpLnJlc3VsdCxcbiAgICAgIGxpc3RTZXJ2aWNlczogKGlkZW50aXR5OiBzdHJpbmcpID0+IHRoaXMucnVudGltZS5saXN0U2VydmljZXMoaWRlbnRpdHkpLFxuICAgICAgY3JlYXRlU2VydmljZTogKGlkZW50aXR5OiBzdHJpbmcsIGlucHV0OiBDcmVhdGVMYWtlYm94U2VydmljZVJlcXVlc3QpID0+XG4gICAgICAgIHRoaXMucnVudGltZS5jcmVhdGVTZXJ2aWNlKGlkZW50aXR5LCBpbnB1dCksXG4gICAgICBzdGFydFNlcnZpY2U6IChpZGVudGl0eTogc3RyaW5nLCBuYW1lOiBzdHJpbmcpID0+IHRoaXMucnVudGltZS5zdGFydFNlcnZpY2UoaWRlbnRpdHksIG5hbWUpLFxuICAgICAgc3RvcFNlcnZpY2U6IChpZGVudGl0eTogc3RyaW5nLCBuYW1lOiBzdHJpbmcpID0+IHRoaXMucnVudGltZS5zdG9wU2VydmljZShpZGVudGl0eSwgbmFtZSksXG4gICAgICByZW1vdmVTZXJ2aWNlOiAoaWRlbnRpdHk6IHN0cmluZywgbmFtZTogc3RyaW5nKSA9PiB0aGlzLnJ1bnRpbWUucmVtb3ZlU2VydmljZShpZGVudGl0eSwgbmFtZSksXG4gICAgICBzZXJ2aWNlTG9nczogKGlkZW50aXR5OiBzdHJpbmcsIGlucHV0OiBMYWtlYm94U2VydmljZUxvZ3NSZXF1ZXN0KSA9PlxuICAgICAgICB0aGlzLnJ1bnRpbWUuc2VydmljZUxvZ3MoaWRlbnRpdHksIGlucHV0KSxcbiAgICAgIG9wZXJhdGlvbnM6IChpZGVudGl0eT86IHN0cmluZykgPT4gdGhpcy5vcGVyYXRpb25zKGlkZW50aXR5KSxcbiAgICAgIHRvb2xraXQ6IChvcHRpb25zPzogVG9vbGtpdE9wdGlvbnMpID0+IHRoaXMudG9vbGtpdChvcHRpb25zKSxcbiAgICB9O1xuICB9XG5cbiAgLyoqIENhbmNlbHMgaW4tZmxpZ2h0IHdvcmsgYmVmb3JlIHNodXRkb3duIHRlYXJzIGRvd24gcmVzb3VyY2VzLiAqL1xuICBvdmVycmlkZSBhYm9ydEFjdGl2ZU9wZXJhdGlvbnMoKTogdm9pZCB7XG4gICAgdGhpcy5ydW50aW1lLmFib3J0QWN0aXZlT3BlcmF0aW9ucygpO1xuICB9XG5cbiAgLyoqIERldGFjaGVzIFdlYlNvY2tldCBoYW5kbGluZyBhbmQgY2xvc2VzIHRoZSBzaGFyZWQgcnVudGltZS4gKi9cbiAgYXN5bmMgc2h1dGRvd24oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMudXBncmFkZUF0dGFjaFRpbWVyKSBjbGVhclRpbWVvdXQodGhpcy51cGdyYWRlQXR0YWNoVGltZXIpO1xuICAgIHRoaXMudXBncmFkZUF0dGFjaFRpbWVyID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuaHR0cFNlcnZlcj8ub2ZmKFwidXBncmFkZVwiLCB0aGlzLnVwZ3JhZGVIYW5kbGVyKTtcbiAgICB0aGlzLmh0dHBTZXJ2ZXIgPSB1bmRlZmluZWQ7XG4gICAgYXdhaXQgdGhpcy5ydW50aW1lLmNsb3NlKCk7XG4gIH1cblxuICAvKiogUmV0dXJucyB0aGUgWm9kLW93bmVkIG9wZXJhdGlvbiBjb250cmFjdHMgdXNlZCBieSBhZ2VudCB0b29scy4gKi9cbiAgb3BlcmF0aW9ucyhpZGVudGl0eT86IHN0cmluZywgb3JpZ2luPzogc3RyaW5nKSB7XG4gICAgY29uc3QgdXNlciA9ICgpID0+IGlkZW50aXR5ID8/IHRoaXMuZXhlY3V0aW9uSWRlbnRpdHkoKTtcbiAgICBjb25zdCBwcmVzZW50U2VydmljZSA9ICh2YWx1ZTogTGFrZWJveFNlcnZpY2UpID0+IG9taXRMb2cod2l0aFNlcnZpY2VPcmlnaW4odmFsdWUsIG9yaWdpbikpO1xuICAgIHJldHVybiB0b29sT3BlcmF0aW9ucy5kZWZpbmVPcGVyYXRpb25zKHtcbiAgICAgIGdldF9sYWtlYm94OiB7XG4gICAgICAgIHNjaGVtYTogZ2V0TGFrZWJveE9wZXJhdGlvblNjaGVtYSxcbiAgICAgICAgZXhlY3V0ZTogYXN5bmMgKF9pbnB1dCwgc2lnbmFsKSA9PiB7XG4gICAgICAgICAgY29uc3Qgc3VtbWFyeSA9IGF3YWl0IHRoaXMucnVudGltZS5zdW1tYXJ5KHVzZXIoKSwgc2lnbmFsKTtcbiAgICAgICAgICByZXR1cm4geyAuLi5zdW1tYXJ5LCBzZXJ2aWNlczogc3VtbWFyeS5zZXJ2aWNlcy5tYXAocHJlc2VudFNlcnZpY2UpIH07XG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgZXhlY3V0ZV9sYWtlYm94X2NvbW1hbmQ6IHtcbiAgICAgICAgc2NoZW1hOiBleGVjdXRlTGFrZWJveENvbW1hbmRPcGVyYXRpb25TY2hlbWEsXG4gICAgICAgIGV4ZWN1dGU6IChpbnB1dCwgc2lnbmFsKSA9PiB0aGlzLnJ1bnRpbWUuZXhlY3V0ZSh1c2VyKCksIGlucHV0LCBzaWduYWwpLnJlc3VsdCxcbiAgICAgIH0sXG4gICAgICBsaXN0X2xha2Vib3hfc2VydmljZXM6IHtcbiAgICAgICAgc2NoZW1hOiBsaXN0TGFrZWJveFNlcnZpY2VzT3BlcmF0aW9uU2NoZW1hLFxuICAgICAgICBleGVjdXRlOiBhc3luYyAoX2lucHV0LCBzaWduYWwpID0+ICh7XG4gICAgICAgICAgc2VydmljZXM6IChhd2FpdCB0aGlzLnJ1bnRpbWUubGlzdFNlcnZpY2VzKHVzZXIoKSwgc2lnbmFsKSkubWFwKHByZXNlbnRTZXJ2aWNlKSxcbiAgICAgICAgfSksXG4gICAgICB9LFxuICAgICAgY3JlYXRlX2xha2Vib3hfc2VydmljZToge1xuICAgICAgICBzY2hlbWE6IGNyZWF0ZUxha2Vib3hTZXJ2aWNlT3BlcmF0aW9uU2NoZW1hLFxuICAgICAgICBleGVjdXRlOiBhc3luYyAoaW5wdXQsIHNpZ25hbCkgPT4gKHtcbiAgICAgICAgICBzZXJ2aWNlOiBwcmVzZW50U2VydmljZShhd2FpdCB0aGlzLnJ1bnRpbWUuY3JlYXRlU2VydmljZSh1c2VyKCksIGlucHV0LCBzaWduYWwpKSxcbiAgICAgICAgfSksXG4gICAgICB9LFxuICAgICAgc3RhcnRfbGFrZWJveF9zZXJ2aWNlOiB7XG4gICAgICAgIHNjaGVtYTogc3RhcnRMYWtlYm94U2VydmljZU9wZXJhdGlvblNjaGVtYSxcbiAgICAgICAgZXhlY3V0ZTogYXN5bmMgKGlucHV0LCBzaWduYWwpID0+ICh7XG4gICAgICAgICAgc2VydmljZTogcHJlc2VudFNlcnZpY2UoYXdhaXQgdGhpcy5ydW50aW1lLnN0YXJ0U2VydmljZSh1c2VyKCksIGlucHV0Lm5hbWUsIHNpZ25hbCkpLFxuICAgICAgICB9KSxcbiAgICAgIH0sXG4gICAgICBzdG9wX2xha2Vib3hfc2VydmljZToge1xuICAgICAgICBzY2hlbWE6IHN0b3BMYWtlYm94U2VydmljZU9wZXJhdGlvblNjaGVtYSxcbiAgICAgICAgZXhlY3V0ZTogYXN5bmMgKGlucHV0LCBzaWduYWwpID0+ICh7XG4gICAgICAgICAgc2VydmljZTogcHJlc2VudFNlcnZpY2UoYXdhaXQgdGhpcy5ydW50aW1lLnN0b3BTZXJ2aWNlKHVzZXIoKSwgaW5wdXQubmFtZSwgc2lnbmFsKSksXG4gICAgICAgIH0pLFxuICAgICAgfSxcbiAgICAgIHJlbW92ZV9sYWtlYm94X3NlcnZpY2U6IHtcbiAgICAgICAgc2NoZW1hOiByZW1vdmVMYWtlYm94U2VydmljZU9wZXJhdGlvblNjaGVtYSxcbiAgICAgICAgZXhlY3V0ZTogYXN5bmMgKGlucHV0LCBzaWduYWwpID0+ICh7XG4gICAgICAgICAgcmVtb3ZlZDogYXdhaXQgdGhpcy5ydW50aW1lLnJlbW92ZVNlcnZpY2UodXNlcigpLCBpbnB1dC5uYW1lLCBzaWduYWwpLFxuICAgICAgICB9KSxcbiAgICAgIH0sXG4gICAgICBnZXRfbGFrZWJveF9zZXJ2aWNlX2xvZ3M6IHtcbiAgICAgICAgc2NoZW1hOiBnZXRMYWtlYm94U2VydmljZUxvZ3NPcGVyYXRpb25TY2hlbWEsXG4gICAgICAgIGV4ZWN1dGU6IChpbnB1dCwgc2lnbmFsKSA9PiB0aGlzLnJ1bnRpbWUuc2VydmljZUxvZ3ModXNlcigpLCBpbnB1dCwgc2lnbmFsKSxcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZVRvb2xSZWdpc3RyeShpZGVudGl0eT86IHN0cmluZywgb3JpZ2luPzogc3RyaW5nKTogVG9vbFJlZ2lzdHJ5IHtcbiAgICByZXR1cm4gdG9vbE9wZXJhdGlvbnMudG9vbFJlZ2lzdHJ5RnJvbU9wZXJhdGlvbnModGhpcy5vcGVyYXRpb25zKGlkZW50aXR5LCBvcmlnaW4pKTtcbiAgfVxuXG4gIHByaXZhdGUgZXhlY3V0aW9uSWRlbnRpdHkoKTogc3RyaW5nIHtcbiAgICBjb25zdCBjb250ZXh0ID0gYXBwa2l0LnRyeUdldEV4ZWN1dGlvbkNvbnRleHQoKTtcbiAgICBpZiAoIWNvbnRleHQpIHRocm93IG5ldyBFcnJvcihcIkxha2Vib3ggdG9vbHMgcmVxdWlyZSBhbiBBcHBLaXQgZXhlY3V0aW9uIGNvbnRleHRcIik7XG4gICAgcmV0dXJuIFwidXNlcklkXCIgaW4gY29udGV4dCA/IGNvbnRleHQudXNlcklkIDogY29udGV4dC5zZXJ2aWNlVXNlcklkO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmVzIHJvdXRlIGlkZW50aXR5IHdpdGggdGhlIHNhbWUgcnVsZXMgYXMgUkVTVDogdGhlIGZvcndhcmRlZCB1c2VyLFxuICAgKiBvciBBcHBLaXQncyBkZXZlbG9wbWVudCB1c2VyIGZvciBkaXJlY3QgbG9vcGJhY2sgbmF2aWdhdGlvbiBvdXRzaWRlXG4gICAqIHByb2R1Y3Rpb24uIEV2ZXJ5dGhpbmcgZWxzZSBpcyBhbm9ueW1vdXMgYW5kIGZhaWxzIGNsb3NlZC5cbiAgICovXG4gIHByaXZhdGUgcmVxdWVzdElkZW50aXR5KGhlYWRlcnM6IEluY29taW5nSHR0cEhlYWRlcnMpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IGZvcndhcmRlZCA9IGhlYWRlclZhbHVlKGhlYWRlcnNbVVNFUl9JRF9IRUFERVJdKT8udHJpbSgpO1xuICAgIGlmIChmb3J3YXJkZWQpIHJldHVybiBmb3J3YXJkZWQ7XG4gICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSBcImRldmVsb3BtZW50XCIgfHwgIWlzTG9vcGJhY2tIb3N0KGhlYWRlclZhbHVlKGhlYWRlcnMuaG9zdCkpKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHRoaXMucmVzb2x2ZVVzZXJJZCh7XG4gICAgICAgIGhlYWRlcjogKG5hbWU6IHN0cmluZykgPT4gaGVhZGVyVmFsdWUoaGVhZGVyc1tuYW1lLnRvTG93ZXJDYXNlKCldKSxcbiAgICAgIH0gYXMgdW5rbm93biBhcyBSZXF1ZXN0KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzdHJlYW1NZXRyaWNzKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGluaXRpYWwgPSBhd2FpdCB0aGlzLnJ1bnRpbWUubWV0cmljc1Jlc3BvbnNlKCk7XG4gICAgcmVzLnN0YXR1c0NvZGUgPSAyMDA7XG4gICAgcmVzLnNldEhlYWRlcihcImNvbnRlbnQtdHlwZVwiLCBcInRleHQvZXZlbnQtc3RyZWFtOyBjaGFyc2V0PXV0Zi04XCIpO1xuICAgIHJlcy5zZXRIZWFkZXIoXCJjYWNoZS1jb250cm9sXCIsIFwibm8tY2FjaGUsIG5vLXRyYW5zZm9ybVwiKTtcbiAgICByZXMuc2V0SGVhZGVyKFwiY29ubmVjdGlvblwiLCBcImtlZXAtYWxpdmVcIik7XG4gICAgcmVzLnNldEhlYWRlcihcIngtYWNjZWwtYnVmZmVyaW5nXCIsIFwibm9cIik7XG4gICAgcmVzLmZsdXNoSGVhZGVycz8uKCk7XG4gICAgcmVzLndyaXRlKGBkYXRhOiAke0pTT04uc3RyaW5naWZ5KGluaXRpYWwpfVxcblxcbmApO1xuICAgIGNvbnN0IHVuc3Vic2NyaWJlID0gdGhpcy5ydW50aW1lLnN1YnNjcmliZU1ldHJpY3MoKHNuYXBzaG90KSA9PiB7XG4gICAgICByZXMud3JpdGUoYGRhdGE6ICR7SlNPTi5zdHJpbmdpZnkoeyBzdGF0dXM6IFwicnVubmluZ1wiLCBzZXJpZXM6IFtzbmFwc2hvdF0gfSl9XFxuXFxuYCk7XG4gICAgfSk7XG4gICAgcmVxLm9uY2UoXCJjbG9zZVwiLCB1bnN1YnNjcmliZSk7XG4gIH1cblxuICBwcml2YXRlIGF0dGFjaFVwZ3JhZGVIYW5kbGVyKHNlcnZlcjogU2VydmVyRXh0ZW5zaW9uKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaHR0cFNlcnZlciB8fCB0aGlzLnVwZ3JhZGVBdHRhY2hUaW1lcikgcmV0dXJuO1xuICAgIHRyeSB7XG4gICAgICB0aGlzLmh0dHBTZXJ2ZXIgPSBzZXJ2ZXIuZ2V0U2VydmVyKCk7XG4gICAgICB0aGlzLmh0dHBTZXJ2ZXIub24oXCJ1cGdyYWRlXCIsIHRoaXMudXBncmFkZUhhbmRsZXIpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdGhpcy51cGdyYWRlQXR0YWNoVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgdGhpcy51cGdyYWRlQXR0YWNoVGltZXIgPSB1bmRlZmluZWQ7XG4gICAgICAgIHRoaXMuYXR0YWNoVXBncmFkZUhhbmRsZXIoc2VydmVyKTtcbiAgICAgIH0sIDEwKTtcbiAgICAgIHRoaXMudXBncmFkZUF0dGFjaFRpbWVyLnVucmVmPy4oKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGhhbmRsZVVwZ3JhZGUoXG4gICAgcmVxdWVzdDogSW5jb21pbmdNZXNzYWdlLFxuICAgIHNvY2tldDogU29ja2V0LFxuICAgIGhlYWQ6IEJ1ZmZlcixcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcGF0aCA9IG5ldyBVUkwocmVxdWVzdC51cmwgPz8gXCIvXCIsIFwiaHR0cDovL2xvY2FsaG9zdFwiKS5wYXRobmFtZTtcbiAgICBpZiAoIXRoaXMucnVudGltZS5yb3V0ZXMuY2FuSGFuZGxlVXBncmFkZShwYXRoKSkgcmV0dXJuO1xuICAgIGNvbnN0IGdhdGUgPSB0aGlzLnVwZ3JhZGVJZGVudGl0eUdhdGU7XG4gICAgaWYgKGdhdGUpIHtcbiAgICAgIGNvbnN0IGhlYWRlcnMgPSByZXF1ZXN0SGVhZGVycyhyZXF1ZXN0KTtcbiAgICAgIGlmIChnYXRlLmlzUHJvdGVjdGVkSG9zdChoZWFkZXJzKSkge1xuICAgICAgICBkZWxldGUgcmVxdWVzdC5oZWFkZXJzW1VTRVJfSURfSEVBREVSXTtcbiAgICAgICAgZGVsZXRlIHJlcXVlc3QuaGVhZGVyc1tVU0VSX0VNQUlMX0hFQURFUl07XG4gICAgICAgIGNvbnN0IHVzZXJJZCA9IGF3YWl0IGdhdGUuc2Vzc2lvbihoZWFkZXJzKTtcbiAgICAgICAgaWYgKCF1c2VySWQpIHtcbiAgICAgICAgICBzb2NrZXQuZGVzdHJveSgpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICByZXF1ZXN0LmhlYWRlcnNbVVNFUl9JRF9IRUFERVJdID0gdXNlcklkO1xuICAgICAgICByZXF1ZXN0LmhlYWRlcnNbVVNFUl9FTUFJTF9IRUFERVJdID0gdXNlcklkO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIShhd2FpdCB0aGlzLnJ1bnRpbWUucm91dGVzLmhhbmRsZVVwZ3JhZGUocmVxdWVzdCwgc29ja2V0LCBoZWFkKSkpIHNvY2tldC5kZXN0cm95KCk7XG4gIH1cbn1cblxuZnVuY3Rpb24gc2VydmljZU5hbWUocmVxOiBSZXF1ZXN0KTogc3RyaW5nIHtcbiAgcmV0dXJuIGxha2Vib3hTZXJ2aWNlQWN0aW9uU2NoZW1hLnBhcnNlKHsgbmFtZTogcmVxLnBhcmFtcy5uYW1lIH0pLm5hbWU7XG59XG5cbmZ1bmN0aW9uIG9taXRMb2c8VCBleHRlbmRzIHsgbG9nPzogc3RyaW5nIH0+KHsgbG9nOiBfbG9nLCAuLi52YWx1ZSB9OiBUKTogT21pdDxULCBcImxvZ1wiPiB7XG4gIHJldHVybiB2YWx1ZTtcbn1cblxuZnVuY3Rpb24gaGVhZGVyVmFsdWUodmFsdWU6IHN0cmluZyB8IHN0cmluZ1tdIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIEFycmF5LmlzQXJyYXkodmFsdWUpID8gdmFsdWVbMF0gOiB2YWx1ZTtcbn1cblxuZnVuY3Rpb24gaXNMb29wYmFja0hvc3QoaG9zdDogc3RyaW5nIHwgdW5kZWZpbmVkKTogYm9vbGVhbiB7XG4gIGlmICghaG9zdCkgcmV0dXJuIGZhbHNlO1xuICB0cnkge1xuICAgIGNvbnN0IGhvc3RuYW1lID0gbmV3IFVSTChgaHR0cDovLyR7aG9zdH1gKS5ob3N0bmFtZS50b0xvd2VyQ2FzZSgpO1xuICAgIHJldHVybiBob3N0bmFtZSA9PT0gXCJsb2NhbGhvc3RcIiB8fCBob3N0bmFtZSA9PT0gXCIxMjcuMC4wLjFcIiB8fCBob3N0bmFtZSA9PT0gXCJbOjoxXVwiO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuZnVuY3Rpb24gcmVzb2x2ZVVwZ3JhZGVJZGVudGl0eUdhdGUocGx1Z2luOiB1bmtub3duKTogVXBncmFkZUlkZW50aXR5R2F0ZSB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGV4cG9ydHMgPSAocGx1Z2luIGFzIHsgZXhwb3J0cz86ICgpID0+IHVua25vd24gfSB8IHVuZGVmaW5lZCk/LmV4cG9ydHM/LigpO1xuICBpZiAoXG4gICAgdHlwZW9mIChleHBvcnRzIGFzIFVwZ3JhZGVJZGVudGl0eUdhdGUgfCB1bmRlZmluZWQpPy5pc1Byb3RlY3RlZEhvc3QgIT09IFwiZnVuY3Rpb25cIiB8fFxuICAgIHR5cGVvZiAoZXhwb3J0cyBhcyBVcGdyYWRlSWRlbnRpdHlHYXRlIHwgdW5kZWZpbmVkKT8uc2Vzc2lvbiAhPT0gXCJmdW5jdGlvblwiXG4gICkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgcmV0dXJuIGV4cG9ydHMgYXMgVXBncmFkZUlkZW50aXR5R2F0ZTtcbn1cblxuZnVuY3Rpb24gcmVxdWVzdEhlYWRlcnMocmVxdWVzdDogSW5jb21pbmdNZXNzYWdlKTogSGVhZGVycyB7XG4gIGNvbnN0IGhlYWRlcnMgPSBuZXcgSGVhZGVycygpO1xuICBmb3IgKGNvbnN0IFtuYW1lLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMocmVxdWVzdC5oZWFkZXJzKSkge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgZm9yIChjb25zdCBpdGVtIG9mIHZhbHVlKSBoZWFkZXJzLmFwcGVuZChuYW1lLCBpdGVtKTtcbiAgICB9IGVsc2UgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGhlYWRlcnMuc2V0KG5hbWUsIHZhbHVlKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGhlYWRlcnM7XG59XG5cbi8qKiBBcHBLaXQgcGx1Z2luIGZhY3RvcnkgZm9yIHtAbGluayBBcHBLaXRMYWtlYm94UGx1Z2lufS4gKi9cbmV4cG9ydCBjb25zdCBsYWtlYm94ID0gdG9QbHVnaW4oQXBwS2l0TGFrZWJveFBsdWdpbik7XG4iXX0=
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { IncomingHttpHeaders, IncomingMessage } from "node:http";
|
|
2
|
+
import { type Socket } from "node:net";
|
|
3
|
+
import type { SshSession } from "@dbx-tools/lakebox/session";
|
|
4
|
+
import type { LakeboxUser } from "@dbx-tools/shared-lakebox";
|
|
5
|
+
import type { NextFunction, Request, Response } from "express";
|
|
6
|
+
import type { LakeboxServiceRoute } from "./services.ts";
|
|
7
|
+
/** Result of resolving one user's service for a routed request. */
|
|
8
|
+
export type LakeboxRouteResolution = {
|
|
9
|
+
kind: "ready";
|
|
10
|
+
session: SshSession;
|
|
11
|
+
route: LakeboxServiceRoute;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "loading";
|
|
14
|
+
} | {
|
|
15
|
+
kind: "failed";
|
|
16
|
+
message: string;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "missing";
|
|
19
|
+
};
|
|
20
|
+
/** Runtime callbacks that authorize and resolve deterministic routes. */
|
|
21
|
+
export interface LakeboxRouteResolver {
|
|
22
|
+
/** Returns the authenticated Lakebox user for request headers, or `undefined`. */
|
|
23
|
+
user(headers: IncomingHttpHeaders): LakeboxUser | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Resolves a running service. Returns `loading` after starting the Lakebox
|
|
26
|
+
* or service in the background, and `missing` for an unknown service.
|
|
27
|
+
*/
|
|
28
|
+
resolve(user: LakeboxUser, service: string): Promise<LakeboxRouteResolution>;
|
|
29
|
+
/** Reports that a ready service refused a forwarded connection. */
|
|
30
|
+
unavailable(user: LakeboxUser, service: string): void;
|
|
31
|
+
}
|
|
32
|
+
interface RouteMatch {
|
|
33
|
+
userHash: string;
|
|
34
|
+
service: string;
|
|
35
|
+
mount: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Proxies `<prefix>/<user-hash>/<service>` to that user's service port.
|
|
39
|
+
*
|
|
40
|
+
* The user hash is the only routing key. A request is forwarded only when its
|
|
41
|
+
* authenticated identity hashes to the same value, and the port is derived from
|
|
42
|
+
* the hash and service name, so there is no stored route table. Requests
|
|
43
|
+
* without an identity are rejected with 404, including WebSocket upgrades.
|
|
44
|
+
*/
|
|
45
|
+
export declare class LakeboxRouteRegistry {
|
|
46
|
+
private readonly prefix;
|
|
47
|
+
private readonly resolver;
|
|
48
|
+
private readonly forwardingReadyTimeoutMs;
|
|
49
|
+
private readonly bridges;
|
|
50
|
+
private readonly upgrades;
|
|
51
|
+
private readonly pending;
|
|
52
|
+
private readonly proxy;
|
|
53
|
+
private shuttingDown;
|
|
54
|
+
/** Creates a registry beneath one AppKit route prefix. */
|
|
55
|
+
constructor(prefix: string, resolver: LakeboxRouteResolver, forwardingReadyTimeoutMs?: number);
|
|
56
|
+
/** Returns the route path segment match for a request path. */
|
|
57
|
+
match(path: string): RouteMatch | undefined;
|
|
58
|
+
/** Express middleware that authorizes, rewrites, and proxies matching requests. */
|
|
59
|
+
middleware(): (request: Request, response: Response, next: NextFunction) => Promise<void>;
|
|
60
|
+
/** Number of open forwarded HTTP and WebSocket connections. */
|
|
61
|
+
activeConnections(): number;
|
|
62
|
+
/** Returns whether an upgrade path belongs to the Lakebox route prefix. */
|
|
63
|
+
canHandleUpgrade(path: string): boolean;
|
|
64
|
+
/** Proxies an authorized WebSocket upgrade. Returns false when it was not handled. */
|
|
65
|
+
handleUpgrade(request: IncomingMessage, socket: Socket, head: Buffer): Promise<boolean>;
|
|
66
|
+
/** Closes every forwarding bridge, for example after the Lakebox stops. */
|
|
67
|
+
closeBridges(): Promise<void>;
|
|
68
|
+
/** Suppresses expected proxy errors once shutdown begins. */
|
|
69
|
+
beginShutdown(): void;
|
|
70
|
+
/** Closes bridges and the shared proxy. */
|
|
71
|
+
close(): Promise<void>;
|
|
72
|
+
private authorize;
|
|
73
|
+
private bridge;
|
|
74
|
+
}
|
|
75
|
+
export {};
|