@dbx-tools/appkit-mastra 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.
Files changed (56) hide show
  1. package/lib/index.d.ts +71 -0
  2. package/lib/index.js +56 -0
  3. package/lib/src/agents.d.ts +347 -0
  4. package/lib/src/agents.js +554 -0
  5. package/lib/src/chart.d.ts +192 -0
  6. package/lib/src/chart.js +638 -0
  7. package/lib/src/config.d.ts +479 -0
  8. package/lib/src/config.js +190 -0
  9. package/lib/src/defaults.d.ts +68 -0
  10. package/lib/src/defaults.js +107 -0
  11. package/lib/src/filesystems.d.ts +208 -0
  12. package/lib/src/filesystems.js +958 -0
  13. package/lib/src/genie.d.ts +166 -0
  14. package/lib/src/genie.js +969 -0
  15. package/lib/src/history.d.ts +97 -0
  16. package/lib/src/history.js +264 -0
  17. package/lib/src/mcp.d.ts +66 -0
  18. package/lib/src/mcp.js +65 -0
  19. package/lib/src/memory.d.ts +111 -0
  20. package/lib/src/memory.js +275 -0
  21. package/lib/src/mlflow.d.ts +63 -0
  22. package/lib/src/mlflow.js +117 -0
  23. package/lib/src/model.d.ts +62 -0
  24. package/lib/src/model.js +168 -0
  25. package/lib/src/observability.d.ts +81 -0
  26. package/lib/src/observability.js +98 -0
  27. package/lib/src/pagination.d.ts +23 -0
  28. package/lib/src/pagination.js +31 -0
  29. package/lib/src/plugin.d.ts +352 -0
  30. package/lib/src/plugin.js +1015 -0
  31. package/lib/src/processors.d.ts +62 -0
  32. package/lib/src/processors.js +162 -0
  33. package/lib/src/rest.d.ts +36 -0
  34. package/lib/src/rest.js +46 -0
  35. package/lib/src/server.d.ts +155 -0
  36. package/lib/src/server.js +336 -0
  37. package/lib/src/serving-sanitize.d.ts +104 -0
  38. package/lib/src/serving-sanitize.js +228 -0
  39. package/lib/src/serving.d.ts +61 -0
  40. package/lib/src/serving.js +78 -0
  41. package/lib/src/statement.d.ts +51 -0
  42. package/lib/src/statement.js +83 -0
  43. package/lib/src/storage-schema.d.ts +14 -0
  44. package/lib/src/storage-schema.js +34 -0
  45. package/lib/src/summarize.d.ts +70 -0
  46. package/lib/src/summarize.js +142 -0
  47. package/lib/src/threads.d.ts +109 -0
  48. package/lib/src/threads.js +301 -0
  49. package/lib/src/validation.d.ts +19 -0
  50. package/lib/src/validation.js +17 -0
  51. package/lib/src/workspaces.d.ts +68 -0
  52. package/lib/src/workspaces.js +246 -0
  53. package/lib/src/writer.d.ts +25 -0
  54. package/lib/src/writer.js +40 -0
  55. package/lib/tsconfig.tsbuildinfo +1 -0
  56. package/package.json +17 -13
@@ -0,0 +1,969 @@
1
+ /**
2
+ * Genie tools for Mastra.
3
+ *
4
+ * Surfaces each configured Genie space as a small set of flat Mastra
5
+ * tools the calling agent drives directly - no inner orchestrator
6
+ * agent. The central agent decomposes user questions, picks which
7
+ * space to ask, streams the per-turn wire events (status, thinking,
8
+ * sql, rows) through `ctx.writer`, and composes the final reply.
9
+ * Rows are never fetched eagerly: the agent reads a statement's
10
+ * values only when it needs to reason about them, otherwise it embeds
11
+ * a `[data:<statement_id>]` marker in prose and lets the host UI
12
+ * resolve the data. Charts are minted asynchronously and referenced
13
+ * by `[chart:<chartId>]` markers so prose isn't blocked on chart
14
+ * generation; the host UI fetches the cached spec by id once ready.
15
+ * Space description and serialized-space lookups are available for
16
+ * grounding when the agent needs schema context.
17
+ *
18
+ * Each tool's `execute` pulls the per-request
19
+ * {@link WorkspaceClient} off `ctx.requestContext` (stamped by
20
+ * `MastraServer` under {@link MASTRA_USER_KEY}) and the per-call
21
+ * `writer` / `abortSignal` off `ctx`, so the tools are stateless
22
+ * across requests and the central agent owns the loop.
23
+ *
24
+ * The tools talk to Genie directly via `@dbx-tools/genie`
25
+ * (`genieEventChat`); statement-row fetching is delegated to
26
+ * {@link fetchStatementData} from `./statement.js`, which wraps
27
+ * the workspace `statementExecution.getStatement` API. AppKit's
28
+ * stock `genie` plugin is honored only for its `spaces` config
29
+ * so existing AppKit-style wiring keeps working without change.
30
+ *
31
+ * Suggested orchestration prompt for the central agent lives in
32
+ * {@link GENIE_INSTRUCTIONS}; compose it into the agent's own
33
+ * `instructions` when you want the canonical "how to drive the
34
+ * Genie tools" guidance.
35
+ *
36
+ * @module
37
+ */
38
+ import { CacheManager, ConfigurationError, ExecutionError, genie, ValidationError, } from "@databricks/appkit";
39
+ import { plugin } from "@dbx-tools/appkit";
40
+ import { chat, space as genieSpace } from "@dbx-tools/genie";
41
+ import { error, log, string } from "@dbx-tools/shared-core";
42
+ import { genieModel } from "@dbx-tools/shared-genie";
43
+ import { wire } from "@dbx-tools/shared-mastra";
44
+ import { MASTRA_THREAD_ID_KEY } from "@mastra/core/request-context";
45
+ import { createTool } from "@mastra/core/tools";
46
+ import { z } from "zod";
47
+ import { chartPlannerRequestSchema, prepareChart } from "./chart.js";
48
+ import { MASTRA_USER_KEY, resolveUserKey } from "./config.js";
49
+ import { fetchStatementData } from "./statement.js";
50
+ import { safeWrite } from "./writer.js";
51
+ const logger = log.logger("mastra/genie");
52
+ /** Default alias used when a single unnamed Genie space is wired up. */
53
+ export const DEFAULT_GENIE_ALIAS = "default";
54
+ /**
55
+ * Pull the per-request {@link WorkspaceClient} off the active
56
+ * `RequestContext`. The Mastra plugin's server middleware stamps
57
+ * a {@link User} on the context under {@link MASTRA_USER_KEY}
58
+ * for every request; tools fail loudly when it's missing because
59
+ * that means the Mastra plugin isn't running (e.g. a tool was
60
+ * invoked outside the chat route).
61
+ */
62
+ function requireClient(ctx, toolId) {
63
+ const requestContext = ctx?.requestContext;
64
+ if (!requestContext) {
65
+ throw ConfigurationError.resourceNotFound(`${toolId} request context`, "Invoke the tool from an agent turn served by the mastra plugin.");
66
+ }
67
+ const user = requestContext.get(MASTRA_USER_KEY);
68
+ if (!user) {
69
+ throw ConfigurationError.resourceNotFound(`${toolId} user context`, "Invoke the tool from an agent turn served by the mastra plugin, which stamps the AppKit user on the Mastra request context.");
70
+ }
71
+ return { client: user.executionContext.client, requestContext };
72
+ }
73
+ /**
74
+ * Lowercased placeholder strings we reject at the `ask_genie`
75
+ * boundary so the LLM doesn't spend a Genie round-trip on a
76
+ * non-question. Genie politely answers any of these with "Your
77
+ * request '...' does not relate to..." which is pure UI noise.
78
+ * Kept narrow on purpose - real questions sometimes start with
79
+ * one of these tokens, so we only match the FULL trimmed string.
80
+ */
81
+ const PLACEHOLDER_QUESTIONS = new Set([
82
+ "noop",
83
+ "no-op",
84
+ "skip",
85
+ "none",
86
+ "n/a",
87
+ "na",
88
+ "null",
89
+ "undefined",
90
+ "test",
91
+ "placeholder",
92
+ ]);
93
+ /* ----------------------- conversation state ----------------------- */
94
+ /**
95
+ * Estimated Genie conversation lifetime in seconds. Databricks
96
+ * publishes no official TTL on the conversation resource itself;
97
+ * community projects (e.g. the open-source Databricks Genie Bot)
98
+ * converge on 4 hours of inactivity as a safe operating window.
99
+ * Treat this as an estimate that gets *extended on every use* by
100
+ * re-setting the cache entry after each successful turn (sliding
101
+ * TTL via re-`set`). When the estimate ends up wrong (conversation
102
+ * deleted, expired upstream, cross-space referenced), `ask_genie`
103
+ * catches the SDK's `RESOURCE_DOES_NOT_EXIST`/404 and transparently
104
+ * starts a fresh conversation.
105
+ */
106
+ const CONVERSATION_TTL_SEC = 4 * 60 * 60;
107
+ /** Cache namespace prefix so coexisting Mastra caches don't collide. */
108
+ const CONVERSATION_CACHE_NAMESPACE = "mastra:genie:conversation";
109
+ /**
110
+ * Build the per-request {@link RequestContext} key the active
111
+ * Genie `conversation_id` lives under for `spaceId`. Scoped by
112
+ * space so an app calling two Genie spaces in one request keeps
113
+ * each conversation distinct (Genie conversation ids are
114
+ * space-scoped on the wire). The same `RequestContext` instance
115
+ * flows from the central agent through to every `ask_genie`
116
+ * invocation, so writes on one call are visible on the next
117
+ * without an explicit shared ref.
118
+ */
119
+ const conversationContextKey = (spaceId) => `mastra__genie_conversation__${spaceId}`;
120
+ /**
121
+ * Read the active Genie `conversation_id` for `spaceId` off the
122
+ * per-request {@link RequestContext}. Returns `undefined` when no
123
+ * conversation has been started yet this request.
124
+ */
125
+ function readContextConversationId(requestContext, spaceId) {
126
+ return requestContext.get(conversationContextKey(spaceId));
127
+ }
128
+ /**
129
+ * Write the active Genie `conversation_id` for `spaceId` onto the
130
+ * per-request {@link RequestContext}. Subsequent `ask_genie` calls
131
+ * in this request will reuse it.
132
+ */
133
+ function writeContextConversationId(requestContext, spaceId, conversationId) {
134
+ requestContext.set(conversationContextKey(spaceId), conversationId);
135
+ }
136
+ /**
137
+ * Build the canonical cache key for a `(spaceId, threadId)` pair, owned by
138
+ * `userKey`. Returns `undefined` when `threadId` is missing - callers should
139
+ * skip caching entirely in that case (no Mastra memory wired up).
140
+ *
141
+ * The identity is part of the key because a client picks its own `threadId`
142
+ * (the thread-selection header / `?threadId=`), so the id alone does not
143
+ * establish who owns the Genie conversation behind it.
144
+ */
145
+ async function conversationCacheKey(spaceId, threadId, userKey) {
146
+ if (!threadId)
147
+ return undefined;
148
+ return (await CacheManager.getInstance()).generateKey([CONVERSATION_CACHE_NAMESPACE, spaceId, threadId], userKey);
149
+ }
150
+ /**
151
+ * Read the cached Genie conversation id for `(spaceId, threadId)`.
152
+ * Returns `undefined` on miss, on expiry, or when the cache layer
153
+ * is unhealthy - never throws. The TTL is renewed via re-`set`
154
+ * after each successful turn (see {@link saveCachedConversationId}).
155
+ */
156
+ async function readCachedConversationId(cacheKey) {
157
+ if (!cacheKey)
158
+ return undefined;
159
+ try {
160
+ const v = await CacheManager.getInstanceSync().get(cacheKey);
161
+ return v ?? undefined;
162
+ }
163
+ catch (err) {
164
+ logger.warn("conversation-cache:read-error", {
165
+ error: error.errorMessage(err),
166
+ });
167
+ return undefined;
168
+ }
169
+ }
170
+ /**
171
+ * Persist the active conversation id under `cacheKey`, refreshing
172
+ * its TTL. Idempotent; no-op when `cacheKey` or `conversationId`
173
+ * is missing. Re-setting the same key acts as a sliding TTL: every
174
+ * turn that uses the conversation extends the window by another
175
+ * {@link CONVERSATION_TTL_SEC} seconds.
176
+ */
177
+ async function saveCachedConversationId(cacheKey, conversationId) {
178
+ if (!cacheKey || !conversationId)
179
+ return;
180
+ try {
181
+ await CacheManager.getInstanceSync().set(cacheKey, conversationId, {
182
+ ttl: CONVERSATION_TTL_SEC,
183
+ });
184
+ }
185
+ catch (err) {
186
+ logger.warn("conversation-cache:write-error", {
187
+ error: error.errorMessage(err),
188
+ });
189
+ }
190
+ }
191
+ /** Force-evict a cached conversation id. Used on the stale-id recovery path. */
192
+ async function evictCachedConversationId(cacheKey) {
193
+ if (!cacheKey)
194
+ return;
195
+ try {
196
+ await CacheManager.getInstanceSync().delete(cacheKey);
197
+ }
198
+ catch (err) {
199
+ logger.warn("conversation-cache:delete-error", {
200
+ error: error.errorMessage(err),
201
+ });
202
+ }
203
+ }
204
+ /**
205
+ * Lazy-seed the active Genie `conversation_id` for `spaceId` from
206
+ * the cross-request cache onto the per-request `RequestContext`.
207
+ * No-op when the slot is already populated (subsequent
208
+ * `ask_genie` calls in the same turn) so we hit the cache at most
209
+ * once per request per space.
210
+ */
211
+ async function ensureConversationSeeded(requestContext, spaceId, cacheKey) {
212
+ if (readContextConversationId(requestContext, spaceId))
213
+ return;
214
+ const cached = await readCachedConversationId(cacheKey);
215
+ if (cached)
216
+ writeContextConversationId(requestContext, spaceId, cached);
217
+ }
218
+ /* ------------------------ prepare_chart input ------------------------ */
219
+ /**
220
+ * Agent-facing `prepare_chart` input schema. Reuses
221
+ * {@link chartPlannerRequestSchema} (the dataset-driven planner
222
+ * contract) but swaps the inline `data` field for a Genie
223
+ * `statement_id` the tool resolves into rows server-side.
224
+ * `title` is loosened to optional - the planner falls back to a
225
+ * generic placeholder when the agent doesn't supply one.
226
+ *
227
+ * Shaped to match Genie's wire form - `statement_id` (snake)
228
+ * mirrors `query_result.statement_id` and the `get_statement`
229
+ * tool's input field name, so the LLM only ever sees one
230
+ * spelling for the same identifier.
231
+ */
232
+ const prepareChartRequestSchema = chartPlannerRequestSchema
233
+ .omit({ data: true, title: true })
234
+ .extend({
235
+ statement_id: z
236
+ .string()
237
+ .min(1, "statement_id is required")
238
+ .describe(string.toDescription(`
239
+ Genie \`statement_id\` to chart. Read from
240
+ \`message.query_result.statement_id\` or
241
+ \`message.attachments[*].query.statement_id\` returned by
242
+ \`ask_genie\`.
243
+ `)),
244
+ title: chartPlannerRequestSchema.shape.title.optional(),
245
+ });
246
+ /* ----------------------------- tool ids ----------------------------- */
247
+ /**
248
+ * Suffix appended to per-space tool ids when the alias isn't the
249
+ * well-known `default`. Single-space deployments get the bare
250
+ * names (`ask_genie`, `get_space_description`, ...); multi-space
251
+ * deployments get `ask_genie_<alias>` etc. so each space's tools
252
+ * stay disambiguated in the central agent's tool registry.
253
+ */
254
+ function aliasSuffix(alias) {
255
+ if (alias === DEFAULT_GENIE_ALIAS)
256
+ return "";
257
+ const slug = string.toIdentifier(alias);
258
+ return slug ? `_${slug}` : "";
259
+ }
260
+ /* --------------------------- per-space tools --------------------------- */
261
+ /**
262
+ * Drop `suggested_questions` attachments from a {@link GenieMessage}
263
+ * before handing it to the central LLM. Those entries already
264
+ * surface in the UI as one-tap pills via the writer's
265
+ * `suggested_questions` events (see `collectSuggestions` on the
266
+ * client); if we let them ride back in the tool result the LLM
267
+ * tends to quote them inline in its prose, double-showing the
268
+ * same questions and stepping on the dedicated suggestion UI.
269
+ * Query / text / row attachments are preserved so the model can
270
+ * still read `statement_id`, SQL, and the answer text.
271
+ */
272
+ function stripSuggestedQuestions(message) {
273
+ const attachments = message.attachments;
274
+ if (!attachments || attachments.length === 0)
275
+ return message;
276
+ const filtered = attachments.filter((att) => !att.suggested_questions);
277
+ if (filtered.length === attachments.length)
278
+ return message;
279
+ return { ...message, attachments: filtered };
280
+ }
281
+ function buildAskGenieTool(opts) {
282
+ const { spaceId, alias, hint } = opts;
283
+ const toolId = `ask_genie${aliasSuffix(alias)}`;
284
+ const hintLine = hint ? ` (${hint})` : "";
285
+ return createTool({
286
+ id: toolId,
287
+ description: string.toDescription(`
288
+ Ask the Genie space "${alias}"${hintLine} ONE focused
289
+ natural-language sub-question and wait for the turn to
290
+ complete. Genie answers best when each call covers a
291
+ single metric / dimension / time window, so expect to
292
+ call this tool MULTIPLE TIMES per user turn (typically
293
+ two to six) and let the results from earlier calls inform
294
+ later ones - that's the normal pattern, not the exception.
295
+ Do NOT try to cram a multi-part question into a single
296
+ call; decompose first, then ask each piece.
297
+
298
+ Returns the final \`GenieMessage\`. Rows are NOT included -
299
+ the Genie wire response carries the \`statement_id\` for any
300
+ SQL that ran (at \`message.query_result.statement_id\` or the
301
+ first attachment's \`query.statement_id\`); call
302
+ \`get_statement\` with that id only when you need to read
303
+ the underlying values to reason about them. If you just
304
+ want to display the rows to the user, embed a
305
+ \`[data:<statement_id>]\` marker in your prose instead -
306
+ the host UI fetches and renders the rows on its own. Wire
307
+ events (status, thinking, sql) stream to the user
308
+ automatically while the call is in flight.
309
+ `),
310
+ inputSchema: z.object({
311
+ question: z
312
+ .string()
313
+ .min(1, "question is required")
314
+ .describe(string.toDescription(`
315
+ ONE focused natural-language question about the data in this
316
+ space, covering a single metric / dimension / time window
317
+ (e.g. "What was Q3 revenue by region?"). Decompose a
318
+ multi-part ask into separate calls rather than combining it
319
+ here.
320
+ `)),
321
+ }),
322
+ outputSchema: z.object({
323
+ message: genieModel.GenieMessageSchema,
324
+ }),
325
+ execute: async ({ question }, ctxRaw) => {
326
+ const ctx = ctxRaw;
327
+ const { client, requestContext } = requireClient(ctx, toolId);
328
+ const writer = ctx?.writer;
329
+ const signal = ctx?.abortSignal;
330
+ const threadId = requestContext.get(MASTRA_THREAD_ID_KEY);
331
+ // Bounce placeholder / no-op questions BEFORE spending a Genie
332
+ // round-trip on them. Genie answers any of these with "Your
333
+ // request 'noop' does not relate to..." - useless noise that
334
+ // shows up in the UI and eats one of the workspace's 5
335
+ // questions/minute. Returning a clear error here surfaces the
336
+ // issue to the agent loop so the model corrects course instead
337
+ // of wasting a turn.
338
+ const trimmed = question.trim();
339
+ if (trimmed.length === 0 || PLACEHOLDER_QUESTIONS.has(trimmed.toLowerCase())) {
340
+ throw ValidationError.invalidValue(`${toolId}.question`, question, "a real natural-language question, not a placeholder; skip the call instead");
341
+ }
342
+ // Seed the active Genie `conversation_id` onto `RequestContext`
343
+ // from the cross-request cache when a Mastra `threadId` is
344
+ // present so multi-turn chats reuse the same Genie conversation
345
+ // (and Genie's accumulated context) across separate user turns.
346
+ // The same `RequestContext` is reused across every `ask_genie`
347
+ // call within one user turn, so `ensureConversationSeeded`
348
+ // hits the cache at most once per request per space.
349
+ const cacheKey = await conversationCacheKey(spaceId, threadId, resolveUserKey(requestContext));
350
+ await ensureConversationSeeded(requestContext, spaceId, cacheKey);
351
+ // Fire the lifecycle `started` event before any LLM /
352
+ // network round-trip so the host UI can pop a "Thinking..."
353
+ // pill the instant the model decides to delegate.
354
+ const startedEvent = {
355
+ type: "started",
356
+ spaceId,
357
+ content: question,
358
+ };
359
+ await safeWrite(logger, writer, startedEvent);
360
+ // Single turn of `genieEventChat`. Hoisted into a closure so
361
+ // we can re-run it after evicting a stale `conversation_id`
362
+ // without duplicating the event-loop body.
363
+ const runTurn = async () => {
364
+ const seedConversationId = readContextConversationId(requestContext, spaceId);
365
+ let finalMessage;
366
+ for await (const event of chat.genieEventChat(spaceId, question, {
367
+ workspaceClient: client,
368
+ ...(seedConversationId ? { conversationId: seedConversationId } : {}),
369
+ ...(signal ? { context: signal } : {}),
370
+ })) {
371
+ if (event.type !== "message") {
372
+ await safeWrite(logger, writer, event);
373
+ }
374
+ const eventConversationId = event.conversation_id;
375
+ if (eventConversationId) {
376
+ writeContextConversationId(requestContext, spaceId, eventConversationId);
377
+ }
378
+ if (event.type === "result") {
379
+ finalMessage = event.message;
380
+ }
381
+ }
382
+ if (!finalMessage) {
383
+ throw ExecutionError.missingData("Genie result event");
384
+ }
385
+ return finalMessage;
386
+ };
387
+ let finalMessage;
388
+ try {
389
+ finalMessage = await runTurn();
390
+ }
391
+ catch (err) {
392
+ // The seeded `conversation_id` was rejected by Genie - most
393
+ // commonly because it was deleted upstream, expired past
394
+ // Databricks' (undocumented) lifetime, or was minted in a
395
+ // different space. Drop both the cached id AND the
396
+ // per-request value so the retry calls `startConversation`,
397
+ // and try once more. Only retry when we *had* a seeded id -
398
+ // a fresh call that 404s shouldn't loop.
399
+ const seeded = readContextConversationId(requestContext, spaceId);
400
+ if (seeded && error.errorContext(err).notAccessible) {
401
+ logger.warn("conversation-cache:stale, resetting", {
402
+ spaceId,
403
+ conversationId: seeded,
404
+ error: error.errorMessage(err),
405
+ });
406
+ await evictCachedConversationId(cacheKey);
407
+ writeContextConversationId(requestContext, spaceId, undefined);
408
+ finalMessage = await runTurn();
409
+ }
410
+ else {
411
+ throw err;
412
+ }
413
+ }
414
+ // Refresh the cache entry on every successful turn. Re-setting
415
+ // the same key both persists newly-minted ids (cache miss path)
416
+ // and extends the TTL on active conversations (sliding window).
417
+ await saveCachedConversationId(cacheKey, readContextConversationId(requestContext, spaceId));
418
+ return { message: stripSuggestedQuestions(finalMessage) };
419
+ },
420
+ });
421
+ }
422
+ function buildSpaceDescriptionTool(opts) {
423
+ const { spaceId, alias } = opts;
424
+ const toolId = `get_space_description${aliasSuffix(alias)}`;
425
+ return createTool({
426
+ id: toolId,
427
+ description: string.toDescription(`
428
+ Return the Genie space "${alias}"'s title, description, and
429
+ warehouse id. Cheap (single REST call, no LLM round-trip).
430
+ Call this FIRST on any user turn that's going to touch
431
+ \`ask_genie\`, unless the same description already landed
432
+ earlier in this conversation - the title + description tell
433
+ you what tables, metrics, and time windows the space
434
+ actually covers, which is what lets you decompose the
435
+ user's question into the right \`ask_genie\` sub-questions.
436
+ `),
437
+ inputSchema: z.object({}),
438
+ outputSchema: z.object({
439
+ spaceId: z.string(),
440
+ title: z.string().optional(),
441
+ description: z.string().optional(),
442
+ warehouseId: z.string().optional(),
443
+ }),
444
+ execute: async (_input, ctxRaw) => {
445
+ const ctx = ctxRaw;
446
+ const { client } = requireClient(ctx, toolId);
447
+ const signal = ctx?.abortSignal;
448
+ // Route through the package's central Genie space fetch. The
449
+ // description surface (title / description / warehouse id) lives
450
+ // on the directory-listing shape, so skip the larger
451
+ // `serialized_space` payload here.
452
+ const space = await genieSpace.getGenieSpace(spaceId, {
453
+ workspaceClient: client,
454
+ serialized: false,
455
+ ...(signal ? { context: signal } : {}),
456
+ });
457
+ return {
458
+ spaceId,
459
+ ...(space.title ? { title: space.title } : {}),
460
+ ...(space.description ? { description: space.description } : {}),
461
+ ...(space.warehouse_id ? { warehouseId: space.warehouse_id } : {}),
462
+ };
463
+ },
464
+ });
465
+ }
466
+ function buildSpaceSerializedTool(opts) {
467
+ const { spaceId, alias } = opts;
468
+ const toolId = `get_space_serialized${aliasSuffix(alias)}`;
469
+ return createTool({
470
+ id: toolId,
471
+ description: string.toDescription(`
472
+ Return the full \`GenieSpace\` JSON for the "${alias}" space.
473
+ Use only when you need exact column / table identifiers
474
+ \`get_space_description\` doesn't expose. Larger payload, so
475
+ prefer the description tool when it's enough.
476
+ `),
477
+ inputSchema: z.object({}),
478
+ outputSchema: z.object({ space: z.unknown() }),
479
+ execute: async (_input, ctxRaw) => {
480
+ const ctx = ctxRaw;
481
+ const { client } = requireClient(ctx, toolId);
482
+ const signal = ctx?.abortSignal;
483
+ // Central Genie space fetch with the opt-in `serialized_space`
484
+ // blob (catalogs, tables, sample questions, prompts) that the
485
+ // typed SDK `getSpace` omits - the whole point of this tool.
486
+ const space = await genieSpace.getGenieSpace(spaceId, {
487
+ workspaceClient: client,
488
+ ...(signal ? { context: signal } : {}),
489
+ });
490
+ return { space };
491
+ },
492
+ });
493
+ }
494
+ /* --------------------------- shared tools --------------------------- */
495
+ /**
496
+ * Default row cap for {@link buildGetStatementTool} when the agent
497
+ * doesn't supply a `limit`. Sized to keep result sets out of the
498
+ * model context unless the agent explicitly opts into more rows -
499
+ * the cheap shape (column names + a handful of representative
500
+ * rows) is usually enough to reason about a query.
501
+ */
502
+ const DEFAULT_STATEMENT_LIMIT = 50;
503
+ function buildGetStatementTool() {
504
+ const toolId = "get_statement";
505
+ return createTool({
506
+ id: toolId,
507
+ description: string.toDescription(`
508
+ Fetch the rows of a Genie statement by its \`statement_id\` (the
509
+ value at \`message.query_result.statement_id\` or
510
+ \`message.attachments[*].query.statement_id\` returned from
511
+ \`ask_genie\`). Use this ONLY when you need to read the underlying
512
+ values to reason about them in your reply - e.g. naming the
513
+ largest row, computing a delta the visualization wouldn't already
514
+ convey, or filtering down to a specific record. If you'd just be
515
+ reciting numbers the user will see anyway, skip the call and
516
+ embed a \`[data:<statement_id>]\` marker in your prose instead;
517
+ the host UI fetches and renders the rows on its own. \`limit\`
518
+ caps the number of rows returned (defaults to
519
+ ${DEFAULT_STATEMENT_LIMIT}). \`rowCount\` reflects the full
520
+ upstream total - compare to \`rows.length\` to detect truncation.
521
+ `),
522
+ inputSchema: z.object({
523
+ statement_id: z
524
+ .string()
525
+ .min(1, "statement_id is required")
526
+ .describe(string.toDescription(`
527
+ Genie \`statement_id\` whose rows to read. Take it from
528
+ \`message.query_result.statement_id\` or
529
+ \`message.attachments[*].query.statement_id\` on an
530
+ \`ask_genie\` result; it is never a value you construct.
531
+ `)),
532
+ limit: z
533
+ .number()
534
+ .int()
535
+ .nonnegative()
536
+ .optional()
537
+ .describe("Max rows to return. Defaults to a small sample; raise only when more rows are genuinely needed."),
538
+ }),
539
+ outputSchema: z.object({
540
+ columns: z.array(z.string()),
541
+ rows: z.array(z.record(z.string(), z.unknown())),
542
+ rowCount: z.number(),
543
+ truncated: z.boolean(),
544
+ }),
545
+ execute: async ({ statement_id, limit }, ctxRaw) => {
546
+ const ctx = ctxRaw;
547
+ const { client } = requireClient(ctx, toolId);
548
+ const signal = ctx?.abortSignal;
549
+ const effectiveLimit = limit ?? DEFAULT_STATEMENT_LIMIT;
550
+ const data = await fetchStatementData(client, statement_id, {
551
+ limit: effectiveLimit,
552
+ ...(signal ? { signal } : {}),
553
+ });
554
+ return {
555
+ columns: data.columns,
556
+ rows: data.rows,
557
+ rowCount: data.rowCount,
558
+ truncated: data.rows.length < data.rowCount,
559
+ };
560
+ },
561
+ });
562
+ }
563
+ /**
564
+ * `prepare_chart` Mastra tool. Thin wrapper over
565
+ * {@link prepareChart} that resolves the dataset by fetching the
566
+ * Genie statement's rows on demand. The tool mints a `chartId`
567
+ * synchronously, caches an empty placeholder, and kicks off the
568
+ * planner in the background so the agent loop never blocks. The
569
+ * host UI resolves `[chart:<chartId>]` markers by reading the
570
+ * cached {@link Chart} entry (1h TTL).
571
+ *
572
+ * Space-agnostic: a Genie `statement_id` is workspace-scoped, so
573
+ * one shared `prepare_chart` tool covers every wired Genie space.
574
+ *
575
+ * Cancellation: deliberately does NOT forward the per-call
576
+ * `abortSignal` to {@link prepareChart}. The planner task is
577
+ * fire-and-forget background work; the tool's own `execute`
578
+ * resolves the moment the `chartId` is minted, so the per-call
579
+ * signal aborts the second the tool returns. The 1h cache TTL
580
+ * caps abandoned entries.
581
+ */
582
+ function buildPrepareChartTool(opts) {
583
+ const { config } = opts;
584
+ const toolId = "prepare_chart";
585
+ return createTool({
586
+ id: toolId,
587
+ description: string.toDescription([
588
+ `
589
+ Queue a chart for the rows of a Genie statement. Mints a
590
+ short \`chartId\` synchronously and kicks off a BACKGROUND
591
+ task that fetches the statement's rows, runs the
592
+ chart-planner to pick a chart type and Echarts spec, and
593
+ caches the result under the \`chartId\` for one hour. The
594
+ host UI fetches the cached chart on its own once it lands.
595
+ `,
596
+ `
597
+ To display the chart in your reply, embed
598
+ \`[chart:<chartId>]\` on its own line at the position you
599
+ want it to appear, using the EXACT \`chartId\` string this
600
+ call returned. Never construct a chart id yourself (it is
601
+ not the \`statement_id\` or any variation of it) - only a
602
+ value returned by this tool resolves to a real chart. The
603
+ tool returns immediately - do NOT wait or call it again to
604
+ "check progress"; the chart resolves asynchronously on the
605
+ host UI's side.
606
+ `,
607
+ `
608
+ Use this only when the data has a story a chart conveys
609
+ better than a table (trends, rankings, distributions,
610
+ parts-of-a-whole). For raw rows, embed
611
+ \`[data:<statement_id>]\` instead and skip this tool.
612
+ `,
613
+ ]),
614
+ inputSchema: prepareChartRequestSchema,
615
+ outputSchema: wire.ChartSchema.pick({ chartId: true }),
616
+ execute: async (request, ctxRaw) => {
617
+ const ctx = ctxRaw;
618
+ const { client, requestContext } = requireClient(ctx, toolId);
619
+ return prepareChart({
620
+ config,
621
+ userKey: resolveUserKey(requestContext),
622
+ ...(request.title ? { title: request.title } : {}),
623
+ ...(request.description ? { description: request.description } : {}),
624
+ resolveData: (taskSignal) => fetchStatementData(client, request.statement_id, {
625
+ ...(taskSignal ? { signal: taskSignal } : {}),
626
+ }),
627
+ ...(ctx?.requestContext ? { requestContext: ctx.requestContext } : {}),
628
+ });
629
+ },
630
+ });
631
+ }
632
+ /* --------------------------- orchestration prompt --------------------------- */
633
+ /**
634
+ * Suggested orchestration prompt for the central agent that owns
635
+ * the Genie tools. Compose into your agent's `instructions` to
636
+ * get the canonical "decompose questions, ask Genie focused
637
+ * sub-questions, place data / chart markers in prose" behavior:
638
+ *
639
+ * ```ts
640
+ * createAgent({
641
+ * instructions: `${myAgentInstructions}\n\n${GENIE_INSTRUCTIONS}`,
642
+ * tools(plugins) {
643
+ * return { ...plugins.genie?.toolkit() };
644
+ * },
645
+ * });
646
+ * ```
647
+ *
648
+ * The prompt references the bare tool names (`ask_genie`,
649
+ * `get_space_description`, `get_space_serialized`,
650
+ * `get_statement`, `prepare_chart`) used for the single-space
651
+ * default alias. Multi-space deployments should write their own
652
+ * variant that names the suffixed per-space tools
653
+ * (e.g. `ask_genie_sales`).
654
+ */
655
+ export const GENIE_INSTRUCTIONS = string.toDescription([
656
+ "Genie orchestration. For every user question that needs SQL-backed data:",
657
+ {
658
+ numbered: [
659
+ `
660
+ Start by calling \`get_space_description\` to ground yourself
661
+ in what the space covers (tables, metrics, time windows),
662
+ unless you already saw the same description earlier in this
663
+ conversation. Reach for \`get_space_serialized\` only when you
664
+ need exact column / table identifiers the description doesn't
665
+ expose - it's a much larger payload.
666
+ `,
667
+ `
668
+ Decompose the user's question into focused sub-questions
669
+ BEFORE asking Genie anything. One sub-question per distinct
670
+ metric, dimension, or time window. Then call \`ask_genie\`
671
+ once per sub-question - usually two to six calls per turn,
672
+ and let earlier answers inform what you ask next. Cramming
673
+ a multi-part question into one \`ask_genie\` call almost
674
+ always produces a worse answer than asking the pieces
675
+ separately. Only collapse to a single call when the question
676
+ is genuinely atomic ("what was Q3 revenue?").
677
+
678
+ Worked example: user asks "How did SKU 1234's revenue
679
+ compare to its category average last quarter, and which
680
+ regions drove the gap?" Decomposes to: (a) \`ask_genie\`
681
+ for SKU 1234's Q3 revenue, (b) \`ask_genie\` for the
682
+ category-average Q3 revenue, (c) \`ask_genie\` for SKU
683
+ 1234's Q3 revenue split by region. Three focused calls,
684
+ each grounded in the prior results.
685
+ `,
686
+ `
687
+ Each \`ask_genie\` call returns the terminal \`GenieMessage\`.
688
+ When the turn ran SQL the result has a \`statement_id\` - read
689
+ it from \`message.query_result.statement_id\` (or the first
690
+ attachment's \`query.statement_id\`).
691
+ `,
692
+ [
693
+ `
694
+ To DISPLAY a result set in your reply, embed a marker on its
695
+ own line where the visualization should appear. Two marker
696
+ shapes:
697
+ `,
698
+ {
699
+ bullets: [
700
+ `
701
+ \`[data:<statement_id>]\` - render the rows as a table.
702
+ Use this when there's no clear visual story (long lists,
703
+ reference data, single-row results, or the user just
704
+ wants to see the data). Embed the marker directly; no
705
+ tool call needed.
706
+ `,
707
+ `
708
+ \`[chart:<chartId>]\` - render the rows as a chart. To
709
+ get a \`<chartId>\`, call \`prepare_chart\` with the
710
+ statement's id (and an optional \`title\` / one-line
711
+ \`description\` of the insight to surface). The tool
712
+ returns the \`chartId\` synchronously and prepares the
713
+ chart spec in the background; embed the returned id as
714
+ \`[chart:<chartId>]\` on its own line wherever the
715
+ chart should appear. Use a chart when the data has a
716
+ story a visual conveys better than a table (trends,
717
+ rankings, distributions, parts-of-a-whole).
718
+
719
+ NEVER invent or hand-build a \`<chartId>\`. A valid
720
+ \`<chartId>\` is the opaque token a \`prepare_chart\`
721
+ call returned to you in THIS turn - nothing else. It
722
+ is NOT a \`statement_id\`, and it is NOT a
723
+ \`statement_id\` prefix with a label appended (e.g.
724
+ \`01f1...-region-fill\`). If you have not called
725
+ \`prepare_chart\` and received an id back, do not write
726
+ a \`[chart:...]\` marker at all - use \`[data:...]\`
727
+ instead. A fabricated chart id renders nothing and
728
+ wastes a request.
729
+ `,
730
+ ],
731
+ },
732
+ `
733
+ The host UI resolves both markers on its own once it sees
734
+ them - you do NOT need to call \`get_statement\` just to
735
+ display data, and you do NOT need to wait on
736
+ \`prepare_chart\` (it returns the id immediately and the
737
+ host UI fetches the cached chart later). Pick at most one
738
+ marker per statement; don't chart AND table the same result
739
+ side by side.
740
+ `,
741
+ ],
742
+ `
743
+ Call \`get_statement(statement_id, limit?)\` ONLY when you need
744
+ to read the actual values to reason about them (e.g. naming a
745
+ specific row, computing a delta the table or chart wouldn't
746
+ show, or sanity-checking a result before interpreting it). If
747
+ you'd just be reciting numbers the visualization already shows,
748
+ skip the call and use a marker instead. \`limit\` defaults to a
749
+ small sample; raise it only when you genuinely need more rows.
750
+ `,
751
+ `
752
+ Compose your final reply as plain prose. Interleave paragraphs
753
+ with \`[data:...]\` / \`[chart:...]\` markers wherever a result
754
+ should render. Don't dump all markers at the end - place each
755
+ one next to the prose that interprets it. Don't restate every
756
+ number the visualization already shows; call out deltas,
757
+ anomalies, takeaways.
758
+ `,
759
+ ],
760
+ },
761
+ ]);
762
+ /* --------------------- multi-alias surface --------------------- */
763
+ /**
764
+ * Normalize the {@link GenieSpacesConfig} record. Bare-string
765
+ * entries (`{ default: "01ef..." }`) get wrapped as
766
+ * `{ spaceId: "01ef..." }`; object entries pass through unchanged.
767
+ *
768
+ * @throws ConfigurationError when an alias is present but carries no space id
769
+ * (`{ default: process.env.DATABRICKS_GENIE_SPACE_ID }` with the variable
770
+ * unset). An alias that resolves to nothing is a wiring contradiction: the
771
+ * agent would advertise no Genie tool for a space the deployment believes it
772
+ * configured, so it fails at construction instead of going quiet.
773
+ */
774
+ export function normalizeGenieSpaces(spaces) {
775
+ if (!spaces)
776
+ return {};
777
+ const out = {};
778
+ for (const [alias, value] of Object.entries(spaces)) {
779
+ const spaceId = typeof value === "string" ? value : value?.spaceId;
780
+ if (!spaceId)
781
+ throw missingSpaceId(alias);
782
+ out[alias] = typeof value === "string" ? { spaceId } : value;
783
+ }
784
+ return out;
785
+ }
786
+ /** Config contradiction: an alias present in `genieSpaces` with no space id. */
787
+ function missingSpaceId(alias) {
788
+ const envHint = alias === DEFAULT_GENIE_ALIAS
789
+ ? "Set DATABRICKS_GENIE_SPACE_ID, pass the space id inline, or drop the alias."
790
+ : `Pass the space id inline (DATABRICKS_GENIE_SPACE_ID only backs the "${DEFAULT_GENIE_ALIAS}" alias) or drop the alias.`;
791
+ return ConfigurationError.resourceNotFound(`genieSpaces.${alias} space id`, envHint);
792
+ }
793
+ /**
794
+ * Discover Genie space aliases from every supported source and
795
+ * merge them into a single record. Precedence (highest first):
796
+ *
797
+ * 1. {@link MastraPluginConfig.genieSpaces} on the `mastra(...)`
798
+ * call. Explicit Mastra wiring always wins so users can
799
+ * override AppKit's defaults per-agent.
800
+ * 2. AppKit `genie({ spaces: { ... } })` plugin instance. Lets
801
+ * users keep using the existing AppKit config format
802
+ * (`genie({ spaces: { sales: "...", ops: "..." } })`)
803
+ * without restating the same record on the Mastra plugin.
804
+ * Read off the live plugin instance via a structural cast
805
+ * since `Plugin.config` is TS-protected (not runtime-private).
806
+ * 3. `DATABRICKS_GENIE_SPACE_ID` env var (registered under the
807
+ * well-known `default` alias). Matches the AppKit `genie()`
808
+ * plugin's fallback behavior so a bare `mastra()` + `genie()`
809
+ * pair just works.
810
+ *
811
+ * Aliases collide cleanly: a higher-precedence source's value
812
+ * replaces a lower one's wholesale. A source that contributes zero
813
+ * aliases is skipped; a source that names an alias without a space
814
+ * id fails through {@link normalizeGenieSpaces}.
815
+ */
816
+ export function resolveGenieSpaces(config, context) {
817
+ const merged = {};
818
+ // Source 3 (lowest precedence): env var.
819
+ const envSpaceId = process.env.DATABRICKS_GENIE_SPACE_ID;
820
+ if (envSpaceId) {
821
+ merged[DEFAULT_GENIE_ALIAS] = { spaceId: envSpaceId };
822
+ }
823
+ // Source 2: AppKit `genie()` plugin instance config. Use a
824
+ // structural cast - `Plugin.config` is `protected` in TS only,
825
+ // and the runtime layout is plain object property access.
826
+ const geniePlugin = plugin.instance(context, genie);
827
+ if (geniePlugin) {
828
+ const pluginSpaces = geniePlugin.config?.spaces;
829
+ if (pluginSpaces) {
830
+ Object.assign(merged, normalizeGenieSpaces(pluginSpaces));
831
+ }
832
+ }
833
+ // Source 1 (highest precedence): explicit Mastra wiring.
834
+ if (config.genieSpaces) {
835
+ Object.assign(merged, normalizeGenieSpaces(config.genieSpaces));
836
+ }
837
+ return merged;
838
+ }
839
+ /**
840
+ * Build the flat Mastra tools record for every configured Genie
841
+ * space. Two shared, space-agnostic tools (`get_statement`,
842
+ * `prepare_chart`) are registered once regardless of how many
843
+ * spaces are wired; the per-space tools (`ask_genie`,
844
+ * `get_space_description`, `get_space_serialized`) are suffixed
845
+ * with `_<alias>` for non-default aliases so multi-space
846
+ * deployments stay disambiguated.
847
+ *
848
+ * Returns a record keyed by tool id, ready to spread into the
849
+ * central `Agent`'s `tools` map (or surfaced via the
850
+ * `plugins.genie?.toolkit()` callback). Returns an empty record
851
+ * when `spaces` resolves to zero entries so the caller can spread
852
+ * safely.
853
+ */
854
+ export function buildGenieTools(opts) {
855
+ const normalized = normalizeGenieSpaces(opts.spaces);
856
+ const tools = {};
857
+ if (Object.keys(normalized).length === 0)
858
+ return tools;
859
+ // Shared, space-agnostic tools.
860
+ tools.get_statement = buildGetStatementTool();
861
+ tools.prepare_chart = buildPrepareChartTool({ config: opts.config });
862
+ for (const [alias, space] of Object.entries(normalized)) {
863
+ const askTool = buildAskGenieTool({
864
+ spaceId: space.spaceId,
865
+ alias,
866
+ ...(space.hint ? { hint: space.hint } : {}),
867
+ });
868
+ const descTool = buildSpaceDescriptionTool({ spaceId: space.spaceId, alias });
869
+ const serTool = buildSpaceSerializedTool({ spaceId: space.spaceId, alias });
870
+ tools[askTool.id] = askTool;
871
+ tools[descTool.id] = descTool;
872
+ tools[serTool.id] = serTool;
873
+ }
874
+ return tools;
875
+ }
876
+ /**
877
+ * Plugin-toolkit adapter so the `plugins.genie?.toolkit()` lookup
878
+ * inside an agent's `tools(plugins)` callback returns the
879
+ * flat Genie tools record instead of throwing on missing plugin.
880
+ * Mirrors AppKit's `PluginToolkitProvider` shape.
881
+ */
882
+ export function buildGenieToolkitProvider(opts) {
883
+ return {
884
+ toolkit(_opts) {
885
+ return buildGenieTools(opts);
886
+ },
887
+ };
888
+ }
889
+ /* --------------------------- starter suggestions --------------------------- */
890
+ /**
891
+ * Default cap on starter suggestions surfaced to the chat empty
892
+ * state. Sample-question lists can run long (10+ on a curated
893
+ * space); a handful of one-tap prompts reads better than a wall of
894
+ * buttons.
895
+ */
896
+ const SUGGESTION_LIMIT = 6;
897
+ /**
898
+ * How long a space's parsed sample questions stay cached. They're
899
+ * authored config that changes rarely, and the lookup is an extra
900
+ * REST round-trip per chat mount, so a few minutes of caching keeps
901
+ * the empty state instant on reload without going stale for long.
902
+ */
903
+ const SUGGESTION_CACHE_TTL_MS = 10 * 60_000;
904
+ /** Space-id -> cached sample questions with an absolute expiry. */
905
+ const _suggestionCache = new Map();
906
+ /** Read a space's cached questions, or `undefined` on miss / expiry. */
907
+ function readSuggestionCache(spaceId) {
908
+ const entry = _suggestionCache.get(spaceId);
909
+ if (!entry)
910
+ return undefined;
911
+ if (entry.expires <= Date.now()) {
912
+ _suggestionCache.delete(spaceId);
913
+ return undefined;
914
+ }
915
+ return entry.questions;
916
+ }
917
+ /** Cache a space's parsed questions for {@link SUGGESTION_CACHE_TTL_MS}. */
918
+ function writeSuggestionCache(spaceId, questions) {
919
+ _suggestionCache.set(spaceId, {
920
+ questions,
921
+ expires: Date.now() + SUGGESTION_CACHE_TTL_MS,
922
+ });
923
+ }
924
+ /**
925
+ * Collect the curated starter questions across every resolved Genie
926
+ * space, deduped and capped. Each space's `sample_questions` are
927
+ * fetched once (cached for {@link SUGGESTION_CACHE_TTL_MS}) via
928
+ * {@link getGenieSpace} + {@link genieSampleQuestions}, then merged in
929
+ * alias-iteration order so a single-space app surfaces that space's
930
+ * questions and a multi-space app round-trips breadth-first up to the
931
+ * cap. A per-space fetch failure degrades to "no questions for that
932
+ * space" (logged, not thrown) so one unreachable space never blanks
933
+ * the whole list. Returns `[]` when no spaces are configured.
934
+ */
935
+ export async function collectSpaceSuggestions(opts) {
936
+ const limit = opts.limit ?? SUGGESTION_LIMIT;
937
+ const merged = [];
938
+ const seen = new Set();
939
+ for (const { spaceId } of Object.values(opts.spaces)) {
940
+ let questions = readSuggestionCache(spaceId);
941
+ if (!questions) {
942
+ try {
943
+ const space = await genieSpace.getGenieSpace(spaceId, {
944
+ workspaceClient: opts.client,
945
+ ...(opts.signal ? { context: opts.signal } : {}),
946
+ });
947
+ questions = genieSpace.genieSampleQuestions(space);
948
+ writeSuggestionCache(spaceId, questions);
949
+ }
950
+ catch (err) {
951
+ logger.warn("suggestions:fetch-error", {
952
+ spaceId,
953
+ error: error.errorMessage(err),
954
+ });
955
+ questions = [];
956
+ }
957
+ }
958
+ for (const question of questions) {
959
+ if (seen.has(question))
960
+ continue;
961
+ seen.add(question);
962
+ merged.push(question);
963
+ if (merged.length >= limit)
964
+ return merged;
965
+ }
966
+ }
967
+ return merged;
968
+ }
969
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuaWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZ2VuaWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9DRztBQUVILE9BQU8sRUFDTCxZQUFZLEVBQ1osa0JBQWtCLEVBQ2xCLGNBQWMsRUFDZCxLQUFLLEVBQ0wsZUFBZSxHQUNoQixNQUFNLG9CQUFvQixDQUFDO0FBRTVCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUMzQyxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssSUFBSSxVQUFVLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUM3RCxPQUFPLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM1RCxPQUFPLEVBQUUsVUFBVSxFQUFxQixNQUFNLHlCQUF5QixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxJQUFJLEVBQXdDLE1BQU0sMEJBQTBCLENBQUM7QUFFdEYsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDcEUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFHeEIsT0FBTyxFQUFFLHlCQUF5QixFQUFFLFlBQVksRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNsRSxPQUFPLEVBQUUsZUFBZSxFQUFFLGNBQWMsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUUzRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDakQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUVyQyxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0FBRTFDLHdFQUF3RTtBQUN4RSxNQUFNLENBQUMsTUFBTSxt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QyxDQUFDLENBQUMsRUFBRSxDQUFDO2lCQUNqRCxDQUFDLENBQUM7Z0JBQ0gsU0FBUyxHQUFHLFVBQVUsQ0FBQyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDbkQsb0JBQW9CLENBQUMsT0FBTyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBQzNDLENBQUM7WUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO2dCQUNiLE1BQU0sQ0FBQyxJQUFJLENBQUMseUJBQXlCLEVBQUU7b0JBQ3JDLE9BQU87b0JBQ1AsS0FBSyxFQUFFLEtBQUssQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDO2lCQUMvQixDQUFDLENBQUM7Z0JBQ0gsU0FBUyxHQUFHLEVBQUUsQ0FBQztZQUNqQixDQUFDO1FBQ0gsQ0FBQztRQUNELEtBQUssTUFBTSxRQUFRLElBQUksU0FBUyxFQUFFLENBQUM7WUFDakMsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQztnQkFBRSxTQUFTO1lBQ2pDLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDbkIsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN0QixJQUFJLE1BQU0sQ0FBQyxNQUFNLElBQUksS0FBSztnQkFBRSxPQUFPLE1BQU0sQ0FBQztRQUM1QyxDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmllIHRvb2xzIGZvciBNYXN0cmEuXG4gKlxuICogU3VyZmFjZXMgZWFjaCBjb25maWd1cmVkIEdlbmllIHNwYWNlIGFzIGEgc21hbGwgc2V0IG9mIGZsYXQgTWFzdHJhXG4gKiB0b29scyB0aGUgY2FsbGluZyBhZ2VudCBkcml2ZXMgZGlyZWN0bHkgLSBubyBpbm5lciBvcmNoZXN0cmF0b3JcbiAqIGFnZW50LiBUaGUgY2VudHJhbCBhZ2VudCBkZWNvbXBvc2VzIHVzZXIgcXVlc3Rpb25zLCBwaWNrcyB3aGljaFxuICogc3BhY2UgdG8gYXNrLCBzdHJlYW1zIHRoZSBwZXItdHVybiB3aXJlIGV2ZW50cyAoc3RhdHVzLCB0aGlua2luZyxcbiAqIHNxbCwgcm93cykgdGhyb3VnaCBgY3R4LndyaXRlcmAsIGFuZCBjb21wb3NlcyB0aGUgZmluYWwgcmVwbHkuXG4gKiBSb3dzIGFyZSBuZXZlciBmZXRjaGVkIGVhZ2VybHk6IHRoZSBhZ2VudCByZWFkcyBhIHN0YXRlbWVudCdzXG4gKiB2YWx1ZXMgb25seSB3aGVuIGl0IG5lZWRzIHRvIHJlYXNvbiBhYm91dCB0aGVtLCBvdGhlcndpc2UgaXQgZW1iZWRzXG4gKiBhIGBbZGF0YTo8c3RhdGVtZW50X2lkPl1gIG1hcmtlciBpbiBwcm9zZSBhbmQgbGV0cyB0aGUgaG9zdCBVSVxuICogcmVzb2x2ZSB0aGUgZGF0YS4gQ2hhcnRzIGFyZSBtaW50ZWQgYXN5bmNocm9ub3VzbHkgYW5kIHJlZmVyZW5jZWRcbiAqIGJ5IGBbY2hhcnQ6PGNoYXJ0SWQ+XWAgbWFya2VycyBzbyBwcm9zZSBpc24ndCBibG9ja2VkIG9uIGNoYXJ0XG4gKiBnZW5lcmF0aW9uOyB0aGUgaG9zdCBVSSBmZXRjaGVzIHRoZSBjYWNoZWQgc3BlYyBieSBpZCBvbmNlIHJlYWR5LlxuICogU3BhY2UgZGVzY3JpcHRpb24gYW5kIHNlcmlhbGl6ZWQtc3BhY2UgbG9va3VwcyBhcmUgYXZhaWxhYmxlIGZvclxuICogZ3JvdW5kaW5nIHdoZW4gdGhlIGFnZW50IG5lZWRzIHNjaGVtYSBjb250ZXh0LlxuICpcbiAqIEVhY2ggdG9vbCdzIGBleGVjdXRlYCBwdWxscyB0aGUgcGVyLXJlcXVlc3RcbiAqIHtAbGluayBXb3Jrc3BhY2VDbGllbnR9IG9mZiBgY3R4LnJlcXVlc3RDb250ZXh0YCAoc3RhbXBlZCBieVxuICogYE1hc3RyYVNlcnZlcmAgdW5kZXIge0BsaW5rIE1BU1RSQV9VU0VSX0tFWX0pIGFuZCB0aGUgcGVyLWNhbGxcbiAqIGB3cml0ZXJgIC8gYGFib3J0U2lnbmFsYCBvZmYgYGN0eGAsIHNvIHRoZSB0b29scyBhcmUgc3RhdGVsZXNzXG4gKiBhY3Jvc3MgcmVxdWVzdHMgYW5kIHRoZSBjZW50cmFsIGFnZW50IG93bnMgdGhlIGxvb3AuXG4gKlxuICogVGhlIHRvb2xzIHRhbGsgdG8gR2VuaWUgZGlyZWN0bHkgdmlhIGBAZGJ4LXRvb2xzL2dlbmllYFxuICogKGBnZW5pZUV2ZW50Q2hhdGApOyBzdGF0ZW1lbnQtcm93IGZldGNoaW5nIGlzIGRlbGVnYXRlZCB0b1xuICoge0BsaW5rIGZldGNoU3RhdGVtZW50RGF0YX0gZnJvbSBgLi9zdGF0ZW1lbnQuanNgLCB3aGljaCB3cmFwc1xuICogdGhlIHdvcmtzcGFjZSBgc3RhdGVtZW50RXhlY3V0aW9uLmdldFN0YXRlbWVudGAgQVBJLiBBcHBLaXQnc1xuICogc3RvY2sgYGdlbmllYCBwbHVnaW4gaXMgaG9ub3JlZCBvbmx5IGZvciBpdHMgYHNwYWNlc2AgY29uZmlnXG4gKiBzbyBleGlzdGluZyBBcHBLaXQtc3R5bGUgd2lyaW5nIGtlZXBzIHdvcmtpbmcgd2l0aG91dCBjaGFuZ2UuXG4gKlxuICogU3VnZ2VzdGVkIG9yY2hlc3RyYXRpb24gcHJvbXB0IGZvciB0aGUgY2VudHJhbCBhZ2VudCBsaXZlcyBpblxuICoge0BsaW5rIEdFTklFX0lOU1RSVUNUSU9OU307IGNvbXBvc2UgaXQgaW50byB0aGUgYWdlbnQncyBvd25cbiAqIGBpbnN0cnVjdGlvbnNgIHdoZW4geW91IHdhbnQgdGhlIGNhbm9uaWNhbCBcImhvdyB0byBkcml2ZSB0aGVcbiAqIEdlbmllIHRvb2xzXCIgZ3VpZGFuY2UuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7XG4gIENhY2hlTWFuYWdlcixcbiAgQ29uZmlndXJhdGlvbkVycm9yLFxuICBFeGVjdXRpb25FcnJvcixcbiAgZ2VuaWUsXG4gIFZhbGlkYXRpb25FcnJvcixcbn0gZnJvbSBcIkBkYXRhYnJpY2tzL2FwcGtpdFwiO1xuaW1wb3J0IHsgV29ya3NwYWNlQ2xpZW50IH0gZnJvbSBcIkBkYXRhYnJpY2tzL3Nkay1leHBlcmltZW50YWxcIjtcbmltcG9ydCB7IHBsdWdpbiB9IGZyb20gXCJAZGJ4LXRvb2xzL2FwcGtpdFwiO1xuaW1wb3J0IHsgY2hhdCwgc3BhY2UgYXMgZ2VuaWVTcGFjZSB9IGZyb20gXCJAZGJ4LXRvb2xzL2dlbmllXCI7XG5pbXBvcnQgeyBlcnJvciwgbG9nLCBzdHJpbmcgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgZ2VuaWVNb2RlbCwgdHlwZSBHZW5pZU1lc3NhZ2UgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtZ2VuaWVcIjtcbmltcG9ydCB7IHdpcmUsIHR5cGUgTWFzdHJhV3JpdGVyLCB0eXBlIFN0YXJ0ZWRFdmVudCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1tYXN0cmFcIjtcbmltcG9ydCB0eXBlIHsgUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiQG1hc3RyYS9jb3JlL3JlcXVlc3QtY29udGV4dFwiO1xuaW1wb3J0IHsgTUFTVFJBX1RIUkVBRF9JRF9LRVkgfSBmcm9tIFwiQG1hc3RyYS9jb3JlL3JlcXVlc3QtY29udGV4dFwiO1xuaW1wb3J0IHsgY3JlYXRlVG9vbCB9IGZyb20gXCJAbWFzdHJhL2NvcmUvdG9vbHNcIjtcbmltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5cbmltcG9ydCB0eXBlIHsgTWFzdHJhVG9vbHMgfSBmcm9tIFwiLi9hZ2VudHNcIjtcbmltcG9ydCB7IGNoYXJ0UGxhbm5lclJlcXVlc3RTY2hlbWEsIHByZXBhcmVDaGFydCB9IGZyb20gXCIuL2NoYXJ0XCI7XG5pbXBvcnQgeyBNQVNUUkFfVVNFUl9LRVksIHJlc29sdmVVc2VyS2V5IH0gZnJvbSBcIi4vY29uZmlnXCI7XG5pbXBvcnQgdHlwZSB7IE1hc3RyYVBsdWdpbkNvbmZpZywgVXNlciB9IGZyb20gXCIuL2NvbmZpZ1wiO1xuaW1wb3J0IHsgZmV0Y2hTdGF0ZW1lbnREYXRhIH0gZnJvbSBcIi4vc3RhdGVtZW50XCI7XG5pbXBvcnQgeyBzYWZlV3JpdGUgfSBmcm9tIFwiLi93cml0ZXJcIjtcblxuY29uc3QgbG9nZ2VyID0gbG9nLmxvZ2dlcihcIm1hc3RyYS9nZW5pZVwiKTtcblxuLyoqIERlZmF1bHQgYWxpYXMgdXNlZCB3aGVuIGEgc2luZ2xlIHVubmFtZWQgR2VuaWUgc3BhY2UgaXMgd2lyZWQgdXAuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9HRU5JRV9BTElBUyA9IFwiZGVmYXVsdFwiO1xuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gY29uZmlnIHR5cGVzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKiogUGVyLXNwYWNlIEdlbmllIGFnZW50IGNvbmZpZ3VyYXRpb24uICovXG5leHBvcnQgaW50ZXJmYWNlIEdlbmllU3BhY2VDb25maWcge1xuICAvKiogR2VuaWUgYHNwYWNlX2lkYC4gUmVxdWlyZWQ7IHJlc29sdmVzIHZpYSBgY2xpZW50LmdlbmllLmdldFNwYWNlYC4gKi9cbiAgc3BhY2VJZDogc3RyaW5nO1xuICAvKipcbiAgICogT3B0aW9uYWwgaHVtYW4tcmVhZGFibGUgZGVzY3JpcHRpb24gYXBwZW5kZWQgdG8gdGhlIHBlci1zcGFjZVxuICAgKiB0b29sIGRlc2NyaXB0aW9ucyBzbyB0aGUgY2FsbGluZyBMTE0gaGFzIGhpbnRzIGFib3V0ICp3aGF0XG4gICAqIGRhdGEqIHRoaXMgc3BhY2UgY292ZXJzIChlLmcuIFwib3JkZXJzLCByZXR1cm5zLFxuICAgKiBmdWxmaWxsbWVudFwiKS4gV2hlbiBvbWl0dGVkLCBvbmx5IHRoZSBzcGFjZSdzIG93blxuICAgKiBgZGVzY3JpcHRpb25gIChmZXRjaGVkIG9uIGZpcnN0IHVzZSBvZiBgZ2V0X3NwYWNlX2Rlc2NyaXB0aW9uYClcbiAgICogaXMgc2hvd24uXG4gICAqL1xuICBoaW50Pzogc3RyaW5nO1xufVxuXG4vKiogTWFwIG9mIGFsaWFzIC0+IHNwYWNlIGNvbmZpZy4gQWNjZXB0cyBlaXRoZXIgZXhwbGljaXQgb2JqZWN0cyBvciBiYXJlIHNwYWNlIGlkcy4gKi9cbmV4cG9ydCB0eXBlIEdlbmllU3BhY2VzQ29uZmlnID0gUmVjb3JkPHN0cmluZywgR2VuaWVTcGFjZUNvbmZpZyB8IHN0cmluZz47XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gY3R4IGhlbHBlcnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKipcbiAqIE5hcnJvdyB2aWV3IG9mIHRoZSBzZWNvbmQgYXJnIE1hc3RyYSBwYXNzZXMgdG8gYSB0b29sJ3NcbiAqIGBleGVjdXRlKGlucHV0LCBjdHgpYC4gQ2FwdHVyZXMgdGhlIGZpZWxkcyB0aGUgR2VuaWUgdG9vbHNcbiAqIGFjdHVhbGx5IHJlYWQgLSBgcmVxdWVzdENvbnRleHRgIChmb3IgdXNlciAvIGNvbnZlcnNhdGlvblxuICogc3RhdGUpLCBgd3JpdGVyYCAoZm9yIHN0cmVhbWluZyBldmVudHMgdG8gdGhlIGhvc3QgVUkpLCBhbmRcbiAqIGBhYm9ydFNpZ25hbGAgKGZvciBwZXItY2FsbCBjYW5jZWxsYXRpb24pLlxuICovXG50eXBlIFRvb2xFeGVjdXRlQ3R4ID1cbiAgfCB7XG4gICAgICByZXF1ZXN0Q29udGV4dD86IFJlcXVlc3RDb250ZXh0O1xuICAgICAgd3JpdGVyPzogTWFzdHJhV3JpdGVyO1xuICAgICAgYWJvcnRTaWduYWw/OiBBYm9ydFNpZ25hbDtcbiAgICB9XG4gIHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIFB1bGwgdGhlIHBlci1yZXF1ZXN0IHtAbGluayBXb3Jrc3BhY2VDbGllbnR9IG9mZiB0aGUgYWN0aXZlXG4gKiBgUmVxdWVzdENvbnRleHRgLiBUaGUgTWFzdHJhIHBsdWdpbidzIHNlcnZlciBtaWRkbGV3YXJlIHN0YW1wc1xuICogYSB7QGxpbmsgVXNlcn0gb24gdGhlIGNvbnRleHQgdW5kZXIge0BsaW5rIE1BU1RSQV9VU0VSX0tFWX1cbiAqIGZvciBldmVyeSByZXF1ZXN0OyB0b29scyBmYWlsIGxvdWRseSB3aGVuIGl0J3MgbWlzc2luZyBiZWNhdXNlXG4gKiB0aGF0IG1lYW5zIHRoZSBNYXN0cmEgcGx1Z2luIGlzbid0IHJ1bm5pbmcgKGUuZy4gYSB0b29sIHdhc1xuICogaW52b2tlZCBvdXRzaWRlIHRoZSBjaGF0IHJvdXRlKS5cbiAqL1xuZnVuY3Rpb24gcmVxdWlyZUNsaWVudChcbiAgY3R4OiBUb29sRXhlY3V0ZUN0eCxcbiAgdG9vbElkOiBzdHJpbmcsXG4pOiB7XG4gIGNsaWVudDogV29ya3NwYWNlQ2xpZW50O1xuICByZXF1ZXN0Q29udGV4dDogUmVxdWVzdENvbnRleHQ7XG59IHtcbiAgY29uc3QgcmVxdWVzdENvbnRleHQgPSBjdHg/LnJlcXVlc3RDb250ZXh0O1xuICBpZiAoIXJlcXVlc3RDb250ZXh0KSB7XG4gICAgdGhyb3cgQ29uZmlndXJhdGlvbkVycm9yLnJlc291cmNlTm90Rm91bmQoXG4gICAgICBgJHt0b29sSWR9IHJlcXVlc3QgY29udGV4dGAsXG4gICAgICBcIkludm9rZSB0aGUgdG9vbCBmcm9tIGFuIGFnZW50IHR1cm4gc2VydmVkIGJ5IHRoZSBtYXN0cmEgcGx1Z2luLlwiLFxuICAgICk7XG4gIH1cbiAgY29uc3QgdXNlciA9IHJlcXVlc3RDb250ZXh0LmdldChNQVNUUkFfVVNFUl9LRVkpIGFzIFVzZXIgfCB1bmRlZmluZWQ7XG4gIGlmICghdXNlcikge1xuICAgIHRocm93IENvbmZpZ3VyYXRpb25FcnJvci5yZXNvdXJjZU5vdEZvdW5kKFxuICAgICAgYCR7dG9vbElkfSB1c2VyIGNvbnRleHRgLFxuICAgICAgXCJJbnZva2UgdGhlIHRvb2wgZnJvbSBhbiBhZ2VudCB0dXJuIHNlcnZlZCBieSB0aGUgbWFzdHJhIHBsdWdpbiwgd2hpY2ggc3RhbXBzIHRoZSBBcHBLaXQgdXNlciBvbiB0aGUgTWFzdHJhIHJlcXVlc3QgY29udGV4dC5cIixcbiAgICApO1xuICB9XG4gIHJldHVybiB7IGNsaWVudDogdXNlci5leGVjdXRpb25Db250ZXh0LmNsaWVudCwgcmVxdWVzdENvbnRleHQgfTtcbn1cblxuLyoqXG4gKiBMb3dlcmNhc2VkIHBsYWNlaG9sZGVyIHN0cmluZ3Mgd2UgcmVqZWN0IGF0IHRoZSBgYXNrX2dlbmllYFxuICogYm91bmRhcnkgc28gdGhlIExMTSBkb2Vzbid0IHNwZW5kIGEgR2VuaWUgcm91bmQtdHJpcCBvbiBhXG4gKiBub24tcXVlc3Rpb24uIEdlbmllIHBvbGl0ZWx5IGFuc3dlcnMgYW55IG9mIHRoZXNlIHdpdGggXCJZb3VyXG4gKiByZXF1ZXN0ICcuLi4nIGRvZXMgbm90IHJlbGF0ZSB0by4uLlwiIHdoaWNoIGlzIHB1cmUgVUkgbm9pc2UuXG4gKiBLZXB0IG5hcnJvdyBvbiBwdXJwb3NlIC0gcmVhbCBxdWVzdGlvbnMgc29tZXRpbWVzIHN0YXJ0IHdpdGhcbiAqIG9uZSBvZiB0aGVzZSB0b2tlbnMsIHNvIHdlIG9ubHkgbWF0Y2ggdGhlIEZVTEwgdHJpbW1lZCBzdHJpbmcuXG4gKi9cbmNvbnN0IFBMQUNFSE9MREVSX1FVRVNUSU9OUyA9IG5ldyBTZXQoW1xuICBcIm5vb3BcIixcbiAgXCJuby1vcFwiLFxuICBcInNraXBcIixcbiAgXCJub25lXCIsXG4gIFwibi9hXCIsXG4gIFwibmFcIixcbiAgXCJudWxsXCIsXG4gIFwidW5kZWZpbmVkXCIsXG4gIFwidGVzdFwiLFxuICBcInBsYWNlaG9sZGVyXCIsXG5dKTtcblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gY29udmVyc2F0aW9uIHN0YXRlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbi8qKlxuICogRXN0aW1hdGVkIEdlbmllIGNvbnZlcnNhdGlvbiBsaWZldGltZSBpbiBzZWNvbmRzLiBEYXRhYnJpY2tzXG4gKiBwdWJsaXNoZXMgbm8gb2ZmaWNpYWwgVFRMIG9uIHRoZSBjb252ZXJzYXRpb24gcmVzb3VyY2UgaXRzZWxmO1xuICogY29tbXVuaXR5IHByb2plY3RzIChlLmcuIHRoZSBvcGVuLXNvdXJjZSBEYXRhYnJpY2tzIEdlbmllIEJvdClcbiAqIGNvbnZlcmdlIG9uIDQgaG91cnMgb2YgaW5hY3Rpdml0eSBhcyBhIHNhZmUgb3BlcmF0aW5nIHdpbmRvdy5cbiAqIFRyZWF0IHRoaXMgYXMgYW4gZXN0aW1hdGUgdGhhdCBnZXRzICpleHRlbmRlZCBvbiBldmVyeSB1c2UqIGJ5XG4gKiByZS1zZXR0aW5nIHRoZSBjYWNoZSBlbnRyeSBhZnRlciBlYWNoIHN1Y2Nlc3NmdWwgdHVybiAoc2xpZGluZ1xuICogVFRMIHZpYSByZS1gc2V0YCkuIFdoZW4gdGhlIGVzdGltYXRlIGVuZHMgdXAgd3JvbmcgKGNvbnZlcnNhdGlvblxuICogZGVsZXRlZCwgZXhwaXJlZCB1cHN0cmVhbSwgY3Jvc3Mtc3BhY2UgcmVmZXJlbmNlZCksIGBhc2tfZ2VuaWVgXG4gKiBjYXRjaGVzIHRoZSBTREsncyBgUkVTT1VSQ0VfRE9FU19OT1RfRVhJU1RgLzQwNCBhbmQgdHJhbnNwYXJlbnRseVxuICogc3RhcnRzIGEgZnJlc2ggY29udmVyc2F0aW9uLlxuICovXG5jb25zdCBDT05WRVJTQVRJT05fVFRMX1NFQyA9IDQgKiA2MCAqIDYwO1xuXG4vKiogQ2FjaGUgbmFtZXNwYWNlIHByZWZpeCBzbyBjb2V4aXN0aW5nIE1hc3RyYSBjYWNoZXMgZG9uJ3QgY29sbGlkZS4gKi9cbmNvbnN0IENPTlZFUlNBVElPTl9DQUNIRV9OQU1FU1BBQ0UgPSBcIm1hc3RyYTpnZW5pZTpjb252ZXJzYXRpb25cIjtcblxuLyoqXG4gKiBCdWlsZCB0aGUgcGVyLXJlcXVlc3Qge0BsaW5rIFJlcXVlc3RDb250ZXh0fSBrZXkgdGhlIGFjdGl2ZVxuICogR2VuaWUgYGNvbnZlcnNhdGlvbl9pZGAgbGl2ZXMgdW5kZXIgZm9yIGBzcGFjZUlkYC4gU2NvcGVkIGJ5XG4gKiBzcGFjZSBzbyBhbiBhcHAgY2FsbGluZyB0d28gR2VuaWUgc3BhY2VzIGluIG9uZSByZXF1ZXN0IGtlZXBzXG4gKiBlYWNoIGNvbnZlcnNhdGlvbiBkaXN0aW5jdCAoR2VuaWUgY29udmVyc2F0aW9uIGlkcyBhcmVcbiAqIHNwYWNlLXNjb3BlZCBvbiB0aGUgd2lyZSkuIFRoZSBzYW1lIGBSZXF1ZXN0Q29udGV4dGAgaW5zdGFuY2VcbiAqIGZsb3dzIGZyb20gdGhlIGNlbnRyYWwgYWdlbnQgdGhyb3VnaCB0byBldmVyeSBgYXNrX2dlbmllYFxuICogaW52b2NhdGlvbiwgc28gd3JpdGVzIG9uIG9uZSBjYWxsIGFyZSB2aXNpYmxlIG9uIHRoZSBuZXh0XG4gKiB3aXRob3V0IGFuIGV4cGxpY2l0IHNoYXJlZCByZWYuXG4gKi9cbmNvbnN0IGNvbnZlcnNhdGlvbkNvbnRleHRLZXkgPSAoc3BhY2VJZDogc3RyaW5nKTogc3RyaW5nID0+XG4gIGBtYXN0cmFfX2dlbmllX2NvbnZlcnNhdGlvbl9fJHtzcGFjZUlkfWA7XG5cbi8qKlxuICogUmVhZCB0aGUgYWN0aXZlIEdlbmllIGBjb252ZXJzYXRpb25faWRgIGZvciBgc3BhY2VJZGAgb2ZmIHRoZVxuICogcGVyLXJlcXVlc3Qge0BsaW5rIFJlcXVlc3RDb250ZXh0fS4gUmV0dXJucyBgdW5kZWZpbmVkYCB3aGVuIG5vXG4gKiBjb252ZXJzYXRpb24gaGFzIGJlZW4gc3RhcnRlZCB5ZXQgdGhpcyByZXF1ZXN0LlxuICovXG5mdW5jdGlvbiByZWFkQ29udGV4dENvbnZlcnNhdGlvbklkKFxuICByZXF1ZXN0Q29udGV4dDogUmVxdWVzdENvbnRleHQsXG4gIHNwYWNlSWQ6IHN0cmluZyxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIHJldHVybiByZXF1ZXN0Q29udGV4dC5nZXQoY29udmVyc2F0aW9uQ29udGV4dEtleShzcGFjZUlkKSkgYXMgc3RyaW5nIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFdyaXRlIHRoZSBhY3RpdmUgR2VuaWUgYGNvbnZlcnNhdGlvbl9pZGAgZm9yIGBzcGFjZUlkYCBvbnRvIHRoZVxuICogcGVyLXJlcXVlc3Qge0BsaW5rIFJlcXVlc3RDb250ZXh0fS4gU3Vic2VxdWVudCBgYXNrX2dlbmllYCBjYWxsc1xuICogaW4gdGhpcyByZXF1ZXN0IHdpbGwgcmV1c2UgaXQuXG4gKi9cbmZ1bmN0aW9uIHdyaXRlQ29udGV4dENvbnZlcnNhdGlvbklkKFxuICByZXF1ZXN0Q29udGV4dDogUmVxdWVzdENvbnRleHQsXG4gIHNwYWNlSWQ6IHN0cmluZyxcbiAgY29udmVyc2F0aW9uSWQ6IHN0cmluZyB8IHVuZGVmaW5lZCxcbik6IHZvaWQge1xuICByZXF1ZXN0Q29udGV4dC5zZXQoY29udmVyc2F0aW9uQ29udGV4dEtleShzcGFjZUlkKSwgY29udmVyc2F0aW9uSWQpO1xufVxuXG4vKipcbiAqIEJ1aWxkIHRoZSBjYW5vbmljYWwgY2FjaGUga2V5IGZvciBhIGAoc3BhY2VJZCwgdGhyZWFkSWQpYCBwYWlyLCBvd25lZCBieVxuICogYHVzZXJLZXlgLiBSZXR1cm5zIGB1bmRlZmluZWRgIHdoZW4gYHRocmVhZElkYCBpcyBtaXNzaW5nIC0gY2FsbGVycyBzaG91bGRcbiAqIHNraXAgY2FjaGluZyBlbnRpcmVseSBpbiB0aGF0IGNhc2UgKG5vIE1hc3RyYSBtZW1vcnkgd2lyZWQgdXApLlxuICpcbiAqIFRoZSBpZGVudGl0eSBpcyBwYXJ0IG9mIHRoZSBrZXkgYmVjYXVzZSBhIGNsaWVudCBwaWNrcyBpdHMgb3duIGB0aHJlYWRJZGBcbiAqICh0aGUgdGhyZWFkLXNlbGVjdGlvbiBoZWFkZXIgLyBgP3RocmVhZElkPWApLCBzbyB0aGUgaWQgYWxvbmUgZG9lcyBub3RcbiAqIGVzdGFibGlzaCB3aG8gb3ducyB0aGUgR2VuaWUgY29udmVyc2F0aW9uIGJlaGluZCBpdC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gY29udmVyc2F0aW9uQ2FjaGVLZXkoXG4gIHNwYWNlSWQ6IHN0cmluZyxcbiAgdGhyZWFkSWQ6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgdXNlcktleTogc3RyaW5nLFxuKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgaWYgKCF0aHJlYWRJZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIChhd2FpdCBDYWNoZU1hbmFnZXIuZ2V0SW5zdGFuY2UoKSkuZ2VuZXJhdGVLZXkoXG4gICAgW0NPTlZFUlNBVElPTl9DQUNIRV9OQU1FU1BBQ0UsIHNwYWNlSWQsIHRocmVhZElkXSxcbiAgICB1c2VyS2V5LFxuICApO1xufVxuXG4vKipcbiAqIFJlYWQgdGhlIGNhY2hlZCBHZW5pZSBjb252ZXJzYXRpb24gaWQgZm9yIGAoc3BhY2VJZCwgdGhyZWFkSWQpYC5cbiAqIFJldHVybnMgYHVuZGVmaW5lZGAgb24gbWlzcywgb24gZXhwaXJ5LCBvciB3aGVuIHRoZSBjYWNoZSBsYXllclxuICogaXMgdW5oZWFsdGh5IC0gbmV2ZXIgdGhyb3dzLiBUaGUgVFRMIGlzIHJlbmV3ZWQgdmlhIHJlLWBzZXRgXG4gKiBhZnRlciBlYWNoIHN1Y2Nlc3NmdWwgdHVybiAoc2VlIHtAbGluayBzYXZlQ2FjaGVkQ29udmVyc2F0aW9uSWR9KS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVhZENhY2hlZENvbnZlcnNhdGlvbklkKGNhY2hlS2V5OiBzdHJpbmcgfCB1bmRlZmluZWQpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICBpZiAoIWNhY2hlS2V5KSByZXR1cm4gdW5kZWZpbmVkO1xuICB0cnkge1xuICAgIGNvbnN0IHYgPSBhd2FpdCBDYWNoZU1hbmFnZXIuZ2V0SW5zdGFuY2VTeW5jKCkuZ2V0PHN0cmluZz4oY2FjaGVLZXkpO1xuICAgIHJldHVybiB2ID8/IHVuZGVmaW5lZDtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLndhcm4oXCJjb252ZXJzYXRpb24tY2FjaGU6cmVhZC1lcnJvclwiLCB7XG4gICAgICBlcnJvcjogZXJyb3IuZXJyb3JNZXNzYWdlKGVyciksXG4gICAgfSk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIFBlcnNpc3QgdGhlIGFjdGl2ZSBjb252ZXJzYXRpb24gaWQgdW5kZXIgYGNhY2hlS2V5YCwgcmVmcmVzaGluZ1xuICogaXRzIFRUTC4gSWRlbXBvdGVudDsgbm8tb3Agd2hlbiBgY2FjaGVLZXlgIG9yIGBjb252ZXJzYXRpb25JZGBcbiAqIGlzIG1pc3NpbmcuIFJlLXNldHRpbmcgdGhlIHNhbWUga2V5IGFjdHMgYXMgYSBzbGlkaW5nIFRUTDogZXZlcnlcbiAqIHR1cm4gdGhhdCB1c2VzIHRoZSBjb252ZXJzYXRpb24gZXh0ZW5kcyB0aGUgd2luZG93IGJ5IGFub3RoZXJcbiAqIHtAbGluayBDT05WRVJTQVRJT05fVFRMX1NFQ30gc2Vjb25kcy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gc2F2ZUNhY2hlZENvbnZlcnNhdGlvbklkKFxuICBjYWNoZUtleTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICBjb252ZXJzYXRpb25JZDogc3RyaW5nIHwgdW5kZWZpbmVkLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmICghY2FjaGVLZXkgfHwgIWNvbnZlcnNhdGlvbklkKSByZXR1cm47XG4gIHRyeSB7XG4gICAgYXdhaXQgQ2FjaGVNYW5hZ2VyLmdldEluc3RhbmNlU3luYygpLnNldChjYWNoZUtleSwgY29udmVyc2F0aW9uSWQsIHtcbiAgICAgIHR0bDogQ09OVkVSU0FUSU9OX1RUTF9TRUMsXG4gICAgfSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci53YXJuKFwiY29udmVyc2F0aW9uLWNhY2hlOndyaXRlLWVycm9yXCIsIHtcbiAgICAgIGVycm9yOiBlcnJvci5lcnJvck1lc3NhZ2UoZXJyKSxcbiAgICB9KTtcbiAgfVxufVxuXG4vKiogRm9yY2UtZXZpY3QgYSBjYWNoZWQgY29udmVyc2F0aW9uIGlkLiBVc2VkIG9uIHRoZSBzdGFsZS1pZCByZWNvdmVyeSBwYXRoLiAqL1xuYXN5bmMgZnVuY3Rpb24gZXZpY3RDYWNoZWRDb252ZXJzYXRpb25JZChjYWNoZUtleTogc3RyaW5nIHwgdW5kZWZpbmVkKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmICghY2FjaGVLZXkpIHJldHVybjtcbiAgdHJ5IHtcbiAgICBhd2FpdCBDYWNoZU1hbmFnZXIuZ2V0SW5zdGFuY2VTeW5jKCkuZGVsZXRlKGNhY2hlS2V5KTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLndhcm4oXCJjb252ZXJzYXRpb24tY2FjaGU6ZGVsZXRlLWVycm9yXCIsIHtcbiAgICAgIGVycm9yOiBlcnJvci5lcnJvck1lc3NhZ2UoZXJyKSxcbiAgICB9KTtcbiAgfVxufVxuXG4vKipcbiAqIExhenktc2VlZCB0aGUgYWN0aXZlIEdlbmllIGBjb252ZXJzYXRpb25faWRgIGZvciBgc3BhY2VJZGAgZnJvbVxuICogdGhlIGNyb3NzLXJlcXVlc3QgY2FjaGUgb250byB0aGUgcGVyLXJlcXVlc3QgYFJlcXVlc3RDb250ZXh0YC5cbiAqIE5vLW9wIHdoZW4gdGhlIHNsb3QgaXMgYWxyZWFkeSBwb3B1bGF0ZWQgKHN1YnNlcXVlbnRcbiAqIGBhc2tfZ2VuaWVgIGNhbGxzIGluIHRoZSBzYW1lIHR1cm4pIHNvIHdlIGhpdCB0aGUgY2FjaGUgYXQgbW9zdFxuICogb25jZSBwZXIgcmVxdWVzdCBwZXIgc3BhY2UuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGVuc3VyZUNvbnZlcnNhdGlvblNlZWRlZChcbiAgcmVxdWVzdENvbnRleHQ6IFJlcXVlc3RDb250ZXh0LFxuICBzcGFjZUlkOiBzdHJpbmcsXG4gIGNhY2hlS2V5OiBzdHJpbmcgfCB1bmRlZmluZWQsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKHJlYWRDb250ZXh0Q29udmVyc2F0aW9uSWQocmVxdWVzdENvbnRleHQsIHNwYWNlSWQpKSByZXR1cm47XG4gIGNvbnN0IGNhY2hlZCA9IGF3YWl0IHJlYWRDYWNoZWRDb252ZXJzYXRpb25JZChjYWNoZUtleSk7XG4gIGlmIChjYWNoZWQpIHdyaXRlQ29udGV4dENvbnZlcnNhdGlvbklkKHJlcXVlc3RDb250ZXh0LCBzcGFjZUlkLCBjYWNoZWQpO1xufVxuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gcHJlcGFyZV9jaGFydCBpbnB1dCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqXG4gKiBBZ2VudC1mYWNpbmcgYHByZXBhcmVfY2hhcnRgIGlucHV0IHNjaGVtYS4gUmV1c2VzXG4gKiB7QGxpbmsgY2hhcnRQbGFubmVyUmVxdWVzdFNjaGVtYX0gKHRoZSBkYXRhc2V0LWRyaXZlbiBwbGFubmVyXG4gKiBjb250cmFjdCkgYnV0IHN3YXBzIHRoZSBpbmxpbmUgYGRhdGFgIGZpZWxkIGZvciBhIEdlbmllXG4gKiBgc3RhdGVtZW50X2lkYCB0aGUgdG9vbCByZXNvbHZlcyBpbnRvIHJvd3Mgc2VydmVyLXNpZGUuXG4gKiBgdGl0bGVgIGlzIGxvb3NlbmVkIHRvIG9wdGlvbmFsIC0gdGhlIHBsYW5uZXIgZmFsbHMgYmFjayB0byBhXG4gKiBnZW5lcmljIHBsYWNlaG9sZGVyIHdoZW4gdGhlIGFnZW50IGRvZXNuJ3Qgc3VwcGx5IG9uZS5cbiAqXG4gKiBTaGFwZWQgdG8gbWF0Y2ggR2VuaWUncyB3aXJlIGZvcm0gLSBgc3RhdGVtZW50X2lkYCAoc25ha2UpXG4gKiBtaXJyb3JzIGBxdWVyeV9yZXN1bHQuc3RhdGVtZW50X2lkYCBhbmQgdGhlIGBnZXRfc3RhdGVtZW50YFxuICogdG9vbCdzIGlucHV0IGZpZWxkIG5hbWUsIHNvIHRoZSBMTE0gb25seSBldmVyIHNlZXMgb25lXG4gKiBzcGVsbGluZyBmb3IgdGhlIHNhbWUgaWRlbnRpZmllci5cbiAqL1xuY29uc3QgcHJlcGFyZUNoYXJ0UmVxdWVzdFNjaGVtYSA9IGNoYXJ0UGxhbm5lclJlcXVlc3RTY2hlbWFcbiAgLm9taXQoeyBkYXRhOiB0cnVlLCB0aXRsZTogdHJ1ZSB9KVxuICAuZXh0ZW5kKHtcbiAgICBzdGF0ZW1lbnRfaWQ6IHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLm1pbigxLCBcInN0YXRlbWVudF9pZCBpcyByZXF1aXJlZFwiKVxuICAgICAgLmRlc2NyaWJlKFxuICAgICAgICBzdHJpbmcudG9EZXNjcmlwdGlvbihgXG4gICAgICAgICAgR2VuaWUgXFxgc3RhdGVtZW50X2lkXFxgIHRvIGNoYXJ0LiBSZWFkIGZyb21cbiAgICAgICAgICBcXGBtZXNzYWdlLnF1ZXJ5X3Jlc3VsdC5zdGF0ZW1lbnRfaWRcXGAgb3JcbiAgICAgICAgICBcXGBtZXNzYWdlLmF0dGFjaG1lbnRzWypdLnF1ZXJ5LnN0YXRlbWVudF9pZFxcYCByZXR1cm5lZCBieVxuICAgICAgICAgIFxcYGFza19nZW5pZVxcYC5cbiAgICAgICAgYCksXG4gICAgICApLFxuICAgIHRpdGxlOiBjaGFydFBsYW5uZXJSZXF1ZXN0U2NoZW1hLnNoYXBlLnRpdGxlLm9wdGlvbmFsKCksXG4gIH0pO1xuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSB0b29sIGlkcyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKipcbiAqIFN1ZmZpeCBhcHBlbmRlZCB0byBwZXItc3BhY2UgdG9vbCBpZHMgd2hlbiB0aGUgYWxpYXMgaXNuJ3QgdGhlXG4gKiB3ZWxsLWtub3duIGBkZWZhdWx0YC4gU2luZ2xlLXNwYWNlIGRlcGxveW1lbnRzIGdldCB0aGUgYmFyZVxuICogbmFtZXMgKGBhc2tfZ2VuaWVgLCBgZ2V0X3NwYWNlX2Rlc2NyaXB0aW9uYCwgLi4uKTsgbXVsdGktc3BhY2VcbiAqIGRlcGxveW1lbnRzIGdldCBgYXNrX2dlbmllXzxhbGlhcz5gIGV0Yy4gc28gZWFjaCBzcGFjZSdzIHRvb2xzXG4gKiBzdGF5IGRpc2FtYmlndWF0ZWQgaW4gdGhlIGNlbnRyYWwgYWdlbnQncyB0b29sIHJlZ2lzdHJ5LlxuICovXG5mdW5jdGlvbiBhbGlhc1N1ZmZpeChhbGlhczogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKGFsaWFzID09PSBERUZBVUxUX0dFTklFX0FMSUFTKSByZXR1cm4gXCJcIjtcbiAgY29uc3Qgc2x1ZyA9IHN0cmluZy50b0lkZW50aWZpZXIoYWxpYXMpO1xuICByZXR1cm4gc2x1ZyA/IGBfJHtzbHVnfWAgOiBcIlwiO1xufVxuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gcGVyLXNwYWNlIHRvb2xzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKipcbiAqIERyb3AgYHN1Z2dlc3RlZF9xdWVzdGlvbnNgIGF0dGFjaG1lbnRzIGZyb20gYSB7QGxpbmsgR2VuaWVNZXNzYWdlfVxuICogYmVmb3JlIGhhbmRpbmcgaXQgdG8gdGhlIGNlbnRyYWwgTExNLiBUaG9zZSBlbnRyaWVzIGFscmVhZHlcbiAqIHN1cmZhY2UgaW4gdGhlIFVJIGFzIG9uZS10YXAgcGlsbHMgdmlhIHRoZSB3cml0ZXInc1xuICogYHN1Z2dlc3RlZF9xdWVzdGlvbnNgIGV2ZW50cyAoc2VlIGBjb2xsZWN0U3VnZ2VzdGlvbnNgIG9uIHRoZVxuICogY2xpZW50KTsgaWYgd2UgbGV0IHRoZW0gcmlkZSBiYWNrIGluIHRoZSB0b29sIHJlc3VsdCB0aGUgTExNXG4gKiB0ZW5kcyB0byBxdW90ZSB0aGVtIGlubGluZSBpbiBpdHMgcHJvc2UsIGRvdWJsZS1zaG93aW5nIHRoZVxuICogc2FtZSBxdWVzdGlvbnMgYW5kIHN0ZXBwaW5nIG9uIHRoZSBkZWRpY2F0ZWQgc3VnZ2VzdGlvbiBVSS5cbiAqIFF1ZXJ5IC8gdGV4dCAvIHJvdyBhdHRhY2htZW50cyBhcmUgcHJlc2VydmVkIHNvIHRoZSBtb2RlbCBjYW5cbiAqIHN0aWxsIHJlYWQgYHN0YXRlbWVudF9pZGAsIFNRTCwgYW5kIHRoZSBhbnN3ZXIgdGV4dC5cbiAqL1xuZnVuY3Rpb24gc3RyaXBTdWdnZXN0ZWRRdWVzdGlvbnMobWVzc2FnZTogR2VuaWVNZXNzYWdlKTogR2VuaWVNZXNzYWdlIHtcbiAgY29uc3QgYXR0YWNobWVudHMgPSBtZXNzYWdlLmF0dGFjaG1lbnRzO1xuICBpZiAoIWF0dGFjaG1lbnRzIHx8IGF0dGFjaG1lbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG1lc3NhZ2U7XG4gIGNvbnN0IGZpbHRlcmVkID0gYXR0YWNobWVudHMuZmlsdGVyKChhdHQpID0+ICFhdHQuc3VnZ2VzdGVkX3F1ZXN0aW9ucyk7XG4gIGlmIChmaWx0ZXJlZC5sZW5ndGggPT09IGF0dGFjaG1lbnRzLmxlbmd0aCkgcmV0dXJuIG1lc3NhZ2U7XG4gIHJldHVybiB7IC4uLm1lc3NhZ2UsIGF0dGFjaG1lbnRzOiBmaWx0ZXJlZCB9O1xufVxuXG5mdW5jdGlvbiBidWlsZEFza0dlbmllVG9vbChvcHRzOiB7IHNwYWNlSWQ6IHN0cmluZzsgYWxpYXM6IHN0cmluZzsgaGludD86IHN0cmluZyB9KSB7XG4gIGNvbnN0IHsgc3BhY2VJZCwgYWxpYXMsIGhpbnQgfSA9IG9wdHM7XG4gIGNvbnN0IHRvb2xJZCA9IGBhc2tfZ2VuaWUke2FsaWFzU3VmZml4KGFsaWFzKX1gO1xuICBjb25zdCBoaW50TGluZSA9IGhpbnQgPyBgICgke2hpbnR9KWAgOiBcIlwiO1xuICByZXR1cm4gY3JlYXRlVG9vbCh7XG4gICAgaWQ6IHRvb2xJZCxcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nLnRvRGVzY3JpcHRpb24oYFxuICAgICAgQXNrIHRoZSBHZW5pZSBzcGFjZSBcIiR7YWxpYXN9XCIke2hpbnRMaW5lfSBPTkUgZm9jdXNlZFxuICAgICAgbmF0dXJhbC1sYW5ndWFnZSBzdWItcXVlc3Rpb24gYW5kIHdhaXQgZm9yIHRoZSB0dXJuIHRvXG4gICAgICBjb21wbGV0ZS4gR2VuaWUgYW5zd2VycyBiZXN0IHdoZW4gZWFjaCBjYWxsIGNvdmVycyBhXG4gICAgICBzaW5nbGUgbWV0cmljIC8gZGltZW5zaW9uIC8gdGltZSB3aW5kb3csIHNvIGV4cGVjdCB0b1xuICAgICAgY2FsbCB0aGlzIHRvb2wgTVVMVElQTEUgVElNRVMgcGVyIHVzZXIgdHVybiAodHlwaWNhbGx5XG4gICAgICB0d28gdG8gc2l4KSBhbmQgbGV0IHRoZSByZXN1bHRzIGZyb20gZWFybGllciBjYWxscyBpbmZvcm1cbiAgICAgIGxhdGVyIG9uZXMgLSB0aGF0J3MgdGhlIG5vcm1hbCBwYXR0ZXJuLCBub3QgdGhlIGV4Y2VwdGlvbi5cbiAgICAgIERvIE5PVCB0cnkgdG8gY3JhbSBhIG11bHRpLXBhcnQgcXVlc3Rpb24gaW50byBhIHNpbmdsZVxuICAgICAgY2FsbDsgZGVjb21wb3NlIGZpcnN0LCB0aGVuIGFzayBlYWNoIHBpZWNlLlxuXG4gICAgICBSZXR1cm5zIHRoZSBmaW5hbCBcXGBHZW5pZU1lc3NhZ2VcXGAuIFJvd3MgYXJlIE5PVCBpbmNsdWRlZCAtXG4gICAgICB0aGUgR2VuaWUgd2lyZSByZXNwb25zZSBjYXJyaWVzIHRoZSBcXGBzdGF0ZW1lbnRfaWRcXGAgZm9yIGFueVxuICAgICAgU1FMIHRoYXQgcmFuIChhdCBcXGBtZXNzYWdlLnF1ZXJ5X3Jlc3VsdC5zdGF0ZW1lbnRfaWRcXGAgb3IgdGhlXG4gICAgICBmaXJzdCBhdHRhY2htZW50J3MgXFxgcXVlcnkuc3RhdGVtZW50X2lkXFxgKTsgY2FsbFxuICAgICAgXFxgZ2V0X3N0YXRlbWVudFxcYCB3aXRoIHRoYXQgaWQgb25seSB3aGVuIHlvdSBuZWVkIHRvIHJlYWRcbiAgICAgIHRoZSB1bmRlcmx5aW5nIHZhbHVlcyB0byByZWFzb24gYWJvdXQgdGhlbS4gSWYgeW91IGp1c3RcbiAgICAgIHdhbnQgdG8gZGlzcGxheSB0aGUgcm93cyB0byB0aGUgdXNlciwgZW1iZWQgYVxuICAgICAgXFxgW2RhdGE6PHN0YXRlbWVudF9pZD5dXFxgIG1hcmtlciBpbiB5b3VyIHByb3NlIGluc3RlYWQgLVxuICAgICAgdGhlIGhvc3QgVUkgZmV0Y2hlcyBhbmQgcmVuZGVycyB0aGUgcm93cyBvbiBpdHMgb3duLiBXaXJlXG4gICAgICBldmVudHMgKHN0YXR1cywgdGhpbmtpbmcsIHNxbCkgc3RyZWFtIHRvIHRoZSB1c2VyXG4gICAgICBhdXRvbWF0aWNhbGx5IHdoaWxlIHRoZSBjYWxsIGlzIGluIGZsaWdodC5cbiAgICBgKSxcbiAgICBpbnB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgcXVlc3Rpb246IHpcbiAgICAgICAgLnN0cmluZygpXG4gICAgICAgIC5taW4oMSwgXCJxdWVzdGlvbiBpcyByZXF1aXJlZFwiKVxuICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgc3RyaW5nLnRvRGVzY3JpcHRpb24oYFxuICAgICAgICAgICAgT05FIGZvY3VzZWQgbmF0dXJhbC1sYW5ndWFnZSBxdWVzdGlvbiBhYm91dCB0aGUgZGF0YSBpbiB0aGlzXG4gICAgICAgICAgICBzcGFjZSwgY292ZXJpbmcgYSBzaW5nbGUgbWV0cmljIC8gZGltZW5zaW9uIC8gdGltZSB3aW5kb3dcbiAgICAgICAgICAgIChlLmcuIFwiV2hhdCB3YXMgUTMgcmV2ZW51ZSBieSByZWdpb24/XCIpLiBEZWNvbXBvc2UgYVxuICAgICAgICAgICAgbXVsdGktcGFydCBhc2sgaW50byBzZXBhcmF0ZSBjYWxscyByYXRoZXIgdGhhbiBjb21iaW5pbmcgaXRcbiAgICAgICAgICAgIGhlcmUuXG4gICAgICAgICAgYCksXG4gICAgICAgICksXG4gICAgfSksXG4gICAgb3V0cHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICBtZXNzYWdlOiBnZW5pZU1vZGVsLkdlbmllTWVzc2FnZVNjaGVtYSxcbiAgICB9KSxcbiAgICBleGVjdXRlOiBhc3luYyAoeyBxdWVzdGlvbiB9LCBjdHhSYXcpID0+IHtcbiAgICAgIGNvbnN0IGN0eCA9IGN0eFJhdyBhcyBUb29sRXhlY3V0ZUN0eDtcbiAgICAgIGNvbnN0IHsgY2xpZW50LCByZXF1ZXN0Q29udGV4dCB9ID0gcmVxdWlyZUNsaWVudChjdHgsIHRvb2xJZCk7XG4gICAgICBjb25zdCB3cml0ZXIgPSBjdHg/LndyaXRlcjtcbiAgICAgIGNvbnN0IHNpZ25hbCA9IGN0eD8uYWJvcnRTaWduYWw7XG4gICAgICBjb25zdCB0aHJlYWRJZCA9IHJlcXVlc3RDb250ZXh0LmdldChNQVNUUkFfVEhSRUFEX0lEX0tFWSkgYXMgc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gICAgICAvLyBCb3VuY2UgcGxhY2Vob2xkZXIgLyBuby1vcCBxdWVzdGlvbnMgQkVGT1JFIHNwZW5kaW5nIGEgR2VuaWVcbiAgICAgIC8vIHJvdW5kLXRyaXAgb24gdGhlbS4gR2VuaWUgYW5zd2VycyBhbnkgb2YgdGhlc2Ugd2l0aCBcIllvdXJcbiAgICAgIC8vIHJlcXVlc3QgJ25vb3AnIGRvZXMgbm90IHJlbGF0ZSB0by4uLlwiIC0gdXNlbGVzcyBub2lzZSB0aGF0XG4gICAgICAvLyBzaG93cyB1cCBpbiB0aGUgVUkgYW5kIGVhdHMgb25lIG9mIHRoZSB3b3Jrc3BhY2UncyA1XG4gICAgICAvLyBxdWVzdGlvbnMvbWludXRlLiBSZXR1cm5pbmcgYSBjbGVhciBlcnJvciBoZXJlIHN1cmZhY2VzIHRoZVxuICAgICAgLy8gaXNzdWUgdG8gdGhlIGFnZW50IGxvb3Agc28gdGhlIG1vZGVsIGNvcnJlY3RzIGNvdXJzZSBpbnN0ZWFkXG4gICAgICAvLyBvZiB3YXN0aW5nIGEgdHVybi5cbiAgICAgIGNvbnN0IHRyaW1tZWQgPSBxdWVzdGlvbi50cmltKCk7XG4gICAgICBpZiAodHJpbW1lZC5sZW5ndGggPT09IDAgfHwgUExBQ0VIT0xERVJfUVVFU1RJT05TLmhhcyh0cmltbWVkLnRvTG93ZXJDYXNlKCkpKSB7XG4gICAgICAgIHRocm93IFZhbGlkYXRpb25FcnJvci5pbnZhbGlkVmFsdWUoXG4gICAgICAgICAgYCR7dG9vbElkfS5xdWVzdGlvbmAsXG4gICAgICAgICAgcXVlc3Rpb24sXG4gICAgICAgICAgXCJhIHJlYWwgbmF0dXJhbC1sYW5ndWFnZSBxdWVzdGlvbiwgbm90IGEgcGxhY2Vob2xkZXI7IHNraXAgdGhlIGNhbGwgaW5zdGVhZFwiLFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBTZWVkIHRoZSBhY3RpdmUgR2VuaWUgYGNvbnZlcnNhdGlvbl9pZGAgb250byBgUmVxdWVzdENvbnRleHRgXG4gICAgICAvLyBmcm9tIHRoZSBjcm9zcy1yZXF1ZXN0IGNhY2hlIHdoZW4gYSBNYXN0cmEgYHRocmVhZElkYCBpc1xuICAgICAgLy8gcHJlc2VudCBzbyBtdWx0aS10dXJuIGNoYXRzIHJldXNlIHRoZSBzYW1lIEdlbmllIGNvbnZlcnNhdGlvblxuICAgICAgLy8gKGFuZCBHZW5pZSdzIGFjY3VtdWxhdGVkIGNvbnRleHQpIGFjcm9zcyBzZXBhcmF0ZSB1c2VyIHR1cm5zLlxuICAgICAgLy8gVGhlIHNhbWUgYFJlcXVlc3RDb250ZXh0YCBpcyByZXVzZWQgYWNyb3NzIGV2ZXJ5IGBhc2tfZ2VuaWVgXG4gICAgICAvLyBjYWxsIHdpdGhpbiBvbmUgdXNlciB0dXJuLCBzbyBgZW5zdXJlQ29udmVyc2F0aW9uU2VlZGVkYFxuICAgICAgLy8gaGl0cyB0aGUgY2FjaGUgYXQgbW9zdCBvbmNlIHBlciByZXF1ZXN0IHBlciBzcGFjZS5cbiAgICAgIGNvbnN0IGNhY2hlS2V5ID0gYXdhaXQgY29udmVyc2F0aW9uQ2FjaGVLZXkoXG4gICAgICAgIHNwYWNlSWQsXG4gICAgICAgIHRocmVhZElkLFxuICAgICAgICByZXNvbHZlVXNlcktleShyZXF1ZXN0Q29udGV4dCksXG4gICAgICApO1xuICAgICAgYXdhaXQgZW5zdXJlQ29udmVyc2F0aW9uU2VlZGVkKHJlcXVlc3RDb250ZXh0LCBzcGFjZUlkLCBjYWNoZUtleSk7XG5cbiAgICAgIC8vIEZpcmUgdGhlIGxpZmVjeWNsZSBgc3RhcnRlZGAgZXZlbnQgYmVmb3JlIGFueSBMTE0gL1xuICAgICAgLy8gbmV0d29yayByb3VuZC10cmlwIHNvIHRoZSBob3N0IFVJIGNhbiBwb3AgYSBcIlRoaW5raW5nLi4uXCJcbiAgICAgIC8vIHBpbGwgdGhlIGluc3RhbnQgdGhlIG1vZGVsIGRlY2lkZXMgdG8gZGVsZWdhdGUuXG4gICAgICBjb25zdCBzdGFydGVkRXZlbnQ6IFN0YXJ0ZWRFdmVudCA9IHtcbiAgICAgICAgdHlwZTogXCJzdGFydGVkXCIsXG4gICAgICAgIHNwYWNlSWQsXG4gICAgICAgIGNvbnRlbnQ6IHF1ZXN0aW9uLFxuICAgICAgfTtcbiAgICAgIGF3YWl0IHNhZmVXcml0ZShsb2dnZXIsIHdyaXRlciwgc3RhcnRlZEV2ZW50KTtcblxuICAgICAgLy8gU2luZ2xlIHR1cm4gb2YgYGdlbmllRXZlbnRDaGF0YC4gSG9pc3RlZCBpbnRvIGEgY2xvc3VyZSBzb1xuICAgICAgLy8gd2UgY2FuIHJlLXJ1biBpdCBhZnRlciBldmljdGluZyBhIHN0YWxlIGBjb252ZXJzYXRpb25faWRgXG4gICAgICAvLyB3aXRob3V0IGR1cGxpY2F0aW5nIHRoZSBldmVudC1sb29wIGJvZHkuXG4gICAgICBjb25zdCBydW5UdXJuID0gYXN5bmMgKCk6IFByb21pc2U8R2VuaWVNZXNzYWdlPiA9PiB7XG4gICAgICAgIGNvbnN0IHNlZWRDb252ZXJzYXRpb25JZCA9IHJlYWRDb250ZXh0Q29udmVyc2F0aW9uSWQocmVxdWVzdENvbnRleHQsIHNwYWNlSWQpO1xuICAgICAgICBsZXQgZmluYWxNZXNzYWdlOiBHZW5pZU1lc3NhZ2UgfCB1bmRlZmluZWQ7XG4gICAgICAgIGZvciBhd2FpdCAoY29uc3QgZXZlbnQgb2YgY2hhdC5nZW5pZUV2ZW50Q2hhdChzcGFjZUlkLCBxdWVzdGlvbiwge1xuICAgICAgICAgIHdvcmtzcGFjZUNsaWVudDogY2xpZW50LFxuICAgICAgICAgIC4uLihzZWVkQ29udmVyc2F0aW9uSWQgPyB7IGNvbnZlcnNhdGlvbklkOiBzZWVkQ29udmVyc2F0aW9uSWQgfSA6IHt9KSxcbiAgICAgICAgICAuLi4oc2lnbmFsID8geyBjb250ZXh0OiBzaWduYWwgfSA6IHt9KSxcbiAgICAgICAgfSkpIHtcbiAgICAgICAgICBpZiAoZXZlbnQudHlwZSAhPT0gXCJtZXNzYWdlXCIpIHtcbiAgICAgICAgICAgIGF3YWl0IHNhZmVXcml0ZShsb2dnZXIsIHdyaXRlciwgZXZlbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBldmVudENvbnZlcnNhdGlvbklkID0gZXZlbnQuY29udmVyc2F0aW9uX2lkO1xuICAgICAgICAgIGlmIChldmVudENvbnZlcnNhdGlvbklkKSB7XG4gICAgICAgICAgICB3cml0ZUNvbnRleHRDb252ZXJzYXRpb25JZChyZXF1ZXN0Q29udGV4dCwgc3BhY2VJZCwgZXZlbnRDb252ZXJzYXRpb25JZCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChldmVudC50eXBlID09PSBcInJlc3VsdFwiKSB7XG4gICAgICAgICAgICBmaW5hbE1lc3NhZ2UgPSBldmVudC5tZXNzYWdlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoIWZpbmFsTWVzc2FnZSkge1xuICAgICAgICAgIHRocm93IEV4ZWN1dGlvbkVycm9yLm1pc3NpbmdEYXRhKFwiR2VuaWUgcmVzdWx0IGV2ZW50XCIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmaW5hbE1lc3NhZ2U7XG4gICAgICB9O1xuXG4gICAgICBsZXQgZmluYWxNZXNzYWdlOiBHZW5pZU1lc3NhZ2U7XG4gICAgICB0cnkge1xuICAgICAgICBmaW5hbE1lc3NhZ2UgPSBhd2FpdCBydW5UdXJuKCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgLy8gVGhlIHNlZWRlZCBgY29udmVyc2F0aW9uX2lkYCB3YXMgcmVqZWN0ZWQgYnkgR2VuaWUgLSBtb3N0XG4gICAgICAgIC8vIGNvbW1vbmx5IGJlY2F1c2UgaXQgd2FzIGRlbGV0ZWQgdXBzdHJlYW0sIGV4cGlyZWQgcGFzdFxuICAgICAgICAvLyBEYXRhYnJpY2tzJyAodW5kb2N1bWVudGVkKSBsaWZldGltZSwgb3Igd2FzIG1pbnRlZCBpbiBhXG4gICAgICAgIC8vIGRpZmZlcmVudCBzcGFjZS4gRHJvcCBib3RoIHRoZSBjYWNoZWQgaWQgQU5EIHRoZVxuICAgICAgICAvLyBwZXItcmVxdWVzdCB2YWx1ZSBzbyB0aGUgcmV0cnkgY2FsbHMgYHN0YXJ0Q29udmVyc2F0aW9uYCxcbiAgICAgICAgLy8gYW5kIHRyeSBvbmNlIG1vcmUuIE9ubHkgcmV0cnkgd2hlbiB3ZSAqaGFkKiBhIHNlZWRlZCBpZCAtXG4gICAgICAgIC8vIGEgZnJlc2ggY2FsbCB0aGF0IDQwNHMgc2hvdWxkbid0IGxvb3AuXG4gICAgICAgIGNvbnN0IHNlZWRlZCA9IHJlYWRDb250ZXh0Q29udmVyc2F0aW9uSWQocmVxdWVzdENvbnRleHQsIHNwYWNlSWQpO1xuICAgICAgICBpZiAoc2VlZGVkICYmIGVycm9yLmVycm9yQ29udGV4dChlcnIpLm5vdEFjY2Vzc2libGUpIHtcbiAgICAgICAgICBsb2dnZXIud2FybihcImNvbnZlcnNhdGlvbi1jYWNoZTpzdGFsZSwgcmVzZXR0aW5nXCIsIHtcbiAgICAgICAgICAgIHNwYWNlSWQsXG4gICAgICAgICAgICBjb252ZXJzYXRpb25JZDogc2VlZGVkLFxuICAgICAgICAgICAgZXJyb3I6IGVycm9yLmVycm9yTWVzc2FnZShlcnIpLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGF3YWl0IGV2aWN0Q2FjaGVkQ29udmVyc2F0aW9uSWQoY2FjaGVLZXkpO1xuICAgICAgICAgIHdyaXRlQ29udGV4dENvbnZlcnNhdGlvbklkKHJlcXVlc3RDb250ZXh0LCBzcGFjZUlkLCB1bmRlZmluZWQpO1xuICAgICAgICAgIGZpbmFsTWVzc2FnZSA9IGF3YWl0IHJ1blR1cm4oKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gUmVmcmVzaCB0aGUgY2FjaGUgZW50cnkgb24gZXZlcnkgc3VjY2Vzc2Z1bCB0dXJuLiBSZS1zZXR0aW5nXG4gICAgICAvLyB0aGUgc2FtZSBrZXkgYm90aCBwZXJzaXN0cyBuZXdseS1taW50ZWQgaWRzIChjYWNoZSBtaXNzIHBhdGgpXG4gICAgICAvLyBhbmQgZXh0ZW5kcyB0aGUgVFRMIG9uIGFjdGl2ZSBjb252ZXJzYXRpb25zIChzbGlkaW5nIHdpbmRvdykuXG4gICAgICBhd2FpdCBzYXZlQ2FjaGVkQ29udmVyc2F0aW9uSWQoY2FjaGVLZXksIHJlYWRDb250ZXh0Q29udmVyc2F0aW9uSWQocmVxdWVzdENvbnRleHQsIHNwYWNlSWQpKTtcblxuICAgICAgcmV0dXJuIHsgbWVzc2FnZTogc3RyaXBTdWdnZXN0ZWRRdWVzdGlvbnMoZmluYWxNZXNzYWdlKSB9O1xuICAgIH0sXG4gIH0pO1xufVxuXG5mdW5jdGlvbiBidWlsZFNwYWNlRGVzY3JpcHRpb25Ub29sKG9wdHM6IHsgc3BhY2VJZDogc3RyaW5nOyBhbGlhczogc3RyaW5nIH0pIHtcbiAgY29uc3QgeyBzcGFjZUlkLCBhbGlhcyB9ID0gb3B0cztcbiAgY29uc3QgdG9vbElkID0gYGdldF9zcGFjZV9kZXNjcmlwdGlvbiR7YWxpYXNTdWZmaXgoYWxpYXMpfWA7XG4gIHJldHVybiBjcmVhdGVUb29sKHtcbiAgICBpZDogdG9vbElkLFxuICAgIGRlc2NyaXB0aW9uOiBzdHJpbmcudG9EZXNjcmlwdGlvbihgXG4gICAgICBSZXR1cm4gdGhlIEdlbmllIHNwYWNlIFwiJHthbGlhc31cIidzIHRpdGxlLCBkZXNjcmlwdGlvbiwgYW5kXG4gICAgICB3YXJlaG91c2UgaWQuIENoZWFwIChzaW5nbGUgUkVTVCBjYWxsLCBubyBMTE0gcm91bmQtdHJpcCkuXG4gICAgICBDYWxsIHRoaXMgRklSU1Qgb24gYW55IHVzZXIgdHVybiB0aGF0J3MgZ29pbmcgdG8gdG91Y2hcbiAgICAgIFxcYGFza19nZW5pZVxcYCwgdW5sZXNzIHRoZSBzYW1lIGRlc2NyaXB0aW9uIGFscmVhZHkgbGFuZGVkXG4gICAgICBlYXJsaWVyIGluIHRoaXMgY29udmVyc2F0aW9uIC0gdGhlIHRpdGxlICsgZGVzY3JpcHRpb24gdGVsbFxuICAgICAgeW91IHdoYXQgdGFibGVzLCBtZXRyaWNzLCBhbmQgdGltZSB3aW5kb3dzIHRoZSBzcGFjZVxuICAgICAgYWN0dWFsbHkgY292ZXJzLCB3aGljaCBpcyB3aGF0IGxldHMgeW91IGRlY29tcG9zZSB0aGVcbiAgICAgIHVzZXIncyBxdWVzdGlvbiBpbnRvIHRoZSByaWdodCBcXGBhc2tfZ2VuaWVcXGAgc3ViLXF1ZXN0aW9ucy5cbiAgICBgKSxcbiAgICBpbnB1dFNjaGVtYTogei5vYmplY3Qoe30pLFxuICAgIG91dHB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgc3BhY2VJZDogei5zdHJpbmcoKSxcbiAgICAgIHRpdGxlOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXG4gICAgICBkZXNjcmlwdGlvbjogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICAgICAgd2FyZWhvdXNlSWQ6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgICB9KSxcbiAgICBleGVjdXRlOiBhc3luYyAoX2lucHV0LCBjdHhSYXcpID0+IHtcbiAgICAgIGNvbnN0IGN0eCA9IGN0eFJhdyBhcyBUb29sRXhlY3V0ZUN0eDtcbiAgICAgIGNvbnN0IHsgY2xpZW50IH0gPSByZXF1aXJlQ2xpZW50KGN0eCwgdG9vbElkKTtcbiAgICAgIGNvbnN0IHNpZ25hbCA9IGN0eD8uYWJvcnRTaWduYWw7XG4gICAgICAvLyBSb3V0ZSB0aHJvdWdoIHRoZSBwYWNrYWdlJ3MgY2VudHJhbCBHZW5pZSBzcGFjZSBmZXRjaC4gVGhlXG4gICAgICAvLyBkZXNjcmlwdGlvbiBzdXJmYWNlICh0aXRsZSAvIGRlc2NyaXB0aW9uIC8gd2FyZWhvdXNlIGlkKSBsaXZlc1xuICAgICAgLy8gb24gdGhlIGRpcmVjdG9yeS1saXN0aW5nIHNoYXBlLCBzbyBza2lwIHRoZSBsYXJnZXJcbiAgICAgIC8vIGBzZXJpYWxpemVkX3NwYWNlYCBwYXlsb2FkIGhlcmUuXG4gICAgICBjb25zdCBzcGFjZSA9IGF3YWl0IGdlbmllU3BhY2UuZ2V0R2VuaWVTcGFjZShzcGFjZUlkLCB7XG4gICAgICAgIHdvcmtzcGFjZUNsaWVudDogY2xpZW50LFxuICAgICAgICBzZXJpYWxpemVkOiBmYWxzZSxcbiAgICAgICAgLi4uKHNpZ25hbCA/IHsgY29udGV4dDogc2lnbmFsIH0gOiB7fSksXG4gICAgICB9KTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHNwYWNlSWQsXG4gICAgICAgIC4uLihzcGFjZS50aXRsZSA/IHsgdGl0bGU6IHNwYWNlLnRpdGxlIH0gOiB7fSksXG4gICAgICAgIC4uLihzcGFjZS5kZXNjcmlwdGlvbiA/IHsgZGVzY3JpcHRpb246IHNwYWNlLmRlc2NyaXB0aW9uIH0gOiB7fSksXG4gICAgICAgIC4uLihzcGFjZS53YXJlaG91c2VfaWQgPyB7IHdhcmVob3VzZUlkOiBzcGFjZS53YXJlaG91c2VfaWQgfSA6IHt9KSxcbiAgICAgIH07XG4gICAgfSxcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGJ1aWxkU3BhY2VTZXJpYWxpemVkVG9vbChvcHRzOiB7IHNwYWNlSWQ6IHN0cmluZzsgYWxpYXM6IHN0cmluZyB9KSB7XG4gIGNvbnN0IHsgc3BhY2VJZCwgYWxpYXMgfSA9IG9wdHM7XG4gIGNvbnN0IHRvb2xJZCA9IGBnZXRfc3BhY2Vfc2VyaWFsaXplZCR7YWxpYXNTdWZmaXgoYWxpYXMpfWA7XG4gIHJldHVybiBjcmVhdGVUb29sKHtcbiAgICBpZDogdG9vbElkLFxuICAgIGRlc2NyaXB0aW9uOiBzdHJpbmcudG9EZXNjcmlwdGlvbihgXG4gICAgICBSZXR1cm4gdGhlIGZ1bGwgXFxgR2VuaWVTcGFjZVxcYCBKU09OIGZvciB0aGUgXCIke2FsaWFzfVwiIHNwYWNlLlxuICAgICAgVXNlIG9ubHkgd2hlbiB5b3UgbmVlZCBleGFjdCBjb2x1bW4gLyB0YWJsZSBpZGVudGlmaWVyc1xuICAgICAgXFxgZ2V0X3NwYWNlX2Rlc2NyaXB0aW9uXFxgIGRvZXNuJ3QgZXhwb3NlLiBMYXJnZXIgcGF5bG9hZCwgc29cbiAgICAgIHByZWZlciB0aGUgZGVzY3JpcHRpb24gdG9vbCB3aGVuIGl0J3MgZW5vdWdoLlxuICAgIGApLFxuICAgIGlucHV0U2NoZW1hOiB6Lm9iamVjdCh7fSksXG4gICAgb3V0cHV0U2NoZW1hOiB6Lm9iamVjdCh7IHNwYWNlOiB6LnVua25vd24oKSB9KSxcbiAgICBleGVjdXRlOiBhc3luYyAoX2lucHV0LCBjdHhSYXcpID0+IHtcbiAgICAgIGNvbnN0IGN0eCA9IGN0eFJhdyBhcyBUb29sRXhlY3V0ZUN0eDtcbiAgICAgIGNvbnN0IHsgY2xpZW50IH0gPSByZXF1aXJlQ2xpZW50KGN0eCwgdG9vbElkKTtcbiAgICAgIGNvbnN0IHNpZ25hbCA9IGN0eD8uYWJvcnRTaWduYWw7XG4gICAgICAvLyBDZW50cmFsIEdlbmllIHNwYWNlIGZldGNoIHdpdGggdGhlIG9wdC1pbiBgc2VyaWFsaXplZF9zcGFjZWBcbiAgICAgIC8vIGJsb2IgKGNhdGFsb2dzLCB0YWJsZXMsIHNhbXBsZSBxdWVzdGlvbnMsIHByb21wdHMpIHRoYXQgdGhlXG4gICAgICAvLyB0eXBlZCBTREsgYGdldFNwYWNlYCBvbWl0cyAtIHRoZSB3aG9sZSBwb2ludCBvZiB0aGlzIHRvb2wuXG4gICAgICBjb25zdCBzcGFjZSA9IGF3YWl0IGdlbmllU3BhY2UuZ2V0R2VuaWVTcGFjZShzcGFjZUlkLCB7XG4gICAgICAgIHdvcmtzcGFjZUNsaWVudDogY2xpZW50LFxuICAgICAgICAuLi4oc2lnbmFsID8geyBjb250ZXh0OiBzaWduYWwgfSA6IHt9KSxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHsgc3BhY2UgfTtcbiAgICB9LFxuICB9KTtcbn1cblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHNoYXJlZCB0b29scyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqXG4gKiBEZWZhdWx0IHJvdyBjYXAgZm9yIHtAbGluayBidWlsZEdldFN0YXRlbWVudFRvb2x9IHdoZW4gdGhlIGFnZW50XG4gKiBkb2Vzbid0IHN1cHBseSBhIGBsaW1pdGAuIFNpemVkIHRvIGtlZXAgcmVzdWx0IHNldHMgb3V0IG9mIHRoZVxuICogbW9kZWwgY29udGV4dCB1bmxlc3MgdGhlIGFnZW50IGV4cGxpY2l0bHkgb3B0cyBpbnRvIG1vcmUgcm93cyAtXG4gKiB0aGUgY2hlYXAgc2hhcGUgKGNvbHVtbiBuYW1lcyArIGEgaGFuZGZ1bCBvZiByZXByZXNlbnRhdGl2ZVxuICogcm93cykgaXMgdXN1YWxseSBlbm91Z2ggdG8gcmVhc29uIGFib3V0IGEgcXVlcnkuXG4gKi9cbmNvbnN0IERFRkFVTFRfU1RBVEVNRU5UX0xJTUlUID0gNTA7XG5cbmZ1bmN0aW9uIGJ1aWxkR2V0U3RhdGVtZW50VG9vbCgpIHtcbiAgY29uc3QgdG9vbElkID0gXCJnZXRfc3RhdGVtZW50XCI7XG4gIHJldHVybiBjcmVhdGVUb29sKHtcbiAgICBpZDogdG9vbElkLFxuICAgIGRlc2NyaXB0aW9uOiBzdHJpbmcudG9EZXNjcmlwdGlvbihgXG4gICAgICBGZXRjaCB0aGUgcm93cyBvZiBhIEdlbmllIHN0YXRlbWVudCBieSBpdHMgXFxgc3RhdGVtZW50X2lkXFxgICh0aGVcbiAgICAgIHZhbHVlIGF0IFxcYG1lc3NhZ2UucXVlcnlfcmVzdWx0LnN0YXRlbWVudF9pZFxcYCBvclxuICAgICAgXFxgbWVzc2FnZS5hdHRhY2htZW50c1sqXS5xdWVyeS5zdGF0ZW1lbnRfaWRcXGAgcmV0dXJuZWQgZnJvbVxuICAgICAgXFxgYXNrX2dlbmllXFxgKS4gVXNlIHRoaXMgT05MWSB3aGVuIHlvdSBuZWVkIHRvIHJlYWQgdGhlIHVuZGVybHlpbmdcbiAgICAgIHZhbHVlcyB0byByZWFzb24gYWJvdXQgdGhlbSBpbiB5b3VyIHJlcGx5IC0gZS5nLiBuYW1pbmcgdGhlXG4gICAgICBsYXJnZXN0IHJvdywgY29tcHV0aW5nIGEgZGVsdGEgdGhlIHZpc3VhbGl6YXRpb24gd291bGRuJ3QgYWxyZWFkeVxuICAgICAgY29udmV5LCBvciBmaWx0ZXJpbmcgZG93biB0byBhIHNwZWNpZmljIHJlY29yZC4gSWYgeW91J2QganVzdCBiZVxuICAgICAgcmVjaXRpbmcgbnVtYmVycyB0aGUgdXNlciB3aWxsIHNlZSBhbnl3YXksIHNraXAgdGhlIGNhbGwgYW5kXG4gICAgICBlbWJlZCBhIFxcYFtkYXRhOjxzdGF0ZW1lbnRfaWQ+XVxcYCBtYXJrZXIgaW4geW91ciBwcm9zZSBpbnN0ZWFkO1xuICAgICAgdGhlIGhvc3QgVUkgZmV0Y2hlcyBhbmQgcmVuZGVycyB0aGUgcm93cyBvbiBpdHMgb3duLiBcXGBsaW1pdFxcYFxuICAgICAgY2FwcyB0aGUgbnVtYmVyIG9mIHJvd3MgcmV0dXJuZWQgKGRlZmF1bHRzIHRvXG4gICAgICAke0RFRkFVTFRfU1RBVEVNRU5UX0xJTUlUfSkuIFxcYHJvd0NvdW50XFxgIHJlZmxlY3RzIHRoZSBmdWxsXG4gICAgICB1cHN0cmVhbSB0b3RhbCAtIGNvbXBhcmUgdG8gXFxgcm93cy5sZW5ndGhcXGAgdG8gZGV0ZWN0IHRydW5jYXRpb24uXG4gICAgYCksXG4gICAgaW5wdXRTY2hlbWE6IHoub2JqZWN0KHtcbiAgICAgIHN0YXRlbWVudF9pZDogelxuICAgICAgICAuc3RyaW5nKClcbiAgICAgICAgLm1pbigxLCBcInN0YXRlbWVudF9pZCBpcyByZXF1aXJlZFwiKVxuICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgc3RyaW5nLnRvRGVzY3JpcHRpb24oYFxuICAgICAgICAgICAgR2VuaWUgXFxgc3RhdGVtZW50X2lkXFxgIHdob3NlIHJvd3MgdG8gcmVhZC4gVGFrZSBpdCBmcm9tXG4gICAgICAgICAgICBcXGBtZXNzYWdlLnF1ZXJ5X3Jlc3VsdC5zdGF0ZW1lbnRfaWRcXGAgb3JcbiAgICAgICAgICAgIFxcYG1lc3NhZ2UuYXR0YWNobWVudHNbKl0ucXVlcnkuc3RhdGVtZW50X2lkXFxgIG9uIGFuXG4gICAgICAgICAgICBcXGBhc2tfZ2VuaWVcXGAgcmVzdWx0OyBpdCBpcyBuZXZlciBhIHZhbHVlIHlvdSBjb25zdHJ1Y3QuXG4gICAgICAgICAgYCksXG4gICAgICAgICksXG4gICAgICBsaW1pdDogelxuICAgICAgICAubnVtYmVyKClcbiAgICAgICAgLmludCgpXG4gICAgICAgIC5ub25uZWdhdGl2ZSgpXG4gICAgICAgIC5vcHRpb25hbCgpXG4gICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICBcIk1heCByb3dzIHRvIHJldHVybi4gRGVmYXVsdHMgdG8gYSBzbWFsbCBzYW1wbGU7IHJhaXNlIG9ubHkgd2hlbiBtb3JlIHJvd3MgYXJlIGdlbnVpbmVseSBuZWVkZWQuXCIsXG4gICAgICAgICksXG4gICAgfSksXG4gICAgb3V0cHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICBjb2x1bW5zOiB6LmFycmF5KHouc3RyaW5nKCkpLFxuICAgICAgcm93czogei5hcnJheSh6LnJlY29yZCh6LnN0cmluZygpLCB6LnVua25vd24oKSkpLFxuICAgICAgcm93Q291bnQ6IHoubnVtYmVyKCksXG4gICAgICB0cnVuY2F0ZWQ6IHouYm9vbGVhbigpLFxuICAgIH0pLFxuICAgIGV4ZWN1dGU6IGFzeW5jICh7IHN0YXRlbWVudF9pZCwgbGltaXQgfSwgY3R4UmF3KSA9PiB7XG4gICAgICBjb25zdCBjdHggPSBjdHhSYXcgYXMgVG9vbEV4ZWN1dGVDdHg7XG4gICAgICBjb25zdCB7IGNsaWVudCB9ID0gcmVxdWlyZUNsaWVudChjdHgsIHRvb2xJZCk7XG4gICAgICBjb25zdCBzaWduYWwgPSBjdHg/LmFib3J0U2lnbmFsO1xuICAgICAgY29uc3QgZWZmZWN0aXZlTGltaXQgPSBsaW1pdCA/PyBERUZBVUxUX1NUQVRFTUVOVF9MSU1JVDtcbiAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBmZXRjaFN0YXRlbWVudERhdGEoY2xpZW50LCBzdGF0ZW1lbnRfaWQsIHtcbiAgICAgICAgbGltaXQ6IGVmZmVjdGl2ZUxpbWl0LFxuICAgICAgICAuLi4oc2lnbmFsID8geyBzaWduYWwgfSA6IHt9KSxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgY29sdW1uczogZGF0YS5jb2x1bW5zLFxuICAgICAgICByb3dzOiBkYXRhLnJvd3MsXG4gICAgICAgIHJvd0NvdW50OiBkYXRhLnJvd0NvdW50LFxuICAgICAgICB0cnVuY2F0ZWQ6IGRhdGEucm93cy5sZW5ndGggPCBkYXRhLnJvd0NvdW50LFxuICAgICAgfTtcbiAgICB9LFxuICB9KTtcbn1cblxuLyoqXG4gKiBgcHJlcGFyZV9jaGFydGAgTWFzdHJhIHRvb2wuIFRoaW4gd3JhcHBlciBvdmVyXG4gKiB7QGxpbmsgcHJlcGFyZUNoYXJ0fSB0aGF0IHJlc29sdmVzIHRoZSBkYXRhc2V0IGJ5IGZldGNoaW5nIHRoZVxuICogR2VuaWUgc3RhdGVtZW50J3Mgcm93cyBvbiBkZW1hbmQuIFRoZSB0b29sIG1pbnRzIGEgYGNoYXJ0SWRgXG4gKiBzeW5jaHJvbm91c2x5LCBjYWNoZXMgYW4gZW1wdHkgcGxhY2Vob2xkZXIsIGFuZCBraWNrcyBvZmYgdGhlXG4gKiBwbGFubmVyIGluIHRoZSBiYWNrZ3JvdW5kIHNvIHRoZSBhZ2VudCBsb29wIG5ldmVyIGJsb2Nrcy4gVGhlXG4gKiBob3N0IFVJIHJlc29sdmVzIGBbY2hhcnQ6PGNoYXJ0SWQ+XWAgbWFya2VycyBieSByZWFkaW5nIHRoZVxuICogY2FjaGVkIHtAbGluayBDaGFydH0gZW50cnkgKDFoIFRUTCkuXG4gKlxuICogU3BhY2UtYWdub3N0aWM6IGEgR2VuaWUgYHN0YXRlbWVudF9pZGAgaXMgd29ya3NwYWNlLXNjb3BlZCwgc29cbiAqIG9uZSBzaGFyZWQgYHByZXBhcmVfY2hhcnRgIHRvb2wgY292ZXJzIGV2ZXJ5IHdpcmVkIEdlbmllIHNwYWNlLlxuICpcbiAqIENhbmNlbGxhdGlvbjogZGVsaWJlcmF0ZWx5IGRvZXMgTk9UIGZvcndhcmQgdGhlIHBlci1jYWxsXG4gKiBgYWJvcnRTaWduYWxgIHRvIHtAbGluayBwcmVwYXJlQ2hhcnR9LiBUaGUgcGxhbm5lciB0YXNrIGlzXG4gKiBmaXJlLWFuZC1mb3JnZXQgYmFja2dyb3VuZCB3b3JrOyB0aGUgdG9vbCdzIG93biBgZXhlY3V0ZWBcbiAqIHJlc29sdmVzIHRoZSBtb21lbnQgdGhlIGBjaGFydElkYCBpcyBtaW50ZWQsIHNvIHRoZSBwZXItY2FsbFxuICogc2lnbmFsIGFib3J0cyB0aGUgc2Vjb25kIHRoZSB0b29sIHJldHVybnMuIFRoZSAxaCBjYWNoZSBUVExcbiAqIGNhcHMgYWJhbmRvbmVkIGVudHJpZXMuXG4gKi9cbmZ1bmN0aW9uIGJ1aWxkUHJlcGFyZUNoYXJ0VG9vbChvcHRzOiB7IGNvbmZpZzogTWFzdHJhUGx1Z2luQ29uZmlnIH0pIHtcbiAgY29uc3QgeyBjb25maWcgfSA9IG9wdHM7XG4gIGNvbnN0IHRvb2xJZCA9IFwicHJlcGFyZV9jaGFydFwiO1xuICByZXR1cm4gY3JlYXRlVG9vbCh7XG4gICAgaWQ6IHRvb2xJZCxcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nLnRvRGVzY3JpcHRpb24oW1xuICAgICAgYFxuICAgICAgICBRdWV1ZSBhIGNoYXJ0IGZvciB0aGUgcm93cyBvZiBhIEdlbmllIHN0YXRlbWVudC4gTWludHMgYVxuICAgICAgICBzaG9ydCBcXGBjaGFydElkXFxgIHN5bmNocm9ub3VzbHkgYW5kIGtpY2tzIG9mZiBhIEJBQ0tHUk9VTkRcbiAgICAgICAgdGFzayB0aGF0IGZldGNoZXMgdGhlIHN0YXRlbWVudCdzIHJvd3MsIHJ1bnMgdGhlXG4gICAgICAgIGNoYXJ0LXBsYW5uZXIgdG8gcGljayBhIGNoYXJ0IHR5cGUgYW5kIEVjaGFydHMgc3BlYywgYW5kXG4gICAgICAgIGNhY2hlcyB0aGUgcmVzdWx0IHVuZGVyIHRoZSBcXGBjaGFydElkXFxgIGZvciBvbmUgaG91ci4gVGhlXG4gICAgICAgIGhvc3QgVUkgZmV0Y2hlcyB0aGUgY2FjaGVkIGNoYXJ0IG9uIGl0cyBvd24gb25jZSBpdCBsYW5kcy5cbiAgICAgIGAsXG4gICAgICBgXG4gICAgICAgIFRvIGRpc3BsYXkgdGhlIGNoYXJ0IGluIHlvdXIgcmVwbHksIGVtYmVkXG4gICAgICAgIFxcYFtjaGFydDo8Y2hhcnRJZD5dXFxgIG9uIGl0cyBvd24gbGluZSBhdCB0aGUgcG9zaXRpb24geW91XG4gICAgICAgIHdhbnQgaXQgdG8gYXBwZWFyLCB1c2luZyB0aGUgRVhBQ1QgXFxgY2hhcnRJZFxcYCBzdHJpbmcgdGhpc1xuICAgICAgICBjYWxsIHJldHVybmVkLiBOZXZlciBjb25zdHJ1Y3QgYSBjaGFydCBpZCB5b3Vyc2VsZiAoaXQgaXNcbiAgICAgICAgbm90IHRoZSBcXGBzdGF0ZW1lbnRfaWRcXGAgb3IgYW55IHZhcmlhdGlvbiBvZiBpdCkgLSBvbmx5IGFcbiAgICAgICAgdmFsdWUgcmV0dXJuZWQgYnkgdGhpcyB0b29sIHJlc29sdmVzIHRvIGEgcmVhbCBjaGFydC4gVGhlXG4gICAgICAgIHRvb2wgcmV0dXJucyBpbW1lZGlhdGVseSAtIGRvIE5PVCB3YWl0IG9yIGNhbGwgaXQgYWdhaW4gdG9cbiAgICAgICAgXCJjaGVjayBwcm9ncmVzc1wiOyB0aGUgY2hhcnQgcmVzb2x2ZXMgYXN5bmNocm9ub3VzbHkgb24gdGhlXG4gICAgICAgIGhvc3QgVUkncyBzaWRlLlxuICAgICAgYCxcbiAgICAgIGBcbiAgICAgICAgVXNlIHRoaXMgb25seSB3aGVuIHRoZSBkYXRhIGhhcyBhIHN0b3J5IGEgY2hhcnQgY29udmV5c1xuICAgICAgICBiZXR0ZXIgdGhhbiBhIHRhYmxlICh0cmVuZHMsIHJhbmtpbmdzLCBkaXN0cmlidXRpb25zLFxuICAgICAgICBwYXJ0cy1vZi1hLXdob2xlKS4gRm9yIHJhdyByb3dzLCBlbWJlZFxuICAgICAgICBcXGBbZGF0YTo8c3RhdGVtZW50X2lkPl1cXGAgaW5zdGVhZCBhbmQgc2tpcCB0aGlzIHRvb2wuXG4gICAgICBgLFxuICAgIF0pLFxuICAgIGlucHV0U2NoZW1hOiBwcmVwYXJlQ2hhcnRSZXF1ZXN0U2NoZW1hLFxuICAgIG91dHB1dFNjaGVtYTogd2lyZS5DaGFydFNjaGVtYS5waWNrKHsgY2hhcnRJZDogdHJ1ZSB9KSxcbiAgICBleGVjdXRlOiBhc3luYyAocmVxdWVzdCwgY3R4UmF3KSA9PiB7XG4gICAgICBjb25zdCBjdHggPSBjdHhSYXcgYXMgVG9vbEV4ZWN1dGVDdHg7XG4gICAgICBjb25zdCB7IGNsaWVudCwgcmVxdWVzdENvbnRleHQgfSA9IHJlcXVpcmVDbGllbnQoY3R4LCB0b29sSWQpO1xuICAgICAgcmV0dXJuIHByZXBhcmVDaGFydCh7XG4gICAgICAgIGNvbmZpZyxcbiAgICAgICAgdXNlcktleTogcmVzb2x2ZVVzZXJLZXkocmVxdWVzdENvbnRleHQpLFxuICAgICAgICAuLi4ocmVxdWVzdC50aXRsZSA/IHsgdGl0bGU6IHJlcXVlc3QudGl0bGUgfSA6IHt9KSxcbiAgICAgICAgLi4uKHJlcXVlc3QuZGVzY3JpcHRpb24gPyB7IGRlc2NyaXB0aW9uOiByZXF1ZXN0LmRlc2NyaXB0aW9uIH0gOiB7fSksXG4gICAgICAgIHJlc29sdmVEYXRhOiAodGFza1NpZ25hbCkgPT5cbiAgICAgICAgICBmZXRjaFN0YXRlbWVudERhdGEoY2xpZW50LCByZXF1ZXN0LnN0YXRlbWVudF9pZCwge1xuICAgICAgICAgICAgLi4uKHRhc2tTaWduYWwgPyB7IHNpZ25hbDogdGFza1NpZ25hbCB9IDoge30pLFxuICAgICAgICAgIH0pLFxuICAgICAgICAuLi4oY3R4Py5yZXF1ZXN0Q29udGV4dCA/IHsgcmVxdWVzdENvbnRleHQ6IGN0eC5yZXF1ZXN0Q29udGV4dCB9IDoge30pLFxuICAgICAgfSk7XG4gICAgfSxcbiAgfSk7XG59XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBvcmNoZXN0cmF0aW9uIHByb21wdCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqXG4gKiBTdWdnZXN0ZWQgb3JjaGVzdHJhdGlvbiBwcm9tcHQgZm9yIHRoZSBjZW50cmFsIGFnZW50IHRoYXQgb3duc1xuICogdGhlIEdlbmllIHRvb2xzLiBDb21wb3NlIGludG8geW91ciBhZ2VudCdzIGBpbnN0cnVjdGlvbnNgIHRvXG4gKiBnZXQgdGhlIGNhbm9uaWNhbCBcImRlY29tcG9zZSBxdWVzdGlvbnMsIGFzayBHZW5pZSBmb2N1c2VkXG4gKiBzdWItcXVlc3Rpb25zLCBwbGFjZSBkYXRhIC8gY2hhcnQgbWFya2VycyBpbiBwcm9zZVwiIGJlaGF2aW9yOlxuICpcbiAqIGBgYHRzXG4gKiBjcmVhdGVBZ2VudCh7XG4gKiAgIGluc3RydWN0aW9uczogYCR7bXlBZ2VudEluc3RydWN0aW9uc31cXG5cXG4ke0dFTklFX0lOU1RSVUNUSU9OU31gLFxuICogICB0b29scyhwbHVnaW5zKSB7XG4gKiAgICAgcmV0dXJuIHsgLi4ucGx1Z2lucy5nZW5pZT8udG9vbGtpdCgpIH07XG4gKiAgIH0sXG4gKiB9KTtcbiAqIGBgYFxuICpcbiAqIFRoZSBwcm9tcHQgcmVmZXJlbmNlcyB0aGUgYmFyZSB0b29sIG5hbWVzIChgYXNrX2dlbmllYCxcbiAqIGBnZXRfc3BhY2VfZGVzY3JpcHRpb25gLCBgZ2V0X3NwYWNlX3NlcmlhbGl6ZWRgLFxuICogYGdldF9zdGF0ZW1lbnRgLCBgcHJlcGFyZV9jaGFydGApIHVzZWQgZm9yIHRoZSBzaW5nbGUtc3BhY2VcbiAqIGRlZmF1bHQgYWxpYXMuIE11bHRpLXNwYWNlIGRlcGxveW1lbnRzIHNob3VsZCB3cml0ZSB0aGVpciBvd25cbiAqIHZhcmlhbnQgdGhhdCBuYW1lcyB0aGUgc3VmZml4ZWQgcGVyLXNwYWNlIHRvb2xzXG4gKiAoZS5nLiBgYXNrX2dlbmllX3NhbGVzYCkuXG4gKi9cbmV4cG9ydCBjb25zdCBHRU5JRV9JTlNUUlVDVElPTlMgPSBzdHJpbmcudG9EZXNjcmlwdGlvbihbXG4gIFwiR2VuaWUgb3JjaGVzdHJhdGlvbi4gRm9yIGV2ZXJ5IHVzZXIgcXVlc3Rpb24gdGhhdCBuZWVkcyBTUUwtYmFja2VkIGRhdGE6XCIsXG4gIHtcbiAgICBudW1iZXJlZDogW1xuICAgICAgYFxuICAgICAgICBTdGFydCBieSBjYWxsaW5nIFxcYGdldF9zcGFjZV9kZXNjcmlwdGlvblxcYCB0byBncm91bmQgeW91cnNlbGZcbiAgICAgICAgaW4gd2hhdCB0aGUgc3BhY2UgY292ZXJzICh0YWJsZXMsIG1ldHJpY3MsIHRpbWUgd2luZG93cyksXG4gICAgICAgIHVubGVzcyB5b3UgYWxyZWFkeSBzYXcgdGhlIHNhbWUgZGVzY3JpcHRpb24gZWFybGllciBpbiB0aGlzXG4gICAgICAgIGNvbnZlcnNhdGlvbi4gUmVhY2ggZm9yIFxcYGdldF9zcGFjZV9zZXJpYWxpemVkXFxgIG9ubHkgd2hlbiB5b3VcbiAgICAgICAgbmVlZCBleGFjdCBjb2x1bW4gLyB0YWJsZSBpZGVudGlmaWVycyB0aGUgZGVzY3JpcHRpb24gZG9lc24ndFxuICAgICAgICBleHBvc2UgLSBpdCdzIGEgbXVjaCBsYXJnZXIgcGF5bG9hZC5cbiAgICAgIGAsXG4gICAgICBgXG4gICAgICAgIERlY29tcG9zZSB0aGUgdXNlcidzIHF1ZXN0aW9uIGludG8gZm9jdXNlZCBzdWItcXVlc3Rpb25zXG4gICAgICAgIEJFRk9SRSBhc2tpbmcgR2VuaWUgYW55dGhpbmcuIE9uZSBzdWItcXVlc3Rpb24gcGVyIGRpc3RpbmN0XG4gICAgICAgIG1ldHJpYywgZGltZW5zaW9uLCBvciB0aW1lIHdpbmRvdy4gVGhlbiBjYWxsIFxcYGFza19nZW5pZVxcYFxuICAgICAgICBvbmNlIHBlciBzdWItcXVlc3Rpb24gLSB1c3VhbGx5IHR3byB0byBzaXggY2FsbHMgcGVyIHR1cm4sXG4gICAgICAgIGFuZCBsZXQgZWFybGllciBhbnN3ZXJzIGluZm9ybSB3aGF0IHlvdSBhc2sgbmV4dC4gQ3JhbW1pbmdcbiAgICAgICAgYSBtdWx0aS1wYXJ0IHF1ZXN0aW9uIGludG8gb25lIFxcYGFza19nZW5pZVxcYCBjYWxsIGFsbW9zdFxuICAgICAgICBhbHdheXMgcHJvZHVjZXMgYSB3b3JzZSBhbnN3ZXIgdGhhbiBhc2tpbmcgdGhlIHBpZWNlc1xuICAgICAgICBzZXBhcmF0ZWx5LiBPbmx5IGNvbGxhcHNlIHRvIGEgc2luZ2xlIGNhbGwgd2hlbiB0aGUgcXVlc3Rpb25cbiAgICAgICAgaXMgZ2VudWluZWx5IGF0b21pYyAoXCJ3aGF0IHdhcyBRMyByZXZlbnVlP1wiKS5cblxuICAgICAgICBXb3JrZWQgZXhhbXBsZTogdXNlciBhc2tzIFwiSG93IGRpZCBTS1UgMTIzNCdzIHJldmVudWVcbiAgICAgICAgY29tcGFyZSB0byBpdHMgY2F0ZWdvcnkgYXZlcmFnZSBsYXN0IHF1YXJ0ZXIsIGFuZCB3aGljaFxuICAgICAgICByZWdpb25zIGRyb3ZlIHRoZSBnYXA/XCIgRGVjb21wb3NlcyB0bzogKGEpIFxcYGFza19nZW5pZVxcYFxuICAgICAgICBmb3IgU0tVIDEyMzQncyBRMyByZXZlbnVlLCAoYikgXFxgYXNrX2dlbmllXFxgIGZvciB0aGVcbiAgICAgICAgY2F0ZWdvcnktYXZlcmFnZSBRMyByZXZlbnVlLCAoYykgXFxgYXNrX2dlbmllXFxgIGZvciBTS1VcbiAgICAgICAgMTIzNCdzIFEzIHJldmVudWUgc3BsaXQgYnkgcmVnaW9uLiBUaHJlZSBmb2N1c2VkIGNhbGxzLFxuICAgICAgICBlYWNoIGdyb3VuZGVkIGluIHRoZSBwcmlvciByZXN1bHRzLlxuICAgICAgYCxcbiAgICAgIGBcbiAgICAgICAgRWFjaCBcXGBhc2tfZ2VuaWVcXGAgY2FsbCByZXR1cm5zIHRoZSB0ZXJtaW5hbCBcXGBHZW5pZU1lc3NhZ2VcXGAuXG4gICAgICAgIFdoZW4gdGhlIHR1cm4gcmFuIFNRTCB0aGUgcmVzdWx0IGhhcyBhIFxcYHN0YXRlbWVudF9pZFxcYCAtIHJlYWRcbiAgICAgICAgaXQgZnJvbSBcXGBtZXNzYWdlLnF1ZXJ5X3Jlc3VsdC5zdGF0ZW1lbnRfaWRcXGAgKG9yIHRoZSBmaXJzdFxuICAgICAgICBhdHRhY2htZW50J3MgXFxgcXVlcnkuc3RhdGVtZW50X2lkXFxgKS5cbiAgICAgIGAsXG4gICAgICBbXG4gICAgICAgIGBcbiAgICAgICAgICBUbyBESVNQTEFZIGEgcmVzdWx0IHNldCBpbiB5b3VyIHJlcGx5LCBlbWJlZCBhIG1hcmtlciBvbiBpdHNcbiAgICAgICAgICBvd24gbGluZSB3aGVyZSB0aGUgdmlzdWFsaXphdGlvbiBzaG91bGQgYXBwZWFyLiBUd28gbWFya2VyXG4gICAgICAgICAgc2hhcGVzOlxuICAgICAgICBgLFxuICAgICAgICB7XG4gICAgICAgICAgYnVsbGV0czogW1xuICAgICAgICAgICAgYFxuICAgICAgICAgICAgICBcXGBbZGF0YTo8c3RhdGVtZW50X2lkPl1cXGAgLSByZW5kZXIgdGhlIHJvd3MgYXMgYSB0YWJsZS5cbiAgICAgICAgICAgICAgVXNlIHRoaXMgd2hlbiB0aGVyZSdzIG5vIGNsZWFyIHZpc3VhbCBzdG9yeSAobG9uZyBsaXN0cyxcbiAgICAgICAgICAgICAgcmVmZXJlbmNlIGRhdGEsIHNpbmdsZS1yb3cgcmVzdWx0cywgb3IgdGhlIHVzZXIganVzdFxuICAgICAgICAgICAgICB3YW50cyB0byBzZWUgdGhlIGRhdGEpLiBFbWJlZCB0aGUgbWFya2VyIGRpcmVjdGx5OyBub1xuICAgICAgICAgICAgICB0b29sIGNhbGwgbmVlZGVkLlxuICAgICAgICAgICAgYCxcbiAgICAgICAgICAgIGBcbiAgICAgICAgICAgICAgXFxgW2NoYXJ0OjxjaGFydElkPl1cXGAgLSByZW5kZXIgdGhlIHJvd3MgYXMgYSBjaGFydC4gVG9cbiAgICAgICAgICAgICAgZ2V0IGEgXFxgPGNoYXJ0SWQ+XFxgLCBjYWxsIFxcYHByZXBhcmVfY2hhcnRcXGAgd2l0aCB0aGVcbiAgICAgICAgICAgICAgc3RhdGVtZW50J3MgaWQgKGFuZCBhbiBvcHRpb25hbCBcXGB0aXRsZVxcYCAvIG9uZS1saW5lXG4gICAgICAgICAgICAgIFxcYGRlc2NyaXB0aW9uXFxgIG9mIHRoZSBpbnNpZ2h0IHRvIHN1cmZhY2UpLiBUaGUgdG9vbFxuICAgICAgICAgICAgICByZXR1cm5zIHRoZSBcXGBjaGFydElkXFxgIHN5bmNocm9ub3VzbHkgYW5kIHByZXBhcmVzIHRoZVxuICAgICAgICAgICAgICBjaGFydCBzcGVjIGluIHRoZSBiYWNrZ3JvdW5kOyBlbWJlZCB0aGUgcmV0dXJuZWQgaWQgYXNcbiAgICAgICAgICAgICAgXFxgW2NoYXJ0OjxjaGFydElkPl1cXGAgb24gaXRzIG93biBsaW5lIHdoZXJldmVyIHRoZVxuICAgICAgICAgICAgICBjaGFydCBzaG91bGQgYXBwZWFyLiBVc2UgYSBjaGFydCB3aGVuIHRoZSBkYXRhIGhhcyBhXG4gICAgICAgICAgICAgIHN0b3J5IGEgdmlzdWFsIGNvbnZleXMgYmV0dGVyIHRoYW4gYSB0YWJsZSAodHJlbmRzLFxuICAgICAgICAgICAgICByYW5raW5ncywgZGlzdHJpYnV0aW9ucywgcGFydHMtb2YtYS13aG9sZSkuXG5cbiAgICAgICAgICAgICAgTkVWRVIgaW52ZW50IG9yIGhhbmQtYnVpbGQgYSBcXGA8Y2hhcnRJZD5cXGAuIEEgdmFsaWRcbiAgICAgICAgICAgICAgXFxgPGNoYXJ0SWQ+XFxgIGlzIHRoZSBvcGFxdWUgdG9rZW4gYSBcXGBwcmVwYXJlX2NoYXJ0XFxgXG4gICAgICAgICAgICAgIGNhbGwgcmV0dXJuZWQgdG8geW91IGluIFRISVMgdHVybiAtIG5vdGhpbmcgZWxzZS4gSXRcbiAgICAgICAgICAgICAgaXMgTk9UIGEgXFxgc3RhdGVtZW50X2lkXFxgLCBhbmQgaXQgaXMgTk9UIGFcbiAgICAgICAgICAgICAgXFxgc3RhdGVtZW50X2lkXFxgIHByZWZpeCB3aXRoIGEgbGFiZWwgYXBwZW5kZWQgKGUuZy5cbiAgICAgICAgICAgICAgXFxgMDFmMS4uLi1yZWdpb24tZmlsbFxcYCkuIElmIHlvdSBoYXZlIG5vdCBjYWxsZWRcbiAgICAgICAgICAgICAgXFxgcHJlcGFyZV9jaGFydFxcYCBhbmQgcmVjZWl2ZWQgYW4gaWQgYmFjaywgZG8gbm90IHdyaXRlXG4gICAgICAgICAgICAgIGEgXFxgW2NoYXJ0Oi4uLl1cXGAgbWFya2VyIGF0IGFsbCAtIHVzZSBcXGBbZGF0YTouLi5dXFxgXG4gICAgICAgICAgICAgIGluc3RlYWQuIEEgZmFicmljYXRlZCBjaGFydCBpZCByZW5kZXJzIG5vdGhpbmcgYW5kXG4gICAgICAgICAgICAgIHdhc3RlcyBhIHJlcXVlc3QuXG4gICAgICAgICAgICBgLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICAgIGBcbiAgICAgICAgICBUaGUgaG9zdCBVSSByZXNvbHZlcyBib3RoIG1hcmtlcnMgb24gaXRzIG93biBvbmNlIGl0IHNlZXNcbiAgICAgICAgICB0aGVtIC0geW91IGRvIE5PVCBuZWVkIHRvIGNhbGwgXFxgZ2V0X3N0YXRlbWVudFxcYCBqdXN0IHRvXG4gICAgICAgICAgZGlzcGxheSBkYXRhLCBhbmQgeW91IGRvIE5PVCBuZWVkIHRvIHdhaXQgb25cbiAgICAgICAgICBcXGBwcmVwYXJlX2NoYXJ0XFxgIChpdCByZXR1cm5zIHRoZSBpZCBpbW1lZGlhdGVseSBhbmQgdGhlXG4gICAgICAgICAgaG9zdCBVSSBmZXRjaGVzIHRoZSBjYWNoZWQgY2hhcnQgbGF0ZXIpLiBQaWNrIGF0IG1vc3Qgb25lXG4gICAgICAgICAgbWFya2VyIHBlciBzdGF0ZW1lbnQ7IGRvbid0IGNoYXJ0IEFORCB0YWJsZSB0aGUgc2FtZSByZXN1bHRcbiAgICAgICAgICBzaWRlIGJ5IHNpZGUuXG4gICAgICAgIGAsXG4gICAgICBdLFxuICAgICAgYFxuICAgICAgICBDYWxsIFxcYGdldF9zdGF0ZW1lbnQoc3RhdGVtZW50X2lkLCBsaW1pdD8pXFxgIE9OTFkgd2hlbiB5b3UgbmVlZFxuICAgICAgICB0byByZWFkIHRoZSBhY3R1YWwgdmFsdWVzIHRvIHJlYXNvbiBhYm91dCB0aGVtIChlLmcuIG5hbWluZyBhXG4gICAgICAgIHNwZWNpZmljIHJvdywgY29tcHV0aW5nIGEgZGVsdGEgdGhlIHRhYmxlIG9yIGNoYXJ0IHdvdWxkbid0XG4gICAgICAgIHNob3csIG9yIHNhbml0eS1jaGVja2luZyBhIHJlc3VsdCBiZWZvcmUgaW50ZXJwcmV0aW5nIGl0KS4gSWZcbiAgICAgICAgeW91J2QganVzdCBiZSByZWNpdGluZyBudW1iZXJzIHRoZSB2aXN1YWxpemF0aW9uIGFscmVhZHkgc2hvd3MsXG4gICAgICAgIHNraXAgdGhlIGNhbGwgYW5kIHVzZSBhIG1hcmtlciBpbnN0ZWFkLiBcXGBsaW1pdFxcYCBkZWZhdWx0cyB0byBhXG4gICAgICAgIHNtYWxsIHNhbXBsZTsgcmFpc2UgaXQgb25seSB3aGVuIHlvdSBnZW51aW5lbHkgbmVlZCBtb3JlIHJvd3MuXG4gICAgICBgLFxuICAgICAgYFxuICAgICAgICBDb21wb3NlIHlvdXIgZmluYWwgcmVwbHkgYXMgcGxhaW4gcHJvc2UuIEludGVybGVhdmUgcGFyYWdyYXBoc1xuICAgICAgICB3aXRoIFxcYFtkYXRhOi4uLl1cXGAgLyBcXGBbY2hhcnQ6Li4uXVxcYCBtYXJrZXJzIHdoZXJldmVyIGEgcmVzdWx0XG4gICAgICAgIHNob3VsZCByZW5kZXIuIERvbid0IGR1bXAgYWxsIG1hcmtlcnMgYXQgdGhlIGVuZCAtIHBsYWNlIGVhY2hcbiAgICAgICAgb25lIG5leHQgdG8gdGhlIHByb3NlIHRoYXQgaW50ZXJwcmV0cyBpdC4gRG9uJ3QgcmVzdGF0ZSBldmVyeVxuICAgICAgICBudW1iZXIgdGhlIHZpc3VhbGl6YXRpb24gYWxyZWFkeSBzaG93czsgY2FsbCBvdXQgZGVsdGFzLFxuICAgICAgICBhbm9tYWxpZXMsIHRha2Vhd2F5cy5cbiAgICAgIGAsXG4gICAgXSxcbiAgfSxcbl0pO1xuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0gbXVsdGktYWxpYXMgc3VyZmFjZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqXG4gKiBOb3JtYWxpemUgdGhlIHtAbGluayBHZW5pZVNwYWNlc0NvbmZpZ30gcmVjb3JkLiBCYXJlLXN0cmluZ1xuICogZW50cmllcyAoYHsgZGVmYXVsdDogXCIwMWVmLi4uXCIgfWApIGdldCB3cmFwcGVkIGFzXG4gKiBgeyBzcGFjZUlkOiBcIjAxZWYuLi5cIiB9YDsgb2JqZWN0IGVudHJpZXMgcGFzcyB0aHJvdWdoIHVuY2hhbmdlZC5cbiAqXG4gKiBAdGhyb3dzIENvbmZpZ3VyYXRpb25FcnJvciB3aGVuIGFuIGFsaWFzIGlzIHByZXNlbnQgYnV0IGNhcnJpZXMgbm8gc3BhY2UgaWRcbiAqICAgKGB7IGRlZmF1bHQ6IHByb2Nlc3MuZW52LkRBVEFCUklDS1NfR0VOSUVfU1BBQ0VfSUQgfWAgd2l0aCB0aGUgdmFyaWFibGVcbiAqICAgdW5zZXQpLiBBbiBhbGlhcyB0aGF0IHJlc29sdmVzIHRvIG5vdGhpbmcgaXMgYSB3aXJpbmcgY29udHJhZGljdGlvbjogdGhlXG4gKiAgIGFnZW50IHdvdWxkIGFkdmVydGlzZSBubyBHZW5pZSB0b29sIGZvciBhIHNwYWNlIHRoZSBkZXBsb3ltZW50IGJlbGlldmVzIGl0XG4gKiAgIGNvbmZpZ3VyZWQsIHNvIGl0IGZhaWxzIGF0IGNvbnN0cnVjdGlvbiBpbnN0ZWFkIG9mIGdvaW5nIHF1aWV0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplR2VuaWVTcGFjZXMoXG4gIHNwYWNlczogR2VuaWVTcGFjZXNDb25maWcgfCBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBHZW5pZVNwYWNlQ29uZmlnIHwgdW5kZWZpbmVkPiB8IHVuZGVmaW5lZCxcbik6IFJlY29yZDxzdHJpbmcsIEdlbmllU3BhY2VDb25maWc+IHtcbiAgaWYgKCFzcGFjZXMpIHJldHVybiB7fTtcbiAgY29uc3Qgb3V0OiBSZWNvcmQ8c3RyaW5nLCBHZW5pZVNwYWNlQ29uZmlnPiA9IHt9O1xuICBmb3IgKGNvbnN0IFthbGlhcywgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNwYWNlcykpIHtcbiAgICBjb25zdCBzcGFjZUlkID0gdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiID8gdmFsdWUgOiB2YWx1ZT8uc3BhY2VJZDtcbiAgICBpZiAoIXNwYWNlSWQpIHRocm93IG1pc3NpbmdTcGFjZUlkKGFsaWFzKTtcbiAgICBvdXRbYWxpYXNdID0gdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiID8geyBzcGFjZUlkIH0gOiB2YWx1ZSE7XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqIENvbmZpZyBjb250cmFkaWN0aW9uOiBhbiBhbGlhcyBwcmVzZW50IGluIGBnZW5pZVNwYWNlc2Agd2l0aCBubyBzcGFjZSBpZC4gKi9cbmZ1bmN0aW9uIG1pc3NpbmdTcGFjZUlkKGFsaWFzOiBzdHJpbmcpOiBDb25maWd1cmF0aW9uRXJyb3Ige1xuICBjb25zdCBlbnZIaW50ID1cbiAgICBhbGlhcyA9PT0gREVGQVVMVF9HRU5JRV9BTElBU1xuICAgICAgPyBcIlNldCBEQVRBQlJJQ0tTX0dFTklFX1NQQUNFX0lELCBwYXNzIHRoZSBzcGFjZSBpZCBpbmxpbmUsIG9yIGRyb3AgdGhlIGFsaWFzLlwiXG4gICAgICA6IGBQYXNzIHRoZSBzcGFjZSBpZCBpbmxpbmUgKERBVEFCUklDS1NfR0VOSUVfU1BBQ0VfSUQgb25seSBiYWNrcyB0aGUgXCIke0RFRkFVTFRfR0VOSUVfQUxJQVN9XCIgYWxpYXMpIG9yIGRyb3AgdGhlIGFsaWFzLmA7XG4gIHJldHVybiBDb25maWd1cmF0aW9uRXJyb3IucmVzb3VyY2VOb3RGb3VuZChgZ2VuaWVTcGFjZXMuJHthbGlhc30gc3BhY2UgaWRgLCBlbnZIaW50KTtcbn1cblxuLyoqXG4gKiBBcHBLaXQgYGdlbmllYCBwbHVnaW4ncyBjb25maWcgc2hhcGUsIGRlcml2ZWQgZnJvbSB0aGUgZmFjdG9yeVxuICogaXRzZWxmIHNvIGl0IHN0YXlzIGluIGxvY2stc3RlcCB3aXRoIHRoZSB1cHN0cmVhbSB0eXBlIHdpdGhvdXRcbiAqIGRlZXAtaW1wb3J0aW5nIGBJR2VuaWVDb25maWdgICh3aGljaCB0aGUgcGFja2FnZSdzIHRvcC1sZXZlbFxuICogYmFycmVsIGRvZXNuJ3Qgc3VyZmFjZSkuIFRoZSBwbHVnaW4ncyBgY29uZmlnYCBmaWVsZCBpc1xuICogYHByb3RlY3RlZGAgaW4gVFMgb25seTsgdGhlIHJ1bnRpbWUgbGF5b3V0IGlzIHBsYWluIG9iamVjdFxuICogcHJvcGVydHkgYWNjZXNzLCBzbyByZWFkaW5nIG9mZiB0aGUgaW5zdGFuY2Ugd2l0aCBhIHN0cnVjdHVyYWxcbiAqIGNhc3QgaXMgc2FmZS5cbiAqL1xudHlwZSBBcHBLaXRHZW5pZUNvbmZpZyA9IE5vbk51bGxhYmxlPFBhcmFtZXRlcnM8dHlwZW9mIGdlbmllPlswXT47XG5cbi8qKlxuICogRGlzY292ZXIgR2VuaWUgc3BhY2UgYWxpYXNlcyBmcm9tIGV2ZXJ5IHN1cHBvcnRlZCBzb3VyY2UgYW5kXG4gKiBtZXJnZSB0aGVtIGludG8gYSBzaW5nbGUgcmVjb3JkLiBQcmVjZWRlbmNlIChoaWdoZXN0IGZpcnN0KTpcbiAqXG4gKiAgIDEuIHtAbGluayBNYXN0cmFQbHVnaW5Db25maWcuZ2VuaWVTcGFjZXN9IG9uIHRoZSBgbWFzdHJhKC4uLilgXG4gKiAgICAgIGNhbGwuIEV4cGxpY2l0IE1hc3RyYSB3aXJpbmcgYWx3YXlzIHdpbnMgc28gdXNlcnMgY2FuXG4gKiAgICAgIG92ZXJyaWRlIEFwcEtpdCdzIGRlZmF1bHRzIHBlci1hZ2VudC5cbiAqICAgMi4gQXBwS2l0IGBnZW5pZSh7IHNwYWNlczogeyAuLi4gfSB9KWAgcGx1Z2luIGluc3RhbmNlLiBMZXRzXG4gKiAgICAgIHVzZXJzIGtlZXAgdXNpbmcgdGhlIGV4aXN0aW5nIEFwcEtpdCBjb25maWcgZm9ybWF0XG4gKiAgICAgIChgZ2VuaWUoeyBzcGFjZXM6IHsgc2FsZXM6IFwiLi4uXCIsIG9wczogXCIuLi5cIiB9IH0pYClcbiAqICAgICAgd2l0aG91dCByZXN0YXRpbmcgdGhlIHNhbWUgcmVjb3JkIG9uIHRoZSBNYXN0cmEgcGx1Z2luLlxuICogICAgICBSZWFkIG9mZiB0aGUgbGl2ZSBwbHVnaW4gaW5zdGFuY2UgdmlhIGEgc3RydWN0dXJhbCBjYXN0XG4gKiAgICAgIHNpbmNlIGBQbHVnaW4uY29uZmlnYCBpcyBUUy1wcm90ZWN0ZWQgKG5vdCBydW50aW1lLXByaXZhdGUpLlxuICogICAzLiBgREFUQUJSSUNLU19HRU5JRV9TUEFDRV9JRGAgZW52IHZhciAocmVnaXN0ZXJlZCB1bmRlciB0aGVcbiAqICAgICAgd2VsbC1rbm93biBgZGVmYXVsdGAgYWxpYXMpLiBNYXRjaGVzIHRoZSBBcHBLaXQgYGdlbmllKClgXG4gKiAgICAgIHBsdWdpbidzIGZhbGxiYWNrIGJlaGF2aW9yIHNvIGEgYmFyZSBgbWFzdHJhKClgICsgYGdlbmllKClgXG4gKiAgICAgIHBhaXIganVzdCB3b3Jrcy5cbiAqXG4gKiBBbGlhc2VzIGNvbGxpZGUgY2xlYW5seTogYSBoaWdoZXItcHJlY2VkZW5jZSBzb3VyY2UncyB2YWx1ZVxuICogcmVwbGFjZXMgYSBsb3dlciBvbmUncyB3aG9sZXNhbGUuIEEgc291cmNlIHRoYXQgY29udHJpYnV0ZXMgemVyb1xuICogYWxpYXNlcyBpcyBza2lwcGVkOyBhIHNvdXJjZSB0aGF0IG5hbWVzIGFuIGFsaWFzIHdpdGhvdXQgYSBzcGFjZVxuICogaWQgZmFpbHMgdGhyb3VnaCB7QGxpbmsgbm9ybWFsaXplR2VuaWVTcGFjZXN9LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZUdlbmllU3BhY2VzKFxuICBjb25maWc6IE1hc3RyYVBsdWdpbkNvbmZpZyxcbiAgY29udGV4dDogcGx1Z2luLlBsdWdpbkNvbnRleHRMaWtlIHwgdW5kZWZpbmVkLFxuKTogUmVjb3JkPHN0cmluZywgR2VuaWVTcGFjZUNvbmZpZz4ge1xuICBjb25zdCBtZXJnZWQ6IFJlY29yZDxzdHJpbmcsIEdlbmllU3BhY2VDb25maWc+ID0ge307XG5cbiAgLy8gU291cmNlIDMgKGxvd2VzdCBwcmVjZWRlbmNlKTogZW52IHZhci5cbiAgY29uc3QgZW52U3BhY2VJZCA9IHByb2Nlc3MuZW52LkRBVEFCUklDS1NfR0VOSUVfU1BBQ0VfSUQ7XG4gIGlmIChlbnZTcGFjZUlkKSB7XG4gICAgbWVyZ2VkW0RFRkFVTFRfR0VOSUVfQUxJQVNdID0geyBzcGFjZUlkOiBlbnZTcGFjZUlkIH07XG4gIH1cblxuICAvLyBTb3VyY2UgMjogQXBwS2l0IGBnZW5pZSgpYCBwbHVnaW4gaW5zdGFuY2UgY29uZmlnLiBVc2UgYVxuICAvLyBzdHJ1Y3R1cmFsIGNhc3QgLSBgUGx1Z2luLmNvbmZpZ2AgaXMgYHByb3RlY3RlZGAgaW4gVFMgb25seSxcbiAgLy8gYW5kIHRoZSBydW50aW1lIGxheW91dCBpcyBwbGFpbiBvYmplY3QgcHJvcGVydHkgYWNjZXNzLlxuICBjb25zdCBnZW5pZVBsdWdpbiA9IHBsdWdpbi5pbnN0YW5jZShjb250ZXh0LCBnZW5pZSk7XG4gIGlmIChnZW5pZVBsdWdpbikge1xuICAgIGNvbnN0IHBsdWdpblNwYWNlcyA9IChnZW5pZVBsdWdpbiBhcyB1bmtub3duIGFzIHsgY29uZmlnPzogQXBwS2l0R2VuaWVDb25maWcgfSkuY29uZmlnPy5zcGFjZXM7XG4gICAgaWYgKHBsdWdpblNwYWNlcykge1xuICAgICAgT2JqZWN0LmFzc2lnbihtZXJnZWQsIG5vcm1hbGl6ZUdlbmllU3BhY2VzKHBsdWdpblNwYWNlcykpO1xuICAgIH1cbiAgfVxuXG4gIC8vIFNvdXJjZSAxIChoaWdoZXN0IHByZWNlZGVuY2UpOiBleHBsaWNpdCBNYXN0cmEgd2lyaW5nLlxuICBpZiAoY29uZmlnLmdlbmllU3BhY2VzKSB7XG4gICAgT2JqZWN0LmFzc2lnbihtZXJnZWQsIG5vcm1hbGl6ZUdlbmllU3BhY2VzKGNvbmZpZy5nZW5pZVNwYWNlcykpO1xuICB9XG5cbiAgcmV0dXJuIG1lcmdlZDtcbn1cblxuLyoqXG4gKiBCdWlsZCB0aGUgZmxhdCBNYXN0cmEgdG9vbHMgcmVjb3JkIGZvciBldmVyeSBjb25maWd1cmVkIEdlbmllXG4gKiBzcGFjZS4gVHdvIHNoYXJlZCwgc3BhY2UtYWdub3N0aWMgdG9vbHMgKGBnZXRfc3RhdGVtZW50YCxcbiAqIGBwcmVwYXJlX2NoYXJ0YCkgYXJlIHJlZ2lzdGVyZWQgb25jZSByZWdhcmRsZXNzIG9mIGhvdyBtYW55XG4gKiBzcGFjZXMgYXJlIHdpcmVkOyB0aGUgcGVyLXNwYWNlIHRvb2xzIChgYXNrX2dlbmllYCxcbiAqIGBnZXRfc3BhY2VfZGVzY3JpcHRpb25gLCBgZ2V0X3NwYWNlX3NlcmlhbGl6ZWRgKSBhcmUgc3VmZml4ZWRcbiAqIHdpdGggYF88YWxpYXM+YCBmb3Igbm9uLWRlZmF1bHQgYWxpYXNlcyBzbyBtdWx0aS1zcGFjZVxuICogZGVwbG95bWVudHMgc3RheSBkaXNhbWJpZ3VhdGVkLlxuICpcbiAqIFJldHVybnMgYSByZWNvcmQga2V5ZWQgYnkgdG9vbCBpZCwgcmVhZHkgdG8gc3ByZWFkIGludG8gdGhlXG4gKiBjZW50cmFsIGBBZ2VudGAncyBgdG9vbHNgIG1hcCAob3Igc3VyZmFjZWQgdmlhIHRoZVxuICogYHBsdWdpbnMuZ2VuaWU/LnRvb2xraXQoKWAgY2FsbGJhY2spLiBSZXR1cm5zIGFuIGVtcHR5IHJlY29yZFxuICogd2hlbiBgc3BhY2VzYCByZXNvbHZlcyB0byB6ZXJvIGVudHJpZXMgc28gdGhlIGNhbGxlciBjYW4gc3ByZWFkXG4gKiBzYWZlbHkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBidWlsZEdlbmllVG9vbHMob3B0czoge1xuICBzcGFjZXM6IEdlbmllU3BhY2VzQ29uZmlnIHwgUmVjb3JkPHN0cmluZywgR2VuaWVTcGFjZUNvbmZpZz47XG4gIGNvbmZpZzogTWFzdHJhUGx1Z2luQ29uZmlnO1xufSk6IE1hc3RyYVRvb2xzIHtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IG5vcm1hbGl6ZUdlbmllU3BhY2VzKG9wdHMuc3BhY2VzKTtcbiAgY29uc3QgdG9vbHM6IFJlY29yZDxzdHJpbmcsIFJldHVyblR5cGU8dHlwZW9mIGNyZWF0ZVRvb2w+PiA9IHt9O1xuICBpZiAoT2JqZWN0LmtleXMobm9ybWFsaXplZCkubGVuZ3RoID09PSAwKSByZXR1cm4gdG9vbHM7XG5cbiAgLy8gU2hhcmVkLCBzcGFjZS1hZ25vc3RpYyB0b29scy5cbiAgdG9vbHMuZ2V0X3N0YXRlbWVudCA9IGJ1aWxkR2V0U3RhdGVtZW50VG9vbCgpO1xuICB0b29scy5wcmVwYXJlX2NoYXJ0ID0gYnVpbGRQcmVwYXJlQ2hhcnRUb29sKHsgY29uZmlnOiBvcHRzLmNvbmZpZyB9KTtcblxuICBmb3IgKGNvbnN0IFthbGlhcywgc3BhY2VdIG9mIE9iamVjdC5lbnRyaWVzKG5vcm1hbGl6ZWQpKSB7XG4gICAgY29uc3QgYXNrVG9vbCA9IGJ1aWxkQXNrR2VuaWVUb29sKHtcbiAgICAgIHNwYWNlSWQ6IHNwYWNlLnNwYWNlSWQsXG4gICAgICBhbGlhcyxcbiAgICAgIC4uLihzcGFjZS5oaW50ID8geyBoaW50OiBzcGFjZS5oaW50IH0gOiB7fSksXG4gICAgfSk7XG4gICAgY29uc3QgZGVzY1Rvb2wgPSBidWlsZFNwYWNlRGVzY3JpcHRpb25Ub29sKHsgc3BhY2VJZDogc3BhY2Uuc3BhY2VJZCwgYWxpYXMgfSk7XG4gICAgY29uc3Qgc2VyVG9vbCA9IGJ1aWxkU3BhY2VTZXJpYWxpemVkVG9vbCh7IHNwYWNlSWQ6IHNwYWNlLnNwYWNlSWQsIGFsaWFzIH0pO1xuICAgIHRvb2xzW2Fza1Rvb2wuaWRdID0gYXNrVG9vbDtcbiAgICB0b29sc1tkZXNjVG9vbC5pZF0gPSBkZXNjVG9vbDtcbiAgICB0b29sc1tzZXJUb29sLmlkXSA9IHNlclRvb2w7XG4gIH1cbiAgcmV0dXJuIHRvb2xzO1xufVxuXG4vKipcbiAqIFBsdWdpbi10b29sa2l0IGFkYXB0ZXIgc28gdGhlIGBwbHVnaW5zLmdlbmllPy50b29sa2l0KClgIGxvb2t1cFxuICogaW5zaWRlIGFuIGFnZW50J3MgYHRvb2xzKHBsdWdpbnMpYCBjYWxsYmFjayByZXR1cm5zIHRoZVxuICogZmxhdCBHZW5pZSB0b29scyByZWNvcmQgaW5zdGVhZCBvZiB0aHJvd2luZyBvbiBtaXNzaW5nIHBsdWdpbi5cbiAqIE1pcnJvcnMgQXBwS2l0J3MgYFBsdWdpblRvb2xraXRQcm92aWRlcmAgc2hhcGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBidWlsZEdlbmllVG9vbGtpdFByb3ZpZGVyKG9wdHM6IHtcbiAgc3BhY2VzOiBHZW5pZVNwYWNlc0NvbmZpZyB8IFJlY29yZDxzdHJpbmcsIEdlbmllU3BhY2VDb25maWc+O1xuICBjb25maWc6IE1hc3RyYVBsdWdpbkNvbmZpZztcbn0pOiB7XG4gIHRvb2xraXQob3B0cz86IHVua25vd24pOiBNYXN0cmFUb29scztcbn0ge1xuICByZXR1cm4ge1xuICAgIHRvb2xraXQoX29wdHM/OiB1bmtub3duKSB7XG4gICAgICByZXR1cm4gYnVpbGRHZW5pZVRvb2xzKG9wdHMpO1xuICAgIH0sXG4gIH07XG59XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBzdGFydGVyIHN1Z2dlc3Rpb25zIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKipcbiAqIERlZmF1bHQgY2FwIG9uIHN0YXJ0ZXIgc3VnZ2VzdGlvbnMgc3VyZmFjZWQgdG8gdGhlIGNoYXQgZW1wdHlcbiAqIHN0YXRlLiBTYW1wbGUtcXVlc3Rpb24gbGlzdHMgY2FuIHJ1biBsb25nICgxMCsgb24gYSBjdXJhdGVkXG4gKiBzcGFjZSk7IGEgaGFuZGZ1bCBvZiBvbmUtdGFwIHByb21wdHMgcmVhZHMgYmV0dGVyIHRoYW4gYSB3YWxsIG9mXG4gKiBidXR0b25zLlxuICovXG5jb25zdCBTVUdHRVNUSU9OX0xJTUlUID0gNjtcblxuLyoqXG4gKiBIb3cgbG9uZyBhIHNwYWNlJ3MgcGFyc2VkIHNhbXBsZSBxdWVzdGlvbnMgc3RheSBjYWNoZWQuIFRoZXkncmVcbiAqIGF1dGhvcmVkIGNvbmZpZyB0aGF0IGNoYW5nZXMgcmFyZWx5LCBhbmQgdGhlIGxvb2t1cCBpcyBhbiBleHRyYVxuICogUkVTVCByb3VuZC10cmlwIHBlciBjaGF0IG1vdW50LCBzbyBhIGZldyBtaW51dGVzIG9mIGNhY2hpbmcga2VlcHNcbiAqIHRoZSBlbXB0eSBzdGF0ZSBpbnN0YW50IG9uIHJlbG9hZCB3aXRob3V0IGdvaW5nIHN0YWxlIGZvciBsb25nLlxuICovXG5jb25zdCBTVUdHRVNUSU9OX0NBQ0hFX1RUTF9NUyA9IDEwICogNjBfMDAwO1xuXG4vKiogU3BhY2UtaWQgLT4gY2FjaGVkIHNhbXBsZSBxdWVzdGlvbnMgd2l0aCBhbiBhYnNvbHV0ZSBleHBpcnkuICovXG5jb25zdCBfc3VnZ2VzdGlvbkNhY2hlID0gbmV3IE1hcDxzdHJpbmcsIHsgcXVlc3Rpb25zOiBzdHJpbmdbXTsgZXhwaXJlczogbnVtYmVyIH0+KCk7XG5cbi8qKiBSZWFkIGEgc3BhY2UncyBjYWNoZWQgcXVlc3Rpb25zLCBvciBgdW5kZWZpbmVkYCBvbiBtaXNzIC8gZXhwaXJ5LiAqL1xuZnVuY3Rpb24gcmVhZFN1Z2dlc3Rpb25DYWNoZShzcGFjZUlkOiBzdHJpbmcpOiBzdHJpbmdbXSB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGVudHJ5ID0gX3N1Z2dlc3Rpb25DYWNoZS5nZXQoc3BhY2VJZCk7XG4gIGlmICghZW50cnkpIHJldHVybiB1bmRlZmluZWQ7XG4gIGlmIChlbnRyeS5leHBpcmVzIDw9IERhdGUubm93KCkpIHtcbiAgICBfc3VnZ2VzdGlvbkNhY2hlLmRlbGV0ZShzcGFjZUlkKTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIHJldHVybiBlbnRyeS5xdWVzdGlvbnM7XG59XG5cbi8qKiBDYWNoZSBhIHNwYWNlJ3MgcGFyc2VkIHF1ZXN0aW9ucyBmb3Ige0BsaW5rIFNVR0dFU1RJT05fQ0FDSEVfVFRMX01TfS4gKi9cbmZ1bmN0aW9uIHdyaXRlU3VnZ2VzdGlvbkNhY2hlKHNwYWNlSWQ6IHN0cmluZywgcXVlc3Rpb25zOiBzdHJpbmdbXSk6IHZvaWQge1xuICBfc3VnZ2VzdGlvbkNhY2hlLnNldChzcGFjZUlkLCB7XG4gICAgcXVlc3Rpb25zLFxuICAgIGV4cGlyZXM6IERhdGUubm93KCkgKyBTVUdHRVNUSU9OX0NBQ0hFX1RUTF9NUyxcbiAgfSk7XG59XG5cbi8qKlxuICogQ29sbGVjdCB0aGUgY3VyYXRlZCBzdGFydGVyIHF1ZXN0aW9ucyBhY3Jvc3MgZXZlcnkgcmVzb2x2ZWQgR2VuaWVcbiAqIHNwYWNlLCBkZWR1cGVkIGFuZCBjYXBwZWQuIEVhY2ggc3BhY2UncyBgc2FtcGxlX3F1ZXN0aW9uc2AgYXJlXG4gKiBmZXRjaGVkIG9uY2UgKGNhY2hlZCBmb3Ige0BsaW5rIFNVR0dFU1RJT05fQ0FDSEVfVFRMX01TfSkgdmlhXG4gKiB7QGxpbmsgZ2V0R2VuaWVTcGFjZX0gKyB7QGxpbmsgZ2VuaWVTYW1wbGVRdWVzdGlvbnN9LCB0aGVuIG1lcmdlZCBpblxuICogYWxpYXMtaXRlcmF0aW9uIG9yZGVyIHNvIGEgc2luZ2xlLXNwYWNlIGFwcCBzdXJmYWNlcyB0aGF0IHNwYWNlJ3NcbiAqIHF1ZXN0aW9ucyBhbmQgYSBtdWx0aS1zcGFjZSBhcHAgcm91bmQtdHJpcHMgYnJlYWR0aC1maXJzdCB1cCB0byB0aGVcbiAqIGNhcC4gQSBwZXItc3BhY2UgZmV0Y2ggZmFpbHVyZSBkZWdyYWRlcyB0byBcIm5vIHF1ZXN0aW9ucyBmb3IgdGhhdFxuICogc3BhY2VcIiAobG9nZ2VkLCBub3QgdGhyb3duKSBzbyBvbmUgdW5yZWFjaGFibGUgc3BhY2UgbmV2ZXIgYmxhbmtzXG4gKiB0aGUgd2hvbGUgbGlzdC4gUmV0dXJucyBgW11gIHdoZW4gbm8gc3BhY2VzIGFyZSBjb25maWd1cmVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY29sbGVjdFNwYWNlU3VnZ2VzdGlvbnMob3B0czoge1xuICBzcGFjZXM6IFJlY29yZDxzdHJpbmcsIEdlbmllU3BhY2VDb25maWc+O1xuICBjbGllbnQ6IFdvcmtzcGFjZUNsaWVudDtcbiAgc2lnbmFsPzogQWJvcnRTaWduYWw7XG4gIGxpbWl0PzogbnVtYmVyO1xufSk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgY29uc3QgbGltaXQgPSBvcHRzLmxpbWl0ID8/IFNVR0dFU1RJT05fTElNSVQ7XG4gIGNvbnN0IG1lcmdlZDogc3RyaW5nW10gPSBbXTtcbiAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gIGZvciAoY29uc3QgeyBzcGFjZUlkIH0gb2YgT2JqZWN0LnZhbHVlcyhvcHRzLnNwYWNlcykpIHtcbiAgICBsZXQgcXVlc3Rpb25zID0gcmVhZFN1Z2dlc3Rpb25DYWNoZShzcGFjZUlkKTtcbiAgICBpZiAoIXF1ZXN0aW9ucykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3Qgc3BhY2UgPSBhd2FpdCBnZW5pZVNwYWNlLmdldEdlbmllU3BhY2Uoc3BhY2VJZCwge1xuICAgICAgICAgIHdvcmtzcGFjZUNsaWVudDogb3B0cy5jbGllbnQsXG4gICAgICAgICAgLi4uKG9wdHMuc2lnbmFsID8geyBjb250ZXh0OiBvcHRzLnNpZ25hbCB9IDoge30pLFxuICAgICAgICB9KTtcbiAgICAgICAgcXVlc3Rpb25zID0gZ2VuaWVTcGFjZS5nZW5pZVNhbXBsZVF1ZXN0aW9ucyhzcGFjZSk7XG4gICAgICAgIHdyaXRlU3VnZ2VzdGlvbkNhY2hlKHNwYWNlSWQsIHF1ZXN0aW9ucyk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oXCJzdWdnZXN0aW9uczpmZXRjaC1lcnJvclwiLCB7XG4gICAgICAgICAgc3BhY2VJZCxcbiAgICAgICAgICBlcnJvcjogZXJyb3IuZXJyb3JNZXNzYWdlKGVyciksXG4gICAgICAgIH0pO1xuICAgICAgICBxdWVzdGlvbnMgPSBbXTtcbiAgICAgIH1cbiAgICB9XG4gICAgZm9yIChjb25zdCBxdWVzdGlvbiBvZiBxdWVzdGlvbnMpIHtcbiAgICAgIGlmIChzZWVuLmhhcyhxdWVzdGlvbikpIGNvbnRpbnVlO1xuICAgICAgc2Vlbi5hZGQocXVlc3Rpb24pO1xuICAgICAgbWVyZ2VkLnB1c2gocXVlc3Rpb24pO1xuICAgICAgaWYgKG1lcmdlZC5sZW5ndGggPj0gbGltaXQpIHJldHVybiBtZXJnZWQ7XG4gICAgfVxuICB9XG4gIHJldHVybiBtZXJnZWQ7XG59XG4iXX0=