@dbx-tools/appkit-model-gateway 0.9.190 → 0.9.193

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,406 @@
1
+ /**
2
+ * Databricks AI Functions `ai_decide` model selection.
3
+ *
4
+ * @module
5
+ */
6
+ import { getExecutionContext } from "@databricks/appkit";
7
+ import { closeCache, createCache, getOrSet } from "@dbx-tools/cache";
8
+ import { refreshWorkspaceClientAuthentication } from "@dbx-tools/databricks";
9
+ import { endpointCapabilities, modelMetadataFor, selection, versionTuple } from "@dbx-tools/model";
10
+ import { isRecord, log, toError } from "@dbx-tools/shared-core";
11
+ import { ModelClass } from "@dbx-tools/shared-model";
12
+ import { AiDecideModelFiltersSchema, AiDecideObservationSchema, AiDecideStrategySchema, } from "@dbx-tools/shared-model-gateway";
13
+ import { z } from "zod";
14
+ import { AppKitSmartRouterProbeStore, SmartRouterContextBuilder, SmartRouterProbeRecordSchema, } from "./smart-router.js";
15
+ const AI_DECIDE_PATH = "/api/2.0/ai-functions/ai-decide";
16
+ const DEFAULT_TIMEOUT_MS = 10_000;
17
+ const PROBE_KEY = "ai-decide-v1";
18
+ const POSITIVE_PROBE_TTL_MS = 5 * 60_000;
19
+ const NEGATIVE_PROBE_TTL_MS = 30_000;
20
+ const PROBE_CACHE_TTL_MS = POSITIVE_PROBE_TTL_MS * 2;
21
+ const logger = log.logger("appkit/model-gateway/ai-decide");
22
+ const AiDecideChoiceAnswerSchema = z
23
+ .object({
24
+ type: z.literal("choice"),
25
+ choice: z.string().trim().min(1),
26
+ probabilities: z.record(z.string(), z.number().min(0).max(1)).optional(),
27
+ confidence: z.number().min(0).max(1).optional(),
28
+ })
29
+ .passthrough();
30
+ const AiDecideTaskComplexitySchema = z.enum(["simple", "standard", "advanced"]);
31
+ const AiDecideTaskComplexityAnswerSchema = z
32
+ .object({
33
+ type: z.literal("choice"),
34
+ choice: AiDecideTaskComplexitySchema,
35
+ })
36
+ .passthrough();
37
+ const AiDecideTaskComplexityResponseSchema = z
38
+ .object({
39
+ response: z
40
+ .object({
41
+ answers: z
42
+ .object({
43
+ task_complexity: AiDecideTaskComplexityAnswerSchema,
44
+ })
45
+ .passthrough(),
46
+ })
47
+ .passthrough(),
48
+ metadata: z.object({ version: z.string() }).passthrough().optional(),
49
+ })
50
+ .passthrough();
51
+ const AiDecideModelResponseSchema = z
52
+ .object({
53
+ response: z
54
+ .object({
55
+ answers: z
56
+ .object({
57
+ model: AiDecideChoiceAnswerSchema,
58
+ })
59
+ .passthrough(),
60
+ })
61
+ .passthrough(),
62
+ metadata: z.object({ version: z.string() }).passthrough().optional(),
63
+ })
64
+ .passthrough();
65
+ /** Select the best sufficient live foundation model through Databricks `ai_decide`. */
66
+ export class AiDecideRouterService {
67
+ invoke;
68
+ probeStore;
69
+ context = new SmartRouterContextBuilder();
70
+ probes = new WeakMap();
71
+ probeCaches = new Set();
72
+ constructor(invoke = invokeAiDecide, probeStore = new AppKitSmartRouterProbeStore()) {
73
+ this.invoke = invoke;
74
+ this.probeStore = probeStore;
75
+ }
76
+ async select(input, endpoints, client = undefined, options = {}) {
77
+ const workspaceClient = client ?? getExecutionContext().client;
78
+ const strategy = AiDecideStrategySchema.parse(options.strategy ?? "balanced");
79
+ const filters = AiDecideModelFiltersSchema.parse(options.filters ?? {});
80
+ const candidates = modelCandidates(endpoints, filters);
81
+ if (candidates.length === 0) {
82
+ throw new AiDecideRouterError(400, "No eligible foundation models are available");
83
+ }
84
+ if (candidates.length === 1) {
85
+ const [endpoint] = candidates;
86
+ return {
87
+ endpoint: endpoint,
88
+ observation: AiDecideObservationSchema.parse({
89
+ selectedModel: endpoint.name,
90
+ strategy,
91
+ confidence: 1,
92
+ probabilities: { [endpoint.name]: 1 },
93
+ latencyMs: 0,
94
+ }),
95
+ };
96
+ }
97
+ const context = await this.context.analyze(input);
98
+ if (!context.task) {
99
+ throw new AiDecideRouterError(400, "ai_decide input contains no routable text");
100
+ }
101
+ const currentRequest = [...context.events]
102
+ .reverse()
103
+ .find((event) => event.role === "user")?.text;
104
+ const currentTask = currentRequest ?? context.task;
105
+ const taskComplexityBody = {
106
+ state: {
107
+ task: currentTask,
108
+ current_request: currentTask,
109
+ },
110
+ questions: {
111
+ task_complexity: {
112
+ type: "choice",
113
+ instructions: "Classify the current request only. Choose advanced when a complete answer needs dependencies, configuration, APIs, and multiple code artifacts; architecture, debugging, or several interacting constraints. Choose standard for a focused implementation or analysis with limited moving parts. Choose simple only for short factual, creative, formatting, or explanation requests.",
114
+ criteria: {
115
+ simple: "One direct answer or artifact with little reasoning or implementation risk.",
116
+ standard: "Focused implementation or analysis with limited interacting requirements.",
117
+ advanced: "Multiple implementation artifacts or interacting technical constraints where completeness and correctness require stronger reasoning.",
118
+ },
119
+ },
120
+ },
121
+ options: { version: "1.0" },
122
+ };
123
+ const buildDecision = (decisionCandidates, taskComplexity) => {
124
+ const labels = new Map(decisionCandidates.map((endpoint, index) => [`model_${index + 1}`, endpoint]));
125
+ const criteria = Object.fromEntries([...labels].map(([label, endpoint], index) => [
126
+ label,
127
+ candidateDescription(endpoint, index + 1),
128
+ ]));
129
+ return {
130
+ labels,
131
+ body: {
132
+ state: {
133
+ task: currentTask,
134
+ current_request: currentTask,
135
+ ...(context.events.length > 1 ? { conversation_context: context.task } : {}),
136
+ conversation_turns: context.events.filter((event) => event.role === "user").length,
137
+ context_tokens: context.tokenCount,
138
+ completion_requirement: "The selected model must answer the current request accurately and completely in one response. Partial or truncated output is insufficient.",
139
+ task_complexity: taskComplexity,
140
+ strategy,
141
+ candidates: decisionCandidates.map((endpoint, index) => candidateState(endpoint, index + 1)),
142
+ },
143
+ questions: {
144
+ model: {
145
+ type: "choice",
146
+ instructions: `${strategyInstructions(strategy)} The task has already been classified as ${taskComplexity}.`,
147
+ criteria,
148
+ },
149
+ },
150
+ options: { version: "1.0" },
151
+ },
152
+ };
153
+ };
154
+ const startedAt = performance.now();
155
+ const signal = options.signal ?? new AbortController().signal;
156
+ let decision;
157
+ let response;
158
+ try {
159
+ const taskComplexity = AiDecideTaskComplexityResponseSchema.parse(await this.invoke(workspaceClient, taskComplexityBody, signal, options.timeoutMs ?? DEFAULT_TIMEOUT_MS)).response.answers.task_complexity.choice;
160
+ decision = buildDecision(sufficientCandidates(candidates, taskComplexity), taskComplexity);
161
+ response = AiDecideModelResponseSchema.parse(await this.invoke(workspaceClient, decision.body, signal, options.timeoutMs ?? DEFAULT_TIMEOUT_MS));
162
+ this.setProbeValue(workspaceClient, true);
163
+ }
164
+ catch (error) {
165
+ this.setProbeValue(workspaceClient, false);
166
+ throw error;
167
+ }
168
+ const answer = response.response.answers.model;
169
+ const selected = decision.labels.get(answer.choice);
170
+ if (!selected) {
171
+ throw new AiDecideRouterError(502, `ai_decide selected unknown candidate ${answer.choice}`);
172
+ }
173
+ const probabilities = answer.probabilities
174
+ ? Object.fromEntries(Object.entries(answer.probabilities).flatMap(([label, probability]) => {
175
+ const endpoint = decision.labels.get(label);
176
+ return endpoint ? [[endpoint.name, probability]] : [];
177
+ }))
178
+ : undefined;
179
+ return {
180
+ endpoint: selected,
181
+ observation: AiDecideObservationSchema.parse({
182
+ selectedModel: selected.name,
183
+ strategy,
184
+ ...(answer.confidence !== undefined ? { confidence: answer.confidence } : {}),
185
+ ...(probabilities && Object.keys(probabilities).length > 0 ? { probabilities } : {}),
186
+ latencyMs: Math.round(performance.now() - startedAt),
187
+ }),
188
+ };
189
+ }
190
+ /** Probe and memoize whether the active workspace identity can call `ai_decide`. */
191
+ async isEnabled(endpoints, client = undefined) {
192
+ if (modelCandidates(endpoints, AiDecideModelFiltersSchema.parse({})).length < 2) {
193
+ return false;
194
+ }
195
+ let workspaceClient;
196
+ try {
197
+ workspaceClient = client ?? getExecutionContext().client;
198
+ }
199
+ catch {
200
+ return false;
201
+ }
202
+ const cache = this.probeCache(workspaceClient);
203
+ const probe = await getOrSet(cache, PROBE_KEY, () => this.loadProbe(endpoints, workspaceClient), {
204
+ ttl: PROBE_CACHE_TTL_MS,
205
+ refreshAfterWrite: (value) => this.probeTtl(value.enabled),
206
+ });
207
+ return probe?.enabled ?? false;
208
+ }
209
+ /** Stop process-local probe caches after active refreshes settle. */
210
+ dispose() {
211
+ for (const cache of this.probeCaches)
212
+ void closeCache(cache);
213
+ this.probeCaches.clear();
214
+ }
215
+ async loadProbe(endpoints, client) {
216
+ const stored = await this.readStoredProbe(client);
217
+ if (stored && stored.expiresAt > Date.now())
218
+ return stored;
219
+ const enabled = await this.select("Choose the lowest-latency sufficient model for a one-sentence factual answer.", endpoints, client, { strategy: "latency", timeoutMs: DEFAULT_TIMEOUT_MS })
220
+ .then(() => true)
221
+ .catch((error) => {
222
+ logger.debug("ai_decide capability probe unavailable", { error: toError(error) });
223
+ return false;
224
+ });
225
+ const probe = this.probeRecord(enabled);
226
+ await this.writeStoredProbe(probe, client);
227
+ return probe;
228
+ }
229
+ setProbeValue(client, enabled) {
230
+ const probe = this.probeRecord(enabled);
231
+ void this.writeProcessProbe(this.probeCache(client), probe);
232
+ void this.writeStoredProbe(probe, client);
233
+ }
234
+ probeRecord(enabled) {
235
+ return { enabled, expiresAt: Date.now() + this.probeTtl(enabled) };
236
+ }
237
+ probeTtl(enabled) {
238
+ return enabled ? POSITIVE_PROBE_TTL_MS : NEGATIVE_PROBE_TTL_MS;
239
+ }
240
+ async readStoredProbe(client) {
241
+ try {
242
+ const parsed = SmartRouterProbeRecordSchema.safeParse(await this.probeStore.get(PROBE_KEY, client));
243
+ return parsed.success ? parsed.data : undefined;
244
+ }
245
+ catch (error) {
246
+ logger.debug("ai_decide probe cache read failed", { error: toError(error) });
247
+ return undefined;
248
+ }
249
+ }
250
+ async writeProcessProbe(cache, probe) {
251
+ try {
252
+ await cache.set(PROBE_KEY, probe, { ttl: PROBE_CACHE_TTL_MS });
253
+ }
254
+ catch (error) {
255
+ logger.debug("ai_decide process probe cache write failed", { error: toError(error) });
256
+ }
257
+ }
258
+ async writeStoredProbe(probe, client) {
259
+ try {
260
+ await this.probeStore.set(PROBE_KEY, probe, Math.max(1, Math.ceil(PROBE_CACHE_TTL_MS / 1_000)), client);
261
+ }
262
+ catch (error) {
263
+ logger.debug("ai_decide probe cache write failed", { error: toError(error) });
264
+ }
265
+ }
266
+ probeCache(client) {
267
+ const owner = client.config && typeof client.config === "object" ? client.config : client;
268
+ let cache = this.probes.get(owner);
269
+ if (!cache) {
270
+ cache = createCache({ maxEntries: 1, useClone: false });
271
+ this.probes.set(owner, cache);
272
+ this.probeCaches.add(cache);
273
+ }
274
+ return cache;
275
+ }
276
+ }
277
+ /** HTTP failure returned by the Databricks AI Functions router. */
278
+ export class AiDecideRouterError extends Error {
279
+ status;
280
+ constructor(status, message) {
281
+ super(message);
282
+ this.status = status;
283
+ this.name = "AiDecideRouterError";
284
+ }
285
+ }
286
+ function modelCandidates(endpoints, filters) {
287
+ const families = filters.families?.map((family) => family.toLowerCase());
288
+ return selection
289
+ .lookupModels(endpoints, {
290
+ ...(filters.modelClass ? { modelClass: filters.modelClass } : {}),
291
+ modelSource: filters.modelSource,
292
+ ...(filters.requiresTools !== undefined ? { requiresTools: filters.requiresTools } : {}),
293
+ ...(filters.requiresStructuredOutput !== undefined
294
+ ? { requiresStructuredOutput: filters.requiresStructuredOutput }
295
+ : {}),
296
+ limit: filters.maxCandidates,
297
+ }, { preferSystemModels: true })
298
+ .map(({ endpoint }) => endpoint)
299
+ .filter((endpoint) => !families || (endpoint.family && families.includes(endpoint.family.toLowerCase())));
300
+ }
301
+ function sufficientCandidates(candidates, taskComplexity) {
302
+ const classOrder = {
303
+ simple: [ModelClass.ChatFast, ModelClass.ChatBalanced, ModelClass.ChatThinking],
304
+ standard: [ModelClass.ChatBalanced, ModelClass.ChatThinking, ModelClass.ChatFast],
305
+ advanced: [ModelClass.ChatThinking, ModelClass.ChatBalanced, ModelClass.ChatFast],
306
+ }[taskComplexity];
307
+ for (const modelClass of classOrder) {
308
+ const sufficient = candidates.filter((endpoint) => endpoint.class === modelClass);
309
+ if (sufficient.length > 0)
310
+ return sufficient;
311
+ }
312
+ return [...candidates];
313
+ }
314
+ function candidateState(endpoint, rank) {
315
+ const capabilities = endpointCapabilities(endpoint);
316
+ return {
317
+ id: endpoint.name,
318
+ rank,
319
+ display_name: endpoint.displayName,
320
+ family: endpoint.family,
321
+ version: versionTuple(endpoint.name),
322
+ class: endpoint.class,
323
+ profile: endpoint.profile,
324
+ benchmarks: candidateBenchmarks(endpoint),
325
+ capabilities: {
326
+ chat: capabilities.chat,
327
+ tools: capabilities.tools,
328
+ structured_output: endpoint.supportsStructuredOutput === true,
329
+ reasoning_efforts: endpoint.reasoningEfforts ?? [],
330
+ },
331
+ };
332
+ }
333
+ function candidateDescription(endpoint, rank) {
334
+ const benchmarks = candidateBenchmarks(endpoint);
335
+ return {
336
+ model: endpoint.name,
337
+ rank,
338
+ family: endpoint.family ?? null,
339
+ version: versionTuple(endpoint.name),
340
+ capability_class: endpoint.class ?? null,
341
+ quality_score: endpoint.profile?.quality ?? null,
342
+ speed_score: endpoint.profile?.speed ?? null,
343
+ cost_score: endpoint.profile?.cost ?? null,
344
+ measured_quality_percentile: benchmarks.quality_percentile,
345
+ normalized_response_time_ms: benchmarks.normalized_response_time_ms,
346
+ time_to_first_token_ms: benchmarks.time_to_first_token_ms,
347
+ output_tokens_per_second: benchmarks.output_tokens_per_second,
348
+ supports_tools: endpointCapabilities(endpoint).tools,
349
+ supports_structured_output: endpoint.supportsStructuredOutput === true,
350
+ reasoning_efforts: endpoint.reasoningEfforts ?? [],
351
+ };
352
+ }
353
+ function candidateBenchmarks(endpoint) {
354
+ const metadata = modelMetadataFor(endpoint);
355
+ return {
356
+ quality_percentile: metadata.rating?.score ?? null,
357
+ normalized_response_time_ms: metadata.latencyScore?.score ?? null,
358
+ time_to_first_token_ms: metadata.latencyScore?.measurements.timeToFirstTokenMs ?? null,
359
+ output_tokens_per_second: metadata.latencyScore?.measurements.outputTokensPerSecond ?? null,
360
+ successful_run_count: metadata.latencyScore?.measurements.successfulRunCount ?? null,
361
+ };
362
+ }
363
+ function strategyInstructions(strategy) {
364
+ const objective = {
365
+ balanced: "Choose the smallest and least expensive model that is still likely to answer the task accurately and completely.",
366
+ quality: "Choose the model most likely to produce the highest-quality correct answer.",
367
+ cost: "Choose the lowest-cost model that is still sufficient for the task. Keep premier and newer unscored models eligible when they are materially more likely to complete the request correctly. When candidates have similar expected answer quality and completeness, prefer lower cost over lower latency.",
368
+ latency: "Choose the fastest model that is still sufficient for the task.",
369
+ }[strategy];
370
+ return `${objective} Judge current_request as the work that must be completed now; use task only as conversation context, and do not let simpler earlier turns reduce the current request's difficulty. A model is sufficient only if it is likely to produce a complete, correct answer in one response. Treat partial or truncated output as insufficient. Software implementation that requires dependencies, configuration, APIs, and multiple code artifacts needs materially more quality than a short explanation, even when the request itself is concise. Optimize for the selected strategy only among sufficient candidates. Use the supplied rank, version, capability class, quality, measured latency, throughput, cost, tool, structured-output, family, and reasoning metadata. Lower normalized_response_time_ms and time_to_first_token_ms are faster; higher output_tokens_per_second and measured_quality_percentile are better. Treat a newer unscored model as potentially stronger than an older scored predecessor rather than penalizing missing profile scores. Prefer simpler models for genuinely simple requests and reserve stronger models for implementation, multi-constraint reasoning, architecture, and debugging.`;
371
+ }
372
+ async function invokeAiDecide(client, body, signal, timeoutMs) {
373
+ const host = (await client.config.getHost()).toString();
374
+ const url = new URL(AI_DECIDE_PATH, host);
375
+ const headers = new Headers({ "content-type": "application/json" });
376
+ await client.config.authenticate(headers);
377
+ const combinedSignal = AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]);
378
+ let response = await fetch(url, {
379
+ method: "POST",
380
+ headers,
381
+ body: JSON.stringify(body),
382
+ signal: combinedSignal,
383
+ });
384
+ if (response.status === 401 && (await refreshWorkspaceClientAuthentication(client))) {
385
+ await response.body?.cancel();
386
+ headers.delete("authorization");
387
+ headers.delete("x-databricks-workspace-id");
388
+ await client.config.authenticate(headers);
389
+ response = await fetch(url, {
390
+ method: "POST",
391
+ headers,
392
+ body: JSON.stringify(body),
393
+ signal: combinedSignal,
394
+ });
395
+ }
396
+ if (!response.ok) {
397
+ const detail = (await response.text().catch(() => "")).trim().slice(0, 500);
398
+ throw new AiDecideRouterError(response.status, `Databricks ai_decide failed with HTTP ${response.status}${detail ? `: ${detail}` : ""}`);
399
+ }
400
+ const value = (await response.json());
401
+ if (isRecord(value) && typeof value.error_message === "string" && value.error_message) {
402
+ throw new AiDecideRouterError(502, value.error_message);
403
+ }
404
+ return value;
405
+ }
406
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWktZGVjaWRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FpLWRlY2lkZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBRUgsT0FBTyxFQUFFLG1CQUFtQixFQUF3QixNQUFNLG9CQUFvQixDQUFDO0FBQy9FLE9BQU8sRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxvQ0FBb0MsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzdFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxnQkFBZ0IsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbkcsT0FBTyxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDaEUsT0FBTyxFQUFFLFVBQVUsRUFBK0IsTUFBTSx5QkFBeUIsQ0FBQztBQUNsRixPQUFPLEVBQ0wsMEJBQTBCLEVBQzFCLHlCQUF5QixFQUN6QixzQkFBc0IsR0FLdkIsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6QyxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRXhCLE9BQU8sRUFDTCwyQkFBMkIsRUFDM0IseUJBQXlCLEVBQ3pCLDRCQUE0QixHQUc3QixNQUFNLG1CQUFtQixDQUFDO0FBRTNCLE1BQU0sY0FBYyxHQUFHLGlDQUFpQyxDQUFDO0FBQ3pELE1BQU0sa0JBQWtCLEdBQUcsTUFBTSxDQUFDO0FBQ2xDLE1BQU0sU0FBUyxHQUFHLGNBQWMsQ0FBQztBQUNqQyxNQUFNLHFCQUFxQixHQUFHLENBQUMsR0FBRyxNQUFNLENBQUM7QUFDekMsTUFBTSxxQkFBcUIsR0FBRyxNQUFNLENBQUM7QUFDckMsTUFBTSxrQkFBa0IsR0FBRyxxQkFBcUIsR0FBRyxDQUFDLENBQUM7QUFDckQsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0s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QUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzVFLE1BQU0sSUFBSSxtQkFBbUIsQ0FDM0IsUUFBUSxDQUFDLE1BQU0sRUFDZix5Q0FBeUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUN6RixDQUFDO0lBQ0osQ0FBQztJQUNELE1BQU0sS0FBSyxHQUFHLENBQUMsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQVksQ0FBQztJQUNqRCxJQUFJLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxPQUFPLEtBQUssQ0FBQyxhQUFhLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUN0RixNQUFNLElBQUksbUJBQW1CLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUMxRCxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBEYXRhYnJpY2tzIEFJIEZ1bmN0aW9ucyBgYWlfZGVjaWRlYCBtb2RlbCBzZWxlY3Rpb24uXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IGdldEV4ZWN1dGlvbkNvbnRleHQsIHR5cGUgV29ya3NwYWNlQ2xpZW50IH0gZnJvbSBcIkBkYXRhYnJpY2tzL2FwcGtpdFwiO1xuaW1wb3J0IHsgY2xvc2VDYWNoZSwgY3JlYXRlQ2FjaGUsIGdldE9yU2V0IH0gZnJvbSBcIkBkYngtdG9vbHMvY2FjaGVcIjtcbmltcG9ydCB7IHJlZnJlc2hXb3Jrc3BhY2VDbGllbnRBdXRoZW50aWNhdGlvbiB9IGZyb20gXCJAZGJ4LXRvb2xzL2RhdGFicmlja3NcIjtcbmltcG9ydCB7IGVuZHBvaW50Q2FwYWJpbGl0aWVzLCBtb2RlbE1ldGFkYXRhRm9yLCBzZWxlY3Rpb24sIHZlcnNpb25UdXBsZSB9IGZyb20gXCJAZGJ4LXRvb2xzL21vZGVsXCI7XG5pbXBvcnQgeyBpc1JlY29yZCwgbG9nLCB0b0Vycm9yIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB7IE1vZGVsQ2xhc3MsIHR5cGUgU2VydmluZ0VuZHBvaW50U3VtbWFyeSB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1tb2RlbFwiO1xuaW1wb3J0IHtcbiAgQWlEZWNpZGVNb2RlbEZpbHRlcnNTY2hlbWEsXG4gIEFpRGVjaWRlT2JzZXJ2YXRpb25TY2hlbWEsXG4gIEFpRGVjaWRlU3RyYXRlZ3lTY2hlbWEsXG4gIHR5cGUgQWlEZWNpZGVNb2RlbEZpbHRlcnMsXG4gIHR5cGUgQWlEZWNpZGVPYnNlcnZhdGlvbixcbiAgdHlwZSBBaURlY2lkZVN0cmF0ZWd5LFxuICB0eXBlIFJlc29sdmVkQWlEZWNpZGVNb2RlbEZpbHRlcnMsXG59IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1tb2RlbC1nYXRld2F5XCI7XG5pbXBvcnQgeyB6IH0gZnJvbSBcInpvZFwiO1xuXG5pbXBvcnQge1xuICBBcHBLaXRTbWFydFJvdXRlclByb2JlU3RvcmUsXG4gIFNtYXJ0Um91dGVyQ29udGV4dEJ1aWxkZXIsXG4gIFNtYXJ0Um91dGVyUHJvYmVSZWNvcmRTY2hlbWEsXG4gIHR5cGUgU21hcnRSb3V0ZXJQcm9iZVJlY29yZCxcbiAgdHlwZSBTbWFydFJvdXRlclByb2JlU3RvcmUsXG59IGZyb20gXCIuL3NtYXJ0LXJvdXRlci50c1wiO1xuXG5jb25zdCBBSV9ERUNJREVfUEFUSCA9IFwiL2FwaS8yLjAvYWktZnVuY3Rpb25zL2FpLWRlY2lkZVwiO1xuY29uc3QgREVGQVVMVF9USU1FT1VUX01TID0gMTBfMDAwO1xuY29uc3QgUFJPQkVfS0VZID0gXCJhaS1kZWNpZGUtdjFcIjtcbmNvbnN0IFBPU0lUSVZFX1BST0JFX1RUTF9NUyA9IDUgKiA2MF8wMDA7XG5jb25zdCBORUdBVElWRV9QUk9CRV9UVExfTVMgPSAzMF8wMDA7XG5jb25zdCBQUk9CRV9DQUNIRV9UVExfTVMgPSBQT1NJVElWRV9QUk9CRV9UVExfTVMgKiAyO1xuY29uc3QgbG9nZ2VyID0gbG9nLmxvZ2dlcihcImFwcGtpdC9tb2RlbC1nYXRld2F5L2FpLWRlY2lkZVwiKTtcblxuY29uc3QgQWlEZWNpZGVDaG9pY2VBbnN3ZXJTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIHR5cGU6IHoubGl0ZXJhbChcImNob2ljZVwiKSxcbiAgICBjaG9pY2U6IHouc3RyaW5nKCkudHJpbSgpLm1pbigxKSxcbiAgICBwcm9iYWJpbGl0aWVzOiB6LnJlY29yZCh6LnN0cmluZygpLCB6Lm51bWJlcigpLm1pbigwKS5tYXgoMSkpLm9wdGlvbmFsKCksXG4gICAgY29uZmlkZW5jZTogei5udW1iZXIoKS5taW4oMCkubWF4KDEpLm9wdGlvbmFsKCksXG4gIH0pXG4gIC5wYXNzdGhyb3VnaCgpO1xuXG5jb25zdCBBaURlY2lkZVRhc2tDb21wbGV4aXR5U2NoZW1hID0gei5lbnVtKFtcInNpbXBsZVwiLCBcInN0YW5kYXJkXCIsIFwiYWR2YW5jZWRcIl0pO1xuXG5jb25zdCBBaURlY2lkZVRhc2tDb21wbGV4aXR5QW5zd2VyU2NoZW1hID0gelxuICAub2JqZWN0KHtcbiAgICB0eXBlOiB6LmxpdGVyYWwoXCJjaG9pY2VcIiksXG4gICAgY2hvaWNlOiBBaURlY2lkZVRhc2tDb21wbGV4aXR5U2NoZW1hLFxuICB9KVxuICAucGFzc3Rocm91Z2goKTtcblxuY29uc3QgQWlEZWNpZGVUYXNrQ29tcGxleGl0eVJlc3BvbnNlU2NoZW1hID0gelxuICAub2JqZWN0KHtcbiAgICByZXNwb25zZTogelxuICAgICAgLm9iamVjdCh7XG4gICAgICAgIGFuc3dlcnM6IHpcbiAgICAgICAgICAub2JqZWN0KHtcbiAgICAgICAgICAgIHRhc2tfY29tcGxleGl0eTogQWlEZWNpZGVUYXNrQ29tcGxleGl0eUFuc3dlclNjaGVtYSxcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5wYXNzdGhyb3VnaCgpLFxuICAgICAgfSlcbiAgICAgIC5wYXNzdGhyb3VnaCgpLFxuICAgIG1ldGFkYXRhOiB6Lm9iamVjdCh7IHZlcnNpb246IHouc3RyaW5nKCkgfSkucGFzc3Rocm91Z2goKS5vcHRpb25hbCgpLFxuICB9KVxuICAucGFzc3Rocm91Z2goKTtcblxuY29uc3QgQWlEZWNpZGVNb2RlbFJlc3BvbnNlU2NoZW1hID0gelxuICAub2JqZWN0KHtcbiAgICByZXNwb25zZTogelxuICAgICAgLm9iamVjdCh7XG4gICAgICAgIGFuc3dlcnM6IHpcbiAgICAgICAgICAub2JqZWN0KHtcbiAgICAgICAgICAgIG1vZGVsOiBBaURlY2lkZUNob2ljZUFuc3dlclNjaGVtYSxcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5wYXNzdGhyb3VnaCgpLFxuICAgICAgfSlcbiAgICAgIC5wYXNzdGhyb3VnaCgpLFxuICAgIG1ldGFkYXRhOiB6Lm9iamVjdCh7IHZlcnNpb246IHouc3RyaW5nKCkgfSkucGFzc3Rocm91Z2goKS5vcHRpb25hbCgpLFxuICB9KVxuICAucGFzc3Rocm91Z2goKTtcblxuLyoqIFNlbGVjdGlvbiBwb2xpY3kgYWNjZXB0ZWQgYnkge0BsaW5rIEFpRGVjaWRlUm91dGVyU2VydmljZS5zZWxlY3R9LiAqL1xuZXhwb3J0IGludGVyZmFjZSBBaURlY2lkZVNlbGVjdGlvbk9wdGlvbnMge1xuICByZWFkb25seSBzdHJhdGVneT86IEFpRGVjaWRlU3RyYXRlZ3k7XG4gIHJlYWRvbmx5IGZpbHRlcnM/OiBBaURlY2lkZU1vZGVsRmlsdGVycztcbiAgcmVhZG9ubHkgc2lnbmFsPzogQWJvcnRTaWduYWw7XG4gIHJlYWRvbmx5IHRpbWVvdXRNcz86IG51bWJlcjtcbn1cblxuLyoqIENvbmNyZXRlIGVuZHBvaW50IGFuZCBvYnNlcnZhYmxlIGRlY2lzaW9uIHJldHVybmVkIGJ5IGBhaV9kZWNpZGVgLiAqL1xuZXhwb3J0IGludGVyZmFjZSBBaURlY2lkZVNlbGVjdGlvbiB7XG4gIHJlYWRvbmx5IGVuZHBvaW50OiBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5O1xuICByZWFkb25seSBvYnNlcnZhdGlvbjogQWlEZWNpZGVPYnNlcnZhdGlvbjtcbn1cblxudHlwZSBBaURlY2lkZUludm9rZXIgPSAoXG4gIGNsaWVudDogV29ya3NwYWNlQ2xpZW50LFxuICBib2R5OiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4sXG4gIHNpZ25hbDogQWJvcnRTaWduYWwsXG4gIHRpbWVvdXRNczogbnVtYmVyLFxuKSA9PiBQcm9taXNlPHVua25vd24+O1xuXG50eXBlIEFpRGVjaWRlUHJvYmVDYWNoZSA9IFJldHVyblR5cGU8dHlwZW9mIGNyZWF0ZUNhY2hlPjtcblxuLyoqIFNlbGVjdCB0aGUgYmVzdCBzdWZmaWNpZW50IGxpdmUgZm91bmRhdGlvbiBtb2RlbCB0aHJvdWdoIERhdGFicmlja3MgYGFpX2RlY2lkZWAuICovXG5leHBvcnQgY2xhc3MgQWlEZWNpZGVSb3V0ZXJTZXJ2aWNlIHtcbiAgcHJpdmF0ZSByZWFkb25seSBjb250ZXh0ID0gbmV3IFNtYXJ0Um91dGVyQ29udGV4dEJ1aWxkZXIoKTtcbiAgcHJpdmF0ZSByZWFkb25seSBwcm9iZXMgPSBuZXcgV2Vha01hcDxvYmplY3QsIEFpRGVjaWRlUHJvYmVDYWNoZT4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBwcm9iZUNhY2hlcyA9IG5ldyBTZXQ8QWlEZWNpZGVQcm9iZUNhY2hlPigpO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgaW52b2tlOiBBaURlY2lkZUludm9rZXIgPSBpbnZva2VBaURlY2lkZSxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHByb2JlU3RvcmU6IFNtYXJ0Um91dGVyUHJvYmVTdG9yZSA9IG5ldyBBcHBLaXRTbWFydFJvdXRlclByb2JlU3RvcmUoKSxcbiAgKSB7fVxuXG4gIGFzeW5jIHNlbGVjdChcbiAgICBpbnB1dDogdW5rbm93bixcbiAgICBlbmRwb2ludHM6IHJlYWRvbmx5IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSxcbiAgICBjbGllbnQ6IFdvcmtzcGFjZUNsaWVudCB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZCxcbiAgICBvcHRpb25zOiBBaURlY2lkZVNlbGVjdGlvbk9wdGlvbnMgPSB7fSxcbiAgKTogUHJvbWlzZTxBaURlY2lkZVNlbGVjdGlvbj4ge1xuICAgIGNvbnN0IHdvcmtzcGFjZUNsaWVudCA9IGNsaWVudCA/PyBnZXRFeGVjdXRpb25Db250ZXh0KCkuY2xpZW50O1xuICAgIGNvbnN0IHN0cmF0ZWd5ID0gQWlEZWNpZGVTdHJhdGVneVNjaGVtYS5wYXJzZShvcHRpb25zLnN0cmF0ZWd5ID8/IFwiYmFsYW5jZWRcIik7XG4gICAgY29uc3QgZmlsdGVycyA9IEFpRGVjaWRlTW9kZWxGaWx0ZXJzU2NoZW1hLnBhcnNlKG9wdGlvbnMuZmlsdGVycyA/PyB7fSk7XG4gICAgY29uc3QgY2FuZGlkYXRlcyA9IG1vZGVsQ2FuZGlkYXRlcyhlbmRwb2ludHMsIGZpbHRlcnMpO1xuICAgIGlmIChjYW5kaWRhdGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEFpRGVjaWRlUm91dGVyRXJyb3IoNDAwLCBcIk5vIGVsaWdpYmxlIGZvdW5kYXRpb24gbW9kZWxzIGFyZSBhdmFpbGFibGVcIik7XG4gICAgfVxuICAgIGlmIChjYW5kaWRhdGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgY29uc3QgW2VuZHBvaW50XSA9IGNhbmRpZGF0ZXM7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBlbmRwb2ludDogZW5kcG9pbnQhLFxuICAgICAgICBvYnNlcnZhdGlvbjogQWlEZWNpZGVPYnNlcnZhdGlvblNjaGVtYS5wYXJzZSh7XG4gICAgICAgICAgc2VsZWN0ZWRNb2RlbDogZW5kcG9pbnQhLm5hbWUsXG4gICAgICAgICAgc3RyYXRlZ3ksXG4gICAgICAgICAgY29uZmlkZW5jZTogMSxcbiAgICAgICAgICBwcm9iYWJpbGl0aWVzOiB7IFtlbmRwb2ludCEubmFtZV06IDEgfSxcbiAgICAgICAgICBsYXRlbmN5TXM6IDAsXG4gICAgICAgIH0pLFxuICAgICAgfTtcbiAgICB9XG4gICAgY29uc3QgY29udGV4dCA9IGF3YWl0IHRoaXMuY29udGV4dC5hbmFseXplKGlucHV0KTtcbiAgICBpZiAoIWNvbnRleHQudGFzaykge1xuICAgICAgdGhyb3cgbmV3IEFpRGVjaWRlUm91dGVyRXJyb3IoNDAwLCBcImFpX2RlY2lkZSBpbnB1dCBjb250YWlucyBubyByb3V0YWJsZSB0ZXh0XCIpO1xuICAgIH1cbiAgICBjb25zdCBjdXJyZW50UmVxdWVzdCA9IFsuLi5jb250ZXh0LmV2ZW50c11cbiAgICAgIC5yZXZlcnNlKClcbiAgICAgIC5maW5kKChldmVudCkgPT4gZXZlbnQucm9sZSA9PT0gXCJ1c2VyXCIpPy50ZXh0O1xuICAgIGNvbnN0IGN1cnJlbnRUYXNrID0gY3VycmVudFJlcXVlc3QgPz8gY29udGV4dC50YXNrO1xuICAgIGNvbnN0IHRhc2tDb21wbGV4aXR5Qm9keSA9IHtcbiAgICAgIHN0YXRlOiB7XG4gICAgICAgIHRhc2s6IGN1cnJlbnRUYXNrLFxuICAgICAgICBjdXJyZW50X3JlcXVlc3Q6IGN1cnJlbnRUYXNrLFxuICAgICAgfSxcbiAgICAgIHF1ZXN0aW9uczoge1xuICAgICAgICB0YXNrX2NvbXBsZXhpdHk6IHtcbiAgICAgICAgICB0eXBlOiBcImNob2ljZVwiIGFzIGNvbnN0LFxuICAgICAgICAgIGluc3RydWN0aW9uczpcbiAgICAgICAgICAgIFwiQ2xhc3NpZnkgdGhlIGN1cnJlbnQgcmVxdWVzdCBvbmx5LiBDaG9vc2UgYWR2YW5jZWQgd2hlbiBhIGNvbXBsZXRlIGFuc3dlciBuZWVkcyBkZXBlbmRlbmNpZXMsIGNvbmZpZ3VyYXRpb24sIEFQSXMsIGFuZCBtdWx0aXBsZSBjb2RlIGFydGlmYWN0czsgYXJjaGl0ZWN0dXJlLCBkZWJ1Z2dpbmcsIG9yIHNldmVyYWwgaW50ZXJhY3RpbmcgY29uc3RyYWludHMuIENob29zZSBzdGFuZGFyZCBmb3IgYSBmb2N1c2VkIGltcGxlbWVudGF0aW9uIG9yIGFuYWx5c2lzIHdpdGggbGltaXRlZCBtb3ZpbmcgcGFydHMuIENob29zZSBzaW1wbGUgb25seSBmb3Igc2hvcnQgZmFjdHVhbCwgY3JlYXRpdmUsIGZvcm1hdHRpbmcsIG9yIGV4cGxhbmF0aW9uIHJlcXVlc3RzLlwiLFxuICAgICAgICAgIGNyaXRlcmlhOiB7XG4gICAgICAgICAgICBzaW1wbGU6IFwiT25lIGRpcmVjdCBhbnN3ZXIgb3IgYXJ0aWZhY3Qgd2l0aCBsaXR0bGUgcmVhc29uaW5nIG9yIGltcGxlbWVudGF0aW9uIHJpc2suXCIsXG4gICAgICAgICAgICBzdGFuZGFyZDogXCJGb2N1c2VkIGltcGxlbWVudGF0aW9uIG9yIGFuYWx5c2lzIHdpdGggbGltaXRlZCBpbnRlcmFjdGluZyByZXF1aXJlbWVudHMuXCIsXG4gICAgICAgICAgICBhZHZhbmNlZDpcbiAgICAgICAgICAgICAgXCJNdWx0aXBsZSBpbXBsZW1lbnRhdGlvbiBhcnRpZmFjdHMgb3IgaW50ZXJhY3RpbmcgdGVjaG5pY2FsIGNvbnN0cmFpbnRzIHdoZXJlIGNvbXBsZXRlbmVzcyBhbmQgY29ycmVjdG5lc3MgcmVxdWlyZSBzdHJvbmdlciByZWFzb25pbmcuXCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICBvcHRpb25zOiB7IHZlcnNpb246IFwiMS4wXCIgfSxcbiAgICB9O1xuICAgIGNvbnN0IGJ1aWxkRGVjaXNpb24gPSAoXG4gICAgICBkZWNpc2lvbkNhbmRpZGF0ZXM6IHJlYWRvbmx5IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSxcbiAgICAgIHRhc2tDb21wbGV4aXR5OiB6LmluZmVyPHR5cGVvZiBBaURlY2lkZVRhc2tDb21wbGV4aXR5U2NoZW1hPixcbiAgICApID0+IHtcbiAgICAgIGNvbnN0IGxhYmVscyA9IG5ldyBNYXAoXG4gICAgICAgIGRlY2lzaW9uQ2FuZGlkYXRlcy5tYXAoKGVuZHBvaW50LCBpbmRleCkgPT4gW2Btb2RlbF8ke2luZGV4ICsgMX1gLCBlbmRwb2ludF0pLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IGNyaXRlcmlhID0gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgICBbLi4ubGFiZWxzXS5tYXAoKFtsYWJlbCwgZW5kcG9pbnRdLCBpbmRleCkgPT4gW1xuICAgICAgICAgIGxhYmVsLFxuICAgICAgICAgIGNhbmRpZGF0ZURlc2NyaXB0aW9uKGVuZHBvaW50LCBpbmRleCArIDEpLFxuICAgICAgICBdKSxcbiAgICAgICk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBsYWJlbHMsXG4gICAgICAgIGJvZHk6IHtcbiAgICAgICAgICBzdGF0ZToge1xuICAgICAgICAgICAgdGFzazogY3VycmVudFRhc2ssXG4gICAgICAgICAgICBjdXJyZW50X3JlcXVlc3Q6IGN1cnJlbnRUYXNrLFxuICAgICAgICAgICAgLi4uKGNvbnRleHQuZXZlbnRzLmxlbmd0aCA+IDEgPyB7IGNvbnZlcnNhdGlvbl9jb250ZXh0OiBjb250ZXh0LnRhc2sgfSA6IHt9KSxcbiAgICAgICAgICAgIGNvbnZlcnNhdGlvbl90dXJuczogY29udGV4dC5ldmVudHMuZmlsdGVyKChldmVudCkgPT4gZXZlbnQucm9sZSA9PT0gXCJ1c2VyXCIpLmxlbmd0aCxcbiAgICAgICAgICAgIGNvbnRleHRfdG9rZW5zOiBjb250ZXh0LnRva2VuQ291bnQsXG4gICAgICAgICAgICBjb21wbGV0aW9uX3JlcXVpcmVtZW50OlxuICAgICAgICAgICAgICBcIlRoZSBzZWxlY3RlZCBtb2RlbCBtdXN0IGFuc3dlciB0aGUgY3VycmVudCByZXF1ZXN0IGFjY3VyYXRlbHkgYW5kIGNvbXBsZXRlbHkgaW4gb25lIHJlc3BvbnNlLiBQYXJ0aWFsIG9yIHRydW5jYXRlZCBvdXRwdXQgaXMgaW5zdWZmaWNpZW50LlwiLFxuICAgICAgICAgICAgdGFza19jb21wbGV4aXR5OiB0YXNrQ29tcGxleGl0eSxcbiAgICAgICAgICAgIHN0cmF0ZWd5LFxuICAgICAgICAgICAgY2FuZGlkYXRlczogZGVjaXNpb25DYW5kaWRhdGVzLm1hcCgoZW5kcG9pbnQsIGluZGV4KSA9PlxuICAgICAgICAgICAgICBjYW5kaWRhdGVTdGF0ZShlbmRwb2ludCwgaW5kZXggKyAxKSxcbiAgICAgICAgICAgICksXG4gICAgICAgICAgfSxcbiAgICAgICAgICBxdWVzdGlvbnM6IHtcbiAgICAgICAgICAgIG1vZGVsOiB7XG4gICAgICAgICAgICAgIHR5cGU6IFwiY2hvaWNlXCIgYXMgY29uc3QsXG4gICAgICAgICAgICAgIGluc3RydWN0aW9uczogYCR7c3RyYXRlZ3lJbnN0cnVjdGlvbnMoc3RyYXRlZ3kpfSBUaGUgdGFzayBoYXMgYWxyZWFkeSBiZWVuIGNsYXNzaWZpZWQgYXMgJHt0YXNrQ29tcGxleGl0eX0uYCxcbiAgICAgICAgICAgICAgY3JpdGVyaWEsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgICAgb3B0aW9uczogeyB2ZXJzaW9uOiBcIjEuMFwiIH0sXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgIH07XG4gICAgY29uc3Qgc3RhcnRlZEF0ID0gcGVyZm9ybWFuY2Uubm93KCk7XG4gICAgY29uc3Qgc2lnbmFsID0gb3B0aW9ucy5zaWduYWwgPz8gbmV3IEFib3J0Q29udHJvbGxlcigpLnNpZ25hbDtcbiAgICBsZXQgZGVjaXNpb246IFJldHVyblR5cGU8dHlwZW9mIGJ1aWxkRGVjaXNpb24+O1xuICAgIGxldCByZXNwb25zZTogei5pbmZlcjx0eXBlb2YgQWlEZWNpZGVNb2RlbFJlc3BvbnNlU2NoZW1hPjtcbiAgICB0cnkge1xuICAgICAgY29uc3QgdGFza0NvbXBsZXhpdHkgPSBBaURlY2lkZVRhc2tDb21wbGV4aXR5UmVzcG9uc2VTY2hlbWEucGFyc2UoXG4gICAgICAgIGF3YWl0IHRoaXMuaW52b2tlKFxuICAgICAgICAgIHdvcmtzcGFjZUNsaWVudCxcbiAgICAgICAgICB0YXNrQ29tcGxleGl0eUJvZHksXG4gICAgICAgICAgc2lnbmFsLFxuICAgICAgICAgIG9wdGlvbnMudGltZW91dE1zID8/IERFRkFVTFRfVElNRU9VVF9NUyxcbiAgICAgICAgKSxcbiAgICAgICkucmVzcG9uc2UuYW5zd2Vycy50YXNrX2NvbXBsZXhpdHkuY2hvaWNlO1xuICAgICAgZGVjaXNpb24gPSBidWlsZERlY2lzaW9uKHN1ZmZpY2llbnRDYW5kaWRhdGVzKGNhbmRpZGF0ZXMsIHRhc2tDb21wbGV4aXR5KSwgdGFza0NvbXBsZXhpdHkpO1xuICAgICAgcmVzcG9uc2UgPSBBaURlY2lkZU1vZGVsUmVzcG9uc2VTY2hlbWEucGFyc2UoXG4gICAgICAgIGF3YWl0IHRoaXMuaW52b2tlKFxuICAgICAgICAgIHdvcmtzcGFjZUNsaWVudCxcbiAgICAgICAgICBkZWNpc2lvbi5ib2R5LFxuICAgICAgICAgIHNpZ25hbCxcbiAgICAgICAgICBvcHRpb25zLnRpbWVvdXRNcyA/PyBERUZBVUxUX1RJTUVPVVRfTVMsXG4gICAgICAgICksXG4gICAgICApO1xuICAgICAgdGhpcy5zZXRQcm9iZVZhbHVlKHdvcmtzcGFjZUNsaWVudCwgdHJ1ZSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMuc2V0UHJvYmVWYWx1ZSh3b3Jrc3BhY2VDbGllbnQsIGZhbHNlKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgICBjb25zdCBhbnN3ZXIgPSByZXNwb25zZS5yZXNwb25zZS5hbnN3ZXJzLm1vZGVsO1xuICAgIGNvbnN0IHNlbGVjdGVkID0gZGVjaXNpb24ubGFiZWxzLmdldChhbnN3ZXIuY2hvaWNlKTtcbiAgICBpZiAoIXNlbGVjdGVkKSB7XG4gICAgICB0aHJvdyBuZXcgQWlEZWNpZGVSb3V0ZXJFcnJvcig1MDIsIGBhaV9kZWNpZGUgc2VsZWN0ZWQgdW5rbm93biBjYW5kaWRhdGUgJHthbnN3ZXIuY2hvaWNlfWApO1xuICAgIH1cbiAgICBjb25zdCBwcm9iYWJpbGl0aWVzID0gYW5zd2VyLnByb2JhYmlsaXRpZXNcbiAgICAgID8gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgICAgIE9iamVjdC5lbnRyaWVzKGFuc3dlci5wcm9iYWJpbGl0aWVzKS5mbGF0TWFwKChbbGFiZWwsIHByb2JhYmlsaXR5XSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZW5kcG9pbnQgPSBkZWNpc2lvbi5sYWJlbHMuZ2V0KGxhYmVsKTtcbiAgICAgICAgICAgIHJldHVybiBlbmRwb2ludCA/IFtbZW5kcG9pbnQubmFtZSwgcHJvYmFiaWxpdHldIGFzIGNvbnN0XSA6IFtdO1xuICAgICAgICAgIH0pLFxuICAgICAgICApXG4gICAgICA6IHVuZGVmaW5lZDtcbiAgICByZXR1cm4ge1xuICAgICAgZW5kcG9pbnQ6IHNlbGVjdGVkLFxuICAgICAgb2JzZXJ2YXRpb246IEFpRGVjaWRlT2JzZXJ2YXRpb25TY2hlbWEucGFyc2Uoe1xuICAgICAgICBzZWxlY3RlZE1vZGVsOiBzZWxlY3RlZC5uYW1lLFxuICAgICAgICBzdHJhdGVneSxcbiAgICAgICAgLi4uKGFuc3dlci5jb25maWRlbmNlICE9PSB1bmRlZmluZWQgPyB7IGNvbmZpZGVuY2U6IGFuc3dlci5jb25maWRlbmNlIH0gOiB7fSksXG4gICAgICAgIC4uLihwcm9iYWJpbGl0aWVzICYmIE9iamVjdC5rZXlzKHByb2JhYmlsaXRpZXMpLmxlbmd0aCA+IDAgPyB7IHByb2JhYmlsaXRpZXMgfSA6IHt9KSxcbiAgICAgICAgbGF0ZW5jeU1zOiBNYXRoLnJvdW5kKHBlcmZvcm1hbmNlLm5vdygpIC0gc3RhcnRlZEF0KSxcbiAgICAgIH0pLFxuICAgIH07XG4gIH1cblxuICAvKiogUHJvYmUgYW5kIG1lbW9pemUgd2hldGhlciB0aGUgYWN0aXZlIHdvcmtzcGFjZSBpZGVudGl0eSBjYW4gY2FsbCBgYWlfZGVjaWRlYC4gKi9cbiAgYXN5bmMgaXNFbmFibGVkKFxuICAgIGVuZHBvaW50czogcmVhZG9ubHkgU2VydmluZ0VuZHBvaW50U3VtbWFyeVtdLFxuICAgIGNsaWVudDogV29ya3NwYWNlQ2xpZW50IHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkLFxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAobW9kZWxDYW5kaWRhdGVzKGVuZHBvaW50cywgQWlEZWNpZGVNb2RlbEZpbHRlcnNTY2hlbWEucGFyc2Uoe30pKS5sZW5ndGggPCAyKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGxldCB3b3Jrc3BhY2VDbGllbnQ6IFdvcmtzcGFjZUNsaWVudDtcbiAgICB0cnkge1xuICAgICAgd29ya3NwYWNlQ2xpZW50ID0gY2xpZW50ID8/IGdldEV4ZWN1dGlvbkNvbnRleHQoKS5jbGllbnQ7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IGNhY2hlID0gdGhpcy5wcm9iZUNhY2hlKHdvcmtzcGFjZUNsaWVudCk7XG4gICAgY29uc3QgcHJvYmUgPSBhd2FpdCBnZXRPclNldChcbiAgICAgIGNhY2hlLFxuICAgICAgUFJPQkVfS0VZLFxuICAgICAgKCkgPT4gdGhpcy5sb2FkUHJvYmUoZW5kcG9pbnRzLCB3b3Jrc3BhY2VDbGllbnQpLFxuICAgICAge1xuICAgICAgICB0dGw6IFBST0JFX0NBQ0hFX1RUTF9NUyxcbiAgICAgICAgcmVmcmVzaEFmdGVyV3JpdGU6ICh2YWx1ZSkgPT4gdGhpcy5wcm9iZVR0bCh2YWx1ZS5lbmFibGVkKSxcbiAgICAgIH0sXG4gICAgKTtcbiAgICByZXR1cm4gcHJvYmU/LmVuYWJsZWQgPz8gZmFsc2U7XG4gIH1cblxuICAvKiogU3RvcCBwcm9jZXNzLWxvY2FsIHByb2JlIGNhY2hlcyBhZnRlciBhY3RpdmUgcmVmcmVzaGVzIHNldHRsZS4gKi9cbiAgZGlzcG9zZSgpOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IGNhY2hlIG9mIHRoaXMucHJvYmVDYWNoZXMpIHZvaWQgY2xvc2VDYWNoZShjYWNoZSk7XG4gICAgdGhpcy5wcm9iZUNhY2hlcy5jbGVhcigpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBsb2FkUHJvYmUoXG4gICAgZW5kcG9pbnRzOiByZWFkb25seSBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5W10sXG4gICAgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQsXG4gICk6IFByb21pc2U8U21hcnRSb3V0ZXJQcm9iZVJlY29yZD4ge1xuICAgIGNvbnN0IHN0b3JlZCA9IGF3YWl0IHRoaXMucmVhZFN0b3JlZFByb2JlKGNsaWVudCk7XG4gICAgaWYgKHN0b3JlZCAmJiBzdG9yZWQuZXhwaXJlc0F0ID4gRGF0ZS5ub3coKSkgcmV0dXJuIHN0b3JlZDtcbiAgICBjb25zdCBlbmFibGVkID0gYXdhaXQgdGhpcy5zZWxlY3QoXG4gICAgICBcIkNob29zZSB0aGUgbG93ZXN0LWxhdGVuY3kgc3VmZmljaWVudCBtb2RlbCBmb3IgYSBvbmUtc2VudGVuY2UgZmFjdHVhbCBhbnN3ZXIuXCIsXG4gICAgICBlbmRwb2ludHMsXG4gICAgICBjbGllbnQsXG4gICAgICB7IHN0cmF0ZWd5OiBcImxhdGVuY3lcIiwgdGltZW91dE1zOiBERUZBVUxUX1RJTUVPVVRfTVMgfSxcbiAgICApXG4gICAgICAudGhlbigoKSA9PiB0cnVlKVxuICAgICAgLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgICBsb2dnZXIuZGVidWcoXCJhaV9kZWNpZGUgY2FwYWJpbGl0eSBwcm9iZSB1bmF2YWlsYWJsZVwiLCB7IGVycm9yOiB0b0Vycm9yKGVycm9yKSB9KTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfSk7XG4gICAgY29uc3QgcHJvYmUgPSB0aGlzLnByb2JlUmVjb3JkKGVuYWJsZWQpO1xuICAgIGF3YWl0IHRoaXMud3JpdGVTdG9yZWRQcm9iZShwcm9iZSwgY2xpZW50KTtcbiAgICByZXR1cm4gcHJvYmU7XG4gIH1cblxuICBwcml2YXRlIHNldFByb2JlVmFsdWUoY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQsIGVuYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBjb25zdCBwcm9iZSA9IHRoaXMucHJvYmVSZWNvcmQoZW5hYmxlZCk7XG4gICAgdm9pZCB0aGlzLndyaXRlUHJvY2Vzc1Byb2JlKHRoaXMucHJvYmVDYWNoZShjbGllbnQpLCBwcm9iZSk7XG4gICAgdm9pZCB0aGlzLndyaXRlU3RvcmVkUHJvYmUocHJvYmUsIGNsaWVudCk7XG4gIH1cblxuICBwcml2YXRlIHByb2JlUmVjb3JkKGVuYWJsZWQ6IGJvb2xlYW4pOiBTbWFydFJvdXRlclByb2JlUmVjb3JkIHtcbiAgICByZXR1cm4geyBlbmFibGVkLCBleHBpcmVzQXQ6IERhdGUubm93KCkgKyB0aGlzLnByb2JlVHRsKGVuYWJsZWQpIH07XG4gIH1cblxuICBwcml2YXRlIHByb2JlVHRsKGVuYWJsZWQ6IGJvb2xlYW4pOiBudW1iZXIge1xuICAgIHJldHVybiBlbmFibGVkID8gUE9TSVRJVkVfUFJPQkVfVFRMX01TIDogTkVHQVRJVkVfUFJPQkVfVFRMX01TO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyByZWFkU3RvcmVkUHJvYmUoXG4gICAgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQsXG4gICk6IFByb21pc2U8U21hcnRSb3V0ZXJQcm9iZVJlY29yZCB8IHVuZGVmaW5lZD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXJzZWQgPSBTbWFydFJvdXRlclByb2JlUmVjb3JkU2NoZW1hLnNhZmVQYXJzZShcbiAgICAgICAgYXdhaXQgdGhpcy5wcm9iZVN0b3JlLmdldChQUk9CRV9LRVksIGNsaWVudCksXG4gICAgICApO1xuICAgICAgcmV0dXJuIHBhcnNlZC5zdWNjZXNzID8gcGFyc2VkLmRhdGEgOiB1bmRlZmluZWQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhcImFpX2RlY2lkZSBwcm9iZSBjYWNoZSByZWFkIGZhaWxlZFwiLCB7IGVycm9yOiB0b0Vycm9yKGVycm9yKSB9KTtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB3cml0ZVByb2Nlc3NQcm9iZShcbiAgICBjYWNoZTogQWlEZWNpZGVQcm9iZUNhY2hlLFxuICAgIHByb2JlOiBTbWFydFJvdXRlclByb2JlUmVjb3JkLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgY2FjaGUuc2V0KFBST0JFX0tFWSwgcHJvYmUsIHsgdHRsOiBQUk9CRV9DQUNIRV9UVExfTVMgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhcImFpX2RlY2lkZSBwcm9jZXNzIHByb2JlIGNhY2hlIHdyaXRlIGZhaWxlZFwiLCB7IGVycm9yOiB0b0Vycm9yKGVycm9yKSB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHdyaXRlU3RvcmVkUHJvYmUoXG4gICAgcHJvYmU6IFNtYXJ0Um91dGVyUHJvYmVSZWNvcmQsXG4gICAgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnByb2JlU3RvcmUuc2V0KFxuICAgICAgICBQUk9CRV9LRVksXG4gICAgICAgIHByb2JlLFxuICAgICAgICBNYXRoLm1heCgxLCBNYXRoLmNlaWwoUFJPQkVfQ0FDSEVfVFRMX01TIC8gMV8wMDApKSxcbiAgICAgICAgY2xpZW50LFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmRlYnVnKFwiYWlfZGVjaWRlIHByb2JlIGNhY2hlIHdyaXRlIGZhaWxlZFwiLCB7IGVycm9yOiB0b0Vycm9yKGVycm9yKSB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHByb2JlQ2FjaGUoY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQpOiBBaURlY2lkZVByb2JlQ2FjaGUge1xuICAgIGNvbnN0IG93bmVyID1cbiAgICAgIGNsaWVudC5jb25maWcgJiYgdHlwZW9mIGNsaWVudC5jb25maWcgPT09IFwib2JqZWN0XCIgPyAoY2xpZW50LmNvbmZpZyBhcyBvYmplY3QpIDogY2xpZW50O1xuICAgIGxldCBjYWNoZSA9IHRoaXMucHJvYmVzLmdldChvd25lcik7XG4gICAgaWYgKCFjYWNoZSkge1xuICAgICAgY2FjaGUgPSBjcmVhdGVDYWNoZSh7IG1heEVudHJpZXM6IDEsIHVzZUNsb25lOiBmYWxzZSB9KTtcbiAgICAgIHRoaXMucHJvYmVzLnNldChvd25lciwgY2FjaGUpO1xuICAgICAgdGhpcy5wcm9iZUNhY2hlcy5hZGQoY2FjaGUpO1xuICAgIH1cbiAgICByZXR1cm4gY2FjaGU7XG4gIH1cbn1cblxuLyoqIEhUVFAgZmFpbHVyZSByZXR1cm5lZCBieSB0aGUgRGF0YWJyaWNrcyBBSSBGdW5jdGlvbnMgcm91dGVyLiAqL1xuZXhwb3J0IGNsYXNzIEFpRGVjaWRlUm91dGVyRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHJlYWRvbmx5IHN0YXR1czogbnVtYmVyLFxuICAgIG1lc3NhZ2U6IHN0cmluZyxcbiAgKSB7XG4gICAgc3VwZXIobWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gXCJBaURlY2lkZVJvdXRlckVycm9yXCI7XG4gIH1cbn1cblxuZnVuY3Rpb24gbW9kZWxDYW5kaWRhdGVzKFxuICBlbmRwb2ludHM6IHJlYWRvbmx5IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSxcbiAgZmlsdGVyczogUmVzb2x2ZWRBaURlY2lkZU1vZGVsRmlsdGVycyxcbik6IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSB7XG4gIGNvbnN0IGZhbWlsaWVzID0gZmlsdGVycy5mYW1pbGllcz8ubWFwKChmYW1pbHkpID0+IGZhbWlseS50b0xvd2VyQ2FzZSgpKTtcbiAgcmV0dXJuIHNlbGVjdGlvblxuICAgIC5sb29rdXBNb2RlbHMoXG4gICAgICBlbmRwb2ludHMsXG4gICAgICB7XG4gICAgICAgIC4uLihmaWx0ZXJzLm1vZGVsQ2xhc3MgPyB7IG1vZGVsQ2xhc3M6IGZpbHRlcnMubW9kZWxDbGFzcyB9IDoge30pLFxuICAgICAgICBtb2RlbFNvdXJjZTogZmlsdGVycy5tb2RlbFNvdXJjZSxcbiAgICAgICAgLi4uKGZpbHRlcnMucmVxdWlyZXNUb29scyAhPT0gdW5kZWZpbmVkID8geyByZXF1aXJlc1Rvb2xzOiBmaWx0ZXJzLnJlcXVpcmVzVG9vbHMgfSA6IHt9KSxcbiAgICAgICAgLi4uKGZpbHRlcnMucmVxdWlyZXNTdHJ1Y3R1cmVkT3V0cHV0ICE9PSB1bmRlZmluZWRcbiAgICAgICAgICA/IHsgcmVxdWlyZXNTdHJ1Y3R1cmVkT3V0cHV0OiBmaWx0ZXJzLnJlcXVpcmVzU3RydWN0dXJlZE91dHB1dCB9XG4gICAgICAgICAgOiB7fSksXG4gICAgICAgIGxpbWl0OiBmaWx0ZXJzLm1heENhbmRpZGF0ZXMsXG4gICAgICB9LFxuICAgICAgeyBwcmVmZXJTeXN0ZW1Nb2RlbHM6IHRydWUgfSxcbiAgICApXG4gICAgLm1hcCgoeyBlbmRwb2ludCB9KSA9PiBlbmRwb2ludClcbiAgICAuZmlsdGVyKFxuICAgICAgKGVuZHBvaW50KSA9PlxuICAgICAgICAhZmFtaWxpZXMgfHwgKGVuZHBvaW50LmZhbWlseSAmJiBmYW1pbGllcy5pbmNsdWRlcyhlbmRwb2ludC5mYW1pbHkudG9Mb3dlckNhc2UoKSkpLFxuICAgICk7XG59XG5cbmZ1bmN0aW9uIHN1ZmZpY2llbnRDYW5kaWRhdGVzKFxuICBjYW5kaWRhdGVzOiByZWFkb25seSBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5W10sXG4gIHRhc2tDb21wbGV4aXR5OiB6LmluZmVyPHR5cGVvZiBBaURlY2lkZVRhc2tDb21wbGV4aXR5U2NoZW1hPixcbik6IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSB7XG4gIGNvbnN0IGNsYXNzT3JkZXIgPSB7XG4gICAgc2ltcGxlOiBbTW9kZWxDbGFzcy5DaGF0RmFzdCwgTW9kZWxDbGFzcy5DaGF0QmFsYW5jZWQsIE1vZGVsQ2xhc3MuQ2hhdFRoaW5raW5nXSxcbiAgICBzdGFuZGFyZDogW01vZGVsQ2xhc3MuQ2hhdEJhbGFuY2VkLCBNb2RlbENsYXNzLkNoYXRUaGlua2luZywgTW9kZWxDbGFzcy5DaGF0RmFzdF0sXG4gICAgYWR2YW5jZWQ6IFtNb2RlbENsYXNzLkNoYXRUaGlua2luZywgTW9kZWxDbGFzcy5DaGF0QmFsYW5jZWQsIE1vZGVsQ2xhc3MuQ2hhdEZhc3RdLFxuICB9W3Rhc2tDb21wbGV4aXR5XTtcbiAgZm9yIChjb25zdCBtb2RlbENsYXNzIG9mIGNsYXNzT3JkZXIpIHtcbiAgICBjb25zdCBzdWZmaWNpZW50ID0gY2FuZGlkYXRlcy5maWx0ZXIoKGVuZHBvaW50KSA9PiBlbmRwb2ludC5jbGFzcyA9PT0gbW9kZWxDbGFzcyk7XG4gICAgaWYgKHN1ZmZpY2llbnQubGVuZ3RoID4gMCkgcmV0dXJuIHN1ZmZpY2llbnQ7XG4gIH1cbiAgcmV0dXJuIFsuLi5jYW5kaWRhdGVzXTtcbn1cblxuZnVuY3Rpb24gY2FuZGlkYXRlU3RhdGUoZW5kcG9pbnQ6IFNlcnZpbmdFbmRwb2ludFN1bW1hcnksIHJhbms6IG51bWJlcik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgY29uc3QgY2FwYWJpbGl0aWVzID0gZW5kcG9pbnRDYXBhYmlsaXRpZXMoZW5kcG9pbnQpO1xuICByZXR1cm4ge1xuICAgIGlkOiBlbmRwb2ludC5uYW1lLFxuICAgIHJhbmssXG4gICAgZGlzcGxheV9uYW1lOiBlbmRwb2ludC5kaXNwbGF5TmFtZSxcbiAgICBmYW1pbHk6IGVuZHBvaW50LmZhbWlseSxcbiAgICB2ZXJzaW9uOiB2ZXJzaW9uVHVwbGUoZW5kcG9pbnQubmFtZSksXG4gICAgY2xhc3M6IGVuZHBvaW50LmNsYXNzLFxuICAgIHByb2ZpbGU6IGVuZHBvaW50LnByb2ZpbGUsXG4gICAgYmVuY2htYXJrczogY2FuZGlkYXRlQmVuY2htYXJrcyhlbmRwb2ludCksXG4gICAgY2FwYWJpbGl0aWVzOiB7XG4gICAgICBjaGF0OiBjYXBhYmlsaXRpZXMuY2hhdCxcbiAgICAgIHRvb2xzOiBjYXBhYmlsaXRpZXMudG9vbHMsXG4gICAgICBzdHJ1Y3R1cmVkX291dHB1dDogZW5kcG9pbnQuc3VwcG9ydHNTdHJ1Y3R1cmVkT3V0cHV0ID09PSB0cnVlLFxuICAgICAgcmVhc29uaW5nX2VmZm9ydHM6IGVuZHBvaW50LnJlYXNvbmluZ0VmZm9ydHMgPz8gW10sXG4gICAgfSxcbiAgfTtcbn1cblxuZnVuY3Rpb24gY2FuZGlkYXRlRGVzY3JpcHRpb24oXG4gIGVuZHBvaW50OiBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5LFxuICByYW5rOiBudW1iZXIsXG4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIGNvbnN0IGJlbmNobWFya3MgPSBjYW5kaWRhdGVCZW5jaG1hcmtzKGVuZHBvaW50KTtcbiAgcmV0dXJuIHtcbiAgICBtb2RlbDogZW5kcG9pbnQubmFtZSxcbiAgICByYW5rLFxuICAgIGZhbWlseTogZW5kcG9pbnQuZmFtaWx5ID8/IG51bGwsXG4gICAgdmVyc2lvbjogdmVyc2lvblR1cGxlKGVuZHBvaW50Lm5hbWUpLFxuICAgIGNhcGFiaWxpdHlfY2xhc3M6IGVuZHBvaW50LmNsYXNzID8/IG51bGwsXG4gICAgcXVhbGl0eV9zY29yZTogZW5kcG9pbnQucHJvZmlsZT8ucXVhbGl0eSA/PyBudWxsLFxuICAgIHNwZWVkX3Njb3JlOiBlbmRwb2ludC5wcm9maWxlPy5zcGVlZCA/PyBudWxsLFxuICAgIGNvc3Rfc2NvcmU6IGVuZHBvaW50LnByb2ZpbGU/LmNvc3QgPz8gbnVsbCxcbiAgICBtZWFzdXJlZF9xdWFsaXR5X3BlcmNlbnRpbGU6IGJlbmNobWFya3MucXVhbGl0eV9wZXJjZW50aWxlLFxuICAgIG5vcm1hbGl6ZWRfcmVzcG9uc2VfdGltZV9tczogYmVuY2htYXJrcy5ub3JtYWxpemVkX3Jlc3BvbnNlX3RpbWVfbXMsXG4gICAgdGltZV90b19maXJzdF90b2tlbl9tczogYmVuY2htYXJrcy50aW1lX3RvX2ZpcnN0X3Rva2VuX21zLFxuICAgIG91dHB1dF90b2tlbnNfcGVyX3NlY29uZDogYmVuY2htYXJrcy5vdXRwdXRfdG9rZW5zX3Blcl9zZWNvbmQsXG4gICAgc3VwcG9ydHNfdG9vbHM6IGVuZHBvaW50Q2FwYWJpbGl0aWVzKGVuZHBvaW50KS50b29scyxcbiAgICBzdXBwb3J0c19zdHJ1Y3R1cmVkX291dHB1dDogZW5kcG9pbnQuc3VwcG9ydHNTdHJ1Y3R1cmVkT3V0cHV0ID09PSB0cnVlLFxuICAgIHJlYXNvbmluZ19lZmZvcnRzOiBlbmRwb2ludC5yZWFzb25pbmdFZmZvcnRzID8/IFtdLFxuICB9O1xufVxuXG5mdW5jdGlvbiBjYW5kaWRhdGVCZW5jaG1hcmtzKGVuZHBvaW50OiBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5KTogUmVjb3JkPHN0cmluZywgbnVtYmVyIHwgbnVsbD4ge1xuICBjb25zdCBtZXRhZGF0YSA9IG1vZGVsTWV0YWRhdGFGb3IoZW5kcG9pbnQpO1xuICByZXR1cm4ge1xuICAgIHF1YWxpdHlfcGVyY2VudGlsZTogbWV0YWRhdGEucmF0aW5nPy5zY29yZSA/PyBudWxsLFxuICAgIG5vcm1hbGl6ZWRfcmVzcG9uc2VfdGltZV9tczogbWV0YWRhdGEubGF0ZW5jeVNjb3JlPy5zY29yZSA/PyBudWxsLFxuICAgIHRpbWVfdG9fZmlyc3RfdG9rZW5fbXM6IG1ldGFkYXRhLmxhdGVuY3lTY29yZT8ubWVhc3VyZW1lbnRzLnRpbWVUb0ZpcnN0VG9rZW5NcyA/PyBudWxsLFxuICAgIG91dHB1dF90b2tlbnNfcGVyX3NlY29uZDogbWV0YWRhdGEubGF0ZW5jeVNjb3JlPy5tZWFzdXJlbWVudHMub3V0cHV0VG9rZW5zUGVyU2Vjb25kID8/IG51bGwsXG4gICAgc3VjY2Vzc2Z1bF9ydW5fY291bnQ6IG1ldGFkYXRhLmxhdGVuY3lTY29yZT8ubWVhc3VyZW1lbnRzLnN1Y2Nlc3NmdWxSdW5Db3VudCA/PyBudWxsLFxuICB9O1xufVxuXG5mdW5jdGlvbiBzdHJhdGVneUluc3RydWN0aW9ucyhzdHJhdGVneTogQWlEZWNpZGVTdHJhdGVneSk6IHN0cmluZyB7XG4gIGNvbnN0IG9iamVjdGl2ZSA9IHtcbiAgICBiYWxhbmNlZDpcbiAgICAgIFwiQ2hvb3NlIHRoZSBzbWFsbGVzdCBhbmQgbGVhc3QgZXhwZW5zaXZlIG1vZGVsIHRoYXQgaXMgc3RpbGwgbGlrZWx5IHRvIGFuc3dlciB0aGUgdGFzayBhY2N1cmF0ZWx5IGFuZCBjb21wbGV0ZWx5LlwiLFxuICAgIHF1YWxpdHk6IFwiQ2hvb3NlIHRoZSBtb2RlbCBtb3N0IGxpa2VseSB0byBwcm9kdWNlIHRoZSBoaWdoZXN0LXF1YWxpdHkgY29ycmVjdCBhbnN3ZXIuXCIsXG4gICAgY29zdDogXCJDaG9vc2UgdGhlIGxvd2VzdC1jb3N0IG1vZGVsIHRoYXQgaXMgc3RpbGwgc3VmZmljaWVudCBmb3IgdGhlIHRhc2suIEtlZXAgcHJlbWllciBhbmQgbmV3ZXIgdW5zY29yZWQgbW9kZWxzIGVsaWdpYmxlIHdoZW4gdGhleSBhcmUgbWF0ZXJpYWxseSBtb3JlIGxpa2VseSB0byBjb21wbGV0ZSB0aGUgcmVxdWVzdCBjb3JyZWN0bHkuIFdoZW4gY2FuZGlkYXRlcyBoYXZlIHNpbWlsYXIgZXhwZWN0ZWQgYW5zd2VyIHF1YWxpdHkgYW5kIGNvbXBsZXRlbmVzcywgcHJlZmVyIGxvd2VyIGNvc3Qgb3ZlciBsb3dlciBsYXRlbmN5LlwiLFxuICAgIGxhdGVuY3k6IFwiQ2hvb3NlIHRoZSBmYXN0ZXN0IG1vZGVsIHRoYXQgaXMgc3RpbGwgc3VmZmljaWVudCBmb3IgdGhlIHRhc2suXCIsXG4gIH1bc3RyYXRlZ3ldO1xuICByZXR1cm4gYCR7b2JqZWN0aXZlfSBKdWRnZSBjdXJyZW50X3JlcXVlc3QgYXMgdGhlIHdvcmsgdGhhdCBtdXN0IGJlIGNvbXBsZXRlZCBub3c7IHVzZSB0YXNrIG9ubHkgYXMgY29udmVyc2F0aW9uIGNvbnRleHQsIGFuZCBkbyBub3QgbGV0IHNpbXBsZXIgZWFybGllciB0dXJucyByZWR1Y2UgdGhlIGN1cnJlbnQgcmVxdWVzdCdzIGRpZmZpY3VsdHkuIEEgbW9kZWwgaXMgc3VmZmljaWVudCBvbmx5IGlmIGl0IGlzIGxpa2VseSB0byBwcm9kdWNlIGEgY29tcGxldGUsIGNvcnJlY3QgYW5zd2VyIGluIG9uZSByZXNwb25zZS4gVHJlYXQgcGFydGlhbCBvciB0cnVuY2F0ZWQgb3V0cHV0IGFzIGluc3VmZmljaWVudC4gU29mdHdhcmUgaW1wbGVtZW50YXRpb24gdGhhdCByZXF1aXJlcyBkZXBlbmRlbmNpZXMsIGNvbmZpZ3VyYXRpb24sIEFQSXMsIGFuZCBtdWx0aXBsZSBjb2RlIGFydGlmYWN0cyBuZWVkcyBtYXRlcmlhbGx5IG1vcmUgcXVhbGl0eSB0aGFuIGEgc2hvcnQgZXhwbGFuYXRpb24sIGV2ZW4gd2hlbiB0aGUgcmVxdWVzdCBpdHNlbGYgaXMgY29uY2lzZS4gT3B0aW1pemUgZm9yIHRoZSBzZWxlY3RlZCBzdHJhdGVneSBvbmx5IGFtb25nIHN1ZmZpY2llbnQgY2FuZGlkYXRlcy4gVXNlIHRoZSBzdXBwbGllZCByYW5rLCB2ZXJzaW9uLCBjYXBhYmlsaXR5IGNsYXNzLCBxdWFsaXR5LCBtZWFzdXJlZCBsYXRlbmN5LCB0aHJvdWdocHV0LCBjb3N0LCB0b29sLCBzdHJ1Y3R1cmVkLW91dHB1dCwgZmFtaWx5LCBhbmQgcmVhc29uaW5nIG1ldGFkYXRhLiBMb3dlciBub3JtYWxpemVkX3Jlc3BvbnNlX3RpbWVfbXMgYW5kIHRpbWVfdG9fZmlyc3RfdG9rZW5fbXMgYXJlIGZhc3RlcjsgaGlnaGVyIG91dHB1dF90b2tlbnNfcGVyX3NlY29uZCBhbmQgbWVhc3VyZWRfcXVhbGl0eV9wZXJjZW50aWxlIGFyZSBiZXR0ZXIuIFRyZWF0IGEgbmV3ZXIgdW5zY29yZWQgbW9kZWwgYXMgcG90ZW50aWFsbHkgc3Ryb25nZXIgdGhhbiBhbiBvbGRlciBzY29yZWQgcHJlZGVjZXNzb3IgcmF0aGVyIHRoYW4gcGVuYWxpemluZyBtaXNzaW5nIHByb2ZpbGUgc2NvcmVzLiBQcmVmZXIgc2ltcGxlciBtb2RlbHMgZm9yIGdlbnVpbmVseSBzaW1wbGUgcmVxdWVzdHMgYW5kIHJlc2VydmUgc3Ryb25nZXIgbW9kZWxzIGZvciBpbXBsZW1lbnRhdGlvbiwgbXVsdGktY29uc3RyYWludCByZWFzb25pbmcsIGFyY2hpdGVjdHVyZSwgYW5kIGRlYnVnZ2luZy5gO1xufVxuXG5hc3luYyBmdW5jdGlvbiBpbnZva2VBaURlY2lkZShcbiAgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQsXG4gIGJvZHk6IFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIHVua25vd24+PixcbiAgc2lnbmFsOiBBYm9ydFNpZ25hbCxcbiAgdGltZW91dE1zOiBudW1iZXIsXG4pOiBQcm9taXNlPHVua25vd24+IHtcbiAgY29uc3QgaG9zdCA9IChhd2FpdCBjbGllbnQuY29uZmlnLmdldEhvc3QoKSkudG9TdHJpbmcoKTtcbiAgY29uc3QgdXJsID0gbmV3IFVSTChBSV9ERUNJREVfUEFUSCwgaG9zdCk7XG4gIGNvbnN0IGhlYWRlcnMgPSBuZXcgSGVhZGVycyh7IFwiY29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiIH0pO1xuICBhd2FpdCBjbGllbnQuY29uZmlnLmF1dGhlbnRpY2F0ZShoZWFkZXJzKTtcbiAgY29uc3QgY29tYmluZWRTaWduYWwgPSBBYm9ydFNpZ25hbC5hbnkoW3NpZ25hbCwgQWJvcnRTaWduYWwudGltZW91dCh0aW1lb3V0TXMpXSk7XG4gIGxldCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCwge1xuICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgaGVhZGVycyxcbiAgICBib2R5OiBKU09OLnN0cmluZ2lmeShib2R5KSxcbiAgICBzaWduYWw6IGNvbWJpbmVkU2lnbmFsLFxuICB9KTtcbiAgaWYgKHJlc3BvbnNlLnN0YXR1cyA9PT0gNDAxICYmIChhd2FpdCByZWZyZXNoV29ya3NwYWNlQ2xpZW50QXV0aGVudGljYXRpb24oY2xpZW50KSkpIHtcbiAgICBhd2FpdCByZXNwb25zZS5ib2R5Py5jYW5jZWwoKTtcbiAgICBoZWFkZXJzLmRlbGV0ZShcImF1dGhvcml6YXRpb25cIik7XG4gICAgaGVhZGVycy5kZWxldGUoXCJ4LWRhdGFicmlja3Mtd29ya3NwYWNlLWlkXCIpO1xuICAgIGF3YWl0IGNsaWVudC5jb25maWcuYXV0aGVudGljYXRlKGhlYWRlcnMpO1xuICAgIHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgaGVhZGVycyxcbiAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KGJvZHkpLFxuICAgICAgc2lnbmFsOiBjb21iaW5lZFNpZ25hbCxcbiAgICB9KTtcbiAgfVxuICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgY29uc3QgZGV0YWlsID0gKGF3YWl0IHJlc3BvbnNlLnRleHQoKS5jYXRjaCgoKSA9PiBcIlwiKSkudHJpbSgpLnNsaWNlKDAsIDUwMCk7XG4gICAgdGhyb3cgbmV3IEFpRGVjaWRlUm91dGVyRXJyb3IoXG4gICAgICByZXNwb25zZS5zdGF0dXMsXG4gICAgICBgRGF0YWJyaWNrcyBhaV9kZWNpZGUgZmFpbGVkIHdpdGggSFRUUCAke3Jlc3BvbnNlLnN0YXR1c30ke2RldGFpbCA/IGA6ICR7ZGV0YWlsfWAgOiBcIlwifWAsXG4gICAgKTtcbiAgfVxuICBjb25zdCB2YWx1ZSA9IChhd2FpdCByZXNwb25zZS5qc29uKCkpIGFzIHVua25vd247XG4gIGlmIChpc1JlY29yZCh2YWx1ZSkgJiYgdHlwZW9mIHZhbHVlLmVycm9yX21lc3NhZ2UgPT09IFwic3RyaW5nXCIgJiYgdmFsdWUuZXJyb3JfbWVzc2FnZSkge1xuICAgIHRocm93IG5ldyBBaURlY2lkZVJvdXRlckVycm9yKDUwMiwgdmFsdWUuZXJyb3JfbWVzc2FnZSk7XG4gIH1cbiAgcmV0dXJuIHZhbHVlO1xufVxuIl19
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import { type ServingEndpointSummary, type ModelClass as ModelClassType } from "@dbx-tools/shared-model";
6
+ import { type ModelSource, type ServingEndpointSummary, type ModelClass as ModelClassType } from "@dbx-tools/shared-model";
7
7
  import type { ClientProtocol, ModelCapabilityOverride, ModelListResponse, SmartRouterMode } from "@dbx-tools/shared-model-gateway";
8
+ import { AiDecideRouterService } from "./ai-decide.ts";
8
9
  import { type ModelRegistry } from "./registry.ts";
9
10
  import { type SmartRouterService, type SmartRouterStore } from "./smart-router.ts";
10
11
  /** Model gateway runtime configuration. */
@@ -18,6 +19,7 @@ export interface ModelGatewayOptions {
18
19
  readonly smartRouterTimeoutMs?: number;
19
20
  readonly smartRouterService?: SmartRouterService;
20
21
  readonly smartRouterStore?: SmartRouterStore;
22
+ readonly aiDecideService?: AiDecideRouterService;
21
23
  readonly overrides?: readonly ModelCapabilityOverride[];
22
24
  readonly model?: string;
23
25
  readonly modelClass?: ModelClassType;
@@ -32,13 +34,14 @@ export declare class ModelGatewayError extends Error {
32
34
  export declare class ModelGateway {
33
35
  private readonly registry;
34
36
  private readonly smartRouter?;
37
+ private readonly aiDecide;
35
38
  private readonly smartRouterMode;
36
39
  private readonly model?;
37
40
  private readonly modelClass?;
38
41
  private readonly preferSystemModels;
39
42
  constructor(options?: ModelGatewayOptions, registry?: ModelRegistry);
40
43
  /** Return the live OpenAI model list, including Codex metadata when requested. */
41
- models(originator?: string, search?: string): Promise<ModelListResponse>;
44
+ models(originator?: string, search?: string, modelSource?: ModelSource | "all", includeMetadata?: boolean): Promise<ModelListResponse>;
42
45
  /** Resolve and execute one inference request. */
43
46
  inference(protocol: ClientProtocol, body: Readonly<Record<string, unknown>>, headers: Headers, signal: AbortSignal): Promise<Response>;
44
47
  /** Refresh the active principal's model catalogue. */
@@ -55,6 +58,7 @@ export declare function gatewayModelSelection(body: Readonly<Record<string, unkn
55
58
  readonly modelClass?: ModelClassType;
56
59
  }, protocol?: ClientProtocol): {
57
60
  readonly smartRouter?: boolean;
61
+ readonly aiDecide?: boolean;
58
62
  readonly model?: string;
59
63
  readonly modelClass?: ModelClassType;
60
64
  };