@bitgo-beta/sdk-api 1.10.1-beta.1225 → 1.10.1-beta.1227
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +10 -7
- package/dist/test/unit/api.d.ts +2 -0
- package/dist/test/unit/api.d.ts.map +1 -0
- package/dist/test/unit/api.js +158 -0
- package/dist/test/unit/bitgoAPI.d.ts +2 -0
- package/dist/test/unit/bitgoAPI.d.ts.map +1 -0
- package/dist/test/unit/bitgoAPI.js +314 -0
- package/dist/test/unit/encrypt.d.ts +2 -0
- package/dist/test/unit/encrypt.d.ts.map +1 -0
- package/dist/test/unit/encrypt.js +62 -0
- package/dist/test/unit/utils.d.ts +2 -0
- package/dist/test/unit/utils.d.ts.map +1 -0
- package/dist/test/unit/utils.js +65 -0
- package/dist/test/unit/v1/fixtures/accelerate-tx.d.ts +4 -0
- package/dist/test/unit/v1/fixtures/accelerate-tx.d.ts.map +1 -0
- package/dist/test/unit/v1/fixtures/accelerate-tx.js +53 -0
- package/dist/test/unit/v1/fixtures/index.d.ts +3 -0
- package/dist/test/unit/v1/fixtures/index.d.ts.map +1 -0
- package/dist/test/unit/v1/fixtures/index.js +24 -0
- package/dist/test/unit/v1/signPsbt.d.ts +2 -0
- package/dist/test/unit/v1/signPsbt.d.ts.map +1 -0
- package/dist/test/unit/v1/signPsbt.js +53 -0
- package/dist/test/unit/v1/wallet.d.ts +2 -0
- package/dist/test/unit/v1/wallet.d.ts.map +1 -0
- package/dist/test/unit/v1/wallet.js +1378 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +10 -7
- package/.eslintignore +0 -5
- package/CHANGELOG.md +0 -1317
|
@@ -0,0 +1,1378 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//
|
|
3
|
+
// Tests for Wallet
|
|
4
|
+
//
|
|
5
|
+
// Copyright 2014, BitGo, Inc. All Rights Reserved.
|
|
6
|
+
//
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
const fixtures_1 = require("./fixtures");
|
|
45
|
+
const Wallet = require('../../../src/v1/wallet');
|
|
46
|
+
const bitgoAPI_1 = require("../../../src/bitgoAPI");
|
|
47
|
+
const _ = __importStar(require("lodash"));
|
|
48
|
+
const sdk_core_1 = require("@bitgo-beta/sdk-core");
|
|
49
|
+
const utxolib = __importStar(require("@bitgo-beta/utxo-lib"));
|
|
50
|
+
const should = __importStar(require("should"));
|
|
51
|
+
const nock_1 = __importDefault(require("nock"));
|
|
52
|
+
const sinon = __importStar(require("sinon"));
|
|
53
|
+
const accelerate_tx_1 = require("./fixtures/accelerate-tx");
|
|
54
|
+
nock_1.default.disableNetConnect();
|
|
55
|
+
const TestBitGo = {
|
|
56
|
+
TEST_WALLET1_PASSCODE: 'iVWeATjqLS1jJShrPpETti0b',
|
|
57
|
+
};
|
|
58
|
+
const originalFetchConstants = bitgoAPI_1.BitGoAPI.prototype.fetchConstants;
|
|
59
|
+
bitgoAPI_1.BitGoAPI.prototype.fetchConstants = function () {
|
|
60
|
+
(0, nock_1.default)(this._baseUrl).get('/api/v1/client/constants').reply(200, { ttl: 3600, constants: {} });
|
|
61
|
+
// force client constants reload
|
|
62
|
+
bitgoAPI_1.BitGoAPI['_constants'] = undefined;
|
|
63
|
+
return originalFetchConstants.apply(this, arguments);
|
|
64
|
+
};
|
|
65
|
+
describe('Wallet Prototype Methods', function () {
|
|
66
|
+
const fixtures = (0, accelerate_tx_1.getFixtures)();
|
|
67
|
+
let bitgo = new bitgoAPI_1.BitGoAPI({ env: 'test' });
|
|
68
|
+
// bitgo.initializeTestVars();
|
|
69
|
+
const userKeypair = {
|
|
70
|
+
xprv: 'xprv9s21ZrQH143K2fJ91S4BRsupcYrE6mmY96fcX5HkhoTrrwmwjd16Cn87cWinJjByrfpojjx7ezsJLx7TAKLT8m8hM5Kax9YcoxnBeJZ3t2k',
|
|
71
|
+
xpub: 'xpub661MyMwAqRbcF9Nc7TbBo1rZAagiWEVPWKbDKThNG8zqjk76HAKLkaSbTn6dK2dQPfuD7xjicxCZVWvj67fP5nQ9W7QURmoMVAX8m6jZsGp',
|
|
72
|
+
rawPub: '02c103ac74481874b5ef0f385d12725e4f14aedc9e00bc814ce96f47f62ce7adf2',
|
|
73
|
+
rawPrv: '936c5af3f8af81f75cdad1b08f29e7d9c01e598e2db2d7be18b9e5a8646e87c6',
|
|
74
|
+
path: 'm',
|
|
75
|
+
walletSubPath: '/0/0',
|
|
76
|
+
};
|
|
77
|
+
const backupKeypair = {
|
|
78
|
+
xprv: 'xprv9s21ZrQH143K47sEkLkykgYmq1xF5ZWrPYhUZcmBpPFMQojvGUmEcr5jFXYGfr8CpFdpTvhQ7L9NN2rLtsBFjSix3BAjwJcBj6U3D5hxTPc',
|
|
79
|
+
xpub: 'xpub661MyMwAqRbcGbwhrNHz7pVWP3njV2Ehkmd5N1AoNinLHc54p25VAeQD6q2oTS3uuDMDnfnXnthbS9ufC8JVYpNnWU5Rn3pYaNuLCNywkw1',
|
|
80
|
+
rawPub: '03bbcb73997977068d9e36666bbd5cd37579acae8e2bd5ce9d0a6e5c150a423bc3',
|
|
81
|
+
rawPrv: '77a15f14796f4001d1092ae84f766bd869e9bee6bffae6547def5045b96fa943',
|
|
82
|
+
path: 'm',
|
|
83
|
+
walletSubPath: '/0/0',
|
|
84
|
+
};
|
|
85
|
+
const bitgoKey = {
|
|
86
|
+
xpub: 'xpub661MyMwAqRbcGQcVFiwcrtc7c3vopsX96jsJUYPcFMREcRTqAqsqbv2ZRyCJAPLm5NMHCy85E3ZwpT4EAUw9WGU7vMhG6z83hDeKXBWn6Lf',
|
|
87
|
+
path: 'm',
|
|
88
|
+
walletSubPath: '/0/0',
|
|
89
|
+
};
|
|
90
|
+
const fakeWallet = new Wallet(bitgo, {
|
|
91
|
+
id: '2NCoSfHH6Ls4CdTS5QahgC9k7x9RfXeSwY4',
|
|
92
|
+
private: { keychains: [userKeypair, backupKeypair, bitgoKey] },
|
|
93
|
+
});
|
|
94
|
+
describe('Generate Address', function () {
|
|
95
|
+
before(() => nock_1.default.pendingMocks().should.be.empty());
|
|
96
|
+
it('generate first address', function () {
|
|
97
|
+
const idAddress = fakeWallet.generateAddress({ path: '/0/0', segwit: false });
|
|
98
|
+
idAddress.address.should.equal(fakeWallet.id());
|
|
99
|
+
idAddress.chain.should.equal(0);
|
|
100
|
+
idAddress.index.should.equal(0);
|
|
101
|
+
idAddress.chainPath.should.equal('/0/0');
|
|
102
|
+
idAddress.path.should.equal('/0/0');
|
|
103
|
+
idAddress.outputScript.should.equal('a914d682476e9bd54454a885f9dff1e604e99cef43dc87');
|
|
104
|
+
idAddress.redeemScript.should.equal('522102cd3c8e6006a4627705021d1d016d097c2944d98100a47bf2da67a5fe15aeeb342102ee1fa9e812e779356aa3c31ebf317d0cffebab92864cfe38bab223e0820f98bc21026ba05752baa6eafd5c5659da62b7f0ac51fd2886b65c241d0afef1c4fdfa1cbc53ae');
|
|
105
|
+
idAddress.wallet.should.equal(fakeWallet.id());
|
|
106
|
+
});
|
|
107
|
+
it('generate second address', function () {
|
|
108
|
+
const p2shAddress = fakeWallet.generateAddress({ path: '/0/1', segwit: false });
|
|
109
|
+
p2shAddress.address.should.equal('2N5y5RLVqdZi7qp5PmzMdPR6YvQzUqBQFWK');
|
|
110
|
+
p2shAddress.chain.should.equal(0);
|
|
111
|
+
p2shAddress.index.should.equal(1);
|
|
112
|
+
p2shAddress.chainPath.should.equal('/0/1');
|
|
113
|
+
p2shAddress.path.should.equal('/0/1');
|
|
114
|
+
p2shAddress.outputScript.should.equal('a9148b8bd3da68ef0f2465523146bd2de33c86b9c87187');
|
|
115
|
+
p2shAddress.redeemScript.should.equal('522102709edb6a2198d364c485a76b981d12065eabde8aa2d85bd7e7a035f7ecb3579b2102a724efed499c05fdb4da1e139700951fae00c006b3283888bdfd1b46979292242102b32abe44d61986ff57b835e3bd16293d93f303d0d8fb0454e2c9cceda5c4929853ae');
|
|
116
|
+
p2shAddress.wallet.should.equal(fakeWallet.id());
|
|
117
|
+
});
|
|
118
|
+
it('generate change address', function () {
|
|
119
|
+
const p2shAddress = fakeWallet.generateAddress({ path: '/1/0', segwit: false });
|
|
120
|
+
p2shAddress.address.should.equal('2NFj9JrpZc5MyYnCouyREtzNY4eoyKWDfgP');
|
|
121
|
+
p2shAddress.chain.should.equal(1);
|
|
122
|
+
p2shAddress.index.should.equal(0);
|
|
123
|
+
p2shAddress.chainPath.should.equal('/1/0');
|
|
124
|
+
p2shAddress.path.should.equal('/1/0');
|
|
125
|
+
p2shAddress.outputScript.should.equal('a914f69a81fad75ea65ad166da76515291679a4f1ad887');
|
|
126
|
+
p2shAddress.redeemScript.should.equal('5221020b4c4f891a5520f5a0b6818d8d53919552a0d4d806b5fa05c97708079d83737e2102c5cc49bf0331eb0b0890a7e7d87f7e9e0dea515438280dc76834c21d198efe08210370e52cf741ebf4513749d028839d696891eb789ba7a58592cfbc857cdc0a9de753ae');
|
|
127
|
+
p2shAddress.wallet.should.equal(fakeWallet.id());
|
|
128
|
+
});
|
|
129
|
+
it('generate segwit address', function () {
|
|
130
|
+
const segwitAddress = fakeWallet.generateAddress({ path: '/10/0', segwit: true });
|
|
131
|
+
segwitAddress.address.should.equal('2N5EVegRPWnmed2PpqDggZPw7DcNDguRYv8');
|
|
132
|
+
segwitAddress.chain.should.equal(10);
|
|
133
|
+
segwitAddress.index.should.equal(0);
|
|
134
|
+
segwitAddress.chainPath.should.equal('/10/0');
|
|
135
|
+
segwitAddress.path.should.equal('/10/0');
|
|
136
|
+
segwitAddress.outputScript.should.equal('a914837e2adcb6f6386fea3c5d40316b282ccf39121d87');
|
|
137
|
+
segwitAddress.redeemScript.should.equal('0020a62afee1d211c5adb9739f81ed4e36330e6cda651c7bdd314e32ccc465ec2203');
|
|
138
|
+
segwitAddress.witnessScript.should.equal('5221027b30505777a4ed8947b069fcb0116e287995d97278d84da4db6c613270649d3d21034c30e51f1e614cad667815c91d041404c18225d0b2f79e2c0bcb63fd2604316b2103b65ddfc06159b691693390761e75a0b8cc7a65b6ff305d094f3ad972f17953fe53ae');
|
|
139
|
+
segwitAddress.wallet.should.equal(fakeWallet.id());
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
describe('Create Transaction', function () {
|
|
143
|
+
let bgUrl, bgUrlTest;
|
|
144
|
+
let fakeProdWallet;
|
|
145
|
+
before(function () {
|
|
146
|
+
nock_1.default.pendingMocks().should.be.empty();
|
|
147
|
+
const prodBitgo = new bitgoAPI_1.BitGoAPI({ env: 'prod' });
|
|
148
|
+
// prodBitgo.initializeTestVars();
|
|
149
|
+
bgUrl = sdk_core_1.common.Environments[prodBitgo.getEnv()].uri;
|
|
150
|
+
fakeProdWallet = new Wallet(prodBitgo, {
|
|
151
|
+
id: '2NCoSfHH6Ls4CdTS5QahgC9k7x9RfXeSwY4',
|
|
152
|
+
private: { keychains: [userKeypair, backupKeypair, bitgoKey] },
|
|
153
|
+
});
|
|
154
|
+
bgUrlTest = sdk_core_1.common.Environments[bitgo.getEnv()].uri;
|
|
155
|
+
});
|
|
156
|
+
it('extra unspent fetch params', async function () {
|
|
157
|
+
const billingAddress = '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy';
|
|
158
|
+
const customUnspentsFetchParams = { test: 123 };
|
|
159
|
+
const sendAmount = 1e5;
|
|
160
|
+
(0, nock_1.default)(bgUrl).post('/api/v1/billing/address').reply(200, { address: billingAddress });
|
|
161
|
+
const scope = (0, nock_1.default)(bgUrl)
|
|
162
|
+
.get(`/api/v1/wallet/${fakeProdWallet.id()}/unspents`)
|
|
163
|
+
.query(_.merge(customUnspentsFetchParams, {
|
|
164
|
+
segwit: true,
|
|
165
|
+
target: sendAmount,
|
|
166
|
+
minSize: 0,
|
|
167
|
+
}))
|
|
168
|
+
.reply(200, { unspents: [] });
|
|
169
|
+
await fakeProdWallet
|
|
170
|
+
.createTransaction({
|
|
171
|
+
unspentsFetchParams: customUnspentsFetchParams,
|
|
172
|
+
recipients: { [billingAddress]: sendAmount },
|
|
173
|
+
feeRate: 10000,
|
|
174
|
+
bitgoFee: {
|
|
175
|
+
amount: 0,
|
|
176
|
+
address: '',
|
|
177
|
+
},
|
|
178
|
+
})
|
|
179
|
+
.should.be.rejectedWith('0 unspents available for transaction creation');
|
|
180
|
+
scope.isDone().should.be.true();
|
|
181
|
+
});
|
|
182
|
+
it('default p2sh', async function () {
|
|
183
|
+
const p2shAddress = fakeProdWallet.generateAddress({ path: '/0/13', segwit: false });
|
|
184
|
+
const unspent = {
|
|
185
|
+
addresses: ['2NCEDmmKNNnqKvnWw7pE3RLzuFe5aHHVy1X'],
|
|
186
|
+
value: '0.00504422',
|
|
187
|
+
value_int: 504422,
|
|
188
|
+
txid: 'b816ded89c3d8d5021b01097f4a3129a6a68a5cb7c886e97945f4205cba5de44',
|
|
189
|
+
n: 1,
|
|
190
|
+
script_pub_key: {
|
|
191
|
+
asm: 'OP_HASH160 d039cb3344294a5a384a5508a006444c420cbc11 OP_EQUAL',
|
|
192
|
+
hex: 'a914d039cb3344294a5a384a5508a006444c420cbc1187',
|
|
193
|
+
},
|
|
194
|
+
req_sigs: 1,
|
|
195
|
+
type: 'scripthash',
|
|
196
|
+
confirmations: 9,
|
|
197
|
+
id: 61330229,
|
|
198
|
+
};
|
|
199
|
+
_.extend(unspent, p2shAddress);
|
|
200
|
+
unspent.value = unspent.value_int;
|
|
201
|
+
unspent.tx_hash = unspent.txid;
|
|
202
|
+
unspent.tx_output_n = unspent.n;
|
|
203
|
+
unspent.script = unspent.outputScript;
|
|
204
|
+
(0, nock_1.default)(bgUrl).post('/api/v1/billing/address').reply(200, { address: '2MswQjkvN6oWYdE7L2brJ5cAAMjPmG59oco' });
|
|
205
|
+
const transaction = (await fakeProdWallet.createTransaction({
|
|
206
|
+
changeAddress: p2shAddress.address,
|
|
207
|
+
unspents: [unspent],
|
|
208
|
+
recipients: {},
|
|
209
|
+
noSplitChange: true,
|
|
210
|
+
forceChangeAtEnd: true,
|
|
211
|
+
feeRate: 10000,
|
|
212
|
+
bitgoFee: {
|
|
213
|
+
amount: 0,
|
|
214
|
+
address: '',
|
|
215
|
+
},
|
|
216
|
+
opReturns: { 'BitGo p2sh test': 1000 },
|
|
217
|
+
}));
|
|
218
|
+
transaction.transactionHex.should.equal('010000000144dea5cb05425f94976e887ccba5686a9a12a3f49710b021508d3d9cd8de16b80100000000ffffffff02e803000000000000116a0f426974476f2070327368207465737422a107000000000017a914d039cb3344294a5a384a5508a006444c420cbc118700000000');
|
|
219
|
+
// add first signature
|
|
220
|
+
transaction.keychain = userKeypair;
|
|
221
|
+
const signature1 = (await fakeProdWallet.signTransaction(transaction));
|
|
222
|
+
signature1.tx.should.equal('010000000144dea5cb05425f94976e887ccba5686a9a12a3f49710b021508d3d9cd8de16b801000000b600473044022021fa73d5fe61ac8942cd70ff4507c574677ce747de5bc46c3dd2e38ec2448fce022047906d2c0154337ab96041e8fb58c243b9bce5f8818fa991643c1260a1859ad80100004c695221031cd227e40ad61b4e137109cb2845eb6f5a584ed5c67d9d3135cdaa5045a842ea2103a2e7b54c7b2da0992555353b8e26c6acff4248f4351f08787bf3e2efc94b658321025c2a6cde33c2d73ccf12eecf64c54f08f722c2f073824498950695e9883b141253aeffffffff02e803000000000000116a0f426974476f2070327368207465737422a107000000000017a914d039cb3344294a5a384a5508a006444c420cbc118700000000');
|
|
223
|
+
// add second signature
|
|
224
|
+
transaction.transactionHex = signature1.tx;
|
|
225
|
+
transaction.keychain = backupKeypair;
|
|
226
|
+
transaction.fullLocalSigning = true;
|
|
227
|
+
const signature2 = (await fakeProdWallet.signTransaction(transaction));
|
|
228
|
+
// This transaction has actually worked: https://testnet.smartbit.com.au/tx/a8ccb928169032d6e1f37bf81dfd9ab6d90362a4f84e577397fa690aa711550c
|
|
229
|
+
// Note that the tx hex below no longer corresponds to the above transaction because our fee estimation has
|
|
230
|
+
// changed, changing the output amounts and thus the tx hex.
|
|
231
|
+
signature2.tx.should.equal('010000000144dea5cb05425f94976e887ccba5686a9a12a3f49710b021508d3d9cd8de16b801000000fdfd0000473044022021fa73d5fe61ac8942cd70ff4507c574677ce747de5bc46c3dd2e38ec2448fce022047906d2c0154337ab96041e8fb58c243b9bce5f8818fa991643c1260a1859ad80147304402202ae01f01b5ae0c3fa7d67ac73db81932cb5aca10db16a99063fef45e3f1398cd022055001ba7e163cb350910fc7321ecd7eb6359b321d4c04887484d9c7284b78c4701004c695221031cd227e40ad61b4e137109cb2845eb6f5a584ed5c67d9d3135cdaa5045a842ea2103a2e7b54c7b2da0992555353b8e26c6acff4248f4351f08787bf3e2efc94b658321025c2a6cde33c2d73ccf12eecf64c54f08f722c2f073824498950695e9883b141253aeffffffff02e803000000000000116a0f426974476f2070327368207465737422a107000000000017a914d039cb3344294a5a384a5508a006444c420cbc118700000000');
|
|
232
|
+
});
|
|
233
|
+
it('BCH p2sh', async function () {
|
|
234
|
+
const p2shAddress = fakeProdWallet.generateAddress({ path: '/0/13', segwit: false });
|
|
235
|
+
const unspent = {
|
|
236
|
+
addresses: ['2NCEDmmKNNnqKvnWw7pE3RLzuFe5aHHVy1X'],
|
|
237
|
+
value: '0.00504422',
|
|
238
|
+
value_int: 504422,
|
|
239
|
+
txid: 'b816ded89c3d8d5021b01097f4a3129a6a68a5cb7c886e97945f4205cba5de44',
|
|
240
|
+
n: 1,
|
|
241
|
+
script_pub_key: {
|
|
242
|
+
asm: 'OP_HASH160 d039cb3344294a5a384a5508a006444c420cbc11 OP_EQUAL',
|
|
243
|
+
hex: 'a914d039cb3344294a5a384a5508a006444c420cbc1187',
|
|
244
|
+
},
|
|
245
|
+
req_sigs: 1,
|
|
246
|
+
type: 'scripthash',
|
|
247
|
+
confirmations: 9,
|
|
248
|
+
id: 61330229,
|
|
249
|
+
};
|
|
250
|
+
_.extend(unspent, p2shAddress);
|
|
251
|
+
unspent.value = unspent.value_int;
|
|
252
|
+
unspent.tx_hash = unspent.txid;
|
|
253
|
+
unspent.tx_output_n = unspent.n;
|
|
254
|
+
unspent.script = unspent.outputScript;
|
|
255
|
+
(0, nock_1.default)(bgUrl).post('/api/v1/billing/address').reply(200, { address: '2MswQjkvN6oWYdE7L2brJ5cAAMjPmG59oco' });
|
|
256
|
+
const transaction = (await fakeProdWallet.createTransaction({
|
|
257
|
+
changeAddress: p2shAddress.address,
|
|
258
|
+
unspents: [unspent],
|
|
259
|
+
recipients: {},
|
|
260
|
+
noSplitChange: true,
|
|
261
|
+
forceChangeAtEnd: true,
|
|
262
|
+
feeRate: 10000,
|
|
263
|
+
bitgoFee: {
|
|
264
|
+
amount: 0,
|
|
265
|
+
address: '',
|
|
266
|
+
},
|
|
267
|
+
opReturns: { 'BitGo p2sh test': 1000 },
|
|
268
|
+
}));
|
|
269
|
+
transaction.transactionHex.should.equal('010000000144dea5cb05425f94976e887ccba5686a9a12a3f49710b021508d3d9cd8de16b80100000000ffffffff02e803000000000000116a0f426974476f2070327368207465737422a107000000000017a914d039cb3344294a5a384a5508a006444c420cbc118700000000');
|
|
270
|
+
// add first signature
|
|
271
|
+
transaction.keychain = userKeypair;
|
|
272
|
+
transaction.forceBCH = true;
|
|
273
|
+
const signature1 = (await fakeProdWallet.signTransaction(transaction));
|
|
274
|
+
signature1.tx.should.equal('010000000144dea5cb05425f94976e887ccba5686a9a12a3f49710b021508d3d9cd8de16b801000000b60047304402206221a97f081d87e02e3b14988a64861811a6a8de4f11f74f5aaea45981cf612e022077a08a5bd7d781e79838afbb126af2e48802fefad660afdbd8805f5e598ed5884100004c695221031cd227e40ad61b4e137109cb2845eb6f5a584ed5c67d9d3135cdaa5045a842ea2103a2e7b54c7b2da0992555353b8e26c6acff4248f4351f08787bf3e2efc94b658321025c2a6cde33c2d73ccf12eecf64c54f08f722c2f073824498950695e9883b141253aeffffffff02e803000000000000116a0f426974476f2070327368207465737422a107000000000017a914d039cb3344294a5a384a5508a006444c420cbc118700000000');
|
|
275
|
+
// add second signature
|
|
276
|
+
transaction.transactionHex = signature1.tx;
|
|
277
|
+
transaction.keychain = backupKeypair;
|
|
278
|
+
transaction.fullLocalSigning = true;
|
|
279
|
+
const signature2 = (await fakeProdWallet.signTransaction(transaction));
|
|
280
|
+
// this transaction has actually worked: https://testnet.smartbit.com.au/tx/a8ccb928169032d6e1f37bf81dfd9ab6d90362a4f84e577397fa690aa711550c
|
|
281
|
+
// Note that the tx hex below no longer corresponds to the above transaction because our fee estimation has
|
|
282
|
+
// changed, changing the output amounts and thus the tx hex.
|
|
283
|
+
signature2.tx.should.equal('010000000144dea5cb05425f94976e887ccba5686a9a12a3f49710b021508d3d9cd8de16b801000000fdfe000047304402206221a97f081d87e02e3b14988a64861811a6a8de4f11f74f5aaea45981cf612e022077a08a5bd7d781e79838afbb126af2e48802fefad660afdbd8805f5e598ed5884148304502210082bc546293858459f3895db24c85ccf37505c56f8faf4bb8f78cf40135bc2f2b02203dc1c78d7c7ceaf6b924eca3c39b95e8a227b069a07047581273136b47ca7ac441004c695221031cd227e40ad61b4e137109cb2845eb6f5a584ed5c67d9d3135cdaa5045a842ea2103a2e7b54c7b2da0992555353b8e26c6acff4248f4351f08787bf3e2efc94b658321025c2a6cde33c2d73ccf12eecf64c54f08f722c2f073824498950695e9883b141253aeffffffff02e803000000000000116a0f426974476f2070327368207465737422a107000000000017a914d039cb3344294a5a384a5508a006444c420cbc118700000000');
|
|
284
|
+
});
|
|
285
|
+
it('default segwit', async function () {
|
|
286
|
+
const segwitAddress = fakeProdWallet.generateAddress({ path: '/10/13', segwit: true });
|
|
287
|
+
const unspent = {
|
|
288
|
+
addresses: ['2MxKkH8yB3S9YWmTQRbvmborYQyQnH5petP'],
|
|
289
|
+
value: '0.18750000',
|
|
290
|
+
value_int: 18750000,
|
|
291
|
+
txid: '7d282878a85daee5d46e043827daed57596d75d1aa6e04fd0c09a36f9130881f',
|
|
292
|
+
n: 0,
|
|
293
|
+
script_pub_key: {
|
|
294
|
+
asm: 'OP_HASH160 37b393fce627a0ec634eb543dda1e608e2d1c78a OP_EQUAL',
|
|
295
|
+
hex: 'a91437b393fce627a0ec634eb543dda1e608e2d1c78a87',
|
|
296
|
+
},
|
|
297
|
+
req_sigs: 1,
|
|
298
|
+
type: 'scripthash',
|
|
299
|
+
confirmations: 0,
|
|
300
|
+
id: 61331617,
|
|
301
|
+
};
|
|
302
|
+
_.extend(unspent, segwitAddress);
|
|
303
|
+
unspent.value = unspent.value_int;
|
|
304
|
+
unspent.tx_hash = unspent.txid;
|
|
305
|
+
unspent.tx_output_n = unspent.n;
|
|
306
|
+
unspent.script = unspent.outputScript;
|
|
307
|
+
(0, nock_1.default)(bgUrl).post('/api/v1/billing/address').reply(200, { address: '2MswQjkvN6oWYdE7L2brJ5cAAMjPmG59oco' });
|
|
308
|
+
const transaction = (await fakeProdWallet.createTransaction({
|
|
309
|
+
changeAddress: segwitAddress.address,
|
|
310
|
+
unspents: [unspent],
|
|
311
|
+
recipients: {},
|
|
312
|
+
noSplitChange: true,
|
|
313
|
+
forceChangeAtEnd: true,
|
|
314
|
+
feeRate: 10000,
|
|
315
|
+
bitgoFee: {
|
|
316
|
+
amount: 0,
|
|
317
|
+
address: '',
|
|
318
|
+
},
|
|
319
|
+
opReturns: { 'BitGo segwit test': 1000 },
|
|
320
|
+
}));
|
|
321
|
+
transaction.transactionHex.should.equal('01000000011f8830916fa3090cfd046eaad1756d5957edda2738046ed4e5ae5da87828287d0000000000ffffffff02e803000000000000136a11426974476f2073656777697420746573740e0f1e010000000017a91437b393fce627a0ec634eb543dda1e608e2d1c78a8700000000');
|
|
322
|
+
// add first signature
|
|
323
|
+
transaction.keychain = userKeypair;
|
|
324
|
+
const signature1 = (await fakeProdWallet.signTransaction(transaction));
|
|
325
|
+
signature1.tx.should.equal('010000000001011f8830916fa3090cfd046eaad1756d5957edda2738046ed4e5ae5da87828287d0000000023220020440e858228b753544b4c57e300296b55717f811053883f9be9b6a712eacd931cffffffff02e803000000000000136a11426974476f2073656777697420746573740e0f1e010000000017a91437b393fce627a0ec634eb543dda1e608e2d1c78a870500483045022100bf3a8914a1bfe92661f27ca37c0d6b5c0b3c7353614c955646929f2e7eb89ffe02202d556b0ffab37c104bae67406ca16f8859cfa37c6a40f2013d89afcecd5594f3010000695221032c505fc8a1e4b56811b27366a371e61c9faf565dd2fabaff7a70eac19c32157c210251160b583bd5dc0f0d48096505131c4347ab65b4f21ed57d76c38157499c003d2102679712d62a2560917cc43fd2cc3a1b9b61f528c88bc64905bae6ee079e60609f53ae00000000');
|
|
326
|
+
// add second signature
|
|
327
|
+
transaction.transactionHex = signature1.tx;
|
|
328
|
+
transaction.keychain = backupKeypair;
|
|
329
|
+
transaction.fullLocalSigning = true;
|
|
330
|
+
const signature2 = (await fakeProdWallet.signTransaction(transaction));
|
|
331
|
+
// this transaction has actually worked: https://testnet.smartbit.com.au/tx/d67266f1de905baaee750011fa4b3d88a8e3a1758d5173a659c67709488dde07
|
|
332
|
+
// Note that the tx hex below no longer corresponds to the above transaction because our fee estimation has
|
|
333
|
+
// changed, changing the output amounts and thus the tx hex.
|
|
334
|
+
signature2.tx.should.equal('010000000001011f8830916fa3090cfd046eaad1756d5957edda2738046ed4e5ae5da87828287d0000000023220020440e858228b753544b4c57e300296b55717f811053883f9be9b6a712eacd931cffffffff02e803000000000000136a11426974476f2073656777697420746573740e0f1e010000000017a91437b393fce627a0ec634eb543dda1e608e2d1c78a870500483045022100bf3a8914a1bfe92661f27ca37c0d6b5c0b3c7353614c955646929f2e7eb89ffe02202d556b0ffab37c104bae67406ca16f8859cfa37c6a40f2013d89afcecd5594f30147304402205cf8d2f2be6ce083d35654bdc3fa85d7e71b227d457e9245bb603b21e7b5165102203ea686226db8320e08c26bfb304048b3a9473d0e05797d3658dacb2f09a2b51c0100695221032c505fc8a1e4b56811b27366a371e61c9faf565dd2fabaff7a70eac19c32157c210251160b583bd5dc0f0d48096505131c4347ab65b4f21ed57d76c38157499c003d2102679712d62a2560917cc43fd2cc3a1b9b61f528c88bc64905bae6ee079e60609f53ae00000000');
|
|
335
|
+
});
|
|
336
|
+
it('creates an unsigned tx made of uncompressed public keys of v1 safe wallet', async function () {
|
|
337
|
+
const { address, redeemScript, scriptPubKey } = await (0, fixtures_1.getFixture)(`${__dirname}/fixtures/sign-transaction.json`);
|
|
338
|
+
const testBitgo = new bitgoAPI_1.BitGoAPI({ env: 'test' });
|
|
339
|
+
const fakeTestV1SafeWallet = new Wallet(testBitgo, {
|
|
340
|
+
id: address,
|
|
341
|
+
private: { safe: { redeemScript } },
|
|
342
|
+
});
|
|
343
|
+
const unspentsToSpend = [
|
|
344
|
+
{
|
|
345
|
+
value: 100000,
|
|
346
|
+
redeemScript,
|
|
347
|
+
script: scriptPubKey,
|
|
348
|
+
tx_hash: 'a55d11dc8b701bd19601fbfe711a1e465fc8f128ec4474e78e1fd087e808e5fe',
|
|
349
|
+
tx_output_n: 0,
|
|
350
|
+
confirmations: 1,
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
value: 100000,
|
|
354
|
+
redeemScript,
|
|
355
|
+
script: scriptPubKey,
|
|
356
|
+
tx_hash: '48fb879cec879356045a331937023aed859f5dc5db955a1dc8a5ccf29f49d108',
|
|
357
|
+
tx_output_n: 0,
|
|
358
|
+
confirmations: 1,
|
|
359
|
+
},
|
|
360
|
+
];
|
|
361
|
+
const recipients = {
|
|
362
|
+
'2MyGxrhLC4kRfuVjLqCVYFtC7DchhgMCiNz': 191340, // purposely set to simulate a sweep transaction
|
|
363
|
+
};
|
|
364
|
+
const scope = (0, nock_1.default)(bgUrlTest)
|
|
365
|
+
.post('/api/v1/billing/address')
|
|
366
|
+
.reply(200, { address: '2N3L9cu9WN2Df7Xvb1Y8owokuDVj5Hdyv4i' });
|
|
367
|
+
const result = await fakeTestV1SafeWallet.createTransaction({
|
|
368
|
+
recipients,
|
|
369
|
+
unspents: unspentsToSpend,
|
|
370
|
+
feeRate: 10000, // 10 sat/byte
|
|
371
|
+
bitgoFee: {
|
|
372
|
+
amount: 0,
|
|
373
|
+
address: '',
|
|
374
|
+
},
|
|
375
|
+
});
|
|
376
|
+
scope.isDone().should.be.true();
|
|
377
|
+
result.estimatedSize.should.equal(866);
|
|
378
|
+
result.fee.should.equal(8660);
|
|
379
|
+
// This should equal to 1 because this is a sweep transaction but due to hardcoded addition of
|
|
380
|
+
// 1 change output in transactionBuilder, it is 2.
|
|
381
|
+
// Because of this the estimated size of the transactions is more than what it actually is in the hex.
|
|
382
|
+
result.txInfo.nOutputs.should.equal(2);
|
|
383
|
+
});
|
|
384
|
+
it('signs an unsigned tx made of uncompressed public keys of v1 safe wallet & verifies signatures', async function () {
|
|
385
|
+
const { address, redeemScript, scriptPubKey, userKeyWIF: userSigningKey, bitgoKeyWIF: bitgoSigningKey, unsignedTxHex, halfSignedTxHex, fullSignedTxHex, } = await (0, fixtures_1.getFixture)(`${__dirname}/fixtures/sign-transaction.json`);
|
|
386
|
+
const testBitgo = new bitgoAPI_1.BitGoAPI({ env: 'test' });
|
|
387
|
+
const fakeTestV1SafeWallet = new Wallet(testBitgo, {
|
|
388
|
+
id: address,
|
|
389
|
+
private: { safe: { redeemScript } },
|
|
390
|
+
});
|
|
391
|
+
const unspentsToSpend = [
|
|
392
|
+
{ value: 100000, redeemScript, script: scriptPubKey },
|
|
393
|
+
{ value: 100000, redeemScript, script: scriptPubKey },
|
|
394
|
+
];
|
|
395
|
+
const halfSignedTx = await fakeTestV1SafeWallet.signTransaction({
|
|
396
|
+
transactionHex: unsignedTxHex,
|
|
397
|
+
signingKey: userSigningKey,
|
|
398
|
+
unspents: unspentsToSpend,
|
|
399
|
+
validate: true,
|
|
400
|
+
});
|
|
401
|
+
halfSignedTx.tx.should.equal(halfSignedTxHex);
|
|
402
|
+
const fullSignedTx = await fakeTestV1SafeWallet.signTransaction({
|
|
403
|
+
transactionHex: halfSignedTxHex,
|
|
404
|
+
signingKey: bitgoSigningKey,
|
|
405
|
+
unspents: unspentsToSpend,
|
|
406
|
+
validate: true,
|
|
407
|
+
fullLocalSigning: true,
|
|
408
|
+
});
|
|
409
|
+
// Upon calling txb.build() instead after getting 2 valid signatures, we get a valid full signed tx that was broadcast
|
|
410
|
+
// and confirmed on testnet here: https://mempool.space/testnet/tx/bde09f1bd5e6661c28d90e4c96291853e21ba15ab42f3e4a30719decb73e791b
|
|
411
|
+
// It's present in the fullSignedTxHexBuildComplete property of the fixture.
|
|
412
|
+
fullSignedTx.tx.should.equal(fullSignedTxHex);
|
|
413
|
+
});
|
|
414
|
+
it('BCH segwit should fail', async function () {
|
|
415
|
+
const segwitAddress = fakeProdWallet.generateAddress({ path: '/10/13', segwit: true });
|
|
416
|
+
const unspent = {
|
|
417
|
+
addresses: ['2MxKkH8yB3S9YWmTQRbvmborYQyQnH5petP'],
|
|
418
|
+
value: '0.18750000',
|
|
419
|
+
value_int: 18750000,
|
|
420
|
+
txid: '7d282878a85daee5d46e043827daed57596d75d1aa6e04fd0c09a36f9130881f',
|
|
421
|
+
n: 0,
|
|
422
|
+
script_pub_key: {
|
|
423
|
+
asm: 'OP_HASH160 37b393fce627a0ec634eb543dda1e608e2d1c78a OP_EQUAL',
|
|
424
|
+
hex: 'a91437b393fce627a0ec634eb543dda1e608e2d1c78a87',
|
|
425
|
+
},
|
|
426
|
+
req_sigs: 1,
|
|
427
|
+
type: 'scripthash',
|
|
428
|
+
confirmations: 0,
|
|
429
|
+
id: 61331617,
|
|
430
|
+
};
|
|
431
|
+
_.extend(unspent, segwitAddress);
|
|
432
|
+
unspent.value = unspent.value_int;
|
|
433
|
+
unspent.tx_hash = unspent.txid;
|
|
434
|
+
unspent.tx_output_n = unspent.n;
|
|
435
|
+
unspent.script = unspent.outputScript;
|
|
436
|
+
(0, nock_1.default)(bgUrl).post('/api/v1/billing/address').reply(200, { address: '2MswQjkvN6oWYdE7L2brJ5cAAMjPmG59oco' });
|
|
437
|
+
const transaction = (await fakeProdWallet.createTransaction({
|
|
438
|
+
changeAddress: segwitAddress.address,
|
|
439
|
+
unspents: [unspent],
|
|
440
|
+
recipients: {},
|
|
441
|
+
noSplitChange: true,
|
|
442
|
+
forceChangeAtEnd: true,
|
|
443
|
+
feeRate: 10000,
|
|
444
|
+
bitgoFee: {
|
|
445
|
+
amount: 0,
|
|
446
|
+
address: '',
|
|
447
|
+
},
|
|
448
|
+
opReturns: { 'BitGo segwit test': 1000 },
|
|
449
|
+
}));
|
|
450
|
+
transaction.transactionHex.should.equal('01000000011f8830916fa3090cfd046eaad1756d5957edda2738046ed4e5ae5da87828287d0000000000ffffffff02e803000000000000136a11426974476f2073656777697420746573740e0f1e010000000017a91437b393fce627a0ec634eb543dda1e608e2d1c78a8700000000');
|
|
451
|
+
// add first signature
|
|
452
|
+
transaction.keychain = userKeypair;
|
|
453
|
+
transaction.forceBCH = true;
|
|
454
|
+
(() => fakeProdWallet.signTransaction(transaction)).should.throw('BCH does not support segwit inputs');
|
|
455
|
+
});
|
|
456
|
+
it('mixed p2sh & segwit', async function () {
|
|
457
|
+
const p2shAddress = fakeWallet.generateAddress({ path: '/0/14', segwit: false });
|
|
458
|
+
const segwitAddress = fakeWallet.generateAddress({ path: '/10/14', segwit: true });
|
|
459
|
+
const p2shUnspent = {
|
|
460
|
+
addresses: ['2N533fqgyPYKVD892nBRaYmFHbbTykhYSEw'],
|
|
461
|
+
value: '2.99996610',
|
|
462
|
+
value_int: 299996610,
|
|
463
|
+
txid: 'f654ce0a5be3f12df7fecf4ee777b6d86b5aa8c710ef6946ec121206b4f8757c',
|
|
464
|
+
n: 1,
|
|
465
|
+
script_pub_key: {
|
|
466
|
+
asm: 'OP_HASH160 8153e7a35508088b6cf599226792c7de2dbff252 OP_EQUAL',
|
|
467
|
+
hex: 'a9148153e7a35508088b6cf599226792c7de2dbff25287',
|
|
468
|
+
},
|
|
469
|
+
req_sigs: 1,
|
|
470
|
+
type: 'scripthash',
|
|
471
|
+
confirmations: 0,
|
|
472
|
+
id: 61331263,
|
|
473
|
+
};
|
|
474
|
+
const segwitUnspent = {
|
|
475
|
+
addresses: ['2NBtpXcDruf3zRutmF4AbCMFNQHXsGNP6kT'],
|
|
476
|
+
value: '1.50000000',
|
|
477
|
+
value_int: 150000000,
|
|
478
|
+
txid: 'a4409c3f042fae67b890ac3df40ef0db03539c67331fd7e9260511893b4f9f24',
|
|
479
|
+
n: 0,
|
|
480
|
+
script_pub_key: {
|
|
481
|
+
asm: 'OP_HASH160 cc8e7cbf481389d3183a590acfa6aa66eb97c8e1 OP_EQUAL',
|
|
482
|
+
hex: 'a914cc8e7cbf481389d3183a590acfa6aa66eb97c8e187',
|
|
483
|
+
},
|
|
484
|
+
req_sigs: 1,
|
|
485
|
+
type: 'scripthash',
|
|
486
|
+
confirmations: 0,
|
|
487
|
+
id: 61330882,
|
|
488
|
+
};
|
|
489
|
+
const addresses = [p2shAddress, segwitAddress];
|
|
490
|
+
const unspents = [p2shUnspent, segwitUnspent].map((unspent, index) => {
|
|
491
|
+
const address = addresses[index];
|
|
492
|
+
_.extend(unspent, address);
|
|
493
|
+
unspent.value = unspent.value_int;
|
|
494
|
+
unspent.tx_hash = unspent.txid;
|
|
495
|
+
unspent.tx_output_n = unspent.n;
|
|
496
|
+
unspent.script = unspent.outputScript;
|
|
497
|
+
return unspent;
|
|
498
|
+
});
|
|
499
|
+
const transaction = (await fakeWallet.createTransaction({
|
|
500
|
+
changeAddress: p2shAddress.address,
|
|
501
|
+
unspents: unspents,
|
|
502
|
+
recipients: {},
|
|
503
|
+
noSplitChange: true,
|
|
504
|
+
forceChangeAtEnd: true,
|
|
505
|
+
feeRate: 10000,
|
|
506
|
+
opReturns: { 'BitGo mixed p2sh & segwit test': 400000000 },
|
|
507
|
+
bitgoFee: {
|
|
508
|
+
amount: 81760,
|
|
509
|
+
address: '2ND7jQR5itjGTbh3DKgbpZWSY9ungDrwcwb',
|
|
510
|
+
},
|
|
511
|
+
}));
|
|
512
|
+
transaction.transactionHex.should.equal('01000000027c75f8b4061212ec4669ef10c7a85a6bd8b677e74ecffef72df1e35b0ace54f60100000000ffffffff249f4f3b89110526e9d71f33679c5303dbf00ef43dac90b867ae2f043f9c40a40000000000ffffffff030084d71700000000206a1e426974476f206d6978656420703273682026207365677769742074657374b08ff9020000000017a9148153e7a35508088b6cf599226792c7de2dbff25287603f01000000000017a914d9f7be47975c036f94228b0bfd70701912758ba98700000000');
|
|
513
|
+
// add first signature
|
|
514
|
+
transaction.keychain = userKeypair;
|
|
515
|
+
const signature1 = (await fakeProdWallet.signTransaction(transaction));
|
|
516
|
+
signature1.tx.should.equal('010000000001027c75f8b4061212ec4669ef10c7a85a6bd8b677e74ecffef72df1e35b0ace54f601000000b700483045022100ffc45d93cbaf4c1c850e21f277c5b311d3e3957f1338955cb165d72a768a054c022052020593b36781eea00a9f8dcbeb76608f920c7a933a9088318ab2f70c11e1d90100004c69522103da95b28a13aa2d4bb490d70628e2e5d912461d375fef381aadd89dc1256220752103121287a510c5f32e8ba72d2479e90eb52ba44a467173df339feb0ff215f100e32102977cdfbee76066ae739db72d55371ad49dc6712fb8f2f3f69bb1a4c2422b0b1a53aeffffffff249f4f3b89110526e9d71f33679c5303dbf00ef43dac90b867ae2f043f9c40a400000000232200208b91aa03eb0f7f31e3917088084168ba5282a915e7cde0a5a934b7ea02eb057bffffffff030084d71700000000206a1e426974476f206d6978656420703273682026207365677769742074657374b08ff9020000000017a9148153e7a35508088b6cf599226792c7de2dbff25287603f01000000000017a914d9f7be47975c036f94228b0bfd70701912758ba98700050047304402205898bee711467c09a5e22e1dcb1a11fce1a0d6ea129d911f813f87c7d45e067b02202f69fb118bbf0b072ed26d72cf8073e7acd66c205419a4a00f86a7ba0f6e3dd6010000695221030780186c0be5df0d2d62cf54cc2f3d2c09911e377aa95b5fe875fa352aed0a592103f3237edd2d87010e8fe9f43f34e8c63de6384283de909795d62af4ddb4d579542102ad03de5504ef947e4e6ee2fa6b15d150d553c21275f49f2ce2359d9fdedb9ade53ae00000000');
|
|
517
|
+
// add second signature
|
|
518
|
+
transaction.transactionHex = signature1.tx;
|
|
519
|
+
transaction.keychain = backupKeypair;
|
|
520
|
+
transaction.fullLocalSigning = true;
|
|
521
|
+
const signature2 = (await fakeProdWallet.signTransaction(transaction));
|
|
522
|
+
// this transaction has actually worked: https://testnet.smartbit.com.au/tx/e2f696bcba91a376c36bb525df8c367938f6e2fd6344c90587bf12802091124c
|
|
523
|
+
// Note that the tx hex below no longer corresponds to the above transaction because our fee estimation has
|
|
524
|
+
// changed, changing the output amounts and thus the tx hex.
|
|
525
|
+
signature2.tx.should.equal('010000000001027c75f8b4061212ec4669ef10c7a85a6bd8b677e74ecffef72df1e35b0ace54f601000000fdff0000483045022100ffc45d93cbaf4c1c850e21f277c5b311d3e3957f1338955cb165d72a768a054c022052020593b36781eea00a9f8dcbeb76608f920c7a933a9088318ab2f70c11e1d9014830450221008254d100401a3a831ed019e1662dbd90b96c6c4072b81ce640d152bc29295c10022013f86c5af5716234999a7bd6e94fc8f428f7697cc3138b3649d0ec4dd8681bc701004c69522103da95b28a13aa2d4bb490d70628e2e5d912461d375fef381aadd89dc1256220752103121287a510c5f32e8ba72d2479e90eb52ba44a467173df339feb0ff215f100e32102977cdfbee76066ae739db72d55371ad49dc6712fb8f2f3f69bb1a4c2422b0b1a53aeffffffff249f4f3b89110526e9d71f33679c5303dbf00ef43dac90b867ae2f043f9c40a400000000232200208b91aa03eb0f7f31e3917088084168ba5282a915e7cde0a5a934b7ea02eb057bffffffff030084d71700000000206a1e426974476f206d6978656420703273682026207365677769742074657374b08ff9020000000017a9148153e7a35508088b6cf599226792c7de2dbff25287603f01000000000017a914d9f7be47975c036f94228b0bfd70701912758ba98700050047304402205898bee711467c09a5e22e1dcb1a11fce1a0d6ea129d911f813f87c7d45e067b02202f69fb118bbf0b072ed26d72cf8073e7acd66c205419a4a00f86a7ba0f6e3dd60147304402207713d671b45989688e2665c2b11ab7e5ea8d57eb14f9da233c095dabe441308d022069521b5aeb071b07a70a7197a0c2bbc40a23ae63a04160cf3627250c4ba4c40f0100695221030780186c0be5df0d2d62cf54cc2f3d2c09911e377aa95b5fe875fa352aed0a592103f3237edd2d87010e8fe9f43f34e8c63de6384283de909795d62af4ddb4d579542102ad03de5504ef947e4e6ee2fa6b15d150d553c21275f49f2ce2359d9fdedb9ade53ae00000000');
|
|
526
|
+
});
|
|
527
|
+
it('should send to bech32 recipient', async function () {
|
|
528
|
+
const p2shAddress = fakeWallet.generateAddress({ path: '/0/14', segwit: false });
|
|
529
|
+
const segwitAddress = fakeWallet.generateAddress({ path: '/10/14', segwit: true });
|
|
530
|
+
const p2shUnspent = {
|
|
531
|
+
addresses: ['2N533fqgyPYKVD892nBRaYmFHbbTykhYSEw'],
|
|
532
|
+
value: '2.99996610',
|
|
533
|
+
value_int: 299996610,
|
|
534
|
+
txid: 'f654ce0a5be3f12df7fecf4ee777b6d86b5aa8c710ef6946ec121206b4f8757c',
|
|
535
|
+
n: 1,
|
|
536
|
+
script_pub_key: {
|
|
537
|
+
asm: 'OP_HASH160 8153e7a35508088b6cf599226792c7de2dbff252 OP_EQUAL',
|
|
538
|
+
hex: 'a9148153e7a35508088b6cf599226792c7de2dbff25287',
|
|
539
|
+
},
|
|
540
|
+
req_sigs: 1,
|
|
541
|
+
type: 'scripthash',
|
|
542
|
+
confirmations: 0,
|
|
543
|
+
id: 61331263,
|
|
544
|
+
};
|
|
545
|
+
const segwitUnspent = {
|
|
546
|
+
addresses: ['2NBtpXcDruf3zRutmF4AbCMFNQHXsGNP6kT'],
|
|
547
|
+
value: '1.50000000',
|
|
548
|
+
value_int: 150000000,
|
|
549
|
+
txid: 'a4409c3f042fae67b890ac3df40ef0db03539c67331fd7e9260511893b4f9f24',
|
|
550
|
+
n: 0,
|
|
551
|
+
script_pub_key: {
|
|
552
|
+
asm: 'OP_HASH160 cc8e7cbf481389d3183a590acfa6aa66eb97c8e1 OP_EQUAL',
|
|
553
|
+
hex: 'a914cc8e7cbf481389d3183a590acfa6aa66eb97c8e187',
|
|
554
|
+
},
|
|
555
|
+
req_sigs: 1,
|
|
556
|
+
type: 'scripthash',
|
|
557
|
+
confirmations: 0,
|
|
558
|
+
id: 61330882,
|
|
559
|
+
};
|
|
560
|
+
const addresses = [p2shAddress, segwitAddress];
|
|
561
|
+
const unspents = [p2shUnspent, segwitUnspent].map((unspent, index) => {
|
|
562
|
+
const address = addresses[index];
|
|
563
|
+
_.extend(unspent, address);
|
|
564
|
+
unspent.value = unspent.value_int;
|
|
565
|
+
unspent.tx_hash = unspent.txid;
|
|
566
|
+
unspent.tx_output_n = unspent.n;
|
|
567
|
+
unspent.script = unspent.outputScript;
|
|
568
|
+
return unspent;
|
|
569
|
+
});
|
|
570
|
+
const transaction = (await fakeWallet.createTransaction({
|
|
571
|
+
changeAddress: p2shAddress.address,
|
|
572
|
+
unspents: unspents,
|
|
573
|
+
recipients: { tb1qguzyk4w6kaqtpsczs5aj0w8r7598jq36egm8e98wqph3rwmex68seslgsg: 300000 },
|
|
574
|
+
noSplitChange: true,
|
|
575
|
+
forceChangeAtEnd: true,
|
|
576
|
+
feeRate: 10000,
|
|
577
|
+
opReturns: { 'BitGo mixed p2sh & segwit test': 400000000 },
|
|
578
|
+
bitgoFee: {
|
|
579
|
+
amount: 81760,
|
|
580
|
+
address: '2ND7jQR5itjGTbh3DKgbpZWSY9ungDrwcwb',
|
|
581
|
+
},
|
|
582
|
+
}));
|
|
583
|
+
transaction.transactionHex.should.equal('01000000027c75f8b4061212ec4669ef10c7a85a6bd8b677e74ecffef72df1e35b0ace54f60100000000ffffffff249f4f3b89110526e9d71f33679c5303dbf00ef43dac90b867ae2f043f9c40a40000000000ffffffff04e09304000000000022002047044b55dab740b0c302853b27b8e3f50a79023aca367c94ee006f11bb79368f0084d71700000000206a1e426974476f206d69786564207032736820262073656777697420746573747cfaf4020000000017a9148153e7a35508088b6cf599226792c7de2dbff25287603f01000000000017a914d9f7be47975c036f94228b0bfd70701912758ba98700000000');
|
|
584
|
+
// add first signature
|
|
585
|
+
transaction.keychain = userKeypair;
|
|
586
|
+
const signature1 = (await fakeProdWallet.signTransaction(transaction));
|
|
587
|
+
signature1.tx.should.equal('010000000001027c75f8b4061212ec4669ef10c7a85a6bd8b677e74ecffef72df1e35b0ace54f601000000b7004830450221008809377634e667d6e19f38a138a55b2b6370312af76a5ca3b776df61fc719617022021d90347b9085ab71a76c8400f984e322c15451ecc673dd37de30887436d37b40100004c69522103da95b28a13aa2d4bb490d70628e2e5d912461d375fef381aadd89dc1256220752103121287a510c5f32e8ba72d2479e90eb52ba44a467173df339feb0ff215f100e32102977cdfbee76066ae739db72d55371ad49dc6712fb8f2f3f69bb1a4c2422b0b1a53aeffffffff249f4f3b89110526e9d71f33679c5303dbf00ef43dac90b867ae2f043f9c40a400000000232200208b91aa03eb0f7f31e3917088084168ba5282a915e7cde0a5a934b7ea02eb057bffffffff04e09304000000000022002047044b55dab740b0c302853b27b8e3f50a79023aca367c94ee006f11bb79368f0084d71700000000206a1e426974476f206d69786564207032736820262073656777697420746573747cfaf4020000000017a9148153e7a35508088b6cf599226792c7de2dbff25287603f01000000000017a914d9f7be47975c036f94228b0bfd70701912758ba9870005004830450221008b95ac83e44c727b79ffbf4571171925d06f883a05c122b3b33c055f0bffa70102207b5ee3412ea8a5cec4a5c386f1b464ab68d531c6c697077bc462c05eb44a2832010000695221030780186c0be5df0d2d62cf54cc2f3d2c09911e377aa95b5fe875fa352aed0a592103f3237edd2d87010e8fe9f43f34e8c63de6384283de909795d62af4ddb4d579542102ad03de5504ef947e4e6ee2fa6b15d150d553c21275f49f2ce2359d9fdedb9ade53ae00000000');
|
|
588
|
+
// add second signature
|
|
589
|
+
transaction.transactionHex = signature1.tx;
|
|
590
|
+
transaction.keychain = backupKeypair;
|
|
591
|
+
transaction.fullLocalSigning = true;
|
|
592
|
+
const signature2 = (await fakeProdWallet.signTransaction(transaction));
|
|
593
|
+
console.log('signature1 ' + JSON.stringify(signature2));
|
|
594
|
+
// this transaction has actually worked: https://testnet.smartbit.com.au/tx/e2f696bcba91a376c36bb525df8c367938f6e2fd6344c90587bf12802091124c
|
|
595
|
+
// Note that the tx hex below no longer corresponds to the above transaction because our fee estimation has
|
|
596
|
+
// changed, changing the output amounts and thus the tx hex.
|
|
597
|
+
signature2.tx.should.equal('010000000001027c75f8b4061212ec4669ef10c7a85a6bd8b677e74ecffef72df1e35b0ace54f601000000fdfe00004830450221008809377634e667d6e19f38a138a55b2b6370312af76a5ca3b776df61fc719617022021d90347b9085ab71a76c8400f984e322c15451ecc673dd37de30887436d37b40147304402205a58e602042b8e8a5da509d19ce31050147dd0ffcfbe2bb337c23d4c88f4cc41022075bfa455d1f74e30fbd9c786cd4811a1defe54310f235b4193ce4ffa0e8309a101004c69522103da95b28a13aa2d4bb490d70628e2e5d912461d375fef381aadd89dc1256220752103121287a510c5f32e8ba72d2479e90eb52ba44a467173df339feb0ff215f100e32102977cdfbee76066ae739db72d55371ad49dc6712fb8f2f3f69bb1a4c2422b0b1a53aeffffffff249f4f3b89110526e9d71f33679c5303dbf00ef43dac90b867ae2f043f9c40a400000000232200208b91aa03eb0f7f31e3917088084168ba5282a915e7cde0a5a934b7ea02eb057bffffffff04e09304000000000022002047044b55dab740b0c302853b27b8e3f50a79023aca367c94ee006f11bb79368f0084d71700000000206a1e426974476f206d69786564207032736820262073656777697420746573747cfaf4020000000017a9148153e7a35508088b6cf599226792c7de2dbff25287603f01000000000017a914d9f7be47975c036f94228b0bfd70701912758ba9870005004830450221008b95ac83e44c727b79ffbf4571171925d06f883a05c122b3b33c055f0bffa70102207b5ee3412ea8a5cec4a5c386f1b464ab68d531c6c697077bc462c05eb44a283201473044022053690234582a6911a28cae9f534c980b7d7918749a7413c1c59327debf16ff0b022056175f5c27a363416b2ce4791aefc3d55545cacbd0527202e869e1127fc2f24d0100695221030780186c0be5df0d2d62cf54cc2f3d2c09911e377aa95b5fe875fa352aed0a592103f3237edd2d87010e8fe9f43f34e8c63de6384283de909795d62af4ddb4d579542102ad03de5504ef947e4e6ee2fa6b15d150d553c21275f49f2ce2359d9fdedb9ade53ae00000000');
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
describe('Send Many', function () {
|
|
601
|
+
it('responds with proper fee and fee rate', async function () {
|
|
602
|
+
const params = {
|
|
603
|
+
recipients: [
|
|
604
|
+
{
|
|
605
|
+
address: '2MutpXVYs8Lyk74pVDn3eAG7xnK4Wc2kjTQ',
|
|
606
|
+
amount: 300000,
|
|
607
|
+
},
|
|
608
|
+
],
|
|
609
|
+
};
|
|
610
|
+
const unspents = [
|
|
611
|
+
{
|
|
612
|
+
value: 8170,
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
value: 800000,
|
|
616
|
+
},
|
|
617
|
+
];
|
|
618
|
+
const createAndSignResponse = {
|
|
619
|
+
bitgoFee: 0,
|
|
620
|
+
travelInfos: [],
|
|
621
|
+
unspents,
|
|
622
|
+
tx: 'halfsignedhex',
|
|
623
|
+
};
|
|
624
|
+
sinon.stub(fakeWallet, 'createAndSignTransaction').returns(Promise.resolve(createAndSignResponse));
|
|
625
|
+
const getSendTxResponse = () => ({
|
|
626
|
+
status: 'accepted',
|
|
627
|
+
tx: '0100000000010228b5c3e2789d4770fc397ec79fa7255f86235297c5a04def678b481b8b09e81b0100000023220020b3bbe067960be39501f365b8999d53f2a8285d8d9836f61fad020e6a4a9e26fdffffffff1510e90411a86c49f2a52546a32a03febde2bc604741f0e85dc47adec33f515900000000fdfd0000483045022100a44bbf97b155c57703862be69d2b20c4b2ab9e94f402595880bf74402ccc87e202200a4aaf98f939b65c98ca08eb96074c222ecb1fc37e359b1d67a05f1c56dedfc001473044022003f3989a14284f132bbb550118c20256d4ea737704123a29955acc1d03ea6eb7022017223da7edcf73076d89875aa33360aa6a12141807f683c6c1b9a5a0d3ff6019014c695221025789857cc8be110ff4cbf354b52dd0e7e9326c6bfe0aee6c30c1ee69660c3dc02102f58f1b1516d05814ae688ca701856695e27050e3e16d3a2351284d7af84498882102385c7bcec3f38c13e87b558aebf2f20a8928e7ecbe11e7c3a47792bc8e33fe8853aeffffffff02e09304000000000017a9141d0c791cec3af1f37808d42f04593095d6fdea268705bc07000000000017a914d8c720f646c7c56c5467248e47c72dc0b2d30bbc87040047304402201eaa1359fffd3bdec5b48268bd2f15193a299c22b1970356f390883473324651022074186232f02245af9c0977031448c2c99e7b7e2b05b2ba4b32c3227d8ca1494e01483045022100bd61b37051c28533ea0b00dda75b1c4f1dee1b683bb7351b2d8dd720f6dfbe1102203acc4cf9d2dd44b294aa25812e99e7d8eb3730e4ff6f889d3cdcd525195750b8016952210219d093c18c27cb547737b4a49dddac9c3412b10e9f880eb30053c3eba81928542103747118892cac1b4da11526fc4ebeebe168dae0907cefb1a1812541cd46b07602210339f73b6750f8f91efd484b5aa2974321a6cc2776d5bd78b9cfb5fe18e3b2d66253ae005a9e1600',
|
|
628
|
+
hash: 'f8df43c2c650b3bb11277aee4531db99a715fa3b9dfd3d45a8d171342c1bf780',
|
|
629
|
+
instant: false,
|
|
630
|
+
});
|
|
631
|
+
const expectedResult = Object.assign({
|
|
632
|
+
fee: 1285,
|
|
633
|
+
feeRate: 2519.607843137255,
|
|
634
|
+
}, getSendTxResponse());
|
|
635
|
+
sinon.stub(fakeWallet, 'sendTransaction').resolves(getSendTxResponse());
|
|
636
|
+
const result = (await fakeWallet.sendMany(params));
|
|
637
|
+
result.tx.should.equal(expectedResult.tx);
|
|
638
|
+
result.fee.should.equal(expectedResult.fee);
|
|
639
|
+
result.feeRate.should.equal(expectedResult.feeRate);
|
|
640
|
+
});
|
|
641
|
+
});
|
|
642
|
+
describe('Accelerate Transaction (server mocked)', function accelerateTxMockedDescribe() {
|
|
643
|
+
let wallet;
|
|
644
|
+
let bgUrl;
|
|
645
|
+
let explorerUrl;
|
|
646
|
+
let minChangeSize;
|
|
647
|
+
let parentTxId = '6a74b74df4991d93c32d751336c85b5f2d1ee544a2dfbae2e5f4beb4f914e5e0';
|
|
648
|
+
const outputIdx = 0;
|
|
649
|
+
const outputAddress = '2NCoSfHH6Ls4CdTS5QahgC9k7x9RfXeSwY4';
|
|
650
|
+
const unrelatedTxId = '08f5e0b4acb5ab8245229dfe161ce4ca0da1ec983e7a34b09e72f56979a467df';
|
|
651
|
+
const walletId = '2NCoSfHH6Ls4CdTS5QahgC9k7x9RfXeSwY4';
|
|
652
|
+
/**
|
|
653
|
+
* Helper function to get the parent transaction ID from a transaction input
|
|
654
|
+
*
|
|
655
|
+
* This function converts `hash` (which is a Buffer object) to a usable txid string.
|
|
656
|
+
* The issue is that the bytes are stored in reverse order in the buffer, so
|
|
657
|
+
* the simple approach of just comparing the hex strings doesn't work.
|
|
658
|
+
* Instead, the Buffer is copied to a new Buffer object, the new Buffer
|
|
659
|
+
* object is reversed in-place, and then the new Buffer is converted to a
|
|
660
|
+
* hex string. After this, the result is a hex string which is the parent txid
|
|
661
|
+
*
|
|
662
|
+
* @param hash a bitcoinjs-lib transaction object's input hash
|
|
663
|
+
*/
|
|
664
|
+
function inputParentTxId({ hash }) {
|
|
665
|
+
return Buffer.from(hash).reverse().toString('hex');
|
|
666
|
+
}
|
|
667
|
+
before(function accelerateTxMockedBefore() {
|
|
668
|
+
nock_1.default.pendingMocks().should.be.empty();
|
|
669
|
+
bitgo = new bitgoAPI_1.BitGoAPI({ env: 'mock' });
|
|
670
|
+
// bitgo.initializeTestVars();
|
|
671
|
+
bitgo.setValidate(false);
|
|
672
|
+
wallet = new Wallet(bitgo, { id: walletId, private: { keychains: [userKeypair, backupKeypair, bitgoKey] } });
|
|
673
|
+
wallet.bitgo = bitgo;
|
|
674
|
+
bgUrl = sdk_core_1.common.Environments[bitgo.getEnv()].uri;
|
|
675
|
+
explorerUrl = sdk_core_1.common.Environments[bitgo.getEnv()].btcExplorerBaseUrl;
|
|
676
|
+
// try to get the min change size from the server, otherwise default to 0.1 BTC
|
|
677
|
+
// TODO: minChangeSize is not currently a constant defined on the client and should be added
|
|
678
|
+
minChangeSize = 1e7;
|
|
679
|
+
});
|
|
680
|
+
after(function accelerateTxMockedAfter() {
|
|
681
|
+
// make sure all nocks are cleared or consumed after the tests are complete
|
|
682
|
+
nock_1.default.pendingMocks().should.be.empty();
|
|
683
|
+
});
|
|
684
|
+
it('arguments', async () => {
|
|
685
|
+
await wallet.accelerateTransaction({ feeRate: 123 }).should.be.rejectedWith(/^Missing parameter: transactionID$/);
|
|
686
|
+
await wallet
|
|
687
|
+
.accelerateTransaction({ transactionID: 123, feeRate: 123 })
|
|
688
|
+
.should.be.rejectedWith(/^Expecting parameter string: transactionID but found number$/);
|
|
689
|
+
await wallet
|
|
690
|
+
.accelerateTransaction({ transactionID: '123' })
|
|
691
|
+
.should.be.rejectedWith(/^Missing parameter: feeRate$/);
|
|
692
|
+
const feeRatesParams = ['123', 0, -10, -Infinity, Infinity, NaN];
|
|
693
|
+
for (const feeRate of feeRatesParams) {
|
|
694
|
+
await wallet
|
|
695
|
+
.accelerateTransaction({ transactionID: '123', feeRate })
|
|
696
|
+
.should.be.rejectedWith(/^Expecting positive finite number for parameter: feeRate$/);
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
describe('bad input', function badInputDescribe() {
|
|
700
|
+
after(() => {
|
|
701
|
+
// make sure all nocks are cleared or consumed after the tests are complete
|
|
702
|
+
nock_1.default.pendingMocks().should.be.empty();
|
|
703
|
+
});
|
|
704
|
+
it('non existent transaction ID', async () => {
|
|
705
|
+
(0, nock_1.default)(bgUrl)
|
|
706
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
707
|
+
.reply(404, 'transaction not found on this wallet');
|
|
708
|
+
await wallet
|
|
709
|
+
.accelerateTransaction({ transactionID: parentTxId, feeRate: 123 })
|
|
710
|
+
.should.be.rejectedWith(/^404\ntransaction not found on this wallet$/);
|
|
711
|
+
});
|
|
712
|
+
it('confirmed transaction', async () => {
|
|
713
|
+
(0, nock_1.default)(bgUrl).get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`).reply(200, {
|
|
714
|
+
confirmations: 6,
|
|
715
|
+
});
|
|
716
|
+
await wallet
|
|
717
|
+
.accelerateTransaction({ transactionID: parentTxId, feeRate: 2000 })
|
|
718
|
+
.should.be.rejectedWith(/^Transaction [0-9a-f]+ is already confirmed and cannot be accelerated$/);
|
|
719
|
+
});
|
|
720
|
+
it('no outputs to wallet', async () => {
|
|
721
|
+
(0, nock_1.default)(bgUrl)
|
|
722
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
723
|
+
.reply(200, {
|
|
724
|
+
outputs: [
|
|
725
|
+
{
|
|
726
|
+
account: outputAddress,
|
|
727
|
+
value: 1890000,
|
|
728
|
+
vout: 0,
|
|
729
|
+
chain: 0,
|
|
730
|
+
},
|
|
731
|
+
],
|
|
732
|
+
confirmations: 0,
|
|
733
|
+
});
|
|
734
|
+
await wallet
|
|
735
|
+
.accelerateTransaction({ transactionID: parentTxId, feeRate: 2000 })
|
|
736
|
+
.should.be.rejectedWith(/^Transaction [0-9a-f]+ contains no outputs to this wallet, and thus cannot be accelerated$/);
|
|
737
|
+
});
|
|
738
|
+
/*
|
|
739
|
+
* This test covers the case where a failure occurs during the process of
|
|
740
|
+
* converting an output from the parent transaction into an unspent which
|
|
741
|
+
* can be used to chain the child tx to the parent.
|
|
742
|
+
*
|
|
743
|
+
* This should never happen, but it is possible (for example, in the case
|
|
744
|
+
* of an attempted double spend of the output from the parent, or a race
|
|
745
|
+
* between finding the parent output, and retrieving the corresponding unspent).
|
|
746
|
+
*/
|
|
747
|
+
it('cannot find correct unspent to use', async () => {
|
|
748
|
+
(0, nock_1.default)(bgUrl)
|
|
749
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
750
|
+
.reply(200, {
|
|
751
|
+
outputs: [
|
|
752
|
+
{
|
|
753
|
+
account: outputAddress,
|
|
754
|
+
value: 50 * 1e4,
|
|
755
|
+
vout: outputIdx,
|
|
756
|
+
isMine: true,
|
|
757
|
+
chain: 0,
|
|
758
|
+
},
|
|
759
|
+
],
|
|
760
|
+
confirmations: 0,
|
|
761
|
+
hex: parentTxId,
|
|
762
|
+
fee: 10,
|
|
763
|
+
});
|
|
764
|
+
(0, nock_1.default)(bgUrl).get(`/api/v1/wallet/${wallet.id()}/unspents`).query(true).reply(200, {
|
|
765
|
+
count: 0,
|
|
766
|
+
unspents: [],
|
|
767
|
+
});
|
|
768
|
+
await wallet
|
|
769
|
+
.accelerateTransaction({ transactionID: parentTxId, feeRate: 2000 })
|
|
770
|
+
.should.be.rejectedWith(/^Could not find unspent output from parent tx to use as child input$/);
|
|
771
|
+
});
|
|
772
|
+
it('Detects when an incorrect tx hex is returned by the external service', async () => {
|
|
773
|
+
(0, nock_1.default)(bgUrl)
|
|
774
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
775
|
+
.reply(200, {
|
|
776
|
+
outputs: [
|
|
777
|
+
{
|
|
778
|
+
account: outputAddress,
|
|
779
|
+
value: 10,
|
|
780
|
+
vout: outputIdx,
|
|
781
|
+
isMine: true,
|
|
782
|
+
chain: 0,
|
|
783
|
+
},
|
|
784
|
+
],
|
|
785
|
+
confirmations: 0,
|
|
786
|
+
hex: fixtures[parentTxId],
|
|
787
|
+
fee: 10,
|
|
788
|
+
});
|
|
789
|
+
(0, nock_1.default)(bgUrl)
|
|
790
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
791
|
+
.query(true)
|
|
792
|
+
.reply(200, {
|
|
793
|
+
count: 1,
|
|
794
|
+
unspents: [
|
|
795
|
+
{
|
|
796
|
+
tx_hash: parentTxId,
|
|
797
|
+
tx_output_n: outputIdx,
|
|
798
|
+
},
|
|
799
|
+
],
|
|
800
|
+
});
|
|
801
|
+
(0, nock_1.default)(explorerUrl).get(`/tx/${parentTxId}/hex`).reply(200, fixtures[unrelatedTxId]);
|
|
802
|
+
await wallet
|
|
803
|
+
.accelerateTransaction({ transactionID: parentTxId, feeRate: 2000 })
|
|
804
|
+
.should.be.rejectedWith(/^Decoded transaction id is [0-9a-f]+, which does not match given txid [0-9a-f]+$/);
|
|
805
|
+
});
|
|
806
|
+
it('cannot cover child fee with one parent output and one wallet unspent', async () => {
|
|
807
|
+
(0, nock_1.default)(bgUrl)
|
|
808
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
809
|
+
.reply(200, {
|
|
810
|
+
outputs: [
|
|
811
|
+
{
|
|
812
|
+
account: outputAddress,
|
|
813
|
+
value: 10,
|
|
814
|
+
vout: outputIdx,
|
|
815
|
+
isMine: true,
|
|
816
|
+
chain: 0,
|
|
817
|
+
},
|
|
818
|
+
],
|
|
819
|
+
confirmations: 0,
|
|
820
|
+
hex: fixtures[parentTxId],
|
|
821
|
+
fee: 10,
|
|
822
|
+
});
|
|
823
|
+
(0, nock_1.default)(bgUrl)
|
|
824
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
825
|
+
.query(true)
|
|
826
|
+
.reply(200, {
|
|
827
|
+
count: 1,
|
|
828
|
+
unspents: [
|
|
829
|
+
{
|
|
830
|
+
tx_hash: parentTxId,
|
|
831
|
+
tx_output_n: outputIdx,
|
|
832
|
+
},
|
|
833
|
+
],
|
|
834
|
+
});
|
|
835
|
+
(0, nock_1.default)(explorerUrl).get(`/tx/${parentTxId}/hex`).reply(200, fixtures[parentTxId]);
|
|
836
|
+
(0, nock_1.default)(bgUrl).get(`/api/v1/wallet/${wallet.id()}/unspents`).query(true).reply(200, {
|
|
837
|
+
count: 0,
|
|
838
|
+
unspents: [],
|
|
839
|
+
});
|
|
840
|
+
await wallet
|
|
841
|
+
.accelerateTransaction({ transactionID: parentTxId, feeRate: 2000 })
|
|
842
|
+
.should.be.rejectedWith(/^Insufficient confirmed unspents available to cover the child fee$/);
|
|
843
|
+
});
|
|
844
|
+
it('cannot lower fee rate', async () => {
|
|
845
|
+
(0, nock_1.default)(bgUrl)
|
|
846
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
847
|
+
.reply(200, {
|
|
848
|
+
outputs: [
|
|
849
|
+
{
|
|
850
|
+
account: outputAddress,
|
|
851
|
+
value: 10,
|
|
852
|
+
vout: outputIdx,
|
|
853
|
+
isMine: true,
|
|
854
|
+
chain: 11,
|
|
855
|
+
},
|
|
856
|
+
],
|
|
857
|
+
confirmations: 0,
|
|
858
|
+
hex: fixtures[parentTxId],
|
|
859
|
+
fee: 10000, // large fee, and thus fee rate, for parent
|
|
860
|
+
});
|
|
861
|
+
(0, nock_1.default)(bgUrl)
|
|
862
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
863
|
+
.query(true)
|
|
864
|
+
.reply(200, {
|
|
865
|
+
count: 1,
|
|
866
|
+
unspents: [
|
|
867
|
+
{
|
|
868
|
+
tx_hash: parentTxId,
|
|
869
|
+
tx_output_n: outputIdx,
|
|
870
|
+
},
|
|
871
|
+
],
|
|
872
|
+
});
|
|
873
|
+
(0, nock_1.default)(explorerUrl).get(`/tx/${parentTxId}/hex`).reply(200, fixtures[parentTxId]);
|
|
874
|
+
await wallet
|
|
875
|
+
.accelerateTransaction({ transactionID: parentTxId, feeRate: 2000 })
|
|
876
|
+
.should.be.rejectedWith(/^Cannot lower fee rate! \(Parent tx fee rate is \d+\.?\d* sat\/kB, and requested fee rate was \d+\.?\d* sat\/kB\)$/);
|
|
877
|
+
});
|
|
878
|
+
it('cannot break maximum fee limit for combined transaction', async () => {
|
|
879
|
+
(0, nock_1.default)(bgUrl)
|
|
880
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
881
|
+
.reply(200, {
|
|
882
|
+
outputs: [
|
|
883
|
+
{
|
|
884
|
+
account: outputAddress,
|
|
885
|
+
value: 3e7,
|
|
886
|
+
vout: outputIdx,
|
|
887
|
+
isMine: true,
|
|
888
|
+
chain: 11,
|
|
889
|
+
},
|
|
890
|
+
],
|
|
891
|
+
confirmations: 0,
|
|
892
|
+
hex: fixtures[parentTxId],
|
|
893
|
+
fee: 1000,
|
|
894
|
+
});
|
|
895
|
+
(0, nock_1.default)(bgUrl)
|
|
896
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
897
|
+
.query(true)
|
|
898
|
+
.reply(200, {
|
|
899
|
+
count: 1,
|
|
900
|
+
unspents: [
|
|
901
|
+
{
|
|
902
|
+
tx_hash: parentTxId,
|
|
903
|
+
tx_output_n: outputIdx,
|
|
904
|
+
},
|
|
905
|
+
],
|
|
906
|
+
});
|
|
907
|
+
(0, nock_1.default)(explorerUrl).get(`/tx/${parentTxId}/hex`).reply(200, fixtures[parentTxId]);
|
|
908
|
+
await wallet
|
|
909
|
+
.accelerateTransaction({ transactionID: parentTxId, feeRate: 2e6 })
|
|
910
|
+
.should.be.rejectedWith(/^Transaction cannot be accelerated\. Combined fee rate of \d+\.?\d* sat\/kB exceeds maximum fee rate of \d+\.?\d* sat\/kB$/);
|
|
911
|
+
});
|
|
912
|
+
});
|
|
913
|
+
describe('successful tx acceleration', function successfulTxDescribe() {
|
|
914
|
+
const feeRate = 20000;
|
|
915
|
+
beforeEach(() => {
|
|
916
|
+
(0, nock_1.default)(bgUrl).post(`/api/v1/wallet/${wallet.id()}/address/1`).reply(200, {
|
|
917
|
+
address: '2NCYjG8Q56yr8tx9jazNoYnGKxjgB2MQSfY',
|
|
918
|
+
});
|
|
919
|
+
(0, nock_1.default)(bgUrl).post('/api/v1/billing/address').reply(200, {
|
|
920
|
+
address: '2NFbvo2HK4eXZm1aqDcSDGGqD64FPt7T6d8',
|
|
921
|
+
});
|
|
922
|
+
(0, nock_1.default)(bgUrl).get('/api/v1/tx/fee').query(true).reply(200, {
|
|
923
|
+
feePerKb: 0,
|
|
924
|
+
});
|
|
925
|
+
(0, nock_1.default)(bgUrl)
|
|
926
|
+
.post(`/api/v1/keychain/${userKeypair.xpub}`, {})
|
|
927
|
+
.reply(200, {
|
|
928
|
+
encryptedXprv: bitgo.encrypt({ input: userKeypair.xprv, password: TestBitGo.TEST_WALLET1_PASSCODE }),
|
|
929
|
+
path: userKeypair.path + userKeypair.walletSubPath,
|
|
930
|
+
});
|
|
931
|
+
});
|
|
932
|
+
it('accelerates a stuck tx without additional unspents', async () => {
|
|
933
|
+
parentTxId = '75cfc5a7b214c4b73c92c7b02608cde70b226767a9576f84c04407e43fd385bd';
|
|
934
|
+
(0, nock_1.default)(bgUrl)
|
|
935
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
936
|
+
.reply(200, {
|
|
937
|
+
fee: 434,
|
|
938
|
+
outputs: [
|
|
939
|
+
{
|
|
940
|
+
vout: 0,
|
|
941
|
+
value: 10348500,
|
|
942
|
+
isMine: true,
|
|
943
|
+
chain: 1,
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
vout: 1,
|
|
947
|
+
value: 10000,
|
|
948
|
+
isMine: true,
|
|
949
|
+
chain: 11,
|
|
950
|
+
},
|
|
951
|
+
],
|
|
952
|
+
});
|
|
953
|
+
(0, nock_1.default)(bgUrl)
|
|
954
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
955
|
+
.query(true)
|
|
956
|
+
.reply(200, {
|
|
957
|
+
unspents: [
|
|
958
|
+
{
|
|
959
|
+
tx_hash: parentTxId,
|
|
960
|
+
tx_output_n: 0,
|
|
961
|
+
value: 10348500,
|
|
962
|
+
redeemScript: '0020f7b58d455351b7b8ddd7c8986d98244f6a95f0746720091537323b967800f744',
|
|
963
|
+
chainPath: '/11/160',
|
|
964
|
+
witnessScript: '5221027f0b45bb4155ea532e3b4312fe0be80166f297d1e0753d2d4a9118c073ad6514210310aa9d68c98831625f329b7826b6c3e3b53e16736b1994b8902442bdcd6653d121026e0ca414f2488b0ab572b99e0ae5442911ab4e0821b2709d885175a527fd552b53ae',
|
|
965
|
+
},
|
|
966
|
+
],
|
|
967
|
+
});
|
|
968
|
+
(0, nock_1.default)(explorerUrl).get(`/tx/${parentTxId}/hex`).reply(200, fixtures[parentTxId]);
|
|
969
|
+
(0, nock_1.default)(bgUrl)
|
|
970
|
+
.post('/api/v1/tx/send', (body) => {
|
|
971
|
+
return !body.ignoreMaxFeeRate;
|
|
972
|
+
})
|
|
973
|
+
.reply(200, function (_, body) {
|
|
974
|
+
return {
|
|
975
|
+
transaction: body.tx,
|
|
976
|
+
};
|
|
977
|
+
});
|
|
978
|
+
const childTx = await wallet.accelerateTransaction({
|
|
979
|
+
transactionID: parentTxId,
|
|
980
|
+
feeRate,
|
|
981
|
+
walletPassphrase: TestBitGo.TEST_WALLET1_PASSCODE,
|
|
982
|
+
});
|
|
983
|
+
should.exist(childTx);
|
|
984
|
+
childTx.should.have.property('status', 'accepted');
|
|
985
|
+
childTx.should.have.property('tx');
|
|
986
|
+
// assert the following:
|
|
987
|
+
// 0) The child tx has exactly one input
|
|
988
|
+
// 1) The parent tx output is an input
|
|
989
|
+
// 2) The child tx has exactly one output
|
|
990
|
+
// 3) The child tx output meets the minimum change threshold
|
|
991
|
+
const decodedChild = utxolib.bitgo.createTransactionFromHex(childTx.tx, utxolib.networks.bitcoin);
|
|
992
|
+
decodedChild.ins.length.should.equal(1);
|
|
993
|
+
decodedChild.outs.length.should.equal(1);
|
|
994
|
+
const childInput = decodedChild.ins[0];
|
|
995
|
+
childInput.should.have.property('index', 0);
|
|
996
|
+
childInput.should.have.property('hash');
|
|
997
|
+
const inputTxId = inputParentTxId(childInput);
|
|
998
|
+
inputTxId.should.equal(parentTxId);
|
|
999
|
+
const childOutput = decodedChild.outs[0];
|
|
1000
|
+
childOutput.should.have.property('value');
|
|
1001
|
+
childOutput.value.should.be.above(minChangeSize);
|
|
1002
|
+
});
|
|
1003
|
+
it('accelerates a stuck tx with one additional segwit unspent', async () => {
|
|
1004
|
+
parentTxId = '8815f202c8654b6c8b295749545c711878cd845a14cb1ea982394d0c14945c33';
|
|
1005
|
+
const additionalUnspentTxId = '07d6ee57b024ce2b6108f67847454a0a79a4fcfb98ab255553a2993a1a170b87';
|
|
1006
|
+
(0, nock_1.default)(bgUrl)
|
|
1007
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
1008
|
+
.reply(200, {
|
|
1009
|
+
fee: 1336,
|
|
1010
|
+
outputs: [
|
|
1011
|
+
{
|
|
1012
|
+
vout: 0,
|
|
1013
|
+
value: 10000,
|
|
1014
|
+
isMine: true,
|
|
1015
|
+
chain: 11,
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
vout: 1,
|
|
1019
|
+
value: 8664,
|
|
1020
|
+
isMine: true,
|
|
1021
|
+
chain: 1,
|
|
1022
|
+
},
|
|
1023
|
+
],
|
|
1024
|
+
confirmations: 0,
|
|
1025
|
+
});
|
|
1026
|
+
(0, nock_1.default)(bgUrl)
|
|
1027
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
1028
|
+
.query(true)
|
|
1029
|
+
.reply(200, {
|
|
1030
|
+
unspents: [
|
|
1031
|
+
{
|
|
1032
|
+
tx_hash: parentTxId,
|
|
1033
|
+
tx_output_n: 0,
|
|
1034
|
+
value: 10000,
|
|
1035
|
+
redeemScript: '522102cd3c8e6006a4627705021d1d016d097c2944d98100a47bf2da67a5fe15aeeb342102ee1fa9e812e779356aa3c31ebf317d0cffebab92864cfe38bab223e0820f98bc21026ba05752baa6eafd5c5659da62b7f0ac51fd2886b65c241d0afef1c4fdfa1cbc53ae',
|
|
1036
|
+
chainPath: '/0/0',
|
|
1037
|
+
},
|
|
1038
|
+
],
|
|
1039
|
+
});
|
|
1040
|
+
(0, nock_1.default)(bgUrl)
|
|
1041
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
1042
|
+
.query(true)
|
|
1043
|
+
.reply(200, {
|
|
1044
|
+
unspents: [
|
|
1045
|
+
{
|
|
1046
|
+
tx_hash: additionalUnspentTxId,
|
|
1047
|
+
tx_output_n: 0,
|
|
1048
|
+
value: 19935526,
|
|
1049
|
+
redeemScript: '0020d34ef6dd34ef2a4fbea67c541c1c796749a60afe4a97fee8ec7ded188bd749da',
|
|
1050
|
+
chainPath: '/11/155',
|
|
1051
|
+
witnessScript: '522102219d2aa8417633f0bce3911374a1604c1b64161f83a3c2ee409c27c42355f08e2102c9734920dc4da06c289fe69171dfcd75e3b9b4f190d0cbc3d5d0ff3f5fdeeaae2103ccd68d7fa8dc0d02dd45dad165557a48582eda4435fae7377b3c31e08ad065c953ae',
|
|
1052
|
+
},
|
|
1053
|
+
],
|
|
1054
|
+
});
|
|
1055
|
+
(0, nock_1.default)(explorerUrl).get(`/tx/${parentTxId}/hex`).reply(200, fixtures[parentTxId]);
|
|
1056
|
+
(0, nock_1.default)(bgUrl)
|
|
1057
|
+
.post('/api/v1/tx/send', (body) => {
|
|
1058
|
+
return !body.ignoreMaxFeeRate;
|
|
1059
|
+
})
|
|
1060
|
+
.reply(200, function (_, body) {
|
|
1061
|
+
return {
|
|
1062
|
+
transaction: body.tx,
|
|
1063
|
+
};
|
|
1064
|
+
});
|
|
1065
|
+
const childTx = await wallet.accelerateTransaction({
|
|
1066
|
+
transactionID: parentTxId,
|
|
1067
|
+
feeRate,
|
|
1068
|
+
walletPassphrase: TestBitGo.TEST_WALLET1_PASSCODE,
|
|
1069
|
+
});
|
|
1070
|
+
should.exist(childTx);
|
|
1071
|
+
childTx.should.have.property('status', 'accepted');
|
|
1072
|
+
childTx.should.have.property('tx');
|
|
1073
|
+
// assert the following:
|
|
1074
|
+
// 0) The child tx has exactly two inputs
|
|
1075
|
+
// 1) The parent tx output is an input
|
|
1076
|
+
// 2) The additional unspent output is an input
|
|
1077
|
+
// 3) The child tx has exactly one output
|
|
1078
|
+
// 4) The child tx output meets the minimum change threshold
|
|
1079
|
+
const decodedChild = utxolib.bitgo.createTransactionFromHex(childTx.tx, utxolib.networks.bitcoin);
|
|
1080
|
+
decodedChild.ins.length.should.equal(2);
|
|
1081
|
+
decodedChild.outs.length.should.equal(1);
|
|
1082
|
+
let inputFromParent = undefined;
|
|
1083
|
+
let additionalInput = undefined;
|
|
1084
|
+
_.forEach(decodedChild.ins, (input) => {
|
|
1085
|
+
input.should.have.property('hash');
|
|
1086
|
+
input.should.have.property('index');
|
|
1087
|
+
const inputTxId = inputParentTxId(input);
|
|
1088
|
+
if (inputTxId === parentTxId) {
|
|
1089
|
+
inputFromParent = input;
|
|
1090
|
+
}
|
|
1091
|
+
else {
|
|
1092
|
+
additionalInput = input;
|
|
1093
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
should.exist(inputFromParent);
|
|
1096
|
+
const inputFromParentHash = inputParentTxId(inputFromParent);
|
|
1097
|
+
inputFromParentHash.should.equal(parentTxId);
|
|
1098
|
+
inputFromParent.index.should.equal(0);
|
|
1099
|
+
should.exist(additionalInput);
|
|
1100
|
+
const additionalInputHash = inputParentTxId(additionalInput);
|
|
1101
|
+
additionalInputHash.should.equal(additionalUnspentTxId);
|
|
1102
|
+
additionalInput.index.should.equal(0);
|
|
1103
|
+
const childOutput = decodedChild.outs[0];
|
|
1104
|
+
childOutput.should.have.property('value');
|
|
1105
|
+
childOutput.value.should.be.above(minChangeSize);
|
|
1106
|
+
});
|
|
1107
|
+
it('accelerates a stuck tx with one additional P2SH unspent', async () => {
|
|
1108
|
+
parentTxId = '8815f202c8654b6c8b295749545c711878cd845a14cb1ea982394d0c14945c33';
|
|
1109
|
+
const additionalUnspentTxId = 'e190310f2f3f71aa8846f1161cbce1533c24a857dd24e4501b131feb400aad58';
|
|
1110
|
+
(0, nock_1.default)(bgUrl)
|
|
1111
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
1112
|
+
.reply(200, {
|
|
1113
|
+
fee: 1336,
|
|
1114
|
+
outputs: [
|
|
1115
|
+
{
|
|
1116
|
+
vout: 0,
|
|
1117
|
+
value: 10000,
|
|
1118
|
+
isMine: true,
|
|
1119
|
+
chain: 11,
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
vout: 1,
|
|
1123
|
+
value: 8664,
|
|
1124
|
+
isMine: true,
|
|
1125
|
+
chain: 1,
|
|
1126
|
+
},
|
|
1127
|
+
],
|
|
1128
|
+
confirmations: 0,
|
|
1129
|
+
});
|
|
1130
|
+
(0, nock_1.default)(bgUrl)
|
|
1131
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
1132
|
+
.query(true)
|
|
1133
|
+
.reply(200, {
|
|
1134
|
+
unspents: [
|
|
1135
|
+
{
|
|
1136
|
+
tx_hash: parentTxId,
|
|
1137
|
+
tx_output_n: 0,
|
|
1138
|
+
value: 10000,
|
|
1139
|
+
redeemScript: '522102cd3c8e6006a4627705021d1d016d097c2944d98100a47bf2da67a5fe15aeeb342102ee1fa9e812e779356aa3c31ebf317d0cffebab92864cfe38bab223e0820f98bc21026ba05752baa6eafd5c5659da62b7f0ac51fd2886b65c241d0afef1c4fdfa1cbc53ae',
|
|
1140
|
+
chainPath: '/0/0',
|
|
1141
|
+
},
|
|
1142
|
+
],
|
|
1143
|
+
});
|
|
1144
|
+
(0, nock_1.default)(bgUrl)
|
|
1145
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
1146
|
+
.query(true)
|
|
1147
|
+
.reply(200, {
|
|
1148
|
+
unspents: [
|
|
1149
|
+
{
|
|
1150
|
+
tx_hash: additionalUnspentTxId,
|
|
1151
|
+
tx_output_n: 1,
|
|
1152
|
+
value: 20000000,
|
|
1153
|
+
redeemScript: '522102cd3c8e6006a4627705021d1d016d097c2944d98100a47bf2da67a5fe15aeeb342102ee1fa9e812e779356aa3c31ebf317d0cffebab92864cfe38bab223e0820f98bc21026ba05752baa6eafd5c5659da62b7f0ac51fd2886b65c241d0afef1c4fdfa1cbc53ae',
|
|
1154
|
+
chainPath: '/0/0',
|
|
1155
|
+
},
|
|
1156
|
+
],
|
|
1157
|
+
});
|
|
1158
|
+
(0, nock_1.default)(explorerUrl).get(`/tx/${parentTxId}/hex`).reply(200, fixtures[parentTxId]);
|
|
1159
|
+
(0, nock_1.default)(bgUrl)
|
|
1160
|
+
.post('/api/v1/tx/send', (body) => {
|
|
1161
|
+
return !body.ignoreMaxFeeRate;
|
|
1162
|
+
})
|
|
1163
|
+
.reply(200, function (_, body) {
|
|
1164
|
+
return {
|
|
1165
|
+
transaction: body.tx,
|
|
1166
|
+
};
|
|
1167
|
+
});
|
|
1168
|
+
const childTx = await wallet.accelerateTransaction({
|
|
1169
|
+
transactionID: parentTxId,
|
|
1170
|
+
feeRate,
|
|
1171
|
+
walletPassphrase: TestBitGo.TEST_WALLET1_PASSCODE,
|
|
1172
|
+
});
|
|
1173
|
+
should.exist(childTx);
|
|
1174
|
+
childTx.should.have.property('status', 'accepted');
|
|
1175
|
+
childTx.should.have.property('tx');
|
|
1176
|
+
// assert the following:
|
|
1177
|
+
// 0) The child tx has exactly two inputs
|
|
1178
|
+
// 1) The parent tx output is an input
|
|
1179
|
+
// 2) The additional unspent output is an input
|
|
1180
|
+
// 3) The child tx has exactly one output
|
|
1181
|
+
// 4) The child tx output meets the minimum change threshold
|
|
1182
|
+
const decodedChild = utxolib.bitgo.createTransactionFromHex(childTx.tx, utxolib.networks.bitcoin);
|
|
1183
|
+
decodedChild.ins.length.should.equal(2);
|
|
1184
|
+
decodedChild.outs.length.should.equal(1);
|
|
1185
|
+
let inputFromParent = undefined;
|
|
1186
|
+
let additionalInput = undefined;
|
|
1187
|
+
_.forEach(decodedChild.ins, (input) => {
|
|
1188
|
+
input.should.have.property('hash');
|
|
1189
|
+
input.should.have.property('index');
|
|
1190
|
+
const inputHash = inputParentTxId(input);
|
|
1191
|
+
if (inputHash === parentTxId) {
|
|
1192
|
+
inputFromParent = input;
|
|
1193
|
+
}
|
|
1194
|
+
else {
|
|
1195
|
+
additionalInput = input;
|
|
1196
|
+
}
|
|
1197
|
+
});
|
|
1198
|
+
should.exist(inputFromParent);
|
|
1199
|
+
const inputFromParentHash = inputParentTxId(inputFromParent);
|
|
1200
|
+
inputFromParentHash.should.equal(parentTxId);
|
|
1201
|
+
inputFromParent.index.should.equal(0);
|
|
1202
|
+
should.exist(additionalInput);
|
|
1203
|
+
const additionalInputHash = inputParentTxId(additionalInput);
|
|
1204
|
+
additionalInputHash.should.equal(additionalUnspentTxId);
|
|
1205
|
+
additionalInput.index.should.equal(1);
|
|
1206
|
+
const childOutput = decodedChild.outs[0];
|
|
1207
|
+
childOutput.should.have.property('value');
|
|
1208
|
+
childOutput.value.should.be.above(minChangeSize);
|
|
1209
|
+
});
|
|
1210
|
+
it('accelerates a stuck tx with two additional unspents (segwit and P2SH)', async () => {
|
|
1211
|
+
parentTxId = '8815f202c8654b6c8b295749545c711878cd845a14cb1ea982394d0c14945c33';
|
|
1212
|
+
(0, nock_1.default)(bgUrl)
|
|
1213
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
1214
|
+
.reply(200, {
|
|
1215
|
+
fee: 1336,
|
|
1216
|
+
outputs: [
|
|
1217
|
+
{
|
|
1218
|
+
vout: 0,
|
|
1219
|
+
value: 10000,
|
|
1220
|
+
isMine: true,
|
|
1221
|
+
chain: 11,
|
|
1222
|
+
},
|
|
1223
|
+
{
|
|
1224
|
+
vout: 1,
|
|
1225
|
+
value: 8664,
|
|
1226
|
+
isMine: true,
|
|
1227
|
+
chain: 1,
|
|
1228
|
+
},
|
|
1229
|
+
],
|
|
1230
|
+
confirmations: 0,
|
|
1231
|
+
});
|
|
1232
|
+
(0, nock_1.default)(bgUrl)
|
|
1233
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
1234
|
+
.query(true)
|
|
1235
|
+
.reply(200, {
|
|
1236
|
+
unspents: [
|
|
1237
|
+
{
|
|
1238
|
+
tx_hash: parentTxId,
|
|
1239
|
+
tx_output_n: 0,
|
|
1240
|
+
value: 10000,
|
|
1241
|
+
redeemScript: '522102cd3c8e6006a4627705021d1d016d097c2944d98100a47bf2da67a5fe15aeeb342102ee1fa9e812e779356aa3c31ebf317d0cffebab92864cfe38bab223e0820f98bc21026ba05752baa6eafd5c5659da62b7f0ac51fd2886b65c241d0afef1c4fdfa1cbc53ae',
|
|
1242
|
+
chainPath: '/0/0',
|
|
1243
|
+
},
|
|
1244
|
+
],
|
|
1245
|
+
});
|
|
1246
|
+
(0, nock_1.default)(bgUrl)
|
|
1247
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
1248
|
+
.query(true)
|
|
1249
|
+
.reply(200, {
|
|
1250
|
+
unspents: [
|
|
1251
|
+
{
|
|
1252
|
+
tx_hash: 'e190310f2f3f71aa8846f1161cbce1533c24a857dd24e4501b131feb400aad58',
|
|
1253
|
+
tx_output_n: 1,
|
|
1254
|
+
value: 800000,
|
|
1255
|
+
redeemScript: '522102cd3c8e6006a4627705021d1d016d097c2944d98100a47bf2da67a5fe15aeeb342102ee1fa9e812e779356aa3c31ebf317d0cffebab92864cfe38bab223e0820f98bc21026ba05752baa6eafd5c5659da62b7f0ac51fd2886b65c241d0afef1c4fdfa1cbc53ae',
|
|
1256
|
+
chainPath: '/0/0',
|
|
1257
|
+
},
|
|
1258
|
+
{
|
|
1259
|
+
tx_hash: '07d6ee57b024ce2b6108f67847454a0a79a4fcfb98ab255553a2993a1a170b87',
|
|
1260
|
+
tx_output_n: 0,
|
|
1261
|
+
value: 20006284,
|
|
1262
|
+
redeemScript: '0020d34ef6dd34ef2a4fbea67c541c1c796749a60afe4a97fee8ec7ded188bd749da',
|
|
1263
|
+
chainPath: '/11/155',
|
|
1264
|
+
witnessScript: '522102219d2aa8417633f0bce3911374a1604c1b64161f83a3c2ee409c27c42355f08e2102c9734920dc4da06c289fe69171dfcd75e3b9b4f190d0cbc3d5d0ff3f5fdeeaae2103ccd68d7fa8dc0d02dd45dad165557a48582eda4435fae7377b3c31e08ad065c953ae',
|
|
1265
|
+
},
|
|
1266
|
+
],
|
|
1267
|
+
});
|
|
1268
|
+
(0, nock_1.default)(explorerUrl).get(`/tx/${parentTxId}/hex`).reply(200, fixtures[parentTxId]);
|
|
1269
|
+
(0, nock_1.default)(bgUrl)
|
|
1270
|
+
.post('/api/v1/tx/send', (body) => {
|
|
1271
|
+
return !body.ignoreMaxFeeRate;
|
|
1272
|
+
})
|
|
1273
|
+
.reply(200, function (_, body) {
|
|
1274
|
+
return {
|
|
1275
|
+
transaction: body.tx,
|
|
1276
|
+
};
|
|
1277
|
+
});
|
|
1278
|
+
const childTx = await wallet.accelerateTransaction({
|
|
1279
|
+
transactionID: parentTxId,
|
|
1280
|
+
walletPassphrase: TestBitGo.TEST_WALLET1_PASSCODE,
|
|
1281
|
+
feeRate,
|
|
1282
|
+
});
|
|
1283
|
+
should.exist(childTx);
|
|
1284
|
+
childTx.should.have.property('status', 'accepted');
|
|
1285
|
+
childTx.should.have.property('tx');
|
|
1286
|
+
// assert the following:
|
|
1287
|
+
// 0) The child tx has exactly three inputs
|
|
1288
|
+
// 1) The parent tx output is an input
|
|
1289
|
+
// 2) The child tx has exactly one output
|
|
1290
|
+
// 3) The child tx output meets the minimum change threshold
|
|
1291
|
+
const decodedChild = utxolib.bitgo.createTransactionFromHex(childTx.tx, utxolib.networks.bitcoin);
|
|
1292
|
+
decodedChild.ins.length.should.equal(3);
|
|
1293
|
+
decodedChild.outs.length.should.equal(1);
|
|
1294
|
+
let inputFromParent = undefined;
|
|
1295
|
+
const additionalInputs = [];
|
|
1296
|
+
_.forEach(decodedChild.ins, (input) => {
|
|
1297
|
+
input.should.have.property('hash');
|
|
1298
|
+
input.should.have.property('index');
|
|
1299
|
+
const inputHash = inputParentTxId(input);
|
|
1300
|
+
if (inputHash === parentTxId) {
|
|
1301
|
+
inputFromParent = input;
|
|
1302
|
+
}
|
|
1303
|
+
else {
|
|
1304
|
+
additionalInputs.push(input);
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1307
|
+
should.exist(inputFromParent);
|
|
1308
|
+
const inputFromParentHash = inputParentTxId(inputFromParent);
|
|
1309
|
+
inputFromParentHash.should.equal(parentTxId);
|
|
1310
|
+
inputFromParent.index.should.equal(0);
|
|
1311
|
+
additionalInputs.length.should.equal(2);
|
|
1312
|
+
const childOutput = decodedChild.outs[0];
|
|
1313
|
+
childOutput.should.have.property('value');
|
|
1314
|
+
childOutput.value.should.be.above(minChangeSize);
|
|
1315
|
+
});
|
|
1316
|
+
it('correctly uses the ignoreMaxFeeRate parameter only when necessary', async () => {
|
|
1317
|
+
parentTxId = '75cfc5a7b214c4b73c92c7b02608cde70b226767a9576f84c04407e43fd385bd';
|
|
1318
|
+
(0, nock_1.default)(bgUrl)
|
|
1319
|
+
.get(`/api/v1/wallet/${wallet.id()}/tx/${parentTxId}`)
|
|
1320
|
+
.reply(200, {
|
|
1321
|
+
fee: 434,
|
|
1322
|
+
outputs: [
|
|
1323
|
+
{
|
|
1324
|
+
vout: 0,
|
|
1325
|
+
value: 10348500,
|
|
1326
|
+
isMine: true,
|
|
1327
|
+
chain: 0,
|
|
1328
|
+
},
|
|
1329
|
+
{
|
|
1330
|
+
vout: 1,
|
|
1331
|
+
value: 10000,
|
|
1332
|
+
isMine: true,
|
|
1333
|
+
chain: 11,
|
|
1334
|
+
},
|
|
1335
|
+
],
|
|
1336
|
+
});
|
|
1337
|
+
(0, nock_1.default)(bgUrl)
|
|
1338
|
+
.get(`/api/v1/wallet/${wallet.id()}/unspents`)
|
|
1339
|
+
.query(true)
|
|
1340
|
+
.reply(200, {
|
|
1341
|
+
unspents: [
|
|
1342
|
+
{
|
|
1343
|
+
tx_hash: parentTxId,
|
|
1344
|
+
tx_output_n: 0,
|
|
1345
|
+
value: 10348500,
|
|
1346
|
+
redeemScript: '0020f7b58d455351b7b8ddd7c8986d98244f6a95f0746720091537323b967800f744',
|
|
1347
|
+
chainPath: '/11/160',
|
|
1348
|
+
witnessScript: '5221027f0b45bb4155ea532e3b4312fe0be80166f297d1e0753d2d4a9118c073ad6514210310aa9d68c98831625f329b7826b6c3e3b53e16736b1994b8902442bdcd6653d121026e0ca414f2488b0ab572b99e0ae5442911ab4e0821b2709d885175a527fd552b53ae',
|
|
1349
|
+
},
|
|
1350
|
+
],
|
|
1351
|
+
});
|
|
1352
|
+
(0, nock_1.default)(explorerUrl).get(`/tx/${parentTxId}/hex`).reply(200, fixtures[parentTxId]);
|
|
1353
|
+
(0, nock_1.default)(bgUrl)
|
|
1354
|
+
.post('/api/v1/tx/send', (body) => {
|
|
1355
|
+
// ignore max fee rate must be set for this test
|
|
1356
|
+
return body.ignoreMaxFeeRate;
|
|
1357
|
+
})
|
|
1358
|
+
.reply(200);
|
|
1359
|
+
// monkey patch the bitgo getConstants() function
|
|
1360
|
+
const oldGetConstants = bitgo.__proto__.getConstants;
|
|
1361
|
+
bitgo.__proto__.getConstants = () => ({
|
|
1362
|
+
// child fee rate in this test is 31378 sat/kb
|
|
1363
|
+
// so set the max fee rate just below that limit,
|
|
1364
|
+
// but above the combined fee rate of 20000
|
|
1365
|
+
maxFeeRate: 30000,
|
|
1366
|
+
});
|
|
1367
|
+
await wallet.accelerateTransaction({
|
|
1368
|
+
transactionID: parentTxId,
|
|
1369
|
+
feeRate,
|
|
1370
|
+
walletPassphrase: TestBitGo.TEST_WALLET1_PASSCODE,
|
|
1371
|
+
});
|
|
1372
|
+
nock_1.default.pendingMocks().should.be.empty();
|
|
1373
|
+
bitgo.__proto__.getConstants = oldGetConstants;
|
|
1374
|
+
});
|
|
1375
|
+
});
|
|
1376
|
+
});
|
|
1377
|
+
});
|
|
1378
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2FsbGV0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdGVzdC91bml0L3YxL3dhbGxldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsRUFBRTtBQUNGLG1CQUFtQjtBQUNuQixFQUFFO0FBQ0Ysb0RBQW9EO0FBQ3BELEVBQUU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUYseUNBQXdDO0FBRXhDLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO0FBQ2pELG9EQUFpRDtBQUNqRCwwQ0FBNEI7QUFDNUIsbURBQThDO0FBQzlDLDhEQUFnRDtBQUNoRCwrQ0FBaUM7QUFDakMsZ0RBQXdCO0FBQ3hCLDZDQUErQjtBQUUvQiw0REFBdUQ7QUFFdkQsY0FBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7QUFFekIsTUFBTSxTQUFTLEdBQUc7SUFDaEIscUJBQXFCLEVBQUUsMEJBQTBCO0NBQ2xELENBQUM7QUFDRixNQUFNLHNCQUFzQixHQUFHLG1CQUFRLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQztBQUNqRSxtQkFBUSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEdBQUc7SUFDbEMsSUFBQSxjQUFJLEVBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEdBQUcsQ0FBQywwQkFBMEIsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBRTdGLGdDQUFnQztJQUNoQyxtQkFBUSxDQUFDLFlBQVksQ0FBQyxHQUFHLFNBQVMsQ0FBQztJQUVuQyxPQUFPLHNCQUFzQixDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsU0FBZ0IsQ0FBQyxDQUFDO0FBQzlELENBQUMsQ0FBQztBQUNGLFFBQVEsQ0FBQywwQkFBMEIsRUFBRTtJQUNuQyxNQUFNLFFBQVEsR0FBRyxJQUFBLDJCQUFXLEdBQUUs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R0FBRyxDQUFDLENBQUM7Z0JBRWQsaURBQWlEO2dCQUNqRCxNQUFNLGVBQWUsR0FBSSxLQUFhLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQztnQkFDN0QsS0FBYSxDQUFDLFNBQVMsQ0FBQyxZQUFZLEdBQUcsR0FBRyxFQUFFLENBQUMsQ0FBQztvQkFDN0MsOENBQThDO29CQUM5QyxpREFBaUQ7b0JBQ2pELDJDQUEyQztvQkFDM0MsVUFBVSxFQUFFLEtBQUs7aUJBQ2xCLENBQUMsQ0FBQztnQkFFSCxNQUFNLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQztvQkFDakMsYUFBYSxFQUFFLFVBQVU7b0JBQ3pCLE9BQU87b0JBQ1AsZ0JBQWdCLEVBQUUsU0FBUyxDQUFDLHFCQUFxQjtpQkFDbEQsQ0FBQyxDQUFDO2dCQUNILGNBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUVyQyxLQUFhLENBQUMsU0FBUyxDQUFDLFlBQVksR0FBRyxlQUFlLENBQUM7WUFDMUQsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvL1xuLy8gVGVzdHMgZm9yIFdhbGxldFxuLy9cbi8vIENvcHlyaWdodCAyMDE0LCBCaXRHbywgSW5jLiAgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbi8vXG5cbmltcG9ydCB7IGdldEZpeHR1cmUgfSBmcm9tICcuL2ZpeHR1cmVzJztcblxuY29uc3QgV2FsbGV0ID0gcmVxdWlyZSgnLi4vLi4vLi4vc3JjL3YxL3dhbGxldCcpO1xuaW1wb3J0IHsgQml0R29BUEkgfSBmcm9tICcuLi8uLi8uLi9zcmMvYml0Z29BUEknO1xuaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgY29tbW9uIH0gZnJvbSAnQGJpdGdvLWJldGEvc2RrLWNvcmUnO1xuaW1wb3J0ICogYXMgdXR4b2xpYiBmcm9tICdAYml0Z28tYmV0YS91dHhvLWxpYic7XG5pbXBvcnQgKiBhcyBzaG91bGQgZnJvbSAnc2hvdWxkJztcbmltcG9ydCBub2NrIGZyb20gJ25vY2snO1xuaW1wb3J0ICogYXMgc2lub24gZnJvbSAnc2lub24nO1xuXG5pbXBvcnQgeyBnZXRGaXh0dXJlcyB9IGZyb20gJy4vZml4dHVyZXMvYWNjZWxlcmF0ZS10eCc7XG5cbm5vY2suZGlzYWJsZU5ldENvbm5lY3QoKTtcblxuY29uc3QgVGVzdEJpdEdvID0ge1xuICBURVNUX1dBTExFVDFfUEFTU0NPREU6ICdpVldlQVRqcUxTMWpKU2hyUHBFVHRpMGInLFxufTtcbmNvbnN0IG9yaWdpbmFsRmV0Y2hDb25zdGFudHMgPSBCaXRHb0FQSS5wcm90b3R5cGUuZmV0Y2hDb25zdGFudHM7XG5CaXRHb0FQSS5wcm90b3R5cGUuZmV0Y2hDb25zdGFudHMgPSBmdW5jdGlvbiAodGhpczogYW55KSB7XG4gIG5vY2sodGhpcy5fYmFzZVVybCkuZ2V0KCcvYXBpL3YxL2NsaWVudC9jb25zdGFudHMnKS5yZXBseSgyMDAsIHsgdHRsOiAzNjAwLCBjb25zdGFudHM6IHt9IH0pO1xuXG4gIC8vIGZvcmNlIGNsaWVudCBjb25zdGFudHMgcmVsb2FkXG4gIEJpdEdvQVBJWydfY29uc3RhbnRzJ10gPSB1bmRlZmluZWQ7XG5cbiAgcmV0dXJuIG9yaWdpbmFsRmV0Y2hDb25zdGFudHMuYXBwbHkodGhpcywgYXJndW1lbnRzIGFzIGFueSk7XG59O1xuZGVzY3JpYmUoJ1dhbGxldCBQcm90b3R5cGUgTWV0aG9kcycsIGZ1bmN0aW9uICgpIHtcbiAgY29uc3QgZml4dHVyZXMgPSBnZXRGaXh0dXJlcygpO1xuXG4gIGxldCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7IGVudjogJ3Rlc3QnIH0pO1xuICAvLyBiaXRnby5pbml0aWFsaXplVGVzdFZhcnMoKTtcblxuICBjb25zdCB1c2VyS2V5cGFpciA9IHtcbiAgICB4cHJ2OiAneHBydjlzMjFaclFIMTQzSzJmSjkxUzRCUnN1cGNZckU2bW1ZOTZmY1g1SGtob1Rycndtd2pkMTZDbjg3Y1dpbkpqQnlyZnBvamp4N2V6c0pMeDdUQUtMVDhtOGhNNUtheDlZY294bkJlSlozdDJrJyxcbiAgICB4cHViOiAneHB1YjY2MU15TXdBcVJiY0Y5TmM3VGJCbzFyWkFhZ2lXRVZQV0tiREtUaE5HOHpxams3NkhBS0xrYVNiVG42ZEsyZFFQZnVEN3hqaWN4Q1pWV3ZqNjdmUDVuUTlXN1FVUm1vTVZBWDhtNmpac0dwJyxcbiAgICByYXdQdWI6ICcwMmMxMDNhYzc0NDgxODc0YjVlZjBmMzg1ZDEyNzI1ZTRmMTRhZWRjOWUwMGJjODE0Y2U5NmY0N2Y2MmNlN2FkZjInLFxuICAgIHJhd1BydjogJzkzNmM1YWYzZjhhZjgxZjc1Y2RhZDFiMDhmMjllN2Q5YzAxZTU5OGUyZGIyZDdiZTE4YjllNWE4NjQ2ZTg3YzYnLFxuICAgIHBhdGg6ICdtJyxcbiAgICB3YWxsZXRTdWJQYXRoOiAnLzAvMCcsXG4gIH07XG4gIGNvbnN0IGJhY2t1cEtleXBhaXIgPSB7XG4gICAgeHBydjogJ3hwcnY5czIxWnJRSDE0M0s0N3NFa0xreWtnWW1xMXhGNVpXclBZaFVaY21CcFBGTVFvanZHVW1FY3I1akZYWUdmcjhDcEZkcFR2aFE3TDlOTjJyTHRzQkZqU2l4M0JBandKY0JqNlUzRDVoeFRQYycsXG4gICAgeHB1YjogJ3hwdWI2NjFNeU13QXFSYmNHYndock5IejdwVldQM25qVjJFaGttZDVOMUFvTmluTEhjNTRwMjVWQWVRRDZxMm9UUzN1dURNRG5mblhudGhiUzl1ZkM4SlZZcE5uV1U1Um4zcFlhTnVMQ055d2t3MScsXG4gICAgcmF3UHViOiAnMDNiYmNiNzM5OTc5NzcwNjhkOWUzNjY2NmJiZDVjZDM3NTc5YWNhZThlMmJkNWNlOWQwYTZlNWMxNTBhNDIzYmMzJyxcbiAgICByYXdQcnY6ICc3N2ExNWYxNDc5NmY0MDAxZDEwOTJhZTg0Zjc2NmJkODY5ZTliZWU2YmZmYWU2NTQ3ZGVmNTA0NWI5NmZhOTQzJyxcbiAgICBwYXRoOiAnbScsXG4gICAgd2FsbGV0U3ViUGF0aDogJy8wLzAnLFxuICB9O1xuICBjb25zdCBiaXRnb0tleSA9IHtcbiAgICB4cHViOiAneHB1YjY2MU15TXdBcVJiY0dRY1ZGaXdjcnRjN2Mzdm9wc1g5NmpzSlVZUGNGTVJFY1JUcUFxc3FidjJaUnlDSkFQTG01Tk1IQ3k4NUUzWndwVDRFQVV3OVdHVTd2TWhHNno4M2hEZUtYQlduNkxmJyxcbiAgICBwYXRoOiAnbScsXG4gICAgd2FsbGV0U3ViUGF0aDogJy8wLzAnLFxuICB9O1xuXG4gIGNvbnN0IGZha2VXYWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCB7XG4gICAgaWQ6ICcyTkNvU2ZISDZMczRDZFRTNVFhaGdDOWs3eDlSZlhlU3dZNCcsXG4gICAgcHJpdmF0ZTogeyBrZXljaGFpbnM6IFt1c2VyS2V5cGFpciwgYmFja3VwS2V5cGFpciwgYml0Z29LZXldIH0sXG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdHZW5lcmF0ZSBBZGRyZXNzJywgZnVuY3Rpb24gKCkge1xuICAgIGJlZm9yZSgoKSA9PiBub2NrLnBlbmRpbmdNb2NrcygpLnNob3VsZC5iZS5lbXB0eSgpKTtcblxuICAgIGl0KCdnZW5lcmF0ZSBmaXJzdCBhZGRyZXNzJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgaWRBZGRyZXNzID0gZmFrZVdhbGxldC5nZW5lcmF0ZUFkZHJlc3MoeyBwYXRoOiAnLzAvMCcsIHNlZ3dpdDogZmFsc2UgfSk7XG4gICAgICBpZEFkZHJlc3MuYWRkcmVzcy5zaG91bGQuZXF1YWwoZmFrZVdhbGxldC5pZCgpKTtcbiAgICAgIGlkQWRkcmVzcy5jaGFpbi5zaG91bGQuZXF1YWwoMCk7XG4gICAgICBpZEFkZHJlc3MuaW5kZXguc2hvdWxkLmVxdWFsKDApO1xuICAgICAgaWRBZGRyZXNzLmNoYWluUGF0aC5zaG91bGQuZXF1YWwoJy8wLzAnKTtcbiAgICAgIGlkQWRkcmVzcy5wYXRoLnNob3VsZC5lcXVhbCgnLzAvMCcpO1xuICAgICAgaWRBZGRyZXNzLm91dHB1dFNjcmlwdC5zaG91bGQuZXF1YWwoJ2E5MTRkNjgyNDc2ZTliZDU0NDU0YTg4NWY5ZGZmMWU2MDRlOTljZWY0M2RjODcnKTtcbiAgICAgIGlkQWRkcmVzcy5yZWRlZW1TY3JpcHQuc2hvdWxkLmVxdWFsKFxuICAgICAgICAnNTIyMTAyY2QzYzhlNjAwNmE0NjI3NzA1MDIxZDFkMDE2ZDA5N2MyOTQ0ZDk4MTAwYTQ3YmYyZGE2N2E1ZmUxNWFlZWIzNDIxMDJlZTFmYTllODEyZTc3OTM1NmFhM2MzMWViZjMxN2QwY2ZmZWJhYjkyODY0Y2ZlMzhiYWIyMjNlMDgyMGY5OGJjMjEwMjZiYTA1NzUyYmFhNmVhZmQ1YzU2NTlkYTYyYjdmMGFjNTFmZDI4ODZiNjVjMjQxZDBhZmVmMWM0ZmRmYTFjYmM1M2FlJ1xuICAgICAgKTtcbiAgICAgIGlkQWRkcmVzcy53YWxsZXQuc2hvdWxkLmVxdWFsKGZha2VXYWxsZXQuaWQoKSk7XG4gICAgfSk7XG5cbiAgICBpdCgnZ2VuZXJhdGUgc2Vjb25kIGFkZHJlc3MnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBwMnNoQWRkcmVzcyA9IGZha2VXYWxsZXQuZ2VuZXJhdGVBZGRyZXNzKHsgcGF0aDogJy8wLzEnLCBzZWd3aXQ6IGZhbHNlIH0pO1xuICAgICAgcDJzaEFkZHJlc3MuYWRkcmVzcy5zaG91bGQuZXF1YWwoJzJONXk1UkxWcWRaaTdxcDVQbXpNZFBSNll2UXpVcUJRRldLJyk7XG4gICAgICBwMnNoQWRkcmVzcy5jaGFpbi5zaG91bGQuZXF1YWwoMCk7XG4gICAgICBwMnNoQWRkcmVzcy5pbmRleC5zaG91bGQuZXF1YWwoMSk7XG4gICAgICBwMnNoQWRkcmVzcy5jaGFpblBhdGguc2hvdWxkLmVxdWFsKCcvMC8xJyk7XG4gICAgICBwMnNoQWRkcmVzcy5wYXRoLnNob3VsZC5lcXVhbCgnLzAvMScpO1xuICAgICAgcDJzaEFkZHJlc3Mub3V0cHV0U2NyaXB0LnNob3VsZC5lcXVhbCgnYTkxNDhiOGJkM2RhNjhlZjBmMjQ2NTUyMzE0NmJkMmRlMzNjODZiOWM4NzE4NycpO1xuICAgICAgcDJzaEFkZHJlc3MucmVkZWVtU2NyaXB0LnNob3VsZC5lcXVhbChcbiAgICAgICAgJzUyMjEwMjcwOWVkYjZhMjE5OGQzNjRjNDg1YTc2Yjk4MWQxMjA2NWVhYmRlOGFhMmQ4NWJkN2U3YTAzNWY3ZWNiMzU3OWIyMTAyYTcyNGVmZWQ0OTljMDVmZGI0ZGExZTEzOTcwMDk1MWZhZTAwYzAwNmIzMjgzODg4YmRmZDFiNDY5NzkyOTIyNDIxMDJiMzJhYmU0NGQ2MTk4NmZmNTdiODM1ZTNiZDE2MjkzZDkzZjMwM2QwZDhmYjA0NTRlMmM5Y2NlZGE1YzQ5Mjk4NTNhZSdcbiAgICAgICk7XG4gICAgICBwMnNoQWRkcmVzcy53YWxsZXQuc2hvdWxkLmVxdWFsKGZha2VXYWxsZXQuaWQoKSk7XG4gICAgfSk7XG5cbiAgICBpdCgnZ2VuZXJhdGUgY2hhbmdlIGFkZHJlc3MnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBwMnNoQWRkcmVzcyA9IGZha2VXYWxsZXQuZ2VuZXJhdGVBZGRyZXNzKHsgcGF0aDogJy8xLzAnLCBzZWd3aXQ6IGZhbHNlIH0pO1xuICAgICAgcDJzaEFkZHJlc3MuYWRkcmVzcy5zaG91bGQuZXF1YWwoJzJORmo5SnJwWmM1TXlZbkNvdXlSRXR6Tlk0ZW95S1dEZmdQJyk7XG4gICAgICBwMnNoQWRkcmVzcy5jaGFpbi5zaG91bGQuZXF1YWwoMSk7XG4gICAgICBwMnNoQWRkcmVzcy5pbmRleC5zaG91bGQuZXF1YWwoMCk7XG4gICAgICBwMnNoQWRkcmVzcy5jaGFpblBhdGguc2hvdWxkLmVxdWFsKCcvMS8wJyk7XG4gICAgICBwMnNoQWRkcmVzcy5wYXRoLnNob3VsZC5lcXVhbCgnLzEvMCcpO1xuICAgICAgcDJzaEFkZHJlc3Mub3V0cHV0U2NyaXB0LnNob3VsZC5lcXVhbCgnYTkxNGY2OWE4MWZhZDc1ZWE2NWFkMTY2ZGE3NjUxNTI5MTY3OWE0ZjFhZDg4NycpO1xuICAgICAgcDJzaEFkZHJlc3MucmVkZWVtU2NyaXB0LnNob3VsZC5lcXVhbChcbiAgICAgICAgJzUyMjEwMjBiNGM0Zjg5MWE1NTIwZjVhMGI2ODE4ZDhkNTM5MTk1NTJhMGQ0ZDgwNmI1ZmEwNWM5NzcwODA3OWQ4MzczN2UyMTAyYzVjYzQ5YmYwMzMxZWIwYjA4OTBhN2U3ZDg3ZjdlOWUwZGVhNTE1NDM4MjgwZGM3NjgzNGMyMWQxOThlZmUwODIxMDM3MGU1MmNmNzQxZWJmNDUxMzc0OWQwMjg4MzlkNjk2ODkxZWI3ODliYTdhNTg1OTJjZmJjODU3Y2RjMGE5ZGU3NTNhZSdcbiAgICAgICk7XG4gICAgICBwMnNoQWRkcmVzcy53YWxsZXQuc2hvdWxkLmVxdWFsKGZha2VXYWxsZXQuaWQoKSk7XG4gICAgfSk7XG5cbiAgICBpdCgnZ2VuZXJhdGUgc2Vnd2l0IGFkZHJlc3MnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBzZWd3aXRBZGRyZXNzID0gZmFrZVdhbGxldC5nZW5lcmF0ZUFkZHJlc3MoeyBwYXRoOiAnLzEwLzAnLCBzZWd3aXQ6IHRydWUgfSk7XG4gICAgICBzZWd3aXRBZGRyZXNzLmFkZHJlc3Muc2hvdWxkLmVxdWFsKCcyTjVFVmVnUlBXbm1lZDJQcHFEZ2daUHc3RGNORGd1Ull2OCcpO1xuICAgICAgc2Vnd2l0QWRkcmVzcy5jaGFpbi5zaG91bGQuZXF1YWwoMTApO1xuICAgICAgc2Vnd2l0QWRkcmVzcy5pbmRleC5zaG91bGQuZXF1YWwoMCk7XG4gICAgICBzZWd3aXRBZGRyZXNzLmNoYWluUGF0aC5zaG91bGQuZXF1YWwoJy8xMC8wJyk7XG4gICAgICBzZWd3aXRBZGRyZXNzLnBhdGguc2hvdWxkLmVxdWFsKCcvMTAvMCcpO1xuICAgICAgc2Vnd2l0QWRkcmVzcy5vdXRwdXRTY3JpcHQuc2hvdWxkLmVxdWFsKCdhOTE0ODM3ZTJhZGNiNmY2Mzg2ZmVhM2M1ZDQwMzE2YjI4MmNjZjM5MTIxZDg3Jyk7XG4gICAgICBzZWd3aXRBZGRyZXNzLnJlZGVlbVNjcmlwdC5zaG91bGQuZXF1YWwoJzAwMjBhNjJhZmVlMWQyMTFjNWFkYjk3MzlmODFlZDRlMzYzMzBlNmNkYTY1MWM3YmRkMzE0ZTMyY2NjNDY1ZWMyMjAzJyk7XG4gICAgICBzZWd3aXRBZGRyZXNzLndpdG5lc3NTY3JpcHQuc2hvdWxkLmVxdWFsKFxuICAgICAgICAnNTIyMTAyN2IzMDUwNTc3N2E0ZWQ4OTQ3YjA2OWZjYjAxMTZlMjg3OTk1ZDk3Mjc4ZDg0ZGE0ZGI2YzYxMzI3MDY0OWQzZDIxMDM0YzMwZTUxZjFlNjE0Y2FkNjY3ODE1YzkxZDA0MTQwNGMxODIyNWQwYjJmNzllMmMwYmNiNjNmZDI2MDQzMTZiMjEwM2I2NWRkZmMwNjE1OWI2OTE2OTMzOTA3NjFlNzVhMGI4Y2M3YTY1YjZmZjMwNWQwOTRmM2FkOTcyZjE3OTUzZmU1M2FlJ1xuICAgICAgKTtcbiAgICAgIHNlZ3dpdEFkZHJlc3Mud2FsbGV0LnNob3VsZC5lcXVhbChmYWtlV2FsbGV0LmlkKCkpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnQ3JlYXRlIFRyYW5zYWN0aW9uJywgZnVuY3Rpb24gKCkge1xuICAgIGxldCBiZ1VybCwgYmdVcmxUZXN0O1xuICAgIGxldCBmYWtlUHJvZFdhbGxldDtcblxuICAgIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgICBub2NrLnBlbmRpbmdNb2NrcygpLnNob3VsZC5iZS5lbXB0eSgpO1xuICAgICAgY29uc3QgcHJvZEJpdGdvID0gbmV3IEJpdEdvQVBJKHsgZW52OiAncHJvZCcgfSk7XG4gICAgICAvLyBwcm9kQml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgICBiZ1VybCA9IGNvbW1vbi5FbnZpcm9ubWVudHNbcHJvZEJpdGdvLmdldEVudigpXS51cmk7XG4gICAgICBmYWtlUHJvZFdhbGxldCA9IG5ldyBXYWxsZXQocHJvZEJpdGdvLCB7XG4gICAgICAgIGlkOiAnMk5Db1NmSEg2THM0Q2RUUzVRYWhnQzlrN3g5UmZYZVN3WTQnLFxuICAgICAgICBwcml2YXRlOiB7IGtleWNoYWluczogW3VzZXJLZXlwYWlyLCBiYWNrdXBLZXlwYWlyLCBiaXRnb0tleV0gfSxcbiAgICAgIH0pO1xuICAgICAgYmdVcmxUZXN0ID0gY29tbW9uLkVudmlyb25tZW50c1tiaXRnby5nZXRFbnYoKV0udXJpO1xuICAgIH0pO1xuXG4gICAgaXQoJ2V4dHJhIHVuc3BlbnQgZmV0Y2ggcGFyYW1zJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYmlsbGluZ0FkZHJlc3MgPSAnM0o5OHQxV3BFWjczQ05tUXZpZWNybnlpV3JucVJoV05MeSc7XG4gICAgICBjb25zdCBjdXN0b21VbnNwZW50c0ZldGNoUGFyYW1zID0geyB0ZXN0OiAxMjMgfTtcbiAgICAgIGNvbnN0IHNlbmRBbW91bnQgPSAxZTU7XG5cbiAgICAgIG5vY2soYmdVcmwpLnBvc3QoJy9hcGkvdjEvYmlsbGluZy9hZGRyZXNzJykucmVwbHkoMjAwLCB7IGFkZHJlc3M6IGJpbGxpbmdBZGRyZXNzIH0pO1xuXG4gICAgICBjb25zdCBzY29wZSA9IG5vY2soYmdVcmwpXG4gICAgICAgIC5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7ZmFrZVByb2RXYWxsZXQuaWQoKX0vdW5zcGVudHNgKVxuICAgICAgICAucXVlcnkoXG4gICAgICAgICAgXy5tZXJnZShjdXN0b21VbnNwZW50c0ZldGNoUGFyYW1zLCB7XG4gICAgICAgICAgICBzZWd3aXQ6IHRydWUsXG4gICAgICAgICAgICB0YXJnZXQ6IHNlbmRBbW91bnQsXG4gICAgICAgICAgICBtaW5TaXplOiAwLFxuICAgICAgICAgIH0pXG4gICAgICAgIClcbiAgICAgICAgLnJlcGx5KDIwMCwgeyB1bnNwZW50czogW10gfSk7XG5cbiAgICAgIGF3YWl0IGZha2VQcm9kV2FsbGV0XG4gICAgICAgIC5jcmVhdGVUcmFuc2FjdGlvbih7XG4gICAgICAgICAgdW5zcGVudHNGZXRjaFBhcmFtczogY3VzdG9tVW5zcGVudHNGZXRjaFBhcmFtcyxcbiAgICAgICAgICByZWNpcGllbnRzOiB7IFtiaWxsaW5nQWRkcmVzc106IHNlbmRBbW91bnQgfSxcbiAgICAgICAgICBmZWVSYXRlOiAxMDAwMCxcbiAgICAgICAgICBiaXRnb0ZlZToge1xuICAgICAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICAgICAgYWRkcmVzczogJycsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJzAgdW5zcGVudHMgYXZhaWxhYmxlIGZvciB0cmFuc2FjdGlvbiBjcmVhdGlvbicpO1xuXG4gICAgICBzY29wZS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ2RlZmF1bHQgcDJzaCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHAyc2hBZGRyZXNzID0gZmFrZVByb2RXYWxsZXQuZ2VuZXJhdGVBZGRyZXNzKHsgcGF0aDogJy8wLzEzJywgc2Vnd2l0OiBmYWxzZSB9KTtcbiAgICAgIGNvbnN0IHVuc3BlbnQ6IGFueSA9IHtcbiAgICAgICAgYWRkcmVzc2VzOiBbJzJOQ0VEbW1LTk5ucUt2bld3N3BFM1JMenVGZTVhSEhWeTFYJ10sXG4gICAgICAgIHZhbHVlOiAnMC4wMDUwNDQyMicsXG4gICAgICAgIHZhbHVlX2ludDogNTA0NDIyLFxuICAgICAgICB0eGlkOiAnYjgxNmRlZDg5YzNkOGQ1MDIxYjAxMDk3ZjRhMzEyOWE2YTY4YTVjYjdjODg2ZTk3OTQ1ZjQyMDVjYmE1ZGU0NCcsXG4gICAgICAgIG46IDEsXG4gICAgICAgIHNjcmlwdF9wdWJfa2V5OiB7XG4gICAgICAgICAgYXNtOiAnT1BfSEFTSDE2MCBkMDM5Y2IzMzQ0Mjk0YTVhMzg0YTU1MDhhMDA2NDQ0YzQyMGNiYzExIE9QX0VRVUFMJyxcbiAgICAgICAgICBoZXg6ICdhOTE0ZDAzOWNiMzM0NDI5NGE1YTM4NGE1NTA4YTAwNjQ0NGM0MjBjYmMxMTg3JyxcbiAgICAgICAgfSxcbiAgICAgICAgcmVxX3NpZ3M6IDEsXG4gICAgICAgIHR5cGU6ICdzY3JpcHRoYXNoJyxcbiAgICAgICAgY29uZmlybWF0aW9uczogOSxcbiAgICAgICAgaWQ6IDYxMzMwMjI5LFxuICAgICAgfTtcbiAgICAgIF8uZXh0ZW5kKHVuc3BlbnQsIHAyc2hBZGRyZXNzKTtcbiAgICAgIHVuc3BlbnQudmFsdWUgPSB1bnNwZW50LnZhbHVlX2ludDtcbiAgICAgIHVuc3BlbnQudHhfaGFzaCA9IHVuc3BlbnQudHhpZDtcbiAgICAgIHVuc3BlbnQudHhfb3V0cHV0X24gPSB1bnNwZW50Lm47XG4gICAgICB1bnNwZW50LnNjcmlwdCA9IHVuc3BlbnQub3V0cHV0U2NyaXB0O1xuXG4gICAgICBub2NrKGJnVXJsKS5wb3N0KCcvYXBpL3YxL2JpbGxpbmcvYWRkcmVzcycpLnJlcGx5KDIwMCwgeyBhZGRyZXNzOiAnMk1zd1Fqa3ZONm9XWWRFN0wyYnJKNWNBQU1qUG1HNTlvY28nIH0pO1xuXG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IChhd2FpdCBmYWtlUHJvZFdhbGxldC5jcmVhdGVUcmFuc2FjdGlvbih7XG4gICAgICAgIGNoYW5nZUFkZHJlc3M6IHAyc2hBZGRyZXNzLmFkZHJlc3MsXG4gICAgICAgIHVuc3BlbnRzOiBbdW5zcGVudF0sXG4gICAgICAgIHJlY2lwaWVudHM6IHt9LFxuICAgICAgICBub1NwbGl0Q2hhbmdlOiB0cnVlLFxuICAgICAgICBmb3JjZUNoYW5nZUF0RW5kOiB0cnVlLFxuICAgICAgICBmZWVSYXRlOiAxMDAwMCxcbiAgICAgICAgYml0Z29GZWU6IHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgYWRkcmVzczogJycsXG4gICAgICAgIH0sXG4gICAgICAgIG9wUmV0dXJuczogeyAnQml0R28gcDJzaCB0ZXN0JzogMTAwMCB9LFxuICAgICAgfSkpIGFzIGFueTtcbiAgICAgIHRyYW5zYWN0aW9uLnRyYW5zYWN0aW9uSGV4LnNob3VsZC5lcXVhbChcbiAgICAgICAgJzAxMDAwMDAwMDE0NGRlYTVjYjA1NDI1Zjk0OTc2ZTg4N2NjYmE1Njg2YTlhMTJhM2Y0OTcxMGIwMjE1MDhkM2Q5Y2Q4ZGUxNmI4MDEwMDAwMDAwMGZmZmZmZmZmMDJlODAzMDAwMDAwMDAwMDAwMTE2YTBmNDI2OTc0NDc2ZjIwNzAzMjczNjgyMDc0NjU3Mzc0MjJhMTA3MDAwMDAwMDAwMDE3YTkxNGQwMzljYjMzNDQyOTRhNWEzODRhNTUwOGEwMDY0NDRjNDIwY2JjMTE4NzAwMDAwMDAwJ1xuICAgICAgKTtcblxuICAgICAgLy8gYWRkIGZpcnN0IHNpZ25hdHVyZVxuICAgICAgdHJhbnNhY3Rpb24ua2V5Y2hhaW4gPSB1c2VyS2V5cGFpcjtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZTEgPSAoYXdhaXQgZmFrZVByb2RXYWxsZXQuc2lnblRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uKSkgYXMgYW55O1xuICAgICAgc2lnbmF0dXJlMS50eC5zaG91bGQuZXF1YWwoXG4gICAgICAgICcwMTAwMDAwMDAxNDRkZWE1Y2IwNTQyNWY5NDk3NmU4ODdjY2JhNTY4NmE5YTEyYTNmNDk3MTBiMDIxNTA4ZDNkOWNkOGRlMTZiODAxMDAwMDAwYjYwMDQ3MzA0NDAyMjAyMWZhNzNkNWZlNjFhYzg5NDJjZDcwZmY0NTA3YzU3NDY3N2NlNzQ3ZGU1YmM0NmMzZGQyZTM4ZWMyNDQ4ZmNlMDIyMDQ3OTA2ZDJjMDE1NDMzN2FiOTYwNDFlOGZiNThjMjQzYjliY2U1Zjg4MThmYTk5MTY0M2MxMjYwYTE4NTlhZDgwMTAwMDA0YzY5NTIyMTAzMWNkMjI3ZTQwYWQ2MWI0ZTEzNzEwOWNiMjg0NWViNmY1YTU4NGVkNWM2N2Q5ZDMxMzVjZGFhNTA0NWE4NDJlYTIxMDNhMmU3YjU0YzdiMmRhMDk5MjU1NTM1M2I4ZTI2YzZhY2ZmNDI0OGY0MzUxZjA4Nzg3YmYzZTJlZmM5NGI2NTgzMjEwMjVjMmE2Y2RlMzNjMmQ3M2NjZjEyZWVjZjY0YzU0ZjA4ZjcyMmMyZjA3MzgyNDQ5ODk1MDY5NWU5ODgzYjE0MTI1M2FlZmZmZmZmZmYwMmU4MDMwMDAwMDAwMDAwMDAxMTZhMGY0MjY5NzQ0NzZmMjA3MDMyNzM2ODIwNzQ2NTczNzQyMmExMDcwMDAwMDAwMDAwMTdhOTE0ZDAzOWNiMzM0NDI5NGE1YTM4NGE1NTA4YTAwNjQ0NGM0MjBjYmMxMTg3MDAwMDAwMDAnXG4gICAgICApO1xuXG4gICAgICAvLyBhZGQgc2Vjb25kIHNpZ25hdHVyZVxuICAgICAgdHJhbnNhY3Rpb24udHJhbnNhY3Rpb25IZXggPSBzaWduYXR1cmUxLnR4O1xuICAgICAgdHJhbnNhY3Rpb24ua2V5Y2hhaW4gPSBiYWNrdXBLZXlwYWlyO1xuICAgICAgdHJhbnNhY3Rpb24uZnVsbExvY2FsU2lnbmluZyA9IHRydWU7XG4gICAgICBjb25zdCBzaWduYXR1cmUyID0gKGF3YWl0IGZha2VQcm9kV2FsbGV0LnNpZ25UcmFuc2FjdGlvbih0cmFuc2FjdGlvbikpIGFzIGFueTtcbiAgICAgIC8vIFRoaXMgdHJhbnNhY3Rpb24gaGFzIGFjdHVhbGx5IHdvcmtlZDogaHR0cHM6Ly90ZXN0bmV0LnNtYXJ0Yml0LmNvbS5hdS90eC9hOGNjYjkyODE2OTAzMmQ2ZTFmMzdiZjgxZGZkOWFiNmQ5MDM2MmE0Zjg0ZTU3NzM5N2ZhNjkwYWE3MTE1NTBjXG4gICAgICAvLyBOb3RlIHRoYXQgdGhlIHR4IGhleCBiZWxvdyBubyBsb25nZXIgY29ycmVzcG9uZHMgdG8gdGhlIGFib3ZlIHRyYW5zYWN0aW9uIGJlY2F1c2Ugb3VyIGZlZSBlc3RpbWF0aW9uIGhhc1xuICAgICAgLy8gY2hhbmdlZCwgY2hhbmdpbmcgdGhlIG91dHB1dCBhbW91bnRzIGFuZCB0aHVzIHRoZSB0eCBoZXguXG4gICAgICBzaWduYXR1cmUyLnR4LnNob3VsZC5lcXVhbChcbiAgICAgICAgJzAxMDAwMDAwMDE0NGRlYTVjYjA1NDI1Zjk0OTc2ZTg4N2NjYmE1Njg2YTlhMTJhM2Y0OTcxMGIwMjE1MDhkM2Q5Y2Q4ZGUxNmI4MDEwMDAwMDBmZGZkMDAwMDQ3MzA0NDAyMjAyMWZhNzNkNWZlNjFhYzg5NDJjZDcwZmY0NTA3YzU3NDY3N2NlNzQ3ZGU1YmM0NmMzZGQyZTM4ZWMyNDQ4ZmNlMDIyMDQ3OTA2ZDJjMDE1NDMzN2FiOTYwNDFlOGZiNThjMjQzYjliY2U1Zjg4MThmYTk5MTY0M2MxMjYwYTE4NTlhZDgwMTQ3MzA0NDAyMjAyYWUwMWYwMWI1YWUwYzNmYTdkNjdhYzczZGI4MTkzMmNiNWFjYTEwZGIxNmE5OTA2M2ZlZjQ1ZTNmMTM5OGNkMDIyMDU1MDAxYmE3ZTE2M2NiMzUwOTEwZmM3MzIxZWNkN2ViNjM1OWIzMjFkNGMwNDg4NzQ4NGQ5YzcyODRiNzhjNDcwMTAwNGM2OTUyMjEwMzFjZDIyN2U0MGFkNjFiNGUxMzcxMDljYjI4NDVlYjZmNWE1ODRlZDVjNjdkOWQzMTM1Y2RhYTUwNDVhODQyZWEyMTAzYTJlN2I1NGM3YjJkYTA5OTI1NTUzNTNiOGUyNmM2YWNmZjQyNDhmNDM1MWYwODc4N2JmM2UyZWZjOTRiNjU4MzIxMDI1YzJhNmNkZTMzYzJkNzNjY2YxMmVlY2Y2NGM1NGYwOGY3MjJjMmYwNzM4MjQ0OTg5NTA2OTVlOTg4M2IxNDEyNTNhZWZmZmZmZmZmMDJlODAzMDAwMDAwMDAwMDAwMTE2YTBmNDI2OTc0NDc2ZjIwNzAzMjczNjgyMDc0NjU3Mzc0MjJhMTA3MDAwMDAwMDAwMDE3YTkxNGQwMzljYjMzNDQyOTRhNWEzODRhNTUwOGEwMDY0NDRjNDIwY2JjMTE4NzAwMDAwMDAwJ1xuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdCQ0ggcDJzaCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHAyc2hBZGRyZXNzID0gZmFrZVByb2RXYWxsZXQuZ2VuZXJhdGVBZGRyZXNzKHsgcGF0aDogJy8wLzEzJywgc2Vnd2l0OiBmYWxzZSB9KTtcbiAgICAgIGNvbnN0IHVuc3BlbnQ6IGFueSA9IHtcbiAgICAgICAgYWRkcmVzc2VzOiBbJzJOQ0VEbW1LTk5ucUt2bld3N3BFM1JMenVGZTVhSEhWeTFYJ10sXG4gICAgICAgIHZhbHVlOiAnMC4wMDUwNDQyMicsXG4gICAgICAgIHZhbHVlX2ludDogNTA0NDIyLFxuICAgICAgICB0eGlkOiAnYjgxNmRlZDg5YzNkOGQ1MDIxYjAxMDk3ZjRhMzEyOWE2YTY4YTVjYjdjODg2ZTk3OTQ1ZjQyMDVjYmE1ZGU0NCcsXG4gICAgICAgIG46IDEsXG4gICAgICAgIHNjcmlwdF9wdWJfa2V5OiB7XG4gICAgICAgICAgYXNtOiAnT1BfSEFTSDE2MCBkMDM5Y2IzMzQ0Mjk0YTVhMzg0YTU1MDhhMDA2NDQ0YzQyMGNiYzExIE9QX0VRVUFMJyxcbiAgICAgICAgICBoZXg6ICdhOTE0ZDAzOWNiMzM0NDI5NGE1YTM4NGE1NTA4YTAwNjQ0NGM0MjBjYmMxMTg3JyxcbiAgICAgICAgfSxcbiAgICAgICAgcmVxX3NpZ3M6IDEsXG4gICAgICAgIHR5cGU6ICdzY3JpcHRoYXNoJyxcbiAgICAgICAgY29uZmlybWF0aW9uczogOSxcbiAgICAgICAgaWQ6IDYxMzMwMjI5LFxuICAgICAgfTtcbiAgICAgIF8uZXh0ZW5kKHVuc3BlbnQsIHAyc2hBZGRyZXNzKTtcbiAgICAgIHVuc3BlbnQudmFsdWUgPSB1bnNwZW50LnZhbHVlX2ludDtcbiAgICAgIHVuc3BlbnQudHhfaGFzaCA9IHVuc3BlbnQudHhpZDtcbiAgICAgIHVuc3BlbnQudHhfb3V0cHV0X24gPSB1bnNwZW50Lm47XG4gICAgICB1bnNwZW50LnNjcmlwdCA9IHVuc3BlbnQub3V0cHV0U2NyaXB0O1xuXG4gICAgICBub2NrKGJnVXJsKS5wb3N0KCcvYXBpL3YxL2JpbGxpbmcvYWRkcmVzcycpLnJlcGx5KDIwMCwgeyBhZGRyZXNzOiAnMk1zd1Fqa3ZONm9XWWRFN0wyYnJKNWNBQU1qUG1HNTlvY28nIH0pO1xuXG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IChhd2FpdCBmYWtlUHJvZFdhbGxldC5jcmVhdGVUcmFuc2FjdGlvbih7XG4gICAgICAgIGNoYW5nZUFkZHJlc3M6IHAyc2hBZGRyZXNzLmFkZHJlc3MsXG4gICAgICAgIHVuc3BlbnRzOiBbdW5zcGVudF0sXG4gICAgICAgIHJlY2lwaWVudHM6IHt9LFxuICAgICAgICBub1NwbGl0Q2hhbmdlOiB0cnVlLFxuICAgICAgICBmb3JjZUNoYW5nZUF0RW5kOiB0cnVlLFxuICAgICAgICBmZWVSYXRlOiAxMDAwMCxcbiAgICAgICAgYml0Z29GZWU6IHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgYWRkcmVzczogJycsXG4gICAgICAgIH0sXG4gICAgICAgIG9wUmV0dXJuczogeyAnQml0R28gcDJzaCB0ZXN0JzogMTAwMCB9LFxuICAgICAgfSkpIGFzIGFueTtcbiAgICAgIHRyYW5zYWN0aW9uLnRyYW5zYWN0aW9uSGV4LnNob3VsZC5lcXVhbChcbiAgICAgICAgJzAxMDAwMDAwMDE0NGRlYTVjYjA1NDI1Zjk0OTc2ZTg4N2NjYmE1Njg2YTlhMTJhM2Y0OTcxMGIwMjE1MDhkM2Q5Y2Q4ZGUxNmI4MDEwMDAwMDAwMGZmZmZmZmZmMDJlODAzMDAwMDAwMDAwMDAwMTE2YTBmNDI2OTc0NDc2ZjIwNzAzMjczNjgyMDc0NjU3Mzc0MjJhMTA3MDAwMDAwMDAwMDE3YTkxNGQwMzljYjMzNDQyOTRhNWEzODRhNTUwOGEwMDY0NDRjNDIwY2JjMTE4NzAwMDAwMDAwJ1xuICAgICAgKTtcblxuICAgICAgLy8gYWRkIGZpcnN0IHNpZ25hdHVyZVxuICAgICAgdHJhbnNhY3Rpb24ua2V5Y2hhaW4gPSB1c2VyS2V5cGFpcjtcbiAgICAgIHRyYW5zYWN0aW9uLmZvcmNlQkNIID0gdHJ1ZTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZTEgPSAoYXdhaXQgZmFrZVByb2RXYWxsZXQuc2lnblRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uKSkgYXMgYW55O1xuICAgICAgc2lnbmF0dXJlMS50eC5zaG91bGQuZXF1YWwoXG4gICAgICAgICcwMTAwMDAwMDAxNDRkZWE1Y2IwNTQyNWY5NDk3NmU4ODdjY2JhNTY4NmE5YTEyYTNmNDk3MTBiMDIxNTA4ZDNkOWNkOGRlMTZiODAxMDAwMDAwYjYwMDQ3MzA0NDAyMjA2MjIxYTk3ZjA4MWQ4N2UwMmUzYjE0OTg4YTY0ODYxODExYTZhOGRlNGYxMWY3NGY1YWFlYTQ1OTgxY2Y2MTJlMDIyMDc3YTA4YTViZDdkNzgxZTc5ODM4YWZiYjEyNmFmMmU0ODgwMmZlZmFkNjYwYWZkYmQ4ODA1ZjVlNTk4ZWQ1ODg0MTAwMDA0YzY5NTIyMTAzMWNkMjI3ZTQwYWQ2MWI0ZTEzNzEwOWNiMjg0NWViNmY1YTU4NGVkNWM2N2Q5ZDMxMzVjZGFhNTA0NWE4NDJlYTIxMDNhMmU3YjU0YzdiMmRhMDk5MjU1NTM1M2I4ZTI2YzZhY2ZmNDI0OGY0MzUxZjA4Nzg3YmYzZTJlZmM5NGI2NTgzMjEwMjVjMmE2Y2RlMzNjMmQ3M2NjZjEyZWVjZjY0YzU0ZjA4ZjcyMmMyZjA3MzgyNDQ5ODk1MDY5NWU5ODgzYjE0MTI1M2FlZmZmZmZmZmYwMmU4MDMwMDAwMDAwMDAwMDAxMTZhMGY0MjY5NzQ0NzZmMjA3MDMyNzM2ODIwNzQ2NTczNzQyMmExMDcwMDAwMDAwMDAwMTdhOTE0ZDAzOWNiMzM0NDI5NGE1YTM4NGE1NTA4YTAwNjQ0NGM0MjBjYmMxMTg3MDAwMDAwMDAnXG4gICAgICApO1xuICAgICAgLy8gYWRkIHNlY29uZCBzaWduYXR1cmVcbiAgICAgIHRyYW5zYWN0aW9uLnRyYW5zYWN0aW9uSGV4ID0gc2lnbmF0dXJlMS50eDtcbiAgICAgIHRyYW5zYWN0aW9uLmtleWNoYWluID0gYmFja3VwS2V5cGFpcjtcbiAgICAgIHRyYW5zYWN0aW9uLmZ1bGxMb2NhbFNpZ25pbmcgPSB0cnVlO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlMiA9IChhd2FpdCBmYWtlUHJvZFdhbGxldC5zaWduVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pKSBhcyBhbnk7XG4gICAgICAvLyB0aGlzIHRyYW5zYWN0aW9uIGhhcyBhY3R1YWxseSB3b3JrZWQ6IGh0dHBzOi8vdGVzdG5ldC5zbWFydGJpdC5jb20uYXUvdHgvYThjY2I5MjgxNjkwMzJkNmUxZjM3YmY4MWRmZDlhYjZkOTAzNjJhNGY4NGU1NzczOTdmYTY5MGFhNzExNTUwY1xuICAgICAgLy8gTm90ZSB0aGF0IHRoZSB0eCBoZXggYmVsb3cgbm8gbG9uZ2VyIGNvcnJlc3BvbmRzIHRvIHRoZSBhYm92ZSB0cmFuc2FjdGlvbiBiZWNhdXNlIG91ciBmZWUgZXN0aW1hdGlvbiBoYXNcbiAgICAgIC8vIGNoYW5nZWQsIGNoYW5naW5nIHRoZSBvdXRwdXQgYW1vdW50cyBhbmQgdGh1cyB0aGUgdHggaGV4LlxuICAgICAgc2lnbmF0dXJlMi50eC5zaG91bGQuZXF1YWwoXG4gICAgICAgICcwMTAwMDAwMDAxNDRkZWE1Y2IwNTQyNWY5NDk3NmU4ODdjY2JhNTY4NmE5YTEyYTNmNDk3MTBiMDIxNTA4ZDNkOWNkOGRlMTZiODAxMDAwMDAwZmRmZTAwMDA0NzMwNDQwMjIwNjIyMWE5N2YwODFkODdlMDJlM2IxNDk4OGE2NDg2MTgxMWE2YThkZTRmMTFmNzRmNWFhZWE0NTk4MWNmNjEyZTAyMjA3N2EwOGE1YmQ3ZDc4MWU3OTgzOGFmYmIxMjZhZjJlNDg4MDJmZWZhZDY2MGFmZGJkODgwNWY1ZTU5OGVkNTg4NDE0ODMwNDUwMjIxMDA4MmJjNTQ2MjkzODU4NDU5ZjM4OTVkYjI0Yzg1Y2NmMzc1MDVjNTZmOGZhZjRiYjhmNzhjZjQwMTM1YmMyZjJiMDIyMDNkYzFjNzhkN2M3Y2VhZjZiOTI0ZWNhM2MzOWI5NWU4YTIyN2IwNjlhMDcwNDc1ODEyNzMxMzZiNDdjYTdhYzQ0MTAwNGM2OTUyMjEwMzFjZDIyN2U0MGFkNjFiNGUxMzcxMDljYjI4NDVlYjZmNWE1ODRlZDVjNjdkOWQzMTM1Y2RhYTUwNDVhODQyZWEyMTAzYTJlN2I1NGM3YjJkYTA5OTI1NTUzNTNiOGUyNmM2YWNmZjQyNDhmNDM1MWYwODc4N2JmM2UyZWZjOTRiNjU4MzIxMDI1YzJhNmNkZTMzYzJkNzNjY2YxMmVlY2Y2NGM1NGYwOGY3MjJjMmYwNzM4MjQ0OTg5NTA2OTVlOTg4M2IxNDEyNTNhZWZmZmZmZmZmMDJlODAzMDAwMDAwMDAwMDAwMTE2YTBmNDI2OTc0NDc2ZjIwNzAzMjczNjgyMDc0NjU3Mzc0MjJhMTA3MDAwMDAwMDAwMDE3YTkxNGQwMzljYjMzNDQyOTRhNWEzODRhNTUwOGEwMDY0NDRjNDIwY2JjMTE4NzAwMDAwMDAwJ1xuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdkZWZhdWx0IHNlZ3dpdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHNlZ3dpdEFkZHJlc3MgPSBmYWtlUHJvZFdhbGxldC5nZW5lcmF0ZUFkZHJlc3MoeyBwYXRoOiAnLzEwLzEzJywgc2Vnd2l0OiB0cnVlIH0pO1xuICAgICAgY29uc3QgdW5zcGVudDogYW55ID0ge1xuICAgICAgICBhZGRyZXNzZXM6IFsnMk14S2tIOHlCM1M5WVdtVFFSYnZtYm9yWVF5UW5INXBldFAnXSxcbiAgICAgICAgdmFsdWU6ICcwLjE4NzUwMDAwJyxcbiAgICAgICAgdmFsdWVfaW50OiAxODc1MDAwMCxcbiAgICAgICAgdHhpZDogJzdkMjgyODc4YTg1ZGFlZTVkNDZlMDQzODI3ZGFlZDU3NTk2ZDc1ZDFhYTZlMDRmZDBjMDlhMzZmOTEzMDg4MWYnLFxuICAgICAgICBuOiAwLFxuICAgICAgICBzY3JpcHRfcHViX2tleToge1xuICAgICAgICAgIGFzbTogJ09QX0hBU0gxNjAgMzdiMzkzZmNlNjI3YTBlYzYzNGViNTQzZGRhMWU2MDhlMmQxYzc4YSBPUF9FUVVBTCcsXG4gICAgICAgICAgaGV4OiAnYTkxNDM3YjM5M2ZjZTYyN2EwZWM2MzRlYjU0M2RkYTFlNjA4ZTJkMWM3OGE4NycsXG4gICAgICAgIH0sXG4gICAgICAgIHJlcV9zaWdzOiAxLFxuICAgICAgICB0eXBlOiAnc2NyaXB0aGFzaCcsXG4gICAgICAgIGNvbmZpcm1hdGlvbnM6IDAsXG4gICAgICAgIGlkOiA2MTMzMTYxNyxcbiAgICAgIH07XG4gICAgICBfLmV4dGVuZCh1bnNwZW50LCBzZWd3aXRBZGRyZXNzKTtcbiAgICAgIHVuc3BlbnQudmFsdWUgPSB1bnNwZW50LnZhbHVlX2ludDtcbiAgICAgIHVuc3BlbnQudHhfaGFzaCA9IHVuc3BlbnQudHhpZDtcbiAgICAgIHVuc3BlbnQudHhfb3V0cHV0X24gPSB1bnNwZW50Lm47XG4gICAgICB1bnNwZW50LnNjcmlwdCA9IHVuc3BlbnQub3V0cHV0U2NyaXB0O1xuXG4gICAgICBub2NrKGJnVXJsKS5wb3N0KCcvYXBpL3YxL2JpbGxpbmcvYWRkcmVzcycpLnJlcGx5KDIwMCwgeyBhZGRyZXNzOiAnMk1zd1Fqa3ZONm9XWWRFN0wyYnJKNWNBQU1qUG1HNTlvY28nIH0pO1xuXG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IChhd2FpdCBmYWtlUHJvZFdhbGxldC5jcmVhdGVUcmFuc2FjdGlvbih7XG4gICAgICAgIGNoYW5nZUFkZHJlc3M6IHNlZ3dpdEFkZHJlc3MuYWRkcmVzcyxcbiAgICAgICAgdW5zcGVudHM6IFt1bnNwZW50XSxcbiAgICAgICAgcmVjaXBpZW50czoge30sXG4gICAgICAgIG5vU3BsaXRDaGFuZ2U6IHRydWUsXG4gICAgICAgIGZvcmNlQ2hhbmdlQXRFbmQ6IHRydWUsXG4gICAgICAgIGZlZVJhdGU6IDEwMDAwLFxuICAgICAgICBiaXRnb0ZlZToge1xuICAgICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgICBhZGRyZXNzOiAnJyxcbiAgICAgICAgfSxcbiAgICAgICAgb3BSZXR1cm5zOiB7ICdCaXRHbyBzZWd3aXQgdGVzdCc6IDEwMDAgfSxcbiAgICAgIH0pKSBhcyBhbnk7XG4gICAgICB0cmFuc2FjdGlvbi50cmFuc2FjdGlvbkhleC5zaG91bGQuZXF1YWwoXG4gICAgICAgICcwMTAwMDAwMDAxMWY4ODMwOTE2ZmEzMDkwY2ZkMDQ2ZWFhZDE3NTZkNTk1N2VkZGEyNzM4MDQ2ZWQ0ZTVhZTVkYTg3ODI4Mjg3ZDAwMDAwMDAwMDBmZmZmZmZmZjAyZTgwMzAwMDAwMDAwMDAwMDEzNmExMTQyNjk3NDQ3NmYyMDczNjU2Nzc3Njk3NDIwNzQ2NTczNzQwZTBmMWUwMTAwMDAwMDAwMTdhOTE0MzdiMzkzZmNlNjI3YTBlYzYzNGViNTQzZGRhMWU2MDhlMmQxYzc4YTg3MDAwMDAwMDAnXG4gICAgICApO1xuXG4gICAgICAvLyBhZGQgZmlyc3Qgc2lnbmF0dXJlXG4gICAgICB0cmFuc2FjdGlvbi5rZXljaGFpbiA9IHVzZXJLZXlwYWlyO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlMSA9IChhd2FpdCBmYWtlUHJvZFdhbGxldC5zaWduVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pKSBhcyBhbnk7XG4gICAgICBzaWduYXR1cmUxLnR4LnNob3VsZC5lcXVhbChcbiAgICAgICAgJzAxMDAwMDAwMDAwMTAxMWY4ODMwOTE2ZmEzMDkwY2ZkMDQ2ZWFhZDE3NTZkNTk1N2VkZGEyNzM4MDQ2ZWQ0ZTVhZTVkYTg3ODI4Mjg3ZDAwMDAwMDAwMjMyMjAwMjA0NDBlODU4MjI4Yjc1MzU0NGI0YzU3ZTMwMDI5NmI1NTcxN2Y4MTEwNTM4ODNmOWJlOWI2YTcxMmVhY2Q5MzFjZmZmZmZmZmYwMmU4MDMwMDAwMDAwMDAwMDAxMzZhMTE0MjY5NzQ0NzZmMjA3MzY1Njc3NzY5NzQyMDc0NjU3Mzc0MGUwZjFlMDEwMDAwMDAwMDE3YTkxNDM3YjM5M2ZjZTYyN2EwZWM2MzRlYjU0M2RkYTFlNjA4ZTJkMWM3OGE4NzA1MDA0ODMwNDUwMjIxMDBiZjNhODkxNGExYmZlOTI2NjFmMjdjYTM3YzBkNmI1YzBiM2M3MzUzNjE0Yzk1NTY0NjkyOWYyZTdlYjg5ZmZlMDIyMDJkNTU2YjBmZmFiMzdjMTA0YmFlNjc0MDZjYTE2Zjg4NTljZmEzN2M2YTQwZjIwMTNkODlhZmNlY2Q1NTk0ZjMwMTAwMDA2OTUyMjEwMzJjNTA1ZmM4YTFlNGI1NjgxMWIyNzM2NmEzNzFlNjFjOWZhZjU2NWRkMmZhYmFmZjdhNzBlYWMxOWMzMjE1N2MyMTAyNTExNjBiNTgzYmQ1ZGMwZjBkNDgwOTY1MDUxMzFjNDM0N2FiNjViNGYyMWVkNTdkNzZjMzgxNTc0OTljMDAzZDIxMDI2Nzk3MTJkNjJhMjU2MDkxN2NjNDNmZDJjYzNhMWI5YjYxZjUyOGM4OGJjNjQ5MDViYWU2ZWUwNzllNjA2MDlmNTNhZTAwMDAwMDAwJ1xuICAgICAgKTtcblxuICAgICAgLy8gYWRkIHNlY29uZCBzaWduYXR1cmVcbiAgICAgIHRyYW5zYWN0aW9uLnRyYW5zYWN0aW9uSGV4ID0gc2lnbmF0dXJlMS50eDtcbiAgICAgIHRyYW5zYWN0aW9uLmtleWNoYWluID0gYmFja3VwS2V5cGFpcjtcbiAgICAgIHRyYW5zYWN0aW9uLmZ1bGxMb2NhbFNpZ25pbmcgPSB0cnVlO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlMiA9IChhd2FpdCBmYWtlUHJvZFdhbGxldC5zaWduVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pKSBhcyBhbnk7XG4gICAgICAvLyB0aGlzIHRyYW5zYWN0aW9uIGhhcyBhY3R1YWxseSB3b3JrZWQ6IGh0dHBzOi8vdGVzdG5ldC5zbWFydGJpdC5jb20uYXUvdHgvZDY3MjY2ZjFkZTkwNWJhYWVlNzUwMDExZmE0YjNkODhhOGUzYTE3NThkNTE3M2E2NTljNjc3MDk0ODhkZGUwN1xuICAgICAgLy8gTm90ZSB0aGF0IHRoZSB0eCBoZXggYmVsb3cgbm8gbG9uZ2VyIGNvcnJlc3BvbmRzIHRvIHRoZSBhYm92ZSB0cmFuc2FjdGlvbiBiZWNhdXNlIG91ciBmZWUgZXN0aW1hdGlvbiBoYXNcbiAgICAgIC8vIGNoYW5nZWQsIGNoYW5naW5nIHRoZSBvdXRwdXQgYW1vdW50cyBhbmQgdGh1cyB0aGUgdHggaGV4LlxuICAgICAgc2lnbmF0dXJlMi50eC5zaG91bGQuZXF1YWwoXG4gICAgICAgICcwMTAwMDAwMDAwMDEwMTFmODgzMDkxNmZhMzA5MGNmZDA0NmVhYWQxNzU2ZDU5NTdlZGRhMjczODA0NmVkNGU1YWU1ZGE4NzgyODI4N2QwMDAwMDAwMDIzMjIwMDIwNDQwZTg1ODIyOGI3NTM1NDRiNGM1N2UzMDAyOTZiNTU3MTdmODExMDUzODgzZjliZTliNmE3MTJlYWNkOTMxY2ZmZmZmZmZmMDJlODAzMDAwMDAwMDAwMDAwMTM2YTExNDI2OTc0NDc2ZjIwNzM2NTY3Nzc2OTc0MjA3NDY1NzM3NDBlMGYxZTAxMDAwMDAwMDAxN2E5MTQzN2IzOTNmY2U2MjdhMGVjNjM0ZWI1NDNkZGExZTYwOGUyZDFjNzhhODcwNTAwNDgzMDQ1MDIyMTAwYmYzYTg5MTRhMWJmZTkyNjYxZjI3Y2EzN2MwZDZiNWMwYjNjNzM1MzYxNGM5NTU2NDY5MjlmMmU3ZWI4OWZmZTAyMjAyZDU1NmIwZmZhYjM3YzEwNGJhZTY3NDA2Y2ExNmY4ODU5Y2ZhMzdjNmE0MGYyMDEzZDg5YWZjZWNkNTU5NGYzMDE0NzMwNDQwMjIwNWNmOGQyZjJiZTZjZTA4M2QzNTY1NGJkYzNmYTg1ZDdlNzFiMjI3ZDQ1N2U5MjQ1YmI2MDNiMjFlN2I1MTY1MTAyMjAzZWE2ODYyMjZkYjgzMjBlMDhjMjZiZmIzMDQwNDhiM2E5NDczZDBlMDU3OTdkMzY1OGRhY2IyZjA5YTJiNTFjMDEwMDY5NTIyMTAzMmM1MDVmYzhhMWU0YjU2ODExYjI3MzY2YTM3MWU2MWM5ZmFmNTY1ZGQyZmFiYWZmN2E3MGVhYzE5YzMyMTU3YzIxMDI1MTE2MGI1ODNiZDVkYzBmMGQ0ODA5NjUwNTEzMWM0MzQ3YWI2NWI0ZjIxZWQ1N2Q3NmMzODE1NzQ5OWMwMDNkMjEwMjY3OTcxMmQ2MmEyNTYwOTE3Y2M0M2ZkMmNjM2ExYjliNjFmNTI4Yzg4YmM2NDkwNWJhZTZlZTA3OWU2MDYwOWY1M2FlMDAwMDAwMDAnXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ2NyZWF0ZXMgYW4gdW5zaWduZWQgdHggbWFkZSBvZiB1bmNvbXByZXNzZWQgcHVibGljIGtleXMgb2YgdjEgc2FmZSB3YWxsZXQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB7IGFkZHJlc3MsIHJlZGVlbVNjcmlwdCwgc2NyaXB0UHViS2V5IH0gPSBhd2FpdCBnZXRGaXh0dXJlPFJlY29yZDxzdHJpbmcsIHVua25vd24+PihcbiAgICAgICAgYCR7X19kaXJuYW1lfS9maXh0dXJlcy9zaWduLXRyYW5zYWN0aW9uLmpzb25gXG4gICAgICApO1xuICAgICAgY29uc3QgdGVzdEJpdGdvID0gbmV3IEJpdEdvQVBJKHsgZW52OiAndGVzdCcgfSk7XG4gICAgICBjb25zdCBmYWtlVGVzdFYxU2FmZVdhbGxldCA9IG5ldyBXYWxsZXQodGVzdEJpdGdvLCB7XG4gICAgICAgIGlkOiBhZGRyZXNzLFxuICAgICAgICBwcml2YXRlOiB7IHNhZmU6IHsgcmVkZWVtU2NyaXB0IH0gfSxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgdW5zcGVudHNUb1NwZW5kID0gW1xuICAgICAgICB7XG4gICAgICAgICAgdmFsdWU6IDEwMDAwMCxcbiAgICAgICAgICByZWRlZW1TY3JpcHQsXG4gICAgICAgICAgc2NyaXB0OiBzY3JpcHRQdWJLZXksXG4gICAgICAgICAgdHhfaGFzaDogJ2E1NWQxMWRjOGI3MDFiZDE5NjAxZmJmZTcxMWExZTQ2NWZjOGYxMjhlYzQ0NzRlNzhlMWZkMDg3ZTgwOGU1ZmUnLFxuICAgICAgICAgIHR4X291dHB1dF9uOiAwLFxuICAgICAgICAgIGNvbmZpcm1hdGlvbnM6IDEsXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICB2YWx1ZTogMTAwMDAwLFxuICAgICAgICAgIHJlZGVlbVNjcmlwdCxcbiAgICAgICAgICBzY3JpcHQ6IHNjcmlwdFB1YktleSxcbiAgICAgICAgICB0eF9oYXNoOiAnNDhmYjg3OWNlYzg3OTM1NjA0NWEzMzE5MzcwMjNhZWQ4NTlmNWRjNWRiOTU1YTFkYzhhNWNjZjI5ZjQ5ZDEwOCcsXG4gICAgICAgICAgdHhfb3V0cHV0X246IDAsXG4gICAgICAgICAgY29uZmlybWF0aW9uczogMSxcbiAgICAgICAgfSxcbiAgICAgIF07XG4gICAgICBjb25zdCByZWNpcGllbnRzID0ge1xuICAgICAgICAnMk15R3hyaExDNGtSZnVWakxxQ1ZZRnRDN0RjaGhnTUNpTnonOiAxOTEzNDAsIC8vIHB1cnBvc2VseSBzZXQgdG8gc2ltdWxhdGUgYSBzd2VlcCB0cmFuc2FjdGlvblxuICAgICAgfTtcblxuICAgICAgY29uc3Qgc2NvcGUgPSBub2NrKGJnVXJsVGVzdClcbiAgICAgICAgLnBvc3QoJy9hcGkvdjEvYmlsbGluZy9hZGRyZXNzJylcbiAgICAgICAgLnJlcGx5KDIwMCwgeyBhZGRyZXNzOiAnMk4zTDljdTlXTjJEZjdYdmIxWThvd29rdURWajVIZHl2NGknIH0pO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBmYWtlVGVzdFYxU2FmZVdhbGxldC5jcmVhdGVUcmFuc2FjdGlvbih7XG4gICAgICAgIHJlY2lwaWVudHMsXG4gICAgICAgIHVuc3BlbnRzOiB1bnNwZW50c1RvU3BlbmQsXG4gICAgICAgIGZlZVJhdGU6IDEwMDAwLCAvLyAxMCBzYXQvYnl0ZVxuICAgICAgICBiaXRnb0ZlZToge1xuICAgICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgICBhZGRyZXNzOiAnJyxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBzY29wZS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuXG4gICAgICByZXN1bHQuZXN0aW1hdGVkU2l6ZS5zaG91bGQuZXF1YWwoODY2KTtcbiAgICAgIHJlc3VsdC5mZWUuc2hvdWxkLmVxdWFsKDg2NjApO1xuICAgICAgLy8gVGhpcyBzaG91bGQgZXF1YWwgdG8gMSBiZWNhdXNlIHRoaXMgaXMgYSBzd2VlcCB0cmFuc2FjdGlvbiBidXQgZHVlIHRvIGhhcmRjb2RlZCBhZGRpdGlvbiBvZlxuICAgICAgLy8gMSBjaGFuZ2Ugb3V0cHV0IGluIHRyYW5zYWN0aW9uQnVpbGRlciwgaXQgaXMgMi5cbiAgICAgIC8vIEJlY2F1c2Ugb2YgdGhpcyB0aGUgZXN0aW1hdGVkIHNpemUgb2YgdGhlIHRyYW5zYWN0aW9ucyBpcyBtb3JlIHRoYW4gd2hhdCBpdCBhY3R1YWxseSBpcyBpbiB0aGUgaGV4LlxuICAgICAgcmVzdWx0LnR4SW5mby5uT3V0cHV0cy5zaG91bGQuZXF1YWwoMik7XG4gICAgfSk7XG5cbiAgICBpdCgnc2lnbnMgYW4gdW5zaWduZWQgdHggbWFkZSBvZiB1bmNvbXByZXNzZWQgcHVibGljIGtleXMgb2YgdjEgc2FmZSB3YWxsZXQgJiB2ZXJpZmllcyBzaWduYXR1cmVzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qge1xuICAgICAgICBhZGRyZXNzLFxuICAgICAgICByZWRlZW1TY3JpcHQsXG4gICAgICAgIHNjcmlwdFB1YktleSxcbiAgICAgICAgdXNlcktleVdJRjogdXNlclNpZ25pbmdLZXksXG4gICAgICAgIGJpdGdvS2V5V0lGOiBiaXRnb1NpZ25pbmdLZXksXG4gICAgICAgIHVuc2lnbmVkVHhIZXgsXG4gICAgICAgIGhhbGZTaWduZWRUeEhleCxcbiAgICAgICAgZnVsbFNpZ25lZFR4SGV4LFxuICAgICAgfSA9IGF3YWl0IGdldEZpeHR1cmU8UmVjb3JkPHN0cmluZywgdW5rbm93bj4+KGAke19fZGlybmFtZX0vZml4dHVyZXMvc2lnbi10cmFuc2FjdGlvbi5qc29uYCk7XG4gICAgICBjb25zdCB0ZXN0Qml0Z28gPSBuZXcgQml0R29BUEkoeyBlbnY6ICd0ZXN0JyB9KTtcbiAgICAgIGNvbnN0IGZha2VUZXN0VjFTYWZlV2FsbGV0ID0gbmV3IFdhbGxldCh0ZXN0Qml0Z28sIHtcbiAgICAgICAgaWQ6IGFkZHJlc3MsXG4gICAgICAgIHByaXZhdGU6IHsgc2FmZTogeyByZWRlZW1TY3JpcHQgfSB9LFxuICAgICAgfSk7XG4gICAgICBjb25zdCB1bnNwZW50c1RvU3BlbmQgPSBbXG4gICAgICAgIHsgdmFsdWU6IDEwMDAwMCwgcmVkZWVtU2NyaXB0LCBzY3JpcHQ6IHNjcmlwdFB1YktleSB9LFxuICAgICAgICB7IHZhbHVlOiAxMDAwMDAsIHJlZGVlbVNjcmlwdCwgc2NyaXB0OiBzY3JpcHRQdWJLZXkgfSxcbiAgICAgIF07XG4gICAgICBjb25zdCBoYWxmU2lnbmVkVHggPSBhd2FpdCBmYWtlVGVzdFYxU2FmZVdhbGxldC5zaWduVHJhbnNhY3Rpb24oe1xuICAgICAgICB0cmFuc2FjdGlvbkhleDogdW5zaWduZWRUeEhleCxcbiAgICAgICAgc2lnbmluZ0tleTogdXNlclNpZ25pbmdLZXksXG4gICAgICAgIHVuc3BlbnRzOiB1bnNwZW50c1RvU3BlbmQsXG4gICAgICAgIHZhbGlkYXRlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgICBoYWxmU2lnbmVkVHgudHguc2hvdWxkLmVxdWFsKGhhbGZTaWduZWRUeEhleCk7XG5cbiAgICAgIGNvbnN0IGZ1bGxTaWduZWRUeCA9IGF3YWl0IGZha2VUZXN0VjFTYWZlV2FsbGV0LnNpZ25UcmFuc2FjdGlvbih7XG4gICAgICAgIHRyYW5zYWN0aW9uSGV4OiBoYWxmU2lnbmVkVHhIZXgsXG4gICAgICAgIHNpZ25pbmdLZXk6IGJpdGdvU2lnbmluZ0tleSxcbiAgICAgICAgdW5zcGVudHM6IHVuc3BlbnRzVG9TcGVuZCxcbiAgICAgICAgdmFsaWRhdGU6IHRydWUsXG4gICAgICAgIGZ1bGxMb2NhbFNpZ25pbmc6IHRydWUsXG4gICAgICB9KTtcbiAgICAgIC8vIFVwb24gY2FsbGluZyB0eGIuYnVpbGQoKSBpbnN0ZWFkIGFmdGVyIGdldHRpbmcgMiB2YWxpZCBzaWduYXR1cmVzLCB3ZSBnZXQgYSB2YWxpZCBmdWxsIHNpZ25lZCB0eCB0aGF0IHdhcyBicm9hZGNhc3RcbiAgICAgIC8vIGFuZCBjb25maXJtZWQgb24gdGVzdG5ldCBoZXJlOiBodHRwczovL21lbXBvb2wuc3BhY2UvdGVzdG5ldC90eC9iZGUwOWYxYmQ1ZTY2NjFjMjhkOTBlNGM5NjI5MTg1M2UyMWJhMTVhYjQyZjNlNGEzMDcxOWRlY2I3M2U3OTFiXG4gICAgICAvLyBJdCdzIHByZXNlbnQgaW4gdGhlIGZ1bGxTaWduZWRUeEhleEJ1aWxkQ29tcGxldGUgcHJvcGVydHkgb2YgdGhlIGZpeHR1cmUuXG4gICAgICBmdWxsU2lnbmVkVHgudHguc2hvdWxkLmVxdWFsKGZ1bGxTaWduZWRUeEhleCk7XG4gICAgfSk7XG5cbiAgICBpdCgnQkNIIHNlZ3dpdCBzaG91bGQgZmFpbCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHNlZ3dpdEFkZHJlc3MgPSBmYWtlUHJvZFdhbGxldC5nZW5lcmF0ZUFkZHJlc3MoeyBwYXRoOiAnLzEwLzEzJywgc2Vnd2l0OiB0cnVlIH0pO1xuICAgICAgY29uc3QgdW5zcGVudDogYW55ID0ge1xuICAgICAgICBhZGRyZXNzZXM6IFsnMk14S2tIOHlCM1M5WVdtVFFSYnZtYm9yWVF5UW5INXBldFAnXSxcbiAgICAgICAgdmFsdWU6ICcwLjE4NzUwMDAwJyxcbiAgICAgICAgdmFsdWVfaW50OiAxODc1MDAwMCxcbiAgICAgICAgdHhpZDogJzdkMjgyODc4YTg1ZGFlZTVkNDZlMDQzODI3ZGFlZDU3NTk2ZDc1ZDFhYTZlMDRmZDBjMDlhMzZmOTEzMDg4MWYnLFxuICAgICAgICBuOiAwLFxuICAgICAgICBzY3JpcHRfcHViX2tleToge1xuICAgICAgICAgIGFzbTogJ09QX0hBU0gxNjAgMzdiMzkzZmNlNjI3YTBlYzYzNGViNTQzZGRhMWU2MDhlMmQxYzc4YSBPUF9FUVVBTCcsXG4gICAgICAgICAgaGV4OiAnYTkxNDM3YjM5M2ZjZTYyN2EwZWM2MzRlYjU0M2RkYTFlNjA4ZTJkMWM3OGE4NycsXG4gICAgICAgIH0sXG4gICAgICAgIHJlcV9zaWdzOiAxLFxuICAgICAgICB0eXBlOiAnc2NyaXB0aGFzaCcsXG4gICAgICAgIGNvbmZpcm1hdGlvbnM6IDAsXG4gICAgICAgIGlkOiA2MTMzMTYxNyxcbiAgICAgIH07XG4gICAgICBfLmV4dGVuZCh1bnNwZW50LCBzZWd3aXRBZGRyZXNzKTtcbiAgICAgIHVuc3BlbnQudmFsdWUgPSB1bnNwZW50LnZhbHVlX2ludDtcbiAgICAgIHVuc3BlbnQudHhfaGFzaCA9IHVuc3BlbnQudHhpZDtcbiAgICAgIHVuc3BlbnQudHhfb3V0cHV0X24gPSB1bnNwZW50Lm47XG4gICAgICB1bnNwZW50LnNjcmlwdCA9IHVuc3BlbnQub3V0cHV0U2NyaXB0O1xuXG4gICAgICBub2NrKGJnVXJsKS5wb3N0KCcvYXBpL3YxL2JpbGxpbmcvYWRkcmVzcycpLnJlcGx5KDIwMCwgeyBhZGRyZXNzOiAnMk1zd1Fqa3ZONm9XWWRFN0wyYnJKNWNBQU1qUG1HNTlvY28nIH0pO1xuXG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IChhd2FpdCBmYWtlUHJvZFdhbGxldC5jcmVhdGVUcmFuc2FjdGlvbih7XG4gICAgICAgIGNoYW5nZUFkZHJlc3M6IHNlZ3dpdEFkZHJlc3MuYWRkcmVzcyxcbiAgICAgICAgdW5zcGVudHM6IFt1bnNwZW50XSxcbiAgICAgICAgcmVjaXBpZW50czoge30sXG4gICAgICAgIG5vU3BsaXRDaGFuZ2U6IHRydWUsXG4gICAgICAgIGZvcmNlQ2hhbmdlQXRFbmQ6IHRydWUsXG4gICAgICAgIGZlZVJhdGU6IDEwMDAwLFxuICAgICAgICBiaXRnb0ZlZToge1xuICAgICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgICBhZGRyZXNzOiAnJyxcbiAgICAgICAgfSxcbiAgICAgICAgb3BSZXR1cm5zOiB7ICdCaXRHbyBzZWd3aXQgdGVzdCc6IDEwMDAgfSxcbiAgICAgIH0pKSBhcyBhbnk7XG4gICAgICB0cmFuc2FjdGlvbi50cmFuc2FjdGlvbkhleC5zaG91bGQuZXF1YWwoXG4gICAgICAgICcwMTAwMDAwMDAxMWY4ODMwOTE2ZmEzMDkwY2ZkMDQ2ZWFhZDE3NTZkNTk1N2VkZGEyNzM4MDQ2ZWQ0ZTVhZTVkYTg3ODI4Mjg3ZDAwMDAwMDAwMDBmZmZmZmZmZjAyZTgwMzAwMDAwMDAwMDAwMDEzNmExMTQyNjk3NDQ3NmYyMDczNjU2Nzc3Njk3NDIwNzQ2NTczNzQwZTBmMWUwMTAwMDAwMDAwMTdhOTE0MzdiMzkzZmNlNjI3YTBlYzYzNGViNTQzZGRhMWU2MDhlMmQxYzc4YTg3MDAwMDAwMDAnXG4gICAgICApO1xuXG4gICAgICAvLyBhZGQgZmlyc3Qgc2lnbmF0dXJlXG4gICAgICB0cmFuc2FjdGlvbi5rZXljaGFpbiA9IHVzZXJLZXlwYWlyO1xuICAgICAgdHJhbnNhY3Rpb24uZm9yY2VCQ0ggPSB0cnVlO1xuICAgICAgKCgpID0+IGZha2VQcm9kV2FsbGV0LnNpZ25UcmFuc2FjdGlvbih0cmFuc2FjdGlvbikpLnNob3VsZC50aHJvdygnQkNIIGRvZXMgbm90IHN1cHBvcnQgc2Vnd2l0IGlucHV0cycpO1xuICAgIH0pO1xuXG4gICAgaXQoJ21peGVkIHAyc2ggJiBzZWd3aXQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBwMnNoQWRkcmVzcyA9IGZha2VXYWxsZXQuZ2VuZXJhdGVBZGRyZXNzKHsgcGF0aDogJy8wLzE0Jywgc2Vnd2l0OiBmYWxzZSB9KTtcbiAgICAgIGNvbnN0IHNlZ3dpdEFkZHJlc3MgPSBmYWtlV2FsbGV0LmdlbmVyYXRlQWRkcmVzcyh7IHBhdGg6ICcvMTAvMTQnLCBzZWd3aXQ6IHRydWUgfSk7XG4gICAgICBjb25zdCBwMnNoVW5zcGVudCA9IHtcbiAgICAgICAgYWRkcmVzc2VzOiBbJzJONTMzZnFneVBZS1ZEODkybkJSYVltRkhiYlR5a2hZU0V3J10sXG4gICAgICAgIHZhbHVlOiAnMi45OTk5NjYxMCcsXG4gICAgICAgIHZhbHVlX2ludDogMjk5OTk2NjEwLFxuICAgICAgICB0eGlkOiAnZjY1NGNlMGE1YmUzZjEyZGY3ZmVjZjRlZTc3N2I2ZDg2YjVhYThjNzEwZWY2OTQ2ZWMxMjEyMDZiNGY4NzU3YycsXG4gICAgICAgIG46IDEsXG4gICAgICAgIHNjcmlwdF9wdWJfa2V5OiB7XG4gICAgICAgICAgYXNtOiAnT1BfSEFTSDE2MCA4MTUzZTdhMzU1MDgwODhiNmNmNTk5MjI2NzkyYzdkZTJkYmZmMjUyIE9QX0VRVUFMJyxcbiAgICAgICAgICBoZXg6ICdhOTE0ODE1M2U3YTM1NTA4MDg4YjZjZjU5OTIyNjc5MmM3ZGUyZGJmZjI1Mjg3JyxcbiAgICAgICAgfSxcbiAgICAgICAgcmVxX3NpZ3M6IDEsXG4gICAgICAgIHR5cGU6ICdzY3JpcHRoYXNoJyxcbiAgICAgICAgY29uZmlybWF0aW9uczogMCxcbiAgICAgICAgaWQ6IDYxMzMxMjYzLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHNlZ3dpdFVuc3BlbnQgPSB7XG4gICAgICAgIGFkZHJlc3NlczogWycyTkJ0cFhjRHJ1ZjN6UnV0bUY0QWJDTUZOUUhYc0dOUDZrVCddLFxuICAgICAgICB2YWx1ZTogJzEuNTAwMDAwMDAnLFxuICAgICAgICB2YWx1ZV9pbnQ6IDE1MDAwMDAwMCxcbiAgICAgICAgdHhpZDogJ2E0NDA5YzNmMDQyZmFlNjdiODkwYWMzZGY0MGVmMGRiMDM1MzljNjczMzFmZDdlOTI2MDUxMTg5M2I0ZjlmMjQnLFxuICAgICAgICBuOiAwLFxuICAgICAgICBzY3JpcHRfcHViX2tleToge1xuICAgICAgICAgIGFzbTogJ09QX0hBU0gxNjAgY2M4ZTdjYmY0ODEzODlkMzE4M2E1OTBhY2ZhNmFhNjZlYjk3YzhlMSBPUF9FUVVBTCcsXG4gICAgICAgICAgaGV4OiAnYTkxNGNjOGU3Y2JmNDgxMzg5ZDMxODNhNTkwYWNmYTZhYTY2ZWI5N2M4ZTE4NycsXG4gICAgICAgIH0sXG4gICAgICAgIHJlcV9zaWdzOiAxLFxuICAgICAgICB0eXBlOiAnc2NyaXB0aGFzaCcsXG4gICAgICAgIGNvbmZpcm1hdGlvbnM6IDAsXG4gICAgICAgIGlkOiA2MTMzMDg4MixcbiAgICAgIH07XG4gICAgICBjb25zdCBhZGRyZXNzZXMgPSBbcDJzaEFkZHJlc3MsIHNlZ3dpdEFkZHJlc3NdO1xuICAgICAgY29uc3QgdW5zcGVudHMgPSBbcDJzaFVuc3BlbnQsIHNlZ3dpdFVuc3BlbnRdLm1hcCgodW5zcGVudDogYW55LCBpbmRleCkgPT4ge1xuICAgICAgICBjb25zdCBhZGRyZXNzID0gYWRkcmVzc2VzW2luZGV4XTtcbiAgICAgICAgXy5leHRlbmQodW5zcGVudCwgYWRkcmVzcyk7XG4gICAgICAgIHVuc3BlbnQudmFsdWUgPSB1bnNwZW50LnZhbHVlX2ludDtcbiAgICAgICAgdW5zcGVudC50eF9oYXNoID0gdW5zcGVudC50eGlkO1xuICAgICAgICB1bnNwZW50LnR4X291dHB1dF9uID0gdW5zcGVudC5uO1xuICAgICAgICB1bnNwZW50LnNjcmlwdCA9IHVuc3BlbnQub3V0cHV0U2NyaXB0O1xuICAgICAgICByZXR1cm4gdW5zcGVudDtcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IChhd2FpdCBmYWtlV2FsbGV0LmNyZWF0ZVRyYW5zYWN0aW9uKHtcbiAgICAgICAgY2hhbmdlQWRkcmVzczogcDJzaEFkZHJlc3MuYWRkcmVzcyxcbiAgICAgICAgdW5zcGVudHM6IHVuc3BlbnRzLFxuICAgICAgICByZWNpcGllbnRzOiB7fSxcbiAgICAgICAgbm9TcGxpdENoYW5nZTogdHJ1ZSxcbiAgICAgICAgZm9yY2VDaGFuZ2VBdEVuZDogdHJ1ZSxcbiAgICAgICAgZmVlUmF0ZTogMTAwMDAsXG4gICAgICAgIG9wUmV0dXJuczogeyAnQml0R28gbWl4ZWQgcDJzaCAmIHNlZ3dpdCB0ZXN0JzogNDAwMDAwMDAwIH0sXG4gICAgICAgIGJpdGdvRmVlOiB7XG4gICAgICAgICAgYW1vdW50OiA4MTc2MCxcbiAgICAgICAgICBhZGRyZXNzOiAnMk5EN2pRUjVpdGpHVGJoM0RLZ2JwWldTWTl1bmdEcndjd2InLFxuICAgICAgICB9LFxuICAgICAgfSkpIGFzIGFueTtcbiAgICAgIHRyYW5zYWN0aW9uLnRyYW5zYWN0aW9uSGV4LnNob3VsZC5lcXVhbChcbiAgICAgICAgJzAxMDAwMDAwMDI3Yzc1ZjhiNDA2MTIxMmVjNDY2OWVmMTBjN2E4NWE2YmQ4YjY3N2U3NGVjZmZlZjcyZGYxZTM1YjBhY2U1NGY2MDEwMDAwMDAwMGZmZmZmZmZmMjQ5ZjRmM2I4OTExMDUyNmU5ZDcxZjMzNjc5YzUzMDNkYmYwMGVmNDNkYWM5MGI4NjdhZTJmMDQzZjljNDBhNDAwMDAwMDAwMDBmZmZmZmZmZjAzMDA4NGQ3MTcwMDAwMDAwMDIwNmExZTQyNjk3NDQ3NmYyMDZkNjk3ODY1NjQyMDcwMzI3MzY4MjAyNjIwNzM2NTY3Nzc2OTc0MjA3NDY1NzM3NGIwOGZmOTAyMDAwMDAwMDAxN2E5MTQ4MTUzZTdhMzU1MDgwODhiNmNmNTk5MjI2NzkyYzdkZTJkYmZmMjUyODc2MDNmMDEwMDAwMDAwMDAwMTdhOTE0ZDlmN2JlNDc5NzVjMDM2Zjk0MjI4YjBiZmQ3MDcwMTkxMjc1OGJhOTg3MDAwMDAwMDAnXG4gICAgICApO1xuXG4gICAgICAvLyBhZGQgZmlyc3Qgc2lnbmF0dXJlXG4gICAgICB0cmFuc2FjdGlvbi5rZXljaGFpbiA9IHVzZXJLZXlwYWlyO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlMSA9IChhd2FpdCBmYWtlUHJvZFdhbGxldC5zaWduVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pKSBhcyBhbnk7XG4gICAgICBzaWduYXR1cmUxLnR4LnNob3VsZC5lcXVhbChcbiAgICAgICAgJzAxMDAwMDAwMDAwMTAyN2M3NWY4YjQwNjEyMTJlYzQ2NjllZjEwYzdhODVhNmJkOGI2NzdlNzRlY2ZmZWY3MmRmMWUzNWIwYWNlNTRmNjAxMDAwMDAwYjcwMDQ4MzA0NTAyMjEwMGZmYzQ1ZDkzY2JhZjRjMWM4NTBlMjFmMjc3YzViMzExZDNlMzk1N2YxMzM4OTU1Y2IxNjVkNzJhNzY4YTA1NGMwMjIwNTIwMjA1OTNiMzY3ODFlZWEwMGE5ZjhkY2JlYjc2NjA4ZjkyMGM3YTkzM2E5MDg4MzE4YWIyZjcwYzExZTFkOTAxMDAwMDRjNjk1MjIxMDNkYTk1YjI4YTEzYWEyZDRiYjQ5MGQ3MDYyOGUyZTVkOTEyNDYxZDM3NWZlZjM4MWFhZGQ4OWRjMTI1NjIyMDc1MjEwMzEyMTI4N2E1MTBjNWYzMmU4YmE3MmQyNDc5ZTkwZWI1MmJhNDRhNDY3MTczZGYzMzlmZWIwZmYyMTVmMTAwZTMyMTAyOTc3Y2RmYmVlNzYwNjZhZTczOWRiNzJkNTUzNzFhZDQ5ZGM2NzEyZmI4ZjJmM2Y2OWJiMWE0YzI0MjJiMGIxYTUzYWVmZmZmZmZmZjI0OWY0ZjNiODkxMTA1MjZlOWQ3MWYzMzY3OWM1MzAzZGJmMDBlZjQzZGFjOTBiODY3YWUyZjA0M2Y5YzQwYTQwMDAwMDAwMDIzMjIwMDIwOGI5MWFhMDNlYjBmN2YzMWUzOTE3MDg4MDg0MTY4YmE1MjgyYTkxNWU3Y2RlMGE1YTkzNGI3ZWEwMmViMDU3YmZmZmZmZmZmMDMwMDg0ZDcxNzAwMDAwMDAwMjA2YTFlNDI2OTc0NDc2ZjIwNmQ2OTc4NjU2NDIwNzAzMjczNjgyMDI2MjA3MzY1Njc3NzY5NzQyMDc0NjU3Mzc0YjA4ZmY5MDIwMDAwMDAwMDE3YTkxNDgxNTNlN2EzNTUwODA4OGI2Y2Y1OTkyMjY3OTJjN2RlMmRiZmYyNTI4NzYwM2YwMTAwMDAwMDAwMDAxN2E5MTRkOWY3YmU0Nzk3NWMwMzZmOTQyMjhiMGJmZDcwNzAxOTEyNzU4YmE5ODcwMDA1MDA0NzMwNDQwMjIwNTg5OGJlZTcxMTQ2N2MwOWE1ZTIyZTFkY2IxYTExZmNlMWEwZDZlYTEyOWQ5MTFmODEzZjg3YzdkNDVlMDY3YjAyMjAyZjY5ZmIxMThiYmYwYjA3MmVkMjZkNzJjZjgwNzNlN2FjZDY2YzIwNTQxOWE0YTAwZjg2YTdiYTBmNmUzZGQ2MDEwMDAwNjk1MjIxMDMwNzgwMTg2YzBiZTVkZjBkMmQ2MmNmNTRjYzJmM2QyYzA5OTExZTM3N2FhOTViNWZlODc1ZmEzNTJhZWQwYTU5MjEwM2YzMjM3ZWRkMmQ4NzAxMGU4ZmU5ZjQzZjM0ZThjNjNkZTYzODQyODNkZTkwOTc5NWQ2MmFmNGRkYjRkNTc5NTQyMTAyYWQwM2RlNTUwNGVmOTQ3ZTRlNmVlMmZhNmIxNWQxNTBkNTUzYzIxMjc1ZjQ5ZjJjZTIzNTlkOWZkZWRiOWFkZTUzYWUwMDAwMDAwMCdcbiAgICAgICk7XG5cbiAgICAgIC8vIGFkZCBzZWNvbmQgc2lnbmF0dXJlXG4gICAgICB0cmFuc2FjdGlvbi50cmFuc2FjdGlvbkhleCA9IHNpZ25hdHVyZTEudHg7XG4gICAgICB0cmFuc2FjdGlvbi5rZXljaGFpbiA9IGJhY2t1cEtleXBhaXI7XG4gICAgICB0cmFuc2FjdGlvbi5mdWxsTG9jYWxTaWduaW5nID0gdHJ1ZTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZTIgPSAoYXdhaXQgZmFrZVByb2RXYWxsZXQuc2lnblRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uKSkgYXMgYW55O1xuICAgICAgLy8gdGhpcyB0cmFuc2FjdGlvbiBoYXMgYWN0dWFsbHkgd29ya2VkOiBodHRwczovL3Rlc3RuZXQuc21hcnRiaXQuY29tLmF1L3R4L2UyZjY5NmJjYmE5MWEzNzZjMzZiYjUyNWRmOGMzNjc5MzhmNmUyZmQ2MzQ0YzkwNTg3YmYxMjgwMjA5MTEyNGNcbiAgICAgIC8vIE5vdGUgdGhhdCB0aGUgdHggaGV4IGJlbG93IG5vIGxvbmdlciBjb3JyZXNwb25kcyB0byB0aGUgYWJvdmUgdHJhbnNhY3Rpb24gYmVjYXVzZSBvdXIgZmVlIGVzdGltYXRpb24gaGFzXG4gICAgICAvLyBjaGFuZ2VkLCBjaGFuZ2luZyB0aGUgb3V0cHV0IGFtb3VudHMgYW5kIHRodXMgdGhlIHR4IGhleC5cbiAgICAgIHNpZ25hdHVyZTIudHguc2hvdWxkLmVxdWFsKFxuICAgICAgICAnMDEwMDAwMDAwMDAxMDI3Yzc1ZjhiNDA2MTIxMmVjNDY2OWVmMTBjN2E4NWE2YmQ4YjY3N2U3NGVjZmZlZjcyZGYxZTM1YjBhY2U1NGY2MDEwMDAwMDBmZGZmMDAwMDQ4MzA0NTAyMjEwMGZmYzQ1ZDkzY2JhZjRjMWM4NTBlMjFmMjc3YzViMzExZDNlMzk1N2YxMzM4OTU1Y2IxNjVkNzJhNzY4YTA1NGMwMjIwNTIwMjA1OTNiMzY3ODFlZWEwMGE5ZjhkY2JlYjc2NjA4ZjkyMGM3YTkzM2E5MDg4MzE4YWIyZjcwYzExZTFkOTAxNDgzMDQ1MDIyMTAwODI1NGQxMDA0MDFhM2E4MzFlZDAxOWUxNjYyZGJkOTBiOTZjNmM0MDcyYjgxY2U2NDBkMTUyYmMyOTI5NWMxMDAyMjAxM2Y4NmM1YWY1NzE2MjM0OTk5YTdiZDZlOTRmYzhmNDI4Zjc2OTdjYzMxMzhiMzY0OWQwZWM0ZGQ4NjgxYmM3MDEwMDRjNjk1MjIxMDNkYTk1YjI4YTEzYWEyZDRiYjQ5MGQ3MDYyOGUyZTVkOTEyNDYxZDM3NWZlZjM4MWFhZGQ4OWRjMTI1NjIyMDc1MjEwMzEyMTI4N2E1MTBjNWYzMmU4YmE3MmQyNDc5ZTkwZWI1MmJhNDRhNDY3MTczZGYzMzlmZWIwZmYyMTVmMTAwZTMyMTAyOTc3Y2RmYmVlNzYwNjZhZTczOWRiNzJkNTUzNzFhZDQ5ZGM2NzEyZmI4ZjJmM2Y2OWJiMWE0YzI0MjJiMGIxYTUzYWVmZmZmZmZmZjI0OWY0ZjNiODkxMTA1MjZlOWQ3MWYzMzY3OWM1MzAzZGJmMDBlZjQzZGFjOTBiODY3YWUyZjA0M2Y5YzQwYTQwMDAwMDAwMDIzMjIwMDIwOGI5MWFhMDNlYjBmN2YzMWUzOTE3MDg4MDg0MTY4YmE1MjgyYTkxNWU3Y2RlMGE1YTkzNGI3ZWEwMmViMDU3YmZmZmZmZmZmMDMwMDg0ZDcxNzAwMDAwMDAwMjA2YTFlNDI2OTc0NDc2ZjIwNmQ2OTc4NjU2NDIwNzAzMjczNjgyMDI2MjA3MzY1Njc3NzY5NzQyMDc0NjU3Mzc0YjA4ZmY5MDIwMDAwMDAwMDE3YTkxNDgxNTNlN2EzNTUwODA4OGI2Y2Y1OTkyMjY3OTJjN2RlMmRiZmYyNTI4NzYwM2YwMTAwMDAwMDAwMDAxN2E5MTRkOWY3YmU0Nzk3NWMwMzZmOTQyMjhiMGJmZDcwNzAxOTEyNzU4YmE5ODcwMDA1MDA0NzMwNDQwMjIwNTg5OGJlZTcxMTQ2N2MwOWE1ZTIyZTFkY2IxYTExZmNlMWEwZDZlYTEyOWQ5MTFmODEzZjg3YzdkNDVlMDY3YjAyMjAyZjY5ZmIxMThiYmYwYjA3MmVkMjZkNzJjZjgwNzNlN2FjZDY2YzIwNTQxOWE0YTAwZjg2YTdiYTBmNmUzZGQ2MDE0NzMwNDQwMjIwNzcxM2Q2NzFiNDU5ODk2ODhlMjY2NWMyYjExYWI3ZTVlYThkNTdlYjE0ZjlkYTIzM2MwOTVkYWJlNDQxMzA4ZDAyMjA2OTUyMWI1YWViMDcxYjA3YTcwYTcxOTdhMGMyYmJjNDBhMjNhZTYzYTA0MTYwY2YzNjI3MjUwYzRiYTRjNDBmMDEwMDY5NTIyMTAzMDc4MDE4NmMwYmU1ZGYwZDJkNjJjZjU0Y2MyZjNkMmMwOTkxMWUzNzdhYTk1YjVmZTg3NWZhMzUyYWVkMGE1OTIxMDNmMzIzN2VkZDJkODcwMTBlOGZlOWY0M2YzNGU4YzYzZGU2Mzg0MjgzZGU5MDk3OTVkNjJhZjRkZGI0ZDU3OTU0MjEwMmFkMDNkZTU1MDRlZjk0N2U0ZTZlZTJmYTZiMTVkMTUwZDU1M2MyMTI3NWY0OWYyY2UyMzU5ZDlmZGVkYjlhZGU1M2FlMDAwMDAwMDAnXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBzZW5kIHRvIGJlY2gzMiByZWNpcGllbnQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBwMnNoQWRkcmVzcyA9IGZha2VXYWxsZXQuZ2VuZXJhdGVBZGRyZXNzKHsgcGF0aDogJy8wLzE0Jywgc2Vnd2l0OiBmYWxzZSB9KTtcbiAgICAgIGNvbnN0IHNlZ3dpdEFkZHJlc3MgPSBmYWtlV2FsbGV0LmdlbmVyYXRlQWRkcmVzcyh7IHBhdGg6ICcvMTAvMTQnLCBzZWd3aXQ6IHRydWUgfSk7XG4gICAgICBjb25zdCBwMnNoVW5zcGVudCA9IHtcbiAgICAgICAgYWRkcmVzc2VzOiBbJzJONTMzZnFneVBZS1ZEODkybkJSYVltRkhiYlR5a2hZU0V3J10sXG4gICAgICAgIHZhbHVlOiAnMi45OTk5NjYxMCcsXG4gICAgICAgIHZhbHVlX2ludDogMjk5OTk2NjEwLFxuICAgICAgICB0eGlkOiAnZjY1NGNlMGE1YmUzZjEyZGY3ZmVjZjRlZTc3N2I2ZDg2YjVhYThjNzEwZWY2OTQ2ZWMxMjEyMDZiNGY4NzU3YycsXG4gICAgICAgIG46IDEsXG4gICAgICAgIHNjcmlwdF9wdWJfa2V5OiB7XG4gICAgICAgICAgYXNtOiAnT1BfSEFTSDE2MCA4MTUzZTdhMzU1MDgwODhiNmNmNTk5MjI2NzkyYzdkZTJkYmZmMjUyIE9QX0VRVUFMJyxcbiAgICAgICAgICBoZXg6ICdhOTE0ODE1M2U3YTM1NTA4MDg4YjZjZjU5OTIyNjc5MmM3ZGUyZGJmZjI1Mjg3JyxcbiAgICAgICAgfSxcbiAgICAgICAgcmVxX3NpZ3M6IDEsXG4gICAgICAgIHR5cGU6ICdzY3JpcHRoYXNoJyxcbiAgICAgICAgY29uZmlybWF0aW9uczogMCxcbiAgICAgICAgaWQ6IDYxMzMxMjYzLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHNlZ3dpdFVuc3BlbnQgPSB7XG4gICAgICAgIGFkZHJlc3NlczogWycyTkJ0cFhjRHJ1ZjN6UnV0bUY0QWJDTUZOUUhYc0dOUDZrVCddLFxuICAgICAgICB2YWx1ZTogJzEuNTAwMDAwMDAnLFxuICAgICAgICB2YWx1ZV9pbnQ6IDE1MDAwMDAwMCxcbiAgICAgICAgdHhpZDogJ2E0NDA5YzNmMDQyZmFlNjdiODkwYWMzZGY0MGVmMGRiMDM1MzljNjczMzFmZDdlOTI2MDUxMTg5M2I0ZjlmMjQnLFxuICAgICAgICBuOiAwLFxuICAgICAgICBzY3JpcHRfcHViX2tleToge1xuICAgICAgICAgIGFzbTogJ09QX0hBU0gxNjAgY2M4ZTdjYmY0ODEzODlkMzE4M2E1OTBhY2ZhNmFhNjZlYjk3YzhlMSBPUF9FUVVBTCcsXG4gICAgICAgICAgaGV4OiAnYTkxNGNjOGU3Y2JmNDgxMzg5ZDMxODNhNTkwYWNmYTZhYTY2ZWI5N2M4ZTE4NycsXG4gICAgICAgIH0sXG4gICAgICAgIHJlcV9zaWdzOiAxLFxuICAgICAgICB0eXBlOiAnc2NyaXB0aGFzaCcsXG4gICAgICAgIGNvbmZpcm1hdGlvbnM6IDAsXG4gICAgICAgIGlkOiA2MTMzMDg4MixcbiAgICAgIH07XG4gICAgICBjb25zdCBhZGRyZXNzZXMgPSBbcDJzaEFkZHJlc3MsIHNlZ3dpdEFkZHJlc3NdO1xuICAgICAgY29uc3QgdW5zcGVudHMgPSBbcDJzaFVuc3BlbnQsIHNlZ3dpdFVuc3BlbnRdLm1hcCgodW5zcGVudDogYW55LCBpbmRleCkgPT4ge1xuICAgICAgICBjb25zdCBhZGRyZXNzID0gYWRkcmVzc2VzW2luZGV4XTtcbiAgICAgICAgXy5leHRlbmQodW5zcGVudCwgYWRkcmVzcyk7XG4gICAgICAgIHVuc3BlbnQudmFsdWUgPSB1bnNwZW50LnZhbHVlX2ludDtcbiAgICAgICAgdW5zcGVudC50eF9oYXNoID0gdW5zcGVudC50eGlkO1xuICAgICAgICB1bnNwZW50LnR4X291dHB1dF9uID0gdW5zcGVudC5uO1xuICAgICAgICB1bnNwZW50LnNjcmlwdCA9IHVuc3BlbnQub3V0cHV0U2NyaXB0O1xuICAgICAgICByZXR1cm4gdW5zcGVudDtcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IChhd2FpdCBmYWtlV2FsbGV0LmNyZWF0ZVRyYW5zYWN0aW9uKHtcbiAgICAgICAgY2hhbmdlQWRkcmVzczogcDJzaEFkZHJlc3MuYWRkcmVzcyxcbiAgICAgICAgdW5zcGVudHM6IHVuc3BlbnRzLFxuICAgICAgICByZWNpcGllbnRzOiB7IHRiMXFndXp5azR3NmthcXRwc2N6czVhajB3OHI3NTk4anEzNmVnbThlOTh3cXBoM3J3bWV4NjhzZXNsZ3NnOiAzMDAwMDAgfSxcbiAgICAgICAgbm9TcGxpdENoYW5nZTogdHJ1ZSxcbiAgICAgICAgZm9yY2VDaGFuZ2VBdEVuZDogdHJ1ZSxcbiAgICAgICAgZmVlUmF0ZTogMTAwMDAsXG4gICAgICAgIG9wUmV0dXJuczogeyAnQml0R28gbWl4ZWQgcDJzaCAmIHNlZ3dpdCB0ZXN0JzogNDAwMDAwMDAwIH0sXG4gICAgICAgIGJpdGdvRmVlOiB7XG4gICAgICAgICAgYW1vdW50OiA4MTc2MCxcbiAgICAgICAgICBhZGRyZXNzOiAnMk5EN2pRUjVpdGpHVGJoM0RLZ2JwWldTWTl1bmdEcndjd2InLFxuICAgICAgICB9LFxuICAgICAgfSkpIGFzIGFueTtcbiAgICAgIHRyYW5zYWN0aW9uLnRyYW5zYWN0aW9uSGV4LnNob3VsZC5lcXVhbChcbiAgICAgICAgJzAxMDAwMDAwMDI3Yzc1ZjhiNDA2MTIxMmVjNDY2OWVmMTBjN2E4NWE2YmQ4YjY3N2U3NGVjZmZlZjcyZGYxZTM1YjBhY2U1NGY2MDEwMDAwMDAwMGZmZmZmZmZmMjQ5ZjRmM2I4OTExMDUyNmU5ZDcxZjMzNjc5YzUzMDNkYmYwMGVmNDNkYWM5MGI4NjdhZTJmMDQzZjljNDBhNDAwMDAwMDAwMDBmZmZmZmZmZjA0ZTA5MzA0MDAwMDAwMDAwMDIyMDAyMDQ3MDQ0YjU1ZGFiNzQwYjBjMzAyODUzYjI3YjhlM2Y1MGE3OTAyM2FjYTM2N2M5NGVlMDA2ZjExYmI3OTM2OGYwMDg0ZDcxNzAwMDAwMDAwMjA2YTFlNDI2OTc0NDc2ZjIwNmQ2OTc4NjU2NDIwNzAzMjczNjgyMDI2MjA3MzY1Njc3NzY5NzQyMDc0NjU3Mzc0N2NmYWY0MDIwMDAwMDAwMDE3YTkxNDgxNTNlN2EzNTUwODA4OGI2Y2Y1OTkyMjY3OTJjN2RlMmRiZmYyNTI4NzYwM2YwMTAwMDAwMDAwMDAxN2E5MTRkOWY3YmU0Nzk3NWMwMzZmOTQyMjhiMGJmZDcwNzAxOTEyNzU4YmE5ODcwMDAwMDAwMCdcbiAgICAgICk7XG5cbiAgICAgIC8vIGFkZCBmaXJzdCBzaWduYXR1cmVcbiAgICAgIHRyYW5zYWN0aW9uLmtleWNoYWluID0gdXNlcktleXBhaXI7XG4gICAgICBjb25zdCBzaWduYXR1cmUxID0gKGF3YWl0IGZha2VQcm9kV2FsbGV0LnNpZ25UcmFuc2FjdGlvbih0cmFuc2FjdGlvbikpIGFzIGFueTtcbiAgICAgIHNpZ25hdHVyZTEudHguc2hvdWxkLmVxdWFsKFxuICAgICAgICAnMDEwMDAwMDAwMDAxMDI3Yzc1ZjhiNDA2MTIxMmVjNDY2OWVmMTBjN2E4NWE2YmQ4YjY3N2U3NGVjZmZlZjcyZGYxZTM1YjBhY2U1NGY2MDEwMDAwMDBiNzAwNDgzMDQ1MDIyMTAwODgwOTM3NzYzNGU2NjdkNmUxOWYzOGExMzhhNTViMmI2MzcwMzEyYWY3NmE1Y2EzYjc3NmRmNjFmYzcxOTYxNzAyMjAyMWQ5MDM0N2I5MDg1YWI3MWE3NmM4NDAwZjk4NGUzMjJjMTU0NTFlY2M2NzNkZDM3ZGUzMDg4NzQzNmQzN2I0MDEwMDAwNGM2OTUyMjEwM2RhOTViMjhhMTNhYTJkNGJiNDkwZDcwNjI4ZTJlNWQ5MTI0NjFkMzc1ZmVmMzgxYWFkZDg5ZGMxMjU2MjIwNzUyMTAzMTIxMjg3YTUxMGM1ZjMyZThiYTcyZDI0NzllOTBlYjUyYmE0NGE0NjcxNzNkZjMzOWZlYjBmZjIxNWYxMDBlMzIxMDI5NzdjZGZiZWU3NjA2NmFlNzM5ZGI3MmQ1NTM3MWFkNDlkYzY3MTJmYjhmMmYzZjY5YmIxYTRjMjQyMmIwYjFhNTNhZWZmZmZmZmZmMjQ5ZjRmM2I4OTExMDUyNmU5ZDcxZjMzNjc5YzUzMDNkYmYwMGVmNDNkYWM5MGI4NjdhZTJmMDQzZjljNDBhNDAwMDAwMDAwMjMyMjAwMjA4YjkxYWEwM2ViMGY3ZjMxZTM5MTcwODgwODQxNjhiYTUyODJhOTE1ZTdjZGUwYTVhOTM0YjdlYTAyZWIwNTdiZmZmZmZmZmYwNGUwOTMwNDAwMDAwMDAwMDAyMjAwMjA0NzA0NGI1NWRhYjc0MGIwYzMwMjg1M2IyN2I4ZTNmNTBhNzkwMjNhY2EzNjdjOTRlZTAwNmYxMWJiNzkzNjhmMDA4NGQ3MTcwMDAwMDAwMDIwNmExZTQyNjk3NDQ3NmYyMDZkNjk3ODY1NjQyMDcwMzI3MzY4MjAyNjIwNzM2NTY3Nzc2OTc0MjA3NDY1NzM3NDdjZmFmNDAyMDAwMDAwMDAxN2E5MTQ4MTUzZTdhMzU1MDgwODhiNmNmNTk5MjI2NzkyYzdkZTJkYmZmMjUyODc2MDNmMDEwMDAwMDAwMDAwMTdhOTE0ZDlmN2JlNDc5NzVjMDM2Zjk0MjI4YjBiZmQ3MDcwMTkxMjc1OGJhOTg3MDAwNTAwNDgzMDQ1MDIyMTAwOGI5NWFjODNlNDRjNzI3Yjc5ZmZiZjQ1NzExNzE5MjVkMDZmODgzYTA1YzEyMmIzYjMzYzA1NWYwYmZmYTcwMTAyMjA3YjVlZTM0MTJlYThhNWNlYzRhNWMzODZmMWI0NjRhYjY4ZDUzMWM2YzY5NzA3N2JjNDYyYzA1ZWI0NGEyODMyMDEwMDAwNjk1MjIxMDMwNzgwMTg2YzBiZTVkZjBkMmQ2MmNmNTRjYzJmM2QyYzA5OTExZTM3N2FhOTViNWZlODc1ZmEzNTJhZWQwYTU5MjEwM2YzMjM3ZWRkMmQ4NzAxMGU4ZmU5ZjQzZjM0ZThjNjNkZTYzODQyODNkZTkwOTc5NWQ2MmFmNGRkYjRkNTc5NTQyMTAyYWQwM2RlNTUwNGVmOTQ3ZTRlNmVlMmZhNmIxNWQxNTBkNTUzYzIxMjc1ZjQ5ZjJjZTIzNTlkOWZkZWRiOWFkZTUzYWUwMDAwMDAwMCdcbiAgICAgICk7XG5cbiAgICAgIC8vIGFkZCBzZWNvbmQgc2lnbmF0dXJlXG4gICAgICB0cmFuc2FjdGlvbi50cmFuc2FjdGlvbkhleCA9IHNpZ25hdHVyZTEudHg7XG4gICAgICB0cmFuc2FjdGlvbi5rZXljaGFpbiA9IGJhY2t1cEtleXBhaXI7XG4gICAgICB0cmFuc2FjdGlvbi5mdWxsTG9jYWxTaWduaW5nID0gdHJ1ZTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZTIgPSAoYXdhaXQgZmFrZVByb2RXYWxsZXQuc2lnblRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uKSkgYXMgYW55O1xuICAgICAgY29uc29sZS5sb2coJ3NpZ25hdHVyZTEgJyArIEpTT04uc3RyaW5naWZ5KHNpZ25hdHVyZTIpKTtcbiAgICAgIC8vIHRoaXMgdHJhbnNhY3Rpb24gaGFzIGFjdHVhbGx5IHdvcmtlZDogaHR0cHM6Ly90ZXN0bmV0LnNtYXJ0Yml0LmNvbS5hdS90eC9lMmY2OTZiY2JhOTFhMzc2YzM2YmI1MjVkZjhjMzY3OTM4ZjZlMmZkNjM0NGM5MDU4N2JmMTI4MDIwOTExMjRjXG4gICAgICAvLyBOb3RlIHRoYXQgdGhlIHR4IGhleCBiZWxvdyBubyBsb25nZXIgY29ycmVzcG9uZHMgdG8gdGhlIGFib3ZlIHRyYW5zYWN0aW9uIGJlY2F1c2Ugb3VyIGZlZSBlc3RpbWF0aW9uIGhhc1xuICAgICAgLy8gY2hhbmdlZCwgY2hhbmdpbmcgdGhlIG91dHB1dCBhbW91bnRzIGFuZCB0aHVzIHRoZSB0eCBoZXguXG4gICAgICBzaWduYXR1cmUyLnR4LnNob3VsZC5lcXVhbChcbiAgICAgICAgJzAxMDAwMDAwMDAwMTAyN2M3NWY4YjQwNjEyMTJlYzQ2NjllZjEwYzdhODVhNmJkOGI2NzdlNzRlY2ZmZWY3MmRmMWUzNWIwYWNlNTRmNjAxMDAwMDAwZmRmZTAwMDA0ODMwNDUwMjIxMDA4ODA5Mzc3NjM0ZTY2N2Q2ZTE5ZjM4YTEzOGE1NWIyYjYzNzAzMTJhZjc2YTVjYTNiNzc2ZGY2MWZjNzE5NjE3MDIyMDIxZDkwMzQ3YjkwODVhYjcxYTc2Yzg0MDBmOTg0ZTMyMmMxNTQ1MWVjYzY3M2RkMzdkZTMwODg3NDM2ZDM3YjQwMTQ3MzA0NDAyMjA1YTU4ZTYwMjA0MmI4ZThhNWRhNTA5ZDE5Y2UzMTA1MDE0N2RkMGZmY2ZiZTJiYjMzN2MyM2Q0Yzg4ZjRjYzQxMDIyMDc1YmZhNDU1ZDFmNzRlMzBmYmQ5Yzc4NmNkNDgxMWExZGVmZTU0MzEwZjIzNWI0MTkzY2U0ZmZhMGU4MzA5YTEwMTAwNGM2OTUyMjEwM2RhOTViMjhhMTNhYTJkNGJiNDkwZDcwNjI4ZTJlNWQ5MTI0NjFkMzc1ZmVmMzgxYWFkZDg5ZGMxMjU2MjIwNzUyMTAzMTIxMjg3YTUxMGM1ZjMyZThiYTcyZDI0NzllOTBlYjUyYmE0NGE0NjcxNzNkZjMzOWZlYjBmZjIxNWYxMDBlMzIxMDI5NzdjZGZiZWU3NjA2NmFlNzM5ZGI3MmQ1NTM3MWFkNDlkYzY3MTJmYjhmMmYzZjY5YmIxYTRjMjQyMmIwYjFhNTNhZWZmZmZmZmZmMjQ5ZjRmM2I4OTExMDUyNmU5ZDcxZjMzNjc5YzUzMDNkYmYwMGVmNDNkYWM5MGI4NjdhZTJmMDQzZjljNDBhNDAwMDAwMDAwMjMyMjAwMjA4YjkxYWEwM2ViMGY3ZjMxZTM5MTcwODgwODQxNjhiYTUyODJhOTE1ZTdjZGUwYTVhOTM0YjdlYTAyZWIwNTdiZmZmZmZmZmYwNGUwOTMwNDAwMDAwMDAwMDAyMjAwMjA0NzA0NGI1NWRhYjc0MGIwYzMwMjg1M2IyN2I4ZTNmNTBhNzkwMjNhY2EzNjdjOTRlZTAwNmYxMWJiNzkzNjhmMDA4NGQ3MTcwMDAwMDAwMDIwNmExZTQyNjk3NDQ3NmYyMDZkNjk3ODY1NjQyMDcwMzI3MzY4MjAyNjIwNzM2NTY3Nzc2OTc0MjA3NDY1NzM3NDdjZmFmNDAyMDAwMDAwMDAxN2E5MTQ4MTUzZTdhMzU1MDgwODhiNmNmNTk5MjI2NzkyYzdkZTJkYmZmMjUyODc2MDNmMDEwMDAwMDAwMDAwMTdhOTE0ZDlmN2JlNDc5NzVjMDM2Zjk0MjI4YjBiZmQ3MDcwMTkxMjc1OGJhOTg3MDAwNTAwNDgzMDQ1MDIyMTAwOGI5NWFjODNlNDRjNzI3Yjc5ZmZiZjQ1NzExNzE5MjVkMDZmODgzYTA1YzEyMmIzYjMzYzA1NWYwYmZmYTcwMTAyMjA3YjVlZTM0MTJlYThhNWNlYzRhNWMzODZmMWI0NjRhYjY4ZDUzMWM2YzY5NzA3N2JjNDYyYzA1ZWI0NGEyODMyMDE0NzMwNDQwMjIwNTM2OTAyMzQ1ODJhNjkxMWEyOGNhZTlmNTM0Yzk4MGI3ZDc5MTg3NDlhNzQxM2MxYzU5MzI3ZGViZjE2ZmYwYjAyMjA1NjE3NWY1YzI3YTM2MzQxNmIyY2U0NzkxYWVmYzNkNTU1NDVjYWNiZDA1MjcyMDJlODY5ZTExMjdmYzJmMjRkMDEwMDY5NTIyMTAzMDc4MDE4NmMwYmU1ZGYwZDJkNjJjZjU0Y2MyZjNkMmMwOTkxMWUzNzdhYTk1YjVmZTg3NWZhMzUyYWVkMGE1OTIxMDNmMzIzN2VkZDJkODcwMTBlOGZlOWY0M2YzNGU4YzYzZGU2Mzg0MjgzZGU5MDk3OTVkNjJhZjRkZGI0ZDU3OTU0MjEwMmFkMDNkZTU1MDRlZjk0N2U0ZTZlZTJmYTZiMTVkMTUwZDU1M2MyMTI3NWY0OWYyY2UyMzU5ZDlmZGVkYjlhZGU1M2FlMDAwMDAwMDAnXG4gICAgICApO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnU2VuZCBNYW55JywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdyZXNwb25kcyB3aXRoIHByb3BlciBmZWUgYW5kIGZlZSByYXRlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgcGFyYW1zID0ge1xuICAgICAgICByZWNpcGllbnRzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgYWRkcmVzczogJzJNdXRwWFZZczhMeWs3NHBWRG4zZUFHN3huSzRXYzJralRRJyxcbiAgICAgICAgICAgIGFtb3VudDogMzAwMDAwLFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICB9O1xuICAgICAgY29uc3QgdW5zcGVudHMgPSBbXG4gICAgICAgIHtcbiAgICAgICAgICB2YWx1ZTogODE3MCxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIHZhbHVlOiA4MDAwMDAsXG4gICAgICAgIH0sXG4gICAgICBdO1xuICAgICAgY29uc3QgY3JlYXRlQW5kU2lnblJlc3BvbnNlID0ge1xuICAgICAgICBiaXRnb0ZlZTogMCxcbiAgICAgICAgdHJhdmVsSW5mb3M6IFtdLFxuICAgICAgICB1bnNwZW50cyxcbiAgICAgICAgdHg6ICdoYWxmc2lnbmVkaGV4JyxcbiAgICAgIH07XG4gICAgICBzaW5vbi5zdHViKGZha2VXYWxsZXQsICdjcmVhdGVBbmRTaWduVHJhbnNhY3Rpb24nKS5yZXR1cm5zKFByb21pc2UucmVzb2x2ZShjcmVhdGVBbmRTaWduUmVzcG9uc2UpKTtcbiAgICAgIGNvbnN0IGdldFNlbmRUeFJlc3BvbnNlID0gKCkgPT4gKHtcbiAgICAgICAgc3RhdHVzOiAnYWNjZXB0ZWQnLFxuICAgICAgICB0eDogJzAxMDAwMDAwMDAwMTAyMjhiNWMzZTI3ODlkNDc3MGZjMzk3ZWM3OWZhNzI1NWY4NjIzNTI5N2M1YTA0ZGVmNjc4YjQ4MWI4YjA5ZTgxYjAxMDAwMDAwMjMyMjAwMjBiM2JiZTA2Nzk2MGJlMzk1MDFmMzY1Yjg5OTlkNTNmMmE4Mjg1ZDhkOTgzNmY2MWZhZDAyMGU2YTRhOWUyNmZkZmZmZmZmZmYxNTEwZTkwNDExYTg2YzQ5ZjJhNTI1NDZhMzJhMDNmZWJkZTJiYzYwNDc0MWYwZTg1ZGM0N2FkZWMzM2Y1MTU5MDAwMDAwMDBmZGZkMDAwMDQ4MzA0NTAyMjEwMGE0NGJiZjk3YjE1NWM1NzcwMzg2MmJlNjlkMmIyMGM0YjJhYjllOTRmNDAyNTk1ODgwYmY3NDQwMmNjYzg3ZTIwMjIwMGE0YWFmOThmOTM5YjY1Yzk4Y2EwOGViOTYwNzRjMjIyZWNiMWZjMzdlMzU5YjFkNjdhMDVmMWM1NmRlZGZjMDAxNDczMDQ0MDIyMDAzZjM5ODlhMTQyODRmMTMyYmJiNTUwMTE4YzIwMjU2ZDRlYTczNzcwNDEyM2EyOTk1NWFjYzFkMDNlYTZlYjcwMjIwMTcyMjNkYTdlZGNmNzMwNzZkODk4NzVhYTMzMzYwYWE2YTEyMTQxODA3ZjY4M2M2YzFiOWE1YTBkM2ZmNjAxOTAxNGM2OTUyMjEwMjU3ODk4NTdjYzhiZTExMGZmNGNiZjM1NGI1MmRkMGU3ZTkzMjZjNmJmZTBhZWU2YzMwYzFlZTY5NjYwYzNkYzAyMTAyZjU4ZjFiMTUxNmQwNTgxNGFlNjg4Y2E3MDE4NTY2OTVlMjcwNTBlM2UxNmQzYTIzNTEyODRkN2FmODQ0OTg4ODIxMDIzODVjN2JjZWMzZjM4YzEzZTg3YjU1OGFlYmYyZjIwYTg5MjhlN2VjYmUxMWU3YzNhNDc3OTJiYzhlMzNmZTg4NTNhZWZmZmZmZmZmMDJlMDkzMDQwMDAwMDAwMDAwMTdhOTE0MWQwYzc5MWNlYzNhZjFmMzc4MDhkNDJmMDQ1OTMwOTVkNmZkZWEyNjg3MDViYzA3MDAwMDAwMDAwMDE3YTkxNGQ4YzcyMGY2NDZjN2M1NmM1NDY3MjQ4ZTQ3YzcyZGMwYjJkMzBiYmM4NzA0MDA0NzMwNDQwMjIwMWVhYTEzNTlmZmZkM2JkZWM1YjQ4MjY4YmQyZjE1MTkzYTI5OWMyMmIxOTcwMzU2ZjM5MDg4MzQ3MzMyNDY1MTAyMjA3NDE4NjIzMmYwMjI0NWFmOWMwOTc3MDMxNDQ4YzJjOTllN2I3ZTJiMDViMmJhNGIzMmMzMjI3ZDhjYTE0OTRlMDE0ODMwNDUwMjIxMDBiZDYxYjM3MDUxYzI4NTMzZWEwYjAwZGRhNzViMWM0ZjFkZWUxYjY4M2JiNzM1MWIyZDhkZDcyMGY2ZGZiZTExMDIyMDNhY2M0Y2Y5ZDJkZDQ0YjI5NGFhMjU4MTJlOTllN2Q4ZWIzNzMwZTRmZjZmODg5ZDNjZGNkNTI1MTk1NzUwYjgwMTY5NTIyMTAyMTlkMDkzYzE4YzI3Y2I1NDc3MzdiNGE0OWRkZGFjOWMzNDEyYjEwZTlmODgwZWIzMDA1M2MzZWJhODE5Mjg1NDIxMDM3NDcxMTg4OTJjYWMxYjRkYTExNTI2ZmM0ZWJlZWJlMTY4ZGFlMDkwN2NlZmIxYTE4MTI1NDFjZDQ2YjA3NjAyMjEwMzM5ZjczYjY3NTBmOGY5MWVmZDQ4NGI1YWEyOTc0MzIxYTZjYzI3NzZkNWJkNzhiOWNmYjVmZTE4ZTNiMmQ2NjI1M2FlMDA1YTllMTYwMCcsXG4gICAgICAgIGhhc2g6ICdmOGRmNDNjMmM2NTBiM2JiMTEyNzdhZWU0NTMxZGI5OWE3MTVmYTNiOWRmZDNkNDVhOGQxNzEzNDJjMWJmNzgwJyxcbiAgICAgICAgaW5zdGFudDogZmFsc2UsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGV4cGVjdGVkUmVzdWx0ID0gT2JqZWN0LmFzc2lnbihcbiAgICAgICAge1xuICAgICAgICAgIGZlZTogMTI4NSxcbiAgICAgICAgICBmZWVSYXRlOiAyNTE5LjYwNzg0MzEzNzI1NSxcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0U2VuZFR4UmVzcG9uc2UoKVxuICAgICAgKTtcbiAgICAgIHNpbm9uLnN0dWIoZmFrZVdhbGxldCwgJ3NlbmRUcmFuc2FjdGlvbicpLnJlc29sdmVzKGdldFNlbmRUeFJlc3BvbnNlKCkpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gKGF3YWl0IGZha2VXYWxsZXQuc2VuZE1hbnkocGFyYW1zKSkgYXMgYW55O1xuICAgICAgcmVzdWx0LnR4LnNob3VsZC5lcXVhbChleHBlY3RlZFJlc3VsdC50eCk7XG4gICAgICByZXN1bHQuZmVlLnNob3VsZC5lcXVhbChleHBlY3RlZFJlc3VsdC5mZWUpO1xuICAgICAgcmVzdWx0LmZlZVJhdGUuc2hvdWxkLmVxdWFsKGV4cGVjdGVkUmVzdWx0LmZlZVJhdGUpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnQWNjZWxlcmF0ZSBUcmFuc2FjdGlvbiAoc2VydmVyIG1vY2tlZCknLCBmdW5jdGlvbiBhY2NlbGVyYXRlVHhNb2NrZWREZXNjcmliZSgpIHtcbiAgICBsZXQgd2FsbGV0O1xuICAgIGxldCBiZ1VybDtcbiAgICBsZXQgZXhwbG9yZXJVcmw7XG4gICAgbGV0IG1pbkNoYW5nZVNpemU7XG5cbiAgICBsZXQgcGFyZW50VHhJZCA9ICc2YTc0Yjc0ZGY0OTkxZDkzYzMyZDc1MTMzNmM4NWI1ZjJkMWVlNTQ0YTJkZmJhZTJlNWY0YmViNGY5MTRlNWUwJztcbiAgICBjb25zdCBvdXRwdXRJZHggPSAwO1xuICAgIGNvbnN0IG91dHB1dEFkZHJlc3MgPSAnMk5Db1NmSEg2THM0Q2RUUzVRYWhnQzlrN3g5UmZYZVN3WTQnO1xuICAgIGNvbnN0IHVucmVsYXRlZFR4SWQgPSAnMDhmNWUwYjRhY2I1YWI4MjQ1MjI5ZGZlMTYxY2U0Y2EwZGExZWM5ODNlN2EzNGIwOWU3MmY1Njk3OWE0NjdkZic7XG4gICAgY29uc3Qgd2FsbGV0SWQgPSAnMk5Db1NmSEg2THM0Q2RUUzVRYWhnQzlrN3g5UmZYZVN3WTQnO1xuXG4gICAgLyoqXG4gICAgICogSGVscGVyIGZ1bmN0aW9uIHRvIGdldCB0aGUgcGFyZW50IHRyYW5zYWN0aW9uIElEIGZyb20gYSB0cmFuc2FjdGlvbiBpbnB1dFxuICAgICAqXG4gICAgICogVGhpcyBmdW5jdGlvbiBjb252ZXJ0cyBgaGFzaGAgKHdoaWNoIGlzIGEgQnVmZmVyIG9iamVjdCkgdG8gYSB1c2FibGUgdHhpZCBzdHJpbmcuXG4gICAgICogVGhlIGlzc3VlIGlzIHRoYXQgdGhlIGJ5dGVzIGFyZSBzdG9yZWQgaW4gcmV2ZXJzZSBvcmRlciBpbiB0aGUgYnVmZmVyLCBzb1xuICAgICAqIHRoZSBzaW1wbGUgYXBwcm9hY2ggb2YganVzdCBjb21wYXJpbmcgdGhlIGhleCBzdHJpbmdzIGRvZXNuJ3Qgd29yay5cbiAgICAgKiBJbnN0ZWFkLCB0aGUgQnVmZmVyIGlzIGNvcGllZCB0byBhIG5ldyBCdWZmZXIgb2JqZWN0LCB0aGUgbmV3IEJ1ZmZlclxuICAgICAqIG9iamVjdCBpcyByZXZlcnNlZCBpbi1wbGFjZSwgYW5kIHRoZW4gdGhlIG5ldyBCdWZmZXIgaXMgY29udmVydGVkIHRvIGFcbiAgICAgKiBoZXggc3RyaW5nLiBBZnRlciB0aGlzLCB0aGUgcmVzdWx0IGlzIGEgaGV4IHN0cmluZyB3aGljaCBpcyB0aGUgcGFyZW50IHR4aWRcbiAgICAgKlxuICAgICAqIEBwYXJhbSBoYXNoIGEgYml0Y29pbmpzLWxpYiB0cmFuc2FjdGlvbiBvYmplY3QncyBpbnB1dCBoYXNoXG4gICAgICovXG4gICAgZnVuY3Rpb24gaW5wdXRQYXJlbnRUeElkKHsgaGFzaCB9KTogc3RyaW5nIHtcbiAgICAgIHJldHVybiAoQnVmZmVyLmZyb20oaGFzaCkucmV2ZXJzZSgpIGFzIEJ1ZmZlcikudG9TdHJpbmcoJ2hleCcpO1xuICAgIH1cblxuICAgIGJlZm9yZShmdW5jdGlvbiBhY2NlbGVyYXRlVHhNb2NrZWRCZWZvcmUoKSB7XG4gICAgICBub2NrLnBlbmRpbmdNb2NrcygpLnNob3VsZC5iZS5lbXB0eSgpO1xuXG4gICAgICBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7IGVudjogJ21vY2snIH0pO1xuICAgICAgLy8gYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgICBiaXRnby5zZXRWYWxpZGF0ZShmYWxzZSk7XG4gICAgICB3YWxsZXQgPSBuZXcgV2FsbGV0KGJpdGdvLCB7IGlkOiB3YWxsZXRJZCwgcHJpdmF0ZTogeyBrZXljaGFpbnM6IFt1c2VyS2V5cGFpciwgYmFja3VwS2V5cGFpciwgYml0Z29LZXldIH0gfSk7XG4gICAgICAod2FsbGV0IGFzIGFueSkuYml0Z28gPSBiaXRnbztcbiAgICAgIGJnVXJsID0gY29tbW9uLkVudmlyb25tZW50c1tiaXRnby5nZXRFbnYoKV0udXJpO1xuICAgICAgZXhwbG9yZXJVcmwgPSBjb21tb24uRW52aXJvbm1lbnRzW2JpdGdvLmdldEVudigpXS5idGNFeHBsb3JlckJhc2VVcmw7XG5cbiAgICAgIC8vIHRyeSB0byBnZXQgdGhlIG1pbiBjaGFuZ2Ugc2l6ZSBmcm9tIHRoZSBzZXJ2ZXIsIG90aGVyd2lzZSBkZWZhdWx0IHRvIDAuMSBCVENcbiAgICAgIC8vIFRPRE86IG1pbkNoYW5nZVNpemUgaXMgbm90IGN1cnJlbnRseSBhIGNvbnN0YW50IGRlZmluZWQgb24gdGhlIGNsaWVudCBhbmQgc2hvdWxkIGJlIGFkZGVkXG4gICAgICBtaW5DaGFuZ2VTaXplID0gMWU3O1xuICAgIH0pO1xuXG4gICAgYWZ0ZXIoZnVuY3Rpb24gYWNjZWxlcmF0ZVR4TW9ja2VkQWZ0ZXIoKSB7XG4gICAgICAvLyBtYWtlIHN1cmUgYWxsIG5vY2tzIGFyZSBjbGVhcmVkIG9yIGNvbnN1bWVkIGFmdGVyIHRoZSB0ZXN0cyBhcmUgY29tcGxldGVcbiAgICAgIG5vY2sucGVuZGluZ01vY2tzKCkuc2hvdWxkLmJlLmVtcHR5KCk7XG4gICAgfSk7XG5cbiAgICBpdCgnYXJndW1lbnRzJywgYXN5bmMgKCkgPT4ge1xuICAgICAgYXdhaXQgd2FsbGV0LmFjY2VsZXJhdGVUcmFuc2FjdGlvbih7IGZlZVJhdGU6IDEyMyB9KS5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9eTWlzc2luZyBwYXJhbWV0ZXI6IHRyYW5zYWN0aW9uSUQkLyk7XG5cbiAgICAgIGF3YWl0IHdhbGxldFxuICAgICAgICAuYWNjZWxlcmF0ZVRyYW5zYWN0aW9uKHsgdHJhbnNhY3Rpb25JRDogMTIzLCBmZWVSYXRlOiAxMjMgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL15FeHBlY3RpbmcgcGFyYW1ldGVyIHN0cmluZzogdHJhbnNhY3Rpb25JRCBidXQgZm91bmQgbnVtYmVyJC8pO1xuXG4gICAgICBhd2FpdCB3YWxsZXRcbiAgICAgICAgLmFjY2VsZXJhdGVUcmFuc2FjdGlvbih7IHRyYW5zYWN0aW9uSUQ6ICcxMjMnIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9eTWlzc2luZyBwYXJhbWV0ZXI6IGZlZVJhdGUkLyk7XG5cbiAgICAgIGNvbnN0IGZlZVJhdGVzUGFyYW1zID0gWycxMjMnLCAwLCAtMTAsIC1JbmZpbml0eSwgSW5maW5pdHksIE5hTl07XG4gICAgICBmb3IgKGNvbnN0IGZlZVJhdGUgb2YgZmVlUmF0ZXNQYXJhbXMpIHtcbiAgICAgICAgYXdhaXQgd2FsbGV0XG4gICAgICAgICAgLmFjY2VsZXJhdGVUcmFuc2FjdGlvbih7IHRyYW5zYWN0aW9uSUQ6ICcxMjMnLCBmZWVSYXRlIH0pXG4gICAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL15FeHBlY3RpbmcgcG9zaXRpdmUgZmluaXRlIG51bWJlciBmb3IgcGFyYW1ldGVyOiBmZWVSYXRlJC8pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ2JhZCBpbnB1dCcsIGZ1bmN0aW9uIGJhZElucHV0RGVzY3JpYmUoKSB7XG4gICAgICBhZnRlcigoKSA9PiB7XG4gICAgICAgIC8vIG1ha2Ugc3VyZSBhbGwgbm9ja3MgYXJlIGNsZWFyZWQgb3IgY29uc3VtZWQgYWZ0ZXIgdGhlIHRlc3RzIGFyZSBjb21wbGV0ZVxuICAgICAgICBub2NrLnBlbmRpbmdNb2NrcygpLnNob3VsZC5iZS5lbXB0eSgpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdub24gZXhpc3RlbnQgdHJhbnNhY3Rpb24gSUQnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgICAgLmdldChgL2FwaS92MS93YWxsZXQvJHt3YWxsZXQuaWQoKX0vdHgvJHtwYXJlbnRUeElkfWApXG4gICAgICAgICAgLnJlcGx5KDQwNCwgJ3RyYW5zYWN0aW9uIG5vdCBmb3VuZCBvbiB0aGlzIHdhbGxldCcpO1xuXG4gICAgICAgIGF3YWl0IHdhbGxldFxuICAgICAgICAgIC5hY2NlbGVyYXRlVHJhbnNhY3Rpb24oeyB0cmFuc2FjdGlvbklEOiBwYXJlbnRUeElkLCBmZWVSYXRlOiAxMjMgfSlcbiAgICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvXjQwNFxcbnRyYW5zYWN0aW9uIG5vdCBmb3VuZCBvbiB0aGlzIHdhbGxldCQvKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnY29uZmlybWVkIHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgICBub2NrKGJnVXJsKS5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7d2FsbGV0LmlkKCl9L3R4LyR7cGFyZW50VHhJZH1gKS5yZXBseSgyMDAsIHtcbiAgICAgICAgICBjb25maXJtYXRpb25zOiA2LFxuICAgICAgICB9KTtcblxuICAgICAgICBhd2FpdCB3YWxsZXRcbiAgICAgICAgICAuYWNjZWxlcmF0ZVRyYW5zYWN0aW9uKHsgdHJhbnNhY3Rpb25JRDogcGFyZW50VHhJZCwgZmVlUmF0ZTogMjAwMCB9KVxuICAgICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9eVHJhbnNhY3Rpb24gWzAtOWEtZl0rIGlzIGFscmVhZHkgY29uZmlybWVkIGFuZCBjYW5ub3QgYmUgYWNjZWxlcmF0ZWQkLyk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ25vIG91dHB1dHMgdG8gd2FsbGV0JywgYXN5bmMgKCkgPT4ge1xuICAgICAgICBub2NrKGJnVXJsKVxuICAgICAgICAgIC5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7d2FsbGV0LmlkKCl9L3R4LyR7cGFyZW50VHhJZH1gKVxuICAgICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAgIG91dHB1dHM6IFtcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGFjY291bnQ6IG91dHB1dEFkZHJlc3MsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDE4OTAwMDAsXG4gICAgICAgICAgICAgICAgdm91dDogMCxcbiAgICAgICAgICAgICAgICBjaGFpbjogMCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBjb25maXJtYXRpb25zOiAwLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgIGF3YWl0IHdhbGxldFxuICAgICAgICAgIC5hY2NlbGVyYXRlVHJhbnNhY3Rpb24oeyB0cmFuc2FjdGlvbklEOiBwYXJlbnRUeElkLCBmZWVSYXRlOiAyMDAwIH0pXG4gICAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoXG4gICAgICAgICAgICAvXlRyYW5zYWN0aW9uIFswLTlhLWZdKyBjb250YWlucyBubyBvdXRwdXRzIHRvIHRoaXMgd2FsbGV0LCBhbmQgdGh1cyBjYW5ub3QgYmUgYWNjZWxlcmF0ZWQkL1xuICAgICAgICAgICk7XG4gICAgICB9KTtcblxuICAgICAgLypcbiAgICAgICAqIFRoaXMgdGVzdCBjb3ZlcnMgdGhlIGNhc2Ugd2hlcmUgYSBmYWlsdXJlIG9jY3VycyBkdXJpbmcgdGhlIHByb2Nlc3Mgb2ZcbiAgICAgICAqIGNvbnZlcnRpbmcgYW4gb3V0cHV0IGZyb20gdGhlIHBhcmVudCB0cmFuc2FjdGlvbiBpbnRvIGFuIHVuc3BlbnQgd2hpY2hcbiAgICAgICAqIGNhbiBiZSB1c2VkIHRvIGNoYWluIHRoZSBjaGlsZCB0eCB0byB0aGUgcGFyZW50LlxuICAgICAgICpcbiAgICAgICAqIFRoaXMgc2hvdWxkIG5ldmVyIGhhcHBlbiwgYnV0IGl0IGlzIHBvc3NpYmxlIChmb3IgZXhhbXBsZSwgaW4gdGhlIGNhc2VcbiAgICAgICAqIG9mIGFuIGF0dGVtcHRlZCBkb3VibGUgc3BlbmQgb2YgdGhlIG91dHB1dCBmcm9tIHRoZSBwYXJlbnQsIG9yIGEgcmFjZVxuICAgICAgICogYmV0d2VlbiBmaW5kaW5nIHRoZSBwYXJlbnQgb3V0cHV0LCBhbmQgcmV0cmlldmluZyB0aGUgY29ycmVzcG9uZGluZyB1bnNwZW50KS5cbiAgICAgICAqL1xuICAgICAgaXQoJ2Nhbm5vdCBmaW5kIGNvcnJlY3QgdW5zcGVudCB0byB1c2UnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgICAgLmdldChgL2FwaS92MS93YWxsZXQvJHt3YWxsZXQuaWQoKX0vdHgvJHtwYXJlbnRUeElkfWApXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgb3V0cHV0czogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3V0cHV0QWRkcmVzcyxcbiAgICAgICAgICAgICAgICB2YWx1ZTogNTAgKiAxZTQsXG4gICAgICAgICAgICAgICAgdm91dDogb3V0cHV0SWR4LFxuICAgICAgICAgICAgICAgIGlzTWluZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjaGFpbjogMCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBjb25maXJtYXRpb25zOiAwLFxuICAgICAgICAgICAgaGV4OiBwYXJlbnRUeElkLFxuICAgICAgICAgICAgZmVlOiAxMCxcbiAgICAgICAgICB9KTtcblxuICAgICAgICBub2NrKGJnVXJsKS5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7d2FsbGV0LmlkKCl9L3Vuc3BlbnRzYCkucXVlcnkodHJ1ZSkucmVwbHkoMjAwLCB7XG4gICAgICAgICAgY291bnQ6IDAsXG4gICAgICAgICAgdW5zcGVudHM6IFtdLFxuICAgICAgICB9KTtcblxuICAgICAgICBhd2FpdCB3YWxsZXRcbiAgICAgICAgICAuYWNjZWxlcmF0ZVRyYW5zYWN0aW9uKHsgdHJhbnNhY3Rpb25JRDogcGFyZW50VHhJZCwgZmVlUmF0ZTogMjAwMCB9KVxuICAgICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9eQ291bGQgbm90IGZpbmQgdW5zcGVudCBvdXRwdXQgZnJvbSBwYXJlbnQgdHggdG8gdXNlIGFzIGNoaWxkIGlucHV0JC8pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdEZXRlY3RzIHdoZW4gYW4gaW5jb3JyZWN0IHR4IGhleCBpcyByZXR1cm5lZCBieSB0aGUgZXh0ZXJuYWwgc2VydmljZScsIGFzeW5jICgpID0+IHtcbiAgICAgICAgbm9jayhiZ1VybClcbiAgICAgICAgICAuZ2V0KGAvYXBpL3YxL3dhbGxldC8ke3dhbGxldC5pZCgpfS90eC8ke3BhcmVudFR4SWR9YClcbiAgICAgICAgICAucmVwbHkoMjAwLCB7XG4gICAgICAgICAgICBvdXRwdXRzOiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBhY2NvdW50OiBvdXRwdXRBZGRyZXNzLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAxMCxcbiAgICAgICAgICAgICAgICB2b3V0OiBvdXRwdXRJZHgsXG4gICAgICAgICAgICAgICAgaXNNaW5lOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNoYWluOiAwLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIGNvbmZpcm1hdGlvbnM6IDAsXG4gICAgICAgICAgICBoZXg6IGZpeHR1cmVzW3BhcmVudFR4SWRdLFxuICAgICAgICAgICAgZmVlOiAxMCxcbiAgICAgICAgICB9KTtcblxuICAgICAgICBub2NrKGJnVXJsKVxuICAgICAgICAgIC5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7d2FsbGV0LmlkKCl9L3Vuc3BlbnRzYClcbiAgICAgICAgICAucXVlcnkodHJ1ZSlcbiAgICAgICAgICAucmVwbHkoMjAwLCB7XG4gICAgICAgICAgICBjb3VudDogMSxcbiAgICAgICAgICAgIHVuc3BlbnRzOiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB0eF9oYXNoOiBwYXJlbnRUeElkLFxuICAgICAgICAgICAgICAgIHR4X291dHB1dF9uOiBvdXRwdXRJZHgsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgIG5vY2soZXhwbG9yZXJVcmwpLmdldChgL3R4LyR7cGFyZW50VHhJZH0vaGV4YCkucmVwbHkoMjAwLCBmaXh0dXJlc1t1bnJlbGF0ZWRUeElkXSk7XG5cbiAgICAgICAgYXdhaXQgd2FsbGV0XG4gICAgICAgICAgLmFjY2VsZXJhdGVUcmFuc2FjdGlvbih7IHRyYW5zYWN0aW9uSUQ6IHBhcmVudFR4SWQsIGZlZVJhdGU6IDIwMDAgfSlcbiAgICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvXkRlY29kZWQgdHJhbnNhY3Rpb24gaWQgaXMgWzAtOWEtZl0rLCB3aGljaCBkb2VzIG5vdCBtYXRjaCBnaXZlbiB0eGlkIFswLTlhLWZdKyQvKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnY2Fubm90IGNvdmVyIGNoaWxkIGZlZSB3aXRoIG9uZSBwYXJlbnQgb3V0cHV0IGFuZCBvbmUgd2FsbGV0IHVuc3BlbnQnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgICAgLmdldChgL2FwaS92MS93YWxsZXQvJHt3YWxsZXQuaWQoKX0vdHgvJHtwYXJlbnRUeElkfWApXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgb3V0cHV0czogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3V0cHV0QWRkcmVzcyxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMTAsXG4gICAgICAgICAgICAgICAgdm91dDogb3V0cHV0SWR4LFxuICAgICAgICAgICAgICAgIGlzTWluZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjaGFpbjogMCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBjb25maXJtYXRpb25zOiAwLFxuICAgICAgICAgICAgaGV4OiBmaXh0dXJlc1twYXJlbnRUeElkXSxcbiAgICAgICAgICAgIGZlZTogMTAsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgbm9jayhiZ1VybClcbiAgICAgICAgICAuZ2V0KGAvYXBpL3YxL3dhbGxldC8ke3dhbGxldC5pZCgpfS91bnNwZW50c2ApXG4gICAgICAgICAgLnF1ZXJ5KHRydWUpXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgY291bnQ6IDEsXG4gICAgICAgICAgICB1bnNwZW50czogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdHhfaGFzaDogcGFyZW50VHhJZCxcbiAgICAgICAgICAgICAgICB0eF9vdXRwdXRfbjogb3V0cHV0SWR4LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICBub2NrKGV4cGxvcmVyVXJsKS5nZXQoYC90eC8ke3BhcmVudFR4SWR9L2hleGApLnJlcGx5KDIwMCwgZml4dHVyZXNbcGFyZW50VHhJZF0pO1xuXG4gICAgICAgIG5vY2soYmdVcmwpLmdldChgL2FwaS92MS93YWxsZXQvJHt3YWxsZXQuaWQoKX0vdW5zcGVudHNgKS5xdWVyeSh0cnVlKS5yZXBseSgyMDAsIHtcbiAgICAgICAgICBjb3VudDogMCxcbiAgICAgICAgICB1bnNwZW50czogW10sXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGF3YWl0IHdhbGxldFxuICAgICAgICAgIC5hY2NlbGVyYXRlVHJhbnNhY3Rpb24oeyB0cmFuc2FjdGlvbklEOiBwYXJlbnRUeElkLCBmZWVSYXRlOiAyMDAwIH0pXG4gICAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL15JbnN1ZmZpY2llbnQgY29uZmlybWVkIHVuc3BlbnRzIGF2YWlsYWJsZSB0byBjb3ZlciB0aGUgY2hpbGQgZmVlJC8pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdjYW5ub3QgbG93ZXIgZmVlIHJhdGUnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgICAgLmdldChgL2FwaS92MS93YWxsZXQvJHt3YWxsZXQuaWQoKX0vdHgvJHtwYXJlbnRUeElkfWApXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgb3V0cHV0czogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3V0cHV0QWRkcmVzcyxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMTAsXG4gICAgICAgICAgICAgICAgdm91dDogb3V0cHV0SWR4LFxuICAgICAgICAgICAgICAgIGlzTWluZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjaGFpbjogMTEsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgY29uZmlybWF0aW9uczogMCxcbiAgICAgICAgICAgIGhleDogZml4dHVyZXNbcGFyZW50VHhJZF0sXG4gICAgICAgICAgICBmZWU6IDEwMDAwLCAvLyBsYXJnZSBmZWUsIGFuZCB0aHVzIGZlZSByYXRlLCBmb3IgcGFyZW50XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgbm9jayhiZ1VybClcbiAgICAgICAgICAuZ2V0KGAvYXBpL3YxL3dhbGxldC8ke3dhbGxldC5pZCgpfS91bnNwZW50c2ApXG4gICAgICAgICAgLnF1ZXJ5KHRydWUpXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgY291bnQ6IDEsXG4gICAgICAgICAgICB1bnNwZW50czogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdHhfaGFzaDogcGFyZW50VHhJZCxcbiAgICAgICAgICAgICAgICB0eF9vdXRwdXRfbjogb3V0cHV0SWR4LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICBub2NrKGV4cGxvcmVyVXJsKS5nZXQoYC90eC8ke3BhcmVudFR4SWR9L2hleGApLnJlcGx5KDIwMCwgZml4dHVyZXNbcGFyZW50VHhJZF0pO1xuXG4gICAgICAgIGF3YWl0IHdhbGxldFxuICAgICAgICAgIC5hY2NlbGVyYXRlVHJhbnNhY3Rpb24oeyB0cmFuc2FjdGlvbklEOiBwYXJlbnRUeElkLCBmZWVSYXRlOiAyMDAwIH0pXG4gICAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoXG4gICAgICAgICAgICAvXkNhbm5vdCBsb3dlciBmZWUgcmF0ZSEgXFwoUGFyZW50IHR4IGZlZSByYXRlIGlzIFxcZCtcXC4/XFxkKiBzYXRcXC9rQiwgYW5kIHJlcXVlc3RlZCBmZWUgcmF0ZSB3YXMgXFxkK1xcLj9cXGQqIHNhdFxcL2tCXFwpJC9cbiAgICAgICAgICApO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdjYW5ub3QgYnJlYWsgbWF4aW11bSBmZWUgbGltaXQgZm9yIGNvbWJpbmVkIHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgICBub2NrKGJnVXJsKVxuICAgICAgICAgIC5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7d2FsbGV0LmlkKCl9L3R4LyR7cGFyZW50VHhJZH1gKVxuICAgICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAgIG91dHB1dHM6IFtcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGFjY291bnQ6IG91dHB1dEFkZHJlc3MsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDNlNyxcbiAgICAgICAgICAgICAgICB2b3V0OiBvdXRwdXRJZHgsXG4gICAgICAgICAgICAgICAgaXNNaW5lOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNoYWluOiAxMSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBjb25maXJtYXRpb25zOiAwLFxuICAgICAgICAgICAgaGV4OiBmaXh0dXJlc1twYXJlbnRUeElkXSxcbiAgICAgICAgICAgIGZlZTogMTAwMCxcbiAgICAgICAgICB9KTtcblxuICAgICAgICBub2NrKGJnVXJsKVxuICAgICAgICAgIC5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7d2FsbGV0LmlkKCl9L3Vuc3BlbnRzYClcbiAgICAgICAgICAucXVlcnkodHJ1ZSlcbiAgICAgICAgICAucmVwbHkoMjAwLCB7XG4gICAgICAgICAgICBjb3VudDogMSxcbiAgICAgICAgICAgIHVuc3BlbnRzOiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB0eF9oYXNoOiBwYXJlbnRUeElkLFxuICAgICAgICAgICAgICAgIHR4X291dHB1dF9uOiBvdXRwdXRJZHgsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgIG5vY2soZXhwbG9yZXJVcmwpLmdldChgL3R4LyR7cGFyZW50VHhJZH0vaGV4YCkucmVwbHkoMjAwLCBmaXh0dXJlc1twYXJlbnRUeElkXSk7XG5cbiAgICAgICAgYXdhaXQgd2FsbGV0XG4gICAgICAgICAgLmFjY2VsZXJhdGVUcmFuc2FjdGlvbih7IHRyYW5zYWN0aW9uSUQ6IHBhcmVudFR4SWQsIGZlZVJhdGU6IDJlNiB9KVxuICAgICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKFxuICAgICAgICAgICAgL15UcmFuc2FjdGlvbiBjYW5ub3QgYmUgYWNjZWxlcmF0ZWRcXC4gQ29tYmluZWQgZmVlIHJhdGUgb2YgXFxkK1xcLj9cXGQqIHNhdFxcL2tCIGV4Y2VlZHMgbWF4aW11bSBmZWUgcmF0ZSBvZiBcXGQrXFwuP1xcZCogc2F0XFwva0IkL1xuICAgICAgICAgICk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCdzdWNjZXNzZnVsIHR4IGFjY2VsZXJhdGlvbicsIGZ1bmN0aW9uIHN1Y2Nlc3NmdWxUeERlc2NyaWJlKCkge1xuICAgICAgY29uc3QgZmVlUmF0ZSA9IDIwMDAwO1xuXG4gICAgICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICAgICAgbm9jayhiZ1VybCkucG9zdChgL2FwaS92MS93YWxsZXQvJHt3YWxsZXQuaWQoKX0vYWRkcmVzcy8xYCkucmVwbHkoMjAwLCB7XG4gICAgICAgICAgYWRkcmVzczogJzJOQ1lqRzhRNTZ5cjh0eDlqYXpOb1luR0t4amdCMk1RU2ZZJyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgbm9jayhiZ1VybCkucG9zdCgnL2FwaS92MS9iaWxsaW5nL2FkZHJlc3MnKS5yZXBseSgyMDAsIHtcbiAgICAgICAgICBhZGRyZXNzOiAnMk5GYnZvMkhLNGVYWm0xYXFEY1NER0dxRDY0RlB0N1Q2ZDgnLFxuICAgICAgICB9KTtcblxuICAgICAgICBub2NrKGJnVXJsKS5nZXQoJy9hcGkvdjEvdHgvZmVlJykucXVlcnkodHJ1ZSkucmVwbHkoMjAwLCB7XG4gICAgICAgICAgZmVlUGVyS2I6IDAsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgICAgLnBvc3QoYC9hcGkvdjEva2V5Y2hhaW4vJHt1c2VyS2V5cGFpci54cHVifWAsIHt9KVxuICAgICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAgIGVuY3J5cHRlZFhwcnY6IGJpdGdvLmVuY3J5cHQoeyBpbnB1dDogdXNlcktleXBhaXIueHBydiwgcGFzc3dvcmQ6IFRlc3RCaXRHby5URVNUX1dBTExFVDFfUEFTU0NPREUgfSksXG4gICAgICAgICAgICBwYXRoOiB1c2VyS2V5cGFpci5wYXRoICsgdXNlcktleXBhaXIud2FsbGV0U3ViUGF0aCxcbiAgICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnYWNjZWxlcmF0ZXMgYSBzdHVjayB0eCB3aXRob3V0IGFkZGl0aW9uYWwgdW5zcGVudHMnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIHBhcmVudFR4SWQgPSAnNzVjZmM1YTdiMjE0YzRiNzNjOTJjN2IwMjYwOGNkZTcwYjIyNjc2N2E5NTc2Zjg0YzA0NDA3ZTQzZmQzODViZCc7XG4gICAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgICAgLmdldChgL2FwaS92MS93YWxsZXQvJHt3YWxsZXQuaWQoKX0vdHgvJHtwYXJlbnRUeElkfWApXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgZmVlOiA0MzQsXG4gICAgICAgICAgICBvdXRwdXRzOiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB2b3V0OiAwLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAxMDM0ODUwMCxcbiAgICAgICAgICAgICAgICBpc01pbmU6IHRydWUsXG4gICAgICAgICAgICAgICAgY2hhaW46IDEsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB2b3V0OiAxLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAxMDAwMCxcbiAgICAgICAgICAgICAgICBpc01pbmU6IHRydWUsXG4gICAgICAgICAgICAgICAgY2hhaW46IDExLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICBub2NrKGJnVXJsKVxuICAgICAgICAgIC5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7d2FsbGV0LmlkKCl9L3Vuc3BlbnRzYClcbiAgICAgICAgICAucXVlcnkodHJ1ZSlcbiAgICAgICAgICAucmVwbHkoMjAwLCB7XG4gICAgICAgICAgICB1bnNwZW50czogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdHhfaGFzaDogcGFyZW50VHhJZCxcbiAgICAgICAgICAgICAgICB0eF9vdXRwdXRfbjogMCxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMTAzNDg1MDAsXG4gICAgICAgICAgICAgICAgcmVkZWVtU2NyaXB0OiAnMDAyMGY3YjU4ZDQ1NTM1MWI3YjhkZGQ3Yzg5ODZkOTgyNDRmNmE5NWYwNzQ2NzIwMDkxNTM3MzIzYjk2NzgwMGY3NDQnLFxuICAgICAgICAgICAgICAgIGNoYWluUGF0aDogJy8xMS8xNjAnLFxuICAgICAgICAgICAgICAgIHdpdG5lc3NTY3JpcHQ6XG4gICAgICAgICAgICAgICAgICAnNTIyMTAyN2YwYjQ1YmI0MTU1ZWE1MzJlM2I0MzEyZmUwYmU4MDE2NmYyOTdkMWUwNzUzZDJkNGE5MTE4YzA3M2FkNjUxNDIxMDMxMGFhOWQ2OGM5ODgzMTYyNWYzMjliNzgyNmI2YzNlM2I1M2UxNjczNmIxOTk0Yjg5MDI0NDJiZGNkNjY1M2QxMjEwMjZlMGNhNDE0ZjI0ODhiMGFiNTcyYjk5ZTBhZTU0NDI5MTFhYjRlMDgyMWIyNzA5ZDg4NTE3NWE1MjdmZDU1MmI1M2FlJyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgbm9jayhleHBsb3JlclVybCkuZ2V0KGAvdHgvJHtwYXJlbnRUeElkfS9oZXhgKS5yZXBseSgyMDAsIGZpeHR1cmVzW3BhcmVudFR4SWRdKTtcblxuICAgICAgICBub2NrKGJnVXJsKVxuICAgICAgICAgIC5wb3N0KCcvYXBpL3YxL3R4L3NlbmQnLCAoYm9keSkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuICFib2R5Lmlnbm9yZU1heEZlZVJhdGU7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAucmVwbHkoMjAwLCBmdW5jdGlvbiAoXywgYm9keSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgdHJhbnNhY3Rpb246IChib2R5IGFzIGFueSkudHgsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IGNoaWxkVHggPSBhd2FpdCB3YWxsZXQuYWNjZWxlcmF0ZVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0cmFuc2FjdGlvbklEOiBwYXJlbnRUeElkLFxuICAgICAgICAgIGZlZVJhdGUsXG4gICAgICAgICAgd2FsbGV0UGFzc3BocmFzZTogVGVzdEJpdEdvLlRFU1RfV0FMTEVUMV9QQVNTQ09ERSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgc2hvdWxkLmV4aXN0KGNoaWxkVHgpO1xuICAgICAgICBjaGlsZFR4LnNob3VsZC5oYXZlLnByb3BlcnR5KCdzdGF0dXMnLCAnYWNjZXB0ZWQnKTtcbiAgICAgICAgY2hpbGRUeC5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndHgnKTtcblxuICAgICAgICAvLyBhc3NlcnQgdGhlIGZvbGxvd2luZzpcbiAgICAgICAgLy8gMCkgVGhlIGNoaWxkIHR4IGhhcyBleGFjdGx5IG9uZSBpbnB1dFxuICAgICAgICAvLyAxKSBUaGUgcGFyZW50IHR4IG91dHB1dCBpcyBhbiBpbnB1dFxuICAgICAgICAvLyAyKSBUaGUgY2hpbGQgdHggaGFzIGV4YWN0bHkgb25lIG91dHB1dFxuICAgICAgICAvLyAzKSBUaGUgY2hpbGQgdHggb3V0cHV0IG1lZXRzIHRoZSBtaW5pbXVtIGNoYW5nZSB0aHJlc2hvbGRcbiAgICAgICAgY29uc3QgZGVjb2RlZENoaWxkID0gdXR4b2xpYi5iaXRnby5jcmVhdGVUcmFuc2FjdGlvbkZyb21IZXgoY2hpbGRUeC50eCwgdXR4b2xpYi5uZXR3b3Jrcy5iaXRjb2luKTtcbiAgICAgICAgZGVjb2RlZENoaWxkLmlucy5sZW5ndGguc2hvdWxkLmVxdWFsKDEpO1xuICAgICAgICBkZWNvZGVkQ2hpbGQub3V0cy5sZW5ndGguc2hvdWxkLmVxdWFsKDEpO1xuXG4gICAgICAgIGNvbnN0IGNoaWxkSW5wdXQgPSBkZWNvZGVkQ2hpbGQuaW5zWzBdO1xuICAgICAgICBjaGlsZElucHV0LnNob3VsZC5oYXZlLnByb3BlcnR5KCdpbmRleCcsIDApO1xuICAgICAgICBjaGlsZElucHV0LnNob3VsZC5oYXZlLnByb3BlcnR5KCdoYXNoJyk7XG5cbiAgICAgICAgY29uc3QgaW5wdXRUeElkID0gaW5wdXRQYXJlbnRUeElkKGNoaWxkSW5wdXQpO1xuICAgICAgICBpbnB1dFR4SWQuc2hvdWxkLmVxdWFsKHBhcmVudFR4SWQpO1xuXG4gICAgICAgIGNvbnN0IGNoaWxkT3V0cHV0ID0gZGVjb2RlZENoaWxkLm91dHNbMF07XG4gICAgICAgIGNoaWxkT3V0cHV0LnNob3VsZC5oYXZlLnByb3BlcnR5KCd2YWx1ZScpO1xuICAgICAgICBjaGlsZE91dHB1dC52YWx1ZS5zaG91bGQuYmUuYWJvdmUobWluQ2hhbmdlU2l6ZSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ2FjY2VsZXJhdGVzIGEgc3R1Y2sgdHggd2l0aCBvbmUgYWRkaXRpb25hbCBzZWd3aXQgdW5zcGVudCcsIGFzeW5jICgpID0+IHtcbiAgICAgICAgcGFyZW50VHhJZCA9ICc4ODE1ZjIwMmM4NjU0YjZjOGIyOTU3NDk1NDVjNzExODc4Y2Q4NDVhMTRjYjFlYTk4MjM5NGQwYzE0OTQ1YzMzJztcbiAgICAgICAgY29uc3QgYWRkaXRpb25hbFVuc3BlbnRUeElkID0gJzA3ZDZlZTU3YjAyNGNlMmI2MTA4ZjY3ODQ3NDU0YTBhNzlhNGZjZmI5OGFiMjU1NTUzYTI5OTNhMWExNzBiODcnO1xuICAgICAgICBub2NrKGJnVXJsKVxuICAgICAgICAgIC5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7d2FsbGV0LmlkKCl9L3R4LyR7cGFyZW50VHhJZH1gKVxuICAgICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAgIGZlZTogMTMzNixcbiAgICAgICAgICAgIG91dHB1dHM6IFtcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHZvdXQ6IDAsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDEwMDAwLFxuICAgICAgICAgICAgICAgIGlzTWluZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjaGFpbjogMTEsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB2b3V0OiAxLFxuICAgICAgICAgICAgICAgIHZhbHVlOiA4NjY0LFxuICAgICAgICAgICAgICAgIGlzTWluZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjaGFpbjogMSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBjb25maXJtYXRpb25zOiAwLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgICAgLmdldChgL2FwaS92MS93YWxsZXQvJHt3YWxsZXQuaWQoKX0vdW5zcGVudHNgKVxuICAgICAgICAgIC5xdWVyeSh0cnVlKVxuICAgICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAgIHVuc3BlbnRzOiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB0eF9oYXNoOiBwYXJlbnRUeElkLFxuICAgICAgICAgICAgICAgIHR4X291dHB1dF9uOiAwLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAxMDAwMCxcbiAgICAgICAgICAgICAgICByZWRlZW1TY3JpcHQ6XG4gICAgICAgICAgICAgICAgICAnNTIyMTAyY2QzYzhlNjAwNmE0NjI3NzA1MDIxZDFkMDE2ZDA5N2MyOTQ0ZDk4MTAwYTQ3YmYyZGE2N2E1ZmUxNWFlZWIzNDIxMDJlZTFmYTllODEyZTc3OTM1NmFhM2MzMWViZjMxN2QwY2ZmZWJhYjkyODY0Y2ZlMzhiYWIyMjNlMDgyMGY5OGJjMjEwMjZiYTA1NzUyYmFhNmVhZmQ1YzU2NTlkYTYyYjdmMGFjNTFmZDI4ODZiNjVjMjQxZDBhZmVmMWM0ZmRmYTFjYmM1M2FlJyxcbiAgICAgICAgICAgICAgICBjaGFpblBhdGg6ICcvMC8wJyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgbm9jayhiZ1VybClcbiAgICAgICAgICAuZ2V0KGAvYXBpL3YxL3dhbGxldC8ke3dhbGxldC5pZCgpfS91bnNwZW50c2ApXG4gICAgICAgICAgLnF1ZXJ5KHRydWUpXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgdW5zcGVudHM6IFtcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHR4X2hhc2g6IGFkZGl0aW9uYWxVbnNwZW50VHhJZCxcbiAgICAgICAgICAgICAgICB0eF9vdXRwdXRfbjogMCxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMTk5MzU1MjYsXG4gICAgICAgICAgICAgICAgcmVkZWVtU2NyaXB0OiAnMDAyMGQzNGVmNmRkMzRlZjJhNGZiZWE2N2M1NDFjMWM3OTY3NDlhNjBhZmU0YTk3ZmVlOGVjN2RlZDE4OGJkNzQ5ZGEnLFxuICAgICAgICAgICAgICAgIGNoYWluUGF0aDogJy8xMS8xNTUnLFxuICAgICAgICAgICAgICAgIHdpdG5lc3NTY3JpcHQ6XG4gICAgICAgICAgICAgICAgICAnNTIyMTAyMjE5ZDJhYTg0MTc2MzNmMGJjZTM5MTEzNzRhMTYwNGMxYjY0MTYxZjgzYTNjMmVlNDA5YzI3YzQyMzU1ZjA4ZTIxMDJjOTczNDkyMGRjNGRhMDZjMjg5ZmU2OTE3MWRmY2Q3NWUzYjliNGYxOTBkMGNiYzNkNWQwZmYzZjVmZGVlYWFlMjEwM2NjZDY4ZDdmYThkYzBkMDJkZDQ1ZGFkMTY1NTU3YTQ4NTgyZWRhNDQzNWZhZTczNzdiM2MzMWUwOGFkMDY1Yzk1M2FlJyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgbm9jayhleHBsb3JlclVybCkuZ2V0KGAvdHgvJHtwYXJlbnRUeElkfS9oZXhgKS5yZXBseSgyMDAsIGZpeHR1cmVzW3BhcmVudFR4SWRdKTtcblxuICAgICAgICBub2NrKGJnVXJsKVxuICAgICAgICAgIC5wb3N0KCcvYXBpL3YxL3R4L3NlbmQnLCAoYm9keSkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuICFib2R5Lmlnbm9yZU1heEZlZVJhdGU7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAucmVwbHkoMjAwLCBmdW5jdGlvbiAoXywgYm9keSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgdHJhbnNhY3Rpb246IChib2R5IGFzIGFueSkudHgsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IGNoaWxkVHggPSBhd2FpdCB3YWxsZXQuYWNjZWxlcmF0ZVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0cmFuc2FjdGlvbklEOiBwYXJlbnRUeElkLFxuICAgICAgICAgIGZlZVJhdGUsXG4gICAgICAgICAgd2FsbGV0UGFzc3BocmFzZTogVGVzdEJpdEdvLlRFU1RfV0FMTEVUMV9QQVNTQ09ERSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgc2hvdWxkLmV4aXN0KGNoaWxkVHgpO1xuICAgICAgICBjaGlsZFR4LnNob3VsZC5oYXZlLnByb3BlcnR5KCdzdGF0dXMnLCAnYWNjZXB0ZWQnKTtcbiAgICAgICAgY2hpbGRUeC5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndHgnKTtcblxuICAgICAgICAvLyBhc3NlcnQgdGhlIGZvbGxvd2luZzpcbiAgICAgICAgLy8gMCkgVGhlIGNoaWxkIHR4IGhhcyBleGFjdGx5IHR3byBpbnB1dHNcbiAgICAgICAgLy8gMSkgVGhlIHBhcmVudCB0eCBvdXRwdXQgaXMgYW4gaW5wdXRcbiAgICAgICAgLy8gMikgVGhlIGFkZGl0aW9uYWwgdW5zcGVudCBvdXRwdXQgaXMgYW4gaW5wdXRcbiAgICAgICAgLy8gMykgVGhlIGNoaWxkIHR4IGhhcyBleGFjdGx5IG9uZSBvdXRwdXRcbiAgICAgICAgLy8gNCkgVGhlIGNoaWxkIHR4IG91dHB1dCBtZWV0cyB0aGUgbWluaW11bSBjaGFuZ2UgdGhyZXNob2xkXG4gICAgICAgIGNvbnN0IGRlY29kZWRDaGlsZCA9IHV0eG9saWIuYml0Z28uY3JlYXRlVHJhbnNhY3Rpb25Gcm9tSGV4KGNoaWxkVHgudHgsIHV0eG9saWIubmV0d29ya3MuYml0Y29pbik7XG4gICAgICAgIGRlY29kZWRDaGlsZC5pbnMubGVuZ3RoLnNob3VsZC5lcXVhbCgyKTtcbiAgICAgICAgZGVjb2RlZENoaWxkLm91dHMubGVuZ3RoLnNob3VsZC5lcXVhbCgxKTtcblxuICAgICAgICBsZXQgaW5wdXRGcm9tUGFyZW50OiBhbnkgPSB1bmRlZmluZWQ7XG4gICAgICAgIGxldCBhZGRpdGlvbmFsSW5wdXQ6IGFueSA9IHVuZGVmaW5lZDtcblxuICAgICAgICBfLmZvckVhY2goZGVjb2RlZENoaWxkLmlucywgKGlucHV0KSA9PiB7XG4gICAgICAgICAgaW5wdXQuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2hhc2gnKTtcbiAgICAgICAgICBpbnB1dC5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnaW5kZXgnKTtcblxuICAgICAgICAgIGNvbnN0IGlucHV0VHhJZCA9IGlucHV0UGFyZW50VHhJZChpbnB1dCk7XG5cbiAgICAgICAgICBpZiAoaW5wdXRUeElkID09PSBwYXJlbnRUeElkKSB7XG4gICAgICAgICAgICBpbnB1dEZyb21QYXJlbnQgPSBpbnB1dDtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYWRkaXRpb25hbElucHV0ID0gaW5wdXQ7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBzaG91bGQuZXhpc3QoaW5wdXRGcm9tUGFyZW50KTtcbiAgICAgICAgY29uc3QgaW5wdXRGcm9tUGFyZW50SGFzaCA9IGlucHV0UGFyZW50VHhJZChpbnB1dEZyb21QYXJlbnQpO1xuICAgICAgICBpbnB1dEZyb21QYXJlbnRIYXNoLnNob3VsZC5lcXVhbChwYXJlbnRUeElkKTtcbiAgICAgICAgaW5wdXRGcm9tUGFyZW50LmluZGV4LnNob3VsZC5lcXVhbCgwKTtcblxuICAgICAgICBzaG91bGQuZXhpc3QoYWRkaXRpb25hbElucHV0KTtcbiAgICAgICAgY29uc3QgYWRkaXRpb25hbElucHV0SGFzaCA9IGlucHV0UGFyZW50VHhJZChhZGRpdGlvbmFsSW5wdXQpO1xuICAgICAgICBhZGRpdGlvbmFsSW5wdXRIYXNoLnNob3VsZC5lcXVhbChhZGRpdGlvbmFsVW5zcGVudFR4SWQpO1xuICAgICAgICBhZGRpdGlvbmFsSW5wdXQuaW5kZXguc2hvdWxkLmVxdWFsKDApO1xuXG4gICAgICAgIGNvbnN0IGNoaWxkT3V0cHV0ID0gZGVjb2RlZENoaWxkLm91dHNbMF07XG4gICAgICAgIGNoaWxkT3V0cHV0LnNob3VsZC5oYXZlLnByb3BlcnR5KCd2YWx1ZScpO1xuICAgICAgICBjaGlsZE91dHB1dC52YWx1ZS5zaG91bGQuYmUuYWJvdmUobWluQ2hhbmdlU2l6ZSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ2FjY2VsZXJhdGVzIGEgc3R1Y2sgdHggd2l0aCBvbmUgYWRkaXRpb25hbCBQMlNIIHVuc3BlbnQnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIHBhcmVudFR4SWQgPSAnODgxNWYyMDJjODY1NGI2YzhiMjk1NzQ5NTQ1YzcxMTg3OGNkODQ1YTE0Y2IxZWE5ODIzOTRkMGMxNDk0NWMzMyc7XG4gICAgICAgIGNvbnN0IGFkZGl0aW9uYWxVbnNwZW50VHhJZCA9ICdlMTkwMzEwZjJmM2Y3MWFhODg0NmYxMTYxY2JjZTE1MzNjMjRhODU3ZGQyNGU0NTAxYjEzMWZlYjQwMGFhZDU4JztcbiAgICAgICAgbm9jayhiZ1VybClcbiAgICAgICAgICAuZ2V0KGAvYXBpL3YxL3dhbGxldC8ke3dhbGxldC5pZCgpfS90eC8ke3BhcmVudFR4SWR9YClcbiAgICAgICAgICAucmVwbHkoMjAwLCB7XG4gICAgICAgICAgICBmZWU6IDEzMzYsXG4gICAgICAgICAgICBvdXRwdXRzOiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB2b3V0OiAwLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAxMDAwMCxcbiAgICAgICAgICAgICAgICBpc01pbmU6IHRydWUsXG4gICAgICAgICAgICAgICAgY2hhaW46IDExLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdm91dDogMSxcbiAgICAgICAgICAgICAgICB2YWx1ZTogODY2NCxcbiAgICAgICAgICAgICAgICBpc01pbmU6IHRydWUsXG4gICAgICAgICAgICAgICAgY2hhaW46IDEsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgY29uZmlybWF0aW9uczogMCxcbiAgICAgICAgICB9KTtcblxuICAgICAgICBub2NrKGJnVXJsKVxuICAgICAgICAgIC5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7d2FsbGV0LmlkKCl9L3Vuc3BlbnRzYClcbiAgICAgICAgICAucXVlcnkodHJ1ZSlcbiAgICAgICAgICAucmVwbHkoMjAwLCB7XG4gICAgICAgICAgICB1bnNwZW50czogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdHhfaGFzaDogcGFyZW50VHhJZCxcbiAgICAgICAgICAgICAgICB0eF9vdXRwdXRfbjogMCxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMTAwMDAsXG4gICAgICAgICAgICAgICAgcmVkZWVtU2NyaXB0OlxuICAgICAgICAgICAgICAgICAgJzUyMjEwMmNkM2M4ZTYwMDZhNDYyNzcwNTAyMWQxZDAxNmQwOTdjMjk0NGQ5ODEwMGE0N2JmMmRhNjdhNWZlMTVhZWViMzQyMTAyZWUxZmE5ZTgxMmU3NzkzNTZhYTNjMzFlYmYzMTdkMGNmZmViYWI5Mjg2NGNmZTM4YmFiMjIzZTA4MjBmOThiYzIxMDI2YmEwNTc1MmJhYTZlYWZkNWM1NjU5ZGE2MmI3ZjBhYzUxZmQyODg2YjY1YzI0MWQwYWZlZjFjNGZkZmExY2JjNTNhZScsXG4gICAgICAgICAgICAgICAgY2hhaW5QYXRoOiAnLzAvMCcsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgICAgLmdldChgL2FwaS92MS93YWxsZXQvJHt3YWxsZXQuaWQoKX0vdW5zcGVudHNgKVxuICAgICAgICAgIC5xdWVyeSh0cnVlKVxuICAgICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAgIHVuc3BlbnRzOiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB0eF9oYXNoOiBhZGRpdGlvbmFsVW5zcGVudFR4SWQsXG4gICAgICAgICAgICAgICAgdHhfb3V0cHV0X246IDEsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDIwMDAwMDAwLFxuICAgICAgICAgICAgICAgIHJlZGVlbVNjcmlwdDpcbiAgICAgICAgICAgICAgICAgICc1MjIxMDJjZDNjOGU2MDA2YTQ2Mjc3MDUwMjFkMWQwMTZkMDk3YzI5NDRkOTgxMDBhNDdiZjJkYTY3YTVmZTE1YWVlYjM0MjEwMmVlMWZhOWU4MTJlNzc5MzU2YWEzYzMxZWJmMzE3ZDBjZmZlYmFiOTI4NjRjZmUzOGJhYjIyM2UwODIwZjk4YmMyMTAyNmJhMDU3NTJiYWE2ZWFmZDVjNTY1OWRhNjJiN2YwYWM1MWZkMjg4NmI2NWMyNDFkMGFmZWYxYzRmZGZhMWNiYzUzYWUnLFxuICAgICAgICAgICAgICAgIGNoYWluUGF0aDogJy8wLzAnLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICBub2NrKGV4cGxvcmVyVXJsKS5nZXQoYC90eC8ke3BhcmVudFR4SWR9L2hleGApLnJlcGx5KDIwMCwgZml4dHVyZXNbcGFyZW50VHhJZF0pO1xuXG4gICAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgICAgLnBvc3QoJy9hcGkvdjEvdHgvc2VuZCcsIChib2R5KSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gIWJvZHkuaWdub3JlTWF4RmVlUmF0ZTtcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5yZXBseSgyMDAsIGZ1bmN0aW9uIChfLCBib2R5KSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICB0cmFuc2FjdGlvbjogKGJvZHkgYXMgYW55KS50eCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgY2hpbGRUeCA9IGF3YWl0IHdhbGxldC5hY2NlbGVyYXRlVHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHRyYW5zYWN0aW9uSUQ6IHBhcmVudFR4SWQsXG4gICAgICAgICAgZmVlUmF0ZSxcbiAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiBUZXN0Qml0R28uVEVTVF9XQUxMRVQxX1BBU1NDT0RFLFxuICAgICAgICB9KTtcblxuICAgICAgICBzaG91bGQuZXhpc3QoY2hpbGRUeCk7XG4gICAgICAgIGNoaWxkVHguc2hvdWxkLmhhdmUucHJvcGVydHkoJ3N0YXR1cycsICdhY2NlcHRlZCcpO1xuICAgICAgICBjaGlsZFR4LnNob3VsZC5oYXZlLnByb3BlcnR5KCd0eCcpO1xuXG4gICAgICAgIC8vIGFzc2VydCB0aGUgZm9sbG93aW5nOlxuICAgICAgICAvLyAwKSBUaGUgY2hpbGQgdHggaGFzIGV4YWN0bHkgdHdvIGlucHV0c1xuICAgICAgICAvLyAxKSBUaGUgcGFyZW50IHR4IG91dHB1dCBpcyBhbiBpbnB1dFxuICAgICAgICAvLyAyKSBUaGUgYWRkaXRpb25hbCB1bnNwZW50IG91dHB1dCBpcyBhbiBpbnB1dFxuICAgICAgICAvLyAzKSBUaGUgY2hpbGQgdHggaGFzIGV4YWN0bHkgb25lIG91dHB1dFxuICAgICAgICAvLyA0KSBUaGUgY2hpbGQgdHggb3V0cHV0IG1lZXRzIHRoZSBtaW5pbXVtIGNoYW5nZSB0aHJlc2hvbGRcbiAgICAgICAgY29uc3QgZGVjb2RlZENoaWxkID0gdXR4b2xpYi5iaXRnby5jcmVhdGVUcmFuc2FjdGlvbkZyb21IZXgoY2hpbGRUeC50eCwgdXR4b2xpYi5uZXR3b3Jrcy5iaXRjb2luKTtcbiAgICAgICAgZGVjb2RlZENoaWxkLmlucy5sZW5ndGguc2hvdWxkLmVxdWFsKDIpO1xuICAgICAgICBkZWNvZGVkQ2hpbGQub3V0cy5sZW5ndGguc2hvdWxkLmVxdWFsKDEpO1xuXG4gICAgICAgIGxldCBpbnB1dEZyb21QYXJlbnQ6IGFueSA9IHVuZGVmaW5lZDtcbiAgICAgICAgbGV0IGFkZGl0aW9uYWxJbnB1dDogYW55ID0gdW5kZWZpbmVkO1xuXG4gICAgICAgIF8uZm9yRWFjaChkZWNvZGVkQ2hpbGQuaW5zLCAoaW5wdXQpID0+IHtcbiAgICAgICAgICBpbnB1dC5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnaGFzaCcpO1xuICAgICAgICAgIGlucHV0LnNob3VsZC5oYXZlLnByb3BlcnR5KCdpbmRleCcpO1xuXG4gICAgICAgICAgY29uc3QgaW5wdXRIYXNoID0gaW5wdXRQYXJlbnRUeElkKGlucHV0KTtcblxuICAgICAgICAgIGlmIChpbnB1dEhhc2ggPT09IHBhcmVudFR4SWQpIHtcbiAgICAgICAgICAgIGlucHV0RnJvbVBhcmVudCA9IGlucHV0O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhZGRpdGlvbmFsSW5wdXQgPSBpbnB1dDtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHNob3VsZC5leGlzdChpbnB1dEZyb21QYXJlbnQpO1xuICAgICAgICBjb25zdCBpbnB1dEZyb21QYXJlbnRIYXNoID0gaW5wdXRQYXJlbnRUeElkKGlucHV0RnJvbVBhcmVudCk7XG4gICAgICAgIGlucHV0RnJvbVBhcmVudEhhc2guc2hvdWxkLmVxdWFsKHBhcmVudFR4SWQpO1xuICAgICAgICBpbnB1dEZyb21QYXJlbnQuaW5kZXguc2hvdWxkLmVxdWFsKDApO1xuXG4gICAgICAgIHNob3VsZC5leGlzdChhZGRpdGlvbmFsSW5wdXQpO1xuICAgICAgICBjb25zdCBhZGRpdGlvbmFsSW5wdXRIYXNoID0gaW5wdXRQYXJlbnRUeElkKGFkZGl0aW9uYWxJbnB1dCk7XG4gICAgICAgIGFkZGl0aW9uYWxJbnB1dEhhc2guc2hvdWxkLmVxdWFsKGFkZGl0aW9uYWxVbnNwZW50VHhJZCk7XG4gICAgICAgIGFkZGl0aW9uYWxJbnB1dC5pbmRleC5zaG91bGQuZXF1YWwoMSk7XG5cbiAgICAgICAgY29uc3QgY2hpbGRPdXRwdXQgPSBkZWNvZGVkQ2hpbGQub3V0c1swXTtcbiAgICAgICAgY2hpbGRPdXRwdXQuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3ZhbHVlJyk7XG4gICAgICAgIGNoaWxkT3V0cHV0LnZhbHVlLnNob3VsZC5iZS5hYm92ZShtaW5DaGFuZ2VTaXplKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnYWNjZWxlcmF0ZXMgYSBzdHVjayB0eCB3aXRoIHR3byBhZGRpdGlvbmFsIHVuc3BlbnRzIChzZWd3aXQgYW5kIFAyU0gpJywgYXN5bmMgKCkgPT4ge1xuICAgICAgICBwYXJlbnRUeElkID0gJzg4MTVmMjAyYzg2NTRiNmM4YjI5NTc0OTU0NWM3MTE4NzhjZDg0NWExNGNiMWVhOTgyMzk0ZDBjMTQ5NDVjMzMnO1xuICAgICAgICBub2NrKGJnVXJsKVxuICAgICAgICAgIC5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7d2FsbGV0LmlkKCl9L3R4LyR7cGFyZW50VHhJZH1gKVxuICAgICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAgIGZlZTogMTMzNixcbiAgICAgICAgICAgIG91dHB1dHM6IFtcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHZvdXQ6IDAsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDEwMDAwLFxuICAgICAgICAgICAgICAgIGlzTWluZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjaGFpbjogMTEsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB2b3V0OiAxLFxuICAgICAgICAgICAgICAgIHZhbHVlOiA4NjY0LFxuICAgICAgICAgICAgICAgIGlzTWluZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjaGFpbjogMSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBjb25maXJtYXRpb25zOiAwLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgICAgLmdldChgL2FwaS92MS93YWxsZXQvJHt3YWxsZXQuaWQoKX0vdW5zcGVudHNgKVxuICAgICAgICAgIC5xdWVyeSh0cnVlKVxuICAgICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAgIHVuc3BlbnRzOiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB0eF9oYXNoOiBwYXJlbnRUeElkLFxuICAgICAgICAgICAgICAgIHR4X291dHB1dF9uOiAwLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAxMDAwMCxcbiAgICAgICAgICAgICAgICByZWRlZW1TY3JpcHQ6XG4gICAgICAgICAgICAgICAgICAnNTIyMTAyY2QzYzhlNjAwNmE0NjI3NzA1MDIxZDFkMDE2ZDA5N2MyOTQ0ZDk4MTAwYTQ3YmYyZGE2N2E1ZmUxNWFlZWIzNDIxMDJlZTFmYTllODEyZTc3OTM1NmFhM2MzMWViZjMxN2QwY2ZmZWJhYjkyODY0Y2ZlMzhiYWIyMjNlMDgyMGY5OGJjMjEwMjZiYTA1NzUyYmFhNmVhZmQ1YzU2NTlkYTYyYjdmMGFjNTFmZDI4ODZiNjVjMjQxZDBhZmVmMWM0ZmRmYTFjYmM1M2FlJyxcbiAgICAgICAgICAgICAgICBjaGFpblBhdGg6ICcvMC8wJyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgbm9jayhiZ1VybClcbiAgICAgICAgICAuZ2V0KGAvYXBpL3YxL3dhbGxldC8ke3dhbGxldC5pZCgpfS91bnNwZW50c2ApXG4gICAgICAgICAgLnF1ZXJ5KHRydWUpXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgdW5zcGVudHM6IFtcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHR4X2hhc2g6ICdlMTkwMzEwZjJmM2Y3MWFhODg0NmYxMTYxY2JjZTE1MzNjMjRhODU3ZGQyNGU0NTAxYjEzMWZlYjQwMGFhZDU4JyxcbiAgICAgICAgICAgICAgICB0eF9vdXRwdXRfbjogMSxcbiAgICAgICAgICAgICAgICB2YWx1ZTogODAwMDAwLFxuICAgICAgICAgICAgICAgIHJlZGVlbVNjcmlwdDpcbiAgICAgICAgICAgICAgICAgICc1MjIxMDJjZDNjOGU2MDA2YTQ2Mjc3MDUwMjFkMWQwMTZkMDk3YzI5NDRkOTgxMDBhNDdiZjJkYTY3YTVmZTE1YWVlYjM0MjEwMmVlMWZhOWU4MTJlNzc5MzU2YWEzYzMxZWJmMzE3ZDBjZmZlYmFiOTI4NjRjZmUzOGJhYjIyM2UwODIwZjk4YmMyMTAyNmJhMDU3NTJiYWE2ZWFmZDVjNTY1OWRhNjJiN2YwYWM1MWZkMjg4NmI2NWMyNDFkMGFmZWYxYzRmZGZhMWNiYzUzYWUnLFxuICAgICAgICAgICAgICAgIGNoYWluUGF0aDogJy8wLzAnLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdHhfaGFzaDogJzA3ZDZlZTU3YjAyNGNlMmI2MTA4ZjY3ODQ3NDU0YTBhNzlhNGZjZmI5OGFiMjU1NTUzYTI5OTNhMWExNzBiODcnLFxuICAgICAgICAgICAgICAgIHR4X291dHB1dF9uOiAwLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAyMDAwNjI4NCxcbiAgICAgICAgICAgICAgICByZWRlZW1TY3JpcHQ6ICcwMDIwZDM0ZWY2ZGQzNGVmMmE0ZmJlYTY3YzU0MWMxYzc5Njc0OWE2MGFmZTRhOTdmZWU4ZWM3ZGVkMTg4YmQ3NDlkYScsXG4gICAgICAgICAgICAgICAgY2hhaW5QYXRoOiAnLzExLzE1NScsXG4gICAgICAgICAgICAgICAgd2l0bmVzc1NjcmlwdDpcbiAgICAgICAgICAgICAgICAgICc1MjIxMDIyMTlkMmFhODQxNzYzM2YwYmNlMzkxMTM3NGExNjA0YzFiNjQxNjFmODNhM2MyZWU0MDljMjdjNDIzNTVmMDhlMjEwMmM5NzM0OTIwZGM0ZGEwNmMyODlmZTY5MTcxZGZjZDc1ZTNiOWI0ZjE5MGQwY2JjM2Q1ZDBmZjNmNWZkZWVhYWUyMTAzY2NkNjhkN2ZhOGRjMGQwMmRkNDVkYWQxNjU1NTdhNDg1ODJlZGE0NDM1ZmFlNzM3N2IzYzMxZTA4YWQwNjVjOTUzYWUnLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICBub2NrKGV4cGxvcmVyVXJsKS5nZXQoYC90eC8ke3BhcmVudFR4SWR9L2hleGApLnJlcGx5KDIwMCwgZml4dHVyZXNbcGFyZW50VHhJZF0pO1xuXG4gICAgICAgIG5vY2soYmdVcmwpXG4gICAgICAgICAgLnBvc3QoJy9hcGkvdjEvdHgvc2VuZCcsIChib2R5KSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gIWJvZHkuaWdub3JlTWF4RmVlUmF0ZTtcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5yZXBseSgyMDAsIGZ1bmN0aW9uIChfLCBib2R5KSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICB0cmFuc2FjdGlvbjogKGJvZHkgYXMgYW55KS50eCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgY2hpbGRUeCA9IGF3YWl0IHdhbGxldC5hY2NlbGVyYXRlVHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHRyYW5zYWN0aW9uSUQ6IHBhcmVudFR4SWQsXG4gICAgICAgICAgd2FsbGV0UGFzc3BocmFzZTogVGVzdEJpdEdvLlRFU1RfV0FMTEVUMV9QQVNTQ09ERSxcbiAgICAgICAgICBmZWVSYXRlLFxuICAgICAgICB9KTtcblxuICAgICAgICBzaG91bGQuZXhpc3QoY2hpbGRUeCk7XG4gICAgICAgIGNoaWxkVHguc2hvdWxkLmhhdmUucHJvcGVydHkoJ3N0YXR1cycsICdhY2NlcHRlZCcpO1xuICAgICAgICBjaGlsZFR4LnNob3VsZC5oYXZlLnByb3BlcnR5KCd0eCcpO1xuXG4gICAgICAgIC8vIGFzc2VydCB0aGUgZm9sbG93aW5nOlxuICAgICAgICAvLyAwKSBUaGUgY2hpbGQgdHggaGFzIGV4YWN0bHkgdGhyZWUgaW5wdXRzXG4gICAgICAgIC8vIDEpIFRoZSBwYXJlbnQgdHggb3V0cHV0IGlzIGFuIGlucHV0XG4gICAgICAgIC8vIDIpIFRoZSBjaGlsZCB0eCBoYXMgZXhhY3RseSBvbmUgb3V0cHV0XG4gICAgICAgIC8vIDMpIFRoZSBjaGlsZCB0eCBvdXRwdXQgbWVldHMgdGhlIG1pbmltdW0gY2hhbmdlIHRocmVzaG9sZFxuICAgICAgICBjb25zdCBkZWNvZGVkQ2hpbGQgPSB1dHhvbGliLmJpdGdvLmNyZWF0ZVRyYW5zYWN0aW9uRnJvbUhleChjaGlsZFR4LnR4LCB1dHhvbGliLm5ldHdvcmtzLmJpdGNvaW4pO1xuICAgICAgICBkZWNvZGVkQ2hpbGQuaW5zLmxlbmd0aC5zaG91bGQuZXF1YWwoMyk7XG4gICAgICAgIGRlY29kZWRDaGlsZC5vdXRzLmxlbmd0aC5zaG91bGQuZXF1YWwoMSk7XG5cbiAgICAgICAgbGV0IGlucHV0RnJvbVBhcmVudDogYW55ID0gdW5kZWZpbmVkO1xuICAgICAgICBjb25zdCBhZGRpdGlvbmFsSW5wdXRzOiBhbnlbXSA9IFtdO1xuXG4gICAgICAgIF8uZm9yRWFjaChkZWNvZGVkQ2hpbGQuaW5zLCAoaW5wdXQpID0+IHtcbiAgICAgICAgICBpbnB1dC5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnaGFzaCcpO1xuICAgICAgICAgIGlucHV0LnNob3VsZC5oYXZlLnByb3BlcnR5KCdpbmRleCcpO1xuXG4gICAgICAgICAgY29uc3QgaW5wdXRIYXNoID0gaW5wdXRQYXJlbnRUeElkKGlucHV0KTtcblxuICAgICAgICAgIGlmIChpbnB1dEhhc2ggPT09IHBhcmVudFR4SWQpIHtcbiAgICAgICAgICAgIGlucHV0RnJvbVBhcmVudCA9IGlucHV0O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhZGRpdGlvbmFsSW5wdXRzLnB1c2goaW5wdXQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgc2hvdWxkLmV4aXN0KGlucHV0RnJvbVBhcmVudCk7XG4gICAgICAgIGNvbnN0IGlucHV0RnJvbVBhcmVudEhhc2ggPSBpbnB1dFBhcmVudFR4SWQoaW5wdXRGcm9tUGFyZW50KTtcbiAgICAgICAgaW5wdXRGcm9tUGFyZW50SGFzaC5zaG91bGQuZXF1YWwocGFyZW50VHhJZCk7XG4gICAgICAgIGlucHV0RnJvbVBhcmVudC5pbmRleC5zaG91bGQuZXF1YWwoMCk7XG5cbiAgICAgICAgYWRkaXRpb25hbElucHV0cy5sZW5ndGguc2hvdWxkLmVxdWFsKDIpO1xuXG4gICAgICAgIGNvbnN0IGNoaWxkT3V0cHV0ID0gZGVjb2RlZENoaWxkLm91dHNbMF07XG4gICAgICAgIGNoaWxkT3V0cHV0LnNob3VsZC5oYXZlLnByb3BlcnR5KCd2YWx1ZScpO1xuICAgICAgICBjaGlsZE91dHB1dC52YWx1ZS5zaG91bGQuYmUuYWJvdmUobWluQ2hhbmdlU2l6ZSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ2NvcnJlY3RseSB1c2VzIHRoZSBpZ25vcmVNYXhGZWVSYXRlIHBhcmFtZXRlciBvbmx5IHdoZW4gbmVjZXNzYXJ5JywgYXN5bmMgKCkgPT4ge1xuICAgICAgICBwYXJlbnRUeElkID0gJzc1Y2ZjNWE3YjIxNGM0YjczYzkyYzdiMDI2MDhjZGU3MGIyMjY3NjdhOTU3NmY4NGMwNDQwN2U0M2ZkMzg1YmQnO1xuICAgICAgICBub2NrKGJnVXJsKVxuICAgICAgICAgIC5nZXQoYC9hcGkvdjEvd2FsbGV0LyR7d2FsbGV0LmlkKCl9L3R4LyR7cGFyZW50VHhJZH1gKVxuICAgICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAgIGZlZTogNDM0LFxuICAgICAgICAgICAgb3V0cHV0czogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdm91dDogMCxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMTAzNDg1MDAsXG4gICAgICAgICAgICAgICAgaXNNaW5lOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNoYWluOiAwLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdm91dDogMSxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMTAwMDAsXG4gICAgICAgICAgICAgICAgaXNNaW5lOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNoYWluOiAxMSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgbm9jayhiZ1VybClcbiAgICAgICAgICAuZ2V0KGAvYXBpL3YxL3dhbGxldC8ke3dhbGxldC5pZCgpfS91bnNwZW50c2ApXG4gICAgICAgICAgLnF1ZXJ5KHRydWUpXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgdW5zcGVudHM6IFtcbiAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHR4X2hhc2g6IHBhcmVudFR4SWQsXG4gICAgICAgICAgICAgICAgdHhfb3V0cHV0X246IDAsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDEwMzQ4NTAwLFxuICAgICAgICAgICAgICAgIHJlZGVlbVNjcmlwdDogJzAwMjBmN2I1OGQ0NTUzNTFiN2I4ZGRkN2M4OTg2ZDk4MjQ0ZjZhOTVmMDc0NjcyMDA5MTUzNzMyM2I5Njc4MDBmNzQ0JyxcbiAgICAgICAgICAgICAgICBjaGFpblBhdGg6ICcvMTEvMTYwJyxcbiAgICAgICAgICAgICAgICB3aXRuZXNzU2NyaXB0OlxuICAgICAgICAgICAgICAgICAgJzUyMjEwMjdmMGI0NWJiNDE1NWVhNTMyZTNiNDMxMmZlMGJlODAxNjZmMjk3ZDFlMDc1M2QyZDRhOTExOGMwNzNhZDY1MTQyMTAzMTBhYTlkNjhjOTg4MzE2MjVmMzI5Yjc4MjZiNmMzZTNiNTNlMTY3MzZiMTk5NGI4OTAyNDQyYmRjZDY2NTNkMTIxMDI2ZTBjYTQxNGYyNDg4YjBhYjU3MmI5OWUwYWU1NDQyOTExYWI0ZTA4MjFiMjcwOWQ4ODUxNzVhNTI3ZmQ1NTJiNTNhZScsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgIG5vY2soZXhwbG9yZXJVcmwpLmdldChgL3R4LyR7cGFyZW50VHhJZH0vaGV4YCkucmVwbHkoMjAwLCBmaXh0dXJlc1twYXJlbnRUeElkXSk7XG5cbiAgICAgICAgbm9jayhiZ1VybClcbiAgICAgICAgICAucG9zdCgnL2FwaS92MS90eC9zZW5kJywgKGJvZHkpID0+IHtcbiAgICAgICAgICAgIC8vIGlnbm9yZSBtYXggZmVlIHJhdGUgbXVzdCBiZSBzZXQgZm9yIHRoaXMgdGVzdFxuICAgICAgICAgICAgcmV0dXJuIGJvZHkuaWdub3JlTWF4RmVlUmF0ZTtcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5yZXBseSgyMDApO1xuXG4gICAgICAgIC8vIG1vbmtleSBwYXRjaCB0aGUgYml0Z28gZ2V0Q29uc3RhbnRzKCkgZnVuY3Rpb25cbiAgICAgICAgY29uc3Qgb2xkR2V0Q29uc3RhbnRzID0gKGJpdGdvIGFzIGFueSkuX19wcm90b19fLmdldENvbnN0YW50cztcbiAgICAgICAgKGJpdGdvIGFzIGFueSkuX19wcm90b19fLmdldENvbnN0YW50cyA9ICgpID0+ICh7XG4gICAgICAgICAgLy8gY2hpbGQgZmVlIHJhdGUgaW4gdGhpcyB0ZXN0IGlzIDMxMzc4IHNhdC9rYlxuICAgICAgICAgIC8vIHNvIHNldCB0aGUgbWF4IGZlZSByYXRlIGp1c3QgYmVsb3cgdGhhdCBsaW1pdCxcbiAgICAgICAgICAvLyBidXQgYWJvdmUgdGhlIGNvbWJpbmVkIGZlZSByYXRlIG9mIDIwMDAwXG4gICAgICAgICAgbWF4RmVlUmF0ZTogMzAwMDAsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGF3YWl0IHdhbGxldC5hY2NlbGVyYXRlVHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHRyYW5zYWN0aW9uSUQ6IHBhcmVudFR4SWQsXG4gICAgICAgICAgZmVlUmF0ZSxcbiAgICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiBUZXN0Qml0R28uVEVTVF9XQUxMRVQxX1BBU1NDT0RFLFxuICAgICAgICB9KTtcbiAgICAgICAgbm9jay5wZW5kaW5nTW9ja3MoKS5zaG91bGQuYmUuZW1wdHkoKTtcblxuICAgICAgICAoYml0Z28gYXMgYW55KS5fX3Byb3RvX18uZ2V0Q29uc3RhbnRzID0gb2xkR2V0Q29uc3RhbnRzO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=
|