@dbx-tools/shared-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.
@@ -0,0 +1,367 @@
1
+ import { z } from "zod";
2
+ export const lakeboxStatusSchema = z
3
+ .enum(["missing", "unknown", "starting", "running", "stopping", "stopped", "error"])
4
+ .describe("Normalized Lakebox lifecycle state. missing means the app Lakebox has not been created yet; it is created on first use.");
5
+ export const lakeboxUserSchema = z
6
+ .object({
7
+ hash: z
8
+ .string()
9
+ .regex(/^[0-9a-z]+$/)
10
+ .describe("FNV-1a hash of the authenticated identity; the only user routing key."),
11
+ name: z.string().min(1).describe("Locked, non-sudo Linux account that runs the user's work."),
12
+ uid: z.number().int().min(1).max(65535).describe("Deterministic Linux UID of the account."),
13
+ home: z.string().startsWith("/").describe("Stable home path, a symlink to persistent storage."),
14
+ routePrefix: z
15
+ .string()
16
+ .startsWith("/")
17
+ .describe("AppKit route prefix beneath which this user's services are exposed."),
18
+ })
19
+ .strict()
20
+ .describe("The Lakebox account derived from the current authenticated user.");
21
+ /** Built-in services every user can start without a definition. */
22
+ export const LAKEBOX_BUILT_IN_SERVICES = [
23
+ { name: "terminal", label: "Terminal" },
24
+ { name: "desktop", label: "Desktop" },
25
+ ];
26
+ export const lakeboxBuiltInServiceNameSchema = z
27
+ .enum(["terminal", "desktop"])
28
+ .describe("Built-in user service backed by a package-owned definition.");
29
+ /** Environment variables the runtime injects into every service. */
30
+ export const LAKEBOX_RESERVED_SERVICE_ENV = [
31
+ "SERVICE_NAME",
32
+ "SERVICE_PATH",
33
+ "SERVICE_PORT",
34
+ "PORT",
35
+ ];
36
+ export const lakeboxServiceNameSchema = z
37
+ .string()
38
+ .regex(/^[a-z][a-z0-9-]{0,30}$/, "Use 1-31 lowercase letters, digits, or hyphens, starting with a letter.")
39
+ .describe("Service name, unique per user. It is the route segment and, with the user hash, derives the service port.");
40
+ export const lakeboxServiceStateSchema = z
41
+ .enum(["stopped", "starting", "ready", "error"])
42
+ .describe("Current service state.");
43
+ export const lakeboxServiceKindSchema = z
44
+ .enum(["image", "terminal", "desktop"])
45
+ .describe("image runs an OCI image; terminal and desktop are built-in services that run the Lakebox host environment.");
46
+ export const lakeboxServiceSchema = z
47
+ .object({
48
+ name: lakeboxServiceNameSchema,
49
+ kind: lakeboxServiceKindSchema,
50
+ image: z.string().optional().describe("OCI image reference for image services."),
51
+ openPath: z
52
+ .string()
53
+ .optional()
54
+ .describe("Configured entry path appended to the service route."),
55
+ state: lakeboxServiceStateSchema,
56
+ port: z
57
+ .number()
58
+ .int()
59
+ .min(1024)
60
+ .max(65535)
61
+ .describe("Loopback port derived from the user hash and service name."),
62
+ route: z
63
+ .boolean()
64
+ .describe("Whether AppKit exposes the service through an authenticated route."),
65
+ path: z.string().startsWith("/").describe("AppKit route path for the service."),
66
+ openUrl: z
67
+ .union([z.string().startsWith("/"), z.httpUrl()])
68
+ .optional()
69
+ .describe("AppKit URL that opens the service; REST responses use a path and agent tools resolve it against the browser app origin."),
70
+ error: z.string().optional().describe("Latest start or readiness failure."),
71
+ log: z
72
+ .string()
73
+ .optional()
74
+ .describe("Bounded tail of the service log; omitted in agent listings."),
75
+ })
76
+ .strict()
77
+ .describe("One user-scoped Lakebox service.");
78
+ export const lakeboxSummarySchema = z
79
+ .object({
80
+ supported: z.boolean().describe("Whether the workspace exposes the Databricks Lakebox API."),
81
+ auto: z
82
+ .boolean()
83
+ .describe("Whether commands, services, and routes start or create the Lakebox on demand."),
84
+ status: lakeboxStatusSchema,
85
+ id: z.string().optional().describe("Databricks Lakebox identifier, once created."),
86
+ name: z.string().min(1).describe("Product display label; never the upstream machine name."),
87
+ idleTimeoutSeconds: z
88
+ .number()
89
+ .int()
90
+ .positive()
91
+ .optional()
92
+ .describe("Platform idle timeout after which the Lakebox stops."),
93
+ user: lakeboxUserSchema,
94
+ services: z.array(lakeboxServiceSchema).describe("The current user's services."),
95
+ servicesStale: z
96
+ .boolean()
97
+ .describe("True when services come from the last successful controller observation rather than live Lakebox state."),
98
+ servicesObservedAt: z
99
+ .string()
100
+ .datetime()
101
+ .optional()
102
+ .describe("Time of the last successful live service observation."),
103
+ canStart: z.boolean().describe("Whether the Lakebox can be started or created now."),
104
+ canStop: z.boolean().describe("Whether the Lakebox can be stopped now."),
105
+ })
106
+ .strict()
107
+ .describe("Secret-free summary of the app Lakebox for the current user.");
108
+ const environmentSchema = z
109
+ .record(z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/), z.string())
110
+ .describe("Environment variables.");
111
+ export const lakeboxCommandRequestSchema = z
112
+ .object({
113
+ command: z
114
+ .string()
115
+ .min(1)
116
+ .regex(/^\S+$/, 'Command must be one executable name; use command "sh" for shell syntax.')
117
+ .describe('Executable name only. Put arguments in args. For shell syntax, use command "sh" with args ["-lc", "<script>"].'),
118
+ args: z
119
+ .array(z.string())
120
+ .default([])
121
+ .describe("Individual arguments. Never concatenate the executable and its arguments."),
122
+ cwd: z
123
+ .string()
124
+ .optional()
125
+ .describe("Working directory on the Lakebox host. Defaults to the user's home."),
126
+ env: environmentSchema
127
+ .optional()
128
+ .describe("Non-authentication environment overlay. Databricks credentials and SSH agent variables are rejected."),
129
+ timeoutMs: z.number().int().positive().max(3_600_000).optional().describe("Command timeout."),
130
+ })
131
+ .strict()
132
+ .superRefine((request, context) => rejectCredentialEnvKeys(request.env, context))
133
+ .describe("Command executed as the current user's Lakebox account.");
134
+ export const lakeboxCommandResultSchema = z
135
+ .object({
136
+ success: z.boolean().describe("Whether the command exited successfully."),
137
+ exitCode: z.number().int().describe("Remote exit code."),
138
+ stdout: z.string().describe("Captured standard output."),
139
+ stderr: z.string().describe("Captured standard error."),
140
+ executionTimeMs: z.number().nonnegative().describe("Elapsed execution time."),
141
+ timedOut: z.boolean().optional().describe("Whether timeout terminated the command."),
142
+ command: z.string().describe("Executed command."),
143
+ args: z.array(z.string()).describe("Executed arguments."),
144
+ })
145
+ .strict()
146
+ .describe("Lakebox command execution result.");
147
+ export const lakeboxServiceMountSchema = z
148
+ .object({
149
+ source: z
150
+ .string()
151
+ .min(1)
152
+ .describe("Host directory relative to the user's home, such as data. It is created when missing. Absolute paths and parent traversal are rejected."),
153
+ target: z
154
+ .string()
155
+ .startsWith("/")
156
+ .describe("Absolute path inside the container, such as /example."),
157
+ readOnly: z.boolean().default(false).describe("Mount read-only inside the container."),
158
+ })
159
+ .strict()
160
+ .refine((mount) => !mount.source.startsWith("/") && !mount.source.split("/").includes(".."), {
161
+ message: "Mount sources must stay inside the user's home.",
162
+ path: ["source"],
163
+ })
164
+ .describe("Bind mount from the user's persistent home into the container.");
165
+ export const createLakeboxServiceRequestSchema = z
166
+ .object({
167
+ name: lakeboxServiceNameSchema,
168
+ image: z
169
+ .string()
170
+ .min(1)
171
+ .regex(/^\S+$/)
172
+ .describe("OCI image reference pulled anonymously, such as docker.io/library/python:3.12-alpine."),
173
+ command: z
174
+ .array(z.string())
175
+ .min(1)
176
+ .optional()
177
+ .describe('Complete argv that replaces the image entrypoint and command. Tokens are passed literally; there is no shell parsing unless the first tokens are a shell such as ["sh", "-c", "..."]. Omit to run the image\'s own entrypoint and command.'),
178
+ env: environmentSchema
179
+ .default({})
180
+ .describe("Container environment. SERVICE_NAME, SERVICE_PATH, SERVICE_PORT, and PORT are injected and reserved; Databricks credentials are rejected."),
181
+ workingDirectory: z
182
+ .string()
183
+ .startsWith("/")
184
+ .optional()
185
+ .describe("Working directory inside the container. Defaults to the image working directory."),
186
+ mounts: z
187
+ .array(lakeboxServiceMountSchema)
188
+ .default([])
189
+ .describe("Bind mounts from the user's home. Host file permissions still apply."),
190
+ route: z
191
+ .boolean()
192
+ .default(true)
193
+ .describe("Expose the service through the user's authenticated AppKit route. Routed services must listen on 127.0.0.1:$SERVICE_PORT; there is no Docker-style port publishing."),
194
+ openPath: z
195
+ .string()
196
+ .optional()
197
+ .describe("Entry path appended to the route, such as index.html?mode=1."),
198
+ stripPrefix: z
199
+ .boolean()
200
+ .default(true)
201
+ .describe("Remove the route prefix before forwarding. Set false only when the server is configured for the full SERVICE_PATH base path."),
202
+ pull: z
203
+ .enum(["missing", "always"])
204
+ .default("missing")
205
+ .describe("Pull the image only when absent, or always before starting."),
206
+ })
207
+ .strict()
208
+ .superRefine((request, context) => {
209
+ rejectCredentialEnvKeys(request.env, context);
210
+ for (const name of LAKEBOX_RESERVED_SERVICE_ENV) {
211
+ if (name in request.env) {
212
+ context.addIssue({
213
+ code: "custom",
214
+ path: ["env", name],
215
+ message: `${name} is injected by the Lakebox runtime and cannot be set.`,
216
+ });
217
+ }
218
+ }
219
+ if (LAKEBOX_BUILT_IN_SERVICES.some((service) => service.name === request.name)) {
220
+ context.addIssue({
221
+ code: "custom",
222
+ path: ["name"],
223
+ message: `${request.name} is a built-in service name.`,
224
+ });
225
+ }
226
+ })
227
+ .describe("Create or replace a user service that runs an OCI image detached under the Lakebox runtime.");
228
+ export const lakeboxServiceActionSchema = z
229
+ .object({ name: lakeboxServiceNameSchema })
230
+ .strict()
231
+ .describe("Request that targets one of the current user's services.");
232
+ /** Default number of service log lines returned by bounded log reads. */
233
+ export const LAKEBOX_LOG_DEFAULT_MAX_LINES = 200;
234
+ /** Default service log character cap returned by bounded log reads. */
235
+ export const LAKEBOX_LOG_DEFAULT_MAX_CHARS = 16_000;
236
+ export const lakeboxServiceLogsRequestSchema = lakeboxServiceActionSchema
237
+ .extend({
238
+ maxLines: z.coerce
239
+ .number()
240
+ .int()
241
+ .min(1)
242
+ .max(1_000)
243
+ .default(LAKEBOX_LOG_DEFAULT_MAX_LINES)
244
+ .describe("Maximum number of trailing log lines."),
245
+ maxChars: z.coerce
246
+ .number()
247
+ .int()
248
+ .min(1)
249
+ .max(64_000)
250
+ .default(LAKEBOX_LOG_DEFAULT_MAX_CHARS)
251
+ .describe("Maximum number of trailing log characters."),
252
+ })
253
+ .strict()
254
+ .describe("Bounded log request for one service.");
255
+ export const lakeboxServiceLogsResponseSchema = z
256
+ .object({ log: z.string().describe("Bounded trailing service log, including image pulls.") })
257
+ .strict()
258
+ .describe("Bounded service log response.");
259
+ export const lakeboxServicesResponseSchema = z
260
+ .object({ services: z.array(lakeboxServiceSchema).describe("The current user's services.") })
261
+ .strict()
262
+ .describe("Service listing response.");
263
+ export const lakeboxServiceResponseSchema = z
264
+ .object({ service: lakeboxServiceSchema })
265
+ .strict()
266
+ .describe("Single service response.");
267
+ export const removeLakeboxServiceResponseSchema = z
268
+ .object({ removed: z.boolean().describe("Whether a saved service was removed.") })
269
+ .strict()
270
+ .describe("Service removal response.");
271
+ export const lakeboxMetricsSnapshotSchema = z
272
+ .object({
273
+ at: z.string().datetime().describe("Sample time."),
274
+ cpu: z
275
+ .object({
276
+ cores: z.number().int().positive().describe("Online CPU count."),
277
+ usedPercent: z
278
+ .number()
279
+ .min(0)
280
+ .max(100)
281
+ .describe("CPU busy percentage since the last sample."),
282
+ load1: z.number().nonnegative().describe("One-minute load average."),
283
+ })
284
+ .strict()
285
+ .describe("CPU usage."),
286
+ memory: z
287
+ .object({
288
+ totalBytes: z.number().nonnegative().describe("Total memory."),
289
+ usedBytes: z.number().nonnegative().describe("Memory in use, excluding reclaimable cache."),
290
+ })
291
+ .strict()
292
+ .describe("Memory usage."),
293
+ storage: z
294
+ .object({
295
+ totalBytes: z.number().nonnegative().describe("Persistent home volume size."),
296
+ usedBytes: z.number().nonnegative().describe("Persistent home volume usage."),
297
+ })
298
+ .strict()
299
+ .describe("Persistent storage usage."),
300
+ network: z
301
+ .object({
302
+ rxBytesPerSecond: z.number().nonnegative().describe("Inbound network throughput."),
303
+ txBytesPerSecond: z.number().nonnegative().describe("Outbound network throughput."),
304
+ })
305
+ .strict()
306
+ .describe("Network throughput on the primary interface."),
307
+ })
308
+ .strict()
309
+ .describe("Machine-level Lakebox resource sample. Never includes process information.");
310
+ export const lakeboxMetricsResponseSchema = z
311
+ .object({
312
+ status: lakeboxStatusSchema,
313
+ series: z
314
+ .array(lakeboxMetricsSnapshotSchema)
315
+ .describe("Recent samples, oldest first. Empty while the Lakebox is not running."),
316
+ })
317
+ .strict()
318
+ .describe("Lakebox metrics response.");
319
+ const readTool = { appkitTool: { agentTool: true, effect: "read", requiresUserContext: true } };
320
+ const writeTool = { appkitTool: { agentTool: true, effect: "write", requiresUserContext: true } };
321
+ export const getLakeboxOperationSchema = z
322
+ .object({})
323
+ .strict()
324
+ .describe("Return the app Lakebox status, the current user's Lakebox account, and that user's services. This never creates the Lakebox.")
325
+ .meta(readTool);
326
+ export const executeLakeboxCommandOperationSchema = lakeboxCommandRequestSchema
327
+ .describe("Run a command on the Lakebox host as the current user's locked, non-sudo account, starting the Lakebox when needed. Use services, not background commands, for long-running servers.")
328
+ .meta(writeTool);
329
+ export const listLakeboxServicesOperationSchema = z
330
+ .object({})
331
+ .strict()
332
+ .describe("List the current user's services with state, port, and route. Logs are omitted.")
333
+ .meta(readTool);
334
+ export const createLakeboxServiceOperationSchema = createLakeboxServiceRequestSchema
335
+ .describe("Create or replace a user service from an OCI image, start it detached, and wait until it is ready or failed. This is a constrained container API, not the Docker CLI: there is no daemon, port publishing, privileged mode, or device access. Routed services listen on 127.0.0.1:$SERVICE_PORT and are reached at the returned openUrl. Services restart from their saved definition when the Lakebox starts; process memory is not resumed.")
336
+ .meta(writeTool);
337
+ export const startLakeboxServiceOperationSchema = lakeboxServiceActionSchema
338
+ .describe("Start a saved service or a built-in terminal or desktop and wait until it is ready or failed.")
339
+ .meta({ appkitTool: { ...writeTool.appkitTool, idempotent: true } });
340
+ export const stopLakeboxServiceOperationSchema = lakeboxServiceActionSchema
341
+ .describe("Stop one running service without removing its definition.")
342
+ .meta({ appkitTool: { ...writeTool.appkitTool, idempotent: true } });
343
+ export const removeLakeboxServiceOperationSchema = lakeboxServiceActionSchema
344
+ .describe("Stop and delete one saved service definition and its image root filesystem. Mounted home directories are preserved.")
345
+ .meta({
346
+ appkitTool: {
347
+ agentTool: true,
348
+ effect: "destructive",
349
+ approval: true,
350
+ requiresUserContext: true,
351
+ },
352
+ });
353
+ export const getLakeboxServiceLogsOperationSchema = lakeboxServiceLogsRequestSchema
354
+ .describe("Read a bounded tail of one service log, including image pull and readiness output.")
355
+ .meta(readTool);
356
+ function rejectCredentialEnvKeys(env, context) {
357
+ for (const name of Object.keys(env ?? {})) {
358
+ if (name.startsWith("DATABRICKS_") || name === "SSH_AUTH_SOCK") {
359
+ context.addIssue({
360
+ code: "custom",
361
+ path: ["env", name],
362
+ message: "Environment overlays cannot restore Databricks or SSH agent credentials; use a dedicated app-mediated capability.",
363
+ });
364
+ }
365
+ }
366
+ }
367
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NoZW1hcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zY2hlbWFzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFFeEIsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQztLQUNqQyxJQUFJLENBQUMsQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQztLQUNuRixRQUFRLENBQ1AseUhBQXlILENBQzFILENBQUM7QUFHSixNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxDQUFDO0tBQy9CLE1BQU0sQ0FBQztJQUNOLElBQUksRUFBRSxDQUFDO1NBQ0osTUFBTSxFQUFFO1NBQ1IsS0FBSyxDQUFDLGFBQWEsQ0FBQztTQUNwQixRQUFRLENBQUMsdUVBQXVFLENBQUM7SUFDcEYsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLDJEQUEyRCxDQUFDO0lBQzdGLEdBQUcsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxRQUFRLENBQUMseUNBQXlDLENBQUM7SUFDM0YsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLG9EQUFvRCxDQUFDO0lBQy9GLFdBQVcsRUFBRSxDQUFDO1NBQ1gsTUFBTSxFQUFFO1NBQ1IsVUFBVSxDQUFDLEdBQUcsQ0FBQztTQUNmLFFBQVEsQ0FBQyxxRUFBcUUsQ0FBQztDQUNuRixDQUFDO0tBQ0QsTUFBTSxFQUFFO0tBQ1IsUUFBUSxDQUFDLGtFQUFrRSxDQUFD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LEVBQUUsQ0FBQztZQUMvRCxPQUFPLENBQUMsUUFBUSxDQUFDO2dCQUNmLElBQUksRUFBRSxRQUFRO2dCQUNkLElBQUksRUFBRSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUM7Z0JBQ25CLE9BQU8sRUFDTCxtSEFBbUg7YUFDdEgsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcblxuZXhwb3J0IGNvbnN0IGxha2Vib3hTdGF0dXNTY2hlbWEgPSB6XG4gIC5lbnVtKFtcIm1pc3NpbmdcIiwgXCJ1bmtub3duXCIsIFwic3RhcnRpbmdcIiwgXCJydW5uaW5nXCIsIFwic3RvcHBpbmdcIiwgXCJzdG9wcGVkXCIsIFwiZXJyb3JcIl0pXG4gIC5kZXNjcmliZShcbiAgICBcIk5vcm1hbGl6ZWQgTGFrZWJveCBsaWZlY3ljbGUgc3RhdGUuIG1pc3NpbmcgbWVhbnMgdGhlIGFwcCBMYWtlYm94IGhhcyBub3QgYmVlbiBjcmVhdGVkIHlldDsgaXQgaXMgY3JlYXRlZCBvbiBmaXJzdCB1c2UuXCIsXG4gICk7XG5leHBvcnQgdHlwZSBMYWtlYm94U3RhdHVzID0gei5pbmZlcjx0eXBlb2YgbGFrZWJveFN0YXR1c1NjaGVtYT47XG5cbmV4cG9ydCBjb25zdCBsYWtlYm94VXNlclNjaGVtYSA9IHpcbiAgLm9iamVjdCh7XG4gICAgaGFzaDogelxuICAgICAgLnN0cmluZygpXG4gICAgICAucmVnZXgoL15bMC05YS16XSskLylcbiAgICAgIC5kZXNjcmliZShcIkZOVi0xYSBoYXNoIG9mIHRoZSBhdXRoZW50aWNhdGVkIGlkZW50aXR5OyB0aGUgb25seSB1c2VyIHJvdXRpbmcga2V5LlwiKSxcbiAgICBuYW1lOiB6LnN0cmluZygpLm1pbigxKS5kZXNjcmliZShcIkxvY2tlZCwgbm9uLXN1ZG8gTGludXggYWNjb3VudCB0aGF0IHJ1bnMgdGhlIHVzZXIncyB3b3JrLlwiKSxcbiAgICB1aWQ6IHoubnVtYmVyKCkuaW50KCkubWluKDEpLm1heCg2NTUzNSkuZGVzY3JpYmUoXCJEZXRlcm1pbmlzdGljIExpbnV4IFVJRCBvZiB0aGUgYWNjb3VudC5cIiksXG4gICAgaG9tZTogei5zdHJpbmcoKS5zdGFydHNXaXRoKFwiL1wiKS5kZXNjcmliZShcIlN0YWJsZSBob21lIHBhdGgsIGEgc3ltbGluayB0byBwZXJzaXN0ZW50IHN0b3JhZ2UuXCIpLFxuICAgIHJvdXRlUHJlZml4OiB6XG4gICAgICAuc3RyaW5nKClcbiAgICAgIC5zdGFydHNXaXRoKFwiL1wiKVxuICAgICAgLmRlc2NyaWJlKFwiQXBwS2l0IHJvdXRlIHByZWZpeCBiZW5lYXRoIHdoaWNoIHRoaXMgdXNlcidzIHNlcnZpY2VzIGFyZSBleHBvc2VkLlwiKSxcbiAgfSlcbiAgLnN0cmljdCgpXG4gIC5kZXNjcmliZShcIlRoZSBMYWtlYm94IGFjY291bnQgZGVyaXZlZCBmcm9tIHRoZSBjdXJyZW50IGF1dGhlbnRpY2F0ZWQgdXNlci5cIik7XG5leHBvcnQgdHlwZSBMYWtlYm94VXNlciA9IHouaW5mZXI8dHlwZW9mIGxha2Vib3hVc2VyU2NoZW1hPjtcblxuLyoqIEJ1aWx0LWluIHNlcnZpY2VzIGV2ZXJ5IHVzZXIgY2FuIHN0YXJ0IHdpdGhvdXQgYSBkZWZpbml0aW9uLiAqL1xuZXhwb3J0IGNvbnN0IExBS0VCT1hfQlVJTFRfSU5fU0VSVklDRVMgPSBbXG4gIHsgbmFtZTogXCJ0ZXJtaW5hbFwiLCBsYWJlbDogXCJUZXJtaW5hbFwiIH0sXG4gIHsgbmFtZTogXCJkZXNrdG9wXCIsIGxhYmVsOiBcIkRlc2t0b3BcIiB9LFxuXSBhcyBjb25zdDtcblxuZXhwb3J0IGNvbnN0IGxha2Vib3hCdWlsdEluU2VydmljZU5hbWVTY2hlbWEgPSB6XG4gIC5lbnVtKFtcInRlcm1pbmFsXCIsIFwiZGVza3RvcFwiXSlcbiAgLmRlc2NyaWJlKFwiQnVpbHQtaW4gdXNlciBzZXJ2aWNlIGJhY2tlZCBieSBhIHBhY2thZ2Utb3duZWQgZGVmaW5pdGlvbi5cIik7XG5leHBvcnQgdHlwZSBMYWtlYm94QnVpbHRJblNlcnZpY2VOYW1lID0gei5pbmZlcjx0eXBlb2YgbGFrZWJveEJ1aWx0SW5TZXJ2aWNlTmFtZVNjaGVtYT47XG5cbi8qKiBFbnZpcm9ubWVudCB2YXJpYWJsZXMgdGhlIHJ1bnRpbWUgaW5qZWN0cyBpbnRvIGV2ZXJ5IHNlcnZpY2UuICovXG5leHBvcnQgY29uc3QgTEFLRUJPWF9SRVNFUlZFRF9TRVJWSUNFX0VOViA9IFtcbiAgXCJTRVJWSUNFX05BTUVcIixcbiAgXCJTRVJWSUNFX1BBVEhcIixcbiAgXCJTRVJWSUNFX1BPUlRcIixcbiAgXCJQT1JUXCIsXG5dIGFzIGNvbnN0O1xuXG5leHBvcnQgY29uc3QgbGFrZWJveFNlcnZpY2VOYW1lU2NoZW1hID0gelxuICAuc3RyaW5nKClcbiAgLnJlZ2V4KFxuICAgIC9eW2Etel1bYS16MC05LV17MCwzMH0kLyxcbiAgICBcIlVzZSAxLTMxIGxvd2VyY2FzZSBsZXR0ZXJzLCBkaWdpdHMsIG9yIGh5cGhlbnMsIHN0YXJ0aW5nIHdpdGggYSBsZXR0ZXIuXCIsXG4gIClcbiAgLmRlc2NyaWJlKFxuICAgIFwiU2VydmljZSBuYW1lLCB1bmlxdWUgcGVyIHVzZXIuIEl0IGlzIHRoZSByb3V0ZSBzZWdtZW50IGFuZCwgd2l0aCB0aGUgdXNlciBoYXNoLCBkZXJpdmVzIHRoZSBzZXJ2aWNlIHBvcnQuXCIsXG4gICk7XG5cbmV4cG9ydCBjb25zdCBsYWtlYm94U2VydmljZVN0YXRlU2NoZW1hID0gelxuICAuZW51bShbXCJzdG9wcGVkXCIsIFwic3RhcnRpbmdcIiwgXCJyZWFkeVwiLCBcImVycm9yXCJdKVxuICAuZGVzY3JpYmUoXCJDdXJyZW50IHNlcnZpY2Ugc3RhdGUuXCIpO1xuZXhwb3J0IHR5cGUgTGFrZWJveFNlcnZpY2VTdGF0ZSA9IHouaW5mZXI8dHlwZW9mIGxha2Vib3hTZXJ2aWNlU3RhdGVTY2hlbWE+O1xuXG5leHBvcnQgY29uc3QgbGFrZWJveFNlcnZpY2VLaW5kU2NoZW1hID0gelxuICAuZW51bShbXCJpbWFnZVwiLCBcInRlcm1pbmFsXCIsIFwiZGVza3RvcFwiXSlcbiAgLmRlc2NyaWJlKFxuICAgIFwiaW1hZ2UgcnVucyBhbiBPQ0kgaW1hZ2U7IHRlcm1pbmFsIGFuZCBkZXNrdG9wIGFyZSBidWlsdC1pbiBzZXJ2aWNlcyB0aGF0IHJ1biB0aGUgTGFrZWJveCBob3N0IGVudmlyb25tZW50LlwiLFxuICApO1xuZXhwb3J0IHR5cGUgTGFrZWJveFNlcnZpY2VLaW5kID0gei5pbmZlcjx0eXBlb2YgbGFrZWJveFNlcnZpY2VLaW5kU2NoZW1hPjtcblxuZXhwb3J0IGNvbnN0IGxha2Vib3hTZXJ2aWNlU2NoZW1hID0gelxuICAub2JqZWN0KHtcbiAgICBuYW1lOiBsYWtlYm94U2VydmljZU5hbWVTY2hlbWEsXG4gICAga2luZDogbGFrZWJveFNlcnZpY2VLaW5kU2NoZW1hLFxuICAgIGltYWdlOiB6LnN0cmluZygpLm9wdGlvbmFsKCkuZGVzY3JpYmUoXCJPQ0kgaW1hZ2UgcmVmZXJlbmNlIGZvciBpbWFnZSBzZXJ2aWNlcy5cIiksXG4gICAgb3BlblBhdGg6IHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLm9wdGlvbmFsKClcbiAgICAgIC5kZXNjcmliZShcIkNvbmZpZ3VyZWQgZW50cnkgcGF0aCBhcHBlbmRlZCB0byB0aGUgc2VydmljZSByb3V0ZS5cIiksXG4gICAgc3RhdGU6IGxha2Vib3hTZXJ2aWNlU3RhdGVTY2hlbWEsXG4gICAgcG9ydDogelxuICAgICAgLm51bWJlcigpXG4gICAgICAuaW50KClcbiAgICAgIC5taW4oMTAyNClcbiAgICAgIC5tYXgoNjU1MzUpXG4gICAgICAuZGVzY3JpYmUoXCJMb29wYmFjayBwb3J0IGRlcml2ZWQgZnJvbSB0aGUgdXNlciBoYXNoIGFuZCBzZXJ2aWNlIG5hbWUuXCIpLFxuICAgIHJvdXRlOiB6XG4gICAgICAuYm9vbGVhbigpXG4gICAgICAuZGVzY3JpYmUoXCJXaGV0aGVyIEFwcEtpdCBleHBvc2VzIHRoZSBzZXJ2aWNlIHRocm91Z2ggYW4gYXV0aGVudGljYXRlZCByb3V0ZS5cIiksXG4gICAgcGF0aDogei5zdHJpbmcoKS5zdGFydHNXaXRoKFwiL1wiKS5kZXNjcmliZShcIkFwcEtpdCByb3V0ZSBwYXRoIGZvciB0aGUgc2VydmljZS5cIiksXG4gICAgb3BlblVybDogelxuICAgICAgLnVuaW9uKFt6LnN0cmluZygpLnN0YXJ0c1dpdGgoXCIvXCIpLCB6Lmh0dHBVcmwoKV0pXG4gICAgICAub3B0aW9uYWwoKVxuICAgICAgLmRlc2NyaWJlKFxuICAgICAgICBcIkFwcEtpdCBVUkwgdGhhdCBvcGVucyB0aGUgc2VydmljZTsgUkVTVCByZXNwb25zZXMgdXNlIGEgcGF0aCBhbmQgYWdlbnQgdG9vbHMgcmVzb2x2ZSBpdCBhZ2FpbnN0IHRoZSBicm93c2VyIGFwcCBvcmlnaW4uXCIsXG4gICAgICApLFxuICAgIGVycm9yOiB6LnN0cmluZygpLm9wdGlvbmFsKCkuZGVzY3JpYmUoXCJMYXRlc3Qgc3RhcnQgb3IgcmVhZGluZXNzIGZhaWx1cmUuXCIpLFxuICAgIGxvZzogelxuICAgICAgLnN0cmluZygpXG4gICAgICAub3B0aW9uYWwoKVxuICAgICAgLmRlc2NyaWJlKFwiQm91bmRlZCB0YWlsIG9mIHRoZSBzZXJ2aWNlIGxvZzsgb21pdHRlZCBpbiBhZ2VudCBsaXN0aW5ncy5cIiksXG4gIH0pXG4gIC5zdHJpY3QoKVxuICAuZGVzY3JpYmUoXCJPbmUgdXNlci1zY29wZWQgTGFrZWJveCBzZXJ2aWNlLlwiKTtcbmV4cG9ydCB0eXBlIExha2Vib3hTZXJ2aWNlID0gei5pbmZlcjx0eXBlb2YgbGFrZWJveFNlcnZpY2VTY2hlbWE+O1xuXG5leHBvcnQgY29uc3QgbGFrZWJveFN1bW1hcnlTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIHN1cHBvcnRlZDogei5ib29sZWFuKCkuZGVzY3JpYmUoXCJXaGV0aGVyIHRoZSB3b3Jrc3BhY2UgZXhwb3NlcyB0aGUgRGF0YWJyaWNrcyBMYWtlYm94IEFQSS5cIiksXG4gICAgYXV0bzogelxuICAgICAgLmJvb2xlYW4oKVxuICAgICAgLmRlc2NyaWJlKFwiV2hldGhlciBjb21tYW5kcywgc2VydmljZXMsIGFuZCByb3V0ZXMgc3RhcnQgb3IgY3JlYXRlIHRoZSBMYWtlYm94IG9uIGRlbWFuZC5cIiksXG4gICAgc3RhdHVzOiBsYWtlYm94U3RhdHVzU2NoZW1hLFxuICAgIGlkOiB6LnN0cmluZygpLm9wdGlvbmFsKCkuZGVzY3JpYmUoXCJEYXRhYnJpY2tzIExha2Vib3ggaWRlbnRpZmllciwgb25jZSBjcmVhdGVkLlwiKSxcbiAgICBuYW1lOiB6LnN0cmluZygpLm1pbigxKS5kZXNjcmliZShcIlByb2R1Y3QgZGlzcGxheSBsYWJlbDsgbmV2ZXIgdGhlIHVwc3RyZWFtIG1hY2hpbmUgbmFtZS5cIiksXG4gICAgaWRsZVRpbWVvdXRTZWNvbmRzOiB6XG4gICAgICAubnVtYmVyKClcbiAgICAgIC5pbnQoKVxuICAgICAgLnBvc2l0aXZlKClcbiAgICAgIC5vcHRpb25hbCgpXG4gICAgICAuZGVzY3JpYmUoXCJQbGF0Zm9ybSBpZGxlIHRpbWVvdXQgYWZ0ZXIgd2hpY2ggdGhlIExha2Vib3ggc3RvcHMuXCIpLFxuICAgIHVzZXI6IGxha2Vib3hVc2VyU2NoZW1hLFxuICAgIHNlcnZpY2VzOiB6LmFycmF5KGxha2Vib3hTZXJ2aWNlU2NoZW1hKS5kZXNjcmliZShcIlRoZSBjdXJyZW50IHVzZXIncyBzZXJ2aWNlcy5cIiksXG4gICAgc2VydmljZXNTdGFsZTogelxuICAgICAgLmJvb2xlYW4oKVxuICAgICAgLmRlc2NyaWJlKFxuICAgICAgICBcIlRydWUgd2hlbiBzZXJ2aWNlcyBjb21lIGZyb20gdGhlIGxhc3Qgc3VjY2Vzc2Z1bCBjb250cm9sbGVyIG9ic2VydmF0aW9uIHJhdGhlciB0aGFuIGxpdmUgTGFrZWJveCBzdGF0ZS5cIixcbiAgICAgICksXG4gICAgc2VydmljZXNPYnNlcnZlZEF0OiB6XG4gICAgICAuc3RyaW5nKClcbiAgICAgIC5kYXRldGltZSgpXG4gICAgICAub3B0aW9uYWwoKVxuICAgICAgLmRlc2NyaWJlKFwiVGltZSBvZiB0aGUgbGFzdCBzdWNjZXNzZnVsIGxpdmUgc2VydmljZSBvYnNlcnZhdGlvbi5cIiksXG4gICAgY2FuU3RhcnQ6IHouYm9vbGVhbigpLmRlc2NyaWJlKFwiV2hldGhlciB0aGUgTGFrZWJveCBjYW4gYmUgc3RhcnRlZCBvciBjcmVhdGVkIG5vdy5cIiksXG4gICAgY2FuU3RvcDogei5ib29sZWFuKCkuZGVzY3JpYmUoXCJXaGV0aGVyIHRoZSBMYWtlYm94IGNhbiBiZSBzdG9wcGVkIG5vdy5cIiksXG4gIH0pXG4gIC5zdHJpY3QoKVxuICAuZGVzY3JpYmUoXCJTZWNyZXQtZnJlZSBzdW1tYXJ5IG9mIHRoZSBhcHAgTGFrZWJveCBmb3IgdGhlIGN1cnJlbnQgdXNlci5cIik7XG5leHBvcnQgdHlwZSBMYWtlYm94U3VtbWFyeSA9IHouaW5mZXI8dHlwZW9mIGxha2Vib3hTdW1tYXJ5U2NoZW1hPjtcblxuY29uc3QgZW52aXJvbm1lbnRTY2hlbWEgPSB6XG4gIC5yZWNvcmQoei5zdHJpbmcoKS5yZWdleCgvXltBLVphLXpfXVtBLVphLXowLTlfXSokLyksIHouc3RyaW5nKCkpXG4gIC5kZXNjcmliZShcIkVudmlyb25tZW50IHZhcmlhYmxlcy5cIik7XG5cbmV4cG9ydCBjb25zdCBsYWtlYm94Q29tbWFuZFJlcXVlc3RTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIGNvbW1hbmQ6IHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLm1pbigxKVxuICAgICAgLnJlZ2V4KC9eXFxTKyQvLCAnQ29tbWFuZCBtdXN0IGJlIG9uZSBleGVjdXRhYmxlIG5hbWU7IHVzZSBjb21tYW5kIFwic2hcIiBmb3Igc2hlbGwgc3ludGF4LicpXG4gICAgICAuZGVzY3JpYmUoXG4gICAgICAgICdFeGVjdXRhYmxlIG5hbWUgb25seS4gUHV0IGFyZ3VtZW50cyBpbiBhcmdzLiBGb3Igc2hlbGwgc3ludGF4LCB1c2UgY29tbWFuZCBcInNoXCIgd2l0aCBhcmdzIFtcIi1sY1wiLCBcIjxzY3JpcHQ+XCJdLicsXG4gICAgICApLFxuICAgIGFyZ3M6IHpcbiAgICAgIC5hcnJheSh6LnN0cmluZygpKVxuICAgICAgLmRlZmF1bHQoW10pXG4gICAgICAuZGVzY3JpYmUoXCJJbmRpdmlkdWFsIGFyZ3VtZW50cy4gTmV2ZXIgY29uY2F0ZW5hdGUgdGhlIGV4ZWN1dGFibGUgYW5kIGl0cyBhcmd1bWVudHMuXCIpLFxuICAgIGN3ZDogelxuICAgICAgLnN0cmluZygpXG4gICAgICAub3B0aW9uYWwoKVxuICAgICAgLmRlc2NyaWJlKFwiV29ya2luZyBkaXJlY3Rvcnkgb24gdGhlIExha2Vib3ggaG9zdC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIncyBob21lLlwiKSxcbiAgICBlbnY6IGVudmlyb25tZW50U2NoZW1hXG4gICAgICAub3B0aW9uYWwoKVxuICAgICAgLmRlc2NyaWJlKFxuICAgICAgICBcIk5vbi1hdXRoZW50aWNhdGlvbiBlbnZpcm9ubWVudCBvdmVybGF5LiBEYXRhYnJpY2tzIGNyZWRlbnRpYWxzIGFuZCBTU0ggYWdlbnQgdmFyaWFibGVzIGFyZSByZWplY3RlZC5cIixcbiAgICAgICksXG4gICAgdGltZW91dE1zOiB6Lm51bWJlcigpLmludCgpLnBvc2l0aXZlKCkubWF4KDNfNjAwXzAwMCkub3B0aW9uYWwoKS5kZXNjcmliZShcIkNvbW1hbmQgdGltZW91dC5cIiksXG4gIH0pXG4gIC5zdHJpY3QoKVxuICAuc3VwZXJSZWZpbmUoKHJlcXVlc3QsIGNvbnRleHQpID0+IHJlamVjdENyZWRlbnRpYWxFbnZLZXlzKHJlcXVlc3QuZW52LCBjb250ZXh0KSlcbiAgLmRlc2NyaWJlKFwiQ29tbWFuZCBleGVjdXRlZCBhcyB0aGUgY3VycmVudCB1c2VyJ3MgTGFrZWJveCBhY2NvdW50LlwiKTtcbmV4cG9ydCB0eXBlIExha2Vib3hDb21tYW5kUmVxdWVzdCA9IHouaW5wdXQ8dHlwZW9mIGxha2Vib3hDb21tYW5kUmVxdWVzdFNjaGVtYT47XG5cbmV4cG9ydCBjb25zdCBsYWtlYm94Q29tbWFuZFJlc3VsdFNjaGVtYSA9IHpcbiAgLm9iamVjdCh7XG4gICAgc3VjY2Vzczogei5ib29sZWFuKCkuZGVzY3JpYmUoXCJXaGV0aGVyIHRoZSBjb21tYW5kIGV4aXRlZCBzdWNjZXNzZnVsbHkuXCIpLFxuICAgIGV4aXRDb2RlOiB6Lm51bWJlcigpLmludCgpLmRlc2NyaWJlKFwiUmVtb3RlIGV4aXQgY29kZS5cIiksXG4gICAgc3Rkb3V0OiB6LnN0cmluZygpLmRlc2NyaWJlKFwiQ2FwdHVyZWQgc3RhbmRhcmQgb3V0cHV0LlwiKSxcbiAgICBzdGRlcnI6IHouc3RyaW5nKCkuZGVzY3JpYmUoXCJDYXB0dXJlZCBzdGFuZGFyZCBlcnJvci5cIiksXG4gICAgZXhlY3V0aW9uVGltZU1zOiB6Lm51bWJlcigpLm5vbm5lZ2F0aXZlKCkuZGVzY3JpYmUoXCJFbGFwc2VkIGV4ZWN1dGlvbiB0aW1lLlwiKSxcbiAgICB0aW1lZE91dDogei5ib29sZWFuKCkub3B0aW9uYWwoKS5kZXNjcmliZShcIldoZXRoZXIgdGltZW91dCB0ZXJtaW5hdGVkIHRoZSBjb21tYW5kLlwiKSxcbiAgICBjb21tYW5kOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiRXhlY3V0ZWQgY29tbWFuZC5cIiksXG4gICAgYXJnczogei5hcnJheSh6LnN0cmluZygpKS5kZXNjcmliZShcIkV4ZWN1dGVkIGFyZ3VtZW50cy5cIiksXG4gIH0pXG4gIC5zdHJpY3QoKVxuICAuZGVzY3JpYmUoXCJMYWtlYm94IGNvbW1hbmQgZXhlY3V0aW9uIHJlc3VsdC5cIik7XG5leHBvcnQgdHlwZSBMYWtlYm94Q29tbWFuZFJlc3VsdCA9IHouaW5mZXI8dHlwZW9mIGxha2Vib3hDb21tYW5kUmVzdWx0U2NoZW1hPjtcblxuZXhwb3J0IGNvbnN0IGxha2Vib3hTZXJ2aWNlTW91bnRTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIHNvdXJjZTogelxuICAgICAgLnN0cmluZygpXG4gICAgICAubWluKDEpXG4gICAgICAuZGVzY3JpYmUoXG4gICAgICAgIFwiSG9zdCBkaXJlY3RvcnkgcmVsYXRpdmUgdG8gdGhlIHVzZXIncyBob21lLCBzdWNoIGFzIGRhdGEuIEl0IGlzIGNyZWF0ZWQgd2hlbiBtaXNzaW5nLiBBYnNvbHV0ZSBwYXRocyBhbmQgcGFyZW50IHRyYXZlcnNhbCBhcmUgcmVqZWN0ZWQuXCIsXG4gICAgICApLFxuICAgIHRhcmdldDogelxuICAgICAgLnN0cmluZygpXG4gICAgICAuc3RhcnRzV2l0aChcIi9cIilcbiAgICAgIC5kZXNjcmliZShcIkFic29sdXRlIHBhdGggaW5zaWRlIHRoZSBjb250YWluZXIsIHN1Y2ggYXMgL2V4YW1wbGUuXCIpLFxuICAgIHJlYWRPbmx5OiB6LmJvb2xlYW4oKS5kZWZhdWx0KGZhbHNlKS5kZXNjcmliZShcIk1vdW50IHJlYWQtb25seSBpbnNpZGUgdGhlIGNvbnRhaW5lci5cIiksXG4gIH0pXG4gIC5zdHJpY3QoKVxuICAucmVmaW5lKChtb3VudCkgPT4gIW1vdW50LnNvdXJjZS5zdGFydHNXaXRoKFwiL1wiKSAmJiAhbW91bnQuc291cmNlLnNwbGl0KFwiL1wiKS5pbmNsdWRlcyhcIi4uXCIpLCB7XG4gICAgbWVzc2FnZTogXCJNb3VudCBzb3VyY2VzIG11c3Qgc3RheSBpbnNpZGUgdGhlIHVzZXIncyBob21lLlwiLFxuICAgIHBhdGg6IFtcInNvdXJjZVwiXSxcbiAgfSlcbiAgLmRlc2NyaWJlKFwiQmluZCBtb3VudCBmcm9tIHRoZSB1c2VyJ3MgcGVyc2lzdGVudCBob21lIGludG8gdGhlIGNvbnRhaW5lci5cIik7XG5leHBvcnQgdHlwZSBMYWtlYm94U2VydmljZU1vdW50ID0gei5pbnB1dDx0eXBlb2YgbGFrZWJveFNlcnZpY2VNb3VudFNjaGVtYT47XG5cbmV4cG9ydCBjb25zdCBjcmVhdGVMYWtlYm94U2VydmljZVJlcXVlc3RTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIG5hbWU6IGxha2Vib3hTZXJ2aWNlTmFtZVNjaGVtYSxcbiAgICBpbWFnZTogelxuICAgICAgLnN0cmluZygpXG4gICAgICAubWluKDEpXG4gICAgICAucmVnZXgoL15cXFMrJC8pXG4gICAgICAuZGVzY3JpYmUoXG4gICAgICAgIFwiT0NJIGltYWdlIHJlZmVyZW5jZSBwdWxsZWQgYW5vbnltb3VzbHksIHN1Y2ggYXMgZG9ja2VyLmlvL2xpYnJhcnkvcHl0aG9uOjMuMTItYWxwaW5lLlwiLFxuICAgICAgKSxcbiAgICBjb21tYW5kOiB6XG4gICAgICAuYXJyYXkoei5zdHJpbmcoKSlcbiAgICAgIC5taW4oMSlcbiAgICAgIC5vcHRpb25hbCgpXG4gICAgICAuZGVzY3JpYmUoXG4gICAgICAgICdDb21wbGV0ZSBhcmd2IHRoYXQgcmVwbGFjZXMgdGhlIGltYWdlIGVudHJ5cG9pbnQgYW5kIGNvbW1hbmQuIFRva2VucyBhcmUgcGFzc2VkIGxpdGVyYWxseTsgdGhlcmUgaXMgbm8gc2hlbGwgcGFyc2luZyB1bmxlc3MgdGhlIGZpcnN0IHRva2VucyBhcmUgYSBzaGVsbCBzdWNoIGFzIFtcInNoXCIsIFwiLWNcIiwgXCIuLi5cIl0uIE9taXQgdG8gcnVuIHRoZSBpbWFnZVxcJ3Mgb3duIGVudHJ5cG9pbnQgYW5kIGNvbW1hbmQuJyxcbiAgICAgICksXG4gICAgZW52OiBlbnZpcm9ubWVudFNjaGVtYVxuICAgICAgLmRlZmF1bHQoe30pXG4gICAgICAuZGVzY3JpYmUoXG4gICAgICAgIFwiQ29udGFpbmVyIGVudmlyb25tZW50LiBTRVJWSUNFX05BTUUsIFNFUlZJQ0VfUEFUSCwgU0VSVklDRV9QT1JULCBhbmQgUE9SVCBhcmUgaW5qZWN0ZWQgYW5kIHJlc2VydmVkOyBEYXRhYnJpY2tzIGNyZWRlbnRpYWxzIGFyZSByZWplY3RlZC5cIixcbiAgICAgICksXG4gICAgd29ya2luZ0RpcmVjdG9yeTogelxuICAgICAgLnN0cmluZygpXG4gICAgICAuc3RhcnRzV2l0aChcIi9cIilcbiAgICAgIC5vcHRpb25hbCgpXG4gICAgICAuZGVzY3JpYmUoXCJXb3JraW5nIGRpcmVjdG9yeSBpbnNpZGUgdGhlIGNvbnRhaW5lci4gRGVmYXVsdHMgdG8gdGhlIGltYWdlIHdvcmtpbmcgZGlyZWN0b3J5LlwiKSxcbiAgICBtb3VudHM6IHpcbiAgICAgIC5hcnJheShsYWtlYm94U2VydmljZU1vdW50U2NoZW1hKVxuICAgICAgLmRlZmF1bHQoW10pXG4gICAgICAuZGVzY3JpYmUoXCJCaW5kIG1vdW50cyBmcm9tIHRoZSB1c2VyJ3MgaG9tZS4gSG9zdCBmaWxlIHBlcm1pc3Npb25zIHN0aWxsIGFwcGx5LlwiKSxcbiAgICByb3V0ZTogelxuICAgICAgLmJvb2xlYW4oKVxuICAgICAgLmRlZmF1bHQodHJ1ZSlcbiAgICAgIC5kZXNjcmliZShcbiAgICAgICAgXCJFeHBvc2UgdGhlIHNlcnZpY2UgdGhyb3VnaCB0aGUgdXNlcidzIGF1dGhlbnRpY2F0ZWQgQXBwS2l0IHJvdXRlLiBSb3V0ZWQgc2VydmljZXMgbXVzdCBsaXN0ZW4gb24gMTI3LjAuMC4xOiRTRVJWSUNFX1BPUlQ7IHRoZXJlIGlzIG5vIERvY2tlci1zdHlsZSBwb3J0IHB1Ymxpc2hpbmcuXCIsXG4gICAgICApLFxuICAgIG9wZW5QYXRoOiB6XG4gICAgICAuc3RyaW5nKClcbiAgICAgIC5vcHRpb25hbCgpXG4gICAgICAuZGVzY3JpYmUoXCJFbnRyeSBwYXRoIGFwcGVuZGVkIHRvIHRoZSByb3V0ZSwgc3VjaCBhcyBpbmRleC5odG1sP21vZGU9MS5cIiksXG4gICAgc3RyaXBQcmVmaXg6IHpcbiAgICAgIC5ib29sZWFuKClcbiAgICAgIC5kZWZhdWx0KHRydWUpXG4gICAgICAuZGVzY3JpYmUoXG4gICAgICAgIFwiUmVtb3ZlIHRoZSByb3V0ZSBwcmVmaXggYmVmb3JlIGZvcndhcmRpbmcuIFNldCBmYWxzZSBvbmx5IHdoZW4gdGhlIHNlcnZlciBpcyBjb25maWd1cmVkIGZvciB0aGUgZnVsbCBTRVJWSUNFX1BBVEggYmFzZSBwYXRoLlwiLFxuICAgICAgKSxcbiAgICBwdWxsOiB6XG4gICAgICAuZW51bShbXCJtaXNzaW5nXCIsIFwiYWx3YXlzXCJdKVxuICAgICAgLmRlZmF1bHQoXCJtaXNzaW5nXCIpXG4gICAgICAuZGVzY3JpYmUoXCJQdWxsIHRoZSBpbWFnZSBvbmx5IHdoZW4gYWJzZW50LCBvciBhbHdheXMgYmVmb3JlIHN0YXJ0aW5nLlwiKSxcbiAgfSlcbiAgLnN0cmljdCgpXG4gIC5zdXBlclJlZmluZSgocmVxdWVzdCwgY29udGV4dCkgPT4ge1xuICAgIHJlamVjdENyZWRlbnRpYWxFbnZLZXlzKHJlcXVlc3QuZW52LCBjb250ZXh0KTtcbiAgICBmb3IgKGNvbnN0IG5hbWUgb2YgTEFLRUJPWF9SRVNFUlZFRF9TRVJWSUNFX0VOVikge1xuICAgICAgaWYgKG5hbWUgaW4gcmVxdWVzdC5lbnYpIHtcbiAgICAgICAgY29udGV4dC5hZGRJc3N1ZSh7XG4gICAgICAgICAgY29kZTogXCJjdXN0b21cIixcbiAgICAgICAgICBwYXRoOiBbXCJlbnZcIiwgbmFtZV0sXG4gICAgICAgICAgbWVzc2FnZTogYCR7bmFtZX0gaXMgaW5qZWN0ZWQgYnkgdGhlIExha2Vib3ggcnVudGltZSBhbmQgY2Fubm90IGJlIHNldC5gLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKExBS0VCT1hfQlVJTFRfSU5fU0VSVklDRVMuc29tZSgoc2VydmljZSkgPT4gc2VydmljZS5uYW1lID09PSByZXF1ZXN0Lm5hbWUpKSB7XG4gICAgICBjb250ZXh0LmFkZElzc3VlKHtcbiAgICAgICAgY29kZTogXCJjdXN0b21cIixcbiAgICAgICAgcGF0aDogW1wibmFtZVwiXSxcbiAgICAgICAgbWVzc2FnZTogYCR7cmVxdWVzdC5uYW1lfSBpcyBhIGJ1aWx0LWluIHNlcnZpY2UgbmFtZS5gLFxuICAgICAgfSk7XG4gICAgfVxuICB9KVxuICAuZGVzY3JpYmUoXG4gICAgXCJDcmVhdGUgb3IgcmVwbGFjZSBhIHVzZXIgc2VydmljZSB0aGF0IHJ1bnMgYW4gT0NJIGltYWdlIGRldGFjaGVkIHVuZGVyIHRoZSBMYWtlYm94IHJ1bnRpbWUuXCIsXG4gICk7XG5leHBvcnQgdHlwZSBDcmVhdGVMYWtlYm94U2VydmljZVJlcXVlc3QgPSB6LmlucHV0PHR5cGVvZiBjcmVhdGVMYWtlYm94U2VydmljZVJlcXVlc3RTY2hlbWE+O1xuZXhwb3J0IHR5cGUgTGFrZWJveFNlcnZpY2VEZWZpbml0aW9uID0gei5vdXRwdXQ8dHlwZW9mIGNyZWF0ZUxha2Vib3hTZXJ2aWNlUmVxdWVzdFNjaGVtYT47XG5cbmV4cG9ydCBjb25zdCBsYWtlYm94U2VydmljZUFjdGlvblNjaGVtYSA9IHpcbiAgLm9iamVjdCh7IG5hbWU6IGxha2Vib3hTZXJ2aWNlTmFtZVNjaGVtYSB9KVxuICAuc3RyaWN0KClcbiAgLmRlc2NyaWJlKFwiUmVxdWVzdCB0aGF0IHRhcmdldHMgb25lIG9mIHRoZSBjdXJyZW50IHVzZXIncyBzZXJ2aWNlcy5cIik7XG5leHBvcnQgdHlwZSBMYWtlYm94U2VydmljZUFjdGlvbiA9IHouaW5mZXI8dHlwZW9mIGxha2Vib3hTZXJ2aWNlQWN0aW9uU2NoZW1hPjtcblxuLyoqIERlZmF1bHQgbnVtYmVyIG9mIHNlcnZpY2UgbG9nIGxpbmVzIHJldHVybmVkIGJ5IGJvdW5kZWQgbG9nIHJlYWRzLiAqL1xuZXhwb3J0IGNvbnN0IExBS0VCT1hfTE9HX0RFRkFVTFRfTUFYX0xJTkVTID0gMjAwO1xuLyoqIERlZmF1bHQgc2VydmljZSBsb2cgY2hhcmFjdGVyIGNhcCByZXR1cm5lZCBieSBib3VuZGVkIGxvZyByZWFkcy4gKi9cbmV4cG9ydCBjb25zdCBMQUtFQk9YX0xPR19ERUZBVUxUX01BWF9DSEFSUyA9IDE2XzAwMDtcblxuZXhwb3J0IGNvbnN0IGxha2Vib3hTZXJ2aWNlTG9nc1JlcXVlc3RTY2hlbWEgPSBsYWtlYm94U2VydmljZUFjdGlvblNjaGVtYVxuICAuZXh0ZW5kKHtcbiAgICBtYXhMaW5lczogei5jb2VyY2VcbiAgICAgIC5udW1iZXIoKVxuICAgICAgLmludCgpXG4gICAgICAubWluKDEpXG4gICAgICAubWF4KDFfMDAwKVxuICAgICAgLmRlZmF1bHQoTEFLRUJPWF9MT0dfREVGQVVMVF9NQVhfTElORVMpXG4gICAgICAuZGVzY3JpYmUoXCJNYXhpbXVtIG51bWJlciBvZiB0cmFpbGluZyBsb2cgbGluZXMuXCIpLFxuICAgIG1heENoYXJzOiB6LmNvZXJjZVxuICAgICAgLm51bWJlcigpXG4gICAgICAuaW50KClcbiAgICAgIC5taW4oMSlcbiAgICAgIC5tYXgoNjRfMDAwKVxuICAgICAgLmRlZmF1bHQoTEFLRUJPWF9MT0dfREVGQVVMVF9NQVhfQ0hBUlMpXG4gICAgICAuZGVzY3JpYmUoXCJNYXhpbXVtIG51bWJlciBvZiB0cmFpbGluZyBsb2cgY2hhcmFjdGVycy5cIiksXG4gIH0pXG4gIC5zdHJpY3QoKVxuICAuZGVzY3JpYmUoXCJCb3VuZGVkIGxvZyByZXF1ZXN0IGZvciBvbmUgc2VydmljZS5cIik7XG5leHBvcnQgdHlwZSBMYWtlYm94U2VydmljZUxvZ3NSZXF1ZXN0ID0gei5pbnB1dDx0eXBlb2YgbGFrZWJveFNlcnZpY2VMb2dzUmVxdWVzdFNjaGVtYT47XG5cbmV4cG9ydCBjb25zdCBsYWtlYm94U2VydmljZUxvZ3NSZXNwb25zZVNjaGVtYSA9IHpcbiAgLm9iamVjdCh7IGxvZzogei5zdHJpbmcoKS5kZXNjcmliZShcIkJvdW5kZWQgdHJhaWxpbmcgc2VydmljZSBsb2csIGluY2x1ZGluZyBpbWFnZSBwdWxscy5cIikgfSlcbiAgLnN0cmljdCgpXG4gIC5kZXNjcmliZShcIkJvdW5kZWQgc2VydmljZSBsb2cgcmVzcG9uc2UuXCIpO1xuZXhwb3J0IHR5cGUgTGFrZWJveFNlcnZpY2VMb2dzUmVzcG9uc2UgPSB6LmluZmVyPHR5cGVvZiBsYWtlYm94U2VydmljZUxvZ3NSZXNwb25zZVNjaGVtYT47XG5cbmV4cG9ydCBjb25zdCBsYWtlYm94U2VydmljZXNSZXNwb25zZVNjaGVtYSA9IHpcbiAgLm9iamVjdCh7IHNlcnZpY2VzOiB6LmFycmF5KGxha2Vib3hTZXJ2aWNlU2NoZW1hKS5kZXNjcmliZShcIlRoZSBjdXJyZW50IHVzZXIncyBzZXJ2aWNlcy5cIikgfSlcbiAgLnN0cmljdCgpXG4gIC5kZXNjcmliZShcIlNlcnZpY2UgbGlzdGluZyByZXNwb25zZS5cIik7XG5leHBvcnQgdHlwZSBMYWtlYm94U2VydmljZXNSZXNwb25zZSA9IHouaW5mZXI8dHlwZW9mIGxha2Vib3hTZXJ2aWNlc1Jlc3BvbnNlU2NoZW1hPjtcblxuZXhwb3J0IGNvbnN0IGxha2Vib3hTZXJ2aWNlUmVzcG9uc2VTY2hlbWEgPSB6XG4gIC5vYmplY3QoeyBzZXJ2aWNlOiBsYWtlYm94U2VydmljZVNjaGVtYSB9KVxuICAuc3RyaWN0KClcbiAgLmRlc2NyaWJlKFwiU2luZ2xlIHNlcnZpY2UgcmVzcG9uc2UuXCIpO1xuZXhwb3J0IHR5cGUgTGFrZWJveFNlcnZpY2VSZXNwb25zZSA9IHouaW5mZXI8dHlwZW9mIGxha2Vib3hTZXJ2aWNlUmVzcG9uc2VTY2hlbWE+O1xuXG5leHBvcnQgY29uc3QgcmVtb3ZlTGFrZWJveFNlcnZpY2VSZXNwb25zZVNjaGVtYSA9IHpcbiAgLm9iamVjdCh7IHJlbW92ZWQ6IHouYm9vbGVhbigpLmRlc2NyaWJlKFwiV2hldGhlciBhIHNhdmVkIHNlcnZpY2Ugd2FzIHJlbW92ZWQuXCIpIH0pXG4gIC5zdHJpY3QoKVxuICAuZGVzY3JpYmUoXCJTZXJ2aWNlIHJlbW92YWwgcmVzcG9uc2UuXCIpO1xuZXhwb3J0IHR5cGUgUmVtb3ZlTGFrZWJveFNlcnZpY2VSZXNwb25zZSA9IHouaW5mZXI8dHlwZW9mIHJlbW92ZUxha2Vib3hTZXJ2aWNlUmVzcG9uc2VTY2hlbWE+O1xuXG5leHBvcnQgY29uc3QgbGFrZWJveE1ldHJpY3NTbmFwc2hvdFNjaGVtYSA9IHpcbiAgLm9iamVjdCh7XG4gICAgYXQ6IHouc3RyaW5nKCkuZGF0ZXRpbWUoKS5kZXNjcmliZShcIlNhbXBsZSB0aW1lLlwiKSxcbiAgICBjcHU6IHpcbiAgICAgIC5vYmplY3Qoe1xuICAgICAgICBjb3Jlczogei5udW1iZXIoKS5pbnQoKS5wb3NpdGl2ZSgpLmRlc2NyaWJlKFwiT25saW5lIENQVSBjb3VudC5cIiksXG4gICAgICAgIHVzZWRQZXJjZW50OiB6XG4gICAgICAgICAgLm51bWJlcigpXG4gICAgICAgICAgLm1pbigwKVxuICAgICAgICAgIC5tYXgoMTAwKVxuICAgICAgICAgIC5kZXNjcmliZShcIkNQVSBidXN5IHBlcmNlbnRhZ2Ugc2luY2UgdGhlIGxhc3Qgc2FtcGxlLlwiKSxcbiAgICAgICAgbG9hZDE6IHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKS5kZXNjcmliZShcIk9uZS1taW51dGUgbG9hZCBhdmVyYWdlLlwiKSxcbiAgICAgIH0pXG4gICAgICAuc3RyaWN0KClcbiAgICAgIC5kZXNjcmliZShcIkNQVSB1c2FnZS5cIiksXG4gICAgbWVtb3J5OiB6XG4gICAgICAub2JqZWN0KHtcbiAgICAgICAgdG90YWxCeXRlczogei5udW1iZXIoKS5ub25uZWdhdGl2ZSgpLmRlc2NyaWJlKFwiVG90YWwgbWVtb3J5LlwiKSxcbiAgICAgICAgdXNlZEJ5dGVzOiB6Lm51bWJlcigpLm5vbm5lZ2F0aXZlKCkuZGVzY3JpYmUoXCJNZW1vcnkgaW4gdXNlLCBleGNsdWRpbmcgcmVjbGFpbWFibGUgY2FjaGUuXCIpLFxuICAgICAgfSlcbiAgICAgIC5zdHJpY3QoKVxuICAgICAgLmRlc2NyaWJlKFwiTWVtb3J5IHVzYWdlLlwiKSxcbiAgICBzdG9yYWdlOiB6XG4gICAgICAub2JqZWN0KHtcbiAgICAgICAgdG90YWxCeXRlczogei5udW1iZXIoKS5ub25uZWdhdGl2ZSgpLmRlc2NyaWJlKFwiUGVyc2lzdGVudCBob21lIHZvbHVtZSBzaXplLlwiKSxcbiAgICAgICAgdXNlZEJ5dGVzOiB6Lm51bWJlcigpLm5vbm5lZ2F0aXZlKCkuZGVzY3JpYmUoXCJQZXJzaXN0ZW50IGhvbWUgdm9sdW1lIHVzYWdlLlwiKSxcbiAgICAgIH0pXG4gICAgICAuc3RyaWN0KClcbiAgICAgIC5kZXNjcmliZShcIlBlcnNpc3RlbnQgc3RvcmFnZSB1c2FnZS5cIiksXG4gICAgbmV0d29yazogelxuICAgICAgLm9iamVjdCh7XG4gICAgICAgIHJ4Qnl0ZXNQZXJTZWNvbmQ6IHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKS5kZXNjcmliZShcIkluYm91bmQgbmV0d29yayB0aHJvdWdocHV0LlwiKSxcbiAgICAgICAgdHhCeXRlc1BlclNlY29uZDogei5udW1iZXIoKS5ub25uZWdhdGl2ZSgpLmRlc2NyaWJlKFwiT3V0Ym91bmQgbmV0d29yayB0aHJvdWdocHV0LlwiKSxcbiAgICAgIH0pXG4gICAgICAuc3RyaWN0KClcbiAgICAgIC5kZXNjcmliZShcIk5ldHdvcmsgdGhyb3VnaHB1dCBvbiB0aGUgcHJpbWFyeSBpbnRlcmZhY2UuXCIpLFxuICB9KVxuICAuc3RyaWN0KClcbiAgLmRlc2NyaWJlKFwiTWFjaGluZS1sZXZlbCBMYWtlYm94IHJlc291cmNlIHNhbXBsZS4gTmV2ZXIgaW5jbHVkZXMgcHJvY2VzcyBpbmZvcm1hdGlvbi5cIik7XG5leHBvcnQgdHlwZSBMYWtlYm94TWV0cmljc1NuYXBzaG90ID0gei5pbmZlcjx0eXBlb2YgbGFrZWJveE1ldHJpY3NTbmFwc2hvdFNjaGVtYT47XG5cbmV4cG9ydCBjb25zdCBsYWtlYm94TWV0cmljc1Jlc3BvbnNlU2NoZW1hID0gelxuICAub2JqZWN0KHtcbiAgICBzdGF0dXM6IGxha2Vib3hTdGF0dXNTY2hlbWEsXG4gICAgc2VyaWVzOiB6XG4gICAgICAuYXJyYXkobGFrZWJveE1ldHJpY3NTbmFwc2hvdFNjaGVtYSlcbiAgICAgIC5kZXNjcmliZShcIlJlY2VudCBzYW1wbGVzLCBvbGRlc3QgZmlyc3QuIEVtcHR5IHdoaWxlIHRoZSBMYWtlYm94IGlzIG5vdCBydW5uaW5nLlwiKSxcbiAgfSlcbiAgLnN0cmljdCgpXG4gIC5kZXNjcmliZShcIkxha2Vib3ggbWV0cmljcyByZXNwb25zZS5cIik7XG5leHBvcnQgdHlwZSBMYWtlYm94TWV0cmljc1Jlc3BvbnNlID0gei5pbmZlcjx0eXBlb2YgbGFrZWJveE1ldHJpY3NSZXNwb25zZVNjaGVtYT47XG5cbmNvbnN0IHJlYWRUb29sID0geyBhcHBraXRUb29sOiB7IGFnZW50VG9vbDogdHJ1ZSwgZWZmZWN0OiBcInJlYWRcIiwgcmVxdWlyZXNVc2VyQ29udGV4dDogdHJ1ZSB9IH07XG5jb25zdCB3cml0ZVRvb2wgPSB7IGFwcGtpdFRvb2w6IHsgYWdlbnRUb29sOiB0cnVlLCBlZmZlY3Q6IFwid3JpdGVcIiwgcmVxdWlyZXNVc2VyQ29udGV4dDogdHJ1ZSB9IH07XG5cbmV4cG9ydCBjb25zdCBnZXRMYWtlYm94T3BlcmF0aW9uU2NoZW1hID0gelxuICAub2JqZWN0KHt9KVxuICAuc3RyaWN0KClcbiAgLmRlc2NyaWJlKFxuICAgIFwiUmV0dXJuIHRoZSBhcHAgTGFrZWJveCBzdGF0dXMsIHRoZSBjdXJyZW50IHVzZXIncyBMYWtlYm94IGFjY291bnQsIGFuZCB0aGF0IHVzZXIncyBzZXJ2aWNlcy4gVGhpcyBuZXZlciBjcmVhdGVzIHRoZSBMYWtlYm94LlwiLFxuICApXG4gIC5tZXRhKHJlYWRUb29sKTtcblxuZXhwb3J0IGNvbnN0IGV4ZWN1dGVMYWtlYm94Q29tbWFuZE9wZXJhdGlvblNjaGVtYSA9IGxha2Vib3hDb21tYW5kUmVxdWVzdFNjaGVtYVxuICAuZGVzY3JpYmUoXG4gICAgXCJSdW4gYSBjb21tYW5kIG9uIHRoZSBMYWtlYm94IGhvc3QgYXMgdGhlIGN1cnJlbnQgdXNlcidzIGxvY2tlZCwgbm9uLXN1ZG8gYWNjb3VudCwgc3RhcnRpbmcgdGhlIExha2Vib3ggd2hlbiBuZWVkZWQuIFVzZSBzZXJ2aWNlcywgbm90IGJhY2tncm91bmQgY29tbWFuZHMsIGZvciBsb25nLXJ1bm5pbmcgc2VydmVycy5cIixcbiAgKVxuICAubWV0YSh3cml0ZVRvb2wpO1xuXG5leHBvcnQgY29uc3QgbGlzdExha2Vib3hTZXJ2aWNlc09wZXJhdGlvblNjaGVtYSA9IHpcbiAgLm9iamVjdCh7fSlcbiAgLnN0cmljdCgpXG4gIC5kZXNjcmliZShcIkxpc3QgdGhlIGN1cnJlbnQgdXNlcidzIHNlcnZpY2VzIHdpdGggc3RhdGUsIHBvcnQsIGFuZCByb3V0ZS4gTG9ncyBhcmUgb21pdHRlZC5cIilcbiAgLm1ldGEocmVhZFRvb2wpO1xuXG5leHBvcnQgY29uc3QgY3JlYXRlTGFrZWJveFNlcnZpY2VPcGVyYXRpb25TY2hlbWEgPSBjcmVhdGVMYWtlYm94U2VydmljZVJlcXVlc3RTY2hlbWFcbiAgLmRlc2NyaWJlKFxuICAgIFwiQ3JlYXRlIG9yIHJlcGxhY2UgYSB1c2VyIHNlcnZpY2UgZnJvbSBhbiBPQ0kgaW1hZ2UsIHN0YXJ0IGl0IGRldGFjaGVkLCBhbmQgd2FpdCB1bnRpbCBpdCBpcyByZWFkeSBvciBmYWlsZWQuIFRoaXMgaXMgYSBjb25zdHJhaW5lZCBjb250YWluZXIgQVBJLCBub3QgdGhlIERvY2tlciBDTEk6IHRoZXJlIGlzIG5vIGRhZW1vbiwgcG9ydCBwdWJsaXNoaW5nLCBwcml2aWxlZ2VkIG1vZGUsIG9yIGRldmljZSBhY2Nlc3MuIFJvdXRlZCBzZXJ2aWNlcyBsaXN0ZW4gb24gMTI3LjAuMC4xOiRTRVJWSUNFX1BPUlQgYW5kIGFyZSByZWFjaGVkIGF0IHRoZSByZXR1cm5lZCBvcGVuVXJsLiBTZXJ2aWNlcyByZXN0YXJ0IGZyb20gdGhlaXIgc2F2ZWQgZGVmaW5pdGlvbiB3aGVuIHRoZSBMYWtlYm94IHN0YXJ0czsgcHJvY2VzcyBtZW1vcnkgaXMgbm90IHJlc3VtZWQuXCIsXG4gIClcbiAgLm1ldGEod3JpdGVUb29sKTtcblxuZXhwb3J0IGNvbnN0IHN0YXJ0TGFrZWJveFNlcnZpY2VPcGVyYXRpb25TY2hlbWEgPSBsYWtlYm94U2VydmljZUFjdGlvblNjaGVtYVxuICAuZGVzY3JpYmUoXG4gICAgXCJTdGFydCBhIHNhdmVkIHNlcnZpY2Ugb3IgYSBidWlsdC1pbiB0ZXJtaW5hbCBvciBkZXNrdG9wIGFuZCB3YWl0IHVudGlsIGl0IGlzIHJlYWR5IG9yIGZhaWxlZC5cIixcbiAgKVxuICAubWV0YSh7IGFwcGtpdFRvb2w6IHsgLi4ud3JpdGVUb29sLmFwcGtpdFRvb2wsIGlkZW1wb3RlbnQ6IHRydWUgfSB9KTtcblxuZXhwb3J0IGNvbnN0IHN0b3BMYWtlYm94U2VydmljZU9wZXJhdGlvblNjaGVtYSA9IGxha2Vib3hTZXJ2aWNlQWN0aW9uU2NoZW1hXG4gIC5kZXNjcmliZShcIlN0b3Agb25lIHJ1bm5pbmcgc2VydmljZSB3aXRob3V0IHJlbW92aW5nIGl0cyBkZWZpbml0aW9uLlwiKVxuICAubWV0YSh7IGFwcGtpdFRvb2w6IHsgLi4ud3JpdGVUb29sLmFwcGtpdFRvb2wsIGlkZW1wb3RlbnQ6IHRydWUgfSB9KTtcblxuZXhwb3J0IGNvbnN0IHJlbW92ZUxha2Vib3hTZXJ2aWNlT3BlcmF0aW9uU2NoZW1hID0gbGFrZWJveFNlcnZpY2VBY3Rpb25TY2hlbWFcbiAgLmRlc2NyaWJlKFxuICAgIFwiU3RvcCBhbmQgZGVsZXRlIG9uZSBzYXZlZCBzZXJ2aWNlIGRlZmluaXRpb24gYW5kIGl0cyBpbWFnZSByb290IGZpbGVzeXN0ZW0uIE1vdW50ZWQgaG9tZSBkaXJlY3RvcmllcyBhcmUgcHJlc2VydmVkLlwiLFxuICApXG4gIC5tZXRhKHtcbiAgICBhcHBraXRUb29sOiB7XG4gICAgICBhZ2VudFRvb2w6IHRydWUsXG4gICAgICBlZmZlY3Q6IFwiZGVzdHJ1Y3RpdmVcIixcbiAgICAgIGFwcHJvdmFsOiB0cnVlLFxuICAgICAgcmVxdWlyZXNVc2VyQ29udGV4dDogdHJ1ZSxcbiAgICB9LFxuICB9KTtcblxuZXhwb3J0IGNvbnN0IGdldExha2Vib3hTZXJ2aWNlTG9nc09wZXJhdGlvblNjaGVtYSA9IGxha2Vib3hTZXJ2aWNlTG9nc1JlcXVlc3RTY2hlbWFcbiAgLmRlc2NyaWJlKFwiUmVhZCBhIGJvdW5kZWQgdGFpbCBvZiBvbmUgc2VydmljZSBsb2csIGluY2x1ZGluZyBpbWFnZSBwdWxsIGFuZCByZWFkaW5lc3Mgb3V0cHV0LlwiKVxuICAubWV0YShyZWFkVG9vbCk7XG5cbmZ1bmN0aW9uIHJlamVjdENyZWRlbnRpYWxFbnZLZXlzKFxuICBlbnY6IFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIHN0cmluZz4+IHwgdW5kZWZpbmVkLFxuICBjb250ZXh0OiB6LlJlZmluZW1lbnRDdHgsXG4pOiB2b2lkIHtcbiAgZm9yIChjb25zdCBuYW1lIG9mIE9iamVjdC5rZXlzKGVudiA/PyB7fSkpIHtcbiAgICBpZiAobmFtZS5zdGFydHNXaXRoKFwiREFUQUJSSUNLU19cIikgfHwgbmFtZSA9PT0gXCJTU0hfQVVUSF9TT0NLXCIpIHtcbiAgICAgIGNvbnRleHQuYWRkSXNzdWUoe1xuICAgICAgICBjb2RlOiBcImN1c3RvbVwiLFxuICAgICAgICBwYXRoOiBbXCJlbnZcIiwgbmFtZV0sXG4gICAgICAgIG1lc3NhZ2U6XG4gICAgICAgICAgXCJFbnZpcm9ubWVudCBvdmVybGF5cyBjYW5ub3QgcmVzdG9yZSBEYXRhYnJpY2tzIG9yIFNTSCBhZ2VudCBjcmVkZW50aWFsczsgdXNlIGEgZGVkaWNhdGVkIGFwcC1tZWRpYXRlZCBjYXBhYmlsaXR5LlwiLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG59XG4iXX0=
@@ -0,0 +1 @@
1
+ {"root":["../src/client.ts","../src/schemas.ts","../index.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -1,6 +1,86 @@
1
1
  {
2
2
  "name": "@dbx-tools/shared-lakebox",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "description": "Browser-safe contracts for the app Lakebox, user services, commands, metrics, and routes",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/reggie-db/dbx-tools.git",
7
+ "directory": "packages/js/shared/lakebox"
8
+ },
9
+ "scripts": {
10
+ "build": "projen build",
11
+ "compile": "projen compile",
12
+ "default": "projen default",
13
+ "package": "projen package",
14
+ "post-compile": "projen post-compile",
15
+ "pre-compile": "projen pre-compile",
16
+ "prepack": "projen prepack",
17
+ "test": "projen test",
18
+ "watch": "projen watch",
19
+ "projen": "projen"
20
+ },
21
+ "devDependencies": {
22
+ "typescript": "^5.9.3"
23
+ },
24
+ "dependencies": {
25
+ "zod": "4.3.6"
26
+ },
27
+ "main": "./lib/index.js",
28
+ "license": "Apache-2.0",
29
+ "publishConfig": {
30
+ "access": "public",
31
+ "main": "./lib/index.js",
32
+ "types": "./lib/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./lib/index.d.ts",
36
+ "default": "./lib/index.js"
37
+ },
38
+ "./client": {
39
+ "types": "./lib/src/client.d.ts",
40
+ "default": "./lib/src/client.js"
41
+ },
42
+ "./schemas": {
43
+ "types": "./lib/src/schemas.d.ts",
44
+ "default": "./lib/src/schemas.js"
45
+ },
46
+ "./*": {
47
+ "types": "./lib/src/*/index.d.ts",
48
+ "default": "./lib/src/*/index.js"
49
+ },
50
+ "./package.json": "./package.json"
51
+ }
52
+ },
53
+ "version": "0.9.132",
54
+ "types": "./lib/index.d.ts",
55
+ "dbxToolsConfig": {
56
+ "tags": [
57
+ "shared"
58
+ ]
59
+ },
60
+ "type": "module",
61
+ "exports": {
62
+ ".": {
63
+ "types": "./lib/index.d.ts",
64
+ "default": "./lib/index.js"
65
+ },
66
+ "./client": {
67
+ "types": "./lib/src/client.d.ts",
68
+ "default": "./lib/src/client.js"
69
+ },
70
+ "./schemas": {
71
+ "types": "./lib/src/schemas.d.ts",
72
+ "default": "./lib/src/schemas.js"
73
+ },
74
+ "./*": {
75
+ "types": "./lib/src/*/index.d.ts",
76
+ "default": "./lib/src/*/index.js"
77
+ },
78
+ "./package.json": "./package.json"
79
+ },
80
+ "files": [
81
+ "index.ts",
82
+ "src",
83
+ "lib"
84
+ ],
85
+ "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"bunx projen\"."
86
+ }
package/src/client.ts ADDED
@@ -0,0 +1,64 @@
1
+ import { z } from "zod";
2
+
3
+ /** AppKit plugin name used to publish and read the Lakebox browser client config. */
4
+ export const LAKEBOX_PLUGIN_NAME = "lakebox";
5
+
6
+ /** Default AppKit mount path for the Lakebox plugin API. */
7
+ export const LAKEBOX_DEFAULT_BASE_PATH = `/api/${LAKEBOX_PLUGIN_NAME}`;
8
+
9
+ /** Default AppKit root path for user-scoped Lakebox service routes. */
10
+ export const LAKEBOX_DEFAULT_ROUTE_PREFIX = "/lakebox";
11
+
12
+ /** Shared server route templates owned by the Lakebox plugin contract. */
13
+ export const LAKEBOX_ROUTES = {
14
+ status: "/status",
15
+ start: "/start",
16
+ stop: "/stop",
17
+ commands: "/commands",
18
+ services: "/services",
19
+ service: "/services/:name",
20
+ serviceStart: "/services/:name/start",
21
+ serviceStop: "/services/:name/stop",
22
+ serviceLogs: "/services/:name/logs",
23
+ metrics: "/metrics",
24
+ metricsStream: "/metrics/stream",
25
+ } as const;
26
+
27
+ /** Browser-safe configuration published by the Lakebox AppKit plugin. */
28
+ export const LakeboxClientConfigSchema = z
29
+ .object({
30
+ basePath: z
31
+ .string()
32
+ .startsWith("/")
33
+ .default(LAKEBOX_DEFAULT_BASE_PATH)
34
+ .describe("AppKit mount path for Lakebox API routes."),
35
+ routePrefix: z
36
+ .string()
37
+ .startsWith("/")
38
+ .default(LAKEBOX_DEFAULT_ROUTE_PREFIX)
39
+ .describe("AppKit root path beneath which each user's services are routed."),
40
+ })
41
+ .strict()
42
+ .describe("Lakebox plugin browser client configuration.");
43
+ export type LakeboxClientConfig = z.infer<typeof LakeboxClientConfigSchema>;
44
+ export type LakeboxClientConfigInput = z.input<typeof LakeboxClientConfigSchema>;
45
+
46
+ /** Replace named route parameters with encoded browser-safe values. */
47
+ export const lakeboxRoute = (
48
+ template: string,
49
+ parameters: Readonly<Record<string, string>> = {},
50
+ ): string =>
51
+ Object.entries(parameters).reduce(
52
+ (route, [name, value]) => route.replace(`:${name}`, encodeURIComponent(value)),
53
+ template,
54
+ );
55
+
56
+ /**
57
+ * Returns the AppKit route for one user's service.
58
+ *
59
+ * The user hash is the only routing key: the server derives the service port
60
+ * from the same hash and service name, so no path or port mapping is stored.
61
+ */
62
+ export function lakeboxServicePath(routePrefix: string, userHash: string, name: string): string {
63
+ return `${routePrefix.replace(/\/+$/, "")}/${userHash}/${name}`;
64
+ }