@bitgo-beta/abstract-cosmos 1.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.
- package/.eslintignore +5 -0
- package/.mocharc.yml +8 -0
- package/LICENSE +191 -0
- package/README.md +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +14 -0
- package/dist/src/lib/constants.d.ts +7 -0
- package/dist/src/lib/constants.d.ts.map +1 -0
- package/dist/src/lib/constants.js +10 -0
- package/dist/src/lib/iface.d.ts +46 -0
- package/dist/src/lib/iface.d.ts.map +1 -0
- package/dist/src/lib/iface.js +3 -0
- package/dist/src/lib/index.d.ts +8 -0
- package/dist/src/lib/index.d.ts.map +1 -0
- package/dist/src/lib/index.js +25 -0
- package/dist/src/lib/keyPair.d.ts +18 -0
- package/dist/src/lib/keyPair.d.ts.map +1 -0
- package/dist/src/lib/keyPair.js +52 -0
- package/dist/src/lib/transaction.d.ts +53 -0
- package/dist/src/lib/transaction.d.ts.map +1 -0
- package/dist/src/lib/transaction.js +254 -0
- package/dist/src/lib/transactionBuilder.d.ts +57 -0
- package/dist/src/lib/transactionBuilder.d.ts.map +1 -0
- package/dist/src/lib/transactionBuilder.js +87 -0
- package/dist/src/lib/utils.d.ts +144 -0
- package/dist/src/lib/utils.d.ts.map +1 -0
- package/dist/src/lib/utils.js +345 -0
- package/dist/tsconfig.tsbuildinfo +10779 -0
- package/package.json +54 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CosmosLikeUtils = void 0;
|
|
4
|
+
const sdk_core_1 = require("@bitgo-beta/sdk-core");
|
|
5
|
+
const amino_1 = require("@cosmjs/amino");
|
|
6
|
+
const encoding_1 = require("@cosmjs/encoding");
|
|
7
|
+
const proto_signing_1 = require("@cosmjs/proto-signing");
|
|
8
|
+
const stargate_1 = require("@cosmjs/stargate");
|
|
9
|
+
const bignumber_js_1 = require("bignumber.js");
|
|
10
|
+
const tx_1 = require("cosmjs-types/cosmos/tx/v1beta1/tx");
|
|
11
|
+
const constants = require("./constants");
|
|
12
|
+
const keyPair_1 = require("./keyPair");
|
|
13
|
+
class CosmosLikeUtils {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.registry = new proto_signing_1.Registry([...stargate_1.defaultRegistryTypes]);
|
|
16
|
+
}
|
|
17
|
+
/** @inheritdoc */
|
|
18
|
+
isValidBlockId(hash) {
|
|
19
|
+
return this.validateBlake2b(hash);
|
|
20
|
+
}
|
|
21
|
+
/** @inheritdoc */
|
|
22
|
+
isValidPrivateKey(key) {
|
|
23
|
+
try {
|
|
24
|
+
new keyPair_1.CosmosKeyPair({ prv: key });
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** @inheritdoc */
|
|
32
|
+
isValidPublicKey(key) {
|
|
33
|
+
try {
|
|
34
|
+
new keyPair_1.CosmosKeyPair({ pub: key });
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** @inheritdoc */
|
|
42
|
+
isValidSignature(signature) {
|
|
43
|
+
throw new sdk_core_1.NotImplementedError('isValidSignature not implemented');
|
|
44
|
+
}
|
|
45
|
+
/** @inheritdoc */
|
|
46
|
+
isValidTransactionId(txId) {
|
|
47
|
+
return this.validateBlake2b(txId);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Checks if transaction hash is in valid black2b format
|
|
51
|
+
*/
|
|
52
|
+
validateBlake2b(hash) {
|
|
53
|
+
if ((hash === null || hash === void 0 ? void 0 : hash.length) !== 64) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return hash.match(/^[a-zA-Z0-9]+$/) !== null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Validates whether amounts are in range
|
|
60
|
+
*
|
|
61
|
+
* @param {number[]} amounts - the amounts to validate
|
|
62
|
+
* @returns {boolean} - the validation result
|
|
63
|
+
*/
|
|
64
|
+
isValidAmounts(amounts) {
|
|
65
|
+
for (const amount of amounts) {
|
|
66
|
+
if (!this.isValidAmount(amount)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Validates whether amount is in range
|
|
74
|
+
* @param {number} amount
|
|
75
|
+
* @returns {boolean} the validation result
|
|
76
|
+
*/
|
|
77
|
+
isValidAmount(amount) {
|
|
78
|
+
const bigNumberAmount = new bignumber_js_1.default(amount);
|
|
79
|
+
if (!bigNumberAmount.isInteger() || bigNumberAmount.isLessThanOrEqualTo(0)) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Decodes raw tx data into messages, signing info, and fee data
|
|
86
|
+
* @param {string} txHex - raw base64 tx
|
|
87
|
+
* @returns {DecodedTxRaw} Decoded transaction
|
|
88
|
+
*/
|
|
89
|
+
getDecodedTxFromRawBase64(txRaw) {
|
|
90
|
+
try {
|
|
91
|
+
return proto_signing_1.decodeTxRaw(encoding_1.fromBase64(txRaw));
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
throw new sdk_core_1.ParseTransactionError('Error decoding TxRaw base64 encoded string: ' + e.message);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Returns the array of messages in the body of the decoded transaction
|
|
99
|
+
* @param {DecodedTxRaw} decodedTx
|
|
100
|
+
* @returns {EncodeObject[]} messages along with type url
|
|
101
|
+
*/
|
|
102
|
+
getEncodedMessagesFromDecodedTx(decodedTx) {
|
|
103
|
+
return decodedTx.body.messages;
|
|
104
|
+
}
|
|
105
|
+
validateSequence(sequence) {
|
|
106
|
+
if (sequence < 0) {
|
|
107
|
+
throw new sdk_core_1.InvalidTransactionError('Invalid sequence: less than zero');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Pulls the sequence number from a DecodedTxRaw AuthInfo property
|
|
112
|
+
* @param {DecodedTxRaw} decodedTx
|
|
113
|
+
* @returns {number} sequence
|
|
114
|
+
*/
|
|
115
|
+
getSequenceFromDecodedTx(decodedTx) {
|
|
116
|
+
return Number(decodedTx.authInfo.signerInfos[0].sequence);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Pulls the typeUrl from the encoded message of a DecodedTxRaw
|
|
120
|
+
* @param {DecodedTxRaw} decodedTx
|
|
121
|
+
* @returns {string} osmosis proto type url
|
|
122
|
+
*/
|
|
123
|
+
getTypeUrlFromDecodedTx(decodedTx) {
|
|
124
|
+
const encodedMessage = this.getEncodedMessagesFromDecodedTx(decodedTx)[0];
|
|
125
|
+
return encodedMessage.typeUrl;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Returns the fee data from the decoded transaction
|
|
129
|
+
* @param {DecodedTxRaw} decodedTx
|
|
130
|
+
* @returns {FeeData} fee data
|
|
131
|
+
*/
|
|
132
|
+
getGasBudgetFromDecodedTx(decodedTx) {
|
|
133
|
+
var _a, _b;
|
|
134
|
+
return {
|
|
135
|
+
amount: (_a = decodedTx.authInfo.fee) === null || _a === void 0 ? void 0 : _a.amount,
|
|
136
|
+
gasLimit: Number((_b = decodedTx.authInfo.fee) === null || _b === void 0 ? void 0 : _b.gasLimit),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Returns the publicKey from the decoded transaction
|
|
141
|
+
* @param {DecodedTxRaw} decodedTx
|
|
142
|
+
* @returns {string | undefined} publicKey in hex format if it exists, undefined otherwise
|
|
143
|
+
*/
|
|
144
|
+
getPublicKeyFromDecodedTx(decodedTx) {
|
|
145
|
+
var _a, _b, _c, _d;
|
|
146
|
+
const publicKeyUInt8Array = (_b = (_a = decodedTx.authInfo.signerInfos) === null || _a === void 0 ? void 0 : _a[0].publicKey) === null || _b === void 0 ? void 0 : _b.value;
|
|
147
|
+
if (publicKeyUInt8Array) {
|
|
148
|
+
return encoding_1.toHex(encoding_1.fromBase64((_d = proto_signing_1.decodePubkey((_c = decodedTx.authInfo.signerInfos) === null || _c === void 0 ? void 0 : _c[0].publicKey)) === null || _d === void 0 ? void 0 : _d.value));
|
|
149
|
+
}
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Returns the array of MessageData[] from the decoded transaction
|
|
154
|
+
* @param {DecodedTxRaw} decodedTx
|
|
155
|
+
* @returns {MessageData[]} Send transaction message data
|
|
156
|
+
*/
|
|
157
|
+
getSendMessageDataFromDecodedTx(decodedTx) {
|
|
158
|
+
return decodedTx.body.messages.map((message) => {
|
|
159
|
+
const value = this.registry.decode(message);
|
|
160
|
+
return {
|
|
161
|
+
value: {
|
|
162
|
+
fromAddress: value.fromAddress,
|
|
163
|
+
toAddress: value.toAddress,
|
|
164
|
+
amount: value.amount,
|
|
165
|
+
},
|
|
166
|
+
typeUrl: message.typeUrl,
|
|
167
|
+
};
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Returns the array of MessageData[] from the decoded transaction
|
|
172
|
+
* @param {DecodedTxRaw} decodedTx
|
|
173
|
+
* @returns {MessageData[]} Delegate of undelegate transaction message data
|
|
174
|
+
*/
|
|
175
|
+
getDelegateOrUndelegateMessageDataFromDecodedTx(decodedTx) {
|
|
176
|
+
return decodedTx.body.messages.map((message) => {
|
|
177
|
+
const value = this.registry.decode(message);
|
|
178
|
+
return {
|
|
179
|
+
value: {
|
|
180
|
+
delegatorAddress: value.delegatorAddress,
|
|
181
|
+
validatorAddress: value.validatorAddress,
|
|
182
|
+
amount: value.amount,
|
|
183
|
+
},
|
|
184
|
+
typeUrl: message.typeUrl,
|
|
185
|
+
};
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Returns the array of MessageData[] from the decoded transaction
|
|
190
|
+
* @param {DecodedTxRaw} decodedTx
|
|
191
|
+
* @returns {MessageData[]} WithdrawDelegatorRewards transaction message data
|
|
192
|
+
*/
|
|
193
|
+
getWithdrawRewardsMessageDataFromDecodedTx(decodedTx) {
|
|
194
|
+
return decodedTx.body.messages.map((message) => {
|
|
195
|
+
const value = this.registry.decode(message);
|
|
196
|
+
return {
|
|
197
|
+
value: {
|
|
198
|
+
delegatorAddress: value.delegatorAddress,
|
|
199
|
+
validatorAddress: value.validatorAddress,
|
|
200
|
+
},
|
|
201
|
+
typeUrl: message.typeUrl,
|
|
202
|
+
};
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Returns the array of MessageData[] from the decoded transaction
|
|
207
|
+
* @param {DecodedTxRaw} decodedTx
|
|
208
|
+
* @returns {MessageData[]} Delegate of undelegate transaction message data
|
|
209
|
+
*/
|
|
210
|
+
getWithdrawDelegatorRewardsMessageDataFromDecodedTx(decodedTx) {
|
|
211
|
+
return decodedTx.body.messages.map((message) => {
|
|
212
|
+
const value = this.registry.decode(message);
|
|
213
|
+
return {
|
|
214
|
+
value: {
|
|
215
|
+
delegatorAddress: value.delegatorAddress,
|
|
216
|
+
validatorAddress: value.validatorAddress,
|
|
217
|
+
},
|
|
218
|
+
typeUrl: message.typeUrl,
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Determines bitgo transaction type based on osmosis proto type url
|
|
224
|
+
* @param {string} typeUrl
|
|
225
|
+
* @returns {TransactionType | undefined} TransactionType if url is supported else undefined
|
|
226
|
+
*/
|
|
227
|
+
getTransactionTypeFromTypeUrl(typeUrl) {
|
|
228
|
+
switch (typeUrl) {
|
|
229
|
+
case constants.sendMsgTypeUrl:
|
|
230
|
+
return sdk_core_1.TransactionType.Send;
|
|
231
|
+
case constants.delegateMsgTypeUrl:
|
|
232
|
+
return sdk_core_1.TransactionType.StakingActivate;
|
|
233
|
+
case constants.undelegateMsgTypeUrl:
|
|
234
|
+
return sdk_core_1.TransactionType.StakingDeactivate;
|
|
235
|
+
case constants.withdrawDelegatorRewardMsgTypeUrl:
|
|
236
|
+
return sdk_core_1.TransactionType.StakingWithdraw;
|
|
237
|
+
default:
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Creates a txRaw from an cosmos like transaction @see CosmosLikeTransaction
|
|
243
|
+
* @Precondition cosmosLikeTransaction.publicKey must be defined
|
|
244
|
+
* @param {CosmosLikeTransaction} cosmosLikeTransaction
|
|
245
|
+
* @returns {TxRaw} Unsigned raw transaction
|
|
246
|
+
*/
|
|
247
|
+
createTxRawFromCosmosLikeTransaction(cosmosLikeTransaction) {
|
|
248
|
+
if (!cosmosLikeTransaction.publicKey) {
|
|
249
|
+
throw new Error('publicKey is required to create a txRaw');
|
|
250
|
+
}
|
|
251
|
+
const encodedPublicKey = proto_signing_1.encodePubkey(amino_1.encodeSecp256k1Pubkey(encoding_1.fromHex(cosmosLikeTransaction.publicKey)));
|
|
252
|
+
const messages = cosmosLikeTransaction.sendMessages;
|
|
253
|
+
let txBodyValue;
|
|
254
|
+
if (cosmosLikeTransaction.memo) {
|
|
255
|
+
txBodyValue = {
|
|
256
|
+
memo: cosmosLikeTransaction.memo,
|
|
257
|
+
messages: messages,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
txBodyValue = {
|
|
262
|
+
messages: messages,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const txBodyBytes = this.registry.encodeTxBody(txBodyValue);
|
|
266
|
+
const sequence = cosmosLikeTransaction.sequence;
|
|
267
|
+
const authInfoBytes = proto_signing_1.makeAuthInfoBytes([{ pubkey: encodedPublicKey, sequence }], cosmosLikeTransaction.gasBudget.amount, cosmosLikeTransaction.gasBudget.gasLimit, undefined, undefined, undefined);
|
|
268
|
+
return tx_1.TxRaw.fromPartial({
|
|
269
|
+
bodyBytes: txBodyBytes,
|
|
270
|
+
authInfoBytes: authInfoBytes,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Encodes a signature into a txRaw
|
|
275
|
+
* @param {string} publicKeyHex publicKey in hex encoded string format
|
|
276
|
+
* @param {string} signatureHex signature in hex encoded string format
|
|
277
|
+
* @param {TxRaw} unsignedTx raw transaction
|
|
278
|
+
* @returns {TxRaw} Signed raw transaction
|
|
279
|
+
*/
|
|
280
|
+
createSignedTxRaw(publicKeyHex, signatureHex, unsignedTx) {
|
|
281
|
+
const stdSignature = amino_1.encodeSecp256k1Signature(encoding_1.fromHex(publicKeyHex), encoding_1.fromHex(signatureHex));
|
|
282
|
+
return tx_1.TxRaw.fromPartial({
|
|
283
|
+
bodyBytes: unsignedTx.bodyBytes,
|
|
284
|
+
authInfoBytes: unsignedTx.authInfoBytes,
|
|
285
|
+
signatures: [encoding_1.fromBase64(stdSignature.signature)],
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Decodes a raw transaction into a DecodedTxRaw and checks if it has non empty signatures
|
|
290
|
+
* @param {string} rawTransaction
|
|
291
|
+
* @returns {boolean} true if transaction is signed else false
|
|
292
|
+
*/
|
|
293
|
+
isSignedRawTx(rawTransaction) {
|
|
294
|
+
const decodedTx = this.getDecodedTxFromRawBase64(rawTransaction);
|
|
295
|
+
if (decodedTx.signatures.length > 0) {
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
validatePublicKey(publicKey) {
|
|
301
|
+
if (publicKey !== undefined) {
|
|
302
|
+
try {
|
|
303
|
+
new keyPair_1.CosmosKeyPair({ pub: publicKey });
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
throw new sdk_core_1.InvalidTransactionError(`Key validation failed`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Validates if the address matches with regex @see accountAddressRegex
|
|
312
|
+
*
|
|
313
|
+
* @param {string} address
|
|
314
|
+
* @returns {boolean} - the validation result
|
|
315
|
+
*/
|
|
316
|
+
isValidAddress(address) {
|
|
317
|
+
throw new sdk_core_1.NotImplementedError('isValidAddress not implemented');
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Creates a sign doc from an cosmos like transaction @see CosmosLikeTransaction
|
|
321
|
+
* @Precondition cosmosLikeTransaction.accountNumber and cosmosLikeTransaction.chainId must be defined
|
|
322
|
+
* @param {CosmosLikeTransaction} cosmosLikeTransaction
|
|
323
|
+
* @returns {SignDoc} sign doc
|
|
324
|
+
*/
|
|
325
|
+
createSignDoc(cosmosLikeTransaction, accountNumber, chainId) {
|
|
326
|
+
if (!accountNumber) {
|
|
327
|
+
throw new Error('accountNumber is required to create a sign doc');
|
|
328
|
+
}
|
|
329
|
+
if (!chainId) {
|
|
330
|
+
throw new Error('chainId is required to create a sign doc');
|
|
331
|
+
}
|
|
332
|
+
if (!cosmosLikeTransaction) {
|
|
333
|
+
throw new Error('cosmosLikeTransaction is required to create a sign doc');
|
|
334
|
+
}
|
|
335
|
+
const txRaw = utils.createTxRawFromCosmosLikeTransaction(cosmosLikeTransaction);
|
|
336
|
+
return proto_signing_1.makeSignDoc(txRaw.bodyBytes, txRaw.authInfoBytes, chainId, accountNumber);
|
|
337
|
+
}
|
|
338
|
+
isValidHexString(hexString) {
|
|
339
|
+
return /^[0-9A-Fa-f]*$/.test(hexString);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
exports.CosmosLikeUtils = CosmosLikeUtils;
|
|
343
|
+
const utils = new CosmosLikeUtils();
|
|
344
|
+
exports.default = utils;
|
|
345
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG1EQU04QjtBQUM5Qix5Q0FBZ0Y7QUFDaEYsK0NBQThEO0FBQzlELHlEQVMrQjtBQUMvQiwrQ0FBOEQ7QUFDOUQsK0NBQXFDO0FBQ3JDLDBEQUFtRTtBQUduRSx5Q0FBeUM7QUFFekMsdUNBQXFEO0FBRXJELE1BQWEsZUFBZTtJQUE1QjtRQUNVLGFBQVEsR0FBRyxJQUFJLHdCQUFRLENBQUMsQ0FBQyxHQUFHLCtCQUFvQixDQUFDLENBQUMsQ0FBQztJQXlXN0QsQ0FBQztJQXZXQyxrQkFBa0I7SUFDbEIsY0FBYyxDQUFDLElBQVk7UUFDekIsT0FBTyxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFFRCxrQkFBa0I7SUFDbEIsaUJBQWlCLENBQUMsR0FBVztRQUMzQixJQUFJO1lBQ0YsSUFBSSx1QkFBTyxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7WUFDMUIsT0FBTyxJQUFJLENBQUM7U0FDYjtRQUFDLE1BQU07WUFDTixPQUFPLEtBQUssQ0FBQztTQUNkO0lBQ0gsQ0FBQztJQUVELGtCQUFrQjtJQUNsQixnQkFBZ0IsQ0FBQyxHQUFXO1FBQzFCLElBQUk7WUFDRixJQUFJLHVCQUFPLENBQUMsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztZQUMxQixPQUFPLElBQUksQ0FBQztTQUNiO1FBQUMsTUFBTTtZQUNOLE9BQU8sS0FBSyxDQUFDO1NBQ2Q7SUFDSCxDQUFDO0lBRUQsa0JBQWtCO0lBQ2xCLGdCQUFnQixDQUFDLFNBQWlCO1FBQ2hDLE1BQU0sSUFBSSw4QkFBbUIsQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO0lBQ3BFLENBQUM7SUFFRCxrQkFBa0I7SUFDbEIsb0JBQW9CLENBQUMsSUFBWTtRQUMvQixPQUFP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QWEsRUFBRTtZQUNsQixNQUFNLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7U0FDbkU7UUFDRCxJQUFJLENBQUMsT0FBTyxFQUFFO1lBQ1osTUFBTSxJQUFJLEtBQUssQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO1NBQzdEO1FBQ0QsSUFBSSxDQUFDLHFCQUFxQixFQUFFO1lBQzFCLE1BQU0sSUFBSSxLQUFLLENBQUMsd0RBQXdELENBQUMsQ0FBQztTQUMzRTtRQUNELE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxvQ0FBb0MsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1FBQ2hGLE9BQU8sMkJBQVcsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxhQUFhLEVBQUUsT0FBTyxFQUFFLGFBQWEsQ0FBQyxDQUFDO0lBQ25GLENBQUM7SUFFRCxnQkFBZ0IsQ0FBQyxTQUFpQjtRQUNoQyxPQUFPLGdCQUFnQixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUMxQyxDQUFDO0NBQ0Y7QUExV0QsMENBMFdDO0FBRUQsTUFBTSxLQUFLLEdBQUcsSUFBSSxlQUFlLEVBQUUsQ0FBQztBQUVwQyxrQkFBZSxLQUFLLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBCYXNlVXRpbHMsXG4gIEludmFsaWRUcmFuc2FjdGlvbkVycm9yLFxuICBOb3RJbXBsZW1lbnRlZEVycm9yLFxuICBQYXJzZVRyYW5zYWN0aW9uRXJyb3IsXG4gIFRyYW5zYWN0aW9uVHlwZSxcbn0gZnJvbSAnQGJpdGdvLWJldGEvc2RrLWNvcmUnO1xuaW1wb3J0IHsgZW5jb2RlU2VjcDI1NmsxUHVia2V5LCBlbmNvZGVTZWNwMjU2azFTaWduYXR1cmUgfSBmcm9tICdAY29zbWpzL2FtaW5vJztcbmltcG9ydCB7IGZyb21CYXNlNjQsIGZyb21IZXgsIHRvSGV4IH0gZnJvbSAnQGNvc21qcy9lbmNvZGluZyc7XG5pbXBvcnQge1xuICBEZWNvZGVkVHhSYXcsXG4gIGRlY29kZVB1YmtleSxcbiAgZGVjb2RlVHhSYXcsXG4gIEVuY29kZU9iamVjdCxcbiAgZW5jb2RlUHVia2V5LFxuICBtYWtlQXV0aEluZm9CeXRlcyxcbiAgbWFrZVNpZ25Eb2MsXG4gIFJlZ2lzdHJ5LFxufSBmcm9tICdAY29zbWpzL3Byb3RvLXNpZ25pbmcnO1xuaW1wb3J0IHsgQ29pbiwgZGVmYXVsdFJlZ2lzdHJ5VHlwZXMgfSBmcm9tICdAY29zbWpzL3N0YXJnYXRlJztcbmltcG9ydCBCaWdOdW1iZXIgZnJvbSAnYmlnbnVtYmVyLmpzJztcbmltcG9ydCB7IFNpZ25Eb2MsIFR4UmF3IH0gZnJvbSAnY29zbWpzLXR5cGVzL2Nvc21vcy90eC92MWJldGExL3R4JztcbmltcG9ydCB7IEFueSB9IGZyb20gJ2Nvc21qcy10eXBlcy9nb29nbGUvcHJvdG9idWYvYW55JztcblxuaW1wb3J0ICogYXMgY29uc3RhbnRzIGZyb20gJy4vY29uc3RhbnRzJztcbmltcG9ydCB7IENvc21vc0xpa2VUcmFuc2FjdGlvbiwgRmVlRGF0YSwgTWVzc2FnZURhdGEgfSBmcm9tICcuL2lmYWNlJztcbmltcG9ydCB7IENvc21vc0tleVBhaXIgYXMgS2V5UGFpciB9IGZyb20gJy4va2V5UGFpcic7XG5cbmV4cG9ydCBjbGFzcyBDb3Ntb3NMaWtlVXRpbHMgaW1wbGVtZW50cyBCYXNlVXRpbHMge1xuICBwcml2YXRlIHJlZ2lzdHJ5ID0gbmV3IFJlZ2lzdHJ5KFsuLi5kZWZhdWx0UmVnaXN0cnlUeXBlc10pO1xuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBpc1ZhbGlkQmxvY2tJZChoYXNoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy52YWxpZGF0ZUJsYWtlMmIoaGFzaCk7XG4gIH1cblxuICAvKiogQGluaGVyaXRkb2MgKi9cbiAgaXNWYWxpZFByaXZhdGVLZXkoa2V5OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgbmV3IEtleVBhaXIoeyBwcnY6IGtleSB9KTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBAaW5oZXJpdGRvYyAqL1xuICBpc1ZhbGlkUHVibGljS2V5KGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgdHJ5IHtcbiAgICAgIG5ldyBLZXlQYWlyKHsgcHViOiBrZXkgfSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKiogQGluaGVyaXRkb2MgKi9cbiAgaXNWYWxpZFNpZ25hdHVyZShzaWduYXR1cmU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRocm93IG5ldyBOb3RJbXBsZW1lbnRlZEVycm9yKCdpc1ZhbGlkU2lnbmF0dXJlIG5vdCBpbXBsZW1lbnRlZCcpO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0ZG9jICovXG4gIGlzVmFsaWRUcmFuc2FjdGlvbklkKHR4SWQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnZhbGlkYXRlQmxha2UyYih0eElkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgdHJhbnNhY3Rpb24gaGFzaCBpcyBpbiB2YWxpZCBibGFjazJiIGZvcm1hdFxuICAgKi9cbiAgdmFsaWRhdGVCbGFrZTJiKGhhc2g6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGlmIChoYXNoPy5sZW5ndGggIT09IDY0KSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiBoYXNoLm1hdGNoKC9eW2EtekEtWjAtOV0rJC8pICE9PSBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyB3aGV0aGVyIGFtb3VudHMgYXJlIGluIHJhbmdlXG4gICAqXG4gICAqIEBwYXJhbSB7bnVtYmVyW119IGFtb3VudHMgLSB0aGUgYW1vdW50cyB0byB2YWxpZGF0ZVxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSB0aGUgdmFsaWRhdGlvbiByZXN1bHRcbiAgICovXG4gIGlzVmFsaWRBbW91bnRzKGFtb3VudHM6IG51bWJlcltdKTogYm9vbGVhbiB7XG4gICAgZm9yIChjb25zdCBhbW91bnQgb2YgYW1vdW50cykge1xuICAgICAgaWYgKCF0aGlzLmlzVmFsaWRBbW91bnQoYW1vdW50KSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyB3aGV0aGVyIGFtb3VudCBpcyBpbiByYW5nZVxuICAgKiBAcGFyYW0ge251bWJlcn0gYW1vdW50XG4gICAqIEByZXR1cm5zIHtib29sZWFufSB0aGUgdmFsaWRhdGlvbiByZXN1bHRcbiAgICovXG4gIGlzVmFsaWRBbW91bnQoYW1vdW50OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICBjb25zdCBiaWdOdW1iZXJBbW91bnQgPSBuZXcgQmlnTnVtYmVyKGFtb3VudCk7XG4gICAgaWYgKCFiaWdOdW1iZXJBbW91bnQuaXNJbnRlZ2VyKCkgfHwgYmlnTnVtYmVyQW1vdW50LmlzTGVzc1RoYW5PckVxdWFsVG8oMCkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogRGVjb2RlcyByYXcgdHggZGF0YSBpbnRvIG1lc3NhZ2VzLCBzaWduaW5nIGluZm8sIGFuZCBmZWUgZGF0YVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHhIZXggLSByYXcgYmFzZTY0IHR4XG4gICAqIEByZXR1cm5zIHtEZWNvZGVkVHhSYXd9IERlY29kZWQgdHJhbnNhY3Rpb25cbiAgICovXG4gIGdldERlY29kZWRUeEZyb21SYXdCYXNlNjQodHhSYXc6IHN0cmluZyk6IERlY29kZWRUeFJhdyB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBkZWNvZGVUeFJhdyhmcm9tQmFzZTY0KHR4UmF3KSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhyb3cgbmV3IFBhcnNlVHJhbnNhY3Rpb25FcnJvcignRXJyb3IgZGVjb2RpbmcgVHhSYXcgYmFzZTY0IGVuY29kZWQgc3RyaW5nOiAnICsgZS5tZXNzYWdlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgYXJyYXkgb2YgbWVzc2FnZXMgaW4gdGhlIGJvZHkgb2YgdGhlIGRlY29kZWQgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtEZWNvZGVkVHhSYXd9IGRlY29kZWRUeFxuICAgKiBAcmV0dXJucyB7RW5jb2RlT2JqZWN0W119IG1lc3NhZ2VzIGFsb25nIHdpdGggdHlwZSB1cmxcbiAgICovXG4gIHByaXZhdGUgZ2V0RW5jb2RlZE1lc3NhZ2VzRnJvbURlY29kZWRUeChkZWNvZGVkVHg6IERlY29kZWRUeFJhdyk6IEVuY29kZU9iamVjdFtdIHtcbiAgICByZXR1cm4gZGVjb2RlZFR4LmJvZHkubWVzc2FnZXM7XG4gIH1cblxuICB2YWxpZGF0ZVNlcXVlbmNlKHNlcXVlbmNlOiBudW1iZXIpIHtcbiAgICBpZiAoc2VxdWVuY2UgPCAwKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZFRyYW5zYWN0aW9uRXJyb3IoJ0ludmFsaWQgc2VxdWVuY2U6IGxlc3MgdGhhbiB6ZXJvJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFB1bGxzIHRoZSBzZXF1ZW5jZSBudW1iZXIgZnJvbSBhIERlY29kZWRUeFJhdyBBdXRoSW5mbyBwcm9wZXJ0eVxuICAgKiBAcGFyYW0ge0RlY29kZWRUeFJhd30gZGVjb2RlZFR4XG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IHNlcXVlbmNlXG4gICAqL1xuICBnZXRTZXF1ZW5jZUZyb21EZWNvZGVkVHgoZGVjb2RlZFR4OiBEZWNvZGVkVHhSYXcpOiBudW1iZXIge1xuICAgIHJldHVybiBOdW1iZXIoZGVjb2RlZFR4LmF1dGhJbmZvLnNpZ25lckluZm9zWzBdLnNlcXVlbmNlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQdWxscyB0aGUgdHlwZVVybCBmcm9tIHRoZSBlbmNvZGVkIG1lc3NhZ2Ugb2YgYSBEZWNvZGVkVHhSYXdcbiAgICogQHBhcmFtIHtEZWNvZGVkVHhSYXd9IGRlY29kZWRUeFxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBvc21vc2lzIHByb3RvIHR5cGUgdXJsXG4gICAqL1xuICBnZXRUeXBlVXJsRnJvbURlY29kZWRUeChkZWNvZGVkVHg6IERlY29kZWRUeFJhdyk6IHN0cmluZyB7XG4gICAgY29uc3QgZW5jb2RlZE1lc3NhZ2UgPSB0aGlzLmdldEVuY29kZWRNZXNzYWdlc0Zyb21EZWNvZGVkVHgoZGVjb2RlZFR4KVswXTtcbiAgICByZXR1cm4gZW5jb2RlZE1lc3NhZ2UudHlwZVVybDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBmZWUgZGF0YSBmcm9tIHRoZSBkZWNvZGVkIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7RGVjb2RlZFR4UmF3fSBkZWNvZGVkVHhcbiAgICogQHJldHVybnMge0ZlZURhdGF9IGZlZSBkYXRhXG4gICAqL1xuICBnZXRHYXNCdWRnZXRGcm9tRGVjb2RlZFR4KGRlY29kZWRUeDogRGVjb2RlZFR4UmF3KTogRmVlRGF0YSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGFtb3VudDogZGVjb2RlZFR4LmF1dGhJbmZvLmZlZT8uYW1vdW50IGFzIENvaW5bXSxcbiAgICAgIGdhc0xpbWl0OiBOdW1iZXIoZGVjb2RlZFR4LmF1dGhJbmZvLmZlZT8uZ2FzTGltaXQpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgcHVibGljS2V5IGZyb20gdGhlIGRlY29kZWQgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtEZWNvZGVkVHhSYXd9IGRlY29kZWRUeFxuICAgKiBAcmV0dXJucyB7c3RyaW5nIHwgdW5kZWZpbmVkfSBwdWJsaWNLZXkgaW4gaGV4IGZvcm1hdCBpZiBpdCBleGlzdHMsIHVuZGVmaW5lZCBvdGhlcndpc2VcbiAgICovXG4gIGdldFB1YmxpY0tleUZyb21EZWNvZGVkVHgoZGVjb2RlZFR4OiBEZWNvZGVkVHhSYXcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHB1YmxpY0tleVVJbnQ4QXJyYXkgPSBkZWNvZGVkVHguYXV0aEluZm8uc2lnbmVySW5mb3M/LlswXS5wdWJsaWNLZXk/LnZhbHVlO1xuICAgIGlmIChwdWJsaWNLZXlVSW50OEFycmF5KSB7XG4gICAgICByZXR1cm4gdG9IZXgoZnJvbUJhc2U2NChkZWNvZGVQdWJrZXkoZGVjb2RlZFR4LmF1dGhJbmZvLnNpZ25lckluZm9zPy5bMF0ucHVibGljS2V5KT8udmFsdWUpKTtcbiAgICB9XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBhcnJheSBvZiBNZXNzYWdlRGF0YVtdIGZyb20gdGhlIGRlY29kZWQgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtEZWNvZGVkVHhSYXd9IGRlY29kZWRUeFxuICAgKiBAcmV0dXJucyB7TWVzc2FnZURhdGFbXX0gU2VuZCB0cmFuc2FjdGlvbiBtZXNzYWdlIGRhdGFcbiAgICovXG4gIHByb3RlY3RlZCBnZXRTZW5kTWVzc2FnZURhdGFGcm9tRGVjb2RlZFR4KGRlY29kZWRUeDogRGVjb2RlZFR4UmF3KTogTWVzc2FnZURhdGFbXSB7XG4gICAgcmV0dXJuIGRlY29kZWRUeC5ib2R5Lm1lc3NhZ2VzLm1hcCgobWVzc2FnZSkgPT4ge1xuICAgICAgY29uc3QgdmFsdWUgPSB0aGlzLnJlZ2lzdHJ5LmRlY29kZShtZXNzYWdlKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHZhbHVlOiB7XG4gICAgICAgICAgZnJvbUFkZHJlc3M6IHZhbHVlLmZyb21BZGRyZXNzLFxuICAgICAgICAgIHRvQWRkcmVzczogdmFsdWUudG9BZGRyZXNzLFxuICAgICAgICAgIGFtb3VudDogdmFsdWUuYW1vdW50LFxuICAgICAgICB9LFxuICAgICAgICB0eXBlVXJsOiBtZXNzYWdlLnR5cGVVcmwsXG4gICAgICB9O1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGFycmF5IG9mIE1lc3NhZ2VEYXRhW10gZnJvbSB0aGUgZGVjb2RlZCB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge0RlY29kZWRUeFJhd30gZGVjb2RlZFR4XG4gICAqIEByZXR1cm5zIHtNZXNzYWdlRGF0YVtdfSBEZWxlZ2F0ZSBvZiB1bmRlbGVnYXRlIHRyYW5zYWN0aW9uIG1lc3NhZ2UgZGF0YVxuICAgKi9cbiAgZ2V0RGVsZWdhdGVPclVuZGVsZWdhdGVNZXNzYWdlRGF0YUZyb21EZWNvZGVkVHgoZGVjb2RlZFR4OiBEZWNvZGVkVHhSYXcpOiBNZXNzYWdlRGF0YVtdIHtcbiAgICByZXR1cm4gZGVjb2RlZFR4LmJvZHkubWVzc2FnZXMubWFwKChtZXNzYWdlKSA9PiB7XG4gICAgICBjb25zdCB2YWx1ZSA9IHRoaXMucmVnaXN0cnkuZGVjb2RlKG1lc3NhZ2UpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsdWU6IHtcbiAgICAgICAgICBkZWxlZ2F0b3JBZGRyZXNzOiB2YWx1ZS5kZWxlZ2F0b3JBZGRyZXNzLFxuICAgICAgICAgIHZhbGlkYXRvckFkZHJlc3M6IHZhbHVlLnZhbGlkYXRvckFkZHJlc3MsXG4gICAgICAgICAgYW1vdW50OiB2YWx1ZS5hbW91bnQsXG4gICAgICAgIH0sXG4gICAgICAgIHR5cGVVcmw6IG1lc3NhZ2UudHlwZVVybCxcbiAgICAgIH07XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgYXJyYXkgb2YgTWVzc2FnZURhdGFbXSBmcm9tIHRoZSBkZWNvZGVkIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7RGVjb2RlZFR4UmF3fSBkZWNvZGVkVHhcbiAgICogQHJldHVybnMge01lc3NhZ2VEYXRhW119IFdpdGhkcmF3RGVsZWdhdG9yUmV3YXJkcyB0cmFuc2FjdGlvbiBtZXNzYWdlIGRhdGFcbiAgICovXG4gIGdldFdpdGhkcmF3UmV3YXJkc01lc3NhZ2VEYXRhRnJvbURlY29kZWRUeChkZWNvZGVkVHg6IERlY29kZWRUeFJhdyk6IE1lc3NhZ2VEYXRhW10ge1xuICAgIHJldHVybiBkZWNvZGVkVHguYm9keS5tZXNzYWdlcy5tYXAoKG1lc3NhZ2UpID0+IHtcbiAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5yZWdpc3RyeS5kZWNvZGUobWVzc2FnZSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWx1ZToge1xuICAgICAgICAgIGRlbGVnYXRvckFkZHJlc3M6IHZhbHVlLmRlbGVnYXRvckFkZHJlc3MsXG4gICAgICAgICAgdmFsaWRhdG9yQWRkcmVzczogdmFsdWUudmFsaWRhdG9yQWRkcmVzcyxcbiAgICAgICAgfSxcbiAgICAgICAgdHlwZVVybDogbWVzc2FnZS50eXBlVXJsLFxuICAgICAgfTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBhcnJheSBvZiBNZXNzYWdlRGF0YVtdIGZyb20gdGhlIGRlY29kZWQgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtEZWNvZGVkVHhSYXd9IGRlY29kZWRUeFxuICAgKiBAcmV0dXJucyB7TWVzc2FnZURhdGFbXX0gRGVsZWdhdGUgb2YgdW5kZWxlZ2F0ZSB0cmFuc2FjdGlvbiBtZXNzYWdlIGRhdGFcbiAgICovXG4gIGdldFdpdGhkcmF3RGVsZWdhdG9yUmV3YXJkc01lc3NhZ2VEYXRhRnJvbURlY29kZWRUeChkZWNvZGVkVHg6IERlY29kZWRUeFJhdyk6IE1lc3NhZ2VEYXRhW10ge1xuICAgIHJldHVybiBkZWNvZGVkVHguYm9keS5tZXNzYWdlcy5tYXAoKG1lc3NhZ2UpID0+IHtcbiAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5yZWdpc3RyeS5kZWNvZGUobWVzc2FnZSk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWx1ZToge1xuICAgICAgICAgIGRlbGVnYXRvckFkZHJlc3M6IHZhbHVlLmRlbGVnYXRvckFkZHJlc3MsXG4gICAgICAgICAgdmFsaWRhdG9yQWRkcmVzczogdmFsdWUudmFsaWRhdG9yQWRkcmVzcyxcbiAgICAgICAgfSxcbiAgICAgICAgdHlwZVVybDogbWVzc2FnZS50eXBlVXJsLFxuICAgICAgfTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGJpdGdvIHRyYW5zYWN0aW9uIHR5cGUgYmFzZWQgb24gb3Ntb3NpcyBwcm90byB0eXBlIHVybFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHlwZVVybFxuICAgKiBAcmV0dXJucyB7VHJhbnNhY3Rpb25UeXBlIHwgdW5kZWZpbmVkfSBUcmFuc2FjdGlvblR5cGUgaWYgdXJsIGlzIHN1cHBvcnRlZCBlbHNlIHVuZGVmaW5lZFxuICAgKi9cbiAgZ2V0VHJhbnNhY3Rpb25UeXBlRnJvbVR5cGVVcmwodHlwZVVybDogc3RyaW5nKTogVHJhbnNhY3Rpb25UeXBlIHwgdW5kZWZpbmVkIHtcbiAgICBzd2l0Y2ggKHR5cGVVcmwpIHtcbiAgICAgIGNhc2UgY29uc3RhbnRzLnNlbmRNc2dUeXBlVXJsOlxuICAgICAgICByZXR1cm4gVHJhbnNhY3Rpb25UeXBlLlNlbmQ7XG4gICAgICBjYXNlIGNvbnN0YW50cy5kZWxlZ2F0ZU1zZ1R5cGVVcmw6XG4gICAgICAgIHJldHVybiBUcmFuc2FjdGlvblR5cGUuU3Rha2luZ0FjdGl2YXRlO1xuICAgICAgY2FzZSBjb25zdGFudHMudW5kZWxlZ2F0ZU1zZ1R5cGVVcmw6XG4gICAgICAgIHJldHVybiBUcmFuc2FjdGlvblR5cGUuU3Rha2luZ0RlYWN0aXZhdGU7XG4gICAgICBjYXNlIGNvbnN0YW50cy53aXRoZHJhd0RlbGVnYXRvclJld2FyZE1zZ1R5cGVVcmw6XG4gICAgICAgIHJldHVybiBUcmFuc2FjdGlvblR5cGUuU3Rha2luZ1dpdGhkcmF3O1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHR4UmF3IGZyb20gYW4gY29zbW9zIGxpa2UgdHJhbnNhY3Rpb24gQHNlZSBDb3Ntb3NMaWtlVHJhbnNhY3Rpb25cbiAgICogQFByZWNvbmRpdGlvbiBjb3Ntb3NMaWtlVHJhbnNhY3Rpb24ucHVibGljS2V5IG11c3QgYmUgZGVmaW5lZFxuICAgKiBAcGFyYW0ge0Nvc21vc0xpa2VUcmFuc2FjdGlvbn0gY29zbW9zTGlrZVRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm5zIHtUeFJhd30gVW5zaWduZWQgcmF3IHRyYW5zYWN0aW9uXG4gICAqL1xuICBjcmVhdGVUeFJhd0Zyb21Db3Ntb3NMaWtlVHJhbnNhY3Rpb24oY29zbW9zTGlrZVRyYW5zYWN0aW9uOiBDb3Ntb3NMaWtlVHJhbnNhY3Rpb24pOiBUeFJhdyB7XG4gICAgaWYgKCFjb3Ntb3NMaWtlVHJhbnNhY3Rpb24ucHVibGljS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3B1YmxpY0tleSBpcyByZXF1aXJlZCB0byBjcmVhdGUgYSB0eFJhdycpO1xuICAgIH1cbiAgICBjb25zdCBlbmNvZGVkUHVibGljS2V5OiBBbnkgPSBlbmNvZGVQdWJrZXkoZW5jb2RlU2VjcDI1NmsxUHVia2V5KGZyb21IZXgoY29zbW9zTGlrZVRyYW5zYWN0aW9uLnB1YmxpY0tleSkpKTtcbiAgICBjb25zdCBtZXNzYWdlcyA9IGNvc21vc0xpa2VUcmFuc2FjdGlvbi5zZW5kTWVzc2FnZXMgYXMgdW5rbm93biBhcyBBbnlbXTtcbiAgICBsZXQgdHhCb2R5VmFsdWU7XG4gICAgaWYgKGNvc21vc0xpa2VUcmFuc2FjdGlvbi5tZW1vKSB7XG4gICAgICB0eEJvZHlWYWx1ZSA9IHtcbiAgICAgICAgbWVtbzogY29zbW9zTGlrZVRyYW5zYWN0aW9uLm1lbW8sXG4gICAgICAgIG1lc3NhZ2VzOiBtZXNzYWdlcyxcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIHR4Qm9keVZhbHVlID0ge1xuICAgICAgICBtZXNzYWdlczogbWVzc2FnZXMsXG4gICAgICB9O1xuICAgIH1cblxuICAgIGNvbnN0IHR4Qm9keUJ5dGVzID0gdGhpcy5yZWdpc3RyeS5lbmNvZGVUeEJvZHkodHhCb2R5VmFsdWUpO1xuICAgIGNvbnN0IHNlcXVlbmNlID0gY29zbW9zTGlrZVRyYW5zYWN0aW9uLnNlcXVlbmNlO1xuICAgIGNvbnN0IGF1dGhJbmZvQnl0ZXMgPSBtYWtlQXV0aEluZm9CeXRlcyhcbiAgICAgIFt7IHB1YmtleTogZW5jb2RlZFB1YmxpY0tleSwgc2VxdWVuY2UgfV0sXG4gICAgICBjb3Ntb3NMaWtlVHJhbnNhY3Rpb24uZ2FzQnVkZ2V0LmFtb3VudCxcbiAgICAgIGNvc21vc0xpa2VUcmFuc2FjdGlvbi5nYXNCdWRnZXQuZ2FzTGltaXQsXG4gICAgICB1bmRlZmluZWQsXG4gICAgICB1bmRlZmluZWQsXG4gICAgICB1bmRlZmluZWRcbiAgICApO1xuICAgIHJldHVybiBUeFJhdy5mcm9tUGFydGlhbCh7XG4gICAgICBib2R5Qnl0ZXM6IHR4Qm9keUJ5dGVzLFxuICAgICAgYXV0aEluZm9CeXRlczogYXV0aEluZm9CeXRlcyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmNvZGVzIGEgc2lnbmF0dXJlIGludG8gYSB0eFJhd1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcHVibGljS2V5SGV4IHB1YmxpY0tleSBpbiBoZXggZW5jb2RlZCBzdHJpbmcgZm9ybWF0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzaWduYXR1cmVIZXggc2lnbmF0dXJlIGluIGhleCBlbmNvZGVkIHN0cmluZyBmb3JtYXRcbiAgICogQHBhcmFtIHtUeFJhd30gdW5zaWduZWRUeCByYXcgdHJhbnNhY3Rpb25cbiAgICogQHJldHVybnMge1R4UmF3fSBTaWduZWQgcmF3IHRyYW5zYWN0aW9uXG4gICAqL1xuICBjcmVhdGVTaWduZWRUeFJhdyhcbiAgICBwdWJsaWNLZXlIZXg6IHN0cmluZyxcbiAgICBzaWduYXR1cmVIZXg6IHN0cmluZyxcbiAgICB1bnNpZ25lZFR4OiB7IGJvZHlCeXRlczogVWludDhBcnJheTsgYXV0aEluZm9CeXRlczogVWludDhBcnJheSB9XG4gICk6IFR4UmF3IHtcbiAgICBjb25zdCBzdGRTaWduYXR1cmUgPSBlbmNvZGVTZWNwMjU2azFTaWduYXR1cmUoZnJvbUhleChwdWJsaWNLZXlIZXgpLCBmcm9tSGV4KHNpZ25hdHVyZUhleCkpO1xuICAgIHJldHVybiBUeFJhdy5mcm9tUGFydGlhbCh7XG4gICAgICBib2R5Qnl0ZXM6IHVuc2lnbmVkVHguYm9keUJ5dGVzLFxuICAgICAgYXV0aEluZm9CeXRlczogdW5zaWduZWRUeC5hdXRoSW5mb0J5dGVzLFxuICAgICAgc2lnbmF0dXJlczogW2Zyb21CYXNlNjQoc3RkU2lnbmF0dXJlLnNpZ25hdHVyZSldLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIERlY29kZXMgYSByYXcgdHJhbnNhY3Rpb24gaW50byBhIERlY29kZWRUeFJhdyBhbmQgY2hlY2tzIGlmIGl0IGhhcyBub24gZW1wdHkgc2lnbmF0dXJlc1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcmF3VHJhbnNhY3Rpb25cbiAgICogQHJldHVybnMge2Jvb2xlYW59IHRydWUgaWYgdHJhbnNhY3Rpb24gaXMgc2lnbmVkIGVsc2UgZmFsc2VcbiAgICovXG4gIGlzU2lnbmVkUmF3VHgocmF3VHJhbnNhY3Rpb246IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGRlY29kZWRUeCA9IHRoaXMuZ2V0RGVjb2RlZFR4RnJvbVJhd0Jhc2U2NChyYXdUcmFuc2FjdGlvbik7XG4gICAgaWYgKGRlY29kZWRUeC5zaWduYXR1cmVzLmxlbmd0aCA+IDApIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICB2YWxpZGF0ZVB1YmxpY0tleShwdWJsaWNLZXk6IHN0cmluZyB8IHVuZGVmaW5lZCkge1xuICAgIGlmIChwdWJsaWNLZXkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgbmV3IEtleVBhaXIoeyBwdWI6IHB1YmxpY0tleSB9KTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICB0aHJvdyBuZXcgSW52YWxpZFRyYW5zYWN0aW9uRXJyb3IoYEtleSB2YWxpZGF0aW9uIGZhaWxlZGApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgaWYgdGhlIGFkZHJlc3MgbWF0Y2hlcyB3aXRoIHJlZ2V4IEBzZWUgYWNjb3VudEFkZHJlc3NSZWdleFxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWRkcmVzc1xuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSB0aGUgdmFsaWRhdGlvbiByZXN1bHRcbiAgICovXG4gIGlzVmFsaWRBZGRyZXNzKGFkZHJlc3M6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRocm93IG5ldyBOb3RJbXBsZW1lbnRlZEVycm9yKCdpc1ZhbGlkQWRkcmVzcyBub3QgaW1wbGVtZW50ZWQnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgc2lnbiBkb2MgZnJvbSBhbiBjb3Ntb3MgbGlrZSB0cmFuc2FjdGlvbiBAc2VlIENvc21vc0xpa2VUcmFuc2FjdGlvblxuICAgKiBAUHJlY29uZGl0aW9uIGNvc21vc0xpa2VUcmFuc2FjdGlvbi5hY2NvdW50TnVtYmVyIGFuZCBjb3Ntb3NMaWtlVHJhbnNhY3Rpb24uY2hhaW5JZCBtdXN0IGJlIGRlZmluZWRcbiAgICogQHBhcmFtIHtDb3Ntb3NMaWtlVHJhbnNhY3Rpb259IGNvc21vc0xpa2VUcmFuc2FjdGlvblxuICAgKiBAcmV0dXJucyB7U2lnbkRvY30gc2lnbiBkb2NcbiAgICovXG4gIGNyZWF0ZVNpZ25Eb2MoXG4gICAgY29zbW9zTGlrZVRyYW5zYWN0aW9uOiBDb3Ntb3NMaWtlVHJhbnNhY3Rpb24sXG4gICAgYWNjb3VudE51bWJlcjogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICAgIGNoYWluSWQ6IHN0cmluZyB8IHVuZGVmaW5lZFxuICApOiBTaWduRG9jIHtcbiAgICBpZiAoIWFjY291bnROdW1iZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignYWNjb3VudE51bWJlciBpcyByZXF1aXJlZCB0byBjcmVhdGUgYSBzaWduIGRvYycpO1xuICAgIH1cbiAgICBpZiAoIWNoYWluSWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY2hhaW5JZCBpcyByZXF1aXJlZCB0byBjcmVhdGUgYSBzaWduIGRvYycpO1xuICAgIH1cbiAgICBpZiAoIWNvc21vc0xpa2VUcmFuc2FjdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjb3Ntb3NMaWtlVHJhbnNhY3Rpb24gaXMgcmVxdWlyZWQgdG8gY3JlYXRlIGEgc2lnbiBkb2MnKTtcbiAgICB9XG4gICAgY29uc3QgdHhSYXcgPSB1dGlscy5jcmVhdGVUeFJhd0Zyb21Db3Ntb3NMaWtlVHJhbnNhY3Rpb24oY29zbW9zTGlrZVRyYW5zYWN0aW9uKTtcbiAgICByZXR1cm4gbWFrZVNpZ25Eb2ModHhSYXcuYm9keUJ5dGVzLCB0eFJhdy5hdXRoSW5mb0J5dGVzLCBjaGFpbklkLCBhY2NvdW50TnVtYmVyKTtcbiAgfVxuXG4gIGlzVmFsaWRIZXhTdHJpbmcoaGV4U3RyaW5nOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gL15bMC05QS1GYS1mXSokLy50ZXN0KGhleFN0cmluZyk7XG4gIH1cbn1cblxuY29uc3QgdXRpbHMgPSBuZXcgQ29zbW9zTGlrZVV0aWxzKCk7XG5cbmV4cG9ydCBkZWZhdWx0IHV0aWxzO1xuIl19
|