@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/index.d.ts +36 -0
- package/lib/index.js +30 -0
- package/lib/src/async.d.ts +152 -0
- package/lib/src/async.js +163 -0
- package/lib/src/brand.d.ts +94 -0
- package/lib/src/brand.js +123 -0
- package/lib/src/error.d.ts +76 -0
- package/lib/src/error.js +168 -0
- package/lib/src/function.d.ts +38 -0
- package/lib/src/function.js +44 -0
- package/lib/src/hash.d.ts +102 -0
- package/lib/src/hash.js +274 -0
- package/lib/src/http.d.ts +79 -0
- package/lib/src/http.js +189 -0
- package/lib/src/json.d.ts +48 -0
- package/lib/src/json.js +49 -0
- package/lib/src/log.d.ts +86 -0
- package/lib/src/log.js +352 -0
- package/lib/src/net.d.ts +246 -0
- package/lib/src/net.js +465 -0
- package/lib/src/object.d.ts +382 -0
- package/lib/src/object.js +749 -0
- package/lib/src/predicate.d.ts +81 -0
- package/lib/src/predicate.js +43 -0
- package/lib/src/string.d.ts +221 -0
- package/lib/src/string.js +509 -0
- package/lib/src/token.d.ts +30 -0
- package/lib/src/token.js +126 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/package.json +9 -5
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=
|