@dbx-tools/cli-model-proxy 0.3.44 → 0.4.0

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,515 @@
1
+ /**
2
+ * OpenAI-compatible HTTP proxy in front of Databricks Model Serving.
3
+ *
4
+ * Databricks serving endpoints speak OpenAI wire formats, so this server is a
5
+ * thin pass-through: it resolves the request's (possibly fuzzy) `model` to a
6
+ * real endpoint id via the {@link DatabricksBackend}, stamps a fresh auth
7
+ * header, and forwards to the right Databricks URL:
8
+ *
9
+ * - Chat Completions → `/serving-endpoints/<name>/invocations`, except for
10
+ * Responses-only models (Codex) which are translated and sent to
11
+ * `/serving-endpoints/responses`.
12
+ * - Responses → native `/serving-endpoints/responses` (OpenAI-family) or
13
+ * `/serving-endpoints/open-responses` (Claude/Gemini/…), body forwarded
14
+ * as-is. No chat round-trip.
15
+ *
16
+ * Any OpenAI-compatible tool (iTerm, editors, the `openai` SDK, Codex CLI) can
17
+ * point its base URL at this server and use loose model names.
18
+ *
19
+ * Routes:
20
+ * - `GET /health`, `GET /` liveness
21
+ * - `GET /v1/models`, `GET /models` list resolvable endpoints. Emits the
22
+ * OpenAI `{object:"list",data:[…]}` shape by default; when the request
23
+ * looks like the Codex CLI (a `client_version` query param, which Codex
24
+ * always sends) it emits Codex's `{models:[{slug,…}]}` shape instead, so
25
+ * both standard OpenAI clients and Codex can enumerate the catalogue.
26
+ * - `POST /v1/chat/completions` proxy (also `/completions`,
27
+ * `/v1/completions`, `/v1/embeddings`, and the un-prefixed variants)
28
+ * - `POST /v1/responses` OpenAI Responses API, forwarded to
29
+ * Databricks' native Responses / Open Responses surface.
30
+ *
31
+ * @module
32
+ */
33
+ import { createServer } from "node:http";
34
+ import { async as asyncUtil, error, json, log } from "@dbx-tools/shared-core";
35
+ import { classify, openaiChat, openaiResponses } from "@dbx-tools/shared-model";
36
+ import { Agent } from "undici";
37
+ import { DEFAULT_BIND_HOST, DEFAULT_PORT, DEFAULT_RETRY } from "./defaults.js";
38
+ const { chatToResponsesRequest, responseToChatCompletion, sanitizeOpenResponsesRequest } = openaiResponses;
39
+ const logger = log.logger("model-proxy/server");
40
+ /**
41
+ * Dispatcher for every upstream call, with undici's inactivity timeouts
42
+ * DISABLED (`0`).
43
+ *
44
+ * A proxied turn is only as fast as the model behind it, and undici's
45
+ * defaults (300s `headersTimeout`, 300s `bodyTimeout`) are both wrong here.
46
+ * `bodyTimeout` is the killer: it measures the gap BETWEEN chunks, so a model
47
+ * that thinks for a while mid-stream - extended reasoning, a long tool round
48
+ * trip, a slow Genie/SQL step - trips it and undici tears the socket down
49
+ * with `UND_ERR_BODY_TIMEOUT`, which the client sees as a truncated stream.
50
+ *
51
+ * The proxy has no opinion on how long a model may take, so it imposes no
52
+ * deadline: the stream ends when the upstream ends it, or when the client
53
+ * hangs up (see {@link requestAbortSignal}). Callers that DO want a deadline
54
+ * should send one, the same as they would to OpenAI.
55
+ */
56
+ const upstreamDispatcher = new Agent({ headersTimeout: 0, bodyTimeout: 0 });
57
+ /** POST routes forwarded to a serving endpoint (chat or Responses-only). */
58
+ const PROXY_PATHS = new Set([
59
+ "/v1/chat/completions",
60
+ "/chat/completions",
61
+ "/v1/completions",
62
+ "/completions",
63
+ "/v1/embeddings",
64
+ "/embeddings",
65
+ ]);
66
+ /** GET routes that list the resolvable model catalogue. */
67
+ const MODELS_PATHS = new Set(["/v1/models", "/models"]);
68
+ /** POST routes that carry an OpenAI Responses API body (native passthrough). */
69
+ const RESPONSES_PATHS = new Set(["/v1/responses", "/responses"]);
70
+ /**
71
+ * Extra request fields to strip before forwarding, on top of
72
+ * `openaiChat.UNSUPPORTED_CHAT_FIELDS`. Comma-separated in `PROXY_DROP_FIELDS`.
73
+ *
74
+ * An escape hatch: when a workspace or a new client version trips a field
75
+ * Databricks rejects, an operator can unblock themselves immediately instead of
76
+ * waiting on a release of this package.
77
+ */
78
+ function extraDropFields() {
79
+ return (process.env.PROXY_DROP_FIELDS ?? "")
80
+ .split(",")
81
+ .map((field) => field.trim())
82
+ .filter((field) => field.length > 0);
83
+ }
84
+ /** Build (but do not start) the proxy HTTP server. */
85
+ export function createProxyServer(backend, options = {}) {
86
+ const server = createServer((req, res) => {
87
+ void handleRequest(backend, options, req, res);
88
+ });
89
+ // Match the upstream policy on the INBOUND side: never cut a client off
90
+ // mid-turn. Node's defaults (300s `requestTimeout`, 60s `headersTimeout`)
91
+ // are sized for ordinary web traffic, not for holding a streamed model
92
+ // response open, and a client that hits one gets a dead socket rather than
93
+ // an error it can act on. `0` disables each; the turn now ends when the
94
+ // model is done or the client disconnects.
95
+ server.requestTimeout = 0;
96
+ server.headersTimeout = 0;
97
+ server.timeout = 0;
98
+ return server;
99
+ }
100
+ /**
101
+ * Signal that aborts when the client hangs up.
102
+ *
103
+ * Removing the timeouts means nothing else will ever end a forgotten request,
104
+ * so the client's own disconnect becomes the only backstop against an upstream
105
+ * call running on with no one to receive it. Passing this to `fetch` is what
106
+ * makes a cancelled turn (Ctrl-C, a closed tab, a killed CLI) release the
107
+ * Databricks-side stream instead of leaking it for the life of the process.
108
+ *
109
+ * Keyed off the RESPONSE, not the request: `IncomingMessage` emits `close` as
110
+ * soon as its body has been fully consumed, which on every POST here happens
111
+ * before the upstream call is even made - watching that would abort each turn
112
+ * instantly. `ServerResponse` emits `close` when the response finishes or the
113
+ * connection drops, so the `writableFinished` check separates "client left"
114
+ * from "we replied".
115
+ */
116
+ function clientAbortSignal(res) {
117
+ const controller = new AbortController();
118
+ res.once("close", () => {
119
+ if (!res.writableFinished)
120
+ controller.abort();
121
+ });
122
+ return controller.signal;
123
+ }
124
+ /**
125
+ * POST a JSON body to a serving endpoint on the no-timeout
126
+ * {@link upstreamDispatcher}, cancelled via `signal`.
127
+ *
128
+ * Every upstream call goes through here so the timeout and cancellation policy
129
+ * is stated once. `dispatcher` is an undici extension that the DOM
130
+ * `RequestInit` Node compiles against does not declare, hence the local
131
+ * intersection type rather than a cast at each call site.
132
+ */
133
+ async function upstreamFetch(url, headers, body, signal) {
134
+ const init = { method: "POST", headers, body, signal };
135
+ // `dispatcher` is an undici extension the DOM `RequestInit` doesn't declare,
136
+ // and it can't simply be typed on: `@types/node` pins its own `undici-types`
137
+ // copy, so the `Agent` from our `undici` dependency is a structurally
138
+ // identical but nominally different type than the one the global `fetch`
139
+ // signature expects. Attaching it structurally sidesteps a version skew that
140
+ // no cast expresses cleanly, and `fetch` reads it at runtime all the same.
141
+ Reflect.set(init, "dispatcher", upstreamDispatcher);
142
+ return fetch(url, init);
143
+ }
144
+ /**
145
+ * Delay (ms) a `429` response asks us to wait, from its `Retry-After` header,
146
+ * or `undefined` when absent/unparseable. Handles both header forms: an integer
147
+ * count of seconds, and an HTTP date to wait until (clamped to `>= 0`).
148
+ */
149
+ export function parseRetryAfterMs(header, nowMs) {
150
+ if (!header)
151
+ return undefined;
152
+ const trimmed = header.trim();
153
+ if (/^\d+$/.test(trimmed))
154
+ return Number(trimmed) * 1000;
155
+ const when = Date.parse(trimmed);
156
+ if (Number.isNaN(when))
157
+ return undefined;
158
+ return Math.max(0, when - nowMs);
159
+ }
160
+ /**
161
+ * Backoff (ms) before retry `attempt` (0-based): exponential from
162
+ * `baseDelayMs`, capped at `maxDelayMs`, with up to +50% jitter so concurrent
163
+ * retries from one agent don't resynchronize into the next burst. A server-sent
164
+ * `Retry-After` wins outright (still capped), since the server knows better
165
+ * than our schedule when it will accept traffic again.
166
+ */
167
+ export function backoffDelayMs(attempt, retry, retryAfterMs, jitter) {
168
+ if (retryAfterMs !== undefined)
169
+ return Math.min(retryAfterMs, retry.maxDelayMs);
170
+ const exponential = retry.baseDelayMs * 2 ** attempt;
171
+ const capped = Math.min(exponential, retry.maxDelayMs);
172
+ return Math.round(capped * (1 + jitter * 0.5));
173
+ }
174
+ /**
175
+ * {@link upstreamFetch} with in-proxy `429` handling. When `retry.enabled`, a
176
+ * 429 is retried up to `retry.maxRetries` times with {@link backoffDelayMs}
177
+ * backoff instead of being surfaced; the throttled response body is drained
178
+ * each time so the connection is released. The retry happens BEFORE the caller
179
+ * writes any status line, so it is transparent to both streaming and
180
+ * non-streaming paths - the client only ever sees the final response.
181
+ *
182
+ * Bails early (returning the 429) when retries are exhausted, when the client
183
+ * has hung up (`signal.aborted`), or when the response carries no `Retry-After`
184
+ * and we would otherwise loop blind past the cap.
185
+ */
186
+ async function upstreamFetchRetrying(backend, url, headers, body, res, retry) {
187
+ const signal = clientAbortSignal(res);
188
+ const payload = JSON.stringify(body);
189
+ let response = await upstreamFetch(url, headers, payload, signal);
190
+ if (!retry.enabled)
191
+ return response;
192
+ for (let attempt = 0; response.status === 429 && attempt < retry.maxRetries; attempt++) {
193
+ const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"), Date.now());
194
+ const delayMs = backoffDelayMs(attempt, retry, retryAfterMs, jitterFraction());
195
+ // Release the throttled response's socket before waiting; its body is an
196
+ // error payload we are choosing not to relay.
197
+ await response.body?.cancel().catch(() => { });
198
+ logger.warn("upstream 429; backing off", {
199
+ attempt: attempt + 1,
200
+ maxRetries: retry.maxRetries,
201
+ delayMs,
202
+ ...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
203
+ });
204
+ try {
205
+ await asyncUtil.sleep(delayMs, signal);
206
+ }
207
+ catch {
208
+ // Client hung up mid-wait: return the last 429 rather than issue a
209
+ // request no one is listening for.
210
+ return response;
211
+ }
212
+ // Fresh auth header per attempt so a long backoff can't outlive the token.
213
+ const retryHeaders = { ...(await backend.authHeaders()), ...headers };
214
+ response = await upstreamFetch(url, retryHeaders, payload, signal);
215
+ }
216
+ return response;
217
+ }
218
+ /**
219
+ * Jitter fraction in `[0, 1)`. Split out so tests can stub determinism;
220
+ * `Math.random` is fine for spreading retry timing.
221
+ */
222
+ function jitterFraction() {
223
+ return Math.random();
224
+ }
225
+ /**
226
+ * Build and start the proxy, resolving once it is accepting connections.
227
+ * Returns the server and its base URL (with the actually-bound port, so a
228
+ * `port: 0` request surfaces the OS-assigned port).
229
+ */
230
+ export async function startProxyServer(backend, options = {}) {
231
+ const host = options.host ?? DEFAULT_BIND_HOST;
232
+ const port = options.port ?? DEFAULT_PORT;
233
+ const server = createProxyServer(backend, options);
234
+ await new Promise((resolve, reject) => {
235
+ const onError = (err) => reject(err);
236
+ server.once("error", onError);
237
+ server.listen(port, host, () => {
238
+ server.off("error", onError);
239
+ resolve();
240
+ });
241
+ });
242
+ const address = server.address();
243
+ const boundPort = typeof address === "object" && address ? address.port : port;
244
+ return { server, url: `http://${host}:${boundPort}` };
245
+ }
246
+ async function handleRequest(backend, options, req, res) {
247
+ const rawUrl = req.url ?? "/";
248
+ const [path, query = ""] = rawUrl.split("?");
249
+ const routePath = path ?? "/";
250
+ try {
251
+ if (req.method === "GET" && (routePath === "/health" || routePath === "/")) {
252
+ sendJson(res, 200, { status: "ok" });
253
+ return;
254
+ }
255
+ if (options.apiKey && !isAuthorized(req, options.apiKey)) {
256
+ sendJson(res, 401, errorBody("invalid api key", "invalid_request_error"));
257
+ return;
258
+ }
259
+ if (req.method === "GET" && MODELS_PATHS.has(routePath)) {
260
+ // Codex always sends `?client_version=…`; use that to pick its list shape.
261
+ const wantsCodexShape = new URLSearchParams(query).has("client_version");
262
+ await handleModels(backend, res, wantsCodexShape);
263
+ return;
264
+ }
265
+ const retry = options.retry ?? DEFAULT_RETRY;
266
+ if (req.method === "POST" && RESPONSES_PATHS.has(routePath)) {
267
+ await handleResponses(backend, req, res, retry);
268
+ return;
269
+ }
270
+ if (req.method === "POST" && PROXY_PATHS.has(routePath)) {
271
+ await handleProxy(backend, req, res, retry);
272
+ return;
273
+ }
274
+ sendJson(res, 404, errorBody(`unsupported route ${req.method ?? "?"} ${routePath}`, "invalid_request_error"));
275
+ }
276
+ catch (err) {
277
+ const message = error.errorMessage(err);
278
+ logger.error("request failed", { path: routePath, error: message });
279
+ if (!res.headersSent)
280
+ sendJson(res, 500, errorBody(message, "proxy_error"));
281
+ else
282
+ res.end();
283
+ }
284
+ }
285
+ /**
286
+ * `GET /v1/models`: surface the serving catalogue. Two shapes:
287
+ *
288
+ * - OpenAI (default): `{object:"list", data:[{id,object,created,owned_by}]}`,
289
+ * what the `openai` SDK and most tools expect.
290
+ * - Codex (`codexShape`): `{models:[{slug, display_name, …}]}`, the ChatGPT
291
+ * backend shape the Codex CLI decodes. A response missing the top-level
292
+ * `models` field makes Codex log "failed to decode models response", so it
293
+ * gets its own envelope. Only chat endpoints are advertised to Codex.
294
+ */
295
+ async function handleModels(backend, res, codexShape) {
296
+ const endpoints = await backend.models(true);
297
+ if (codexShape) {
298
+ const models = endpoints
299
+ .filter((endpoint) => classify.endpointCapabilities(endpoint).chat)
300
+ .map((endpoint) => ({
301
+ slug: endpoint.name,
302
+ display_name: endpoint.displayName ?? endpoint.name,
303
+ ...(endpoint.description ? { description: endpoint.description } : {}),
304
+ // Fields Codex's strict decoder requires on every model entry.
305
+ default_reasoning_level: "medium",
306
+ supported_reasoning_levels: [],
307
+ shell_type: "shell_command",
308
+ visibility: "list",
309
+ supported_in_api: true,
310
+ }));
311
+ sendJson(res, 200, { models });
312
+ return;
313
+ }
314
+ const data = endpoints.map((endpoint) => ({
315
+ id: endpoint.name,
316
+ object: "model",
317
+ created: 0,
318
+ owned_by: "databricks",
319
+ }));
320
+ sendJson(res, 200, { object: "list", data });
321
+ }
322
+ /**
323
+ * Resolve the request's model and forward a Chat Completions body. Responses-
324
+ * only models (Codex) are translated to a Responses request and posted to
325
+ * `/serving-endpoints/responses`; everything else goes to `/invocations`.
326
+ */
327
+ async function handleProxy(backend, req, res, retry) {
328
+ const body = await readJsonBody(req);
329
+ const requested = typeof body.model === "string" ? body.model : undefined;
330
+ if (!requested) {
331
+ sendJson(res, 400, errorBody("missing 'model' in request body", "invalid_request_error"));
332
+ return;
333
+ }
334
+ const resolved = await backend.resolve(requested);
335
+ body.model = resolved.modelId;
336
+ if (backend.isResponsesOnly(resolved.modelId)) {
337
+ await proxyChatViaResponses(backend, body, requested, resolved.modelId, resolved.matched, res, retry);
338
+ return;
339
+ }
340
+ // This route forwards the client's body as-is, so anything Databricks refuses
341
+ // to parse fails the turn. Drop the known offenders rather than relaying a
342
+ // 400 the client can do nothing about.
343
+ const dropped = openaiChat.stripUnsupportedChatFields(body, extraDropFields());
344
+ const wantsStream = body.stream === true;
345
+ const headers = await backend.authHeaders();
346
+ headers["content-type"] = "application/json";
347
+ headers.accept = wantsStream ? "text/event-stream" : "application/json";
348
+ logger.info("proxy", {
349
+ requested,
350
+ resolved: resolved.modelId,
351
+ matched: resolved.matched,
352
+ upstream: "invocations",
353
+ stream: wantsStream,
354
+ ...(dropped.length > 0 ? { dropped } : {}),
355
+ });
356
+ const upstream = await upstreamFetchRetrying(backend, backend.invocationsUrl(resolved.modelId), headers, body, res, retry);
357
+ res.writeHead(upstream.status, {
358
+ "content-type": upstream.headers.get("content-type") ?? "application/json",
359
+ "x-resolved-model": resolved.modelId,
360
+ });
361
+ await streamBody(upstream, res);
362
+ }
363
+ /**
364
+ * Chat Completions client → Responses-only Databricks model: translate the
365
+ * request, POST to `/serving-endpoints/responses`, translate the reply back.
366
+ * Streaming is not translated yet - those clients should use `/v1/responses`.
367
+ */
368
+ async function proxyChatViaResponses(backend, body, requested, modelId, matched, res, retry) {
369
+ const { responses, stream } = chatToResponsesRequest(body);
370
+ responses.model = modelId;
371
+ if (stream) {
372
+ sendJson(res, 400, errorBody(`model ${modelId} only supports the Responses API; use POST /v1/responses for streaming`, "invalid_request_error"));
373
+ return;
374
+ }
375
+ const headers = await backend.authHeaders();
376
+ headers["content-type"] = "application/json";
377
+ headers.accept = "application/json";
378
+ const upstreamUrl = backend.responsesUrl(modelId);
379
+ const forward = upstreamUrl.includes("/open-responses")
380
+ ? sanitizeOpenResponsesRequest(responses)
381
+ : responses;
382
+ logger.info("proxy", {
383
+ requested,
384
+ resolved: modelId,
385
+ matched,
386
+ upstream: upstreamUrl,
387
+ stream: false,
388
+ });
389
+ const upstream = await upstreamFetchRetrying(backend, upstreamUrl, headers, forward, res, retry);
390
+ if (!upstream.ok) {
391
+ const text = await upstream.text();
392
+ res.writeHead(upstream.status, { "content-type": "application/json" });
393
+ res.end(text || JSON.stringify(errorBody("upstream error", "proxy_error")));
394
+ return;
395
+ }
396
+ const responseJson = (await upstream.json());
397
+ sendJson(res, 200, responseToChatCompletion(responseJson, modelId));
398
+ }
399
+ /**
400
+ * `POST /v1/responses`: forward the Responses body to Databricks' native
401
+ * Responses / Open Responses surface (model stays in the body; URL is
402
+ * workspace-level). Streaming and non-streaming both pass through as-is.
403
+ *
404
+ * Open Responses (Claude/Gemini/…) only accepts `function` tools and
405
+ * `input_*` content part types, and rejects replayed Claude thinking
406
+ * blocks — so Codex's built-in tools, prior-turn `output_text`, and
407
+ * `redacted_thinking` / `thinking` / `reasoning` parts are rewritten or
408
+ * stripped there. The OpenAI `/responses` path keeps them - GPT supports
409
+ * those shapes.
410
+ */
411
+ async function handleResponses(backend, req, res, retry) {
412
+ const body = await readJsonBody(req);
413
+ const requested = typeof body.model === "string" ? body.model : undefined;
414
+ if (!requested) {
415
+ sendJson(res, 400, errorBody("missing 'model' in request body", "invalid_request_error"));
416
+ return;
417
+ }
418
+ const resolved = await backend.resolve(requested);
419
+ body.model = resolved.modelId;
420
+ const upstreamUrl = backend.responsesUrl(resolved.modelId);
421
+ // Cross-provider Open Responses rejects non-function tools and `output_*`
422
+ // content parts in `input`; OpenAI `/responses` keeps Codex's native shapes.
423
+ const forward = upstreamUrl.includes("/open-responses")
424
+ ? sanitizeOpenResponsesRequest(body)
425
+ : body;
426
+ const wantsStream = forward.stream === true;
427
+ const headers = await backend.authHeaders();
428
+ headers["content-type"] = "application/json";
429
+ headers.accept = wantsStream ? "text/event-stream" : "application/json";
430
+ const stripped = Array.isArray(body.tools) &&
431
+ (!Array.isArray(forward.tools) || forward.tools.length !== body.tools.length);
432
+ logger.info("responses", {
433
+ requested,
434
+ resolved: resolved.modelId,
435
+ matched: resolved.matched,
436
+ upstream: upstreamUrl,
437
+ stream: wantsStream,
438
+ ...(stripped ? { strippedNonFunctionTools: true } : {}),
439
+ });
440
+ const upstream = await upstreamFetchRetrying(backend, upstreamUrl, headers, forward, res, retry);
441
+ res.writeHead(upstream.status, {
442
+ "content-type": upstream.headers.get("content-type") ?? "application/json",
443
+ "x-resolved-model": resolved.modelId,
444
+ });
445
+ await streamBody(upstream, res);
446
+ }
447
+ /**
448
+ * Pump an upstream `fetch` Response body to the Node response, chunk by chunk.
449
+ *
450
+ * A mid-stream upstream failure is logged rather than thrown: the status line
451
+ * and some number of chunks have already gone out, so there is no way left to
452
+ * turn it into an HTTP error and the only honest move is to end the response
453
+ * and say why in the log. Without this the read loop rejected into the caller's
454
+ * catch, which found `headersSent` and ended the response silently - making an
455
+ * upstream teardown indistinguishable from a clean finish.
456
+ */
457
+ async function streamBody(upstream, res) {
458
+ const body = upstream.body;
459
+ if (!body) {
460
+ res.end();
461
+ return;
462
+ }
463
+ const reader = body.getReader();
464
+ try {
465
+ for (;;) {
466
+ const { done, value } = await reader.read();
467
+ if (done)
468
+ break;
469
+ if (value && !res.writableEnded)
470
+ res.write(Buffer.from(value));
471
+ if (res.writableEnded)
472
+ break;
473
+ }
474
+ }
475
+ catch (err) {
476
+ // An aborted request is the expected shape of a client hanging up, not a
477
+ // fault worth reporting at error level.
478
+ const aborted = res.writableEnded || !res.writable;
479
+ logger[aborted ? "info" : "error"]("stream ended early", {
480
+ error: error.errorMessage(err),
481
+ });
482
+ }
483
+ finally {
484
+ await reader.cancel().catch(() => { });
485
+ res.end();
486
+ }
487
+ }
488
+ /** True when the request carries the expected bearer token. */
489
+ function isAuthorized(req, apiKey) {
490
+ const header = req.headers.authorization;
491
+ if (!header)
492
+ return false;
493
+ return header.replace(/^Bearer\s+/i, "").trim() === apiKey;
494
+ }
495
+ /**
496
+ * Drain a request body and parse it as a JSON object. An empty, malformed, or
497
+ * non-object body yields `{}`, which the callers reject as a missing `model`.
498
+ */
499
+ async function readJsonBody(req) {
500
+ const chunks = [];
501
+ for await (const chunk of req) {
502
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
503
+ }
504
+ return json.parseRecord(Buffer.concat(chunks).toString("utf8")) ?? {};
505
+ }
506
+ /** Serialize and send a JSON response. */
507
+ function sendJson(res, status, body) {
508
+ res.writeHead(status, { "content-type": "application/json" });
509
+ res.end(JSON.stringify(body));
510
+ }
511
+ /** OpenAI-shaped error envelope. */
512
+ function errorBody(message, type) {
513
+ return { error: { message, type } };
514
+ }
515
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQStCRztBQUVILE9BQU8sRUFBRSxZQUFZLEVBQTBELE1BQU0sV0FBVyxDQUFDO0FBQ2pHLE9BQU8sRUFBRSxLQUFLLElBQUksU0FBUyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDOUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUUsZUFBZSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDaEYsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUcvQixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBb0IsTUFBTSxZQUFZLENBQUM7QUFFOUYsTUFBTSxFQUFFLHNCQUFzQixFQUFFLHdCQUF3QixFQUFFLDRCQUE0QixFQUFFLEdBQ3RGLGVBQWUsQ0FBQztBQUVsQixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLG9CQUFvQixDQUFDLENBQUM7QUFFaEQ7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBQ0gsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLEtBQUssQ0FBQyxFQUFFLGNBQWMsRUFBRSxDQUFDLEVBQUUsV0FBVyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7QUFFNUUsNEVBQTRFO0FBQzVFLE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxDQUFDO0lBQzFCLHNCQUFzQjtJQUN0QixtQkFBbUI7SUFDbkIsaUJBQWlCO0lBQ2pCLGNBQWM7SUFDZCxnQkFBZ0I7SUFDaEIsYUFBYTtDQUNkLENBQUMsQ0FBQztBQUVILDJEQUEyRDtBQUMzRCxNQUFNLFlBQVksR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLFlBQVksRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFD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RUFBRSxFQUFFLGNBQWMsRUFBRSxrQkFBa0IsRUFBRSxDQUFDLENBQUM7SUFDOUQsR0FBRyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7QUFDaEMsQ0FBQztBQUVELG9DQUFvQztBQUNwQyxTQUFTLFNBQVMsQ0FBQyxPQUFlLEVBQUUsSUFBWTtJQUM5QyxPQUFPLEVBQUUsS0FBSyxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUM7QUFDdEMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogT3BlbkFJLWNvbXBhdGlibGUgSFRUUCBwcm94eSBpbiBmcm9udCBvZiBEYXRhYnJpY2tzIE1vZGVsIFNlcnZpbmcuXG4gKlxuICogRGF0YWJyaWNrcyBzZXJ2aW5nIGVuZHBvaW50cyBzcGVhayBPcGVuQUkgd2lyZSBmb3JtYXRzLCBzbyB0aGlzIHNlcnZlciBpcyBhXG4gKiB0aGluIHBhc3MtdGhyb3VnaDogaXQgcmVzb2x2ZXMgdGhlIHJlcXVlc3QncyAocG9zc2libHkgZnV6enkpIGBtb2RlbGAgdG8gYVxuICogcmVhbCBlbmRwb2ludCBpZCB2aWEgdGhlIHtAbGluayBEYXRhYnJpY2tzQmFja2VuZH0sIHN0YW1wcyBhIGZyZXNoIGF1dGhcbiAqIGhlYWRlciwgYW5kIGZvcndhcmRzIHRvIHRoZSByaWdodCBEYXRhYnJpY2tzIFVSTDpcbiAqXG4gKiAgIC0gQ2hhdCBDb21wbGV0aW9ucyDihpIgYC9zZXJ2aW5nLWVuZHBvaW50cy88bmFtZT4vaW52b2NhdGlvbnNgLCBleGNlcHQgZm9yXG4gKiAgICAgUmVzcG9uc2VzLW9ubHkgbW9kZWxzIChDb2RleCkgd2hpY2ggYXJlIHRyYW5zbGF0ZWQgYW5kIHNlbnQgdG9cbiAqICAgICBgL3NlcnZpbmctZW5kcG9pbnRzL3Jlc3BvbnNlc2AuXG4gKiAgIC0gUmVzcG9uc2VzIOKGkiBuYXRpdmUgYC9zZXJ2aW5nLWVuZHBvaW50cy9yZXNwb25zZXNgIChPcGVuQUktZmFtaWx5KSBvclxuICogICAgIGAvc2VydmluZy1lbmRwb2ludHMvb3Blbi1yZXNwb25zZXNgIChDbGF1ZGUvR2VtaW5pL+KApiksIGJvZHkgZm9yd2FyZGVkXG4gKiAgICAgYXMtaXMuIE5vIGNoYXQgcm91bmQtdHJpcC5cbiAqXG4gKiBBbnkgT3BlbkFJLWNvbXBhdGlibGUgdG9vbCAoaVRlcm0sIGVkaXRvcnMsIHRoZSBgb3BlbmFpYCBTREssIENvZGV4IENMSSkgY2FuXG4gKiBwb2ludCBpdHMgYmFzZSBVUkwgYXQgdGhpcyBzZXJ2ZXIgYW5kIHVzZSBsb29zZSBtb2RlbCBuYW1lcy5cbiAqXG4gKiBSb3V0ZXM6XG4gKiAgIC0gYEdFVCAgL2hlYWx0aGAsIGBHRVQgL2AgICAgICAgICAgICBsaXZlbmVzc1xuICogICAtIGBHRVQgIC92MS9tb2RlbHNgLCBgR0VUIC9tb2RlbHNgICAgbGlzdCByZXNvbHZhYmxlIGVuZHBvaW50cy4gRW1pdHMgdGhlXG4gKiAgICAgT3BlbkFJIGB7b2JqZWN0OlwibGlzdFwiLGRhdGE6W+KApl19YCBzaGFwZSBieSBkZWZhdWx0OyB3aGVuIHRoZSByZXF1ZXN0XG4gKiAgICAgbG9va3MgbGlrZSB0aGUgQ29kZXggQ0xJIChhIGBjbGllbnRfdmVyc2lvbmAgcXVlcnkgcGFyYW0sIHdoaWNoIENvZGV4XG4gKiAgICAgYWx3YXlzIHNlbmRzKSBpdCBlbWl0cyBDb2RleCdzIGB7bW9kZWxzOlt7c2x1ZyzigKZ9XX1gIHNoYXBlIGluc3RlYWQsIHNvXG4gKiAgICAgYm90aCBzdGFuZGFyZCBPcGVuQUkgY2xpZW50cyBhbmQgQ29kZXggY2FuIGVudW1lcmF0ZSB0aGUgY2F0YWxvZ3VlLlxuICogICAtIGBQT1NUIC92MS9jaGF0L2NvbXBsZXRpb25zYCAgICAgICAgcHJveHkgKGFsc28gYC9jb21wbGV0aW9uc2AsXG4gKiAgICAgYC92MS9jb21wbGV0aW9uc2AsIGAvdjEvZW1iZWRkaW5nc2AsIGFuZCB0aGUgdW4tcHJlZml4ZWQgdmFyaWFudHMpXG4gKiAgIC0gYFBPU1QgL3YxL3Jlc3BvbnNlc2AgICAgICAgICAgICAgICBPcGVuQUkgUmVzcG9uc2VzIEFQSSwgZm9yd2FyZGVkIHRvXG4gKiAgICAgRGF0YWJyaWNrcycgbmF0aXZlIFJlc3BvbnNlcyAvIE9wZW4gUmVzcG9uc2VzIHN1cmZhY2UuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGNyZWF0ZVNlcnZlciwgdHlwZSBJbmNvbWluZ01lc3NhZ2UsIHR5cGUgU2VydmVyLCB0eXBlIFNlcnZlclJlc3BvbnNlIH0gZnJvbSBcIm5vZGU6aHR0cFwiO1xuaW1wb3J0IHsgYXN5bmMgYXMgYXN5bmNVdGlsLCBlcnJvciwganNvbiwgbG9nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IGNsYXNzaWZ5LCBvcGVuYWlDaGF0LCBvcGVuYWlSZXNwb25zZXMgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtbW9kZWxcIjtcbmltcG9ydCB7IEFnZW50IH0gZnJvbSBcInVuZGljaVwiO1xuXG5pbXBvcnQgdHlwZSB7IERhdGFicmlja3NCYWNrZW5kIH0gZnJvbSBcIi4vYmFja2VuZFwiO1xuaW1wb3J0IHsgREVGQVVMVF9CSU5EX0hPU1QsIERFRkFVTFRfUE9SVCwgREVGQVVMVF9SRVRSWSwgdHlwZSBSZXRyeUNvbmZpZyB9IGZyb20gXCIuL2RlZmF1bHRzXCI7XG5cbmNvbnN0IHsgY2hhdFRvUmVzcG9uc2VzUmVxdWVzdCwgcmVzcG9uc2VUb0NoYXRDb21wbGV0aW9uLCBzYW5pdGl6ZU9wZW5SZXNwb25zZXNSZXF1ZXN0IH0gPVxuICBvcGVuYWlSZXNwb25zZXM7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJtb2RlbC1wcm94eS9zZXJ2ZXJcIik7XG5cbi8qKlxuICogRGlzcGF0Y2hlciBmb3IgZXZlcnkgdXBzdHJlYW0gY2FsbCwgd2l0aCB1bmRpY2kncyBpbmFjdGl2aXR5IHRpbWVvdXRzXG4gKiBESVNBQkxFRCAoYDBgKS5cbiAqXG4gKiBBIHByb3hpZWQgdHVybiBpcyBvbmx5IGFzIGZhc3QgYXMgdGhlIG1vZGVsIGJlaGluZCBpdCwgYW5kIHVuZGljaSdzXG4gKiBkZWZhdWx0cyAoMzAwcyBgaGVhZGVyc1RpbWVvdXRgLCAzMDBzIGBib2R5VGltZW91dGApIGFyZSBib3RoIHdyb25nIGhlcmUuXG4gKiBgYm9keVRpbWVvdXRgIGlzIHRoZSBraWxsZXI6IGl0IG1lYXN1cmVzIHRoZSBnYXAgQkVUV0VFTiBjaHVua3MsIHNvIGEgbW9kZWxcbiAqIHRoYXQgdGhpbmtzIGZvciBhIHdoaWxlIG1pZC1zdHJlYW0gLSBleHRlbmRlZCByZWFzb25pbmcsIGEgbG9uZyB0b29sIHJvdW5kXG4gKiB0cmlwLCBhIHNsb3cgR2VuaWUvU1FMIHN0ZXAgLSB0cmlwcyBpdCBhbmQgdW5kaWNpIHRlYXJzIHRoZSBzb2NrZXQgZG93blxuICogd2l0aCBgVU5EX0VSUl9CT0RZX1RJTUVPVVRgLCB3aGljaCB0aGUgY2xpZW50IHNlZXMgYXMgYSB0cnVuY2F0ZWQgc3RyZWFtLlxuICpcbiAqIFRoZSBwcm94eSBoYXMgbm8gb3BpbmlvbiBvbiBob3cgbG9uZyBhIG1vZGVsIG1heSB0YWtlLCBzbyBpdCBpbXBvc2VzIG5vXG4gKiBkZWFkbGluZTogdGhlIHN0cmVhbSBlbmRzIHdoZW4gdGhlIHVwc3RyZWFtIGVuZHMgaXQsIG9yIHdoZW4gdGhlIGNsaWVudFxuICogaGFuZ3MgdXAgKHNlZSB7QGxpbmsgcmVxdWVzdEFib3J0U2lnbmFsfSkuIENhbGxlcnMgdGhhdCBETyB3YW50IGEgZGVhZGxpbmVcbiAqIHNob3VsZCBzZW5kIG9uZSwgdGhlIHNhbWUgYXMgdGhleSB3b3VsZCB0byBPcGVuQUkuXG4gKi9cbmNvbnN0IHVwc3RyZWFtRGlzcGF0Y2hlciA9IG5ldyBBZ2VudCh7IGhlYWRlcnNUaW1lb3V0OiAwLCBib2R5VGltZW91dDogMCB9KTtcblxuLyoqIFBPU1Qgcm91dGVzIGZvcndhcmRlZCB0byBhIHNlcnZpbmcgZW5kcG9pbnQgKGNoYXQgb3IgUmVzcG9uc2VzLW9ubHkpLiAqL1xuY29uc3QgUFJPWFlfUEFUSFMgPSBuZXcgU2V0KFtcbiAgXCIvdjEvY2hhdC9jb21wbGV0aW9uc1wiLFxuICBcIi9jaGF0L2NvbXBsZXRpb25zXCIsXG4gIFwiL3YxL2NvbXBsZXRpb25zXCIsXG4gIFwiL2NvbXBsZXRpb25zXCIsXG4gIFwiL3YxL2VtYmVkZGluZ3NcIixcbiAgXCIvZW1iZWRkaW5nc1wiLFxuXSk7XG5cbi8qKiBHRVQgcm91dGVzIHRoYXQgbGlzdCB0aGUgcmVzb2x2YWJsZSBtb2RlbCBjYXRhbG9ndWUuICovXG5jb25zdCBNT0RFTFNfUEFUSFMgPSBuZXcgU2V0KFtcIi92MS9tb2RlbHNcIiwgXCIvbW9kZWxzXCJdKTtcblxuLyoqIFBPU1Qgcm91dGVzIHRoYXQgY2FycnkgYW4gT3BlbkFJIFJlc3BvbnNlcyBBUEkgYm9keSAobmF0aXZlIHBhc3N0aHJvdWdoKS4gKi9cbmNvbnN0IFJFU1BPTlNFU19QQVRIUyA9IG5ldyBTZXQoW1wiL3YxL3Jlc3BvbnNlc1wiLCBcIi9yZXNwb25zZXNcIl0pO1xuXG4vKipcbiAqIEV4dHJhIHJlcXVlc3QgZmllbGRzIHRvIHN0cmlwIGJlZm9yZSBmb3J3YXJkaW5nLCBvbiB0b3Agb2ZcbiAqIGBvcGVuYWlDaGF0LlVOU1VQUE9SVEVEX0NIQVRfRklFTERTYC4gQ29tbWEtc2VwYXJhdGVkIGluIGBQUk9YWV9EUk9QX0ZJRUxEU2AuXG4gKlxuICogQW4gZXNjYXBlIGhhdGNoOiB3aGVuIGEgd29ya3NwYWNlIG9yIGEgbmV3IGNsaWVudCB2ZXJzaW9uIHRyaXBzIGEgZmllbGRcbiAqIERhdGFicmlja3MgcmVqZWN0cywgYW4gb3BlcmF0b3IgY2FuIHVuYmxvY2sgdGhlbXNlbHZlcyBpbW1lZGlhdGVseSBpbnN0ZWFkIG9mXG4gKiB3YWl0aW5nIG9uIGEgcmVsZWFzZSBvZiB0aGlzIHBhY2thZ2UuXG4gKi9cbmZ1bmN0aW9uIGV4dHJhRHJvcEZpZWxkcygpOiBzdHJpbmdbXSB7XG4gIHJldHVybiAocHJvY2Vzcy5lbnYuUFJPWFlfRFJPUF9GSUVMRFMgPz8gXCJcIilcbiAgICAuc3BsaXQoXCIsXCIpXG4gICAgLm1hcCgoZmllbGQpID0+IGZpZWxkLnRyaW0oKSlcbiAgICAuZmlsdGVyKChmaWVsZCkgPT4gZmllbGQubGVuZ3RoID4gMCk7XG59XG5cbi8qKiBPcHRpb25zIHNoYXJlZCBieSB7QGxpbmsgY3JlYXRlUHJveHlTZXJ2ZXJ9IGFuZCB7QGxpbmsgc3RhcnRQcm94eVNlcnZlcn0uICovXG5leHBvcnQgaW50ZXJmYWNlIFByb3h5U2VydmVyT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBXaGVuIHNldCwgbG9jYWwgY2xpZW50cyBtdXN0IHByZXNlbnQgdGhpcyB2YWx1ZSBhcyBhIGJlYXJlciB0b2tlblxuICAgKiAoYEF1dGhvcml6YXRpb246IEJlYXJlciA8a2V5PmApLiBVbnNldCBsZWF2ZXMgdGhlIHByb3h5IG9wZW4sIHdoaWNoIGlzIGZpbmVcbiAgICogZm9yIGEgbG9vcGJhY2sgYmluZCBidXQgc2hvdWxkIGJlIHBhaXJlZCB3aXRoIGEga2V5IG9uIGEgd2lkZXIgb25lLlxuICAgKi9cbiAgYXBpS2V5Pzogc3RyaW5nO1xuICAvKipcbiAgICogUG9saWN5IGZvciBhYnNvcmJpbmcgdXBzdHJlYW0gNDI5cy4gT21pdHRlZCBkZWZhdWx0cyB0byB7QGxpbmtcbiAgICogREVGQVVMVF9SRVRSWX0gKHJldHJ5IG9uKS4gU2VlIHtAbGluayBSZXRyeUNvbmZpZ30uXG4gICAqL1xuICByZXRyeT86IFJldHJ5Q29uZmlnO1xufVxuXG4vKiogT3B0aW9ucyBmb3Ige0BsaW5rIHN0YXJ0UHJveHlTZXJ2ZXJ9LCBhZGRpbmcgdGhlIGxpc3RlbiBhZGRyZXNzLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTdGFydFByb3h5T3B0aW9ucyBleHRlbmRzIFByb3h5U2VydmVyT3B0aW9ucyB7XG4gIGhvc3Q/OiBzdHJpbmc7XG4gIHBvcnQ/OiBudW1iZXI7XG59XG5cbi8qKiBCdWlsZCAoYnV0IGRvIG5vdCBzdGFydCkgdGhlIHByb3h5IEhUVFAgc2VydmVyLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVByb3h5U2VydmVyKFxuICBiYWNrZW5kOiBEYXRhYnJpY2tzQmFja2VuZCxcbiAgb3B0aW9uczogUHJveHlTZXJ2ZXJPcHRpb25zID0ge30sXG4pOiBTZXJ2ZXIge1xuICBjb25zdCBzZXJ2ZXIgPSBjcmVhdGVTZXJ2ZXIoKHJlcSwgcmVzKSA9PiB7XG4gICAgdm9pZCBoYW5kbGVSZXF1ZXN0KGJhY2tlbmQsIG9wdGlvbnMsIHJlcSwgcmVzKTtcbiAgfSk7XG4gIC8vIE1hdGNoIHRoZSB1cHN0cmVhbSBwb2xpY3kgb24gdGhlIElOQk9VTkQgc2lkZTogbmV2ZXIgY3V0IGEgY2xpZW50IG9mZlxuICAvLyBtaWQtdHVybi4gTm9kZSdzIGRlZmF1bHRzICgzMDBzIGByZXF1ZXN0VGltZW91dGAsIDYwcyBgaGVhZGVyc1RpbWVvdXRgKVxuICAvLyBhcmUgc2l6ZWQgZm9yIG9yZGluYXJ5IHdlYiB0cmFmZmljLCBub3QgZm9yIGhvbGRpbmcgYSBzdHJlYW1lZCBtb2RlbFxuICAvLyByZXNwb25zZSBvcGVuLCBhbmQgYSBjbGllbnQgdGhhdCBoaXRzIG9uZSBnZXRzIGEgZGVhZCBzb2NrZXQgcmF0aGVyIHRoYW5cbiAgLy8gYW4gZXJyb3IgaXQgY2FuIGFjdCBvbi4gYDBgIGRpc2FibGVzIGVhY2g7IHRoZSB0dXJuIG5vdyBlbmRzIHdoZW4gdGhlXG4gIC8vIG1vZGVsIGlzIGRvbmUgb3IgdGhlIGNsaWVudCBkaXNjb25uZWN0cy5cbiAgc2VydmVyLnJlcXVlc3RUaW1lb3V0ID0gMDtcbiAgc2VydmVyLmhlYWRlcnNUaW1lb3V0ID0gMDtcbiAgc2VydmVyLnRpbWVvdXQgPSAwO1xuICByZXR1cm4gc2VydmVyO1xufVxuXG4vKipcbiAqIFNpZ25hbCB0aGF0IGFib3J0cyB3aGVuIHRoZSBjbGllbnQgaGFuZ3MgdXAuXG4gKlxuICogUmVtb3ZpbmcgdGhlIHRpbWVvdXRzIG1lYW5zIG5vdGhpbmcgZWxzZSB3aWxsIGV2ZXIgZW5kIGEgZm9yZ290dGVuIHJlcXVlc3QsXG4gKiBzbyB0aGUgY2xpZW50J3Mgb3duIGRpc2Nvbm5lY3QgYmVjb21lcyB0aGUgb25seSBiYWNrc3RvcCBhZ2FpbnN0IGFuIHVwc3RyZWFtXG4gKiBjYWxsIHJ1bm5pbmcgb24gd2l0aCBubyBvbmUgdG8gcmVjZWl2ZSBpdC4gUGFzc2luZyB0aGlzIHRvIGBmZXRjaGAgaXMgd2hhdFxuICogbWFrZXMgYSBjYW5jZWxsZWQgdHVybiAoQ3RybC1DLCBhIGNsb3NlZCB0YWIsIGEga2lsbGVkIENMSSkgcmVsZWFzZSB0aGVcbiAqIERhdGFicmlja3Mtc2lkZSBzdHJlYW0gaW5zdGVhZCBvZiBsZWFraW5nIGl0IGZvciB0aGUgbGlmZSBvZiB0aGUgcHJvY2Vzcy5cbiAqXG4gKiBLZXllZCBvZmYgdGhlIFJFU1BPTlNFLCBub3QgdGhlIHJlcXVlc3Q6IGBJbmNvbWluZ01lc3NhZ2VgIGVtaXRzIGBjbG9zZWAgYXNcbiAqIHNvb24gYXMgaXRzIGJvZHkgaGFzIGJlZW4gZnVsbHkgY29uc3VtZWQsIHdoaWNoIG9uIGV2ZXJ5IFBPU1QgaGVyZSBoYXBwZW5zXG4gKiBiZWZvcmUgdGhlIHVwc3RyZWFtIGNhbGwgaXMgZXZlbiBtYWRlIC0gd2F0Y2hpbmcgdGhhdCB3b3VsZCBhYm9ydCBlYWNoIHR1cm5cbiAqIGluc3RhbnRseS4gYFNlcnZlclJlc3BvbnNlYCBlbWl0cyBgY2xvc2VgIHdoZW4gdGhlIHJlc3BvbnNlIGZpbmlzaGVzIG9yIHRoZVxuICogY29ubmVjdGlvbiBkcm9wcywgc28gdGhlIGB3cml0YWJsZUZpbmlzaGVkYCBjaGVjayBzZXBhcmF0ZXMgXCJjbGllbnQgbGVmdFwiXG4gKiBmcm9tIFwid2UgcmVwbGllZFwiLlxuICovXG5mdW5jdGlvbiBjbGllbnRBYm9ydFNpZ25hbChyZXM6IFNlcnZlclJlc3BvbnNlKTogQWJvcnRTaWduYWwge1xuICBjb25zdCBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICByZXMub25jZShcImNsb3NlXCIsICgpID0+IHtcbiAgICBpZiAoIXJlcy53cml0YWJsZUZpbmlzaGVkKSBjb250cm9sbGVyLmFib3J0KCk7XG4gIH0pO1xuICByZXR1cm4gY29udHJvbGxlci5zaWduYWw7XG59XG5cbi8qKlxuICogUE9TVCBhIEpTT04gYm9keSB0byBhIHNlcnZpbmcgZW5kcG9pbnQgb24gdGhlIG5vLXRpbWVvdXRcbiAqIHtAbGluayB1cHN0cmVhbURpc3BhdGNoZXJ9LCBjYW5jZWxsZWQgdmlhIGBzaWduYWxgLlxuICpcbiAqIEV2ZXJ5IHVwc3RyZWFtIGNhbGwgZ29lcyB0aHJvdWdoIGhlcmUgc28gdGhlIHRpbWVvdXQgYW5kIGNhbmNlbGxhdGlvbiBwb2xpY3lcbiAqIGlzIHN0YXRlZCBvbmNlLiBgZGlzcGF0Y2hlcmAgaXMgYW4gdW5kaWNpIGV4dGVuc2lvbiB0aGF0IHRoZSBET01cbiAqIGBSZXF1ZXN0SW5pdGAgTm9kZSBjb21waWxlcyBhZ2FpbnN0IGRvZXMgbm90IGRlY2xhcmUsIGhlbmNlIHRoZSBsb2NhbFxuICogaW50ZXJzZWN0aW9uIHR5cGUgcmF0aGVyIHRoYW4gYSBjYXN0IGF0IGVhY2ggY2FsbCBzaXRlLlxuICovXG5hc3luYyBmdW5jdGlvbiB1cHN0cmVhbUZldGNoKFxuICB1cmw6IHN0cmluZyxcbiAgaGVhZGVyczogUmVjb3JkPHN0cmluZywgc3RyaW5nPixcbiAgYm9keTogc3RyaW5nLFxuICBzaWduYWw6IEFib3J0U2lnbmFsLFxuKTogUHJvbWlzZTxSZXNwb25zZT4ge1xuICBjb25zdCBpbml0OiBSZXF1ZXN0SW5pdCA9IHsgbWV0aG9kOiBcIlBPU1RcIiwgaGVhZGVycywgYm9keSwgc2lnbmFsIH07XG4gIC8vIGBkaXNwYXRjaGVyYCBpcyBhbiB1bmRpY2kgZXh0ZW5zaW9uIHRoZSBET00gYFJlcXVlc3RJbml0YCBkb2Vzbid0IGRlY2xhcmUsXG4gIC8vIGFuZCBpdCBjYW4ndCBzaW1wbHkgYmUgdHlwZWQgb246IGBAdHlwZXMvbm9kZWAgcGlucyBpdHMgb3duIGB1bmRpY2ktdHlwZXNgXG4gIC8vIGNvcHksIHNvIHRoZSBgQWdlbnRgIGZyb20gb3VyIGB1bmRpY2lgIGRlcGVuZGVuY3kgaXMgYSBzdHJ1Y3R1cmFsbHlcbiAgLy8gaWRlbnRpY2FsIGJ1dCBub21pbmFsbHkgZGlmZmVyZW50IHR5cGUgdGhhbiB0aGUgb25lIHRoZSBnbG9iYWwgYGZldGNoYFxuICAvLyBzaWduYXR1cmUgZXhwZWN0cy4gQXR0YWNoaW5nIGl0IHN0cnVjdHVyYWxseSBzaWRlc3RlcHMgYSB2ZXJzaW9uIHNrZXcgdGhhdFxuICAvLyBubyBjYXN0IGV4cHJlc3NlcyBjbGVhbmx5LCBhbmQgYGZldGNoYCByZWFkcyBpdCBhdCBydW50aW1lIGFsbCB0aGUgc2FtZS5cbiAgUmVmbGVjdC5zZXQoaW5pdCwgXCJkaXNwYXRjaGVyXCIsIHVwc3RyZWFtRGlzcGF0Y2hlcik7XG4gIHJldHVybiBmZXRjaCh1cmwsIGluaXQpO1xufVxuXG4vKipcbiAqIERlbGF5IChtcykgYSBgNDI5YCByZXNwb25zZSBhc2tzIHVzIHRvIHdhaXQsIGZyb20gaXRzIGBSZXRyeS1BZnRlcmAgaGVhZGVyLFxuICogb3IgYHVuZGVmaW5lZGAgd2hlbiBhYnNlbnQvdW5wYXJzZWFibGUuIEhhbmRsZXMgYm90aCBoZWFkZXIgZm9ybXM6IGFuIGludGVnZXJcbiAqIGNvdW50IG9mIHNlY29uZHMsIGFuZCBhbiBIVFRQIGRhdGUgdG8gd2FpdCB1bnRpbCAoY2xhbXBlZCB0byBgPj0gMGApLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VSZXRyeUFmdGVyTXMoaGVhZGVyOiBzdHJpbmcgfCBudWxsLCBub3dNczogbnVtYmVyKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgaWYgKCFoZWFkZXIpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IHRyaW1tZWQgPSBoZWFkZXIudHJpbSgpO1xuICBpZiAoL15cXGQrJC8udGVzdCh0cmltbWVkKSkgcmV0dXJuIE51bWJlcih0cmltbWVkKSAqIDEwMDA7XG4gIGNvbnN0IHdoZW4gPSBEYXRlLnBhcnNlKHRyaW1tZWQpO1xuICBpZiAoTnVtYmVyLmlzTmFOKHdoZW4pKSByZXR1cm4gdW5kZWZpbmVkO1xuICByZXR1cm4gTWF0aC5tYXgoMCwgd2hlbiAtIG5vd01zKTtcbn1cblxuLyoqXG4gKiBCYWNrb2ZmIChtcykgYmVmb3JlIHJldHJ5IGBhdHRlbXB0YCAoMC1iYXNlZCk6IGV4cG9uZW50aWFsIGZyb21cbiAqIGBiYXNlRGVsYXlNc2AsIGNhcHBlZCBhdCBgbWF4RGVsYXlNc2AsIHdpdGggdXAgdG8gKzUwJSBqaXR0ZXIgc28gY29uY3VycmVudFxuICogcmV0cmllcyBmcm9tIG9uZSBhZ2VudCBkb24ndCByZXN5bmNocm9uaXplIGludG8gdGhlIG5leHQgYnVyc3QuIEEgc2VydmVyLXNlbnRcbiAqIGBSZXRyeS1BZnRlcmAgd2lucyBvdXRyaWdodCAoc3RpbGwgY2FwcGVkKSwgc2luY2UgdGhlIHNlcnZlciBrbm93cyBiZXR0ZXJcbiAqIHRoYW4gb3VyIHNjaGVkdWxlIHdoZW4gaXQgd2lsbCBhY2NlcHQgdHJhZmZpYyBhZ2Fpbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJhY2tvZmZEZWxheU1zKFxuICBhdHRlbXB0OiBudW1iZXIsXG4gIHJldHJ5OiBSZXRyeUNvbmZpZyxcbiAgcmV0cnlBZnRlck1zOiBudW1iZXIgfCB1bmRlZmluZWQsXG4gIGppdHRlcjogbnVtYmVyLFxuKTogbnVtYmVyIHtcbiAgaWYgKHJldHJ5QWZ0ZXJNcyAhPT0gdW5kZWZpbmVkKSByZXR1cm4gTWF0aC5taW4ocmV0cnlBZnRlck1zLCByZXRyeS5tYXhEZWxheU1zKTtcbiAgY29uc3QgZXhwb25lbnRpYWwgPSByZXRyeS5iYXNlRGVsYXlNcyAqIDIgKiogYXR0ZW1wdDtcbiAgY29uc3QgY2FwcGVkID0gTWF0aC5taW4oZXhwb25lbnRpYWwsIHJldHJ5Lm1heERlbGF5TXMpO1xuICByZXR1cm4gTWF0aC5yb3VuZChjYXBwZWQgKiAoMSArIGppdHRlciAqIDAuNSkpO1xufVxuXG4vKipcbiAqIHtAbGluayB1cHN0cmVhbUZldGNofSB3aXRoIGluLXByb3h5IGA0MjlgIGhhbmRsaW5nLiBXaGVuIGByZXRyeS5lbmFibGVkYCwgYVxuICogNDI5IGlzIHJldHJpZWQgdXAgdG8gYHJldHJ5Lm1heFJldHJpZXNgIHRpbWVzIHdpdGgge0BsaW5rIGJhY2tvZmZEZWxheU1zfVxuICogYmFja29mZiBpbnN0ZWFkIG9mIGJlaW5nIHN1cmZhY2VkOyB0aGUgdGhyb3R0bGVkIHJlc3BvbnNlIGJvZHkgaXMgZHJhaW5lZFxuICogZWFjaCB0aW1lIHNvIHRoZSBjb25uZWN0aW9uIGlzIHJlbGVhc2VkLiBUaGUgcmV0cnkgaGFwcGVucyBCRUZPUkUgdGhlIGNhbGxlclxuICogd3JpdGVzIGFueSBzdGF0dXMgbGluZSwgc28gaXQgaXMgdHJhbnNwYXJlbnQgdG8gYm90aCBzdHJlYW1pbmcgYW5kXG4gKiBub24tc3RyZWFtaW5nIHBhdGhzIC0gdGhlIGNsaWVudCBvbmx5IGV2ZXIgc2VlcyB0aGUgZmluYWwgcmVzcG9uc2UuXG4gKlxuICogQmFpbHMgZWFybHkgKHJldHVybmluZyB0aGUgNDI5KSB3aGVuIHJldHJpZXMgYXJlIGV4aGF1c3RlZCwgd2hlbiB0aGUgY2xpZW50XG4gKiBoYXMgaHVuZyB1cCAoYHNpZ25hbC5hYm9ydGVkYCksIG9yIHdoZW4gdGhlIHJlc3BvbnNlIGNhcnJpZXMgbm8gYFJldHJ5LUFmdGVyYFxuICogYW5kIHdlIHdvdWxkIG90aGVyd2lzZSBsb29wIGJsaW5kIHBhc3QgdGhlIGNhcC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gdXBzdHJlYW1GZXRjaFJldHJ5aW5nKFxuICBiYWNrZW5kOiBEYXRhYnJpY2tzQmFja2VuZCxcbiAgdXJsOiBzdHJpbmcsXG4gIGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4sXG4gIGJvZHk6IHVua25vd24sXG4gIHJlczogU2VydmVyUmVzcG9uc2UsXG4gIHJldHJ5OiBSZXRyeUNvbmZpZyxcbik6IFByb21pc2U8UmVzcG9uc2U+IHtcbiAgY29uc3Qgc2lnbmFsID0gY2xpZW50QWJvcnRTaWduYWwocmVzKTtcbiAgY29uc3QgcGF5bG9hZCA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xuICBsZXQgcmVzcG9uc2UgPSBhd2FpdCB1cHN0cmVhbUZldGNoKHVybCwgaGVhZGVycywgcGF5bG9hZCwgc2lnbmFsKTtcbiAgaWYgKCFyZXRyeS5lbmFibGVkKSByZXR1cm4gcmVzcG9uc2U7XG5cbiAgZm9yIChsZXQgYXR0ZW1wdCA9IDA7IHJlc3BvbnNlLnN0YXR1cyA9PT0gNDI5ICYmIGF0dGVtcHQgPCByZXRyeS5tYXhSZXRyaWVzOyBhdHRlbXB0KyspIHtcbiAgICBjb25zdCByZXRyeUFmdGVyTXMgPSBwYXJzZVJldHJ5QWZ0ZXJNcyhyZXNwb25zZS5oZWFkZXJzLmdldChcInJldHJ5LWFmdGVyXCIpLCBEYXRlLm5vdygpKTtcbiAgICBjb25zdCBkZWxheU1zID0gYmFja29mZkRlbGF5TXMoYXR0ZW1wdCwgcmV0cnksIHJldHJ5QWZ0ZXJNcywgaml0dGVyRnJhY3Rpb24oKSk7XG4gICAgLy8gUmVsZWFzZSB0aGUgdGhyb3R0bGVkIHJlc3BvbnNlJ3Mgc29ja2V0IGJlZm9yZSB3YWl0aW5nOyBpdHMgYm9keSBpcyBhblxuICAgIC8vIGVycm9yIHBheWxvYWQgd2UgYXJlIGNob29zaW5nIG5vdCB0byByZWxheS5cbiAgICBhd2FpdCByZXNwb25zZS5ib2R5Py5jYW5jZWwoKS5jYXRjaCgoKSA9PiB7fSk7XG4gICAgbG9nZ2VyLndhcm4oXCJ1cHN0cmVhbSA0Mjk7IGJhY2tpbmcgb2ZmXCIsIHtcbiAgICAgIGF0dGVtcHQ6IGF0dGVtcHQgKyAxLFxuICAgICAgbWF4UmV0cmllczogcmV0cnkubWF4UmV0cmllcyxcbiAgICAgIGRlbGF5TXMsXG4gICAgICAuLi4ocmV0cnlBZnRlck1zICE9PSB1bmRlZmluZWQgPyB7IHJldHJ5QWZ0ZXJNcyB9IDoge30pLFxuICAgIH0pO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBhc3luY1V0aWwuc2xlZXAoZGVsYXlNcywgc2lnbmFsKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIENsaWVudCBodW5nIHVwIG1pZC13YWl0OiByZXR1cm4gdGhlIGxhc3QgNDI5IHJhdGhlciB0aGFuIGlzc3VlIGFcbiAgICAgIC8vIHJlcXVlc3Qgbm8gb25lIGlzIGxpc3RlbmluZyBmb3IuXG4gICAgICByZXR1cm4gcmVzcG9uc2U7XG4gICAgfVxuICAgIC8vIEZyZXNoIGF1dGggaGVhZGVyIHBlciBhdHRlbXB0IHNvIGEgbG9uZyBiYWNrb2ZmIGNhbid0IG91dGxpdmUgdGhlIHRva2VuLlxuICAgIGNvbnN0IHJldHJ5SGVhZGVycyA9IHsgLi4uKGF3YWl0IGJhY2tlbmQuYXV0aEhlYWRlcnMoKSksIC4uLmhlYWRlcnMgfTtcbiAgICByZXNwb25zZSA9IGF3YWl0IHVwc3RyZWFtRmV0Y2godXJsLCByZXRyeUhlYWRlcnMsIHBheWxvYWQsIHNpZ25hbCk7XG4gIH1cbiAgcmV0dXJuIHJlc3BvbnNlO1xufVxuXG4vKipcbiAqIEppdHRlciBmcmFjdGlvbiBpbiBgWzAsIDEpYC4gU3BsaXQgb3V0IHNvIHRlc3RzIGNhbiBzdHViIGRldGVybWluaXNtO1xuICogYE1hdGgucmFuZG9tYCBpcyBmaW5lIGZvciBzcHJlYWRpbmcgcmV0cnkgdGltaW5nLlxuICovXG5mdW5jdGlvbiBqaXR0ZXJGcmFjdGlvbigpOiBudW1iZXIge1xuICByZXR1cm4gTWF0aC5yYW5kb20oKTtcbn1cblxuLyoqXG4gKiBCdWlsZCBhbmQgc3RhcnQgdGhlIHByb3h5LCByZXNvbHZpbmcgb25jZSBpdCBpcyBhY2NlcHRpbmcgY29ubmVjdGlvbnMuXG4gKiBSZXR1cm5zIHRoZSBzZXJ2ZXIgYW5kIGl0cyBiYXNlIFVSTCAod2l0aCB0aGUgYWN0dWFsbHktYm91bmQgcG9ydCwgc28gYVxuICogYHBvcnQ6IDBgIHJlcXVlc3Qgc3VyZmFjZXMgdGhlIE9TLWFzc2lnbmVkIHBvcnQpLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRQcm94eVNlcnZlcihcbiAgYmFja2VuZDogRGF0YWJyaWNrc0JhY2tlbmQsXG4gIG9wdGlvbnM6IFN0YXJ0UHJveHlPcHRpb25zID0ge30sXG4pOiBQcm9taXNlPHsgc2VydmVyOiBTZXJ2ZXI7IHVybDogc3RyaW5nIH0+IHtcbiAgY29uc3QgaG9zdCA9IG9wdGlvbnMuaG9zdCA/PyBERUZBVUxUX0JJTkRfSE9TVDtcbiAgY29uc3QgcG9ydCA9IG9wdGlvbnMucG9ydCA/PyBERUZBVUxUX1BPUlQ7XG4gIGNvbnN0IHNlcnZlciA9IGNyZWF0ZVByb3h5U2VydmVyKGJhY2tlbmQsIG9wdGlvbnMpO1xuICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3Qgb25FcnJvciA9IChlcnI6IEVycm9yKSA9PiByZWplY3QoZXJyKTtcbiAgICBzZXJ2ZXIub25jZShcImVycm9yXCIsIG9uRXJyb3IpO1xuICAgIHNlcnZlci5saXN0ZW4ocG9ydCwgaG9zdCwgKCkgPT4ge1xuICAgICAgc2VydmVyLm9mZihcImVycm9yXCIsIG9uRXJyb3IpO1xuICAgICAgcmVzb2x2ZSgpO1xuICAgIH0pO1xuICB9KTtcbiAgY29uc3QgYWRkcmVzcyA9IHNlcnZlci5hZGRyZXNzKCk7XG4gIGNvbnN0IGJvdW5kUG9ydCA9IHR5cGVvZiBhZGRyZXNzID09PSBcIm9iamVjdFwiICYmIGFkZHJlc3MgPyBhZGRyZXNzLnBvcnQgOiBwb3J0O1xuICByZXR1cm4geyBzZXJ2ZXIsIHVybDogYGh0dHA6Ly8ke2hvc3R9OiR7Ym91bmRQb3J0fWAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaGFuZGxlUmVxdWVzdChcbiAgYmFja2VuZDogRGF0YWJyaWNrc0JhY2tlbmQsXG4gIG9wdGlvbnM6IFByb3h5U2VydmVyT3B0aW9ucyxcbiAgcmVxOiBJbmNvbWluZ01lc3NhZ2UsXG4gIHJlczogU2VydmVyUmVzcG9uc2UsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgcmF3VXJsID0gcmVxLnVybCA/PyBcIi9cIjtcbiAgY29uc3QgW3BhdGgsIHF1ZXJ5ID0gXCJcIl0gPSByYXdVcmwuc3BsaXQoXCI/XCIpO1xuICBjb25zdCByb3V0ZVBhdGggPSBwYXRoID8/IFwiL1wiO1xuICB0cnkge1xuICAgIGlmIChyZXEubWV0aG9kID09PSBcIkdFVFwiICYmIChyb3V0ZVBhdGggPT09IFwiL2hlYWx0aFwiIHx8IHJvdXRlUGF0aCA9PT0gXCIvXCIpKSB7XG4gICAgICBzZW5kSnNvbihyZXMsIDIwMCwgeyBzdGF0dXM6IFwib2tcIiB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMuYXBpS2V5ICYmICFpc0F1dGhvcml6ZWQocmVxLCBvcHRpb25zLmFwaUtleSkpIHtcbiAgICAgIHNlbmRKc29uKHJlcywgNDAxLCBlcnJvckJvZHkoXCJpbnZhbGlkIGFwaSBrZXlcIiwgXCJpbnZhbGlkX3JlcXVlc3RfZXJyb3JcIikpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAocmVxLm1ldGhvZCA9PT0gXCJHRVRcIiAmJiBNT0RFTFNfUEFUSFMuaGFzKHJvdXRlUGF0aCkpIHtcbiAgICAgIC8vIENvZGV4IGFsd2F5cyBzZW5kcyBgP2NsaWVudF92ZXJzaW9uPeKApmA7IHVzZSB0aGF0IHRvIHBpY2sgaXRzIGxpc3Qgc2hhcGUuXG4gICAgICBjb25zdCB3YW50c0NvZGV4U2hhcGUgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHF1ZXJ5KS5oYXMoXCJjbGllbnRfdmVyc2lvblwiKTtcbiAgICAgIGF3YWl0IGhhbmRsZU1vZGVscyhiYWNrZW5kLCByZXMsIHdhbnRzQ29kZXhTaGFwZSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHJldHJ5ID0gb3B0aW9ucy5yZXRyeSA/PyBERUZBVUxUX1JFVFJZO1xuICAgIGlmIChyZXEubWV0aG9kID09PSBcIlBPU1RcIiAmJiBSRVNQT05TRVNfUEFUSFMuaGFzKHJvdXRlUGF0aCkpIHtcbiAgICAgIGF3YWl0IGhhbmRsZVJlc3BvbnNlcyhiYWNrZW5kLCByZXEsIHJlcywgcmV0cnkpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAocmVxLm1ldGhvZCA9PT0gXCJQT1NUXCIgJiYgUFJPWFlfUEFUSFMuaGFzKHJvdXRlUGF0aCkpIHtcbiAgICAgIGF3YWl0IGhhbmRsZVByb3h5KGJhY2tlbmQsIHJlcSwgcmVzLCByZXRyeSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHNlbmRKc29uKFxuICAgICAgcmVzLFxuICAgICAgNDA0LFxuICAgICAgZXJyb3JCb2R5KGB1bnN1cHBvcnRlZCByb3V0ZSAke3JlcS5tZXRob2QgPz8gXCI/XCJ9ICR7cm91dGVQYXRofWAsIFwiaW52YWxpZF9yZXF1ZXN0X2Vycm9yXCIpLFxuICAgICk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBlcnJvci5lcnJvck1lc3NhZ2UoZXJyKTtcbiAgICBsb2dnZXIuZXJyb3IoXCJyZXF1ZXN0IGZhaWxlZFwiLCB7IHBhdGg6IHJvdXRlUGF0aCwgZXJyb3I6IG1lc3NhZ2UgfSk7XG4gICAgaWYgKCFyZXMuaGVhZGVyc1NlbnQpIHNlbmRKc29uKHJlcywgNTAwLCBlcnJvckJvZHkobWVzc2FnZSwgXCJwcm94eV9lcnJvclwiKSk7XG4gICAgZWxzZSByZXMuZW5kKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBgR0VUIC92MS9tb2RlbHNgOiBzdXJmYWNlIHRoZSBzZXJ2aW5nIGNhdGFsb2d1ZS4gVHdvIHNoYXBlczpcbiAqXG4gKiAgIC0gT3BlbkFJIChkZWZhdWx0KTogYHtvYmplY3Q6XCJsaXN0XCIsIGRhdGE6W3tpZCxvYmplY3QsY3JlYXRlZCxvd25lZF9ieX1dfWAsXG4gKiAgICAgd2hhdCB0aGUgYG9wZW5haWAgU0RLIGFuZCBtb3N0IHRvb2xzIGV4cGVjdC5cbiAqICAgLSBDb2RleCAoYGNvZGV4U2hhcGVgKTogYHttb2RlbHM6W3tzbHVnLCBkaXNwbGF5X25hbWUsIOKApn1dfWAsIHRoZSBDaGF0R1BUXG4gKiAgICAgYmFja2VuZCBzaGFwZSB0aGUgQ29kZXggQ0xJIGRlY29kZXMuIEEgcmVzcG9uc2UgbWlzc2luZyB0aGUgdG9wLWxldmVsXG4gKiAgICAgYG1vZGVsc2AgZmllbGQgbWFrZXMgQ29kZXggbG9nIFwiZmFpbGVkIHRvIGRlY29kZSBtb2RlbHMgcmVzcG9uc2VcIiwgc28gaXRcbiAqICAgICBnZXRzIGl0cyBvd24gZW52ZWxvcGUuIE9ubHkgY2hhdCBlbmRwb2ludHMgYXJlIGFkdmVydGlzZWQgdG8gQ29kZXguXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGhhbmRsZU1vZGVscyhcbiAgYmFja2VuZDogRGF0YWJyaWNrc0JhY2tlbmQsXG4gIHJlczogU2VydmVyUmVzcG9uc2UsXG4gIGNvZGV4U2hhcGU6IGJvb2xlYW4sXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgZW5kcG9pbnRzID0gYXdhaXQgYmFja2VuZC5tb2RlbHModHJ1ZSk7XG4gIGlmIChjb2RleFNoYXBlKSB7XG4gICAgY29uc3QgbW9kZWxzID0gZW5kcG9pbnRzXG4gICAgICAuZmlsdGVyKChlbmRwb2ludCkgPT4gY2xhc3NpZnkuZW5kcG9pbnRDYXBhYmlsaXRpZXMoZW5kcG9pbnQpLmNoYXQpXG4gICAgICAubWFwKChlbmRwb2ludCkgPT4gKHtcbiAgICAgICAgc2x1ZzogZW5kcG9pbnQubmFtZSxcbiAgICAgICAgZGlzcGxheV9uYW1lOiBlbmRwb2ludC5kaXNwbGF5TmFtZSA/PyBlbmRwb2ludC5uYW1lLFxuICAgICAgICAuLi4oZW5kcG9pbnQuZGVzY3JpcHRpb24gPyB7IGRlc2NyaXB0aW9uOiBlbmRwb2ludC5kZXNjcmlwdGlvbiB9IDoge30pLFxuICAgICAgICAvLyBGaWVsZHMgQ29kZXgncyBzdHJpY3QgZGVjb2RlciByZXF1aXJlcyBvbiBldmVyeSBtb2RlbCBlbnRyeS5cbiAgICAgICAgZGVmYXVsdF9yZWFzb25pbmdfbGV2ZWw6IFwibWVkaXVtXCIsXG4gICAgICAgIHN1cHBvcnRlZF9yZWFzb25pbmdfbGV2ZWxzOiBbXSBhcyBzdHJpbmdbXSxcbiAgICAgICAgc2hlbGxfdHlwZTogXCJzaGVsbF9jb21tYW5kXCIsXG4gICAgICAgIHZpc2liaWxpdHk6IFwibGlzdFwiLFxuICAgICAgICBzdXBwb3J0ZWRfaW5fYXBpOiB0cnVlLFxuICAgICAgfSkpO1xuICAgIHNlbmRKc29uKHJlcywgMjAwLCB7IG1vZGVscyB9KTtcbiAgICByZXR1cm47XG4gIH1cbiAgY29uc3QgZGF0YSA9IGVuZHBvaW50cy5tYXAoKGVuZHBvaW50KSA9PiAoe1xuICAgIGlkOiBlbmRwb2ludC5uYW1lLFxuICAgIG9iamVjdDogXCJtb2RlbFwiLFxuICAgIGNyZWF0ZWQ6IDAsXG4gICAgb3duZWRfYnk6IFwiZGF0YWJyaWNrc1wiLFxuICB9KSk7XG4gIHNlbmRKc29uKHJlcywgMjAwLCB7IG9iamVjdDogXCJsaXN0XCIsIGRhdGEgfSk7XG59XG5cbi8qKlxuICogUmVzb2x2ZSB0aGUgcmVxdWVzdCdzIG1vZGVsIGFuZCBmb3J3YXJkIGEgQ2hhdCBDb21wbGV0aW9ucyBib2R5LiBSZXNwb25zZXMtXG4gKiBvbmx5IG1vZGVscyAoQ29kZXgpIGFyZSB0cmFuc2xhdGVkIHRvIGEgUmVzcG9uc2VzIHJlcXVlc3QgYW5kIHBvc3RlZCB0b1xuICogYC9zZXJ2aW5nLWVuZHBvaW50cy9yZXNwb25zZXNgOyBldmVyeXRoaW5nIGVsc2UgZ29lcyB0byBgL2ludm9jYXRpb25zYC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gaGFuZGxlUHJveHkoXG4gIGJhY2tlbmQ6IERhdGFicmlja3NCYWNrZW5kLFxuICByZXE6IEluY29taW5nTWVzc2FnZSxcbiAgcmVzOiBTZXJ2ZXJSZXNwb25zZSxcbiAgcmV0cnk6IFJldHJ5Q29uZmlnLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGJvZHkgPSBhd2FpdCByZWFkSnNvbkJvZHkocmVxKTtcbiAgY29uc3QgcmVxdWVzdGVkID0gdHlwZW9mIGJvZHkubW9kZWwgPT09IFwic3RyaW5nXCIgPyBib2R5Lm1vZGVsIDogdW5kZWZpbmVkO1xuICBpZiAoIXJlcXVlc3RlZCkge1xuICAgIHNlbmRKc29uKHJlcywgNDAwLCBlcnJvckJvZHkoXCJtaXNzaW5nICdtb2RlbCcgaW4gcmVxdWVzdCBib2R5XCIsIFwiaW52YWxpZF9yZXF1ZXN0X2Vycm9yXCIpKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCByZXNvbHZlZCA9IGF3YWl0IGJhY2tlbmQucmVzb2x2ZShyZXF1ZXN0ZWQpO1xuICBib2R5Lm1vZGVsID0gcmVzb2x2ZWQubW9kZWxJZDtcblxuICBpZiAoYmFja2VuZC5pc1Jlc3BvbnNlc09ubHkocmVzb2x2ZWQubW9kZWxJZCkpIHtcbiAgICBhd2FpdCBwcm94eUNoYXRWaWFSZXNwb25zZXMoXG4gICAgICBiYWNrZW5kLFxuICAgICAgYm9keSxcbiAgICAgIHJlcXVlc3RlZCxcbiAgICAgIHJlc29sdmVkLm1vZGVsSWQsXG4gICAgICByZXNvbHZlZC5tYXRjaGVkLFxuICAgICAgcmVzLFxuICAgICAgcmV0cnksXG4gICAgKTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBUaGlzIHJvdXRlIGZvcndhcmRzIHRoZSBjbGllbnQncyBib2R5IGFzLWlzLCBzbyBhbnl0aGluZyBEYXRhYnJpY2tzIHJlZnVzZXNcbiAgLy8gdG8gcGFyc2UgZmFpbHMgdGhlIHR1cm4uIERyb3AgdGhlIGtub3duIG9mZmVuZGVycyByYXRoZXIgdGhhbiByZWxheWluZyBhXG4gIC8vIDQwMCB0aGUgY2xpZW50IGNhbiBkbyBub3RoaW5nIGFib3V0LlxuICBjb25zdCBkcm9wcGVkID0gb3BlbmFpQ2hhdC5zdHJpcFVuc3VwcG9ydGVkQ2hhdEZpZWxkcyhib2R5LCBleHRyYURyb3BGaWVsZHMoKSk7XG5cbiAgY29uc3Qgd2FudHNTdHJlYW0gPSBib2R5LnN0cmVhbSA9PT0gdHJ1ZTtcbiAgY29uc3QgaGVhZGVycyA9IGF3YWl0IGJhY2tlbmQuYXV0aEhlYWRlcnMoKTtcbiAgaGVhZGVyc1tcImNvbnRlbnQtdHlwZVwiXSA9IFwiYXBwbGljYXRpb24vanNvblwiO1xuICBoZWFkZXJzLmFjY2VwdCA9IHdhbnRzU3RyZWFtID8gXCJ0ZXh0L2V2ZW50LXN0cmVhbVwiIDogXCJhcHBsaWNhdGlvbi9qc29uXCI7XG5cbiAgbG9nZ2VyLmluZm8oXCJwcm94eVwiLCB7XG4gICAgcmVxdWVzdGVkLFxuICAgIHJlc29sdmVkOiByZXNvbHZlZC5tb2RlbElkLFxuICAgIG1hdGNoZWQ6IHJlc29sdmVkLm1hdGNoZWQsXG4gICAgdXBzdHJlYW06IFwiaW52b2NhdGlvbnNcIixcbiAgICBzdHJlYW06IHdhbnRzU3RyZWFtLFxuICAgIC4uLihkcm9wcGVkLmxlbmd0aCA+IDAgPyB7IGRyb3BwZWQgfSA6IHt9KSxcbiAgfSk7XG5cbiAgY29uc3QgdXBzdHJlYW0gPSBhd2FpdCB1cHN0cmVhbUZldGNoUmV0cnlpbmcoXG4gICAgYmFja2VuZCxcbiAgICBiYWNrZW5kLmludm9jYXRpb25zVXJsKHJlc29sdmVkLm1vZGVsSWQpLFxuICAgIGhlYWRlcnMsXG4gICAgYm9keSxcbiAgICByZXMsXG4gICAgcmV0cnksXG4gICk7XG5cbiAgcmVzLndyaXRlSGVhZCh1cHN0cmVhbS5zdGF0dXMsIHtcbiAgICBcImNvbnRlbnQtdHlwZVwiOiB1cHN0cmVhbS5oZWFkZXJzLmdldChcImNvbnRlbnQtdHlwZVwiKSA/PyBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICBcIngtcmVzb2x2ZWQtbW9kZWxcIjogcmVzb2x2ZWQubW9kZWxJZCxcbiAgfSk7XG4gIGF3YWl0IHN0cmVhbUJvZHkodXBzdHJlYW0sIHJlcyk7XG59XG5cbi8qKlxuICogQ2hhdCBDb21wbGV0aW9ucyBjbGllbnQg4oaSIFJlc3BvbnNlcy1vbmx5IERhdGFicmlja3MgbW9kZWw6IHRyYW5zbGF0ZSB0aGVcbiAqIHJlcXVlc3QsIFBPU1QgdG8gYC9zZXJ2aW5nLWVuZHBvaW50cy9yZXNwb25zZXNgLCB0cmFuc2xhdGUgdGhlIHJlcGx5IGJhY2suXG4gKiBTdHJlYW1pbmcgaXMgbm90IHRyYW5zbGF0ZWQgeWV0IC0gdGhvc2UgY2xpZW50cyBzaG91bGQgdXNlIGAvdjEvcmVzcG9uc2VzYC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcHJveHlDaGF0VmlhUmVzcG9uc2VzKFxuICBiYWNrZW5kOiBEYXRhYnJpY2tzQmFja2VuZCxcbiAgYm9keTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIHJlcXVlc3RlZDogc3RyaW5nLFxuICBtb2RlbElkOiBzdHJpbmcsXG4gIG1hdGNoZWQ6IGJvb2xlYW4sXG4gIHJlczogU2VydmVyUmVzcG9uc2UsXG4gIHJldHJ5OiBSZXRyeUNvbmZpZyxcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB7IHJlc3BvbnNlcywgc3RyZWFtIH0gPSBjaGF0VG9SZXNwb25zZXNSZXF1ZXN0KGJvZHkpO1xuICByZXNwb25zZXMubW9kZWwgPSBtb2RlbElkO1xuXG4gIGlmIChzdHJlYW0pIHtcbiAgICBzZW5kSnNvbihcbiAgICAgIHJlcyxcbiAgICAgIDQwMCxcbiAgICAgIGVycm9yQm9keShcbiAgICAgICAgYG1vZGVsICR7bW9kZWxJZH0gb25seSBzdXBwb3J0cyB0aGUgUmVzcG9uc2VzIEFQSTsgdXNlIFBPU1QgL3YxL3Jlc3BvbnNlcyBmb3Igc3RyZWFtaW5nYCxcbiAgICAgICAgXCJpbnZhbGlkX3JlcXVlc3RfZXJyb3JcIixcbiAgICAgICksXG4gICAgKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBoZWFkZXJzID0gYXdhaXQgYmFja2VuZC5hdXRoSGVhZGVycygpO1xuICBoZWFkZXJzW1wiY29udGVudC10eXBlXCJdID0gXCJhcHBsaWNhdGlvbi9qc29uXCI7XG4gIGhlYWRlcnMuYWNjZXB0ID0gXCJhcHBsaWNhdGlvbi9qc29uXCI7XG5cbiAgY29uc3QgdXBzdHJlYW1VcmwgPSBiYWNrZW5kLnJlc3BvbnNlc1VybChtb2RlbElkKTtcbiAgY29uc3QgZm9yd2FyZCA9IHVwc3RyZWFtVXJsLmluY2x1ZGVzKFwiL29wZW4tcmVzcG9uc2VzXCIpXG4gICAgPyBzYW5pdGl6ZU9wZW5SZXNwb25zZXNSZXF1ZXN0KHJlc3BvbnNlcylcbiAgICA6IHJlc3BvbnNlcztcblxuICBsb2dnZXIuaW5mbyhcInByb3h5XCIsIHtcbiAgICByZXF1ZXN0ZWQsXG4gICAgcmVzb2x2ZWQ6IG1vZGVsSWQsXG4gICAgbWF0Y2hlZCxcbiAgICB1cHN0cmVhbTogdXBzdHJlYW1VcmwsXG4gICAgc3RyZWFtOiBmYWxzZSxcbiAgfSk7XG5cbiAgY29uc3QgdXBzdHJlYW0gPSBhd2FpdCB1cHN0cmVhbUZldGNoUmV0cnlpbmcoYmFja2VuZCwgdXBzdHJlYW1VcmwsIGhlYWRlcnMsIGZvcndhcmQsIHJlcywgcmV0cnkpO1xuXG4gIGlmICghdXBzdHJlYW0ub2spIHtcbiAgICBjb25zdCB0ZXh0ID0gYXdhaXQgdXBzdHJlYW0udGV4dCgpO1xuICAgIHJlcy53cml0ZUhlYWQodXBzdHJlYW0uc3RhdHVzLCB7IFwiY29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiIH0pO1xuICAgIHJlcy5lbmQodGV4dCB8fCBKU09OLnN0cmluZ2lmeShlcnJvckJvZHkoXCJ1cHN0cmVhbSBlcnJvclwiLCBcInByb3h5X2Vycm9yXCIpKSk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgcmVzcG9uc2VKc29uID0gKGF3YWl0IHVwc3RyZWFtLmpzb24oKSkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIHNlbmRKc29uKHJlcywgMjAwLCByZXNwb25zZVRvQ2hhdENvbXBsZXRpb24ocmVzcG9uc2VKc29uLCBtb2RlbElkKSk7XG59XG5cbi8qKlxuICogYFBPU1QgL3YxL3Jlc3BvbnNlc2A6IGZvcndhcmQgdGhlIFJlc3BvbnNlcyBib2R5IHRvIERhdGFicmlja3MnIG5hdGl2ZVxuICogUmVzcG9uc2VzIC8gT3BlbiBSZXNwb25zZXMgc3VyZmFjZSAobW9kZWwgc3RheXMgaW4gdGhlIGJvZHk7IFVSTCBpc1xuICogd29ya3NwYWNlLWxldmVsKS4gU3RyZWFtaW5nIGFuZCBub24tc3RyZWFtaW5nIGJvdGggcGFzcyB0aHJvdWdoIGFzLWlzLlxuICpcbiAqIE9wZW4gUmVzcG9uc2VzIChDbGF1ZGUvR2VtaW5pL+KApikgb25seSBhY2NlcHRzIGBmdW5jdGlvbmAgdG9vbHMgYW5kXG4gKiBgaW5wdXRfKmAgY29udGVudCBwYXJ0IHR5cGVzLCBhbmQgcmVqZWN0cyByZXBsYXllZCBDbGF1ZGUgdGhpbmtpbmdcbiAqIGJsb2NrcyDigJQgc28gQ29kZXgncyBidWlsdC1pbiB0b29scywgcHJpb3ItdHVybiBgb3V0cHV0X3RleHRgLCBhbmRcbiAqIGByZWRhY3RlZF90aGlua2luZ2AgLyBgdGhpbmtpbmdgIC8gYHJlYXNvbmluZ2AgcGFydHMgYXJlIHJld3JpdHRlbiBvclxuICogc3RyaXBwZWQgdGhlcmUuIFRoZSBPcGVuQUkgYC9yZXNwb25zZXNgIHBhdGgga2VlcHMgdGhlbSAtIEdQVCBzdXBwb3J0c1xuICogdGhvc2Ugc2hhcGVzLlxuICovXG5hc3luYyBmdW5jdGlvbiBoYW5kbGVSZXNwb25zZXMoXG4gIGJhY2tlbmQ6IERhdGFicmlja3NCYWNrZW5kLFxuICByZXE6IEluY29taW5nTWVzc2FnZSxcbiAgcmVzOiBTZXJ2ZXJSZXNwb25zZSxcbiAgcmV0cnk6IFJldHJ5Q29uZmlnLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGJvZHkgPSBhd2FpdCByZWFkSnNvbkJvZHkocmVxKTtcbiAgY29uc3QgcmVxdWVzdGVkID0gdHlwZW9mIGJvZHkubW9kZWwgPT09IFwic3RyaW5nXCIgPyBib2R5Lm1vZGVsIDogdW5kZWZpbmVkO1xuICBpZiAoIXJlcXVlc3RlZCkge1xuICAgIHNlbmRKc29uKHJlcywgNDAwLCBlcnJvckJvZHkoXCJtaXNzaW5nICdtb2RlbCcgaW4gcmVxdWVzdCBib2R5XCIsIFwiaW52YWxpZF9yZXF1ZXN0X2Vycm9yXCIpKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCByZXNvbHZlZCA9IGF3YWl0IGJhY2tlbmQucmVzb2x2ZShyZXF1ZXN0ZWQpO1xuICBib2R5Lm1vZGVsID0gcmVzb2x2ZWQubW9kZWxJZDtcblxuICBjb25zdCB1cHN0cmVhbVVybCA9IGJhY2tlbmQucmVzcG9uc2VzVXJsKHJlc29sdmVkLm1vZGVsSWQpO1xuICAvLyBDcm9zcy1wcm92aWRlciBPcGVuIFJlc3BvbnNlcyByZWplY3RzIG5vbi1mdW5jdGlvbiB0b29scyBhbmQgYG91dHB1dF8qYFxuICAvLyBjb250ZW50IHBhcnRzIGluIGBpbnB1dGA7IE9wZW5BSSBgL3Jlc3BvbnNlc2Aga2VlcHMgQ29kZXgncyBuYXRpdmUgc2hhcGVzLlxuICBjb25zdCBmb3J3YXJkID0gdXBzdHJlYW1VcmwuaW5jbHVkZXMoXCIvb3Blbi1yZXNwb25zZXNcIilcbiAgICA/IHNhbml0aXplT3BlblJlc3BvbnNlc1JlcXVlc3QoYm9keSlcbiAgICA6IGJvZHk7XG5cbiAgY29uc3Qgd2FudHNTdHJlYW0gPSBmb3J3YXJkLnN0cmVhbSA9PT0gdHJ1ZTtcbiAgY29uc3QgaGVhZGVycyA9IGF3YWl0IGJhY2tlbmQuYXV0aEhlYWRlcnMoKTtcbiAgaGVhZGVyc1tcImNvbnRlbnQtdHlwZVwiXSA9IFwiYXBwbGljYXRpb24vanNvblwiO1xuICBoZWFkZXJzLmFjY2VwdCA9IHdhbnRzU3RyZWFtID8gXCJ0ZXh0L2V2ZW50LXN0cmVhbVwiIDogXCJhcHBsaWNhdGlvbi9qc29uXCI7XG5cbiAgY29uc3Qgc3RyaXBwZWQgPVxuICAgIEFycmF5LmlzQXJyYXkoYm9keS50b29scykgJiZcbiAgICAoIUFycmF5LmlzQXJyYXkoZm9yd2FyZC50b29scykgfHwgZm9yd2FyZC50b29scy5sZW5ndGggIT09IGJvZHkudG9vbHMubGVuZ3RoKTtcblxuICBsb2dnZXIuaW5mbyhcInJlc3BvbnNlc1wiLCB7XG4gICAgcmVxdWVzdGVkLFxuICAgIHJlc29sdmVkOiByZXNvbHZlZC5tb2RlbElkLFxuICAgIG1hdGNoZWQ6IHJlc29sdmVkLm1hdGNoZWQsXG4gICAgdXBzdHJlYW06IHVwc3RyZWFtVXJsLFxuICAgIHN0cmVhbTogd2FudHNTdHJlYW0sXG4gICAgLi4uKHN0cmlwcGVkID8geyBzdHJpcHBlZE5vbkZ1bmN0aW9uVG9vbHM6IHRydWUgfSA6IHt9KSxcbiAgfSk7XG5cbiAgY29uc3QgdXBzdHJlYW0gPSBhd2FpdCB1cHN0cmVhbUZldGNoUmV0cnlpbmcoYmFja2VuZCwgdXBzdHJlYW1VcmwsIGhlYWRlcnMsIGZvcndhcmQsIHJlcywgcmV0cnkpO1xuXG4gIHJlcy53cml0ZUhlYWQodXBzdHJlYW0uc3RhdHVzLCB7XG4gICAgXCJjb250ZW50LXR5cGVcIjogdXBzdHJlYW0uaGVhZGVycy5nZXQoXCJjb250ZW50LXR5cGVcIikgPz8gXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgXCJ4LXJlc29sdmVkLW1vZGVsXCI6IHJlc29sdmVkLm1vZGVsSWQsXG4gIH0pO1xuICBhd2FpdCBzdHJlYW1Cb2R5KHVwc3RyZWFtLCByZXMpO1xufVxuXG4vKipcbiAqIFB1bXAgYW4gdXBzdHJlYW0gYGZldGNoYCBSZXNwb25zZSBib2R5IHRvIHRoZSBOb2RlIHJlc3BvbnNlLCBjaHVuayBieSBjaHVuay5cbiAqXG4gKiBBIG1pZC1zdHJlYW0gdXBzdHJlYW0gZmFpbHVyZSBpcyBsb2dnZWQgcmF0aGVyIHRoYW4gdGhyb3duOiB0aGUgc3RhdHVzIGxpbmVcbiAqIGFuZCBzb21lIG51bWJlciBvZiBjaHVua3MgaGF2ZSBhbHJlYWR5IGdvbmUgb3V0LCBzbyB0aGVyZSBpcyBubyB3YXkgbGVmdCB0b1xuICogdHVybiBpdCBpbnRvIGFuIEhUVFAgZXJyb3IgYW5kIHRoZSBvbmx5IGhvbmVzdCBtb3ZlIGlzIHRvIGVuZCB0aGUgcmVzcG9uc2VcbiAqIGFuZCBzYXkgd2h5IGluIHRoZSBsb2cuIFdpdGhvdXQgdGhpcyB0aGUgcmVhZCBsb29wIHJlamVjdGVkIGludG8gdGhlIGNhbGxlcidzXG4gKiBjYXRjaCwgd2hpY2ggZm91bmQgYGhlYWRlcnNTZW50YCBhbmQgZW5kZWQgdGhlIHJlc3BvbnNlIHNpbGVudGx5IC0gbWFraW5nIGFuXG4gKiB1cHN0cmVhbSB0ZWFyZG93biBpbmRpc3Rpbmd1aXNoYWJsZSBmcm9tIGEgY2xlYW4gZmluaXNoLlxuICovXG5hc3luYyBmdW5jdGlvbiBzdHJlYW1Cb2R5KHVwc3RyZWFtOiBSZXNwb25zZSwgcmVzOiBTZXJ2ZXJSZXNwb25zZSk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBib2R5ID0gdXBzdHJlYW0uYm9keTtcbiAgaWYgKCFib2R5KSB7XG4gICAgcmVzLmVuZCgpO1xuICAgIHJldHVybjtcbiAgfVxuICBjb25zdCByZWFkZXIgPSBib2R5LmdldFJlYWRlcigpO1xuICB0cnkge1xuICAgIGZvciAoOzspIHtcbiAgICAgIGNvbnN0IHsgZG9uZSwgdmFsdWUgfSA9IGF3YWl0IHJlYWRlci5yZWFkKCk7XG4gICAgICBpZiAoZG9uZSkgYnJlYWs7XG4gICAgICBpZiAodmFsdWUgJiYgIXJlcy53cml0YWJsZUVuZGVkKSByZXMud3JpdGUoQnVmZmVyLmZyb20odmFsdWUpKTtcbiAgICAgIGlmIChyZXMud3JpdGFibGVFbmRlZCkgYnJlYWs7XG4gICAgfVxuICB9IGNhdGNoIChlcnIpIHtcbiAgICAvLyBBbiBhYm9ydGVkIHJlcXVlc3QgaXMgdGhlIGV4cGVjdGVkIHNoYXBlIG9mIGEgY2xpZW50IGhhbmdpbmcgdXAsIG5vdCBhXG4gICAgLy8gZmF1bHQgd29ydGggcmVwb3J0aW5nIGF0IGVycm9yIGxldmVsLlxuICAgIGNvbnN0IGFib3J0ZWQgPSByZXMud3JpdGFibGVFbmRlZCB8fCAhcmVzLndyaXRhYmxlO1xuICAgIGxvZ2dlclthYm9ydGVkID8gXCJpbmZvXCIgOiBcImVycm9yXCJdKFwic3RyZWFtIGVuZGVkIGVhcmx5XCIsIHtcbiAgICAgIGVycm9yOiBlcnJvci5lcnJvck1lc3NhZ2UoZXJyKSxcbiAgICB9KTtcbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCByZWFkZXIuY2FuY2VsKCkuY2F0Y2goKCkgPT4ge30pO1xuICAgIHJlcy5lbmQoKTtcbiAgfVxufVxuXG4vKiogVHJ1ZSB3aGVuIHRoZSByZXF1ZXN0IGNhcnJpZXMgdGhlIGV4cGVjdGVkIGJlYXJlciB0b2tlbi4gKi9cbmZ1bmN0aW9uIGlzQXV0aG9yaXplZChyZXE6IEluY29taW5nTWVzc2FnZSwgYXBpS2V5OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgY29uc3QgaGVhZGVyID0gcmVxLmhlYWRlcnMuYXV0aG9yaXphdGlvbjtcbiAgaWYgKCFoZWFkZXIpIHJldHVybiBmYWxzZTtcbiAgcmV0dXJuIGhlYWRlci5yZXBsYWNlKC9eQmVhcmVyXFxzKy9pLCBcIlwiKS50cmltKCkgPT09IGFwaUtleTtcbn1cblxuLyoqXG4gKiBEcmFpbiBhIHJlcXVlc3QgYm9keSBhbmQgcGFyc2UgaXQgYXMgYSBKU09OIG9iamVjdC4gQW4gZW1wdHksIG1hbGZvcm1lZCwgb3JcbiAqIG5vbi1vYmplY3QgYm9keSB5aWVsZHMgYHt9YCwgd2hpY2ggdGhlIGNhbGxlcnMgcmVqZWN0IGFzIGEgbWlzc2luZyBgbW9kZWxgLlxuICovXG5hc3luYyBmdW5jdGlvbiByZWFkSnNvbkJvZHkocmVxOiBJbmNvbWluZ01lc3NhZ2UpOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIHVua25vd24+PiB7XG4gIGNvbnN0IGNodW5rczogQnVmZmVyW10gPSBbXTtcbiAgZm9yIGF3YWl0IChjb25zdCBjaHVuayBvZiByZXEpIHtcbiAgICBjaHVua3MucHVzaChCdWZmZXIuaXNCdWZmZXIoY2h1bmspID8gY2h1bmsgOiBCdWZmZXIuZnJvbShjaHVuayBhcyBVaW50OEFycmF5KSk7XG4gIH1cbiAgcmV0dXJuIGpzb24ucGFyc2VSZWNvcmQoQnVmZmVyLmNvbmNhdChjaHVua3MpLnRvU3RyaW5nKFwidXRmOFwiKSkgPz8ge307XG59XG5cbi8qKiBTZXJpYWxpemUgYW5kIHNlbmQgYSBKU09OIHJlc3BvbnNlLiAqL1xuZnVuY3Rpb24gc2VuZEpzb24ocmVzOiBTZXJ2ZXJSZXNwb25zZSwgc3RhdHVzOiBudW1iZXIsIGJvZHk6IHVua25vd24pOiB2b2lkIHtcbiAgcmVzLndyaXRlSGVhZChzdGF0dXMsIHsgXCJjb250ZW50LXR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIgfSk7XG4gIHJlcy5lbmQoSlNPTi5zdHJpbmdpZnkoYm9keSkpO1xufVxuXG4vKiogT3BlbkFJLXNoYXBlZCBlcnJvciBlbnZlbG9wZS4gKi9cbmZ1bmN0aW9uIGVycm9yQm9keShtZXNzYWdlOiBzdHJpbmcsIHR5cGU6IHN0cmluZyk6IHsgZXJyb3I6IHsgbWVzc2FnZTogc3RyaW5nOyB0eXBlOiBzdHJpbmcgfSB9IHtcbiAgcmV0dXJuIHsgZXJyb3I6IHsgbWVzc2FnZSwgdHlwZSB9IH07XG59XG4iXX0=
@@ -0,0 +1 @@
1
+ {"root":["../src/backend.ts","../src/cli.ts","../src/defaults.ts","../src/server.ts","../index.ts","../bin/dbx-tools-model-proxy.ts"],"version":"5.9.3"}