@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,638 @@
1
+ /**
2
+ * Chart planner + chart cache.
3
+ *
4
+ * Self-contained chart subsystem with two layers:
5
+ *
6
+ * 1. Inner planner agent (private). Pure dataset-in /
7
+ * `EChartsOption`-out brain. Driven by {@link prepareChart};
8
+ * callers never instantiate it directly.
9
+ * 2. {@link prepareChart}: orchestration on top of the planner.
10
+ * Mints a `chartId`, caches an empty `{ chartId }` record
11
+ * synchronously, then resolves the dataset and runs the
12
+ * planner in the background. The terminal entry settles with
13
+ * either `result` (success) or `error` (failure). Both
14
+ * undefined means the entry is still processing.
15
+ *
16
+ * The cache surface ({@link fetchChart}) is the only state the
17
+ * HTTP route and the chart-producing tools share. `prepareChart`
18
+ * is dataset-agnostic - callers supply a `resolveData` callback
19
+ * that fetches the rows however they like (Genie statement, inline
20
+ * dataset, custom API). The module has no knowledge of Genie or
21
+ * statement ids; those concerns live in the tools that wrap it.
22
+ *
23
+ * Wire-format schemas live in `@dbx-tools/shared-mastra` so
24
+ * the demo client and any other UI consumer share the exact same
25
+ * shape this module reads and writes.
26
+ *
27
+ * @module
28
+ */
29
+ import { AppKitError, CacheManager, ExecutionError } from "@databricks/appkit";
30
+ import { async, error, hash, log, string } from "@dbx-tools/shared-core";
31
+ import { wire } from "@dbx-tools/shared-mastra";
32
+ import { model } from "@dbx-tools/shared-model";
33
+ import { Agent } from "@mastra/core/agent";
34
+ import { createTool } from "@mastra/core/tools";
35
+ import { z } from "zod";
36
+ import { resolveUserKey } from "./config.js";
37
+ import { buildModel } from "./model.js";
38
+ const logger = log.logger("mastra/chart");
39
+ /* ------------------------------ constants ------------------------------ */
40
+ /**
41
+ * TTL for cached chart entries. One hour balances "long enough for
42
+ * the host UI to fetch the chart well after the model finished
43
+ * talking" against "short enough that abandoned chart ids don't
44
+ * pin storage". Matches the typical Databricks OBO token lifetime
45
+ * so any data re-resolution stays inside the original auth window.
46
+ */
47
+ const CHART_CACHE_TTL_SEC = 60 * 60;
48
+ /** Cache namespace; keeps the chart keyspace tidy. */
49
+ const CHART_CACHE_NAMESPACE = "mastra:chart";
50
+ /** Default server-side long-poll budget for {@link fetchChart}. */
51
+ const DEFAULT_FETCH_TIMEOUT_MS = 60_000;
52
+ /** Default inter-poll sleep for {@link fetchChart}. */
53
+ const DEFAULT_FETCH_INTERVAL_MS = 250;
54
+ /** Stable text stored on a chart entry whose planner run failed. */
55
+ const CHART_FAILED_MESSAGE = "Chart generation failed";
56
+ /* ------------------------------- schemas ------------------------------- */
57
+ /**
58
+ * One series data point. Wide variant set so the planner agent can
59
+ * faithfully pass through whatever the SQL row set contained
60
+ * (numbers, stringified numbers, nulls for missing measurements,
61
+ * `[x, y]` tuples for scatter, `{name, value}` slices for pie)
62
+ * without the structured-output guard rejecting the whole plan.
63
+ *
64
+ * Three layers of tolerance:
65
+ *
66
+ * 1. {@link z.preprocess} normalizes wire shapes BEFORE union
67
+ * dispatch: stringified numbers parse to numbers, finite
68
+ * checks reject `NaN` / `Infinity`, 2-element arrays coerce
69
+ * tuple components, and `{value}` objects with missing /
70
+ * stringified `value` get coerced or rejected uniformly.
71
+ * Anything not handleable becomes `null`.
72
+ * 2. The union accepts `null` as a first-class variant. Echarts
73
+ * renders null as a gap on bar / line / area (which is the
74
+ * right visual signal for "missing reading"). Scatter and
75
+ * pie filter nulls in {@link planToEchartsOption} because
76
+ * Echarts crashes on null tuples / slices.
77
+ * 3. {@link z.union#catch} backstops the whole thing: if
78
+ * preprocess somehow produces a shape that still doesn't
79
+ * match any variant, the bad item becomes `null` instead of
80
+ * taking down the entire chart with a
81
+ * `Structured output validation failed` error.
82
+ */
83
+ const chartDataPointSchema = z
84
+ .preprocess((v) => {
85
+ if (v === null || v === undefined)
86
+ return null;
87
+ if (typeof v === "number")
88
+ return Number.isFinite(v) ? v : null;
89
+ if (typeof v === "string") {
90
+ const n = Number(v);
91
+ return Number.isFinite(n) ? n : null;
92
+ }
93
+ if (Array.isArray(v) && v.length === 2) {
94
+ const x = typeof v[0] === "number" ? v[0] : Number(v[0]);
95
+ const y = typeof v[1] === "number" ? v[1] : Number(v[1]);
96
+ return Number.isFinite(x) && Number.isFinite(y) ? [x, y] : null;
97
+ }
98
+ if (typeof v === "object" && v !== null && "value" in v) {
99
+ const obj = v;
100
+ const val = typeof obj.value === "number" ? obj.value : Number(obj.value);
101
+ if (!Number.isFinite(val))
102
+ return null;
103
+ // Coerce numeric / boolean / nullish names to strings so a
104
+ // pie slice keyed on a year (`2024`) or category id is
105
+ // accepted without round-tripping through the catch arm.
106
+ const rawName = obj.name;
107
+ const name = typeof rawName === "string" ? rawName : rawName == null ? "" : String(rawName);
108
+ return { name, value: val };
109
+ }
110
+ return null;
111
+ }, z.union([
112
+ z.number(),
113
+ z.null(),
114
+ // `[x, y]` scatter point. Modelled as a length-constrained
115
+ // homogeneous array rather than `z.tuple`: Zod emits a tuple as
116
+ // JSON Schema 2020-12 `prefixItems`, and Databricks' Gemini
117
+ // endpoints reject a `response_json_schema` containing it
118
+ // ("must be a boolean or an object", since `items` is absent).
119
+ // `z.array(z.number()).length(2)` emits `items` + `minItems` /
120
+ // `maxItems`, which every provider understands, and validates
121
+ // the same two-number shape.
122
+ z.array(z.number()).length(2),
123
+ z.object({ name: z.string(), value: z.number() }),
124
+ ]))
125
+ .catch(null);
126
+ /**
127
+ * Compact, model-friendly representation of an Echarts spec. The
128
+ * planner agent emits this; {@link planToEchartsOption} expands it
129
+ * into a real `EChartsOption` JSON. Two layers because letting the
130
+ * model fill in a fully-typed `EChartsOption` is brittle (hundreds
131
+ * of optional fields, deep unions, version-dependent shapes). A
132
+ * small "chart plan" schema is much more reliable for a fast model
133
+ * and keeps animation / tooltip / styling defaults consistent
134
+ * across charts.
135
+ */
136
+ export const chartPlanSchema = z.object({
137
+ chartType: wire.ChartTypeSchema,
138
+ title: z
139
+ .string()
140
+ .optional()
141
+ .describe(string.toDescription(`
142
+ Short title shown above the chart. Optional; defaults to the
143
+ \`title\` argument the caller passed in.
144
+ `)),
145
+ xAxisLabel: z
146
+ .string()
147
+ .optional()
148
+ .describe(string.toDescription(`
149
+ Axis label below the chart. Used for bar / line / area / scatter;
150
+ ignored for pie.
151
+ `)),
152
+ yAxisLabel: z
153
+ .string()
154
+ .optional()
155
+ .describe(string.toDescription(`
156
+ Axis label to the left of the chart. Used for bar / line / area /
157
+ scatter; ignored for pie.
158
+ `)),
159
+ categories: z
160
+ .array(z.string())
161
+ .optional()
162
+ .describe(string.toDescription(`
163
+ X-axis category labels for \`bar\` / \`line\` / \`area\` charts
164
+ (one per data point in each series). Omit for \`scatter\` (uses
165
+ [x, y] tuples) and \`pie\` (each slice carries its own \`name\`).
166
+ `)),
167
+ series: z
168
+ .array(z.object({
169
+ name: z.string().describe(string.toDescription(`
170
+ Legend name for this series.
171
+ `)),
172
+ data: z.array(chartDataPointSchema).describe(string.toDescription(`
173
+ Data points. For \`bar\` / \`line\` / \`area\`, an array of
174
+ numbers aligned to \`categories\`. For \`scatter\`, an array
175
+ of \`[x, y]\` numeric tuples. For \`pie\`, an array of
176
+ \`{name, value}\` objects.
177
+ `)),
178
+ }))
179
+ .min(1)
180
+ .describe(string.toDescription(`
181
+ One or more series to plot. Pie charts use exactly one series;
182
+ bar/line/area can stack multiple series sharing the same
183
+ \`categories\` axis.
184
+ `)),
185
+ });
186
+ /**
187
+ * Canonical planner input shape. Tools that source rows from an
188
+ * inline dataset (`render_data`) use it as their `inputSchema`
189
+ * verbatim; tools that resolve rows from a remote (`prepare_chart`
190
+ * over a Genie statement) `omit({ data })` and `extend` with their
191
+ * own identifier field, so the field-level `.describe()` text
192
+ * stays a single source of truth. Server-only - the UI never
193
+ * sees a planner request, only the resolved {@link Chart}.
194
+ */
195
+ export const chartPlannerRequestSchema = z.object({
196
+ title: z.string().describe(string.toDescription(`
197
+ Concise title shown above the chart (e.g. "Top 10 SKUs by Revenue").
198
+ `)),
199
+ description: z
200
+ .string()
201
+ .optional()
202
+ .describe(string.toDescription(`
203
+ One-line intent the chart-planner uses when picking a chart type
204
+ and axis encodings (e.g. "compare quarterly revenue across
205
+ regions", "highlight the steep drop after position 5"). Not shown
206
+ to the user.
207
+ `)),
208
+ data: z
209
+ .array(z.record(z.string(), z.unknown()))
210
+ .nonempty("Data must contain at least one row")
211
+ .readonly()
212
+ .describe(string.toDescription(`
213
+ Tabular dataset to chart. One object per row, keyed by column
214
+ name. Values may be strings, numbers, booleans, or null. The
215
+ chart-planner decides which columns are categories vs. numeric
216
+ series. Cap at a few hundred rows for legibility; sample /
217
+ aggregate larger datasets first.
218
+ `)),
219
+ });
220
+ /* --------------------------- planner instructions --------------------------- */
221
+ /**
222
+ * Format {@link wire.ChartTypeSchema}'s variants as a single
223
+ * human-friendly string of `` `<value>` for <description> ``
224
+ * clauses joined by semicolons, drawn from each variant's own
225
+ * `.describe()` so the planner prompt stays in lock-step with
226
+ * the schema by construction.
227
+ */
228
+ function formatChartTypePicker() {
229
+ return wire.ChartTypeSchema.options
230
+ .map((opt) => `\`${opt.value}\` for ${opt.description ?? ""}`)
231
+ .join("; ");
232
+ }
233
+ /**
234
+ * System prompt for the inner chart-planning agent. Tuned for a
235
+ * fast-tier model (Haiku, GPT-5-mini, Gemini Flash Lite).
236
+ */
237
+ const CHART_PLANNER_INSTRUCTIONS = string.toDescription(`
238
+ You design Apache Echarts visualizations. The user gives you a
239
+ tabular dataset (rows of objects) plus a title and an optional
240
+ description of the intent. You produce a small chart plan (chart
241
+ type, axis labels, categories, series) that best conveys the data.
242
+
243
+ Decision guide. Pick the chart type whose data shape matches the
244
+ dataset and the user's intent: ${formatChartTypePicker()}.
245
+
246
+ When in doubt between bar and line, prefer bar for unordered
247
+ categories and line for ordered ones (dates, time buckets, ranks).
248
+ Never pick pie for more than 7 slices.
249
+
250
+ For bar / line / area: pick one column as the category axis (usually
251
+ the only string-valued column) and one or more numeric columns as
252
+ series. Sort categories by the primary series value descending unless
253
+ the data is naturally ordered (dates, ranks).
254
+
255
+ For pie: pick the category column for slice names and one numeric
256
+ column for slice values. Emit a single series.
257
+
258
+ For scatter: pick two numeric columns and emit \`[x, y]\` tuples in a
259
+ single series.
260
+
261
+ Keep series names human-readable (use the column name; title case it
262
+ lightly if needed). Keep titles concise; do not repeat the user's
263
+ title in xAxisLabel / yAxisLabel.
264
+ `);
265
+ /* ----------------------------- planner agent ----------------------------- */
266
+ /**
267
+ * One planner `Agent` per plugin config. Cached on config object
268
+ * identity so callers can `prepareChart({ config, ... })` from a
269
+ * hot path without paying the Agent-constructor cost every call.
270
+ * `WeakMap` lets retired configs (e.g. test reconfigurations)
271
+ * release their agent without manual eviction.
272
+ */
273
+ const plannerAgents = new WeakMap();
274
+ function getPlannerAgent(config) {
275
+ let agent = plannerAgents.get(config);
276
+ if (!agent) {
277
+ agent = new Agent({
278
+ id: "chart_planner",
279
+ name: "Chart Planner",
280
+ description: "Picks chart type and axis encodings for a dataset.",
281
+ instructions: CHART_PLANNER_INSTRUCTIONS,
282
+ model: ({ requestContext }) => buildModel(config, requestContext, { modelClass: model.ModelClass.ChatFast }),
283
+ });
284
+ plannerAgents.set(config, agent);
285
+ }
286
+ return agent;
287
+ }
288
+ /**
289
+ * Run the planner against `request` and return the resolved
290
+ * Echarts spec. Throws on planner failure - {@link prepareChart}
291
+ * catches and stashes the error in the cache entry.
292
+ */
293
+ async function runChartPlanner(config, request, options = {}) {
294
+ const { title, description, data } = request;
295
+ const { requestContext, abortSignal } = options;
296
+ const prompt = string.toDescription({
297
+ Title: title,
298
+ ...(description ? { Description: description } : {}),
299
+ "Dataset (JSON, one row per object)": JSON.stringify(data, null, 2),
300
+ });
301
+ const result = await getPlannerAgent(config).generate(prompt, {
302
+ structuredOutput: { schema: chartPlanSchema },
303
+ ...(requestContext ? { requestContext } : {}),
304
+ ...(abortSignal ? { abortSignal } : {}),
305
+ });
306
+ const plan = chartPlanSchema.parse(result.object);
307
+ const option = planToEchartsOption(plan, title, config.brand);
308
+ return { chartType: plan.chartType, option };
309
+ }
310
+ /* ------------------------------ cache helpers ------------------------------ */
311
+ /**
312
+ * Build the canonical cache key for a `chartId` owned by `userKey`.
313
+ *
314
+ * The identity is part of the key, not a filter applied after the read, so a
315
+ * chart id guessed or copied from another user's transcript resolves to a
316
+ * different key and simply misses. That miss is what the HTTP route turns into
317
+ * a 404, which is also the answer that leaks the least.
318
+ */
319
+ async function chartCacheKey(chartId, userKey) {
320
+ return (await CacheManager.getInstance()).generateKey([CHART_CACHE_NAMESPACE, chartId], userKey);
321
+ }
322
+ /**
323
+ * Persist a {@link Chart} entry under its `chartId`, owned by `userKey`.
324
+ * Refreshes the TTL on every write. Cache-layer failures are logged and
325
+ * swallowed so background runners never throw into the
326
+ * unhandled-rejection stream.
327
+ */
328
+ async function writeChart(entry, userKey) {
329
+ try {
330
+ const key = await chartCacheKey(entry.chartId, userKey);
331
+ await CacheManager.getInstanceSync().set(key, entry, {
332
+ ttl: CHART_CACHE_TTL_SEC,
333
+ });
334
+ }
335
+ catch (err) {
336
+ logger.warn("write-error", {
337
+ chartId: entry.chartId,
338
+ error: error.errorMessage(err),
339
+ });
340
+ }
341
+ }
342
+ /**
343
+ * Look up a chart `userKey` owns. Returns `undefined` on miss, on
344
+ * expiry, when another identity owns the id, or when the cache layer is
345
+ * unhealthy - never throws.
346
+ */
347
+ async function readChart(chartId, userKey) {
348
+ try {
349
+ const key = await chartCacheKey(chartId, userKey);
350
+ const v = await CacheManager.getInstanceSync().get(key);
351
+ return v ?? undefined;
352
+ }
353
+ catch (err) {
354
+ logger.warn("read-error", {
355
+ chartId,
356
+ error: error.errorMessage(err),
357
+ });
358
+ return undefined;
359
+ }
360
+ }
361
+ /**
362
+ * Mint a `chartId`, cache an empty `{ chartId }` placeholder
363
+ * synchronously, and kick off a background task that resolves the
364
+ * dataset and runs the planner. Returns the `chartId` once the
365
+ * placeholder lands so the first {@link fetchChart} call always
366
+ * sees an entry (no spurious 404 race).
367
+ *
368
+ * The background task swallows its own failures and writes them
369
+ * as `error` entries, so callers never see a rejected promise.
370
+ * Cache state machine:
371
+ *
372
+ * - just after this call returns: `{ chartId }` (processing)
373
+ * - on planner success: `{ chartId, result }`
374
+ * - on data / planner failure: `{ chartId, error }`
375
+ */
376
+ export async function prepareChart(opts) {
377
+ const chartId = hash.id();
378
+ await writeChart({ chartId }, opts.userKey);
379
+ logger.debug("queued", { chartId });
380
+ // Fire-and-forget. Failures land in the cache as `error` entries;
381
+ // never escape into an unhandled rejection.
382
+ void runPrepareChart(chartId, opts);
383
+ return { chartId };
384
+ }
385
+ async function runPrepareChart(chartId, opts) {
386
+ const startedAt = Date.now();
387
+ try {
388
+ const data = await opts.resolveData(opts.signal);
389
+ if (data.rows.length === 0) {
390
+ throw new ExecutionError("Dataset has no rows; nothing to chart");
391
+ }
392
+ const result = await runChartPlanner(opts.config, {
393
+ title: opts.title ?? "Chart",
394
+ ...(opts.description ? { description: opts.description } : {}),
395
+ data: data.rows,
396
+ }, {
397
+ ...(opts.requestContext ? { requestContext: opts.requestContext } : {}),
398
+ ...(opts.signal ? { abortSignal: opts.signal } : {}),
399
+ });
400
+ await writeChart({ chartId, result }, opts.userKey);
401
+ logger.info("done", {
402
+ chartId,
403
+ chartType: result.chartType,
404
+ elapsedMs: Date.now() - startedAt,
405
+ });
406
+ }
407
+ catch (err) {
408
+ logger.warn("error", { chartId, error: error.errorMessage(err) });
409
+ // The entry's `error` is rendered in the chat, so only an AppKitError's
410
+ // own message travels; anything else could carry upstream provider detail.
411
+ const errText = err instanceof AppKitError ? err.message : CHART_FAILED_MESSAGE;
412
+ await writeChart({ chartId, error: errText }, opts.userKey);
413
+ }
414
+ }
415
+ /**
416
+ * Long-poll the chart cache until the entry settles (`result` or
417
+ * `error` set), the entry is missing, or the server-side timeout
418
+ * elapses.
419
+ *
420
+ * Returns:
421
+ * - the resolved {@link Chart} when it settled, errored, or
422
+ * stayed in processing past `timeoutMs` (so the client can
423
+ * re-poll);
424
+ * - `undefined` when the entry is missing, expired, or owned by
425
+ * another identity (the consumer should treat as 404).
426
+ *
427
+ * `signal` lets the caller cancel ahead of timeout (e.g. the HTTP
428
+ * request closed). Cancellation propagates to the inter-poll sleep
429
+ * so the helper returns immediately.
430
+ */
431
+ export async function fetchChart(chartId, options) {
432
+ const timeoutMs = options.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
433
+ const intervalMs = options.intervalMs ?? DEFAULT_FETCH_INTERVAL_MS;
434
+ const deadline = Date.now() + timeoutMs;
435
+ let last;
436
+ while (true) {
437
+ options.signal?.throwIfAborted();
438
+ last = await readChart(chartId, options.userKey);
439
+ if (!last)
440
+ return undefined;
441
+ if (last.result !== undefined || last.error !== undefined)
442
+ return last;
443
+ const remaining = deadline - Date.now();
444
+ if (remaining <= 0)
445
+ return last;
446
+ await async.sleep(Math.min(intervalMs, remaining), options.signal);
447
+ }
448
+ }
449
+ /**
450
+ * AppKit's categorical chart palette (`--chart-cat-1` .. `--chart-cat-8` from
451
+ * `@databricks/appkit-ui`), as hex. Server-rendered chart specs cannot read the
452
+ * browser's CSS custom properties, so the values are mirrored here to keep a
453
+ * generated chart visually consistent with the AppKit-styled UI around it.
454
+ * Keep in sync with AppKit's stylesheet if it changes.
455
+ */
456
+ const APPKIT_CHART_PALETTE = [
457
+ "#2463EB", // blue
458
+ "#2EB88A", // teal
459
+ "#AB47BD", // purple
460
+ "#F69E23", // amber
461
+ "#DD2C4D", // rose
462
+ "#1BA3BB", // cyan
463
+ "#9B61D1", // lavender
464
+ "#34B262", // emerald
465
+ ];
466
+ /**
467
+ * Expand two brand hex colors into a legible categorical cycle. Echarts
468
+ * repeats the `color` array across series / categories, so a good default
469
+ * needs several distinct hues, not two. We seed with the brand primary and
470
+ * accent (the identity colors) and follow with AppKit's own categorical chart
471
+ * palette, so multi-series / many-slice charts stay readable and match the
472
+ * surrounding AppKit UI while the first one or two marks land on-brand.
473
+ */
474
+ function brandColorCycle(primary, accent) {
475
+ const spread = APPKIT_CHART_PALETTE;
476
+ const seen = new Set();
477
+ return [primary, accent, ...spread].filter((c) => {
478
+ const key = c.toLowerCase();
479
+ if (seen.has(key))
480
+ return false;
481
+ seen.add(key);
482
+ return true;
483
+ });
484
+ }
485
+ /**
486
+ * Derive an Echarts {@link ChartTheme} from a brand context: the primary +
487
+ * accent colors seed the series cycle, the sans stack becomes the base font,
488
+ * and the brand foreground becomes the base text color.
489
+ */
490
+ function brandChartTheme(brand) {
491
+ return {
492
+ color: brandColorCycle(brand.colors.primary, brand.colors.accent),
493
+ textStyle: { fontFamily: brand.typography.sans, color: brand.colors.foreground },
494
+ };
495
+ }
496
+ /* ----------------------------- echarts expansion ----------------------------- */
497
+ /**
498
+ * Expand a {@link ChartPlan} into a full Echarts `EChartsOption`
499
+ * JSON. Centralized here so the planner agent only fills in the
500
+ * compact plan shape; tooltip / animation / color / grid defaults
501
+ * stay consistent across charts and are easy to tune without
502
+ * retraining model behaviour.
503
+ *
504
+ * When `brand` is set, the resolved spec is themed with the brand's series
505
+ * color cycle and base text style (see {@link brandChartTheme}); otherwise
506
+ * Echarts' defaults apply.
507
+ */
508
+ function planToEchartsOption(plan, fallbackTitle, brand) {
509
+ const baseTitle = plan.title ?? fallbackTitle;
510
+ const grid = { left: 48, right: 24, top: 56, bottom: 48, containLabel: true };
511
+ const theme = brand ? brandChartTheme(brand) : undefined;
512
+ const themed = (option) => theme ? { ...theme, ...option } : option;
513
+ if (plan.chartType === "pie") {
514
+ // Echarts crashes on null pie slices - filter them out.
515
+ // `{name, value}` slices are the only valid pie data shape,
516
+ // so drop bare numbers / tuples / nulls the planner may
517
+ // have leaked into a pie series.
518
+ const slices = (plan.series[0]?.data ?? []).filter((d) => d !== null && typeof d === "object" && !Array.isArray(d));
519
+ return themed({
520
+ title: { text: baseTitle, left: "center" },
521
+ tooltip: { trigger: "item" },
522
+ legend: { bottom: 0 },
523
+ series: [
524
+ {
525
+ name: plan.series[0]?.name ?? baseTitle,
526
+ type: "pie",
527
+ radius: ["35%", "65%"],
528
+ data: slices,
529
+ },
530
+ ],
531
+ });
532
+ }
533
+ if (plan.chartType === "scatter") {
534
+ // Echarts crashes on null scatter points - keep only valid
535
+ // `[x, y]` tuples. Bare numbers / objects / nulls from a
536
+ // mismatched plan get dropped silently.
537
+ return themed({
538
+ title: { text: baseTitle, left: "center" },
539
+ tooltip: { trigger: "item" },
540
+ legend: { bottom: 0 },
541
+ grid,
542
+ xAxis: { type: "value", name: plan.xAxisLabel },
543
+ yAxis: { type: "value", name: plan.yAxisLabel },
544
+ series: plan.series.map((s) => ({
545
+ name: s.name,
546
+ type: "scatter",
547
+ data: s.data.filter((d) => Array.isArray(d) && d.length === 2),
548
+ })),
549
+ });
550
+ }
551
+ // bar / line / area share the same axis layout.
552
+ const isArea = plan.chartType === "area";
553
+ const seriesType = plan.chartType === "bar" ? "bar" : "line";
554
+ return themed({
555
+ title: { text: baseTitle, left: "center" },
556
+ tooltip: { trigger: "axis" },
557
+ legend: { bottom: 0 },
558
+ grid,
559
+ xAxis: {
560
+ type: "category",
561
+ data: plan.categories ?? [],
562
+ name: plan.xAxisLabel,
563
+ },
564
+ yAxis: { type: "value", name: plan.yAxisLabel },
565
+ series: plan.series.map((s) => ({
566
+ name: s.name,
567
+ type: seriesType,
568
+ data: s.data,
569
+ smooth: seriesType === "line",
570
+ ...(isArea ? { areaStyle: {} } : {}),
571
+ })),
572
+ });
573
+ }
574
+ /* ----------------------------- render_data tool ----------------------------- */
575
+ /**
576
+ * Build the `render_data` Mastra tool bound to the given plugin
577
+ * config. Auto-wired as a system tool on every agent (see
578
+ * `agents.ts`); per-agent tools can shadow it by registering a
579
+ * same-named entry.
580
+ *
581
+ * Thin wrapper over {@link prepareChart} for callers that already
582
+ * have a dataset in hand. Mints a `chartId` synchronously, caches
583
+ * an empty placeholder, and kicks off the chart-planner in the
584
+ * background. Returns just the `chartId`; the host UI resolves
585
+ * `[chart:<chartId>]` markers by hitting the plugin's
586
+ * `/embed/chart/:id` route.
587
+ *
588
+ * For Genie statement results, prefer the Genie agent's
589
+ * `prepare_chart` tool, which accepts a `statement_id` and
590
+ * resolves the rows lazily.
591
+ */
592
+ export function buildRenderDataTool(config) {
593
+ return createTool({
594
+ id: "render_data",
595
+ description: string.toDescription([
596
+ `
597
+ Submit a tabular dataset for inline rendering as a chart in
598
+ the user's view. Pass a title, the raw rows (array of objects
599
+ keyed by column name), and an optional one-line description
600
+ of the insight to highlight. Returns a short \`chartId\`;
601
+ the chart renders inline at the position you embed the
602
+ matching \`[chart:<chartId>]\` marker.
603
+ `,
604
+ `
605
+ Placement contract: embed \`[chart:<chartId>]\` on its own
606
+ line (blank lines above and below) wherever you want the
607
+ chart to appear in your reply. The chart resolves
608
+ asynchronously - the tool returns the id immediately and the
609
+ host UI fetches the chart from the cache once the planner
610
+ lands. You can call \`render_data\` multiple times in the
611
+ same turn (the tool is parallel-safe) and interleave the
612
+ markers with prose so each chart sits next to its
613
+ commentary.
614
+ `,
615
+ `
616
+ Use whenever a SQL row set, API response, or hand-built
617
+ dataset would land better as a picture than as a list or
618
+ table. Cap input at a few hundred rows; sample or aggregate
619
+ larger datasets first.
620
+ `,
621
+ ]),
622
+ inputSchema: chartPlannerRequestSchema,
623
+ outputSchema: wire.ChartSchema.pick({ chartId: true }),
624
+ execute: async (input, ctxRaw) => {
625
+ const { title, description, data } = input;
626
+ const ctx = ctxRaw;
627
+ return prepareChart({
628
+ config,
629
+ userKey: resolveUserKey(ctx?.requestContext),
630
+ title,
631
+ ...(description ? { description } : {}),
632
+ resolveData: () => Promise.resolve({ rows: data }),
633
+ ...(ctx?.requestContext ? { requestContext: ctx.requestContext } : {}),
634
+ });
635
+ },
636
+ });
637
+ }
638
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2hhcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTJCRztBQUVILE9BQU8sRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLGNBQWMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQy9FLE9BQU8sRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFxQixNQUFNLHdCQUF3QixDQUFDO0FBQzVGLE9BQU8sRUFBRSxJQUFJLEVBQWdDLE1BQU0sMEJBQTBCLENBQUM7QUFDOUUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ2hELE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUUzQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDaEQsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUV4QixPQUFPLEVBQUUsY0FBYyxFQUEyQixNQUFNLFVBQVUsQ0FBQztBQUNuRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBRXJDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7QUFFMUMsNkVBQTZFO0FBRTdFOzs7Ozs7R0FNRztBQUNILE1BQU0sbUJBQW1CLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQztBQUVwQyxzREFBc0Q7QUFDdEQsTUFBTSxxQkFBcUIsR0FBRyxjQUFjLENBQUM7QUFFN0MsbUVBQW1FO0FBQ25FLE1BQU0sd0JBQXdCLEdBQUcsTUFBTSxDQUFDO0FBRXhDLHVEQUF1RDtBQUN2RCxNQUFNLHlCQUF5QixHQUFHLEdBQUcsQ0FBQztBQUV0QyxvRUFBb0U7QUFDcEUsTUFBTSxvQkFBb0IsR0FBRyx5QkFBeUIsQ0FBQztBQUV2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TSxFQUFFLEVBQUU7WUFDL0IsTUFBTSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLEdBQUcsS0FBNEIsQ0FBQztZQUNsRSxNQUFNLEdBQUcsR0FBRyxNQUF5RCxDQUFDO1lBQ3RFLE9BQU8sWUFBWSxDQUFDO2dCQUNsQixNQUFNO2dCQUNOLE9BQU8sRUFBRSxjQUFjLENBQUMsR0FBRyxFQUFFLGNBQWMsQ0FBQztnQkFDNUMsS0FBSztnQkFDTCxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ3ZDLFdBQVcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDO2dCQUNsRCxHQUFHLENBQUMsR0FBRyxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUMsRUFBRSxjQUFjLEVBQUUsR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7YUFDdkUsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztLQUNGLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENoYXJ0IHBsYW5uZXIgKyBjaGFydCBjYWNoZS5cbiAqXG4gKiBTZWxmLWNvbnRhaW5lZCBjaGFydCBzdWJzeXN0ZW0gd2l0aCB0d28gbGF5ZXJzOlxuICpcbiAqICAgMS4gSW5uZXIgcGxhbm5lciBhZ2VudCAocHJpdmF0ZSkuIFB1cmUgZGF0YXNldC1pbiAvXG4gKiAgICAgIGBFQ2hhcnRzT3B0aW9uYC1vdXQgYnJhaW4uIERyaXZlbiBieSB7QGxpbmsgcHJlcGFyZUNoYXJ0fTtcbiAqICAgICAgY2FsbGVycyBuZXZlciBpbnN0YW50aWF0ZSBpdCBkaXJlY3RseS5cbiAqICAgMi4ge0BsaW5rIHByZXBhcmVDaGFydH06IG9yY2hlc3RyYXRpb24gb24gdG9wIG9mIHRoZSBwbGFubmVyLlxuICogICAgICBNaW50cyBhIGBjaGFydElkYCwgY2FjaGVzIGFuIGVtcHR5IGB7IGNoYXJ0SWQgfWAgcmVjb3JkXG4gKiAgICAgIHN5bmNocm9ub3VzbHksIHRoZW4gcmVzb2x2ZXMgdGhlIGRhdGFzZXQgYW5kIHJ1bnMgdGhlXG4gKiAgICAgIHBsYW5uZXIgaW4gdGhlIGJhY2tncm91bmQuIFRoZSB0ZXJtaW5hbCBlbnRyeSBzZXR0bGVzIHdpdGhcbiAqICAgICAgZWl0aGVyIGByZXN1bHRgIChzdWNjZXNzKSBvciBgZXJyb3JgIChmYWlsdXJlKS4gQm90aFxuICogICAgICB1bmRlZmluZWQgbWVhbnMgdGhlIGVudHJ5IGlzIHN0aWxsIHByb2Nlc3NpbmcuXG4gKlxuICogVGhlIGNhY2hlIHN1cmZhY2UgKHtAbGluayBmZXRjaENoYXJ0fSkgaXMgdGhlIG9ubHkgc3RhdGUgdGhlXG4gKiBIVFRQIHJvdXRlIGFuZCB0aGUgY2hhcnQtcHJvZHVjaW5nIHRvb2xzIHNoYXJlLiBgcHJlcGFyZUNoYXJ0YFxuICogaXMgZGF0YXNldC1hZ25vc3RpYyAtIGNhbGxlcnMgc3VwcGx5IGEgYHJlc29sdmVEYXRhYCBjYWxsYmFja1xuICogdGhhdCBmZXRjaGVzIHRoZSByb3dzIGhvd2V2ZXIgdGhleSBsaWtlIChHZW5pZSBzdGF0ZW1lbnQsIGlubGluZVxuICogZGF0YXNldCwgY3VzdG9tIEFQSSkuIFRoZSBtb2R1bGUgaGFzIG5vIGtub3dsZWRnZSBvZiBHZW5pZSBvclxuICogc3RhdGVtZW50IGlkczsgdGhvc2UgY29uY2VybnMgbGl2ZSBpbiB0aGUgdG9vbHMgdGhhdCB3cmFwIGl0LlxuICpcbiAqIFdpcmUtZm9ybWF0IHNjaGVtYXMgbGl2ZSBpbiBgQGRieC10b29scy9zaGFyZWQtbWFzdHJhYCBzb1xuICogdGhlIGRlbW8gY2xpZW50IGFuZCBhbnkgb3RoZXIgVUkgY29uc3VtZXIgc2hhcmUgdGhlIGV4YWN0IHNhbWVcbiAqIHNoYXBlIHRoaXMgbW9kdWxlIHJlYWRzIGFuZCB3cml0ZXMuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IEFwcEtpdEVycm9yLCBDYWNoZU1hbmFnZXIsIEV4ZWN1dGlvbkVycm9yIH0gZnJvbSBcIkBkYXRhYnJpY2tzL2FwcGtpdFwiO1xuaW1wb3J0IHsgYXN5bmMsIGVycm9yLCBoYXNoLCBsb2csIHN0cmluZywgdHlwZSBCcmFuZENvbnRleHQgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgd2lyZSwgdHlwZSBDaGFydCwgdHlwZSBDaGFydFJlc3VsdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1tYXN0cmFcIjtcbmltcG9ydCB7IG1vZGVsIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLW1vZGVsXCI7XG5pbXBvcnQgeyBBZ2VudCB9IGZyb20gXCJAbWFzdHJhL2NvcmUvYWdlbnRcIjtcbmltcG9ydCB0eXBlIHsgUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiQG1hc3RyYS9jb3JlL3JlcXVlc3QtY29udGV4dFwiO1xuaW1wb3J0IHsgY3JlYXRlVG9vbCB9IGZyb20gXCJAbWFzdHJhL2NvcmUvdG9vbHNcIjtcbmltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5cbmltcG9ydCB7IHJlc29sdmVVc2VyS2V5LCB0eXBlIE1hc3RyYVBsdWdpbkNvbmZpZyB9IGZyb20gXCIuL2NvbmZpZ1wiO1xuaW1wb3J0IHsgYnVpbGRNb2RlbCB9IGZyb20gXCIuL21vZGVsXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJtYXN0cmEvY2hhcnRcIik7XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBjb25zdGFudHMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbi8qKlxuICogVFRMIGZvciBjYWNoZWQgY2hhcnQgZW50cmllcy4gT25lIGhvdXIgYmFsYW5jZXMgXCJsb25nIGVub3VnaCBmb3JcbiAqIHRoZSBob3N0IFVJIHRvIGZldGNoIHRoZSBjaGFydCB3ZWxsIGFmdGVyIHRoZSBtb2RlbCBmaW5pc2hlZFxuICogdGFsa2luZ1wiIGFnYWluc3QgXCJzaG9ydCBlbm91Z2ggdGhhdCBhYmFuZG9uZWQgY2hhcnQgaWRzIGRvbid0XG4gKiBwaW4gc3RvcmFnZVwiLiBNYXRjaGVzIHRoZSB0eXBpY2FsIERhdGFicmlja3MgT0JPIHRva2VuIGxpZmV0aW1lXG4gKiBzbyBhbnkgZGF0YSByZS1yZXNvbHV0aW9uIHN0YXlzIGluc2lkZSB0aGUgb3JpZ2luYWwgYXV0aCB3aW5kb3cuXG4gKi9cbmNvbnN0IENIQVJUX0NBQ0hFX1RUTF9TRUMgPSA2MCAqIDYwO1xuXG4vKiogQ2FjaGUgbmFtZXNwYWNlOyBrZWVwcyB0aGUgY2hhcnQga2V5c3BhY2UgdGlkeS4gKi9cbmNvbnN0IENIQVJUX0NBQ0hFX05BTUVTUEFDRSA9IFwibWFzdHJhOmNoYXJ0XCI7XG5cbi8qKiBEZWZhdWx0IHNlcnZlci1zaWRlIGxvbmctcG9sbCBidWRnZXQgZm9yIHtAbGluayBmZXRjaENoYXJ0fS4gKi9cbmNvbnN0IERFRkFVTFRfRkVUQ0hfVElNRU9VVF9NUyA9IDYwXzAwMDtcblxuLyoqIERlZmF1bHQgaW50ZXItcG9sbCBzbGVlcCBmb3Ige0BsaW5rIGZldGNoQ2hhcnR9LiAqL1xuY29uc3QgREVGQVVMVF9GRVRDSF9JTlRFUlZBTF9NUyA9IDI1MDtcblxuLyoqIFN0YWJsZSB0ZXh0IHN0b3JlZCBvbiBhIGNoYXJ0IGVudHJ5IHdob3NlIHBsYW5uZXIgcnVuIGZhaWxlZC4gKi9cbmNvbnN0IENIQVJUX0ZBSUxFRF9NRVNTQUdFID0gXCJDaGFydCBnZW5lcmF0aW9uIGZhaWxlZFwiO1xuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHNjaGVtYXMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKipcbiAqIE9uZSBzZXJpZXMgZGF0YSBwb2ludC4gV2lkZSB2YXJpYW50IHNldCBzbyB0aGUgcGxhbm5lciBhZ2VudCBjYW5cbiAqIGZhaXRoZnVsbHkgcGFzcyB0aHJvdWdoIHdoYXRldmVyIHRoZSBTUUwgcm93IHNldCBjb250YWluZWRcbiAqIChudW1iZXJzLCBzdHJpbmdpZmllZCBudW1iZXJzLCBudWxscyBmb3IgbWlzc2luZyBtZWFzdXJlbWVudHMsXG4gKiBgW3gsIHldYCB0dXBsZXMgZm9yIHNjYXR0ZXIsIGB7bmFtZSwgdmFsdWV9YCBzbGljZXMgZm9yIHBpZSlcbiAqIHdpdGhvdXQgdGhlIHN0cnVjdHVyZWQtb3V0cHV0IGd1YXJkIHJlamVjdGluZyB0aGUgd2hvbGUgcGxhbi5cbiAqXG4gKiBUaHJlZSBsYXllcnMgb2YgdG9sZXJhbmNlOlxuICpcbiAqICAgMS4ge0BsaW5rIHoucHJlcHJvY2Vzc30gbm9ybWFsaXplcyB3aXJlIHNoYXBlcyBCRUZPUkUgdW5pb25cbiAqICAgICAgZGlzcGF0Y2g6IHN0cmluZ2lmaWVkIG51bWJlcnMgcGFyc2UgdG8gbnVtYmVycywgZmluaXRlXG4gKiAgICAgIGNoZWNrcyByZWplY3QgYE5hTmAgLyBgSW5maW5pdHlgLCAyLWVsZW1lbnQgYXJyYXlzIGNvZXJjZVxuICogICAgICB0dXBsZSBjb21wb25lbnRzLCBhbmQgYHt2YWx1ZX1gIG9iamVjdHMgd2l0aCBtaXNzaW5nIC9cbiAqICAgICAgc3RyaW5naWZpZWQgYHZhbHVlYCBnZXQgY29lcmNlZCBvciByZWplY3RlZCB1bmlmb3JtbHkuXG4gKiAgICAgIEFueXRoaW5nIG5vdCBoYW5kbGVhYmxlIGJlY29tZXMgYG51bGxgLlxuICogICAyLiBUaGUgdW5pb24gYWNjZXB0cyBgbnVsbGAgYXMgYSBmaXJzdC1jbGFzcyB2YXJpYW50LiBFY2hhcnRzXG4gKiAgICAgIHJlbmRlcnMgbnVsbCBhcyBhIGdhcCBvbiBiYXIgLyBsaW5lIC8gYXJlYSAod2hpY2ggaXMgdGhlXG4gKiAgICAgIHJpZ2h0IHZpc3VhbCBzaWduYWwgZm9yIFwibWlzc2luZyByZWFkaW5nXCIpLiBTY2F0dGVyIGFuZFxuICogICAgICBwaWUgZmlsdGVyIG51bGxzIGluIHtAbGluayBwbGFuVG9FY2hhcnRzT3B0aW9ufSBiZWNhdXNlXG4gKiAgICAgIEVjaGFydHMgY3Jhc2hlcyBvbiBudWxsIHR1cGxlcyAvIHNsaWNlcy5cbiAqICAgMy4ge0BsaW5rIHoudW5pb24jY2F0Y2h9IGJhY2tzdG9wcyB0aGUgd2hvbGUgdGhpbmc6IGlmXG4gKiAgICAgIHByZXByb2Nlc3Mgc29tZWhvdyBwcm9kdWNlcyBhIHNoYXBlIHRoYXQgc3RpbGwgZG9lc24ndFxuICogICAgICBtYXRjaCBhbnkgdmFyaWFudCwgdGhlIGJhZCBpdGVtIGJlY29tZXMgYG51bGxgIGluc3RlYWQgb2ZcbiAqICAgICAgdGFraW5nIGRvd24gdGhlIGVudGlyZSBjaGFydCB3aXRoIGFcbiAqICAgICAgYFN0cnVjdHVyZWQgb3V0cHV0IHZhbGlkYXRpb24gZmFpbGVkYCBlcnJvci5cbiAqL1xuY29uc3QgY2hhcnREYXRhUG9pbnRTY2hlbWEgPSB6XG4gIC5wcmVwcm9jZXNzKFxuICAgICh2KSA9PiB7XG4gICAgICBpZiAodiA9PT0gbnVsbCB8fCB2ID09PSB1bmRlZmluZWQpIHJldHVybiBudWxsO1xuICAgICAgaWYgKHR5cGVvZiB2ID09PSBcIm51bWJlclwiKSByZXR1cm4gTnVtYmVyLmlzRmluaXRlKHYpID8gdiA6IG51bGw7XG4gICAgICBpZiAodHlwZW9mIHYgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgY29uc3QgbiA9IE51bWJlcih2KTtcbiAgICAgICAgcmV0dXJuIE51bWJlci5pc0Zpbml0ZShuKSA/IG4gOiBudWxsO1xuICAgICAgfVxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkodikgJiYgdi5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgY29uc3QgeCA9IHR5cGVvZiB2WzBdID09PSBcIm51bWJlclwiID8gdlswXSA6IE51bWJlcih2WzBdKTtcbiAgICAgICAgY29uc3QgeSA9IHR5cGVvZiB2WzFdID09PSBcIm51bWJlclwiID8gdlsxXSA6IE51bWJlcih2WzFdKTtcbiAgICAgICAgcmV0dXJuIE51bWJlci5pc0Zpbml0ZSh4KSAmJiBOdW1iZXIuaXNGaW5pdGUoeSkgPyBbeCwgeV0gOiBudWxsO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGVvZiB2ID09PSBcIm9iamVjdFwiICYmIHYgIT09IG51bGwgJiYgXCJ2YWx1ZVwiIGluIHYpIHtcbiAgICAgICAgY29uc3Qgb2JqID0gdiBhcyB7IG5hbWU/OiB1bmtub3duOyB2YWx1ZTogdW5rbm93biB9O1xuICAgICAgICBjb25zdCB2YWwgPSB0eXBlb2Ygb2JqLnZhbHVlID09PSBcIm51bWJlclwiID8gb2JqLnZhbHVlIDogTnVtYmVyKG9iai52YWx1ZSk7XG4gICAgICAgIGlmICghTnVtYmVyLmlzRmluaXRlKHZhbCkpIHJldHVybiBudWxsO1xuICAgICAgICAvLyBDb2VyY2UgbnVtZXJpYyAvIGJvb2xlYW4gLyBudWxsaXNoIG5hbWVzIHRvIHN0cmluZ3Mgc28gYVxuICAgICAgICAvLyBwaWUgc2xpY2Uga2V5ZWQgb24gYSB5ZWFyIChgMjAyNGApIG9yIGNhdGVnb3J5IGlkIGlzXG4gICAgICAgIC8vIGFjY2VwdGVkIHdpdGhvdXQgcm91bmQtdHJpcHBpbmcgdGhyb3VnaCB0aGUgY2F0Y2ggYXJtLlxuICAgICAgICBjb25zdCByYXdOYW1lID0gb2JqLm5hbWU7XG4gICAgICAgIGNvbnN0IG5hbWUgPSB0eXBlb2YgcmF3TmFtZSA9PT0gXCJzdHJpbmdcIiA/IHJhd05hbWUgOiByYXdOYW1lID09IG51bGwgPyBcIlwiIDogU3RyaW5nKHJhd05hbWUpO1xuICAgICAgICByZXR1cm4geyBuYW1lLCB2YWx1ZTogdmFsIH07XG4gICAgICB9XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9LFxuICAgIHoudW5pb24oW1xuICAgICAgei5udW1iZXIoKSxcbiAgICAgIHoubnVsbCgpLFxuICAgICAgLy8gYFt4LCB5XWAgc2NhdHRlciBwb2ludC4gTW9kZWxsZWQgYXMgYSBsZW5ndGgtY29uc3RyYWluZWRcbiAgICAgIC8vIGhvbW9nZW5lb3VzIGFycmF5IHJhdGhlciB0aGFuIGB6LnR1cGxlYDogWm9kIGVtaXRzIGEgdHVwbGUgYXNcbiAgICAgIC8vIEpTT04gU2NoZW1hIDIwMjAtMTIgYHByZWZpeEl0ZW1zYCwgYW5kIERhdGFicmlja3MnIEdlbWluaVxuICAgICAgLy8gZW5kcG9pbnRzIHJlamVjdCBhIGByZXNwb25zZV9qc29uX3NjaGVtYWAgY29udGFpbmluZyBpdFxuICAgICAgLy8gKFwibXVzdCBiZSBhIGJvb2xlYW4gb3IgYW4gb2JqZWN0XCIsIHNpbmNlIGBpdGVtc2AgaXMgYWJzZW50KS5cbiAgICAgIC8vIGB6LmFycmF5KHoubnVtYmVyKCkpLmxlbmd0aCgyKWAgZW1pdHMgYGl0ZW1zYCArIGBtaW5JdGVtc2AgL1xuICAgICAgLy8gYG1heEl0ZW1zYCwgd2hpY2ggZXZlcnkgcHJvdmlkZXIgdW5kZXJzdGFuZHMsIGFuZCB2YWxpZGF0ZXNcbiAgICAgIC8vIHRoZSBzYW1lIHR3by1udW1iZXIgc2hhcGUuXG4gICAgICB6LmFycmF5KHoubnVtYmVyKCkpLmxlbmd0aCgyKSxcbiAgICAgIHoub2JqZWN0KHsgbmFtZTogei5zdHJpbmcoKSwgdmFsdWU6IHoubnVtYmVyKCkgfSksXG4gICAgXSksXG4gIClcbiAgLmNhdGNoKG51bGwpO1xuXG4vKipcbiAqIENvbXBhY3QsIG1vZGVsLWZyaWVuZGx5IHJlcHJlc2VudGF0aW9uIG9mIGFuIEVjaGFydHMgc3BlYy4gVGhlXG4gKiBwbGFubmVyIGFnZW50IGVtaXRzIHRoaXM7IHtAbGluayBwbGFuVG9FY2hhcnRzT3B0aW9ufSBleHBhbmRzIGl0XG4gKiBpbnRvIGEgcmVhbCBgRUNoYXJ0c09wdGlvbmAgSlNPTi4gVHdvIGxheWVycyBiZWNhdXNlIGxldHRpbmcgdGhlXG4gKiBtb2RlbCBmaWxsIGluIGEgZnVsbHktdHlwZWQgYEVDaGFydHNPcHRpb25gIGlzIGJyaXR0bGUgKGh1bmRyZWRzXG4gKiBvZiBvcHRpb25hbCBmaWVsZHMsIGRlZXAgdW5pb25zLCB2ZXJzaW9uLWRlcGVuZGVudCBzaGFwZXMpLiBBXG4gKiBzbWFsbCBcImNoYXJ0IHBsYW5cIiBzY2hlbWEgaXMgbXVjaCBtb3JlIHJlbGlhYmxlIGZvciBhIGZhc3QgbW9kZWxcbiAqIGFuZCBrZWVwcyBhbmltYXRpb24gLyB0b29sdGlwIC8gc3R5bGluZyBkZWZhdWx0cyBjb25zaXN0ZW50XG4gKiBhY3Jvc3MgY2hhcnRzLlxuICovXG5leHBvcnQgY29uc3QgY2hhcnRQbGFuU2NoZW1hID0gei5vYmplY3Qoe1xuICBjaGFydFR5cGU6IHdpcmUuQ2hhcnRUeXBlU2NoZW1hLFxuICB0aXRsZTogelxuICAgIC5zdHJpbmcoKVxuICAgIC5vcHRpb25hbCgpXG4gICAgLmRlc2NyaWJlKFxuICAgICAgc3RyaW5nLnRvRGVzY3JpcHRpb24oYFxuICAgICAgICBTaG9ydCB0aXRsZSBzaG93biBhYm92ZSB0aGUgY2hhcnQuIE9wdGlvbmFsOyBkZWZhdWx0cyB0byB0aGVcbiAgICAgICAgXFxgdGl0bGVcXGAgYXJndW1lbnQgdGhlIGNhbGxlciBwYXNzZWQgaW4uXG4gICAgICBgKSxcbiAgICApLFxuICB4QXhpc0xhYmVsOiB6XG4gICAgLnN0cmluZygpXG4gICAgLm9wdGlvbmFsKClcbiAgICAuZGVzY3JpYmUoXG4gICAgICBzdHJpbmcudG9EZXNjcmlwdGlvbihgXG4gICAgICAgIEF4aXMgbGFiZWwgYmVsb3cgdGhlIGNoYXJ0LiBVc2VkIGZvciBiYXIgLyBsaW5lIC8gYXJlYSAvIHNjYXR0ZXI7XG4gICAgICAgIGlnbm9yZWQgZm9yIHBpZS5cbiAgICAgIGApLFxuICAgICksXG4gIHlBeGlzTGFiZWw6IHpcbiAgICAuc3RyaW5nKClcbiAgICAub3B0aW9uYWwoKVxuICAgIC5kZXNjcmliZShcbiAgICAgIHN0cmluZy50b0Rlc2NyaXB0aW9uKGBcbiAgICAgICAgQXhpcyBsYWJlbCB0byB0aGUgbGVmdCBvZiB0aGUgY2hhcnQuIFVzZWQgZm9yIGJhciAvIGxpbmUgLyBhcmVhIC9cbiAgICAgICAgc2NhdHRlcjsgaWdub3JlZCBmb3IgcGllLlxuICAgICAgYCksXG4gICAgKSxcbiAgY2F0ZWdvcmllczogelxuICAgIC5hcnJheSh6LnN0cmluZygpKVxuICAgIC5vcHRpb25hbCgpXG4gICAgLmRlc2NyaWJlKFxuICAgICAgc3RyaW5nLnRvRGVzY3JpcHRpb24oYFxuICAgICAgICBYLWF4aXMgY2F0ZWdvcnkgbGFiZWxzIGZvciBcXGBiYXJcXGAgLyBcXGBsaW5lXFxgIC8gXFxgYXJlYVxcYCBjaGFydHNcbiAgICAgICAgKG9uZSBwZXIgZGF0YSBwb2ludCBpbiBlYWNoIHNlcmllcykuIE9taXQgZm9yIFxcYHNjYXR0ZXJcXGAgKHVzZXNcbiAgICAgICAgW3gsIHldIHR1cGxlcykgYW5kIFxcYHBpZVxcYCAoZWFjaCBzbGljZSBjYXJyaWVzIGl0cyBvd24gXFxgbmFtZVxcYCkuXG4gICAgICBgKSxcbiAgICApLFxuICBzZXJpZXM6IHpcbiAgICAuYXJyYXkoXG4gICAgICB6Lm9iamVjdCh7XG4gICAgICAgIG5hbWU6IHouc3RyaW5nKCkuZGVzY3JpYmUoXG4gICAgICAgICAgc3RyaW5nLnRvRGVzY3JpcHRpb24oYFxuICAgICAgICAgICAgTGVnZW5kIG5hbWUgZm9yIHRoaXMgc2VyaWVzLlxuICAgICAgICAgIGApLFxuICAgICAgICApLFxuICAgICAgICBkYXRhOiB6LmFycmF5KGNoYXJ0RGF0YVBvaW50U2NoZW1hKS5kZXNjcmliZShcbiAgICAgICAgICBzdHJpbmcudG9EZXNjcmlwdGlvbihgXG4gICAgICAgICAgICBEYXRhIHBvaW50cy4gRm9yIFxcYGJhclxcYCAvIFxcYGxpbmVcXGAgLyBcXGBhcmVhXFxgLCBhbiBhcnJheSBvZlxuICAgICAgICAgICAgbnVtYmVycyBhbGlnbmVkIHRvIFxcYGNhdGVnb3JpZXNcXGAuIEZvciBcXGBzY2F0dGVyXFxgLCBhbiBhcnJheVxuICAgICAgICAgICAgb2YgXFxgW3gsIHldXFxgIG51bWVyaWMgdHVwbGVzLiBGb3IgXFxgcGllXFxgLCBhbiBhcnJheSBvZlxuICAgICAgICAgICAgXFxge25hbWUsIHZhbHVlfVxcYCBvYmplY3RzLlxuICAgICAgICAgIGApLFxuICAgICAgICApLFxuICAgICAgfSksXG4gICAgKVxuICAgIC5taW4oMSlcbiAgICAuZGVzY3JpYmUoXG4gICAgICBzdHJpbmcudG9EZXNjcmlwdGlvbihgXG4gICAgICAgIE9uZSBvciBtb3JlIHNlcmllcyB0byBwbG90LiBQaWUgY2hhcnRzIHVzZSBleGFjdGx5IG9uZSBzZXJpZXM7XG4gICAgICAgIGJhci9saW5lL2FyZWEgY2FuIHN0YWNrIG11bHRpcGxlIHNlcmllcyBzaGFyaW5nIHRoZSBzYW1lXG4gICAgICAgIFxcYGNhdGVnb3JpZXNcXGAgYXhpcy5cbiAgICAgIGApLFxuICAgICksXG59KTtcblxudHlwZSBDaGFydFBsYW4gPSB6LmluZmVyPHR5cGVvZiBjaGFydFBsYW5TY2hlbWE+O1xuXG4vKipcbiAqIENhbm9uaWNhbCBwbGFubmVyIGlucHV0IHNoYXBlLiBUb29scyB0aGF0IHNvdXJjZSByb3dzIGZyb20gYW5cbiAqIGlubGluZSBkYXRhc2V0IChgcmVuZGVyX2RhdGFgKSB1c2UgaXQgYXMgdGhlaXIgYGlucHV0U2NoZW1hYFxuICogdmVyYmF0aW07IHRvb2xzIHRoYXQgcmVzb2x2ZSByb3dzIGZyb20gYSByZW1vdGUgKGBwcmVwYXJlX2NoYXJ0YFxuICogb3ZlciBhIEdlbmllIHN0YXRlbWVudCkgYG9taXQoeyBkYXRhIH0pYCBhbmQgYGV4dGVuZGAgd2l0aCB0aGVpclxuICogb3duIGlkZW50aWZpZXIgZmllbGQsIHNvIHRoZSBmaWVsZC1sZXZlbCBgLmRlc2NyaWJlKClgIHRleHRcbiAqIHN0YXlzIGEgc2luZ2xlIHNvdXJjZSBvZiB0cnV0aC4gU2VydmVyLW9ubHkgLSB0aGUgVUkgbmV2ZXJcbiAqIHNlZXMgYSBwbGFubmVyIHJlcXVlc3QsIG9ubHkgdGhlIHJlc29sdmVkIHtAbGluayBDaGFydH0uXG4gKi9cbmV4cG9ydCBjb25zdCBjaGFydFBsYW5uZXJSZXF1ZXN0U2NoZW1hID0gei5vYmplY3Qoe1xuICB0aXRsZTogei5zdHJpbmcoKS5kZXNjcmliZShcbiAgICBzdHJpbmcudG9EZXNjcmlwdGlvbihgXG4gICAgICAgIENvbmNpc2UgdGl0bGUgc2hvd24gYWJvdmUgdGhlIGNoYXJ0IChlLmcuIFwiVG9wIDEwIFNLVXMgYnkgUmV2ZW51ZVwiKS5cbiAgICAgIGApLFxuICApLFxuICBkZXNjcmlwdGlvbjogelxuICAgIC5zdHJpbmcoKVxuICAgIC5vcHRpb25hbCgpXG4gICAgLmRlc2NyaWJlKFxuICAgICAgc3RyaW5nLnRvRGVzY3JpcHRpb24oYFxuICAgICAgICBPbmUtbGluZSBpbnRlbnQgdGhlIGNoYXJ0LXBsYW5uZXIgdXNlcyB3aGVuIHBpY2tpbmcgYSBjaGFydCB0eXBlXG4gICAgICAgIGFuZCBheGlzIGVuY29kaW5ncyAoZS5nLiBcImNvbXBhcmUgcXVhcnRlcmx5IHJldmVudWUgYWNyb3NzXG4gICAgICAgIHJlZ2lvbnNcIiwgXCJoaWdobGlnaHQgdGhlIHN0ZWVwIGRyb3AgYWZ0ZXIgcG9zaXRpb24gNVwiKS4gTm90IHNob3duXG4gICAgICAgIHRvIHRoZSB1c2VyLlxuICAgICAgYCksXG4gICAgKSxcbiAgZGF0YTogelxuICAgIC5hcnJheSh6LnJlY29yZCh6LnN0cmluZygpLCB6LnVua25vd24oKSkpXG4gICAgLm5vbmVtcHR5KFwiRGF0YSBtdXN0IGNvbnRhaW4gYXQgbGVhc3Qgb25lIHJvd1wiKVxuICAgIC5yZWFkb25seSgpXG4gICAgLmRlc2NyaWJlKFxuICAgICAgc3RyaW5nLnRvRGVzY3JpcHRpb24oYFxuICAgICAgICBUYWJ1bGFyIGRhdGFzZXQgdG8gY2hhcnQuIE9uZSBvYmplY3QgcGVyIHJvdywga2V5ZWQgYnkgY29sdW1uXG4gICAgICAgIG5hbWUuIFZhbHVlcyBtYXkgYmUgc3RyaW5ncywgbnVtYmVycywgYm9vbGVhbnMsIG9yIG51bGwuIFRoZVxuICAgICAgICBjaGFydC1wbGFubmVyIGRlY2lkZXMgd2hpY2ggY29sdW1ucyBhcmUgY2F0ZWdvcmllcyB2cy4gbnVtZXJpY1xuICAgICAgICBzZXJpZXMuIENhcCBhdCBhIGZldyBodW5kcmVkIHJvd3MgZm9yIGxlZ2liaWxpdHk7IHNhbXBsZSAvXG4gICAgICAgIGFnZ3JlZ2F0ZSBsYXJnZXIgZGF0YXNldHMgZmlyc3QuXG4gICAgICBgKSxcbiAgICApLFxufSk7XG5cbmV4cG9ydCB0eXBlIENoYXJ0UGxhbm5lclJlcXVlc3QgPSB6LmluZmVyPHR5cGVvZiBjaGFydFBsYW5uZXJSZXF1ZXN0U2NoZW1hPjtcblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHBsYW5uZXIgaW5zdHJ1Y3Rpb25zIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKipcbiAqIEZvcm1hdCB7QGxpbmsgd2lyZS5DaGFydFR5cGVTY2hlbWF9J3MgdmFyaWFudHMgYXMgYSBzaW5nbGVcbiAqIGh1bWFuLWZyaWVuZGx5IHN0cmluZyBvZiBgYCBgPHZhbHVlPmAgZm9yIDxkZXNjcmlwdGlvbj4gYGBcbiAqIGNsYXVzZXMgam9pbmVkIGJ5IHNlbWljb2xvbnMsIGRyYXduIGZyb20gZWFjaCB2YXJpYW50J3Mgb3duXG4gKiBgLmRlc2NyaWJlKClgIHNvIHRoZSBwbGFubmVyIHByb21wdCBzdGF5cyBpbiBsb2NrLXN0ZXAgd2l0aFxuICogdGhlIHNjaGVtYSBieSBjb25zdHJ1Y3Rpb24uXG4gKi9cbmZ1bmN0aW9uIGZvcm1hdENoYXJ0VHlwZVBpY2tlcigpOiBzdHJpbmcge1xuICByZXR1cm4gd2lyZS5DaGFydFR5cGVTY2hlbWEub3B0aW9uc1xuICAgIC5tYXAoKG9wdCkgPT4gYFxcYCR7b3B0LnZhbHVlfVxcYCBmb3IgJHtvcHQuZGVzY3JpcHRpb24gPz8gXCJcIn1gKVxuICAgIC5qb2luKFwiOyBcIik7XG59XG5cbi8qKlxuICogU3lzdGVtIHByb21wdCBmb3IgdGhlIGlubmVyIGNoYXJ0LXBsYW5uaW5nIGFnZW50LiBUdW5lZCBmb3IgYVxuICogZmFzdC10aWVyIG1vZGVsIChIYWlrdSwgR1BULTUtbWluaSwgR2VtaW5pIEZsYXNoIExpdGUpLlxuICovXG5jb25zdCBDSEFSVF9QTEFOTkVSX0lOU1RSVUNUSU9OUyA9IHN0cmluZy50b0Rlc2NyaXB0aW9uKGBcbiAgWW91IGRlc2lnbiBBcGFjaGUgRWNoYXJ0cyB2aXN1YWxpemF0aW9ucy4gVGhlIHVzZXIgZ2l2ZXMgeW91IGFcbiAgdGFidWxhciBkYXRhc2V0IChyb3dzIG9mIG9iamVjdHMpIHBsdXMgYSB0aXRsZSBhbmQgYW4gb3B0aW9uYWxcbiAgZGVzY3JpcHRpb24gb2YgdGhlIGludGVudC4gWW91IHByb2R1Y2UgYSBzbWFsbCBjaGFydCBwbGFuIChjaGFydFxuICB0eXBlLCBheGlzIGxhYmVscywgY2F0ZWdvcmllcywgc2VyaWVzKSB0aGF0IGJlc3QgY29udmV5cyB0aGUgZGF0YS5cblxuICBEZWNpc2lvbiBndWlkZS4gUGljayB0aGUgY2hhcnQgdHlwZSB3aG9zZSBkYXRhIHNoYXBlIG1hdGNoZXMgdGhlXG4gIGRhdGFzZXQgYW5kIHRoZSB1c2VyJ3MgaW50ZW50OiAke2Zvcm1hdENoYXJ0VHlwZVBpY2tlcigpfS5cblxuICBXaGVuIGluIGRvdWJ0IGJldHdlZW4gYmFyIGFuZCBsaW5lLCBwcmVmZXIgYmFyIGZvciB1bm9yZGVyZWRcbiAgY2F0ZWdvcmllcyBhbmQgbGluZSBmb3Igb3JkZXJlZCBvbmVzIChkYXRlcywgdGltZSBidWNrZXRzLCByYW5rcykuXG4gIE5ldmVyIHBpY2sgcGllIGZvciBtb3JlIHRoYW4gNyBzbGljZXMuXG5cbiAgRm9yIGJhciAvIGxpbmUgLyBhcmVhOiBwaWNrIG9uZSBjb2x1bW4gYXMgdGhlIGNhdGVnb3J5IGF4aXMgKHVzdWFsbHlcbiAgdGhlIG9ubHkgc3RyaW5nLXZhbHVlZCBjb2x1bW4pIGFuZCBvbmUgb3IgbW9yZSBudW1lcmljIGNvbHVtbnMgYXNcbiAgc2VyaWVzLiBTb3J0IGNhdGVnb3JpZXMgYnkgdGhlIHByaW1hcnkgc2VyaWVzIHZhbHVlIGRlc2NlbmRpbmcgdW5sZXNzXG4gIHRoZSBkYXRhIGlzIG5hdHVyYWxseSBvcmRlcmVkIChkYXRlcywgcmFua3MpLlxuXG4gIEZvciBwaWU6IHBpY2sgdGhlIGNhdGVnb3J5IGNvbHVtbiBmb3Igc2xpY2UgbmFtZXMgYW5kIG9uZSBudW1lcmljXG4gIGNvbHVtbiBmb3Igc2xpY2UgdmFsdWVzLiBFbWl0IGEgc2luZ2xlIHNlcmllcy5cblxuICBGb3Igc2NhdHRlcjogcGljayB0d28gbnVtZXJpYyBjb2x1bW5zIGFuZCBlbWl0IFxcYFt4LCB5XVxcYCB0dXBsZXMgaW4gYVxuICBzaW5nbGUgc2VyaWVzLlxuXG4gIEtlZXAgc2VyaWVzIG5hbWVzIGh1bWFuLXJlYWRhYmxlICh1c2UgdGhlIGNvbHVtbiBuYW1lOyB0aXRsZSBjYXNlIGl0XG4gIGxpZ2h0bHkgaWYgbmVlZGVkKS4gS2VlcCB0aXRsZXMgY29uY2lzZTsgZG8gbm90IHJlcGVhdCB0aGUgdXNlcidzXG4gIHRpdGxlIGluIHhBeGlzTGFiZWwgLyB5QXhpc0xhYmVsLlxuYCk7XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHBsYW5uZXIgYWdlbnQgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqXG4gKiBPbmUgcGxhbm5lciBgQWdlbnRgIHBlciBwbHVnaW4gY29uZmlnLiBDYWNoZWQgb24gY29uZmlnIG9iamVjdFxuICogaWRlbnRpdHkgc28gY2FsbGVycyBjYW4gYHByZXBhcmVDaGFydCh7IGNvbmZpZywgLi4uIH0pYCBmcm9tIGFcbiAqIGhvdCBwYXRoIHdpdGhvdXQgcGF5aW5nIHRoZSBBZ2VudC1jb25zdHJ1Y3RvciBjb3N0IGV2ZXJ5IGNhbGwuXG4gKiBgV2Vha01hcGAgbGV0cyByZXRpcmVkIGNvbmZpZ3MgKGUuZy4gdGVzdCByZWNvbmZpZ3VyYXRpb25zKVxuICogcmVsZWFzZSB0aGVpciBhZ2VudCB3aXRob3V0IG1hbnVhbCBldmljdGlvbi5cbiAqL1xuY29uc3QgcGxhbm5lckFnZW50cyA9IG5ldyBXZWFrTWFwPE1hc3RyYVBsdWdpbkNvbmZpZywgQWdlbnQ+KCk7XG5cbmZ1bmN0aW9uIGdldFBsYW5uZXJBZ2VudChjb25maWc6IE1hc3RyYVBsdWdpbkNvbmZpZyk6IEFnZW50IHtcbiAgbGV0IGFnZW50ID0gcGxhbm5lckFnZW50cy5nZXQoY29uZmlnKTtcbiAgaWYgKCFhZ2VudCkge1xuICAgIGFnZW50ID0gbmV3IEFnZW50KHtcbiAgICAgIGlkOiBcImNoYXJ0X3BsYW5uZXJcIixcbiAgICAgIG5hbWU6IFwiQ2hhcnQgUGxhbm5lclwiLFxuICAgICAgZGVzY3JpcHRpb246IFwiUGlja3MgY2hhcnQgdHlwZSBhbmQgYXhpcyBlbmNvZGluZ3MgZm9yIGEgZGF0YXNldC5cIixcbiAgICAgIGluc3RydWN0aW9uczogQ0hBUlRfUExBTk5FUl9JTlNUUlVDVElPTlMsXG4gICAgICBtb2RlbDogKHsgcmVxdWVzdENvbnRleHQgfSkgPT5cbiAgICAgICAgYnVpbGRNb2RlbChjb25maWcsIHJlcXVlc3RDb250ZXh0LCB7IG1vZGVsQ2xhc3M6IG1vZGVsLk1vZGVsQ2xhc3MuQ2hhdEZhc3QgfSksXG4gICAgfSk7XG4gICAgcGxhbm5lckFnZW50cy5zZXQoY29uZmlnLCBhZ2VudCk7XG4gIH1cbiAgcmV0dXJuIGFnZW50O1xufVxuXG4vKipcbiAqIFJ1biB0aGUgcGxhbm5lciBhZ2FpbnN0IGByZXF1ZXN0YCBhbmQgcmV0dXJuIHRoZSByZXNvbHZlZFxuICogRWNoYXJ0cyBzcGVjLiBUaHJvd3Mgb24gcGxhbm5lciBmYWlsdXJlIC0ge0BsaW5rIHByZXBhcmVDaGFydH1cbiAqIGNhdGNoZXMgYW5kIHN0YXNoZXMgdGhlIGVycm9yIGluIHRoZSBjYWNoZSBlbnRyeS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcnVuQ2hhcnRQbGFubmVyKFxuICBjb25maWc6IE1hc3RyYVBsdWdpbkNvbmZpZyxcbiAgcmVxdWVzdDogQ2hhcnRQbGFubmVyUmVxdWVzdCxcbiAgb3B0aW9uczogeyByZXF1ZXN0Q29udGV4dD86IFJlcXVlc3RDb250ZXh0OyBhYm9ydFNpZ25hbD86IEFib3J0U2lnbmFsIH0gPSB7fSxcbik6IFByb21pc2U8Q2hhcnRSZXN1bHQ+IHtcbiAgY29uc3QgeyB0aXRsZSwgZGVzY3JpcHRpb24sIGRhdGEgfSA9IHJlcXVlc3Q7XG4gIGNvbnN0IHsgcmVxdWVzdENvbnRleHQsIGFib3J0U2lnbmFsIH0gPSBvcHRpb25zO1xuICBjb25zdCBwcm9tcHQgPSBzdHJpbmcudG9EZXNjcmlwdGlvbih7XG4gICAgVGl0bGU6IHRpdGxlLFxuICAgIC4uLihkZXNjcmlwdGlvbiA/IHsgRGVzY3JpcHRpb246IGRlc2NyaXB0aW9uIH0gOiB7fSksXG4gICAgXCJEYXRhc2V0IChKU09OLCBvbmUgcm93IHBlciBvYmplY3QpXCI6IEpTT04uc3RyaW5naWZ5KGRhdGEsIG51bGwsIDIpLFxuICB9KTtcbiAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZ2V0UGxhbm5lckFnZW50KGNvbmZpZykuZ2VuZXJhdGUocHJvbXB0LCB7XG4gICAgc3RydWN0dXJlZE91dHB1dDogeyBzY2hlbWE6IGNoYXJ0UGxhblNjaGVtYSB9LFxuICAgIC4uLihyZXF1ZXN0Q29udGV4dCA/IHsgcmVxdWVzdENvbnRleHQgfSA6IHt9KSxcbiAgICAuLi4oYWJvcnRTaWduYWwgPyB7IGFib3J0U2lnbmFsIH0gOiB7fSksXG4gIH0pO1xuICBjb25zdCBwbGFuID0gY2hhcnRQbGFuU2NoZW1hLnBhcnNlKHJlc3VsdC5vYmplY3QpO1xuICBjb25zdCBvcHRpb24gPSBwbGFuVG9FY2hhcnRzT3B0aW9uKHBsYW4sIHRpdGxlLCBjb25maWcuYnJhbmQpO1xuICByZXR1cm4geyBjaGFydFR5cGU6IHBsYW4uY2hhcnRUeXBlLCBvcHRpb24gfTtcbn1cblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIGNhY2hlIGhlbHBlcnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbi8qKlxuICogQnVpbGQgdGhlIGNhbm9uaWNhbCBjYWNoZSBrZXkgZm9yIGEgYGNoYXJ0SWRgIG93bmVkIGJ5IGB1c2VyS2V5YC5cbiAqXG4gKiBUaGUgaWRlbnRpdHkgaXMgcGFydCBvZiB0aGUga2V5LCBub3QgYSBmaWx0ZXIgYXBwbGllZCBhZnRlciB0aGUgcmVhZCwgc28gYVxuICogY2hhcnQgaWQgZ3Vlc3NlZCBvciBjb3BpZWQgZnJvbSBhbm90aGVyIHVzZXIncyB0cmFuc2NyaXB0IHJlc29sdmVzIHRvIGFcbiAqIGRpZmZlcmVudCBrZXkgYW5kIHNpbXBseSBtaXNzZXMuIFRoYXQgbWlzcyBpcyB3aGF0IHRoZSBIVFRQIHJvdXRlIHR1cm5zIGludG9cbiAqIGEgNDA0LCB3aGljaCBpcyBhbHNvIHRoZSBhbnN3ZXIgdGhhdCBsZWFrcyB0aGUgbGVhc3QuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGNoYXJ0Q2FjaGVLZXkoY2hhcnRJZDogc3RyaW5nLCB1c2VyS2V5OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICByZXR1cm4gKGF3YWl0IENhY2hlTWFuYWdlci5nZXRJbnN0YW5jZSgpKS5nZW5lcmF0ZUtleShbQ0hBUlRfQ0FDSEVfTkFNRVNQQUNFLCBjaGFydElkXSwgdXNlcktleSk7XG59XG5cbi8qKlxuICogUGVyc2lzdCBhIHtAbGluayBDaGFydH0gZW50cnkgdW5kZXIgaXRzIGBjaGFydElkYCwgb3duZWQgYnkgYHVzZXJLZXlgLlxuICogUmVmcmVzaGVzIHRoZSBUVEwgb24gZXZlcnkgd3JpdGUuIENhY2hlLWxheWVyIGZhaWx1cmVzIGFyZSBsb2dnZWQgYW5kXG4gKiBzd2FsbG93ZWQgc28gYmFja2dyb3VuZCBydW5uZXJzIG5ldmVyIHRocm93IGludG8gdGhlXG4gKiB1bmhhbmRsZWQtcmVqZWN0aW9uIHN0cmVhbS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gd3JpdGVDaGFydChlbnRyeTogQ2hhcnQsIHVzZXJLZXk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IGNoYXJ0Q2FjaGVLZXkoZW50cnkuY2hhcnRJZCwgdXNlcktleSk7XG4gICAgYXdhaXQgQ2FjaGVNYW5hZ2VyLmdldEluc3RhbmNlU3luYygpLnNldChrZXksIGVudHJ5LCB7XG4gICAgICB0dGw6IENIQVJUX0NBQ0hFX1RUTF9TRUMsXG4gICAgfSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci53YXJuKFwid3JpdGUtZXJyb3JcIiwge1xuICAgICAgY2hhcnRJZDogZW50cnkuY2hhcnRJZCxcbiAgICAgIGVycm9yOiBlcnJvci5lcnJvck1lc3NhZ2UoZXJyKSxcbiAgICB9KTtcbiAgfVxufVxuXG4vKipcbiAqIExvb2sgdXAgYSBjaGFydCBgdXNlcktleWAgb3ducy4gUmV0dXJucyBgdW5kZWZpbmVkYCBvbiBtaXNzLCBvblxuICogZXhwaXJ5LCB3aGVuIGFub3RoZXIgaWRlbnRpdHkgb3ducyB0aGUgaWQsIG9yIHdoZW4gdGhlIGNhY2hlIGxheWVyIGlzXG4gKiB1bmhlYWx0aHkgLSBuZXZlciB0aHJvd3MuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlYWRDaGFydChjaGFydElkOiBzdHJpbmcsIHVzZXJLZXk6IHN0cmluZyk6IFByb21pc2U8Q2hhcnQgfCB1bmRlZmluZWQ+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBrZXkgPSBhd2FpdCBjaGFydENhY2hlS2V5KGNoYXJ0SWQsIHVzZXJLZXkpO1xuICAgIGNvbnN0IHYgPSBhd2FpdCBDYWNoZU1hbmFnZXIuZ2V0SW5zdGFuY2VTeW5jKCkuZ2V0PENoYXJ0PihrZXkpO1xuICAgIHJldHVybiB2ID8/IHVuZGVmaW5lZDtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLndhcm4oXCJyZWFkLWVycm9yXCIsIHtcbiAgICAgIGNoYXJ0SWQsXG4gICAgICBlcnJvcjogZXJyb3IuZXJyb3JNZXNzYWdlKGVyciksXG4gICAgfSk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gcHJlcGFyZUNoYXJ0IG9yY2hlc3RyYXRvciAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqIElucHV0cyB0byB7QGxpbmsgcHJlcGFyZUNoYXJ0fS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUHJlcGFyZUNoYXJ0T3B0aW9ucyB7XG4gIC8qKiBQbHVnaW4gY29uZmlnOyByZXNvbHZlcyB0aGUgcGxhbm5lciBhZ2VudCdzIG1vZGVsLiAqL1xuICBjb25maWc6IE1hc3RyYVBsdWdpbkNvbmZpZztcbiAgLyoqXG4gICAqIElkZW50aXR5IHRoYXQgb3ducyB0aGUgbWludGVkIGNoYXJ0LiBPbmx5IGEge0BsaW5rIGZldGNoQ2hhcnR9IGNhbGxcbiAgICogY2FycnlpbmcgdGhlIHNhbWUga2V5IHJlc29sdmVzIGl0LiBVc2Uge0BsaW5rIHJlc29sdmVVc2VyS2V5fS5cbiAgICovXG4gIHVzZXJLZXk6IHN0cmluZztcbiAgLyoqIERpc3BsYXkgdGl0bGUgZm9yd2FyZGVkIHRvIHRoZSBwbGFubmVyIGFnZW50LiAqL1xuICB0aXRsZT86IHN0cmluZztcbiAgLyoqIE9wdGlvbmFsIGludGVudCBoaW50IGZvcndhcmRlZCB0byB0aGUgcGxhbm5lciBhZ2VudC4gKi9cbiAgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBSZXNvbHZlcyB0aGUgcm93cyB0byBjaGFydC4gQ2FsbGVkIG9uY2UsIGluIHRoZSBiYWNrZ3JvdW5kLlxuICAgKiBBbnkgdGhyb3duIGVycm9yIGxhbmRzIGluIHRoZSBjYWNoZSBhcyB0aGUgZW50cnkncyBgZXJyb3JgXG4gICAqIGZpZWxkIChuZXZlciBwcm9wYWdhdGVkIHRvIHRoZSBjYWxsZXIgb2Yge0BsaW5rIHByZXBhcmVDaGFydH0pLlxuICAgKiBBbiBlbXB0eSBgcm93c2AgYXJyYXkgaXMgcmVqZWN0ZWQgYXMgYFwiZGF0YXNldCBoYXMgbm8gcm93cztcbiAgICogbm90aGluZyB0byBjaGFydFwiYC5cbiAgICovXG4gIHJlc29sdmVEYXRhOiAoc2lnbmFsPzogQWJvcnRTaWduYWwpID0+IFByb21pc2U8eyByb3dzOiBSZWFkb25seUFycmF5PFJlY29yZDxzdHJpbmcsIHVua25vd24+PiB9PjtcbiAgLyoqXG4gICAqIFBlci1yZXF1ZXN0IGBSZXF1ZXN0Q29udGV4dGAuIEZvcndhcmRlZCB0byB0aGUgcGxhbm5lciBhZ2VudCBzb1xuICAgKiB1c2VyLXNjb3BlZCBtb2RlbCByZXNvbHV0aW9uIChPQk8pIHN0YXlzIGluIGVmZmVjdC5cbiAgICovXG4gIHJlcXVlc3RDb250ZXh0PzogUmVxdWVzdENvbnRleHQ7XG4gIC8qKlxuICAgKiBDb29wZXJhdGl2ZSBjYW5jZWxsYXRpb24uIEZvcndhcmRlZCB0byBgcmVzb2x2ZURhdGFgIGFuZCB0aGVcbiAgICogcGxhbm5lciBhZ2VudC4gTm90ZTogdGhlIGNoYXJ0IHRhc2sgY29udGludWVzIHJ1bm5pbmcgaW4gdGhlXG4gICAqIGJhY2tncm91bmQgYWZ0ZXIgdGhlIHBhcmVudCByZXF1ZXN0IGVuZHMsIHNvIGV4dGVybmFsIGFib3J0XG4gICAqIHNpZ25hbHMgYXJlIGJlc3QtZWZmb3J0OyB0eXBpY2FsIHVzZSBpcyB0byBsZWF2ZSB0aGlzIHVuc2V0XG4gICAqIGFuZCBsZXQgdGhlIDFoIFRUTCBjYXAgc3RhbGUgZW50cmllcy5cbiAgICovXG4gIHNpZ25hbD86IEFib3J0U2lnbmFsO1xufVxuXG4vKipcbiAqIE1pbnQgYSBgY2hhcnRJZGAsIGNhY2hlIGFuIGVtcHR5IGB7IGNoYXJ0SWQgfWAgcGxhY2Vob2xkZXJcbiAqIHN5bmNocm9ub3VzbHksIGFuZCBraWNrIG9mZiBhIGJhY2tncm91bmQgdGFzayB0aGF0IHJlc29sdmVzIHRoZVxuICogZGF0YXNldCBhbmQgcnVucyB0aGUgcGxhbm5lci4gUmV0dXJucyB0aGUgYGNoYXJ0SWRgIG9uY2UgdGhlXG4gKiBwbGFjZWhvbGRlciBsYW5kcyBzbyB0aGUgZmlyc3Qge0BsaW5rIGZldGNoQ2hhcnR9IGNhbGwgYWx3YXlzXG4gKiBzZWVzIGFuIGVudHJ5IChubyBzcHVyaW91cyA0MDQgcmFjZSkuXG4gKlxuICogVGhlIGJhY2tncm91bmQgdGFzayBzd2FsbG93cyBpdHMgb3duIGZhaWx1cmVzIGFuZCB3cml0ZXMgdGhlbVxuICogYXMgYGVycm9yYCBlbnRyaWVzLCBzbyBjYWxsZXJzIG5ldmVyIHNlZSBhIHJlamVjdGVkIHByb21pc2UuXG4gKiBDYWNoZSBzdGF0ZSBtYWNoaW5lOlxuICpcbiAqICAgLSBqdXN0IGFmdGVyIHRoaXMgY2FsbCByZXR1cm5zOiBgeyBjaGFydElkIH1gIChwcm9jZXNzaW5nKVxuICogICAtIG9uIHBsYW5uZXIgc3VjY2VzczogICAgICAgICAgIGB7IGNoYXJ0SWQsIHJlc3VsdCB9YFxuICogICAtIG9uIGRhdGEgLyBwbGFubmVyIGZhaWx1cmU6ICAgIGB7IGNoYXJ0SWQsIGVycm9yIH1gXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwcmVwYXJlQ2hhcnQob3B0czogUHJlcGFyZUNoYXJ0T3B0aW9ucyk6IFByb21pc2U8eyBjaGFydElkOiBzdHJpbmcgfT4ge1xuICBjb25zdCBjaGFydElkID0gaGFzaC5pZCgpO1xuICBhd2FpdCB3cml0ZUNoYXJ0KHsgY2hhcnRJZCB9LCBvcHRzLnVzZXJLZXkpO1xuICBsb2dnZXIuZGVidWcoXCJxdWV1ZWRcIiwgeyBjaGFydElkIH0pO1xuICAvLyBGaXJlLWFuZC1mb3JnZXQuIEZhaWx1cmVzIGxhbmQgaW4gdGhlIGNhY2hlIGFzIGBlcnJvcmAgZW50cmllcztcbiAgLy8gbmV2ZXIgZXNjYXBlIGludG8gYW4gdW5oYW5kbGVkIHJlamVjdGlvbi5cbiAgdm9pZCBydW5QcmVwYXJlQ2hhcnQoY2hhcnRJZCwgb3B0cyk7XG4gIHJldHVybiB7IGNoYXJ0SWQgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcnVuUHJlcGFyZUNoYXJ0KGNoYXJ0SWQ6IHN0cmluZywgb3B0czogUHJlcGFyZUNoYXJ0T3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBzdGFydGVkQXQgPSBEYXRlLm5vdygpO1xuICB0cnkge1xuICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBvcHRzLnJlc29sdmVEYXRhKG9wdHMuc2lnbmFsKTtcbiAgICBpZiAoZGF0YS5yb3dzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEV4ZWN1dGlvbkVycm9yKFwiRGF0YXNldCBoYXMgbm8gcm93czsgbm90aGluZyB0byBjaGFydFwiKTtcbiAgICB9XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcnVuQ2hhcnRQbGFubmVyKFxuICAgICAgb3B0cy5jb25maWcsXG4gICAgICB7XG4gICAgICAgIHRpdGxlOiBvcHRzLnRpdGxlID8/IFwiQ2hhcnRcIixcbiAgICAgICAgLi4uKG9wdHMuZGVzY3JpcHRpb24gPyB7IGRlc2NyaXB0aW9uOiBvcHRzLmRlc2NyaXB0aW9uIH0gOiB7fSksXG4gICAgICAgIGRhdGE6IGRhdGEucm93cyBhcyBDaGFydFBsYW5uZXJSZXF1ZXN0W1wiZGF0YVwiXSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIC4uLihvcHRzLnJlcXVlc3RDb250ZXh0ID8geyByZXF1ZXN0Q29udGV4dDogb3B0cy5yZXF1ZXN0Q29udGV4dCB9IDoge30pLFxuICAgICAgICAuLi4ob3B0cy5zaWduYWwgPyB7IGFib3J0U2lnbmFsOiBvcHRzLnNpZ25hbCB9IDoge30pLFxuICAgICAgfSxcbiAgICApO1xuICAgIGF3YWl0IHdyaXRlQ2hhcnQoeyBjaGFydElkLCByZXN1bHQgfSwgb3B0cy51c2VyS2V5KTtcbiAgICBsb2dnZXIuaW5mbyhcImRvbmVcIiwge1xuICAgICAgY2hhcnRJZCxcbiAgICAgIGNoYXJ0VHlwZTogcmVzdWx0LmNoYXJ0VHlwZSxcbiAgICAgIGVsYXBzZWRNczogRGF0ZS5ub3coKSAtIHN0YXJ0ZWRBdCxcbiAgICB9KTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLndhcm4oXCJlcnJvclwiLCB7IGNoYXJ0SWQsIGVycm9yOiBlcnJvci5lcnJvck1lc3NhZ2UoZXJyKSB9KTtcbiAgICAvLyBUaGUgZW50cnkncyBgZXJyb3JgIGlzIHJlbmRlcmVkIGluIHRoZSBjaGF0LCBzbyBvbmx5IGFuIEFwcEtpdEVycm9yJ3NcbiAgICAvLyBvd24gbWVzc2FnZSB0cmF2ZWxzOyBhbnl0aGluZyBlbHNlIGNvdWxkIGNhcnJ5IHVwc3RyZWFtIHByb3ZpZGVyIGRldGFpbC5cbiAgICBjb25zdCBlcnJUZXh0ID0gZXJyIGluc3RhbmNlb2YgQXBwS2l0RXJyb3IgPyBlcnIubWVzc2FnZSA6IENIQVJUX0ZBSUxFRF9NRVNTQUdFO1xuICAgIGF3YWl0IHdyaXRlQ2hhcnQoeyBjaGFydElkLCBlcnJvcjogZXJyVGV4dCB9LCBvcHRzLnVzZXJLZXkpO1xuICB9XG59XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gbG9uZy1wb2xsIGZldGNoIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqIElucHV0cyB0byB7QGxpbmsgZmV0Y2hDaGFydH0uICovXG5leHBvcnQgaW50ZXJmYWNlIEZldGNoQ2hhcnRPcHRpb25zIHtcbiAgLyoqXG4gICAqIElkZW50aXR5IHRoZSBjaGFydCBtdXN0IGJlbG9uZyB0by4gQSBjaGFydCBtaW50ZWQgdW5kZXIgYSBkaWZmZXJlbnQga2V5XG4gICAqIGlzIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gYW4gdW5rbm93biBpZC4gVXNlIHtAbGluayByZXNvbHZlVXNlcktleX0uXG4gICAqL1xuICB1c2VyS2V5OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBTZXJ2ZXItc2lkZSBwb2xsaW5nIGJ1ZGdldCBpbiBtcy4gV2hlbiB0aGUgZW50cnkgc3RheXMgaW5cbiAgICogdGhlIHByb2Nlc3Npbmcgc3RhdGUgcGFzdCB0aGlzIHdpbmRvdywgdGhlIGhlbHBlciByZXR1cm5zIHRoZVxuICAgKiBsYXN0IHNlZW4gdmFsdWUgKHN0aWxsIHByb2Nlc3NpbmcpIHNvIHRoZSBjbGllbnQgY2FuIHJlLXBvbGwuXG4gICAqIERlZmF1bHRzIHRvIHtAbGluayBERUZBVUxUX0ZFVENIX1RJTUVPVVRfTVN9ICg2MHMpLlxuICAgKi9cbiAgdGltZW91dE1zPzogbnVtYmVyO1xuICAvKipcbiAgICogUG9sbCBpbnRlcnZhbCBpbiBtcy4gRGVmYXVsdHMgdG9cbiAgICoge0BsaW5rIERFRkFVTFRfRkVUQ0hfSU5URVJWQUxfTVN9ICgyNTBtcykuXG4gICAqL1xuICBpbnRlcnZhbE1zPzogbnVtYmVyO1xuICAvKiogRXh0ZXJuYWwgY2FuY2VsbGF0aW9uIGhhbmRsZSAoZS5nLiByZXF1ZXN0IGByZXEuc2lnbmFsYCkuICovXG4gIHNpZ25hbD86IEFib3J0U2lnbmFsO1xufVxuXG4vKipcbiAqIExvbmctcG9sbCB0aGUgY2hhcnQgY2FjaGUgdW50aWwgdGhlIGVudHJ5IHNldHRsZXMgKGByZXN1bHRgIG9yXG4gKiBgZXJyb3JgIHNldCksIHRoZSBlbnRyeSBpcyBtaXNzaW5nLCBvciB0aGUgc2VydmVyLXNpZGUgdGltZW91dFxuICogZWxhcHNlcy5cbiAqXG4gKiBSZXR1cm5zOlxuICogICAtIHRoZSByZXNvbHZlZCB7QGxpbmsgQ2hhcnR9IHdoZW4gaXQgc2V0dGxlZCwgZXJyb3JlZCwgb3JcbiAqICAgICBzdGF5ZWQgaW4gcHJvY2Vzc2luZyBwYXN0IGB0aW1lb3V0TXNgIChzbyB0aGUgY2xpZW50IGNhblxuICogICAgIHJlLXBvbGwpO1xuICogICAtIGB1bmRlZmluZWRgIHdoZW4gdGhlIGVudHJ5IGlzIG1pc3NpbmcsIGV4cGlyZWQsIG9yIG93bmVkIGJ5XG4gKiAgICAgYW5vdGhlciBpZGVudGl0eSAodGhlIGNvbnN1bWVyIHNob3VsZCB0cmVhdCBhcyA0MDQpLlxuICpcbiAqIGBzaWduYWxgIGxldHMgdGhlIGNhbGxlciBjYW5jZWwgYWhlYWQgb2YgdGltZW91dCAoZS5nLiB0aGUgSFRUUFxuICogcmVxdWVzdCBjbG9zZWQpLiBDYW5jZWxsYXRpb24gcHJvcGFnYXRlcyB0byB0aGUgaW50ZXItcG9sbCBzbGVlcFxuICogc28gdGhlIGhlbHBlciByZXR1cm5zIGltbWVkaWF0ZWx5LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmV0Y2hDaGFydChcbiAgY2hhcnRJZDogc3RyaW5nLFxuICBvcHRpb25zOiBGZXRjaENoYXJ0T3B0aW9ucyxcbik6IFByb21pc2U8Q2hhcnQgfCB1bmRlZmluZWQ+IHtcbiAgY29uc3QgdGltZW91dE1zID0gb3B0aW9ucy50aW1lb3V0TXMgPz8gREVGQVVMVF9GRVRDSF9USU1FT1VUX01TO1xuICBjb25zdCBpbnRlcnZhbE1zID0gb3B0aW9ucy5pbnRlcnZhbE1zID8/IERFRkFVTFRfRkVUQ0hfSU5URVJWQUxfTVM7XG4gIGNvbnN0IGRlYWRsaW5lID0gRGF0ZS5ub3coKSArIHRpbWVvdXRNcztcblxuICBsZXQgbGFzdDogQ2hhcnQgfCB1bmRlZmluZWQ7XG4gIHdoaWxlICh0cnVlKSB7XG4gICAgb3B0aW9ucy5zaWduYWw/LnRocm93SWZBYm9ydGVkKCk7XG4gICAgbGFzdCA9IGF3YWl0IHJlYWRDaGFydChjaGFydElkLCBvcHRpb25zLnVzZXJLZXkpO1xuICAgIGlmICghbGFzdCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBpZiAobGFzdC5yZXN1bHQgIT09IHVuZGVmaW5lZCB8fCBsYXN0LmVycm9yICE9PSB1bmRlZmluZWQpIHJldHVybiBsYXN0O1xuICAgIGNvbnN0IHJlbWFpbmluZyA9IGRlYWRsaW5lIC0gRGF0ZS5ub3coKTtcbiAgICBpZiAocmVtYWluaW5nIDw9IDApIHJldHVybiBsYXN0O1xuICAgIGF3YWl0IGFzeW5jLnNsZWVwKE1hdGgubWluKGludGVydmFsTXMsIHJlbWFpbmluZyksIG9wdGlvbnMuc2lnbmFsKTtcbiAgfVxufVxuXG4vKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBlY2hhcnRzIHRoZW1lIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbi8qKlxuICogVGhlIHNsaWNlIG9mIGFuIEVjaGFydHMgb3B0aW9uIHRoYXQgY2FycmllcyBicmFuZCBpZGVudGl0eTogdGhlIHNlcmllc1xuICogY29sb3IgY3ljbGUgYW5kIHRoZSBiYXNlIHRleHQgc3R5bGUgKGZvbnQgZmFtaWx5ICsgZm9yZWdyb3VuZCBjb2xvcikuXG4gKiBEZXJpdmVkIGZyb20gYSB7QGxpbmsgQnJhbmRDb250ZXh0fSBieSB7QGxpbmsgYnJhbmRDaGFydFRoZW1lfSBhbmQgbWVyZ2VkXG4gKiBpbnRvIGV2ZXJ5IHNwZWMgYnkge0BsaW5rIHBsYW5Ub0VjaGFydHNPcHRpb259LlxuICovXG5pbnRlcmZhY2UgQ2hhcnRUaGVtZSB7XG4gIGNvbG9yOiBzdHJpbmdbXTtcbiAgdGV4dFN0eWxlOiB7IGZvbnRGYW1pbHk6IHN0cmluZzsgY29sb3I6IHN0cmluZyB9O1xufVxuXG4vKipcbiAqIEFwcEtpdCdzIGNhdGVnb3JpY2FsIGNoYXJ0IHBhbGV0dGUgKGAtLWNoYXJ0LWNhdC0xYCAuLiBgLS1jaGFydC1jYXQtOGAgZnJvbVxuICogYEBkYXRhYnJpY2tzL2FwcGtpdC11aWApLCBhcyBoZXguIFNlcnZlci1yZW5kZXJlZCBjaGFydCBzcGVjcyBjYW5ub3QgcmVhZCB0aGVcbiAqIGJyb3dzZXIncyBDU1MgY3VzdG9tIHByb3BlcnRpZXMsIHNvIHRoZSB2YWx1ZXMgYXJlIG1pcnJvcmVkIGhlcmUgdG8ga2VlcCBhXG4gKiBnZW5lcmF0ZWQgY2hhcnQgdmlzdWFsbHkgY29uc2lzdGVudCB3aXRoIHRoZSBBcHBLaXQtc3R5bGVkIFVJIGFyb3VuZCBpdC5cbiAqIEtlZXAgaW4gc3luYyB3aXRoIEFwcEtpdCdzIHN0eWxlc2hlZXQgaWYgaXQgY2hhbmdlcy5cbiAqL1xuY29uc3QgQVBQS0lUX0NIQVJUX1BBTEVUVEUgPSBbXG4gIFwiIzI0NjNFQlwiLCAvLyBibHVlXG4gIFwiIzJFQjg4QVwiLCAvLyB0ZWFsXG4gIFwiI0FCNDdCRFwiLCAvLyBwdXJwbGVcbiAgXCIjRjY5RTIzXCIsIC8vIGFtYmVyXG4gIFwiI0REMkM0RFwiLCAvLyByb3NlXG4gIFwiIzFCQTNCQlwiLCAvLyBjeWFuXG4gIFwiIzlCNjFEMVwiLCAvLyBsYXZlbmRlclxuICBcIiMzNEIyNjJcIiwgLy8gZW1lcmFsZFxuXSBhcyBjb25zdDtcblxuLyoqXG4gKiBFeHBhbmQgdHdvIGJyYW5kIGhleCBjb2xvcnMgaW50byBhIGxlZ2libGUgY2F0ZWdvcmljYWwgY3ljbGUuIEVjaGFydHNcbiAqIHJlcGVhdHMgdGhlIGBjb2xvcmAgYXJyYXkgYWNyb3NzIHNlcmllcyAvIGNhdGVnb3JpZXMsIHNvIGEgZ29vZCBkZWZhdWx0XG4gKiBuZWVkcyBzZXZlcmFsIGRpc3RpbmN0IGh1ZXMsIG5vdCB0d28uIFdlIHNlZWQgd2l0aCB0aGUgYnJhbmQgcHJpbWFyeSBhbmRcbiAqIGFjY2VudCAodGhlIGlkZW50aXR5IGNvbG9ycykgYW5kIGZvbGxvdyB3aXRoIEFwcEtpdCdzIG93biBjYXRlZ29yaWNhbCBjaGFydFxuICogcGFsZXR0ZSwgc28gbXVsdGktc2VyaWVzIC8gbWFueS1zbGljZSBjaGFydHMgc3RheSByZWFkYWJsZSBhbmQgbWF0Y2ggdGhlXG4gKiBzdXJyb3VuZGluZyBBcHBLaXQgVUkgd2hpbGUgdGhlIGZpcnN0IG9uZSBvciB0d28gbWFya3MgbGFuZCBvbi1icmFuZC5cbiAqL1xuZnVuY3Rpb24gYnJhbmRDb2xvckN5Y2xlKHByaW1hcnk6IHN0cmluZywgYWNjZW50OiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gIGNvbnN0IHNwcmVhZCA9IEFQUEtJVF9DSEFSVF9QQUxFVFRFO1xuICBjb25zdCBzZWVuID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIHJldHVybiBbcHJpbWFyeSwgYWNjZW50LCAuLi5zcHJlYWRdLmZpbHRlcigoYykgPT4ge1xuICAgIGNvbnN0IGtleSA9IGMudG9Mb3dlckNhc2UoKTtcbiAgICBpZiAoc2Vlbi5oYXMoa2V5KSkgcmV0dXJuIGZhbHNlO1xuICAgIHNlZW4uYWRkKGtleSk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH0pO1xufVxuXG4vKipcbiAqIERlcml2ZSBhbiBFY2hhcnRzIHtAbGluayBDaGFydFRoZW1lfSBmcm9tIGEgYnJhbmQgY29udGV4dDogdGhlIHByaW1hcnkgK1xuICogYWNjZW50IGNvbG9ycyBzZWVkIHRoZSBzZXJpZXMgY3ljbGUsIHRoZSBzYW5zIHN0YWNrIGJlY29tZXMgdGhlIGJhc2UgZm9udCxcbiAqIGFuZCB0aGUgYnJhbmQgZm9yZWdyb3VuZCBiZWNvbWVzIHRoZSBiYXNlIHRleHQgY29sb3IuXG4gKi9cbmZ1bmN0aW9uIGJyYW5kQ2hhcnRUaGVtZShicmFuZDogQnJhbmRDb250ZXh0KTogQ2hhcnRUaGVtZSB7XG4gIHJldHVybiB7XG4gICAgY29sb3I6IGJyYW5kQ29sb3JDeWNsZShicmFuZC5jb2xvcnMucHJpbWFyeSwgYnJhbmQuY29sb3JzLmFjY2VudCksXG4gICAgdGV4dFN0eWxlOiB7IGZvbnRGYW1pbHk6IGJyYW5kLnR5cG9ncmFwaHkuc2FucywgY29sb3I6IGJyYW5kLmNvbG9ycy5mb3JlZ3JvdW5kIH0sXG4gIH07XG59XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIGVjaGFydHMgZXhwYW5zaW9uIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbi8qKlxuICogRXhwYW5kIGEge0BsaW5rIENoYXJ0UGxhbn0gaW50byBhIGZ1bGwgRWNoYXJ0cyBgRUNoYXJ0c09wdGlvbmBcbiAqIEpTT04uIENlbnRyYWxpemVkIGhlcmUgc28gdGhlIHBsYW5uZXIgYWdlbnQgb25seSBmaWxscyBpbiB0aGVcbiAqIGNvbXBhY3QgcGxhbiBzaGFwZTsgdG9vbHRpcCAvIGFuaW1hdGlvbiAvIGNvbG9yIC8gZ3JpZCBkZWZhdWx0c1xuICogc3RheSBjb25zaXN0ZW50IGFjcm9zcyBjaGFydHMgYW5kIGFyZSBlYXN5IHRvIHR1bmUgd2l0aG91dFxuICogcmV0cmFpbmluZyBtb2RlbCBiZWhhdmlvdXIuXG4gKlxuICogV2hlbiBgYnJhbmRgIGlzIHNldCwgdGhlIHJlc29sdmVkIHNwZWMgaXMgdGhlbWVkIHdpdGggdGhlIGJyYW5kJ3Mgc2VyaWVzXG4gKiBjb2xvciBjeWNsZSBhbmQgYmFzZSB0ZXh0IHN0eWxlIChzZWUge0BsaW5rIGJyYW5kQ2hhcnRUaGVtZX0pOyBvdGhlcndpc2VcbiAqIEVjaGFydHMnIGRlZmF1bHRzIGFwcGx5LlxuICovXG5mdW5jdGlvbiBwbGFuVG9FY2hhcnRzT3B0aW9uKFxuICBwbGFuOiBDaGFydFBsYW4sXG4gIGZhbGxiYWNrVGl0bGU6IHN0cmluZyxcbiAgYnJhbmQ/OiBCcmFuZENvbnRleHQsXG4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIGNvbnN0IGJhc2VUaXRsZSA9IHBsYW4udGl0bGUgPz8gZmFsbGJhY2tUaXRsZTtcbiAgY29uc3QgZ3JpZCA9IHsgbGVmdDogNDgsIHJpZ2h0OiAyNCwgdG9wOiA1NiwgYm90dG9tOiA0OCwgY29udGFpbkxhYmVsOiB0cnVlIH07XG4gIGNvbnN0IHRoZW1lID0gYnJhbmQgPyBicmFuZENoYXJ0VGhlbWUoYnJhbmQpIDogdW5kZWZpbmVkO1xuICBjb25zdCB0aGVtZWQgPSAob3B0aW9uOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0+XG4gICAgdGhlbWUgPyB7IC4uLnRoZW1lLCAuLi5vcHRpb24gfSA6IG9wdGlvbjtcblxuICBpZiAocGxhbi5jaGFydFR5cGUgPT09IFwicGllXCIpIHtcbiAgICAvLyBFY2hhcnRzIGNyYXNoZXMgb24gbnVsbCBwaWUgc2xpY2VzIC0gZmlsdGVyIHRoZW0gb3V0LlxuICAgIC8vIGB7bmFtZSwgdmFsdWV9YCBzbGljZXMgYXJlIHRoZSBvbmx5IHZhbGlkIHBpZSBkYXRhIHNoYXBlLFxuICAgIC8vIHNvIGRyb3AgYmFyZSBudW1iZXJzIC8gdHVwbGVzIC8gbnVsbHMgdGhlIHBsYW5uZXIgbWF5XG4gICAgLy8gaGF2ZSBsZWFrZWQgaW50byBhIHBpZSBzZXJpZXMuXG4gICAgY29uc3Qgc2xpY2VzID0gKHBsYW4uc2VyaWVzWzBdPy5kYXRhID8/IFtdKS5maWx0ZXIoXG4gICAgICAoZCk6IGQgaXMgeyBuYW1lOiBzdHJpbmc7IHZhbHVlOiBudW1iZXIgfSA9PlxuICAgICAgICBkICE9PSBudWxsICYmIHR5cGVvZiBkID09PSBcIm9iamVjdFwiICYmICFBcnJheS5pc0FycmF5KGQpLFxuICAgICk7XG4gICAgcmV0dXJuIHRoZW1lZCh7XG4gICAgICB0aXRsZTogeyB0ZXh0OiBiYXNlVGl0bGUsIGxlZnQ6IFwiY2VudGVyXCIgfSxcbiAgICAgIHRvb2x0aXA6IHsgdHJpZ2dlcjogXCJpdGVtXCIgfSxcbiAgICAgIGxlZ2VuZDogeyBib3R0b206IDAgfSxcbiAgICAgIHNlcmllczogW1xuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogcGxhbi5zZXJpZXNbMF0/Lm5hbWUgPz8gYmFzZVRpdGxlLFxuICAgICAgICAgIHR5cGU6IFwicGllXCIsXG4gICAgICAgICAgcmFkaXVzOiBbXCIzNSVcIiwgXCI2NSVcIl0sXG4gICAgICAgICAgZGF0YTogc2xpY2VzLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgfVxuXG4gIGlmIChwbGFuLmNoYXJ0VHlwZSA9PT0gXCJzY2F0dGVyXCIpIHtcbiAgICAvLyBFY2hhcnRzIGNyYXNoZXMgb24gbnVsbCBzY2F0dGVyIHBvaW50cyAtIGtlZXAgb25seSB2YWxpZFxuICAgIC8vIGBbeCwgeV1gIHR1cGxlcy4gQmFyZSBudW1iZXJzIC8gb2JqZWN0cyAvIG51bGxzIGZyb20gYVxuICAgIC8vIG1pc21hdGNoZWQgcGxhbiBnZXQgZHJvcHBlZCBzaWxlbnRseS5cbiAgICByZXR1cm4gdGhlbWVkKHtcbiAgICAgIHRpdGxlOiB7IHRleHQ6IGJhc2VUaXRsZSwgbGVmdDogXCJjZW50ZXJcIiB9LFxuICAgICAgdG9vbHRpcDogeyB0cmlnZ2VyOiBcIml0ZW1cIiB9LFxuICAgICAgbGVnZW5kOiB7IGJvdHRvbTogMCB9LFxuICAgICAgZ3JpZCxcbiAgICAgIHhBeGlzOiB7IHR5cGU6IFwidmFsdWVcIiwgbmFtZTogcGxhbi54QXhpc0xhYmVsIH0sXG4gICAgICB5QXhpczogeyB0eXBlOiBcInZhbHVlXCIsIG5hbWU6IHBsYW4ueUF4aXNMYWJlbCB9LFxuICAgICAgc2VyaWVzOiBwbGFuLnNlcmllcy5tYXAoKHMpID0+ICh7XG4gICAgICAgIG5hbWU6IHMubmFtZSxcbiAgICAgICAgdHlwZTogXCJzY2F0dGVyXCIsXG4gICAgICAgIGRhdGE6IHMuZGF0YS5maWx0ZXIoKGQpOiBkIGlzIFtudW1iZXIsIG51bWJlcl0gPT4gQXJyYXkuaXNBcnJheShkKSAmJiBkLmxlbmd0aCA9PT0gMiksXG4gICAgICB9KSksXG4gICAgfSk7XG4gIH1cblxuICAvLyBiYXIgLyBsaW5lIC8gYXJlYSBzaGFyZSB0aGUgc2FtZSBheGlzIGxheW91dC5cbiAgY29uc3QgaXNBcmVhID0gcGxhbi5jaGFydFR5cGUgPT09IFwiYXJlYVwiO1xuICBjb25zdCBzZXJpZXNUeXBlID0gcGxhbi5jaGFydFR5cGUgPT09IFwiYmFyXCIgPyBcImJhclwiIDogXCJsaW5lXCI7XG4gIHJldHVybiB0aGVtZWQoe1xuICAgIHRpdGxlOiB7IHRleHQ6IGJhc2VUaXRsZSwgbGVmdDogXCJjZW50ZXJcIiB9LFxuICAgIHRvb2x0aXA6IHsgdHJpZ2dlcjogXCJheGlzXCIgfSxcbiAgICBsZWdlbmQ6IHsgYm90dG9tOiAwIH0sXG4gICAgZ3JpZCxcbiAgICB4QXhpczoge1xuICAgICAgdHlwZTogXCJjYXRlZ29yeVwiLFxuICAgICAgZGF0YTogcGxhbi5jYXRlZ29yaWVzID8/IFtdLFxuICAgICAgbmFtZTogcGxhbi54QXhpc0xhYmVsLFxuICAgIH0sXG4gICAgeUF4aXM6IHsgdHlwZTogXCJ2YWx1ZVwiLCBuYW1lOiBwbGFuLnlBeGlzTGFiZWwgfSxcbiAgICBzZXJpZXM6IHBsYW4uc2VyaWVzLm1hcCgocykgPT4gKHtcbiAgICAgIG5hbWU6IHMubmFtZSxcbiAgICAgIHR5cGU6IHNlcmllc1R5cGUsXG4gICAgICBkYXRhOiBzLmRhdGEsXG4gICAgICBzbW9vdGg6IHNlcmllc1R5cGUgPT09IFwibGluZVwiLFxuICAgICAgLi4uKGlzQXJlYSA/IHsgYXJlYVN0eWxlOiB7fSB9IDoge30pLFxuICAgIH0pKSxcbiAgfSk7XG59XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHJlbmRlcl9kYXRhIHRvb2wgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuLyoqXG4gKiBCdWlsZCB0aGUgYHJlbmRlcl9kYXRhYCBNYXN0cmEgdG9vbCBib3VuZCB0byB0aGUgZ2l2ZW4gcGx1Z2luXG4gKiBjb25maWcuIEF1dG8td2lyZWQgYXMgYSBzeXN0ZW0gdG9vbCBvbiBldmVyeSBhZ2VudCAoc2VlXG4gKiBgYWdlbnRzLnRzYCk7IHBlci1hZ2VudCB0b29scyBjYW4gc2hhZG93IGl0IGJ5IHJlZ2lzdGVyaW5nIGFcbiAqIHNhbWUtbmFtZWQgZW50cnkuXG4gKlxuICogVGhpbiB3cmFwcGVyIG92ZXIge0BsaW5rIHByZXBhcmVDaGFydH0gZm9yIGNhbGxlcnMgdGhhdCBhbHJlYWR5XG4gKiBoYXZlIGEgZGF0YXNldCBpbiBoYW5kLiBNaW50cyBhIGBjaGFydElkYCBzeW5jaHJvbm91c2x5LCBjYWNoZXNcbiAqIGFuIGVtcHR5IHBsYWNlaG9sZGVyLCBhbmQga2lja3Mgb2ZmIHRoZSBjaGFydC1wbGFubmVyIGluIHRoZVxuICogYmFja2dyb3VuZC4gUmV0dXJucyBqdXN0IHRoZSBgY2hhcnRJZGA7IHRoZSBob3N0IFVJIHJlc29sdmVzXG4gKiBgW2NoYXJ0OjxjaGFydElkPl1gIG1hcmtlcnMgYnkgaGl0dGluZyB0aGUgcGx1Z2luJ3NcbiAqIGAvZW1iZWQvY2hhcnQvOmlkYCByb3V0ZS5cbiAqXG4gKiBGb3IgR2VuaWUgc3RhdGVtZW50IHJlc3VsdHMsIHByZWZlciB0aGUgR2VuaWUgYWdlbnQnc1xuICogYHByZXBhcmVfY2hhcnRgIHRvb2wsIHdoaWNoIGFjY2VwdHMgYSBgc3RhdGVtZW50X2lkYCBhbmRcbiAqIHJlc29sdmVzIHRoZSByb3dzIGxhemlseS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkUmVuZGVyRGF0YVRvb2woY29uZmlnOiBNYXN0cmFQbHVnaW5Db25maWcpIHtcbiAgcmV0dXJuIGNyZWF0ZVRvb2woe1xuICAgIGlkOiBcInJlbmRlcl9kYXRhXCIsXG4gICAgZGVzY3JpcHRpb246IHN0cmluZy50b0Rlc2NyaXB0aW9uKFtcbiAgICAgIGBcbiAgICAgICAgU3VibWl0IGEgdGFidWxhciBkYXRhc2V0IGZvciBpbmxpbmUgcmVuZGVyaW5nIGFzIGEgY2hhcnQgaW5cbiAgICAgICAgdGhlIHVzZXIncyB2aWV3LiBQYXNzIGEgdGl0bGUsIHRoZSByYXcgcm93cyAoYXJyYXkgb2Ygb2JqZWN0c1xuICAgICAgICBrZXllZCBieSBjb2x1bW4gbmFtZSksIGFuZCBhbiBvcHRpb25hbCBvbmUtbGluZSBkZXNjcmlwdGlvblxuICAgICAgICBvZiB0aGUgaW5zaWdodCB0byBoaWdobGlnaHQuIFJldHVybnMgYSBzaG9ydCBcXGBjaGFydElkXFxgO1xuICAgICAgICB0aGUgY2hhcnQgcmVuZGVycyBpbmxpbmUgYXQgdGhlIHBvc2l0aW9uIHlvdSBlbWJlZCB0aGVcbiAgICAgICAgbWF0Y2hpbmcgXFxgW2NoYXJ0OjxjaGFydElkPl1cXGAgbWFya2VyLlxuICAgICAgYCxcbiAgICAgIGBcbiAgICAgICAgUGxhY2VtZW50IGNvbnRyYWN0OiBlbWJlZCBcXGBbY2hhcnQ6PGNoYXJ0SWQ+XVxcYCBvbiBpdHMgb3duXG4gICAgICAgIGxpbmUgKGJsYW5rIGxpbmVzIGFib3ZlIGFuZCBiZWxvdykgd2hlcmV2ZXIgeW91IHdhbnQgdGhlXG4gICAgICAgIGNoYXJ0IHRvIGFwcGVhciBpbiB5b3VyIHJlcGx5LiBUaGUgY2hhcnQgcmVzb2x2ZXNcbiAgICAgICAgYXN5bmNocm9ub3VzbHkgLSB0aGUgdG9vbCByZXR1cm5zIHRoZSBpZCBpbW1lZGlhdGVseSBhbmQgdGhlXG4gICAgICAgIGhvc3QgVUkgZmV0Y2hlcyB0aGUgY2hhcnQgZnJvbSB0aGUgY2FjaGUgb25jZSB0aGUgcGxhbm5lclxuICAgICAgICBsYW5kcy4gWW91IGNhbiBjYWxsIFxcYHJlbmRlcl9kYXRhXFxgIG11bHRpcGxlIHRpbWVzIGluIHRoZVxuICAgICAgICBzYW1lIHR1cm4gKHRoZSB0b29sIGlzIHBhcmFsbGVsLXNhZmUpIGFuZCBpbnRlcmxlYXZlIHRoZVxuICAgICAgICBtYXJrZXJzIHdpdGggcHJvc2Ugc28gZWFjaCBjaGFydCBzaXRzIG5leHQgdG8gaXRzXG4gICAgICAgIGNvbW1lbnRhcnkuXG4gICAgICBgLFxuICAgICAgYFxuICAgICAgICBVc2Ugd2hlbmV2ZXIgYSBTUUwgcm93IHNldCwgQVBJIHJlc3BvbnNlLCBvciBoYW5kLWJ1aWx0XG4gICAgICAgIGRhdGFzZXQgd291bGQgbGFuZCBiZXR0ZXIgYXMgYSBwaWN0dXJlIHRoYW4gYXMgYSBsaXN0IG9yXG4gICAgICAgIHRhYmxlLiBDYXAgaW5wdXQgYXQgYSBmZXcgaHVuZHJlZCByb3dzOyBzYW1wbGUgb3IgYWdncmVnYXRlXG4gICAgICAgIGxhcmdlciBkYXRhc2V0cyBmaXJzdC5cbiAgICAgIGAsXG4gICAgXSksXG4gICAgaW5wdXRTY2hlbWE6IGNoYXJ0UGxhbm5lclJlcXVlc3RTY2hlbWEsXG4gICAgb3V0cHV0U2NoZW1hOiB3aXJlLkNoYXJ0U2NoZW1hLnBpY2soeyBjaGFydElkOiB0cnVlIH0pLFxuICAgIGV4ZWN1dGU6IGFzeW5jIChpbnB1dCwgY3R4UmF3KSA9PiB7XG4gICAgICBjb25zdCB7IHRpdGxlLCBkZXNjcmlwdGlvbiwgZGF0YSB9ID0gaW5wdXQgYXMgQ2hhcnRQbGFubmVyUmVxdWVzdDtcbiAgICAgIGNvbnN0IGN0eCA9IGN0eFJhdyBhcyB7IHJlcXVlc3RDb250ZXh0PzogUmVxdWVzdENvbnRleHQgfSB8IHVuZGVmaW5lZDtcbiAgICAgIHJldHVybiBwcmVwYXJlQ2hhcnQoe1xuICAgICAgICBjb25maWcsXG4gICAgICAgIHVzZXJLZXk6IHJlc29sdmVVc2VyS2V5KGN0eD8ucmVxdWVzdENvbnRleHQpLFxuICAgICAgICB0aXRsZSxcbiAgICAgICAgLi4uKGRlc2NyaXB0aW9uID8geyBkZXNjcmlwdGlvbiB9IDoge30pLFxuICAgICAgICByZXNvbHZlRGF0YTogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKHsgcm93czogZGF0YSB9KSxcbiAgICAgICAgLi4uKGN0eD8ucmVxdWVzdENvbnRleHQgPyB7IHJlcXVlc3RDb250ZXh0OiBjdHgucmVxdWVzdENvbnRleHQgfSA6IHt9KSxcbiAgICAgIH0pO1xuICAgIH0sXG4gIH0pO1xufVxuIl19