@dbx-tools/shared-core 0.3.44 → 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.
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Browser-safe JSON helpers for the parse-untrusted-text case.
3
+ *
4
+ * `JSON.parse` throws on malformed input and returns `any`, so almost every
5
+ * caller in this repo wrapped it in the same try/catch and then re-narrowed the
6
+ * result by hand. {@link parse} collapses the try/catch (a bad document yields
7
+ * the fallback instead of throwing) and {@link parseRecord} adds the narrowing
8
+ * that untrusted JSON almost always needs before it can be indexed.
9
+ *
10
+ * Use these when the document comes from OUTSIDE the process - a request body,
11
+ * an env var, a config file, a subprocess's stdout, a third-party API. Keep
12
+ * bare `JSON.parse` where a throw is the correct outcome (an internally
13
+ * produced document that must be well-formed).
14
+ *
15
+ * These deliberately do NOT validate shape beyond "is it a record". Reach for
16
+ * a zod schema when the payload has a contract; these only get you from `string`
17
+ * to a safely typed starting point.
18
+ *
19
+ * @module
20
+ */
21
+ import { isRecord } from "./object.js";
22
+ export function parse(text, fallback) {
23
+ if (typeof text !== "string" || text.trim().length === 0)
24
+ return fallback;
25
+ try {
26
+ return JSON.parse(text);
27
+ }
28
+ catch {
29
+ return fallback;
30
+ }
31
+ }
32
+ /**
33
+ * Parse JSON text that is expected to be an object, returning `undefined` when
34
+ * it is absent, malformed, or parses to a non-record (an array, a bare string,
35
+ * `null`, ...).
36
+ *
37
+ * This is the common case for manifests, env-var config blobs, and untyped API
38
+ * payloads: {@link parse} followed by {@link isRecord}, so the result can be
39
+ * indexed without an `as Record<string, unknown>` cast.
40
+ *
41
+ * @example
42
+ * const manifest = json.parseRecord(await readFile("package.json", "utf8")) ?? {};
43
+ * const name = manifest.name;
44
+ */
45
+ export function parseRecord(text) {
46
+ const parsed = parse(text);
47
+ return isRecord(parsed) ? parsed : undefined;
48
+ }
49
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianNvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9qc29uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBRUgsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQWdCcEMsTUFBTSxVQUFVLEtBQUssQ0FBYyxJQUFhLEVBQUUsUUFBWTtJQUM1RCxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLFFBQVEsQ0FBQztJQUMxRSxJQUFJLENBQUM7UUFDSCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFNLENBQUM7SUFDL0IsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsTUFBTSxVQUFVLFdBQVcsQ0FBQyxJQUFhO0lBQ3ZDLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMzQixPQUFPLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDL0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQnJvd3Nlci1zYWZlIEpTT04gaGVscGVycyBmb3IgdGhlIHBhcnNlLXVudHJ1c3RlZC10ZXh0IGNhc2UuXG4gKlxuICogYEpTT04ucGFyc2VgIHRocm93cyBvbiBtYWxmb3JtZWQgaW5wdXQgYW5kIHJldHVybnMgYGFueWAsIHNvIGFsbW9zdCBldmVyeVxuICogY2FsbGVyIGluIHRoaXMgcmVwbyB3cmFwcGVkIGl0IGluIHRoZSBzYW1lIHRyeS9jYXRjaCBhbmQgdGhlbiByZS1uYXJyb3dlZCB0aGVcbiAqIHJlc3VsdCBieSBoYW5kLiB7QGxpbmsgcGFyc2V9IGNvbGxhcHNlcyB0aGUgdHJ5L2NhdGNoIChhIGJhZCBkb2N1bWVudCB5aWVsZHNcbiAqIHRoZSBmYWxsYmFjayBpbnN0ZWFkIG9mIHRocm93aW5nKSBhbmQge0BsaW5rIHBhcnNlUmVjb3JkfSBhZGRzIHRoZSBuYXJyb3dpbmdcbiAqIHRoYXQgdW50cnVzdGVkIEpTT04gYWxtb3N0IGFsd2F5cyBuZWVkcyBiZWZvcmUgaXQgY2FuIGJlIGluZGV4ZWQuXG4gKlxuICogVXNlIHRoZXNlIHdoZW4gdGhlIGRvY3VtZW50IGNvbWVzIGZyb20gT1VUU0lERSB0aGUgcHJvY2VzcyAtIGEgcmVxdWVzdCBib2R5LFxuICogYW4gZW52IHZhciwgYSBjb25maWcgZmlsZSwgYSBzdWJwcm9jZXNzJ3Mgc3Rkb3V0LCBhIHRoaXJkLXBhcnR5IEFQSS4gS2VlcFxuICogYmFyZSBgSlNPTi5wYXJzZWAgd2hlcmUgYSB0aHJvdyBpcyB0aGUgY29ycmVjdCBvdXRjb21lIChhbiBpbnRlcm5hbGx5XG4gKiBwcm9kdWNlZCBkb2N1bWVudCB0aGF0IG11c3QgYmUgd2VsbC1mb3JtZWQpLlxuICpcbiAqIFRoZXNlIGRlbGliZXJhdGVseSBkbyBOT1QgdmFsaWRhdGUgc2hhcGUgYmV5b25kIFwiaXMgaXQgYSByZWNvcmRcIi4gUmVhY2ggZm9yXG4gKiBhIHpvZCBzY2hlbWEgd2hlbiB0aGUgcGF5bG9hZCBoYXMgYSBjb250cmFjdDsgdGhlc2Ugb25seSBnZXQgeW91IGZyb20gYHN0cmluZ2BcbiAqIHRvIGEgc2FmZWx5IHR5cGVkIHN0YXJ0aW5nIHBvaW50LlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBpc1JlY29yZCB9IGZyb20gXCIuL29iamVjdFwiO1xuXG4vKipcbiAqIFBhcnNlIEpTT04gdGV4dCwgcmV0dXJuaW5nIGBmYWxsYmFja2AgKGRlZmF1bHQgYHVuZGVmaW5lZGApIGluc3RlYWQgb2ZcbiAqIHRocm93aW5nIHdoZW4gYHRleHRgIGlzIGFic2VudCBvciBtYWxmb3JtZWQuXG4gKlxuICogVGhlIHJldHVybiB0eXBlIGlzIGNhbGxlci1hc3NlcnRlZCwgZXhhY3RseSBsaWtlIGBKU09OLnBhcnNlYCAtIHRoaXMgb25seVxuICogcmVtb3ZlcyB0aGUgdHJ5L2NhdGNoLCBpdCBkb2VzIG5vdCB2YWxpZGF0ZS4gUHJlZmVyIHtAbGluayBwYXJzZVJlY29yZH0gb3IgYVxuICogc2NoZW1hIHdoZW4gdGhlIHJlc3VsdCBpcyBpbmRleGVkLlxuICpcbiAqIEBleGFtcGxlXG4gKiBjb25zdCBjb25maWcgPSBqc29uLnBhcnNlPENvbmZpZz4oYXdhaXQgcmVhZEZpbGUocGF0aCwgXCJ1dGY4XCIpKTtcbiAqIGNvbnN0IHRhZ3MgPSBqc29uLnBhcnNlKHByb2Nlc3MuZW52LlRBR1MsIFtdKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlPFQgPSB1bmtub3duPih0ZXh0OiB1bmtub3duLCBmYWxsYmFjazogVCk6IFQ7XG5leHBvcnQgZnVuY3Rpb24gcGFyc2U8VCA9IHVua25vd24+KHRleHQ6IHVua25vd24pOiBUIHwgdW5kZWZpbmVkO1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlPFQgPSB1bmtub3duPih0ZXh0OiB1bmtub3duLCBmYWxsYmFjaz86IFQpOiBUIHwgdW5kZWZpbmVkIHtcbiAgaWYgKHR5cGVvZiB0ZXh0ICE9PSBcInN0cmluZ1wiIHx8IHRleHQudHJpbSgpLmxlbmd0aCA9PT0gMCkgcmV0dXJuIGZhbGxiYWNrO1xuICB0cnkge1xuICAgIHJldHVybiBKU09OLnBhcnNlKHRleHQpIGFzIFQ7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBmYWxsYmFjaztcbiAgfVxufVxuXG4vKipcbiAqIFBhcnNlIEpTT04gdGV4dCB0aGF0IGlzIGV4cGVjdGVkIHRvIGJlIGFuIG9iamVjdCwgcmV0dXJuaW5nIGB1bmRlZmluZWRgIHdoZW5cbiAqIGl0IGlzIGFic2VudCwgbWFsZm9ybWVkLCBvciBwYXJzZXMgdG8gYSBub24tcmVjb3JkIChhbiBhcnJheSwgYSBiYXJlIHN0cmluZyxcbiAqIGBudWxsYCwgLi4uKS5cbiAqXG4gKiBUaGlzIGlzIHRoZSBjb21tb24gY2FzZSBmb3IgbWFuaWZlc3RzLCBlbnYtdmFyIGNvbmZpZyBibG9icywgYW5kIHVudHlwZWQgQVBJXG4gKiBwYXlsb2Fkczoge0BsaW5rIHBhcnNlfSBmb2xsb3dlZCBieSB7QGxpbmsgaXNSZWNvcmR9LCBzbyB0aGUgcmVzdWx0IGNhbiBiZVxuICogaW5kZXhlZCB3aXRob3V0IGFuIGBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPmAgY2FzdC5cbiAqXG4gKiBAZXhhbXBsZVxuICogY29uc3QgbWFuaWZlc3QgPSBqc29uLnBhcnNlUmVjb3JkKGF3YWl0IHJlYWRGaWxlKFwicGFja2FnZS5qc29uXCIsIFwidXRmOFwiKSkgPz8ge307XG4gKiBjb25zdCBuYW1lID0gbWFuaWZlc3QubmFtZTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlUmVjb3JkKHRleHQ6IHVua25vd24pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHBhcnNlZCA9IHBhcnNlKHRleHQpO1xuICByZXR1cm4gaXNSZWNvcmQocGFyc2VkKSA/IHBhcnNlZCA6IHVuZGVmaW5lZDtcbn1cbiJdfQ==
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Tagged, leveled logging for every runtime - the one logger the whole
3
+ * monorepo shares.
4
+ *
5
+ * {@link logger} resolves a tagged {@link Logger} via a {@link LoggerFactory}
6
+ * chosen once at module load. {@link LogLevel} filtering runs through
7
+ * {@link shouldEmit} in the consola reporter or in per-level wrappers on the
8
+ * `console` fallbacks.
9
+ *
10
+ * Sink selection chains two factories with nullish coalescing (first match
11
+ * wins):
12
+ *
13
+ * 1. {@link createConsolaLoggerFactory} when consola resolves and
14
+ * `LOG_CONSOLA_DISABLED` is not truthy.
15
+ * 2. {@link createConsoleLoggerFactory} everywhere else.
16
+ *
17
+ * The console fallback writes formatted lines to `process.stderr` when it is
18
+ * available (Bun `inspect` per argument when `LOG_BUN_CONSOLE_DISABLED` is
19
+ * unset, otherwise `node:util` `formatWithOptions`), or delegates to global
20
+ * `console.*` when stderr or `node:util` is unavailable. Browser hosts omit
21
+ * the `LEVEL` text prefix (devtools show severity) and keep only the `[name]`
22
+ * tag.
23
+ *
24
+ * Env toggles (read once at init): `LOG_LEVEL`, `LOG_CONSOLA_DISABLED`,
25
+ * `LOG_BUN_CONSOLE_DISABLED`.
26
+ *
27
+ * Browser-safe: `process` / `Bun` / `window` / `document` are all reached
28
+ * through `globalThis` and guarded, and consola / `node:util` load lazily, so
29
+ * the module works in any runtime. Consola is an optional peer; the module
30
+ * loads fine without it.
31
+ *
32
+ * @module
33
+ */
34
+ import { type NameLike } from "./object.js";
35
+ declare const LOG_LEVELS: readonly ["debug", "info", "warn", "error"];
36
+ /**
37
+ * Supported severities, lowest to highest: `debug`, `info`, `warn`, `error`.
38
+ * A call below the active threshold is discarded before any string work or
39
+ * sink I/O.
40
+ *
41
+ * The threshold comes from `process.env.LOG_LEVEL` on every call
42
+ * (case-insensitive, default `info` when unset, empty, or unknown) so test
43
+ * runners and embedders can change verbosity after import without restarting
44
+ * the process.
45
+ */
46
+ export type LogLevel = (typeof LOG_LEVELS)[number];
47
+ export type Logger = {
48
+ [K in LogLevel]: (...args: any[]) => void;
49
+ } & {
50
+ /** Success message (consola `success`; falls back to `info`-level output). */
51
+ success: (...args: any[]) => void;
52
+ /** Start / in-progress message (consola `start`; falls back to `info`-level output). */
53
+ start: (...args: any[]) => void;
54
+ };
55
+ /**
56
+ * Whether a call at `level` would be emitted at the current
57
+ * `process.env.LOG_LEVEL` threshold. Use before building expensive debug
58
+ * payloads.
59
+ *
60
+ * @example
61
+ * if (isLevelEnabled("debug")) {
62
+ * log.debug("mounts:resolver", { contribution: await heavySnapshot() });
63
+ * }
64
+ */
65
+ export declare function isLevelEnabled(level: LogLevel): boolean;
66
+ /**
67
+ * Build a tagged logger for a plugin or module.
68
+ *
69
+ * The tag is `[name]` when `loggerName` is a non-empty string, a
70
+ * {@link NameLike} with `name`, or a file / URL path (the basename without
71
+ * extension is used). Consola applies the tag via `withTag` (render-time).
72
+ * The `console` fallbacks prepend `LEVEL [name]` on Node/Bun hosts or `[name]`
73
+ * alone in browsers via {@link createFormatter}.
74
+ *
75
+ * Calls below `process.env.LOG_LEVEL` are dropped by {@link shouldEmit} before
76
+ * the sink formats or writes the line.
77
+ *
78
+ * @example
79
+ * import { log } from "@dbx-tools/shared-core";
80
+ *
81
+ * const logger = log.logger("genie/chat");
82
+ * logger.info("starting");
83
+ * logger.warn("missing optional config", { reason: "no env var" });
84
+ */
85
+ export declare function logger(loggerName: NameLike | string | undefined): Logger;
86
+ export {};
package/lib/src/log.js ADDED
@@ -0,0 +1,352 @@
1
+ /**
2
+ * Tagged, leveled logging for every runtime - the one logger the whole
3
+ * monorepo shares.
4
+ *
5
+ * {@link logger} resolves a tagged {@link Logger} via a {@link LoggerFactory}
6
+ * chosen once at module load. {@link LogLevel} filtering runs through
7
+ * {@link shouldEmit} in the consola reporter or in per-level wrappers on the
8
+ * `console` fallbacks.
9
+ *
10
+ * Sink selection chains two factories with nullish coalescing (first match
11
+ * wins):
12
+ *
13
+ * 1. {@link createConsolaLoggerFactory} when consola resolves and
14
+ * `LOG_CONSOLA_DISABLED` is not truthy.
15
+ * 2. {@link createConsoleLoggerFactory} everywhere else.
16
+ *
17
+ * The console fallback writes formatted lines to `process.stderr` when it is
18
+ * available (Bun `inspect` per argument when `LOG_BUN_CONSOLE_DISABLED` is
19
+ * unset, otherwise `node:util` `formatWithOptions`), or delegates to global
20
+ * `console.*` when stderr or `node:util` is unavailable. Browser hosts omit
21
+ * the `LEVEL` text prefix (devtools show severity) and keep only the `[name]`
22
+ * tag.
23
+ *
24
+ * Env toggles (read once at init): `LOG_LEVEL`, `LOG_CONSOLA_DISABLED`,
25
+ * `LOG_BUN_CONSOLE_DISABLED`.
26
+ *
27
+ * Browser-safe: `process` / `Bun` / `window` / `document` are all reached
28
+ * through `globalThis` and guarded, and consola / `node:util` load lazily, so
29
+ * the module works in any runtime. Consola is an optional peer; the module
30
+ * loads fine without it.
31
+ *
32
+ * @module
33
+ */
34
+ import { memoize } from "./function.js";
35
+ import { toBoolean } from "./object.js";
36
+ const globalProcess = globalThis.process;
37
+ const globalBun = globalThis.Bun;
38
+ /**
39
+ * Node `process.stderr` when writable, else `undefined` (stable for the
40
+ * process). Typed loosely (`any`) because it is handed to consola's
41
+ * `ctx.options.stdout` (a `WriteStream`) and to the console fallback's
42
+ * `.write`, neither of which our structural {@link ProcessLike} shape satisfies
43
+ * nominally.
44
+ */
45
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
46
+ const globalProcessStdErr = globalProcess && typeof globalProcess.stderr?.write === "function"
47
+ ? globalProcess.stderr
48
+ : undefined;
49
+ const LOG_LEVELS = ["debug", "info", "warn", "error"];
50
+ const LOG_LEVEL_RANK = Object.fromEntries(LOG_LEVELS.map((level, index) => [level, index]));
51
+ const LOG_LEVEL_COLORS = Object.fromEntries(LOG_LEVELS.map((level) => {
52
+ let color = "\x1b[90m"; // gray
53
+ switch (level) {
54
+ case "info":
55
+ color = "\x1b[34m"; // blue
56
+ break;
57
+ case "warn":
58
+ color = "\x1b[33m"; // yellow
59
+ break;
60
+ case "error":
61
+ color = "\x1b[31m"; // red
62
+ break;
63
+ }
64
+ return [level, color];
65
+ }));
66
+ const LOG_LEVEL_COLOR_RESET = "\x1b[0m";
67
+ const DEFAULT_LEVEL = "info";
68
+ /**
69
+ * Consola-backed {@link LoggerFactory}, or `undefined` when consola is
70
+ * disabled, fails to import, or throws during setup.
71
+ *
72
+ * Builds one `createConsola` instance (badge off, level `verbose`) whose
73
+ * reporter calls {@link shouldEmit} on `logObj.type` before delegating to
74
+ * consola's default reporters. In Node, when `globalProcessStdErr` is set,
75
+ * recognized {@link LogLevel} types are redirected to stderr for that write.
76
+ * Tags use `withTag` (rendered `[name]`, not merged into args).
77
+ *
78
+ * Memoized: the dynamic `consola` import, env checks, and `createConsola`
79
+ * setup (plus the import/throw fallback) run once; later calls share the one
80
+ * resolved factory (or the one resolved `undefined`). A rejection is evicted
81
+ * by {@link memoize} so a later call retries.
82
+ */
83
+ const createConsolaLoggerFactory = memoize(async () => {
84
+ const consolaDisabled = toBoolean(globalProcess?.env?.LOG_CONSOLA_DISABLED);
85
+ if (!consolaDisabled) {
86
+ try {
87
+ const { consola, createConsola, LogLevels } = await import(/* @vite-ignore */ "consola");
88
+ const defaultOptions = consola.options;
89
+ const createConsolaOptions = {
90
+ ...consola.options,
91
+ defaults: { badge: false },
92
+ // `LOG_LEVEL` is enforced in {@link shouldEmit}; keep consola permissive
93
+ // so a threshold change after import is not blocked by its own filter.
94
+ level: LogLevels.verbose,
95
+ reporters: [
96
+ {
97
+ log: (logObj, ctx) => {
98
+ const logLevel = parseLogLevel(logObj.type);
99
+ if (!shouldEmit(logLevel, true))
100
+ return;
101
+ const ctxStdout = ctx.options.stdout;
102
+ try {
103
+ if (globalProcessStdErr !== undefined && logLevel !== undefined) {
104
+ ctx.options.stdout = globalProcessStdErr;
105
+ }
106
+ defaultOptions.reporters.forEach((reporter) => reporter.log(logObj, ctx));
107
+ }
108
+ finally {
109
+ ctx.options.stdout = ctxStdout;
110
+ }
111
+ },
112
+ },
113
+ ],
114
+ };
115
+ const consolaLogger = createConsola(createConsolaOptions);
116
+ return (name) => {
117
+ return name ? consolaLogger.withTag(name) : consolaLogger;
118
+ };
119
+ }
120
+ catch (error) {
121
+ // consola is an OPTIONAL peer - not having it installed is the EXPECTED
122
+ // path (the module degrades to the console fallback), so this is not an
123
+ // error. Note it only at debug level, and without a stack trace (the
124
+ // message, not `console.trace`, so a missing optional dep stays quiet).
125
+ if (isLevelEnabled("debug")) {
126
+ console.debug("consola not available; using console fallback:", String(error));
127
+ }
128
+ }
129
+ }
130
+ return undefined;
131
+ });
132
+ /**
133
+ * Console {@link LoggerFactory}; always succeeds.
134
+ *
135
+ * When `process.stderr` is available, formats each line and writes only to
136
+ * stderr. Bun `inspect` formats each argument when enabled; otherwise
137
+ * `util.formatWithOptions` when `node:util` loads, or a `JSON.stringify`
138
+ * fallback when it does not. When stderr is unavailable, binds
139
+ * {@link createFormatter} prefixes into global `console.*` calls.
140
+ */
141
+ async function createConsoleLoggerFactory(globalProcessStdErr) {
142
+ // Indirect specifier so this browser-safe module doesn't statically pull in
143
+ // node types: `node:util` is optional (the JSON fallback covers its absence).
144
+ const nodeUtil = "node:util";
145
+ const utils = await import(/* @vite-ignore */ nodeUtil).catch(() => undefined);
146
+ const bunInspect = globalBun !== undefined && !toBoolean(globalBun.env?.LOG_BUN_CONSOLE_DISABLED)
147
+ ? globalBun.inspect
148
+ : undefined;
149
+ const resetColorsPrefix = bunInspect !== undefined;
150
+ const inspect = (arg, colors) => {
151
+ if (Array.isArray(arg) || (typeof arg === "object" && arg !== null)) {
152
+ if (bunInspect !== undefined) {
153
+ return bunInspect(arg, {
154
+ colors: colors,
155
+ depth: utils?.inspect?.defaultOptions?.depth ?? undefined,
156
+ });
157
+ }
158
+ else if (utils !== undefined) {
159
+ return utils.inspect(arg, {
160
+ ...utils?.inspect?.defaultOptions,
161
+ colors: false,
162
+ });
163
+ }
164
+ else {
165
+ const seen = new WeakSet();
166
+ return JSON.stringify(arg, (_, value) => {
167
+ if (typeof value === "object" && value !== null) {
168
+ if (seen.has(value))
169
+ return "[Circular]";
170
+ seen.add(value);
171
+ }
172
+ return value;
173
+ });
174
+ }
175
+ }
176
+ else {
177
+ return String(arg);
178
+ }
179
+ };
180
+ const factory = (name) => {
181
+ const prefixFormatter = createFormatter(name, globalProcessStdErr, resetColorsPrefix);
182
+ const logger = Object.fromEntries(LOG_LEVELS.map((level) => {
183
+ const { prefix, colors, resetColors } = prefixFormatter(level);
184
+ const emitter = (...args) => {
185
+ if (!shouldEmit(level, true))
186
+ return;
187
+ if (globalProcessStdErr !== undefined) {
188
+ const messageParts = prefix ? [prefix] : [];
189
+ messageParts.push(...args.map((arg) => inspect(arg, colors)));
190
+ if (resetColors)
191
+ messageParts.push(LOG_LEVEL_COLOR_RESET);
192
+ globalProcessStdErr.write(messageParts.join(" ") + "\n");
193
+ }
194
+ else {
195
+ let levelFn = console[level];
196
+ if (typeof levelFn !== "function") {
197
+ levelFn = console.log;
198
+ }
199
+ if (prefix)
200
+ levelFn = levelFn.bind(console, prefix);
201
+ levelFn(...args);
202
+ }
203
+ };
204
+ return [level, emitter];
205
+ }));
206
+ // consola sugar the console fallback doesn't have natively - route to info.
207
+ logger.success = logger.info;
208
+ logger.start = logger.info;
209
+ return logger;
210
+ };
211
+ const defaultFactory = memoize(factory);
212
+ return (name) => (name ? factory(name) : defaultFactory());
213
+ }
214
+ /**
215
+ * Module-scoped {@link LoggerFactory}, initialized once via top-level `await`.
216
+ * Delegates to {@link createConsolaLoggerFactory}, then
217
+ * {@link createConsoleLoggerFactory}. Each {@link logger} call invokes the
218
+ * chosen factory with a resolved tag. Env toggles are read only during init.
219
+ */
220
+ const createLogger = await (async () => {
221
+ return ((await createConsolaLoggerFactory()) ?? (await createConsoleLoggerFactory(globalProcessStdErr)));
222
+ })();
223
+ /**
224
+ * Build a line prefix of `LEVEL [name]` on Node/Bun hosts, or `[name]` alone
225
+ * in browsers (either part omitted when absent). Applies per-level ANSI color
226
+ * when `streamSupportsColor` is true for the given stderr stream.
227
+ */
228
+ function createFormatter(name, stream, resetColorsPrefix) {
229
+ const glob = globalThis;
230
+ const isBrowser = glob.window !== undefined && glob.document !== undefined;
231
+ const supportsColor = !isBrowser ? streamSupportsColor(stream) : false;
232
+ const namePrefix = name ? "[" + name + "]" : undefined;
233
+ return (level) => {
234
+ const color = supportsColor && level !== undefined ? LOG_LEVEL_COLORS[level] : undefined;
235
+ let prefix = [!isBrowser && level ? level.toUpperCase() : undefined, namePrefix]
236
+ .filter(Boolean)
237
+ .join(" ");
238
+ let resetColors = false;
239
+ if (color) {
240
+ const applyResetColorsPrefix = resetColorsPrefix || "info" === level;
241
+ if (!applyResetColorsPrefix)
242
+ resetColors = true;
243
+ prefix = applyResetColorsPrefix ? color + prefix + LOG_LEVEL_COLOR_RESET : color + prefix;
244
+ }
245
+ return { prefix, colors: color ? true : false, resetColors };
246
+ };
247
+ }
248
+ /** True when `stream` is a TTY and the terminal is not `dumb`. */
249
+ function streamSupportsColor(stream) {
250
+ if (globalProcess === undefined || typeof stream !== "object" || stream === null)
251
+ return false;
252
+ const { isTTY } = stream;
253
+ if (isTTY !== true)
254
+ return false;
255
+ const term = globalProcess.env?.TERM?.toLowerCase();
256
+ if ("dumb" == term)
257
+ return false;
258
+ return true;
259
+ }
260
+ /** Parse a raw value as {@link LogLevel} (trimmed, case-insensitive). */
261
+ function parseLogLevel(raw) {
262
+ if (raw === undefined || raw === null) {
263
+ return undefined;
264
+ }
265
+ let text = typeof raw === "string" ? raw : String(raw);
266
+ for (let i = 0; i < 2; i++) {
267
+ if (i > 0) {
268
+ const normalized = text.trim().toLowerCase();
269
+ if (text === normalized)
270
+ break;
271
+ text = normalized;
272
+ }
273
+ if (!text) {
274
+ break;
275
+ }
276
+ else if (text in LOG_LEVEL_RANK) {
277
+ return text;
278
+ }
279
+ }
280
+ return undefined;
281
+ }
282
+ /** Active threshold from `process.env.LOG_LEVEL`, default {@link DEFAULT_LEVEL}. */
283
+ function activeLevel() {
284
+ return parseLogLevel(globalProcess?.env?.LOG_LEVEL) ?? DEFAULT_LEVEL;
285
+ }
286
+ /**
287
+ * Whether `raw` meets the current `LOG_LEVEL` threshold.
288
+ *
289
+ * Parses `raw` as a {@link LogLevel}; when parsing fails, returns
290
+ * `defaultResult` if supplied, otherwise `false`. Used for consola reporter
291
+ * lines where unknown `logObj.type` values should pass through when
292
+ * `defaultResult` is `true`.
293
+ */
294
+ function shouldEmit(raw, defaultResult) {
295
+ const level = parseLogLevel(raw);
296
+ if (level === undefined)
297
+ return defaultResult ?? false;
298
+ return LOG_LEVEL_RANK[level] >= LOG_LEVEL_RANK[activeLevel()];
299
+ }
300
+ /**
301
+ * Whether a call at `level` would be emitted at the current
302
+ * `process.env.LOG_LEVEL` threshold. Use before building expensive debug
303
+ * payloads.
304
+ *
305
+ * @example
306
+ * if (isLevelEnabled("debug")) {
307
+ * log.debug("mounts:resolver", { contribution: await heavySnapshot() });
308
+ * }
309
+ */
310
+ export function isLevelEnabled(level) {
311
+ return shouldEmit(level);
312
+ }
313
+ const LOGGER_NAME_REGEX = /^(?:[a-z][a-z0-9+.-]*:\/\/)?.*\/([^/.]+)(?:\.[^/]+)?$/i;
314
+ /**
315
+ * Derive the tag string from a logger name, plugin, or path. Slash- and
316
+ * URL-shaped strings use the last path segment (extension stripped); plain
317
+ * strings pass through unchanged. Empty or missing names -> `undefined`
318
+ * (untagged sink).
319
+ */
320
+ function extractLoggerName(loggerName) {
321
+ if (!loggerName)
322
+ return undefined;
323
+ if (typeof loggerName === "string") {
324
+ const match = loggerName.match(LOGGER_NAME_REGEX);
325
+ return match?.[1] ?? loggerName;
326
+ }
327
+ return extractLoggerName(loggerName.name);
328
+ }
329
+ /**
330
+ * Build a tagged logger for a plugin or module.
331
+ *
332
+ * The tag is `[name]` when `loggerName` is a non-empty string, a
333
+ * {@link NameLike} with `name`, or a file / URL path (the basename without
334
+ * extension is used). Consola applies the tag via `withTag` (render-time).
335
+ * The `console` fallbacks prepend `LEVEL [name]` on Node/Bun hosts or `[name]`
336
+ * alone in browsers via {@link createFormatter}.
337
+ *
338
+ * Calls below `process.env.LOG_LEVEL` are dropped by {@link shouldEmit} before
339
+ * the sink formats or writes the line.
340
+ *
341
+ * @example
342
+ * import { log } from "@dbx-tools/shared-core";
343
+ *
344
+ * const logger = log.logger("genie/chat");
345
+ * logger.info("starting");
346
+ * logger.warn("missing optional config", { reason: "no env var" });
347
+ */
348
+ export function logger(loggerName) {
349
+ const name = extractLoggerName(loggerName);
350
+ return createLogger(name);
351
+ }
352
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2xvZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQ0c7QUFFSCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3JDLE9BQU8sRUFBaUIsU0FBUyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBY3BELE1BQU0sYUFBYSxHQUFJLFVBQXdDLENBQUMsT0FBTyxDQUFDO0FBQ3hFLE1BQU0sU0FBUyxHQUFJLFVBQWdDLENBQUMsR0FBRyxDQUFDO0FBRXhEOzs7Ozs7R0FNRztBQUNILDhEQUE4RDtBQUM5RCxNQUFNLG1CQUFtQixHQUN2QixhQUFhLElBQUksT0FBTyxhQUFhLENBQUMsTUFBTSxFQUFFLEtBQUssS0FBSyxVQUFVO0lBQ2hFLENBQUMsQ0FBQyxhQUFhLENBQUMsTUFBTTtJQUN0QixDQUFDLENBQUMsU0FBUyxDQUFDO0FBRWhCLE1BQU0sVUFBVSxHQUFHLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFVLENBQUM7QUFDL0QsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FDdkMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQ3JCLENBQUM7QUFDOUIsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUN6QyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7SUFDdkIsSUFBSSxLQUFLLEdBQUcsVUFBVSxDQUFDLENBQUMsT0FBTztJQUMvQixRQUFRLEtBQUssRUFBRSxDQUFDO1FBQ2QsS0FBSyxNQUFNO1lBQ1QsS0FBSyxHQUFHLFVBQVUsQ0FBQyxDQUFDLE9BQU87WUFDM0IsTUFBTTtRQUNSLEtBQUssTUFB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QUFDO0FBQzNCLENBQUM7QUFFRCxNQUFNLGlCQUFpQixHQUFHLHdEQUF3RCxDQUFDO0FBRW5GOzs7OztHQUtHO0FBQ0gsU0FBUyxpQkFBaUIsQ0FBQyxVQUF5QztJQUNsRSxJQUFJLENBQUMsVUFBVTtRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ2xDLElBQUksT0FBTyxVQUFVLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDbkMsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQ2xELE9BQU8sS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksVUFBVSxDQUFDO0lBQ2xDLENBQUM7SUFDRCxPQUFPLGlCQUFpQixDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUM1QyxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUNILE1BQU0sVUFBVSxNQUFNLENBQUMsVUFBeUM7SUFDOUQsTUFBTSxJQUFJLEdBQUcsaUJBQWlCLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDM0MsT0FBTyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDNUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVGFnZ2VkLCBsZXZlbGVkIGxvZ2dpbmcgZm9yIGV2ZXJ5IHJ1bnRpbWUgLSB0aGUgb25lIGxvZ2dlciB0aGUgd2hvbGVcbiAqIG1vbm9yZXBvIHNoYXJlcy5cbiAqXG4gKiB7QGxpbmsgbG9nZ2VyfSByZXNvbHZlcyBhIHRhZ2dlZCB7QGxpbmsgTG9nZ2VyfSB2aWEgYSB7QGxpbmsgTG9nZ2VyRmFjdG9yeX1cbiAqIGNob3NlbiBvbmNlIGF0IG1vZHVsZSBsb2FkLiB7QGxpbmsgTG9nTGV2ZWx9IGZpbHRlcmluZyBydW5zIHRocm91Z2hcbiAqIHtAbGluayBzaG91bGRFbWl0fSBpbiB0aGUgY29uc29sYSByZXBvcnRlciBvciBpbiBwZXItbGV2ZWwgd3JhcHBlcnMgb24gdGhlXG4gKiBgY29uc29sZWAgZmFsbGJhY2tzLlxuICpcbiAqIFNpbmsgc2VsZWN0aW9uIGNoYWlucyB0d28gZmFjdG9yaWVzIHdpdGggbnVsbGlzaCBjb2FsZXNjaW5nIChmaXJzdCBtYXRjaFxuICogd2lucyk6XG4gKlxuICogMS4ge0BsaW5rIGNyZWF0ZUNvbnNvbGFMb2dnZXJGYWN0b3J5fSB3aGVuIGNvbnNvbGEgcmVzb2x2ZXMgYW5kXG4gKiAgICBgTE9HX0NPTlNPTEFfRElTQUJMRURgIGlzIG5vdCB0cnV0aHkuXG4gKiAyLiB7QGxpbmsgY3JlYXRlQ29uc29sZUxvZ2dlckZhY3Rvcnl9IGV2ZXJ5d2hlcmUgZWxzZS5cbiAqXG4gKiBUaGUgY29uc29sZSBmYWxsYmFjayB3cml0ZXMgZm9ybWF0dGVkIGxpbmVzIHRvIGBwcm9jZXNzLnN0ZGVycmAgd2hlbiBpdCBpc1xuICogYXZhaWxhYmxlIChCdW4gYGluc3BlY3RgIHBlciBhcmd1bWVudCB3aGVuIGBMT0dfQlVOX0NPTlNPTEVfRElTQUJMRURgIGlzXG4gKiB1bnNldCwgb3RoZXJ3aXNlIGBub2RlOnV0aWxgIGBmb3JtYXRXaXRoT3B0aW9uc2ApLCBvciBkZWxlZ2F0ZXMgdG8gZ2xvYmFsXG4gKiBgY29uc29sZS4qYCB3aGVuIHN0ZGVyciBvciBgbm9kZTp1dGlsYCBpcyB1bmF2YWlsYWJsZS4gQnJvd3NlciBob3N0cyBvbWl0XG4gKiB0aGUgYExFVkVMYCB0ZXh0IHByZWZpeCAoZGV2dG9vbHMgc2hvdyBzZXZlcml0eSkgYW5kIGtlZXAgb25seSB0aGUgYFtuYW1lXWBcbiAqIHRhZy5cbiAqXG4gKiBFbnYgdG9nZ2xlcyAocmVhZCBvbmNlIGF0IGluaXQpOiBgTE9HX0xFVkVMYCwgYExPR19DT05TT0xBX0RJU0FCTEVEYCxcbiAqIGBMT0dfQlVOX0NPTlNPTEVfRElTQUJMRURgLlxuICpcbiAqIEJyb3dzZXItc2FmZTogYHByb2Nlc3NgIC8gYEJ1bmAgLyBgd2luZG93YCAvIGBkb2N1bWVudGAgYXJlIGFsbCByZWFjaGVkXG4gKiB0aHJvdWdoIGBnbG9iYWxUaGlzYCBhbmQgZ3VhcmRlZCwgYW5kIGNvbnNvbGEgLyBgbm9kZTp1dGlsYCBsb2FkIGxhemlseSwgc29cbiAqIHRoZSBtb2R1bGUgd29ya3MgaW4gYW55IHJ1bnRpbWUuIENvbnNvbGEgaXMgYW4gb3B0aW9uYWwgcGVlcjsgdGhlIG1vZHVsZVxuICogbG9hZHMgZmluZSB3aXRob3V0IGl0LlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBtZW1vaXplIH0gZnJvbSBcIi4vZnVuY3Rpb25cIjtcbmltcG9ydCB7IHR5cGUgTmFtZUxpa2UsIHRvQm9vbGVhbiB9IGZyb20gXCIuL29iamVjdFwiO1xuXG4vKiogYHByb2Nlc3NgLXNoYXBlZCB2aWV3IG9mZiBgZ2xvYmFsVGhpc2AsIHNvIG5vIG5vZGUgdHlwZXMgYXJlIG5lZWRlZC4gKi9cbmludGVyZmFjZSBQcm9jZXNzTGlrZSB7XG4gIGVudj86IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IHVuZGVmaW5lZD47XG4gIHN0ZGVycj86IHsgd3JpdGU/OiAoY2h1bms6IHN0cmluZykgPT4gdm9pZDsgaXNUVFk/OiB1bmtub3duIH07XG59XG5cbi8qKiBgQnVuYC1zaGFwZWQgdmlldyBvZmYgYGdsb2JhbFRoaXNgLCBzbyBubyBgQHR5cGVzL2J1bmAgaXMgbmVlZGVkLiAqL1xuaW50ZXJmYWNlIEJ1bkxpa2Uge1xuICBlbnY/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+O1xuICBpbnNwZWN0PzogKHZhbHVlOiB1bmtub3duLCBvcHRpb25zPzogeyBjb2xvcnM/OiBib29sZWFuOyBkZXB0aD86IG51bWJlciB9KSA9PiBzdHJpbmc7XG59XG5cbmNvbnN0IGdsb2JhbFByb2Nlc3MgPSAoZ2xvYmFsVGhpcyBhcyB7IHByb2Nlc3M/OiBQcm9jZXNzTGlrZSB9KS5wcm9jZXNzO1xuY29uc3QgZ2xvYmFsQnVuID0gKGdsb2JhbFRoaXMgYXMgeyBCdW4/OiBCdW5MaWtlIH0pLkJ1bjtcblxuLyoqXG4gKiBOb2RlIGBwcm9jZXNzLnN0ZGVycmAgd2hlbiB3cml0YWJsZSwgZWxzZSBgdW5kZWZpbmVkYCAoc3RhYmxlIGZvciB0aGVcbiAqIHByb2Nlc3MpLiBUeXBlZCBsb29zZWx5IChgYW55YCkgYmVjYXVzZSBpdCBpcyBoYW5kZWQgdG8gY29uc29sYSdzXG4gKiBgY3R4Lm9wdGlvbnMuc3Rkb3V0YCAoYSBgV3JpdGVTdHJlYW1gKSBhbmQgdG8gdGhlIGNvbnNvbGUgZmFsbGJhY2snc1xuICogYC53cml0ZWAsIG5laXRoZXIgb2Ygd2hpY2ggb3VyIHN0cnVjdHVyYWwge0BsaW5rIFByb2Nlc3NMaWtlfSBzaGFwZSBzYXRpc2ZpZXNcbiAqIG5vbWluYWxseS5cbiAqL1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnlcbmNvbnN0IGdsb2JhbFByb2Nlc3NTdGRFcnI6IGFueSA9XG4gIGdsb2JhbFByb2Nlc3MgJiYgdHlwZW9mIGdsb2JhbFByb2Nlc3Muc3RkZXJyPy53cml0ZSA9PT0gXCJmdW5jdGlvblwiXG4gICAgPyBnbG9iYWxQcm9jZXNzLnN0ZGVyclxuICAgIDogdW5kZWZpbmVkO1xuXG5jb25zdCBMT0dfTEVWRUxTID0gW1wiZGVidWdcIiwgXCJpbmZvXCIsIFwid2FyblwiLCBcImVycm9yXCJdIGFzIGNvbnN0O1xuY29uc3QgTE9HX0xFVkVMX1JBTksgPSBPYmplY3QuZnJvbUVudHJpZXMoXG4gIExPR19MRVZFTFMubWFwKChsZXZlbCwgaW5kZXgpID0+IFtsZXZlbCwgaW5kZXhdKSxcbikgYXMgUmVjb3JkPExvZ0xldmVsLCBudW1iZXI+O1xuY29uc3QgTE9HX0xFVkVMX0NPTE9SUyA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgTE9HX0xFVkVMUy5tYXAoKGxldmVsKSA9PiB7XG4gICAgbGV0IGNvbG9yID0gXCJcXHgxYls5MG1cIjsgLy8gZ3JheVxuICAgIHN3aXRjaCAobGV2ZWwpIHtcbiAgICAgIGNhc2UgXCJpbmZvXCI6XG4gICAgICAgIGNvbG9yID0gXCJcXHgxYlszNG1cIjsgLy8gYmx1ZVxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgXCJ3YXJuXCI6XG4gICAgICAgIGNvbG9yID0gXCJcXHgxYlszM21cIjsgLy8geWVsbG93XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBcImVycm9yXCI6XG4gICAgICAgIGNvbG9yID0gXCJcXHgxYlszMW1cIjsgLy8gcmVkXG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgICByZXR1cm4gW2xldmVsLCBjb2xvcl07XG4gIH0pLFxuKSBhcyBSZWNvcmQ8TG9nTGV2ZWwsIHN0cmluZz47XG5jb25zdCBMT0dfTEVWRUxfQ09MT1JfUkVTRVQgPSBcIlxceDFiWzBtXCI7XG5jb25zdCBERUZBVUxUX0xFVkVMOiBMb2dMZXZlbCA9IFwiaW5mb1wiO1xuXG4vKipcbiAqIFN1cHBvcnRlZCBzZXZlcml0aWVzLCBsb3dlc3QgdG8gaGlnaGVzdDogYGRlYnVnYCwgYGluZm9gLCBgd2FybmAsIGBlcnJvcmAuXG4gKiBBIGNhbGwgYmVsb3cgdGhlIGFjdGl2ZSB0aHJlc2hvbGQgaXMgZGlzY2FyZGVkIGJlZm9yZSBhbnkgc3RyaW5nIHdvcmsgb3JcbiAqIHNpbmsgSS9PLlxuICpcbiAqIFRoZSB0aHJlc2hvbGQgY29tZXMgZnJvbSBgcHJvY2Vzcy5lbnYuTE9HX0xFVkVMYCBvbiBldmVyeSBjYWxsXG4gKiAoY2FzZS1pbnNlbnNpdGl2ZSwgZGVmYXVsdCBgaW5mb2Agd2hlbiB1bnNldCwgZW1wdHksIG9yIHVua25vd24pIHNvIHRlc3RcbiAqIHJ1bm5lcnMgYW5kIGVtYmVkZGVycyBjYW4gY2hhbmdlIHZlcmJvc2l0eSBhZnRlciBpbXBvcnQgd2l0aG91dCByZXN0YXJ0aW5nXG4gKiB0aGUgcHJvY2Vzcy5cbiAqL1xuZXhwb3J0IHR5cGUgTG9nTGV2ZWwgPSAodHlwZW9mIExPR19MRVZFTFMpW251bWJlcl07XG5cbmV4cG9ydCB0eXBlIExvZ2dlciA9IHtcbiAgW0sgaW4gTG9nTGV2ZWxdOiAoLi4uYXJnczogYW55W10pID0+IHZvaWQ7XG59ICYge1xuICAvKiogU3VjY2VzcyBtZXNzYWdlIChjb25zb2xhIGBzdWNjZXNzYDsgZmFsbHMgYmFjayB0byBgaW5mb2AtbGV2ZWwgb3V0cHV0KS4gKi9cbiAgc3VjY2VzczogKC4uLmFyZ3M6IGFueVtdKSA9PiB2b2lkO1xuICAvKiogU3RhcnQgLyBpbi1wcm9ncmVzcyBtZXNzYWdlIChjb25zb2xhIGBzdGFydGA7IGZhbGxzIGJhY2sgdG8gYGluZm9gLWxldmVsIG91dHB1dCkuICovXG4gIHN0YXJ0OiAoLi4uYXJnczogYW55W10pID0+IHZvaWQ7XG59O1xuXG4vKiogYChuYW1lPykgPT4gTG9nZ2VyYCBzaW5rIGNvbnN0cnVjdG9yIHJldHVybmVkIGJ5IHRoZSBpbml0LXRpbWUgZmFjdG9yeSBjaGFpbi4gKi9cbnR5cGUgTG9nZ2VyRmFjdG9yeSA9IChuYW1lPzogc3RyaW5nKSA9PiBMb2dnZXI7XG5cbi8qKlxuICogQ29uc29sYS1iYWNrZWQge0BsaW5rIExvZ2dlckZhY3Rvcnl9LCBvciBgdW5kZWZpbmVkYCB3aGVuIGNvbnNvbGEgaXNcbiAqIGRpc2FibGVkLCBmYWlscyB0byBpbXBvcnQsIG9yIHRocm93cyBkdXJpbmcgc2V0dXAuXG4gKlxuICogQnVpbGRzIG9uZSBgY3JlYXRlQ29uc29sYWAgaW5zdGFuY2UgKGJhZGdlIG9mZiwgbGV2ZWwgYHZlcmJvc2VgKSB3aG9zZVxuICogcmVwb3J0ZXIgY2FsbHMge0BsaW5rIHNob3VsZEVtaXR9IG9uIGBsb2dPYmoudHlwZWAgYmVmb3JlIGRlbGVnYXRpbmcgdG9cbiAqIGNvbnNvbGEncyBkZWZhdWx0IHJlcG9ydGVycy4gSW4gTm9kZSwgd2hlbiBgZ2xvYmFsUHJvY2Vzc1N0ZEVycmAgaXMgc2V0LFxuICogcmVjb2duaXplZCB7QGxpbmsgTG9nTGV2ZWx9IHR5cGVzIGFyZSByZWRpcmVjdGVkIHRvIHN0ZGVyciBmb3IgdGhhdCB3cml0ZS5cbiAqIFRhZ3MgdXNlIGB3aXRoVGFnYCAocmVuZGVyZWQgYFtuYW1lXWAsIG5vdCBtZXJnZWQgaW50byBhcmdzKS5cbiAqXG4gKiBNZW1vaXplZDogdGhlIGR5bmFtaWMgYGNvbnNvbGFgIGltcG9ydCwgZW52IGNoZWNrcywgYW5kIGBjcmVhdGVDb25zb2xhYFxuICogc2V0dXAgKHBsdXMgdGhlIGltcG9ydC90aHJvdyBmYWxsYmFjaykgcnVuIG9uY2U7IGxhdGVyIGNhbGxzIHNoYXJlIHRoZSBvbmVcbiAqIHJlc29sdmVkIGZhY3RvcnkgKG9yIHRoZSBvbmUgcmVzb2x2ZWQgYHVuZGVmaW5lZGApLiBBIHJlamVjdGlvbiBpcyBldmljdGVkXG4gKiBieSB7QGxpbmsgbWVtb2l6ZX0gc28gYSBsYXRlciBjYWxsIHJldHJpZXMuXG4gKi9cbmNvbnN0IGNyZWF0ZUNvbnNvbGFMb2dnZXJGYWN0b3J5ID0gbWVtb2l6ZShhc3luYyAoKTogUHJvbWlzZTxMb2dnZXJGYWN0b3J5IHwgdW5kZWZpbmVkPiA9PiB7XG4gIGNvbnN0IGNvbnNvbGFEaXNhYmxlZCA9IHRvQm9vbGVhbihnbG9iYWxQcm9jZXNzPy5lbnY/LkxPR19DT05TT0xBX0RJU0FCTEVEKTtcbiAgaWYgKCFjb25zb2xhRGlzYWJsZWQpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgeyBjb25zb2xhLCBjcmVhdGVDb25zb2xhLCBMb2dMZXZlbHMgfSA9IGF3YWl0IGltcG9ydCgvKiBAdml0ZS1pZ25vcmUgKi8gXCJjb25zb2xhXCIpO1xuICAgICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBjb25zb2xhLm9wdGlvbnM7XG4gICAgICBjb25zdCBjcmVhdGVDb25zb2xhT3B0aW9ucyA9IHtcbiAgICAgICAgLi4uY29uc29sYS5vcHRpb25zLFxuICAgICAgICBkZWZhdWx0czogeyBiYWRnZTogZmFsc2UgfSxcbiAgICAgICAgLy8gYExPR19MRVZFTGAgaXMgZW5mb3JjZWQgaW4ge0BsaW5rIHNob3VsZEVtaXR9OyBrZWVwIGNvbnNvbGEgcGVybWlzc2l2ZVxuICAgICAgICAvLyBzbyBhIHRocmVzaG9sZCBjaGFuZ2UgYWZ0ZXIgaW1wb3J0IGlzIG5vdCBibG9ja2VkIGJ5IGl0cyBvd24gZmlsdGVyLlxuICAgICAgICBsZXZlbDogTG9nTGV2ZWxzLnZlcmJvc2UsXG4gICAgICAgIHJlcG9ydGVyczogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIGxvZzogKGxvZ09iaiwgY3R4KSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IGxvZ0xldmVsID0gcGFyc2VMb2dMZXZlbChsb2dPYmoudHlwZSk7XG4gICAgICAgICAgICAgIGlmICghc2hvdWxkRW1pdChsb2dMZXZlbCwgdHJ1ZSkpIHJldHVybjtcbiAgICAgICAgICAgICAgY29uc3QgY3R4U3Rkb3V0ID0gY3R4Lm9wdGlvbnMuc3Rkb3V0O1xuICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGlmIChnbG9iYWxQcm9jZXNzU3RkRXJyICE9PSB1bmRlZmluZWQgJiYgbG9nTGV2ZWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgY3R4Lm9wdGlvbnMuc3Rkb3V0ID0gZ2xvYmFsUHJvY2Vzc1N0ZEVycjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZGVmYXVsdE9wdGlvbnMucmVwb3J0ZXJzLmZvckVhY2goKHJlcG9ydGVyKSA9PiByZXBvcnRlci5sb2cobG9nT2JqLCBjdHgpKTtcbiAgICAgICAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgICAgICBjdHgub3B0aW9ucy5zdGRvdXQgPSBjdHhTdGRvdXQ7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0gYXMgTm9uTnVsbGFibGU8UGFyYW1ldGVyczx0eXBlb2YgY3JlYXRlQ29uc29sYT5bMF0+O1xuICAgICAgY29uc3QgY29uc29sYUxvZ2dlciA9IGNyZWF0ZUNvbnNvbGEoY3JlYXRlQ29uc29sYU9wdGlvbnMpO1xuICAgICAgcmV0dXJuIChuYW1lPzogc3RyaW5nKSA9PiB7XG4gICAgICAgIHJldHVybiBuYW1lID8gY29uc29sYUxvZ2dlci53aXRoVGFnKG5hbWUpIDogY29uc29sYUxvZ2dlcjtcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIGNvbnNvbGEgaXMgYW4gT1BUSU9OQUwgcGVlciAtIG5vdCBoYXZpbmcgaXQgaW5zdGFsbGVkIGlzIHRoZSBFWFBFQ1RFRFxuICAgICAgLy8gcGF0aCAodGhlIG1vZHVsZSBkZWdyYWRlcyB0byB0aGUgY29uc29sZSBmYWxsYmFjayksIHNvIHRoaXMgaXMgbm90IGFuXG4gICAgICAvLyBlcnJvci4gTm90ZSBpdCBvbmx5IGF0IGRlYnVnIGxldmVsLCBhbmQgd2l0aG91dCBhIHN0YWNrIHRyYWNlICh0aGVcbiAgICAgIC8vIG1lc3NhZ2UsIG5vdCBgY29uc29sZS50cmFjZWAsIHNvIGEgbWlzc2luZyBvcHRpb25hbCBkZXAgc3RheXMgcXVpZXQpLlxuICAgICAgaWYgKGlzTGV2ZWxFbmFibGVkKFwiZGVidWdcIikpIHtcbiAgICAgICAgY29uc29sZS5kZWJ1ZyhcImNvbnNvbGEgbm90IGF2YWlsYWJsZTsgdXNpbmcgY29uc29sZSBmYWxsYmFjazpcIiwgU3RyaW5nKGVycm9yKSk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59KTtcblxuLyoqXG4gKiBDb25zb2xlIHtAbGluayBMb2dnZXJGYWN0b3J5fTsgYWx3YXlzIHN1Y2NlZWRzLlxuICpcbiAqIFdoZW4gYHByb2Nlc3Muc3RkZXJyYCBpcyBhdmFpbGFibGUsIGZvcm1hdHMgZWFjaCBsaW5lIGFuZCB3cml0ZXMgb25seSB0b1xuICogc3RkZXJyLiBCdW4gYGluc3BlY3RgIGZvcm1hdHMgZWFjaCBhcmd1bWVudCB3aGVuIGVuYWJsZWQ7IG90aGVyd2lzZVxuICogYHV0aWwuZm9ybWF0V2l0aE9wdGlvbnNgIHdoZW4gYG5vZGU6dXRpbGAgbG9hZHMsIG9yIGEgYEpTT04uc3RyaW5naWZ5YFxuICogZmFsbGJhY2sgd2hlbiBpdCBkb2VzIG5vdC4gV2hlbiBzdGRlcnIgaXMgdW5hdmFpbGFibGUsIGJpbmRzXG4gKiB7QGxpbmsgY3JlYXRlRm9ybWF0dGVyfSBwcmVmaXhlcyBpbnRvIGdsb2JhbCBgY29uc29sZS4qYCBjYWxscy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gY3JlYXRlQ29uc29sZUxvZ2dlckZhY3RvcnkoZ2xvYmFsUHJvY2Vzc1N0ZEVycjogYW55KTogUHJvbWlzZTxMb2dnZXJGYWN0b3J5PiB7XG4gIC8vIEluZGlyZWN0IHNwZWNpZmllciBzbyB0aGlzIGJyb3dzZXItc2FmZSBtb2R1bGUgZG9lc24ndCBzdGF0aWNhbGx5IHB1bGwgaW5cbiAgLy8gbm9kZSB0eXBlczogYG5vZGU6dXRpbGAgaXMgb3B0aW9uYWwgKHRoZSBKU09OIGZhbGxiYWNrIGNvdmVycyBpdHMgYWJzZW5jZSkuXG4gIGNvbnN0IG5vZGVVdGlsID0gXCJub2RlOnV0aWxcIjtcbiAgY29uc3QgdXRpbHM6IHsgaW5zcGVjdD86IGFueSB9IHwgdW5kZWZpbmVkID0gYXdhaXQgaW1wb3J0KC8qIEB2aXRlLWlnbm9yZSAqLyBub2RlVXRpbCkuY2F0Y2goXG4gICAgKCkgPT4gdW5kZWZpbmVkLFxuICApO1xuICBjb25zdCBidW5JbnNwZWN0ID1cbiAgICBnbG9iYWxCdW4gIT09IHVuZGVmaW5lZCAmJiAhdG9Cb29sZWFuKGdsb2JhbEJ1bi5lbnY/LkxPR19CVU5fQ09OU09MRV9ESVNBQkxFRClcbiAgICAgID8gZ2xvYmFsQnVuLmluc3BlY3RcbiAgICAgIDogdW5kZWZpbmVkO1xuICBjb25zdCByZXNldENvbG9yc1ByZWZpeCA9IGJ1bkluc3BlY3QgIT09IHVuZGVmaW5lZDtcblxuICBjb25zdCBpbnNwZWN0ID0gKGFyZzogYW55LCBjb2xvcnM/OiBib29sZWFuKSA9PiB7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkoYXJnKSB8fCAodHlwZW9mIGFyZyA9PT0gXCJvYmplY3RcIiAmJiBhcmcgIT09IG51bGwpKSB7XG4gICAgICBpZiAoYnVuSW5zcGVjdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBidW5JbnNwZWN0KGFyZywge1xuICAgICAgICAgIGNvbG9yczogY29sb3JzLFxuICAgICAgICAgIGRlcHRoOiB1dGlscz8uaW5zcGVjdD8uZGVmYXVsdE9wdGlvbnM/LmRlcHRoID8/IHVuZGVmaW5lZCxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKHV0aWxzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIHV0aWxzLmluc3BlY3QoYXJnLCB7XG4gICAgICAgICAgLi4udXRpbHM/Lmluc3BlY3Q/LmRlZmF1bHRPcHRpb25zLFxuICAgICAgICAgIGNvbG9yczogZmFsc2UsXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3Qgc2VlbiA9IG5ldyBXZWFrU2V0KCk7XG4gICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShhcmcsIChfLCB2YWx1ZSkgPT4ge1xuICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIgJiYgdmFsdWUgIT09IG51bGwpIHtcbiAgICAgICAgICAgIGlmIChzZWVuLmhhcyh2YWx1ZSkpIHJldHVybiBcIltDaXJjdWxhcl1cIjtcbiAgICAgICAgICAgIHNlZW4uYWRkKHZhbHVlKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIFN0cmluZyhhcmcpO1xuICAgIH1cbiAgfTtcblxuICBjb25zdCBmYWN0b3J5ID0gKG5hbWU/OiBzdHJpbmcpID0+IHtcbiAgICBjb25zdCBwcmVmaXhGb3JtYXR0ZXIgPSBjcmVhdGVGb3JtYXR0ZXIobmFtZSwgZ2xvYmFsUHJvY2Vzc1N0ZEVyciwgcmVzZXRDb2xvcnNQcmVmaXgpO1xuICAgIGNvbnN0IGxvZ2dlciA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgIExPR19MRVZFTFMubWFwKChsZXZlbCkgPT4ge1xuICAgICAgICBjb25zdCB7IHByZWZpeCwgY29sb3JzLCByZXNldENvbG9ycyB9ID0gcHJlZml4Rm9ybWF0dGVyKGxldmVsKTtcbiAgICAgICAgY29uc3QgZW1pdHRlciA9ICguLi5hcmdzOiBhbnlbXSkgPT4ge1xuICAgICAgICAgIGlmICghc2hvdWxkRW1pdChsZXZlbCwgdHJ1ZSkpIHJldHVybjtcbiAgICAgICAgICBpZiAoZ2xvYmFsUHJvY2Vzc1N0ZEVyciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlUGFydHMgPSBwcmVmaXggPyBbcHJlZml4XSA6IFtdO1xuICAgICAgICAgICAgbWVzc2FnZVBhcnRzLnB1c2goLi4uYXJncy5tYXAoKGFyZykgPT4gaW5zcGVjdChhcmcsIGNvbG9ycykpKTtcbiAgICAgICAgICAgIGlmIChyZXNldENvbG9ycykgbWVzc2FnZVBhcnRzLnB1c2goTE9HX0xFVkVMX0NPTE9SX1JFU0VUKTtcbiAgICAgICAgICAgIGdsb2JhbFByb2Nlc3NTdGRFcnIud3JpdGUobWVzc2FnZVBhcnRzLmpvaW4oXCIgXCIpICsgXCJcXG5cIik7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGxldCBsZXZlbEZuID0gY29uc29sZVtsZXZlbF07XG4gICAgICAgICAgICBpZiAodHlwZW9mIGxldmVsRm4gIT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICBsZXZlbEZuID0gY29uc29sZS5sb2c7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAocHJlZml4KSBsZXZlbEZuID0gbGV2ZWxGbi5iaW5kKGNvbnNvbGUsIHByZWZpeCk7XG4gICAgICAgICAgICBsZXZlbEZuKC4uLmFyZ3MpO1xuICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIFtsZXZlbCwgZW1pdHRlcl07XG4gICAgICB9KSxcbiAgICApIGFzIExvZ2dlcjtcbiAgICAvLyBjb25zb2xhIHN1Z2FyIHRoZSBjb25zb2xlIGZhbGxiYWNrIGRvZXNuJ3QgaGF2ZSBuYXRpdmVseSAtIHJvdXRlIHRvIGluZm8uXG4gICAgbG9nZ2VyLnN1Y2Nlc3MgPSBsb2dnZXIuaW5mbztcbiAgICBsb2dnZXIuc3RhcnQgPSBsb2dnZXIuaW5mbztcbiAgICByZXR1cm4gbG9nZ2VyO1xuICB9O1xuICBjb25zdCBkZWZhdWx0RmFjdG9yeSA9IG1lbW9pemUoZmFjdG9yeSk7XG4gIHJldHVybiAobmFtZT86IHN0cmluZykgPT4gKG5hbWUgPyBmYWN0b3J5KG5hbWUpIDogZGVmYXVsdEZhY3RvcnkoKSk7XG59XG5cbi8qKlxuICogTW9kdWxlLXNjb3BlZCB7QGxpbmsgTG9nZ2VyRmFjdG9yeX0sIGluaXRpYWxpemVkIG9uY2UgdmlhIHRvcC1sZXZlbCBgYXdhaXRgLlxuICogRGVsZWdhdGVzIHRvIHtAbGluayBjcmVhdGVDb25zb2xhTG9nZ2VyRmFjdG9yeX0sIHRoZW5cbiAqIHtAbGluayBjcmVhdGVDb25zb2xlTG9nZ2VyRmFjdG9yeX0uIEVhY2gge0BsaW5rIGxvZ2dlcn0gY2FsbCBpbnZva2VzIHRoZVxuICogY2hvc2VuIGZhY3Rvcnkgd2l0aCBhIHJlc29sdmVkIHRhZy4gRW52IHRvZ2dsZXMgYXJlIHJlYWQgb25seSBkdXJpbmcgaW5pdC5cbiAqL1xuY29uc3QgY3JlYXRlTG9nZ2VyOiBMb2dnZXJGYWN0b3J5ID0gYXdhaXQgKGFzeW5jICgpID0+IHtcbiAgcmV0dXJuIChcbiAgICAoYXdhaXQgY3JlYXRlQ29uc29sYUxvZ2dlckZhY3RvcnkoKSkgPz8gKGF3YWl0IGNyZWF0ZUNvbnNvbGVMb2dnZXJGYWN0b3J5KGdsb2JhbFByb2Nlc3NTdGRFcnIpKVxuICApO1xufSkoKTtcblxuLyoqXG4gKiBCdWlsZCBhIGxpbmUgcHJlZml4IG9mIGBMRVZFTCBbbmFtZV1gIG9uIE5vZGUvQnVuIGhvc3RzLCBvciBgW25hbWVdYCBhbG9uZVxuICogaW4gYnJvd3NlcnMgKGVpdGhlciBwYXJ0IG9taXR0ZWQgd2hlbiBhYnNlbnQpLiBBcHBsaWVzIHBlci1sZXZlbCBBTlNJIGNvbG9yXG4gKiB3aGVuIGBzdHJlYW1TdXBwb3J0c0NvbG9yYCBpcyB0cnVlIGZvciB0aGUgZ2l2ZW4gc3RkZXJyIHN0cmVhbS5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlRm9ybWF0dGVyKFxuICBuYW1lOiBhbnksXG4gIHN0cmVhbTogYW55LFxuICByZXNldENvbG9yc1ByZWZpeD86IGJvb2xlYW4sXG4pOiAobGV2ZWw/OiBMb2dMZXZlbCkgPT4geyBwcmVmaXg6IHN0cmluZzsgY29sb3JzOiBib29sZWFuOyByZXNldENvbG9yczogYm9vbGVhbiB9IHtcbiAgY29uc3QgZ2xvYiA9IGdsb2JhbFRoaXMgYXMgeyB3aW5kb3c/OiB1bmtub3duOyBkb2N1bWVudD86IHVua25vd24gfTtcbiAgY29uc3QgaXNCcm93c2VyID0gZ2xvYi53aW5kb3cgIT09IHVuZGVmaW5lZCAmJiBnbG9iLmRvY3VtZW50ICE9PSB1bmRlZmluZWQ7XG4gIGNvbnN0IHN1cHBvcnRzQ29sb3IgPSAhaXNCcm93c2VyID8gc3RyZWFtU3VwcG9ydHNDb2xvcihzdHJlYW0pIDogZmFsc2U7XG4gIGNvbnN0IG5hbWVQcmVmaXggPSBuYW1lID8gXCJbXCIgKyBuYW1lICsgXCJdXCIgOiB1bmRlZmluZWQ7XG4gIHJldHVybiAobGV2ZWw/OiBMb2dMZXZlbCkgPT4ge1xuICAgIGNvbnN0IGNvbG9yID0gc3VwcG9ydHNDb2xvciAmJiBsZXZlbCAhPT0gdW5kZWZpbmVkID8gTE9HX0xFVkVMX0NPTE9SU1tsZXZlbF0gOiB1bmRlZmluZWQ7XG4gICAgbGV0IHByZWZpeCA9IFshaXNCcm93c2VyICYmIGxldmVsID8gbGV2ZWwudG9VcHBlckNhc2UoKSA6IHVuZGVmaW5lZCwgbmFtZVByZWZpeF1cbiAgICAgIC5maWx0ZXIoQm9vbGVhbilcbiAgICAgIC5qb2luKFwiIFwiKTtcbiAgICBsZXQgcmVzZXRDb2xvcnMgPSBmYWxzZTtcbiAgICBpZiAoY29sb3IpIHtcbiAgICAgIGNvbnN0IGFwcGx5UmVzZXRDb2xvcnNQcmVmaXggPSByZXNldENvbG9yc1ByZWZpeCB8fCBcImluZm9cIiA9PT0gbGV2ZWw7XG4gICAgICBpZiAoIWFwcGx5UmVzZXRDb2xvcnNQcmVmaXgpIHJlc2V0Q29sb3JzID0gdHJ1ZTtcbiAgICAgIHByZWZpeCA9IGFwcGx5UmVzZXRDb2xvcnNQcmVmaXggPyBjb2xvciArIHByZWZpeCArIExPR19MRVZFTF9DT0xPUl9SRVNFVCA6IGNvbG9yICsgcHJlZml4O1xuICAgIH1cbiAgICByZXR1cm4geyBwcmVmaXgsIGNvbG9yczogY29sb3IgPyB0cnVlIDogZmFsc2UsIHJlc2V0Q29sb3JzIH07XG4gIH07XG59XG5cbi8qKiBUcnVlIHdoZW4gYHN0cmVhbWAgaXMgYSBUVFkgYW5kIHRoZSB0ZXJtaW5hbCBpcyBub3QgYGR1bWJgLiAqL1xuZnVuY3Rpb24gc3RyZWFtU3VwcG9ydHNDb2xvcihzdHJlYW0/OiB1bmtub3duKTogYm9vbGVhbiB7XG4gIGlmIChnbG9iYWxQcm9jZXNzID09PSB1bmRlZmluZWQgfHwgdHlwZW9mIHN0cmVhbSAhPT0gXCJvYmplY3RcIiB8fCBzdHJlYW0gPT09IG51bGwpIHJldHVybiBmYWxzZTtcbiAgY29uc3QgeyBpc1RUWSB9ID0gc3RyZWFtIGFzIHsgaXNUVFk/OiB1bmtub3duIH07XG4gIGlmIChpc1RUWSAhPT0gdHJ1ZSkgcmV0dXJuIGZhbHNlO1xuICBjb25zdCB0ZXJtID0gZ2xvYmFsUHJvY2Vzcy5lbnY/LlRFUk0/LnRvTG93ZXJDYXNlKCk7XG4gIGlmIChcImR1bWJcIiA9PSB0ZXJtKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiB0cnVlO1xufVxuXG4vKiogUGFyc2UgYSByYXcgdmFsdWUgYXMge0BsaW5rIExvZ0xldmVsfSAodHJpbW1lZCwgY2FzZS1pbnNlbnNpdGl2ZSkuICovXG5mdW5jdGlvbiBwYXJzZUxvZ0xldmVsKHJhdzogdW5rbm93bik6IExvZ0xldmVsIHwgdW5kZWZpbmVkIHtcbiAgaWYgKHJhdyA9PT0gdW5kZWZpbmVkIHx8IHJhdyA9PT0gbnVsbCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgbGV0IHRleHQgPSB0eXBlb2YgcmF3ID09PSBcInN0cmluZ1wiID8gcmF3IDogU3RyaW5nKHJhdyk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgMjsgaSsrKSB7XG4gICAgaWYgKGkgPiAwKSB7XG4gICAgICBjb25zdCBub3JtYWxpemVkID0gdGV4dC50cmltKCkudG9Mb3dlckNhc2UoKTtcbiAgICAgIGlmICh0ZXh0ID09PSBub3JtYWxpemVkKSBicmVhaztcbiAgICAgIHRleHQgPSBub3JtYWxpemVkO1xuICAgIH1cbiAgICBpZiAoIXRleHQpIHtcbiAgICAgIGJyZWFrO1xuICAgIH0gZWxzZSBpZiAodGV4dCBpbiBMT0dfTEVWRUxfUkFOSykge1xuICAgICAgcmV0dXJuIHRleHQgYXMgTG9nTGV2ZWw7XG4gICAgfVxuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8qKiBBY3RpdmUgdGhyZXNob2xkIGZyb20gYHByb2Nlc3MuZW52LkxPR19MRVZFTGAsIGRlZmF1bHQge0BsaW5rIERFRkFVTFRfTEVWRUx9LiAqL1xuZnVuY3Rpb24gYWN0aXZlTGV2ZWwoKTogTG9nTGV2ZWwge1xuICByZXR1cm4gcGFyc2VMb2dMZXZlbChnbG9iYWxQcm9jZXNzPy5lbnY/LkxPR19MRVZFTCkgPz8gREVGQVVMVF9MRVZFTDtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGByYXdgIG1lZXRzIHRoZSBjdXJyZW50IGBMT0dfTEVWRUxgIHRocmVzaG9sZC5cbiAqXG4gKiBQYXJzZXMgYHJhd2AgYXMgYSB7QGxpbmsgTG9nTGV2ZWx9OyB3aGVuIHBhcnNpbmcgZmFpbHMsIHJldHVybnNcbiAqIGBkZWZhdWx0UmVzdWx0YCBpZiBzdXBwbGllZCwgb3RoZXJ3aXNlIGBmYWxzZWAuIFVzZWQgZm9yIGNvbnNvbGEgcmVwb3J0ZXJcbiAqIGxpbmVzIHdoZXJlIHVua25vd24gYGxvZ09iai50eXBlYCB2YWx1ZXMgc2hvdWxkIHBhc3MgdGhyb3VnaCB3aGVuXG4gKiBgZGVmYXVsdFJlc3VsdGAgaXMgYHRydWVgLlxuICovXG5mdW5jdGlvbiBzaG91bGRFbWl0KHJhdzogdW5rbm93biwgZGVmYXVsdFJlc3VsdD86IGJvb2xlYW4pOiBib29sZWFuIHtcbiAgY29uc3QgbGV2ZWwgPSBwYXJzZUxvZ0xldmVsKHJhdyk7XG4gIGlmIChsZXZlbCA9PT0gdW5kZWZpbmVkKSByZXR1cm4gZGVmYXVsdFJlc3VsdCA/PyBmYWxzZTtcbiAgcmV0dXJuIExPR19MRVZFTF9SQU5LW2xldmVsXSA+PSBMT0dfTEVWRUxfUkFOS1thY3RpdmVMZXZlbCgpXTtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGEgY2FsbCBhdCBgbGV2ZWxgIHdvdWxkIGJlIGVtaXR0ZWQgYXQgdGhlIGN1cnJlbnRcbiAqIGBwcm9jZXNzLmVudi5MT0dfTEVWRUxgIHRocmVzaG9sZC4gVXNlIGJlZm9yZSBidWlsZGluZyBleHBlbnNpdmUgZGVidWdcbiAqIHBheWxvYWRzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBpZiAoaXNMZXZlbEVuYWJsZWQoXCJkZWJ1Z1wiKSkge1xuICogICBsb2cuZGVidWcoXCJtb3VudHM6cmVzb2x2ZXJcIiwgeyBjb250cmlidXRpb246IGF3YWl0IGhlYXZ5U25hcHNob3QoKSB9KTtcbiAqIH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzTGV2ZWxFbmFibGVkKGxldmVsOiBMb2dMZXZlbCk6IGJvb2xlYW4ge1xuICByZXR1cm4gc2hvdWxkRW1pdChsZXZlbCk7XG59XG5cbmNvbnN0IExPR0dFUl9OQU1FX1JFR0VYID0gL14oPzpbYS16XVthLXowLTkrLi1dKjpcXC9cXC8pPy4qXFwvKFteLy5dKykoPzpcXC5bXi9dKyk/JC9pO1xuXG4vKipcbiAqIERlcml2ZSB0aGUgdGFnIHN0cmluZyBmcm9tIGEgbG9nZ2VyIG5hbWUsIHBsdWdpbiwgb3IgcGF0aC4gU2xhc2gtIGFuZFxuICogVVJMLXNoYXBlZCBzdHJpbmdzIHVzZSB0aGUgbGFzdCBwYXRoIHNlZ21lbnQgKGV4dGVuc2lvbiBzdHJpcHBlZCk7IHBsYWluXG4gKiBzdHJpbmdzIHBhc3MgdGhyb3VnaCB1bmNoYW5nZWQuIEVtcHR5IG9yIG1pc3NpbmcgbmFtZXMgLT4gYHVuZGVmaW5lZGBcbiAqICh1bnRhZ2dlZCBzaW5rKS5cbiAqL1xuZnVuY3Rpb24gZXh0cmFjdExvZ2dlck5hbWUobG9nZ2VyTmFtZTogTmFtZUxpa2UgfCBzdHJpbmcgfCB1bmRlZmluZWQpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBpZiAoIWxvZ2dlck5hbWUpIHJldHVybiB1bmRlZmluZWQ7XG4gIGlmICh0eXBlb2YgbG9nZ2VyTmFtZSA9PT0gXCJzdHJpbmdcIikge1xuICAgIGNvbnN0IG1hdGNoID0gbG9nZ2VyTmFtZS5tYXRjaChMT0dHRVJfTkFNRV9SRUdFWCk7XG4gICAgcmV0dXJuIG1hdGNoPy5bMV0gPz8gbG9nZ2VyTmFtZTtcbiAgfVxuICByZXR1cm4gZXh0cmFjdExvZ2dlck5hbWUobG9nZ2VyTmFtZS5uYW1lKTtcbn1cblxuLyoqXG4gKiBCdWlsZCBhIHRhZ2dlZCBsb2dnZXIgZm9yIGEgcGx1Z2luIG9yIG1vZHVsZS5cbiAqXG4gKiBUaGUgdGFnIGlzIGBbbmFtZV1gIHdoZW4gYGxvZ2dlck5hbWVgIGlzIGEgbm9uLWVtcHR5IHN0cmluZywgYVxuICoge0BsaW5rIE5hbWVMaWtlfSB3aXRoIGBuYW1lYCwgb3IgYSBmaWxlIC8gVVJMIHBhdGggKHRoZSBiYXNlbmFtZSB3aXRob3V0XG4gKiBleHRlbnNpb24gaXMgdXNlZCkuIENvbnNvbGEgYXBwbGllcyB0aGUgdGFnIHZpYSBgd2l0aFRhZ2AgKHJlbmRlci10aW1lKS5cbiAqIFRoZSBgY29uc29sZWAgZmFsbGJhY2tzIHByZXBlbmQgYExFVkVMIFtuYW1lXWAgb24gTm9kZS9CdW4gaG9zdHMgb3IgYFtuYW1lXWBcbiAqIGFsb25lIGluIGJyb3dzZXJzIHZpYSB7QGxpbmsgY3JlYXRlRm9ybWF0dGVyfS5cbiAqXG4gKiBDYWxscyBiZWxvdyBgcHJvY2Vzcy5lbnYuTE9HX0xFVkVMYCBhcmUgZHJvcHBlZCBieSB7QGxpbmsgc2hvdWxkRW1pdH0gYmVmb3JlXG4gKiB0aGUgc2luayBmb3JtYXRzIG9yIHdyaXRlcyB0aGUgbGluZS5cbiAqXG4gKiBAZXhhbXBsZVxuICogaW1wb3J0IHsgbG9nIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbiAqXG4gKiBjb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwiZ2VuaWUvY2hhdFwiKTtcbiAqIGxvZ2dlci5pbmZvKFwic3RhcnRpbmdcIik7XG4gKiBsb2dnZXIud2FybihcIm1pc3Npbmcgb3B0aW9uYWwgY29uZmlnXCIsIHsgcmVhc29uOiBcIm5vIGVudiB2YXJcIiB9KTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxvZ2dlcihsb2dnZXJOYW1lOiBOYW1lTGlrZSB8IHN0cmluZyB8IHVuZGVmaW5lZCk6IExvZ2dlciB7XG4gIGNvbnN0IG5hbWUgPSBleHRyYWN0TG9nZ2VyTmFtZShsb2dnZXJOYW1lKTtcbiAgcmV0dXJuIGNyZWF0ZUxvZ2dlcihuYW1lKTtcbn1cbiJdfQ==