@dbx-tools/teams 0.3.44 → 0.4.1

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,509 @@
1
+ /**
2
+ * The Teams conversation turn: run a Mastra agent against an inbound Bot
3
+ * Framework activity and answer with Adaptive Card attachments.
4
+ *
5
+ * This is the piece that makes `POST /api/teams/activity` behave like a Teams
6
+ * bot rather than a chat API that happens to return JSON. A turn is:
7
+ *
8
+ * 1. read the user's text off the inbound `message` activity;
9
+ * 2. ANSWER it - a normal tool-using agent turn, with no mention of cards, so
10
+ * the agent queries Genie / calls its tools exactly as it would on a
11
+ * streaming chat endpoint;
12
+ * 3. FORMAT that answer into a {@link card.CardSpec} in a second pass, via
13
+ * Mastra's `structuredOutput` (prompt-injected, see
14
+ * {@link JSON_PROMPT_INJECTION});
15
+ * 4. compile the spec with the same deterministic builder the
16
+ * `create_teams_card` tool uses, and attach it to an outbound activity.
17
+ *
18
+ * The two passes are the important part. Asking for the answer AND the card
19
+ * shape in ONE request makes the model treat formatting as the task: it emits a
20
+ * card straight away and never calls its tools, so a question that should have
21
+ * queried a data source came back as "I don't have a real system connected -
22
+ * here is a template card with placeholders". Answering first, then formatting a
23
+ * REAL answer, makes this endpoint's content identical to the streaming
24
+ * endpoint's; only the presentation differs.
25
+ *
26
+ * Formatting is also why the turn does not simply rely on the agent calling
27
+ * `create_teams_card`: on this endpoint a card IS the response format, so it
28
+ * should be a property of the turn rather than a tool the model may forget.
29
+ * Agents keep the tool for the other direction - answering in prose on a normal
30
+ * chat endpoint and choosing to attach a card. When the agent DOES call it
31
+ * during the answering pass, that spec wins and the formatting pass is skipped.
32
+ *
33
+ * The conversation id doubles as the agent's memory thread id, so a client that
34
+ * keeps posting the same `conversation.id` gets a continuous conversation - the
35
+ * same mapping a real channel relies on.
36
+ *
37
+ * @module
38
+ */
39
+ import { error, hash, json, log, object, string } from "@dbx-tools/shared-core";
40
+ import { activity as activityContract, card } from "@dbx-tools/shared-teams";
41
+ import { buildAdaptiveCard } from "./builder.js";
42
+ const logger = log.logger("teams:conversation");
43
+ /** Tool id whose arguments are already a {@link card.CardSpec}. */
44
+ const CARD_TOOL_NAMES = ["create_teams_card", "createCard"];
45
+ /**
46
+ * The card spec an agent passed to the card tool, if it called it.
47
+ *
48
+ * Mastra nests a tool result under `payload` (`{ payload: { toolName, args } }`)
49
+ * but has used a flat shape too, so both are read.
50
+ */
51
+ const toolCardSpec = (result) => {
52
+ for (const entry of result.toolResults ?? []) {
53
+ const name = entry.payload?.toolName ?? entry.toolName;
54
+ if (!name || !CARD_TOOL_NAMES.includes(name))
55
+ continue;
56
+ const parsed = card.cardSpecSchema.safeParse(entry.payload?.args ?? entry.args);
57
+ if (parsed.success)
58
+ return parsed.data;
59
+ }
60
+ return null;
61
+ };
62
+ /**
63
+ * Ask for the card shape via PROMPT injection rather than the provider's native
64
+ * response format.
65
+ *
66
+ * Databricks Model Serving rejects a request carrying both `response_format` and
67
+ * `tools` ("Cannot specify both response_format and tools in the same request"),
68
+ * and the agents this endpoint drives normally do have tools. Native structured
69
+ * output would therefore fail for exactly the agents worth talking to, so the
70
+ * schema is injected as instructions instead - which costs nothing here because
71
+ * the answer is re-validated with `cardSpecSchema` before it is compiled.
72
+ */
73
+ const JSON_PROMPT_INJECTION = "system";
74
+ /** The bot's identity on outbound activities when the caller names none. */
75
+ export const BOT_ACCOUNT = {
76
+ id: "dbx-tools-teams-bot",
77
+ name: "Databricks Agent",
78
+ };
79
+ /**
80
+ * Instructions for the FORMATTING pass only - turning an answer the agent has
81
+ * already produced into the card vocabulary.
82
+ *
83
+ * Deliberately NOT sent with the user's question. Asking for a card and an
84
+ * answer in one request makes the model treat formatting as the task: it emits a
85
+ * card immediately instead of calling its tools, so a question that should have
86
+ * queried Genie came back as "I don't have a real system connected - here is a
87
+ * template card". Formatting is a separate, second pass over a real answer.
88
+ */
89
+ export const CARD_FORMAT_INSTRUCTIONS = [
90
+ "Reformat the assistant answer below as a Microsoft Teams Adaptive Card.",
91
+ "Preserve the answer's facts EXACTLY - every number, name, date and id.",
92
+ "Do not add caveats, placeholders or invented values, and do not describe the",
93
+ "card; if the answer states a value, that value belongs in the card.",
94
+ "Put the headline finding in `title` and keep it under ~60 characters.",
95
+ "Use `text` for the explanation, with '-' bullets for lists.",
96
+ "Use `facts` for key/value detail (metrics, counts, owners, ids) instead of",
97
+ "writing it as prose.",
98
+ "Add `actions` only for URLs present in the answer; never invent a link.",
99
+ "Drop any `[chart:...]` / `[data:...]` marker: a card cannot render one, so",
100
+ "write the values it stood for into `facts` or `text` instead.",
101
+ ].join(" ");
102
+ /**
103
+ * Nudge added to the ANSWERING pass.
104
+ *
105
+ * The agent answers the question normally here - tools included - so this only
106
+ * asks for the shape that survives compression into a card well. It must not
107
+ * mention cards, or the model starts formatting instead of answering.
108
+ */
109
+ export const CARD_ANSWER_INSTRUCTIONS = [
110
+ "Answer using your tools and data sources as you normally would.",
111
+ "Be concise and lead with the finding, and state concrete values",
112
+ "(numbers, names, dates) plainly so they can be summarized.",
113
+ // Agents on a chat endpoint are told to defer tables and charts to the host UI
114
+ // as `[data:<id>]` / `[chart:<id>]` markers. A card has no embed slot to fill,
115
+ // so a deferred number arrives as a literal `[data:01f1...]` in the card. The
116
+ // turn asks for the values themselves instead, and strips any that slip
117
+ // through (see EMBED_MARKER_RE).
118
+ "This channel cannot display chart or data embeds: do not emit",
119
+ "`[chart:...]` or `[data:...]` markers - write the actual numbers you",
120
+ "retrieved into your answer instead.",
121
+ ].join(" ");
122
+ /**
123
+ * A host-embed marker (`[chart:<id>]`, `[data:<id>]`) in an agent's prose.
124
+ *
125
+ * Chat hosts swap these for a rendered chart or table. An Adaptive Card has no
126
+ * such slot, so a marker that survives into card text renders as literal
127
+ * `[data:01f1895c-...]` noise where a number should be. The answering pass asks
128
+ * the agent not to emit them; this removes any that still arrive.
129
+ *
130
+ * The generic `[type:id]` grammar is spelled here rather than imported so this
131
+ * package stays a leaf add-on with no dependency on the agent plugin's
132
+ * contracts - it only ever needs to RECOGNIZE a marker, never resolve one.
133
+ */
134
+ const EMBED_MARKER_RE = /\[[A-Za-z][A-Za-z0-9_-]*:[^\]\s]+\]/g;
135
+ /**
136
+ * Drop embed markers from `text`, tidying the whitespace they leave behind so a
137
+ * marker that sat on its own line does not become a blank one.
138
+ */
139
+ const stripEmbedMarkers = (text) => text
140
+ .replace(EMBED_MARKER_RE, "")
141
+ .replace(/[ \t]+$/gm, "")
142
+ .replace(/\n{3,}/g, "\n\n")
143
+ .trim();
144
+ /** True when `value` exposes the `generate` a turn drives. */
145
+ const isCardAgent = (value) => typeof value?.generate === "function";
146
+ /** True when `value` exposes the agent-registry `exports()` a turn reads. */
147
+ const isAgentProvider = (value) => typeof value?.exports === "function";
148
+ /**
149
+ * Read one agent out of a provider's `exports()`.
150
+ *
151
+ * Every member is probed before it is called: the provider is matched
152
+ * structurally by plugin name, so a DIFFERENT plugin registered under that name
153
+ * can satisfy `isAgentProvider` (it has an `exports()`) while exposing no agent
154
+ * registry at all. Calling blindly would throw a `TypeError` out of route
155
+ * resolution; a miss is just "no agent", which the route reports as 503.
156
+ */
157
+ const readAgent = (provider, agentId) => {
158
+ const registry = provider.exports();
159
+ if (agentId)
160
+ return typeof registry.get === "function" ? registry.get(agentId) : null;
161
+ return typeof registry.getDefault === "function" ? registry.getDefault() : null;
162
+ };
163
+ /**
164
+ * Resolve the agent that answers a turn from the AppKit plugin registry.
165
+ *
166
+ * `agentId` picks a specific agent; omitted, the provider's default agent
167
+ * answers. Returns `null` when the provider is absent or the id is unknown, so
168
+ * the route can answer 503 / 404 instead of throwing.
169
+ */
170
+ export const resolveCardAgent = (plugins, providerName, agentId) => {
171
+ const provider = plugins?.get(providerName);
172
+ if (!isAgentProvider(provider))
173
+ return null;
174
+ const found = readAgent(provider, agentId);
175
+ return isCardAgent(found) ? found : null;
176
+ };
177
+ /**
178
+ * The agent plugin's request-context factory, when it exposes one.
179
+ *
180
+ * Resolved separately from the agent because it is the piece that gives an
181
+ * out-of-band turn the same tool reach as a chat turn; a provider without it
182
+ * still answers, just without user-scoped tools.
183
+ */
184
+ export const resolveCardContextFactory = (plugins, providerName) => {
185
+ const provider = plugins?.get(providerName);
186
+ if (!isAgentProvider(provider))
187
+ return null;
188
+ const registry = provider.exports();
189
+ const factory = registry.createRequestContext;
190
+ return typeof factory === "function" ? (options) => factory.call(registry, options) : null;
191
+ };
192
+ /**
193
+ * The text a `message` activity carries, or `null` when it carries none.
194
+ *
195
+ * A channel sends plenty of activities with no usable text (a `typing`
196
+ * indicator, a `conversationUpdate` when someone joins, or a `message` whose
197
+ * payload is only an attachment). Those are not errors - they simply produce no
198
+ * reply - so this returns `null` rather than throwing.
199
+ */
200
+ export const promptOf = (inbound) => inbound.type === "message" ? string.trimToNull(inbound.text ?? "") : null;
201
+ /**
202
+ * Build an outbound activity carrying `cards`, addressed back to the sender of
203
+ * `inbound`.
204
+ *
205
+ * Exported because a client rendering an optimistic local reply, and a test
206
+ * asserting the envelope, both need the same construction the turn uses.
207
+ */
208
+ export const toReplyActivity = (inbound, cards, options = {}) => ({
209
+ type: "message",
210
+ id: hash.id(),
211
+ timestamp: new Date().toISOString(),
212
+ from: options.bot ?? BOT_ACCOUNT,
213
+ ...(inbound.from ? { recipient: inbound.from } : {}),
214
+ ...(inbound.conversation ? { conversation: inbound.conversation } : {}),
215
+ ...(options.text ? { text: options.text } : {}),
216
+ attachments: cards.map((document) => activityContract.toCardAttachment(document)),
217
+ });
218
+ /**
219
+ * Recover a {@link card.CardSpec} from a full Adaptive Card DOCUMENT.
220
+ *
221
+ * A capable model asked for "a Microsoft Teams Adaptive Card" often answers with
222
+ * the finished 1.5 document instead of the small spec - correct Adaptive Card
223
+ * JSON, wrong schema, so `structuredOutput` rejects it (`title: expected
224
+ * string`) and a genuinely good answer is thrown away. Reading the document back
225
+ * into the spec vocabulary keeps it: the heading TextBlocks become
226
+ * title/subtitle, remaining TextBlocks the body, the FactSet the facts, and any
227
+ * `Action.OpenUrl` the actions.
228
+ *
229
+ * Deliberately tolerant about the container: `type` may be missing and the body
230
+ * may nest elements inside a `Container` / `ColumnSet`, so blocks are collected
231
+ * recursively and anything unrecognized is ignored.
232
+ */
233
+ export const documentCardSpec = (value) => {
234
+ if (!object.isRecord(value) || !Array.isArray(value.body))
235
+ return null;
236
+ const texts = [];
237
+ const facts = [];
238
+ const collect = (elements) => {
239
+ for (const element of elements) {
240
+ if (!object.isRecord(element))
241
+ continue;
242
+ if (element.type === "TextBlock") {
243
+ const text = string.trimToNull(typeof element.text === "string" ? element.text : "");
244
+ if (text)
245
+ texts.push(text);
246
+ }
247
+ else if (element.type === "FactSet" && Array.isArray(element.facts)) {
248
+ for (const fact of element.facts) {
249
+ const parsed = card.cardFactSchema.safeParse(fact);
250
+ if (parsed.success)
251
+ facts.push(parsed.data);
252
+ }
253
+ }
254
+ // A Container / ColumnSet / Column nests the blocks that matter.
255
+ for (const key of ["items", "columns"]) {
256
+ const nested = element[key];
257
+ if (Array.isArray(nested))
258
+ collect(nested);
259
+ }
260
+ }
261
+ };
262
+ collect(value.body);
263
+ const actions = [];
264
+ for (const action of Array.isArray(value.actions) ? value.actions : []) {
265
+ if (!object.isRecord(action))
266
+ continue;
267
+ const parsed = card.cardActionSchema.safeParse({ title: action.title, url: action.url });
268
+ if (parsed.success)
269
+ actions.push(parsed.data);
270
+ }
271
+ const [title, ...rest] = texts;
272
+ if (!title)
273
+ return null;
274
+ // The second block is a subtitle only when the document styled it as one;
275
+ // otherwise it is body text and must not be demoted to a subheading.
276
+ const second = object.isRecord(value.body[1]) ? value.body[1] : undefined;
277
+ const hasSubtitle = rest.length > 0 && second?.isSubtle === true;
278
+ const body = (hasSubtitle ? rest.slice(1) : rest).join("\n\n");
279
+ return {
280
+ title: toTitle(title),
281
+ ...(hasSubtitle && rest[0] ? { subtitle: rest[0] } : {}),
282
+ ...(body ? { text: body } : {}),
283
+ ...(facts.length > 0 ? { facts } : {}),
284
+ ...(actions.length > 0 ? { actions } : {}),
285
+ };
286
+ };
287
+ /**
288
+ * The card the model produced, wherever it ended up.
289
+ *
290
+ * `structuredOutput` rejects anything off-schema by THROWING, and Mastra puts
291
+ * the offending payload on the error (`details.value`) - so the model's real
292
+ * answer is recoverable from a failed call. Both the spec shape and a full
293
+ * Adaptive Card document are accepted, from an object or from JSON text.
294
+ */
295
+ export const rejectedCardSpec = (err) => {
296
+ const details = object.isRecord(err) ? err.details : undefined;
297
+ const value = object.isRecord(details) ? details.value : undefined;
298
+ const candidates = [];
299
+ if (typeof value === "string") {
300
+ candidates.push(json.parse(value, undefined));
301
+ }
302
+ else if (value !== undefined) {
303
+ candidates.push(value);
304
+ }
305
+ for (const candidate of candidates) {
306
+ const spec = card.cardSpecSchema.safeParse(candidate);
307
+ if (spec.success)
308
+ return spec.data;
309
+ const fromDocument = documentCardSpec(candidate);
310
+ if (fromDocument)
311
+ return fromDocument;
312
+ }
313
+ return null;
314
+ };
315
+ /**
316
+ * Turn whatever the agent produced into a card spec.
317
+ *
318
+ * `structuredOutput` is best-effort in practice, not a guarantee. Because the
319
+ * schema is prompt-injected (see {@link JSON_PROMPT_INJECTION}) rather than
320
+ * enforced by the provider, a model can answer with prose, with JSON wrapped in
321
+ * a ```` ```json ```` fence, or - on Databricks Model Serving - with an empty
322
+ * parsed object while the text carries the real answer. Observed failure rate on
323
+ * the demo endpoint was roughly one turn in three, all of which surfaced as a
324
+ * hard `STRUCTURED_OUTPUT_SCHEMA_VALIDATION_FAILED` and no reply at all.
325
+ *
326
+ * A missing card is not worth dropping the answer over, so this recovers in
327
+ * four stages: the parsed object when it validates; else the arguments the agent
328
+ * passed to `create_teams_card` (on the prose retry an agent holding that tool
329
+ * usually calls it, which is a REAL card spec, not a guess); else a JSON object
330
+ * embedded in the text; else the prose wrapped in a minimal text-only card. The
331
+ * user always gets the agent's answer; at worst it is less structured.
332
+ */
333
+ const toCardSpec = (result) => {
334
+ const parsed = card.cardSpecSchema.safeParse(result.object);
335
+ if (parsed.success)
336
+ return parsed.data;
337
+ // A model that answered with the finished Adaptive Card document rather than
338
+ // the spec still produced a real card; read it back into the spec vocabulary.
339
+ const fromDocument = documentCardSpec(result.object);
340
+ if (fromDocument)
341
+ return fromDocument;
342
+ // Prefer a card the agent explicitly composed via the tool over anything
343
+ // scraped out of its prose.
344
+ const fromTool = toolCardSpec(result);
345
+ if (fromTool)
346
+ return fromTool;
347
+ const text = string.trimToNull(result.text ?? "");
348
+ if (text) {
349
+ // A fenced or inline JSON object in the prose: the model followed the
350
+ // instructions but the provider did not surface a parsed object.
351
+ const embedded = text.match(/\{[\s\S]*\}/);
352
+ if (embedded) {
353
+ const value = json.parse(embedded[0], undefined);
354
+ const retry = card.cardSpecSchema.safeParse(value);
355
+ if (retry.success)
356
+ return retry.data;
357
+ const asDocument = documentCardSpec(value);
358
+ if (asDocument)
359
+ return asDocument;
360
+ }
361
+ // Prose only: keep the answer, drop the structure. The first line becomes
362
+ // the title (a card with no title renders as an untitled block), the rest
363
+ // stays as the body.
364
+ const lines = text
365
+ .split("\n")
366
+ .filter((line) => line.trim().length > 0)
367
+ // A model introducing its own answer ("Here is the Adaptive Card:") would
368
+ // otherwise become the card's headline, which reads as a bug. Drop the
369
+ // preamble so the first REAL line is the title.
370
+ .filter((line) => !PREAMBLE_RE.test(line.trim()));
371
+ const [first, ...rest] = lines;
372
+ const title = string.trimToNull(first ?? "") ?? "Answer";
373
+ const body = rest.join("\n").trim();
374
+ return {
375
+ title: toTitle(title),
376
+ ...(body ? { text: body } : title.length > 120 ? { text: title } : {}),
377
+ };
378
+ }
379
+ throw new Error("teams: the agent returned neither a card nor any text to fall back on");
380
+ };
381
+ /**
382
+ * A line that only announces the card rather than saying anything - e.g.
383
+ * "Here is the Adaptive Card:", "Here's your Teams card:", "Here are the card
384
+ * details:". Matched so it never becomes the card's title.
385
+ *
386
+ * Anchored to a "here is/are/here's ... card ..." opener that ENDS in a colon,
387
+ * which is what keeps it from eating a real sentence that merely mentions a card
388
+ * ("Here is the card reader status: offline." has text after the colon).
389
+ */
390
+ const PREAMBLE_RE = /^(here (is|are)|here's)\b[^.!?]*\bcard\b[^.!?:]*:\s*$/i;
391
+ /**
392
+ * Trim a line down to something usable as a card title. Adaptive Card titles are
393
+ * a single bold line, so an overlong one is truncated rather than wrapped; the
394
+ * markdown emphasis a model often adds is stripped since the title is already
395
+ * styled bold.
396
+ */
397
+ const toTitle = (value) => {
398
+ const plain = value
399
+ .replace(/^#+\s*/, "")
400
+ .replace(/\*\*/g, "")
401
+ .trim();
402
+ return plain.length > 120 ? `${plain.slice(0, 117)}...` : plain;
403
+ };
404
+ /**
405
+ * Compile an answer the agent has already produced into a card spec.
406
+ *
407
+ * A second, deliberately stateless pass: the formatting request is NOT threaded
408
+ * onto agent memory, so the conversation the user sees keeps only their question
409
+ * and the answer, not the reformatting chatter in between.
410
+ *
411
+ * Returns `null` when the pass is unusable (Mastra throws when the model returns
412
+ * no parsed object) so the caller can fall back to the answer text - a less
413
+ * structured card carrying the real answer beats losing the answer.
414
+ */
415
+ const formatAsCard = async (agent, prompt, answer, request) => {
416
+ const body = [
417
+ CARD_FORMAT_INSTRUCTIONS,
418
+ "",
419
+ `Question: ${prompt}`,
420
+ "",
421
+ "Assistant answer:",
422
+ answer,
423
+ ].join("\n");
424
+ const options = {
425
+ structuredOutput: {
426
+ schema: card.cardSpecSchema,
427
+ jsonPromptInjection: JSON_PROMPT_INJECTION,
428
+ },
429
+ ...request,
430
+ };
431
+ // Mastra THROWS when the model returns no parsed object, and because the
432
+ // schema is prompt-injected rather than provider-enforced that happens
433
+ // intermittently on the same input. One retry converts most of those misses
434
+ // into a proper card; the answer is already safe either way.
435
+ for (let attempt = 0; attempt < 2; attempt += 1) {
436
+ try {
437
+ return toCardSpec(await agent.generate(body, options));
438
+ }
439
+ catch (err) {
440
+ // The rejected payload usually IS the card - most often the full Adaptive
441
+ // Card document rather than the spec - so it is salvaged before retrying.
442
+ const rejected = rejectedCardSpec(err);
443
+ if (rejected) {
444
+ logger.debug("recovered the card from the rejected structured payload");
445
+ return rejected;
446
+ }
447
+ logger.warn("card formatting pass failed", {
448
+ attempt: attempt + 1,
449
+ error: error.errorMessage(err),
450
+ });
451
+ }
452
+ }
453
+ logger.warn("falling back to the answer text for the card");
454
+ return null;
455
+ };
456
+ /**
457
+ * Run one conversation turn: drive `agent` with the inbound activity's text and
458
+ * return the activities to append to the transcript.
459
+ *
460
+ * Returns an EMPTY array for an activity that carries no prompt (a typing
461
+ * indicator, a join event), which is exactly what a bot does with one - the
462
+ * route answers `{ activities: [] }` and the transcript is unchanged.
463
+ *
464
+ * Two agent calls, in this order:
465
+ *
466
+ * 1. the ANSWER - no `structuredOutput`, so the agent's tools are available
467
+ * and the content matches what the streaming endpoint would say;
468
+ * 2. the FORMAT - {@link formatAsCard} compiling that answer into a card.
469
+ *
470
+ * Every failure mode still yields the answer: a card the agent composed with
471
+ * `create_teams_card` during pass 1 short-circuits pass 2, and a failed pass 2
472
+ * falls back to {@link toCardSpec} over the answer text.
473
+ */
474
+ export const runCardTurn = async (agent, inbound, options = {}) => {
475
+ const prompt = promptOf(inbound);
476
+ if (!prompt)
477
+ return [];
478
+ const conversationId = inbound.conversation?.id;
479
+ const userId = inbound.from?.id;
480
+ const signal = options.signal ? { abortSignal: options.signal } : {};
481
+ // The AppKit user rides on this, so the agent's tools (Genie, serving, the
482
+ // model resolver) work exactly as they do on the chat endpoints. Built once
483
+ // and shared by both passes.
484
+ const requestContext = options.createRequestContext
485
+ ? await options.createRequestContext({
486
+ ...(conversationId ? { threadId: conversationId } : {}),
487
+ ...(userId ? { resourceId: userId } : {}),
488
+ })
489
+ : undefined;
490
+ const context = requestContext ? { requestContext } : {};
491
+ // Thread the conversation onto agent memory so the same `conversation.id`
492
+ // continues one conversation. Only passed when the client supplied both ids -
493
+ // Mastra requires the pair, and a memory-less agent ignores it.
494
+ const memory = conversationId && userId ? { memory: { thread: conversationId, resource: userId } } : {};
495
+ const answered = await agent.generate(`${prompt}\n\n${CARD_ANSWER_INSTRUCTIONS}`, {
496
+ ...memory,
497
+ ...context,
498
+ ...signal,
499
+ });
500
+ // An agent that composed a card itself has already said it in the right
501
+ // vocabulary; reformatting it would only risk paraphrasing the values.
502
+ const composed = toolCardSpec(answered);
503
+ const answer = string.trimToNull(stripEmbedMarkers(answered.text ?? ""));
504
+ const spec = composed ??
505
+ (answer ? await formatAsCard(agent, prompt, answer, { ...context, ...signal }) : null);
506
+ const document = buildAdaptiveCard(spec ?? toCardSpec({ ...answered, ...(answer ? { text: answer } : {}) }));
507
+ return [toReplyActivity(inbound, [document], { ...(options.bot ? { bot: options.bot } : {}) })];
508
+ };
509
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udmVyc2F0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbnZlcnNhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFDRztBQUVILE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2hGLE9BQU8sRUFBRSxRQUFRLElBQUksZ0JBQWdCLEVBQUUsSUFBSSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDN0UsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sV0FBVyxDQUFDO0FBRTlDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQztBQW1EaEQsbUVBQW1FO0FBQ25FLE1BQU0sZUFBZSxHQUFHLENBQUMsbUJBQW1CLEVBQUUsWUFBWSxDQUFDLENBQUM7QUFFNUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFlBQVksR0FBRyxDQUFDLE1BQW1CLEVBQXdCLEVBQUU7SUFDakUsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFNLENBQUMsV0FBVyxJQUFJLEVBQUUsRUFBRSxDQUFDO1FBQzdDLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxPQUFPLEVBQUUsUUFBUSxJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUM7UUFDdkQsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDO1lBQUUsU0FBUztRQUN2RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLElBQUksSUFBSSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEYsSUFBSSxNQUFNLENBQUMsT0FBTztZQUFFLE9BQU8sTUFBTSxDQUFD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RyxNQUFNO0tBQ1YsQ0FBQyxDQUFDO0lBRUgsd0VBQXdFO0lBQ3hFLHVFQUF1RTtJQUN2RSxNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDeEMsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDekUsTUFBTSxJQUFJLEdBQ1IsUUFBUTtRQUNSLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLFlBQVksQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxFQUFFLEdBQUcsT0FBTyxFQUFFLEdBQUcsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFekYsTUFBTSxRQUFRLEdBQUcsaUJBQWlCLENBQ2hDLElBQUksSUFBSSxVQUFVLENBQUMsRUFBRSxHQUFHLFFBQVEsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUN6RSxDQUFDO0lBQ0YsT0FBTyxDQUFDLGVBQWUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ2xHLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVGhlIFRlYW1zIGNvbnZlcnNhdGlvbiB0dXJuOiBydW4gYSBNYXN0cmEgYWdlbnQgYWdhaW5zdCBhbiBpbmJvdW5kIEJvdFxuICogRnJhbWV3b3JrIGFjdGl2aXR5IGFuZCBhbnN3ZXIgd2l0aCBBZGFwdGl2ZSBDYXJkIGF0dGFjaG1lbnRzLlxuICpcbiAqIFRoaXMgaXMgdGhlIHBpZWNlIHRoYXQgbWFrZXMgYFBPU1QgL2FwaS90ZWFtcy9hY3Rpdml0eWAgYmVoYXZlIGxpa2UgYSBUZWFtc1xuICogYm90IHJhdGhlciB0aGFuIGEgY2hhdCBBUEkgdGhhdCBoYXBwZW5zIHRvIHJldHVybiBKU09OLiBBIHR1cm4gaXM6XG4gKlxuICogICAxLiByZWFkIHRoZSB1c2VyJ3MgdGV4dCBvZmYgdGhlIGluYm91bmQgYG1lc3NhZ2VgIGFjdGl2aXR5O1xuICogICAyLiBBTlNXRVIgaXQgLSBhIG5vcm1hbCB0b29sLXVzaW5nIGFnZW50IHR1cm4sIHdpdGggbm8gbWVudGlvbiBvZiBjYXJkcywgc29cbiAqICAgICAgdGhlIGFnZW50IHF1ZXJpZXMgR2VuaWUgLyBjYWxscyBpdHMgdG9vbHMgZXhhY3RseSBhcyBpdCB3b3VsZCBvbiBhXG4gKiAgICAgIHN0cmVhbWluZyBjaGF0IGVuZHBvaW50O1xuICogICAzLiBGT1JNQVQgdGhhdCBhbnN3ZXIgaW50byBhIHtAbGluayBjYXJkLkNhcmRTcGVjfSBpbiBhIHNlY29uZCBwYXNzLCB2aWFcbiAqICAgICAgTWFzdHJhJ3MgYHN0cnVjdHVyZWRPdXRwdXRgIChwcm9tcHQtaW5qZWN0ZWQsIHNlZVxuICogICAgICB7QGxpbmsgSlNPTl9QUk9NUFRfSU5KRUNUSU9OfSk7XG4gKiAgIDQuIGNvbXBpbGUgdGhlIHNwZWMgd2l0aCB0aGUgc2FtZSBkZXRlcm1pbmlzdGljIGJ1aWxkZXIgdGhlXG4gKiAgICAgIGBjcmVhdGVfdGVhbXNfY2FyZGAgdG9vbCB1c2VzLCBhbmQgYXR0YWNoIGl0IHRvIGFuIG91dGJvdW5kIGFjdGl2aXR5LlxuICpcbiAqIFRoZSB0d28gcGFzc2VzIGFyZSB0aGUgaW1wb3J0YW50IHBhcnQuIEFza2luZyBmb3IgdGhlIGFuc3dlciBBTkQgdGhlIGNhcmRcbiAqIHNoYXBlIGluIE9ORSByZXF1ZXN0IG1ha2VzIHRoZSBtb2RlbCB0cmVhdCBmb3JtYXR0aW5nIGFzIHRoZSB0YXNrOiBpdCBlbWl0cyBhXG4gKiBjYXJkIHN0cmFpZ2h0IGF3YXkgYW5kIG5ldmVyIGNhbGxzIGl0cyB0b29scywgc28gYSBxdWVzdGlvbiB0aGF0IHNob3VsZCBoYXZlXG4gKiBxdWVyaWVkIGEgZGF0YSBzb3VyY2UgY2FtZSBiYWNrIGFzIFwiSSBkb24ndCBoYXZlIGEgcmVhbCBzeXN0ZW0gY29ubmVjdGVkIC1cbiAqIGhlcmUgaXMgYSB0ZW1wbGF0ZSBjYXJkIHdpdGggcGxhY2Vob2xkZXJzXCIuIEFuc3dlcmluZyBmaXJzdCwgdGhlbiBmb3JtYXR0aW5nIGFcbiAqIFJFQUwgYW5zd2VyLCBtYWtlcyB0aGlzIGVuZHBvaW50J3MgY29udGVudCBpZGVudGljYWwgdG8gdGhlIHN0cmVhbWluZ1xuICogZW5kcG9pbnQnczsgb25seSB0aGUgcHJlc2VudGF0aW9uIGRpZmZlcnMuXG4gKlxuICogRm9ybWF0dGluZyBpcyBhbHNvIHdoeSB0aGUgdHVybiBkb2VzIG5vdCBzaW1wbHkgcmVseSBvbiB0aGUgYWdlbnQgY2FsbGluZ1xuICogYGNyZWF0ZV90ZWFtc19jYXJkYDogb24gdGhpcyBlbmRwb2ludCBhIGNhcmQgSVMgdGhlIHJlc3BvbnNlIGZvcm1hdCwgc28gaXRcbiAqIHNob3VsZCBiZSBhIHByb3BlcnR5IG9mIHRoZSB0dXJuIHJhdGhlciB0aGFuIGEgdG9vbCB0aGUgbW9kZWwgbWF5IGZvcmdldC5cbiAqIEFnZW50cyBrZWVwIHRoZSB0b29sIGZvciB0aGUgb3RoZXIgZGlyZWN0aW9uIC0gYW5zd2VyaW5nIGluIHByb3NlIG9uIGEgbm9ybWFsXG4gKiBjaGF0IGVuZHBvaW50IGFuZCBjaG9vc2luZyB0byBhdHRhY2ggYSBjYXJkLiBXaGVuIHRoZSBhZ2VudCBET0VTIGNhbGwgaXRcbiAqIGR1cmluZyB0aGUgYW5zd2VyaW5nIHBhc3MsIHRoYXQgc3BlYyB3aW5zIGFuZCB0aGUgZm9ybWF0dGluZyBwYXNzIGlzIHNraXBwZWQuXG4gKlxuICogVGhlIGNvbnZlcnNhdGlvbiBpZCBkb3VibGVzIGFzIHRoZSBhZ2VudCdzIG1lbW9yeSB0aHJlYWQgaWQsIHNvIGEgY2xpZW50IHRoYXRcbiAqIGtlZXBzIHBvc3RpbmcgdGhlIHNhbWUgYGNvbnZlcnNhdGlvbi5pZGAgZ2V0cyBhIGNvbnRpbnVvdXMgY29udmVyc2F0aW9uIC0gdGhlXG4gKiBzYW1lIG1hcHBpbmcgYSByZWFsIGNoYW5uZWwgcmVsaWVzIG9uLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBlcnJvciwgaGFzaCwganNvbiwgbG9nLCBvYmplY3QsIHN0cmluZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgeyBhY3Rpdml0eSBhcyBhY3Rpdml0eUNvbnRyYWN0LCBjYXJkIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLXRlYW1zXCI7XG5pbXBvcnQgeyBidWlsZEFkYXB0aXZlQ2FyZCB9IGZyb20gXCIuL2J1aWxkZXJcIjtcblxuY29uc3QgbG9nZ2VyID0gbG9nLmxvZ2dlcihcInRlYW1zOmNvbnZlcnNhdGlvblwiKTtcblxuLyoqXG4gKiBNaW5pbWFsIHN0cnVjdHVyYWwgc2hhcGUgb2YgdGhlIE1hc3RyYSBgQWdlbnRgIHRoaXMgbW9kdWxlIGRyaXZlcy5cbiAqXG4gKiBEZWNsYXJlZCBzdHJ1Y3R1cmFsbHkgcmF0aGVyIHRoYW4gaW1wb3J0aW5nIGBAbWFzdHJhL2NvcmVgJ3MgYEFnZW50YDogdGhpc1xuICogcGFja2FnZSBtdXN0IG5vdCBkZXBlbmQgb24gdGhlIE1hc3RyYSBwbHVnaW4gKHRoZSBwbHVnaW4gZGVwZW5kcyBvbiBub3RoaW5nXG4gKiBoZXJlIGVpdGhlciksIGFuZCBhIHR1cm4gb25seSBldmVyIG5lZWRzIGBnZW5lcmF0ZWAuIEFueSBvYmplY3Qgd2l0aCBhXG4gKiBjb21wYXRpYmxlIGBnZW5lcmF0ZWAgc2F0aXNmaWVzIGl0LCB3aGljaCBhbHNvIG1ha2VzIHRoZSB0dXJuIHRyaXZpYWxseVxuICogdGVzdGFibGUgd2l0aCBhIHN0dWIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2FyZEFnZW50TGlrZSB7XG4gIGdlbmVyYXRlKFxuICAgIHByb21wdDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IHtcbiAgICAgIHN0cnVjdHVyZWRPdXRwdXQ/OiB7XG4gICAgICAgIHNjaGVtYTogdHlwZW9mIGNhcmQuY2FyZFNwZWNTY2hlbWE7XG4gICAgICAgIGpzb25Qcm9tcHRJbmplY3Rpb24/OiBib29sZWFuIHwgXCJzeXN0ZW1cIiB8IFwiaW5saW5lXCI7XG4gICAgICB9O1xuICAgICAgbWVtb3J5PzogeyB0aHJlYWQ6IHN0cmluZzsgcmVzb3VyY2U6IHN0cmluZyB9O1xuICAgICAgLyoqXG4gICAgICAgKiBNYXN0cmEncyBwZXItdHVybiBgUmVxdWVzdENvbnRleHRgLiBPcGFxdWUgaGVyZSAtIHRoZSBvYmplY3QgY29tZXMgZnJvbVxuICAgICAgICogdGhlIGFnZW50IHBsdWdpbiAoc2VlIHtAbGluayBBZ2VudFByb3ZpZGVyTGlrZS5leHBvcnRzfSkgYW5kIGlzIG9ubHlcbiAgICAgICAqIGZvcndhcmRlZCAtIGJ1dCBSRVFVSVJFRCBmb3IgcGFyaXR5IHdpdGggdGhlIGNoYXQgZW5kcG9pbnRzOiBNYXN0cmEnc1xuICAgICAgICogdXNlci1zY29wZWQgdG9vbHMgcmVhZCB0aGUgQXBwS2l0IHVzZXIgb2ZmIGl0LCBzbyBhIHR1cm4gd2l0aG91dCBvbmVcbiAgICAgICAqIGFuc3dlcnMgXCJ0aGUgZGF0YSBzb3VyY2UgaXMgdW5yZWFjaGFibGVcIiB3aGVyZSBjaGF0IGFuc3dlcnMgd2l0aCBkYXRhLlxuICAgICAgICovXG4gICAgICByZXF1ZXN0Q29udGV4dD86IHVua25vd247XG4gICAgICBhYm9ydFNpZ25hbD86IEFib3J0U2lnbmFsO1xuICAgIH0sXG4gICk6IFByb21pc2U8QWdlbnRSZXN1bHQ+O1xufVxuXG4vKipcbiAqIFRoZSBzbGljZSBvZiBNYXN0cmEncyBgZ2VuZXJhdGVgIHJlc3VsdCBhIHR1cm4gcmVhZHMuXG4gKlxuICogYHRvb2xSZXN1bHRzYCBtYXR0ZXJzIGFzIG11Y2ggYXMgYG9iamVjdGAgaGVyZTogd2hlbiBzdHJ1Y3R1cmVkIG91dHB1dCBmYWlsc1xuICogYW5kIHRoZSB0dXJuIHJlLWFza3MgYXMgcHJvc2UsIGFuIGFnZW50IGhvbGRpbmcgdGhlIGBjcmVhdGVfdGVhbXNfY2FyZGAgdG9vbFxuICogdHlwaWNhbGx5IENBTExTIGl0LCBzbyB0aGUgYmVzdCBhdmFpbGFibGUgY2FyZCBzcGVjIGlzIHRoZSB0b29sJ3MgYXJndW1lbnRzIC1cbiAqIGFscmVhZHkgaW4gdGhlIHJpZ2h0IHZvY2FidWxhcnkgLSByYXRoZXIgdGhhbiBhbnl0aGluZyBpbiB0aGUgcHJvc2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQWdlbnRSZXN1bHQge1xuICBvYmplY3Q/OiB1bmtub3duO1xuICB0ZXh0Pzogc3RyaW5nO1xuICB0b29sUmVzdWx0cz86IHtcbiAgICBwYXlsb2FkPzogeyB0b29sTmFtZT86IHN0cmluZzsgYXJncz86IHVua25vd24gfTtcbiAgICB0b29sTmFtZT86IHN0cmluZztcbiAgICBhcmdzPzogdW5rbm93bjtcbiAgfVtdO1xufVxuXG4vKiogVG9vbCBpZCB3aG9zZSBhcmd1bWVudHMgYXJlIGFscmVhZHkgYSB7QGxpbmsgY2FyZC5DYXJkU3BlY30uICovXG5jb25zdCBDQVJEX1RPT0xfTkFNRVMgPSBbXCJjcmVhdGVfdGVhbXNfY2FyZFwiLCBcImNyZWF0ZUNhcmRcIl07XG5cbi8qKlxuICogVGhlIGNhcmQgc3BlYyBhbiBhZ2VudCBwYXNzZWQgdG8gdGhlIGNhcmQgdG9vbCwgaWYgaXQgY2FsbGVkIGl0LlxuICpcbiAqIE1hc3RyYSBuZXN0cyBhIHRvb2wgcmVzdWx0IHVuZGVyIGBwYXlsb2FkYCAoYHsgcGF5bG9hZDogeyB0b29sTmFtZSwgYXJncyB9IH1gKVxuICogYnV0IGhhcyB1c2VkIGEgZmxhdCBzaGFwZSB0b28sIHNvIGJvdGggYXJlIHJlYWQuXG4gKi9cbmNvbnN0IHRvb2xDYXJkU3BlYyA9IChyZXN1bHQ6IEFnZW50UmVzdWx0KTogY2FyZC5DYXJkU3BlYyB8IG51bGwgPT4ge1xuICBmb3IgKGNvbnN0IGVudHJ5IG9mIHJlc3VsdC50b29sUmVzdWx0cyA/PyBbXSkge1xuICAgIGNvbnN0IG5hbWUgPSBlbnRyeS5wYXlsb2FkPy50b29sTmFtZSA/PyBlbnRyeS50b29sTmFtZTtcbiAgICBpZiAoIW5hbWUgfHwgIUNBUkRfVE9PTF9OQU1FUy5pbmNsdWRlcyhuYW1lKSkgY29udGludWU7XG4gICAgY29uc3QgcGFyc2VkID0gY2FyZC5jYXJkU3BlY1NjaGVtYS5zYWZlUGFyc2UoZW50cnkucGF5bG9hZD8uYXJncyA/PyBlbnRyeS5hcmdzKTtcbiAgICBpZiAocGFyc2VkLnN1Y2Nlc3MpIHJldHVybiBwYXJzZWQuZGF0YTtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn07XG5cbi8qKlxuICogQXNrIGZvciB0aGUgY2FyZCBzaGFwZSB2aWEgUFJPTVBUIGluamVjdGlvbiByYXRoZXIgdGhhbiB0aGUgcHJvdmlkZXIncyBuYXRpdmVcbiAqIHJlc3BvbnNlIGZvcm1hdC5cbiAqXG4gKiBEYXRhYnJpY2tzIE1vZGVsIFNlcnZpbmcgcmVqZWN0cyBhIHJlcXVlc3QgY2FycnlpbmcgYm90aCBgcmVzcG9uc2VfZm9ybWF0YCBhbmRcbiAqIGB0b29sc2AgKFwiQ2Fubm90IHNwZWNpZnkgYm90aCByZXNwb25zZV9mb3JtYXQgYW5kIHRvb2xzIGluIHRoZSBzYW1lIHJlcXVlc3RcIiksXG4gKiBhbmQgdGhlIGFnZW50cyB0aGlzIGVuZHBvaW50IGRyaXZlcyBub3JtYWxseSBkbyBoYXZlIHRvb2xzLiBOYXRpdmUgc3RydWN0dXJlZFxuICogb3V0cHV0IHdvdWxkIHRoZXJlZm9yZSBmYWlsIGZvciBleGFjdGx5IHRoZSBhZ2VudHMgd29ydGggdGFsa2luZyB0bywgc28gdGhlXG4gKiBzY2hlbWEgaXMgaW5qZWN0ZWQgYXMgaW5zdHJ1Y3Rpb25zIGluc3RlYWQgLSB3aGljaCBjb3N0cyBub3RoaW5nIGhlcmUgYmVjYXVzZVxuICogdGhlIGFuc3dlciBpcyByZS12YWxpZGF0ZWQgd2l0aCBgY2FyZFNwZWNTY2hlbWFgIGJlZm9yZSBpdCBpcyBjb21waWxlZC5cbiAqL1xuY29uc3QgSlNPTl9QUk9NUFRfSU5KRUNUSU9OID0gXCJzeXN0ZW1cIiBhcyBjb25zdDtcblxuLyoqIFRoZSBib3QncyBpZGVudGl0eSBvbiBvdXRib3VuZCBhY3Rpdml0aWVzIHdoZW4gdGhlIGNhbGxlciBuYW1lcyBub25lLiAqL1xuZXhwb3J0IGNvbnN0IEJPVF9BQ0NPVU5UOiBhY3Rpdml0eUNvbnRyYWN0LkNoYW5uZWxBY2NvdW50ID0ge1xuICBpZDogXCJkYngtdG9vbHMtdGVhbXMtYm90XCIsXG4gIG5hbWU6IFwiRGF0YWJyaWNrcyBBZ2VudFwiLFxufTtcblxuLyoqXG4gKiBJbnN0cnVjdGlvbnMgZm9yIHRoZSBGT1JNQVRUSU5HIHBhc3Mgb25seSAtIHR1cm5pbmcgYW4gYW5zd2VyIHRoZSBhZ2VudCBoYXNcbiAqIGFscmVhZHkgcHJvZHVjZWQgaW50byB0aGUgY2FyZCB2b2NhYnVsYXJ5LlxuICpcbiAqIERlbGliZXJhdGVseSBOT1Qgc2VudCB3aXRoIHRoZSB1c2VyJ3MgcXVlc3Rpb24uIEFza2luZyBmb3IgYSBjYXJkIGFuZCBhblxuICogYW5zd2VyIGluIG9uZSByZXF1ZXN0IG1ha2VzIHRoZSBtb2RlbCB0cmVhdCBmb3JtYXR0aW5nIGFzIHRoZSB0YXNrOiBpdCBlbWl0cyBhXG4gKiBjYXJkIGltbWVkaWF0ZWx5IGluc3RlYWQgb2YgY2FsbGluZyBpdHMgdG9vbHMsIHNvIGEgcXVlc3Rpb24gdGhhdCBzaG91bGQgaGF2ZVxuICogcXVlcmllZCBHZW5pZSBjYW1lIGJhY2sgYXMgXCJJIGRvbid0IGhhdmUgYSByZWFsIHN5c3RlbSBjb25uZWN0ZWQgLSBoZXJlIGlzIGFcbiAqIHRlbXBsYXRlIGNhcmRcIi4gRm9ybWF0dGluZyBpcyBhIHNlcGFyYXRlLCBzZWNvbmQgcGFzcyBvdmVyIGEgcmVhbCBhbnN3ZXIuXG4gKi9cbmV4cG9ydCBjb25zdCBDQVJEX0ZPUk1BVF9JTlNUUlVDVElPTlMgPSBbXG4gIFwiUmVmb3JtYXQgdGhlIGFzc2lzdGFudCBhbnN3ZXIgYmVsb3cgYXMgYSBNaWNyb3NvZnQgVGVhbXMgQWRhcHRpdmUgQ2FyZC5cIixcbiAgXCJQcmVzZXJ2ZSB0aGUgYW5zd2VyJ3MgZmFjdHMgRVhBQ1RMWSAtIGV2ZXJ5IG51bWJlciwgbmFtZSwgZGF0ZSBhbmQgaWQuXCIsXG4gIFwiRG8gbm90IGFkZCBjYXZlYXRzLCBwbGFjZWhvbGRlcnMgb3IgaW52ZW50ZWQgdmFsdWVzLCBhbmQgZG8gbm90IGRlc2NyaWJlIHRoZVwiLFxuICBcImNhcmQ7IGlmIHRoZSBhbnN3ZXIgc3RhdGVzIGEgdmFsdWUsIHRoYXQgdmFsdWUgYmVsb25ncyBpbiB0aGUgY2FyZC5cIixcbiAgXCJQdXQgdGhlIGhlYWRsaW5lIGZpbmRpbmcgaW4gYHRpdGxlYCBhbmQga2VlcCBpdCB1bmRlciB+NjAgY2hhcmFjdGVycy5cIixcbiAgXCJVc2UgYHRleHRgIGZvciB0aGUgZXhwbGFuYXRpb24sIHdpdGggJy0nIGJ1bGxldHMgZm9yIGxpc3RzLlwiLFxuICBcIlVzZSBgZmFjdHNgIGZvciBrZXkvdmFsdWUgZGV0YWlsIChtZXRyaWNzLCBjb3VudHMsIG93bmVycywgaWRzKSBpbnN0ZWFkIG9mXCIsXG4gIFwid3JpdGluZyBpdCBhcyBwcm9zZS5cIixcbiAgXCJBZGQgYGFjdGlvbnNgIG9ubHkgZm9yIFVSTHMgcHJlc2VudCBpbiB0aGUgYW5zd2VyOyBuZXZlciBpbnZlbnQgYSBsaW5rLlwiLFxuICBcIkRyb3AgYW55IGBbY2hhcnQ6Li4uXWAgLyBgW2RhdGE6Li4uXWAgbWFya2VyOiBhIGNhcmQgY2Fubm90IHJlbmRlciBvbmUsIHNvXCIsXG4gIFwid3JpdGUgdGhlIHZhbHVlcyBpdCBzdG9vZCBmb3IgaW50byBgZmFjdHNgIG9yIGB0ZXh0YCBpbnN0ZWFkLlwiLFxuXS5qb2luKFwiIFwiKTtcblxuLyoqXG4gKiBOdWRnZSBhZGRlZCB0byB0aGUgQU5TV0VSSU5HIHBhc3MuXG4gKlxuICogVGhlIGFnZW50IGFuc3dlcnMgdGhlIHF1ZXN0aW9uIG5vcm1hbGx5IGhlcmUgLSB0b29scyBpbmNsdWRlZCAtIHNvIHRoaXMgb25seVxuICogYXNrcyBmb3IgdGhlIHNoYXBlIHRoYXQgc3Vydml2ZXMgY29tcHJlc3Npb24gaW50byBhIGNhcmQgd2VsbC4gSXQgbXVzdCBub3RcbiAqIG1lbnRpb24gY2FyZHMsIG9yIHRoZSBtb2RlbCBzdGFydHMgZm9ybWF0dGluZyBpbnN0ZWFkIG9mIGFuc3dlcmluZy5cbiAqL1xuZXhwb3J0IGNvbnN0IENBUkRfQU5TV0VSX0lOU1RSVUNUSU9OUyA9IFtcbiAgXCJBbnN3ZXIgdXNpbmcgeW91ciB0b29scyBhbmQgZGF0YSBzb3VyY2VzIGFzIHlvdSBub3JtYWxseSB3b3VsZC5cIixcbiAgXCJCZSBjb25jaXNlIGFuZCBsZWFkIHdpdGggdGhlIGZpbmRpbmcsIGFuZCBzdGF0ZSBjb25jcmV0ZSB2YWx1ZXNcIixcbiAgXCIobnVtYmVycywgbmFtZXMsIGRhdGVzKSBwbGFpbmx5IHNvIHRoZXkgY2FuIGJlIHN1bW1hcml6ZWQuXCIsXG4gIC8vIEFnZW50cyBvbiBhIGNoYXQgZW5kcG9pbnQgYXJlIHRvbGQgdG8gZGVmZXIgdGFibGVzIGFuZCBjaGFydHMgdG8gdGhlIGhvc3QgVUlcbiAgLy8gYXMgYFtkYXRhOjxpZD5dYCAvIGBbY2hhcnQ6PGlkPl1gIG1hcmtlcnMuIEEgY2FyZCBoYXMgbm8gZW1iZWQgc2xvdCB0byBmaWxsLFxuICAvLyBzbyBhIGRlZmVycmVkIG51bWJlciBhcnJpdmVzIGFzIGEgbGl0ZXJhbCBgW2RhdGE6MDFmMS4uLl1gIGluIHRoZSBjYXJkLiBUaGVcbiAgLy8gdHVybiBhc2tzIGZvciB0aGUgdmFsdWVzIHRoZW1zZWx2ZXMgaW5zdGVhZCwgYW5kIHN0cmlwcyBhbnkgdGhhdCBzbGlwXG4gIC8vIHRocm91Z2ggKHNlZSBFTUJFRF9NQVJLRVJfUkUpLlxuICBcIlRoaXMgY2hhbm5lbCBjYW5ub3QgZGlzcGxheSBjaGFydCBvciBkYXRhIGVtYmVkczogZG8gbm90IGVtaXRcIixcbiAgXCJgW2NoYXJ0Oi4uLl1gIG9yIGBbZGF0YTouLi5dYCBtYXJrZXJzIC0gd3JpdGUgdGhlIGFjdHVhbCBudW1iZXJzIHlvdVwiLFxuICBcInJldHJpZXZlZCBpbnRvIHlvdXIgYW5zd2VyIGluc3RlYWQuXCIsXG5dLmpvaW4oXCIgXCIpO1xuXG4vKipcbiAqIEEgaG9zdC1lbWJlZCBtYXJrZXIgKGBbY2hhcnQ6PGlkPl1gLCBgW2RhdGE6PGlkPl1gKSBpbiBhbiBhZ2VudCdzIHByb3NlLlxuICpcbiAqIENoYXQgaG9zdHMgc3dhcCB0aGVzZSBmb3IgYSByZW5kZXJlZCBjaGFydCBvciB0YWJsZS4gQW4gQWRhcHRpdmUgQ2FyZCBoYXMgbm9cbiAqIHN1Y2ggc2xvdCwgc28gYSBtYXJrZXIgdGhhdCBzdXJ2aXZlcyBpbnRvIGNhcmQgdGV4dCByZW5kZXJzIGFzIGxpdGVyYWxcbiAqIGBbZGF0YTowMWYxODk1Yy0uLi5dYCBub2lzZSB3aGVyZSBhIG51bWJlciBzaG91bGQgYmUuIFRoZSBhbnN3ZXJpbmcgcGFzcyBhc2tzXG4gKiB0aGUgYWdlbnQgbm90IHRvIGVtaXQgdGhlbTsgdGhpcyByZW1vdmVzIGFueSB0aGF0IHN0aWxsIGFycml2ZS5cbiAqXG4gKiBUaGUgZ2VuZXJpYyBgW3R5cGU6aWRdYCBncmFtbWFyIGlzIHNwZWxsZWQgaGVyZSByYXRoZXIgdGhhbiBpbXBvcnRlZCBzbyB0aGlzXG4gKiBwYWNrYWdlIHN0YXlzIGEgbGVhZiBhZGQtb24gd2l0aCBubyBkZXBlbmRlbmN5IG9uIHRoZSBhZ2VudCBwbHVnaW4nc1xuICogY29udHJhY3RzIC0gaXQgb25seSBldmVyIG5lZWRzIHRvIFJFQ09HTklaRSBhIG1hcmtlciwgbmV2ZXIgcmVzb2x2ZSBvbmUuXG4gKi9cbmNvbnN0IEVNQkVEX01BUktFUl9SRSA9IC9cXFtbQS1aYS16XVtBLVphLXowLTlfLV0qOlteXFxdXFxzXStcXF0vZztcblxuLyoqXG4gKiBEcm9wIGVtYmVkIG1hcmtlcnMgZnJvbSBgdGV4dGAsIHRpZHlpbmcgdGhlIHdoaXRlc3BhY2UgdGhleSBsZWF2ZSBiZWhpbmQgc28gYVxuICogbWFya2VyIHRoYXQgc2F0IG9uIGl0cyBvd24gbGluZSBkb2VzIG5vdCBiZWNvbWUgYSBibGFuayBvbmUuXG4gKi9cbmNvbnN0IHN0cmlwRW1iZWRNYXJrZXJzID0gKHRleHQ6IHN0cmluZyk6IHN0cmluZyA9PlxuICB0ZXh0XG4gICAgLnJlcGxhY2UoRU1CRURfTUFSS0VSX1JFLCBcIlwiKVxuICAgIC5yZXBsYWNlKC9bIFxcdF0rJC9nbSwgXCJcIilcbiAgICAucmVwbGFjZSgvXFxuezMsfS9nLCBcIlxcblxcblwiKVxuICAgIC50cmltKCk7XG5cbi8qKlxuICogU3RydWN0dXJhbCBzaGFwZSBvZiB0aGUgc2libGluZyBwbHVnaW4gdGhhdCBvd25zIHRoZSBhZ2VudCByZWdpc3RyeSAtIHRoZVxuICogc2xpY2Ugb2YgYEBkYngtdG9vbHMvYXBwa2l0LW1hc3RyYWAncyBgZXhwb3J0cygpYCBhIHR1cm4gbmVlZHMuXG4gKlxuICogTWF0Y2hlZCBzdHJ1Y3R1cmFsbHksIGJ5IHJlZ2lzdGVyZWQgcGx1Z2luIE5BTUUsIHJhdGhlciB0aGFuIGltcG9ydGluZyB0aGVcbiAqIE1hc3RyYSBwbHVnaW46IHRoaXMgcGFja2FnZSBzdGF5cyBhIGxlYWYgYWRkLW9uIChpdCBkZXBlbmRzIG9uIG5vIG90aGVyXG4gKiBkYngtdG9vbHMgcnVudGltZSBwYWNrYWdlLCBsaWtlIG5vZGUtZW1haWwpLCB0aGUgZGVwZW5kZW5jeSBkaXJlY3Rpb24gc3RheXNcbiAqIG9uZS13YXksIGFuZCBhbnkgcGx1Z2luIGV4cG9zaW5nIHRoZSBzYW1lIGBnZXRgIC8gYGdldERlZmF1bHRgIHBhaXIgY2FuIGJhY2tcbiAqIHRoZSBlbmRwb2ludC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBZ2VudFByb3ZpZGVyTGlrZSB7XG4gIGV4cG9ydHMoKToge1xuICAgIGdldChpZDogc3RyaW5nKTogdW5rbm93bjtcbiAgICBnZXREZWZhdWx0KCk6IHVua25vd247XG4gICAgLyoqXG4gICAgICogQnVpbGRzIHRoZSBwZXItdHVybiBgUmVxdWVzdENvbnRleHRgIHRoZSBwcm92aWRlcidzIHRvb2xzIGV4cGVjdC4gT3B0aW9uYWxcbiAgICAgKiBzbyBhbiBvbGRlciBwcm92aWRlciAob3IgYSBkaWZmZXJlbnRseS1zaGFwZWQgb25lKSBzdGlsbCByZXNvbHZlcyBhblxuICAgICAqIGFnZW50OyB0aGUgdHVybiBzaW1wbHkgcnVucyB3aXRob3V0IHVzZXItc2NvcGVkIHRvb2wgY29udGV4dCB0aGVuLlxuICAgICAqL1xuICAgIGNyZWF0ZVJlcXVlc3RDb250ZXh0PyhvcHRpb25zOiB7IHRocmVhZElkPzogc3RyaW5nOyByZXNvdXJjZUlkPzogc3RyaW5nIH0pOiBQcm9taXNlPHVua25vd24+O1xuICB9O1xufVxuXG4vKiogVHJ1ZSB3aGVuIGB2YWx1ZWAgZXhwb3NlcyB0aGUgYGdlbmVyYXRlYCBhIHR1cm4gZHJpdmVzLiAqL1xuY29uc3QgaXNDYXJkQWdlbnQgPSAodmFsdWU6IHVua25vd24pOiB2YWx1ZSBpcyBDYXJkQWdlbnRMaWtlID0+XG4gIHR5cGVvZiAodmFsdWUgYXMgQ2FyZEFnZW50TGlrZSB8IG51bGwpPy5nZW5lcmF0ZSA9PT0gXCJmdW5jdGlvblwiO1xuXG4vKiogVHJ1ZSB3aGVuIGB2YWx1ZWAgZXhwb3NlcyB0aGUgYWdlbnQtcmVnaXN0cnkgYGV4cG9ydHMoKWAgYSB0dXJuIHJlYWRzLiAqL1xuY29uc3QgaXNBZ2VudFByb3ZpZGVyID0gKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgQWdlbnRQcm92aWRlckxpa2UgPT5cbiAgdHlwZW9mICh2YWx1ZSBhcyBBZ2VudFByb3ZpZGVyTGlrZSB8IG51bGwpPy5leHBvcnRzID09PSBcImZ1bmN0aW9uXCI7XG5cbi8qKlxuICogUmVhZCBvbmUgYWdlbnQgb3V0IG9mIGEgcHJvdmlkZXIncyBgZXhwb3J0cygpYC5cbiAqXG4gKiBFdmVyeSBtZW1iZXIgaXMgcHJvYmVkIGJlZm9yZSBpdCBpcyBjYWxsZWQ6IHRoZSBwcm92aWRlciBpcyBtYXRjaGVkXG4gKiBzdHJ1Y3R1cmFsbHkgYnkgcGx1Z2luIG5hbWUsIHNvIGEgRElGRkVSRU5UIHBsdWdpbiByZWdpc3RlcmVkIHVuZGVyIHRoYXQgbmFtZVxuICogY2FuIHNhdGlzZnkgYGlzQWdlbnRQcm92aWRlcmAgKGl0IGhhcyBhbiBgZXhwb3J0cygpYCkgd2hpbGUgZXhwb3Npbmcgbm8gYWdlbnRcbiAqIHJlZ2lzdHJ5IGF0IGFsbC4gQ2FsbGluZyBibGluZGx5IHdvdWxkIHRocm93IGEgYFR5cGVFcnJvcmAgb3V0IG9mIHJvdXRlXG4gKiByZXNvbHV0aW9uOyBhIG1pc3MgaXMganVzdCBcIm5vIGFnZW50XCIsIHdoaWNoIHRoZSByb3V0ZSByZXBvcnRzIGFzIDUwMy5cbiAqL1xuY29uc3QgcmVhZEFnZW50ID0gKHByb3ZpZGVyOiBBZ2VudFByb3ZpZGVyTGlrZSwgYWdlbnRJZD86IHN0cmluZyk6IHVua25vd24gPT4ge1xuICBjb25zdCByZWdpc3RyeSA9IHByb3ZpZGVyLmV4cG9ydHMoKSBhcyBQYXJ0aWFsPFJldHVyblR5cGU8QWdlbnRQcm92aWRlckxpa2VbXCJleHBvcnRzXCJdPj47XG4gIGlmIChhZ2VudElkKSByZXR1cm4gdHlwZW9mIHJlZ2lzdHJ5LmdldCA9PT0gXCJmdW5jdGlvblwiID8gcmVnaXN0cnkuZ2V0KGFnZW50SWQpIDogbnVsbDtcbiAgcmV0dXJuIHR5cGVvZiByZWdpc3RyeS5nZXREZWZhdWx0ID09PSBcImZ1bmN0aW9uXCIgPyByZWdpc3RyeS5nZXREZWZhdWx0KCkgOiBudWxsO1xufTtcblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBhZ2VudCB0aGF0IGFuc3dlcnMgYSB0dXJuIGZyb20gdGhlIEFwcEtpdCBwbHVnaW4gcmVnaXN0cnkuXG4gKlxuICogYGFnZW50SWRgIHBpY2tzIGEgc3BlY2lmaWMgYWdlbnQ7IG9taXR0ZWQsIHRoZSBwcm92aWRlcidzIGRlZmF1bHQgYWdlbnRcbiAqIGFuc3dlcnMuIFJldHVybnMgYG51bGxgIHdoZW4gdGhlIHByb3ZpZGVyIGlzIGFic2VudCBvciB0aGUgaWQgaXMgdW5rbm93biwgc29cbiAqIHRoZSByb3V0ZSBjYW4gYW5zd2VyIDUwMyAvIDQwNCBpbnN0ZWFkIG9mIHRocm93aW5nLlxuICovXG5leHBvcnQgY29uc3QgcmVzb2x2ZUNhcmRBZ2VudCA9IChcbiAgcGx1Z2luczogUmVhZG9ubHlNYXA8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZCxcbiAgcHJvdmlkZXJOYW1lOiBzdHJpbmcsXG4gIGFnZW50SWQ/OiBzdHJpbmcsXG4pOiBDYXJkQWdlbnRMaWtlIHwgbnVsbCA9PiB7XG4gIGNvbnN0IHByb3ZpZGVyID0gcGx1Z2lucz8uZ2V0KHByb3ZpZGVyTmFtZSk7XG4gIGlmICghaXNBZ2VudFByb3ZpZGVyKHByb3ZpZGVyKSkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IGZvdW5kID0gcmVhZEFnZW50KHByb3ZpZGVyLCBhZ2VudElkKTtcbiAgcmV0dXJuIGlzQ2FyZEFnZW50KGZvdW5kKSA/IGZvdW5kIDogbnVsbDtcbn07XG5cbi8qKiBPcHRpb25zIGZvciB7QGxpbmsgcnVuQ2FyZFR1cm59LiAqL1xuZXhwb3J0IGludGVyZmFjZSBDYXJkVHVybk9wdGlvbnMge1xuICAvKiogQ2FuY2VscyB0aGUgYWdlbnQgY2FsbCB3aXRoIHRoZSByZXF1ZXN0LiAqL1xuICBzaWduYWw/OiBBYm9ydFNpZ25hbDtcbiAgLyoqIE92ZXJyaWRlcyB0aGUgYm90IGlkZW50aXR5IHN0YW1wZWQgb24gdGhlIHJlcGx5LiAqL1xuICBib3Q/OiBhY3Rpdml0eUNvbnRyYWN0LkNoYW5uZWxBY2NvdW50O1xuICAvKipcbiAgICogQnVpbGRzIHRoZSBNYXN0cmEgYFJlcXVlc3RDb250ZXh0YCBmb3IgdGhlIHR1cm4sIGZyb21cbiAgICoge0BsaW5rIHJlc29sdmVDYXJkQ29udGV4dEZhY3Rvcnl9LiBPbWl0dGVkLCB0aGUgdHVybiBzdGlsbCBhbnN3ZXJzLCBidXRcbiAgICogd2l0aG91dCB0aGUgQXBwS2l0IHVzZXIgaXRzIHVzZXItc2NvcGVkIHRvb2xzIGNhbm5vdCByZWFjaCBEYXRhYnJpY2tzIC0gc29cbiAgICogdGhlIHJvdXRlIHNob3VsZCBhbHdheXMgc3VwcGx5IGl0LlxuICAgKi9cbiAgY3JlYXRlUmVxdWVzdENvbnRleHQ/OiBDYXJkQ29udGV4dEZhY3Rvcnk7XG59XG5cbi8qKiBCdWlsZHMgdGhlIHBlci10dXJuIHJlcXVlc3QgY29udGV4dCB0aGUgYWdlbnQncyB0b29scyByZWFkLiAqL1xuZXhwb3J0IHR5cGUgQ2FyZENvbnRleHRGYWN0b3J5ID0gKG9wdGlvbnM6IHtcbiAgdGhyZWFkSWQ/OiBzdHJpbmc7XG4gIHJlc291cmNlSWQ/OiBzdHJpbmc7XG59KSA9PiBQcm9taXNlPHVua25vd24+O1xuXG4vKipcbiAqIFRoZSBhZ2VudCBwbHVnaW4ncyByZXF1ZXN0LWNvbnRleHQgZmFjdG9yeSwgd2hlbiBpdCBleHBvc2VzIG9uZS5cbiAqXG4gKiBSZXNvbHZlZCBzZXBhcmF0ZWx5IGZyb20gdGhlIGFnZW50IGJlY2F1c2UgaXQgaXMgdGhlIHBpZWNlIHRoYXQgZ2l2ZXMgYW5cbiAqIG91dC1vZi1iYW5kIHR1cm4gdGhlIHNhbWUgdG9vbCByZWFjaCBhcyBhIGNoYXQgdHVybjsgYSBwcm92aWRlciB3aXRob3V0IGl0XG4gKiBzdGlsbCBhbnN3ZXJzLCBqdXN0IHdpdGhvdXQgdXNlci1zY29wZWQgdG9vbHMuXG4gKi9cbmV4cG9ydCBjb25zdCByZXNvbHZlQ2FyZENvbnRleHRGYWN0b3J5ID0gKFxuICBwbHVnaW5zOiBSZWFkb25seU1hcDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkLFxuICBwcm92aWRlck5hbWU6IHN0cmluZyxcbik6IENhcmRDb250ZXh0RmFjdG9yeSB8IG51bGwgPT4ge1xuICBjb25zdCBwcm92aWRlciA9IHBsdWdpbnM/LmdldChwcm92aWRlck5hbWUpO1xuICBpZiAoIWlzQWdlbnRQcm92aWRlcihwcm92aWRlcikpIHJldHVybiBudWxsO1xuICBjb25zdCByZWdpc3RyeSA9IHByb3ZpZGVyLmV4cG9ydHMoKSBhcyBQYXJ0aWFsPFJldHVyblR5cGU8QWdlbnRQcm92aWRlckxpa2VbXCJleHBvcnRzXCJdPj47XG4gIGNvbnN0IGZhY3RvcnkgPSByZWdpc3RyeS5jcmVhdGVSZXF1ZXN0Q29udGV4dDtcbiAgcmV0dXJuIHR5cGVvZiBmYWN0b3J5ID09PSBcImZ1bmN0aW9uXCIgPyAob3B0aW9ucykgPT4gZmFjdG9yeS5jYWxsKHJlZ2lzdHJ5LCBvcHRpb25zKSA6IG51bGw7XG59O1xuXG4vKipcbiAqIFRoZSB0ZXh0IGEgYG1lc3NhZ2VgIGFjdGl2aXR5IGNhcnJpZXMsIG9yIGBudWxsYCB3aGVuIGl0IGNhcnJpZXMgbm9uZS5cbiAqXG4gKiBBIGNoYW5uZWwgc2VuZHMgcGxlbnR5IG9mIGFjdGl2aXRpZXMgd2l0aCBubyB1c2FibGUgdGV4dCAoYSBgdHlwaW5nYFxuICogaW5kaWNhdG9yLCBhIGBjb252ZXJzYXRpb25VcGRhdGVgIHdoZW4gc29tZW9uZSBqb2lucywgb3IgYSBgbWVzc2FnZWAgd2hvc2VcbiAqIHBheWxvYWQgaXMgb25seSBhbiBhdHRhY2htZW50KS4gVGhvc2UgYXJlIG5vdCBlcnJvcnMgLSB0aGV5IHNpbXBseSBwcm9kdWNlIG5vXG4gKiByZXBseSAtIHNvIHRoaXMgcmV0dXJucyBgbnVsbGAgcmF0aGVyIHRoYW4gdGhyb3dpbmcuXG4gKi9cbmV4cG9ydCBjb25zdCBwcm9tcHRPZiA9IChpbmJvdW5kOiBhY3Rpdml0eUNvbnRyYWN0LkFjdGl2aXR5KTogc3RyaW5nIHwgbnVsbCA9PlxuICBpbmJvdW5kLnR5cGUgPT09IFwibWVzc2FnZVwiID8gc3RyaW5nLnRyaW1Ub051bGwoaW5ib3VuZC50ZXh0ID8/IFwiXCIpIDogbnVsbDtcblxuLyoqXG4gKiBCdWlsZCBhbiBvdXRib3VuZCBhY3Rpdml0eSBjYXJyeWluZyBgY2FyZHNgLCBhZGRyZXNzZWQgYmFjayB0byB0aGUgc2VuZGVyIG9mXG4gKiBgaW5ib3VuZGAuXG4gKlxuICogRXhwb3J0ZWQgYmVjYXVzZSBhIGNsaWVudCByZW5kZXJpbmcgYW4gb3B0aW1pc3RpYyBsb2NhbCByZXBseSwgYW5kIGEgdGVzdFxuICogYXNzZXJ0aW5nIHRoZSBlbnZlbG9wZSwgYm90aCBuZWVkIHRoZSBzYW1lIGNvbnN0cnVjdGlvbiB0aGUgdHVybiB1c2VzLlxuICovXG5leHBvcnQgY29uc3QgdG9SZXBseUFjdGl2aXR5ID0gKFxuICBpbmJvdW5kOiBhY3Rpdml0eUNvbnRyYWN0LkFjdGl2aXR5LFxuICBjYXJkczogY2FyZC5BZGFwdGl2ZUNhcmRbXSxcbiAgb3B0aW9uczogeyBib3Q/OiBhY3Rpdml0eUNvbnRyYWN0LkNoYW5uZWxBY2NvdW50OyB0ZXh0Pzogc3RyaW5nIH0gPSB7fSxcbik6IGFjdGl2aXR5Q29udHJhY3QuQWN0aXZpdHkgPT4gKHtcbiAgdHlwZTogXCJtZXNzYWdlXCIsXG4gIGlkOiBoYXNoLmlkKCksXG4gIHRpbWVzdGFtcDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICBmcm9tOiBvcHRpb25zLmJvdCA/PyBCT1RfQUNDT1VOVCxcbiAgLi4uKGluYm91bmQuZnJvbSA/IHsgcmVjaXBpZW50OiBpbmJvdW5kLmZyb20gfSA6IHt9KSxcbiAgLi4uKGluYm91bmQuY29udmVyc2F0aW9uID8geyBjb252ZXJzYXRpb246IGluYm91bmQuY29udmVyc2F0aW9uIH0gOiB7fSksXG4gIC4uLihvcHRpb25zLnRleHQgPyB7IHRleHQ6IG9wdGlvbnMudGV4dCB9IDoge30pLFxuICBhdHRhY2htZW50czogY2FyZHMubWFwKChkb2N1bWVudCkgPT4gYWN0aXZpdHlDb250cmFjdC50b0NhcmRBdHRhY2htZW50KGRvY3VtZW50KSksXG59KTtcblxuLyoqXG4gKiBSZWNvdmVyIGEge0BsaW5rIGNhcmQuQ2FyZFNwZWN9IGZyb20gYSBmdWxsIEFkYXB0aXZlIENhcmQgRE9DVU1FTlQuXG4gKlxuICogQSBjYXBhYmxlIG1vZGVsIGFza2VkIGZvciBcImEgTWljcm9zb2Z0IFRlYW1zIEFkYXB0aXZlIENhcmRcIiBvZnRlbiBhbnN3ZXJzIHdpdGhcbiAqIHRoZSBmaW5pc2hlZCAxLjUgZG9jdW1lbnQgaW5zdGVhZCBvZiB0aGUgc21hbGwgc3BlYyAtIGNvcnJlY3QgQWRhcHRpdmUgQ2FyZFxuICogSlNPTiwgd3Jvbmcgc2NoZW1hLCBzbyBgc3RydWN0dXJlZE91dHB1dGAgcmVqZWN0cyBpdCAoYHRpdGxlOiBleHBlY3RlZFxuICogc3RyaW5nYCkgYW5kIGEgZ2VudWluZWx5IGdvb2QgYW5zd2VyIGlzIHRocm93biBhd2F5LiBSZWFkaW5nIHRoZSBkb2N1bWVudCBiYWNrXG4gKiBpbnRvIHRoZSBzcGVjIHZvY2FidWxhcnkga2VlcHMgaXQ6IHRoZSBoZWFkaW5nIFRleHRCbG9ja3MgYmVjb21lXG4gKiB0aXRsZS9zdWJ0aXRsZSwgcmVtYWluaW5nIFRleHRCbG9ja3MgdGhlIGJvZHksIHRoZSBGYWN0U2V0IHRoZSBmYWN0cywgYW5kIGFueVxuICogYEFjdGlvbi5PcGVuVXJsYCB0aGUgYWN0aW9ucy5cbiAqXG4gKiBEZWxpYmVyYXRlbHkgdG9sZXJhbnQgYWJvdXQgdGhlIGNvbnRhaW5lcjogYHR5cGVgIG1heSBiZSBtaXNzaW5nIGFuZCB0aGUgYm9keVxuICogbWF5IG5lc3QgZWxlbWVudHMgaW5zaWRlIGEgYENvbnRhaW5lcmAgLyBgQ29sdW1uU2V0YCwgc28gYmxvY2tzIGFyZSBjb2xsZWN0ZWRcbiAqIHJlY3Vyc2l2ZWx5IGFuZCBhbnl0aGluZyB1bnJlY29nbml6ZWQgaXMgaWdub3JlZC5cbiAqL1xuZXhwb3J0IGNvbnN0IGRvY3VtZW50Q2FyZFNwZWMgPSAodmFsdWU6IHVua25vd24pOiBjYXJkLkNhcmRTcGVjIHwgbnVsbCA9PiB7XG4gIGlmICghb2JqZWN0LmlzUmVjb3JkKHZhbHVlKSB8fCAhQXJyYXkuaXNBcnJheSh2YWx1ZS5ib2R5KSkgcmV0dXJuIG51bGw7XG5cbiAgY29uc3QgdGV4dHM6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IGZhY3RzOiBjYXJkLkNhcmRGYWN0W10gPSBbXTtcbiAgY29uc3QgY29sbGVjdCA9IChlbGVtZW50czogdW5rbm93bltdKTogdm9pZCA9PiB7XG4gICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGVsZW1lbnRzKSB7XG4gICAgICBpZiAoIW9iamVjdC5pc1JlY29yZChlbGVtZW50KSkgY29udGludWU7XG4gICAgICBpZiAoZWxlbWVudC50eXBlID09PSBcIlRleHRCbG9ja1wiKSB7XG4gICAgICAgIGNvbnN0IHRleHQgPSBzdHJpbmcudHJpbVRvTnVsbCh0eXBlb2YgZWxlbWVudC50ZXh0ID09PSBcInN0cmluZ1wiID8gZWxlbWVudC50ZXh0IDogXCJcIik7XG4gICAgICAgIGlmICh0ZXh0KSB0ZXh0cy5wdXNoKHRleHQpO1xuICAgICAgfSBlbHNlIGlmIChlbGVtZW50LnR5cGUgPT09IFwiRmFjdFNldFwiICYmIEFycmF5LmlzQXJyYXkoZWxlbWVudC5mYWN0cykpIHtcbiAgICAgICAgZm9yIChjb25zdCBmYWN0IG9mIGVsZW1lbnQuZmFjdHMpIHtcbiAgICAgICAgICBjb25zdCBwYXJzZWQgPSBjYXJkLmNhcmRGYWN0U2NoZW1hLnNhZmVQYXJzZShmYWN0KTtcbiAgICAgICAgICBpZiAocGFyc2VkLnN1Y2Nlc3MpIGZhY3RzLnB1c2gocGFyc2VkLmRhdGEpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBBIENvbnRhaW5lciAvIENvbHVtblNldCAvIENvbHVtbiBuZXN0cyB0aGUgYmxvY2tzIHRoYXQgbWF0dGVyLlxuICAgICAgZm9yIChjb25zdCBrZXkgb2YgW1wiaXRlbXNcIiwgXCJjb2x1bW5zXCJdKSB7XG4gICAgICAgIGNvbnN0IG5lc3RlZCA9IGVsZW1lbnRba2V5XTtcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkobmVzdGVkKSkgY29sbGVjdChuZXN0ZWQpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcbiAgY29sbGVjdCh2YWx1ZS5ib2R5KTtcblxuICBjb25zdCBhY3Rpb25zOiBjYXJkLkNhcmRBY3Rpb25bXSA9IFtdO1xuICBmb3IgKGNvbnN0IGFjdGlvbiBvZiBBcnJheS5pc0FycmF5KHZhbHVlLmFjdGlvbnMpID8gdmFsdWUuYWN0aW9ucyA6IFtdKSB7XG4gICAgaWYgKCFvYmplY3QuaXNSZWNvcmQoYWN0aW9uKSkgY29udGludWU7XG4gICAgY29uc3QgcGFyc2VkID0gY2FyZC5jYXJkQWN0aW9uU2NoZW1hLnNhZmVQYXJzZSh7IHRpdGxlOiBhY3Rpb24udGl0bGUsIHVybDogYWN0aW9uLnVybCB9KTtcbiAgICBpZiAocGFyc2VkLnN1Y2Nlc3MpIGFjdGlvbnMucHVzaChwYXJzZWQuZGF0YSk7XG4gIH1cblxuICBjb25zdCBbdGl0bGUsIC4uLnJlc3RdID0gdGV4dHM7XG4gIGlmICghdGl0bGUpIHJldHVybiBudWxsO1xuICAvLyBUaGUgc2Vjb25kIGJsb2NrIGlzIGEgc3VidGl0bGUgb25seSB3aGVuIHRoZSBkb2N1bWVudCBzdHlsZWQgaXQgYXMgb25lO1xuICAvLyBvdGhlcndpc2UgaXQgaXMgYm9keSB0ZXh0IGFuZCBtdXN0IG5vdCBiZSBkZW1vdGVkIHRvIGEgc3ViaGVhZGluZy5cbiAgY29uc3Qgc2Vjb25kID0gb2JqZWN0LmlzUmVjb3JkKHZhbHVlLmJvZHlbMV0pID8gdmFsdWUuYm9keVsxXSA6IHVuZGVmaW5lZDtcbiAgY29uc3QgaGFzU3VidGl0bGUgPSByZXN0Lmxlbmd0aCA+IDAgJiYgc2Vjb25kPy5pc1N1YnRsZSA9PT0gdHJ1ZTtcbiAgY29uc3QgYm9keSA9IChoYXNTdWJ0aXRsZSA/IHJlc3Quc2xpY2UoMSkgOiByZXN0KS5qb2luKFwiXFxuXFxuXCIpO1xuICByZXR1cm4ge1xuICAgIHRpdGxlOiB0b1RpdGxlKHRpdGxlKSxcbiAgICAuLi4oaGFzU3VidGl0bGUgJiYgcmVzdFswXSA/IHsgc3VidGl0bGU6IHJlc3RbMF0gfSA6IHt9KSxcbiAgICAuLi4oYm9keSA/IHsgdGV4dDogYm9keSB9IDoge30pLFxuICAgIC4uLihmYWN0cy5sZW5ndGggPiAwID8geyBmYWN0cyB9IDoge30pLFxuICAgIC4uLihhY3Rpb25zLmxlbmd0aCA+IDAgPyB7IGFjdGlvbnMgfSA6IHt9KSxcbiAgfTtcbn07XG5cbi8qKlxuICogVGhlIGNhcmQgdGhlIG1vZGVsIHByb2R1Y2VkLCB3aGVyZXZlciBpdCBlbmRlZCB1cC5cbiAqXG4gKiBgc3RydWN0dXJlZE91dHB1dGAgcmVqZWN0cyBhbnl0aGluZyBvZmYtc2NoZW1hIGJ5IFRIUk9XSU5HLCBhbmQgTWFzdHJhIHB1dHNcbiAqIHRoZSBvZmZlbmRpbmcgcGF5bG9hZCBvbiB0aGUgZXJyb3IgKGBkZXRhaWxzLnZhbHVlYCkgLSBzbyB0aGUgbW9kZWwncyByZWFsXG4gKiBhbnN3ZXIgaXMgcmVjb3ZlcmFibGUgZnJvbSBhIGZhaWxlZCBjYWxsLiBCb3RoIHRoZSBzcGVjIHNoYXBlIGFuZCBhIGZ1bGxcbiAqIEFkYXB0aXZlIENhcmQgZG9jdW1lbnQgYXJlIGFjY2VwdGVkLCBmcm9tIGFuIG9iamVjdCBvciBmcm9tIEpTT04gdGV4dC5cbiAqL1xuZXhwb3J0IGNvbnN0IHJlamVjdGVkQ2FyZFNwZWMgPSAoZXJyOiB1bmtub3duKTogY2FyZC5DYXJkU3BlYyB8IG51bGwgPT4ge1xuICBjb25zdCBkZXRhaWxzID0gb2JqZWN0LmlzUmVjb3JkKGVycikgPyBlcnIuZGV0YWlscyA6IHVuZGVmaW5lZDtcbiAgY29uc3QgdmFsdWUgPSBvYmplY3QuaXNSZWNvcmQoZGV0YWlscykgPyBkZXRhaWxzLnZhbHVlIDogdW5kZWZpbmVkO1xuICBjb25zdCBjYW5kaWRhdGVzOiB1bmtub3duW10gPSBbXTtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIikge1xuICAgIGNhbmRpZGF0ZXMucHVzaChqc29uLnBhcnNlKHZhbHVlLCB1bmRlZmluZWQpKTtcbiAgfSBlbHNlIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY2FuZGlkYXRlcy5wdXNoKHZhbHVlKTtcbiAgfVxuICBmb3IgKGNvbnN0IGNhbmRpZGF0ZSBvZiBjYW5kaWRhdGVzKSB7XG4gICAgY29uc3Qgc3BlYyA9IGNhcmQuY2FyZFNwZWNTY2hlbWEuc2FmZVBhcnNlKGNhbmRpZGF0ZSk7XG4gICAgaWYgKHNwZWMuc3VjY2VzcykgcmV0dXJuIHNwZWMuZGF0YTtcbiAgICBjb25zdCBmcm9tRG9jdW1lbnQgPSBkb2N1bWVudENhcmRTcGVjKGNhbmRpZGF0ZSk7XG4gICAgaWYgKGZyb21Eb2N1bWVudCkgcmV0dXJuIGZyb21Eb2N1bWVudDtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn07XG5cbi8qKlxuICogVHVybiB3aGF0ZXZlciB0aGUgYWdlbnQgcHJvZHVjZWQgaW50byBhIGNhcmQgc3BlYy5cbiAqXG4gKiBgc3RydWN0dXJlZE91dHB1dGAgaXMgYmVzdC1lZmZvcnQgaW4gcHJhY3RpY2UsIG5vdCBhIGd1YXJhbnRlZS4gQmVjYXVzZSB0aGVcbiAqIHNjaGVtYSBpcyBwcm9tcHQtaW5qZWN0ZWQgKHNlZSB7QGxpbmsgSlNPTl9QUk9NUFRfSU5KRUNUSU9OfSkgcmF0aGVyIHRoYW5cbiAqIGVuZm9yY2VkIGJ5IHRoZSBwcm92aWRlciwgYSBtb2RlbCBjYW4gYW5zd2VyIHdpdGggcHJvc2UsIHdpdGggSlNPTiB3cmFwcGVkIGluXG4gKiBhIGBgYGAgYGBganNvbiBgYGBgIGZlbmNlLCBvciAtIG9uIERhdGFicmlja3MgTW9kZWwgU2VydmluZyAtIHdpdGggYW4gZW1wdHlcbiAqIHBhcnNlZCBvYmplY3Qgd2hpbGUgdGhlIHRleHQgY2FycmllcyB0aGUgcmVhbCBhbnN3ZXIuIE9ic2VydmVkIGZhaWx1cmUgcmF0ZSBvblxuICogdGhlIGRlbW8gZW5kcG9pbnQgd2FzIHJvdWdobHkgb25lIHR1cm4gaW4gdGhyZWUsIGFsbCBvZiB3aGljaCBzdXJmYWNlZCBhcyBhXG4gKiBoYXJkIGBTVFJVQ1RVUkVEX09VVFBVVF9TQ0hFTUFfVkFMSURBVElPTl9GQUlMRURgIGFuZCBubyByZXBseSBhdCBhbGwuXG4gKlxuICogQSBtaXNzaW5nIGNhcmQgaXMgbm90IHdvcnRoIGRyb3BwaW5nIHRoZSBhbnN3ZXIgb3Zlciwgc28gdGhpcyByZWNvdmVycyBpblxuICogZm91ciBzdGFnZXM6IHRoZSBwYXJzZWQgb2JqZWN0IHdoZW4gaXQgdmFsaWRhdGVzOyBlbHNlIHRoZSBhcmd1bWVudHMgdGhlIGFnZW50XG4gKiBwYXNzZWQgdG8gYGNyZWF0ZV90ZWFtc19jYXJkYCAob24gdGhlIHByb3NlIHJldHJ5IGFuIGFnZW50IGhvbGRpbmcgdGhhdCB0b29sXG4gKiB1c3VhbGx5IGNhbGxzIGl0LCB3aGljaCBpcyBhIFJFQUwgY2FyZCBzcGVjLCBub3QgYSBndWVzcyk7IGVsc2UgYSBKU09OIG9iamVjdFxuICogZW1iZWRkZWQgaW4gdGhlIHRleHQ7IGVsc2UgdGhlIHByb3NlIHdyYXBwZWQgaW4gYSBtaW5pbWFsIHRleHQtb25seSBjYXJkLiBUaGVcbiAqIHVzZXIgYWx3YXlzIGdldHMgdGhlIGFnZW50J3MgYW5zd2VyOyBhdCB3b3JzdCBpdCBpcyBsZXNzIHN0cnVjdHVyZWQuXG4gKi9cbmNvbnN0IHRvQ2FyZFNwZWMgPSAocmVzdWx0OiBBZ2VudFJlc3VsdCk6IGNhcmQuQ2FyZFNwZWMgPT4ge1xuICBjb25zdCBwYXJzZWQgPSBjYXJkLmNhcmRTcGVjU2NoZW1hLnNhZmVQYXJzZShyZXN1bHQub2JqZWN0KTtcbiAgaWYgKHBhcnNlZC5zdWNjZXNzKSByZXR1cm4gcGFyc2VkLmRhdGE7XG5cbiAgLy8gQSBtb2RlbCB0aGF0IGFuc3dlcmVkIHdpdGggdGhlIGZpbmlzaGVkIEFkYXB0aXZlIENhcmQgZG9jdW1lbnQgcmF0aGVyIHRoYW5cbiAgLy8gdGhlIHNwZWMgc3RpbGwgcHJvZHVjZWQgYSByZWFsIGNhcmQ7IHJlYWQgaXQgYmFjayBpbnRvIHRoZSBzcGVjIHZvY2FidWxhcnkuXG4gIGNvbnN0IGZyb21Eb2N1bWVudCA9IGRvY3VtZW50Q2FyZFNwZWMocmVzdWx0Lm9iamVjdCk7XG4gIGlmIChmcm9tRG9jdW1lbnQpIHJldHVybiBmcm9tRG9jdW1lbnQ7XG5cbiAgLy8gUHJlZmVyIGEgY2FyZCB0aGUgYWdlbnQgZXhwbGljaXRseSBjb21wb3NlZCB2aWEgdGhlIHRvb2wgb3ZlciBhbnl0aGluZ1xuICAvLyBzY3JhcGVkIG91dCBvZiBpdHMgcHJvc2UuXG4gIGNvbnN0IGZyb21Ub29sID0gdG9vbENhcmRTcGVjKHJlc3VsdCk7XG4gIGlmIChmcm9tVG9vbCkgcmV0dXJuIGZyb21Ub29sO1xuXG4gIGNvbnN0IHRleHQgPSBzdHJpbmcudHJpbVRvTnVsbChyZXN1bHQudGV4dCA/PyBcIlwiKTtcbiAgaWYgKHRleHQpIHtcbiAgICAvLyBBIGZlbmNlZCBvciBpbmxpbmUgSlNPTiBvYmplY3QgaW4gdGhlIHByb3NlOiB0aGUgbW9kZWwgZm9sbG93ZWQgdGhlXG4gICAgLy8gaW5zdHJ1Y3Rpb25zIGJ1dCB0aGUgcHJvdmlkZXIgZGlkIG5vdCBzdXJmYWNlIGEgcGFyc2VkIG9iamVjdC5cbiAgICBjb25zdCBlbWJlZGRlZCA9IHRleHQubWF0Y2goL1xce1tcXHNcXFNdKlxcfS8pO1xuICAgIGlmIChlbWJlZGRlZCkge1xuICAgICAgY29uc3QgdmFsdWUgPSBqc29uLnBhcnNlKGVtYmVkZGVkWzBdLCB1bmRlZmluZWQpO1xuICAgICAgY29uc3QgcmV0cnkgPSBjYXJkLmNhcmRTcGVjU2NoZW1hLnNhZmVQYXJzZSh2YWx1ZSk7XG4gICAgICBpZiAocmV0cnkuc3VjY2VzcykgcmV0dXJuIHJldHJ5LmRhdGE7XG4gICAgICBjb25zdCBhc0RvY3VtZW50ID0gZG9jdW1lbnRDYXJkU3BlYyh2YWx1ZSk7XG4gICAgICBpZiAoYXNEb2N1bWVudCkgcmV0dXJuIGFzRG9jdW1lbnQ7XG4gICAgfVxuICAgIC8vIFByb3NlIG9ubHk6IGtlZXAgdGhlIGFuc3dlciwgZHJvcCB0aGUgc3RydWN0dXJlLiBUaGUgZmlyc3QgbGluZSBiZWNvbWVzXG4gICAgLy8gdGhlIHRpdGxlIChhIGNhcmQgd2l0aCBubyB0aXRsZSByZW5kZXJzIGFzIGFuIHVudGl0bGVkIGJsb2NrKSwgdGhlIHJlc3RcbiAgICAvLyBzdGF5cyBhcyB0aGUgYm9keS5cbiAgICBjb25zdCBsaW5lcyA9IHRleHRcbiAgICAgIC5zcGxpdChcIlxcblwiKVxuICAgICAgLmZpbHRlcigobGluZSkgPT4gbGluZS50cmltKCkubGVuZ3RoID4gMClcbiAgICAgIC8vIEEgbW9kZWwgaW50cm9kdWNpbmcgaXRzIG93biBhbnN3ZXIgKFwiSGVyZSBpcyB0aGUgQWRhcHRpdmUgQ2FyZDpcIikgd291bGRcbiAgICAgIC8vIG90aGVyd2lzZSBiZWNvbWUgdGhlIGNhcmQncyBoZWFkbGluZSwgd2hpY2ggcmVhZHMgYXMgYSBidWcuIERyb3AgdGhlXG4gICAgICAvLyBwcmVhbWJsZSBzbyB0aGUgZmlyc3QgUkVBTCBsaW5lIGlzIHRoZSB0aXRsZS5cbiAgICAgIC5maWx0ZXIoKGxpbmUpID0+ICFQUkVBTUJMRV9SRS50ZXN0KGxpbmUudHJpbSgpKSk7XG4gICAgY29uc3QgW2ZpcnN0LCAuLi5yZXN0XSA9IGxpbmVzO1xuICAgIGNvbnN0IHRpdGxlID0gc3RyaW5nLnRyaW1Ub051bGwoZmlyc3QgPz8gXCJcIikgPz8gXCJBbnN3ZXJcIjtcbiAgICBjb25zdCBib2R5ID0gcmVzdC5qb2luKFwiXFxuXCIpLnRyaW0oKTtcbiAgICByZXR1cm4ge1xuICAgICAgdGl0bGU6IHRvVGl0bGUodGl0bGUpLFxuICAgICAgLi4uKGJvZHkgPyB7IHRleHQ6IGJvZHkgfSA6IHRpdGxlLmxlbmd0aCA+IDEyMCA/IHsgdGV4dDogdGl0bGUgfSA6IHt9KSxcbiAgICB9O1xuICB9XG5cbiAgdGhyb3cgbmV3IEVycm9yKFwidGVhbXM6IHRoZSBhZ2VudCByZXR1cm5lZCBuZWl0aGVyIGEgY2FyZCBub3IgYW55IHRleHQgdG8gZmFsbCBiYWNrIG9uXCIpO1xufTtcblxuLyoqXG4gKiBBIGxpbmUgdGhhdCBvbmx5IGFubm91bmNlcyB0aGUgY2FyZCByYXRoZXIgdGhhbiBzYXlpbmcgYW55dGhpbmcgLSBlLmcuXG4gKiBcIkhlcmUgaXMgdGhlIEFkYXB0aXZlIENhcmQ6XCIsIFwiSGVyZSdzIHlvdXIgVGVhbXMgY2FyZDpcIiwgXCJIZXJlIGFyZSB0aGUgY2FyZFxuICogZGV0YWlsczpcIi4gTWF0Y2hlZCBzbyBpdCBuZXZlciBiZWNvbWVzIHRoZSBjYXJkJ3MgdGl0bGUuXG4gKlxuICogQW5jaG9yZWQgdG8gYSBcImhlcmUgaXMvYXJlL2hlcmUncyAuLi4gY2FyZCAuLi5cIiBvcGVuZXIgdGhhdCBFTkRTIGluIGEgY29sb24sXG4gKiB3aGljaCBpcyB3aGF0IGtlZXBzIGl0IGZyb20gZWF0aW5nIGEgcmVhbCBzZW50ZW5jZSB0aGF0IG1lcmVseSBtZW50aW9ucyBhIGNhcmRcbiAqIChcIkhlcmUgaXMgdGhlIGNhcmQgcmVhZGVyIHN0YXR1czogb2ZmbGluZS5cIiBoYXMgdGV4dCBhZnRlciB0aGUgY29sb24pLlxuICovXG5jb25zdCBQUkVBTUJMRV9SRSA9IC9eKGhlcmUgKGlzfGFyZSl8aGVyZSdzKVxcYlteLiE/XSpcXGJjYXJkXFxiW14uIT86XSo6XFxzKiQvaTtcblxuLyoqXG4gKiBUcmltIGEgbGluZSBkb3duIHRvIHNvbWV0aGluZyB1c2FibGUgYXMgYSBjYXJkIHRpdGxlLiBBZGFwdGl2ZSBDYXJkIHRpdGxlcyBhcmVcbiAqIGEgc2luZ2xlIGJvbGQgbGluZSwgc28gYW4gb3Zlcmxvbmcgb25lIGlzIHRydW5jYXRlZCByYXRoZXIgdGhhbiB3cmFwcGVkOyB0aGVcbiAqIG1hcmtkb3duIGVtcGhhc2lzIGEgbW9kZWwgb2Z0ZW4gYWRkcyBpcyBzdHJpcHBlZCBzaW5jZSB0aGUgdGl0bGUgaXMgYWxyZWFkeVxuICogc3R5bGVkIGJvbGQuXG4gKi9cbmNvbnN0IHRvVGl0bGUgPSAodmFsdWU6IHN0cmluZyk6IHN0cmluZyA9PiB7XG4gIGNvbnN0IHBsYWluID0gdmFsdWVcbiAgICAucmVwbGFjZSgvXiMrXFxzKi8sIFwiXCIpXG4gICAgLnJlcGxhY2UoL1xcKlxcKi9nLCBcIlwiKVxuICAgIC50cmltKCk7XG4gIHJldHVybiBwbGFpbi5sZW5ndGggPiAxMjAgPyBgJHtwbGFpbi5zbGljZSgwLCAxMTcpfS4uLmAgOiBwbGFpbjtcbn07XG5cbi8qKlxuICogQ29tcGlsZSBhbiBhbnN3ZXIgdGhlIGFnZW50IGhhcyBhbHJlYWR5IHByb2R1Y2VkIGludG8gYSBjYXJkIHNwZWMuXG4gKlxuICogQSBzZWNvbmQsIGRlbGliZXJhdGVseSBzdGF0ZWxlc3MgcGFzczogdGhlIGZvcm1hdHRpbmcgcmVxdWVzdCBpcyBOT1QgdGhyZWFkZWRcbiAqIG9udG8gYWdlbnQgbWVtb3J5LCBzbyB0aGUgY29udmVyc2F0aW9uIHRoZSB1c2VyIHNlZXMga2VlcHMgb25seSB0aGVpciBxdWVzdGlvblxuICogYW5kIHRoZSBhbnN3ZXIsIG5vdCB0aGUgcmVmb3JtYXR0aW5nIGNoYXR0ZXIgaW4gYmV0d2Vlbi5cbiAqXG4gKiBSZXR1cm5zIGBudWxsYCB3aGVuIHRoZSBwYXNzIGlzIHVudXNhYmxlIChNYXN0cmEgdGhyb3dzIHdoZW4gdGhlIG1vZGVsIHJldHVybnNcbiAqIG5vIHBhcnNlZCBvYmplY3QpIHNvIHRoZSBjYWxsZXIgY2FuIGZhbGwgYmFjayB0byB0aGUgYW5zd2VyIHRleHQgLSBhIGxlc3NcbiAqIHN0cnVjdHVyZWQgY2FyZCBjYXJyeWluZyB0aGUgcmVhbCBhbnN3ZXIgYmVhdHMgbG9zaW5nIHRoZSBhbnN3ZXIuXG4gKi9cbmNvbnN0IGZvcm1hdEFzQ2FyZCA9IGFzeW5jIChcbiAgYWdlbnQ6IENhcmRBZ2VudExpa2UsXG4gIHByb21wdDogc3RyaW5nLFxuICBhbnN3ZXI6IHN0cmluZyxcbiAgcmVxdWVzdDogeyBhYm9ydFNpZ25hbD86IEFib3J0U2lnbmFsOyByZXF1ZXN0Q29udGV4dD86IHVua25vd24gfSxcbik6IFByb21pc2U8Y2FyZC5DYXJkU3BlYyB8IG51bGw+ID0+IHtcbiAgY29uc3QgYm9keSA9IFtcbiAgICBDQVJEX0ZPUk1BVF9JTlNUUlVDVElPTlMsXG4gICAgXCJcIixcbiAgICBgUXVlc3Rpb246ICR7cHJvbXB0fWAsXG4gICAgXCJcIixcbiAgICBcIkFzc2lzdGFudCBhbnN3ZXI6XCIsXG4gICAgYW5zd2VyLFxuICBdLmpvaW4oXCJcXG5cIik7XG4gIGNvbnN0IG9wdGlvbnMgPSB7XG4gICAgc3RydWN0dXJlZE91dHB1dDoge1xuICAgICAgc2NoZW1hOiBjYXJkLmNhcmRTcGVjU2NoZW1hLFxuICAgICAganNvblByb21wdEluamVjdGlvbjogSlNPTl9QUk9NUFRfSU5KRUNUSU9OLFxuICAgIH0sXG4gICAgLi4ucmVxdWVzdCxcbiAgfTtcbiAgLy8gTWFzdHJhIFRIUk9XUyB3aGVuIHRoZSBtb2RlbCByZXR1cm5zIG5vIHBhcnNlZCBvYmplY3QsIGFuZCBiZWNhdXNlIHRoZVxuICAvLyBzY2hlbWEgaXMgcHJvbXB0LWluamVjdGVkIHJhdGhlciB0aGFuIHByb3ZpZGVyLWVuZm9yY2VkIHRoYXQgaGFwcGVuc1xuICAvLyBpbnRlcm1pdHRlbnRseSBvbiB0aGUgc2FtZSBpbnB1dC4gT25lIHJldHJ5IGNvbnZlcnRzIG1vc3Qgb2YgdGhvc2UgbWlzc2VzXG4gIC8vIGludG8gYSBwcm9wZXIgY2FyZDsgdGhlIGFuc3dlciBpcyBhbHJlYWR5IHNhZmUgZWl0aGVyIHdheS5cbiAgZm9yIChsZXQgYXR0ZW1wdCA9IDA7IGF0dGVtcHQgPCAyOyBhdHRlbXB0ICs9IDEpIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHRvQ2FyZFNwZWMoYXdhaXQgYWdlbnQuZ2VuZXJhdGUoYm9keSwgb3B0aW9ucykpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gVGhlIHJlamVjdGVkIHBheWxvYWQgdXN1YWxseSBJUyB0aGUgY2FyZCAtIG1vc3Qgb2Z0ZW4gdGhlIGZ1bGwgQWRhcHRpdmVcbiAgICAgIC8vIENhcmQgZG9jdW1lbnQgcmF0aGVyIHRoYW4gdGhlIHNwZWMgLSBzbyBpdCBpcyBzYWx2YWdlZCBiZWZvcmUgcmV0cnlpbmcuXG4gICAgICBjb25zdCByZWplY3RlZCA9IHJlamVjdGVkQ2FyZFNwZWMoZXJyKTtcbiAgICAgIGlmIChyZWplY3RlZCkge1xuICAgICAgICBsb2dnZXIuZGVidWcoXCJyZWNvdmVyZWQgdGhlIGNhcmQgZnJvbSB0aGUgcmVqZWN0ZWQgc3RydWN0dXJlZCBwYXlsb2FkXCIpO1xuICAgICAgICByZXR1cm4gcmVqZWN0ZWQ7XG4gICAgICB9XG4gICAgICBsb2dnZXIud2FybihcImNhcmQgZm9ybWF0dGluZyBwYXNzIGZhaWxlZFwiLCB7XG4gICAgICAgIGF0dGVtcHQ6IGF0dGVtcHQgKyAxLFxuICAgICAgICBlcnJvcjogZXJyb3IuZXJyb3JNZXNzYWdlKGVyciksXG4gICAgICB9KTtcbiAgICB9XG4gIH1cbiAgbG9nZ2VyLndhcm4oXCJmYWxsaW5nIGJhY2sgdG8gdGhlIGFuc3dlciB0ZXh0IGZvciB0aGUgY2FyZFwiKTtcbiAgcmV0dXJuIG51bGw7XG59O1xuXG4vKipcbiAqIFJ1biBvbmUgY29udmVyc2F0aW9uIHR1cm46IGRyaXZlIGBhZ2VudGAgd2l0aCB0aGUgaW5ib3VuZCBhY3Rpdml0eSdzIHRleHQgYW5kXG4gKiByZXR1cm4gdGhlIGFjdGl2aXRpZXMgdG8gYXBwZW5kIHRvIHRoZSB0cmFuc2NyaXB0LlxuICpcbiAqIFJldHVybnMgYW4gRU1QVFkgYXJyYXkgZm9yIGFuIGFjdGl2aXR5IHRoYXQgY2FycmllcyBubyBwcm9tcHQgKGEgdHlwaW5nXG4gKiBpbmRpY2F0b3IsIGEgam9pbiBldmVudCksIHdoaWNoIGlzIGV4YWN0bHkgd2hhdCBhIGJvdCBkb2VzIHdpdGggb25lIC0gdGhlXG4gKiByb3V0ZSBhbnN3ZXJzIGB7IGFjdGl2aXRpZXM6IFtdIH1gIGFuZCB0aGUgdHJhbnNjcmlwdCBpcyB1bmNoYW5nZWQuXG4gKlxuICogVHdvIGFnZW50IGNhbGxzLCBpbiB0aGlzIG9yZGVyOlxuICpcbiAqICAgMS4gdGhlIEFOU1dFUiAtIG5vIGBzdHJ1Y3R1cmVkT3V0cHV0YCwgc28gdGhlIGFnZW50J3MgdG9vbHMgYXJlIGF2YWlsYWJsZVxuICogICAgICBhbmQgdGhlIGNvbnRlbnQgbWF0Y2hlcyB3aGF0IHRoZSBzdHJlYW1pbmcgZW5kcG9pbnQgd291bGQgc2F5O1xuICogICAyLiB0aGUgRk9STUFUIC0ge0BsaW5rIGZvcm1hdEFzQ2FyZH0gY29tcGlsaW5nIHRoYXQgYW5zd2VyIGludG8gYSBjYXJkLlxuICpcbiAqIEV2ZXJ5IGZhaWx1cmUgbW9kZSBzdGlsbCB5aWVsZHMgdGhlIGFuc3dlcjogYSBjYXJkIHRoZSBhZ2VudCBjb21wb3NlZCB3aXRoXG4gKiBgY3JlYXRlX3RlYW1zX2NhcmRgIGR1cmluZyBwYXNzIDEgc2hvcnQtY2lyY3VpdHMgcGFzcyAyLCBhbmQgYSBmYWlsZWQgcGFzcyAyXG4gKiBmYWxscyBiYWNrIHRvIHtAbGluayB0b0NhcmRTcGVjfSBvdmVyIHRoZSBhbnN3ZXIgdGV4dC5cbiAqL1xuZXhwb3J0IGNvbnN0IHJ1bkNhcmRUdXJuID0gYXN5bmMgKFxuICBhZ2VudDogQ2FyZEFnZW50TGlrZSxcbiAgaW5ib3VuZDogYWN0aXZpdHlDb250cmFjdC5BY3Rpdml0eSxcbiAgb3B0aW9uczogQ2FyZFR1cm5PcHRpb25zID0ge30sXG4pOiBQcm9taXNlPGFjdGl2aXR5Q29udHJhY3QuQWN0aXZpdHlbXT4gPT4ge1xuICBjb25zdCBwcm9tcHQgPSBwcm9tcHRPZihpbmJvdW5kKTtcbiAgaWYgKCFwcm9tcHQpIHJldHVybiBbXTtcblxuICBjb25zdCBjb252ZXJzYXRpb25JZCA9IGluYm91bmQuY29udmVyc2F0aW9uPy5pZDtcbiAgY29uc3QgdXNlcklkID0gaW5ib3VuZC5mcm9tPy5pZDtcbiAgY29uc3Qgc2lnbmFsID0gb3B0aW9ucy5zaWduYWwgPyB7IGFib3J0U2lnbmFsOiBvcHRpb25zLnNpZ25hbCB9IDoge307XG4gIC8vIFRoZSBBcHBLaXQgdXNlciByaWRlcyBvbiB0aGlzLCBzbyB0aGUgYWdlbnQncyB0b29scyAoR2VuaWUsIHNlcnZpbmcsIHRoZVxuICAvLyBtb2RlbCByZXNvbHZlcikgd29yayBleGFjdGx5IGFzIHRoZXkgZG8gb24gdGhlIGNoYXQgZW5kcG9pbnRzLiBCdWlsdCBvbmNlXG4gIC8vIGFuZCBzaGFyZWQgYnkgYm90aCBwYXNzZXMuXG4gIGNvbnN0IHJlcXVlc3RDb250ZXh0ID0gb3B0aW9ucy5jcmVhdGVSZXF1ZXN0Q29udGV4dFxuICAgID8gYXdhaXQgb3B0aW9ucy5jcmVhdGVSZXF1ZXN0Q29udGV4dCh7XG4gICAgICAgIC4uLihjb252ZXJzYXRpb25JZCA/IHsgdGhyZWFkSWQ6IGNvbnZlcnNhdGlvbklkIH0gOiB7fSksXG4gICAgICAgIC4uLih1c2VySWQgPyB7IHJlc291cmNlSWQ6IHVzZXJJZCB9IDoge30pLFxuICAgICAgfSlcbiAgICA6IHVuZGVmaW5lZDtcbiAgY29uc3QgY29udGV4dCA9IHJlcXVlc3RDb250ZXh0ID8geyByZXF1ZXN0Q29udGV4dCB9IDoge307XG4gIC8vIFRocmVhZCB0aGUgY29udmVyc2F0aW9uIG9udG8gYWdlbnQgbWVtb3J5IHNvIHRoZSBzYW1lIGBjb252ZXJzYXRpb24uaWRgXG4gIC8vIGNvbnRpbnVlcyBvbmUgY29udmVyc2F0aW9uLiBPbmx5IHBhc3NlZCB3aGVuIHRoZSBjbGllbnQgc3VwcGxpZWQgYm90aCBpZHMgLVxuICAvLyBNYXN0cmEgcmVxdWlyZXMgdGhlIHBhaXIsIGFuZCBhIG1lbW9yeS1sZXNzIGFnZW50IGlnbm9yZXMgaXQuXG4gIGNvbnN0IG1lbW9yeSA9XG4gICAgY29udmVyc2F0aW9uSWQgJiYgdXNlcklkID8geyBtZW1vcnk6IHsgdGhyZWFkOiBjb252ZXJzYXRpb25JZCwgcmVzb3VyY2U6IHVzZXJJZCB9IH0gOiB7fTtcblxuICBjb25zdCBhbnN3ZXJlZCA9IGF3YWl0IGFnZW50LmdlbmVyYXRlKGAke3Byb21wdH1cXG5cXG4ke0NBUkRfQU5TV0VSX0lOU1RSVUNUSU9OU31gLCB7XG4gICAgLi4ubWVtb3J5LFxuICAgIC4uLmNvbnRleHQsXG4gICAgLi4uc2lnbmFsLFxuICB9KTtcblxuICAvLyBBbiBhZ2VudCB0aGF0IGNvbXBvc2VkIGEgY2FyZCBpdHNlbGYgaGFzIGFscmVhZHkgc2FpZCBpdCBpbiB0aGUgcmlnaHRcbiAgLy8gdm9jYWJ1bGFyeTsgcmVmb3JtYXR0aW5nIGl0IHdvdWxkIG9ubHkgcmlzayBwYXJhcGhyYXNpbmcgdGhlIHZhbHVlcy5cbiAgY29uc3QgY29tcG9zZWQgPSB0b29sQ2FyZFNwZWMoYW5zd2VyZWQpO1xuICBjb25zdCBhbnN3ZXIgPSBzdHJpbmcudHJpbVRvTnVsbChzdHJpcEVtYmVkTWFya2VycyhhbnN3ZXJlZC50ZXh0ID8/IFwiXCIpKTtcbiAgY29uc3Qgc3BlYyA9XG4gICAgY29tcG9zZWQgPz9cbiAgICAoYW5zd2VyID8gYXdhaXQgZm9ybWF0QXNDYXJkKGFnZW50LCBwcm9tcHQsIGFuc3dlciwgeyAuLi5jb250ZXh0LCAuLi5zaWduYWwgfSkgOiBudWxsKTtcblxuICBjb25zdCBkb2N1bWVudCA9IGJ1aWxkQWRhcHRpdmVDYXJkKFxuICAgIHNwZWMgPz8gdG9DYXJkU3BlYyh7IC4uLmFuc3dlcmVkLCAuLi4oYW5zd2VyID8geyB0ZXh0OiBhbnN3ZXIgfSA6IHt9KSB9KSxcbiAgKTtcbiAgcmV0dXJuIFt0b1JlcGx5QWN0aXZpdHkoaW5ib3VuZCwgW2RvY3VtZW50XSwgeyAuLi4ob3B0aW9ucy5ib3QgPyB7IGJvdDogb3B0aW9ucy5ib3QgfSA6IHt9KSB9KV07XG59O1xuIl19