UNPKG

bitgo

Version:
431 lines • 63.5 kB
"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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnblR4UmVxdWVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Rlc3QvdjIvdW5pdC9pbnRlcm5hbC90c3NVdGlscy9lY2RzYU1QQ3YyL3NpZ25UeFJlcXVlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUE4UkEsd0RBS0M7QUFFRCw0REFLQztBQXpTRCw4Q0FVeUI7QUFDekIsb0RBQW1FO0FBQ25FLHlCQUF5QjtBQUN6QixzQ0FBcUM7QUFTckMsbUNBQW1DO0FBQ25DLDZCQUE4QjtBQUM5Qiw4Q0FBd0Q7QUFDeEQsK0NBQThDO0FBQzlDLE1BQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBTzNDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRTtJQUN6QixJQUFJLFFBQW9DLENBQUM7SUFDekMsSUFBSSxNQUFjLENBQUM7SUFDbkIsSUFBSSxLQUF5QixDQUFDO0lBQzlCLElBQUksUUFBa0IsQ0FBQztJQUN2QixJQUFJLFdBQThDLENBQUM7SUFDbkQsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDO0lBRXpCLE1BQU0sS0FBSyxHQUFHLElBQUksd0JBQWEsRUFBRSxDQUFDO0lBQ2xDLE1BQU0sV0FBVyxHQUFHLGVBQWUsQ0FBQztJQUNwQyxNQUFNLFdBQVcsR0FBRyxrRUFBa0UsQ0FBQztJQUN2RixNQUFNLFNBQVMsR0FBYztRQUMzQixXQUFXO1FBQ1gsWUFBWSxFQUFFLHNDQUFzQztRQUNwRCxZQUFZLEVBQUU7WUFDWjtnQkFDRSxVQUFVLEVBQUU7b0JBQ1YsZUFBZSxFQUFFLGtCQUFrQjtvQkFDbkMsV0FBVztvQkFDWCxjQUFjLEVBQUUsS0FBSyxFQUFFLDhDQUE4QztpQkFDdEU7Z0JBQ0QsS0FBSyxFQUFFLGtCQUFrQjtnQkFDekIsZUFBZSxFQUFFLEVBQUU7YUFDcEI7U0FDRjtRQUNELFdBQVcsRUFBRSxFQUFFO1FBQ2YsSUFBSSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMs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QUcsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO1FBQzlCLGlFQUFpRTtRQUVqRSxPQUFPO1lBQ0wsV0FBVyxFQUFFLFNBQVMsQ0FBQyxXQUFXO1NBQ25DLENBQUM7SUFDSixDQUFDLENBQUMsQ0FBQztBQUNQLENBQUM7QUFFRCxLQUFLLFVBQVUsaUJBQWlCLENBQUMsU0FBb0I7SUFDbkQsTUFBTSxZQUFZLEdBQUcsSUFBQSxpQkFBUSxFQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3ZDLE9BQU8sSUFBSSxDQUFDLHVCQUF1QixDQUFDO1NBQ2pDLElBQUksQ0FBQyxrQkFBa0IsU0FBUyxDQUFDLFFBQVEsZUFBZSxTQUFTLENBQUMsV0FBVyxHQUFHLFlBQVksT0FBTyxDQUFDO1NBQ3BHLEtBQUssQ0FBQyxDQUFDLENBQUM7U0FDUixLQUFLLENBQUMsR0FBRyxFQUFFO1FBQ1YsV0FBVyxFQUFFLFNBQVMsQ0FBQyxXQUFXO0tBQ25DLENBQUMsQ0FBQztBQUNQLENBQUM7QUFFRCxLQUFLLFVBQVUsd0NBQXdDLENBQ3JELElBQVksRUFDWixZQUFvQixFQUNwQixlQUFrRDtJQUVsRCxNQUFNLHlCQUF5QixHQUFzQjtRQUNuRCxJQUFJLEVBQUUsWUFBWTtRQUNsQixTQUFTLEVBQUUsZUFBZSxDQUFDLFNBQVM7UUFDcEMsY0FBYyxFQUFFLGVBQWUsQ0FBQyxTQUFTO1FBQ3pDLFlBQVk7S0FDYixDQUFDO0lBQ0YsSUFBSSxDQUFDLHVCQUF1QixDQUFDO1NBQzFCLEdBQUcsQ0FBQyxXQUFXLElBQUksYUFBYSxDQUFDO1NBQ2pDLEtBQUssQ0FBQyxDQUFDLENBQUM7U0FDUixLQUFLLENBQUMsRUFBRSxZQUFZLEVBQUUsQ0FBQztTQUN2QixLQUFLLENBQUMsR0FBRyxFQUFFLHlCQUF5QixDQUFDLENBQUM7SUFDekMsT0FBTyx5QkFBeUIsQ0FBQztBQUNuQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSGFzaCB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQge1xuICBCYXNlQ29pbixcbiAgQml0Z29HUEdQdWJsaWNLZXksXG4gIGNvbW1vbixcbiAgRUNEU0FVdGlscyxcbiAgUmVxdWVzdFRyYWNlcixcbiAgU2lnbmF0dXJlU2hhcmVSZWNvcmQsXG4gIFNpZ25hdHVyZVNoYXJlVHlwZSxcbiAgVHhSZXF1ZXN0LFxuICBXYWxsZXQsXG59IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBEa2xzRHNnLCBEa2xzVHlwZXMsIERrbHNDb21tcyB9IGZyb20gJ0BiaXRnby9zZGstbGliLW1wYyc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgeyBnZXRSb3V0ZSB9IGZyb20gJy4uL2NvbW1vbic7XG5pbXBvcnQge1xuICBNUEN2MlNpZ25hdHVyZVNoYXJlUm91bmQxT3V0cHV0LFxuICBNUEN2MlNpZ25hdHVyZVNoYXJlUm91bmQxSW5wdXQsXG4gIE1QQ3YyU2lnbmF0dXJlU2hhcmVSb3VuZDJJbnB1dCxcbiAgTVBDdjJTaWduYXR1cmVTaGFyZVJvdW5kMk91dHB1dCxcbiAgTVBDdjJTaWduYXR1cmVTaGFyZVJvdW5kM0lucHV0LFxuICBNUEN2MlBhcnR5RnJvbVN0cmluZ09yTnVtYmVyLFxufSBmcm9tICdAYml0Z28vcHVibGljLXR5cGVzJztcbmltcG9ydCAqIGFzIG9wZW5wZ3AgZnJvbSAnb3BlbnBncCc7XG5pbXBvcnQgbm9jayA9IHJlcXVpcmUoJ25vY2snKTtcbmltcG9ydCB7IFRlc3RhYmxlQkcsIFRlc3RCaXRHbyB9IGZyb20gJ0BiaXRnby9zZGstdGVzdCc7XG5pbXBvcnQgeyBCaXRHbyB9IGZyb20gJy4uLy4uLy4uLy4uLy4uLy4uL3NyYyc7XG5jb25zdCBjcmVhdGVLZWNjYWtIYXNoID0gcmVxdWlyZSgna2VjY2FrJyk7XG5cbmludGVyZmFjZSBTaWduYXR1cmVTaGFyZUFwaUJvZHkge1xuICBzaWduYXR1cmVTaGFyZXM6IFNpZ25hdHVyZVNoYXJlUmVjb3JkW107XG4gIHNpZ25lckdwZ1B1YmxpY0tleTogc3RyaW5nO1xufVxuXG5kZXNjcmliZSgnc2lnblR4UmVxdWVzdDonLCBmdW5jdGlvbiAoKSB7XG4gIGxldCB0c3NVdGlsczogRUNEU0FVdGlscy5FY2RzYU1QQ3YyVXRpbHM7XG4gIGxldCB3YWxsZXQ6IFdhbGxldDtcbiAgbGV0IGJpdGdvOiBUZXN0YWJsZUJHICYgQml0R287XG4gIGxldCBiYXNlQ29pbjogQmFzZUNvaW47XG4gIGxldCBiaXRnb0dwZ0tleTogb3BlbnBncC5TZXJpYWxpemVkS2V5UGFpcjxzdHJpbmc+O1xuICBjb25zdCBjb2luTmFtZSA9ICdodGV0aCc7XG5cbiAgY29uc3QgcmVxSWQgPSBuZXcgUmVxdWVzdFRyYWNlcigpO1xuICBjb25zdCB0eFJlcXVlc3RJZCA9ICdyYW5kb21UeFJlcUlkJztcbiAgY29uc3Qgc2lnbmFibGVIZXggPSAnZTI3YWVjYWVhNTU5ZmJlZGM5YWU4YTIyYjBhYjY2NTRjMmQ2ODY0MDNjMmFlYjQzNGIzMDI1NDVjOTRlZWQzYic7XG4gIGNvbnN0IHR4UmVxdWVzdDogVHhSZXF1ZXN0ID0ge1xuICAgIHR4UmVxdWVzdElkLFxuICAgIGVudGVycHJpc2VJZDogJzQ1MTdhYmZiLWY1NjctNGI3YS05ZjkxLTQwNzUwOWQyOTQwMycsXG4gICAgdHJhbnNhY3Rpb25zOiBbXG4gICAgICB7XG4gICAgICAgIHVuc2lnbmVkVHg6IHtcbiAgICAgICAgICBzZXJpYWxpemVkVHhIZXg6ICdUT08gTUFOWSBTRUNSRVRTJyxcbiAgICAgICAgICBzaWduYWJsZUhleCxcbiAgICAgICAgICBkZXJpdmF0aW9uUGF0aDogJ20vMCcsIC8vIE5lZWRzIHRoaXMgd2hlbiBrZXkgZGVyaXZhdGlvbiBpcyBzdXBwb3J0ZWRcbiAgICAgICAgfSxcbiAgICAgICAgc3RhdGU6ICdwZW5kaW5nU2lnbmF0dXJlJyxcbiAgICAgICAgc2lnbmF0dXJlU2hhcmVzOiBbXSxcbiAgICAgIH0sXG4gICAgXSxcbiAgICB1bnNpZ25lZFR4czogW10sXG4gICAgZGF0ZTogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgIGludGVudDoge1xuICAgICAgaW50ZW50VHlwZTogJ3BheW1lbnQnLFxuICAgIH0sXG4gICAgbGF0ZXN0OiB0cnVlLFxuICAgIHN0YXRlOiAncGVuZGluZ1VzZXJTaWduYXR1cmUnLFxuICAgIHdhbGxldFR5cGU6ICdob3QnLFxuICAgIHdhbGxldElkOiAnd2FsbGV0SWQnLFxuICAgIHBvbGljaWVzQ2hlY2tlZDogdHJ1ZSxcbiAgICB2ZXJzaW9uOiAxLFxuICAgIHVzZXJJZDogJ3VzZXJJZCcsXG4gICAgYXBpVmVyc2lvbjogJ2Z1bGwnLFxuICB9O1xuXG4gIGNvbnN0IHR4UmVxdWVzdEZvck1lc3NhZ2VTaWduaW5nOiBUeFJlcXVlc3QgPSB7XG4gICAgdHhSZXF1ZXN0SWQsXG4gICAgZW50ZXJwcmlzZUlkOiAnNDUxN2FiZmItZjU2Ny00YjdhLTlmOTEtNDA3NTA5ZDI5NDAzJyxcbiAgICBtZXNzYWdlczogW1xuICAgICAge1xuICAgICAgICBtZXNzYWdlUmF3OiAnVE9PIE1BTlkgU0VDUkVUUycsXG4gICAgICAgIGRlcml2YXRpb25QYXRoOiAnbS8wJyxcbiAgICAgICAgc3RhdGU6ICdwZW5kaW5nU2lnbmF0dXJlJyxcbiAgICAgICAgc2lnbmF0dXJlU2hhcmVzOiBbXSxcbiAgICAgIH0sXG4gICAgXSxcbiAgICB1bnNpZ25lZFR4czogW10sXG4gICAgZGF0ZTogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgIGludGVudDoge1xuICAgICAgaW50ZW50VHlwZTogJ3BheW1lbnQnLFxuICAgIH0sXG4gICAgbGF0ZXN0OiB0cnVlLFxuICAgIHN0YXRlOiAncGVuZGluZ1VzZXJTaWduYXR1cmUnLFxuICAgIHdhbGxldFR5cGU6ICdob3QnLFxuICAgIHdhbGxldElkOiAnd2FsbGV0SWQnLFxuICAgIHBvbGljaWVzQ2hlY2tlZDogdHJ1ZSxcbiAgICB2ZXJzaW9uOiAxLFxuICAgIHVzZXJJZDogJ3VzZXJJZCcsXG4gICAgYXBpVmVyc2lvbjogJ2Z1bGwnLFxuICB9O1xuXG4gIGNvbnN0IHZlY3RvciA9IHtcbiAgICBwYXJ0eTE6IDAsXG4gICAgcGFydHkyOiAyLFxuICAgIHBhcnR5MzogMSxcbiAgfTtcbiAgLy8gVG8gZ2VuZXJhdGUgdGhlIGZpeHR1cmVzLCBydW4gREtHIGFzIGluIHRoZSBka2xzRGtnLnRzIHRlc3RzIGFuZCBzYXZlIHRoZSByZXN1bHRpbmcgcGFydHkuZ2V0S2V5U2hhcmUgaW4gYSBmaWxlIGJ5IGRvaW5nIGZzLndyaXRlU3luYyhwYXJ0eS5nZXRLZXlTaGFyZSgpKS5cbiAgY29uc3Qgc2hhcmVGaWxlcyA9IFtcbiAgICBgJHtfX2Rpcm5hbWV9L2ZpeHR1cmVzL3VzZXJTaGFyZWAsXG4gICAgYCR7X19kaXJuYW1lfS9maXh0dXJlcy9iYWNrdXBTaGFyZWAsXG4gICAgYCR7X19kaXJuYW1lfS9maXh0dXJlcy9iaXRnb1NoYXJlYCxcbiAgXTtcblxuICBsZXQgYml0Z29QYXJ0eTogRGtsc0RzZy5Ec2c7XG5cbiAgYmVmb3JlKGFzeW5jICgpID0+IHtcbiAgICBiaXRnbyA9IFRlc3RCaXRHby5kZWNvcmF0ZShCaXRHbywgeyBlbnY6ICdtb2NrJyB9KTtcbiAgICBiaXRnby5pbml0aWFsaXplVGVzdFZhcnMoKTtcbiAgICBjb25zdCBiZ1VybCA9IGNvbW1vbi5FbnZpcm9ubWVudHNbYml0Z28uZ2V0RW52KCldLnVyaTtcbiAgICBiaXRnb0dwZ0tleSA9IGF3YWl0IG9wZW5wZ3AuZ2VuZXJhdGVLZXkoe1xuICAgICAgdXNlcklEczogW1xuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogJ2JpdGdvJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBjdXJ2ZTogJ3NlY3AyNTZrMScsXG4gICAgICBjb25maWc6IHtcbiAgICAgICAgcmVqZWN0Q3VydmVzOiBuZXcgU2V0KCksXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGNvbnN0IGNvbnN0YW50cyA9IHtcbiAgICAgIG1wYzoge1xuICAgICAgICBiaXRnb1B1YmxpY0tleTogYml0Z29HcGdLZXkucHVibGljS2V5LFxuICAgICAgICBiaXRnb01QQ3YyUHVibGljS2V5OiBiaXRnb0dwZ0tleS5wdWJsaWNLZXksXG4gICAgICB9LFxuICAgIH07XG4gICAgbm9jayhiZ1VybCkuZ2V0KCcvYXBpL3YxL2NsaWVudC9jb25zdGFudHMnKS50aW1lcygyMCkucmVwbHkoMjAwLCB7IHR0bDogMzYwMCwgY29uc3RhbnRzIH0pO1xuXG4gICAgYmFzZUNvaW4gPSBiaXRnby5jb2luKGNvaW5OYW1lKTtcblxuICAgIGxldCBoYXNoRm46IEhhc2g7XG4gICAgdHJ5IHtcbiAgICAgIGhhc2hGbiA9IGJhc2VDb2luLmdldEhhc2hGdW5jdGlvbigpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgaGFzaEZuID0gY3JlYXRlS2VjY2FrSGFzaCgna2VjY2FrMjU2JykgYXMgSGFzaDtcbiAgICB9XG4gICAgY29uc3QgaGFzaEJ1ZmZlciA9IGhhc2hGbi51cGRhdGUoQnVmZmVyLmZyb20oc2lnbmFibGVIZXgsICdoZXgnKSkuZGlnZXN0KCk7XG5cbiAgICAvLyBOb2NrIG91dCBib3RoIHRoZSB1c2VyIGFuZCBiaXRnbyBzaWRlIHJlc3BvbnNlcyB0byBjcmVhdGUgdmFsaWQgc2lnbmF0dXJlc1xuICAgIGJpdGdvUGFydHkgPSBuZXcgRGtsc0RzZy5Ec2coXG4gICAgICBmcy5yZWFkRmlsZVN5bmMoc2hhcmVGaWxlc1t2ZWN0b3IucGFydHkyXSksXG4gICAgICB2ZWN0b3IucGFydHkyLFxuICAgICAgdHhSZXF1ZXN0LnRyYW5zYWN0aW9ucyFbMF0udW5zaWduZWRUeC5kZXJpdmF0aW9uUGF0aCxcbiAgICAgIGhhc2hCdWZmZXJcbiAgICApO1xuICAgIC8vIC8vIFJvdW5kIDEgLy8vL1xuICAgIGNvbnN0IHdhbGxldERhdGEgPSB7XG4gICAgICBpZDogdHhSZXF1ZXN0LndhbGxldElkLFxuICAgICAgZW50ZXJwcmlzZTogdHhSZXF1ZXN0LmVudGVycHJpc2VJZCxcbiAgICAgIGNvaW46IGNvaW5OYW1lLFxuICAgICAgY29pblNwZWNpZmljOiB7fSxcbiAgICAgIG11bHRpc2lnVHlwZTogJ3RzcycsXG4gICAgICBtdWx0aXNpZ1R5cGVWZXJzaW9uOiAnTVBDdjInLFxuICAgIH07XG4gICAgd2FsbGV0ID0gbmV3IFdhbGxldChiaXRnbywgYmFzZUNvaW4sIHdhbGxldERhdGEpO1xuICAgIHRzc1V0aWxzID0gbmV3IEVDRFNBVXRpbHMuRWNkc2FNUEN2MlV0aWxzKGJpdGdvLCBiYXNlQ29pbiwgd2FsbGV0KTtcbiAgfSk7XG5cbiAgYmVmb3JlRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgYXdhaXQgbm9ja0dldEJpdGdvUHVibGljS2V5QmFzZWRPbkZlYXR1cmVGbGFncyhjb2luTmFtZSwgdHhSZXF1ZXN0LmVudGVycHJpc2VJZCEsIGJpdGdvR3BnS2V5KTtcbiAgfSk7XG5cbiAgYWZ0ZXIoZnVuY3Rpb24gKCkge1xuICAgIG5vY2suY2xlYW5BbGwoKTtcbiAgfSk7XG5cbiAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICBiaXRnb1BhcnR5LmVuZFNlc3Npb24oKTtcbiAgICBub2NrLmNsZWFuQWxsKCk7XG4gIH0pO1xuXG4gIGl0KCdzdWNjZXNzZnVsbHkgc2lnbnMgYSB0eFJlcXVlc3Qgd2l0aCB1c2VyIGtleSBmb3IgYSBka2xzIGhvdCB3YWxsZXQgd2l0aCBXUCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBub2NrUHJvbWlzZXMgPSBbXG4gICAgICBhd2FpdCBub2NrVHhSZXF1ZXN0UmVzcG9uc2VTaWduYXR1cmVTaGFyZVJvdW5kT25lKGJpdGdvUGFydHksIHR4UmVxdWVzdCwgYml0Z29HcGdLZXkpLFxuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZFR3byhiaXRnb1BhcnR5LCB0eFJlcXVlc3QsIGJpdGdvR3BnS2V5KSxcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRUaHJlZSh0eFJlcXVlc3QpLFxuICAgICAgYXdhaXQgbm9ja1NlbmRUeFJlcXVlc3QodHhSZXF1ZXN0KSxcbiAgICBdO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKG5vY2tQcm9taXNlcyk7XG5cbiAgICBjb25zdCB1c2VyU2hhcmUgPSBmcy5yZWFkRmlsZVN5bmMoc2hhcmVGaWxlc1t2ZWN0b3IucGFydHkxXSk7XG4gICAgY29uc3QgdXNlclBydkJhc2U2NCA9IEJ1ZmZlci5mcm9tKHVzZXJTaGFyZSkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICAgIGF3YWl0IHRzc1V0aWxzLnNpZ25UeFJlcXVlc3Qoe1xuICAgICAgdHhSZXF1ZXN0LFxuICAgICAgcHJ2OiB1c2VyUHJ2QmFzZTY0LFxuICAgICAgcmVxSWQsXG4gICAgfSk7XG4gICAgbm9ja1Byb21pc2VzWzBdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzFdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzJdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gIH0pO1xuXG4gIGl0KCdzdWNjZXNzZnVsbHkgc2lnbnMgYSB0eFJlcXVlc3Qgd2l0aCBiYWNrdXAga2V5IGZvciBhIGRrbHMgaG90IHdhbGxldCB3aXRoIFdQJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IG5vY2tQcm9taXNlcyA9IFtcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRPbmUoYml0Z29QYXJ0eSwgdHhSZXF1ZXN0LCBiaXRnb0dwZ0tleSwgMSksXG4gICAgICBhd2FpdCBub2NrVHhSZXF1ZXN0UmVzcG9uc2VTaWduYXR1cmVTaGFyZVJvdW5kVHdvKGJpdGdvUGFydHksIHR4UmVxdWVzdCwgYml0Z29HcGdLZXksIDEpLFxuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZFRocmVlKHR4UmVxdWVzdCksXG4gICAgICBhd2FpdCBub2NrU2VuZFR4UmVxdWVzdCh0eFJlcXVlc3QpLFxuICAgIF07XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwobm9ja1Byb21pc2VzKTtcblxuICAgIGNvbnN0IGJhY2t1cFNoYXJlID0gZnMucmVhZEZpbGVTeW5jKHNoYXJlRmlsZXNbdmVjdG9yLnBhcnR5M10pO1xuICAgIGNvbnN0IGJhY2t1cFBydkJhc2U2NCA9IEJ1ZmZlci5mcm9tKGJhY2t1cFNoYXJlKS50b1N0cmluZygnYmFzZTY0Jyk7XG4gICAgYXdhaXQgdHNzVXRpbHMuc2lnblR4UmVxdWVzdCh7XG4gICAgICB0eFJlcXVlc3QsXG4gICAgICBwcnY6IGJhY2t1cFBydkJhc2U2NCxcbiAgICAgIG1wY3YyUGFydHlJZDogMSxcbiAgICAgIHJlcUlkLFxuICAgIH0pO1xuICAgIG5vY2tQcm9taXNlc1swXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIG5vY2tQcm9taXNlc1sxXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIG5vY2tQcm9taXNlc1syXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICB9KTtcblxuICBpdCgnc3VjY2Vzc2Z1bGx5IHNpZ25zIGEgdHhSZXF1ZXN0IHdpdGggYSBtZXNzYWdlIGZvciBhIGRrbHMgaG90IHdhbGxldCB3aXRoIFdQJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IG5vY2tQcm9taXNlcyA9IFtcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRPbmUoYml0Z29QYXJ0eSwgdHhSZXF1ZXN0Rm9yTWVzc2FnZVNpZ25pbmcsIGJpdGdvR3BnS2V5KSxcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRUd28oYml0Z29QYXJ0eSwgdHhSZXF1ZXN0Rm9yTWVzc2FnZVNpZ25pbmcsIGJpdGdvR3BnS2V5KSxcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRUaHJlZSh0eFJlcXVlc3RGb3JNZXNzYWdlU2lnbmluZyksXG4gICAgICBhd2FpdCBub2NrU2VuZFR4UmVxdWVzdCh0eFJlcXVlc3RGb3JNZXNzYWdlU2lnbmluZyksXG4gICAgXTtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChub2NrUHJvbWlzZXMpO1xuXG4gICAgY29uc3QgdXNlclNoYXJlID0gZnMucmVhZEZpbGVTeW5jKHNoYXJlRmlsZXNbdmVjdG9yLnBhcnR5MV0pO1xuICAgIGNvbnN0IHVzZXJQcnZCYXNlNjQgPSBCdWZmZXIuZnJvbSh1c2VyU2hhcmUpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbiAgICBhd2FpdCB0c3NVdGlscy5zaWduVHhSZXF1ZXN0KHtcbiAgICAgIHR4UmVxdWVzdCxcbiAgICAgIHBydjogdXNlclBydkJhc2U2NCxcbiAgICAgIHJlcUlkLFxuICAgIH0pO1xuICAgIG5vY2tQcm9taXNlc1swXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIG5vY2tQcm9taXNlc1sxXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIG5vY2tQcm9taXNlc1syXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICB9KTtcblxuICBpdCgnc3VjY2Vzc2Z1bGx5IHNpZ25zIGEgdHhSZXF1ZXN0IGZvciBhIGRrbHMgaG90IHdhbGxldCBhZnRlciByZWNlaXZpbmcgbXVsdGlwbGUgNDI5IGVycm9ycycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBub2NrUHJvbWlzZXMgPSBbXG4gICAgICBhd2FpdCBub2NrVHhSZXF1ZXN0UmVzcG9uc2VTaWduYXR1cmVTaGFyZVJvdW5kT25lKGJpdGdvUGFydHksIHR4UmVxdWVzdCwgYml0Z29HcGdLZXkpLFxuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZFR3byhiaXRnb1BhcnR5LCB0eFJlcXVlc3QsIGJpdGdvR3BnS2V5LCAwLCAzKSxcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRUaHJlZSh0eFJlcXVlc3QpLFxuICAgICAgYXdhaXQgbm9ja1NlbmRUeFJlcXVlc3QodHhSZXF1ZXN0KSxcbiAgICBdO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKG5vY2tQcm9taXNlcyk7XG5cbiAgICBjb25zdCB1c2VyU2hhcmUgPSBmcy5yZWFkRmlsZVN5bmMoc2hhcmVGaWxlc1t2ZWN0b3IucGFydHkxXSk7XG4gICAgY29uc3QgdXNlclBydkJhc2U2NCA9IEJ1ZmZlci5mcm9tKHVzZXJTaGFyZSkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICAgIGF3YWl0IHRzc1V0aWxzLnNpZ25UeFJlcXVlc3Qoe1xuICAgICAgdHhSZXF1ZXN0LFxuICAgICAgcHJ2OiB1c2VyUHJ2QmFzZTY0LFxuICAgICAgcmVxSWQsXG4gICAgfSk7XG4gICAgbm9ja1Byb21pc2VzWzBdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzFdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzJdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gIH0pO1xuXG4gIGl0KCdmYWlscyB0byBzaWducyBhIHR4UmVxdWVzdCBmb3IgYSBka2xzIGhvdCB3YWxsZXQgYWZ0ZXIgcmVjZWl2aW5nIG92ZXIgMyA0MjkgZXJyb3JzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IG5vY2tQcm9taXNlcyA9IFtcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRPbmUoYml0Z2