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