@bitgo/sdk-api 1.3.0-dev.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +170 -0
- package/dist/package.json +20 -9
- package/dist/src/api.d.ts.map +1 -1
- package/dist/src/api.js +5 -5
- package/dist/src/bitgoAPI.d.ts +227 -6
- package/dist/src/bitgoAPI.d.ts.map +1 -1
- package/dist/src/bitgoAPI.js +612 -17
- package/dist/src/types.d.ts +110 -9
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +2 -14
- package/dist/src/util.d.ts +0 -8
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +2 -21
- package/dist/src/v1/blockchain.d.ts +5 -0
- package/dist/src/v1/blockchain.d.ts.map +1 -0
- package/dist/src/v1/blockchain.js +114 -0
- package/dist/src/v1/keychains.d.ts +5 -0
- package/dist/src/v1/keychains.d.ts.map +1 -0
- package/dist/src/v1/keychains.js +315 -0
- package/dist/src/v1/markets.d.ts +5 -0
- package/dist/src/v1/markets.d.ts.map +1 -0
- package/dist/src/v1/markets.js +63 -0
- package/dist/src/v1/pendingapproval.d.ts +6 -0
- package/dist/src/v1/pendingapproval.d.ts.map +1 -0
- package/dist/src/v1/pendingapproval.js +322 -0
- package/dist/src/v1/pendingapprovals.d.ts +6 -0
- package/dist/src/v1/pendingapprovals.d.ts.map +1 -0
- package/dist/src/v1/pendingapprovals.js +68 -0
- package/dist/src/v1/transactionBuilder.d.ts +5 -0
- package/dist/src/v1/transactionBuilder.d.ts.map +1 -0
- package/dist/src/v1/transactionBuilder.js +889 -0
- package/dist/src/v1/travelRule.d.ts +5 -0
- package/dist/src/v1/travelRule.d.ts.map +1 -0
- package/dist/src/v1/travelRule.js +257 -0
- package/dist/src/v1/wallet.d.ts +6 -0
- package/dist/src/v1/wallet.d.ts.map +1 -0
- package/dist/src/v1/wallet.js +2095 -0
- package/dist/src/v1/wallets.d.ts +5 -0
- package/dist/src/v1/wallets.d.ts.map +1 -0
- package/dist/src/v1/wallets.js +472 -0
- package/dist/web/main.js +1 -1
- package/dist/web/main.js.LICENSE.txt +41 -0
- package/package.json +20 -9
- package/dist/tsconfig.tsbuildinfo +0 -7006
|
@@ -0,0 +1,889 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @hidden
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
/**
|
|
7
|
+
*/
|
|
8
|
+
//
|
|
9
|
+
// TransactionBuilder
|
|
10
|
+
// A utility for building and signing transactions
|
|
11
|
+
//
|
|
12
|
+
// Copyright 2014, BitGo, Inc. All Rights Reserved.
|
|
13
|
+
//
|
|
14
|
+
const utxo_lib_1 = require("@bitgo/utxo-lib");
|
|
15
|
+
const Bluebird = require("bluebird");
|
|
16
|
+
const utxolib = require("@bitgo/utxo-lib");
|
|
17
|
+
const _ = require("lodash");
|
|
18
|
+
const unspents_1 = require("@bitgo/unspents");
|
|
19
|
+
const debugLib = require("debug");
|
|
20
|
+
const debug = debugLib('bitgo:v1:txb');
|
|
21
|
+
const sdk_core_1 = require("@bitgo/sdk-core");
|
|
22
|
+
//
|
|
23
|
+
// TransactionBuilder
|
|
24
|
+
// @params:
|
|
25
|
+
// wallet: a wallet object to send from
|
|
26
|
+
// recipients: array of recipient objects and the amount to send to each e.g. [{address: '38BKDNZbPcLogvVbcx2ekJ9E6Vv94DqDqw', amount: 1500}, {address: '36eL8yQqCn1HMRmVFFo49t2PJ3pai8wQam', amount: 2000}]
|
|
27
|
+
// fee: the fee to use with this transaction. if not provided, a default, minimum fee will be used.
|
|
28
|
+
// feeRate: the amount of fee per kilobyte - optional - specify either fee, feeRate, or feeTxConfirmTarget but not more than one
|
|
29
|
+
// feeTxConfirmTarget: calculate the fees per kilobyte such that the transaction will be confirmed in this number of blocks
|
|
30
|
+
// maxFeeRate: The maximum fee per kb to use in satoshis, for safety purposes when using dynamic fees
|
|
31
|
+
// minConfirms: the minimum confirmations an output must have before spending
|
|
32
|
+
// forceChangeAtEnd: force the change address to be the last output
|
|
33
|
+
// changeAddress: specify the change address rather than generate a new one
|
|
34
|
+
// noSplitChange: set to true to disable automatic change splitting for purposes of unspent management
|
|
35
|
+
// targetWalletUnspents: specify a number of target unspents to maintain in the wallet (currently defaulted to 8 by the server)
|
|
36
|
+
// validate: extra verification of the change addresses, which is always done server-side and is redundant client-side (defaults true)
|
|
37
|
+
// minUnspentSize: The minimum size in satoshis of unspent to use (to prevent spending unspents worth less than fee added). Defaults to 0.
|
|
38
|
+
// feeSingleKeySourceAddress: Use this single key address to pay fees
|
|
39
|
+
// feeSingleKeyWIF: Use the address based on this private key to pay fees
|
|
40
|
+
// unspentsFetchParams: Extra parameters to use for fetching unspents for this transaction
|
|
41
|
+
exports.createTransaction = function (params) {
|
|
42
|
+
const minConfirms = params.minConfirms || 0;
|
|
43
|
+
const validate = params.validate === undefined ? true : params.validate;
|
|
44
|
+
let recipients = [];
|
|
45
|
+
let opReturns = [];
|
|
46
|
+
let extraChangeAmounts = [];
|
|
47
|
+
let estTxSize;
|
|
48
|
+
let travelInfos;
|
|
49
|
+
// Sanity check the arguments passed in
|
|
50
|
+
if (!_.isObject(params.wallet) ||
|
|
51
|
+
(params.fee && !_.isNumber(params.fee)) ||
|
|
52
|
+
(params.feeRate && !_.isNumber(params.feeRate)) ||
|
|
53
|
+
!_.isInteger(minConfirms) ||
|
|
54
|
+
(params.forceChangeAtEnd && !_.isBoolean(params.forceChangeAtEnd)) ||
|
|
55
|
+
(params.changeAddress && !_.isString(params.changeAddress)) ||
|
|
56
|
+
(params.noSplitChange && !_.isBoolean(params.noSplitChange)) ||
|
|
57
|
+
(params.targetWalletUnspents && !_.isInteger(params.targetWalletUnspents)) ||
|
|
58
|
+
(validate && !_.isBoolean(validate)) ||
|
|
59
|
+
(params.enforceMinConfirmsForChange && !_.isBoolean(params.enforceMinConfirmsForChange)) ||
|
|
60
|
+
(params.minUnspentSize && !_.isNumber(params.minUnspentSize)) ||
|
|
61
|
+
(params.maxFeeRate && !_.isNumber(params.maxFeeRate)) ||
|
|
62
|
+
// this should be an array and its length must be at least 1
|
|
63
|
+
(params.unspents && (!Array.isArray(params.unspents) || params.unspents.length < 1)) ||
|
|
64
|
+
(params.feeTxConfirmTarget && !_.isInteger(params.feeTxConfirmTarget)) ||
|
|
65
|
+
(params.instant && !_.isBoolean(params.instant)) ||
|
|
66
|
+
(params.bitgoFee && !_.isObject(params.bitgoFee)) ||
|
|
67
|
+
(params.unspentsFetchParams && !_.isObject(params.unspentsFetchParams))) {
|
|
68
|
+
throw new Error('invalid argument');
|
|
69
|
+
}
|
|
70
|
+
const bitgo = params.wallet.bitgo;
|
|
71
|
+
const constants = bitgo.getConstants();
|
|
72
|
+
const network = sdk_core_1.getNetwork(sdk_core_1.common.Environments[bitgo.getEnv()].network);
|
|
73
|
+
// The user can specify a seperate, single-key wallet for the purposes of paying miner's fees
|
|
74
|
+
// When creating a transaction this can be specified as an input address or the private key in WIF
|
|
75
|
+
let feeSingleKeySourceAddress;
|
|
76
|
+
let feeSingleKeyInputAmount = 0;
|
|
77
|
+
if (params.feeSingleKeySourceAddress) {
|
|
78
|
+
try {
|
|
79
|
+
utxolib.address.fromBase58Check(params.feeSingleKeySourceAddress, network);
|
|
80
|
+
feeSingleKeySourceAddress = params.feeSingleKeySourceAddress;
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
throw new Error('invalid bitcoin address: ' + params.feeSingleKeySourceAddress);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (params.feeSingleKeyWIF) {
|
|
87
|
+
const feeSingleKey = utxolib.ECPair.fromWIF(params.feeSingleKeyWIF, network);
|
|
88
|
+
feeSingleKeySourceAddress = sdk_core_1.getAddressP2PKH(feeSingleKey);
|
|
89
|
+
// If the user specifies both, check to make sure the feeSingleKeySourceAddress corresponds to the address of feeSingleKeyWIF
|
|
90
|
+
if (params.feeSingleKeySourceAddress && params.feeSingleKeySourceAddress !== feeSingleKeySourceAddress) {
|
|
91
|
+
throw new Error('feeSingleKeySourceAddress: ' +
|
|
92
|
+
params.feeSingleKeySourceAddress +
|
|
93
|
+
' did not correspond to address of feeSingleKeyWIF: ' +
|
|
94
|
+
feeSingleKeySourceAddress);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (!_.isObject(params.recipients)) {
|
|
98
|
+
throw new Error('recipients must be array of { address: abc, amount: 100000 } objects');
|
|
99
|
+
}
|
|
100
|
+
let feeParamsDefined = 0;
|
|
101
|
+
if (!_.isUndefined(params.fee)) {
|
|
102
|
+
feeParamsDefined++;
|
|
103
|
+
}
|
|
104
|
+
if (!_.isUndefined(params.feeRate)) {
|
|
105
|
+
feeParamsDefined++;
|
|
106
|
+
}
|
|
107
|
+
if (!_.isUndefined(params.feeTxConfirmTarget)) {
|
|
108
|
+
feeParamsDefined++;
|
|
109
|
+
}
|
|
110
|
+
if (feeParamsDefined > 1) {
|
|
111
|
+
throw new Error('cannot specify more than one of fee, feeRate and feeTxConfirmTarget');
|
|
112
|
+
}
|
|
113
|
+
if (_.isUndefined(params.maxFeeRate)) {
|
|
114
|
+
params.maxFeeRate = constants.maxFeeRate;
|
|
115
|
+
}
|
|
116
|
+
// Convert the old format of params.recipients (dictionary of address:amount) to new format: { destinationAddress, amount }
|
|
117
|
+
if (!(params.recipients instanceof Array)) {
|
|
118
|
+
recipients = [];
|
|
119
|
+
Object.keys(params.recipients).forEach(function (destinationAddress) {
|
|
120
|
+
const amount = params.recipients[destinationAddress];
|
|
121
|
+
recipients.push({ address: destinationAddress, amount: amount });
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
recipients = params.recipients;
|
|
126
|
+
}
|
|
127
|
+
if (params.opReturns) {
|
|
128
|
+
if (!(params.opReturns instanceof Array)) {
|
|
129
|
+
opReturns = [];
|
|
130
|
+
Object.keys(params.opReturns).forEach(function (message) {
|
|
131
|
+
const amount = params.opReturns[message];
|
|
132
|
+
opReturns.push({ message, amount });
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
opReturns = params.opReturns;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (recipients.length === 0 && opReturns.length === 0) {
|
|
140
|
+
throw new Error('must have at least one recipient');
|
|
141
|
+
}
|
|
142
|
+
let fee = params.fee;
|
|
143
|
+
let feeRate = params.feeRate;
|
|
144
|
+
// Flag indicating whether this class will compute the fee
|
|
145
|
+
const shouldComputeBestFee = _.isUndefined(fee);
|
|
146
|
+
let totalOutputAmount = 0;
|
|
147
|
+
recipients.forEach(function (recipient) {
|
|
148
|
+
if (_.isString(recipient.address)) {
|
|
149
|
+
try {
|
|
150
|
+
utxolib.address.fromBase58Check(recipient.address, network);
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
throw new Error('invalid bitcoin address: ' + recipient.address);
|
|
154
|
+
}
|
|
155
|
+
if (!!recipient.script) {
|
|
156
|
+
// A script was provided as well - validate that the address corresponds to that
|
|
157
|
+
if (utxolib.address.toOutputScript(recipient.address, network).toString('hex') !== recipient.script) {
|
|
158
|
+
throw new Error('both script and address provided but they did not match: ' + recipient.address + ' ' + recipient.script);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (!_.isInteger(recipient.amount) || recipient.amount < 0) {
|
|
163
|
+
throw new Error('invalid amount for ' + recipient.address + ': ' + recipient.amount);
|
|
164
|
+
}
|
|
165
|
+
totalOutputAmount += recipient.amount;
|
|
166
|
+
});
|
|
167
|
+
opReturns.forEach(function (opReturn) {
|
|
168
|
+
totalOutputAmount += opReturn.amount;
|
|
169
|
+
});
|
|
170
|
+
let bitgoFeeInfo = params.bitgoFee;
|
|
171
|
+
if (bitgoFeeInfo && (!_.isInteger(bitgoFeeInfo.amount) || !_.isString(bitgoFeeInfo.address))) {
|
|
172
|
+
throw new Error('invalid bitgoFeeInfo');
|
|
173
|
+
}
|
|
174
|
+
// The total amount needed for this transaction.
|
|
175
|
+
let totalAmount = totalOutputAmount + (fee || 0);
|
|
176
|
+
// The list of unspent transactions being used in this transaction.
|
|
177
|
+
let unspents;
|
|
178
|
+
// the total number of unspents on this wallet
|
|
179
|
+
let totalUnspentsCount;
|
|
180
|
+
// the number of unspents we fetched from the server, before filtering
|
|
181
|
+
let fetchedUnspentsCount;
|
|
182
|
+
// The list of unspent transactions being used with zero-confirmations
|
|
183
|
+
let zeroConfUnspentTxIds;
|
|
184
|
+
// The sum of the input values for this transaction.
|
|
185
|
+
let inputAmount;
|
|
186
|
+
let changeOutputs = [];
|
|
187
|
+
// The transaction.
|
|
188
|
+
let transaction = utxolib.bitgo.createTransactionBuilderForNetwork(network);
|
|
189
|
+
const getBitGoFee = function () {
|
|
190
|
+
return Bluebird.try(function () {
|
|
191
|
+
if (bitgoFeeInfo) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
return params.wallet.getBitGoFee({ amount: totalOutputAmount, instant: params.instant }).then(function (result) {
|
|
195
|
+
if (result && result.fee > 0) {
|
|
196
|
+
bitgoFeeInfo = {
|
|
197
|
+
amount: result.fee,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}).then(function () {
|
|
202
|
+
if (bitgoFeeInfo && bitgoFeeInfo.amount > 0) {
|
|
203
|
+
totalAmount += bitgoFeeInfo.amount;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
const getBitGoFeeAddress = function () {
|
|
208
|
+
return Bluebird.try(function () {
|
|
209
|
+
// If we don't have bitgoFeeInfo, or address is already set, don't get a new one
|
|
210
|
+
if (!bitgoFeeInfo || bitgoFeeInfo.address) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
return bitgo.getBitGoFeeAddress().then(function (result) {
|
|
214
|
+
bitgoFeeInfo.address = result.address;
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
// Get a dynamic fee estimate from the BitGo server if feeTxConfirmTarget
|
|
219
|
+
// is specified or if no fee-related params are specified
|
|
220
|
+
const getDynamicFeeRateEstimate = function () {
|
|
221
|
+
if (params.feeTxConfirmTarget || !feeParamsDefined) {
|
|
222
|
+
return bitgo
|
|
223
|
+
.estimateFee({
|
|
224
|
+
numBlocks: params.feeTxConfirmTarget,
|
|
225
|
+
maxFee: params.maxFeeRate,
|
|
226
|
+
inputs: zeroConfUnspentTxIds,
|
|
227
|
+
txSize: estTxSize,
|
|
228
|
+
cpfpAware: true,
|
|
229
|
+
})
|
|
230
|
+
.then(function (result) {
|
|
231
|
+
const estimatedFeeRate = result.cpfpFeePerKb;
|
|
232
|
+
const minimum = params.instant
|
|
233
|
+
? Math.max(constants.minFeeRate, constants.minInstantFeeRate)
|
|
234
|
+
: constants.minFeeRate;
|
|
235
|
+
// 5 satoshis per byte
|
|
236
|
+
// it is worth noting that the padding only applies when the threshold is crossed, but not when the delta is less than the padding
|
|
237
|
+
const padding = 5000;
|
|
238
|
+
if (estimatedFeeRate < minimum) {
|
|
239
|
+
console.log(new Date() +
|
|
240
|
+
': Error when estimating fee for send from ' +
|
|
241
|
+
params.wallet.id() +
|
|
242
|
+
', it was too low - ' +
|
|
243
|
+
estimatedFeeRate);
|
|
244
|
+
feeRate = minimum + padding;
|
|
245
|
+
}
|
|
246
|
+
else if (estimatedFeeRate > params.maxFeeRate) {
|
|
247
|
+
feeRate = params.maxFeeRate - padding;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
feeRate = estimatedFeeRate;
|
|
251
|
+
}
|
|
252
|
+
return feeRate;
|
|
253
|
+
})
|
|
254
|
+
.catch(function (e) {
|
|
255
|
+
// sanity check failed on tx size
|
|
256
|
+
if (_.includes(e.message, 'invalid txSize')) {
|
|
257
|
+
return Bluebird.reject(e);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
// couldn't estimate the fee, proceed using the default
|
|
261
|
+
feeRate = constants.fallbackFeeRate;
|
|
262
|
+
console.log('Error estimating fee for send from ' + params.wallet.id() + ': ' + e.message);
|
|
263
|
+
return Bluebird.resolve();
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
// Get the unspents for the sending wallet.
|
|
269
|
+
const getUnspents = function () {
|
|
270
|
+
if (params.unspents) {
|
|
271
|
+
// we just wanna use custom unspents
|
|
272
|
+
unspents = params.unspents;
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
// Get enough unspents for the requested amount
|
|
276
|
+
const options = _.merge({}, params.unspentsFetchParams || {}, {
|
|
277
|
+
target: totalAmount,
|
|
278
|
+
minSize: params.minUnspentSize || 0,
|
|
279
|
+
instant: params.instant,
|
|
280
|
+
targetWalletUnspents: params.targetWalletUnspents,
|
|
281
|
+
});
|
|
282
|
+
if (params.instant) {
|
|
283
|
+
options.instant = params.instant; // insist on instant unspents only
|
|
284
|
+
}
|
|
285
|
+
return params.wallet.unspentsPaged(options).then(function (results) {
|
|
286
|
+
totalUnspentsCount = results.total;
|
|
287
|
+
fetchedUnspentsCount = results.count;
|
|
288
|
+
unspents = results.unspents.filter(function (u) {
|
|
289
|
+
const confirms = u.confirmations || 0;
|
|
290
|
+
if (!params.enforceMinConfirmsForChange && u.isChange) {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
return confirms >= minConfirms;
|
|
294
|
+
});
|
|
295
|
+
// abort early if there's no viable unspents, because it won't be possible to create the txn later
|
|
296
|
+
if (unspents.length === 0) {
|
|
297
|
+
throw Error('0 unspents available for transaction creation');
|
|
298
|
+
}
|
|
299
|
+
// create array of unconfirmed unspent ID strings of the form "txHash:outputIndex"
|
|
300
|
+
zeroConfUnspentTxIds = _(results.unspents)
|
|
301
|
+
.filter(function (u) {
|
|
302
|
+
return !u.confirmations;
|
|
303
|
+
})
|
|
304
|
+
.map(function (u) {
|
|
305
|
+
return u.tx_hash + ':' + u.tx_output_n;
|
|
306
|
+
})
|
|
307
|
+
.value();
|
|
308
|
+
if (_.isEmpty(zeroConfUnspentTxIds)) {
|
|
309
|
+
// we don't want to pass an empty array of inputs to the server, because it assumes if the
|
|
310
|
+
// inputs arguments exists, it contains values
|
|
311
|
+
zeroConfUnspentTxIds = undefined;
|
|
312
|
+
}
|
|
313
|
+
// For backwards compatibility, respect the old splitChangeSize=0 parameter
|
|
314
|
+
if (!params.noSplitChange && params.splitChangeSize !== 0) {
|
|
315
|
+
extraChangeAmounts = results.extraChangeAmounts || [];
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
};
|
|
319
|
+
// Get the unspents for the single key fee address
|
|
320
|
+
let feeSingleKeyUnspents = [];
|
|
321
|
+
const getUnspentsForSingleKey = function () {
|
|
322
|
+
if (feeSingleKeySourceAddress) {
|
|
323
|
+
let feeTarget = 0.01e8;
|
|
324
|
+
if (params.instant) {
|
|
325
|
+
feeTarget += totalAmount * 0.001;
|
|
326
|
+
}
|
|
327
|
+
return bitgo
|
|
328
|
+
.get(bitgo.url('/address/' + feeSingleKeySourceAddress + '/unspents?target=' + feeTarget))
|
|
329
|
+
.then(function (response) {
|
|
330
|
+
if (response.body.total <= 0) {
|
|
331
|
+
throw new Error('No unspents available in single key fee source');
|
|
332
|
+
}
|
|
333
|
+
feeSingleKeyUnspents = response.body.unspents;
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
let minerFeeInfo = {};
|
|
338
|
+
let txInfo = {};
|
|
339
|
+
// Iterate unspents, sum the inputs, and save _inputs with the total
|
|
340
|
+
// input amount and final list of inputs to use with the transaction.
|
|
341
|
+
let feeSingleKeyUnspentsUsed = [];
|
|
342
|
+
const collectInputs = function () {
|
|
343
|
+
if (!unspents.length) {
|
|
344
|
+
throw new Error('no unspents available on wallet');
|
|
345
|
+
}
|
|
346
|
+
inputAmount = 0;
|
|
347
|
+
// Calculate the cost of spending a single input, i.e. the smallest economical unspent value
|
|
348
|
+
return Bluebird.try(function () {
|
|
349
|
+
if (_.isNumber(params.feeRate) || _.isNumber(params.originalFeeRate)) {
|
|
350
|
+
return !_.isUndefined(params.feeRate) ? params.feeRate : params.originalFeeRate;
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
return bitgo
|
|
354
|
+
.estimateFee({
|
|
355
|
+
numBlocks: params.feeTxConfirmTarget,
|
|
356
|
+
maxFee: params.maxFeeRate,
|
|
357
|
+
})
|
|
358
|
+
.then(function (feeRateEstimate) {
|
|
359
|
+
return feeRateEstimate.feePerKb;
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
})
|
|
363
|
+
.then(function (feeRate) {
|
|
364
|
+
// Don't spend inputs that cannot pay for their own cost.
|
|
365
|
+
let minInputValue = 0;
|
|
366
|
+
if (_.isInteger(params.minUnspentSize)) {
|
|
367
|
+
minInputValue = params.minUnspentSize;
|
|
368
|
+
}
|
|
369
|
+
let prunedUnspentCount = 0;
|
|
370
|
+
const originalUnspentCount = unspents.length;
|
|
371
|
+
unspents = _.filter(unspents, function (unspent) {
|
|
372
|
+
const isSegwitInput = !!unspent.witnessScript;
|
|
373
|
+
const currentInputSize = isSegwitInput ? unspents_1.VirtualSizes.txP2shP2wshInputSize : unspents_1.VirtualSizes.txP2shInputSize;
|
|
374
|
+
const feeBasedMinInputValue = (feeRate * currentInputSize) / 1000;
|
|
375
|
+
const currentMinInputValue = Math.max(minInputValue, feeBasedMinInputValue);
|
|
376
|
+
if (currentMinInputValue > unspent.value) {
|
|
377
|
+
// pruning unspent
|
|
378
|
+
const pruneDetails = {
|
|
379
|
+
generalMinInputValue: minInputValue,
|
|
380
|
+
feeBasedMinInputValue,
|
|
381
|
+
currentMinInputValue,
|
|
382
|
+
feeRate,
|
|
383
|
+
inputSize: currentInputSize,
|
|
384
|
+
unspent: unspent,
|
|
385
|
+
};
|
|
386
|
+
console.log(`pruning unspent: ${JSON.stringify(pruneDetails, null, 4)}`);
|
|
387
|
+
prunedUnspentCount++;
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
return true;
|
|
391
|
+
});
|
|
392
|
+
if (prunedUnspentCount > 0) {
|
|
393
|
+
console.log(`pruned ${prunedUnspentCount} out of ${originalUnspentCount} unspents`);
|
|
394
|
+
}
|
|
395
|
+
if (unspents.length === 0) {
|
|
396
|
+
throw new Error('insufficient funds');
|
|
397
|
+
}
|
|
398
|
+
let segwitInputCount = 0;
|
|
399
|
+
unspents.every(function (unspent) {
|
|
400
|
+
if (unspent.witnessScript) {
|
|
401
|
+
segwitInputCount++;
|
|
402
|
+
}
|
|
403
|
+
inputAmount += unspent.value;
|
|
404
|
+
transaction.addInput(unspent.tx_hash, unspent.tx_output_n, 0xffffffff);
|
|
405
|
+
return inputAmount < (feeSingleKeySourceAddress ? totalOutputAmount : totalAmount);
|
|
406
|
+
});
|
|
407
|
+
// if paying fees from an external single key wallet, add the inputs
|
|
408
|
+
if (feeSingleKeySourceAddress) {
|
|
409
|
+
// collect the amount used in the fee inputs so we can get change later
|
|
410
|
+
feeSingleKeyInputAmount = 0;
|
|
411
|
+
feeSingleKeyUnspentsUsed = [];
|
|
412
|
+
feeSingleKeyUnspents.every(function (unspent) {
|
|
413
|
+
feeSingleKeyInputAmount += unspent.value;
|
|
414
|
+
inputAmount += unspent.value;
|
|
415
|
+
transaction.addInput(unspent.tx_hash, unspent.tx_output_n);
|
|
416
|
+
feeSingleKeyUnspentsUsed.push(unspent);
|
|
417
|
+
// use the fee wallet to pay miner fees and potentially instant fees
|
|
418
|
+
return feeSingleKeyInputAmount < fee + (bitgoFeeInfo ? bitgoFeeInfo.amount : 0);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
txInfo = {
|
|
422
|
+
nP2shInputs: transaction.tx.ins.length - (feeSingleKeySourceAddress ? 1 : 0) - segwitInputCount,
|
|
423
|
+
nP2shP2wshInputs: segwitInputCount,
|
|
424
|
+
nP2pkhInputs: feeSingleKeySourceAddress ? 1 : 0,
|
|
425
|
+
// add single key source address change
|
|
426
|
+
nOutputs: recipients.length +
|
|
427
|
+
1 + // recipients and change
|
|
428
|
+
extraChangeAmounts.length + // extra change splitting
|
|
429
|
+
(bitgoFeeInfo && bitgoFeeInfo.amount > 0 ? 1 : 0) + // add output for bitgo fee
|
|
430
|
+
(feeSingleKeySourceAddress ? 1 : 0),
|
|
431
|
+
};
|
|
432
|
+
estTxSize = estimateTransactionSize({
|
|
433
|
+
nP2shInputs: txInfo.nP2shInputs,
|
|
434
|
+
nP2shP2wshInputs: txInfo.nP2shP2wshInputs,
|
|
435
|
+
nP2pkhInputs: txInfo.nP2pkhInputs,
|
|
436
|
+
nOutputs: txInfo.nOutputs,
|
|
437
|
+
});
|
|
438
|
+
})
|
|
439
|
+
.then(getDynamicFeeRateEstimate)
|
|
440
|
+
.then(function () {
|
|
441
|
+
minerFeeInfo = exports.calculateMinerFeeInfo({
|
|
442
|
+
bitgo: params.wallet.bitgo,
|
|
443
|
+
feeRate: feeRate,
|
|
444
|
+
nP2shInputs: txInfo.nP2shInputs,
|
|
445
|
+
nP2shP2wshInputs: txInfo.nP2shP2wshInputs,
|
|
446
|
+
nP2pkhInputs: txInfo.nP2pkhInputs,
|
|
447
|
+
nOutputs: txInfo.nOutputs,
|
|
448
|
+
});
|
|
449
|
+
if (shouldComputeBestFee) {
|
|
450
|
+
const approximateFee = minerFeeInfo.fee;
|
|
451
|
+
const shouldRecurse = _.isUndefined(fee) || approximateFee > fee;
|
|
452
|
+
fee = approximateFee;
|
|
453
|
+
// Recompute totalAmount from scratch
|
|
454
|
+
totalAmount = fee + totalOutputAmount;
|
|
455
|
+
if (bitgoFeeInfo) {
|
|
456
|
+
totalAmount += bitgoFeeInfo.amount;
|
|
457
|
+
}
|
|
458
|
+
if (shouldRecurse) {
|
|
459
|
+
// if fee changed, re-collect inputs
|
|
460
|
+
inputAmount = 0;
|
|
461
|
+
transaction = utxolib.bitgo.createTransactionBuilderForNetwork(network);
|
|
462
|
+
return collectInputs();
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
const totalFee = fee + (bitgoFeeInfo ? bitgoFeeInfo.amount : 0);
|
|
466
|
+
if (feeSingleKeySourceAddress) {
|
|
467
|
+
const summedSingleKeyUnspents = _.sumBy(feeSingleKeyUnspents, 'value');
|
|
468
|
+
if (totalFee > summedSingleKeyUnspents) {
|
|
469
|
+
const err = new Error('Insufficient fee amount available in single key fee source: ' + summedSingleKeyUnspents);
|
|
470
|
+
err.result = {
|
|
471
|
+
fee: fee,
|
|
472
|
+
feeRate: feeRate,
|
|
473
|
+
estimatedSize: minerFeeInfo.size,
|
|
474
|
+
available: inputAmount,
|
|
475
|
+
bitgoFee: bitgoFeeInfo,
|
|
476
|
+
txInfo: txInfo,
|
|
477
|
+
};
|
|
478
|
+
return Bluebird.reject(err);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (inputAmount < (feeSingleKeySourceAddress ? totalOutputAmount : totalAmount)) {
|
|
482
|
+
// The unspents we're using for inputs do not have sufficient value on them to
|
|
483
|
+
// satisfy the user's requested spend amount. That may be because the wallet's balance
|
|
484
|
+
// is simply too low, or it might be that the wallet's balance is sufficient but
|
|
485
|
+
// we didn't fetch enough unspents. Too few unspents could result from the wallet
|
|
486
|
+
// having many small unspents and we hit our limit on the number of inputs we can use
|
|
487
|
+
// in a txn, or it might have been that the filters the user passed in (like minConfirms)
|
|
488
|
+
// disqualified too many of the unspents
|
|
489
|
+
let err;
|
|
490
|
+
if (totalUnspentsCount === fetchedUnspentsCount) {
|
|
491
|
+
// we fetched every unspent the wallet had, but it still wasn't enough
|
|
492
|
+
err = new Error('Insufficient funds');
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
// we weren't able to fetch all the unspents on the wallet
|
|
496
|
+
err = new Error(`Transaction size too large due to too many unspents. Can send only ${inputAmount} satoshis in this transaction`);
|
|
497
|
+
}
|
|
498
|
+
err.result = {
|
|
499
|
+
fee: fee,
|
|
500
|
+
feeRate: feeRate,
|
|
501
|
+
estimatedSize: minerFeeInfo.size,
|
|
502
|
+
available: inputAmount,
|
|
503
|
+
bitgoFee: bitgoFeeInfo,
|
|
504
|
+
txInfo: txInfo,
|
|
505
|
+
};
|
|
506
|
+
return Bluebird.reject(err);
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
};
|
|
510
|
+
// Add the outputs for this transaction.
|
|
511
|
+
const collectOutputs = function () {
|
|
512
|
+
if (minerFeeInfo.size >= 90000) {
|
|
513
|
+
throw new Error('transaction too large: estimated size ' + minerFeeInfo.size + ' bytes');
|
|
514
|
+
}
|
|
515
|
+
const outputs = [];
|
|
516
|
+
recipients.forEach(function (recipient) {
|
|
517
|
+
let script;
|
|
518
|
+
if (_.isString(recipient.address)) {
|
|
519
|
+
script = utxolib.address.toOutputScript(recipient.address, network);
|
|
520
|
+
}
|
|
521
|
+
else if (_.isObject(recipient.script)) {
|
|
522
|
+
script = recipient.script;
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
throw new Error('neither recipient address nor script was provided');
|
|
526
|
+
}
|
|
527
|
+
// validate travelInfo if it exists
|
|
528
|
+
let travelInfo;
|
|
529
|
+
if (!_.isEmpty(recipient.travelInfo)) {
|
|
530
|
+
travelInfo = recipient.travelInfo;
|
|
531
|
+
// Better to avoid trouble now, before tx is created
|
|
532
|
+
bitgo.travelRule().validateTravelInfo(travelInfo);
|
|
533
|
+
}
|
|
534
|
+
outputs.push({
|
|
535
|
+
script: script,
|
|
536
|
+
amount: recipient.amount,
|
|
537
|
+
travelInfo: travelInfo,
|
|
538
|
+
});
|
|
539
|
+
});
|
|
540
|
+
opReturns.forEach(function ({ message, amount }) {
|
|
541
|
+
const script = utxolib.script.fromASM('OP_RETURN ' + Buffer.from(message).toString('hex'));
|
|
542
|
+
outputs.push({ script, amount });
|
|
543
|
+
});
|
|
544
|
+
const getChangeOutputs = function (changeAmount) {
|
|
545
|
+
if (changeAmount < 0) {
|
|
546
|
+
throw new Error('negative change amount: ' + changeAmount);
|
|
547
|
+
}
|
|
548
|
+
const result = [];
|
|
549
|
+
// if we paid fees from a single key wallet, return the fee change first
|
|
550
|
+
if (feeSingleKeySourceAddress) {
|
|
551
|
+
const feeSingleKeyWalletChangeAmount = feeSingleKeyInputAmount - (fee + (bitgoFeeInfo ? bitgoFeeInfo.amount : 0));
|
|
552
|
+
if (feeSingleKeyWalletChangeAmount >= constants.minOutputSize) {
|
|
553
|
+
result.push({ address: feeSingleKeySourceAddress, amount: feeSingleKeyWalletChangeAmount });
|
|
554
|
+
changeAmount = changeAmount - feeSingleKeyWalletChangeAmount;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (changeAmount < constants.minOutputSize) {
|
|
558
|
+
// Give it to the miners
|
|
559
|
+
return result;
|
|
560
|
+
}
|
|
561
|
+
if (params.wallet.type() === 'safe') {
|
|
562
|
+
return params.wallet.addresses().then(function (response) {
|
|
563
|
+
result.push({ address: response.addresses[0].address, amount: changeAmount });
|
|
564
|
+
return result;
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
let extraChangeTotal = _.sum(extraChangeAmounts);
|
|
568
|
+
// Sanity check
|
|
569
|
+
if (extraChangeTotal > changeAmount) {
|
|
570
|
+
extraChangeAmounts = [];
|
|
571
|
+
extraChangeTotal = 0;
|
|
572
|
+
}
|
|
573
|
+
// copy and add remaining change amount
|
|
574
|
+
const allChangeAmounts = extraChangeAmounts.slice(0);
|
|
575
|
+
allChangeAmounts.push(changeAmount - extraChangeTotal);
|
|
576
|
+
// Recursive async func to add all change outputs
|
|
577
|
+
const addChangeOutputs = function () {
|
|
578
|
+
const thisAmount = allChangeAmounts.shift();
|
|
579
|
+
if (!thisAmount) {
|
|
580
|
+
return result;
|
|
581
|
+
}
|
|
582
|
+
return Bluebird.try(function () {
|
|
583
|
+
if (params.changeAddress) {
|
|
584
|
+
// If user passed a change address, use it for all outputs
|
|
585
|
+
return params.changeAddress;
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
// Otherwise create a new address per output, for privacy
|
|
589
|
+
// determine if segwit or not
|
|
590
|
+
const changeChain = params.wallet.getChangeChain(params);
|
|
591
|
+
return params.wallet.createAddress({ chain: changeChain, validate: validate }).then(function (result) {
|
|
592
|
+
return result.address;
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
}).then(function (address) {
|
|
596
|
+
result.push({ address: address, amount: thisAmount });
|
|
597
|
+
return addChangeOutputs();
|
|
598
|
+
});
|
|
599
|
+
};
|
|
600
|
+
return addChangeOutputs();
|
|
601
|
+
};
|
|
602
|
+
// Add change output(s) and instant fee output if applicable
|
|
603
|
+
return Bluebird.try(function () {
|
|
604
|
+
return getChangeOutputs(inputAmount - totalAmount);
|
|
605
|
+
}).then(function (result) {
|
|
606
|
+
changeOutputs = result;
|
|
607
|
+
const extraOutputs = changeOutputs.concat([]); // copy the array
|
|
608
|
+
if (bitgoFeeInfo && bitgoFeeInfo.amount > 0) {
|
|
609
|
+
extraOutputs.push(bitgoFeeInfo);
|
|
610
|
+
}
|
|
611
|
+
extraOutputs.forEach(function (output) {
|
|
612
|
+
if (output.address) {
|
|
613
|
+
output.script = utxolib.address.toOutputScript(output.address, network);
|
|
614
|
+
}
|
|
615
|
+
// decide where to put the outputs - default is to randomize unless forced to end
|
|
616
|
+
const outputIndex = params.forceChangeAtEnd ? outputs.length : _.random(0, outputs.length);
|
|
617
|
+
outputs.splice(outputIndex, 0, output);
|
|
618
|
+
});
|
|
619
|
+
// Add all outputs to the transaction
|
|
620
|
+
outputs.forEach(function (output) {
|
|
621
|
+
transaction.addOutput(output.script, output.amount);
|
|
622
|
+
});
|
|
623
|
+
travelInfos = _(outputs)
|
|
624
|
+
.map(function (output, index) {
|
|
625
|
+
const result = output.travelInfo;
|
|
626
|
+
if (!result) {
|
|
627
|
+
return undefined;
|
|
628
|
+
}
|
|
629
|
+
result.outputIndex = index;
|
|
630
|
+
return result;
|
|
631
|
+
})
|
|
632
|
+
.filter()
|
|
633
|
+
.value();
|
|
634
|
+
});
|
|
635
|
+
};
|
|
636
|
+
// Serialize the transaction, returning what is needed to sign it
|
|
637
|
+
const serialize = function () {
|
|
638
|
+
// only need to return the unspents that were used and just the chainPath, redeemScript, and instant flag
|
|
639
|
+
const pickedUnspents = _.map(unspents, function (unspent) {
|
|
640
|
+
return _.pick(unspent, ['chainPath', 'redeemScript', 'instant', 'witnessScript', 'script', 'value']);
|
|
641
|
+
});
|
|
642
|
+
const prunedUnspents = _.slice(pickedUnspents, 0, transaction.tx.ins.length - feeSingleKeyUnspentsUsed.length);
|
|
643
|
+
_.each(feeSingleKeyUnspentsUsed, function (feeUnspent) {
|
|
644
|
+
prunedUnspents.push({ redeemScript: false, chainPath: false }); // mark as false to signify a non-multisig address
|
|
645
|
+
});
|
|
646
|
+
const result = {
|
|
647
|
+
transactionHex: transaction.buildIncomplete().toHex(),
|
|
648
|
+
unspents: prunedUnspents,
|
|
649
|
+
fee: fee,
|
|
650
|
+
changeAddresses: changeOutputs.map(function (co) {
|
|
651
|
+
return _.pick(co, ['address', 'path', 'amount']);
|
|
652
|
+
}),
|
|
653
|
+
walletId: params.wallet.id(),
|
|
654
|
+
walletKeychains: params.wallet.keychains,
|
|
655
|
+
feeRate: feeRate,
|
|
656
|
+
instant: params.instant,
|
|
657
|
+
bitgoFee: bitgoFeeInfo,
|
|
658
|
+
estimatedSize: minerFeeInfo.size,
|
|
659
|
+
txInfo: txInfo,
|
|
660
|
+
travelInfos: travelInfos,
|
|
661
|
+
};
|
|
662
|
+
// Add for backwards compatibility
|
|
663
|
+
if (result.instant && bitgoFeeInfo) {
|
|
664
|
+
result.instantFee = _.pick(bitgoFeeInfo, ['amount', 'address']);
|
|
665
|
+
}
|
|
666
|
+
return result;
|
|
667
|
+
};
|
|
668
|
+
return Bluebird.try(function () {
|
|
669
|
+
return getBitGoFee();
|
|
670
|
+
})
|
|
671
|
+
.then(function () {
|
|
672
|
+
return Bluebird.all([getBitGoFeeAddress(), getUnspents(), getUnspentsForSingleKey()]);
|
|
673
|
+
})
|
|
674
|
+
.then(collectInputs)
|
|
675
|
+
.then(collectOutputs)
|
|
676
|
+
.then(serialize);
|
|
677
|
+
};
|
|
678
|
+
/**
|
|
679
|
+
* Estimate the size of a transaction in bytes based on the number of
|
|
680
|
+
* inputs and outputs present.
|
|
681
|
+
* @params params {
|
|
682
|
+
* nP2shInputs: number of P2SH (multisig) inputs
|
|
683
|
+
* nP2pkhInputs: number of P2PKH (single sig) inputs
|
|
684
|
+
* nOutputs: number of outputs
|
|
685
|
+
* }
|
|
686
|
+
*
|
|
687
|
+
* @returns size: estimated size of the transaction in bytes
|
|
688
|
+
*/
|
|
689
|
+
const estimateTransactionSize = function (params) {
|
|
690
|
+
if (!_.isInteger(params.nP2shInputs) || params.nP2shInputs < 0) {
|
|
691
|
+
throw new Error('expecting positive nP2shInputs');
|
|
692
|
+
}
|
|
693
|
+
if (!_.isInteger(params.nP2pkhInputs) || params.nP2pkhInputs < 0) {
|
|
694
|
+
throw new Error('expecting positive nP2pkhInputs to be numeric');
|
|
695
|
+
}
|
|
696
|
+
if (!_.isInteger(params.nP2shP2wshInputs) || params.nP2shP2wshInputs < 0) {
|
|
697
|
+
throw new Error('expecting positive nP2shP2wshInputs to be numeric');
|
|
698
|
+
}
|
|
699
|
+
if (params.nP2shInputs + params.nP2shP2wshInputs < 1) {
|
|
700
|
+
throw new Error('expecting at least one nP2shInputs or nP2shP2wshInputs');
|
|
701
|
+
}
|
|
702
|
+
if (!_.isInteger(params.nOutputs) || params.nOutputs < 1) {
|
|
703
|
+
throw new Error('expecting positive nOutputs');
|
|
704
|
+
}
|
|
705
|
+
const estimatedSize = unspents_1.VirtualSizes.txP2shInputSize * params.nP2shInputs +
|
|
706
|
+
unspents_1.VirtualSizes.txP2shP2wshInputSize * (params.nP2shP2wshInputs || 0) +
|
|
707
|
+
unspents_1.VirtualSizes.txP2pkhInputSizeUncompressedKey * (params.nP2pkhInputs || 0) +
|
|
708
|
+
unspents_1.VirtualSizes.txP2pkhOutputSize * params.nOutputs +
|
|
709
|
+
// if the tx contains at least one segwit input, the tx overhead is increased by 1
|
|
710
|
+
unspents_1.VirtualSizes.txOverheadSize +
|
|
711
|
+
(params.nP2shP2wshInputs > 0 ? 1 : 0);
|
|
712
|
+
return estimatedSize;
|
|
713
|
+
};
|
|
714
|
+
/**
|
|
715
|
+
* Calculate the fee and estimated size in bytes for a transaction.
|
|
716
|
+
* @params params {
|
|
717
|
+
* bitgo: bitgo object
|
|
718
|
+
* feeRate: satoshis per kilobyte
|
|
719
|
+
* nP2shInputs: number of P2SH (multisig) inputs
|
|
720
|
+
* nP2pkhInputs: number of P2PKH (single sig) inputs
|
|
721
|
+
* nOutputs: number of outputs
|
|
722
|
+
* }
|
|
723
|
+
*
|
|
724
|
+
* @returns {
|
|
725
|
+
* size: estimated size of the transaction in bytes
|
|
726
|
+
* fee: estimated fee in satoshis for the transaction
|
|
727
|
+
* feeRate: fee rate that was used to estimate the fee for the transaction
|
|
728
|
+
* }
|
|
729
|
+
*/
|
|
730
|
+
exports.calculateMinerFeeInfo = function (params) {
|
|
731
|
+
const feeRateToUse = params.feeRate || params.bitgo.getConstants().fallbackFeeRate;
|
|
732
|
+
const estimatedSize = estimateTransactionSize(params);
|
|
733
|
+
return {
|
|
734
|
+
size: estimatedSize,
|
|
735
|
+
fee: Math.ceil((estimatedSize * feeRateToUse) / 1000),
|
|
736
|
+
feeRate: feeRateToUse,
|
|
737
|
+
};
|
|
738
|
+
};
|
|
739
|
+
/*
|
|
740
|
+
* Given a transaction hex, unspent information (chain path and redeem scripts), and the keychain xprv,
|
|
741
|
+
* perform key derivation and sign the inputs in the transaction based on the unspent information provided
|
|
742
|
+
*
|
|
743
|
+
* @params:
|
|
744
|
+
* transactionHex serialized form of the transaction in hex
|
|
745
|
+
* unspents array of unspent information, where each unspent is a chainPath and redeemScript with the same
|
|
746
|
+
* index as the inputs in the transactionHex
|
|
747
|
+
* keychain Keychain containing the xprv to sign with. For legacy support of safe wallets, keychain can
|
|
748
|
+
also be a WIF private key.
|
|
749
|
+
* signingKey private key in WIF for safe wallets, when keychain is unavailable
|
|
750
|
+
* validate client-side signature verification - can be disabled for improved performance (signatures
|
|
751
|
+
* are still validated server-side).
|
|
752
|
+
* feeSingleKeyWIF Use the address based on this private key to pay fees
|
|
753
|
+
* @returns {*}
|
|
754
|
+
*/
|
|
755
|
+
exports.signTransaction = function (params) {
|
|
756
|
+
let keychain = params.keychain; // duplicate so as to not mutate below
|
|
757
|
+
const validate = params.validate === undefined ? true : params.validate;
|
|
758
|
+
let privKey;
|
|
759
|
+
if (!_.isString(params.transactionHex)) {
|
|
760
|
+
throw new Error('expecting the transaction hex as a string');
|
|
761
|
+
}
|
|
762
|
+
if (!Array.isArray(params.unspents)) {
|
|
763
|
+
throw new Error('expecting the unspents array');
|
|
764
|
+
}
|
|
765
|
+
if (!_.isBoolean(validate)) {
|
|
766
|
+
throw new Error('expecting validate to be a boolean');
|
|
767
|
+
}
|
|
768
|
+
let network = sdk_core_1.getNetwork();
|
|
769
|
+
const enableBCH = _.isBoolean(params.forceBCH) && params.forceBCH === true;
|
|
770
|
+
if (!_.isObject(keychain) || !_.isString(keychain.xprv)) {
|
|
771
|
+
if (_.isString(params.signingKey)) {
|
|
772
|
+
privKey = utxolib.ECPair.fromWIF(params.signingKey, network);
|
|
773
|
+
keychain = undefined;
|
|
774
|
+
}
|
|
775
|
+
else {
|
|
776
|
+
throw new Error('expecting the keychain object with xprv');
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
let feeSingleKey;
|
|
780
|
+
if (params.feeSingleKeyWIF) {
|
|
781
|
+
feeSingleKey = utxolib.ECPair.fromWIF(params.feeSingleKeyWIF, network);
|
|
782
|
+
}
|
|
783
|
+
debug('Network: %O', network);
|
|
784
|
+
if (enableBCH) {
|
|
785
|
+
debug('Enabling BCH…');
|
|
786
|
+
network = utxolib.networks.bitcoincash;
|
|
787
|
+
debug('New network: %O', network);
|
|
788
|
+
}
|
|
789
|
+
const transaction = utxolib.bitgo.createTransactionFromHex(params.transactionHex, network);
|
|
790
|
+
if (transaction.ins.length !== params.unspents.length) {
|
|
791
|
+
throw new Error('length of unspents array should equal to the number of transaction inputs');
|
|
792
|
+
}
|
|
793
|
+
// decorate transaction with input values for TransactionBuilder instantiation
|
|
794
|
+
const isUtxoTx = _.isObject(transaction) && Array.isArray(transaction.ins);
|
|
795
|
+
const areValidUnspents = _.isObject(params) && Array.isArray(params.unspents);
|
|
796
|
+
if (isUtxoTx && areValidUnspents) {
|
|
797
|
+
// extend the transaction inputs with the values
|
|
798
|
+
const inputValues = _.map(params.unspents, (u) => _.pick(u, 'value'));
|
|
799
|
+
transaction.ins.map((currentItem, index) => _.extend(currentItem, inputValues[index]));
|
|
800
|
+
}
|
|
801
|
+
let rootExtKey;
|
|
802
|
+
if (keychain) {
|
|
803
|
+
rootExtKey = utxo_lib_1.bip32.fromBase58(keychain.xprv);
|
|
804
|
+
}
|
|
805
|
+
const txb = utxolib.bitgo.createTransactionBuilderFromTransaction(transaction);
|
|
806
|
+
for (let index = 0; index < txb.tx.ins.length; ++index) {
|
|
807
|
+
const currentUnspent = params.unspents[index];
|
|
808
|
+
if (currentUnspent.redeemScript === false) {
|
|
809
|
+
// this is the input from a single key fee address
|
|
810
|
+
if (!feeSingleKey) {
|
|
811
|
+
throw new Error('single key address used in input but feeSingleKeyWIF not provided');
|
|
812
|
+
}
|
|
813
|
+
if (enableBCH) {
|
|
814
|
+
feeSingleKey.network = network;
|
|
815
|
+
}
|
|
816
|
+
txb.sign(index, feeSingleKey);
|
|
817
|
+
continue;
|
|
818
|
+
}
|
|
819
|
+
if (currentUnspent.witnessScript && enableBCH) {
|
|
820
|
+
throw new Error('BCH does not support segwit inputs');
|
|
821
|
+
}
|
|
822
|
+
const chainPath = currentUnspent.chainPath;
|
|
823
|
+
if (rootExtKey) {
|
|
824
|
+
const { walletSubPath = '/0/0' } = keychain;
|
|
825
|
+
const path = sdk_core_1.sanitizeLegacyPath(keychain.path + walletSubPath + chainPath);
|
|
826
|
+
debug('derived user key path "%s" using keychain path "%s", walletSubPath "%s", keychain walletSubPath "%s" and chainPath "%s"', path, keychain.path, walletSubPath, keychain.walletSubPath, chainPath);
|
|
827
|
+
privKey = rootExtKey.derivePath(path);
|
|
828
|
+
}
|
|
829
|
+
privKey.network = network;
|
|
830
|
+
// subscript is the part of the output script after the OP_CODESEPARATOR.
|
|
831
|
+
// Since we are only ever signing p2sh outputs, which do not have
|
|
832
|
+
// OP_CODESEPARATORS, it is always the output script.
|
|
833
|
+
const subscript = Buffer.from(currentUnspent.redeemScript, 'hex');
|
|
834
|
+
currentUnspent.validationScript = subscript;
|
|
835
|
+
// In order to sign with bitcoinjs-lib, we must use its transaction
|
|
836
|
+
// builder, confusingly named the same exact thing as our transaction
|
|
837
|
+
// builder, but with inequivalent behavior.
|
|
838
|
+
try {
|
|
839
|
+
const witnessScript = currentUnspent.witnessScript ? Buffer.from(currentUnspent.witnessScript, 'hex') : undefined;
|
|
840
|
+
const sigHash = utxolib.bitgo.getDefaultSigHash(network);
|
|
841
|
+
txb.sign(index, privKey, subscript, sigHash, currentUnspent.value, witnessScript);
|
|
842
|
+
}
|
|
843
|
+
catch (e) {
|
|
844
|
+
// try fallback derivation path (see BG-46497)
|
|
845
|
+
let fallbackSigningSuccessful = false;
|
|
846
|
+
try {
|
|
847
|
+
const fallbackPath = sdk_core_1.sanitizeLegacyPath(keychain.path + chainPath);
|
|
848
|
+
debug('derived fallback user key path "%s" using keychain path "%s" and chainPath "%s"', fallbackPath, keychain.path, chainPath);
|
|
849
|
+
privKey = rootExtKey.derivePath(fallbackPath);
|
|
850
|
+
const witnessScript = currentUnspent.witnessScript
|
|
851
|
+
? Buffer.from(currentUnspent.witnessScript, 'hex')
|
|
852
|
+
: undefined;
|
|
853
|
+
const sigHash = utxolib.bitgo.getDefaultSigHash(network);
|
|
854
|
+
txb.sign(index, privKey, subscript, sigHash, currentUnspent.value, witnessScript);
|
|
855
|
+
fallbackSigningSuccessful = true;
|
|
856
|
+
}
|
|
857
|
+
catch (fallbackError) {
|
|
858
|
+
debug('input sign failed for fallback path: %s', fallbackError.message);
|
|
859
|
+
}
|
|
860
|
+
// we need to know what's causing this
|
|
861
|
+
if (!fallbackSigningSuccessful) {
|
|
862
|
+
e.result = {
|
|
863
|
+
unspent: currentUnspent,
|
|
864
|
+
};
|
|
865
|
+
e.message = `Failed to sign input #${index} - ${e.message} - ${JSON.stringify(e.result, null, 4)} - \n${e.stack}`;
|
|
866
|
+
debug('input sign failed: %s', e.message);
|
|
867
|
+
return Bluebird.reject(e);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
const partialTransaction = txb.buildIncomplete();
|
|
872
|
+
if (validate) {
|
|
873
|
+
partialTransaction.ins.forEach((input, index) => {
|
|
874
|
+
const signatureCount = utxolib.bitgo
|
|
875
|
+
.getSignatureVerifications(partialTransaction, index, params.unspents[index].value)
|
|
876
|
+
.filter((v) => v.signedBy !== undefined).length;
|
|
877
|
+
if (signatureCount < 1) {
|
|
878
|
+
throw new Error('expected at least one valid signature');
|
|
879
|
+
}
|
|
880
|
+
if (params.fullLocalSigning && signatureCount < 2) {
|
|
881
|
+
throw new Error('fullLocalSigning set: expected at least two valid signatures');
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
return Bluebird.resolve({
|
|
886
|
+
transactionHex: partialTransaction.toHex(),
|
|
887
|
+
});
|
|
888
|
+
};
|
|
889
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNhY3Rpb25CdWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3YxL3RyYW5zYWN0aW9uQnVpbGRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7O0FBRUg7R0FDRztBQUNILEVBQUU7QUFDRixxQkFBcUI7QUFDckIsa0RBQWtEO0FBQ2xELEVBQUU7QUFDRixvREFBb0Q7QUFDcEQsRUFBRTtBQUVGLDhDQUF3QztBQUN4QyxxQ0FBcUM7QUFDckMsMkNBQTJDO0FBQzNDLDRCQUE0QjtBQUM1Qiw4Q0FBK0M7QUFDL0Msa0NBQW1DO0FBQ25DLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQztBQUN2Qyw4Q0FBMEY7QUF1QjFGLEVBQUU7QUFDRixxQkFBcUI7QUFDckIsV0FBVztBQUNYLDBDQUEwQztBQUMxQyw4TUFBOE07QUFDOU0sc0dBQXNHO0FBQ3RHLGtJQUFrSTtBQUNsSSw2SEFBNkg7QUFDN0gsdUdBQXVHO0FBQ3ZHLCtFQUErRTtBQUMvRSxxRUFBcUU7QUFDckUsNkVBQTZFO0FBQzdFLHdHQUF3RztBQUN4RyxpSUFBaUk7QUFDakksd0lBQXdJO0FBQ3hJLDRJQUE0STtBQUM1SSx1RUFBdUU7QUFDdkUsMkVBQTJFO0FBQzNFLDRGQUE0RjtBQUM1RixPQUFPLENBQUMsaUJBQWlCLEdBQUcsVUFBVSxNQUFNO0lBQzFDLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxXQUFXLElBQUksQ0FBQyxDQUFDO0lBQzVDLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxRQUFRLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUM7SUFDeEUsSUFBSSxVQUFVLEdBQTZFLEVBQUUsQ0FBQztJQUM5RixJQUFJLFNBQVMsR0FBMEMsRUFBRSxDQUFDO0lBQzFELElBQUksa0JBQWtCLEdBQWEsRUFBRSxDQUFDO0lBQ3RDLElB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RjtJQUVELE1BQU0sa0JBQWtCLEdBQUcsR0FBRyxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBRWpELElBQUksUUFBUSxFQUFFO1FBQ1osa0JBQWtCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRTtZQUM5QyxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsS0FBSztpQkFDakMseUJBQXlCLENBQUMsa0JBQWtCLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDO2lCQUNsRixNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxRQUFRLEtBQUssU0FBUyxDQUFDLENBQUMsTUFBTSxDQUFDO1lBQ2xELElBQUksY0FBYyxHQUFHLENBQUMsRUFBRTtnQkFDdEIsTUFBTSxJQUFJLEtBQUssQ0FBQyx1Q0FBdUMsQ0FBQyxDQUFDO2FBQzFEO1lBQ0QsSUFBSSxNQUFNLENBQUMsZ0JBQWdCLElBQUksY0FBYyxHQUFHLENBQUMsRUFBRTtnQkFDakQsTUFBTSxJQUFJLEtBQUssQ0FBQyw4REFBOEQsQ0FBQyxDQUFDO2FBQ2pGO1FBQ0gsQ0FBQyxDQUFDLENBQUM7S0FDSjtJQUVELE9BQU8sUUFBUSxDQUFDLE9BQU8sQ0FBQztRQUN0QixjQUFjLEVBQUUsa0JBQWtCLENBQUMsS0FBSyxFQUFFO0tBQzNDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGhpZGRlblxuICovXG5cbi8qKlxuICovXG4vL1xuLy8gVHJhbnNhY3Rpb25CdWlsZGVyXG4vLyBBIHV0aWxpdHkgZm9yIGJ1aWxkaW5nIGFuZCBzaWduaW5nIHRyYW5zYWN0aW9uc1xuLy9cbi8vIENvcHlyaWdodCAyMDE0LCBCaXRHbywgSW5jLiAgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbi8vXG5cbmltcG9ydCB7IGJpcDMyIH0gZnJvbSAnQGJpdGdvL3V0eG8tbGliJztcbmltcG9ydCAqIGFzIEJsdWViaXJkIGZyb20gJ2JsdWViaXJkJztcbmltcG9ydCAqIGFzIHV0eG9saWIgZnJvbSAnQGJpdGdvL3V0eG8tbGliJztcbmltcG9ydCAqIGFzIF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IFZpcnR1YWxTaXplcyB9IGZyb20gJ0BiaXRnby91bnNwZW50cyc7XG5pbXBvcnQgZGVidWdMaWIgPSByZXF1aXJlKCdkZWJ1ZycpO1xuY29uc3QgZGVidWcgPSBkZWJ1Z0xpYignYml0Z286djE6dHhiJyk7XG5pbXBvcnQgeyBjb21tb24sIGdldEFkZHJlc3NQMlBLSCwgZ2V0TmV0d29yaywgc2FuaXRpemVMZWdhY3lQYXRoIH0gZnJvbSAnQGJpdGdvL3Nkay1jb3JlJztcblxuaW50ZXJmYWNlIEJhc2VPdXRwdXQge1xuICBhbW91bnQ6IG51bWJlcjtcbiAgdHJhdmVsSW5mbz86IGFueTtcbn1cblxuaW50ZXJmYWNlIEFkZHJlc3NPdXRwdXQgZXh0ZW5kcyBCYXNlT3V0cHV0IHtcbiAgYWRkcmVzczogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgU2NyaXB0T3V0cHV0IGV4dGVuZHMgQmFzZU91dHB1dCB7XG4gIHNjcmlwdDogQnVmZmVyO1xufVxuXG50eXBlIE91dHB1dCA9IEFkZHJlc3NPdXRwdXQgfCBTY3JpcHRPdXRwdXQ7XG5cbmludGVyZmFjZSBCaXRHb1Vuc3BlbnQge1xuICB2YWx1ZTogbnVtYmVyO1xuICB0eF9oYXNoOiBCdWZmZXI7XG4gIHR4X291dHB1dF9uOiBudW1iZXI7XG59XG5cbi8vXG4vLyBUcmFuc2FjdGlvbkJ1aWxkZXJcbi8vIEBwYXJhbXM6XG4vLyAgIHdhbGxldDogIGEgd2FsbGV0IG9iamVjdCB0byBzZW5kIGZyb21cbi8vICAgcmVjaXBpZW50czogYXJyYXkgb2YgcmVjaXBpZW50IG9iamVjdHMgYW5kIHRoZSBhbW91bnQgdG8gc2VuZCB0byBlYWNoIGUuZy4gW3thZGRyZXNzOiAnMzhCS0ROWmJQY0xvZ3ZWYmN4MmVrSjlFNlZ2OTREcURxdycsIGFtb3VudDogMTUwMH0sIHthZGRyZXNzOiAnMzZlTDh5UXFDbjFITVJtVkZGbzQ5dDJQSjNwYWk4d1FhbScsIGFtb3VudDogMjAwMH1dXG4vLyAgIGZlZTogdGhlIGZlZSB0byB1c2Ugd2l0aCB0aGlzIHRyYW5zYWN0aW9uLiAgaWYgbm90IHByb3ZpZGVkLCBhIGRlZmF1bHQsIG1pbmltdW0gZmVlIHdpbGwgYmUgdXNlZC5cbi8vICAgZmVlUmF0ZTogdGhlIGFtb3VudCBvZiBmZWUgcGVyIGtpbG9ieXRlIC0gb3B0aW9uYWwgLSBzcGVjaWZ5IGVpdGhlciBmZWUsIGZlZVJhdGUsIG9yIGZlZVR4Q29uZmlybVRhcmdldCBidXQgbm90IG1vcmUgdGhhbiBvbmVcbi8vICAgZmVlVHhDb25maXJtVGFyZ2V0OiBjYWxjdWxhdGUgdGhlIGZlZXMgcGVyIGtpbG9ieXRlIHN1Y2ggdGhhdCB0aGUgdHJhbnNhY3Rpb24gd2lsbCBiZSBjb25maXJtZWQgaW4gdGhpcyBudW1iZXIgb2YgYmxvY2tzXG4vLyAgIG1heEZlZVJhdGU6IFRoZSBtYXhpbXVtIGZlZSBwZXIga2IgdG8gdXNlIGluIHNhdG9zaGlzLCBmb3Igc2FmZXR5IHB1cnBvc2VzIHdoZW4gdXNpbmcgZHluYW1pYyBmZWVzXG4vLyAgIG1pbkNvbmZpcm1zOiB0aGUgbWluaW11bSBjb25maXJtYXRpb25zIGFuIG91dHB1dCBtdXN0IGhhdmUgYmVmb3JlIHNwZW5kaW5nXG4vLyAgIGZvcmNlQ2hhbmdlQXRFbmQ6IGZvcmNlIHRoZSBjaGFuZ2UgYWRkcmVzcyB0byBiZSB0aGUgbGFzdCBvdXRwdXRcbi8vICAgY2hhbmdlQWRkcmVzczogc3BlY2lmeSB0aGUgY2hhbmdlIGFkZHJlc3MgcmF0aGVyIHRoYW4gZ2VuZXJhdGUgYSBuZXcgb25lXG4vLyAgIG5vU3BsaXRDaGFuZ2U6IHNldCB0byB0cnVlIHRvIGRpc2FibGUgYXV0b21hdGljIGNoYW5nZSBzcGxpdHRpbmcgZm9yIHB1cnBvc2VzIG9mIHVuc3BlbnQgbWFuYWdlbWVudFxuLy8gICB0YXJnZXRXYWxsZXRVbnNwZW50czogc3BlY2lmeSBhIG51bWJlciBvZiB0YXJnZXQgdW5zcGVudHMgdG8gbWFpbnRhaW4gaW4gdGhlIHdhbGxldCAoY3VycmVudGx5IGRlZmF1bHRlZCB0byA4IGJ5IHRoZSBzZXJ2ZXIpXG4vLyAgIHZhbGlkYXRlOiBleHRyYSB2ZXJpZmljYXRpb24gb2YgdGhlIGNoYW5nZSBhZGRyZXNzZXMsIHdoaWNoIGlzIGFsd2F5cyBkb25lIHNlcnZlci1zaWRlIGFuZCBpcyByZWR1bmRhbnQgY2xpZW50LXNpZGUgKGRlZmF1bHRzIHRydWUpXG4vLyAgIG1pblVuc3BlbnRTaXplOiBUaGUgbWluaW11bSBzaXplIGluIHNhdG9zaGlzIG9mIHVuc3BlbnQgdG8gdXNlICh0byBwcmV2ZW50IHNwZW5kaW5nIHVuc3BlbnRzIHdvcnRoIGxlc3MgdGhhbiBmZWUgYWRkZWQpLiBEZWZhdWx0cyB0byAwLlxuLy8gICBmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzOiBVc2UgdGhpcyBzaW5nbGUga2V5IGFkZHJlc3MgdG8gcGF5IGZlZXNcbi8vICAgZmVlU2luZ2xlS2V5V0lGOiBVc2UgdGhlIGFkZHJlc3MgYmFzZWQgb24gdGhpcyBwcml2YXRlIGtleSB0byBwYXkgZmVlc1xuLy8gICB1bnNwZW50c0ZldGNoUGFyYW1zOiBFeHRyYSBwYXJhbWV0ZXJzIHRvIHVzZSBmb3IgZmV0Y2hpbmcgdW5zcGVudHMgZm9yIHRoaXMgdHJhbnNhY3Rpb25cbmV4cG9ydHMuY3JlYXRlVHJhbnNhY3Rpb24gPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gIGNvbnN0IG1pbkNvbmZpcm1zID0gcGFyYW1zLm1pbkNvbmZpcm1zIHx8IDA7XG4gIGNvbnN0IHZhbGlkYXRlID0gcGFyYW1zLnZhbGlkYXRlID09PSB1bmRlZmluZWQgPyB0cnVlIDogcGFyYW1zLnZhbGlkYXRlO1xuICBsZXQgcmVjaXBpZW50czogeyBhZGRyZXNzOiBzdHJpbmc7IGFtb3VudDogbnVtYmVyOyBzY3JpcHQ/OiBzdHJpbmc7IHRyYXZlbEluZm8/OiBhbnkgfVtdID0gW107XG4gIGxldCBvcFJldHVybnM6IHsgbWVzc2FnZTogc3RyaW5nOyBhbW91bnQ6IG51bWJlciB9W10gPSBbXTtcbiAgbGV0IGV4dHJhQ2hhbmdlQW1vdW50czogbnVtYmVyW10gPSBbXTtcbiAgbGV0IGVzdFR4U2l6ZTogbnVtYmVyO1xuICBsZXQgdHJhdmVsSW5mb3M7XG5cbiAgLy8gU2FuaXR5IGNoZWNrIHRoZSBhcmd1bWVudHMgcGFzc2VkIGluXG4gIGlmIChcbiAgICAhXy5pc09iamVjdChwYXJhbXMud2FsbGV0KSB8fFxuICAgIChwYXJhbXMuZmVlICYmICFfLmlzTnVtYmVyKHBhcmFtcy5mZWUpKSB8fFxuICAgIChwYXJhbXMuZmVlUmF0ZSAmJiAhXy5pc051bWJlcihwYXJhbXMuZmVlUmF0ZSkpIHx8XG4gICAgIV8uaXNJbnRlZ2VyKG1pbkNvbmZpcm1zKSB8fFxuICAgIChwYXJhbXMuZm9yY2VDaGFuZ2VBdEVuZCAmJiAhXy5pc0Jvb2xlYW4ocGFyYW1zLmZvcmNlQ2hhbmdlQXRFbmQpKSB8fFxuICAgIChwYXJhbXMuY2hhbmdlQWRkcmVzcyAmJiAhXy5pc1N0cmluZyhwYXJhbXMuY2hhbmdlQWRkcmVzcykpIHx8XG4gICAgKHBhcmFtcy5ub1NwbGl0Q2hhbmdlICYmICFfLmlzQm9vbGVhbihwYXJhbXMubm9TcGxpdENoYW5nZSkpIHx8XG4gICAgKHBhcmFtcy50YXJnZXRXYWxsZXRVbnNwZW50cyAmJiAhXy5pc0ludGVnZXIocGFyYW1zLnRhcmdldFdhbGxldFVuc3BlbnRzKSkgfHxcbiAgICAodmFsaWRhdGUgJiYgIV8uaXNCb29sZWFuKHZhbGlkYXRlKSkgfHxcbiAgICAocGFyYW1zLmVuZm9yY2VNaW5Db25maXJtc0ZvckNoYW5nZSAmJiAhXy5pc0Jvb2xlYW4ocGFyYW1zLmVuZm9yY2VNaW5Db25maXJtc0ZvckNoYW5nZSkpIHx8XG4gICAgKHBhcmFtcy5taW5VbnNwZW50U2l6ZSAmJiAhXy5pc051bWJlcihwYXJhbXMubWluVW5zcGVudFNpemUpKSB8fFxuICAgIChwYXJhbXMubWF4RmVlUmF0ZSAmJiAhXy5pc051bWJlcihwYXJhbXMubWF4RmVlUmF0ZSkpIHx8XG4gICAgLy8gdGhpcyBzaG91bGQgYmUgYW4gYXJyYXkgYW5kIGl0cyBsZW5ndGggbXVzdCBiZSBhdCBsZWFzdCAxXG4gICAgKHBhcmFtcy51bnNwZW50cyAmJiAoIUFycmF5LmlzQXJyYXkocGFyYW1zLnVuc3BlbnRzKSB8fCBwYXJhbXMudW5zcGVudHMubGVuZ3RoIDwgMSkpIHx8XG4gICAgKHBhcmFtcy5mZWVUeENvbmZpcm1UYXJnZXQgJiYgIV8uaXNJbnRlZ2VyKHBhcmFtcy5mZWVUeENvbmZpcm1UYXJnZXQpKSB8fFxuICAgIChwYXJhbXMuaW5zdGFudCAmJiAhXy5pc0Jvb2xlYW4ocGFyYW1zLmluc3RhbnQpKSB8fFxuICAgIChwYXJhbXMuYml0Z29GZWUgJiYgIV8uaXNPYmplY3QocGFyYW1zLmJpdGdvRmVlKSkgfHxcbiAgICAocGFyYW1zLnVuc3BlbnRzRmV0Y2hQYXJhbXMgJiYgIV8uaXNPYmplY3QocGFyYW1zLnVuc3BlbnRzRmV0Y2hQYXJhbXMpKVxuICApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgYXJndW1lbnQnKTtcbiAgfVxuXG4gIGNvbnN0IGJpdGdvID0gcGFyYW1zLndhbGxldC5iaXRnbztcbiAgY29uc3QgY29uc3RhbnRzID0gYml0Z28uZ2V0Q29uc3RhbnRzKCk7XG4gIGNvbnN0IG5ldHdvcmsgPSBnZXROZXR3b3JrKGNvbW1vbi5FbnZpcm9ubWVudHNbYml0Z28uZ2V0RW52KCldLm5ldHdvcmspO1xuXG4gIC8vIFRoZSB1c2VyIGNhbiBzcGVjaWZ5IGEgc2VwZXJhdGUsIHNpbmdsZS1rZXkgd2FsbGV0IGZvciB0aGUgcHVycG9zZXMgb2YgcGF5aW5nIG1pbmVyJ3MgZmVlc1xuICAvLyBXaGVuIGNyZWF0aW5nIGEgdHJhbnNhY3Rpb24gdGhpcyBjYW4gYmUgc3BlY2lmaWVkIGFzIGFuIGlucHV0IGFkZHJlc3Mgb3IgdGhlIHByaXZhdGUga2V5IGluIFdJRlxuICBsZXQgZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcztcbiAgbGV0IGZlZVNpbmdsZUtleUlucHV0QW1vdW50ID0gMDtcbiAgaWYgKHBhcmFtcy5mZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzKSB7XG4gICAgdHJ5IHtcbiAgICAgIHV0eG9saWIuYWRkcmVzcy5mcm9tQmFzZTU4Q2hlY2socGFyYW1zLmZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MsIG5ldHdvcmspO1xuICAgICAgZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcyA9IHBhcmFtcy5mZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBiaXRjb2luIGFkZHJlc3M6ICcgKyBwYXJhbXMuZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcyk7XG4gICAgfVxuICB9XG5cbiAgaWYgKHBhcmFtcy5mZWVTaW5nbGVLZXlXSUYpIHtcbiAgICBjb25zdCBmZWVTaW5nbGVLZXkgPSB1dHhvbGliLkVDUGFpci5mcm9tV0lGKHBhcmFtcy5mZWVTaW5nbGVLZXlXSUYsIG5ldHdvcmsgYXMgdXR4b2xpYi5CaXRjb2luSlNOZXR3b3JrKTtcbiAgICBmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzID0gZ2V0QWRkcmVzc1AyUEtIKGZlZVNpbmdsZUtleSk7XG4gICAgLy8gSWYgdGhlIHVzZXIgc3BlY2lmaWVzIGJvdGgsIGNoZWNrIHRvIG1ha2Ugc3VyZSB0aGUgZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcyBjb3JyZXNwb25kcyB0byB0aGUgYWRkcmVzcyBvZiBmZWVTaW5nbGVLZXlXSUZcbiAgICBpZiAocGFyYW1zLmZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MgJiYgcGFyYW1zLmZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MgIT09IGZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ2ZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3M6ICcgK1xuICAgICAgICAgIHBhcmFtcy5mZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzICtcbiAgICAgICAgICAnIGRpZCBub3QgY29ycmVzcG9uZCB0byBhZGRyZXNzIG9mIGZlZVNpbmdsZUtleVdJRjogJyArXG4gICAgICAgICAgZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzc1xuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBpZiAoIV8uaXNPYmplY3QocGFyYW1zLnJlY2lwaWVudHMpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdyZWNpcGllbnRzIG11c3QgYmUgYXJyYXkgb2YgeyBhZGRyZXNzOiBhYmMsIGFtb3VudDogMTAwMDAwIH0gb2JqZWN0cycpO1xuICB9XG5cbiAgbGV0IGZlZVBhcmFtc0RlZmluZWQgPSAwO1xuICBpZiAoIV8uaXNVbmRlZmluZWQocGFyYW1zLmZlZSkpIHtcbiAgICBmZWVQYXJhbXNEZWZpbmVkKys7XG4gIH1cblxuICBpZiAoIV8uaXNVbmRlZmluZWQocGFyYW1zLmZlZVJhdGUpKSB7XG4gICAgZmVlUGFyYW1zRGVmaW5lZCsrO1xuICB9XG5cbiAgaWYgKCFfLmlzVW5kZWZpbmVkKHBhcmFtcy5mZWVUeENvbmZpcm1UYXJnZXQpKSB7XG4gICAgZmVlUGFyYW1zRGVmaW5lZCsrO1xuICB9XG5cbiAgaWYgKGZlZVBhcmFtc0RlZmluZWQgPiAxKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjYW5ub3Qgc3BlY2lmeSBtb3JlIHRoYW4gb25lIG9mIGZlZSwgZmVlUmF0ZSBhbmQgZmVlVHhDb25maXJtVGFyZ2V0Jyk7XG4gIH1cblxuICBpZiAoXy5pc1VuZGVmaW5lZChwYXJhbXMubWF4RmVlUmF0ZSkpIHtcbiAgICBwYXJhbXMubWF4RmVlUmF0ZSA9IGNvbnN0YW50cy5tYXhGZWVSYXRlO1xuICB9XG5cbiAgLy8gQ29udmVydCB0aGUgb2xkIGZvcm1hdCBvZiBwYXJhbXMucmVjaXBpZW50cyAoZGljdGlvbmFyeSBvZiBhZGRyZXNzOmFtb3VudCkgdG8gbmV3IGZvcm1hdDogeyBkZXN0aW5hdGlvbkFkZHJlc3MsIGFtb3VudCB9XG4gIGlmICghKHBhcmFtcy5yZWNpcGllbnRzIGluc3RhbmNlb2YgQXJyYXkpKSB7XG4gICAgcmVjaXBpZW50cyA9IFtdO1xuICAgIE9iamVjdC5rZXlzKHBhcmFtcy5yZWNpcGllbnRzKS5mb3JFYWNoKGZ1bmN0aW9uIChkZXN0aW5hdGlvbkFkZHJlc3MpIHtcbiAgICAgIGNvbnN0IGFtb3VudCA9IHBhcmFtcy5yZWNpcGllbnRzW2Rlc3RpbmF0aW9uQWRkcmVzc107XG4gICAgICByZWNpcGllbnRzLnB1c2goeyBhZGRyZXNzOiBkZXN0aW5hdGlvbkFkZHJlc3MsIGFtb3VudDogYW1vdW50IH0pO1xuICAgIH0pO1xuICB9IGVsc2Uge1xuICAgIHJlY2lwaWVudHMgPSBwYXJhbXMucmVjaXBpZW50cztcbiAgfVxuXG4gIGlmIChwYXJhbXMub3BSZXR1cm5zKSB7XG4gICAgaWYgKCEocGFyYW1zLm9wUmV0dXJucyBpbnN0YW5jZW9mIEFycmF5KSkge1xuICAgICAgb3BSZXR1cm5zID0gW107XG4gICAgICBPYmplY3Qua2V5cyhwYXJhbXMub3BSZXR1cm5zKS5mb3JFYWNoKGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgIGNvbnN0IGFtb3VudCA9IHBhcmFtcy5vcFJldHVybnNbbWVzc2FnZV07XG4gICAgICAgIG9wUmV0dXJucy5wdXNoKHsgbWVzc2FnZSwgYW1vdW50IH0pO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG9wUmV0dXJucyA9IHBhcmFtcy5vcFJldHVybnM7XG4gICAgfVxuICB9XG5cbiAgaWYgKHJlY2lwaWVudHMubGVuZ3RoID09PSAwICYmIG9wUmV0dXJucy5sZW5ndGggPT09IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ211c3QgaGF2ZSBhdCBsZWFzdCBvbmUgcmVjaXBpZW50Jyk7XG4gIH1cblxuICBsZXQgZmVlID0gcGFyYW1zLmZlZTtcbiAgbGV0IGZlZVJhdGUgPSBwYXJhbXMuZmVlUmF0ZTtcblxuICAvLyBGbGFnIGluZGljYXRpbmcgd2hldGhlciB0aGlzIGNsYXNzIHdpbGwgY29tcHV0ZSB0aGUgZmVlXG4gIGNvbnN0IHNob3VsZENvbXB1dGVCZXN0RmVlID0gXy5pc1VuZGVmaW5lZChmZWUpO1xuXG4gIGxldCB0b3RhbE91dHB1dEFtb3VudCA9IDA7XG5cbiAgcmVjaXBpZW50cy5mb3JFYWNoKGZ1bmN0aW9uIChyZWNpcGllbnQpIHtcbiAgICBpZiAoXy5pc1N0cmluZyhyZWNpcGllbnQuYWRkcmVzcykpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHV0eG9saWIuYWRkcmVzcy5mcm9tQmFzZTU4Q2hlY2socmVjaXBpZW50LmFkZHJlc3MsIG5ldHdvcmspO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgYml0Y29pbiBhZGRyZXNzOiAnICsgcmVjaXBpZW50LmFkZHJlc3MpO1xuICAgICAgfVxuICAgICAgaWYgKCEhcmVjaXBpZW50LnNjcmlwdCkge1xuICAgICAgICAvLyBBIHNjcmlwdCB3YXMgcHJvdmlkZWQgYXMgd2VsbCAtIHZhbGlkYXRlIHRoYXQgdGhlIGFkZHJlc3MgY29ycmVzcG9uZHMgdG8gdGhhdFxuICAgICAgICBpZiAodXR4b2xpYi5hZGRyZXNzLnRvT3V0cHV0U2NyaXB0KHJlY2lwaWVudC5hZGRyZXNzLCBuZXR3b3JrKS50b1N0cmluZygnaGV4JykgIT09IHJlY2lwaWVudC5zY3JpcHQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAnYm90aCBzY3JpcHQgYW5kIGFkZHJlc3MgcHJvdmlkZWQgYnV0IHRoZXkgZGlkIG5vdCBtYXRjaDogJyArIHJlY2lwaWVudC5hZGRyZXNzICsgJyAnICsgcmVjaXBpZW50LnNjcmlwdFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKCFfLmlzSW50ZWdlcihyZWNpcGllbnQuYW1vdW50KSB8fCByZWNpcGllbnQuYW1vdW50IDwgMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGFtb3VudCBmb3IgJyArIHJlY2lwaWVudC5hZGRyZXNzICsgJzogJyArIHJlY2lwaWVudC5hbW91bnQpO1xuICAgIH1cbiAgICB0b3RhbE91dHB1dEFtb3VudCArPSByZWNpcGllbnQuYW1vdW50O1xuICB9KTtcblxuICBvcFJldHVybnMuZm9yRWFjaChmdW5jdGlvbiAob3BSZXR1cm4pIHtcbiAgICB0b3RhbE91dHB1dEFtb3VudCArPSBvcFJldHVybi5hbW91bnQ7XG4gIH0pO1xuXG4gIGxldCBiaXRnb0ZlZUluZm8gPSBwYXJhbXMuYml0Z29GZWU7XG4gIGlmIChiaXRnb0ZlZUluZm8gJiYgKCFfLmlzSW50ZWdlcihiaXRnb0ZlZUluZm8uYW1vdW50KSB8fCAhXy5pc1N0cmluZyhiaXRnb0ZlZUluZm8uYWRkcmVzcykpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGJpdGdvRmVlSW5mbycpO1xuICB9XG5cbiAgLy8gVGhlIHRvdGFsIGFtb3VudCBuZWVkZWQgZm9yIHRoaXMgdHJhbnNhY3Rpb24uXG4gIGxldCB0b3RhbEFtb3VudCA9IHRvdGFsT3V0cHV0QW1vdW50ICsgKGZlZSB8fCAwKTtcblxuICAvLyBUaGUgbGlzdCBvZiB1bnNwZW50IHRyYW5zYWN0aW9ucyBiZWluZyB1c2VkIGluIHRoaXMgdHJhbnNhY3Rpb24uXG4gIGxldCB1bnNwZW50cztcblxuICAvLyB0aGUgdG90YWwgbnVtYmVyIG9mIHVuc3BlbnRzIG9uIHRoaXMgd2FsbGV0XG4gIGxldCB0b3RhbFVuc3BlbnRzQ291bnQ7XG5cbiAgLy8gdGhlIG51bWJlciBvZiB1bnNwZW50cyB3ZSBmZXRjaGVkIGZyb20gdGhlIHNlcnZlciwgYmVmb3JlIGZpbHRlcmluZ1xuICBsZXQgZmV0Y2hlZFVuc3BlbnRzQ291bnQ7XG5cbiAgLy8gVGhlIGxpc3Qgb2YgdW5zcGVudCB0cmFuc2FjdGlvbnMgYmVpbmcgdXNlZCB3aXRoIHplcm8tY29uZmlybWF0aW9uc1xuICBsZXQgemVyb0NvbmZVbnNwZW50VHhJZHM7XG5cbiAgLy8gVGhlIHN1bSBvZiB0aGUgaW5wdXQgdmFsdWVzIGZvciB0aGlzIHRyYW5zYWN0aW9uLlxuICBsZXQgaW5wdXRBbW91bnQ7XG5cbiAgbGV0IGNoYW5nZU91dHB1dHM6IE91dHB1dFtdID0gW107XG5cbiAgLy8gVGhlIHRyYW5zYWN0aW9uLlxuICBsZXQgdHJhbnNhY3Rpb24gPSB1dHhvbGliLmJpdGdvLmNyZWF0ZVRyYW5zYWN0aW9uQnVpbGRlckZvck5ldHdvcmsobmV0d29yayk7XG5cbiAgY29uc3QgZ2V0Qml0R29GZWUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIEJsdWViaXJkLnRyeShmdW5jdGlvbiAoKSB7XG4gICAgICBpZiAoYml0Z29GZWVJbmZvKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHJldHVybiBwYXJhbXMud2FsbGV0LmdldEJpdEdvRmVlKHsgYW1vdW50OiB0b3RhbE91dHB1dEFtb3VudCwgaW5zdGFudDogcGFyYW1zLmluc3RhbnQgfSkudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgIGlmIChyZXN1bHQgJiYgcmVzdWx0LmZlZSA+IDApIHtcbiAgICAgICAgICBiaXRnb0ZlZUluZm8gPSB7XG4gICAgICAgICAgICBhbW91bnQ6IHJlc3VsdC5mZWUsXG4gICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICBpZiAoYml0Z29GZWVJbmZvICYmIGJpdGdvRmVlSW5mby5hbW91bnQgPiAwKSB7XG4gICAgICAgIHRvdGFsQW1vdW50ICs9IGJpdGdvRmVlSW5mby5hbW91bnQ7XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgY29uc3QgZ2V0Qml0R29GZWVBZGRyZXNzID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBCbHVlYmlyZC50cnkoZnVuY3Rpb24gKCkge1xuICAgICAgLy8gSWYgd2UgZG9uJ3QgaGF2ZSBiaXRnb0ZlZUluZm8sIG9yIGFkZHJlc3MgaXMgYWxyZWFkeSBzZXQsIGRvbid0IGdldCBhIG5ldyBvbmVcbiAgICAgIGlmICghYml0Z29GZWVJbmZvIHx8IGJpdGdvRmVlSW5mby5hZGRyZXNzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHJldHVybiBiaXRnby5nZXRCaXRHb0ZlZUFkZHJlc3MoKS50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgYml0Z29GZWVJbmZvLmFkZHJlc3MgPSByZXN1bHQuYWRkcmVzcztcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9O1xuXG4gIC8vIEdldCBhIGR5bmFtaWMgZmVlIGVzdGltYXRlIGZyb20gdGhlIEJpdEdvIHNlcnZlciBpZiBmZWVUeENvbmZpcm1UYXJnZXRcbiAgLy8gaXMgc3BlY2lmaWVkIG9yIGlmIG5vIGZlZS1yZWxhdGVkIHBhcmFtcyBhcmUgc3BlY2lmaWVkXG4gIGNvbnN0IGdldER5bmFtaWNGZWVSYXRlRXN0aW1hdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHBhcmFtcy5mZWVUeENvbmZpcm1UYXJnZXQgfHwgIWZlZVBhcmFtc0RlZmluZWQpIHtcbiAgICAgIHJldHVybiBiaXRnb1xuICAgICAgICAuZXN0aW1hdGVGZWUoe1xuICAgICAgICAgIG51bUJsb2NrczogcGFyYW1zLmZlZVR4Q29uZmlybVRhcmdldCxcbiAgICAgICAgICBtYXhGZWU6IHBhcmFtcy5tYXhGZWVSYXRlLFxuICAgICAgICAgIGlucHV0czogemVyb0NvbmZVbnNwZW50VHhJZHMsXG4gICAgICAgICAgdHhTaXplOiBlc3RUeFNpemUsXG4gICAgICAgICAgY3BmcEF3YXJlOiB0cnVlLFxuICAgICAgICB9KVxuICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgY29uc3QgZXN0aW1hdGVkRmVlUmF0ZSA9IHJlc3VsdC5jcGZwRmVlUGVyS2I7XG4gICAgICAgICAgY29uc3QgbWluaW11bSA9IHBhcmFtcy5pbnN0YW50XG4gICAgICAgICAgICA/IE1hdGgubWF4KGNvbnN0YW50cy5taW5GZWVSYXRlLCBjb25zdGFudHMubWluSW5zdGFudEZlZVJhdGUpXG4gICAgICAgICAgICA6IGNvbnN0YW50cy5taW5GZWVSYXRlO1xuICAgICAgICAgIC8vIDUgc2F0b3NoaXMgcGVyIGJ5dGVcbiAgICAgICAgICAvLyBpdCBpcyB3b3J0aCBub3RpbmcgdGhhdCB0aGUgcGFkZGluZyBvbmx5IGFwcGxpZXMgd2hlbiB0aGUgdGhyZXNob2xkIGlzIGNyb3NzZWQsIGJ1dCBub3Qgd2hlbiB0aGUgZGVsdGEgaXMgbGVzcyB0aGFuIHRoZSBwYWRkaW5nXG4gICAgICAgICAgY29uc3QgcGFkZGluZyA9IDUwMDA7XG4gICAgICAgICAgaWYgKGVzdGltYXRlZEZlZVJhdGUgPCBtaW5pbXVtKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgbmV3IERhdGUoKSArXG4gICAgICAgICAgICAgICAgJzogRXJyb3Igd2hlbiBlc3RpbWF0aW5nIGZlZSBmb3Igc2VuZCBmcm9tICcgK1xuICAgICAgICAgICAgICAgIHBhcmFtcy53YWxsZXQuaWQoKSArXG4gICAgICAgICAgICAgICAgJywgaXQgd2FzIHRvbyBsb3cgLSAnICtcbiAgICAgICAgICAgICAgICBlc3RpbWF0ZWRGZWVSYXRlXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgZmVlUmF0ZSA9IG1pbmltdW0gKyBwYWRkaW5nO1xuICAgICAgICAgIH0gZWxzZSBpZiAoZXN0aW1hdGVkRmVlUmF0ZSA+IHBhcmFtcy5tYXhGZWVSYXRlKSB7XG4gICAgICAgICAgICBmZWVSYXRlID0gcGFyYW1zLm1heEZlZVJhdGUgLSBwYWRkaW5nO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmZWVSYXRlID0gZXN0aW1hdGVkRmVlUmF0ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGZlZVJhdGU7XG4gICAgICAgIH0pXG4gICAgICAgIC5jYXRjaChmdW5jdGlvbiAoZSkge1xuICAgICAgICAgIC8vIHNhbml0eSBjaGVjayBmYWlsZWQgb24gdHggc2l6ZVxuICAgICAgICAgIGlmIChfLmluY2x1ZGVzKGUubWVzc2FnZSwgJ2ludmFsaWQgdHhTaXplJykpIHtcbiAgICAgICAgICAgIHJldHVybiBCbHVlYmlyZC5yZWplY3QoZSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIGNvdWxkbid0IGVzdGltYXRlIHRoZSBmZWUsIHByb2NlZWQgdXNpbmcgdGhlIGRlZmF1bHRcbiAgICAgICAgICAgIGZlZVJhdGUgPSBjb25zdGFudHMuZmFsbGJhY2tGZWVSYXRlO1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ0Vycm9yIGVzdGltYXRpbmcgZmVlIGZvciBzZW5kIGZyb20gJyArIHBhcmFtcy53YWxsZXQuaWQoKSArICc6ICcgKyBlLm1lc3NhZ2UpO1xuICAgICAgICAgICAgcmV0dXJuIEJsdWViaXJkLnJlc29sdmUoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgfTtcblxuICAvLyBHZXQgdGhlIHVuc3BlbnRzIGZvciB0aGUgc2VuZGluZyB3YWxsZXQuXG4gIGNvbnN0IGdldFVuc3BlbnRzID0gZnVuY3Rpb24gKCkge1xuICAgIGlmIChwYXJhbXMudW5zcGVudHMpIHtcbiAgICAgIC8vIHdlIGp1c3Qgd2FubmEgdXNlIGN1c3RvbSB1bnNwZW50c1xuICAgICAgdW5zcGVudHMgPSBwYXJhbXMudW5zcGVudHM7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gR2V0IGVub3VnaCB1bnNwZW50cyBmb3IgdGhlIHJlcXVlc3RlZCBhbW91bnRcbiAgICBjb25zdCBvcHRpb25zID0gXy5tZXJnZSh7fSwgcGFyYW1zLnVuc3BlbnRzRmV0Y2hQYXJhbXMgfHwge30sIHtcbiAgICAgIHRhcmdldDogdG90YWxBbW91bnQsXG4gICAgICBtaW5TaXplOiBwYXJhbXMubWluVW5zcGVudFNpemUgfHwgMCxcbiAgICAgIGluc3RhbnQ6IHBhcmFtcy5pbnN0YW50LCAvLyBpbnNpc3Qgb24gaW5zdGFudCB1bnNwZW50cyBvbmx5XG4gICAgICB0YXJnZXRXYWxsZXRVbnNwZW50czogcGFyYW1zLnRhcmdldFdhbGxldFVuc3BlbnRzLFxuICAgIH0pO1xuICAgIGlmIChwYXJhbXMuaW5zdGFudCkge1xuICAgICAgb3B0aW9ucy5pbnN0YW50ID0gcGFyYW1zLmluc3RhbnQ7IC8vIGluc2lzdCBvbiBpbnN0YW50IHVuc3BlbnRzIG9ubHlcbiAgICB9XG5cbiAgICByZXR1cm4gcGFyYW1zLndhbGxldC51bnNwZW50c1BhZ2VkKG9wdGlvbnMpLnRoZW4oZnVuY3Rpb24gKHJlc3VsdHMpIHtcbiAgICAgIHRvdGFsVW5zcGVudHNDb3VudCA9IHJlc3VsdHMudG90YWw7XG4gICAgICBmZXRjaGVkVW5zcGVudHNDb3VudCA9IHJlc3VsdHMuY291bnQ7XG4gICAgICB1bnNwZW50cyA9IHJlc3VsdHMudW5zcGVudHMuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgIGNvbnN0IGNvbmZpcm1zID0gdS5jb25maXJtYXRpb25zIHx8IDA7XG4gICAgICAgIGlmICghcGFyYW1zLmVuZm9yY2VNaW5Db25maXJtc0ZvckNoYW5nZSAmJiB1LmlzQ2hhbmdlKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNvbmZpcm1zID49IG1pbkNvbmZpcm1zO1xuICAgICAgfSk7XG5cbiAgICAgIC8vIGFib3J0IGVhcmx5IGlmIHRoZXJlJ3Mgbm8gdmlhYmxlIHVuc3BlbnRzLCBiZWNhdXNlIGl0IHdvbid0IGJlIHBvc3NpYmxlIHRvIGNyZWF0ZSB0aGUgdHhuIGxhdGVyXG4gICAgICBpZiAodW5zcGVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRocm93IEVycm9yKCcwIHVuc3BlbnRzIGF2YWlsYWJsZSBmb3IgdHJhbnNhY3Rpb24gY3JlYXRpb24nKTtcbiAgICAgIH1cblxuICAgICAgLy8gY3JlYXRlIGFycmF5IG9mIHVuY29uZmlybWVkIHVuc3BlbnQgSUQgc3RyaW5ncyBvZiB0aGUgZm9ybSBcInR4SGFzaDpvdXRwdXRJbmRleFwiXG4gICAgICB6ZXJvQ29uZlVuc3BlbnRUeElkcyA9IF8ocmVzdWx0cy51bnNwZW50cylcbiAgICAgICAgLmZpbHRlcihmdW5jdGlvbiAodSkge1xuICAgICAgICAgIHJldHVybiAhdS5jb25maXJtYXRpb25zO1xuICAgICAgICB9KVxuICAgICAgICAubWFwKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgcmV0dXJuIHUudHhfaGFzaCArICc6JyArIHUudHhfb3V0cHV0X247XG4gICAgICAgIH0pXG4gICAgICAgIC52YWx1ZSgpO1xuICAgICAgaWYgKF8uaXNFbXB0eSh6ZXJvQ29uZlVuc3BlbnRUeElkcykpIHtcbiAgICAgICAgLy8gd2UgZG9uJ3Qgd2FudCB0byBwYXNzIGFuIGVtcHR5IGFycmF5IG9mIGlucHV0cyB0byB0aGUgc2VydmVyLCBiZWNhdXNlIGl0IGFzc3VtZXMgaWYgdGhlXG4gICAgICAgIC8vIGlucHV0cyBhcmd1bWVudHMgZXhpc3RzLCBpdCBjb250YWlucyB2YWx1ZXNcbiAgICAgICAgemVyb0NvbmZVbnNwZW50VHhJZHMgPSB1bmRlZmluZWQ7XG4gICAgICB9XG5cbiAgICAgIC8vIEZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eSwgcmVzcGVjdCB0aGUgb2xkIHNwbGl0Q2hhbmdlU2l6ZT0wIHBhcmFtZXRlclxuICAgICAgaWYgKCFwYXJhbXMubm9TcGxpdENoYW5nZSAmJiBwYXJhbXMuc3BsaXRDaGFuZ2VTaXplICE9PSAwKSB7XG4gICAgICAgIGV4dHJhQ2hhbmdlQW1vdW50cyA9IHJlc3VsdHMuZXh0cmFDaGFuZ2VBbW91bnRzIHx8IFtdO1xuICAgICAgfVxuICAgIH0pO1xuICB9O1xuXG4gIC8vIEdldCB0aGUgdW5zcGVudHMgZm9yIHRoZSBzaW5nbGUga2V5IGZlZSBhZGRyZXNzXG4gIGxldCBmZWVTaW5nbGVLZXlVbnNwZW50czogQml0R29VbnNwZW50W10gPSBbXTtcbiAgY29uc3QgZ2V0VW5zcGVudHNGb3JTaW5nbGVLZXkgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKGZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MpIHtcbiAgICAgIGxldCBmZWVUYXJnZXQgPSAwLjAxZTg7XG4gICAgICBpZiAocGFyYW1zLmluc3RhbnQpIHtcbiAgICAgICAgZmVlVGFyZ2V0ICs9IHRvdGFsQW1vdW50ICogMC4wMDE7XG4gICAgICB9XG4gICAgICByZXR1cm4gYml0Z29cbiAgICAgICAgLmdldChiaXRnby51cmwoJy9hZGRyZXNzLycgKyBmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzICsgJy91bnNwZW50cz90YXJnZXQ9JyArIGZlZVRhcmdldCkpXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgIGlmIChyZXNwb25zZS5ib2R5LnRvdGFsIDw9IDApIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gdW5zcGVudHMgYXZhaWxhYmxlIGluIHNpbmdsZSBrZXkgZmVlIHNvdXJjZScpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBmZWVTaW5nbGVLZXlVbnNwZW50cyA9IHJlc3BvbnNlLmJvZHkudW5zcGVudHM7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgfTtcblxuICBsZXQgbWluZXJGZWVJbmZvOiBhbnkgPSB7fTtcbiAgbGV0IHR4SW5mbzogYW55ID0ge307XG5cbiAgLy8gSXRlcmF0ZSB1bnNwZW50cywgc3VtIHRoZSBpbnB1dHMsIGFuZCBzYXZlIF9pbnB1dHMgd2l0aCB0aGUgdG90YWxcbiAgLy8gaW5wdXQgYW1vdW50IGFuZCBmaW5hbCBsaXN0IG9mIGlucHV0cyB0byB1c2Ugd2l0aCB0aGUgdHJhbnNhY3Rpb24uXG4gIGxldCBmZWVTaW5nbGVLZXlVbnNwZW50c1VzZWQ6IEJpdEdvVW5zcGVudFtdID0gW107XG5cbiAgY29uc3QgY29sbGVjdElucHV0cyA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXVuc3BlbnRzLmxlbmd0aCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdubyB1bnNwZW50cyBhdmFpbGFibGUgb24gd2FsbGV0Jyk7XG4gICAgfVxuICAgIGlucHV0QW1vdW50ID0gMDtcblxuICAgIC8vIENhbGN1bGF0ZSB0aGUgY29zdCBvZiBzcGVuZGluZyBhIHNpbmdsZSBpbnB1dCwgaS5lLiB0aGUgc21hbGxlc3QgZWNvbm9taWNhbCB1bnNwZW50IHZhbHVlXG4gICAgcmV0dXJuIEJsdWViaXJkLnRyeShmdW5jdGlvbiAoKSB7XG4gICAgICBpZiAoXy5pc051bWJlcihwYXJhbXMuZmVlUmF0ZSkgfHwgXy5pc051bWJlcihwYXJhbXMub3JpZ2luYWxGZWVSYXRlKSkge1xuICAgICAgICByZXR1cm4gIV8uaXNVbmRlZmluZWQocGFyYW1zLmZlZVJhdGUpID8gcGFyYW1zLmZlZVJhdGUgOiBwYXJhbXMub3JpZ2luYWxGZWVSYXRlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGJpdGdvXG4gICAgICAgICAgLmVzdGltYXRlRmVlKHtcbiAgICAgICAgICAgIG51bUJsb2NrczogcGFyYW1zLmZlZVR4Q29uZmlybVRhcmdldCxcbiAgICAgICAgICAgIG1heEZlZTogcGFyYW1zLm1heEZlZVJhdGUsXG4gICAgICAgICAgfSlcbiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZmVlUmF0ZUVzdGltYXRlKSB7XG4gICAgICAgICAgICByZXR1cm4gZmVlUmF0ZUVzdGltYXRlLmZlZVBlcktiO1xuICAgICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pXG4gICAgICAudGhlbihmdW5jdGlvbiAoZmVlUmF0ZSkge1xuICAgICAgICAvLyBEb24ndCBzcGVuZCBpbnB1dHMgdGhhdCBjYW5ub3QgcGF5IGZvciB0aGVpciBvd24gY29zdC5cbiAgICAgICAgbGV0IG1pbklucHV0VmFsdWUgPSAwO1xuICAgICAgICBpZiAoXy5pc0ludGVnZXIocGFyYW1zLm1pblVuc3BlbnRTaXplKSkge1xuICAgICAgICAgIG1pbklucHV0VmFsdWUgPSBwYXJhbXMubWluVW5zcGVudFNpemU7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgcHJ1bmVkVW5zcGVudENvdW50ID0gMDtcbiAgICAgICAgY29uc3Qgb3JpZ2luYWxVbnNwZW50Q291bnQgPSB1bnNwZW50cy5sZW5ndGg7XG4gICAgICAgIHVuc3BlbnRzID0gXy5maWx0ZXIodW5zcGVudHMsIGZ1bmN0aW9uICh1bnNwZW50KSB7XG4gICAgICAgICAgY29uc3QgaXNTZWd3aXRJbnB1dCA9ICEhdW5zcGVudC53aXRuZXNzU2NyaXB0O1xuICAgICAgICAgIGNvbnN0IGN1cnJlbnRJbnB1dFNpemUgPSBpc1NlZ3dpdElucHV0ID8gVmlydHVhbFNpemVzLnR4UDJzaFAyd3NoSW5wdXRTaXplIDogVmlydHVhbFNpemVzLnR4UDJzaElucHV0U2l6ZTtcbiAgICAgICAgICBjb25zdCBmZWVCYXNlZE1pbklucHV0VmFsdWUgPSAoZmVlUmF0ZSAqIGN1cnJlbnRJbnB1dFNpemUpIC8gMTAwMDtcbiAgICAgICAgICBjb25zdCBjdXJyZW50TWluSW5wdXRWYWx1ZSA9IE1hdGgubWF4KG1pbklucHV0VmFsdWUsIGZlZUJhc2VkTWluSW5wdXRWYWx1ZSk7XG4gICAgICAgICAgaWYgKGN1cnJlbnRNaW5JbnB1dFZhbHVlID4gdW5zcGVudC52YWx1ZSkge1xuICAgICAgICAgICAgLy8gcHJ1bmluZyB1bnNwZW50XG4gICAgICAgICAgICBjb25zdCBwcnVuZURldGFpbHMgPSB7XG4gICAgICAgICAgICAgIGdlbmVyYWxNaW5JbnB1dFZhbHVlOiBtaW5JbnB1dFZhbHVlLFxuICAgICAgICAgICAgICBmZWVCYXNlZE1pbklucHV0VmFsdWUsXG4gICAgICAgICAgICAgIGN1cnJlbnRNaW5JbnB1dFZhbHVlLFxuICAgICAgICAgICAgICBmZWVSYXRlLFxuICAgICAgICAgICAgICBpbnB1dFNpemU6IGN1cnJlbnRJbnB1dFNpemUsXG4gICAgICAgICAgICAgIHVuc3BlbnQ6IHVuc3BlbnQsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgY29uc29sZS5sb2coYHBydW5pbmcgdW5zcGVudDogJHtKU09OLnN0cmluZ2lmeShwcnVuZURldGFpbHMsIG51bGwsIDQpfWApO1xuICAgICAgICAgICAgcHJ1bmVkVW5zcGVudENvdW50Kys7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAocHJ1bmVkVW5zcGVudENvdW50ID4gMCkge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGBwcnVuZWQgJHtwcnVuZWRVbnNwZW50Q291bnR9IG91dCBvZiAke29yaWdpbmFsVW5zcGVudENvdW50fSB1bnNwZW50c2ApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHVuc3BlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignaW5zdWZmaWNpZW50IGZ1bmRzJyk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHNlZ3dpdElucHV0Q291bnQgPSAwO1xuICAgICAgICB1bnNwZW50cy5ldmVyeShmdW5jdGlvbiAodW5zcGVudCkge1xuICAgICAgICAgIGlmICh1bnNwZW50LndpdG5lc3NTY3JpcHQpIHtcbiAgICAgICAgICAgIHNlZ3dpdElucHV0Q291bnQrKztcbiAgICAgICAgICB9XG4gICAgICAgICAgaW5wdXRBbW91bnQgKz0gdW5zcGVudC52YWx1ZTtcbiAgICAgICAgICB0cmFuc2FjdGlvbi5hZGRJbnB1dCh1bnNwZW50LnR4X2hhc2gsIHVuc3BlbnQudHhfb3V0cHV0X24sIDB4ZmZmZmZmZmYpO1xuXG4gICAgICAgICAgcmV0dXJuIGlucHV0QW1vdW50IDwgKGZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MgPyB0b3RhbE91dHB1dEFtb3VudCA6IHRvdGFsQW1vdW50KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gaWYgcGF5aW5nIGZlZXMgZnJvbSBhbiBleHRlcm5hbCBzaW5nbGUga2V5IHdhbGxldCwgYWRkIHRoZSBpbnB1dHNcbiAgICAgICAgaWYgKGZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MpIHtcbiAgICAgICAgICAvLyBjb2xsZWN0IHRoZSBhbW91bnQgdXNlZCBpbiB0aGUgZmVlIGlucHV0cyBzbyB3ZSBjYW4gZ2V0IGNoYW5nZSBsYXRlclxuICAgICAgICAgIGZlZVNpbmdsZUtleUlucHV0QW1vdW50ID0gMDtcbiAgICAgICAgICBmZWVTaW5nbGVLZXlVbnNwZW50c1VzZWQgPSBbXTtcbiAgICAgICAgICBmZWVTaW5nbGVLZXlVbnNwZW50cy5ldmVyeShmdW5jdGlvbiAodW5zcGVudCkge1xuICAgICAgICAgICAgZmVlU2luZ2xlS2V5SW5wdXRBbW91bnQgKz0gdW5zcGVudC52YWx1ZTtcbiAgICAgICAgICAgIGlucHV0QW1vdW50ICs9IHVuc3BlbnQudmFsdWU7XG4gICAgICAgICAgICB0cmFuc2FjdGlvbi5hZGRJbnB1dCh1bnNwZW50LnR4X2hhc2gsIHVuc3BlbnQudHhfb3V0cHV0X24pO1xuICAgICAgICAgICAgZmVlU2luZ2xlS2V5VW5zcGVudHNVc2VkLnB1c2godW5zcGVudCk7XG4gICAgICAgICAgICAvLyB1c2UgdGhlIGZlZSB3YWxsZXQgdG8gcGF5IG1pbmVyIGZlZXMgYW5kIHBvdGVudGlhbGx5IGluc3RhbnQgZmVlc1xuICAgICAgICAgICAgcmV0dXJuIGZlZVNpbmdsZUtleUlucHV0QW1vdW50IDwgZmVlICsgKGJpdGdvRmVlSW5mbyA/IGJpdGdvRmVlSW5mby5hbW91bnQgOiAwKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHR4SW5mbyA9IHtcbiAgICAgICAgICBuUDJzaElucHV0czogdHJhbnNhY3Rpb24udHguaW5zLmxlbmd0aCAtIChmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzID8gMSA6IDApIC0gc2Vnd2l0SW5wdXRDb3VudCxcbiAgICAgICAgICBuUDJzaFAyd3NoSW5wdXRzOiBzZWd3aXRJbnB1dENvdW50LFxuICAgICAgICAgIG5QMnBraElucHV0czogZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcyA/IDEgOiAwLFxuICAgICAgICAgIC8vIGFkZCBzaW5nbGUga2V5IHNvdXJjZSBhZGRyZXNzIGNoYW5nZVxuICAgICAgICAgIG5PdXRwdXRzOlxuICAgICAgICAgICAgcmVjaXBpZW50cy5sZW5ndGggK1xuICAgICAgICAgICAgMSArIC8vIHJlY2lwaWVudHMgYW5kIGNoYW5nZVxuICAgICAgICAgICAgZXh0cmFDaGFuZ2VBbW91bnRzLmxlbmd0aCArIC8vIGV4dHJhIGNoYW5nZSBzcGxpdHRpbmdcbiAgICAgICAgICAgIChiaXRnb0ZlZUluZm8gJiYgYml0Z29GZWVJbmZvLmFtb3VudCA+IDAgPyAxIDogMCkgKyAvLyBhZGQgb3V0cHV0IGZvciBiaXRnbyBmZWVcbiAgICAgICAgICAgIChmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzID8gMSA6IDApLFxuICAgICAgICB9O1xuXG4gICAgICAgIGVzdFR4U2l6ZSA9IGVzdGltYXRlVHJhbnNhY3Rpb25TaXplKHtcbiAgICAgICAgICBuUDJzaElucHV0czogdHhJbmZvLm5QMnNoSW5wdXRzLFxuICAgICAgICAgIG5QMnNoUDJ3c2hJbnB1dHM6IHR4SW5mby5uUDJzaFAyd3NoSW5wdXRzLFxuICAgICAgICAgIG5QMnBraElucHV0czogdHhJbmZvLm5QMnBraElucHV0cyxcbiAgICAgICAgICBuT3V0cHV0czogdHhJbmZvLm5PdXRwdXRzLFxuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgICAudGhlbihnZXREeW5hbWljRmVlUmF0ZUVzdGltYXRlKVxuICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICBtaW5lckZlZUluZm8gPSBleHBvcnRzLmNhbGN1bGF0ZU1pbmVyRmVlSW5mbyh7XG4gICAgICAgICAgYml0Z286IHBhcmFtcy53YWxsZXQuYml0Z28sXG4gICAgICAgICAgZmVlUmF0ZTogZmVlUmF0ZSxcbiAgICAgICAgICBuUDJzaElucHV0czogdHhJbmZvLm5QMnNoSW5wdXRzLFxuICAgICAgICAgIG5QMnNoUDJ3c2hJbnB1dHM6IHR4SW5mby5uUDJzaFAyd3NoSW5wdXRzLFxuICAgICAgICAgIG5QMnBraElucHV0czogdHhJbmZvLm5QMnBraElucHV0cyxcbiAgICAgICAgICBuT3V0cHV0czogdHhJbmZvLm5PdXRwdXRzLFxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoc2hvdWxkQ29tcHV0ZUJlc3RGZWUpIHtcbiAgICAgICAgICBjb25zdCBhcHByb3hpbWF0ZUZlZSA9IG1pbmVyRmVlSW5mby5mZWU7XG4gICAgICAgICAgY29uc3Qgc2hvdWxkUmVjdXJzZSA9IF8uaXNVbmRlZmluZWQoZmVlKSB8fCBhcHByb3hpbWF0ZUZlZSA+IGZlZTtcbiAgICAgICAgICBmZWUgPSBhcHByb3hpbWF0ZUZlZTtcbiAgICAgICAgICAvLyBSZWNvbXB1dGUgdG90YWxBbW91bnQgZnJvbSBzY3JhdGNoXG4gICAgICAgICAgdG90YWxBbW91bnQgPSBmZWUgKyB0b3RhbE91dHB1dEFtb3VudDtcbiAgICAgICAgICBpZiAoYml0Z29GZWVJbmZvKSB7XG4gICAgICAgICAgICB0b3RhbEFtb3VudCArPSBiaXRnb0ZlZUluZm8uYW1vdW50O1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoc2hvdWxkUmVjdXJzZSkge1xuICAgICAgICAgICAgLy8gaWYgZmVlIGNoYW5nZWQsIHJlLWNvbGxlY3QgaW5wdXRzXG4gICAgICAgICAgICBpbnB1dEFtb3VudCA9IDA7XG4gICAgICAgICAgICB0cmFuc2FjdGlvbiA9IHV0eG9saWIuYml0Z28uY3JlYXRlVHJhbnNhY3Rpb25CdWlsZGVyRm9yTmV0d29yayhuZXR3b3JrKTtcbiAgICAgICAgICAgIHJldHVybiBjb2xsZWN0SW5wdXRzKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdG90YWxGZWUgPSBmZWUgKyAoYml0Z29GZWVJbmZvID8gYml0Z29GZWVJbmZvLmFtb3VudCA6IDApO1xuXG4gICAgICAgIGlmIChmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzKSB7XG4gICAgICAgICAgY29uc3Qgc3VtbWVkU2luZ2xlS2V5VW5zcGVudHMgPSBfLnN1bUJ5KGZlZVNpbmdsZUtleVVuc3BlbnRzLCAndmFsdWUnKTtcbiAgICAgICAgICBpZiAodG90YWxGZWUgPiBzdW1tZWRTaW5nbGVLZXlVbnNwZW50cykge1xuICAgICAgICAgICAgY29uc3QgZXJyOiBhbnkgPSBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICdJbnN1ZmZpY2llbnQgZmVlIGFtb3VudCBhdmFpbGFibGUgaW4gc2luZ2xlIGtleSBmZWUgc291cmNlOiAnICsgc3VtbWVkU2luZ2xlS2V5VW5zcGVudHNcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBlcnIucmVzdWx0ID0ge1xuICAgICAgICAgICAgICBmZWU6IGZlZSxcbiAgICAgICAgICAgICAgZmVlUmF0ZTogZmVlUmF0ZSxcbiAgICAgICAgICAgICAgZXN0aW1hdGVkU2l6ZTogbWluZXJGZWVJbmZvLnNpemUsXG4gICAgICAgICAgICAgIGF2YWlsYWJsZTogaW5wdXRBbW91bnQsXG4gICAgICAgICAgICAgIGJpdGdvRmVlOiBiaXRnb0ZlZUluZm8sXG4gICAgICAgICAgICAgIHR4SW5mbzogdHhJbmZvLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBCbHVlYmlyZC5yZWplY3QoZXJyKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5wdXRBbW91bnQgPCAoZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcyA/IHRvdGFsT3V0cHV0QW1vdW50IDogdG90YWxBbW91bnQpKSB7XG4gICAgICAgICAgLy8gVGhlIHVuc3BlbnRzIHdlJ3JlIHVzaW5nIGZvciBpbnB1dHMgZG8gbm90IGhhdmUgc3VmZmljaWVudCB2YWx1ZSBvbiB0aGVtIHRvXG4gICAgICAgICAgLy8gc2F0aXNmeSB0aGUgdXNlcidzIHJlcXVlc3RlZCBzcGVuZCBhbW91bnQuIFRoYXQgbWF5IGJlIGJlY2F1c2UgdGhlIHdhbGxldCdzIGJhbGFuY2VcbiAgICAgICAgICAvLyBpcyBzaW1wbHkgdG9vIGxvdywgb3IgaXQgbWlnaHQgYmUgdGhhdCB0aGUgd2FsbGV0J3MgYmFsYW5jZSBpcyBzdWZmaWNpZW50IGJ1dFxuICAgICAgICAgIC8vIHdlIGRpZG4ndCBmZXRjaCBlbm91Z2ggdW5zcGVudHMuIFRvbyBmZXcgdW5zcGVudHMgY291bGQgcmVzdWx0IGZyb20gdGhlIHdhbGxldFxuICAgICAgICAgIC8vIGhhdmluZyBtYW55IHNtYWxsIHVuc3BlbnRzIGFuZCB3ZSBoaXQgb3VyIGxpbWl0IG9uIHRoZSBudW1iZXIgb2YgaW5wdXRzIHdlIGNhbiB1c2VcbiAgICAgICAgICAvLyBpbiBhIHR4biwgb3IgaXQgbWlnaHQgaGF2ZSBiZWVuIHRoYXQgdGhlIGZpbHRlcnMgdGhlIHVzZXIgcGFzc2VkIGluIChsaWtlIG1pbkNvbmZpcm1zKVxuICAgICAgICAgIC8vIGRpc3F1YWxpZmllZCB0b28gbWFueSBvZiB0aGUgdW5zcGVudHNcbiAgICAgICAgICBsZXQgZXJyO1xuICAgICAgICAgIGlmICh0b3RhbFVuc3BlbnRzQ291bnQgPT09IGZldGNoZWRVbnNwZW50c0NvdW50KSB7XG4gICAgICAgICAgICAvLyB3ZSBmZXRjaGVkIGV2ZXJ5IHVuc3BlbnQgdGhlIHdhbGxldCBoYWQsIGJ1dCBpdCBzdGlsbCB3YXNuJ3QgZW5vdWdoXG4gICAgICAgICAgICBlcnIgPSBuZXcgRXJyb3IoJ0luc3VmZmljaWVudCBmdW5kcycpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyB3ZSB3ZXJlbid0IGFibGUgdG8gZmV0Y2ggYWxsIHRoZSB1bnNwZW50cyBvbiB0aGUgd2FsbGV0XG4gICAgICAgICAgICBlcnIgPSBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgIGBUcmFuc2FjdGlvbiBzaXplIHRvbyBsYXJnZSBkdWUgdG8gdG9vIG1hbnkgdW5zcGVudHMuIENhbiBzZW5kIG9ubHkgJHtpbnB1dEFtb3VudH0gc2F0b3NoaXMgaW4gdGhpcyB0cmFuc2FjdGlvbmBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGVyci5yZXN1bHQgPSB7XG4gICAgICAgICAgICBmZWU6IGZlZSxcbiAgICAgICAgICAgIGZlZVJhdGU6IGZlZVJhdGUsXG4gICAgICAgICAgICBlc3RpbWF0ZWRTaXplOiBtaW5lckZlZUluZm8uc2l6ZSxcbiAgICAgICAgICAgIGF2YWlsYWJsZTogaW5wdXRBbW91bnQsXG4gICAgICAgICAgICBiaXRnb0ZlZTogYml0Z29GZWVJbmZvLFxuICAgICAgICAgICAgdHhJbmZvOiB0eEluZm8sXG4gICAgICAgICAgfTtcbiAgICAgICAgICByZXR1cm4gQmx1ZWJpcmQucmVqZWN0KGVycik7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICB9O1xuXG4gIC8vIEFkZCB0aGUgb3V0cHV0cyBmb3IgdGhpcyB0cmFuc2FjdGlvbi5cbiAgY29uc3QgY29sbGVjdE91dHB1dHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKG1pbmVyRmVlSW5mby5zaXplID49IDkwMDAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3RyYW5zYWN0aW9uIHRvbyBsYXJnZTogZXN0aW1hdGVkIHNpemUgJyArIG1pbmVyRmVlSW5mby5zaXplICsgJyBieXRlcycpO1xuICAgIH1cblxuICAgIGNvbnN0IG91dHB1dHM6IE91dHB1dFtdID0gW107XG5cbiAgICByZWNpcGllbnRzLmZvckVhY2goZnVuY3Rpb24gKHJlY2lwaWVudCkge1xuICAgICAgbGV0IHNjcmlwdDtcbiAgICAgIGlmIChfLmlzU3RyaW5nKHJlY2lwaWVudC5hZGRyZXNzKSkge1xuICAgICAgICBzY3JpcHQgPSB1dHhvbGliLmFkZHJlc3MudG9PdXRwdXRTY3JpcHQocmVjaXBpZW50LmFkZHJlc3MsIG5ldHdvcmspO1xuICAgICAgfSBlbHNlIGlmIChfLmlzT2JqZWN0KHJlY2lwaWVudC5zY3JpcHQpKSB7XG4gICAgICAgIHNjcmlwdCA9IHJlY2lwaWVudC5zY3JpcHQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ25laXRoZXIgcmVjaXBpZW50IGFkZHJlc3Mgbm9yIHNjcmlwdCB3YXMgcHJvdmlkZWQnKTtcbiAgICAgIH1cblxuICAgICAgLy8gdmFsaWRhdGUgdHJhdmVsSW5mbyBpZiBpdCBleGlzdHNcbiAgICAgIGxldCB0cmF2ZWxJbmZvO1xuICAgICAgaWYgKCFfLmlzRW1wdHkocmVjaXBpZW50LnRyYXZlbEluZm8pKSB7XG4gICAgICAgIHRyYXZlbEluZm8gPSByZWNpcGllbnQudHJhdmVsSW5mbztcbiAgICAgICAgLy8gQmV0dGVyIHRvIGF2b2lkIHRyb3VibGUgbm93LCBiZWZvcmUgdHggaXMgY3JlYXRlZFxuICAgICAgICBiaXRnby50cmF2ZWxSdWxlKCkudmFsaWRhdGVUcmF2ZWxJbmZvKHRyYXZlbEluZm8pO1xuICAgICAgfVxuXG4gICAgICBvdXRwdXRzLnB1c2goe1xuICAgICAgICBzY3JpcHQ6IHNjcmlwdCxcbiAgICAgICAgYW1vdW50OiByZWNpcGllbnQuYW1vdW50LFxuICAgICAgICB0cmF2ZWxJbmZvOiB0cmF2ZWxJbmZvLFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBvcFJldHVybnMuZm9yRWFjaChmdW5jdGlvbiAoeyBtZXNzYWdlLCBhbW91bnQgfSkge1xuICAgICAgY29uc3Qgc2NyaXB0ID0gdXR4b2xpYi5zY3JpcHQuZnJvbUFTTSgnT1BfUkVUVVJOICcgKyBCdWZmZXIuZnJvbShtZXNzYWdlKS50b1N0cmluZygnaGV4JykpO1xuICAgICAgb3V0cHV0cy5wdXNoKHsgc2NyaXB0LCBhbW91bnQgfSk7XG4gICAgfSk7XG5cbiAgICBjb25zdCBnZXRDaGFuZ2VPdXRwdXRzID0gZnVuY3Rpb24gKGNoYW5nZUFtb3VudDogbnVtYmVyKTogT3V0cHV0W10gfCBCbHVlYmlyZDxPdXRwdXRbXT4ge1xuICAgICAgaWYgKGNoYW5nZUFtb3VudCA8IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCduZWdhdGl2ZSBjaGFuZ2UgYW1vdW50OiAnICsgY2hhbmdlQW1vdW50KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVzdWx0OiBPdXRwdXRbXSA9IFtdO1xuICAgICAgLy8gaWYgd2UgcGFpZCBmZWVzIGZyb20gYSBzaW5nbGUga2V5IHdhbGxldCwgcmV0dXJuIHRoZSBmZWUgY2hhbmdlIGZpcnN0XG4gICAgICBpZiAoZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcykge1xuICAgICAgICBjb25zdCBmZWVTaW5nbGVLZXlXYWxsZXRDaGFuZ2VBbW91bnQgPVxuICAgICAgICAgIGZlZVNpbmdsZUtleUlucHV0QW1vdW50IC0gKGZlZSArIChiaXRnb0ZlZUluZm8gPyBiaXRnb0ZlZUluZm8uYW1vdW50IDogMCkpO1xuICAgICAgICBpZiAoZmVlU2luZ2xlS2V5V2FsbGV0Q2hhbmdlQW1vdW50ID49IGNvbnN0YW50cy5taW5PdXRwdXRTaXplKSB7XG4gICAgICAgICAgcmVzdWx0LnB1c2goeyBhZGRyZXNzOiBmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzLCBhbW91bnQ6IGZlZVNpbmdsZUtleVdhbGxldENoYW5nZUFtb3VudCB9KTtcbiAgICAgICAgICBjaGFuZ2VBbW91bnQgPSBjaGFuZ2VBbW91bnQgLSBmZWVTaW5nbGVLZXlXYWxsZXRDaGFuZ2VBbW91bnQ7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKGNoYW5nZUFtb3VudCA8IGNvbnN0YW50cy5taW5PdXRwdXRTaXplKSB7XG4gICAgICAgIC8vIEdpdmUgaXQgdG8gdGhlIG1pbmVyc1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfVxuXG4gICAgICBpZiAocGFyYW1zLndhbGxldC50eXBlKCkgPT09ICdzYWZlJykge1xuICAgICAgICByZXR1cm4gcGFyYW1zLndhbGxldC5hZGRyZXNzZXMoKS50aGVuKGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgIHJlc3VsdC5wdXNoKHsgYWRkcmVzczogcmVzcG9uc2UuYWRkcmVzc2VzWzBdLmFkZHJlc3MsIGFtb3VudDogY2hhbmdlQW1vdW50IH0pO1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBsZXQgZXh0cmFDaGFuZ2VUb3RhbCA9IF8uc3VtKGV4dHJhQ2hhbmdlQW1vdW50cyk7XG4gICAgICAvLyBTYW5pdHkgY2hlY2tcbiAgICAgIGlmIChleHRyYUNoYW5nZVRvdGFsID4gY2hhbmdlQW1vdW50KSB7XG4gICAgICAgIGV4dHJhQ2hhbmdlQW1vdW50cyA9IFtdO1xuICAgICAgICBleHRyYUNoYW5nZVRvdGFsID0gMDtcbiAgICAgIH1cblxuICAgICAgLy8gY29weSBhbmQgYWRkIHJlbWFpbmluZyBjaGFuZ2UgYW1vdW50XG4gICAgICBjb25zdCBhbGxDaGFuZ2VBbW91bnRzID0gZXh0cmFDaGFuZ2VBbW91bnRzLnNsaWNlKDApO1xuICAgICAgYWxsQ2hhbmdlQW1vdW50cy5wdXNoKGNoYW5nZUFtb3VudCAtIGV4dHJhQ2hhbmdlVG90YWwpO1xuXG4gICAgICAvLyBSZWN1cnNpdmUgYXN5bmMgZnVuYyB0byBhZGQgYWxsIGNoYW5nZSBvdXRwdXRzXG4gICAgICBjb25zdCBhZGRDaGFuZ2VPdXRwdXRzID0gZnVuY3Rpb24gKCk6IE91dHB1dFtdIHwgQmx1ZWJpcmQ8T3V0cHV0W10+IHtcbiAgICAgICAgY29uc3QgdGhpc0Ftb3VudCA9IGFsbENoYW5nZUFtb3VudHMuc2hpZnQoKTtcbiAgICAgICAgaWYgKCF0aGlzQW1vdW50KSB7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gQmx1ZWJpcmQudHJ5KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBpZiAocGFyYW1zLmNoYW5nZUFkZHJlc3MpIHtcbiAgICAgICAgICAgIC8vIElmIHVzZXIgcGFzc2VkIGEgY2hhbmdlIGFkZHJlc3MsIHVzZSBpdCBmb3IgYWxsIG91dHB1dHNcbiAgICAgICAgICAgIHJldHVybiBwYXJhbXMuY2hhbmdlQWRkcmVzcztcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gT3RoZXJ3aXNlIGNyZWF0ZSBhIG5ldyBhZGRyZXNzIHBlciBvdXRwdXQsIGZvciBwcml2YWN5XG4gICAgICAgICAgICAvLyBkZXRlcm1pbmUgaWYgc2Vnd2l0IG9yIG5vdFxuICAgICAgICAgICAgY29uc3QgY2hhbmdlQ2hhaW4gPSBwYXJhbXMud2FsbGV0LmdldENoYW5nZUNoYWluKHBhcmFtcyk7XG4gICAgICAgICAgICByZXR1cm4gcGFyYW1zLndhbGxldC5jcmVhdGVBZGRyZXNzKHsgY2hhaW46IGNoYW5nZUNoYWluLCB2YWxpZGF0ZTogdmFsaWRhdGUgfSkudGhlbihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgIHJldHVybiByZXN1bHQuYWRkcmVzcztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAoYWRkcmVzcykge1xuICAgICAgICAgIHJlc3VsdC5wdXNoKHsgYWRkcmVzczogYWRkcmVzcywgYW1vdW50OiB0aGlzQW1vdW50IH0pO1xuICAgICAgICAgIHJldHVybiBhZGRDaGFuZ2VPdXRwdXRzKCk7XG4gICAgICAgIH0pO1xuICAgICAgfTtcblxuICAgICAgcmV0dXJuIGFkZENoYW5nZU91dHB1dHMoKTtcbiAgICB9O1xuXG4gICAgLy8gQWRkIGNoYW5nZSBvdXRwdXQocykgYW5kIGluc3RhbnQgZmVlIG91dHB1dCBpZiBhcHBsaWNhYmxlXG4gICAgcmV0dXJuIEJsdWViaXJkLnRyeShmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gZ2V0Q2hhbmdlT3V0cHV0cyhpbnB1dEFtb3VudCAtIHRvdGFsQW1vdW50KTtcbiAgICB9KS50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgIGNoYW5nZU91dHB1dHMgPSByZXN1bHQ7XG4gICAgICBjb25zdCBleHRyYU91dHB1dHMgPSBjaGFuZ2VPdXRwdXRzLmNvbmNhdChbXSk7IC8vIGNvcHkgdGhlIGFycmF5XG4gICAgICBpZiAoYml0Z29GZWVJbmZvICYmIGJpdGdvRmVlSW5mby5hbW91bnQgPiAwKSB7XG4gICAgICAgIGV4dHJhT3V0cHV0cy5wdXNoKGJpdGdvRmVlSW5mbyk7XG4gICAgICB9XG4gICAgICBleHRyYU91dHB1dHMuZm9yRWFjaChmdW5jdGlvbiAob3V0cHV0KSB7XG4gICAgICAgIGlmICgob3V0cHV0IGFzIEFkZHJlc3NPdXRwdXQpLmFkZHJlc3MpIHtcbiAgICAgICAgICAob3V0cHV0IGFzIFNjcmlwdE91dHB1dCkuc2NyaXB0ID0gdXR4b2xpYi5hZGRyZXNzLnRvT3V0cHV0U2NyaXB0KChvdXRwdXQgYXMgQWRkcmVzc091dHB1dCkuYWRkcmVzcywgbmV0d29yayk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkZWNpZGUgd2hlcmUgdG8gcHV0IHRoZSBvdXRwdXRzIC0gZGVmYXVsdCBpcyB0byByYW5kb21pemUgdW5sZXNzIGZvcmNlZCB0byBlbmRcbiAgICAgICAgY29uc3Qgb3V0cHV0SW5kZXggPSBwYXJhbXMuZm9yY2VDaGFuZ2VBdEVuZCA/IG91dHB1dHMubGVuZ3RoIDogXy5yYW5kb20oMCwgb3V0cHV0cy5sZW5ndGgpO1xuICAgICAgICBvdXRwdXRzLnNwbGljZShvdXRwdXRJbmRleCwgMCwgb3V0cHV0KTtcbiAgICAgIH0pO1xuXG4gICAgICAvLyBBZGQgYWxsIG91dHB1dHMgdG8gdGhlIHRyYW5zYWN0aW9uXG4gICAgICBvdXRwdXRzLmZvckVhY2goZnVuY3Rpb24gKG91dHB1dCkge1xuICAgICAgICB0cmFuc2FjdGlvbi5hZGRPdXRwdXQoKG91dHB1dCBhcyBTY3JpcHRPdXRwdXQpLnNjcmlwdCwgb3V0cHV0LmFtb3VudCk7XG4gICAgICB9KTtcblxuICAgICAgdHJhdmVsSW5mb3MgPSBfKG91dHB1dHMpXG4gICAgICAgIC5tYXAoZnVuY3Rpb24gKG91dHB1dCwgaW5kZXgpIHtcbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBvdXRwdXQudHJhdmVsSW5mbztcbiAgICAgICAgICBpZiAoIXJlc3VsdCkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmVzdWx0Lm91dHB1dEluZGV4ID0gaW5kZXg7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSlcbiAgICAgICAgLmZpbHRlcigpXG4gICAgICAgIC52YWx1ZSgpO1xuICAgIH0pO1xuICB9O1xuXG4gIC8vIFNlcmlhbGl6ZSB0aGUgdHJhbnNhY3Rpb24sIHJldHVybmluZyB3aGF0IGlzIG5lZWRlZCB0byBzaWduIGl0XG4gIGNvbnN0IHNlcmlhbGl6ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAvLyBvbmx5IG5lZWQgdG8gcmV0dXJuIHRoZSB1bnNwZW50cyB0aGF0IHdlcmUgdXNlZCBhbmQganVzdCB0aGUgY2hhaW5QYXRoLCByZWRlZW1TY3JpcHQsIGFuZCBpbnN0YW50IGZsYWdcbiAgICBjb25zdCBwaWNrZWRVbnNwZW50czogYW55ID0gXy5tYXAodW5zcGVudHMsIGZ1bmN0aW9uICh1bnNwZW50KSB7XG4gICAgICByZXR1cm4gXy5waWNrKHVuc3BlbnQsIFsnY2hhaW5QYXRoJywgJ3JlZGVlbVNjcmlwdCcsICdpbnN0YW50JywgJ3dpdG5lc3NTY3JpcHQnLCAnc2NyaXB0JywgJ3ZhbHVlJ10pO1xuICAgIH0pO1xuICAgIGNvbnN0IHBydW5lZFVuc3BlbnRzID0gXy5zbGljZShwaWNrZWRVbnNwZW50cywgMCwgdHJhbnNhY3Rpb24udHguaW5zLmxlbmd0aCAtIGZlZVNpbmdsZUtleVVuc3BlbnRzVXNlZC5sZW5ndGgpO1xuICAgIF8uZWFjaChmZWVTaW5nbGVLZXlVbnNwZW50c1VzZWQsIGZ1bmN0aW9uIChmZWVVbnNwZW50KSB7XG4gICAgICBwcnVuZWRVbnNwZW50cy5wdXNoKHsgcmVkZWVtU2NyaXB0OiBmYWxzZSwgY2hhaW5QYXRoOiBmYWxzZSB9KTsgLy8gbWFyayBhcyBmYWxzZSB0byBzaWduaWZ5IGEgbm9uLW11bHRpc2lnIGFkZHJlc3NcbiAgICB9KTtcbiAgICBjb25zdCByZXN1bHQ6IGFueSA9IHtcbiAgICAgIHRyYW5zYWN0aW9uSGV4OiB0cmFuc2FjdGlvbi5idWlsZEluY29tcGxldGUoKS50b0hleCgpLFxuICAgICAgdW5zcGVudHM6IHBydW5lZFVuc3BlbnRzLFxuICAgICAgZmVlOiBmZWUsXG4gICAgICBjaGFuZ2VBZGRyZXNzZXM6IGNoYW5nZU91dHB1dHMubWFwKGZ1bmN0aW9uIChjbykge1xuICAgICAgICByZXR1cm4gXy5waWNrKGNvLCBbJ2FkZHJlc3MnLCAncGF0aCcsICdhbW91bnQnXSk7XG4gICAgICB9KSxcbiAgICAgIHdhbGxldElkOiBwYXJhbXMud2FsbGV0LmlkKCksXG4gICAgICB3YWxsZXRLZXljaGFpbnM6IHBhcmFtcy53YWxsZXQua2V5Y2hhaW5zLFxuICAgICAgZmVlUmF0ZTogZmVlUmF0ZSxcbiAgICAgIGluc3RhbnQ6IHBhcmFtcy5pbnN0YW50LFxuICAgICAgYml0Z29GZWU6IGJpdGdvRmVlSW5mbyxcbiAgICAgIGVzdGltYXRlZFNpemU6IG1pbmVyRmVlSW5mby5zaXplLFxuICAgICAgdHhJbmZvOiB0eEluZm8sXG4gICAgICB0cmF2ZWxJbmZvczogdHJhdmVsSW5mb3MsXG4gICAgfTtcblxuICAgIC8vIEFkZCBmb3IgYmFja3dhcmRzIGNvbXBhdGliaWxpdHlcbiAgICBpZiAocmVzdWx0Lmluc3RhbnQgJiYgYml0Z29GZWVJbmZvKSB7XG4gICAgICByZXN1bHQuaW5zdGFudEZlZSA9IF8ucGljayhiaXRnb0ZlZUluZm8sIFsnYW1vdW50JywgJ2FkZHJlc3MnXSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfTtcblxuICByZXR1cm4gQmx1ZWJpcmQudHJ5KGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gZ2V0Qml0R29GZWUoKTtcbiAgfSlcbiAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gQmx1ZWJpcmQuYWxsKFtnZXRCaXRHb0ZlZUFkZHJlc3MoKSwgZ2V0VW5zcGVudHMoKSwgZ2V0VW5zcGVudHNGb3JTaW5nbGVLZXkoKV0pO1xuICAgIH0pXG4gICAgLnRoZW4oY29sbGVjdElucHV0cylcbiAgICAudGhlbihjb2xsZWN0T3V0cHV0cylcbiAgICAudGhlbihzZXJpYWxpemUpO1xufTtcblxuLyoqXG4gKiBFc3RpbWF0ZSB0aGUgc2l6ZSBvZiBhIHRyYW5zYWN0aW9uIGluIGJ5dGVzIGJhc2VkIG9uIHRoZSBudW1iZXIgb2ZcbiAqIGlucHV0cyBhbmQgb3V0cHV0cyBwcmVzZW50LlxuICogQHBhcmFtcyBwYXJhbXMge1xuICogICBuUDJzaElucHV0czogbnVtYmVyIG9mIFAyU0ggKG11bHRpc2lnKSBpbnB1dHNcbiAqICAgblAycGtoSW5wdXRzOiBudW1iZXIgb2YgUDJQS0ggKHNpbmdsZSBzaWcpIGlucHV0c1xuICogICBuT3V0cHV0czogbnVtYmVyIG9mIG91dHB1dHNcbiAqIH1cbiAqXG4gKiBAcmV0dXJucyBzaXplOiBlc3RpbWF0ZWQgc2l6ZSBvZiB0aGUgdHJhbnNhY3Rpb24gaW4gYnl0ZXNcbiAqL1xuY29uc3QgZXN0aW1hdGVUcmFuc2FjdGlvblNpemUgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gIGlmICghXy5pc0ludGVnZXIocGFyYW1zLm5QMnNoSW5wdXRzKSB8fCBwYXJhbXMublAyc2hJbnB1dHMgPCAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdleHBlY3RpbmcgcG9zaXRpdmUgblAyc2hJbnB1dHMnKTtcbiAgfVxuICBpZiAoIV8uaXNJbnRlZ2VyKHBhcmFtcy5uUDJwa2hJbnB1dHMpIHx8IHBhcmFtcy5uUDJwa2hJbnB1dHMgPCAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdleHBlY3RpbmcgcG9zaXRpdmUgblAycGtoSW5wdXRzIHRvIGJlIG51bWVyaWMnKTtcbiAgfVxuICBpZiAoIV8uaXNJbnRlZ2VyKHBhcmFtcy5uUDJzaFAyd3NoSW5wdXRzKSB8fCBwYXJhbXMublAyc2hQMndzaElucHV0cyA8IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cGVjdGluZyBwb3NpdGl2ZSBuUDJzaFAyd3NoSW5wdXRzIHRvIGJlIG51bWVyaWMnKTtcbiAgfVxuICBpZiAocGFyYW1zLm5QMnNoSW5wdXRzICsgcGFyYW1zLm5QMnNoUDJ3c2hJbnB1dHMgPCAxKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdleHBlY3RpbmcgYXQgbGVhc3Qgb25lIG5QMnNoSW5wdXRzIG9yIG5QMnNoUDJ3c2hJbnB1dHMnKTtcbiAgfVxuICBpZiAoIV8uaXNJbnRlZ2VyKHBhcmFtcy5uT3V0cHV0cykgfHwgcGFyYW1zLm5PdXRwdXRzIDwgMSkge1xuICAgIHRocm93IG5ldyBFcnJvcignZXhwZWN0aW5nIHBvc2l0aXZlIG5PdXRwdXRzJyk7XG4gIH1cblxuICBjb25zdCBlc3RpbWF0ZWRTaXplID1cbiAgICBWaXJ0dWFsU2l6ZXMudHhQMnNoSW5wdXRTaXplICogcGFyYW1zLm5QMnNoSW5wdXRzICtcbiAgICBWaXJ0dWFsU2l6ZXMudHhQMnNoUDJ3c2hJbnB1dFNpemUgKiAocGFyYW1zLm5QMnNoUDJ3c2hJbnB1dHMgfHwgMCkgK1xuICAgIFZpcnR1YWxTaXplcy50eFAycGtoSW5wdXRTaXplVW5jb21wcmVzc2VkS2V5ICogKHBhcmFtcy5uUDJwa2hJbnB1dHMgfHwgMCkgK1xuICAgIFZpcnR1YWxTaXplcy50eFAycGtoT3V0cHV0U2l6ZSAqIHBhcmFtcy5uT3V0cHV0cyArXG4gICAgLy8gaWYgdGhlIHR4IGNvbnRhaW5zIGF0IGxlYXN0IG9uZSBzZWd3aXQgaW5wdXQsIHRoZSB0eCBvdmVyaGVhZCBpcyBpbmNyZWFzZWQgYnkgMVxuICAgIFZpcnR1YWxTaXplcy50eE92ZXJoZWFkU2l6ZSArXG4gICAgKHBhcmFtcy5uUDJzaFAyd3NoSW5wdXRzID4gMCA/IDEgOiAwKTtcblxuICByZXR1cm4gZXN0aW1hdGVkU2l6ZTtcbn07XG5cbi8qKlxuICogQ2FsY3VsYXRlIHRoZSBmZWUgYW5kIGVzdGltYXRlZCBzaXplIGluIGJ5dGVzIGZvciBhIHRyYW5zYWN0aW9uLlxuICogQHBhcmFtcyBwYXJhbXMge1xuICogICBiaXRnbzogYml0Z28gb2JqZWN0XG4gKiAgIGZlZVJhdGU6IHNhdG9zaGlzIHBlciBraWxvYnl0ZVxuICogICBuUDJzaElucHV0czogbnVtYmVyIG9mIFAyU0ggKG11bHRpc2lnKSBpbnB1dHNcbiAqICAgblAycGtoSW5wdXRzOiBudW1iZXIgb2YgUDJQS0ggKHNpbmdsZSBzaWcpIGlucHV0c1xuICogICBuT3V0cHV0czogbnVtYmVyIG9mIG91dHB1dHNcbiAqIH1cbiAqXG4gKiBAcmV0dXJucyB7XG4gKiAgIHNpemU6IGVzdGltYXRlZCBzaXplIG9mIHRoZSB0cmFuc2FjdGlvbiBpbiBieXRlc1xuICogICBmZWU6IGVzdGltYXRlZCBmZWUgaW4gc2F0b3NoaXMgZm9yIHRoZSB0cmFuc2FjdGlvblxuICogICBmZWVSYXRlOiBmZWUgcmF0ZSB0aGF0IHdhcyB1c2VkIHRvIGVzdGltYXRlIHRoZSBmZWUgZm9yIHRoZSB0cmFuc2FjdGlvblxuICogfVxuICovXG5leHBvcnRzLmNhbGN1bGF0ZU1pbmVyRmVlSW5mbyA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgY29uc3QgZmVlUmF0ZVRvVXNlID0gcGFyYW1zLmZlZVJhdGUgfHwgcGFyYW1zLmJpdGdvLmdldENvbnN0YW50cygpLmZhbGxiYWNrRmVlUmF0ZTtcbiAgY29uc3QgZXN0aW1hdGVkU2l6ZSA9IGVzdGltYXRlVHJhbnNhY3Rpb25TaXplKHBhcmFtcyk7XG5cbiAgcmV0dXJuIHtcbiAgICBzaXplOiBlc3RpbWF0ZWRTaXplLFxuICAgIGZlZTogTWF0aC5jZWlsKChlc3RpbWF0ZWRTaXplICogZmVlUmF0ZVRvVXNlKSAvIDEwMDApLFxuICAgIGZlZVJhdGU6IGZlZVJhdGVUb1VzZSxcbiAgfTtcbn07XG5cbi8qXG4gKiBHaXZlbiBhIHRyYW5zYWN0aW9uIGhleCwgdW5zcGVudCBpbmZvcm1hdGlvbiAoY2hhaW4gcGF0aCBhbmQgcmVkZWVtIHNjcmlwdHMpLCBhbmQgdGhlIGtleWNoYWluIHhwcnYsXG4gKiBwZXJmb3JtIGtleSBkZXJpdmF0aW9uIGFuZCBzaWduIHRoZSBpbnB1dHMgaW4gdGhlIHRyYW5zYWN0aW9uIGJhc2VkIG9uIHRoZSB1bnNwZW50IGluZm9ybWF0aW9uIHByb3ZpZGVkXG4gKlxuICogQHBhcmFtczpcbiAqICB0cmFuc2FjdGlvbkhleCBzZXJpYWxpemVkIGZvcm0gb2YgdGhlIHRyYW5zYWN0aW9uIGluIGhleFxuICogIHVuc3BlbnRzIGFycmF5IG9mIHVuc3BlbnQgaW5mb3JtYXRpb24sIHdoZXJlIGVhY2ggdW5zcGVudCBpcyBhIGNoYWluUGF0aCBhbmQgcmVkZWVtU2NyaXB0IHdpdGggdGhlIHNhbWVcbiAqICBpbmRleCBhcyB0aGUgaW5wdXRzIGluIHRoZSB0cmFuc2FjdGlvbkhleFxuICogIGtleWNoYWluIEtleWNoYWluIGNvbnRhaW5pbmcgdGhlIHhwcnYgdG8gc2lnbiB3aXRoLiBGb3IgbGVnYWN5IHN1cHBvcnQgb2Ygc2FmZSB3YWxsZXRzLCBrZXljaGFpbiBjYW5cbiBhbHNvIGJlIGEgV0lGIHByaXZhdGUga2V5LlxuICogIHNpZ25pbmdLZXkgcHJpdmF0ZSBrZXkgaW4gV0lGIGZvciBzYWZlIHdhbGxldHMsIHdoZW4ga2V5Y2hhaW4gaXMgdW5hdmFpbGFibGVcbiAqICB2YWxpZGF0ZSBjbGllbnQtc2lkZSBzaWduYXR1cmUgdmVyaWZpY2F0aW9uIC0gY2FuIGJlIGRpc2FibGVkIGZvciBpbXByb3ZlZCBwZXJmb3JtYW5jZSAoc2lnbmF0dXJlc1xuICogICAgICAgICAgIGFyZSBzdGlsbCB2YWxpZGF0ZWQgc2VydmVyLXNpZGUpLlxuICogIGZlZVNpbmdsZUtleVdJRiBVc2UgdGhlIGFkZHJlc3MgYmFzZWQgb24gdGhpcyBwcml2YXRlIGtleSB0byBwYXkgZmVlc1xuICogQHJldHVybnMgeyp9XG4gKi9cbmV4cG9ydHMuc2lnblRyYW5zYWN0aW9uID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICBsZXQga2V5Y2hhaW4gPSBwYXJhbXMua2V5Y2hhaW47IC8vIGR1cGxpY2F0ZSBzbyBhcyB0byBub3QgbXV0YXRlIGJlbG93XG5cbiAgY29uc3QgdmFsaWRhdGUgPSBwYXJhbXMudmFsaWRhdGUgPT09IHVuZGVmaW5lZCA/IHRydWUgOiBwYXJhbXMudmFsaWRhdGU7XG4gIGxldCBwcml2S2V5O1xuICBpZiAoIV8uaXNTdHJpbmcocGFyYW1zLnRyYW5zYWN0aW9uSGV4KSkge1xuICAgIHRocm93IG5ldyBFcnJvcignZXhwZWN0aW5nIHRoZSB0cmFuc2FjdGlvbiBoZXggYXMgYSBzdHJpbmcnKTtcbiAgfVxuICBpZiAoIUFycmF5LmlzQXJyYXkocGFyYW1zLnVuc3BlbnRzKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignZXhwZWN0aW5nIHRoZSB1bnNwZW50cyBhcnJheScpO1xuICB9XG4gIGlmICghXy5pc0Jvb2xlYW4odmFsaWRhdGUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdleHBlY3RpbmcgdmFsaWRhdGUgdG8gYmUgYSBib29sZWFuJyk7XG4gIH1cbiAgbGV0IG5ldHdvcmsgPSBnZXROZXR3b3JrKCk7XG4gIGNvbnN0IGVuYWJsZUJDSCA9IF8uaXNCb29sZWFuKHBhcmFtcy5mb3JjZUJDSCkgJiYgcGFyYW1zLmZvcmNlQkNIID09PSB0cnVlO1xuXG4gIGlmICghXy5pc09iamVjdChrZXljaGFpbikgfHwgIV8uaXNTdHJpbmcoKGtleWNoYWluIGFzIGFueSkueHBydikpIHtcbiAgICBpZiAoXy5pc1N0cmluZyhwYXJhbXMuc2lnbmluZ0tleSkpIHtcbiAgICAgIHByaXZLZXkgPSB1dHhvbGliLkVDUGFpci5mcm9tV0lGKHBhcmFtcy5zaWduaW5nS2V5LCBuZXR3b3JrIGFzIHV0eG9saWIuQml0Y29pbkpTTmV0d29yayk7XG4gICAgICBrZXljaGFpbiA9IHVuZGVmaW5lZDtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdleHBlY3RpbmcgdGhlIGtleWNoYWluIG9iamVjdCB3aXRoIHhwcnYnKTtcbiAgICB9XG4gIH1cblxuICBsZXQgZmVlU2luZ2xlS2V5O1xuICBpZiAocGFyYW1zLmZlZVNpbmdsZUtleVdJRikge1xuICAgIGZlZVNpbmdsZUtleSA9IHV0eG9saWIuRUNQYWlyLmZyb21XSUYocGFyYW1zLmZlZVNpbmdsZUtleVdJRiwgbmV0d29yayBhcyB1dHhvbGliLkJpdGNvaW5KU05ldHdvcmspO1xuICB9XG5cbiAgZGVidWcoJ05ldHdvcms6ICVPJywgbmV0d29yayk7XG5cbiAgaWYgKGVuYWJsZUJDSCkge1xuICAgIGRlYnVnKCdFbmFibGluZyBCQ0jigKYnKTtcbiAgICBuZXR3b3JrID0gdXR4b2xpYi5uZXR3b3Jrcy5iaXRjb2luY2FzaDtcbiAgICBkZWJ1ZygnTmV3IG5ldHdvcms6ICVPJywgbmV0d29yayk7XG4gIH1cblxuICBjb25zdCB0cmFuc2FjdGlvbiA9IHV0eG9saWIuYml0Z28uY3JlYXRlVHJhbnNhY3Rpb25Gcm9tSGV4KHBhcmFtcy50cmFuc2FjdGlvbkhleCwgbmV0d29yayk7XG4gIGlmICh0cmFuc2FjdGlvbi5pbnMubGVuZ3RoICE9PSBwYXJhbXMudW5zcGVudHMubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdsZW5ndGggb2YgdW5zcGVudHMgYXJyYXkgc2hvdWxkIGVxdWFsIHRvIHRoZSBudW1iZXIgb2YgdHJhbnNhY3Rpb24gaW5wdXRzJyk7XG4gIH1cblxuICAvLyBkZWNvcmF0ZSB0cmFuc2FjdGlvbiB3aXRoIGlucHV0IHZhbHVlcyBmb3IgVHJhbnNhY3Rpb25CdWlsZGVyIGluc3RhbnRpYXRpb25cbiAgY29uc3QgaXNVdHhvVHggPSBfLmlzT2JqZWN0KHRyYW5zYWN0aW9uKSAmJiBBcnJheS5pc0FycmF5KCh0cmFuc2FjdGlvbiBhcyBhbnkpLmlucyk7XG4gIGNvbnN0IGFyZVZhbGlkVW5zcGVudHMgPSBfLmlzT2JqZWN0KHBhcmFtcykgJiYgQXJyYXkuaXNBcnJheSgocGFyYW1zIGFzIGFueSkudW5zcGVudHMpO1xuICBpZiAoaXNVdHhvVHggJiYgYXJlVmFsaWRVbnNwZW50cykge1xuICAgIC8vIGV4dGVuZCB0aGUgdHJhbnNhY3Rpb24gaW5wdXRzIHdpdGggdGhlIHZhbHVlc1xuICAgIGNvbnN0IGlucHV0VmFsdWVzID0gXy5tYXAoKHBhcmFtcyBhcyBhbnkpLnVuc3BlbnRzLCAodSkgPT4gXy5waWNrKHUsICd2YWx1ZScpKTtcbiAgICB0cmFuc2FjdGlvbi5pbnMubWFwKChjdXJyZW50SXRlbSwgaW5kZXgpID0+IF8uZXh0ZW5kKGN1cnJlbnRJdGVtLCBpbnB1dFZhbHVlc1tpbmRleF0pKTtcbiAgfVxuXG4gIGxldCByb290RXh0S2V5O1xuICBpZiAoa2V5Y2hhaW4pIHtcbiAgICByb290RXh0S2V5ID0gYmlwMzIuZnJvbUJhc2U1OChrZXljaGFpbi54cHJ2KTtcbiAgfVxuXG4gIGNvbnN0IHR4YiA9IHV0eG9saWIuYml0Z28uY3JlYXRlVHJhbnNhY3Rpb25CdWlsZGVyRnJvbVRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uKTtcblxuICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgdHhiLnR4Lmlucy5sZW5ndGg7ICsraW5kZXgpIHtcbiAgICBjb25zdCBjdXJyZW50VW5zcGVudCA9IHBhcmFtcy51bnNwZW50c1tpbmRleF07XG4gICAgaWYgKGN1cnJlbnRVbnNwZW50LnJlZGVlbVNjcmlwdCA9PT0gZmFsc2UpIHtcbiAgICAgIC8vIHRoaXMgaXMgdGhlIGlucHV0IGZyb20gYSBzaW5nbGUga2V5IGZlZSBhZGRyZXNzXG4gICAgICBpZiAoIWZlZVNpbmdsZUtleSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3NpbmdsZSBrZXkgYWRkcmVzcyB1c2VkIGluIGlucHV0IGJ1dCBmZWVTaW5nbGVLZXlXSUYgbm90IHByb3ZpZGVkJyk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlbmFibGVCQ0gpIHtcbiAgICAgICAgZmVlU2luZ2xlS2V5Lm5ldHdvcmsgPSBuZXR3b3JrO1xuICAgICAgfVxuXG4gICAgICB0eGIuc2lnbihpbmRleCwgZmVlU2luZ2xlS2V5KTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmIChjdXJyZW50VW5zcGVudC53aXRuZXNzU2NyaXB0ICYmIGVuYWJsZUJDSCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdCQ0ggZG9lcyBub3Qgc3VwcG9ydCBzZWd3aXQgaW5wdXRzJyk7XG4gICAgfVxuXG4gICAgY29uc3QgY2hhaW5QYXRoID0gY3VycmVudFVuc3BlbnQuY2hhaW5QYXRoO1xuICAgIGlmIChyb290RXh0S2V5KSB7XG4gICAgICBjb25zdCB7IHdhbGxldFN1YlBhdGggPSAnLzAvMCcgfSA9IGtleWNoYWluO1xuICAgICAgY29uc3QgcGF0aCA9IHNhbml0aXplTGVnYWN5UGF0aChrZXljaGFpbi5wYXRoICsgd2FsbGV0U3ViUGF0aCArIGNoYWluUGF0aCk7XG4gICAgICBkZWJ1ZyhcbiAgICAgICAgJ2Rlcml2ZWQgdXNlciBrZXkgcGF0aCBcIiVzXCIgdXNpbmcga2V5Y2hhaW4gcGF0aCBcIiVzXCIsIHdhbGxldFN1YlBhdGggXCIlc1wiLCBrZXljaGFpbiB3YWxsZXRTdWJQYXRoIFwiJXNcIiBhbmQgY2hhaW5QYXRoIFwiJXNcIicsXG4gICAgICAgIHBhdGgsXG4gICAgICAgIGtleWNoYWluLnBhdGgsXG4gICAgICAgIHdhbGxldFN1YlBhdGgsXG4gICAgICAgIGtleWNoYWluLndhbGxldFN1YlBhdGgsXG4gICAgICAgIGNoYWluUGF0aFxuICAgICAgKTtcbiAgICAgIHByaXZLZXkgPSByb290RXh0S2V5LmRlcml2ZVBhdGgocGF0aCk7XG4gICAgfVxuXG4gICAgcHJpdktleS5uZXR3b3JrID0gbmV0d29yaztcblxuICAgIC8vIHN1YnNjcmlwdCBpcyB0aGUgcGFydCBvZiB0aGUgb3V0cHV0IHNjcmlwdCBhZnRlciB0aGUgT1BfQ09ERVNFUEFSQVRPUi5cbiAgICAvLyBTaW5jZSB3ZSBhcmUgb25seSBldmVyIHNpZ25pbmcgcDJzaCBvdXRwdXRzLCB3aGljaCBkbyBub3QgaGF2ZVxuICAgIC8vIE9QX0NPREVTRVBBUkFUT1JTLCBpdCBpcyBhbHdheXMgdGhlIG91dHB1dCBzY3JpcHQuXG4gICAgY29uc3Qgc3Vic2NyaXB0ID0gQnVmZmVyLmZyb20oY3VycmVudFVuc3BlbnQucmVkZWVtU2NyaXB0LCAnaGV4Jyk7XG4gICAgY3VycmVudFVuc3BlbnQudmFsaWRhdGlvblNjcmlwdCA9IHN1YnNjcmlwdDtcblxuICAgIC8vIEluIG9yZGVyIHRvIHNpZ24gd2l0aCBiaXRjb2luanMtbGliLCB3ZSBtdXN0IHVzZSBpdHMgdHJhbnNhY3Rpb25cbiAgICAvLyBidWlsZGVyLCBjb25mdXNpbmdseSBuYW1lZCB0aGUgc2FtZSBleGFjdCB0aGluZyBhcyBvdXIgdHJhbnNhY3Rpb25cbiAgICAvLyBidWlsZGVyLCBidXQgd2l0aCBpbmVxdWl2YWxlbnQgYmVoYXZpb3IuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHdpdG5lc3NTY3JpcHQgPSBjdXJyZW50VW5zcGVudC53aXRuZXNzU2NyaXB0ID8gQnVmZmVyLmZyb20oY3VycmVudFVuc3BlbnQud2l0bmVzc1NjcmlwdCwgJ2hleCcpIDogdW5kZWZpbmVkO1xuICAgICAgY29uc3Qgc2lnSGFzaCA9IHV0eG9saWIuYml0Z28uZ2V0RGVmYXVsdFNpZ0hhc2gobmV0d29yayk7XG4gICAgICB0eGIuc2lnbihpbmRleCwgcHJpdktleSwgc3Vic2NyaXB0LCBzaWdIYXNoLCBjdXJyZW50VW5zcGVudC52YWx1ZSwgd2l0bmVzc1NjcmlwdCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgLy8gdHJ5IGZhbGxiYWNrIGRlcml2YXRpb24gcGF0aCAoc2VlIEJHLTQ2NDk3KVxuICAgICAgbGV0IGZhbGxiYWNrU2lnbmluZ1N1Y2Nlc3NmdWwgPSBmYWxzZTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGZhbGxiYWNrUGF0aCA9IHNhbml0aXplTGVnYWN5UGF0aChrZXljaGFpbi5wYXRoICsgY2hhaW5QYXRoKTtcbiAgICAgICAgZGVidWcoXG4gICAgICAgICAgJ2Rlcml2ZWQgZmFsbGJhY2sgdXNlciBrZXkgcGF0aCBcIiVzXCIgdXNpbmcga2V5Y2hhaW4gcGF0aCBcIiVzXCIgYW5kIGNoYWluUGF0aCBcIiVzXCInLFxuICAgICAgICAgIGZhbGxiYWNrUGF0aCxcbiAgICAgICAgICBrZXljaGFpbi5wYXRoLFxuICAgICAgICAgIGNoYWluUGF0aFxuICAgICAgICApO1xuICAgICAgICBwcml2S2V5ID0gcm9vdEV4dEtleS5kZXJpdmVQYXRoKGZhbGxiYWNrUGF0aCk7XG4gICAgICAgIGNvbnN0IHdpdG5lc3NTY3JpcHQgPSBjdXJyZW50VW5zcGVudC53aXRuZXNzU2NyaXB0XG4gICAgICAgICAgPyBCdWZmZXIuZnJvbShjdXJyZW50VW5zcGVudC53aXRuZXNzU2NyaXB0LCAnaGV4JylcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgICAgY29uc3Qgc2lnSGFzaCA9IHV0eG9saWIuYml0Z28uZ2V0RGVmYXVsdFNpZ0hhc2gobmV0d29yayk7XG4gICAgICAgIHR4Yi5zaWduKGluZGV4LCBwcml2S2V5LCBzdWJzY3JpcHQsIHNpZ0hhc2gsIGN1cnJlbnRVbnNwZW50LnZhbHVlLCB3aXRuZXNzU2NyaXB0KTtcbiAgICAgICAgZmFsbGJhY2tTaWduaW5nU3VjY2Vzc2Z1bCA9IHRydWU7XG4gICAgICB9IGNhdGNoIChmYWxsYmFja0Vycm9yKSB7XG4gICAgICAgIGRlYnVnKCdpbnB1dCBzaWduIGZhaWxlZCBmb3IgZmFsbGJhY2sgcGF0aDogJXMnLCBmYWxsYmFja0Vycm9yLm1lc3NhZ2UpO1xuICAgICAgfVxuICAgICAgLy8gd2UgbmVlZCB0byBrbm93IHdoYXQncyBjYXVzaW5nIHRoaXNcbiAgICAgIGlmICghZmFsbGJhY2tTaWduaW5nU3VjY2Vzc2Z1bCkge1xuICAgICAgICBlLnJlc3VsdCA9IHtcbiAgICAgICAgICB1bnNwZW50OiBjdXJyZW50VW5zcGVudCxcbiAgICAgICAgfTtcbiAgICAgICAgZS5tZXNzYWdlID0gYEZhaWxlZCB0byBzaWduIGlucHV0ICMke2luZGV4fSAtICR7ZS5tZXNzYWdlfSAtICR7SlNPTi5zdHJpbmdpZnkoZS5yZXN1bHQsIG51bGwsIDQpfSAtIFxcbiR7XG4gICAgICAgICAgZS5zdGFja1xuICAgICAgICB9YDtcbiAgICAgICAgZGVidWcoJ2lucHV0IHNpZ24gZmFpbGVkOiAlcycsIGUubWVzc2FnZSk7XG4gICAgICAgIHJldHVybiBCbHVlYmlyZC5yZWplY3QoZSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY29uc3QgcGFydGlhbFRyYW5zYWN0aW9uID0gdHhiLmJ1aWxkSW5jb21wbGV0ZSgpO1xuXG4gIGlmICh2YWxpZGF0ZSkge1xuICAgIHBhcnRpYWxUcmFuc2FjdGlvbi5pbnMuZm9yRWFjaCgoaW5wdXQsIGluZGV4KSA9PiB7XG4gICAgICBjb25zdCBzaWduYXR1cmVDb3VudCA9IHV0eG9saWIuYml0Z29cbiAgICAgICAgLmdldFNpZ25hdHVyZVZlcmlmaWNhdGlvbnMocGFydGlhbFRyYW5zYWN0aW9uLCBpbmRleCwgcGFyYW1zLnVuc3BlbnRzW2luZGV4XS52YWx1ZSlcbiAgICAgICAgLmZpbHRlcigodikgPT4gdi5zaWduZWRCeSAhPT0gdW5kZWZpbmVkKS5sZW5ndGg7XG4gICAgICBpZiAoc2lnbmF0dXJlQ291bnQgPCAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignZXhwZWN0ZWQgYXQgbGVhc3Qgb25lIHZhbGlkIHNpZ25hdHVyZScpO1xuICAgICAgfVxuICAgICAgaWYgKHBhcmFtcy5mdWxsTG9jYWxTaWduaW5nICYmIHNpZ25hdHVyZUNvdW50IDwgMikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2Z1bGxMb2NhbFNpZ25pbmcgc2V0OiBleHBlY3RlZCBhdCBsZWFzdCB0d28gdmFsaWQgc2lnbmF0dXJlcycpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIEJsdWViaXJkLnJlc29sdmUoe1xuICAgIHRyYW5zYWN0aW9uSGV4OiBwYXJ0aWFsVHJhbnNhY3Rpb24udG9IZXgoKSxcbiAgfSk7XG59O1xuIl19
|