@decaf-ts/for-fabric 0.0.2
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/LICENSE.md +22 -0
- package/README.md +647 -0
- package/dist/for-fabric.cjs +6223 -0
- package/dist/for-fabric.esm.cjs +6180 -0
- package/lib/client/FabricClientAdapter.cjs +760 -0
- package/lib/client/FabricClientAdapter.d.ts +381 -0
- package/lib/client/FabricClientDispatch.cjs +186 -0
- package/lib/client/FabricClientDispatch.d.ts +125 -0
- package/lib/client/FabricClientRepository.cjs +131 -0
- package/lib/client/FabricClientRepository.d.ts +100 -0
- package/lib/client/erc20/erc20ClientRepository.cjs +343 -0
- package/lib/client/erc20/erc20ClientRepository.d.ts +254 -0
- package/lib/client/fabric-fs.cjs +234 -0
- package/lib/client/fabric-fs.d.ts +92 -0
- package/lib/client/index.cjs +30 -0
- package/lib/client/index.d.ts +13 -0
- package/lib/client/logging.cjs +102 -0
- package/lib/client/logging.d.ts +60 -0
- package/lib/client/services/LoggedService.cjs +47 -0
- package/lib/client/services/LoggedService.d.ts +42 -0
- package/lib/client/services/constants.cjs +3 -0
- package/lib/client/services/constants.d.ts +15 -0
- package/lib/client/services/enrollementService.cjs +344 -0
- package/lib/client/services/enrollementService.d.ts +176 -0
- package/lib/client/services/index.cjs +18 -0
- package/lib/client/services/index.d.ts +1 -0
- package/lib/contracts/ContractAdapter.cjs +730 -0
- package/lib/contracts/ContractAdapter.d.ts +296 -0
- package/lib/contracts/ContractContext.cjs +85 -0
- package/lib/contracts/ContractContext.d.ts +64 -0
- package/lib/contracts/ContractPrivateDataAdapter.cjs +281 -0
- package/lib/contracts/ContractPrivateDataAdapter.d.ts +74 -0
- package/lib/contracts/FabricConstruction.cjs +441 -0
- package/lib/contracts/FabricConstruction.d.ts +304 -0
- package/lib/contracts/FabricContractRepository.cjs +306 -0
- package/lib/contracts/FabricContractRepository.d.ts +162 -0
- package/lib/contracts/FabricContractRepositoryObservableHandler.cjs +85 -0
- package/lib/contracts/FabricContractRepositoryObservableHandler.d.ts +62 -0
- package/lib/contracts/FabricContractSequence.cjs +139 -0
- package/lib/contracts/FabricContractSequence.d.ts +61 -0
- package/lib/contracts/FabricContractStatement.cjs +119 -0
- package/lib/contracts/FabricContractStatement.d.ts +34 -0
- package/lib/contracts/PrivateSequence.cjs +36 -0
- package/lib/contracts/PrivateSequence.d.ts +15 -0
- package/lib/contracts/crud/crud-contract.cjs +257 -0
- package/lib/contracts/crud/crud-contract.d.ts +168 -0
- package/lib/contracts/crud/index.cjs +19 -0
- package/lib/contracts/crud/index.d.ts +2 -0
- package/lib/contracts/crud/serialized-crud-contract.cjs +172 -0
- package/lib/contracts/crud/serialized-crud-contract.d.ts +37 -0
- package/lib/contracts/erc20/erc20contract.cjs +569 -0
- package/lib/contracts/erc20/erc20contract.d.ts +151 -0
- package/lib/contracts/erc20/index.cjs +21 -0
- package/lib/contracts/erc20/index.d.ts +2 -0
- package/lib/contracts/erc20/models.cjs +209 -0
- package/lib/contracts/erc20/models.d.ts +114 -0
- package/lib/contracts/index.cjs +32 -0
- package/lib/contracts/index.d.ts +15 -0
- package/lib/contracts/logging.cjs +96 -0
- package/lib/contracts/logging.d.ts +49 -0
- package/lib/contracts/private-data.cjs +121 -0
- package/lib/contracts/private-data.d.ts +16 -0
- package/lib/contracts/types.cjs +3 -0
- package/lib/contracts/types.d.ts +26 -0
- package/lib/esm/client/FabricClientAdapter.d.ts +381 -0
- package/lib/esm/client/FabricClientAdapter.js +723 -0
- package/lib/esm/client/FabricClientDispatch.d.ts +125 -0
- package/lib/esm/client/FabricClientDispatch.js +182 -0
- package/lib/esm/client/FabricClientRepository.d.ts +100 -0
- package/lib/esm/client/FabricClientRepository.js +127 -0
- package/lib/esm/client/erc20/erc20ClientRepository.d.ts +254 -0
- package/lib/esm/client/erc20/erc20ClientRepository.js +339 -0
- package/lib/esm/client/fabric-fs.d.ts +92 -0
- package/lib/esm/client/fabric-fs.js +191 -0
- package/lib/esm/client/index.d.ts +13 -0
- package/lib/esm/client/index.js +14 -0
- package/lib/esm/client/logging.d.ts +60 -0
- package/lib/esm/client/logging.js +98 -0
- package/lib/esm/client/services/LoggedService.d.ts +42 -0
- package/lib/esm/client/services/LoggedService.js +43 -0
- package/lib/esm/client/services/constants.d.ts +15 -0
- package/lib/esm/client/services/constants.js +2 -0
- package/lib/esm/client/services/enrollementService.d.ts +176 -0
- package/lib/esm/client/services/enrollementService.js +337 -0
- package/lib/esm/client/services/index.d.ts +1 -0
- package/lib/esm/client/services/index.js +2 -0
- package/lib/esm/contracts/ContractAdapter.d.ts +296 -0
- package/lib/esm/contracts/ContractAdapter.js +724 -0
- package/lib/esm/contracts/ContractContext.d.ts +64 -0
- package/lib/esm/contracts/ContractContext.js +81 -0
- package/lib/esm/contracts/ContractPrivateDataAdapter.d.ts +74 -0
- package/lib/esm/contracts/ContractPrivateDataAdapter.js +277 -0
- package/lib/esm/contracts/FabricConstruction.d.ts +304 -0
- package/lib/esm/contracts/FabricConstruction.js +433 -0
- package/lib/esm/contracts/FabricContractRepository.d.ts +162 -0
- package/lib/esm/contracts/FabricContractRepository.js +302 -0
- package/lib/esm/contracts/FabricContractRepositoryObservableHandler.d.ts +62 -0
- package/lib/esm/contracts/FabricContractRepositoryObservableHandler.js +81 -0
- package/lib/esm/contracts/FabricContractSequence.d.ts +61 -0
- package/lib/esm/contracts/FabricContractSequence.js +135 -0
- package/lib/esm/contracts/FabricContractStatement.d.ts +34 -0
- package/lib/esm/contracts/FabricContractStatement.js +115 -0
- package/lib/esm/contracts/PrivateSequence.d.ts +15 -0
- package/lib/esm/contracts/PrivateSequence.js +33 -0
- package/lib/esm/contracts/crud/crud-contract.d.ts +168 -0
- package/lib/esm/contracts/crud/crud-contract.js +253 -0
- package/lib/esm/contracts/crud/index.d.ts +2 -0
- package/lib/esm/contracts/crud/index.js +3 -0
- package/lib/esm/contracts/crud/serialized-crud-contract.d.ts +37 -0
- package/lib/esm/contracts/crud/serialized-crud-contract.js +168 -0
- package/lib/esm/contracts/erc20/erc20contract.d.ts +151 -0
- package/lib/esm/contracts/erc20/erc20contract.js +565 -0
- package/lib/esm/contracts/erc20/index.d.ts +2 -0
- package/lib/esm/contracts/erc20/index.js +4 -0
- package/lib/esm/contracts/erc20/models.d.ts +114 -0
- package/lib/esm/contracts/erc20/models.js +206 -0
- package/lib/esm/contracts/index.d.ts +15 -0
- package/lib/esm/contracts/index.js +16 -0
- package/lib/esm/contracts/logging.d.ts +49 -0
- package/lib/esm/contracts/logging.js +92 -0
- package/lib/esm/contracts/private-data.d.ts +16 -0
- package/lib/esm/contracts/private-data.js +113 -0
- package/lib/esm/contracts/types.d.ts +26 -0
- package/lib/esm/contracts/types.js +2 -0
- package/lib/esm/index.d.ts +8 -0
- package/lib/esm/index.js +9 -0
- package/lib/esm/shared/ClientSerializer.d.ts +52 -0
- package/lib/esm/shared/ClientSerializer.js +80 -0
- package/lib/esm/shared/DeterministicSerializer.d.ts +40 -0
- package/lib/esm/shared/DeterministicSerializer.js +50 -0
- package/lib/esm/shared/SimpleDeterministicSerializer.d.ts +7 -0
- package/lib/esm/shared/SimpleDeterministicSerializer.js +42 -0
- package/lib/esm/shared/constants.d.ts +39 -0
- package/lib/esm/shared/constants.js +42 -0
- package/lib/esm/shared/crypto.d.ts +107 -0
- package/lib/esm/shared/crypto.js +331 -0
- package/lib/esm/shared/decorators.d.ts +24 -0
- package/lib/esm/shared/decorators.js +98 -0
- package/lib/esm/shared/erc20/erc20-constants.d.ts +25 -0
- package/lib/esm/shared/erc20/erc20-constants.js +27 -0
- package/lib/esm/shared/errors.d.ts +116 -0
- package/lib/esm/shared/errors.js +132 -0
- package/lib/esm/shared/events.d.ts +39 -0
- package/lib/esm/shared/events.js +47 -0
- package/lib/esm/shared/fabric-types.d.ts +33 -0
- package/lib/esm/shared/fabric-types.js +2 -0
- package/lib/esm/shared/index.d.ts +13 -0
- package/lib/esm/shared/index.js +14 -0
- package/lib/esm/shared/interfaces/Checkable.d.ts +21 -0
- package/lib/esm/shared/interfaces/Checkable.js +2 -0
- package/lib/esm/shared/math.d.ts +34 -0
- package/lib/esm/shared/math.js +61 -0
- package/lib/esm/shared/model/Identity.d.ts +42 -0
- package/lib/esm/shared/model/Identity.js +78 -0
- package/lib/esm/shared/model/IdentityCredentials.d.ts +41 -0
- package/lib/esm/shared/model/IdentityCredentials.js +74 -0
- package/lib/esm/shared/model/index.d.ts +1 -0
- package/lib/esm/shared/model/index.js +2 -0
- package/lib/esm/shared/model/utils.d.ts +60 -0
- package/lib/esm/shared/model/utils.js +108 -0
- package/lib/esm/shared/types.d.ts +79 -0
- package/lib/esm/shared/types.js +2 -0
- package/lib/esm/shared/utils.d.ts +55 -0
- package/lib/esm/shared/utils.js +148 -0
- package/lib/index.cjs +25 -0
- package/lib/index.d.ts +8 -0
- package/lib/shared/ClientSerializer.cjs +84 -0
- package/lib/shared/ClientSerializer.d.ts +52 -0
- package/lib/shared/DeterministicSerializer.cjs +54 -0
- package/lib/shared/DeterministicSerializer.d.ts +40 -0
- package/lib/shared/SimpleDeterministicSerializer.cjs +46 -0
- package/lib/shared/SimpleDeterministicSerializer.d.ts +7 -0
- package/lib/shared/constants.cjs +45 -0
- package/lib/shared/constants.d.ts +39 -0
- package/lib/shared/crypto.cjs +369 -0
- package/lib/shared/crypto.d.ts +107 -0
- package/lib/shared/decorators.cjs +105 -0
- package/lib/shared/decorators.d.ts +24 -0
- package/lib/shared/erc20/erc20-constants.cjs +30 -0
- package/lib/shared/erc20/erc20-constants.d.ts +25 -0
- package/lib/shared/errors.cjs +142 -0
- package/lib/shared/errors.d.ts +116 -0
- package/lib/shared/events.cjs +51 -0
- package/lib/shared/events.d.ts +39 -0
- package/lib/shared/fabric-types.cjs +4 -0
- package/lib/shared/fabric-types.d.ts +33 -0
- package/lib/shared/index.cjs +30 -0
- package/lib/shared/index.d.ts +13 -0
- package/lib/shared/interfaces/Checkable.cjs +3 -0
- package/lib/shared/interfaces/Checkable.d.ts +21 -0
- package/lib/shared/math.cjs +66 -0
- package/lib/shared/math.d.ts +34 -0
- package/lib/shared/model/Identity.cjs +81 -0
- package/lib/shared/model/Identity.d.ts +42 -0
- package/lib/shared/model/IdentityCredentials.cjs +77 -0
- package/lib/shared/model/IdentityCredentials.d.ts +41 -0
- package/lib/shared/model/index.cjs +18 -0
- package/lib/shared/model/index.d.ts +1 -0
- package/lib/shared/model/utils.cjs +114 -0
- package/lib/shared/model/utils.d.ts +60 -0
- package/lib/shared/types.cjs +3 -0
- package/lib/shared/types.d.ts +79 -0
- package/lib/shared/utils.cjs +185 -0
- package/lib/shared/utils.d.ts +55 -0
- package/package.json +166 -0
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.FabricERC20Contract = void 0;
|
|
13
|
+
const core_1 = require("@decaf-ts/core");
|
|
14
|
+
const fabric_contract_api_1 = require("fabric-contract-api");
|
|
15
|
+
const math_1 = require("./../../shared/math.cjs");
|
|
16
|
+
const errors_1 = require("./../../shared/errors.cjs");
|
|
17
|
+
const ContractAdapter_1 = require("./../ContractAdapter.cjs");
|
|
18
|
+
const models_1 = require("./models.cjs");
|
|
19
|
+
const decorators_1 = require("./../../shared/decorators.cjs");
|
|
20
|
+
const FabricContractRepository_1 = require("./../FabricContractRepository.cjs");
|
|
21
|
+
const db_decorators_1 = require("@decaf-ts/db-decorators");
|
|
22
|
+
const crud_contract_1 = require("./../crud/crud-contract.cjs");
|
|
23
|
+
const erc20_constants_1 = require("./../../shared/erc20/erc20-constants.cjs");
|
|
24
|
+
/**
|
|
25
|
+
* @description ERC20 token contract base for Hyperledger Fabric
|
|
26
|
+
* @summary Implements ERC20-like token logic using repositories and adapters, providing standard token operations such as balance queries, transfers, approvals, minting and burning.
|
|
27
|
+
* @param {string} name - The contract name used to scope token identity
|
|
28
|
+
* @note https://eips.ethereum.org/EIPS/eip-20
|
|
29
|
+
* @return {void}
|
|
30
|
+
* @class FabricERC20Contract
|
|
31
|
+
* @example
|
|
32
|
+
* class MyTokenContract extends FabricERC20Contract {
|
|
33
|
+
* constructor() { super('MyToken'); }
|
|
34
|
+
* }
|
|
35
|
+
* // The contract exposes methods like Transfer, Approve, Mint, Burn, etc.
|
|
36
|
+
* @mermaid
|
|
37
|
+
* sequenceDiagram
|
|
38
|
+
* participant Client
|
|
39
|
+
* participant Contract
|
|
40
|
+
* participant WalletRepo
|
|
41
|
+
* participant TokenRepo
|
|
42
|
+
* participant Ledger
|
|
43
|
+
* Client->>Contract: Transfer(ctx, to, value)
|
|
44
|
+
* Contract->>WalletRepo: read(from)
|
|
45
|
+
* Contract->>WalletRepo: read(to)
|
|
46
|
+
* Contract->>Ledger: putState(updated balances)
|
|
47
|
+
* Contract-->>Client: success
|
|
48
|
+
*/
|
|
49
|
+
class FabricERC20Contract extends crud_contract_1.FabricCrudContract {
|
|
50
|
+
constructor(name) {
|
|
51
|
+
super(name, models_1.ERC20Wallet);
|
|
52
|
+
FabricERC20Contract.adapter =
|
|
53
|
+
FabricERC20Contract.adapter || new ContractAdapter_1.FabricContractAdapter();
|
|
54
|
+
this.walletRepository = FabricContractRepository_1.FabricContractRepository.forModel(models_1.ERC20Wallet, FabricERC20Contract.adapter.alias);
|
|
55
|
+
this.tokenRepository = FabricContractRepository_1.FabricContractRepository.forModel(models_1.ERC20Token, FabricERC20Contract.adapter.alias);
|
|
56
|
+
this.allowanceRepository = FabricContractRepository_1.FabricContractRepository.forModel(models_1.Allowance, FabricERC20Contract.adapter.alias);
|
|
57
|
+
}
|
|
58
|
+
async TokenName(ctx) {
|
|
59
|
+
// Check contract options are already set first to execute the function
|
|
60
|
+
await this.CheckInitialized(ctx);
|
|
61
|
+
const select = await this.tokenRepository.selectWithContext(undefined, ctx);
|
|
62
|
+
const token = (await select.execute())[0];
|
|
63
|
+
return token.name;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Return the symbol of the token. E.g. “HIX”.
|
|
67
|
+
*
|
|
68
|
+
* @param {Context} ctx the transaction context
|
|
69
|
+
* @returns {String} Returns the symbol of the token
|
|
70
|
+
*/
|
|
71
|
+
async Symbol(ctx) {
|
|
72
|
+
// Check contract options are already set first to execute the function
|
|
73
|
+
await this.CheckInitialized(ctx);
|
|
74
|
+
const select = await this.tokenRepository.selectWithContext(undefined, ctx);
|
|
75
|
+
const token = (await select.execute())[0];
|
|
76
|
+
return token.symbol;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Return the number of decimals the token uses
|
|
80
|
+
* e.g. 8, means to divide the token amount by 100000000 to get its user representation.
|
|
81
|
+
*
|
|
82
|
+
* @param {Context} ctx the transaction context
|
|
83
|
+
* @returns {Number} Returns the number of decimals
|
|
84
|
+
*/
|
|
85
|
+
async Decimals(ctx) {
|
|
86
|
+
// Check contract options are already set first to execute the function
|
|
87
|
+
await this.CheckInitialized(ctx);
|
|
88
|
+
const select = await this.tokenRepository.selectWithContext(undefined, ctx);
|
|
89
|
+
const token = (await select.execute())[0];
|
|
90
|
+
return token.decimals;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Return the total token supply.
|
|
94
|
+
*
|
|
95
|
+
* @param {Context} ctx the transaction context
|
|
96
|
+
* @returns {Number} Returns the total token supply
|
|
97
|
+
*/
|
|
98
|
+
async TotalSupply(ctx) {
|
|
99
|
+
// Check contract options are already set first to execute the function
|
|
100
|
+
await this.CheckInitialized(ctx);
|
|
101
|
+
const select = await this.walletRepository.selectWithContext(undefined, ctx);
|
|
102
|
+
const wallets = await select.execute();
|
|
103
|
+
if (wallets.length == 0) {
|
|
104
|
+
throw new db_decorators_1.NotFoundError(`The token ${this.getName()} does not exist`);
|
|
105
|
+
}
|
|
106
|
+
let total = 0;
|
|
107
|
+
wallets.forEach((wallet) => {
|
|
108
|
+
total += wallet.balance;
|
|
109
|
+
});
|
|
110
|
+
return total;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* BalanceOf returns the balance of the given account.
|
|
114
|
+
*
|
|
115
|
+
* @param {Context} ctx the transaction context
|
|
116
|
+
* @param {String} owner The owner from which the balance will be retrieved
|
|
117
|
+
* @returns {Number} Returns the account balance
|
|
118
|
+
*/
|
|
119
|
+
async BalanceOf(ctx, owner) {
|
|
120
|
+
// Check contract options are already set first to execute the function
|
|
121
|
+
await this.CheckInitialized(ctx);
|
|
122
|
+
const wallet = await this.walletRepository.read(owner, ctx);
|
|
123
|
+
return wallet.balance;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* @summary Transfer transfers tokens from client account to recipient account.
|
|
127
|
+
* @description recipient account must be a valid clientID as returned by the ClientAccountID() function.
|
|
128
|
+
*
|
|
129
|
+
* @param {Context} ctx the transaction context
|
|
130
|
+
* @param {String} to The recipient
|
|
131
|
+
* @param {number} value The amount of token to be transferred
|
|
132
|
+
*
|
|
133
|
+
* @returns {Boolean} Return whether the transfer was successful or not
|
|
134
|
+
*/
|
|
135
|
+
async Transfer(ctx, to, value) {
|
|
136
|
+
// Check contract options are already set first to execute the function
|
|
137
|
+
await this.CheckInitialized(ctx);
|
|
138
|
+
const from = ctx.clientIdentity.getID();
|
|
139
|
+
const transferResp = await this._transfer(ctx, from, to, value);
|
|
140
|
+
if (!transferResp) {
|
|
141
|
+
throw new db_decorators_1.InternalError("Failed to transfer");
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Transfer `value` amount of tokens from `from` to `to`.
|
|
147
|
+
*
|
|
148
|
+
* @param {Context} ctx the transaction context
|
|
149
|
+
* @param {String} from The sender
|
|
150
|
+
* @param {String} to The recipient
|
|
151
|
+
* @param {number} value The amount of token to be transferred
|
|
152
|
+
* @returns {Boolean} Return whether the transfer was successful or not
|
|
153
|
+
*/
|
|
154
|
+
async TransferFrom(ctx, from, to, value) {
|
|
155
|
+
// Check contract options are already set first to execute the function
|
|
156
|
+
await this.CheckInitialized(ctx);
|
|
157
|
+
// Retrieve the allowance of the spender
|
|
158
|
+
const spender = ctx.clientIdentity.getID();
|
|
159
|
+
const allowance = await this._getAllowance(ctx, from, spender);
|
|
160
|
+
if (!allowance || allowance.value < 0) {
|
|
161
|
+
throw new errors_1.AllowanceError(`spender ${spender} has no allowance from ${from}`);
|
|
162
|
+
}
|
|
163
|
+
const currentAllowance = allowance.value;
|
|
164
|
+
// Check if the transferred value is less than the allowance
|
|
165
|
+
if (currentAllowance < value) {
|
|
166
|
+
throw new errors_1.BalanceError("The spender does not have enough allowance to spend.");
|
|
167
|
+
}
|
|
168
|
+
// Decrease the allowance
|
|
169
|
+
const updatedAllowance = (0, math_1.sub)(currentAllowance, value);
|
|
170
|
+
const newAllowance = Object.assign({}, allowance, {
|
|
171
|
+
value: updatedAllowance,
|
|
172
|
+
});
|
|
173
|
+
await this.allowanceRepository.update(newAllowance, ctx);
|
|
174
|
+
//Realize the transfer
|
|
175
|
+
const transferResp = await this._transfer(ctx, from, to, value);
|
|
176
|
+
if (!transferResp) {
|
|
177
|
+
throw new db_decorators_1.InternalError("Failed to transfer");
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
async _transfer(ctx, from, to, value) {
|
|
182
|
+
const logger = this.logFor(ctx).for(this._transfer);
|
|
183
|
+
if (from === to) {
|
|
184
|
+
throw new core_1.AuthorizationError("cannot transfer to and from same client account");
|
|
185
|
+
}
|
|
186
|
+
if (value < 0) {
|
|
187
|
+
// transfer of 0 is allowed in ERC20, so just validate against negative amounts
|
|
188
|
+
throw new errors_1.BalanceError("transfer amount cannot be negative");
|
|
189
|
+
}
|
|
190
|
+
// Retrieve the current balance of the sender
|
|
191
|
+
const fromWallet = await this.walletRepository.read(from, ctx);
|
|
192
|
+
const fromBalance = fromWallet.balance;
|
|
193
|
+
// Check if the sender has enough tokens to spend.
|
|
194
|
+
if (fromBalance < value) {
|
|
195
|
+
throw new errors_1.BalanceError(`client account ${from} has insufficient funds.`);
|
|
196
|
+
}
|
|
197
|
+
// Retrieve the current balance of the recepient
|
|
198
|
+
let toWallet;
|
|
199
|
+
let newToWallet = false;
|
|
200
|
+
try {
|
|
201
|
+
toWallet = await this.walletRepository.read(to, ctx);
|
|
202
|
+
}
|
|
203
|
+
catch (e) {
|
|
204
|
+
if (e instanceof db_decorators_1.BaseError) {
|
|
205
|
+
if (e.code === 404) {
|
|
206
|
+
// Create a new wallet for the minter
|
|
207
|
+
toWallet = new models_1.ERC20Wallet({
|
|
208
|
+
id: to,
|
|
209
|
+
balance: 0,
|
|
210
|
+
token: await this.TokenName(ctx),
|
|
211
|
+
});
|
|
212
|
+
newToWallet = true;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
throw new db_decorators_1.InternalError(e.message);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
throw new db_decorators_1.InternalError(e);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const toBalance = toWallet.balance;
|
|
223
|
+
// Update the balance
|
|
224
|
+
const fromUpdatedBalance = (0, math_1.sub)(fromBalance, value);
|
|
225
|
+
const toUpdatedBalance = (0, math_1.add)(toBalance, value);
|
|
226
|
+
const updatedFromWallet = Object.assign({}, fromWallet, {
|
|
227
|
+
balance: fromUpdatedBalance,
|
|
228
|
+
});
|
|
229
|
+
await this.walletRepository.update(updatedFromWallet, ctx);
|
|
230
|
+
const updatedToWallet = Object.assign({}, toWallet, {
|
|
231
|
+
balance: toUpdatedBalance,
|
|
232
|
+
});
|
|
233
|
+
if (newToWallet) {
|
|
234
|
+
await this.walletRepository.create(updatedToWallet, ctx);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
await this.walletRepository.update(updatedToWallet, ctx);
|
|
238
|
+
}
|
|
239
|
+
// Emit the Transfer event
|
|
240
|
+
const transferEvent = { from, to, value: value };
|
|
241
|
+
const eventHandler = this.repo.ObserverHandler();
|
|
242
|
+
eventHandler.updateObservers(logger, "", erc20_constants_1.ERC20Events.TRANSFER, "", ctx, "", transferEvent);
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Allows `spender` to spend `value` amount of tokens from the owner. New Approve calls override the previous allowance.
|
|
247
|
+
* @note https://eips.ethereum.org/EIPS/eip-20
|
|
248
|
+
*
|
|
249
|
+
* @param {Context} ctx the transaction context
|
|
250
|
+
* @param {String} spender The spender
|
|
251
|
+
* @param {number} value The amount of tokens to be approved for transfer
|
|
252
|
+
* @returns {Boolean} Return whether the approval was successful or not
|
|
253
|
+
*/
|
|
254
|
+
async Approve(ctx, spender, value) {
|
|
255
|
+
// Check contract options are already set first to execute the function
|
|
256
|
+
await this.CheckInitialized(ctx);
|
|
257
|
+
const logger = this.logFor(ctx).for(this.Approve);
|
|
258
|
+
const owner = ctx.clientIdentity.getID();
|
|
259
|
+
let allowance = await this._getAllowance(ctx, owner, spender);
|
|
260
|
+
const ownerWallet = await this.walletRepository.read(owner, ctx);
|
|
261
|
+
if (ownerWallet.balance < value) {
|
|
262
|
+
throw new errors_1.BalanceError(`client account ${owner} has insufficient funds.`);
|
|
263
|
+
}
|
|
264
|
+
if (allowance) {
|
|
265
|
+
// Overwrite the allowance
|
|
266
|
+
allowance.value = value;
|
|
267
|
+
await this.allowanceRepository.update(allowance, ctx);
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
allowance = new models_1.Allowance({
|
|
271
|
+
owner: owner,
|
|
272
|
+
spender: spender,
|
|
273
|
+
value: value,
|
|
274
|
+
});
|
|
275
|
+
await this.allowanceRepository.create(allowance, ctx);
|
|
276
|
+
}
|
|
277
|
+
// Emit the Approval event
|
|
278
|
+
const approvalEvent = { owner, spender, value: value };
|
|
279
|
+
const eventHandler = this.repo.ObserverHandler();
|
|
280
|
+
eventHandler.updateObservers(logger, "", erc20_constants_1.ERC20Events.APPROVAL, "", ctx, "", approvalEvent);
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Returns the amount of tokens which ` ` is allowed to withdraw from `owner`.
|
|
285
|
+
*
|
|
286
|
+
* @param {Context} ctx the transaction context
|
|
287
|
+
* @param {String} owner The owner of tokens
|
|
288
|
+
* @param {String} spender The spender who are able to transfer the tokens
|
|
289
|
+
* @returns {number} Return the amount of remaining tokens allowed to spent
|
|
290
|
+
*/
|
|
291
|
+
async Allowance(ctx, owner, spender) {
|
|
292
|
+
// Check contract options are already set first to execute the function
|
|
293
|
+
await this.CheckInitialized(ctx);
|
|
294
|
+
const allowance = await this._getAllowance(ctx, owner, spender);
|
|
295
|
+
if (!allowance) {
|
|
296
|
+
throw new errors_1.AllowanceError(`spender ${spender} has no allowance from ${owner}`);
|
|
297
|
+
}
|
|
298
|
+
return allowance.value;
|
|
299
|
+
}
|
|
300
|
+
async _getAllowance(ctx, owner, spender) {
|
|
301
|
+
const allowanceCondition = core_1.Condition.and(core_1.Condition.attribute("owner").eq(owner), core_1.Condition.attribute("spender").eq(spender));
|
|
302
|
+
const select = await this.allowanceRepository.selectWithContext(undefined, ctx);
|
|
303
|
+
const allowance = await select.where(allowanceCondition).execute();
|
|
304
|
+
return allowance?.[0];
|
|
305
|
+
}
|
|
306
|
+
// ================== Extended Functions ==========================
|
|
307
|
+
/**
|
|
308
|
+
* Set optional infomation for a token.
|
|
309
|
+
*
|
|
310
|
+
* @param {Context} ctx the transaction context
|
|
311
|
+
* @param {String} name The name of the token
|
|
312
|
+
* @param {String} symbol The symbol of the token
|
|
313
|
+
* @param {String} decimals The decimals of the token
|
|
314
|
+
* @param {String} totalSupply The totalSupply of the token
|
|
315
|
+
*/
|
|
316
|
+
async Initialize(ctx, token) {
|
|
317
|
+
// Check contract options are not already set, client is not authorized to change them once intitialized
|
|
318
|
+
const select = await this.tokenRepository.selectWithContext(undefined, ctx);
|
|
319
|
+
const tokens = await select.execute();
|
|
320
|
+
if (tokens.length > 0) {
|
|
321
|
+
throw new core_1.AuthorizationError("contract options are already set, client is not authorized to change them");
|
|
322
|
+
}
|
|
323
|
+
token.owner = ctx.clientIdentity.getID();
|
|
324
|
+
await this.tokenRepository.create(token, ctx);
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
// Checks that contract options have been already initialized
|
|
328
|
+
async CheckInitialized(ctx) {
|
|
329
|
+
const select = await this.tokenRepository.selectWithContext(undefined, ctx);
|
|
330
|
+
const tokens = await select.execute();
|
|
331
|
+
if (tokens.length == 0) {
|
|
332
|
+
throw new errors_1.NotInitializedError("contract options need to be set before calling any function, call Initialize() to initialize contract");
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Mint creates new tokens and adds them to minter's account balance
|
|
337
|
+
*
|
|
338
|
+
* @param {Context} ctx the transaction context
|
|
339
|
+
* @param {number} amount amount of tokens to be minted
|
|
340
|
+
* @returns {Object} The balance
|
|
341
|
+
*/
|
|
342
|
+
async Mint(ctx, amount) {
|
|
343
|
+
// Check contract options are already set first to execute the function
|
|
344
|
+
await this.CheckInitialized(ctx);
|
|
345
|
+
const logger = this.logFor(ctx).for(this.Mint);
|
|
346
|
+
// Get ID of submitting client identity
|
|
347
|
+
const minter = ctx.clientIdentity.getID();
|
|
348
|
+
if (amount <= 0) {
|
|
349
|
+
throw new db_decorators_1.ValidationError("mint amount must be a positive integer");
|
|
350
|
+
}
|
|
351
|
+
let minterWallet;
|
|
352
|
+
try {
|
|
353
|
+
minterWallet = await this.walletRepository.read(minter, ctx);
|
|
354
|
+
const currentBalance = minterWallet.balance;
|
|
355
|
+
const updatedBalance = (0, math_1.add)(currentBalance, amount);
|
|
356
|
+
const updatedminter = Object.assign({}, minterWallet, {
|
|
357
|
+
balance: updatedBalance,
|
|
358
|
+
});
|
|
359
|
+
await this.walletRepository.update(updatedminter, ctx);
|
|
360
|
+
}
|
|
361
|
+
catch (e) {
|
|
362
|
+
if (e instanceof db_decorators_1.BaseError) {
|
|
363
|
+
if (e.code === 404) {
|
|
364
|
+
// Create a new wallet for the minter
|
|
365
|
+
const newWallet = new models_1.ERC20Wallet({
|
|
366
|
+
id: minter,
|
|
367
|
+
balance: amount,
|
|
368
|
+
token: await this.TokenName(ctx),
|
|
369
|
+
});
|
|
370
|
+
await this.walletRepository.create(newWallet, ctx);
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
throw new db_decorators_1.InternalError(e.message);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
throw new db_decorators_1.InternalError(e);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
// Emit the Transfer event
|
|
381
|
+
const transferEvent = { from: "0x0", to: minter, value: amount };
|
|
382
|
+
const eventHandler = this.repo.ObserverHandler();
|
|
383
|
+
eventHandler.updateObservers(logger, "", erc20_constants_1.ERC20Events.TRANSFER, "", ctx, "", transferEvent);
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Burn redeem tokens from minter's account balance
|
|
387
|
+
*
|
|
388
|
+
* @param {Context} ctx the transaction context
|
|
389
|
+
* @param {number} amount amount of tokens to be burned
|
|
390
|
+
* @returns {Object} The balance
|
|
391
|
+
*/
|
|
392
|
+
async Burn(ctx, amount) {
|
|
393
|
+
// Check contract options are already set first to execute the function
|
|
394
|
+
await this.CheckInitialized(ctx);
|
|
395
|
+
const logger = this.logFor(ctx).for(this.Burn);
|
|
396
|
+
const minter = ctx.clientIdentity.getID();
|
|
397
|
+
const minterWallet = await this.walletRepository.read(minter, ctx);
|
|
398
|
+
const currentBalance = minterWallet.balance;
|
|
399
|
+
if (currentBalance < amount) {
|
|
400
|
+
throw new errors_1.BalanceError(`Minter has insufficient funds.`);
|
|
401
|
+
}
|
|
402
|
+
const updatedBalance = (0, math_1.sub)(currentBalance, amount);
|
|
403
|
+
const updatedminter = Object.assign({}, minterWallet, {
|
|
404
|
+
balance: updatedBalance,
|
|
405
|
+
});
|
|
406
|
+
await this.walletRepository.update(updatedminter, ctx);
|
|
407
|
+
logger.info(`${amount} tokens were burned`);
|
|
408
|
+
// Emit the Transfer event
|
|
409
|
+
const transferEvent = { from: minter, to: "0x0", value: amount };
|
|
410
|
+
const eventHandler = this.repo.ObserverHandler();
|
|
411
|
+
eventHandler.updateObservers(logger, "", erc20_constants_1.ERC20Events.TRANSFER, "", ctx, "", transferEvent);
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* BurnFrom redeem tokens from account allowence and balance
|
|
415
|
+
*
|
|
416
|
+
* @param {Context} ctx the transaction context
|
|
417
|
+
* @param {number} account account from where tokens will be burned
|
|
418
|
+
* @param {number} amount amount of tokens to be burned
|
|
419
|
+
* @returns {Object} The balance
|
|
420
|
+
*/
|
|
421
|
+
async BurnFrom(ctx, account, amount) {
|
|
422
|
+
// Check contract options are already set first to execute the function
|
|
423
|
+
await this.CheckInitialized(ctx);
|
|
424
|
+
const logger = this.logFor(ctx).for(this.BurnFrom);
|
|
425
|
+
const accountWallet = await this.walletRepository.read(account, ctx);
|
|
426
|
+
const currentBalance = accountWallet.balance;
|
|
427
|
+
if (currentBalance < amount) {
|
|
428
|
+
throw new errors_1.BalanceError(`${account} has insufficient funds.`);
|
|
429
|
+
}
|
|
430
|
+
const updatedBalance = (0, math_1.sub)(currentBalance, amount);
|
|
431
|
+
const updatedaccount = Object.assign({}, accountWallet, {
|
|
432
|
+
balance: updatedBalance,
|
|
433
|
+
});
|
|
434
|
+
await this.walletRepository.update(updatedaccount, ctx);
|
|
435
|
+
logger.info(`${amount} tokens were berned from ${account}`);
|
|
436
|
+
// Emit the Transfer event
|
|
437
|
+
const transferEvent = { from: account, to: "0x0", value: amount };
|
|
438
|
+
const eventHandler = this.repo.ObserverHandler();
|
|
439
|
+
eventHandler.updateObservers(logger, "", erc20_constants_1.ERC20Events.TRANSFER, "", ctx, "", transferEvent);
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* ClientAccountBalance returns the balance of the requesting client's account.
|
|
443
|
+
*
|
|
444
|
+
* @param {Context} ctx the transaction context
|
|
445
|
+
* @returns {Number} Returns the account balance
|
|
446
|
+
*/
|
|
447
|
+
async ClientAccountBalance(ctx) {
|
|
448
|
+
// Check contract options are already set first to execute the function
|
|
449
|
+
await this.CheckInitialized(ctx);
|
|
450
|
+
// Get ID of submitting client identity
|
|
451
|
+
const clientAccountID = ctx.clientIdentity.getID();
|
|
452
|
+
const clientWallet = await this.walletRepository.read(clientAccountID, ctx);
|
|
453
|
+
if (!clientWallet) {
|
|
454
|
+
throw new errors_1.BalanceError(`The account ${clientAccountID} does not exist`);
|
|
455
|
+
}
|
|
456
|
+
return clientWallet.balance;
|
|
457
|
+
}
|
|
458
|
+
// ClientAccountID returns the id of the requesting client's account.
|
|
459
|
+
// In this implementation, the client account ID is the clientId itself.
|
|
460
|
+
// Users can use this function to get their own account id, which they can then give to others as the payment address
|
|
461
|
+
async ClientAccountID(ctx) {
|
|
462
|
+
// Check contract options are already set first to execute the function
|
|
463
|
+
await this.CheckInitialized(ctx);
|
|
464
|
+
// Get ID of submitting client identity
|
|
465
|
+
const clientAccountID = ctx.clientIdentity.getID();
|
|
466
|
+
return clientAccountID;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
exports.FabricERC20Contract = FabricERC20Contract;
|
|
470
|
+
__decorate([
|
|
471
|
+
(0, fabric_contract_api_1.Transaction)(false),
|
|
472
|
+
__metadata("design:type", Function),
|
|
473
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context]),
|
|
474
|
+
__metadata("design:returntype", Promise)
|
|
475
|
+
], FabricERC20Contract.prototype, "TokenName", null);
|
|
476
|
+
__decorate([
|
|
477
|
+
(0, fabric_contract_api_1.Transaction)(false),
|
|
478
|
+
__metadata("design:type", Function),
|
|
479
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context]),
|
|
480
|
+
__metadata("design:returntype", Promise)
|
|
481
|
+
], FabricERC20Contract.prototype, "Symbol", null);
|
|
482
|
+
__decorate([
|
|
483
|
+
(0, fabric_contract_api_1.Transaction)(false),
|
|
484
|
+
__metadata("design:type", Function),
|
|
485
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context]),
|
|
486
|
+
__metadata("design:returntype", Promise)
|
|
487
|
+
], FabricERC20Contract.prototype, "Decimals", null);
|
|
488
|
+
__decorate([
|
|
489
|
+
(0, fabric_contract_api_1.Transaction)(false),
|
|
490
|
+
__metadata("design:type", Function),
|
|
491
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context]),
|
|
492
|
+
__metadata("design:returntype", Promise)
|
|
493
|
+
], FabricERC20Contract.prototype, "TotalSupply", null);
|
|
494
|
+
__decorate([
|
|
495
|
+
(0, fabric_contract_api_1.Transaction)(false),
|
|
496
|
+
__metadata("design:type", Function),
|
|
497
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context, String]),
|
|
498
|
+
__metadata("design:returntype", Promise)
|
|
499
|
+
], FabricERC20Contract.prototype, "BalanceOf", null);
|
|
500
|
+
__decorate([
|
|
501
|
+
(0, fabric_contract_api_1.Transaction)(),
|
|
502
|
+
__metadata("design:type", Function),
|
|
503
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context, String, Number]),
|
|
504
|
+
__metadata("design:returntype", Promise)
|
|
505
|
+
], FabricERC20Contract.prototype, "Transfer", null);
|
|
506
|
+
__decorate([
|
|
507
|
+
(0, fabric_contract_api_1.Transaction)(),
|
|
508
|
+
__metadata("design:type", Function),
|
|
509
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context, String, String, Number]),
|
|
510
|
+
__metadata("design:returntype", Promise)
|
|
511
|
+
], FabricERC20Contract.prototype, "TransferFrom", null);
|
|
512
|
+
__decorate([
|
|
513
|
+
(0, fabric_contract_api_1.Transaction)(),
|
|
514
|
+
__metadata("design:type", Function),
|
|
515
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context, String, Number]),
|
|
516
|
+
__metadata("design:returntype", Promise)
|
|
517
|
+
], FabricERC20Contract.prototype, "Approve", null);
|
|
518
|
+
__decorate([
|
|
519
|
+
(0, fabric_contract_api_1.Transaction)(),
|
|
520
|
+
__metadata("design:type", Function),
|
|
521
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context, String, String]),
|
|
522
|
+
__metadata("design:returntype", Promise)
|
|
523
|
+
], FabricERC20Contract.prototype, "Allowance", null);
|
|
524
|
+
__decorate([
|
|
525
|
+
(0, fabric_contract_api_1.Transaction)(),
|
|
526
|
+
__metadata("design:type", Function),
|
|
527
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context, models_1.ERC20Token]),
|
|
528
|
+
__metadata("design:returntype", Promise)
|
|
529
|
+
], FabricERC20Contract.prototype, "Initialize", null);
|
|
530
|
+
__decorate([
|
|
531
|
+
(0, fabric_contract_api_1.Transaction)(false),
|
|
532
|
+
__metadata("design:type", Function),
|
|
533
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context]),
|
|
534
|
+
__metadata("design:returntype", Promise)
|
|
535
|
+
], FabricERC20Contract.prototype, "CheckInitialized", null);
|
|
536
|
+
__decorate([
|
|
537
|
+
(0, decorators_1.Owner)(),
|
|
538
|
+
(0, fabric_contract_api_1.Transaction)(),
|
|
539
|
+
__metadata("design:type", Function),
|
|
540
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context, Number]),
|
|
541
|
+
__metadata("design:returntype", Promise)
|
|
542
|
+
], FabricERC20Contract.prototype, "Mint", null);
|
|
543
|
+
__decorate([
|
|
544
|
+
(0, decorators_1.Owner)(),
|
|
545
|
+
(0, fabric_contract_api_1.Transaction)(),
|
|
546
|
+
__metadata("design:type", Function),
|
|
547
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context, Number]),
|
|
548
|
+
__metadata("design:returntype", Promise)
|
|
549
|
+
], FabricERC20Contract.prototype, "Burn", null);
|
|
550
|
+
__decorate([
|
|
551
|
+
(0, decorators_1.Owner)(),
|
|
552
|
+
(0, fabric_contract_api_1.Transaction)(),
|
|
553
|
+
__metadata("design:type", Function),
|
|
554
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context, String, Number]),
|
|
555
|
+
__metadata("design:returntype", Promise)
|
|
556
|
+
], FabricERC20Contract.prototype, "BurnFrom", null);
|
|
557
|
+
__decorate([
|
|
558
|
+
(0, fabric_contract_api_1.Transaction)(),
|
|
559
|
+
__metadata("design:type", Function),
|
|
560
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context]),
|
|
561
|
+
__metadata("design:returntype", Promise)
|
|
562
|
+
], FabricERC20Contract.prototype, "ClientAccountBalance", null);
|
|
563
|
+
__decorate([
|
|
564
|
+
(0, fabric_contract_api_1.Transaction)(),
|
|
565
|
+
__metadata("design:type", Function),
|
|
566
|
+
__metadata("design:paramtypes", [fabric_contract_api_1.Context]),
|
|
567
|
+
__metadata("design:returntype", Promise)
|
|
568
|
+
], FabricERC20Contract.prototype, "ClientAccountID", null);
|
|
569
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJjMjBjb250cmFjdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb250cmFjdHMvZXJjMjAvZXJjMjBjb250cmFjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFBQSx5Q0FBK0Q7QUFDL0QsNkRBQTJEO0FBQzNELGtEQUE2QztBQUM3QyxzREFJNkI7QUFDN0IsOERBQTJEO0FBQzNELHlDQUE4RDtBQUM5RCw4REFBZ0Q7QUFDaEQsZ0ZBQXVFO0FBQ3ZFLDJEQUtpQztBQUNqQywrREFBMkQ7QUFFM0QsOEVBQWlFO0FBRWpFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F3Qkc7QUFDSCxNQUFzQixtQkFBb0IsU0FBUSxrQ0FBK0I7SUFPL0UsWUFBc0IsSUFBWTtRQUNoQyxLQUFLLENBQUMsSUFBSSxFQUFFLG9CQUFXLENBQUMsQ0FBQztRQUV6QixtQkFBbUIsQ0FBQyxPQUFPO1lBQ3pCLG1CQUFtQixDQUFDLE9BQU8sSUFBSSxJQUFJLHVDQUFxQixFQUFFLENBQUM7UUFFN0QsSUFBSSxDQUFDLGdCQUFnQixHQUFHLG1EQUF3QixDQUFDLFFBQVEsQ0FDdkQsb0JBQVcsRUFDWCxtQkFBbUIsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUNsQyxDQUFDO1FBRUYsSUFBSSxDQUFDLGVBQWUsR0FBRyxtREFBd0IsQ0FBQyxRQUFRLENBQ3RELG1CQUFVLEVBQ1YsbUJBQW1CLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FDbEMsQ0FBQztRQUVGLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxtREFBd0IsQ0FBQyxRQUFRLENBQzFELGtCQUFTLEVBQ1QsbUJBQW1CLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FDbEMsQ0FBQztJQUNKLENBQUM7SUFHSyxBQUFOLEtBQUssQ0FBQyxTQUFTLENBQUMsR0FBWTtRQUMxQix1RUFBdUU7UUFDdkUsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFakMsTUFB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Q0FBVyxHQUFFOztxQ0FFUCw2QkFBTzs7dURBMkNiO0FBb0dLO0lBREwsSUFBQSxpQ0FBVyxHQUFFOztxQ0FFUCw2QkFBTzs7a0RBK0NiO0FBV0s7SUFETCxJQUFBLGlDQUFXLEdBQUU7O3FDQUVQLDZCQUFPOztvREFlYjtBQWdDSztJQURMLElBQUEsaUNBQVcsR0FBRTs7cUNBQ1EsNkJBQU8sRUFBUyxtQkFBVTs7cURBZS9DO0FBSUs7SUFETCxJQUFBLGlDQUFXLEVBQUMsS0FBSyxDQUFDOztxQ0FDUyw2QkFBTzs7MkRBUWxDO0FBV0s7SUFGTCxJQUFBLGtCQUFLLEdBQUU7SUFDUCxJQUFBLGlDQUFXLEdBQUU7O3FDQUNFLDZCQUFPOzsrQ0F5RHRCO0FBV0s7SUFGTCxJQUFBLGtCQUFLLEdBQUU7SUFDUCxJQUFBLGlDQUFXLEdBQUU7O3FDQUNFLDZCQUFPOzsrQ0F1Q3RCO0FBWUs7SUFGTCxJQUFBLGtCQUFLLEdBQUU7SUFDUCxJQUFBLGlDQUFXLEdBQUU7O3FDQUNNLDZCQUFPOzttREFxQzFCO0FBU0s7SUFETCxJQUFBLGlDQUFXLEdBQUU7O3FDQUNrQiw2QkFBTzs7K0RBY3RDO0FBTUs7SUFETCxJQUFBLGlDQUFXLEdBQUU7O3FDQUNhLDZCQUFPOzswREFPakMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBdXRob3JpemF0aW9uRXJyb3IsIENvbmRpdGlvbiB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgQ29udGV4dCwgVHJhbnNhY3Rpb24gfSBmcm9tIFwiZmFicmljLWNvbnRyYWN0LWFwaVwiO1xuaW1wb3J0IHsgYWRkLCBzdWIgfSBmcm9tIFwiLi4vLi4vc2hhcmVkL21hdGhcIjtcbmltcG9ydCB7XG4gIEFsbG93YW5jZUVycm9yLFxuICBCYWxhbmNlRXJyb3IsXG4gIE5vdEluaXRpYWxpemVkRXJyb3IsXG59IGZyb20gXCIuLi8uLi9zaGFyZWQvZXJyb3JzXCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdEFkYXB0ZXIgfSBmcm9tIFwiLi4vQ29udHJhY3RBZGFwdGVyXCI7XG5pbXBvcnQgeyBBbGxvd2FuY2UsIEVSQzIwVG9rZW4sIEVSQzIwV2FsbGV0IH0gZnJvbSBcIi4vbW9kZWxzXCI7XG5pbXBvcnQgeyBPd25lciB9IGZyb20gXCIuLi8uLi9zaGFyZWQvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5IH0gZnJvbSBcIi4uL0ZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeVwiO1xuaW1wb3J0IHtcbiAgQmFzZUVycm9yLFxuICBJbnRlcm5hbEVycm9yLFxuICBOb3RGb3VuZEVycm9yLFxuICBWYWxpZGF0aW9uRXJyb3IsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgRmFicmljQ3J1ZENvbnRyYWN0IH0gZnJvbSBcIi4uL2NydWQvY3J1ZC1jb250cmFjdFwiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXIgfSBmcm9tIFwiLi4vRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXJcIjtcbmltcG9ydCB7IEVSQzIwRXZlbnRzIH0gZnJvbSBcIi4uLy4uL3NoYXJlZC9lcmMyMC9lcmMyMC1jb25zdGFudHNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRVJDMjAgdG9rZW4gY29udHJhY3QgYmFzZSBmb3IgSHlwZXJsZWRnZXIgRmFicmljXG4gKiBAc3VtbWFyeSBJbXBsZW1lbnRzIEVSQzIwLWxpa2UgdG9rZW4gbG9naWMgdXNpbmcgcmVwb3NpdG9yaWVzIGFuZCBhZGFwdGVycywgcHJvdmlkaW5nIHN0YW5kYXJkIHRva2VuIG9wZXJhdGlvbnMgc3VjaCBhcyBiYWxhbmNlIHF1ZXJpZXMsIHRyYW5zZmVycywgYXBwcm92YWxzLCBtaW50aW5nIGFuZCBidXJuaW5nLlxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgY29udHJhY3QgbmFtZSB1c2VkIHRvIHNjb3BlIHRva2VuIGlkZW50aXR5XG4gKiBAbm90ZSBodHRwczovL2VpcHMuZXRoZXJldW0ub3JnL0VJUFMvZWlwLTIwXG4gKiBAcmV0dXJuIHt2b2lkfVxuICogQGNsYXNzIEZhYnJpY0VSQzIwQ29udHJhY3RcbiAqIEBleGFtcGxlXG4gKiBjbGFzcyBNeVRva2VuQ29udHJhY3QgZXh0ZW5kcyBGYWJyaWNFUkMyMENvbnRyYWN0IHtcbiAqICAgY29uc3RydWN0b3IoKSB7IHN1cGVyKCdNeVRva2VuJyk7IH1cbiAqIH1cbiAqIC8vIFRoZSBjb250cmFjdCBleHBvc2VzIG1ldGhvZHMgbGlrZSBUcmFuc2ZlciwgQXBwcm92ZSwgTWludCwgQnVybiwgZXRjLlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDbGllbnRcbiAqICAgcGFydGljaXBhbnQgQ29udHJhY3RcbiAqICAgcGFydGljaXBhbnQgV2FsbGV0UmVwb1xuICogICBwYXJ0aWNpcGFudCBUb2tlblJlcG9cbiAqICAgcGFydGljaXBhbnQgTGVkZ2VyXG4gKiAgIENsaWVudC0+PkNvbnRyYWN0OiBUcmFuc2ZlcihjdHgsIHRvLCB2YWx1ZSlcbiAqICAgQ29udHJhY3QtPj5XYWxsZXRSZXBvOiByZWFkKGZyb20pXG4gKiAgIENvbnRyYWN0LT4+V2FsbGV0UmVwbzogcmVhZCh0bylcbiAqICAgQ29udHJhY3QtPj5MZWRnZXI6IHB1dFN0YXRlKHVwZGF0ZWQgYmFsYW5jZXMpXG4gKiAgIENvbnRyYWN0LS0+PkNsaWVudDogc3VjY2Vzc1xuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgRmFicmljRVJDMjBDb250cmFjdCBleHRlbmRzIEZhYnJpY0NydWRDb250cmFjdDxFUkMyMFdhbGxldD4ge1xuICBwcml2YXRlIHdhbGxldFJlcG9zaXRvcnk6IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxFUkMyMFdhbGxldD47XG5cbiAgcHJpdmF0ZSB0b2tlblJlcG9zaXRvcnk6IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxFUkMyMFRva2VuPjtcblxuICBwcml2YXRlIGFsbG93YW5jZVJlcG9zaXRvcnk6IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxBbGxvd2FuY2U+O1xuXG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihuYW1lOiBzdHJpbmcpIHtcbiAgICBzdXBlcihuYW1lLCBFUkMyMFdhbGxldCk7XG5cbiAgICBGYWJyaWNFUkMyMENvbnRyYWN0LmFkYXB0ZXIgPVxuICAgICAgRmFicmljRVJDMjBDb250cmFjdC5hZGFwdGVyIHx8IG5ldyBGYWJyaWNDb250cmFjdEFkYXB0ZXIoKTtcblxuICAgIHRoaXMud2FsbGV0UmVwb3NpdG9yeSA9IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeS5mb3JNb2RlbChcbiAgICAgIEVSQzIwV2FsbGV0LFxuICAgICAgRmFicmljRVJDMjBDb250cmFjdC5hZGFwdGVyLmFsaWFzXG4gICAgKTtcblxuICAgIHRoaXMudG9rZW5SZXBvc2l0b3J5ID0gRmFicmljQ29udHJhY3RSZXBvc2l0b3J5LmZvck1vZGVsKFxuICAgICAgRVJDMjBUb2tlbixcbiAgICAgIEZhYnJpY0VSQzIwQ29udHJhY3QuYWRhcHRlci5hbGlhc1xuICAgICk7XG5cbiAgICB0aGlzLmFsbG93YW5jZVJlcG9zaXRvcnkgPSBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnkuZm9yTW9kZWwoXG4gICAgICBBbGxvd2FuY2UsXG4gICAgICBGYWJyaWNFUkMyMENvbnRyYWN0LmFkYXB0ZXIuYWxpYXNcbiAgICApO1xuICB9XG5cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBUb2tlbk5hbWUoY3R4OiBDb250ZXh0KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHgpO1xuXG4gICAgY29uc3Qgc2VsZWN0ID0gYXdhaXQgdGhpcy50b2tlblJlcG9zaXRvcnkuc2VsZWN0V2l0aENvbnRleHQodW5kZWZpbmVkLCBjdHgpO1xuICAgIGNvbnN0IHRva2VuID0gKGF3YWl0IHNlbGVjdC5leGVjdXRlKCkpWzBdO1xuXG4gICAgcmV0dXJuIHRva2VuLm5hbWU7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBzeW1ib2wgb2YgdGhlIHRva2VuLiBFLmcuIOKAnEhJWOKAnS5cbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjdHggdGhlIHRyYW5zYWN0aW9uIGNvbnRleHRcbiAgICogQHJldHVybnMge1N0cmluZ30gUmV0dXJucyB0aGUgc3ltYm9sIG9mIHRoZSB0b2tlblxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBTeW1ib2woY3R4OiBDb250ZXh0KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHgpO1xuXG4gICAgY29uc3Qgc2VsZWN0ID0gYXdhaXQgdGhpcy50b2tlblJlcG9zaXRvcnkuc2VsZWN0V2l0aENvbnRleHQodW5kZWZpbmVkLCBjdHgpO1xuICAgIGNvbnN0IHRva2VuID0gKGF3YWl0IHNlbGVjdC5leGVjdXRlKCkpWzBdO1xuXG4gICAgcmV0dXJuIHRva2VuLnN5bWJvbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIG51bWJlciBvZiBkZWNpbWFscyB0aGUgdG9rZW4gdXNlc1xuICAgKiBlLmcuIDgsIG1lYW5zIHRvIGRpdmlkZSB0aGUgdG9rZW4gYW1vdW50IGJ5IDEwMDAwMDAwMCB0byBnZXQgaXRzIHVzZXIgcmVwcmVzZW50YXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY3R4IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgdGhlIG51bWJlciBvZiBkZWNpbWFsc1xuICAgKi9cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBEZWNpbWFscyhjdHg6IENvbnRleHQpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCk7XG5cbiAgICBjb25zdCBzZWxlY3QgPSBhd2FpdCB0aGlzLnRva2VuUmVwb3NpdG9yeS5zZWxlY3RXaXRoQ29udGV4dCh1bmRlZmluZWQsIGN0eCk7XG4gICAgY29uc3QgdG9rZW4gPSAoYXdhaXQgc2VsZWN0LmV4ZWN1dGUoKSlbMF07XG5cbiAgICByZXR1cm4gdG9rZW4uZGVjaW1hbHM7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSB0b3RhbCB0b2tlbiBzdXBwbHkuXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY3R4IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgdGhlIHRvdGFsIHRva2VuIHN1cHBseVxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBUb3RhbFN1cHBseShjdHg6IENvbnRleHQpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCk7XG5cbiAgICBjb25zdCBzZWxlY3QgPSBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkuc2VsZWN0V2l0aENvbnRleHQoXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBjdHhcbiAgICApO1xuICAgIGNvbnN0IHdhbGxldHMgPSBhd2FpdCBzZWxlY3QuZXhlY3V0ZSgpO1xuXG4gICAgaWYgKHdhbGxldHMubGVuZ3RoID09IDApIHtcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEVycm9yKGBUaGUgdG9rZW4gJHt0aGlzLmdldE5hbWUoKX0gZG9lcyBub3QgZXhpc3RgKTtcbiAgICB9XG5cbiAgICBsZXQgdG90YWwgPSAwO1xuXG4gICAgd2FsbGV0cy5mb3JFYWNoKCh3YWxsZXQpID0+IHtcbiAgICAgIHRvdGFsICs9IHdhbGxldC5iYWxhbmNlO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRvdGFsO1xuICB9XG5cbiAgLyoqXG4gICAqIEJhbGFuY2VPZiByZXR1cm5zIHRoZSBiYWxhbmNlIG9mIHRoZSBnaXZlbiBhY2NvdW50LlxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGN0eCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge1N0cmluZ30gb3duZXIgVGhlIG93bmVyIGZyb20gd2hpY2ggdGhlIGJhbGFuY2Ugd2lsbCBiZSByZXRyaWV2ZWRcbiAgICogQHJldHVybnMge051bWJlcn0gUmV0dXJucyB0aGUgYWNjb3VudCBiYWxhbmNlXG4gICAqL1xuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIGFzeW5jIEJhbGFuY2VPZihjdHg6IENvbnRleHQsIG93bmVyOiBzdHJpbmcpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCk7XG5cbiAgICBjb25zdCB3YWxsZXQgPSBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkucmVhZChvd25lciwgY3R4KTtcblxuICAgIHJldHVybiB3YWxsZXQuYmFsYW5jZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAc3VtbWFyeSBUcmFuc2ZlciB0cmFuc2ZlcnMgdG9rZW5zIGZyb20gY2xpZW50IGFjY291bnQgdG8gcmVjaXBpZW50IGFjY291bnQuXG4gICAqIEBkZXNjcmlwdGlvbiByZWNpcGllbnQgYWNjb3VudCBtdXN0IGJlIGEgdmFsaWQgY2xpZW50SUQgYXMgcmV0dXJuZWQgYnkgdGhlIENsaWVudEFjY291bnRJRCgpIGZ1bmN0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGN0eCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge1N0cmluZ30gdG8gVGhlIHJlY2lwaWVudFxuICAgKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgVGhlIGFtb3VudCBvZiB0b2tlbiB0byBiZSB0cmFuc2ZlcnJlZFxuICAgKlxuICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gUmV0dXJuIHdoZXRoZXIgdGhlIHRyYW5zZmVyIHdhcyBzdWNjZXNzZnVsIG9yIG5vdFxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKClcbiAgYXN5bmMgVHJhbnNmZXIoY3R4OiBDb250ZXh0LCB0bzogc3RyaW5nLCB2YWx1ZTogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQgZmlyc3QgdG8gZXhlY3V0ZSB0aGUgZnVuY3Rpb25cbiAgICBhd2FpdCB0aGlzLkNoZWNrSW5pdGlhbGl6ZWQoY3R4KTtcblxuICAgIGNvbnN0IGZyb20gPSBjdHguY2xpZW50SWRlbnRpdHkuZ2V0SUQoKTtcblxuICAgIGNvbnN0IHRyYW5zZmVyUmVzcCA9IGF3YWl0IHRoaXMuX3RyYW5zZmVyKGN0eCwgZnJvbSwgdG8sIHZhbHVlKTtcbiAgICBpZiAoIXRyYW5zZmVyUmVzcCkge1xuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJGYWlsZWQgdG8gdHJhbnNmZXJcIik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogVHJhbnNmZXIgYHZhbHVlYCBhbW91bnQgb2YgdG9rZW5zIGZyb20gYGZyb21gIHRvIGB0b2AuXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY3R4IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBmcm9tIFRoZSBzZW5kZXJcbiAgICogQHBhcmFtIHtTdHJpbmd9IHRvIFRoZSByZWNpcGllbnRcbiAgICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIFRoZSBhbW91bnQgb2YgdG9rZW4gdG8gYmUgdHJhbnNmZXJyZWRcbiAgICogQHJldHVybnMge0Jvb2xlYW59IFJldHVybiB3aGV0aGVyIHRoZSB0cmFuc2ZlciB3YXMgc3VjY2Vzc2Z1bCBvciBub3RcbiAgICovXG4gIEBUcmFuc2FjdGlvbigpXG4gIGFzeW5jIFRyYW5zZmVyRnJvbShcbiAgICBjdHg6IENvbnRleHQsXG4gICAgZnJvbTogc3RyaW5nLFxuICAgIHRvOiBzdHJpbmcsXG4gICAgdmFsdWU6IG51bWJlclxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHgpO1xuXG4gICAgLy8gUmV0cmlldmUgdGhlIGFsbG93YW5jZSBvZiB0aGUgc3BlbmRlclxuXG4gICAgY29uc3Qgc3BlbmRlciA9IGN0eC5jbGllbnRJZGVudGl0eS5nZXRJRCgpO1xuXG4gICAgY29uc3QgYWxsb3dhbmNlID0gYXdhaXQgdGhpcy5fZ2V0QWxsb3dhbmNlKGN0eCwgZnJvbSwgc3BlbmRlcik7XG4gICAgaWYgKCFhbGxvd2FuY2UgfHwgYWxsb3dhbmNlLnZhbHVlIDwgMCkge1xuICAgICAgdGhyb3cgbmV3IEFsbG93YW5jZUVycm9yKFxuICAgICAgICBgc3BlbmRlciAke3NwZW5kZXJ9IGhhcyBubyBhbGxvd2FuY2UgZnJvbSAke2Zyb219YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJyZW50QWxsb3dhbmNlID0gYWxsb3dhbmNlLnZhbHVlO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHRyYW5zZmVycmVkIHZhbHVlIGlzIGxlc3MgdGhhbiB0aGUgYWxsb3dhbmNlXG4gICAgaWYgKGN1cnJlbnRBbGxvd2FuY2UgPCB2YWx1ZSkge1xuICAgICAgdGhyb3cgbmV3IEJhbGFuY2VFcnJvcihcbiAgICAgICAgXCJUaGUgc3BlbmRlciBkb2VzIG5vdCBoYXZlIGVub3VnaCBhbGxvd2FuY2UgdG8gc3BlbmQuXCJcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gRGVjcmVhc2UgdGhlIGFsbG93YW5jZVxuICAgIGNvbnN0IHVwZGF0ZWRBbGxvd2FuY2UgPSBzdWIoY3VycmVudEFsbG93YW5jZSwgdmFsdWUpO1xuICAgIGNvbnN0IG5ld0FsbG93YW5jZSA9IE9iamVjdC5hc3NpZ24oe30sIGFsbG93YW5jZSwge1xuICAgICAgdmFsdWU6IHVwZGF0ZWRBbGxvd2FuY2UsXG4gICAgfSk7XG5cbiAgICBhd2FpdCB0aGlzLmFsbG93YW5jZVJlcG9zaXRvcnkudXBkYXRlKG5ld0FsbG93YW5jZSwgY3R4KTtcblxuICAgIC8vUmVhbGl6ZSB0aGUgdHJhbnNmZXJcbiAgICBjb25zdCB0cmFuc2ZlclJlc3AgPSBhd2FpdCB0aGlzLl90cmFuc2ZlcihjdHgsIGZyb20sIHRvLCB2YWx1ZSk7XG4gICAgaWYgKCF0cmFuc2ZlclJlc3ApIHtcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiRmFpbGVkIHRvIHRyYW5zZmVyXCIpO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgYXN5bmMgX3RyYW5zZmVyKGN0eDogQ29udGV4dCwgZnJvbTogc3RyaW5nLCB0bzogc3RyaW5nLCB2YWx1ZTogbnVtYmVyKSB7XG4gICAgY29uc3QgbG9nZ2VyID0gdGhpcy5sb2dGb3IoY3R4KS5mb3IodGhpcy5fdHJhbnNmZXIpO1xuXG4gICAgaWYgKGZyb20gPT09IHRvKSB7XG4gICAgICB0aHJvdyBuZXcgQXV0aG9yaXphdGlvbkVycm9yKFxuICAgICAgICBcImNhbm5vdCB0cmFuc2ZlciB0byBhbmQgZnJvbSBzYW1lIGNsaWVudCBhY2NvdW50XCJcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKHZhbHVlIDwgMCkge1xuICAgICAgLy8gdHJhbnNmZXIgb2YgMCBpcyBhbGxvd2VkIGluIEVSQzIwLCBzbyBqdXN0IHZhbGlkYXRlIGFnYWluc3QgbmVnYXRpdmUgYW1vdW50c1xuICAgICAgdGhyb3cgbmV3IEJhbGFuY2VFcnJvcihcInRyYW5zZmVyIGFtb3VudCBjYW5ub3QgYmUgbmVnYXRpdmVcIik7XG4gICAgfVxuXG4gICAgLy8gUmV0cmlldmUgdGhlIGN1cnJlbnQgYmFsYW5jZSBvZiB0aGUgc2VuZGVyXG5cbiAgICBjb25zdCBmcm9tV2FsbGV0ID0gYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnJlYWQoZnJvbSwgY3R4KTtcblxuICAgIGNvbnN0IGZyb21CYWxhbmNlID0gZnJvbVdhbGxldC5iYWxhbmNlO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHNlbmRlciBoYXMgZW5vdWdoIHRva2VucyB0byBzcGVuZC5cbiAgICBpZiAoZnJvbUJhbGFuY2UgPCB2YWx1ZSkge1xuICAgICAgdGhyb3cgbmV3IEJhbGFuY2VFcnJvcihgY2xpZW50IGFjY291bnQgJHtmcm9tfSBoYXMgaW5zdWZmaWNpZW50IGZ1bmRzLmApO1xuICAgIH1cblxuICAgIC8vIFJldHJpZXZlIHRoZSBjdXJyZW50IGJhbGFuY2Ugb2YgdGhlIHJlY2VwaWVudFxuXG4gICAgbGV0IHRvV2FsbGV0OiBFUkMyMFdhbGxldDtcbiAgICBsZXQgbmV3VG9XYWxsZXQ6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICB0cnkge1xuICAgICAgdG9XYWxsZXQgPSBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkucmVhZCh0bywgY3R4KTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICBpZiAoZSBpbnN0YW5jZW9mIEJhc2VFcnJvcikge1xuICAgICAgICBpZiAoZS5jb2RlID09PSA0MDQpIHtcbiAgICAgICAgICAvLyBDcmVhdGUgYSBuZXcgd2FsbGV0IGZvciB0aGUgbWludGVyXG4gICAgICAgICAgdG9XYWxsZXQgPSBuZXcgRVJDMjBXYWxsZXQoe1xuICAgICAgICAgICAgaWQ6IHRvLFxuICAgICAgICAgICAgYmFsYW5jZTogMCxcbiAgICAgICAgICAgIHRva2VuOiBhd2FpdCB0aGlzLlRva2VuTmFtZShjdHgpLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIG5ld1RvV2FsbGV0ID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihlLm1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihlIGFzIHN0cmluZyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgdG9CYWxhbmNlID0gdG9XYWxsZXQuYmFsYW5jZTtcblxuICAgIC8vIFVwZGF0ZSB0aGUgYmFsYW5jZVxuICAgIGNvbnN0IGZyb21VcGRhdGVkQmFsYW5jZSA9IHN1Yihmcm9tQmFsYW5jZSwgdmFsdWUpO1xuICAgIGNvbnN0IHRvVXBkYXRlZEJhbGFuY2UgPSBhZGQodG9CYWxhbmNlLCB2YWx1ZSk7XG5cbiAgICBjb25zdCB1cGRhdGVkRnJvbVdhbGxldCA9IE9iamVjdC5hc3NpZ24oe30sIGZyb21XYWxsZXQsIHtcbiAgICAgIGJhbGFuY2U6IGZyb21VcGRhdGVkQmFsYW5jZSxcbiAgICB9KTtcblxuICAgIGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS51cGRhdGUodXBkYXRlZEZyb21XYWxsZXQsIGN0eCk7XG5cbiAgICBjb25zdCB1cGRhdGVkVG9XYWxsZXQgPSBPYmplY3QuYXNzaWduKHt9LCB0b1dhbGxldCwge1xuICAgICAgYmFsYW5jZTogdG9VcGRhdGVkQmFsYW5jZSxcbiAgICB9KTtcblxuICAgIGlmIChuZXdUb1dhbGxldCkge1xuICAgICAgYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LmNyZWF0ZSh1cGRhdGVkVG9XYWxsZXQsIGN0eCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS51cGRhdGUodXBkYXRlZFRvV2FsbGV0LCBjdHgpO1xuICAgIH1cblxuICAgIC8vIEVtaXQgdGhlIFRyYW5zZmVyIGV2ZW50XG4gICAgY29uc3QgdHJhbnNmZXJFdmVudCA9IHsgZnJvbSwgdG8sIHZhbHVlOiB2YWx1ZSB9O1xuICAgIGNvbnN0IGV2ZW50SGFuZGxlciA9XG4gICAgICB0aGlzLnJlcG8uT2JzZXJ2ZXJIYW5kbGVyKCkgYXMgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXI7XG4gICAgZXZlbnRIYW5kbGVyLnVwZGF0ZU9ic2VydmVycyhcbiAgICAgIGxvZ2dlcixcbiAgICAgIFwiXCIsXG4gICAgICBFUkMyMEV2ZW50cy5UUkFOU0ZFUixcbiAgICAgIFwiXCIsXG4gICAgICBjdHgsXG4gICAgICBcIlwiLFxuICAgICAgdHJhbnNmZXJFdmVudFxuICAgICk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbGxvd3MgYHNwZW5kZXJgIHRvIHNwZW5kIGB2YWx1ZWAgYW1vdW50IG9mIHRva2VucyBmcm9tIHRoZSBvd25lci4gTmV3IEFwcHJvdmUgY2FsbHMgb3ZlcnJpZGUgdGhlIHByZXZpb3VzIGFsbG93YW5jZS5cbiAgICogQG5vdGUgaHR0cHM6Ly9laXBzLmV0aGVyZXVtLm9yZy9FSVBTL2VpcC0yMFxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGN0eCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge1N0cmluZ30gc3BlbmRlciBUaGUgc3BlbmRlclxuICAgKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgVGhlIGFtb3VudCBvZiB0b2tlbnMgdG8gYmUgYXBwcm92ZWQgZm9yIHRyYW5zZmVyXG4gICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm4gd2hldGhlciB0aGUgYXBwcm92YWwgd2FzIHN1Y2Nlc3NmdWwgb3Igbm90XG4gICAqL1xuICBAVHJhbnNhY3Rpb24oKVxuICBhc3luYyBBcHByb3ZlKFxuICAgIGN0eDogQ29udGV4dCxcbiAgICBzcGVuZGVyOiBzdHJpbmcsXG4gICAgdmFsdWU6IG51bWJlclxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHgpO1xuICAgIGNvbnN0IGxvZ2dlciA9IHRoaXMubG9nRm9yKGN0eCkuZm9yKHRoaXMuQXBwcm92ZSk7XG5cbiAgICBjb25zdCBvd25lciA9IGN0eC5jbGllbnRJZGVudGl0eS5nZXRJRCgpO1xuXG4gICAgbGV0IGFsbG93YW5jZSA9IGF3YWl0IHRoaXMuX2dldEFsbG93YW5jZShjdHgsIG93bmVyLCBzcGVuZGVyKTtcblxuICAgIGNvbnN0IG93bmVyV2FsbGV0ID0gYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnJlYWQob3duZXIsIGN0eCk7XG5cbiAgICBpZiAob3duZXJXYWxsZXQuYmFsYW5jZSA8IHZhbHVlKSB7XG4gICAgICB0aHJvdyBuZXcgQmFsYW5jZUVycm9yKGBjbGllbnQgYWNjb3VudCAke293bmVyfSBoYXMgaW5zdWZmaWNpZW50IGZ1bmRzLmApO1xuICAgIH1cblxuICAgIGlmIChhbGxvd2FuY2UpIHtcbiAgICAgIC8vIE92ZXJ3cml0ZSB0aGUgYWxsb3dhbmNlXG4gICAgICBhbGxvd2FuY2UudmFsdWUgPSB2YWx1ZTtcbiAgICAgIGF3YWl0IHRoaXMuYWxsb3dhbmNlUmVwb3NpdG9yeS51cGRhdGUoYWxsb3dhbmNlLCBjdHgpO1xuICAgIH0gZWxzZSB7XG4gICAgICBhbGxvd2FuY2UgPSBuZXcgQWxsb3dhbmNlKHtcbiAgICAgICAgb3duZXI6IG93bmVyLFxuICAgICAgICBzcGVuZGVyOiBzcGVuZGVyLFxuICAgICAgICB2YWx1ZTogdmFsdWUsXG4gICAgICB9KTtcblxuICAgICAgYXdhaXQgdGhpcy5hbGxvd2FuY2VSZXBvc2l0b3J5LmNyZWF0ZShhbGxvd2FuY2UsIGN0eCk7XG4gICAgfVxuXG4gICAgLy8gRW1pdCB0aGUgQXBwcm92YWwgZXZlbnRcbiAgICBjb25zdCBhcHByb3ZhbEV2ZW50ID0geyBvd25lciwgc3BlbmRlciwgdmFsdWU6IHZhbHVlIH07XG4gICAgY29uc3QgZXZlbnRIYW5kbGVyID1cbiAgICAgIHRoaXMucmVwby5PYnNlcnZlckhhbmRsZXIoKSBhcyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnlPYnNlcnZhYmxlSGFuZGxlcjtcbiAgICBldmVudEhhbmRsZXIudXBkYXRlT2JzZXJ2ZXJzKFxuICAgICAgbG9nZ2VyLFxuICAgICAgXCJcIixcbiAgICAgIEVSQzIwRXZlbnRzLkFQUFJPVkFMLFxuICAgICAgXCJcIixcbiAgICAgIGN0eCxcbiAgICAgIFwiXCIsXG4gICAgICBhcHByb3ZhbEV2ZW50XG4gICAgKTtcblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGFtb3VudCBvZiB0b2tlbnMgd2hpY2ggYCBgIGlzIGFsbG93ZWQgdG8gd2l0aGRyYXcgZnJvbSBgb3duZXJgLlxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGN0eCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge1N0cmluZ30gb3duZXIgVGhlIG93bmVyIG9mIHRva2Vuc1xuICAgKiBAcGFyYW0ge1N0cmluZ30gc3BlbmRlciBUaGUgc3BlbmRlciB3aG8gYXJlIGFibGUgdG8gdHJhbnNmZXIgdGhlIHRva2Vuc1xuICAgKiBAcmV0dXJucyB7bnVtYmVyfSBSZXR1cm4gdGhlIGFtb3VudCBvZiByZW1haW5pbmcgdG9rZW5zIGFsbG93ZWQgdG8gc3BlbnRcbiAgICovXG4gIEBUcmFuc2FjdGlvbigpXG4gIGFzeW5jIEFsbG93YW5jZShcbiAgICBjdHg6IENvbnRleHQsXG4gICAgb3duZXI6IHN0cmluZyxcbiAgICBzcGVuZGVyOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHgpO1xuXG4gICAgY29uc3QgYWxsb3dhbmNlID0gYXdhaXQgdGhpcy5fZ2V0QWxsb3dhbmNlKGN0eCwgb3duZXIsIHNwZW5kZXIpO1xuXG4gICAgaWYgKCFhbGxvd2FuY2UpIHtcbiAgICAgIHRocm93IG5ldyBBbGxvd2FuY2VFcnJvcihcbiAgICAgICAgYHNwZW5kZXIgJHtzcGVuZGVyfSBoYXMgbm8gYWxsb3dhbmNlIGZyb20gJHtvd25lcn1gXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gYWxsb3dhbmNlLnZhbHVlO1xuICB9XG5cbiAgYXN5bmMgX2dldEFsbG93YW5jZShcbiAgICBjdHg6IENvbnRleHQsXG4gICAgb3duZXI6IHN0cmluZyxcbiAgICBzcGVuZGVyOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxBbGxvd2FuY2U+IHtcbiAgICBjb25zdCBhbGxvd2FuY2VDb25kaXRpb24gPSBDb25kaXRpb24uYW5kKFxuICAgICAgQ29uZGl0aW9uLmF0dHJpYnV0ZTxBbGxvd2FuY2U+KFwib3duZXJcIikuZXEob3duZXIpLFxuICAgICAgQ29uZGl0aW9uLmF0dHJpYnV0ZTxBbGxvd2FuY2U+KFwic3BlbmRlclwiKS5lcShzcGVuZGVyKVxuICAgICk7XG5cbiAgICBjb25zdCBzZWxlY3QgPSBhd2FpdCB0aGlzLmFsbG93YW5jZVJlcG9zaXRvcnkuc2VsZWN0V2l0aENvbnRleHQoXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBjdHhcbiAgICApO1xuICAgIGNvbnN0IGFsbG93YW5jZSA9IGF3YWl0IHNlbGVjdC53aGVyZShhbGxvd2FuY2VDb25kaXRpb24pLmV4ZWN1dGUoKTtcbiAgICByZXR1cm4gYWxsb3dhbmNlPy5bMF07XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT0gRXh0ZW5kZWQgRnVuY3Rpb25zID09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIFNldCBvcHRpb25hbCBpbmZvbWF0aW9uIGZvciBhIHRva2VuLlxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGN0eCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBUaGUgbmFtZSBvZiB0aGUgdG9rZW5cbiAgICogQHBhcmFtIHtTdHJpbmd9IHN5bWJvbCBUaGUgc3ltYm9sIG9mIHRoZSB0b2tlblxuICAgKiBAcGFyYW0ge1N0cmluZ30gZGVjaW1hbHMgVGhlIGRlY2ltYWxzIG9mIHRoZSB0b2tlblxuICAgKiBAcGFyYW0ge1N0cmluZ30gdG90YWxTdXBwbHkgVGhlIHRvdGFsU3VwcGx5IG9mIHRoZSB0b2tlblxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKClcbiAgYXN5bmMgSW5pdGlhbGl6ZShjdHg6IENvbnRleHQsIHRva2VuOiBFUkMyMFRva2VuKSB7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgbm90IGFscmVhZHkgc2V0LCBjbGllbnQgaXMgbm90IGF1dGhvcml6ZWQgdG8gY2hhbmdlIHRoZW0gb25jZSBpbnRpdGlhbGl6ZWRcbiAgICBjb25zdCBzZWxlY3QgPSBhd2FpdCB0aGlzLnRva2VuUmVwb3NpdG9yeS5zZWxlY3RXaXRoQ29udGV4dCh1bmRlZmluZWQsIGN0eCk7XG4gICAgY29uc3QgdG9rZW5zID0gYXdhaXQgc2VsZWN0LmV4ZWN1dGUoKTtcbiAgICBpZiAodG9rZW5zLmxlbmd0aCA+IDApIHtcbiAgICAgIHRocm93IG5ldyBBdXRob3JpemF0aW9uRXJyb3IoXG4gICAgICAgIFwiY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQsIGNsaWVudCBpcyBub3QgYXV0aG9yaXplZCB0byBjaGFuZ2UgdGhlbVwiXG4gICAgICApO1xuICAgIH1cblxuICAgIHRva2VuLm93bmVyID0gY3R4LmNsaWVudElkZW50aXR5LmdldElEKCk7XG5cbiAgICBhd2FpdCB0aGlzLnRva2VuUmVwb3NpdG9yeS5jcmVhdGUodG9rZW4sIGN0eCk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8vIENoZWNrcyB0aGF0IGNvbnRyYWN0IG9wdGlvbnMgaGF2ZSBiZWVuIGFscmVhZHkgaW5pdGlhbGl6ZWRcbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBDaGVja0luaXRpYWxpemVkKGN0eDogQ29udGV4dCkge1xuICAgIGNvbnN0IHNlbGVjdCA9IGF3YWl0IHRoaXMudG9rZW5SZXBvc2l0b3J5LnNlbGVjdFdpdGhDb250ZXh0KHVuZGVmaW5lZCwgY3R4KTtcbiAgICBjb25zdCB0b2tlbnMgPSBhd2FpdCBzZWxlY3QuZXhlY3V0ZSgpO1xuICAgIGlmICh0b2tlbnMubGVuZ3RoID09IDApIHtcbiAgICAgIHRocm93IG5ldyBOb3RJbml0aWFsaXplZEVycm9yKFxuICAgICAgICBcImNvbnRyYWN0IG9wdGlvbnMgbmVlZCB0byBiZSBzZXQgYmVmb3JlIGNhbGxpbmcgYW55IGZ1bmN0aW9uLCBjYWxsIEluaXRpYWxpemUoKSB0byBpbml0aWFsaXplIGNvbnRyYWN0XCJcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE1pbnQgY3JlYXRlcyBuZXcgdG9rZW5zIGFuZCBhZGRzIHRoZW0gdG8gbWludGVyJ3MgYWNjb3VudCBiYWxhbmNlXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY3R4IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBhbW91bnQgYW1vdW50IG9mIHRva2VucyB0byBiZSBtaW50ZWRcbiAgICogQHJldHVybnMge09iamVjdH0gVGhlIGJhbGFuY2VcbiAgICovXG4gIEBPd25lcigpXG4gIEBUcmFuc2FjdGlvbigpXG4gIGFzeW5jIE1pbnQoY3R4OiBDb250ZXh0LCBhbW91bnQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCk7XG5cbiAgICBjb25zdCBsb2dnZXIgPSB0aGlzLmxvZ0ZvcihjdHgpLmZvcih0aGlzLk1pbnQpO1xuXG4gICAgLy8gR2V0IElEIG9mIHN1Ym1pdHRpbmcgY2xpZW50IGlkZW50aXR5XG4gICAgY29uc3QgbWludGVyID0gY3R4LmNsaWVudElkZW50aXR5LmdldElEKCk7XG5cbiAgICBpZiAoYW1vdW50IDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoXCJtaW50IGFtb3VudCBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlclwiKTtcbiAgICB9XG5cbiAgICBsZXQgbWludGVyV2FsbGV0OiBFUkMyMFdhbGxldDtcbiAgICB0cnkge1xuICAgICAgbWludGVyV2FsbGV0ID0gYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnJlYWQobWludGVyLCBjdHgpO1xuXG4gICAgICBjb25zdCBjdXJyZW50QmFsYW5jZSA9IG1pbnRlcldhbGxldC5iYWxhbmNlO1xuXG4gICAgICBjb25zdCB1cGRhdGVkQmFsYW5jZSA9IGFkZChjdXJyZW50QmFsYW5jZSwgYW1vdW50KTtcblxuICAgICAgY29uc3QgdXBkYXRlZG1pbnRlciA9IE9iamVjdC5hc3NpZ24oe30sIG1pbnRlcldhbGxldCwge1xuICAgICAgICBiYWxhbmNlOiB1cGRhdGVkQmFsYW5jZSxcbiAgICAgIH0pO1xuXG4gICAgICBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkudXBkYXRlKHVwZGF0ZWRtaW50ZXIsIGN0eCk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgaWYgKGUgaW5zdGFuY2VvZiBCYXNlRXJyb3IpIHtcbiAgICAgICAgaWYgKGUuY29kZSA9PT0gNDA0KSB7XG4gICAgICAgICAgLy8gQ3JlYXRlIGEgbmV3IHdhbGxldCBmb3IgdGhlIG1pbnRlclxuICAgICAgICAgIGNvbnN0IG5ld1dhbGxldCA9IG5ldyBFUkMyMFdhbGxldCh7XG4gICAgICAgICAgICBpZDogbWludGVyLFxuICAgICAgICAgICAgYmFsYW5jZTogYW1vdW50LFxuICAgICAgICAgICAgdG9rZW46IGF3YWl0IHRoaXMuVG9rZW5OYW1lKGN0eCksXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LmNyZWF0ZShuZXdXYWxsZXQsIGN0eCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoZS5tZXNzYWdlKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoZSBhcyBzdHJpbmcpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEVtaXQgdGhlIFRyYW5zZmVyIGV2ZW50XG4gICAgY29uc3QgdHJhbnNmZXJFdmVudCA9IHsgZnJvbTogXCIweDBcIiwgdG86IG1pbnRlciwgdmFsdWU6IGFtb3VudCB9O1xuICAgIGNvbnN0IGV2ZW50SGFuZGxlciA9XG4gICAgICB0aGlzLnJlcG8uT2JzZXJ2ZXJIYW5kbGVyKCkgYXMgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXI7XG4gICAgZXZlbnRIYW5kbGVyLnVwZGF0ZU9ic2VydmVycyhcbiAgICAgIGxvZ2dlcixcbiAgICAgIFwiXCIsXG4gICAgICBFUkMyMEV2ZW50cy5UUkFOU0ZFUixcbiAgICAgIFwiXCIsXG4gICAgICBjdHgsXG4gICAgICBcIlwiLFxuICAgICAgdHJhbnNmZXJFdmVudFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQnVybiByZWRlZW0gdG9rZW5zIGZyb20gbWludGVyJ3MgYWNjb3VudCBiYWxhbmNlXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY3R4IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBhbW91bnQgYW1vdW50IG9mIHRva2VucyB0byBiZSBidXJuZWRcbiAgICogQHJldHVybnMge09iamVjdH0gVGhlIGJhbGFuY2VcbiAgICovXG4gIEBPd25lcigpXG4gIEBUcmFuc2FjdGlvbigpXG4gIGFzeW5jIEJ1cm4oY3R4OiBDb250ZXh0LCBhbW91bnQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCk7XG5cbiAgICBjb25zdCBsb2dnZXIgPSB0aGlzLmxvZ0ZvcihjdHgpLmZvcih0aGlzLkJ1cm4pO1xuXG4gICAgY29uc3QgbWludGVyID0gY3R4LmNsaWVudElkZW50aXR5LmdldElEKCk7XG5cbiAgICBjb25zdCBtaW50ZXJXYWxsZXQgPSBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkucmVhZChtaW50ZXIsIGN0eCk7XG5cbiAgICBjb25zdCBjdXJyZW50QmFsYW5jZSA9IG1pbnRlcldhbGxldC5iYWxhbmNlO1xuXG4gICAgaWYgKGN1cnJlbnRCYWxhbmNlIDwgYW1vdW50KSB7XG4gICAgICB0aHJvdyBuZXcgQmFsYW5jZUVycm9yKGBNaW50ZXIgaGFzIGluc3VmZmljaWVudCBmdW5kcy5gKTtcbiAgICB9XG5cbiAgICBjb25zdCB1cGRhdGVkQmFsYW5jZSA9IHN1YihjdXJyZW50QmFsYW5jZSwgYW1vdW50KTtcblxuICAgIGNvbnN0IHVwZGF0ZWRtaW50ZXIgPSBPYmplY3QuYXNzaWduKHt9LCBtaW50ZXJXYWxsZXQsIHtcbiAgICAgIGJhbGFuY2U6IHVwZGF0ZWRCYWxhbmNlLFxuICAgIH0pO1xuXG4gICAgYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnVwZGF0ZSh1cGRhdGVkbWludGVyLCBjdHgpO1xuXG4gICAgbG9nZ2VyLmluZm8oYCR7YW1vdW50fSB0b2tlbnMgd2VyZSBidXJuZWRgKTtcblxuICAgIC8vIEVtaXQgdGhlIFRyYW5zZmVyIGV2ZW50XG4gICAgY29uc3QgdHJhbnNmZXJFdmVudCA9IHsgZnJvbTogbWludGVyLCB0bzogXCIweDBcIiwgdmFsdWU6IGFtb3VudCB9O1xuICAgIGNvbnN0IGV2ZW50SGFuZGxlciA9XG4gICAgICB0aGlzLnJlcG8uT2JzZXJ2ZXJIYW5kbGVyKCkgYXMgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXI7XG4gICAgZXZlbnRIYW5kbGVyLnVwZGF0ZU9ic2VydmVycyhcbiAgICAgIGxvZ2dlcixcbiAgICAgIFwiXCIsXG4gICAgICBFUkMyMEV2ZW50cy5UUkFOU0ZFUixcbiAgICAgIFwiXCIsXG4gICAgICBjdHgsXG4gICAgICBcIlwiLFxuICAgICAgdHJhbnNmZXJFdmVudFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQnVybkZyb20gcmVkZWVtIHRva2VucyBmcm9tIGFjY291bnQgYWxsb3dlbmNlIGFuZCBiYWxhbmNlXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY3R4IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBhY2NvdW50IGFjY291bnQgZnJvbSB3aGVyZSB0b2tlbnMgd2lsbCBiZSBidXJuZWRcbiAgICogQHBhcmFtIHtudW1iZXJ9IGFtb3VudCBhbW91bnQgb2YgdG9rZW5zIHRvIGJlIGJ1cm5lZFxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgYmFsYW5jZVxuICAgKi9cbiAgQE93bmVyKClcbiAgQFRyYW5zYWN0aW9uKClcbiAgYXN5bmMgQnVybkZyb20oY3R4OiBDb250ZXh0LCBhY2NvdW50OiBzdHJpbmcsIGFtb3VudDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQgZmlyc3QgdG8gZXhlY3V0ZSB0aGUgZnVuY3Rpb25cbiAgICBhd2FpdCB0aGlzLkNoZWNrSW5pdGlhbGl6ZWQoY3R4KTtcblxuICAgIGNvbnN0IGxvZ2dlciA9IHRoaXMubG9nRm9yKGN0eCkuZm9yKHRoaXMuQnVybkZyb20pO1xuXG4gICAgY29uc3QgYWNjb3VudFdhbGxldCA9IGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS5yZWFkKGFjY291bnQsIGN0eCk7XG5cbiAgICBjb25zdCBjdXJyZW50QmFsYW5jZSA9IGFjY291bnRXYWxsZXQuYmFsYW5jZTtcblxuICAgIGlmIChjdXJyZW50QmFsYW5jZSA8IGFtb3VudCkge1xuICAgICAgdGhyb3cgbmV3IEJhbGFuY2VFcnJvcihgJHthY2NvdW50fSBoYXMgaW5zdWZmaWNpZW50IGZ1bmRzLmApO1xuICAgIH1cblxuICAgIGNvbnN0IHVwZGF0ZWRCYWxhbmNlID0gc3ViKGN1cnJlbnRCYWxhbmNlLCBhbW91bnQpO1xuXG4gICAgY29uc3QgdXBkYXRlZGFjY291bnQgPSBPYmplY3QuYXNzaWduKHt9LCBhY2NvdW50V2FsbGV0LCB7XG4gICAgICBiYWxhbmNlOiB1cGRhdGVkQmFsYW5jZSxcbiAgICB9KTtcblxuICAgIGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS51cGRhdGUodXBkYXRlZGFjY291bnQsIGN0eCk7XG5cbiAgICBsb2dnZXIuaW5mbyhgJHthbW91bnR9IHRva2VucyB3ZXJlIGJlcm5lZCBmcm9tICR7YWNjb3VudH1gKTtcblxuICAgIC8vIEVtaXQgdGhlIFRyYW5zZmVyIGV2ZW50XG4gICAgY29uc3QgdHJhbnNmZXJFdmVudCA9IHsgZnJvbTogYWNjb3VudCwgdG86IFwiMHgwXCIsIHZhbHVlOiBhbW91bnQgfTtcbiAgICBjb25zdCBldmVudEhhbmRsZXIgPVxuICAgICAgdGhpcy5yZXBvLk9ic2VydmVySGFuZGxlcigpIGFzIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyO1xuICAgIGV2ZW50SGFuZGxlci51cGRhdGVPYnNlcnZlcnMoXG4gICAgICBsb2dnZXIsXG4gICAgICBcIlwiLFxuICAgICAgRVJDMjBFdmVudHMuVFJBTlNGRVIsXG4gICAgICBcIlwiLFxuICAgICAgY3R4LFxuICAgICAgXCJcIixcbiAgICAgIHRyYW5zZmVyRXZlbnRcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIENsaWVudEFjY291bnRCYWxhbmNlIHJldHVybnMgdGhlIGJhbGFuY2Ugb2YgdGhlIHJlcXVlc3RpbmcgY2xpZW50J3MgYWNjb3VudC5cbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjdHggdGhlIHRyYW5zYWN0aW9uIGNvbnRleHRcbiAgICogQHJldHVybnMge051bWJlcn0gUmV0dXJucyB0aGUgYWNjb3VudCBiYWxhbmNlXG4gICAqL1xuICBAVHJhbnNhY3Rpb24oKVxuICBhc3luYyBDbGllbnRBY2NvdW50QmFsYW5jZShjdHg6IENvbnRleHQpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCk7XG5cbiAgICAvLyBHZXQgSUQgb2Ygc3VibWl0dGluZyBjbGllbnQgaWRlbnRpdHlcbiAgICBjb25zdCBjbGllbnRBY2NvdW50SUQgPSBjdHguY2xpZW50SWRlbnRpdHkuZ2V0SUQoKTtcblxuICAgIGNvbnN0IGNsaWVudFdhbGxldCA9IGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS5yZWFkKGNsaWVudEFjY291bnRJRCwgY3R4KTtcblxuICAgIGlmICghY2xpZW50V2FsbGV0KSB7XG4gICAgICB0aHJvdyBuZXcgQmFsYW5jZUVycm9yKGBUaGUgYWNjb3VudCAke2NsaWVudEFjY291bnRJRH0gZG9lcyBub3QgZXhpc3RgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY2xpZW50V2FsbGV0LmJhbGFuY2U7XG4gIH1cblxuICAvLyBDbGllbnRBY2NvdW50SUQgcmV0dXJucyB0aGUgaWQgb2YgdGhlIHJlcXVlc3RpbmcgY2xpZW50J3MgYWNjb3VudC5cbiAgLy8gSW4gdGhpcyBpbXBsZW1lbnRhdGlvbiwgdGhlIGNsaWVudCBhY2NvdW50IElEIGlzIHRoZSBjbGllbnRJZCBpdHNlbGYuXG4gIC8vIFVzZXJzIGNhbiB1c2UgdGhpcyBmdW5jdGlvbiB0byBnZXQgdGhlaXIgb3duIGFjY291bnQgaWQsIHdoaWNoIHRoZXkgY2FuIHRoZW4gZ2l2ZSB0byBvdGhlcnMgYXMgdGhlIHBheW1lbnQgYWRkcmVzc1xuICBAVHJhbnNhY3Rpb24oKVxuICBhc3luYyBDbGllbnRBY2NvdW50SUQoY3R4OiBDb250ZXh0KSB7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQgZmlyc3QgdG8gZXhlY3V0ZSB0aGUgZnVuY3Rpb25cbiAgICBhd2FpdCB0aGlzLkNoZWNrSW5pdGlhbGl6ZWQoY3R4KTtcblxuICAgIC8vIEdldCBJRCBvZiBzdWJtaXR0aW5nIGNsaWVudCBpZGVudGl0eVxuICAgIGNvbnN0IGNsaWVudEFjY291bnRJRCA9IGN0eC5jbGllbnRJZGVudGl0eS5nZXRJRCgpO1xuICAgIHJldHVybiBjbGllbnRBY2NvdW50SUQ7XG4gIH1cbn1cbiJdfQ==
|