@dbx-tools/model 0.9.21 → 0.9.29
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 +61 -10
- package/index.ts +12 -2
- package/lib/exports.d.ts +1 -0
- package/lib/exports.js +2 -0
- package/lib/index.d.ts +12 -2
- package/lib/index.js +9 -2
- package/lib/src/_metadata-contract.d.ts +42 -0
- package/lib/src/_metadata-contract.js +11 -0
- package/lib/src/_metadata-generator.d.ts +7 -0
- package/lib/src/_metadata-generator.js +182 -0
- package/lib/src/_ranking.d.ts +20 -0
- package/lib/src/_ranking.js +226 -0
- package/lib/src/_selection.d.ts +23 -0
- package/lib/src/_selection.js +95 -0
- package/lib/src/classes.d.ts +2 -2
- package/lib/src/classes.js +10 -8
- package/lib/src/classify.d.ts +130 -0
- package/lib/src/classify.js +283 -0
- package/lib/src/fallback.d.ts +4 -4
- package/lib/src/fallback.js +7 -7
- package/lib/src/generated/model-capabilities.json +90 -0
- package/lib/src/generated/model-rate-limits.json +342 -0
- package/lib/src/generated/retired-models.json +32 -0
- package/lib/src/invoke.js +3 -3
- package/lib/src/metadata.d.ts +33 -0
- package/lib/src/metadata.js +120 -0
- package/lib/src/model-catalog.d.ts +4 -4
- package/lib/src/model-catalog.js +19 -24
- package/lib/src/model-client.d.ts +67 -0
- package/lib/src/model-client.js +181 -0
- package/lib/src/policy.d.ts +14 -8
- package/lib/src/policy.js +173 -14
- package/lib/src/python.d.ts +2 -0
- package/lib/src/python.js +3 -0
- package/lib/src/resolve.d.ts +10 -143
- package/lib/src/resolve.js +11 -196
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -5
- package/src/_metadata-contract.ts +56 -0
- package/src/_metadata-generator.ts +199 -0
- package/src/_ranking.ts +260 -0
- package/src/_selection.ts +141 -0
- package/src/classes.ts +11 -7
- package/src/classify.ts +324 -0
- package/src/fallback.ts +11 -7
- package/src/generated/model-capabilities.json +90 -0
- package/src/generated/model-rate-limits.json +342 -0
- package/src/generated/retired-models.json +32 -0
- package/src/invoke.ts +2 -2
- package/src/metadata.ts +189 -0
- package/src/model-catalog.ts +26 -28
- package/src/model-client.ts +311 -0
- package/src/policy.ts +176 -19
- package/src/python.ts +2 -0
- package/src/resolve.ts +24 -270
- package/._LICENSE +0 -0
- package/._README.md +0 -0
- package/._index.ts +0 -0
- package/._package.json +0 -0
- package/lib/._index.d.ts +0 -0
- package/lib/._index.js +0 -0
- package/lib/._tsconfig.tsbuildinfo +0 -0
- package/lib/src/.__native.d.ts +0 -0
- package/lib/src/.__native.js +0 -0
- package/lib/src/._classes.d.ts +0 -0
- package/lib/src/._classes.js +0 -0
- package/lib/src/._fallback.d.ts +0 -0
- package/lib/src/._fallback.js +0 -0
- package/lib/src/._invoke.d.ts +0 -0
- package/lib/src/._invoke.js +0 -0
- package/lib/src/._model-catalog.d.ts +0 -0
- package/lib/src/._model-catalog.js +0 -0
- package/lib/src/._policy.d.ts +0 -0
- package/lib/src/._policy.js +0 -0
- package/lib/src/._resolve.d.ts +0 -0
- package/lib/src/._resolve.js +0 -0
- package/lib/src/_native.d.ts +0 -14
- package/lib/src/_native.js +0 -124
- package/src/.__native.ts +0 -0
- package/src/._classes.ts +0 -0
- package/src/._fallback.ts +0 -0
- package/src/._invoke.ts +0 -0
- package/src/._model-catalog.ts +0 -0
- package/src/._policy.ts +0 -0
- package/src/._resolve.ts +0 -0
- package/src/_native.ts +0 -174
package/lib/src/resolve.js
CHANGED
|
@@ -1,215 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
* Workspace-aware model selection.
|
|
3
|
-
*
|
|
4
|
-
* Given a caller's intent - a search string, a capability {@link ModelClass}
|
|
5
|
-
* ceiling, both, or nothing - the toolkit returns matching endpoints ranked by
|
|
6
|
-
* match quality then class, or collapses to the single best id the workspace
|
|
7
|
-
* actually has, degrading from "best in range" down to the static fallback
|
|
8
|
-
* floor. Selection is chat-only: embedding endpoints surface only when
|
|
9
|
-
* `modelClass` is explicitly {@link ModelClass.Embedding}.
|
|
10
|
-
*
|
|
11
|
-
* Two shapes of selection, each in a pure form (over an endpoint list the
|
|
12
|
-
* caller already holds) and an I/O wrapper (that lists `/serving-endpoints`
|
|
13
|
-
* first): ranking, which returns a match- then class-ordered list, and
|
|
14
|
-
* single-selection, which collapses to one id plus how it was reached and
|
|
15
|
-
* layers the operator-pinned fallback / static-floor safety net on top. A chat
|
|
16
|
-
* `modelClass` acts as a ceiling: that band and the less-capable chat bands
|
|
17
|
-
* below it are eligible (see {@link classesAtOrBelow}), so a `chat-balanced`
|
|
18
|
-
* ask can fall to `chat-fast` but never escalate to `chat-thinking`.
|
|
19
|
-
*
|
|
20
|
-
* @module
|
|
21
|
-
*/
|
|
22
|
-
import { object } from "@dbx-tools/shared-core";
|
|
23
|
-
import { rankEndpoints } from "./_native.js";
|
|
24
|
-
import { FALLBACK_MODEL_IDS, modelsForClass } from "./fallback.js";
|
|
1
|
+
import { lookupModels, rankModelId, resolveModel, } from "./_selection.js";
|
|
25
2
|
import { listServingEndpoints, } from "./model-catalog.js";
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
const DEFAULT_MODEL_FAMILY_SEARCH = "gpt";
|
|
29
|
-
/**
|
|
30
|
-
* Rank the live catalogue against a {@link ModelQuery}, best-first.
|
|
31
|
-
*
|
|
32
|
-
* Rust owns classification, fuzzy scoring, family-version ordering, preferred
|
|
33
|
-
* variants, class ceilings, tool filtering, and result limiting. Node retains
|
|
34
|
-
* the caller's endpoint objects so fields outside the ranking contract remain
|
|
35
|
-
* available unchanged.
|
|
36
|
-
*/
|
|
37
|
-
export function lookupModels(endpoints, query = {}) {
|
|
38
|
-
return rankEndpoints(endpoints, query);
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Collapse {@link lookupModels} to a single id: the closest endpoint to `search`
|
|
42
|
-
* in a catalogue snapshot, or the input verbatim when nothing scores within the
|
|
43
|
-
* threshold.
|
|
44
|
-
*
|
|
45
|
-
* The ranked counterpart to {@link resolveModelId}: equal
|
|
46
|
-
* match scores are broken by class and then within-class version, so a loose
|
|
47
|
-
* `"opus"` prefers `opus-5` over `opus-4-7` instead of picking whichever
|
|
48
|
-
* sibling appeared first. Returning the input unmatched (rather
|
|
49
|
-
* than a near neighbour) is deliberate - a deliberate endpoint id is never
|
|
50
|
-
* silently rewritten, and Databricks surfaces a clean 404.
|
|
51
|
-
*/
|
|
52
|
-
export function rankModelId(endpoints, search, options = {}) {
|
|
53
|
-
const [top] = lookupModels(endpoints, {
|
|
54
|
-
search,
|
|
55
|
-
limit: 1,
|
|
56
|
-
...(options.threshold !== undefined ? { threshold: options.threshold } : {}),
|
|
57
|
-
...(options.requiresTools !== undefined ? { requiresTools: options.requiresTools } : {}),
|
|
58
|
-
});
|
|
59
|
-
if (!top)
|
|
60
|
-
return { modelId: search, matched: false };
|
|
61
|
-
return { modelId: top.endpoint.name, matched: true, score: top.score };
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* {@link rankModelId} against a catalogue the caller may be holding stale:
|
|
65
|
-
* match the loaded snapshot, and on a miss reload once with `force` and match
|
|
66
|
-
* again. That way a model deployed after the catalogue was cached still
|
|
67
|
-
* resolves on first use, without a restart and without giving up caching.
|
|
68
|
-
*
|
|
69
|
-
* The catalogue arrives as a loader rather than a client so the caller keeps
|
|
70
|
-
* ownership of *how* it is cached - {@link listServingEndpoints} and its
|
|
71
|
-
* `CacheManager`, a plain process-lifetime field in a CLI, or a test double.
|
|
72
|
-
* Only one reload is attempted: a genuinely unknown name should fail fast
|
|
73
|
-
* rather than re-list on every request.
|
|
74
|
-
*
|
|
75
|
-
* @param load - Returns the catalogue; `force` asks it to bypass its cache.
|
|
76
|
-
*/
|
|
3
|
+
export { lookupModels, rankModelId, resolveModel } from "./_selection.js";
|
|
4
|
+
/** Resolve against a potentially stale catalogue, refreshing once on a miss. */
|
|
77
5
|
export async function rankModelIdLive(load, search, options = {}) {
|
|
78
6
|
const resolved = rankModelId(await load(false), search, options);
|
|
79
7
|
if (resolved.matched)
|
|
80
8
|
return resolved;
|
|
81
9
|
return rankModelId(await load(true), search, options);
|
|
82
10
|
}
|
|
83
|
-
/**
|
|
84
|
-
* Rank a workspace's catalogue in one call: list its `/serving-endpoints`
|
|
85
|
-
* (cached) and run {@link lookupModels} over the result. The list counterpart to
|
|
86
|
-
* {@link selectModel}, for a consumer that wants the full ranked set (a model
|
|
87
|
-
* picker, a CLI) rather than a single id. Catalogue fetches fail loud: network
|
|
88
|
-
* / auth errors propagate so the caller sees the real SDK message.
|
|
89
|
-
*
|
|
90
|
-
* @param host - Workspace host used as the cache key. Pass the value resolved
|
|
91
|
-
* from `client.config.getHost()`.
|
|
92
|
-
*/
|
|
11
|
+
/** List and rank a workspace model catalogue. */
|
|
93
12
|
export async function searchModels(client, host, input = {}) {
|
|
94
|
-
const endpoints = await listServingEndpoints(client, host,
|
|
95
|
-
...(input.ttlMs !== undefined ? { ttlMs: input.ttlMs } : {}),
|
|
96
|
-
...(input.cacheIdentity !== undefined ? { cacheIdentity: input.cacheIdentity } : {}),
|
|
97
|
-
});
|
|
13
|
+
const endpoints = await listServingEndpoints(client, host, catalogueOptions(input));
|
|
98
14
|
return lookupModels(endpoints, input);
|
|
99
15
|
}
|
|
100
|
-
/**
|
|
101
|
-
* Resolve a model id for a workspace in one call: list its `/serving-endpoints`
|
|
102
|
-
* (cached) and run {@link resolveModel} over the result. This is the entry
|
|
103
|
-
* point for any consumer that holds a `WorkspaceClient` and just wants a usable
|
|
104
|
-
* model name - a Lakeflow job, a one-off script, or the Mastra plugin alike.
|
|
105
|
-
*
|
|
106
|
-
* Cheap exit: when an `explicit` name is given, `fuzzy` is off, and tool
|
|
107
|
-
* capability is not required, the catalogue is never fetched. Catalogue
|
|
108
|
-
* fetches otherwise fail loud: network / auth errors propagate so the caller
|
|
109
|
-
* sees the real SDK message instead of a silent fallback.
|
|
110
|
-
*
|
|
111
|
-
* @param host - Workspace host used as the cache key. Pass the value resolved
|
|
112
|
-
* from `client.config.getHost()`.
|
|
113
|
-
*/
|
|
16
|
+
/** List a workspace catalogue and resolve one model. */
|
|
114
17
|
export async function selectModel(client, host, input = {}) {
|
|
115
18
|
if (input.explicit !== undefined && input.fuzzy === false && !input.requiresTools) {
|
|
116
19
|
return { modelId: input.explicit, source: "explicit" };
|
|
117
20
|
}
|
|
118
|
-
const endpoints = await listServingEndpoints(client, host,
|
|
119
|
-
...(input.ttlMs !== undefined ? { ttlMs: input.ttlMs } : {}),
|
|
120
|
-
...(input.cacheIdentity !== undefined ? { cacheIdentity: input.cacheIdentity } : {}),
|
|
121
|
-
});
|
|
21
|
+
const endpoints = await listServingEndpoints(client, host, catalogueOptions(input));
|
|
122
22
|
return resolveModel(endpoints, input);
|
|
123
23
|
}
|
|
124
|
-
|
|
125
|
-
* Resolve a single model id from the live catalogue and caller intent,
|
|
126
|
-
* delegating the live selection to {@link lookupModels} with `limit: 1`.
|
|
127
|
-
*
|
|
128
|
-
* 1. **Explicit ask**: with `fuzzy` off, returned verbatim; otherwise
|
|
129
|
-
* fuzzy-ranked within the (optional) class ceiling and the best taken,
|
|
130
|
-
* falling back to the input verbatim when nothing matches.
|
|
131
|
-
* 2. **No explicit ask**: an operator-pinned `fallback` that exists in the live
|
|
132
|
-
* catalogue wins first. A class request ranks within that ceiling. A
|
|
133
|
-
* general request prefers the highest-ranked live GPT, then any ranked live
|
|
134
|
-
* chat model. The static {@link FALLBACK_MODEL_IDS} floor is used only when
|
|
135
|
-
* the catalogue yields nothing in range.
|
|
136
|
-
*/
|
|
137
|
-
export function resolveModel(endpoints, input = {}) {
|
|
138
|
-
if (input.explicit !== undefined) {
|
|
139
|
-
if (input.fuzzy === false) {
|
|
140
|
-
if (input.requiresTools)
|
|
141
|
-
assertToolSupport(endpoints, input.explicit);
|
|
142
|
-
return { modelId: input.explicit, source: "explicit" };
|
|
143
|
-
}
|
|
144
|
-
const [top] = lookupModels(endpoints, buildQuery(input, input.explicit));
|
|
145
|
-
if (input.requiresTools && !top) {
|
|
146
|
-
throw new Error(`No tool-capable model matches "${input.explicit}"`);
|
|
147
|
-
}
|
|
148
|
-
return { modelId: top?.endpoint.name ?? input.explicit, source: "fuzzy-match" };
|
|
149
|
-
}
|
|
150
|
-
// Operator-pinned fallbacks win when present and live (e.g. a regulated
|
|
151
|
-
// workspace restricted to an approved subset).
|
|
152
|
-
if (input.modelClass === undefined && input.fallbacks && input.fallbacks.length > 0) {
|
|
153
|
-
const present = new Set(endpoints
|
|
154
|
-
.filter((endpoint) => !input.requiresTools || endpointSupportsTools(endpoint))
|
|
155
|
-
.map((endpoint) => endpoint.name));
|
|
156
|
-
const pinned = input.fallbacks.find((id) => present.has(id));
|
|
157
|
-
if (pinned)
|
|
158
|
-
return { modelId: pinned, source: "fallback" };
|
|
159
|
-
}
|
|
160
|
-
const source = input.modelClass !== undefined ? "class" : "fallback";
|
|
161
|
-
if (input.modelClass === undefined) {
|
|
162
|
-
const [preferred] = lookupModels(endpoints, buildQuery(input, DEFAULT_MODEL_FAMILY_SEARCH));
|
|
163
|
-
if (preferred)
|
|
164
|
-
return { modelId: preferred.endpoint.name, source };
|
|
165
|
-
}
|
|
166
|
-
const [top] = lookupModels(endpoints, buildQuery(input, undefined));
|
|
167
|
-
if (top)
|
|
168
|
-
return { modelId: top.endpoint.name, source };
|
|
169
|
-
if (input.liveOnly) {
|
|
170
|
-
throw new Error("No matching live Model Serving endpoint is available");
|
|
171
|
-
}
|
|
172
|
-
// Live catalogue yielded nothing in range: walk the static floor.
|
|
173
|
-
const floorSource = input.modelClass !== undefined ? modelsForClass(input.modelClass) : (input.fallbacks ?? []);
|
|
174
|
-
const floor = object.sequence(floorSource).concat(FALLBACK_MODEL_IDS).distinct().toArray();
|
|
175
|
-
if (input.requiresTools) {
|
|
176
|
-
const available = new Set(endpoints.filter(endpointSupportsTools).map((endpoint) => endpoint.name));
|
|
177
|
-
const selected = floor.find((id) => available.has(id));
|
|
178
|
-
if (!selected)
|
|
179
|
-
throw new Error("No tool-capable model is available");
|
|
180
|
-
return { modelId: selected, source };
|
|
181
|
-
}
|
|
182
|
-
return { modelId: pickFirstAvailable(floor, endpoints), source };
|
|
183
|
-
}
|
|
184
|
-
/** Build a {@link ModelQuery} from {@link ResolveModelInput} for the `limit: 1` delegation. */
|
|
185
|
-
function buildQuery(input, search) {
|
|
24
|
+
function catalogueOptions(input) {
|
|
186
25
|
return {
|
|
187
|
-
...(
|
|
188
|
-
...(input.
|
|
189
|
-
...(input.requiresTools !== undefined ? { requiresTools: input.requiresTools } : {}),
|
|
190
|
-
...(input.threshold !== undefined ? { threshold: input.threshold } : {}),
|
|
191
|
-
limit: 1,
|
|
26
|
+
...(input.ttlMs !== undefined ? { ttlMs: input.ttlMs } : {}),
|
|
27
|
+
...(input.cacheIdentity !== undefined ? { cacheIdentity: input.cacheIdentity } : {}),
|
|
192
28
|
};
|
|
193
29
|
}
|
|
194
|
-
|
|
195
|
-
function assertToolSupport(endpoints, modelId) {
|
|
196
|
-
const endpoint = endpoints.find((candidate) => candidate.name === modelId);
|
|
197
|
-
if (!endpoint || !endpointSupportsTools(endpoint)) {
|
|
198
|
-
throw new Error(`Model "${modelId}" does not support function tools`);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Find the first id in `candidates` whose endpoint is present in `endpoints`.
|
|
203
|
-
* Returns the top candidate when the workspace has none of them so callers
|
|
204
|
-
* always get a string; an offline workspace then receives a clean 404 from
|
|
205
|
-
* Databricks instead of a malformed config.
|
|
206
|
-
*/
|
|
207
|
-
function pickFirstAvailable(candidates, endpoints) {
|
|
208
|
-
const present = new Set(endpoints.map((e) => e.name));
|
|
209
|
-
for (const candidate of candidates) {
|
|
210
|
-
if (present.has(candidate))
|
|
211
|
-
return candidate;
|
|
212
|
-
}
|
|
213
|
-
return candidates[0] ?? FALLBACK_MODEL_IDS[0];
|
|
214
|
-
}
|
|
215
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzb2x2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9yZXNvbHZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9CRztBQUVILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQVFoRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzdDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxjQUFjLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkUsT0FBTyxFQUNMLG9CQUFvQixHQUlyQixNQUFNLG9CQUFvQixDQUFDO0FBQzVCLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUlwRCw4RUFBOEU7QUFDOUUsTUFBTSwyQkFBMkIsR0FBRyxLQUFLLENBQUM7QUErRDFDOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLFVBQVUsWUFBWSxDQUMxQixTQUE0QyxFQUM1QyxRQUFvQixFQUFFO0lBRXRCLE9BQU8sYUFBYSxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsQ0FBQztBQUN6QyxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFNLFVBQVUsV0FBVyxDQUN6QixTQUE0QyxFQUM1QyxNQUFjLEVBQ2QsVUFBK0IsRUFBRTtJQUVqQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsWUFBWSxDQUFDLFNBQVMsRUFBRTtRQUNwQyxNQUFNO1FBQ04sS0FBSyxFQUFFLENBQUM7UUFDUixHQUFHLENBQUMsT0FBTyxDQUFDLFNBQVMsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzVFLEdBQUcsQ0FBQyxPQUFPLENBQUMsYUFBYSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxhQUFhLEVBQUUsT0FBTyxDQUFDLGFBQWEsRUFBRSxD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cGFjZS1hd2FyZSBtb2RlbCBzZWxlY3Rpb24uXG4gKlxuICogR2l2ZW4gYSBjYWxsZXIncyBpbnRlbnQgLSBhIHNlYXJjaCBzdHJpbmcsIGEgY2FwYWJpbGl0eSB7QGxpbmsgTW9kZWxDbGFzc31cbiAqIGNlaWxpbmcsIGJvdGgsIG9yIG5vdGhpbmcgLSB0aGUgdG9vbGtpdCByZXR1cm5zIG1hdGNoaW5nIGVuZHBvaW50cyByYW5rZWQgYnlcbiAqIG1hdGNoIHF1YWxpdHkgdGhlbiBjbGFzcywgb3IgY29sbGFwc2VzIHRvIHRoZSBzaW5nbGUgYmVzdCBpZCB0aGUgd29ya3NwYWNlXG4gKiBhY3R1YWxseSBoYXMsIGRlZ3JhZGluZyBmcm9tIFwiYmVzdCBpbiByYW5nZVwiIGRvd24gdG8gdGhlIHN0YXRpYyBmYWxsYmFja1xuICogZmxvb3IuIFNlbGVjdGlvbiBpcyBjaGF0LW9ubHk6IGVtYmVkZGluZyBlbmRwb2ludHMgc3VyZmFjZSBvbmx5IHdoZW5cbiAqIGBtb2RlbENsYXNzYCBpcyBleHBsaWNpdGx5IHtAbGluayBNb2RlbENsYXNzLkVtYmVkZGluZ30uXG4gKlxuICogVHdvIHNoYXBlcyBvZiBzZWxlY3Rpb24sIGVhY2ggaW4gYSBwdXJlIGZvcm0gKG92ZXIgYW4gZW5kcG9pbnQgbGlzdCB0aGVcbiAqIGNhbGxlciBhbHJlYWR5IGhvbGRzKSBhbmQgYW4gSS9PIHdyYXBwZXIgKHRoYXQgbGlzdHMgYC9zZXJ2aW5nLWVuZHBvaW50c2BcbiAqIGZpcnN0KTogcmFua2luZywgd2hpY2ggcmV0dXJucyBhIG1hdGNoLSB0aGVuIGNsYXNzLW9yZGVyZWQgbGlzdCwgYW5kXG4gKiBzaW5nbGUtc2VsZWN0aW9uLCB3aGljaCBjb2xsYXBzZXMgdG8gb25lIGlkIHBsdXMgaG93IGl0IHdhcyByZWFjaGVkIGFuZFxuICogbGF5ZXJzIHRoZSBvcGVyYXRvci1waW5uZWQgZmFsbGJhY2sgLyBzdGF0aWMtZmxvb3Igc2FmZXR5IG5ldCBvbiB0b3AuIEEgY2hhdFxuICogYG1vZGVsQ2xhc3NgIGFjdHMgYXMgYSBjZWlsaW5nOiB0aGF0IGJhbmQgYW5kIHRoZSBsZXNzLWNhcGFibGUgY2hhdCBiYW5kc1xuICogYmVsb3cgaXQgYXJlIGVsaWdpYmxlIChzZWUge0BsaW5rIGNsYXNzZXNBdE9yQmVsb3d9KSwgc28gYSBgY2hhdC1iYWxhbmNlZGBcbiAqIGFzayBjYW4gZmFsbCB0byBgY2hhdC1mYXN0YCBidXQgbmV2ZXIgZXNjYWxhdGUgdG8gYGNoYXQtdGhpbmtpbmdgLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBvYmplY3QgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHtcbiAgbW9kZWwsXG4gIHR5cGUgTW9kZWxRdWVyeSxcbiAgdHlwZSBSYW5rZWRNb2RlbCxcbiAgdHlwZSBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5LFxufSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtbW9kZWxcIjtcblxuaW1wb3J0IHsgcmFua0VuZHBvaW50cyB9IGZyb20gXCIuL19uYXRpdmUudHNcIjtcbmltcG9ydCB7IEZBTExCQUNLX01PREVMX0lEUywgbW9kZWxzRm9yQ2xhc3MgfSBmcm9tIFwiLi9mYWxsYmFjay50c1wiO1xuaW1wb3J0IHtcbiAgbGlzdFNlcnZpbmdFbmRwb2ludHMsXG4gIHR5cGUgUmVzb2x2ZWRNb2RlbCxcbiAgdHlwZSBSZXNvbHZlTW9kZWxPcHRpb25zLFxuICB0eXBlIFdvcmtzcGFjZUNsaWVudExpa2UsXG59IGZyb20gXCIuL21vZGVsLWNhdGFsb2cudHNcIjtcbmltcG9ydCB7IGVuZHBvaW50U3VwcG9ydHNUb29scyB9IGZyb20gXCIuL3BvbGljeS50c1wiO1xuXG50eXBlIE1vZGVsQ2xhc3MgPSBtb2RlbC5Nb2RlbENsYXNzO1xuXG4vKiogUHJlZmVycmVkIGxpdmUgZmFtaWx5IGZvciBhbiB1bmNvbmZpZ3VyZWQgZ2VuZXJhbC1wdXJwb3NlIGNoYXQgZGVmYXVsdC4gKi9cbmNvbnN0IERFRkFVTFRfTU9ERUxfRkFNSUxZX1NFQVJDSCA9IFwiZ3B0XCI7XG5cbi8qKiBDYWxsZXIgaW50ZW50IHBhc3NlZCB0byB7QGxpbmsgcmVzb2x2ZU1vZGVsfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVzb2x2ZU1vZGVsSW5wdXQge1xuICAvKipcbiAgICogRXhwbGljaXQgbW9kZWwgaWQgLyBsb29zZSBuYW1lIChwZXItcmVxdWVzdCBvdmVycmlkZSwgYWdlbnQgLyBwbHVnaW5cbiAgICogZGVmYXVsdCwgb3IgZW52IHZhcikuIFdoZW4gc2V0IGl0IHdpbnMgb3ZlciBgbW9kZWxDbGFzc2AgYW5kIGBmYWxsYmFja3NgLlxuICAgKi9cbiAgZXhwbGljaXQ/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBGdXp6eS1tYXRjaCBhbiBgZXhwbGljaXRgIG5hbWUgYWdhaW5zdCB0aGUgbGl2ZSBjYXRhbG9ndWUgc28gbG9vc2UgbmFtZXNcbiAgICogbGlrZSBgXCJjbGF1ZGUgc29ubmV0XCJgIHJlc29sdmUuIERlZmF1bHQgYHRydWVgLiBXaGVuIGBmYWxzZWAgdGhlIGV4cGxpY2l0XG4gICAqIGlucHV0IGlzIHJldHVybmVkIHZlcmJhdGltIChEYXRhYnJpY2tzIHN1cmZhY2VzIHRoZSBjYW5vbmljYWwgNDA0IGlmIGl0XG4gICAqIGRvZXNuJ3QgZXhpc3QpLlxuICAgKi9cbiAgZnV6enk/OiBib29sZWFuO1xuICAvKiogUnVzdCBmdXp6eS1kaXN0YW5jZSB0aHJlc2hvbGQgZm9yd2FyZGVkIHRvIHRoZSBzZWFyY2ggbWF0Y2guICovXG4gIHRocmVzaG9sZD86IG51bWJlcjtcbiAgLyoqIFJlcXVpcmUgYSBtb2RlbCB0aGF0IHN1cHBvcnRzIGEgY29tcGxldGUgZnVuY3Rpb24tdG9vbCByb3VuZC10cmlwLiAqL1xuICByZXF1aXJlc1Rvb2xzPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIENoYXQgY2FwYWJpbGl0eSBjbGFzcyB0byByZXNvbHZlIHdoZW4gbm8gYGV4cGxpY2l0YCBpZCBpcyBnaXZlbi4gVGhlIGxpdmVcbiAgICogY2F0YWxvZ3VlIGlzIGNsYXNzaWZpZWQgYnkgaXRzIEZvdW5kYXRpb24gTW9kZWwgQVBJIHNjb3JlcyBhbmQgdGhlIHRvcFxuICAgKiBhdmFpbGFibGUgbW9kZWwgaW4gdGhlIGNsYXNzIChhbmQgdGhlIGNoYXQgYmFuZHMgYmVsb3cgaXQpIHdpbnMsIGZhbGxpbmdcbiAgICogYmFjayB0byB0aGUgY2xhc3MncyBzbWFsbCBzdGF0aWMgbGlzdC5cbiAgICovXG4gIG1vZGVsQ2xhc3M/OiBNb2RlbENsYXNzO1xuICAvKipcbiAgICogT3BlcmF0b3Itc3VwcGxpZWQgZmFsbGJhY2sgaWRzIHRyaWVkICpmaXJzdCogaW4gdGhlIG5vLWV4cGxpY2l0LCBuby1jbGFzc1xuICAgKiBwYXRoIChlLmcuIGEgcmVndWxhdGVkIHdvcmtzcGFjZSBwaW5uZWQgdG8gYW4gYXBwcm92ZWQgc3Vic2V0KSwgYWhlYWQgb2ZcbiAgICogdGhlIGF1dG8tY2xhc3NpZmllZCBjYXRhbG9ndWUuXG4gICAqL1xuICBmYWxsYmFja3M/OiByZWFkb25seSBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIFJlZnVzZSB0aGUgc3RhdGljIG9mZmxpbmUgZmxvb3Igd2hlbiB0aGUgbGl2ZSBjYXRhbG9ndWUgaGFzIG5vIG1hdGNoLlxuICAgKiBVc2UgZm9yIHVucGlubmVkIGRlZmF1bHRzIHRoYXQgbXVzdCBhbHdheXMgbmFtZSBhIGN1cnJlbnRseSBhdmFpbGFibGVcbiAgICogZW5kcG9pbnQuXG4gICAqL1xuICBsaXZlT25seT86IGJvb2xlYW47XG59XG5cbi8qKiBPdXRjb21lIG9mIHtAbGluayByZXNvbHZlTW9kZWx9OiB0aGUgY2hvc2VuIGlkIHBsdXMgaG93IGl0IHdhcyByZWFjaGVkLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlZE1vZGVsU2VsZWN0aW9uIHtcbiAgbW9kZWxJZDogc3RyaW5nO1xuICBzb3VyY2U6IFwiZXhwbGljaXRcIiB8IFwiZnV6enktbWF0Y2hcIiB8IFwiY2xhc3NcIiB8IFwiZmFsbGJhY2tcIjtcbn1cblxuLyoqIEludGVudCArIGNhdGFsb2d1ZSBrbm9icyBwYXNzZWQgdG8ge0BsaW5rIHNlbGVjdE1vZGVsfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2VsZWN0TW9kZWxJbnB1dCBleHRlbmRzIFJlc29sdmVNb2RlbElucHV0IHtcbiAgLyoqIFRUTCBvdmVycmlkZSBmb3IgdGhlIGNhY2hlZCBgL3NlcnZpbmctZW5kcG9pbnRzYCBsaXN0aW5nLCBpbiBtcy4gKi9cbiAgdHRsTXM/OiBudW1iZXI7XG4gIC8qKiBUcnVzdGVkIG9wYXF1ZSBpZGVudGl0eSBvZiB0aGUgY3JlZGVudGlhbCB1c2VkIGJ5IHRoZSB3b3Jrc3BhY2UgY2xpZW50LiAqL1xuICBjYWNoZUlkZW50aXR5Pzogc3RyaW5nO1xufVxuXG4vKiogVFRMIG92ZXJyaWRlIG1lcmdlZCBpbnRvIGEge0BsaW5rIE1vZGVsUXVlcnl9IGZvciB7QGxpbmsgc2VhcmNoTW9kZWxzfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2VhcmNoTW9kZWxzSW5wdXQgZXh0ZW5kcyBNb2RlbFF1ZXJ5IHtcbiAgLyoqIFRUTCBvdmVycmlkZSBmb3IgdGhlIGNhY2hlZCBgL3NlcnZpbmctZW5kcG9pbnRzYCBsaXN0aW5nLCBpbiBtcy4gKi9cbiAgdHRsTXM/OiBudW1iZXI7XG4gIC8qKiBUcnVzdGVkIG9wYXF1ZSBpZGVudGl0eSBvZiB0aGUgY3JlZGVudGlhbCB1c2VkIGJ5IHRoZSB3b3Jrc3BhY2UgY2xpZW50LiAqL1xuICBjYWNoZUlkZW50aXR5Pzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFJhbmsgdGhlIGxpdmUgY2F0YWxvZ3VlIGFnYWluc3QgYSB7QGxpbmsgTW9kZWxRdWVyeX0sIGJlc3QtZmlyc3QuXG4gKlxuICogUnVzdCBvd25zIGNsYXNzaWZpY2F0aW9uLCBmdXp6eSBzY29yaW5nLCBmYW1pbHktdmVyc2lvbiBvcmRlcmluZywgcHJlZmVycmVkXG4gKiB2YXJpYW50cywgY2xhc3MgY2VpbGluZ3MsIHRvb2wgZmlsdGVyaW5nLCBhbmQgcmVzdWx0IGxpbWl0aW5nLiBOb2RlIHJldGFpbnNcbiAqIHRoZSBjYWxsZXIncyBlbmRwb2ludCBvYmplY3RzIHNvIGZpZWxkcyBvdXRzaWRlIHRoZSByYW5raW5nIGNvbnRyYWN0IHJlbWFpblxuICogYXZhaWxhYmxlIHVuY2hhbmdlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxvb2t1cE1vZGVscyhcbiAgZW5kcG9pbnRzOiByZWFkb25seSBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5W10sXG4gIHF1ZXJ5OiBNb2RlbFF1ZXJ5ID0ge30sXG4pOiBSYW5rZWRNb2RlbFtdIHtcbiAgcmV0dXJuIHJhbmtFbmRwb2ludHMoZW5kcG9pbnRzLCBxdWVyeSk7XG59XG5cbi8qKlxuICogQ29sbGFwc2Uge0BsaW5rIGxvb2t1cE1vZGVsc30gdG8gYSBzaW5nbGUgaWQ6IHRoZSBjbG9zZXN0IGVuZHBvaW50IHRvIGBzZWFyY2hgXG4gKiBpbiBhIGNhdGFsb2d1ZSBzbmFwc2hvdCwgb3IgdGhlIGlucHV0IHZlcmJhdGltIHdoZW4gbm90aGluZyBzY29yZXMgd2l0aGluIHRoZVxuICogdGhyZXNob2xkLlxuICpcbiAqIFRoZSByYW5rZWQgY291bnRlcnBhcnQgdG8ge0BsaW5rIHJlc29sdmVNb2RlbElkfTogZXF1YWxcbiAqIG1hdGNoIHNjb3JlcyBhcmUgYnJva2VuIGJ5IGNsYXNzIGFuZCB0aGVuIHdpdGhpbi1jbGFzcyB2ZXJzaW9uLCBzbyBhIGxvb3NlXG4gKiBgXCJvcHVzXCJgIHByZWZlcnMgYG9wdXMtNWAgb3ZlciBgb3B1cy00LTdgIGluc3RlYWQgb2YgcGlja2luZyB3aGljaGV2ZXJcbiAqIHNpYmxpbmcgYXBwZWFyZWQgZmlyc3QuIFJldHVybmluZyB0aGUgaW5wdXQgdW5tYXRjaGVkIChyYXRoZXJcbiAqIHRoYW4gYSBuZWFyIG5laWdoYm91cikgaXMgZGVsaWJlcmF0ZSAtIGEgZGVsaWJlcmF0ZSBlbmRwb2ludCBpZCBpcyBuZXZlclxuICogc2lsZW50bHkgcmV3cml0dGVuLCBhbmQgRGF0YWJyaWNrcyBzdXJmYWNlcyBhIGNsZWFuIDQwNC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJhbmtNb2RlbElkKFxuICBlbmRwb2ludHM6IHJlYWRvbmx5IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSxcbiAgc2VhcmNoOiBzdHJpbmcsXG4gIG9wdGlvbnM6IFJlc29sdmVNb2RlbE9wdGlvbnMgPSB7fSxcbik6IFJlc29sdmVkTW9kZWwge1xuICBjb25zdCBbdG9wXSA9IGxvb2t1cE1vZGVscyhlbmRwb2ludHMsIHtcbiAgICBzZWFyY2gsXG4gICAgbGltaXQ6IDEsXG4gICAgLi4uKG9wdGlvbnMudGhyZXNob2xkICE9PSB1bmRlZmluZWQgPyB7IHRocmVzaG9sZDogb3B0aW9ucy50aHJlc2hvbGQgfSA6IHt9KSxcbiAgICAuLi4ob3B0aW9ucy5yZXF1aXJlc1Rvb2xzICE9PSB1bmRlZmluZWQgPyB7IHJlcXVpcmVzVG9vbHM6IG9wdGlvbnMucmVxdWlyZXNUb29scyB9IDoge30pLFxuICB9KTtcbiAgaWYgKCF0b3ApIHJldHVybiB7IG1vZGVsSWQ6IHNlYXJjaCwgbWF0Y2hlZDogZmFsc2UgfTtcbiAgcmV0dXJuIHsgbW9kZWxJZDogdG9wLmVuZHBvaW50Lm5hbWUsIG1hdGNoZWQ6IHRydWUsIHNjb3JlOiB0b3Auc2NvcmUgfTtcbn1cblxuLyoqXG4gKiB7QGxpbmsgcmFua01vZGVsSWR9IGFnYWluc3QgYSBjYXRhbG9ndWUgdGhlIGNhbGxlciBtYXkgYmUgaG9sZGluZyBzdGFsZTpcbiAqIG1hdGNoIHRoZSBsb2FkZWQgc25hcHNob3QsIGFuZCBvbiBhIG1pc3MgcmVsb2FkIG9uY2Ugd2l0aCBgZm9yY2VgIGFuZCBtYXRjaFxuICogYWdhaW4uIFRoYXQgd2F5IGEgbW9kZWwgZGVwbG95ZWQgYWZ0ZXIgdGhlIGNhdGFsb2d1ZSB3YXMgY2FjaGVkIHN0aWxsXG4gKiByZXNvbHZlcyBvbiBmaXJzdCB1c2UsIHdpdGhvdXQgYSByZXN0YXJ0IGFuZCB3aXRob3V0IGdpdmluZyB1cCBjYWNoaW5nLlxuICpcbiAqIFRoZSBjYXRhbG9ndWUgYXJyaXZlcyBhcyBhIGxvYWRlciByYXRoZXIgdGhhbiBhIGNsaWVudCBzbyB0aGUgY2FsbGVyIGtlZXBzXG4gKiBvd25lcnNoaXAgb2YgKmhvdyogaXQgaXMgY2FjaGVkIC0ge0BsaW5rIGxpc3RTZXJ2aW5nRW5kcG9pbnRzfSBhbmQgaXRzXG4gKiBgQ2FjaGVNYW5hZ2VyYCwgYSBwbGFpbiBwcm9jZXNzLWxpZmV0aW1lIGZpZWxkIGluIGEgQ0xJLCBvciBhIHRlc3QgZG91YmxlLlxuICogT25seSBvbmUgcmVsb2FkIGlzIGF0dGVtcHRlZDogYSBnZW51aW5lbHkgdW5rbm93biBuYW1lIHNob3VsZCBmYWlsIGZhc3RcbiAqIHJhdGhlciB0aGFuIHJlLWxpc3Qgb24gZXZlcnkgcmVxdWVzdC5cbiAqXG4gKiBAcGFyYW0gbG9hZCAtIFJldHVybnMgdGhlIGNhdGFsb2d1ZTsgYGZvcmNlYCBhc2tzIGl0IHRvIGJ5cGFzcyBpdHMgY2FjaGUuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByYW5rTW9kZWxJZExpdmUoXG4gIGxvYWQ6IChmb3JjZTogYm9vbGVhbikgPT4gUHJvbWlzZTxyZWFkb25seSBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5W10+LFxuICBzZWFyY2g6IHN0cmluZyxcbiAgb3B0aW9uczogUmVzb2x2ZU1vZGVsT3B0aW9ucyA9IHt9LFxuKTogUHJvbWlzZTxSZXNvbHZlZE1vZGVsPiB7XG4gIGNvbnN0IHJlc29sdmVkID0gcmFua01vZGVsSWQoYXdhaXQgbG9hZChmYWxzZSksIHNlYXJjaCwgb3B0aW9ucyk7XG4gIGlmIChyZXNvbHZlZC5tYXRjaGVkKSByZXR1cm4gcmVzb2x2ZWQ7XG4gIHJldHVybiByYW5rTW9kZWxJZChhd2FpdCBsb2FkKHRydWUpLCBzZWFyY2gsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFJhbmsgYSB3b3Jrc3BhY2UncyBjYXRhbG9ndWUgaW4gb25lIGNhbGw6IGxpc3QgaXRzIGAvc2VydmluZy1lbmRwb2ludHNgXG4gKiAoY2FjaGVkKSBhbmQgcnVuIHtAbGluayBsb29rdXBNb2RlbHN9IG92ZXIgdGhlIHJlc3VsdC4gVGhlIGxpc3QgY291bnRlcnBhcnQgdG9cbiAqIHtAbGluayBzZWxlY3RNb2RlbH0sIGZvciBhIGNvbnN1bWVyIHRoYXQgd2FudHMgdGhlIGZ1bGwgcmFua2VkIHNldCAoYSBtb2RlbFxuICogcGlja2VyLCBhIENMSSkgcmF0aGVyIHRoYW4gYSBzaW5nbGUgaWQuIENhdGFsb2d1ZSBmZXRjaGVzIGZhaWwgbG91ZDogbmV0d29ya1xuICogLyBhdXRoIGVycm9ycyBwcm9wYWdhdGUgc28gdGhlIGNhbGxlciBzZWVzIHRoZSByZWFsIFNESyBtZXNzYWdlLlxuICpcbiAqIEBwYXJhbSBob3N0IC0gV29ya3NwYWNlIGhvc3QgdXNlZCBhcyB0aGUgY2FjaGUga2V5LiBQYXNzIHRoZSB2YWx1ZSByZXNvbHZlZFxuICogICBmcm9tIGBjbGllbnQuY29uZmlnLmdldEhvc3QoKWAuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZWFyY2hNb2RlbHMoXG4gIGNsaWVudDogV29ya3NwYWNlQ2xpZW50TGlrZSxcbiAgaG9zdDogc3RyaW5nLFxuICBpbnB1dDogU2VhcmNoTW9kZWxzSW5wdXQgPSB7fSxcbik6IFByb21pc2U8UmFua2VkTW9kZWxbXT4ge1xuICBjb25zdCBlbmRwb2ludHMgPSBhd2FpdCBsaXN0U2VydmluZ0VuZHBvaW50cyhjbGllbnQsIGhvc3QsIHtcbiAgICAuLi4oaW5wdXQudHRsTXMgIT09IHVuZGVmaW5lZCA/IHsgdHRsTXM6IGlucHV0LnR0bE1zIH0gOiB7fSksXG4gICAgLi4uKGlucHV0LmNhY2hlSWRlbnRpdHkgIT09IHVuZGVmaW5lZCA/IHsgY2FjaGVJZGVudGl0eTogaW5wdXQuY2FjaGVJZGVudGl0eSB9IDoge30pLFxuICB9KTtcbiAgcmV0dXJuIGxvb2t1cE1vZGVscyhlbmRwb2ludHMsIGlucHV0KTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgbW9kZWwgaWQgZm9yIGEgd29ya3NwYWNlIGluIG9uZSBjYWxsOiBsaXN0IGl0cyBgL3NlcnZpbmctZW5kcG9pbnRzYFxuICogKGNhY2hlZCkgYW5kIHJ1biB7QGxpbmsgcmVzb2x2ZU1vZGVsfSBvdmVyIHRoZSByZXN1bHQuIFRoaXMgaXMgdGhlIGVudHJ5XG4gKiBwb2ludCBmb3IgYW55IGNvbnN1bWVyIHRoYXQgaG9sZHMgYSBgV29ya3NwYWNlQ2xpZW50YCBhbmQganVzdCB3YW50cyBhIHVzYWJsZVxuICogbW9kZWwgbmFtZSAtIGEgTGFrZWZsb3cgam9iLCBhIG9uZS1vZmYgc2NyaXB0LCBvciB0aGUgTWFzdHJhIHBsdWdpbiBhbGlrZS5cbiAqXG4gKiBDaGVhcCBleGl0OiB3aGVuIGFuIGBleHBsaWNpdGAgbmFtZSBpcyBnaXZlbiwgYGZ1enp5YCBpcyBvZmYsIGFuZCB0b29sXG4gKiBjYXBhYmlsaXR5IGlzIG5vdCByZXF1aXJlZCwgdGhlIGNhdGFsb2d1ZSBpcyBuZXZlciBmZXRjaGVkLiBDYXRhbG9ndWVcbiAqIGZldGNoZXMgb3RoZXJ3aXNlIGZhaWwgbG91ZDogbmV0d29yayAvIGF1dGggZXJyb3JzIHByb3BhZ2F0ZSBzbyB0aGUgY2FsbGVyXG4gKiBzZWVzIHRoZSByZWFsIFNESyBtZXNzYWdlIGluc3RlYWQgb2YgYSBzaWxlbnQgZmFsbGJhY2suXG4gKlxuICogQHBhcmFtIGhvc3QgLSBXb3Jrc3BhY2UgaG9zdCB1c2VkIGFzIHRoZSBjYWNoZSBrZXkuIFBhc3MgdGhlIHZhbHVlIHJlc29sdmVkXG4gKiAgIGZyb20gYGNsaWVudC5jb25maWcuZ2V0SG9zdCgpYC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlbGVjdE1vZGVsKFxuICBjbGllbnQ6IFdvcmtzcGFjZUNsaWVudExpa2UsXG4gIGhvc3Q6IHN0cmluZyxcbiAgaW5wdXQ6IFNlbGVjdE1vZGVsSW5wdXQgPSB7fSxcbik6IFByb21pc2U8UmVzb2x2ZWRNb2RlbFNlbGVjdGlvbj4ge1xuICBpZiAoaW5wdXQuZXhwbGljaXQgIT09IHVuZGVmaW5lZCAmJiBpbnB1dC5mdXp6eSA9PT0gZmFsc2UgJiYgIWlucHV0LnJlcXVpcmVzVG9vbHMpIHtcbiAgICByZXR1cm4geyBtb2RlbElkOiBpbnB1dC5leHBsaWNpdCwgc291cmNlOiBcImV4cGxpY2l0XCIgfTtcbiAgfVxuICBjb25zdCBlbmRwb2ludHMgPSBhd2FpdCBsaXN0U2VydmluZ0VuZHBvaW50cyhjbGllbnQsIGhvc3QsIHtcbiAgICAuLi4oaW5wdXQudHRsTXMgIT09IHVuZGVmaW5lZCA/IHsgdHRsTXM6IGlucHV0LnR0bE1zIH0gOiB7fSksXG4gICAgLi4uKGlucHV0LmNhY2hlSWRlbnRpdHkgIT09IHVuZGVmaW5lZCA/IHsgY2FjaGVJZGVudGl0eTogaW5wdXQuY2FjaGVJZGVudGl0eSB9IDoge30pLFxuICB9KTtcbiAgcmV0dXJuIHJlc29sdmVNb2RlbChlbmRwb2ludHMsIGlucHV0KTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgc2luZ2xlIG1vZGVsIGlkIGZyb20gdGhlIGxpdmUgY2F0YWxvZ3VlIGFuZCBjYWxsZXIgaW50ZW50LFxuICogZGVsZWdhdGluZyB0aGUgbGl2ZSBzZWxlY3Rpb24gdG8ge0BsaW5rIGxvb2t1cE1vZGVsc30gd2l0aCBgbGltaXQ6IDFgLlxuICpcbiAqIDEuICoqRXhwbGljaXQgYXNrKio6IHdpdGggYGZ1enp5YCBvZmYsIHJldHVybmVkIHZlcmJhdGltOyBvdGhlcndpc2VcbiAqICAgIGZ1enp5LXJhbmtlZCB3aXRoaW4gdGhlIChvcHRpb25hbCkgY2xhc3MgY2VpbGluZyBhbmQgdGhlIGJlc3QgdGFrZW4sXG4gKiAgICBmYWxsaW5nIGJhY2sgdG8gdGhlIGlucHV0IHZlcmJhdGltIHdoZW4gbm90aGluZyBtYXRjaGVzLlxuICogMi4gKipObyBleHBsaWNpdCBhc2sqKjogYW4gb3BlcmF0b3ItcGlubmVkIGBmYWxsYmFja2AgdGhhdCBleGlzdHMgaW4gdGhlIGxpdmVcbiAqICAgIGNhdGFsb2d1ZSB3aW5zIGZpcnN0LiBBIGNsYXNzIHJlcXVlc3QgcmFua3Mgd2l0aGluIHRoYXQgY2VpbGluZy4gQVxuICogICAgZ2VuZXJhbCByZXF1ZXN0IHByZWZlcnMgdGhlIGhpZ2hlc3QtcmFua2VkIGxpdmUgR1BULCB0aGVuIGFueSByYW5rZWQgbGl2ZVxuICogICAgY2hhdCBtb2RlbC4gVGhlIHN0YXRpYyB7QGxpbmsgRkFMTEJBQ0tfTU9ERUxfSURTfSBmbG9vciBpcyB1c2VkIG9ubHkgd2hlblxuICogICAgdGhlIGNhdGFsb2d1ZSB5aWVsZHMgbm90aGluZyBpbiByYW5nZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVNb2RlbChcbiAgZW5kcG9pbnRzOiByZWFkb25seSBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5W10sXG4gIGlucHV0OiBSZXNvbHZlTW9kZWxJbnB1dCA9IHt9LFxuKTogUmVzb2x2ZWRNb2RlbFNlbGVjdGlvbiB7XG4gIGlmIChpbnB1dC5leHBsaWNpdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgaWYgKGlucHV0LmZ1enp5ID09PSBmYWxzZSkge1xuICAgICAgaWYgKGlucHV0LnJlcXVpcmVzVG9vbHMpIGFzc2VydFRvb2xTdXBwb3J0KGVuZHBvaW50cywgaW5wdXQuZXhwbGljaXQpO1xuICAgICAgcmV0dXJuIHsgbW9kZWxJZDogaW5wdXQuZXhwbGljaXQsIHNvdXJjZTogXCJleHBsaWNpdFwiIH07XG4gICAgfVxuICAgIGNvbnN0IFt0b3BdID0gbG9va3VwTW9kZWxzKGVuZHBvaW50cywgYnVpbGRRdWVyeShpbnB1dCwgaW5wdXQuZXhwbGljaXQpKTtcbiAgICBpZiAoaW5wdXQucmVxdWlyZXNUb29scyAmJiAhdG9wKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIHRvb2wtY2FwYWJsZSBtb2RlbCBtYXRjaGVzIFwiJHtpbnB1dC5leHBsaWNpdH1cImApO1xuICAgIH1cbiAgICByZXR1cm4geyBtb2RlbElkOiB0b3A/LmVuZHBvaW50Lm5hbWUgPz8gaW5wdXQuZXhwbGljaXQsIHNvdXJjZTogXCJmdXp6eS1tYXRjaFwiIH07XG4gIH1cblxuICAvLyBPcGVyYXRvci1waW5uZWQgZmFsbGJhY2tzIHdpbiB3aGVuIHByZXNlbnQgYW5kIGxpdmUgKGUuZy4gYSByZWd1bGF0ZWRcbiAgLy8gd29ya3NwYWNlIHJlc3RyaWN0ZWQgdG8gYW4gYXBwcm92ZWQgc3Vic2V0KS5cbiAgaWYgKGlucHV0Lm1vZGVsQ2xhc3MgPT09IHVuZGVmaW5lZCAmJiBpbnB1dC5mYWxsYmFja3MgJiYgaW5wdXQuZmFsbGJhY2tzLmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCBwcmVzZW50ID0gbmV3IFNldChcbiAgICAgIGVuZHBvaW50c1xuICAgICAgICAuZmlsdGVyKChlbmRwb2ludCkgPT4gIWlucHV0LnJlcXVpcmVzVG9vbHMgfHwgZW5kcG9pbnRTdXBwb3J0c1Rvb2xzKGVuZHBvaW50KSlcbiAgICAgICAgLm1hcCgoZW5kcG9pbnQpID0+IGVuZHBvaW50Lm5hbWUpLFxuICAgICk7XG4gICAgY29uc3QgcGlubmVkID0gaW5wdXQuZmFsbGJhY2tzLmZpbmQoKGlkKSA9PiBwcmVzZW50LmhhcyhpZCkpO1xuICAgIGlmIChwaW5uZWQpIHJldHVybiB7IG1vZGVsSWQ6IHBpbm5lZCwgc291cmNlOiBcImZhbGxiYWNrXCIgfTtcbiAgfVxuXG4gIGNvbnN0IHNvdXJjZSA9IGlucHV0Lm1vZGVsQ2xhc3MgIT09IHVuZGVmaW5lZCA/IFwiY2xhc3NcIiA6IFwiZmFsbGJhY2tcIjtcbiAgaWYgKGlucHV0Lm1vZGVsQ2xhc3MgPT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IFtwcmVmZXJyZWRdID0gbG9va3VwTW9kZWxzKGVuZHBvaW50cywgYnVpbGRRdWVyeShpbnB1dCwgREVGQVVMVF9NT0RFTF9GQU1JTFlfU0VBUkNIKSk7XG4gICAgaWYgKHByZWZlcnJlZCkgcmV0dXJuIHsgbW9kZWxJZDogcHJlZmVycmVkLmVuZHBvaW50Lm5hbWUsIHNvdXJjZSB9O1xuICB9XG4gIGNvbnN0IFt0b3BdID0gbG9va3VwTW9kZWxzKGVuZHBvaW50cywgYnVpbGRRdWVyeShpbnB1dCwgdW5kZWZpbmVkKSk7XG4gIGlmICh0b3ApIHJldHVybiB7IG1vZGVsSWQ6IHRvcC5lbmRwb2ludC5uYW1lLCBzb3VyY2UgfTtcblxuICBpZiAoaW5wdXQubGl2ZU9ubHkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyBtYXRjaGluZyBsaXZlIE1vZGVsIFNlcnZpbmcgZW5kcG9pbnQgaXMgYXZhaWxhYmxlXCIpO1xuICB9XG5cbiAgLy8gTGl2ZSBjYXRhbG9ndWUgeWllbGRlZCBub3RoaW5nIGluIHJhbmdlOiB3YWxrIHRoZSBzdGF0aWMgZmxvb3IuXG4gIGNvbnN0IGZsb29yU291cmNlID1cbiAgICBpbnB1dC5tb2RlbENsYXNzICE9PSB1bmRlZmluZWQgPyBtb2RlbHNGb3JDbGFzcyhpbnB1dC5tb2RlbENsYXNzKSA6IChpbnB1dC5mYWxsYmFja3MgPz8gW10pO1xuICBjb25zdCBmbG9vciA9IG9iamVjdC5zZXF1ZW5jZShmbG9vclNvdXJjZSkuY29uY2F0KEZBTExCQUNLX01PREVMX0lEUykuZGlzdGluY3QoKS50b0FycmF5KCk7XG4gIGlmIChpbnB1dC5yZXF1aXJlc1Rvb2xzKSB7XG4gICAgY29uc3QgYXZhaWxhYmxlID0gbmV3IFNldChcbiAgICAgIGVuZHBvaW50cy5maWx0ZXIoZW5kcG9pbnRTdXBwb3J0c1Rvb2xzKS5tYXAoKGVuZHBvaW50KSA9PiBlbmRwb2ludC5uYW1lKSxcbiAgICApO1xuICAgIGNvbnN0IHNlbGVjdGVkID0gZmxvb3IuZmluZCgoaWQpID0+IGF2YWlsYWJsZS5oYXMoaWQpKTtcbiAgICBpZiAoIXNlbGVjdGVkKSB0aHJvdyBuZXcgRXJyb3IoXCJObyB0b29sLWNhcGFibGUgbW9kZWwgaXMgYXZhaWxhYmxlXCIpO1xuICAgIHJldHVybiB7IG1vZGVsSWQ6IHNlbGVjdGVkLCBzb3VyY2UgfTtcbiAgfVxuICByZXR1cm4geyBtb2RlbElkOiBwaWNrRmlyc3RBdmFpbGFibGUoZmxvb3IsIGVuZHBvaW50cyksIHNvdXJjZSB9O1xufVxuXG4vKiogQnVpbGQgYSB7QGxpbmsgTW9kZWxRdWVyeX0gZnJvbSB7QGxpbmsgUmVzb2x2ZU1vZGVsSW5wdXR9IGZvciB0aGUgYGxpbWl0OiAxYCBkZWxlZ2F0aW9uLiAqL1xuZnVuY3Rpb24gYnVpbGRRdWVyeShpbnB1dDogUmVzb2x2ZU1vZGVsSW5wdXQsIHNlYXJjaDogc3RyaW5nIHwgdW5kZWZpbmVkKTogTW9kZWxRdWVyeSB7XG4gIHJldHVybiB7XG4gICAgLi4uKHNlYXJjaCAhPT0gdW5kZWZpbmVkID8geyBzZWFyY2ggfSA6IHt9KSxcbiAgICAuLi4oaW5wdXQubW9kZWxDbGFzcyAhPT0gdW5kZWZpbmVkID8geyBtb2RlbENsYXNzOiBpbnB1dC5tb2RlbENsYXNzIH0gOiB7fSksXG4gICAgLi4uKGlucHV0LnJlcXVpcmVzVG9vbHMgIT09IHVuZGVmaW5lZCA/IHsgcmVxdWlyZXNUb29sczogaW5wdXQucmVxdWlyZXNUb29scyB9IDoge30pLFxuICAgIC4uLihpbnB1dC50aHJlc2hvbGQgIT09IHVuZGVmaW5lZCA/IHsgdGhyZXNob2xkOiBpbnB1dC50aHJlc2hvbGQgfSA6IHt9KSxcbiAgICBsaW1pdDogMSxcbiAgfTtcbn1cblxuLyoqIFRocm93IHdoZW4gYW4gZXhwbGljaXQgaWQgaXMgYWJzZW50IG9yIG5vdCB2ZXJpZmllZCBmb3IgZnVuY3Rpb24gdG9vbHMuICovXG5mdW5jdGlvbiBhc3NlcnRUb29sU3VwcG9ydChlbmRwb2ludHM6IHJlYWRvbmx5IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSwgbW9kZWxJZDogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IGVuZHBvaW50ID0gZW5kcG9pbnRzLmZpbmQoKGNhbmRpZGF0ZSkgPT4gY2FuZGlkYXRlLm5hbWUgPT09IG1vZGVsSWQpO1xuICBpZiAoIWVuZHBvaW50IHx8ICFlbmRwb2ludFN1cHBvcnRzVG9vbHMoZW5kcG9pbnQpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBNb2RlbCBcIiR7bW9kZWxJZH1cIiBkb2VzIG5vdCBzdXBwb3J0IGZ1bmN0aW9uIHRvb2xzYCk7XG4gIH1cbn1cblxuLyoqXG4gKiBGaW5kIHRoZSBmaXJzdCBpZCBpbiBgY2FuZGlkYXRlc2Agd2hvc2UgZW5kcG9pbnQgaXMgcHJlc2VudCBpbiBgZW5kcG9pbnRzYC5cbiAqIFJldHVybnMgdGhlIHRvcCBjYW5kaWRhdGUgd2hlbiB0aGUgd29ya3NwYWNlIGhhcyBub25lIG9mIHRoZW0gc28gY2FsbGVyc1xuICogYWx3YXlzIGdldCBhIHN0cmluZzsgYW4gb2ZmbGluZSB3b3Jrc3BhY2UgdGhlbiByZWNlaXZlcyBhIGNsZWFuIDQwNCBmcm9tXG4gKiBEYXRhYnJpY2tzIGluc3RlYWQgb2YgYSBtYWxmb3JtZWQgY29uZmlnLlxuICovXG5mdW5jdGlvbiBwaWNrRmlyc3RBdmFpbGFibGUoXG4gIGNhbmRpZGF0ZXM6IHJlYWRvbmx5IHN0cmluZ1tdLFxuICBlbmRwb2ludHM6IHJlYWRvbmx5IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSxcbik6IHN0cmluZyB7XG4gIGNvbnN0IHByZXNlbnQgPSBuZXcgU2V0KGVuZHBvaW50cy5tYXAoKGUpID0+IGUubmFtZSkpO1xuICBmb3IgKGNvbnN0IGNhbmRpZGF0ZSBvZiBjYW5kaWRhdGVzKSB7XG4gICAgaWYgKHByZXNlbnQuaGFzKGNhbmRpZGF0ZSkpIHJldHVybiBjYW5kaWRhdGU7XG4gIH1cbiAgcmV0dXJuIGNhbmRpZGF0ZXNbMF0gPz8gRkFMTEJBQ0tfTU9ERUxfSURTWzBdITtcbn1cbiJdfQ==
|
|
30
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzb2x2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9yZXNvbHZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQU9BLE9BQU8sRUFDTCxZQUFZLEVBQ1osV0FBVyxFQUdYLFlBQVksR0FDYixNQUFNLGlCQUFpQixDQUFDO0FBQ3pCLE9BQU8sRUFDTCxvQkFBb0IsR0FLckIsTUFBTSxvQkFBb0IsQ0FBQztBQUU1QixPQUFPLEVBQUUsWUFBWSxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQWUxRSxnRkFBZ0Y7QUFDaEYsTUFBTSxDQUFDLEtBQUssVUFBVSxlQUFlLENBQ25DLElBQW9FLEVBQ3BFLE1BQWMsRUFDZCxVQUErQixFQUFFO0lBRWpDLE1BQU0sUUFBUSxHQUFHLFdBQVcsQ0FBQyxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDakUsSUFBSSxRQUFRLENBQUMsT0FBTztRQUFFLE9BQU8sUUFBUSxDQUFDO0lBQ3RDLE9BQU8sV0FBVyxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztBQUN4RCxDQUFDO0FBRUQsaURBQWlEO0FBQ2pELE1BQU0sQ0FBQyxLQUFLLFVBQVUsWUFBWSxDQUNoQyxNQUEyQixFQUMzQixJQUFZLEVBQ1osUUFBMkIsRUFBRTtJQUU3QixNQUFNLFNBQVMsR0FBRyxNQUFNLG9CQUFvQixDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUNwRixPQUFPLFlBQVksQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDeEMsQ0FBQztBQUVELHdEQUF3RDtBQUN4RCxNQUFNLENBQUMsS0FBSyxVQUFVLFdBQVcsQ0FDL0IsTUFBMkIsRUFDM0IsSUFBWSxFQUNaLFFBQTBCLEVBQUU7SUFFNUIsSUFBSSxLQUFLLENBQUMsUUFBUSxLQUFLLFNBQVMsSUFBSSxLQUFLLENBQUMsS0FBSyxLQUFLLEtBQUssSUFBSSxDQUFDLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUNsRixPQUFPLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxDQUFDO0lBQ3pELENBQUM7SUFDRCxNQUFNLFNBQVMsR0FBRyxNQUFNLG9CQUFvQixDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUNwRixPQUFPLFlBQVksQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDeEMsQ0FBQztBQUVELFNBQVMsZ0JBQWdCLENBQUMsS0FHekI7SUFDQyxPQUFPO1FBQ0wsR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFLLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM1RCxHQUFHLENBQUMsS0FBSyxDQUFDLGFBQWEsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsYUFBYSxFQUFFLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQ3JGLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBXb3Jrc3BhY2UtYXdhcmUgbW9kZWwgc2VsZWN0aW9uIHdyYXBwZXJzLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuaW1wb3J0IHR5cGUgeyBNb2RlbFF1ZXJ5LCBSYW5rZWRNb2RlbCwgU2VydmluZ0VuZHBvaW50U3VtbWFyeSB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1tb2RlbFwiO1xuXG5pbXBvcnQge1xuICBsb29rdXBNb2RlbHMsXG4gIHJhbmtNb2RlbElkLFxuICB0eXBlIFJlc29sdmVNb2RlbElucHV0LFxuICB0eXBlIFJlc29sdmVkTW9kZWxTZWxlY3Rpb24sXG4gIHJlc29sdmVNb2RlbCxcbn0gZnJvbSBcIi4vX3NlbGVjdGlvbi50c1wiO1xuaW1wb3J0IHtcbiAgbGlzdFNlcnZpbmdFbmRwb2ludHMsXG4gIHR5cGUgTGlzdFNlcnZpbmdFbmRwb2ludHNPcHRpb25zLFxuICB0eXBlIFJlc29sdmVkTW9kZWwsXG4gIHR5cGUgUmVzb2x2ZU1vZGVsT3B0aW9ucyxcbiAgdHlwZSBXb3Jrc3BhY2VDbGllbnRMaWtlLFxufSBmcm9tIFwiLi9tb2RlbC1jYXRhbG9nLnRzXCI7XG5cbmV4cG9ydCB7IGxvb2t1cE1vZGVscywgcmFua01vZGVsSWQsIHJlc29sdmVNb2RlbCB9IGZyb20gXCIuL19zZWxlY3Rpb24udHNcIjtcbmV4cG9ydCB0eXBlIHsgUmVzb2x2ZU1vZGVsSW5wdXQsIFJlc29sdmVkTW9kZWxTZWxlY3Rpb24gfSBmcm9tIFwiLi9fc2VsZWN0aW9uLnRzXCI7XG5cbi8qKiBJbnRlbnQgcGx1cyBjYXRhbG9ndWUgY2FjaGUgY29udHJvbHMgcGFzc2VkIHRvIHtAbGluayBzZWxlY3RNb2RlbH0uICovXG5leHBvcnQgaW50ZXJmYWNlIFNlbGVjdE1vZGVsSW5wdXQgZXh0ZW5kcyBSZXNvbHZlTW9kZWxJbnB1dCB7XG4gIHR0bE1zPzogbnVtYmVyO1xuICBjYWNoZUlkZW50aXR5Pzogc3RyaW5nO1xufVxuXG4vKiogUXVlcnkgcGx1cyBjYXRhbG9ndWUgY2FjaGUgY29udHJvbHMgcGFzc2VkIHRvIHtAbGluayBzZWFyY2hNb2RlbHN9LiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZWFyY2hNb2RlbHNJbnB1dCBleHRlbmRzIE1vZGVsUXVlcnkge1xuICB0dGxNcz86IG51bWJlcjtcbiAgY2FjaGVJZGVudGl0eT86IHN0cmluZztcbn1cblxuLyoqIFJlc29sdmUgYWdhaW5zdCBhIHBvdGVudGlhbGx5IHN0YWxlIGNhdGFsb2d1ZSwgcmVmcmVzaGluZyBvbmNlIG9uIGEgbWlzcy4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByYW5rTW9kZWxJZExpdmUoXG4gIGxvYWQ6IChmb3JjZTogYm9vbGVhbikgPT4gUHJvbWlzZTxyZWFkb25seSBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5W10+LFxuICBzZWFyY2g6IHN0cmluZyxcbiAgb3B0aW9uczogUmVzb2x2ZU1vZGVsT3B0aW9ucyA9IHt9LFxuKTogUHJvbWlzZTxSZXNvbHZlZE1vZGVsPiB7XG4gIGNvbnN0IHJlc29sdmVkID0gcmFua01vZGVsSWQoYXdhaXQgbG9hZChmYWxzZSksIHNlYXJjaCwgb3B0aW9ucyk7XG4gIGlmIChyZXNvbHZlZC5tYXRjaGVkKSByZXR1cm4gcmVzb2x2ZWQ7XG4gIHJldHVybiByYW5rTW9kZWxJZChhd2FpdCBsb2FkKHRydWUpLCBzZWFyY2gsIG9wdGlvbnMpO1xufVxuXG4vKiogTGlzdCBhbmQgcmFuayBhIHdvcmtzcGFjZSBtb2RlbCBjYXRhbG9ndWUuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2VhcmNoTW9kZWxzKFxuICBjbGllbnQ6IFdvcmtzcGFjZUNsaWVudExpa2UsXG4gIGhvc3Q6IHN0cmluZyxcbiAgaW5wdXQ6IFNlYXJjaE1vZGVsc0lucHV0ID0ge30sXG4pOiBQcm9taXNlPFJhbmtlZE1vZGVsW10+IHtcbiAgY29uc3QgZW5kcG9pbnRzID0gYXdhaXQgbGlzdFNlcnZpbmdFbmRwb2ludHMoY2xpZW50LCBob3N0LCBjYXRhbG9ndWVPcHRpb25zKGlucHV0KSk7XG4gIHJldHVybiBsb29rdXBNb2RlbHMoZW5kcG9pbnRzLCBpbnB1dCk7XG59XG5cbi8qKiBMaXN0IGEgd29ya3NwYWNlIGNhdGFsb2d1ZSBhbmQgcmVzb2x2ZSBvbmUgbW9kZWwuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2VsZWN0TW9kZWwoXG4gIGNsaWVudDogV29ya3NwYWNlQ2xpZW50TGlrZSxcbiAgaG9zdDogc3RyaW5nLFxuICBpbnB1dDogU2VsZWN0TW9kZWxJbnB1dCA9IHt9LFxuKTogUHJvbWlzZTxSZXNvbHZlZE1vZGVsU2VsZWN0aW9uPiB7XG4gIGlmIChpbnB1dC5leHBsaWNpdCAhPT0gdW5kZWZpbmVkICYmIGlucHV0LmZ1enp5ID09PSBmYWxzZSAmJiAhaW5wdXQucmVxdWlyZXNUb29scykge1xuICAgIHJldHVybiB7IG1vZGVsSWQ6IGlucHV0LmV4cGxpY2l0LCBzb3VyY2U6IFwiZXhwbGljaXRcIiB9O1xuICB9XG4gIGNvbnN0IGVuZHBvaW50cyA9IGF3YWl0IGxpc3RTZXJ2aW5nRW5kcG9pbnRzKGNsaWVudCwgaG9zdCwgY2F0YWxvZ3VlT3B0aW9ucyhpbnB1dCkpO1xuICByZXR1cm4gcmVzb2x2ZU1vZGVsKGVuZHBvaW50cywgaW5wdXQpO1xufVxuXG5mdW5jdGlvbiBjYXRhbG9ndWVPcHRpb25zKGlucHV0OiB7XG4gIHJlYWRvbmx5IHR0bE1zPzogbnVtYmVyO1xuICByZWFkb25seSBjYWNoZUlkZW50aXR5Pzogc3RyaW5nO1xufSk6IExpc3RTZXJ2aW5nRW5kcG9pbnRzT3B0aW9ucyB7XG4gIHJldHVybiB7XG4gICAgLi4uKGlucHV0LnR0bE1zICE9PSB1bmRlZmluZWQgPyB7IHR0bE1zOiBpbnB1dC50dGxNcyB9IDoge30pLFxuICAgIC4uLihpbnB1dC5jYWNoZUlkZW50aXR5ICE9PSB1bmRlZmluZWQgPyB7IGNhY2hlSWRlbnRpdHk6IGlucHV0LmNhY2hlSWRlbnRpdHkgfSA6IHt9KSxcbiAgfTtcbn1cbiJdfQ==
|
package/lib/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/
|
|
1
|
+
{"root":["../src/_metadata-contract.ts","../src/_metadata-generator.ts","../src/_ranking.ts","../src/_selection.ts","../src/classes.ts","../src/classify.ts","../src/fallback.ts","../src/invoke.ts","../src/metadata.ts","../src/model-catalog.ts","../src/model-client.ts","../src/policy.ts","../src/python.ts","../src/resolve.ts","../index.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
|
@@ -21,14 +21,16 @@
|
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/bun": "1.3.14",
|
|
23
23
|
"@types/node": "^24.6.0",
|
|
24
|
+
"cheerio": "^1.2.0",
|
|
24
25
|
"typescript": "^5.9.3"
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
28
|
"@databricks/appkit": "0.81.0",
|
|
28
|
-
"@dbx-tools/appkit": "^0.9.
|
|
29
|
-
"@dbx-tools/
|
|
30
|
-
"@dbx-tools/shared-core": "^0.9.
|
|
31
|
-
"@dbx-tools/shared-model": "^0.9.
|
|
29
|
+
"@dbx-tools/appkit": "^0.9.29",
|
|
30
|
+
"@dbx-tools/auth": "^0.9.29",
|
|
31
|
+
"@dbx-tools/shared-core": "^0.9.29",
|
|
32
|
+
"@dbx-tools/shared-model": "^0.9.29",
|
|
33
|
+
"fuse.js": "^7.4.2"
|
|
32
34
|
},
|
|
33
35
|
"main": "./lib/index.js",
|
|
34
36
|
"license": "Apache-2.0",
|
|
@@ -41,10 +43,14 @@
|
|
|
41
43
|
"types": "./lib/index.d.ts",
|
|
42
44
|
"default": "./lib/index.js"
|
|
43
45
|
},
|
|
46
|
+
"./python": {
|
|
47
|
+
"types": "./lib/src/python.d.ts",
|
|
48
|
+
"default": "./lib/src/python.js"
|
|
49
|
+
},
|
|
44
50
|
"./package.json": "./package.json"
|
|
45
51
|
}
|
|
46
52
|
},
|
|
47
|
-
"version": "0.9.
|
|
53
|
+
"version": "0.9.29",
|
|
48
54
|
"types": "./lib/index.d.ts",
|
|
49
55
|
"type": "module",
|
|
50
56
|
"exports": {
|
|
@@ -52,6 +58,10 @@
|
|
|
52
58
|
"types": "./lib/index.d.ts",
|
|
53
59
|
"default": "./lib/index.js"
|
|
54
60
|
},
|
|
61
|
+
"./python": {
|
|
62
|
+
"types": "./lib/src/python.d.ts",
|
|
63
|
+
"default": "./lib/src/python.js"
|
|
64
|
+
},
|
|
55
65
|
"./package.json": "./package.json"
|
|
56
66
|
},
|
|
57
67
|
"files": [
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** One day, matching the refresh cadence of Databricks model documentation. */
|
|
2
|
+
export const MODEL_METADATA_TTL_MS = 24 * 60 * 60 * 1000;
|
|
3
|
+
|
|
4
|
+
/** Databricks documentation URL for retired foundation models. */
|
|
5
|
+
export const RETIRED_MODELS_URL =
|
|
6
|
+
"https://docs.databricks.com/aws/en/machine-learning/retired-models-policy";
|
|
7
|
+
|
|
8
|
+
/** Databricks documentation URL for OpenAI Responses model support. */
|
|
9
|
+
export const OPENAI_RESPONSES_MODELS_URL =
|
|
10
|
+
"https://docs.databricks.com/aws/en/machine-learning/model-serving/query-openai-responses";
|
|
11
|
+
|
|
12
|
+
/** Databricks documentation URL for native web-search model support. */
|
|
13
|
+
export const WEB_SEARCH_MODELS_URL =
|
|
14
|
+
"https://docs.databricks.com/aws/en/machine-learning/model-serving/web-search";
|
|
15
|
+
|
|
16
|
+
/** Databricks documentation URL for Foundation Model API limits. */
|
|
17
|
+
export const MODEL_RATE_LIMITS_URL =
|
|
18
|
+
"https://docs.databricks.com/aws/en/machine-learning/foundation-model-apis/limits";
|
|
19
|
+
|
|
20
|
+
/** Build-generated retired-model snapshot. */
|
|
21
|
+
export interface RetiredModelsSnapshot {
|
|
22
|
+
readonly generatedAt: number;
|
|
23
|
+
readonly models: readonly string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Normalized model identities grouped by documented capability. */
|
|
27
|
+
export interface ModelCapabilityCatalogue {
|
|
28
|
+
readonly responses: readonly string[];
|
|
29
|
+
readonly imageInput: readonly string[];
|
|
30
|
+
readonly applyPatch: readonly string[];
|
|
31
|
+
readonly webSearch: readonly string[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Build-generated model-capability snapshot. */
|
|
35
|
+
export interface ModelCapabilitiesSnapshot {
|
|
36
|
+
readonly generatedAt: number;
|
|
37
|
+
readonly capabilities: ModelCapabilityCatalogue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Published pay-per-token limits for one model. */
|
|
41
|
+
export interface ModelRateLimits {
|
|
42
|
+
readonly inputTokensPerMinute: number | null;
|
|
43
|
+
readonly outputTokensPerMinute: number | null;
|
|
44
|
+
readonly queriesPerHour: number | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Model limits keyed by normalized Databricks model identity. */
|
|
48
|
+
export interface ModelRateLimitCatalogue {
|
|
49
|
+
readonly models: Readonly<Record<string, ModelRateLimits>>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Build-generated model-rate-limit snapshot. */
|
|
53
|
+
export interface ModelRateLimitsSnapshot {
|
|
54
|
+
readonly generatedAt: number;
|
|
55
|
+
readonly catalogue: ModelRateLimitCatalogue;
|
|
56
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { load, type CheerioAPI } from "cheerio";
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
ModelCapabilitiesSnapshot,
|
|
5
|
+
ModelRateLimitCatalogue,
|
|
6
|
+
ModelRateLimitsSnapshot,
|
|
7
|
+
RetiredModelsSnapshot,
|
|
8
|
+
} from "./_metadata-contract.ts";
|
|
9
|
+
import { modelSearchQuery } from "./policy.ts";
|
|
10
|
+
|
|
11
|
+
type Selection = ReturnType<CheerioAPI>;
|
|
12
|
+
|
|
13
|
+
/** Parse retired model names from Databricks retirement-policy HTML. */
|
|
14
|
+
export function parseRetiredModels(html: string, generatedAt: number): RetiredModelsSnapshot {
|
|
15
|
+
const $ = load(html);
|
|
16
|
+
const models = new Set<string>();
|
|
17
|
+
$("table").each((_, table) => {
|
|
18
|
+
const rows = $(table).find("tr");
|
|
19
|
+
const header = collapseText($(rows.get(0)).find("th, td").first()).toLowerCase();
|
|
20
|
+
if (header !== "open model" && header !== "partner model") return;
|
|
21
|
+
rows.slice(1).each((__, row) => {
|
|
22
|
+
for (const name of collapseText($(row).find("th, td").first()).split("/")) {
|
|
23
|
+
const trimmed = name.trim();
|
|
24
|
+
if (trimmed) models.add(trimmed);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
if (models.size === 0) throw new Error("Databricks retirement tables contained no model names");
|
|
29
|
+
return {
|
|
30
|
+
generatedAt,
|
|
31
|
+
models: [...models].sort((left, right) =>
|
|
32
|
+
left.localeCompare(right, "en", { sensitivity: "base" }),
|
|
33
|
+
),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Parse Responses and web-search documentation into model capability sets. */
|
|
38
|
+
export function parseModelCapabilities(
|
|
39
|
+
responsesHtml: string,
|
|
40
|
+
webSearchHtml: string,
|
|
41
|
+
generatedAt: number,
|
|
42
|
+
): ModelCapabilitiesSnapshot {
|
|
43
|
+
const responsesDocument = load(responsesHtml);
|
|
44
|
+
const responses = modelsAfterHeading(responsesDocument, "databricks-hosted-foundation-models");
|
|
45
|
+
if (responses.length === 0) {
|
|
46
|
+
throw new Error("Databricks documentation contained no OpenAI Responses models");
|
|
47
|
+
}
|
|
48
|
+
const inputTypes = sectionElements(responsesDocument, "supported-input-types")
|
|
49
|
+
.map((element) => collapseText(element))
|
|
50
|
+
.join(" ")
|
|
51
|
+
.toLowerCase();
|
|
52
|
+
const inputTypeWords = new Set(inputTypes.split(/[^a-z0-9]+/).filter(Boolean));
|
|
53
|
+
const imageInput = inputTypeWords.has("text") && inputTypeWords.has("image") ? responses : [];
|
|
54
|
+
const applyPatch = codeValuesAfterHeading(responsesDocument, "limitations").includes(
|
|
55
|
+
"apply_patch",
|
|
56
|
+
)
|
|
57
|
+
? responses
|
|
58
|
+
: [];
|
|
59
|
+
const webSearch = nativeWebSearchModels(load(webSearchHtml), responses);
|
|
60
|
+
if (webSearch.length === 0) {
|
|
61
|
+
throw new Error("Databricks documentation contained no native web-search models");
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
generatedAt,
|
|
65
|
+
capabilities: { responses, imageInput, applyPatch, webSearch },
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Parse pay-per-token limits from Databricks Foundation Model API HTML. */
|
|
70
|
+
export function parseModelRateLimits(html: string, generatedAt: number): ModelRateLimitsSnapshot {
|
|
71
|
+
const $ = load(html);
|
|
72
|
+
const models: Record<string, ModelRateLimitCatalogue["models"][string]> = {};
|
|
73
|
+
$("table").each((_, table) => {
|
|
74
|
+
const rows = $(table).find("tr");
|
|
75
|
+
const headers = $(rows.get(0))
|
|
76
|
+
.find("th, td")
|
|
77
|
+
.toArray()
|
|
78
|
+
.map((cell) => collapseText($(cell)).toLowerCase());
|
|
79
|
+
const modelIndex = headers.findIndex((value) => value.includes("model"));
|
|
80
|
+
const inputIndex = headers.findIndex((value) => value.includes("itpm"));
|
|
81
|
+
const outputIndex = headers.findIndex((value) => value.includes("otpm"));
|
|
82
|
+
const queryIndex = headers.findIndex((value) => value.includes("qph"));
|
|
83
|
+
if (modelIndex < 0 || inputIndex < 0 || outputIndex < 0) return;
|
|
84
|
+
rows.slice(1).each((__, row) => {
|
|
85
|
+
const cells = $(row)
|
|
86
|
+
.find("th, td")
|
|
87
|
+
.toArray()
|
|
88
|
+
.map((cell) => collapseText($(cell)));
|
|
89
|
+
const key = modelKey(cells[modelIndex]);
|
|
90
|
+
if (!key) return;
|
|
91
|
+
models[key] = {
|
|
92
|
+
inputTokensPerMinute: number(cells[inputIndex]),
|
|
93
|
+
outputTokensPerMinute: number(cells[outputIndex]),
|
|
94
|
+
queriesPerHour: queryIndex < 0 ? null : number(cells[queryIndex]),
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
if (Object.keys(models).length === 0) {
|
|
99
|
+
throw new Error("Databricks model-limit documentation contained no models");
|
|
100
|
+
}
|
|
101
|
+
return { generatedAt, catalogue: { models: sortRecord(models) } };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function modelsAfterHeading($: CheerioAPI, headingId: string): string[] {
|
|
105
|
+
return [
|
|
106
|
+
...new Set(codeValuesAfterHeading($, headingId).flatMap((value) => modelKey(value) ?? [])),
|
|
107
|
+
].sort();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function nativeWebSearchModels($: CheerioAPI, responses: readonly string[]): string[] {
|
|
111
|
+
const families = new Set<string>();
|
|
112
|
+
const models = new Set<string>();
|
|
113
|
+
let nativeSection = false;
|
|
114
|
+
for (const element of sectionElements($, "supported-models")) {
|
|
115
|
+
if (headingLevel(nodeTagName(element.get(0))) !== undefined) {
|
|
116
|
+
nativeSection = !collapseText(element).toLowerCase().includes("via mcp");
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (!nativeSection) continue;
|
|
120
|
+
const values = nodeTagName(element.get(0)) === "code" ? [collapseText(element)] : [];
|
|
121
|
+
element.find("code").each((_, code) => {
|
|
122
|
+
values.push(collapseText($(code)));
|
|
123
|
+
});
|
|
124
|
+
for (const value of values) {
|
|
125
|
+
const model = modelKey(value);
|
|
126
|
+
if (!model) continue;
|
|
127
|
+
models.add(model);
|
|
128
|
+
families.add(model.split("-", 1)[0]);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (const model of responses) {
|
|
132
|
+
if (families.has(model.split("-", 1)[0])) models.add(model);
|
|
133
|
+
}
|
|
134
|
+
return [...models].sort();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function codeValuesAfterHeading($: CheerioAPI, headingId: string): string[] {
|
|
138
|
+
const values: string[] = [];
|
|
139
|
+
for (const element of sectionElements($, headingId)) {
|
|
140
|
+
if (nodeTagName(element.get(0)) === "code") values.push(collapseText(element));
|
|
141
|
+
element.find("code").each((_, code) => {
|
|
142
|
+
values.push(collapseText($(code)));
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return values;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function sectionElements($: CheerioAPI, headingId: string): Selection[] {
|
|
149
|
+
const heading = $(`#${headingId}`).first();
|
|
150
|
+
if (heading.length === 0)
|
|
151
|
+
throw new Error(`Databricks capability page is missing section ${headingId}`);
|
|
152
|
+
const level = headingLevel(nodeTagName(heading.get(0)));
|
|
153
|
+
if (level === undefined)
|
|
154
|
+
throw new Error(`Databricks capability section ${headingId} is not a heading`);
|
|
155
|
+
const elements: Selection[] = [];
|
|
156
|
+
let sibling = heading.next();
|
|
157
|
+
while (sibling.length > 0) {
|
|
158
|
+
const siblingLevel = headingLevel(nodeTagName(sibling.get(0)));
|
|
159
|
+
if (siblingLevel !== undefined && siblingLevel <= level) break;
|
|
160
|
+
elements.push(sibling);
|
|
161
|
+
sibling = sibling.next();
|
|
162
|
+
}
|
|
163
|
+
return elements;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function headingLevel(name: string | undefined): number | undefined {
|
|
167
|
+
const match = /^h([1-6])$/.exec(name ?? "");
|
|
168
|
+
return match ? Number(match[1]) : undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function collapseText(element: Selection): string {
|
|
172
|
+
return element.text().split(/\s+/).filter(Boolean).join(" ");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function nodeTagName(node: unknown): string | undefined {
|
|
176
|
+
if (!node || typeof node !== "object" || !("tagName" in node)) return undefined;
|
|
177
|
+
return typeof node.tagName === "string" ? node.tagName : undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function modelKey(value: string | undefined): string | undefined {
|
|
181
|
+
if (!value) return undefined;
|
|
182
|
+
let name = value.trim().replace(/\*+$/, "").trim();
|
|
183
|
+
for (const suffix of ["(Public Preview)", "(Beta)", "(Preview)"]) {
|
|
184
|
+
if (name.endsWith(suffix)) name = name.slice(0, -suffix.length).trim();
|
|
185
|
+
}
|
|
186
|
+
return modelSearchQuery(name)?.replaceAll(" ", "-");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function number(value: string | undefined): number | null {
|
|
190
|
+
if (!value) return null;
|
|
191
|
+
const parsed = Number(value.replaceAll(",", "").trim());
|
|
192
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function sortRecord<T>(record: Readonly<Record<string, T>>): Record<string, T> {
|
|
196
|
+
return Object.fromEntries(
|
|
197
|
+
Object.entries(record).sort(([left], [right]) => left.localeCompare(right)),
|
|
198
|
+
);
|
|
199
|
+
}
|