@dbx-tools/appkit-model-gateway 0.9.175 → 0.9.176
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -0
- package/index.ts +4 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.js +4 -2
- package/lib/src/gateway.d.ts +13 -1
- package/lib/src/gateway.js +98 -15
- package/lib/src/models.d.ts +3 -3
- package/lib/src/models.js +100 -6
- package/lib/src/plugin.js +2 -10
- package/lib/src/registry.js +3 -1
- package/lib/src/router.js +27 -5
- package/lib/src/routes.js +5 -2
- package/lib/src/smart-router.d.ts +160 -0
- package/lib/src/smart-router.js +753 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/src/gateway.ts +152 -14
- package/src/models.ts +128 -5
- package/src/plugin.ts +1 -9
- package/src/registry.ts +2 -0
- package/src/router.ts +29 -4
- package/src/routes.ts +4 -1
- package/src/smart-router.ts +983 -0
|
@@ -0,0 +1,753 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Databricks Smart Router transport, context construction, probing, and turn pinning.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { CacheManager, getExecutionContext } from "@databricks/appkit";
|
|
8
|
+
import { refreshWorkspaceClientAuthentication } from "@dbx-tools/databricks";
|
|
9
|
+
import { isRecord, log, toError } from "@dbx-tools/shared-core";
|
|
10
|
+
import { ReasoningEffortSchema } from "@dbx-tools/shared-model";
|
|
11
|
+
import { SMART_ROUTER_NAME, SmartRouterObservationSchema, SmartRouterRequestSchema, SmartRouterResponseSchema, } from "@dbx-tools/shared-model-gateway";
|
|
12
|
+
import { Tiktoken } from "js-tiktoken/lite";
|
|
13
|
+
import o200kBase from "js-tiktoken/ranks/o200k_base";
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
import { resolveRoute } from "./router.js";
|
|
16
|
+
const logger = log.logger("appkit/model-gateway/smart-router");
|
|
17
|
+
const ROUTE_CACHE_NAMESPACE = "model-gateway-smart-router";
|
|
18
|
+
const ROUTE_POLICY_VERSION = 1;
|
|
19
|
+
const PROBE_CACHE_NAMESPACE = "model-gateway-smart-router-probe";
|
|
20
|
+
const PROBE_CACHE_VERSION = 1;
|
|
21
|
+
const PROBE_TASK = "Check whether Smart Router can select an available model.";
|
|
22
|
+
const NEGATIVE_PROBE_TTL_MS = 30_000;
|
|
23
|
+
const CONTEXT_ENCODING = new Tiktoken(o200kBase);
|
|
24
|
+
export const SmartRouterProbeRecordSchema = z
|
|
25
|
+
.object({
|
|
26
|
+
enabled: z.boolean().describe("Whether the live Smart Router probe succeeded."),
|
|
27
|
+
expiresAt: z.number().int().describe("Epoch milliseconds when this probe becomes stale."),
|
|
28
|
+
})
|
|
29
|
+
.describe("Persisted Smart Router capability probe result.");
|
|
30
|
+
/** Error carrying an HTTP status for Smart Router validation or availability failures. */
|
|
31
|
+
export class SmartRouterError extends Error {
|
|
32
|
+
status;
|
|
33
|
+
constructor(status, message) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.status = status;
|
|
36
|
+
this.name = "SmartRouterError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** AppKit cache adapter; configured Lakebase/Postgres storage remains AppKit-owned. */
|
|
40
|
+
export class AppKitSmartRouterStore {
|
|
41
|
+
async get(key) {
|
|
42
|
+
const cache = await CacheManager.getInstance();
|
|
43
|
+
return cache.get(cache.generateKey([ROUTE_CACHE_NAMESPACE, ROUTE_POLICY_VERSION], key));
|
|
44
|
+
}
|
|
45
|
+
async set(key, value, ttlSeconds) {
|
|
46
|
+
const cache = await CacheManager.getInstance();
|
|
47
|
+
await cache.set(cache.generateKey([ROUTE_CACHE_NAMESPACE, ROUTE_POLICY_VERSION], key), value, {
|
|
48
|
+
ttl: ttlSeconds,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** AppKit cache adapter for process- and persistence-backed capability probes. */
|
|
53
|
+
export class AppKitSmartRouterProbeStore {
|
|
54
|
+
async get(key, client) {
|
|
55
|
+
const cache = appKitCacheManager();
|
|
56
|
+
if (!cache)
|
|
57
|
+
return undefined;
|
|
58
|
+
const identity = await smartRouterProbeIdentity(client);
|
|
59
|
+
return cache.get(cache.generateKey([PROBE_CACHE_NAMESPACE, PROBE_CACHE_VERSION], `${identity}:${key}`));
|
|
60
|
+
}
|
|
61
|
+
async set(key, value, ttlSeconds, client) {
|
|
62
|
+
const cache = appKitCacheManager();
|
|
63
|
+
if (!cache)
|
|
64
|
+
return;
|
|
65
|
+
const identity = await smartRouterProbeIdentity(client);
|
|
66
|
+
await cache.set(cache.generateKey([PROBE_CACHE_NAMESPACE, PROBE_CACHE_VERSION], `${identity}:${key}`), value, { ttl: ttlSeconds });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Dedicated Smart Router service for strings, request objects, message arrays,
|
|
71
|
+
* and generic JSON-like inputs.
|
|
72
|
+
*/
|
|
73
|
+
export class SmartRouterService {
|
|
74
|
+
settings;
|
|
75
|
+
invoke;
|
|
76
|
+
probeStore;
|
|
77
|
+
context;
|
|
78
|
+
probes = new WeakMap();
|
|
79
|
+
probeEntries = new Set();
|
|
80
|
+
probeRefreshTimer;
|
|
81
|
+
constructor(settings, invoke = invokeSmartRouter, probeStore = new AppKitSmartRouterProbeStore()) {
|
|
82
|
+
this.settings = settings;
|
|
83
|
+
this.invoke = invoke;
|
|
84
|
+
this.probeStore = probeStore;
|
|
85
|
+
this.context = new SmartRouterContextBuilder(settings.contextTokenBudget);
|
|
86
|
+
}
|
|
87
|
+
/** Select one offered route for arbitrary input content. */
|
|
88
|
+
async select(input, candidates, options = {}) {
|
|
89
|
+
const task = this.context.build(input);
|
|
90
|
+
if (!task)
|
|
91
|
+
throw new SmartRouterError(400, "Smart Router input contains no routable text");
|
|
92
|
+
const client = options.client ?? getExecutionContext().client;
|
|
93
|
+
try {
|
|
94
|
+
const selection = await this.selectTask(task, candidates, { ...options, client });
|
|
95
|
+
this.setProbeValue(candidates, client, true);
|
|
96
|
+
return selection;
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
this.setProbeUnavailable(candidates, client);
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** Return a memoized live capability probe for the active identity and candidate menu. */
|
|
104
|
+
async isEnabled(candidates, client = getExecutionContext().client) {
|
|
105
|
+
const offered = uniqueCandidates(candidates);
|
|
106
|
+
if (offered.length === 0)
|
|
107
|
+
return false;
|
|
108
|
+
const cache = this.probeCache(client);
|
|
109
|
+
const key = probeKey(offered, this.settings.routerName);
|
|
110
|
+
const now = Date.now();
|
|
111
|
+
const cached = cache.get(key);
|
|
112
|
+
if (cached) {
|
|
113
|
+
if (cached.value === undefined)
|
|
114
|
+
return cached.refresh;
|
|
115
|
+
if (cached.expiresAt <= now && !cached.refresh)
|
|
116
|
+
void this.refreshProbe(cached);
|
|
117
|
+
return cached.value;
|
|
118
|
+
}
|
|
119
|
+
const entry = this.createProbeEntry(cache, key, offered, client);
|
|
120
|
+
return this.initializeProbe(entry);
|
|
121
|
+
}
|
|
122
|
+
/** Stop this service's unref'd background probe refresh timer. */
|
|
123
|
+
dispose() {
|
|
124
|
+
if (this.probeRefreshTimer)
|
|
125
|
+
clearInterval(this.probeRefreshTimer);
|
|
126
|
+
this.probeRefreshTimer = undefined;
|
|
127
|
+
this.probeEntries.clear();
|
|
128
|
+
}
|
|
129
|
+
createProbeEntry(cache, key, candidates, client) {
|
|
130
|
+
const entry = {
|
|
131
|
+
cache,
|
|
132
|
+
candidates,
|
|
133
|
+
client: new WeakRef(client),
|
|
134
|
+
key,
|
|
135
|
+
expiresAt: 0,
|
|
136
|
+
};
|
|
137
|
+
this.replaceProbe(cache, key, entry);
|
|
138
|
+
return entry;
|
|
139
|
+
}
|
|
140
|
+
initializeProbe(entry) {
|
|
141
|
+
const client = entry.client.deref();
|
|
142
|
+
if (!client)
|
|
143
|
+
return Promise.resolve(false);
|
|
144
|
+
let refresh;
|
|
145
|
+
refresh = this.readStoredProbe(entry, client)
|
|
146
|
+
.then((stored) => {
|
|
147
|
+
if (stored && stored.expiresAt > Date.now()) {
|
|
148
|
+
entry.value = stored.enabled;
|
|
149
|
+
entry.expiresAt = stored.expiresAt;
|
|
150
|
+
return stored.enabled;
|
|
151
|
+
}
|
|
152
|
+
return this.executeProbe(entry, client);
|
|
153
|
+
})
|
|
154
|
+
.finally(() => {
|
|
155
|
+
if (entry.refresh === refresh)
|
|
156
|
+
entry.refresh = undefined;
|
|
157
|
+
});
|
|
158
|
+
entry.refresh = refresh;
|
|
159
|
+
return refresh;
|
|
160
|
+
}
|
|
161
|
+
refreshProbe(entry) {
|
|
162
|
+
if (entry.refresh)
|
|
163
|
+
return entry.refresh;
|
|
164
|
+
const client = entry.client.deref();
|
|
165
|
+
if (!client)
|
|
166
|
+
return Promise.resolve(false);
|
|
167
|
+
let refresh;
|
|
168
|
+
refresh = this.executeProbe(entry, client).finally(() => {
|
|
169
|
+
if (entry.refresh === refresh)
|
|
170
|
+
entry.refresh = undefined;
|
|
171
|
+
});
|
|
172
|
+
entry.refresh = refresh;
|
|
173
|
+
return refresh;
|
|
174
|
+
}
|
|
175
|
+
async executeProbe(entry, client) {
|
|
176
|
+
const enabled = await this.selectTask(PROBE_TASK, entry.candidates, { client })
|
|
177
|
+
.then(() => true)
|
|
178
|
+
.catch((error) => {
|
|
179
|
+
logger.debug("Smart Router capability probe unavailable", { error: toError(error) });
|
|
180
|
+
return false;
|
|
181
|
+
});
|
|
182
|
+
if (entry.cache.get(entry.key) === entry) {
|
|
183
|
+
this.updateProbeEntry(entry, enabled);
|
|
184
|
+
void this.writeStoredProbe(entry, enabled, client);
|
|
185
|
+
}
|
|
186
|
+
return enabled;
|
|
187
|
+
}
|
|
188
|
+
setProbeValue(candidates, client, enabled) {
|
|
189
|
+
const offered = uniqueCandidates(candidates);
|
|
190
|
+
if (offered.length === 0)
|
|
191
|
+
return;
|
|
192
|
+
const cache = this.probeCache(client);
|
|
193
|
+
const key = probeKey(offered, this.settings.routerName);
|
|
194
|
+
const entry = cache.get(key) ?? this.createProbeEntry(cache, key, offered, client);
|
|
195
|
+
this.updateProbeEntry(entry, enabled);
|
|
196
|
+
void this.writeStoredProbe(entry, enabled, client);
|
|
197
|
+
}
|
|
198
|
+
setProbeUnavailable(candidates, client) {
|
|
199
|
+
const cache = this.probeCache(client);
|
|
200
|
+
for (const cached of cache.values()) {
|
|
201
|
+
this.updateProbeEntry(cached, false);
|
|
202
|
+
void this.writeStoredProbe(cached, false, client);
|
|
203
|
+
}
|
|
204
|
+
this.setProbeValue(candidates, client, false);
|
|
205
|
+
}
|
|
206
|
+
updateProbeEntry(entry, enabled) {
|
|
207
|
+
entry.value = enabled;
|
|
208
|
+
entry.expiresAt = Date.now() + this.probeTtl(enabled);
|
|
209
|
+
}
|
|
210
|
+
async readStoredProbe(entry, client) {
|
|
211
|
+
try {
|
|
212
|
+
const parsed = SmartRouterProbeRecordSchema.safeParse(await this.probeStore.get(entry.key, client));
|
|
213
|
+
return parsed.success ? parsed.data : undefined;
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
logger.debug("Smart Router probe cache read failed", { error: toError(error) });
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async writeStoredProbe(entry, enabled, client) {
|
|
221
|
+
try {
|
|
222
|
+
await this.probeStore.set(entry.key, { enabled, expiresAt: entry.expiresAt }, Math.max(1, Math.ceil((Math.max(this.settings.probeRefreshIntervalMs, this.settings.probeTtlMs) * 2) / 1_000)), client);
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
logger.debug("Smart Router probe cache write failed", { error: toError(error) });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
probeCache(client) {
|
|
229
|
+
const owner = client.config;
|
|
230
|
+
let cache = this.probes.get(owner);
|
|
231
|
+
if (!cache) {
|
|
232
|
+
cache = new Map();
|
|
233
|
+
this.probes.set(owner, cache);
|
|
234
|
+
}
|
|
235
|
+
return cache;
|
|
236
|
+
}
|
|
237
|
+
replaceProbe(cache, key, entry) {
|
|
238
|
+
const previous = cache.get(key);
|
|
239
|
+
if (previous)
|
|
240
|
+
this.probeEntries.delete(previous);
|
|
241
|
+
cache.set(key, entry);
|
|
242
|
+
this.probeEntries.add(entry);
|
|
243
|
+
this.ensureProbeRefreshTimer();
|
|
244
|
+
}
|
|
245
|
+
probeTtl(enabled) {
|
|
246
|
+
return enabled
|
|
247
|
+
? this.settings.probeTtlMs
|
|
248
|
+
: Math.min(this.settings.probeTtlMs, NEGATIVE_PROBE_TTL_MS);
|
|
249
|
+
}
|
|
250
|
+
ensureProbeRefreshTimer() {
|
|
251
|
+
if (this.probeRefreshTimer)
|
|
252
|
+
return;
|
|
253
|
+
this.probeRefreshTimer = setInterval(() => {
|
|
254
|
+
void this.refreshProbes();
|
|
255
|
+
}, this.settings.probeRefreshIntervalMs);
|
|
256
|
+
this.probeRefreshTimer.unref();
|
|
257
|
+
}
|
|
258
|
+
async refreshProbes() {
|
|
259
|
+
const refreshes = [];
|
|
260
|
+
for (const entry of [...this.probeEntries]) {
|
|
261
|
+
if (entry.cache.get(entry.key) !== entry) {
|
|
262
|
+
this.probeEntries.delete(entry);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
const client = entry.client.deref();
|
|
266
|
+
if (!client) {
|
|
267
|
+
entry.cache.delete(entry.key);
|
|
268
|
+
this.probeEntries.delete(entry);
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
if (!entry.refresh)
|
|
272
|
+
refreshes.push(this.refreshProbe(entry));
|
|
273
|
+
}
|
|
274
|
+
await Promise.allSettled(refreshes);
|
|
275
|
+
}
|
|
276
|
+
async selectTask(task, candidates, options) {
|
|
277
|
+
const offered = uniqueCandidates(candidates);
|
|
278
|
+
if (offered.length === 0) {
|
|
279
|
+
throw new SmartRouterError(400, "No compatible system models are available to Smart Router");
|
|
280
|
+
}
|
|
281
|
+
const request = SmartRouterRequestSchema.parse({
|
|
282
|
+
route_options: offered.map(({ model, harness }) => ({ model, harness })),
|
|
283
|
+
task: { prompt: task },
|
|
284
|
+
route_selector: { router_name: this.settings.routerName },
|
|
285
|
+
});
|
|
286
|
+
const client = options.client ?? getExecutionContext().client;
|
|
287
|
+
const signal = options.signal ?? new AbortController().signal;
|
|
288
|
+
const startedAt = Date.now();
|
|
289
|
+
const response = SmartRouterResponseSchema.parse(await this.invoke(client, request, signal, this.settings.timeoutMs));
|
|
290
|
+
const selection = response.route_selection[0];
|
|
291
|
+
const selected = offered.find((candidate) => normalizeRouteModel(candidate.model) ===
|
|
292
|
+
normalizeRouteModel(selection.route_option.model) &&
|
|
293
|
+
(!selection.route_option.harness || candidate.harness === selection.route_option.harness));
|
|
294
|
+
if (!selected) {
|
|
295
|
+
throw new SmartRouterError(502, `Smart Router selected an unsupported model: ${selection.route_option.model}`);
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
value: selected.value,
|
|
299
|
+
routeModel: selection.route_option.model,
|
|
300
|
+
harness: selected.harness,
|
|
301
|
+
routerName: this.settings.routerName,
|
|
302
|
+
latencyMs: Date.now() - startedAt,
|
|
303
|
+
...(response.rationale ? { rationale: response.rationale } : {}),
|
|
304
|
+
...(selection.params ? { params: selection.params } : {}),
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/** Build a Smart Router candidate menu from values carrying modelServiceName. */
|
|
309
|
+
export function smartRouterCandidates(values, harness) {
|
|
310
|
+
return values.flatMap((value) => {
|
|
311
|
+
const model = value.modelServiceName?.trim();
|
|
312
|
+
if (!model || !model.toLowerCase().startsWith("system.ai."))
|
|
313
|
+
return [];
|
|
314
|
+
return [{ model, harness, value }];
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Context extractor shared by the gateway, Mastra, and the file/stdin CLI.
|
|
319
|
+
* It favors conversation/task fields and ignores credentials, tool schemas,
|
|
320
|
+
* and tool arguments.
|
|
321
|
+
*/
|
|
322
|
+
export class SmartRouterContextBuilder {
|
|
323
|
+
tokenBudget;
|
|
324
|
+
constructor(tokenBudget = 4_096) {
|
|
325
|
+
this.tokenBudget = tokenBudget;
|
|
326
|
+
}
|
|
327
|
+
/** Return only the bounded task prompt required by routes:select. */
|
|
328
|
+
build(input) {
|
|
329
|
+
return this.analyze(input).task;
|
|
330
|
+
}
|
|
331
|
+
/** Return bounded task text plus logical-turn metadata used for pinning. */
|
|
332
|
+
analyze(input) {
|
|
333
|
+
const normalized = parseJsonString(input);
|
|
334
|
+
const events = conversationEvents(normalized);
|
|
335
|
+
if (events.length > 0)
|
|
336
|
+
return contextFromEvents(events, this.tokenBudget);
|
|
337
|
+
const values = collectTaskStrings(normalized);
|
|
338
|
+
const task = truncateText(values.join("\n"), this.tokenBudget, "start");
|
|
339
|
+
return { task, logicalTurn: task, continuation: false };
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/** Smart Router orchestration shared by Responses, Chat Completions, and Messages. */
|
|
343
|
+
export class SmartModelRouter {
|
|
344
|
+
settings;
|
|
345
|
+
store;
|
|
346
|
+
client;
|
|
347
|
+
service;
|
|
348
|
+
constructor(settings, service = new SmartRouterService(settings), store = new AppKitSmartRouterStore(), client) {
|
|
349
|
+
this.settings = settings;
|
|
350
|
+
this.store = store;
|
|
351
|
+
this.client = client;
|
|
352
|
+
this.service = service;
|
|
353
|
+
}
|
|
354
|
+
/** Probe whether Smart Router is usable for the current model catalogue. */
|
|
355
|
+
isEnabled(targets) {
|
|
356
|
+
const candidates = smartRouterCandidates(targets.filter((target) => target.capabilities.chat && target.capabilities.aiGatewayCodex), "codex");
|
|
357
|
+
return this.client
|
|
358
|
+
? this.service.isEnabled(candidates, this.client)
|
|
359
|
+
: this.service.isEnabled(candidates);
|
|
360
|
+
}
|
|
361
|
+
/** Resolve one virtual smart-router request to a concrete compatible target. */
|
|
362
|
+
async resolve(input) {
|
|
363
|
+
const harness = input.protocol === "anthropic-messages" ? "claude" : "codex";
|
|
364
|
+
const explicitReasoningEffort = requestedReasoningEffort(input.body);
|
|
365
|
+
const eligibleTargets = input.targets.filter((target) => isEligibleTarget(target, { ...input, originator: input.headers.get("originator") ?? undefined }, explicitReasoningEffort, harness));
|
|
366
|
+
const candidates = smartRouterCandidates(eligibleTargets, harness);
|
|
367
|
+
if (candidates.length === 0) {
|
|
368
|
+
throw new SmartRouterError(400, "No compatible system models are available to Databricks Smart Router");
|
|
369
|
+
}
|
|
370
|
+
const context = this.service.context.analyze(input.body);
|
|
371
|
+
if (!context.task) {
|
|
372
|
+
throw new SmartRouterError(400, "Smart Router request contains no task text");
|
|
373
|
+
}
|
|
374
|
+
const key = smartRouterTurnKey(context.logicalTurn, candidates, {
|
|
375
|
+
harness,
|
|
376
|
+
protocol: input.protocol,
|
|
377
|
+
features: input.features,
|
|
378
|
+
...(explicitReasoningEffort ? { explicitReasoningEffort } : {}),
|
|
379
|
+
});
|
|
380
|
+
const cached = context.continuation ? await this.readCached(key, eligibleTargets) : undefined;
|
|
381
|
+
if (cached) {
|
|
382
|
+
return {
|
|
383
|
+
target: eligibleTargets.find((target) => target.id === cached.selectedModel),
|
|
384
|
+
body: input.body,
|
|
385
|
+
observation: { ...cached, source: "cache" },
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
const selected = await this.service.select(context.task, candidates, {
|
|
389
|
+
signal: input.signal,
|
|
390
|
+
...(this.client ? { client: this.client } : {}),
|
|
391
|
+
});
|
|
392
|
+
const target = selected.value;
|
|
393
|
+
const observation = SmartRouterObservationSchema.parse({
|
|
394
|
+
selectedModel: target.id,
|
|
395
|
+
routeModel: selected.routeModel,
|
|
396
|
+
harness: selected.harness,
|
|
397
|
+
routerName: selected.routerName,
|
|
398
|
+
source: "router",
|
|
399
|
+
latencyMs: selected.latencyMs,
|
|
400
|
+
...(selected.rationale ? { rationale: selected.rationale } : {}),
|
|
401
|
+
...(selected.params ? { params: selected.params } : {}),
|
|
402
|
+
});
|
|
403
|
+
await this.writeCached(key, observation);
|
|
404
|
+
logger.debug("selected Smart Router model", {
|
|
405
|
+
candidateCount: candidates.length,
|
|
406
|
+
harness,
|
|
407
|
+
latencyMs: observation.latencyMs,
|
|
408
|
+
model: observation.selectedModel,
|
|
409
|
+
routeModel: observation.routeModel,
|
|
410
|
+
routerName: observation.routerName,
|
|
411
|
+
});
|
|
412
|
+
return { target, body: input.body, observation };
|
|
413
|
+
}
|
|
414
|
+
async readCached(key, targets) {
|
|
415
|
+
try {
|
|
416
|
+
const parsed = SmartRouterObservationSchema.safeParse(await this.store.get(key));
|
|
417
|
+
if (!parsed.success)
|
|
418
|
+
return undefined;
|
|
419
|
+
return targets.some((target) => target.id === parsed.data.selectedModel)
|
|
420
|
+
? parsed.data
|
|
421
|
+
: undefined;
|
|
422
|
+
}
|
|
423
|
+
catch (error) {
|
|
424
|
+
logger.debug("Smart Router cache read failed", { error: toError(error) });
|
|
425
|
+
return undefined;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
async writeCached(key, observation) {
|
|
429
|
+
try {
|
|
430
|
+
await this.store.set(key, observation, this.settings.routeTtlSeconds);
|
|
431
|
+
}
|
|
432
|
+
catch (error) {
|
|
433
|
+
logger.debug("Smart Router cache write failed", { error: toError(error) });
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
/** Stable logical-turn key shared by initial requests and tool continuations. */
|
|
438
|
+
export function smartRouterTurnKey(logicalTurn, candidates, context) {
|
|
439
|
+
return createHash("sha256")
|
|
440
|
+
.update(JSON.stringify({
|
|
441
|
+
logicalTurn,
|
|
442
|
+
candidates: candidates.map(({ model, harness }) => ({ model, harness })),
|
|
443
|
+
context,
|
|
444
|
+
}))
|
|
445
|
+
.digest("hex");
|
|
446
|
+
}
|
|
447
|
+
function isEligibleTarget(target, input, explicitReasoningEffort, harness) {
|
|
448
|
+
if (!target.endpoint || target.endpoint.status?.deprecated === true)
|
|
449
|
+
return false;
|
|
450
|
+
if (!target.modelServiceName?.toLowerCase().startsWith("system.ai."))
|
|
451
|
+
return false;
|
|
452
|
+
if (!target.capabilities.chat)
|
|
453
|
+
return false;
|
|
454
|
+
if (harness === "codex" && !target.capabilities.aiGatewayCodex)
|
|
455
|
+
return false;
|
|
456
|
+
if (harness === "claude" && !target.capabilities.anthropic)
|
|
457
|
+
return false;
|
|
458
|
+
if (input.features.tools && !target.capabilities.tools)
|
|
459
|
+
return false;
|
|
460
|
+
if (input.features.parallelTools && !target.capabilities.parallelTools)
|
|
461
|
+
return false;
|
|
462
|
+
if (input.features.customTools && !target.capabilities.customTools)
|
|
463
|
+
return false;
|
|
464
|
+
if (input.features.structuredOutput && !target.capabilities.structuredOutput)
|
|
465
|
+
return false;
|
|
466
|
+
if (input.features.webSearch && !target.capabilities.webSearch)
|
|
467
|
+
return false;
|
|
468
|
+
if (input.features.imageInput && !target.capabilities.imageInput)
|
|
469
|
+
return false;
|
|
470
|
+
if (input.features.applyPatch && !target.capabilities.applyPatch)
|
|
471
|
+
return false;
|
|
472
|
+
if (input.features.reasoning && !target.capabilities.reasoning)
|
|
473
|
+
return false;
|
|
474
|
+
if (explicitReasoningEffort &&
|
|
475
|
+
explicitReasoningEffort !== "none" &&
|
|
476
|
+
!target.reasoningEfforts.includes(explicitReasoningEffort)) {
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
try {
|
|
480
|
+
resolveRoute({
|
|
481
|
+
clientProtocol: input.protocol,
|
|
482
|
+
...(input.originator ? { originator: input.originator } : {}),
|
|
483
|
+
preferSystemModels: input.preferSystemModels,
|
|
484
|
+
features: input.features,
|
|
485
|
+
target,
|
|
486
|
+
});
|
|
487
|
+
return true;
|
|
488
|
+
}
|
|
489
|
+
catch {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
function requestedReasoningEffort(body) {
|
|
494
|
+
const reasoning = isRecord(body.reasoning) ? body.reasoning : undefined;
|
|
495
|
+
const outputConfig = isRecord(body.output_config) ? body.output_config : undefined;
|
|
496
|
+
const raw = body.reasoning_effort ?? reasoning?.effort ?? outputConfig?.effort;
|
|
497
|
+
if (raw === undefined || raw === null)
|
|
498
|
+
return undefined;
|
|
499
|
+
const normalized = String(raw).trim().toLowerCase().replaceAll("_", "-");
|
|
500
|
+
const parsed = ReasoningEffortSchema.safeParse(normalized === "extra-high" ? "xhigh" : normalized);
|
|
501
|
+
if (!parsed.success) {
|
|
502
|
+
throw new SmartRouterError(400, `Unsupported Smart Router reasoning effort: ${String(raw)}`);
|
|
503
|
+
}
|
|
504
|
+
return parsed.data;
|
|
505
|
+
}
|
|
506
|
+
function contextFromEvents(events, tokenBudget) {
|
|
507
|
+
const latestUserIndex = lastEventIndex(events, "user");
|
|
508
|
+
const taskEvent = latestUserIndex >= 0 ? events[latestUserIndex] : events.at(-1);
|
|
509
|
+
const task = truncateText(taskEvent?.text ?? "", tokenBudget, "start");
|
|
510
|
+
let remaining = Math.max(0, tokenBudget - countTokens(task));
|
|
511
|
+
const context = [];
|
|
512
|
+
for (let index = (taskEvent ? events.indexOf(taskEvent) : events.length) - 1; index >= 0; index -= 1) {
|
|
513
|
+
const event = events[index];
|
|
514
|
+
if (!event || !event.text || event.role === "tool")
|
|
515
|
+
continue;
|
|
516
|
+
const value = `${event.role}: ${event.text}`;
|
|
517
|
+
const retained = truncateText(value, remaining, "end");
|
|
518
|
+
if (!retained)
|
|
519
|
+
break;
|
|
520
|
+
context.unshift(retained);
|
|
521
|
+
remaining -= countTokens(retained);
|
|
522
|
+
}
|
|
523
|
+
const combined = [...context, task].filter(Boolean).join("\n");
|
|
524
|
+
const logicalEvents = latestUserIndex >= 0 ? events.slice(0, latestUserIndex + 1) : events;
|
|
525
|
+
return {
|
|
526
|
+
task: combined,
|
|
527
|
+
logicalTurn: logicalEvents.map((event) => `${event.role}:${event.text}`).join("\n"),
|
|
528
|
+
continuation: latestUserIndex >= 0 &&
|
|
529
|
+
events.slice(latestUserIndex + 1).some((event) => event.role !== "system"),
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
function conversationEvents(input) {
|
|
533
|
+
if (typeof input === "string")
|
|
534
|
+
return input.trim() ? [{ role: "user", text: input.trim() }] : [];
|
|
535
|
+
if (Array.isArray(input))
|
|
536
|
+
return input.flatMap(messageEvent);
|
|
537
|
+
if (!isRecord(input))
|
|
538
|
+
return [];
|
|
539
|
+
for (const key of ["messages", "input"]) {
|
|
540
|
+
const value = input[key];
|
|
541
|
+
if (typeof value === "string" && value.trim())
|
|
542
|
+
return [{ role: "user", text: value.trim() }];
|
|
543
|
+
if (Array.isArray(value)) {
|
|
544
|
+
const events = value.flatMap(messageEvent);
|
|
545
|
+
if (events.length > 0)
|
|
546
|
+
return events;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return [];
|
|
550
|
+
}
|
|
551
|
+
function messageEvent(value) {
|
|
552
|
+
if (typeof value === "string")
|
|
553
|
+
return value.trim() ? [{ role: "user", text: value.trim() }] : [];
|
|
554
|
+
if (!isRecord(value))
|
|
555
|
+
return [];
|
|
556
|
+
const role = messageRole(value);
|
|
557
|
+
if (!role)
|
|
558
|
+
return [];
|
|
559
|
+
const text = contentText(value.content ?? value.text ?? value.input_text ?? value.output_text);
|
|
560
|
+
return text ? [{ role, text }] : [];
|
|
561
|
+
}
|
|
562
|
+
function messageRole(value) {
|
|
563
|
+
if (value.role === "user" || value.role === "assistant" || value.role === "system") {
|
|
564
|
+
return value.role;
|
|
565
|
+
}
|
|
566
|
+
if (value.role === "tool" ||
|
|
567
|
+
value.type === "function_call_output" ||
|
|
568
|
+
value.type === "tool_result") {
|
|
569
|
+
return "tool";
|
|
570
|
+
}
|
|
571
|
+
if (value.type === "function_call" || value.type === "reasoning")
|
|
572
|
+
return "assistant";
|
|
573
|
+
if (value.type === "message" && value.role === undefined)
|
|
574
|
+
return "user";
|
|
575
|
+
return undefined;
|
|
576
|
+
}
|
|
577
|
+
function contentText(value) {
|
|
578
|
+
if (typeof value === "string")
|
|
579
|
+
return value.trim();
|
|
580
|
+
if (Array.isArray(value))
|
|
581
|
+
return value.map(contentText).filter(Boolean).join("\n");
|
|
582
|
+
if (!isRecord(value))
|
|
583
|
+
return "";
|
|
584
|
+
for (const key of ["text", "input_text", "output_text", "content"]) {
|
|
585
|
+
const text = contentText(value[key]);
|
|
586
|
+
if (text)
|
|
587
|
+
return text;
|
|
588
|
+
}
|
|
589
|
+
return "";
|
|
590
|
+
}
|
|
591
|
+
const TASK_KEYS = [
|
|
592
|
+
"prompt",
|
|
593
|
+
"task",
|
|
594
|
+
"query",
|
|
595
|
+
"question",
|
|
596
|
+
"request",
|
|
597
|
+
"description",
|
|
598
|
+
"message",
|
|
599
|
+
"text",
|
|
600
|
+
"input",
|
|
601
|
+
];
|
|
602
|
+
const IGNORED_KEYS = new Set([
|
|
603
|
+
"api_key",
|
|
604
|
+
"authorization",
|
|
605
|
+
"arguments",
|
|
606
|
+
"credentials",
|
|
607
|
+
"headers",
|
|
608
|
+
"metadata",
|
|
609
|
+
"password",
|
|
610
|
+
"secret",
|
|
611
|
+
"token",
|
|
612
|
+
"tools",
|
|
613
|
+
]);
|
|
614
|
+
function collectTaskStrings(input) {
|
|
615
|
+
if (typeof input === "string")
|
|
616
|
+
return input.trim() ? [input.trim()] : [];
|
|
617
|
+
const preferred = [];
|
|
618
|
+
if (isRecord(input)) {
|
|
619
|
+
for (const key of TASK_KEYS)
|
|
620
|
+
preferred.push(...stringLeaves(input[key], key, 0));
|
|
621
|
+
}
|
|
622
|
+
return preferred.length > 0 ? preferred.slice(0, 32) : stringLeaves(input, "", 0).slice(0, 32);
|
|
623
|
+
}
|
|
624
|
+
function stringLeaves(value, key, depth) {
|
|
625
|
+
if (depth > 6 || IGNORED_KEYS.has(key.toLowerCase()))
|
|
626
|
+
return [];
|
|
627
|
+
if (typeof value === "string")
|
|
628
|
+
return value.trim() ? [value.trim()] : [];
|
|
629
|
+
if (Array.isArray(value))
|
|
630
|
+
return value.flatMap((item) => stringLeaves(item, key, depth + 1));
|
|
631
|
+
if (!isRecord(value))
|
|
632
|
+
return [];
|
|
633
|
+
return Object.entries(value).flatMap(([childKey, child]) => stringLeaves(child, childKey, depth + 1));
|
|
634
|
+
}
|
|
635
|
+
function parseJsonString(input) {
|
|
636
|
+
if (typeof input !== "string")
|
|
637
|
+
return input;
|
|
638
|
+
const trimmed = input.trim();
|
|
639
|
+
if (!trimmed || (!trimmed.startsWith("{") && !trimmed.startsWith("[")))
|
|
640
|
+
return input;
|
|
641
|
+
try {
|
|
642
|
+
return JSON.parse(trimmed);
|
|
643
|
+
}
|
|
644
|
+
catch {
|
|
645
|
+
return input;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
function countTokens(text) {
|
|
649
|
+
return CONTEXT_ENCODING.encode(text, [], []).length;
|
|
650
|
+
}
|
|
651
|
+
function truncateText(text, tokenBudget, edge) {
|
|
652
|
+
if (tokenBudget <= 0 || !text)
|
|
653
|
+
return "";
|
|
654
|
+
const tokens = CONTEXT_ENCODING.encode(text, [], []);
|
|
655
|
+
if (tokens.length <= tokenBudget)
|
|
656
|
+
return text;
|
|
657
|
+
return CONTEXT_ENCODING.decode(edge === "start" ? tokens.slice(0, tokenBudget) : tokens.slice(-tokenBudget));
|
|
658
|
+
}
|
|
659
|
+
function lastEventIndex(events, role) {
|
|
660
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
661
|
+
if (events[index]?.role === role)
|
|
662
|
+
return index;
|
|
663
|
+
}
|
|
664
|
+
return -1;
|
|
665
|
+
}
|
|
666
|
+
function uniqueCandidates(candidates) {
|
|
667
|
+
const seen = new Set();
|
|
668
|
+
return candidates.filter((candidate) => {
|
|
669
|
+
const key = `${candidate.harness}:${normalizeRouteModel(candidate.model)}`;
|
|
670
|
+
if (seen.has(key))
|
|
671
|
+
return false;
|
|
672
|
+
seen.add(key);
|
|
673
|
+
return true;
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
function normalizeRouteModel(model) {
|
|
677
|
+
let normalized = model.trim().toLowerCase().split("/").at(-1) ?? "";
|
|
678
|
+
for (const prefix of ["databricks-", "system.ai."]) {
|
|
679
|
+
if (normalized.startsWith(prefix)) {
|
|
680
|
+
normalized = normalized.slice(prefix.length);
|
|
681
|
+
break;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return normalized;
|
|
685
|
+
}
|
|
686
|
+
function probeKey(candidates, routerName) {
|
|
687
|
+
return JSON.stringify({
|
|
688
|
+
routerName,
|
|
689
|
+
candidates: candidates
|
|
690
|
+
.map(({ model, harness }) => ({ model: normalizeRouteModel(model), harness }))
|
|
691
|
+
.sort((left, right) => `${left.harness}:${left.model}`.localeCompare(`${right.harness}:${right.model}`)),
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
function appKitCacheManager() {
|
|
695
|
+
try {
|
|
696
|
+
return CacheManager.getInstanceSync();
|
|
697
|
+
}
|
|
698
|
+
catch {
|
|
699
|
+
return undefined;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
async function smartRouterProbeIdentity(client) {
|
|
703
|
+
const headers = new Headers();
|
|
704
|
+
const host = (await client.config.getHost()).toString();
|
|
705
|
+
await client.config.authenticate(headers);
|
|
706
|
+
return createHash("sha256")
|
|
707
|
+
.update(host)
|
|
708
|
+
.update("\0")
|
|
709
|
+
.update(headers.get("authorization") ?? "")
|
|
710
|
+
.update("\0")
|
|
711
|
+
.update(headers.get("x-databricks-workspace-id") ?? "")
|
|
712
|
+
.digest("hex");
|
|
713
|
+
}
|
|
714
|
+
async function invokeSmartRouter(client, body, signal, timeoutMs) {
|
|
715
|
+
const host = (await client.config.getHost()).toString();
|
|
716
|
+
const url = new URL("/ai-gateway/routing/v1/routes:select", host);
|
|
717
|
+
const headers = new Headers({ "content-type": "application/json" });
|
|
718
|
+
await client.config.authenticate(headers);
|
|
719
|
+
const combinedSignal = AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]);
|
|
720
|
+
let response = await fetch(url, {
|
|
721
|
+
method: "POST",
|
|
722
|
+
headers,
|
|
723
|
+
body: JSON.stringify(body),
|
|
724
|
+
signal: combinedSignal,
|
|
725
|
+
});
|
|
726
|
+
if (response.status === 401 && (await refreshWorkspaceClientAuthentication(client))) {
|
|
727
|
+
await response.body?.cancel();
|
|
728
|
+
headers.delete("authorization");
|
|
729
|
+
headers.delete("x-databricks-workspace-id");
|
|
730
|
+
await client.config.authenticate(headers);
|
|
731
|
+
response = await fetch(url, {
|
|
732
|
+
method: "POST",
|
|
733
|
+
headers,
|
|
734
|
+
body: JSON.stringify(body),
|
|
735
|
+
signal: combinedSignal,
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
if (!response.ok) {
|
|
739
|
+
const detail = (await response.text().catch(() => "")).trim().slice(0, 500);
|
|
740
|
+
throw new SmartRouterError(response.status === 404 ? 404 : 503, `Databricks Smart Router failed with HTTP ${response.status}${detail ? `: ${detail}` : ""}`);
|
|
741
|
+
}
|
|
742
|
+
return response.json();
|
|
743
|
+
}
|
|
744
|
+
/** Defaults shared by gateway, Mastra, and CLI Smart Router callers. */
|
|
745
|
+
export const SMART_ROUTER_DEFAULT_SETTINGS = Object.freeze({
|
|
746
|
+
contextTokenBudget: 4_096,
|
|
747
|
+
probeRefreshIntervalMs: 3_600_000,
|
|
748
|
+
probeTtlMs: 300_000,
|
|
749
|
+
routeTtlSeconds: 21_600,
|
|
750
|
+
routerName: SMART_ROUTER_NAME,
|
|
751
|
+
timeoutMs: 10_000,
|
|
752
|
+
});
|
|
753
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnQtcm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NtYXJ0LXJvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBRUgsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN6QyxPQUFPLEVBQUUsWUFBWSxFQUFFLG1CQUFtQixFQUF3QixNQUFNLG9CQUFvQixDQUFDO0FBQzdGLE9BQU8sRUFBRSxvQ0FBb0MsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzdFLE9BQU8sRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxxQkFBcUIsRUFBd0IsTUFBTSx5QkFBeUIsQ0FBQztBQUN0RixPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLDRCQUE0QixFQUM1Qix3QkFBd0IsRUFDeEIseUJBQXlCLEdBTzFCLE1BQU0saUNBQWlDLENBQUM7QUFDekMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sU0FBUyxNQUFNLDhCQUE4QixDQUFDO0FBQ3JELE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFFeEIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUUzQyxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLG1DQUFtQyxDQUFDLENBQUM7QUFDL0QsTUFBTSxxQkFBcUIsR0FBRyw0QkFBNEIsQ0FBQztBQUMzRCxNQUFNLG9CQUFvQixHQUFHLENBQUMsQ0FBQztBQUMvQixNQUFNLHFCQUFxQixHQUFHLGtDQUFrQyxDQUFDO0FBQ2pFLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO0FBQzlCLE1BQU0sVUFBVSxHQUFHLDJEQUEyRCxDQUFDO0FBQy9FLE1BQU0scUJBQXFCLEdBQUcsTUFBTSxDQUFDO0FBQ3JDLE1BQU0sZ0JBQWdC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a0IsRUFBRSxLQUFLO0lBQ3pCLHNCQUFzQixFQUFFLFNBQVM7SUFDakMsVUFBVSxFQUFFLE9BQU87SUFDbkIsZUFBZSxFQUFFLE1BQU07SUFDdkIsVUFBVSxFQUFFLGlCQUFpQjtJQUM3QixTQUFTLEVBQUUsTUFBTTtDQUNsQixDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIERhdGFicmlja3MgU21hcnQgUm91dGVyIHRyYW5zcG9ydCwgY29udGV4dCBjb25zdHJ1Y3Rpb24sIHByb2JpbmcsIGFuZCB0dXJuIHBpbm5pbmcuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGNyZWF0ZUhhc2ggfSBmcm9tIFwibm9kZTpjcnlwdG9cIjtcbmltcG9ydCB7IENhY2hlTWFuYWdlciwgZ2V0RXhlY3V0aW9uQ29udGV4dCwgdHlwZSBXb3Jrc3BhY2VDbGllbnQgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyByZWZyZXNoV29ya3NwYWNlQ2xpZW50QXV0aGVudGljYXRpb24gfSBmcm9tIFwiQGRieC10b29scy9kYXRhYnJpY2tzXCI7XG5pbXBvcnQgeyBpc1JlY29yZCwgbG9nLCB0b0Vycm9yIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IFJlYXNvbmluZ0VmZm9ydFNjaGVtYSwgdHlwZSBSZWFzb25pbmdFZmZvcnQgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtbW9kZWxcIjtcbmltcG9ydCB7XG4gIFNNQVJUX1JPVVRFUl9OQU1FLFxuICBTbWFydFJvdXRlck9ic2VydmF0aW9uU2NoZW1hLFxuICBTbWFydFJvdXRlclJlcXVlc3RTY2hlbWEsXG4gIFNtYXJ0Um91dGVyUmVzcG9uc2VTY2hlbWEsXG4gIHR5cGUgQ2xpZW50UHJvdG9jb2wsXG4gIHR5cGUgTW9kZWxUYXJnZXQsXG4gIHR5cGUgUmVxdWVzdGVkRmVhdHVyZXMsXG4gIHR5cGUgU21hcnRSb3V0ZXJIYXJuZXNzLFxuICB0eXBlIFNtYXJ0Um91dGVyT2JzZXJ2YXRpb24sXG4gIHR5cGUgU21hcnRSb3V0ZXJSZXF1ZXN0LFxufSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtbW9kZWwtZ2F0ZXdheVwiO1xuaW1wb3J0IHsgVGlrdG9rZW4gfSBmcm9tIFwianMtdGlrdG9rZW4vbGl0ZVwiO1xuaW1wb3J0IG8yMDBrQmFzZSBmcm9tIFwianMtdGlrdG9rZW4vcmFua3MvbzIwMGtfYmFzZVwiO1xuaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcblxuaW1wb3J0IHsgcmVzb2x2ZVJvdXRlIH0gZnJvbSBcIi4vcm91dGVyLnRzXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJhcHBraXQvbW9kZWwtZ2F0ZXdheS9zbWFydC1yb3V0ZXJcIik7XG5jb25zdCBST1VURV9DQUNIRV9OQU1FU1BBQ0UgPSBcIm1vZGVsLWdhdGV3YXktc21hcnQtcm91dGVyXCI7XG5jb25zdCBST1VURV9QT0xJQ1lfVkVSU0lPTiA9IDE7XG5jb25zdCBQUk9CRV9DQUNIRV9OQU1FU1BBQ0UgPSBcIm1vZGVsLWdhdGV3YXktc21hcnQtcm91dGVyLXByb2JlXCI7XG5jb25zdCBQUk9CRV9DQUNIRV9WRVJTSU9OID0gMTtcbmNvbnN0IFBST0JFX1RBU0sgPSBcIkNoZWNrIHdoZXRoZXIgU21hcnQgUm91dGVyIGNhbiBzZWxlY3QgYW4gYXZhaWxhYmxlIG1vZGVsLlwiO1xuY29uc3QgTkVHQVRJVkVfUFJPQkVfVFRMX01TID0gMzBfMDAwO1xuY29uc3QgQ09OVEVYVF9FTkNPRElORyA9IG5ldyBUaWt0b2tlbihvMjAwa0Jhc2UpO1xuXG4vKiogUnVudGltZSBzZXR0aW5ncyBmb3IgU21hcnQgUm91dGVyLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTbWFydFJvdXRlclNldHRpbmdzIHtcbiAgcmVhZG9ubHkgY29udGV4dFRva2VuQnVkZ2V0OiBudW1iZXI7XG4gIHJlYWRvbmx5IHByb2JlUmVmcmVzaEludGVydmFsTXM6IG51bWJlcjtcbiAgcmVhZG9ubHkgcHJvYmVUdGxNczogbnVtYmVyO1xuICByZWFkb25seSByb3V0ZVR0bFNlY29uZHM6IG51bWJlcjtcbiAgcmVhZG9ubHkgcm91dGVyTmFtZTogc3RyaW5nO1xuICByZWFkb25seSB0aW1lb3V0TXM6IG51bWJlcjtcbn1cblxuLyoqIE9uZSByb3V0ZSBvcHRpb24gYXNzb2NpYXRlZCB3aXRoIHRoZSBjYWxsZXItb3duZWQgdmFsdWUgaXQgcmVwcmVzZW50cy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU21hcnRSb3V0ZXJDYW5kaWRhdGU8VD4ge1xuICByZWFkb25seSBoYXJuZXNzOiBTbWFydFJvdXRlckhhcm5lc3M7XG4gIHJlYWRvbmx5IG1vZGVsOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHZhbHVlOiBUO1xufVxuXG4vKiogUmVzdWx0IHJldHVybmVkIGFmdGVyIG1hcHBpbmcgYSBEYXRhYnJpY2tzIHJvdXRlIGJhY2sgdG8gYSBjYWxsZXItb3duZWQgdmFsdWUuICovXG5leHBvcnQgaW50ZXJmYWNlIFNtYXJ0Um91dGVyU2VsZWN0aW9uPFQ+IHtcbiAgcmVhZG9ubHkgaGFybmVzczogU21hcnRSb3V0ZXJIYXJuZXNzO1xuICByZWFkb25seSBsYXRlbmN5TXM6IG51bWJlcjtcbiAgcmVhZG9ubHkgcGFyYW1zPzogUmVhZG9ubHk8UmVjb3JkPHN0cmluZywgdW5rbm93bj4+O1xuICByZWFkb25seSByYXRpb25hbGU/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJvdXRlTW9kZWw6IHN0cmluZztcbiAgcmVhZG9ubHkgcm91dGVyTmFtZTogc3RyaW5nO1xuICByZWFkb25seSB2YWx1ZTogVDtcbn1cblxuLyoqIFBvcnRhYmxlIHBlcnNpc3RlbmNlIHN1cmZhY2UgZm9yIGEgcGlubmVkIFNtYXJ0IFJvdXRlciB0dXJuLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTbWFydFJvdXRlclN0b3JlIHtcbiAgZ2V0KGtleTogc3RyaW5nKTogUHJvbWlzZTx1bmtub3duPjtcbiAgc2V0KGtleTogc3RyaW5nLCB2YWx1ZTogU21hcnRSb3V0ZXJPYnNlcnZhdGlvbiwgdHRsU2Vjb25kczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPjtcbn1cblxuZXhwb3J0IGNvbnN0IFNtYXJ0Um91dGVyUHJvYmVSZWNvcmRTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIGVuYWJsZWQ6IHouYm9vbGVhbigpLmRlc2NyaWJlKFwiV2hldGhlciB0aGUgbGl2ZSBTbWFydCBSb3V0ZXIgcHJvYmUgc3VjY2VlZGVkLlwiKSxcbiAgICBleHBpcmVzQXQ6IHoubnVtYmVyKCkuaW50KCkuZGVzY3JpYmUoXCJFcG9jaCBtaWxsaXNlY29uZHMgd2hlbiB0aGlzIHByb2JlIGJlY29tZXMgc3RhbGUuXCIpLFxuICB9KVxuICAuZGVzY3JpYmUoXCJQZXJzaXN0ZWQgU21hcnQgUm91dGVyIGNhcGFiaWxpdHkgcHJvYmUgcmVzdWx0LlwiKTtcblxuZXhwb3J0IHR5cGUgU21hcnRSb3V0ZXJQcm9iZVJlY29yZCA9IHouaW5mZXI8dHlwZW9mIFNtYXJ0Um91dGVyUHJvYmVSZWNvcmRTY2hlbWE+O1xuXG4vKiogT3B0aW9uYWwgcGVyc2lzdGVudCBjYWNoZSBmb3IgY2FwYWJpbGl0eSBwcm9iZXMuICovXG5leHBvcnQgaW50ZXJmYWNlIFNtYXJ0Um91dGVyUHJvYmVTdG9yZSB7XG4gIGdldChrZXk6IHN0cmluZywgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQpOiBQcm9taXNlPHVua25vd24+O1xuICBzZXQoXG4gICAga2V5OiBzdHJpbmcsXG4gICAgdmFsdWU6IFNtYXJ0Um91dGVyUHJvYmVSZWNvcmQsXG4gICAgdHRsU2Vjb25kczogbnVtYmVyLFxuICAgIGNsaWVudDogV29ya3NwYWNlQ2xpZW50LFxuICApOiBQcm9taXNlPHZvaWQ+O1xufVxuXG4vKiogUmVzdWx0IGFwcGxpZWQgdG8gb25lIGNvbmNyZXRlIGdhdGV3YXkgcmVxdWVzdC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU21hcnRSb3V0ZXJSZXN1bHQge1xuICByZWFkb25seSBib2R5OiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj47XG4gIHJlYWRvbmx5IG9ic2VydmF0aW9uOiBTbWFydFJvdXRlck9ic2VydmF0aW9uO1xuICByZWFkb25seSB0YXJnZXQ6IE1vZGVsVGFyZ2V0O1xufVxuXG4vKiogQm91bmRlZCB0YXNrIGNvbnRleHQgZXh0cmFjdGVkIGZyb20gYW4gYXJiaXRyYXJ5IHN1cHBvcnRlZCBpbnB1dCBzaGFwZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU21hcnRSb3V0ZXJDb250ZXh0IHtcbiAgcmVhZG9ubHkgY29udGludWF0aW9uOiBib29sZWFuO1xuICByZWFkb25seSBsb2dpY2FsVHVybjogc3RyaW5nO1xuICByZWFkb25seSB0YXNrOiBzdHJpbmc7XG59XG5cbi8qKiBFcnJvciBjYXJyeWluZyBhbiBIVFRQIHN0YXR1cyBmb3IgU21hcnQgUm91dGVyIHZhbGlkYXRpb24gb3IgYXZhaWxhYmlsaXR5IGZhaWx1cmVzLiAqL1xuZXhwb3J0IGNsYXNzIFNtYXJ0Um91dGVyRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHJlYWRvbmx5IHN0YXR1czogbnVtYmVyLFxuICAgIG1lc3NhZ2U6IHN0cmluZyxcbiAgKSB7XG4gICAgc3VwZXIobWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gXCJTbWFydFJvdXRlckVycm9yXCI7XG4gIH1cbn1cblxuLyoqIEFwcEtpdCBjYWNoZSBhZGFwdGVyOyBjb25maWd1cmVkIExha2ViYXNlL1Bvc3RncmVzIHN0b3JhZ2UgcmVtYWlucyBBcHBLaXQtb3duZWQuICovXG5leHBvcnQgY2xhc3MgQXBwS2l0U21hcnRSb3V0ZXJTdG9yZSBpbXBsZW1lbnRzIFNtYXJ0Um91dGVyU3RvcmUge1xuICBhc3luYyBnZXQoa2V5OiBzdHJpbmcpOiBQcm9taXNlPHVua25vd24+IHtcbiAgICBjb25zdCBjYWNoZSA9IGF3YWl0IENhY2hlTWFuYWdlci5nZXRJbnN0YW5jZSgpO1xuICAgIHJldHVybiBjYWNoZS5nZXQoY2FjaGUuZ2VuZXJhdGVLZXkoW1JPVVRFX0NBQ0hFX05BTUVTUEFDRSwgUk9VVEVfUE9MSUNZX1ZFUlNJT05dLCBrZXkpKTtcbiAgfVxuXG4gIGFzeW5jIHNldChrZXk6IHN0cmluZywgdmFsdWU6IFNtYXJ0Um91dGVyT2JzZXJ2YXRpb24sIHR0bFNlY29uZHM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNhY2hlID0gYXdhaXQgQ2FjaGVNYW5hZ2VyLmdldEluc3RhbmNlKCk7XG4gICAgYXdhaXQgY2FjaGUuc2V0KGNhY2hlLmdlbmVyYXRlS2V5KFtST1VURV9DQUNIRV9OQU1FU1BBQ0UsIFJPVVRFX1BPTElDWV9WRVJTSU9OXSwga2V5KSwgdmFsdWUsIHtcbiAgICAgIHR0bDogdHRsU2Vjb25kcyxcbiAgICB9KTtcbiAgfVxufVxuXG4vKiogQXBwS2l0IGNhY2hlIGFkYXB0ZXIgZm9yIHByb2Nlc3MtIGFuZCBwZXJzaXN0ZW5jZS1iYWNrZWQgY2FwYWJpbGl0eSBwcm9iZXMuICovXG5leHBvcnQgY2xhc3MgQXBwS2l0U21hcnRSb3V0ZXJQcm9iZVN0b3JlIGltcGxlbWVudHMgU21hcnRSb3V0ZXJQcm9iZVN0b3JlIHtcbiAgYXN5bmMgZ2V0KGtleTogc3RyaW5nLCBjbGllbnQ6IFdvcmtzcGFjZUNsaWVudCk6IFByb21pc2U8dW5rbm93bj4ge1xuICAgIGNvbnN0IGNhY2hlID0gYXBwS2l0Q2FjaGVNYW5hZ2VyKCk7XG4gICAgaWYgKCFjYWNoZSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBjb25zdCBpZGVudGl0eSA9IGF3YWl0IHNtYXJ0Um91dGVyUHJvYmVJZGVudGl0eShjbGllbnQpO1xuICAgIHJldHVybiBjYWNoZS5nZXQoXG4gICAgICBjYWNoZS5nZW5lcmF0ZUtleShbUFJPQkVfQ0FDSEVfTkFNRVNQQUNFLCBQUk9CRV9DQUNIRV9WRVJTSU9OXSwgYCR7aWRlbnRpdHl9OiR7a2V5fWApLFxuICAgICk7XG4gIH1cblxuICBhc3luYyBzZXQoXG4gICAga2V5OiBzdHJpbmcsXG4gICAgdmFsdWU6IFNtYXJ0Um91dGVyUHJvYmVSZWNvcmQsXG4gICAgdHRsU2Vjb25kczogbnVtYmVyLFxuICAgIGNsaWVudDogV29ya3NwYWNlQ2xpZW50LFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBjYWNoZSA9IGFwcEtpdENhY2hlTWFuYWdlcigpO1xuICAgIGlmICghY2FjaGUpIHJldHVybjtcbiAgICBjb25zdCBpZGVudGl0eSA9IGF3YWl0IHNtYXJ0Um91dGVyUHJvYmVJZGVudGl0eShjbGllbnQpO1xuICAgIGF3YWl0IGNhY2hlLnNldChcbiAgICAgIGNhY2hlLmdlbmVyYXRlS2V5KFtQUk9CRV9DQUNIRV9OQU1FU1BBQ0UsIFBST0JFX0NBQ0hFX1ZFUlNJT05dLCBgJHtpZGVudGl0eX06JHtrZXl9YCksXG4gICAgICB2YWx1ZSxcbiAgICAgIHsgdHRsOiB0dGxTZWNvbmRzIH0sXG4gICAgKTtcbiAgfVxufVxuXG5pbnRlcmZhY2UgUHJvYmVFbnRyeSB7XG4gIHJlYWRvbmx5IGNhY2hlOiBNYXA8c3RyaW5nLCBQcm9iZUVudHJ5PjtcbiAgcmVhZG9ubHkgY2FuZGlkYXRlczogcmVhZG9ubHkgU21hcnRSb3V0ZXJDYW5kaWRhdGU8dW5rbm93bj5bXTtcbiAgcmVhZG9ubHkgY2xpZW50OiBXZWFrUmVmPFdvcmtzcGFjZUNsaWVudD47XG4gIHJlYWRvbmx5IGtleTogc3RyaW5nO1xuICBleHBpcmVzQXQ6IG51bWJlcjtcbiAgcmVmcmVzaD86IFByb21pc2U8Ym9vbGVhbj47XG4gIHZhbHVlPzogYm9vbGVhbjtcbn1cblxuLyoqIE9wdGlvbmFsIGlkZW50aXR5IGFuZCBjYW5jZWxsYXRpb24gaW5wdXRzIGZvciBvbmUgU21hcnQgUm91dGVyIGNhbGwuICovXG5leHBvcnQgaW50ZXJmYWNlIFNtYXJ0Um91dGVyU2VsZWN0T3B0aW9ucyB7XG4gIHJlYWRvbmx5IGNsaWVudD86IFdvcmtzcGFjZUNsaWVudDtcbiAgcmVhZG9ubHkgc2lnbmFsPzogQWJvcnRTaWduYWw7XG59XG5cbnR5cGUgU21hcnRSb3V0ZXJJbnZva2VyID0gKFxuICBjbGllbnQ6IFdvcmtzcGFjZUNsaWVudCxcbiAgcmVxdWVzdDogU21hcnRSb3V0ZXJSZXF1ZXN0LFxuICBzaWduYWw6IEFib3J0U2lnbmFsLFxuICB0aW1lb3V0TXM6IG51bWJlcixcbikgPT4gUHJvbWlzZTx1bmtub3duPjtcblxuLyoqXG4gKiBEZWRpY2F0ZWQgU21hcnQgUm91dGVyIHNlcnZpY2UgZm9yIHN0cmluZ3MsIHJlcXVlc3Qgb2JqZWN0cywgbWVzc2FnZSBhcnJheXMsXG4gKiBhbmQgZ2VuZXJpYyBKU09OLWxpa2UgaW5wdXRzLlxuICovXG5leHBvcnQgY2xhc3MgU21hcnRSb3V0ZXJTZXJ2aWNlIHtcbiAgcmVhZG9ubHkgY29udGV4dDogU21hcnRSb3V0ZXJDb250ZXh0QnVpbGRlcjtcbiAgcHJpdmF0ZSByZWFkb25seSBwcm9iZXMgPSBuZXcgV2Vha01hcDxvYmplY3QsIE1hcDxzdHJpbmcsIFByb2JlRW50cnk+PigpO1xuICBwcml2YXRlIHJlYWRvbmx5IHByb2JlRW50cmllcyA9IG5ldyBTZXQ8UHJvYmVFbnRyeT4oKTtcbiAgcHJpdmF0ZSBwcm9iZVJlZnJlc2hUaW1lcj86IE5vZGVKUy5UaW1lb3V0O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgc2V0dGluZ3M6IFNtYXJ0Um91dGVyU2V0dGluZ3MsXG4gICAgcHJpdmF0ZSByZWFkb25seSBpbnZva2U6IFNtYXJ0Um91dGVySW52b2tlciA9IGludm9rZVNtYXJ0Um91dGVyLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgcHJvYmVTdG9yZTogU21hcnRSb3V0ZXJQcm9iZVN0b3JlID0gbmV3IEFwcEtpdFNtYXJ0Um91dGVyUHJvYmVTdG9yZSgpLFxuICApIHtcbiAgICB0aGlzLmNvbnRleHQgPSBuZXcgU21hcnRSb3V0ZXJDb250ZXh0QnVpbGRlcihzZXR0aW5ncy5jb250ZXh0VG9rZW5CdWRnZXQpO1xuICB9XG5cbiAgLyoqIFNlbGVjdCBvbmUgb2ZmZXJlZCByb3V0ZSBmb3IgYXJiaXRyYXJ5IGlucHV0IGNvbnRlbnQuICovXG4gIGFzeW5jIHNlbGVjdDxUPihcbiAgICBpbnB1dDogdW5rbm93bixcbiAgICBjYW5kaWRhdGVzOiByZWFkb25seSBTbWFydFJvdXRlckNhbmRpZGF0ZTxUPltdLFxuICAgIG9wdGlvbnM6IFNtYXJ0Um91dGVyU2VsZWN0T3B0aW9ucyA9IHt9LFxuICApOiBQcm9taXNlPFNtYXJ0Um91dGVyU2VsZWN0aW9uPFQ+PiB7XG4gICAgY29uc3QgdGFzayA9IHRoaXMuY29udGV4dC5idWlsZChpbnB1dCk7XG4gICAgaWYgKCF0YXNrKSB0aHJvdyBuZXcgU21hcnRSb3V0ZXJFcnJvcig0MDAsIFwiU21hcnQgUm91dGVyIGlucHV0IGNvbnRhaW5zIG5vIHJvdXRhYmxlIHRleHRcIik7XG4gICAgY29uc3QgY2xpZW50ID0gb3B0aW9ucy5jbGllbnQgPz8gZ2V0RXhlY3V0aW9uQ29udGV4dCgpLmNsaWVudDtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc2VsZWN0aW9uID0gYXdhaXQgdGhpcy5zZWxlY3RUYXNrKHRhc2ssIGNhbmRpZGF0ZXMsIHsgLi4ub3B0aW9ucywgY2xpZW50IH0pO1xuICAgICAgdGhpcy5zZXRQcm9iZVZhbHVlKGNhbmRpZGF0ZXMsIGNsaWVudCwgdHJ1ZSk7XG4gICAgICByZXR1cm4gc2VsZWN0aW9uO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLnNldFByb2JlVW5hdmFpbGFibGUoY2FuZGlkYXRlcywgY2xpZW50KTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBSZXR1cm4gYSBtZW1vaXplZCBsaXZlIGNhcGFiaWxpdHkgcHJvYmUgZm9yIHRoZSBhY3RpdmUgaWRlbnRpdHkgYW5kIGNhbmRpZGF0ZSBtZW51LiAqL1xuICBhc3luYyBpc0VuYWJsZWQ8VD4oXG4gICAgY2FuZGlkYXRlczogcmVhZG9ubHkgU21hcnRSb3V0ZXJDYW5kaWRhdGU8VD5bXSxcbiAgICBjbGllbnQgPSBnZXRFeGVjdXRpb25Db250ZXh0KCkuY2xpZW50LFxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBvZmZlcmVkID0gdW5pcXVlQ2FuZGlkYXRlcyhjYW5kaWRhdGVzKTtcbiAgICBpZiAob2ZmZXJlZC5sZW5ndGggPT09IDApIHJldHVybiBmYWxzZTtcbiAgICBjb25zdCBjYWNoZSA9IHRoaXMucHJvYmVDYWNoZShjbGllbnQpO1xuICAgIGNvbnN0IGtleSA9IHByb2JlS2V5KG9mZmVyZWQsIHRoaXMuc2V0dGluZ3Mucm91dGVyTmFtZSk7XG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICBjb25zdCBjYWNoZWQgPSBjYWNoZS5nZXQoa2V5KTtcbiAgICBpZiAoY2FjaGVkKSB7XG4gICAgICBpZiAoY2FjaGVkLnZhbHVlID09PSB1bmRlZmluZWQpIHJldHVybiBjYWNoZWQucmVmcmVzaCE7XG4gICAgICBpZiAoY2FjaGVkLmV4cGlyZXNBdCA8PSBub3cgJiYgIWNhY2hlZC5yZWZyZXNoKSB2b2lkIHRoaXMucmVmcmVzaFByb2JlKGNhY2hlZCk7XG4gICAgICByZXR1cm4gY2FjaGVkLnZhbHVlO1xuICAgIH1cbiAgICBjb25zdCBlbnRyeSA9IHRoaXMuY3JlYXRlUHJvYmVFbnRyeShjYWNoZSwga2V5LCBvZmZlcmVkLCBjbGllbnQpO1xuICAgIHJldHVybiB0aGlzLmluaXRpYWxpemVQcm9iZShlbnRyeSk7XG4gIH1cblxuICAvKiogU3RvcCB0aGlzIHNlcnZpY2UncyB1bnJlZidkIGJhY2tncm91bmQgcHJvYmUgcmVmcmVzaCB0aW1lci4gKi9cbiAgZGlzcG9zZSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5wcm9iZVJlZnJlc2hUaW1lcikgY2xlYXJJbnRlcnZhbCh0aGlzLnByb2JlUmVmcmVzaFRpbWVyKTtcbiAgICB0aGlzLnByb2JlUmVmcmVzaFRpbWVyID0gdW5kZWZpbmVkO1xuICAgIHRoaXMucHJvYmVFbnRyaWVzLmNsZWFyKCk7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZVByb2JlRW50cnk8VD4oXG4gICAgY2FjaGU6IE1hcDxzdHJpbmcsIFByb2JlRW50cnk+LFxuICAgIGtleTogc3RyaW5nLFxuICAgIGNhbmRpZGF0ZXM6IHJlYWRvbmx5IFNtYXJ0Um91dGVyQ2FuZGlkYXRlPFQ+W10sXG4gICAgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQsXG4gICk6IFByb2JlRW50cnkge1xuICAgIGNvbnN0IGVudHJ5OiBQcm9iZUVudHJ5ID0ge1xuICAgICAgY2FjaGUsXG4gICAgICBjYW5kaWRhdGVzLFxuICAgICAgY2xpZW50OiBuZXcgV2Vha1JlZihjbGllbnQpLFxuICAgICAga2V5LFxuICAgICAgZXhwaXJlc0F0OiAwLFxuICAgIH07XG4gICAgdGhpcy5yZXBsYWNlUHJvYmUoY2FjaGUsIGtleSwgZW50cnkpO1xuICAgIHJldHVybiBlbnRyeTtcbiAgfVxuXG4gIHByaXZhdGUgaW5pdGlhbGl6ZVByb2JlKGVudHJ5OiBQcm9iZUVudHJ5KTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgY2xpZW50ID0gZW50cnkuY2xpZW50LmRlcmVmKCk7XG4gICAgaWYgKCFjbGllbnQpIHJldHVybiBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xuICAgIGxldCByZWZyZXNoITogUHJvbWlzZTxib29sZWFuPjtcbiAgICByZWZyZXNoID0gdGhpcy5yZWFkU3RvcmVkUHJvYmUoZW50cnksIGNsaWVudClcbiAgICAgIC50aGVuKChzdG9yZWQpID0+IHtcbiAgICAgICAgaWYgKHN0b3JlZCAmJiBzdG9yZWQuZXhwaXJlc0F0ID4gRGF0ZS5ub3coKSkge1xuICAgICAgICAgIGVudHJ5LnZhbHVlID0gc3RvcmVkLmVuYWJsZWQ7XG4gICAgICAgICAgZW50cnkuZXhwaXJlc0F0ID0gc3RvcmVkLmV4cGlyZXNBdDtcbiAgICAgICAgICByZXR1cm4gc3RvcmVkLmVuYWJsZWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuZXhlY3V0ZVByb2JlKGVudHJ5LCBjbGllbnQpO1xuICAgICAgfSlcbiAgICAgIC5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgaWYgKGVudHJ5LnJlZnJlc2ggPT09IHJlZnJlc2gpIGVudHJ5LnJlZnJlc2ggPSB1bmRlZmluZWQ7XG4gICAgICB9KTtcbiAgICBlbnRyeS5yZWZyZXNoID0gcmVmcmVzaDtcbiAgICByZXR1cm4gcmVmcmVzaDtcbiAgfVxuXG4gIHByaXZhdGUgcmVmcmVzaFByb2JlKGVudHJ5OiBQcm9iZUVudHJ5KTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgaWYgKGVudHJ5LnJlZnJlc2gpIHJldHVybiBlbnRyeS5yZWZyZXNoO1xuICAgIGNvbnN0IGNsaWVudCA9IGVudHJ5LmNsaWVudC5kZXJlZigpO1xuICAgIGlmICghY2xpZW50KSByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGZhbHNlKTtcbiAgICBsZXQgcmVmcmVzaCE6IFByb21pc2U8Ym9vbGVhbj47XG4gICAgcmVmcmVzaCA9IHRoaXMuZXhlY3V0ZVByb2JlKGVudHJ5LCBjbGllbnQpLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgaWYgKGVudHJ5LnJlZnJlc2ggPT09IHJlZnJlc2gpIGVudHJ5LnJlZnJlc2ggPSB1bmRlZmluZWQ7XG4gICAgfSk7XG4gICAgZW50cnkucmVmcmVzaCA9IHJlZnJlc2g7XG4gICAgcmV0dXJuIHJlZnJlc2g7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGV4ZWN1dGVQcm9iZShlbnRyeTogUHJvYmVFbnRyeSwgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBlbmFibGVkID0gYXdhaXQgdGhpcy5zZWxlY3RUYXNrKFBST0JFX1RBU0ssIGVudHJ5LmNhbmRpZGF0ZXMsIHsgY2xpZW50IH0pXG4gICAgICAudGhlbigoKSA9PiB0cnVlKVxuICAgICAgLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICBsb2dnZXIuZGVidWcoXCJTbWFydCBSb3V0ZXIgY2FwYWJpbGl0eSBwcm9iZSB1bmF2YWlsYWJsZVwiLCB7IGVycm9yOiB0b0Vycm9yKGVycm9yKSB9KTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfSk7XG4gICAgaWYgKGVudHJ5LmNhY2hlLmdldChlbnRyeS5rZXkpID09PSBlbnRyeSkge1xuICAgICAgdGhpcy51cGRhdGVQcm9iZUVudHJ5KGVudHJ5LCBlbmFibGVkKTtcbiAgICAgIHZvaWQgdGhpcy53cml0ZVN0b3JlZFByb2JlKGVudHJ5LCBlbmFibGVkLCBjbGllbnQpO1xuICAgIH1cbiAgICByZXR1cm4gZW5hYmxlZDtcbiAgfVxuXG4gIHByaXZhdGUgc2V0UHJvYmVWYWx1ZTxUPihcbiAgICBjYW5kaWRhdGVzOiByZWFkb25seSBTbWFydFJvdXRlckNhbmRpZGF0ZTxUPltdLFxuICAgIGNsaWVudDogV29ya3NwYWNlQ2xpZW50LFxuICAgIGVuYWJsZWQ6IGJvb2xlYW4sXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IG9mZmVyZWQgPSB1bmlxdWVDYW5kaWRhdGVzKGNhbmRpZGF0ZXMpO1xuICAgIGlmIChvZmZlcmVkLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIGNvbnN0IGNhY2hlID0gdGhpcy5wcm9iZUNhY2hlKGNsaWVudCk7XG4gICAgY29uc3Qga2V5ID0gcHJvYmVLZXkob2ZmZXJlZCwgdGhpcy5zZXR0aW5ncy5yb3V0ZXJOYW1lKTtcbiAgICBjb25zdCBlbnRyeSA9IGNhY2hlLmdldChrZXkpID8/IHRoaXMuY3JlYXRlUHJvYmVFbnRyeShjYWNoZSwga2V5LCBvZmZlcmVkLCBjbGllbnQpO1xuICAgIHRoaXMudXBkYXRlUHJvYmVFbnRyeShlbnRyeSwgZW5hYmxlZCk7XG4gICAgdm9pZCB0aGlzLndyaXRlU3RvcmVkUHJvYmUoZW50cnksIGVuYWJsZWQsIGNsaWVudCk7XG4gIH1cblxuICBwcml2YXRlIHNldFByb2JlVW5hdmFpbGFibGU8VD4oXG4gICAgY2FuZGlkYXRlczogcmVhZG9ubHkgU21hcnRSb3V0ZXJDYW5kaWRhdGU8VD5bXSxcbiAgICBjbGllbnQ6IFdvcmtzcGFjZUNsaWVudCxcbiAgKTogdm9pZCB7XG4gICAgY29uc3QgY2FjaGUgPSB0aGlzLnByb2JlQ2FjaGUoY2xpZW50KTtcbiAgICBmb3IgKGNvbnN0IGNhY2hlZCBvZiBjYWNoZS52YWx1ZXMoKSkge1xuICAgICAgdGhpcy51cGRhdGVQcm9iZUVudHJ5KGNhY2hlZCwgZmFsc2UpO1xuICAgICAgdm9pZCB0aGlzLndyaXRlU3RvcmVkUHJvYmUoY2FjaGVkLCBmYWxzZSwgY2xpZW50KTtcbiAgICB9XG4gICAgdGhpcy5zZXRQcm9iZVZhbHVlKGNhbmRpZGF0ZXMsIGNsaWVudCwgZmFsc2UpO1xuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGVQcm9iZUVudHJ5KGVudHJ5OiBQcm9iZUVudHJ5LCBlbmFibGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgZW50cnkudmFsdWUgPSBlbmFibGVkO1xuICAgIGVudHJ5LmV4cGlyZXNBdCA9IERhdGUubm93KCkgKyB0aGlzLnByb2JlVHRsKGVuYWJsZWQpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyByZWFkU3RvcmVkUHJvYmUoXG4gICAgZW50cnk6IFByb2JlRW50cnksXG4gICAgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQsXG4gICk6IFByb21pc2U8U21hcnRSb3V0ZXJQcm9iZVJlY29yZCB8IHVuZGVmaW5lZD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXJzZWQgPSBTbWFydFJvdXRlclByb2JlUmVjb3JkU2NoZW1hLnNhZmVQYXJzZShcbiAgICAgICAgYXdhaXQgdGhpcy5wcm9iZVN0b3JlLmdldChlbnRyeS5rZXksIGNsaWVudCksXG4gICAgICApO1xuICAgICAgcmV0dXJuIHBhcnNlZC5zdWNjZXNzID8gcGFyc2VkLmRhdGEgOiB1bmRlZmluZWQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhcIlNtYXJ0IFJvdXRlciBwcm9iZSBjYWNoZSByZWFkIGZhaWxlZFwiLCB7IGVycm9yOiB0b0Vycm9yKGVycm9yKSB9KTtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB3cml0ZVN0b3JlZFByb2JlKFxuICAgIGVudHJ5OiBQcm9iZUVudHJ5LFxuICAgIGVuYWJsZWQ6IGJvb2xlYW4sXG4gICAgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnByb2JlU3RvcmUuc2V0KFxuICAgICAgICBlbnRyeS5rZXksXG4gICAgICAgIHsgZW5hYmxlZCwgZXhwaXJlc0F0OiBlbnRyeS5leHBpcmVzQXQgfSxcbiAgICAgICAgTWF0aC5tYXgoXG4gICAgICAgICAgMSxcbiAgICAgICAgICBNYXRoLmNlaWwoXG4gICAgICAgICAgICAoTWF0aC5tYXgodGhpcy5zZXR0aW5ncy5wcm9iZVJlZnJlc2hJbnRlcnZhbE1zLCB0aGlzLnNldHRpbmdzLnByb2JlVHRsTXMpICogMikgLyAxXzAwMCxcbiAgICAgICAgICApLFxuICAgICAgICApLFxuICAgICAgICBjbGllbnQsXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZGVidWcoXCJTbWFydCBSb3V0ZXIgcHJvYmUgY2FjaGUgd3JpdGUgZmFpbGVkXCIsIHsgZXJyb3I6IHRvRXJyb3IoZXJyb3IpIH0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcHJvYmVDYWNoZShjbGllbnQ6IFdvcmtzcGFjZUNsaWVudCk6IE1hcDxzdHJpbmcsIFByb2JlRW50cnk+IHtcbiAgICBjb25zdCBvd25lciA9IGNsaWVudC5jb25maWcgYXMgb2JqZWN0O1xuICAgIGxldCBjYWNoZSA9IHRoaXMucHJvYmVzLmdldChvd25lcik7XG4gICAgaWYgKCFjYWNoZSkge1xuICAgICAgY2FjaGUgPSBuZXcgTWFwKCk7XG4gICAgICB0aGlzLnByb2Jlcy5zZXQob3duZXIsIGNhY2hlKTtcbiAgICB9XG4gICAgcmV0dXJuIGNhY2hlO1xuICB9XG5cbiAgcHJpdmF0ZSByZXBsYWNlUHJvYmUoY2FjaGU6IE1hcDxzdHJpbmcsIFByb2JlRW50cnk+LCBrZXk6IHN0cmluZywgZW50cnk6IFByb2JlRW50cnkpOiB2b2lkIHtcbiAgICBjb25zdCBwcmV2aW91cyA9IGNhY2hlLmdldChrZXkpO1xuICAgIGlmIChwcmV2aW91cykgdGhpcy5wcm9iZUVudHJpZXMuZGVsZXRlKHByZXZpb3VzKTtcbiAgICBjYWNoZS5zZXQoa2V5LCBlbnRyeSk7XG4gICAgdGhpcy5wcm9iZUVudHJpZXMuYWRkKGVudHJ5KTtcbiAgICB0aGlzLmVuc3VyZVByb2JlUmVmcmVzaFRpbWVyKCk7XG4gIH1cblxuICBwcml2YXRlIHByb2JlVHRsKGVuYWJsZWQ6IGJvb2xlYW4pOiBudW1iZXIge1xuICAgIHJldHVybiBlbmFibGVkXG4gICAgICA/IHRoaXMuc2V0dGluZ3MucHJvYmVUdGxNc1xuICAgICAgOiBNYXRoLm1pbih0aGlzLnNldHRpbmdzLnByb2JlVHRsTXMsIE5FR0FUSVZFX1BST0JFX1RUTF9NUyk7XG4gIH1cblxuICBwcml2YXRlIGVuc3VyZVByb2JlUmVmcmVzaFRpbWVyKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnByb2JlUmVmcmVzaFRpbWVyKSByZXR1cm47XG4gICAgdGhpcy5wcm9iZVJlZnJlc2hUaW1lciA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgIHZvaWQgdGhpcy5yZWZyZXNoUHJvYmVzKCk7XG4gICAgfSwgdGhpcy5zZXR0aW5ncy5wcm9iZVJlZnJlc2hJbnRlcnZhbE1zKTtcbiAgICB0aGlzLnByb2JlUmVmcmVzaFRpbWVyLnVucmVmKCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJlZnJlc2hQcm9iZXMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcmVmcmVzaGVzOiBQcm9taXNlPGJvb2xlYW4+W10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIFsuLi50aGlzLnByb2JlRW50cmllc10pIHtcbiAgICAgIGlmIChlbnRyeS5jYWNoZS5nZXQoZW50cnkua2V5KSAhPT0gZW50cnkpIHtcbiAgICAgICAgdGhpcy5wcm9iZUVudHJpZXMuZGVsZXRlKGVudHJ5KTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCBjbGllbnQgPSBlbnRyeS5jbGllbnQuZGVyZWYoKTtcbiAgICAgIGlmICghY2xpZW50KSB7XG4gICAgICAgIGVudHJ5LmNhY2hlLmRlbGV0ZShlbnRyeS5rZXkpO1xuICAgICAgICB0aGlzLnByb2JlRW50cmllcy5kZWxldGUoZW50cnkpO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGlmICghZW50cnkucmVmcmVzaCkgcmVmcmVzaGVzLnB1c2godGhpcy5yZWZyZXNoUHJvYmUoZW50cnkpKTtcbiAgICB9XG4gICAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKHJlZnJlc2hlcyk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHNlbGVjdFRhc2s8VD4oXG4gICAgdGFzazogc3RyaW5nLFxuICAgIGNhbmRpZGF0ZXM6IHJlYWRvbmx5IFNtYXJ0Um91dGVyQ2FuZGlkYXRlPFQ+W10sXG4gICAgb3B0aW9uczogU21hcnRSb3V0ZXJTZWxlY3RPcHRpb25zLFxuICApOiBQcm9taXNlPFNtYXJ0Um91dGVyU2VsZWN0aW9uPFQ+PiB7XG4gICAgY29uc3Qgb2ZmZXJlZCA9IHVuaXF1ZUNhbmRpZGF0ZXMoY2FuZGlkYXRlcyk7XG4gICAgaWYgKG9mZmVyZWQubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgU21hcnRSb3V0ZXJFcnJvcig0MDAsIFwiTm8gY29tcGF0aWJsZSBzeXN0ZW0gbW9kZWxzIGFyZSBhdmFpbGFibGUgdG8gU21hcnQgUm91dGVyXCIpO1xuICAgIH1cbiAgICBjb25zdCByZXF1ZXN0ID0gU21hcnRSb3V0ZXJSZXF1ZXN0U2NoZW1hLnBhcnNlKHtcbiAgICAgIHJvdXRlX29wdGlvbnM6IG9mZmVyZWQubWFwKCh7IG1vZGVsLCBoYXJuZXNzIH0pID0+ICh7IG1vZGVsLCBoYXJuZXNzIH0pKSxcbiAgICAgIHRhc2s6IHsgcHJvbXB0OiB0YXNrIH0sXG4gICAgICByb3V0ZV9zZWxlY3RvcjogeyByb3V0ZXJfbmFtZTogdGhpcy5zZXR0aW5ncy5yb3V0ZXJOYW1lIH0sXG4gICAgfSk7XG4gICAgY29uc3QgY2xpZW50ID0gb3B0aW9ucy5jbGllbnQgPz8gZ2V0RXhlY3V0aW9uQ29udGV4dCgpLmNsaWVudDtcbiAgICBjb25zdCBzaWduYWwgPSBvcHRpb25zLnNpZ25hbCA/PyBuZXcgQWJvcnRDb250cm9sbGVyKCkuc2lnbmFsO1xuICAgIGNvbnN0IHN0YXJ0ZWRBdCA9IERhdGUubm93KCk7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBTbWFydFJvdXRlclJlc3BvbnNlU2NoZW1hLnBhcnNlKFxuICAgICAgYXdhaXQgdGhpcy5pbnZva2UoY2xpZW50LCByZXF1ZXN0LCBzaWduYWwsIHRoaXMuc2V0dGluZ3MudGltZW91dE1zKSxcbiAgICApO1xuICAgIGNvbnN0IHNlbGVjdGlvbiA9IHJlc3BvbnNlLnJvdXRlX3NlbGVjdGlvblswXSE7XG4gICAgY29uc3Qgc2VsZWN0ZWQgPSBvZmZlcmVkLmZpbmQoXG4gICAgICAoY2FuZGlkYXRlKSA9PlxuICAgICAgICBub3JtYWxpemVSb3V0ZU1vZGVsKGNhbmRpZGF0ZS5tb2RlbCkgPT09XG4gICAgICAgICAgbm9ybWFsaXplUm91dGVNb2RlbChzZWxlY3Rpb24ucm91dGVfb3B0aW9uLm1vZGVsKSAmJlxuICAgICAgICAoIXNlbGVjdGlvbi5yb3V0ZV9vcHRpb24uaGFybmVzcyB8fCBjYW5kaWRhdGUuaGFybmVzcyA9PT0gc2VsZWN0aW9uLnJvdXRlX29wdGlvbi5oYXJuZXNzKSxcbiAgICApO1xuICAgIGlmICghc2VsZWN0ZWQpIHtcbiAgICAgIHRocm93IG5ldyBTbWFydFJvdXRlckVycm9yKFxuICAgICAgICA1MDIsXG4gICAgICAgIGBTbWFydCBSb3V0ZXIgc2VsZWN0ZWQgYW4gdW5zdXBwb3J0ZWQgbW9kZWw6ICR7c2VsZWN0aW9uLnJvdXRlX29wdGlvbi5tb2RlbH1gLFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIHZhbHVlOiBzZWxlY3RlZC52YWx1ZSxcbiAgICAgIHJvdXRlTW9kZWw6IHNlbGVjdGlvbi5yb3V0ZV9vcHRpb24ubW9kZWwsXG4gICAgICBoYXJuZXNzOiBzZWxlY3RlZC5oYXJuZXNzLFxuICAgICAgcm91dGVyTmFtZTogdGhpcy5zZXR0aW5ncy5yb3V0ZXJOYW1lLFxuICAgICAgbGF0ZW5jeU1zOiBEYXRlLm5vdygpIC0gc3RhcnRlZEF0LFxuICAgICAgLi4uKHJlc3BvbnNlLnJhdGlvbmFsZSA/IHsgcmF0aW9uYWxlOiByZXNwb25zZS5yYXRpb25hbGUgfSA6IHt9KSxcbiAgICAgIC4uLihzZWxlY3Rpb24ucGFyYW1zID8geyBwYXJhbXM6IHNlbGVjdGlvbi5wYXJhbXMgfSA6IHt9KSxcbiAgICB9O1xuICB9XG59XG5cbi8qKiBCdWlsZCBhIFNtYXJ0IFJvdXRlciBjYW5kaWRhdGUgbWVudSBmcm9tIHZhbHVlcyBjYXJyeWluZyBtb2RlbFNlcnZpY2VOYW1lLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNtYXJ0Um91dGVyQ2FuZGlkYXRlczxUIGV4dGVuZHMgeyByZWFkb25seSBtb2RlbFNlcnZpY2VOYW1lPzogc3RyaW5nIH0+KFxuICB2YWx1ZXM6IHJlYWRvbmx5IFRbXSxcbiAgaGFybmVzczogU21hcnRSb3V0ZXJIYXJuZXNzLFxuKTogU21hcnRSb3V0ZXJDYW5kaWRhdGU8VD5bXSB7XG4gIHJldHVybiB2YWx1ZXMuZmxhdE1hcCgodmFsdWUpID0+IHtcbiAgICBjb25zdCBtb2RlbCA9IHZhbHVlLm1vZGVsU2VydmljZU5hbWU/LnRyaW0oKTtcbiAgICBpZiAoIW1vZGVsIHx8ICFtb2RlbC50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoXCJzeXN0ZW0uYWkuXCIpKSByZXR1cm4gW107XG4gICAgcmV0dXJuIFt7IG1vZGVsLCBoYXJuZXNzLCB2YWx1ZSB9XTtcbiAgfSk7XG59XG5cbi8qKlxuICogQ29udGV4dCBleHRyYWN0b3Igc2hhcmVkIGJ5IHRoZSBnYXRld2F5LCBNYXN0cmEsIGFuZCB0aGUgZmlsZS9zdGRpbiBDTEkuXG4gKiBJdCBmYXZvcnMgY29udmVyc2F0aW9uL3Rhc2sgZmllbGRzIGFuZCBpZ25vcmVzIGNyZWRlbnRpYWxzLCB0b29sIHNjaGVtYXMsXG4gKiBhbmQgdG9vbCBhcmd1bWVudHMuXG4gKi9cbmV4cG9ydCBjbGFzcyBTbWFydFJvdXRlckNvbnRleHRCdWlsZGVyIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSB0b2tlbkJ1ZGdldCA9IDRfMDk2KSB7fVxuXG4gIC8qKiBSZXR1cm4gb25seSB0aGUgYm91bmRlZCB0YXNrIHByb21wdCByZXF1aXJlZCBieSByb3V0ZXM6c2VsZWN0LiAqL1xuICBidWlsZChpbnB1dDogdW5rbm93bik6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuYW5hbHl6ZShpbnB1dCkudGFzaztcbiAgfVxuXG4gIC8qKiBSZXR1cm4gYm91bmRlZCB0YXNrIHRleHQgcGx1cyBsb2dpY2FsLXR1cm4gbWV0YWRhdGEgdXNlZCBmb3IgcGlubmluZy4gKi9cbiAgYW5hbHl6ZShpbnB1dDogdW5rbm93bik6IFNtYXJ0Um91dGVyQ29udGV4dCB7XG4gICAgY29uc3Qgbm9ybWFsaXplZCA9IHBhcnNlSnNvblN0cmluZyhpbnB1dCk7XG4gICAgY29uc3QgZXZlbnRzID0gY29udmVyc2F0aW9uRXZlbnRzKG5vcm1hbGl6ZWQpO1xuICAgIGlmIChldmVudHMubGVuZ3RoID4gMCkgcmV0dXJuIGNvbnRleHRGcm9tRXZlbnRzKGV2ZW50cywgdGhpcy50b2tlbkJ1ZGdldCk7XG4gICAgY29uc3QgdmFsdWVzID0gY29sbGVjdFRhc2tTdHJpbmdzKG5vcm1hbGl6ZWQpO1xuICAgIGNvbnN0IHRhc2sgPSB0cnVuY2F0ZVRleHQodmFsdWVzLmpvaW4oXCJcXG5cIiksIHRoaXMudG9rZW5CdWRnZXQsIFwic3RhcnRcIik7XG4gICAgcmV0dXJuIHsgdGFzaywgbG9naWNhbFR1cm46IHRhc2ssIGNvbnRpbnVhdGlvbjogZmFsc2UgfTtcbiAgfVxufVxuXG4vKiogU21hcnQgUm91dGVyIG9yY2hlc3RyYXRpb24gc2hhcmVkIGJ5IFJlc3BvbnNlcywgQ2hhdCBDb21wbGV0aW9ucywgYW5kIE1lc3NhZ2VzLiAqL1xuZXhwb3J0IGNsYXNzIFNtYXJ0TW9kZWxSb3V0ZXIge1xuICByZWFkb25seSBzZXJ2aWNlOiBTbWFydFJvdXRlclNlcnZpY2U7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBzZXR0aW5nczogU21hcnRSb3V0ZXJTZXR0aW5ncyxcbiAgICBzZXJ2aWNlID0gbmV3IFNtYXJ0Um91dGVyU2VydmljZShzZXR0aW5ncyksXG4gICAgcHJpdmF0ZSByZWFkb25seSBzdG9yZTogU21hcnRSb3V0ZXJTdG9yZSA9IG5ldyBBcHBLaXRTbWFydFJvdXRlclN0b3JlKCksXG4gICAgcHJpdmF0ZSByZWFkb25seSBjbGllbnQ/OiBXb3Jrc3BhY2VDbGllbnQsXG4gICkge1xuICAgIHRoaXMuc2VydmljZSA9IHNlcnZpY2U7XG4gIH1cblxuICAvKiogUHJvYmUgd2hldGhlciBTbWFydCBSb3V0ZXIgaXMgdXNhYmxlIGZvciB0aGUgY3VycmVudCBtb2RlbCBjYXRhbG9ndWUuICovXG4gIGlzRW5hYmxlZCh0YXJnZXRzOiByZWFkb25seSBNb2RlbFRhcmdldFtdKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgY2FuZGlkYXRlcyA9IHNtYXJ0Um91dGVyQ2FuZGlkYXRlcyhcbiAgICAgIHRhcmdldHMuZmlsdGVyKCh0YXJnZXQpID0+IHRhcmdldC5jYXBhYmlsaXRpZXMuY2hhdCAmJiB0YXJnZXQuY2FwYWJpbGl0aWVzLmFpR2F0ZXdheUNvZGV4KSxcbiAgICAgIFwiY29kZXhcIixcbiAgICApO1xuICAgIHJldHVybiB0aGlzLmNsaWVudFxuICAgICAgPyB0aGlzLnNlcnZpY2UuaXNFbmFibGVkKGNhbmRpZGF0ZXMsIHRoaXMuY2xpZW50KVxuICAgICAgOiB0aGlzLnNlcnZpY2UuaXNFbmFibGVkKGNhbmRpZGF0ZXMpO1xuICB9XG5cbiAgLyoqIFJlc29sdmUgb25lIHZpcnR1YWwgc21hcnQtcm91dGVyIHJlcXVlc3QgdG8gYSBjb25jcmV0ZSBjb21wYXRpYmxlIHRhcmdldC4gKi9cbiAgYXN5bmMgcmVzb2x2ZShpbnB1dDoge1xuICAgIHJlYWRvbmx5IGJvZHk6IFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIHVua25vd24+PjtcbiAgICByZWFkb25seSBmZWF0dXJlczogUmVxdWVzdGVkRmVhdHVyZXM7XG4gICAgcmVhZG9ubHkgaGVhZGVyczogSGVhZGVycztcbiAgICByZWFkb25seSBwcmVmZXJTeXN0ZW1Nb2RlbHM6IGJvb2xlYW47XG4gICAgcmVhZG9ubHkgcHJvdG9jb2w6IEV4Y2x1ZGU8Q2xpZW50UHJvdG9jb2wsIFwib3BlbmFpLWVtYmVkZGluZ3NcIj47XG4gICAgcmVhZG9ubHkgc2lnbmFsOiBBYm9ydFNpZ25hbDtcbiAgICByZWFkb25seSB0YXJnZXRzOiByZWFkb25seSBNb2RlbFRhcmdldFtdO1xuICB9KTogUHJvbWlzZTxTbWFydFJvdXRlclJlc3VsdD4ge1xuICAgIGNvbnN0IGhhcm5lc3M6IFNtYXJ0Um91dGVySGFybmVzcyA9XG4gICAgICBpbnB1dC5wcm90b2NvbCA9PT0gXCJhbnRocm9waWMtbWVzc2FnZXNcIiA/IFwiY2xhdWRlXCIgOiBcImNvZGV4XCI7XG4gICAgY29uc3QgZXhwbGljaXRSZWFzb25pbmdFZmZvcnQgPSByZXF1ZXN0ZWRSZWFzb25pbmdFZmZvcnQoaW5wdXQuYm9keSk7XG4gICAgY29uc3QgZWxpZ2libGVUYXJnZXRzID0gaW5wdXQudGFyZ2V0cy5maWx0ZXIoKHRhcmdldCkgPT5cbiAgICAgIGlzRWxpZ2libGVUYXJnZXQoXG4gICAgICAgIHRhcmdldCxcbiAgICAgICAgeyAuLi5pbnB1dCwgb3JpZ2luYXRvcjogaW5wdXQuaGVhZGVycy5nZXQoXCJvcmlnaW5hdG9yXCIpID8/IHVuZGVmaW5lZCB9LFxuICAgICAgICBleHBsaWNpdFJlYXNvbmluZ0VmZm9ydCxcbiAgICAgICAgaGFybmVzcyxcbiAgICAgICksXG4gICAgKTtcbiAgICBjb25zdCBjYW5kaWRhdGVzID0gc21hcnRSb3V0ZXJDYW5kaWRhdGVzKGVsaWdpYmxlVGFyZ2V0cywgaGFybmVzcyk7XG4gICAgaWYgKGNhbmRpZGF0ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgU21hcnRSb3V0ZXJFcnJvcihcbiAgICAgICAgNDAwLFxuICAgICAgICBcIk5vIGNvbXBhdGlibGUgc3lzdGVtIG1vZGVscyBhcmUgYXZhaWxhYmxlIHRvIERhdGFicmlja3MgU21hcnQgUm91dGVyXCIsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbnRleHQgPSB0aGlzLnNlcnZpY2UuY29udGV4dC5hbmFseXplKGlucHV0LmJvZHkpO1xuICAgIGlmICghY29udGV4dC50YXNrKSB7XG4gICAgICB0aHJvdyBuZXcgU21hcnRSb3V0ZXJFcnJvcig0MDAsIFwiU21hcnQgUm91dGVyIHJlcXVlc3QgY29udGFpbnMgbm8gdGFzayB0ZXh0XCIpO1xuICAgIH1cbiAgICBjb25zdCBrZXkgPSBzbWFydFJvdXRlclR1cm5LZXkoY29udGV4dC5sb2dpY2FsVHVybiwgY2FuZGlkYXRlcywge1xuICAgICAgaGFybmVzcyxcbiAgICAgIHByb3RvY29sOiBpbnB1dC5wcm90b2NvbCxcbiAgICAgIGZlYXR1cmVzOiBpbnB1dC5mZWF0dXJlcyxcbiAgICAgIC4uLihleHBsaWNpdFJlYXNvbmluZ0VmZm9ydCA/IHsgZXhwbGljaXRSZWFzb25pbmdFZmZvcnQgfSA6IHt9KSxcbiAgICB9KTtcbiAgICBjb25zdCBjYWNoZWQgPSBjb250ZXh0LmNvbnRpbnVhdGlvbiA/IGF3YWl0IHRoaXMucmVhZENhY2hlZChrZXksIGVsaWdpYmxlVGFyZ2V0cykgOiB1bmRlZmluZWQ7XG4gICAgaWYgKGNhY2hlZCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdGFyZ2V0OiBlbGlnaWJsZVRhcmdldHMuZmluZCgodGFyZ2V0KSA9PiB0YXJnZXQuaWQgPT09IGNhY2hlZC5zZWxlY3RlZE1vZGVsKSEsXG4gICAgICAgIGJvZHk6IGlucHV0LmJvZHksXG4gICAgICAgIG9ic2VydmF0aW9uOiB7IC4uLmNhY2hlZCwgc291cmNlOiBcImNhY2hlXCIgfSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29uc3Qgc2VsZWN0ZWQgPSBhd2FpdCB0aGlzLnNlcnZpY2Uuc2VsZWN0KGNvbnRleHQudGFzaywgY2FuZGlkYXRlcywge1xuICAgICAgc2lnbmFsOiBpbnB1dC5zaWduYWwsXG4gICAgICAuLi4odGhpcy5jbGllbnQgPyB7IGNsaWVudDogdGhpcy5jbGllbnQgfSA6IHt9KSxcbiAgICB9KTtcbiAgICBjb25zdCB0YXJnZXQgPSBzZWxlY3RlZC52YWx1ZTtcbiAgICBjb25zdCBvYnNlcnZhdGlvbiA9IFNtYXJ0Um91dGVyT2JzZXJ2YXRpb25TY2hlbWEucGFyc2Uoe1xuICAgICAgc2VsZWN0ZWRNb2RlbDogdGFyZ2V0LmlkLFxuICAgICAgcm91dGVNb2RlbDogc2VsZWN0ZWQucm91dGVNb2RlbCxcbiAgICAgIGhhcm5lc3M6IHNlbGVjdGVkLmhhcm5lc3MsXG4gICAgICByb3V0ZXJOYW1lOiBzZWxlY3RlZC5yb3V0ZXJOYW1lLFxuICAgICAgc291cmNlOiBcInJvdXRlclwiLFxuICAgICAgbGF0ZW5jeU1zOiBzZWxlY3RlZC5sYXRlbmN5TXMsXG4gICAgICAuLi4oc2VsZWN0ZWQucmF0aW9uYWxlID8geyByYXRpb25hbGU6IHNlbGVjdGVkLnJhdGlvbmFsZSB9IDoge30pLFxuICAgICAgLi4uKHNlbGVjdGVkLnBhcmFtcyA/IHsgcGFyYW1zOiBzZWxlY3RlZC5wYXJhbXMgfSA6IHt9KSxcbiAgICB9KTtcbiAgICBhd2FpdCB0aGlzLndyaXRlQ2FjaGVkKGtleSwgb2JzZXJ2YXRpb24pO1xuICAgIGxvZ2dlci5kZWJ1ZyhcInNlbGVjdGVkIFNtYXJ0IFJvdXRlciBtb2RlbFwiLCB7XG4gICAgICBjYW5kaWRhdGVDb3VudDogY2FuZGlkYXRlcy5sZW5ndGgsXG4gICAgICBoYXJuZXNzLFxuICAgICAgbGF0ZW5jeU1zOiBvYnNlcnZhdGlvbi5sYXRlbmN5TXMsXG4gICAgICBtb2RlbDogb2JzZXJ2YXRpb24uc2VsZWN0ZWRNb2RlbCxcbiAgICAgIHJvdXRlTW9kZWw6IG9ic2VydmF0aW9uLnJvdXRlTW9kZWwsXG4gICAgICByb3V0ZXJOYW1lOiBvYnNlcnZhdGlvbi5yb3V0ZXJOYW1lLFxuICAgIH0pO1xuICAgIHJldHVybiB7IHRhcmdldCwgYm9keTogaW5wdXQuYm9keSwgb2JzZXJ2YXRpb24gfTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcmVhZENhY2hlZChcbiAgICBrZXk6IHN0cmluZyxcbiAgICB0YXJnZXRzOiByZWFkb25seSBNb2RlbFRhcmdldFtdLFxuICApOiBQcm9taXNlPFNtYXJ0Um91dGVyT2JzZXJ2YXRpb24gfCB1bmRlZmluZWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcGFyc2VkID0gU21hcnRSb3V0ZXJPYnNlcnZhdGlvblNjaGVtYS5zYWZlUGFyc2UoYXdhaXQgdGhpcy5zdG9yZS5nZXQoa2V5KSk7XG4gICAgICBpZiAoIXBhcnNlZC5zdWNjZXNzKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgcmV0dXJuIHRhcmdldHMuc29tZSgodGFyZ2V0KSA9PiB0YXJnZXQuaWQgPT09IHBhcnNlZC5kYXRhLnNlbGVjdGVkTW9kZWwpXG4gICAgICAgID8gcGFyc2VkLmRhdGFcbiAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhcIlNtYXJ0IFJvdXRlciBjYWNoZSByZWFkIGZhaWxlZFwiLCB7IGVycm9yOiB0b0Vycm9yKGVycm9yKSB9KTtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB3cml0ZUNhY2hlZChrZXk6IHN0cmluZywgb2JzZXJ2YXRpb246IFNtYXJ0Um91dGVyT2JzZXJ2YXRpb24pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5zdG9yZS5zZXQoa2V5LCBvYnNlcnZhdGlvbiwgdGhpcy5zZXR0aW5ncy5yb3V0ZVR0bFNlY29uZHMpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZGVidWcoXCJTbWFydCBSb3V0ZXIgY2FjaGUgd3JpdGUgZmFpbGVkXCIsIHsgZXJyb3I6IHRvRXJyb3IoZXJyb3IpIH0pO1xuICAgIH1cbiAgfVxufVxuXG4vKiogU3RhYmxlIGxvZ2ljYWwtdHVybiBrZXkgc2hhcmVkIGJ5IGluaXRpYWwgcmVxdWVzdHMgYW5kIHRvb2wgY29udGludWF0aW9ucy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzbWFydFJvdXRlclR1cm5LZXkoXG4gIGxvZ2ljYWxUdXJuOiBzdHJpbmcsXG4gIGNhbmRpZGF0ZXM6IHJlYWRvbmx5IFNtYXJ0Um91dGVyQ2FuZGlkYXRlPHVua25vd24+W10sXG4gIGNvbnRleHQ6IFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIHVua25vd24+Pixcbik6IHN0cmluZyB7XG4gIHJldHVybiBjcmVhdGVIYXNoKFwic2hhMjU2XCIpXG4gICAgLnVwZGF0ZShcbiAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgbG9naWNhbFR1cm4sXG4gICAgICAgIGNhbmRpZGF0ZXM6IGNhbmRpZGF0ZXMubWFwKCh7IG1vZGVsLCBoYXJuZXNzIH0pID0+ICh7IG1vZGVsLCBoYXJuZXNzIH0pKSxcbiAgICAgICAgY29udGV4dCxcbiAgICAgIH0pLFxuICAgIClcbiAgICAuZGlnZXN0KFwiaGV4XCIpO1xufVxuXG5mdW5jdGlvbiBpc0VsaWdpYmxlVGFyZ2V0KFxuICB0YXJnZXQ6IE1vZGVsVGFyZ2V0LFxuICBpbnB1dDoge1xuICAgIHJlYWRvbmx5IGZlYXR1cmVzOiBSZXF1ZXN0ZWRGZWF0dXJlcztcbiAgICByZWFkb25seSBvcmlnaW5hdG9yPzogc3RyaW5nO1xuICAgIHJlYWRvbmx5IHByZWZlclN5c3RlbU1vZGVsczogYm9vbGVhbjtcbiAgICByZWFkb25seSBwcm90b2NvbDogRXhjbHVkZTxDbGllbnRQcm90b2NvbCwgXCJvcGVuYWktZW1iZWRkaW5nc1wiPjtcbiAgfSxcbiAgZXhwbGljaXRSZWFzb25pbmdFZmZvcnQ6IFJlYXNvbmluZ0VmZm9ydCB8IHVuZGVmaW5lZCxcbiAgaGFybmVzczogU21hcnRSb3V0ZXJIYXJuZXNzLFxuKTogYm9vbGVhbiB7XG4gIGlmICghdGFyZ2V0LmVuZHBvaW50IHx8IHRhcmdldC5lbmRwb2ludC5zdGF0dXM/LmRlcHJlY2F0ZWQgPT09IHRydWUpIHJldHVybiBmYWxzZTtcbiAgaWYgKCF0YXJnZXQubW9kZWxTZXJ2aWNlTmFtZT8udG9Mb3dlckNhc2UoKS5zdGFydHNXaXRoKFwic3lzdGVtLmFpLlwiKSkgcmV0dXJuIGZhbHNlO1xuICBpZiAoIXRhcmdldC5jYXBhYmlsaXRpZXMuY2hhdCkgcmV0dXJuIGZhbHNlO1xuICBpZiAoaGFybmVzcyA9PT0gXCJjb2RleFwiICYmICF0YXJnZXQuY2FwYWJpbGl0aWVzLmFpR2F0ZXdheUNvZGV4KSByZXR1cm4gZmFsc2U7XG4gIGlmIChoYXJuZXNzID09PSBcImNsYXVkZVwiICYmICF0YXJnZXQuY2FwYWJpbGl0aWVzLmFudGhyb3BpYykgcmV0dXJuIGZhbHNlO1xuICBpZiAoaW5wdXQuZmVhdHVyZXMudG9vbHMgJiYgIXRhcmdldC5jYXBhYmlsaXRpZXMudG9vbHMpIHJldHVybiBmYWxzZTtcbiAgaWYgKGlucHV0LmZlYXR1cmVzLnBhcmFsbGVsVG9vbHMgJiYgIXRhcmdldC5jYXBhYmlsaXRpZXMucGFyYWxsZWxUb29scykgcmV0dXJuIGZhbHNlO1xuICBpZiAoaW5wdXQuZmVhdHVyZXMuY3VzdG9tVG9vbHMgJiYgIXRhcmdldC5jYXBhYmlsaXRpZXMuY3VzdG9tVG9vbHMpIHJldHVybiBmYWxzZTtcbiAgaWYgKGlucHV0LmZlYXR1cmVzLnN0cnVjdHVyZWRPdXRwdXQgJiYgIXRhcmdldC5jYXBhYmlsaXRpZXMuc3RydWN0dXJlZE91dHB1dCkgcmV0dXJuIGZhbHNlO1xuICBpZiAoaW5wdXQuZmVhdHVyZXMud2ViU2VhcmNoICYmICF0YXJnZXQuY2FwYWJpbGl0aWVzLndlYlNlYXJjaCkgcmV0dXJuIGZhbHNlO1xuICBpZiAoaW5wdXQuZmVhdHVyZXMuaW1hZ2VJbnB1dCAmJiAhdGFyZ2V0LmNhcGFiaWxpdGllcy5pbWFnZUlucHV0KSByZXR1cm4gZmFsc2U7XG4gIGlmIChpbnB1dC5mZWF0dXJlcy5hcHBseVBhdGNoICYmICF0YXJnZXQuY2FwYWJpbGl0aWVzLmFwcGx5UGF0Y2gpIHJldHVybiBmYWxzZTtcbiAgaWYgKGlucHV0LmZlYXR1cmVzLnJlYXNvbmluZyAmJiAhdGFyZ2V0LmNhcGFiaWxpdGllcy5yZWFzb25pbmcpIHJldHVybiBmYWxzZTtcbiAgaWYgKFxuICAgIGV4cGxpY2l0UmVhc29uaW5nRWZmb3J0ICYmXG4gICAgZXhwbGljaXRSZWFzb25pbmdFZmZvcnQgIT09IFwibm9uZVwiICYmXG4gICAgIXRhcmdldC5yZWFzb25pbmdFZmZvcnRzLmluY2x1ZGVzKGV4cGxpY2l0UmVhc29uaW5nRWZmb3J0KVxuICApIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgdHJ5IHtcbiAgICByZXNvbHZlUm91dGUoe1xuICAgICAgY2xpZW50UHJvdG9jb2w6IGlucHV0LnByb3RvY29sLFxuICAgICAgLi4uKGlucHV0Lm9yaWdpbmF0b3IgPyB7IG9yaWdpbmF0b3I6IGlucHV0Lm9yaWdpbmF0b3IgfSA6IHt9KSxcbiAgICAgIHByZWZlclN5c3RlbU1vZGVsczogaW5wdXQucHJlZmVyU3lzdGVtTW9kZWxzLFxuICAgICAgZmVhdHVyZXM6IGlucHV0LmZlYXR1cmVzLFxuICAgICAgdGFyZ2V0LFxuICAgIH0pO1xuICAgIHJldHVybiB0cnVlO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuZnVuY3Rpb24gcmVxdWVzdGVkUmVhc29uaW5nRWZmb3J0KFxuICBib2R5OiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4sXG4pOiBSZWFzb25pbmdFZmZvcnQgfCB1bmRlZmluZWQge1xuICBjb25zdCByZWFzb25pbmcgPSBpc1JlY29yZChib2R5LnJlYXNvbmluZykgPyBib2R5LnJlYXNvbmluZyA6IHVuZGVmaW5lZDtcbiAgY29uc3Qgb3V0cHV0Q29uZmlnID0gaXNSZWNvcmQoYm9keS5vdXRwdXRfY29uZmlnKSA/IGJvZHkub3V0cHV0X2NvbmZpZyA6IHVuZGVmaW5lZDtcbiAgY29uc3QgcmF3ID0gYm9keS5yZWFzb25pbmdfZWZmb3J0ID8/IHJlYXNvbmluZz8uZWZmb3J0ID8/IG91dHB1dENvbmZpZz8uZWZmb3J0O1xuICBpZiAocmF3ID09PSB1bmRlZmluZWQgfHwgcmF3ID09PSBudWxsKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCBub3JtYWxpemVkID0gU3RyaW5nKHJhdykudHJpbSgpLnRvTG93ZXJDYXNlKCkucmVwbGFjZUFsbChcIl9cIiwgXCItXCIpO1xuICBjb25zdCBwYXJzZWQgPSBSZWFzb25pbmdFZmZvcnRTY2hlbWEuc2FmZVBhcnNlKFxuICAgIG5vcm1hbGl6ZWQgPT09IFwiZXh0cmEtaGlnaFwiID8gXCJ4aGlnaFwiIDogbm9ybWFsaXplZCxcbiAgKTtcbiAgaWYgKCFwYXJzZWQuc3VjY2Vzcykge1xuICAgIHRocm93IG5ldyBTbWFydFJvdXRlckVycm9yKDQwMCwgYFVuc3VwcG9ydGVkIFNtYXJ0IFJvdXRlciByZWFzb25pbmcgZWZmb3J0OiAke1N0cmluZyhyYXcpfWApO1xuICB9XG4gIHJldHVybiBwYXJzZWQuZGF0YTtcbn1cblxuaW50ZXJmYWNlIENvbnZlcnNhdGlvbkV2ZW50IHtcbiAgcmVhZG9ubHkgcm9sZTogXCJhc3Npc3RhbnRcIiB8IFwic3lzdGVtXCIgfCBcInRvb2xcIiB8IFwidXNlclwiO1xuICByZWFkb25seSB0ZXh0OiBzdHJpbmc7XG59XG5cbmZ1bmN0aW9uIGNvbnRleHRGcm9tRXZlbnRzKFxuICBldmVudHM6IHJlYWRvbmx5IENvbnZlcnNhdGlvbkV2ZW50W10sXG4gIHRva2VuQnVkZ2V0OiBudW1iZXIsXG4pOiBTbWFydFJvdXRlckNvbnRleHQge1xuICBjb25zdCBsYXRlc3RVc2VySW5kZXggPSBsYXN0RXZlbnRJbmRleChldmVudHMsIFwidXNlclwiKTtcbiAgY29uc3QgdGFza0V2ZW50ID0gbGF0ZXN0VXNlckluZGV4ID49IDAgPyBldmVudHNbbGF0ZXN0VXNlckluZGV4XSA6IGV2ZW50cy5hdCgtMSk7XG4gIGNvbnN0IHRhc2sgPSB0cnVuY2F0ZVRleHQodGFza0V2ZW50Py50ZXh0ID8/IFwiXCIsIHRva2VuQnVkZ2V0LCBcInN0YXJ0XCIpO1xuICBsZXQgcmVtYWluaW5nID0gTWF0aC5tYXgoMCwgdG9rZW5CdWRnZXQgLSBjb3VudFRva2Vucyh0YXNrKSk7XG4gIGNvbnN0IGNvbnRleHQ6IHN0cmluZ1tdID0gW107XG4gIGZvciAoXG4gICAgbGV0IGluZGV4ID0gKHRhc2tFdmVudCA/IGV2ZW50cy5pbmRleE9mKHRhc2tFdmVudCkgOiBldmVudHMubGVuZ3RoKSAtIDE7XG4gICAgaW5kZXggPj0gMDtcbiAgICBpbmRleCAtPSAxXG4gICkge1xuICAgIGNvbnN0IGV2ZW50ID0gZXZlbnRzW2luZGV4XTtcbiAgICBpZiAoIWV2ZW50IHx8ICFldmVudC50ZXh0IHx8IGV2ZW50LnJvbGUgPT09IFwidG9vbFwiKSBjb250aW51ZTtcbiAgICBjb25zdCB2YWx1ZSA9IGAke2V2ZW50LnJvbGV9OiAke2V2ZW50LnRleHR9YDtcbiAgICBjb25zdCByZXRhaW5lZCA9IHRydW5jYXRlVGV4dCh2YWx1ZSwgcmVtYWluaW5nLCBcImVuZFwiKTtcbiAgICBpZiAoIXJldGFpbmVkKSBicmVhaztcbiAgICBjb250ZXh0LnVuc2hpZnQocmV0YWluZWQpO1xuICAgIHJlbWFpbmluZyAtPSBjb3VudFRva2VucyhyZXRhaW5lZCk7XG4gIH1cbiAgY29uc3QgY29tYmluZWQgPSBbLi4uY29udGV4dCwgdGFza10uZmlsdGVyKEJvb2xlYW4pLmpvaW4oXCJcXG5cIik7XG4gIGNvbnN0IGxvZ2ljYWxFdmVudHMgPSBsYXRlc3RVc2VySW5kZXggPj0gMCA/IGV2ZW50cy5zbGljZSgwLCBsYXRlc3RVc2VySW5kZXggKyAxKSA6IGV2ZW50cztcbiAgcmV0dXJuIHtcbiAgICB0YXNrOiBjb21iaW5lZCxcbiAgICBsb2dpY2FsVHVybjogbG9naWNhbEV2ZW50cy5tYXAoKGV2ZW50KSA9PiBgJHtldmVudC5yb2xlfToke2V2ZW50LnRleHR9YCkuam9pbihcIlxcblwiKSxcbiAgICBjb250aW51YXRpb246XG4gICAgICBsYXRlc3RVc2VySW5kZXggPj0gMCAmJlxuICAgICAgZXZlbnRzLnNsaWNlKGxhdGVzdFVzZXJJbmRleCArIDEpLnNvbWUoKGV2ZW50KSA9PiBldmVudC5yb2xlICE9PSBcInN5c3RlbVwiKSxcbiAgfTtcbn1cblxuZnVuY3Rpb24gY29udmVyc2F0aW9uRXZlbnRzKGlucHV0OiB1bmtub3duKTogQ29udmVyc2F0aW9uRXZlbnRbXSB7XG4gIGlmICh0eXBlb2YgaW5wdXQgPT09IFwic3RyaW5nXCIpIHJldHVybiBpbnB1dC50cmltKCkgPyBbeyByb2xlOiBcInVzZXJcIiwgdGV4dDogaW5wdXQudHJpbSgpIH1dIDogW107XG4gIGlmIChBcnJheS5pc0FycmF5KGlucHV0KSkgcmV0dXJuIGlucHV0LmZsYXRNYXAobWVzc2FnZUV2ZW50KTtcbiAgaWYgKCFpc1JlY29yZChpbnB1dCkpIHJldHVybiBbXTtcbiAgZm9yIChjb25zdCBrZXkgb2YgW1wibWVzc2FnZXNcIiwgXCJpbnB1dFwiXSBhcyBjb25zdCkge1xuICAgIGNvbnN0IHZhbHVlID0gaW5wdXRba2V5XTtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiICYmIHZhbHVlLnRyaW0oKSkgcmV0dXJuIFt7IHJvbGU6IFwidXNlclwiLCB0ZXh0OiB2YWx1ZS50cmltKCkgfV07XG4gICAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICBjb25zdCBldmVudHMgPSB2YWx1ZS5mbGF0TWFwKG1lc3NhZ2VFdmVudCk7XG4gICAgICBpZiAoZXZlbnRzLmxlbmd0aCA+IDApIHJldHVybiBldmVudHM7XG4gICAgfVxuICB9XG4gIHJldHVybiBbXTtcbn1cblxuZnVuY3Rpb24gbWVzc2FnZUV2ZW50KHZhbHVlOiB1bmtub3duKTogQ29udmVyc2F0aW9uRXZlbnRbXSB7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIpIHJldHVybiB2YWx1ZS50cmltKCkgPyBbeyByb2xlOiBcInVzZXJcIiwgdGV4dDogdmFsdWUudHJpbSgpIH1dIDogW107XG4gIGlmICghaXNSZWNvcmQodmFsdWUpKSByZXR1cm4gW107XG4gIGNvbnN0IHJvbGUgPSBtZXNzYWdlUm9sZSh2YWx1ZSk7XG4gIGlmICghcm9sZSkgcmV0dXJuIFtdO1xuICBjb25zdCB0ZXh0ID0gY29udGVudFRleHQodmFsdWUuY29udGVudCA/PyB2YWx1ZS50ZXh0ID8/IHZhbHVlLmlucHV0X3RleHQgPz8gdmFsdWUub3V0cHV0X3RleHQpO1xuICByZXR1cm4gdGV4dCA/IFt7IHJvbGUsIHRleHQgfV0gOiBbXTtcbn1cblxuZnVuY3Rpb24gbWVzc2FnZVJvbGUoXG4gIHZhbHVlOiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4sXG4pOiBDb252ZXJzYXRpb25FdmVudFtcInJvbGVcIl0gfCB1bmRlZmluZWQge1xuICBpZiAodmFsdWUucm9sZSA9PT0gXCJ1c2VyXCIgfHwgdmFsdWUucm9sZSA9PT0gXCJhc3Npc3RhbnRcIiB8fCB2YWx1ZS5yb2xlID09PSBcInN5c3RlbVwiKSB7XG4gICAgcmV0dXJuIHZhbHVlLnJvbGU7XG4gIH1cbiAgaWYgKFxuICAgIHZhbHVlLnJvbGUgPT09IFwidG9vbFwiIHx8XG4gICAgdmFsdWUudHlwZSA9PT0gXCJmdW5jdGlvbl9jYWxsX291dHB1dFwiIHx8XG4gICAgdmFsdWUudHlwZSA9PT0gXCJ0b29sX3Jlc3VsdFwiXG4gICkge1xuICAgIHJldHVybiBcInRvb2xcIjtcbiAgfVxuICBpZiAodmFsdWUudHlwZSA9PT0gXCJmdW5jdGlvbl9jYWxsXCIgfHwgdmFsdWUudHlwZSA9PT0gXCJyZWFzb25pbmdcIikgcmV0dXJuIFwiYXNzaXN0YW50XCI7XG4gIGlmICh2YWx1ZS50eXBlID09PSBcIm1lc3NhZ2VcIiAmJiB2YWx1ZS5yb2xlID09PSB1bmRlZmluZWQpIHJldHVybiBcInVzZXJcIjtcbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuZnVuY3Rpb24gY29udGVudFRleHQodmFsdWU6IHVua25vd24pOiBzdHJpbmcge1xuICBpZiAodHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiKSByZXR1cm4gdmFsdWUudHJpbSgpO1xuICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHJldHVybiB2YWx1ZS5tYXAoY29udGVudFRleHQpLmZpbHRlcihCb29sZWFuKS5qb2luKFwiXFxuXCIpO1xuICBpZiAoIWlzUmVjb3JkKHZhbHVlKSkgcmV0dXJuIFwiXCI7XG4gIGZvciAoY29uc3Qga2V5IG9mIFtcInRleHRcIiwgXCJpbnB1dF90ZXh0XCIsIFwib3V0cHV0X3RleHRcIiwgXCJjb250ZW50XCJdIGFzIGNvbnN0KSB7XG4gICAgY29uc3QgdGV4dCA9IGNvbnRlbnRUZXh0KHZhbHVlW2tleV0pO1xuICAgIGlmICh0ZXh0KSByZXR1cm4gdGV4dDtcbiAgfVxuICByZXR1cm4gXCJcIjtcbn1cblxuY29uc3QgVEFTS19LRVlTID0gW1xuICBcInByb21wdFwiLFxuICBcInRhc2tcIixcbiAgXCJxdWVyeVwiLFxuICBcInF1ZXN0aW9uXCIsXG4gIFwicmVxdWVzdFwiLFxuICBcImRlc2NyaXB0aW9uXCIsXG4gIFwibWVzc2FnZVwiLFxuICBcInRleHRcIixcbiAgXCJpbnB1dFwiLFxuXSBhcyBjb25zdDtcbmNvbnN0IElHTk9SRURfS0VZUyA9IG5ldyBTZXQoW1xuICBcImFwaV9rZXlcIixcbiAgXCJhdXRob3JpemF0aW9uXCIsXG4gIFwiYXJndW1lbnRzXCIsXG4gIFwiY3JlZGVudGlhbHNcIixcbiAgXCJoZWFkZXJzXCIsXG4gIFwibWV0YWRhdGFcIixcbiAgXCJwYXNzd29yZFwiLFxuICBcInNlY3JldFwiLFxuICBcInRva2VuXCIsXG4gIFwidG9vbHNcIixcbl0pO1xuXG5mdW5jdGlvbiBjb2xsZWN0VGFza1N0cmluZ3MoaW5wdXQ6IHVua25vd24pOiBzdHJpbmdbXSB7XG4gIGlmICh0eXBlb2YgaW5wdXQgPT09IFwic3RyaW5nXCIpIHJldHVybiBpbnB1dC50cmltKCkgPyBbaW5wdXQudHJpbSgpXSA6IFtdO1xuICBjb25zdCBwcmVmZXJyZWQ6IHN0cmluZ1tdID0gW107XG4gIGlmIChpc1JlY29yZChpbnB1dCkpIHtcbiAgICBmb3IgKGNvbnN0IGtleSBvZiBUQVNLX0tFWVMpIHByZWZlcnJlZC5wdXNoKC4uLnN0cmluZ0xlYXZlcyhpbnB1dFtrZXldLCBrZXksIDApKTtcbiAgfVxuICByZXR1cm4gcHJlZmVycmVkLmxlbmd0aCA+IDAgPyBwcmVmZXJyZWQuc2xpY2UoMCwgMzIpIDogc3RyaW5nTGVhdmVzKGlucHV0LCBcIlwiLCAwKS5zbGljZSgwLCAzMik7XG59XG5cbmZ1bmN0aW9uIHN0cmluZ0xlYXZlcyh2YWx1ZTogdW5rbm93biwga2V5OiBzdHJpbmcsIGRlcHRoOiBudW1iZXIpOiBzdHJpbmdbXSB7XG4gIGlmIChkZXB0aCA+IDYgfHwgSUdOT1JFRF9LRVlTLmhhcyhrZXkudG9Mb3dlckNhc2UoKSkpIHJldHVybiBbXTtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIikgcmV0dXJuIHZhbHVlLnRyaW0oKSA/IFt2YWx1ZS50cmltKCldIDogW107XG4gIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkgcmV0dXJuIHZhbHVlLmZsYXRNYXAoKGl0ZW0pID0+IHN0cmluZ0xlYXZlcyhpdGVtLCBrZXksIGRlcHRoICsgMSkpO1xuICBpZiAoIWlzUmVjb3JkKHZhbHVlKSkgcmV0dXJuIFtdO1xuICByZXR1cm4gT2JqZWN0LmVudHJpZXModmFsdWUpLmZsYXRNYXAoKFtjaGlsZEtleSwgY2hpbGRdKSA9PlxuICAgIHN0cmluZ0xlYXZlcyhjaGlsZCwgY2hpbGRLZXksIGRlcHRoICsgMSksXG4gICk7XG59XG5cbmZ1bmN0aW9uIHBhcnNlSnNvblN0cmluZyhpbnB1dDogdW5rbm93bik6IHVua25vd24ge1xuICBpZiAodHlwZW9mIGlucHV0ICE9PSBcInN0cmluZ1wiKSByZXR1cm4gaW5wdXQ7XG4gIGNvbnN0IHRyaW1tZWQgPSBpbnB1dC50cmltKCk7XG4gIGlmICghdHJpbW1lZCB8fCAoIXRyaW1tZWQuc3RhcnRzV2l0aChcIntcIikgJiYgIXRyaW1tZWQuc3RhcnRzV2l0aChcIltcIikpKSByZXR1cm4gaW5wdXQ7XG4gIHRyeSB7XG4gICAgcmV0dXJuIEpTT04ucGFyc2UodHJpbW1lZCkgYXMgdW5rbm93bjtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGlucHV0O1xuICB9XG59XG5cbmZ1bmN0aW9uIGNvdW50VG9rZW5zKHRleHQ6IHN0cmluZyk6IG51bWJlciB7XG4gIHJldHVybiBDT05URVhUX0VOQ09ESU5HLmVuY29kZSh0ZXh0LCBbXSwgW10pLmxlbmd0aDtcbn1cblxuZnVuY3Rpb24gdHJ1bmNhdGVUZXh0KHRleHQ6IHN0cmluZywgdG9rZW5CdWRnZXQ6IG51bWJlciwgZWRnZTogXCJzdGFydFwiIHwgXCJlbmRcIik6IHN0cmluZyB7XG4gIGlmICh0b2tlbkJ1ZGdldCA8PSAwIHx8ICF0ZXh0KSByZXR1cm4gXCJcIjtcbiAgY29uc3QgdG9rZW5zID0gQ09OVEVYVF9FTkNPRElORy5lbmNvZGUodGV4dCwgW10sIFtdKTtcbiAgaWYgKHRva2Vucy5sZW5ndGggPD0gdG9rZW5CdWRnZXQpIHJldHVybiB0ZXh0O1xuICByZXR1cm4gQ09OVEVYVF9FTkNPRElORy5kZWNvZGUoXG4gICAgZWRnZSA9PT0gXCJzdGFydFwiID8gdG9rZW5zLnNsaWNlKDAsIHRva2VuQnVkZ2V0KSA6IHRva2Vucy5zbGljZSgtdG9rZW5CdWRnZXQpLFxuICApO1xufVxuXG5mdW5jdGlvbiBsYXN0RXZlbnRJbmRleChcbiAgZXZlbnRzOiByZWFkb25seSBDb252ZXJzYXRpb25FdmVudFtdLFxuICByb2xlOiBDb252ZXJzYXRpb25FdmVudFtcInJvbGVcIl0sXG4pOiBudW1iZXIge1xuICBmb3IgKGxldCBpbmRleCA9IGV2ZW50cy5sZW5ndGggLSAxOyBpbmRleCA+PSAwOyBpbmRleCAtPSAxKSB7XG4gICAgaWYgKGV2ZW50c1tpbmRleF0/LnJvbGUgPT09IHJvbGUpIHJldHVybiBpbmRleDtcbiAgfVxuICByZXR1cm4gLTE7XG59XG5cbmZ1bmN0aW9uIHVuaXF1ZUNhbmRpZGF0ZXM8VD4oXG4gIGNhbmRpZGF0ZXM6IHJlYWRvbmx5IFNtYXJ0Um91dGVyQ2FuZGlkYXRlPFQ+W10sXG4pOiBTbWFydFJvdXRlckNhbmRpZGF0ZTxUPltdIHtcbiAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICByZXR1cm4gY2FuZGlkYXRlcy5maWx0ZXIoKGNhbmRpZGF0ZSkgPT4ge1xuICAgIGNvbnN0IGtleSA9IGAke2NhbmRpZGF0ZS5oYXJuZXNzfToke25vcm1hbGl6ZVJvdXRlTW9kZWwoY2FuZGlkYXRlLm1vZGVsKX1gO1xuICAgIGlmIChzZWVuLmhhcyhrZXkpKSByZXR1cm4gZmFsc2U7XG4gICAgc2Vlbi5hZGQoa2V5KTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZVJvdXRlTW9kZWwobW9kZWw6IHN0cmluZyk6IHN0cmluZyB7XG4gIGxldCBub3JtYWxpemVkID0gbW9kZWwudHJpbSgpLnRvTG93ZXJDYXNlKCkuc3BsaXQoXCIvXCIpLmF0KC0xKSA/PyBcIlwiO1xuICBmb3IgKGNvbnN0IHByZWZpeCBvZiBbXCJkYXRhYnJpY2tzLVwiLCBcInN5c3RlbS5haS5cIl0gYXMgY29uc3QpIHtcbiAgICBpZiAobm9ybWFsaXplZC5zdGFydHNXaXRoKHByZWZpeCkpIHtcbiAgICAgIG5vcm1hbGl6ZWQgPSBub3JtYWxpemVkLnNsaWNlKHByZWZpeC5sZW5ndGgpO1xuICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG4gIHJldHVybiBub3JtYWxpemVkO1xufVxuXG5mdW5jdGlvbiBwcm9iZUtleTxUPihjYW5kaWRhdGVzOiByZWFkb25seSBTbWFydFJvdXRlckNhbmRpZGF0ZTxUPltdLCByb3V0ZXJOYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoe1xuICAgIHJvdXRlck5hbWUsXG4gICAgY2FuZGlkYXRlczogY2FuZGlkYXRlc1xuICAgICAgLm1hcCgoeyBtb2RlbCwgaGFybmVzcyB9KSA9PiAoeyBtb2RlbDogbm9ybWFsaXplUm91dGVNb2RlbChtb2RlbCksIGhhcm5lc3MgfSkpXG4gICAgICAuc29ydCgobGVmdCwgcmlnaHQpID0+XG4gICAgICAgIGAke2xlZnQuaGFybmVzc306JHtsZWZ0Lm1vZGVsfWAubG9jYWxlQ29tcGFyZShgJHtyaWdodC5oYXJuZXNzfToke3JpZ2h0Lm1vZGVsfWApLFxuICAgICAgKSxcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGFwcEtpdENhY2hlTWFuYWdlcigpOiBDYWNoZU1hbmFnZXIgfCB1bmRlZmluZWQge1xuICB0cnkge1xuICAgIHJldHVybiBDYWNoZU1hbmFnZXIuZ2V0SW5zdGFuY2VTeW5jKCk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gc21hcnRSb3V0ZXJQcm9iZUlkZW50aXR5KGNsaWVudDogV29ya3NwYWNlQ2xpZW50KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgY29uc3QgaGVhZGVycyA9IG5ldyBIZWFkZXJzKCk7XG4gIGNvbnN0IGhvc3QgPSAoYXdhaXQgY2xpZW50LmNvbmZpZy5nZXRIb3N0KCkpLnRvU3RyaW5nKCk7XG4gIGF3YWl0IGNsaWVudC5jb25maWcuYXV0aGVudGljYXRlKGhlYWRlcnMpO1xuICByZXR1cm4gY3JlYXRlSGFzaChcInNoYTI1NlwiKVxuICAgIC51cGRhdGUoaG9zdClcbiAgICAudXBkYXRlKFwiXFwwXCIpXG4gICAgLnVwZGF0ZShoZWFkZXJzLmdldChcImF1dGhvcml6YXRpb25cIikgPz8gXCJcIilcbiAgICAudXBkYXRlKFwiXFwwXCIpXG4gICAgLnVwZGF0ZShoZWFkZXJzLmdldChcIngtZGF0YWJyaWNrcy13b3Jrc3BhY2UtaWRcIikgPz8gXCJcIilcbiAgICAuZGlnZXN0KFwiaGV4XCIpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBpbnZva2VTbWFydFJvdXRlcihcbiAgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQsXG4gIGJvZHk6IFNtYXJ0Um91dGVyUmVxdWVzdCxcbiAgc2lnbmFsOiBBYm9ydFNpZ25hbCxcbiAgdGltZW91dE1zOiBudW1iZXIsXG4pOiBQcm9taXNlPHVua25vd24+IHtcbiAgY29uc3QgaG9zdCA9IChhd2FpdCBjbGllbnQuY29uZmlnLmdldEhvc3QoKSkudG9TdHJpbmcoKTtcbiAgY29uc3QgdXJsID0gbmV3IFVSTChcIi9haS1nYXRld2F5L3JvdXRpbmcvdjEvcm91dGVzOnNlbGVjdFwiLCBob3N0KTtcbiAgY29uc3QgaGVhZGVycyA9IG5ldyBIZWFkZXJzKHsgXCJjb250ZW50LXR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIgfSk7XG4gIGF3YWl0IGNsaWVudC5jb25maWcuYXV0aGVudGljYXRlKGhlYWRlcnMpO1xuICBjb25zdCBjb21iaW5lZFNpZ25hbCA9IEFib3J0U2lnbmFsLmFueShbc2lnbmFsLCBBYm9ydFNpZ25hbC50aW1lb3V0KHRpbWVvdXRNcyldKTtcbiAgbGV0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICBoZWFkZXJzLFxuICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KGJvZHkpLFxuICAgIHNpZ25hbDogY29tYmluZWRTaWduYWwsXG4gIH0pO1xuICBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSA0MDEgJiYgKGF3YWl0IHJlZnJlc2hXb3Jrc3BhY2VDbGllbnRBdXRoZW50aWNhdGlvbihjbGllbnQpKSkge1xuICAgIGF3YWl0IHJlc3BvbnNlLmJvZHk/LmNhbmNlbCgpO1xuICAgIGhlYWRlcnMuZGVsZXRlKFwiYXV0aG9yaXphdGlvblwiKTtcbiAgICBoZWFkZXJzLmRlbGV0ZShcIngtZGF0YWJyaWNrcy13b3Jrc3BhY2UtaWRcIik7XG4gICAgYXdhaXQgY2xpZW50LmNvbmZpZy5hdXRoZW50aWNhdGUoaGVhZGVycyk7XG4gICAgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCh1cmwsIHtcbiAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICBoZWFkZXJzLFxuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoYm9keSksXG4gICAgICBzaWduYWw6IGNvbWJpbmVkU2lnbmFsLFxuICAgIH0pO1xuICB9XG4gIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICBjb25zdCBkZXRhaWwgPSAoYXdhaXQgcmVzcG9uc2UudGV4dCgpLmNhdGNoKCgpID0+IFwiXCIpKS50cmltKCkuc2xpY2UoMCwgNTAwKTtcbiAgICB0aHJvdyBuZXcgU21hcnRSb3V0ZXJFcnJvcihcbiAgICAgIHJlc3BvbnNlLnN0YXR1cyA9PT0gNDA0ID8gNDA0IDogNTAzLFxuICAgICAgYERhdGFicmlja3MgU21hcnQgUm91dGVyIGZhaWxlZCB3aXRoIEhUVFAgJHtyZXNwb25zZS5zdGF0dXN9JHtkZXRhaWwgPyBgOiAke2RldGFpbH1gIDogXCJcIn1gLFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIHJlc3BvbnNlLmpzb24oKTtcbn1cblxuLyoqIERlZmF1bHRzIHNoYXJlZCBieSBnYXRld2F5LCBNYXN0cmEsIGFuZCBDTEkgU21hcnQgUm91dGVyIGNhbGxlcnMuICovXG5leHBvcnQgY29uc3QgU01BUlRfUk9VVEVSX0RFRkFVTFRfU0VUVElOR1M6IFNtYXJ0Um91dGVyU2V0dGluZ3MgPSBPYmplY3QuZnJlZXplKHtcbiAgY29udGV4dFRva2VuQnVkZ2V0OiA0XzA5NixcbiAgcHJvYmVSZWZyZXNoSW50ZXJ2YWxNczogM182MDBfMDAwLFxuICBwcm9iZVR0bE1zOiAzMDBfMDAwLFxuICByb3V0ZVR0bFNlY29uZHM6IDIxXzYwMCxcbiAgcm91dGVyTmFtZTogU01BUlRfUk9VVEVSX05BTUUsXG4gIHRpbWVvdXRNczogMTBfMDAwLFxufSk7XG4iXX0=
|