@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.
Files changed (205) hide show
  1. package/LICENSE.md +22 -0
  2. package/README.md +647 -0
  3. package/dist/for-fabric.cjs +6223 -0
  4. package/dist/for-fabric.esm.cjs +6180 -0
  5. package/lib/client/FabricClientAdapter.cjs +760 -0
  6. package/lib/client/FabricClientAdapter.d.ts +381 -0
  7. package/lib/client/FabricClientDispatch.cjs +186 -0
  8. package/lib/client/FabricClientDispatch.d.ts +125 -0
  9. package/lib/client/FabricClientRepository.cjs +131 -0
  10. package/lib/client/FabricClientRepository.d.ts +100 -0
  11. package/lib/client/erc20/erc20ClientRepository.cjs +343 -0
  12. package/lib/client/erc20/erc20ClientRepository.d.ts +254 -0
  13. package/lib/client/fabric-fs.cjs +234 -0
  14. package/lib/client/fabric-fs.d.ts +92 -0
  15. package/lib/client/index.cjs +30 -0
  16. package/lib/client/index.d.ts +13 -0
  17. package/lib/client/logging.cjs +102 -0
  18. package/lib/client/logging.d.ts +60 -0
  19. package/lib/client/services/LoggedService.cjs +47 -0
  20. package/lib/client/services/LoggedService.d.ts +42 -0
  21. package/lib/client/services/constants.cjs +3 -0
  22. package/lib/client/services/constants.d.ts +15 -0
  23. package/lib/client/services/enrollementService.cjs +344 -0
  24. package/lib/client/services/enrollementService.d.ts +176 -0
  25. package/lib/client/services/index.cjs +18 -0
  26. package/lib/client/services/index.d.ts +1 -0
  27. package/lib/contracts/ContractAdapter.cjs +730 -0
  28. package/lib/contracts/ContractAdapter.d.ts +296 -0
  29. package/lib/contracts/ContractContext.cjs +85 -0
  30. package/lib/contracts/ContractContext.d.ts +64 -0
  31. package/lib/contracts/ContractPrivateDataAdapter.cjs +281 -0
  32. package/lib/contracts/ContractPrivateDataAdapter.d.ts +74 -0
  33. package/lib/contracts/FabricConstruction.cjs +441 -0
  34. package/lib/contracts/FabricConstruction.d.ts +304 -0
  35. package/lib/contracts/FabricContractRepository.cjs +306 -0
  36. package/lib/contracts/FabricContractRepository.d.ts +162 -0
  37. package/lib/contracts/FabricContractRepositoryObservableHandler.cjs +85 -0
  38. package/lib/contracts/FabricContractRepositoryObservableHandler.d.ts +62 -0
  39. package/lib/contracts/FabricContractSequence.cjs +139 -0
  40. package/lib/contracts/FabricContractSequence.d.ts +61 -0
  41. package/lib/contracts/FabricContractStatement.cjs +119 -0
  42. package/lib/contracts/FabricContractStatement.d.ts +34 -0
  43. package/lib/contracts/PrivateSequence.cjs +36 -0
  44. package/lib/contracts/PrivateSequence.d.ts +15 -0
  45. package/lib/contracts/crud/crud-contract.cjs +257 -0
  46. package/lib/contracts/crud/crud-contract.d.ts +168 -0
  47. package/lib/contracts/crud/index.cjs +19 -0
  48. package/lib/contracts/crud/index.d.ts +2 -0
  49. package/lib/contracts/crud/serialized-crud-contract.cjs +172 -0
  50. package/lib/contracts/crud/serialized-crud-contract.d.ts +37 -0
  51. package/lib/contracts/erc20/erc20contract.cjs +569 -0
  52. package/lib/contracts/erc20/erc20contract.d.ts +151 -0
  53. package/lib/contracts/erc20/index.cjs +21 -0
  54. package/lib/contracts/erc20/index.d.ts +2 -0
  55. package/lib/contracts/erc20/models.cjs +209 -0
  56. package/lib/contracts/erc20/models.d.ts +114 -0
  57. package/lib/contracts/index.cjs +32 -0
  58. package/lib/contracts/index.d.ts +15 -0
  59. package/lib/contracts/logging.cjs +96 -0
  60. package/lib/contracts/logging.d.ts +49 -0
  61. package/lib/contracts/private-data.cjs +121 -0
  62. package/lib/contracts/private-data.d.ts +16 -0
  63. package/lib/contracts/types.cjs +3 -0
  64. package/lib/contracts/types.d.ts +26 -0
  65. package/lib/esm/client/FabricClientAdapter.d.ts +381 -0
  66. package/lib/esm/client/FabricClientAdapter.js +723 -0
  67. package/lib/esm/client/FabricClientDispatch.d.ts +125 -0
  68. package/lib/esm/client/FabricClientDispatch.js +182 -0
  69. package/lib/esm/client/FabricClientRepository.d.ts +100 -0
  70. package/lib/esm/client/FabricClientRepository.js +127 -0
  71. package/lib/esm/client/erc20/erc20ClientRepository.d.ts +254 -0
  72. package/lib/esm/client/erc20/erc20ClientRepository.js +339 -0
  73. package/lib/esm/client/fabric-fs.d.ts +92 -0
  74. package/lib/esm/client/fabric-fs.js +191 -0
  75. package/lib/esm/client/index.d.ts +13 -0
  76. package/lib/esm/client/index.js +14 -0
  77. package/lib/esm/client/logging.d.ts +60 -0
  78. package/lib/esm/client/logging.js +98 -0
  79. package/lib/esm/client/services/LoggedService.d.ts +42 -0
  80. package/lib/esm/client/services/LoggedService.js +43 -0
  81. package/lib/esm/client/services/constants.d.ts +15 -0
  82. package/lib/esm/client/services/constants.js +2 -0
  83. package/lib/esm/client/services/enrollementService.d.ts +176 -0
  84. package/lib/esm/client/services/enrollementService.js +337 -0
  85. package/lib/esm/client/services/index.d.ts +1 -0
  86. package/lib/esm/client/services/index.js +2 -0
  87. package/lib/esm/contracts/ContractAdapter.d.ts +296 -0
  88. package/lib/esm/contracts/ContractAdapter.js +724 -0
  89. package/lib/esm/contracts/ContractContext.d.ts +64 -0
  90. package/lib/esm/contracts/ContractContext.js +81 -0
  91. package/lib/esm/contracts/ContractPrivateDataAdapter.d.ts +74 -0
  92. package/lib/esm/contracts/ContractPrivateDataAdapter.js +277 -0
  93. package/lib/esm/contracts/FabricConstruction.d.ts +304 -0
  94. package/lib/esm/contracts/FabricConstruction.js +433 -0
  95. package/lib/esm/contracts/FabricContractRepository.d.ts +162 -0
  96. package/lib/esm/contracts/FabricContractRepository.js +302 -0
  97. package/lib/esm/contracts/FabricContractRepositoryObservableHandler.d.ts +62 -0
  98. package/lib/esm/contracts/FabricContractRepositoryObservableHandler.js +81 -0
  99. package/lib/esm/contracts/FabricContractSequence.d.ts +61 -0
  100. package/lib/esm/contracts/FabricContractSequence.js +135 -0
  101. package/lib/esm/contracts/FabricContractStatement.d.ts +34 -0
  102. package/lib/esm/contracts/FabricContractStatement.js +115 -0
  103. package/lib/esm/contracts/PrivateSequence.d.ts +15 -0
  104. package/lib/esm/contracts/PrivateSequence.js +33 -0
  105. package/lib/esm/contracts/crud/crud-contract.d.ts +168 -0
  106. package/lib/esm/contracts/crud/crud-contract.js +253 -0
  107. package/lib/esm/contracts/crud/index.d.ts +2 -0
  108. package/lib/esm/contracts/crud/index.js +3 -0
  109. package/lib/esm/contracts/crud/serialized-crud-contract.d.ts +37 -0
  110. package/lib/esm/contracts/crud/serialized-crud-contract.js +168 -0
  111. package/lib/esm/contracts/erc20/erc20contract.d.ts +151 -0
  112. package/lib/esm/contracts/erc20/erc20contract.js +565 -0
  113. package/lib/esm/contracts/erc20/index.d.ts +2 -0
  114. package/lib/esm/contracts/erc20/index.js +4 -0
  115. package/lib/esm/contracts/erc20/models.d.ts +114 -0
  116. package/lib/esm/contracts/erc20/models.js +206 -0
  117. package/lib/esm/contracts/index.d.ts +15 -0
  118. package/lib/esm/contracts/index.js +16 -0
  119. package/lib/esm/contracts/logging.d.ts +49 -0
  120. package/lib/esm/contracts/logging.js +92 -0
  121. package/lib/esm/contracts/private-data.d.ts +16 -0
  122. package/lib/esm/contracts/private-data.js +113 -0
  123. package/lib/esm/contracts/types.d.ts +26 -0
  124. package/lib/esm/contracts/types.js +2 -0
  125. package/lib/esm/index.d.ts +8 -0
  126. package/lib/esm/index.js +9 -0
  127. package/lib/esm/shared/ClientSerializer.d.ts +52 -0
  128. package/lib/esm/shared/ClientSerializer.js +80 -0
  129. package/lib/esm/shared/DeterministicSerializer.d.ts +40 -0
  130. package/lib/esm/shared/DeterministicSerializer.js +50 -0
  131. package/lib/esm/shared/SimpleDeterministicSerializer.d.ts +7 -0
  132. package/lib/esm/shared/SimpleDeterministicSerializer.js +42 -0
  133. package/lib/esm/shared/constants.d.ts +39 -0
  134. package/lib/esm/shared/constants.js +42 -0
  135. package/lib/esm/shared/crypto.d.ts +107 -0
  136. package/lib/esm/shared/crypto.js +331 -0
  137. package/lib/esm/shared/decorators.d.ts +24 -0
  138. package/lib/esm/shared/decorators.js +98 -0
  139. package/lib/esm/shared/erc20/erc20-constants.d.ts +25 -0
  140. package/lib/esm/shared/erc20/erc20-constants.js +27 -0
  141. package/lib/esm/shared/errors.d.ts +116 -0
  142. package/lib/esm/shared/errors.js +132 -0
  143. package/lib/esm/shared/events.d.ts +39 -0
  144. package/lib/esm/shared/events.js +47 -0
  145. package/lib/esm/shared/fabric-types.d.ts +33 -0
  146. package/lib/esm/shared/fabric-types.js +2 -0
  147. package/lib/esm/shared/index.d.ts +13 -0
  148. package/lib/esm/shared/index.js +14 -0
  149. package/lib/esm/shared/interfaces/Checkable.d.ts +21 -0
  150. package/lib/esm/shared/interfaces/Checkable.js +2 -0
  151. package/lib/esm/shared/math.d.ts +34 -0
  152. package/lib/esm/shared/math.js +61 -0
  153. package/lib/esm/shared/model/Identity.d.ts +42 -0
  154. package/lib/esm/shared/model/Identity.js +78 -0
  155. package/lib/esm/shared/model/IdentityCredentials.d.ts +41 -0
  156. package/lib/esm/shared/model/IdentityCredentials.js +74 -0
  157. package/lib/esm/shared/model/index.d.ts +1 -0
  158. package/lib/esm/shared/model/index.js +2 -0
  159. package/lib/esm/shared/model/utils.d.ts +60 -0
  160. package/lib/esm/shared/model/utils.js +108 -0
  161. package/lib/esm/shared/types.d.ts +79 -0
  162. package/lib/esm/shared/types.js +2 -0
  163. package/lib/esm/shared/utils.d.ts +55 -0
  164. package/lib/esm/shared/utils.js +148 -0
  165. package/lib/index.cjs +25 -0
  166. package/lib/index.d.ts +8 -0
  167. package/lib/shared/ClientSerializer.cjs +84 -0
  168. package/lib/shared/ClientSerializer.d.ts +52 -0
  169. package/lib/shared/DeterministicSerializer.cjs +54 -0
  170. package/lib/shared/DeterministicSerializer.d.ts +40 -0
  171. package/lib/shared/SimpleDeterministicSerializer.cjs +46 -0
  172. package/lib/shared/SimpleDeterministicSerializer.d.ts +7 -0
  173. package/lib/shared/constants.cjs +45 -0
  174. package/lib/shared/constants.d.ts +39 -0
  175. package/lib/shared/crypto.cjs +369 -0
  176. package/lib/shared/crypto.d.ts +107 -0
  177. package/lib/shared/decorators.cjs +105 -0
  178. package/lib/shared/decorators.d.ts +24 -0
  179. package/lib/shared/erc20/erc20-constants.cjs +30 -0
  180. package/lib/shared/erc20/erc20-constants.d.ts +25 -0
  181. package/lib/shared/errors.cjs +142 -0
  182. package/lib/shared/errors.d.ts +116 -0
  183. package/lib/shared/events.cjs +51 -0
  184. package/lib/shared/events.d.ts +39 -0
  185. package/lib/shared/fabric-types.cjs +4 -0
  186. package/lib/shared/fabric-types.d.ts +33 -0
  187. package/lib/shared/index.cjs +30 -0
  188. package/lib/shared/index.d.ts +13 -0
  189. package/lib/shared/interfaces/Checkable.cjs +3 -0
  190. package/lib/shared/interfaces/Checkable.d.ts +21 -0
  191. package/lib/shared/math.cjs +66 -0
  192. package/lib/shared/math.d.ts +34 -0
  193. package/lib/shared/model/Identity.cjs +81 -0
  194. package/lib/shared/model/Identity.d.ts +42 -0
  195. package/lib/shared/model/IdentityCredentials.cjs +77 -0
  196. package/lib/shared/model/IdentityCredentials.d.ts +41 -0
  197. package/lib/shared/model/index.cjs +18 -0
  198. package/lib/shared/model/index.d.ts +1 -0
  199. package/lib/shared/model/utils.cjs +114 -0
  200. package/lib/shared/model/utils.d.ts +60 -0
  201. package/lib/shared/types.cjs +3 -0
  202. package/lib/shared/types.d.ts +79 -0
  203. package/lib/shared/utils.cjs +185 -0
  204. package/lib/shared/utils.d.ts +55 -0
  205. 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==