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