@dbx-tools/shared-core 0.9.5 → 0.9.7
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 +45 -35
- package/index.ts +12 -12
- package/lib/index.d.ts +12 -12
- package/lib/index.js +8 -8
- package/lib/src/{async.d.ts → async-utils.d.ts} +20 -0
- package/lib/src/async-utils.js +208 -0
- package/lib/src/brand-utils.js +132 -0
- package/lib/src/error-utils.js +168 -0
- package/lib/src/execution.js +3 -3
- package/lib/src/{function.d.ts → function-utils.d.ts} +1 -1
- package/lib/src/function-utils.js +44 -0
- package/lib/src/log.js +2 -2
- package/lib/src/pattern.js +2 -2
- package/lib/src/{string.d.ts → string-utils.d.ts} +19 -0
- package/lib/src/string-utils.js +520 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/{async.ts → async-utils.ts} +62 -0
- package/src/{error.ts → error-utils.ts} +1 -1
- package/src/execution.ts +2 -2
- package/src/{function.ts → function-utils.ts} +1 -1
- package/src/log.ts +1 -1
- package/src/pattern.ts +1 -1
- package/src/{string.ts → string-utils.ts} +33 -13
- package/lib/src/async.js +0 -169
- package/lib/src/brand.js +0 -132
- package/lib/src/error.js +0 -168
- package/lib/src/function.js +0 -44
- package/lib/src/string.js +0 -513
- /package/lib/src/{brand.d.ts → brand-utils.d.ts} +0 -0
- /package/lib/src/{error.d.ts → error-utils.d.ts} +0 -0
- /package/src/{brand.ts → brand-utils.ts} +0 -0
|
@@ -10,6 +10,68 @@ import { deepEqual } from "./object.ts";
|
|
|
10
10
|
|
|
11
11
|
const DEFAULT_RETRY_DELAYS_MS = [1_000, 2_000, 5_000, 10_000, 30_000] as const;
|
|
12
12
|
|
|
13
|
+
/** Controls how {@link mapConcurrent} reacts when a worker rejects. */
|
|
14
|
+
export type ConcurrentErrorMode = "fail-fast" | "settle";
|
|
15
|
+
|
|
16
|
+
/** Bounded-worker settings for {@link mapConcurrent}. */
|
|
17
|
+
export interface MapConcurrentOptions {
|
|
18
|
+
/** Maximum number of callbacks running at once. */
|
|
19
|
+
concurrency: number;
|
|
20
|
+
/**
|
|
21
|
+
* `"fail-fast"` stops claiming new work after the first rejection.
|
|
22
|
+
* `"settle"` attempts every value and throws an `AggregateError` afterward.
|
|
23
|
+
*/
|
|
24
|
+
errorMode?: ConcurrentErrorMode;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Map values through a bounded worker pool while preserving input order.
|
|
29
|
+
*
|
|
30
|
+
* Active callbacks are always allowed to settle. In fail-fast mode no new
|
|
31
|
+
* callback starts after the first observed rejection. Settle mode attempts
|
|
32
|
+
* every value and reports all failures in input order through `AggregateError`.
|
|
33
|
+
*/
|
|
34
|
+
export async function mapConcurrent<T, R>(
|
|
35
|
+
values: readonly T[],
|
|
36
|
+
callback: (value: T, index: number) => R | PromiseLike<R>,
|
|
37
|
+
options: MapConcurrentOptions,
|
|
38
|
+
): Promise<R[]> {
|
|
39
|
+
const { concurrency, errorMode = "fail-fast" } = options;
|
|
40
|
+
if (!Number.isSafeInteger(concurrency) || concurrency < 1) {
|
|
41
|
+
throw new RangeError(`concurrency must be a positive integer, got ${String(concurrency)}`);
|
|
42
|
+
}
|
|
43
|
+
if (values.length === 0) return [];
|
|
44
|
+
|
|
45
|
+
const results = new Array<R>(values.length);
|
|
46
|
+
const failures: Array<{ index: number; reason: unknown }> = [];
|
|
47
|
+
let next = 0;
|
|
48
|
+
let failed = false;
|
|
49
|
+
|
|
50
|
+
const worker = async (): Promise<void> => {
|
|
51
|
+
while (next < values.length && !(failed && errorMode === "fail-fast")) {
|
|
52
|
+
const index = next++;
|
|
53
|
+
try {
|
|
54
|
+
results[index] = await callback(values[index]!, index);
|
|
55
|
+
} catch (reason) {
|
|
56
|
+
failures.push({ index, reason });
|
|
57
|
+
failed = true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, values.length) }, () => worker()));
|
|
63
|
+
if (failures.length === 0) return results;
|
|
64
|
+
|
|
65
|
+
failures.sort((left, right) => left.index - right.index);
|
|
66
|
+
if (errorMode === "settle") {
|
|
67
|
+
throw new AggregateError(
|
|
68
|
+
failures.map(({ reason }) => reason),
|
|
69
|
+
`${failures.length} concurrent operation${failures.length === 1 ? "" : "s"} failed`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
throw failures[0]!.reason;
|
|
73
|
+
}
|
|
74
|
+
|
|
13
75
|
export function boundedRetryDelay(
|
|
14
76
|
attempt: number,
|
|
15
77
|
delaysMs: readonly number[] = DEFAULT_RETRY_DELAYS_MS,
|
package/src/execution.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Generic helpers for AppKit-style intercepted execution. */
|
|
2
|
-
import * as async from "./async.ts";
|
|
3
|
-
import * as error from "./error.ts";
|
|
2
|
+
import * as async from "./async-utils.ts";
|
|
3
|
+
import * as error from "./error-utils.ts";
|
|
4
4
|
import * as object from "./object.ts";
|
|
5
5
|
|
|
6
6
|
/** Success/failure shape returned by an interceptor-backed executor. */
|
|
@@ -32,7 +32,7 @@ export interface MemoizeOptions {
|
|
|
32
32
|
* pending promise until it settles.
|
|
33
33
|
*
|
|
34
34
|
* @example
|
|
35
|
-
* const ranges =
|
|
35
|
+
* const ranges = functionUtils.memoize(fetchIpRanges, { ttlMs: 24 * 60 * 60 * 1000 });
|
|
36
36
|
* await ranges(); // fetches
|
|
37
37
|
* await ranges(); // cached until 24h later
|
|
38
38
|
*/
|
package/src/log.ts
CHANGED
package/src/pattern.ts
CHANGED
|
@@ -47,6 +47,18 @@ export type IdentifierOptions = KeyOptions & {
|
|
|
47
47
|
delimiter?: string;
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
+
/** Leading and trailing blank-line handling for {@link dedent}. */
|
|
51
|
+
export type DedentOptions = {
|
|
52
|
+
/** Remove leading blank lines after indentation normalization. Defaults to `true`. */
|
|
53
|
+
trimStart?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Remove trailing blank lines after indentation normalization. Defaults to `true`.
|
|
56
|
+
*/
|
|
57
|
+
trimEnd?: boolean;
|
|
58
|
+
/** Remove spaces and tabs from each line end. Defaults to `true`. */
|
|
59
|
+
trimLineEnd?: boolean;
|
|
60
|
+
};
|
|
61
|
+
|
|
50
62
|
type ResolvedTokenizeOptions = Required<TokenizeOptions>;
|
|
51
63
|
type ResolvedIdentifierOptions = Required<
|
|
52
64
|
IdentifierOptions & Pick<TokenizeOptions, "lowerCase" | "capitalize">
|
|
@@ -420,7 +432,7 @@ export function toDescription(node: Description): string {
|
|
|
420
432
|
|
|
421
433
|
function renderBlock(node: Description, pad: string): string {
|
|
422
434
|
if (node == null) return "";
|
|
423
|
-
if (typeof node === "string") return prependPad(
|
|
435
|
+
if (typeof node === "string") return prependPad(dedent(node), pad);
|
|
424
436
|
if (Array.isArray(node)) return renderSequence(node, pad);
|
|
425
437
|
const kind = listKind(node as Record<string, unknown>);
|
|
426
438
|
if (kind) {
|
|
@@ -430,18 +442,17 @@ function renderBlock(node: Description, pad: string): string {
|
|
|
430
442
|
}
|
|
431
443
|
|
|
432
444
|
/**
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
*
|
|
436
|
-
* `textwrap.dedent` semantics so embedded indented template
|
|
437
|
-
* literals round-trip cleanly.
|
|
445
|
+
* Right-strip every line, remove common indentation, and optionally trim
|
|
446
|
+
* leading and trailing blank lines. Whitespace-only lines normalize to empty
|
|
447
|
+
* lines, matching common dedent implementations.
|
|
438
448
|
*/
|
|
439
|
-
function
|
|
440
|
-
if (!text) return
|
|
441
|
-
const
|
|
449
|
+
export function dedentLines(text: string, options: DedentOptions = {}): string[] {
|
|
450
|
+
if (!text) return [];
|
|
451
|
+
const { trimStart = true, trimEnd = true, trimLineEnd = true } = options;
|
|
452
|
+
const lines = text.split("\n").map((line) => (trimLineEnd ? line.replace(/[ \t]+$/, "") : line));
|
|
442
453
|
let min = Infinity;
|
|
443
454
|
for (const line of lines) {
|
|
444
|
-
if (!line) continue;
|
|
455
|
+
if (!line.trim()) continue;
|
|
445
456
|
const match = /^[ \t]*/.exec(line);
|
|
446
457
|
const width = match ? match[0].length : 0;
|
|
447
458
|
if (width < min) min = width;
|
|
@@ -450,9 +461,18 @@ function dedentSection(text: string): string {
|
|
|
450
461
|
min === Infinity || min === 0 ? lines : lines.map((line) => (line ? line.slice(min) : ""));
|
|
451
462
|
let start = 0;
|
|
452
463
|
let end = stripped.length;
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
464
|
+
if (trimStart) {
|
|
465
|
+
while (start < end && !stripped[start]!.trim()) start += 1;
|
|
466
|
+
}
|
|
467
|
+
if (trimEnd) {
|
|
468
|
+
while (end > start && !stripped[end - 1]!.trim()) end -= 1;
|
|
469
|
+
}
|
|
470
|
+
return stripped.slice(start, end);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/** Join {@link dedentLines}, trimming leading and trailing blank lines by default. */
|
|
474
|
+
export function dedent(text: string, options: DedentOptions = {}): string {
|
|
475
|
+
return dedentLines(text, options).join("\n");
|
|
456
476
|
}
|
|
457
477
|
|
|
458
478
|
/**
|
package/lib/src/async.js
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cancellation-aware async primitives: an abortable {@link sleep}, an
|
|
3
|
-
* {@link AbortController} linker ({@link tieAbortSignal}), and a periodic
|
|
4
|
-
* {@link poll} generator. Dependency-free; `poll`'s `"distinct"` filter
|
|
5
|
-
* uses the local {@link deepEqual}.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
import { deepEqual } from "./object.js";
|
|
10
|
-
const DEFAULT_RETRY_DELAYS_MS = [1_000, 2_000, 5_000, 10_000, 30_000];
|
|
11
|
-
export function boundedRetryDelay(attempt, delaysMs = DEFAULT_RETRY_DELAYS_MS) {
|
|
12
|
-
if (!delaysMs.length)
|
|
13
|
-
return 0;
|
|
14
|
-
return delaysMs[Math.min(Math.max(0, attempt), delaysMs.length - 1)];
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Async iterable that drives a periodic poll. Each iteration:
|
|
18
|
-
*
|
|
19
|
-
* 1. Builds a {@link PollContext} (`attempt`, `previous`, `signal`,
|
|
20
|
-
* shared `attributes`) and calls `producer(ctx)`; yields the
|
|
21
|
-
* resolved value (subject to `filter`).
|
|
22
|
-
* 2. Evaluates `options.predicate(value, ctx)`; stops when it
|
|
23
|
-
* returns (or resolves to) `false`.
|
|
24
|
-
* 3. Sleeps `options.intervalMs` before the next attempt.
|
|
25
|
-
*
|
|
26
|
-
* The first call runs immediately (no leading sleep) so the consumer
|
|
27
|
-
* sees a value without waiting an interval. Errors thrown by
|
|
28
|
-
* `producer` propagate through the generator.
|
|
29
|
-
*
|
|
30
|
-
* `poll` always creates an internal `AbortController` and exposes
|
|
31
|
-
* `internal.signal` as `ctx.signal`, so producers can rely on a
|
|
32
|
-
* defined signal without a nullish check. The external
|
|
33
|
-
* `options.signal` is tied in, and a `try/finally` aborts the
|
|
34
|
-
* internal signal when the consumer breaks out of the `for await`
|
|
35
|
-
* (or the loop throws), so any producer work still holding the
|
|
36
|
-
* signal sees the cancellation too.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* for await (const msg of poll(
|
|
40
|
-
* async ({ signal }) =>
|
|
41
|
-
* client.genie.getMessage({ ... }, { abortSignal: signal }),
|
|
42
|
-
* {
|
|
43
|
-
* intervalMs: 250,
|
|
44
|
-
* predicate: (m) => !TERMINAL_STATUSES.has(m.status),
|
|
45
|
-
* signal: controller.signal,
|
|
46
|
-
* },
|
|
47
|
-
* )) {
|
|
48
|
-
* render(msg);
|
|
49
|
-
* }
|
|
50
|
-
*/
|
|
51
|
-
export async function* poll(producer, options) {
|
|
52
|
-
const { intervalMs, predicate, signal, attributes, timeoutMs } = options;
|
|
53
|
-
const controller = new AbortController();
|
|
54
|
-
if (signal)
|
|
55
|
-
tieAbortSignal(controller, signal);
|
|
56
|
-
if (timeoutMs !== undefined) {
|
|
57
|
-
tieAbortSignal(controller, AbortSignal.timeout(timeoutMs));
|
|
58
|
-
}
|
|
59
|
-
// Single shared attributes object so writes from one iteration are
|
|
60
|
-
// visible on the next. `{} as A` is safe because either the caller
|
|
61
|
-
// supplied `attributes` (typed) or `A` defaulted to the unknown
|
|
62
|
-
// record shape (in which case `{}` satisfies it).
|
|
63
|
-
const sharedAttributes = attributes ?? {};
|
|
64
|
-
try {
|
|
65
|
-
let previous;
|
|
66
|
-
for (let attempt = 0;; attempt++) {
|
|
67
|
-
controller.signal.throwIfAborted();
|
|
68
|
-
const ctx = {
|
|
69
|
-
attempt,
|
|
70
|
-
previous,
|
|
71
|
-
signal: controller.signal,
|
|
72
|
-
attributes: sharedAttributes,
|
|
73
|
-
};
|
|
74
|
-
const value = await producer(ctx);
|
|
75
|
-
if (options.filter) {
|
|
76
|
-
if (options.filter === "distinct") {
|
|
77
|
-
if (deepEqual(previous, value)) {
|
|
78
|
-
await sleep(intervalMs, controller.signal);
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
else if (!(await options.filter(value, ctx))) {
|
|
83
|
-
await sleep(intervalMs, controller.signal);
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
yield value;
|
|
88
|
-
if (predicate && !(await predicate(value, ctx)))
|
|
89
|
-
return;
|
|
90
|
-
await sleep(intervalMs, controller.signal);
|
|
91
|
-
previous = value;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
finally {
|
|
95
|
-
controller.abort();
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Tie a child `AbortController` to a parent signal. The child aborts
|
|
100
|
-
* whenever the parent aborts; aborting the child does not affect the
|
|
101
|
-
* parent (so a fetch-level cancel doesn't tear down the main poll loop).
|
|
102
|
-
*/
|
|
103
|
-
export function tieAbortSignal(child, parent) {
|
|
104
|
-
if (!parent) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
else if (parent.aborted) {
|
|
108
|
-
child.abort(parent.reason);
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
parent.addEventListener("abort", () => child.abort(parent.reason), {
|
|
112
|
-
once: true,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Combine several optional cancellation sources into one signal that aborts
|
|
117
|
-
* as soon as any of them does.
|
|
118
|
-
*
|
|
119
|
-
* The usual caller is an operation that has to honor more than one source at
|
|
120
|
-
* once - a caller's own signal (a closed connection, an agent run being
|
|
121
|
-
* cancelled) plus one derived from a timeout - where the awaited I/O accepts
|
|
122
|
-
* only a single signal. Absent sources are ignored, and a lone signal is
|
|
123
|
-
* returned as-is so the common path allocates nothing. Returns `undefined`
|
|
124
|
-
* only when every input is absent, which callers can pass straight through
|
|
125
|
-
* to an optional `signal` parameter.
|
|
126
|
-
*
|
|
127
|
-
* Aborting an input aborts the result (carrying that input's `reason`);
|
|
128
|
-
* nothing propagates back the other way.
|
|
129
|
-
*
|
|
130
|
-
* @example
|
|
131
|
-
* await fetch(url, { signal: combineAbortSignals(req.signal, timeout.signal) });
|
|
132
|
-
*/
|
|
133
|
-
export function combineAbortSignals(...signals) {
|
|
134
|
-
const present = signals.filter((signal) => signal !== undefined);
|
|
135
|
-
if (present.length <= 1)
|
|
136
|
-
return present[0];
|
|
137
|
-
return AbortSignal.any(present);
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Promisified `setTimeout` that wakes up early (and rejects with
|
|
141
|
-
* `signal.reason`) when `signal` aborts mid-wait. Short-circuits to a
|
|
142
|
-
* rejected promise when the signal is already aborted on entry, so the
|
|
143
|
-
* abort path is consistent regardless of whether the wait actually
|
|
144
|
-
* started.
|
|
145
|
-
*
|
|
146
|
-
* Use as the building block for any "wait, but cancel cleanly" pattern -
|
|
147
|
-
* inter-poll backoff, pacing loops, retry timers, long-poll budgets - so
|
|
148
|
-
* cancellation always rejects with the caller's `signal.reason` rather
|
|
149
|
-
* than silently resolving after the timer expires.
|
|
150
|
-
*
|
|
151
|
-
* @example
|
|
152
|
-
* await sleep(250, req.signal);
|
|
153
|
-
*/
|
|
154
|
-
export function sleep(ms, signal) {
|
|
155
|
-
if (signal?.aborted)
|
|
156
|
-
return Promise.reject(signal.reason);
|
|
157
|
-
return new Promise((resolve, reject) => {
|
|
158
|
-
const onAbort = () => {
|
|
159
|
-
clearTimeout(timer);
|
|
160
|
-
reject(signal.reason);
|
|
161
|
-
};
|
|
162
|
-
const timer = setTimeout(() => {
|
|
163
|
-
signal?.removeEventListener("abort", onAbort);
|
|
164
|
-
resolve();
|
|
165
|
-
}, ms);
|
|
166
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXN5bmMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXN5bmMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7R0FPRztBQUNILE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFeEMsTUFBTSx1QkFBdUIsR0FBRyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQVUsQ0FBQztBQUUvRSxNQUFNLFVBQVUsaUJBQWlCLENBQy9CLE9BQWUsRUFDZixXQUE4Qix1QkFBdUI7SUFFckQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNO1FBQUUsT0FBTyxDQUFDLENBQUM7SUFDL0IsT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsRUFBRSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFFLENBQUM7QUFDeEUsQ0FBQztBQXNGRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtDRztBQUNILE1BQU0sQ0FBQyxLQUFLLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FDekIsUUFBNEIsRUFDNUIsT0FBMEI7SUFFMUIsTUFBTSxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsR0FBRyxPQUFPLENBQUM7SUFDekUsTUFBTSxVQUFVLEdBQUcsSUFBSSxlQUFlLEVBQUUsQ0FBQztJQUN6QyxJQUFJLE1BQU07UUFBRSxjQUFjLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQy9DLElBQUksU0FBUyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQzVCLGNBQWMsQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFDRCxtRUFBbUU7SUFDbkUs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Q0FBQyxNQUFNLENBQUMsQ0FBQztJQUMxRCxPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQ3JDLE1BQU0sT0FBTyxHQUFHLEdBQVMsRUFBRTtZQUN6QixZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDcEIsTUFBTSxDQUFDLE1BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN6QixDQUFDLENBQUM7UUFDRixNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQzVCLE1BQU0sRUFBRSxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDOUMsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDUCxNQUFNLEVBQUUsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQzdELENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ2FuY2VsbGF0aW9uLWF3YXJlIGFzeW5jIHByaW1pdGl2ZXM6IGFuIGFib3J0YWJsZSB7QGxpbmsgc2xlZXB9LCBhblxuICoge0BsaW5rIEFib3J0Q29udHJvbGxlcn0gbGlua2VyICh7QGxpbmsgdGllQWJvcnRTaWduYWx9KSwgYW5kIGEgcGVyaW9kaWNcbiAqIHtAbGluayBwb2xsfSBnZW5lcmF0b3IuIERlcGVuZGVuY3ktZnJlZTsgYHBvbGxgJ3MgYFwiZGlzdGluY3RcImAgZmlsdGVyXG4gKiB1c2VzIHRoZSBsb2NhbCB7QGxpbmsgZGVlcEVxdWFsfS5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cbmltcG9ydCB7IGRlZXBFcXVhbCB9IGZyb20gXCIuL29iamVjdC50c1wiO1xuXG5jb25zdCBERUZBVUxUX1JFVFJZX0RFTEFZU19NUyA9IFsxXzAwMCwgMl8wMDAsIDVfMDAwLCAxMF8wMDAsIDMwXzAwMF0gYXMgY29uc3Q7XG5cbmV4cG9ydCBmdW5jdGlvbiBib3VuZGVkUmV0cnlEZWxheShcbiAgYXR0ZW1wdDogbnVtYmVyLFxuICBkZWxheXNNczogcmVhZG9ubHkgbnVtYmVyW10gPSBERUZBVUxUX1JFVFJZX0RFTEFZU19NUyxcbik6IG51bWJlciB7XG4gIGlmICghZGVsYXlzTXMubGVuZ3RoKSByZXR1cm4gMDtcbiAgcmV0dXJuIGRlbGF5c01zW01hdGgubWluKE1hdGgubWF4KDAsIGF0dGVtcHQpLCBkZWxheXNNcy5sZW5ndGggLSAxKV0hO1xufVxuXG4vKipcbiAqIFBlci1pdGVyYXRpb24gY29udGV4dCBoYW5kZWQgdG8ge0BsaW5rIFBvbGxQcm9kdWNlcn0gYW5kIHRoZVxuICogcHJlZGljYXRlIG9uIGVhY2ggc3RlcCBvZiBhIHtAbGluayBwb2xsfSBsb29wLiBCdW5kbGVzIHRoZVxuICogaXRlcmF0aW9uIG1ldGFkYXRhIHNvIHRoZSBjYWxsIHNpZ25hdHVyZXMgc3RheSBzdGFibGUgYXMgYHBvbGxgXG4gKiBncm93cyBhZGRpdGlvbmFsIGZpZWxkcy5cbiAqXG4gKiBgc2lnbmFsYCBpcyBvd25lZCBieSBgcG9sbGA6IGl0IHRyYWNrcyB0aGUgZXh0ZXJuYWxcbiAqIGBQb2xsT3B0aW9ucy5zaWduYWxgICh3aGVuIHN1cHBsaWVkKSBhbmQgYWxzbyBmaXJlcyB3aGVuIHRoZVxuICogY29uc3VtZXIgYnJlYWtzIG91dCBvZiB0aGUgbG9vcCwgc28gcHJvZHVjZXJzIGNhbiBmb3J3YXJkIGl0IHRvXG4gKiBhbnkgaW4tZmxpZ2h0IHdvcmsgKGBmZXRjaGAsIFNESyBjYWxscywgZXRjLikgYW5kIGhhdmUgYSBzaW5nbGVcbiAqIGNhbmNlbGxhdGlvbiBzb3VyY2UgdGVhciBkb3duIGJvdGggdGhlIHJlcXVlc3QgYW5kIHRoZSBsb29wLlxuICpcbiAqIGBhdHRyaWJ1dGVzYCBpcyBhIG11dGFibGUgc2NyYXRjaHBhZCBzaGFyZWQgYWNyb3NzIGV2ZXJ5XG4gKiBpdGVyYXRpb24gb2YgYSBzaW5nbGUgYHBvbGxgIHJ1bi4gVGhlIHNhbWUgb2JqZWN0IHJlZmVyZW5jZSBpc1xuICogcGFzc2VkIGVhY2ggY2FsbCBzbyB3cml0ZXMgZnJvbSBvbmUgaXRlcmF0aW9uIGFyZSB2aXNpYmxlIHRvIHRoZVxuICogbmV4dCAtIHVzZWZ1bCBmb3Igc3Rhc2hpbmcgcGVyLWxvb3Agc3RhdGUgKHJldHJ5IGNvdW50ZXJzLCBzdGFydFxuICogdGltZXN0YW1wcywgYW55dGhpbmcgeW91J2Qgb3RoZXJ3aXNlIGNsb3NlIG92ZXIgdmlhIGEgbGV0KS5cbiAqIEdlbmVyaWMgYEFgIGxldHMgY2FsbGVycyB0eXBlIHRoZSBiYWc7IGRlZmF1bHRzIHRvXG4gKiBgUmVjb3JkPHN0cmluZywgdW5rbm93bj5gLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBvbGxDb250ZXh0PFQsIEEgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4ge1xuICAvKiogWmVyby1iYXNlZCBpdGVyYXRpb24gaW5kZXggKGAwYCBvbiB0aGUgZmlyc3QgY2FsbCkuICovXG4gIGF0dGVtcHQ6IG51bWJlcjtcbiAgLyoqIFZhbHVlIHlpZWxkZWQgb24gdGhlIHByaW9yIGl0ZXJhdGlvbjsgYHVuZGVmaW5lZGAgb24gdGhlIGZpcnN0LiAqL1xuICBwcmV2aW91czogVCB8IHVuZGVmaW5lZDtcbiAgLyoqIENhbmNlbGxhdGlvbiBoYW5kbGUuIEFsd2F5cyBkZWZpbmVkOyBmb3J3YXJkIHRvIGluLWZsaWdodCB3b3JrLiAqL1xuICBzaWduYWw6IEFib3J0U2lnbmFsO1xuICAvKiogUGVyLXJ1biBtdXRhYmxlIHNjcmF0Y2hwYWQgc2hhcmVkIGFjcm9zcyBpdGVyYXRpb25zLiAqL1xuICBhdHRyaWJ1dGVzOiBBO1xufVxuXG4vKiogT25lIHN0ZXAgb2YgYSB7QGxpbmsgcG9sbH0gbG9vcC4gU2VlIHtAbGluayBQb2xsQ29udGV4dH0uICovXG5leHBvcnQgdHlwZSBQb2xsUHJvZHVjZXI8VCwgQSA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+PiA9IChcbiAgY3R4OiBQb2xsQ29udGV4dDxULCBBPixcbikgPT4gVCB8IFByb21pc2VMaWtlPFQ+O1xuXG4vKipcbiAqIENvbnRyb2xzIHBvbGwgY2FkZW5jZSwgZmlsdGVyaW5nLCB0ZXJtaW5hdGlvbiwgY2FuY2VsbGF0aW9uLCB0aW1lb3V0LCBhbmRcbiAqIHRoZSBtdXRhYmxlIHBlci1ydW4gYXR0cmlidXRlcyBleHBvc2VkIHRocm91Z2gge0BsaW5rIFBvbGxDb250ZXh0fS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBQb2xsT3B0aW9uczxULCBBID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4+IHtcbiAgLyoqIE1pbGxpc2Vjb25kcyB0byB3YWl0IGJldHdlZW4gcG9sbHMuICovXG4gIGludGVydmFsTXM6IG51bWJlcjtcbiAgLyoqXG4gICAqIFByZWRpY2F0ZSBldmFsdWF0ZWQgYWdhaW5zdCBlYWNoIHlpZWxkZWQgdmFsdWU6IHJldHVybiBgdHJ1ZWAgdG9cbiAgICoga2VlcCBpdCwgYGZhbHNlYCB0byBza2lwIGl0ICh3aXRob3V0IHN0b3BwaW5nIHRoZSBsb29wKS4gTWF5IGJlXG4gICAqIHN5bmMgb3IgYXN5bmMgLSBhIGBQcm9taXNlTGlrZTxib29sZWFuPmAgaXMgYXdhaXRlZCBiZWZvcmUgdGhlXG4gICAqIGRlY2lzaW9uIGlzIG1hZGUuIFJlY2VpdmVzIHRoZSBzYW1lIHtAbGluayBQb2xsQ29udGV4dH0gYXMgdGhlXG4gICAqIHByb2R1Y2VyIChzYW1lIGBzaWduYWxgLCBzYW1lIGBhdHRyaWJ1dGVzYCBiYWcpLiBUaGUgc3BlY2lhbFxuICAgKiB2YWx1ZSBgXCJkaXN0aW5jdFwiYCBza2lwcyBhIHZhbHVlIHRoYXQgZGVlcC1lcXVhbHMgdGhlIHByZXZpb3VzXG4gICAqIG9uZS5cbiAgICovXG4gIGZpbHRlcj86ICgodmFsdWU6IFQsIGN0eDogUG9sbENvbnRleHQ8VCwgQT4pID0+IGJvb2xlYW4gfCBQcm9taXNlTGlrZTxib29sZWFuPikgfCBcImRpc3RpbmN0XCI7XG4gIC8qKlxuICAgKiBQcmVkaWNhdGUgZXZhbHVhdGVkIGFnYWluc3QgZWFjaCB5aWVsZGVkIHZhbHVlOiByZXR1cm4gYHRydWVgIHRvXG4gICAqIGtlZXAgcG9sbGluZywgYGZhbHNlYCB0byBzdG9wLiBNYXkgYmUgc3luYyBvciBhc3luYy4gT21pdCB0byBwb2xsXG4gICAqIGZvcmV2ZXIgKHRoZSBjb25zdW1lciBzdG9wcyBieSBicmVha2luZyBvdXQgb2YgdGhlIGxvb3Agb3IgYnlcbiAgICogYWJvcnRpbmcgYHNpZ25hbGApLlxuICAgKi9cbiAgcHJlZGljYXRlPzogKHZhbHVlOiBULCBjdHg6IFBvbGxDb250ZXh0PFQsIEE+KSA9PiBib29sZWFuIHwgUHJvbWlzZUxpa2U8Ym9vbGVhbj47XG4gIC8qKlxuICAgKiBFeHRlcm5hbCBjYW5jZWxsYXRpb24gaGFuZGxlLiBUaWVkIGludG8gdGhlIGludGVybmFsIHNpZ25hbCB0aGF0XG4gICAqIGBwb2xsYCBoYW5kcyB0byBgcHJvZHVjZXJgLCBzbyBhYm9ydGluZyBpdCB0ZWFycyBkb3duIGJvdGggdGhlXG4gICAqIGluLWZsaWdodCByZXF1ZXN0IGFuZCB0aGUgaW50ZXItcG9sbCBzbGVlcC5cbiAgICovXG4gIHNpZ25hbD86IEFib3J0U2lnbmFsO1xuICAvKipcbiAgICogSGFyZCB1cHBlciBib3VuZCBvbiB0aGUgdG90YWwgbGlmZXRpbWUgb2YgdGhlIHBvbGwgbG9vcCwgaW5cbiAgICogbWlsbGlzZWNvbmRzLiBXaGVuIHRoZSBidWRnZXQgZWxhcHNlcywgYHBvbGxgIGFib3J0cyBpdHMgaW50ZXJuYWxcbiAgICogc2lnbmFsIHNvIHRoZSBpbi1mbGlnaHQgcHJvZHVjZXIgYW5kIGludGVyLXBvbGwgc2xlZXAgYm90aCB0ZWFyXG4gICAqIGRvd24gcHJvbXB0bHksIGFuZCB0aGUgbG9vcCB0aHJvd3MgdGhlIGBUaW1lb3V0RXJyb3JgXG4gICAqIGBET01FeGNlcHRpb25gIHByb2R1Y2VkIGJ5IGBBYm9ydFNpZ25hbC50aW1lb3V0KHRpbWVvdXRNcylgLiBUaGVcbiAgICogYnVkZ2V0IHN0YXJ0cyB0aWNraW5nIHRoZSBtb21lbnQgdGhlIGdlbmVyYXRvciBpcyBjcmVhdGVkLlxuICAgKi9cbiAgdGltZW91dE1zPzogbnVtYmVyO1xuICAvKipcbiAgICogSW5pdGlhbCB2YWx1ZSBmb3IgYGN0eC5hdHRyaWJ1dGVzYC4gRGVmYXVsdHMgdG8gYHt9YC4gVGhlIHNhbWVcbiAgICogb2JqZWN0IGlzIHJldXNlZCBhY3Jvc3MgaXRlcmF0aW9ucywgc28gY2FsbGVycyBjYW4gcHJlLXBvcHVsYXRlXG4gICAqIGZpZWxkcyAodGltZXJzLCByZXRyeSBjb3VudGVycywgZXRjLikgYW5kIHRoZSBwcm9kdWNlciAvXG4gICAqIHByZWRpY2F0ZSBjYW4gbXV0YXRlIHRoZW0gaW4gcGxhY2UuXG4gICAqL1xuICBhdHRyaWJ1dGVzPzogQTtcbn1cblxuLyoqXG4gKiBBc3luYyBpdGVyYWJsZSB0aGF0IGRyaXZlcyBhIHBlcmlvZGljIHBvbGwuIEVhY2ggaXRlcmF0aW9uOlxuICpcbiAqICAgMS4gQnVpbGRzIGEge0BsaW5rIFBvbGxDb250ZXh0fSAoYGF0dGVtcHRgLCBgcHJldmlvdXNgLCBgc2lnbmFsYCxcbiAqICAgICAgc2hhcmVkIGBhdHRyaWJ1dGVzYCkgYW5kIGNhbGxzIGBwcm9kdWNlcihjdHgpYDsgeWllbGRzIHRoZVxuICogICAgICByZXNvbHZlZCB2YWx1ZSAoc3ViamVjdCB0byBgZmlsdGVyYCkuXG4gKiAgIDIuIEV2YWx1YXRlcyBgb3B0aW9ucy5wcmVkaWNhdGUodmFsdWUsIGN0eClgOyBzdG9wcyB3aGVuIGl0XG4gKiAgICAgIHJldHVybnMgKG9yIHJlc29sdmVzIHRvKSBgZmFsc2VgLlxuICogICAzLiBTbGVlcHMgYG9wdGlvbnMuaW50ZXJ2YWxNc2AgYmVmb3JlIHRoZSBuZXh0IGF0dGVtcHQuXG4gKlxuICogVGhlIGZpcnN0IGNhbGwgcnVucyBpbW1lZGlhdGVseSAobm8gbGVhZGluZyBzbGVlcCkgc28gdGhlIGNvbnN1bWVyXG4gKiBzZWVzIGEgdmFsdWUgd2l0aG91dCB3YWl0aW5nIGFuIGludGVydmFsLiBFcnJvcnMgdGhyb3duIGJ5XG4gKiBgcHJvZHVjZXJgIHByb3BhZ2F0ZSB0aHJvdWdoIHRoZSBnZW5lcmF0b3IuXG4gKlxuICogYHBvbGxgIGFsd2F5cyBjcmVhdGVzIGFuIGludGVybmFsIGBBYm9ydENvbnRyb2xsZXJgIGFuZCBleHBvc2VzXG4gKiBgaW50ZXJuYWwuc2lnbmFsYCBhcyBgY3R4LnNpZ25hbGAsIHNvIHByb2R1Y2VycyBjYW4gcmVseSBvbiBhXG4gKiBkZWZpbmVkIHNpZ25hbCB3aXRob3V0IGEgbnVsbGlzaCBjaGVjay4gVGhlIGV4dGVybmFsXG4gKiBgb3B0aW9ucy5zaWduYWxgIGlzIHRpZWQgaW4sIGFuZCBhIGB0cnkvZmluYWxseWAgYWJvcnRzIHRoZVxuICogaW50ZXJuYWwgc2lnbmFsIHdoZW4gdGhlIGNvbnN1bWVyIGJyZWFrcyBvdXQgb2YgdGhlIGBmb3IgYXdhaXRgXG4gKiAob3IgdGhlIGxvb3AgdGhyb3dzKSwgc28gYW55IHByb2R1Y2VyIHdvcmsgc3RpbGwgaG9sZGluZyB0aGVcbiAqIHNpZ25hbCBzZWVzIHRoZSBjYW5jZWxsYXRpb24gdG9vLlxuICpcbiAqIEBleGFtcGxlXG4gKiBmb3IgYXdhaXQgKGNvbnN0IG1zZyBvZiBwb2xsKFxuICogICBhc3luYyAoeyBzaWduYWwgfSkgPT5cbiAqICAgICBjbGllbnQuZ2VuaWUuZ2V0TWVzc2FnZSh7IC4uLiB9LCB7IGFib3J0U2lnbmFsOiBzaWduYWwgfSksXG4gKiAgIHtcbiAqICAgICBpbnRlcnZhbE1zOiAyNTAsXG4gKiAgICAgcHJlZGljYXRlOiAobSkgPT4gIVRFUk1JTkFMX1NUQVRVU0VTLmhhcyhtLnN0YXR1cyksXG4gKiAgICAgc2lnbmFsOiBjb250cm9sbGVyLnNpZ25hbCxcbiAqICAgfSxcbiAqICkpIHtcbiAqICAgcmVuZGVyKG1zZyk7XG4gKiB9XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiogcG9sbDxULCBBID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4+KFxuICBwcm9kdWNlcjogUG9sbFByb2R1Y2VyPFQsIEE+LFxuICBvcHRpb25zOiBQb2xsT3B0aW9uczxULCBBPixcbik6IEFzeW5jR2VuZXJhdG9yPFQsIHZvaWQsIHZvaWQ+IHtcbiAgY29uc3QgeyBpbnRlcnZhbE1zLCBwcmVkaWNhdGUsIHNpZ25hbCwgYXR0cmlidXRlcywgdGltZW91dE1zIH0gPSBvcHRpb25zO1xuICBjb25zdCBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICBpZiAoc2lnbmFsKSB0aWVBYm9ydFNpZ25hbChjb250cm9sbGVyLCBzaWduYWwpO1xuICBpZiAodGltZW91dE1zICE9PSB1bmRlZmluZWQpIHtcbiAgICB0aWVBYm9ydFNpZ25hbChjb250cm9sbGVyLCBBYm9ydFNpZ25hbC50aW1lb3V0KHRpbWVvdXRNcykpO1xuICB9XG4gIC8vIFNpbmdsZSBzaGFyZWQgYXR0cmlidXRlcyBvYmplY3Qgc28gd3JpdGVzIGZyb20gb25lIGl0ZXJhdGlvbiBhcmVcbiAgLy8gdmlzaWJsZSBvbiB0aGUgbmV4dC4gYHt9IGFzIEFgIGlzIHNhZmUgYmVjYXVzZSBlaXRoZXIgdGhlIGNhbGxlclxuICAvLyBzdXBwbGllZCBgYXR0cmlidXRlc2AgKHR5cGVkKSBvciBgQWAgZGVmYXVsdGVkIHRvIHRoZSB1bmtub3duXG4gIC8vIHJlY29yZCBzaGFwZSAoaW4gd2hpY2ggY2FzZSBge31gIHNhdGlzZmllcyBpdCkuXG4gIGNvbnN0IHNoYXJlZEF0dHJpYnV0ZXMgPSBhdHRyaWJ1dGVzID8/ICh7fSBhcyBBKTtcbiAgdHJ5IHtcbiAgICBsZXQgcHJldmlvdXM6IFQgfCB1bmRlZmluZWQ7XG4gICAgZm9yIChsZXQgYXR0ZW1wdCA9IDA7IDsgYXR0ZW1wdCsrKSB7XG4gICAgICBjb250cm9sbGVyLnNpZ25hbC50aHJvd0lmQWJvcnRlZCgpO1xuICAgICAgY29uc3QgY3R4OiBQb2xsQ29udGV4dDxULCBBPiA9IHtcbiAgICAgICAgYXR0ZW1wdCxcbiAgICAgICAgcHJldmlvdXMsXG4gICAgICAgIHNpZ25hbDogY29udHJvbGxlci5zaWduYWwsXG4gICAgICAgIGF0dHJpYnV0ZXM6IHNoYXJlZEF0dHJpYnV0ZXMsXG4gICAgICB9O1xuICAgICAgY29uc3QgdmFsdWUgPSBhd2FpdCBwcm9kdWNlcihjdHgpO1xuICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlciA9PT0gXCJkaXN0aW5jdFwiKSB7XG4gICAgICAgICAgaWYgKGRlZXBFcXVhbChwcmV2aW91cywgdmFsdWUpKSB7XG4gICAgICAgICAgICBhd2FpdCBzbGVlcChpbnRlcnZhbE1zLCBjb250cm9sbGVyLnNpZ25hbCk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoIShhd2FpdCBvcHRpb25zLmZpbHRlcih2YWx1ZSwgY3R4KSkpIHtcbiAgICAgICAgICBhd2FpdCBzbGVlcChpbnRlcnZhbE1zLCBjb250cm9sbGVyLnNpZ25hbCk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHlpZWxkIHZhbHVlO1xuICAgICAgaWYgKHByZWRpY2F0ZSAmJiAhKGF3YWl0IHByZWRpY2F0ZSh2YWx1ZSwgY3R4KSkpIHJldHVybjtcbiAgICAgIGF3YWl0IHNsZWVwKGludGVydmFsTXMsIGNvbnRyb2xsZXIuc2lnbmFsKTtcbiAgICAgIHByZXZpb3VzID0gdmFsdWU7XG4gICAgfVxuICB9IGZpbmFsbHkge1xuICAgIGNvbnRyb2xsZXIuYWJvcnQoKTtcbiAgfVxufVxuXG4vKipcbiAqIFRpZSBhIGNoaWxkIGBBYm9ydENvbnRyb2xsZXJgIHRvIGEgcGFyZW50IHNpZ25hbC4gVGhlIGNoaWxkIGFib3J0c1xuICogd2hlbmV2ZXIgdGhlIHBhcmVudCBhYm9ydHM7IGFib3J0aW5nIHRoZSBjaGlsZCBkb2VzIG5vdCBhZmZlY3QgdGhlXG4gKiBwYXJlbnQgKHNvIGEgZmV0Y2gtbGV2ZWwgY2FuY2VsIGRvZXNuJ3QgdGVhciBkb3duIHRoZSBtYWluIHBvbGwgbG9vcCkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0aWVBYm9ydFNpZ25hbChjaGlsZDogQWJvcnRDb250cm9sbGVyLCBwYXJlbnQ/OiBBYm9ydFNpZ25hbCk6IHZvaWQge1xuICBpZiAoIXBhcmVudCkge1xuICAgIHJldHVybjtcbiAgfSBlbHNlIGlmIChwYXJlbnQuYWJvcnRlZCkge1xuICAgIGNoaWxkLmFib3J0KHBhcmVudC5yZWFzb24pO1xuICAgIHJldHVybjtcbiAgfVxuICBwYXJlbnQuYWRkRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsICgpID0+IGNoaWxkLmFib3J0KHBhcmVudC5yZWFzb24pLCB7XG4gICAgb25jZTogdHJ1ZSxcbiAgfSk7XG59XG5cbi8qKlxuICogQ29tYmluZSBzZXZlcmFsIG9wdGlvbmFsIGNhbmNlbGxhdGlvbiBzb3VyY2VzIGludG8gb25lIHNpZ25hbCB0aGF0IGFib3J0c1xuICogYXMgc29vbiBhcyBhbnkgb2YgdGhlbSBkb2VzLlxuICpcbiAqIFRoZSB1c3VhbCBjYWxsZXIgaXMgYW4gb3BlcmF0aW9uIHRoYXQgaGFzIHRvIGhvbm9yIG1vcmUgdGhhbiBvbmUgc291cmNlIGF0XG4gKiBvbmNlIC0gYSBjYWxsZXIncyBvd24gc2lnbmFsIChhIGNsb3NlZCBjb25uZWN0aW9uLCBhbiBhZ2VudCBydW4gYmVpbmdcbiAqIGNhbmNlbGxlZCkgcGx1cyBvbmUgZGVyaXZlZCBmcm9tIGEgdGltZW91dCAtIHdoZXJlIHRoZSBhd2FpdGVkIEkvTyBhY2NlcHRzXG4gKiBvbmx5IGEgc2luZ2xlIHNpZ25hbC4gQWJzZW50IHNvdXJjZXMgYXJlIGlnbm9yZWQsIGFuZCBhIGxvbmUgc2lnbmFsIGlzXG4gKiByZXR1cm5lZCBhcy1pcyBzbyB0aGUgY29tbW9uIHBhdGggYWxsb2NhdGVzIG5vdGhpbmcuIFJldHVybnMgYHVuZGVmaW5lZGBcbiAqIG9ubHkgd2hlbiBldmVyeSBpbnB1dCBpcyBhYnNlbnQsIHdoaWNoIGNhbGxlcnMgY2FuIHBhc3Mgc3RyYWlnaHQgdGhyb3VnaFxuICogdG8gYW4gb3B0aW9uYWwgYHNpZ25hbGAgcGFyYW1ldGVyLlxuICpcbiAqIEFib3J0aW5nIGFuIGlucHV0IGFib3J0cyB0aGUgcmVzdWx0IChjYXJyeWluZyB0aGF0IGlucHV0J3MgYHJlYXNvbmApO1xuICogbm90aGluZyBwcm9wYWdhdGVzIGJhY2sgdGhlIG90aGVyIHdheS5cbiAqXG4gKiBAZXhhbXBsZVxuICogYXdhaXQgZmV0Y2godXJsLCB7IHNpZ25hbDogY29tYmluZUFib3J0U2lnbmFscyhyZXEuc2lnbmFsLCB0aW1lb3V0LnNpZ25hbCkgfSk7XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21iaW5lQWJvcnRTaWduYWxzKFxuICAuLi5zaWduYWxzOiAoQWJvcnRTaWduYWwgfCB1bmRlZmluZWQpW11cbik6IEFib3J0U2lnbmFsIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcHJlc2VudCA9IHNpZ25hbHMuZmlsdGVyKChzaWduYWwpOiBzaWduYWwgaXMgQWJvcnRTaWduYWwgPT4gc2lnbmFsICE9PSB1bmRlZmluZWQpO1xuICBpZiAocHJlc2VudC5sZW5ndGggPD0gMSkgcmV0dXJuIHByZXNlbnRbMF07XG4gIHJldHVybiBBYm9ydFNpZ25hbC5hbnkocHJlc2VudCk7XG59XG5cbi8qKlxuICogUHJvbWlzaWZpZWQgYHNldFRpbWVvdXRgIHRoYXQgd2FrZXMgdXAgZWFybHkgKGFuZCByZWplY3RzIHdpdGhcbiAqIGBzaWduYWwucmVhc29uYCkgd2hlbiBgc2lnbmFsYCBhYm9ydHMgbWlkLXdhaXQuIFNob3J0LWNpcmN1aXRzIHRvIGFcbiAqIHJlamVjdGVkIHByb21pc2Ugd2hlbiB0aGUgc2lnbmFsIGlzIGFscmVhZHkgYWJvcnRlZCBvbiBlbnRyeSwgc28gdGhlXG4gKiBhYm9ydCBwYXRoIGlzIGNvbnNpc3RlbnQgcmVnYXJkbGVzcyBvZiB3aGV0aGVyIHRoZSB3YWl0IGFjdHVhbGx5XG4gKiBzdGFydGVkLlxuICpcbiAqIFVzZSBhcyB0aGUgYnVpbGRpbmcgYmxvY2sgZm9yIGFueSBcIndhaXQsIGJ1dCBjYW5jZWwgY2xlYW5seVwiIHBhdHRlcm4gLVxuICogaW50ZXItcG9sbCBiYWNrb2ZmLCBwYWNpbmcgbG9vcHMsIHJldHJ5IHRpbWVycywgbG9uZy1wb2xsIGJ1ZGdldHMgLSBzb1xuICogY2FuY2VsbGF0aW9uIGFsd2F5cyByZWplY3RzIHdpdGggdGhlIGNhbGxlcidzIGBzaWduYWwucmVhc29uYCByYXRoZXJcbiAqIHRoYW4gc2lsZW50bHkgcmVzb2x2aW5nIGFmdGVyIHRoZSB0aW1lciBleHBpcmVzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBhd2FpdCBzbGVlcCgyNTAsIHJlcS5zaWduYWwpO1xuICovXG5leHBvcnQgZnVuY3Rpb24gc2xlZXAobXM6IG51bWJlciwgc2lnbmFsPzogQWJvcnRTaWduYWwpOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKHNpZ25hbD8uYWJvcnRlZCkgcmV0dXJuIFByb21pc2UucmVqZWN0KHNpZ25hbC5yZWFzb24pO1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IG9uQWJvcnQgPSAoKTogdm9pZCA9PiB7XG4gICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgcmVqZWN0KHNpZ25hbCEucmVhc29uKTtcbiAgICB9O1xuICAgIGNvbnN0IHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICBzaWduYWw/LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBvbkFib3J0KTtcbiAgICAgIHJlc29sdmUoKTtcbiAgICB9LCBtcyk7XG4gICAgc2lnbmFsPy5hZGRFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgb25BYm9ydCwgeyBvbmNlOiB0cnVlIH0pO1xuICB9KTtcbn1cbiJdfQ==
|
package/lib/src/brand.js
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Browser-safe brand contract, defaults, and LLM serialization helpers.
|
|
3
|
-
*
|
|
4
|
-
* Asset values are intentionally strings: they may be relative file paths,
|
|
5
|
-
* package exports, data URLs, or network URLs depending on the consumer.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
import { z } from "zod";
|
|
10
|
-
const nonBlankString = z.string().trim().min(1);
|
|
11
|
-
const color = z.string().regex(/^#(?:[\da-f]{3}|[\da-f]{6}|[\da-f]{8})$/i, "Expected a hex color.");
|
|
12
|
-
/** Package asset references used when a brand context supplies no custom artwork. */
|
|
13
|
-
export const DEFAULT_BRAND_ASSETS = {
|
|
14
|
-
icon: {
|
|
15
|
-
light: "@dbx-tools/ui-branding/assets/icon-light.svg",
|
|
16
|
-
dark: "@dbx-tools/ui-branding/assets/icon-dark.svg",
|
|
17
|
-
},
|
|
18
|
-
logo: {
|
|
19
|
-
light: "@dbx-tools/ui-branding/assets/logo-light.svg",
|
|
20
|
-
dark: "@dbx-tools/ui-branding/assets/logo-dark.svg",
|
|
21
|
-
},
|
|
22
|
-
favicon: "@dbx-tools/ui-branding/assets/icon-light.svg",
|
|
23
|
-
};
|
|
24
|
-
/** Validates light and optional dark variants for one visual asset. */
|
|
25
|
-
export const BrandAssetSetSchema = z
|
|
26
|
-
.object({
|
|
27
|
-
light: nonBlankString.describe("Asset for light surfaces."),
|
|
28
|
-
dark: nonBlankString.optional().describe("Asset for dark surfaces; light is the fallback."),
|
|
29
|
-
})
|
|
30
|
-
.strict()
|
|
31
|
-
.describe("Theme-aware references to one visual asset.");
|
|
32
|
-
/** Strict brand palette whose omitted colors resolve to the dbx tools defaults. */
|
|
33
|
-
export const BrandColorsSchema = z
|
|
34
|
-
.object({
|
|
35
|
-
primary: color.default("#1B3139").describe("Primary action and identity color."),
|
|
36
|
-
primaryHover: color.default("#0E538B").describe("Primary hover or pressed color."),
|
|
37
|
-
accent: color.default("#00A972").describe("Secondary accent color."),
|
|
38
|
-
foreground: color.default("#1B3139").describe("Default text and mark color."),
|
|
39
|
-
background: color.default("#FFFFFF").describe("Default page background."),
|
|
40
|
-
surface: color.default("#F9F7F4").describe("Secondary surface background."),
|
|
41
|
-
muted: color.default("#618794").describe("Muted text color."),
|
|
42
|
-
border: color.default("#E4E2DD").describe("Default border color."),
|
|
43
|
-
})
|
|
44
|
-
.strict()
|
|
45
|
-
.prefault({});
|
|
46
|
-
/** Strict audience, tone, principle, and avoidance lists with practical defaults. */
|
|
47
|
-
export const BrandVoiceSchema = z
|
|
48
|
-
.object({
|
|
49
|
-
audience: z
|
|
50
|
-
.array(nonBlankString)
|
|
51
|
-
.default(["Databricks developers", "application engineers", "AI agents"]),
|
|
52
|
-
tone: z.array(nonBlankString).default(["direct", "practical", "technical", "approachable"]),
|
|
53
|
-
principles: z
|
|
54
|
-
.array(nonBlankString)
|
|
55
|
-
.default([
|
|
56
|
-
"Lead with the useful outcome.",
|
|
57
|
-
"Prefer concrete examples and accurate technical language.",
|
|
58
|
-
"Keep product claims specific and defensible.",
|
|
59
|
-
]),
|
|
60
|
-
avoid: z
|
|
61
|
-
.array(nonBlankString)
|
|
62
|
-
.default(["unsupported superlatives", "vague AI claims", "unnecessary jargon"]),
|
|
63
|
-
})
|
|
64
|
-
.strict()
|
|
65
|
-
.prefault({});
|
|
66
|
-
/**
|
|
67
|
-
* Strict portable brand contract that fills identity, assets, colors,
|
|
68
|
-
* typography, voice, links, and extension defaults during parsing.
|
|
69
|
-
*/
|
|
70
|
-
export const BrandContextSchema = z
|
|
71
|
-
.object({
|
|
72
|
-
schemaVersion: z.literal("1").default("1"),
|
|
73
|
-
name: nonBlankString.default("dbx tools").describe("Canonical display name."),
|
|
74
|
-
shortName: nonBlankString.default("dbx").describe("Compact name for constrained UI."),
|
|
75
|
-
tagline: nonBlankString
|
|
76
|
-
.default("Practical tools for Databricks builders.")
|
|
77
|
-
.describe("Short product line suitable for a header or metadata."),
|
|
78
|
-
description: nonBlankString
|
|
79
|
-
.default("Companion packages for Databricks developers building apps, agents, data workflows, and reusable UI.")
|
|
80
|
-
.describe("Plain-language product description."),
|
|
81
|
-
assets: z
|
|
82
|
-
.object({
|
|
83
|
-
icon: BrandAssetSetSchema.default(DEFAULT_BRAND_ASSETS.icon),
|
|
84
|
-
logo: BrandAssetSetSchema.default(DEFAULT_BRAND_ASSETS.logo),
|
|
85
|
-
favicon: nonBlankString.default(DEFAULT_BRAND_ASSETS.favicon),
|
|
86
|
-
})
|
|
87
|
-
.strict()
|
|
88
|
-
.default(DEFAULT_BRAND_ASSETS),
|
|
89
|
-
colors: BrandColorsSchema,
|
|
90
|
-
typography: z
|
|
91
|
-
.object({
|
|
92
|
-
sans: nonBlankString.default("'DM Sans', ui-sans-serif, system-ui, sans-serif"),
|
|
93
|
-
mono: nonBlankString.default("'DM Mono', ui-monospace, SFMono-Regular, Menlo, monospace"),
|
|
94
|
-
})
|
|
95
|
-
.strict()
|
|
96
|
-
.prefault({}),
|
|
97
|
-
voice: BrandVoiceSchema,
|
|
98
|
-
links: z
|
|
99
|
-
.object({
|
|
100
|
-
website: z.string().url().optional(),
|
|
101
|
-
repository: z.string().url().optional(),
|
|
102
|
-
documentation: z.string().url().optional(),
|
|
103
|
-
})
|
|
104
|
-
.strict()
|
|
105
|
-
.default({}),
|
|
106
|
-
extensions: z
|
|
107
|
-
.record(nonBlankString, z.unknown())
|
|
108
|
-
.default({})
|
|
109
|
-
.describe("Namespaced consumer-specific values that do not belong in the portable core."),
|
|
110
|
-
})
|
|
111
|
-
.strict()
|
|
112
|
-
.describe("Portable identity, visual, and voice context for UI, libraries, and LLMs.");
|
|
113
|
-
/** Validate input and fill every dbx tools default. */
|
|
114
|
-
export function parseBrandContext(input = {}) {
|
|
115
|
-
return BrandContextSchema.parse(input);
|
|
116
|
-
}
|
|
117
|
-
/** Canonical dbx tools brand context with all schema defaults resolved. */
|
|
118
|
-
export const defaultBrandContext = parseBrandContext();
|
|
119
|
-
/** JSON Schema representation suitable for structured-output and tool definitions. */
|
|
120
|
-
export function brandContextJsonSchema() {
|
|
121
|
-
return z.toJSONSchema(BrandContextSchema);
|
|
122
|
-
}
|
|
123
|
-
/** Stable prompt block for an LLM that needs to write or design in this brand. */
|
|
124
|
-
export function brandContextPrompt(context = defaultBrandContext) {
|
|
125
|
-
return [
|
|
126
|
-
`Use the following ${context.name} brand context for names, visual choices, and writing voice.`,
|
|
127
|
-
"Treat explicit task instructions as higher priority than this context.",
|
|
128
|
-
"",
|
|
129
|
-
JSON.stringify(context, null, 2),
|
|
130
|
-
].join("\n");
|
|
131
|
-
}
|
|
132
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnJhbmQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYnJhbmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7R0FPRztBQUNILE9BQU8sRUFBRSxDQUFDLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFFeEIsTUFBTSxjQUFjLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNoRCxNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLDBDQUEwQyxFQUFFLHVCQUF1QixDQUFDLENBQUM7QUFFcEcscUZBQXFGO0FBQ3JGLE1BQU0sQ0FBQyxNQUFNLG9CQUFvQixHQUFHO0lBQ2xDLElBQUksRUFBRTtRQUNKLEtBQUssRUFBRSw4Q0FBOEM7UUFDckQsSUFBSSxFQUFFLDZDQUE2QztLQUNwRDtJQUNELElBQUksRUFBRTtRQUNKLEtBQUssRUFBRSw4Q0FBOEM7UUFDckQsSUFBSSxFQUFFLDZDQUE2QztLQUNwRDtJQUNELE9BQU8sRUFBRSw4Q0FBOEM7Q0FDL0MsQ0FBQztBQUVYLHVFQUF1RTtBQUN2RSxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxDQUFDO0tBQ2pDLE1BQU0sQ0FBQztJQUNOLEtBQUssRUFBRSxjQUFjLENBQUMsUUFBUSxDQUFDLDJCQUEyQixDQUFDO0lBQzNELElBQUksRUFBRSxjQUFjLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLGlEQUFpRCxDQUFDO0NBQzVGLENBQUM7S0FDRCxNQUFNLEVBQUU7S0FDUixRQUFRLENBQUMsNkNBQTZDLENBQUMsQ0FBQztBQUUzRCxtRkFBbUY7QUFDbkYsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsQ0FBQztLQUMvQixNQUFNLENBQUM7SUFDTixPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxRQUFRLENB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RSxDQUFDO0FBRXJFLHNGQUFzRjtBQUN0RixNQUFNLFVBQVUsc0JBQXNCO0lBQ3BDLE9BQU8sQ0FBQyxDQUFDLFlBQVksQ0FBQyxrQkFBa0IsQ0FBNEIsQ0FBQztBQUN2RSxDQUFDO0FBRUQsa0ZBQWtGO0FBQ2xGLE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxVQUF3QixtQkFBbUI7SUFDNUUsT0FBTztRQUNMLHFCQUFxQixPQUFPLENBQUMsSUFBSSw4REFBOEQ7UUFDL0Ysd0VBQXdFO1FBQ3hFLEVBQUU7UUFDRixJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0tBQ2pDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ2YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQnJvd3Nlci1zYWZlIGJyYW5kIGNvbnRyYWN0LCBkZWZhdWx0cywgYW5kIExMTSBzZXJpYWxpemF0aW9uIGhlbHBlcnMuXG4gKlxuICogQXNzZXQgdmFsdWVzIGFyZSBpbnRlbnRpb25hbGx5IHN0cmluZ3M6IHRoZXkgbWF5IGJlIHJlbGF0aXZlIGZpbGUgcGF0aHMsXG4gKiBwYWNrYWdlIGV4cG9ydHMsIGRhdGEgVVJMcywgb3IgbmV0d29yayBVUkxzIGRlcGVuZGluZyBvbiB0aGUgY29uc3VtZXIuXG4gKlxuICogQG1vZHVsZVxuICovXG5pbXBvcnQgeyB6IH0gZnJvbSBcInpvZFwiO1xuXG5jb25zdCBub25CbGFua1N0cmluZyA9IHouc3RyaW5nKCkudHJpbSgpLm1pbigxKTtcbmNvbnN0IGNvbG9yID0gei5zdHJpbmcoKS5yZWdleCgvXiMoPzpbXFxkYS1mXXszfXxbXFxkYS1mXXs2fXxbXFxkYS1mXXs4fSkkL2ksIFwiRXhwZWN0ZWQgYSBoZXggY29sb3IuXCIpO1xuXG4vKiogUGFja2FnZSBhc3NldCByZWZlcmVuY2VzIHVzZWQgd2hlbiBhIGJyYW5kIGNvbnRleHQgc3VwcGxpZXMgbm8gY3VzdG9tIGFydHdvcmsuICovXG5leHBvcnQgY29uc3QgREVGQVVMVF9CUkFORF9BU1NFVFMgPSB7XG4gIGljb246IHtcbiAgICBsaWdodDogXCJAZGJ4LXRvb2xzL3VpLWJyYW5kaW5nL2Fzc2V0cy9pY29uLWxpZ2h0LnN2Z1wiLFxuICAgIGRhcms6IFwiQGRieC10b29scy91aS1icmFuZGluZy9hc3NldHMvaWNvbi1kYXJrLnN2Z1wiLFxuICB9LFxuICBsb2dvOiB7XG4gICAgbGlnaHQ6IFwiQGRieC10b29scy91aS1icmFuZGluZy9hc3NldHMvbG9nby1saWdodC5zdmdcIixcbiAgICBkYXJrOiBcIkBkYngtdG9vbHMvdWktYnJhbmRpbmcvYXNzZXRzL2xvZ28tZGFyay5zdmdcIixcbiAgfSxcbiAgZmF2aWNvbjogXCJAZGJ4LXRvb2xzL3VpLWJyYW5kaW5nL2Fzc2V0cy9pY29uLWxpZ2h0LnN2Z1wiLFxufSBhcyBjb25zdDtcblxuLyoqIFZhbGlkYXRlcyBsaWdodCBhbmQgb3B0aW9uYWwgZGFyayB2YXJpYW50cyBmb3Igb25lIHZpc3VhbCBhc3NldC4gKi9cbmV4cG9ydCBjb25zdCBCcmFuZEFzc2V0U2V0U2NoZW1hID0gelxuICAub2JqZWN0KHtcbiAgICBsaWdodDogbm9uQmxhbmtTdHJpbmcuZGVzY3JpYmUoXCJBc3NldCBmb3IgbGlnaHQgc3VyZmFjZXMuXCIpLFxuICAgIGRhcms6IG5vbkJsYW5rU3RyaW5nLm9wdGlvbmFsKCkuZGVzY3JpYmUoXCJBc3NldCBmb3IgZGFyayBzdXJmYWNlczsgbGlnaHQgaXMgdGhlIGZhbGxiYWNrLlwiKSxcbiAgfSlcbiAgLnN0cmljdCgpXG4gIC5kZXNjcmliZShcIlRoZW1lLWF3YXJlIHJlZmVyZW5jZXMgdG8gb25lIHZpc3VhbCBhc3NldC5cIik7XG5cbi8qKiBTdHJpY3QgYnJhbmQgcGFsZXR0ZSB3aG9zZSBvbWl0dGVkIGNvbG9ycyByZXNvbHZlIHRvIHRoZSBkYnggdG9vbHMgZGVmYXVsdHMuICovXG5leHBvcnQgY29uc3QgQnJhbmRDb2xvcnNTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIHByaW1hcnk6IGNvbG9yLmRlZmF1bHQoXCIjMUIzMTM5XCIpLmRlc2NyaWJlKFwiUHJpbWFyeSBhY3Rpb24gYW5kIGlkZW50aXR5IGNvbG9yLlwiKSxcbiAgICBwcmltYXJ5SG92ZXI6IGNvbG9yLmRlZmF1bHQoXCIjMEU1MzhCXCIpLmRlc2NyaWJlKFwiUHJpbWFyeSBob3ZlciBvciBwcmVzc2VkIGNvbG9yLlwiKSxcbiAgICBhY2NlbnQ6IGNvbG9yLmRlZmF1bHQoXCIjMDBBOTcyXCIpLmRlc2NyaWJlKFwiU2Vjb25kYXJ5IGFjY2VudCBjb2xvci5cIiksXG4gICAgZm9yZWdyb3VuZDogY29sb3IuZGVmYXVsdChcIiMxQjMxMzlcIikuZGVzY3JpYmUoXCJEZWZhdWx0IHRleHQgYW5kIG1hcmsgY29sb3IuXCIpLFxuICAgIGJhY2tncm91bmQ6IGNvbG9yLmRlZmF1bHQoXCIjRkZGRkZGXCIpLmRlc2NyaWJlKFwiRGVmYXVsdCBwYWdlIGJhY2tncm91bmQuXCIpLFxuICAgIHN1cmZhY2U6IGNvbG9yLmRlZmF1bHQoXCIjRjlGN0Y0XCIpLmRlc2NyaWJlKFwiU2Vjb25kYXJ5IHN1cmZhY2UgYmFja2dyb3VuZC5cIiksXG4gICAgbXV0ZWQ6IGNvbG9yLmRlZmF1bHQoXCIjNjE4Nzk0XCIpLmRlc2NyaWJlKFwiTXV0ZWQgdGV4dCBjb2xvci5cIiksXG4gICAgYm9yZGVyOiBjb2xvci5kZWZhdWx0KFwiI0U0RTJERFwiKS5kZXNjcmliZShcIkRlZmF1bHQgYm9yZGVyIGNvbG9yLlwiKSxcbiAgfSlcbiAgLnN0cmljdCgpXG4gIC5wcmVmYXVsdCh7fSk7XG5cbi8qKiBTdHJpY3QgYXVkaWVuY2UsIHRvbmUsIHByaW5jaXBsZSwgYW5kIGF2b2lkYW5jZSBsaXN0cyB3aXRoIHByYWN0aWNhbCBkZWZhdWx0cy4gKi9cbmV4cG9ydCBjb25zdCBCcmFuZFZvaWNlU2NoZW1hID0gelxuICAub2JqZWN0KHtcbiAgICBhdWRpZW5jZTogelxuICAgICAgLmFycmF5KG5vbkJsYW5rU3RyaW5nKVxuICAgICAgLmRlZmF1bHQoW1wiRGF0YWJyaWNrcyBkZXZlbG9wZXJzXCIsIFwiYXBwbGljYXRpb24gZW5naW5lZXJzXCIsIFwiQUkgYWdlbnRzXCJdKSxcbiAgICB0b25lOiB6LmFycmF5KG5vbkJsYW5rU3RyaW5nKS5kZWZhdWx0KFtcImRpcmVjdFwiLCBcInByYWN0aWNhbFwiLCBcInRlY2huaWNhbFwiLCBcImFwcHJvYWNoYWJsZVwiXSksXG4gICAgcHJpbmNpcGxlczogelxuICAgICAgLmFycmF5KG5vbkJsYW5rU3RyaW5nKVxuICAgICAgLmRlZmF1bHQoW1xuICAgICAgICBcIkxlYWQgd2l0aCB0aGUgdXNlZnVsIG91dGNvbWUuXCIsXG4gICAgICAgIFwiUHJlZmVyIGNvbmNyZXRlIGV4YW1wbGVzIGFuZCBhY2N1cmF0ZSB0ZWNobmljYWwgbGFuZ3VhZ2UuXCIsXG4gICAgICAgIFwiS2VlcCBwcm9kdWN0IGNsYWltcyBzcGVjaWZpYyBhbmQgZGVmZW5zaWJsZS5cIixcbiAgICAgIF0pLFxuICAgIGF2b2lkOiB6XG4gICAgICAuYXJyYXkobm9uQmxhbmtTdHJpbmcpXG4gICAgICAuZGVmYXVsdChbXCJ1bnN1cHBvcnRlZCBzdXBlcmxhdGl2ZXNcIiwgXCJ2YWd1ZSBBSSBjbGFpbXNcIiwgXCJ1bm5lY2Vzc2FyeSBqYXJnb25cIl0pLFxuICB9KVxuICAuc3RyaWN0KClcbiAgLnByZWZhdWx0KHt9KTtcblxuLyoqXG4gKiBTdHJpY3QgcG9ydGFibGUgYnJhbmQgY29udHJhY3QgdGhhdCBmaWxscyBpZGVudGl0eSwgYXNzZXRzLCBjb2xvcnMsXG4gKiB0eXBvZ3JhcGh5LCB2b2ljZSwgbGlua3MsIGFuZCBleHRlbnNpb24gZGVmYXVsdHMgZHVyaW5nIHBhcnNpbmcuXG4gKi9cbmV4cG9ydCBjb25zdCBCcmFuZENvbnRleHRTY2hlbWEgPSB6XG4gIC5vYmplY3Qoe1xuICAgIHNjaGVtYVZlcnNpb246IHoubGl0ZXJhbChcIjFcIikuZGVmYXVsdChcIjFcIiksXG4gICAgbmFtZTogbm9uQmxhbmtTdHJpbmcuZGVmYXVsdChcImRieCB0b29sc1wiKS5kZXNjcmliZShcIkNhbm9uaWNhbCBkaXNwbGF5IG5hbWUuXCIpLFxuICAgIHNob3J0TmFtZTogbm9uQmxhbmtTdHJpbmcuZGVmYXVsdChcImRieFwiKS5kZXNjcmliZShcIkNvbXBhY3QgbmFtZSBmb3IgY29uc3RyYWluZWQgVUkuXCIpLFxuICAgIHRhZ2xpbmU6IG5vbkJsYW5rU3RyaW5nXG4gICAgICAuZGVmYXVsdChcIlByYWN0aWNhbCB0b29scyBmb3IgRGF0YWJyaWNrcyBidWlsZGVycy5cIilcbiAgICAgIC5kZXNjcmliZShcIlNob3J0IHByb2R1Y3QgbGluZSBzdWl0YWJsZSBmb3IgYSBoZWFkZXIgb3IgbWV0YWRhdGEuXCIpLFxuICAgIGRlc2NyaXB0aW9uOiBub25CbGFua1N0cmluZ1xuICAgICAgLmRlZmF1bHQoXG4gICAgICAgIFwiQ29tcGFuaW9uIHBhY2thZ2VzIGZvciBEYXRhYnJpY2tzIGRldmVsb3BlcnMgYnVpbGRpbmcgYXBwcywgYWdlbnRzLCBkYXRhIHdvcmtmbG93cywgYW5kIHJldXNhYmxlIFVJLlwiLFxuICAgICAgKVxuICAgICAgLmRlc2NyaWJlKFwiUGxhaW4tbGFuZ3VhZ2UgcHJvZHVjdCBkZXNjcmlwdGlvbi5cIiksXG4gICAgYXNzZXRzOiB6XG4gICAgICAub2JqZWN0KHtcbiAgICAgICAgaWNvbjogQnJhbmRBc3NldFNldFNjaGVtYS5kZWZhdWx0KERFRkFVTFRfQlJBTkRfQVNTRVRTLmljb24pLFxuICAgICAgICBsb2dvOiBCcmFuZEFzc2V0U2V0U2NoZW1hLmRlZmF1bHQoREVGQVVMVF9CUkFORF9BU1NFVFMubG9nbyksXG4gICAgICAgIGZhdmljb246IG5vbkJsYW5rU3RyaW5nLmRlZmF1bHQoREVGQVVMVF9CUkFORF9BU1NFVFMuZmF2aWNvbiksXG4gICAgICB9KVxuICAgICAgLnN0cmljdCgpXG4gICAgICAuZGVmYXVsdChERUZBVUxUX0JSQU5EX0FTU0VUUyksXG4gICAgY29sb3JzOiBCcmFuZENvbG9yc1NjaGVtYSxcbiAgICB0eXBvZ3JhcGh5OiB6XG4gICAgICAub2JqZWN0KHtcbiAgICAgICAgc2Fuczogbm9uQmxhbmtTdHJpbmcuZGVmYXVsdChcIidETSBTYW5zJywgdWktc2Fucy1zZXJpZiwgc3lzdGVtLXVpLCBzYW5zLXNlcmlmXCIpLFxuICAgICAgICBtb25vOiBub25CbGFua1N0cmluZy5kZWZhdWx0KFwiJ0RNIE1vbm8nLCB1aS1tb25vc3BhY2UsIFNGTW9uby1SZWd1bGFyLCBNZW5sbywgbW9ub3NwYWNlXCIpLFxuICAgICAgfSlcbiAgICAgIC5zdHJpY3QoKVxuICAgICAgLnByZWZhdWx0KHt9KSxcbiAgICB2b2ljZTogQnJhbmRWb2ljZVNjaGVtYSxcbiAgICBsaW5rczogelxuICAgICAgLm9iamVjdCh7XG4gICAgICAgIHdlYnNpdGU6IHouc3RyaW5nKCkudXJsKCkub3B0aW9uYWwoKSxcbiAgICAgICAgcmVwb3NpdG9yeTogei5zdHJpbmcoKS51cmwoKS5vcHRpb25hbCgpLFxuICAgICAgICBkb2N1bWVudGF0aW9uOiB6LnN0cmluZygpLnVybCgpLm9wdGlvbmFsKCksXG4gICAgICB9KVxuICAgICAgLnN0cmljdCgpXG4gICAgICAuZGVmYXVsdCh7fSksXG4gICAgZXh0ZW5zaW9uczogelxuICAgICAgLnJlY29yZChub25CbGFua1N0cmluZywgei51bmtub3duKCkpXG4gICAgICAuZGVmYXVsdCh7fSlcbiAgICAgIC5kZXNjcmliZShcIk5hbWVzcGFjZWQgY29uc3VtZXItc3BlY2lmaWMgdmFsdWVzIHRoYXQgZG8gbm90IGJlbG9uZyBpbiB0aGUgcG9ydGFibGUgY29yZS5cIiksXG4gIH0pXG4gIC5zdHJpY3QoKVxuICAuZGVzY3JpYmUoXCJQb3J0YWJsZSBpZGVudGl0eSwgdmlzdWFsLCBhbmQgdm9pY2UgY29udGV4dCBmb3IgVUksIGxpYnJhcmllcywgYW5kIExMTXMuXCIpO1xuXG4vKiogRnVsbHkgdmFsaWRhdGVkIGJyYW5kIGNvbnRleHQgYWZ0ZXIgZXZlcnkgc2NoZW1hIGRlZmF1bHQgaGFzIGJlZW4gYXBwbGllZC4gKi9cbmV4cG9ydCB0eXBlIEJyYW5kQ29udGV4dCA9IHoub3V0cHV0PHR5cGVvZiBCcmFuZENvbnRleHRTY2hlbWE+O1xuLyoqIElucHV0IGFjY2VwdGVkIGJ5IHtAbGluayBCcmFuZENvbnRleHRTY2hlbWF9LCBiZWZvcmUgZGVmYXVsdHMgYXJlIG1hdGVyaWFsaXplZC4gKi9cbmV4cG9ydCB0eXBlIEJyYW5kQ29udGV4dElucHV0ID0gei5pbnB1dDx0eXBlb2YgQnJhbmRDb250ZXh0U2NoZW1hPjtcbi8qKiBUaGVtZS1hd2FyZSBsaWdodCBhbmQgb3B0aW9uYWwgZGFyayByZWZlcmVuY2VzIGZvciBvbmUgYnJhbmQgYXNzZXQuICovXG5leHBvcnQgdHlwZSBCcmFuZEFzc2V0U2V0ID0gei5vdXRwdXQ8dHlwZW9mIEJyYW5kQXNzZXRTZXRTY2hlbWE+O1xuXG4vKiogVmFsaWRhdGUgaW5wdXQgYW5kIGZpbGwgZXZlcnkgZGJ4IHRvb2xzIGRlZmF1bHQuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VCcmFuZENvbnRleHQoaW5wdXQ6IHVua25vd24gPSB7fSk6IEJyYW5kQ29udGV4dCB7XG4gIHJldHVybiBCcmFuZENvbnRleHRTY2hlbWEucGFyc2UoaW5wdXQpO1xufVxuXG4vKiogQ2Fub25pY2FsIGRieCB0b29scyBicmFuZCBjb250ZXh0IHdpdGggYWxsIHNjaGVtYSBkZWZhdWx0cyByZXNvbHZlZC4gKi9cbmV4cG9ydCBjb25zdCBkZWZhdWx0QnJhbmRDb250ZXh0OiBCcmFuZENvbnRleHQgPSBwYXJzZUJyYW5kQ29udGV4dCgpO1xuXG4vKiogSlNPTiBTY2hlbWEgcmVwcmVzZW50YXRpb24gc3VpdGFibGUgZm9yIHN0cnVjdHVyZWQtb3V0cHV0IGFuZCB0b29sIGRlZmluaXRpb25zLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJyYW5kQ29udGV4dEpzb25TY2hlbWEoKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4gei50b0pTT05TY2hlbWEoQnJhbmRDb250ZXh0U2NoZW1hKSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuLyoqIFN0YWJsZSBwcm9tcHQgYmxvY2sgZm9yIGFuIExMTSB0aGF0IG5lZWRzIHRvIHdyaXRlIG9yIGRlc2lnbiBpbiB0aGlzIGJyYW5kLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJyYW5kQ29udGV4dFByb21wdChjb250ZXh0OiBCcmFuZENvbnRleHQgPSBkZWZhdWx0QnJhbmRDb250ZXh0KTogc3RyaW5nIHtcbiAgcmV0dXJuIFtcbiAgICBgVXNlIHRoZSBmb2xsb3dpbmcgJHtjb250ZXh0Lm5hbWV9IGJyYW5kIGNvbnRleHQgZm9yIG5hbWVzLCB2aXN1YWwgY2hvaWNlcywgYW5kIHdyaXRpbmcgdm9pY2UuYCxcbiAgICBcIlRyZWF0IGV4cGxpY2l0IHRhc2sgaW5zdHJ1Y3Rpb25zIGFzIGhpZ2hlciBwcmlvcml0eSB0aGFuIHRoaXMgY29udGV4dC5cIixcbiAgICBcIlwiLFxuICAgIEpTT04uc3RyaW5naWZ5KGNvbnRleHQsIG51bGwsIDIpLFxuICBdLmpvaW4oXCJcXG5cIik7XG59XG4iXX0=
|