@dbx-tools/shared-core 0.3.43 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +36 -0
- package/lib/index.js +30 -0
- package/lib/src/async.d.ts +152 -0
- package/lib/src/async.js +163 -0
- package/lib/src/brand.d.ts +94 -0
- package/lib/src/brand.js +123 -0
- package/lib/src/error.d.ts +76 -0
- package/lib/src/error.js +168 -0
- package/lib/src/function.d.ts +38 -0
- package/lib/src/function.js +44 -0
- package/lib/src/hash.d.ts +102 -0
- package/lib/src/hash.js +274 -0
- package/lib/src/http.d.ts +79 -0
- package/lib/src/http.js +189 -0
- package/lib/src/json.d.ts +48 -0
- package/lib/src/json.js +49 -0
- package/lib/src/log.d.ts +86 -0
- package/lib/src/log.js +352 -0
- package/lib/src/net.d.ts +246 -0
- package/lib/src/net.js +465 -0
- package/lib/src/object.d.ts +382 -0
- package/lib/src/object.js +749 -0
- package/lib/src/predicate.d.ts +81 -0
- package/lib/src/predicate.js +43 -0
- package/lib/src/string.d.ts +221 -0
- package/lib/src/string.js +509 -0
- package/lib/src/token.d.ts +30 -0
- package/lib/src/token.js +126 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +9 -5
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-safe string toolkit: tokenization, identifier / slug
|
|
3
|
+
* generation (with hash-suffix collision resistance), HTML escaping,
|
|
4
|
+
* header-value trimming, and a nested description-tree renderer for
|
|
5
|
+
* long-form LLM prompt / tool-description text. Depends only on the
|
|
6
|
+
* local {@link fnvHashWithOptions} for deterministic hash suffixes.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { fnvHashWithOptions } from "./hash.js";
|
|
11
|
+
// A leading `v`/`V` immediately followed by digits (a version marker like
|
|
12
|
+
// `v2`) is kept as ONE token instead of splitting into `v` + `2`; it leads the
|
|
13
|
+
// alternation so it wins over the generic letter / digit runs. Everything else
|
|
14
|
+
// is the usual camelCase word / number / all-caps-acronym split.
|
|
15
|
+
const TOKENIZE_CAMEL_CASE_REGEXP = /[vV][0-9]+|[A-Z]?[a-z]+|[0-9]+|[A-Z]+(?![a-z])/g;
|
|
16
|
+
const TOKENIZE_NON_ALPHANUMERIC_REGEXP = /[a-zA-Z0-9]+/g;
|
|
17
|
+
const TOKENIZE_OVERRIDES = [
|
|
18
|
+
(token, options) => {
|
|
19
|
+
if (options.capitalize && token.toLowerCase() === "ai") {
|
|
20
|
+
return "AI";
|
|
21
|
+
}
|
|
22
|
+
return token;
|
|
23
|
+
},
|
|
24
|
+
// Version marker `v2` -> `V2` when capitalizing (the leading `v` uppercases,
|
|
25
|
+
// the digits stay), so it reads as one unit rather than "V 2".
|
|
26
|
+
(token, options) => {
|
|
27
|
+
if (options.capitalize && /^v[0-9]+$/.test(token)) {
|
|
28
|
+
return `V${token.slice(1)}`;
|
|
29
|
+
}
|
|
30
|
+
return token;
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
const URI_REGEXP = /^([a-zA-Z][a-zA-Z0-9+.-]*)?:\/\/([^\s/?#][^\s]*)?$/;
|
|
34
|
+
const EMAIL_REGEXP = /^([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+)@([a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+)$/;
|
|
35
|
+
const TOKENIZE_DEFAULTS = {
|
|
36
|
+
distinct: false,
|
|
37
|
+
lowerCase: false,
|
|
38
|
+
capitalize: false,
|
|
39
|
+
omitUriScheme: false,
|
|
40
|
+
omitEmailDomain: false,
|
|
41
|
+
camelCase: true,
|
|
42
|
+
};
|
|
43
|
+
const IDENTIFIER_DEFAULTS = {
|
|
44
|
+
...TOKENIZE_DEFAULTS,
|
|
45
|
+
lowerCase: true,
|
|
46
|
+
maxLength: Infinity,
|
|
47
|
+
truncateStrategy: "hash",
|
|
48
|
+
truncateHashLength: 6,
|
|
49
|
+
delimiter: "-",
|
|
50
|
+
};
|
|
51
|
+
export function* tokenizeWithOptions(options, ...values) {
|
|
52
|
+
const opts = { ...TOKENIZE_DEFAULTS, ...options };
|
|
53
|
+
const seen = opts.distinct ? new Set() : undefined;
|
|
54
|
+
const regexp = opts.camelCase ? TOKENIZE_CAMEL_CASE_REGEXP : TOKENIZE_NON_ALPHANUMERIC_REGEXP;
|
|
55
|
+
for (const value of values) {
|
|
56
|
+
if (value == null)
|
|
57
|
+
continue;
|
|
58
|
+
let stringValue = typeof value === "string" ? value : String(value);
|
|
59
|
+
if (!stringValue)
|
|
60
|
+
continue;
|
|
61
|
+
if (opts.omitUriScheme) {
|
|
62
|
+
const match = stringValue.match(URI_REGEXP);
|
|
63
|
+
if (match)
|
|
64
|
+
stringValue = match[2] ?? "";
|
|
65
|
+
}
|
|
66
|
+
if (opts.omitEmailDomain) {
|
|
67
|
+
const match = stringValue.match(EMAIL_REGEXP);
|
|
68
|
+
if (match)
|
|
69
|
+
stringValue = match[1] ?? "";
|
|
70
|
+
}
|
|
71
|
+
if (!stringValue)
|
|
72
|
+
continue;
|
|
73
|
+
for (const tokenMatch of stringValue.matchAll(regexp)) {
|
|
74
|
+
let token = tokenMatch[0];
|
|
75
|
+
if (opts.lowerCase)
|
|
76
|
+
token = token.toLowerCase();
|
|
77
|
+
if (opts.capitalize)
|
|
78
|
+
token = capitalize(token);
|
|
79
|
+
if (!token)
|
|
80
|
+
continue;
|
|
81
|
+
for (const override of TOKENIZE_OVERRIDES) {
|
|
82
|
+
token = override(token, opts);
|
|
83
|
+
if (!token)
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
if (!token || seen?.has(token))
|
|
87
|
+
continue;
|
|
88
|
+
seen?.add(token);
|
|
89
|
+
yield token;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export function* tokenize(...values) {
|
|
94
|
+
yield* tokenizeWithOptions({}, ...values);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Join tokenized values with `delimiter`. When the next token would push the
|
|
98
|
+
* result over `maxLength`: `trim` stops adding; `empty` returns `""`; `hash`
|
|
99
|
+
* appends a digest of accepted tokens plus the overflow token if the result
|
|
100
|
+
* still fits, otherwise `""`.
|
|
101
|
+
*/
|
|
102
|
+
export function toIdentifierWithOptions(options, ...values) {
|
|
103
|
+
const opts = {
|
|
104
|
+
...IDENTIFIER_DEFAULTS,
|
|
105
|
+
...options,
|
|
106
|
+
lowerCase: true,
|
|
107
|
+
};
|
|
108
|
+
const tokens = [];
|
|
109
|
+
let currentLength = 0;
|
|
110
|
+
for (const token of tokenizeWithOptions(opts, ...values)) {
|
|
111
|
+
const sepLength = tokens.length > 0 ? opts.delimiter.length : 0;
|
|
112
|
+
const nextLength = currentLength + sepLength + token.length;
|
|
113
|
+
if (nextLength > opts.maxLength) {
|
|
114
|
+
if (opts.truncateStrategy === "empty")
|
|
115
|
+
return "";
|
|
116
|
+
if (opts.truncateStrategy === "trim")
|
|
117
|
+
break;
|
|
118
|
+
const hash = digestTokens(opts.truncateHashLength, tokens, token);
|
|
119
|
+
if (currentLength + sepLength + hash.length <= opts.maxLength) {
|
|
120
|
+
return tokens.length > 0 ? tokens.join(opts.delimiter) + opts.delimiter + hash : hash;
|
|
121
|
+
}
|
|
122
|
+
return "";
|
|
123
|
+
}
|
|
124
|
+
tokens.push(token);
|
|
125
|
+
currentLength = nextLength;
|
|
126
|
+
}
|
|
127
|
+
return tokens.join(opts.delimiter);
|
|
128
|
+
}
|
|
129
|
+
export function toIdentifier(...values) {
|
|
130
|
+
return toIdentifierWithOptions({}, ...values);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Slugified identifier: same rules as {@link toIdentifierWithOptions} with the
|
|
134
|
+
* delimiter forced to `-`. Accepts {@link KeyOptions} so callers cannot
|
|
135
|
+
* override the delimiter.
|
|
136
|
+
*/
|
|
137
|
+
export function toSlugWithOptions(options, ...values) {
|
|
138
|
+
return toIdentifierWithOptions({ ...options, delimiter: "-" }, ...values);
|
|
139
|
+
}
|
|
140
|
+
export function toSlug(...values) {
|
|
141
|
+
return toSlugWithOptions({}, ...values);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Trim `value` and return `null` for non-strings, `undefined`, or
|
|
145
|
+
* strings that are empty after trimming. Lets call sites collapse the
|
|
146
|
+
* common
|
|
147
|
+
*
|
|
148
|
+
* ```ts
|
|
149
|
+
* typeof v === "string" && v.trim() ? v.trim() : null
|
|
150
|
+
* ```
|
|
151
|
+
*
|
|
152
|
+
* dance into a single helper. Useful for HTTP header / query / form
|
|
153
|
+
* extractors where downstream code wants `string | null` to drive a
|
|
154
|
+
* cheap `??` / `if (x)` cascade.
|
|
155
|
+
*/
|
|
156
|
+
export function trimToNull(value) {
|
|
157
|
+
if (typeof value !== "string")
|
|
158
|
+
return null;
|
|
159
|
+
const trimmed = value.trim();
|
|
160
|
+
return trimmed ? trimmed : null;
|
|
161
|
+
}
|
|
162
|
+
// Config lists arrive either already split (an array) or as one env-var string
|
|
163
|
+
// with entries separated by commas and/or whitespace.
|
|
164
|
+
const LIST_SEPARATOR_REGEXP = /[\s,]+/;
|
|
165
|
+
/**
|
|
166
|
+
* Normalize a config list that may arrive as an array or as a single
|
|
167
|
+
* comma/whitespace-separated string: split, apply `transform`, drop empties,
|
|
168
|
+
* and de-duplicate (first occurrence wins).
|
|
169
|
+
*
|
|
170
|
+
* This is the shape every allow-list / fallback-order setting in this repo
|
|
171
|
+
* takes, because the same value can come from typed config (`string[]`) or from
|
|
172
|
+
* an environment variable (`"a, b c"`). Pass `transform` to normalize entries
|
|
173
|
+
* as they are read; it defaults to trimming.
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* parseList("docs.example.com, *.databricks.com");
|
|
177
|
+
* parseList(process.env.MODEL_FALLBACKS);
|
|
178
|
+
* parseList(raw, normalizeUrlPattern);
|
|
179
|
+
*/
|
|
180
|
+
export function parseList(raw, transform = (entry) => entry.trim()) {
|
|
181
|
+
const entries = typeof raw === "string" ? raw.split(LIST_SEPARATOR_REGEXP) : Array.isArray(raw) ? raw : [];
|
|
182
|
+
const out = [];
|
|
183
|
+
const seen = new Set();
|
|
184
|
+
for (const entry of entries) {
|
|
185
|
+
const normalized = transform(entry);
|
|
186
|
+
if (!normalized || seen.has(normalized))
|
|
187
|
+
continue;
|
|
188
|
+
seen.add(normalized);
|
|
189
|
+
out.push(normalized);
|
|
190
|
+
}
|
|
191
|
+
return out;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* {@link trimToNull} with an empty-string miss instead of `null`, for callers
|
|
195
|
+
* that build a string unconditionally and treat "absent" as "".
|
|
196
|
+
*
|
|
197
|
+
* Reading loosely-typed JSON is the motivating case: a field that should be a
|
|
198
|
+
* string may be missing or the wrong type, and the caller wants `""` rather
|
|
199
|
+
* than a null check at every access.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* const title = trimToEmpty(record.title); // always a string
|
|
203
|
+
*/
|
|
204
|
+
export function trimToEmpty(value) {
|
|
205
|
+
return trimToNull(value) ?? "";
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Trim the first usable string out of `value`. Returns `null` when
|
|
209
|
+
* `value` is `undefined`, `null`, an empty string, or an array whose
|
|
210
|
+
* first string member is empty. Mirrors how Express / Node header
|
|
211
|
+
* accessors expose single vs. repeated headers - the first
|
|
212
|
+
* non-empty entry wins, everything else is ignored.
|
|
213
|
+
*/
|
|
214
|
+
export function firstNonEmpty(value) {
|
|
215
|
+
if (Array.isArray(value)) {
|
|
216
|
+
for (const item of value) {
|
|
217
|
+
const trimmed = trimToNull(item);
|
|
218
|
+
if (trimmed)
|
|
219
|
+
return trimmed;
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
return trimToNull(value);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Escape the five characters significant in HTML text and
|
|
227
|
+
* double-quoted attribute values (`&`, `<`, `>`, `"`, `'`) so an
|
|
228
|
+
* untrusted string can be interpolated into markup without breaking
|
|
229
|
+
* out of its context. `&` is replaced first so ampersands introduced
|
|
230
|
+
* by the later replacements aren't double-escaped.
|
|
231
|
+
*/
|
|
232
|
+
export function escapeHtml(value) {
|
|
233
|
+
return value
|
|
234
|
+
.replace(/&/g, "&")
|
|
235
|
+
.replace(/</g, "<")
|
|
236
|
+
.replace(/>/g, ">")
|
|
237
|
+
.replace(/"/g, """)
|
|
238
|
+
.replace(/'/g, "'");
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Slugify `value` (using the standard {@link toIdentifierWithOptions}
|
|
242
|
+
* tokenizer + delimiter rules) and **always** suffix a short
|
|
243
|
+
* deterministic hash. Use when you need a stable, slugified id that
|
|
244
|
+
* is guaranteed to be unique across descriptions sharing the same
|
|
245
|
+
* leading tokens (tool ids, cache keys, etc.).
|
|
246
|
+
*
|
|
247
|
+
* Behaviour differs from `toIdentifierWithOptions({ maxLength,
|
|
248
|
+
* truncateStrategy: "hash" })`: that helper only appends a hash when
|
|
249
|
+
* the slug *overflows* `maxLength`. This helper appends a hash
|
|
250
|
+
* unconditionally so the result is collision-resistant even for
|
|
251
|
+
* short inputs. The hash is computed over the raw `value` so two
|
|
252
|
+
* descriptions producing the same slug still get different ids.
|
|
253
|
+
*
|
|
254
|
+
* @param value - Source string (typically a tool/agent description).
|
|
255
|
+
* @param options.delimiter - Token separator (default `"_"`).
|
|
256
|
+
* @param options.slugMaxLength - Cap on the slug portion (the part
|
|
257
|
+
* before the hash). Default 32.
|
|
258
|
+
* @param options.hashLength - Length of the suffix produced by
|
|
259
|
+
* {@link fnvHashWithOptions} (Crockford-style base-32 alphabet, max 7
|
|
260
|
+
* chars). Default 6.
|
|
261
|
+
* @param options.fallbackPrefix - Prefix used when the slug is empty
|
|
262
|
+
* (e.g. punctuation-only input). Default `"id"`.
|
|
263
|
+
*/
|
|
264
|
+
export function toUniqueSlug(value, options = {}) {
|
|
265
|
+
const delimiter = options.delimiter ?? "_";
|
|
266
|
+
const slugMaxLength = options.slugMaxLength ?? 32;
|
|
267
|
+
const hashLength = options.hashLength ?? 6;
|
|
268
|
+
const fallbackPrefix = options.fallbackPrefix ?? "id";
|
|
269
|
+
const slug = toIdentifierWithOptions({ delimiter, maxLength: slugMaxLength, truncateStrategy: "trim" }, value);
|
|
270
|
+
const suffix = fnvHashWithOptions({ length: hashLength }, value);
|
|
271
|
+
return slug ? `${slug}${delimiter}${suffix}` : `${fallbackPrefix}${delimiter}${suffix}`;
|
|
272
|
+
}
|
|
273
|
+
function digestTokens(length, parts, extra) {
|
|
274
|
+
let combined = "";
|
|
275
|
+
for (const part of parts)
|
|
276
|
+
combined += part + "\0";
|
|
277
|
+
if (extra !== undefined)
|
|
278
|
+
combined += extra + "\0";
|
|
279
|
+
return fnvHashWithOptions({ length }, combined);
|
|
280
|
+
}
|
|
281
|
+
const LIST_KEYS = ["bullets", "numbered"];
|
|
282
|
+
/**
|
|
283
|
+
* Format a nested description tree as a Markdown-ish string suitable
|
|
284
|
+
* for an LLM system prompt, Zod `.describe()` block, Mastra tool
|
|
285
|
+
* description, or any other long-form text destination.
|
|
286
|
+
*
|
|
287
|
+
* Every string section is dedented (common leading whitespace stripped),
|
|
288
|
+
* right-trimmed line by line, and freed of leading / trailing blank
|
|
289
|
+
* lines, so callers can write multi-line template literals indented
|
|
290
|
+
* naturally in source without leaking that indentation into the
|
|
291
|
+
* consumer-facing output. Plain-string inputs flow through unchanged
|
|
292
|
+
* apart from the same normalization pass, so a single multi-line
|
|
293
|
+
* template literal works directly:
|
|
294
|
+
*
|
|
295
|
+
* ```ts
|
|
296
|
+
* toDescription(`
|
|
297
|
+
* Ask the Genie space "${alias}" a question.
|
|
298
|
+
* Pass the answer through as-is.
|
|
299
|
+
* `);
|
|
300
|
+
* // Ask the Genie space "default" a question.
|
|
301
|
+
* // Pass the answer through as-is.
|
|
302
|
+
*
|
|
303
|
+
* toDescription([
|
|
304
|
+
* `
|
|
305
|
+
* Ask the Genie space a question.
|
|
306
|
+
* Phrase it from the user's perspective.
|
|
307
|
+
* `,
|
|
308
|
+
* { bullets: [
|
|
309
|
+
* ["Pass the answer through as-is", { numbered: ["item", "item"] }],
|
|
310
|
+
* ]},
|
|
311
|
+
* { Instructions: "Reply with the SQL only." },
|
|
312
|
+
* ]);
|
|
313
|
+
* // Ask the Genie space a question.
|
|
314
|
+
* // Phrase it from the user's perspective.
|
|
315
|
+
* // - Pass the answer through as-is
|
|
316
|
+
* // 1. item
|
|
317
|
+
* // 2. item
|
|
318
|
+
* //
|
|
319
|
+
* // Instructions:
|
|
320
|
+
* //
|
|
321
|
+
* // Reply with the SQL only.
|
|
322
|
+
* ```
|
|
323
|
+
*
|
|
324
|
+
* See {@link Description} for the node grammar.
|
|
325
|
+
*/
|
|
326
|
+
export function toDescription(node) {
|
|
327
|
+
return renderBlock(node, "")
|
|
328
|
+
.replace(/[ \t]+$/gm, "")
|
|
329
|
+
.replace(/\n+$/, "");
|
|
330
|
+
}
|
|
331
|
+
function renderBlock(node, pad) {
|
|
332
|
+
if (node == null)
|
|
333
|
+
return "";
|
|
334
|
+
if (typeof node === "string")
|
|
335
|
+
return prependPad(dedentSection(node), pad);
|
|
336
|
+
if (Array.isArray(node))
|
|
337
|
+
return renderSequence(node, pad);
|
|
338
|
+
const kind = listKind(node);
|
|
339
|
+
if (kind) {
|
|
340
|
+
return renderList(node[kind], pad, kind);
|
|
341
|
+
}
|
|
342
|
+
return renderMap(node, pad);
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Normalize a string section: right-strip every line, drop the
|
|
346
|
+
* common leading-whitespace prefix shared by all non-blank lines,
|
|
347
|
+
* and trim leading / trailing blank lines. Matches Python's
|
|
348
|
+
* `textwrap.dedent` semantics so embedded indented template
|
|
349
|
+
* literals round-trip cleanly.
|
|
350
|
+
*/
|
|
351
|
+
function dedentSection(text) {
|
|
352
|
+
if (!text)
|
|
353
|
+
return "";
|
|
354
|
+
const lines = text.split("\n").map((line) => line.replace(/[ \t]+$/, ""));
|
|
355
|
+
let min = Infinity;
|
|
356
|
+
for (const line of lines) {
|
|
357
|
+
if (!line)
|
|
358
|
+
continue;
|
|
359
|
+
const match = /^[ \t]*/.exec(line);
|
|
360
|
+
const width = match ? match[0].length : 0;
|
|
361
|
+
if (width < min)
|
|
362
|
+
min = width;
|
|
363
|
+
}
|
|
364
|
+
const stripped = min === Infinity || min === 0 ? lines : lines.map((line) => (line ? line.slice(min) : ""));
|
|
365
|
+
let start = 0;
|
|
366
|
+
let end = stripped.length;
|
|
367
|
+
while (start < end && !stripped[start])
|
|
368
|
+
start += 1;
|
|
369
|
+
while (end > start && !stripped[end - 1])
|
|
370
|
+
end -= 1;
|
|
371
|
+
return stripped.slice(start, end).join("\n");
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* An object is treated as a typed list only when it has exactly one
|
|
375
|
+
* own key, that key is `bullets` or `numbered`, and the value is an
|
|
376
|
+
* array. Everything else is a headers map - so callers wanting a
|
|
377
|
+
* single header literally named `bullets` or `numbered` can use a
|
|
378
|
+
* multi-key map or rename.
|
|
379
|
+
*/
|
|
380
|
+
function listKind(node) {
|
|
381
|
+
const keys = Object.keys(node);
|
|
382
|
+
if (keys.length !== 1)
|
|
383
|
+
return null;
|
|
384
|
+
const key = keys[0];
|
|
385
|
+
if (LIST_KEYS.includes(key) && Array.isArray(node[key])) {
|
|
386
|
+
return key;
|
|
387
|
+
}
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
function prependPad(text, pad) {
|
|
391
|
+
if (!text)
|
|
392
|
+
return "";
|
|
393
|
+
if (!pad)
|
|
394
|
+
return text;
|
|
395
|
+
return text
|
|
396
|
+
.split("\n")
|
|
397
|
+
.map((line) => (line ? pad + line : ""))
|
|
398
|
+
.join("\n");
|
|
399
|
+
}
|
|
400
|
+
function renderSequence(items, pad) {
|
|
401
|
+
const rendered = [];
|
|
402
|
+
for (const item of items) {
|
|
403
|
+
const text = renderBlock(item, pad);
|
|
404
|
+
if (!text)
|
|
405
|
+
continue;
|
|
406
|
+
rendered.push({ text, node: item });
|
|
407
|
+
}
|
|
408
|
+
if (rendered.length === 0)
|
|
409
|
+
return "";
|
|
410
|
+
let out = rendered[0].text;
|
|
411
|
+
for (let i = 1; i < rendered.length; i += 1) {
|
|
412
|
+
const sep = needsBlankLineBetween(rendered[i - 1].node, rendered[i].node) ? "\n\n" : "\n";
|
|
413
|
+
out += sep + rendered[i].text;
|
|
414
|
+
}
|
|
415
|
+
return out;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Maps always create their own section boundary (a `Header:` line plus
|
|
419
|
+
* a blank line before the body), so anything touching a map gets a
|
|
420
|
+
* blank-line break. Plain text adjacent to a typed list flushes
|
|
421
|
+
* together in either direction: text-before-list reads as a lead-in,
|
|
422
|
+
* text-after-list as a trailing summary. Two text paragraphs and two
|
|
423
|
+
* adjacent lists both get a blank-line break for legibility.
|
|
424
|
+
*/
|
|
425
|
+
function needsBlankLineBetween(prev, curr) {
|
|
426
|
+
if (isMap(prev) || isMap(curr))
|
|
427
|
+
return true;
|
|
428
|
+
const prevIsText = typeof prev === "string";
|
|
429
|
+
const currIsText = typeof curr === "string";
|
|
430
|
+
if (prevIsText !== currIsText)
|
|
431
|
+
return false;
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* A node is a headers map when it is a non-array, non-list object.
|
|
436
|
+
* `bullets` / `numbered` single-key objects are the only structured
|
|
437
|
+
* objects that aren't maps.
|
|
438
|
+
*/
|
|
439
|
+
function isMap(node) {
|
|
440
|
+
if (node == null)
|
|
441
|
+
return false;
|
|
442
|
+
if (typeof node === "string")
|
|
443
|
+
return false;
|
|
444
|
+
if (Array.isArray(node))
|
|
445
|
+
return false;
|
|
446
|
+
return listKind(node) === null;
|
|
447
|
+
}
|
|
448
|
+
function renderList(items, pad, kind) {
|
|
449
|
+
if (items.length === 0)
|
|
450
|
+
return "";
|
|
451
|
+
if (items.length === 1 && typeof items[0] === "string") {
|
|
452
|
+
return prependPad(items[0], pad);
|
|
453
|
+
}
|
|
454
|
+
const lines = [];
|
|
455
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
456
|
+
const item = items[i];
|
|
457
|
+
const marker = kind === "bullets" ? "- " : `${i + 1}. `;
|
|
458
|
+
const body = renderBlock(item, "");
|
|
459
|
+
const bodyLines = body.split("\n");
|
|
460
|
+
lines.push(`${pad}${marker}${bodyLines[0] ?? ""}`);
|
|
461
|
+
const continuation = pad + " ".repeat(marker.length);
|
|
462
|
+
for (const line of bodyLines.slice(1)) {
|
|
463
|
+
lines.push(line ? `${continuation}${line}` : "");
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return lines.join("\n");
|
|
467
|
+
}
|
|
468
|
+
function renderMap(node, pad) {
|
|
469
|
+
const parts = [];
|
|
470
|
+
for (const [header, value] of Object.entries(node)) {
|
|
471
|
+
const body = renderBlock(value, pad);
|
|
472
|
+
if (!body && !header.trim())
|
|
473
|
+
continue;
|
|
474
|
+
const headerLine = header.trim() ? `${pad}${header}:` : "";
|
|
475
|
+
parts.push(body ? `${headerLine}\n\n${body}` : headerLine);
|
|
476
|
+
}
|
|
477
|
+
return parts.join("\n\n");
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Format a count with its noun, pluralizing (naive `+s`) unless the count is 1:
|
|
481
|
+
* `pluralize(1, "barrel")` -> `"1 barrel"`, `pluralize(3, "barrel")` ->
|
|
482
|
+
* `"3 barrels"`. Collapses the `${n} noun${n === 1 ? "" : "s"}` idiom.
|
|
483
|
+
*/
|
|
484
|
+
export function pluralize(count, noun) {
|
|
485
|
+
return `${count} ${noun}${count === 1 ? "" : "s"}`;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Title-case a snake / kebab / camel identifier into a human-readable label:
|
|
489
|
+
* tokenize (lowercased, capitalized), then join with spaces. Falls back to
|
|
490
|
+
* the raw `value` when it yields no tokens (e.g. punctuation-only input).
|
|
491
|
+
* `bge_large_en` -> `"Bge Large En"`, `promptId` -> `"Prompt Id"`.
|
|
492
|
+
*
|
|
493
|
+
* The single source of truth for the "humanize a column / field name" idiom -
|
|
494
|
+
* reused by the chat data-grid headers and the export renderer. Extra
|
|
495
|
+
* {@link TokenizeOptions} (e.g. `camelCase: false`) merge over the defaults.
|
|
496
|
+
*/
|
|
497
|
+
export function toLabel(value, options) {
|
|
498
|
+
const tokens = [...tokenizeWithOptions({ lowerCase: true, capitalize: true, ...options }, value)];
|
|
499
|
+
return tokens.length > 0 ? tokens.join(" ") : value;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Upper-case the first character of `value`, leaving the rest untouched.
|
|
503
|
+
* `"working"` -> `"Working"`. Collapses the
|
|
504
|
+
* `s.charAt(0).toUpperCase() + s.slice(1)` idiom.
|
|
505
|
+
*/
|
|
506
|
+
export function capitalize(value) {
|
|
507
|
+
return value ? value.charAt(0).toUpperCase() + value.slice(1) : value;
|
|
508
|
+
}
|
|
509
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RyaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0cmluZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7R0FRRztBQUNILE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQXlDNUMsMEVBQTBFO0FBQzFFLCtFQUErRTtBQUMvRSwrRUFBK0U7QUFDL0UsaUVBQWlFO0FBQ2pFLE1BQU0sMEJBQTBCLEdBQUcsaURBQWlELENBQUM7QUFDckYsTUFBTSxnQ0FBZ0MsR0FBRyxlQUFlLENBQUM7QUFDekQsTUFBTSxrQkFBa0IsR0FBNEQ7SUFDbEYsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7UUFDakIsSUFBSSxPQUFPLENBQUMsVUFBVSxJQUFJLEtBQUssQ0FBQyxXQUFXLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUN2RCxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCw2RUFBNkU7SUFDN0UsK0RBQStEO0lBQy9ELENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxFQUFFO1FBQ2pCLElBQUksT0FBTyxDQUFDLFVBQVUsSUFBSSxXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDbEQsT0FBTyxJQUFJLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM5QixDQUFDO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0NBQ0YsQ0FBQztBQUNGLE1BQU0sVUFBVSxHQUFHLG9EQUFvRCxDQUFDO0FBQ3hFLE1BQU0sWUFBWSxHQUFHLDBFQUEwRSxDQUFDO0FBRWhHLE1BQU0saUJBQWlCLEdBQTRCO0lBQ2pELFFBQVEsRUFBRSxLQUFLO0lBQ2YsU0FBUyxFQUFFLEtBQUs7SUFDaEIsVUFBVSxFQUFFLEtBQUs7SUFDakIsYUFBYSxFQUFFLEtBQUs7SUFDcEIsZUFBZSxF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SyxDQUFDLENBQUMsQ0FBRSxDQUFDO1FBQ3ZCLE1BQU0sTUFBTSxHQUFHLElBQUksS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUM7UUFDeEQsTUFBTSxJQUFJLEdBQUcsV0FBVyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNuQyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ25DLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsTUFBTSxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ25ELE1BQU0sWUFBWSxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNyRCxLQUFLLE1BQU0sSUFBSSxJQUFJLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUN0QyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxZQUFZLEdBQUcsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ25ELENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzFCLENBQUM7QUFFRCxTQUFTLFNBQVMsQ0FBQyxJQUFpQyxFQUFFLEdBQVc7SUFDL0QsTUFBTSxLQUFLLEdBQWEsRUFBRSxDQUFDO0lBQzNCLEtBQUssTUFBTSxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDbkQsTUFBTSxJQUFJLEdBQUcsV0FBVyxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNyQyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRTtZQUFFLFNBQVM7UUFDdEMsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsR0FBRyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzNELEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLFVBQVUsT0FBTyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDN0QsQ0FBQztJQUNELE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUM1QixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxTQUFTLENBQUMsS0FBYSxFQUFFLElBQVk7SUFDbkQsT0FBTyxHQUFHLEtBQUssSUFBSSxJQUFJLEdBQUcsS0FBSyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQztBQUNyRCxDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxVQUFVLE9BQU8sQ0FBQyxLQUFhLEVBQUUsT0FBeUI7SUFDOUQsTUFBTSxNQUFNLEdBQUcsQ0FBQyxHQUFHLG1CQUFtQixDQUFDLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLEdBQUcsT0FBTyxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUNsRyxPQUFPLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7QUFDdEQsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsVUFBVSxDQUFDLEtBQWE7SUFDdEMsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxFQUFFLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0FBQ3hFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEJyb3dzZXItc2FmZSBzdHJpbmcgdG9vbGtpdDogdG9rZW5pemF0aW9uLCBpZGVudGlmaWVyIC8gc2x1Z1xuICogZ2VuZXJhdGlvbiAod2l0aCBoYXNoLXN1ZmZpeCBjb2xsaXNpb24gcmVzaXN0YW5jZSksIEhUTUwgZXNjYXBpbmcsXG4gKiBoZWFkZXItdmFsdWUgdHJpbW1pbmcsIGFuZCBhIG5lc3RlZCBkZXNjcmlwdGlvbi10cmVlIHJlbmRlcmVyIGZvclxuICogbG9uZy1mb3JtIExMTSBwcm9tcHQgLyB0b29sLWRlc2NyaXB0aW9uIHRleHQuIERlcGVuZHMgb25seSBvbiB0aGVcbiAqIGxvY2FsIHtAbGluayBmbnZIYXNoV2l0aE9wdGlvbnN9IGZvciBkZXRlcm1pbmlzdGljIGhhc2ggc3VmZml4ZXMuXG4gKlxuICogQG1vZHVsZVxuICovXG5pbXBvcnQgeyBmbnZIYXNoV2l0aE9wdGlvbnMgfSBmcm9tIFwiLi9oYXNoXCI7XG5cbi8qKlxuICogT3B0aW9ucyBjb250cm9sbGluZyB7QGxpbmsgdG9rZW5pemVXaXRoT3B0aW9uc30uIEFsbCBkZWZhdWx0IG9mZiBleGNlcHRcbiAqIGBjYW1lbENhc2VgLlxuICpcbiAqIC0gYGRpc3RpbmN0YCAtIGRyb3AgZHVwbGljYXRlIHRva2VucyAoZmlyc3Qgb2NjdXJyZW5jZSB3aW5zKS5cbiAqIC0gYGxvd2VyQ2FzZWAgLSBsb3dlcmNhc2UgZXZlcnkgdG9rZW4uXG4gKiAtIGBjYXBpdGFsaXplYCAtIHVwcGVyLWNhc2UgZWFjaCB0b2tlbidzIGZpcnN0IGxldHRlciAodGhlblxuICogICB7QGxpbmsgVE9LRU5JWkVfT1ZFUlJJREVTfSBmaXggdXAgYGFpYCAtPiBgQUlgIGFuZCBgdjJgIC0+IGBWMmApLlxuICogLSBgb21pdFVyaVNjaGVtZWAgLSBzdHJpcCBhIGxlYWRpbmcgYHNjaGVtZTovL2AgYmVmb3JlIHRva2VuaXppbmcuXG4gKiAtIGBvbWl0RW1haWxEb21haW5gIC0ga2VlcCBvbmx5IHRoZSBsb2NhbCBwYXJ0IG9mIGFuIGVtYWlsLlxuICogLSBgY2FtZWxDYXNlYCAtIHNwbGl0IG9uIGNhbWVsQ2FzZSBib3VuZGFyaWVzIC8gZGlnaXQgcnVucyAvIGFjcm9ueW1zXG4gKiAgIChkZWZhdWx0IGB0cnVlYCk7IHdoZW4gYGZhbHNlYCwgc3BsaXQgb25seSBvbiBub24tYWxwaGFudW1lcmljcy5cbiAqL1xuZXhwb3J0IHR5cGUgVG9rZW5pemVPcHRpb25zID0ge1xuICBkaXN0aW5jdD86IGJvb2xlYW47XG4gIGxvd2VyQ2FzZT86IGJvb2xlYW47XG4gIGNhcGl0YWxpemU/OiBib29sZWFuO1xuICBvbWl0VXJpU2NoZW1lPzogYm9vbGVhbjtcbiAgb21pdEVtYWlsRG9tYWluPzogYm9vbGVhbjtcbiAgY2FtZWxDYXNlPzogYm9vbGVhbjtcbn07XG5cbi8vIEtleXMvaWRlbnRpZmllcnMvc2x1Z3MgYXJlIGFsd2F5cyBsb3dlcmNhc2VkOyBgbG93ZXJDYXNlYCBpcyBub3QgYVxuLy8gY2FsbGVyLWNvbmZpZ3VyYWJsZSBvcHRpb24uXG5leHBvcnQgdHlwZSBLZXlPcHRpb25zID0gT21pdDxUb2tlbml6ZU9wdGlvbnMsIFwibG93ZXJDYXNlXCIgfCBcImNhcGl0YWxpemVcIj4gJiB7XG4gIG1heExlbmd0aD86IG51bWJlcjtcbiAgdHJ1bmNhdGVTdHJhdGVneT86IFwiaGFzaFwiIHwgXCJ0cmltXCIgfCBcImVtcHR5XCI7XG4gIHRydW5jYXRlSGFzaExlbmd0aD86IG51bWJlcjtcbn07XG5cbmV4cG9ydCB0eXBlIElkZW50aWZpZXJPcHRpb25zID0gS2V5T3B0aW9ucyAmIHtcbiAgZGVsaW1pdGVyPzogc3RyaW5nO1xufTtcblxudHlwZSBSZXNvbHZlZFRva2VuaXplT3B0aW9ucyA9IFJlcXVpcmVkPFRva2VuaXplT3B0aW9ucz47XG50eXBlIFJlc29sdmVkSWRlbnRpZmllck9wdGlvbnMgPSBSZXF1aXJlZDxcbiAgSWRlbnRpZmllck9wdGlvbnMgJiBQaWNrPFRva2VuaXplT3B0aW9ucywgXCJsb3dlckNhc2VcIiB8IFwiY2FwaXRhbGl6ZVwiPlxuPjtcblxuLy8gQSBsZWFkaW5nIGB2YC9gVmAgaW1tZWRpYXRlbHkgZm9sbG93ZWQgYnkgZGlnaXRzIChhIHZlcnNpb24gbWFya2VyIGxpa2Vcbi8vIGB2MmApIGlzIGtlcHQgYXMgT05FIHRva2VuIGluc3RlYWQgb2Ygc3BsaXR0aW5nIGludG8gYHZgICsgYDJgOyBpdCBsZWFkcyB0aGVcbi8vIGFsdGVybmF0aW9uIHNvIGl0IHdpbnMgb3ZlciB0aGUgZ2VuZXJpYyBsZXR0ZXIgLyBkaWdpdCBydW5zLiBFdmVyeXRoaW5nIGVsc2Vcbi8vIGlzIHRoZSB1c3VhbCBjYW1lbENhc2Ugd29yZCAvIG51bWJlciAvIGFsbC1jYXBzLWFjcm9ueW0gc3BsaXQuXG5jb25zdCBUT0tFTklaRV9DQU1FTF9DQVNFX1JFR0VYUCA9IC9bdlZdWzAtOV0rfFtBLVpdP1thLXpdK3xbMC05XSt8W0EtWl0rKD8hW2Etel0pL2c7XG5jb25zdCBUT0tFTklaRV9OT05fQUxQSEFOVU1FUklDX1JFR0VYUCA9IC9bYS16QS1aMC05XSsvZztcbmNvbnN0IFRPS0VOSVpFX09WRVJSSURFUzogKCh0b2tlbjogc3RyaW5nLCBvcHRpb25zOiBUb2tlbml6ZU9wdGlvbnMpID0+IHN0cmluZylbXSA9IFtcbiAgKHRva2VuLCBvcHRpb25zKSA9PiB7XG4gICAgaWYgKG9wdGlvbnMuY2FwaXRhbGl6ZSAmJiB0b2tlbi50b0xvd2VyQ2FzZSgpID09PSBcImFpXCIpIHtcbiAgICAgIHJldHVybiBcIkFJXCI7XG4gICAgfVxuICAgIHJldHVybiB0b2tlbjtcbiAgfSxcbiAgLy8gVmVyc2lvbiBtYXJrZXIgYHYyYCAtPiBgVjJgIHdoZW4gY2FwaXRhbGl6aW5nICh0aGUgbGVhZGluZyBgdmAgdXBwZXJjYXNlcyxcbiAgLy8gdGhlIGRpZ2l0cyBzdGF5KSwgc28gaXQgcmVhZHMgYXMgb25lIHVuaXQgcmF0aGVyIHRoYW4gXCJWIDJcIi5cbiAgKHRva2VuLCBvcHRpb25zKSA9PiB7XG4gICAgaWYgKG9wdGlvbnMuY2FwaXRhbGl6ZSAmJiAvXnZbMC05XSskLy50ZXN0KHRva2VuKSkge1xuICAgICAgcmV0dXJuIGBWJHt0b2tlbi5zbGljZSgxKX1gO1xuICAgIH1cbiAgICByZXR1cm4gdG9rZW47XG4gIH0sXG5dO1xuY29uc3QgVVJJX1JFR0VYUCA9IC9eKFthLXpBLVpdW2EtekEtWjAtOSsuLV0qKT86XFwvXFwvKFteXFxzLz8jXVteXFxzXSopPyQvO1xuY29uc3QgRU1BSUxfUkVHRVhQID0gL14oW2EtekEtWjAtOS4hIyQlJicqKy89P15fYHt8fX4tXSspQChbYS16QS1aMC05LV0rKD86XFwuW2EtekEtWjAtOS1dKykrKSQvO1xuXG5jb25zdCBUT0tFTklaRV9ERUZBVUxUUzogUmVzb2x2ZWRUb2tlbml6ZU9wdGlvbnMgPSB7XG4gIGRpc3RpbmN0OiBmYWxzZSxcbiAgbG93ZXJDYXNlOiBmYWxzZSxcbiAgY2FwaXRhbGl6ZTogZmFsc2UsXG4gIG9taXRVcmlTY2hlbWU6IGZhbHNlLFxuICBvbWl0RW1haWxEb21haW46IGZhbHNlLFxuICBjYW1lbENhc2U6IHRydWUsXG59O1xuXG5jb25zdCBJREVOVElGSUVSX0RFRkFVTFRTOiBSZXNvbHZlZElkZW50aWZpZXJPcHRpb25zID0ge1xuICAuLi5UT0tFTklaRV9ERUZBVUxUUyxcbiAgbG93ZXJDYXNlOiB0cnVlLFxuICBtYXhMZW5ndGg6IEluZmluaXR5LFxuICB0cnVuY2F0ZVN0cmF0ZWd5OiBcImhhc2hcIixcbiAgdHJ1bmNhdGVIYXNoTGVuZ3RoOiA2LFxuICBkZWxpbWl0ZXI6IFwiLVwiLFxufTtcblxuZXhwb3J0IGZ1bmN0aW9uKiB0b2tlbml6ZVdpdGhPcHRpb25zKFxuICBvcHRpb25zOiBUb2tlbml6ZU9wdGlvbnMsXG4gIC4uLnZhbHVlczogdW5rbm93bltdXG4pOiBHZW5lcmF0b3I8c3RyaW5nPiB7XG4gIGNvbnN0IG9wdHM6IFJlc29sdmVkVG9rZW5pemVPcHRpb25zID0geyAuLi5UT0tFTklaRV9ERUZBVUxUUywgLi4ub3B0aW9ucyB9O1xuICBjb25zdCBzZWVuID0gb3B0cy5kaXN0aW5jdCA/IG5ldyBTZXQ8c3RyaW5nPigpIDogdW5kZWZpbmVkO1xuICBjb25zdCByZWdleHAgPSBvcHRzLmNhbWVsQ2FzZSA/IFRPS0VOSVpFX0NBTUVMX0NBU0VfUkVHRVhQIDogVE9LRU5JWkVfTk9OX0FMUEhBTlVNRVJJQ19SRUdFWFA7XG5cbiAgZm9yIChjb25zdCB2YWx1ZSBvZiB2YWx1ZXMpIHtcbiAgICBpZiAodmFsdWUgPT0gbnVsbCkgY29udGludWU7XG4gICAgbGV0IHN0cmluZ1ZhbHVlID0gdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiID8gdmFsdWUgOiBTdHJpbmcodmFsdWUpO1xuICAgIGlmICghc3RyaW5nVmFsdWUpIGNvbnRpbnVlO1xuICAgIGlmIChvcHRzLm9taXRVcmlTY2hlbWUpIHtcbiAgICAgIGNvbnN0IG1hdGNoID0gc3RyaW5nVmFsdWUubWF0Y2goVVJJX1JFR0VYUCk7XG4gICAgICBpZiAobWF0Y2gpIHN0cmluZ1ZhbHVlID0gbWF0Y2hbMl0gPz8gXCJcIjtcbiAgICB9XG4gICAgaWYgKG9wdHMub21pdEVtYWlsRG9tYWluKSB7XG4gICAgICBjb25zdCBtYXRjaCA9IHN0cmluZ1ZhbHVlLm1hdGNoKEVNQUlMX1JFR0VYUCk7XG4gICAgICBpZiAobWF0Y2gpIHN0cmluZ1ZhbHVlID0gbWF0Y2hbMV0gPz8gXCJcIjtcbiAgICB9XG4gICAgaWYgKCFzdHJpbmdWYWx1ZSkgY29udGludWU7XG4gICAgZm9yIChjb25zdCB0b2tlbk1hdGNoIG9mIHN0cmluZ1ZhbHVlLm1hdGNoQWxsKHJlZ2V4cCkpIHtcbiAgICAgIGxldCB0b2tlbiA9IHRva2VuTWF0Y2hbMF0hO1xuICAgICAgaWYgKG9wdHMubG93ZXJDYXNlKSB0b2tlbiA9IHRva2VuLnRvTG93ZXJDYXNlKCk7XG4gICAgICBpZiAob3B0cy5jYXBpdGFsaXplKSB0b2tlbiA9IGNhcGl0YWxpemUodG9rZW4pO1xuICAgICAgaWYgKCF0b2tlbikgY29udGludWU7XG4gICAgICBmb3IgKGNvbnN0IG92ZXJyaWRlIG9mIFRPS0VOSVpFX09WRVJSSURFUykge1xuICAgICAgICB0b2tlbiA9IG92ZXJyaWRlKHRva2VuLCBvcHRzKTtcbiAgICAgICAgaWYgKCF0b2tlbikgYnJlYWs7XG4gICAgICB9XG4gICAgICBpZiAoIXRva2VuIHx8IHNlZW4/Lmhhcyh0b2tlbikpIGNvbnRpbnVlO1xuICAgICAgc2Vlbj8uYWRkKHRva2VuKTtcbiAgICAgIHlpZWxkIHRva2VuO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24qIHRva2VuaXplKC4uLnZhbHVlczogdW5rbm93bltdKTogR2VuZXJhdG9yPHN0cmluZz4ge1xuICB5aWVsZCogdG9rZW5pemVXaXRoT3B0aW9ucyh7fSwgLi4udmFsdWVzKTtcbn1cblxuLyoqXG4gKiBKb2luIHRva2VuaXplZCB2YWx1ZXMgd2l0aCBgZGVsaW1pdGVyYC4gV2hlbiB0aGUgbmV4dCB0b2tlbiB3b3VsZCBwdXNoIHRoZVxuICogcmVzdWx0IG92ZXIgYG1heExlbmd0aGA6IGB0cmltYCBzdG9wcyBhZGRpbmc7IGBlbXB0eWAgcmV0dXJucyBgXCJcImA7IGBoYXNoYFxuICogYXBwZW5kcyBhIGRpZ2VzdCBvZiBhY2NlcHRlZCB0b2tlbnMgcGx1cyB0aGUgb3ZlcmZsb3cgdG9rZW4gaWYgdGhlIHJlc3VsdFxuICogc3RpbGwgZml0cywgb3RoZXJ3aXNlIGBcIlwiYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvSWRlbnRpZmllcldpdGhPcHRpb25zKG9wdGlvbnM6IElkZW50aWZpZXJPcHRpb25zLCAuLi52YWx1ZXM6IHVua25vd25bXSk6IHN0cmluZyB7XG4gIGNvbnN0IG9wdHM6IFJlc29sdmVkSWRlbnRpZmllck9wdGlvbnMgPSB7XG4gICAgLi4uSURFTlRJRklFUl9ERUZBVUxUUyxcbiAgICAuLi5vcHRpb25zLFxuICAgIGxvd2VyQ2FzZTogdHJ1ZSxcbiAgfTtcbiAgY29uc3QgdG9rZW5zOiBzdHJpbmdbXSA9IFtdO1xuICBsZXQgY3VycmVudExlbmd0aCA9IDA7XG5cbiAgZm9yIChjb25zdCB0b2tlbiBvZiB0b2tlbml6ZVdpdGhPcHRpb25zKG9wdHMsIC4uLnZhbHVlcykpIHtcbiAgICBjb25zdCBzZXBMZW5ndGggPSB0b2tlbnMubGVuZ3RoID4gMCA/IG9wdHMuZGVsaW1pdGVyLmxlbmd0aCA6IDA7XG4gICAgY29uc3QgbmV4dExlbmd0aCA9IGN1cnJlbnRMZW5ndGggKyBzZXBMZW5ndGggKyB0b2tlbi5sZW5ndGg7XG5cbiAgICBpZiAobmV4dExlbmd0aCA+IG9wdHMubWF4TGVuZ3RoKSB7XG4gICAgICBpZiAob3B0cy50cnVuY2F0ZVN0cmF0ZWd5ID09PSBcImVtcHR5XCIpIHJldHVybiBcIlwiO1xuICAgICAgaWYgKG9wdHMudHJ1bmNhdGVTdHJhdGVneSA9PT0gXCJ0cmltXCIpIGJyZWFrO1xuXG4gICAgICBjb25zdCBoYXNoID0gZGlnZXN0VG9rZW5zKG9wdHMudHJ1bmNhdGVIYXNoTGVuZ3RoLCB0b2tlbnMsIHRva2VuKTtcbiAgICAgIGlmIChjdXJyZW50TGVuZ3RoICsgc2VwTGVuZ3RoICsgaGFzaC5sZW5ndGggPD0gb3B0cy5tYXhMZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuIHRva2Vucy5sZW5ndGggPiAwID8gdG9rZW5zLmpvaW4ob3B0cy5kZWxpbWl0ZXIpICsgb3B0cy5kZWxpbWl0ZXIgKyBoYXNoIDogaGFzaDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBcIlwiO1xuICAgIH1cblxuICAgIHRva2Vucy5wdXNoKHRva2VuKTtcbiAgICBjdXJyZW50TGVuZ3RoID0gbmV4dExlbmd0aDtcbiAgfVxuXG4gIHJldHVybiB0b2tlbnMuam9pbihvcHRzLmRlbGltaXRlcik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0b0lkZW50aWZpZXIoLi4udmFsdWVzOiB1bmtub3duW10pOiBzdHJpbmcge1xuICByZXR1cm4gdG9JZGVudGlmaWVyV2l0aE9wdGlvbnMoe30sIC4uLnZhbHVlcyk7XG59XG5cbi8qKlxuICogU2x1Z2lmaWVkIGlkZW50aWZpZXI6IHNhbWUgcnVsZXMgYXMge0BsaW5rIHRvSWRlbnRpZmllcldpdGhPcHRpb25zfSB3aXRoIHRoZVxuICogZGVsaW1pdGVyIGZvcmNlZCB0byBgLWAuIEFjY2VwdHMge0BsaW5rIEtleU9wdGlvbnN9IHNvIGNhbGxlcnMgY2Fubm90XG4gKiBvdmVycmlkZSB0aGUgZGVsaW1pdGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9TbHVnV2l0aE9wdGlvbnMob3B0aW9uczogS2V5T3B0aW9ucywgLi4udmFsdWVzOiB1bmtub3duW10pOiBzdHJpbmcge1xuICByZXR1cm4gdG9JZGVudGlmaWVyV2l0aE9wdGlvbnMoeyAuLi5vcHRpb25zLCBkZWxpbWl0ZXI6IFwiLVwiIH0sIC4uLnZhbHVlcyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0b1NsdWcoLi4udmFsdWVzOiB1bmtub3duW10pOiBzdHJpbmcge1xuICByZXR1cm4gdG9TbHVnV2l0aE9wdGlvbnMoe30sIC4uLnZhbHVlcyk7XG59XG5cbi8qKlxuICogVHJpbSBgdmFsdWVgIGFuZCByZXR1cm4gYG51bGxgIGZvciBub24tc3RyaW5ncywgYHVuZGVmaW5lZGAsIG9yXG4gKiBzdHJpbmdzIHRoYXQgYXJlIGVtcHR5IGFmdGVyIHRyaW1taW5nLiBMZXRzIGNhbGwgc2l0ZXMgY29sbGFwc2UgdGhlXG4gKiBjb21tb25cbiAqXG4gKiBgYGB0c1xuICogdHlwZW9mIHYgPT09IFwic3RyaW5nXCIgJiYgdi50cmltKCkgPyB2LnRyaW0oKSA6IG51bGxcbiAqIGBgYFxuICpcbiAqIGRhbmNlIGludG8gYSBzaW5nbGUgaGVscGVyLiBVc2VmdWwgZm9yIEhUVFAgaGVhZGVyIC8gcXVlcnkgLyBmb3JtXG4gKiBleHRyYWN0b3JzIHdoZXJlIGRvd25zdHJlYW0gY29kZSB3YW50cyBgc3RyaW5nIHwgbnVsbGAgdG8gZHJpdmUgYVxuICogY2hlYXAgYD8/YCAvIGBpZiAoeClgIGNhc2NhZGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cmltVG9OdWxsKHZhbHVlOiB1bmtub3duKTogc3RyaW5nIHwgbnVsbCB7XG4gIGlmICh0eXBlb2YgdmFsdWUgIT09IFwic3RyaW5nXCIpIHJldHVybiBudWxsO1xuICBjb25zdCB0cmltbWVkID0gdmFsdWUudHJpbSgpO1xuICByZXR1cm4gdHJpbW1lZCA/IHRyaW1tZWQgOiBudWxsO1xufVxuXG4vLyBDb25maWcgbGlzdHMgYXJyaXZlIGVpdGhlciBhbHJlYWR5IHNwbGl0IChhbiBhcnJheSkgb3IgYXMgb25lIGVudi12YXIgc3RyaW5nXG4vLyB3aXRoIGVudHJpZXMgc2VwYXJhdGVkIGJ5IGNvbW1hcyBhbmQvb3Igd2hpdGVzcGFjZS5cbmNvbnN0IExJU1RfU0VQQVJBVE9SX1JFR0VYUCA9IC9bXFxzLF0rLztcblxuLyoqXG4gKiBOb3JtYWxpemUgYSBjb25maWcgbGlzdCB0aGF0IG1heSBhcnJpdmUgYXMgYW4gYXJyYXkgb3IgYXMgYSBzaW5nbGVcbiAqIGNvbW1hL3doaXRlc3BhY2Utc2VwYXJhdGVkIHN0cmluZzogc3BsaXQsIGFwcGx5IGB0cmFuc2Zvcm1gLCBkcm9wIGVtcHRpZXMsXG4gKiBhbmQgZGUtZHVwbGljYXRlIChmaXJzdCBvY2N1cnJlbmNlIHdpbnMpLlxuICpcbiAqIFRoaXMgaXMgdGhlIHNoYXBlIGV2ZXJ5IGFsbG93LWxpc3QgLyBmYWxsYmFjay1vcmRlciBzZXR0aW5nIGluIHRoaXMgcmVwb1xuICogdGFrZXMsIGJlY2F1c2UgdGhlIHNhbWUgdmFsdWUgY2FuIGNvbWUgZnJvbSB0eXBlZCBjb25maWcgKGBzdHJpbmdbXWApIG9yIGZyb21cbiAqIGFuIGVudmlyb25tZW50IHZhcmlhYmxlIChgXCJhLCBiIGNcImApLiBQYXNzIGB0cmFuc2Zvcm1gIHRvIG5vcm1hbGl6ZSBlbnRyaWVzXG4gKiBhcyB0aGV5IGFyZSByZWFkOyBpdCBkZWZhdWx0cyB0byB0cmltbWluZy5cbiAqXG4gKiBAZXhhbXBsZVxuICogcGFyc2VMaXN0KFwiZG9jcy5leGFtcGxlLmNvbSwgKi5kYXRhYnJpY2tzLmNvbVwiKTtcbiAqIHBhcnNlTGlzdChwcm9jZXNzLmVudi5NT0RFTF9GQUxMQkFDS1MpO1xuICogcGFyc2VMaXN0KHJhdywgbm9ybWFsaXplVXJsUGF0dGVybik7XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUxpc3QoXG4gIHJhdzogc3RyaW5nIHwgcmVhZG9ubHkgc3RyaW5nW10gfCB1bmRlZmluZWQgfCBudWxsLFxuICB0cmFuc2Zvcm06IChlbnRyeTogc3RyaW5nKSA9PiBzdHJpbmcgPSAoZW50cnkpID0+IGVudHJ5LnRyaW0oKSxcbik6IHN0cmluZ1tdIHtcbiAgY29uc3QgZW50cmllcyA9XG4gICAgdHlwZW9mIHJhdyA9PT0gXCJzdHJpbmdcIiA/IHJhdy5zcGxpdChMSVNUX1NFUEFSQVRPUl9SRUdFWFApIDogQXJyYXkuaXNBcnJheShyYXcpID8gcmF3IDogW107XG4gIGNvbnN0IG91dDogc3RyaW5nW10gPSBbXTtcbiAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICBjb25zdCBub3JtYWxpemVkID0gdHJhbnNmb3JtKGVudHJ5KTtcbiAgICBpZiAoIW5vcm1hbGl6ZWQgfHwgc2Vlbi5oYXMobm9ybWFsaXplZCkpIGNvbnRpbnVlO1xuICAgIHNlZW4uYWRkKG5vcm1hbGl6ZWQpO1xuICAgIG91dC5wdXNoKG5vcm1hbGl6ZWQpO1xuICB9XG4gIHJldHVybiBvdXQ7XG59XG5cbi8qKlxuICoge0BsaW5rIHRyaW1Ub051bGx9IHdpdGggYW4gZW1wdHktc3RyaW5nIG1pc3MgaW5zdGVhZCBvZiBgbnVsbGAsIGZvciBjYWxsZXJzXG4gKiB0aGF0IGJ1aWxkIGEgc3RyaW5nIHVuY29uZGl0aW9uYWxseSBhbmQgdHJlYXQgXCJhYnNlbnRcIiBhcyBcIlwiLlxuICpcbiAqIFJlYWRpbmcgbG9vc2VseS10eXBlZCBKU09OIGlzIHRoZSBtb3RpdmF0aW5nIGNhc2U6IGEgZmllbGQgdGhhdCBzaG91bGQgYmUgYVxuICogc3RyaW5nIG1heSBiZSBtaXNzaW5nIG9yIHRoZSB3cm9uZyB0eXBlLCBhbmQgdGhlIGNhbGxlciB3YW50cyBgXCJcImAgcmF0aGVyXG4gKiB0aGFuIGEgbnVsbCBjaGVjayBhdCBldmVyeSBhY2Nlc3MuXG4gKlxuICogQGV4YW1wbGVcbiAqIGNvbnN0IHRpdGxlID0gdHJpbVRvRW1wdHkocmVjb3JkLnRpdGxlKTsgLy8gYWx3YXlzIGEgc3RyaW5nXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0cmltVG9FbXB0eSh2YWx1ZTogdW5rbm93bik6IHN0cmluZyB7XG4gIHJldHVybiB0cmltVG9OdWxsKHZhbHVlKSA/PyBcIlwiO1xufVxuXG4vKipcbiAqIFRyaW0gdGhlIGZpcnN0IHVzYWJsZSBzdHJpbmcgb3V0IG9mIGB2YWx1ZWAuIFJldHVybnMgYG51bGxgIHdoZW5cbiAqIGB2YWx1ZWAgaXMgYHVuZGVmaW5lZGAsIGBudWxsYCwgYW4gZW1wdHkgc3RyaW5nLCBvciBhbiBhcnJheSB3aG9zZVxuICogZmlyc3Qgc3RyaW5nIG1lbWJlciBpcyBlbXB0eS4gTWlycm9ycyBob3cgRXhwcmVzcyAvIE5vZGUgaGVhZGVyXG4gKiBhY2Nlc3NvcnMgZXhwb3NlIHNpbmdsZSB2cy4gcmVwZWF0ZWQgaGVhZGVycyAtIHRoZSBmaXJzdFxuICogbm9uLWVtcHR5IGVudHJ5IHdpbnMsIGV2ZXJ5dGhpbmcgZWxzZSBpcyBpZ25vcmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZmlyc3ROb25FbXB0eSh2YWx1ZTogdW5rbm93bik6IHN0cmluZyB8IG51bGwge1xuICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgdmFsdWUpIHtcbiAgICAgIGNvbnN0IHRyaW1tZWQgPSB0cmltVG9OdWxsKGl0ZW0pO1xuICAgICAgaWYgKHRyaW1tZWQpIHJldHVybiB0cmltbWVkO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICByZXR1cm4gdHJpbVRvTnVsbCh2YWx1ZSk7XG59XG5cbi8qKlxuICogRXNjYXBlIHRoZSBmaXZlIGNoYXJhY3RlcnMgc2lnbmlmaWNhbnQgaW4gSFRNTCB0ZXh0IGFuZFxuICogZG91YmxlLXF1b3RlZCBhdHRyaWJ1dGUgdmFsdWVzIChgJmAsIGA8YCwgYD5gLCBgXCJgLCBgJ2ApIHNvIGFuXG4gKiB1bnRydXN0ZWQgc3RyaW5nIGNhbiBiZSBpbnRlcnBvbGF0ZWQgaW50byBtYXJrdXAgd2l0aG91dCBicmVha2luZ1xuICogb3V0IG9mIGl0cyBjb250ZXh0LiBgJmAgaXMgcmVwbGFjZWQgZmlyc3Qgc28gYW1wZXJzYW5kcyBpbnRyb2R1Y2VkXG4gKiBieSB0aGUgbGF0ZXIgcmVwbGFjZW1lbnRzIGFyZW4ndCBkb3VibGUtZXNjYXBlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVzY2FwZUh0bWwodmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiB2YWx1ZVxuICAgIC5yZXBsYWNlKC8mL2csIFwiJmFtcDtcIilcbiAgICAucmVwbGFjZSgvPC9nLCBcIiZsdDtcIilcbiAgICAucmVwbGFjZSgvPi9nLCBcIiZndDtcIilcbiAgICAucmVwbGFjZSgvXCIvZywgXCImcXVvdDtcIilcbiAgICAucmVwbGFjZSgvJy9nLCBcIiYjMzk7XCIpO1xufVxuXG4vKipcbiAqIFNsdWdpZnkgYHZhbHVlYCAodXNpbmcgdGhlIHN0YW5kYXJkIHtAbGluayB0b0lkZW50aWZpZXJXaXRoT3B0aW9uc31cbiAqIHRva2VuaXplciArIGRlbGltaXRlciBydWxlcykgYW5kICoqYWx3YXlzKiogc3VmZml4IGEgc2hvcnRcbiAqIGRldGVybWluaXN0aWMgaGFzaC4gVXNlIHdoZW4geW91IG5lZWQgYSBzdGFibGUsIHNsdWdpZmllZCBpZCB0aGF0XG4gKiBpcyBndWFyYW50ZWVkIHRvIGJlIHVuaXF1ZSBhY3Jvc3MgZGVzY3JpcHRpb25zIHNoYXJpbmcgdGhlIHNhbWVcbiAqIGxlYWRpbmcgdG9rZW5zICh0b29sIGlkcywgY2FjaGUga2V5cywgZXRjLikuXG4gKlxuICogQmVoYXZpb3VyIGRpZmZlcnMgZnJvbSBgdG9JZGVudGlmaWVyV2l0aE9wdGlvbnMoeyBtYXhMZW5ndGgsXG4gKiB0cnVuY2F0ZVN0cmF0ZWd5OiBcImhhc2hcIiB9KWA6IHRoYXQgaGVscGVyIG9ubHkgYXBwZW5kcyBhIGhhc2ggd2hlblxuICogdGhlIHNsdWcgKm92ZXJmbG93cyogYG1heExlbmd0aGAuIFRoaXMgaGVscGVyIGFwcGVuZHMgYSBoYXNoXG4gKiB1bmNvbmRpdGlvbmFsbHkgc28gdGhlIHJlc3VsdCBpcyBjb2xsaXNpb24tcmVzaXN0YW50IGV2ZW4gZm9yXG4gKiBzaG9ydCBpbnB1dHMuIFRoZSBoYXNoIGlzIGNvbXB1dGVkIG92ZXIgdGhlIHJhdyBgdmFsdWVgIHNvIHR3b1xuICogZGVzY3JpcHRpb25zIHByb2R1Y2luZyB0aGUgc2FtZSBzbHVnIHN0aWxsIGdldCBkaWZmZXJlbnQgaWRzLlxuICpcbiAqIEBwYXJhbSB2YWx1ZSAtIFNvdXJjZSBzdHJpbmcgKHR5cGljYWxseSBhIHRvb2wvYWdlbnQgZGVzY3JpcHRpb24pLlxuICogQHBhcmFtIG9wdGlvbnMuZGVsaW1pdGVyIC0gVG9rZW4gc2VwYXJhdG9yIChkZWZhdWx0IGBcIl9cImApLlxuICogQHBhcmFtIG9wdGlvbnMuc2x1Z01heExlbmd0aCAtIENhcCBvbiB0aGUgc2x1ZyBwb3J0aW9uICh0aGUgcGFydFxuICogICBiZWZvcmUgdGhlIGhhc2gpLiBEZWZhdWx0IDMyLlxuICogQHBhcmFtIG9wdGlvbnMuaGFzaExlbmd0aCAtIExlbmd0aCBvZiB0aGUgc3VmZml4IHByb2R1Y2VkIGJ5XG4gKiAgIHtAbGluayBmbnZIYXNoV2l0aE9wdGlvbnN9IChDcm9ja2ZvcmQtc3R5bGUgYmFzZS0zMiBhbHBoYWJldCwgbWF4IDdcbiAqICAgY2hhcnMpLiBEZWZhdWx0IDYuXG4gKiBAcGFyYW0gb3B0aW9ucy5mYWxsYmFja1ByZWZpeCAtIFByZWZpeCB1c2VkIHdoZW4gdGhlIHNsdWcgaXMgZW1wdHlcbiAqICAgKGUuZy4gcHVuY3R1YXRpb24tb25seSBpbnB1dCkuIERlZmF1bHQgYFwiaWRcImAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0b1VuaXF1ZVNsdWcoXG4gIHZhbHVlOiBzdHJpbmcsXG4gIG9wdGlvbnM6IHtcbiAgICBkZWxpbWl0ZXI/OiBzdHJpbmc7XG4gICAgc2x1Z01heExlbmd0aD86IG51bWJlcjtcbiAgICBoYXNoTGVuZ3RoPzogbnVtYmVyO1xuICAgIGZhbGxiYWNrUHJlZml4Pzogc3RyaW5nO1xuICB9ID0ge30sXG4pOiBzdHJpbmcge1xuICBjb25zdCBkZWxpbWl0ZXIgPSBvcHRpb25zLmRlbGltaXRlciA/PyBcIl9cIjtcbiAgY29uc3Qgc2x1Z01heExlbmd0aCA9IG9wdGlvbnMuc2x1Z01heExlbmd0aCA/PyAzMjtcbiAgY29uc3QgaGFzaExlbmd0aCA9IG9wdGlvbnMuaGFzaExlbmd0aCA/PyA2O1xuICBjb25zdCBmYWxsYmFja1ByZWZpeCA9IG9wdGlvbnMuZmFsbGJhY2tQcmVmaXggPz8gXCJpZFwiO1xuICBjb25zdCBzbHVnID0gdG9JZGVudGlmaWVyV2l0aE9wdGlvbnMoXG4gICAgeyBkZWxpbWl0ZXIsIG1heExlbmd0aDogc2x1Z01heExlbmd0aCwgdHJ1bmNhdGVTdHJhdGVneTogXCJ0cmltXCIgfSxcbiAgICB2YWx1ZSxcbiAgKTtcbiAgY29uc3Qgc3VmZml4ID0gZm52SGFzaFdpdGhPcHRpb25zKHsgbGVuZ3RoOiBoYXNoTGVuZ3RoIH0sIHZhbHVlKTtcbiAgcmV0dXJuIHNsdWcgPyBgJHtzbHVnfSR7ZGVsaW1pdGVyfSR7c3VmZml4fWAgOiBgJHtmYWxsYmFja1ByZWZpeH0ke2RlbGltaXRlcn0ke3N1ZmZpeH1gO1xufVxuXG5mdW5jdGlvbiBkaWdlc3RUb2tlbnMobGVuZ3RoOiBudW1iZXIsIHBhcnRzOiByZWFkb25seSBzdHJpbmdbXSwgZXh0cmE/OiBzdHJpbmcpOiBzdHJpbmcge1xuICBsZXQgY29tYmluZWQgPSBcIlwiO1xuICBmb3IgKGNvbnN0IHBhcnQgb2YgcGFydHMpIGNvbWJpbmVkICs9IHBhcnQgKyBcIlxcMFwiO1xuICBpZiAoZXh0cmEgIT09IHVuZGVmaW5lZCkgY29tYmluZWQgKz0gZXh0cmEgKyBcIlxcMFwiO1xuICByZXR1cm4gZm52SGFzaFdpdGhPcHRpb25zKHsgbGVuZ3RoIH0sIGNvbWJpbmVkKTtcbn1cblxuLyoqXG4gKiBBIG5vZGUgaW4gdGhlIGRlc2NyaXB0aW9uIHRyZWUgY29uc3VtZWQgYnkge0BsaW5rIHRvRGVzY3JpcHRpb259LlxuICpcbiAqIC0gYHN0cmluZ2AgLSBhIHRleHQgcGFyYWdyYXBoLlxuICogLSBgRGVzY3JpcHRpb25bXWAgLSBhIHNlcXVlbmNlIG9mIHN0YWNrZWQgYmxvY2tzIGF0IHRoZSBzYW1lIGxldmVsXG4gKiAgIChubyBsaXN0IG1hcmtlcnMpLiBQbGFpbiB0ZXh0IGFkamFjZW50IHRvIGEgbGlzdCAoZWl0aGVyIGRpcmVjdGlvbilcbiAqICAgZmx1c2hlcyB0b2dldGhlciBzbyB0aGUgcHJvc2UgcmVhZHMgYXMgYSBsZWFkLWluIG9yIHRyYWlsaW5nXG4gKiAgIHN1bW1hcnkuIFR3byB0ZXh0IHBhcmFncmFwaHMsIHR3byBhZGphY2VudCBsaXN0cywgYW5kIGFueXRoaW5nXG4gKiAgIHRvdWNoaW5nIGEgbWFwIGdldCBhIGJsYW5rLWxpbmUgYnJlYWsuXG4gKiAtIGB7IGJ1bGxldHM6IFsuLi5dIH1gIC8gYHsgbnVtYmVyZWQ6IFsuLi5dIH1gIC0gZXhwbGljaXQgbGlzdC4gQVxuICogICBsaXN0IG9mIG9uZSBiYXJlIHN0cmluZyBkcm9wcyBpdHMgbWFya2VyIChgLWAgLyBgMS5gKTsgYSBsaXN0IG9mXG4gKiAgIG9uZSBpdGVtIHdpdGggbmVzdGVkIGNoaWxkcmVuIGtlZXBzIGl0cyBtYXJrZXIgYXMgdGhlIHZpc3VhbCBhbmNob3JcbiAqICAgZm9yIHRoZSBpbmRlbnRlZCBjaGlsZHJlbi5cbiAqIC0gYW55IG90aGVyIG9iamVjdCAtIGhlYWRlcnMgbWFwOiBlYWNoIGtleSBiZWNvbWVzIGEgYEhlYWRlcjpgIGxpbmVcbiAqICAgZm9sbG93ZWQgYnkgYSBibGFuayBsaW5lIGFuZCB0aGUgcmVuZGVyZWQgdmFsdWUuXG4gKi9cbmV4cG9ydCB0eXBlIERlc2NyaXB0aW9uID0gc3RyaW5nIHwgcmVhZG9ubHkgRGVzY3JpcHRpb25bXSB8IHsgcmVhZG9ubHkgW2tleTogc3RyaW5nXTogRGVzY3JpcHRpb24gfTtcblxuY29uc3QgTElTVF9LRVlTID0gW1wiYnVsbGV0c1wiLCBcIm51bWJlcmVkXCJdIGFzIGNvbnN0O1xudHlwZSBMaXN0S2luZCA9ICh0eXBlb2YgTElTVF9LRVlTKVtudW1iZXJdO1xuXG4vKipcbiAqIEZvcm1hdCBhIG5lc3RlZCBkZXNjcmlwdGlvbiB0cmVlIGFzIGEgTWFya2Rvd24taXNoIHN0cmluZyBzdWl0YWJsZVxuICogZm9yIGFuIExMTSBzeXN0ZW0gcHJvbXB0LCBab2QgYC5kZXNjcmliZSgpYCBibG9jaywgTWFzdHJhIHRvb2xcbiAqIGRlc2NyaXB0aW9uLCBvciBhbnkgb3RoZXIgbG9uZy1mb3JtIHRleHQgZGVzdGluYXRpb24uXG4gKlxuICogRXZlcnkgc3RyaW5nIHNlY3Rpb24gaXMgZGVkZW50ZWQgKGNvbW1vbiBsZWFkaW5nIHdoaXRlc3BhY2Ugc3RyaXBwZWQpLFxuICogcmlnaHQtdHJpbW1lZCBsaW5lIGJ5IGxpbmUsIGFuZCBmcmVlZCBvZiBsZWFkaW5nIC8gdHJhaWxpbmcgYmxhbmtcbiAqIGxpbmVzLCBzbyBjYWxsZXJzIGNhbiB3cml0ZSBtdWx0aS1saW5lIHRlbXBsYXRlIGxpdGVyYWxzIGluZGVudGVkXG4gKiBuYXR1cmFsbHkgaW4gc291cmNlIHdpdGhvdXQgbGVha2luZyB0aGF0IGluZGVudGF0aW9uIGludG8gdGhlXG4gKiBjb25zdW1lci1mYWNpbmcgb3V0cHV0LiBQbGFpbi1zdHJpbmcgaW5wdXRzIGZsb3cgdGhyb3VnaCB1bmNoYW5nZWRcbiAqIGFwYXJ0IGZyb20gdGhlIHNhbWUgbm9ybWFsaXphdGlvbiBwYXNzLCBzbyBhIHNpbmdsZSBtdWx0aS1saW5lXG4gKiB0ZW1wbGF0ZSBsaXRlcmFsIHdvcmtzIGRpcmVjdGx5OlxuICpcbiAqIGBgYHRzXG4gKiB0b0Rlc2NyaXB0aW9uKGBcbiAqICAgQXNrIHRoZSBHZW5pZSBzcGFjZSBcIiR7YWxpYXN9XCIgYSBxdWVzdGlvbi5cbiAqICAgUGFzcyB0aGUgYW5zd2VyIHRocm91Z2ggYXMtaXMuXG4gKiBgKTtcbiAqIC8vIEFzayB0aGUgR2VuaWUgc3BhY2UgXCJkZWZhdWx0XCIgYSBxdWVzdGlvbi5cbiAqIC8vIFBhc3MgdGhlIGFuc3dlciB0aHJvdWdoIGFzLWlzLlxuICpcbiAqIHRvRGVzY3JpcHRpb24oW1xuICogICBgXG4gKiAgICAgQXNrIHRoZSBHZW5pZSBzcGFjZSBhIHF1ZXN0aW9uLlxuICogICAgIFBocmFzZSBpdCBmcm9tIHRoZSB1c2VyJ3MgcGVyc3BlY3RpdmUuXG4gKiAgIGAsXG4gKiAgIHsgYnVsbGV0czogW1xuICogICAgIFtcIlBhc3MgdGhlIGFuc3dlciB0aHJvdWdoIGFzLWlzXCIsIHsgbnVtYmVyZWQ6IFtcIml0ZW1cIiwgXCJpdGVtXCJdIH1dLFxuICogICBdfSxcbiAqICAgeyBJbnN0cnVjdGlvbnM6IFwiUmVwbHkgd2l0aCB0aGUgU1FMIG9ubHkuXCIgfSxcbiAqIF0pO1xuICogLy8gQXNrIHRoZSBHZW5pZSBzcGFjZSBhIHF1ZXN0aW9uLlxuICogLy8gUGhyYXNlIGl0IGZyb20gdGhlIHVzZXIncyBwZXJzcGVjdGl2ZS5cbiAqIC8vIC0gUGFzcyB0aGUgYW5zd2VyIHRocm91Z2ggYXMtaXNcbiAqIC8vICAgMS4gaXRlbVxuICogLy8gICAyLiBpdGVtXG4gKiAvL1xuICogLy8gSW5zdHJ1Y3Rpb25zOlxuICogLy9cbiAqIC8vIFJlcGx5IHdpdGggdGhlIFNRTCBvbmx5LlxuICogYGBgXG4gKlxuICogU2VlIHtAbGluayBEZXNjcmlwdGlvbn0gZm9yIHRoZSBub2RlIGdyYW1tYXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0b0Rlc2NyaXB0aW9uKG5vZGU6IERlc2NyaXB0aW9uKTogc3RyaW5nIHtcbiAgcmV0dXJuIHJlbmRlckJsb2NrKG5vZGUsIFwiXCIpXG4gICAgLnJlcGxhY2UoL1sgXFx0XSskL2dtLCBcIlwiKVxuICAgIC5yZXBsYWNlKC9cXG4rJC8sIFwiXCIpO1xufVxuXG5mdW5jdGlvbiByZW5kZXJCbG9jayhub2RlOiBEZXNjcmlwdGlvbiwgcGFkOiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAobm9kZSA9PSBudWxsKSByZXR1cm4gXCJcIjtcbiAgaWYgKHR5cGVvZiBub2RlID09PSBcInN0cmluZ1wiKSByZXR1cm4gcHJlcGVuZFBhZChkZWRlbnRTZWN0aW9uKG5vZGUpLCBwYWQpO1xuICBpZiAoQXJyYXkuaXNBcnJheShub2RlKSkgcmV0dXJuIHJlbmRlclNlcXVlbmNlKG5vZGUsIHBhZCk7XG4gIGNvbnN0IGtpbmQgPSBsaXN0S2luZChub2RlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KTtcbiAgaWYgKGtpbmQpIHtcbiAgICByZXR1cm4gcmVuZGVyTGlzdCgobm9kZSBhcyBSZWNvcmQ8TGlzdEtpbmQsIHJlYWRvbmx5IERlc2NyaXB0aW9uW10+KVtraW5kXSwgcGFkLCBraW5kKTtcbiAgfVxuICByZXR1cm4gcmVuZGVyTWFwKG5vZGUgYXMgUmVjb3JkPHN0cmluZywgRGVzY3JpcHRpb24+LCBwYWQpO1xufVxuXG4vKipcbiAqIE5vcm1hbGl6ZSBhIHN0cmluZyBzZWN0aW9uOiByaWdodC1zdHJpcCBldmVyeSBsaW5lLCBkcm9wIHRoZVxuICogY29tbW9uIGxlYWRpbmctd2hpdGVzcGFjZSBwcmVmaXggc2hhcmVkIGJ5IGFsbCBub24tYmxhbmsgbGluZXMsXG4gKiBhbmQgdHJpbSBsZWFkaW5nIC8gdHJhaWxpbmcgYmxhbmsgbGluZXMuIE1hdGNoZXMgUHl0aG9uJ3NcbiAqIGB0ZXh0d3JhcC5kZWRlbnRgIHNlbWFudGljcyBzbyBlbWJlZGRlZCBpbmRlbnRlZCB0ZW1wbGF0ZVxuICogbGl0ZXJhbHMgcm91bmQtdHJpcCBjbGVhbmx5LlxuICovXG5mdW5jdGlvbiBkZWRlbnRTZWN0aW9uKHRleHQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIGlmICghdGV4dCkgcmV0dXJuIFwiXCI7XG4gIGNvbnN0IGxpbmVzID0gdGV4dC5zcGxpdChcIlxcblwiKS5tYXAoKGxpbmUpID0+IGxpbmUucmVwbGFjZSgvWyBcXHRdKyQvLCBcIlwiKSk7XG4gIGxldCBtaW4gPSBJbmZpbml0eTtcbiAgZm9yIChjb25zdCBsaW5lIG9mIGxpbmVzKSB7XG4gICAgaWYgKCFsaW5lKSBjb250aW51ZTtcbiAgICBjb25zdCBtYXRjaCA9IC9eWyBcXHRdKi8uZXhlYyhsaW5lKTtcbiAgICBjb25zdCB3aWR0aCA9IG1hdGNoID8gbWF0Y2hbMF0ubGVuZ3RoIDogMDtcbiAgICBpZiAod2lkdGggPCBtaW4pIG1pbiA9IHdpZHRoO1xuICB9XG4gIGNvbnN0IHN0cmlwcGVkID1cbiAgICBtaW4gPT09IEluZmluaXR5IHx8IG1pbiA9PT0gMCA/IGxpbmVzIDogbGluZXMubWFwKChsaW5lKSA9PiAobGluZSA/IGxpbmUuc2xpY2UobWluKSA6IFwiXCIpKTtcbiAgbGV0IHN0YXJ0ID0gMDtcbiAgbGV0IGVuZCA9IHN0cmlwcGVkLmxlbmd0aDtcbiAgd2hpbGUgKHN0YXJ0IDwgZW5kICYmICFzdHJpcHBlZFtzdGFydF0pIHN0YXJ0ICs9IDE7XG4gIHdoaWxlIChlbmQgPiBzdGFydCAmJiAhc3RyaXBwZWRbZW5kIC0gMV0pIGVuZCAtPSAxO1xuICByZXR1cm4gc3RyaXBwZWQuc2xpY2Uoc3RhcnQsIGVuZCkuam9pbihcIlxcblwiKTtcbn1cblxuLyoqXG4gKiBBbiBvYmplY3QgaXMgdHJlYXRlZCBhcyBhIHR5cGVkIGxpc3Qgb25seSB3aGVuIGl0IGhhcyBleGFjdGx5IG9uZVxuICogb3duIGtleSwgdGhhdCBrZXkgaXMgYGJ1bGxldHNgIG9yIGBudW1iZXJlZGAsIGFuZCB0aGUgdmFsdWUgaXMgYW5cbiAqIGFycmF5LiBFdmVyeXRoaW5nIGVsc2UgaXMgYSBoZWFkZXJzIG1hcCAtIHNvIGNhbGxlcnMgd2FudGluZyBhXG4gKiBzaW5nbGUgaGVhZGVyIGxpdGVyYWxseSBuYW1lZCBgYnVsbGV0c2Agb3IgYG51bWJlcmVkYCBjYW4gdXNlIGFcbiAqIG11bHRpLWtleSBtYXAgb3IgcmVuYW1lLlxuICovXG5mdW5jdGlvbiBsaXN0S2luZChub2RlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IExpc3RLaW5kIHwgbnVsbCB7XG4gIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhub2RlKTtcbiAgaWYgKGtleXMubGVuZ3RoICE9PSAxKSByZXR1cm4gbnVsbDtcbiAgY29uc3Qga2V5ID0ga2V5c1swXSE7XG4gIGlmICgoTElTVF9LRVlTIGFzIHJlYWRvbmx5IHN0cmluZ1tdKS5pbmNsdWRlcyhrZXkpICYmIEFycmF5LmlzQXJyYXkobm9kZVtrZXldKSkge1xuICAgIHJldHVybiBrZXkgYXMgTGlzdEtpbmQ7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbmZ1bmN0aW9uIHByZXBlbmRQYWQodGV4dDogc3RyaW5nLCBwYWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIGlmICghdGV4dCkgcmV0dXJuIFwiXCI7XG4gIGlmICghcGFkKSByZXR1cm4gdGV4dDtcbiAgcmV0dXJuIHRleHRcbiAgICAuc3BsaXQoXCJcXG5cIilcbiAgICAubWFwKChsaW5lKSA9PiAobGluZSA/IHBhZCArIGxpbmUgOiBcIlwiKSlcbiAgICAuam9pbihcIlxcblwiKTtcbn1cblxuZnVuY3Rpb24gcmVuZGVyU2VxdWVuY2UoaXRlbXM6IHJlYWRvbmx5IERlc2NyaXB0aW9uW10sIHBhZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgcmVuZGVyZWQ6IHsgdGV4dDogc3RyaW5nOyBub2RlOiBEZXNjcmlwdGlvbiB9W10gPSBbXTtcbiAgZm9yIChjb25zdCBpdGVtIG9mIGl0ZW1zKSB7XG4gICAgY29uc3QgdGV4dCA9IHJlbmRlckJsb2NrKGl0ZW0sIHBhZCk7XG4gICAgaWYgKCF0ZXh0KSBjb250aW51ZTtcbiAgICByZW5kZXJlZC5wdXNoKHsgdGV4dCwgbm9kZTogaXRlbSB9KTtcbiAgfVxuICBpZiAocmVuZGVyZWQubGVuZ3RoID09PSAwKSByZXR1cm4gXCJcIjtcbiAgbGV0IG91dCA9IHJlbmRlcmVkWzBdIS50ZXh0O1xuICBmb3IgKGxldCBpID0gMTsgaSA8IHJlbmRlcmVkLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgY29uc3Qgc2VwID0gbmVlZHNCbGFua0xpbmVCZXR3ZWVuKHJlbmRlcmVkW2kgLSAxXSEubm9kZSwgcmVuZGVyZWRbaV0hLm5vZGUpID8gXCJcXG5cXG5cIiA6IFwiXFxuXCI7XG4gICAgb3V0ICs9IHNlcCArIHJlbmRlcmVkW2ldIS50ZXh0O1xuICB9XG4gIHJldHVybiBvdXQ7XG59XG5cbi8qKlxuICogTWFwcyBhbHdheXMgY3JlYXRlIHRoZWlyIG93biBzZWN0aW9uIGJvdW5kYXJ5IChhIGBIZWFkZXI6YCBsaW5lIHBsdXNcbiAqIGEgYmxhbmsgbGluZSBiZWZvcmUgdGhlIGJvZHkpLCBzbyBhbnl0aGluZyB0b3VjaGluZyBhIG1hcCBnZXRzIGFcbiAqIGJsYW5rLWxpbmUgYnJlYWsuIFBsYWluIHRleHQgYWRqYWNlbnQgdG8gYSB0eXBlZCBsaXN0IGZsdXNoZXNcbiAqIHRvZ2V0aGVyIGluIGVpdGhlciBkaXJlY3Rpb246IHRleHQtYmVmb3JlLWxpc3QgcmVhZHMgYXMgYSBsZWFkLWluLFxuICogdGV4dC1hZnRlci1saXN0IGFzIGEgdHJhaWxpbmcgc3VtbWFyeS4gVHdvIHRleHQgcGFyYWdyYXBocyBhbmQgdHdvXG4gKiBhZGphY2VudCBsaXN0cyBib3RoIGdldCBhIGJsYW5rLWxpbmUgYnJlYWsgZm9yIGxlZ2liaWxpdHkuXG4gKi9cbmZ1bmN0aW9uIG5lZWRzQmxhbmtMaW5lQmV0d2VlbihwcmV2OiBEZXNjcmlwdGlvbiwgY3VycjogRGVzY3JpcHRpb24pOiBib29sZWFuIHtcbiAgaWYgKGlzTWFwKHByZXYpIHx8IGlzTWFwKGN1cnIpKSByZXR1cm4gdHJ1ZTtcbiAgY29uc3QgcHJldklzVGV4dCA9IHR5cGVvZiBwcmV2ID09PSBcInN0cmluZ1wiO1xuICBjb25zdCBjdXJySXNUZXh0ID0gdHlwZW9mIGN1cnIgPT09IFwic3RyaW5nXCI7XG4gIGlmIChwcmV2SXNUZXh0ICE9PSBjdXJySXNUZXh0KSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiB0cnVlO1xufVxuXG4vKipcbiAqIEEgbm9kZSBpcyBhIGhlYWRlcnMgbWFwIHdoZW4gaXQgaXMgYSBub24tYXJyYXksIG5vbi1saXN0IG9iamVjdC5cbiAqIGBidWxsZXRzYCAvIGBudW1iZXJlZGAgc2luZ2xlLWtleSBvYmplY3RzIGFyZSB0aGUgb25seSBzdHJ1Y3R1cmVkXG4gKiBvYmplY3RzIHRoYXQgYXJlbid0IG1hcHMuXG4gKi9cbmZ1bmN0aW9uIGlzTWFwKG5vZGU6IERlc2NyaXB0aW9uKTogYm9vbGVhbiB7XG4gIGlmIChub2RlID09IG51bGwpIHJldHVybiBmYWxzZTtcbiAgaWYgKHR5cGVvZiBub2RlID09PSBcInN0cmluZ1wiKSByZXR1cm4gZmFsc2U7XG4gIGlmIChBcnJheS5pc0FycmF5KG5vZGUpKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiBsaXN0S2luZChub2RlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PT0gbnVsbDtcbn1cblxuZnVuY3Rpb24gcmVuZGVyTGlzdChpdGVtczogcmVhZG9ubHkgRGVzY3JpcHRpb25bXSwgcGFkOiBzdHJpbmcsIGtpbmQ6IExpc3RLaW5kKTogc3RyaW5nIHtcbiAgaWYgKGl0ZW1zLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFwiXCI7XG4gIGlmIChpdGVtcy5sZW5ndGggPT09IDEgJiYgdHlwZW9mIGl0ZW1zWzBdID09PSBcInN0cmluZ1wiKSB7XG4gICAgcmV0dXJuIHByZXBlbmRQYWQoaXRlbXNbMF0sIHBhZCk7XG4gIH1cbiAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgaXRlbXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBjb25zdCBpdGVtID0gaXRlbXNbaV0hO1xuICAgIGNvbnN0IG1hcmtlciA9IGtpbmQgPT09IFwiYnVsbGV0c1wiID8gXCItIFwiIDogYCR7aSArIDF9LiBgO1xuICAgIGNvbnN0IGJvZHkgPSByZW5kZXJCbG9jayhpdGVtLCBcIlwiKTtcbiAgICBjb25zdCBib2R5TGluZXMgPSBib2R5LnNwbGl0KFwiXFxuXCIpO1xuICAgIGxpbmVzLnB1c2goYCR7cGFkfSR7bWFya2VyfSR7Ym9keUxpbmVzWzBdID8/IFwiXCJ9YCk7XG4gICAgY29uc3QgY29udGludWF0aW9uID0gcGFkICsgXCIgXCIucmVwZWF0KG1hcmtlci5sZW5ndGgpO1xuICAgIGZvciAoY29uc3QgbGluZSBvZiBib2R5TGluZXMuc2xpY2UoMSkpIHtcbiAgICAgIGxpbmVzLnB1c2gobGluZSA/IGAke2NvbnRpbnVhdGlvbn0ke2xpbmV9YCA6IFwiXCIpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gbGluZXMuam9pbihcIlxcblwiKTtcbn1cblxuZnVuY3Rpb24gcmVuZGVyTWFwKG5vZGU6IFJlY29yZDxzdHJpbmcsIERlc2NyaXB0aW9uPiwgcGFkOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBwYXJ0czogc3RyaW5nW10gPSBbXTtcbiAgZm9yIChjb25zdCBbaGVhZGVyLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobm9kZSkpIHtcbiAgICBjb25zdCBib2R5ID0gcmVuZGVyQmxvY2sodmFsdWUsIHBhZCk7XG4gICAgaWYgKCFib2R5ICYmICFoZWFkZXIudHJpbSgpKSBjb250aW51ZTtcbiAgICBjb25zdCBoZWFkZXJMaW5lID0gaGVhZGVyLnRyaW0oKSA/IGAke3BhZH0ke2hlYWRlcn06YCA6IFwiXCI7XG4gICAgcGFydHMucHVzaChib2R5ID8gYCR7aGVhZGVyTGluZX1cXG5cXG4ke2JvZHl9YCA6IGhlYWRlckxpbmUpO1xuICB9XG4gIHJldHVybiBwYXJ0cy5qb2luKFwiXFxuXFxuXCIpO1xufVxuXG4vKipcbiAqIEZvcm1hdCBhIGNvdW50IHdpdGggaXRzIG5vdW4sIHBsdXJhbGl6aW5nIChuYWl2ZSBgK3NgKSB1bmxlc3MgdGhlIGNvdW50IGlzIDE6XG4gKiBgcGx1cmFsaXplKDEsIFwiYmFycmVsXCIpYCAtPiBgXCIxIGJhcnJlbFwiYCwgYHBsdXJhbGl6ZSgzLCBcImJhcnJlbFwiKWAgLT5cbiAqIGBcIjMgYmFycmVsc1wiYC4gQ29sbGFwc2VzIHRoZSBgJHtufSBub3VuJHtuID09PSAxID8gXCJcIiA6IFwic1wifWAgaWRpb20uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwbHVyYWxpemUoY291bnQ6IG51bWJlciwgbm91bjogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke2NvdW50fSAke25vdW59JHtjb3VudCA9PT0gMSA/IFwiXCIgOiBcInNcIn1gO1xufVxuXG4vKipcbiAqIFRpdGxlLWNhc2UgYSBzbmFrZSAvIGtlYmFiIC8gY2FtZWwgaWRlbnRpZmllciBpbnRvIGEgaHVtYW4tcmVhZGFibGUgbGFiZWw6XG4gKiB0b2tlbml6ZSAobG93ZXJjYXNlZCwgY2FwaXRhbGl6ZWQpLCB0aGVuIGpvaW4gd2l0aCBzcGFjZXMuIEZhbGxzIGJhY2sgdG9cbiAqIHRoZSByYXcgYHZhbHVlYCB3aGVuIGl0IHlpZWxkcyBubyB0b2tlbnMgKGUuZy4gcHVuY3R1YXRpb24tb25seSBpbnB1dCkuXG4gKiBgYmdlX2xhcmdlX2VuYCAtPiBgXCJCZ2UgTGFyZ2UgRW5cImAsIGBwcm9tcHRJZGAgLT4gYFwiUHJvbXB0IElkXCJgLlxuICpcbiAqIFRoZSBzaW5nbGUgc291cmNlIG9mIHRydXRoIGZvciB0aGUgXCJodW1hbml6ZSBhIGNvbHVtbiAvIGZpZWxkIG5hbWVcIiBpZGlvbSAtXG4gKiByZXVzZWQgYnkgdGhlIGNoYXQgZGF0YS1ncmlkIGhlYWRlcnMgYW5kIHRoZSBleHBvcnQgcmVuZGVyZXIuIEV4dHJhXG4gKiB7QGxpbmsgVG9rZW5pemVPcHRpb25zfSAoZS5nLiBgY2FtZWxDYXNlOiBmYWxzZWApIG1lcmdlIG92ZXIgdGhlIGRlZmF1bHRzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9MYWJlbCh2YWx1ZTogc3RyaW5nLCBvcHRpb25zPzogVG9rZW5pemVPcHRpb25zKTogc3RyaW5nIHtcbiAgY29uc3QgdG9rZW5zID0gWy4uLnRva2VuaXplV2l0aE9wdGlvbnMoeyBsb3dlckNhc2U6IHRydWUsIGNhcGl0YWxpemU6IHRydWUsIC4uLm9wdGlvbnMgfSwgdmFsdWUpXTtcbiAgcmV0dXJuIHRva2Vucy5sZW5ndGggPiAwID8gdG9rZW5zLmpvaW4oXCIgXCIpIDogdmFsdWU7XG59XG5cbi8qKlxuICogVXBwZXItY2FzZSB0aGUgZmlyc3QgY2hhcmFjdGVyIG9mIGB2YWx1ZWAsIGxlYXZpbmcgdGhlIHJlc3QgdW50b3VjaGVkLlxuICogYFwid29ya2luZ1wiYCAtPiBgXCJXb3JraW5nXCJgLiBDb2xsYXBzZXMgdGhlXG4gKiBgcy5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSArIHMuc2xpY2UoMSlgIGlkaW9tLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2FwaXRhbGl6ZSh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHZhbHVlID8gdmFsdWUuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyB2YWx1ZS5zbGljZSgxKSA6IHZhbHVlO1xufVxuIl19
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT access-token helpers for Databricks Apps.
|
|
3
|
+
*
|
|
4
|
+
* Parses bearer tokens and `x-forwarded-access-token` payloads to read
|
|
5
|
+
* OAuth scopes and other claims from incoming HTTP requests.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { type HeaderLike } from "./http.js";
|
|
10
|
+
/**
|
|
11
|
+
* Decode the JWT payload from a bearer token string or request headers.
|
|
12
|
+
*
|
|
13
|
+
* When `input` is header-like, walks every value for `headerName` (default
|
|
14
|
+
* `x-forwarded-access-token`) and merges claim keys left-to-right.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getAccessTokenPayload(input: HeaderLike | string, headerName?: string | undefined): Record<string, unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* OAuth scopes from the access-token JWT on `input`.
|
|
19
|
+
*
|
|
20
|
+
* Defaults to the `x-forwarded-access-token` header, which Databricks Apps
|
|
21
|
+
* forward from the browser session.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getAccessTokenScopes(input: HeaderLike | string, headerName?: string): Iterable<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Return true when `scopes` contains any value from `allowed`.
|
|
26
|
+
*
|
|
27
|
+
* Accepts the raw {@link MASTRA_SCOPES_KEY} array stamped on
|
|
28
|
+
* `RequestContext` as well as iterables from {@link getAccessTokenScopes}.
|
|
29
|
+
*/
|
|
30
|
+
export declare function includesAccessTokenScope(scopes: unknown, allowed: readonly string[]): boolean;
|