@bitgo-beta/sdk-coin-canton 1.0.1-beta.82 → 1.0.1-beta.821
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/dist/src/canton.d.ts +22 -1
- package/dist/src/canton.d.ts.map +1 -1
- package/dist/src/canton.js +293 -10
- package/dist/src/cantonToken.d.ts +19 -0
- package/dist/src/cantonToken.d.ts.map +1 -0
- package/dist/src/cantonToken.js +52 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/lib/allocationAllocateBuilder.d.ts +126 -0
- package/dist/src/lib/allocationAllocateBuilder.d.ts.map +1 -0
- package/dist/src/lib/allocationAllocateBuilder.js +248 -0
- package/dist/src/lib/allocationAllocateWithdrawnBuilder.d.ts +67 -0
- package/dist/src/lib/allocationAllocateWithdrawnBuilder.d.ts.map +1 -0
- package/dist/src/lib/allocationAllocateWithdrawnBuilder.js +130 -0
- package/dist/src/lib/allocationRejectBuilder.d.ts +51 -0
- package/dist/src/lib/allocationRejectBuilder.d.ts.map +1 -0
- package/dist/src/lib/allocationRejectBuilder.js +107 -0
- package/dist/src/lib/allocationRequestBuilder.d.ts +116 -0
- package/dist/src/lib/allocationRequestBuilder.d.ts.map +1 -0
- package/dist/src/lib/allocationRequestBuilder.js +243 -0
- package/dist/src/lib/amount.d.ts +8 -0
- package/dist/src/lib/amount.d.ts.map +1 -0
- package/dist/src/lib/amount.js +33 -0
- package/dist/src/lib/cantonCommandBuilder.d.ts +72 -0
- package/dist/src/lib/cantonCommandBuilder.d.ts.map +1 -0
- package/dist/src/lib/cantonCommandBuilder.js +173 -0
- package/dist/src/lib/clearSigning.d.ts +58 -0
- package/dist/src/lib/clearSigning.d.ts.map +1 -0
- package/dist/src/lib/clearSigning.js +66 -0
- package/dist/src/lib/cosignDelegationAcceptBuilder.d.ts +56 -0
- package/dist/src/lib/cosignDelegationAcceptBuilder.d.ts.map +1 -0
- package/dist/src/lib/cosignDelegationAcceptBuilder.js +112 -0
- package/dist/src/lib/cosignDelegationProposalBuilder.d.ts +60 -0
- package/dist/src/lib/cosignDelegationProposalBuilder.d.ts.map +1 -0
- package/dist/src/lib/cosignDelegationProposalBuilder.js +111 -0
- package/dist/src/lib/endInvestorOnboardingOfferBuilder.d.ts +58 -0
- package/dist/src/lib/endInvestorOnboardingOfferBuilder.d.ts.map +1 -0
- package/dist/src/lib/endInvestorOnboardingOfferBuilder.js +112 -0
- package/dist/src/lib/iface.d.ts +141 -2
- package/dist/src/lib/iface.d.ts.map +1 -1
- package/dist/src/lib/iface.js +3 -1
- package/dist/src/lib/index.d.ts +13 -0
- package/dist/src/lib/index.d.ts.map +1 -1
- package/dist/src/lib/index.js +29 -2
- package/dist/src/lib/messages/cantonBaseMessage.d.ts +16 -0
- package/dist/src/lib/messages/cantonBaseMessage.d.ts.map +1 -0
- package/dist/src/lib/messages/cantonBaseMessage.js +28 -0
- package/dist/src/lib/messages/cantonSignTopology/cantonSignTopologyMessage.d.ts +14 -0
- package/dist/src/lib/messages/cantonSignTopology/cantonSignTopologyMessage.d.ts.map +1 -0
- package/dist/src/lib/messages/cantonSignTopology/cantonSignTopologyMessage.js +23 -0
- package/dist/src/lib/messages/cantonSignTopology/cantonSignTopologyMessageBuilder.d.ts +17 -0
- package/dist/src/lib/messages/cantonSignTopology/cantonSignTopologyMessageBuilder.d.ts.map +1 -0
- package/dist/src/lib/messages/cantonSignTopology/cantonSignTopologyMessageBuilder.js +25 -0
- package/dist/src/lib/messages/cantonSignTopology/index.d.ts +3 -0
- package/dist/src/lib/messages/cantonSignTopology/index.d.ts.map +1 -0
- package/dist/src/lib/messages/cantonSignTopology/index.js +19 -0
- package/dist/src/lib/messages/cantonSignTransaction/cantonSignTransactionMessage.d.ts +13 -0
- package/dist/src/lib/messages/cantonSignTransaction/cantonSignTransactionMessage.d.ts.map +1 -0
- package/dist/src/lib/messages/cantonSignTransaction/cantonSignTransactionMessage.js +22 -0
- package/dist/src/lib/messages/cantonSignTransaction/cantonSignTransactionMessageBuilder.d.ts +14 -0
- package/dist/src/lib/messages/cantonSignTransaction/cantonSignTransactionMessageBuilder.d.ts.map +1 -0
- package/dist/src/lib/messages/cantonSignTransaction/cantonSignTransactionMessageBuilder.js +22 -0
- package/dist/src/lib/messages/cantonSignTransaction/index.d.ts +3 -0
- package/dist/src/lib/messages/cantonSignTransaction/index.d.ts.map +1 -0
- package/dist/src/lib/messages/cantonSignTransaction/index.js +19 -0
- package/dist/src/lib/messages/index.d.ts +5 -0
- package/dist/src/lib/messages/index.d.ts.map +1 -0
- package/dist/src/lib/messages/index.js +21 -0
- package/dist/src/lib/messages/messageBuilderFactory.d.ts +7 -0
- package/dist/src/lib/messages/messageBuilderFactory.d.ts.map +1 -0
- package/dist/src/lib/messages/messageBuilderFactory.js +23 -0
- package/dist/src/lib/oneStepPreApprovalBuilder.d.ts +8 -0
- package/dist/src/lib/oneStepPreApprovalBuilder.d.ts.map +1 -1
- package/dist/src/lib/oneStepPreApprovalBuilder.js +15 -1
- package/dist/src/lib/resourcesInterface.d.ts +1 -1
- package/dist/src/lib/resourcesInterface.d.ts.map +1 -1
- package/dist/src/lib/resourcesInterface.js +1 -1
- package/dist/src/lib/transaction/transaction.d.ts +17 -1
- package/dist/src/lib/transaction/transaction.d.ts.map +1 -1
- package/dist/src/lib/transaction/transaction.js +307 -16
- package/dist/src/lib/transactionBuilderFactory.d.ts +22 -0
- package/dist/src/lib/transactionBuilderFactory.d.ts.map +1 -1
- package/dist/src/lib/transactionBuilderFactory.js +78 -1
- package/dist/src/lib/transferAcknowledgeBuilder.d.ts +4 -4
- package/dist/src/lib/transferAcknowledgeBuilder.d.ts.map +1 -1
- package/dist/src/lib/transferAcknowledgeBuilder.js +5 -7
- package/dist/src/lib/transferBuilder.d.ts +84 -2
- package/dist/src/lib/transferBuilder.d.ts.map +1 -1
- package/dist/src/lib/transferBuilder.js +164 -2
- package/dist/src/lib/transferOfferWithdrawnBuilder.d.ts +67 -0
- package/dist/src/lib/transferOfferWithdrawnBuilder.d.ts.map +1 -0
- package/dist/src/lib/transferOfferWithdrawnBuilder.js +130 -0
- package/dist/src/lib/transferPreapprovalCancelBuilder.d.ts +68 -0
- package/dist/src/lib/transferPreapprovalCancelBuilder.d.ts.map +1 -0
- package/dist/src/lib/transferPreapprovalCancelBuilder.js +124 -0
- package/dist/src/lib/utils.d.ts +45 -3
- package/dist/src/lib/utils.d.ts.map +1 -1
- package/dist/src/lib/utils.js +776 -66
- package/dist/src/lib/walletInitBuilder.d.ts +2 -1
- package/dist/src/lib/walletInitBuilder.d.ts.map +1 -1
- package/dist/src/lib/walletInitBuilder.js +4 -1
- package/dist/src/lib/walletInitialization/walletInitTransaction.d.ts +2 -1
- package/dist/src/lib/walletInitialization/walletInitTransaction.d.ts.map +1 -1
- package/dist/src/lib/walletInitialization/walletInitTransaction.js +14 -1
- package/dist/src/register.d.ts +2 -0
- package/dist/src/register.d.ts.map +1 -1
- package/dist/src/register.js +19 -2
- package/dist/test/helper.d.ts +3 -0
- package/dist/test/helper.d.ts.map +1 -0
- package/dist/test/helper.js +9 -0
- package/dist/test/integration/canton.integration.d.ts +2 -0
- package/dist/test/integration/canton.integration.d.ts.map +1 -0
- package/dist/test/integration/canton.integration.js +157 -0
- package/dist/test/integration/canton.token.integration.d.ts +2 -0
- package/dist/test/integration/canton.token.integration.d.ts.map +1 -0
- package/dist/test/integration/canton.token.integration.js +51 -0
- package/dist/test/resources.d.ts +263 -2
- package/dist/test/resources.d.ts.map +1 -1
- package/dist/test/resources.js +269 -7
- package/dist/test/unit/builder/allocationAllocate/allocationAllocateBuilder.d.ts +2 -0
- package/dist/test/unit/builder/allocationAllocate/allocationAllocateBuilder.d.ts.map +1 -0
- package/dist/test/unit/builder/allocationAllocate/allocationAllocateBuilder.js +368 -0
- package/dist/test/unit/builder/allocationAllocateWithdrawn/allocationAllocateWithdrawnBuilder.d.ts +2 -0
- package/dist/test/unit/builder/allocationAllocateWithdrawn/allocationAllocateWithdrawnBuilder.d.ts.map +1 -0
- package/dist/test/unit/builder/allocationAllocateWithdrawn/allocationAllocateWithdrawnBuilder.js +133 -0
- package/dist/test/unit/builder/allocationReject/allocationRejectBuilder.d.ts +2 -0
- package/dist/test/unit/builder/allocationReject/allocationRejectBuilder.d.ts.map +1 -0
- package/dist/test/unit/builder/allocationReject/allocationRejectBuilder.js +121 -0
- package/dist/test/unit/builder/allocationRequest/allocationRequestBuilder.d.ts +2 -0
- package/dist/test/unit/builder/allocationRequest/allocationRequestBuilder.d.ts.map +1 -0
- package/dist/test/unit/builder/allocationRequest/allocationRequestBuilder.js +437 -0
- package/dist/test/unit/builder/cantonCommand/cantonCommandBuilder.d.ts +2 -0
- package/dist/test/unit/builder/cantonCommand/cantonCommandBuilder.d.ts.map +1 -0
- package/dist/test/unit/builder/cantonCommand/cantonCommandBuilder.js +340 -0
- package/dist/test/unit/builder/cosignDelegationAccept/cosignDelegationAcceptBuilder.d.ts +2 -0
- package/dist/test/unit/builder/cosignDelegationAccept/cosignDelegationAcceptBuilder.d.ts.map +1 -0
- package/dist/test/unit/builder/cosignDelegationAccept/cosignDelegationAcceptBuilder.js +116 -0
- package/dist/test/unit/builder/cosignDelegationProposal/cosignDelegationProposalBuilder.d.ts +2 -0
- package/dist/test/unit/builder/cosignDelegationProposal/cosignDelegationProposalBuilder.d.ts.map +1 -0
- package/dist/test/unit/builder/cosignDelegationProposal/cosignDelegationProposalBuilder.js +74 -0
- package/dist/test/unit/builder/endInvestorOnboardingOffer/endInvestorOnboardingOfferBuilder.d.ts +2 -0
- package/dist/test/unit/builder/endInvestorOnboardingOffer/endInvestorOnboardingOfferBuilder.d.ts.map +1 -0
- package/dist/test/unit/builder/endInvestorOnboardingOffer/endInvestorOnboardingOfferBuilder.js +116 -0
- package/dist/test/unit/builder/oneStepEnablement/oneStepEnablementBuilder.js +20 -1
- package/dist/test/unit/builder/transfer/transferBuilder.d.ts +2 -0
- package/dist/test/unit/builder/transfer/transferBuilder.d.ts.map +1 -0
- package/dist/test/unit/builder/transfer/transferBuilder.js +100 -0
- package/dist/test/unit/builder/transferAccept/transferAcceptBuilder.js +65 -1
- package/dist/test/unit/builder/transferAcknowledge/transferAcknowledgeBuilder.js +34 -1
- package/dist/test/unit/builder/transferOfferWithdrawn/transferOfferWithdrawnBuilder.d.ts +2 -0
- package/dist/test/unit/builder/transferOfferWithdrawn/transferOfferWithdrawnBuilder.d.ts.map +1 -0
- package/dist/test/unit/builder/transferOfferWithdrawn/transferOfferWithdrawnBuilder.js +64 -0
- package/dist/test/unit/builder/transferPreapprovalCancel/transferPreapprovalCancelBuilder.d.ts +2 -0
- package/dist/test/unit/builder/transferPreapprovalCancel/transferPreapprovalCancelBuilder.d.ts.map +1 -0
- package/dist/test/unit/builder/transferPreapprovalCancel/transferPreapprovalCancelBuilder.js +74 -0
- package/dist/test/unit/builder/transferReject/transferRejectBuilder.js +41 -1
- package/dist/test/unit/canton.d.ts +2 -0
- package/dist/test/unit/canton.d.ts.map +1 -0
- package/dist/test/unit/canton.js +853 -0
- package/dist/test/unit/index.d.ts +5 -0
- package/dist/test/unit/index.d.ts.map +1 -1
- package/dist/test/unit/index.js +6 -1
- package/dist/test/unit/messages/cantonSignTopologyMessage.d.ts +2 -0
- package/dist/test/unit/messages/cantonSignTopologyMessage.d.ts.map +1 -0
- package/dist/test/unit/messages/cantonSignTopologyMessage.js +46 -0
- package/dist/test/unit/messages/cantonSignTransactionMessage.d.ts +2 -0
- package/dist/test/unit/messages/cantonSignTransactionMessage.d.ts.map +1 -0
- package/dist/test/unit/messages/cantonSignTransactionMessage.js +48 -0
- package/dist/test/unit/messages/clearSigning.d.ts +2 -0
- package/dist/test/unit/messages/clearSigning.d.ts.map +1 -0
- package/dist/test/unit/messages/clearSigning.js +72 -0
- package/dist/test/unit/messages/messageBuilderFactory.d.ts +2 -0
- package/dist/test/unit/messages/messageBuilderFactory.d.ts.map +1 -0
- package/dist/test/unit/messages/messageBuilderFactory.js +52 -0
- package/dist/test/unit/register.d.ts +2 -0
- package/dist/test/unit/register.d.ts.map +1 -0
- package/dist/test/unit/register.js +65 -0
- package/dist/test/unit/utils.js +389 -9
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
|
@@ -0,0 +1,853 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
require("should");
|
|
4
|
+
const sdk_api_1 = require("@bitgo-beta/sdk-api");
|
|
5
|
+
const sdk_test_1 = require("@bitgo-beta/sdk-test");
|
|
6
|
+
const sdk_core_1 = require("@bitgo-beta/sdk-core");
|
|
7
|
+
const statics_1 = require("@bitgo-beta/statics");
|
|
8
|
+
const src_1 = require("../../src");
|
|
9
|
+
const resources_1 = require("../resources");
|
|
10
|
+
/**
|
|
11
|
+
* Builds a base64-encoded raw transaction for a OneStepPreApproval (enable token flow).
|
|
12
|
+
* For TSS wallets (which Canton always is), verifyTransaction receives txParams.enableTokens,
|
|
13
|
+
* not txParams.recipients. The wallet SDK's buildTokenEnablements passes enableTokens through
|
|
14
|
+
* unchanged for TSS wallets rather than converting them to recipients.
|
|
15
|
+
*/
|
|
16
|
+
function buildOneStepPreApprovalRawTx(prepareResponse, commandId) {
|
|
17
|
+
const data = {
|
|
18
|
+
prepareCommandResponse: prepareResponse,
|
|
19
|
+
txType: 'OneStepPreApproval',
|
|
20
|
+
preparedTransaction: '',
|
|
21
|
+
partySignatures: { signatures: [] },
|
|
22
|
+
deduplicationPeriod: { Empty: {} },
|
|
23
|
+
submissionId: commandId,
|
|
24
|
+
hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V2',
|
|
25
|
+
minLedgerTime: { time: { Empty: {} } },
|
|
26
|
+
};
|
|
27
|
+
return Buffer.from(JSON.stringify(data)).toString('base64');
|
|
28
|
+
}
|
|
29
|
+
/** Returns a mock wallet whose coinSpecific().rootAddress matches the given party ID. */
|
|
30
|
+
function walletWithRootAddress(rootAddress) {
|
|
31
|
+
return { coinSpecific: () => ({ rootAddress }) };
|
|
32
|
+
}
|
|
33
|
+
/** Builds a base64-encoded raw transaction for a non-OneStep txType (e.g. AllocationReject). */
|
|
34
|
+
function buildRawTx(txType, prepareResponse, commandId) {
|
|
35
|
+
const data = {
|
|
36
|
+
prepareCommandResponse: prepareResponse,
|
|
37
|
+
txType,
|
|
38
|
+
preparedTransaction: '',
|
|
39
|
+
partySignatures: { signatures: [] },
|
|
40
|
+
deduplicationPeriod: { Empty: {} },
|
|
41
|
+
submissionId: commandId,
|
|
42
|
+
hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V2',
|
|
43
|
+
minLedgerTime: { time: { Empty: {} } },
|
|
44
|
+
};
|
|
45
|
+
return Buffer.from(JSON.stringify(data)).toString('base64');
|
|
46
|
+
}
|
|
47
|
+
describe('Canton coin:', function () {
|
|
48
|
+
let bitgo;
|
|
49
|
+
let basecoin;
|
|
50
|
+
before(function () {
|
|
51
|
+
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'mock' });
|
|
52
|
+
bitgo.safeRegister('canton', src_1.Canton.createInstance);
|
|
53
|
+
bitgo.safeRegister('tcanton', src_1.Tcanton.createInstance);
|
|
54
|
+
bitgo.initializeTestVars();
|
|
55
|
+
basecoin = bitgo.coin('tcanton');
|
|
56
|
+
});
|
|
57
|
+
describe('supportsMessageSigning', function () {
|
|
58
|
+
it('should return true', function () {
|
|
59
|
+
basecoin.supportsMessageSigning().should.equal(true);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe('Canton verifyTransaction:', function () {
|
|
64
|
+
let bitgo;
|
|
65
|
+
let basecoin;
|
|
66
|
+
before(function () {
|
|
67
|
+
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'mock' });
|
|
68
|
+
bitgo.safeRegister('canton', src_1.Canton.createInstance);
|
|
69
|
+
bitgo.safeRegister('tcanton', src_1.Tcanton.createInstance);
|
|
70
|
+
bitgo.initializeTestVars();
|
|
71
|
+
basecoin = bitgo.coin('tcanton');
|
|
72
|
+
});
|
|
73
|
+
describe('OneStepPreApproval (enable token flow):', function () {
|
|
74
|
+
it('should return true when txParams has no type (non-enabletoken flow)', async function () {
|
|
75
|
+
const txHex = buildOneStepPreApprovalRawTx(resources_1.OneStepPreApprovalPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
76
|
+
const result = await basecoin.verifyTransaction({
|
|
77
|
+
txPrebuild: { txHex },
|
|
78
|
+
txParams: {},
|
|
79
|
+
wallet: {},
|
|
80
|
+
});
|
|
81
|
+
result.should.equal(true);
|
|
82
|
+
});
|
|
83
|
+
it('should return true when enableTokens is absent', async function () {
|
|
84
|
+
const txHex = buildOneStepPreApprovalRawTx(resources_1.OneStepPreApprovalPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
85
|
+
const result = await basecoin.verifyTransaction({
|
|
86
|
+
txPrebuild: { txHex },
|
|
87
|
+
txParams: { type: 'enabletoken' },
|
|
88
|
+
wallet: {},
|
|
89
|
+
});
|
|
90
|
+
result.should.equal(true);
|
|
91
|
+
});
|
|
92
|
+
it('should return true when enableTokens is empty', async function () {
|
|
93
|
+
const txHex = buildOneStepPreApprovalRawTx(resources_1.OneStepPreApprovalPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
94
|
+
const result = await basecoin.verifyTransaction({
|
|
95
|
+
txPrebuild: { txHex },
|
|
96
|
+
txParams: { type: 'enabletoken', enableTokens: [] },
|
|
97
|
+
wallet: {},
|
|
98
|
+
});
|
|
99
|
+
result.should.equal(true);
|
|
100
|
+
});
|
|
101
|
+
describe('coin pre-approval (TransferPreapprovalProposal):', function () {
|
|
102
|
+
let txHex;
|
|
103
|
+
let receiver;
|
|
104
|
+
before(function () {
|
|
105
|
+
txHex = buildOneStepPreApprovalRawTx(resources_1.OneStepPreApprovalPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
106
|
+
// Dynamically derive receiver from parsed transaction to avoid hardcoding protobuf-decoded addresses
|
|
107
|
+
const txBuilder = new src_1.TransactionBuilderFactory(statics_1.coins.get('tcanton')).from(txHex);
|
|
108
|
+
receiver = txBuilder.transaction.toJson().receiver;
|
|
109
|
+
});
|
|
110
|
+
it('should return true when wallet has no coinSpecific (receiver check skipped)', async function () {
|
|
111
|
+
// Typical case: wallet mock has no coinSpecific() method, and no address in enableTokens
|
|
112
|
+
const result = await basecoin.verifyTransaction({
|
|
113
|
+
txPrebuild: { txHex },
|
|
114
|
+
txParams: {
|
|
115
|
+
type: 'enabletoken',
|
|
116
|
+
enableTokens: [{ name: 'canton' }],
|
|
117
|
+
},
|
|
118
|
+
wallet: {},
|
|
119
|
+
});
|
|
120
|
+
result.should.equal(true);
|
|
121
|
+
});
|
|
122
|
+
it('should return true when wallet rootAddress matches receiver', async function () {
|
|
123
|
+
// Typical UI flow: enableTokens has no address, receiver validated from wallet.coinSpecific().rootAddress
|
|
124
|
+
const result = await basecoin.verifyTransaction({
|
|
125
|
+
txPrebuild: { txHex },
|
|
126
|
+
txParams: {
|
|
127
|
+
type: 'enabletoken',
|
|
128
|
+
enableTokens: [{ name: 'canton' }],
|
|
129
|
+
},
|
|
130
|
+
wallet: walletWithRootAddress(receiver),
|
|
131
|
+
});
|
|
132
|
+
result.should.equal(true);
|
|
133
|
+
});
|
|
134
|
+
it('should return true when enableToken.address matches receiver (explicit address)', async function () {
|
|
135
|
+
const result = await basecoin.verifyTransaction({
|
|
136
|
+
txPrebuild: { txHex },
|
|
137
|
+
txParams: {
|
|
138
|
+
type: 'enabletoken',
|
|
139
|
+
enableTokens: [{ name: 'canton', address: receiver }],
|
|
140
|
+
},
|
|
141
|
+
wallet: {},
|
|
142
|
+
});
|
|
143
|
+
result.should.equal(true);
|
|
144
|
+
});
|
|
145
|
+
it('should throw when wallet rootAddress does not match receiver', async function () {
|
|
146
|
+
const wrongAddress = 'wrong-party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
|
147
|
+
await basecoin
|
|
148
|
+
.verifyTransaction({
|
|
149
|
+
txPrebuild: { txHex },
|
|
150
|
+
txParams: {
|
|
151
|
+
type: 'enabletoken',
|
|
152
|
+
enableTokens: [{ name: 'canton' }],
|
|
153
|
+
},
|
|
154
|
+
wallet: walletWithRootAddress(wrongAddress),
|
|
155
|
+
})
|
|
156
|
+
.should.be.rejectedWith(/OneStepPreApproval receiver mismatch/);
|
|
157
|
+
});
|
|
158
|
+
it('should throw when explicit enableToken.address does not match receiver', async function () {
|
|
159
|
+
const wrongAddress = 'wrong-party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
|
160
|
+
await basecoin
|
|
161
|
+
.verifyTransaction({
|
|
162
|
+
txPrebuild: { txHex },
|
|
163
|
+
txParams: {
|
|
164
|
+
type: 'enabletoken',
|
|
165
|
+
enableTokens: [{ name: 'canton', address: wrongAddress }],
|
|
166
|
+
},
|
|
167
|
+
wallet: {},
|
|
168
|
+
})
|
|
169
|
+
.should.be.rejectedWith(/OneStepPreApproval receiver mismatch/);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
describe('token pre-approval (TransferPreapproval):', function () {
|
|
173
|
+
let txHex;
|
|
174
|
+
let receiver;
|
|
175
|
+
before(function () {
|
|
176
|
+
const commandId = '7d99789d-2f22-49e1-85cb-79d2ce5a69c1';
|
|
177
|
+
txHex = buildOneStepPreApprovalRawTx(resources_1.CantonTokenPreApprovalPrepareResponse, commandId);
|
|
178
|
+
const txBuilder = new src_1.TransactionBuilderFactory(statics_1.coins.get('tcanton')).from(txHex);
|
|
179
|
+
receiver = txBuilder.transaction.toJson().receiver;
|
|
180
|
+
});
|
|
181
|
+
it('should return true when wallet rootAddress matches receiver', async function () {
|
|
182
|
+
const result = await basecoin.verifyTransaction({
|
|
183
|
+
txPrebuild: { txHex },
|
|
184
|
+
txParams: {
|
|
185
|
+
type: 'enabletoken',
|
|
186
|
+
enableTokens: [{ name: 'tcanton:testcoin1' }],
|
|
187
|
+
},
|
|
188
|
+
wallet: walletWithRootAddress(receiver),
|
|
189
|
+
});
|
|
190
|
+
result.should.equal(true);
|
|
191
|
+
});
|
|
192
|
+
it('should return true when enableToken.address matches receiver (explicit address)', async function () {
|
|
193
|
+
const result = await basecoin.verifyTransaction({
|
|
194
|
+
txPrebuild: { txHex },
|
|
195
|
+
txParams: {
|
|
196
|
+
type: 'enabletoken',
|
|
197
|
+
enableTokens: [{ name: 'tcanton:testcoin1', address: receiver }],
|
|
198
|
+
},
|
|
199
|
+
wallet: {},
|
|
200
|
+
});
|
|
201
|
+
result.should.equal(true);
|
|
202
|
+
});
|
|
203
|
+
it('should throw when wallet rootAddress does not match receiver', async function () {
|
|
204
|
+
const wrongAddress = 'wrong-party::1220bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb';
|
|
205
|
+
await basecoin
|
|
206
|
+
.verifyTransaction({
|
|
207
|
+
txPrebuild: { txHex },
|
|
208
|
+
txParams: {
|
|
209
|
+
type: 'enabletoken',
|
|
210
|
+
enableTokens: [{ name: 'tcanton:testcoin1' }],
|
|
211
|
+
},
|
|
212
|
+
wallet: walletWithRootAddress(wrongAddress),
|
|
213
|
+
})
|
|
214
|
+
.should.be.rejectedWith(/OneStepPreApproval receiver mismatch/);
|
|
215
|
+
});
|
|
216
|
+
it('should throw when explicit enableToken.address does not match receiver', async function () {
|
|
217
|
+
const wrongAddress = 'wrong-party::1220bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb';
|
|
218
|
+
await basecoin
|
|
219
|
+
.verifyTransaction({
|
|
220
|
+
txPrebuild: { txHex },
|
|
221
|
+
txParams: {
|
|
222
|
+
type: 'enabletoken',
|
|
223
|
+
enableTokens: [{ name: 'tcanton:testcoin1', address: wrongAddress }],
|
|
224
|
+
},
|
|
225
|
+
wallet: {},
|
|
226
|
+
})
|
|
227
|
+
.should.be.rejectedWith(/OneStepPreApproval receiver mismatch/);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
describe('TransferPreapprovalCancel (disable token flow):', function () {
|
|
232
|
+
// Real captured TransferPreapproval_Cancel exercise-node fixture: parsed sender === receiver
|
|
233
|
+
// === CancelParty, matching the actual on-chain choice/actingParties shape.
|
|
234
|
+
it('should return true when txParams has no type (non-disabletoken flow)', async function () {
|
|
235
|
+
const txHex = buildRawTx('TransferPreapprovalCancel', resources_1.TransferPreapprovalCancelPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
236
|
+
const result = await basecoin.verifyTransaction({
|
|
237
|
+
txPrebuild: { txHex },
|
|
238
|
+
txParams: {},
|
|
239
|
+
wallet: {},
|
|
240
|
+
});
|
|
241
|
+
result.should.equal(true);
|
|
242
|
+
});
|
|
243
|
+
it('should return true when enableTokens is absent', async function () {
|
|
244
|
+
const txHex = buildRawTx('TransferPreapprovalCancel', resources_1.TransferPreapprovalCancelPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
245
|
+
const result = await basecoin.verifyTransaction({
|
|
246
|
+
txPrebuild: { txHex },
|
|
247
|
+
txParams: { type: 'disabletoken' },
|
|
248
|
+
wallet: {},
|
|
249
|
+
});
|
|
250
|
+
result.should.equal(true);
|
|
251
|
+
});
|
|
252
|
+
it('should return true when enableTokens is empty', async function () {
|
|
253
|
+
const txHex = buildRawTx('TransferPreapprovalCancel', resources_1.TransferPreapprovalCancelPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
254
|
+
const result = await basecoin.verifyTransaction({
|
|
255
|
+
txPrebuild: { txHex },
|
|
256
|
+
txParams: { type: 'disabletoken', enableTokens: [] },
|
|
257
|
+
wallet: {},
|
|
258
|
+
});
|
|
259
|
+
result.should.equal(true);
|
|
260
|
+
});
|
|
261
|
+
it('should return true when wallet has no coinSpecific and no explicit address (receiver check skipped)', async function () {
|
|
262
|
+
const txHex = buildRawTx('TransferPreapprovalCancel', resources_1.TransferPreapprovalCancelPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
263
|
+
const result = await basecoin.verifyTransaction({
|
|
264
|
+
txPrebuild: { txHex },
|
|
265
|
+
txParams: {
|
|
266
|
+
type: 'disabletoken',
|
|
267
|
+
enableTokens: [{ name: 'canton' }],
|
|
268
|
+
},
|
|
269
|
+
wallet: {},
|
|
270
|
+
});
|
|
271
|
+
result.should.equal(true);
|
|
272
|
+
});
|
|
273
|
+
it('should return true when wallet rootAddress matches the parsed receiver', async function () {
|
|
274
|
+
const txHex = buildRawTx('TransferPreapprovalCancel', resources_1.TransferPreapprovalCancelPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
275
|
+
const result = await basecoin.verifyTransaction({
|
|
276
|
+
txPrebuild: { txHex },
|
|
277
|
+
txParams: {
|
|
278
|
+
type: 'disabletoken',
|
|
279
|
+
enableTokens: [{ name: 'canton' }],
|
|
280
|
+
},
|
|
281
|
+
wallet: walletWithRootAddress(resources_1.CancelParty),
|
|
282
|
+
});
|
|
283
|
+
result.should.equal(true);
|
|
284
|
+
});
|
|
285
|
+
it('should return true when explicit enableToken.address matches the parsed receiver', async function () {
|
|
286
|
+
const txHex = buildRawTx('TransferPreapprovalCancel', resources_1.TransferPreapprovalCancelPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
287
|
+
const result = await basecoin.verifyTransaction({
|
|
288
|
+
txPrebuild: { txHex },
|
|
289
|
+
txParams: {
|
|
290
|
+
type: 'disabletoken',
|
|
291
|
+
enableTokens: [{ name: 'canton', address: resources_1.CancelParty }],
|
|
292
|
+
},
|
|
293
|
+
wallet: {},
|
|
294
|
+
});
|
|
295
|
+
result.should.equal(true);
|
|
296
|
+
});
|
|
297
|
+
it('should throw when wallet rootAddress does not match the parsed receiver', async function () {
|
|
298
|
+
const txHex = buildRawTx('TransferPreapprovalCancel', resources_1.TransferPreapprovalCancelPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
299
|
+
const someAddress = 'some-party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
|
300
|
+
await basecoin
|
|
301
|
+
.verifyTransaction({
|
|
302
|
+
txPrebuild: { txHex },
|
|
303
|
+
txParams: {
|
|
304
|
+
type: 'disabletoken',
|
|
305
|
+
enableTokens: [{ name: 'canton' }],
|
|
306
|
+
},
|
|
307
|
+
wallet: walletWithRootAddress(someAddress),
|
|
308
|
+
})
|
|
309
|
+
.should.be.rejectedWith(/TransferPreapprovalCancel receiver mismatch/);
|
|
310
|
+
});
|
|
311
|
+
it('should throw when explicit enableToken.address does not match the parsed receiver', async function () {
|
|
312
|
+
const txHex = buildRawTx('TransferPreapprovalCancel', resources_1.TransferPreapprovalCancelPrepareResponse, resources_1.OneStepEnablement.commandId);
|
|
313
|
+
const someAddress = 'some-party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
|
314
|
+
await basecoin
|
|
315
|
+
.verifyTransaction({
|
|
316
|
+
txPrebuild: { txHex },
|
|
317
|
+
txParams: {
|
|
318
|
+
type: 'disabletoken',
|
|
319
|
+
enableTokens: [{ name: 'canton', address: someAddress }],
|
|
320
|
+
},
|
|
321
|
+
wallet: {},
|
|
322
|
+
})
|
|
323
|
+
.should.be.rejectedWith(/TransferPreapprovalCancel receiver mismatch/);
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
describe('Canton verifyTransaction - AllocationReject:', function () {
|
|
328
|
+
let bitgo;
|
|
329
|
+
let basecoin;
|
|
330
|
+
before(function () {
|
|
331
|
+
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'mock' });
|
|
332
|
+
bitgo.safeRegister('canton', src_1.Canton.createInstance);
|
|
333
|
+
bitgo.safeRegister('tcanton', src_1.Tcanton.createInstance);
|
|
334
|
+
bitgo.initializeTestVars();
|
|
335
|
+
basecoin = bitgo.coin('tcanton');
|
|
336
|
+
});
|
|
337
|
+
it('should return true for an AllocationReject transaction (no recipient info to verify)', async function () {
|
|
338
|
+
const txHex = buildRawTx('AllocationReject', resources_1.CantonAllocationRejectPrepareResponse, resources_1.AllocationRejection.commandId);
|
|
339
|
+
const result = await basecoin.verifyTransaction({
|
|
340
|
+
txPrebuild: { txHex },
|
|
341
|
+
txParams: {},
|
|
342
|
+
wallet: {},
|
|
343
|
+
});
|
|
344
|
+
result.should.equal(true);
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
describe('Canton explainTransaction - AllocationReject:', function () {
|
|
348
|
+
it('should return an empty explanation (no funds move on an AllocationRequest reject)', function () {
|
|
349
|
+
// AllocationRequest_Reject fires before the actor has allocated their leg — no Holding
|
|
350
|
+
// was ever locked for this trade, so nothing is returned. Unlike TransferReject (which
|
|
351
|
+
// unwinds a real fund movement), this is a pure "decline to trade" signal with no
|
|
352
|
+
// balance impact, so it intentionally falls through to the default (empty) explanation
|
|
353
|
+
// rather than being reported as an input.
|
|
354
|
+
const tx = new src_1.Transaction(statics_1.coins.get('tcanton'));
|
|
355
|
+
tx.id = resources_1.AllocationRejection.commandId;
|
|
356
|
+
tx.transactionType = sdk_core_1.TransactionType.AllocationReject;
|
|
357
|
+
tx.prepareCommand = resources_1.CantonAllocationRejectPrepareResponse;
|
|
358
|
+
const explanation = tx.explainTransaction();
|
|
359
|
+
explanation.inputs.length.should.equal(0);
|
|
360
|
+
explanation.inputAmount.should.equal('0');
|
|
361
|
+
explanation.outputs.length.should.equal(0);
|
|
362
|
+
explanation.outputAmount.should.equal('0');
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
// --------------- ExerciseCommand verification tests ---------------
|
|
366
|
+
const CANTON_CMD_ACT_AS = 'RegRegistrar::1220508e54fb709dcb1a9b4096408ad415d2217d8881ad9034a9850752933ba88ad5';
|
|
367
|
+
const CANTON_CMD_TEMPLATE_ID = '7a75ef6e69f69395a4e60919e228528bb8f3881150ccfde3f31bcc73864b18ab:Utility.Registry.App.V0.Service.AllocationFactory:AllocationFactory';
|
|
368
|
+
const CANTON_CMD_CONTRACT_ID = '00f3afdce846a40c6f3f618c4b584b022a0197010057ecd59458200183ab27de0aca1212204aef7ede37a5f41b674a1d95446d42a404461c5558c4e6d1860b65560120ef18';
|
|
369
|
+
const CANTON_CMD_CHOICE = 'AllocationFactory_OfferMint';
|
|
370
|
+
function buildCantonCommandRawTx(prepareResponse, commandId) {
|
|
371
|
+
const data = {
|
|
372
|
+
prepareCommandResponse: prepareResponse,
|
|
373
|
+
txType: 'CantonCommand',
|
|
374
|
+
preparedTransaction: '',
|
|
375
|
+
partySignatures: { signatures: [] },
|
|
376
|
+
deduplicationPeriod: { Empty: {} },
|
|
377
|
+
submissionId: commandId,
|
|
378
|
+
hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V2',
|
|
379
|
+
minLedgerTime: { time: { Empty: {} } },
|
|
380
|
+
};
|
|
381
|
+
return Buffer.from(JSON.stringify(data)).toString('base64');
|
|
382
|
+
}
|
|
383
|
+
describe('Canton verifyTransaction - CantonCommand:', function () {
|
|
384
|
+
let bitgo;
|
|
385
|
+
let basecoin;
|
|
386
|
+
before(function () {
|
|
387
|
+
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'mock' });
|
|
388
|
+
bitgo.safeRegister('canton', src_1.Canton.createInstance);
|
|
389
|
+
bitgo.safeRegister('tcanton', src_1.Tcanton.createInstance);
|
|
390
|
+
bitgo.initializeTestVars();
|
|
391
|
+
basecoin = bitgo.coin('tcanton');
|
|
392
|
+
});
|
|
393
|
+
describe('Happy path tests:', function () {
|
|
394
|
+
let txHex;
|
|
395
|
+
before(function () {
|
|
396
|
+
txHex = buildCantonCommandRawTx(resources_1.CantonExerciseCommandPrepareResponse, 'test-canton-cmd-001');
|
|
397
|
+
});
|
|
398
|
+
it('should return true when cantonCommandParams is undefined (no user params to verify)', async function () {
|
|
399
|
+
const result = await basecoin.verifyTransaction({
|
|
400
|
+
txPrebuild: { txHex },
|
|
401
|
+
txParams: {},
|
|
402
|
+
wallet: {},
|
|
403
|
+
});
|
|
404
|
+
result.should.equal(true);
|
|
405
|
+
});
|
|
406
|
+
it('should return true for matching ExerciseCommand (templateId, choice, contractId, actAs, argument)', async function () {
|
|
407
|
+
const result = await basecoin.verifyTransaction({
|
|
408
|
+
txPrebuild: { txHex },
|
|
409
|
+
txParams: {
|
|
410
|
+
cantonCommandParams: {
|
|
411
|
+
command: {
|
|
412
|
+
ExerciseCommand: {
|
|
413
|
+
templateId: CANTON_CMD_TEMPLATE_ID,
|
|
414
|
+
contractId: CANTON_CMD_CONTRACT_ID,
|
|
415
|
+
choice: CANTON_CMD_CHOICE,
|
|
416
|
+
choiceArgument: {
|
|
417
|
+
expectedAdmin: CANTON_CMD_ACT_AS,
|
|
418
|
+
mint: {
|
|
419
|
+
instrumentId: {
|
|
420
|
+
admin: CANTON_CMD_ACT_AS,
|
|
421
|
+
id: 'TESTTOKEN',
|
|
422
|
+
},
|
|
423
|
+
amount: '100',
|
|
424
|
+
holder: 'RegIssuer::1220508e54fb709dcb1a9b4096408ad415d2217d8881ad9034a9850752933ba88ad5',
|
|
425
|
+
reference: 'test-prepare-mint',
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
431
|
+
readAs: [],
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
wallet: {},
|
|
435
|
+
});
|
|
436
|
+
result.should.equal(true);
|
|
437
|
+
});
|
|
438
|
+
it('should return true when contractId is omitted (IMS-resolved)', async function () {
|
|
439
|
+
const result = await basecoin.verifyTransaction({
|
|
440
|
+
txPrebuild: { txHex },
|
|
441
|
+
txParams: {
|
|
442
|
+
cantonCommandParams: {
|
|
443
|
+
command: {
|
|
444
|
+
ExerciseCommand: {
|
|
445
|
+
templateId: CANTON_CMD_TEMPLATE_ID,
|
|
446
|
+
choice: CANTON_CMD_CHOICE,
|
|
447
|
+
choiceArgument: {},
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
451
|
+
readAs: [],
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
wallet: {},
|
|
455
|
+
});
|
|
456
|
+
result.should.equal(true);
|
|
457
|
+
});
|
|
458
|
+
it('should return true with resolveContracts injectAs skipping contractId (empty contractId)', async function () {
|
|
459
|
+
const result = await basecoin.verifyTransaction({
|
|
460
|
+
txPrebuild: { txHex },
|
|
461
|
+
txParams: {
|
|
462
|
+
cantonCommandParams: {
|
|
463
|
+
command: {
|
|
464
|
+
ExerciseCommand: {
|
|
465
|
+
templateId: CANTON_CMD_TEMPLATE_ID,
|
|
466
|
+
contractId: '',
|
|
467
|
+
choice: CANTON_CMD_CHOICE,
|
|
468
|
+
choiceArgument: {},
|
|
469
|
+
},
|
|
470
|
+
},
|
|
471
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
472
|
+
readAs: [],
|
|
473
|
+
resolveContracts: [
|
|
474
|
+
{
|
|
475
|
+
templateId: CANTON_CMD_TEMPLATE_ID,
|
|
476
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
477
|
+
injectAs: 'command.ExerciseCommand.contractId',
|
|
478
|
+
},
|
|
479
|
+
],
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
wallet: {},
|
|
483
|
+
});
|
|
484
|
+
result.should.equal(true);
|
|
485
|
+
});
|
|
486
|
+
it('should return true with resolveContracts injectAs skipping non-empty contractId mismatch', async function () {
|
|
487
|
+
// User supplies a placeholder contractId that doesn't match what's on-chain;
|
|
488
|
+
// resolveContracts marks it as IMS-injected, so the mismatch must be ignored.
|
|
489
|
+
const result = await basecoin.verifyTransaction({
|
|
490
|
+
txPrebuild: { txHex },
|
|
491
|
+
txParams: {
|
|
492
|
+
cantonCommandParams: {
|
|
493
|
+
command: {
|
|
494
|
+
ExerciseCommand: {
|
|
495
|
+
templateId: CANTON_CMD_TEMPLATE_ID,
|
|
496
|
+
contractId: '00placeholder_contract_id_not_on_chain',
|
|
497
|
+
choice: CANTON_CMD_CHOICE,
|
|
498
|
+
choiceArgument: {},
|
|
499
|
+
},
|
|
500
|
+
},
|
|
501
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
502
|
+
readAs: [],
|
|
503
|
+
resolveContracts: [
|
|
504
|
+
{
|
|
505
|
+
templateId: CANTON_CMD_TEMPLATE_ID,
|
|
506
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
507
|
+
injectAs: 'command.ExerciseCommand.contractId',
|
|
508
|
+
},
|
|
509
|
+
],
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
wallet: {},
|
|
513
|
+
});
|
|
514
|
+
result.should.equal(true);
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
describe('Error cases:', function () {
|
|
518
|
+
let txHex;
|
|
519
|
+
before(function () {
|
|
520
|
+
txHex = buildCantonCommandRawTx(resources_1.CantonExerciseCommandPrepareResponse, 'test-canton-cmd-002');
|
|
521
|
+
});
|
|
522
|
+
it('should throw when preparedTransaction is missing on tx prebuild', async function () {
|
|
523
|
+
const emptyPrepare = { ...resources_1.CantonExerciseCommandPrepareResponse, preparedTransaction: undefined };
|
|
524
|
+
const badTx = buildCantonCommandRawTx(emptyPrepare, 'cmd-bad');
|
|
525
|
+
await basecoin
|
|
526
|
+
.verifyTransaction({
|
|
527
|
+
txPrebuild: { txHex: badTx },
|
|
528
|
+
txParams: {
|
|
529
|
+
cantonCommandParams: {
|
|
530
|
+
command: {
|
|
531
|
+
ExerciseCommand: { templateId: CANTON_CMD_TEMPLATE_ID, choice: CANTON_CMD_CHOICE, choiceArgument: {} },
|
|
532
|
+
},
|
|
533
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
wallet: {},
|
|
537
|
+
})
|
|
538
|
+
.should.be.rejectedWith(/missing preparedTransaction/);
|
|
539
|
+
});
|
|
540
|
+
it('should throw when user command has neither CreateCommand nor ExerciseCommand', async function () {
|
|
541
|
+
await basecoin
|
|
542
|
+
.verifyTransaction({
|
|
543
|
+
txPrebuild: { txHex },
|
|
544
|
+
txParams: {
|
|
545
|
+
cantonCommandParams: {
|
|
546
|
+
command: { UnknownCommand: {} },
|
|
547
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
548
|
+
},
|
|
549
|
+
},
|
|
550
|
+
wallet: {},
|
|
551
|
+
})
|
|
552
|
+
.should.be.rejectedWith(/must contain a CreateCommand or ExerciseCommand/);
|
|
553
|
+
});
|
|
554
|
+
it('should throw when user command contains both CreateCommand and ExerciseCommand', async function () {
|
|
555
|
+
await basecoin
|
|
556
|
+
.verifyTransaction({
|
|
557
|
+
txPrebuild: { txHex },
|
|
558
|
+
txParams: {
|
|
559
|
+
cantonCommandParams: {
|
|
560
|
+
command: {
|
|
561
|
+
CreateCommand: { templateId: CANTON_CMD_TEMPLATE_ID, createArguments: {} },
|
|
562
|
+
ExerciseCommand: { templateId: CANTON_CMD_TEMPLATE_ID, choice: CANTON_CMD_CHOICE, choiceArgument: {} },
|
|
563
|
+
},
|
|
564
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
565
|
+
},
|
|
566
|
+
},
|
|
567
|
+
wallet: {},
|
|
568
|
+
})
|
|
569
|
+
.should.be.rejectedWith(/exactly one of CreateCommand or ExerciseCommand/);
|
|
570
|
+
});
|
|
571
|
+
it('should throw on invalid user templateId format', async function () {
|
|
572
|
+
await basecoin
|
|
573
|
+
.verifyTransaction({
|
|
574
|
+
txPrebuild: { txHex },
|
|
575
|
+
txParams: {
|
|
576
|
+
cantonCommandParams: {
|
|
577
|
+
command: {
|
|
578
|
+
ExerciseCommand: {
|
|
579
|
+
templateId: 'InvalidFormat',
|
|
580
|
+
choice: CANTON_CMD_CHOICE,
|
|
581
|
+
choiceArgument: {},
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
585
|
+
},
|
|
586
|
+
},
|
|
587
|
+
wallet: {},
|
|
588
|
+
})
|
|
589
|
+
.should.be.rejectedWith(/invalid user templateId/);
|
|
590
|
+
});
|
|
591
|
+
it('should throw on templateId module/entity mismatch', async function () {
|
|
592
|
+
await basecoin
|
|
593
|
+
.verifyTransaction({
|
|
594
|
+
txPrebuild: { txHex },
|
|
595
|
+
txParams: {
|
|
596
|
+
cantonCommandParams: {
|
|
597
|
+
command: {
|
|
598
|
+
ExerciseCommand: {
|
|
599
|
+
templateId: 'SomePkg:Wrong.Module:WrongEntity',
|
|
600
|
+
choice: CANTON_CMD_CHOICE,
|
|
601
|
+
choiceArgument: {},
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
605
|
+
},
|
|
606
|
+
},
|
|
607
|
+
wallet: {},
|
|
608
|
+
})
|
|
609
|
+
.should.be.rejectedWith(/templateId mismatch/);
|
|
610
|
+
});
|
|
611
|
+
it('should throw on submitterInfo.actAs mismatch', async function () {
|
|
612
|
+
await basecoin
|
|
613
|
+
.verifyTransaction({
|
|
614
|
+
txPrebuild: { txHex },
|
|
615
|
+
txParams: {
|
|
616
|
+
cantonCommandParams: {
|
|
617
|
+
command: {
|
|
618
|
+
ExerciseCommand: {
|
|
619
|
+
templateId: CANTON_CMD_TEMPLATE_ID,
|
|
620
|
+
choice: CANTON_CMD_CHOICE,
|
|
621
|
+
choiceArgument: {},
|
|
622
|
+
},
|
|
623
|
+
},
|
|
624
|
+
actAs: ['WrongParty::1220aaaa'],
|
|
625
|
+
},
|
|
626
|
+
},
|
|
627
|
+
wallet: {},
|
|
628
|
+
})
|
|
629
|
+
.should.be.rejectedWith(/submitterInfo.actAs.*does not match user actAs/);
|
|
630
|
+
});
|
|
631
|
+
it('should throw on choice mismatch for ExerciseCommand', async function () {
|
|
632
|
+
await basecoin
|
|
633
|
+
.verifyTransaction({
|
|
634
|
+
txPrebuild: { txHex },
|
|
635
|
+
txParams: {
|
|
636
|
+
cantonCommandParams: {
|
|
637
|
+
command: {
|
|
638
|
+
ExerciseCommand: {
|
|
639
|
+
templateId: CANTON_CMD_TEMPLATE_ID,
|
|
640
|
+
choice: 'WrongChoice',
|
|
641
|
+
choiceArgument: {},
|
|
642
|
+
},
|
|
643
|
+
},
|
|
644
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
645
|
+
},
|
|
646
|
+
},
|
|
647
|
+
wallet: {},
|
|
648
|
+
})
|
|
649
|
+
.should.be.rejectedWith(/choice mismatch/);
|
|
650
|
+
});
|
|
651
|
+
it('should throw on contractId mismatch when user provides explicit contractId', async function () {
|
|
652
|
+
await basecoin
|
|
653
|
+
.verifyTransaction({
|
|
654
|
+
txPrebuild: { txHex },
|
|
655
|
+
txParams: {
|
|
656
|
+
cantonCommandParams: {
|
|
657
|
+
command: {
|
|
658
|
+
ExerciseCommand: {
|
|
659
|
+
templateId: CANTON_CMD_TEMPLATE_ID,
|
|
660
|
+
contractId: '00wrongcontractid',
|
|
661
|
+
choice: CANTON_CMD_CHOICE,
|
|
662
|
+
choiceArgument: {},
|
|
663
|
+
},
|
|
664
|
+
},
|
|
665
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
wallet: {},
|
|
669
|
+
})
|
|
670
|
+
.should.be.rejectedWith(/contractId mismatch/);
|
|
671
|
+
});
|
|
672
|
+
it('should throw on argument deep mismatch', async function () {
|
|
673
|
+
await basecoin
|
|
674
|
+
.verifyTransaction({
|
|
675
|
+
txPrebuild: { txHex },
|
|
676
|
+
txParams: {
|
|
677
|
+
cantonCommandParams: {
|
|
678
|
+
command: {
|
|
679
|
+
ExerciseCommand: {
|
|
680
|
+
templateId: CANTON_CMD_TEMPLATE_ID,
|
|
681
|
+
choice: CANTON_CMD_CHOICE,
|
|
682
|
+
choiceArgument: {
|
|
683
|
+
expectedAdmin: 'WrongParty::totally-different',
|
|
684
|
+
},
|
|
685
|
+
},
|
|
686
|
+
},
|
|
687
|
+
actAs: [CANTON_CMD_ACT_AS],
|
|
688
|
+
},
|
|
689
|
+
},
|
|
690
|
+
wallet: {},
|
|
691
|
+
})
|
|
692
|
+
.should.be.rejectedWith(/mismatch/);
|
|
693
|
+
});
|
|
694
|
+
});
|
|
695
|
+
});
|
|
696
|
+
// --------------- CreateCommand verification tests ---------------
|
|
697
|
+
const CREATE_CMD_ACT_AS = 'RegProvider::1220508e54fb709dcb1a9b4096408ad415d2217d8881ad9034a9850752933ba88ad5';
|
|
698
|
+
const CREATE_CMD_TEMPLATE_ID = '7a75ef6e69f69395a4e60919e228528bb8f3881150ccfde3f31bcc73864b18ab:Utility.Registry.App.V0.Service.Provider:ProviderServiceRequest';
|
|
699
|
+
const CREATE_CMD_OPERATOR = 'RegOperator::1220508e54fb709dcb1a9b4096408ad415d2217d8881ad9034a9850752933ba88ad5';
|
|
700
|
+
describe('Canton verifyTransaction - CreateCommand:', function () {
|
|
701
|
+
let bitgo;
|
|
702
|
+
let basecoin;
|
|
703
|
+
before(function () {
|
|
704
|
+
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'mock' });
|
|
705
|
+
bitgo.safeRegister('canton', src_1.Canton.createInstance);
|
|
706
|
+
bitgo.safeRegister('tcanton', src_1.Tcanton.createInstance);
|
|
707
|
+
bitgo.initializeTestVars();
|
|
708
|
+
basecoin = bitgo.coin('tcanton');
|
|
709
|
+
});
|
|
710
|
+
describe('Happy path tests:', function () {
|
|
711
|
+
let txHex;
|
|
712
|
+
before(function () {
|
|
713
|
+
txHex = buildCantonCommandRawTx(resources_1.CantonCreateCommandPrepareResponse, 'test-create-cmd-001');
|
|
714
|
+
});
|
|
715
|
+
it('should return true for matching CreateCommand (templateId, createArguments, actAs)', async function () {
|
|
716
|
+
const result = await basecoin.verifyTransaction({
|
|
717
|
+
txPrebuild: { txHex },
|
|
718
|
+
txParams: {
|
|
719
|
+
cantonCommandParams: {
|
|
720
|
+
command: {
|
|
721
|
+
CreateCommand: {
|
|
722
|
+
templateId: CREATE_CMD_TEMPLATE_ID,
|
|
723
|
+
createArguments: {
|
|
724
|
+
operator: CREATE_CMD_OPERATOR,
|
|
725
|
+
provider: CREATE_CMD_ACT_AS,
|
|
726
|
+
},
|
|
727
|
+
},
|
|
728
|
+
},
|
|
729
|
+
actAs: [CREATE_CMD_ACT_AS],
|
|
730
|
+
readAs: [],
|
|
731
|
+
},
|
|
732
|
+
},
|
|
733
|
+
wallet: {},
|
|
734
|
+
});
|
|
735
|
+
result.should.equal(true);
|
|
736
|
+
});
|
|
737
|
+
it('should return true when createArguments is empty (no deep-compare)', async function () {
|
|
738
|
+
const result = await basecoin.verifyTransaction({
|
|
739
|
+
txPrebuild: { txHex },
|
|
740
|
+
txParams: {
|
|
741
|
+
cantonCommandParams: {
|
|
742
|
+
command: {
|
|
743
|
+
CreateCommand: {
|
|
744
|
+
templateId: CREATE_CMD_TEMPLATE_ID,
|
|
745
|
+
createArguments: {},
|
|
746
|
+
},
|
|
747
|
+
},
|
|
748
|
+
actAs: [CREATE_CMD_ACT_AS],
|
|
749
|
+
readAs: [],
|
|
750
|
+
},
|
|
751
|
+
},
|
|
752
|
+
wallet: {},
|
|
753
|
+
});
|
|
754
|
+
result.should.equal(true);
|
|
755
|
+
});
|
|
756
|
+
it('should return true with resolveContracts injectAs skipping createArguments field', async function () {
|
|
757
|
+
const result = await basecoin.verifyTransaction({
|
|
758
|
+
txPrebuild: { txHex },
|
|
759
|
+
txParams: {
|
|
760
|
+
cantonCommandParams: {
|
|
761
|
+
command: {
|
|
762
|
+
CreateCommand: {
|
|
763
|
+
templateId: CREATE_CMD_TEMPLATE_ID,
|
|
764
|
+
createArguments: {
|
|
765
|
+
operator: 'placeholder-operator-id',
|
|
766
|
+
provider: CREATE_CMD_ACT_AS,
|
|
767
|
+
},
|
|
768
|
+
},
|
|
769
|
+
},
|
|
770
|
+
actAs: [CREATE_CMD_ACT_AS],
|
|
771
|
+
readAs: [],
|
|
772
|
+
resolveContracts: [
|
|
773
|
+
{
|
|
774
|
+
templateId: 'some-template',
|
|
775
|
+
actAs: [CREATE_CMD_ACT_AS],
|
|
776
|
+
injectAs: 'command.CreateCommand.createArguments.operator',
|
|
777
|
+
},
|
|
778
|
+
],
|
|
779
|
+
},
|
|
780
|
+
},
|
|
781
|
+
wallet: {},
|
|
782
|
+
});
|
|
783
|
+
result.should.equal(true);
|
|
784
|
+
});
|
|
785
|
+
});
|
|
786
|
+
describe('Error cases:', function () {
|
|
787
|
+
let txHex;
|
|
788
|
+
before(function () {
|
|
789
|
+
txHex = buildCantonCommandRawTx(resources_1.CantonCreateCommandPrepareResponse, 'test-create-cmd-err');
|
|
790
|
+
});
|
|
791
|
+
it('should throw on templateId mismatch for CreateCommand', async function () {
|
|
792
|
+
await basecoin
|
|
793
|
+
.verifyTransaction({
|
|
794
|
+
txPrebuild: { txHex },
|
|
795
|
+
txParams: {
|
|
796
|
+
cantonCommandParams: {
|
|
797
|
+
command: {
|
|
798
|
+
CreateCommand: {
|
|
799
|
+
templateId: 'WrongPkg:Wrong.Module:WrongEntity',
|
|
800
|
+
createArguments: {},
|
|
801
|
+
},
|
|
802
|
+
},
|
|
803
|
+
actAs: [CREATE_CMD_ACT_AS],
|
|
804
|
+
},
|
|
805
|
+
},
|
|
806
|
+
wallet: {},
|
|
807
|
+
})
|
|
808
|
+
.should.be.rejectedWith(/templateId mismatch/);
|
|
809
|
+
});
|
|
810
|
+
it('should throw on createArguments deep mismatch', async function () {
|
|
811
|
+
await basecoin
|
|
812
|
+
.verifyTransaction({
|
|
813
|
+
txPrebuild: { txHex },
|
|
814
|
+
txParams: {
|
|
815
|
+
cantonCommandParams: {
|
|
816
|
+
command: {
|
|
817
|
+
CreateCommand: {
|
|
818
|
+
templateId: CREATE_CMD_TEMPLATE_ID,
|
|
819
|
+
createArguments: {
|
|
820
|
+
operator: 'WrongOperator::totally-different',
|
|
821
|
+
provider: CREATE_CMD_ACT_AS,
|
|
822
|
+
},
|
|
823
|
+
},
|
|
824
|
+
},
|
|
825
|
+
actAs: [CREATE_CMD_ACT_AS],
|
|
826
|
+
},
|
|
827
|
+
},
|
|
828
|
+
wallet: {},
|
|
829
|
+
})
|
|
830
|
+
.should.be.rejectedWith(/mismatch/);
|
|
831
|
+
});
|
|
832
|
+
it('should throw on actAs mismatch for CreateCommand', async function () {
|
|
833
|
+
await basecoin
|
|
834
|
+
.verifyTransaction({
|
|
835
|
+
txPrebuild: { txHex },
|
|
836
|
+
txParams: {
|
|
837
|
+
cantonCommandParams: {
|
|
838
|
+
command: {
|
|
839
|
+
CreateCommand: {
|
|
840
|
+
templateId: CREATE_CMD_TEMPLATE_ID,
|
|
841
|
+
createArguments: {},
|
|
842
|
+
},
|
|
843
|
+
},
|
|
844
|
+
actAs: ['WrongParty::1220aaaa'],
|
|
845
|
+
},
|
|
846
|
+
},
|
|
847
|
+
wallet: {},
|
|
848
|
+
})
|
|
849
|
+
.should.be.rejectedWith(/submitterInfo.actAs.*does not match user actAs/);
|
|
850
|
+
});
|
|
851
|
+
});
|
|
852
|
+
});
|
|
853
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FudG9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdGVzdC91bml0L2NhbnRvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLGtCQUFnQjtBQUNoQixpREFBK0M7QUFDL0MsbURBQStEO0FBQy9ELG1EQUErRTtBQUMvRSxpREFBNEM7QUFFNUMsbUNBQTZHO0FBRTdHLDRDQVVzQjtBQUV0Qjs7Ozs7R0FLRztBQUNILFNBQVMsNEJBQTRCLENBQ25DLGVBQXlELEVBQ3pELFNBQWlCO0lBRWpCLE1BQU0sSUFBSSxHQUFHO1FBQ1gsc0JBQXNCLEVBQUUsZUFBZTtRQUN2QyxNQUFNLEVBQUUsb0JBQW9CO1FBQzVCLG1CQUFtQixFQUFFLEVBQUU7UUFDdkIsZUFBZSxFQUFFLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRTtRQUNuQyxtQkFBbUIsRUFBRSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUU7UUFDbEMsWUFBWSxFQUFFLFNBQVM7UUFDdkIsb0JBQW9CLEVBQUUsMkJBQTJCO1FBQ2pELGFBQWEsRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRTtLQUN2QyxDQUFDO0lBQ0YsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDOUQsQ0FBQztBQUVELHlGQUF5RjtBQUN6RixTQUFTLHFCQUFxQixDQUFDLFdBQW1CO0lBQ2hELE9BQU8sRUFBRSxZQUFZLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxDQUFDLEVBQXdCLENBQUM7QUFDekUsQ0FBQztBQUVELGdHQUFnRztBQUNoRyxTQUFTLFVBQVUsQ0FBQyxNQUFjLEVBQUUsZUFBd0IsRUFBRSxTQUFpQjtJQUM3RSxNQUFNLElBQUksR0FBRztRQUNYLHNCQUFzQixFQUFFLGVBQWU7UUFDdkMsTUFB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QUM7UUFDeEMsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsa0RBQWtELEVBQUUsS0FBSztZQUMxRCxNQUFNLFFBQVE7aUJBQ1gsaUJBQWlCLENBQUM7Z0JBQ2pCLFVBQVUsRUFBRSxFQUFFLEtBQUssRUFBRTtnQkFDckIsUUFBUSxFQUFFO29CQUNSLG1CQUFtQixFQUFFO3dCQUNuQixPQUFPLEVBQUU7NEJBQ1AsYUFBYSxFQUFFO2dDQUNiLFVBQVUsRUFBRSxzQkFBc0I7Z0NBQ2xDLGVBQWUsRUFBRSxFQUFFOzZCQUNwQjt5QkFDRjt3QkFDRCxLQUFLLEVBQUUsQ0FBQyxzQkFBc0IsQ0FBQztxQkFDaEM7aUJBQ3lCO2dCQUM1QixNQUFNLEVBQUUsRUFBYTthQUN0QixDQUFDO2lCQUNELE1BQU0sQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLGdEQUFnRCxDQUFDLENBQUM7UUFDOUUsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICdzaG91bGQnO1xuaW1wb3J0IHsgQml0R29BUEkgfSBmcm9tICdAYml0Z28tYmV0YS9zZGstYXBpJztcbmltcG9ydCB7IFRlc3RCaXRHbywgVGVzdEJpdEdvQVBJIH0gZnJvbSAnQGJpdGdvLWJldGEvc2RrLXRlc3QnO1xuaW1wb3J0IHsgQ2FudG9uQ29tbWFuZCwgSVdhbGxldCwgVHJhbnNhY3Rpb25UeXBlIH0gZnJvbSAnQGJpdGdvLWJldGEvc2RrLWNvcmUnO1xuaW1wb3J0IHsgY29pbnMgfSBmcm9tICdAYml0Z28tYmV0YS9zdGF0aWNzJztcblxuaW1wb3J0IHsgQ2FudG9uLCBDYW50b25UcmFuc2FjdGlvblBhcmFtcywgVGNhbnRvbiwgVHJhbnNhY3Rpb24sIFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkgfSBmcm9tICcuLi8uLi9zcmMnO1xuaW1wb3J0IHsgQ2FudG9uUHJlcGFyZUNvbW1hbmRSZXNwb25zZSB9IGZyb20gJy4uLy4uL3NyYy9saWIvaWZhY2UnO1xuaW1wb3J0IHtcbiAgQWxsb2NhdGlvblJlamVjdGlvbixcbiAgQ2FudG9uQWxsb2NhdGlvblJlamVjdFByZXBhcmVSZXNwb25zZSxcbiAgQ2FudG9uRXhlcmNpc2VDb21tYW5kUHJlcGFyZVJlc3BvbnNlLFxuICBDYW50b25DcmVhdGVDb21tYW5kUHJlcGFyZVJlc3BvbnNlLFxuICBDYW50b25Ub2tlblByZUFwcHJvdmFsUHJlcGFyZVJlc3BvbnNlLFxuICBDYW5jZWxQYXJ0eSxcbiAgT25lU3RlcEVuYWJsZW1lbnQsXG4gIE9uZVN0ZXBQcmVBcHByb3ZhbFByZXBhcmVSZXNwb25zZSxcbiAgVHJhbnNmZXJQcmVhcHByb3ZhbENhbmNlbFByZXBhcmVSZXNwb25zZSxcbn0gZnJvbSAnLi4vcmVzb3VyY2VzJztcblxuLyoqXG4gKiBCdWlsZHMgYSBiYXNlNjQtZW5jb2RlZCByYXcgdHJhbnNhY3Rpb24gZm9yIGEgT25lU3RlcFByZUFwcHJvdmFsIChlbmFibGUgdG9rZW4gZmxvdykuXG4gKiBGb3IgVFNTIHdhbGxldHMgKHdoaWNoIENhbnRvbiBhbHdheXMgaXMpLCB2ZXJpZnlUcmFuc2FjdGlvbiByZWNlaXZlcyB0eFBhcmFtcy5lbmFibGVUb2tlbnMsXG4gKiBub3QgdHhQYXJhbXMucmVjaXBpZW50cy4gVGhlIHdhbGxldCBTREsncyBidWlsZFRva2VuRW5hYmxlbWVudHMgcGFzc2VzIGVuYWJsZVRva2VucyB0aHJvdWdoXG4gKiB1bmNoYW5nZWQgZm9yIFRTUyB3YWxsZXRzIHJhdGhlciB0aGFuIGNvbnZlcnRpbmcgdGhlbSB0byByZWNpcGllbnRzLlxuICovXG5mdW5jdGlvbiBidWlsZE9uZVN0ZXBQcmVBcHByb3ZhbFJhd1R4KFxuICBwcmVwYXJlUmVzcG9uc2U6IHR5cGVvZiBPbmVTdGVwUHJlQXBwcm92YWxQcmVwYXJlUmVzcG9uc2UsXG4gIGNvbW1hbmRJZDogc3RyaW5nXG4pOiBzdHJpbmcge1xuICBjb25zdCBkYXRhID0ge1xuICAgIHByZXBhcmVDb21tYW5kUmVzcG9uc2U6IHByZXBhcmVSZXNwb25zZSxcbiAgICB0eFR5cGU6ICdPbmVTdGVwUHJlQXBwcm92YWwnLFxuICAgIHByZXBhcmVkVHJhbnNhY3Rpb246ICcnLFxuICAgIHBhcnR5U2lnbmF0dXJlczogeyBzaWduYXR1cmVzOiBbXSB9LFxuICAgIGRlZHVwbGljYXRpb25QZXJpb2Q6IHsgRW1wdHk6IHt9IH0sXG4gICAgc3VibWlzc2lvbklkOiBjb21tYW5kSWQsXG4gICAgaGFzaGluZ1NjaGVtZVZlcnNpb246ICdIQVNISU5HX1NDSEVNRV9WRVJTSU9OX1YyJyxcbiAgICBtaW5MZWRnZXJUaW1lOiB7IHRpbWU6IHsgRW1wdHk6IHt9IH0gfSxcbiAgfTtcbiAgcmV0dXJuIEJ1ZmZlci5mcm9tKEpTT04uc3RyaW5naWZ5KGRhdGEpKS50b1N0cmluZygnYmFzZTY0Jyk7XG59XG5cbi8qKiBSZXR1cm5zIGEgbW9jayB3YWxsZXQgd2hvc2UgY29pblNwZWNpZmljKCkucm9vdEFkZHJlc3MgbWF0Y2hlcyB0aGUgZ2l2ZW4gcGFydHkgSUQuICovXG5mdW5jdGlvbiB3YWxsZXRXaXRoUm9vdEFkZHJlc3Mocm9vdEFkZHJlc3M6IHN0cmluZyk6IElXYWxsZXQge1xuICByZXR1cm4geyBjb2luU3BlY2lmaWM6ICgpID0+ICh7IHJvb3RBZGRyZXNzIH0pIH0gYXMgdW5rbm93biBhcyBJV2FsbGV0O1xufVxuXG4vKiogQnVpbGRzIGEgYmFzZTY0LWVuY29kZWQgcmF3IHRyYW5zYWN0aW9uIGZvciBhIG5vbi1PbmVTdGVwIHR4VHlwZSAoZS5nLiBBbGxvY2F0aW9uUmVqZWN0KS4gKi9cbmZ1bmN0aW9uIGJ1aWxkUmF3VHgodHhUeXBlOiBzdHJpbmcsIHByZXBhcmVSZXNwb25zZTogdW5rbm93biwgY29tbWFuZElkOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBkYXRhID0ge1xuICAgIHByZXBhcmVDb21tYW5kUmVzcG9uc2U6IHByZXBhcmVSZXNwb25zZSxcbiAgICB0eFR5cGUsXG4gICAgcHJlcGFyZWRUcmFuc2FjdGlvbjogJycsXG4gICAgcGFydHlTaWduYXR1cmVzOiB7IHNpZ25hdHVyZXM6IFtdIH0sXG4gICAgZGVkdXBsaWNhdGlvblBlcmlvZDogeyBFbXB0eToge30gfSxcbiAgICBzdWJtaXNzaW9uSWQ6IGNvbW1hbmRJZCxcbiAgICBoYXNoaW5nU2NoZW1lVmVyc2lvbjogJ0hBU0hJTkdfU0NIRU1FX1ZFUlNJT05fVjInLFxuICAgIG1pbkxlZGdlclRpbWU6IHsgdGltZTogeyBFbXB0eToge30gfSB9LFxuICB9O1xuICByZXR1cm4gQnVmZmVyLmZyb20oSlNPTi5zdHJpbmdpZnkoZGF0YSkpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbn1cblxuZGVzY3JpYmUoJ0NhbnRvbiBjb2luOicsIGZ1bmN0aW9uICgpIHtcbiAgbGV0IGJpdGdvOiBUZXN0Qml0R29BUEk7XG4gIGxldCBiYXNlY29pbjogQ2FudG9uO1xuXG4gIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgYml0Z28gPSBUZXN0Qml0R28uZGVjb3JhdGUoQml0R29BUEksIHsgZW52OiAnbW9jaycgfSk7XG4gICAgYml0Z28uc2FmZVJlZ2lzdGVyKCdjYW50b24nLCBDYW50b24uY3JlYXRlSW5zdGFuY2UpO1xuICAgIGJpdGdvLnNhZmVSZWdpc3RlcigndGNhbnRvbicsIFRjYW50b24uY3JlYXRlSW5zdGFuY2UpO1xuICAgIGJpdGdvLmluaXRpYWxpemVUZXN0VmFycygpO1xuICAgIGJhc2Vjb2luID0gYml0Z28uY29pbigndGNhbnRvbicpIGFzIENhbnRvbjtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ3N1cHBvcnRzTWVzc2FnZVNpZ25pbmcnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gdHJ1ZScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGJhc2Vjb2luLnN1cHBvcnRzTWVzc2FnZVNpZ25pbmcoKS5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKCdDYW50b24gdmVyaWZ5VHJhbnNhY3Rpb246JywgZnVuY3Rpb24gKCkge1xuICBsZXQgYml0Z286IFRlc3RCaXRHb0FQSTtcbiAgbGV0IGJhc2Vjb2luOiBDYW50b247XG5cbiAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICBiaXRnbyA9IFRlc3RCaXRHby5kZWNvcmF0ZShCaXRHb0FQSSwgeyBlbnY6ICdtb2NrJyB9KTtcbiAgICBiaXRnby5zYWZlUmVnaXN0ZXIoJ2NhbnRvbicsIENhbnRvbi5jcmVhdGVJbnN0YW5jZSk7XG4gICAgYml0Z28uc2FmZVJlZ2lzdGVyKCd0Y2FudG9uJywgVGNhbnRvbi5jcmVhdGVJbnN0YW5jZSk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgYmFzZWNvaW4gPSBiaXRnby5jb2luKCd0Y2FudG9uJykgYXMgQ2FudG9uO1xuICB9KTtcblxuICBkZXNjcmliZSgnT25lU3RlcFByZUFwcHJvdmFsIChlbmFibGUgdG9rZW4gZmxvdyk6JywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgd2hlbiB0eFBhcmFtcyBoYXMgbm8gdHlwZSAobm9uLWVuYWJsZXRva2VuIGZsb3cpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhIZXggPSBidWlsZE9uZVN0ZXBQcmVBcHByb3ZhbFJhd1R4KE9uZVN0ZXBQcmVBcHByb3ZhbFByZXBhcmVSZXNwb25zZSwgT25lU3RlcEVuYWJsZW1lbnQuY29tbWFuZElkKTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICB0eFBhcmFtczoge30sXG4gICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgfSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gdHJ1ZSB3aGVuIGVuYWJsZVRva2VucyBpcyBhYnNlbnQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eEhleCA9IGJ1aWxkT25lU3RlcFByZUFwcHJvdmFsUmF3VHgoT25lU3RlcFByZUFwcHJvdmFsUHJlcGFyZVJlc3BvbnNlLCBPbmVTdGVwRW5hYmxlbWVudC5jb21tYW5kSWQpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0sXG4gICAgICAgIHR4UGFyYW1zOiB7IHR5cGU6ICdlbmFibGV0b2tlbicgfSxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIHdoZW4gZW5hYmxlVG9rZW5zIGlzIGVtcHR5JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhIZXggPSBidWlsZE9uZVN0ZXBQcmVBcHByb3ZhbFJhd1R4KE9uZVN0ZXBQcmVBcHByb3ZhbFByZXBhcmVSZXNwb25zZSwgT25lU3RlcEVuYWJsZW1lbnQuY29tbWFuZElkKTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICB0eFBhcmFtczogeyB0eXBlOiAnZW5hYmxldG9rZW4nLCBlbmFibGVUb2tlbnM6IFtdIH0sXG4gICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgfSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ2NvaW4gcHJlLWFwcHJvdmFsIChUcmFuc2ZlclByZWFwcHJvdmFsUHJvcG9zYWwpOicsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCB0eEhleDogc3RyaW5nO1xuICAgICAgbGV0IHJlY2VpdmVyOiBzdHJpbmc7XG5cbiAgICAgIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgICAgIHR4SGV4ID0gYnVpbGRPbmVTdGVwUHJlQXBwcm92YWxSYXdUeChPbmVTdGVwUHJlQXBwcm92YWxQcmVwYXJlUmVzcG9uc2UsIE9uZVN0ZXBFbmFibGVtZW50LmNvbW1hbmRJZCk7XG4gICAgICAgIC8vIER5bmFtaWNhbGx5IGRlcml2ZSByZWNlaXZlciBmcm9tIHBhcnNlZCB0cmFuc2FjdGlvbiB0byBhdm9pZCBoYXJkY29kaW5nIHByb3RvYnVmLWRlY29kZWQgYWRkcmVzc2VzXG4gICAgICAgIGNvbnN0IHR4QnVpbGRlciA9IG5ldyBUcmFuc2FjdGlvbkJ1aWxkZXJGYWN0b3J5KGNvaW5zLmdldCgndGNhbnRvbicpKS5mcm9tKHR4SGV4KTtcbiAgICAgICAgcmVjZWl2ZXIgPSAodHhCdWlsZGVyLnRyYW5zYWN0aW9uIGFzIGFueSkudG9Kc29uKCkucmVjZWl2ZXIgYXMgc3RyaW5nO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgd2hlbiB3YWxsZXQgaGFzIG5vIGNvaW5TcGVjaWZpYyAocmVjZWl2ZXIgY2hlY2sgc2tpcHBlZCknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIFR5cGljYWwgY2FzZTogd2FsbGV0IG1vY2sgaGFzIG5vIGNvaW5TcGVjaWZpYygpIG1ldGhvZCwgYW5kIG5vIGFkZHJlc3MgaW4gZW5hYmxlVG9rZW5zXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0sXG4gICAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICAgIHR5cGU6ICdlbmFibGV0b2tlbicsXG4gICAgICAgICAgICBlbmFibGVUb2tlbnM6IFt7IG5hbWU6ICdjYW50b24nIH1dLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICAgIH0pO1xuICAgICAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgd2hlbiB3YWxsZXQgcm9vdEFkZHJlc3MgbWF0Y2hlcyByZWNlaXZlcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gVHlwaWNhbCBVSSBmbG93OiBlbmFibGVUb2tlbnMgaGFzIG5vIGFkZHJlc3MsIHJlY2VpdmVyIHZhbGlkYXRlZCBmcm9tIHdhbGxldC5jb2luU3BlY2lmaWMoKS5yb290QWRkcmVzc1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgICB0eXBlOiAnZW5hYmxldG9rZW4nLFxuICAgICAgICAgICAgZW5hYmxlVG9rZW5zOiBbeyBuYW1lOiAnY2FudG9uJyB9XSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHdhbGxldDogd2FsbGV0V2l0aFJvb3RBZGRyZXNzKHJlY2VpdmVyKSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCByZXR1cm4gdHJ1ZSB3aGVuIGVuYWJsZVRva2VuLmFkZHJlc3MgbWF0Y2hlcyByZWNlaXZlciAoZXhwbGljaXQgYWRkcmVzcyknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0sXG4gICAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICAgIHR5cGU6ICdlbmFibGV0b2tlbicsXG4gICAgICAgICAgICBlbmFibGVUb2tlbnM6IFt7IG5hbWU6ICdjYW50b24nLCBhZGRyZXNzOiByZWNlaXZlciB9XSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgICB9KTtcbiAgICAgICAgcmVzdWx0LnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHRocm93IHdoZW4gd2FsbGV0IHJvb3RBZGRyZXNzIGRvZXMgbm90IG1hdGNoIHJlY2VpdmVyJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCB3cm9uZ0FkZHJlc3MgPSAnd3JvbmctcGFydHk6OjEyMjBhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhJztcbiAgICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgICAgZW5hYmxlVG9rZW5zOiBbeyBuYW1lOiAnY2FudG9uJyB9XSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB3YWxsZXQ6IHdhbGxldFdpdGhSb290QWRkcmVzcyh3cm9uZ0FkZHJlc3MpLFxuICAgICAgICAgIH0pXG4gICAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL09uZVN0ZXBQcmVBcHByb3ZhbCByZWNlaXZlciBtaXNtYXRjaC8pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgdGhyb3cgd2hlbiBleHBsaWNpdCBlbmFibGVUb2tlbi5hZGRyZXNzIGRvZXMgbm90IG1hdGNoIHJlY2VpdmVyJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCB3cm9uZ0FkZHJlc3MgPSAnd3JvbmctcGFydHk6OjEyMjBhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhJztcbiAgICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgICAgZW5hYmxlVG9rZW5zOiBbeyBuYW1lOiAnY2FudG9uJywgYWRkcmVzczogd3JvbmdBZGRyZXNzIH1dLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHdhbGxldDoge30gYXMgYW55LFxuICAgICAgICAgIH0pXG4gICAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL09uZVN0ZXBQcmVBcHByb3ZhbCByZWNlaXZlciBtaXNtYXRjaC8pO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgndG9rZW4gcHJlLWFwcHJvdmFsIChUcmFuc2ZlclByZWFwcHJvdmFsKTonLCBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgdHhIZXg6IHN0cmluZztcbiAgICAgIGxldCByZWNlaXZlcjogc3RyaW5nO1xuXG4gICAgICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBjb21tYW5kSWQgPSAnN2Q5OTc4OWQtMmYyMi00OWUxLTg1Y2ItNzlkMmNlNWE2OWMxJztcbiAgICAgICAgdHhIZXggPSBidWlsZE9uZVN0ZXBQcmVBcHByb3ZhbFJhd1R4KENhbnRvblRva2VuUHJlQXBwcm92YWxQcmVwYXJlUmVzcG9uc2UsIGNvbW1hbmRJZCk7XG4gICAgICAgIGNvbnN0IHR4QnVpbGRlciA9IG5ldyBUcmFuc2FjdGlvbkJ1aWxkZXJGYWN0b3J5KGNvaW5zLmdldCgndGNhbnRvbicpKS5mcm9tKHR4SGV4KTtcbiAgICAgICAgcmVjZWl2ZXIgPSAodHhCdWlsZGVyLnRyYW5zYWN0aW9uIGFzIGFueSkudG9Kc29uKCkucmVjZWl2ZXIgYXMgc3RyaW5nO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgd2hlbiB3YWxsZXQgcm9vdEFkZHJlc3MgbWF0Y2hlcyByZWNlaXZlcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgIGVuYWJsZVRva2VuczogW3sgbmFtZTogJ3RjYW50b246dGVzdGNvaW4xJyB9XSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHdhbGxldDogd2FsbGV0V2l0aFJvb3RBZGRyZXNzKHJlY2VpdmVyKSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCByZXR1cm4gdHJ1ZSB3aGVuIGVuYWJsZVRva2VuLmFkZHJlc3MgbWF0Y2hlcyByZWNlaXZlciAoZXhwbGljaXQgYWRkcmVzcyknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0sXG4gICAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICAgIHR5cGU6ICdlbmFibGV0b2tlbicsXG4gICAgICAgICAgICBlbmFibGVUb2tlbnM6IFt7IG5hbWU6ICd0Y2FudG9uOnRlc3Rjb2luMScsIGFkZHJlc3M6IHJlY2VpdmVyIH1dLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICAgIH0pO1xuICAgICAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgdGhyb3cgd2hlbiB3YWxsZXQgcm9vdEFkZHJlc3MgZG9lcyBub3QgbWF0Y2ggcmVjZWl2ZXInLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHdyb25nQWRkcmVzcyA9ICd3cm9uZy1wYXJ0eTo6MTIyMGJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiJztcbiAgICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgICAgZW5hYmxlVG9rZW5zOiBbeyBuYW1lOiAndGNhbnRvbjp0ZXN0Y29pbjEnIH1dLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHdhbGxldDogd2FsbGV0V2l0aFJvb3RBZGRyZXNzKHdyb25nQWRkcmVzcyksXG4gICAgICAgICAgfSlcbiAgICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvT25lU3RlcFByZUFwcHJvdmFsIHJlY2VpdmVyIG1pc21hdGNoLyk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIGV4cGxpY2l0IGVuYWJsZVRva2VuLmFkZHJlc3MgZG9lcyBub3QgbWF0Y2ggcmVjZWl2ZXInLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHdyb25nQWRkcmVzcyA9ICd3cm9uZy1wYXJ0eTo6MTIyMGJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiJztcbiAgICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICAgICAgdHlwZTogJ2VuYWJsZXRva2VuJyxcbiAgICAgICAgICAgICAgZW5hYmxlVG9rZW5zOiBbeyBuYW1lOiAndGNhbnRvbjp0ZXN0Y29pbjEnLCBhZGRyZXNzOiB3cm9uZ0FkZHJlc3MgfV0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgd2FsbGV0OiB7fSBhcyBhbnksXG4gICAgICAgICAgfSlcbiAgICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvT25lU3RlcFByZUFwcHJvdmFsIHJlY2VpdmVyIG1pc21hdGNoLyk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ1RyYW5zZmVyUHJlYXBwcm92YWxDYW5jZWwgKGRpc2FibGUgdG9rZW4gZmxvdyk6JywgZnVuY3Rpb24gKCkge1xuICAgIC8vIFJlYWwgY2FwdHVyZWQgVHJhbnNmZXJQcmVhcHByb3ZhbF9DYW5jZWwgZXhlcmNpc2Utbm9kZSBmaXh0dXJlOiBwYXJzZWQgc2VuZGVyID09PSByZWNlaXZlclxuICAgIC8vID09PSBDYW5jZWxQYXJ0eSwgbWF0Y2hpbmcgdGhlIGFjdHVhbCBvbi1jaGFpbiBjaG9pY2UvYWN0aW5nUGFydGllcyBzaGFwZS5cbiAgICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIHdoZW4gdHhQYXJhbXMgaGFzIG5vIHR5cGUgKG5vbi1kaXNhYmxldG9rZW4gZmxvdyknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eEhleCA9IGJ1aWxkUmF3VHgoXG4gICAgICAgICdUcmFuc2ZlclByZWFwcHJvdmFsQ2FuY2VsJyxcbiAgICAgICAgVHJhbnNmZXJQcmVhcHByb3ZhbENhbmNlbFByZXBhcmVSZXNwb25zZSxcbiAgICAgICAgT25lU3RlcEVuYWJsZW1lbnQuY29tbWFuZElkXG4gICAgICApO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0sXG4gICAgICAgIHR4UGFyYW1zOiB7fSxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyB1bmtub3duIGFzIElXYWxsZXQsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIHdoZW4gZW5hYmxlVG9rZW5zIGlzIGFic2VudCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4SGV4ID0gYnVpbGRSYXdUeChcbiAgICAgICAgJ1RyYW5zZmVyUHJlYXBwcm92YWxDYW5jZWwnLFxuICAgICAgICBUcmFuc2ZlclByZWFwcHJvdmFsQ2FuY2VsUHJlcGFyZVJlc3BvbnNlLFxuICAgICAgICBPbmVTdGVwRW5hYmxlbWVudC5jb21tYW5kSWRcbiAgICAgICk7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgdHhQYXJhbXM6IHsgdHlwZTogJ2Rpc2FibGV0b2tlbicgfSxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBJV2FsbGV0LFxuICAgICAgfSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gdHJ1ZSB3aGVuIGVuYWJsZVRva2VucyBpcyBlbXB0eScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4SGV4ID0gYnVpbGRSYXdUeChcbiAgICAgICAgJ1RyYW5zZmVyUHJlYXBwcm92YWxDYW5jZWwnLFxuICAgICAgICBUcmFuc2ZlclByZWFwcHJvdmFsQ2FuY2VsUHJlcGFyZVJlc3BvbnNlLFxuICAgICAgICBPbmVTdGVwRW5hYmxlbWVudC5jb21tYW5kSWRcbiAgICAgICk7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgdHhQYXJhbXM6IHsgdHlwZTogJ2Rpc2FibGV0b2tlbicsIGVuYWJsZVRva2VuczogW10gfSxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBJV2FsbGV0LFxuICAgICAgfSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gdHJ1ZSB3aGVuIHdhbGxldCBoYXMgbm8gY29pblNwZWNpZmljIGFuZCBubyBleHBsaWNpdCBhZGRyZXNzIChyZWNlaXZlciBjaGVjayBza2lwcGVkKScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4SGV4ID0gYnVpbGRSYXdUeChcbiAgICAgICAgJ1RyYW5zZmVyUHJlYXBwcm92YWxDYW5jZWwnLFxuICAgICAgICBUcmFuc2ZlclByZWFwcHJvdmFsQ2FuY2VsUHJlcGFyZVJlc3BvbnNlLFxuICAgICAgICBPbmVTdGVwRW5hYmxlbWVudC5jb21tYW5kSWRcbiAgICAgICk7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICB0eXBlOiAnZGlzYWJsZXRva2VuJyxcbiAgICAgICAgICBlbmFibGVUb2tlbnM6IFt7IG5hbWU6ICdjYW50b24nIH1dLFxuICAgICAgICB9LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIElXYWxsZXQsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIHdoZW4gd2FsbGV0IHJvb3RBZGRyZXNzIG1hdGNoZXMgdGhlIHBhcnNlZCByZWNlaXZlcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4SGV4ID0gYnVpbGRSYXdUeChcbiAgICAgICAgJ1RyYW5zZmVyUHJlYXBwcm92YWxDYW5jZWwnLFxuICAgICAgICBUcmFuc2ZlclByZWFwcHJvdmFsQ2FuY2VsUHJlcGFyZVJlc3BvbnNlLFxuICAgICAgICBPbmVTdGVwRW5hYmxlbWVudC5jb21tYW5kSWRcbiAgICAgICk7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICB0eXBlOiAnZGlzYWJsZXRva2VuJyxcbiAgICAgICAgICBlbmFibGVUb2tlbnM6IFt7IG5hbWU6ICdjYW50b24nIH1dLFxuICAgICAgICB9LFxuICAgICAgICB3YWxsZXQ6IHdhbGxldFdpdGhSb290QWRkcmVzcyhDYW5jZWxQYXJ0eSksXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIHdoZW4gZXhwbGljaXQgZW5hYmxlVG9rZW4uYWRkcmVzcyBtYXRjaGVzIHRoZSBwYXJzZWQgcmVjZWl2ZXInLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eEhleCA9IGJ1aWxkUmF3VHgoXG4gICAgICAgICdUcmFuc2ZlclByZWFwcHJvdmFsQ2FuY2VsJyxcbiAgICAgICAgVHJhbnNmZXJQcmVhcHByb3ZhbENhbmNlbFByZXBhcmVSZXNwb25zZSxcbiAgICAgICAgT25lU3RlcEVuYWJsZW1lbnQuY29tbWFuZElkXG4gICAgICApO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0sXG4gICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgdHlwZTogJ2Rpc2FibGV0b2tlbicsXG4gICAgICAgICAgZW5hYmxlVG9rZW5zOiBbeyBuYW1lOiAnY2FudG9uJywgYWRkcmVzczogQ2FuY2VsUGFydHkgfV0sXG4gICAgICAgIH0sXG4gICAgICAgIHdhbGxldDoge30gYXMgSVdhbGxldCxcbiAgICAgIH0pO1xuICAgICAgcmVzdWx0LnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgd2hlbiB3YWxsZXQgcm9vdEFkZHJlc3MgZG9lcyBub3QgbWF0Y2ggdGhlIHBhcnNlZCByZWNlaXZlcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4SGV4ID0gYnVpbGRSYXdUeChcbiAgICAgICAgJ1RyYW5zZmVyUHJlYXBwcm92YWxDYW5jZWwnLFxuICAgICAgICBUcmFuc2ZlclByZWFwcHJvdmFsQ2FuY2VsUHJlcGFyZVJlc3BvbnNlLFxuICAgICAgICBPbmVTdGVwRW5hYmxlbWVudC5jb21tYW5kSWRcbiAgICAgICk7XG4gICAgICBjb25zdCBzb21lQWRkcmVzcyA9ICdzb21lLXBhcnR5OjoxMjIwYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYSc7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgdHlwZTogJ2Rpc2FibGV0b2tlbicsXG4gICAgICAgICAgICBlbmFibGVUb2tlbnM6IFt7IG5hbWU6ICdjYW50b24nIH1dLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgd2FsbGV0OiB3YWxsZXRXaXRoUm9vdEFkZHJlc3Moc29tZUFkZHJlc3MpLFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvVHJhbnNmZXJQcmVhcHByb3ZhbENhbmNlbCByZWNlaXZlciBtaXNtYXRjaC8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIGV4cGxpY2l0IGVuYWJsZVRva2VuLmFkZHJlc3MgZG9lcyBub3QgbWF0Y2ggdGhlIHBhcnNlZCByZWNlaXZlcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4SGV4ID0gYnVpbGRSYXdUeChcbiAgICAgICAgJ1RyYW5zZmVyUHJlYXBwcm92YWxDYW5jZWwnLFxuICAgICAgICBUcmFuc2ZlclByZWFwcHJvdmFsQ2FuY2VsUHJlcGFyZVJlc3BvbnNlLFxuICAgICAgICBPbmVTdGVwRW5hYmxlbWVudC5jb21tYW5kSWRcbiAgICAgICk7XG4gICAgICBjb25zdCBzb21lQWRkcmVzcyA9ICdzb21lLXBhcnR5OjoxMjIwYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYSc7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgdHlwZTogJ2Rpc2FibGV0b2tlbicsXG4gICAgICAgICAgICBlbmFibGVUb2tlbnM6IFt7IG5hbWU6ICdjYW50b24nLCBhZGRyZXNzOiBzb21lQWRkcmVzcyB9XSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHdhbGxldDoge30gYXMgSVdhbGxldCxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL1RyYW5zZmVyUHJlYXBwcm92YWxDYW5jZWwgcmVjZWl2ZXIgbWlzbWF0Y2gvKTtcbiAgICB9KTtcbiAgfSk7XG59KTtcblxuZGVzY3JpYmUoJ0NhbnRvbiB2ZXJpZnlUcmFuc2FjdGlvbiAtIEFsbG9jYXRpb25SZWplY3Q6JywgZnVuY3Rpb24gKCkge1xuICBsZXQgYml0Z286IFRlc3RCaXRHb0FQSTtcbiAgbGV0IGJhc2Vjb2luOiBDYW50b247XG5cbiAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICBiaXRnbyA9IFRlc3RCaXRHby5kZWNvcmF0ZShCaXRHb0FQSSwgeyBlbnY6ICdtb2NrJyB9KTtcbiAgICBiaXRnby5zYWZlUmVnaXN0ZXIoJ2NhbnRvbicsIENhbnRvbi5jcmVhdGVJbnN0YW5jZSk7XG4gICAgYml0Z28uc2FmZVJlZ2lzdGVyKCd0Y2FudG9uJywgVGNhbnRvbi5jcmVhdGVJbnN0YW5jZSk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgYmFzZWNvaW4gPSBiaXRnby5jb2luKCd0Y2FudG9uJykgYXMgQ2FudG9uO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIGZvciBhbiBBbGxvY2F0aW9uUmVqZWN0IHRyYW5zYWN0aW9uIChubyByZWNpcGllbnQgaW5mbyB0byB2ZXJpZnkpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IHR4SGV4ID0gYnVpbGRSYXdUeCgnQWxsb2NhdGlvblJlamVjdCcsIENhbnRvbkFsbG9jYXRpb25SZWplY3RQcmVwYXJlUmVzcG9uc2UsIEFsbG9jYXRpb25SZWplY3Rpb24uY29tbWFuZElkKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0sXG4gICAgICB0eFBhcmFtczoge30sXG4gICAgICB3YWxsZXQ6IHt9IGFzIGFueSxcbiAgICB9KTtcbiAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZSgnQ2FudG9uIGV4cGxhaW5UcmFuc2FjdGlvbiAtIEFsbG9jYXRpb25SZWplY3Q6JywgZnVuY3Rpb24gKCkge1xuICBpdCgnc2hvdWxkIHJldHVybiBhbiBlbXB0eSBleHBsYW5hdGlvbiAobm8gZnVuZHMgbW92ZSBvbiBhbiBBbGxvY2F0aW9uUmVxdWVzdCByZWplY3QpJywgZnVuY3Rpb24gKCkge1xuICAgIC8vIEFsbG9jYXRpb25SZXF1ZXN0X1JlamVjdCBmaXJlcyBiZWZvcmUgdGhlIGFjdG9yIGhhcyBhbGxvY2F0ZWQgdGhlaXIgbGVnIOKAlCBubyBIb2xkaW5nXG4gICAgLy8gd2FzIGV2ZXIgbG9ja2VkIGZvciB0aGlzIHRyYWRlLCBzbyBub3RoaW5nIGlzIHJldHVybmVkLiBVbmxpa2UgVHJhbnNmZXJSZWplY3QgKHdoaWNoXG4gICAgLy8gdW53aW5kcyBhIHJlYWwgZnVuZCBtb3ZlbWVudCksIHRoaXMgaXMgYSBwdXJlIFwiZGVjbGluZSB0byB0cmFkZVwiIHNpZ25hbCB3aXRoIG5vXG4gICAgLy8gYmFsYW5jZSBpbXBhY3QsIHNvIGl0IGludGVudGlvbmFsbHkgZmFsbHMgdGhyb3VnaCB0byB0aGUgZGVmYXVsdCAoZW1wdHkpIGV4cGxhbmF0aW9uXG4gICAgLy8gcmF0aGVyIHRoYW4gYmVpbmcgcmVwb3J0ZWQgYXMgYW4gaW5wdXQuXG4gICAgY29uc3QgdHggPSBuZXcgVHJhbnNhY3Rpb24oY29pbnMuZ2V0KCd0Y2FudG9uJykpO1xuICAgIHR4LmlkID0gQWxsb2NhdGlvblJlamVjdGlvbi5jb21tYW5kSWQ7XG4gICAgdHgudHJhbnNhY3Rpb25UeXBlID0gVHJhbnNhY3Rpb25UeXBlLkFsbG9jYXRpb25SZWplY3Q7XG4gICAgdHgucHJlcGFyZUNvbW1hbmQgPSBDYW50b25BbGxvY2F0aW9uUmVqZWN0UHJlcGFyZVJlc3BvbnNlO1xuXG4gICAgY29uc3QgZXhwbGFuYXRpb24gPSB0eC5leHBsYWluVHJhbnNhY3Rpb24oKTtcblxuICAgIGV4cGxhbmF0aW9uLmlucHV0cyEubGVuZ3RoLnNob3VsZC5lcXVhbCgwKTtcbiAgICBleHBsYW5hdGlvbi5pbnB1dEFtb3VudCEuc2hvdWxkLmVxdWFsKCcwJyk7XG4gICAgZXhwbGFuYXRpb24ub3V0cHV0cyEubGVuZ3RoLnNob3VsZC5lcXVhbCgwKTtcbiAgICBleHBsYW5hdGlvbi5vdXRwdXRBbW91bnQhLnNob3VsZC5lcXVhbCgnMCcpO1xuICB9KTtcbn0pO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0gRXhlcmNpc2VDb21tYW5kIHZlcmlmaWNhdGlvbiB0ZXN0cyAtLS0tLS0tLS0tLS0tLS1cblxuY29uc3QgQ0FOVE9OX0NNRF9BQ1RfQVMgPSAnUmVnUmVnaXN0cmFyOjoxMjIwNTA4ZTU0ZmI3MDlkY2IxYTliNDA5NjQwOGFkNDE1ZDIyMTdkODg4MWFkOTAzNGE5ODUwNzUyOTMzYmE4OGFkNSc7XG5jb25zdCBDQU5UT05fQ01EX1RFTVBMQVRFX0lEID1cbiAgJzdhNzVlZjZlNjlmNjkzOTVhNGU2MDkxOWUyMjg1MjhiYjhmMzg4MTE1MGNjZmRlM2YzMWJjYzczODY0YjE4YWI6VXRpbGl0eS5SZWdpc3RyeS5BcHAuVjAuU2VydmljZS5BbGxvY2F0aW9uRmFjdG9yeTpBbGxvY2F0aW9uRmFjdG9yeSc7XG5jb25zdCBDQU5UT05fQ01EX0NPTlRSQUNUX0lEID1cbiAgJzAwZjNhZmRjZTg0NmE0MGM2ZjNmNjE4YzRiNTg0YjAyMmEwMTk3MDEwMDU3ZWNkNTk0NTgyMDAxODNhYjI3ZGUwYWNhMTIxMjIwNGFlZjdlZGUzN2E1ZjQxYjY3NGExZDk1NDQ2ZDQyYTQwNDQ2MWM1NTU4YzRlNmQxODYwYjY1NTYwMTIwZWYxOCc7XG5jb25zdCBDQU5UT05fQ01EX0NIT0lDRSA9ICdBbGxvY2F0aW9uRmFjdG9yeV9PZmZlck1pbnQnO1xuXG5mdW5jdGlvbiBidWlsZENhbnRvbkNvbW1hbmRSYXdUeChwcmVwYXJlUmVzcG9uc2U6IFBhcnRpYWw8Q2FudG9uUHJlcGFyZUNvbW1hbmRSZXNwb25zZT4sIGNvbW1hbmRJZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgZGF0YSA9IHtcbiAgICBwcmVwYXJlQ29tbWFuZFJlc3BvbnNlOiBwcmVwYXJlUmVzcG9uc2UsXG4gICAgdHhUeXBlOiAnQ2FudG9uQ29tbWFuZCcsXG4gICAgcHJlcGFyZWRUcmFuc2FjdGlvbjogJycsXG4gICAgcGFydHlTaWduYXR1cmVzOiB7IHNpZ25hdHVyZXM6IFtdIH0sXG4gICAgZGVkdXBsaWNhdGlvblBlcmlvZDogeyBFbXB0eToge30gfSxcbiAgICBzdWJtaXNzaW9uSWQ6IGNvbW1hbmRJZCxcbiAgICBoYXNoaW5nU2NoZW1lVmVyc2lvbjogJ0hBU0hJTkdfU0NIRU1FX1ZFUlNJT05fVjInLFxuICAgIG1pbkxlZGdlclRpbWU6IHsgdGltZTogeyBFbXB0eToge30gfSB9LFxuICB9O1xuICByZXR1cm4gQnVmZmVyLmZyb20oSlNPTi5zdHJpbmdpZnkoZGF0YSkpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbn1cblxuZGVzY3JpYmUoJ0NhbnRvbiB2ZXJpZnlUcmFuc2FjdGlvbiAtIENhbnRvbkNvbW1hbmQ6JywgZnVuY3Rpb24gKCkge1xuICBsZXQgYml0Z286IFRlc3RCaXRHb0FQSTtcbiAgbGV0IGJhc2Vjb2luOiBDYW50b247XG5cbiAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICBiaXRnbyA9IFRlc3RCaXRHby5kZWNvcmF0ZShCaXRHb0FQSSwgeyBlbnY6ICdtb2NrJyB9KTtcbiAgICBiaXRnby5zYWZlUmVnaXN0ZXIoJ2NhbnRvbicsIENhbnRvbi5jcmVhdGVJbnN0YW5jZSk7XG4gICAgYml0Z28uc2FmZVJlZ2lzdGVyKCd0Y2FudG9uJywgVGNhbnRvbi5jcmVhdGVJbnN0YW5jZSk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgYmFzZWNvaW4gPSBiaXRnby5jb2luKCd0Y2FudG9uJykgYXMgQ2FudG9uO1xuICB9KTtcblxuICBkZXNjcmliZSgnSGFwcHkgcGF0aCB0ZXN0czonLCBmdW5jdGlvbiAoKSB7XG4gICAgbGV0IHR4SGV4OiBzdHJpbmc7XG5cbiAgICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgICAgdHhIZXggPSBidWlsZENhbnRvbkNvbW1hbmRSYXdUeChDYW50b25FeGVyY2lzZUNvbW1hbmRQcmVwYXJlUmVzcG9uc2UsICd0ZXN0LWNhbnRvbi1jbWQtMDAxJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIHdoZW4gY2FudG9uQ29tbWFuZFBhcmFtcyBpcyB1bmRlZmluZWQgKG5vIHVzZXIgcGFyYW1zIHRvIHZlcmlmeSknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgdHhQYXJhbXM6IHt9LFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIElXYWxsZXQsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIGZvciBtYXRjaGluZyBFeGVyY2lzZUNvbW1hbmQgKHRlbXBsYXRlSWQsIGNob2ljZSwgY29udHJhY3RJZCwgYWN0QXMsIGFyZ3VtZW50KScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgIGNhbnRvbkNvbW1hbmRQYXJhbXM6IHtcbiAgICAgICAgICAgIGNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgRXhlcmNpc2VDb21tYW5kOiB7XG4gICAgICAgICAgICAgICAgdGVtcGxhdGVJZDogQ0FOVE9OX0NNRF9URU1QTEFURV9JRCxcbiAgICAgICAgICAgICAgICBjb250cmFjdElkOiBDQU5UT05fQ01EX0NPTlRSQUNUX0lELFxuICAgICAgICAgICAgICAgIGNob2ljZTogQ0FOVE9OX0NNRF9DSE9JQ0UsXG4gICAgICAgICAgICAgICAgY2hvaWNlQXJndW1lbnQ6IHtcbiAgICAgICAgICAgICAgICAgIGV4cGVjdGVkQWRtaW46IENBTlRPTl9DTURfQUNUX0FTLFxuICAgICAgICAgICAgICAgICAgbWludDoge1xuICAgICAgICAgICAgICAgICAgICBpbnN0cnVtZW50SWQ6IHtcbiAgICAgICAgICAgICAgICAgICAgICBhZG1pbjogQ0FOVE9OX0NNRF9BQ1RfQVMsXG4gICAgICAgICAgICAgICAgICAgICAgaWQ6ICdURVNUVE9LRU4nLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBhbW91bnQ6ICcxMDAnLFxuICAgICAgICAgICAgICAgICAgICBob2xkZXI6ICdSZWdJc3N1ZXI6OjEyMjA1MDhlNTRmYjcwOWRjYjFhOWI0MDk2NDA4YWQ0MTVkMjIxN2Q4ODgxYWQ5MDM0YTk4NTA3NTI5MzNiYTg4YWQ1JyxcbiAgICAgICAgICAgICAgICAgICAgcmVmZXJlbmNlOiAndGVzdC1wcmVwYXJlLW1pbnQnLFxuICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGFjdEFzOiBbQ0FOVE9OX0NNRF9BQ1RfQVNdLFxuICAgICAgICAgICAgcmVhZEFzOiBbXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9IGFzIENhbnRvblRyYW5zYWN0aW9uUGFyYW1zLFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIElXYWxsZXQsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIHdoZW4gY29udHJhY3RJZCBpcyBvbWl0dGVkIChJTVMtcmVzb2x2ZWQpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0sXG4gICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgY2FudG9uQ29tbWFuZFBhcmFtczoge1xuICAgICAgICAgICAgY29tbWFuZDoge1xuICAgICAgICAgICAgICBFeGVyY2lzZUNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZUlkOiBDQU5UT05fQ01EX1RFTVBMQVRFX0lELFxuICAgICAgICAgICAgICAgIGNob2ljZTogQ0FOVE9OX0NNRF9DSE9JQ0UsXG4gICAgICAgICAgICAgICAgY2hvaWNlQXJndW1lbnQ6IHt9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGFjdEFzOiBbQ0FOVE9OX0NNRF9BQ1RfQVNdLFxuICAgICAgICAgICAgcmVhZEFzOiBbXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9IGFzIENhbnRvblRyYW5zYWN0aW9uUGFyYW1zLFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIElXYWxsZXQsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIHdpdGggcmVzb2x2ZUNvbnRyYWN0cyBpbmplY3RBcyBza2lwcGluZyBjb250cmFjdElkIChlbXB0eSBjb250cmFjdElkKScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgIGNhbnRvbkNvbW1hbmRQYXJhbXM6IHtcbiAgICAgICAgICAgIGNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgRXhlcmNpc2VDb21tYW5kOiB7XG4gICAgICAgICAgICAgICAgdGVtcGxhdGVJZDogQ0FOVE9OX0NNRF9URU1QTEFURV9JRCxcbiAgICAgICAgICAgICAgICBjb250cmFjdElkOiAnJyxcbiAgICAgICAgICAgICAgICBjaG9pY2U6IENBTlRPTl9DTURfQ0hPSUNFLFxuICAgICAgICAgICAgICAgIGNob2ljZUFyZ3VtZW50OiB7fSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBhY3RBczogW0NBTlRPTl9DTURfQUNUX0FTXSxcbiAgICAgICAgICAgIHJlYWRBczogW10sXG4gICAgICAgICAgICByZXNvbHZlQ29udHJhY3RzOiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZUlkOiBDQU5UT05fQ01EX1RFTVBMQVRFX0lELFxuICAgICAgICAgICAgICAgIGFjdEFzOiBbQ0FOVE9OX0NNRF9BQ1RfQVNdLFxuICAgICAgICAgICAgICAgIGluamVjdEFzOiAnY29tbWFuZC5FeGVyY2lzZUNvbW1hbmQuY29udHJhY3RJZCcsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0gYXMgQ2FudG9uVHJhbnNhY3Rpb25QYXJhbXMsXG4gICAgICAgIHdhbGxldDoge30gYXMgSVdhbGxldCxcbiAgICAgIH0pO1xuICAgICAgcmVzdWx0LnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmV0dXJuIHRydWUgd2l0aCByZXNvbHZlQ29udHJhY3RzIGluamVjdEFzIHNraXBwaW5nIG5vbi1lbXB0eSBjb250cmFjdElkIG1pc21hdGNoJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gVXNlciBzdXBwbGllcyBhIHBsYWNlaG9sZGVyIGNvbnRyYWN0SWQgdGhhdCBkb2Vzbid0IG1hdGNoIHdoYXQncyBvbi1jaGFpbjtcbiAgICAgIC8vIHJlc29sdmVDb250cmFjdHMgbWFya3MgaXQgYXMgSU1TLWluamVjdGVkLCBzbyB0aGUgbWlzbWF0Y2ggbXVzdCBiZSBpZ25vcmVkLlxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0sXG4gICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgY2FudG9uQ29tbWFuZFBhcmFtczoge1xuICAgICAgICAgICAgY29tbWFuZDoge1xuICAgICAgICAgICAgICBFeGVyY2lzZUNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZUlkOiBDQU5UT05fQ01EX1RFTVBMQVRFX0lELFxuICAgICAgICAgICAgICAgIGNvbnRyYWN0SWQ6ICcwMHBsYWNlaG9sZGVyX2NvbnRyYWN0X2lkX25vdF9vbl9jaGFpbicsXG4gICAgICAgICAgICAgICAgY2hvaWNlOiBDQU5UT05fQ01EX0NIT0lDRSxcbiAgICAgICAgICAgICAgICBjaG9pY2VBcmd1bWVudDoge30sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgYWN0QXM6IFtDQU5UT05fQ01EX0FDVF9BU10sXG4gICAgICAgICAgICByZWFkQXM6IFtdLFxuICAgICAgICAgICAgcmVzb2x2ZUNvbnRyYWN0czogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdGVtcGxhdGVJZDogQ0FOVE9OX0NNRF9URU1QTEFURV9JRCxcbiAgICAgICAgICAgICAgICBhY3RBczogW0NBTlRPTl9DTURfQUNUX0FTXSxcbiAgICAgICAgICAgICAgICBpbmplY3RBczogJ2NvbW1hbmQuRXhlcmNpc2VDb21tYW5kLmNvbnRyYWN0SWQnLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9IGFzIENhbnRvblRyYW5zYWN0aW9uUGFyYW1zLFxuICAgICAgICB3YWxsZXQ6IHt9IGFzIElXYWxsZXQsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdFcnJvciBjYXNlczonLCBmdW5jdGlvbiAoKSB7XG4gICAgbGV0IHR4SGV4OiBzdHJpbmc7XG5cbiAgICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgICAgdHhIZXggPSBidWlsZENhbnRvbkNvbW1hbmRSYXdUeChDYW50b25FeGVyY2lzZUNvbW1hbmRQcmVwYXJlUmVzcG9uc2UsICd0ZXN0LWNhbnRvbi1jbWQtMDAyJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IHdoZW4gcHJlcGFyZWRUcmFuc2FjdGlvbiBpcyBtaXNzaW5nIG9uIHR4IHByZWJ1aWxkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZW1wdHlQcmVwYXJlID0geyAuLi5DYW50b25FeGVyY2lzZUNvbW1hbmRQcmVwYXJlUmVzcG9uc2UsIHByZXBhcmVkVHJhbnNhY3Rpb246IHVuZGVmaW5lZCB9O1xuICAgICAgY29uc3QgYmFkVHggPSBidWlsZENhbnRvbkNvbW1hbmRSYXdUeChlbXB0eVByZXBhcmUsICdjbWQtYmFkJyk7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXg6IGJhZFR4IH0sXG4gICAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICAgIGNhbnRvbkNvbW1hbmRQYXJhbXM6IHtcbiAgICAgICAgICAgICAgY29tbWFuZDoge1xuICAgICAgICAgICAgICAgIEV4ZXJjaXNlQ29tbWFuZDogeyB0ZW1wbGF0ZUlkOiBDQU5UT05fQ01EX1RFTVBMQVRFX0lELCBjaG9pY2U6IENBTlRPTl9DTURfQ0hPSUNFLCBjaG9pY2VBcmd1bWVudDoge30gfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgYWN0QXM6IFtDQU5UT05fQ01EX0FDVF9BU10sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0gYXMgQ2FudG9uVHJhbnNhY3Rpb25QYXJhbXMsXG4gICAgICAgICAgd2FsbGV0OiB7fSBhcyBJV2FsbGV0LFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvbWlzc2luZyBwcmVwYXJlZFRyYW5zYWN0aW9uLyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IHdoZW4gdXNlciBjb21tYW5kIGhhcyBuZWl0aGVyIENyZWF0ZUNvbW1hbmQgbm9yIEV4ZXJjaXNlQ29tbWFuZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgICBjYW50b25Db21tYW5kUGFyYW1zOiB7XG4gICAgICAgICAgICAgIGNvbW1hbmQ6IHsgVW5rbm93bkNvbW1hbmQ6IHt9IH0gYXMgdW5rbm93biBhcyBDYW50b25Db21tYW5kLFxuICAgICAgICAgICAgICBhY3RBczogW0NBTlRPTl9DTURfQUNUX0FTXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSBhcyBDYW50b25UcmFuc2FjdGlvblBhcmFtcyxcbiAgICAgICAgICB3YWxsZXQ6IHt9IGFzIElXYWxsZXQsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9tdXN0IGNvbnRhaW4gYSBDcmVhdGVDb21tYW5kIG9yIEV4ZXJjaXNlQ29tbWFuZC8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIHVzZXIgY29tbWFuZCBjb250YWlucyBib3RoIENyZWF0ZUNvbW1hbmQgYW5kIEV4ZXJjaXNlQ29tbWFuZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgICBjYW50b25Db21tYW5kUGFyYW1zOiB7XG4gICAgICAgICAgICAgIGNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgICBDcmVhdGVDb21tYW5kOiB7IHRlbXBsYXRlSWQ6IENBTlRPTl9DTURfVEVNUExBVEVfSUQsIGNyZWF0ZUFyZ3VtZW50czoge30gfSxcbiAgICAgICAgICAgICAgICBFeGVyY2lzZUNvbW1hbmQ6IHsgdGVtcGxhdGVJZDogQ0FOVE9OX0NNRF9URU1QTEFURV9JRCwgY2hvaWNlOiBDQU5UT05fQ01EX0NIT0lDRSwgY2hvaWNlQXJndW1lbnQ6IHt9IH0sXG4gICAgICAgICAgICAgIH0gYXMgdW5rbm93biBhcyBDYW50b25Db21tYW5kLFxuICAgICAgICAgICAgICBhY3RBczogW0NBTlRPTl9DTURfQUNUX0FTXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSBhcyBDYW50b25UcmFuc2FjdGlvblBhcmFtcyxcbiAgICAgICAgICB3YWxsZXQ6IHt9IGFzIElXYWxsZXQsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9leGFjdGx5IG9uZSBvZiBDcmVhdGVDb21tYW5kIG9yIEV4ZXJjaXNlQ29tbWFuZC8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBvbiBpbnZhbGlkIHVzZXIgdGVtcGxhdGVJZCBmb3JtYXQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgY2FudG9uQ29tbWFuZFBhcmFtczoge1xuICAgICAgICAgICAgICBjb21tYW5kOiB7XG4gICAgICAgICAgICAgICAgRXhlcmNpc2VDb21tYW5kOiB7XG4gICAgICAgICAgICAgICAgICB0ZW1wbGF0ZUlkOiAnSW52YWxpZEZvcm1hdCcsXG4gICAgICAgICAgICAgICAgICBjaG9pY2U6IENBTlRPTl9DTURfQ0hPSUNFLFxuICAgICAgICAgICAgICAgICAgY2hvaWNlQXJndW1lbnQ6IHt9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIGFjdEFzOiBbQ0FOVE9OX0NNRF9BQ1RfQVNdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9IGFzIENhbnRvblRyYW5zYWN0aW9uUGFyYW1zLFxuICAgICAgICAgIHdhbGxldDoge30gYXMgSVdhbGxldCxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL2ludmFsaWQgdXNlciB0ZW1wbGF0ZUlkLyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IG9uIHRlbXBsYXRlSWQgbW9kdWxlL2VudGl0eSBtaXNtYXRjaCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgICBjYW50b25Db21tYW5kUGFyYW1zOiB7XG4gICAgICAgICAgICAgIGNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgICBFeGVyY2lzZUNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgICAgIHRlbXBsYXRlSWQ6ICdTb21lUGtnOldyb25nLk1vZHVsZTpXcm9uZ0VudGl0eScsXG4gICAgICAgICAgICAgICAgICBjaG9pY2U6IENBTlRPTl9DTURfQ0hPSUNFLFxuICAgICAgICAgICAgICAgICAgY2hvaWNlQXJndW1lbnQ6IHt9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIGFjdEFzOiBbQ0FOVE9OX0NNRF9BQ1RfQVNdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9IGFzIENhbnRvblRyYW5zYWN0aW9uUGFyYW1zLFxuICAgICAgICAgIHdhbGxldDoge30gYXMgSVdhbGxldCxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL3RlbXBsYXRlSWQgbWlzbWF0Y2gvKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gc3VibWl0dGVySW5mby5hY3RBcyBtaXNtYXRjaCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgICBjYW50b25Db21tYW5kUGFyYW1zOiB7XG4gICAgICAgICAgICAgIGNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgICBFeGVyY2lzZUNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgICAgIHRlbXBsYXRlSWQ6IENBTlRPTl9DTURfVEVNUExBVEVfSUQsXG4gICAgICAgICAgICAgICAgICBjaG9pY2U6IENBTlRPTl9DTURfQ0hPSUNFLFxuICAgICAgICAgICAgICAgICAgY2hvaWNlQXJndW1lbnQ6IHt9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIGFjdEFzOiBbJ1dyb25nUGFydHk6OjEyMjBhYWFhJ10sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0gYXMgQ2FudG9uVHJhbnNhY3Rpb25QYXJhbXMsXG4gICAgICAgICAgd2FsbGV0OiB7fSBhcyBJV2FsbGV0LFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvc3VibWl0dGVySW5mby5hY3RBcy4qZG9lcyBub3QgbWF0Y2ggdXNlciBhY3RBcy8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBvbiBjaG9pY2UgbWlzbWF0Y2ggZm9yIEV4ZXJjaXNlQ29tbWFuZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgICBjYW50b25Db21tYW5kUGFyYW1zOiB7XG4gICAgICAgICAgICAgIGNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgICBFeGVyY2lzZUNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgICAgIHRlbXBsYXRlSWQ6IENBTlRPTl9DTURfVEVNUExBVEVfSUQsXG4gICAgICAgICAgICAgICAgICBjaG9pY2U6ICdXcm9uZ0Nob2ljZScsXG4gICAgICAgICAgICAgICAgICBjaG9pY2VBcmd1bWVudDoge30sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgYWN0QXM6IFtDQU5UT05fQ01EX0FDVF9BU10sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0gYXMgQ2FudG9uVHJhbnNhY3Rpb25QYXJhbXMsXG4gICAgICAgICAgd2FsbGV0OiB7fSBhcyBJV2FsbGV0LFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvY2hvaWNlIG1pc21hdGNoLyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IG9uIGNvbnRyYWN0SWQgbWlzbWF0Y2ggd2hlbiB1c2VyIHByb3ZpZGVzIGV4cGxpY2l0IGNvbnRyYWN0SWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgY2FudG9uQ29tbWFuZFBhcmFtczoge1xuICAgICAgICAgICAgICBjb21tYW5kOiB7XG4gICAgICAgICAgICAgICAgRXhlcmNpc2VDb21tYW5kOiB7XG4gICAgICAgICAgICAgICAgICB0ZW1wbGF0ZUlkOiBDQU5UT05fQ01EX1RFTVBMQVRFX0lELFxuICAgICAgICAgICAgICAgICAgY29udHJhY3RJZDogJzAwd3Jvbmdjb250cmFjdGlkJyxcbiAgICAgICAgICAgICAgICAgIGNob2ljZTogQ0FOVE9OX0NNRF9DSE9JQ0UsXG4gICAgICAgICAgICAgICAgICBjaG9pY2VBcmd1bWVudDoge30sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgYWN0QXM6IFtDQU5UT05fQ01EX0FDVF9BU10sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0gYXMgQ2FudG9uVHJhbnNhY3Rpb25QYXJhbXMsXG4gICAgICAgICAgd2FsbGV0OiB7fSBhcyBJV2FsbGV0LFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvY29udHJhY3RJZCBtaXNtYXRjaC8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBvbiBhcmd1bWVudCBkZWVwIG1pc21hdGNoJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0sXG4gICAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICAgIGNhbnRvbkNvbW1hbmRQYXJhbXM6IHtcbiAgICAgICAgICAgICAgY29tbWFuZDoge1xuICAgICAgICAgICAgICAgIEV4ZXJjaXNlQ29tbWFuZDoge1xuICAgICAgICAgICAgICAgICAgdGVtcGxhdGVJZDogQ0FOVE9OX0NNRF9URU1QTEFURV9JRCxcbiAgICAgICAgICAgICAgICAgIGNob2ljZTogQ0FOVE9OX0NNRF9DSE9JQ0UsXG4gICAgICAgICAgICAgICAgICBjaG9pY2VBcmd1bWVudDoge1xuICAgICAgICAgICAgICAgICAgICBleHBlY3RlZEFkbWluOiAnV3JvbmdQYXJ0eTo6dG90YWxseS1kaWZmZXJlbnQnLFxuICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBhY3RBczogW0NBTlRPTl9DTURfQUNUX0FTXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSBhcyBDYW50b25UcmFuc2FjdGlvblBhcmFtcyxcbiAgICAgICAgICB3YWxsZXQ6IHt9IGFzIElXYWxsZXQsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9taXNtYXRjaC8pO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0gQ3JlYXRlQ29tbWFuZCB2ZXJpZmljYXRpb24gdGVzdHMgLS0tLS0tLS0tLS0tLS0tXG5cbmNvbnN0IENSRUFURV9DTURfQUNUX0FTID0gJ1JlZ1Byb3ZpZGVyOjoxMjIwNTA4ZTU0ZmI3MDlkY2IxYTliNDA5NjQwOGFkNDE1ZDIyMTdkODg4MWFkOTAzNGE5ODUwNzUyOTMzYmE4OGFkNSc7XG5jb25zdCBDUkVBVEVfQ01EX1RFTVBMQVRFX0lEID1cbiAgJzdhNzVlZjZlNjlmNjkzOTVhNGU2MDkxOWUyMjg1MjhiYjhmMzg4MTE1MGNjZmRlM2YzMWJjYzczODY0YjE4YWI6VXRpbGl0eS5SZWdpc3RyeS5BcHAuVjAuU2VydmljZS5Qcm92aWRlcjpQcm92aWRlclNlcnZpY2VSZXF1ZXN0JztcbmNvbnN0IENSRUFURV9DTURfT1BFUkFUT1IgPSAnUmVnT3BlcmF0b3I6OjEyMjA1MDhlNTRmYjcwOWRjYjFhOWI0MDk2NDA4YWQ0MTVkMjIxN2Q4ODgxYWQ5MDM0YTk4NTA3NTI5MzNiYTg4YWQ1JztcblxuZGVzY3JpYmUoJ0NhbnRvbiB2ZXJpZnlUcmFuc2FjdGlvbiAtIENyZWF0ZUNvbW1hbmQ6JywgZnVuY3Rpb24gKCkge1xuICBsZXQgYml0Z286IFRlc3RCaXRHb0FQSTtcbiAgbGV0IGJhc2Vjb2luOiBDYW50b247XG5cbiAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICBiaXRnbyA9IFRlc3RCaXRHby5kZWNvcmF0ZShCaXRHb0FQSSwgeyBlbnY6ICdtb2NrJyB9KTtcbiAgICBiaXRnby5zYWZlUmVnaXN0ZXIoJ2NhbnRvbicsIENhbnRvbi5jcmVhdGVJbnN0YW5jZSk7XG4gICAgYml0Z28uc2FmZVJlZ2lzdGVyKCd0Y2FudG9uJywgVGNhbnRvbi5jcmVhdGVJbnN0YW5jZSk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgYmFzZWNvaW4gPSBiaXRnby5jb2luKCd0Y2FudG9uJykgYXMgQ2FudG9uO1xuICB9KTtcblxuICBkZXNjcmliZSgnSGFwcHkgcGF0aCB0ZXN0czonLCBmdW5jdGlvbiAoKSB7XG4gICAgbGV0IHR4SGV4OiBzdHJpbmc7XG5cbiAgICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgICAgdHhIZXggPSBidWlsZENhbnRvbkNvbW1hbmRSYXdUeChDYW50b25DcmVhdGVDb21tYW5kUHJlcGFyZVJlc3BvbnNlLCAndGVzdC1jcmVhdGUtY21kLTAwMScpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gdHJ1ZSBmb3IgbWF0Y2hpbmcgQ3JlYXRlQ29tbWFuZCAodGVtcGxhdGVJZCwgY3JlYXRlQXJndW1lbnRzLCBhY3RBcyknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgdHhQYXJhbXM6IHtcbiAgICAgICAgICBjYW50b25Db21tYW5kUGFyYW1zOiB7XG4gICAgICAgICAgICBjb21tYW5kOiB7XG4gICAgICAgICAgICAgIENyZWF0ZUNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZUlkOiBDUkVBVEVfQ01EX1RFTVBMQVRFX0lELFxuICAgICAgICAgICAgICAgIGNyZWF0ZUFyZ3VtZW50czoge1xuICAgICAgICAgICAgICAgICAgb3BlcmF0b3I6IENSRUFURV9DTURfT1BFUkFUT1IsXG4gICAgICAgICAgICAgICAgICBwcm92aWRlcjogQ1JFQVRFX0NNRF9BQ1RfQVMsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBhY3RBczogW0NSRUFURV9DTURfQUNUX0FTXSxcbiAgICAgICAgICAgIHJlYWRBczogW10sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSBhcyBDYW50b25UcmFuc2FjdGlvblBhcmFtcyxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBJV2FsbGV0LFxuICAgICAgfSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gdHJ1ZSB3aGVuIGNyZWF0ZUFyZ3VtZW50cyBpcyBlbXB0eSAobm8gZGVlcC1jb21wYXJlKScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgIGNhbnRvbkNvbW1hbmRQYXJhbXM6IHtcbiAgICAgICAgICAgIGNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgQ3JlYXRlQ29tbWFuZDoge1xuICAgICAgICAgICAgICAgIHRlbXBsYXRlSWQ6IENSRUFURV9DTURfVEVNUExBVEVfSUQsXG4gICAgICAgICAgICAgICAgY3JlYXRlQXJndW1lbnRzOiB7fSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBhY3RBczogW0NSRUFURV9DTURfQUNUX0FTXSxcbiAgICAgICAgICAgIHJlYWRBczogW10sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSBhcyBDYW50b25UcmFuc2FjdGlvblBhcmFtcyxcbiAgICAgICAgd2FsbGV0OiB7fSBhcyBJV2FsbGV0LFxuICAgICAgfSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gdHJ1ZSB3aXRoIHJlc29sdmVDb250cmFjdHMgaW5qZWN0QXMgc2tpcHBpbmcgY3JlYXRlQXJndW1lbnRzIGZpZWxkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICB0eFByZWJ1aWxkOiB7IHR4SGV4IH0sXG4gICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgY2FudG9uQ29tbWFuZFBhcmFtczoge1xuICAgICAgICAgICAgY29tbWFuZDoge1xuICAgICAgICAgICAgICBDcmVhdGVDb21tYW5kOiB7XG4gICAgICAgICAgICAgICAgdGVtcGxhdGVJZDogQ1JFQVRFX0NNRF9URU1QTEFURV9JRCxcbiAgICAgICAgICAgICAgICBjcmVhdGVBcmd1bWVudHM6IHtcbiAgICAgICAgICAgICAgICAgIG9wZXJhdG9yOiAncGxhY2Vob2xkZXItb3BlcmF0b3ItaWQnLFxuICAgICAgICAgICAgICAgICAgcHJvdmlkZXI6IENSRUFURV9DTURfQUNUX0FTLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgYWN0QXM6IFtDUkVBVEVfQ01EX0FDVF9BU10sXG4gICAgICAgICAgICByZWFkQXM6IFtdLFxuICAgICAgICAgICAgcmVzb2x2ZUNvbnRyYWN0czogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdGVtcGxhdGVJZDogJ3NvbWUtdGVtcGxhdGUnLFxuICAgICAgICAgICAgICAgIGFjdEFzOiBbQ1JFQVRFX0NNRF9BQ1RfQVNdLFxuICAgICAgICAgICAgICAgIGluamVjdEFzOiAnY29tbWFuZC5DcmVhdGVDb21tYW5kLmNyZWF0ZUFyZ3VtZW50cy5vcGVyYXRvcicsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBdLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0gYXMgQ2FudG9uVHJhbnNhY3Rpb25QYXJhbXMsXG4gICAgICAgIHdhbGxldDoge30gYXMgSVdhbGxldCxcbiAgICAgIH0pO1xuICAgICAgcmVzdWx0LnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0Vycm9yIGNhc2VzOicsIGZ1bmN0aW9uICgpIHtcbiAgICBsZXQgdHhIZXg6IHN0cmluZztcblxuICAgIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgICB0eEhleCA9IGJ1aWxkQ2FudG9uQ29tbWFuZFJhd1R4KENhbnRvbkNyZWF0ZUNvbW1hbmRQcmVwYXJlUmVzcG9uc2UsICd0ZXN0LWNyZWF0ZS1jbWQtZXJyJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IG9uIHRlbXBsYXRlSWQgbWlzbWF0Y2ggZm9yIENyZWF0ZUNvbW1hbmQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgY2FudG9uQ29tbWFuZFBhcmFtczoge1xuICAgICAgICAgICAgICBjb21tYW5kOiB7XG4gICAgICAgICAgICAgICAgQ3JlYXRlQ29tbWFuZDoge1xuICAgICAgICAgICAgICAgICAgdGVtcGxhdGVJZDogJ1dyb25nUGtnOldyb25nLk1vZHVsZTpXcm9uZ0VudGl0eScsXG4gICAgICAgICAgICAgICAgICBjcmVhdGVBcmd1bWVudHM6IHt9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIGFjdEFzOiBbQ1JFQVRFX0NNRF9BQ1RfQVNdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9IGFzIENhbnRvblRyYW5zYWN0aW9uUGFyYW1zLFxuICAgICAgICAgIHdhbGxldDoge30gYXMgSVdhbGxldCxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL3RlbXBsYXRlSWQgbWlzbWF0Y2gvKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gY3JlYXRlQXJndW1lbnRzIGRlZXAgbWlzbWF0Y2gnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UHJlYnVpbGQ6IHsgdHhIZXggfSxcbiAgICAgICAgICB0eFBhcmFtczoge1xuICAgICAgICAgICAgY2FudG9uQ29tbWFuZFBhcmFtczoge1xuICAgICAgICAgICAgICBjb21tYW5kOiB7XG4gICAgICAgICAgICAgICAgQ3JlYXRlQ29tbWFuZDoge1xuICAgICAgICAgICAgICAgICAgdGVtcGxhdGVJZDogQ1JFQVRFX0NNRF9URU1QTEFURV9JRCxcbiAgICAgICAgICAgICAgICAgIGNyZWF0ZUFyZ3VtZW50czoge1xuICAgICAgICAgICAgICAgICAgICBvcGVyYXRvcjogJ1dyb25nT3BlcmF0b3I6OnRvdGFsbHktZGlmZmVyZW50JyxcbiAgICAgICAgICAgICAgICAgICAgcHJvdmlkZXI6IENSRUFURV9DTURfQUNUX0FTLFxuICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBhY3RBczogW0NSRUFURV9DTURfQUNUX0FTXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSBhcyBDYW50b25UcmFuc2FjdGlvblBhcmFtcyxcbiAgICAgICAgICB3YWxsZXQ6IHt9IGFzIElXYWxsZXQsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9taXNtYXRjaC8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBvbiBhY3RBcyBtaXNtYXRjaCBmb3IgQ3JlYXRlQ29tbWFuZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgdHhQcmVidWlsZDogeyB0eEhleCB9LFxuICAgICAgICAgIHR4UGFyYW1zOiB7XG4gICAgICAgICAgICBjYW50b25Db21tYW5kUGFyYW1zOiB7XG4gICAgICAgICAgICAgIGNvbW1hbmQ6IHtcbiAgICAgICAgICAgICAgICBDcmVhdGVDb21tYW5kOiB7XG4gICAgICAgICAgICAgICAgICB0ZW1wbGF0ZUlkOiBDUkVBVEVfQ01EX1RFTVBMQVRFX0lELFxuICAgICAgICAgICAgICAgICAgY3JlYXRlQXJndW1lbnRzOiB7fSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBhY3RBczogWydXcm9uZ1BhcnR5OjoxMjIwYWFhYSddLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9IGFzIENhbnRvblRyYW5zYWN0aW9uUGFyYW1zLFxuICAgICAgICAgIHdhbGxldDoge30gYXMgSVdhbGxldCxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL3N1Ym1pdHRlckluZm8uYWN0QXMuKmRvZXMgbm90IG1hdGNoIHVzZXIgYWN0QXMvKTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ==
|