@dbx-tools/shared-core 0.3.44 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/src/net.js ADDED
@@ -0,0 +1,465 @@
1
+ /**
2
+ * Browser-safe networking helpers built around {@link urlBuilder}: a
3
+ * tolerant `URL` coercion + chainable builder that gracefully handles
4
+ * partial inputs (bare hosts, path-only strings, `{ url }` wrappers),
5
+ * a small IPv4 / IPv6 address + CIDR toolkit (parsing and membership
6
+ * lookups), and email-address parsing ({@link parseEmails} /
7
+ * {@link isEmail}) that normalizes the CSV / single-string / array
8
+ * inputs email recipient and allow-list fields accept into a clean
9
+ * `string[]`. No node-only imports, so this module is the canonical
10
+ * home for anything URL-, IP-, or email-shaped that also has to run in
11
+ * a Vite / Webpack / esbuild client bundle. Node-only network helpers
12
+ * (e.g. DNS resolution) belong in a node-tagged package, not here.
13
+ *
14
+ * @module
15
+ */
16
+ const LOCAL_HOST_URL = new URL("http://localhost");
17
+ const URL_SCHEME_DEFAULT = "https";
18
+ const URL_SCHEME_PREFIX = /^([A-Za-z][A-Za-z0-9+.-]*:\/\/)/;
19
+ const URL_PATH_SEGMENT_TRIM = /^\/+|\/+$/g;
20
+ const URL_SCHEME_SEPARATOR = "://";
21
+ /** Total bit width of an address of each {@link IpVersion}. */
22
+ const IP_BITS = { 4: 32, 6: 128 };
23
+ const IPV4_OCTET = /^\d{1,3}$/;
24
+ const IPV6_HEXTET = /^[0-9a-fA-F]{1,4}$/;
25
+ /** Delimiters between addresses in a free-text / CSV email list. */
26
+ const EMAIL_LIST_SEPARATOR = /[\s,;]+/;
27
+ /** Pragmatic `local@domain.tld` shape check (not full RFC 5322). */
28
+ const EMAIL_ADDRESS = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
29
+ /**
30
+ * A `URL` subclass with chainable, copy-on-write helpers. Every mutating
31
+ * method returns a fresh builder rather than editing in place, so a base
32
+ * builder can be safely reused. Construct one via {@link urlBuilder}.
33
+ */
34
+ class UrlBuilderImpl extends URL {
35
+ constructor(url) {
36
+ super(url);
37
+ }
38
+ /** The scheme without the trailing colon (`https`, not `https:`). */
39
+ get scheme() {
40
+ return this.protocol.slice(0, -1);
41
+ }
42
+ set scheme(value) {
43
+ this.protocol = value + ":";
44
+ }
45
+ /**
46
+ * Return a copy with a single `URL` property (`pathname`, `search`,
47
+ * `hostname`, `scheme`, ...) set to `value`, leaving this builder
48
+ * untouched.
49
+ */
50
+ with(key, value) {
51
+ const next = new UrlBuilderImpl(this);
52
+ next[key] = value;
53
+ return new UrlBuilderImpl(next);
54
+ }
55
+ /**
56
+ * Return a copy with `pathSegments` appended to the current pathname.
57
+ * Segments may be strings or string arrays; each is trimmed of
58
+ * boundary slashes and blanks are dropped before joining with `/`.
59
+ */
60
+ withPathAppend(...pathSegments) {
61
+ return this.withPathReplace(this.pathname, ...pathSegments);
62
+ }
63
+ /**
64
+ * Return a copy whose pathname is `pathSegments` joined with `/`,
65
+ * replacing any existing path. Segments may be strings or string
66
+ * arrays; each is trimmed of boundary slashes and blanks are dropped.
67
+ */
68
+ withPathReplace(...pathSegments) {
69
+ const pathnameParts = [...pathSegments].flatMap((p) => (Array.isArray(p) ? p : [p]));
70
+ const pathname = pathnameParts
71
+ .map((p) => p.replace(URL_PATH_SEGMENT_TRIM, ""))
72
+ .filter(Boolean)
73
+ .join("/");
74
+ return this.with("pathname", "/" + pathname);
75
+ }
76
+ /**
77
+ * Test whether this URL's pathname is `path` or lives beneath it,
78
+ * matching on segment boundaries so `/api` matches `/api` and
79
+ * `/api/cool` but not `/apicool`. A missing leading slash on `path`
80
+ * is tolerated; query and hash are ignored (they aren't part of
81
+ * `pathname`). Matching is exact otherwise - trailing slashes are
82
+ * not normalized and `/` matches only the root.
83
+ */
84
+ pathMatches(path) {
85
+ const pathname = this.pathname;
86
+ if (pathname == path)
87
+ return true;
88
+ if (!path.startsWith("/"))
89
+ path = "/" + path;
90
+ if (pathname == path)
91
+ return true;
92
+ return pathname.startsWith(path + "/");
93
+ }
94
+ }
95
+ export function urlBuilder(input) {
96
+ if (input instanceof URL) {
97
+ return new UrlBuilderImpl(input);
98
+ }
99
+ if (input !== null && typeof input === "object" && "url" in input) {
100
+ input = input.url;
101
+ }
102
+ if (typeof input === "string") {
103
+ input = input.trim();
104
+ }
105
+ if (input) {
106
+ if (input.startsWith("/") || input.startsWith("?") || input.startsWith("#")) {
107
+ const joinedUrl = defaultUrl().toString().slice(0, -1) + input;
108
+ return urlBuilder(joinedUrl);
109
+ }
110
+ else if (input.startsWith(URL_SCHEME_SEPARATOR)) {
111
+ input = `${URL_SCHEME_DEFAULT}${input}`;
112
+ }
113
+ else {
114
+ const match = input.match(URL_SCHEME_PREFIX);
115
+ const schemePrefix = match?.[1];
116
+ if (schemePrefix) {
117
+ const rest = input.slice(schemePrefix.length);
118
+ input = `${schemePrefix}${rest || defaultUrl().hostname}`;
119
+ }
120
+ else {
121
+ input = `${URL_SCHEME_DEFAULT}://${input}`;
122
+ }
123
+ }
124
+ }
125
+ else {
126
+ return urlBuilder(defaultUrl());
127
+ }
128
+ const url = parseUrl(input);
129
+ return url ? urlBuilder(url) : undefined;
130
+ }
131
+ /**
132
+ * Convenience wrapper over {@link UrlBuilder.pathMatches}: coerce
133
+ * `input` via {@link urlBuilder} and test its pathname against `path`.
134
+ * Returns `false` for input that can't be parsed into a URL.
135
+ *
136
+ * @example
137
+ * pathMatch("/api/cool?q=1", "/api"); // true
138
+ * pathMatch("/apicool", "/api"); // false
139
+ * pathMatch("https://host/api", "/api"); // true
140
+ * pathMatch(request, "/api/v2"); // fetch Request
141
+ */
142
+ export function pathMatch(input, path) {
143
+ const urlb = urlBuilder(input);
144
+ if (!urlb)
145
+ return false;
146
+ return urlb.pathMatches(path);
147
+ }
148
+ /**
149
+ * Base origin for resolving path-only inputs. In a browser this is the
150
+ * current page's origin (`window.location.origin`), so `urlBuilder("/api")`
151
+ * reflects where the app is actually served from; on the server / in
152
+ * tests (no `window`, or an opaque `"null"` origin) it falls back to
153
+ * `http://localhost`.
154
+ */
155
+ function defaultUrl() {
156
+ // Reach `window` via `globalThis` so this compiles without the DOM
157
+ // lib (it's `undefined` on the server / in workers without one).
158
+ const origin = globalThis.window?.location
159
+ ?.origin;
160
+ if (origin && origin !== "null") {
161
+ const originUrl = parseUrl(origin);
162
+ if (originUrl) {
163
+ return originUrl;
164
+ }
165
+ }
166
+ return new URL(LOCAL_HOST_URL);
167
+ }
168
+ function parseUrl(input) {
169
+ if (input && input.includes(URL_SCHEME_SEPARATOR)) {
170
+ try {
171
+ return new URL(input);
172
+ }
173
+ catch { }
174
+ }
175
+ return null;
176
+ }
177
+ /**
178
+ * Normalize the shapes an email address field accepts - a single string,
179
+ * a comma / semicolon / whitespace separated list, an array of either,
180
+ * or nothing - into a clean `string[]`. Each entry is split on the list
181
+ * separators, trimmed, and de-emptied; blanks and non-string array
182
+ * members are dropped. By default duplicates are removed
183
+ * case-insensitively (first-seen casing wins) and casing is otherwise
184
+ * preserved; pass `lowercase` to fold everything to lower case (e.g. for
185
+ * an allow-list). This is the one place recipient lists, CC/BCC inputs,
186
+ * and sender allow-lists across the repo agree on how free-text email
187
+ * input is read. Never throws; does not validate - pair with
188
+ * {@link isEmail} when you need to reject malformed addresses.
189
+ *
190
+ * @example
191
+ * parseEmails("a@x.com, b@y.com; a@x.com"); // ["a@x.com", "b@y.com"]
192
+ * parseEmails(["A@x.com", " b@y.com "]); // ["A@x.com", "b@y.com"]
193
+ * parseEmails("*@corp.com", { lowercase: true }); // ["*@corp.com"]
194
+ * parseEmails(undefined); // []
195
+ */
196
+ export function parseEmails(input, options = {}) {
197
+ if (input === null || input === undefined)
198
+ return [];
199
+ const { lowercase = false, dedupe = true } = options;
200
+ const entries = Array.isArray(input) ? input : [input];
201
+ const seen = new Set();
202
+ const out = [];
203
+ for (const entry of entries) {
204
+ if (typeof entry !== "string")
205
+ continue;
206
+ for (const token of entry.split(EMAIL_LIST_SEPARATOR)) {
207
+ const trimmed = token.trim();
208
+ if (!trimmed)
209
+ continue;
210
+ const address = lowercase ? trimmed.toLowerCase() : trimmed;
211
+ if (dedupe) {
212
+ const key = address.toLowerCase();
213
+ if (seen.has(key))
214
+ continue;
215
+ seen.add(key);
216
+ }
217
+ out.push(address);
218
+ }
219
+ }
220
+ return out;
221
+ }
222
+ /**
223
+ * Pragmatic `local@domain.tld` shape check: non-empty local and domain
224
+ * parts around a single `@`, with a dotted domain and no whitespace.
225
+ * Deliberately loose (not full RFC 5322) - enough to catch obvious typos
226
+ * and give CLI / form feedback, not to gate delivery. Trims first. This
227
+ * is a purely syntactic test, so a wildcard allow-list pattern like
228
+ * `*@example.com` passes; distinguishing a pattern from a real address
229
+ * is the sender policy's job, not this validator's.
230
+ *
231
+ * @example
232
+ * isEmail("alice@example.com"); // true
233
+ * isEmail("nope"); // false (no @)
234
+ * isEmail("no@domain"); // false (no dotted domain)
235
+ */
236
+ export function isEmail(value) {
237
+ return EMAIL_ADDRESS.test(value.trim());
238
+ }
239
+ // ────────────────────────────────────────────────────────────────
240
+ // IP addresses and CIDR blocks
241
+ // ────────────────────────────────────────────────────────────────
242
+ /**
243
+ * Parse an IPv4 (`"1.2.3.4"`) or IPv6 (`"2001:db8::1"`,
244
+ * `"::ffff:1.2.3.4"`, `"::1"`) address into a {@link ParsedIp}, or
245
+ * `null` when the input isn't a valid literal. Never throws. Surrounding
246
+ * whitespace, `[...]` brackets around an IPv6 literal, and an IPv6 zone
247
+ * id (`fe80::1%eth0`) are all tolerated. The `value` is returned as a
248
+ * `bigint` so v4 and v6 share one comparison path.
249
+ *
250
+ * @example
251
+ * parseIp("10.0.0.1"); // { version: 4, value: 167772161n }
252
+ * parseIp("2001:db8::1"); // { version: 6, value: ... }
253
+ * parseIp("not-an-ip"); // null
254
+ */
255
+ export function parseIp(input) {
256
+ let text = input.trim();
257
+ if (text.startsWith("[") && text.endsWith("]"))
258
+ text = text.slice(1, -1);
259
+ if (text.includes(":")) {
260
+ // Drop an IPv6 zone id (`fe80::1%eth0`) - it isn't part of the address.
261
+ const zone = text.indexOf("%");
262
+ if (zone >= 0)
263
+ text = text.slice(0, zone);
264
+ const value = parseIpv6(text);
265
+ return value === null ? null : { version: 6, value };
266
+ }
267
+ const value = parseIpv4(text);
268
+ return value === null ? null : { version: 4, value };
269
+ }
270
+ /**
271
+ * Parse a CIDR block (`"10.0.0.0/8"`, `"2001:db8::/32"`) into a
272
+ * {@link Cidr} with host bits cleared from `base`, or `null` when the
273
+ * input isn't a valid block (bad address, missing / out-of-range
274
+ * prefix). Never throws.
275
+ *
276
+ * @example
277
+ * parseCidr("10.0.0.0/8")?.base; // 167772160n (10.0.0.0)
278
+ * parseCidr("10.1.2.3/8")?.base; // 167772160n (host bits dropped)
279
+ * parseCidr("10.0.0.0/40"); // null (prefix > 32 for v4)
280
+ */
281
+ export function parseCidr(input) {
282
+ const text = input.trim();
283
+ const slash = text.lastIndexOf("/");
284
+ if (slash < 0)
285
+ return null;
286
+ const prefixText = text.slice(slash + 1);
287
+ if (!IPV4_OCTET.test(prefixText))
288
+ return null;
289
+ const ip = parseIp(text.slice(0, slash));
290
+ if (!ip)
291
+ return null;
292
+ const prefix = Number(prefixText);
293
+ const bits = IP_BITS[ip.version];
294
+ if (prefix > bits)
295
+ return null;
296
+ const base = ip.value & networkMask(bits, prefix);
297
+ return {
298
+ version: ip.version,
299
+ base,
300
+ prefix,
301
+ cidr: `${text.slice(0, slash)}/${prefix}`,
302
+ };
303
+ }
304
+ /**
305
+ * Test whether `ip` falls inside `cidr`. Both arguments accept either
306
+ * a string (parsed on the fly via {@link parseIp} / {@link parseCidr})
307
+ * or an already-parsed value - pass parsed values in hot loops to skip
308
+ * re-parsing. Returns `false` for unparseable input or a version
309
+ * mismatch (an IPv4 address is never inside an IPv6 block).
310
+ *
311
+ * @example
312
+ * ipInCidr("10.1.2.3", "10.0.0.0/8"); // true
313
+ * ipInCidr("11.0.0.1", "10.0.0.0/8"); // false
314
+ */
315
+ export function ipInCidr(ip, cidr) {
316
+ const parsedIp = typeof ip === "string" ? parseIp(ip) : ip;
317
+ const parsedCidr = typeof cidr === "string" ? parseCidr(cidr) : cidr;
318
+ if (!parsedIp || !parsedCidr || parsedIp.version !== parsedCidr.version) {
319
+ return false;
320
+ }
321
+ const mask = networkMask(IP_BITS[parsedCidr.version], parsedCidr.prefix);
322
+ return (parsedIp.value & mask) === parsedCidr.base;
323
+ }
324
+ /**
325
+ * Return the first CIDR in `cidrs` that contains `ip`, or `null` when
326
+ * none match. `cidrs` holds pre-parsed {@link Cidr} values (or any
327
+ * object extending it), so callers can carry side metadata on each
328
+ * entry (e.g. a region tag) and read it straight off the returned
329
+ * match. Linear scan; parse the address once by passing a
330
+ * {@link ParsedIp}.
331
+ *
332
+ * @example
333
+ * const ranges = ["10.0.0.0/8", "192.168.0.0/16"]
334
+ * .map(parseCidr)
335
+ * .filter((c): c is Cidr => c !== null);
336
+ * findContainingCidr("10.1.2.3", ranges)?.cidr; // "10.0.0.0/8"
337
+ */
338
+ export function findContainingCidr(ip, cidrs) {
339
+ const parsedIp = typeof ip === "string" ? parseIp(ip) : ip;
340
+ if (!parsedIp)
341
+ return null;
342
+ for (const cidr of cidrs) {
343
+ if (cidr.version !== parsedIp.version)
344
+ continue;
345
+ const mask = networkMask(IP_BITS[cidr.version], cidr.prefix);
346
+ if ((parsedIp.value & mask) === cidr.base)
347
+ return cidr;
348
+ }
349
+ return null;
350
+ }
351
+ /**
352
+ * Whether `input`'s host is a loopback address - `localhost`, an IPv4
353
+ * `127.0.0.0/8` address, or IPv6 `::1` - i.e. a service running on this
354
+ * machine (e.g. a local registry). Accepts anything {@link urlBuilder}
355
+ * coerces (a URL string, `URL`, or `{ url }`); returns `false` when the
356
+ * input has no resolvable host.
357
+ *
358
+ * @example
359
+ * isLoopbackHost("http://localhost:4873"); // true
360
+ * isLoopbackHost("http://127.0.0.1"); // true
361
+ * isLoopbackHost("https://registry.npmjs.org"); // false
362
+ */
363
+ export function isLoopbackHost(input) {
364
+ const host = urlBuilder(input)?.hostname;
365
+ if (!host)
366
+ return false;
367
+ if (host === "localhost")
368
+ return true;
369
+ // `URL` brackets an IPv6 host (`[::1]`); strip them before parsing.
370
+ const ip = host.replace(/^\[|\]$/g, "");
371
+ return ipInCidr(ip, "127.0.0.0/8") || ipInCidr(ip, "::1/128");
372
+ }
373
+ /**
374
+ * Network mask for `prefix` leading bits of a `bits`-wide address as a
375
+ * `bigint`: the top `prefix` bits set, the low host bits cleared.
376
+ * `prefix === 0` yields `0n` (matches everything); `prefix === bits`
377
+ * yields the all-ones mask (matches a single address).
378
+ */
379
+ function networkMask(bits, prefix) {
380
+ const hostBits = BigInt(bits - prefix);
381
+ const full = (1n << BigInt(bits)) - 1n;
382
+ return full ^ ((1n << hostBits) - 1n);
383
+ }
384
+ /** Parse a dotted-quad IPv4 literal into a 32-bit value, else `null`. */
385
+ function parseIpv4(input) {
386
+ const parts = input.split(".");
387
+ if (parts.length !== 4)
388
+ return null;
389
+ let value = 0n;
390
+ for (const part of parts) {
391
+ if (!IPV4_OCTET.test(part))
392
+ return null;
393
+ const octet = Number(part);
394
+ if (octet > 255)
395
+ return null;
396
+ value = (value << 8n) | BigInt(octet);
397
+ }
398
+ return value;
399
+ }
400
+ /**
401
+ * Parse an IPv6 literal into a 128-bit value, else `null`. Handles `::`
402
+ * zero-compression (at most once) and a trailing embedded IPv4 group
403
+ * (`::ffff:1.2.3.4`). The zone id, if any, is expected to be stripped
404
+ * by {@link parseIp} before this is called.
405
+ */
406
+ function parseIpv6(input) {
407
+ const halves = input.split("::");
408
+ if (halves.length > 2)
409
+ return null;
410
+ const head = parseHextets(halves[0]);
411
+ if (head === null)
412
+ return null;
413
+ if (halves.length === 2) {
414
+ const tail = parseHextets(halves[1]);
415
+ if (tail === null)
416
+ return null;
417
+ // "::" must stand in for at least one all-zero hextet.
418
+ const missing = 8 - head.length - tail.length;
419
+ if (missing < 1)
420
+ return null;
421
+ return hextetsToValue([...head, ...Array(missing).fill(0), ...tail]);
422
+ }
423
+ if (head.length !== 8)
424
+ return null;
425
+ return hextetsToValue(head);
426
+ }
427
+ /**
428
+ * Parse one colon-separated run of IPv6 hextets, expanding a trailing
429
+ * embedded IPv4 group into its two hextets. An empty string yields an
430
+ * empty list (the side of a leading / trailing `::`).
431
+ */
432
+ function parseHextets(part) {
433
+ if (part === "")
434
+ return [];
435
+ const tokens = part.split(":");
436
+ const hextets = [];
437
+ for (let i = 0; i < tokens.length; i++) {
438
+ const token = tokens[i];
439
+ if (token.includes(".")) {
440
+ // A dotted-quad is only legal as the final group.
441
+ if (i !== tokens.length - 1)
442
+ return null;
443
+ const v4 = parseIpv4(token);
444
+ if (v4 === null)
445
+ return null;
446
+ hextets.push(Number((v4 >> 16n) & 0xffffn), Number(v4 & 0xffffn));
447
+ }
448
+ else {
449
+ if (!IPV6_HEXTET.test(token))
450
+ return null;
451
+ hextets.push(parseInt(token, 16));
452
+ }
453
+ }
454
+ return hextets;
455
+ }
456
+ /** Fold exactly 8 hextets into a single 128-bit `bigint`, else `null`. */
457
+ function hextetsToValue(hextets) {
458
+ if (hextets.length !== 8)
459
+ return null;
460
+ let value = 0n;
461
+ for (const hextet of hextets)
462
+ value = (value << 16n) | BigInt(hextet);
463
+ return value;
464
+ }
465
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL25ldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7R0FjRztBQUlILE1BQU0sY0FBYyxHQUFHLElBQUksR0FBRyxDQUFDLGtCQUFrQixDQUFDLENBQUM7QUFDbkQsTUFBTSxrQkFBa0IsR0FBRyxPQUFPLENBQUM7QUFDbkMsTUFBTSxpQkFBaUIsR0FBRyxpQ0FBaUMsQ0FBQztBQUM1RCxNQUFNLHFCQUFxQixHQUFHLFlBQVksQ0FBQztBQUMzQyxNQUFNLG9CQUFvQixHQUFHLEtBQUssQ0FBQztBQUVuQywrREFBK0Q7QUFDL0QsTUFBTSxPQUFPLEdBQXdDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLENBQUM7QUFDdkUsTUFBTSxVQUFVLEdBQUcsV0FBVyxDQUFDO0FBQy9CLE1BQU0sV0FBVyxHQUFHLG9CQUFvQixDQUFDO0FBRXpDLG9FQUFvRTtBQUNwRSxNQUFNLG9CQUFvQixHQUFHLFNBQVMsQ0FBQztBQUN2QyxvRUFBb0U7QUFDcEUsTUFBTSxhQUFhLEdBQUcsNEJBQTRCLENBQUM7QUFvRG5EOzs7O0dBSUc7QUFDSCxNQUFNLGNBQWUsU0FBUSxHQUFHO0lBQzlCLFlBQVksR0FBUTtRQUNsQixLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDYixDQUFDO0lBRUQscUVBQXFFO0lBQ3JFLElBQUksTUFBTTtRQUNSLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEMsQ0FBQztJQUVELElBQUksTUFBTSxDQUFDLEtBQWE7UUFDdEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxLQUFLLEdBQUcsR0FBRyxDQUFDO0lBQzlCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsSUFBSSxDQUEyQixHQUFNLEVBQUUsS0FBd0I7UUFDN0QsTUFBTSxJQUFJLEdB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LEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEJyb3dzZXItc2FmZSBuZXR3b3JraW5nIGhlbHBlcnMgYnVpbHQgYXJvdW5kIHtAbGluayB1cmxCdWlsZGVyfTogYVxuICogdG9sZXJhbnQgYFVSTGAgY29lcmNpb24gKyBjaGFpbmFibGUgYnVpbGRlciB0aGF0IGdyYWNlZnVsbHkgaGFuZGxlc1xuICogcGFydGlhbCBpbnB1dHMgKGJhcmUgaG9zdHMsIHBhdGgtb25seSBzdHJpbmdzLCBgeyB1cmwgfWAgd3JhcHBlcnMpLFxuICogYSBzbWFsbCBJUHY0IC8gSVB2NiBhZGRyZXNzICsgQ0lEUiB0b29sa2l0IChwYXJzaW5nIGFuZCBtZW1iZXJzaGlwXG4gKiBsb29rdXBzKSwgYW5kIGVtYWlsLWFkZHJlc3MgcGFyc2luZyAoe0BsaW5rIHBhcnNlRW1haWxzfSAvXG4gKiB7QGxpbmsgaXNFbWFpbH0pIHRoYXQgbm9ybWFsaXplcyB0aGUgQ1NWIC8gc2luZ2xlLXN0cmluZyAvIGFycmF5XG4gKiBpbnB1dHMgZW1haWwgcmVjaXBpZW50IGFuZCBhbGxvdy1saXN0IGZpZWxkcyBhY2NlcHQgaW50byBhIGNsZWFuXG4gKiBgc3RyaW5nW11gLiBObyBub2RlLW9ubHkgaW1wb3J0cywgc28gdGhpcyBtb2R1bGUgaXMgdGhlIGNhbm9uaWNhbFxuICogaG9tZSBmb3IgYW55dGhpbmcgVVJMLSwgSVAtLCBvciBlbWFpbC1zaGFwZWQgdGhhdCBhbHNvIGhhcyB0byBydW4gaW5cbiAqIGEgVml0ZSAvIFdlYnBhY2sgLyBlc2J1aWxkIGNsaWVudCBidW5kbGUuIE5vZGUtb25seSBuZXR3b3JrIGhlbHBlcnNcbiAqIChlLmcuIEROUyByZXNvbHV0aW9uKSBiZWxvbmcgaW4gYSBub2RlLXRhZ2dlZCBwYWNrYWdlLCBub3QgaGVyZS5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBOb25GdW5jdGlvbktleXMgfSBmcm9tIFwiLi9vYmplY3RcIjtcblxuY29uc3QgTE9DQUxfSE9TVF9VUkwgPSBuZXcgVVJMKFwiaHR0cDovL2xvY2FsaG9zdFwiKTtcbmNvbnN0IFVSTF9TQ0hFTUVfREVGQVVMVCA9IFwiaHR0cHNcIjtcbmNvbnN0IFVSTF9TQ0hFTUVfUFJFRklYID0gL14oW0EtWmEtel1bQS1aYS16MC05Ky4tXSo6XFwvXFwvKS87XG5jb25zdCBVUkxfUEFUSF9TRUdNRU5UX1RSSU0gPSAvXlxcLyt8XFwvKyQvZztcbmNvbnN0IFVSTF9TQ0hFTUVfU0VQQVJBVE9SID0gXCI6Ly9cIjtcblxuLyoqIFRvdGFsIGJpdCB3aWR0aCBvZiBhbiBhZGRyZXNzIG9mIGVhY2gge0BsaW5rIElwVmVyc2lvbn0uICovXG5jb25zdCBJUF9CSVRTOiBSZWFkb25seTxSZWNvcmQ8SXBWZXJzaW9uLCBudW1iZXI+PiA9IHsgNDogMzIsIDY6IDEyOCB9O1xuY29uc3QgSVBWNF9PQ1RFVCA9IC9eXFxkezEsM30kLztcbmNvbnN0IElQVjZfSEVYVEVUID0gL15bMC05YS1mQS1GXXsxLDR9JC87XG5cbi8qKiBEZWxpbWl0ZXJzIGJldHdlZW4gYWRkcmVzc2VzIGluIGEgZnJlZS10ZXh0IC8gQ1NWIGVtYWlsIGxpc3QuICovXG5jb25zdCBFTUFJTF9MSVNUX1NFUEFSQVRPUiA9IC9bXFxzLDtdKy87XG4vKiogUHJhZ21hdGljIGBsb2NhbEBkb21haW4udGxkYCBzaGFwZSBjaGVjayAobm90IGZ1bGwgUkZDIDUzMjIpLiAqL1xuY29uc3QgRU1BSUxfQUREUkVTUyA9IC9eW15cXHNAXStAW15cXHNAXStcXC5bXlxcc0BdKyQvO1xuXG4vLyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbi8vIFR5cGVzXG4vLyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuLyoqXG4gKiBBbnl0aGluZyB7QGxpbmsgdXJsQnVpbGRlcn0gKGFuZCB7QGxpbmsgcGF0aE1hdGNofSkga25vdyBob3cgdG8gY29lcmNlXG4gKiBpbnRvIGEgVVJMOlxuICpcbiAqIC0gQSBzdHJpbmc6IGEgaG9zdCwgYSBmdWxsIFVSTCwgb3IgYSBwYXRoIC8gcXVlcnkgLyBoYXNoIGZyYWdtZW50LlxuICogLSBBIFdIQVRXRyBgVVJMYCBpbnN0YW5jZS5cbiAqIC0gQW55IG9iamVjdCB3aXRoIGEgYHVybGAgZmllbGQgKGUuZy4gYSBmZXRjaCBgUmVxdWVzdGAsIGEgRGF0YWJyaWNrc1xuICogICBgV29ya3NwYWNlQ2xpZW50YCBjb25maWcpLlxuICovXG5leHBvcnQgdHlwZSBVcmxMaWtlID0gc3RyaW5nIHwgVVJMIHwgeyB1cmw6IHN0cmluZyB9O1xuXG4vKiogSVAgcHJvdG9jb2wgZmFtaWx5OiBgNGAgZm9yIElQdjQsIGA2YCBmb3IgSVB2Ni4gKi9cbmV4cG9ydCB0eXBlIElwVmVyc2lvbiA9IDQgfCA2O1xuXG4vKipcbiAqIEEgcGFyc2VkIElQIGFkZHJlc3MuIGB2YWx1ZWAgaXMgdGhlIGFkZHJlc3MgYXMgYW4gdW5zaWduZWQgaW50ZWdlclxuICogKGEgMzItYml0IHJhbmdlIGZvciB2NCwgMTI4LWJpdCBmb3IgdjYpIGhlbGQgaW4gYSBgYmlnaW50YCBzbyBib3RoXG4gKiBmYW1pbGllcyBzaGFyZSBvbmUgY29tcGFyaXNvbiAvIG1hc2tpbmcgcGF0aC4gUHJvZHVjZSBvbmUgd2l0aFxuICoge0BsaW5rIHBhcnNlSXB9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBhcnNlZElwIHtcbiAgdmVyc2lvbjogSXBWZXJzaW9uO1xuICAvKiogVGhlIGFkZHJlc3MgYXMgYW4gdW5zaWduZWQgaW50ZWdlciAoYGJpZ2ludGAgZm9yIHVuaWZvcm0gdjQvdjYgbWF0aCkuICovXG4gIHZhbHVlOiBiaWdpbnQ7XG59XG5cbi8qKlxuICogQSBwYXJzZWQgQ0lEUiBibG9jayAoYDEwLjAuMC4wLzhgLCBgMjAwMTpkYjg6Oi8zMmApLiBgYmFzZWAgaXMgdGhlXG4gKiBuZXR3b3JrIGFkZHJlc3Mgd2l0aCBhbGwgaG9zdCBiaXRzIGNsZWFyZWQsIHNvIG1lbWJlcnNoaXAgaXMgYVxuICogc2luZ2xlIG1hc2tlZCBjb21wYXJlIChzZWUge0BsaW5rIGlwSW5DaWRyfSkuIFByb2R1Y2Ugb25lIHdpdGhcbiAqIHtAbGluayBwYXJzZUNpZHJ9LiBDYXJyaWVzIHRoZSBub3JtYWxpemVkIGBjaWRyYCBzdHJpbmcgZm9yIGxvZ2dpbmdcbiAqIGFuZCB0byBrZXkgYmFjayB0byBjYWxsZXItc2lkZSBtZXRhZGF0YS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDaWRyIHtcbiAgdmVyc2lvbjogSXBWZXJzaW9uO1xuICAvKiogTmV0d29yayBhZGRyZXNzIChob3N0IGJpdHMgemVyb2VkKSBhcyBhbiB1bnNpZ25lZCBgYmlnaW50YC4gKi9cbiAgYmFzZTogYmlnaW50O1xuICAvKiogUHJlZml4IGxlbmd0aCBpbiBiaXRzICh0aGUgbnVtYmVyIGFmdGVyIHRoZSBgL2ApLiAqL1xuICBwcmVmaXg6IG51bWJlcjtcbiAgLyoqIE5vcm1hbGl6ZWQgYDxhZGRyZXNzPi88cHJlZml4PmAgc3RyaW5nLiAqL1xuICBjaWRyOiBzdHJpbmc7XG59XG5cbi8qKiBTZXR0YWJsZSwgbm9uLW1ldGhvZCBgVVJMYCBwcm9wZXJ0aWVzIC0gdGhlIGtleXMge0BsaW5rIFVybEJ1aWxkZXIud2l0aH0gYWNjZXB0cy4gKi9cbnR5cGUgVXJsUHJvcGVydHlLZXkgPSBOb25GdW5jdGlvbktleXM8VXJsQnVpbGRlckltcGw+O1xuXG4vKipcbiAqIEEgYFVSTGAgc3ViY2xhc3Mgd2l0aCBjaGFpbmFibGUsIGNvcHktb24td3JpdGUgaGVscGVycy4gRXZlcnkgbXV0YXRpbmdcbiAqIG1ldGhvZCByZXR1cm5zIGEgZnJlc2ggYnVpbGRlciByYXRoZXIgdGhhbiBlZGl0aW5nIGluIHBsYWNlLCBzbyBhIGJhc2VcbiAqIGJ1aWxkZXIgY2FuIGJlIHNhZmVseSByZXVzZWQuIENvbnN0cnVjdCBvbmUgdmlhIHtAbGluayB1cmxCdWlsZGVyfS5cbiAqL1xuY2xhc3MgVXJsQnVpbGRlckltcGwgZXh0ZW5kcyBVUkwge1xuICBjb25zdHJ1Y3Rvcih1cmw6IFVSTCkge1xuICAgIHN1cGVyKHVybCk7XG4gIH1cblxuICAvKiogVGhlIHNjaGVtZSB3aXRob3V0IHRoZSB0cmFpbGluZyBjb2xvbiAoYGh0dHBzYCwgbm90IGBodHRwczpgKS4gKi9cbiAgZ2V0IHNjaGVtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnByb3RvY29sLnNsaWNlKDAsIC0xKTtcbiAgfVxuXG4gIHNldCBzY2hlbWUodmFsdWU6IHN0cmluZykge1xuICAgIHRoaXMucHJvdG9jb2wgPSB2YWx1ZSArIFwiOlwiO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBhIGNvcHkgd2l0aCBhIHNpbmdsZSBgVVJMYCBwcm9wZXJ0eSAoYHBhdGhuYW1lYCwgYHNlYXJjaGAsXG4gICAqIGBob3N0bmFtZWAsIGBzY2hlbWVgLCAuLi4pIHNldCB0byBgdmFsdWVgLCBsZWF2aW5nIHRoaXMgYnVpbGRlclxuICAgKiB1bnRvdWNoZWQuXG4gICAqL1xuICB3aXRoPEsgZXh0ZW5kcyBVcmxQcm9wZXJ0eUtleT4oa2V5OiBLLCB2YWx1ZTogVXJsQnVpbGRlckltcGxbS10pOiBVcmxCdWlsZGVyIHtcbiAgICBjb25zdCBuZXh0ID0gbmV3IFVybEJ1aWxkZXJJbXBsKHRoaXMpO1xuICAgIChuZXh0IGFzIGFueSlba2V5XSA9IHZhbHVlO1xuICAgIHJldHVybiBuZXcgVXJsQnVpbGRlckltcGwobmV4dCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGEgY29weSB3aXRoIGBwYXRoU2VnbWVudHNgIGFwcGVuZGVkIHRvIHRoZSBjdXJyZW50IHBhdGhuYW1lLlxuICAgKiBTZWdtZW50cyBtYXkgYmUgc3RyaW5ncyBvciBzdHJpbmcgYXJyYXlzOyBlYWNoIGlzIHRyaW1tZWQgb2ZcbiAgICogYm91bmRhcnkgc2xhc2hlcyBhbmQgYmxhbmtzIGFyZSBkcm9wcGVkIGJlZm9yZSBqb2luaW5nIHdpdGggYC9gLlxuICAgKi9cbiAgd2l0aFBhdGhBcHBlbmQoLi4ucGF0aFNlZ21lbnRzOiAoc3RyaW5nIHwgc3RyaW5nW10pW10pOiBVcmxCdWlsZGVyIHtcbiAgICByZXR1cm4gdGhpcy53aXRoUGF0aFJlcGxhY2UodGhpcy5wYXRobmFtZSwgLi4ucGF0aFNlZ21lbnRzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYSBjb3B5IHdob3NlIHBhdGhuYW1lIGlzIGBwYXRoU2VnbWVudHNgIGpvaW5lZCB3aXRoIGAvYCxcbiAgICogcmVwbGFjaW5nIGFueSBleGlzdGluZyBwYXRoLiBTZWdtZW50cyBtYXkgYmUgc3RyaW5ncyBvciBzdHJpbmdcbiAgICogYXJyYXlzOyBlYWNoIGlzIHRyaW1tZWQgb2YgYm91bmRhcnkgc2xhc2hlcyBhbmQgYmxhbmtzIGFyZSBkcm9wcGVkLlxuICAgKi9cbiAgd2l0aFBhdGhSZXBsYWNlKC4uLnBhdGhTZWdtZW50czogKHN0cmluZyB8IHN0cmluZ1tdKVtdKTogVXJsQnVpbGRlciB7XG4gICAgY29uc3QgcGF0aG5hbWVQYXJ0czogc3RyaW5nW10gPSBbLi4ucGF0aFNlZ21lbnRzXS5mbGF0TWFwKChwKSA9PiAoQXJyYXkuaXNBcnJheShwKSA/IHAgOiBbcF0pKTtcbiAgICBjb25zdCBwYXRobmFtZSA9IHBhdGhuYW1lUGFydHNcbiAgICAgIC5tYXAoKHApID0+IHAucmVwbGFjZShVUkxfUEFUSF9TRUdNRU5UX1RSSU0sIFwiXCIpKVxuICAgICAgLmZpbHRlcihCb29sZWFuKVxuICAgICAgLmpvaW4oXCIvXCIpO1xuICAgIHJldHVybiB0aGlzLndpdGgoXCJwYXRobmFtZVwiLCBcIi9cIiArIHBhdGhuYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUZXN0IHdoZXRoZXIgdGhpcyBVUkwncyBwYXRobmFtZSBpcyBgcGF0aGAgb3IgbGl2ZXMgYmVuZWF0aCBpdCxcbiAgICogbWF0Y2hpbmcgb24gc2VnbWVudCBib3VuZGFyaWVzIHNvIGAvYXBpYCBtYXRjaGVzIGAvYXBpYCBhbmRcbiAgICogYC9hcGkvY29vbGAgYnV0IG5vdCBgL2FwaWNvb2xgLiBBIG1pc3NpbmcgbGVhZGluZyBzbGFzaCBvbiBgcGF0aGBcbiAgICogaXMgdG9sZXJhdGVkOyBxdWVyeSBhbmQgaGFzaCBhcmUgaWdub3JlZCAodGhleSBhcmVuJ3QgcGFydCBvZlxuICAgKiBgcGF0aG5hbWVgKS4gTWF0Y2hpbmcgaXMgZXhhY3Qgb3RoZXJ3aXNlIC0gdHJhaWxpbmcgc2xhc2hlcyBhcmVcbiAgICogbm90IG5vcm1hbGl6ZWQgYW5kIGAvYCBtYXRjaGVzIG9ubHkgdGhlIHJvb3QuXG4gICAqL1xuICBwYXRoTWF0Y2hlcyhwYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBwYXRobmFtZSA9IHRoaXMucGF0aG5hbWU7XG4gICAgaWYgKHBhdGhuYW1lID09IHBhdGgpIHJldHVybiB0cnVlO1xuICAgIGlmICghcGF0aC5zdGFydHNXaXRoKFwiL1wiKSkgcGF0aCA9IFwiL1wiICsgcGF0aDtcbiAgICBpZiAocGF0aG5hbWUgPT0gcGF0aCkgcmV0dXJuIHRydWU7XG4gICAgcmV0dXJuIHBhdGhuYW1lLnN0YXJ0c1dpdGgocGF0aCArIFwiL1wiKTtcbiAgfVxufVxuXG4vKiogUHVibGljIHR5cGUgZm9yIHRoZSB7QGxpbmsgdXJsQnVpbGRlcn0gcmV0dXJuIHZhbHVlLiAqL1xuZXhwb3J0IHR5cGUgVXJsQnVpbGRlciA9IFVybEJ1aWxkZXJJbXBsO1xuXG4vKiogV2l0aCBubyBhcmd1bWVudCwgcmVzb2x2ZXMgdG8gdGhlIGJhc2Ugb3JpZ2luIChuZXZlciBgbnVsbGApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVybEJ1aWxkZXIoKTogVXJsQnVpbGRlcjtcblxuLyoqXG4gKiBDb2VyY2UgYSB7QGxpbmsgVXJsTGlrZX0gaW50byBhIGNoYWluYWJsZSB7QGxpbmsgVXJsQnVpbGRlcn0sIG9yIGBudWxsYFxuICogd2hlbiB0aGUgaW5wdXQgY2Fubm90IGJlIHBhcnNlZCBpbnRvIGEgVVJMLiBOZXZlciB0aHJvd3MuXG4gKlxuICogLSBBIGBVUkxgIGluc3RhbmNlIG9yIGB7IHVybCB9YCB3cmFwcGVyIGlzIGFkb3B0ZWQgYXMtaXMuXG4gKiAtIEEgYmFyZSBob3N0bmFtZSAoYFwiZXhhbXBsZS5jb21cImApIGlzIHVwZ3JhZGVkIHRvIGBodHRwczovL2A7IGFuXG4gKiAgIGV4cGxpY2l0IHNjaGVtZSBpcyBwcmVzZXJ2ZWQuXG4gKiAtIEEgcGF0aCAvIHF1ZXJ5IC8gaGFzaCBmcmFnbWVudCAoYFwiL2FwaVwiYCwgYFwiP3E9MVwiYCwgYFwiI3hcImApIGlzXG4gKiAgIHJlc29sdmVkIGFnYWluc3Qge0BsaW5rIGRlZmF1bHRVcmx9ICh0aGUgYnJvd3NlciBvcmlnaW4sIGVsc2VcbiAqICAgYGh0dHA6Ly9sb2NhbGhvc3RgKS5cbiAqIC0gQW4gZW1wdHkgLyBibGFuayBzdHJpbmcgb3Igb21pdHRlZCBpbnB1dCByZXNvbHZlcyB0byB0aGUgYmFzZVxuICogICBvcmlnaW4uXG4gKlxuICogQGV4YW1wbGVcbiAqIHVybEJ1aWxkZXIoXCJleGFtcGxlLmNvbVwiKTsgICAgICAgICAgLy8gaHR0cHM6Ly9leGFtcGxlLmNvbS9cbiAqIHVybEJ1aWxkZXIoXCJodHRwOi8veC9wYXRoXCIpOyAgICAgICAgLy8gaHR0cDovL3gvcGF0aFxuICogdXJsQnVpbGRlcihcIi9hcGkvdjJcIik7ICAgICAgICAgICAgICAvLyBodHRwOi8vbG9jYWxob3N0L2FwaS92MlxuICogdXJsQnVpbGRlcih7IHVybDogXCJodHRwOi8veVwiIH0pOyAgICAvLyBodHRwOi8veS9cbiAqIHVybEJ1aWxkZXIoKTsgICAgICAgICAgICAgICAgICAgICAgIC8vIGh0dHA6Ly9sb2NhbGhvc3QvXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1cmxCdWlsZGVyKGlucHV0PzogVXJsTGlrZSk6IFVybEJ1aWxkZXIgfCB1bmRlZmluZWQ7XG5cbmV4cG9ydCBmdW5jdGlvbiB1cmxCdWlsZGVyKGlucHV0PzogVXJsTGlrZSk6IFVybEJ1aWxkZXIgfCB1bmRlZmluZWQge1xuICBpZiAoaW5wdXQgaW5zdGFuY2VvZiBVUkwpIHtcbiAgICByZXR1cm4gbmV3IFVybEJ1aWxkZXJJbXBsKGlucHV0KTtcbiAgfVxuICBpZiAoaW5wdXQgIT09IG51bGwgJiYgdHlwZW9mIGlucHV0ID09PSBcIm9iamVjdFwiICYmIFwidXJsXCIgaW4gaW5wdXQpIHtcbiAgICBpbnB1dCA9IGlucHV0LnVybDtcbiAgfVxuICBpZiAodHlwZW9mIGlucHV0ID09PSBcInN0cmluZ1wiKSB7XG4gICAgaW5wdXQgPSBpbnB1dC50cmltKCk7XG4gIH1cbiAgaWYgKGlucHV0KSB7XG4gICAgaWYgKGlucHV0LnN0YXJ0c1dpdGgoXCIvXCIpIHx8IGlucHV0LnN0YXJ0c1dpdGgoXCI/XCIpIHx8IGlucHV0LnN0YXJ0c1dpdGgoXCIjXCIpKSB7XG4gICAgICBjb25zdCBqb2luZWRVcmwgPSBkZWZhdWx0VXJsKCkudG9TdHJpbmcoKS5zbGljZSgwLCAtMSkgKyBpbnB1dDtcbiAgICAgIHJldHVybiB1cmxCdWlsZGVyKGpvaW5lZFVybCk7XG4gICAgfSBlbHNlIGlmIChpbnB1dC5zdGFydHNXaXRoKFVSTF9TQ0hFTUVfU0VQQVJBVE9SKSkge1xuICAgICAgaW5wdXQgPSBgJHtVUkxfU0NIRU1FX0RFRkFVTFR9JHtpbnB1dH1gO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBtYXRjaCA9IGlucHV0Lm1hdGNoKFVSTF9TQ0hFTUVfUFJFRklYKTtcbiAgICAgIGNvbnN0IHNjaGVtZVByZWZpeCA9IG1hdGNoPy5bMV07XG4gICAgICBpZiAoc2NoZW1lUHJlZml4KSB7XG4gICAgICAgIGNvbnN0IHJlc3QgPSBpbnB1dC5zbGljZShzY2hlbWVQcmVmaXgubGVuZ3RoKTtcbiAgICAgICAgaW5wdXQgPSBgJHtzY2hlbWVQcmVmaXh9JHtyZXN0IHx8IGRlZmF1bHRVcmwoKS5ob3N0bmFtZX1gO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaW5wdXQgPSBgJHtVUkxfU0NIRU1FX0RFRkFVTFR9Oi8vJHtpbnB1dH1gO1xuICAgICAgfVxuICAgIH1cbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gdXJsQnVpbGRlcihkZWZhdWx0VXJsKCkpO1xuICB9XG4gIGNvbnN0IHVybCA9IHBhcnNlVXJsKGlucHV0KTtcbiAgcmV0dXJuIHVybCA/IHVybEJ1aWxkZXIodXJsKSA6IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBDb252ZW5pZW5jZSB3cmFwcGVyIG92ZXIge0BsaW5rIFVybEJ1aWxkZXIucGF0aE1hdGNoZXN9OiBjb2VyY2VcbiAqIGBpbnB1dGAgdmlhIHtAbGluayB1cmxCdWlsZGVyfSBhbmQgdGVzdCBpdHMgcGF0aG5hbWUgYWdhaW5zdCBgcGF0aGAuXG4gKiBSZXR1cm5zIGBmYWxzZWAgZm9yIGlucHV0IHRoYXQgY2FuJ3QgYmUgcGFyc2VkIGludG8gYSBVUkwuXG4gKlxuICogQGV4YW1wbGVcbiAqIHBhdGhNYXRjaChcIi9hcGkvY29vbD9xPTFcIiwgXCIvYXBpXCIpOyAgICAgIC8vIHRydWVcbiAqIHBhdGhNYXRjaChcIi9hcGljb29sXCIsIFwiL2FwaVwiKTsgICAgICAgICAgIC8vIGZhbHNlXG4gKiBwYXRoTWF0Y2goXCJodHRwczovL2hvc3QvYXBpXCIsIFwiL2FwaVwiKTsgICAvLyB0cnVlXG4gKiBwYXRoTWF0Y2gocmVxdWVzdCwgXCIvYXBpL3YyXCIpOyAgICAgICAgICAgLy8gZmV0Y2ggUmVxdWVzdFxuICovXG5leHBvcnQgZnVuY3Rpb24gcGF0aE1hdGNoKGlucHV0OiBVcmxMaWtlLCBwYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgY29uc3QgdXJsYiA9IHVybEJ1aWxkZXIoaW5wdXQpO1xuICBpZiAoIXVybGIpIHJldHVybiBmYWxzZTtcbiAgcmV0dXJuIHVybGIucGF0aE1hdGNoZXMocGF0aCk7XG59XG5cbi8qKlxuICogQmFzZSBvcmlnaW4gZm9yIHJlc29sdmluZyBwYXRoLW9ubHkgaW5wdXRzLiBJbiBhIGJyb3dzZXIgdGhpcyBpcyB0aGVcbiAqIGN1cnJlbnQgcGFnZSdzIG9yaWdpbiAoYHdpbmRvdy5sb2NhdGlvbi5vcmlnaW5gKSwgc28gYHVybEJ1aWxkZXIoXCIvYXBpXCIpYFxuICogcmVmbGVjdHMgd2hlcmUgdGhlIGFwcCBpcyBhY3R1YWxseSBzZXJ2ZWQgZnJvbTsgb24gdGhlIHNlcnZlciAvIGluXG4gKiB0ZXN0cyAobm8gYHdpbmRvd2AsIG9yIGFuIG9wYXF1ZSBgXCJudWxsXCJgIG9yaWdpbikgaXQgZmFsbHMgYmFjayB0b1xuICogYGh0dHA6Ly9sb2NhbGhvc3RgLlxuICovXG5mdW5jdGlvbiBkZWZhdWx0VXJsKCk6IFVSTCB7XG4gIC8vIFJlYWNoIGB3aW5kb3dgIHZpYSBgZ2xvYmFsVGhpc2Agc28gdGhpcyBjb21waWxlcyB3aXRob3V0IHRoZSBET01cbiAgLy8gbGliIChpdCdzIGB1bmRlZmluZWRgIG9uIHRoZSBzZXJ2ZXIgLyBpbiB3b3JrZXJzIHdpdGhvdXQgb25lKS5cbiAgY29uc3Qgb3JpZ2luID0gKGdsb2JhbFRoaXMgYXMgeyB3aW5kb3c/OiB7IGxvY2F0aW9uPzogeyBvcmlnaW4/OiBzdHJpbmcgfSB9IH0pLndpbmRvdz8ubG9jYXRpb25cbiAgICA/Lm9yaWdpbjtcbiAgaWYgKG9yaWdpbiAmJiBvcmlnaW4gIT09IFwibnVsbFwiKSB7XG4gICAgY29uc3Qgb3JpZ2luVXJsID0gcGFyc2VVcmwob3JpZ2luKTtcbiAgICBpZiAob3JpZ2luVXJsKSB7XG4gICAgICByZXR1cm4gb3JpZ2luVXJsO1xuICAgIH1cbiAgfVxuICByZXR1cm4gbmV3IFVSTChMT0NBTF9IT1NUX1VSTCk7XG59XG5cbmZ1bmN0aW9uIHBhcnNlVXJsKGlucHV0OiBzdHJpbmcpOiBVUkwgfCBudWxsIHtcbiAgaWYgKGlucHV0ICYmIGlucHV0LmluY2x1ZGVzKFVSTF9TQ0hFTUVfU0VQQVJBVE9SKSkge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gbmV3IFVSTChpbnB1dCk7XG4gICAgfSBjYXRjaCB7fVxuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG4vLyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbi8vIEVtYWlsIGFkZHJlc3Nlc1xuLy8g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKiBPcHRpb25zIGZvciB7QGxpbmsgcGFyc2VFbWFpbHN9LiAqL1xuZXhwb3J0IGludGVyZmFjZSBQYXJzZUVtYWlsc09wdGlvbnMge1xuICAvKiogTG93ZXItY2FzZSBldmVyeSBhZGRyZXNzICh1c2VmdWwgZm9yIGFsbG93LWxpc3RzIC8gbWF0Y2hpbmcpLiBPZmYgYnkgZGVmYXVsdC4gKi9cbiAgbG93ZXJjYXNlPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIERyb3AgbGF0ZXIgY2FzZS1pbnNlbnNpdGl2ZSBkdXBsaWNhdGVzLCBrZWVwaW5nIGZpcnN0LXNlZW4gY2FzaW5nLlxuICAgKiBPbiBieSBkZWZhdWx0IC0gYSByZWNpcGllbnQgb3IgcGF0dGVybiBsaXN0IHJhcmVseSB3YW50cyByZXBlYXRzLlxuICAgKi9cbiAgZGVkdXBlPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBOb3JtYWxpemUgdGhlIHNoYXBlcyBhbiBlbWFpbCBhZGRyZXNzIGZpZWxkIGFjY2VwdHMgLSBhIHNpbmdsZSBzdHJpbmcsXG4gKiBhIGNvbW1hIC8gc2VtaWNvbG9uIC8gd2hpdGVzcGFjZSBzZXBhcmF0ZWQgbGlzdCwgYW4gYXJyYXkgb2YgZWl0aGVyLFxuICogb3Igbm90aGluZyAtIGludG8gYSBjbGVhbiBgc3RyaW5nW11gLiBFYWNoIGVudHJ5IGlzIHNwbGl0IG9uIHRoZSBsaXN0XG4gKiBzZXBhcmF0b3JzLCB0cmltbWVkLCBhbmQgZGUtZW1wdGllZDsgYmxhbmtzIGFuZCBub24tc3RyaW5nIGFycmF5XG4gKiBtZW1iZXJzIGFyZSBkcm9wcGVkLiBCeSBkZWZhdWx0IGR1cGxpY2F0ZXMgYXJlIHJlbW92ZWRcbiAqIGNhc2UtaW5zZW5zaXRpdmVseSAoZmlyc3Qtc2VlbiBjYXNpbmcgd2lucykgYW5kIGNhc2luZyBpcyBvdGhlcndpc2VcbiAqIHByZXNlcnZlZDsgcGFzcyBgbG93ZXJjYXNlYCB0byBmb2xkIGV2ZXJ5dGhpbmcgdG8gbG93ZXIgY2FzZSAoZS5nLiBmb3JcbiAqIGFuIGFsbG93LWxpc3QpLiBUaGlzIGlzIHRoZSBvbmUgcGxhY2UgcmVjaXBpZW50IGxpc3RzLCBDQy9CQ0MgaW5wdXRzLFxuICogYW5kIHNlbmRlciBhbGxvdy1saXN0cyBhY3Jvc3MgdGhlIHJlcG8gYWdyZWUgb24gaG93IGZyZWUtdGV4dCBlbWFpbFxuICogaW5wdXQgaXMgcmVhZC4gTmV2ZXIgdGhyb3dzOyBkb2VzIG5vdCB2YWxpZGF0ZSAtIHBhaXIgd2l0aFxuICoge0BsaW5rIGlzRW1haWx9IHdoZW4geW91IG5lZWQgdG8gcmVqZWN0IG1hbGZvcm1lZCBhZGRyZXNzZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIHBhcnNlRW1haWxzKFwiYUB4LmNvbSwgYkB5LmNvbTsgYUB4LmNvbVwiKTsgLy8gW1wiYUB4LmNvbVwiLCBcImJAeS5jb21cIl1cbiAqIHBhcnNlRW1haWxzKFtcIkFAeC5jb21cIiwgXCIgYkB5LmNvbSBcIl0pOyAgICAgIC8vIFtcIkFAeC5jb21cIiwgXCJiQHkuY29tXCJdXG4gKiBwYXJzZUVtYWlscyhcIipAY29ycC5jb21cIiwgeyBsb3dlcmNhc2U6IHRydWUgfSk7IC8vIFtcIipAY29ycC5jb21cIl1cbiAqIHBhcnNlRW1haWxzKHVuZGVmaW5lZCk7ICAgICAgICAgICAgICAgICAgICAgLy8gW11cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlRW1haWxzKFxuICBpbnB1dDogc3RyaW5nIHwgcmVhZG9ubHkgc3RyaW5nW10gfCBudWxsIHwgdW5kZWZpbmVkLFxuICBvcHRpb25zOiBQYXJzZUVtYWlsc09wdGlvbnMgPSB7fSxcbik6IHN0cmluZ1tdIHtcbiAgaWYgKGlucHV0ID09PSBudWxsIHx8IGlucHV0ID09PSB1bmRlZmluZWQpIHJldHVybiBbXTtcbiAgY29uc3QgeyBsb3dlcmNhc2UgPSBmYWxzZSwgZGVkdXBlID0gdHJ1ZSB9ID0gb3B0aW9ucztcbiAgY29uc3QgZW50cmllcyA9IEFycmF5LmlzQXJyYXkoaW5wdXQpID8gaW5wdXQgOiBbaW5wdXQgYXMgc3RyaW5nXTtcbiAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCBvdXQ6IHN0cmluZ1tdID0gW107XG4gIGZvciAoY29uc3QgZW50cnkgb2YgZW50cmllcykge1xuICAgIGlmICh0eXBlb2YgZW50cnkgIT09IFwic3RyaW5nXCIpIGNvbnRpbnVlO1xuICAgIGZvciAoY29uc3QgdG9rZW4gb2YgZW50cnkuc3BsaXQoRU1BSUxfTElTVF9TRVBBUkFUT1IpKSB7XG4gICAgICBjb25zdCB0cmltbWVkID0gdG9rZW4udHJpbSgpO1xuICAgICAgaWYgKCF0cmltbWVkKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IGFkZHJlc3MgPSBsb3dlcmNhc2UgPyB0cmltbWVkLnRvTG93ZXJDYXNlKCkgOiB0cmltbWVkO1xuICAgICAgaWYgKGRlZHVwZSkge1xuICAgICAgICBjb25zdCBrZXkgPSBhZGRyZXNzLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIGlmIChzZWVuLmhhcyhrZXkpKSBjb250aW51ZTtcbiAgICAgICAgc2Vlbi5hZGQoa2V5KTtcbiAgICAgIH1cbiAgICAgIG91dC5wdXNoKGFkZHJlc3MpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gb3V0O1xufVxuXG4vKipcbiAqIFByYWdtYXRpYyBgbG9jYWxAZG9tYWluLnRsZGAgc2hhcGUgY2hlY2s6IG5vbi1lbXB0eSBsb2NhbCBhbmQgZG9tYWluXG4gKiBwYXJ0cyBhcm91bmQgYSBzaW5nbGUgYEBgLCB3aXRoIGEgZG90dGVkIGRvbWFpbiBhbmQgbm8gd2hpdGVzcGFjZS5cbiAqIERlbGliZXJhdGVseSBsb29zZSAobm90IGZ1bGwgUkZDIDUzMjIpIC0gZW5vdWdoIHRvIGNhdGNoIG9idmlvdXMgdHlwb3NcbiAqIGFuZCBnaXZlIENMSSAvIGZvcm0gZmVlZGJhY2ssIG5vdCB0byBnYXRlIGRlbGl2ZXJ5LiBUcmltcyBmaXJzdC4gVGhpc1xuICogaXMgYSBwdXJlbHkgc3ludGFjdGljIHRlc3QsIHNvIGEgd2lsZGNhcmQgYWxsb3ctbGlzdCBwYXR0ZXJuIGxpa2VcbiAqIGAqQGV4YW1wbGUuY29tYCBwYXNzZXM7IGRpc3Rpbmd1aXNoaW5nIGEgcGF0dGVybiBmcm9tIGEgcmVhbCBhZGRyZXNzXG4gKiBpcyB0aGUgc2VuZGVyIHBvbGljeSdzIGpvYiwgbm90IHRoaXMgdmFsaWRhdG9yJ3MuXG4gKlxuICogQGV4YW1wbGVcbiAqIGlzRW1haWwoXCJhbGljZUBleGFtcGxlLmNvbVwiKTsgLy8gdHJ1ZVxuICogaXNFbWFpbChcIm5vcGVcIik7ICAgICAgICAgICAgICAvLyBmYWxzZSAobm8gQClcbiAqIGlzRW1haWwoXCJub0Bkb21haW5cIik7ICAgICAgICAgLy8gZmFsc2UgKG5vIGRvdHRlZCBkb21haW4pXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0VtYWlsKHZhbHVlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIEVNQUlMX0FERFJFU1MudGVzdCh2YWx1ZS50cmltKCkpO1xufVxuXG4vLyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbi8vIElQIGFkZHJlc3NlcyBhbmQgQ0lEUiBibG9ja3Ncbi8vIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4vKipcbiAqIFBhcnNlIGFuIElQdjQgKGBcIjEuMi4zLjRcImApIG9yIElQdjYgKGBcIjIwMDE6ZGI4OjoxXCJgLFxuICogYFwiOjpmZmZmOjEuMi4zLjRcImAsIGBcIjo6MVwiYCkgYWRkcmVzcyBpbnRvIGEge0BsaW5rIFBhcnNlZElwfSwgb3JcbiAqIGBudWxsYCB3aGVuIHRoZSBpbnB1dCBpc24ndCBhIHZhbGlkIGxpdGVyYWwuIE5ldmVyIHRocm93cy4gU3Vycm91bmRpbmdcbiAqIHdoaXRlc3BhY2UsIGBbLi4uXWAgYnJhY2tldHMgYXJvdW5kIGFuIElQdjYgbGl0ZXJhbCwgYW5kIGFuIElQdjYgem9uZVxuICogaWQgKGBmZTgwOjoxJWV0aDBgKSBhcmUgYWxsIHRvbGVyYXRlZC4gVGhlIGB2YWx1ZWAgaXMgcmV0dXJuZWQgYXMgYVxuICogYGJpZ2ludGAgc28gdjQgYW5kIHY2IHNoYXJlIG9uZSBjb21wYXJpc29uIHBhdGguXG4gKlxuICogQGV4YW1wbGVcbiAqIHBhcnNlSXAoXCIxMC4wLjAuMVwiKTsgICAgICAgIC8vIHsgdmVyc2lvbjogNCwgdmFsdWU6IDE2Nzc3MjE2MW4gfVxuICogcGFyc2VJcChcIjIwMDE6ZGI4OjoxXCIpOyAgICAgLy8geyB2ZXJzaW9uOiA2LCB2YWx1ZTogLi4uIH1cbiAqIHBhcnNlSXAoXCJub3QtYW4taXBcIik7ICAgICAgIC8vIG51bGxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlSXAoaW5wdXQ6IHN0cmluZyk6IFBhcnNlZElwIHwgbnVsbCB7XG4gIGxldCB0ZXh0ID0gaW5wdXQudHJpbSgpO1xuICBpZiAodGV4dC5zdGFydHNXaXRoKFwiW1wiKSAmJiB0ZXh0LmVuZHNXaXRoKFwiXVwiKSkgdGV4dCA9IHRleHQuc2xpY2UoMSwgLTEpO1xuICBpZiAodGV4dC5pbmNsdWRlcyhcIjpcIikpIHtcbiAgICAvLyBEcm9wIGFuIElQdjYgem9uZSBpZCAoYGZlODA6OjElZXRoMGApIC0gaXQgaXNuJ3QgcGFydCBvZiB0aGUgYWRkcmVzcy5cbiAgICBjb25zdCB6b25lID0gdGV4dC5pbmRleE9mKFwiJVwiKTtcbiAgICBpZiAoem9uZSA+PSAwKSB0ZXh0ID0gdGV4dC5zbGljZSgwLCB6b25lKTtcbiAgICBjb25zdCB2YWx1ZSA9IHBhcnNlSXB2Nih0ZXh0KTtcbiAgICByZXR1cm4gdmFsdWUgPT09IG51bGwgPyBudWxsIDogeyB2ZXJzaW9uOiA2LCB2YWx1ZSB9O1xuICB9XG4gIGNvbnN0IHZhbHVlID0gcGFyc2VJcHY0KHRleHQpO1xuICByZXR1cm4gdmFsdWUgPT09IG51bGwgPyBudWxsIDogeyB2ZXJzaW9uOiA0LCB2YWx1ZSB9O1xufVxuXG4vKipcbiAqIFBhcnNlIGEgQ0lEUiBibG9jayAoYFwiMTAuMC4wLjAvOFwiYCwgYFwiMjAwMTpkYjg6Oi8zMlwiYCkgaW50byBhXG4gKiB7QGxpbmsgQ2lkcn0gd2l0aCBob3N0IGJpdHMgY2xlYXJlZCBmcm9tIGBiYXNlYCwgb3IgYG51bGxgIHdoZW4gdGhlXG4gKiBpbnB1dCBpc24ndCBhIHZhbGlkIGJsb2NrIChiYWQgYWRkcmVzcywgbWlzc2luZyAvIG91dC1vZi1yYW5nZVxuICogcHJlZml4KS4gTmV2ZXIgdGhyb3dzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBwYXJzZUNpZHIoXCIxMC4wLjAuMC84XCIpPy5iYXNlOyAgIC8vIDE2Nzc3MjE2MG4gKDEwLjAuMC4wKVxuICogcGFyc2VDaWRyKFwiMTAuMS4yLjMvOFwiKT8uYmFzZTsgICAvLyAxNjc3NzIxNjBuIChob3N0IGJpdHMgZHJvcHBlZClcbiAqIHBhcnNlQ2lkcihcIjEwLjAuMC4wLzQwXCIpOyAgICAgICAgLy8gbnVsbCAocHJlZml4ID4gMzIgZm9yIHY0KVxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VDaWRyKGlucHV0OiBzdHJpbmcpOiBDaWRyIHwgbnVsbCB7XG4gIGNvbnN0IHRleHQgPSBpbnB1dC50cmltKCk7XG4gIGNvbnN0IHNsYXNoID0gdGV4dC5sYXN0SW5kZXhPZihcIi9cIik7XG4gIGlmIChzbGFzaCA8IDApIHJldHVybiBudWxsO1xuICBjb25zdCBwcmVmaXhUZXh0ID0gdGV4dC5zbGljZShzbGFzaCArIDEpO1xuICBpZiAoIUlQVjRfT0NURVQudGVzdChwcmVmaXhUZXh0KSkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IGlwID0gcGFyc2VJcCh0ZXh0LnNsaWNlKDAsIHNsYXNoKSk7XG4gIGlmICghaXApIHJldHVybiBudWxsO1xuICBjb25zdCBwcmVmaXggPSBOdW1iZXIocHJlZml4VGV4dCk7XG4gIGNvbnN0IGJpdHMgPSBJUF9CSVRTW2lwLnZlcnNpb25dO1xuICBpZiAocHJlZml4ID4gYml0cykgcmV0dXJuIG51bGw7XG4gIGNvbnN0IGJhc2UgPSBpcC52YWx1ZSAmIG5ldHdvcmtNYXNrKGJpdHMsIHByZWZpeCk7XG4gIHJldHVybiB7XG4gICAgdmVyc2lvbjogaXAudmVyc2lvbixcbiAgICBiYXNlLFxuICAgIHByZWZpeCxcbiAgICBjaWRyOiBgJHt0ZXh0LnNsaWNlKDAsIHNsYXNoKX0vJHtwcmVmaXh9YCxcbiAgfTtcbn1cblxuLyoqXG4gKiBUZXN0IHdoZXRoZXIgYGlwYCBmYWxscyBpbnNpZGUgYGNpZHJgLiBCb3RoIGFyZ3VtZW50cyBhY2NlcHQgZWl0aGVyXG4gKiBhIHN0cmluZyAocGFyc2VkIG9uIHRoZSBmbHkgdmlhIHtAbGluayBwYXJzZUlwfSAvIHtAbGluayBwYXJzZUNpZHJ9KVxuICogb3IgYW4gYWxyZWFkeS1wYXJzZWQgdmFsdWUgLSBwYXNzIHBhcnNlZCB2YWx1ZXMgaW4gaG90IGxvb3BzIHRvIHNraXBcbiAqIHJlLXBhcnNpbmcuIFJldHVybnMgYGZhbHNlYCBmb3IgdW5wYXJzZWFibGUgaW5wdXQgb3IgYSB2ZXJzaW9uXG4gKiBtaXNtYXRjaCAoYW4gSVB2NCBhZGRyZXNzIGlzIG5ldmVyIGluc2lkZSBhbiBJUHY2IGJsb2NrKS5cbiAqXG4gKiBAZXhhbXBsZVxuICogaXBJbkNpZHIoXCIxMC4xLjIuM1wiLCBcIjEwLjAuMC4wLzhcIik7ICAgLy8gdHJ1ZVxuICogaXBJbkNpZHIoXCIxMS4wLjAuMVwiLCBcIjEwLjAuMC4wLzhcIik7ICAgLy8gZmFsc2VcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlwSW5DaWRyKGlwOiBzdHJpbmcgfCBQYXJzZWRJcCwgY2lkcjogc3RyaW5nIHwgQ2lkcik6IGJvb2xlYW4ge1xuICBjb25zdCBwYXJzZWRJcCA9IHR5cGVvZiBpcCA9PT0gXCJzdHJpbmdcIiA/IHBhcnNlSXAoaXApIDogaXA7XG4gIGNvbnN0IHBhcnNlZENpZHIgPSB0eXBlb2YgY2lkciA9PT0gXCJzdHJpbmdcIiA/IHBhcnNlQ2lkcihjaWRyKSA6IGNpZHI7XG4gIGlmICghcGFyc2VkSXAgfHwgIXBhcnNlZENpZHIgfHwgcGFyc2VkSXAudmVyc2lvbiAhPT0gcGFyc2VkQ2lkci52ZXJzaW9uKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGNvbnN0IG1hc2sgPSBuZXR3b3JrTWFzayhJUF9CSVRTW3BhcnNlZENpZHIudmVyc2lvbl0sIHBhcnNlZENpZHIucHJlZml4KTtcbiAgcmV0dXJuIChwYXJzZWRJcC52YWx1ZSAmIG1hc2spID09PSBwYXJzZWRDaWRyLmJhc2U7XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBmaXJzdCBDSURSIGluIGBjaWRyc2AgdGhhdCBjb250YWlucyBgaXBgLCBvciBgbnVsbGAgd2hlblxuICogbm9uZSBtYXRjaC4gYGNpZHJzYCBob2xkcyBwcmUtcGFyc2VkIHtAbGluayBDaWRyfSB2YWx1ZXMgKG9yIGFueVxuICogb2JqZWN0IGV4dGVuZGluZyBpdCksIHNvIGNhbGxlcnMgY2FuIGNhcnJ5IHNpZGUgbWV0YWRhdGEgb24gZWFjaFxuICogZW50cnkgKGUuZy4gYSByZWdpb24gdGFnKSBhbmQgcmVhZCBpdCBzdHJhaWdodCBvZmYgdGhlIHJldHVybmVkXG4gKiBtYXRjaC4gTGluZWFyIHNjYW47IHBhcnNlIHRoZSBhZGRyZXNzIG9uY2UgYnkgcGFzc2luZyBhXG4gKiB7QGxpbmsgUGFyc2VkSXB9LlxuICpcbiAqIEBleGFtcGxlXG4gKiBjb25zdCByYW5nZXMgPSBbXCIxMC4wLjAuMC84XCIsIFwiMTkyLjE2OC4wLjAvMTZcIl1cbiAqICAgLm1hcChwYXJzZUNpZHIpXG4gKiAgIC5maWx0ZXIoKGMpOiBjIGlzIENpZHIgPT4gYyAhPT0gbnVsbCk7XG4gKiBmaW5kQ29udGFpbmluZ0NpZHIoXCIxMC4xLjIuM1wiLCByYW5nZXMpPy5jaWRyOyAvLyBcIjEwLjAuMC4wLzhcIlxuICovXG5leHBvcnQgZnVuY3Rpb24gZmluZENvbnRhaW5pbmdDaWRyPFQgZXh0ZW5kcyBDaWRyPihcbiAgaXA6IHN0cmluZyB8IFBhcnNlZElwLFxuICBjaWRyczogSXRlcmFibGU8VD4sXG4pOiBUIHwgbnVsbCB7XG4gIGNvbnN0IHBhcnNlZElwID0gdHlwZW9mIGlwID09PSBcInN0cmluZ1wiID8gcGFyc2VJcChpcCkgOiBpcDtcbiAgaWYgKCFwYXJzZWRJcCkgcmV0dXJuIG51bGw7XG4gIGZvciAoY29uc3QgY2lkciBvZiBjaWRycykge1xuICAgIGlmIChjaWRyLnZlcnNpb24gIT09IHBhcnNlZElwLnZlcnNpb24pIGNvbnRpbnVlO1xuICAgIGNvbnN0IG1hc2sgPSBuZXR3b3JrTWFzayhJUF9CSVRTW2NpZHIudmVyc2lvbl0sIGNpZHIucHJlZml4KTtcbiAgICBpZiAoKHBhcnNlZElwLnZhbHVlICYgbWFzaykgPT09IGNpZHIuYmFzZSkgcmV0dXJuIGNpZHI7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogV2hldGhlciBgaW5wdXRgJ3MgaG9zdCBpcyBhIGxvb3BiYWNrIGFkZHJlc3MgLSBgbG9jYWxob3N0YCwgYW4gSVB2NFxuICogYDEyNy4wLjAuMC84YCBhZGRyZXNzLCBvciBJUHY2IGA6OjFgIC0gaS5lLiBhIHNlcnZpY2UgcnVubmluZyBvbiB0aGlzXG4gKiBtYWNoaW5lIChlLmcuIGEgbG9jYWwgcmVnaXN0cnkpLiBBY2NlcHRzIGFueXRoaW5nIHtAbGluayB1cmxCdWlsZGVyfVxuICogY29lcmNlcyAoYSBVUkwgc3RyaW5nLCBgVVJMYCwgb3IgYHsgdXJsIH1gKTsgcmV0dXJucyBgZmFsc2VgIHdoZW4gdGhlXG4gKiBpbnB1dCBoYXMgbm8gcmVzb2x2YWJsZSBob3N0LlxuICpcbiAqIEBleGFtcGxlXG4gKiBpc0xvb3BiYWNrSG9zdChcImh0dHA6Ly9sb2NhbGhvc3Q6NDg3M1wiKTsgLy8gdHJ1ZVxuICogaXNMb29wYmFja0hvc3QoXCJodHRwOi8vMTI3LjAuMC4xXCIpOyAgICAgICAvLyB0cnVlXG4gKiBpc0xvb3BiYWNrSG9zdChcImh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnXCIpOyAvLyBmYWxzZVxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNMb29wYmFja0hvc3QoaW5wdXQ6IFVybExpa2UpOiBib29sZWFuIHtcbiAgY29uc3QgaG9zdCA9IHVybEJ1aWxkZXIoaW5wdXQpPy5ob3N0bmFtZTtcbiAgaWYgKCFob3N0KSByZXR1cm4gZmFsc2U7XG4gIGlmIChob3N0ID09PSBcImxvY2FsaG9zdFwiKSByZXR1cm4gdHJ1ZTtcbiAgLy8gYFVSTGAgYnJhY2tldHMgYW4gSVB2NiBob3N0IChgWzo6MV1gKTsgc3RyaXAgdGhlbSBiZWZvcmUgcGFyc2luZy5cbiAgY29uc3QgaXAgPSBob3N0LnJlcGxhY2UoL15cXFt8XFxdJC9nLCBcIlwiKTtcbiAgcmV0dXJuIGlwSW5DaWRyKGlwLCBcIjEyNy4wLjAuMC84XCIpIHx8IGlwSW5DaWRyKGlwLCBcIjo6MS8xMjhcIik7XG59XG5cbi8qKlxuICogTmV0d29yayBtYXNrIGZvciBgcHJlZml4YCBsZWFkaW5nIGJpdHMgb2YgYSBgYml0c2Atd2lkZSBhZGRyZXNzIGFzIGFcbiAqIGBiaWdpbnRgOiB0aGUgdG9wIGBwcmVmaXhgIGJpdHMgc2V0LCB0aGUgbG93IGhvc3QgYml0cyBjbGVhcmVkLlxuICogYHByZWZpeCA9PT0gMGAgeWllbGRzIGAwbmAgKG1hdGNoZXMgZXZlcnl0aGluZyk7IGBwcmVmaXggPT09IGJpdHNgXG4gKiB5aWVsZHMgdGhlIGFsbC1vbmVzIG1hc2sgKG1hdGNoZXMgYSBzaW5nbGUgYWRkcmVzcykuXG4gKi9cbmZ1bmN0aW9uIG5ldHdvcmtNYXNrKGJpdHM6IG51bWJlciwgcHJlZml4OiBudW1iZXIpOiBiaWdpbnQge1xuICBjb25zdCBob3N0Qml0cyA9IEJpZ0ludChiaXRzIC0gcHJlZml4KTtcbiAgY29uc3QgZnVsbCA9ICgxbiA8PCBCaWdJbnQoYml0cykpIC0gMW47XG4gIHJldHVybiBmdWxsIF4gKCgxbiA8PCBob3N0Qml0cykgLSAxbik7XG59XG5cbi8qKiBQYXJzZSBhIGRvdHRlZC1xdWFkIElQdjQgbGl0ZXJhbCBpbnRvIGEgMzItYml0IHZhbHVlLCBlbHNlIGBudWxsYC4gKi9cbmZ1bmN0aW9uIHBhcnNlSXB2NChpbnB1dDogc3RyaW5nKTogYmlnaW50IHwgbnVsbCB7XG4gIGNvbnN0IHBhcnRzID0gaW5wdXQuc3BsaXQoXCIuXCIpO1xuICBpZiAocGFydHMubGVuZ3RoICE9PSA0KSByZXR1cm4gbnVsbDtcbiAgbGV0IHZhbHVlID0gMG47XG4gIGZvciAoY29uc3QgcGFydCBvZiBwYXJ0cykge1xuICAgIGlmICghSVBWNF9PQ1RFVC50ZXN0KHBhcnQpKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCBvY3RldCA9IE51bWJlcihwYXJ0KTtcbiAgICBpZiAob2N0ZXQgPiAyNTUpIHJldHVybiBudWxsO1xuICAgIHZhbHVlID0gKHZhbHVlIDw8IDhuKSB8IEJpZ0ludChvY3RldCk7XG4gIH1cbiAgcmV0dXJuIHZhbHVlO1xufVxuXG4vKipcbiAqIFBhcnNlIGFuIElQdjYgbGl0ZXJhbCBpbnRvIGEgMTI4LWJpdCB2YWx1ZSwgZWxzZSBgbnVsbGAuIEhhbmRsZXMgYDo6YFxuICogemVyby1jb21wcmVzc2lvbiAoYXQgbW9zdCBvbmNlKSBhbmQgYSB0cmFpbGluZyBlbWJlZGRlZCBJUHY0IGdyb3VwXG4gKiAoYDo6ZmZmZjoxLjIuMy40YCkuIFRoZSB6b25lIGlkLCBpZiBhbnksIGlzIGV4cGVjdGVkIHRvIGJlIHN0cmlwcGVkXG4gKiBieSB7QGxpbmsgcGFyc2VJcH0gYmVmb3JlIHRoaXMgaXMgY2FsbGVkLlxuICovXG5mdW5jdGlvbiBwYXJzZUlwdjYoaW5wdXQ6IHN0cmluZyk6IGJpZ2ludCB8IG51bGwge1xuICBjb25zdCBoYWx2ZXMgPSBpbnB1dC5zcGxpdChcIjo6XCIpO1xuICBpZiAoaGFsdmVzLmxlbmd0aCA+IDIpIHJldHVybiBudWxsO1xuXG4gIGNvbnN0IGhlYWQgPSBwYXJzZUhleHRldHMoaGFsdmVzWzBdISk7XG4gIGlmIChoZWFkID09PSBudWxsKSByZXR1cm4gbnVsbDtcblxuICBpZiAoaGFsdmVzLmxlbmd0aCA9PT0gMikge1xuICAgIGNvbnN0IHRhaWwgPSBwYXJzZUhleHRldHMoaGFsdmVzWzFdISk7XG4gICAgaWYgKHRhaWwgPT09IG51bGwpIHJldHVybiBudWxsO1xuICAgIC8vIFwiOjpcIiBtdXN0IHN0YW5kIGluIGZvciBhdCBsZWFzdCBvbmUgYWxsLXplcm8gaGV4dGV0LlxuICAgIGNvbnN0IG1pc3NpbmcgPSA4IC0gaGVhZC5sZW5ndGggLSB0YWlsLmxlbmd0aDtcbiAgICBpZiAobWlzc2luZyA8IDEpIHJldHVybiBudWxsO1xuICAgIHJldHVybiBoZXh0ZXRzVG9WYWx1ZShbLi4uaGVhZCwgLi4uQXJyYXkobWlzc2luZykuZmlsbCgwKSwgLi4udGFpbF0pO1xuICB9XG5cbiAgaWYgKGhlYWQubGVuZ3RoICE9PSA4KSByZXR1cm4gbnVsbDtcbiAgcmV0dXJuIGhleHRldHNUb1ZhbHVlKGhlYWQpO1xufVxuXG4vKipcbiAqIFBhcnNlIG9uZSBjb2xvbi1zZXBhcmF0ZWQgcnVuIG9mIElQdjYgaGV4dGV0cywgZXhwYW5kaW5nIGEgdHJhaWxpbmdcbiAqIGVtYmVkZGVkIElQdjQgZ3JvdXAgaW50byBpdHMgdHdvIGhleHRldHMuIEFuIGVtcHR5IHN0cmluZyB5aWVsZHMgYW5cbiAqIGVtcHR5IGxpc3QgKHRoZSBzaWRlIG9mIGEgbGVhZGluZyAvIHRyYWlsaW5nIGA6OmApLlxuICovXG5mdW5jdGlvbiBwYXJzZUhleHRldHMocGFydDogc3RyaW5nKTogbnVtYmVyW10gfCBudWxsIHtcbiAgaWYgKHBhcnQgPT09IFwiXCIpIHJldHVybiBbXTtcbiAgY29uc3QgdG9rZW5zID0gcGFydC5zcGxpdChcIjpcIik7XG4gIGNvbnN0IGhleHRldHM6IG51bWJlcltdID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdG9rZW5zLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgdG9rZW4gPSB0b2tlbnNbaV0hO1xuICAgIGlmICh0b2tlbi5pbmNsdWRlcyhcIi5cIikpIHtcbiAgICAgIC8vIEEgZG90dGVkLXF1YWQgaXMgb25seSBsZWdhbCBhcyB0aGUgZmluYWwgZ3JvdXAuXG4gICAgICBpZiAoaSAhPT0gdG9rZW5zLmxlbmd0aCAtIDEpIHJldHVybiBudWxsO1xuICAgICAgY29uc3QgdjQgPSBwYXJzZUlwdjQodG9rZW4pO1xuICAgICAgaWYgKHY0ID09PSBudWxsKSByZXR1cm4gbnVsbDtcbiAgICAgIGhleHRldHMucHVzaChOdW1iZXIoKHY0ID4+IDE2bikgJiAweGZmZmZuKSwgTnVtYmVyKHY0ICYgMHhmZmZmbikpO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoIUlQVjZfSEVYVEVULnRlc3QodG9rZW4pKSByZXR1cm4gbnVsbDtcbiAgICAgIGhleHRldHMucHVzaChwYXJzZUludCh0b2tlbiwgMTYpKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGhleHRldHM7XG59XG5cbi8qKiBGb2xkIGV4YWN0bHkgOCBoZXh0ZXRzIGludG8gYSBzaW5nbGUgMTI4LWJpdCBgYmlnaW50YCwgZWxzZSBgbnVsbGAuICovXG5mdW5jdGlvbiBoZXh0ZXRzVG9WYWx1ZShoZXh0ZXRzOiBudW1iZXJbXSk6IGJpZ2ludCB8IG51bGwge1xuICBpZiAoaGV4dGV0cy5sZW5ndGggIT09IDgpIHJldHVybiBudWxsO1xuICBsZXQgdmFsdWUgPSAwbjtcbiAgZm9yIChjb25zdCBoZXh0ZXQgb2YgaGV4dGV0cykgdmFsdWUgPSAodmFsdWUgPDwgMTZuKSB8IEJpZ0ludChoZXh0ZXQpO1xuICByZXR1cm4gdmFsdWU7XG59XG4iXX0=