sliftutils 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,530 @@
1
+ "use strict";
2
+ /// <reference path="./node-forge-ed25519.d.ts" />
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || function (mod) {
20
+ if (mod && mod.__esModule) return mod;
21
+ var result = {};
22
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
+ __setModuleDefault(result, mod);
24
+ return result;
25
+ };
26
+ var __importDefault = (this && this.__importDefault) || function (mod) {
27
+ return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
28
+ };
29
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
30
+ exports.getOwnNodeIdAllowUndefined = exports.getOwnNodeId = exports.createTestBrowserKeyCert = exports.getThreadKeyCert = exports.verifyMachineIdForPublicKey = exports.getOwnMachineId = exports.getIdentityCAPromise = exports.getIdentityCA = exports.loadIdentityCA = exports.setIdentityCARaw = exports.encodeNodeId = exports.decodeNodeIdAssert = exports.decodeNodeId = exports.getMachineId = exports.createCertFromCA = exports.generateTestCA = exports.generateRSAKeyPair = exports.generateKeyPair = exports.validateCertificate = exports.validateCACert = exports.verify = exports.sign = exports.getPublicIdentifier = exports.parseCert = exports.privateKeyToPem = exports.createX509 = exports.getCommonName = exports.identityStorageKey = exports.CA_NOT_FOUND_ERROR = void 0;
31
+ module.allowclient = true;
32
+ // https://www.rfc-editor.org/rfc/rfc5280#page-42
33
+ const compileFlags_1 = require("socket-function/require/compileFlags");
34
+ const forge = __importStar(require("node-forge"));
35
+ const caching_1 = require("socket-function/src/caching");
36
+ const misc_1 = require("socket-function/src/misc");
37
+ const js_sha256_1 = __importDefault(require("js-sha256"));
38
+ const crypto_1 = __importDefault(require("crypto"));
39
+ const certStore_1 = require("socket-function/src/certStore");
40
+ const measure_1 = require("socket-function/src/profiling/measure");
41
+ const nodeCache_1 = require("socket-function/src/nodeCache");
42
+ const SocketFunction_1 = require("socket-function/SocketFunction");
43
+ const nodeCache_2 = require("socket-function/src/nodeCache");
44
+ const persistentLocalStorage_1 = require("./persistentLocalStorage");
45
+ (0, compileFlags_1.setFlag)(require, "node-forge", "allowclient", true);
46
+ (0, compileFlags_1.setFlag)(require, "js-sha256", "allowclient", true);
47
+ const timeInDay = 1000 * 60 * 60 * 24;
48
+ exports.CA_NOT_FOUND_ERROR = "18aa7318-f88f-4d2d-b41f-3daf4a433827";
49
+ exports.identityStorageKey = "machineCA_10";
50
+ function getIdentityStore(domain) {
51
+ return (0, persistentLocalStorage_1.getKeyStore)(domain, exports.identityStorageKey);
52
+ }
53
+ function getCommonName(cert) {
54
+ let subject = new crypto_1.default.X509Certificate(cert).subject;
55
+ let subjectKVPs = new Map(subject.split(",").map(x => x.trim().split("=")).map(x => [x[0], x.slice(1).join("=")]));
56
+ let commonName = subjectKVPs.get("CN");
57
+ if (!commonName)
58
+ throw new Error(`No common name in subject: ${subject}`);
59
+ return commonName;
60
+ }
61
+ exports.getCommonName = getCommonName;
62
+ function createX509(config) {
63
+ return (0, measure_1.measureBlock)(function createX509() {
64
+ let { domain, issuer, lifeSpan, keyPair } = config;
65
+ let certObj = forge.pki.createCertificate();
66
+ certObj.publicKey = keyPair.publicKey;
67
+ certObj.serialNumber = "01";
68
+ // Give it 5 minutes before now. If we give it too much time, it can look like the cert is really
69
+ // old, which will trigger various processes to try to get a fresher one (as if it lasts for
70
+ // 1 hour, but we set notBefore to 1 month ago, it looks 1 month old, and so almost expired,
71
+ // when it isn't...)
72
+ certObj.validity.notBefore = new Date(Date.now() - 1000 * 60 * 5);
73
+ certObj.validity.notAfter = new Date(Date.now() + lifeSpan);
74
+ const commonNameAttrs = [{ name: "commonName", value: domain }];
75
+ certObj.setSubject(commonNameAttrs);
76
+ if (issuer === "self") {
77
+ certObj.setIssuer(commonNameAttrs);
78
+ }
79
+ else {
80
+ certObj.setIssuer(forge.pki.certificateFromPem(issuer.cert.toString()).subject.attributes);
81
+ }
82
+ let extensions = [];
83
+ const isCA = issuer === "self";
84
+ if (isCA) {
85
+ extensions.push({ name: "basicConstraints", cA: true });
86
+ }
87
+ let localHostDomain = "127-0-0-1." + domain.split(".").slice(-2).join(".");
88
+ extensions.push(...[
89
+ { name: "keyUsage", keyCertSign: isCA, digitalSignature: true, nonRepudiation: true, keyEncipherment: true, dataEncipherment: true },
90
+ { name: "subjectKeyIdentifier" },
91
+ {
92
+ name: "subjectAltName",
93
+ altNames: [
94
+ { type: 2, value: domain },
95
+ { type: 2, value: "*." + domain },
96
+ { type: 2, value: localHostDomain },
97
+ // NOTE: No longer allow 127.0.0.1, to make this more secure. We might enable this
98
+ // behavior behind a flag, for development.
99
+ //{ type: 7, ip: "127.0.0.1" }
100
+ ]
101
+ },
102
+ // NOTE: nameConstraints are supported with our branch. But... chrome doesn't support them, so there's no point in using them.
103
+ // "node-forge": "https://github.com/sliftist/forge#e618181b469b07bdc70b968b0391beb8ef5fecd6",
104
+ // {
105
+ // name: "nameConstraints",
106
+ // permittedSubtrees: [
107
+ // // Chrome doesn't respect nameConstraints per https://bugs.chromium.org/p/chromium/issues/detail?id=1072083,
108
+ // // as the spec decided that "free to process or ignore such information" (when present in self
109
+ // // signed certificates), and therefore the chrome implementation decided "The first order is to behave predictably",
110
+ // // so... they're not going to support it, because why have a feature in one place, if it isn't
111
+ // // on android as well... ugh...
112
+ // // Works fine on Edge though
113
+ // { type: 2, value: forge.util.encodeUtf8(domain) },
114
+ // { type: 2, value: forge.util.encodeUtf8(localHostDomain) },
115
+ // ]
116
+ // },
117
+ ]);
118
+ certObj.setExtensions(extensions);
119
+ (0, measure_1.measureBlock)(function sign() {
120
+ if (issuer === "self") {
121
+ certObj.sign(keyPair.privateKey, forge.md.sha256.create());
122
+ }
123
+ else {
124
+ certObj.sign(privateKeyFromPem(issuer.key.toString()), forge.md.sha256.create());
125
+ }
126
+ });
127
+ return (0, measure_1.measureBlock)(function toPems() {
128
+ return {
129
+ domain,
130
+ cert: Buffer.from(forge.pki.certificateToPem(certObj)),
131
+ key: Buffer.from(privateKeyToPem(keyPair.privateKey)),
132
+ };
133
+ });
134
+ });
135
+ }
136
+ exports.createX509 = createX509;
137
+ function privateKeyToPem(buffer) {
138
+ if ("privateKeyBytes" in buffer) {
139
+ return forge.ed25519.privateKeyToPem(buffer);
140
+ }
141
+ return forge.pki.privateKeyToPem(buffer);
142
+ }
143
+ exports.privateKeyToPem = privateKeyToPem;
144
+ function privateKeyFromPem(pem) {
145
+ // We want to guess the type correctly, as caught exceptions make debugging annoying
146
+ if (pem.length < 200) {
147
+ try {
148
+ return forge.ed25519.privateKeyFromPem(pem);
149
+ }
150
+ catch (_a) { }
151
+ }
152
+ try {
153
+ return forge.pki.privateKeyFromPem(pem);
154
+ }
155
+ catch (_b) {
156
+ return forge.ed25519.privateKeyFromPem(pem);
157
+ }
158
+ }
159
+ function publicKeyFromCert(cert) {
160
+ return parseCert(cert).publicKey;
161
+ }
162
+ function parseCert(PEMorDER) {
163
+ return forge.pki.certificateFromPem(normalizeCertToPEM(PEMorDER));
164
+ }
165
+ exports.parseCert = parseCert;
166
+ // Gets a unique value to represent the public key
167
+ function getPublicIdentifier(PEMorDER) {
168
+ let obj = parseCert(PEMorDER);
169
+ let publicKey = obj.publicKey;
170
+ if ("publicKeyBytes" in publicKey) {
171
+ return Buffer.from(publicKey.publicKeyBytes);
172
+ }
173
+ return Buffer.from(new Uint32Array(publicKey.n.data).buffer);
174
+ }
175
+ exports.getPublicIdentifier = getPublicIdentifier;
176
+ function isED25519(key) {
177
+ return key.length < 256;
178
+ }
179
+ // EQUIVALENT TO: `crypto.createSign("SHA256").update(JSON.stringify(payload)).sign(keyCert.key, "binary")`
180
+ exports.sign = (0, measure_1.measureWrap)(function sign(keyPair, data) {
181
+ let dataStr = JSON.stringify(data);
182
+ if (isED25519(keyPair.key)) {
183
+ let privateKey = forge.pki.ed25519.privateKeyFromPem(keyPair.key.toString());
184
+ return privateKey.sign(dataStr);
185
+ }
186
+ else {
187
+ let privateKey = forge.pki.privateKeyFromPem(keyPair.key.toString());
188
+ const md = forge.md.sha256.create();
189
+ md.update(dataStr);
190
+ return privateKey.sign(md);
191
+ }
192
+ });
193
+ function verify(cert, signature, data) {
194
+ let certObj = parseCert(cert);
195
+ return certObj.publicKey.verify(JSON.stringify(data), signature);
196
+ }
197
+ exports.verify = verify;
198
+ function normalizeCertToPEM(PEMorDER) {
199
+ if (PEMorDER.toString().startsWith("-----BEGIN CERTIFICATE-----")) {
200
+ return PEMorDER.toString();
201
+ }
202
+ PEMorDER = PEMorDER.toString("base64");
203
+ return "-----BEGIN CERTIFICATE-----\n" + PEMorDER + "\n-----END CERTIFICATE-----";
204
+ }
205
+ function getDomainPartFromPublicKey(publicKey) {
206
+ let bytes;
207
+ if ("publicKeyBytes" in publicKey) {
208
+ bytes = publicKey.publicKeyBytes;
209
+ }
210
+ else if (publicKey instanceof Buffer) {
211
+ bytes = publicKey;
212
+ }
213
+ else {
214
+ bytes = Buffer.from(new Uint32Array(publicKey.n.data).buffer);
215
+ }
216
+ return "b" + js_sha256_1.default.sha256(Buffer.from(bytes)).slice(0, 16).replaceAll("+", "-").replaceAll("/", "_");
217
+ }
218
+ function validateCACert(domain, cert) {
219
+ let certParsed = parseCert(cert);
220
+ let subject = certParsed.subject.getField("CN").value;
221
+ let localhostDomain = "127-0-0-1." + subject.split(".").slice(-2).join(".");
222
+ let domainParts = subject.split(".").reverse();
223
+ let rootDomainParsed = [domainParts.shift(), domainParts.shift()].reverse().join(".");
224
+ if (rootDomainParsed !== domain) {
225
+ // This is important, as our trust store contains more then just OUR certificates,
226
+ // so if we allow any domains then real domains can impersonate anyone! It has to
227
+ // be one OUR domain to be trusted!
228
+ throw new Error(`Certificate root domain should be ${domain}, but is ${rootDomainParsed}`);
229
+ }
230
+ // TODO: Maybe just skip if it isn't a hash string?
231
+ if (domainParts[0] === "noproxy") {
232
+ domainParts.shift();
233
+ }
234
+ let certExpectedPublicKeyPart = (domainParts.shift() || "").split("-").slice(-1)[0];
235
+ let certActualPublicKeyPart = getDomainPartFromPublicKey(certParsed.publicKey);
236
+ if (certExpectedPublicKeyPart !== certActualPublicKeyPart) {
237
+ throw new Error(`Certificate public key in the url is ${certExpectedPublicKeyPart}, but in the cert is ${certActualPublicKeyPart}`);
238
+ }
239
+ // ALSO, require name constraints to be present, and to restrict to the "CN"
240
+ let nameConstraints = certParsed.getExtension("nameConstraints");
241
+ if (!nameConstraints) {
242
+ throw new Error(`Certificate must have nameConstraints`);
243
+ }
244
+ let subtrees = nameConstraints.permittedSubtrees;
245
+ if (!subtrees) {
246
+ throw new Error(`Certificate must have nameConstraints.permittedSubtrees`);
247
+ }
248
+ let subtreeValues = subtrees.map((x) => x.value);
249
+ // Ignore localhostDomain, as it can always safely be allowed (the same machine
250
+ // is always allowed).
251
+ subtreeValues = subtreeValues.filter((x) => x !== localhostDomain);
252
+ if (subtreeValues.length !== 1 || subtreeValues[0] !== subject) {
253
+ throw new Error(`Certificate must have a single constrained domain (had ${JSON.stringify(subtreeValues)})`);
254
+ }
255
+ validateAltNames(certParsed, subject);
256
+ }
257
+ exports.validateCACert = validateCACert;
258
+ function validateCertificate(domain, cert, issuerCert) {
259
+ validateCACert(domain, issuerCert);
260
+ let certParsed = parseCert(cert);
261
+ let subject = certParsed.subject.getField("CN").value;
262
+ let localhostDomain = "127-0-0-1." + subject.split(".").slice(-2).join(".");
263
+ let domainParts = subject.split(".").reverse();
264
+ let rootDomainParsed = [domainParts.shift(), domainParts.shift()].reverse().join(".");
265
+ if (rootDomainParsed !== domain) {
266
+ throw new Error(`Certificate root domain should be ${domain}, but is ${rootDomainParsed}`);
267
+ }
268
+ // TODO: Maybe just skip if it isn't a hash string?
269
+ if (domainParts[0] === "noproxy") {
270
+ domainParts.shift();
271
+ }
272
+ let issuerCertParsed = parseCert(issuerCert);
273
+ let issuerExpectedPublicKeyPart = domainParts.shift() || "";
274
+ let issuerActualPublicKeyPart = getDomainPartFromPublicKey(issuerCertParsed.publicKey);
275
+ if (issuerExpectedPublicKeyPart !== issuerActualPublicKeyPart) {
276
+ throw new Error(`Issuer public key in the url is ${issuerExpectedPublicKeyPart}, but in the cert is ${issuerActualPublicKeyPart}`);
277
+ }
278
+ // Take the last part
279
+ let certExpectedPublicKeyPart = domainParts.shift() || "";
280
+ let certActualPublicKeyPart = getDomainPartFromPublicKey(certParsed.publicKey);
281
+ if (certExpectedPublicKeyPart !== certActualPublicKeyPart) {
282
+ throw new Error(`Certificate public key in the url is ${certExpectedPublicKeyPart}, but in the cert is ${certActualPublicKeyPart}`);
283
+ }
284
+ let nameConstraints = issuerCertParsed.getExtension("nameConstraints");
285
+ if (!nameConstraints) {
286
+ throw new Error(`CA must have nameConstraints`);
287
+ }
288
+ let subtrees = nameConstraints.permittedSubtrees;
289
+ if (!subtrees) {
290
+ throw new Error(`CA must have nameConstraints.permittedSubtrees`);
291
+ }
292
+ let subtreeValues = subtrees.map((x) => x.value);
293
+ // Ignore localhostDomain, as it can always safely be allowed (the same machine
294
+ // is always allowed).
295
+ subtreeValues = subtreeValues.filter((x) => x !== localhostDomain);
296
+ if (subtreeValues.length !== 1) {
297
+ throw new Error(`CA must have a single constrained domain (had ${JSON.stringify(subtreeValues)})`);
298
+ }
299
+ let subtree = subtreeValues[0];
300
+ if (subtree !== subject && !subject.endsWith("." + subtree)) {
301
+ throw new Error(`Certificate must be a subtree of the CA (CA: ${subtree}, cert: ${subject})`);
302
+ }
303
+ validateAltNames(certParsed, subject);
304
+ // Verify issuer ACTUALLY signed certParsed
305
+ if (!issuerCertParsed.verify(certParsed)) {
306
+ throw new Error(`Issuer did not sign certificate`);
307
+ }
308
+ }
309
+ exports.validateCertificate = validateCertificate;
310
+ // Require alt names to be either equal to "CN", or a subtree of "CN"
311
+ function validateAltNames(certParsed, subject) {
312
+ let localhostDomain = "127-0-0-1." + subject.split(".").slice(-2).join(".");
313
+ let altNamesObj = certParsed.getExtension("subjectAltName");
314
+ let altNames = altNamesObj === null || altNamesObj === void 0 ? void 0 : altNamesObj.altNames.map((x) => x.value);
315
+ // Allow localhostDomain, as it can always safely be allowed
316
+ altNames = altNames.filter((x) => x !== localhostDomain);
317
+ if (altNames.some((x) => !(x === subject
318
+ || x.endsWith("." + subject)
319
+ // Commented out, because... it is so easy to publish a 127.0.0.1 A record,
320
+ // and even to generate a real cert, so, we should jsut do that, and keep it secure.
321
+ // If we need this for development we can put it behind a flag, so non-development
322
+ // instances are still secure.
323
+ // // Also allow 127.0.0.1, for local testing, for now?
324
+ // // - This might be insecure if these are trusted by the browser,
325
+ // // as then anyone that stores any cookies in this ip can have
326
+ // // the cookies stolen. But... if this is just cross-server...
327
+ // // I don't see how this could cause a security vulnerability.
328
+ // || x === Buffer.from([127, 0, 0, 1]).toString()
329
+ ))) {
330
+ throw new Error(`Invalid alt names. Must be subtrees of the subject (CN) ${JSON.stringify(subject)}, was ${JSON.stringify(altNames)}`);
331
+ }
332
+ }
333
+ function generateKeyPair() {
334
+ return (0, measure_1.measureBlock)(function generateKeyPair() {
335
+ // NOTE: We use ED25519 because it can generated keys about 10X faster, WHICH, is still slow
336
+ // (~6ms on my machine). So we DEFINITELY don't want it to be 10X slower!
337
+ // NOTE: ED25519 doens't have great support in browsers, but we shouldn't need self signed certificates
338
+ // in the browser anyway.
339
+ // - https://security.stackexchange.com/a/236943/282367
340
+ //let keyPair = forge.ed25519.generateKeyPair();
341
+ let keyPair = forge.pki.rsa.generateKeyPair();
342
+ return keyPair;
343
+ });
344
+ }
345
+ exports.generateKeyPair = generateKeyPair;
346
+ function generateRSAKeyPair() {
347
+ return (0, measure_1.measureBlock)(function generateKeyPair() {
348
+ return forge.pki.rsa.generateKeyPair();
349
+ });
350
+ }
351
+ exports.generateRSAKeyPair = generateRSAKeyPair;
352
+ function generateTestCA(domain) {
353
+ const keyPair = generateKeyPair();
354
+ let caPublicKeyPart = getDomainPartFromPublicKey(keyPair.publicKey);
355
+ let fullDomain = `${caPublicKeyPart}.${domain}`;
356
+ if (!(0, misc_1.isNode)()) {
357
+ fullDomain = `${caPublicKeyPart}.${domain}`;
358
+ }
359
+ return createX509({ domain: fullDomain, issuer: "self", keyPair, lifeSpan: timeInDay * 365 * 20 });
360
+ }
361
+ exports.generateTestCA = generateTestCA;
362
+ let identityCA = (0, caching_1.cache)((domain) => {
363
+ let identityCA = (0, caching_1.lazy)((async () => {
364
+ let identityCACached = getIdentityStore(domain);
365
+ let caCached = await identityCACached.get();
366
+ if (!caCached) {
367
+ console.log(`Generating new identity CA`);
368
+ const keyPair = generateKeyPair();
369
+ let caPublicKeyPart = getDomainPartFromPublicKey(keyPair.publicKey);
370
+ let fullDomain = `${caPublicKeyPart}.${domain}`;
371
+ if (!(0, misc_1.isNode)()) {
372
+ fullDomain = `${caPublicKeyPart}.${domain}`;
373
+ }
374
+ let value = createX509({ domain: fullDomain, issuer: "self", keyPair, lifeSpan: timeInDay * 365 * 20 });
375
+ caCached = {
376
+ domain: value.domain,
377
+ certB64: value.cert.toString("base64"),
378
+ keyB64: value.key.toString("base64"),
379
+ };
380
+ await identityCACached.set(caCached);
381
+ }
382
+ let result = {
383
+ domain: caCached.domain,
384
+ cert: Buffer.from(caCached.certB64, "base64"),
385
+ key: Buffer.from(caCached.keyB64, "base64"),
386
+ };
387
+ (0, certStore_1.trustCertificate)(result.cert.toString());
388
+ identityCA.set(result);
389
+ return result;
390
+ }));
391
+ return identityCA;
392
+ });
393
+ // IMPORTANT! We do not embed any debug info in this domain. If we did, it would be useful,
394
+ // but... potentally a security vulnerability, as if the debug info (such as a prefix)
395
+ // is used to identify what a certificate is for, it would be easy for an attack to
396
+ // forge this (as the debug info won't be secured). So it is much better to keep
397
+ // the certificate opaque, and then require any metadata to be actually vetted
398
+ // (and hopefully stored in a UI, showing IP, time, etc).
399
+ function createCertFromCA(config) {
400
+ return (0, measure_1.measureBlock)(function createCertFromCA() {
401
+ let { CAKeyPair } = config;
402
+ const keyPair = generateKeyPair();
403
+ let domainKeyPart = getDomainPartFromPublicKey(keyPair.publicKey);
404
+ let fullDomain = `${domainKeyPart}.${config.CAKeyPair.domain}`;
405
+ return createX509({
406
+ domain: fullDomain,
407
+ issuer: CAKeyPair,
408
+ keyPair,
409
+ lifeSpan: timeInDay * 365 * 10,
410
+ });
411
+ });
412
+ }
413
+ exports.createCertFromCA = createCertFromCA;
414
+ function getMachineId(domainName) {
415
+ return domainName.split(".").slice(-3).join(".");
416
+ }
417
+ exports.getMachineId = getMachineId;
418
+ function decodeNodeId(nodeId) {
419
+ let locationObj = (0, nodeCache_1.getNodeIdLocation)(nodeId);
420
+ if (!locationObj) {
421
+ return undefined;
422
+ }
423
+ let parts = locationObj.address.split(".");
424
+ if (nodeId.startsWith("127-0-0-1.") && parts.length === 3) {
425
+ return {
426
+ threadId: "",
427
+ machineId: parts.at(-3) || "",
428
+ domain: parts.slice(-2).join("."),
429
+ port: locationObj.port,
430
+ };
431
+ }
432
+ if (parts.length < 4) {
433
+ return undefined;
434
+ }
435
+ return {
436
+ threadId: parts.at(-4) || "",
437
+ machineId: parts.at(-3) || "",
438
+ domain: parts.slice(-2).join(".") || "",
439
+ port: locationObj.port,
440
+ };
441
+ }
442
+ exports.decodeNodeId = decodeNodeId;
443
+ function decodeNodeIdAssert(nodeId) {
444
+ let result = decodeNodeId(nodeId);
445
+ if (!result) {
446
+ throw new Error(`Invalid nodeId: ${nodeId}`);
447
+ }
448
+ return result;
449
+ }
450
+ exports.decodeNodeIdAssert = decodeNodeIdAssert;
451
+ function encodeNodeId(parts) {
452
+ return `${parts.threadId}.${parts.machineId}.${parts.domain}:${parts.port}`;
453
+ }
454
+ exports.encodeNodeId = encodeNodeId;
455
+ async function setIdentityCARaw(domain, json) {
456
+ let identityCACached = getIdentityStore(domain);
457
+ let obj = JSON.parse(json);
458
+ let ca = {
459
+ domain: obj.domain,
460
+ cert: Buffer.from(obj.certB64, "base64"),
461
+ key: Buffer.from(obj.keyB64, "base64"),
462
+ };
463
+ (0, certStore_1.trustCertificate)(ca.cert.toString());
464
+ identityCA(domain).set(ca);
465
+ getThreadKeyCertBase(domain).reset();
466
+ await identityCACached.set(obj);
467
+ (0, nodeCache_2.resetAllNodeCallFactories)();
468
+ }
469
+ exports.setIdentityCARaw = setIdentityCARaw;
470
+ async function loadIdentityCA(domain) {
471
+ await identityCA(domain)();
472
+ }
473
+ exports.loadIdentityCA = loadIdentityCA;
474
+ function getIdentityCA(domain) {
475
+ let value = identityCA(domain)();
476
+ if (value instanceof Promise) {
477
+ throw new Error("Identity CA is not yet loaded. Call and wait for loadIdentityCA() in your startup before accessing the identity (or call getIdentityCAPromise())");
478
+ }
479
+ return value;
480
+ }
481
+ exports.getIdentityCA = getIdentityCA;
482
+ // TODO: Replace this with a database, so it is easy for us to trust CAs
483
+ // cross machine, and even have multiple users, etc, etc.
484
+ function getIdentityCAPromise(domain) {
485
+ return identityCA(domain)();
486
+ }
487
+ exports.getIdentityCAPromise = getIdentityCAPromise;
488
+ function getOwnMachineId(domain) {
489
+ return getMachineId(getIdentityCA(domain).domain);
490
+ }
491
+ exports.getOwnMachineId = getOwnMachineId;
492
+ /** Part of the machineId comes from the publicKey, so we can use it to verify */
493
+ function verifyMachineIdForPublicKey(config) {
494
+ let { machineId, publicKey } = config;
495
+ let domainPart = getDomainPartFromPublicKey(publicKey);
496
+ return machineId.split(".").at(-3) === domainPart;
497
+ }
498
+ exports.verifyMachineIdForPublicKey = verifyMachineIdForPublicKey;
499
+ // NOTE: We don't have a cache per CA, as... the CA should be set first
500
+ // TODO: Maybe throw if they try to change the CA after they generate any certificates?
501
+ // TODO: Regenerate certificates after enough time (as thread certs should be relatively short lived,
502
+ // so it is plausible for them to expire)
503
+ // - We will also need to provide a callback so that users of the cert can update the cert they
504
+ // are using as well.
505
+ function getThreadKeyCert(domain) {
506
+ return getThreadKeyCertBase(domain)();
507
+ }
508
+ exports.getThreadKeyCert = getThreadKeyCert;
509
+ const getThreadKeyCertBase = (0, caching_1.cache)((domain) => (0, caching_1.lazy)(() => {
510
+ let ca = getIdentityCA(domain);
511
+ return createCertFromCA({ CAKeyPair: ca });
512
+ }));
513
+ exports.createTestBrowserKeyCert = (0, caching_1.lazy)(async () => {
514
+ let keyPair = generateRSAKeyPair();
515
+ return await createX509({ domain: "test", issuer: "self", keyPair, lifeSpan: timeInDay * 365 * 20 });
516
+ });
517
+ function getOwnNodeId() {
518
+ let nodeId = SocketFunction_1.SocketFunction.mountedNodeId;
519
+ if (!nodeId) {
520
+ throw new Error(`Node must be mounted before nodeId is accessed`);
521
+ }
522
+ return nodeId;
523
+ }
524
+ exports.getOwnNodeId = getOwnNodeId;
525
+ function getOwnNodeIdAllowUndefined() {
526
+ return SocketFunction_1.SocketFunction.mountedNodeId;
527
+ }
528
+ exports.getOwnNodeIdAllowUndefined = getOwnNodeIdAllowUndefined;
529
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjZXJ0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsa0RBQWtEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVsRCxNQUFNLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztBQUUxQixpREFBaUQ7QUFFakQsdUVBQStEO0FBQy9ELGtEQUFvQztBQUdwQyx5REFBMEQ7QUFDMUQsbURBQWtEO0FBQ2xELDBEQUErQjtBQUMvQixvREFBNEI7QUFDNUIsNkRBQWlFO0FBQ2pFLG1FQUE4RjtBQUM5Riw2REFBa0g7QUFFbEgsbUVBQWdFO0FBQ2hFLDZEQUEwRTtBQUMxRSxxRUFBdUQ7QUFFdkQsSUFBQSxzQkFBTyxFQUFDLE9BQU8sRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQ3BELElBQUEsc0JBQU8sRUFBQyxPQUFPLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxJQUFJLENBQUMsQ0FBQztBQUVuRCxNQUFNLFNBQVMsR0FBRyxJQUFJLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUM7QUFFekIsUUFBQSxrQkFBa0IsR0FBRyxzQ0FBc0MsQ0FBQztBQUU1RCxRQUFBLGtCQUFrQixHQUFHLGNBQWMsQ0FBQztBQUdqRCxTQUFTLGdCQUFnQixDQUFDLE1BQWM7SUFDcEMsT0FBTyxJQUFBLG9DQUFXLEVBQXNCLE1BQU0sRUFBRSwwQkFBa0IsQ0FBQyxDQUFDO0FBQ3hFLENBQUM7QUFJRCxTQUFnQixhQUFhLENBQUMsSUFBcUI7SUFDL0MsSUFBSSxPQUFPLEdBQUcsSUFBSSxnQkFBTSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUM7SUFDdkQsSUFBSSxXQUFXLEdBQUcsSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbkgsSUFBSSxVQUFVLEdBQUcsV0FBVyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN2QyxJQUFJLENBQUMsVUFBVTtRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDMUUsT0FBTyxVQUFVLENBQUM7QUFDdEIsQ0FBQztBQU5ELHNDQU1DO0FBRUQsU0FBZ0IsVUFBVSxDQUN0QixNQVFDO0lBRUQsT0FBTyxJQUFBLHNCQUFZLEVBQUMsU0FBUyxVQUFVO1FBQ25DLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsR0FBRyxNQUFNLENBQUM7UUFFbkQsSUFBSSxPQUFPLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQzVDLE9BQU8sQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQztRQUN0QyxPQUFPLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQztRQUM1QixpR0FBaUc7UUFDakcsNkZBQTZGO1FBQzdGLDZGQUE2RjtRQUM3RixxQkFBcUI7UUFDckIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxTQUFTLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDbEUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFFBQVEsQ0FBQyxDQUFDO1FBRTVELE1BQU0sZUFBZSxHQUFHLENBQUMsRUFBRSxJQUFJLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQ2hFLE9BQU8sQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLENBQUM7UUFFcEMsSUFBSSxNQUFNLEtBQUssTUFBTSxFQUFFLENBQUM7WUFDcEIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUN2QyxDQUFDO2FBQU0sQ0FBQztZQUNKLE9BQU8sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQy9GLENBQUM7UUFFRCxJQUFJLFVBQVUsR0FBRyxFQUFFLENBQUM7UUFDcEIsTUFBTSxJQUFJLEdBQUcsTUFBTSxLQUFLLE1BQU0sQ0FBQztRQUMvQixJQUFJLElBQUksRUFBRSxDQUFDO1lBQ1AsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxrQkFBa0IsRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUM1RCxDQUFDO1FBRUQsSUFBSSxlQUFlLEdBQUcsWUFBWSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRTNFLFVBQVUsQ0FBQyxJQUFJLENBQUMsR0FBRztZQUNmLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLElBQUksRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLGVBQWUsRUFBRSxJQUFJLEVBQUUsZ0JBQWdCLEVBQUUsSUFBSSxFQUFFO1lBQ3BJLEVBQUUsSUFBSSxFQUFFLHNCQUFzQixFQUFFO1lBQ2hDO2dCQUNJLElBQUksRUFBRSxnQkFBZ0I7Z0JBQ3RCLFFBQVEsRUFBRTtvQkFDTixFQUFFLElBQUksRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRTtvQkFDMUIsRUFBRSxJQUFJLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLEdBQUcsTUFBTSxFQUFFO29CQUNqQyxFQUFFLElBQUksRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLGVBQWUsRUFBRTtvQkFDbkMsa0ZBQWtGO29CQUNsRiw0Q0FBNEM7b0JBQzVDLDhCQUE4QjtpQkFDakM7YUFDSjtZQUNELDhIQUE4SDtZQUM5SCxtR0FBbUc7WUFDbkcsSUFBSTtZQUNKLCtCQUErQjtZQUMvQiwyQkFBMkI7WUFDM0IsdUhBQXVIO1lBQ3ZILDBHQUEwRztZQUMxRyxnSUFBZ0k7WUFDaEksMEdBQTBHO1lBQzFHLDJDQUEyQztZQUMzQyx1Q0FBdUM7WUFDdkMsNkRBQTZEO1lBQzdELHNFQUFzRTtZQUN0RSxRQUFRO1lBQ1IsS0FBSztTQUNSLENBQUMsQ0FBQztRQUNILE9BQU8sQ0FBQyxhQUFhLENBQUMsVUFBVSxDQUFDLENBQUM7UUFHbEMsSUFBQSxzQkFBWSxFQUFDLFNBQVMsSUFBSTtZQUN0QixJQUFJLE1BQU0sS0FBSyxNQUFNLEVBQUUsQ0FBQztnQkFDcEIsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBaUIsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBQ3RFLENBQUM7aUJBQU0sQ0FBQztnQkFDSixPQUFPLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLENBQVEsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBQzVGLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztRQUVILE9BQU8sSUFBQSxzQkFBWSxFQUFDLFNBQVMsTUFBTTtZQUMvQixPQUFPO2dCQUNILE1BQU07Z0JBQ04sSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDdEQsR0FBRyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQzthQUN4RCxDQUFDO1FBQ04sQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDLENBQUMsQ0FBQztBQUNQLENBQUM7QUExRkQsZ0NBMEZDO0FBQ0QsU0FBZ0IsZUFBZSxDQUFDLE1BQXNEO0lBQ2xGLElBQUksaUJBQWlCLElBQUksTUFBTSxFQUFFLENBQUM7UUFDOUIsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUM3QyxDQUFDO0FBTEQsMENBS0M7QUFDRCxTQUFTLGlCQUFpQixDQUFDLEdBQVc7SUFDbEMsb0ZBQW9GO0lBQ3BGLElBQUksR0FBRyxDQUFDLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQztRQUNuQixJQUFJLENBQUM7WUFDRCxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDaEQsQ0FBQztRQUFDLFdBQU0sQ0FBQyxDQUFDLENBQUM7SUFDZixDQUFDO0lBQ0QsSUFBSSxDQUFDO1FBQ0QsT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFBQyxXQUFNLENBQUM7UUFDTCxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDaEQsQ0FBQztBQUNMLENBQUM7QUFDRCxTQUFTLGlCQUFpQixDQUFDLElBQVk7SUFDbkMsT0FBTyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxDQUFDO0FBQ3JDLENBQUM7QUFDRCxTQUFnQixTQUFTLENBQUMsUUFBeUI7SUFDL0MsT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLGtCQUFrQixDQUFDLGtCQUFrQixDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7QUFDdEUsQ0FBQztBQUZELDhCQUVDO0FBRUQsa0RBQWtEO0FBQ2xELFNBQWdCLG1CQUFtQixDQUFDLFFBQXlCO0lBQ3pELElBQUksR0FBRyxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM5QixJQUFJLFNBQVMsR0FBRyxHQUFHLENBQUMsU0FBUyxDQUFDO0lBQzlCLElBQUksZ0JBQWdCLElBQUksU0FBUyxFQUFFLENBQUM7UUFDaEMsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFxQixDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLFdBQVcsQ0FBRSxTQUFpQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUMxRSxDQUFDO0FBUEQsa0RBT0M7QUFFRCxTQUFTLFNBQVMsQ0FBQyxHQUFvQjtJQUNuQyxPQUFPLEdBQUcsQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDO0FBQzVCLENBQUM7QUFFRCwyR0FBMkc7QUFDOUYsUUFBQSxJQUFJLEdBQUcsSUFBQSxxQkFBVyxFQUFDLFNBQVMsSUFBSSxDQUFDLE9BQWlDLEVBQUUsSUFBYTtJQUMxRixJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ25DLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ3pCLElBQUksVUFBVSxHQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsT0FBZSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUN0RixPQUFPLFVBQVUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDcEMsQ0FBQztTQUFNLENBQUM7UUFDSixJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUNyRSxNQUFNLEVBQUUsR0FBRyxLQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNwQyxFQUFFLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ25CLE9BQU8sVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMvQixDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUM7QUFFSCxTQUFnQixNQUFNLENBQUMsSUFBWSxFQUFFLFNBQWlCLEVBQUUsSUFBYTtJQUNqRSxJQUFJLE9BQU8sR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDOUIsT0FBUSxPQUFPLENBQUMsU0FBcUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQztBQUNsRyxDQUFDO0FBSEQsd0JBR0M7QUFFRCxTQUFTLGtCQUFrQixDQUFDLFFBQXlCO0lBQ2pELElBQUksUUFBUSxDQUFDLFFBQVEsRUFBRSxDQUFDLFVBQVUsQ0FBQyw2QkFBNkIsQ0FBQyxFQUFFLENBQUM7UUFDaEUsT0FBTyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDL0IsQ0FBQztJQUNELFFBQVEsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3ZDLE9BQU8sK0JBQStCLEdBQUcsUUFBUSxHQUFHLDZCQUE2QixDQUFDO0FBQ3RGLENBQUM7QUFFRCxTQUFTLDBCQUEwQixDQUFDLFNBQStFO0lBQy9HLElBQUksS0FBYSxDQUFDO0lBQ2xCLElBQUksZ0JBQWdCLElBQUksU0FBUyxFQUFFLENBQUM7UUFDaEMsS0FBSyxHQUFHLFNBQVMsQ0FBQyxjQUFjLENBQUM7SUFDckMsQ0FBQztTQUFNLElBQUksU0FBUyxZQUFZLE1BQU0sRUFBRSxDQUFDO1FBQ3JDLEtBQUssR0FBRyxTQUFTLENBQUM7SUFDdEIsQ0FBQztTQUFNLENBQUM7UUFDSixLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLFdBQVcsQ0FBRSxTQUFpQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBQ0QsT0FBTyxHQUFHLEdBQUcsbUJBQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBQzFHLENBQUM7QUFFRCxTQUFnQixjQUFjLENBQUMsTUFBYyxFQUFFLElBQXFCO0lBQ2hFLElBQUksVUFBVSxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUVqQyxJQUFJLE9BQU8sR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFlLENBQUM7SUFDaEUsSUFBSSxlQUFlLEdBQUcsWUFBWSxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRTVFLElBQUksV0FBVyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFFL0MsSUFBSSxnQkFBZ0IsR0FBRyxDQUFDLFdBQVcsQ0FBQyxLQUFLLEVBQUUsRUFBRSxXQUFXLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdEYsSUFBSSxnQkFBZ0IsS0FBSyxNQUFNLEVBQUUsQ0FBQztRQUM5QixrRkFBa0Y7UUFDbEYsa0ZBQWtGO1FBQ2xGLG9DQUFvQztRQUNwQyxNQUFNLElBQUksS0FBSyxDQUFDLHFDQUFxQyxNQUFNLFlBQVksZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDO0lBQy9GLENBQUM7SUFDRCxtREFBbUQ7SUFDbkQsSUFBSSxXQUFXLENBQUMsQ0FBQyxDQUFDLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDL0IsV0FBVyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFRCxJQUFJLHlCQUF5QixHQUFHLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNwRixJQUFJLHVCQUF1QixHQUFHLDBCQUEwQixDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUMvRSxJQUFJLHlCQUF5QixLQUFLLHVCQUF1QixFQUFFLENBQUM7UUFDeEQsTUFBTSxJQUFJLEtBQUssQ0FBQyx3Q0FBd0MseUJBQXlCLHdCQUF3Qix1QkFBdUIsRUFBRSxDQUFDLENBQUM7SUFDeEksQ0FBQztJQUVELDRFQUE0RTtJQUM1RSxJQUFJLGVBQWUsR0FBRyxVQUFVLENBQUMsWUFBWSxDQUFDLGlCQUFpQixDQUFRLENBQUM7SUFDeEUsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ25CLE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBQ0QsSUFBSSxRQUFRLEdBQUcsZUFBZSxDQUFDLGlCQUFpQixDQUFDO0lBQ2pELElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNaLE1BQU0sSUFBSSxLQUFLLENBQUMseURBQXlELENBQUMsQ0FBQztJQUMvRSxDQUFDO0lBQ0QsSUFBSSxhQUFhLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3RELCtFQUErRTtJQUMvRSwyQkFBMkI7SUFDM0IsYUFBYSxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFTLEVBQUUsRUFBRSxDQUFDLENBQUMsS0FBSyxlQUFlLENBQUMsQ0FBQztJQUMzRSxJQUFJLGFBQWEsQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLGFBQWEsQ0FBQyxDQUFDLENBQUMsS0FBSyxPQUFPLEVBQUUsQ0FBQztRQUM3RCxNQUFNLElBQUksS0FBSyxDQUFDLDBEQUEwRCxJQUFJLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNoSCxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBQzFDLENBQUM7QUE1Q0Qsd0NBNENDO0FBRUQsU0FBZ0IsbUJBQW1CLENBQUMsTUFBYyxFQUFFLElBQXFCLEVBQUUsVUFBMkI7SUFDbEcsY0FBYyxDQUFDLE1BQU0sRUFBRSxVQUFVLENBQUMsQ0FBQztJQUVuQyxJQUFJLFVBQVUsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDakMsSUFBSSxPQUFPLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBZSxDQUFDO0lBQ2hFLElBQUksZUFBZSxHQUFHLFlBQVksR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUU1RSxJQUFJLFdBQVcsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBRS9DLElBQUksZ0JBQWdCLEdBQUcsQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLEVBQUUsV0FBVyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3RGLElBQUksZ0JBQWdCLEtBQUssTUFBTSxFQUFFLENBQUM7UUFDOUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxxQ0FBcUMsTUFBTSxZQUFZLGdCQUFnQixFQUFFLENBQUMsQ0FBQztJQUMvRixDQUFDO0lBQ0QsbURBQW1EO0lBQ25ELElBQUksV0FBVyxDQUFDLENBQUMsQ0FBQyxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQy9CLFdBQVcsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUN4QixDQUFDO0lBRUQsSUFBSSxnQkFBZ0IsR0FBRyxTQUFTLENBQUMsVUFBVSxDQUFDLENBQUM7SUFFN0MsSUFBSSwyQkFBMkIsR0FBRyxXQUFXLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDO0lBQzVELElBQUkseUJBQXlCLEdBQUcsMEJBQTBCLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDdkYsSUFBSSwyQkFBMkIsS0FBSyx5QkFBeUIsRUFBRSxDQUFDO1FBQzVELE1BQU0sSUFBSSxLQUFLLENBQUMsbUNBQW1DLDJCQUEyQix3QkFBd0IseUJBQXlCLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZJLENBQUM7SUFFRCxxQkFBcUI7SUFDckIsSUFBSSx5QkFBeUIsR0FBRyxXQUFXLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDO0lBQzFELElBQUksdUJBQXVCLEdBQUcsMEJBQTBCLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQy9FLElBQUkseUJBQXlCLEtBQUssdUJBQXVCLEVBQUUsQ0FBQztRQUN4RCxNQUFNLElBQUksS0FBSyxDQUFDLHdDQUF3Qyx5QkFBeUIsd0JBQXdCLHVCQUF1QixFQUFFLENBQUMsQ0FBQztJQUN4SSxDQUFDO0lBR0QsSUFBSSxlQUFlLEdBQUcsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLGlCQUFpQixDQUFRLENBQUM7SUFDOUUsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ25CLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBQ0QsSUFBSSxRQUFRLEdBQUcsZUFBZSxDQUFDLGlCQUFpQixDQUFDO0lBQ2pELElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNaLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBQ0QsSUFBSSxhQUFhLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3RELCtFQUErRTtJQUMvRSwyQkFBMkI7SUFDM0IsYUFBYSxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFTLEVBQUUsRUFBRSxDQUFDLENBQUMsS0FBSyxlQUFlLENBQUMsQ0FBQztJQUMzRSxJQUFJLGFBQWEsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDN0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxpREFBaUQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdkcsQ0FBQztJQUVELElBQUksT0FBTyxHQUFHLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMvQixJQUFJLE9BQU8sS0FBSyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsR0FBRyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQzFELE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELE9BQU8sV0FBVyxPQUFPLEdBQUcsQ0FBQyxDQUFDO0lBQ2xHLENBQUM7SUFFRCxnQkFBZ0IsQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFFdEMsMkNBQTJDO0lBQzNDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUN2QyxNQUFNLElBQUksS0FBSyxDQUFDLGlDQUFpQyxDQUFDLENBQUM7SUFDdkQsQ0FBQztBQUNMLENBQUM7QUE3REQsa0RBNkRDO0FBRUQscUVBQXFFO0FBQ3JFLFNBQVMsZ0JBQWdCLENBQUMsVUFBaUMsRUFBRSxPQUFlO0lBQ3hFLElBQUksZUFBZSxHQUFHLFlBQVksR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUU1RSxJQUFJLFdBQVcsR0FBRyxVQUFVLENBQUMsWUFBWSxDQUFDLGdCQUFnQixDQUFRLENBQUM7SUFDbkUsSUFBSSxRQUFRLEdBQUcsV0FBVyxhQUFYLFdBQVcsdUJBQVgsV0FBVyxDQUFFLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM5RCw0REFBNEQ7SUFDNUQsUUFBUSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFTLEVBQUUsRUFBRSxDQUFDLENBQUMsS0FBSyxlQUFlLENBQUMsQ0FBQztJQUNqRSxJQUNJLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFTLEVBQUUsRUFBRSxDQUN4QixDQUFDLENBQ0csQ0FBQyxLQUFLLE9BQU87V0FDVixDQUFDLENBQUMsUUFBUSxDQUFDLEdBQUcsR0FBRyxPQUFPLENBQUM7SUFDNUIsMkVBQTJFO0lBQzNFLHFGQUFxRjtJQUNyRixtRkFBbUY7SUFDbkYsK0JBQStCO0lBQy9CLHVEQUF1RDtJQUN2RCxvRUFBb0U7SUFDcEUscUVBQXFFO0lBQ3JFLHFFQUFxRTtJQUNyRSxxRUFBcUU7SUFDckUsa0RBQWtEO0tBQ3JELENBQ0osRUFDSCxDQUFDO1FBQ0MsTUFBTSxJQUFJLEtBQUssQ0FBQywyREFBMkQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsU0FBUyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMzSSxDQUFDO0FBQ0wsQ0FBQztBQUdELFNBQWdCLGVBQWU7SUFDM0IsT0FBTyxJQUFBLHNCQUFZLEVBQUMsU0FBUyxlQUFlO1FBQ3hDLDRGQUE0RjtRQUM1RiwwRUFBMEU7UUFDMUUsdUdBQXVHO1FBQ3ZHLDBCQUEwQjtRQUMxQix3REFBd0Q7UUFDeEQsZ0RBQWdEO1FBQ2hELElBQUksT0FBTyxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQzlDLE9BQU8sT0FBTyxDQUFDO0lBQ25CLENBQUMsQ0FBQyxDQUFDO0FBQ1AsQ0FBQztBQVhELDBDQVdDO0FBQ0QsU0FBZ0Isa0JBQWtCO0lBQzlCLE9BQU8sSUFBQSxzQkFBWSxFQUFDLFNBQVMsZUFBZTtRQUN4QyxPQUFPLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQzNDLENBQUMsQ0FBQyxDQUFDO0FBQ1AsQ0FBQztBQUpELGdEQUlDO0FBRUQsU0FBZ0IsY0FBYyxDQUFDLE1BQWM7SUFDekMsTUFBTSxPQUFPLEdBQUcsZUFBZSxFQUFFLENBQUM7SUFDbEMsSUFBSSxlQUFlLEdBQUcsMEJBQTBCLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3BFLElBQUksVUFBVSxHQUFHLEdBQUcsZUFBZSxJQUFJLE1BQU0sRUFBRSxDQUFDO0lBQ2hELElBQUksQ0FBQyxJQUFBLGFBQU0sR0FBRSxFQUFFLENBQUM7UUFDWixVQUFVLEdBQUcsR0FBRyxlQUFlLElBQUksTUFBTSxFQUFFLENBQUM7SUFDaEQsQ0FBQztJQUVELE9BQU8sVUFBVSxDQUFDLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsU0FBUyxHQUFHLEdBQUcsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQ3ZHLENBQUM7QUFURCx3Q0FTQztBQUVELElBQUksVUFBVSxHQUFHLElBQUEsZUFBSyxFQUFDLENBQUMsTUFBYyxFQUFFLEVBQUU7SUFDdEMsSUFBSSxVQUFVLEdBQUcsSUFBQSxjQUFJLEVBQUMsQ0FBQyxLQUFLLElBQTBCLEVBQUU7UUFDcEQsSUFBSSxnQkFBZ0IsR0FBRyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNoRCxJQUFJLFFBQVEsR0FBRyxNQUFNLGdCQUFnQixDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQzVDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNaLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLENBQUMsQ0FBQztZQUMxQyxNQUFNLE9BQU8sR0FBRyxlQUFlLEVBQUUsQ0FBQztZQUNsQyxJQUFJLGVBQWUsR0FBRywwQkFBMEIsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDcEUsSUFBSSxVQUFVLEdBQUcsR0FBRyxlQUFlLElBQUksTUFBTSxFQUFFLENBQUM7WUFDaEQsSUFBSSxDQUFDLElBQUEsYUFBTSxHQUFFLEVBQUUsQ0FBQztnQkFDWixVQUFVLEdBQUcsR0FBRyxlQUFlLElBQUksTUFBTSxFQUFFLENBQUM7WUFDaEQsQ0FBQztZQUVELElBQUksS0FBSyxHQUFHLFVBQVUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLFNBQVMsR0FBRyxHQUFHLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUV4RyxRQUFRLEdBQUc7Z0JBQ1AsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNO2dCQUNwQixPQUFPLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDO2dCQUN0QyxNQUFNLEVBQUUsS0FBSyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDO2FBQ3ZDLENBQUM7WUFDRixNQUFNLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUN6QyxDQUFDO1FBQ0QsSUFBSSxNQUFNLEdBQUc7WUFDVCxNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU07WUFDdkIsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUM7WUFDN0MsR0FBRyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUM7U0FDOUMsQ0FBQztRQUNGLElBQUEsNEJBQWdCLEVBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBQ3pDLFVBQVUsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDdkIsT0FBTyxNQUFNLENBQUM7SUFDbEIsQ0FBQyxDQUFzQyxDQUFDLENBQUM7SUFDekMsT0FBTyxVQUFVLENBQUM7QUFDdEIsQ0FBQyxDQUFDLENBQUM7QUFFSCwyRkFBMkY7QUFDM0YsdUZBQXVGO0FBQ3ZGLG9GQUFvRjtBQUNwRixpRkFBaUY7QUFDakYsK0VBQStFO0FBQy9FLDBEQUEwRDtBQUMxRCxTQUFnQixnQkFBZ0IsQ0FBQyxNQUVoQztJQUNHLE9BQU8sSUFBQSxzQkFBWSxFQUFDLFNBQVMsZ0JBQWdCO1FBQ3pDLElBQUksRUFBRSxTQUFTLEVBQUUsR0FBRyxNQUFNLENBQUM7UUFDM0IsTUFBTSxPQUFPLEdBQUcsZUFBZSxFQUFFLENBQUM7UUFDbEMsSUFBSSxhQUFhLEdBQUcsMEJBQTBCLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ2xFLElBQUksVUFBVSxHQUFHLEdBQUcsYUFBYSxJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDL0QsT0FBTyxVQUFVLENBQUM7WUFDZCxNQUFNLEVBQUUsVUFBVTtZQUNsQixNQUFNLEVBQUUsU0FBUztZQUNqQixPQUFPO1lBQ1AsUUFBUSxFQUFFLFNBQVMsR0FBRyxHQUFHLEdBQUcsRUFBRTtTQUNqQyxDQUFDLENBQUM7SUFDUCxDQUFDLENBQUMsQ0FBQztBQUNQLENBQUM7QUFmRCw0Q0FlQztBQUVELFNBQWdCLFlBQVksQ0FBQyxVQUFrQjtJQUMzQyxPQUFPLFVBQVUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ3JELENBQUM7QUFGRCxvQ0FFQztBQVFELFNBQWdCLFlBQVksQ0FBQyxNQUFjO0lBQ3ZDLElBQUksV0FBVyxHQUFHLElBQUEsNkJBQWlCLEVBQUMsTUFBTSxDQUFDLENBQUM7SUFDNUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ2YsT0FBTyxTQUFTLENBQUM7SUFDckIsQ0FBQztJQUNELElBQUksS0FBSyxHQUFHLFdBQVcsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzNDLElBQUksTUFBTSxDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3hELE9BQU87WUFDSCxRQUFRLEVBQUUsRUFBRTtZQUNaLFNBQVMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRTtZQUM3QixNQUFNLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7WUFDakMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxJQUFJO1NBQ3pCLENBQUM7SUFDTixDQUFDO0lBQ0QsSUFBSSxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ25CLE9BQU8sU0FBUyxDQUFDO0lBQ3JCLENBQUM7SUFDRCxPQUFPO1FBQ0gsUUFBUSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFO1FBQzVCLFNBQVMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRTtRQUM3QixNQUFNLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFO1FBQ3ZDLElBQUksRUFBRSxXQUFXLENBQUMsSUFBSTtLQUN6QixDQUFDO0FBQ04sQ0FBQztBQXZCRCxvQ0F1QkM7QUFDRCxTQUFnQixrQkFBa0IsQ0FBQyxNQUFjO0lBQzdDLElBQUksTUFBTSxHQUFHLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNsQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDVixNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNsQixDQUFDO0FBTkQsZ0RBTUM7QUFDRCxTQUFnQixZQUFZLENBQUMsS0FBa0I7SUFDM0MsT0FBTyxHQUFHLEtBQUssQ0FBQyxRQUFRLElBQUksS0FBSyxDQUFDLFNBQVMsSUFBSSxLQUFLLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUNoRixDQUFDO0FBRkQsb0NBRUM7QUFFTSxLQUFLLFVBQVUsZ0JBQWdCLENBQUMsTUFBYyxFQUFFLElBQVk7SUFDL0QsSUFBSSxnQkFBZ0IsR0FBRyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNoRCxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FJeEIsQ0FBQztJQUNGLElBQUksRUFBRSxHQUFHO1FBQ0wsTUFBTSxFQUFFLEdBQUcsQ0FBQyxNQUFNO1FBQ2xCLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDO1FBQ3hDLEdBQUcsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDO0tBQ3pDLENBQUM7SUFDRixJQUFBLDRCQUFnQixFQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUNyQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzNCLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3JDLE1BQU0sZ0JBQWdCLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2hDLElBQUEscUNBQXlCLEdBQUUsQ0FBQztBQUNoQyxDQUFDO0FBakJELDRDQWlCQztBQUVNLEtBQUssVUFBVSxjQUFjLENBQUMsTUFBYztJQUMvQyxNQUFNLFVBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO0FBQy9CLENBQUM7QUFGRCx3Q0FFQztBQUNELFNBQWdCLGFBQWEsQ0FBQyxNQUFjO0lBQ3hDLElBQUksS0FBSyxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO0lBQ2pDLElBQUksS0FBSyxZQUFZLE9BQU8sRUFBRSxDQUFDO1FBQzNCLE1BQU0sSUFBSSxLQUFLLENBQUMsa0pBQWtKLENBQUMsQ0FBQztJQUN4SyxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDakIsQ0FBQztBQU5ELHNDQU1DO0FBRUQsd0VBQXdFO0FBQ3hFLDBEQUEwRDtBQUMxRCxTQUFnQixvQkFBb0IsQ0FBQyxNQUFjO0lBQy9DLE9BQU8sVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7QUFDaEMsQ0FBQztBQUZELG9EQUVDO0FBR0QsU0FBZ0IsZUFBZSxDQUFDLE1BQWM7SUFDMUMsT0FBTyxZQUFZLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQ3RELENBQUM7QUFGRCwwQ0FFQztBQUVELGlGQUFpRjtBQUNqRixTQUFnQiwyQkFBMkIsQ0FBQyxNQUczQztJQUNHLElBQUksRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLEdBQUcsTUFBTSxDQUFDO0lBQ3RDLElBQUksVUFBVSxHQUFHLDBCQUEwQixDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3ZELE9BQU8sU0FBUyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxVQUFVLENBQUM7QUFDdEQsQ0FBQztBQVBELGtFQU9DO0FBRUQsdUVBQXVFO0FBQ3ZFLHdGQUF3RjtBQUN4RixxR0FBcUc7QUFDckcsMENBQTBDO0FBQzFDLGdHQUFnRztBQUNoRywwQkFBMEI7QUFDMUIsU0FBZ0IsZ0JBQWdCLENBQUMsTUFBYztJQUMzQyxPQUFPLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7QUFDMUMsQ0FBQztBQUZELDRDQUVDO0FBQ0QsTUFBTSxvQkFBb0IsR0FBRyxJQUFBLGVBQUssRUFBQyxDQUFDLE1BQWMsRUFBRSxFQUFFLENBQUMsSUFBQSxjQUFJLEVBQUMsR0FBRyxFQUFFO0lBQzdELElBQUksRUFBRSxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUMvQixPQUFPLGdCQUFnQixDQUFDLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDL0MsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUVTLFFBQUEsd0JBQXdCLEdBQUcsSUFBQSxjQUFJLEVBQUMsS0FBSyxJQUFJLEVBQUU7SUFDcEQsSUFBSSxPQUFPLEdBQUcsa0JBQWtCLEVBQUUsQ0FBQztJQUNuQyxPQUFPLE1BQU0sVUFBVSxDQUFDLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsU0FBUyxHQUFHLEdBQUcsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0FBQ3pHLENBQUMsQ0FBQyxDQUFDO0FBRUgsU0FBZ0IsWUFBWTtJQUN4QixJQUFJLE1BQU0sR0FBRywrQkFBYyxDQUFDLGFBQWEsQ0FBQztJQUMxQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDVixNQUFNLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7SUFDdEUsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2xCLENBQUM7QUFORCxvQ0FNQztBQUVELFNBQWdCLDBCQUEwQjtJQUN0QyxPQUFPLCtCQUFjLENBQUMsYUFBYSxDQUFDO0FBQ3hDLENBQUM7QUFGRCxnRUFFQyIsInNvdXJjZXNDb250ZW50IjpbIi8vLyA8cmVmZXJlbmNlIHBhdGg9XCIuL25vZGUtZm9yZ2UtZWQyNTUxOS5kLnRzXCIgLz5cblxubW9kdWxlLmFsbG93Y2xpZW50ID0gdHJ1ZTtcblxuLy8gaHR0cHM6Ly93d3cucmZjLWVkaXRvci5vcmcvcmZjL3JmYzUyODAjcGFnZS00MlxuXG5pbXBvcnQgeyBzZXRGbGFnIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9yZXF1aXJlL2NvbXBpbGVGbGFnc1wiO1xuaW1wb3J0ICogYXMgZm9yZ2UgZnJvbSBcIm5vZGUtZm9yZ2VcIjtcbmltcG9ydCBvcyBmcm9tIFwib3NcIjtcbmltcG9ydCBmc1N5bmMgZnJvbSBcImZzXCI7XG5pbXBvcnQgeyBjYWNoZSwgbGF6eSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2NhY2hpbmdcIjtcbmltcG9ydCB7IGlzTm9kZSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL21pc2NcIjtcbmltcG9ydCBzaGEyNjUgZnJvbSBcImpzLXNoYTI1NlwiO1xuaW1wb3J0IGNyeXB0byBmcm9tIFwiY3J5cHRvXCI7XG5pbXBvcnQgeyB0cnVzdENlcnRpZmljYXRlIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvY2VydFN0b3JlXCI7XG5pbXBvcnQgeyBtZWFzdXJlQmxvY2ssIG1lYXN1cmVGbmMsIG1lYXN1cmVXcmFwIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvcHJvZmlsaW5nL21lYXN1cmVcIjtcbmltcG9ydCB7IGdldE5vZGVJZERvbWFpbiwgZ2V0Tm9kZUlkRG9tYWluTWF5YmVVbmRlZmluZWQsIGdldE5vZGVJZExvY2F0aW9uIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvbm9kZUNhY2hlXCI7XG5pbXBvcnQgeyBNYXliZVByb21pc2UgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy90eXBlc1wiO1xuaW1wb3J0IHsgU29ja2V0RnVuY3Rpb24gfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL1NvY2tldEZ1bmN0aW9uXCI7XG5pbXBvcnQgeyByZXNldEFsbE5vZGVDYWxsRmFjdG9yaWVzIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvbm9kZUNhY2hlXCI7XG5pbXBvcnQgeyBnZXRLZXlTdG9yZSB9IGZyb20gXCIuL3BlcnNpc3RlbnRMb2NhbFN0b3JhZ2VcIjtcblxuc2V0RmxhZyhyZXF1aXJlLCBcIm5vZGUtZm9yZ2VcIiwgXCJhbGxvd2NsaWVudFwiLCB0cnVlKTtcbnNldEZsYWcocmVxdWlyZSwgXCJqcy1zaGEyNTZcIiwgXCJhbGxvd2NsaWVudFwiLCB0cnVlKTtcblxuY29uc3QgdGltZUluRGF5ID0gMTAwMCAqIDYwICogNjAgKiAyNDtcblxuZXhwb3J0IGNvbnN0IENBX05PVF9GT1VORF9FUlJPUiA9IFwiMThhYTczMTgtZjg4Zi00ZDJkLWI0MWYtM2RhZjRhNDMzODI3XCI7XG5cbmV4cG9ydCBjb25zdCBpZGVudGl0eVN0b3JhZ2VLZXkgPSBcIm1hY2hpbmVDQV8xMFwiO1xuZXhwb3J0IHR5cGUgSWRlbnRpdHlTdG9yYWdlVHlwZSA9IHsgZG9tYWluOiBzdHJpbmc7IGNlcnRCNjQ6IHN0cmluZzsga2V5QjY0OiBzdHJpbmcgfTtcblxuZnVuY3Rpb24gZ2V0SWRlbnRpdHlTdG9yZShkb21haW46IHN0cmluZykge1xuICAgIHJldHVybiBnZXRLZXlTdG9yZTxJZGVudGl0eVN0b3JhZ2VUeXBlPihkb21haW4sIGlkZW50aXR5U3RvcmFnZUtleSk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgWDUwOUtleVBhaXIgeyBkb21haW46IHN0cmluZzsgY2VydDogQnVmZmVyOyBrZXk6IEJ1ZmZlcjsgfVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q29tbW9uTmFtZShjZXJ0OiBCdWZmZXIgfCBzdHJpbmcpIHtcbiAgICBsZXQgc3ViamVjdCA9IG5ldyBjcnlwdG8uWDUwOUNlcnRpZmljYXRlKGNlcnQpLnN1YmplY3Q7XG4gICAgbGV0IHN1YmplY3RLVlBzID0gbmV3IE1hcChzdWJqZWN0LnNwbGl0KFwiLFwiKS5tYXAoeCA9PiB4LnRyaW0oKS5zcGxpdChcIj1cIikpLm1hcCh4ID0+IFt4WzBdLCB4LnNsaWNlKDEpLmpvaW4oXCI9XCIpXSkpO1xuICAgIGxldCBjb21tb25OYW1lID0gc3ViamVjdEtWUHMuZ2V0KFwiQ05cIik7XG4gICAgaWYgKCFjb21tb25OYW1lKSB0aHJvdyBuZXcgRXJyb3IoYE5vIGNvbW1vbiBuYW1lIGluIHN1YmplY3Q6ICR7c3ViamVjdH1gKTtcbiAgICByZXR1cm4gY29tbW9uTmFtZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVg1MDkoXG4gICAgY29uZmlnOiB7XG4gICAgICAgIGRvbWFpbjogc3RyaW5nO1xuICAgICAgICBpc3N1ZXI6IFg1MDlLZXlQYWlyIHwgXCJzZWxmXCI7XG4gICAgICAgIGxpZmVTcGFuOiBudW1iZXI7XG4gICAgICAgIGtleVBhaXI6IHtcbiAgICAgICAgICAgIHB1YmxpY0tleTogZm9yZ2UuRWQyNTUxOVB1YmxpY0tleTtcbiAgICAgICAgICAgIHByaXZhdGVLZXk6IGZvcmdlLkVkMjU1MTlQcml2YXRlS2V5O1xuICAgICAgICB9IHwgZm9yZ2UucGtpLktleVBhaXI7XG4gICAgfVxuKTogWDUwOUtleVBhaXIge1xuICAgIHJldHVybiBtZWFzdXJlQmxvY2soZnVuY3Rpb24gY3JlYXRlWDUwOSgpIHtcbiAgICAgICAgbGV0IHsgZG9tYWluLCBpc3N1ZXIsIGxpZmVTcGFuLCBrZXlQYWlyIH0gPSBjb25maWc7XG5cbiAgICAgICAgbGV0IGNlcnRPYmogPSBmb3JnZS5wa2kuY3JlYXRlQ2VydGlmaWNhdGUoKTtcbiAgICAgICAgY2VydE9iai5wdWJsaWNLZXkgPSBrZXlQYWlyLnB1YmxpY0tleTtcbiAgICAgICAgY2VydE9iai5zZXJpYWxOdW1iZXIgPSBcIjAxXCI7XG4gICAgICAgIC8vIEdpdmUgaXQgNSBtaW51dGVzIGJlZm9yZSBub3cuIElmIHdlIGdpdmUgaXQgdG9vIG11Y2ggdGltZSwgaXQgY2FuIGxvb2sgbGlrZSB0aGUgY2VydCBpcyByZWFsbHlcbiAgICAgICAgLy8gIG9sZCwgd2hpY2ggd2lsbCB0cmlnZ2VyIHZhcmlvdXMgcHJvY2Vzc2VzIHRvIHRyeSB0byBnZXQgYSBmcmVzaGVyIG9uZSAoYXMgaWYgaXQgbGFzdHMgZm9yXG4gICAgICAgIC8vICAxIGhvdXIsIGJ1dCB3ZSBzZXQgbm90QmVmb3JlIHRvIDEgbW9udGggYWdvLCBpdCBsb29rcyAxIG1vbnRoIG9sZCwgYW5kIHNvIGFsbW9zdCBleHBpcmVkLFxuICAgICAgICAvLyAgd2hlbiBpdCBpc24ndC4uLilcbiAgICAgICAgY2VydE9iai52YWxpZGl0eS5ub3RCZWZvcmUgPSBuZXcgRGF0ZShEYXRlLm5vdygpIC0gMTAwMCAqIDYwICogNSk7XG4gICAgICAgIGNlcnRPYmoudmFsaWRpdHkubm90QWZ0ZXIgPSBuZXcgRGF0ZShEYXRlLm5vdygpICsgbGlmZVNwYW4pO1xuXG4gICAgICAgIGNvbnN0IGNvbW1vbk5hbWVBdHRycyA9IFt7IG5hbWU6IFwiY29tbW9uTmFtZVwiLCB2YWx1ZTogZG9tYWluIH1dO1xuICAgICAgICBjZXJ0T2JqLnNldFN1YmplY3QoY29tbW9uTmFtZUF0dHJzKTtcblxuICAgICAgICBpZiAoaXNzdWVyID09PSBcInNlbGZcIikge1xuICAgICAgICAgICAgY2VydE9iai5zZXRJc3N1ZXIoY29tbW9uTmFtZUF0dHJzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNlcnRPYmouc2V0SXNzdWVyKGZvcmdlLnBraS5jZXJ0aWZpY2F0ZUZyb21QZW0oaXNzdWVyLmNlcnQudG9TdHJpbmcoKSkuc3ViamVjdC5hdHRyaWJ1dGVzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBleHRlbnNpb25zID0gW107XG4gICAgICAgIGNvbnN0IGlzQ0EgPSBpc3N1ZXIgPT09IFwic2VsZlwiO1xuICAgICAgICBpZiAoaXNDQSkge1xuICAgICAgICAgICAgZXh0ZW5zaW9ucy5wdXNoKHsgbmFtZTogXCJiYXNpY0NvbnN0cmFpbnRzXCIsIGNBOiB0cnVlIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGxvY2FsSG9zdERvbWFpbiA9IFwiMTI3LTAtMC0xLlwiICsgZG9tYWluLnNwbGl0KFwiLlwiKS5zbGljZSgtMikuam9pbihcIi5cIik7XG5cbiAgICAgICAgZXh0ZW5zaW9ucy5wdXNoKC4uLltcbiAgICAgICAgICAgIHsgbmFtZTogXCJrZXlVc2FnZVwiLCBrZXlDZXJ0U2lnbjogaXNDQSwgZGlnaXRhbFNpZ25hdHVyZTogdHJ1ZSwgbm9uUmVwdWRpYXRpb246IHRydWUsIGtleUVuY2lwaGVybWVudDogdHJ1ZSwgZGF0YUVuY2lwaGVybWVudDogdHJ1ZSB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcInN1YmplY3RLZXlJZGVudGlmaWVyXCIgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcInN1YmplY3RBbHROYW1lXCIsXG4gICAgICAgICAgICAgICAgYWx0TmFtZXM6IFtcbiAgICAgICAgICAgICAgICAgICAgeyB0eXBlOiAyLCB2YWx1ZTogZG9tYWluIH0sXG4gICAgICAgICAgICAgICAgICAgIHsgdHlwZTogMiwgdmFsdWU6IFwiKi5cIiArIGRvbWFpbiB9LFxuICAgICAgICAgICAgICAgICAgICB7IHR5cGU6IDIsIHZhbHVlOiBsb2NhbEhvc3REb21haW4gfSxcbiAgICAgICAgICAgICAgICAgICAgLy8gTk9URTogTm8gbG9uZ2VyIGFsbG93IDEyNy4wLjAuMSwgdG8gbWFrZSB0aGlzIG1vcmUgc2VjdXJlLiBXZSBtaWdodCBlbmFibGUgdGhpc1xuICAgICAgICAgICAgICAgICAgICAvLyAgYmVoYXZpb3IgYmVoaW5kIGEgZmxhZywgZm9yIGRldmVsb3BtZW50LlxuICAgICAgICAgICAgICAgICAgICAvL3sgdHlwZTogNywgaXA6IFwiMTI3LjAuMC4xXCIgfVxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAvLyBOT1RFOiBuYW1lQ29uc3RyYWludHMgYXJlIHN1cHBvcnRlZCB3aXRoIG91ciBicmFuY2guIEJ1dC4uLiBjaHJvbWUgZG9lc24ndCBzdXBwb3J0IHRoZW0sIHNvIHRoZXJlJ3Mgbm8gcG9pbnQgaW4gdXNpbmcgdGhlbS5cbiAgICAgICAgICAgIC8vICAgICAgXCJub2RlLWZvcmdlXCI6IFwiaHR0cHM6Ly9naXRodWIuY29tL3NsaWZ0aXN0L2ZvcmdlI2U2MTgxODFiNDY5YjA3YmRjNzBiOTY4YjAzOTFiZWI4ZWY1ZmVjZDZcIixcbiAgICAgICAgICAgIC8vIHtcbiAgICAgICAgICAgIC8vICAgICBuYW1lOiBcIm5hbWVDb25zdHJhaW50c1wiLFxuICAgICAgICAgICAgLy8gICAgIHBlcm1pdHRlZFN1YnRyZWVzOiBbXG4gICAgICAgICAgICAvLyAgICAgICAgIC8vIENocm9tZSBkb2Vzbid0IHJlc3BlY3QgbmFtZUNvbnN0cmFpbnRzIHBlciBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD0xMDcyMDgzLFxuICAgICAgICAgICAgLy8gICAgICAgICAvLyAgYXMgdGhlIHNwZWMgZGVjaWRlZCB0aGF0IFwiZnJlZSB0byBwcm9jZXNzIG9yIGlnbm9yZSBzdWNoIGluZm9ybWF0aW9uXCIgKHdoZW4gcHJlc2VudCBpbiBzZWxmXG4gICAgICAgICAgICAvLyAgICAgICAgIC8vICBzaWduZWQgY2VydGlmaWNhdGVzKSwgYW5kIHRoZXJlZm9yZSB0aGUgY2hyb21lIGltcGxlbWVudGF0aW9uIGRlY2lkZWQgXCJUaGUgZmlyc3Qgb3JkZXIgaXMgdG8gYmVoYXZlIHByZWRpY3RhYmx5XCIsXG4gICAgICAgICAgICAvLyAgICAgICAgIC8vICBzby4uLiB0aGV5J3JlIG5vdCBnb2luZyB0byBzdXBwb3J0IGl0LCBiZWNhdXNlIHdoeSBoYXZlIGEgZmVhdHVyZSBpbiBvbmUgcGxhY2UsIGlmIGl0IGlzbid0XG4gICAgICAgICAgICAvLyAgICAgICAgIC8vICBvbiBhbmRyb2lkIGFzIHdlbGwuLi4gdWdoLi4uXG4gICAgICAgICAgICAvLyAgICAgICAgIC8vIFdvcmtzIGZpbmUgb24gRWRnZSB0aG91Z2hcbiAgICAgICAgICAgIC8vICAgICAgICAgeyB0eXBlOiAyLCB2YWx1ZTogZm9yZ2UudXRpbC5lbmNvZGVVdGY4KGRvbWFpbikgfSxcbiAgICAgICAgICAgIC8vICAgICAgICAgeyB0eXBlOiAyLCB2YWx1ZTogZm9yZ2UudXRpbC5lbmNvZGVVdGY4KGxvY2FsSG9zdERvbWFpbikgfSxcbiAgICAgICAgICAgIC8vICAgICBdXG4gICAgICAgICAgICAvLyB9LFxuICAgICAgICBdKTtcbiAgICAgICAgY2VydE9iai5zZXRFeHRlbnNpb25zKGV4dGVuc2lvbnMpO1xuXG5cbiAgICAgICAgbWVhc3VyZUJsb2NrKGZ1bmN0aW9uIHNpZ24oKSB7XG4gICAgICAgICAgICBpZiAoaXNzdWVyID09PSBcInNlbGZcIikge1xuICAgICAgICAgICAgICAgIGNlcnRPYmouc2lnbihrZXlQYWlyLnByaXZhdGVLZXkgYXMgYW55LCBmb3JnZS5tZC5zaGEyNTYuY3JlYXRlKCkpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjZXJ0T2JqLnNpZ24ocHJpdmF0ZUtleUZyb21QZW0oaXNzdWVyLmtleS50b1N0cmluZygpKSBhcyBhbnksIGZvcmdlLm1kLnNoYTI1Ni5jcmVhdGUoKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBtZWFzdXJlQmxvY2soZnVuY3Rpb24gdG9QZW1zKCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBkb21haW4sXG4gICAgICAgICAgICAgICAgY2VydDogQnVmZmVyLmZyb20oZm9yZ2UucGtpLmNlcnRpZmljYXRlVG9QZW0oY2VydE9iaikpLFxuICAgICAgICAgICAgICAgIGtleTogQnVmZmVyLmZyb20ocHJpdmF0ZUtleVRvUGVtKGtleVBhaXIucHJpdmF0ZUtleSkpLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59XG5leHBvcnQgZnVuY3Rpb24gcHJpdmF0ZUtleVRvUGVtKGJ1ZmZlcjogZm9yZ2UucGtpLlByaXZhdGVLZXkgfCBmb3JnZS5FZDI1NTE5UHJpdmF0ZUtleSkge1xuICAgIGlmIChcInByaXZhdGVLZXlCeXRlc1wiIGluIGJ1ZmZlcikge1xuICAgICAgICByZXR1cm4gZm9yZ2UuZWQyNTUxOS5wcml2YXRlS2V5VG9QZW0oYnVmZmVyKTtcbiAgICB9XG4gICAgcmV0dXJuIGZvcmdlLnBraS5wcml2YXRlS2V5VG9QZW0oYnVmZmVyKTtcbn1cbmZ1bmN0aW9uIHByaXZhdGVLZXlGcm9tUGVtKHBlbTogc3RyaW5nKSB7XG4gICAgLy8gV2Ugd2FudCB0byBndWVzcyB0aGUgdHlwZSBjb3JyZWN0bHksIGFzIGNhdWdodCBleGNlcHRpb25zIG1ha2UgZGVidWdnaW5nIGFubm95aW5nXG4gICAgaWYgKHBlbS5sZW5ndGggPCAyMDApIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBmb3JnZS5lZDI1NTE5LnByaXZhdGVLZXlGcm9tUGVtKHBlbSk7XG4gICAgICAgIH0gY2F0Y2ggeyB9XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBmb3JnZS5wa2kucHJpdmF0ZUtleUZyb21QZW0ocGVtKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIGZvcmdlLmVkMjU1MTkucHJpdmF0ZUtleUZyb21QZW0ocGVtKTtcbiAgICB9XG59XG5mdW5jdGlvbiBwdWJsaWNLZXlGcm9tQ2VydChjZXJ0OiBzdHJpbmcpIHtcbiAgICByZXR1cm4gcGFyc2VDZXJ0KGNlcnQpLnB1YmxpY0tleTtcbn1cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUNlcnQoUEVNb3JERVI6IHN0cmluZyB8IEJ1ZmZlcikge1xuICAgIHJldHVybiBmb3JnZS5wa2kuY2VydGlmaWNhdGVGcm9tUGVtKG5vcm1hbGl6ZUNlcnRUb1BFTShQRU1vckRFUikpO1xufVxuXG4vLyBHZXRzIGEgdW5pcXVlIHZhbHVlIHRvIHJlcHJlc2VudCB0aGUgcHVibGljIGtleVxuZXhwb3J0IGZ1bmN0aW9uIGdldFB1YmxpY0lkZW50aWZpZXIoUEVNb3JERVI6IHN0cmluZyB8IEJ1ZmZlcik6IEJ1ZmZlciB7XG4gICAgbGV0IG9iaiA9IHBhcnNlQ2VydChQRU1vckRFUik7XG4gICAgbGV0IHB1YmxpY0tleSA9IG9iai5wdWJsaWNLZXk7XG4gICAgaWYgKFwicHVibGljS2V5Qnl0ZXNcIiBpbiBwdWJsaWNLZXkpIHtcbiAgICAgICAgcmV0dXJuIEJ1ZmZlci5mcm9tKHB1YmxpY0tleS5wdWJsaWNLZXlCeXRlcyBhcyBhbnkpO1xuICAgIH1cbiAgICByZXR1cm4gQnVmZmVyLmZyb20obmV3IFVpbnQzMkFycmF5KChwdWJsaWNLZXkgYXMgYW55KS5uLmRhdGEpLmJ1ZmZlcik7XG59XG5cbmZ1bmN0aW9uIGlzRUQyNTUxOShrZXk6IHN0cmluZyB8IEJ1ZmZlcikge1xuICAgIHJldHVybiBrZXkubGVuZ3RoIDwgMjU2O1xufVxuXG4vLyBFUVVJVkFMRU5UIFRPOiBgY3J5cHRvLmNyZWF0ZVNpZ24oXCJTSEEyNTZcIikudXBkYXRlKEpTT04uc3RyaW5naWZ5KHBheWxvYWQpKS5zaWduKGtleUNlcnQua2V5LCBcImJpbmFyeVwiKWBcbmV4cG9ydCBjb25zdCBzaWduID0gbWVhc3VyZVdyYXAoZnVuY3Rpb24gc2lnbihrZXlQYWlyOiB7IGtleTogc3RyaW5nIHwgQnVmZmVyIH0sIGRhdGE6IHVua25vd24pOiBzdHJpbmcge1xuICAgIGxldCBkYXRhU3RyID0gSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gICAgaWYgKGlzRUQyNTUxOShrZXlQYWlyLmtleSkpIHtcbiAgICAgICAgbGV0IHByaXZhdGVLZXkgPSAoZm9yZ2UucGtpLmVkMjU1MTkgYXMgYW55KS5wcml2YXRlS2V5RnJvbVBlbShrZXlQYWlyLmtleS50b1N0cmluZygpKTtcbiAgICAgICAgcmV0dXJuIHByaXZhdGVLZXkuc2lnbihkYXRhU3RyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgcHJpdmF0ZUtleSA9IGZvcmdlLnBraS5wcml2YXRlS2V5RnJvbVBlbShrZXlQYWlyLmtleS50b1N0cmluZygpKTtcbiAgICAgICAgY29uc3QgbWQgPSBmb3JnZS5tZC5zaGEyNTYuY3JlYXRlKCk7XG4gICAgICAgIG1kLnVwZGF0ZShkYXRhU3RyKTtcbiAgICAgICAgcmV0dXJuIHByaXZhdGVLZXkuc2lnbihtZCk7XG4gICAgfVxufSk7XG5cbmV4cG9ydCBmdW5jdGlvbiB2ZXJpZnkoY2VydDogc3RyaW5nLCBzaWduYXR1cmU6IHN0cmluZywgZGF0YTogdW5rbm93bikge1xuICAgIGxldCBjZXJ0T2JqID0gcGFyc2VDZXJ0KGNlcnQpO1xuICAgIHJldHVybiAoY2VydE9iai5wdWJsaWNLZXkgYXMgZm9yZ2UucGtpLnJzYS5QdWJsaWNLZXkpLnZlcmlmeShKU09OLnN0cmluZ2lmeShkYXRhKSwgc2lnbmF0dXJlKTtcbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplQ2VydFRvUEVNKFBFTW9yREVSOiBzdHJpbmcgfCBCdWZmZXIpOiBzdHJpbmcge1xuICAgIGlmIChQRU1vckRFUi50b1N0cmluZygpLnN0YXJ0c1dpdGgoXCItLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS1cIikpIHtcbiAgICAgICAgcmV0dXJuIFBFTW9yREVSLnRvU3RyaW5nKCk7XG4gICAgfVxuICAgIFBFTW9yREVSID0gUEVNb3JERVIudG9TdHJpbmcoXCJiYXNlNjRcIik7XG4gICAgcmV0dXJuIFwiLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tXFxuXCIgKyBQRU1vckRFUiArIFwiXFxuLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLVwiO1xufVxuXG5mdW5jdGlvbiBnZXREb21haW5QYXJ0RnJvbVB1YmxpY0tleShwdWJsaWNLZXk6IHsgcHVibGljS2V5Qnl0ZXM6IEJ1ZmZlciB9IHwgZm9yZ2UucGtpLktleVBhaXJbXCJwdWJsaWNLZXlcIl0gfCBCdWZmZXIpIHtcbiAgICBsZXQgYnl0ZXM6IEJ1ZmZlcjtcbiAgICBpZiAoXCJwdWJsaWNLZXlCeXRlc1wiIGluIHB1YmxpY0tleSkge1xuICAgICAgICBieXRlcyA9IHB1YmxpY0tleS5wdWJsaWNLZXlCeXRlcztcbiAgICB9IGVsc2UgaWYgKHB1YmxpY0tleSBpbnN0YW5jZW9mIEJ1ZmZlcikge1xuICAgICAgICBieXRlcyA9IHB1YmxpY0tleTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBieXRlcyA9IEJ1ZmZlci5mcm9tKG5ldyBVaW50MzJBcnJheSgocHVibGljS2V5IGFzIGFueSkubi5kYXRhKS5idWZmZXIpO1xuICAgIH1cbiAgICByZXR1cm4gXCJiXCIgKyBzaGEyNjUuc2hhMjU2KEJ1ZmZlci5mcm9tKGJ5dGVzKSkuc2xpY2UoMCwgMTYpLnJlcGxhY2VBbGwoXCIrXCIsIFwiLVwiKS5yZXBsYWNlQWxsKFwiL1wiLCBcIl9cIik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZUNBQ2VydChkb21haW46IHN0cmluZywgY2VydDogc3RyaW5nIHwgQnVmZmVyKSB7XG4gICAgbGV0IGNlcnRQYXJzZWQgPSBwYXJzZUNlcnQoY2VydCk7XG5cbiAgICBsZXQgc3ViamVjdCA9IGNlcnRQYXJzZWQuc3ViamVjdC5nZXRGaWVsZChcIkNOXCIpLnZhbHVlIGFzIHN0cmluZztcbiAgICBsZXQgbG9jYWxob3N0RG9tYWluID0gXCIxMjctMC0wLTEuXCIgKyBzdWJqZWN0LnNwbGl0KFwiLlwiKS5zbGljZSgtMikuam9pbihcIi5cIik7XG5cbiAgICBsZXQgZG9tYWluUGFydHMgPSBzdWJqZWN0LnNwbGl0KFwiLlwiKS5yZXZlcnNlKCk7XG5cbiAgICBsZXQgcm9vdERvbWFpblBhcnNlZCA9IFtkb21haW5QYXJ0cy5zaGlmdCgpLCBkb21haW5QYXJ0cy5zaGlmdCgpXS5yZXZlcnNlKCkuam9pbihcIi5cIik7XG4gICAgaWYgKHJvb3REb21haW5QYXJzZWQgIT09IGRvbWFpbikge1xuICAgICAgICAvLyBUaGlzIGlzIGltcG9ydGFudCwgYXMgb3VyIHRydXN0IHN0b3JlIGNvbnRhaW5zIG1vcmUgdGhlbiBqdXN0IE9VUiBjZXJ0aWZpY2F0ZXMsXG4gICAgICAgIC8vICBzbyBpZiB3ZSBhbGxvdyBhbnkgZG9tYWlucyB0aGVuIHJlYWwgZG9tYWlucyBjYW4gaW1wZXJzb25hdGUgYW55b25lISBJdCBoYXMgdG9cbiAgICAgICAgLy8gIGJlIG9uZSBPVVIgZG9tYWluIHRvIGJlIHRydXN0ZWQhXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2VydGlmaWNhdGUgcm9vdCBkb21haW4gc2hvdWxkIGJlICR7ZG9tYWlufSwgYnV0IGlzICR7cm9vdERvbWFpblBhcnNlZH1gKTtcbiAgICB9XG4gICAgLy8gVE9ETzogTWF5YmUganVzdCBza2lwIGlmIGl0IGlzbid0IGEgaGFzaCBzdHJpbmc/XG4gICAgaWYgKGRvbWFpblBhcnRzWzBdID09PSBcIm5vcHJveHlcIikge1xuICAgICAgICBkb21haW5QYXJ0cy5zaGlmdCgpO1xuICAgIH1cblxuICAgIGxldCBjZXJ0RXhwZWN0ZWRQdWJsaWNLZXlQYXJ0ID0gKGRvbWFpblBhcnRzLnNoaWZ0KCkgfHwgXCJcIikuc3BsaXQoXCItXCIpLnNsaWNlKC0xKVswXTtcbiAgICBsZXQgY2VydEFjdHVhbFB1YmxpY0tleVBhcnQgPSBnZXREb21haW5QYXJ0RnJvbVB1YmxpY0tleShjZXJ0UGFyc2VkLnB1YmxpY0tleSk7XG4gICAgaWYgKGNlcnRFeHBlY3RlZFB1YmxpY0tleVBhcnQgIT09IGNlcnRBY3R1YWxQdWJsaWNLZXlQYXJ0KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2VydGlmaWNhdGUgcHVibGljIGtleSBpbiB0aGUgdXJsIGlzICR7Y2VydEV4cGVjdGVkUHVibGljS2V5UGFydH0sIGJ1dCBpbiB0aGUgY2VydCBpcyAke2NlcnRBY3R1YWxQdWJsaWNLZXlQYXJ0fWApO1xuICAgIH1cblxuICAgIC8vIEFMU08sIHJlcXVpcmUgbmFtZSBjb25zdHJhaW50cyB0byBiZSBwcmVzZW50LCBhbmQgdG8gcmVzdHJpY3QgdG8gdGhlIFwiQ05cIlxuICAgIGxldCBuYW1lQ29uc3RyYWludHMgPSBjZXJ0UGFyc2VkLmdldEV4dGVuc2lvbihcIm5hbWVDb25zdHJhaW50c1wiKSBhcyBhbnk7XG4gICAgaWYgKCFuYW1lQ29uc3RyYWludHMpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDZXJ0aWZpY2F0ZSBtdXN0IGhhdmUgbmFtZUNvbnN0cmFpbnRzYCk7XG4gICAgfVxuICAgIGxldCBzdWJ0cmVlcyA9IG5hbWVDb25zdHJhaW50cy5wZXJtaXR0ZWRTdWJ0cmVlcztcbiAgICBpZiAoIXN1YnRyZWVzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2VydGlmaWNhdGUgbXVzdCBoYXZlIG5hbWVDb25zdHJhaW50cy5wZXJtaXR0ZWRTdWJ0cmVlc2ApO1xuICAgIH1cbiAgICBsZXQgc3VidHJlZVZhbHVlcyA9IHN1YnRyZWVzLm1hcCgoeDogYW55KSA9PiB4LnZhbHVlKTtcbiAgICAvLyBJZ25vcmUgbG9jYWxob3N0RG9tYWluLCBhcyBpdCBjYW4gYWx3YXlzIHNhZmVseSBiZSBhbGxvd2VkICh0aGUgc2FtZSBtYWNoaW5lXG4gICAgLy8gICAgICBpcyBhbHdheXMgYWxsb3dlZCkuXG4gICAgc3VidHJlZVZhbHVlcyA9IHN1YnRyZWVWYWx1ZXMuZmlsdGVyKCh4OiBzdHJpbmcpID0+IHggIT09IGxvY2FsaG9zdERvbWFpbik7XG4gICAgaWYgKHN1YnRyZWVWYWx1ZXMubGVuZ3RoICE9PSAxIHx8IHN1YnRyZWVWYWx1ZXNbMF0gIT09IHN1YmplY3QpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDZXJ0aWZpY2F0ZSBtdXN0IGhhdmUgYSBzaW5nbGUgY29uc3RyYWluZWQgZG9tYWluIChoYWQgJHtKU09OLnN0cmluZ2lmeShzdWJ0cmVlVmFsdWVzKX0pYCk7XG4gICAgfVxuXG4gICAgdmFsaWRhdGVBbHROYW1lcyhjZXJ0UGFyc2VkLCBzdWJqZWN0KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlQ2VydGlmaWNhdGUoZG9tYWluOiBzdHJpbmcsIGNlcnQ6IEJ1ZmZlciB8IHN0cmluZywgaXNzdWVyQ2VydDogQnVmZmVyIHwgc3RyaW5nKSB7XG4gICAgdmFsaWRhdGVDQUNlcnQoZG9tYWluLCBpc3N1ZXJDZXJ0KTtcblxuICAgIGxldCBjZXJ0UGFyc2VkID0gcGFyc2VDZXJ0KGNlcnQpO1xuICAgIGxldCBzdWJqZWN0ID0gY2VydFBhcnNlZC5zdWJqZWN0LmdldEZpZWxkKFwiQ05cIikudmFsdWUgYXMgc3RyaW5nO1xuICAgIGxldCBsb2NhbGhvc3REb21haW4gPSBcIjEyNy0wLTAtMS5cIiArIHN1YmplY3Quc3BsaXQoXCIuXCIpLnNsaWNlKC0yKS5qb2luKFwiLlwiKTtcblxuICAgIGxldCBkb21haW5QYXJ0cyA9IHN1YmplY3Quc3BsaXQoXCIuXCIpLnJldmVyc2UoKTtcblxuICAgIGxldCByb290RG9tYWluUGFyc2VkID0gW2RvbWFpblBhcnRzLnNoaWZ0KCksIGRvbWFpblBhcnRzLnNoaWZ0KCldLnJldmVyc2UoKS5qb2luKFwiLlwiKTtcbiAgICBpZiAocm9vdERvbWFpblBhcnNlZCAhPT0gZG9tYWluKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2VydGlmaWNhdGUgcm9vdCBkb21haW4gc2hvdWxkIGJlICR7ZG9tYWlufSwgYnV0IGlzICR7cm9vdERvbWFpblBhcnNlZH1gKTtcbiAgICB9XG4gICAgLy8gVE9ETzogTWF5YmUganVzdCBza2lwIGlmIGl0IGlzbid0IGEgaGFzaCBzdHJpbmc/XG4gICAgaWYgKGRvbWFpblBhcnRzWzBdID09PSBcIm5vcHJveHlcIikge1xuICAgICAgICBkb21haW5QYXJ0cy5zaGlmdCgpO1xuICAgIH1cblxuICAgIGxldCBpc3N1ZXJDZXJ0UGFyc2VkID0gcGFyc2VDZXJ0KGlzc3VlckNlcnQpO1xuXG4gICAgbGV0IGlzc3VlckV4cGVjdGVkUHVibGljS2V5UGFydCA9IGRvbWFpblBhcnRzLnNoaWZ0KCkgfHwgXCJcIjtcbiAgICBsZXQgaXNzdWVyQWN0dWFsUHVibGljS2V5UGFydCA9IGdldERvbWFpblBhcnRGcm9tUHVibGljS2V5KGlzc3VlckNlcnRQYXJzZWQucHVibGljS2V5KTtcbiAgICBpZiAoaXNzdWVyRXhwZWN0ZWRQdWJsaWNLZXlQYXJ0ICE9PSBpc3N1ZXJBY3R1YWxQdWJsaWNLZXlQYXJ0KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSXNzdWVyIHB1YmxpYyBrZXkgaW4gdGhlIHVybCBpcyAke2lzc3VlckV4cGVjdGVkUHVibGljS2V5UGFydH0sIGJ1dCBpbiB0aGUgY2VydCBpcyAke2lzc3VlckFjdHVhbFB1YmxpY0tleVBhcnR9YCk7XG4gICAgfVxuXG4gICAgLy8gVGFrZSB0aGUgbGFzdCBwYXJ0XG4gICAgbGV0IGNlcnRFeHBlY3RlZFB1YmxpY0tleVBhcnQgPSBkb21haW5QYXJ0cy5zaGlmdCgpIHx8IFwiXCI7XG4gICAgbGV0IGNlcnRBY3R1YWxQdWJsaWNLZXlQYXJ0ID0gZ2V0RG9tYWluUGFydEZyb21QdWJsaWNLZXkoY2VydFBhcnNlZC5wdWJsaWNLZXkpO1xuICAgIGlmIChjZXJ0RXhwZWN0ZWRQdWJsaWNLZXlQYXJ0ICE9PSBjZXJ0QWN0dWFsUHVibGljS2V5UGFydCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENlcnRpZmljYXRlIHB1YmxpYyBrZXkgaW4gdGhlIHVybCBpcyAke2NlcnRFeHBlY3RlZFB1YmxpY0tleVBhcnR9LCBidXQgaW4gdGhlIGNlcnQgaXMgJHtjZXJ0QWN0dWFsUHVibGljS2V5UGFydH1gKTtcbiAgICB9XG5cblxuICAgIGxldCBuYW1lQ29uc3RyYWludHMgPSBpc3N1ZXJDZXJ0UGFyc2VkLmdldEV4dGVuc2lvbihcIm5hbWVDb25zdHJhaW50c1wiKSBhcyBhbnk7XG4gICAgaWYgKCFuYW1lQ29uc3RyYWludHMpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDQSBtdXN0IGhhdmUgbmFtZUNvbnN0cmFpbnRzYCk7XG4gICAgfVxuICAgIGxldCBzdWJ0cmVlcyA9IG5hbWVDb25zdHJhaW50cy5wZXJtaXR0ZWRTdWJ0cmVlcztcbiAgICBpZiAoIXN1YnRyZWVzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ0EgbXVzdCBoYXZlIG5hbWVDb25zdHJhaW50cy5wZXJtaXR0ZWRTdWJ0cmVlc2ApO1xuICAgIH1cbiAgICBsZXQgc3VidHJlZVZhbHVlcyA9IHN1YnRyZWVzLm1hcCgoeDogYW55KSA9PiB4LnZhbHVlKTtcbiAgICAvLyBJZ25vcmUgbG9jYWxob3N0RG9tYWluLCBhcyBpdCBjYW4gYWx3YXlzIHNhZmVseSBiZSBhbGxvd2VkICh0aGUgc2FtZSBtYWNoaW5lXG4gICAgLy8gICAgICBpcyBhbHdheXMgYWxsb3dlZCkuXG4gICAgc3VidHJlZVZhbHVlcyA9IHN1YnRyZWVWYWx1ZXMuZmlsdGVyKCh4OiBzdHJpbmcpID0+IHggIT09IGxvY2FsaG9zdERvbWFpbik7XG4gICAgaWYgKHN1YnRyZWVWYWx1ZXMubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ0EgbXVzdCBoYXZlIGEgc2luZ2xlIGNvbnN0cmFpbmVkIGRvbWFpbiAoaGFkICR7SlNPTi5zdHJpbmdpZnkoc3VidHJlZVZhbHVlcyl9KWApO1xuICAgIH1cblxuICAgIGxldCBzdWJ0cmVlID0gc3VidHJlZVZhbHVlc1swXTtcbiAgICBpZiAoc3VidHJlZSAhPT0gc3ViamVjdCAmJiAhc3ViamVjdC5lbmRzV2l0aChcIi5cIiArIHN1YnRyZWUpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2VydGlmaWNhdGUgbXVzdCBiZSBhIHN1YnRyZWUgb2YgdGhlIENBIChDQTogJHtzdWJ0cmVlfSwgY2VydDogJHtzdWJqZWN0fSlgKTtcbiAgICB9XG5cbiAgICB2YWxpZGF0ZUFsdE5hbWVzKGNlcnRQYXJzZWQsIHN1YmplY3QpO1xuXG4gICAgLy8gVmVyaWZ5IGlzc3VlciBBQ1RVQUxMWSBzaWduZWQgY2VydFBhcnNlZFxuICAgIGlmICghaXNzdWVyQ2VydFBhcnNlZC52ZXJpZnkoY2VydFBhcnNlZCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJc3N1ZXIgZGlkIG5vdCBzaWduIGNlcnRpZmljYXRlYCk7XG4gICAgfVxufVxuXG4vLyBSZXF1aXJlIGFsdCBuYW1lcyB0byBiZSBlaXRoZXIgZXF1YWwgdG8gXCJDTlwiLCBvciBhIHN1YnRyZWUgb2YgXCJDTlwiXG5mdW5jdGlvbiB2YWxpZGF0ZUFsdE5hbWVzKGNlcnRQYXJzZWQ6IGZvcmdlLnBraS5DZXJ0aWZpY2F0ZSwgc3ViamVjdDogc3RyaW5nKSB7XG4gICAgbGV0IGxvY2FsaG9zdERvbWFpbiA9IFwiMTI3LTAtMC0xLlwiICsgc3ViamVjdC5zcGxpdChcIi5cIikuc2xpY2UoLTIpLmpvaW4oXCIuXCIpO1xuXG4gICAgbGV0IGFsdE5hbWVzT2JqID0gY2VydFBhcnNlZC5nZXRFeHRlbnNpb24oXCJzdWJqZWN0QWx0TmFtZVwiKSBhcyBhbnk7XG4gICAgbGV0IGFsdE5hbWVzID0gYWx0TmFtZXNPYmo/LmFsdE5hbWVzLm1hcCgoeDogYW55KSA9PiB4LnZhbHVlKTtcbiAgICAvLyBBbGxvdyBsb2NhbGhvc3REb21haW4sIGFzIGl0IGNhbiBhbHdheXMgc2FmZWx5IGJlIGFsbG93ZWRcbiAgICBhbHROYW1lcyA9IGFsdE5hbWVzLmZpbHRlcigoeDogc3RyaW5nKSA9PiB4ICE9PSBsb2NhbGhvc3REb21haW4pO1xuICAgIGlmIChcbiAgICAgICAgYWx0TmFtZXMuc29tZSgoeDogc3RyaW5nKSA9PlxuICAgICAgICAgICAgIShcbiAgICAgICAgICAgICAgICB4ID09PSBzdWJqZWN0XG4gICAgICAgICAgICAgICAgfHwgeC5lbmRzV2l0aChcIi5cIiArIHN1YmplY3QpXG4gICAgICAgICAgICAgICAgLy8gQ29tbWVudGVkIG91dCwgYmVjYXVzZS4uLiBpdCBpcyBzbyBlYXN5IHRvIHB1Ymxpc2ggYSAxMjcuMC4wLjEgQSByZWNvcmQsXG4gICAgICAgICAgICAgICAgLy8gIGFuZCBldmVuIHRvIGdlbmVyYXRlIGEgcmVhbCBjZXJ0LCBzbywgd2Ugc2hvdWxkIGpzdXQgZG8gdGhhdCwgYW5kIGtlZXAgaXQgc2VjdXJlLlxuICAgICAgICAgICAgICAgIC8vICBJZiB3ZSBuZWVkIHRoaXMgZm9yIGRldmVsb3BtZW50IHdlIGNhbiBwdXQgaXQgYmVoaW5kIGEgZmxhZywgc28gbm9uLWRldmVsb3BtZW50XG4gICAgICAgICAgICAgICAgLy8gIGluc3RhbmNlcyBhcmUgc3RpbGwgc2VjdXJlLlxuICAgICAgICAgICAgICAgIC8vIC8vIEFsc28gYWxsb3cgMTI3LjAuMC4xLCBmb3IgbG9jYWwgdGVzdGluZywgZm9yIG5vdz9cbiAgICAgICAgICAgICAgICAvLyAvLyAgLSBUaGlzIG1pZ2h0IGJlIGluc2VjdXJlIGlmIHRoZXNlIGFyZSB0cnVzdGVkIGJ5IHRoZSBicm93c2VyLFxuICAgICAgICAgICAgICAgIC8vIC8vICAgICAgYXMgdGhlbiBhbnlvbmUgdGhhdCBzdG9yZXMgYW55IGNvb2tpZXMgaW4gdGhpcyBpcCBjYW4gaGF2ZVxuICAgICAgICAgICAgICAgIC8vIC8vICAgICAgdGhlIGNvb2tpZXMgc3RvbGVuLiBCdXQuLi4gaWYgdGhpcyBpcyBqdXN0IGNyb3NzLXNlcnZlci4uLlxuICAgICAgICAgICAgICAgIC8vIC8vICAgICAgSSBkb24ndCBzZWUgaG93IHRoaXMgY291bGQgY2F1c2UgYSBzZWN1cml0eSB2dWxuZXJhYmlsaXR5LlxuICAgICAgICAgICAgICAgIC8vIHx8IHggPT09IEJ1ZmZlci5mcm9tKFsxMjcsIDAsIDAsIDFdKS50b1N0cmluZygpXG4gICAgICAgICAgICApXG4gICAgICAgIClcbiAgICApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGFsdCBuYW1lcy4gTXVzdCBiZSBzdWJ0cmVlcyBvZiB0aGUgc3ViamVjdCAoQ04pICR7SlNPTi5zdHJpbmdpZnkoc3ViamVjdCl9LCB3YXMgJHtKU09OLnN0cmluZ2lmeShhbHROYW1lcyl9YCk7XG4gICAgfVxufVxuXG5cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZUtleVBhaXIoKSB7XG4gICAgcmV0dXJuIG1lYXN1cmVCbG9jayhmdW5jdGlvbiBnZW5lcmF0ZUtleVBhaXIoKSB7XG4gICAgICAgIC8vIE5PVEU6IFdlIHVzZSBFRDI1NTE5IGJlY2F1c2UgaXQgY2FuIGdlbmVyYXRlZCBrZXlzIGFib3V0IDEwWCBmYXN0ZXIsIFdISUNILCBpcyBzdGlsbCBzbG93XG4gICAgICAgIC8vICAofjZtcyBvbiBteSBtYWNoaW5lKS4gU28gd2UgREVGSU5JVEVMWSBkb24ndCB3YW50IGl0IHRvIGJlIDEwWCBzbG93ZXIhXG4gICAgICAgIC8vIE5PVEU6IEVEMjU1MTkgZG9lbnMndCBoYXZlIGdyZWF0IHN1cHBvcnQgaW4gYnJvd3NlcnMsIGJ1dCB3ZSBzaG91bGRuJ3QgbmVlZCBzZWxmIHNpZ25lZCBjZXJ0aWZpY2F0ZXNcbiAgICAgICAgLy8gIGluIHRoZSBicm93c2VyIGFueXdheS5cbiAgICAgICAgLy8gIC0gaHR0cHM6Ly9zZWN1cml0eS5zdGFja2V4Y2hhbmdlLmNvbS9hLzIzNjk0My8yODIzNjdcbiAgICAgICAgLy9sZXQga2V5UGFpciA9IGZvcmdlLmVkMjU1MTkuZ2VuZXJhdGVLZXlQYWlyKCk7XG4gICAgICAgIGxldCBrZXlQYWlyID0gZm9yZ2UucGtpLnJzYS5nZW5lcmF0ZUtleVBhaXIoKTtcbiAgICAgICAgcmV0dXJuIGtleVBhaXI7XG4gICAgfSk7XG59XG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVSU0FLZXlQYWlyKCkge1xuICAgIHJldHVybiBtZWFzdXJlQmxvY2soZnVuY3Rpb24gZ2VuZXJhdGVLZXlQYWlyKCkge1xuICAgICAgICByZXR1cm4gZm9yZ2UucGtpLnJzYS5nZW5lcmF0ZUtleVBhaXIoKTtcbiAgICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlVGVzdENBKGRvbWFpbjogc3RyaW5nKSB7XG4gICAgY29uc3Qga2V5UGFpciA9IGdlbmVyYXRlS2V5UGFpcigpO1xuICAgIGxldCBjYVB1YmxpY0tleVBhcnQgPSBnZXREb21haW5QYXJ0RnJvbVB1YmxpY0tleShrZXlQYWlyLnB1YmxpY0tleSk7XG4gICAgbGV0IGZ1bGxEb21haW4gPSBgJHtjYVB1YmxpY0tleVBhcnR9LiR7ZG9tYWlufWA7XG4gICAgaWYgKCFpc05vZGUoKSkge1xuICAgICAgICBmdWxsRG9tYWluID0gYCR7Y2FQdWJsaWNLZXlQYXJ0fS4ke2RvbWFpbn1gO1xuICAgIH1cblxuICAgIHJldHVybiBjcmVhdGVYNTA5KHsgZG9tYWluOiBmdWxsRG9tYWluLCBpc3N1ZXI6IFwic2VsZlwiLCBrZXlQYWlyLCBsaWZlU3BhbjogdGltZUluRGF5ICogMzY1ICogMjAgfSk7XG59XG5cbmxldCBpZGVudGl0eUNBID0gY2FjaGUoKGRvbWFpbjogc3RyaW5nKSA9PiB7XG4gICAgbGV0IGlkZW50aXR5Q0EgPSBsYXp5KChhc3luYyAoKTogUHJvbWlzZTxYNTA5S2V5UGFpcj4gPT4ge1xuICAgICAgICBsZXQgaWRlbnRpdHlDQUNhY2hlZCA9IGdldElkZW50aXR5U3RvcmUoZG9tYWluKTtcbiAgICAgICAgbGV0IGNhQ2FjaGVkID0gYXdhaXQgaWRlbnRpdHlDQUNhY2hlZC5nZXQoKTtcbiAgICAgICAgaWYgKCFjYUNhY2hlZCkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coYEdlbmVyYXRpbmcgbmV3IGlkZW50aXR5IENBYCk7XG4gICAgICAgICAgICBjb25zdCBrZXlQYWlyID0gZ2VuZXJhdGVLZXlQYWlyKCk7XG4gICAgICAgICAgICBsZXQgY2FQdWJsaWNLZXlQYXJ0ID0gZ2V0RG9tYWluUGFydEZyb21QdWJsaWNLZXkoa2V5UGFpci5wdWJsaWNLZXkpO1xuICAgICAgICAgICAgbGV0IGZ1bGxEb21haW4gPSBgJHtjYVB1YmxpY0tleVBhcnR9LiR7ZG9tYWlufWA7XG4gICAgICAgICAgICBpZiAoIWlzTm9kZSgpKSB7XG4gICAgICAgICAgICAgICAgZnVsbERvbWFpbiA9IGAke2NhUHVibGljS2V5UGFydH0uJHtkb21haW59YDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IHZhbHVlID0gY3JlYXRlWDUwOSh7IGRvbWFpbjogZnVsbERvbWFpbiwgaXNzdWVyOiBcInNlbGZcIiwga2V5UGFpciwgbGlmZVNwYW46IHRpbWVJbkRheSAqIDM2NSAqIDIwIH0pO1xuXG4gICAgICAgICAgICBjYUNhY2hlZCA9IHtcbiAgICAgICAgICAgICAgICBkb21haW46IHZhbHVlLmRvbWFpbixcbiAgICAgICAgICAgICAgICBjZXJ0QjY0OiB2YWx1ZS5jZXJ0LnRvU3RyaW5nKFwiYmFzZTY0XCIpLFxuICAgICAgICAgICAgICAgIGtleUI2NDogdmFsdWUua2V5LnRvU3RyaW5nKFwiYmFzZTY0XCIpLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGF3YWl0IGlkZW50aXR5Q0FDYWNoZWQuc2V0KGNhQ2FjaGVkKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcmVzdWx0ID0ge1xuICAgICAgICAgICAgZG9tYWluOiBjYUNhY2hlZC5kb21haW4sXG4gICAgICAgICAgICBjZXJ0OiBCdWZmZXIuZnJvbShjYUNhY2hlZC5jZXJ0QjY0LCBcImJhc2U2NFwiKSxcbiAgICAgICAgICAgIGtleTogQnVmZmVyLmZyb20oY2FDYWNoZWQua2V5QjY0LCBcImJhc2U2NFwiKSxcbiAgICAgICAgfTtcbiAgICAgICAgdHJ1c3RDZXJ0aWZpY2F0ZShyZXN1bHQuY2VydC50b1N0cmluZygpKTtcbiAgICAgICAgaWRlbnRpdHlDQS5zZXQocmVzdWx0KTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9KSBhcyAoKCkgPT4gTWF5YmVQcm9taXNlPFg1MDlLZXlQYWlyPikpO1xuICAgIHJldHVybiBpZGVudGl0eUNBO1xufSk7XG5cbi8vIElNUE9SVEFOVCEgV2UgZG8gbm90IGVtYmVkIGFueSBkZWJ1ZyBpbmZvIGluIHRoaXMgZG9tYWluLiBJZiB3ZSBkaWQsIGl0IHdvdWxkIGJlIHVzZWZ1bCxcbi8vICBidXQuLi4gcG90ZW50YWxseSBhIHNlY3VyaXR5IHZ1bG5lcmFiaWxpdHksIGFzIGlmIHRoZSBkZWJ1ZyBpbmZvIChzdWNoIGFzIGEgcHJlZml4KVxuLy8gIGlzIHVzZWQgdG8gaWRlbnRpZnkgd2hhdCBhIGNlcnRpZmljYXRlIGlzIGZvciwgaXQgd291bGQgYmUgZWFzeSBmb3IgYW4gYXR0YWNrIHRvXG4vLyAgZm9yZ2UgdGhpcyAoYXMgdGhlIGRlYnVnIGluZm8gd29uJ3QgYmUgc2VjdXJlZCkuIFNvIGl0IGlzIG11Y2ggYmV0dGVyIHRvIGtlZXBcbi8vICB0aGUgY2VydGlmaWNhdGUgb3BhcXVlLCBhbmQgdGhlbiByZXF1aXJlIGFueSBtZXRhZGF0YSB0byBiZSBhY3R1YWxseSB2ZXR0ZWRcbi8vICAoYW5kIGhvcGVmdWxseSBzdG9yZWQgaW4gYSBVSSwgc2hvd2luZyBJUCwgdGltZSwgZXRjKS5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVDZXJ0RnJvbUNBKGNvbmZpZzoge1xuICAgIENBS2V5UGFpcjogWDUwOUtleVBhaXI7XG59KTogWDUwOUtleVBhaXIge1xuICAgIHJldHVybiBtZWFzdXJlQmxvY2soZnVuY3Rpb24gY3JlYXRlQ2VydEZyb21DQSgpIHtcbiAgICAgICAgbGV0IHsgQ0FLZXlQYWlyIH0gPSBjb25maWc7XG4gICAgICAgIGNvbnN0IGtleVBhaXIgPSBnZW5lcmF0ZUtleVBhaXIoKTtcbiAgICAgICAgbGV0IGRvbWFpbktleVBhcnQgPSBnZXREb21haW5QYXJ0RnJvbVB1YmxpY0tleShrZXlQYWlyLnB1YmxpY0tleSk7XG4gICAgICAgIGxldCBmdWxsRG9tYWluID0gYCR7ZG9tYWluS2V5UGFydH0uJHtjb25maWcuQ0FLZXlQYWlyLmRvbWFpbn1gO1xuICAgICAgICByZXR1cm4gY3JlYXRlWDUwOSh7XG4gICAgICAgICAgICBkb21haW46IGZ1bGxEb21haW4sXG4gICAgICAgICAgICBpc3N1ZXI6IENBS2V5UGFpcixcbiAgICAgICAgICAgIGtleVBhaXIsXG4gICAgICAgICAgICBsaWZlU3BhbjogdGltZUluRGF5ICogMzY1ICogMTAsXG4gICAgICAgIH0pO1xuICAgIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0TWFjaGluZUlkKGRvbWFpbk5hbWU6IHN0cmluZykge1xuICAgIHJldHVybiBkb21haW5OYW1lLnNwbGl0KFwiLlwiKS5zbGljZSgtMykuam9pbihcIi5cIik7XG59XG5cbmV4cG9ydCB0eXBlIE5vZGVJZFBhcnRzID0ge1xuICAgIHRocmVhZElkOiBzdHJpbmc7XG4gICAgbWFjaGluZUlkOiBzdHJpbmc7XG4gICAgZG9tYWluOiBzdHJpbmc7XG4gICAgcG9ydDogbnVtYmVyO1xufTtcbmV4cG9ydCBmdW5jdGlvbiBkZWNvZGVOb2RlSWQobm9kZUlkOiBzdHJpbmcpOiBOb2RlSWRQYXJ0cyB8IHVuZGVmaW5lZCB7XG4gICAgbGV0IGxvY2F0aW9uT2JqID0gZ2V0Tm9kZUlkTG9jYXRpb24obm9kZUlkKTtcbiAgICBpZiAoIWxvY2F0aW9uT2JqKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGxldCBwYXJ0cyA9IGxvY2F0aW9uT2JqLmFkZHJlc3Muc3BsaXQoXCIuXCIpO1xuICAgIGlmIChub2RlSWQuc3RhcnRzV2l0aChcIjEyNy0wLTAtMS5cIikgJiYgcGFydHMubGVuZ3RoID09PSAzKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0aHJlYWRJZDogXCJcIixcbiAgICAgICAgICAgIG1hY2hpbmVJZDogcGFydHMuYXQoLTMpIHx8IFwiXCIsXG4gICAgICAgICAgICBkb21haW46IHBhcnRzLnNsaWNlKC0yKS5qb2luKFwiLlwiKSxcbiAgICAgICAgICAgIHBvcnQ6IGxvY2F0aW9uT2JqLnBvcnQsXG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChwYXJ0cy5sZW5ndGggPCA0KSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIHRocmVhZElkOiBwYXJ0cy5hdCgtNCkgfHwgXCJcIixcbiAgICAgICAgbWFjaGluZUlkOiBwYXJ0cy5hdCgtMykgfHwgXCJcIixcbiAgICAgICAgZG9tYWluOiBwYXJ0cy5zbGljZSgtMikuam9pbihcIi5cIikgfHwgXCJcIixcbiAgICAgICAgcG9ydDogbG9jYXRpb25PYmoucG9ydCxcbiAgICB9O1xufVxuZXhwb3J0IGZ1bmN0aW9uIGRlY29kZU5vZGVJZEFzc2VydChub2RlSWQ6IHN0cmluZyk6IE5vZGVJZFBhcnRzIHtcbiAgICBsZXQgcmVzdWx0ID0gZGVjb2RlTm9kZUlkKG5vZGVJZCk7XG4gICAgaWYgKCFyZXN1bHQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIG5vZGVJZDogJHtub2RlSWR9YCk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG59XG5leHBvcnQgZnVuY3Rpb24gZW5jb2RlTm9kZUlkKHBhcnRzOiBOb2RlSWRQYXJ0cykge1xuICAgIHJldHVybiBgJHtwYXJ0cy50aHJlYWRJZH0uJHtwYXJ0cy5tYWNoaW5lSWR9LiR7cGFydHMuZG9tYWlufToke3BhcnRzLnBvcnR9YDtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNldElkZW50aXR5Q0FSYXcoZG9tYWluOiBzdHJpbmcsIGpzb246IHN0cmluZykge1xuICAgIGxldCBpZGVudGl0eUNBQ2FjaGVkID0gZ2V0SWRlbnRpdHlTdG9yZShkb21haW4pO1xuICAgIGxldCBvYmogPSBKU09OLnBhcnNlKGpzb24pIGFzIHtcbiAgICAgICAgZG9tYWluOiBzdHJpbmc7XG4gICAgICAgIGNlcnRCNjQ6IHN0cmluZztcbiAgICAgICAga2V5QjY0OiBzdHJpbmc7XG4gICAgfTtcbiAgICBsZXQgY2EgPSB7XG4gICAgICAgIGRvbWFpbjogb2JqLmRvbWFpbixcbiAgICAgICAgY2VydDogQnVmZmVyLmZyb20ob2JqLmNlcnRCNjQsIFwiYmFzZTY0XCIpLFxuICAgICAgICBrZXk6IEJ1ZmZlci5mcm9tKG9iai5rZXlCNjQsIFwiYmFzZTY0XCIpLFxuICAgIH07XG4gICAgdHJ1c3RDZXJ0aWZpY2F0ZShjYS5jZXJ0LnRvU3RyaW5nKCkpO1xuICAgIGlkZW50aXR5Q0EoZG9tYWluKS5zZXQoY2EpO1xuICAgIGdldFRocmVhZEtleUNlcnRCYXNlKGRvbWFpbikucmVzZXQoKTtcbiAgICBhd2FpdCBpZGVudGl0eUNBQ2FjaGVkLnNldChvYmopO1xuICAgIHJlc2V0QWxsTm9kZUNhbGxGYWN0b3JpZXMoKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxvYWRJZGVudGl0eUNBKGRvbWFpbjogc3RyaW5nKSB7XG4gICAgYXdhaXQgaWRlbnRpdHlDQShkb21haW4pKCk7XG59XG5leHBvcnQgZnVuY3Rpb24gZ2V0SWRlbnRpdHlDQShkb21haW46IHN0cmluZyk6IFg1MDlLZXlQYWlyIHtcbiAgICBsZXQgdmFsdWUgPSBpZGVudGl0eUNBKGRvbWFpbikoKTtcbiAgICBpZiAodmFsdWUgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIklkZW50aXR5IENBIGlzIG5vdCB5ZXQgbG9hZGVkLiBDYWxsIGFuZCB3YWl0IGZvciBsb2FkSWRlbnRpdHlDQSgpIGluIHlvdXIgc3RhcnR1cCBiZWZvcmUgYWNjZXNzaW5nIHRoZSBpZGVudGl0eSAob3IgY2FsbCBnZXRJZGVudGl0eUNBUHJvbWlzZSgpKVwiKTtcbiAgICB9XG4gICAgcmV0dXJuIHZhbHVlO1xufVxuXG4vLyBUT0RPOiBSZXBsYWNlIHRoaXMgd2l0aCBhIGRhdGFiYXNlLCBzbyBpdCBpcyBlYXN5IGZvciB1cyB0byB0cnVzdCBDQXNcbi8vICBjcm9zcyBtYWNoaW5lLCBhbmQgZXZlbiBoYXZlIG11bHRpcGxlIHVzZXJzLCBldGMsIGV0Yy5cbmV4cG9ydCBmdW5jdGlvbiBnZXRJZGVudGl0eUNBUHJvbWlzZShkb21haW46IHN0cmluZyk6IE1heWJlUHJvbWlzZTxYNTA5S2V5UGFpcj4ge1xuICAgIHJldHVybiBpZGVudGl0eUNBKGRvbWFpbikoKTtcbn1cblxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0T3duTWFjaGluZUlkKGRvbWFpbjogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGdldE1hY2hpbmVJZChnZXRJZGVudGl0eUNBKGRvbWFpbikuZG9tYWluKTtcbn1cblxuLyoqIFBhcnQgb2YgdGhlIG1hY2hpbmVJZCBjb21lcyBmcm9tIHRoZSBwdWJsaWNLZXksIHNvIHdlIGNhbiB1c2UgaXQgdG8gdmVyaWZ5ICovXG5leHBvcnQgZnVuY3Rpb24gdmVyaWZ5TWFjaGluZUlkRm9yUHVibGljS2V5KGNvbmZpZzoge1xuICAgIG1hY2hpbmVJZDogc3RyaW5nO1xuICAgIHB1YmxpY0tleTogQnVmZmVyO1xufSk6IGJvb2xlYW4ge1xuICAgIGxldCB7IG1hY2hpbmVJZCwgcHVibGljS2V5IH0gPSBjb25maWc7XG4gICAgbGV0IGRvbWFpblBhcnQgPSBnZXREb21haW5QYXJ0RnJvbVB1YmxpY0tleShwdWJsaWNLZXkpO1xuICAgIHJldHVybiBtYWNoaW5lSWQuc3BsaXQoXCIuXCIpLmF0KC0zKSA9PT0gZG9tYWluUGFydDtcbn1cblxuLy8gTk9URTogV2UgZG9uJ3QgaGF2ZSBhIGNhY2hlIHBlciBDQSwgYXMuLi4gdGhlIENBIHNob3VsZCBiZSBzZXQgZmlyc3Rcbi8vICBUT0RPOiBNYXliZSB0aHJvdyBpZiB0aGV5IHRyeSB0byBjaGFuZ2UgdGhlIENBIGFmdGVyIHRoZXkgZ2VuZXJhdGUgYW55IGNlcnRpZmljYXRlcz9cbi8vIFRPRE86IFJlZ2VuZXJhdGUgY2VydGlmaWNhdGVzIGFmdGVyIGVub3VnaCB0aW1lIChhcyB0aHJlYWQgY2VydHMgc2hvdWxkIGJlIHJlbGF0aXZlbHkgc2hvcnQgbGl2ZWQsXG4vLyAgc28gaXQgaXMgcGxhdXNpYmxlIGZvciB0aGVtIHRvIGV4cGlyZSlcbi8vICAtIFdlIHdpbGwgYWxzbyBuZWVkIHRvIHByb3ZpZGUgYSBjYWxsYmFjayBzbyB0aGF0IHVzZXJzIG9mIHRoZSBjZXJ0IGNhbiB1cGRhdGUgdGhlIGNlcnQgdGhleVxuLy8gICAgICBhcmUgdXNpbmcgYXMgd2VsbC5cbmV4cG9ydCBmdW5jdGlvbiBnZXRUaHJlYWRLZXlDZXJ0KGRvbWFpbjogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGdldFRocmVhZEtleUNlcnRCYXNlKGRvbWFpbikoKTtcbn1cbmNvbnN0IGdldFRocmVhZEtleUNlcnRCYXNlID0gY2FjaGUoKGRvbWFpbjogc3RyaW5nKSA9PiBsYXp5KCgpID0+IHtcbiAgICBsZXQgY2EgPSBnZXRJZGVudGl0eUNBKGRvbWFpbik7XG4gICAgcmV0dXJuIGNyZWF0ZUNlcnRGcm9tQ0EoeyBDQUtleVBhaXI6IGNhIH0pO1xufSkpO1xuXG5leHBvcnQgY29uc3QgY3JlYXRlVGVzdEJyb3dzZXJLZXlDZXJ0ID0gbGF6eShhc3luYyAoKSA9PiB7XG4gICAgbGV0IGtleVBhaXIgPSBnZW5lcmF0ZVJTQUtleVBhaXIoKTtcbiAgICByZXR1cm4gYXdhaXQgY3JlYXRlWDUwOSh7IGRvbWFpbjogXCJ0ZXN0XCIsIGlzc3VlcjogXCJzZWxmXCIsIGtleVBhaXIsIGxpZmVTcGFuOiB0aW1lSW5EYXkgKiAzNjUgKiAyMCB9KTtcbn0pO1xuXG5leHBvcnQgZnVuY3Rpb24gZ2V0T3duTm9kZUlkKCk6IHN0cmluZyB7XG4gICAgbGV0IG5vZGVJZCA9IFNvY2tldEZ1bmN0aW9uLm1vdW50ZWROb2RlSWQ7XG4gICAgaWYgKCFub2RlSWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBOb2RlIG11c3QgYmUgbW91bnRlZCBiZWZvcmUgbm9kZUlkIGlzIGFjY2Vzc2VkYCk7XG4gICAgfVxuICAgIHJldHVybiBub2RlSWQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRPd25Ob2RlSWRBbGxvd1VuZGVmaW5lZCgpIHtcbiAgICByZXR1cm4gU29ja2V0RnVuY3Rpb24ubW91bnRlZE5vZGVJZDtcbn0iXX0=
530
+ /* _JS_SOURCE_HASH = "be134c2204a9b9ba8ae9e00631d6a5b87b56d49723154c00ab8e24807b63c905"; */