PHP WebShell
Текущая директория: /opt/BitGoJS/modules/bitgo/dist/test/v2/unit/internal/tssUtils/ecdsaMPCv2
Просмотр файла: signTxRequest.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBitGoPartyGpgKeyPrv = getBitGoPartyGpgKeyPrv;
exports.getUserPartyGpgKeyPublic = getUserPartyGpgKeyPublic;
const sdk_core_1 = require("@bitgo/sdk-core");
const sdk_lib_mpc_1 = require("@bitgo/sdk-lib-mpc");
const fs = require("fs");
const common_1 = require("../common");
const openpgp = require("openpgp");
const nock = require("nock");
const sdk_test_1 = require("@bitgo/sdk-test");
const src_1 = require("../../../../../../src");
const createKeccakHash = require('keccak');
describe('signTxRequest:', function () {
let tssUtils;
let wallet;
let bitgo;
let baseCoin;
let bitgoGpgKey;
const coinName = 'hteth';
const reqId = new sdk_core_1.RequestTracer();
const txRequestId = 'randomTxReqId';
const signableHex = 'e27aecaea559fbedc9ae8a22b0ab6654c2d686403c2aeb434b302545c94eed3b';
const txRequest = {
txRequestId,
enterpriseId: '4517abfb-f567-4b7a-9f91-407509d29403',
transactions: [
{
unsignedTx: {
serializedTxHex: 'TOO MANY SECRETS',
signableHex,
derivationPath: 'm/0', // Needs this when key derivation is supported
},
state: 'pendingSignature',
signatureShares: [],
},
],
unsignedTxs: [],
date: new Date().toISOString(),
intent: {
intentType: 'payment',
},
latest: true,
state: 'pendingUserSignature',
walletType: 'hot',
walletId: 'walletId',
policiesChecked: true,
version: 1,
userId: 'userId',
apiVersion: 'full',
};
const txRequestForMessageSigning = {
txRequestId,
enterpriseId: '4517abfb-f567-4b7a-9f91-407509d29403',
messages: [
{
messageRaw: 'TOO MANY SECRETS',
derivationPath: 'm/0',
state: 'pendingSignature',
signatureShares: [],
},
],
unsignedTxs: [],
date: new Date().toISOString(),
intent: {
intentType: 'payment',
},
latest: true,
state: 'pendingUserSignature',
walletType: 'hot',
walletId: 'walletId',
policiesChecked: true,
version: 1,
userId: 'userId',
apiVersion: 'full',
};
const vector = {
party1: 0,
party2: 2,
party3: 1,
};
// To generate the fixtures, run DKG as in the dklsDkg.ts tests and save the resulting party.getKeyShare in a file by doing fs.writeSync(party.getKeyShare()).
const shareFiles = [
`${__dirname}/fixtures/userShare`,
`${__dirname}/fixtures/backupShare`,
`${__dirname}/fixtures/bitgoShare`,
];
let bitgoParty;
before(async () => {
bitgo = sdk_test_1.TestBitGo.decorate(src_1.BitGo, { env: 'mock' });
bitgo.initializeTestVars();
const bgUrl = sdk_core_1.common.Environments[bitgo.getEnv()].uri;
bitgoGpgKey = await openpgp.generateKey({
userIDs: [
{
name: 'bitgo',
},
],
curve: 'secp256k1',
config: {
rejectCurves: new Set(),
},
});
const constants = {
mpc: {
bitgoPublicKey: bitgoGpgKey.publicKey,
bitgoMPCv2PublicKey: bitgoGpgKey.publicKey,
},
};
nock(bgUrl).get('/api/v1/client/constants').times(20).reply(200, { ttl: 3600, constants });
baseCoin = bitgo.coin(coinName);
let hashFn;
try {
hashFn = baseCoin.getHashFunction();
}
catch (err) {
hashFn = createKeccakHash('keccak256');
}
const hashBuffer = hashFn.update(Buffer.from(signableHex, 'hex')).digest();
// Nock out both the user and bitgo side responses to create valid signatures
bitgoParty = new sdk_lib_mpc_1.DklsDsg.Dsg(fs.readFileSync(shareFiles[vector.party2]), vector.party2, txRequest.transactions[0].unsignedTx.derivationPath, hashBuffer);
// // Round 1 ////
const walletData = {
id: txRequest.walletId,
enterprise: txRequest.enterpriseId,
coin: coinName,
coinSpecific: {},
multisigType: 'tss',
multisigTypeVersion: 'MPCv2',
};
wallet = new sdk_core_1.Wallet(bitgo, baseCoin, walletData);
tssUtils = new sdk_core_1.ECDSAUtils.EcdsaMPCv2Utils(bitgo, baseCoin, wallet);
});
beforeEach(async function () {
await nockGetBitgoPublicKeyBasedOnFeatureFlags(coinName, txRequest.enterpriseId, bitgoGpgKey);
});
after(function () {
nock.cleanAll();
});
afterEach(function () {
bitgoParty.endSession();
nock.cleanAll();
});
it('successfully signs a txRequest with user key for a dkls hot wallet with WP', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundThree(txRequest),
await nockSendTxRequest(txRequest),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('successfully signs a txRequest with backup key for a dkls hot wallet with WP', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey, 1),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey, 1),
await nockTxRequestResponseSignatureShareRoundThree(txRequest),
await nockSendTxRequest(txRequest),
];
await Promise.all(nockPromises);
const backupShare = fs.readFileSync(shareFiles[vector.party3]);
const backupPrvBase64 = Buffer.from(backupShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: backupPrvBase64,
mpcv2PartyId: 1,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('successfully signs a txRequest with a message for a dkls hot wallet with WP', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequestForMessageSigning, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequestForMessageSigning, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundThree(txRequestForMessageSigning),
await nockSendTxRequest(txRequestForMessageSigning),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('successfully signs a txRequest for a dkls hot wallet after receiving multiple 429 errors', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey, 0, 3),
await nockTxRequestResponseSignatureShareRoundThree(txRequest),
await nockSendTxRequest(txRequest),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('fails to signs a txRequest for a dkls hot wallet after receiving over 3 429 errors', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey, 0, 4),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils
.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
})
.should.be.rejectedWith('Too many requests, slow down!');
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.false();
});
});
function getBitGoPartyGpgKeyPrv(key) {
return {
partyId: 2,
gpgKey: key.privateKey,
};
}
function getUserPartyGpgKeyPublic(userPubKey, partyId = 0) {
return {
partyId: partyId,
gpgKey: userPubKey,
};
}
async function nockTxRequestResponseSignatureShareRoundOne(bitgoSession, txRequest, bitgoGpgKey, partyId = 0) {
const transactions = (0, common_1.getRoute)('ecdsa');
return nock('https://bitgo.fakeurl')
.persist(true)
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round1Input')
.times(1)
.reply(200, async (uri, body) => {
// Do the actual signing on BitGo's side based on User's messages
const signatureShare = JSON.parse(body.signatureShares[0].share);
const deserializedMessages = sdk_lib_mpc_1.DklsTypes.deserializeMessages({
p2pMessages: [],
broadcastMessages: [
{
from: signatureShare.data.msg1.from,
payload: signatureShare.data.msg1.message,
},
],
});
if (signatureShare.type === 'round1Input') {
const bitgoToUserRound1BroadcastMsg = await bitgoSession.init();
const bitgoToUserRound2Msg = bitgoSession.handleIncomingMessages({
p2pMessages: [],
broadcastMessages: deserializedMessages.broadcastMessages,
});
const serializedBitGoToUserRound1And2Msgs = sdk_lib_mpc_1.DklsTypes.serializeMessages({
p2pMessages: bitgoToUserRound2Msg.p2pMessages,
broadcastMessages: [bitgoToUserRound1BroadcastMsg],
});
const authEncMessages = await sdk_lib_mpc_1.DklsComms.encryptAndAuthOutgoingMessages(serializedBitGoToUserRound1And2Msgs, [getUserPartyGpgKeyPublic(body.signerGpgPublicKey, partyId)], [getBitGoPartyGpgKeyPrv(bitgoGpgKey)]);
const bitgoToUserSignatureShare = {
type: 'round1Output',
data: {
msg1: {
from: authEncMessages.broadcastMessages[0].from,
signature: authEncMessages.broadcastMessages[0].payload.signature,
message: authEncMessages.broadcastMessages[0].payload.message,
},
msg2: {
from: authEncMessages.p2pMessages[0].from,
to: authEncMessages.p2pMessages[0].to,
encryptedMessage: authEncMessages.p2pMessages[0].payload.encryptedMessage,
signature: authEncMessages.p2pMessages[0].payload.signature,
},
},
};
return {
txRequestId: txRequest.txRequestId,
transactions: [
{
signatureShares: [
{
from: sdk_core_1.SignatureShareType.BITGO,
to: partyId === 0 ? sdk_core_1.SignatureShareType.USER : sdk_core_1.SignatureShareType.BACKUP,
share: JSON.stringify(bitgoToUserSignatureShare),
},
],
},
],
};
}
});
}
async function nockTxRequestResponseSignatureShareRoundTwo(bitgoSession, txRequest, bitgoGpgKey, partyId = 0, rateLimitErrorCount = 0) {
const transactions = (0, common_1.getRoute)('ecdsa');
const scope = nock('https://bitgo.fakeurl');
if (rateLimitErrorCount > 0) {
scope
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round2Input')
.times(rateLimitErrorCount)
.reply(429, {
error: 'Too many requests, slow down!',
name: 'TooManyRequests',
requestId: 'cm5qx01lh0013b2ek2sxl4w00',
context: {},
});
}
return scope
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round2Input')
.times(1)
.reply(200, async (uri, body) => {
// Do the actual signing on BitGo's side based on User's messages
const parsedSignatureShare = JSON.parse(body.signatureShares[0].share);
const serializedMessages = await sdk_lib_mpc_1.DklsComms.decryptAndVerifyIncomingMessages({
p2pMessages: [
{
from: parsedSignatureShare.data.msg2.from,
to: parsedSignatureShare.data.msg2.to,
payload: {
encryptedMessage: parsedSignatureShare.data.msg2.encryptedMessage,
signature: parsedSignatureShare.data.msg2.signature,
},
},
{
from: parsedSignatureShare.data.msg3.from,
to: parsedSignatureShare.data.msg3.to,
payload: {
encryptedMessage: parsedSignatureShare.data.msg3.encryptedMessage,
signature: parsedSignatureShare.data.msg3.signature,
},
},
],
broadcastMessages: [],
}, [getUserPartyGpgKeyPublic(body.signerGpgPublicKey, partyId)], [getBitGoPartyGpgKeyPrv(bitgoGpgKey)]);
const deserializedMessages = sdk_lib_mpc_1.DklsTypes.deserializeMessages({
p2pMessages: [serializedMessages.p2pMessages[0]],
broadcastMessages: [],
});
if (parsedSignatureShare.type === 'round2Input') {
const bitgoToUserRound3Msg = bitgoSession.handleIncomingMessages(deserializedMessages);
const serializedBitGoToUserRound3Msgs = sdk_lib_mpc_1.DklsTypes.serializeMessages(bitgoToUserRound3Msg);
const authEncMessages = await sdk_lib_mpc_1.DklsComms.encryptAndAuthOutgoingMessages(serializedBitGoToUserRound3Msgs, [getUserPartyGpgKeyPublic(body.signerGpgPublicKey, partyId)], [getBitGoPartyGpgKeyPrv(bitgoGpgKey)]);
const bitgoToUserSignatureShare = {
type: 'round2Output',
data: {
msg3: {
from: authEncMessages.p2pMessages[0].from,
to: authEncMessages.p2pMessages[0].to,
encryptedMessage: authEncMessages.p2pMessages[0].payload.encryptedMessage,
signature: authEncMessages.p2pMessages[0].payload.signature,
},
},
};
return {
txRequestId: txRequest.txRequestId,
transactions: [
{
signatureShares: [
{
from: partyId === 0 ? sdk_core_1.SignatureShareType.USER : sdk_core_1.SignatureShareType.BACKUP,
to: sdk_core_1.SignatureShareType.BITGO,
share: 'some old share we dont care about',
},
{
from: sdk_core_1.SignatureShareType.BITGO,
to: partyId === 0 ? sdk_core_1.SignatureShareType.USER : sdk_core_1.SignatureShareType.BACKUP,
share: JSON.stringify(bitgoToUserSignatureShare),
},
],
},
],
};
}
});
}
async function nockTxRequestResponseSignatureShareRoundThree(txRequest) {
const transactions = (0, common_1.getRoute)('ecdsa');
return nock('https://bitgo.fakeurl')
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round3Input')
.times(1)
.reply(200, async (uri, body) => {
// Do the actual signing on BitGo's side based on User's messages
return {
txRequestId: txRequest.txRequestId,
};
});
}
async function nockSendTxRequest(txRequest) {
const transactions = (0, common_1.getRoute)('ecdsa');
return nock('https://bitgo.fakeurl')
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/send`)
.times(1)
.reply(200, {
txRequestId: txRequest.txRequestId,
});
}
async function nockGetBitgoPublicKeyBasedOnFeatureFlags(coin, enterpriseId, bitgoGpgKeyPair) {
const bitgoGPGPublicKeyResponse = {
name: 'irrelevant',
publicKey: bitgoGpgKeyPair.publicKey,
mpcv2PublicKey: bitgoGpgKeyPair.publicKey,
enterpriseId,
};
nock('https://bitgo.fakeurl')
.get(`/api/v2/${coin}/tss/pubkey`)
.times(4)
.query({ enterpriseId })
.reply(200, bitgoGPGPublicKeyResponse);
return bitgoGPGPublicKeyResponse;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnblR4UmVxdWVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Rlc3QvdjIvdW5pdC9pbnRlcm5hbC90c3NVdGlscy9lY2RzYU1QQ3YyL3NpZ25UeFJlcXVlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUE4UkEsd0RBS0M7QUFFRCw0REFLQztBQXpTRCw4Q0FVeUI7QUFDekIsb0RBQW1FO0FBQ25FLHlCQUF5QjtBQUN6QixzQ0FBcUM7QUFTckMsbUNBQW1DO0FBQ25DLDZCQUE2QjtBQUM3Qiw4Q0FBd0Q7QUFDeEQsK0NBQThDO0FBQzlDLE1BQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBTzNDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRTtJQUN6QixJQUFJLFFBQW9DLENBQUM7SUFDekMsSUFBSSxNQUFjLENBQUM7SUFDbkIsSUFBSSxLQUF5QixDQUFDO0lBQzlCLElBQUksUUFBa0IsQ0FBQztJQUN2QixJQUFJLFdBQThDLENBQUM7SUFDbkQsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDO0lBRXpCLE1BQU0sS0FBSyxHQUFHLElBQUksd0JBQWEsRUFBRSxDQUFDO0lBQ2xDLE1BQU0sV0FBVyxHQUFHLGVBQWUsQ0FBQztJQUNwQyxNQUFNLFdBQVcsR0FBRyxrRUFBa0UsQ0FBQztJQUN2RixNQUFNLFNBQVMsR0FBYztRQUMzQixXQUFXO1FBQ1gsWUFBWSxFQUFFLHNDQUFzQztRQUNwRCxZQUFZLEVBQUU7WUFDWjtnQkFDRSxVQUFVLEVBQUU7b0JBQ1YsZUFBZSxFQUFFLGtCQUFrQjtvQkFDbkMsV0FBVztvQkFDWCxjQUFjLEVBQUUsS0FBSyxFQUFFLDhDQUE4QztpQkFDdEU7Z0JBQ0QsS0FBSyxFQUFFLGtCQUFrQjtnQkFDekIsZUFBZSxFQUFFLEVBQUU7YUFDcEI7U0FDRjtRQUNELFdBQVcsRUFBRSxFQUFFO1FBQ2YsSUFBSSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMs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QUcsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO1FBQzlCLGlFQUFpRTtRQUVqRSxPQUFPO1lBQ0wsV0FBVyxFQUFFLFNBQVMsQ0FBQyxXQUFXO1NBQ25DLENBQUM7SUFDSixDQUFDLENBQUMsQ0FBQztBQUNQLENBQUM7QUFFRCxLQUFLLFVBQVUsaUJBQWlCLENBQUMsU0FBb0I7SUFDbkQsTUFBTSxZQUFZLEdBQUcsSUFBQSxpQkFBUSxFQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3ZDLE9BQU8sSUFBSSxDQUFDLHVCQUF1QixDQUFDO1NBQ2pDLElBQUksQ0FBQyxrQkFBa0IsU0FBUyxDQUFDLFFBQVEsZUFBZSxTQUFTLENBQUMsV0FBVyxHQUFHLFlBQVksT0FBTyxDQUFDO1NBQ3BHLEtBQUssQ0FBQyxDQUFDLENBQUM7U0FDUixLQUFLLENBQUMsR0FBRyxFQUFFO1FBQ1YsV0FBVyxFQUFFLFNBQVMsQ0FBQyxXQUFXO0tBQ25DLENBQUMsQ0FBQztBQUNQLENBQUM7QUFFRCxLQUFLLFVBQVUsd0NBQXdDLENBQ3JELElBQVksRUFDWixZQUFvQixFQUNwQixlQUFrRDtJQUVsRCxNQUFNLHlCQUF5QixHQUFzQjtRQUNuRCxJQUFJLEVBQUUsWUFBWTtRQUNsQixTQUFTLEVBQUUsZUFBZSxDQUFDLFNBQVM7UUFDcEMsY0FBYyxFQUFFLGVBQWUsQ0FBQyxTQUFTO1FBQ3pDLFlBQVk7S0FDYixDQUFDO0lBQ0YsSUFBSSxDQUFDLHVCQUF1QixDQUFDO1NBQzFCLEdBQUcsQ0FBQyxXQUFXLElBQUksYUFBYSxDQUFDO1NBQ2pDLEtBQUssQ0FBQyxDQUFDLENBQUM7U0FDUixLQUFLLENBQUMsRUFBRSxZQUFZLEVBQUUsQ0FBQztTQUN2QixLQUFLLENBQUMsR0FBRyxFQUFFLHlCQUF5QixDQUFDLENBQUM7SUFDekMsT0FBTyx5QkFBeUIsQ0FBQztBQUNuQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSGFzaCB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQge1xuICBCYXNlQ29pbixcbiAgQml0Z29HUEdQdWJsaWNLZXksXG4gIGNvbW1vbixcbiAgRUNEU0FVdGlscyxcbiAgUmVxdWVzdFRyYWNlcixcbiAgU2lnbmF0dXJlU2hhcmVSZWNvcmQsXG4gIFNpZ25hdHVyZVNoYXJlVHlwZSxcbiAgVHhSZXF1ZXN0LFxuICBXYWxsZXQsXG59IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBEa2xzRHNnLCBEa2xzVHlwZXMsIERrbHNDb21tcyB9IGZyb20gJ0BiaXRnby9zZGstbGliLW1wYyc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgeyBnZXRSb3V0ZSB9IGZyb20gJy4uL2NvbW1vbic7XG5pbXBvcnQge1xuICBNUEN2MlNpZ25hdHVyZVNoYXJlUm91bmQxT3V0cHV0LFxuICBNUEN2MlNpZ25hdHVyZVNoYXJlUm91bmQxSW5wdXQsXG4gIE1QQ3YyU2lnbmF0dXJlU2hhcmVSb3VuZDJJbnB1dCxcbiAgTVBDdjJTaWduYXR1cmVTaGFyZVJvdW5kMk91dHB1dCxcbiAgTVBDdjJTaWduYXR1cmVTaGFyZVJvdW5kM0lucHV0LFxuICBNUEN2MlBhcnR5RnJvbVN0cmluZ09yTnVtYmVyLFxufSBmcm9tICdAYml0Z28vcHVibGljLXR5cGVzJztcbmltcG9ydCAqIGFzIG9wZW5wZ3AgZnJvbSAnb3BlbnBncCc7XG5pbXBvcnQgKiBhcyBub2NrIGZyb20gJ25vY2snO1xuaW1wb3J0IHsgVGVzdGFibGVCRywgVGVzdEJpdEdvIH0gZnJvbSAnQGJpdGdvL3Nkay10ZXN0JztcbmltcG9ydCB7IEJpdEdvIH0gZnJvbSAnLi4vLi4vLi4vLi4vLi4vLi4vc3JjJztcbmNvbnN0IGNyZWF0ZUtlY2Nha0hhc2ggPSByZXF1aXJlKCdrZWNjYWsnKTtcblxuaW50ZXJmYWNlIFNpZ25hdHVyZVNoYXJlQXBpQm9keSB7XG4gIHNpZ25hdHVyZVNoYXJlczogU2lnbmF0dXJlU2hhcmVSZWNvcmRbXTtcbiAgc2lnbmVyR3BnUHVibGljS2V5OiBzdHJpbmc7XG59XG5cbmRlc2NyaWJlKCdzaWduVHhSZXF1ZXN0OicsIGZ1bmN0aW9uICgpIHtcbiAgbGV0IHRzc1V0aWxzOiBFQ0RTQVV0aWxzLkVjZHNhTVBDdjJVdGlscztcbiAgbGV0IHdhbGxldDogV2FsbGV0O1xuICBsZXQgYml0Z286IFRlc3RhYmxlQkcgJiBCaXRHbztcbiAgbGV0IGJhc2VDb2luOiBCYXNlQ29pbjtcbiAgbGV0IGJpdGdvR3BnS2V5OiBvcGVucGdwLlNlcmlhbGl6ZWRLZXlQYWlyPHN0cmluZz47XG4gIGNvbnN0IGNvaW5OYW1lID0gJ2h0ZXRoJztcblxuICBjb25zdCByZXFJZCA9IG5ldyBSZXF1ZXN0VHJhY2VyKCk7XG4gIGNvbnN0IHR4UmVxdWVzdElkID0gJ3JhbmRvbVR4UmVxSWQnO1xuICBjb25zdCBzaWduYWJsZUhleCA9ICdlMjdhZWNhZWE1NTlmYmVkYzlhZThhMjJiMGFiNjY1NGMyZDY4NjQwM2MyYWViNDM0YjMwMjU0NWM5NGVlZDNiJztcbiAgY29uc3QgdHhSZXF1ZXN0OiBUeFJlcXVlc3QgPSB7XG4gICAgdHhSZXF1ZXN0SWQsXG4gICAgZW50ZXJwcmlzZUlkOiAnNDUxN2FiZmItZjU2Ny00YjdhLTlmOTEtNDA3NTA5ZDI5NDAzJyxcbiAgICB0cmFuc2FjdGlvbnM6IFtcbiAgICAgIHtcbiAgICAgICAgdW5zaWduZWRUeDoge1xuICAgICAgICAgIHNlcmlhbGl6ZWRUeEhleDogJ1RPTyBNQU5ZIFNFQ1JFVFMnLFxuICAgICAgICAgIHNpZ25hYmxlSGV4LFxuICAgICAgICAgIGRlcml2YXRpb25QYXRoOiAnbS8wJywgLy8gTmVlZHMgdGhpcyB3aGVuIGtleSBkZXJpdmF0aW9uIGlzIHN1cHBvcnRlZFxuICAgICAgICB9LFxuICAgICAgICBzdGF0ZTogJ3BlbmRpbmdTaWduYXR1cmUnLFxuICAgICAgICBzaWduYXR1cmVTaGFyZXM6IFtdLFxuICAgICAgfSxcbiAgICBdLFxuICAgIHVuc2lnbmVkVHhzOiBbXSxcbiAgICBkYXRlOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgaW50ZW50OiB7XG4gICAgICBpbnRlbnRUeXBlOiAncGF5bWVudCcsXG4gICAgfSxcbiAgICBsYXRlc3Q6IHRydWUsXG4gICAgc3RhdGU6ICdwZW5kaW5nVXNlclNpZ25hdHVyZScsXG4gICAgd2FsbGV0VHlwZTogJ2hvdCcsXG4gICAgd2FsbGV0SWQ6ICd3YWxsZXRJZCcsXG4gICAgcG9saWNpZXNDaGVja2VkOiB0cnVlLFxuICAgIHZlcnNpb246IDEsXG4gICAgdXNlcklkOiAndXNlcklkJyxcbiAgICBhcGlWZXJzaW9uOiAnZnVsbCcsXG4gIH07XG5cbiAgY29uc3QgdHhSZXF1ZXN0Rm9yTWVzc2FnZVNpZ25pbmc6IFR4UmVxdWVzdCA9IHtcbiAgICB0eFJlcXVlc3RJZCxcbiAgICBlbnRlcnByaXNlSWQ6ICc0NTE3YWJmYi1mNTY3LTRiN2EtOWY5MS00MDc1MDlkMjk0MDMnLFxuICAgIG1lc3NhZ2VzOiBbXG4gICAgICB7XG4gICAgICAgIG1lc3NhZ2VSYXc6ICdUT08gTUFOWSBTRUNSRVRTJyxcbiAgICAgICAgZGVyaXZhdGlvblBhdGg6ICdtLzAnLFxuICAgICAgICBzdGF0ZTogJ3BlbmRpbmdTaWduYXR1cmUnLFxuICAgICAgICBzaWduYXR1cmVTaGFyZXM6IFtdLFxuICAgICAgfSxcbiAgICBdLFxuICAgIHVuc2lnbmVkVHhzOiBbXSxcbiAgICBkYXRlOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgaW50ZW50OiB7XG4gICAgICBpbnRlbnRUeXBlOiAncGF5bWVudCcsXG4gICAgfSxcbiAgICBsYXRlc3Q6IHRydWUsXG4gICAgc3RhdGU6ICdwZW5kaW5nVXNlclNpZ25hdHVyZScsXG4gICAgd2FsbGV0VHlwZTogJ2hvdCcsXG4gICAgd2FsbGV0SWQ6ICd3YWxsZXRJZCcsXG4gICAgcG9saWNpZXNDaGVja2VkOiB0cnVlLFxuICAgIHZlcnNpb246IDEsXG4gICAgdXNlcklkOiAndXNlcklkJyxcbiAgICBhcGlWZXJzaW9uOiAnZnVsbCcsXG4gIH07XG5cbiAgY29uc3QgdmVjdG9yID0ge1xuICAgIHBhcnR5MTogMCxcbiAgICBwYXJ0eTI6IDIsXG4gICAgcGFydHkzOiAxLFxuICB9O1xuICAvLyBUbyBnZW5lcmF0ZSB0aGUgZml4dHVyZXMsIHJ1biBES0cgYXMgaW4gdGhlIGRrbHNEa2cudHMgdGVzdHMgYW5kIHNhdmUgdGhlIHJlc3VsdGluZyBwYXJ0eS5nZXRLZXlTaGFyZSBpbiBhIGZpbGUgYnkgZG9pbmcgZnMud3JpdGVTeW5jKHBhcnR5LmdldEtleVNoYXJlKCkpLlxuICBjb25zdCBzaGFyZUZpbGVzID0gW1xuICAgIGAke19fZGlybmFtZX0vZml4dHVyZXMvdXNlclNoYXJlYCxcbiAgICBgJHtfX2Rpcm5hbWV9L2ZpeHR1cmVzL2JhY2t1cFNoYXJlYCxcbiAgICBgJHtfX2Rpcm5hbWV9L2ZpeHR1cmVzL2JpdGdvU2hhcmVgLFxuICBdO1xuXG4gIGxldCBiaXRnb1BhcnR5OiBEa2xzRHNnLkRzZztcblxuICBiZWZvcmUoYXN5bmMgKCkgPT4ge1xuICAgIGJpdGdvID0gVGVzdEJpdEdvLmRlY29yYXRlKEJpdEdvLCB7IGVudjogJ21vY2snIH0pO1xuICAgIGJpdGdvLmluaXRpYWxpemVUZXN0VmFycygpO1xuICAgIGNvbnN0IGJnVXJsID0gY29tbW9uLkVudmlyb25tZW50c1tiaXRnby5nZXRFbnYoKV0udXJpO1xuICAgIGJpdGdvR3BnS2V5ID0gYXdhaXQgb3BlbnBncC5nZW5lcmF0ZUtleSh7XG4gICAgICB1c2VySURzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiAnYml0Z28nLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgIGN1cnZlOiAnc2VjcDI1NmsxJyxcbiAgICAgIGNvbmZpZzoge1xuICAgICAgICByZWplY3RDdXJ2ZXM6IG5ldyBTZXQoKSxcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgY29uc3QgY29uc3RhbnRzID0ge1xuICAgICAgbXBjOiB7XG4gICAgICAgIGJpdGdvUHVibGljS2V5OiBiaXRnb0dwZ0tleS5wdWJsaWNLZXksXG4gICAgICAgIGJpdGdvTVBDdjJQdWJsaWNLZXk6IGJpdGdvR3BnS2V5LnB1YmxpY0tleSxcbiAgICAgIH0sXG4gICAgfTtcbiAgICBub2NrKGJnVXJsKS5nZXQoJy9hcGkvdjEvY2xpZW50L2NvbnN0YW50cycpLnRpbWVzKDIwKS5yZXBseSgyMDAsIHsgdHRsOiAzNjAwLCBjb25zdGFudHMgfSk7XG5cbiAgICBiYXNlQ29pbiA9IGJpdGdvLmNvaW4oY29pbk5hbWUpO1xuXG4gICAgbGV0IGhhc2hGbjogSGFzaDtcbiAgICB0cnkge1xuICAgICAgaGFzaEZuID0gYmFzZUNvaW4uZ2V0SGFzaEZ1bmN0aW9uKCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBoYXNoRm4gPSBjcmVhdGVLZWNjYWtIYXNoKCdrZWNjYWsyNTYnKSBhcyBIYXNoO1xuICAgIH1cbiAgICBjb25zdCBoYXNoQnVmZmVyID0gaGFzaEZuLnVwZGF0ZShCdWZmZXIuZnJvbShzaWduYWJsZUhleCwgJ2hleCcpKS5kaWdlc3QoKTtcblxuICAgIC8vIE5vY2sgb3V0IGJvdGggdGhlIHVzZXIgYW5kIGJpdGdvIHNpZGUgcmVzcG9uc2VzIHRvIGNyZWF0ZSB2YWxpZCBzaWduYXR1cmVzXG4gICAgYml0Z29QYXJ0eSA9IG5ldyBEa2xzRHNnLkRzZyhcbiAgICAgIGZzLnJlYWRGaWxlU3luYyhzaGFyZUZpbGVzW3ZlY3Rvci5wYXJ0eTJdKSxcbiAgICAgIHZlY3Rvci5wYXJ0eTIsXG4gICAgICB0eFJlcXVlc3QudHJhbnNhY3Rpb25zIVswXS51bnNpZ25lZFR4LmRlcml2YXRpb25QYXRoLFxuICAgICAgaGFzaEJ1ZmZlclxuICAgICk7XG4gICAgLy8gLy8gUm91bmQgMSAvLy8vXG4gICAgY29uc3Qgd2FsbGV0RGF0YSA9IHtcbiAgICAgIGlkOiB0eFJlcXVlc3Qud2FsbGV0SWQsXG4gICAgICBlbnRlcnByaXNlOiB0eFJlcXVlc3QuZW50ZXJwcmlzZUlkLFxuICAgICAgY29pbjogY29pbk5hbWUsXG4gICAgICBjb2luU3BlY2lmaWM6IHt9LFxuICAgICAgbXVsdGlzaWdUeXBlOiAndHNzJyxcbiAgICAgIG11bHRpc2lnVHlwZVZlcnNpb246ICdNUEN2MicsXG4gICAgfTtcbiAgICB3YWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCBiYXNlQ29pbiwgd2FsbGV0RGF0YSk7XG4gICAgdHNzVXRpbHMgPSBuZXcgRUNEU0FVdGlscy5FY2RzYU1QQ3YyVXRpbHMoYml0Z28sIGJhc2VDb2luLCB3YWxsZXQpO1xuICB9KTtcblxuICBiZWZvcmVFYWNoKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBhd2FpdCBub2NrR2V0Qml0Z29QdWJsaWNLZXlCYXNlZE9uRmVhdHVyZUZsYWdzKGNvaW5OYW1lLCB0eFJlcXVlc3QuZW50ZXJwcmlzZUlkISwgYml0Z29HcGdLZXkpO1xuICB9KTtcblxuICBhZnRlcihmdW5jdGlvbiAoKSB7XG4gICAgbm9jay5jbGVhbkFsbCgpO1xuICB9KTtcblxuICBhZnRlckVhY2goZnVuY3Rpb24gKCkge1xuICAgIGJpdGdvUGFydHkuZW5kU2Vzc2lvbigpO1xuICAgIG5vY2suY2xlYW5BbGwoKTtcbiAgfSk7XG5cbiAgaXQoJ3N1Y2Nlc3NmdWxseSBzaWducyBhIHR4UmVxdWVzdCB3aXRoIHVzZXIga2V5IGZvciBhIGRrbHMgaG90IHdhbGxldCB3aXRoIFdQJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IG5vY2tQcm9taXNlcyA9IFtcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRPbmUoYml0Z29QYXJ0eSwgdHhSZXF1ZXN0LCBiaXRnb0dwZ0tleSksXG4gICAgICBhd2FpdCBub2NrVHhSZXF1ZXN0UmVzcG9uc2VTaWduYXR1cmVTaGFyZVJvdW5kVHdvKGJpdGdvUGFydHksIHR4UmVxdWVzdCwgYml0Z29HcGdLZXkpLFxuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZFRocmVlKHR4UmVxdWVzdCksXG4gICAgICBhd2FpdCBub2NrU2VuZFR4UmVxdWVzdCh0eFJlcXVlc3QpLFxuICAgIF07XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwobm9ja1Byb21pc2VzKTtcblxuICAgIGNvbnN0IHVzZXJTaGFyZSA9IGZzLnJlYWRGaWxlU3luYyhzaGFyZUZpbGVzW3ZlY3Rvci5wYXJ0eTFdKTtcbiAgICBjb25zdCB1c2VyUHJ2QmFzZTY0ID0gQnVmZmVyLmZyb20odXNlclNoYXJlKS50b1N0cmluZygnYmFzZTY0Jyk7XG4gICAgYXdhaXQgdHNzVXRpbHMuc2lnblR4UmVxdWVzdCh7XG4gICAgICB0eFJlcXVlc3QsXG4gICAgICBwcnY6IHVzZXJQcnZCYXNlNjQsXG4gICAgICByZXFJZCxcbiAgICB9KTtcbiAgICBub2NrUHJvbWlzZXNbMF0uaXNEb25lKCkuc2hvdWxkLmJlLnRydWUoKTtcbiAgICBub2NrUHJvbWlzZXNbMV0uaXNEb25lKCkuc2hvdWxkLmJlLnRydWUoKTtcbiAgICBub2NrUHJvbWlzZXNbMl0uaXNEb25lKCkuc2hvdWxkLmJlLnRydWUoKTtcbiAgfSk7XG5cbiAgaXQoJ3N1Y2Nlc3NmdWxseSBzaWducyBhIHR4UmVxdWVzdCB3aXRoIGJhY2t1cCBrZXkgZm9yIGEgZGtscyBob3Qgd2FsbGV0IHdpdGggV1AnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3Qgbm9ja1Byb21pc2VzID0gW1xuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZE9uZShiaXRnb1BhcnR5LCB0eFJlcXVlc3QsIGJpdGdvR3BnS2V5LCAxKSxcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRUd28oYml0Z29QYXJ0eSwgdHhSZXF1ZXN0LCBiaXRnb0dwZ0tleSwgMSksXG4gICAgICBhd2FpdCBub2NrVHhSZXF1ZXN0UmVzcG9uc2VTaWduYXR1cmVTaGFyZVJvdW5kVGhyZWUodHhSZXF1ZXN0KSxcbiAgICAgIGF3YWl0IG5vY2tTZW5kVHhSZXF1ZXN0KHR4UmVxdWVzdCksXG4gICAgXTtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChub2NrUHJvbWlzZXMpO1xuXG4gICAgY29uc3QgYmFja3VwU2hhcmUgPSBmcy5yZWFkRmlsZVN5bmMoc2hhcmVGaWxlc1t2ZWN0b3IucGFydHkzXSk7XG4gICAgY29uc3QgYmFja3VwUHJ2QmFzZTY0ID0gQnVmZmVyLmZyb20oYmFja3VwU2hhcmUpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbiAgICBhd2FpdCB0c3NVdGlscy5zaWduVHhSZXF1ZXN0KHtcbiAgICAgIHR4UmVxdWVzdCxcbiAgICAgIHBydjogYmFja3VwUHJ2QmFzZTY0LFxuICAgICAgbXBjdjJQYXJ0eUlkOiAxLFxuICAgICAgcmVxSWQsXG4gICAgfSk7XG4gICAgbm9ja1Byb21pc2VzWzBdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzFdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzJdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gIH0pO1xuXG4gIGl0KCdzdWNjZXNzZnVsbHkgc2lnbnMgYSB0eFJlcXVlc3Qgd2l0aCBhIG1lc3NhZ2UgZm9yIGEgZGtscyBob3Qgd2FsbGV0IHdpdGggV1AnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3Qgbm9ja1Byb21pc2VzID0gW1xuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZE9uZShiaXRnb1BhcnR5LCB0eFJlcXVlc3RGb3JNZXNzYWdlU2lnbmluZywgYml0Z29HcGdLZXkpLFxuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZFR3byhiaXRnb1BhcnR5LCB0eFJlcXVlc3RGb3JNZXNzYWdlU2lnbmluZywgYml0Z29HcGdLZXkpLFxuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZFRocmVlKHR4UmVxdWVzdEZvck1lc3NhZ2VTaWduaW5nKSxcbiAgICAgIGF3YWl0IG5vY2tTZW5kVHhSZXF1ZXN0KHR4UmVxdWVzdEZvck1lc3NhZ2VTaWduaW5nKSxcbiAgICBdO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKG5vY2tQcm9taXNlcyk7XG5cbiAgICBjb25zdCB1c2VyU2hhcmUgPSBmcy5yZWFkRmlsZVN5bmMoc2hhcmVGaWxlc1t2ZWN0b3IucGFydHkxXSk7XG4gICAgY29uc3QgdXNlclBydkJhc2U2NCA9IEJ1ZmZlci5mcm9tKHVzZXJTaGFyZSkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICAgIGF3YWl0IHRzc1V0aWxzLnNpZ25UeFJlcXVlc3Qoe1xuICAgICAgdHhSZXF1ZXN0LFxuICAgICAgcHJ2OiB1c2VyUHJ2QmFzZTY0LFxuICAgICAgcmVxSWQsXG4gICAgfSk7XG4gICAgbm9ja1Byb21pc2VzWzBdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzFdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzJdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gIH0pO1xuXG4gIGl0KCdzdWNjZXNzZnVsbHkgc2lnbnMgYSB0eFJlcXVlc3QgZm9yIGEgZGtscyBob3Qgd2FsbGV0IGFmdGVyIHJlY2VpdmluZyBtdWx0aXBsZSA0MjkgZXJyb3JzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IG5vY2tQcm9taXNlcyA9IFtcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRPbmUoYml0Z29QYXJ0eSwgdHhSZXF1ZXN0LCBiaXRnb0dwZ0tleSksXG4gICAgICBhd2FpdCBub2NrVHhSZXF1ZXN0UmVzcG9uc2VTaWduYXR1cmVTaGFyZVJvdW5kVHdvKGJpdGdvUGFydHksIHR4UmVxdWVzdCwgYml0Z29HcGdLZXksIDAsIDMpLFxuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZFRocmVlKHR4UmVxdWVzdCksXG4gICAgICBhd2FpdCBub2NrU2VuZFR4UmVxdWVzdCh0eFJlcXVlc3QpLFxuICAgIF07XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwobm9ja1Byb21pc2VzKTtcblxuICAgIGNvbnN0IHVzZXJTaGFyZSA9IGZzLnJlYWRGaWxlU3luYyhzaGFyZUZpbGVzW3ZlY3Rvci5wYXJ0eTFdKTtcbiAgICBjb25zdCB1c2VyUHJ2QmFzZTY0ID0gQnVmZmVyLmZyb20odXNlclNoYXJlKS50b1N0cmluZygnYmFzZTY0Jyk7XG4gICAgYXdhaXQgdHNzVXRpbHMuc2lnblR4UmVxdWVzdCh7XG4gICAgICB0eFJlcXVlc3QsXG4gICAgICBwcnY6IHVzZXJQcnZCYXNlNjQsXG4gICAgICByZXFJZCxcbiAgICB9KTtcbiAgICBub2NrUHJvbWlzZXNbMF0uaXNEb25lKCkuc2hvdWxkLmJlLnRydWUoKTtcbiAgICBub2NrUHJvbWlzZXNbMV0uaXNEb25lKCkuc2hvdWxkLmJlLnRydWUoKTtcbiAgICBub2NrUHJvbWlzZXNbMl0uaXNEb25lKCkuc2hvdWxkLmJlLnRydWUoKTtcbiAgfSk7XG5cbiAgaXQoJ2ZhaWxzIHRvIHNpZ25zIGEgdHhSZXF1ZXN0IGZvciBhIGRrbHMgaG90IHdhbGxldCBhZnRlciByZWNlaXZpbmcgb3ZlciAzIDQyOSBlcnJvcnMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgY29uc3Qgbm9ja1Byb21pc2VzID0gW1xuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZE9uZShiaXRnb1BhcnR5LCB0eFJlcXVlc3QsIGJpdGdvR3BnS2V5KSxcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRUd28oYml0Z29QYXJ0eSwgdHhSZXF1ZXN0LCBiaXRnb0dwZ0tleSwgMCwgNCksXG4gICAgXTtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChub2NrUHJvbWlzZXMpO1xuXG4gICAgY29uc3QgdXNlclNoYXJlID0gZnMucmVhZEZpbGVTeW5jKHNoYXJlRmlsZXNbdmVjdG9yLnBhcnR5MV0pO1xuICAgIGNvbnN0IHVzZXJQcnZCYXNlNjQgPSBCdWZmZXIuZnJvbSh1c2VyU2hhcmUpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbiAgICBhd2FpdCB0c3NVdGlsc1xuICAgICAgLnNpZ25UeFJlcXVlc3Qoe1xuICAgICAgICB0eFJlcXVlc3QsXG4gICAgICAgIHBydjogdXNlclBydkJhc2U2NCxcbiAgICAgICAgcmVxSWQsXG4gICAgICB9KVxuICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ1RvbyBtYW55IHJlcXVlc3RzLCBzbG93IGRvd24hJyk7XG4gICAgbm9ja1Byb21pc2VzWzBdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzFdLmlzRG9uZSgpLnNob3VsZC5iZS5mYWxzZSgpO1xuICB9KTtcbn0pO1xuXG5leHBvcnQgZnVuY3Rpb24gZ2V0Qml0R29QYXJ0eUdwZ0tleVBydihrZXk6IG9wZW5wZ3AuU2VyaWFsaXplZEtleVBhaXI8c3RyaW5nPik6IERrbHNUeXBlcy5QYXJ0eUdwZ0tleSB7XG4gIHJldHVybiB7XG4gICAgcGFydHlJZDogMixcbiAgICBncGdLZXk6IGtleS5wcml2YXRlS2V5LFxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VXNlclBhcnR5R3BnS2V5UHVibGljKHVzZXJQdWJLZXk6IHN0cmluZywgcGFydHlJZDogMCB8IDEgPSAwKTogRGtsc1R5cGVzLlBhcnR5R3BnS2V5IHtcbiAgcmV0dXJuIHtcbiAgICBwYXJ0eUlkOiBwYXJ0eUlkLFxuICAgIGdwZ0tleTogdXNlclB1YktleSxcbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZE9uZShcbiAgYml0Z29TZXNzaW9uOiBEa2xzRHNnLkRzZyxcbiAgdHhSZXF1ZXN0OiBUeFJlcXVlc3QsXG4gIGJpdGdvR3BnS2V5OiBvcGVucGdwLlNlcmlhbGl6ZWRLZXlQYWlyPHN0cmluZz4sXG4gIHBhcnR5SWQ6IDAgfCAxID0gMFxuKTogUHJvbWlzZTxub2NrLlNjb3BlPiB7XG4gIGNvbnN0IHRyYW5zYWN0aW9ucyA9IGdldFJvdXRlKCdlY2RzYScpO1xuICByZXR1cm4gbm9jaygnaHR0cHM6Ly9iaXRnby5mYWtldXJsJylcbiAgICAucGVyc2lzdCh0cnVlKVxuICAgIC5wb3N0KFxuICAgICAgYC9hcGkvdjIvd2FsbGV0LyR7dHhSZXF1ZXN0LndhbGxldElkfS90eHJlcXVlc3RzLyR7dHhSZXF1ZXN0LnR4UmVxdWVzdElkICsgdHJhbnNhY3Rpb25zfS9zaWduYCxcbiAgICAgIChib2R5KSA9PiAoSlNPTi5wYXJzZShib2R5LnNpZ25hdHVyZVNoYXJlc1swXS5zaGFyZSkgYXMgTVBDdjJTaWduYXR1cmVTaGFyZVJvdW5kMUlucHV0KS50eXBlID09PSAncm91bmQxSW5wdXQnXG4gICAgKVxuICAgIC50aW1lcygxKVxuICAgIC5yZXBseSgyMDAsIGFzeW5jICh1cmksIGJvZHk6IFNpZ25hdHVyZVNoYXJlQXBpQm9keSkgPT4ge1xuICAgICAgLy8gRG8gdGhlIGFjdHVhbCBzaWduaW5nIG9uIEJpdEdvJ3Mgc2lkZSBiYXNlZCBvbiBVc2VyJ3MgbWVzc2FnZXNcbiAgICAgIGNvbnN0IHNpZ25hdHVyZVNoYXJlID0gSlNPTi5wYXJzZShib2R5LnNpZ25hdHVyZVNoYXJlc1swXS5zaGFyZSkgYXMgTVBDdjJTaWduYXR1cmVTaGFyZVJvdW5kMUlucHV0O1xuICAgICAgY29uc3QgZGVzZXJpYWxpemVkTWVzc2FnZXMgPSBEa2xzVHlwZXMuZGVzZXJpYWxpemVNZXNzYWdlcyh7XG4gICAgICAgIHAycE1lc3NhZ2VzOiBbXSxcbiAgICAgICAgYnJvYWRjYXN0TWVzc2FnZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBmcm9tOiBzaWduYXR1cmVTaGFyZS5kYXRhLm1zZzEuZnJvbSxcbiAgICAgICAgICAgIHBheWxvYWQ6IHNpZ25hdHVyZVNoYXJlLmRhdGEubXNnMS5tZXNzYWdlLFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICB9KTtcbiAgICAgIGlmIChzaWduYXR1cmVTaGFyZS50eXBlID09PSAncm91bmQxSW5wdXQnKSB7XG4gICAgICAgIGNvbnN0IGJpdGdvVG9Vc2VyUm91bmQxQnJvYWRjYXN0TXNnID0gYXdhaXQgYml0Z29TZXNzaW9uLmluaXQoKTtcblxuICAgICAgICBjb25zdCBiaXRnb1RvVXNlclJvdW5kMk1zZyA9IGJpdGdvU2Vzc2lvbi5oYW5kbGVJbmNvbWluZ01lc3NhZ2VzKHtcbiAgICAgICAgICBwMnBNZXNzYWdlczogW10sXG4gICAgICAgICAgYnJvYWRjYXN0TWVzc2FnZXM6IGRlc2VyaWFsaXplZE1lc3NhZ2VzLmJyb2FkY2FzdE1lc3NhZ2VzLFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3Qgc2VyaWFsaXplZEJpdEdvVG9Vc2VyUm91bmQxQW5kMk1zZ3MgPSBEa2xzVHlwZXMuc2VyaWFsaXplTWVzc2FnZXMoe1xuICAgICAgICAgIHAycE1lc3NhZ2VzOiBiaXRnb1RvVXNlclJvdW5kMk1zZy5wMnBNZXNzYWdlcyxcbiAgICAgICAgICBicm9hZGNhc3RNZXNzYWdlczogW2JpdGdvVG9Vc2VyUm91bmQxQnJvYWRjYXN0TXNnXSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgYXV0aEVuY01lc3NhZ2VzID0gYXdhaXQgRGtsc0NvbW1zLmVuY3J5cHRBbmRBdXRoT3V0Z29pbmdNZXNzYWdlcyhcbiAgICAgICAgICBzZXJpYWxpemVkQml0R29Ub1VzZXJSb3VuZDFBbmQyTXNncyxcbiAgICAgICAgICBbZ2V0VXNlclBhcnR5R3BnS2V5UHVibGljKGJvZHkuc2lnbmVyR3BnUHVibGljS2V5LCBwYXJ0eUlkKV0sXG4gICAgICAgICAgW2dldEJpdEdvUGFydHlHcGdLZXlQcnYoYml0Z29HcGdLZXkpXVxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IGJpdGdvVG9Vc2VyU2lnbmF0dXJlU2hhcmU6IE1QQ3YyU2lnbmF0dXJlU2hhcmVSb3VuZDFPdXRwdXQgPSB7XG4gICAgICAgICAgdHlwZTogJ3JvdW5kMU91dHB1dCcsXG4gICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgbXNnMToge1xuICAgICAgICAgICAgICBmcm9tOiBhdXRoRW5jTWVzc2FnZXMuYnJvYWRjYXN0TWVzc2FnZXNbMF0uZnJvbSBhcyBNUEN2MlBhcnR5RnJvbVN0cmluZ09yTnVtYmVyLFxuICAgICAgICAgICAgICBzaWduYXR1cmU6IGF1dGhFbmNNZXNzYWdlcy5icm9hZGNhc3RNZXNzYWdlc1swXS5wYXlsb2FkLnNpZ25hdHVyZSxcbiAgICAgICAgICAgICAgbWVzc2FnZTogYXV0aEVuY01lc3NhZ2VzLmJyb2FkY2FzdE1lc3NhZ2VzWzBdLnBheWxvYWQubWVzc2FnZSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBtc2cyOiB7XG4gICAgICAgICAgICAgIGZyb206IGF1dGhFbmNNZXNzYWdlcy5wMnBNZXNzYWdlc1swXS5mcm9tIGFzIE1QQ3YyUGFydHlGcm9tU3RyaW5nT3JOdW1iZXIsXG4gICAgICAgICAgICAgIHRvOiBhdXRoRW5jTWVzc2FnZXMucDJwTWVzc2FnZXNbMF0udG8gYXMgTVBDdjJQYXJ0eUZyb21TdHJpbmdPck51bWJlcixcbiAgICAgICAgICAgICAgZW5jcnlwdGVkTWVzc2FnZTogYXV0aEVuY01lc3NhZ2VzLnAycE1lc3NhZ2VzWzBdLnBheWxvYWQuZW5jcnlwdGVkTWVzc2FnZSxcbiAgICAgICAgICAgICAgc2lnbmF0dXJlOiBhdXRoRW5jTWVzc2FnZXMucDJwTWVzc2FnZXNbMF0ucGF5bG9hZC5zaWduYXR1cmUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdHhSZXF1ZXN0SWQ6IHR4UmVxdWVzdC50eFJlcXVlc3RJZCxcbiAgICAgICAgICB0cmFuc2FjdGlvbnM6IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgc2lnbmF0dXJlU2hhcmVzOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgZnJvbTogU2lnbmF0dXJlU2hhcmVUeXBlLkJJVEdPLFxuICAgICAgICAgICAgICAgICAgdG86IHBhcnR5SWQgPT09IDAgPyBTaWduYXR1cmVTaGFyZVR5cGUuVVNFUiA6IFNpZ25hdHVyZVNoYXJlVHlwZS5CQUNLVVAsXG4gICAgICAgICAgICAgICAgICBzaGFyZTogSlNPTi5zdHJpbmdpZnkoYml0Z29Ub1VzZXJTaWduYXR1cmVTaGFyZSksXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZFR3byhcbiAgYml0Z29TZXNzaW9uOiBEa2xzRHNnLkRzZyxcbiAgdHhSZXF1ZXN0OiBUeFJlcXVlc3QsXG4gIGJpdGdvR3BnS2V5OiBvcGVucGdwLlNlcmlhbGl6ZWRLZXlQYWlyPHN0cmluZz4sXG4gIHBhcnR5SWQ6IDAgfCAxID0gMCxcbiAgcmF0ZUxpbWl0RXJyb3JDb3VudCA9IDBcbik6IFByb21pc2U8bm9jay5TY29wZT4ge1xuICBjb25zdCB0cmFuc2FjdGlvbnMgPSBnZXRSb3V0ZSgnZWNkc2EnKTtcbiAgY29uc3Qgc2NvcGUgPSBub2NrKCdodHRwczovL2JpdGdvLmZha2V1cmwnKTtcblxuICBpZiAocmF0ZUxpbWl0RXJyb3JDb3VudCA+IDApIHtcbiAgICBzY29wZVxuICAgICAgLnBvc3QoXG4gICAgICAgIGAvYXBpL3YyL3dhbGxldC8ke3R4UmVxdWVzdC53YWxsZXRJZH0vdHhyZXF1ZXN0cy8ke3R4UmVxdWVzdC50eFJlcXVlc3RJZCArIHRyYW5zYWN0aW9uc30vc2lnbmAsXG4gICAgICAgIChib2R5KSA9PiAoSlNPTi5wYXJzZShib2R5LnNpZ25hdHVyZVNoYXJlc1swXS5zaGFyZSkgYXMgTVBDdjJTaWduYXR1cmVTaGFyZVJvdW5kMklucHV0KS50eXBlID09PSAncm91bmQySW5wdXQnXG4gICAgICApXG4gICAgICAudGltZXMocmF0ZUxpbWl0RXJyb3JDb3VudClcbiAgICAgIC5yZXBseSg0MjksIHtcbiAgICAgICAgZXJyb3I6ICdUb28gbWFueSByZXF1ZXN0cywgc2xvdyBkb3duIScsXG4gICAgICAgIG5hbWU6ICdUb29NYW55UmVxdWVzdHMnLFxuICAgICAgICByZXF1ZXN0SWQ6ICdjbTVxeDAxbGgwMDEzYjJlazJzeGw0dzAwJyxcbiAgICAgICAgY29udGV4dDoge30sXG4gICAgICB9KTtcbiAgfVxuICByZXR1cm4gc2NvcGVcbiAgICAucG9zdChcbiAgICAgIGAvYXBpL3YyL3dhbGxldC8ke3R4UmVxdWVzdC53YWxsZXRJZH0vdHhyZXF1ZXN0cy8ke3R4UmVxdWVzdC50eFJlcXVlc3RJZCArIHRyYW5zYWN0aW9uc30vc2lnbmAsXG4gICAgICAoYm9keSkgPT4gKEpTT04ucGFyc2UoYm9keS5zaWduYXR1cmVTaGFyZXNbMF0uc2hhcmUpIGFzIE1QQ3YyU2lnbmF0dXJlU2hhcmVSb3VuZDJJbnB1dCkudHlwZSA9PT0gJ3JvdW5kMklucHV0J1xuICAgIClcbiAgICAudGltZXMoMSlcbiAgICAucmVwbHkoMjAwLCBhc3luYyAodXJpLCBib2R5OiBTaWduYXR1cmVTaGFyZUFwaUJvZHkpID0+IHtcbiAgICAgIC8vIERvIHRoZSBhY3R1YWwgc2lnbmluZyBvbiBCaXRHbydzIHNpZGUgYmFzZWQgb24gVXNlcidzIG1lc3NhZ2VzXG4gICAgICBjb25zdCBwYXJzZWRTaWduYXR1cmVTaGFyZSA9IEpTT04ucGFyc2UoYm9keS5zaWduYXR1cmVTaGFyZXNbMF0uc2hhcmUpIGFzIE1QQ3YyU2lnbmF0dXJlU2hhcmVSb3VuZDJJbnB1dDtcbiAgICAgIGNvbnN0IHNlcmlhbGl6ZWRNZXNzYWdlcyA9IGF3YWl0IERrbHNDb21tcy5kZWNyeXB0QW5kVmVyaWZ5SW5jb21pbmdNZXNzYWdlcyhcbiAgICAgICAge1xuICAgICAgICAgIHAycE1lc3NhZ2VzOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGZyb206IHBhcnNlZFNpZ25hdHVyZVNoYXJlLmRhdGEubXNnMi5mcm9tLFxuICAgICAgICAgICAgICB0bzogcGFyc2VkU2lnbmF0dXJlU2hhcmUuZGF0YS5tc2cyLnRvLFxuICAgICAgICAgICAgICBwYXlsb2FkOiB7XG4gICAgICAgICAgICAgICAgZW5jcnlwdGVkTWVzc2FnZTogcGFyc2VkU2lnbmF0dXJlU2hhcmUuZGF0YS5tc2cyLmVuY3J5cHRlZE1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgc2lnbmF0dXJlOiBwYXJzZWRTaWduYXR1cmVTaGFyZS5kYXRhLm1zZzIuc2lnbmF0dXJlLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgZnJvbTogcGFyc2VkU2lnbmF0dXJlU2hhcmUuZGF0YS5tc2czLmZyb20sXG4gICAgICAgICAgICAgIHRvOiBwYXJzZWRTaWduYXR1cmVTaGFyZS5kYXRhLm1zZzMudG8sXG4gICAgICAgICAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAgICAgICAgICBlbmNyeXB0ZWRNZXNzYWdlOiBwYXJzZWRTaWduYXR1cmVTaGFyZS5kYXRhLm1zZzMuZW5jcnlwdGVkTWVzc2FnZSxcbiAgICAgICAgICAgICAgICBzaWduYXR1cmU6IHBhcnNlZFNpZ25hdHVyZVNoYXJlLmRhdGEubXNnMy5zaWduYXR1cmUsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIF0sXG4gICAgICAgICAgYnJvYWRjYXN0TWVzc2FnZXM6IFtdLFxuICAgICAgICB9LFxuICAgICAgICBbZ2V0VXNlclBhcnR5R3BnS2V5UHVibGljKGJvZHkuc2lnbmVyR3BnUHVibGljS2V5LCBwYXJ0eUlkKV0sXG4gICAgICAgIFtnZXRCaXRHb1BhcnR5R3BnS2V5UHJ2KGJpdGdvR3BnS2V5KV1cbiAgICAgICk7XG4gICAgICBjb25zdCBkZXNlcmlhbGl6ZWRNZXNzYWdlcyA9IERrbHNUeXBlcy5kZXNlcmlhbGl6ZU1lc3NhZ2VzKHtcbiAgICAgICAgcDJwTWVzc2FnZXM6IFtzZXJpYWxpemVkTWVzc2FnZXMucDJwTWVzc2FnZXNbMF1dLFxuICAgICAgICBicm9hZGNhc3RNZXNzYWdlczogW10sXG4gICAgICB9KTtcbiAgICAgIGlmIChwYXJzZWRTaWduYXR1cmVTaGFyZS50eXBlID09PSAncm91bmQySW5wdXQnKSB7XG4gICAgICAgIGNvbnN0IGJpdGdvVG9Vc2VyUm91bmQzTXNnID0gYml0Z29TZXNzaW9uLmhhbmRsZUluY29taW5nTWVzc2FnZXMoZGVzZXJpYWxpemVkTWVzc2FnZXMpO1xuICAgICAgICBjb25zdCBzZXJpYWxpemVkQml0R29Ub1VzZXJSb3VuZDNNc2dzID0gRGtsc1R5cGVzLnNlcmlhbGl6ZU1lc3NhZ2VzKGJpdGdvVG9Vc2VyUm91bmQzTXNnKTtcblxuICAgICAgICBjb25zdCBhdXRoRW5jTWVzc2FnZXMgPSBhd2FpdCBEa2xzQ29tbXMuZW5jcnlwdEFuZEF1dGhPdXRnb2luZ01lc3NhZ2VzKFxuICAgICAgICAgIHNlcmlhbGl6ZWRCaXRHb1RvVXNlclJvdW5kM01zZ3MsXG4gICAgICAgICAgW2dldFVzZXJQYXJ0eUdwZ0tleVB1YmxpYyhib2R5LnNpZ25lckdwZ1B1YmxpY0tleSwgcGFydHlJZCldLFxuICAgICAgICAgIFtnZXRCaXRHb1BhcnR5R3BnS2V5UHJ2KGJpdGdvR3BnS2V5KV1cbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCBiaXRnb1RvVXNlclNpZ25hdHVyZVNoYXJlOiBNUEN2MlNpZ25hdHVyZVNoYXJlUm91bmQyT3V0cHV0ID0ge1xuICAgICAgICAgIHR5cGU6ICdyb3VuZDJPdXRwdXQnLFxuICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgIG1zZzM6IHtcbiAgICAgICAgICAgICAgZnJvbTogYXV0aEVuY01lc3NhZ2VzLnAycE1lc3NhZ2VzWzBdLmZyb20gYXMgTVBDdjJQYXJ0eUZyb21TdHJpbmdPck51bWJlcixcbiAgICAgICAgICAgICAgdG86IGF1dGhFbmNNZXNzYWdlcy5wMnBNZXNzYWdlc1swXS50byBhcyBNUEN2MlBhcnR5RnJvbVN0cmluZ09yTnVtYmVyLFxuICAgICAgICAgICAgICBlbmNyeXB0ZWRNZXNzYWdlOiBhdXRoRW5jTWVzc2FnZXMucDJwTWVzc2FnZXNbMF0ucGF5bG9hZC5lbmNyeXB0ZWRNZXNzYWdlLFxuICAgICAgICAgICAgICBzaWduYXR1cmU6IGF1dGhFbmNNZXNzYWdlcy5wMnBNZXNzYWdlc1swXS5wYXlsb2FkLnNpZ25hdHVyZSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB0eFJlcXVlc3RJZDogdHhSZXF1ZXN0LnR4UmVxdWVzdElkLFxuICAgICAgICAgIHRyYW5zYWN0aW9uczogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBzaWduYXR1cmVTaGFyZXM6IFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICBmcm9tOiBwYXJ0eUlkID09PSAwID8gU2lnbmF0dXJlU2hhcmVUeXBlLlVTRVIgOiBTaWduYXR1cmVTaGFyZVR5cGUuQkFDS1VQLFxuICAgICAgICAgICAgICAgICAgdG86IFNpZ25hdHVyZVNoYXJlVHlwZS5CSVRHTyxcbiAgICAgICAgICAgICAgICAgIHNoYXJlOiAnc29tZSBvbGQgc2hhcmUgd2UgZG9udCBjYXJlIGFib3V0JyxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIGZyb206IFNpZ25hdHVyZVNoYXJlVHlwZS5CSVRHTyxcbiAgICAgICAgICAgICAgICAgIHRvOiBwYXJ0eUlkID09PSAwID8gU2lnbmF0dXJlU2hhcmVUeXBlLlVTRVIgOiBTaWduYXR1cmVTaGFyZVR5cGUuQkFDS1VQLFxuICAgICAgICAgICAgICAgICAgc2hhcmU6IEpTT04uc3RyaW5naWZ5KGJpdGdvVG9Vc2VyU2lnbmF0dXJlU2hhcmUpLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIF0sXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRUaHJlZSh0eFJlcXVlc3Q6IFR4UmVxdWVzdCk6IFByb21pc2U8bm9jay5TY29wZT4ge1xuICBjb25zdCB0cmFuc2FjdGlvbnMgPSBnZXRSb3V0ZSgnZWNkc2EnKTtcbiAgcmV0dXJuIG5vY2soJ2h0dHBzOi8vYml0Z28uZmFrZXVybCcpXG4gICAgLnBvc3QoXG4gICAgICBgL2FwaS92Mi93YWxsZXQvJHt0eFJlcXVlc3Qud2FsbGV0SWR9L3R4cmVxdWVzdHMvJHt0eFJlcXVlc3QudHhSZXF1ZXN0SWQgKyB0cmFuc2FjdGlvbnN9L3NpZ25gLFxuICAgICAgKGJvZHk6IFNpZ25hdHVyZVNoYXJlQXBpQm9keSkgPT5cbiAgICAgICAgKEpTT04ucGFyc2UoYm9keS5zaWduYXR1cmVTaGFyZXNbMF0uc2hhcmUpIGFzIE1QQ3YyU2lnbmF0dXJlU2hhcmVSb3VuZDNJbnB1dCkudHlwZSA9PT0gJ3JvdW5kM0lucHV0J1xuICAgIClcbiAgICAudGltZXMoMSlcbiAgICAucmVwbHkoMjAwLCBhc3luYyAodXJpLCBib2R5KSA9PiB7XG4gICAgICAvLyBEbyB0aGUgYWN0dWFsIHNpZ25pbmcgb24gQml0R28ncyBzaWRlIGJhc2VkIG9uIFVzZXIncyBtZXNzYWdlc1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICB0eFJlcXVlc3RJZDogdHhSZXF1ZXN0LnR4UmVxdWVzdElkLFxuICAgICAgfTtcbiAgICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gbm9ja1NlbmRUeFJlcXVlc3QodHhSZXF1ZXN0OiBUeFJlcXVlc3QpOiBQcm9taXNlPG5vY2suU2NvcGU+IHtcbiAgY29uc3QgdHJhbnNhY3Rpb25zID0gZ2V0Um91dGUoJ2VjZHNhJyk7XG4gIHJldHVybiBub2NrKCdodHRwczovL2JpdGdvLmZha2V1cmwnKVxuICAgIC5wb3N0KGAvYXBpL3YyL3dhbGxldC8ke3R4UmVxdWVzdC53YWxsZXRJZH0vdHhyZXF1ZXN0cy8ke3R4UmVxdWVzdC50eFJlcXVlc3RJZCArIHRyYW5zYWN0aW9uc30vc2VuZGApXG4gICAgLnRpbWVzKDEpXG4gICAgLnJlcGx5KDIwMCwge1xuICAgICAgdHhSZXF1ZXN0SWQ6IHR4UmVxdWVzdC50eFJlcXVlc3RJZCxcbiAgICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gbm9ja0dldEJpdGdvUHVibGljS2V5QmFzZWRPbkZlYXR1cmVGbGFncyhcbiAgY29pbjogc3RyaW5nLFxuICBlbnRlcnByaXNlSWQ6IHN0cmluZyxcbiAgYml0Z29HcGdLZXlQYWlyOiBvcGVucGdwLlNlcmlhbGl6ZWRLZXlQYWlyPHN0cmluZz5cbik6IFByb21pc2U8Qml0Z29HUEdQdWJsaWNLZXk+IHtcbiAgY29uc3QgYml0Z29HUEdQdWJsaWNLZXlSZXNwb25zZTogQml0Z29HUEdQdWJsaWNLZXkgPSB7XG4gICAgbmFtZTogJ2lycmVsZXZhbnQnLFxuICAgIHB1YmxpY0tleTogYml0Z29HcGdLZXlQYWlyLnB1YmxpY0tleSxcbiAgICBtcGN2MlB1YmxpY0tleTogYml0Z29HcGdLZXlQYWlyLnB1YmxpY0tleSxcbiAgICBlbnRlcnByaXNlSWQsXG4gIH07XG4gIG5vY2soJ2h0dHBzOi8vYml0Z28uZmFrZXVybCcpXG4gICAgLmdldChgL2FwaS92Mi8ke2NvaW59L3Rzcy9wdWJrZXlgKVxuICAgIC50aW1lcyg0KVxuICAgIC5xdWVyeSh7IGVudGVycHJpc2VJZCB9KVxuICAgIC5yZXBseSgyMDAsIGJpdGdvR1BHUHVibGljS2V5UmVzcG9uc2UpO1xuICByZXR1cm4gYml0Z29HUEdQdWJsaWNLZXlSZXNwb25zZTtcbn1cbiJdfQ==Выполнить команду
Для локальной разработки. Не используйте в интернете!