@bitgo/sdk-api 1.1.0-rc.7 → 1.1.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +225 -0
  2. package/dist/package.json +27 -20
  3. package/dist/src/api.d.ts.map +1 -1
  4. package/dist/src/api.js +5 -5
  5. package/dist/src/bitgoAPI.d.ts +228 -6
  6. package/dist/src/bitgoAPI.d.ts.map +1 -1
  7. package/dist/src/bitgoAPI.js +597 -15
  8. package/dist/src/types.d.ts +83 -9
  9. package/dist/src/types.d.ts.map +1 -1
  10. package/dist/src/types.js +2 -14
  11. package/dist/src/util.d.ts +0 -8
  12. package/dist/src/util.d.ts.map +1 -1
  13. package/dist/src/util.js +2 -21
  14. package/dist/src/v1/blockchain.d.ts +5 -0
  15. package/dist/src/v1/blockchain.d.ts.map +1 -0
  16. package/dist/src/v1/blockchain.js +114 -0
  17. package/dist/src/v1/keychains.d.ts +5 -0
  18. package/dist/src/v1/keychains.d.ts.map +1 -0
  19. package/dist/src/v1/keychains.js +315 -0
  20. package/dist/src/v1/markets.d.ts +5 -0
  21. package/dist/src/v1/markets.d.ts.map +1 -0
  22. package/dist/src/v1/markets.js +63 -0
  23. package/dist/src/v1/pendingapproval.d.ts +6 -0
  24. package/dist/src/v1/pendingapproval.d.ts.map +1 -0
  25. package/dist/src/v1/pendingapproval.js +322 -0
  26. package/dist/src/v1/pendingapprovals.d.ts +6 -0
  27. package/dist/src/v1/pendingapprovals.d.ts.map +1 -0
  28. package/dist/src/v1/pendingapprovals.js +68 -0
  29. package/dist/src/v1/transactionBuilder.d.ts +5 -0
  30. package/dist/src/v1/transactionBuilder.d.ts.map +1 -0
  31. package/dist/src/v1/transactionBuilder.js +889 -0
  32. package/dist/src/v1/travelRule.d.ts +5 -0
  33. package/dist/src/v1/travelRule.d.ts.map +1 -0
  34. package/dist/src/v1/travelRule.js +257 -0
  35. package/dist/src/v1/wallet.d.ts +6 -0
  36. package/dist/src/v1/wallet.d.ts.map +1 -0
  37. package/dist/src/v1/wallet.js +2095 -0
  38. package/dist/src/v1/wallets.d.ts +5 -0
  39. package/dist/src/v1/wallets.d.ts.map +1 -0
  40. package/dist/src/v1/wallets.js +472 -0
  41. package/dist/web/main.js +1 -1
  42. package/dist/web/main.js.LICENSE.txt +41 -0
  43. package/package.json +27 -20
  44. package/dist/src/bip32path.d.ts +0 -24
  45. package/dist/src/bip32path.d.ts.map +0 -1
  46. package/dist/src/bip32path.js +0 -45
  47. package/dist/tsconfig.tsbuildinfo +0 -6755
  48. package/dist/web/browser.html +0 -1
@@ -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 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 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 = 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNhY3Rpb25CdWlsZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3YxL3RyYW5zYWN0aW9uQnVpbGRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7O0FBRUg7R0FDRztBQUNILEVBQUU7QUFDRixxQkFBcUI7QUFDckIsa0RBQWtEO0FBQ2xELEVBQUU7QUFDRixvREFBb0Q7QUFDcEQsRUFBRTtBQUVGLCtCQUErQjtBQUMvQixxQ0FBcUM7QUFDckMsMkNBQTJDO0FBQzNDLDRCQUE0QjtBQUM1Qiw4Q0FBK0M7QUFDL0Msa0NBQW1DO0FBQ25DLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQztBQUN2Qyw4Q0FBMEY7QUF1QjFGLEVBQUU7QUFDRixxQkFBcUI7QUFDckIsV0FBVztBQUNYLDBDQUEwQztBQUMxQyw4TUFBOE07QUFDOU0sc0dBQXNHO0FBQ3RHLGtJQUFrSTtBQUNsSSw2SEFBNkg7QUFDN0gsdUdBQXVHO0FBQ3ZHLCtFQUErRTtBQUMvRSxxRUFBcUU7QUFDckUsNkVBQTZFO0FBQzdFLHdHQUF3RztBQUN4RyxpSUFBaUk7QUFDakksd0lBQXdJO0FBQ3hJLDRJQUE0STtBQUM1SSx1RUFBdUU7QUFDdkUsMkVBQTJFO0FBQzNFLDRGQUE0RjtBQUM1RixPQUFPLENBQUMsaUJBQWlCLEdBQUcsVUFBVSxNQUFNO0lBQzFDLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxXQUFXLElBQUksQ0FBQyxDQUFDO0lBQzVDLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxRQUFRLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUM7SUFDeEUsSUFBSSxVQUFVLEdBQTZFLEVBQUUsQ0FBQztJQUM5RixJQUFJLFNBQVMsR0FBMEMsRUFBRSxDQUFDO0lBQzFELElBQUksa0JBQWtCLEdBQWEsRUFBRSxDQUFDO0lBQ3RDLElB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O0lBRUQsTUFBTSxrQkFBa0IsR0FBRyxHQUFHLENBQUMsZUFBZSxFQUFFLENBQUM7SUFFakQsSUFBSSxRQUFRLEVBQUU7UUFDWixrQkFBa0IsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFO1lBQzlDLE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxLQUFLO2lCQUNqQyx5QkFBeUIsQ0FBQyxrQkFBa0IsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUM7aUJBQ2xGLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsS0FBSyxTQUFTLENBQUMsQ0FBQyxNQUFNLENBQUM7WUFDbEQsSUFBSSxjQUFjLEdBQUcsQ0FBQyxFQUFFO2dCQUN0QixNQUFNLElBQUksS0FBSyxDQUFDLHVDQUF1QyxDQUFDLENBQUM7YUFDMUQ7WUFDRCxJQUFJLE1BQU0sQ0FBQyxnQkFBZ0IsSUFBSSxjQUFjLEdBQUcsQ0FBQyxFQUFFO2dCQUNqRCxNQUFNLElBQUksS0FBSyxDQUFDLDhEQUE4RCxDQUFDLENBQUM7YUFDakY7UUFDSCxDQUFDLENBQUMsQ0FBQztLQUNKO0lBRUQsT0FBTyxRQUFRLENBQUMsT0FBTyxDQUFDO1FBQ3RCLGNBQWMsRUFBRSxrQkFBa0IsQ0FBQyxLQUFLLEVBQUU7S0FDM0MsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAaGlkZGVuXG4gKi9cblxuLyoqXG4gKi9cbi8vXG4vLyBUcmFuc2FjdGlvbkJ1aWxkZXJcbi8vIEEgdXRpbGl0eSBmb3IgYnVpbGRpbmcgYW5kIHNpZ25pbmcgdHJhbnNhY3Rpb25zXG4vL1xuLy8gQ29weXJpZ2h0IDIwMTQsIEJpdEdvLCBJbmMuICBBbGwgUmlnaHRzIFJlc2VydmVkLlxuLy9cblxuaW1wb3J0ICogYXMgYmlwMzIgZnJvbSAnYmlwMzInO1xuaW1wb3J0ICogYXMgQmx1ZWJpcmQgZnJvbSAnYmx1ZWJpcmQnO1xuaW1wb3J0ICogYXMgdXR4b2xpYiBmcm9tICdAYml0Z28vdXR4by1saWInO1xuaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgVmlydHVhbFNpemVzIH0gZnJvbSAnQGJpdGdvL3Vuc3BlbnRzJztcbmltcG9ydCBkZWJ1Z0xpYiA9IHJlcXVpcmUoJ2RlYnVnJyk7XG5jb25zdCBkZWJ1ZyA9IGRlYnVnTGliKCdiaXRnbzp2MTp0eGInKTtcbmltcG9ydCB7IGNvbW1vbiwgZ2V0QWRkcmVzc1AyUEtILCBnZXROZXR3b3JrLCBzYW5pdGl6ZUxlZ2FjeVBhdGggfSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuXG5pbnRlcmZhY2UgQmFzZU91dHB1dCB7XG4gIGFtb3VudDogbnVtYmVyO1xuICB0cmF2ZWxJbmZvPzogYW55O1xufVxuXG5pbnRlcmZhY2UgQWRkcmVzc091dHB1dCBleHRlbmRzIEJhc2VPdXRwdXQge1xuICBhZGRyZXNzOiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBTY3JpcHRPdXRwdXQgZXh0ZW5kcyBCYXNlT3V0cHV0IHtcbiAgc2NyaXB0OiBCdWZmZXI7XG59XG5cbnR5cGUgT3V0cHV0ID0gQWRkcmVzc091dHB1dCB8IFNjcmlwdE91dHB1dDtcblxuaW50ZXJmYWNlIEJpdEdvVW5zcGVudCB7XG4gIHZhbHVlOiBudW1iZXI7XG4gIHR4X2hhc2g6IEJ1ZmZlcjtcbiAgdHhfb3V0cHV0X246IG51bWJlcjtcbn1cblxuLy9cbi8vIFRyYW5zYWN0aW9uQnVpbGRlclxuLy8gQHBhcmFtczpcbi8vICAgd2FsbGV0OiAgYSB3YWxsZXQgb2JqZWN0IHRvIHNlbmQgZnJvbVxuLy8gICByZWNpcGllbnRzOiBhcnJheSBvZiByZWNpcGllbnQgb2JqZWN0cyBhbmQgdGhlIGFtb3VudCB0byBzZW5kIHRvIGVhY2ggZS5nLiBbe2FkZHJlc3M6ICczOEJLRE5aYlBjTG9ndlZiY3gyZWtKOUU2VnY5NERxRHF3JywgYW1vdW50OiAxNTAwfSwge2FkZHJlc3M6ICczNmVMOHlRcUNuMUhNUm1WRkZvNDl0MlBKM3BhaTh3UWFtJywgYW1vdW50OiAyMDAwfV1cbi8vICAgZmVlOiB0aGUgZmVlIHRvIHVzZSB3aXRoIHRoaXMgdHJhbnNhY3Rpb24uICBpZiBub3QgcHJvdmlkZWQsIGEgZGVmYXVsdCwgbWluaW11bSBmZWUgd2lsbCBiZSB1c2VkLlxuLy8gICBmZWVSYXRlOiB0aGUgYW1vdW50IG9mIGZlZSBwZXIga2lsb2J5dGUgLSBvcHRpb25hbCAtIHNwZWNpZnkgZWl0aGVyIGZlZSwgZmVlUmF0ZSwgb3IgZmVlVHhDb25maXJtVGFyZ2V0IGJ1dCBub3QgbW9yZSB0aGFuIG9uZVxuLy8gICBmZWVUeENvbmZpcm1UYXJnZXQ6IGNhbGN1bGF0ZSB0aGUgZmVlcyBwZXIga2lsb2J5dGUgc3VjaCB0aGF0IHRoZSB0cmFuc2FjdGlvbiB3aWxsIGJlIGNvbmZpcm1lZCBpbiB0aGlzIG51bWJlciBvZiBibG9ja3Ncbi8vICAgbWF4RmVlUmF0ZTogVGhlIG1heGltdW0gZmVlIHBlciBrYiB0byB1c2UgaW4gc2F0b3NoaXMsIGZvciBzYWZldHkgcHVycG9zZXMgd2hlbiB1c2luZyBkeW5hbWljIGZlZXNcbi8vICAgbWluQ29uZmlybXM6IHRoZSBtaW5pbXVtIGNvbmZpcm1hdGlvbnMgYW4gb3V0cHV0IG11c3QgaGF2ZSBiZWZvcmUgc3BlbmRpbmdcbi8vICAgZm9yY2VDaGFuZ2VBdEVuZDogZm9yY2UgdGhlIGNoYW5nZSBhZGRyZXNzIHRvIGJlIHRoZSBsYXN0IG91dHB1dFxuLy8gICBjaGFuZ2VBZGRyZXNzOiBzcGVjaWZ5IHRoZSBjaGFuZ2UgYWRkcmVzcyByYXRoZXIgdGhhbiBnZW5lcmF0ZSBhIG5ldyBvbmVcbi8vICAgbm9TcGxpdENoYW5nZTogc2V0IHRvIHRydWUgdG8gZGlzYWJsZSBhdXRvbWF0aWMgY2hhbmdlIHNwbGl0dGluZyBmb3IgcHVycG9zZXMgb2YgdW5zcGVudCBtYW5hZ2VtZW50XG4vLyAgIHRhcmdldFdhbGxldFVuc3BlbnRzOiBzcGVjaWZ5IGEgbnVtYmVyIG9mIHRhcmdldCB1bnNwZW50cyB0byBtYWludGFpbiBpbiB0aGUgd2FsbGV0IChjdXJyZW50bHkgZGVmYXVsdGVkIHRvIDggYnkgdGhlIHNlcnZlcilcbi8vICAgdmFsaWRhdGU6IGV4dHJhIHZlcmlmaWNhdGlvbiBvZiB0aGUgY2hhbmdlIGFkZHJlc3Nlcywgd2hpY2ggaXMgYWx3YXlzIGRvbmUgc2VydmVyLXNpZGUgYW5kIGlzIHJlZHVuZGFudCBjbGllbnQtc2lkZSAoZGVmYXVsdHMgdHJ1ZSlcbi8vICAgbWluVW5zcGVudFNpemU6IFRoZSBtaW5pbXVtIHNpemUgaW4gc2F0b3NoaXMgb2YgdW5zcGVudCB0byB1c2UgKHRvIHByZXZlbnQgc3BlbmRpbmcgdW5zcGVudHMgd29ydGggbGVzcyB0aGFuIGZlZSBhZGRlZCkuIERlZmF1bHRzIHRvIDAuXG4vLyAgIGZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3M6IFVzZSB0aGlzIHNpbmdsZSBrZXkgYWRkcmVzcyB0byBwYXkgZmVlc1xuLy8gICBmZWVTaW5nbGVLZXlXSUY6IFVzZSB0aGUgYWRkcmVzcyBiYXNlZCBvbiB0aGlzIHByaXZhdGUga2V5IHRvIHBheSBmZWVzXG4vLyAgIHVuc3BlbnRzRmV0Y2hQYXJhbXM6IEV4dHJhIHBhcmFtZXRlcnMgdG8gdXNlIGZvciBmZXRjaGluZyB1bnNwZW50cyBmb3IgdGhpcyB0cmFuc2FjdGlvblxuZXhwb3J0cy5jcmVhdGVUcmFuc2FjdGlvbiA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgY29uc3QgbWluQ29uZmlybXMgPSBwYXJhbXMubWluQ29uZmlybXMgfHwgMDtcbiAgY29uc3QgdmFsaWRhdGUgPSBwYXJhbXMudmFsaWRhdGUgPT09IHVuZGVmaW5lZCA/IHRydWUgOiBwYXJhbXMudmFsaWRhdGU7XG4gIGxldCByZWNpcGllbnRzOiB7IGFkZHJlc3M6IHN0cmluZzsgYW1vdW50OiBudW1iZXI7IHNjcmlwdD86IHN0cmluZzsgdHJhdmVsSW5mbz86IGFueSB9W10gPSBbXTtcbiAgbGV0IG9wUmV0dXJuczogeyBtZXNzYWdlOiBzdHJpbmc7IGFtb3VudDogbnVtYmVyIH1bXSA9IFtdO1xuICBsZXQgZXh0cmFDaGFuZ2VBbW91bnRzOiBudW1iZXJbXSA9IFtdO1xuICBsZXQgZXN0VHhTaXplOiBudW1iZXI7XG4gIGxldCB0cmF2ZWxJbmZvcztcblxuICAvLyBTYW5pdHkgY2hlY2sgdGhlIGFyZ3VtZW50cyBwYXNzZWQgaW5cbiAgaWYgKFxuICAgICFfLmlzT2JqZWN0KHBhcmFtcy53YWxsZXQpIHx8XG4gICAgKHBhcmFtcy5mZWUgJiYgIV8uaXNOdW1iZXIocGFyYW1zLmZlZSkpIHx8XG4gICAgKHBhcmFtcy5mZWVSYXRlICYmICFfLmlzTnVtYmVyKHBhcmFtcy5mZWVSYXRlKSkgfHxcbiAgICAhXy5pc0ludGVnZXIobWluQ29uZmlybXMpIHx8XG4gICAgKHBhcmFtcy5mb3JjZUNoYW5nZUF0RW5kICYmICFfLmlzQm9vbGVhbihwYXJhbXMuZm9yY2VDaGFuZ2VBdEVuZCkpIHx8XG4gICAgKHBhcmFtcy5jaGFuZ2VBZGRyZXNzICYmICFfLmlzU3RyaW5nKHBhcmFtcy5jaGFuZ2VBZGRyZXNzKSkgfHxcbiAgICAocGFyYW1zLm5vU3BsaXRDaGFuZ2UgJiYgIV8uaXNCb29sZWFuKHBhcmFtcy5ub1NwbGl0Q2hhbmdlKSkgfHxcbiAgICAocGFyYW1zLnRhcmdldFdhbGxldFVuc3BlbnRzICYmICFfLmlzSW50ZWdlcihwYXJhbXMudGFyZ2V0V2FsbGV0VW5zcGVudHMpKSB8fFxuICAgICh2YWxpZGF0ZSAmJiAhXy5pc0Jvb2xlYW4odmFsaWRhdGUpKSB8fFxuICAgIChwYXJhbXMuZW5mb3JjZU1pbkNvbmZpcm1zRm9yQ2hhbmdlICYmICFfLmlzQm9vbGVhbihwYXJhbXMuZW5mb3JjZU1pbkNvbmZpcm1zRm9yQ2hhbmdlKSkgfHxcbiAgICAocGFyYW1zLm1pblVuc3BlbnRTaXplICYmICFfLmlzTnVtYmVyKHBhcmFtcy5taW5VbnNwZW50U2l6ZSkpIHx8XG4gICAgKHBhcmFtcy5tYXhGZWVSYXRlICYmICFfLmlzTnVtYmVyKHBhcmFtcy5tYXhGZWVSYXRlKSkgfHxcbiAgICAvLyB0aGlzIHNob3VsZCBiZSBhbiBhcnJheSBhbmQgaXRzIGxlbmd0aCBtdXN0IGJlIGF0IGxlYXN0IDFcbiAgICAocGFyYW1zLnVuc3BlbnRzICYmICghQXJyYXkuaXNBcnJheShwYXJhbXMudW5zcGVudHMpIHx8IHBhcmFtcy51bnNwZW50cy5sZW5ndGggPCAxKSkgfHxcbiAgICAocGFyYW1zLmZlZVR4Q29uZmlybVRhcmdldCAmJiAhXy5pc0ludGVnZXIocGFyYW1zLmZlZVR4Q29uZmlybVRhcmdldCkpIHx8XG4gICAgKHBhcmFtcy5pbnN0YW50ICYmICFfLmlzQm9vbGVhbihwYXJhbXMuaW5zdGFudCkpIHx8XG4gICAgKHBhcmFtcy5iaXRnb0ZlZSAmJiAhXy5pc09iamVjdChwYXJhbXMuYml0Z29GZWUpKSB8fFxuICAgIChwYXJhbXMudW5zcGVudHNGZXRjaFBhcmFtcyAmJiAhXy5pc09iamVjdChwYXJhbXMudW5zcGVudHNGZXRjaFBhcmFtcykpXG4gICkge1xuICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBhcmd1bWVudCcpO1xuICB9XG5cbiAgY29uc3QgYml0Z28gPSBwYXJhbXMud2FsbGV0LmJpdGdvO1xuICBjb25zdCBjb25zdGFudHMgPSBiaXRnby5nZXRDb25zdGFudHMoKTtcbiAgY29uc3QgbmV0d29yayA9IGdldE5ldHdvcmsoY29tbW9uLkVudmlyb25tZW50c1tiaXRnby5nZXRFbnYoKV0ubmV0d29yayk7XG5cbiAgLy8gVGhlIHVzZXIgY2FuIHNwZWNpZnkgYSBzZXBlcmF0ZSwgc2luZ2xlLWtleSB3YWxsZXQgZm9yIHRoZSBwdXJwb3NlcyBvZiBwYXlpbmcgbWluZXIncyBmZWVzXG4gIC8vIFdoZW4gY3JlYXRpbmcgYSB0cmFuc2FjdGlvbiB0aGlzIGNhbiBiZSBzcGVjaWZpZWQgYXMgYW4gaW5wdXQgYWRkcmVzcyBvciB0aGUgcHJpdmF0ZSBrZXkgaW4gV0lGXG4gIGxldCBmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzO1xuICBsZXQgZmVlU2luZ2xlS2V5SW5wdXRBbW91bnQgPSAwO1xuICBpZiAocGFyYW1zLmZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MpIHtcbiAgICB0cnkge1xuICAgICAgdXR4b2xpYi5hZGRyZXNzLmZyb21CYXNlNThDaGVjayhwYXJhbXMuZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcywgbmV0d29yayk7XG4gICAgICBmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzID0gcGFyYW1zLmZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3M7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIGJpdGNvaW4gYWRkcmVzczogJyArIHBhcmFtcy5mZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzKTtcbiAgICB9XG4gIH1cblxuICBpZiAocGFyYW1zLmZlZVNpbmdsZUtleVdJRikge1xuICAgIGNvbnN0IGZlZVNpbmdsZUtleSA9IHV0eG9saWIuRUNQYWlyLmZyb21XSUYocGFyYW1zLmZlZVNpbmdsZUtleVdJRiwgbmV0d29yayBhcyB1dHhvbGliLkJpdGNvaW5KU05ldHdvcmspO1xuICAgIGZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MgPSBnZXRBZGRyZXNzUDJQS0goZmVlU2luZ2xlS2V5KTtcbiAgICAvLyBJZiB0aGUgdXNlciBzcGVjaWZpZXMgYm90aCwgY2hlY2sgdG8gbWFrZSBzdXJlIHRoZSBmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzIGNvcnJlc3BvbmRzIHRvIHRoZSBhZGRyZXNzIG9mIGZlZVNpbmdsZUtleVdJRlxuICAgIGlmIChwYXJhbXMuZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcyAmJiBwYXJhbXMuZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcyAhPT0gZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzczogJyArXG4gICAgICAgICAgcGFyYW1zLmZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MgK1xuICAgICAgICAgICcgZGlkIG5vdCBjb3JyZXNwb25kIHRvIGFkZHJlc3Mgb2YgZmVlU2luZ2xlS2V5V0lGOiAnICtcbiAgICAgICAgICBmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIGlmICghXy5pc09iamVjdChwYXJhbXMucmVjaXBpZW50cykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3JlY2lwaWVudHMgbXVzdCBiZSBhcnJheSBvZiB7IGFkZHJlc3M6IGFiYywgYW1vdW50OiAxMDAwMDAgfSBvYmplY3RzJyk7XG4gIH1cblxuICBsZXQgZmVlUGFyYW1zRGVmaW5lZCA9IDA7XG4gIGlmICghXy5pc1VuZGVmaW5lZChwYXJhbXMuZmVlKSkge1xuICAgIGZlZVBhcmFtc0RlZmluZWQrKztcbiAgfVxuXG4gIGlmICghXy5pc1VuZGVmaW5lZChwYXJhbXMuZmVlUmF0ZSkpIHtcbiAgICBmZWVQYXJhbXNEZWZpbmVkKys7XG4gIH1cblxuICBpZiAoIV8uaXNVbmRlZmluZWQocGFyYW1zLmZlZVR4Q29uZmlybVRhcmdldCkpIHtcbiAgICBmZWVQYXJhbXNEZWZpbmVkKys7XG4gIH1cblxuICBpZiAoZmVlUGFyYW1zRGVmaW5lZCA+IDEpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2Nhbm5vdCBzcGVjaWZ5IG1vcmUgdGhhbiBvbmUgb2YgZmVlLCBmZWVSYXRlIGFuZCBmZWVUeENvbmZpcm1UYXJnZXQnKTtcbiAgfVxuXG4gIGlmIChfLmlzVW5kZWZpbmVkKHBhcmFtcy5tYXhGZWVSYXRlKSkge1xuICAgIHBhcmFtcy5tYXhGZWVSYXRlID0gY29uc3RhbnRzLm1heEZlZVJhdGU7XG4gIH1cblxuICAvLyBDb252ZXJ0IHRoZSBvbGQgZm9ybWF0IG9mIHBhcmFtcy5yZWNpcGllbnRzIChkaWN0aW9uYXJ5IG9mIGFkZHJlc3M6YW1vdW50KSB0byBuZXcgZm9ybWF0OiB7IGRlc3RpbmF0aW9uQWRkcmVzcywgYW1vdW50IH1cbiAgaWYgKCEocGFyYW1zLnJlY2lwaWVudHMgaW5zdGFuY2VvZiBBcnJheSkpIHtcbiAgICByZWNpcGllbnRzID0gW107XG4gICAgT2JqZWN0LmtleXMocGFyYW1zLnJlY2lwaWVudHMpLmZvckVhY2goZnVuY3Rpb24gKGRlc3RpbmF0aW9uQWRkcmVzcykge1xuICAgICAgY29uc3QgYW1vdW50ID0gcGFyYW1zLnJlY2lwaWVudHNbZGVzdGluYXRpb25BZGRyZXNzXTtcbiAgICAgIHJlY2lwaWVudHMucHVzaCh7IGFkZHJlc3M6IGRlc3RpbmF0aW9uQWRkcmVzcywgYW1vdW50OiBhbW91bnQgfSk7XG4gICAgfSk7XG4gIH0gZWxzZSB7XG4gICAgcmVjaXBpZW50cyA9IHBhcmFtcy5yZWNpcGllbnRzO1xuICB9XG5cbiAgaWYgKHBhcmFtcy5vcFJldHVybnMpIHtcbiAgICBpZiAoIShwYXJhbXMub3BSZXR1cm5zIGluc3RhbmNlb2YgQXJyYXkpKSB7XG4gICAgICBvcFJldHVybnMgPSBbXTtcbiAgICAgIE9iamVjdC5rZXlzKHBhcmFtcy5vcFJldHVybnMpLmZvckVhY2goZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgY29uc3QgYW1vdW50ID0gcGFyYW1zLm9wUmV0dXJuc1ttZXNzYWdlXTtcbiAgICAgICAgb3BSZXR1cm5zLnB1c2goeyBtZXNzYWdlLCBhbW91bnQgfSk7XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgb3BSZXR1cm5zID0gcGFyYW1zLm9wUmV0dXJucztcbiAgICB9XG4gIH1cblxuICBpZiAocmVjaXBpZW50cy5sZW5ndGggPT09IDAgJiYgb3BSZXR1cm5zLmxlbmd0aCA9PT0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcignbXVzdCBoYXZlIGF0IGxlYXN0IG9uZSByZWNpcGllbnQnKTtcbiAgfVxuXG4gIGxldCBmZWUgPSBwYXJhbXMuZmVlO1xuICBsZXQgZmVlUmF0ZSA9IHBhcmFtcy5mZWVSYXRlO1xuXG4gIC8vIEZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIHRoaXMgY2xhc3Mgd2lsbCBjb21wdXRlIHRoZSBmZWVcbiAgY29uc3Qgc2hvdWxkQ29tcHV0ZUJlc3RGZWUgPSBfLmlzVW5kZWZpbmVkKGZlZSk7XG5cbiAgbGV0IHRvdGFsT3V0cHV0QW1vdW50ID0gMDtcblxuICByZWNpcGllbnRzLmZvckVhY2goZnVuY3Rpb24gKHJlY2lwaWVudCkge1xuICAgIGlmIChfLmlzU3RyaW5nKHJlY2lwaWVudC5hZGRyZXNzKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdXR4b2xpYi5hZGRyZXNzLmZyb21CYXNlNThDaGVjayhyZWNpcGllbnQuYWRkcmVzcywgbmV0d29yayk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBiaXRjb2luIGFkZHJlc3M6ICcgKyByZWNpcGllbnQuYWRkcmVzcyk7XG4gICAgICB9XG4gICAgICBpZiAoISFyZWNpcGllbnQuc2NyaXB0KSB7XG4gICAgICAgIC8vIEEgc2NyaXB0IHdhcyBwcm92aWRlZCBhcyB3ZWxsIC0gdmFsaWRhdGUgdGhhdCB0aGUgYWRkcmVzcyBjb3JyZXNwb25kcyB0byB0aGF0XG4gICAgICAgIGlmICh1dHhvbGliLmFkZHJlc3MudG9PdXRwdXRTY3JpcHQocmVjaXBpZW50LmFkZHJlc3MsIG5ldHdvcmspLnRvU3RyaW5nKCdoZXgnKSAhPT0gcmVjaXBpZW50LnNjcmlwdCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICdib3RoIHNjcmlwdCBhbmQgYWRkcmVzcyBwcm92aWRlZCBidXQgdGhleSBkaWQgbm90IG1hdGNoOiAnICsgcmVjaXBpZW50LmFkZHJlc3MgKyAnICcgKyByZWNpcGllbnQuc2NyaXB0XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIV8uaXNJbnRlZ2VyKHJlY2lwaWVudC5hbW91bnQpIHx8IHJlY2lwaWVudC5hbW91bnQgPCAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgYW1vdW50IGZvciAnICsgcmVjaXBpZW50LmFkZHJlc3MgKyAnOiAnICsgcmVjaXBpZW50LmFtb3VudCk7XG4gICAgfVxuICAgIHRvdGFsT3V0cHV0QW1vdW50ICs9IHJlY2lwaWVudC5hbW91bnQ7XG4gIH0pO1xuXG4gIG9wUmV0dXJucy5mb3JFYWNoKGZ1bmN0aW9uIChvcFJldHVybikge1xuICAgIHRvdGFsT3V0cHV0QW1vdW50ICs9IG9wUmV0dXJuLmFtb3VudDtcbiAgfSk7XG5cbiAgbGV0IGJpdGdvRmVlSW5mbyA9IHBhcmFtcy5iaXRnb0ZlZTtcbiAgaWYgKGJpdGdvRmVlSW5mbyAmJiAoIV8uaXNJbnRlZ2VyKGJpdGdvRmVlSW5mby5hbW91bnQpIHx8ICFfLmlzU3RyaW5nKGJpdGdvRmVlSW5mby5hZGRyZXNzKSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgYml0Z29GZWVJbmZvJyk7XG4gIH1cblxuICAvLyBUaGUgdG90YWwgYW1vdW50IG5lZWRlZCBmb3IgdGhpcyB0cmFuc2FjdGlvbi5cbiAgbGV0IHRvdGFsQW1vdW50ID0gdG90YWxPdXRwdXRBbW91bnQgKyAoZmVlIHx8IDApO1xuXG4gIC8vIFRoZSBsaXN0IG9mIHVuc3BlbnQgdHJhbnNhY3Rpb25zIGJlaW5nIHVzZWQgaW4gdGhpcyB0cmFuc2FjdGlvbi5cbiAgbGV0IHVuc3BlbnRzO1xuXG4gIC8vIHRoZSB0b3RhbCBudW1iZXIgb2YgdW5zcGVudHMgb24gdGhpcyB3YWxsZXRcbiAgbGV0IHRvdGFsVW5zcGVudHNDb3VudDtcblxuICAvLyB0aGUgbnVtYmVyIG9mIHVuc3BlbnRzIHdlIGZldGNoZWQgZnJvbSB0aGUgc2VydmVyLCBiZWZvcmUgZmlsdGVyaW5nXG4gIGxldCBmZXRjaGVkVW5zcGVudHNDb3VudDtcblxuICAvLyBUaGUgbGlzdCBvZiB1bnNwZW50IHRyYW5zYWN0aW9ucyBiZWluZyB1c2VkIHdpdGggemVyby1jb25maXJtYXRpb25zXG4gIGxldCB6ZXJvQ29uZlVuc3BlbnRUeElkcztcblxuICAvLyBUaGUgc3VtIG9mIHRoZSBpbnB1dCB2YWx1ZXMgZm9yIHRoaXMgdHJhbnNhY3Rpb24uXG4gIGxldCBpbnB1dEFtb3VudDtcblxuICBsZXQgY2hhbmdlT3V0cHV0czogT3V0cHV0W10gPSBbXTtcblxuICAvLyBUaGUgdHJhbnNhY3Rpb24uXG4gIGxldCB0cmFuc2FjdGlvbiA9IHV0eG9saWIuYml0Z28uY3JlYXRlVHJhbnNhY3Rpb25CdWlsZGVyRm9yTmV0d29yayhuZXR3b3JrKTtcblxuICBjb25zdCBnZXRCaXRHb0ZlZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gQmx1ZWJpcmQudHJ5KGZ1bmN0aW9uICgpIHtcbiAgICAgIGlmIChiaXRnb0ZlZUluZm8pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHBhcmFtcy53YWxsZXQuZ2V0Qml0R29GZWUoeyBhbW91bnQ6IHRvdGFsT3V0cHV0QW1vdW50LCBpbnN0YW50OiBwYXJhbXMuaW5zdGFudCB9KS50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgaWYgKHJlc3VsdCAmJiByZXN1bHQuZmVlID4gMCkge1xuICAgICAgICAgIGJpdGdvRmVlSW5mbyA9IHtcbiAgICAgICAgICAgIGFtb3VudDogcmVzdWx0LmZlZSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgIGlmIChiaXRnb0ZlZUluZm8gJiYgYml0Z29GZWVJbmZvLmFtb3VudCA+IDApIHtcbiAgICAgICAgdG90YWxBbW91bnQgKz0gYml0Z29GZWVJbmZvLmFtb3VudDtcbiAgICAgIH1cbiAgICB9KTtcbiAgfTtcblxuICBjb25zdCBnZXRCaXRHb0ZlZUFkZHJlc3MgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIEJsdWViaXJkLnRyeShmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBJZiB3ZSBkb24ndCBoYXZlIGJpdGdvRmVlSW5mbywgb3IgYWRkcmVzcyBpcyBhbHJlYWR5IHNldCwgZG9uJ3QgZ2V0IGEgbmV3IG9uZVxuICAgICAgaWYgKCFiaXRnb0ZlZUluZm8gfHwgYml0Z29GZWVJbmZvLmFkZHJlc3MpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGJpdGdvLmdldEJpdEdvRmVlQWRkcmVzcygpLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICBiaXRnb0ZlZUluZm8uYWRkcmVzcyA9IHJlc3VsdC5hZGRyZXNzO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gR2V0IGEgZHluYW1pYyBmZWUgZXN0aW1hdGUgZnJvbSB0aGUgQml0R28gc2VydmVyIGlmIGZlZVR4Q29uZmlybVRhcmdldFxuICAvLyBpcyBzcGVjaWZpZWQgb3IgaWYgbm8gZmVlLXJlbGF0ZWQgcGFyYW1zIGFyZSBzcGVjaWZpZWRcbiAgY29uc3QgZ2V0RHluYW1pY0ZlZVJhdGVFc3RpbWF0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAocGFyYW1zLmZlZVR4Q29uZmlybVRhcmdldCB8fCAhZmVlUGFyYW1zRGVmaW5lZCkge1xuICAgICAgcmV0dXJuIGJpdGdvXG4gICAgICAgIC5lc3RpbWF0ZUZlZSh7XG4gICAgICAgICAgbnVtQmxvY2tzOiBwYXJhbXMuZmVlVHhDb25maXJtVGFyZ2V0LFxuICAgICAgICAgIG1heEZlZTogcGFyYW1zLm1heEZlZVJhdGUsXG4gICAgICAgICAgaW5wdXRzOiB6ZXJvQ29uZlVuc3BlbnRUeElkcyxcbiAgICAgICAgICB0eFNpemU6IGVzdFR4U2l6ZSxcbiAgICAgICAgICBjcGZwQXdhcmU6IHRydWUsXG4gICAgICAgIH0pXG4gICAgICAgIC50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICBjb25zdCBlc3RpbWF0ZWRGZWVSYXRlID0gcmVzdWx0LmNwZnBGZWVQZXJLYjtcbiAgICAgICAgICBjb25zdCBtaW5pbXVtID0gcGFyYW1zLmluc3RhbnRcbiAgICAgICAgICAgID8gTWF0aC5tYXgoY29uc3RhbnRzLm1pbkZlZVJhdGUsIGNvbnN0YW50cy5taW5JbnN0YW50RmVlUmF0ZSlcbiAgICAgICAgICAgIDogY29uc3RhbnRzLm1pbkZlZVJhdGU7XG4gICAgICAgICAgLy8gNSBzYXRvc2hpcyBwZXIgYnl0ZVxuICAgICAgICAgIC8vIGl0IGlzIHdvcnRoIG5vdGluZyB0aGF0IHRoZSBwYWRkaW5nIG9ubHkgYXBwbGllcyB3aGVuIHRoZSB0aHJlc2hvbGQgaXMgY3Jvc3NlZCwgYnV0IG5vdCB3aGVuIHRoZSBkZWx0YSBpcyBsZXNzIHRoYW4gdGhlIHBhZGRpbmdcbiAgICAgICAgICBjb25zdCBwYWRkaW5nID0gNTAwMDtcbiAgICAgICAgICBpZiAoZXN0aW1hdGVkRmVlUmF0ZSA8IG1pbmltdW0pIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICBuZXcgRGF0ZSgpICtcbiAgICAgICAgICAgICAgICAnOiBFcnJvciB3aGVuIGVzdGltYXRpbmcgZmVlIGZvciBzZW5kIGZyb20gJyArXG4gICAgICAgICAgICAgICAgcGFyYW1zLndhbGxldC5pZCgpICtcbiAgICAgICAgICAgICAgICAnLCBpdCB3YXMgdG9vIGxvdyAtICcgK1xuICAgICAgICAgICAgICAgIGVzdGltYXRlZEZlZVJhdGVcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBmZWVSYXRlID0gbWluaW11bSArIHBhZGRpbmc7XG4gICAgICAgICAgfSBlbHNlIGlmIChlc3RpbWF0ZWRGZWVSYXRlID4gcGFyYW1zLm1heEZlZVJhdGUpIHtcbiAgICAgICAgICAgIGZlZVJhdGUgPSBwYXJhbXMubWF4RmVlUmF0ZSAtIHBhZGRpbmc7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGZlZVJhdGUgPSBlc3RpbWF0ZWRGZWVSYXRlO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gZmVlUmF0ZTtcbiAgICAgICAgfSlcbiAgICAgICAgLmNhdGNoKGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgLy8gc2FuaXR5IGNoZWNrIGZhaWxlZCBvbiB0eCBzaXplXG4gICAgICAgICAgaWYgKF8uaW5jbHVkZXMoZS5tZXNzYWdlLCAnaW52YWxpZCB0eFNpemUnKSkge1xuICAgICAgICAgICAgcmV0dXJuIEJsdWViaXJkLnJlamVjdChlKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gY291bGRuJ3QgZXN0aW1hdGUgdGhlIGZlZSwgcHJvY2VlZCB1c2luZyB0aGUgZGVmYXVsdFxuICAgICAgICAgICAgZmVlUmF0ZSA9IGNvbnN0YW50cy5mYWxsYmFja0ZlZVJhdGU7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygnRXJyb3IgZXN0aW1hdGluZyBmZWUgZm9yIHNlbmQgZnJvbSAnICsgcGFyYW1zLndhbGxldC5pZCgpICsgJzogJyArIGUubWVzc2FnZSk7XG4gICAgICAgICAgICByZXR1cm4gQmx1ZWJpcmQucmVzb2x2ZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICB9O1xuXG4gIC8vIEdldCB0aGUgdW5zcGVudHMgZm9yIHRoZSBzZW5kaW5nIHdhbGxldC5cbiAgY29uc3QgZ2V0VW5zcGVudHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHBhcmFtcy51bnNwZW50cykge1xuICAgICAgLy8gd2UganVzdCB3YW5uYSB1c2UgY3VzdG9tIHVuc3BlbnRzXG4gICAgICB1bnNwZW50cyA9IHBhcmFtcy51bnNwZW50cztcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBHZXQgZW5vdWdoIHVuc3BlbnRzIGZvciB0aGUgcmVxdWVzdGVkIGFtb3VudFxuICAgIGNvbnN0IG9wdGlvbnMgPSBfLm1lcmdlKHt9LCBwYXJhbXMudW5zcGVudHNGZXRjaFBhcmFtcyB8fCB7fSwge1xuICAgICAgdGFyZ2V0OiB0b3RhbEFtb3VudCxcbiAgICAgIG1pblNpemU6IHBhcmFtcy5taW5VbnNwZW50U2l6ZSB8fCAwLFxuICAgICAgaW5zdGFudDogcGFyYW1zLmluc3RhbnQsIC8vIGluc2lzdCBvbiBpbnN0YW50IHVuc3BlbnRzIG9ubHlcbiAgICAgIHRhcmdldFdhbGxldFVuc3BlbnRzOiBwYXJhbXMudGFyZ2V0V2FsbGV0VW5zcGVudHMsXG4gICAgfSk7XG4gICAgaWYgKHBhcmFtcy5pbnN0YW50KSB7XG4gICAgICBvcHRpb25zLmluc3RhbnQgPSBwYXJhbXMuaW5zdGFudDsgLy8gaW5zaXN0IG9uIGluc3RhbnQgdW5zcGVudHMgb25seVxuICAgIH1cblxuICAgIHJldHVybiBwYXJhbXMud2FsbGV0LnVuc3BlbnRzUGFnZWQob3B0aW9ucykudGhlbihmdW5jdGlvbiAocmVzdWx0cykge1xuICAgICAgdG90YWxVbnNwZW50c0NvdW50ID0gcmVzdWx0cy50b3RhbDtcbiAgICAgIGZldGNoZWRVbnNwZW50c0NvdW50ID0gcmVzdWx0cy5jb3VudDtcbiAgICAgIHVuc3BlbnRzID0gcmVzdWx0cy51bnNwZW50cy5maWx0ZXIoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgY29uc3QgY29uZmlybXMgPSB1LmNvbmZpcm1hdGlvbnMgfHwgMDtcbiAgICAgICAgaWYgKCFwYXJhbXMuZW5mb3JjZU1pbkNvbmZpcm1zRm9yQ2hhbmdlICYmIHUuaXNDaGFuZ2UpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY29uZmlybXMgPj0gbWluQ29uZmlybXM7XG4gICAgICB9KTtcblxuICAgICAgLy8gYWJvcnQgZWFybHkgaWYgdGhlcmUncyBubyB2aWFibGUgdW5zcGVudHMsIGJlY2F1c2UgaXQgd29uJ3QgYmUgcG9zc2libGUgdG8gY3JlYXRlIHRoZSB0eG4gbGF0ZXJcbiAgICAgIGlmICh1bnNwZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgdGhyb3cgRXJyb3IoJzAgdW5zcGVudHMgYXZhaWxhYmxlIGZvciB0cmFuc2FjdGlvbiBjcmVhdGlvbicpO1xuICAgICAgfVxuXG4gICAgICAvLyBjcmVhdGUgYXJyYXkgb2YgdW5jb25maXJtZWQgdW5zcGVudCBJRCBzdHJpbmdzIG9mIHRoZSBmb3JtIFwidHhIYXNoOm91dHB1dEluZGV4XCJcbiAgICAgIHplcm9Db25mVW5zcGVudFR4SWRzID0gXyhyZXN1bHRzLnVuc3BlbnRzKVxuICAgICAgICAuZmlsdGVyKGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgcmV0dXJuICF1LmNvbmZpcm1hdGlvbnM7XG4gICAgICAgIH0pXG4gICAgICAgIC5tYXAoZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICByZXR1cm4gdS50eF9oYXNoICsgJzonICsgdS50eF9vdXRwdXRfbjtcbiAgICAgICAgfSlcbiAgICAgICAgLnZhbHVlKCk7XG4gICAgICBpZiAoXy5pc0VtcHR5KHplcm9Db25mVW5zcGVudFR4SWRzKSkge1xuICAgICAgICAvLyB3ZSBkb24ndCB3YW50IHRvIHBhc3MgYW4gZW1wdHkgYXJyYXkgb2YgaW5wdXRzIHRvIHRoZSBzZXJ2ZXIsIGJlY2F1c2UgaXQgYXNzdW1lcyBpZiB0aGVcbiAgICAgICAgLy8gaW5wdXRzIGFyZ3VtZW50cyBleGlzdHMsIGl0IGNvbnRhaW5zIHZhbHVlc1xuICAgICAgICB6ZXJvQ29uZlVuc3BlbnRUeElkcyA9IHVuZGVmaW5lZDtcbiAgICAgIH1cblxuICAgICAgLy8gRm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5LCByZXNwZWN0IHRoZSBvbGQgc3BsaXRDaGFuZ2VTaXplPTAgcGFyYW1ldGVyXG4gICAgICBpZiAoIXBhcmFtcy5ub1NwbGl0Q2hhbmdlICYmIHBhcmFtcy5zcGxpdENoYW5nZVNpemUgIT09IDApIHtcbiAgICAgICAgZXh0cmFDaGFuZ2VBbW91bnRzID0gcmVzdWx0cy5leHRyYUNoYW5nZUFtb3VudHMgfHwgW107XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gR2V0IHRoZSB1bnNwZW50cyBmb3IgdGhlIHNpbmdsZSBrZXkgZmVlIGFkZHJlc3NcbiAgbGV0IGZlZVNpbmdsZUtleVVuc3BlbnRzOiBCaXRHb1Vuc3BlbnRbXSA9IFtdO1xuICBjb25zdCBnZXRVbnNwZW50c0ZvclNpbmdsZUtleSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcykge1xuICAgICAgbGV0IGZlZVRhcmdldCA9IDAuMDFlODtcbiAgICAgIGlmIChwYXJhbXMuaW5zdGFudCkge1xuICAgICAgICBmZWVUYXJnZXQgKz0gdG90YWxBbW91bnQgKiAwLjAwMTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBiaXRnb1xuICAgICAgICAuZ2V0KGJpdGdvLnVybCgnL2FkZHJlc3MvJyArIGZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MgKyAnL3Vuc3BlbnRzP3RhcmdldD0nICsgZmVlVGFyZ2V0KSlcbiAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgaWYgKHJlc3BvbnNlLmJvZHkudG90YWwgPD0gMCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1bnNwZW50cyBhdmFpbGFibGUgaW4gc2luZ2xlIGtleSBmZWUgc291cmNlJyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGZlZVNpbmdsZUtleVVuc3BlbnRzID0gcmVzcG9uc2UuYm9keS51bnNwZW50cztcbiAgICAgICAgfSk7XG4gICAgfVxuICB9O1xuXG4gIGxldCBtaW5lckZlZUluZm86IGFueSA9IHt9O1xuICBsZXQgdHhJbmZvOiBhbnkgPSB7fTtcblxuICAvLyBJdGVyYXRlIHVuc3BlbnRzLCBzdW0gdGhlIGlucHV0cywgYW5kIHNhdmUgX2lucHV0cyB3aXRoIHRoZSB0b3RhbFxuICAvLyBpbnB1dCBhbW91bnQgYW5kIGZpbmFsIGxpc3Qgb2YgaW5wdXRzIHRvIHVzZSB3aXRoIHRoZSB0cmFuc2FjdGlvbi5cbiAgbGV0IGZlZVNpbmdsZUtleVVuc3BlbnRzVXNlZDogQml0R29VbnNwZW50W10gPSBbXTtcblxuICBjb25zdCBjb2xsZWN0SW5wdXRzID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICghdW5zcGVudHMubGVuZ3RoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ25vIHVuc3BlbnRzIGF2YWlsYWJsZSBvbiB3YWxsZXQnKTtcbiAgICB9XG4gICAgaW5wdXRBbW91bnQgPSAwO1xuXG4gICAgLy8gQ2FsY3VsYXRlIHRoZSBjb3N0IG9mIHNwZW5kaW5nIGEgc2luZ2xlIGlucHV0LCBpLmUuIHRoZSBzbWFsbGVzdCBlY29ub21pY2FsIHVuc3BlbnQgdmFsdWVcbiAgICByZXR1cm4gQmx1ZWJpcmQudHJ5KGZ1bmN0aW9uICgpIHtcbiAgICAgIGlmIChfLmlzTnVtYmVyKHBhcmFtcy5mZWVSYXRlKSB8fCBfLmlzTnVtYmVyKHBhcmFtcy5vcmlnaW5hbEZlZVJhdGUpKSB7XG4gICAgICAgIHJldHVybiAhXy5pc1VuZGVmaW5lZChwYXJhbXMuZmVlUmF0ZSkgPyBwYXJhbXMuZmVlUmF0ZSA6IHBhcmFtcy5vcmlnaW5hbEZlZVJhdGU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gYml0Z29cbiAgICAgICAgICAuZXN0aW1hdGVGZWUoe1xuICAgICAgICAgICAgbnVtQmxvY2tzOiBwYXJhbXMuZmVlVHhDb25maXJtVGFyZ2V0LFxuICAgICAgICAgICAgbWF4RmVlOiBwYXJhbXMubWF4RmVlUmF0ZSxcbiAgICAgICAgICB9KVxuICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChmZWVSYXRlRXN0aW1hdGUpIHtcbiAgICAgICAgICAgIHJldHVybiBmZWVSYXRlRXN0aW1hdGUuZmVlUGVyS2I7XG4gICAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSlcbiAgICAgIC50aGVuKGZ1bmN0aW9uIChmZWVSYXRlKSB7XG4gICAgICAgIC8vIERvbid0IHNwZW5kIGlucHV0cyB0aGF0IGNhbm5vdCBwYXkgZm9yIHRoZWlyIG93biBjb3N0LlxuICAgICAgICBsZXQgbWluSW5wdXRWYWx1ZSA9IDA7XG4gICAgICAgIGlmIChfLmlzSW50ZWdlcihwYXJhbXMubWluVW5zcGVudFNpemUpKSB7XG4gICAgICAgICAgbWluSW5wdXRWYWx1ZSA9IHBhcmFtcy5taW5VbnNwZW50U2l6ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBwcnVuZWRVbnNwZW50Q291bnQgPSAwO1xuICAgICAgICBjb25zdCBvcmlnaW5hbFVuc3BlbnRDb3VudCA9IHVuc3BlbnRzLmxlbmd0aDtcbiAgICAgICAgdW5zcGVudHMgPSBfLmZpbHRlcih1bnNwZW50cywgZnVuY3Rpb24gKHVuc3BlbnQpIHtcbiAgICAgICAgICBjb25zdCBpc1NlZ3dpdElucHV0ID0gISF1bnNwZW50LndpdG5lc3NTY3JpcHQ7XG4gICAgICAgICAgY29uc3QgY3VycmVudElucHV0U2l6ZSA9IGlzU2Vnd2l0SW5wdXQgPyBWaXJ0dWFsU2l6ZXMudHhQMnNoUDJ3c2hJbnB1dFNpemUgOiBWaXJ0dWFsU2l6ZXMudHhQMnNoSW5wdXRTaXplO1xuICAgICAgICAgIGNvbnN0IGZlZUJhc2VkTWluSW5wdXRWYWx1ZSA9IChmZWVSYXRlICogY3VycmVudElucHV0U2l6ZSkgLyAxMDAwO1xuICAgICAgICAgIGNvbnN0IGN1cnJlbnRNaW5JbnB1dFZhbHVlID0gTWF0aC5tYXgobWluSW5wdXRWYWx1ZSwgZmVlQmFzZWRNaW5JbnB1dFZhbHVlKTtcbiAgICAgICAgICBpZiAoY3VycmVudE1pbklucHV0VmFsdWUgPiB1bnNwZW50LnZhbHVlKSB7XG4gICAgICAgICAgICAvLyBwcnVuaW5nIHVuc3BlbnRcbiAgICAgICAgICAgIGNvbnN0IHBydW5lRGV0YWlscyA9IHtcbiAgICAgICAgICAgICAgZ2VuZXJhbE1pbklucHV0VmFsdWU6IG1pbklucHV0VmFsdWUsXG4gICAgICAgICAgICAgIGZlZUJhc2VkTWluSW5wdXRWYWx1ZSxcbiAgICAgICAgICAgICAgY3VycmVudE1pbklucHV0VmFsdWUsXG4gICAgICAgICAgICAgIGZlZVJhdGUsXG4gICAgICAgICAgICAgIGlucHV0U2l6ZTogY3VycmVudElucHV0U2l6ZSxcbiAgICAgICAgICAgICAgdW5zcGVudDogdW5zcGVudCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgcHJ1bmluZyB1bnNwZW50OiAke0pTT04uc3RyaW5naWZ5KHBydW5lRGV0YWlscywgbnVsbCwgNCl9YCk7XG4gICAgICAgICAgICBwcnVuZWRVbnNwZW50Q291bnQrKztcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChwcnVuZWRVbnNwZW50Q291bnQgPiAwKSB7XG4gICAgICAgICAgY29uc29sZS5sb2coYHBydW5lZCAke3BydW5lZFVuc3BlbnRDb3VudH0gb3V0IG9mICR7b3JpZ2luYWxVbnNwZW50Q291bnR9IHVuc3BlbnRzYCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodW5zcGVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnN1ZmZpY2llbnQgZnVuZHMnKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgc2Vnd2l0SW5wdXRDb3VudCA9IDA7XG4gICAgICAgIHVuc3BlbnRzLmV2ZXJ5KGZ1bmN0aW9uICh1bnNwZW50KSB7XG4gICAgICAgICAgaWYgKHVuc3BlbnQud2l0bmVzc1NjcmlwdCkge1xuICAgICAgICAgICAgc2Vnd2l0SW5wdXRDb3VudCsrO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpbnB1dEFtb3VudCArPSB1bnNwZW50LnZhbHVlO1xuICAgICAgICAgIHRyYW5zYWN0aW9uLmFkZElucHV0KHVuc3BlbnQudHhfaGFzaCwgdW5zcGVudC50eF9vdXRwdXRfbiwgMHhmZmZmZmZmZik7XG5cbiAgICAgICAgICByZXR1cm4gaW5wdXRBbW91bnQgPCAoZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcyA/IHRvdGFsT3V0cHV0QW1vdW50IDogdG90YWxBbW91bnQpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBpZiBwYXlpbmcgZmVlcyBmcm9tIGFuIGV4dGVybmFsIHNpbmdsZSBrZXkgd2FsbGV0LCBhZGQgdGhlIGlucHV0c1xuICAgICAgICBpZiAoZmVlU2luZ2xlS2V5U291cmNlQWRkcmVzcykge1xuICAgICAgICAgIC8vIGNvbGxlY3QgdGhlIGFtb3VudCB1c2VkIGluIHRoZSBmZWUgaW5wdXRzIHNvIHdlIGNhbiBnZXQgY2hhbmdlIGxhdGVyXG4gICAgICAgICAgZmVlU2luZ2xlS2V5SW5wdXRBbW91bnQgPSAwO1xuICAgICAgICAgIGZlZVNpbmdsZUtleVVuc3BlbnRzVXNlZCA9IFtdO1xuICAgICAgICAgIGZlZVNpbmdsZUtleVVuc3BlbnRzLmV2ZXJ5KGZ1bmN0aW9uICh1bnNwZW50KSB7XG4gICAgICAgICAgICBmZWVTaW5nbGVLZXlJbnB1dEFtb3VudCArPSB1bnNwZW50LnZhbHVlO1xuICAgICAgICAgICAgaW5wdXRBbW91bnQgKz0gdW5zcGVudC52YWx1ZTtcbiAgICAgICAgICAgIHRyYW5zYWN0aW9uLmFkZElucHV0KHVuc3BlbnQudHhfaGFzaCwgdW5zcGVudC50eF9vdXRwdXRfbik7XG4gICAgICAgICAgICBmZWVTaW5nbGVLZXlVbnNwZW50c1VzZWQucHVzaCh1bnNwZW50KTtcbiAgICAgICAgICAgIC8vIHVzZSB0aGUgZmVlIHdhbGxldCB0byBwYXkgbWluZXIgZmVlcyBhbmQgcG90ZW50aWFsbHkgaW5zdGFudCBmZWVzXG4gICAgICAgICAgICByZXR1cm4gZmVlU2luZ2xlS2V5SW5wdXRBbW91bnQgPCBmZWUgKyAoYml0Z29GZWVJbmZvID8gYml0Z29GZWVJbmZvLmFtb3VudCA6IDApO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgdHhJbmZvID0ge1xuICAgICAgICAgIG5QMnNoSW5wdXRzOiB0cmFuc2FjdGlvbi50eC5pbnMubGVuZ3RoIC0gKGZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MgPyAxIDogMCkgLSBzZWd3aXRJbnB1dENvdW50LFxuICAgICAgICAgIG5QMnNoUDJ3c2hJbnB1dHM6IHNlZ3dpdElucHV0Q291bnQsXG4gICAgICAgICAgblAycGtoSW5wdXRzOiBmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzID8gMSA6IDAsXG4gICAgICAgICAgLy8gYWRkIHNpbmdsZSBrZXkgc291cmNlIGFkZHJlc3MgY2hhbmdlXG4gICAgICAgICAgbk91dHB1dHM6XG4gICAgICAgICAgICByZWNpcGllbnRzLmxlbmd0aCArXG4gICAgICAgICAgICAxICsgLy8gcmVjaXBpZW50cyBhbmQgY2hhbmdlXG4gICAgICAgICAgICBleHRyYUNoYW5nZUFtb3VudHMubGVuZ3RoICsgLy8gZXh0cmEgY2hhbmdlIHNwbGl0dGluZ1xuICAgICAgICAgICAgKGJpdGdvRmVlSW5mbyAmJiBiaXRnb0ZlZUluZm8uYW1vdW50ID4gMCA/IDEgOiAwKSArIC8vIGFkZCBvdXRwdXQgZm9yIGJpdGdvIGZlZVxuICAgICAgICAgICAgKGZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MgPyAxIDogMCksXG4gICAgICAgIH07XG5cbiAgICAgICAgZXN0VHhTaXplID0gZXN0aW1hdGVUcmFuc2FjdGlvblNpemUoe1xuICAgICAgICAgIG5QMnNoSW5wdXRzOiB0eEluZm8ublAyc2hJbnB1dHMsXG4gICAgICAgICAgblAyc2hQMndzaElucHV0czogdHhJbmZvLm5QMnNoUDJ3c2hJbnB1dHMsXG4gICAgICAgICAgblAycGtoSW5wdXRzOiB0eEluZm8ublAycGtoSW5wdXRzLFxuICAgICAgICAgIG5PdXRwdXRzOiB0eEluZm8ubk91dHB1dHMsXG4gICAgICAgIH0pO1xuICAgICAgfSlcbiAgICAgIC50aGVuKGdldER5bmFtaWNGZWVSYXRlRXN0aW1hdGUpXG4gICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgIG1pbmVyRmVlSW5mbyA9IGV4cG9ydHMuY2FsY3VsYXRlTWluZXJGZWVJbmZvKHtcbiAgICAgICAgICBiaXRnbzogcGFyYW1zLndhbGxldC5iaXRnbyxcbiAgICAgICAgICBmZWVSYXRlOiBmZWVSYXRlLFxuICAgICAgICAgIG5QMnNoSW5wdXRzOiB0eEluZm8ublAyc2hJbnB1dHMsXG4gICAgICAgICAgblAyc2hQMndzaElucHV0czogdHhJbmZvLm5QMnNoUDJ3c2hJbnB1dHMsXG4gICAgICAgICAgblAycGtoSW5wdXRzOiB0eEluZm8ublAycGtoSW5wdXRzLFxuICAgICAgICAgIG5PdXRwdXRzOiB0eEluZm8ubk91dHB1dHMsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChzaG91bGRDb21wdXRlQmVzdEZlZSkge1xuICAgICAgICAgIGNvbnN0IGFwcHJveGltYXRlRmVlID0gbWluZXJGZWVJbmZvLmZlZTtcbiAgICAgICAgICBjb25zdCBzaG91bGRSZWN1cnNlID0gXy5pc1VuZGVmaW5lZChmZWUpIHx8IGFwcHJveGltYXRlRmVlID4gZmVlO1xuICAgICAgICAgIGZlZSA9IGFwcHJveGltYXRlRmVlO1xuICAgICAgICAgIC8vIFJlY29tcHV0ZSB0b3RhbEFtb3VudCBmcm9tIHNjcmF0Y2hcbiAgICAgICAgICB0b3RhbEFtb3VudCA9IGZlZSArIHRvdGFsT3V0cHV0QW1vdW50O1xuICAgICAgICAgIGlmIChiaXRnb0ZlZUluZm8pIHtcbiAgICAgICAgICAgIHRvdGFsQW1vdW50ICs9IGJpdGdvRmVlSW5mby5hbW91bnQ7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChzaG91bGRSZWN1cnNlKSB7XG4gICAgICAgICAgICAvLyBpZiBmZWUgY2hhbmdlZCwgcmUtY29sbGVjdCBpbnB1dHNcbiAgICAgICAgICAgIGlucHV0QW1vdW50ID0gMDtcbiAgICAgICAgICAgIHRyYW5zYWN0aW9uID0gdXR4b2xpYi5iaXRnby5jcmVhdGVUcmFuc2FjdGlvbkJ1aWxkZXJGb3JOZXR3b3JrKG5ldHdvcmspO1xuICAgICAgICAgICAgcmV0dXJuIGNvbGxlY3RJbnB1dHMoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB0b3RhbEZlZSA9IGZlZSArIChiaXRnb0ZlZUluZm8gPyBiaXRnb0ZlZUluZm8uYW1vdW50IDogMCk7XG5cbiAgICAgICAgaWYgKGZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MpIHtcbiAgICAgICAgICBjb25zdCBzdW1tZWRTaW5nbGVLZXlVbnNwZW50cyA9IF8uc3VtQnkoZmVlU2luZ2xlS2V5VW5zcGVudHMsICd2YWx1ZScpO1xuICAgICAgICAgIGlmICh0b3RhbEZlZSA+IHN1bW1lZFNpbmdsZUtleVVuc3BlbnRzKSB7XG4gICAgICAgICAgICBjb25zdCBlcnI6IGFueSA9IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgJ0luc3VmZmljaWVudCBmZWUgYW1vdW50IGF2YWlsYWJsZSBpbiBzaW5nbGUga2V5IGZlZSBzb3VyY2U6ICcgKyBzdW1tZWRTaW5nbGVLZXlVbnNwZW50c1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGVyci5yZXN1bHQgPSB7XG4gICAgICAgICAgICAgIGZlZTogZmVlLFxuICAgICAgICAgICAgICBmZWVSYXRlOiBmZWVSYXRlLFxuICAgICAgICAgICAgICBlc3RpbWF0ZWRTaXplOiBtaW5lckZlZUluZm8uc2l6ZSxcbiAgICAgICAgICAgICAgYXZhaWxhYmxlOiBpbnB1dEFtb3VudCxcbiAgICAgICAgICAgICAgYml0Z29GZWU6IGJpdGdvRmVlSW5mbyxcbiAgICAgICAgICAgICAgdHhJbmZvOiB0eEluZm8sXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuIEJsdWViaXJkLnJlamVjdChlcnIpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpbnB1dEFtb3VudCA8IChmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzID8gdG90YWxPdXRwdXRBbW91bnQgOiB0b3RhbEFtb3VudCkpIHtcbiAgICAgICAgICAvLyBUaGUgdW5zcGVudHMgd2UncmUgdXNpbmcgZm9yIGlucHV0cyBkbyBub3QgaGF2ZSBzdWZmaWNpZW50IHZhbHVlIG9uIHRoZW0gdG9cbiAgICAgICAgICAvLyBzYXRpc2Z5IHRoZSB1c2VyJ3MgcmVxdWVzdGVkIHNwZW5kIGFtb3VudC4gVGhhdCBtYXkgYmUgYmVjYXVzZSB0aGUgd2FsbGV0J3MgYmFsYW5jZVxuICAgICAgICAgIC8vIGlzIHNpbXBseSB0b28gbG93LCBvciBpdCBtaWdodCBiZSB0aGF0IHRoZSB3YWxsZXQncyBiYWxhbmNlIGlzIHN1ZmZpY2llbnQgYnV0XG4gICAgICAgICAgLy8gd2UgZGlkbid0IGZldGNoIGVub3VnaCB1bnNwZW50cy4gVG9vIGZldyB1bnNwZW50cyBjb3VsZCByZXN1bHQgZnJvbSB0aGUgd2FsbGV0XG4gICAgICAgICAgLy8gaGF2aW5nIG1hbnkgc21hbGwgdW5zcGVudHMgYW5kIHdlIGhpdCBvdXIgbGltaXQgb24gdGhlIG51bWJlciBvZiBpbnB1dHMgd2UgY2FuIHVzZVxuICAgICAgICAgIC8vIGluIGEgdHhuLCBvciBpdCBtaWdodCBoYXZlIGJlZW4gdGhhdCB0aGUgZmlsdGVycyB0aGUgdXNlciBwYXNzZWQgaW4gKGxpa2UgbWluQ29uZmlybXMpXG4gICAgICAgICAgLy8gZGlzcXVhbGlmaWVkIHRvbyBtYW55IG9mIHRoZSB1bnNwZW50c1xuICAgICAgICAgIGxldCBlcnI7XG4gICAgICAgICAgaWYgKHRvdGFsVW5zcGVudHNDb3VudCA9PT0gZmV0Y2hlZFVuc3BlbnRzQ291bnQpIHtcbiAgICAgICAgICAgIC8vIHdlIGZldGNoZWQgZXZlcnkgdW5zcGVudCB0aGUgd2FsbGV0IGhhZCwgYnV0IGl0IHN0aWxsIHdhc24ndCBlbm91Z2hcbiAgICAgICAgICAgIGVyciA9IG5ldyBFcnJvcignSW5zdWZmaWNpZW50IGZ1bmRzJyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIHdlIHdlcmVuJ3QgYWJsZSB0byBmZXRjaCBhbGwgdGhlIHVuc3BlbnRzIG9uIHRoZSB3YWxsZXRcbiAgICAgICAgICAgIGVyciA9IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgYFRyYW5zYWN0aW9uIHNpemUgdG9vIGxhcmdlIGR1ZSB0byB0b28gbWFueSB1bnNwZW50cy4gQ2FuIHNlbmQgb25seSAke2lucHV0QW1vdW50fSBzYXRvc2hpcyBpbiB0aGlzIHRyYW5zYWN0aW9uYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgZXJyLnJlc3VsdCA9IHtcbiAgICAgICAgICAgIGZlZTogZmVlLFxuICAgICAgICAgICAgZmVlUmF0ZTogZmVlUmF0ZSxcbiAgICAgICAgICAgIGVzdGltYXRlZFNpemU6IG1pbmVyRmVlSW5mby5zaXplLFxuICAgICAgICAgICAgYXZhaWxhYmxlOiBpbnB1dEFtb3VudCxcbiAgICAgICAgICAgIGJpdGdvRmVlOiBiaXRnb0ZlZUluZm8sXG4gICAgICAgICAgICB0eEluZm86IHR4SW5mbyxcbiAgICAgICAgICB9O1xuICAgICAgICAgIHJldHVybiBCbHVlYmlyZC5yZWplY3QoZXJyKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gIH07XG5cbiAgLy8gQWRkIHRoZSBvdXRwdXRzIGZvciB0aGlzIHRyYW5zYWN0aW9uLlxuICBjb25zdCBjb2xsZWN0T3V0cHV0cyA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAobWluZXJGZWVJbmZvLnNpemUgPj0gOTAwMDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndHJhbnNhY3Rpb24gdG9vIGxhcmdlOiBlc3RpbWF0ZWQgc2l6ZSAnICsgbWluZXJGZWVJbmZvLnNpemUgKyAnIGJ5dGVzJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgb3V0cHV0czogT3V0cHV0W10gPSBbXTtcblxuICAgIHJlY2lwaWVudHMuZm9yRWFjaChmdW5jdGlvbiAocmVjaXBpZW50KSB7XG4gICAgICBsZXQgc2NyaXB0O1xuICAgICAgaWYgKF8uaXNTdHJpbmcocmVjaXBpZW50LmFkZHJlc3MpKSB7XG4gICAgICAgIHNjcmlwdCA9IHV0eG9saWIuYWRkcmVzcy50b091dHB1dFNjcmlwdChyZWNpcGllbnQuYWRkcmVzcywgbmV0d29yayk7XG4gICAgICB9IGVsc2UgaWYgKF8uaXNPYmplY3QocmVjaXBpZW50LnNjcmlwdCkpIHtcbiAgICAgICAgc2NyaXB0ID0gcmVjaXBpZW50LnNjcmlwdDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignbmVpdGhlciByZWNpcGllbnQgYWRkcmVzcyBub3Igc2NyaXB0IHdhcyBwcm92aWRlZCcpO1xuICAgICAgfVxuXG4gICAgICAvLyB2YWxpZGF0ZSB0cmF2ZWxJbmZvIGlmIGl0IGV4aXN0c1xuICAgICAgbGV0IHRyYXZlbEluZm87XG4gICAgICBpZiAoIV8uaXNFbXB0eShyZWNpcGllbnQudHJhdmVsSW5mbykpIHtcbiAgICAgICAgdHJhdmVsSW5mbyA9IHJlY2lwaWVudC50cmF2ZWxJbmZvO1xuICAgICAgICAvLyBCZXR0ZXIgdG8gYXZvaWQgdHJvdWJsZSBub3csIGJlZm9yZSB0eCBpcyBjcmVhdGVkXG4gICAgICAgIGJpdGdvLnRyYXZlbFJ1bGUoKS52YWxpZGF0ZVRyYXZlbEluZm8odHJhdmVsSW5mbyk7XG4gICAgICB9XG5cbiAgICAgIG91dHB1dHMucHVzaCh7XG4gICAgICAgIHNjcmlwdDogc2NyaXB0LFxuICAgICAgICBhbW91bnQ6IHJlY2lwaWVudC5hbW91bnQsXG4gICAgICAgIHRyYXZlbEluZm86IHRyYXZlbEluZm8sXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIG9wUmV0dXJucy5mb3JFYWNoKGZ1bmN0aW9uICh7IG1lc3NhZ2UsIGFtb3VudCB9KSB7XG4gICAgICBjb25zdCBzY3JpcHQgPSB1dHhvbGliLnNjcmlwdC5mcm9tQVNNKCdPUF9SRVRVUk4gJyArIEJ1ZmZlci5mcm9tKG1lc3NhZ2UpLnRvU3RyaW5nKCdoZXgnKSk7XG4gICAgICBvdXRwdXRzLnB1c2goeyBzY3JpcHQsIGFtb3VudCB9KTtcbiAgICB9KTtcblxuICAgIGNvbnN0IGdldENoYW5nZU91dHB1dHMgPSBmdW5jdGlvbiAoY2hhbmdlQW1vdW50OiBudW1iZXIpOiBPdXRwdXRbXSB8IEJsdWViaXJkPE91dHB1dFtdPiB7XG4gICAgICBpZiAoY2hhbmdlQW1vdW50IDwgMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ25lZ2F0aXZlIGNoYW5nZSBhbW91bnQ6ICcgKyBjaGFuZ2VBbW91bnQpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCByZXN1bHQ6IE91dHB1dFtdID0gW107XG4gICAgICAvLyBpZiB3ZSBwYWlkIGZlZXMgZnJvbSBhIHNpbmdsZSBrZXkgd2FsbGV0LCByZXR1cm4gdGhlIGZlZSBjaGFuZ2UgZmlyc3RcbiAgICAgIGlmIChmZWVTaW5nbGVLZXlTb3VyY2VBZGRyZXNzKSB7XG4gICAgICAgIGNvbnN0IGZlZVNpbmdsZUtleVdhbGxldENoYW5nZUFtb3VudCA9XG4gICAgICAgICAgZmVlU2luZ2xlS2V5SW5wdXRBbW91bnQgLSAoZmVlICsgKGJpdGdvRmVlSW5mbyA/IGJpdGdvRmVlSW5mby5hbW91bnQgOiAwKSk7XG4gICAgICAgIGlmIChmZWVTaW5nbGVLZXlXYWxsZXRDaGFuZ2VBbW91bnQgPj0gY29uc3RhbnRzLm1pbk91dHB1dFNpemUpIHtcbiAgICAgICAgICByZXN1bHQucHVzaCh7IGFkZHJlc3M6IGZlZVNpbmdsZUtleVNvdXJjZUFkZHJlc3MsIGFtb3VudDogZmVlU2luZ2xlS2V5V2FsbGV0Q2hhbmdlQW1vdW50IH0pO1xuICAgICAgICAgIGNoYW5nZUFtb3VudCA9IGNoYW5nZUFtb3VudCAtIGZlZVNpbmdsZUtleVdhbGxldENoYW5nZUFtb3VudDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoY2hhbmdlQW1vdW50IDwgY29uc3RhbnRzLm1pbk91dHB1dFNpemUpIHtcbiAgICAgICAgLy8gR2l2ZSBpdCB0byB0aGUgbWluZXJzXG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9XG5cbiAgICAgIGlmIChwYXJhbXMud2FsbGV0LnR5cGUoKSA9PT0gJ3NhZmUnKSB7XG4gICAgICAgIHJldHVybiBwYXJhbXMud2FsbGV0LmFkZHJlc3NlcygpLnRoZW4oZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgcmVzdWx0LnB1c2goeyBhZGRyZXNzOiByZXNwb25zZS5hZGRyZXNzZXNbMF0uYWRkcmVzcywgYW1vdW50OiBjaGFuZ2VBbW91bnQgfSk7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGxldCBleHRyYUNoYW5nZVRvdGFsID0gXy5zdW0oZXh0cmFDaGFuZ2VBbW91bnRzKTtcbiAgICAgIC8vIFNhbml0eSBjaGVja1xuICAgICAgaWYgKGV4dHJhQ2hhbmdlVG90YWwgPiBjaGFuZ2VBbW91bnQpIHtcbiAgICAgICAgZXh0cmFDaGFuZ2VBbW91bnRzID0gW107XG4gICAgICAgIGV4dHJhQ2hhbmdlVG90YWwgPSAwO1xuICAgICAgfVxuXG4gICAgICAvLyBjb3B5IGFuZCBhZGQgcmVtYWluaW5nIGNoYW5nZSBhbW91bnRcbiAgICAgIGNvbnN0IGFsbENoYW5nZUFtb3VudHMgPSBleHRyYUNoYW5nZUFtb3VudHMuc2xpY2UoMCk7XG4gICAgICBhbGxDaGFuZ2VBbW91bnRzLnB1c2goY2hhbmdlQW1vdW50IC0gZXh0cmFDaGFuZ2VUb3RhbCk7XG5cbiAgICAgIC8vIFJlY3Vyc2l2ZSBhc3luYyBmdW5jIHRvIGFkZCBhbGwgY2hhbmdlIG91dHB1dHNcbiAgICAgIGNvbnN0IGFkZENoYW5nZU91dHB1dHMgPSBmdW5jdGlvbiAoKTogT3V0cHV0W10gfCBCbHVlYmlyZDxPdXRwdXRbXT4ge1xuICAgICAgICBjb25zdCB0aGlzQW1vdW50ID0gYWxsQ2hhbmdlQW1vdW50cy5zaGlmdCgpO1xuICAgICAgICBpZiAoIXRoaXNBbW91bnQpIHtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBCbHVlYmlyZC50cnkoZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGlmIChwYXJhbXMuY2hhbmdlQWRkcmVzcykge1xuICAgICAgICAgICAgLy8gSWYgdXNlciBwYXNzZWQgYSBjaGFuZ2UgYWRkcmVzcywgdXNlIGl0IGZvciBhbGwgb3V0cHV0c1xuICAgICAgICAgICAgcmV0dXJuIHBhcmFtcy5jaGFuZ2VBZGRyZXNzO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBPdGhlcndpc2UgY3JlYXRlIGEgbmV3IGFkZHJlc3MgcGVyIG91dHB1dCwgZm9yIHByaXZhY3lcbiAgICAgICAgICAgIC8vIGRldGVybWluZSBpZiBzZWd3aXQgb3Igbm90XG4gICAgICAgICAgICBjb25zdCBjaGFuZ2VDaGFpbiA9IHBhcmFtcy53YWxsZXQuZ2V0Q2hhbmdlQ2hhaW4ocGFyYW1zKTtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbXMud2FsbGV0LmNyZWF0ZUFkZHJlc3MoeyBjaGFpbjogY2hhbmdlQ2hhaW4sIHZhbGlkYXRlOiB2YWxpZGF0ZSB9KS50aGVuKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdC5hZGRyZXNzO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KS50aGVuKGZ1bmN0aW9uIChhZGRyZXNzKSB7XG4gICAgICAgICAgcmVzdWx0LnB1c2goeyBhZGRyZXNzOiBhZGRyZXNzLCBhbW91bnQ6IHRoaXNBbW91bnQgfSk7XG4gICAgICAgICAgcmV0dXJuIGFkZENoYW5nZU91dHB1dHMoKTtcbiAgICAgICAgfSk7XG4gICAgICB9O1xuXG4gICAgICByZXR1cm4gYWRkQ2hhbmdlT3V0cHV0cygpO1xuICAgIH07XG5cbiAgICAvLyBBZGQgY2hhbmdlIG91dHB1dChzKSBhbmQgaW5zdGFudCBmZWUgb3V0cHV0IGlmIGFwcGxpY2FibGVcbiAgICByZXR1cm4gQmx1ZWJpcmQudHJ5KGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBnZXRDaGFuZ2VPdXRwdXRzKGlucHV0QW1vdW50IC0gdG90YWxBbW91bnQpO1xuICAgIH0pLnRoZW4oZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgY2hhbmdlT3V0cHV0cyA9IHJlc3VsdDtcbiAgICAgIGNvbnN0IGV4dHJhT3V0cHV0cyA9IGNoYW5nZU91dHB1dHMuY29uY2F0KFtdKTsgLy8gY29weSB0aGUgYXJyYXlcbiAgICAgIGlmIChiaXRnb0ZlZUluZm8gJiYgYml0Z29GZWVJbmZvLmFtb3VudCA+IDApIHtcbiAgICAgICAgZXh0cmFPdXRwdXRzLnB1c2goYml0Z29GZWVJbmZvKTtcbiAgICAgIH1cbiAgICAgIGV4dHJhT3V0cHV0cy5mb3JFYWNoKGZ1bmN0aW9uIChvdXRwdXQpIHtcbiAgICAgICAgaWYgKChvdXRwdXQgYXMgQWRkcmVzc091dHB1dCkuYWRkcmVzcykge1xuICAgICAgICAgIChvdXRwdXQgYXMgU2NyaXB0T3V0cHV0KS5zY3JpcHQgPSB1dHhvbGliLmFkZHJlc3MudG9PdXRwdXRTY3JpcHQoKG91dHB1dCBhcyBBZGRyZXNzT3V0cHV0KS5hZGRyZXNzLCBuZXR3b3JrKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGRlY2lkZSB3aGVyZSB0byBwdXQgdGhlIG91dHB1dHMgLSBkZWZhdWx0IGlzIHRvIHJhbmRvbWl6ZSB1bmxlc3MgZm9yY2VkIHRvIGVuZFxuICAgICAgICBjb25zdCBvdXRwdXRJbmRleCA9IHBhcmFtcy5mb3JjZUNoYW5nZUF0RW5kID8gb3V0cHV0cy5sZW5ndGggOiBfLnJhbmRvbSgwLCBvdXRwdXRzLmxlbmd0aCk7XG4gICAgICAgIG91dHB1dHMuc3BsaWNlKG91dHB1dEluZGV4LCAwLCBvdXRwdXQpO1xuICAgICAgfSk7XG5cbiAgICAgIC8vIEFkZCBhbGwgb3V0cHV0cyB0byB0aGUgdHJhbnNhY3Rpb25cbiAgICAgIG91dHB1dHMuZm9yRWFjaChmdW5jdGlvbiAob3V0cHV0KSB7XG4gICAgICAgIHRyYW5zYWN0aW9uLmFkZE91dHB1dCgob3V0cHV0IGFzIFNjcmlwdE91dHB1dCkuc2NyaXB0LCBvdXRwdXQuYW1vdW50KTtcbiAgICAgIH0pO1xuXG4gICAgICB0cmF2ZWxJbmZvcyA9IF8ob3V0cHV0cylcbiAgICAgICAgLm1hcChmdW5jdGlvbiAob3V0cHV0LCBpbmRleCkge1xuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IG91dHB1dC50cmF2ZWxJbmZvO1xuICAgICAgICAgIGlmICghcmVzdWx0KSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXN1bHQub3V0cHV0SW5kZXggPSBpbmRleDtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9KVxuICAgICAgICAuZmlsdGVyKClcbiAgICAgICAgLnZhbHVlKCk7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gU2VyaWFsaXplIHRoZSB0cmFuc2FjdGlvbiwgcmV0dXJuaW5nIHdoYXQgaXMgbmVlZGVkIHRvIHNpZ24gaXRcbiAgY29uc3Qgc2VyaWFsaXplID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIG9ubHkgbmVlZCB0byByZXR1cm4gdGhlIHVuc3BlbnRzIHRoYXQgd2VyZSB1c2VkIGFuZCBqdXN0IHRoZSBjaGFpblBhdGgsIHJlZGVlbVNjcmlwdCwgYW5kIGluc3RhbnQgZmxhZ1xuICAgIGNvbnN0IHBpY2tlZFVuc3BlbnRzOiBhbnkgPSBfLm1hcCh1bnNwZW50cywgZnVuY3Rpb24gKHVuc3BlbnQpIHtcbiAgICAgIHJldHVybiBfLnBpY2sodW5zcGVudCwgWydjaGFpblBhdGgnLCAncmVkZWVtU2NyaXB0JywgJ2luc3RhbnQnLCAnd2l0bmVzc1NjcmlwdCcsICdzY3JpcHQnLCAndmFsdWUnXSk7XG4gICAgfSk7XG4gICAgY29uc3QgcHJ1bmVkVW5zcGVudHMgPSBfLnNsaWNlKHBpY2tlZFVuc3BlbnRzLCAwLCB0cmFuc2FjdGlvbi50eC5pbnMubGVuZ3RoIC0gZmVlU2luZ2xlS2V5VW5zcGVudHNVc2VkLmxlbmd0aCk7XG4gICAgXy5lYWNoKGZlZVNpbmdsZUtleVVuc3BlbnRzVXNlZCwgZnVuY3Rpb24gKGZlZVVuc3BlbnQpIHtcbiAgICAgIHBydW5lZFVuc3BlbnRzLnB1c2goeyByZWRlZW1TY3JpcHQ6IGZhbHNlLCBjaGFpblBhdGg6IGZhbHNlIH0pOyAvLyBtYXJrIGFzIGZhbHNlIHRvIHNpZ25pZnkgYSBub24tbXVsdGlzaWcgYWRkcmVzc1xuICAgIH0pO1xuICAgIGNvbnN0IHJlc3VsdDogYW55ID0ge1xuICAgICAgdHJhbnNhY3Rpb25IZXg6IHRyYW5zYWN0aW9uLmJ1aWxkSW5jb21wbGV0ZSgpLnRvSGV4KCksXG4gICAgICB1bnNwZW50czogcHJ1bmVkVW5zcGVudHMsXG4gICAgICBmZWU6IGZlZSxcbiAgICAgIGNoYW5nZUFkZHJlc3NlczogY2hhbmdlT3V0cHV0cy5tYXAoZnVuY3Rpb24gKGNvKSB7XG4gICAgICAgIHJldHVybiBfLnBpY2soY28sIFsnYWRkcmVzcycsICdwYXRoJywgJ2Ftb3VudCddKTtcbiAgICAgIH0pLFxuICAgICAgd2FsbGV0SWQ6IHBhcmFtcy53YWxsZXQuaWQoKSxcbiAgICAgIHdhbGxldEtleWNoYWluczogcGFyYW1zLndhbGxldC5rZXljaGFpbnMsXG4gICAgICBmZWVSYXRlOiBmZWVSYXRlLFxuICAgICAgaW5zdGFudDogcGFyYW1zLmluc3RhbnQsXG4gICAgICBiaXRnb0ZlZTogYml0Z29GZWVJbmZvLFxuICAgICAgZXN0aW1hdGVkU2l6ZTogbWluZXJGZWVJbmZvLnNpemUsXG4gICAgICB0eEluZm86IHR4SW5mbyxcbiAgICAgIHRyYXZlbEluZm9zOiB0cmF2ZWxJbmZvcyxcbiAgICB9O1xuXG4gICAgLy8gQWRkIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eVxuICAgIGlmIChyZXN1bHQuaW5zdGFudCAmJiBiaXRnb0ZlZUluZm8pIHtcbiAgICAgIHJlc3VsdC5pbnN0YW50RmVlID0gXy5waWNrKGJpdGdvRmVlSW5mbywgWydhbW91bnQnLCAnYWRkcmVzcyddKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuXG4gIHJldHVybiBCbHVlYmlyZC50cnkoZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBnZXRCaXRHb0ZlZSgpO1xuICB9KVxuICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBCbHVlYmlyZC5hbGwoW2dldEJpdEdvRmVlQWRkcmVzcygpLCBnZXRVbnNwZW50cygpLCBnZXRVbnNwZW50c0ZvclNpbmdsZUtleSgpXSk7XG4gICAgfSlcbiAgICAudGhlbihjb2xsZWN0SW5wdXRzKVxuICAgIC50aGVuKGNvbGxlY3RPdXRwdXRzKVxuICAgIC50aGVuKHNlcmlhbGl6ZSk7XG59O1xuXG4vKipcbiAqIEVzdGltYXRlIHRoZSBzaXplIG9mIGEgdHJhbnNhY3Rpb24gaW4gYnl0ZXMgYmFzZWQgb24gdGhlIG51bWJlciBvZlxuICogaW5wdXRzIGFuZCBvdXRwdXRzIHByZXNlbnQuXG4gKiBAcGFyYW1zIHBhcmFtcyB7XG4gKiAgIG5QMnNoSW5wdXRzOiBudW1iZXIgb2YgUDJTSCAobXVsdGlzaWcpIGlucHV0c1xuICogICBuUDJwa2hJbnB1dHM6IG51bWJlciBvZiBQMlBLSCAoc2luZ2xlIHNpZykgaW5wdXRzXG4gKiAgIG5PdXRwdXRzOiBudW1iZXIgb2Ygb3V0cHV0c1xuICogfVxuICpcbiAqIEByZXR1cm5zIHNpemU6IGVzdGltYXRlZCBzaXplIG9mIHRoZSB0cmFuc2FjdGlvbiBpbiBieXRlc1xuICovXG5jb25zdCBlc3RpbWF0ZVRyYW5zYWN0aW9uU2l6ZSA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgaWYgKCFfLmlzSW50ZWdlcihwYXJhbXMublAyc2hJbnB1dHMpIHx8IHBhcmFtcy5uUDJzaElucHV0cyA8IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cGVjdGluZyBwb3NpdGl2ZSBuUDJzaElucHV0cycpO1xuICB9XG4gIGlmICghXy5pc0ludGVnZXIocGFyYW1zLm5QMnBraElucHV0cykgfHwgcGFyYW1zLm5QMnBraElucHV0cyA8IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cGVjdGluZyBwb3NpdGl2ZSBuUDJwa2hJbnB1dHMgdG8gYmUgbnVtZXJpYycpO1xuICB9XG4gIGlmICghXy5pc0ludGVnZXIocGFyYW1zLm5QMnNoUDJ3c2hJbnB1dHMpIHx8IHBhcmFtcy5uUDJzaFAyd3NoSW5wdXRzIDwgMCkge1xuICAgIHRocm93IG5ldyBFcnJvcignZXhwZWN0aW5nIHBvc2l0aXZlIG5QMnNoUDJ3c2hJbnB1dHMgdG8gYmUgbnVtZXJpYycpO1xuICB9XG4gIGlmIChwYXJhbXMublAyc2hJbnB1dHMgKyBwYXJhbXMublAyc2hQMndzaElucHV0cyA8IDEpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cGVjdGluZyBhdCBsZWFzdCBvbmUgblAyc2hJbnB1dHMgb3IgblAyc2hQMndzaElucHV0cycpO1xuICB9XG4gIGlmICghXy5pc0ludGVnZXIocGFyYW1zLm5PdXRwdXRzKSB8fCBwYXJhbXMubk91dHB1dHMgPCAxKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdleHBlY3RpbmcgcG9zaXRpdmUgbk91dHB1dHMnKTtcbiAgfVxuXG4gIGNvbnN0IGVzdGltYXRlZFNpemUgPVxuICAgIFZpcnR1YWxTaXplcy50eFAyc2hJbnB1dFNpemUgKiBwYXJhbXMublAyc2hJbnB1dHMgK1xuICAgIFZpcnR1YWxTaXplcy50eFAyc2hQMndzaElucHV0U2l6ZSAqIChwYXJhbXMublAyc2hQMndzaElucHV0cyB8fCAwKSArXG4gICAgVmlydHVhbFNpemVzLnR4UDJwa2hJbnB1dFNpemVVbmNvbXByZXNzZWRLZXkgKiAocGFyYW1zLm5QMnBraElucHV0cyB8fCAwKSArXG4gICAgVmlydHVhbFNpemVzLnR4UDJwa2hPdXRwdXRTaXplICogcGFyYW1zLm5PdXRwdXRzICtcbiAgICAvLyBpZiB0aGUgdHggY29udGFpbnMgYXQgbGVhc3Qgb25lIHNlZ3dpdCBpbnB1dCwgdGhlIHR4IG92ZXJoZWFkIGlzIGluY3JlYXNlZCBieSAxXG4gICAgVmlydHVhbFNpemVzLnR4T3ZlcmhlYWRTaXplICtcbiAgICAocGFyYW1zLm5QMnNoUDJ3c2hJbnB1dHMgPiAwID8gMSA6IDApO1xuXG4gIHJldHVybiBlc3RpbWF0ZWRTaXplO1xufTtcblxuLyoqXG4gKiBDYWxjdWxhdGUgdGhlIGZlZSBhbmQgZXN0aW1hdGVkIHNpemUgaW4gYnl0ZXMgZm9yIGEgdHJhbnNhY3Rpb24uXG4gKiBAcGFyYW1zIHBhcmFtcyB7XG4gKiAgIGJpdGdvOiBiaXRnbyBvYmplY3RcbiAqICAgZmVlUmF0ZTogc2F0b3NoaXMgcGVyIGtpbG9ieXRlXG4gKiAgIG5QMnNoSW5wdXRzOiBudW1iZXIgb2YgUDJTSCAobXVsdGlzaWcpIGlucHV0c1xuICogICBuUDJwa2hJbnB1dHM6IG51bWJlciBvZiBQMlBLSCAoc2luZ2xlIHNpZykgaW5wdXRzXG4gKiAgIG5PdXRwdXRzOiBudW1iZXIgb2Ygb3V0cHV0c1xuICogfVxuICpcbiAqIEByZXR1cm5zIHtcbiAqICAgc2l6ZTogZXN0aW1hdGVkIHNpemUgb2YgdGhlIHRyYW5zYWN0aW9uIGluIGJ5dGVzXG4gKiAgIGZlZTogZXN0aW1hdGVkIGZlZSBpbiBzYXRvc2hpcyBmb3IgdGhlIHRyYW5zYWN0aW9uXG4gKiAgIGZlZVJhdGU6IGZlZSByYXRlIHRoYXQgd2FzIHVzZWQgdG8gZXN0aW1hdGUgdGhlIGZlZSBmb3IgdGhlIHRyYW5zYWN0aW9uXG4gKiB9XG4gKi9cbmV4cG9ydHMuY2FsY3VsYXRlTWluZXJGZWVJbmZvID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICBjb25zdCBmZWVSYXRlVG9Vc2UgPSBwYXJhbXMuZmVlUmF0ZSB8fCBwYXJhbXMuYml0Z28uZ2V0Q29uc3RhbnRzKCkuZmFsbGJhY2tGZWVSYXRlO1xuICBjb25zdCBlc3RpbWF0ZWRTaXplID0gZXN0aW1hdGVUcmFuc2FjdGlvblNpemUocGFyYW1zKTtcblxuICByZXR1cm4ge1xuICAgIHNpemU6IGVzdGltYXRlZFNpemUsXG4gICAgZmVlOiBNYXRoLmNlaWwoKGVzdGltYXRlZFNpemUgKiBmZWVSYXRlVG9Vc2UpIC8gMTAwMCksXG4gICAgZmVlUmF0ZTogZmVlUmF0ZVRvVXNlLFxuICB9O1xufTtcblxuLypcbiAqIEdpdmVuIGEgdHJhbnNhY3Rpb24gaGV4LCB1bnNwZW50IGluZm9ybWF0aW9uIChjaGFpbiBwYXRoIGFuZCByZWRlZW0gc2NyaXB0cyksIGFuZCB0aGUga2V5Y2hhaW4geHBydixcbiAqIHBlcmZvcm0ga2V5IGRlcml2YXRpb24gYW5kIHNpZ24gdGhlIGlucHV0cyBpbiB0aGUgdHJhbnNhY3Rpb24gYmFzZWQgb24gdGhlIHVuc3BlbnQgaW5mb3JtYXRpb24gcHJvdmlkZWRcbiAqXG4gKiBAcGFyYW1zOlxuICogIHRyYW5zYWN0aW9uSGV4IHNlcmlhbGl6ZWQgZm9ybSBvZiB0aGUgdHJhbnNhY3Rpb24gaW4gaGV4XG4gKiAgdW5zcGVudHMgYXJyYXkgb2YgdW5zcGVudCBpbmZvcm1hdGlvbiwgd2hlcmUgZWFjaCB1bnNwZW50IGlzIGEgY2hhaW5QYXRoIGFuZCByZWRlZW1TY3JpcHQgd2l0aCB0aGUgc2FtZVxuICogIGluZGV4IGFzIHRoZSBpbnB1dHMgaW4gdGhlIHRyYW5zYWN0aW9uSGV4XG4gKiAga2V5Y2hhaW4gS2V5Y2hhaW4gY29udGFpbmluZyB0aGUgeHBydiB0byBzaWduIHdpdGguIEZvciBsZWdhY3kgc3VwcG9ydCBvZiBzYWZlIHdhbGxldHMsIGtleWNoYWluIGNhblxuIGFsc28gYmUgYSBXSUYgcHJpdmF0ZSBrZXkuXG4gKiAgc2lnbmluZ0tleSBwcml2YXRlIGtleSBpbiBXSUYgZm9yIHNhZmUgd2FsbGV0cywgd2hlbiBrZXljaGFpbiBpcyB1bmF2YWlsYWJsZVxuICogIHZhbGlkYXRlIGNsaWVudC1zaWRlIHNpZ25hdHVyZSB2ZXJpZmljYXRpb24gLSBjYW4gYmUgZGlzYWJsZWQgZm9yIGltcHJvdmVkIHBlcmZvcm1hbmNlIChzaWduYXR1cmVzXG4gKiAgICAgICAgICAgYXJlIHN0aWxsIHZhbGlkYXRlZCBzZXJ2ZXItc2lkZSkuXG4gKiAgZmVlU2luZ2xlS2V5V0lGIFVzZSB0aGUgYWRkcmVzcyBiYXNlZCBvbiB0aGlzIHByaXZhdGUga2V5IHRvIHBheSBmZWVzXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuZXhwb3J0cy5zaWduVHJhbnNhY3Rpb24gPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gIGxldCBrZXljaGFpbiA9IHBhcmFtcy5rZXljaGFpbjsgLy8gZHVwbGljYXRlIHNvIGFzIHRvIG5vdCBtdXRhdGUgYmVsb3dcblxuICBjb25zdCB2YWxpZGF0ZSA9IHBhcmFtcy52YWxpZGF0ZSA9PT0gdW5kZWZpbmVkID8gdHJ1ZSA6IHBhcmFtcy52YWxpZGF0ZTtcbiAgbGV0IHByaXZLZXk7XG4gIGlmICghXy5pc1N0cmluZyhwYXJhbXMudHJhbnNhY3Rpb25IZXgpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdleHBlY3RpbmcgdGhlIHRyYW5zYWN0aW9uIGhleCBhcyBhIHN0cmluZycpO1xuICB9XG4gIGlmICghQXJyYXkuaXNBcnJheShwYXJhbXMudW5zcGVudHMpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdleHBlY3RpbmcgdGhlIHVuc3BlbnRzIGFycmF5Jyk7XG4gIH1cbiAgaWYgKCFfLmlzQm9vbGVhbih2YWxpZGF0ZSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cGVjdGluZyB2YWxpZGF0ZSB0byBiZSBhIGJvb2xlYW4nKTtcbiAgfVxuICBsZXQgbmV0d29yayA9IGdldE5ldHdvcmsoKTtcbiAgY29uc3QgZW5hYmxlQkNIID0gXy5pc0Jvb2xlYW4ocGFyYW1zLmZvcmNlQkNIKSAmJiBwYXJhbXMuZm9yY2VCQ0ggPT09IHRydWU7XG5cbiAgaWYgKCFfLmlzT2JqZWN0KGtleWNoYWluKSB8fCAhXy5pc1N0cmluZygoa2V5Y2hhaW4gYXMgYW55KS54cHJ2KSkge1xuICAgIGlmIChfLmlzU3RyaW5nKHBhcmFtcy5zaWduaW5nS2V5KSkge1xuICAgICAgcHJpdktleSA9IHV0eG9saWIuRUNQYWlyLmZyb21XSUYocGFyYW1zLnNpZ25pbmdLZXksIG5ldHdvcmsgYXMgdXR4b2xpYi5CaXRjb2luSlNOZXR3b3JrKTtcbiAgICAgIGtleWNoYWluID0gdW5kZWZpbmVkO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2V4cGVjdGluZyB0aGUga2V5Y2hhaW4gb2JqZWN0IHdpdGggeHBydicpO1xuICAgIH1cbiAgfVxuXG4gIGxldCBmZWVTaW5nbGVLZXk7XG4gIGlmIChwYXJhbXMuZmVlU2luZ2xlS2V5V0lGKSB7XG4gICAgZmVlU2luZ2xlS2V5ID0gdXR4b2xpYi5FQ1BhaXIuZnJvbVdJRihwYXJhbXMuZmVlU2luZ2xlS2V5V0lGLCBuZXR3b3JrIGFzIHV0eG9saWIuQml0Y29pbkpTTmV0d29yayk7XG4gIH1cblxuICBkZWJ1ZygnTmV0d29yazogJU8nLCBuZXR3b3JrKTtcblxuICBpZiAoZW5hYmxlQkNIKSB7XG4gICAgZGVidWcoJ0VuYWJsaW5nIEJDSOKApicpO1xuICAgIG5ldHdvcmsgPSB1dHhvbGliLm5ldHdvcmtzLmJpdGNvaW5jYXNoO1xuICAgIGRlYnVnKCdOZXcgbmV0d29yazogJU8nLCBuZXR3b3JrKTtcbiAgfVxuXG4gIGNvbnN0IHRyYW5zYWN0aW9uID0gdXR4b2xpYi5iaXRnby5jcmVhdGVUcmFuc2FjdGlvbkZyb21IZXgocGFyYW1zLnRyYW5zYWN0aW9uSGV4LCBuZXR3b3JrKTtcbiAgaWYgKHRyYW5zYWN0aW9uLmlucy5sZW5ndGggIT09IHBhcmFtcy51bnNwZW50cy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2xlbmd0aCBvZiB1bnNwZW50cyBhcnJheSBzaG91bGQgZXF1YWwgdG8gdGhlIG51bWJlciBvZiB0cmFuc2FjdGlvbiBpbnB1dHMnKTtcbiAgfVxuXG4gIC8vIGRlY29yYXRlIHRyYW5zYWN0aW9uIHdpdGggaW5wdXQgdmFsdWVzIGZvciBUcmFuc2FjdGlvbkJ1aWxkZXIgaW5zdGFudGlhdGlvblxuICBjb25zdCBpc1V0eG9UeCA9IF8uaXNPYmplY3QodHJhbnNhY3Rpb24pICYmIEFycmF5LmlzQXJyYXkoKHRyYW5zYWN0aW9uIGFzIGFueSkuaW5zKTtcbiAgY29uc3QgYXJlVmFsaWRVbnNwZW50cyA9IF8uaXNPYmplY3QocGFyYW1zKSAmJiBBcnJheS5pc0FycmF5KChwYXJhbXMgYXMgYW55KS51bnNwZW50cyk7XG4gIGlmIChpc1V0eG9UeCAmJiBhcmVWYWxpZFVuc3BlbnRzKSB7XG4gICAgLy8gZXh0ZW5kIHRoZSB0cmFuc2FjdGlvbiBpbnB1dHMgd2l0aCB0aGUgdmFsdWVzXG4gICAgY29uc3QgaW5wdXRWYWx1ZXMgPSBfLm1hcCgocGFyYW1zIGFzIGFueSkudW5zcGVudHMsICh1KSA9PiBfLnBpY2sodSwgJ3ZhbHVlJykpO1xuICAgIHRyYW5zYWN0aW9uLmlucy5tYXAoKGN1cnJlbnRJdGVtLCBpbmRleCkgPT4gXy5leHRlbmQoY3VycmVudEl0ZW0sIGlucHV0VmFsdWVzW2luZGV4XSkpO1xuICB9XG5cbiAgbGV0IHJvb3RFeHRLZXk7XG4gIGlmIChrZXljaGFpbikge1xuICAgIHJvb3RFeHRLZXkgPSBiaXAzMi5mcm9tQmFzZTU4KGtleWNoYWluLnhwcnYpO1xuICB9XG5cbiAgY29uc3QgdHhiID0gdXR4b2xpYi5iaXRnby5jcmVhdGVUcmFuc2FjdGlvbkJ1aWxkZXJGcm9tVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pO1xuXG4gIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCB0eGIudHguaW5zLmxlbmd0aDsgKytpbmRleCkge1xuICAgIGNvbnN0IGN1cnJlbnRVbnNwZW50ID0gcGFyYW1zLnVuc3BlbnRzW2luZGV4XTtcbiAgICBpZiAoY3VycmVudFVuc3BlbnQucmVkZWVtU2NyaXB0ID09PSBmYWxzZSkge1xuICAgICAgLy8gdGhpcyBpcyB0aGUgaW5wdXQgZnJvbSBhIHNpbmdsZSBrZXkgZmVlIGFkZHJlc3NcbiAgICAgIGlmICghZmVlU2luZ2xlS2V5KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignc2luZ2xlIGtleSBhZGRyZXNzIHVzZWQgaW4gaW5wdXQgYnV0IGZlZVNpbmdsZUtleVdJRiBub3QgcHJvdmlkZWQnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGVuYWJsZUJDSCkge1xuICAgICAgICBmZWVTaW5nbGVLZXkubmV0d29yayA9IG5ldHdvcms7XG4gICAgICB9XG5cbiAgICAgIHR4Yi5zaWduKGluZGV4LCBmZWVTaW5nbGVLZXkpO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgaWYgKGN1cnJlbnRVbnNwZW50LndpdG5lc3NTY3JpcHQgJiYgZW5hYmxlQkNIKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0JDSCBkb2VzIG5vdCBzdXBwb3J0IHNlZ3dpdCBpbnB1dHMnKTtcbiAgICB9XG5cbiAgICBjb25zdCBjaGFpblBhdGggPSBjdXJyZW50VW5zcGVudC5jaGFpblBhdGg7XG4gICAgaWYgKHJvb3RFeHRLZXkpIHtcbiAgICAgIGNvbnN0IHsgd2FsbGV0U3ViUGF0aCA9ICcvMC8wJyB9ID0ga2V5Y2hhaW47XG4gICAgICBjb25zdCBwYXRoID0gc2FuaXRpemVMZWdhY3lQYXRoKGtleWNoYWluLnBhdGggKyB3YWxsZXRTdWJQYXRoICsgY2hhaW5QYXRoKTtcbiAgICAgIGRlYnVnKFxuICAgICAgICAnZGVyaXZlZCB1c2VyIGtleSBwYXRoIFwiJXNcIiB1c2luZyBrZXljaGFpbiBwYXRoIFwiJXNcIiwgd2FsbGV0U3ViUGF0aCBcIiVzXCIsIGtleWNoYWluIHdhbGxldFN1YlBhdGggXCIlc1wiIGFuZCBjaGFpblBhdGggXCIlc1wiJyxcbiAgICAgICAgcGF0aCxcbiAgICAgICAga2V5Y2hhaW4ucGF0aCxcbiAgICAgICAgd2FsbGV0U3ViUGF0aCxcbiAgICAgICAga2V5Y2hhaW4ud2FsbGV0U3ViUGF0aCxcbiAgICAgICAgY2hhaW5QYXRoXG4gICAgICApO1xuICAgICAgcHJpdktleSA9IHJvb3RFeHRLZXkuZGVyaXZlUGF0aChwYXRoKTtcbiAgICB9XG5cbiAgICBwcml2S2V5Lm5ldHdvcmsgPSBuZXR3b3JrO1xuXG4gICAgLy8gc3Vic2NyaXB0IGlzIHRoZSBwYXJ0IG9mIHRoZSBvdXRwdXQgc2NyaXB0IGFmdGVyIHRoZSBPUF9DT0RFU0VQQVJBVE9SLlxuICAgIC8vIFNpbmNlIHdlIGFyZSBvbmx5IGV2ZXIgc2lnbmluZyBwMnNoIG91dHB1dHMsIHdoaWNoIGRvIG5vdCBoYXZlXG4gICAgLy8gT1BfQ09ERVNFUEFSQVRPUlMsIGl0IGlzIGFsd2F5cyB0aGUgb3V0cHV0IHNjcmlwdC5cbiAgICBjb25zdCBzdWJzY3JpcHQgPSBCdWZmZXIuZnJvbShjdXJyZW50VW5zcGVudC5yZWRlZW1TY3JpcHQsICdoZXgnKTtcbiAgICBjdXJyZW50VW5zcGVudC52YWxpZGF0aW9uU2NyaXB0ID0gc3Vic2NyaXB0O1xuXG4gICAgLy8gSW4gb3JkZXIgdG8gc2lnbiB3aXRoIGJpdGNvaW5qcy1saWIsIHdlIG11c3QgdXNlIGl0cyB0cmFuc2FjdGlvblxuICAgIC8vIGJ1aWxkZXIsIGNvbmZ1c2luZ2x5IG5hbWVkIHRoZSBzYW1lIGV4YWN0IHRoaW5nIGFzIG91ciB0cmFuc2FjdGlvblxuICAgIC8vIGJ1aWxkZXIsIGJ1dCB3aXRoIGluZXF1aXZhbGVudCBiZWhhdmlvci5cbiAgICB0cnkge1xuICAgICAgY29uc3Qgd2l0bmVzc1NjcmlwdCA9IGN1cnJlbnRVbnNwZW50LndpdG5lc3NTY3JpcHQgPyBCdWZmZXIuZnJvbShjdXJyZW50VW5zcGVudC53aXRuZXNzU2NyaXB0LCAnaGV4JykgOiB1bmRlZmluZWQ7XG4gICAgICBjb25zdCBzaWdIYXNoID0gdXR4b2xpYi5iaXRnby5nZXREZWZhdWx0U2lnSGFzaChuZXR3b3JrKTtcbiAgICAgIHR4Yi5zaWduKGluZGV4LCBwcml2S2V5LCBzdWJzY3JpcHQsIHNpZ0hhc2gsIGN1cnJlbnRVbnNwZW50LnZhbHVlLCB3aXRuZXNzU2NyaXB0KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyB0cnkgZmFsbGJhY2sgZGVyaXZhdGlvbiBwYXRoIChzZWUgQkctNDY0OTcpXG4gICAgICBsZXQgZmFsbGJhY2tTaWduaW5nU3VjY2Vzc2Z1bCA9IGZhbHNlO1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgZmFsbGJhY2tQYXRoID0gc2FuaXRpemVMZWdhY3lQYXRoKGtleWNoYWluLnBhdGggKyBjaGFpblBhdGgpO1xuICAgICAgICBkZWJ1ZyhcbiAgICAgICAgICAnZGVyaXZlZCBmYWxsYmFjayB1c2VyIGtleSBwYXRoIFwiJXNcIiB1c2luZyBrZXljaGFpbiBwYXRoIFwiJXNcIiBhbmQgY2hhaW5QYXRoIFwiJXNcIicsXG4gICAgICAgICAgZmFsbGJhY2tQYXRoLFxuICAgICAgICAgIGtleWNoYWluLnBhdGgsXG4gICAgICAgICAgY2hhaW5QYXRoXG4gICAgICAgICk7XG4gICAgICAgIHByaXZLZXkgPSByb290RXh0S2V5LmRlcml2ZVBhdGgoZmFsbGJhY2tQYXRoKTtcbiAgICAgICAgY29uc3Qgd2l0bmVzc1NjcmlwdCA9IGN1cnJlbnRVbnNwZW50LndpdG5lc3NTY3JpcHRcbiAgICAgICAgICA/IEJ1ZmZlci5mcm9tKGN1cnJlbnRVbnNwZW50LndpdG5lc3NTY3JpcHQsICdoZXgnKVxuICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgICBjb25zdCBzaWdIYXNoID0gdXR4b2xpYi5iaXRnby5nZXREZWZhdWx0U2lnSGFzaChuZXR3b3JrKTtcbiAgICAgICAgdHhiLnNpZ24oaW5kZXgsIHByaXZLZXksIHN1YnNjcmlwdCwgc2lnSGFzaCwgY3VycmVudFVuc3BlbnQudmFsdWUsIHdpdG5lc3NTY3JpcHQpO1xuICAgICAgICBmYWxsYmFja1NpZ25pbmdTdWNjZXNzZnVsID0gdHJ1ZTtcbiAgICAgIH0gY2F0Y2ggKGZhbGxiYWNrRXJyb3IpIHtcbiAgICAgICAgZGVidWcoJ2lucHV0IHNpZ24gZmFpbGVkIGZvciBmYWxsYmFjayBwYXRoOiAlcycsIGZhbGxiYWNrRXJyb3IubWVzc2FnZSk7XG4gICAgICB9XG4gICAgICAvLyB3ZSBuZWVkIHRvIGtub3cgd2hhdCdzIGNhdXNpbmcgdGhpc1xuICAgICAgaWYgKCFmYWxsYmFja1NpZ25pbmdTdWNjZXNzZnVsKSB7XG4gICAgICAgIGUucmVzdWx0ID0ge1xuICAgICAgICAgIHVuc3BlbnQ6IGN1cnJlbnRVbnNwZW50LFxuICAgICAgICB9O1xuICAgICAgICBlLm1lc3NhZ2UgPSBgRmFpbGVkIHRvIHNpZ24gaW5wdXQgIyR7aW5kZXh9IC0gJHtlLm1lc3NhZ2V9IC0gJHtKU09OLnN0cmluZ2lmeShlLnJlc3VsdCwgbnVsbCwgNCl9IC0gXFxuJHtcbiAgICAgICAgICBlLnN0YWNrXG4gICAgICAgIH1gO1xuICAgICAgICBkZWJ1ZygnaW5wdXQgc2lnbiBmYWlsZWQ6ICVzJywgZS5tZXNzYWdlKTtcbiAgICAgICAgcmV0dXJuIEJsdWViaXJkLnJlamVjdChlKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjb25zdCBwYXJ0aWFsVHJhbnNhY3Rpb24gPSB0eGIuYnVpbGRJbmNvbXBsZXRlKCk7XG5cbiAgaWYgKHZhbGlkYXRlKSB7XG4gICAgcGFydGlhbFRyYW5zYWN0aW9uLmlucy5mb3JFYWNoKChpbnB1dCwgaW5kZXgpID0+IHtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZUNvdW50ID0gdXR4b2xpYi5iaXRnb1xuICAgICAgICAuZ2V0U2lnbmF0dXJlVmVyaWZpY2F0aW9ucyhwYXJ0aWFsVHJhbnNhY3Rpb24sIGluZGV4LCBwYXJhbXMudW5zcGVudHNbaW5kZXhdLnZhbHVlKVxuICAgICAgICAuZmlsdGVyKCh2KSA9PiB2LnNpZ25lZEJ5ICE9PSB1bmRlZmluZWQpLmxlbmd0aDtcbiAgICAgIGlmIChzaWduYXR1cmVDb3VudCA8IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdleHBlY3RlZCBhdCBsZWFzdCBvbmUgdmFsaWQgc2lnbmF0dXJlJyk7XG4gICAgICB9XG4gICAgICBpZiAocGFyYW1zLmZ1bGxMb2NhbFNpZ25pbmcgJiYgc2lnbmF0dXJlQ291bnQgPCAyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignZnVsbExvY2FsU2lnbmluZyBzZXQ6IGV4cGVjdGVkIGF0IGxlYXN0IHR3byB2YWxpZCBzaWduYXR1cmVzJyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gQmx1ZWJpcmQucmVzb2x2ZSh7XG4gICAgdHJhbnNhY3Rpb25IZXg6IHBhcnRpYWxUcmFuc2FjdGlvbi50b0hleCgpLFxuICB9KTtcbn07XG4iXX0=