@dbx-tools/shared-model 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.
- package/lib/index.d.ts +14 -0
- package/lib/index.js +14 -0
- package/lib/src/classify.d.ts +111 -0
- package/lib/src/classify.js +261 -0
- package/lib/src/display.d.ts +19 -0
- package/lib/src/display.js +106 -0
- package/lib/src/model.d.ts +107 -0
- package/lib/src/model.js +123 -0
- package/lib/src/openai-chat.d.ts +108 -0
- package/lib/src/openai-chat.js +87 -0
- package/lib/src/openai-responses.d.ts +175 -0
- package/lib/src/openai-responses.js +686 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +10 -6
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI Responses API <-> Chat Completions translation.
|
|
3
|
+
*
|
|
4
|
+
* Some clients speak only the Responses API (`POST /v1/responses`) - the Codex
|
|
5
|
+
* CLI is the motivating one. Databricks now also exposes native Responses
|
|
6
|
+
* surfaces (`/serving-endpoints/responses` and `/serving-endpoints/open-responses`),
|
|
7
|
+
* while most endpoints still speak Chat Completions at `/invocations`. This
|
|
8
|
+
* module bridges the two, in both directions:
|
|
9
|
+
*
|
|
10
|
+
* - {@link responsesToChat} lowers a Responses request body to a chat
|
|
11
|
+
* completions body (instructions -> system message, typed `input` items ->
|
|
12
|
+
* `messages`, `tools`/`tool_choice` carried through, function-call outputs
|
|
13
|
+
* folded back into the transcript).
|
|
14
|
+
* - {@link chatToResponsesRequest} raises a chat-completions request into a
|
|
15
|
+
* Responses request (the inverse of {@link responsesToChat}), for routing a
|
|
16
|
+
* chat client at a Responses-only model like Codex.
|
|
17
|
+
* - {@link chatToResponse} lifts a non-streaming chat completion back into a
|
|
18
|
+
* Responses `response` object.
|
|
19
|
+
* - {@link responseToChatCompletion} lifts a native Responses `response`
|
|
20
|
+
* back into a chat-completions body (the inverse of {@link chatToResponse}).
|
|
21
|
+
* - {@link createResponsesStreamTranslator} lifts a streaming chat completion
|
|
22
|
+
* (an OpenAI SSE `chat.completion.chunk` stream) into the Responses SSE
|
|
23
|
+
* event stream those clients consume (`response.created`,
|
|
24
|
+
* `response.output_text.delta`, function-call argument deltas,
|
|
25
|
+
* `response.completed`).
|
|
26
|
+
* - {@link readResponsesOutput} reads the other direction: pull the answer
|
|
27
|
+
* text and citations out of a `response` object returned by an endpoint
|
|
28
|
+
* that speaks Responses natively (the Databricks native web-search tool).
|
|
29
|
+
* - {@link sanitizeResponsesTools} keeps only `function` tools on a Responses
|
|
30
|
+
* request body (for `/open-responses` / Anthropic, which reject Codex
|
|
31
|
+
* built-ins like `web_search`).
|
|
32
|
+
* - {@link sanitizeOpenResponsesInput} rewrites `output_*` content part types
|
|
33
|
+
* in `input` to `input_*`, and drops Claude thinking / reasoning blocks
|
|
34
|
+
* that Open Responses rejects on replay (`redacted_thinking`, …).
|
|
35
|
+
*
|
|
36
|
+
* Only the surface real clients exercise is translated; unknown fields are
|
|
37
|
+
* ignored rather than rejected, so a newer client degrades instead of breaking.
|
|
38
|
+
*
|
|
39
|
+
* Browser-safe: pure functions over plain JSON, no transport and no Node
|
|
40
|
+
* built-ins, so the same translation runs in a proxy, a server route, or a test.
|
|
41
|
+
*
|
|
42
|
+
* @module
|
|
43
|
+
*/
|
|
44
|
+
import { string } from "@dbx-tools/shared-core";
|
|
45
|
+
import { chatContentToText } from "./openai-chat.js";
|
|
46
|
+
/**
|
|
47
|
+
* Lower a Responses request body to a chat-completions body. Returns the chat
|
|
48
|
+
* body plus whether the caller asked for streaming (the server needs it to pick
|
|
49
|
+
* the upstream `accept` header and the translation path).
|
|
50
|
+
*/
|
|
51
|
+
export function responsesToChat(body) {
|
|
52
|
+
const messages = [];
|
|
53
|
+
// `instructions` becomes the leading system message.
|
|
54
|
+
if (typeof body.instructions === "string" && body.instructions.length > 0) {
|
|
55
|
+
messages.push({ role: "system", content: body.instructions });
|
|
56
|
+
}
|
|
57
|
+
// `input` is an array of typed items: messages, function_call, and
|
|
58
|
+
// function_call_output. Fold each into the chat transcript.
|
|
59
|
+
const input = Array.isArray(body.input) ? body.input : [];
|
|
60
|
+
for (const raw of input) {
|
|
61
|
+
if (!raw || typeof raw !== "object")
|
|
62
|
+
continue;
|
|
63
|
+
const item = raw;
|
|
64
|
+
const type = item.type;
|
|
65
|
+
if (type === "function_call") {
|
|
66
|
+
// A prior tool call the model made; re-attach it to an assistant turn.
|
|
67
|
+
messages.push({
|
|
68
|
+
role: "assistant",
|
|
69
|
+
content: null,
|
|
70
|
+
tool_calls: [toChatToolCall(item)],
|
|
71
|
+
});
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (type === "function_call_output") {
|
|
75
|
+
// The tool's result, keyed back to the call it answers.
|
|
76
|
+
messages.push({
|
|
77
|
+
role: "tool",
|
|
78
|
+
tool_call_id: String(item.call_id ?? item.id ?? ""),
|
|
79
|
+
content: typeof item.output === "string" ? item.output : chatContentToText(item.output),
|
|
80
|
+
});
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// Default: a message item with a role and typed content.
|
|
84
|
+
const role = typeof item.role === "string" ? item.role : "user";
|
|
85
|
+
// Chat has no "developer" role; treat it as system (its intent here).
|
|
86
|
+
const chatRole = role === "developer" ? "system" : role;
|
|
87
|
+
messages.push({ role: chatRole, content: chatContentToText(item.content) });
|
|
88
|
+
}
|
|
89
|
+
const chat = {
|
|
90
|
+
model: body.model,
|
|
91
|
+
messages,
|
|
92
|
+
stream: body.stream === true,
|
|
93
|
+
};
|
|
94
|
+
// Carry through function-calling config when present. Responses function
|
|
95
|
+
// tools are FLAT (`{type:"function", name, description, parameters}`); chat
|
|
96
|
+
// wants them NESTED (`{type:"function", function:{name, …}}`). Clients also
|
|
97
|
+
// send built-in tool types (local_shell, web_search, …) that Databricks chat
|
|
98
|
+
// rejects ("Missing 'function' in the tool specification"), so we translate
|
|
99
|
+
// only function tools and drop the rest.
|
|
100
|
+
if (Array.isArray(body.tools) && body.tools.length > 0) {
|
|
101
|
+
const chatTools = body.tools
|
|
102
|
+
.map(toChatTool)
|
|
103
|
+
.filter((t) => t !== undefined);
|
|
104
|
+
if (chatTools.length > 0) {
|
|
105
|
+
chat.tools = chatTools;
|
|
106
|
+
if (body.tool_choice !== undefined)
|
|
107
|
+
chat.tool_choice = body.tool_choice;
|
|
108
|
+
// NOTE: do NOT forward `parallel_tool_calls`. Clients send it, but
|
|
109
|
+
// Databricks Model Serving's chat API rejects unknown fields
|
|
110
|
+
// ("parallel_tool_calls: Extra inputs are not permitted"), which would
|
|
111
|
+
// fail the whole turn. Drop it.
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return { chat, stream: body.stream === true };
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Raise a chat-completions request into a Responses request body. Inverse of
|
|
118
|
+
* {@link responsesToChat}: used when a chat client hits a Responses-only
|
|
119
|
+
* Databricks model (e.g. Codex) so the proxy can POST to
|
|
120
|
+
* `/serving-endpoints/responses` without the client knowing.
|
|
121
|
+
*/
|
|
122
|
+
export function chatToResponsesRequest(body) {
|
|
123
|
+
const messages = Array.isArray(body.messages) ? body.messages : [];
|
|
124
|
+
const input = [];
|
|
125
|
+
let instructions;
|
|
126
|
+
for (const raw of messages) {
|
|
127
|
+
if (!raw || typeof raw !== "object")
|
|
128
|
+
continue;
|
|
129
|
+
const message = raw;
|
|
130
|
+
const role = typeof message.role === "string" ? message.role : "user";
|
|
131
|
+
// Leading system / developer messages become top-level `instructions`.
|
|
132
|
+
if ((role === "system" || role === "developer") &&
|
|
133
|
+
instructions === undefined &&
|
|
134
|
+
input.length === 0) {
|
|
135
|
+
const text = chatContentToText(message.content);
|
|
136
|
+
if (text)
|
|
137
|
+
instructions = text;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (role === "tool") {
|
|
141
|
+
input.push({
|
|
142
|
+
type: "function_call_output",
|
|
143
|
+
call_id: String(message.tool_call_id ?? ""),
|
|
144
|
+
output: chatContentToText(message.content),
|
|
145
|
+
});
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (role === "assistant" &&
|
|
149
|
+
Array.isArray(message.tool_calls) &&
|
|
150
|
+
message.tool_calls.length > 0) {
|
|
151
|
+
for (const rawCall of message.tool_calls) {
|
|
152
|
+
if (!rawCall || typeof rawCall !== "object")
|
|
153
|
+
continue;
|
|
154
|
+
input.push(toFunctionCallItem(rawCall));
|
|
155
|
+
}
|
|
156
|
+
const text = chatContentToText(message.content);
|
|
157
|
+
if (text) {
|
|
158
|
+
input.push({ type: "message", role: "assistant", content: text });
|
|
159
|
+
}
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
input.push({
|
|
163
|
+
type: "message",
|
|
164
|
+
role,
|
|
165
|
+
content: chatContentToText(message.content),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
const responses = {
|
|
169
|
+
model: body.model,
|
|
170
|
+
input,
|
|
171
|
+
stream: body.stream === true,
|
|
172
|
+
};
|
|
173
|
+
if (instructions)
|
|
174
|
+
responses.instructions = instructions;
|
|
175
|
+
// Chat tools are nested (`function: { name, … }`); Responses wants them flat.
|
|
176
|
+
if (Array.isArray(body.tools) && body.tools.length > 0) {
|
|
177
|
+
const tools = body.tools
|
|
178
|
+
.map(toResponsesTool)
|
|
179
|
+
.filter((t) => t !== undefined);
|
|
180
|
+
if (tools.length > 0) {
|
|
181
|
+
responses.tools = tools;
|
|
182
|
+
if (body.tool_choice !== undefined)
|
|
183
|
+
responses.tool_choice = body.tool_choice;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Prefer Responses' max_output_tokens naming; fall back from chat max_tokens.
|
|
187
|
+
if (typeof body.max_output_tokens === "number") {
|
|
188
|
+
responses.max_output_tokens = body.max_output_tokens;
|
|
189
|
+
}
|
|
190
|
+
else if (typeof body.max_tokens === "number") {
|
|
191
|
+
responses.max_output_tokens = body.max_tokens;
|
|
192
|
+
}
|
|
193
|
+
return { responses, stream: body.stream === true };
|
|
194
|
+
}
|
|
195
|
+
/** Lift a non-streaming chat completion JSON into a Responses `response` object. */
|
|
196
|
+
export function chatToResponse(chat, model) {
|
|
197
|
+
const choices = Array.isArray(chat.choices) ? chat.choices : [];
|
|
198
|
+
const first = (choices[0] ?? {});
|
|
199
|
+
const message = (first.message ?? {});
|
|
200
|
+
const output = [];
|
|
201
|
+
const text = typeof message.content === "string" ? message.content : "";
|
|
202
|
+
if (text) {
|
|
203
|
+
output.push({
|
|
204
|
+
type: "message",
|
|
205
|
+
role: "assistant",
|
|
206
|
+
content: [{ type: "output_text", text }],
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
// Surface any tool calls as Responses `function_call` output items.
|
|
210
|
+
const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
|
|
211
|
+
for (const raw of toolCalls) {
|
|
212
|
+
output.push(toFunctionCallItem(raw));
|
|
213
|
+
}
|
|
214
|
+
const usage = (chat.usage ?? {});
|
|
215
|
+
return {
|
|
216
|
+
id: String(chat.id ?? "resp"),
|
|
217
|
+
object: "response",
|
|
218
|
+
created_at: typeof chat.created === "number" ? chat.created : 0,
|
|
219
|
+
model,
|
|
220
|
+
status: "completed",
|
|
221
|
+
output,
|
|
222
|
+
usage: {
|
|
223
|
+
input_tokens: Number(usage.prompt_tokens ?? 0),
|
|
224
|
+
output_tokens: Number(usage.completion_tokens ?? 0),
|
|
225
|
+
total_tokens: Number(usage.total_tokens ?? 0),
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Lift a native Responses `response` object into a chat-completions body.
|
|
231
|
+
* Inverse of {@link chatToResponse}: used after a Responses-only upstream call
|
|
232
|
+
* when the client spoke Chat Completions.
|
|
233
|
+
*/
|
|
234
|
+
export function responseToChatCompletion(response, model) {
|
|
235
|
+
const { text } = readResponsesOutput(response);
|
|
236
|
+
const toolCalls = [];
|
|
237
|
+
const output = Array.isArray(response.output) ? response.output : [];
|
|
238
|
+
for (const raw of output) {
|
|
239
|
+
if (!raw || typeof raw !== "object")
|
|
240
|
+
continue;
|
|
241
|
+
const item = raw;
|
|
242
|
+
if (item.type !== "function_call")
|
|
243
|
+
continue;
|
|
244
|
+
toolCalls.push(toChatToolCall(item));
|
|
245
|
+
}
|
|
246
|
+
const message = {
|
|
247
|
+
role: "assistant",
|
|
248
|
+
content: text || null,
|
|
249
|
+
};
|
|
250
|
+
if (toolCalls.length > 0)
|
|
251
|
+
message.tool_calls = toolCalls;
|
|
252
|
+
const usage = (response.usage ?? {});
|
|
253
|
+
return {
|
|
254
|
+
id: String(response.id ?? "chatcmpl"),
|
|
255
|
+
object: "chat.completion",
|
|
256
|
+
created: typeof response.created_at === "number" ? response.created_at : 0,
|
|
257
|
+
model,
|
|
258
|
+
choices: [
|
|
259
|
+
{
|
|
260
|
+
index: 0,
|
|
261
|
+
message,
|
|
262
|
+
finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop",
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
usage: {
|
|
266
|
+
prompt_tokens: Number(usage.input_tokens ?? 0),
|
|
267
|
+
completion_tokens: Number(usage.output_tokens ?? 0),
|
|
268
|
+
total_tokens: Number(usage.total_tokens ?? 0),
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* A tool call's `arguments` JSON. Both wires carry it as an unparsed string;
|
|
274
|
+
* anything else (absent, an already-parsed object) becomes an empty literal so
|
|
275
|
+
* the receiving side always has valid JSON to parse.
|
|
276
|
+
*/
|
|
277
|
+
function callArguments(value) {
|
|
278
|
+
return typeof value === "string" ? value : "{}";
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* The Responses `function_call` item for a tool call in either spelling: a chat
|
|
282
|
+
* `tool_calls[]` entry (`{id, function:{name, arguments}}`) or an item that is
|
|
283
|
+
* already flat.
|
|
284
|
+
*/
|
|
285
|
+
function toFunctionCallItem(call) {
|
|
286
|
+
const fn = (call.function ?? call);
|
|
287
|
+
return {
|
|
288
|
+
type: "function_call",
|
|
289
|
+
call_id: String(call.call_id ?? call.id ?? ""),
|
|
290
|
+
name: String(fn.name ?? ""),
|
|
291
|
+
arguments: callArguments(fn.arguments),
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
/** The chat `tool_calls[]` entry for a Responses `function_call` item. */
|
|
295
|
+
function toChatToolCall(item) {
|
|
296
|
+
return {
|
|
297
|
+
id: String(item.call_id ?? item.id ?? ""),
|
|
298
|
+
type: "function",
|
|
299
|
+
function: {
|
|
300
|
+
name: String(item.name ?? ""),
|
|
301
|
+
arguments: callArguments(item.arguments),
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* The chat-nested spelling (`{type:"function", function:{name, …}}`) of a tool
|
|
307
|
+
* spec, or `undefined` for a built-in Responses tool (`web_search`,
|
|
308
|
+
* `local_shell`, …) that chat cannot express and Databricks rejects.
|
|
309
|
+
*/
|
|
310
|
+
function toChatTool(value) {
|
|
311
|
+
if (!value || typeof value !== "object")
|
|
312
|
+
return undefined;
|
|
313
|
+
const tool = value;
|
|
314
|
+
if (tool.type !== "function")
|
|
315
|
+
return undefined;
|
|
316
|
+
if (tool.function && typeof tool.function === "object")
|
|
317
|
+
return tool; // already nested
|
|
318
|
+
if (typeof tool.name !== "string")
|
|
319
|
+
return undefined;
|
|
320
|
+
return {
|
|
321
|
+
type: "function",
|
|
322
|
+
function: {
|
|
323
|
+
name: tool.name,
|
|
324
|
+
...(tool.description ? { description: tool.description } : {}),
|
|
325
|
+
...(tool.parameters ? { parameters: tool.parameters } : {}),
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* The flat Responses spelling (`{type:"function", name, …}`) of a tool spec.
|
|
331
|
+
* Inverse of {@link toChatTool}; non-function tools are dropped the same way.
|
|
332
|
+
*/
|
|
333
|
+
function toResponsesTool(value) {
|
|
334
|
+
if (!value || typeof value !== "object")
|
|
335
|
+
return undefined;
|
|
336
|
+
const tool = value;
|
|
337
|
+
if (tool.type !== "function")
|
|
338
|
+
return undefined;
|
|
339
|
+
if (tool.function && typeof tool.function === "object") {
|
|
340
|
+
const fn = tool.function;
|
|
341
|
+
return {
|
|
342
|
+
type: "function",
|
|
343
|
+
name: fn.name,
|
|
344
|
+
...(fn.description ? { description: fn.description } : {}),
|
|
345
|
+
...(fn.parameters ? { parameters: fn.parameters } : {}),
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
return typeof tool.name === "string" ? tool : undefined; // already flat
|
|
349
|
+
}
|
|
350
|
+
/** One Server-Sent Event, ready to write to the client. */
|
|
351
|
+
function sse(event, data) {
|
|
352
|
+
return `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Translate an upstream chat-completions SSE stream into the Responses SSE
|
|
356
|
+
* event stream a Responses client consumes.
|
|
357
|
+
*
|
|
358
|
+
* Upstream chunks are `chat.completion.chunk` objects whose `choices[0].delta`
|
|
359
|
+
* carries incremental `content` (assistant text) and/or `tool_calls` (function
|
|
360
|
+
* calls, streamed by `index` with partial `arguments`). We emit the Responses
|
|
361
|
+
* lifecycle around them:
|
|
362
|
+
*
|
|
363
|
+
* response.created
|
|
364
|
+
* -> per text run: output_item.added → output_text.delta* → output_item.done
|
|
365
|
+
* -> per tool call: output_item.added → function_call_arguments.delta*
|
|
366
|
+
* → function_call_arguments.done → output_item.done
|
|
367
|
+
* response.completed (with the assembled final `response` object)
|
|
368
|
+
*
|
|
369
|
+
* The translator is intentionally tolerant: malformed/keepalive lines yield
|
|
370
|
+
* nothing.
|
|
371
|
+
*/
|
|
372
|
+
export function createResponsesStreamTranslator(model, responseId) {
|
|
373
|
+
let started = false;
|
|
374
|
+
let outputIndex = 0;
|
|
375
|
+
// Text run state: whether a message item is currently open, and its buffer.
|
|
376
|
+
let textOpen = false;
|
|
377
|
+
let textBuffer = "";
|
|
378
|
+
let textItemId = "";
|
|
379
|
+
const tools = new Map();
|
|
380
|
+
const created = () => sse("response.created", {
|
|
381
|
+
type: "response.created",
|
|
382
|
+
response: { id: responseId, object: "response", status: "in_progress", model, output: [] },
|
|
383
|
+
});
|
|
384
|
+
function openText() {
|
|
385
|
+
textOpen = true;
|
|
386
|
+
textItemId = `${responseId}-msg-${outputIndex}`;
|
|
387
|
+
const ev = sse("response.output_item.added", {
|
|
388
|
+
type: "response.output_item.added",
|
|
389
|
+
output_index: outputIndex,
|
|
390
|
+
item: { id: textItemId, type: "message", role: "assistant", content: [] },
|
|
391
|
+
});
|
|
392
|
+
return ev;
|
|
393
|
+
}
|
|
394
|
+
function closeText() {
|
|
395
|
+
if (!textOpen)
|
|
396
|
+
return "";
|
|
397
|
+
const item = {
|
|
398
|
+
id: textItemId,
|
|
399
|
+
type: "message",
|
|
400
|
+
role: "assistant",
|
|
401
|
+
content: [{ type: "output_text", text: textBuffer }],
|
|
402
|
+
};
|
|
403
|
+
const ev = sse("response.output_text.done", {
|
|
404
|
+
type: "response.output_text.done",
|
|
405
|
+
item_id: textItemId,
|
|
406
|
+
output_index: outputIndex,
|
|
407
|
+
content_index: 0,
|
|
408
|
+
text: textBuffer,
|
|
409
|
+
}) +
|
|
410
|
+
sse("response.output_item.done", {
|
|
411
|
+
type: "response.output_item.done",
|
|
412
|
+
output_index: outputIndex,
|
|
413
|
+
item,
|
|
414
|
+
});
|
|
415
|
+
textOpen = false;
|
|
416
|
+
textBuffer = "";
|
|
417
|
+
outputIndex += 1;
|
|
418
|
+
return ev;
|
|
419
|
+
}
|
|
420
|
+
function feed(chunk) {
|
|
421
|
+
let out = "";
|
|
422
|
+
if (!started) {
|
|
423
|
+
started = true;
|
|
424
|
+
out += created();
|
|
425
|
+
}
|
|
426
|
+
const choices = Array.isArray(chunk.choices) ? chunk.choices : [];
|
|
427
|
+
const choice = (choices[0] ?? {});
|
|
428
|
+
const delta = (choice.delta ?? {});
|
|
429
|
+
// Assistant text deltas.
|
|
430
|
+
if (typeof delta.content === "string" && delta.content.length > 0) {
|
|
431
|
+
if (!textOpen)
|
|
432
|
+
out += openText();
|
|
433
|
+
textBuffer += delta.content;
|
|
434
|
+
out += sse("response.output_text.delta", {
|
|
435
|
+
type: "response.output_text.delta",
|
|
436
|
+
item_id: textItemId,
|
|
437
|
+
output_index: outputIndex,
|
|
438
|
+
content_index: 0,
|
|
439
|
+
delta: delta.content,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
// Tool-call deltas: each is keyed by `index`; `arguments` arrives in pieces.
|
|
443
|
+
const toolDeltas = Array.isArray(delta.tool_calls) ? delta.tool_calls : [];
|
|
444
|
+
for (const rawTc of toolDeltas) {
|
|
445
|
+
const tc = rawTc;
|
|
446
|
+
const idx = Number(tc.index ?? 0);
|
|
447
|
+
const fn = (tc.function ?? {});
|
|
448
|
+
let state = tools.get(idx);
|
|
449
|
+
if (!state) {
|
|
450
|
+
// First fragment for this call: a text run (if open) must close first so
|
|
451
|
+
// output ordering stays monotonic, then we open a function_call item.
|
|
452
|
+
out += closeText();
|
|
453
|
+
state = {
|
|
454
|
+
outputIndex,
|
|
455
|
+
callId: String(tc.id ?? `${responseId}-call-${idx}`),
|
|
456
|
+
name: String(fn.name ?? ""),
|
|
457
|
+
args: "",
|
|
458
|
+
};
|
|
459
|
+
tools.set(idx, state);
|
|
460
|
+
out += sse("response.output_item.added", {
|
|
461
|
+
type: "response.output_item.added",
|
|
462
|
+
output_index: state.outputIndex,
|
|
463
|
+
item: {
|
|
464
|
+
id: state.callId,
|
|
465
|
+
type: "function_call",
|
|
466
|
+
call_id: state.callId,
|
|
467
|
+
name: state.name,
|
|
468
|
+
arguments: "",
|
|
469
|
+
},
|
|
470
|
+
});
|
|
471
|
+
outputIndex += 1;
|
|
472
|
+
}
|
|
473
|
+
if (typeof fn.name === "string" && fn.name && !state.name)
|
|
474
|
+
state.name = fn.name;
|
|
475
|
+
if (typeof fn.arguments === "string" && fn.arguments.length > 0) {
|
|
476
|
+
state.args += fn.arguments;
|
|
477
|
+
out += sse("response.function_call_arguments.delta", {
|
|
478
|
+
type: "response.function_call_arguments.delta",
|
|
479
|
+
item_id: state.callId,
|
|
480
|
+
output_index: state.outputIndex,
|
|
481
|
+
delta: fn.arguments,
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return out;
|
|
486
|
+
}
|
|
487
|
+
function finish() {
|
|
488
|
+
let out = closeText();
|
|
489
|
+
// Close any open tool calls, emitting their assembled arguments.
|
|
490
|
+
for (const state of tools.values()) {
|
|
491
|
+
out += sse("response.function_call_arguments.done", {
|
|
492
|
+
type: "response.function_call_arguments.done",
|
|
493
|
+
item_id: state.callId,
|
|
494
|
+
output_index: state.outputIndex,
|
|
495
|
+
arguments: state.args,
|
|
496
|
+
});
|
|
497
|
+
out += sse("response.output_item.done", {
|
|
498
|
+
type: "response.output_item.done",
|
|
499
|
+
output_index: state.outputIndex,
|
|
500
|
+
item: {
|
|
501
|
+
id: state.callId,
|
|
502
|
+
type: "function_call",
|
|
503
|
+
call_id: state.callId,
|
|
504
|
+
name: state.name,
|
|
505
|
+
arguments: state.args,
|
|
506
|
+
},
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
out += sse("response.completed", {
|
|
510
|
+
type: "response.completed",
|
|
511
|
+
response: { id: responseId, object: "response", status: "completed", model },
|
|
512
|
+
});
|
|
513
|
+
return out;
|
|
514
|
+
}
|
|
515
|
+
return { feed, finish };
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Read the answer text and cited sources out of a Responses `response` payload.
|
|
519
|
+
*
|
|
520
|
+
* This is the inverse of {@link chatToResponse}: it consumes what an endpoint
|
|
521
|
+
* speaking Responses natively returns, rather than producing it. The Databricks
|
|
522
|
+
* native web-search tool answers this way, with each source attached as a
|
|
523
|
+
* `url_citation` annotation on the content part that used it.
|
|
524
|
+
*
|
|
525
|
+
* Prefers the flattened `output_text` when the payload carries it, and falls
|
|
526
|
+
* back to walking `output[].content[].text`. Every field is optional upstream,
|
|
527
|
+
* so a payload missing any of it yields empty results rather than throwing.
|
|
528
|
+
*/
|
|
529
|
+
export function readResponsesOutput(payload) {
|
|
530
|
+
const output = Array.isArray(payload.output) ? payload.output : [];
|
|
531
|
+
const texts = [];
|
|
532
|
+
const citations = [];
|
|
533
|
+
const seen = new Set();
|
|
534
|
+
for (const rawItem of output) {
|
|
535
|
+
if (!rawItem || typeof rawItem !== "object")
|
|
536
|
+
continue;
|
|
537
|
+
const content = rawItem.content;
|
|
538
|
+
if (!Array.isArray(content))
|
|
539
|
+
continue;
|
|
540
|
+
for (const rawPart of content) {
|
|
541
|
+
if (!rawPart || typeof rawPart !== "object")
|
|
542
|
+
continue;
|
|
543
|
+
const part = rawPart;
|
|
544
|
+
const text = string.trimToEmpty(part.text);
|
|
545
|
+
if (text)
|
|
546
|
+
texts.push(text);
|
|
547
|
+
const annotations = Array.isArray(part.annotations) ? part.annotations : [];
|
|
548
|
+
for (const rawAnn of annotations) {
|
|
549
|
+
if (!rawAnn || typeof rawAnn !== "object")
|
|
550
|
+
continue;
|
|
551
|
+
const ann = rawAnn;
|
|
552
|
+
const url = string.trimToEmpty(ann.url);
|
|
553
|
+
if (!url || seen.has(url))
|
|
554
|
+
continue;
|
|
555
|
+
seen.add(url);
|
|
556
|
+
const title = string.trimToEmpty(ann.title);
|
|
557
|
+
citations.push({ url, ...(title ? { title } : {}) });
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return { text: string.trimToEmpty(payload.output_text) || texts.join("\n").trim(), citations };
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* Strip tool types the upstream model doesn't support from a Responses request
|
|
565
|
+
* body, returning a shallow copy safe to forward (the input is not mutated).
|
|
566
|
+
*
|
|
567
|
+
* Clients like the Codex CLI include built-in Responses tools (`web_search`,
|
|
568
|
+
* `local_shell`, `custom`, ...) alongside their `function` tools. Databricks'
|
|
569
|
+
* Open Responses surface for Anthropic/Claude (and other non-OpenAI providers)
|
|
570
|
+
* only accepts `function` tools and hard-errors otherwise:
|
|
571
|
+
* "Anthropic does not support tool type 'web_search'. Only 'function' is supported."
|
|
572
|
+
* Call this before forwarding to `/serving-endpoints/open-responses`. The OpenAI
|
|
573
|
+
* `/serving-endpoints/responses` path should keep built-ins (GPT supports them).
|
|
574
|
+
* If filtering empties the list, `tools` / `tool_choice` / `parallel_tool_calls`
|
|
575
|
+
* are dropped so we never send an empty `tools: []`.
|
|
576
|
+
*/
|
|
577
|
+
export function sanitizeResponsesTools(body) {
|
|
578
|
+
if (!Array.isArray(body.tools) || body.tools.length === 0)
|
|
579
|
+
return body;
|
|
580
|
+
const fnTools = body.tools.filter((t) => t && typeof t === "object" && t.type === "function");
|
|
581
|
+
if (fnTools.length === body.tools.length)
|
|
582
|
+
return body; // nothing to strip
|
|
583
|
+
const next = { ...body };
|
|
584
|
+
if (fnTools.length > 0) {
|
|
585
|
+
next.tools = fnTools;
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
delete next.tools;
|
|
589
|
+
delete next.tool_choice;
|
|
590
|
+
delete next.parallel_tool_calls;
|
|
591
|
+
}
|
|
592
|
+
return next;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Content-part / input-item types Claude extended thinking uses on the wire.
|
|
596
|
+
*
|
|
597
|
+
* Shared so both wire surfaces strip the same set: the Responses path here
|
|
598
|
+
* ({@link sanitizeOpenResponsesInput}) and the Chat Completions path in
|
|
599
|
+
* `@dbx-tools/appkit-mastra`'s serving sanitize. Anthropic signs these blocks,
|
|
600
|
+
* so a replay that mutates one is rejected outright - both paths must agree on
|
|
601
|
+
* what counts as a reasoning block.
|
|
602
|
+
*/
|
|
603
|
+
export const REASONING_TYPES = new Set([
|
|
604
|
+
"reasoning",
|
|
605
|
+
"thinking",
|
|
606
|
+
"redacted_thinking",
|
|
607
|
+
]);
|
|
608
|
+
/**
|
|
609
|
+
* Rewrite Responses `input` so Open Responses will accept it.
|
|
610
|
+
*
|
|
611
|
+
* Two OpenAI / Codex shapes that Databricks Open Responses (Claude, Gemini, …)
|
|
612
|
+
* reject:
|
|
613
|
+
*
|
|
614
|
+
* 1. Prior assistant turns with `output_text` / `output_*` content parts —
|
|
615
|
+
* Open Responses only allows `input_text`, `input_image`, `input_file`,
|
|
616
|
+
* `input_audio`. Map every `output_<kind>` part to `input_<kind>`.
|
|
617
|
+
* 2. Replayed extended-thinking blocks (`thinking`, `redacted_thinking`,
|
|
618
|
+
* `reasoning` content parts, and top-level `reasoning` input items). Claude
|
|
619
|
+
* signs those; any client round-trip that mutates them (or a cross-provider
|
|
620
|
+
* replay) fails with e.g.
|
|
621
|
+
* "messages.N.content.M: Invalid `data` in `redacted_thinking` block"
|
|
622
|
+
* Strip them — the UI/client already showed the thinking; replay does not
|
|
623
|
+
* need the signed blob. Same policy as appkit-mastra's serving sanitize.
|
|
624
|
+
*
|
|
625
|
+
* Returns a shallow copy when anything changes; otherwise the input body.
|
|
626
|
+
*/
|
|
627
|
+
export function sanitizeOpenResponsesInput(body) {
|
|
628
|
+
if (!Array.isArray(body.input) || body.input.length === 0)
|
|
629
|
+
return body;
|
|
630
|
+
let changed = false;
|
|
631
|
+
const input = [];
|
|
632
|
+
for (const raw of body.input) {
|
|
633
|
+
if (!raw || typeof raw !== "object") {
|
|
634
|
+
input.push(raw);
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
const item = raw;
|
|
638
|
+
// Top-level Responses reasoning items (not message content parts).
|
|
639
|
+
if (typeof item.type === "string" && REASONING_TYPES.has(item.type)) {
|
|
640
|
+
changed = true;
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
if (!Array.isArray(item.content)) {
|
|
644
|
+
input.push(raw);
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
let partChanged = false;
|
|
648
|
+
const content = [];
|
|
649
|
+
for (const part of item.content) {
|
|
650
|
+
if (!part || typeof part !== "object") {
|
|
651
|
+
content.push(part);
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
const p = part;
|
|
655
|
+
if (typeof p.type === "string" && REASONING_TYPES.has(p.type)) {
|
|
656
|
+
partChanged = true;
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
if (typeof p.type === "string" && p.type.startsWith("output_")) {
|
|
660
|
+
partChanged = true;
|
|
661
|
+
content.push({ ...p, type: `input_${p.type.slice("output_".length)}` });
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
content.push(part);
|
|
665
|
+
}
|
|
666
|
+
if (!partChanged) {
|
|
667
|
+
input.push(raw);
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
changed = true;
|
|
671
|
+
// Drop assistant turns that only carried thinking (nothing left to replay).
|
|
672
|
+
if (content.length === 0 && item.role === "assistant")
|
|
673
|
+
continue;
|
|
674
|
+
input.push({ ...item, content });
|
|
675
|
+
}
|
|
676
|
+
return changed ? { ...body, input } : body;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Full Open Responses request sanitizer: strip non-`function` tools, rewrite
|
|
680
|
+
* `output_*` content parts, and drop thinking / reasoning blocks. Safe no-op
|
|
681
|
+
* when nothing needs changing.
|
|
682
|
+
*/
|
|
683
|
+
export function sanitizeOpenResponsesRequest(body) {
|
|
684
|
+
return sanitizeOpenResponsesInput(sanitizeResponsesTools(body));
|
|
685
|
+
}
|
|
686
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlbmFpLXJlc3BvbnNlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9vcGVuYWktcmVzcG9uc2VzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EwQ0c7QUFFSCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFaEQsT0FBTyxFQUF1QyxpQkFBaUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUV2Rjs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FBQyxJQUE2QjtJQUkzRCxNQUFNLFFBQVEsR0FBa0IsRUFBRSxDQUFDO0lBRW5DLHFEQUFxRDtJQUNyRCxJQUFJLE9BQU8sSUFBSSxDQUFDLFlBQVksS0FBSyxRQUFRLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDMUUsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUFDO0lBQ2hFLENBQUM7SUFFRCxtRUFBbUU7SUFDbkUsNERBQTREO0lBQzVELE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDMUQsS0FBSyxNQUFNLEdBQUcsSUFBSSxLQUFLLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsR0FBRyxJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVE7WUFBRSxTQUFTO1FBQzlDLE1BQU0sSUFBSSxHQUFHLEdBQThCLENBQUM7UUFDNUMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztRQUV2QixJQUFJLElBQUksS0FBSyxlQUFlLEVBQUUsQ0FBQztZQUM3Qix1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TUFBTSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ3hFLFNBQVM7WUFDWCxDQUFDO1lBQ0QsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNyQixDQUFDO1FBRUQsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ2pCLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDaEIsU0FBUztRQUNYLENBQUM7UUFDRCxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ2YsNEVBQTRFO1FBQzVFLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksS0FBSyxXQUFXO1lBQUUsU0FBUztRQUNoRSxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBRUQsT0FBTyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztBQUM3QyxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSw0QkFBNEIsQ0FDMUMsSUFBNkI7SUFFN0IsT0FBTywwQkFBMEIsQ0FBQyxzQkFBc0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0FBQ2xFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE9wZW5BSSBSZXNwb25zZXMgQVBJIDwtPiBDaGF0IENvbXBsZXRpb25zIHRyYW5zbGF0aW9uLlxuICpcbiAqIFNvbWUgY2xpZW50cyBzcGVhayBvbmx5IHRoZSBSZXNwb25zZXMgQVBJIChgUE9TVCAvdjEvcmVzcG9uc2VzYCkgLSB0aGUgQ29kZXhcbiAqIENMSSBpcyB0aGUgbW90aXZhdGluZyBvbmUuIERhdGFicmlja3Mgbm93IGFsc28gZXhwb3NlcyBuYXRpdmUgUmVzcG9uc2VzXG4gKiBzdXJmYWNlcyAoYC9zZXJ2aW5nLWVuZHBvaW50cy9yZXNwb25zZXNgIGFuZCBgL3NlcnZpbmctZW5kcG9pbnRzL29wZW4tcmVzcG9uc2VzYCksXG4gKiB3aGlsZSBtb3N0IGVuZHBvaW50cyBzdGlsbCBzcGVhayBDaGF0IENvbXBsZXRpb25zIGF0IGAvaW52b2NhdGlvbnNgLiBUaGlzXG4gKiBtb2R1bGUgYnJpZGdlcyB0aGUgdHdvLCBpbiBib3RoIGRpcmVjdGlvbnM6XG4gKlxuICogICAtIHtAbGluayByZXNwb25zZXNUb0NoYXR9IGxvd2VycyBhIFJlc3BvbnNlcyByZXF1ZXN0IGJvZHkgdG8gYSBjaGF0XG4gKiAgICAgY29tcGxldGlvbnMgYm9keSAoaW5zdHJ1Y3Rpb25zIC0+IHN5c3RlbSBtZXNzYWdlLCB0eXBlZCBgaW5wdXRgIGl0ZW1zIC0+XG4gKiAgICAgYG1lc3NhZ2VzYCwgYHRvb2xzYC9gdG9vbF9jaG9pY2VgIGNhcnJpZWQgdGhyb3VnaCwgZnVuY3Rpb24tY2FsbCBvdXRwdXRzXG4gKiAgICAgZm9sZGVkIGJhY2sgaW50byB0aGUgdHJhbnNjcmlwdCkuXG4gKiAgIC0ge0BsaW5rIGNoYXRUb1Jlc3BvbnNlc1JlcXVlc3R9IHJhaXNlcyBhIGNoYXQtY29tcGxldGlvbnMgcmVxdWVzdCBpbnRvIGFcbiAqICAgICBSZXNwb25zZXMgcmVxdWVzdCAodGhlIGludmVyc2Ugb2Yge0BsaW5rIHJlc3BvbnNlc1RvQ2hhdH0pLCBmb3Igcm91dGluZyBhXG4gKiAgICAgY2hhdCBjbGllbnQgYXQgYSBSZXNwb25zZXMtb25seSBtb2RlbCBsaWtlIENvZGV4LlxuICogICAtIHtAbGluayBjaGF0VG9SZXNwb25zZX0gbGlmdHMgYSBub24tc3RyZWFtaW5nIGNoYXQgY29tcGxldGlvbiBiYWNrIGludG8gYVxuICogICAgIFJlc3BvbnNlcyBgcmVzcG9uc2VgIG9iamVjdC5cbiAqICAgLSB7QGxpbmsgcmVzcG9uc2VUb0NoYXRDb21wbGV0aW9ufSBsaWZ0cyBhIG5hdGl2ZSBSZXNwb25zZXMgYHJlc3BvbnNlYFxuICogICAgIGJhY2sgaW50byBhIGNoYXQtY29tcGxldGlvbnMgYm9keSAodGhlIGludmVyc2Ugb2Yge0BsaW5rIGNoYXRUb1Jlc3BvbnNlfSkuXG4gKiAgIC0ge0BsaW5rIGNyZWF0ZVJlc3BvbnNlc1N0cmVhbVRyYW5zbGF0b3J9IGxpZnRzIGEgc3RyZWFtaW5nIGNoYXQgY29tcGxldGlvblxuICogICAgIChhbiBPcGVuQUkgU1NFIGBjaGF0LmNvbXBsZXRpb24uY2h1bmtgIHN0cmVhbSkgaW50byB0aGUgUmVzcG9uc2VzIFNTRVxuICogICAgIGV2ZW50IHN0cmVhbSB0aG9zZSBjbGllbnRzIGNvbnN1bWUgKGByZXNwb25zZS5jcmVhdGVkYCxcbiAqICAgICBgcmVzcG9uc2Uub3V0cHV0X3RleHQuZGVsdGFgLCBmdW5jdGlvbi1jYWxsIGFyZ3VtZW50IGRlbHRhcyxcbiAqICAgICBgcmVzcG9uc2UuY29tcGxldGVkYCkuXG4gKiAgIC0ge0BsaW5rIHJlYWRSZXNwb25zZXNPdXRwdXR9IHJlYWRzIHRoZSBvdGhlciBkaXJlY3Rpb246IHB1bGwgdGhlIGFuc3dlclxuICogICAgIHRleHQgYW5kIGNpdGF0aW9ucyBvdXQgb2YgYSBgcmVzcG9uc2VgIG9iamVjdCByZXR1cm5lZCBieSBhbiBlbmRwb2ludFxuICogICAgIHRoYXQgc3BlYWtzIFJlc3BvbnNlcyBuYXRpdmVseSAodGhlIERhdGFicmlja3MgbmF0aXZlIHdlYi1zZWFyY2ggdG9vbCkuXG4gKiAgIC0ge0BsaW5rIHNhbml0aXplUmVzcG9uc2VzVG9vbHN9IGtlZXBzIG9ubHkgYGZ1bmN0aW9uYCB0b29scyBvbiBhIFJlc3BvbnNlc1xuICogICAgIHJlcXVlc3QgYm9keSAoZm9yIGAvb3Blbi1yZXNwb25zZXNgIC8gQW50aHJvcGljLCB3aGljaCByZWplY3QgQ29kZXhcbiAqICAgICBidWlsdC1pbnMgbGlrZSBgd2ViX3NlYXJjaGApLlxuICogICAtIHtAbGluayBzYW5pdGl6ZU9wZW5SZXNwb25zZXNJbnB1dH0gcmV3cml0ZXMgYG91dHB1dF8qYCBjb250ZW50IHBhcnQgdHlwZXNcbiAqICAgICBpbiBgaW5wdXRgIHRvIGBpbnB1dF8qYCwgYW5kIGRyb3BzIENsYXVkZSB0aGlua2luZyAvIHJlYXNvbmluZyBibG9ja3NcbiAqICAgICB0aGF0IE9wZW4gUmVzcG9uc2VzIHJlamVjdHMgb24gcmVwbGF5IChgcmVkYWN0ZWRfdGhpbmtpbmdgLCDigKYpLlxuICpcbiAqIE9ubHkgdGhlIHN1cmZhY2UgcmVhbCBjbGllbnRzIGV4ZXJjaXNlIGlzIHRyYW5zbGF0ZWQ7IHVua25vd24gZmllbGRzIGFyZVxuICogaWdub3JlZCByYXRoZXIgdGhhbiByZWplY3RlZCwgc28gYSBuZXdlciBjbGllbnQgZGVncmFkZXMgaW5zdGVhZCBvZiBicmVha2luZy5cbiAqXG4gKiBCcm93c2VyLXNhZmU6IHB1cmUgZnVuY3Rpb25zIG92ZXIgcGxhaW4gSlNPTiwgbm8gdHJhbnNwb3J0IGFuZCBubyBOb2RlXG4gKiBidWlsdC1pbnMsIHNvIHRoZSBzYW1lIHRyYW5zbGF0aW9uIHJ1bnMgaW4gYSBwcm94eSwgYSBzZXJ2ZXIgcm91dGUsIG9yIGEgdGVzdC5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgc3RyaW5nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcblxuaW1wb3J0IHsgdHlwZSBDaGF0TWVzc2FnZSwgdHlwZSBDaGF0VG9vbENhbGwsIGNoYXRDb250ZW50VG9UZXh0IH0gZnJvbSBcIi4vb3BlbmFpLWNoYXRcIjtcblxuLyoqXG4gKiBMb3dlciBhIFJlc3BvbnNlcyByZXF1ZXN0IGJvZHkgdG8gYSBjaGF0LWNvbXBsZXRpb25zIGJvZHkuIFJldHVybnMgdGhlIGNoYXRcbiAqIGJvZHkgcGx1cyB3aGV0aGVyIHRoZSBjYWxsZXIgYXNrZWQgZm9yIHN0cmVhbWluZyAodGhlIHNlcnZlciBuZWVkcyBpdCB0byBwaWNrXG4gKiB0aGUgdXBzdHJlYW0gYGFjY2VwdGAgaGVhZGVyIGFuZCB0aGUgdHJhbnNsYXRpb24gcGF0aCkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNwb25zZXNUb0NoYXQoYm9keTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiB7XG4gIGNoYXQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBzdHJlYW06IGJvb2xlYW47XG59IHtcbiAgY29uc3QgbWVzc2FnZXM6IENoYXRNZXNzYWdlW10gPSBbXTtcblxuICAvLyBgaW5zdHJ1Y3Rpb25zYCBiZWNvbWVzIHRoZSBsZWFkaW5nIHN5c3RlbSBtZXNzYWdlLlxuICBpZiAodHlwZW9mIGJvZHkuaW5zdHJ1Y3Rpb25zID09PSBcInN0cmluZ1wiICYmIGJvZHkuaW5zdHJ1Y3Rpb25zLmxlbmd0aCA+IDApIHtcbiAgICBtZXNzYWdlcy5wdXNoKHsgcm9sZTogXCJzeXN0ZW1cIiwgY29udGVudDogYm9keS5pbnN0cnVjdGlvbnMgfSk7XG4gIH1cblxuICAvLyBgaW5wdXRgIGlzIGFuIGFycmF5IG9mIHR5cGVkIGl0ZW1zOiBtZXNzYWdlcywgZnVuY3Rpb25fY2FsbCwgYW5kXG4gIC8vIGZ1bmN0aW9uX2NhbGxfb3V0cHV0LiBGb2xkIGVhY2ggaW50byB0aGUgY2hhdCB0cmFuc2NyaXB0LlxuICBjb25zdCBpbnB1dCA9IEFycmF5LmlzQXJyYXkoYm9keS5pbnB1dCkgPyBib2R5LmlucHV0IDogW107XG4gIGZvciAoY29uc3QgcmF3IG9mIGlucHV0KSB7XG4gICAgaWYgKCFyYXcgfHwgdHlwZW9mIHJhdyAhPT0gXCJvYmplY3RcIikgY29udGludWU7XG4gICAgY29uc3QgaXRlbSA9IHJhdyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICBjb25zdCB0eXBlID0gaXRlbS50eXBlO1xuXG4gICAgaWYgKHR5cGUgPT09IFwiZnVuY3Rpb25fY2FsbFwiKSB7XG4gICAgICAvLyBBIHByaW9yIHRvb2wgY2FsbCB0aGUgbW9kZWwgbWFkZTsgcmUtYXR0YWNoIGl0IHRvIGFuIGFzc2lzdGFudCB0dXJuLlxuICAgICAgbWVzc2FnZXMucHVzaCh7XG4gICAgICAgIHJvbGU6IFwiYXNzaXN0YW50XCIsXG4gICAgICAgIGNvbnRlbnQ6IG51bGwsXG4gICAgICAgIHRvb2xfY2FsbHM6IFt0b0NoYXRUb29sQ2FsbChpdGVtKV0sXG4gICAgICB9KTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmICh0eXBlID09PSBcImZ1bmN0aW9uX2NhbGxfb3V0cHV0XCIpIHtcbiAgICAgIC8vIFRoZSB0b29sJ3MgcmVzdWx0LCBrZXllZCBiYWNrIHRvIHRoZSBjYWxsIGl0IGFuc3dlcnMuXG4gICAgICBtZXNzYWdlcy5wdXNoKHtcbiAgICAgICAgcm9sZTogXCJ0b29sXCIsXG4gICAgICAgIHRvb2xfY2FsbF9pZDogU3RyaW5nKGl0ZW0uY2FsbF9pZCA/PyBpdGVtLmlkID8/IFwiXCIpLFxuICAgICAgICBjb250ZW50OiB0eXBlb2YgaXRlbS5vdXRwdXQgPT09IFwic3RyaW5nXCIgPyBpdGVtLm91dHB1dCA6IGNoYXRDb250ZW50VG9UZXh0KGl0ZW0ub3V0cHV0KSxcbiAgICAgIH0pO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgLy8gRGVmYXVsdDogYSBtZXNzYWdlIGl0ZW0gd2l0aCBhIHJvbGUgYW5kIHR5cGVkIGNvbnRlbnQuXG4gICAgY29uc3Qgcm9sZSA9IHR5cGVvZiBpdGVtLnJvbGUgPT09IFwic3RyaW5nXCIgPyBpdGVtLnJvbGUgOiBcInVzZXJcIjtcbiAgICAvLyBDaGF0IGhhcyBubyBcImRldmVsb3BlclwiIHJvbGU7IHRyZWF0IGl0IGFzIHN5c3RlbSAoaXRzIGludGVudCBoZXJlKS5cbiAgICBjb25zdCBjaGF0Um9sZSA9IHJvbGUgPT09IFwiZGV2ZWxvcGVyXCIgPyBcInN5c3RlbVwiIDogcm9sZTtcbiAgICBtZXNzYWdlcy5wdXNoKHsgcm9sZTogY2hhdFJvbGUsIGNvbnRlbnQ6IGNoYXRDb250ZW50VG9UZXh0KGl0ZW0uY29udGVudCkgfSk7XG4gIH1cblxuICBjb25zdCBjaGF0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHtcbiAgICBtb2RlbDogYm9keS5tb2RlbCxcbiAgICBtZXNzYWdlcyxcbiAgICBzdHJlYW06IGJvZHkuc3RyZWFtID09PSB0cnVlLFxuICB9O1xuXG4gIC8vIENhcnJ5IHRocm91Z2ggZnVuY3Rpb24tY2FsbGluZyBjb25maWcgd2hlbiBwcmVzZW50LiBSZXNwb25zZXMgZnVuY3Rpb25cbiAgLy8gdG9vbHMgYXJlIEZMQVQgKGB7dHlwZTpcImZ1bmN0aW9uXCIsIG5hbWUsIGRlc2NyaXB0aW9uLCBwYXJhbWV0ZXJzfWApOyBjaGF0XG4gIC8vIHdhbnRzIHRoZW0gTkVTVEVEIChge3R5cGU6XCJmdW5jdGlvblwiLCBmdW5jdGlvbjp7bmFtZSwg4oCmfX1gKS4gQ2xpZW50cyBhbHNvXG4gIC8vIHNlbmQgYnVpbHQtaW4gdG9vbCB0eXBlcyAobG9jYWxfc2hlbGwsIHdlYl9zZWFyY2gsIOKApikgdGhhdCBEYXRhYnJpY2tzIGNoYXRcbiAgLy8gcmVqZWN0cyAoXCJNaXNzaW5nICdmdW5jdGlvbicgaW4gdGhlIHRvb2wgc3BlY2lmaWNhdGlvblwiKSwgc28gd2UgdHJhbnNsYXRlXG4gIC8vIG9ubHkgZnVuY3Rpb24gdG9vbHMgYW5kIGRyb3AgdGhlIHJlc3QuXG4gIGlmIChBcnJheS5pc0FycmF5KGJvZHkudG9vbHMpICYmIGJvZHkudG9vbHMubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IGNoYXRUb29scyA9IGJvZHkudG9vbHNcbiAgICAgIC5tYXAodG9DaGF0VG9vbClcbiAgICAgIC5maWx0ZXIoKHQpOiB0IGlzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0+IHQgIT09IHVuZGVmaW5lZCk7XG4gICAgaWYgKGNoYXRUb29scy5sZW5ndGggPiAwKSB7XG4gICAgICBjaGF0LnRvb2xzID0gY2hhdFRvb2xzO1xuICAgICAgaWYgKGJvZHkudG9vbF9jaG9pY2UgIT09IHVuZGVmaW5lZCkgY2hhdC50b29sX2Nob2ljZSA9IGJvZHkudG9vbF9jaG9pY2U7XG4gICAgICAvLyBOT1RFOiBkbyBOT1QgZm9yd2FyZCBgcGFyYWxsZWxfdG9vbF9jYWxsc2AuIENsaWVudHMgc2VuZCBpdCwgYnV0XG4gICAgICAvLyBEYXRhYnJpY2tzIE1vZGVsIFNlcnZpbmcncyBjaGF0IEFQSSByZWplY3RzIHVua25vd24gZmllbGRzXG4gICAgICAvLyAoXCJwYXJhbGxlbF90b29sX2NhbGxzOiBFeHRyYSBpbnB1dHMgYXJlIG5vdCBwZXJtaXR0ZWRcIiksIHdoaWNoIHdvdWxkXG4gICAgICAvLyBmYWlsIHRoZSB3aG9sZSB0dXJuLiBEcm9wIGl0LlxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7IGNoYXQsIHN0cmVhbTogYm9keS5zdHJlYW0gPT09IHRydWUgfTtcbn1cblxuLyoqXG4gKiBSYWlzZSBhIGNoYXQtY29tcGxldGlvbnMgcmVxdWVzdCBpbnRvIGEgUmVzcG9uc2VzIHJlcXVlc3QgYm9keS4gSW52ZXJzZSBvZlxuICoge0BsaW5rIHJlc3BvbnNlc1RvQ2hhdH06IHVzZWQgd2hlbiBhIGNoYXQgY2xpZW50IGhpdHMgYSBSZXNwb25zZXMtb25seVxuICogRGF0YWJyaWNrcyBtb2RlbCAoZS5nLiBDb2RleCkgc28gdGhlIHByb3h5IGNhbiBQT1NUIHRvXG4gKiBgL3NlcnZpbmctZW5kcG9pbnRzL3Jlc3BvbnNlc2Agd2l0aG91dCB0aGUgY2xpZW50IGtub3dpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjaGF0VG9SZXNwb25zZXNSZXF1ZXN0KGJvZHk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KToge1xuICByZXNwb25zZXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBzdHJlYW06IGJvb2xlYW47XG59IHtcbiAgY29uc3QgbWVzc2FnZXMgPSBBcnJheS5pc0FycmF5KGJvZHkubWVzc2FnZXMpID8gYm9keS5tZXNzYWdlcyA6IFtdO1xuICBjb25zdCBpbnB1dDogdW5rbm93bltdID0gW107XG4gIGxldCBpbnN0cnVjdGlvbnM6IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICBmb3IgKGNvbnN0IHJhdyBvZiBtZXNzYWdlcykge1xuICAgIGlmICghcmF3IHx8IHR5cGVvZiByYXcgIT09IFwib2JqZWN0XCIpIGNvbnRpbnVlO1xuICAgIGNvbnN0IG1lc3NhZ2UgPSByYXcgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgY29uc3Qgcm9sZSA9IHR5cGVvZiBtZXNzYWdlLnJvbGUgPT09IFwic3RyaW5nXCIgPyBtZXNzYWdlLnJvbGUgOiBcInVzZXJcIjtcblxuICAgIC8vIExlYWRpbmcgc3lzdGVtIC8gZGV2ZWxvcGVyIG1lc3NhZ2VzIGJlY29tZSB0b3AtbGV2ZWwgYGluc3RydWN0aW9uc2AuXG4gICAgaWYgKFxuICAgICAgKHJvbGUgPT09IFwic3lzdGVtXCIgfHwgcm9sZSA9PT0gXCJkZXZlbG9wZXJcIikgJiZcbiAgICAgIGluc3RydWN0aW9ucyA9PT0gdW5kZWZpbmVkICYmXG4gICAgICBpbnB1dC5sZW5ndGggPT09IDBcbiAgICApIHtcbiAgICAgIGNvbnN0IHRleHQgPSBjaGF0Q29udGVudFRvVGV4dChtZXNzYWdlLmNvbnRlbnQpO1xuICAgICAgaWYgKHRleHQpIGluc3RydWN0aW9ucyA9IHRleHQ7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBpZiAocm9sZSA9PT0gXCJ0b29sXCIpIHtcbiAgICAgIGlucHV0LnB1c2goe1xuICAgICAgICB0eXBlOiBcImZ1bmN0aW9uX2NhbGxfb3V0cHV0XCIsXG4gICAgICAgIGNhbGxfaWQ6IFN0cmluZyhtZXNzYWdlLnRvb2xfY2FsbF9pZCA/PyBcIlwiKSxcbiAgICAgICAgb3V0cHV0OiBjaGF0Q29udGVudFRvVGV4dChtZXNzYWdlLmNvbnRlbnQpLFxuICAgICAgfSk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICByb2xlID09PSBcImFzc2lzdGFudFwiICYmXG4gICAgICBBcnJheS5pc0FycmF5KG1lc3NhZ2UudG9vbF9jYWxscykgJiZcbiAgICAgIG1lc3NhZ2UudG9vbF9jYWxscy5sZW5ndGggPiAwXG4gICAgKSB7XG4gICAgICBmb3IgKGNvbnN0IHJhd0NhbGwgb2YgbWVzc2FnZS50b29sX2NhbGxzKSB7XG4gICAgICAgIGlmICghcmF3Q2FsbCB8fCB0eXBlb2YgcmF3Q2FsbCAhPT0gXCJvYmplY3RcIikgY29udGludWU7XG4gICAgICAgIGlucHV0LnB1c2godG9GdW5jdGlvbkNhbGxJdGVtKHJhd0NhbGwgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHRleHQgPSBjaGF0Q29udGVudFRvVGV4dChtZXNzYWdlLmNvbnRlbnQpO1xuICAgICAgaWYgKHRleHQpIHtcbiAgICAgICAgaW5wdXQucHVzaCh7IHR5cGU6IFwibWVzc2FnZVwiLCByb2xlOiBcImFzc2lzdGFudFwiLCBjb250ZW50OiB0ZXh0IH0pO1xuICAgICAgfVxuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgaW5wdXQucHVzaCh7XG4gICAgICB0eXBlOiBcIm1lc3NhZ2VcIixcbiAgICAgIHJvbGUsXG4gICAgICBjb250ZW50OiBjaGF0Q29udGVudFRvVGV4dChtZXNzYWdlLmNvbnRlbnQpLFxuICAgIH0pO1xuICB9XG5cbiAgY29uc3QgcmVzcG9uc2VzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHtcbiAgICBtb2RlbDogYm9keS5tb2RlbCxcbiAgICBpbnB1dCxcbiAgICBzdHJlYW06IGJvZHkuc3RyZWFtID09PSB0cnVlLFxuICB9O1xuICBpZiAoaW5zdHJ1Y3Rpb25zKSByZXNwb25zZXMuaW5zdHJ1Y3Rpb25zID0gaW5zdHJ1Y3Rpb25zO1xuXG4gIC8vIENoYXQgdG9vbHMgYXJlIG5lc3RlZCAoYGZ1bmN0aW9uOiB7IG5hbWUsIOKApiB9YCk7IFJlc3BvbnNlcyB3YW50cyB0aGVtIGZsYXQuXG4gIGlmIChBcnJheS5pc0FycmF5KGJvZHkudG9vbHMpICYmIGJvZHkudG9vbHMubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IHRvb2xzID0gYm9keS50b29sc1xuICAgICAgLm1hcCh0b1Jlc3BvbnNlc1Rvb2wpXG4gICAgICAuZmlsdGVyKCh0KTogdCBpcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9PiB0ICE9PSB1bmRlZmluZWQpO1xuICAgIGlmICh0b29scy5sZW5ndGggPiAwKSB7XG4gICAgICByZXNwb25zZXMudG9vbHMgPSB0b29scztcbiAgICAgIGlmIChib2R5LnRvb2xfY2hvaWNlICE9PSB1bmRlZmluZWQpIHJlc3BvbnNlcy50b29sX2Nob2ljZSA9IGJvZHkudG9vbF9jaG9pY2U7XG4gICAgfVxuICB9XG5cbiAgLy8gUHJlZmVyIFJlc3BvbnNlcycgbWF4X291dHB1dF90b2tlbnMgbmFtaW5nOyBmYWxsIGJhY2sgZnJvbSBjaGF0IG1heF90b2tlbnMuXG4gIGlmICh0eXBlb2YgYm9keS5tYXhfb3V0cHV0X3Rva2VucyA9PT0gXCJudW1iZXJcIikge1xuICAgIHJlc3BvbnNlcy5tYXhfb3V0cHV0X3Rva2VucyA9IGJvZHkubWF4X291dHB1dF90b2tlbnM7XG4gIH0gZWxzZSBpZiAodHlwZW9mIGJvZHkubWF4X3Rva2VucyA9PT0gXCJudW1iZXJcIikge1xuICAgIHJlc3BvbnNlcy5tYXhfb3V0cHV0X3Rva2VucyA9IGJvZHkubWF4X3Rva2VucztcbiAgfVxuXG4gIHJldHVybiB7IHJlc3BvbnNlcywgc3RyZWFtOiBib2R5LnN0cmVhbSA9PT0gdHJ1ZSB9O1xufVxuXG4vKiogTGlmdCBhIG5vbi1zdHJlYW1pbmcgY2hhdCBjb21wbGV0aW9uIEpTT04gaW50byBhIFJlc3BvbnNlcyBgcmVzcG9uc2VgIG9iamVjdC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjaGF0VG9SZXNwb25zZShjaGF0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwgbW9kZWw6IHN0cmluZyk6IHVua25vd24ge1xuICBjb25zdCBjaG9pY2VzID0gQXJyYXkuaXNBcnJheShjaGF0LmNob2ljZXMpID8gY2hhdC5jaG9pY2VzIDogW107XG4gIGNvbnN0IGZpcnN0ID0gKGNob2ljZXNbMF0gPz8ge30pIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBjb25zdCBtZXNzYWdlID0gKGZpcnN0Lm1lc3NhZ2UgPz8ge30pIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBjb25zdCBvdXRwdXQ6IHVua25vd25bXSA9IFtdO1xuXG4gIGNvbnN0IHRleHQgPSB0eXBlb2YgbWVzc2FnZS5jb250ZW50ID09PSBcInN0cmluZ1wiID8gbWVzc2FnZS5jb250ZW50IDogXCJcIjtcbiAgaWYgKHRleHQpIHtcbiAgICBvdXRwdXQucHVzaCh7XG4gICAgICB0eXBlOiBcIm1lc3NhZ2VcIixcbiAgICAgIHJvbGU6IFwiYXNzaXN0YW50XCIsXG4gICAgICBjb250ZW50OiBbeyB0eXBlOiBcIm91dHB1dF90ZXh0XCIsIHRleHQgfV0sXG4gICAgfSk7XG4gIH1cblxuICAvLyBTdXJmYWNlIGFueSB0b29sIGNhbGxzIGFzIFJlc3BvbnNlcyBgZnVuY3Rpb25fY2FsbGAgb3V0cHV0IGl0ZW1zLlxuICBjb25zdCB0b29sQ2FsbHMgPSBBcnJheS5pc0FycmF5KG1lc3NhZ2UudG9vbF9jYWxscykgPyBtZXNzYWdlLnRvb2xfY2FsbHMgOiBbXTtcbiAgZm9yIChjb25zdCByYXcgb2YgdG9vbENhbGxzKSB7XG4gICAgb3V0cHV0LnB1c2godG9GdW5jdGlvbkNhbGxJdGVtKHJhdyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikpO1xuICB9XG5cbiAgY29uc3QgdXNhZ2UgPSAoY2hhdC51c2FnZSA/PyB7fSkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIHJldHVybiB7XG4gICAgaWQ6IFN0cmluZyhjaGF0LmlkID8/IFwicmVzcFwiKSxcbiAgICBvYmplY3Q6IFwicmVzcG9uc2VcIixcbiAgICBjcmVhdGVkX2F0OiB0eXBlb2YgY2hhdC5jcmVhdGVkID09PSBcIm51bWJlclwiID8gY2hhdC5jcmVhdGVkIDogMCxcbiAgICBtb2RlbCxcbiAgICBzdGF0dXM6IFwiY29tcGxldGVkXCIsXG4gICAgb3V0cHV0LFxuICAgIHVzYWdlOiB7XG4gICAgICBpbnB1dF90b2tlbnM6IE51bWJlcih1c2FnZS5wcm9tcHRfdG9rZW5zID8/IDApLFxuICAgICAgb3V0cHV0X3Rva2VuczogTnVtYmVyKHVzYWdlLmNvbXBsZXRpb25fdG9rZW5zID8/IDApLFxuICAgICAgdG90YWxfdG9rZW5zOiBOdW1iZXIodXNhZ2UudG90YWxfdG9rZW5zID8/IDApLFxuICAgIH0sXG4gIH07XG59XG5cbi8qKlxuICogTGlmdCBhIG5hdGl2ZSBSZXNwb25zZXMgYHJlc3BvbnNlYCBvYmplY3QgaW50byBhIGNoYXQtY29tcGxldGlvbnMgYm9keS5cbiAqIEludmVyc2Ugb2Yge0BsaW5rIGNoYXRUb1Jlc3BvbnNlfTogdXNlZCBhZnRlciBhIFJlc3BvbnNlcy1vbmx5IHVwc3RyZWFtIGNhbGxcbiAqIHdoZW4gdGhlIGNsaWVudCBzcG9rZSBDaGF0IENvbXBsZXRpb25zLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzcG9uc2VUb0NoYXRDb21wbGV0aW9uKFxuICByZXNwb25zZTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIG1vZGVsOiBzdHJpbmcsXG4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIGNvbnN0IHsgdGV4dCB9ID0gcmVhZFJlc3BvbnNlc091dHB1dChyZXNwb25zZSk7XG4gIGNvbnN0IHRvb2xDYWxsczogdW5rbm93bltdID0gW107XG4gIGNvbnN0IG91dHB1dCA9IEFycmF5LmlzQXJyYXkocmVzcG9uc2Uub3V0cHV0KSA/IHJlc3BvbnNlLm91dHB1dCA6IFtdO1xuICBmb3IgKGNvbnN0IHJhdyBvZiBvdXRwdXQpIHtcbiAgICBpZiAoIXJhdyB8fCB0eXBlb2YgcmF3ICE9PSBcIm9iamVjdFwiKSBjb250aW51ZTtcbiAgICBjb25zdCBpdGVtID0gcmF3IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIGlmIChpdGVtLnR5cGUgIT09IFwiZnVuY3Rpb25fY2FsbFwiKSBjb250aW51ZTtcbiAgICB0b29sQ2FsbHMucHVzaCh0b0NoYXRUb29sQ2FsbChpdGVtKSk7XG4gIH1cblxuICBjb25zdCBtZXNzYWdlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHtcbiAgICByb2xlOiBcImFzc2lzdGFudFwiLFxuICAgIGNvbnRlbnQ6IHRleHQgfHwgbnVsbCxcbiAgfTtcbiAgaWYgKHRvb2xDYWxscy5sZW5ndGggPiAwKSBtZXNzYWdlLnRvb2xfY2FsbHMgPSB0b29sQ2FsbHM7XG5cbiAgY29uc3QgdXNhZ2UgPSAocmVzcG9uc2UudXNhZ2UgPz8ge30pIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICByZXR1cm4ge1xuICAgIGlkOiBTdHJpbmcocmVzcG9uc2UuaWQgPz8gXCJjaGF0Y21wbFwiKSxcbiAgICBvYmplY3Q6IFwiY2hhdC5jb21wbGV0aW9uXCIsXG4gICAgY3JlYXRlZDogdHlwZW9mIHJlc3BvbnNlLmNyZWF0ZWRfYXQgPT09IFwibnVtYmVyXCIgPyByZXNwb25zZS5jcmVhdGVkX2F0IDogMCxcbiAgICBtb2RlbCxcbiAgICBjaG9pY2VzOiBbXG4gICAgICB7XG4gICAgICAgIGluZGV4OiAwLFxuICAgICAgICBtZXNzYWdlLFxuICAgICAgICBmaW5pc2hfcmVhc29uOiB0b29sQ2FsbHMubGVuZ3RoID4gMCA/IFwidG9vbF9jYWxsc1wiIDogXCJzdG9wXCIsXG4gICAgICB9LFxuICAgIF0sXG4gICAgdXNhZ2U6IHtcbiAgICAgIHByb21wdF90b2tlbnM6IE51bWJlcih1c2FnZS5pbnB1dF90b2tlbnMgPz8gMCksXG4gICAgICBjb21wbGV0aW9uX3Rva2VuczogTnVtYmVyKHVzYWdlLm91dHB1dF90b2tlbnMgPz8gMCksXG4gICAgICB0b3RhbF90b2tlbnM6IE51bWJlcih1c2FnZS50b3RhbF90b2tlbnMgPz8gMCksXG4gICAgfSxcbiAgfTtcbn1cblxuLyoqXG4gKiBBIHRvb2wgY2FsbCdzIGBhcmd1bWVudHNgIEpTT04uIEJvdGggd2lyZXMgY2FycnkgaXQgYXMgYW4gdW5wYXJzZWQgc3RyaW5nO1xuICogYW55dGhpbmcgZWxzZSAoYWJzZW50LCBhbiBhbHJlYWR5LXBhcnNlZCBvYmplY3QpIGJlY29tZXMgYW4gZW1wdHkgbGl0ZXJhbCBzb1xuICogdGhlIHJlY2VpdmluZyBzaWRlIGFsd2F5cyBoYXMgdmFsaWQgSlNPTiB0byBwYXJzZS5cbiAqL1xuZnVuY3Rpb24gY2FsbEFyZ3VtZW50cyh2YWx1ZTogdW5rbm93bik6IHN0cmluZyB7XG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgPyB2YWx1ZSA6IFwie31cIjtcbn1cblxuLyoqXG4gKiBUaGUgUmVzcG9uc2VzIGBmdW5jdGlvbl9jYWxsYCBpdGVtIGZvciBhIHRvb2wgY2FsbCBpbiBlaXRoZXIgc3BlbGxpbmc6IGEgY2hhdFxuICogYHRvb2xfY2FsbHNbXWAgZW50cnkgKGB7aWQsIGZ1bmN0aW9uOntuYW1lLCBhcmd1bWVudHN9fWApIG9yIGFuIGl0ZW0gdGhhdCBpc1xuICogYWxyZWFkeSBmbGF0LlxuICovXG5mdW5jdGlvbiB0b0Z1bmN0aW9uQ2FsbEl0ZW0oY2FsbDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIGNvbnN0IGZuID0gKGNhbGwuZnVuY3Rpb24gPz8gY2FsbCkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIHJldHVybiB7XG4gICAgdHlwZTogXCJmdW5jdGlvbl9jYWxsXCIsXG4gICAgY2FsbF9pZDogU3RyaW5nKGNhbGwuY2FsbF9pZCA/PyBjYWxsLmlkID8/IFwiXCIpLFxuICAgIG5hbWU6IFN0cmluZyhmbi5uYW1lID8/IFwiXCIpLFxuICAgIGFyZ3VtZW50czogY2FsbEFyZ3VtZW50cyhmbi5hcmd1bWVudHMpLFxuICB9O1xufVxuXG4vKiogVGhlIGNoYXQgYHRvb2xfY2FsbHNbXWAgZW50cnkgZm9yIGEgUmVzcG9uc2VzIGBmdW5jdGlvbl9jYWxsYCBpdGVtLiAqL1xuZnVuY3Rpb24gdG9DaGF0VG9vbENhbGwoaXRlbTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBDaGF0VG9vbENhbGwge1xuICByZXR1cm4ge1xuICAgIGlkOiBTdHJpbmcoaXRlbS5jYWxsX2lkID8/IGl0ZW0uaWQgPz8gXCJcIiksXG4gICAgdHlwZTogXCJmdW5jdGlvblwiLFxuICAgIGZ1bmN0aW9uOiB7XG4gICAgICBuYW1lOiBTdHJpbmcoaXRlbS5uYW1lID8/IFwiXCIpLFxuICAgICAgYXJndW1lbnRzOiBjYWxsQXJndW1lbnRzKGl0ZW0uYXJndW1lbnRzKSxcbiAgICB9LFxuICB9O1xufVxuXG4vKipcbiAqIFRoZSBjaGF0LW5lc3RlZCBzcGVsbGluZyAoYHt0eXBlOlwiZnVuY3Rpb25cIiwgZnVuY3Rpb246e25hbWUsIOKApn19YCkgb2YgYSB0b29sXG4gKiBzcGVjLCBvciBgdW5kZWZpbmVkYCBmb3IgYSBidWlsdC1pbiBSZXNwb25zZXMgdG9vbCAoYHdlYl9zZWFyY2hgLFxuICogYGxvY2FsX3NoZWxsYCwg4oCmKSB0aGF0IGNoYXQgY2Fubm90IGV4cHJlc3MgYW5kIERhdGFicmlja3MgcmVqZWN0cy5cbiAqL1xuZnVuY3Rpb24gdG9DaGF0VG9vbCh2YWx1ZTogdW5rbm93bik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkIHtcbiAgaWYgKCF2YWx1ZSB8fCB0eXBlb2YgdmFsdWUgIT09IFwib2JqZWN0XCIpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IHRvb2wgPSB2YWx1ZSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgaWYgKHRvb2wudHlwZSAhPT0gXCJmdW5jdGlvblwiKSByZXR1cm4gdW5kZWZpbmVkO1xuICBpZiAodG9vbC5mdW5jdGlvbiAmJiB0eXBlb2YgdG9vbC5mdW5jdGlvbiA9PT0gXCJvYmplY3RcIikgcmV0dXJuIHRvb2w7IC8vIGFscmVhZHkgbmVzdGVkXG4gIGlmICh0eXBlb2YgdG9vbC5uYW1lICE9PSBcInN0cmluZ1wiKSByZXR1cm4gdW5kZWZpbmVkO1xuICByZXR1cm4ge1xuICAgIHR5cGU6IFwiZnVuY3Rpb25cIixcbiAgICBmdW5jdGlvbjoge1xuICAgICAgbmFtZTogdG9vbC5uYW1lLFxuICAgICAgLi4uKHRvb2wuZGVzY3JpcHRpb24gPyB7IGRlc2NyaXB0aW9uOiB0b29sLmRlc2NyaXB0aW9uIH0gOiB7fSksXG4gICAgICAuLi4odG9vbC5wYXJhbWV0ZXJzID8geyBwYXJhbWV0ZXJzOiB0b29sLnBhcmFtZXRlcnMgfSA6IHt9KSxcbiAgICB9LFxuICB9O1xufVxuXG4vKipcbiAqIFRoZSBmbGF0IFJlc3BvbnNlcyBzcGVsbGluZyAoYHt0eXBlOlwiZnVuY3Rpb25cIiwgbmFtZSwg4oCmfWApIG9mIGEgdG9vbCBzcGVjLlxuICogSW52ZXJzZSBvZiB7QGxpbmsgdG9DaGF0VG9vbH07IG5vbi1mdW5jdGlvbiB0b29scyBhcmUgZHJvcHBlZCB0aGUgc2FtZSB3YXkuXG4gKi9cbmZ1bmN0aW9uIHRvUmVzcG9uc2VzVG9vbCh2YWx1ZTogdW5rbm93bik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkIHtcbiAgaWYgKCF2YWx1ZSB8fCB0eXBlb2YgdmFsdWUgIT09IFwib2JqZWN0XCIpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IHRvb2wgPSB2YWx1ZSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgaWYgKHRvb2wudHlwZSAhPT0gXCJmdW5jdGlvblwiKSByZXR1cm4gdW5kZWZpbmVkO1xuICBpZiAodG9vbC5mdW5jdGlvbiAmJiB0eXBlb2YgdG9vbC5mdW5jdGlvbiA9PT0gXCJvYmplY3RcIikge1xuICAgIGNvbnN0IGZuID0gdG9vbC5mdW5jdGlvbiBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICByZXR1cm4ge1xuICAgICAgdHlwZTogXCJmdW5jdGlvblwiLFxuICAgICAgbmFtZTogZm4ubmFtZSxcbiAgICAgIC4uLihmbi5kZXNjcmlwdGlvbiA/IHsgZGVzY3JpcHRpb246IGZuLmRlc2NyaXB0aW9uIH0gOiB7fSksXG4gICAgICAuLi4oZm4ucGFyYW1ldGVycyA/IHsgcGFyYW1ldGVyczogZm4ucGFyYW1ldGVycyB9IDoge30pLFxuICAgIH07XG4gIH1cbiAgcmV0dXJuIHR5cGVvZiB0b29sLm5hbWUgPT09IFwic3RyaW5nXCIgPyB0b29sIDogdW5kZWZpbmVkOyAvLyBhbHJlYWR5IGZsYXRcbn1cblxuLyoqIE9uZSBTZXJ2ZXItU2VudCBFdmVudCwgcmVhZHkgdG8gd3JpdGUgdG8gdGhlIGNsaWVudC4gKi9cbmZ1bmN0aW9uIHNzZShldmVudDogc3RyaW5nLCBkYXRhOiB1bmtub3duKTogc3RyaW5nIHtcbiAgcmV0dXJuIGBldmVudDogJHtldmVudH1cXG5kYXRhOiAke0pTT04uc3RyaW5naWZ5KGRhdGEpfVxcblxcbmA7XG59XG5cbi8qKlxuICogSW5jcmVtZW50YWwgY2hhdC1jaHVuayAtPiBSZXNwb25zZXMtU1NFIHRyYW5zbGF0b3IuIGBmZWVkYCBhbmQgYGZpbmlzaGAgYm90aFxuICogcmV0dXJuIHRoZSBTU0UgYnl0ZXMgdG8gZm9yd2FyZCwgb3IgYFwiXCJgIHdoZW4gYSBjaHVuayBwcm9kdWNlZCBubyBldmVudC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXNwb25zZXNTdHJlYW1UcmFuc2xhdG9yIHtcbiAgLyoqIFRyYW5zbGF0ZSBvbmUgdXBzdHJlYW0gYGNoYXQuY29tcGxldGlvbi5jaHVua2Agb2JqZWN0LiAqL1xuICBmZWVkKGNodW5rOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IHN0cmluZztcbiAgLyoqIENsb3NlIGFueSBvcGVuIGl0ZW1zIGFuZCBlbWl0IGByZXNwb25zZS5jb21wbGV0ZWRgLiBDYWxsIG9uY2UsIGF0IGVuZCBvZiBzdHJlYW0uICovXG4gIGZpbmlzaCgpOiBzdHJpbmc7XG59XG5cbi8qKlxuICogVHJhbnNsYXRlIGFuIHVwc3RyZWFtIGNoYXQtY29tcGxldGlvbnMgU1NFIHN0cmVhbSBpbnRvIHRoZSBSZXNwb25zZXMgU1NFXG4gKiBldmVudCBzdHJlYW0gYSBSZXNwb25zZXMgY2xpZW50IGNvbnN1bWVzLlxuICpcbiAqIFVwc3RyZWFtIGNodW5rcyBhcmUgYGNoYXQuY29tcGxldGlvbi5jaHVua2Agb2JqZWN0cyB3aG9zZSBgY2hvaWNlc1swXS5kZWx0YWBcbiAqIGNhcnJpZXMgaW5jcmVtZW50YWwgYGNvbnRlbnRgIChhc3Npc3RhbnQgdGV4dCkgYW5kL29yIGB0b29sX2NhbGxzYCAoZnVuY3Rpb25cbiAqIGNhbGxzLCBzdHJlYW1lZCBieSBgaW5kZXhgIHdpdGggcGFydGlhbCBgYXJndW1lbnRzYCkuIFdlIGVtaXQgdGhlIFJlc3BvbnNlc1xuICogbGlmZWN5Y2xlIGFyb3VuZCB0aGVtOlxuICpcbiAqICAgcmVzcG9uc2UuY3JlYXRlZFxuICogICAtPiBwZXIgdGV4dCBydW46ICBvdXRwdXRfaXRlbS5hZGRlZCDihpIgb3V0cHV0X3RleHQuZGVsdGEqIOKGkiBvdXRwdXRfaXRlbS5kb25lXG4gKiAgIC0+IHBlciB0b29sIGNhbGw6IG91dHB1dF9pdGVtLmFkZGVkIOKGkiBmdW5jdGlvbl9jYWxsX2FyZ3VtZW50cy5kZWx0YSpcbiAqICAgICAgICAgICAgICAgICAgICAgICDihpIgZnVuY3Rpb25fY2FsbF9hcmd1bWVudHMuZG9uZSDihpIgb3V0cHV0X2l0ZW0uZG9uZVxuICogICByZXNwb25zZS5jb21wbGV0ZWQgICAod2l0aCB0aGUgYXNzZW1ibGVkIGZpbmFsIGByZXNwb25zZWAgb2JqZWN0KVxuICpcbiAqIFRoZSB0cmFuc2xhdG9yIGlzIGludGVudGlvbmFsbHkgdG9sZXJhbnQ6IG1hbGZvcm1lZC9rZWVwYWxpdmUgbGluZXMgeWllbGRcbiAqIG5vdGhpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVSZXNwb25zZXNTdHJlYW1UcmFuc2xhdG9yKFxuICBtb2RlbDogc3RyaW5nLFxuICByZXNwb25zZUlkOiBzdHJpbmcsXG4pOiBSZXNwb25zZXNTdHJlYW1UcmFuc2xhdG9yIHtcbiAgbGV0IHN0YXJ0ZWQgPSBmYWxzZTtcbiAgbGV0IG91dHB1dEluZGV4ID0gMDtcblxuICAvLyBUZXh0IHJ1biBzdGF0ZTogd2hldGhlciBhIG1lc3NhZ2UgaXRlbSBpcyBjdXJyZW50bHkgb3BlbiwgYW5kIGl0cyBidWZmZXIuXG4gIGxldCB0ZXh0T3BlbiA9IGZhbHNlO1xuICBsZXQgdGV4dEJ1ZmZlciA9IFwiXCI7XG4gIGxldCB0ZXh0SXRlbUlkID0gXCJcIjtcblxuICAvLyBUb29sLWNhbGwgc3RhdGUsIGtleWVkIGJ5IHRoZSB1cHN0cmVhbSBgdG9vbF9jYWxsc1tdLmluZGV4YC5cbiAgaW50ZXJmYWNlIFRvb2xTdGF0ZSB7XG4gICAgb3V0cHV0SW5kZXg6IG51bWJlcjtcbiAgICBjYWxsSWQ6IHN0cmluZztcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgYXJnczogc3RyaW5nO1xuICB9XG4gIGNvbnN0IHRvb2xzID0gbmV3IE1hcDxudW1iZXIsIFRvb2xTdGF0ZT4oKTtcblxuICBjb25zdCBjcmVhdGVkID0gKCkgPT5cbiAgICBzc2UoXCJyZXNwb25zZS5jcmVhdGVkXCIsIHtcbiAgICAgIHR5cGU6IFwicmVzcG9uc2UuY3JlYXRlZFwiLFxuICAgICAgcmVzcG9uc2U6IHsgaWQ6IHJlc3BvbnNlSWQsIG9iamVjdDogXCJyZXNwb25zZVwiLCBzdGF0dXM6IFwiaW5fcHJvZ3Jlc3NcIiwgbW9kZWwsIG91dHB1dDogW10gfSxcbiAgICB9KTtcblxuICBmdW5jdGlvbiBvcGVuVGV4dCgpOiBzdHJpbmcge1xuICAgIHRleHRPcGVuID0gdHJ1ZTtcbiAgICB0ZXh0SXRlbUlkID0gYCR7cmVzcG9uc2VJZH0tbXNnLSR7b3V0cHV0SW5kZXh9YDtcbiAgICBjb25zdCBldiA9IHNzZShcInJlc3BvbnNlLm91dHB1dF9pdGVtLmFkZGVkXCIsIHtcbiAgICAgIHR5cGU6IFwicmVzcG9uc2Uub3V0cHV0X2l0ZW0uYWRkZWRcIixcbiAgICAgIG91dHB1dF9pbmRleDogb3V0cHV0SW5kZXgsXG4gICAgICBpdGVtOiB7IGlkOiB0ZXh0SXRlbUlkLCB0eXBlOiBcIm1lc3NhZ2VcIiwgcm9sZTogXCJhc3Npc3RhbnRcIiwgY29udGVudDogW10gfSxcbiAgICB9KTtcbiAgICByZXR1cm4gZXY7XG4gIH1cblxuICBmdW5jdGlvbiBjbG9zZVRleHQoKTogc3RyaW5nIHtcbiAgICBpZiAoIXRleHRPcGVuKSByZXR1cm4gXCJcIjtcbiAgICBjb25zdCBpdGVtID0ge1xuICAgICAgaWQ6IHRleHRJdGVtSWQsXG4gICAgICB0eXBlOiBcIm1lc3NhZ2VcIixcbiAgICAgIHJvbGU6IFwiYXNzaXN0YW50XCIsXG4gICAgICBjb250ZW50OiBbeyB0eXBlOiBcIm91dHB1dF90ZXh0XCIsIHRleHQ6IHRleHRCdWZmZXIgfV0sXG4gICAgfTtcbiAgICBjb25zdCBldiA9XG4gICAgICBzc2UoXCJyZXNwb25zZS5vdXRwdXRfdGV4dC5kb25lXCIsIHtcbiAgICAgICAgdHlwZTogXCJyZXNwb25zZS5vdXRwdXRfdGV4dC5kb25lXCIsXG4gICAgICAgIGl0ZW1faWQ6IHRleHRJdGVtSWQsXG4gICAgICAgIG91dHB1dF9pbmRleDogb3V0cHV0SW5kZXgsXG4gICAgICAgIGNvbnRlbnRfaW5kZXg6IDAsXG4gICAgICAgIHRleHQ6IHRleHRCdWZmZXIsXG4gICAgICB9KSArXG4gICAgICBzc2UoXCJyZXNwb25zZS5vdXRwdXRfaXRlbS5kb25lXCIsIHtcbiAgICAgICAgdHlwZTogXCJyZXNwb25zZS5vdXRwdXRfaXRlbS5kb25lXCIsXG4gICAgICAgIG91dHB1dF9pbmRleDogb3V0cHV0SW5kZXgsXG4gICAgICAgIGl0ZW0sXG4gICAgICB9KTtcbiAgICB0ZXh0T3BlbiA9IGZhbHNlO1xuICAgIHRleHRCdWZmZXIgPSBcIlwiO1xuICAgIG91dHB1dEluZGV4ICs9IDE7XG4gICAgcmV0dXJuIGV2O1xuICB9XG5cbiAgZnVuY3Rpb24gZmVlZChjaHVuazogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBzdHJpbmcge1xuICAgIGxldCBvdXQgPSBcIlwiO1xuICAgIGlmICghc3RhcnRlZCkge1xuICAgICAgc3RhcnRlZCA9IHRydWU7XG4gICAgICBvdXQgKz0gY3JlYXRlZCgpO1xuICAgIH1cbiAgICBjb25zdCBjaG9pY2VzID0gQXJyYXkuaXNBcnJheShjaHVuay5jaG9pY2VzKSA/IGNodW5rLmNob2ljZXMgOiBbXTtcbiAgICBjb25zdCBjaG9pY2UgPSAoY2hvaWNlc1swXSA/PyB7fSkgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgY29uc3QgZGVsdGEgPSAoY2hvaWNlLmRlbHRhID8/IHt9KSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcblxuICAgIC8vIEFzc2lzdGFudCB0ZXh0IGRlbHRhcy5cbiAgICBpZiAodHlwZW9mIGRlbHRhLmNvbnRlbnQgPT09IFwic3RyaW5nXCIgJiYgZGVsdGEuY29udGVudC5sZW5ndGggPiAwKSB7XG4gICAgICBpZiAoIXRleHRPcGVuKSBvdXQgKz0gb3BlblRleHQoKTtcbiAgICAgIHRleHRCdWZmZXIgKz0gZGVsdGEuY29udGVudDtcbiAgICAgIG91dCArPSBzc2UoXCJyZXNwb25zZS5vdXRwdXRfdGV4dC5kZWx0YVwiLCB7XG4gICAgICAgIHR5cGU6IFwicmVzcG9uc2Uub3V0cHV0X3RleHQuZGVsdGFcIixcbiAgICAgICAgaXRlbV9pZDogdGV4dEl0ZW1JZCxcbiAgICAgICAgb3V0cHV0X2luZGV4OiBvdXRwdXRJbmRleCxcbiAgICAgICAgY29udGVudF9pbmRleDogMCxcbiAgICAgICAgZGVsdGE6IGRlbHRhLmNvbnRlbnQsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBUb29sLWNhbGwgZGVsdGFzOiBlYWNoIGlzIGtleWVkIGJ5IGBpbmRleGA7IGBhcmd1bWVudHNgIGFycml2ZXMgaW4gcGllY2VzLlxuICAgIGNvbnN0IHRvb2xEZWx0YXMgPSBBcnJheS5pc0FycmF5KGRlbHRhLnRvb2xfY2FsbHMpID8gZGVsdGEudG9vbF9jYWxscyA6IFtdO1xuICAgIGZvciAoY29uc3QgcmF3VGMgb2YgdG9vbERlbHRhcykge1xuICAgICAgY29uc3QgdGMgPSByYXdUYyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICAgIGNvbnN0IGlkeCA9IE51bWJlcih0Yy5pbmRleCA/PyAwKTtcbiAgICAgIGNvbnN0IGZuID0gKHRjLmZ1bmN0aW9uID8/IHt9KSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICAgIGxldCBzdGF0ZSA9IHRvb2xzLmdldChpZHgpO1xuICAgICAgaWYgKCFzdGF0ZSkge1xuICAgICAgICAvLyBGaXJzdCBmcmFnbWVudCBmb3IgdGhpcyBjYWxsOiBhIHRleHQgcnVuIChpZiBvcGVuKSBtdXN0IGNsb3NlIGZpcnN0IHNvXG4gICAgICAgIC8vIG91dHB1dCBvcmRlcmluZyBzdGF5cyBtb25vdG9uaWMsIHRoZW4gd2Ugb3BlbiBhIGZ1bmN0aW9uX2NhbGwgaXRlbS5cbiAgICAgICAgb3V0ICs9IGNsb3NlVGV4dCgpO1xuICAgICAgICBzdGF0ZSA9IHtcbiAgICAgICAgICBvdXRwdXRJbmRleCxcbiAgICAgICAgICBjYWxsSWQ6IFN0cmluZyh0Yy5pZCA/PyBgJHtyZXNwb25zZUlkfS1jYWxsLSR7aWR4fWApLFxuICAgICAgICAgIG5hbWU6IFN0cmluZyhmbi5uYW1lID8/IFwiXCIpLFxuICAgICAgICAgIGFyZ3M6IFwiXCIsXG4gICAgICAgIH07XG4gICAgICAgIHRvb2xzLnNldChpZHgsIHN0YXRlKTtcbiAgICAgICAgb3V0ICs9IHNzZShcInJlc3BvbnNlLm91dHB1dF9pdGVtLmFkZGVkXCIsIHtcbiAgICAgICAgICB0eXBlOiBcInJlc3BvbnNlLm91dHB1dF9pdGVtLmFkZGVkXCIsXG4gICAgICAgICAgb3V0cHV0X2luZGV4OiBzdGF0ZS5vdXRwdXRJbmRleCxcbiAgICAgICAgICBpdGVtOiB7XG4gICAgICAgICAgICBpZDogc3RhdGUuY2FsbElkLFxuICAgICAgICAgICAgdHlwZTogXCJmdW5jdGlvbl9jYWxsXCIsXG4gICAgICAgICAgICBjYWxsX2lkOiBzdGF0ZS5jYWxsSWQsXG4gICAgICAgICAgICBuYW1lOiBzdGF0ZS5uYW1lLFxuICAgICAgICAgICAgYXJndW1lbnRzOiBcIlwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgICAgICBvdXRwdXRJbmRleCArPSAxO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGVvZiBmbi5uYW1lID09PSBcInN0cmluZ1wiICYmIGZuLm5hbWUgJiYgIXN0YXRlLm5hbWUpIHN0YXRlLm5hbWUgPSBmbi5uYW1lO1xuICAgICAgaWYgKHR5cGVvZiBmbi5hcmd1bWVudHMgPT09IFwic3RyaW5nXCIgJiYgZm4uYXJndW1lbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgc3RhdGUuYXJncyArPSBmbi5hcmd1bWVudHM7XG4gICAgICAgIG91dCArPSBzc2UoXCJyZXNwb25zZS5mdW5jdGlvbl9jYWxsX2FyZ3VtZW50cy5kZWx0YVwiLCB7XG4gICAgICAgICAgdHlwZTogXCJyZXNwb25zZS5mdW5jdGlvbl9jYWxsX2FyZ3VtZW50cy5kZWx0YVwiLFxuICAgICAgICAgIGl0ZW1faWQ6IHN0YXRlLmNhbGxJZCxcbiAgICAgICAgICBvdXRwdXRfaW5kZXg6IHN0YXRlLm91dHB1dEluZGV4LFxuICAgICAgICAgIGRlbHRhOiBmbi5hcmd1bWVudHMsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gb3V0O1xuICB9XG5cbiAgZnVuY3Rpb24gZmluaXNoKCk6IHN0cmluZyB7XG4gICAgbGV0IG91dCA9IGNsb3NlVGV4dCgpO1xuICAgIC8vIENsb3NlIGFueSBvcGVuIHRvb2wgY2FsbHMsIGVtaXR0aW5nIHRoZWlyIGFzc2VtYmxlZCBhcmd1bWVudHMuXG4gICAgZm9yIChjb25zdCBzdGF0ZSBvZiB0b29scy52YWx1ZXMoKSkge1xuICAgICAgb3V0ICs9IHNzZShcInJlc3BvbnNlLmZ1bmN0aW9uX2NhbGxfYXJndW1lbnRzLmRvbmVcIiwge1xuICAgICAgICB0eXBlOiBcInJlc3BvbnNlLmZ1bmN0aW9uX2NhbGxfYXJndW1lbnRzLmRvbmVcIixcbiAgICAgICAgaXRlbV9pZDogc3RhdGUuY2FsbElkLFxuICAgICAgICBvdXRwdXRfaW5kZXg6IHN0YXRlLm91dHB1dEluZGV4LFxuICAgICAgICBhcmd1bWVudHM6IHN0YXRlLmFyZ3MsXG4gICAgICB9KTtcbiAgICAgIG91dCArPSBzc2UoXCJyZXNwb25zZS5vdXRwdXRfaXRlbS5kb25lXCIsIHtcbiAgICAgICAgdHlwZTogXCJyZXNwb25zZS5vdXRwdXRfaXRlbS5kb25lXCIsXG4gICAgICAgIG91dHB1dF9pbmRleDogc3RhdGUub3V0cHV0SW5kZXgsXG4gICAgICAgIGl0ZW06IHtcbiAgICAgICAgICBpZDogc3RhdGUuY2FsbElkLFxuICAgICAgICAgIHR5cGU6IFwiZnVuY3Rpb25fY2FsbFwiLFxuICAgICAgICAgIGNhbGxfaWQ6IHN0YXRlLmNhbGxJZCxcbiAgICAgICAgICBuYW1lOiBzdGF0ZS5uYW1lLFxuICAgICAgICAgIGFyZ3VtZW50czogc3RhdGUuYXJncyxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH1cbiAgICBvdXQgKz0gc3NlKFwicmVzcG9uc2UuY29tcGxldGVkXCIsIHtcbiAgICAgIHR5cGU6IFwicmVzcG9uc2UuY29tcGxldGVkXCIsXG4gICAgICByZXNwb25zZTogeyBpZDogcmVzcG9uc2VJZCwgb2JqZWN0OiBcInJlc3BvbnNlXCIsIHN0YXR1czogXCJjb21wbGV0ZWRcIiwgbW9kZWwgfSxcbiAgICB9KTtcbiAgICByZXR1cm4gb3V0O1xuICB9XG5cbiAgcmV0dXJuIHsgZmVlZCwgZmluaXNoIH07XG59XG5cbi8qKiBBIHNvdXJjZSB0aGUgbW9kZWwgY2l0ZWQsIGFzIGNhcnJpZWQgYnkgYSBSZXNwb25zZXMgY29udGVudC1wYXJ0IGFubm90YXRpb24uICovXG5leHBvcnQgaW50ZXJmYWNlIFJlc3BvbnNlc0NpdGF0aW9uIHtcbiAgdXJsOiBzdHJpbmc7XG4gIHRpdGxlPzogc3RyaW5nO1xufVxuXG4vKiogV2hhdCB7QGxpbmsgcmVhZFJlc3BvbnNlc091dHB1dH0gcHVsbHMgb3V0IG9mIGEgYHJlc3BvbnNlYCBvYmplY3QuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlc3BvbnNlc091dHB1dCB7XG4gIC8qKiBUaGUgYXNzaXN0YW50J3MgYW5zd2VyLCB3aXRoIHRoZSBvdXRwdXQgaXRlbXMgY29uY2F0ZW5hdGVkLiAqL1xuICB0ZXh0OiBzdHJpbmc7XG4gIC8qKiBDaXRlZCBzb3VyY2VzIGluIGZpcnN0LXNlZW4gb3JkZXIsIGRlZHVwbGljYXRlZCBieSBVUkwuICovXG4gIGNpdGF0aW9uczogUmVzcG9uc2VzQ2l0YXRpb25bXTtcbn1cblxuLyoqXG4gKiBSZWFkIHRoZSBhbnN3ZXIgdGV4dCBhbmQgY2l0ZWQgc291cmNlcyBvdXQgb2YgYSBSZXNwb25zZXMgYHJlc3BvbnNlYCBwYXlsb2FkLlxuICpcbiAqIFRoaXMgaXMgdGhlIGludmVyc2Ugb2Yge0BsaW5rIGNoYXRUb1Jlc3BvbnNlfTogaXQgY29uc3VtZXMgd2hhdCBhbiBlbmRwb2ludFxuICogc3BlYWtpbmcgUmVzcG9uc2VzIG5hdGl2ZWx5IHJldHVybnMsIHJhdGhlciB0aGFuIHByb2R1Y2luZyBpdC4gVGhlIERhdGFicmlja3NcbiAqIG5hdGl2ZSB3ZWItc2VhcmNoIHRvb2wgYW5zd2VycyB0aGlzIHdheSwgd2l0aCBlYWNoIHNvdXJjZSBhdHRhY2hlZCBhcyBhXG4gKiBgdXJsX2NpdGF0aW9uYCBhbm5vdGF0aW9uIG9uIHRoZSBjb250ZW50IHBhcnQgdGhhdCB1c2VkIGl0LlxuICpcbiAqIFByZWZlcnMgdGhlIGZsYXR0ZW5lZCBgb3V0cHV0X3RleHRgIHdoZW4gdGhlIHBheWxvYWQgY2FycmllcyBpdCwgYW5kIGZhbGxzXG4gKiBiYWNrIHRvIHdhbGtpbmcgYG91dHB1dFtdLmNvbnRlbnRbXS50ZXh0YC4gRXZlcnkgZmllbGQgaXMgb3B0aW9uYWwgdXBzdHJlYW0sXG4gKiBzbyBhIHBheWxvYWQgbWlzc2luZyBhbnkgb2YgaXQgeWllbGRzIGVtcHR5IHJlc3VsdHMgcmF0aGVyIHRoYW4gdGhyb3dpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkUmVzcG9uc2VzT3V0cHV0KHBheWxvYWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogUmVzcG9uc2VzT3V0cHV0IHtcbiAgY29uc3Qgb3V0cHV0ID0gQXJyYXkuaXNBcnJheShwYXlsb2FkLm91dHB1dCkgPyAocGF5bG9hZC5vdXRwdXQgYXMgdW5rbm93bltdKSA6IFtdO1xuICBjb25zdCB0ZXh0czogc3RyaW5nW10gPSBbXTtcbiAgY29uc3QgY2l0YXRpb25zOiBSZXNwb25zZXNDaXRhdGlvbltdID0gW107XG4gIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcblxuICBmb3IgKGNvbnN0IHJhd0l0ZW0gb2Ygb3V0cHV0KSB7XG4gICAgaWYgKCFyYXdJdGVtIHx8IHR5cGVvZiByYXdJdGVtICE9PSBcIm9iamVjdFwiKSBjb250aW51ZTtcbiAgICBjb25zdCBjb250ZW50ID0gKHJhd0l0ZW0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLmNvbnRlbnQ7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KGNvbnRlbnQpKSBjb250aW51ZTtcbiAgICBmb3IgKGNvbnN0IHJhd1BhcnQgb2YgY29udGVudCkge1xuICAgICAgaWYgKCFyYXdQYXJ0IHx8IHR5cGVvZiByYXdQYXJ0ICE9PSBcIm9iamVjdFwiKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IHBhcnQgPSByYXdQYXJ0IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgICAgY29uc3QgdGV4dCA9IHN0cmluZy50cmltVG9FbXB0eShwYXJ0LnRleHQpO1xuICAgICAgaWYgKHRleHQpIHRleHRzLnB1c2godGV4dCk7XG4gICAgICBjb25zdCBhbm5vdGF0aW9ucyA9IEFycmF5LmlzQXJyYXkocGFydC5hbm5vdGF0aW9ucykgPyBwYXJ0LmFubm90YXRpb25zIDogW107XG4gICAgICBmb3IgKGNvbnN0IHJhd0FubiBvZiBhbm5vdGF0aW9ucykge1xuICAgICAgICBpZiAoIXJhd0FubiB8fCB0eXBlb2YgcmF3QW5uICE9PSBcIm9iamVjdFwiKSBjb250aW51ZTtcbiAgICAgICAgY29uc3QgYW5uID0gcmF3QW5uIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgICAgICBjb25zdCB1cmwgPSBzdHJpbmcudHJpbVRvRW1wdHkoYW5uLnVybCk7XG4gICAgICAgIGlmICghdXJsIHx8IHNlZW4uaGFzKHVybCkpIGNvbnRpbnVlO1xuICAgICAgICBzZWVuLmFkZCh1cmwpO1xuICAgICAgICBjb25zdCB0aXRsZSA9IHN0cmluZy50cmltVG9FbXB0eShhbm4udGl0bGUpO1xuICAgICAgICBjaXRhdGlvbnMucHVzaCh7IHVybCwgLi4uKHRpdGxlID8geyB0aXRsZSB9IDoge30pIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7IHRleHQ6IHN0cmluZy50cmltVG9FbXB0eShwYXlsb2FkLm91dHB1dF90ZXh0KSB8fCB0ZXh0cy5qb2luKFwiXFxuXCIpLnRyaW0oKSwgY2l0YXRpb25zIH07XG59XG5cbi8qKlxuICogU3RyaXAgdG9vbCB0eXBlcyB0aGUgdXBzdHJlYW0gbW9kZWwgZG9lc24ndCBzdXBwb3J0IGZyb20gYSBSZXNwb25zZXMgcmVxdWVzdFxuICogYm9keSwgcmV0dXJuaW5nIGEgc2hhbGxvdyBjb3B5IHNhZmUgdG8gZm9yd2FyZCAodGhlIGlucHV0IGlzIG5vdCBtdXRhdGVkKS5cbiAqXG4gKiBDbGllbnRzIGxpa2UgdGhlIENvZGV4IENMSSBpbmNsdWRlIGJ1aWx0LWluIFJlc3BvbnNlcyB0b29scyAoYHdlYl9zZWFyY2hgLFxuICogYGxvY2FsX3NoZWxsYCwgYGN1c3RvbWAsIC4uLikgYWxvbmdzaWRlIHRoZWlyIGBmdW5jdGlvbmAgdG9vbHMuIERhdGFicmlja3MnXG4gKiBPcGVuIFJlc3BvbnNlcyBzdXJmYWNlIGZvciBBbnRocm9waWMvQ2xhdWRlIChhbmQgb3RoZXIgbm9uLU9wZW5BSSBwcm92aWRlcnMpXG4gKiBvbmx5IGFjY2VwdHMgYGZ1bmN0aW9uYCB0b29scyBhbmQgaGFyZC1lcnJvcnMgb3RoZXJ3aXNlOlxuICogICBcIkFudGhyb3BpYyBkb2VzIG5vdCBzdXBwb3J0IHRvb2wgdHlwZSAnd2ViX3NlYXJjaCcuIE9ubHkgJ2Z1bmN0aW9uJyBpcyBzdXBwb3J0ZWQuXCJcbiAqIENhbGwgdGhpcyBiZWZvcmUgZm9yd2FyZGluZyB0byBgL3NlcnZpbmctZW5kcG9pbnRzL29wZW4tcmVzcG9uc2VzYC4gVGhlIE9wZW5BSVxuICogYC9zZXJ2aW5nLWVuZHBvaW50cy9yZXNwb25zZXNgIHBhdGggc2hvdWxkIGtlZXAgYnVpbHQtaW5zIChHUFQgc3VwcG9ydHMgdGhlbSkuXG4gKiBJZiBmaWx0ZXJpbmcgZW1wdGllcyB0aGUgbGlzdCwgYHRvb2xzYCAvIGB0b29sX2Nob2ljZWAgLyBgcGFyYWxsZWxfdG9vbF9jYWxsc2BcbiAqIGFyZSBkcm9wcGVkIHNvIHdlIG5ldmVyIHNlbmQgYW4gZW1wdHkgYHRvb2xzOiBbXWAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZVJlc3BvbnNlc1Rvb2xzKGJvZHk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICBpZiAoIUFycmF5LmlzQXJyYXkoYm9keS50b29scykgfHwgYm9keS50b29scy5sZW5ndGggPT09IDApIHJldHVybiBib2R5O1xuICBjb25zdCBmblRvb2xzID0gYm9keS50b29scy5maWx0ZXIoXG4gICAgKHQpID0+IHQgJiYgdHlwZW9mIHQgPT09IFwib2JqZWN0XCIgJiYgKHQgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLnR5cGUgPT09IFwiZnVuY3Rpb25cIixcbiAgKTtcbiAgaWYgKGZuVG9vbHMubGVuZ3RoID09PSBib2R5LnRvb2xzLmxlbmd0aCkgcmV0dXJuIGJvZHk7IC8vIG5vdGhpbmcgdG8gc3RyaXBcbiAgY29uc3QgbmV4dDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7IC4uLmJvZHkgfTtcbiAgaWYgKGZuVG9vbHMubGVuZ3RoID4gMCkge1xuICAgIG5leHQudG9vbHMgPSBmblRvb2xzO1xuICB9IGVsc2Uge1xuICAgIGRlbGV0ZSBuZXh0LnRvb2xzO1xuICAgIGRlbGV0ZSBuZXh0LnRvb2xfY2hvaWNlO1xuICAgIGRlbGV0ZSBuZXh0LnBhcmFsbGVsX3Rvb2xfY2FsbHM7XG4gIH1cbiAgcmV0dXJuIG5leHQ7XG59XG5cbi8qKlxuICogQ29udGVudC1wYXJ0IC8gaW5wdXQtaXRlbSB0eXBlcyBDbGF1ZGUgZXh0ZW5kZWQgdGhpbmtpbmcgdXNlcyBvbiB0aGUgd2lyZS5cbiAqXG4gKiBTaGFyZWQgc28gYm90aCB3aXJlIHN1cmZhY2VzIHN0cmlwIHRoZSBzYW1lIHNldDogdGhlIFJlc3BvbnNlcyBwYXRoIGhlcmVcbiAqICh7QGxpbmsgc2FuaXRpemVPcGVuUmVzcG9uc2VzSW5wdXR9KSBhbmQgdGhlIENoYXQgQ29tcGxldGlvbnMgcGF0aCBpblxuICogYEBkYngtdG9vbHMvYXBwa2l0LW1hc3RyYWAncyBzZXJ2aW5nIHNhbml0aXplLiBBbnRocm9waWMgc2lnbnMgdGhlc2UgYmxvY2tzLFxuICogc28gYSByZXBsYXkgdGhhdCBtdXRhdGVzIG9uZSBpcyByZWplY3RlZCBvdXRyaWdodCAtIGJvdGggcGF0aHMgbXVzdCBhZ3JlZSBvblxuICogd2hhdCBjb3VudHMgYXMgYSByZWFzb25pbmcgYmxvY2suXG4gKi9cbmV4cG9ydCBjb25zdCBSRUFTT05JTkdfVFlQRVM6IFJlYWRvbmx5U2V0PHN0cmluZz4gPSBuZXcgU2V0KFtcbiAgXCJyZWFzb25pbmdcIixcbiAgXCJ0aGlua2luZ1wiLFxuICBcInJlZGFjdGVkX3RoaW5raW5nXCIsXG5dKTtcblxuLyoqXG4gKiBSZXdyaXRlIFJlc3BvbnNlcyBgaW5wdXRgIHNvIE9wZW4gUmVzcG9uc2VzIHdpbGwgYWNjZXB0IGl0LlxuICpcbiAqIFR3byBPcGVuQUkgLyBDb2RleCBzaGFwZXMgdGhhdCBEYXRhYnJpY2tzIE9wZW4gUmVzcG9uc2VzIChDbGF1ZGUsIEdlbWluaSwg4oCmKVxuICogcmVqZWN0OlxuICpcbiAqIDEuIFByaW9yIGFzc2lzdGFudCB0dXJucyB3aXRoIGBvdXRwdXRfdGV4dGAgLyBgb3V0cHV0XypgIGNvbnRlbnQgcGFydHMg4oCUXG4gKiAgICBPcGVuIFJlc3BvbnNlcyBvbmx5IGFsbG93cyBgaW5wdXRfdGV4dGAsIGBpbnB1dF9pbWFnZWAsIGBpbnB1dF9maWxlYCxcbiAqICAgIGBpbnB1dF9hdWRpb2AuIE1hcCBldmVyeSBgb3V0cHV0XzxraW5kPmAgcGFydCB0byBgaW5wdXRfPGtpbmQ+YC5cbiAqIDIuIFJlcGxheWVkIGV4dGVuZGVkLXRoaW5raW5nIGJsb2NrcyAoYHRoaW5raW5nYCwgYHJlZGFjdGVkX3RoaW5raW5nYCxcbiAqICAgIGByZWFzb25pbmdgIGNvbnRlbnQgcGFydHMsIGFuZCB0b3AtbGV2ZWwgYHJlYXNvbmluZ2AgaW5wdXQgaXRlbXMpLiBDbGF1ZGVcbiAqICAgIHNpZ25zIHRob3NlOyBhbnkgY2xpZW50IHJvdW5kLXRyaXAgdGhhdCBtdXRhdGVzIHRoZW0gKG9yIGEgY3Jvc3MtcHJvdmlkZXJcbiAqICAgIHJlcGxheSkgZmFpbHMgd2l0aCBlLmcuXG4gKiAgICAgIFwibWVzc2FnZXMuTi5jb250ZW50Lk06IEludmFsaWQgYGRhdGFgIGluIGByZWRhY3RlZF90aGlua2luZ2AgYmxvY2tcIlxuICogICAgU3RyaXAgdGhlbSDigJQgdGhlIFVJL2NsaWVudCBhbHJlYWR5IHNob3dlZCB0aGUgdGhpbmtpbmc7IHJlcGxheSBkb2VzIG5vdFxuICogICAgbmVlZCB0aGUgc2lnbmVkIGJsb2IuIFNhbWUgcG9saWN5IGFzIGFwcGtpdC1tYXN0cmEncyBzZXJ2aW5nIHNhbml0aXplLlxuICpcbiAqIFJldHVybnMgYSBzaGFsbG93IGNvcHkgd2hlbiBhbnl0aGluZyBjaGFuZ2VzOyBvdGhlcndpc2UgdGhlIGlucHV0IGJvZHkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZU9wZW5SZXNwb25zZXNJbnB1dChib2R5OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KGJvZHkuaW5wdXQpIHx8IGJvZHkuaW5wdXQubGVuZ3RoID09PSAwKSByZXR1cm4gYm9keTtcblxuICBsZXQgY2hhbmdlZCA9IGZhbHNlO1xuICBjb25zdCBpbnB1dDogdW5rbm93bltdID0gW107XG5cbiAgZm9yIChjb25zdCByYXcgb2YgYm9keS5pbnB1dCkge1xuICAgIGlmICghcmF3IHx8IHR5cGVvZiByYXcgIT09IFwib2JqZWN0XCIpIHtcbiAgICAgIGlucHV0LnB1c2gocmF3KTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBjb25zdCBpdGVtID0gcmF3IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuXG4gICAgLy8gVG9wLWxldmVsIFJlc3BvbnNlcyByZWFzb25pbmcgaXRlbXMgKG5vdCBtZXNzYWdlIGNvbnRlbnQgcGFydHMpLlxuICAgIGlmICh0eXBlb2YgaXRlbS50eXBlID09PSBcInN0cmluZ1wiICYmIFJFQVNPTklOR19UWVBFUy5oYXMoaXRlbS50eXBlKSkge1xuICAgICAgY2hhbmdlZCA9IHRydWU7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBpZiAoIUFycmF5LmlzQXJyYXkoaXRlbS5jb250ZW50KSkge1xuICAgICAgaW5wdXQucHVzaChyYXcpO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgbGV0IHBhcnRDaGFuZ2VkID0gZmFsc2U7XG4gICAgY29uc3QgY29udGVudDogdW5rbm93bltdID0gW107XG4gICAgZm9yIChjb25zdCBwYXJ0IG9mIGl0ZW0uY29udGVudCkge1xuICAgICAgaWYgKCFwYXJ0IHx8IHR5cGVvZiBwYXJ0ICE9PSBcIm9iamVjdFwiKSB7XG4gICAgICAgIGNvbnRlbnQucHVzaChwYXJ0KTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCBwID0gcGFydCBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICAgIGlmICh0eXBlb2YgcC50eXBlID09PSBcInN0cmluZ1wiICYmIFJFQVNPTklOR19UWVBFUy5oYXMocC50eXBlKSkge1xuICAgICAgICBwYXJ0Q2hhbmdlZCA9IHRydWU7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGVvZiBwLnR5cGUgPT09IFwic3RyaW5nXCIgJiYgcC50eXBlLnN0YXJ0c1dpdGgoXCJvdXRwdXRfXCIpKSB7XG4gICAgICAgIHBhcnRDaGFuZ2VkID0gdHJ1ZTtcbiAgICAgICAgY29udGVudC5wdXNoKHsgLi4ucCwgdHlwZTogYGlucHV0XyR7cC50eXBlLnNsaWNlKFwib3V0cHV0X1wiLmxlbmd0aCl9YCB9KTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb250ZW50LnB1c2gocGFydCk7XG4gICAgfVxuXG4gICAgaWYgKCFwYXJ0Q2hhbmdlZCkge1xuICAgICAgaW5wdXQucHVzaChyYXcpO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGNoYW5nZWQgPSB0cnVlO1xuICAgIC8vIERyb3AgYXNzaXN0YW50IHR1cm5zIHRoYXQgb25seSBjYXJyaWVkIHRoaW5raW5nIChub3RoaW5nIGxlZnQgdG8gcmVwbGF5KS5cbiAgICBpZiAoY29udGVudC5sZW5ndGggPT09IDAgJiYgaXRlbS5yb2xlID09PSBcImFzc2lzdGFudFwiKSBjb250aW51ZTtcbiAgICBpbnB1dC5wdXNoKHsgLi4uaXRlbSwgY29udGVudCB9KTtcbiAgfVxuXG4gIHJldHVybiBjaGFuZ2VkID8geyAuLi5ib2R5LCBpbnB1dCB9IDogYm9keTtcbn1cblxuLyoqXG4gKiBGdWxsIE9wZW4gUmVzcG9uc2VzIHJlcXVlc3Qgc2FuaXRpemVyOiBzdHJpcCBub24tYGZ1bmN0aW9uYCB0b29scywgcmV3cml0ZVxuICogYG91dHB1dF8qYCBjb250ZW50IHBhcnRzLCBhbmQgZHJvcCB0aGlua2luZyAvIHJlYXNvbmluZyBibG9ja3MuIFNhZmUgbm8tb3BcbiAqIHdoZW4gbm90aGluZyBuZWVkcyBjaGFuZ2luZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNhbml0aXplT3BlblJlc3BvbnNlc1JlcXVlc3QoXG4gIGJvZHk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4gc2FuaXRpemVPcGVuUmVzcG9uc2VzSW5wdXQoc2FuaXRpemVSZXNwb25zZXNUb29scyhib2R5KSk7XG59XG4iXX0=
|