@decaf-ts/for-fabric 0.1.23 → 0.1.25

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 (289) hide show
  1. package/dist/for-fabric.cjs +1726 -2
  2. package/dist/for-fabric.js +1831 -2
  3. package/lib/bin/build-contract.cjs +2 -1
  4. package/lib/bin/build-contracts.cjs +2 -1
  5. package/lib/bin/build-contracts2.cjs +2 -1
  6. package/lib/bin/compile-indexes.cjs +2 -1
  7. package/lib/cli-module.cjs +1 -1
  8. package/lib/client/FabricClientAdapter.cjs +8 -1
  9. package/lib/client/FabricClientDispatch.cjs +1 -1
  10. package/lib/client/FabricClientPaginator.cjs +1 -1
  11. package/lib/client/FabricClientRepository.cjs +2 -2
  12. package/lib/client/FabricClientStatement.cjs +1 -1
  13. package/lib/client/erc20/FabricERC20ClientRepository.cjs +1 -1
  14. package/lib/client/erc20/index.cjs +1 -1
  15. package/lib/client/fabric-fs.cjs +1 -1
  16. package/lib/client/fabric-fs.d.ts +1 -1
  17. package/lib/client/fabric-hsm.cjs +1 -1
  18. package/lib/client/index.cjs +1 -1
  19. package/lib/client/indexes/generation.cjs +1 -1
  20. package/lib/client/indexes/index.cjs +1 -1
  21. package/lib/client/logging.cjs +1 -1
  22. package/lib/client/services/FabricEnrollmentService.cjs +1 -1
  23. package/lib/client/services/constants.cjs +1 -1
  24. package/lib/client/services/index.cjs +1 -1
  25. package/lib/contract/Product.cjs +1 -1
  26. package/lib/contract/ProductContract.cjs +1 -1
  27. package/lib/contract/User.cjs +1 -1
  28. package/lib/contract/UserContract.cjs +1 -1
  29. package/lib/contract/index.cjs +1 -1
  30. package/lib/contracts/ContractAdapter.cjs +1 -1
  31. package/lib/contracts/ContractContext.cjs +1 -1
  32. package/lib/contracts/ContractPrivateDataAdapter.cjs +1 -1
  33. package/lib/contracts/FabricConstruction.cjs +1 -1
  34. package/lib/contracts/FabricContractRepository.cjs +1 -1
  35. package/lib/contracts/FabricContractRepositoryObservableHandler.cjs +1 -1
  36. package/lib/contracts/FabricContractStatement.cjs +1 -1
  37. package/lib/contracts/PrivateSequence.cjs +1 -1
  38. package/lib/contracts/crud/crud-contract.cjs +1 -1
  39. package/lib/contracts/crud/index.cjs +1 -1
  40. package/lib/contracts/crud/serialized-crud-contract.cjs +1 -1
  41. package/lib/contracts/erc20/erc20contract.cjs +1 -1
  42. package/lib/contracts/erc20/index.cjs +1 -1
  43. package/lib/contracts/erc20/models.cjs +1 -1
  44. package/lib/contracts/index.cjs +1 -1
  45. package/lib/contracts/logging.cjs +1 -1
  46. package/lib/contracts/private-data.cjs +1 -1
  47. package/lib/contracts/types.cjs +1 -1
  48. package/lib/esm/bin/build-contract.js +1 -1
  49. package/lib/esm/bin/build-contracts.js +1 -1
  50. package/lib/esm/bin/build-contracts2.js +1 -1
  51. package/lib/esm/bin/compile-indexes.js +1 -1
  52. package/lib/esm/cli-module.js +1 -1
  53. package/lib/esm/client/FabricClientAdapter.js +8 -1
  54. package/lib/esm/client/FabricClientDispatch.js +1 -1
  55. package/lib/esm/client/FabricClientPaginator.js +1 -1
  56. package/lib/esm/client/FabricClientRepository.js +2 -2
  57. package/lib/esm/client/FabricClientStatement.js +1 -1
  58. package/lib/esm/client/erc20/FabricERC20ClientRepository.js +1 -1
  59. package/lib/esm/client/erc20/index.js +1 -1
  60. package/lib/esm/client/fabric-fs.d.ts +1 -1
  61. package/lib/esm/client/fabric-fs.js +1 -1
  62. package/lib/esm/client/fabric-hsm.js +1 -1
  63. package/lib/esm/client/index.js +1 -1
  64. package/lib/esm/client/indexes/generation.js +1 -1
  65. package/lib/esm/client/indexes/index.js +1 -1
  66. package/lib/esm/client/logging.js +1 -1
  67. package/lib/esm/client/services/FabricEnrollmentService.js +1 -1
  68. package/lib/esm/client/services/constants.js +1 -1
  69. package/lib/esm/client/services/index.js +1 -1
  70. package/lib/esm/contract/Product.js +1 -1
  71. package/lib/esm/contract/ProductContract.js +1 -1
  72. package/lib/esm/contract/User.js +1 -1
  73. package/lib/esm/contract/UserContract.js +1 -1
  74. package/lib/esm/contract/index.js +1 -1
  75. package/lib/esm/contracts/ContractAdapter.js +1 -1
  76. package/lib/esm/contracts/ContractContext.js +1 -1
  77. package/lib/esm/contracts/ContractPrivateDataAdapter.js +1 -1
  78. package/lib/esm/contracts/FabricConstruction.js +1 -1
  79. package/lib/esm/contracts/FabricContractRepository.js +1 -1
  80. package/lib/esm/contracts/FabricContractRepositoryObservableHandler.js +1 -1
  81. package/lib/esm/contracts/FabricContractStatement.js +1 -1
  82. package/lib/esm/contracts/PrivateSequence.js +1 -1
  83. package/lib/esm/contracts/crud/crud-contract.js +1 -1
  84. package/lib/esm/contracts/crud/index.js +1 -1
  85. package/lib/esm/contracts/crud/serialized-crud-contract.js +1 -1
  86. package/lib/esm/contracts/erc20/erc20contract.js +1 -1
  87. package/lib/esm/contracts/erc20/index.js +1 -1
  88. package/lib/esm/contracts/erc20/models.js +1 -1
  89. package/lib/esm/contracts/index.js +1 -1
  90. package/lib/esm/contracts/logging.js +1 -1
  91. package/lib/esm/contracts/private-data.js +1 -1
  92. package/lib/esm/contracts/types.js +1 -1
  93. package/lib/esm/index.js +1 -1
  94. package/lib/esm/shared/ClientSerializer.js +1 -1
  95. package/lib/esm/shared/DeterministicSerializer.js +1 -1
  96. package/lib/esm/shared/SimpleDeterministicSerializer.js +1 -1
  97. package/lib/esm/shared/constants.js +1 -1
  98. package/lib/esm/shared/crypto.js +1 -1
  99. package/lib/esm/shared/decorators.js +1 -1
  100. package/lib/esm/shared/erc20/erc20-constants.js +1 -1
  101. package/lib/esm/shared/errors.d.ts +3 -0
  102. package/lib/esm/shared/errors.js +6 -1
  103. package/lib/esm/shared/events.js +1 -1
  104. package/lib/esm/shared/fabric-types.js +1 -1
  105. package/lib/esm/shared/index.js +1 -1
  106. package/lib/esm/shared/interfaces/Checkable.js +1 -1
  107. package/lib/esm/shared/math.js +1 -1
  108. package/lib/esm/shared/model/FabricBaseModel.js +1 -1
  109. package/lib/esm/shared/model/FabricIdentifiedBaseModel.js +1 -1
  110. package/lib/esm/shared/model/Identity.js +1 -1
  111. package/lib/esm/shared/model/IdentityCredentials.js +1 -1
  112. package/lib/esm/shared/model/index.js +1 -1
  113. package/lib/esm/shared/overrides/Model.js +1 -1
  114. package/lib/esm/shared/overrides/index.js +1 -1
  115. package/lib/esm/shared/overrides/overrides.js +1 -1
  116. package/lib/esm/shared/types.js +1 -1
  117. package/lib/esm/shared/utils.d.ts +1 -1
  118. package/lib/esm/shared/utils.js +1 -1
  119. package/lib/esm/version.d.ts +1 -1
  120. package/lib/esm/version.js +2 -2
  121. package/lib/index.cjs +1 -1
  122. package/lib/shared/ClientSerializer.cjs +1 -1
  123. package/lib/shared/DeterministicSerializer.cjs +1 -1
  124. package/lib/shared/SimpleDeterministicSerializer.cjs +1 -1
  125. package/lib/shared/constants.cjs +1 -1
  126. package/lib/shared/crypto.cjs +1 -1
  127. package/lib/shared/decorators.cjs +1 -1
  128. package/lib/shared/erc20/erc20-constants.cjs +1 -1
  129. package/lib/shared/errors.cjs +8 -2
  130. package/lib/shared/errors.d.ts +3 -0
  131. package/lib/shared/events.cjs +1 -1
  132. package/lib/shared/fabric-types.cjs +1 -1
  133. package/lib/shared/index.cjs +1 -1
  134. package/lib/shared/interfaces/Checkable.cjs +1 -1
  135. package/lib/shared/math.cjs +1 -1
  136. package/lib/shared/model/FabricBaseModel.cjs +1 -1
  137. package/lib/shared/model/FabricIdentifiedBaseModel.cjs +1 -1
  138. package/lib/shared/model/Identity.cjs +1 -1
  139. package/lib/shared/model/IdentityCredentials.cjs +1 -1
  140. package/lib/shared/model/index.cjs +1 -1
  141. package/lib/shared/overrides/Model.cjs +1 -1
  142. package/lib/shared/overrides/index.cjs +1 -1
  143. package/lib/shared/overrides/overrides.cjs +1 -1
  144. package/lib/shared/types.cjs +1 -1
  145. package/lib/shared/utils.cjs +1 -1
  146. package/lib/shared/utils.d.ts +1 -1
  147. package/lib/version.cjs +2 -2
  148. package/lib/version.d.ts +1 -1
  149. package/package.json +1 -1
  150. package/dist/for-fabric.cjs.map +0 -1
  151. package/dist/for-fabric.js.map +0 -1
  152. package/lib/bin/build-contract.js.map +0 -1
  153. package/lib/bin/build-contracts.js.map +0 -1
  154. package/lib/bin/build-contracts2.js.map +0 -1
  155. package/lib/bin/compile-indexes.js.map +0 -1
  156. package/lib/cli-module.js.map +0 -1
  157. package/lib/client/FabricClientAdapter.js.map +0 -1
  158. package/lib/client/FabricClientDispatch.js.map +0 -1
  159. package/lib/client/FabricClientPaginator.js.map +0 -1
  160. package/lib/client/FabricClientRepository.js.map +0 -1
  161. package/lib/client/FabricClientStatement.js.map +0 -1
  162. package/lib/client/erc20/FabricERC20ClientRepository.js.map +0 -1
  163. package/lib/client/erc20/index.js.map +0 -1
  164. package/lib/client/fabric-fs.js.map +0 -1
  165. package/lib/client/fabric-hsm.js.map +0 -1
  166. package/lib/client/index.js.map +0 -1
  167. package/lib/client/indexes/generation.js.map +0 -1
  168. package/lib/client/indexes/index.js.map +0 -1
  169. package/lib/client/logging.js.map +0 -1
  170. package/lib/client/services/FabricEnrollmentService.js.map +0 -1
  171. package/lib/client/services/constants.js.map +0 -1
  172. package/lib/client/services/index.js.map +0 -1
  173. package/lib/contract/Product.js.map +0 -1
  174. package/lib/contract/ProductContract.js.map +0 -1
  175. package/lib/contract/User.js.map +0 -1
  176. package/lib/contract/UserContract.js.map +0 -1
  177. package/lib/contract/index.js.map +0 -1
  178. package/lib/contracts/ContractAdapter.js.map +0 -1
  179. package/lib/contracts/ContractContext.js.map +0 -1
  180. package/lib/contracts/ContractPrivateDataAdapter.js.map +0 -1
  181. package/lib/contracts/FabricConstruction.js.map +0 -1
  182. package/lib/contracts/FabricContractRepository.js.map +0 -1
  183. package/lib/contracts/FabricContractRepositoryObservableHandler.js.map +0 -1
  184. package/lib/contracts/FabricContractStatement.js.map +0 -1
  185. package/lib/contracts/PrivateSequence.js.map +0 -1
  186. package/lib/contracts/crud/crud-contract.js.map +0 -1
  187. package/lib/contracts/crud/index.js.map +0 -1
  188. package/lib/contracts/crud/serialized-crud-contract.js.map +0 -1
  189. package/lib/contracts/erc20/erc20contract.js.map +0 -1
  190. package/lib/contracts/erc20/index.js.map +0 -1
  191. package/lib/contracts/erc20/models.js.map +0 -1
  192. package/lib/contracts/index.js.map +0 -1
  193. package/lib/contracts/logging.js.map +0 -1
  194. package/lib/contracts/private-data.js.map +0 -1
  195. package/lib/contracts/types.js.map +0 -1
  196. package/lib/esm/bin/build-contract.js.map +0 -1
  197. package/lib/esm/bin/build-contracts.js.map +0 -1
  198. package/lib/esm/bin/build-contracts2.js.map +0 -1
  199. package/lib/esm/bin/compile-indexes.js.map +0 -1
  200. package/lib/esm/cli-module.js.map +0 -1
  201. package/lib/esm/client/FabricClientAdapter.js.map +0 -1
  202. package/lib/esm/client/FabricClientDispatch.js.map +0 -1
  203. package/lib/esm/client/FabricClientPaginator.js.map +0 -1
  204. package/lib/esm/client/FabricClientRepository.js.map +0 -1
  205. package/lib/esm/client/FabricClientStatement.js.map +0 -1
  206. package/lib/esm/client/erc20/FabricERC20ClientRepository.js.map +0 -1
  207. package/lib/esm/client/erc20/index.js.map +0 -1
  208. package/lib/esm/client/fabric-fs.js.map +0 -1
  209. package/lib/esm/client/fabric-hsm.js.map +0 -1
  210. package/lib/esm/client/index.js.map +0 -1
  211. package/lib/esm/client/indexes/generation.js.map +0 -1
  212. package/lib/esm/client/indexes/index.js.map +0 -1
  213. package/lib/esm/client/logging.js.map +0 -1
  214. package/lib/esm/client/services/FabricEnrollmentService.js.map +0 -1
  215. package/lib/esm/client/services/constants.js.map +0 -1
  216. package/lib/esm/client/services/index.js.map +0 -1
  217. package/lib/esm/contract/Product.js.map +0 -1
  218. package/lib/esm/contract/ProductContract.js.map +0 -1
  219. package/lib/esm/contract/User.js.map +0 -1
  220. package/lib/esm/contract/UserContract.js.map +0 -1
  221. package/lib/esm/contract/index.js.map +0 -1
  222. package/lib/esm/contracts/ContractAdapter.js.map +0 -1
  223. package/lib/esm/contracts/ContractContext.js.map +0 -1
  224. package/lib/esm/contracts/ContractPrivateDataAdapter.js.map +0 -1
  225. package/lib/esm/contracts/FabricConstruction.js.map +0 -1
  226. package/lib/esm/contracts/FabricContractRepository.js.map +0 -1
  227. package/lib/esm/contracts/FabricContractRepositoryObservableHandler.js.map +0 -1
  228. package/lib/esm/contracts/FabricContractStatement.js.map +0 -1
  229. package/lib/esm/contracts/PrivateSequence.js.map +0 -1
  230. package/lib/esm/contracts/crud/crud-contract.js.map +0 -1
  231. package/lib/esm/contracts/crud/index.js.map +0 -1
  232. package/lib/esm/contracts/crud/serialized-crud-contract.js.map +0 -1
  233. package/lib/esm/contracts/erc20/erc20contract.js.map +0 -1
  234. package/lib/esm/contracts/erc20/index.js.map +0 -1
  235. package/lib/esm/contracts/erc20/models.js.map +0 -1
  236. package/lib/esm/contracts/index.js.map +0 -1
  237. package/lib/esm/contracts/logging.js.map +0 -1
  238. package/lib/esm/contracts/private-data.js.map +0 -1
  239. package/lib/esm/contracts/types.js.map +0 -1
  240. package/lib/esm/index.js.map +0 -1
  241. package/lib/esm/shared/ClientSerializer.js.map +0 -1
  242. package/lib/esm/shared/DeterministicSerializer.js.map +0 -1
  243. package/lib/esm/shared/SimpleDeterministicSerializer.js.map +0 -1
  244. package/lib/esm/shared/constants.js.map +0 -1
  245. package/lib/esm/shared/crypto.js.map +0 -1
  246. package/lib/esm/shared/decorators.js.map +0 -1
  247. package/lib/esm/shared/erc20/erc20-constants.js.map +0 -1
  248. package/lib/esm/shared/errors.js.map +0 -1
  249. package/lib/esm/shared/events.js.map +0 -1
  250. package/lib/esm/shared/fabric-types.js.map +0 -1
  251. package/lib/esm/shared/index.js.map +0 -1
  252. package/lib/esm/shared/interfaces/Checkable.js.map +0 -1
  253. package/lib/esm/shared/math.js.map +0 -1
  254. package/lib/esm/shared/model/FabricBaseModel.js.map +0 -1
  255. package/lib/esm/shared/model/FabricIdentifiedBaseModel.js.map +0 -1
  256. package/lib/esm/shared/model/Identity.js.map +0 -1
  257. package/lib/esm/shared/model/IdentityCredentials.js.map +0 -1
  258. package/lib/esm/shared/model/index.js.map +0 -1
  259. package/lib/esm/shared/overrides/Model.js.map +0 -1
  260. package/lib/esm/shared/overrides/index.js.map +0 -1
  261. package/lib/esm/shared/overrides/overrides.js.map +0 -1
  262. package/lib/esm/shared/types.js.map +0 -1
  263. package/lib/esm/shared/utils.js.map +0 -1
  264. package/lib/esm/version.js.map +0 -1
  265. package/lib/index.js.map +0 -1
  266. package/lib/shared/ClientSerializer.js.map +0 -1
  267. package/lib/shared/DeterministicSerializer.js.map +0 -1
  268. package/lib/shared/SimpleDeterministicSerializer.js.map +0 -1
  269. package/lib/shared/constants.js.map +0 -1
  270. package/lib/shared/crypto.js.map +0 -1
  271. package/lib/shared/decorators.js.map +0 -1
  272. package/lib/shared/erc20/erc20-constants.js.map +0 -1
  273. package/lib/shared/errors.js.map +0 -1
  274. package/lib/shared/events.js.map +0 -1
  275. package/lib/shared/fabric-types.js.map +0 -1
  276. package/lib/shared/index.js.map +0 -1
  277. package/lib/shared/interfaces/Checkable.js.map +0 -1
  278. package/lib/shared/math.js.map +0 -1
  279. package/lib/shared/model/FabricBaseModel.js.map +0 -1
  280. package/lib/shared/model/FabricIdentifiedBaseModel.js.map +0 -1
  281. package/lib/shared/model/Identity.js.map +0 -1
  282. package/lib/shared/model/IdentityCredentials.js.map +0 -1
  283. package/lib/shared/model/index.js.map +0 -1
  284. package/lib/shared/overrides/Model.js.map +0 -1
  285. package/lib/shared/overrides/index.js.map +0 -1
  286. package/lib/shared/overrides/overrides.js.map +0 -1
  287. package/lib/shared/types.js.map +0 -1
  288. package/lib/shared/utils.js.map +0 -1
  289. package/lib/version.js.map +0 -1
@@ -1,2 +1,1726 @@
1
- var t,e;t=this,e=function(t,e,a,r,n,i,o,s,c){"use strict";class l extends r.Context{constructor(){super()}get stub(){return this.get("stub")}get timestamp(){return this.stub.getDateTimestamp()}get identity(){return this.get("identity")}toString(){return"fabric ctx"+(this.stub?" with stub":"without stub")}}class d extends r.ObserverHandler{constructor(t=[n.OperationKeys.CREATE,n.OperationKeys.UPDATE,n.OperationKeys.DELETE,n.BulkCrudOperationKeys.CREATE_ALL,n.BulkCrudOperationKeys.UPDATE_ALL,n.BulkCrudOperationKeys.DELETE_ALL]){super(),this.supportedEvents=t}async updateObservers(t,e,a,...n){const{log:i,ctx:o}=r.Adapter.logCtx(n,this.updateObservers),{stub:s}=o,[c,l]=n,d="string"==typeof t?t:t.name;if(-1!==this.supportedEvents.indexOf(e)){i.debug(`Emitting ${e} event`);const t=((t,e,a)=>{const r=[t,e];return a&&r.push(a),r.join("_")})(d,e,c);s.setEvent(t,Buffer.from(JSON.stringify({id:a})))}else s.setEvent(e,Buffer.from(JSON.stringify(l)))}}class u extends r.Repository{constructor(t,e,a){super(t,e),this.trackedEvents=a}ObserverHandler(){return new d}async updateObservers(t,e,a,...r){if(!this.trackedEvents||-1!==this.trackedEvents.indexOf(e))return await super.updateObservers(t,e,a,...r)}}class p extends e.CouchDBStatement{constructor(t){super(t)}async raw(t,...e){const{ctx:r}=this.logCtx(e,this.raw),i=await this.adapter.raw(t,!0,r),s=a.Model.pk(this.fromSelector),c=o.Metadata.get(this.fromSelector,o.Metadata.key(n.DBKeys.ID,s))?.type;return this.selectSelector?i:i.map((t=>this.processRecord(t,s,c,r)))}build(){const t={};t[e.CouchDBKeys.TABLE]={},t[e.CouchDBKeys.TABLE]=a.Model.tableName(this.fromSelector);const n={selector:t};if(this.selectSelector&&(n.fields=this.selectSelector),this.whereCondition){const t=this.parseCondition(r.Condition.and(this.whereCondition,r.Condition.attribute(e.CouchDBKeys.TABLE).eq(n.selector[e.CouchDBKeys.TABLE]))).selector,a=Object.keys(t);if(1===a.length&&-1!==Object.values(e.CouchDBGroupOperator).indexOf(a[0]))switch(a[0]){case e.CouchDBGroupOperator.AND:t[e.CouchDBGroupOperator.AND]=[...Object.values(t[e.CouchDBGroupOperator.AND]).reduce(((t,a)=>{const r=Object.keys(a);if(1!==r.length)throw Error("Too many keys in query selector. should be one");const n=r[0];return n===e.CouchDBGroupOperator.AND?t.push(...a[n]):t.push(a),t}),[])],n.selector=t;break;case e.CouchDBGroupOperator.OR:{const a={};a[e.CouchDBGroupOperator.AND]=[t,...Object.entries(n.selector).map((([t,e])=>{const a={};return a[t]=e,a}))],n.selector=a;break}default:throw Error("This should be impossible")}else Object.entries(t).forEach((([t,e])=>{n.selector[t],n.selector[t]=e}))}if(this.orderBySelector){n.sort=n.sort||[],n.selector=n.selector||{};const[t,a]=this.orderBySelector,r={};r[t]=a,n.sort.push(r),n.selector[t]||(n.selector[t]={},n.selector[t][e.CouchDBOperator.BIGGER]=null)}return this.limitSelector&&(n.limit=this.limitSelector),this.offsetSelector&&(n.skip=this.offsetSelector),n}}var g,h;(t=>{t.PRIVATE="private",t.SHARED="shared",t.FABRIC="fabric.",t.OWNEDBY="owned-by"})(g||(g={})),(t=>{t.X509="X.509"})(h||(h={}));const y="hlf-fabric";class m extends a.JSONSerializer{constructor(){super()}deserialize(t,e){return JSON.parse(t)}serialize(t){return require("json-stringify-deterministic")(require("sort-keys-recursive")(this.preSerialize(t)))}preSerialize(t){return Object.assign({},t)}}async function w(t,e,i,o){const s=o[i];if(!s)return;if("object"!=typeof s){const e=r.repositoryFromTypeMetadata(o,i,this.adapter.alias),a=await e.read(s,t);return await r.cacheModelForPopulate(t,o,i,s,a),void(o[i]=s)}e.class="string"==typeof e.class?e.class:e.class().name;const c=a.Model.get(e.class);if(!c)throw new n.InternalError("Could not find model "+e.class);const l=r.Repository.forModel(c,this.adapter.alias),d=await l.create(s,t),u=a.Model.pk(d);await r.cacheModelForPopulate(t,o,i,d[u],d),o[i]=d[u]}async function f(t,e,n,i){const o=i[n];if(!o)return;if(e.cascade.update!==r.Cascade.CASCADE)return;if("object"!=typeof o){const e=r.repositoryFromTypeMetadata(i,n,this.adapter.alias),a=await e.read(o,t);return await r.cacheModelForPopulate(t,i,n,o,a),void(i[n]=o)}const s=await r.createOrUpdate(i[n],t,this.adapter.alias),c=a.Model.pk(s);await r.cacheModelForPopulate(t,i,n,s[c],s),i[n]=s[c]}async function _(t,e,n,i){const o=i[n];if(!o)return;if(e.cascade.update!==r.Cascade.CASCADE)return;const s=r.repositoryFromTypeMetadata(i,n,this.adapter.alias);let c;c=o instanceof a.Model?await s.delete(i[n][a.Model.pk(s.class)],t):await s.delete(i[n],t),await r.cacheModelForPopulate(t,i,n,c[a.Model.pk(s.class)],c)}async function x(t,e,i,o){const s=o[i];if(!s||!s.length)return;const c=typeof s[0];if(!s.every((t=>typeof t===c)))throw new n.InternalError(`Invalid operation. All elements of property ${i} must match the same type.`);const l=new Set([...s]);if("object"!==c){const e=r.repositoryFromTypeMetadata(o,i,this.adapter.alias);for(const a of l){const n=await e.read(a,t);await r.cacheModelForPopulate(t,o,i,a,n)}return void(o[i]=[...l])}const d=a.Model.pk(s[0]),u=new Set;for(const e of s){const a=await r.createOrUpdate(e,t,this.adapter.alias);await r.cacheModelForPopulate(t,o,i,a[d],a),u.add(a[d])}o[i]=[...u]}async function C(t,e,i,o){if(e.cascade.delete!==r.Cascade.CASCADE)return;const s=o[i];if(!s||!s.length)return;const c=typeof s[0];if(!s.every((t=>typeof t===c)))throw new n.InternalError(`Invalid operation. All elements of property ${i} must match the same type.`);const l="object"===c,d=l?r.Repository.forModel(s[0],this.adapter.alias):r.repositoryFromTypeMetadata(o,i,this.adapter.alias),u=new Set([...l?s.map((t=>t[a.Model.pk(this.class)])):s]);for(const e of u.values()){const a=await d.delete(e,t);await r.cacheModelForPopulate(t,o,i,e,a)}o[i]=[...u]}async function b(t,e,a,i){if(!e.populate)return;const o=i[a],s=Array.isArray(o);if(void 0===o||s&&0===o.length)return;const c=await(async(e,a,i,o,s)=>{let c,l;const d=[];for(const u of o){c=r.getPopulateKey(a.constructor.name,i,u);try{l=await e.get(c)}catch(e){const o=r.repositoryFromTypeMetadata(a,i,s);if(!o)throw new n.InternalError("Could not find repo");l=await o.read(u,t)}d.push(l)}return d})(t,i,a,s?o:[o],this.adapter.alias);i[a]=s?c:c[0]}class A extends s.MiniLogger{constructor(t,e,a){super(t,e),this.logger=a?a.logging.getLogger(t):new s.MiniLogger(t,e)}log(t,e,a){if(s.NumericLogLevels[this.config("level")]<s.NumericLogLevels[t])return;let r;switch(t){case s.LogLevel.info:r=this.logger.info;break;case s.LogLevel.verbose:r=this.logger.verbose;break;case s.LogLevel.debug:r=this.logger.debug;break;case s.LogLevel.error:r=this.logger.error;break;case s.LogLevel.silly:r=this.logger.silly;break;default:throw new n.InternalError("Invalid log level")}r.call(this.logger,this.createLog(t,e,a))}}async function S(t,e,a,n){try{const e=t.get("identity");n[a]=e.getID()}catch(t){throw new r.UnsupportedError("No User found in context. Please provide a user in the context")}}async function E(t,e,r,i){if(!e.type||i[r])return;let o;e.name||(e.name=a.Model.sequenceName(i,"pk"));try{o=await this.adapter.Sequence(e)}catch(t){throw new n.InternalError(`Failed to instantiate Sequence ${e.name}: ${t}`)}const s=await o.next(t);Object.defineProperty(i,r,{enumerable:!0,writable:!1,configurable:!0,value:s})}s.Logging.setFactory(((t,e,a)=>new A(t||A.name,e||{},a)));class v extends e.CouchDBAdapter{getClient(){throw new r.UnsupportedError("Client is not supported in Fabric contracts")}static{this.textDecoder=new TextDecoder("utf8")}static{this.serializer=new m}repository(){return u}constructor(t,e){super(t,y,e),this.Context=l}for(t,...e){return super.for(t,...e)}async create(t,e,r,...n){const{ctx:i,log:o,stub:s}=this.logCtx(n,this.create);o.info("in ADAPTER create with args "+n);const c=a.Model.tableName(t);try{o.info(`adding entry to ${c} table with pk ${e}`);const t=s.createCompositeKey(c,[e+""]);r=await this.putState(t,r,i)}catch(t){throw this.parseError(t)}return r}async read(t,e,...r){const{ctx:n,log:i,stub:o}=this.logCtx(r,this.read);i.info("in ADAPTER read with args "+r);const s=a.Model.tableName(t);let c;try{const t=o.createCompositeKey(s,[e+""]);c=await this.readState(t,n)}catch(t){throw this.parseError(t)}return c}async update(t,e,r,...n){const{ctx:i,log:o,stub:s}=this.logCtx(n,this.update),c=a.Model.tableName(t);try{o.verbose(`updating entry to ${c} table with pk ${e}`);const t=s.createCompositeKey(c,[e+""]);r=await this.putState(t,r,i)}catch(t){throw this.parseError(t)}return r}async delete(t,e,...r){const{ctx:n,log:i,ctxArgs:o,stub:s}=this.logCtx(r,this.delete),c=a.Model.tableName(t);let l;try{const a=s.createCompositeKey(c,[e+""]);l=await this.read(t,e,...o),i.verbose(`deleting entry with pk ${e} from ${c} table`),await this.deleteState(a,n)}catch(t){throw this.parseError(t)}return l}async deleteState(t,e){const{stub:a}=this.logCtx([e],this.deleteState);await a.deleteState(t)}forPrivate(t){const e=[this.putState,this.readState,this.deleteState,this.queryResult,this.queryResultPaginated].map((t=>t.name));return new Proxy(this,{get:(a,r,i)=>e.includes(r)?new Proxy(a[r],{async apply(e,a,i){switch(r){case"putState":{const[e,a,r]=i;return await e.putPrivateData(t,a.toString(),r),r}case"deleteState":{const[e,a]=i;return e.deletePrivateData(t,a)}case"readState":{const[e,a]=i;return e.getPrivateData(t,a)}case"queryResult":{const[e,a]=i;return e.getPrivateDataQueryResult(t,a)}case"queryResultPaginated":{const[e,a,r,n]=i,o=await e.getPrivateDataQueryResult(t,a),s=[];let c=0,l=!n,d=null;for(;;){const t=await o.next();if(t.value&&t.value.value.toString()){const e=t.value.key,a=t.value.value.toString("utf8");if(!l){e===n?.toString()&&(l=!0);continue}if(s.push({Key:e,Record:JSON.parse(a)}),d=e,c++,c>=r)return await o.close(),{iterator:s,metadata:{fetchedRecordsCount:s.length,bookmark:d}}}if(t.done)return await o.close(),{iterator:s,metadata:{fetchedRecordsCount:s.length,bookmark:""}}}}default:throw new n.InternalError("Unsupported method override "+r)}}}):Reflect.get(a,r,i)})}async putState(t,e,a){let r;const{stub:i,log:o}=this.logCtx([a],this.putState);try{r=Buffer.from(v.serializer.serialize(e))}catch(e){throw new n.SerializationError(`Failed to serialize record with id ${t}: ${e}`)}const s=a.get("segregated");return s?await i.putPrivateData(s,t.toString(),r):await i.putState(t.toString(),r),o.silly(`state stored${s?` in ${s} collection`:""} under id ${t}`),e}async readState(t,e){let a;const{stub:r,log:i}=this.logCtx([e],this.readState);let o;const s=e.get("segregated");if(o=s?(await r.getPrivateData(s,t.toString())).toString():(await r.getState(t.toString())).toString(),!o)throw new n.NotFoundError(`Record with id ${t}${s?` in ${s} collection`:""} not found`);i.silly(`state retrieved from${s?` ${s} collection`:""} under id ${t}`);try{a=v.serializer.deserialize(o.toString())}catch(t){throw new n.SerializationError("Failed to parse record: "+t)}return a}async queryResult(t,e,...a){const{ctx:r}=this.logCtx(a,this.readState);let n;const i=r.get("segregated");return n=i?await t.getPrivateDataQueryResult(i,JSON.stringify(e)):await t.getQueryResult(JSON.stringify(e)),n}async queryResultPaginated(t,e,a=250,r,...n){const{ctx:i}=this.logCtx(n,this.readState);let o;const s=i.get("segregated");return s?(e.selector={...e.selector,_id:r?{$gt:r.toString()}:{$gte:""}},o={iterator:await t.getPrivateDataQueryResult(s,JSON.stringify(e)),metadata:{fetchedRecordsCount:a,bookmark:""}}):o=await t.getQueryResultWithPagination(JSON.stringify(e),a,r?.toString()),o}mergeModels(t){const e=t=>Object.entries(t).reduce(((t,[e,a])=>(void 0!==a&&(t[e]=a),t)),{});let a=t.pop();for(const r of t)a=Object.assign({},e(a),e(r));return a}decode(t){return v.textDecoder.decode(t)}async flags(t,e,a,r,...n){const i={stub:r.stub,segregated:!1};return Object.assign(i,r instanceof l?{logger:r.logger,identity:r.identity,correlationId:r.stub.getTxID()}:{identity:r.clientIdentity,logger:new A(this,void 0,r),correlationId:r.stub.getTxID()}),await super.flags(t,e,i,...n)}index(t){return Promise.resolve(void 0)}async resultIterator(t,e,a=!1){const r=[];let n=await e.next();for(;!n.done;){if(n.value&&n.value.value.toString()){let e={};if(t.debug(n.value.value.toString("utf8")),a){e.TxId=n.value.txId,e.Timestamp=n.value.timestamp;try{e.Value=JSON.parse(n.value.value.toString("utf8"))}catch(a){t.error(a),e.Value=n.value.value.toString("utf8")}}else try{e=JSON.parse(n.value.value.toString("utf8"))}catch(a){t.error(a),e=n.value.value.toString("utf8")}r.push(e)}n=await e.next()}return t.debug(`Closing iterator after ${r.length} results`),e.close(),r}async raw(t,e=!0,...a){const{log:r,stub:n}=this.logCtx(a,this.raw),{skip:i,limit:o}=t;let s;o||i?(delete t.limit,delete t.skip,r.debug(`Retrieving paginated iterator: limit: ${o}/ skip: ${i}`),s=(await this.queryResultPaginated(n,t,o||250,i?.toString())).iterator):(r.debug("Retrieving iterator"),s=await this.queryResult(n,t)),r.debug("Iterator acquired");const c=await this.resultIterator(r,s);return r.debug(`returning ${Array.isArray(c)?c.length:1} results`),c}Statement(){return new p(this)}async createAll(t,e,r,...i){if(e.length!==r.length)throw new n.InternalError("Ids and models must have the same length");const{log:o,ctxArgs:s}=this.logCtx(i,this.createAll),c=a.Model.tableName(t);return o.debug(`Creating ${e.length} entries ${c} table`),Promise.all(e.map(((e,a)=>this.create(t,e,r[a],...s))))}async updateAll(t,e,r,...i){if(e.length!==r.length)throw new n.InternalError("Ids and models must have the same length");const{log:o,ctxArgs:s}=this.logCtx(i,this.updateAll),c=a.Model.tableName(t);return o.debug(`Updating ${e.length} entries ${c} table`),Promise.all(e.map(((e,a)=>this.update(t,e,r[a],...s))))}prepare(t,...e){const{log:r}=this.logCtx(e,this.prepare),i=a.Model.tableName(t.constructor),o=a.Model.pk(t.constructor),s=a.Model.segregate(t),c=Object.entries(s.model).reduce(((e,[r,i])=>{if(void 0===i)return e;const o=a.Model.columnName(t,r);if(this.isReserved(o))throw new n.InternalError(`Property name ${o} is reserved`);return e[o]=i,e}),{});return r.silly(`Preparing record for ${i} table with pk ${t[o]}`),{record:c,id:t[o],transient:s.transient}}revert(t,e,r,i,...o){const{log:s}=this.logCtx(o,this.revert),c={};c[a.Model.pk(e)]=r;const l="string"==typeof e?a.Model.build(c,e):new e(c);s.silly(`Rebuilding model ${l.constructor.name} id ${r}`);const d=Object.keys(l).reduce(((e,r)=>(e[r]=t[a.Model.columnName(e,r)],e)),l);return i&&(s.debug("re-adding transient properties: "+Object.keys(i).join(", ")),Object.entries(i).forEach((([t,e])=>{if(t in d&&void 0!==d[t])throw new n.InternalError(`Transient property ${t} already exists on model ${l.constructor.name}. should be impossible`);d[t]=e}))),d}createPrefix(t,r,n,...i){const{ctxArgs:o}=this.logCtx(i,this.createPrefix),s={};return s[e.CouchDBKeys.TABLE]=a.Model.tableName(t),Object.assign(s,n),[t,r,s,...o]}updatePrefix(t,r,n,...i){const{ctxArgs:o}=this.logCtx(i,this.updatePrefix),s={};return s[e.CouchDBKeys.TABLE]=a.Model.tableName(t),Object.assign(s,n),[t,r,s,...o]}createAllPrefix(t,a,r,...i){if(a.length!==r.length)throw new n.InternalError("Ids and models must have the same length");const o=i.pop(),s=a.map(((a,n)=>{const i={};return i[e.CouchDBKeys.TABLE]=t,Object.assign(i,r[n]),i}));return[t,a,s,o]}updateAllPrefix(t,a,r,...i){if(a.length!==r.length)throw new n.InternalError("Ids and models must have the same length");const o=i.pop(),s=a.map(((a,n)=>{const i={};return i[e.CouchDBKeys.TABLE]=t,Object.assign(i,r[n]),i}));return[t,a,s,o]}parseError(t,e){return v.parseError(e||t)}logCtx(t,e){return v.logCtx.call(this,t,e)}static logCtx(t,e){if(1>t.length)throw new n.InternalError("No context provided");const a=t.pop();if(!(a instanceof r.Context))throw new n.InternalError("No context provided");if(t.filter((t=>t instanceof r.Context)).length>1)throw Error("here");const i=this?a.logger.for(this).for(e):a.logger.clear().for(this).for(e);return{ctx:a,log:e?i.for(e):i,stub:a.stub,identity:a.identity,ctxArgs:[...t,a]}}static parseError(t){const e="string"==typeof t?t:t.message;return e.includes(n.NotFoundError.name)?new n.NotFoundError(t):e.includes(n.ConflictError.name)?new n.ConflictError(t):e.includes(n.BadRequestError.name)?new n.BadRequestError(t):e.includes(r.QueryError.name)?new r.QueryError(t):e.includes(r.PagingError.name)?new r.PagingError(t):e.includes(r.UnsupportedError.name)?new r.UnsupportedError(t):e.includes(r.MigrationError.name)?new r.MigrationError(t):e.includes(r.ObserverError.name)?new r.ObserverError(t):e.includes(r.AuthorizationError.name)?new r.AuthorizationError(t):e.includes(r.ForbiddenError.name)?new r.ForbiddenError(t):e.includes(r.ConnectionError.name)?new r.ConnectionError(t):e.includes(n.SerializationError.name)?new n.SerializationError(t):new n.InternalError(t)}static decoration(){super.decoration(),o.Decoration.flavouredAs(y).for(r.PersistenceKeys.CREATED_BY).define(n.onCreate(S),o.propMetadata(r.PersistenceKeys.CREATED_BY,{})).apply(),o.Decoration.flavouredAs(y).for(r.PersistenceKeys.UPDATED_BY).define(n.onCreateUpdate(S),o.propMetadata(r.PersistenceKeys.UPDATED_BY,{})).apply(),o.Decoration.flavouredAs(y).for(n.DBKeys.ID).define({decorator:(t,e)=>(r,i)=>o.apply(a.required(),n.readonly(),o.propMetadata(o.Metadata.key(n.DBKeys.ID,i),t),n.onCreate(E,t,e))(r,i)}).apply(),o.Decoration.flavouredAs(y).for(r.PersistenceKeys.COLUMN).extend(i.Property()).apply(),o.Decoration.flavouredAs(y).for(r.PersistenceKeys.TABLE).extend((t=>i.Object()(t))).apply(),o.Decoration.flavouredAs(y).for(r.PersistenceKeys.ONE_TO_ONE).define({decorator:(t,e,i,s,c)=>{const l={class:t,cascade:e,populate:i};return s&&(l.joinTable=s),c&&(l.name=c),o.apply(o.prop(),r.relation(r.PersistenceKeys.ONE_TO_ONE,l),a.type([t,String,Number,BigInt]),n.onCreate(w,l),n.onUpdate(f,l),n.onDelete(_,l),n.afterAny(b,l),o.propMetadata(r.PersistenceKeys.ONE_TO_ONE,l))}}).apply(),o.Decoration.for(r.PersistenceKeys.ONE_TO_MANY).define({decorator:(t,e,i,s,c)=>{const l={class:t,cascade:e,populate:i};return s&&(l.joinTable=s),c&&(l.name=c),o.apply(o.prop(),r.relation(r.PersistenceKeys.ONE_TO_MANY,l),a.list([t,String,Number]),n.onCreate(x,l),n.onUpdate(r.oneToManyOnUpdate,l),n.onDelete(C,l),n.afterAny(b,l),o.propMetadata(r.PersistenceKeys.ONE_TO_MANY,l))}}).apply()}}v.decoration(),r.Adapter.setCurrent(y);class O extends a.JSONSerializer{constructor(){super()}deserialize(t){return super.deserialize(t)}serialize(t){return require("json-stringify-deterministic")(require("sort-keys-recursive")(this.preSerialize(t)))}}class T extends i.Contract{static{this.adapter=new v}static{this.serializer=new O}constructor(t,e){super(t),this.clazz=e,this.initialized=!1,this.repo=r.Repository.forModel(e)}async listBy(t,e,a,...r){const{ctxArgs:n}=await this.logCtx([...r,t],this.listBy);return this.repo.listBy(e,a,...n)}async paginateBy(t,e,a,r,...n){const{ctxArgs:i}=await this.logCtx([...n,t],this.paginateBy);return this.repo.paginateBy(e,a,r,...i)}async findOneBy(t,e,a,...r){const{ctxArgs:n}=await this.logCtx([...r,t],this.findOneBy);return this.repo.findOneBy(e,a,...n)}async statement(t,e,...a){const{ctxArgs:r}=await this.logCtx([...a,t],this.statement);return this.repo.statement(e,...r)}async create(t,e,...r){const{log:n,ctxArgs:i}=await this.logCtx([...r,t],this.create);n.info("CONTRACT CREATE, "+i),"string"==typeof e&&(e=this.deserialize(e)),n.info("Creating model: "+JSON.stringify(e));const o=this.getTransientData(t);return n.info("Merging transient data..."),e=a.Model.merge(e,o,this.clazz),this.repo.create(e,...i)}async read(t,e,...a){const{log:r,ctxArgs:n}=await this.logCtx([...a,t],this.read);return r.info(`reading entry with pk ${e} `),this.repo.read(e,...n)}getTransientData(t){const e=t.stub.getTransient();let a={};return e.has(this.repo.tableName)&&(a=JSON.parse(e.get(this.repo.tableName)?.toString("utf8"))),a}async update(t,e,...r){const{log:n,ctxArgs:i}=await this.logCtx([...r,t],this.update);"string"==typeof e&&(e=this.deserialize(e)),n.info("Updating model: "+JSON.stringify(e));const o=this.getTransientData(t);return n.info("Merging transient data..."),e=a.Model.merge(e,o,this.clazz),this.repo.update(e,...i)}async delete(t,e,...a){const{log:r,ctxArgs:n}=await this.logCtx([...a,t],this.delete);return r.info(`deleting entry with pk ${e} `),this.repo.delete(e+"",...n)}async deleteAll(t,e,...a){const{ctxArgs:r}=await this.logCtx([...a,t],this.readAll);return"string"==typeof e&&(e=JSON.parse(e)),this.repo.deleteAll(e,...r)}async readAll(t,e,...a){const{ctxArgs:r}=await this.logCtx([...a,t],this.readAll);return"string"==typeof e&&(e=JSON.parse(e)),this.repo.readAll(e,...r)}async updateAll(t,e,...a){const{log:r,ctxArgs:n}=await this.logCtx([...a,t],this.updateAll);return"string"==typeof e&&(e=JSON.parse(e).map((t=>this.deserialize(t))).map((t=>new this.clazz(t)))),r.info(`updating ${e.length} entries to the table`),this.repo.updateAll(e,...n)}async query(t,e,a,n=r.OrderDirection.ASC,i,o,...s){const{ctxArgs:c}=await this.logCtx([...s,t],this.query);return this.repo.query(e,a,n,i,o,...c)}async raw(t,e,a,...r){const{ctxArgs:n}=await this.logCtx([...r,t],this.raw);return"string"==typeof e&&(e=JSON.parse(e)),T.adapter.raw(e,a,...n)}serialize(t){return T.serializer.serialize(t)}deserialize(t){return T.serializer.deserialize(t)}async init(t){const{log:e}=await this.logCtx([t],this.init);e.info(`Running contract ${this.getName()} initialization...`),this.initialized=!0,e.info("Contract initialization completed.")}async healthcheck(t){const{log:e}=await this.logCtx([t],this.healthcheck);return e.info(`Running Healthcheck: ${this.initialized}...`),{healthcheck:this.initialized}}async createAll(t,e,...a){const{log:r}=await this.logCtx([...a,t],this.createAll);return"string"==typeof e&&(e=JSON.parse(e).map((t=>this.deserialize(t))).map((t=>new this.clazz(t)))),r.info(`adding ${e.length} entries to the table`),this.repo.createAll(e,t,...a)}async logCtx(t,e){return T.logCtx.bind(this)(t,e)}static async logCtx(t,e){if(1>t.length)throw new n.InternalError("No context provided");const a=t.pop();if(a instanceof l)return{ctx:a,log:a.logger.clear().for(this).for(e),ctxArgs:[...t,a],stub:a.stub,identity:a.identity};if(!(a instanceof i.Context))throw new n.InternalError("No valid context provided");const r={correlationId:a.stub.getTxID()},o=await T.adapter.context((()=>{if("string"==typeof e)return e;switch(e.name){case n.OperationKeys.CREATE:case n.OperationKeys.READ:case n.OperationKeys.UPDATE:case n.OperationKeys.DELETE:case n.BulkCrudOperationKeys.CREATE_ALL:case n.BulkCrudOperationKeys.READ_ALL:case n.BulkCrudOperationKeys.UPDATE_ALL:case n.BulkCrudOperationKeys.DELETE_ALL:}return e.name})(),r,this.clazz,a),s=this?o.logger.for(this).for(e):o.logger.clear().for(this).for(e);return{ctx:o,log:s,stub:o.stub,identity:o.identity,ctxArgs:[...t,o]}}}class N extends T{constructor(t,e){super(t,e)}async create(t,e){const{log:a,ctx:r}=await this.logCtx([t],this.create);a.info("Creating model: "+e);const n=this.deserialize(e);return a.info("Model deserialized: "+JSON.stringify(n)),this.serialize(await super.create(r,n))}async read(t,e){const{log:a,ctx:r}=await this.logCtx([t],this.read);return a.info("Reading id: "+e),this.serialize(await super.read(r,e))}async update(t,e){const{log:a,ctx:r}=await this.logCtx([t],this.update);return a.info("Updating model: "+e),this.serialize(await super.update(r,e))}async delete(t,e){const{log:a,ctx:r}=await this.logCtx([t],this.delete);return a.info("Deleting id: "+e),this.serialize(await super.delete(r,e))}async deleteAll(t,e){const a=JSON.parse(e),{log:r,ctx:n}=await this.logCtx([t],this.deleteAll);return r.info(`deleting ${a.length} entries from the table`),JSON.stringify((await super.deleteAll(n,a)).map((t=>this.serialize(t))))}async readAll(t,e){const a=JSON.parse(e),{log:r,ctx:n}=await this.logCtx([t],this.readAll);return r.info(`reading ${a.length} entries from the table`),JSON.stringify((await super.readAll(n,a)).map((t=>this.serialize(t))))}async updateAll(t,e){const{log:a,ctx:r}=await this.logCtx([t],this.updateAll),n=JSON.parse(e).map((t=>this.deserialize(t))).map((t=>new this.clazz(t)));return a.info(`Updating ${n.length} entries to the table`),JSON.stringify((await super.updateAll(r,n)).map((t=>this.serialize(t))))}async statement(t,e,...a){const{ctx:r,log:n}=await this.logCtx([...a,t],this.statement);return a=a.map((t=>{try{return JSON.parse(t)}catch(e){return t}})),n.info("calling prepared statement "+e),n.debug("with args "+a),super.statement(r,e,...a)}async listBy(t,e,a,...r){const{ctx:n}=await this.logCtx([...r,t],this.listBy);return super.listBy(n,e,a)}async paginateBy(t,e,a,r,...n){const{ctx:i}=await this.logCtx([...n,t],this.paginateBy);return super.paginateBy(i,e,a,r)}async findOneBy(t,e,a,...r){const{ctx:n}=await this.logCtx([...r,t],this.paginateBy);return super.findOneBy(n,e,a,...r)}async query(t,e,a,i,o,s,...c){const{ctx:l}=await this.logCtx([t],this.query);let d;try{d=r.Condition.from(JSON.parse(e))}catch(t){throw new n.SerializationError("Invalid condition: "+t)}return super.query(l,d,a,i,o,s,...c)}async raw(t,e,a,...r){const{ctx:n}=await this.logCtx([t],this.raw),i=JSON.parse(e);return super.raw(n,i,a,...r)}async init(t){await super.init(t)}async healthcheck(t){const{log:e,ctx:a}=await this.logCtx([t],this.updateAll);return e.debug(`Running Healthcheck: ${this.initialized}...`),JSON.stringify(await super.healthcheck(a))}async createAll(t,e){const{log:a}=await this.logCtx([t],this.createAll),r=JSON.parse(e).map((t=>this.deserialize(t))).map((t=>new this.clazz(t)));return a.info(`Adding ${r.length} entries to the table`),JSON.stringify((await super.createAll(t,r)).map((t=>this.serialize(t))))}}c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String]),c.__metadata("design:returntype",Promise)],N.prototype,"create",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String]),c.__metadata("design:returntype",Promise)],N.prototype,"read",null),c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String]),c.__metadata("design:returntype",Promise)],N.prototype,"update",null),c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String]),c.__metadata("design:returntype",Promise)],N.prototype,"delete",null),c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String]),c.__metadata("design:returntype",Promise)],N.prototype,"deleteAll",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String]),c.__metadata("design:returntype",Promise)],N.prototype,"readAll",null),c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String]),c.__metadata("design:returntype",Promise)],N.prototype,"updateAll",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String,String]),c.__metadata("design:returntype",Promise)],N.prototype,"statement",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String,String,String]),c.__metadata("design:returntype",Promise)],N.prototype,"listBy",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String,String,Number,String]),c.__metadata("design:returntype",Promise)],N.prototype,"paginateBy",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String,String,String]),c.__metadata("design:returntype",Promise)],N.prototype,"findOneBy",null),c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],N.prototype,"init",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],N.prototype,"healthcheck",null),c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String]),c.__metadata("design:returntype",Promise)],N.prototype,"createAll",null);class k extends n.InternalError{constructor(t){super(t,k.name)}}class D extends n.InternalError{constructor(t){super(t,D.name)}}class P extends n.InternalError{constructor(t){super(t,P.name)}}class R extends n.BaseError{constructor(t){super(R.name,t,409)}}function z(t,e){const a=t+e;if(t!==a-e||e!==a-t)throw new k(`Addition overflow: ${t} + ${e}`);return a}function B(t,e){const a=t-e;if(t!==a+e||e!==t-a)throw new k(`Subtraction overflow: ${t} - ${e}`);return a}let I=class extends r.BaseModel{constructor(t){super(t)}};c.__decorate([r.pk({type:"String"}),c.__metadata("design:type",String)],I.prototype,"name",void 0),c.__decorate([r.column(),a.required(),c.__metadata("design:type",String)],I.prototype,"owner",void 0),c.__decorate([r.column(),a.required(),c.__metadata("design:type",String)],I.prototype,"symbol",void 0),c.__decorate([r.column(),a.required(),c.__metadata("design:type",Number)],I.prototype,"decimals",void 0),I=c.__decorate([r.table("erc20_tokens"),a.model(),c.__metadata("design:paramtypes",[Object])],I);let F=class extends r.BaseModel{constructor(t){super(t)}};c.__decorate([r.pk({type:"String"}),c.__metadata("design:type",String)],F.prototype,"id",void 0),c.__decorate([r.column(),a.required(),c.__metadata("design:type",String)],F.prototype,"token",void 0),c.__decorate([r.column(),a.required(),c.__metadata("design:type",Number)],F.prototype,"balance",void 0),c.__decorate([r.column(),c.__metadata("design:type",String)],F.prototype,"captive",void 0),F=c.__decorate([r.table("erc20_wallets"),a.model(),c.__metadata("design:paramtypes",[Object])],F);let M=class extends r.BaseModel{constructor(t){super(t)}};function $(){return function(t,e,a){const i=a.value;return a.value=async function(...t){const a=t[0],o=a.clientIdentity.getID(),s=await this.tokenRepository.select(),c=await s.execute(a);if(0==c.length)throw new n.NotFoundError("No tokens avaialble");if(c.length>1)throw new n.NotFoundError("To many token available : "+c.length);if(c[0].owner!=o)throw new r.AuthorizationError(`User not authorized to run ${e} on the token`);return await i.apply(this,t)},a}}var L;c.__decorate([r.pk({type:"String"}),r.column(),a.required(),c.__metadata("design:type",String)],M.prototype,"owner",void 0),c.__decorate([r.column(),a.required(),c.__metadata("design:type",String)],M.prototype,"spender",void 0),c.__decorate([r.column(),a.required(),c.__metadata("design:type",Number)],M.prototype,"value",void 0),M=c.__decorate([r.table("erc20_allowances"),a.model(),c.__metadata("design:paramtypes",[Object])],M),(t=>{t.TRANSFER="Transfer",t.APPROVAL="Approval"})(L||(L={}));class q extends T{constructor(t){super(t,F),q.adapter=q.adapter||new v,this.walletRepository=u.forModel(F,q.adapter.alias),this.tokenRepository=u.forModel(I,q.adapter.alias),this.allowanceRepository=u.forModel(M,q.adapter.alias)}async TokenName(t){const{ctx:e}=await this.logCtx([t],this.TokenName);await this.CheckInitialized(e);const a=this.tokenRepository.select();return(await a.execute(e))[0].name}async Symbol(t){const{ctx:e}=await this.logCtx([t],this.TokenName);await this.CheckInitialized(e);const a=this.tokenRepository.select();return(await a.execute(e))[0].symbol}async Decimals(t){const{ctx:e}=await this.logCtx([t],this.TokenName);await this.CheckInitialized(e);const a=this.tokenRepository.select();return(await a.execute(e))[0].decimals}async TotalSupply(t){const{ctx:e}=await this.logCtx([t],this.TokenName);await this.CheckInitialized(e);const a=this.walletRepository.select(),r=await a.execute(e);if(0==r.length)throw new n.NotFoundError(`The token ${this.getName()} does not exist`);let i=0;return r.forEach((t=>{i+=t.balance})),i}async BalanceOf(t,e){const{ctx:a}=await this.logCtx([t],this.TokenName);return await this.CheckInitialized(a),(await this.walletRepository.read(e,a)).balance}async Transfer(t,e,a){const{ctx:r}=await this.logCtx([t],this.Transfer);await this.CheckInitialized(r);const i=r.identity.getID();if(!await this._transfer(i,e,a,r))throw new n.InternalError("Failed to transfer");return!0}async TransferFrom(t,e,a,r){const{ctx:i}=await this.logCtx([t],this.BurnFrom);await this.CheckInitialized(i);const o=i.identity.getID(),s=await this._getAllowance(e,o,i);if(!s||0>s.value)throw new P(`spender ${o} has no allowance from ${e}`);const c=s.value;if(r>c)throw new D("The spender does not have enough allowance to spend.");const l=B(c,r),d=Object.assign({},s,{value:l});if(await this.allowanceRepository.update(d,i),!await this._transfer(e,a,r,i))throw new n.InternalError("Failed to transfer");return!0}async _transfer(t,e,a,i){const o=i.logger;if(t===e)throw new r.AuthorizationError("cannot transfer to and from same client account");if(0>a)throw new D("transfer amount cannot be negative");const s=await this.walletRepository.read(t,i),c=s.balance;if(a>c)throw new D(`client account ${t} has insufficient funds.`);let l,d=!1;try{l=await this.walletRepository.read(e,i)}catch(t){if(!(t instanceof n.BaseError))throw new n.InternalError(t);if(404!==t.code)throw new n.InternalError(t.message);l=new F({id:e,balance:0,token:await this.TokenName(i)}),d=!0}const u=l.balance,p=B(c,a),g=z(u,a),h=Object.assign({},s,{balance:p});await this.walletRepository.update(h,i);const y=Object.assign({},l,{balance:g});d?await this.walletRepository.create(y,i):await this.walletRepository.update(y,i);const m={from:t,to:e,value:a};return this.repo.refresh(I,L.TRANSFER,"",m,i).catch((t=>o.error("Failed to notify transfer: "+t))),!0}async Approve(t,e,a){const{ctx:r,ctxArgs:n}=await this.logCtx([t],this.Approve);await this.CheckInitialized(r);const i=r.identity.getID();let o=await this._getAllowance(i,e,r);if((await this.walletRepository.read(i,...n)).balance<a)throw new D(`client account ${i} has insufficient funds.`);o?(o.value=a,await this.allowanceRepository.update(o,...n)):(o=new M({owner:i,spender:e,value:a}),await this.allowanceRepository.create(o,...n));const s={owner:i,spender:e,value:a};return this.repo.refresh(I,L.APPROVAL,"",s,r),!0}async Allowance(t,e,a){const{ctx:r}=await this.logCtx([t],this.Allowance);await this.CheckInitialized(r);const n=await this._getAllowance(e,a,r);if(!n)throw new P(`spender ${a} has no allowance from ${e}`);return n.value}async _getAllowance(t,e,a){const n=r.Condition.and(r.Condition.attribute("owner").eq(t),r.Condition.attribute("spender").eq(e)),i=await this.allowanceRepository.select().where(n).execute(a);return i?.[0]}async Initialize(t,e){const{ctx:a}=await this.logCtx([t],this.Initialize);if((await this.tokenRepository.select().execute(a)).length>0)throw new r.AuthorizationError("contract options are already set, client is not authorized to change them");return e.owner=a.identity.getID(),await this.tokenRepository.create(e,a),!0}async CheckInitialized(t){const{ctx:e}=await this.logCtx([t],this.CheckInitialized);if(0==(await this.tokenRepository.select().execute(e)).length)throw new R("contract options need to be set before calling any function, call Initialize() to initialize contract")}async Mint(t,e){const{ctx:a}=await this.logCtx([t],this.Mint);await this.CheckInitialized(a);const r=a.identity.getID();if(0>=e)throw new n.ValidationError("mint amount must be a positive integer");let i;try{i=await this.walletRepository.read(r,a);const t=z(i.balance,e),n=Object.assign({},i,{balance:t});await this.walletRepository.update(n,a)}catch(i){if(!(i instanceof n.BaseError))throw new n.InternalError(i);if(404!==i.code)throw new n.InternalError(i.message);{const n=new F({id:r,balance:e,token:await this.TokenName(t)});await this.walletRepository.create(n,a)}}const o={from:"0x0",to:r,value:e};this.repo.ObserverHandler().updateObservers(I,L.TRANSFER,"",o,a)}async Burn(t,e){const{log:a,ctx:r}=await this.logCtx([t],this.Burn);await this.CheckInitialized(r);const n=r.identity.getID(),i=await this.walletRepository.read(n,r),o=i.balance;if(e>o)throw new D("Minter has insufficient funds.");const s=B(o,e),c=Object.assign({},i,{balance:s});await this.walletRepository.update(c,r),a.info(e+" tokens were burned");const l={from:n,to:"0x0",value:e};this.repo.ObserverHandler().updateObservers(I,L.TRANSFER,"",l,r)}async BurnFrom(t,e,a){const{log:r,ctx:n}=await this.logCtx([t],this.BurnFrom);await this.CheckInitialized(n);const i=await this.walletRepository.read(e,n),o=i.balance;if(a>o)throw new D(e+" has insufficient funds.");const s=B(o,a),c=Object.assign({},i,{balance:s});await this.walletRepository.update(c,n),r.info(`${a} tokens were burned from ${e}`);const l={from:e,to:"0x0",value:a};this.repo.ObserverHandler().updateObservers(I,L.TRANSFER,"",l,n)}async ClientAccountBalance(t){const{ctx:e}=await this.logCtx([t],this.TokenName);await this.CheckInitialized(e);const a=e.identity.getID(),r=await this.walletRepository.read(a,e);if(!r)throw new D(`The account ${a} does not exist`);return r.balance}async ClientAccountID(t){const{ctx:e}=await this.logCtx([t],this.ClientAccountID);return await this.CheckInitialized(e),e.identity.getID()}}c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],q.prototype,"TokenName",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],q.prototype,"Symbol",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],q.prototype,"Decimals",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],q.prototype,"TotalSupply",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String]),c.__metadata("design:returntype",Promise)],q.prototype,"BalanceOf",null),c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String,Number]),c.__metadata("design:returntype",Promise)],q.prototype,"Transfer",null),c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String,String,Number]),c.__metadata("design:returntype",Promise)],q.prototype,"TransferFrom",null),c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String,Number]),c.__metadata("design:returntype",Promise)],q.prototype,"Approve",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String,String]),c.__metadata("design:returntype",Promise)],q.prototype,"Allowance",null),c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,I]),c.__metadata("design:returntype",Promise)],q.prototype,"Initialize",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],q.prototype,"CheckInitialized",null),c.__decorate([$(),i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,Number]),c.__metadata("design:returntype",Promise)],q.prototype,"Mint",null),c.__decorate([$(),i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,Number]),c.__metadata("design:returntype",Promise)],q.prototype,"Burn",null),c.__decorate([$(),i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String,Number]),c.__metadata("design:returntype",Promise)],q.prototype,"BurnFrom",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],q.prototype,"ClientAccountBalance",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],q.prototype,"ClientAccountID",null);const K=[q],j="##VERSION##",J="##PACKAGE##";o.Metadata.registerLibrary(J,j),t.ContractLogger=A,t.FabricContractAdapter=v,t.FabricContractContext=l,t.FabricContractRepository=u,t.FabricContractRepositoryObservableHandler=d,t.FabricCrudContract=T,t.FabricStatement=p,t.PACKAGE_NAME=J,t.SerializedCrudContract=N,t.VERSION=j,t.contracts=K,t.createdByOnFabricCreateUpdate=S,t.pkFabricOnCreate=E},"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("@decaf-ts/for-couchdb"),require("@decaf-ts/decorator-validation"),require("@decaf-ts/core"),require("@decaf-ts/db-decorators"),require("fabric-contract-api"),require("@decaf-ts/decoration"),require("@decaf-ts/logging"),require("tslib")):"function"==typeof define&&define.amd?define(["exports","@decaf-ts/for-couchdb","@decaf-ts/decorator-validation","@decaf-ts/core","@decaf-ts/db-decorators","fabric-contract-api","@decaf-ts/decoration","@decaf-ts/logging","tslib"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self)["for-fabric"]={},t.decafTsForCouchdb,t.decafTsDecoratorValidation,t.decafTsCore,t.decafTsDbDecorators,t.fabricContractApi,t.decafTsDecoration,t.decafTsLogging,t.tslib);
2
- //# sourceMappingURL=for-fabric.cjs.map
1
+ (function(global, factory) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@decaf-ts/for-couchdb"), require("@decaf-ts/decorator-validation"), require("@decaf-ts/core"), require("@decaf-ts/db-decorators"), require("fabric-contract-api"), require("@decaf-ts/decoration"), require("@decaf-ts/logging"), require("tslib")) : typeof define === "function" && define.amd ? define([ "exports", "@decaf-ts/for-couchdb", "@decaf-ts/decorator-validation", "@decaf-ts/core", "@decaf-ts/db-decorators", "fabric-contract-api", "@decaf-ts/decoration", "@decaf-ts/logging", "tslib" ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self,
3
+ factory(global["for-fabric"] = {}, global.decafTsForCouchdb, global.decafTsDecoratorValidation, global.decafTsCore, global.decafTsDbDecorators, global.fabricContractApi, global.decafTsDecoration, global.decafTsLogging, global.tslib));
4
+ })(this, function(exports, forCouchdb, decoratorValidation, core, dbDecorators, fabricContractApi, decoration, logging, tslib) {
5
+ "use strict";
6
+ class FabricContractContext extends core.Context {
7
+ constructor() {
8
+ super();
9
+ }
10
+ get stub() {
11
+ return this.get("stub");
12
+ }
13
+ get timestamp() {
14
+ return this.stub.getDateTimestamp();
15
+ }
16
+ get identity() {
17
+ return this.get("identity");
18
+ }
19
+ toString() {
20
+ return `fabric ctx${this.stub ? " with stub" : "without stub"}`;
21
+ }
22
+ }
23
+ function generateFabricEventName(table, event, owner) {
24
+ const params = [ table, event ];
25
+ if (owner) params.push(owner);
26
+ return params.join("_");
27
+ }
28
+ function parseEventName(name) {
29
+ const parts = name.split("_");
30
+ if (parts.length < 2 || parts.length > 3) return {
31
+ table: undefined,
32
+ event: name,
33
+ owner: undefined
34
+ };
35
+ return {
36
+ table: parts[0],
37
+ event: parts[1],
38
+ owner: parts[2]
39
+ };
40
+ }
41
+ class FabricContractRepositoryObservableHandler extends core.ObserverHandler {
42
+ constructor(supportedEvents = [ dbDecorators.OperationKeys.CREATE, dbDecorators.OperationKeys.UPDATE, dbDecorators.OperationKeys.DELETE, dbDecorators.BulkCrudOperationKeys.CREATE_ALL, dbDecorators.BulkCrudOperationKeys.UPDATE_ALL, dbDecorators.BulkCrudOperationKeys.DELETE_ALL ]) {
43
+ super();
44
+ this.supportedEvents = supportedEvents;
45
+ }
46
+ async updateObservers(clazz, event, id, ...args) {
47
+ const {log: log, ctx: ctx} = core.Adapter.logCtx(args, this.updateObservers);
48
+ const {stub: stub} = ctx;
49
+ const [owner, payload] = args;
50
+ const table = typeof clazz === "string" ? clazz : clazz.name;
51
+ if (this.supportedEvents.indexOf(event) !== -1) {
52
+ log.debug(`Emitting ${event} event`);
53
+ const eventName = generateFabricEventName(table, event, owner);
54
+ stub.setEvent(eventName, Buffer.from(JSON.stringify({
55
+ id: id
56
+ })));
57
+ } else {
58
+ stub.setEvent(event, Buffer.from(JSON.stringify(payload)));
59
+ }
60
+ }
61
+ }
62
+ class FabricContractRepository extends core.Repository {
63
+ constructor(adapter, clazz, trackedEvents) {
64
+ super(adapter, clazz);
65
+ this.trackedEvents = trackedEvents;
66
+ }
67
+ ObserverHandler() {
68
+ return new FabricContractRepositoryObservableHandler;
69
+ }
70
+ async updateObservers(table, event, id, ...args) {
71
+ if (!this.trackedEvents || this.trackedEvents.indexOf(event) !== -1) return await super.updateObservers(table, event, id, ...args);
72
+ }
73
+ }
74
+ class FabricStatement extends forCouchdb.CouchDBStatement {
75
+ constructor(adapter) {
76
+ super(adapter);
77
+ }
78
+ async raw(rawInput, ...args) {
79
+ const {ctx: ctx} = this.logCtx(args, this.raw);
80
+ const results = await this.adapter.raw(rawInput, true, ctx);
81
+ const pkAttr = decoratorValidation.Model.pk(this.fromSelector);
82
+ const type = decoration.Metadata.get(this.fromSelector, decoration.Metadata.key(dbDecorators.DBKeys.ID, pkAttr))?.type;
83
+ if (!this.selectSelector) return results.map(r => this.processRecord(r, pkAttr, type, ctx));
84
+ return results;
85
+ }
86
+ build() {
87
+ const selectors = {};
88
+ selectors[forCouchdb.CouchDBKeys.TABLE] = {};
89
+ selectors[forCouchdb.CouchDBKeys.TABLE] = decoratorValidation.Model.tableName(this.fromSelector);
90
+ const query = {
91
+ selector: selectors
92
+ };
93
+ if (this.selectSelector) query.fields = this.selectSelector;
94
+ if (this.whereCondition) {
95
+ const condition = this.parseCondition(core.Condition.and(this.whereCondition, core.Condition.attribute(forCouchdb.CouchDBKeys.TABLE).eq(query.selector[forCouchdb.CouchDBKeys.TABLE]))).selector;
96
+ const selectorKeys = Object.keys(condition);
97
+ if (selectorKeys.length === 1 && Object.values(forCouchdb.CouchDBGroupOperator).indexOf(selectorKeys[0]) !== -1) switch (selectorKeys[0]) {
98
+ case forCouchdb.CouchDBGroupOperator.AND:
99
+ condition[forCouchdb.CouchDBGroupOperator.AND] = [ ...Object.values(condition[forCouchdb.CouchDBGroupOperator.AND]).reduce((accum, val) => {
100
+ const keys = Object.keys(val);
101
+ if (keys.length !== 1) throw new Error("Too many keys in query selector. should be one");
102
+ const k = keys[0];
103
+ if (k === forCouchdb.CouchDBGroupOperator.AND) accum.push(...val[k]); else accum.push(val);
104
+ return accum;
105
+ }, []) ];
106
+ query.selector = condition;
107
+ break;
108
+
109
+ case forCouchdb.CouchDBGroupOperator.OR:
110
+ {
111
+ const s = {};
112
+ s[forCouchdb.CouchDBGroupOperator.AND] = [ condition, ...Object.entries(query.selector).map(([key, val]) => {
113
+ const result = {};
114
+ result[key] = val;
115
+ return result;
116
+ }) ];
117
+ query.selector = s;
118
+ break;
119
+ }
120
+
121
+ default:
122
+ throw new Error("This should be impossible");
123
+ } else {
124
+ Object.entries(condition).forEach(([key, val]) => {
125
+ if (query.selector[key]) console.warn(`A ${key} query param is about to be overridden: ${query.selector[key]} by ${val}`);
126
+ query.selector[key] = val;
127
+ });
128
+ }
129
+ }
130
+ if (this.orderBySelector) {
131
+ query.sort = query.sort || [];
132
+ query.selector = query.selector || {};
133
+ const [selector, value] = this.orderBySelector;
134
+ const rec = {};
135
+ rec[selector] = value;
136
+ query.sort.push(rec);
137
+ if (!query.selector[selector]) {
138
+ query.selector[selector] = {};
139
+ query.selector[selector][forCouchdb.CouchDBOperator.BIGGER] = null;
140
+ }
141
+ }
142
+ if (this.limitSelector) query.limit = this.limitSelector;
143
+ if (this.offsetSelector) query.skip = this.offsetSelector;
144
+ return query;
145
+ }
146
+ }
147
+ var FabricModelKeys;
148
+ (function(FabricModelKeys) {
149
+ FabricModelKeys["PRIVATE"] = "private";
150
+ FabricModelKeys["SHARED"] = "shared";
151
+ FabricModelKeys["FABRIC"] = "fabric.";
152
+ FabricModelKeys["OWNEDBY"] = "owned-by";
153
+ })(FabricModelKeys || (FabricModelKeys = {}));
154
+ var IdentityType;
155
+ (function(IdentityType) {
156
+ IdentityType["X509"] = "X.509";
157
+ })(IdentityType || (IdentityType = {}));
158
+ const FabricFlavour = "hlf-fabric";
159
+ class SimpleDeterministicSerializer extends decoratorValidation.JSONSerializer {
160
+ constructor() {
161
+ super();
162
+ }
163
+ deserialize(str, tableName) {
164
+ const deserialization = JSON.parse(str);
165
+ return deserialization;
166
+ }
167
+ serialize(model) {
168
+ const stringify = require("json-stringify-deterministic");
169
+ const sortKeysRecursive = require("sort-keys-recursive");
170
+ return stringify(sortKeysRecursive(this.preSerialize(model)));
171
+ }
172
+ preSerialize(model) {
173
+ const toSerialize = Object.assign({}, model);
174
+ return toSerialize;
175
+ }
176
+ }
177
+ async function oneToOneOnCreate(context, data, key, model) {
178
+ const propertyValue = model[key];
179
+ if (!propertyValue) return;
180
+ if (typeof propertyValue !== "object") {
181
+ const innerRepo = core.repositoryFromTypeMetadata(model, key, this.adapter.alias);
182
+ const read = await innerRepo.read(propertyValue, context);
183
+ await core.cacheModelForPopulate(context, model, key, propertyValue, read);
184
+ model[key] = propertyValue;
185
+ return;
186
+ }
187
+ data.class = typeof data.class === "string" ? data.class : data.class().name;
188
+ const constructor = decoratorValidation.Model.get(data.class);
189
+ if (!constructor) throw new dbDecorators.InternalError(`Could not find model ${data.class}`);
190
+ const repo = core.Repository.forModel(constructor, this.adapter.alias);
191
+ const created = await repo.create(propertyValue, context);
192
+ const pk = decoratorValidation.Model.pk(created);
193
+ await core.cacheModelForPopulate(context, model, key, created[pk], created);
194
+ model[key] = created[pk];
195
+ }
196
+ async function oneToOneOnUpdate(context, data, key, model) {
197
+ const propertyValue = model[key];
198
+ if (!propertyValue) return;
199
+ if (data.cascade.update !== core.Cascade.CASCADE) return;
200
+ if (typeof propertyValue !== "object") {
201
+ const innerRepo = core.repositoryFromTypeMetadata(model, key, this.adapter.alias);
202
+ const read = await innerRepo.read(propertyValue, context);
203
+ await core.cacheModelForPopulate(context, model, key, propertyValue, read);
204
+ model[key] = propertyValue;
205
+ return;
206
+ }
207
+ const updated = await core.createOrUpdate(model[key], context, this.adapter.alias);
208
+ const pk = decoratorValidation.Model.pk(updated);
209
+ await core.cacheModelForPopulate(context, model, key, updated[pk], updated);
210
+ model[key] = updated[pk];
211
+ }
212
+ async function oneToOneOnDelete(context, data, key, model) {
213
+ const propertyValue = model[key];
214
+ if (!propertyValue) return;
215
+ if (data.cascade.update !== core.Cascade.CASCADE) return;
216
+ const innerRepo = core.repositoryFromTypeMetadata(model, key, this.adapter.alias);
217
+ let deleted;
218
+ if (!(propertyValue instanceof decoratorValidation.Model)) deleted = await innerRepo.delete(model[key], context); else deleted = await innerRepo.delete(model[key][decoratorValidation.Model.pk(innerRepo.class)], context);
219
+ await core.cacheModelForPopulate(context, model, key, deleted[decoratorValidation.Model.pk(innerRepo.class)], deleted);
220
+ }
221
+ async function oneToManyOnCreate(context, data, key, model) {
222
+ const propertyValues = model[key];
223
+ if (!propertyValues || !propertyValues.length) return;
224
+ const arrayType = typeof propertyValues[0];
225
+ if (!propertyValues.every(item => typeof item === arrayType)) throw new dbDecorators.InternalError(`Invalid operation. All elements of property ${key} must match the same type.`);
226
+ const uniqueValues = new Set([ ...propertyValues ]);
227
+ if (arrayType !== "object") {
228
+ const repo = core.repositoryFromTypeMetadata(model, key, this.adapter.alias);
229
+ for (const id of uniqueValues) {
230
+ const read = await repo.read(id, context);
231
+ await core.cacheModelForPopulate(context, model, key, id, read);
232
+ }
233
+ model[key] = [ ...uniqueValues ];
234
+ return;
235
+ }
236
+ const pkName = decoratorValidation.Model.pk(propertyValues[0]);
237
+ const result = new Set;
238
+ for (const m of propertyValues) {
239
+ const record = await core.createOrUpdate(m, context, this.adapter.alias);
240
+ await core.cacheModelForPopulate(context, model, key, record[pkName], record);
241
+ result.add(record[pkName]);
242
+ }
243
+ model[key] = [ ...result ];
244
+ }
245
+ async function oneToManyOnDelete(context, data, key, model) {
246
+ if (data.cascade.delete !== core.Cascade.CASCADE) return;
247
+ const values = model[key];
248
+ if (!values || !values.length) return;
249
+ const arrayType = typeof values[0];
250
+ const areAllSameType = values.every(item => typeof item === arrayType);
251
+ if (!areAllSameType) throw new dbDecorators.InternalError(`Invalid operation. All elements of property ${key} must match the same type.`);
252
+ const isInstantiated = arrayType === "object";
253
+ const repo = isInstantiated ? core.Repository.forModel(values[0], this.adapter.alias) : core.repositoryFromTypeMetadata(model, key, this.adapter.alias);
254
+ const uniqueValues = new Set([ ...isInstantiated ? values.map(v => v[decoratorValidation.Model.pk(this.class)]) : values ]);
255
+ for (const id of uniqueValues.values()) {
256
+ const deleted = await repo.delete(id, context);
257
+ await core.cacheModelForPopulate(context, model, key, id, deleted);
258
+ }
259
+ model[key] = [ ...uniqueValues ];
260
+ }
261
+ async function populate(context, data, key, model) {
262
+ if (!data.populate) return;
263
+ const nested = model[key];
264
+ const isArr = Array.isArray(nested);
265
+ if (typeof nested === "undefined" || isArr && nested.length === 0) return;
266
+ async function fetchPopulateValues(c, model, propName, propKeyValues, alias) {
267
+ let cacheKey;
268
+ let val;
269
+ const results = [];
270
+ for (const proKeyValue of propKeyValues) {
271
+ cacheKey = core.getPopulateKey(model.constructor.name, propName, proKeyValue);
272
+ try {
273
+ val = await c.get(cacheKey);
274
+ } catch (e) {
275
+ const repo = core.repositoryFromTypeMetadata(model, propName, alias);
276
+ if (!repo) throw new dbDecorators.InternalError("Could not find repo");
277
+ val = await repo.read(proKeyValue, context);
278
+ }
279
+ results.push(val);
280
+ }
281
+ return results;
282
+ }
283
+ const res = await fetchPopulateValues(context, model, key, isArr ? nested : [ nested ], this.adapter.alias);
284
+ model[key] = isArr ? res : res[0];
285
+ }
286
+ class ContractLogger extends logging.MiniLogger {
287
+ constructor(context, conf, ctx) {
288
+ super(context, conf);
289
+ if (!ctx) {
290
+ this.logger = new logging.MiniLogger(context, conf);
291
+ } else {
292
+ this.logger = ctx.logging.getLogger(context);
293
+ }
294
+ }
295
+ log(level, msg, stack) {
296
+ if (logging.NumericLogLevels[this.config("level")] < logging.NumericLogLevels[level]) return;
297
+ let method;
298
+ switch (level) {
299
+ case logging.LogLevel.info:
300
+ method = this.logger.info;
301
+ break;
302
+
303
+ case logging.LogLevel.verbose:
304
+ method = this.logger.verbose;
305
+ break;
306
+
307
+ case logging.LogLevel.debug:
308
+ method = this.logger.debug;
309
+ break;
310
+
311
+ case logging.LogLevel.error:
312
+ method = this.logger.error;
313
+ break;
314
+
315
+ case logging.LogLevel.silly:
316
+ method = this.logger.silly;
317
+ break;
318
+
319
+ default:
320
+ throw new dbDecorators.InternalError("Invalid log level");
321
+ }
322
+ method.call(this.logger, this.createLog(level, msg, stack));
323
+ }
324
+ }
325
+ const factory = (object, config, ctx) => new ContractLogger(object || ContractLogger.name, config || {}, ctx);
326
+ logging.Logging.setFactory(factory);
327
+ async function createdByOnFabricCreateUpdate(context, data, key, model) {
328
+ try {
329
+ const user = context.get("identity");
330
+ model[key] = user.getID();
331
+ } catch (e) {
332
+ throw new core.UnsupportedError("No User found in context. Please provide a user in the context");
333
+ }
334
+ }
335
+ async function pkFabricOnCreate(context, data, key, model) {
336
+ if (!data.type || model[key]) {
337
+ return;
338
+ }
339
+ const setPrimaryKeyValue = function(target, propertyKey, value) {
340
+ Object.defineProperty(target, propertyKey, {
341
+ enumerable: true,
342
+ writable: false,
343
+ configurable: true,
344
+ value: value
345
+ });
346
+ };
347
+ if (!data.name) data.name = decoratorValidation.Model.sequenceName(model, "pk");
348
+ let sequence;
349
+ try {
350
+ sequence = await this.adapter.Sequence(data);
351
+ } catch (e) {
352
+ throw new dbDecorators.InternalError(`Failed to instantiate Sequence ${data.name}: ${e}`);
353
+ }
354
+ const next = await sequence.next(context);
355
+ setPrimaryKeyValue(model, key, next);
356
+ }
357
+ class FabricContractAdapter extends forCouchdb.CouchDBAdapter {
358
+ getClient() {
359
+ throw new core.UnsupportedError("Client is not supported in Fabric contracts");
360
+ }
361
+ static {
362
+ this.textDecoder = new TextDecoder("utf8");
363
+ }
364
+ static {
365
+ this.serializer = new SimpleDeterministicSerializer;
366
+ }
367
+ repository() {
368
+ return FabricContractRepository;
369
+ }
370
+ constructor(scope, alias) {
371
+ super(scope, FabricFlavour, alias);
372
+ this.Context = FabricContractContext;
373
+ }
374
+ for(config, ...args) {
375
+ return super.for(config, ...args);
376
+ }
377
+ async create(clazz, id, model, ...args) {
378
+ const {ctx: ctx, log: log, stub: stub} = this.logCtx(args, this.create);
379
+ log.info(`in ADAPTER create with args ${args}`);
380
+ const tableName = decoratorValidation.Model.tableName(clazz);
381
+ try {
382
+ log.info(`adding entry to ${tableName} table with pk ${id}`);
383
+ const composedKey = stub.createCompositeKey(tableName, [ String(id) ]);
384
+ model = await this.putState(composedKey, model, ctx);
385
+ } catch (e) {
386
+ throw this.parseError(e);
387
+ }
388
+ return model;
389
+ }
390
+ async read(clazz, id, ...args) {
391
+ const {ctx: ctx, log: log, stub: stub} = this.logCtx(args, this.read);
392
+ log.info(`in ADAPTER read with args ${args}`);
393
+ const tableName = decoratorValidation.Model.tableName(clazz);
394
+ let model;
395
+ try {
396
+ const composedKey = stub.createCompositeKey(tableName, [ String(id) ]);
397
+ model = await this.readState(composedKey, ctx);
398
+ } catch (e) {
399
+ throw this.parseError(e);
400
+ }
401
+ return model;
402
+ }
403
+ async update(clazz, id, model, ...args) {
404
+ const {ctx: ctx, log: log, stub: stub} = this.logCtx(args, this.update);
405
+ const tableName = decoratorValidation.Model.tableName(clazz);
406
+ try {
407
+ log.verbose(`updating entry to ${tableName} table with pk ${id}`);
408
+ const composedKey = stub.createCompositeKey(tableName, [ String(id) ]);
409
+ model = await this.putState(composedKey, model, ctx);
410
+ } catch (e) {
411
+ throw this.parseError(e);
412
+ }
413
+ return model;
414
+ }
415
+ async delete(clazz, id, ...args) {
416
+ const {ctx: ctx, log: log, ctxArgs: ctxArgs, stub: stub} = this.logCtx(args, this.delete);
417
+ const tableName = decoratorValidation.Model.tableName(clazz);
418
+ let model;
419
+ try {
420
+ const composedKey = stub.createCompositeKey(tableName, [ String(id) ]);
421
+ model = await this.read(clazz, id, ...ctxArgs);
422
+ log.verbose(`deleting entry with pk ${id} from ${tableName} table`);
423
+ await this.deleteState(composedKey, ctx);
424
+ } catch (e) {
425
+ throw this.parseError(e);
426
+ }
427
+ return model;
428
+ }
429
+ async deleteState(id, ctx) {
430
+ const {stub: stub} = this.logCtx([ ctx ], this.deleteState);
431
+ await stub.deleteState(id);
432
+ }
433
+ forPrivate(collection) {
434
+ const toOverride = [ this.putState, this.readState, this.deleteState, this.queryResult, this.queryResultPaginated ].map(fn => fn.name);
435
+ return new Proxy(this, {
436
+ get(target, prop, receiver) {
437
+ if (!toOverride.includes(prop)) return Reflect.get(target, prop, receiver);
438
+ return new Proxy(target[prop], {
439
+ async apply(fn, thisArg, argsList) {
440
+ switch (prop) {
441
+ case "putState":
442
+ {
443
+ const [stub, id, model] = argsList;
444
+ await stub.putPrivateData(collection, id.toString(), model);
445
+ return model;
446
+ }
447
+
448
+ case "deleteState":
449
+ {
450
+ const [stub, id] = argsList;
451
+ return stub.deletePrivateData(collection, id);
452
+ }
453
+
454
+ case "readState":
455
+ {
456
+ const [stub, id] = argsList;
457
+ return stub.getPrivateData(collection, id);
458
+ }
459
+
460
+ case "queryResult":
461
+ {
462
+ const [stub, rawInput] = argsList;
463
+ return stub.getPrivateDataQueryResult(collection, rawInput);
464
+ }
465
+
466
+ case "queryResultPaginated":
467
+ {
468
+ const [stub, rawInput, limit, skip] = argsList;
469
+ const iterator = await stub.getPrivateDataQueryResult(collection, rawInput);
470
+ const results = [];
471
+ let count = 0;
472
+ let reachedBookmark = skip ? false : true;
473
+ let lastKey = null;
474
+ while (true) {
475
+ const res = await iterator.next();
476
+ if (res.value && res.value.value.toString()) {
477
+ const recordKey = res.value.key;
478
+ const recordValue = res.value.value.toString("utf8");
479
+ if (!reachedBookmark) {
480
+ if (recordKey === skip?.toString()) {
481
+ reachedBookmark = true;
482
+ }
483
+ continue;
484
+ }
485
+ results.push({
486
+ Key: recordKey,
487
+ Record: JSON.parse(recordValue)
488
+ });
489
+ lastKey = recordKey;
490
+ count++;
491
+ if (count >= limit) {
492
+ await iterator.close();
493
+ return {
494
+ iterator: results,
495
+ metadata: {
496
+ fetchedRecordsCount: results.length,
497
+ bookmark: lastKey
498
+ }
499
+ };
500
+ }
501
+ }
502
+ if (res.done) {
503
+ await iterator.close();
504
+ return {
505
+ iterator: results,
506
+ metadata: {
507
+ fetchedRecordsCount: results.length,
508
+ bookmark: ""
509
+ }
510
+ };
511
+ }
512
+ }
513
+ }
514
+
515
+ default:
516
+ throw new dbDecorators.InternalError(`Unsupported method override ${String(prop)}`);
517
+ }
518
+ }
519
+ });
520
+ }
521
+ });
522
+ }
523
+ async putState(id, model, ctx) {
524
+ let data;
525
+ const {stub: stub, log: log} = this.logCtx([ ctx ], this.putState);
526
+ try {
527
+ data = Buffer.from(FabricContractAdapter.serializer.serialize(model));
528
+ } catch (e) {
529
+ throw new dbDecorators.SerializationError(`Failed to serialize record with id ${id}: ${e}`);
530
+ }
531
+ const collection = ctx.get("segregated");
532
+ if (collection) await stub.putPrivateData(collection, id.toString(), data); else await stub.putState(id.toString(), data);
533
+ log.silly(`state stored${collection ? ` in ${collection} collection` : ""} under id ${id}`);
534
+ return model;
535
+ }
536
+ async readState(id, ctx) {
537
+ let result;
538
+ const {stub: stub, log: log} = this.logCtx([ ctx ], this.readState);
539
+ let res;
540
+ const collection = ctx.get("segregated");
541
+ if (collection) res = (await stub.getPrivateData(collection, id.toString())).toString(); else res = (await stub.getState(id.toString())).toString();
542
+ if (!res) throw new dbDecorators.NotFoundError(`Record with id ${id}${collection ? ` in ${collection} collection` : ""} not found`);
543
+ log.silly(`state retrieved from${collection ? ` ${collection} collection` : ""} under id ${id}`);
544
+ try {
545
+ result = FabricContractAdapter.serializer.deserialize(res.toString());
546
+ } catch (e) {
547
+ throw new dbDecorators.SerializationError(`Failed to parse record: ${e}`);
548
+ }
549
+ return result;
550
+ }
551
+ async queryResult(stub, rawInput, ...args) {
552
+ const {ctx: ctx} = this.logCtx(args, this.readState);
553
+ let res;
554
+ const collection = ctx.get("segregated");
555
+ if (collection) res = await stub.getPrivateDataQueryResult(collection, JSON.stringify(rawInput)); else res = await stub.getQueryResult(JSON.stringify(rawInput));
556
+ return res;
557
+ }
558
+ async queryResultPaginated(stub, rawInput, limit = 250, skip, ...args) {
559
+ const {ctx: ctx} = this.logCtx(args, this.readState);
560
+ let res;
561
+ const collection = ctx.get("segregated");
562
+ if (collection) {
563
+ rawInput.selector = {
564
+ ...rawInput.selector,
565
+ _id: skip ? {
566
+ $gt: skip.toString()
567
+ } : {
568
+ $gte: ""
569
+ }
570
+ };
571
+ const it = await stub.getPrivateDataQueryResult(collection, JSON.stringify(rawInput));
572
+ res = {
573
+ iterator: it,
574
+ metadata: {
575
+ fetchedRecordsCount: limit,
576
+ bookmark: ""
577
+ }
578
+ };
579
+ } else res = await stub.getQueryResultWithPagination(JSON.stringify(rawInput), limit, skip?.toString());
580
+ return res;
581
+ }
582
+ mergeModels(results) {
583
+ const extract = model => Object.entries(model).reduce((accum, [key, val]) => {
584
+ if (typeof val !== "undefined") accum[key] = val;
585
+ return accum;
586
+ }, {});
587
+ let finalModel = results.pop();
588
+ for (const res of results) {
589
+ finalModel = Object.assign({}, extract(finalModel), extract(res));
590
+ }
591
+ return finalModel;
592
+ }
593
+ decode(buffer) {
594
+ return FabricContractAdapter.textDecoder.decode(buffer);
595
+ }
596
+ async flags(operation, model, flags, ctx, ...args) {
597
+ const baseFlags = {
598
+ stub: ctx.stub,
599
+ segregated: false
600
+ };
601
+ if (ctx instanceof FabricContractContext) {
602
+ Object.assign(baseFlags, {
603
+ logger: ctx.logger,
604
+ identity: ctx.identity,
605
+ correlationId: ctx.stub.getTxID()
606
+ });
607
+ } else {
608
+ Object.assign(baseFlags, {
609
+ identity: ctx.clientIdentity,
610
+ logger: new ContractLogger(this, undefined, ctx),
611
+ correlationId: ctx.stub.getTxID()
612
+ });
613
+ }
614
+ flags = await super.flags(operation, model, baseFlags, ...args);
615
+ return flags;
616
+ }
617
+ index(models) {
618
+ return Promise.resolve(undefined);
619
+ }
620
+ async resultIterator(log, iterator, isHistory = false) {
621
+ const allResults = [];
622
+ let res = await iterator.next();
623
+ while (!res.done) {
624
+ if (res.value && res.value.value.toString()) {
625
+ let jsonRes = {};
626
+ log.debug(res.value.value.toString("utf8"));
627
+ if (isHistory) {
628
+ jsonRes.TxId = res.value.txId;
629
+ jsonRes.Timestamp = res.value.timestamp;
630
+ try {
631
+ jsonRes.Value = JSON.parse(res.value.value.toString("utf8"));
632
+ } catch (err) {
633
+ log.error(err);
634
+ jsonRes.Value = res.value.value.toString("utf8");
635
+ }
636
+ } else {
637
+ try {
638
+ jsonRes = JSON.parse(res.value.value.toString("utf8"));
639
+ } catch (err) {
640
+ log.error(err);
641
+ jsonRes = res.value.value.toString("utf8");
642
+ }
643
+ }
644
+ allResults.push(jsonRes);
645
+ }
646
+ res = await iterator.next();
647
+ }
648
+ log.debug(`Closing iterator after ${allResults.length} results`);
649
+ iterator.close();
650
+ return allResults;
651
+ }
652
+ async raw(rawInput, docsOnly = true, ...args) {
653
+ const {log: log, stub: stub} = this.logCtx(args, this.raw);
654
+ const {skip: skip, limit: limit} = rawInput;
655
+ let iterator;
656
+ if (limit || skip) {
657
+ delete rawInput["limit"];
658
+ delete rawInput["skip"];
659
+ log.debug(`Retrieving paginated iterator: limit: ${limit}/ skip: ${skip}`);
660
+ const response = await this.queryResultPaginated(stub, rawInput, limit || 250, skip?.toString());
661
+ iterator = response.iterator;
662
+ } else {
663
+ log.debug("Retrieving iterator");
664
+ iterator = await this.queryResult(stub, rawInput);
665
+ }
666
+ log.debug("Iterator acquired");
667
+ const results = await this.resultIterator(log, iterator);
668
+ log.debug(`returning ${Array.isArray(results) ? results.length : 1} results`);
669
+ return results;
670
+ }
671
+ Statement() {
672
+ return new FabricStatement(this);
673
+ }
674
+ async createAll(tableName, id, model, ...args) {
675
+ if (id.length !== model.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
676
+ const {log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.createAll);
677
+ const tableLabel = decoratorValidation.Model.tableName(tableName);
678
+ log.debug(`Creating ${id.length} entries ${tableLabel} table`);
679
+ return Promise.all(id.map((i, count) => this.create(tableName, i, model[count], ...ctxArgs)));
680
+ }
681
+ async updateAll(tableName, id, model, ...args) {
682
+ if (id.length !== model.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
683
+ const {log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.updateAll);
684
+ const tableLabel = decoratorValidation.Model.tableName(tableName);
685
+ log.debug(`Updating ${id.length} entries ${tableLabel} table`);
686
+ return Promise.all(id.map((i, count) => this.update(tableName, i, model[count], ...ctxArgs)));
687
+ }
688
+ prepare(model, ...args) {
689
+ const {log: log} = this.logCtx(args, this.prepare);
690
+ const tableName = decoratorValidation.Model.tableName(model.constructor);
691
+ const pk = decoratorValidation.Model.pk(model.constructor);
692
+ const split = decoratorValidation.Model.segregate(model);
693
+ const result = Object.entries(split.model).reduce((accum, [key, val]) => {
694
+ if (typeof val === "undefined") return accum;
695
+ const mappedProp = decoratorValidation.Model.columnName(model, key);
696
+ if (this.isReserved(mappedProp)) throw new dbDecorators.InternalError(`Property name ${mappedProp} is reserved`);
697
+ accum[mappedProp] = val;
698
+ return accum;
699
+ }, {});
700
+ log.silly(`Preparing record for ${tableName} table with pk ${model[pk]}`);
701
+ return {
702
+ record: result,
703
+ id: model[pk],
704
+ transient: split.transient
705
+ };
706
+ }
707
+ revert(obj, clazz, id, transient, ...args) {
708
+ const {log: log} = this.logCtx(args, this.revert);
709
+ const ob = {};
710
+ const pk = decoratorValidation.Model.pk(clazz);
711
+ ob[pk] = id;
712
+ const m = typeof clazz === "string" ? decoratorValidation.Model.build(ob, clazz) : new clazz(ob);
713
+ log.silly(`Rebuilding model ${m.constructor.name} id ${id}`);
714
+ const result = Object.keys(m).reduce((accum, key) => {
715
+ accum[key] = obj[decoratorValidation.Model.columnName(accum, key)];
716
+ return accum;
717
+ }, m);
718
+ if (transient) {
719
+ log.debug(`re-adding transient properties: ${Object.keys(transient).join(", ")}`);
720
+ Object.entries(transient).forEach(([key, val]) => {
721
+ if (key in result && result[key] !== undefined) throw new dbDecorators.InternalError(`Transient property ${key} already exists on model ${m.constructor.name}. should be impossible`);
722
+ result[key] = val;
723
+ });
724
+ }
725
+ return result;
726
+ }
727
+ createPrefix(tableName, id, model, ...args) {
728
+ const {ctxArgs: ctxArgs} = this.logCtx(args, this.createPrefix);
729
+ const record = {};
730
+ record[forCouchdb.CouchDBKeys.TABLE] = decoratorValidation.Model.tableName(tableName);
731
+ Object.assign(record, model);
732
+ return [ tableName, id, record, ...ctxArgs ];
733
+ }
734
+ updatePrefix(tableName, id, model, ...args) {
735
+ const {ctxArgs: ctxArgs} = this.logCtx(args, this.updatePrefix);
736
+ const record = {};
737
+ record[forCouchdb.CouchDBKeys.TABLE] = decoratorValidation.Model.tableName(tableName);
738
+ Object.assign(record, model);
739
+ return [ tableName, id, record, ...ctxArgs ];
740
+ }
741
+ createAllPrefix(tableName, ids, models, ...args) {
742
+ if (ids.length !== models.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
743
+ const ctx = args.pop();
744
+ const records = ids.map((id, count) => {
745
+ const record = {};
746
+ record[forCouchdb.CouchDBKeys.TABLE] = tableName;
747
+ Object.assign(record, models[count]);
748
+ return record;
749
+ });
750
+ return [ tableName, ids, records, ctx ];
751
+ }
752
+ updateAllPrefix(tableName, ids, models, ...args) {
753
+ if (ids.length !== models.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
754
+ const ctx = args.pop();
755
+ const records = ids.map((id, count) => {
756
+ const record = {};
757
+ record[forCouchdb.CouchDBKeys.TABLE] = tableName;
758
+ Object.assign(record, models[count]);
759
+ return record;
760
+ });
761
+ return [ tableName, ids, records, ctx ];
762
+ }
763
+ parseError(err, reason) {
764
+ return FabricContractAdapter.parseError(reason || err);
765
+ }
766
+ logCtx(args, method) {
767
+ return FabricContractAdapter.logCtx.call(this, args, method);
768
+ }
769
+ static logCtx(args, method) {
770
+ if (args.length < 1) throw new dbDecorators.InternalError("No context provided");
771
+ const ctx = args.pop();
772
+ if (!(ctx instanceof core.Context)) throw new dbDecorators.InternalError("No context provided");
773
+ if (args.filter(a => a instanceof core.Context).length > 1) throw new Error("here");
774
+ const log = this ? ctx.logger.for(this).for(method) : ctx.logger.clear().for(this).for(method);
775
+ return {
776
+ ctx: ctx,
777
+ log: method ? log.for(method) : log,
778
+ stub: ctx.stub,
779
+ identity: ctx.identity,
780
+ ctxArgs: [ ...args, ctx ]
781
+ };
782
+ }
783
+ static parseError(err) {
784
+ const msg = typeof err === "string" ? err : err.message;
785
+ if (msg.includes(dbDecorators.NotFoundError.name)) return new dbDecorators.NotFoundError(err);
786
+ if (msg.includes(dbDecorators.ConflictError.name)) return new dbDecorators.ConflictError(err);
787
+ if (msg.includes(dbDecorators.BadRequestError.name)) return new dbDecorators.BadRequestError(err);
788
+ if (msg.includes(core.QueryError.name)) return new core.QueryError(err);
789
+ if (msg.includes(core.PagingError.name)) return new core.PagingError(err);
790
+ if (msg.includes(core.UnsupportedError.name)) return new core.UnsupportedError(err);
791
+ if (msg.includes(core.MigrationError.name)) return new core.MigrationError(err);
792
+ if (msg.includes(core.ObserverError.name)) return new core.ObserverError(err);
793
+ if (msg.includes(core.AuthorizationError.name)) return new core.AuthorizationError(err);
794
+ if (msg.includes(core.ForbiddenError.name)) return new core.ForbiddenError(err);
795
+ if (msg.includes(core.ConnectionError.name)) return new core.ConnectionError(err);
796
+ if (msg.includes(dbDecorators.SerializationError.name)) return new dbDecorators.SerializationError(err);
797
+ return new dbDecorators.InternalError(err);
798
+ }
799
+ static decoration() {
800
+ super.decoration();
801
+ decoration.Decoration.flavouredAs(FabricFlavour).for(core.PersistenceKeys.CREATED_BY).define(dbDecorators.onCreate(createdByOnFabricCreateUpdate), decoration.propMetadata(core.PersistenceKeys.CREATED_BY, {})).apply();
802
+ decoration.Decoration.flavouredAs(FabricFlavour).for(core.PersistenceKeys.UPDATED_BY).define(dbDecorators.onCreateUpdate(createdByOnFabricCreateUpdate), decoration.propMetadata(core.PersistenceKeys.UPDATED_BY, {})).apply();
803
+ decoration.Decoration.flavouredAs(FabricFlavour).for(dbDecorators.DBKeys.ID).define({
804
+ decorator: function pkDec(options, groupsort) {
805
+ return function pkDec(obj, attr) {
806
+ return decoration.apply(decoratorValidation.required(), dbDecorators.readonly(), decoration.propMetadata(decoration.Metadata.key(dbDecorators.DBKeys.ID, attr), options), dbDecorators.onCreate(pkFabricOnCreate, options, groupsort))(obj, attr);
807
+ };
808
+ }
809
+ }).apply();
810
+ decoration.Decoration.flavouredAs(FabricFlavour).for(core.PersistenceKeys.COLUMN).extend(fabricContractApi.Property()).apply();
811
+ decoration.Decoration.flavouredAs(FabricFlavour).for(core.PersistenceKeys.TABLE).extend(function table(obj) {
812
+ return fabricContractApi.Object()(obj);
813
+ }).apply();
814
+ function oneToOneDec(clazz, cascade, populate$1, joinColumnOpts, fk) {
815
+ const meta = {
816
+ class: clazz,
817
+ cascade: cascade,
818
+ populate: populate$1
819
+ };
820
+ if (joinColumnOpts) meta.joinTable = joinColumnOpts;
821
+ if (fk) meta.name = fk;
822
+ return decoration.apply(decoration.prop(), core.relation(core.PersistenceKeys.ONE_TO_ONE, meta), decoratorValidation.type([ clazz, String, Number, BigInt ]), dbDecorators.onCreate(oneToOneOnCreate, meta), dbDecorators.onUpdate(oneToOneOnUpdate, meta), dbDecorators.onDelete(oneToOneOnDelete, meta), dbDecorators.afterAny(populate, meta), decoration.propMetadata(core.PersistenceKeys.ONE_TO_ONE, meta));
823
+ }
824
+ decoration.Decoration.flavouredAs(FabricFlavour).for(core.PersistenceKeys.ONE_TO_ONE).define({
825
+ decorator: oneToOneDec
826
+ }).apply();
827
+ function oneToManyDec(clazz, cascade, populate$1, joinTableOpts, fk) {
828
+ const metadata = {
829
+ class: clazz,
830
+ cascade: cascade,
831
+ populate: populate$1
832
+ };
833
+ if (joinTableOpts) metadata.joinTable = joinTableOpts;
834
+ if (fk) metadata.name = fk;
835
+ return decoration.apply(decoration.prop(), core.relation(core.PersistenceKeys.ONE_TO_MANY, metadata), decoratorValidation.list([ clazz, String, Number ]), dbDecorators.onCreate(oneToManyOnCreate, metadata), dbDecorators.onUpdate(core.oneToManyOnUpdate, metadata), dbDecorators.onDelete(oneToManyOnDelete, metadata), dbDecorators.afterAny(populate, metadata), decoration.propMetadata(core.PersistenceKeys.ONE_TO_MANY, metadata));
836
+ }
837
+ decoration.Decoration.for(core.PersistenceKeys.ONE_TO_MANY).define({
838
+ decorator: oneToManyDec
839
+ }).apply();
840
+ }
841
+ }
842
+ FabricContractAdapter.decoration();
843
+ core.Adapter.setCurrent(FabricFlavour);
844
+ class DeterministicSerializer extends decoratorValidation.JSONSerializer {
845
+ constructor() {
846
+ super();
847
+ }
848
+ deserialize(str) {
849
+ return super.deserialize(str);
850
+ }
851
+ serialize(model) {
852
+ const stringify = require("json-stringify-deterministic");
853
+ const sortKeysRecursive = require("sort-keys-recursive");
854
+ return stringify(sortKeysRecursive(this.preSerialize(model)));
855
+ }
856
+ }
857
+ class FabricCrudContract extends fabricContractApi.Contract {
858
+ static {
859
+ this.adapter = new FabricContractAdapter;
860
+ }
861
+ static {
862
+ this.serializer = new DeterministicSerializer;
863
+ }
864
+ constructor(name, clazz) {
865
+ super(name);
866
+ this.clazz = clazz;
867
+ this.initialized = false;
868
+ this.repo = core.Repository.forModel(clazz);
869
+ }
870
+ async listBy(ctx, key, order, ...args) {
871
+ const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.listBy);
872
+ return this.repo.listBy(key, order, ...ctxArgs);
873
+ }
874
+ async paginateBy(ctx, key, order, size, ...args) {
875
+ const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.paginateBy);
876
+ return this.repo.paginateBy(key, order, size, ...ctxArgs);
877
+ }
878
+ async findOneBy(ctx, key, value, ...args) {
879
+ const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.findOneBy);
880
+ return this.repo.findOneBy(key, value, ...ctxArgs);
881
+ }
882
+ async statement(ctx, method, ...args) {
883
+ const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.statement);
884
+ return this.repo.statement(method, ...ctxArgs);
885
+ }
886
+ async create(ctx, model, ...args) {
887
+ const {log: log, ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.create);
888
+ log.info(`CONTRACT CREATE, ${ctxArgs}`);
889
+ if (typeof model === "string") model = this.deserialize(model);
890
+ log.info(`Creating model: ${JSON.stringify(model)}`);
891
+ const transient = this.getTransientData(ctx);
892
+ log.info(`Merging transient data...`);
893
+ model = decoratorValidation.Model.merge(model, transient, this.clazz);
894
+ return this.repo.create(model, ...ctxArgs);
895
+ }
896
+ async read(ctx, key, ...args) {
897
+ const {log: log, ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.read);
898
+ log.info(`reading entry with pk ${key} `);
899
+ return this.repo.read(key, ...ctxArgs);
900
+ }
901
+ getTransientData(ctx) {
902
+ const transientMap = ctx.stub.getTransient();
903
+ let transient = {};
904
+ if (transientMap.has(this.repo.tableName)) {
905
+ transient = JSON.parse(transientMap.get(this.repo.tableName)?.toString("utf8"));
906
+ }
907
+ return transient;
908
+ }
909
+ async update(ctx, model, ...args) {
910
+ const {log: log, ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.update);
911
+ if (typeof model === "string") model = this.deserialize(model);
912
+ log.info(`Updating model: ${JSON.stringify(model)}`);
913
+ const transient = this.getTransientData(ctx);
914
+ log.info(`Merging transient data...`);
915
+ model = decoratorValidation.Model.merge(model, transient, this.clazz);
916
+ return this.repo.update(model, ...ctxArgs);
917
+ }
918
+ async delete(ctx, key, ...args) {
919
+ const {log: log, ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.delete);
920
+ log.info(`deleting entry with pk ${key} `);
921
+ return this.repo.delete(String(key), ...ctxArgs);
922
+ }
923
+ async deleteAll(ctx, keys, ...args) {
924
+ const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.readAll);
925
+ if (typeof keys === "string") keys = JSON.parse(keys);
926
+ return this.repo.deleteAll(keys, ...ctxArgs);
927
+ }
928
+ async readAll(ctx, keys, ...args) {
929
+ const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.readAll);
930
+ if (typeof keys === "string") keys = JSON.parse(keys);
931
+ return this.repo.readAll(keys, ...ctxArgs);
932
+ }
933
+ async updateAll(ctx, models, ...args) {
934
+ const {log: log, ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.updateAll);
935
+ if (typeof models === "string") models = JSON.parse(models).map(m => this.deserialize(m)).map(m => new this.clazz(m));
936
+ log.info(`updating ${models.length} entries to the table`);
937
+ return this.repo.updateAll(models, ...ctxArgs);
938
+ }
939
+ async query(context, condition, orderBy, order = core.OrderDirection.ASC, limit, skip, ...args) {
940
+ const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, context ], this.query);
941
+ return this.repo.query(condition, orderBy, order, limit, skip, ...ctxArgs);
942
+ }
943
+ async raw(ctx, rawInput, docsOnly, ...args) {
944
+ const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.raw);
945
+ if (typeof rawInput === "string") rawInput = JSON.parse(rawInput);
946
+ return FabricCrudContract.adapter.raw(rawInput, docsOnly, ...ctxArgs);
947
+ }
948
+ serialize(model) {
949
+ return FabricCrudContract.serializer.serialize(model);
950
+ }
951
+ deserialize(str) {
952
+ return FabricCrudContract.serializer.deserialize(str);
953
+ }
954
+ async init(ctx) {
955
+ const {log: log} = await this.logCtx([ ctx ], this.init);
956
+ log.info(`Running contract ${this.getName()} initialization...`);
957
+ this.initialized = true;
958
+ log.info(`Contract initialization completed.`);
959
+ }
960
+ async healthcheck(ctx) {
961
+ const {log: log} = await this.logCtx([ ctx ], this.healthcheck);
962
+ log.info(`Running Healthcheck: ${this.initialized}...`);
963
+ return {
964
+ healthcheck: this.initialized
965
+ };
966
+ }
967
+ async createAll(ctx, models, ...args) {
968
+ const {log: log} = await this.logCtx([ ...args, ctx ], this.createAll);
969
+ if (typeof models === "string") models = JSON.parse(models).map(m => this.deserialize(m)).map(m => new this.clazz(m));
970
+ log.info(`adding ${models.length} entries to the table`);
971
+ return this.repo.createAll(models, ctx, ...args);
972
+ }
973
+ async logCtx(args, method) {
974
+ return FabricCrudContract.logCtx.bind(this)(args, method);
975
+ }
976
+ static async logCtx(args, method) {
977
+ if (args.length < 1) throw new dbDecorators.InternalError("No context provided");
978
+ const ctx = args.pop();
979
+ if (ctx instanceof FabricContractContext) return {
980
+ ctx: ctx,
981
+ log: ctx.logger.clear().for(this).for(method),
982
+ ctxArgs: [ ...args, ctx ],
983
+ stub: ctx.stub,
984
+ identity: ctx.identity
985
+ };
986
+ if (!(ctx instanceof fabricContractApi.Context)) throw new dbDecorators.InternalError("No valid context provided");
987
+ function getOp() {
988
+ if (typeof method === "string") return method;
989
+ switch (method.name) {
990
+ case dbDecorators.OperationKeys.CREATE:
991
+ case dbDecorators.OperationKeys.READ:
992
+ case dbDecorators.OperationKeys.UPDATE:
993
+ case dbDecorators.OperationKeys.DELETE:
994
+ case dbDecorators.BulkCrudOperationKeys.CREATE_ALL:
995
+ case dbDecorators.BulkCrudOperationKeys.READ_ALL:
996
+ case dbDecorators.BulkCrudOperationKeys.UPDATE_ALL:
997
+ case dbDecorators.BulkCrudOperationKeys.DELETE_ALL:
998
+ return method.name;
999
+
1000
+ default:
1001
+ return method.name;
1002
+ }
1003
+ }
1004
+ const overrides = {
1005
+ correlationId: ctx.stub.getTxID()
1006
+ };
1007
+ const context = await FabricCrudContract.adapter.context(getOp(), overrides, this.clazz, ctx);
1008
+ const log = this ? context.logger.for(this).for(method) : context.logger.clear().for(this).for(method);
1009
+ return {
1010
+ ctx: context,
1011
+ log: log,
1012
+ stub: context.stub,
1013
+ identity: context.identity,
1014
+ ctxArgs: [ ...args, context ]
1015
+ };
1016
+ }
1017
+ }
1018
+ class SerializedCrudContract extends FabricCrudContract {
1019
+ constructor(name, clazz) {
1020
+ super(name, clazz);
1021
+ }
1022
+ async create(context, model) {
1023
+ const {log: log, ctx: ctx} = await this.logCtx([ context ], this.create);
1024
+ log.info(`Creating model: ${model}`);
1025
+ const m = this.deserialize(model);
1026
+ log.info(`Model deserialized: ${JSON.stringify(m)}`);
1027
+ return this.serialize(await super.create(ctx, m));
1028
+ }
1029
+ async read(context, key) {
1030
+ const {log: log, ctx: ctx} = await this.logCtx([ context ], this.read);
1031
+ log.info(`Reading id: ${key}`);
1032
+ return this.serialize(await super.read(ctx, key));
1033
+ }
1034
+ async update(context, model) {
1035
+ const {log: log, ctx: ctx} = await this.logCtx([ context ], this.update);
1036
+ log.info(`Updating model: ${model}`);
1037
+ return this.serialize(await super.update(ctx, model));
1038
+ }
1039
+ async delete(context, key) {
1040
+ const {log: log, ctx: ctx} = await this.logCtx([ context ], this.delete);
1041
+ log.info(`Deleting id: ${key}`);
1042
+ return this.serialize(await super.delete(ctx, key));
1043
+ }
1044
+ async deleteAll(context, keys) {
1045
+ const parsedKeys = JSON.parse(keys);
1046
+ const {log: log, ctx: ctx} = await this.logCtx([ context ], this.deleteAll);
1047
+ log.info(`deleting ${parsedKeys.length} entries from the table`);
1048
+ return JSON.stringify((await super.deleteAll(ctx, parsedKeys)).map(m => this.serialize(m)));
1049
+ }
1050
+ async readAll(context, keys) {
1051
+ const parsedKeys = JSON.parse(keys);
1052
+ const {log: log, ctx: ctx} = await this.logCtx([ context ], this.readAll);
1053
+ log.info(`reading ${parsedKeys.length} entries from the table`);
1054
+ return JSON.stringify((await super.readAll(ctx, parsedKeys)).map(m => this.serialize(m)));
1055
+ }
1056
+ async updateAll(context, models) {
1057
+ const {log: log, ctx: ctx} = await this.logCtx([ context ], this.updateAll);
1058
+ const list = JSON.parse(models);
1059
+ const modelList = list.map(m => this.deserialize(m)).map(m => new this.clazz(m));
1060
+ log.info(`Updating ${modelList.length} entries to the table`);
1061
+ return JSON.stringify((await super.updateAll(ctx, modelList)).map(m => this.serialize(m)));
1062
+ }
1063
+ async statement(context, method, ...args) {
1064
+ const {ctx: ctx, log: log} = await this.logCtx([ ...args, context ], this.statement);
1065
+ args = args.map(a => {
1066
+ try {
1067
+ return JSON.parse(a);
1068
+ } catch (e) {
1069
+ return a;
1070
+ }
1071
+ });
1072
+ log.info(`calling prepared statement ${method}`);
1073
+ log.debug(`with args ${args}`);
1074
+ return super.statement(ctx, method, ...args);
1075
+ }
1076
+ async listBy(context, key, order, ...args) {
1077
+ const {ctx: ctx} = await this.logCtx([ ...args, context ], this.listBy);
1078
+ return super.listBy(ctx, key, order);
1079
+ }
1080
+ async paginateBy(context, key, order, size, ...args) {
1081
+ const {ctx: ctx} = await this.logCtx([ ...args, context ], this.paginateBy);
1082
+ return super.paginateBy(ctx, key, order, size);
1083
+ }
1084
+ async findOneBy(context, key, value, ...args) {
1085
+ const {ctx: ctx} = await this.logCtx([ ...args, context ], this.paginateBy);
1086
+ return super.findOneBy(ctx, key, value, ...args);
1087
+ }
1088
+ async query(context, condition, orderBy, order, limit, skip, ...args) {
1089
+ const {ctx: ctx} = await this.logCtx([ context ], this.query);
1090
+ let cond;
1091
+ try {
1092
+ cond = core.Condition.from(JSON.parse(condition));
1093
+ } catch (e) {
1094
+ throw new dbDecorators.SerializationError(`Invalid condition: ${e}`);
1095
+ }
1096
+ return super.query(ctx, cond, orderBy, order, limit, skip, ...args);
1097
+ }
1098
+ async raw(context, rawInput, docsOnly, ...args) {
1099
+ const {ctx: ctx} = await this.logCtx([ context ], this.raw);
1100
+ const parsedInput = JSON.parse(rawInput);
1101
+ return super.raw(ctx, parsedInput, docsOnly, ...args);
1102
+ }
1103
+ async init(ctx) {
1104
+ await super.init(ctx);
1105
+ }
1106
+ async healthcheck(context) {
1107
+ const {log: log, ctx: ctx} = await this.logCtx([ context ], this.updateAll);
1108
+ log.debug(`Running Healthcheck: ${this.initialized}...`);
1109
+ return JSON.stringify(await super.healthcheck(ctx));
1110
+ }
1111
+ async createAll(context, models) {
1112
+ const {log: log} = await this.logCtx([ context ], this.createAll);
1113
+ const list = JSON.parse(models);
1114
+ const modelList = list.map(m => this.deserialize(m)).map(m => new this.clazz(m));
1115
+ log.info(`Adding ${modelList.length} entries to the table`);
1116
+ return JSON.stringify((await super.createAll(context, modelList)).map(m => this.serialize(m)));
1117
+ }
1118
+ }
1119
+ tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "create", null);
1120
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "read", null);
1121
+ tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "update", null);
1122
+ tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "delete", null);
1123
+ tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "deleteAll", null);
1124
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "readAll", null);
1125
+ tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "updateAll", null);
1126
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "statement", null);
1127
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String, String, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "listBy", null);
1128
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String, String, Number, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "paginateBy", null);
1129
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String, String, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "findOneBy", null);
1130
+ tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "init", null);
1131
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "healthcheck", null);
1132
+ tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "createAll", null);
1133
+ class OverflowError extends dbDecorators.InternalError {
1134
+ constructor(msg) {
1135
+ super(msg, OverflowError.name);
1136
+ }
1137
+ }
1138
+ class BalanceError extends dbDecorators.InternalError {
1139
+ constructor(msg) {
1140
+ super(msg, BalanceError.name);
1141
+ }
1142
+ }
1143
+ class AllowanceError extends dbDecorators.InternalError {
1144
+ constructor(msg) {
1145
+ super(msg, AllowanceError.name);
1146
+ }
1147
+ }
1148
+ class RegistrationError extends core.AuthorizationError {
1149
+ constructor(msg) {
1150
+ super(msg, RegistrationError.name);
1151
+ }
1152
+ }
1153
+ class MissingContextError extends dbDecorators.InternalError {
1154
+ constructor(msg) {
1155
+ super(msg, MissingContextError.name, 500);
1156
+ }
1157
+ }
1158
+ class UnauthorizedPrivateDataAccess extends dbDecorators.BaseError {
1159
+ constructor(msg = "MISSING_PRIVATE_DATA_ERROR_MESSAGE") {
1160
+ super(UnauthorizedPrivateDataAccess.name, msg, 403);
1161
+ }
1162
+ }
1163
+ class NotInitializedError extends dbDecorators.BaseError {
1164
+ constructor(msg) {
1165
+ super(NotInitializedError.name, msg, 409);
1166
+ }
1167
+ }
1168
+ class MissingPKCSS11Lib extends dbDecorators.InternalError {
1169
+ constructor(msg) {
1170
+ super(msg, MissingPKCSS11Lib.name, 500);
1171
+ }
1172
+ }
1173
+ class EndorsementError extends dbDecorators.InternalError {
1174
+ constructor(message) {
1175
+ super(message, EndorsementError.name, 500);
1176
+ }
1177
+ }
1178
+ function add(a, b) {
1179
+ const c = a + b;
1180
+ if (a !== c - b || b !== c - a) {
1181
+ throw new OverflowError(`Addition overflow: ${a} + ${b}`);
1182
+ }
1183
+ return c;
1184
+ }
1185
+ function sub(a, b) {
1186
+ const c = a - b;
1187
+ if (a !== c + b || b !== a - c) {
1188
+ throw new OverflowError(`Subtraction overflow: ${a} - ${b}`);
1189
+ }
1190
+ return c;
1191
+ }
1192
+ function safeParseInt(string) {
1193
+ const digitRegex = /^\d+$/;
1194
+ if (!digitRegex.test(string)) {
1195
+ throw new dbDecorators.ValidationError(decoratorValidation.stringFormat("Failed to parse: {0}", "string contains digits"));
1196
+ }
1197
+ const parsedint = parseInt(string);
1198
+ if (isNaN(parsedint)) {
1199
+ throw new dbDecorators.ValidationError(decoratorValidation.stringFormat("Failed to parse: {0}", "string is not a parsable integer"));
1200
+ }
1201
+ return parsedint;
1202
+ }
1203
+ let ERC20Token = class ERC20Token extends core.BaseModel {
1204
+ constructor(m) {
1205
+ super(m);
1206
+ }
1207
+ };
1208
+ tslib.__decorate([ core.pk({
1209
+ type: "String"
1210
+ }), tslib.__metadata("design:type", String) ], ERC20Token.prototype, "name", void 0);
1211
+ tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], ERC20Token.prototype, "owner", void 0);
1212
+ tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], ERC20Token.prototype, "symbol", void 0);
1213
+ tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", Number) ], ERC20Token.prototype, "decimals", void 0);
1214
+ ERC20Token = tslib.__decorate([ core.table("erc20_tokens"), decoratorValidation.model(), tslib.__metadata("design:paramtypes", [ Object ]) ], ERC20Token);
1215
+ let ERC20Wallet = class ERC20Wallet extends core.BaseModel {
1216
+ constructor(m) {
1217
+ super(m);
1218
+ }
1219
+ };
1220
+ tslib.__decorate([ core.pk({
1221
+ type: "String"
1222
+ }), tslib.__metadata("design:type", String) ], ERC20Wallet.prototype, "id", void 0);
1223
+ tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], ERC20Wallet.prototype, "token", void 0);
1224
+ tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", Number) ], ERC20Wallet.prototype, "balance", void 0);
1225
+ tslib.__decorate([ core.column(), tslib.__metadata("design:type", String) ], ERC20Wallet.prototype, "captive", void 0);
1226
+ ERC20Wallet = tslib.__decorate([ core.table("erc20_wallets"), decoratorValidation.model(), tslib.__metadata("design:paramtypes", [ Object ]) ], ERC20Wallet);
1227
+ let Allowance = class Allowance extends core.BaseModel {
1228
+ constructor(m) {
1229
+ super(m);
1230
+ }
1231
+ };
1232
+ tslib.__decorate([ core.pk({
1233
+ type: "String"
1234
+ }), core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], Allowance.prototype, "owner", void 0);
1235
+ tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], Allowance.prototype, "spender", void 0);
1236
+ tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", Number) ], Allowance.prototype, "value", void 0);
1237
+ Allowance = tslib.__decorate([ core.table("erc20_allowances"), decoratorValidation.model(), tslib.__metadata("design:paramtypes", [ Object ]) ], Allowance);
1238
+ function Owner() {
1239
+ return function(target, propertyKey, descriptor) {
1240
+ const originalMethod = descriptor.value;
1241
+ descriptor.value = async function(...args) {
1242
+ const ctx = args[0];
1243
+ const acountId = ctx.clientIdentity.getID();
1244
+ const select = await this["tokenRepository"].select();
1245
+ const tokens = await select.execute(ctx);
1246
+ if (tokens.length == 0) {
1247
+ throw new dbDecorators.NotFoundError("No tokens avaialble");
1248
+ }
1249
+ if (tokens.length > 1) {
1250
+ throw new dbDecorators.NotFoundError(`To many token available : ${tokens.length}`);
1251
+ }
1252
+ if (tokens[0].owner != acountId) {
1253
+ throw new core.AuthorizationError(`User not authorized to run ${propertyKey} on the token`);
1254
+ }
1255
+ return await originalMethod.apply(this, args);
1256
+ };
1257
+ return descriptor;
1258
+ };
1259
+ }
1260
+ async function ownedByOnCreate(context, data, key, model) {
1261
+ const {stub: stub} = context;
1262
+ const creator = await stub.getCreator();
1263
+ const owner = creator.mspid;
1264
+ const setOwnedByKeyValue = function(target, propertyKey, value) {
1265
+ Object.defineProperty(target, propertyKey, {
1266
+ enumerable: true,
1267
+ writable: false,
1268
+ configurable: true,
1269
+ value: value
1270
+ });
1271
+ };
1272
+ setOwnedByKeyValue(model, key, owner);
1273
+ }
1274
+ function OwnedBy() {
1275
+ const key = getFabricModelKey(FabricModelKeys.OWNEDBY);
1276
+ function ownedBy() {
1277
+ return function(obj, attribute) {
1278
+ return decoration.apply(decoratorValidation.required(), dbDecorators.readonly(), dbDecorators.onCreate(ownedByOnCreate), decoration.propMetadata(getFabricModelKey(FabricModelKeys.OWNEDBY), attribute))(obj, attribute);
1279
+ };
1280
+ }
1281
+ return decoration.Decoration.for(key).define({
1282
+ decorator: ownedBy,
1283
+ args: []
1284
+ }).apply();
1285
+ }
1286
+ function getFabricModelKey(key) {
1287
+ return decoration.Metadata.key(FabricModelKeys.FABRIC + key);
1288
+ }
1289
+ const ImplicitPrivateCollection = model => `__${model.constructor.name}PrivateCollection`;
1290
+ async function segregatedDataOnCreate(context, data, keys, model) {
1291
+ if (keys.length !== data.length) throw new dbDecorators.InternalError(`Segregated data keys and metadata length mismatch`);
1292
+ const collectionResolver = data[0].collections;
1293
+ const collection = typeof collectionResolver === "string" ? collectionResolver : collectionResolver(model);
1294
+ const rebuilt = keys.reduce((acc, k, i) => {
1295
+ const c = typeof data[i].collections === "string" ? data[i].collections : data[i].collections(model);
1296
+ if (c !== collection) throw new core.UnsupportedError(`Segregated data collection mismatch: ${c} vs ${collection}`);
1297
+ acc[k] = model[k];
1298
+ return acc;
1299
+ }, {});
1300
+ const toCreate = new this.class(rebuilt);
1301
+ const created = await this.override({
1302
+ segregated: collection
1303
+ }).create(toCreate, context);
1304
+ Object.assign(model, created);
1305
+ }
1306
+ async function segregatedDataOnRead(context, data, keys, model) {
1307
+ if (keys.length !== data.length) throw new dbDecorators.InternalError(`Segregated data keys and metadata length mismatch`);
1308
+ const collectionResolver = data[0].collections;
1309
+ const collection = typeof collectionResolver === "string" ? collectionResolver : collectionResolver(model);
1310
+ const rebuilt = keys.reduce((acc, k, i) => {
1311
+ const c = typeof data[i].collections === "string" ? data[i].collections : data[i].collections(model);
1312
+ if (c !== collection) throw new core.UnsupportedError(`Segregated data collection mismatch: ${c} vs ${collection}`);
1313
+ acc[k] = model[k];
1314
+ return acc;
1315
+ }, {});
1316
+ const toCreate = new this.class(rebuilt);
1317
+ const created = await this.override({
1318
+ segregated: collection
1319
+ }).create(toCreate, context);
1320
+ Object.assign(model, created);
1321
+ }
1322
+ async function segregatedDataOnUpdate(context, data, key, model, oldModel) {}
1323
+ async function segregatedDataOnDelete(context, data, key, model) {}
1324
+ function segregated(collection, type) {
1325
+ return function innerSegregated(target, propertyKey) {
1326
+ function segregatedDec(target, propertyKey) {
1327
+ if (!propertyKey) {
1328
+ const props = decoration.Metadata.properties(target) || [];
1329
+ for (const prop of props) segregated(collection, type)(target, prop);
1330
+ return target;
1331
+ }
1332
+ const key = decoration.Metadata.key(type, propertyKey);
1333
+ const constr = target.constructor;
1334
+ const meta = decoration.Metadata.get(constr, key) || {};
1335
+ const collections = new Set(meta.collections || []);
1336
+ collections.add(collection);
1337
+ meta.collections = [ ...collections ];
1338
+ decoration.Metadata.set(constr, key, meta);
1339
+ }
1340
+ const decs = [];
1341
+ if (!propertyKey) {
1342
+ decoration.Metadata.properties(target)?.forEach(p => segregated(collection, type)(target, p));
1343
+ return decoration.metadata(type, true)(target);
1344
+ } else {
1345
+ decs.push(dbDecorators.transient(), segregatedDec, dbDecorators.onCreate(segregatedDataOnCreate, {
1346
+ collections: collection
1347
+ }, {
1348
+ priority: 95,
1349
+ group: typeof collection === "string" ? collection : collection.toString()
1350
+ }), dbDecorators.onRead(segregatedDataOnRead, {
1351
+ collections: collection
1352
+ }, {
1353
+ priority: 95,
1354
+ group: typeof collection === "string" ? collection : collection.toString()
1355
+ }), dbDecorators.onUpdate(segregatedDataOnUpdate, {
1356
+ collections: collection
1357
+ }, {
1358
+ priority: 95,
1359
+ group: typeof collection === "string" ? collection : collection.toString()
1360
+ }), dbDecorators.onDelete(segregatedDataOnDelete, {
1361
+ collections: collection
1362
+ }, {
1363
+ priority: 95,
1364
+ group: typeof collection === "string" ? collection : collection.toString()
1365
+ }));
1366
+ }
1367
+ return decoration.apply(...decs)(target, propertyKey);
1368
+ };
1369
+ }
1370
+ function privateData(collection = ImplicitPrivateCollection) {
1371
+ function privateData(collection) {
1372
+ return segregated(collection, FabricModelKeys.PRIVATE);
1373
+ }
1374
+ return decoration.Decoration.for(FabricModelKeys.PRIVATE).define({
1375
+ decorator: privateData,
1376
+ args: [ collection ]
1377
+ }).apply();
1378
+ }
1379
+ function sharedData(collection) {
1380
+ function sharedData(collection) {
1381
+ return segregated(collection, FabricModelKeys.SHARED);
1382
+ }
1383
+ return decoration.Decoration.for(FabricModelKeys.SHARED).define({
1384
+ decorator: sharedData,
1385
+ args: [ collection ]
1386
+ }).apply();
1387
+ }
1388
+ var ERC20Events;
1389
+ (function(ERC20Events) {
1390
+ ERC20Events["TRANSFER"] = "Transfer";
1391
+ ERC20Events["APPROVAL"] = "Approval";
1392
+ })(ERC20Events || (ERC20Events = {}));
1393
+ class FabricERC20Contract extends FabricCrudContract {
1394
+ constructor(name) {
1395
+ super(name, ERC20Wallet);
1396
+ FabricERC20Contract.adapter = FabricERC20Contract.adapter || new FabricContractAdapter;
1397
+ this.walletRepository = FabricContractRepository.forModel(ERC20Wallet, FabricERC20Contract.adapter.alias);
1398
+ this.tokenRepository = FabricContractRepository.forModel(ERC20Token, FabricERC20Contract.adapter.alias);
1399
+ this.allowanceRepository = FabricContractRepository.forModel(Allowance, FabricERC20Contract.adapter.alias);
1400
+ }
1401
+ async TokenName(context) {
1402
+ const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
1403
+ await this.CheckInitialized(ctx);
1404
+ const select = this.tokenRepository.select();
1405
+ const token = (await select.execute(ctx))[0];
1406
+ return token.name;
1407
+ }
1408
+ async Symbol(context) {
1409
+ const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
1410
+ await this.CheckInitialized(ctx);
1411
+ const select = this.tokenRepository.select();
1412
+ const token = (await select.execute(ctx))[0];
1413
+ return token.symbol;
1414
+ }
1415
+ async Decimals(context) {
1416
+ const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
1417
+ await this.CheckInitialized(ctx);
1418
+ const select = this.tokenRepository.select();
1419
+ const token = (await select.execute(ctx))[0];
1420
+ return token.decimals;
1421
+ }
1422
+ async TotalSupply(context) {
1423
+ const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
1424
+ await this.CheckInitialized(ctx);
1425
+ const select = this.walletRepository.select();
1426
+ const wallets = await select.execute(ctx);
1427
+ if (wallets.length == 0) {
1428
+ throw new dbDecorators.NotFoundError(`The token ${this.getName()} does not exist`);
1429
+ }
1430
+ let total = 0;
1431
+ wallets.forEach(wallet => {
1432
+ total += wallet.balance;
1433
+ });
1434
+ return total;
1435
+ }
1436
+ async BalanceOf(context, owner) {
1437
+ const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
1438
+ await this.CheckInitialized(ctx);
1439
+ const wallet = await this.walletRepository.read(owner, ctx);
1440
+ return wallet.balance;
1441
+ }
1442
+ async Transfer(context, to, value) {
1443
+ const {ctx: ctx} = await this.logCtx([ context ], this.Transfer);
1444
+ await this.CheckInitialized(ctx);
1445
+ const from = ctx.identity.getID();
1446
+ const transferResp = await this._transfer(from, to, value, ctx);
1447
+ if (!transferResp) {
1448
+ throw new dbDecorators.InternalError("Failed to transfer");
1449
+ }
1450
+ return true;
1451
+ }
1452
+ async TransferFrom(context, from, to, value) {
1453
+ const {ctx: ctx} = await this.logCtx([ context ], this.BurnFrom);
1454
+ await this.CheckInitialized(ctx);
1455
+ const spender = ctx.identity.getID();
1456
+ const allowance = await this._getAllowance(from, spender, ctx);
1457
+ if (!allowance || allowance.value < 0) {
1458
+ throw new AllowanceError(`spender ${spender} has no allowance from ${from}`);
1459
+ }
1460
+ const currentAllowance = allowance.value;
1461
+ if (currentAllowance < value) {
1462
+ throw new BalanceError("The spender does not have enough allowance to spend.");
1463
+ }
1464
+ const updatedAllowance = sub(currentAllowance, value);
1465
+ const newAllowance = Object.assign({}, allowance, {
1466
+ value: updatedAllowance
1467
+ });
1468
+ await this.allowanceRepository.update(newAllowance, ctx);
1469
+ const transferResp = await this._transfer(from, to, value, ctx);
1470
+ if (!transferResp) {
1471
+ throw new dbDecorators.InternalError("Failed to transfer");
1472
+ }
1473
+ return true;
1474
+ }
1475
+ async _transfer(from, to, value, ctx) {
1476
+ const log = ctx.logger;
1477
+ if (from === to) {
1478
+ throw new core.AuthorizationError("cannot transfer to and from same client account");
1479
+ }
1480
+ if (value < 0) {
1481
+ throw new BalanceError("transfer amount cannot be negative");
1482
+ }
1483
+ const fromWallet = await this.walletRepository.read(from, ctx);
1484
+ const fromBalance = fromWallet.balance;
1485
+ if (fromBalance < value) {
1486
+ throw new BalanceError(`client account ${from} has insufficient funds.`);
1487
+ }
1488
+ let toWallet;
1489
+ let newToWallet = false;
1490
+ try {
1491
+ toWallet = await this.walletRepository.read(to, ctx);
1492
+ } catch (e) {
1493
+ if (e instanceof dbDecorators.BaseError) {
1494
+ if (e.code === 404) {
1495
+ toWallet = new ERC20Wallet({
1496
+ id: to,
1497
+ balance: 0,
1498
+ token: await this.TokenName(ctx)
1499
+ });
1500
+ newToWallet = true;
1501
+ } else {
1502
+ throw new dbDecorators.InternalError(e.message);
1503
+ }
1504
+ } else {
1505
+ throw new dbDecorators.InternalError(e);
1506
+ }
1507
+ }
1508
+ const toBalance = toWallet.balance;
1509
+ const fromUpdatedBalance = sub(fromBalance, value);
1510
+ const toUpdatedBalance = add(toBalance, value);
1511
+ const updatedFromWallet = Object.assign({}, fromWallet, {
1512
+ balance: fromUpdatedBalance
1513
+ });
1514
+ await this.walletRepository.update(updatedFromWallet, ctx);
1515
+ const updatedToWallet = Object.assign({}, toWallet, {
1516
+ balance: toUpdatedBalance
1517
+ });
1518
+ if (newToWallet) {
1519
+ await this.walletRepository.create(updatedToWallet, ctx);
1520
+ } else {
1521
+ await this.walletRepository.update(updatedToWallet, ctx);
1522
+ }
1523
+ const transferEvent = {
1524
+ from: from,
1525
+ to: to,
1526
+ value: value
1527
+ };
1528
+ this.repo.refresh(ERC20Token, ERC20Events.TRANSFER, "", transferEvent, ctx).catch(e => log.error(`Failed to notify transfer: ${e}`));
1529
+ return true;
1530
+ }
1531
+ async Approve(context, spender, value) {
1532
+ const {ctx: ctx, ctxArgs: ctxArgs} = await this.logCtx([ context ], this.Approve);
1533
+ await this.CheckInitialized(ctx);
1534
+ const owner = ctx.identity.getID();
1535
+ let allowance = await this._getAllowance(owner, spender, ctx);
1536
+ const ownerWallet = await this.walletRepository.read(owner, ...ctxArgs);
1537
+ if (ownerWallet.balance < value) {
1538
+ throw new BalanceError(`client account ${owner} has insufficient funds.`);
1539
+ }
1540
+ if (allowance) {
1541
+ allowance.value = value;
1542
+ await this.allowanceRepository.update(allowance, ...ctxArgs);
1543
+ } else {
1544
+ allowance = new Allowance({
1545
+ owner: owner,
1546
+ spender: spender,
1547
+ value: value
1548
+ });
1549
+ await this.allowanceRepository.create(allowance, ...ctxArgs);
1550
+ }
1551
+ const approvalEvent = {
1552
+ owner: owner,
1553
+ spender: spender,
1554
+ value: value
1555
+ };
1556
+ this.repo.refresh(ERC20Token, ERC20Events.APPROVAL, "", approvalEvent, ctx);
1557
+ return true;
1558
+ }
1559
+ async Allowance(context, owner, spender) {
1560
+ const {ctx: ctx} = await this.logCtx([ context ], this.Allowance);
1561
+ await this.CheckInitialized(ctx);
1562
+ const allowance = await this._getAllowance(owner, spender, ctx);
1563
+ if (!allowance) {
1564
+ throw new AllowanceError(`spender ${spender} has no allowance from ${owner}`);
1565
+ }
1566
+ return allowance.value;
1567
+ }
1568
+ async _getAllowance(owner, spender, ctx) {
1569
+ const allowanceCondition = core.Condition.and(core.Condition.attribute("owner").eq(owner), core.Condition.attribute("spender").eq(spender));
1570
+ const allowance = await this.allowanceRepository.select().where(allowanceCondition).execute(ctx);
1571
+ return allowance?.[0];
1572
+ }
1573
+ async Initialize(context, token) {
1574
+ const {ctx: ctx} = await this.logCtx([ context ], this.Initialize);
1575
+ const tokens = await this.tokenRepository.select().execute(ctx);
1576
+ if (tokens.length > 0) {
1577
+ throw new core.AuthorizationError("contract options are already set, client is not authorized to change them");
1578
+ }
1579
+ token.owner = ctx.identity.getID();
1580
+ await this.tokenRepository.create(token, ctx);
1581
+ return true;
1582
+ }
1583
+ async CheckInitialized(context) {
1584
+ const {ctx: ctx} = await this.logCtx([ context ], this.CheckInitialized);
1585
+ const tokens = await this.tokenRepository.select().execute(ctx);
1586
+ if (tokens.length == 0) {
1587
+ throw new NotInitializedError("contract options need to be set before calling any function, call Initialize() to initialize contract");
1588
+ }
1589
+ }
1590
+ async Mint(context, amount) {
1591
+ const {ctx: ctx} = await this.logCtx([ context ], this.Mint);
1592
+ await this.CheckInitialized(ctx);
1593
+ const minter = ctx.identity.getID();
1594
+ if (amount <= 0) {
1595
+ throw new dbDecorators.ValidationError("mint amount must be a positive integer");
1596
+ }
1597
+ let minterWallet;
1598
+ try {
1599
+ minterWallet = await this.walletRepository.read(minter, ctx);
1600
+ const currentBalance = minterWallet.balance;
1601
+ const updatedBalance = add(currentBalance, amount);
1602
+ const updatedminter = Object.assign({}, minterWallet, {
1603
+ balance: updatedBalance
1604
+ });
1605
+ await this.walletRepository.update(updatedminter, ctx);
1606
+ } catch (e) {
1607
+ if (e instanceof dbDecorators.BaseError) {
1608
+ if (e.code === 404) {
1609
+ const newWallet = new ERC20Wallet({
1610
+ id: minter,
1611
+ balance: amount,
1612
+ token: await this.TokenName(context)
1613
+ });
1614
+ await this.walletRepository.create(newWallet, ctx);
1615
+ } else {
1616
+ throw new dbDecorators.InternalError(e.message);
1617
+ }
1618
+ } else {
1619
+ throw new dbDecorators.InternalError(e);
1620
+ }
1621
+ }
1622
+ const transferEvent = {
1623
+ from: "0x0",
1624
+ to: minter,
1625
+ value: amount
1626
+ };
1627
+ const eventHandler = this.repo.ObserverHandler();
1628
+ eventHandler.updateObservers(ERC20Token, ERC20Events.TRANSFER, "", transferEvent, ctx);
1629
+ }
1630
+ async Burn(context, amount) {
1631
+ const {log: log, ctx: ctx} = await this.logCtx([ context ], this.Burn);
1632
+ await this.CheckInitialized(ctx);
1633
+ const minter = ctx.identity.getID();
1634
+ const minterWallet = await this.walletRepository.read(minter, ctx);
1635
+ const currentBalance = minterWallet.balance;
1636
+ if (currentBalance < amount) {
1637
+ throw new BalanceError(`Minter has insufficient funds.`);
1638
+ }
1639
+ const updatedBalance = sub(currentBalance, amount);
1640
+ const updatedminter = Object.assign({}, minterWallet, {
1641
+ balance: updatedBalance
1642
+ });
1643
+ await this.walletRepository.update(updatedminter, ctx);
1644
+ log.info(`${amount} tokens were burned`);
1645
+ const transferEvent = {
1646
+ from: minter,
1647
+ to: "0x0",
1648
+ value: amount
1649
+ };
1650
+ const eventHandler = this.repo.ObserverHandler();
1651
+ eventHandler.updateObservers(ERC20Token, ERC20Events.TRANSFER, "", transferEvent, ctx);
1652
+ }
1653
+ async BurnFrom(context, account, amount) {
1654
+ const {log: log, ctx: ctx} = await this.logCtx([ context ], this.BurnFrom);
1655
+ await this.CheckInitialized(ctx);
1656
+ const accountWallet = await this.walletRepository.read(account, ctx);
1657
+ const currentBalance = accountWallet.balance;
1658
+ if (currentBalance < amount) {
1659
+ throw new BalanceError(`${account} has insufficient funds.`);
1660
+ }
1661
+ const updatedBalance = sub(currentBalance, amount);
1662
+ const updatedaccount = Object.assign({}, accountWallet, {
1663
+ balance: updatedBalance
1664
+ });
1665
+ await this.walletRepository.update(updatedaccount, ctx);
1666
+ log.info(`${amount} tokens were burned from ${account}`);
1667
+ const transferEvent = {
1668
+ from: account,
1669
+ to: "0x0",
1670
+ value: amount
1671
+ };
1672
+ const eventHandler = this.repo.ObserverHandler();
1673
+ eventHandler.updateObservers(ERC20Token, ERC20Events.TRANSFER, "", transferEvent, ctx);
1674
+ }
1675
+ async ClientAccountBalance(context) {
1676
+ const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
1677
+ await this.CheckInitialized(ctx);
1678
+ const clientAccountID = ctx.identity.getID();
1679
+ const clientWallet = await this.walletRepository.read(clientAccountID, ctx);
1680
+ if (!clientWallet) {
1681
+ throw new BalanceError(`The account ${clientAccountID} does not exist`);
1682
+ }
1683
+ return clientWallet.balance;
1684
+ }
1685
+ async ClientAccountID(context) {
1686
+ const {ctx: ctx} = await this.logCtx([ context ], this.ClientAccountID);
1687
+ await this.CheckInitialized(ctx);
1688
+ const clientAccountID = ctx.identity.getID();
1689
+ return clientAccountID;
1690
+ }
1691
+ }
1692
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "TokenName", null);
1693
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "Symbol", null);
1694
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "Decimals", null);
1695
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "TotalSupply", null);
1696
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "BalanceOf", null);
1697
+ tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String, Number ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "Transfer", null);
1698
+ tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String, String, Number ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "TransferFrom", null);
1699
+ tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String, Number ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "Approve", null);
1700
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String, String ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "Allowance", null);
1701
+ tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, ERC20Token ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "Initialize", null);
1702
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "CheckInitialized", null);
1703
+ tslib.__decorate([ Owner(), fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, Number ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "Mint", null);
1704
+ tslib.__decorate([ Owner(), fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, Number ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "Burn", null);
1705
+ tslib.__decorate([ Owner(), fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String, Number ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "BurnFrom", null);
1706
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "ClientAccountBalance", null);
1707
+ tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context ]), tslib.__metadata("design:returntype", Promise) ], FabricERC20Contract.prototype, "ClientAccountID", null);
1708
+ const contracts = [ FabricERC20Contract ];
1709
+ const VERSION = "0.1.23";
1710
+ const PACKAGE_NAME = "@decaf-ts/for-fabric";
1711
+ decoration.Metadata.registerLibrary(PACKAGE_NAME, VERSION);
1712
+ exports.ContractLogger = ContractLogger;
1713
+ exports.FabricContractAdapter = FabricContractAdapter;
1714
+ exports.FabricContractContext = FabricContractContext;
1715
+ exports.FabricContractRepository = FabricContractRepository;
1716
+ exports.FabricContractRepositoryObservableHandler = FabricContractRepositoryObservableHandler;
1717
+ exports.FabricCrudContract = FabricCrudContract;
1718
+ exports.FabricStatement = FabricStatement;
1719
+ exports.PACKAGE_NAME = PACKAGE_NAME;
1720
+ exports.SerializedCrudContract = SerializedCrudContract;
1721
+ exports.VERSION = VERSION;
1722
+ exports.contracts = contracts;
1723
+ exports.createdByOnFabricCreateUpdate = createdByOnFabricCreateUpdate;
1724
+ exports.pkFabricOnCreate = pkFabricOnCreate;
1725
+ });
1726
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yLWZhYnJpYy5janMiLCJzb3VyY2VzIjpbIi4uL3NyYy9jb250cmFjdHMvQ29udHJhY3RDb250ZXh0LnRzIiwiLi4vc3JjL3NoYXJlZC9ldmVudHMudHMiLCIuLi9zcmMvY29udHJhY3RzL0ZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyLnRzIiwiLi4vc3JjL2NvbnRyYWN0cy9GYWJyaWNDb250cmFjdFJlcG9zaXRvcnkudHMiLCIuLi9zcmMvY29udHJhY3RzL0ZhYnJpY0NvbnRyYWN0U3RhdGVtZW50LnRzIiwiLi4vc3JjL3NoYXJlZC9jb25zdGFudHMudHMiLCIuLi9zcmMvc2hhcmVkL1NpbXBsZURldGVybWluaXN0aWNTZXJpYWxpemVyLnRzIiwiLi4vc3JjL2NvbnRyYWN0cy9GYWJyaWNDb25zdHJ1Y3Rpb24udHMiLCIuLi9zcmMvY29udHJhY3RzL2xvZ2dpbmcudHMiLCIuLi9zcmMvY29udHJhY3RzL0NvbnRyYWN0QWRhcHRlci50cyIsIi4uL3NyYy9zaGFyZWQvRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXIudHMiLCIuLi9zcmMvY29udHJhY3RzL2NydWQvY3J1ZC1jb250cmFjdC50cyIsIi4uL3NyYy9jb250cmFjdHMvY3J1ZC9zZXJpYWxpemVkLWNydWQtY29udHJhY3QudHMiLCIuLi9zcmMvc2hhcmVkL2Vycm9ycy50cyIsIi4uL3NyYy9zaGFyZWQvbWF0aC50cyIsIi4uL3NyYy9jb250cmFjdHMvZXJjMjAvbW9kZWxzLnRzIiwiLi4vc3JjL3NoYXJlZC9kZWNvcmF0b3JzLnRzIiwiLi4vc3JjL3NoYXJlZC9lcmMyMC9lcmMyMC1jb25zdGFudHMudHMiLCIuLi9zcmMvY29udHJhY3RzL2VyYzIwL2VyYzIwY29udHJhY3QudHMiLCIuLi9zcmMvY29udHJhY3RzL2VyYzIwL2luZGV4LnRzIiwiLi4vc3JjL3ZlcnNpb24udHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29udGV4dCB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RGbGFncyB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBDaGFpbmNvZGVTdHViLCBDbGllbnRJZGVudGl0eSB9IGZyb20gXCJmYWJyaWMtc2hpbS1hcGlcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ29udGV4dCBjbGFzcyBmb3IgRmFicmljIGNoYWluY29kZSBvcGVyYXRpb25zXG4gKiBAc3VtbWFyeSBQcm92aWRlcyBhY2Nlc3MgdG8gRmFicmljLXNwZWNpZmljIGNvbnRleHQgZWxlbWVudHMgbGlrZSBzdHViLCBpZGVudGl0eSwgYW5kIGxvZ2dlciB0byBiZSB1c2VkIGJ5IHJlcG9zaXRvcmllcyBhbmQgYWRhcHRlcnMgZHVyaW5nIGNvbnRyYWN0IGV4ZWN1dGlvbi5cbiAqIEB0ZW1wbGF0ZSBGIC0gRmxhZ3Mgc3BlY2lmaWMgdG8gRmFicmljIGNvbnRyYWN0IG9wZXJhdGlvbnNcbiAqIEBwYXJhbSB7b2JqZWN0fSBbYXJnc10gLSBPcHRpb25hbCBpbml0aWFsaXphdGlvbiBhcmd1bWVudHMgcGFzc2VkIHRvIHRoZSBiYXNlIENvbnRleHRcbiAqIEByZXR1cm4ge3ZvaWR9XG4gKiBAY2xhc3MgRmFicmljQ29udHJhY3RDb250ZXh0XG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gSW4gYSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRyYWN0IG1ldGhvZFxuICogY29uc3QgY29udGV4dCA9IG5ldyBGYWJyaWNDb250cmFjdENvbnRleHQoKTtcbiAqIC8vIE9wdGlvbmFsbHkgc2V0IHZhbHVlcyB2aWEgdGhlIGJhc2UgQ29udGV4dCBBUElcbiAqIGNvbnRleHQuc2V0KCdzdHViJywgY3R4LnN0dWIpO1xuICogY29udGV4dC5zZXQoJ2NsaWVudElkZW50aXR5JywgY3R4LmNsaWVudElkZW50aXR5KTtcbiAqIGNvbnRleHQuc2V0KCdsb2dnZXInLCBjb250cmFjdExvZ2dlcik7XG4gKlxuICogLy8gQWNjZXNzIGNvbnRleHQgcHJvcGVydGllc1xuICogY29uc3QgdGltZXN0YW1wID0gY29udGV4dC50aW1lc3RhbXA7XG4gKiBjb25zdCBjcmVhdG9yID0gY29udGV4dC5pZGVudGl0eS5nZXRJRCgpO1xuICogYGBgXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENvbnRyYWN0XG4gKiAgIHBhcnRpY2lwYW50IENvbnRleHRcbiAqICAgcGFydGljaXBhbnQgTGVkZ2VyXG4gKiAgIENvbnRyYWN0LT4+Q29udGV4dDogbmV3IEZhYnJpY0NvbnRyYWN0Q29udGV4dCgpXG4gKiAgIENvbnRyYWN0LT4+Q29udGV4dDogc2V0KCdzdHViJ3wnY2xpZW50SWRlbnRpdHknfCdsb2dnZXInLCAuLi4pXG4gKiAgIENvbnRleHQtLT4+Q29udHJhY3Q6IHRpbWVzdGFtcCwgaWRlbnRpdHksIGxvZ2dlclxuICogICBDb250cmFjdC0+PkxlZGdlcjogSW50ZXJhY3QgdmlhIHN0dWJcbiAqL1xuZXhwb3J0IGNsYXNzIEZhYnJpY0NvbnRyYWN0Q29udGV4dCBleHRlbmRzIENvbnRleHQ8RmFicmljQ29udHJhY3RGbGFncz4ge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgRmFicmljQ29udHJhY3RDb250ZXh0IGluc3RhbmNlXG4gICAqIEBzdW1tYXJ5IEluaXRpYWxpemVzIHRoZSBjb250ZXh0IHdpdGggRmFicmljLXNwZWNpZmljIGZsYWdzXG4gICAqL1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIHRoZSBjaGFpbmNvZGUgc3R1YlxuICAgKiBAc3VtbWFyeSBSZXR1cm5zIHRoZSBDaGFpbmNvZGVTdHViIGluc3RhbmNlIGZvciBpbnRlcmFjdGluZyB3aXRoIHRoZSBsZWRnZXJcbiAgICogQHJldHVybiB7Q2hhaW5jb2RlU3R1Yn0gVGhlIGNoYWluY29kZSBzdHViXG4gICAqL1xuICBnZXQgc3R1YigpOiBDaGFpbmNvZGVTdHViIHtcbiAgICByZXR1cm4gdGhpcy5nZXQoXCJzdHViXCIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIHRoZSB0cmFuc2FjdGlvbiB0aW1lc3RhbXBcbiAgICogQHN1bW1hcnkgT3ZlcnJpZGVzIHRoZSBiYXNlIHRpbWVzdGFtcCBnZXR0ZXIgdG8gdXNlIHRoZSBzdHViJ3MgdGltZXN0YW1wXG4gICAqIEByZXR1cm4ge0RhdGV9IFRoZSB0cmFuc2FjdGlvbiB0aW1lc3RhbXBcbiAgICovXG4gIG92ZXJyaWRlIGdldCB0aW1lc3RhbXAoKTogRGF0ZSB7XG4gICAgcmV0dXJuIHRoaXMuc3R1Yi5nZXREYXRlVGltZXN0YW1wKCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEdldHMgdGhlIGNsaWVudCBpZGVudGl0eVxuICAgKiBAc3VtbWFyeSBSZXR1cm5zIHRoZSBDbGllbnRJZGVudGl0eSBpbnN0YW5jZSBmb3IgdGhlIHRyYW5zYWN0aW9uIHN1Ym1pdHRlclxuICAgKiBAcmV0dXJuIHtDbGllbnRJZGVudGl0eX0gVGhlIGNsaWVudCBpZGVudGl0eVxuICAgKi9cbiAgZ2V0IGlkZW50aXR5KCk6IENsaWVudElkZW50aXR5IHtcbiAgICByZXR1cm4gdGhpcy5nZXQoXCJpZGVudGl0eVwiKTtcbiAgfVxuXG4gIG92ZXJyaWRlIHRvU3RyaW5nKCkge1xuICAgIHJldHVybiBgZmFicmljIGN0eCR7dGhpcy5zdHViID8gXCIgd2l0aCBzdHViXCIgOiBcIndpdGhvdXQgc3R1YlwifWA7XG4gIH1cbn1cbiIsImltcG9ydCB7IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cywgT3BlcmF0aW9uS2V5cyB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBHZW5lcmF0ZXMgYSBGYWJyaWMgZXZlbnQgbmFtZSBmcm9tIGNvbXBvbmVudHNcbiAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBzdGFuZGFyZGl6ZWQgZXZlbnQgbmFtZSBieSBqb2luaW5nIHRhYmxlLCBldmVudCwgYW5kIG9wdGlvbmFsIG93bmVyIHdpdGggdW5kZXJzY29yZXNcbiAqIEBwYXJhbSB7c3RyaW5nfSB0YWJsZSAtIFRoZSB0YWJsZS9jb2xsZWN0aW9uIG5hbWVcbiAqIEBwYXJhbSB7T3BlcmF0aW9uS2V5cyB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyB8IHN0cmluZ30gZXZlbnQgLSBUaGUgZXZlbnQgdHlwZVxuICogQHBhcmFtIHtzdHJpbmd9IFtvd25lcl0gLSBPcHRpb25hbCBvd25lciBpZGVudGlmaWVyXG4gKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBnZW5lcmF0ZWQgZXZlbnQgbmFtZSBpbiBmb3JtYXQgXCJ0YWJsZV9ldmVudFwiIG9yIFwidGFibGVfZXZlbnRfb3duZXJcIlxuICogQGZ1bmN0aW9uIGdlbmVyYXRlRmFicmljRXZlbnROYW1lXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuc2hhcmVkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZUZhYnJpY0V2ZW50TmFtZShcbiAgdGFibGU6IHN0cmluZyxcbiAgZXZlbnQ6IE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmcsXG4gIG93bmVyPzogc3RyaW5nXG4pIHtcbiAgY29uc3QgcGFyYW1zID0gW3RhYmxlLCBldmVudF07XG4gIGlmIChvd25lcikgcGFyYW1zLnB1c2gob3duZXIpO1xuICByZXR1cm4gcGFyYW1zLmpvaW4oXCJfXCIpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBQYXJzZXMgYSBGYWJyaWMgZXZlbnQgbmFtZSBpbnRvIGl0cyBjb21wb25lbnRzXG4gKiBAc3VtbWFyeSBTcGxpdHMgYW4gZXZlbnQgbmFtZSBieSB1bmRlcnNjb3JlcyBhbmQgZXh0cmFjdHMgdGFibGUsIGV2ZW50LCBhbmQgb3B0aW9uYWwgb3duZXJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gVGhlIGV2ZW50IG5hbWUgdG8gcGFyc2VcbiAqIEByZXR1cm4ge3t0YWJsZTogc3RyaW5nLCBldmVudDogT3BlcmF0aW9uS2V5cyB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyB8IHN0cmluZywgb3duZXI6IHN0cmluZ319IFRoZSBwYXJzZWQgY29tcG9uZW50cyBhcyBhIHN0cnVjdHVyZWQgb2JqZWN0XG4gKiBAdGhyb3dzIHtJbnRlcm5hbEVycm9yfSBJZiB0aGUgZXZlbnQgbmFtZSBmb3JtYXQgaXMgaW52YWxpZFxuICogQGZ1bmN0aW9uIHBhcnNlRXZlbnROYW1lXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICogICBwYXJ0aWNpcGFudCBQYXJzZXIgYXMgcGFyc2VFdmVudE5hbWVcbiAqICAgQ2FsbGVyLT4+UGFyc2VyOiBwYXJzZUV2ZW50TmFtZShuYW1lKVxuICogICBQYXJzZXItPj5QYXJzZXI6IHNwbGl0IG5hbWUgYnkgXCJfXCJcbiAqICAgYWx0IHBhcnRzIGxlbmd0aCBpbnZhbGlkXG4gKiAgICAgUGFyc2VyLS0+PkNhbGxlcjogdGhyb3cgSW50ZXJuYWxFcnJvclxuICogICBlbHNlXG4gKiAgICAgUGFyc2VyLS0+PkNhbGxlcjogeyB0YWJsZSwgZXZlbnQsIG93bmVyPyB9XG4gKiAgIGVuZFxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLnNoYXJlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VFdmVudE5hbWUobmFtZTogc3RyaW5nKToge1xuICB0YWJsZT86IHN0cmluZztcbiAgZXZlbnQ6IE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmc7XG4gIG93bmVyPzogc3RyaW5nO1xufSB7XG4gIGNvbnN0IHBhcnRzID0gbmFtZS5zcGxpdChcIl9cIik7XG4gIGlmIChwYXJ0cy5sZW5ndGggPCAyIHx8IHBhcnRzLmxlbmd0aCA+IDMpXG4gICAgcmV0dXJuIHsgdGFibGU6IHVuZGVmaW5lZCwgZXZlbnQ6IG5hbWUsIG93bmVyOiB1bmRlZmluZWQgfTtcbiAgcmV0dXJuIHtcbiAgICB0YWJsZTogcGFydHNbMF0sXG4gICAgZXZlbnQ6IHBhcnRzWzFdLFxuICAgIG93bmVyOiBwYXJ0c1syXSxcbiAgfSBhcyB7XG4gICAgdGFibGU6IHN0cmluZztcbiAgICBldmVudDogT3BlcmF0aW9uS2V5cyB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyB8IHN0cmluZztcbiAgICBvd25lcj86IHN0cmluZztcbiAgfTtcbn1cbiIsImltcG9ydCB7IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cywgT3BlcmF0aW9uS2V5cyB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHtcbiAgQWRhcHRlcixcbiAgQ29udGV4dHVhbEFyZ3MsXG4gIEV2ZW50SWRzLFxuICBPYnNlcnZlckhhbmRsZXIsXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgZ2VuZXJhdGVGYWJyaWNFdmVudE5hbWUgfSBmcm9tIFwiLi4vc2hhcmVkL2V2ZW50c1wiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RDb250ZXh0IH0gZnJvbSBcIi4vQ29udHJhY3RDb250ZXh0XCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBPYnNlcnZlciBoYW5kbGVyIGZvciBGYWJyaWMgY2hhaW5jb2RlIGV2ZW50c1xuICogQHN1bW1hcnkgRW1pdHMgZXZlbnRzIG9uIHRoZSBGYWJyaWMgbGVkZ2VyIHdoZW4gcmVwb3NpdG9yeSBvcGVyYXRpb25zIG9jY3VyXG4gKiBAY2xhc3MgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXJcbiAqIEBleHRlbmRzIHtPYnNlcnZlckhhbmRsZXJ9XG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gSW4gYSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRyYWN0XG4gKiBpbXBvcnQgeyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnlPYnNlcnZhYmxlSGFuZGxlciB9IGZyb20gJ0BkZWNhZi10cy9mb3ItZmFicmljJztcbiAqXG4gKiAvLyBDcmVhdGUgYSBoYW5kbGVyIHdpdGggZGVmYXVsdCBzdXBwb3J0ZWQgZXZlbnRzXG4gKiBjb25zdCBoYW5kbGVyID0gbmV3IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyKCk7XG4gKlxuICogLy8gRW1pdCBhbiBldmVudFxuICogYXdhaXQgaGFuZGxlci51cGRhdGVPYnNlcnZlcnMoXG4gKiAgIGxvZ2dlcixcbiAqICAgJ2Fzc2V0cycsXG4gKiAgIE9wZXJhdGlvbktleXMuQ1JFQVRFLFxuICogICAnYXNzZXQxJyxcbiAqICAgY29udGV4dFxuICogKTtcbiAqIGBgYFxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBSZXBvc2l0b3J5XG4gKiAgIHBhcnRpY2lwYW50IE9ic2VydmFibGVIYW5kbGVyXG4gKiAgIHBhcnRpY2lwYW50IFN0dWJcbiAqICAgcGFydGljaXBhbnQgTGVkZ2VyXG4gKlxuICogICBSZXBvc2l0b3J5LT4+T2JzZXJ2YWJsZUhhbmRsZXI6IHVwZGF0ZU9ic2VydmVycyhsb2csIHRhYmxlLCBldmVudCwgaWQsIGN0eClcbiAqICAgT2JzZXJ2YWJsZUhhbmRsZXItPj5PYnNlcnZhYmxlSGFuZGxlcjogQ2hlY2sgaWYgZXZlbnQgaXMgc3VwcG9ydGVkXG4gKiAgIE9ic2VydmFibGVIYW5kbGVyLT4+T2JzZXJ2YWJsZUhhbmRsZXI6IGdlbmVyYXRlRmFicmljRXZlbnROYW1lKHRhYmxlLCBldmVudCwgb3duZXIpXG4gKiAgIE9ic2VydmFibGVIYW5kbGVyLT4+U3R1Yjogc2V0RXZlbnQoZXZlbnROYW1lLCBwYXlsb2FkKVxuICogICBTdHViLT4+TGVkZ2VyOiBSZWNvcmQgZXZlbnRcbiAqL1xuZXhwb3J0IGNsYXNzIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyIGV4dGVuZHMgT2JzZXJ2ZXJIYW5kbGVyIHtcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgbmV3IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyIGluc3RhbmNlXG4gICAqIEBzdW1tYXJ5IEluaXRpYWxpemVzIHRoZSBoYW5kbGVyIHdpdGggYSBsaXN0IG9mIHN1cHBvcnRlZCBldmVudHNcbiAgICogQHBhcmFtIHtBcnJheTxPcGVyYXRpb25LZXlzIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzIHwgc3RyaW5nPn0gW3N1cHBvcnRlZEV2ZW50c10gLSBFdmVudHMgdGhhdCB3aWxsIHRyaWdnZXIgRmFicmljIGV2ZW50c1xuICAgKi9cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBzdXBwb3J0ZWRFdmVudHM6IChcbiAgICAgIHwgT3BlcmF0aW9uS2V5c1xuICAgICAgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXNcbiAgICAgIHwgc3RyaW5nXG4gICAgKVtdID0gW1xuICAgICAgT3BlcmF0aW9uS2V5cy5DUkVBVEUsXG4gICAgICBPcGVyYXRpb25LZXlzLlVQREFURSxcbiAgICAgIE9wZXJhdGlvbktleXMuREVMRVRFLFxuICAgICAgQnVsa0NydWRPcGVyYXRpb25LZXlzLkNSRUFURV9BTEwsXG4gICAgICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuVVBEQVRFX0FMTCxcbiAgICAgIEJ1bGtDcnVkT3BlcmF0aW9uS2V5cy5ERUxFVEVfQUxMLFxuICAgIF1cbiAgKSB7XG4gICAgc3VwZXIoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVXBkYXRlcyBvYnNlcnZlcnMgYnkgZW1pdHRpbmcgRmFicmljIGV2ZW50c1xuICAgKiBAc3VtbWFyeSBFbWl0cyBldmVudHMgb24gdGhlIEZhYnJpYyBsZWRnZXIgZm9yIHN1cHBvcnRlZCBldmVudCB0eXBlc1xuICAgKiBAcGFyYW0ge0xvZ2dlcn0gbG9nIC0gTG9nZ2VyIGluc3RhbmNlIGZvciBkZWJ1Z2dpbmdcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlIC0gVGhlIHRhYmxlL2NvbGxlY3Rpb24gbmFtZVxuICAgKiBAcGFyYW0ge09wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmd9IGV2ZW50IC0gVGhlIGV2ZW50IHR5cGVcbiAgICogQHBhcmFtIHtFdmVudElkc30gaWQgLSBUaGUgZXZlbnQgaWRlbnRpZmllclxuICAgKiBAcGFyYW0ge0ZhYnJpY0NvbnRyYWN0Q29udGV4dH0gY3R4IC0gVGhlIEZhYnJpYyBjb250cmFjdCBjb250ZXh0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbb3duZXJdIC0gT3B0aW9uYWwgb3duZXIgaWRlbnRpZmllciBmb3IgdGhlIGV2ZW50XG4gICAqIEBwYXJhbSB7b2JqZWN0IHwgc3RyaW5nIHwgdW5kZWZpbmVkfSBbb3duZXJdIC0gT3B0aW9uYWwgcGF5bG9hZCBmb3IgdGhlIGV2ZW50XG4gICAqXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBldmVudCBpcyBlbWl0dGVkXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyB1cGRhdGVPYnNlcnZlcnMoXG4gICAgY2xheno6IHN0cmluZyB8IENvbnN0cnVjdG9yPGFueT4sXG4gICAgZXZlbnQ6IE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmcsXG4gICAgaWQ6IEV2ZW50SWRzLFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPEZhYnJpY0NvbnRyYWN0Q29udGV4dD5cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gQWRhcHRlci5sb2dDdHg8RmFicmljQ29udHJhY3RDb250ZXh0PihcbiAgICAgIGFyZ3MsXG4gICAgICB0aGlzLnVwZGF0ZU9ic2VydmVyc1xuICAgICk7XG4gICAgY29uc3QgeyBzdHViIH0gPSBjdHg7XG4gICAgY29uc3QgW293bmVyLCBwYXlsb2FkXSA9IGFyZ3M7XG4gICAgY29uc3QgdGFibGUgPSB0eXBlb2YgY2xhenogPT09IFwic3RyaW5nXCIgPyBjbGF6eiA6IGNsYXp6Lm5hbWU7XG4gICAgaWYgKHRoaXMuc3VwcG9ydGVkRXZlbnRzLmluZGV4T2YoZXZlbnQpICE9PSAtMSkge1xuICAgICAgbG9nLmRlYnVnKGBFbWl0dGluZyAke2V2ZW50fSBldmVudGApO1xuICAgICAgY29uc3QgZXZlbnROYW1lID0gZ2VuZXJhdGVGYWJyaWNFdmVudE5hbWUodGFibGUsIGV2ZW50LCBvd25lcik7XG4gICAgICBzdHViLnNldEV2ZW50KGV2ZW50TmFtZSwgQnVmZmVyLmZyb20oSlNPTi5zdHJpbmdpZnkoeyBpZDogaWQgfSkpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3R1Yi5zZXRFdmVudChldmVudCwgQnVmZmVyLmZyb20oSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpKTtcbiAgICB9XG4gIH1cbn1cbiIsImltcG9ydCB7XG4gIFJlcG9zaXRvcnksXG4gIE9ic2VydmVySGFuZGxlcixcbiAgRXZlbnRJZHMsXG4gIENvbnRleHR1YWxBcmdzLFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IEZhYnJpY0NvbnRyYWN0Q29udGV4dCB9IGZyb20gXCIuL0NvbnRyYWN0Q29udGV4dFwiO1xuaW1wb3J0IHsgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnlPYnNlcnZhYmxlSGFuZGxlciB9IGZyb20gXCIuL0ZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyXCI7XG5pbXBvcnQgeyBCdWxrQ3J1ZE9wZXJhdGlvbktleXMsIE9wZXJhdGlvbktleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgdHlwZSB7IEZhYnJpY0NvbnRyYWN0QWRhcHRlciB9IGZyb20gXCIuL0NvbnRyYWN0QWRhcHRlclwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZXBvc2l0b3J5IGZvciBIeXBlcmxlZGdlciBGYWJyaWMgY2hhaW5jb2RlIG1vZGVsc1xuICogQHN1bW1hcnkgUHJvdmlkZXMgQ1JVRCBvcGVyYXRpb25zIGZvciBtb2RlbHMgd2l0aGluIEZhYnJpYyBjaGFpbmNvZGUgY29udHJhY3RzXG4gKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAdGVtcGxhdGUgTWFuZ29RdWVyeSAtIFF1ZXJ5IHR5cGUgZm9yIENvdWNoREItbGlrZSBxdWVyaWVzXG4gKiBAdGVtcGxhdGUgRmFicmljQ29udHJhY3RBZGFwdGVyIC0gQWRhcHRlciB0eXBlIGZvciBGYWJyaWMgY29udHJhY3Qgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIEZhYnJpY0NvbnRyYWN0RmxhZ3MgLSBGbGFncyBzcGVjaWZpYyB0byBGYWJyaWMgY29udHJhY3Qgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIEZhYnJpY0NvbnRyYWN0Q29udGV4dCAtIENvbnRleHQgdHlwZSBmb3IgRmFicmljIGNvbnRyYWN0IG9wZXJhdGlvbnNcbiAqXG4gKiBAcGFyYW0ge0ZhYnJpY0NvbnRyYWN0QWRhcHRlcn0gW2FkYXB0ZXJdIC0gVGhlIGFkYXB0ZXIgZm9yIGludGVyYWN0aW5nIHdpdGggdGhlIHN0YXRlIGRhdGFiYXNlXG4gKiBAcGFyYW0ge0NvbnN0cnVjdG9yPE0+fSBbY2xhenpdIC0gVGhlIG1vZGVsIGNvbnN0cnVjdG9yXG4gKiBAcGFyYW0ge0FycmF5PE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmc+fSBbdHJhY2tlZEV2ZW50c10gLSBFdmVudHMgdG8gdHJhY2sgZm9yIG9ic2VydmVyIG5vdGlmaWNhdGlvbnNcbiAqXG4gKiBAY2xhc3MgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5XG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gSW4gYSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRyYWN0IGNsYXNzXG4gKiBpbXBvcnQgeyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnksIEZhYnJpY0NvbnRyYWN0QWRhcHRlciB9IGZyb20gJ0BkZWNhZi10cy9mb3ItZmFicmljJztcbiAqXG4gKiBAdGFibGUoJ2Fzc2V0cycpXG4gKiBjbGFzcyBBc3NldCBleHRlbmRzIE1vZGVsIHtcbiAqICAgQGlkKClcbiAqICAgaWQ6IHN0cmluZztcbiAqXG4gKiAgIEBwcm9wZXJ0eSgpXG4gKiAgIGRhdGE6IHN0cmluZztcbiAqIH1cbiAqXG4gKiBleHBvcnQgY2xhc3MgTXlDb250cmFjdCBleHRlbmRzIENvbnRyYWN0IHtcbiAqICAgcHJpdmF0ZSBhZGFwdGVyID0gbmV3IEZhYnJpY0NvbnRyYWN0QWRhcHRlcigpO1xuICogICBwcml2YXRlIHJlcG9zaXRvcnk6IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxBc3NldD47XG4gKlxuICogICBjb25zdHJ1Y3RvcigpIHtcbiAqICAgICBzdXBlcignTXlDb250cmFjdCcpO1xuICogICAgIHRoaXMucmVwb3NpdG9yeSA9IG5ldyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnk8QXNzZXQ+KHRoaXMuYWRhcHRlciwgQXNzZXQpO1xuICogICB9XG4gKlxuICogICBAVHJhbnNhY3Rpb24oKVxuICogICBhc3luYyBjcmVhdGVBc3NldChjdHg6IENvbnRleHQsIGlkOiBzdHJpbmcsIGRhdGE6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICogICAgIGNvbnN0IGFzc2V0ID0gbmV3IEFzc2V0KCk7XG4gKiAgICAgYXNzZXQuaWQgPSBpZDtcbiAqICAgICBhc3NldC5kYXRhID0gZGF0YTtcbiAqXG4gKiAgICAgYXdhaXQgdGhpcy5yZXBvc2l0b3J5LmNyZWF0ZShhc3NldCwgeyBzdHViOiBjdHguc3R1YiB9KTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENvbnRyYWN0XG4gKiAgIHBhcnRpY2lwYW50IFJlcG9zaXRvcnlcbiAqICAgcGFydGljaXBhbnQgQWRhcHRlclxuICogICBwYXJ0aWNpcGFudCBTdGF0ZURCXG4gKlxuICogICBDb250cmFjdC0+PlJlcG9zaXRvcnk6IGNyZWF0ZShtb2RlbCwgY3R4KVxuICogICBSZXBvc2l0b3J5LT4+QWRhcHRlcjogcHJlcGFyZShtb2RlbCwgcGspXG4gKiAgIFJlcG9zaXRvcnktPj5BZGFwdGVyOiBjcmVhdGUodGFibGVOYW1lLCBpZCwgcmVjb3JkLCB0cmFuc2llbnQsIGN0eClcbiAqICAgQWRhcHRlci0+PlN0YXRlREI6IHB1dFN0YXRlKGlkLCBzZXJpYWxpemVkRGF0YSlcbiAqICAgU3RhdGVEQi0tPj5BZGFwdGVyOiBTdWNjZXNzXG4gKiAgIEFkYXB0ZXItLT4+UmVwb3NpdG9yeTogcmVjb3JkXG4gKiAgIFJlcG9zaXRvcnktPj5BZGFwdGVyOiByZXZlcnQocmVjb3JkLCBjbGFzcywgcGssIGlkLCB0cmFuc2llbnQpXG4gKiAgIEFkYXB0ZXItLT4+UmVwb3NpdG9yeTogbW9kZWxcbiAqICAgUmVwb3NpdG9yeS0tPj5Db250cmFjdDogbW9kZWxcbiAqL1xuZXhwb3J0IGNsYXNzIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxNIGV4dGVuZHMgTW9kZWw+IGV4dGVuZHMgUmVwb3NpdG9yeTxcbiAgTSxcbiAgRmFicmljQ29udHJhY3RBZGFwdGVyXG4+IHtcbiAgY29uc3RydWN0b3IoXG4gICAgYWRhcHRlcj86IEZhYnJpY0NvbnRyYWN0QWRhcHRlcixcbiAgICBjbGF6ej86IENvbnN0cnVjdG9yPE0+LFxuICAgIHByb3RlY3RlZCB0cmFja2VkRXZlbnRzPzogKE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmcpW11cbiAgKSB7XG4gICAgc3VwZXIoYWRhcHRlciwgY2xhenopO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIHRoZSBvYnNlcnZlciBoYW5kbGVyIGZvciB0aGlzIHJlcG9zaXRvcnlcbiAgICogQHN1bW1hcnkgUmV0dXJucyBhIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyIGluc3RhbmNlXG4gICAqIEByZXR1cm4ge09ic2VydmVySGFuZGxlcn0gVGhlIG9ic2VydmVyIGhhbmRsZXJcbiAgICovXG4gIG92ZXJyaWRlIE9ic2VydmVySGFuZGxlcigpOiBPYnNlcnZlckhhbmRsZXIge1xuICAgIHJldHVybiBuZXcgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXIoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVXBkYXRlcyBvYnNlcnZlcnMgYmFzZWQgb24gdHJhY2tlZCBldmVudHNcbiAgICogQHN1bW1hcnkgRmlsdGVycyBldmVudHMgYmFzZWQgb24gdHJhY2tlZEV2ZW50cyBhbmQgZGVsZWdhdGVzIHRvIHRoZSBwYXJlbnQgbWV0aG9kXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWJsZSAtIFRoZSB0YWJsZS9jb2xsZWN0aW9uIG5hbWVcbiAgICogQHBhcmFtIHtPcGVyYXRpb25LZXlzIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzIHwgc3RyaW5nfSBldmVudCAtIFRoZSBldmVudCB0eXBlXG4gICAqIEBwYXJhbSB7RXZlbnRJZHN9IGlkIC0gVGhlIGV2ZW50IGlkZW50aWZpZXJcbiAgICogQHBhcmFtIHtGYWJyaWNDb250cmFjdENvbnRleHR9IGN0eCAtIFRoZSBGYWJyaWMgY29udHJhY3QgY29udGV4dFxuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gb2JzZXJ2ZXJzIGFyZSB1cGRhdGVkXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyB1cGRhdGVPYnNlcnZlcnMoXG4gICAgdGFibGU6IENvbnN0cnVjdG9yPE0+IHwgc3RyaW5nLFxuICAgIGV2ZW50OiBPcGVyYXRpb25LZXlzIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzIHwgc3RyaW5nLFxuICAgIGlkOiBFdmVudElkcyxcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxGYWJyaWNDb250cmFjdENvbnRleHQ+XG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy50cmFja2VkRXZlbnRzIHx8IHRoaXMudHJhY2tlZEV2ZW50cy5pbmRleE9mKGV2ZW50KSAhPT0gLTEpXG4gICAgICByZXR1cm4gYXdhaXQgc3VwZXIudXBkYXRlT2JzZXJ2ZXJzKHRhYmxlLCBldmVudCwgaWQsIC4uLmFyZ3MpO1xuICB9XG59XG4iLCJpbXBvcnQgeyBNb2RlbCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7XG4gIENvdWNoREJBZGFwdGVyLFxuICBDb3VjaERCR3JvdXBPcGVyYXRvcixcbiAgQ291Y2hEQktleXMsXG4gIENvdWNoREJPcGVyYXRvcixcbiAgTWFuZ29PcGVyYXRvcixcbiAgTWFuZ29RdWVyeSxcbiAgTWFuZ29TZWxlY3Rvcixcbn0gZnJvbSBcIkBkZWNhZi10cy9mb3ItY291Y2hkYlwiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RDb250ZXh0IH0gZnJvbSBcIi4vQ29udHJhY3RDb250ZXh0XCI7XG5pbXBvcnQgeyBDb3VjaERCU3RhdGVtZW50IH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItY291Y2hkYlwiO1xuaW1wb3J0IHsgQ29uZGl0aW9uLCBPcmRlckRpcmVjdGlvbiB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgTWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IERCS2V5cyB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBTdGF0ZW1lbnQgd3JhcHBlciBmb3IgZXhlY3V0aW5nIE1hbmdvIHF1ZXJpZXMgd2l0aGluIEZhYnJpYyBjb250cmFjdHNcbiAqIEBzdW1tYXJ5IEJyaWRnZXMgQ291Y2hEQi1zdHlsZSBxdWVyaWVzIHRvIEZhYnJpYyB2aWEgdGhlIEZhYnJpY0NvbnRyYWN0QWRhcHRlciwgaGFuZGxpbmcgaWRlbnRpdHkgYW5kIHByaW1hcnkga2V5IHByb2plY3Rpb24gd2hlbiBuZWVkZWQuXG4gKiBAdGVtcGxhdGUgTSAtIE1vZGVsIHR5cGUgdGhpcyBzdGF0ZW1lbnQgb3BlcmF0ZXMgb25cbiAqIEB0ZW1wbGF0ZSBSIC0gUmVzdWx0IHR5cGUgcmV0dXJuZWQgYnkgdGhlIHN0YXRlbWVudFxuICogQHBhcmFtIHtGYWJyaWNDb250cmFjdEFkYXB0ZXJ9IGFkYXB0ZXIgLSBUaGUgRmFicmljIGNvbnRyYWN0IGFkYXB0ZXIgdXNlZCBmb3IgcmF3IGV4ZWN1dGlvblxuICogQHBhcmFtIHtGYWJyaWNDb250cmFjdENvbnRleHR9IGN0eCAtIFRoZSBGYWJyaWMgY29udHJhY3QgY29udGV4dCBjYXJyeWluZyBzdHViIGFuZCBpZGVudGl0eVxuICogQHJldHVybiB7dm9pZH1cbiAqIEBjbGFzcyBGYWJyaWNTdGF0ZW1lbnRcbiAqIEBleGFtcGxlXG4gKiBjb25zdCBzdG10ID0gbmV3IEZhYnJpY1N0YXRlbWVudDxNeU1vZGVsLCBNeU1vZGVsW10+KGFkYXB0ZXIsIGN0eCk7XG4gKiBjb25zdCByZXN1bHQgPSBhd2FpdCBzdG10LnJhdzxNeU1vZGVsW10+KHsgc2VsZWN0b3I6IHsgdHlwZTogJ015TW9kZWwnIH0gfSk7XG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBwYXJ0aWNpcGFudCBTdGF0ZW1lbnRcbiAqICAgcGFydGljaXBhbnQgQWRhcHRlclxuICogICBwYXJ0aWNpcGFudCBMZWRnZXJcbiAqICAgQXBwLT4+U3RhdGVtZW50OiByYXcoeyBzZWxlY3RvciB9KVxuICogICBTdGF0ZW1lbnQtPj5BZGFwdGVyOiBhZGFwdGVyLnJhdyhtYW5nbywgdHJ1ZSwgY3R4KVxuICogICBBZGFwdGVyLT4+TGVkZ2VyOiBFdmFsdWF0ZSBxdWVyeVxuICogICBBZGFwdGVyLS0+PlN0YXRlbWVudDogcm93c1xuICogICBTdGF0ZW1lbnQtLT4+QXBwOiBtb2RlbHNcbiAqL1xuZXhwb3J0IGNsYXNzIEZhYnJpY1N0YXRlbWVudDxNIGV4dGVuZHMgTW9kZWwsIFI+IGV4dGVuZHMgQ291Y2hEQlN0YXRlbWVudDxcbiAgTSxcbiAgQ291Y2hEQkFkYXB0ZXI8YW55LCB2b2lkLCBGYWJyaWNDb250cmFjdENvbnRleHQ+LFxuICBSXG4+IHtcbiAgY29uc3RydWN0b3IoYWRhcHRlcjogQ291Y2hEQkFkYXB0ZXI8YW55LCB2b2lkLCBGYWJyaWNDb250cmFjdENvbnRleHQ+KSB7XG4gICAgc3VwZXIoYWRhcHRlcik7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyByYXc8Uj4ocmF3SW5wdXQ6IE1hbmdvUXVlcnksIC4uLmFyZ3M6IGFueVtdKTogUHJvbWlzZTxSPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmF3KTtcblxuICAgIGNvbnN0IHJlc3VsdHM6IGFueVtdID0gYXdhaXQgdGhpcy5hZGFwdGVyLnJhdyhyYXdJbnB1dCwgdHJ1ZSwgY3R4KTtcblxuICAgIGNvbnN0IHBrQXR0ciA9IE1vZGVsLnBrKHRoaXMuZnJvbVNlbGVjdG9yKTtcbiAgICBjb25zdCB0eXBlID0gTWV0YWRhdGEuZ2V0KFxuICAgICAgdGhpcy5mcm9tU2VsZWN0b3IsXG4gICAgICBNZXRhZGF0YS5rZXkoREJLZXlzLklELCBwa0F0dHIgYXMgc3RyaW5nKVxuICAgICk/LnR5cGU7XG5cbiAgICBpZiAoIXRoaXMuc2VsZWN0U2VsZWN0b3IpXG4gICAgICByZXR1cm4gcmVzdWx0cy5tYXAoKHIpID0+IHRoaXMucHJvY2Vzc1JlY29yZChyLCBwa0F0dHIsIHR5cGUsIGN0eCkpIGFzIFI7XG4gICAgcmV0dXJuIHJlc3VsdHMgYXMgUjtcbiAgfVxuXG4gIG92ZXJyaWRlIGJ1aWxkKCk6IE1hbmdvUXVlcnkge1xuICAgIGNvbnN0IHNlbGVjdG9yczogTWFuZ29TZWxlY3RvciA9IHt9O1xuICAgIHNlbGVjdG9yc1tDb3VjaERCS2V5cy5UQUJMRV0gPSB7fTtcbiAgICBzZWxlY3RvcnNbQ291Y2hEQktleXMuVEFCTEVdID0gTW9kZWwudGFibGVOYW1lKHRoaXMuZnJvbVNlbGVjdG9yKTtcbiAgICBjb25zdCBxdWVyeTogTWFuZ29RdWVyeSA9IHsgc2VsZWN0b3I6IHNlbGVjdG9ycyB9O1xuICAgIGlmICh0aGlzLnNlbGVjdFNlbGVjdG9yKSBxdWVyeS5maWVsZHMgPSB0aGlzLnNlbGVjdFNlbGVjdG9yIGFzIHN0cmluZ1tdO1xuXG4gICAgaWYgKHRoaXMud2hlcmVDb25kaXRpb24pIHtcbiAgICAgIGNvbnN0IGNvbmRpdGlvbjogTWFuZ29TZWxlY3RvciA9IHRoaXMucGFyc2VDb25kaXRpb24oXG4gICAgICAgIENvbmRpdGlvbi5hbmQoXG4gICAgICAgICAgdGhpcy53aGVyZUNvbmRpdGlvbixcbiAgICAgICAgICBDb25kaXRpb24uYXR0cmlidXRlPE0+KENvdWNoREJLZXlzLlRBQkxFIGFzIGtleW9mIE0pLmVxKFxuICAgICAgICAgICAgcXVlcnkuc2VsZWN0b3JbQ291Y2hEQktleXMuVEFCTEVdXG4gICAgICAgICAgKVxuICAgICAgICApXG4gICAgICApLnNlbGVjdG9yO1xuICAgICAgY29uc3Qgc2VsZWN0b3JLZXlzID0gT2JqZWN0LmtleXMoY29uZGl0aW9uKSBhcyBNYW5nb09wZXJhdG9yW107XG4gICAgICBpZiAoXG4gICAgICAgIHNlbGVjdG9yS2V5cy5sZW5ndGggPT09IDEgJiZcbiAgICAgICAgT2JqZWN0LnZhbHVlcyhDb3VjaERCR3JvdXBPcGVyYXRvcikuaW5kZXhPZihzZWxlY3RvcktleXNbMF0pICE9PSAtMVxuICAgICAgKVxuICAgICAgICBzd2l0Y2ggKHNlbGVjdG9yS2V5c1swXSkge1xuICAgICAgICAgIGNhc2UgQ291Y2hEQkdyb3VwT3BlcmF0b3IuQU5EOlxuICAgICAgICAgICAgY29uZGl0aW9uW0NvdWNoREJHcm91cE9wZXJhdG9yLkFORF0gPSBbXG4gICAgICAgICAgICAgIC4uLk9iamVjdC52YWx1ZXMoXG4gICAgICAgICAgICAgICAgY29uZGl0aW9uW0NvdWNoREJHcm91cE9wZXJhdG9yLkFORF0gYXMgTWFuZ29TZWxlY3RvclxuICAgICAgICAgICAgICApLnJlZHVjZSgoYWNjdW06IE1hbmdvU2VsZWN0b3JbXSwgdmFsOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXModmFsKTtcbiAgICAgICAgICAgICAgICBpZiAoa2V5cy5sZW5ndGggIT09IDEpXG4gICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIFwiVG9vIG1hbnkga2V5cyBpbiBxdWVyeSBzZWxlY3Rvci4gc2hvdWxkIGJlIG9uZVwiXG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGNvbnN0IGsgPSBrZXlzWzBdO1xuICAgICAgICAgICAgICAgIGlmIChrID09PSBDb3VjaERCR3JvdXBPcGVyYXRvci5BTkQpXG4gICAgICAgICAgICAgICAgICBhY2N1bS5wdXNoKC4uLih2YWxba10gYXMgYW55W10pKTtcbiAgICAgICAgICAgICAgICBlbHNlIGFjY3VtLnB1c2godmFsKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gYWNjdW07XG4gICAgICAgICAgICAgIH0sIFtdKSxcbiAgICAgICAgICAgIF07XG4gICAgICAgICAgICBxdWVyeS5zZWxlY3RvciA9IGNvbmRpdGlvbjtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIGNhc2UgQ291Y2hEQkdyb3VwT3BlcmF0b3IuT1I6IHtcbiAgICAgICAgICAgIGNvbnN0IHM6IFJlY29yZDxhbnksIGFueT4gPSB7fTtcbiAgICAgICAgICAgIHNbQ291Y2hEQkdyb3VwT3BlcmF0b3IuQU5EXSA9IFtcbiAgICAgICAgICAgICAgY29uZGl0aW9uLFxuICAgICAgICAgICAgICAuLi5PYmplY3QuZW50cmllcyhxdWVyeS5zZWxlY3RvcikubWFwKChba2V5LCB2YWxdKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8YW55LCBhbnk+ID0ge307XG4gICAgICAgICAgICAgICAgcmVzdWx0W2tleV0gPSB2YWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBdO1xuICAgICAgICAgICAgcXVlcnkuc2VsZWN0b3IgPSBzO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGlzIHNob3VsZCBiZSBpbXBvc3NpYmxlXCIpO1xuICAgICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgT2JqZWN0LmVudHJpZXMoY29uZGl0aW9uKS5mb3JFYWNoKChba2V5LCB2YWxdKSA9PiB7XG4gICAgICAgICAgaWYgKHF1ZXJ5LnNlbGVjdG9yW2tleV0pXG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgIGBBICR7a2V5fSBxdWVyeSBwYXJhbSBpcyBhYm91dCB0byBiZSBvdmVycmlkZGVuOiAke3F1ZXJ5LnNlbGVjdG9yW2tleV19IGJ5ICR7dmFsfWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgcXVlcnkuc2VsZWN0b3Jba2V5XSA9IHZhbDtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHRoaXMub3JkZXJCeVNlbGVjdG9yKSB7XG4gICAgICBxdWVyeS5zb3J0ID0gcXVlcnkuc29ydCB8fCBbXTtcbiAgICAgIHF1ZXJ5LnNlbGVjdG9yID0gcXVlcnkuc2VsZWN0b3IgfHwgKHt9IGFzIE1hbmdvU2VsZWN0b3IpO1xuICAgICAgY29uc3QgW3NlbGVjdG9yLCB2YWx1ZV0gPSB0aGlzLm9yZGVyQnlTZWxlY3RvciBhcyBbXG4gICAgICAgIHN0cmluZyxcbiAgICAgICAgT3JkZXJEaXJlY3Rpb24sXG4gICAgICBdO1xuICAgICAgY29uc3QgcmVjOiBhbnkgPSB7fTtcbiAgICAgIHJlY1tzZWxlY3Rvcl0gPSB2YWx1ZTtcbiAgICAgIChxdWVyeS5zb3J0IGFzIGFueVtdKS5wdXNoKHJlYyBhcyBhbnkpO1xuICAgICAgaWYgKCFxdWVyeS5zZWxlY3RvcltzZWxlY3Rvcl0pIHtcbiAgICAgICAgcXVlcnkuc2VsZWN0b3Jbc2VsZWN0b3JdID0ge30gYXMgTWFuZ29TZWxlY3RvcjtcbiAgICAgICAgKHF1ZXJ5LnNlbGVjdG9yW3NlbGVjdG9yXSBhcyBNYW5nb1NlbGVjdG9yKVtDb3VjaERCT3BlcmF0b3IuQklHR0VSXSA9XG4gICAgICAgICAgbnVsbDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodGhpcy5saW1pdFNlbGVjdG9yKSBxdWVyeS5saW1pdCA9IHRoaXMubGltaXRTZWxlY3RvcjtcblxuICAgIGlmICh0aGlzLm9mZnNldFNlbGVjdG9yKSBxdWVyeS5za2lwID0gdGhpcy5vZmZzZXRTZWxlY3RvcjtcblxuICAgIHJldHVybiBxdWVyeTtcbiAgfVxufVxuIiwiLyoqXG4gKiBAZGVzY3JpcHRpb24gS2V5cyB1c2VkIHRvIG1hcmsgRmFicmljLXNwZWNpZmljIG1vZGVsIG1ldGFkYXRhXG4gKiBAc3VtbWFyeSBFbnVtZXJhdGlvbiBvZiBzcGVjaWFsIGtleXMgdXNlZCBieSB0aGUgc2VyaWFsaXphdGlvbiBsYXllciB0byBwZXJzaXN0IEZhYnJpYy1yZWxhdGVkIGZsYWdzIG9uIG1vZGVsc1xuICogQGVudW0ge3N0cmluZ31cbiAqIEByZWFkb25seVxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLnNoYXJlZFxuICovXG5leHBvcnQgZW51bSBGYWJyaWNNb2RlbEtleXMge1xuICAvKiogUHJpdmF0ZSBkYXRhIG1hcmtlciB1c2VkIHRvIHRhZyBwcm9wZXJ0aWVzIG9yIG1vZGVscyBmb3IgRmFicmljIHByaXZhdGUgY29sbGVjdGlvbnMgKi9cbiAgUFJJVkFURSA9IFwicHJpdmF0ZVwiLFxuICBTSEFSRUQgPSBcInNoYXJlZFwiLFxuICAvKiogTmFtZXNwYWNlIHByZWZpeCB1c2VkIGZvciBGYWJyaWMtc3BlY2lmaWMgbWV0YWRhdGEga2V5cyAqL1xuICBGQUJSSUMgPSBcImZhYnJpYy5cIixcbiAgT1dORURCWSA9IFwib3duZWQtYnlcIixcbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIFN1cHBvcnRlZCBpZGVudGl0eSB0eXBlcyBmb3IgRmFicmljIGNyZWRlbnRpYWxzXG4gKiBAc3VtbWFyeSBFbnVtZXJhdGlvbiBvZiBpZGVudGl0eSBmb3JtYXRzIHJlY29nbml6ZWQgYnkgdGhpcyBsaWJyYXJ5XG4gKiBAZW51bSB7c3RyaW5nfVxuICogQHJlYWRvbmx5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuc2hhcmVkXG4gKi9cbmV4cG9ydCBlbnVtIElkZW50aXR5VHlwZSB7XG4gIC8qKiBTdGFuZGFyZCBYLjUwOSBpZGVudGl0eSBmb3JtYXQgdXNlZCBieSBIeXBlcmxlZGdlciBGYWJyaWMgKi9cbiAgWDUwOSA9IFwiWC41MDlcIixcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gU3RyaW5nIGlkZW50aWZpZXIgZm9yIHRoZSBGYWJyaWMgYWRhcHRlciBmbGF2b3VyXG4gKiBAc3VtbWFyeSBVc2VkIHRvIHRhZyBhZGFwdGVycy9yZXBvc2l0b3JpZXMgdGhhdCBvcGVyYXRlIGFnYWluc3QgSHlwZXJsZWRnZXIgRmFicmljXG4gKiBAY29uc3QgRmFicmljRmxhdm91clxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLnNoYXJlZFxuICovXG5leHBvcnQgY29uc3QgRmFicmljRmxhdm91ciA9IFwiaGxmLWZhYnJpY1wiO1xuIiwiaW1wb3J0IHsgSlNPTlNlcmlhbGl6ZXIsIE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuXG5leHBvcnQgY2xhc3MgU2ltcGxlRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXI8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbj4gZXh0ZW5kcyBKU09OU2VyaWFsaXplcjxNPiB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIG92ZXJyaWRlIGRlc2VyaWFsaXplKHN0cjogc3RyaW5nLCB0YWJsZU5hbWU/OiBzdHJpbmcpOiBNIHtcbiAgICBjb25zdCBkZXNlcmlhbGl6YXRpb24gPSBKU09OLnBhcnNlKHN0cik7XG4gICAgLy8gY29uc3QgY2xhc3NOYW1lID0gdGFibGVOYW1lO1xuICAgIC8vIGlmICghY2xhc3NOYW1lKVxuICAgIC8vICAgdGhyb3cgbmV3IEVycm9yKFwiQ291bGQgbm90IGZpbmQgY2xhc3MgcmVmZXJlbmNlIGluIHNlcmlhbGl6ZWQgbW9kZWxcIik7XG5cbiAgICAvLyAvLyB0aGlzIHdpbGwgcmV0dXJuIHVuZGVmaW5lZCB2YWx1ZXNcbiAgICAvLyBjb25zdCBtb2RlbDogTSA9IE1vZGVsLmJ1aWxkKGRlc2VyaWFsaXphdGlvbiwgY2xhc3NOYW1lKSBhcyB1bmtub3duIGFzIE07XG5cbiAgICAvLyAvLyBQb3B1bGF0ZSBNb2RlbFxuICAgIC8vIGNvbnN0IHByb2Nlc3NlZERlc2VhbGl6YXRpb24gPSBPYmplY3Qua2V5cyhtb2RlbCkucmVkdWNlKFxuICAgIC8vICAgKGFjY3VtOiBNLCBrZXkpID0+IHtcbiAgICAvLyAgICAgKGFjY3VtIGFzIFJlY29yZDxzdHJpbmcsIGFueT4pW2tleV0gPVxuICAgIC8vICAgICAgIGRlc2VyaWFsaXphdGlvbltSZXBvc2l0b3J5LmNvbHVtbihhY2N1bSwga2V5KV07XG4gICAgLy8gICAgIHJldHVybiBhY2N1bTtcbiAgICAvLyAgIH0sXG4gICAgLy8gICBtb2RlbFxuICAgIC8vICk7XG5cbiAgICAvLyBjb25zdCByZXN1bHQgPSBNb2RlbC5idWlsZChcbiAgICAvLyAgIHByb2Nlc3NlZERlc2VhbGl6YXRpb24sXG4gICAgLy8gICBjbGFzc05hbWVcbiAgICAvLyApIGFzIHVua25vd24gYXMgTTtcblxuICAgIC8vIHJldHVybiByZXN1bHQ7XG4gICAgcmV0dXJuIGRlc2VyaWFsaXphdGlvbjtcbiAgfVxuXG4gIG92ZXJyaWRlIHNlcmlhbGl6ZShtb2RlbDogTSk6IHN0cmluZyB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCBzdHJpbmdpZnkgPSByZXF1aXJlKFwianNvbi1zdHJpbmdpZnktZGV0ZXJtaW5pc3RpY1wiKTtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuICAgIGNvbnN0IHNvcnRLZXlzUmVjdXJzaXZlID0gcmVxdWlyZShcInNvcnQta2V5cy1yZWN1cnNpdmVcIik7XG4gICAgcmV0dXJuIHN0cmluZ2lmeShzb3J0S2V5c1JlY3Vyc2l2ZSh0aGlzLnByZVNlcmlhbGl6ZShtb2RlbCkpKTtcbiAgfVxuXG4gIG92ZXJyaWRlIHByZVNlcmlhbGl6ZShtb2RlbDogTSk6IFJlY29yZDxzdHJpbmcsIGFueT4ge1xuICAgIGNvbnN0IHRvU2VyaWFsaXplOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0gT2JqZWN0LmFzc2lnbih7fSwgbW9kZWwpO1xuICAgIHJldHVybiB0b1NlcmlhbGl6ZTtcbiAgfVxufVxuIiwiaW1wb3J0IHtcbiAgY2FjaGVNb2RlbEZvclBvcHVsYXRlLFxuICBDYXNjYWRlLFxuICBjcmVhdGVPclVwZGF0ZSxcbiAgZ2V0UG9wdWxhdGVLZXksXG4gIFJlbGF0aW9uc01ldGFkYXRhLFxuICBSZXBvLFxuICBSZXBvc2l0b3J5LFxuICByZXBvc2l0b3J5RnJvbVR5cGVNZXRhZGF0YSxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBNb2RlbCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IENvbnRleHRPZlJlcG9zaXRvcnksIEludGVybmFsRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeSB9IGZyb20gXCIuL0ZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeVwiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RDb250ZXh0IH0gZnJvbSBcIi4vQ29udHJhY3RDb250ZXh0XCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEhhbmRsZXMgb25lLXRvLW9uZSByZWxhdGlvbnNoaXAgY3JlYXRpb25cbiAqIEBzdW1tYXJ5IFByb2Nlc3NlcyBhIG9uZS10by1vbmUgcmVsYXRpb25zaGlwIHdoZW4gY3JlYXRpbmcgYSBtb2RlbCwgZWl0aGVyIGJ5IHJlZmVyZW5jaW5nIGFuIGV4aXN0aW5nIG1vZGVsIG9yIGNyZWF0aW5nIGEgbmV3IG9uZVxuICogQHRlbXBsYXRlIE0gLSBUaGUgbW9kZWwgdHlwZSBleHRlbmRpbmcgTW9kZWxcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHJlcG9zaXRvcnkgdHlwZSBleHRlbmRpbmcgUmVwbzxNLCBGLCBDPlxuICogQHRlbXBsYXRlIFYgLSBUaGUgcmVsYXRpb25zIG1ldGFkYXRhIHR5cGUgZXh0ZW5kaW5nIFJlbGF0aW9uc01ldGFkYXRhXG4gKiBAdGVtcGxhdGUgRiAtIFRoZSByZXBvc2l0b3J5IGZsYWdzIHR5cGVcbiAqIEB0ZW1wbGF0ZSBDIC0gVGhlIGNvbnRleHQgdHlwZSBleHRlbmRpbmcgQ29udGV4dDxGPlxuICogQHBhcmFtIHtSfSB0aGlzIC0gVGhlIHJlcG9zaXRvcnkgaW5zdGFuY2VcbiAqIEBwYXJhbSB7Q29udGV4dDxGPn0gY29udGV4dCAtIFRoZSBjb250ZXh0IGZvciB0aGUgb3BlcmF0aW9uXG4gKiBAcGFyYW0ge1Z9IGRhdGEgLSBUaGUgcmVsYXRpb25zIG1ldGFkYXRhXG4gKiBAcGFyYW0ge3N0cmluZ30ga2V5IC0gVGhlIHByb3BlcnR5IGtleSBvZiB0aGUgcmVsYXRpb25zaGlwXG4gKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlXG4gKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBvcGVyYXRpb24gaXMgY29tcGxldGVcbiAqIEBmdW5jdGlvbiBvbmVUb09uZU9uQ3JlYXRlXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmNvcmVcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IG9uZVRvT25lT25DcmVhdGVcbiAqICAgcGFydGljaXBhbnQgcmVwb3NpdG9yeUZyb21UeXBlTWV0YWRhdGFcbiAqICAgcGFydGljaXBhbnQgTW9kZWxcbiAqICAgcGFydGljaXBhbnQgUmVwb3NpdG9yeVxuICogICBwYXJ0aWNpcGFudCBjYWNoZU1vZGVsRm9yUG9wdWxhdGVcbiAqXG4gKiAgIENhbGxlci0+Pm9uZVRvT25lT25DcmVhdGU6IHRoaXMsIGNvbnRleHQsIGRhdGEsIGtleSwgbW9kZWxcbiAqICAgb25lVG9PbmVPbkNyZWF0ZS0+Pm9uZVRvT25lT25DcmVhdGU6IGNoZWNrIGlmIHByb3BlcnR5VmFsdWUgZXhpc3RzXG4gKlxuICogICBhbHQgcHJvcGVydHlWYWx1ZSBpcyBub3QgYW4gb2JqZWN0XG4gKiAgICAgb25lVG9PbmVPbkNyZWF0ZS0+PnJlcG9zaXRvcnlGcm9tVHlwZU1ldGFkYXRhOiBtb2RlbCwga2V5XG4gKiAgICAgcmVwb3NpdG9yeUZyb21UeXBlTWV0YWRhdGEtLT4+b25lVG9PbmVPbkNyZWF0ZTogaW5uZXJSZXBvXG4gKiAgICAgb25lVG9PbmVPbkNyZWF0ZS0+PmlubmVyUmVwbzogcmVhZChwcm9wZXJ0eVZhbHVlKVxuICogICAgIGlubmVyUmVwby0tPj5vbmVUb09uZU9uQ3JlYXRlOiByZWFkXG4gKiAgICAgb25lVG9PbmVPbkNyZWF0ZS0+PmNhY2hlTW9kZWxGb3JQb3B1bGF0ZTogY29udGV4dCwgbW9kZWwsIGtleSwgcHJvcGVydHlWYWx1ZSwgcmVhZFxuICogICAgIG9uZVRvT25lT25DcmVhdGUtPj5vbmVUb09uZU9uQ3JlYXRlOiBzZXQgbW9kZWxba2V5XSA9IHByb3BlcnR5VmFsdWVcbiAqICAgZWxzZSBwcm9wZXJ0eVZhbHVlIGlzIGFuIG9iamVjdFxuICogICAgIG9uZVRvT25lT25DcmVhdGUtPj5Nb2RlbDogZ2V0KGRhdGEuY2xhc3MpXG4gKiAgICAgTW9kZWwtLT4+b25lVG9PbmVPbkNyZWF0ZTogY29uc3RydWN0b3JcbiAqICAgICBvbmVUb09uZU9uQ3JlYXRlLT4+UmVwb3NpdG9yeTogZm9yTW9kZWwoY29uc3RydWN0b3IpXG4gKiAgICAgUmVwb3NpdG9yeS0tPj5vbmVUb09uZU9uQ3JlYXRlOiByZXBvXG4gKiAgICAgb25lVG9PbmVPbkNyZWF0ZS0+PnJlcG86IGNyZWF0ZShwcm9wZXJ0eVZhbHVlKVxuICogICAgIHJlcG8tLT4+b25lVG9PbmVPbkNyZWF0ZTogY3JlYXRlZFxuICogICAgIG9uZVRvT25lT25DcmVhdGUtPj5maW5kUHJpbWFyeUtleTogY3JlYXRlZFxuICogICAgIGZpbmRQcmltYXJ5S2V5LS0+Pm9uZVRvT25lT25DcmVhdGU6IHBrXG4gKiAgICAgb25lVG9PbmVPbkNyZWF0ZS0+PmNhY2hlTW9kZWxGb3JQb3B1bGF0ZTogY29udGV4dCwgbW9kZWwsIGtleSwgY3JlYXRlZFtwa10sIGNyZWF0ZWRcbiAqICAgICBvbmVUb09uZU9uQ3JlYXRlLT4+b25lVG9PbmVPbkNyZWF0ZTogc2V0IG1vZGVsW2tleV0gPSBjcmVhdGVkW3BrXVxuICogICBlbmRcbiAqXG4gKiAgIG9uZVRvT25lT25DcmVhdGUtLT4+Q2FsbGVyOiB2b2lkXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBvbmVUb09uZU9uQ3JlYXRlPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIFIgZXh0ZW5kcyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnk8TT4sXG4gIFYgZXh0ZW5kcyBSZWxhdGlvbnNNZXRhZGF0YSxcbj4oXG4gIHRoaXM6IFIsXG4gIGNvbnRleHQ6IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgZGF0YTogVixcbiAga2V5OiBrZXlvZiBNLFxuICBtb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHByb3BlcnR5VmFsdWU6IGFueSA9IG1vZGVsW2tleV07XG4gIGlmICghcHJvcGVydHlWYWx1ZSkgcmV0dXJuO1xuXG4gIGlmICh0eXBlb2YgcHJvcGVydHlWYWx1ZSAhPT0gXCJvYmplY3RcIikge1xuICAgIGNvbnN0IGlubmVyUmVwbyA9IHJlcG9zaXRvcnlGcm9tVHlwZU1ldGFkYXRhKFxuICAgICAgbW9kZWwsXG4gICAgICBrZXksXG4gICAgICB0aGlzLmFkYXB0ZXIuYWxpYXNcbiAgICApO1xuICAgIGNvbnN0IHJlYWQgPSBhd2FpdCBpbm5lclJlcG8ucmVhZChwcm9wZXJ0eVZhbHVlLCBjb250ZXh0KTtcbiAgICBhd2FpdCBjYWNoZU1vZGVsRm9yUG9wdWxhdGUoY29udGV4dCwgbW9kZWwsIGtleSwgcHJvcGVydHlWYWx1ZSwgcmVhZCk7XG4gICAgKG1vZGVsIGFzIGFueSlba2V5XSA9IHByb3BlcnR5VmFsdWU7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgZGF0YS5jbGFzcyA9XG4gICAgdHlwZW9mIGRhdGEuY2xhc3MgPT09IFwic3RyaW5nXCIgPyBkYXRhLmNsYXNzIDogKGRhdGEuY2xhc3MgYXMgYW55KSgpLm5hbWU7XG5cbiAgY29uc3QgY29uc3RydWN0b3IgPSBNb2RlbC5nZXQoZGF0YS5jbGFzcyBhcyB1bmtub3duIGFzIHN0cmluZyk7XG4gIGlmICghY29uc3RydWN0b3IpXG4gICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYENvdWxkIG5vdCBmaW5kIG1vZGVsICR7ZGF0YS5jbGFzc31gKTtcbiAgY29uc3QgcmVwbzogUmVwbzxhbnk+ID0gUmVwb3NpdG9yeS5mb3JNb2RlbChjb25zdHJ1Y3RvciwgdGhpcy5hZGFwdGVyLmFsaWFzKTtcbiAgY29uc3QgY3JlYXRlZCA9IGF3YWl0IHJlcG8uY3JlYXRlKHByb3BlcnR5VmFsdWUsIGNvbnRleHQpO1xuICBjb25zdCBwayA9IE1vZGVsLnBrKGNyZWF0ZWQpO1xuICBhd2FpdCBjYWNoZU1vZGVsRm9yUG9wdWxhdGUoY29udGV4dCwgbW9kZWwsIGtleSwgY3JlYXRlZFtwa10sIGNyZWF0ZWQpO1xuICAobW9kZWwgYXMgYW55KVtrZXldID0gY3JlYXRlZFtwa107XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEhhbmRsZXMgb25lLXRvLW9uZSByZWxhdGlvbnNoaXAgdXBkYXRlc1xuICogQHN1bW1hcnkgUHJvY2Vzc2VzIGEgb25lLXRvLW9uZSByZWxhdGlvbnNoaXAgd2hlbiB1cGRhdGluZyBhIG1vZGVsLCBlaXRoZXIgYnkgcmVmZXJlbmNpbmcgYW4gZXhpc3RpbmcgbW9kZWwgb3IgdXBkYXRpbmcgdGhlIHJlbGF0ZWQgbW9kZWxcbiAqIEB0ZW1wbGF0ZSBNIC0gVGhlIG1vZGVsIHR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAdGVtcGxhdGUgUiAtIFRoZSByZXBvc2l0b3J5IHR5cGUgZXh0ZW5kaW5nIFJlcG88TSwgRiwgQz5cbiAqIEB0ZW1wbGF0ZSBWIC0gVGhlIHJlbGF0aW9ucyBtZXRhZGF0YSB0eXBlIGV4dGVuZGluZyBSZWxhdGlvbnNNZXRhZGF0YVxuICogQHRlbXBsYXRlIEYgLSBUaGUgcmVwb3NpdG9yeSBmbGFncyB0eXBlXG4gKiBAdGVtcGxhdGUgQyAtIFRoZSBjb250ZXh0IHR5cGUgZXh0ZW5kaW5nIENvbnRleHQ8Rj5cbiAqIEBwYXJhbSB7Un0gdGhpcyAtIFRoZSByZXBvc2l0b3J5IGluc3RhbmNlXG4gKiBAcGFyYW0ge0NvbnRleHQ8Rj59IGNvbnRleHQgLSBUaGUgY29udGV4dCBmb3IgdGhlIG9wZXJhdGlvblxuICogQHBhcmFtIHtWfSBkYXRhIC0gVGhlIHJlbGF0aW9ucyBtZXRhZGF0YVxuICogQHBhcmFtIGtleSAtIFRoZSBwcm9wZXJ0eSBrZXkgb2YgdGhlIHJlbGF0aW9uc2hpcFxuICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZVxuICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgb3BlcmF0aW9uIGlzIGNvbXBsZXRlXG4gKiBAZnVuY3Rpb24gb25lVG9PbmVPblVwZGF0ZVxuICogQG1lbWJlck9mIG1vZHVsZTpjb3JlXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICogICBwYXJ0aWNpcGFudCBvbmVUb09uZU9uVXBkYXRlXG4gKiAgIHBhcnRpY2lwYW50IHJlcG9zaXRvcnlGcm9tVHlwZU1ldGFkYXRhXG4gKiAgIHBhcnRpY2lwYW50IGNyZWF0ZU9yVXBkYXRlXG4gKiAgIHBhcnRpY2lwYW50IGZpbmRQcmltYXJ5S2V5XG4gKiAgIHBhcnRpY2lwYW50IGNhY2hlTW9kZWxGb3JQb3B1bGF0ZVxuICpcbiAqICAgQ2FsbGVyLT4+b25lVG9PbmVPblVwZGF0ZTogdGhpcywgY29udGV4dCwgZGF0YSwga2V5LCBtb2RlbFxuICogICBvbmVUb09uZU9uVXBkYXRlLT4+b25lVG9PbmVPblVwZGF0ZTogY2hlY2sgaWYgcHJvcGVydHlWYWx1ZSBleGlzdHNcbiAqICAgb25lVG9PbmVPblVwZGF0ZS0+Pm9uZVRvT25lT25VcGRhdGU6IGNoZWNrIGlmIGNhc2NhZGUudXBkYXRlIGlzIENBU0NBREVcbiAqXG4gKiAgIGFsdCBwcm9wZXJ0eVZhbHVlIGlzIG5vdCBhbiBvYmplY3RcbiAqICAgICBvbmVUb09uZU9uVXBkYXRlLT4+cmVwb3NpdG9yeUZyb21UeXBlTWV0YWRhdGE6IG1vZGVsLCBrZXlcbiAqICAgICByZXBvc2l0b3J5RnJvbVR5cGVNZXRhZGF0YS0tPj5vbmVUb09uZU9uVXBkYXRlOiBpbm5lclJlcG9cbiAqICAgICBvbmVUb09uZU9uVXBkYXRlLT4+aW5uZXJSZXBvOiByZWFkKHByb3BlcnR5VmFsdWUpXG4gKiAgICAgaW5uZXJSZXBvLS0+Pm9uZVRvT25lT25VcGRhdGU6IHJlYWRcbiAqICAgICBvbmVUb09uZU9uVXBkYXRlLT4+Y2FjaGVNb2RlbEZvclBvcHVsYXRlOiBjb250ZXh0LCBtb2RlbCwga2V5LCBwcm9wZXJ0eVZhbHVlLCByZWFkXG4gKiAgICAgb25lVG9PbmVPblVwZGF0ZS0+Pm9uZVRvT25lT25VcGRhdGU6IHNldCBtb2RlbFtrZXldID0gcHJvcGVydHlWYWx1ZVxuICogICBlbHNlIHByb3BlcnR5VmFsdWUgaXMgYW4gb2JqZWN0XG4gKiAgICAgb25lVG9PbmVPblVwZGF0ZS0+PmNyZWF0ZU9yVXBkYXRlOiBtb2RlbFtrZXldLCBjb250ZXh0XG4gKiAgICAgY3JlYXRlT3JVcGRhdGUtLT4+b25lVG9PbmVPblVwZGF0ZTogdXBkYXRlZFxuICogICAgIG9uZVRvT25lT25VcGRhdGUtPj5maW5kUHJpbWFyeUtleTogdXBkYXRlZFxuICogICAgIGZpbmRQcmltYXJ5S2V5LS0+Pm9uZVRvT25lT25VcGRhdGU6IHBrXG4gKiAgICAgb25lVG9PbmVPblVwZGF0ZS0+PmNhY2hlTW9kZWxGb3JQb3B1bGF0ZTogY29udGV4dCwgbW9kZWwsIGtleSwgdXBkYXRlZFtwa10sIHVwZGF0ZWRcbiAqICAgICBvbmVUb09uZU9uVXBkYXRlLT4+b25lVG9PbmVPblVwZGF0ZTogc2V0IG1vZGVsW2tleV0gPSB1cGRhdGVkW3BrXVxuICogICBlbmRcbiAqXG4gKiAgIG9uZVRvT25lT25VcGRhdGUtLT4+Q2FsbGVyOiB2b2lkXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBvbmVUb09uZU9uVXBkYXRlPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIFIgZXh0ZW5kcyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnk8TT4sXG4gIFYgZXh0ZW5kcyBSZWxhdGlvbnNNZXRhZGF0YSxcbj4oXG4gIHRoaXM6IFIsXG4gIGNvbnRleHQ6IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgZGF0YTogVixcbiAga2V5OiBrZXlvZiBNLFxuICBtb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHByb3BlcnR5VmFsdWU6IGFueSA9IG1vZGVsW2tleV07XG4gIGlmICghcHJvcGVydHlWYWx1ZSkgcmV0dXJuO1xuICBpZiAoZGF0YS5jYXNjYWRlLnVwZGF0ZSAhPT0gQ2FzY2FkZS5DQVNDQURFKSByZXR1cm47XG5cbiAgaWYgKHR5cGVvZiBwcm9wZXJ0eVZhbHVlICE9PSBcIm9iamVjdFwiKSB7XG4gICAgY29uc3QgaW5uZXJSZXBvID0gcmVwb3NpdG9yeUZyb21UeXBlTWV0YWRhdGEoXG4gICAgICBtb2RlbCxcbiAgICAgIGtleSxcbiAgICAgIHRoaXMuYWRhcHRlci5hbGlhc1xuICAgICk7XG4gICAgY29uc3QgcmVhZCA9IGF3YWl0IGlubmVyUmVwby5yZWFkKHByb3BlcnR5VmFsdWUsIGNvbnRleHQpO1xuICAgIGF3YWl0IGNhY2hlTW9kZWxGb3JQb3B1bGF0ZShjb250ZXh0LCBtb2RlbCwga2V5LCBwcm9wZXJ0eVZhbHVlLCByZWFkKTtcbiAgICAobW9kZWwgYXMgYW55KVtrZXldID0gcHJvcGVydHlWYWx1ZTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCB1cGRhdGVkOiBhbnkgPSBhd2FpdCBjcmVhdGVPclVwZGF0ZShcbiAgICBtb2RlbFtrZXldIGFzIE0sXG4gICAgY29udGV4dCxcbiAgICB0aGlzLmFkYXB0ZXIuYWxpYXNcbiAgKTtcbiAgY29uc3QgcGsgPSBNb2RlbC5wayh1cGRhdGVkKTtcbiAgYXdhaXQgY2FjaGVNb2RlbEZvclBvcHVsYXRlKFxuICAgIGNvbnRleHQsXG4gICAgbW9kZWwsXG4gICAga2V5LFxuICAgIHVwZGF0ZWRbcGtdIGFzIHN0cmluZyxcbiAgICB1cGRhdGVkXG4gICk7XG4gIG1vZGVsW2tleV0gPSB1cGRhdGVkW3BrXTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gSGFuZGxlcyBvbmUtdG8tb25lIHJlbGF0aW9uc2hpcCBkZWxldGlvblxuICogQHN1bW1hcnkgUHJvY2Vzc2VzIGEgb25lLXRvLW9uZSByZWxhdGlvbnNoaXAgd2hlbiBkZWxldGluZyBhIG1vZGVsLCBkZWxldGluZyB0aGUgcmVsYXRlZCBtb2RlbCBpZiBjYXNjYWRlIGlzIGVuYWJsZWRcbiAqIEB0ZW1wbGF0ZSBNIC0gVGhlIG1vZGVsIHR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAdGVtcGxhdGUgUiAtIFRoZSByZXBvc2l0b3J5IHR5cGUgZXh0ZW5kaW5nIFJlcG88TSwgRiwgQz5cbiAqIEB0ZW1wbGF0ZSBWIC0gVGhlIHJlbGF0aW9ucyBtZXRhZGF0YSB0eXBlIGV4dGVuZGluZyBSZWxhdGlvbnNNZXRhZGF0YVxuICogQHRlbXBsYXRlIEYgLSBUaGUgcmVwb3NpdG9yeSBmbGFncyB0eXBlXG4gKiBAdGVtcGxhdGUgQyAtIFRoZSBjb250ZXh0IHR5cGUgZXh0ZW5kaW5nIENvbnRleHQ8Rj5cbiAqIEBwYXJhbSB7Un0gdGhpcyAtIFRoZSByZXBvc2l0b3J5IGluc3RhbmNlXG4gKiBAcGFyYW0ge0NvbnRleHQ8Rj59IGNvbnRleHQgLSBUaGUgY29udGV4dCBmb3IgdGhlIG9wZXJhdGlvblxuICogQHBhcmFtIHtWfSBkYXRhIC0gVGhlIHJlbGF0aW9ucyBtZXRhZGF0YVxuICogQHBhcmFtIGtleSAtIFRoZSBwcm9wZXJ0eSBrZXkgb2YgdGhlIHJlbGF0aW9uc2hpcFxuICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZVxuICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgb3BlcmF0aW9uIGlzIGNvbXBsZXRlXG4gKiBAZnVuY3Rpb24gb25lVG9PbmVPbkRlbGV0ZVxuICogQG1lbWJlck9mIG1vZHVsZTpjb3JlXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICogICBwYXJ0aWNpcGFudCBvbmVUb09uZU9uRGVsZXRlXG4gKiAgIHBhcnRpY2lwYW50IHJlcG9zaXRvcnlGcm9tVHlwZU1ldGFkYXRhXG4gKiAgIHBhcnRpY2lwYW50IGNhY2hlTW9kZWxGb3JQb3B1bGF0ZVxuICpcbiAqICAgQ2FsbGVyLT4+b25lVG9PbmVPbkRlbGV0ZTogdGhpcywgY29udGV4dCwgZGF0YSwga2V5LCBtb2RlbFxuICogICBvbmVUb09uZU9uRGVsZXRlLT4+b25lVG9PbmVPbkRlbGV0ZTogY2hlY2sgaWYgcHJvcGVydHlWYWx1ZSBleGlzdHNcbiAqICAgb25lVG9PbmVPbkRlbGV0ZS0+Pm9uZVRvT25lT25EZWxldGU6IGNoZWNrIGlmIGNhc2NhZGUudXBkYXRlIGlzIENBU0NBREVcbiAqXG4gKiAgIG9uZVRvT25lT25EZWxldGUtPj5yZXBvc2l0b3J5RnJvbVR5cGVNZXRhZGF0YTogbW9kZWwsIGtleVxuICogICByZXBvc2l0b3J5RnJvbVR5cGVNZXRhZGF0YS0tPj5vbmVUb09uZU9uRGVsZXRlOiBpbm5lclJlcG9cbiAqXG4gKiAgIGFsdCBwcm9wZXJ0eVZhbHVlIGlzIG5vdCBhIE1vZGVsIGluc3RhbmNlXG4gKiAgICAgb25lVG9PbmVPbkRlbGV0ZS0+PmlubmVyUmVwbzogZGVsZXRlKG1vZGVsW2tleV0sIGNvbnRleHQpXG4gKiAgICAgaW5uZXJSZXBvLS0+Pm9uZVRvT25lT25EZWxldGU6IGRlbGV0ZWRcbiAqICAgZWxzZSBwcm9wZXJ0eVZhbHVlIGlzIGEgTW9kZWwgaW5zdGFuY2VcbiAqICAgICBvbmVUb09uZU9uRGVsZXRlLT4+aW5uZXJSZXBvOiBkZWxldGUobW9kZWxba2V5XVtpbm5lclJlcG8ucGtdLCBjb250ZXh0KVxuICogICAgIGlubmVyUmVwby0tPj5vbmVUb09uZU9uRGVsZXRlOiBkZWxldGVkXG4gKiAgIGVuZFxuICpcbiAqICAgb25lVG9PbmVPbkRlbGV0ZS0+PmNhY2hlTW9kZWxGb3JQb3B1bGF0ZTogY29udGV4dCwgbW9kZWwsIGtleSwgZGVsZXRlZFtpbm5lclJlcG8ucGtdLCBkZWxldGVkXG4gKiAgIG9uZVRvT25lT25EZWxldGUtLT4+Q2FsbGVyOiB2b2lkXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBvbmVUb09uZU9uRGVsZXRlPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIFIgZXh0ZW5kcyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnk8TT4sXG4gIFYgZXh0ZW5kcyBSZWxhdGlvbnNNZXRhZGF0YSxcbj4oXG4gIHRoaXM6IFIsXG4gIGNvbnRleHQ6IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgZGF0YTogVixcbiAga2V5OiBrZXlvZiBNLFxuICBtb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHByb3BlcnR5VmFsdWU6IGFueSA9IG1vZGVsW2tleV07XG4gIGlmICghcHJvcGVydHlWYWx1ZSkgcmV0dXJuO1xuICBpZiAoZGF0YS5jYXNjYWRlLnVwZGF0ZSAhPT0gQ2FzY2FkZS5DQVNDQURFKSByZXR1cm47XG4gIGNvbnN0IGlubmVyUmVwbzogUmVwbzxNPiA9IHJlcG9zaXRvcnlGcm9tVHlwZU1ldGFkYXRhKFxuICAgIG1vZGVsLFxuICAgIGtleSxcbiAgICB0aGlzLmFkYXB0ZXIuYWxpYXNcbiAgKTtcbiAgbGV0IGRlbGV0ZWQ6IE07XG4gIGlmICghKHByb3BlcnR5VmFsdWUgaW5zdGFuY2VvZiBNb2RlbCkpXG4gICAgZGVsZXRlZCA9IGF3YWl0IGlubmVyUmVwby5kZWxldGUobW9kZWxba2V5XSBhcyBzdHJpbmcsIGNvbnRleHQpO1xuICBlbHNlXG4gICAgZGVsZXRlZCA9IGF3YWl0IGlubmVyUmVwby5kZWxldGUoXG4gICAgICAobW9kZWxba2V5XSBhcyBNKVtNb2RlbC5wayhpbm5lclJlcG8uY2xhc3MpIGFzIGtleW9mIE1dIGFzIHN0cmluZyxcbiAgICAgIGNvbnRleHRcbiAgICApO1xuICBhd2FpdCBjYWNoZU1vZGVsRm9yUG9wdWxhdGUoXG4gICAgY29udGV4dCxcbiAgICBtb2RlbCxcbiAgICBrZXksXG4gICAgZGVsZXRlZFtNb2RlbC5wayhpbm5lclJlcG8uY2xhc3MpXSBhcyBzdHJpbmcsXG4gICAgZGVsZXRlZFxuICApO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBIYW5kbGVzIG9uZS10by1tYW55IHJlbGF0aW9uc2hpcCBjcmVhdGlvblxuICogQHN1bW1hcnkgUHJvY2Vzc2VzIGEgb25lLXRvLW1hbnkgcmVsYXRpb25zaGlwIHdoZW4gY3JlYXRpbmcgYSBtb2RlbCwgZWl0aGVyIGJ5IHJlZmVyZW5jaW5nIGV4aXN0aW5nIG1vZGVscyBvciBjcmVhdGluZyBuZXcgb25lc1xuICogQHRlbXBsYXRlIE0gLSBUaGUgbW9kZWwgdHlwZSBleHRlbmRpbmcgTW9kZWxcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHJlcG9zaXRvcnkgdHlwZSBleHRlbmRpbmcgUmVwbzxNLCBGLCBDPlxuICogQHRlbXBsYXRlIFYgLSBUaGUgcmVsYXRpb25zIG1ldGFkYXRhIHR5cGUgZXh0ZW5kaW5nIFJlbGF0aW9uc01ldGFkYXRhXG4gKiBAdGVtcGxhdGUgRiAtIFRoZSByZXBvc2l0b3J5IGZsYWdzIHR5cGVcbiAqIEB0ZW1wbGF0ZSBDIC0gVGhlIGNvbnRleHQgdHlwZSBleHRlbmRpbmcgQ29udGV4dDxGPlxuICogQHBhcmFtIHtSfSB0aGlzIC0gVGhlIHJlcG9zaXRvcnkgaW5zdGFuY2VcbiAqIEBwYXJhbSB7Q29udGV4dDxGPn0gY29udGV4dCAtIFRoZSBjb250ZXh0IGZvciB0aGUgb3BlcmF0aW9uXG4gKiBAcGFyYW0ge1Z9IGRhdGEgLSBUaGUgcmVsYXRpb25zIG1ldGFkYXRhXG4gKiBAcGFyYW0ga2V5IC0gVGhlIHByb3BlcnR5IGtleSBvZiB0aGUgcmVsYXRpb25zaGlwXG4gKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlXG4gKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBvcGVyYXRpb24gaXMgY29tcGxldGVcbiAqIEBmdW5jdGlvbiBvbmVUb01hbnlPbkNyZWF0ZVxuICogQG1lbWJlck9mIG1vZHVsZTpjb3JlXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICogICBwYXJ0aWNpcGFudCBvbmVUb01hbnlPbkNyZWF0ZVxuICogICBwYXJ0aWNpcGFudCByZXBvc2l0b3J5RnJvbVR5cGVNZXRhZGF0YVxuICogICBwYXJ0aWNpcGFudCBjcmVhdGVPclVwZGF0ZVxuICogICBwYXJ0aWNpcGFudCBmaW5kUHJpbWFyeUtleVxuICogICBwYXJ0aWNpcGFudCBjYWNoZU1vZGVsRm9yUG9wdWxhdGVcbiAqXG4gKiAgIENhbGxlci0+Pm9uZVRvTWFueU9uQ3JlYXRlOiB0aGlzLCBjb250ZXh0LCBkYXRhLCBrZXksIG1vZGVsXG4gKiAgIG9uZVRvTWFueU9uQ3JlYXRlLT4+b25lVG9NYW55T25DcmVhdGU6IGNoZWNrIGlmIHByb3BlcnR5VmFsdWVzIGV4aXN0cyBhbmQgaGFzIGxlbmd0aFxuICogICBvbmVUb01hbnlPbkNyZWF0ZS0+Pm9uZVRvTWFueU9uQ3JlYXRlOiBjaGVjayBpZiBhbGwgZWxlbWVudHMgaGF2ZSBzYW1lIHR5cGVcbiAqICAgb25lVG9NYW55T25DcmVhdGUtPj5vbmVUb01hbnlPbkNyZWF0ZTogY3JlYXRlIHVuaXF1ZVZhbHVlcyBzZXRcbiAqXG4gKiAgIGFsdCBhcnJheVR5cGUgaXMgbm90IFwib2JqZWN0XCJcbiAqICAgICBvbmVUb01hbnlPbkNyZWF0ZS0+PnJlcG9zaXRvcnlGcm9tVHlwZU1ldGFkYXRhOiBtb2RlbCwga2V5XG4gKiAgICAgcmVwb3NpdG9yeUZyb21UeXBlTWV0YWRhdGEtLT4+b25lVG9NYW55T25DcmVhdGU6IHJlcG9cbiAqICAgICBsb29wIGZvciBlYWNoIGlkIGluIHVuaXF1ZVZhbHVlc1xuICogICAgICAgb25lVG9NYW55T25DcmVhdGUtPj5yZXBvOiByZWFkKGlkKVxuICogICAgICAgcmVwby0tPj5vbmVUb01hbnlPbkNyZWF0ZTogcmVhZFxuICogICAgICAgb25lVG9NYW55T25DcmVhdGUtPj5jYWNoZU1vZGVsRm9yUG9wdWxhdGU6IGNvbnRleHQsIG1vZGVsLCBrZXksIGlkLCByZWFkXG4gKiAgICAgZW5kXG4gKiAgICAgb25lVG9NYW55T25DcmVhdGUtPj5vbmVUb01hbnlPbkNyZWF0ZTogc2V0IG1vZGVsW2tleV0gPSBbLi4udW5pcXVlVmFsdWVzXVxuICogICBlbHNlIGFycmF5VHlwZSBpcyBcIm9iamVjdFwiXG4gKiAgICAgb25lVG9NYW55T25DcmVhdGUtPj5maW5kUHJpbWFyeUtleTogcHJvcGVydHlWYWx1ZXNbMF1cbiAqICAgICBmaW5kUHJpbWFyeUtleS0tPj5vbmVUb01hbnlPbkNyZWF0ZTogcGtOYW1lXG4gKiAgICAgb25lVG9NYW55T25DcmVhdGUtPj5vbmVUb01hbnlPbkNyZWF0ZTogY3JlYXRlIHJlc3VsdCBzZXRcbiAqICAgICBsb29wIGZvciBlYWNoIG0gaW4gcHJvcGVydHlWYWx1ZXNcbiAqICAgICAgIG9uZVRvTWFueU9uQ3JlYXRlLT4+Y3JlYXRlT3JVcGRhdGU6IG0sIGNvbnRleHRcbiAqICAgICAgIGNyZWF0ZU9yVXBkYXRlLS0+Pm9uZVRvTWFueU9uQ3JlYXRlOiByZWNvcmRcbiAqICAgICAgIG9uZVRvTWFueU9uQ3JlYXRlLT4+Y2FjaGVNb2RlbEZvclBvcHVsYXRlOiBjb250ZXh0LCBtb2RlbCwga2V5LCByZWNvcmRbcGtOYW1lXSwgcmVjb3JkXG4gKiAgICAgICBvbmVUb01hbnlPbkNyZWF0ZS0+Pm9uZVRvTWFueU9uQ3JlYXRlOiBhZGQgcmVjb3JkW3BrTmFtZV0gdG8gcmVzdWx0XG4gKiAgICAgZW5kXG4gKiAgICAgb25lVG9NYW55T25DcmVhdGUtPj5vbmVUb01hbnlPbkNyZWF0ZTogc2V0IG1vZGVsW2tleV0gPSBbLi4ucmVzdWx0XVxuICogICBlbmRcbiAqXG4gKiAgIG9uZVRvTWFueU9uQ3JlYXRlLS0+PkNhbGxlcjogdm9pZFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gb25lVG9NYW55T25DcmVhdGU8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxNPixcbiAgViBleHRlbmRzIFJlbGF0aW9uc01ldGFkYXRhLFxuPihcbiAgdGhpczogUixcbiAgY29udGV4dDogRmFicmljQ29udHJhY3RDb250ZXh0LFxuICBkYXRhOiBWLFxuICBrZXk6IGtleW9mIE0sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgcHJvcGVydHlWYWx1ZXM6IGFueSA9IG1vZGVsW2tleV07XG4gIGlmICghcHJvcGVydHlWYWx1ZXMgfHwgIXByb3BlcnR5VmFsdWVzLmxlbmd0aCkgcmV0dXJuO1xuICBjb25zdCBhcnJheVR5cGUgPSB0eXBlb2YgcHJvcGVydHlWYWx1ZXNbMF07XG4gIGlmICghcHJvcGVydHlWYWx1ZXMuZXZlcnkoKGl0ZW06IGFueSkgPT4gdHlwZW9mIGl0ZW0gPT09IGFycmF5VHlwZSkpXG4gICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICBgSW52YWxpZCBvcGVyYXRpb24uIEFsbCBlbGVtZW50cyBvZiBwcm9wZXJ0eSAke2tleSBhcyBzdHJpbmd9IG11c3QgbWF0Y2ggdGhlIHNhbWUgdHlwZS5gXG4gICAgKTtcbiAgY29uc3QgdW5pcXVlVmFsdWVzID0gbmV3IFNldChbLi4ucHJvcGVydHlWYWx1ZXNdKTtcbiAgaWYgKGFycmF5VHlwZSAhPT0gXCJvYmplY3RcIikge1xuICAgIGNvbnN0IHJlcG8gPSByZXBvc2l0b3J5RnJvbVR5cGVNZXRhZGF0YShtb2RlbCwga2V5LCB0aGlzLmFkYXB0ZXIuYWxpYXMpO1xuICAgIGZvciAoY29uc3QgaWQgb2YgdW5pcXVlVmFsdWVzKSB7XG4gICAgICBjb25zdCByZWFkID0gYXdhaXQgcmVwby5yZWFkKGlkLCBjb250ZXh0KTtcbiAgICAgIGF3YWl0IGNhY2hlTW9kZWxGb3JQb3B1bGF0ZShjb250ZXh0LCBtb2RlbCwga2V5LCBpZCwgcmVhZCk7XG4gICAgfVxuICAgIChtb2RlbCBhcyBhbnkpW2tleV0gPSBbLi4udW5pcXVlVmFsdWVzXTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBwa05hbWUgPSBNb2RlbC5wayhwcm9wZXJ0eVZhbHVlc1swXSk7XG5cbiAgY29uc3QgcmVzdWx0OiBTZXQ8c3RyaW5nPiA9IG5ldyBTZXQoKTtcblxuICBmb3IgKGNvbnN0IG0gb2YgcHJvcGVydHlWYWx1ZXMpIHtcbiAgICBjb25zdCByZWNvcmQgPSBhd2FpdCBjcmVhdGVPclVwZGF0ZShtLCBjb250ZXh0LCB0aGlzLmFkYXB0ZXIuYWxpYXMpO1xuICAgIGF3YWl0IGNhY2hlTW9kZWxGb3JQb3B1bGF0ZShjb250ZXh0LCBtb2RlbCwga2V5LCByZWNvcmRbcGtOYW1lXSwgcmVjb3JkKTtcbiAgICByZXN1bHQuYWRkKHJlY29yZFtwa05hbWVdKTtcbiAgfVxuXG4gIChtb2RlbCBhcyBhbnkpW2tleV0gPSBbLi4ucmVzdWx0XTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gSGFuZGxlcyBvbmUtdG8tbWFueSByZWxhdGlvbnNoaXAgZGVsZXRpb25cbiAqIEBzdW1tYXJ5IFByb2Nlc3NlcyBhIG9uZS10by1tYW55IHJlbGF0aW9uc2hpcCB3aGVuIGRlbGV0aW5nIGEgbW9kZWwsIGRlbGV0aW5nIGFsbCByZWxhdGVkIG1vZGVscyBpZiBjYXNjYWRlIGRlbGV0ZSBpcyBlbmFibGVkXG4gKiBAdGVtcGxhdGUgTSAtIFRoZSBtb2RlbCB0eXBlIGV4dGVuZGluZyBNb2RlbFxuICogQHRlbXBsYXRlIFIgLSBUaGUgcmVwb3NpdG9yeSB0eXBlIGV4dGVuZGluZyBSZXBvPE0sIEYsIEM+XG4gKiBAdGVtcGxhdGUgViAtIFRoZSByZWxhdGlvbnMgbWV0YWRhdGEgdHlwZSBleHRlbmRpbmcgUmVsYXRpb25zTWV0YWRhdGFcbiAqIEB0ZW1wbGF0ZSBGIC0gVGhlIHJlcG9zaXRvcnkgZmxhZ3MgdHlwZVxuICogQHRlbXBsYXRlIEMgLSBUaGUgY29udGV4dCB0eXBlIGV4dGVuZGluZyBDb250ZXh0PEY+XG4gKiBAcGFyYW0ge1J9IHRoaXMgLSBUaGUgcmVwb3NpdG9yeSBpbnN0YW5jZVxuICogQHBhcmFtIHtDb250ZXh0PEY+fSBjb250ZXh0IC0gVGhlIGNvbnRleHQgZm9yIHRoZSBvcGVyYXRpb25cbiAqIEBwYXJhbSB7Vn0gZGF0YSAtIFRoZSByZWxhdGlvbnMgbWV0YWRhdGFcbiAqIEBwYXJhbSBrZXkgLSBUaGUgcHJvcGVydHkga2V5IG9mIHRoZSByZWxhdGlvbnNoaXBcbiAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2VcbiAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIG9wZXJhdGlvbiBpcyBjb21wbGV0ZVxuICogQGZ1bmN0aW9uIG9uZVRvTWFueU9uRGVsZXRlXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmNvcmVcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IG9uZVRvTWFueU9uRGVsZXRlXG4gKiAgIHBhcnRpY2lwYW50IFJlcG9zaXRvcnlcbiAqICAgcGFydGljaXBhbnQgcmVwb3NpdG9yeUZyb21UeXBlTWV0YWRhdGFcbiAqICAgcGFydGljaXBhbnQgY2FjaGVNb2RlbEZvclBvcHVsYXRlXG4gKlxuICogICBDYWxsZXItPj5vbmVUb01hbnlPbkRlbGV0ZTogdGhpcywgY29udGV4dCwgZGF0YSwga2V5LCBtb2RlbFxuICogICBvbmVUb01hbnlPbkRlbGV0ZS0+Pm9uZVRvTWFueU9uRGVsZXRlOiBjaGVjayBpZiBjYXNjYWRlLmRlbGV0ZSBpcyBDQVNDQURFXG4gKiAgIG9uZVRvTWFueU9uRGVsZXRlLT4+b25lVG9NYW55T25EZWxldGU6IGNoZWNrIGlmIHZhbHVlcyBleGlzdHMgYW5kIGhhcyBsZW5ndGhcbiAqICAgb25lVG9NYW55T25EZWxldGUtPj5vbmVUb01hbnlPbkRlbGV0ZTogY2hlY2sgaWYgYWxsIGVsZW1lbnRzIGhhdmUgc2FtZSB0eXBlXG4gKlxuICogICBhbHQgaXNJbnN0YW50aWF0ZWQgKGFycmF5VHlwZSBpcyBcIm9iamVjdFwiKVxuICogICAgIG9uZVRvTWFueU9uRGVsZXRlLT4+UmVwb3NpdG9yeTogZm9yTW9kZWwodmFsdWVzWzBdKVxuICogICAgIFJlcG9zaXRvcnktLT4+b25lVG9NYW55T25EZWxldGU6IHJlcG9cbiAqICAgZWxzZSBub3QgaW5zdGFudGlhdGVkXG4gKiAgICAgb25lVG9NYW55T25EZWxldGUtPj5yZXBvc2l0b3J5RnJvbVR5cGVNZXRhZGF0YTogbW9kZWwsIGtleVxuICogICAgIHJlcG9zaXRvcnlGcm9tVHlwZU1ldGFkYXRhLS0+Pm9uZVRvTWFueU9uRGVsZXRlOiByZXBvXG4gKiAgIGVuZFxuICpcbiAqICAgb25lVG9NYW55T25EZWxldGUtPj5vbmVUb01hbnlPbkRlbGV0ZTogY3JlYXRlIHVuaXF1ZVZhbHVlcyBzZXRcbiAqXG4gKiAgIGxvb3AgZm9yIGVhY2ggaWQgaW4gdW5pcXVlVmFsdWVzXG4gKiAgICAgb25lVG9NYW55T25EZWxldGUtPj5yZXBvOiBkZWxldGUoaWQsIGNvbnRleHQpXG4gKiAgICAgcmVwby0tPj5vbmVUb01hbnlPbkRlbGV0ZTogZGVsZXRlZFxuICogICAgIG9uZVRvTWFueU9uRGVsZXRlLT4+Y2FjaGVNb2RlbEZvclBvcHVsYXRlOiBjb250ZXh0LCBtb2RlbCwga2V5LCBpZCwgZGVsZXRlZFxuICogICBlbmRcbiAqXG4gKiAgIG9uZVRvTWFueU9uRGVsZXRlLT4+b25lVG9NYW55T25EZWxldGU6IHNldCBtb2RlbFtrZXldID0gWy4uLnVuaXF1ZVZhbHVlc11cbiAqICAgb25lVG9NYW55T25EZWxldGUtLT4+Q2FsbGVyOiB2b2lkXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBvbmVUb01hbnlPbkRlbGV0ZTxcbiAgTSBleHRlbmRzIE1vZGVsLFxuICBSIGV4dGVuZHMgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5PE0+LFxuICBWIGV4dGVuZHMgUmVsYXRpb25zTWV0YWRhdGEsXG4+KFxuICB0aGlzOiBSLFxuICBjb250ZXh0OiBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gIGRhdGE6IFYsXG4gIGtleToga2V5b2YgTSxcbiAgbW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge1xuICBpZiAoZGF0YS5jYXNjYWRlLmRlbGV0ZSAhPT0gQ2FzY2FkZS5DQVNDQURFKSByZXR1cm47XG4gIGNvbnN0IHZhbHVlcyA9IG1vZGVsW2tleV0gYXMgYW55O1xuICBpZiAoIXZhbHVlcyB8fCAhdmFsdWVzLmxlbmd0aCkgcmV0dXJuO1xuICBjb25zdCBhcnJheVR5cGUgPSB0eXBlb2YgdmFsdWVzWzBdO1xuICBjb25zdCBhcmVBbGxTYW1lVHlwZSA9IHZhbHVlcy5ldmVyeSgoaXRlbTogYW55KSA9PiB0eXBlb2YgaXRlbSA9PT0gYXJyYXlUeXBlKTtcbiAgaWYgKCFhcmVBbGxTYW1lVHlwZSlcbiAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgIGBJbnZhbGlkIG9wZXJhdGlvbi4gQWxsIGVsZW1lbnRzIG9mIHByb3BlcnR5ICR7a2V5IGFzIHN0cmluZ30gbXVzdCBtYXRjaCB0aGUgc2FtZSB0eXBlLmBcbiAgICApO1xuICBjb25zdCBpc0luc3RhbnRpYXRlZCA9IGFycmF5VHlwZSA9PT0gXCJvYmplY3RcIjtcbiAgY29uc3QgcmVwbyA9IGlzSW5zdGFudGlhdGVkXG4gICAgPyBSZXBvc2l0b3J5LmZvck1vZGVsKHZhbHVlc1swXSwgdGhpcy5hZGFwdGVyLmFsaWFzKVxuICAgIDogcmVwb3NpdG9yeUZyb21UeXBlTWV0YWRhdGEobW9kZWwsIGtleSwgdGhpcy5hZGFwdGVyLmFsaWFzKTtcblxuICBjb25zdCB1bmlxdWVWYWx1ZXMgPSBuZXcgU2V0KFtcbiAgICAuLi4oaXNJbnN0YW50aWF0ZWRcbiAgICAgID8gdmFsdWVzLm1hcChcbiAgICAgICAgICAodjogUmVjb3JkPHN0cmluZywgYW55PikgPT4gdltNb2RlbC5wayh0aGlzLmNsYXNzKSBhcyBzdHJpbmddXG4gICAgICAgIClcbiAgICAgIDogdmFsdWVzKSxcbiAgXSk7XG5cbiAgZm9yIChjb25zdCBpZCBvZiB1bmlxdWVWYWx1ZXMudmFsdWVzKCkpIHtcbiAgICBjb25zdCBkZWxldGVkID0gYXdhaXQgcmVwby5kZWxldGUoaWQsIGNvbnRleHQpO1xuICAgIGF3YWl0IGNhY2hlTW9kZWxGb3JQb3B1bGF0ZShjb250ZXh0LCBtb2RlbCwga2V5LCBpZCwgZGVsZXRlZCk7XG4gIH1cbiAgKG1vZGVsIGFzIGFueSlba2V5XSA9IFsuLi51bmlxdWVWYWx1ZXNdO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBQb3B1bGF0ZXMgYSBtb2RlbCdzIHJlbGF0aW9uc2hpcFxuICogQHN1bW1hcnkgUmV0cmlldmVzIGFuZCBhdHRhY2hlcyByZWxhdGVkIG1vZGVscyB0byBhIG1vZGVsJ3MgcmVsYXRpb25zaGlwIHByb3BlcnR5XG4gKiBAdGVtcGxhdGUgTSAtIFRoZSBtb2RlbCB0eXBlIGV4dGVuZGluZyBNb2RlbFxuICogQHRlbXBsYXRlIFIgLSBUaGUgcmVwb3NpdG9yeSB0eXBlIGV4dGVuZGluZyBSZXBvPE0sIEYsIEM+XG4gKiBAdGVtcGxhdGUgViAtIFRoZSByZWxhdGlvbnMgbWV0YWRhdGEgdHlwZSBleHRlbmRpbmcgUmVsYXRpb25zTWV0YWRhdGFcbiAqIEB0ZW1wbGF0ZSBGIC0gVGhlIHJlcG9zaXRvcnkgZmxhZ3MgdHlwZVxuICogQHRlbXBsYXRlIEMgLSBUaGUgY29udGV4dCB0eXBlIGV4dGVuZGluZyBDb250ZXh0PEY+XG4gKiBAcGFyYW0ge1J9IHRoaXMgLSBUaGUgcmVwb3NpdG9yeSBpbnN0YW5jZVxuICogQHBhcmFtIHtDb250ZXh0PEY+fSBjb250ZXh0IC0gVGhlIGNvbnRleHQgZm9yIHRoZSBvcGVyYXRpb25cbiAqIEBwYXJhbSB7Vn0gZGF0YSAtIFRoZSByZWxhdGlvbnMgbWV0YWRhdGFcbiAqIEBwYXJhbSBrZXkgLSBUaGUgcHJvcGVydHkga2V5IG9mIHRoZSByZWxhdGlvbnNoaXBcbiAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2VcbiAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIG9wZXJhdGlvbiBpcyBjb21wbGV0ZVxuICogQGZ1bmN0aW9uIHBvcHVsYXRlXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmNvcmVcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IHBvcHVsYXRlXG4gKiAgIHBhcnRpY2lwYW50IGZldGNoUG9wdWxhdGVWYWx1ZXNcbiAqICAgcGFydGljaXBhbnQgZ2V0UG9wdWxhdGVLZXlcbiAqICAgcGFydGljaXBhbnQgQ29udGV4dFxuICogICBwYXJ0aWNpcGFudCByZXBvc2l0b3J5RnJvbVR5cGVNZXRhZGF0YVxuICpcbiAqICAgQ2FsbGVyLT4+cG9wdWxhdGU6IHRoaXMsIGNvbnRleHQsIGRhdGEsIGtleSwgbW9kZWxcbiAqICAgcG9wdWxhdGUtPj5wb3B1bGF0ZTogY2hlY2sgaWYgZGF0YS5wb3B1bGF0ZSBpcyB0cnVlXG4gKiAgIHBvcHVsYXRlLT4+cG9wdWxhdGU6IGdldCBuZXN0ZWQgdmFsdWUgYW5kIGNoZWNrIGlmIGl0IGV4aXN0c1xuICpcbiAqICAgcG9wdWxhdGUtPj5mZXRjaFBvcHVsYXRlVmFsdWVzOiBjb250ZXh0LCBtb2RlbCwga2V5LCBpc0FyciA/IG5lc3RlZCA6IFtuZXN0ZWRdXG4gKlxuICogICBmZXRjaFBvcHVsYXRlVmFsdWVzLT4+ZmV0Y2hQb3B1bGF0ZVZhbHVlczogaW5pdGlhbGl6ZSB2YXJpYWJsZXNcbiAqXG4gKiAgIGxvb3AgZm9yIGVhY2ggcHJvS2V5VmFsdWUgaW4gcHJvcEtleVZhbHVlc1xuICogICAgIGZldGNoUG9wdWxhdGVWYWx1ZXMtPj5nZXRQb3B1bGF0ZUtleTogbW9kZWwuY29uc3RydWN0b3IubmFtZSwgcHJvcE5hbWUsIHByb0tleVZhbHVlXG4gKiAgICAgZ2V0UG9wdWxhdGVLZXktLT4+ZmV0Y2hQb3B1bGF0ZVZhbHVlczogY2FjaGVLZXlcbiAqXG4gKiAgICAgYWx0IHRyeSB0byBnZXQgZnJvbSBjYWNoZVxuICogICAgICAgZmV0Y2hQb3B1bGF0ZVZhbHVlcy0+PkNvbnRleHQ6IGdldChjYWNoZUtleSlcbiAqICAgICAgIENvbnRleHQtLT4+ZmV0Y2hQb3B1bGF0ZVZhbHVlczogdmFsXG4gKiAgICAgZWxzZSBjYXRjaCBlcnJvclxuICogICAgICAgZmV0Y2hQb3B1bGF0ZVZhbHVlcy0+PnJlcG9zaXRvcnlGcm9tVHlwZU1ldGFkYXRhOiBtb2RlbCwgcHJvcE5hbWVcbiAqICAgICAgIHJlcG9zaXRvcnlGcm9tVHlwZU1ldGFkYXRhLS0+PmZldGNoUG9wdWxhdGVWYWx1ZXM6IHJlcG9cbiAqICAgICAgIGZldGNoUG9wdWxhdGVWYWx1ZXMtPj5yZXBvOiByZWFkKHByb0tleVZhbHVlKVxuICogICAgICAgcmVwby0tPj5mZXRjaFBvcHVsYXRlVmFsdWVzOiB2YWxcbiAqICAgICBlbmRcbiAqXG4gKiAgICAgZmV0Y2hQb3B1bGF0ZVZhbHVlcy0+PmZldGNoUG9wdWxhdGVWYWx1ZXM6IGFkZCB2YWwgdG8gcmVzdWx0c1xuICogICBlbmRcbiAqXG4gKiAgIGZldGNoUG9wdWxhdGVWYWx1ZXMtLT4+cG9wdWxhdGU6IHJlc3VsdHNcbiAqICAgcG9wdWxhdGUtPj5wb3B1bGF0ZTogc2V0IG1vZGVsW2tleV0gPSBpc0FyciA/IHJlcyA6IHJlc1swXVxuICogICBwb3B1bGF0ZS0tPj5DYWxsZXI6IHZvaWRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvcHVsYXRlPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIFIgZXh0ZW5kcyBSZXBvPE0+LFxuICBWIGV4dGVuZHMgUmVsYXRpb25zTWV0YWRhdGEsXG4+KFxuICB0aGlzOiBSLFxuICBjb250ZXh0OiBDb250ZXh0T2ZSZXBvc2l0b3J5PFI+LFxuICBkYXRhOiBWLFxuICBrZXk6IGtleW9mIE0sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKCFkYXRhLnBvcHVsYXRlKSByZXR1cm47XG4gIGNvbnN0IG5lc3RlZDogYW55ID0gbW9kZWxba2V5XTtcbiAgY29uc3QgaXNBcnIgPSBBcnJheS5pc0FycmF5KG5lc3RlZCk7XG4gIGlmICh0eXBlb2YgbmVzdGVkID09PSBcInVuZGVmaW5lZFwiIHx8IChpc0FyciAmJiBuZXN0ZWQubGVuZ3RoID09PSAwKSkgcmV0dXJuO1xuXG4gIGFzeW5jIGZ1bmN0aW9uIGZldGNoUG9wdWxhdGVWYWx1ZXMoXG4gICAgYzogQ29udGV4dE9mUmVwb3NpdG9yeTxSPixcbiAgICBtb2RlbDogTSxcbiAgICBwcm9wTmFtZTogc3RyaW5nLFxuICAgIHByb3BLZXlWYWx1ZXM6IGFueVtdLFxuICAgIGFsaWFzPzogc3RyaW5nXG4gICkge1xuICAgIGxldCBjYWNoZUtleTogc3RyaW5nO1xuICAgIGxldCB2YWw6IGFueTtcbiAgICBjb25zdCByZXN1bHRzOiBNW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IHByb0tleVZhbHVlIG9mIHByb3BLZXlWYWx1ZXMpIHtcbiAgICAgIGNhY2hlS2V5ID0gZ2V0UG9wdWxhdGVLZXkobW9kZWwuY29uc3RydWN0b3IubmFtZSwgcHJvcE5hbWUsIHByb0tleVZhbHVlKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIHZhbCA9IGF3YWl0IGMuZ2V0KGNhY2hlS2V5IGFzIGFueSk7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICBjb25zdCByZXBvID0gcmVwb3NpdG9yeUZyb21UeXBlTWV0YWRhdGEoXG4gICAgICAgICAgbW9kZWwsXG4gICAgICAgICAgcHJvcE5hbWUgYXMga2V5b2YgTSxcbiAgICAgICAgICBhbGlhc1xuICAgICAgICApO1xuICAgICAgICBpZiAoIXJlcG8pIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiQ291bGQgbm90IGZpbmQgcmVwb1wiKTtcbiAgICAgICAgdmFsID0gYXdhaXQgcmVwby5yZWFkKHByb0tleVZhbHVlLCBjb250ZXh0KTtcbiAgICAgIH1cbiAgICAgIHJlc3VsdHMucHVzaCh2YWwpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfVxuICBjb25zdCByZXMgPSBhd2FpdCBmZXRjaFBvcHVsYXRlVmFsdWVzKFxuICAgIGNvbnRleHQsXG4gICAgbW9kZWwsXG4gICAga2V5IGFzIHN0cmluZyxcbiAgICBpc0FyciA/IG5lc3RlZCA6IFtuZXN0ZWRdLFxuICAgIHRoaXMuYWRhcHRlci5hbGlhc1xuICApO1xuICAobW9kZWwgYXMgYW55KVtrZXldID0gaXNBcnIgPyByZXMgOiByZXNbMF07XG59XG4iLCJpbXBvcnQge1xuICBMb2dnZXJGYWN0b3J5LFxuICBMb2dnaW5nLFxuICBMb2dnZXIsXG4gIExvZ0xldmVsLFxuICBNaW5pTG9nZ2VyLFxuICBOdW1lcmljTG9nTGV2ZWxzLFxuICBTdHJpbmdMaWtlLFxufSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7IExvZ2dpbmdDb25maWcgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7IENvbnRleHQgYXMgQ3R4IH0gZnJvbSBcImZhYnJpYy1jb250cmFjdC1hcGlcIjtcbmltcG9ydCB7IEludGVybmFsRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gTG9nZ2VyIGltcGxlbWVudGF0aW9uIGZvciBGYWJyaWMgY2hhaW5jb2RlIGNvbnRyYWN0c1xuICogQHN1bW1hcnkgQWRhcHRzIHRoZSBzdGFuZGFyZCBsb2dnaW5nIGludGVyZmFjZSB0byB3b3JrIHdpdGggRmFicmljJ3MgY2hhaW5jb2RlIGNvbnRleHRcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gY29udGV4dCAtIFRoZSBsb2dnaW5nIGNvbnRleHQgbmFtZVxuICogQHBhcmFtIHtQYXJ0aWFsPExvZ2dpbmdDb25maWc+IHwgdW5kZWZpbmVkfSBjb25mIC0gT3B0aW9uYWwgbG9nZ2luZyBjb25maWd1cmF0aW9uXG4gKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICpcbiAqIEBjbGFzcyBDb250cmFjdExvZ2dlclxuICogQGV4dGVuZHMge01pbmlMb2dnZXJ9XG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gSW4gYSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRyYWN0XG4gKiBpbXBvcnQgeyBDb250cmFjdExvZ2dlciB9IGZyb20gJ0BkZWNhZi10cy9mb3ItZmFicmljJztcbiAqXG4gKiBleHBvcnQgY2xhc3MgTXlDb250cmFjdCBleHRlbmRzIENvbnRyYWN0IHtcbiAqICAgQFRyYW5zYWN0aW9uKClcbiAqICAgYXN5bmMgbXlGdW5jdGlvbihjdHg6IENvbnRleHQpOiBQcm9taXNlPHZvaWQ+IHtcbiAqICAgICBjb25zdCBsb2dnZXIgPSBuZXcgQ29udHJhY3RMb2dnZXIoJ015Q29udHJhY3QnLCB7IGxldmVsOiAnaW5mbycgfSwgY3R4KTtcbiAqXG4gKiAgICAgbG9nZ2VyLmluZm8oJ1Byb2Nlc3NpbmcgdHJhbnNhY3Rpb24nKTtcbiAqICAgICBsb2dnZXIuZGVidWcoJ1RyYW5zYWN0aW9uIGRldGFpbHM6JywgeyAuLi4gfSk7XG4gKlxuICogICAgIC8vIERvIHNvbWV0aGluZ1xuICpcbiAqICAgICBsb2dnZXIuaW5mbygnVHJhbnNhY3Rpb24gY29tcGxldGUnKTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBDb250cmFjdExvZ2dlciBleHRlbmRzIE1pbmlMb2dnZXIge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRoZSB1bmRlcmx5aW5nIEZhYnJpYyBsb2dnZXIgaW5zdGFuY2VcbiAgICovXG4gIHByb3RlY3RlZCBsb2dnZXIhOiBMb2dnZXI7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgY29udGV4dDogc3RyaW5nLFxuICAgIGNvbmY6IFBhcnRpYWw8TG9nZ2luZ0NvbmZpZz4gfCB1bmRlZmluZWQsXG4gICAgY3R4PzogQ3R4XG4gICkge1xuICAgIHN1cGVyKGNvbnRleHQsIGNvbmYpO1xuXG4gICAgaWYgKCFjdHgpIHtcbiAgICAgIHRoaXMubG9nZ2VyID0gbmV3IE1pbmlMb2dnZXIoY29udGV4dCwgY29uZik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubG9nZ2VyID0gY3R4LmxvZ2dpbmcuZ2V0TG9nZ2VyKGNvbnRleHQpIGFzIHVua25vd24gYXMgTG9nZ2VyO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gTG9ncyBhIG1lc3NhZ2UgYXQgdGhlIHNwZWNpZmllZCBsZXZlbFxuICAgKiBAc3VtbWFyeSBPdmVycmlkZXMgdGhlIGJhc2UgbG9nIG1ldGhvZCB0byB1c2UgdGhlIEZhYnJpYyBjb250ZXh0J3MgbG9nZ2VyXG4gICAqIEBwYXJhbSB7TG9nTGV2ZWx9IGxldmVsIC0gVGhlIGxvZyBsZXZlbFxuICAgKiBAcGFyYW0ge1N0cmluZ0xpa2UgfCBFcnJvcn0gbXNnIC0gVGhlIG1lc3NhZ2UgdG8gbG9nXG4gICAqIEBwYXJhbSB7RXJyb3J9IFtzdGFja10gLSBPcHRpb25hbCBzdGFjayB0cmFjZSBmb3IgZXJyb3JzXG4gICAqIEByZXR1cm4ge3ZvaWR9XG4gICAqL1xuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgbG9nKFxuICAgIGxldmVsOiBMb2dMZXZlbCxcbiAgICBtc2c6IFN0cmluZ0xpa2UgfCBFcnJvcixcbiAgICBzdGFjaz86IEVycm9yXG4gICkge1xuICAgIGlmIChcbiAgICAgIE51bWVyaWNMb2dMZXZlbHNbdGhpcy5jb25maWcoXCJsZXZlbFwiKSBhcyBMb2dMZXZlbF0gPFxuICAgICAgTnVtZXJpY0xvZ0xldmVsc1tsZXZlbF1cbiAgICApXG4gICAgICByZXR1cm47XG5cbiAgICBsZXQgbWV0aG9kO1xuICAgIHN3aXRjaCAobGV2ZWwpIHtcbiAgICAgIGNhc2UgTG9nTGV2ZWwuaW5mbzpcbiAgICAgICAgbWV0aG9kID0gdGhpcy5sb2dnZXIuaW5mbztcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIExvZ0xldmVsLnZlcmJvc2U6XG4gICAgICAgIG1ldGhvZCA9IHRoaXMubG9nZ2VyLnZlcmJvc2U7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBMb2dMZXZlbC5kZWJ1ZzpcbiAgICAgICAgbWV0aG9kID0gdGhpcy5sb2dnZXIuZGVidWc7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBMb2dMZXZlbC5lcnJvcjpcbiAgICAgICAgbWV0aG9kID0gdGhpcy5sb2dnZXIuZXJyb3I7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBMb2dMZXZlbC5zaWxseTpcbiAgICAgICAgbWV0aG9kID0gdGhpcy5sb2dnZXIuc2lsbHk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJJbnZhbGlkIGxvZyBsZXZlbFwiKTtcbiAgICB9XG4gICAgbWV0aG9kLmNhbGwodGhpcy5sb2dnZXIsIHRoaXMuY3JlYXRlTG9nKGxldmVsLCBtc2csIHN0YWNrKSk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRmFjdG9yeSBmdW5jdGlvbiBmb3IgY3JlYXRpbmcgQ29udHJhY3RMb2dnZXIgaW5zdGFuY2VzXG4gKiBAc3VtbWFyeSBDcmVhdGVzIGEgbmV3IENvbnRyYWN0TG9nZ2VyIHdpdGggdGhlIGdpdmVuIGNvbnRleHQsIGNvbmZpZywgYW5kIEZhYnJpYyBjb250ZXh0XG4gKiBAcGFyYW0ge3N0cmluZ30gb2JqZWN0IC0gVGhlIGxvZ2dpbmcgY29udGV4dCBuYW1lXG4gKiBAcGFyYW0ge1BhcnRpYWw8TG9nZ2luZ0NvbmZpZz4gfCB1bmRlZmluZWR9IGNvbmZpZyAtIE9wdGlvbmFsIGxvZ2dpbmcgY29uZmlndXJhdGlvblxuICogQHBhcmFtIHtDdHh9IGN0eCAtIFRoZSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRleHRcbiAqIEByZXR1cm4ge0NvbnRyYWN0TG9nZ2VyfSBBIG5ldyBDb250cmFjdExvZ2dlciBpbnN0YW5jZVxuICogQGZ1bmN0aW9uIGZhY3RvcnlcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZmFicmljLmNvbnRyYWN0c1xuICovXG5jb25zdCBmYWN0b3J5OiBMb2dnZXJGYWN0b3J5ID0gKFxuICBvYmplY3Q/OiBzdHJpbmcsXG4gIGNvbmZpZz86IFBhcnRpYWw8TG9nZ2luZ0NvbmZpZz4sXG4gIGN0eD86IEN0eFxuKSA9PiB7XG4gIHJldHVybiBuZXcgQ29udHJhY3RMb2dnZXIoXG4gICAgb2JqZWN0IHx8IENvbnRyYWN0TG9nZ2VyLm5hbWUsXG4gICAgY29uZmlnIHx8IHt9LFxuICAgIGN0eCBhcyBDdHhcbiAgKTtcbn07XG5cbi8vIFNldCB0aGUgZmFjdG9yeSBhcyB0aGUgZGVmYXVsdCBsb2dnZXIgZmFjdG9yeVxuTG9nZ2luZy5zZXRGYWN0b3J5KGZhY3RvcnkpO1xuIiwiaW1wb3J0IHsgQ291Y2hEQkFkYXB0ZXIsIENvdWNoREJLZXlzLCBNYW5nb1F1ZXJ5IH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItY291Y2hkYlwiO1xuaW1wb3J0IHsgbGlzdCwgTW9kZWwsIHJlcXVpcmVkLCB0eXBlIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RGbGFncyB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdENvbnRleHQgfSBmcm9tIFwiLi9Db250cmFjdENvbnRleHRcIjtcbmltcG9ydCB7XG4gIGFmdGVyQW55LFxuICBCYWRSZXF1ZXN0RXJyb3IsXG4gIEJhc2VFcnJvcixcbiAgQ29uZmxpY3RFcnJvcixcbiAgREJLZXlzLFxuICBHcm91cFNvcnQsXG4gIEludGVybmFsRXJyb3IsXG4gIE5vdEZvdW5kRXJyb3IsXG4gIG9uQ3JlYXRlLFxuICBvbkNyZWF0ZVVwZGF0ZSxcbiAgb25EZWxldGUsXG4gIG9uVXBkYXRlLFxuICBPcGVyYXRpb25LZXlzLFxuICBQcmltYXJ5S2V5VHlwZSxcbiAgcmVhZG9ubHksXG4gIFNlcmlhbGl6YXRpb25FcnJvcixcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQge1xuICBDb250ZXh0IGFzIEN0eCxcbiAgT2JqZWN0IGFzIEZhYnJpY09iamVjdCxcbiAgUHJvcGVydHkgYXMgRmFicmljUHJvcGVydHksXG59IGZyb20gXCJmYWJyaWMtY29udHJhY3QtYXBpXCI7XG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7XG4gIFBlcnNpc3RlbmNlS2V5cyxcbiAgUmVsYXRpb25zTWV0YWRhdGEsXG4gIFNlcXVlbmNlLFxuICBTZXF1ZW5jZU9wdGlvbnMsXG4gIFVuc3VwcG9ydGVkRXJyb3IsXG4gIEFkYXB0ZXIsXG4gIENhc2NhZGVNZXRhZGF0YSxcbiAgSm9pbkNvbHVtbk9wdGlvbnMsXG4gIG9uZVRvTWFueU9uVXBkYXRlLFxuICBKb2luVGFibGVPcHRpb25zLFxuICBKb2luVGFibGVNdWx0aXBsZUNvbHVtbnNPcHRpb25zLFxuICByZWxhdGlvbixcbiAgUHJlcGFyZWRNb2RlbCxcbiAgUmVwb3NpdG9yeSxcbiAgUXVlcnlFcnJvcixcbiAgUGFnaW5nRXJyb3IsXG4gIE1pZ3JhdGlvbkVycm9yLFxuICBPYnNlcnZlckVycm9yLFxuICBBdXRob3JpemF0aW9uRXJyb3IsXG4gIEZvcmJpZGRlbkVycm9yLFxuICBDb25uZWN0aW9uRXJyb3IsXG4gIENvbnRleHR1YWxpemVkQXJncyxcbiAgTG9nZ2VyT2YsXG4gIENvbnRleHQsXG4gIFJhd1Jlc3VsdCxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgdHlwZSB7IENvbnRleHR1YWxBcmdzLCBNYXliZUNvbnRleHR1YWxBcmcgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeSB9IGZyb20gXCIuL0ZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeVwiO1xuaW1wb3J0IHtcbiAgQ2hhaW5jb2RlU3R1YixcbiAgQ2xpZW50SWRlbnRpdHksXG4gIEl0ZXJhdG9ycyxcbiAgU3RhdGVRdWVyeVJlc3BvbnNlLFxufSBmcm9tIFwiZmFicmljLXNoaW0tYXBpXCI7XG5pbXBvcnQgeyBGYWJyaWNTdGF0ZW1lbnQgfSBmcm9tIFwiLi9GYWJyaWNDb250cmFjdFN0YXRlbWVudFwiO1xuaW1wb3J0IHsgRmFicmljRmxhdm91ciB9IGZyb20gXCIuLi9zaGFyZWQvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBTaW1wbGVEZXRlcm1pbmlzdGljU2VyaWFsaXplciB9IGZyb20gXCIuLi9zaGFyZWQvU2ltcGxlRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXJcIjtcbmltcG9ydCB7XG4gIG9uZVRvTWFueU9uQ3JlYXRlLFxuICBvbmVUb01hbnlPbkRlbGV0ZSxcbiAgb25lVG9PbmVPbkNyZWF0ZSxcbiAgb25lVG9PbmVPbkRlbGV0ZSxcbiAgb25lVG9PbmVPblVwZGF0ZSxcbiAgcG9wdWxhdGUgYXMgcG9wLFxufSBmcm9tIFwiLi9GYWJyaWNDb25zdHJ1Y3Rpb25cIjtcbmltcG9ydCB7XG4gIGFwcGx5LFxuICBDb25zdHJ1Y3RvcixcbiAgRGVjb3JhdGlvbixcbiAgcHJvcCxcbiAgcHJvcE1ldGFkYXRhLFxuICBNZXRhZGF0YSxcbn0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBDb250cmFjdExvZ2dlciB9IGZyb20gXCIuL2xvZ2dpbmdcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gU2V0cyB0aGUgY3JlYXRvciBvciB1cGRhdGVyIGZpZWxkIGluIGEgbW9kZWwgYmFzZWQgb24gdGhlIHVzZXIgaW4gdGhlIGNvbnRleHRcbiAqIEBzdW1tYXJ5IENhbGxiYWNrIGZ1bmN0aW9uIHVzZWQgaW4gZGVjb3JhdG9ycyB0byBhdXRvbWF0aWNhbGx5IHNldCB0aGUgY3JlYXRlZF9ieSBvciB1cGRhdGVkX2J5IGZpZWxkc1xuICogd2l0aCB0aGUgdXNlcm5hbWUgZnJvbSB0aGUgY29udGV4dCB3aGVuIGEgZG9jdW1lbnQgaXMgY3JlYXRlZCBvciB1cGRhdGVkXG4gKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAdGVtcGxhdGUgUiAtIFR5cGUgZXh0ZW5kaW5nIE5hbm9SZXBvc2l0b3J5PE0+XG4gKiBAdGVtcGxhdGUgViAtIFR5cGUgZXh0ZW5kaW5nIFJlbGF0aW9uc01ldGFkYXRhXG4gKiBAcGFyYW0ge1J9IHRoaXMgLSBUaGUgcmVwb3NpdG9yeSBpbnN0YW5jZVxuICogQHBhcmFtIHtGYWJyaWNDb250cmFjdENvbnRleHR9IGNvbnRleHQgLSBUaGUgb3BlcmF0aW9uIGNvbnRleHQgY29udGFpbmluZyB1c2VyIGluZm9ybWF0aW9uXG4gKiBAcGFyYW0ge1Z9IGRhdGEgLSBUaGUgcmVsYXRpb24gbWV0YWRhdGFcbiAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgLSBUaGUgcHJvcGVydHkga2V5IHRvIHNldCB3aXRoIHRoZSB1c2VybmFtZVxuICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZSBiZWluZyBjcmVhdGVkIG9yIHVwZGF0ZWRcbiAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIG9wZXJhdGlvbiBpcyBjb21wbGV0ZVxuICogQGZ1bmN0aW9uIGNyZWF0ZWRCeU9uRmFicmljQ3JlYXRlVXBkYXRlXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZhYnJpYy5jb250cmFjdHNcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgRiBhcyBjcmVhdGVkQnlPbk5hbm9DcmVhdGVVcGRhdGVcbiAqICAgcGFydGljaXBhbnQgQyBhcyBDb250ZXh0XG4gKiAgIHBhcnRpY2lwYW50IE0gYXMgTW9kZWxcbiAqICAgRi0+PkM6IGdldChcInVzZXJcIilcbiAqICAgQy0tPj5GOiB1c2VyIG9iamVjdFxuICogICBGLT4+TTogc2V0IGtleSB0byB1c2VyLm5hbWVcbiAqICAgTm90ZSBvdmVyIEY6IElmIG5vIHVzZXIgaW4gY29udGV4dFxuICogICBGLS0+PkY6IHRocm93IFVuc3VwcG9ydGVkRXJyb3JcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZWRCeU9uRmFicmljQ3JlYXRlVXBkYXRlPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIFIgZXh0ZW5kcyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnk8TT4sXG4gIFYgZXh0ZW5kcyBSZWxhdGlvbnNNZXRhZGF0YSxcbj4oXG4gIHRoaXM6IFIsXG4gIGNvbnRleHQ6IENvbnRleHQ8RmFicmljQ29udHJhY3RGbGFncz4sXG4gIGRhdGE6IFYsXG4gIGtleToga2V5b2YgTSxcbiAgbW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHVzZXIgPSBjb250ZXh0LmdldChcImlkZW50aXR5XCIpIGFzIENsaWVudElkZW50aXR5O1xuICAgIG1vZGVsW2tleV0gPSB1c2VyLmdldElEKCkgYXMgTVt0eXBlb2Yga2V5XTtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICB0aHJvdyBuZXcgVW5zdXBwb3J0ZWRFcnJvcihcbiAgICAgIFwiTm8gVXNlciBmb3VuZCBpbiBjb250ZXh0LiBQbGVhc2UgcHJvdmlkZSBhIHVzZXIgaW4gdGhlIGNvbnRleHRcIlxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUHJpbWFyeSBrZXkgYXV0by1hc3NpZ25tZW50IGNhbGxiYWNrIGZvciBGYWJyaWMgbW9kZWxzXG4gKiBAc3VtbWFyeSBHZW5lcmF0ZXMgYW5kIGFzc2lnbnMgYSBwcmltYXJ5IGtleSB2YWx1ZSB0byB0aGUgc3BlY2lmaWVkIG1vZGVsIHByb3BlcnR5IHVzaW5nIGEgRmFicmljLWJhY2tlZCBzZXF1ZW5jZSB3aGVuIHRoZSBtb2RlbCBpcyBjcmVhdGVkLiBJZiB0aGUgc2VxdWVuY2UgbmFtZSBpcyBub3QgcHJvdmlkZWQgaW4gb3B0aW9ucywgaXQgaXMgZGVyaXZlZCBmcm9tIHRoZSBtb2RlbCB2aWEgc2VxdWVuY2VOYW1lRm9yTW9kZWwuIFRoZSBhc3NpZ25lZCBrZXkgaXMgZGVmaW5lZCBhcyBub24td3JpdGFibGUgYW5kIGVudW1lcmFibGUuXG4gKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsIGZvciB0aGUgdGFyZ2V0IGluc3RhbmNlXG4gKiBAdGVtcGxhdGUgUiAtIFR5cGUgZXh0ZW5kaW5nIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeSBmb3IgcmVwb3NpdG9yeSBjb250ZXh0XG4gKiBAdGVtcGxhdGUgViAtIFR5cGUgZXh0ZW5kaW5nIFNlcXVlbmNlT3B0aW9ucyB0byBjb25maWd1cmUgc2VxdWVuY2UgYmVoYXZpb3JcbiAqIEB0ZW1wbGF0ZSBGIC0gVHlwZSBleHRlbmRpbmcgRmFicmljQ29udHJhY3RGbGFncyBmb3IgY29udGV4dHVhbCBmbGFnc1xuICogQHBhcmFtIHtSfSB0aGlzIC0gVGhlIHJlcG9zaXRvcnkgaW5zdGFuY2UgaW52b2tpbmcgdGhlIGNhbGxiYWNrXG4gKiBAcGFyYW0ge0ZhYnJpY0NvbnRyYWN0Q29udGV4dH0gY29udGV4dCAtIEZhYnJpYyBjb250cmFjdCBjb250ZXh0IGNvbnRhaW5pbmcgaW52b2NhdGlvbiBtZXRhZGF0YVxuICogQHBhcmFtIHtWfSBkYXRhIC0gU2VxdWVuY2Ugb3B0aW9ucyB1c2VkIHRvIGNvbmZpZ3VyZSBvciBsb2NhdGUgdGhlIHNlcXVlbmNlXG4gKiBAcGFyYW0ge3N0cmluZ30ga2V5IC0gVGhlIHByaW1hcnkga2V5IHByb3BlcnR5IG5hbWUgdG8gYXNzaWduIG9uIHRoZSBtb2RlbFxuICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZSB0byByZWNlaXZlIHRoZSBnZW5lcmF0ZWQgcHJpbWFyeSBrZXlcbiAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFJlc29sdmVzIHdoZW4gdGhlIGtleSBpcyBhc3NpZ25lZCBvciB3aGVuIG5vIGFjdGlvbiBpcyByZXF1aXJlZFxuICogQGZ1bmN0aW9uIHBrRmFicmljT25DcmVhdGVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5jb250cmFjdHNcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgUiBhcyBSZXBvc2l0b3J5XG4gKiAgIHBhcnRpY2lwYW50IEMgYXMgQ29udGV4dDxGPlxuICogICBwYXJ0aWNpcGFudCBTIGFzIEZhYnJpY0NvbnRyYWN0REJTZXF1ZW5jZVxuICogICBwYXJ0aWNpcGFudCBNIGFzIE1vZGVsXG4gKiAgIFItPj5SOiBkZXJpdmUgc2VxdWVuY2UgbmFtZSBpZiBtaXNzaW5nXG4gKiAgIFItPj5TOiBhZGFwdGVyLlNlcXVlbmNlKG9wdGlvbnMpXG4gKiAgIFMtLT4+Ujogc2VxdWVuY2UgaW5zdGFuY2VcbiAqICAgUi0+PlM6IG5leHQoY29udGV4dClcbiAqICAgUy0tPj5SOiBuZXh0IHZhbHVlXG4gKiAgIFItPj5NOiBkZWZpbmUgbm9uLXdyaXRhYmxlIHByaW1hcnkga2V5XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwa0ZhYnJpY09uQ3JlYXRlPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIFIgZXh0ZW5kcyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnk8TT4sXG4+KFxuICB0aGlzOiBSLFxuICBjb250ZXh0OiBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gIGRhdGE6IFNlcXVlbmNlT3B0aW9ucyxcbiAga2V5OiBrZXlvZiBNLFxuICBtb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmICghZGF0YS50eXBlIHx8IG1vZGVsW2tleV0pIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBzZXRQcmltYXJ5S2V5VmFsdWUgPSBmdW5jdGlvbiA8TSBleHRlbmRzIE1vZGVsPihcbiAgICB0YXJnZXQ6IE0sXG4gICAgcHJvcGVydHlLZXk6IHN0cmluZyxcbiAgICB2YWx1ZTogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50XG4gICkge1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIHByb3BlcnR5S2V5LCB7XG4gICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgdmFsdWU6IHZhbHVlLFxuICAgIH0pO1xuICB9O1xuICBpZiAoIWRhdGEubmFtZSkgZGF0YS5uYW1lID0gTW9kZWwuc2VxdWVuY2VOYW1lKG1vZGVsLCBcInBrXCIpO1xuICBsZXQgc2VxdWVuY2U6IFNlcXVlbmNlO1xuICB0cnkge1xuICAgIHNlcXVlbmNlID0gKGF3YWl0IHRoaXMuYWRhcHRlci5TZXF1ZW5jZShkYXRhKSkgYXMgU2VxdWVuY2U7XG4gIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgYEZhaWxlZCB0byBpbnN0YW50aWF0ZSBTZXF1ZW5jZSAke2RhdGEubmFtZX06ICR7ZX1gXG4gICAgKTtcbiAgfVxuXG4gIGNvbnN0IG5leHQgPSBhd2FpdCBzZXF1ZW5jZS5uZXh0KGNvbnRleHQgYXMgRmFicmljQ29udHJhY3RDb250ZXh0KTtcbiAgc2V0UHJpbWFyeUtleVZhbHVlKG1vZGVsLCBrZXkgYXMgc3RyaW5nLCBuZXh0KTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQWRhcHRlciBmb3IgSHlwZXJsZWRnZXIgRmFicmljIGNoYWluY29kZSBzdGF0ZSBkYXRhYmFzZSBvcGVyYXRpb25zXG4gKiBAc3VtbWFyeSBQcm92aWRlcyBhIENvdWNoREItbGlrZSBpbnRlcmZhY2UgZm9yIGludGVyYWN0aW5nIHdpdGggdGhlIEZhYnJpYyBzdGF0ZSBkYXRhYmFzZSBmcm9tIHdpdGhpbiBhIGNoYWluY29kZSBjb250cmFjdFxuICogQHRlbXBsYXRlIHZvaWQgLSBObyBjb25maWd1cmF0aW9uIG5lZWRlZCBmb3IgY29udHJhY3QgYWRhcHRlclxuICogQHRlbXBsYXRlIEZhYnJpY0NvbnRyYWN0RmxhZ3MgLSBGbGFncyBzcGVjaWZpYyB0byBGYWJyaWMgY29udHJhY3Qgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIEZhYnJpY0NvbnRyYWN0Q29udGV4dCAtIENvbnRleHQgdHlwZSBmb3IgRmFicmljIGNvbnRyYWN0IG9wZXJhdGlvbnNcbiAqIEBjbGFzcyBGYWJyaWNDb250cmFjdEFkYXB0ZXJcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBJbiBhIEZhYnJpYyBjaGFpbmNvZGUgY29udHJhY3QgY2xhc3NcbiAqIGltcG9ydCB7IEZhYnJpY0NvbnRyYWN0QWRhcHRlciB9IGZyb20gJ0BkZWNhZi10cy9mb3ItZmFicmljJztcbiAqXG4gKiBleHBvcnQgY2xhc3MgTXlDb250cmFjdCBleHRlbmRzIENvbnRyYWN0IHtcbiAqICAgcHJpdmF0ZSBhZGFwdGVyID0gbmV3IEZhYnJpY0NvbnRyYWN0QWRhcHRlcigpO1xuICpcbiAqICAgQFRyYW5zYWN0aW9uKClcbiAqICAgYXN5bmMgY3JlYXRlQXNzZXQoY3R4OiBDb250ZXh0LCBpZDogc3RyaW5nLCBkYXRhOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAqICAgICBjb25zdCBtb2RlbCA9IHsgaWQsIGRhdGEsIHRpbWVzdGFtcDogRGF0ZS5ub3coKSB9O1xuICogICAgIGF3YWl0IHRoaXMuYWRhcHRlci5jcmVhdGUoJ2Fzc2V0cycsIGlkLCBtb2RlbCwge30sIHsgc3R1YjogY3R4LnN0dWIgfSk7XG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDb250cmFjdFxuICogICBwYXJ0aWNpcGFudCBGYWJyaWNDb250cmFjdEFkYXB0ZXJcbiAqICAgcGFydGljaXBhbnQgU3R1YlxuICogICBwYXJ0aWNpcGFudCBTdGF0ZURCXG4gKlxuICogICBDb250cmFjdC0+PkZhYnJpY0NvbnRyYWN0QWRhcHRlcjogY3JlYXRlKHRhYmxlTmFtZSwgaWQsIG1vZGVsLCB0cmFuc2llbnQsIGN0eClcbiAqICAgRmFicmljQ29udHJhY3RBZGFwdGVyLT4+RmFicmljQ29udHJhY3RBZGFwdGVyOiBTZXJpYWxpemUgbW9kZWwgdG8gSlNPTlxuICogICBGYWJyaWNDb250cmFjdEFkYXB0ZXItPj5TdHViOiBwdXRTdGF0ZShpZCwgc2VyaWFsaXplZERhdGEpXG4gKiAgIFN0dWItPj5TdGF0ZURCOiBXcml0ZSBkYXRhXG4gKiAgIFN0YXRlREItLT4+U3R1YjogU3VjY2Vzc1xuICogICBTdHViLS0+PkZhYnJpY0NvbnRyYWN0QWRhcHRlcjogU3VjY2Vzc1xuICogICBGYWJyaWNDb250cmFjdEFkYXB0ZXItLT4+Q29udHJhY3Q6IG1vZGVsXG4gKi9cbmV4cG9ydCBjbGFzcyBGYWJyaWNDb250cmFjdEFkYXB0ZXIgZXh0ZW5kcyBDb3VjaERCQWRhcHRlcjxcbiAgYW55LFxuICB2b2lkLFxuICBGYWJyaWNDb250cmFjdENvbnRleHRcbj4ge1xuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgZ2V0Q2xpZW50KCk6IHZvaWQge1xuICAgIHRocm93IG5ldyBVbnN1cHBvcnRlZEVycm9yKFwiQ2xpZW50IGlzIG5vdCBzdXBwb3J0ZWQgaW4gRmFicmljIGNvbnRyYWN0c1wiKTtcbiAgfVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFRleHQgZGVjb2RlciBmb3IgY29udmVydGluZyBiaW5hcnkgZGF0YSB0byBzdHJpbmdzXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyB0ZXh0RGVjb2RlciA9IG5ldyBUZXh0RGVjb2RlcihcInV0ZjhcIik7XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBzZXJpYWxpemVyID0gbmV3IFNpbXBsZURldGVybWluaXN0aWNTZXJpYWxpemVyKCk7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDb250ZXh0IGNvbnN0cnVjdG9yIGZvciB0aGlzIGFkYXB0ZXJcbiAgICogQHN1bW1hcnkgT3ZlcnJpZGVzIHRoZSBiYXNlIENvbnRleHQgY29uc3RydWN0b3Igd2l0aCBGYWJyaWNDb250cmFjdENvbnRleHRcbiAgICovXG4gIHByb3RlY3RlZCBvdmVycmlkZSByZWFkb25seSBDb250ZXh0OiBDb25zdHJ1Y3RvcjxGYWJyaWNDb250cmFjdENvbnRleHQ+ID1cbiAgICBGYWJyaWNDb250cmFjdENvbnRleHQ7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIHRoZSByZXBvc2l0b3J5IGNvbnN0cnVjdG9yIGZvciB0aGlzIGFkYXB0ZXJcbiAgICogQHN1bW1hcnkgUmV0dXJucyB0aGUgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5IGNvbnN0cnVjdG9yIGZvciBjcmVhdGluZyByZXBvc2l0b3JpZXNcbiAgICogQHRlbXBsYXRlIE0gLSBUeXBlIGV4dGVuZGluZyBNb2RlbFxuICAgKiBAcmV0dXJuIHtDb25zdHJ1Y3RvcjxSZXBvc2l0b3J5PE0sIE1hbmdvUXVlcnksIEZhYnJpY0NvbnRyYWN0QWRhcHRlciwgRmFicmljQ29udHJhY3RGbGFncywgRmFicmljQ29udHJhY3RDb250ZXh0Pj59IFRoZSByZXBvc2l0b3J5IGNvbnN0cnVjdG9yXG4gICAqL1xuICBvdmVycmlkZSByZXBvc2l0b3J5PFxuICAgIFIgZXh0ZW5kcyBSZXBvc2l0b3J5PFxuICAgICAgYW55LFxuICAgICAgQWRhcHRlcjxhbnksIHZvaWQsIE1hbmdvUXVlcnksIENvbnRleHQ8RmFicmljQ29udHJhY3RGbGFncz4+XG4gICAgPixcbiAgPigpOiBDb25zdHJ1Y3RvcjxSPiB7XG4gICAgcmV0dXJuIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeSBhcyB1bmtub3duIGFzIENvbnN0cnVjdG9yPFI+O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgbmV3IEZhYnJpY0NvbnRyYWN0QWRhcHRlciBpbnN0YW5jZVxuICAgKiBAc3VtbWFyeSBJbml0aWFsaXplcyBhbiBhZGFwdGVyIGZvciBpbnRlcmFjdGluZyB3aXRoIHRoZSBGYWJyaWMgc3RhdGUgZGF0YWJhc2VcbiAgICogQHBhcmFtIHt2b2lkfSBzY29wZSAtIE5vdCB1c2VkIGluIHRoaXMgYWRhcHRlclxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FsaWFzXSAtIE9wdGlvbmFsIGFsaWFzIGZvciB0aGUgYWRhcHRlciBpbnN0YW5jZVxuICAgKi9cbiAgY29uc3RydWN0b3Ioc2NvcGU6IHZvaWQsIGFsaWFzPzogc3RyaW5nKSB7XG4gICAgc3VwZXIoc2NvcGUsIEZhYnJpY0ZsYXZvdXIsIGFsaWFzKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGZvcihjb25maWc6IFBhcnRpYWw8YW55PiwgLi4uYXJnczogYW55KTogdHlwZW9mIHRoaXMge1xuICAgIHJldHVybiBzdXBlci5mb3IoY29uZmlnLCAuLi5hcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIHJlY29yZCBpbiB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgU2VyaWFsaXplcyBhIG1vZGVsIGFuZCBzdG9yZXMgaXQgaW4gdGhlIEZhYnJpYyBzdGF0ZSBkYXRhYmFzZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlL2NvbGxlY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudW1iZXJ9IGlkIC0gVGhlIHJlY29yZCBpZGVudGlmaWVyXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gbW9kZWwgLSBUaGUgcmVjb3JkIGRhdGFcbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSB0cmFuc2llbnQgLSBUcmFuc2llbnQgZGF0YSAobm90IHVzZWQgaW4gdGhpcyBpbXBsZW1lbnRhdGlvbilcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzLCBpbmNsdWRpbmcgdGhlIGNoYWluY29kZSBzdHViIGFuZCBsb2dnZXJcbiAgICogQHJldHVybiB7UHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGNyZWF0ZWQgcmVjb3JkXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyBjcmVhdGU8TSBleHRlbmRzIE1vZGVsPihcbiAgICBjbGF6ejogQ29uc3RydWN0b3I8TT4sXG4gICAgaWQ6IFByaW1hcnlLZXlUeXBlLFxuICAgIG1vZGVsOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ29udHJhY3RGbGFncz4+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICAgIGNvbnN0IHsgY3R4LCBsb2csIHN0dWIgfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMuY3JlYXRlKTtcbiAgICBsb2cuaW5mbyhgaW4gQURBUFRFUiBjcmVhdGUgd2l0aCBhcmdzICR7YXJnc31gKTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBNb2RlbC50YWJsZU5hbWUoY2xhenopO1xuICAgIHRyeSB7XG4gICAgICBsb2cuaW5mbyhgYWRkaW5nIGVudHJ5IHRvICR7dGFibGVOYW1lfSB0YWJsZSB3aXRoIHBrICR7aWR9YCk7XG4gICAgICBjb25zdCBjb21wb3NlZEtleSA9IHN0dWIuY3JlYXRlQ29tcG9zaXRlS2V5KHRhYmxlTmFtZSwgW1N0cmluZyhpZCldKTtcbiAgICAgIG1vZGVsID0gYXdhaXQgdGhpcy5wdXRTdGF0ZShjb21wb3NlZEtleSwgbW9kZWwsIGN0eCk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cblxuICAgIHJldHVybiBtb2RlbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVhZHMgYSByZWNvcmQgZnJvbSB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgUmV0cmlldmVzIGFuZCBkZXNlcmlhbGl6ZXMgYSByZWNvcmQgZnJvbSB0aGUgRmFicmljIHN0YXRlIGRhdGFiYXNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWJsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdGFibGUvY29sbGVjdGlvblxuICAgKiBAcGFyYW0ge3N0cmluZyB8IG51bWJlcn0gaWQgLSBUaGUgcmVjb3JkIGlkZW50aWZpZXJcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzLCBpbmNsdWRpbmcgdGhlIGNoYWluY29kZSBzdHViIGFuZCBsb2dnZXJcbiAgICogQHJldHVybiB7UHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHJldHJpZXZlZCByZWNvcmRcbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIHJlYWQ8TSBleHRlbmRzIE1vZGVsPihcbiAgICBjbGF6ejogQ29uc3RydWN0b3I8TT4sXG4gICAgaWQ6IFByaW1hcnlLZXlUeXBlLFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ29udHJhY3RGbGFncz4+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICAgIGNvbnN0IHsgY3R4LCBsb2csIHN0dWIgfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmVhZCk7XG4gICAgbG9nLmluZm8oYGluIEFEQVBURVIgcmVhZCB3aXRoIGFyZ3MgJHthcmdzfWApO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG5cbiAgICBsZXQgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGNvbXBvc2VkS2V5ID0gc3R1Yi5jcmVhdGVDb21wb3NpdGVLZXkodGFibGVOYW1lLCBbU3RyaW5nKGlkKV0pO1xuICAgICAgbW9kZWwgPSBhd2FpdCB0aGlzLnJlYWRTdGF0ZShjb21wb3NlZEtleSwgY3R4KTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuXG4gICAgcmV0dXJuIG1vZGVsO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIGEgcmVjb3JkIGluIHRoZSBzdGF0ZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBTZXJpYWxpemVzIGEgbW9kZWwgYW5kIHVwZGF0ZXMgaXQgaW4gdGhlIEZhYnJpYyBzdGF0ZSBkYXRhYmFzZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlL2NvbGxlY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudW1iZXJ9IGlkIC0gVGhlIHJlY29yZCBpZGVudGlmaWVyXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gbW9kZWwgLSBUaGUgdXBkYXRlZCByZWNvcmQgZGF0YVxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIGFueT59IHRyYW5zaWVudCAtIFRyYW5zaWVudCBkYXRhIChub3QgdXNlZCBpbiB0aGlzIGltcGxlbWVudGF0aW9uKVxuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMsIGluY2x1ZGluZyB0aGUgY2hhaW5jb2RlIHN0dWIgYW5kIGxvZ2dlclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCByZWNvcmRcbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIHVwZGF0ZTxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDb250cmFjdEZsYWdzPj5cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+PiB7XG4gICAgY29uc3QgeyBjdHgsIGxvZywgc3R1YiB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy51cGRhdGUpO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG5cbiAgICB0cnkge1xuICAgICAgbG9nLnZlcmJvc2UoYHVwZGF0aW5nIGVudHJ5IHRvICR7dGFibGVOYW1lfSB0YWJsZSB3aXRoIHBrICR7aWR9YCk7XG4gICAgICBjb25zdCBjb21wb3NlZEtleSA9IHN0dWIuY3JlYXRlQ29tcG9zaXRlS2V5KHRhYmxlTmFtZSwgW1N0cmluZyhpZCldKTtcbiAgICAgIG1vZGVsID0gYXdhaXQgdGhpcy5wdXRTdGF0ZShjb21wb3NlZEtleSwgbW9kZWwsIGN0eCk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cblxuICAgIHJldHVybiBtb2RlbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVsZXRlcyBhIHJlY29yZCBmcm9tIHRoZSBzdGF0ZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBSZXRyaWV2ZXMgYSByZWNvcmQgYW5kIHRoZW4gcmVtb3ZlcyBpdCBmcm9tIHRoZSBGYWJyaWMgc3RhdGUgZGF0YWJhc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyfSBpZCAtIFRoZSByZWNvcmQgaWRlbnRpZmllciB0byBkZWxldGVcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzLCBpbmNsdWRpbmcgdGhlIGNoYWluY29kZSBzdHViIGFuZCBsb2dnZXJcbiAgICogQHJldHVybiB7UHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGRlbGV0ZWQgcmVjb3JkXG4gICAqL1xuICBhc3luYyBkZWxldGU8TSBleHRlbmRzIE1vZGVsPihcbiAgICBjbGF6ejogQ29uc3RydWN0b3I8TT4sXG4gICAgaWQ6IFByaW1hcnlLZXlUeXBlLFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPENvbnRleHQ8RmFicmljQ29udHJhY3RGbGFncz4+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICAgIGNvbnN0IHsgY3R4LCBsb2csIGN0eEFyZ3MsIHN0dWIgfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMuZGVsZXRlKTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBNb2RlbC50YWJsZU5hbWUoY2xhenopO1xuICAgIGxldCBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PjtcbiAgICB0cnkge1xuICAgICAgY29uc3QgY29tcG9zZWRLZXkgPSBzdHViLmNyZWF0ZUNvbXBvc2l0ZUtleSh0YWJsZU5hbWUsIFtTdHJpbmcoaWQpXSk7XG4gICAgICBtb2RlbCA9IGF3YWl0IHRoaXMucmVhZChjbGF6eiwgaWQsIC4uLmN0eEFyZ3MpO1xuICAgICAgbG9nLnZlcmJvc2UoYGRlbGV0aW5nIGVudHJ5IHdpdGggcGsgJHtpZH0gZnJvbSAke3RhYmxlTmFtZX0gdGFibGVgKTtcbiAgICAgIGF3YWl0IHRoaXMuZGVsZXRlU3RhdGUoY29tcG9zZWRLZXksIGN0eCk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cblxuICAgIHJldHVybiBtb2RlbDtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBkZWxldGVTdGF0ZShpZDogc3RyaW5nLCBjdHg6IEZhYnJpY0NvbnRyYWN0Q29udGV4dCkge1xuICAgIGNvbnN0IHsgc3R1YiB9ID0gdGhpcy5sb2dDdHgoW2N0eF0sIHRoaXMuZGVsZXRlU3RhdGUpO1xuICAgIGF3YWl0IHN0dWIuZGVsZXRlU3RhdGUoaWQpO1xuICB9XG5cbiAgZm9yUHJpdmF0ZShjb2xsZWN0aW9uOiBzdHJpbmcpOiBGYWJyaWNDb250cmFjdEFkYXB0ZXIge1xuICAgIGNvbnN0IHRvT3ZlcnJpZGUgPSBbXG4gICAgICB0aGlzLnB1dFN0YXRlLFxuICAgICAgdGhpcy5yZWFkU3RhdGUsXG4gICAgICB0aGlzLmRlbGV0ZVN0YXRlLFxuICAgICAgdGhpcy5xdWVyeVJlc3VsdCxcbiAgICAgIHRoaXMucXVlcnlSZXN1bHRQYWdpbmF0ZWQsXG4gICAgXS5tYXAoKGZuKSA9PiBmbi5uYW1lKTtcbiAgICByZXR1cm4gbmV3IFByb3h5KHRoaXMsIHtcbiAgICAgIGdldCh0YXJnZXQsIHByb3AsIHJlY2VpdmVyKSB7XG4gICAgICAgIGlmICghdG9PdmVycmlkZS5pbmNsdWRlcyhwcm9wIGFzIHN0cmluZykpXG4gICAgICAgICAgcmV0dXJuIFJlZmxlY3QuZ2V0KHRhcmdldCwgcHJvcCwgcmVjZWl2ZXIpO1xuICAgICAgICByZXR1cm4gbmV3IFByb3h5KCh0YXJnZXQgYXMgYW55KVtwcm9wXSwge1xuICAgICAgICAgIGFzeW5jIGFwcGx5KGZuLCB0aGlzQXJnLCBhcmdzTGlzdCkge1xuICAgICAgICAgICAgc3dpdGNoIChwcm9wKSB7XG4gICAgICAgICAgICAgIGNhc2UgXCJwdXRTdGF0ZVwiOiB7XG4gICAgICAgICAgICAgICAgY29uc3QgW3N0dWIsIGlkLCBtb2RlbF0gPSBhcmdzTGlzdDtcbiAgICAgICAgICAgICAgICBhd2FpdCBzdHViLnB1dFByaXZhdGVEYXRhKGNvbGxlY3Rpb24sIGlkLnRvU3RyaW5nKCksIG1vZGVsKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gbW9kZWw7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgY2FzZSBcImRlbGV0ZVN0YXRlXCI6IHtcbiAgICAgICAgICAgICAgICBjb25zdCBbc3R1YiwgaWRdID0gYXJnc0xpc3Q7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChzdHViIGFzIENoYWluY29kZVN0dWIpLmRlbGV0ZVByaXZhdGVEYXRhKFxuICAgICAgICAgICAgICAgICAgY29sbGVjdGlvbixcbiAgICAgICAgICAgICAgICAgIGlkXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBjYXNlIFwicmVhZFN0YXRlXCI6IHtcbiAgICAgICAgICAgICAgICBjb25zdCBbc3R1YiwgaWRdID0gYXJnc0xpc3Q7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHN0dWIuZ2V0UHJpdmF0ZURhdGEoY29sbGVjdGlvbiwgaWQpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGNhc2UgXCJxdWVyeVJlc3VsdFwiOiB7XG4gICAgICAgICAgICAgICAgY29uc3QgW3N0dWIsIHJhd0lucHV0XSA9IGFyZ3NMaXN0O1xuICAgICAgICAgICAgICAgIHJldHVybiBzdHViLmdldFByaXZhdGVEYXRhUXVlcnlSZXN1bHQoY29sbGVjdGlvbiwgcmF3SW5wdXQpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGNhc2UgXCJxdWVyeVJlc3VsdFBhZ2luYXRlZFwiOiB7XG4gICAgICAgICAgICAgICAgY29uc3QgW3N0dWIsIHJhd0lucHV0LCBsaW1pdCwgc2tpcF0gPSBhcmdzTGlzdDtcbiAgICAgICAgICAgICAgICBjb25zdCBpdGVyYXRvciA9IGF3YWl0IChcbiAgICAgICAgICAgICAgICAgIHN0dWIgYXMgQ2hhaW5jb2RlU3R1YlxuICAgICAgICAgICAgICAgICkuZ2V0UHJpdmF0ZURhdGFRdWVyeVJlc3VsdChjb2xsZWN0aW9uLCByYXdJbnB1dCk7XG4gICAgICAgICAgICAgICAgY29uc3QgcmVzdWx0czogYW55W10gPSBbXTtcbiAgICAgICAgICAgICAgICBsZXQgY291bnQgPSAwO1xuICAgICAgICAgICAgICAgIGxldCByZWFjaGVkQm9va21hcmsgPSBza2lwID8gZmFsc2UgOiB0cnVlO1xuICAgICAgICAgICAgICAgIGxldCBsYXN0S2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuICAgICAgICAgICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCByZXMgPSBhd2FpdCBpdGVyYXRvci5uZXh0KCk7XG5cbiAgICAgICAgICAgICAgICAgIGlmIChyZXMudmFsdWUgJiYgcmVzLnZhbHVlLnZhbHVlLnRvU3RyaW5nKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVjb3JkS2V5ID0gcmVzLnZhbHVlLmtleTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVjb3JkVmFsdWUgPSAocmVzLnZhbHVlLnZhbHVlIGFzIGFueSkudG9TdHJpbmcoXG4gICAgICAgICAgICAgICAgICAgICAgXCJ1dGY4XCJcbiAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBJZiB3ZSBoYXZlIGEgc2tpcCwgc2tpcCB1bnRpbCB3ZSByZWFjaCBpdFxuICAgICAgICAgICAgICAgICAgICBpZiAoIXJlYWNoZWRCb29rbWFyaykge1xuICAgICAgICAgICAgICAgICAgICAgIGlmIChyZWNvcmRLZXkgPT09IHNraXA/LnRvU3RyaW5nKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlYWNoZWRCb29rbWFyayA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0cy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgICBLZXk6IHJlY29yZEtleSxcbiAgICAgICAgICAgICAgICAgICAgICBSZWNvcmQ6IEpTT04ucGFyc2UocmVjb3JkVmFsdWUpLFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgbGFzdEtleSA9IHJlY29yZEtleTtcbiAgICAgICAgICAgICAgICAgICAgY291bnQrKztcblxuICAgICAgICAgICAgICAgICAgICBpZiAoY291bnQgPj0gbGltaXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBpdGVyYXRvci5jbG9zZSgpO1xuICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpdGVyYXRvcjpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyBhcyB1bmtub3duIGFzIEl0ZXJhdG9ycy5TdGF0ZVF1ZXJ5SXRlcmF0b3IsXG4gICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBmZXRjaGVkUmVjb3Jkc0NvdW50OiByZXN1bHRzLmxlbmd0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgYm9va21hcms6IGxhc3RLZXksXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgaWYgKHJlcy5kb25lKSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGl0ZXJhdG9yLmNsb3NlKCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgaXRlcmF0b3I6XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzIGFzIHVua25vd24gYXMgSXRlcmF0b3JzLlN0YXRlUXVlcnlJdGVyYXRvcixcbiAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YToge1xuICAgICAgICAgICAgICAgICAgICAgICAgZmV0Y2hlZFJlY29yZHNDb3VudDogcmVzdWx0cy5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgICAgICBib29rbWFyazogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgICAgICAgYFVuc3VwcG9ydGVkIG1ldGhvZCBvdmVycmlkZSAke1N0cmluZyhwcm9wKX1gXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgcHV0U3RhdGUoXG4gICAgaWQ6IHN0cmluZyxcbiAgICBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICBjdHg6IEZhYnJpY0NvbnRyYWN0Q29udGV4dFxuICApIHtcbiAgICBsZXQgZGF0YTogQnVmZmVyO1xuXG4gICAgY29uc3QgeyBzdHViLCBsb2cgfSA9IHRoaXMubG9nQ3R4KFtjdHhdLCB0aGlzLnB1dFN0YXRlKTtcbiAgICB0cnkge1xuICAgICAgZGF0YSA9IEJ1ZmZlci5mcm9tKFxuICAgICAgICBGYWJyaWNDb250cmFjdEFkYXB0ZXIuc2VyaWFsaXplci5zZXJpYWxpemUobW9kZWwgYXMgTW9kZWwpXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoXG4gICAgICAgIGBGYWlsZWQgdG8gc2VyaWFsaXplIHJlY29yZCB3aXRoIGlkICR7aWR9OiAke2V9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBjb2xsZWN0aW9uID0gY3R4LmdldChcInNlZ3JlZ2F0ZWRcIik7XG4gICAgaWYgKGNvbGxlY3Rpb24pIGF3YWl0IHN0dWIucHV0UHJpdmF0ZURhdGEoY29sbGVjdGlvbiwgaWQudG9TdHJpbmcoKSwgZGF0YSk7XG4gICAgZWxzZSBhd2FpdCBzdHViLnB1dFN0YXRlKGlkLnRvU3RyaW5nKCksIGRhdGEpO1xuXG4gICAgbG9nLnNpbGx5KFxuICAgICAgYHN0YXRlIHN0b3JlZCR7Y29sbGVjdGlvbiA/IGAgaW4gJHtjb2xsZWN0aW9ufSBjb2xsZWN0aW9uYCA6IFwiXCJ9IHVuZGVyIGlkICR7aWR9YFxuICAgICk7XG4gICAgcmV0dXJuIG1vZGVsO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIHJlYWRTdGF0ZShpZDogc3RyaW5nLCBjdHg6IEZhYnJpY0NvbnRyYWN0Q29udGV4dCkge1xuICAgIGxldCByZXN1bHQ6IGFueTtcblxuICAgIGNvbnN0IHsgc3R1YiwgbG9nIH0gPSB0aGlzLmxvZ0N0eChbY3R4XSwgdGhpcy5yZWFkU3RhdGUpO1xuICAgIGxldCByZXM6IHN0cmluZztcbiAgICBjb25zdCBjb2xsZWN0aW9uID0gY3R4LmdldChcInNlZ3JlZ2F0ZWRcIik7XG4gICAgaWYgKGNvbGxlY3Rpb24pXG4gICAgICByZXMgPSAoYXdhaXQgc3R1Yi5nZXRQcml2YXRlRGF0YShjb2xsZWN0aW9uLCBpZC50b1N0cmluZygpKSkudG9TdHJpbmcoKTtcbiAgICBlbHNlIHJlcyA9IChhd2FpdCBzdHViLmdldFN0YXRlKGlkLnRvU3RyaW5nKCkpKS50b1N0cmluZygpO1xuXG4gICAgaWYgKCFyZXMpXG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihcbiAgICAgICAgYFJlY29yZCB3aXRoIGlkICR7aWR9JHtjb2xsZWN0aW9uID8gYCBpbiAke2NvbGxlY3Rpb259IGNvbGxlY3Rpb25gIDogXCJcIn0gbm90IGZvdW5kYFxuICAgICAgKTtcbiAgICBsb2cuc2lsbHkoXG4gICAgICBgc3RhdGUgcmV0cmlldmVkIGZyb20ke2NvbGxlY3Rpb24gPyBgICR7Y29sbGVjdGlvbn0gY29sbGVjdGlvbmAgOiBcIlwifSB1bmRlciBpZCAke2lkfWBcbiAgICApO1xuICAgIHRyeSB7XG4gICAgICByZXN1bHQgPSBGYWJyaWNDb250cmFjdEFkYXB0ZXIuc2VyaWFsaXplci5kZXNlcmlhbGl6ZShyZXMudG9TdHJpbmcoKSk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IFNlcmlhbGl6YXRpb25FcnJvcihgRmFpbGVkIHRvIHBhcnNlIHJlY29yZDogJHtlfWApO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgcXVlcnlSZXN1bHQoXG4gICAgc3R1YjogQ2hhaW5jb2RlU3R1YixcbiAgICByYXdJbnB1dDogYW55LFxuXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxJdGVyYXRvcnMuU3RhdGVRdWVyeUl0ZXJhdG9yPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmVhZFN0YXRlKTtcbiAgICBsZXQgcmVzOiBJdGVyYXRvcnMuU3RhdGVRdWVyeUl0ZXJhdG9yO1xuICAgIGNvbnN0IGNvbGxlY3Rpb24gPSBjdHguZ2V0KFwic2VncmVnYXRlZFwiKTtcbiAgICBpZiAoY29sbGVjdGlvbilcbiAgICAgIHJlcyA9IGF3YWl0IHN0dWIuZ2V0UHJpdmF0ZURhdGFRdWVyeVJlc3VsdChcbiAgICAgICAgY29sbGVjdGlvbixcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkocmF3SW5wdXQpXG4gICAgICApO1xuICAgIGVsc2UgcmVzID0gYXdhaXQgc3R1Yi5nZXRRdWVyeVJlc3VsdChKU09OLnN0cmluZ2lmeShyYXdJbnB1dCkpO1xuXG4gICAgcmV0dXJuIHJlcztcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBxdWVyeVJlc3VsdFBhZ2luYXRlZChcbiAgICBzdHViOiBDaGFpbmNvZGVTdHViLFxuICAgIHJhd0lucHV0OiBhbnksXG4gICAgbGltaXQ6IG51bWJlciA9IDI1MCxcbiAgICBza2lwPzogbnVtYmVyLFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8U3RhdGVRdWVyeVJlc3BvbnNlPEl0ZXJhdG9ycy5TdGF0ZVF1ZXJ5SXRlcmF0b3I+PiB7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmVhZFN0YXRlKTtcbiAgICBsZXQgcmVzOiBTdGF0ZVF1ZXJ5UmVzcG9uc2U8SXRlcmF0b3JzLlN0YXRlUXVlcnlJdGVyYXRvcj47XG4gICAgY29uc3QgY29sbGVjdGlvbiA9IGN0eC5nZXQoXCJzZWdyZWdhdGVkXCIpO1xuICAgIGlmIChjb2xsZWN0aW9uKSB7XG4gICAgICByYXdJbnB1dC5zZWxlY3RvciA9IHtcbiAgICAgICAgLi4ucmF3SW5wdXQuc2VsZWN0b3IsXG4gICAgICAgIF9pZDogc2tpcCA/IHsgJGd0OiBza2lwLnRvU3RyaW5nKCkgfSA6IHsgJGd0ZTogXCJcIiB9LFxuICAgICAgfTtcbiAgICAgIGNvbnN0IGl0ID0gYXdhaXQgc3R1Yi5nZXRQcml2YXRlRGF0YVF1ZXJ5UmVzdWx0KFxuICAgICAgICBjb2xsZWN0aW9uLFxuICAgICAgICBKU09OLnN0cmluZ2lmeShyYXdJbnB1dClcbiAgICAgICk7XG4gICAgICByZXMgPSB7XG4gICAgICAgIGl0ZXJhdG9yOiBpdCxcbiAgICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgICBmZXRjaGVkUmVjb3Jkc0NvdW50OiBsaW1pdCxcbiAgICAgICAgICBib29rbWFyazogXCJcIixcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfSBlbHNlXG4gICAgICByZXMgPSBhd2FpdCBzdHViLmdldFF1ZXJ5UmVzdWx0V2l0aFBhZ2luYXRpb24oXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KHJhd0lucHV0KSxcbiAgICAgICAgbGltaXQsXG4gICAgICAgIHNraXA/LnRvU3RyaW5nKClcbiAgICAgICk7XG5cbiAgICByZXR1cm4gcmVzO1xuICB9XG5cbiAgcHJvdGVjdGVkIG1lcmdlTW9kZWxzKHJlc3VsdHM6IFJlY29yZDxzdHJpbmcsIGFueT5bXSk6IFJlY29yZDxzdHJpbmcsIGFueT4ge1xuICAgIGNvbnN0IGV4dHJhY3QgPSAobW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4pID0+XG4gICAgICBPYmplY3QuZW50cmllcyhtb2RlbCkucmVkdWNlKChhY2N1bTogUmVjb3JkPHN0cmluZywgYW55PiwgW2tleSwgdmFsXSkgPT4ge1xuICAgICAgICBpZiAodHlwZW9mIHZhbCAhPT0gXCJ1bmRlZmluZWRcIikgYWNjdW1ba2V5XSA9IHZhbDtcbiAgICAgICAgcmV0dXJuIGFjY3VtO1xuICAgICAgfSwge30pO1xuXG4gICAgbGV0IGZpbmFsTW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4gPSByZXN1bHRzLnBvcCgpIGFzIFJlY29yZDxzdHJpbmcsIGFueT47XG5cbiAgICBmb3IgKGNvbnN0IHJlcyBvZiByZXN1bHRzKSB7XG4gICAgICBmaW5hbE1vZGVsID0gT2JqZWN0LmFzc2lnbih7fSwgZXh0cmFjdChmaW5hbE1vZGVsKSwgZXh0cmFjdChyZXMpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZmluYWxNb2RlbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVjb2RlcyBiaW5hcnkgZGF0YSB0byBzdHJpbmdcbiAgICogQHN1bW1hcnkgQ29udmVydHMgYSBVaW50OEFycmF5IHRvIGEgc3RyaW5nIHVzaW5nIFVURi04IGVuY29kaW5nXG4gICAqIEBwYXJhbSB7VWludDhBcnJheX0gYnVmZmVyIC0gVGhlIGJpbmFyeSBkYXRhIHRvIGRlY29kZVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBkZWNvZGVkIHN0cmluZ1xuICAgKi9cbiAgcHJvdGVjdGVkIGRlY29kZShidWZmZXI6IFVpbnQ4QXJyYXkpIHtcbiAgICByZXR1cm4gRmFicmljQ29udHJhY3RBZGFwdGVyLnRleHREZWNvZGVyLmRlY29kZShidWZmZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIG9wZXJhdGlvbiBmbGFncyBmb3IgRmFicmljIGNvbnRyYWN0IG9wZXJhdGlvbnNcbiAgICogQHN1bW1hcnkgTWVyZ2VzIGRlZmF1bHQgZmxhZ3Mgd2l0aCBGYWJyaWMtc3BlY2lmaWMgY29udGV4dCBpbmZvcm1hdGlvblxuICAgKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gICAqIEBwYXJhbSB7T3BlcmF0aW9uS2V5c30gb3BlcmF0aW9uIC0gVGhlIG9wZXJhdGlvbiBiZWluZyBwZXJmb3JtZWRcbiAgICogQHBhcmFtIHtDb25zdHJ1Y3RvcjxNPn0gbW9kZWwgLSBUaGUgbW9kZWwgY29uc3RydWN0b3JcbiAgICogQHBhcmFtIHtQYXJ0aWFsPEZhYnJpY0NvbnRyYWN0RmxhZ3M+fSBmbGFncyAtIFBhcnRpYWwgZmxhZ3MgdG8gbWVyZ2Ugd2l0aCBkZWZhdWx0c1xuICAgKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICAgKiBAcmV0dXJuIHtGYWJyaWNDb250cmFjdEZsYWdzfSBUaGUgbWVyZ2VkIGZsYWdzXG4gICAqL1xuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgZmxhZ3M8TSBleHRlbmRzIE1vZGVsPihcbiAgICBvcGVyYXRpb246IE9wZXJhdGlvbktleXMsXG4gICAgbW9kZWw6IENvbnN0cnVjdG9yPE0+LFxuICAgIGZsYWdzOiBQYXJ0aWFsPEZhYnJpY0NvbnRyYWN0RmxhZ3M+LFxuICAgIGN0eDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8RmFicmljQ29udHJhY3RGbGFncz4ge1xuICAgIGNvbnN0IGJhc2VGbGFncyA9IHtcbiAgICAgIHN0dWI6IGN0eC5zdHViLFxuICAgICAgc2VncmVnYXRlZDogZmFsc2UsXG4gICAgfTtcbiAgICBpZiAoY3R4IGluc3RhbmNlb2YgRmFicmljQ29udHJhY3RDb250ZXh0KSB7XG4gICAgICBPYmplY3QuYXNzaWduKGJhc2VGbGFncywge1xuICAgICAgICBsb2dnZXI6IGN0eC5sb2dnZXIsXG4gICAgICAgIGlkZW50aXR5OiBjdHguaWRlbnRpdHksXG4gICAgICAgIGNvcnJlbGF0aW9uSWQ6IGN0eC5zdHViLmdldFR4SUQoKSxcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBPYmplY3QuYXNzaWduKGJhc2VGbGFncywge1xuICAgICAgICBpZGVudGl0eTogY3R4LmNsaWVudElkZW50aXR5LFxuICAgICAgICBsb2dnZXI6IG5ldyBDb250cmFjdExvZ2dlcih0aGlzIGFzIGFueSwgdW5kZWZpbmVkLCBjdHgpLFxuICAgICAgICBjb3JyZWxhdGlvbklkOiBjdHguc3R1Yi5nZXRUeElEKCksXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBmbGFncyA9IChhd2FpdCBzdXBlci5mbGFncyhcbiAgICAgIG9wZXJhdGlvbixcbiAgICAgIG1vZGVsLFxuICAgICAgYmFzZUZsYWdzIGFzIGFueSxcbiAgICAgIC4uLmFyZ3NcbiAgICApKSBhcyBGYWJyaWNDb250cmFjdEZsYWdzO1xuXG4gICAgcmV0dXJuIGZsYWdzIGFzIEZhYnJpY0NvbnRyYWN0RmxhZ3M7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYW4gaW5kZXggZm9yIGEgbW9kZWxcbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgaXMgbm90IGltcGxlbWVudGVkIGZvciBGYWJyaWMgY29udHJhY3RzIGFuZCByZXR1cm5zIGEgcmVzb2x2ZWQgcHJvbWlzZVxuICAgKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gICAqIEBwYXJhbSB7Q29uc3RydWN0b3I8TT59IG1vZGVscyAtIFRoZSBtb2RlbCBjb25zdHJ1Y3RvclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgaW1tZWRpYXRlbHlcbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgcHJvdGVjdGVkIGluZGV4PE0+KG1vZGVsczogQ29uc3RydWN0b3I8TT4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHVuZGVmaW5lZCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByb2Nlc3NlcyByZXN1bHRzIGZyb20gYSBzdGF0ZSBxdWVyeSBpdGVyYXRvclxuICAgKiBAc3VtbWFyeSBJdGVyYXRlcyB0aHJvdWdoIHF1ZXJ5IHJlc3VsdHMgYW5kIGNvbnZlcnRzIHRoZW0gdG8gYSBzdHJ1Y3R1cmVkIGZvcm1hdFxuICAgKiBAcGFyYW0ge0xvZ2dlcn0gbG9nIC0gTG9nZ2VyIGluc3RhbmNlIGZvciBkZWJ1Z2dpbmdcbiAgICogQHBhcmFtIHtJdGVyYXRvcnMuU3RhdGVRdWVyeUl0ZXJhdG9yfSBpdGVyYXRvciAtIFRoZSBzdGF0ZSBxdWVyeSBpdGVyYXRvclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtpc0hpc3Rvcnk9ZmFsc2VdIC0gV2hldGhlciB0aGlzIGlzIGEgaGlzdG9yeSBxdWVyeVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPGFueVtdPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gYXJyYXkgb2YgcHJvY2Vzc2VkIHJlc3VsdHNcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gICAqICAgcGFydGljaXBhbnQgUmVzdWx0SXRlcmF0b3JcbiAgICogICBwYXJ0aWNpcGFudCBJdGVyYXRvclxuICAgKlxuICAgKiAgIENhbGxlci0+PlJlc3VsdEl0ZXJhdG9yOiByZXN1bHRJdGVyYXRvcihsb2csIGl0ZXJhdG9yLCBpc0hpc3RvcnkpXG4gICAqICAgbG9vcCBVbnRpbCBkb25lXG4gICAqICAgICBSZXN1bHRJdGVyYXRvci0+Pkl0ZXJhdG9yOiBuZXh0KClcbiAgICogICAgIEl0ZXJhdG9yLS0+PlJlc3VsdEl0ZXJhdG9yOiB7IHZhbHVlLCBkb25lIH1cbiAgICogICAgIGFsdCBIYXMgdmFsdWVcbiAgICogICAgICAgUmVzdWx0SXRlcmF0b3ItPj5SZXN1bHRJdGVyYXRvcjogUHJvY2VzcyB2YWx1ZSBiYXNlZCBvbiBpc0hpc3RvcnlcbiAgICogICAgICAgUmVzdWx0SXRlcmF0b3ItPj5SZXN1bHRJdGVyYXRvcjogQWRkIHRvIHJlc3VsdHMgYXJyYXlcbiAgICogICAgIGVuZFxuICAgKiAgIGVuZFxuICAgKiAgIFJlc3VsdEl0ZXJhdG9yLT4+SXRlcmF0b3I6IGNsb3NlKClcbiAgICogICBSZXN1bHRJdGVyYXRvci0tPj5DYWxsZXI6IGFsbFJlc3VsdHNcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyByZXN1bHRJdGVyYXRvcihcbiAgICBsb2c6IExvZ2dlcixcbiAgICBpdGVyYXRvcjogSXRlcmF0b3JzLlN0YXRlUXVlcnlJdGVyYXRvcixcbiAgICBpc0hpc3RvcnkgPSBmYWxzZVxuICApIHtcbiAgICBjb25zdCBhbGxSZXN1bHRzID0gW107XG4gICAgbGV0IHJlczogeyB2YWx1ZTogYW55OyBkb25lOiBib29sZWFuIH0gPSBhd2FpdCBpdGVyYXRvci5uZXh0KCk7XG4gICAgd2hpbGUgKCFyZXMuZG9uZSkge1xuICAgICAgaWYgKHJlcy52YWx1ZSAmJiByZXMudmFsdWUudmFsdWUudG9TdHJpbmcoKSkge1xuICAgICAgICBsZXQganNvblJlczogYW55ID0ge307XG4gICAgICAgIGxvZy5kZWJ1ZyhyZXMudmFsdWUudmFsdWUudG9TdHJpbmcoXCJ1dGY4XCIpKTtcbiAgICAgICAgaWYgKGlzSGlzdG9yeSAvKiAmJiBpc0hpc3RvcnkgPT09IHRydWUqLykge1xuICAgICAgICAgIGpzb25SZXMuVHhJZCA9IHJlcy52YWx1ZS50eElkO1xuICAgICAgICAgIGpzb25SZXMuVGltZXN0YW1wID0gcmVzLnZhbHVlLnRpbWVzdGFtcDtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAganNvblJlcy5WYWx1ZSA9IEpTT04ucGFyc2UocmVzLnZhbHVlLnZhbHVlLnRvU3RyaW5nKFwidXRmOFwiKSk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgIGxvZy5lcnJvcihlcnIpO1xuICAgICAgICAgICAganNvblJlcy5WYWx1ZSA9IHJlcy52YWx1ZS52YWx1ZS50b1N0cmluZyhcInV0ZjhcIik7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBqc29uUmVzID0gSlNPTi5wYXJzZShyZXMudmFsdWUudmFsdWUudG9TdHJpbmcoXCJ1dGY4XCIpKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgbG9nLmVycm9yKGVycik7XG4gICAgICAgICAgICBqc29uUmVzID0gcmVzLnZhbHVlLnZhbHVlLnRvU3RyaW5nKFwidXRmOFwiKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgYWxsUmVzdWx0cy5wdXNoKGpzb25SZXMpO1xuICAgICAgfVxuICAgICAgcmVzID0gYXdhaXQgaXRlcmF0b3IubmV4dCgpO1xuICAgIH1cbiAgICBsb2cuZGVidWcoYENsb3NpbmcgaXRlcmF0b3IgYWZ0ZXIgJHthbGxSZXN1bHRzLmxlbmd0aH0gcmVzdWx0c2ApO1xuICAgIGl0ZXJhdG9yLmNsb3NlKCk7IC8vIHB1cnBvc2VseSBub3QgYXdhaXQuIGxldCBpdGVyYXRvciBjbG9zZSBvbiBpdHMgb3duXG4gICAgcmV0dXJuIGFsbFJlc3VsdHM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV4ZWN1dGVzIGEgcmF3IHF1ZXJ5IGFnYWluc3QgdGhlIHN0YXRlIGRhdGFiYXNlXG4gICAqIEBzdW1tYXJ5IFBlcmZvcm1zIGEgcmljaCBxdWVyeSB1c2luZyBDb3VjaERCIHN5bnRheCBhZ2FpbnN0IHRoZSBGYWJyaWMgc3RhdGUgZGF0YWJhc2VcbiAgICogQHRlbXBsYXRlIFIgLSBUaGUgcmV0dXJuIHR5cGVcbiAgICogQHBhcmFtIHtNYW5nb1F1ZXJ5fSByYXdJbnB1dCAtIFRoZSBNYW5nbyBRdWVyeSB0byBleGVjdXRlXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gZG9jc09ubHkgLSBXaGV0aGVyIHRvIHJldHVybiBvbmx5IGRvY3VtZW50cyAobm90IHVzZWQgaW4gdGhpcyBpbXBsZW1lbnRhdGlvbilcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzLCBpbmNsdWRpbmcgdGhlIGNoYWluY29kZSBzdHViIGFuZCBsb2dnZXJcbiAgICogQHJldHVybiB7UHJvbWlzZTxSPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHF1ZXJ5IHJlc3VsdHNcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gICAqICAgcGFydGljaXBhbnQgRmFicmljQ29udHJhY3RBZGFwdGVyXG4gICAqICAgcGFydGljaXBhbnQgU3R1YlxuICAgKiAgIHBhcnRpY2lwYW50IFN0YXRlREJcbiAgICpcbiAgICogICBDYWxsZXItPj5GYWJyaWNDb250cmFjdEFkYXB0ZXI6IHJhdyhyYXdJbnB1dCwgZG9jc09ubHksIGN0eClcbiAgICogICBGYWJyaWNDb250cmFjdEFkYXB0ZXItPj5GYWJyaWNDb250cmFjdEFkYXB0ZXI6IEV4dHJhY3QgbGltaXQgYW5kIHNraXBcbiAgICogICBhbHQgV2l0aCBwYWdpbmF0aW9uXG4gICAqICAgICBGYWJyaWNDb250cmFjdEFkYXB0ZXItPj5TdHViOiBnZXRRdWVyeVJlc3VsdFdpdGhQYWdpbmF0aW9uKHF1ZXJ5LCBsaW1pdCwgc2tpcClcbiAgICogICBlbHNlIFdpdGhvdXQgcGFnaW5hdGlvblxuICAgKiAgICAgRmFicmljQ29udHJhY3RBZGFwdGVyLT4+U3R1YjogZ2V0UXVlcnlSZXN1bHQocXVlcnkpXG4gICAqICAgZW5kXG4gICAqICAgU3R1Yi0+PlN0YXRlREI6IEV4ZWN1dGUgcXVlcnlcbiAgICogICBTdGF0ZURCLS0+PlN0dWI6IEl0ZXJhdG9yXG4gICAqICAgU3R1Yi0tPj5GYWJyaWNDb250cmFjdEFkYXB0ZXI6IEl0ZXJhdG9yXG4gICAqICAgRmFicmljQ29udHJhY3RBZGFwdGVyLT4+RmFicmljQ29udHJhY3RBZGFwdGVyOiByZXN1bHRJdGVyYXRvcihsb2csIGl0ZXJhdG9yKVxuICAgKiAgIEZhYnJpY0NvbnRyYWN0QWRhcHRlci0tPj5DYWxsZXI6IHJlc3VsdHNcbiAgICovXG4gIGFzeW5jIHJhdzxSLCBEIGV4dGVuZHMgYm9vbGVhbj4oXG4gICAgcmF3SW5wdXQ6IE1hbmdvUXVlcnksXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIGRvY3NPbmx5OiBEID0gdHJ1ZSBhcyBELFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPEZhYnJpY0NvbnRyYWN0Q29udGV4dD5cbiAgKTogUHJvbWlzZTxSYXdSZXN1bHQ8UiwgRD4+IHtcbiAgICBjb25zdCB7IGxvZywgc3R1YiB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5yYXcpO1xuXG4gICAgY29uc3QgeyBza2lwLCBsaW1pdCB9ID0gcmF3SW5wdXQ7XG4gICAgbGV0IGl0ZXJhdG9yOiBJdGVyYXRvcnMuU3RhdGVRdWVyeUl0ZXJhdG9yO1xuICAgIGlmIChsaW1pdCB8fCBza2lwKSB7XG4gICAgICBkZWxldGUgcmF3SW5wdXRbXCJsaW1pdFwiXTtcbiAgICAgIGRlbGV0ZSByYXdJbnB1dFtcInNraXBcIl07XG4gICAgICBsb2cuZGVidWcoXG4gICAgICAgIGBSZXRyaWV2aW5nIHBhZ2luYXRlZCBpdGVyYXRvcjogbGltaXQ6ICR7bGltaXR9LyBza2lwOiAke3NraXB9YFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHJlc3BvbnNlOiBTdGF0ZVF1ZXJ5UmVzcG9uc2U8SXRlcmF0b3JzLlN0YXRlUXVlcnlJdGVyYXRvcj4gPVxuICAgICAgICAoYXdhaXQgdGhpcy5xdWVyeVJlc3VsdFBhZ2luYXRlZChcbiAgICAgICAgICBzdHViLFxuICAgICAgICAgIHJhd0lucHV0LFxuICAgICAgICAgIGxpbWl0IHx8IDI1MCxcbiAgICAgICAgICAoc2tpcCBhcyBhbnkpPy50b1N0cmluZygpXG4gICAgICAgICkpIGFzIFN0YXRlUXVlcnlSZXNwb25zZTxJdGVyYXRvcnMuU3RhdGVRdWVyeUl0ZXJhdG9yPjtcbiAgICAgIGl0ZXJhdG9yID0gcmVzcG9uc2UuaXRlcmF0b3I7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZy5kZWJ1ZyhcIlJldHJpZXZpbmcgaXRlcmF0b3JcIik7XG4gICAgICBpdGVyYXRvciA9IChhd2FpdCB0aGlzLnF1ZXJ5UmVzdWx0KFxuICAgICAgICBzdHViLFxuICAgICAgICByYXdJbnB1dFxuICAgICAgKSkgYXMgSXRlcmF0b3JzLlN0YXRlUXVlcnlJdGVyYXRvcjtcbiAgICB9XG4gICAgbG9nLmRlYnVnKFwiSXRlcmF0b3IgYWNxdWlyZWRcIik7XG5cbiAgICBjb25zdCByZXN1bHRzID0gKGF3YWl0IHRoaXMucmVzdWx0SXRlcmF0b3IobG9nLCBpdGVyYXRvcikpIGFzIFI7XG4gICAgbG9nLmRlYnVnKFxuICAgICAgYHJldHVybmluZyAke0FycmF5LmlzQXJyYXkocmVzdWx0cykgPyByZXN1bHRzLmxlbmd0aCA6IDF9IHJlc3VsdHNgXG4gICAgKTtcbiAgICByZXR1cm4gcmVzdWx0cyBhcyBhbnk7XG4gIH1cblxuICBvdmVycmlkZSBTdGF0ZW1lbnQ8TSBleHRlbmRzIE1vZGVsPigpOiBGYWJyaWNTdGF0ZW1lbnQ8TSwgYW55PiB7XG4gICAgcmV0dXJuIG5ldyBGYWJyaWNTdGF0ZW1lbnQodGhpcyBhcyBhbnkpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgY3JlYXRlQWxsPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgdGFibGVOYW1lOiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGVbXSxcbiAgICBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PltdLFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPEZhYnJpY0NvbnRyYWN0Q29udGV4dD5cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+W10+IHtcbiAgICBpZiAoaWQubGVuZ3RoICE9PSBtb2RlbC5sZW5ndGgpXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIklkcyBhbmQgbW9kZWxzIG11c3QgaGF2ZSB0aGUgc2FtZSBsZW5ndGhcIik7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMuY3JlYXRlQWxsKTtcbiAgICBjb25zdCB0YWJsZUxhYmVsID0gTW9kZWwudGFibGVOYW1lKHRhYmxlTmFtZSk7XG4gICAgbG9nLmRlYnVnKGBDcmVhdGluZyAke2lkLmxlbmd0aH0gZW50cmllcyAke3RhYmxlTGFiZWx9IHRhYmxlYCk7XG4gICAgcmV0dXJuIFByb21pc2UuYWxsKFxuICAgICAgaWQubWFwKChpLCBjb3VudCkgPT4gdGhpcy5jcmVhdGUodGFibGVOYW1lLCBpLCBtb2RlbFtjb3VudF0sIC4uLmN0eEFyZ3MpKVxuICAgICk7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyB1cGRhdGVBbGw8TSBleHRlbmRzIE1vZGVsPihcbiAgICB0YWJsZU5hbWU6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkOiBQcmltYXJ5S2V5VHlwZVtdLFxuICAgIG1vZGVsOiBSZWNvcmQ8c3RyaW5nLCBhbnk+W10sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8RmFicmljQ29udHJhY3RDb250ZXh0PlxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT5bXT4ge1xuICAgIGlmIChpZC5sZW5ndGggIT09IG1vZGVsLmxlbmd0aClcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiSWRzIGFuZCBtb2RlbHMgbXVzdCBoYXZlIHRoZSBzYW1lIGxlbmd0aFwiKTtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy51cGRhdGVBbGwpO1xuICAgIGNvbnN0IHRhYmxlTGFiZWwgPSBNb2RlbC50YWJsZU5hbWUodGFibGVOYW1lKTtcbiAgICBsb2cuZGVidWcoYFVwZGF0aW5nICR7aWQubGVuZ3RofSBlbnRyaWVzICR7dGFibGVMYWJlbH0gdGFibGVgKTtcbiAgICByZXR1cm4gUHJvbWlzZS5hbGwoXG4gICAgICBpZC5tYXAoKGksIGNvdW50KSA9PiB0aGlzLnVwZGF0ZSh0YWJsZU5hbWUsIGksIG1vZGVsW2NvdW50XSwgLi4uY3R4QXJncykpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKlxuICAgKiBAcGFyYW0gbW9kZWxcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBrXG4gICAqIEBwYXJhbSBhcmdzXG4gICAqL1xuICBvdmVycmlkZSBwcmVwYXJlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgbW9kZWw6IE0sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8RmFicmljQ29udHJhY3RDb250ZXh0PlxuICApOiBQcmVwYXJlZE1vZGVsIHtcbiAgICBjb25zdCB7IGxvZyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5wcmVwYXJlKTtcblxuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShtb2RlbC5jb25zdHJ1Y3RvciBhcyBhbnkpO1xuICAgIGNvbnN0IHBrID0gTW9kZWwucGsobW9kZWwuY29uc3RydWN0b3IgYXMgYW55KTtcbiAgICBjb25zdCBzcGxpdCA9IE1vZGVsLnNlZ3JlZ2F0ZShtb2RlbCk7XG4gICAgY29uc3QgcmVzdWx0ID0gT2JqZWN0LmVudHJpZXMoc3BsaXQubW9kZWwpLnJlZHVjZShcbiAgICAgIChhY2N1bTogUmVjb3JkPHN0cmluZywgYW55PiwgW2tleSwgdmFsXSkgPT4ge1xuICAgICAgICBpZiAodHlwZW9mIHZhbCA9PT0gXCJ1bmRlZmluZWRcIikgcmV0dXJuIGFjY3VtO1xuICAgICAgICBjb25zdCBtYXBwZWRQcm9wID0gTW9kZWwuY29sdW1uTmFtZShtb2RlbCwga2V5IGFzIGFueSk7XG4gICAgICAgIGlmICh0aGlzLmlzUmVzZXJ2ZWQobWFwcGVkUHJvcCkpXG4gICAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYFByb3BlcnR5IG5hbWUgJHttYXBwZWRQcm9wfSBpcyByZXNlcnZlZGApO1xuICAgICAgICBhY2N1bVttYXBwZWRQcm9wXSA9IHZhbDtcbiAgICAgICAgcmV0dXJuIGFjY3VtO1xuICAgICAgfSxcbiAgICAgIHt9XG4gICAgKTtcblxuICAgIGxvZy5zaWxseShcbiAgICAgIGBQcmVwYXJpbmcgcmVjb3JkIGZvciAke3RhYmxlTmFtZX0gdGFibGUgd2l0aCBwayAkeyhtb2RlbCBhcyBhbnkpW3BrXX1gXG4gICAgKTtcblxuICAgIHJldHVybiB7XG4gICAgICByZWNvcmQ6IHJlc3VsdCxcbiAgICAgIGlkOiAobW9kZWwgYXMgYW55KVtwa10gYXMgc3RyaW5nLFxuICAgICAgdHJhbnNpZW50OiBzcGxpdC50cmFuc2llbnQsXG4gICAgfTtcbiAgfVxuXG4gIG92ZXJyaWRlIHJldmVydDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIG9iajogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICBjbGF6ejogQ29uc3RydWN0b3I8TT4sXG4gICAgaWQ6IFByaW1hcnlLZXlUeXBlLFxuICAgIHRyYW5zaWVudD86IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8RmFicmljQ29udHJhY3RDb250ZXh0PlxuICApOiBNIHtcbiAgICBjb25zdCB7IGxvZyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5yZXZlcnQpO1xuICAgIGNvbnN0IG9iOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgY29uc3QgcGsgPSBNb2RlbC5wayhjbGF6eik7XG4gICAgb2JbcGsgYXMgc3RyaW5nXSA9IGlkO1xuICAgIGNvbnN0IG0gPSAoXG4gICAgICB0eXBlb2YgY2xhenogPT09IFwic3RyaW5nXCIgPyBNb2RlbC5idWlsZChvYiwgY2xhenopIDogbmV3IGNsYXp6KG9iKVxuICAgICkgYXMgTTtcbiAgICBsb2cuc2lsbHkoYFJlYnVpbGRpbmcgbW9kZWwgJHttLmNvbnN0cnVjdG9yLm5hbWV9IGlkICR7aWR9YCk7XG4gICAgY29uc3QgcmVzdWx0ID0gT2JqZWN0LmtleXMobSkucmVkdWNlKChhY2N1bTogTSwga2V5KSA9PiB7XG4gICAgICAoYWNjdW0gYXMgUmVjb3JkPHN0cmluZywgYW55Pilba2V5XSA9XG4gICAgICAgIG9ialtNb2RlbC5jb2x1bW5OYW1lKGFjY3VtLCBrZXkgYXMgYW55KV07XG4gICAgICByZXR1cm4gYWNjdW07XG4gICAgfSwgbSk7XG5cbiAgICBpZiAodHJhbnNpZW50KSB7XG4gICAgICBsb2cuZGVidWcoXG4gICAgICAgIGByZS1hZGRpbmcgdHJhbnNpZW50IHByb3BlcnRpZXM6ICR7T2JqZWN0LmtleXModHJhbnNpZW50KS5qb2luKFwiLCBcIil9YFxuICAgICAgKTtcbiAgICAgIE9iamVjdC5lbnRyaWVzKHRyYW5zaWVudCkuZm9yRWFjaCgoW2tleSwgdmFsXSkgPT4ge1xuICAgICAgICBpZiAoa2V5IGluIHJlc3VsdCAmJiAocmVzdWx0IGFzIGFueSlba2V5XSAhPT0gdW5kZWZpbmVkKVxuICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgYFRyYW5zaWVudCBwcm9wZXJ0eSAke2tleX0gYWxyZWFkeSBleGlzdHMgb24gbW9kZWwgJHttLmNvbnN0cnVjdG9yLm5hbWV9LiBzaG91bGQgYmUgaW1wb3NzaWJsZWBcbiAgICAgICAgICApO1xuICAgICAgICByZXN1bHRba2V5IGFzIGtleW9mIE1dID0gdmFsO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIG92ZXJyaWRlIGNyZWF0ZVByZWZpeDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIHRhYmxlTmFtZTogQ29uc3RydWN0b3I8TT4sXG4gICAgaWQ6IFByaW1hcnlLZXlUeXBlLFxuICAgIG1vZGVsOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxGYWJyaWNDb250cmFjdENvbnRleHQ+XG4gICkge1xuICAgIGNvbnN0IHsgY3R4QXJncyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5jcmVhdGVQcmVmaXgpO1xuICAgIGNvbnN0IHJlY29yZDogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgIHJlY29yZFtDb3VjaERCS2V5cy5UQUJMRV0gPSBNb2RlbC50YWJsZU5hbWUodGFibGVOYW1lKTtcbiAgICBPYmplY3QuYXNzaWduKHJlY29yZCwgbW9kZWwpO1xuXG4gICAgcmV0dXJuIFt0YWJsZU5hbWUsIGlkLCByZWNvcmQsIC4uLmN0eEFyZ3NdIGFzIFtcbiAgICAgIENvbnN0cnVjdG9yPE0+LFxuICAgICAgUHJpbWFyeUtleVR5cGUsXG4gICAgICBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgICAgLi4uYW55W10sXG4gICAgICBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gICAgXTtcbiAgfVxuXG4gIG92ZXJyaWRlIHVwZGF0ZVByZWZpeDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIHRhYmxlTmFtZTogQ29uc3RydWN0b3I8TT4sXG4gICAgaWQ6IFByaW1hcnlLZXlUeXBlLFxuICAgIG1vZGVsOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxGYWJyaWNDb250cmFjdENvbnRleHQ+XG4gICk6IGFueVtdIHtcbiAgICBjb25zdCB7IGN0eEFyZ3MgfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMudXBkYXRlUHJlZml4KTtcbiAgICBjb25zdCByZWNvcmQ6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcbiAgICByZWNvcmRbQ291Y2hEQktleXMuVEFCTEVdID0gTW9kZWwudGFibGVOYW1lKHRhYmxlTmFtZSk7XG4gICAgT2JqZWN0LmFzc2lnbihyZWNvcmQsIG1vZGVsKTtcblxuICAgIHJldHVybiBbdGFibGVOYW1lLCBpZCwgcmVjb3JkLCAuLi5jdHhBcmdzXSBhcyBbXG4gICAgICBDb25zdHJ1Y3RvcjxNPixcbiAgICAgIFByaW1hcnlLZXlUeXBlLFxuICAgICAgUmVjb3JkPHN0cmluZywgYW55PixcbiAgICAgIC4uLmFueVtdLFxuICAgICAgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIF07XG4gIH1cblxuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgY3JlYXRlQWxsUHJlZml4PE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgdGFibGVOYW1lOiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZHM6IFByaW1hcnlLZXlUeXBlW10sXG4gICAgbW9kZWxzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+W10sXG4gICAgLi4uYXJnczogWy4uLmFueSwgRmFicmljQ29udHJhY3RDb250ZXh0XVxuICApOiAoc3RyaW5nIHwgc3RyaW5nW10gfCBudW1iZXJbXSB8IFJlY29yZDxzdHJpbmcsIGFueT5bXSlbXSB7XG4gICAgaWYgKGlkcy5sZW5ndGggIT09IG1vZGVscy5sZW5ndGgpXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIklkcyBhbmQgbW9kZWxzIG11c3QgaGF2ZSB0aGUgc2FtZSBsZW5ndGhcIik7XG5cbiAgICBjb25zdCBjdHg6IEZhYnJpY0NvbnRyYWN0Q29udGV4dCA9IGFyZ3MucG9wKCk7XG5cbiAgICBjb25zdCByZWNvcmRzID0gaWRzLm1hcCgoaWQsIGNvdW50KSA9PiB7XG4gICAgICBjb25zdCByZWNvcmQ6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcbiAgICAgIHJlY29yZFtDb3VjaERCS2V5cy5UQUJMRV0gPSB0YWJsZU5hbWU7XG4gICAgICBPYmplY3QuYXNzaWduKHJlY29yZCwgbW9kZWxzW2NvdW50XSk7XG4gICAgICByZXR1cm4gcmVjb3JkO1xuICAgIH0pO1xuICAgIHJldHVybiBbdGFibGVOYW1lLCBpZHMsIHJlY29yZHMsIGN0eCBhcyBhbnldO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIHVwZGF0ZUFsbFByZWZpeDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIHRhYmxlTmFtZTogQ29uc3RydWN0b3I8TT4sXG4gICAgaWRzOiBQcmltYXJ5S2V5VHlwZVtdLFxuICAgIG1vZGVsczogUmVjb3JkPHN0cmluZywgYW55PltdLFxuICAgIC4uLmFyZ3M6IFsuLi5hbnksIEZhYnJpY0NvbnRyYWN0Q29udGV4dF1cbiAgKSB7XG4gICAgaWYgKGlkcy5sZW5ndGggIT09IG1vZGVscy5sZW5ndGgpXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIklkcyBhbmQgbW9kZWxzIG11c3QgaGF2ZSB0aGUgc2FtZSBsZW5ndGhcIik7XG5cbiAgICBjb25zdCBjdHg6IEZhYnJpY0NvbnRyYWN0Q29udGV4dCA9IGFyZ3MucG9wKCk7XG5cbiAgICBjb25zdCByZWNvcmRzID0gaWRzLm1hcCgoaWQsIGNvdW50KSA9PiB7XG4gICAgICBjb25zdCByZWNvcmQ6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcbiAgICAgIHJlY29yZFtDb3VjaERCS2V5cy5UQUJMRV0gPSB0YWJsZU5hbWU7XG4gICAgICBPYmplY3QuYXNzaWduKHJlY29yZCwgbW9kZWxzW2NvdW50XSk7XG4gICAgICByZXR1cm4gcmVjb3JkO1xuICAgIH0pO1xuICAgIHJldHVybiBbdGFibGVOYW1lLCBpZHMsIHJlY29yZHMsIGN0eCBhcyBhbnldO1xuICB9XG5cbiAgb3ZlcnJpZGUgcGFyc2VFcnJvcjxFIGV4dGVuZHMgQmFzZUVycm9yPihcbiAgICBlcnI6IEVycm9yIHwgc3RyaW5nLFxuICAgIHJlYXNvbj86IHN0cmluZ1xuICApOiBFIHtcbiAgICByZXR1cm4gRmFicmljQ29udHJhY3RBZGFwdGVyLnBhcnNlRXJyb3IocmVhc29uIHx8IGVycik7XG4gIH1cblxuICBvdmVycmlkZSBsb2dDdHg8QVJHUyBleHRlbmRzIGFueVtdPihcbiAgICBhcmdzOiBBUkdTLFxuICAgIG1ldGhvZDogKCguLi5hcmdzOiBhbnlbXSkgPT4gYW55KSB8IHN0cmluZ1xuICApOiBDb250ZXh0dWFsaXplZEFyZ3M8RmFicmljQ29udHJhY3RDb250ZXh0LCBBUkdTPiAmIHtcbiAgICBzdHViOiBDaGFpbmNvZGVTdHViO1xuICAgIGlkZW50aXR5OiBDbGllbnRJZGVudGl0eTtcbiAgfSB7XG4gICAgcmV0dXJuIEZhYnJpY0NvbnRyYWN0QWRhcHRlci5sb2dDdHguY2FsbCh0aGlzLCBhcmdzLCBtZXRob2QgYXMgYW55KSBhcyBhbnk7XG4gIH1cblxuICBzdGF0aWMgb3ZlcnJpZGUgbG9nQ3R4PEFSR1MgZXh0ZW5kcyBhbnlbXT4oXG4gICAgdGhpczogYW55LFxuICAgIGFyZ3M6IEFSR1MsXG4gICAgbWV0aG9kOiBzdHJpbmdcbiAgKTogQ29udGV4dHVhbGl6ZWRBcmdzPEZhYnJpY0NvbnRyYWN0Q29udGV4dCwgQVJHUz4gJiB7XG4gICAgc3R1YjogQ2hhaW5jb2RlU3R1YjtcbiAgICBpZGVudGl0eTogQ2xpZW50SWRlbnRpdHk7XG4gIH07XG4gIHN0YXRpYyBvdmVycmlkZSBsb2dDdHg8QVJHUyBleHRlbmRzIGFueVtdPihcbiAgICB0aGlzOiBhbnksXG4gICAgYXJnczogQVJHUyxcbiAgICBtZXRob2Q6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55XG4gICk6IENvbnRleHR1YWxpemVkQXJnczxGYWJyaWNDb250cmFjdENvbnRleHQsIEFSR1M+ICYge1xuICAgIHN0dWI6IENoYWluY29kZVN0dWI7XG4gICAgaWRlbnRpdHk6IENsaWVudElkZW50aXR5O1xuICB9O1xuICBzdGF0aWMgb3ZlcnJpZGUgbG9nQ3R4PEFSR1MgZXh0ZW5kcyBhbnlbXT4oXG4gICAgdGhpczogYW55LFxuICAgIGFyZ3M6IEFSR1MsXG4gICAgbWV0aG9kOiAoKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnkpIHwgc3RyaW5nXG4gICk6IENvbnRleHR1YWxpemVkQXJnczxGYWJyaWNDb250cmFjdENvbnRleHQsIEFSR1M+ICYge1xuICAgIHN0dWI6IENoYWluY29kZVN0dWI7XG4gICAgaWRlbnRpdHk6IENsaWVudElkZW50aXR5O1xuICB9IHtcbiAgICBpZiAoYXJncy5sZW5ndGggPCAxKSB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIk5vIGNvbnRleHQgcHJvdmlkZWRcIik7XG4gICAgY29uc3QgY3R4ID0gYXJncy5wb3AoKSBhcyBGYWJyaWNDb250cmFjdENvbnRleHQ7XG5cbiAgICBpZiAoIShjdHggaW5zdGFuY2VvZiBDb250ZXh0KSlcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiTm8gY29udGV4dCBwcm92aWRlZFwiKTtcbiAgICBpZiAoYXJncy5maWx0ZXIoKGEpID0+IGEgaW5zdGFuY2VvZiBDb250ZXh0KS5sZW5ndGggPiAxKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiaGVyZVwiKTtcbiAgICBjb25zdCBsb2cgPSAoXG4gICAgICB0aGlzXG4gICAgICAgID8gY3R4LmxvZ2dlci5mb3IodGhpcykuZm9yKG1ldGhvZClcbiAgICAgICAgOiBjdHgubG9nZ2VyLmNsZWFyKCkuZm9yKHRoaXMpLmZvcihtZXRob2QpXG4gICAgKSBhcyBMb2dnZXJPZjxGYWJyaWNDb250cmFjdENvbnRleHQ+O1xuICAgIHJldHVybiB7XG4gICAgICBjdHg6IGN0eCxcbiAgICAgIGxvZzogbWV0aG9kID8gKGxvZy5mb3IobWV0aG9kKSBhcyBMb2dnZXJPZjxGYWJyaWNDb250cmFjdENvbnRleHQ+KSA6IGxvZyxcbiAgICAgIHN0dWI6IGN0eC5zdHViLFxuICAgICAgaWRlbnRpdHk6IGN0eC5pZGVudGl0eSxcbiAgICAgIGN0eEFyZ3M6IFsuLi5hcmdzLCBjdHhdLFxuICAgIH07XG4gIH1cblxuICBzdGF0aWMgb3ZlcnJpZGUgcGFyc2VFcnJvcjxFIGV4dGVuZHMgQmFzZUVycm9yPihlcnI6IEVycm9yIHwgc3RyaW5nKTogRSB7XG4gICAgLy8gaWYgKFxuICAgIC8vICAgTUlTU0lOR19QUklWQVRFX0RBVEFfUkVHRVgudGVzdChcbiAgICAvLyAgICAgdHlwZW9mIGVyciA9PT0gXCJzdHJpbmdcIiA/IGVyciA6IGVyci5tZXNzYWdlXG4gICAgLy8gICApXG4gICAgLy8gKVxuICAgIC8vICAgcmV0dXJuIG5ldyBVbmF1dGhvcml6ZWRQcml2YXRlRGF0YUFjY2VzcyhlcnIpIGFzIEU7XG4gICAgY29uc3QgbXNnID0gdHlwZW9mIGVyciA9PT0gXCJzdHJpbmdcIiA/IGVyciA6IGVyci5tZXNzYWdlO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoTm90Rm91bmRFcnJvci5uYW1lKSkgcmV0dXJuIG5ldyBOb3RGb3VuZEVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKENvbmZsaWN0RXJyb3IubmFtZSkpIHJldHVybiBuZXcgQ29uZmxpY3RFcnJvcihlcnIpIGFzIEU7XG4gICAgaWYgKG1zZy5pbmNsdWRlcyhCYWRSZXF1ZXN0RXJyb3IubmFtZSkpXG4gICAgICByZXR1cm4gbmV3IEJhZFJlcXVlc3RFcnJvcihlcnIpIGFzIEU7XG4gICAgaWYgKG1zZy5pbmNsdWRlcyhRdWVyeUVycm9yLm5hbWUpKSByZXR1cm4gbmV3IFF1ZXJ5RXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoUGFnaW5nRXJyb3IubmFtZSkpIHJldHVybiBuZXcgUGFnaW5nRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoVW5zdXBwb3J0ZWRFcnJvci5uYW1lKSlcbiAgICAgIHJldHVybiBuZXcgVW5zdXBwb3J0ZWRFcnJvcihlcnIpIGFzIEU7XG4gICAgaWYgKG1zZy5pbmNsdWRlcyhNaWdyYXRpb25FcnJvci5uYW1lKSkgcmV0dXJuIG5ldyBNaWdyYXRpb25FcnJvcihlcnIpIGFzIEU7XG4gICAgaWYgKG1zZy5pbmNsdWRlcyhPYnNlcnZlckVycm9yLm5hbWUpKSByZXR1cm4gbmV3IE9ic2VydmVyRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoQXV0aG9yaXphdGlvbkVycm9yLm5hbWUpKVxuICAgICAgcmV0dXJuIG5ldyBBdXRob3JpemF0aW9uRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoRm9yYmlkZGVuRXJyb3IubmFtZSkpIHJldHVybiBuZXcgRm9yYmlkZGVuRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoQ29ubmVjdGlvbkVycm9yLm5hbWUpKVxuICAgICAgcmV0dXJuIG5ldyBDb25uZWN0aW9uRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoU2VyaWFsaXphdGlvbkVycm9yLm5hbWUpKVxuICAgICAgcmV0dXJuIG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoZXJyKSBhcyBFO1xuICAgIHJldHVybiBuZXcgSW50ZXJuYWxFcnJvcihlcnIpIGFzIEU7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFN0YXRpYyBtZXRob2QgZm9yIGRlY29yYXRpb24gb3ZlcnJpZGVzXG4gICAqIEBzdW1tYXJ5IE92ZXJyaWRlcy9leHRlbmRzIGRlY2FmIGRlY29yYXRpb24gd2l0aCBGYWJyaWMtc3BlY2lmaWMgZnVuY3Rpb25hbGl0eVxuICAgKiBAc3RhdGljXG4gICAqIEBvdmVycmlkZVxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKi9cbiAgc3RhdGljIG92ZXJyaWRlIGRlY29yYXRpb24oKTogdm9pZCB7XG4gICAgc3VwZXIuZGVjb3JhdGlvbigpO1xuICAgIERlY29yYXRpb24uZmxhdm91cmVkQXMoRmFicmljRmxhdm91cilcbiAgICAgIC5mb3IoUGVyc2lzdGVuY2VLZXlzLkNSRUFURURfQlkpXG4gICAgICAuZGVmaW5lKFxuICAgICAgICBvbkNyZWF0ZShjcmVhdGVkQnlPbkZhYnJpY0NyZWF0ZVVwZGF0ZSksXG4gICAgICAgIHByb3BNZXRhZGF0YShQZXJzaXN0ZW5jZUtleXMuQ1JFQVRFRF9CWSwge30pXG4gICAgICApXG4gICAgICAuYXBwbHkoKTtcblxuICAgIERlY29yYXRpb24uZmxhdm91cmVkQXMoRmFicmljRmxhdm91cilcbiAgICAgIC5mb3IoUGVyc2lzdGVuY2VLZXlzLlVQREFURURfQlkpXG4gICAgICAuZGVmaW5lKFxuICAgICAgICBvbkNyZWF0ZVVwZGF0ZShjcmVhdGVkQnlPbkZhYnJpY0NyZWF0ZVVwZGF0ZSksXG4gICAgICAgIHByb3BNZXRhZGF0YShQZXJzaXN0ZW5jZUtleXMuVVBEQVRFRF9CWSwge30pXG4gICAgICApXG4gICAgICAuYXBwbHkoKTtcblxuICAgIERlY29yYXRpb24uZmxhdm91cmVkQXMoRmFicmljRmxhdm91cilcbiAgICAgIC5mb3IoREJLZXlzLklEKVxuICAgICAgLmRlZmluZSh7XG4gICAgICAgIGRlY29yYXRvcjogZnVuY3Rpb24gcGtEZWMoXG4gICAgICAgICAgb3B0aW9uczogU2VxdWVuY2VPcHRpb25zLFxuICAgICAgICAgIGdyb3Vwc29ydD86IEdyb3VwU29ydFxuICAgICAgICApIHtcbiAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gcGtEZWMob2JqOiBhbnksIGF0dHI6IGFueSkge1xuICAgICAgICAgICAgcmV0dXJuIGFwcGx5KFxuICAgICAgICAgICAgICByZXF1aXJlZCgpLFxuICAgICAgICAgICAgICByZWFkb25seSgpLFxuICAgICAgICAgICAgICBwcm9wTWV0YWRhdGEoTWV0YWRhdGEua2V5KERCS2V5cy5JRCwgYXR0ciksIG9wdGlvbnMpLFxuICAgICAgICAgICAgICBvbkNyZWF0ZShwa0ZhYnJpY09uQ3JlYXRlIGFzIGFueSwgb3B0aW9ucywgZ3JvdXBzb3J0KVxuICAgICAgICAgICAgKShvYmosIGF0dHIpO1xuICAgICAgICAgIH07XG4gICAgICAgIH0sXG4gICAgICB9IGFzIGFueSlcbiAgICAgIC5hcHBseSgpO1xuXG4gICAgRGVjb3JhdGlvbi5mbGF2b3VyZWRBcyhGYWJyaWNGbGF2b3VyKVxuICAgICAgLmZvcihQZXJzaXN0ZW5jZUtleXMuQ09MVU1OKVxuICAgICAgLmV4dGVuZChGYWJyaWNQcm9wZXJ0eSgpKVxuICAgICAgLmFwcGx5KCk7XG5cbiAgICBEZWNvcmF0aW9uLmZsYXZvdXJlZEFzKEZhYnJpY0ZsYXZvdXIpXG4gICAgICAuZm9yKFBlcnNpc3RlbmNlS2V5cy5UQUJMRSlcbiAgICAgIC5leHRlbmQoZnVuY3Rpb24gdGFibGUob2JqOiBhbnkpIHtcbiAgICAgICAgLy8gY29uc3QgY2hhaW46IGFueVtdID0gW107XG5cbiAgICAgICAgLy8gbGV0IGN1cnJlbnQgPSBvYmo7XG5cbiAgICAgICAgLy8gZG8ge1xuICAgICAgICAvLyAgIGNoYWluLnB1c2goY3VycmVudCk7XG4gICAgICAgIC8vICAgY29uc29sZS5sb2coYEZvdW5kIGNsYXNzOiAke2N1cnJlbnR9YCk7XG4gICAgICAgIC8vIH0gd2hpbGUgKGN1cnJlbnQgJiYgY3VycmVudCAhPT0gT2JqZWN0LnByb3RvdHlwZSk7XG5cbiAgICAgICAgLy8gZG8ge1xuICAgICAgICAvLyAgIGN1cnJlbnQgPSBjaGFpbi5wb3AoKTtcbiAgICAgICAgLy8gICBjb25zb2xlLmxvZyhgQXBwbHlpbmcgQE9iamVjdCgpIHRvIGNsYXNzOiAke2N1cnJlbnR9YCk7XG4gICAgICAgIC8vICAgLy9UT0RPOiBUSElTIElTIE5PVCBXT1JLSU5HIEFORCBUSFJPV1MgRVJST1JcbiAgICAgICAgLy8gICAvLyBGYWJyaWNPYmplY3QoKShjdXJyZW50KTtcbiAgICAgICAgLy8gfSB3aGlsZSAoY2hhaW4ubGVuZ3RoID4gMSk7XG5cbiAgICAgICAgcmV0dXJuIEZhYnJpY09iamVjdCgpKG9iaik7XG4gICAgICB9KVxuICAgICAgLmFwcGx5KCk7XG5cbiAgICBmdW5jdGlvbiBvbmVUb09uZURlYzxNIGV4dGVuZHMgTW9kZWw+KFxuICAgICAgY2xheno6IENvbnN0cnVjdG9yPE0+IHwgKCgpID0+IENvbnN0cnVjdG9yPE0+KSxcbiAgICAgIGNhc2NhZGU6IENhc2NhZGVNZXRhZGF0YSxcbiAgICAgIHBvcHVsYXRlOiBib29sZWFuLFxuICAgICAgam9pbkNvbHVtbk9wdHM/OiBKb2luQ29sdW1uT3B0aW9ucyxcbiAgICAgIGZrPzogc3RyaW5nXG4gICAgKSB7XG4gICAgICBjb25zdCBtZXRhOiBSZWxhdGlvbnNNZXRhZGF0YSA9IHtcbiAgICAgICAgY2xhc3M6IGNsYXp6LFxuICAgICAgICBjYXNjYWRlOiBjYXNjYWRlLFxuICAgICAgICBwb3B1bGF0ZTogcG9wdWxhdGUsXG4gICAgICB9O1xuICAgICAgaWYgKGpvaW5Db2x1bW5PcHRzKSBtZXRhLmpvaW5UYWJsZSA9IGpvaW5Db2x1bW5PcHRzO1xuICAgICAgaWYgKGZrKSBtZXRhLm5hbWUgPSBmaztcbiAgICAgIHJldHVybiBhcHBseShcbiAgICAgICAgcHJvcCgpLFxuICAgICAgICByZWxhdGlvbihQZXJzaXN0ZW5jZUtleXMuT05FX1RPX09ORSwgbWV0YSksXG4gICAgICAgIHR5cGUoW2NsYXp6LCBTdHJpbmcsIE51bWJlciwgQmlnSW50XSksXG4gICAgICAgIG9uQ3JlYXRlKG9uZVRvT25lT25DcmVhdGUgYXMgYW55LCBtZXRhKSxcbiAgICAgICAgb25VcGRhdGUob25lVG9PbmVPblVwZGF0ZSBhcyBhbnksIG1ldGEpLFxuICAgICAgICBvbkRlbGV0ZShvbmVUb09uZU9uRGVsZXRlIGFzIGFueSwgbWV0YSksXG4gICAgICAgIGFmdGVyQW55KHBvcCwgbWV0YSksXG4gICAgICAgIHByb3BNZXRhZGF0YShQZXJzaXN0ZW5jZUtleXMuT05FX1RPX09ORSwgbWV0YSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgRGVjb3JhdGlvbi5mbGF2b3VyZWRBcyhGYWJyaWNGbGF2b3VyKVxuICAgICAgLmZvcihQZXJzaXN0ZW5jZUtleXMuT05FX1RPX09ORSlcbiAgICAgIC5kZWZpbmUoe1xuICAgICAgICBkZWNvcmF0b3I6IG9uZVRvT25lRGVjLFxuICAgICAgfSBhcyBhbnkpXG4gICAgICAuYXBwbHkoKTtcblxuICAgIGZ1bmN0aW9uIG9uZVRvTWFueURlYzxNIGV4dGVuZHMgTW9kZWw+KFxuICAgICAgY2xheno6IENvbnN0cnVjdG9yPE0+IHwgKCgpID0+IENvbnN0cnVjdG9yPE0+KSxcbiAgICAgIGNhc2NhZGU6IENhc2NhZGVNZXRhZGF0YSxcbiAgICAgIHBvcHVsYXRlOiBib29sZWFuLFxuICAgICAgam9pblRhYmxlT3B0cz86IEpvaW5UYWJsZU9wdGlvbnMgfCBKb2luVGFibGVNdWx0aXBsZUNvbHVtbnNPcHRpb25zLFxuICAgICAgZms/OiBzdHJpbmdcbiAgICApIHtcbiAgICAgIGNvbnN0IG1ldGFkYXRhOiBSZWxhdGlvbnNNZXRhZGF0YSA9IHtcbiAgICAgICAgY2xhc3M6IGNsYXp6LFxuICAgICAgICBjYXNjYWRlOiBjYXNjYWRlLFxuICAgICAgICBwb3B1bGF0ZTogcG9wdWxhdGUsXG4gICAgICB9O1xuICAgICAgaWYgKGpvaW5UYWJsZU9wdHMpIG1ldGFkYXRhLmpvaW5UYWJsZSA9IGpvaW5UYWJsZU9wdHM7XG4gICAgICBpZiAoZmspIG1ldGFkYXRhLm5hbWUgPSBmaztcbiAgICAgIHJldHVybiBhcHBseShcbiAgICAgICAgcHJvcCgpLFxuICAgICAgICByZWxhdGlvbihQZXJzaXN0ZW5jZUtleXMuT05FX1RPX01BTlksIG1ldGFkYXRhKSxcbiAgICAgICAgbGlzdChbY2xhenogYXMgQ29uc3RydWN0b3I8TT4sIFN0cmluZywgTnVtYmVyXSksXG4gICAgICAgIG9uQ3JlYXRlKG9uZVRvTWFueU9uQ3JlYXRlIGFzIGFueSwgbWV0YWRhdGEpLFxuICAgICAgICBvblVwZGF0ZShvbmVUb01hbnlPblVwZGF0ZSwgbWV0YWRhdGEpLFxuICAgICAgICBvbkRlbGV0ZShvbmVUb01hbnlPbkRlbGV0ZSBhcyBhbnksIG1ldGFkYXRhKSxcbiAgICAgICAgYWZ0ZXJBbnkocG9wLCBtZXRhZGF0YSksXG4gICAgICAgIHByb3BNZXRhZGF0YShQZXJzaXN0ZW5jZUtleXMuT05FX1RPX01BTlksIG1ldGFkYXRhKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBEZWNvcmF0aW9uLmZvcihQZXJzaXN0ZW5jZUtleXMuT05FX1RPX01BTlkpXG4gICAgICAuZGVmaW5lKHtcbiAgICAgICAgZGVjb3JhdG9yOiBvbmVUb01hbnlEZWMsXG4gICAgICB9IGFzIGFueSlcbiAgICAgIC5hcHBseSgpO1xuICB9XG59XG5cbkZhYnJpY0NvbnRyYWN0QWRhcHRlci5kZWNvcmF0aW9uKCk7XG5BZGFwdGVyLnNldEN1cnJlbnQoRmFicmljRmxhdm91cik7XG4iLCIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzICovXG5pbXBvcnQgeyBKU09OU2VyaWFsaXplciwgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERldGVybWluaXN0aWMgSlNPTiBzZXJpYWxpemVyIGZvciBGYWJyaWMgbW9kZWxzXG4gKiBAc3VtbWFyeSBFbnN1cmVzIHN0YWJsZSwgZGV0ZXJtaW5pc3RpYyBKU09OIG91dHB1dCBieSBzb3J0aW5nIG9iamVjdCBrZXlzIHJlY3Vyc2l2ZWx5IGJlZm9yZSBzdHJpbmdpZmljYXRpb24sIHdoaWNoIGlzIGltcG9ydGFudCBmb3IgRmFicmljIGVuZG9yc2VtZW50IGFuZCBoYXNoaW5nLiBFeHRlbmRzIEpTT05TZXJpYWxpemVyIHRvIHBsdWcgaW50byBleGlzdGluZyBEZWNhZiBtb2RlbCBzZXJpYWxpemF0aW9uIGZsb3cuXG4gKiBAdGVtcGxhdGUgTSAtIFRoZSBEZWNhZiBNb2RlbCBzdWJ0eXBlIHNlcmlhbGl6ZWQgYnkgdGhpcyBpbnN0YW5jZVxuICogQHBhcmFtIHt2b2lkfSBbY29uc3RydWN0b3JdIE5vIHB1YmxpYyBjb25zdHJ1Y3RvciBhcmd1bWVudHNcbiAqIEBjbGFzcyBEZXRlcm1pbmlzdGljU2VyaWFsaXplclxuICogQGV4YW1wbGVcbiAqIGNvbnN0IHNlcmlhbGl6ZXIgPSBuZXcgRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXI8TXlNb2RlbD4oKTtcbiAqIGNvbnN0IGpzb24gPSBzZXJpYWxpemVyLnNlcmlhbGl6ZShtb2RlbCk7XG4gKiBjb25zdCByZWJ1aWx0ID0gc2VyaWFsaXplci5kZXNlcmlhbGl6ZShqc29uKTtcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IERTIGFzIERldGVybWluaXN0aWNTZXJpYWxpemVyXG4gKiAgIENhbGxlci0+PkRTOiBzZXJpYWxpemUobW9kZWwpXG4gKiAgIERTLT4+RFM6IHByZVNlcmlhbGl6ZShtb2RlbClcbiAqICAgRFMtPj5EUzogc29ydC1rZXlzLXJlY3Vyc2l2ZVxuICogICBEUy0+PkRTOiBqc29uLXN0cmluZ2lmeS1kZXRlcm1pbmlzdGljXG4gKiAgIERTLS0+PkNhbGxlcjogc3RyaW5nXG4gKiAgIENhbGxlci0+PkRTOiBkZXNlcmlhbGl6ZShzdHJpbmcpXG4gKiAgIERTLS0+PkNhbGxlcjogbW9kZWxcbiAqL1xuZXhwb3J0IGNsYXNzIERldGVybWluaXN0aWNTZXJpYWxpemVyPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4+IGV4dGVuZHMgSlNPTlNlcmlhbGl6ZXI8TT4ge1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBEZXNlcmlhbGl6ZSBhIEpTT04gc3RyaW5nIGludG8gYSBtb2RlbCBpbnN0YW5jZVxuICAgKiBAc3VtbWFyeSBEZWxlZ2F0ZXMgdG8gdGhlIGJhc2UgSlNPTlNlcmlhbGl6ZXIgaW1wbGVtZW50YXRpb24gdG8gcmVidWlsZCB0aGUgbW9kZWxcbiAgICogQHBhcmFtIHtzdHJpbmd9IHN0ciAtIFRoZSBKU09OIHN0cmluZyB0byBkZXNlcmlhbGl6ZVxuICAgKiBAcmV0dXJuIHtNfSBUaGUgcmVjb25zdHJ1Y3RlZCBtb2RlbCBpbnN0YW5jZVxuICAgKi9cbiAgb3ZlcnJpZGUgZGVzZXJpYWxpemUoc3RyOiBzdHJpbmcpOiBNIHtcbiAgICByZXR1cm4gc3VwZXIuZGVzZXJpYWxpemUoc3RyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU2VyaWFsaXplIGEgbW9kZWwgaW50byBhIGRldGVybWluaXN0aWMgSlNPTiBzdHJpbmdcbiAgICogQHN1bW1hcnkgUHJlcGFyZXMgdGhlIG1vZGVsIHdpdGggcHJlU2VyaWFsaXplLCBzb3J0cyBrZXlzIHJlY3Vyc2l2ZWx5LCBhbmQgc3RyaW5naWZpZXMgZGV0ZXJtaW5pc3RpY2FsbHkgZm9yIHN0YWJsZSBvcmRlcmluZ1xuICAgKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlIHRvIHNlcmlhbGl6ZVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IERldGVybWluaXN0aWMgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGUgbW9kZWxcbiAgICovXG4gIG92ZXJyaWRlIHNlcmlhbGl6ZShtb2RlbDogTSk6IHN0cmluZyB7XG4gICAgY29uc3Qgc3RyaW5naWZ5ID0gcmVxdWlyZShcImpzb24tc3RyaW5naWZ5LWRldGVybWluaXN0aWNcIik7XG4gICAgY29uc3Qgc29ydEtleXNSZWN1cnNpdmUgPSByZXF1aXJlKFwic29ydC1rZXlzLXJlY3Vyc2l2ZVwiKTtcbiAgICByZXR1cm4gc3RyaW5naWZ5KHNvcnRLZXlzUmVjdXJzaXZlKHRoaXMucHJlU2VyaWFsaXplKG1vZGVsKSkpO1xuICB9XG59XG4iLCJpbXBvcnQgeyBGYWJyaWNDb250cmFjdEFkYXB0ZXIgfSBmcm9tIFwiLi4vQ29udHJhY3RBZGFwdGVyXCI7XG5pbXBvcnQgeyBDb250cmFjdCwgQ29udGV4dCBhcyBDdHggfSBmcm9tIFwiZmFicmljLWNvbnRyYWN0LWFwaVwiO1xuaW1wb3J0IHsgTW9kZWwsIFNlcmlhbGl6ZXIgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQge1xuICBDb25kaXRpb24sXG4gIENvbnRleHQsXG4gIENvbnRleHR1YWxpemVkQXJncyxcbiAgTG9nZ2VyT2YsXG4gIE9yZGVyRGlyZWN0aW9uLFxuICBSZXBvc2l0b3J5LFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeSB9IGZyb20gXCIuLi9GYWJyaWNDb250cmFjdFJlcG9zaXRvcnlcIjtcbmltcG9ydCB7IERldGVybWluaXN0aWNTZXJpYWxpemVyIH0gZnJvbSBcIi4uLy4uL3NoYXJlZC9EZXRlcm1pbmlzdGljU2VyaWFsaXplclwiO1xuaW1wb3J0IHsgTWFuZ29RdWVyeSB9IGZyb20gXCJAZGVjYWYtdHMvZm9yLWNvdWNoZGJcIjtcbmltcG9ydCB7IENoZWNrYWJsZSwgaGVhbHRoY2hlY2sgfSBmcm9tIFwiLi4vLi4vc2hhcmVkL2ludGVyZmFjZXMvQ2hlY2thYmxlXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RDb250ZXh0IH0gZnJvbSBcIi4uL0NvbnRyYWN0Q29udGV4dFwiO1xuaW1wb3J0IHtcbiAgQnVsa0NydWRPcGVyYXRpb25LZXlzLFxuICBJbnRlcm5hbEVycm9yLFxuICBPcGVyYXRpb25LZXlzLFxuICBQcmltYXJ5S2V5VHlwZSxcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBDaGFpbmNvZGVTdHViLCBDbGllbnRJZGVudGl0eSB9IGZyb20gXCJmYWJyaWMtc2hpbS1hcGlcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQmFzZSBjb250cmFjdCBjbGFzcyBmb3IgQ1JVRCBvcGVyYXRpb25zIGluIEZhYnJpYyBjaGFpbmNvZGVcbiAqIEBzdW1tYXJ5IFByb3ZpZGVzIHN0YW5kYXJkIGNyZWF0ZSwgcmVhZCwgdXBkYXRlLCBhbmQgZGVsZXRlIG9wZXJhdGlvbnMgZm9yIG1vZGVscyBpbiBGYWJyaWMgY2hhaW5jb2RlXG4gKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAY2xhc3MgRmFicmljQ3J1ZENvbnRyYWN0XG4gKiBAZXh0ZW5kcyB7Q29udHJhY3R9XG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gRGVmaW5lIGEgbW9kZWxcbiAqIEB0YWJsZSgnYXNzZXRzJylcbiAqIGNsYXNzIEFzc2V0IGV4dGVuZHMgTW9kZWwge1xuICogICBAaWQoKVxuICogICBpZDogc3RyaW5nO1xuICpcbiAqICAgQHByb3BlcnR5KClcbiAqICAgZGF0YTogc3RyaW5nO1xuICogfVxuICpcbiAqIC8vIENyZWF0ZSBhIGNvbnRyYWN0IHRoYXQgZXh0ZW5kcyBGYWJyaWNDcnVkQ29udHJhY3RcbiAqIGV4cG9ydCBjbGFzcyBBc3NldENvbnRyYWN0IGV4dGVuZHMgRmFicmljQ3J1ZENvbnRyYWN0PEFzc2V0PiB7XG4gKiAgIGNvbnN0cnVjdG9yKCkge1xuICogICAgIHN1cGVyKCdBc3NldENvbnRyYWN0JywgQXNzZXQpO1xuICogICB9XG4gKlxuICogICAvLyBBZGQgY3VzdG9tIG1ldGhvZHMgYXMgbmVlZGVkXG4gKiAgIGFzeW5jIGdldEFzc2V0SGlzdG9yeShjdHg6IENvbnRleHQsIGlkOiBzdHJpbmcpOiBQcm9taXNlPGFueVtdPiB7XG4gKiAgICAgLy8gQ3VzdG9tIGltcGxlbWVudGF0aW9uXG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDbGllbnRcbiAqICAgcGFydGljaXBhbnQgQ29udHJhY3RcbiAqICAgcGFydGljaXBhbnQgUmVwb3NpdG9yeVxuICogICBwYXJ0aWNpcGFudCBBZGFwdGVyXG4gKiAgIHBhcnRpY2lwYW50IFN0YXRlREJcbiAqXG4gKiAgIENsaWVudC0+PkNvbnRyYWN0OiBjcmVhdGUoY3R4LCBtb2RlbClcbiAqICAgQ29udHJhY3QtPj5SZXBvc2l0b3J5OiByZXBvc2l0b3J5KGN0eClcbiAqICAgQ29udHJhY3QtPj5SZXBvc2l0b3J5OiBjcmVhdGUobW9kZWwsIGN0eClcbiAqICAgUmVwb3NpdG9yeS0+PkFkYXB0ZXI6IGNyZWF0ZSh0YWJsZU5hbWUsIGlkLCByZWNvcmQsIHRyYW5zaWVudCwgY3R4KVxuICogICBBZGFwdGVyLT4+U3RhdGVEQjogcHV0U3RhdGUoaWQsIHNlcmlhbGl6ZWREYXRhKVxuICogICBTdGF0ZURCLS0+PkFkYXB0ZXI6IFN1Y2Nlc3NcbiAqICAgQWRhcHRlci0tPj5SZXBvc2l0b3J5OiByZWNvcmRcbiAqICAgUmVwb3NpdG9yeS0tPj5Db250cmFjdDogbW9kZWxcbiAqICAgQ29udHJhY3QtLT4+Q2xpZW50OiBtb2RlbFxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgRmFicmljQ3J1ZENvbnRyYWN0PE0gZXh0ZW5kcyBNb2RlbD5cbiAgZXh0ZW5kcyBDb250cmFjdFxuICBpbXBsZW1lbnRzIENoZWNrYWJsZVxue1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNoYXJlZCBhZGFwdGVyIGluc3RhbmNlIGZvciBhbGwgY29udHJhY3QgaW5zdGFuY2VzXG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIGFkYXB0ZXI6IEZhYnJpY0NvbnRyYWN0QWRhcHRlciA9IG5ldyBGYWJyaWNDb250cmFjdEFkYXB0ZXIoKTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgcmVwbzogRmFicmljQ29udHJhY3RSZXBvc2l0b3J5PE0+O1xuXG4gIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgc2VyaWFsaXplciA9IG5ldyBEZXRlcm1pbmlzdGljU2VyaWFsaXplcigpO1xuXG4gIHByb3RlY3RlZCBpbml0aWFsaXplZDogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIG5ldyBGYWJyaWNDcnVkQ29udHJhY3QgaW5zdGFuY2VcbiAgICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgYSBjb250cmFjdCB3aXRoIGEgbmFtZSBhbmQgbW9kZWwgY2xhc3NcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgY29udHJhY3RcbiAgICogQHBhcmFtIHtDb25zdHJ1Y3RvcjxNPn0gY2xhenogLSBUaGUgbW9kZWwgY29uc3RydWN0b3JcbiAgICovXG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGNsYXp6OiBDb25zdHJ1Y3RvcjxNPlxuICApIHtcbiAgICBzdXBlcihuYW1lKTtcbiAgICB0aGlzLnJlcG8gPSBSZXBvc2l0b3J5LmZvck1vZGVsKGNsYXp6KTtcbiAgfVxuXG4gIGFzeW5jIGxpc3RCeShcbiAgICBjdHg6IEN0eCB8IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgICBrZXk6IHN0cmluZyB8IGtleW9mIE0sXG4gICAgb3JkZXI6IHN0cmluZyxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApIHtcbiAgICBjb25zdCB7IGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLmxpc3RCeSk7XG4gICAgcmV0dXJuIHRoaXMucmVwby5saXN0QnkoXG4gICAgICBrZXkgYXMga2V5b2YgTSxcbiAgICAgIG9yZGVyIGFzIE9yZGVyRGlyZWN0aW9uLFxuICAgICAgLi4uY3R4QXJnc1xuICAgICk7XG4gIH1cblxuICBhc3luYyBwYWdpbmF0ZUJ5KFxuICAgIGN0eDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIGtleTogc3RyaW5nIHwga2V5b2YgTSxcbiAgICBvcmRlcjogc3RyaW5nLFxuICAgIHNpemU6IG51bWJlcixcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApIHtcbiAgICBjb25zdCB7IGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLnBhZ2luYXRlQnkpO1xuICAgIHJldHVybiB0aGlzLnJlcG8ucGFnaW5hdGVCeShrZXkgYXMga2V5b2YgTSwgb3JkZXIgYXMgYW55LCBzaXplLCAuLi5jdHhBcmdzKTtcbiAgfVxuXG4gIGFzeW5jIGZpbmRPbmVCeShcbiAgICBjdHg6IEN0eCB8IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgICBrZXk6IHN0cmluZyB8IGtleW9mIE0sXG4gICAgdmFsdWU6IGFueSxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApIHtcbiAgICBjb25zdCB7IGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLmZpbmRPbmVCeSk7XG4gICAgcmV0dXJuIHRoaXMucmVwby5maW5kT25lQnkoa2V5IGFzIGtleW9mIE0sIHZhbHVlLCAuLi5jdHhBcmdzKTtcbiAgfVxuXG4gIGFzeW5jIHN0YXRlbWVudChcbiAgICBjdHg6IEN0eCB8IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgICBtZXRob2Q6IHN0cmluZyxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApIHtcbiAgICBjb25zdCB7IGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLnN0YXRlbWVudCk7XG4gICAgcmV0dXJuIHRoaXMucmVwby5zdGF0ZW1lbnQobWV0aG9kLCAuLi5jdHhBcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIHNpbmdsZSBtb2RlbCBpbiB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgY3JlYXRlIG1ldGhvZFxuICAgKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICAgKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIHRvIGNyZWF0ZVxuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgICogQHJldHVybiB7UHJvbWlzZTxNPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGNyZWF0ZWQgbW9kZWxcbiAgICovXG4gIGFzeW5jIGNyZWF0ZShcbiAgICBjdHg6IEN0eCB8IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgICBtb2RlbDogc3RyaW5nIHwgTSxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPHN0cmluZyB8IE0+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoWy4uLmFyZ3MsIGN0eF0sIHRoaXMuY3JlYXRlKTtcbiAgICBsb2cuaW5mbyhgQ09OVFJBQ1QgQ1JFQVRFLCAke2N0eEFyZ3N9YCk7XG5cbiAgICBpZiAodHlwZW9mIG1vZGVsID09PSBcInN0cmluZ1wiKSBtb2RlbCA9IHRoaXMuZGVzZXJpYWxpemU8TT4obW9kZWwpIGFzIE07XG5cbiAgICBsb2cuaW5mbyhgQ3JlYXRpbmcgbW9kZWw6ICR7SlNPTi5zdHJpbmdpZnkobW9kZWwpfWApO1xuXG4gICAgY29uc3QgdHJhbnNpZW50ID0gdGhpcy5nZXRUcmFuc2llbnREYXRhKGN0eCk7XG5cbiAgICBsb2cuaW5mbyhgTWVyZ2luZyB0cmFuc2llbnQgZGF0YS4uLmApO1xuICAgIG1vZGVsID0gTW9kZWwubWVyZ2UobW9kZWwsIHRyYW5zaWVudCwgdGhpcy5jbGF6eikgYXMgTTtcblxuICAgIHJldHVybiB0aGlzLnJlcG8uY3JlYXRlKG1vZGVsLCAuLi5jdHhBcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVhZHMgYSBzaW5nbGUgbW9kZWwgZnJvbSB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgcmVhZCBtZXRob2RcbiAgICogQHBhcmFtIHtDdHh9IGN0eCAtIFRoZSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRleHRcbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudW1iZXJ9IGtleSAtIFRoZSBrZXkgb2YgdGhlIG1vZGVsIHRvIHJlYWRcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSByZXRyaWV2ZWQgbW9kZWxcbiAgICovXG4gIGFzeW5jIHJlYWQoXG4gICAgY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gICAga2V5OiBQcmltYXJ5S2V5VHlwZSB8IHN0cmluZyxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPE0gfCBzdHJpbmc+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoWy4uLmFyZ3MsIGN0eF0sIHRoaXMucmVhZCk7XG5cbiAgICBsb2cuaW5mbyhgcmVhZGluZyBlbnRyeSB3aXRoIHBrICR7a2V5fSBgKTtcblxuICAgIHJldHVybiB0aGlzLnJlcG8ucmVhZChrZXksIC4uLmN0eEFyZ3MpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldFRyYW5zaWVudERhdGEoY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQpOiBhbnkge1xuICAgIGNvbnN0IHRyYW5zaWVudE1hcCA9IGN0eC5zdHViLmdldFRyYW5zaWVudCgpO1xuICAgIGxldCB0cmFuc2llbnQ6IGFueSA9IHt9O1xuXG4gICAgaWYgKHRyYW5zaWVudE1hcC5oYXMoKHRoaXMucmVwbyBhcyBhbnkpLnRhYmxlTmFtZSkpIHtcbiAgICAgIHRyYW5zaWVudCA9IEpTT04ucGFyc2UoXG4gICAgICAgICh0cmFuc2llbnRNYXAuZ2V0KCh0aGlzLnJlcG8gYXMgYW55KS50YWJsZU5hbWUpIGFzIEJ1ZmZlcik/LnRvU3RyaW5nKFxuICAgICAgICAgIFwidXRmOFwiXG4gICAgICAgICkgYXMgc3RyaW5nXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiB0cmFuc2llbnQ7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFVwZGF0ZXMgYSBzaW5nbGUgbW9kZWwgaW4gdGhlIHN0YXRlIGRhdGFiYXNlXG4gICAqIEBzdW1tYXJ5IERlbGVnYXRlcyB0byB0aGUgcmVwb3NpdG9yeSdzIHVwZGF0ZSBtZXRob2RcbiAgICogQHBhcmFtIHtDdHh9IGN0eCAtIFRoZSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRleHRcbiAgICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCB0byB1cGRhdGVcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIG1vZGVsXG4gICAqL1xuICBhc3luYyB1cGRhdGUoXG4gICAgY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gICAgbW9kZWw6IHN0cmluZyB8IE0sXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxzdHJpbmcgfCBNPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLnVwZGF0ZSk7XG5cbiAgICBpZiAodHlwZW9mIG1vZGVsID09PSBcInN0cmluZ1wiKSBtb2RlbCA9IHRoaXMuZGVzZXJpYWxpemU8TT4obW9kZWwpIGFzIE07XG5cbiAgICBsb2cuaW5mbyhgVXBkYXRpbmcgbW9kZWw6ICR7SlNPTi5zdHJpbmdpZnkobW9kZWwpfWApO1xuXG4gICAgY29uc3QgdHJhbnNpZW50ID0gdGhpcy5nZXRUcmFuc2llbnREYXRhKGN0eCk7XG5cbiAgICBsb2cuaW5mbyhgTWVyZ2luZyB0cmFuc2llbnQgZGF0YS4uLmApO1xuICAgIG1vZGVsID0gTW9kZWwubWVyZ2UobW9kZWwsIHRyYW5zaWVudCwgdGhpcy5jbGF6eikgYXMgTTtcbiAgICByZXR1cm4gdGhpcy5yZXBvLnVwZGF0ZShtb2RlbCwgLi4uY3R4QXJncyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIERlbGV0ZXMgYSBzaW5nbGUgbW9kZWwgZnJvbSB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgZGVsZXRlIG1ldGhvZFxuICAgKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICAgKiBAcGFyYW0ge3N0cmluZyB8IG51bWJlcn0ga2V5IC0gVGhlIGtleSBvZiB0aGUgbW9kZWwgdG8gZGVsZXRlXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50c1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPE0+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZGVsZXRlZCBtb2RlbFxuICAgKi9cbiAgYXN5bmMgZGVsZXRlKFxuICAgIGN0eDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIGtleTogUHJpbWFyeUtleVR5cGUgfCBzdHJpbmcsXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxNIHwgc3RyaW5nPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLmRlbGV0ZSk7XG4gICAgbG9nLmluZm8oYGRlbGV0aW5nIGVudHJ5IHdpdGggcGsgJHtrZXl9IGApO1xuICAgIHJldHVybiB0aGlzLnJlcG8uZGVsZXRlKFN0cmluZyhrZXkpLCAuLi5jdHhBcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVsZXRlcyBtdWx0aXBsZSBtb2RlbHMgZnJvbSB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgZGVsZXRlQWxsIG1ldGhvZFxuICAgKiBAcGFyYW0ge3N0cmluZ1tdIHwgbnVtYmVyW119IGtleXMgLSBUaGUga2V5cyBvZiB0aGUgbW9kZWxzIHRvIGRlbGV0ZVxuICAgKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgICogQHJldHVybiB7UHJvbWlzZTxNW10+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZGVsZXRlZCBtb2RlbHNcbiAgICovXG4gIGFzeW5jIGRlbGV0ZUFsbChcbiAgICBjdHg6IEN0eCB8IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgICBrZXlzOiBQcmltYXJ5S2V5VHlwZVtdIHwgc3RyaW5nLFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8TVtdIHwgc3RyaW5nPiB7XG4gICAgY29uc3QgeyBjdHhBcmdzIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbLi4uYXJncywgY3R4XSwgdGhpcy5yZWFkQWxsKTtcbiAgICBpZiAodHlwZW9mIGtleXMgPT09IFwic3RyaW5nXCIpIGtleXMgPSBKU09OLnBhcnNlKGtleXMpIGFzIHN0cmluZ1tdO1xuICAgIHJldHVybiB0aGlzLnJlcG8uZGVsZXRlQWxsKGtleXMsIC4uLmN0eEFyZ3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZWFkcyBtdWx0aXBsZSBtb2RlbHMgZnJvbSB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgcmVhZEFsbCBtZXRob2RcbiAgICogQHBhcmFtIHtDdHh9IGN0eCAtIFRoZSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRleHRcbiAgICogQHBhcmFtIHtzdHJpbmdbXSB8IG51bWJlcltdfSBrZXlzIC0gVGhlIGtleXMgb2YgdGhlIG1vZGVscyB0byByZWFkXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50c1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1bXT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSByZXRyaWV2ZWQgbW9kZWxzXG4gICAqL1xuICBhc3luYyByZWFkQWxsKFxuICAgIGN0eDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIGtleXM6IFByaW1hcnlLZXlUeXBlW10gfCBzdHJpbmcsXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxNW10gfCBzdHJpbmc+IHtcbiAgICBjb25zdCB7IGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLnJlYWRBbGwpO1xuICAgIGlmICh0eXBlb2Yga2V5cyA9PT0gXCJzdHJpbmdcIikga2V5cyA9IEpTT04ucGFyc2Uoa2V5cykgYXMgc3RyaW5nW107XG4gICAgcmV0dXJuIHRoaXMucmVwby5yZWFkQWxsKGtleXMsIC4uLmN0eEFyZ3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIG11bHRpcGxlIG1vZGVscyBpbiB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgdXBkYXRlQWxsIG1ldGhvZFxuICAgKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICAgKiBAcGFyYW0ge01bXX0gbW9kZWxzIC0gVGhlIG1vZGVscyB0byB1cGRhdGVcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TVtdPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWQgbW9kZWxzXG4gICAqL1xuICBhc3luYyB1cGRhdGVBbGwoXG4gICAgY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gICAgbW9kZWxzOiBzdHJpbmcgfCBNW10sXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxzdHJpbmcgfCBNW10+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoWy4uLmFyZ3MsIGN0eF0sIHRoaXMudXBkYXRlQWxsKTtcbiAgICBpZiAodHlwZW9mIG1vZGVscyA9PT0gXCJzdHJpbmdcIilcbiAgICAgIG1vZGVscyA9IChKU09OLnBhcnNlKG1vZGVscykgYXMgW10pXG4gICAgICAgIC5tYXAoKG0pID0+IHRoaXMuZGVzZXJpYWxpemUobSkpXG4gICAgICAgIC5tYXAoKG0pID0+IG5ldyB0aGlzLmNsYXp6KG0pKSBhcyBhbnk7XG5cbiAgICBsb2cuaW5mbyhgdXBkYXRpbmcgJHttb2RlbHMubGVuZ3RofSBlbnRyaWVzIHRvIHRoZSB0YWJsZWApO1xuICAgIHJldHVybiB0aGlzLnJlcG8udXBkYXRlQWxsKG1vZGVscyBhcyB1bmtub3duIGFzIE1bXSwgLi4uY3R4QXJncyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV4ZWN1dGVzIGEgcXVlcnkgd2l0aCB0aGUgc3BlY2lmaWVkIGNvbmRpdGlvbnMgYW5kIG9wdGlvbnMuXG4gICAqIEBzdW1tYXJ5IFByb3ZpZGVzIGEgc2ltcGxpZmllZCB3YXkgdG8gcXVlcnkgdGhlIGRhdGFiYXNlIHdpdGggY29tbW9uIHF1ZXJ5IHBhcmFtZXRlcnMuXG4gICAqIEBwYXJhbSB7Q29uZGl0aW9uPE0+fSBjb25kaXRpb24gLSBUaGUgY29uZGl0aW9uIHRvIGZpbHRlciByZWNvcmRzLlxuICAgKiBAcGFyYW0gb3JkZXJCeSAtIFRoZSBmaWVsZCB0byBvcmRlciByZXN1bHRzIGJ5LlxuICAgKiBAcGFyYW0ge09yZGVyRGlyZWN0aW9ufSBbb3JkZXI9T3JkZXJEaXJlY3Rpb24uQVNDXSAtIFRoZSBzb3J0IGRpcmVjdGlvbi5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFtsaW1pdF0gLSBPcHRpb25hbCBtYXhpbXVtIG51bWJlciBvZiByZXN1bHRzIHRvIHJldHVybi5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFtza2lwXSAtIE9wdGlvbmFsIG51bWJlciBvZiByZXN1bHRzIHRvIHNraXAuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TVtdPn0gVGhlIHF1ZXJ5IHJlc3VsdHMgYXMgbW9kZWwgaW5zdGFuY2VzLlxuICAgKi9cbiAgYXN5bmMgcXVlcnkoXG4gICAgY29udGV4dDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIGNvbmRpdGlvbjogQ29uZGl0aW9uPE0+IHwgc3RyaW5nLFxuICAgIG9yZGVyQnk6IHN0cmluZyB8IGtleW9mIE0sXG4gICAgb3JkZXI6IE9yZGVyRGlyZWN0aW9uIHwgc3RyaW5nID0gT3JkZXJEaXJlY3Rpb24uQVNDLFxuICAgIGxpbWl0PzogbnVtYmVyLFxuICAgIHNraXA/OiBudW1iZXIsXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxNW10+IHtcbiAgICBjb25zdCB7IGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjb250ZXh0XSwgdGhpcy5xdWVyeSk7XG4gICAgcmV0dXJuIHRoaXMucmVwby5xdWVyeShcbiAgICAgIGNvbmRpdGlvbiBhcyBDb25kaXRpb248TT4sXG4gICAgICBvcmRlckJ5IGFzIGtleW9mIE0sXG4gICAgICBvcmRlciBhcyBPcmRlckRpcmVjdGlvbixcbiAgICAgIGxpbWl0LFxuICAgICAgc2tpcCxcbiAgICAgIC4uLmN0eEFyZ3NcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFeGVjdXRlcyBhIHJhdyBxdWVyeSBhZ2FpbnN0IHRoZSBzdGF0ZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBEZWxlZ2F0ZXMgdG8gdGhlIHJlcG9zaXRvcnkncyByYXcgbWV0aG9kXG4gICAqIEBwYXJhbSB7Q3R4fSBjdHggLSBUaGUgRmFicmljIGNoYWluY29kZSBjb250ZXh0XG4gICAqIEBwYXJhbSB7YW55fSByYXdJbnB1dCAtIFRoZSBxdWVyeSB0byBleGVjdXRlXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gZG9jc09ubHkgLSBXaGV0aGVyIHRvIHJldHVybiBvbmx5IGRvY3VtZW50c1xuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgICogQHJldHVybiB7UHJvbWlzZTxhbnk+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgcXVlcnkgcmVzdWx0c1xuICAgKi9cbiAgYXN5bmMgcmF3KFxuICAgIGN0eDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIHJhd0lucHV0OiBNYW5nb1F1ZXJ5IHwgc3RyaW5nLFxuICAgIGRvY3NPbmx5OiBib29sZWFuLFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8YW55IHwgc3RyaW5nPiB7XG4gICAgY29uc3QgeyBjdHhBcmdzIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbLi4uYXJncywgY3R4XSwgdGhpcy5yYXcpO1xuICAgIGlmICh0eXBlb2YgcmF3SW5wdXQgPT09IFwic3RyaW5nXCIpXG4gICAgICByYXdJbnB1dCA9IEpTT04ucGFyc2UocmF3SW5wdXQpIGFzIE1hbmdvUXVlcnk7XG4gICAgcmV0dXJuIEZhYnJpY0NydWRDb250cmFjdC5hZGFwdGVyLnJhdyhyYXdJbnB1dCwgZG9jc09ubHksIC4uLmN0eEFyZ3MpO1xuICB9XG5cbiAgcHJvdGVjdGVkIHNlcmlhbGl6ZShtb2RlbDogTSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIEZhYnJpY0NydWRDb250cmFjdC5zZXJpYWxpemVyLnNlcmlhbGl6ZShtb2RlbCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZGVzZXJpYWxpemU8TSBleHRlbmRzIE1vZGVsPihzdHI6IHN0cmluZyk6IE0ge1xuICAgIHJldHVybiAoXG4gICAgICBGYWJyaWNDcnVkQ29udHJhY3Quc2VyaWFsaXplciBhcyB1bmtub3duIGFzIFNlcmlhbGl6ZXI8TT5cbiAgICApLmRlc2VyaWFsaXplKHN0cik7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgaW5pdChjdHg6IEN0eCB8IEZhYnJpY0NvbnRyYWN0Q29udGV4dCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgbG9nIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY3R4XSwgdGhpcy5pbml0KTtcbiAgICBsb2cuaW5mbyhgUnVubmluZyBjb250cmFjdCAke3RoaXMuZ2V0TmFtZSgpfSBpbml0aWFsaXphdGlvbi4uLmApO1xuICAgIHRoaXMuaW5pdGlhbGl6ZWQgPSB0cnVlO1xuICAgIGxvZy5pbmZvKGBDb250cmFjdCBpbml0aWFsaXphdGlvbiBjb21wbGV0ZWQuYCk7XG4gIH1cblxuICBhc3luYyBoZWFsdGhjaGVjayhcbiAgICBjdHg6IEN0eCB8IEZhYnJpY0NvbnRyYWN0Q29udGV4dFxuICApOiBQcm9taXNlPHN0cmluZyB8IGhlYWx0aGNoZWNrPiB7XG4gICAgY29uc3QgeyBsb2cgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjdHhdLCB0aGlzLmhlYWx0aGNoZWNrKTtcbiAgICBsb2cuaW5mbyhgUnVubmluZyBIZWFsdGhjaGVjazogJHt0aGlzLmluaXRpYWxpemVkfS4uLmApO1xuICAgIHJldHVybiB7IGhlYWx0aGNoZWNrOiB0aGlzLmluaXRpYWxpemVkIH07XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgbXVsdGlwbGUgbW9kZWxzIGluIHRoZSBzdGF0ZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBEZWxlZ2F0ZXMgdG8gdGhlIHJlcG9zaXRvcnkncyBjcmVhdGVBbGwgbWV0aG9kXG4gICAqIEBwYXJhbSB7Q3R4fSBjdHggLSBUaGUgRmFicmljIGNoYWluY29kZSBjb250ZXh0XG4gICAqIEBwYXJhbSB7TVtdfSBtb2RlbHMgLSBUaGUgbW9kZWxzIHRvIGNyZWF0ZVxuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgICogQHJldHVybiB7UHJvbWlzZTxNW10+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgY3JlYXRlZCBtb2RlbHNcbiAgICovXG4gIGFzeW5jIGNyZWF0ZUFsbChcbiAgICBjdHg6IEN0eCB8IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgICBtb2RlbHM6IHN0cmluZyB8IE1bXSxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPHN0cmluZyB8IE1bXT4ge1xuICAgIGNvbnN0IHsgbG9nIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbLi4uYXJncywgY3R4XSwgdGhpcy5jcmVhdGVBbGwpO1xuXG4gICAgaWYgKHR5cGVvZiBtb2RlbHMgPT09IFwic3RyaW5nXCIpXG4gICAgICBtb2RlbHMgPSAoSlNPTi5wYXJzZShtb2RlbHMpIGFzIFtdKVxuICAgICAgICAubWFwKChtKSA9PiB0aGlzLmRlc2VyaWFsaXplKG0pKVxuICAgICAgICAubWFwKChtKSA9PiBuZXcgdGhpcy5jbGF6eihtKSkgYXMgYW55O1xuXG4gICAgbG9nLmluZm8oYGFkZGluZyAke21vZGVscy5sZW5ndGh9IGVudHJpZXMgdG8gdGhlIHRhYmxlYCk7XG4gICAgcmV0dXJuIHRoaXMucmVwby5jcmVhdGVBbGwobW9kZWxzIGFzIHVua25vd24gYXMgTVtdLCBjdHgsIC4uLmFyZ3MpO1xuICB9XG5cbiAgYXN5bmMgbG9nQ3R4PEFSR1MgZXh0ZW5kcyBhbnlbXT4oXG4gICAgYXJnczogQVJHUyxcbiAgICBtZXRob2Q6ICgoLi4uYXJnczogYW55W10pID0+IGFueSkgfCBzdHJpbmdcbiAgKTogUHJvbWlzZTxcbiAgICBDb250ZXh0dWFsaXplZEFyZ3M8RmFicmljQ29udHJhY3RDb250ZXh0LCBBUkdTPiAmIHtcbiAgICAgIHN0dWI6IENoYWluY29kZVN0dWI7XG4gICAgICBpZGVudGl0eTogQ2xpZW50SWRlbnRpdHk7XG4gICAgfVxuICA+IHtcbiAgICByZXR1cm4gRmFicmljQ3J1ZENvbnRyYWN0LmxvZ0N0eC5iaW5kKHRoaXMpKGFyZ3MsIG1ldGhvZCBhcyBhbnkpO1xuICB9XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyBhc3luYyBsb2dDdHg8QVJHUyBleHRlbmRzIGFueVtdPihcbiAgICB0aGlzOiBhbnksXG4gICAgYXJnczogQVJHUyxcbiAgICBtZXRob2Q6IHN0cmluZ1xuICApOiBQcm9taXNlPFxuICAgIENvbnRleHR1YWxpemVkQXJnczxGYWJyaWNDb250cmFjdENvbnRleHQsIEFSR1M+ICYge1xuICAgICAgc3R1YjogQ2hhaW5jb2RlU3R1YjtcbiAgICAgIGlkZW50aXR5OiBDbGllbnRJZGVudGl0eTtcbiAgICB9XG4gID47XG4gIHByb3RlY3RlZCBzdGF0aWMgYXN5bmMgbG9nQ3R4PEFSR1MgZXh0ZW5kcyBhbnlbXT4oXG4gICAgdGhpczogYW55LFxuICAgIGFyZ3M6IEFSR1MsXG4gICAgbWV0aG9kOiAoLi4uYXJnczogYW55W10pID0+IGFueVxuICApOiBQcm9taXNlPFxuICAgIENvbnRleHR1YWxpemVkQXJnczxGYWJyaWNDb250cmFjdENvbnRleHQsIEFSR1M+ICYge1xuICAgICAgc3R1YjogQ2hhaW5jb2RlU3R1YjtcbiAgICAgIGlkZW50aXR5OiBDbGllbnRJZGVudGl0eTtcbiAgICB9XG4gID47XG4gIHByb3RlY3RlZCBzdGF0aWMgYXN5bmMgbG9nQ3R4PEFSR1MgZXh0ZW5kcyBhbnlbXT4oXG4gICAgdGhpczogYW55LFxuICAgIGFyZ3M6IEFSR1MsXG4gICAgbWV0aG9kOiAoKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnkpIHwgc3RyaW5nXG4gICk6IFByb21pc2U8XG4gICAgQ29udGV4dHVhbGl6ZWRBcmdzPEZhYnJpY0NvbnRyYWN0Q29udGV4dCwgQVJHUz4gJiB7XG4gICAgICBzdHViOiBDaGFpbmNvZGVTdHViO1xuICAgICAgaWRlbnRpdHk6IENsaWVudElkZW50aXR5O1xuICAgIH1cbiAgPiB7XG4gICAgaWYgKGFyZ3MubGVuZ3RoIDwgMSkgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJObyBjb250ZXh0IHByb3ZpZGVkXCIpO1xuICAgIGNvbnN0IGN0eCA9IGFyZ3MucG9wKCkgYXMgRmFicmljQ29udHJhY3RDb250ZXh0IHwgQ29udGV4dDtcbiAgICBpZiAoY3R4IGluc3RhbmNlb2YgRmFicmljQ29udHJhY3RDb250ZXh0KVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgY3R4LFxuICAgICAgICBsb2c6IGN0eC5sb2dnZXIuY2xlYXIoKS5mb3IodGhpcykuZm9yKG1ldGhvZCksXG4gICAgICAgIGN0eEFyZ3M6IFsuLi5hcmdzLCBjdHhdLFxuICAgICAgICBzdHViOiBjdHguc3R1YixcbiAgICAgICAgaWRlbnRpdHk6IGN0eC5pZGVudGl0eSxcbiAgICAgIH07XG5cbiAgICBpZiAoIShjdHggaW5zdGFuY2VvZiBDdHgpKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJObyB2YWxpZCBjb250ZXh0IHByb3ZpZGVkXCIpO1xuXG4gICAgZnVuY3Rpb24gZ2V0T3AoKSB7XG4gICAgICBpZiAodHlwZW9mIG1ldGhvZCA9PT0gXCJzdHJpbmdcIikgcmV0dXJuIG1ldGhvZDtcbiAgICAgIHN3aXRjaCAobWV0aG9kLm5hbWUpIHtcbiAgICAgICAgY2FzZSBPcGVyYXRpb25LZXlzLkNSRUFURTpcbiAgICAgICAgY2FzZSBPcGVyYXRpb25LZXlzLlJFQUQ6XG4gICAgICAgIGNhc2UgT3BlcmF0aW9uS2V5cy5VUERBVEU6XG4gICAgICAgIGNhc2UgT3BlcmF0aW9uS2V5cy5ERUxFVEU6XG4gICAgICAgIGNhc2UgQnVsa0NydWRPcGVyYXRpb25LZXlzLkNSRUFURV9BTEw6XG4gICAgICAgIGNhc2UgQnVsa0NydWRPcGVyYXRpb25LZXlzLlJFQURfQUxMOlxuICAgICAgICBjYXNlIEJ1bGtDcnVkT3BlcmF0aW9uS2V5cy5VUERBVEVfQUxMOlxuICAgICAgICBjYXNlIEJ1bGtDcnVkT3BlcmF0aW9uS2V5cy5ERUxFVEVfQUxMOlxuICAgICAgICAgIHJldHVybiBtZXRob2QubmFtZTtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICByZXR1cm4gbWV0aG9kLm5hbWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3Qgb3ZlcnJpZGVzID0ge1xuICAgICAgY29ycmVsYXRpb25JZDogY3R4LnN0dWIuZ2V0VHhJRCgpLFxuICAgIH07XG4gICAgY29uc3QgY29udGV4dCA9IGF3YWl0IEZhYnJpY0NydWRDb250cmFjdC5hZGFwdGVyLmNvbnRleHQoXG4gICAgICBnZXRPcCgpLFxuICAgICAgb3ZlcnJpZGVzIGFzIGFueSxcbiAgICAgIHRoaXMuY2xhenosXG4gICAgICBjdHhcbiAgICApO1xuXG4gICAgY29uc3QgbG9nID0gKFxuICAgICAgdGhpc1xuICAgICAgICA/IGNvbnRleHQubG9nZ2VyLmZvcih0aGlzKS5mb3IobWV0aG9kKVxuICAgICAgICA6IGNvbnRleHQubG9nZ2VyLmNsZWFyKCkuZm9yKHRoaXMpLmZvcihtZXRob2QpXG4gICAgKSBhcyBMb2dnZXJPZjxGYWJyaWNDb250cmFjdENvbnRleHQ+O1xuICAgIHJldHVybiB7XG4gICAgICBjdHg6IGNvbnRleHQsXG4gICAgICBsb2c6IGxvZyxcbiAgICAgIHN0dWI6IGNvbnRleHQuc3R1YixcbiAgICAgIGlkZW50aXR5OiBjb250ZXh0LmlkZW50aXR5LFxuICAgICAgY3R4QXJnczogWy4uLmFyZ3MsIGNvbnRleHRdLFxuICAgIH07XG4gIH1cbn1cbiIsImltcG9ydCB7IEZhYnJpY0NydWRDb250cmFjdCB9IGZyb20gXCIuL2NydWQtY29udHJhY3RcIjtcbmltcG9ydCB7IE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgTWFuZ29RdWVyeSB9IGZyb20gXCJAZGVjYWYtdHMvZm9yLWNvdWNoZGJcIjtcbmltcG9ydCB7IENvbnRleHQgYXMgQ3R4LCBUcmFuc2FjdGlvbiB9IGZyb20gXCJmYWJyaWMtY29udHJhY3QtYXBpXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgQ29uZGl0aW9uLCBPcmRlckRpcmVjdGlvbiB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgU2VyaWFsaXphdGlvbkVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENSVUQgY29udHJhY3QgdmFyaWFudCB0aGF0IHNlcmlhbGl6ZXMvZGVzZXJpYWxpemVzIHBheWxvYWRzXG4gKiBAc3VtbWFyeSBFeHBvc2VzIHRoZSBzYW1lIENSVUQgb3BlcmF0aW9ucyBhcyBGYWJyaWNDcnVkQ29udHJhY3QgYnV0IHRha2VzIGFuZCByZXR1cm5zIEpTT04gc3RyaW5ncyB0byBmYWNpbGl0YXRlIHNpbXBsZSBjbGllbnQgaW50ZXJhY3Rpb25zLlxuICogQHRlbXBsYXRlIE0gLSBNb2RlbCB0eXBlIGhhbmRsZWQgYnkgdGhpcyBjb250cmFjdFxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgY29udHJhY3QgbmFtZVxuICogQHBhcmFtIHtDb25zdHJ1Y3RvcjxNPn0gY2xhenogLSBUaGUgbW9kZWwgY29uc3RydWN0b3IgdXNlZCB0byBpbnN0YW50aWF0ZSBtb2RlbHMgZnJvbSBKU09OXG4gKiBAcmV0dXJuIHt2b2lkfVxuICogQGNsYXNzIFNlcmlhbGl6ZWRDcnVkQ29udHJhY3RcbiAqIEBleGFtcGxlXG4gKiBjb25zdCBjb250cmFjdCA9IG5ldyBTZXJpYWxpemVkQ3J1ZENvbnRyYWN0PE15TW9kZWw+KCdNeU1vZGVsQ29udHJhY3QnLCBNeU1vZGVsKTtcbiAqIC8vIENsaWVudCBzdWJtaXRzIEpTT04gc3RyaW5nIHBheWxvYWRzIGFuZCByZWNlaXZlcyBKU09OIHN0cmluZyByZXNwb25zZXNcbiAqL1xuZXhwb3J0IGNsYXNzIFNlcmlhbGl6ZWRDcnVkQ29udHJhY3Q8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbj4gZXh0ZW5kcyBGYWJyaWNDcnVkQ29udHJhY3Q8TT4ge1xuICBjb25zdHJ1Y3RvcihuYW1lOiBzdHJpbmcsIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPikge1xuICAgIHN1cGVyKG5hbWUsIGNsYXp6KTtcbiAgfVxuXG4gIEBUcmFuc2FjdGlvbigpXG4gIG92ZXJyaWRlIGFzeW5jIGNyZWF0ZShjb250ZXh0OiBDdHgsIG1vZGVsOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5jcmVhdGUpO1xuICAgIGxvZy5pbmZvKGBDcmVhdGluZyBtb2RlbDogJHttb2RlbH1gKTtcblxuICAgIGNvbnN0IG0gPSB0aGlzLmRlc2VyaWFsaXplPE0+KG1vZGVsKTtcblxuICAgIGxvZy5pbmZvKGBNb2RlbCBkZXNlcmlhbGl6ZWQ6ICR7SlNPTi5zdHJpbmdpZnkobSl9YCk7XG4gICAgcmV0dXJuIHRoaXMuc2VyaWFsaXplKChhd2FpdCBzdXBlci5jcmVhdGUoY3R4IGFzIGFueSwgbSkpIGFzIE0pO1xuICB9XG5cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBvdmVycmlkZSBhc3luYyByZWFkKGNvbnRleHQ6IEN0eCwga2V5OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5yZWFkKTtcbiAgICBsb2cuaW5mbyhgUmVhZGluZyBpZDogJHtrZXl9YCk7XG4gICAgcmV0dXJuIHRoaXMuc2VyaWFsaXplKChhd2FpdCBzdXBlci5yZWFkKGN0eCBhcyBhbnksIGtleSkpIGFzIE0pO1xuICB9XG5cbiAgQFRyYW5zYWN0aW9uKClcbiAgb3ZlcnJpZGUgYXN5bmMgdXBkYXRlKGNvbnRleHQ6IEN0eCwgbW9kZWw6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLnVwZGF0ZSk7XG4gICAgbG9nLmluZm8oYFVwZGF0aW5nIG1vZGVsOiAke21vZGVsfWApO1xuICAgIHJldHVybiB0aGlzLnNlcmlhbGl6ZSgoYXdhaXQgc3VwZXIudXBkYXRlKGN0eCBhcyBhbnksIG1vZGVsKSkgYXMgTSk7XG4gIH1cblxuICBAVHJhbnNhY3Rpb24oKVxuICBvdmVycmlkZSBhc3luYyBkZWxldGUoY29udGV4dDogQ3R4LCBrZXk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLmRlbGV0ZSk7XG4gICAgbG9nLmluZm8oYERlbGV0aW5nIGlkOiAke2tleX1gKTtcbiAgICByZXR1cm4gdGhpcy5zZXJpYWxpemUoKGF3YWl0IHN1cGVyLmRlbGV0ZShjdHggYXMgYW55LCBrZXkpKSBhcyBNKTtcbiAgfVxuXG4gIEBUcmFuc2FjdGlvbigpXG4gIG92ZXJyaWRlIGFzeW5jIGRlbGV0ZUFsbChjb250ZXh0OiBDdHgsIGtleXM6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgcGFyc2VkS2V5czogc3RyaW5nW10gPSBKU09OLnBhcnNlKGtleXMpO1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5kZWxldGVBbGwpO1xuXG4gICAgbG9nLmluZm8oYGRlbGV0aW5nICR7cGFyc2VkS2V5cy5sZW5ndGh9IGVudHJpZXMgZnJvbSB0aGUgdGFibGVgKTtcblxuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShcbiAgICAgICgoYXdhaXQgc3VwZXIuZGVsZXRlQWxsKGN0eCBhcyBhbnksIHBhcnNlZEtleXMpKSBhcyBNW10pLm1hcChcbiAgICAgICAgKG0pID0+IHRoaXMuc2VyaWFsaXplKG0pIGFzIHN0cmluZ1xuICAgICAgKVxuICAgICk7XG4gIH1cblxuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIG92ZXJyaWRlIGFzeW5jIHJlYWRBbGwoY29udGV4dDogQ3R4LCBrZXlzOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHBhcnNlZEtleXM6IHN0cmluZ1tdID0gSlNPTi5wYXJzZShrZXlzKTtcblxuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5yZWFkQWxsKTtcbiAgICBsb2cuaW5mbyhgcmVhZGluZyAke3BhcnNlZEtleXMubGVuZ3RofSBlbnRyaWVzIGZyb20gdGhlIHRhYmxlYCk7XG5cbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoXG4gICAgICAoKGF3YWl0IHN1cGVyLnJlYWRBbGwoY3R4IGFzIGFueSwgcGFyc2VkS2V5cykpIGFzIE1bXSkubWFwKChtKSA9PlxuICAgICAgICB0aGlzLnNlcmlhbGl6ZShtKVxuICAgICAgKVxuICAgICk7XG4gIH1cblxuICBAVHJhbnNhY3Rpb24oKVxuICBvdmVycmlkZSBhc3luYyB1cGRhdGVBbGwoY29udGV4dDogQ3R4LCBtb2RlbHM6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLnVwZGF0ZUFsbCk7XG4gICAgY29uc3QgbGlzdDogc3RyaW5nW10gPSBKU09OLnBhcnNlKG1vZGVscyk7XG4gICAgY29uc3QgbW9kZWxMaXN0OiBNW10gPSBsaXN0XG4gICAgICAubWFwKChtKSA9PiB0aGlzLmRlc2VyaWFsaXplKG0pKVxuICAgICAgLm1hcCgobSkgPT4gbmV3IHRoaXMuY2xhenoobSkpO1xuXG4gICAgbG9nLmluZm8oYFVwZGF0aW5nICR7bW9kZWxMaXN0Lmxlbmd0aH0gZW50cmllcyB0byB0aGUgdGFibGVgKTtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoXG4gICAgICAoKGF3YWl0IHN1cGVyLnVwZGF0ZUFsbChjdHggYXMgYW55LCBtb2RlbExpc3QpKSBhcyBNW10pLm1hcChcbiAgICAgICAgKG0pID0+IHRoaXMuc2VyaWFsaXplKG0pIGFzIHN0cmluZ1xuICAgICAgKVxuICAgICk7XG4gIH1cblxuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIG92ZXJyaWRlIGFzeW5jIHN0YXRlbWVudChjb250ZXh0OiBDdHgsIG1ldGhvZDogc3RyaW5nLCAuLi5hcmdzOiBzdHJpbmdbXSkge1xuICAgIGNvbnN0IHsgY3R4LCBsb2cgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjb250ZXh0XSwgdGhpcy5zdGF0ZW1lbnQpO1xuICAgIGFyZ3MgPSBhcmdzLm1hcCgoYSkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoYSk7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgcmV0dXJuIGE7XG4gICAgICB9XG4gICAgfSk7XG4gICAgbG9nLmluZm8oYGNhbGxpbmcgcHJlcGFyZWQgc3RhdGVtZW50ICR7bWV0aG9kfWApO1xuICAgIGxvZy5kZWJ1Zyhgd2l0aCBhcmdzICR7YXJnc31gKTtcbiAgICByZXR1cm4gc3VwZXIuc3RhdGVtZW50KGN0eCwgbWV0aG9kLCAuLi5hcmdzKTtcbiAgfVxuXG4gIEBUcmFuc2FjdGlvbihmYWxzZSlcbiAgb3ZlcnJpZGUgYXN5bmMgbGlzdEJ5KFxuICAgIGNvbnRleHQ6IEN0eCxcbiAgICBrZXk6IHN0cmluZyxcbiAgICBvcmRlcjogc3RyaW5nLFxuICAgIC4uLmFyZ3M6IHN0cmluZ1tdXG4gICkge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbLi4uYXJncywgY29udGV4dF0sIHRoaXMubGlzdEJ5KTtcbiAgICByZXR1cm4gc3VwZXIubGlzdEJ5KGN0eCwga2V5IGFzIGtleW9mIE0sIG9yZGVyIGFzIE9yZGVyRGlyZWN0aW9uKTtcbiAgfVxuXG4gIEBUcmFuc2FjdGlvbihmYWxzZSlcbiAgb3ZlcnJpZGUgYXN5bmMgcGFnaW5hdGVCeShcbiAgICBjb250ZXh0OiBDdHgsXG4gICAga2V5OiBzdHJpbmcsXG4gICAgb3JkZXI6IHN0cmluZyxcbiAgICBzaXplOiBudW1iZXIsXG4gICAgLi4uYXJnczogc3RyaW5nW11cbiAgKSB7XG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjb250ZXh0XSwgdGhpcy5wYWdpbmF0ZUJ5KTtcbiAgICByZXR1cm4gc3VwZXIucGFnaW5hdGVCeShjdHgsIGtleSwgb3JkZXIgYXMgYW55LCBzaXplKTtcbiAgfVxuXG4gIEBUcmFuc2FjdGlvbihmYWxzZSlcbiAgb3ZlcnJpZGUgYXN5bmMgZmluZE9uZUJ5KFxuICAgIGNvbnRleHQ6IEN0eCxcbiAgICBrZXk6IHN0cmluZyxcbiAgICB2YWx1ZTogc3RyaW5nLFxuICAgIC4uLmFyZ3M6IHN0cmluZ1tdXG4gICkge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbLi4uYXJncywgY29udGV4dF0sIHRoaXMucGFnaW5hdGVCeSk7XG4gICAgcmV0dXJuIHN1cGVyLmZpbmRPbmVCeShjdHgsIGtleSwgdmFsdWUsIC4uLmFyZ3MpO1xuICB9XG5cbiAgLy8gQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBvdmVycmlkZSBhc3luYyBxdWVyeShcbiAgICBjb250ZXh0OiBDdHgsXG4gICAgY29uZGl0aW9uOiBzdHJpbmcsXG4gICAgb3JkZXJCeTogc3RyaW5nLFxuICAgIG9yZGVyOiBzdHJpbmcsXG4gICAgbGltaXQ/OiBudW1iZXIsXG4gICAgc2tpcD86IG51bWJlcixcbiAgICAuLi5hcmdzOiBzdHJpbmdbXVxuICApOiBQcm9taXNlPE1bXT4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMucXVlcnkpO1xuICAgIGxldCBjb25kOiBDb25kaXRpb248YW55PjtcbiAgICB0cnkge1xuICAgICAgY29uZCA9IENvbmRpdGlvbi5mcm9tKEpTT04ucGFyc2UoY29uZGl0aW9uKSk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IFNlcmlhbGl6YXRpb25FcnJvcihgSW52YWxpZCBjb25kaXRpb246ICR7ZX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHN1cGVyLnF1ZXJ5KGN0eCwgY29uZCwgb3JkZXJCeSwgb3JkZXIgYXMgYW55LCBsaW1pdCwgc2tpcCwgLi4uYXJncyk7XG4gIH1cblxuICAvLyBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIG92ZXJyaWRlIGFzeW5jIHJhdyhcbiAgICBjb250ZXh0OiBDdHgsXG4gICAgcmF3SW5wdXQ6IHN0cmluZyxcbiAgICBkb2NzT25seTogYm9vbGVhbixcbiAgICAuLi5hcmdzOiBzdHJpbmdbXVxuICApOiBQcm9taXNlPGFueT4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMucmF3KTtcbiAgICBjb25zdCBwYXJzZWRJbnB1dDogTWFuZ29RdWVyeSA9IEpTT04ucGFyc2UocmF3SW5wdXQpO1xuICAgIHJldHVybiBzdXBlci5yYXcoY3R4LCBwYXJzZWRJbnB1dCwgZG9jc09ubHksIC4uLmFyZ3MpO1xuICB9XG5cbiAgQFRyYW5zYWN0aW9uKClcbiAgb3ZlcnJpZGUgYXN5bmMgaW5pdChjdHg6IEN0eCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHN1cGVyLmluaXQoY3R4KTtcbiAgfVxuXG4gIEBUcmFuc2FjdGlvbihmYWxzZSlcbiAgb3ZlcnJpZGUgYXN5bmMgaGVhbHRoY2hlY2soY29udGV4dDogQ3R4KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMudXBkYXRlQWxsKTtcbiAgICBsb2cuZGVidWcoYFJ1bm5pbmcgSGVhbHRoY2hlY2s6ICR7dGhpcy5pbml0aWFsaXplZH0uLi5gKTtcbiAgICAvL1RPRE86IFRSSU0gTk9UIFdPUktJTkcgQ0hFQ0sgTEFURVJcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoYXdhaXQgc3VwZXIuaGVhbHRoY2hlY2soY3R4IGFzIGFueSkpO1xuICB9XG5cbiAgQFRyYW5zYWN0aW9uKClcbiAgb3ZlcnJpZGUgYXN5bmMgY3JlYXRlQWxsKGNvbnRleHQ6IEN0eCwgbW9kZWxzOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHsgbG9nIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuY3JlYXRlQWxsKTtcbiAgICBjb25zdCBsaXN0OiBzdHJpbmdbXSA9IEpTT04ucGFyc2UobW9kZWxzKTtcbiAgICBjb25zdCBtb2RlbExpc3Q6IE1bXSA9IGxpc3RcbiAgICAgIC5tYXAoKG0pID0+IHRoaXMuZGVzZXJpYWxpemUobSkpXG4gICAgICAubWFwKChtKSA9PiBuZXcgdGhpcy5jbGF6eihtKSk7XG5cbiAgICBsb2cuaW5mbyhgQWRkaW5nICR7bW9kZWxMaXN0Lmxlbmd0aH0gZW50cmllcyB0byB0aGUgdGFibGVgKTtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoXG4gICAgICAoKGF3YWl0IHN1cGVyLmNyZWF0ZUFsbChjb250ZXh0LCBtb2RlbExpc3QpKSBhcyBNW10pLm1hcChcbiAgICAgICAgKG0pID0+IHRoaXMuc2VyaWFsaXplKG0pIGFzIHN0cmluZ1xuICAgICAgKVxuICAgICk7XG4gIH1cbn1cbiIsImltcG9ydCB7IEJhc2VFcnJvciwgSW50ZXJuYWxFcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgQXV0aG9yaXphdGlvbkVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG4vLyBpbXBvcnQgeyBNSVNTSU5HX1BSSVZBVEVfREFUQV9FUlJPUl9NRVNTQUdFIH0gZnJvbSBcIi4uL2NvbnRyYWN0cy9wcml2YXRlLWRhdGFcIjtcbi8qKlxuICogQHN1bW1hcnkgUmVwcmVzZW50cyBhbiBvdmVyZmxvdyBlcnJvciBpbiBhcml0aG1ldGljIG9wZXJhdGlvbnMgaW4gU21hcnQgQ29udHJhY3RzXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG1zZyB0aGUgZXJyb3IgbWVzc2FnZVxuICpcbiAqIEBjbGFzcyBPdmVyZmxvd0Vycm9yXG4gKiBAZXh0ZW5kcyBJbnRlcm5hbEVycm9yXG4gKlxuICogQGNhdGVnb3J5IEVycm9yc1xuICovXG5leHBvcnQgY2xhc3MgT3ZlcmZsb3dFcnJvciBleHRlbmRzIEludGVybmFsRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobXNnLCBPdmVyZmxvd0Vycm9yLm5hbWUpO1xuICB9XG59XG5cbi8qKlxuICogQHN1bW1hcnkgUmVwcmVzZW50cyBhIGZhaWx1cmUgaW4gYmFsYW5jZSB0byBwZXJmb3JtIGEgdHJhbnNhY3Rpb24gaW4gU21hcnQgQ29udHJhY3RzXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG1zZyB0aGUgZXJyb3IgbWVzc2FnZVxuICpcbiAqIEBjbGFzcyBCYWxhbmNlRXJyb3JcbiAqIEBleHRlbmRzIEludGVybmFsRXJyb3JcbiAqXG4gKiBAY2F0ZWdvcnkgRXJyb3JzXG4gKi9cbmV4cG9ydCBjbGFzcyBCYWxhbmNlRXJyb3IgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1zZywgQmFsYW5jZUVycm9yLm5hbWUpO1xuICB9XG59XG5cbi8qKlxuICogQHN1bW1hcnkgUmVwcmVzZW50cyBhIGZhaWx1cmUgaW4gYmFsYW5jZSB0byBwZXJmb3JtIGEgdHJhbnNhY3Rpb24gaW4gU21hcnQgQ29udHJhY3RzXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG1zZyB0aGUgZXJyb3IgbWVzc2FnZVxuICpcbiAqIEBjbGFzcyBCYWxhbmNlRXJyb3JcbiAqIEBleHRlbmRzIEludGVybmFsRXJyb3JcbiAqXG4gKiBAY2F0ZWdvcnkgRXJyb3JzXG4gKi9cbmV4cG9ydCBjbGFzcyBBbGxvd2FuY2VFcnJvciBleHRlbmRzIEludGVybmFsRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobXNnLCBBbGxvd2FuY2VFcnJvci5uYW1lKTtcbiAgfVxufVxuXG4vKipcbiAqIEBzdW1tYXJ5IFJlcHJlc2VudHMgYSBmYWlsdXJlIHJlZ2lzdHJhdGluZyBuZXcgZW50aXRpZXNcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbXNnIHRoZSBlcnJvciBtZXNzYWdlXG4gKlxuICogQGNsYXNzIFJlZ2lzdHJhdGlvbkVycm9yXG4gKlxuICogQGNhdGVnb3J0IEVycm9yc1xuICovXG5leHBvcnQgY2xhc3MgUmVnaXN0cmF0aW9uRXJyb3IgZXh0ZW5kcyBBdXRob3JpemF0aW9uRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobXNnLCBSZWdpc3RyYXRpb25FcnJvci5uYW1lKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFcnJvciB0aHJvd24gd2hlbiBhbiB1bnN1cHBvcnRlZCBvcGVyYXRpb24gaXMgYXR0ZW1wdGVkXG4gKiBAc3VtbWFyeSBUaGlzIGVycm9yIGlzIHRocm93biB3aGVuIGFuIG9wZXJhdGlvbiBpcyByZXF1ZXN0ZWQgdGhhdCBpcyBub3Qgc3VwcG9ydGVkIGJ5IHRoZSBjdXJyZW50XG4gKiBwZXJzaXN0ZW5jZSBhZGFwdGVyIG9yIGNvbmZpZ3VyYXRpb24uIEl0IGV4dGVuZHMgdGhlIEJhc2VFcnJvciBjbGFzcyBhbmQgc2V0cyBhIDUwMCBzdGF0dXMgY29kZS5cbiAqIEBwYXJhbSB7c3RyaW5nfEVycm9yfSBtc2cgLSBUaGUgZXJyb3IgbWVzc2FnZSBvciBhbiBFcnJvciBvYmplY3QgdG8gd3JhcFxuICogQGNsYXNzIFVuc3VwcG9ydGVkRXJyb3JcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBUaHJvd2luZyBhbiBVbnN1cHBvcnRlZEVycm9yXG4gKiBpZiAoIWFkYXB0ZXIuc3VwcG9ydHNUcmFuc2FjdGlvbnMoKSkge1xuICogICB0aHJvdyBuZXcgVW5zdXBwb3J0ZWRFcnJvcignVHJhbnNhY3Rpb25zIGFyZSBub3Qgc3VwcG9ydGVkIGJ5IHRoaXMgYWRhcHRlcicpO1xuICogfVxuICpcbiAqIC8vIENhdGNoaW5nIGFuIFVuc3VwcG9ydGVkRXJyb3JcbiAqIHRyeSB7XG4gKiAgIGF3YWl0IGFkYXB0ZXIuYmVnaW5UcmFuc2FjdGlvbigpO1xuICogfSBjYXRjaCAoZXJyb3IpIHtcbiAqICAgaWYgKGVycm9yIGluc3RhbmNlb2YgVW5zdXBwb3J0ZWRFcnJvcikge1xuICogICAgIGNvbnNvbGUuZXJyb3IoJ09wZXJhdGlvbiBub3Qgc3VwcG9ydGVkOicsIGVycm9yLm1lc3NhZ2UpO1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBAY2F0ZWdvcnkgRXJyb3JzXG4gKi9cbmV4cG9ydCBjbGFzcyBNaXNzaW5nQ29udGV4dEVycm9yIGV4dGVuZHMgSW50ZXJuYWxFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtc2csIE1pc3NpbmdDb250ZXh0RXJyb3IubmFtZSwgNTAwKTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgVW5hdXRob3JpemVkUHJpdmF0ZURhdGFBY2Nlc3MgZXh0ZW5kcyBCYXNlRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yID0gXCJNSVNTSU5HX1BSSVZBVEVfREFUQV9FUlJPUl9NRVNTQUdFXCIpIHtcbiAgICBzdXBlcihVbmF1dGhvcml6ZWRQcml2YXRlRGF0YUFjY2Vzcy5uYW1lLCBtc2csIDQwMyk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXByZXNlbnRzIGFuIGVycm9yIHRoYXQgb2NjdXJzIHdoZW4gYSByZXF1aXJlZCBpbml0aWFsaXphdGlvbiBzdGVwIGlzIG5vdCBwZXJmb3JtZWQuXG4gKlxuICogQGNsYXNzIE5vdEluaXRpYWxpemVkRXJyb3JcbiAqIEBleHRlbmRzIEJhc2VFcnJvclxuICpcbiAqIEBjYXRlZ29yeSBFcnJvcnNcbiAqXG4gKiBAcGFyYW0ge3N0cmluZyB8IEVycm9yfSBtc2cgLSBUaGUgZXJyb3IgbWVzc2FnZSBvciBhbiBFcnJvciBvYmplY3QgdG8gd3JhcC5cbiAqXG4gKiBAdGhyb3dzIHtOb3RJbml0aWFsaXplZEVycm9yfSAtIFRocm93cyBhbiBlcnJvciB3aGVuIGEgcmVxdWlyZWQgaW5pdGlhbGl6YXRpb24gc3RlcCBpcyBub3QgcGVyZm9ybWVkLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBJbml0aWFsaXplIHRoZSBhcHBsaWNhdGlvblxuICogaWYgKCFpc0luaXRpYWxpemVkKSB7XG4gKiAgIHRocm93IG5ldyBOb3RJbml0aWFsaXplZEVycm9yKCdBcHBsaWNhdGlvbiBpcyBub3QgaW5pdGlhbGl6ZWQnKTtcbiAqIH1cbiAqXG4gKiAvLyBDYXRjaGluZyBhbiBOb3RJbml0aWFsaXplZEVycm9yXG4gKiB0cnkge1xuICogICAvLyBQZXJmb3JtIG9wZXJhdGlvbnMgdGhhdCByZXF1aXJlIGluaXRpYWxpemF0aW9uXG4gKiB9IGNhdGNoIChlcnJvcikge1xuICogICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBOb3RJbml0aWFsaXplZEVycm9yKSB7XG4gKiAgICAgY29uc29sZS5lcnJvcignSW5pdGlhbGl6YXRpb24gZXJyb3I6JywgZXJyb3IubWVzc2FnZSk7XG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgTm90SW5pdGlhbGl6ZWRFcnJvciBleHRlbmRzIEJhc2VFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihOb3RJbml0aWFsaXplZEVycm9yLm5hbWUsIG1zZywgNDA5KTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgTWlzc2luZ1BLQ1NTMTFMaWIgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1zZywgTWlzc2luZ1BLQ1NTMTFMaWIubmFtZSwgNTAwKTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgRW5kb3JzZW1lbnRFcnJvciBleHRlbmRzIEludGVybmFsRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1lc3NhZ2UsIEVuZG9yc2VtZW50RXJyb3IubmFtZSwgNTAwKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgc3RyaW5nRm9ybWF0IH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgT3ZlcmZsb3dFcnJvciB9IGZyb20gXCIuL2Vycm9yc1wiO1xuaW1wb3J0IHsgVmFsaWRhdGlvbkVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE92ZXJmbG93LXNhZmUgYWRkaXRpb24gb3BlcmF0aW9uXG4gKiBAc3VtbWFyeSBBZGRzIHR3byBudW1iZXJzIGFuZCB2ZXJpZmllcyBubyBvdmVyZmxvdyBieSByZXZlcnNlLWNoZWNraW5nIHRoZSBvcGVyYW5kc1xuICogQHBhcmFtIHtudW1iZXJ9IGEgLSBGaXJzdCBvcGVyYW5kXG4gKiBAcGFyYW0ge251bWJlcn0gYiAtIFNlY29uZCBvcGVyYW5kXG4gKiBAcmV0dXJuIHtudW1iZXJ9IFRoZSBzdW0gb2YgYSBhbmQgYlxuICogQGZ1bmN0aW9uIGFkZFxuICogQHRocm93cyB7T3ZlcmZsb3dFcnJvcn0gb24gYWRkaXRpb24gb3ZlcmZsb3dcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5zaGFyZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFkZChhOiBudW1iZXIsIGI6IG51bWJlcik6IG51bWJlciB7XG4gIGNvbnN0IGMgPSBhICsgYjtcbiAgaWYgKGEgIT09IGMgLSBiIHx8IGIgIT09IGMgLSBhKSB7XG4gICAgdGhyb3cgbmV3IE92ZXJmbG93RXJyb3IoYEFkZGl0aW9uIG92ZXJmbG93OiAke2F9ICsgJHtifWApO1xuICB9XG4gIHJldHVybiBjO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBPdmVyZmxvdy1zYWZlIHN1YnRyYWN0aW9uIG9wZXJhdGlvblxuICogQHN1bW1hcnkgU3VidHJhY3RzIGIgZnJvbSBhIGFuZCB2YWxpZGF0ZXMgbm8gb3ZlcmZsb3cgYnkgcmV2ZXJzZS1jaGVja2luZyB0aGUgb3BlcmFuZHNcbiAqIEBwYXJhbSB7bnVtYmVyfSBhIC0gTWludWVuZFxuICogQHBhcmFtIHtudW1iZXJ9IGIgLSBTdWJ0cmFoZW5kXG4gKiBAcmV0dXJuIHtudW1iZXJ9IFRoZSBkaWZmZXJlbmNlIGEgLSBiXG4gKiBAZnVuY3Rpb24gc3ViXG4gKiBAdGhyb3dzIHtPdmVyZmxvd0Vycm9yfSBvbiBzdWJ0YWN0aW9uIG92ZXJmbG93XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuc2hhcmVkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzdWIoYTogbnVtYmVyLCBiOiBudW1iZXIpOiBudW1iZXIge1xuICBjb25zdCBjID0gYSAtIGI7XG4gIGlmIChhICE9PSBjICsgYiB8fCBiICE9PSBhIC0gYykge1xuICAgIHRocm93IG5ldyBPdmVyZmxvd0Vycm9yKGBTdWJ0cmFjdGlvbiBvdmVyZmxvdzogJHthfSAtICR7Yn1gKTtcbiAgfVxuICByZXR1cm4gYztcbn1cblxuLyoqXG4gKiBAc3VtbWFyeSBTYWZlIEludGVnZXIgUGFyc2VcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nXG4gKlxuICogQGZ1bmN0aW9uIHNhZmVQYXJzZUludFxuICpcbiAqIEB0aHJvd3Mge1ZhbGlkYXRpb25FcnJvcn0gaWYgcGFyc2VJbnQgcmV0dXJucyBOYU5cbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuc2hhcmVkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzYWZlUGFyc2VJbnQoc3RyaW5nOiBzdHJpbmcpOiBudW1iZXIge1xuICAvLyBSZWd1bGFyIGV4cHJlc3Npb24gdG8gY2hlY2sgaWYgc3RyaW5nIG9ubHkgaGF2ZSBkaWdpdHNcbiAgY29uc3QgZGlnaXRSZWdleCA9IC9eXFxkKyQvO1xuICBpZiAoIWRpZ2l0UmVnZXgudGVzdChzdHJpbmcpKSB7XG4gICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihcbiAgICAgIHN0cmluZ0Zvcm1hdChcIkZhaWxlZCB0byBwYXJzZTogezB9XCIsIFwic3RyaW5nIGNvbnRhaW5zIGRpZ2l0c1wiKVxuICAgICk7XG4gIH1cbiAgY29uc3QgcGFyc2VkaW50ID0gcGFyc2VJbnQoc3RyaW5nKTtcbiAgaWYgKGlzTmFOKHBhcnNlZGludCkpIHtcbiAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKFxuICAgICAgc3RyaW5nRm9ybWF0KFwiRmFpbGVkIHRvIHBhcnNlOiB7MH1cIiwgXCJzdHJpbmcgaXMgbm90IGEgcGFyc2FibGUgaW50ZWdlclwiKVxuICAgICk7XG4gIH1cbiAgcmV0dXJuIHBhcnNlZGludDtcbn1cbiIsImltcG9ydCB7IEJhc2VNb2RlbCwgY29sdW1uLCBwaywgdGFibGUgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IG1vZGVsLCB0eXBlIE1vZGVsQXJnLCByZXF1aXJlZCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRVJDMjAgdG9rZW4gbWV0YWRhdGEgbW9kZWxcbiAqIEBzdW1tYXJ5IFJlcHJlc2VudHMgYW4gRVJDMjAgdG9rZW4gZGVmaW5pdGlvbiB3aXRoaW4gdGhlIEZhYnJpYyBFUkMyMCBzYW1wbGUsIGluY2x1ZGluZyBuYW1lLCBzeW1ib2wsIGRlY2ltYWxzLCBhbmQgdGhlIG93bmluZyBpZGVudGl0eS4gVXNlZCB0byBkZWZpbmUgdGhlIHVuaXF1ZSB0b2tlbiBtYW5hZ2VkIGJ5IHRoZSBjb250cmFjdC5cbiAqIEBwYXJhbSB7TW9kZWxBcmc8RVJDMjBUb2tlbj59IFttXSAtIE9wdGlvbmFsIHBhcnRpYWwgZGF0YSBvciBhbm90aGVyIGluc3RhbmNlIHRvIGluaXRpYWxpemUgdGhlIG1vZGVsXG4gKiBAcmV0dXJuIHt2b2lkfVxuICogQGNsYXNzIEVSQzIwVG9rZW5cbiAqIEBleGFtcGxlXG4gKiBjb25zdCB0b2tlbiA9IG5ldyBFUkMyMFRva2VuKHsgbmFtZTogXCJNeVRva2VuXCIsIHN5bWJvbDogXCJNVEtcIiwgZGVjaW1hbHM6IDE4LCBvd25lcjogXCJ4NTA5OjouLi5cIiB9KTtcbiAqIC8vIFBlcnNpc3QgdGhyb3VnaCBhIHJlcG9zaXRvcnk6IGF3YWl0IHJlcG8uY3JlYXRlKHRva2VuLCBjdHgpXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBwYXJ0aWNpcGFudCBSZXBvXG4gKiAgIHBhcnRpY2lwYW50IEFkYXB0ZXJcbiAqICAgQXBwLT4+UmVwbzogY3JlYXRlKG5ldyBFUkMyMFRva2VuKHsuLi59KSwgY3R4KVxuICogICBSZXBvLT4+QWRhcHRlcjogY3JlYXRlKHRhYmxlLCBpZD1uYW1lLCByZWNvcmQsIGZsYWdzKVxuICogICBBZGFwdGVyLS0+PlJlcG86IHN0b3JlZFxuICogICBSZXBvLS0+PkFwcDogbW9kZWxcbiAqL1xuQHRhYmxlKFwiZXJjMjBfdG9rZW5zXCIpXG5AbW9kZWwoKVxuZXhwb3J0IGNsYXNzIEVSQzIwVG9rZW4gZXh0ZW5kcyBCYXNlTW9kZWwge1xuICBAcGsoeyB0eXBlOiBcIlN0cmluZ1wiIH0pXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVG9rZW4gdW5pcXVlIG5hbWVcbiAgICogQHN1bW1hcnkgU2VydmVzIGFzIHRoZSBwcmltYXJ5IGtleSBmb3IgdGhlIEVSQzIwIHRva2VuIGRlZmluaXRpb247IHR5cGljYWxseSBhIGh1bWFuLXJlYWRhYmxlIGlkZW50aWZpZXJcbiAgICovXG4gIG5hbWUhOiBzdHJpbmc7XG5cbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gT3duaW5nIGlkZW50aXR5IG9mIHRoZSB0b2tlblxuICAgKiBAc3VtbWFyeSBYLjUwOSBzdWJqZWN0IG9yIE1TUCBpZGVudGl0eSBzdHJpbmcgdGhhdCBkZW5vdGVzIHdobyBvd25zL2NvbnRyb2xzIHRoZSB0b2tlbiBkZWZpbml0aW9uXG4gICAqL1xuICBvd25lciE6IHN0cmluZztcbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVG9rZW4gc3ltYm9sXG4gICAqIEBzdW1tYXJ5IFNob3J0IHRpY2tlci1saWtlIHN5bWJvbCB1c2VkIHRvIHJlcHJlc2VudCB0aGUgdG9rZW4gKGUuZy4sIE1USylcbiAgICovXG4gIHN5bWJvbCE6IHN0cmluZztcbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVjaW1hbCBwcmVjaXNpb24gZm9yIHRva2VuIGFtb3VudHNcbiAgICogQHN1bW1hcnkgTnVtYmVyIG9mIGRpZ2l0cyBhZnRlciB0aGUgZGVjaW1hbCBzZXBhcmF0b3IgdXNlZCB3aGVuIGZvcm1hdHRpbmcgdG9rZW4gYmFsYW5jZXNcbiAgICovXG4gIGRlY2ltYWxzITogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKG0/OiBNb2RlbEFyZzxFUkMyMFdhbGxldD4pIHtcbiAgICBzdXBlcihtKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFUkMyMCB3YWxsZXQgbW9kZWxcbiAqIEBzdW1tYXJ5IFJlcHJlc2VudHMgYSBob2xkZXIgYWNjb3VudCBmb3IgYW4gRVJDMjAgdG9rZW4gd2l0aGluIHRoZSBGYWJyaWMgbmV0d29yaywgdHJhY2tpbmcgYmFsYW5jZSBhbmQgdG9rZW4gYXNzb2NpYXRpb24uXG4gKiBAcGFyYW0ge01vZGVsQXJnPEVSQzIwV2FsbGV0Pn0gW21dIC0gT3B0aW9uYWwgcGFydGlhbCBkYXRhIG9yIGFub3RoZXIgaW5zdGFuY2UgdG8gaW5pdGlhbGl6ZSB0aGUgbW9kZWxcbiAqIEByZXR1cm4ge3ZvaWR9XG4gKiBAY2xhc3MgRVJDMjBXYWxsZXRcbiAqIEBleGFtcGxlXG4gKiBjb25zdCB3YWxsZXQgPSBuZXcgRVJDMjBXYWxsZXQoeyBpZDogXCJhY2N0MVwiLCB0b2tlbjogXCJNeVRva2VuXCIsIGJhbGFuY2U6IDEwMDAgfSk7XG4gKiAvLyBVcGRhdGUgYmFsYW5jZSB2aWEgcmVwb3NpdG9yeTogYXdhaXQgcmVwby51cGRhdGUod2FsbGV0LCBjdHgpXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBwYXJ0aWNpcGFudCBSZXBvXG4gKiAgIEFwcC0+PlJlcG86IHJlYWQoXCJhY2N0MVwiLCBjdHgpXG4gKiAgIFJlcG8tLT4+QXBwOiBFUkMyMFdhbGxldFxuICovXG5AdGFibGUoXCJlcmMyMF93YWxsZXRzXCIpXG5AbW9kZWwoKVxuZXhwb3J0IGNsYXNzIEVSQzIwV2FsbGV0IGV4dGVuZHMgQmFzZU1vZGVsIHtcbiAgQHBrKHsgdHlwZTogXCJTdHJpbmdcIiB9KVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFdhbGxldCB1bmlxdWUgaWRlbnRpZmllclxuICAgKiBAc3VtbWFyeSBQcmltYXJ5IGtleSBmb3IgdGhlIHdhbGxldDsgY29tbW9ubHkgcmVmZXJlbmNlcyBhbiBhY2NvdW50IG9yIGlkZW50aXR5XG4gICAqL1xuICBpZCE6IHN0cmluZztcblxuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBBc3NvY2lhdGVkIHRva2VuIG5hbWVcbiAgICogQHN1bW1hcnkgUmVmZXJlbmNlcyB0aGUgRVJDMjBUb2tlbiB0aGlzIHdhbGxldCBob2xkczsgbWFpbnRhaW5lZCBhcyBhIHJlbGF0aW9uc2hpcCBmb3IgY2FzY2FkaW5nIHVwZGF0ZXMvZGVsZXRlc1xuICAgKi9cbiAgdG9rZW4hOiBzdHJpbmc7XG5cbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVG9rZW4gYmFsYW5jZSBmb3IgdGhpcyB3YWxsZXRcbiAgICogQHN1bW1hcnkgQ3VycmVudCBhbW91bnQgb2YgdGhlIGFzc29jaWF0ZWQgdG9rZW4gaGVsZCBieSB0aGlzIHdhbGxldFxuICAgKi9cbiAgYmFsYW5jZSE6IG51bWJlcjtcblxuICBAY29sdW1uKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDYXB0aXZlIGZsYWcgb3IgaWRlbnRpZmllclxuICAgKiBAc3VtbWFyeSBPcHRpb25hbCBmaWVsZCB1c2VkIGJ5IHNvbWUgZmxvd3MgdG8gbWFyayBub24tdHJhbnNmZXJhYmxlIGZ1bmRzIG9yIG1hbmFnZWQgY3VzdG9keVxuICAgKi9cbiAgY2FwdGl2ZSE6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihtPzogTW9kZWxBcmc8RVJDMjBXYWxsZXQ+KSB7XG4gICAgc3VwZXIobSk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRVJDMjAgYWxsb3dhbmNlIG1vZGVsXG4gKiBAc3VtbWFyeSBDYXB0dXJlcyBhbiBhcHByb3ZhbCByZWxhdGlvbnNoaXAgd2hlcmUgYW4gb3duZXIgYWxsb3dzIGEgc3BlbmRlciB0byB0cmFuc2ZlciB1cCB0byBhIGNlcnRhaW4gdmFsdWUgZnJvbSB0aGUgb3duZXIncyB3YWxsZXQuXG4gKiBAcGFyYW0ge01vZGVsQXJnPEFsbG93YW5jZT59IFttXSAtIE9wdGlvbmFsIHBhcnRpYWwgZGF0YSBvciBhbm90aGVyIGluc3RhbmNlIHRvIGluaXRpYWxpemUgdGhlIG1vZGVsXG4gKiBAcmV0dXJuIHt2b2lkfVxuICogQGNsYXNzIEFsbG93YW5jZVxuICogQGV4YW1wbGVcbiAqIGNvbnN0IGFsbG93YW5jZSA9IG5ldyBBbGxvd2FuY2UoeyBvd25lcjogXCJhY2N0MVwiLCBzcGVuZGVyOiBcImFjY3QyXCIsIHZhbHVlOiA1MCB9KTtcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQXBwXG4gKiAgIEFwcC0+PkFwcDogbmV3IEFsbG93YW5jZSh7IG93bmVyLCBzcGVuZGVyLCB2YWx1ZSB9KVxuICovXG5AdGFibGUoXCJlcmMyMF9hbGxvd2FuY2VzXCIpXG5AbW9kZWwoKVxuZXhwb3J0IGNsYXNzIEFsbG93YW5jZSBleHRlbmRzIEJhc2VNb2RlbCB7XG4gIEBwayh7IHR5cGU6IFwiU3RyaW5nXCIgfSlcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBBbGxvd2FuY2UgdW5pcXVlIGlkZW50aWZpZXJcbiAgICogQHN1bW1hcnkgUHJpbWFyeSBrZXkgZm9yIHRoZSBhbGxvd2FuY2U7IHR5cGljYWxseSBhIHVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgYXBwcm92YWwgcmVsYXRpb25zaGlwXG4gICAqL1xuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBPd25lciB3YWxsZXQgaWRlbnRpZmllclxuICAgKiBAc3VtbWFyeSBXYWxsZXQgdGhhdCBhdXRob3JpemVzIHRoZSBhbGxvd2FuY2VcbiAgICovXG4gIG93bmVyITogc3RyaW5nO1xuXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNwZW5kZXIgd2FsbGV0IGlkZW50aWZpZXJcbiAgICogQHN1bW1hcnkgV2FsbGV0IGFsbG93ZWQgdG8gc3BlbmQgdXAgdG8gdGhlIGFwcHJvdmVkIHZhbHVlIGZyb20gdGhlIG93bmVyXG4gICAqL1xuICBzcGVuZGVyITogc3RyaW5nO1xuXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEFwcHJvdmVkIHZhbHVlXG4gICAqIEBzdW1tYXJ5IE1heGltdW0gdG9rZW4gYW1vdW50IHRoZSBzcGVuZGVyIG1heSB0cmFuc2ZlciBvbiBiZWhhbGYgb2YgdGhlIG93bmVyXG4gICAqL1xuICB2YWx1ZSE6IG51bWJlcjtcblxuICBjb25zdHJ1Y3RvcihtPzogTW9kZWxBcmc8QWxsb3dhbmNlPikge1xuICAgIHN1cGVyKG0pO1xuICB9XG59XG4iLCJpbXBvcnQge1xuICBBdXRob3JpemF0aW9uRXJyb3IsXG4gIFJlcG8sXG4gIENvbnRleHQsXG4gIFVuc3VwcG9ydGVkRXJyb3IsXG4gIFJlcG9zaXRvcnksXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHtcbiAgSW50ZXJuYWxFcnJvcixcbiAgTm90Rm91bmRFcnJvcixcbiAgb25DcmVhdGUsXG4gIG9uRGVsZXRlLFxuICBvblJlYWQsXG4gIG9uVXBkYXRlLFxuICByZWFkb25seSxcbiAgdHJhbnNpZW50LFxufSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IE1vZGVsLCByZXF1aXJlZCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY01vZGVsS2V5cyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHR5cGUgeyBDb250ZXh0IGFzIEhMQ29udGV4dCB9IGZyb20gXCJmYWJyaWMtY29udHJhY3QtYXBpXCI7XG5pbXBvcnQgeyBGYWJyaWNFUkMyMENvbnRyYWN0IH0gZnJvbSBcIi4uL2NvbnRyYWN0cy9lcmMyMC9lcmMyMGNvbnRyYWN0XCI7XG5pbXBvcnQge1xuICBhcHBseSxcbiAgQ29uc3RydWN0b3IsXG4gIERlY29yYXRpb24sXG4gIG1ldGFkYXRhLFxuICBNZXRhZGF0YSxcbiAgcHJvcE1ldGFkYXRhLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY0ZsYWdzIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuLyoqXG4gKiBEZWNvcmF0b3IgZm9yIG1hcmtpbmcgbWV0aG9kcyB0aGF0IHJlcXVpcmUgb3duZXJzaGlwIGF1dGhvcml6YXRpb24uXG4gKiBDaGVja3MgdGhlIG93bmVyIG9mIHRoZSB0b2tlbiBiZWZvcmUgYWxsb3dpbmcgdGhlIG1ldGhvZCB0byBiZSBleGVjdXRlZC5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY2xhc3MgVG9rZW5Db250cmFjdCBleHRlbmRzIENvbnRyYWN0IHtcbiAqICAgQE93bmVyKClcbiAqICAgYXN5bmMgTWludChjdHg6IENvbnRleHQsIGFtb3VudDogbnVtYmVyKSB7XG4gKiAgICAgLy8gTWludCB0b2tlbiBsb2dpY1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBAcmV0dXJucyB7TWV0aG9kRGVjb3JhdG9yfSBBIG1ldGhvZCBkZWNvcmF0b3IgdGhhdCBjaGVja3Mgb3duZXJzaGlwIGF1dGhvcml6YXRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBPd25lcigpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChcbiAgICB0YXJnZXQ6IGFueSxcbiAgICBwcm9wZXJ0eUtleTogc3RyaW5nLFxuICAgIGRlc2NyaXB0b3I6IFByb3BlcnR5RGVzY3JpcHRvclxuICApIHtcbiAgICBjb25zdCBvcmlnaW5hbE1ldGhvZCA9IGRlc2NyaXB0b3IudmFsdWU7XG5cbiAgICBkZXNjcmlwdG9yLnZhbHVlID0gYXN5bmMgZnVuY3Rpb24gKFxuICAgICAgdGhpczogRmFicmljRVJDMjBDb250cmFjdCxcbiAgICAgIC4uLmFyZ3M6IGFueVtdXG4gICAgKSB7XG4gICAgICBjb25zdCBjdHg6IEhMQ29udGV4dCA9IGFyZ3NbMF07XG4gICAgICBjb25zdCBhY291bnRJZCA9IGN0eC5jbGllbnRJZGVudGl0eS5nZXRJRCgpO1xuXG4gICAgICBjb25zdCBzZWxlY3QgPSBhd2FpdCAodGhpcyBhcyBGYWJyaWNFUkMyMENvbnRyYWN0KVtcbiAgICAgICAgXCJ0b2tlblJlcG9zaXRvcnlcIlxuICAgICAgXS5zZWxlY3QoKTtcblxuICAgICAgY29uc3QgdG9rZW5zID0gYXdhaXQgc2VsZWN0LmV4ZWN1dGUoY3R4KTtcblxuICAgICAgaWYgKHRva2Vucy5sZW5ndGggPT0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihcIk5vIHRva2VucyBhdmFpYWxibGVcIik7XG4gICAgICB9XG5cbiAgICAgIGlmICh0b2tlbnMubGVuZ3RoID4gMSkge1xuICAgICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihgVG8gbWFueSB0b2tlbiBhdmFpbGFibGUgOiAke3Rva2Vucy5sZW5ndGh9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0b2tlbnNbMF0ub3duZXIgIT0gYWNvdW50SWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEF1dGhvcml6YXRpb25FcnJvcihcbiAgICAgICAgICBgVXNlciBub3QgYXV0aG9yaXplZCB0byBydW4gJHtwcm9wZXJ0eUtleX0gb24gdGhlIHRva2VuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gYXdhaXQgb3JpZ2luYWxNZXRob2QuYXBwbHkodGhpcywgYXJncyk7XG4gICAgfTtcblxuICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICB9O1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gb3duZWRCeU9uQ3JlYXRlPFxuICBNIGV4dGVuZHMgTW9kZWw8Ym9vbGVhbj4sXG4gIFIgZXh0ZW5kcyBSZXBvPE0+LFxuICBWLFxuPihcbiAgdGhpczogUixcbiAgY29udGV4dDogQ29udGV4dDxhbnk+LFxuICBkYXRhOiBWLFxuICBrZXk6IGtleW9mIE0sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgeyBzdHViIH0gPSBjb250ZXh0IGFzIGFueTtcblxuICBjb25zdCBjcmVhdG9yID0gYXdhaXQgc3R1Yi5nZXRDcmVhdG9yKCk7XG4gIGNvbnN0IG93bmVyID0gY3JlYXRvci5tc3BpZDtcblxuICBjb25zdCBzZXRPd25lZEJ5S2V5VmFsdWUgPSBmdW5jdGlvbiA8TSBleHRlbmRzIE1vZGVsPihcbiAgICB0YXJnZXQ6IE0sXG4gICAgcHJvcGVydHlLZXk6IHN0cmluZyxcbiAgICB2YWx1ZTogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50XG4gICkge1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIHByb3BlcnR5S2V5LCB7XG4gICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgdmFsdWU6IHZhbHVlLFxuICAgIH0pO1xuICB9O1xuXG4gIHNldE93bmVkQnlLZXlWYWx1ZShtb2RlbCwga2V5IGFzIHN0cmluZywgb3duZXIpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gT3duZWRCeSgpIHtcbiAgY29uc3Qga2V5ID0gZ2V0RmFicmljTW9kZWxLZXkoRmFicmljTW9kZWxLZXlzLk9XTkVEQlkpO1xuXG4gIGZ1bmN0aW9uIG93bmVkQnkoKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIChvYmo6IGFueSwgYXR0cmlidXRlPzogYW55KSB7XG4gICAgICByZXR1cm4gYXBwbHkoXG4gICAgICAgIHJlcXVpcmVkKCksXG4gICAgICAgIHJlYWRvbmx5KCksXG4gICAgICAgIG9uQ3JlYXRlKG93bmVkQnlPbkNyZWF0ZSksXG4gICAgICAgIHByb3BNZXRhZGF0YShnZXRGYWJyaWNNb2RlbEtleShGYWJyaWNNb2RlbEtleXMuT1dORURCWSksIGF0dHJpYnV0ZSlcbiAgICAgICkob2JqLCBhdHRyaWJ1dGUpO1xuICAgIH07XG4gIH1cblxuICByZXR1cm4gRGVjb3JhdGlvbi5mb3Ioa2V5KVxuICAgIC5kZWZpbmUoe1xuICAgICAgZGVjb3JhdG9yOiBvd25lZEJ5LFxuICAgICAgYXJnczogW10sXG4gICAgfSlcbiAgICAuYXBwbHkoKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEZhYnJpY01vZGVsS2V5KGtleTogc3RyaW5nKSB7XG4gIHJldHVybiBNZXRhZGF0YS5rZXkoRmFicmljTW9kZWxLZXlzLkZBQlJJQyArIGtleSk7XG59XG5cbmV4cG9ydCB0eXBlIENvbGxlY3Rpb25SZXNvbHZlciA9IDxNIGV4dGVuZHMgTW9kZWw+KG1vZGVsOiBNKSA9PiBzdHJpbmc7XG5cbmV4cG9ydCBjb25zdCBJbXBsaWNpdFByaXZhdGVDb2xsZWN0aW9uOiBDb2xsZWN0aW9uUmVzb2x2ZXIgPSA8TSBleHRlbmRzIE1vZGVsPihcbiAgbW9kZWw6IE1cbikgPT4ge1xuICByZXR1cm4gYF9fJHttb2RlbC5jb25zdHJ1Y3Rvci5uYW1lfVByaXZhdGVDb2xsZWN0aW9uYDtcbn07XG5cbmV4cG9ydCB0eXBlIFNlZ3JlZ2F0ZWREYXRhTWV0YWRhdGEgPSB7XG4gIGNvbGxlY3Rpb25zOiBzdHJpbmcgfCBDb2xsZWN0aW9uUmVzb2x2ZXI7XG59O1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2VncmVnYXRlZERhdGFPbkNyZWF0ZTxNIGV4dGVuZHMgTW9kZWw+KFxuICB0aGlzOiBSZXBvc2l0b3J5PE0sIGFueT4sXG4gIGNvbnRleHQ6IENvbnRleHQ8RmFicmljRmxhZ3M+LFxuICBkYXRhOiBTZWdyZWdhdGVkRGF0YU1ldGFkYXRhW10sXG4gIGtleXM6IChrZXlvZiBNKVtdLFxuICBtb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmIChrZXlzLmxlbmd0aCAhPT0gZGF0YS5sZW5ndGgpXG4gICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICBgU2VncmVnYXRlZCBkYXRhIGtleXMgYW5kIG1ldGFkYXRhIGxlbmd0aCBtaXNtYXRjaGBcbiAgICApO1xuXG4gIGNvbnN0IGNvbGxlY3Rpb25SZXNvbHZlciA9IGRhdGFbMF0uY29sbGVjdGlvbnM7XG4gIGNvbnN0IGNvbGxlY3Rpb24gPVxuICAgIHR5cGVvZiBjb2xsZWN0aW9uUmVzb2x2ZXIgPT09IFwic3RyaW5nXCJcbiAgICAgID8gY29sbGVjdGlvblJlc29sdmVyXG4gICAgICA6IGNvbGxlY3Rpb25SZXNvbHZlcihtb2RlbCk7XG5cbiAgY29uc3QgcmVidWlsdCA9IGtleXMucmVkdWNlKFxuICAgIChhY2M6IFJlY29yZDxrZXlvZiBNLCBhbnk+LCBrLCBpKSA9PiB7XG4gICAgICBjb25zdCBjID1cbiAgICAgICAgdHlwZW9mIGRhdGFbaV0uY29sbGVjdGlvbnMgPT09IFwic3RyaW5nXCJcbiAgICAgICAgICA/IGRhdGFbaV0uY29sbGVjdGlvbnNcbiAgICAgICAgICA6IGRhdGFbaV0uY29sbGVjdGlvbnMobW9kZWwpO1xuICAgICAgaWYgKGMgIT09IGNvbGxlY3Rpb24pXG4gICAgICAgIHRocm93IG5ldyBVbnN1cHBvcnRlZEVycm9yKFxuICAgICAgICAgIGBTZWdyZWdhdGVkIGRhdGEgY29sbGVjdGlvbiBtaXNtYXRjaDogJHtjfSB2cyAke2NvbGxlY3Rpb259YFxuICAgICAgICApO1xuICAgICAgYWNjW2tdID0gbW9kZWxba107XG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sXG4gICAge30gYXMgUmVjb3JkPGtleW9mIE0sIGFueT5cbiAgKTtcblxuICBjb25zdCB0b0NyZWF0ZSA9IG5ldyB0aGlzLmNsYXNzKHJlYnVpbHQpO1xuXG4gIC8vIGNvbnN0IHNlZ3JlZ2F0ZWQgPSBNb2RlbC5zZWdyZWdhdGUobW9kZWwpO1xuXG4gIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCB0aGlzLm92ZXJyaWRlKHsgc2VncmVnYXRlZDogY29sbGVjdGlvbiB9IGFzIGFueSkuY3JlYXRlKFxuICAgIHRvQ3JlYXRlLFxuICAgIGNvbnRleHRcbiAgKTtcbiAgT2JqZWN0LmFzc2lnbihtb2RlbCwgY3JlYXRlZCk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZWdyZWdhdGVkRGF0YU9uUmVhZDxNIGV4dGVuZHMgTW9kZWw+KFxuICB0aGlzOiBSZXBvc2l0b3J5PE0sIGFueT4sXG4gIGNvbnRleHQ6IENvbnRleHQ8RmFicmljRmxhZ3M+LFxuICBkYXRhOiBTZWdyZWdhdGVkRGF0YU1ldGFkYXRhW10sXG4gIGtleXM6IChrZXlvZiBNKVtdLFxuICBtb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmIChrZXlzLmxlbmd0aCAhPT0gZGF0YS5sZW5ndGgpXG4gICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICBgU2VncmVnYXRlZCBkYXRhIGtleXMgYW5kIG1ldGFkYXRhIGxlbmd0aCBtaXNtYXRjaGBcbiAgICApO1xuXG4gIGNvbnN0IGNvbGxlY3Rpb25SZXNvbHZlciA9IGRhdGFbMF0uY29sbGVjdGlvbnM7XG4gIGNvbnN0IGNvbGxlY3Rpb24gPVxuICAgIHR5cGVvZiBjb2xsZWN0aW9uUmVzb2x2ZXIgPT09IFwic3RyaW5nXCJcbiAgICAgID8gY29sbGVjdGlvblJlc29sdmVyXG4gICAgICA6IGNvbGxlY3Rpb25SZXNvbHZlcihtb2RlbCk7XG5cbiAgY29uc3QgcmVidWlsdCA9IGtleXMucmVkdWNlKFxuICAgIChhY2M6IFJlY29yZDxrZXlvZiBNLCBhbnk+LCBrLCBpKSA9PiB7XG4gICAgICBjb25zdCBjID1cbiAgICAgICAgdHlwZW9mIGRhdGFbaV0uY29sbGVjdGlvbnMgPT09IFwic3RyaW5nXCJcbiAgICAgICAgICA/IGRhdGFbaV0uY29sbGVjdGlvbnNcbiAgICAgICAgICA6IGRhdGFbaV0uY29sbGVjdGlvbnMobW9kZWwpO1xuICAgICAgaWYgKGMgIT09IGNvbGxlY3Rpb24pXG4gICAgICAgIHRocm93IG5ldyBVbnN1cHBvcnRlZEVycm9yKFxuICAgICAgICAgIGBTZWdyZWdhdGVkIGRhdGEgY29sbGVjdGlvbiBtaXNtYXRjaDogJHtjfSB2cyAke2NvbGxlY3Rpb259YFxuICAgICAgICApO1xuICAgICAgYWNjW2tdID0gbW9kZWxba107XG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sXG4gICAge30gYXMgUmVjb3JkPGtleW9mIE0sIGFueT5cbiAgKTtcblxuICBjb25zdCB0b0NyZWF0ZSA9IG5ldyB0aGlzLmNsYXNzKHJlYnVpbHQpO1xuXG4gIC8vIGNvbnN0IHNlZ3JlZ2F0ZWQgPSBNb2RlbC5zZWdyZWdhdGUobW9kZWwpO1xuXG4gIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCB0aGlzLm92ZXJyaWRlKHsgc2VncmVnYXRlZDogY29sbGVjdGlvbiB9IGFzIGFueSkuY3JlYXRlKFxuICAgIHRvQ3JlYXRlLFxuICAgIGNvbnRleHRcbiAgKTtcbiAgT2JqZWN0LmFzc2lnbihtb2RlbCwgY3JlYXRlZCk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZWdyZWdhdGVkRGF0YU9uVXBkYXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIHRoaXM6IFJlcG9zaXRvcnk8TSwgYW55PixcbiAgY29udGV4dDogQ29udGV4dDxGYWJyaWNGbGFncz4sXG4gIGRhdGE6IFNlZ3JlZ2F0ZWREYXRhTWV0YWRhdGFbXSxcbiAga2V5OiBrZXlvZiBNW10sXG4gIG1vZGVsOiBNLFxuICBvbGRNb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7fVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2VncmVnYXRlZERhdGFPbkRlbGV0ZTxcbiAgTSBleHRlbmRzIE1vZGVsLFxuICBSIGV4dGVuZHMgUmVwb3NpdG9yeTxNLCBhbnk+LFxuICBWIGV4dGVuZHMgU2VncmVnYXRlZERhdGFNZXRhZGF0YSxcbj4oXG4gIHRoaXM6IFIsXG4gIGNvbnRleHQ6IENvbnRleHQ8RmFicmljRmxhZ3M+LFxuICBkYXRhOiBWW10sXG4gIGtleToga2V5b2YgTVtdLFxuICBtb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7fVxuXG5mdW5jdGlvbiBzZWdyZWdhdGVkKFxuICBjb2xsZWN0aW9uOiBzdHJpbmcgfCBDb2xsZWN0aW9uUmVzb2x2ZXIsXG4gIHR5cGU6IEZhYnJpY01vZGVsS2V5cy5QUklWQVRFIHwgRmFicmljTW9kZWxLZXlzLlNIQVJFRFxuKSB7XG4gIHJldHVybiBmdW5jdGlvbiBpbm5lclNlZ3JlZ2F0ZWQodGFyZ2V0OiBvYmplY3QsIHByb3BlcnR5S2V5PzogYW55KSB7XG4gICAgZnVuY3Rpb24gc2VncmVnYXRlZERlYyh0YXJnZXQ6IG9iamVjdCwgcHJvcGVydHlLZXk/OiBhbnkpIHtcbiAgICAgIGlmICghcHJvcGVydHlLZXkpIHtcbiAgICAgICAgY29uc3QgcHJvcHMgPSBNZXRhZGF0YS5wcm9wZXJ0aWVzKHRhcmdldCBhcyBDb25zdHJ1Y3RvcikgfHwgW107XG4gICAgICAgIGZvciAoY29uc3QgcHJvcCBvZiBwcm9wcykgc2VncmVnYXRlZChjb2xsZWN0aW9uLCB0eXBlKSh0YXJnZXQsIHByb3ApO1xuICAgICAgICByZXR1cm4gdGFyZ2V0O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBrZXkgPSBNZXRhZGF0YS5rZXkodHlwZSwgcHJvcGVydHlLZXkpO1xuICAgICAgY29uc3QgY29uc3RyOiBDb25zdHJ1Y3RvciA9IHRhcmdldC5jb25zdHJ1Y3RvciBhcyBDb25zdHJ1Y3RvcjtcblxuICAgICAgY29uc3QgbWV0YSA9IE1ldGFkYXRhLmdldChjb25zdHIgYXMgQ29uc3RydWN0b3IsIGtleSkgfHwge307XG4gICAgICBjb25zdCBjb2xsZWN0aW9ucyA9IG5ldyBTZXQobWV0YS5jb2xsZWN0aW9ucyB8fCBbXSk7XG4gICAgICBjb2xsZWN0aW9ucy5hZGQoY29sbGVjdGlvbik7XG4gICAgICBtZXRhLmNvbGxlY3Rpb25zID0gWy4uLmNvbGxlY3Rpb25zXTtcbiAgICAgIE1ldGFkYXRhLnNldChjb25zdHIgYXMgQ29uc3RydWN0b3IsIGtleSwgbWV0YSk7XG4gICAgfVxuICAgIGNvbnN0IGRlY3M6IGFueVtdID0gW107XG4gICAgaWYgKCFwcm9wZXJ0eUtleSkge1xuICAgICAgLy8gZGVjb3JhdGVkIGF0IHRoZSBjbGFzcyBsZXZlbFxuICAgICAgTWV0YWRhdGEucHJvcGVydGllcyh0YXJnZXQgYXMgQ29uc3RydWN0b3IpPy5mb3JFYWNoKChwKSA9PlxuICAgICAgICBzZWdyZWdhdGVkKGNvbGxlY3Rpb24sIHR5cGUpKHRhcmdldCwgcClcbiAgICAgICk7XG4gICAgICByZXR1cm4gbWV0YWRhdGEodHlwZSwgdHJ1ZSkodGFyZ2V0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgZGVjcy5wdXNoKFxuICAgICAgICB0cmFuc2llbnQoKSxcbiAgICAgICAgc2VncmVnYXRlZERlYyxcbiAgICAgICAgb25DcmVhdGUoXG4gICAgICAgICAgc2VncmVnYXRlZERhdGFPbkNyZWF0ZSxcbiAgICAgICAgICB7IGNvbGxlY3Rpb25zOiBjb2xsZWN0aW9uIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgcHJpb3JpdHk6IDk1LFxuICAgICAgICAgICAgZ3JvdXA6XG4gICAgICAgICAgICAgIHR5cGVvZiBjb2xsZWN0aW9uID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICAgICAgPyBjb2xsZWN0aW9uXG4gICAgICAgICAgICAgICAgOiBjb2xsZWN0aW9uLnRvU3RyaW5nKCksXG4gICAgICAgICAgfVxuICAgICAgICApLFxuICAgICAgICBvblJlYWQoXG4gICAgICAgICAgc2VncmVnYXRlZERhdGFPblJlYWQgYXMgYW55LFxuICAgICAgICAgIHsgY29sbGVjdGlvbnM6IGNvbGxlY3Rpb24gfSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBwcmlvcml0eTogOTUsXG4gICAgICAgICAgICBncm91cDpcbiAgICAgICAgICAgICAgdHlwZW9mIGNvbGxlY3Rpb24gPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgICAgICA/IGNvbGxlY3Rpb25cbiAgICAgICAgICAgICAgICA6IGNvbGxlY3Rpb24udG9TdHJpbmcoKSxcbiAgICAgICAgICB9XG4gICAgICAgICksXG4gICAgICAgIG9uVXBkYXRlKFxuICAgICAgICAgIHNlZ3JlZ2F0ZWREYXRhT25VcGRhdGUgYXMgYW55LFxuICAgICAgICAgIHsgY29sbGVjdGlvbnM6IGNvbGxlY3Rpb24gfSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBwcmlvcml0eTogOTUsXG4gICAgICAgICAgICBncm91cDpcbiAgICAgICAgICAgICAgdHlwZW9mIGNvbGxlY3Rpb24gPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgICAgICA/IGNvbGxlY3Rpb25cbiAgICAgICAgICAgICAgICA6IGNvbGxlY3Rpb24udG9TdHJpbmcoKSxcbiAgICAgICAgICB9XG4gICAgICAgICksXG4gICAgICAgIG9uRGVsZXRlKFxuICAgICAgICAgIHNlZ3JlZ2F0ZWREYXRhT25EZWxldGUgYXMgYW55LFxuICAgICAgICAgIHsgY29sbGVjdGlvbnM6IGNvbGxlY3Rpb24gfSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBwcmlvcml0eTogOTUsXG4gICAgICAgICAgICBncm91cDpcbiAgICAgICAgICAgICAgdHlwZW9mIGNvbGxlY3Rpb24gPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgICAgICA/IGNvbGxlY3Rpb25cbiAgICAgICAgICAgICAgICA6IGNvbGxlY3Rpb24udG9TdHJpbmcoKSxcbiAgICAgICAgICB9XG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBhcHBseSguLi5kZWNzKSh0YXJnZXQsIHByb3BlcnR5S2V5KTtcbiAgICAvLyByZXR1cm4gYXBwbHkoKSh0YXJnZXQsIHByb3BlcnR5S2V5KTtcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHByaXZhdGVEYXRhKFxuICBjb2xsZWN0aW9uOiBzdHJpbmcgfCBDb2xsZWN0aW9uUmVzb2x2ZXIgPSBJbXBsaWNpdFByaXZhdGVDb2xsZWN0aW9uXG4pIHtcbiAgZnVuY3Rpb24gcHJpdmF0ZURhdGEoY29sbGVjdGlvbjogc3RyaW5nIHwgQ29sbGVjdGlvblJlc29sdmVyKSB7XG4gICAgcmV0dXJuIHNlZ3JlZ2F0ZWQoY29sbGVjdGlvbiwgRmFicmljTW9kZWxLZXlzLlBSSVZBVEUpO1xuICB9XG5cbiAgcmV0dXJuIERlY29yYXRpb24uZm9yKEZhYnJpY01vZGVsS2V5cy5QUklWQVRFKVxuICAgIC5kZWZpbmUoe1xuICAgICAgZGVjb3JhdG9yOiBwcml2YXRlRGF0YSxcbiAgICAgIGFyZ3M6IFtjb2xsZWN0aW9uXSxcbiAgICB9KVxuICAgIC5hcHBseSgpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2hhcmVkRGF0YShjb2xsZWN0aW9uOiBzdHJpbmcgfCBDb2xsZWN0aW9uUmVzb2x2ZXIpIHtcbiAgZnVuY3Rpb24gc2hhcmVkRGF0YShjb2xsZWN0aW9uOiBzdHJpbmcgfCBDb2xsZWN0aW9uUmVzb2x2ZXIpIHtcbiAgICByZXR1cm4gc2VncmVnYXRlZChjb2xsZWN0aW9uLCBGYWJyaWNNb2RlbEtleXMuU0hBUkVEKTtcbiAgfVxuXG4gIHJldHVybiBEZWNvcmF0aW9uLmZvcihGYWJyaWNNb2RlbEtleXMuU0hBUkVEKVxuICAgIC5kZWZpbmUoe1xuICAgICAgZGVjb3JhdG9yOiBzaGFyZWREYXRhLFxuICAgICAgYXJnczogW2NvbGxlY3Rpb25dLFxuICAgIH0pXG4gICAgLmFwcGx5KCk7XG59XG4vL1xuLy8gZXhwb3J0IGZ1bmN0aW9uIHByaXZhdGVEYXRhKGNvbGxlY3Rpb24/OiBzdHJpbmcpIHtcbi8vICAgaWYgKCFjb2xsZWN0aW9uKSB7XG4vLyAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29sbGVjdGlvbiBuYW1lIGlzIHJlcXVpcmVkXCIpO1xuLy8gICB9XG4vL1xuLy8gICBjb25zdCBrZXk6IHN0cmluZyA9IEZhYnJpY01vZGVsS2V5cy5QUklWQVRFO1xuLy9cbi8vICAgcmV0dXJuIGZ1bmN0aW9uIHByaXZhdGVEYXRhPE0gZXh0ZW5kcyBNb2RlbD4oXG4vLyAgICAgbW9kZWw6IE0gfCBDb25zdHJ1Y3RvcjxNPixcbi8vICAgICBhdHRyaWJ1dGU/OiBhbnlcbi8vICAgKSB7XG4vLyAgICAgY29uc3QgY29uc3RyID1cbi8vICAgICAgIG1vZGVsIGluc3RhbmNlb2YgTW9kZWwgPyAobW9kZWwuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IpIDogbW9kZWw7XG4vL1xuLy8gICAgIGNvbnN0IG1ldGFEYXRhOiBhbnkgPSBNZXRhZGF0YS5nZXQoY29uc3RyKTtcbi8vICAgICBjb25zdCBtb2RlbGRhdGEgPSBtZXRhRGF0YT8ucHJpdmF0ZT8uY29sbGVjdGlvbnMgfHwgW107XG4vL1xuLy8gICAgIHByb3BNZXRhZGF0YShrZXksIHtcbi8vICAgICAgIC4uLighYXR0cmlidXRlICYmIHtcbi8vICAgICAgICAgY29sbGVjdGlvbnM6IG1vZGVsZGF0YVxuLy8gICAgICAgICAgID8gWy4uLm5ldyBTZXQoWy4uLm1vZGVsZGF0YSwgY29sbGVjdGlvbl0pXVxuLy8gICAgICAgICAgIDogW2NvbGxlY3Rpb25dLFxuLy8gICAgICAgfSksXG4vLyAgICAgICBpc1ByaXZhdGU6ICFhdHRyaWJ1dGUsXG4vLyAgICAgfSkoYXR0cmlidXRlID8gY29uc3RyIDogbW9kZWwpO1xuLy9cbi8vICAgICBpZiAoYXR0cmlidXRlKSB7XG4vLyAgICAgICBjb25zdCBhdHRyaWJ1dGVEYXRhID1cbi8vICAgICAgICAgKG1ldGFEYXRhPy5wcml2YXRlPy5bYXR0cmlidXRlXSBhcyBhbnkpPy5jb2xsZWN0aW9ucyB8fCBbXTtcbi8vICAgICAgIHByb3BNZXRhZGF0YShNZXRhZGF0YS5rZXkoa2V5LCBhdHRyaWJ1dGUpLCB7XG4vLyAgICAgICAgIGNvbGxlY3Rpb25zOiBhdHRyaWJ1dGVEYXRhXG4vLyAgICAgICAgICAgPyBbLi4ubmV3IFNldChbLi4uYXR0cmlidXRlRGF0YSwgY29sbGVjdGlvbl0pXVxuLy8gICAgICAgICAgIDogW2NvbGxlY3Rpb25dLFxuLy8gICAgICAgfSkobW9kZWwsIGF0dHJpYnV0ZSk7XG4vLyAgICAgICB0cmFuc2llbnQoKShtb2RlbCwgYXR0cmlidXRlKTtcbi8vICAgICB9XG4vLyAgIH07XG4vLyB9XG4iLCIvKipcbiAqIEVudW0gcmVwcmVzZW50aW5nIHRoZSBldmVudHMgZW1pdHRlZCBieSBhbiBFUkMyMCBjb250cmFjdC5cbiAqXG4gKiBAcmVtYXJrc1xuICogVGhpcyBlbnVtIGlzIHVzZWQgdG8gaWRlbnRpZnkgdGhlIHNwZWNpZmljIGV2ZW50cyB0aGF0IGNhbiBiZSBlbWl0dGVkIGJ5IGFuIEVSQzIwIGNvbnRyYWN0LlxuICogVGhlIGV2ZW50cyBhcmUgbmFtZWQgYWNjb3JkaW5nIHRvIHRoZSBFSVAtMjAgc3RhbmRhcmQuXG4gKi9cbmV4cG9ydCBlbnVtIEVSQzIwRXZlbnRzIHtcbiAgLyoqXG4gICAqIEVtaXR0ZWQgd2hlbiBhIGB0cmFuc2ZlcmAgZnVuY3Rpb24gaXMgY2FsbGVkIHN1Y2Nlc3NmdWxseS5cbiAgICpcbiAgICogQHBhcmFtIGZyb20gLSBUaGUgYWRkcmVzcyBvZiB0aGUgc2VuZGVyLlxuICAgKiBAcGFyYW0gdG8gLSBUaGUgYWRkcmVzcyBvZiB0aGUgcmVjaXBpZW50LlxuICAgKiBAcGFyYW0gdmFsdWUgLSBUaGUgYW1vdW50IG9mIHRva2VucyB0cmFuc2ZlcnJlZC5cbiAgICovXG4gIFRSQU5TRkVSID0gXCJUcmFuc2ZlclwiLFxuXG4gIC8qKlxuICAgKiBFbWl0dGVkIHdoZW4gYW4gYGFwcHJvdmVgIGZ1bmN0aW9uIGlzIGNhbGxlZCBzdWNjZXNzZnVsbHkuXG4gICAqXG4gICAqIEBwYXJhbSBvd25lciAtIFRoZSBhZGRyZXNzIG9mIHRoZSB0b2tlbiBvd25lci5cbiAgICogQHBhcmFtIHNwZW5kZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgYXBwcm92ZWQgc3BlbmRlci5cbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIGFtb3VudCBvZiB0b2tlbnMgYXBwcm92ZWQgZm9yIHRoZSBzcGVuZGVyLlxuICAgKi9cbiAgQVBQUk9WQUwgPSBcIkFwcHJvdmFsXCIsXG59XG4iLCJpbXBvcnQgeyBBdXRob3JpemF0aW9uRXJyb3IsIENvbmRpdGlvbiB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgQ29udGV4dCwgVHJhbnNhY3Rpb24gfSBmcm9tIFwiZmFicmljLWNvbnRyYWN0LWFwaVwiO1xuaW1wb3J0IHsgYWRkLCBzdWIgfSBmcm9tIFwiLi4vLi4vc2hhcmVkL21hdGhcIjtcbmltcG9ydCB7XG4gIEFsbG93YW5jZUVycm9yLFxuICBCYWxhbmNlRXJyb3IsXG4gIE5vdEluaXRpYWxpemVkRXJyb3IsXG59IGZyb20gXCIuLi8uLi9zaGFyZWQvZXJyb3JzXCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdEFkYXB0ZXIgfSBmcm9tIFwiLi4vQ29udHJhY3RBZGFwdGVyXCI7XG5pbXBvcnQgeyBBbGxvd2FuY2UsIEVSQzIwVG9rZW4sIEVSQzIwV2FsbGV0IH0gZnJvbSBcIi4vbW9kZWxzXCI7XG5pbXBvcnQgeyBPd25lciB9IGZyb20gXCIuLi8uLi9zaGFyZWQvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5IH0gZnJvbSBcIi4uL0ZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeVwiO1xuaW1wb3J0IHR5cGUgeyBGYWJyaWNDb250cmFjdENvbnRleHQgfSBmcm9tIFwiLi4vQ29udHJhY3RDb250ZXh0XCI7XG5pbXBvcnQge1xuICBCYXNlRXJyb3IsXG4gIEludGVybmFsRXJyb3IsXG4gIE5vdEZvdW5kRXJyb3IsXG4gIFZhbGlkYXRpb25FcnJvcixcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBGYWJyaWNDcnVkQ29udHJhY3QgfSBmcm9tIFwiLi4vY3J1ZC9jcnVkLWNvbnRyYWN0XCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnlPYnNlcnZhYmxlSGFuZGxlciB9IGZyb20gXCIuLi9GYWJyaWNDb250cmFjdFJlcG9zaXRvcnlPYnNlcnZhYmxlSGFuZGxlclwiO1xuaW1wb3J0IHsgRVJDMjBFdmVudHMgfSBmcm9tIFwiLi4vLi4vc2hhcmVkL2VyYzIwL2VyYzIwLWNvbnN0YW50c1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFUkMyMCB0b2tlbiBjb250cmFjdCBiYXNlIGZvciBIeXBlcmxlZGdlciBGYWJyaWNcbiAqIEBzdW1tYXJ5IEltcGxlbWVudHMgRVJDMjAtbGlrZSB0b2tlbiBsb2dpYyB1c2luZyByZXBvc2l0b3JpZXMgYW5kIGFkYXB0ZXJzLCBwcm92aWRpbmcgc3RhbmRhcmQgdG9rZW4gb3BlcmF0aW9ucyBzdWNoIGFzIGJhbGFuY2UgcXVlcmllcywgdHJhbnNmZXJzLCBhcHByb3ZhbHMsIG1pbnRpbmcgYW5kIGJ1cm5pbmcuXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBjb250cmFjdCBuYW1lIHVzZWQgdG8gc2NvcGUgdG9rZW4gaWRlbnRpdHlcbiAqIEBub3RlIGh0dHBzOi8vZWlwcy5ldGhlcmV1bS5vcmcvRUlQUy9laXAtMjBcbiAqIEByZXR1cm4ge3ZvaWR9XG4gKiBAY2xhc3MgRmFicmljRVJDMjBDb250cmFjdFxuICogQGV4YW1wbGVcbiAqIGNsYXNzIE15VG9rZW5Db250cmFjdCBleHRlbmRzIEZhYnJpY0VSQzIwQ29udHJhY3Qge1xuICogICBjb25zdHJ1Y3RvcigpIHsgc3VwZXIoJ015VG9rZW4nKTsgfVxuICogfVxuICogLy8gVGhlIGNvbnRyYWN0IGV4cG9zZXMgbWV0aG9kcyBsaWtlIFRyYW5zZmVyLCBBcHByb3ZlLCBNaW50LCBCdXJuLCBldGMuXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENsaWVudFxuICogICBwYXJ0aWNpcGFudCBDb250cmFjdFxuICogICBwYXJ0aWNpcGFudCBXYWxsZXRSZXBvXG4gKiAgIHBhcnRpY2lwYW50IFRva2VuUmVwb1xuICogICBwYXJ0aWNpcGFudCBMZWRnZXJcbiAqICAgQ2xpZW50LT4+Q29udHJhY3Q6IFRyYW5zZmVyKGN0eCwgdG8sIHZhbHVlKVxuICogICBDb250cmFjdC0+PldhbGxldFJlcG86IHJlYWQoZnJvbSlcbiAqICAgQ29udHJhY3QtPj5XYWxsZXRSZXBvOiByZWFkKHRvKVxuICogICBDb250cmFjdC0+PkxlZGdlcjogcHV0U3RhdGUodXBkYXRlZCBiYWxhbmNlcylcbiAqICAgQ29udHJhY3QtLT4+Q2xpZW50OiBzdWNjZXNzXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBGYWJyaWNFUkMyMENvbnRyYWN0IGV4dGVuZHMgRmFicmljQ3J1ZENvbnRyYWN0PEVSQzIwV2FsbGV0PiB7XG4gIHByaXZhdGUgd2FsbGV0UmVwb3NpdG9yeTogRmFicmljQ29udHJhY3RSZXBvc2l0b3J5PEVSQzIwV2FsbGV0PjtcblxuICBwcml2YXRlIHRva2VuUmVwb3NpdG9yeTogRmFicmljQ29udHJhY3RSZXBvc2l0b3J5PEVSQzIwVG9rZW4+O1xuXG4gIHByaXZhdGUgYWxsb3dhbmNlUmVwb3NpdG9yeTogRmFicmljQ29udHJhY3RSZXBvc2l0b3J5PEFsbG93YW5jZT47XG5cbiAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yKG5hbWU6IHN0cmluZykge1xuICAgIHN1cGVyKG5hbWUsIEVSQzIwV2FsbGV0KTtcblxuICAgIEZhYnJpY0VSQzIwQ29udHJhY3QuYWRhcHRlciA9XG4gICAgICBGYWJyaWNFUkMyMENvbnRyYWN0LmFkYXB0ZXIgfHwgbmV3IEZhYnJpY0NvbnRyYWN0QWRhcHRlcigpO1xuXG4gICAgdGhpcy53YWxsZXRSZXBvc2l0b3J5ID0gRmFicmljQ29udHJhY3RSZXBvc2l0b3J5LmZvck1vZGVsKFxuICAgICAgRVJDMjBXYWxsZXQsXG4gICAgICBGYWJyaWNFUkMyMENvbnRyYWN0LmFkYXB0ZXIuYWxpYXNcbiAgICApO1xuXG4gICAgdGhpcy50b2tlblJlcG9zaXRvcnkgPSBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnkuZm9yTW9kZWwoXG4gICAgICBFUkMyMFRva2VuLFxuICAgICAgRmFicmljRVJDMjBDb250cmFjdC5hZGFwdGVyLmFsaWFzXG4gICAgKTtcblxuICAgIHRoaXMuYWxsb3dhbmNlUmVwb3NpdG9yeSA9IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeS5mb3JNb2RlbChcbiAgICAgIEFsbG93YW5jZSxcbiAgICAgIEZhYnJpY0VSQzIwQ29udHJhY3QuYWRhcHRlci5hbGlhc1xuICAgICk7XG4gIH1cblxuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIGFzeW5jIFRva2VuTmFtZShjb250ZXh0OiBDb250ZXh0KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLlRva2VuTmFtZSk7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQgZmlyc3QgdG8gZXhlY3V0ZSB0aGUgZnVuY3Rpb25cbiAgICBhd2FpdCB0aGlzLkNoZWNrSW5pdGlhbGl6ZWQoY3R4IGFzIGFueSk7XG5cbiAgICBjb25zdCBzZWxlY3QgPSB0aGlzLnRva2VuUmVwb3NpdG9yeS5zZWxlY3QoKTtcbiAgICBjb25zdCB0b2tlbiA9IChhd2FpdCBzZWxlY3QuZXhlY3V0ZShjdHgpKVswXTtcblxuICAgIHJldHVybiB0b2tlbi5uYW1lO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgc3ltYm9sIG9mIHRoZSB0b2tlbi4gRS5nLiDigJxISVjigJ0uXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY29udGV4dCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcmV0dXJucyB7U3RyaW5nfSBSZXR1cm5zIHRoZSBzeW1ib2wgb2YgdGhlIHRva2VuXG4gICAqL1xuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIGFzeW5jIFN5bWJvbChjb250ZXh0OiBDb250ZXh0KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLlRva2VuTmFtZSk7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQgZmlyc3QgdG8gZXhlY3V0ZSB0aGUgZnVuY3Rpb25cbiAgICBhd2FpdCB0aGlzLkNoZWNrSW5pdGlhbGl6ZWQoY3R4IGFzIGFueSk7XG5cbiAgICBjb25zdCBzZWxlY3QgPSB0aGlzLnRva2VuUmVwb3NpdG9yeS5zZWxlY3QoKTtcbiAgICBjb25zdCB0b2tlbiA9IChhd2FpdCBzZWxlY3QuZXhlY3V0ZShjdHgpKVswXTtcblxuICAgIHJldHVybiB0b2tlbi5zeW1ib2w7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBudW1iZXIgb2YgZGVjaW1hbHMgdGhlIHRva2VuIHVzZXNcbiAgICogZS5nLiA4LCBtZWFucyB0byBkaXZpZGUgdGhlIHRva2VuIGFtb3VudCBieSAxMDAwMDAwMDAgdG8gZ2V0IGl0cyB1c2VyIHJlcHJlc2VudGF0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGNvbnRleHQgdGhlIHRyYW5zYWN0aW9uIGNvbnRleHRcbiAgICogQHJldHVybnMge051bWJlcn0gUmV0dXJucyB0aGUgbnVtYmVyIG9mIGRlY2ltYWxzXG4gICAqL1xuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIGFzeW5jIERlY2ltYWxzKGNvbnRleHQ6IENvbnRleHQpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuVG9rZW5OYW1lKTtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHggYXMgYW55KTtcblxuICAgIGNvbnN0IHNlbGVjdCA9IHRoaXMudG9rZW5SZXBvc2l0b3J5LnNlbGVjdCgpO1xuICAgIGNvbnN0IHRva2VuID0gKGF3YWl0IHNlbGVjdC5leGVjdXRlKGN0eCkpWzBdO1xuXG4gICAgcmV0dXJuIHRva2VuLmRlY2ltYWxzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgdG90YWwgdG9rZW4gc3VwcGx5LlxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGNvbnRleHQgdGhlIHRyYW5zYWN0aW9uIGNvbnRleHRcbiAgICogQHJldHVybnMge051bWJlcn0gUmV0dXJucyB0aGUgdG90YWwgdG9rZW4gc3VwcGx5XG4gICAqL1xuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIGFzeW5jIFRvdGFsU3VwcGx5KGNvbnRleHQ6IENvbnRleHQpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuVG9rZW5OYW1lKTtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHggYXMgYW55KTtcblxuICAgIGNvbnN0IHNlbGVjdCA9IHRoaXMud2FsbGV0UmVwb3NpdG9yeS5zZWxlY3QoKTtcbiAgICBjb25zdCB3YWxsZXRzID0gYXdhaXQgc2VsZWN0LmV4ZWN1dGUoY3R4KTtcblxuICAgIGlmICh3YWxsZXRzLmxlbmd0aCA9PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgTm90Rm91bmRFcnJvcihgVGhlIHRva2VuICR7dGhpcy5nZXROYW1lKCl9IGRvZXMgbm90IGV4aXN0YCk7XG4gICAgfVxuXG4gICAgbGV0IHRvdGFsID0gMDtcblxuICAgIHdhbGxldHMuZm9yRWFjaCgod2FsbGV0KSA9PiB7XG4gICAgICB0b3RhbCArPSB3YWxsZXQuYmFsYW5jZTtcbiAgICB9KTtcblxuICAgIHJldHVybiB0b3RhbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBCYWxhbmNlT2YgcmV0dXJucyB0aGUgYmFsYW5jZSBvZiB0aGUgZ2l2ZW4gYWNjb3VudC5cbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjdHggdGhlIHRyYW5zYWN0aW9uIGNvbnRleHRcbiAgICogQHBhcmFtIHtTdHJpbmd9IG93bmVyIFRoZSBvd25lciBmcm9tIHdoaWNoIHRoZSBiYWxhbmNlIHdpbGwgYmUgcmV0cmlldmVkXG4gICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgdGhlIGFjY291bnQgYmFsYW5jZVxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBCYWxhbmNlT2YoY29udGV4dDogQ29udGV4dCwgb3duZXI6IHN0cmluZyk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5Ub2tlbk5hbWUpO1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCBhcyBhbnkpO1xuXG4gICAgY29uc3Qgd2FsbGV0ID0gYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnJlYWQob3duZXIsIGN0eCk7XG5cbiAgICByZXR1cm4gd2FsbGV0LmJhbGFuY2U7XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgVHJhbnNmZXIgdHJhbnNmZXJzIHRva2VucyBmcm9tIGNsaWVudCBhY2NvdW50IHRvIHJlY2lwaWVudCBhY2NvdW50LlxuICAgKiBAZGVzY3JpcHRpb24gcmVjaXBpZW50IGFjY291bnQgbXVzdCBiZSBhIHZhbGlkIGNsaWVudElEIGFzIHJldHVybmVkIGJ5IHRoZSBDbGllbnRBY2NvdW50SUQoKSBmdW5jdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjb250ZXh0IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSB0byBUaGUgcmVjaXBpZW50XG4gICAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSBUaGUgYW1vdW50IG9mIHRva2VuIHRvIGJlIHRyYW5zZmVycmVkXG4gICAqXG4gICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm4gd2hldGhlciB0aGUgdHJhbnNmZXIgd2FzIHN1Y2Nlc3NmdWwgb3Igbm90XG4gICAqL1xuICBAVHJhbnNhY3Rpb24oKVxuICBhc3luYyBUcmFuc2ZlcihcbiAgICBjb250ZXh0OiBDb250ZXh0LFxuICAgIHRvOiBzdHJpbmcsXG4gICAgdmFsdWU6IG51bWJlclxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuVHJhbnNmZXIpO1xuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHggYXMgYW55KTtcblxuICAgIGNvbnN0IGZyb20gPSBjdHguaWRlbnRpdHkuZ2V0SUQoKTtcblxuICAgIGNvbnN0IHRyYW5zZmVyUmVzcCA9IGF3YWl0IHRoaXMuX3RyYW5zZmVyKGZyb20sIHRvLCB2YWx1ZSwgY3R4KTtcbiAgICBpZiAoIXRyYW5zZmVyUmVzcCkge1xuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJGYWlsZWQgdG8gdHJhbnNmZXJcIik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogVHJhbnNmZXIgYHZhbHVlYCBhbW91bnQgb2YgdG9rZW5zIGZyb20gYGZyb21gIHRvIGB0b2AuXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY29udGV4dCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge1N0cmluZ30gZnJvbSBUaGUgc2VuZGVyXG4gICAqIEBwYXJhbSB7U3RyaW5nfSB0byBUaGUgcmVjaXBpZW50XG4gICAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSBUaGUgYW1vdW50IG9mIHRva2VuIHRvIGJlIHRyYW5zZmVycmVkXG4gICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm4gd2hldGhlciB0aGUgdHJhbnNmZXIgd2FzIHN1Y2Nlc3NmdWwgb3Igbm90XG4gICAqL1xuICBAVHJhbnNhY3Rpb24oKVxuICBhc3luYyBUcmFuc2ZlckZyb20oXG4gICAgY29udGV4dDogQ29udGV4dCxcbiAgICBmcm9tOiBzdHJpbmcsXG4gICAgdG86IHN0cmluZyxcbiAgICB2YWx1ZTogbnVtYmVyXG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5CdXJuRnJvbSk7XG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCBhcyBhbnkpO1xuXG4gICAgLy8gUmV0cmlldmUgdGhlIGFsbG93YW5jZSBvZiB0aGUgc3BlbmRlclxuXG4gICAgY29uc3Qgc3BlbmRlciA9IGN0eC5pZGVudGl0eS5nZXRJRCgpO1xuXG4gICAgY29uc3QgYWxsb3dhbmNlID0gYXdhaXQgdGhpcy5fZ2V0QWxsb3dhbmNlKGZyb20sIHNwZW5kZXIsIGN0eCk7XG4gICAgaWYgKCFhbGxvd2FuY2UgfHwgYWxsb3dhbmNlLnZhbHVlIDwgMCkge1xuICAgICAgdGhyb3cgbmV3IEFsbG93YW5jZUVycm9yKFxuICAgICAgICBgc3BlbmRlciAke3NwZW5kZXJ9IGhhcyBubyBhbGxvd2FuY2UgZnJvbSAke2Zyb219YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJyZW50QWxsb3dhbmNlID0gYWxsb3dhbmNlLnZhbHVlO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHRyYW5zZmVycmVkIHZhbHVlIGlzIGxlc3MgdGhhbiB0aGUgYWxsb3dhbmNlXG4gICAgaWYgKGN1cnJlbnRBbGxvd2FuY2UgPCB2YWx1ZSkge1xuICAgICAgdGhyb3cgbmV3IEJhbGFuY2VFcnJvcihcbiAgICAgICAgXCJUaGUgc3BlbmRlciBkb2VzIG5vdCBoYXZlIGVub3VnaCBhbGxvd2FuY2UgdG8gc3BlbmQuXCJcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gRGVjcmVhc2UgdGhlIGFsbG93YW5jZVxuICAgIGNvbnN0IHVwZGF0ZWRBbGxvd2FuY2UgPSBzdWIoY3VycmVudEFsbG93YW5jZSwgdmFsdWUpO1xuICAgIGNvbnN0IG5ld0FsbG93YW5jZSA9IE9iamVjdC5hc3NpZ24oe30sIGFsbG93YW5jZSwge1xuICAgICAgdmFsdWU6IHVwZGF0ZWRBbGxvd2FuY2UsXG4gICAgfSk7XG5cbiAgICBhd2FpdCB0aGlzLmFsbG93YW5jZVJlcG9zaXRvcnkudXBkYXRlKG5ld0FsbG93YW5jZSwgY3R4KTtcblxuICAgIC8vUmVhbGl6ZSB0aGUgdHJhbnNmZXJcbiAgICBjb25zdCB0cmFuc2ZlclJlc3AgPSBhd2FpdCB0aGlzLl90cmFuc2Zlcihmcm9tLCB0bywgdmFsdWUsIGN0eCk7XG4gICAgaWYgKCF0cmFuc2ZlclJlc3ApIHtcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiRmFpbGVkIHRvIHRyYW5zZmVyXCIpO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgYXN5bmMgX3RyYW5zZmVyKFxuICAgIGZyb206IHN0cmluZyxcbiAgICB0bzogc3RyaW5nLFxuICAgIHZhbHVlOiBudW1iZXIsXG4gICAgY3R4OiBGYWJyaWNDb250cmFjdENvbnRleHRcbiAgKSB7XG4gICAgY29uc3QgbG9nID0gY3R4LmxvZ2dlcjtcblxuICAgIGlmIChmcm9tID09PSB0bykge1xuICAgICAgdGhyb3cgbmV3IEF1dGhvcml6YXRpb25FcnJvcihcbiAgICAgICAgXCJjYW5ub3QgdHJhbnNmZXIgdG8gYW5kIGZyb20gc2FtZSBjbGllbnQgYWNjb3VudFwiXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICh2YWx1ZSA8IDApIHtcbiAgICAgIC8vIHRyYW5zZmVyIG9mIDAgaXMgYWxsb3dlZCBpbiBFUkMyMCwgc28ganVzdCB2YWxpZGF0ZSBhZ2FpbnN0IG5lZ2F0aXZlIGFtb3VudHNcbiAgICAgIHRocm93IG5ldyBCYWxhbmNlRXJyb3IoXCJ0cmFuc2ZlciBhbW91bnQgY2Fubm90IGJlIG5lZ2F0aXZlXCIpO1xuICAgIH1cblxuICAgIC8vIFJldHJpZXZlIHRoZSBjdXJyZW50IGJhbGFuY2Ugb2YgdGhlIHNlbmRlclxuXG4gICAgY29uc3QgZnJvbVdhbGxldCA9IGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS5yZWFkKGZyb20sIGN0eCk7XG5cbiAgICBjb25zdCBmcm9tQmFsYW5jZSA9IGZyb21XYWxsZXQuYmFsYW5jZTtcblxuICAgIC8vIENoZWNrIGlmIHRoZSBzZW5kZXIgaGFzIGVub3VnaCB0b2tlbnMgdG8gc3BlbmQuXG4gICAgaWYgKGZyb21CYWxhbmNlIDwgdmFsdWUpIHtcbiAgICAgIHRocm93IG5ldyBCYWxhbmNlRXJyb3IoYGNsaWVudCBhY2NvdW50ICR7ZnJvbX0gaGFzIGluc3VmZmljaWVudCBmdW5kcy5gKTtcbiAgICB9XG5cbiAgICAvLyBSZXRyaWV2ZSB0aGUgY3VycmVudCBiYWxhbmNlIG9mIHRoZSByZWNlcGllbnRcblxuICAgIGxldCB0b1dhbGxldDogRVJDMjBXYWxsZXQ7XG4gICAgbGV0IG5ld1RvV2FsbGV0OiBib29sZWFuID0gZmFsc2U7XG4gICAgdHJ5IHtcbiAgICAgIHRvV2FsbGV0ID0gYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnJlYWQodG8sIGN0eCk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgaWYgKGUgaW5zdGFuY2VvZiBCYXNlRXJyb3IpIHtcbiAgICAgICAgaWYgKGUuY29kZSA9PT0gNDA0KSB7XG4gICAgICAgICAgLy8gQ3JlYXRlIGEgbmV3IHdhbGxldCBmb3IgdGhlIG1pbnRlclxuICAgICAgICAgIHRvV2FsbGV0ID0gbmV3IEVSQzIwV2FsbGV0KHtcbiAgICAgICAgICAgIGlkOiB0byxcbiAgICAgICAgICAgIGJhbGFuY2U6IDAsXG4gICAgICAgICAgICB0b2tlbjogYXdhaXQgdGhpcy5Ub2tlbk5hbWUoY3R4IGFzIGFueSksXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgbmV3VG9XYWxsZXQgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGUubWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGUgYXMgc3RyaW5nKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCB0b0JhbGFuY2UgPSB0b1dhbGxldC5iYWxhbmNlO1xuXG4gICAgLy8gVXBkYXRlIHRoZSBiYWxhbmNlXG4gICAgY29uc3QgZnJvbVVwZGF0ZWRCYWxhbmNlID0gc3ViKGZyb21CYWxhbmNlLCB2YWx1ZSk7XG4gICAgY29uc3QgdG9VcGRhdGVkQmFsYW5jZSA9IGFkZCh0b0JhbGFuY2UsIHZhbHVlKTtcblxuICAgIGNvbnN0IHVwZGF0ZWRGcm9tV2FsbGV0ID0gT2JqZWN0LmFzc2lnbih7fSwgZnJvbVdhbGxldCwge1xuICAgICAgYmFsYW5jZTogZnJvbVVwZGF0ZWRCYWxhbmNlLFxuICAgIH0pO1xuXG4gICAgYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnVwZGF0ZSh1cGRhdGVkRnJvbVdhbGxldCwgY3R4KTtcblxuICAgIGNvbnN0IHVwZGF0ZWRUb1dhbGxldCA9IE9iamVjdC5hc3NpZ24oe30sIHRvV2FsbGV0LCB7XG4gICAgICBiYWxhbmNlOiB0b1VwZGF0ZWRCYWxhbmNlLFxuICAgIH0pO1xuXG4gICAgaWYgKG5ld1RvV2FsbGV0KSB7XG4gICAgICBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkuY3JlYXRlKHVwZGF0ZWRUb1dhbGxldCwgY3R4KTtcbiAgICB9IGVsc2Uge1xuICAgICAgYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnVwZGF0ZSh1cGRhdGVkVG9XYWxsZXQsIGN0eCk7XG4gICAgfVxuXG4gICAgLy8gRW1pdCB0aGUgVHJhbnNmZXIgZXZlbnRcbiAgICBjb25zdCB0cmFuc2ZlckV2ZW50ID0geyBmcm9tLCB0bywgdmFsdWU6IHZhbHVlIH07XG5cbiAgICB0aGlzLnJlcG9cbiAgICAgIC5yZWZyZXNoKFxuICAgICAgICBFUkMyMFRva2VuIGFzIGFueSxcbiAgICAgICAgRVJDMjBFdmVudHMuVFJBTlNGRVIsXG4gICAgICAgIFwiXCIsXG4gICAgICAgIHRyYW5zZmVyRXZlbnQsXG4gICAgICAgIGN0eCBhcyB1bmtub3duIGFzIEZhYnJpY0NvbnRyYWN0Q29udGV4dFxuICAgICAgKVxuICAgICAgLmNhdGNoKChlKSA9PiBsb2cuZXJyb3IoYEZhaWxlZCB0byBub3RpZnkgdHJhbnNmZXI6ICR7ZX1gKSk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbGxvd3MgYHNwZW5kZXJgIHRvIHNwZW5kIGB2YWx1ZWAgYW1vdW50IG9mIHRva2VucyBmcm9tIHRoZSBvd25lci4gTmV3IEFwcHJvdmUgY2FsbHMgb3ZlcnJpZGUgdGhlIHByZXZpb3VzIGFsbG93YW5jZS5cbiAgICogQG5vdGUgaHR0cHM6Ly9laXBzLmV0aGVyZXVtLm9yZy9FSVBTL2VpcC0yMFxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGN0eCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge1N0cmluZ30gc3BlbmRlciBUaGUgc3BlbmRlclxuICAgKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgVGhlIGFtb3VudCBvZiB0b2tlbnMgdG8gYmUgYXBwcm92ZWQgZm9yIHRyYW5zZmVyXG4gICAqIEByZXR1cm5zIHtCb29sZWFufSBSZXR1cm4gd2hldGhlciB0aGUgYXBwcm92YWwgd2FzIHN1Y2Nlc3NmdWwgb3Igbm90XG4gICAqL1xuICBAVHJhbnNhY3Rpb24oKVxuICBhc3luYyBBcHByb3ZlKFxuICAgIGNvbnRleHQ6IENvbnRleHQsXG4gICAgc3BlbmRlcjogc3RyaW5nLFxuICAgIHZhbHVlOiBudW1iZXJcbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgeyBjdHgsIGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5BcHByb3ZlKTtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHggYXMgYW55KTtcblxuICAgIGNvbnN0IG93bmVyID0gY3R4LmlkZW50aXR5LmdldElEKCk7XG5cbiAgICBsZXQgYWxsb3dhbmNlID0gYXdhaXQgdGhpcy5fZ2V0QWxsb3dhbmNlKG93bmVyLCBzcGVuZGVyLCBjdHgpO1xuXG4gICAgY29uc3Qgb3duZXJXYWxsZXQgPSBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkucmVhZChvd25lciwgLi4uY3R4QXJncyk7XG5cbiAgICBpZiAob3duZXJXYWxsZXQuYmFsYW5jZSA8IHZhbHVlKSB7XG4gICAgICB0aHJvdyBuZXcgQmFsYW5jZUVycm9yKGBjbGllbnQgYWNjb3VudCAke293bmVyfSBoYXMgaW5zdWZmaWNpZW50IGZ1bmRzLmApO1xuICAgIH1cblxuICAgIGlmIChhbGxvd2FuY2UpIHtcbiAgICAgIC8vIE92ZXJ3cml0ZSB0aGUgYWxsb3dhbmNlXG4gICAgICBhbGxvd2FuY2UudmFsdWUgPSB2YWx1ZTtcbiAgICAgIGF3YWl0IHRoaXMuYWxsb3dhbmNlUmVwb3NpdG9yeS51cGRhdGUoYWxsb3dhbmNlLCAuLi5jdHhBcmdzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgYWxsb3dhbmNlID0gbmV3IEFsbG93YW5jZSh7XG4gICAgICAgIG93bmVyOiBvd25lcixcbiAgICAgICAgc3BlbmRlcjogc3BlbmRlcixcbiAgICAgICAgdmFsdWU6IHZhbHVlLFxuICAgICAgfSk7XG5cbiAgICAgIGF3YWl0IHRoaXMuYWxsb3dhbmNlUmVwb3NpdG9yeS5jcmVhdGUoYWxsb3dhbmNlLCAuLi5jdHhBcmdzKTtcbiAgICB9XG5cbiAgICAvLyBFbWl0IHRoZSBBcHByb3ZhbCBldmVudFxuICAgIGNvbnN0IGFwcHJvdmFsRXZlbnQgPSB7IG93bmVyLCBzcGVuZGVyLCB2YWx1ZTogdmFsdWUgfTtcbiAgICB0aGlzLnJlcG8ucmVmcmVzaChcbiAgICAgIEVSQzIwVG9rZW4gYXMgYW55LFxuICAgICAgRVJDMjBFdmVudHMuQVBQUk9WQUwsXG4gICAgICBcIlwiLFxuICAgICAgYXBwcm92YWxFdmVudCxcbiAgICAgIGN0eCBhcyB1bmtub3duIGFzIEZhYnJpY0NvbnRyYWN0Q29udGV4dFxuICAgICk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBhbW91bnQgb2YgdG9rZW5zIHdoaWNoIGAgYCBpcyBhbGxvd2VkIHRvIHdpdGhkcmF3IGZyb20gYG93bmVyYC5cbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjdHggdGhlIHRyYW5zYWN0aW9uIGNvbnRleHRcbiAgICogQHBhcmFtIHtTdHJpbmd9IG93bmVyIFRoZSBvd25lciBvZiB0b2tlbnNcbiAgICogQHBhcmFtIHtTdHJpbmd9IHNwZW5kZXIgVGhlIHNwZW5kZXIgd2hvIGFyZSBhYmxlIHRvIHRyYW5zZmVyIHRoZSB0b2tlbnNcbiAgICogQHJldHVybnMge251bWJlcn0gUmV0dXJuIHRoZSBhbW91bnQgb2YgcmVtYWluaW5nIHRva2VucyBhbGxvd2VkIHRvIHNwZW50XG4gICAqL1xuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIGFzeW5jIEFsbG93YW5jZShcbiAgICBjb250ZXh0OiBDb250ZXh0LFxuICAgIG93bmVyOiBzdHJpbmcsXG4gICAgc3BlbmRlcjogc3RyaW5nXG4gICk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5BbGxvd2FuY2UpO1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCBhcyBhbnkpO1xuXG4gICAgY29uc3QgYWxsb3dhbmNlID0gYXdhaXQgdGhpcy5fZ2V0QWxsb3dhbmNlKG93bmVyLCBzcGVuZGVyLCBjdHgpO1xuXG4gICAgaWYgKCFhbGxvd2FuY2UpIHtcbiAgICAgIHRocm93IG5ldyBBbGxvd2FuY2VFcnJvcihcbiAgICAgICAgYHNwZW5kZXIgJHtzcGVuZGVyfSBoYXMgbm8gYWxsb3dhbmNlIGZyb20gJHtvd25lcn1gXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gYWxsb3dhbmNlLnZhbHVlO1xuICB9XG5cbiAgYXN5bmMgX2dldEFsbG93YW5jZShcbiAgICBvd25lcjogc3RyaW5nLFxuICAgIHNwZW5kZXI6IHN0cmluZyxcbiAgICBjdHg6IEZhYnJpY0NvbnRyYWN0Q29udGV4dFxuICApOiBQcm9taXNlPEFsbG93YW5jZT4ge1xuICAgIGNvbnN0IGFsbG93YW5jZUNvbmRpdGlvbiA9IENvbmRpdGlvbi5hbmQoXG4gICAgICBDb25kaXRpb24uYXR0cmlidXRlPEFsbG93YW5jZT4oXCJvd25lclwiKS5lcShvd25lciksXG4gICAgICBDb25kaXRpb24uYXR0cmlidXRlPEFsbG93YW5jZT4oXCJzcGVuZGVyXCIpLmVxKHNwZW5kZXIpXG4gICAgKTtcblxuICAgIGNvbnN0IGFsbG93YW5jZSA9IGF3YWl0IHRoaXMuYWxsb3dhbmNlUmVwb3NpdG9yeVxuICAgICAgLnNlbGVjdCgpXG4gICAgICAud2hlcmUoYWxsb3dhbmNlQ29uZGl0aW9uKVxuICAgICAgLmV4ZWN1dGUoY3R4KTtcbiAgICByZXR1cm4gYWxsb3dhbmNlPy5bMF07XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT0gRXh0ZW5kZWQgRnVuY3Rpb25zID09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIFNldCBvcHRpb25hbCBpbmZvbWF0aW9uIGZvciBhIHRva2VuLlxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGN0eCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBUaGUgbmFtZSBvZiB0aGUgdG9rZW5cbiAgICogQHBhcmFtIHtTdHJpbmd9IHN5bWJvbCBUaGUgc3ltYm9sIG9mIHRoZSB0b2tlblxuICAgKiBAcGFyYW0ge1N0cmluZ30gZGVjaW1hbHMgVGhlIGRlY2ltYWxzIG9mIHRoZSB0b2tlblxuICAgKiBAcGFyYW0ge1N0cmluZ30gdG90YWxTdXBwbHkgVGhlIHRvdGFsU3VwcGx5IG9mIHRoZSB0b2tlblxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKClcbiAgYXN5bmMgSW5pdGlhbGl6ZShjb250ZXh0OiBDb250ZXh0LCB0b2tlbjogRVJDMjBUb2tlbikge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuSW5pdGlhbGl6ZSk7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgbm90IGFscmVhZHkgc2V0LCBjbGllbnQgaXMgbm90IGF1dGhvcml6ZWQgdG8gY2hhbmdlIHRoZW0gb25jZSBpbnRpdGlhbGl6ZWRcbiAgICBjb25zdCB0b2tlbnMgPSBhd2FpdCB0aGlzLnRva2VuUmVwb3NpdG9yeS5zZWxlY3QoKS5leGVjdXRlKGN0eCk7XG4gICAgaWYgKHRva2Vucy5sZW5ndGggPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgQXV0aG9yaXphdGlvbkVycm9yKFxuICAgICAgICBcImNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0LCBjbGllbnQgaXMgbm90IGF1dGhvcml6ZWQgdG8gY2hhbmdlIHRoZW1cIlxuICAgICAgKTtcbiAgICB9XG5cbiAgICB0b2tlbi5vd25lciA9IGN0eC5pZGVudGl0eS5nZXRJRCgpO1xuXG4gICAgYXdhaXQgdGhpcy50b2tlblJlcG9zaXRvcnkuY3JlYXRlKHRva2VuLCBjdHgpO1xuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvLyBDaGVja3MgdGhhdCBjb250cmFjdCBvcHRpb25zIGhhdmUgYmVlbiBhbHJlYWR5IGluaXRpYWxpemVkXG4gIEBUcmFuc2FjdGlvbihmYWxzZSlcbiAgYXN5bmMgQ2hlY2tJbml0aWFsaXplZChjb250ZXh0OiBDb250ZXh0KSB7XG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5DaGVja0luaXRpYWxpemVkKTtcbiAgICBjb25zdCB0b2tlbnMgPSBhd2FpdCB0aGlzLnRva2VuUmVwb3NpdG9yeS5zZWxlY3QoKS5leGVjdXRlKGN0eCk7XG4gICAgaWYgKHRva2Vucy5sZW5ndGggPT0gMCkge1xuICAgICAgdGhyb3cgbmV3IE5vdEluaXRpYWxpemVkRXJyb3IoXG4gICAgICAgIFwiY29udHJhY3Qgb3B0aW9ucyBuZWVkIHRvIGJlIHNldCBiZWZvcmUgY2FsbGluZyBhbnkgZnVuY3Rpb24sIGNhbGwgSW5pdGlhbGl6ZSgpIHRvIGluaXRpYWxpemUgY29udHJhY3RcIlxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTWludCBjcmVhdGVzIG5ldyB0b2tlbnMgYW5kIGFkZHMgdGhlbSB0byBtaW50ZXIncyBhY2NvdW50IGJhbGFuY2VcbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjb250ZXh0IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBhbW91bnQgYW1vdW50IG9mIHRva2VucyB0byBiZSBtaW50ZWRcbiAgICogQHJldHVybnMge09iamVjdH0gVGhlIGJhbGFuY2VcbiAgICovXG4gIEBPd25lcigpXG4gIEBUcmFuc2FjdGlvbigpXG4gIGFzeW5jIE1pbnQoY29udGV4dDogQ29udGV4dCwgYW1vdW50OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLk1pbnQpO1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCBhcyBhbnkpO1xuXG4gICAgLy8gR2V0IElEIG9mIHN1Ym1pdHRpbmcgY2xpZW50IGlkZW50aXR5XG4gICAgY29uc3QgbWludGVyID0gY3R4LmlkZW50aXR5LmdldElEKCk7XG5cbiAgICBpZiAoYW1vdW50IDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoXCJtaW50IGFtb3VudCBtdXN0IGJlIGEgcG9zaXRpdmUgaW50ZWdlclwiKTtcbiAgICB9XG5cbiAgICBsZXQgbWludGVyV2FsbGV0OiBFUkMyMFdhbGxldDtcbiAgICB0cnkge1xuICAgICAgbWludGVyV2FsbGV0ID0gYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnJlYWQobWludGVyLCBjdHgpO1xuXG4gICAgICBjb25zdCBjdXJyZW50QmFsYW5jZSA9IG1pbnRlcldhbGxldC5iYWxhbmNlO1xuXG4gICAgICBjb25zdCB1cGRhdGVkQmFsYW5jZSA9IGFkZChjdXJyZW50QmFsYW5jZSwgYW1vdW50KTtcblxuICAgICAgY29uc3QgdXBkYXRlZG1pbnRlciA9IE9iamVjdC5hc3NpZ24oe30sIG1pbnRlcldhbGxldCwge1xuICAgICAgICBiYWxhbmNlOiB1cGRhdGVkQmFsYW5jZSxcbiAgICAgIH0pO1xuXG4gICAgICBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkudXBkYXRlKHVwZGF0ZWRtaW50ZXIsIGN0eCk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgaWYgKGUgaW5zdGFuY2VvZiBCYXNlRXJyb3IpIHtcbiAgICAgICAgaWYgKGUuY29kZSA9PT0gNDA0KSB7XG4gICAgICAgICAgLy8gQ3JlYXRlIGEgbmV3IHdhbGxldCBmb3IgdGhlIG1pbnRlclxuICAgICAgICAgIGNvbnN0IG5ld1dhbGxldCA9IG5ldyBFUkMyMFdhbGxldCh7XG4gICAgICAgICAgICBpZDogbWludGVyLFxuICAgICAgICAgICAgYmFsYW5jZTogYW1vdW50LFxuICAgICAgICAgICAgdG9rZW46IGF3YWl0IHRoaXMuVG9rZW5OYW1lKGNvbnRleHQpLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS5jcmVhdGUobmV3V2FsbGV0LCBjdHgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGUubWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGUgYXMgc3RyaW5nKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBFbWl0IHRoZSBUcmFuc2ZlciBldmVudFxuICAgIGNvbnN0IHRyYW5zZmVyRXZlbnQgPSB7IGZyb206IFwiMHgwXCIsIHRvOiBtaW50ZXIsIHZhbHVlOiBhbW91bnQgfTtcbiAgICBjb25zdCBldmVudEhhbmRsZXIgPVxuICAgICAgdGhpcy5yZXBvLk9ic2VydmVySGFuZGxlcigpIGFzIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyO1xuICAgIGV2ZW50SGFuZGxlci51cGRhdGVPYnNlcnZlcnMoXG4gICAgICBFUkMyMFRva2VuLFxuICAgICAgRVJDMjBFdmVudHMuVFJBTlNGRVIsXG4gICAgICBcIlwiLFxuICAgICAgdHJhbnNmZXJFdmVudCxcbiAgICAgIGN0eCBhcyB1bmtub3duIGFzIEZhYnJpY0NvbnRyYWN0Q29udGV4dFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQnVybiByZWRlZW0gdG9rZW5zIGZyb20gbWludGVyJ3MgYWNjb3VudCBiYWxhbmNlXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY29udGV4dCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge251bWJlcn0gYW1vdW50IGFtb3VudCBvZiB0b2tlbnMgdG8gYmUgYnVybmVkXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBiYWxhbmNlXG4gICAqL1xuICBAT3duZXIoKVxuICBAVHJhbnNhY3Rpb24oKVxuICBhc3luYyBCdXJuKGNvbnRleHQ6IENvbnRleHQsIGFtb3VudDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLkJ1cm4pO1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCBhcyBhbnkpO1xuXG4gICAgY29uc3QgbWludGVyID0gY3R4LmlkZW50aXR5LmdldElEKCk7XG5cbiAgICBjb25zdCBtaW50ZXJXYWxsZXQgPSBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkucmVhZChtaW50ZXIsIGN0eCk7XG5cbiAgICBjb25zdCBjdXJyZW50QmFsYW5jZSA9IG1pbnRlcldhbGxldC5iYWxhbmNlO1xuXG4gICAgaWYgKGN1cnJlbnRCYWxhbmNlIDwgYW1vdW50KSB7XG4gICAgICB0aHJvdyBuZXcgQmFsYW5jZUVycm9yKGBNaW50ZXIgaGFzIGluc3VmZmljaWVudCBmdW5kcy5gKTtcbiAgICB9XG5cbiAgICBjb25zdCB1cGRhdGVkQmFsYW5jZSA9IHN1YihjdXJyZW50QmFsYW5jZSwgYW1vdW50KTtcblxuICAgIGNvbnN0IHVwZGF0ZWRtaW50ZXIgPSBPYmplY3QuYXNzaWduKHt9LCBtaW50ZXJXYWxsZXQsIHtcbiAgICAgIGJhbGFuY2U6IHVwZGF0ZWRCYWxhbmNlLFxuICAgIH0pO1xuXG4gICAgYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnVwZGF0ZSh1cGRhdGVkbWludGVyLCBjdHgpO1xuXG4gICAgbG9nLmluZm8oYCR7YW1vdW50fSB0b2tlbnMgd2VyZSBidXJuZWRgKTtcblxuICAgIC8vIEVtaXQgdGhlIFRyYW5zZmVyIGV2ZW50XG4gICAgY29uc3QgdHJhbnNmZXJFdmVudCA9IHsgZnJvbTogbWludGVyLCB0bzogXCIweDBcIiwgdmFsdWU6IGFtb3VudCB9O1xuICAgIGNvbnN0IGV2ZW50SGFuZGxlciA9XG4gICAgICB0aGlzLnJlcG8uT2JzZXJ2ZXJIYW5kbGVyKCkgYXMgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXI7XG4gICAgZXZlbnRIYW5kbGVyLnVwZGF0ZU9ic2VydmVycyhcbiAgICAgIEVSQzIwVG9rZW4sXG4gICAgICBFUkMyMEV2ZW50cy5UUkFOU0ZFUixcbiAgICAgIFwiXCIsXG4gICAgICB0cmFuc2ZlckV2ZW50LFxuICAgICAgY3R4IGFzIHVua25vd24gYXMgRmFicmljQ29udHJhY3RDb250ZXh0XG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdXJuRnJvbSByZWRlZW0gdG9rZW5zIGZyb20gYWNjb3VudCBhbGxvd2VuY2UgYW5kIGJhbGFuY2VcbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjb250ZXh0IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBhY2NvdW50IGFjY291bnQgZnJvbSB3aGVyZSB0b2tlbnMgd2lsbCBiZSBidXJuZWRcbiAgICogQHBhcmFtIHtudW1iZXJ9IGFtb3VudCBhbW91bnQgb2YgdG9rZW5zIHRvIGJlIGJ1cm5lZFxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgYmFsYW5jZVxuICAgKi9cbiAgQE93bmVyKClcbiAgQFRyYW5zYWN0aW9uKClcbiAgYXN5bmMgQnVybkZyb20oXG4gICAgY29udGV4dDogQ29udGV4dCxcbiAgICBhY2NvdW50OiBzdHJpbmcsXG4gICAgYW1vdW50OiBudW1iZXJcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLkJ1cm5Gcm9tKTtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHggYXMgYW55KTtcblxuICAgIGNvbnN0IGFjY291bnRXYWxsZXQgPSBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkucmVhZChhY2NvdW50LCBjdHgpO1xuXG4gICAgY29uc3QgY3VycmVudEJhbGFuY2UgPSBhY2NvdW50V2FsbGV0LmJhbGFuY2U7XG5cbiAgICBpZiAoY3VycmVudEJhbGFuY2UgPCBhbW91bnQpIHtcbiAgICAgIHRocm93IG5ldyBCYWxhbmNlRXJyb3IoYCR7YWNjb3VudH0gaGFzIGluc3VmZmljaWVudCBmdW5kcy5gKTtcbiAgICB9XG5cbiAgICBjb25zdCB1cGRhdGVkQmFsYW5jZSA9IHN1YihjdXJyZW50QmFsYW5jZSwgYW1vdW50KTtcblxuICAgIGNvbnN0IHVwZGF0ZWRhY2NvdW50ID0gT2JqZWN0LmFzc2lnbih7fSwgYWNjb3VudFdhbGxldCwge1xuICAgICAgYmFsYW5jZTogdXBkYXRlZEJhbGFuY2UsXG4gICAgfSk7XG5cbiAgICBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkudXBkYXRlKHVwZGF0ZWRhY2NvdW50LCBjdHgpO1xuXG4gICAgbG9nLmluZm8oYCR7YW1vdW50fSB0b2tlbnMgd2VyZSBidXJuZWQgZnJvbSAke2FjY291bnR9YCk7XG5cbiAgICAvLyBFbWl0IHRoZSBUcmFuc2ZlciBldmVudFxuICAgIGNvbnN0IHRyYW5zZmVyRXZlbnQgPSB7IGZyb206IGFjY291bnQsIHRvOiBcIjB4MFwiLCB2YWx1ZTogYW1vdW50IH07XG4gICAgY29uc3QgZXZlbnRIYW5kbGVyID1cbiAgICAgIHRoaXMucmVwby5PYnNlcnZlckhhbmRsZXIoKSBhcyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnlPYnNlcnZhYmxlSGFuZGxlcjtcbiAgICBldmVudEhhbmRsZXIudXBkYXRlT2JzZXJ2ZXJzKFxuICAgICAgRVJDMjBUb2tlbixcbiAgICAgIEVSQzIwRXZlbnRzLlRSQU5TRkVSLFxuICAgICAgXCJcIixcbiAgICAgIHRyYW5zZmVyRXZlbnQsXG4gICAgICBjdHggYXMgdW5rbm93biBhcyBGYWJyaWNDb250cmFjdENvbnRleHRcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIENsaWVudEFjY291bnRCYWxhbmNlIHJldHVybnMgdGhlIGJhbGFuY2Ugb2YgdGhlIHJlcXVlc3RpbmcgY2xpZW50J3MgYWNjb3VudC5cbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjb250ZXh0IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgdGhlIGFjY291bnQgYmFsYW5jZVxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBDbGllbnRBY2NvdW50QmFsYW5jZShjb250ZXh0OiBDb250ZXh0KTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLlRva2VuTmFtZSk7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQgZmlyc3QgdG8gZXhlY3V0ZSB0aGUgZnVuY3Rpb25cbiAgICBhd2FpdCB0aGlzLkNoZWNrSW5pdGlhbGl6ZWQoY3R4IGFzIGFueSk7XG5cbiAgICAvLyBHZXQgSUQgb2Ygc3VibWl0dGluZyBjbGllbnQgaWRlbnRpdHlcbiAgICBjb25zdCBjbGllbnRBY2NvdW50SUQgPSBjdHguaWRlbnRpdHkuZ2V0SUQoKTtcblxuICAgIGNvbnN0IGNsaWVudFdhbGxldCA9IGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS5yZWFkKGNsaWVudEFjY291bnRJRCwgY3R4KTtcblxuICAgIGlmICghY2xpZW50V2FsbGV0KSB7XG4gICAgICB0aHJvdyBuZXcgQmFsYW5jZUVycm9yKGBUaGUgYWNjb3VudCAke2NsaWVudEFjY291bnRJRH0gZG9lcyBub3QgZXhpc3RgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY2xpZW50V2FsbGV0LmJhbGFuY2U7XG4gIH1cblxuICAvLyBDbGllbnRBY2NvdW50SUQgcmV0dXJucyB0aGUgaWQgb2YgdGhlIHJlcXVlc3RpbmcgY2xpZW50J3MgYWNjb3VudC5cbiAgLy8gSW4gdGhpcyBpbXBsZW1lbnRhdGlvbiwgdGhlIGNsaWVudCBhY2NvdW50IElEIGlzIHRoZSBjbGllbnRJZCBpdHNlbGYuXG4gIC8vIFVzZXJzIGNhbiB1c2UgdGhpcyBmdW5jdGlvbiB0byBnZXQgdGhlaXIgb3duIGFjY291bnQgaWQsIHdoaWNoIHRoZXkgY2FuIHRoZW4gZ2l2ZSB0byBvdGhlcnMgYXMgdGhlIHBheW1lbnQgYWRkcmVzc1xuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIGFzeW5jIENsaWVudEFjY291bnRJRChjb250ZXh0OiBDb250ZXh0KSB7XG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5DbGllbnRBY2NvdW50SUQpO1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCBhcyBhbnkpO1xuXG4gICAgLy8gR2V0IElEIG9mIHN1Ym1pdHRpbmcgY2xpZW50IGlkZW50aXR5XG4gICAgY29uc3QgY2xpZW50QWNjb3VudElEID0gY3R4LmlkZW50aXR5LmdldElEKCk7XG4gICAgcmV0dXJuIGNsaWVudEFjY291bnRJRDtcbiAgfVxufVxuIiwiaW1wb3J0IHsgRmFicmljRVJDMjBDb250cmFjdCB9IGZyb20gXCIuL2VyYzIwY29udHJhY3RcIjtcblxuZXhwb3J0ICogZnJvbSBcIi4uL0ZhYnJpY0NvbnRyYWN0U3RhdGVtZW50XCI7XG5cbmV4cG9ydCBjb25zdCBjb250cmFjdHM6IGFueVtdID0gW0ZhYnJpY0VSQzIwQ29udHJhY3RdO1xuIiwiaW1wb3J0IHsgTWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcblxuZXhwb3J0IGNvbnN0IFZFUlNJT04gPSBcIiMjVkVSU0lPTiMjXCI7XG5leHBvcnQgY29uc3QgUEFDS0FHRV9OQU1FID0gXCIjI1BBQ0tBR0UjI1wiO1xuXG5NZXRhZGF0YS5yZWdpc3RlckxpYnJhcnkoUEFDS0FHRV9OQU1FLCBWRVJTSU9OKTtcbiJdLCJuYW1lcyI6WyJGYWJyaWNDb250cmFjdENvbnRleHQiLCJDb250ZXh0IiwiY29uc3RydWN0b3IiLCJzdXBlciIsInN0dWIiLCJ0aGlzIiwiZ2V0IiwidGltZXN0YW1wIiwiZ2V0RGF0ZVRpbWVzdGFtcCIsImlkZW50aXR5IiwidG9TdHJpbmciLCJnZW5lcmF0ZUZhYnJpY0V2ZW50TmFtZSIsInRhYmxlIiwiZXZlbnQiLCJvd25lciIsInBhcmFtcyIsInB1c2giLCJqb2luIiwicGFyc2VFdmVudE5hbWUiLCJuYW1lIiwicGFydHMiLCJzcGxpdCIsImxlbmd0aCIsInVuZGVmaW5lZCIsIkZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyIiwiT2JzZXJ2ZXJIYW5kbGVyIiwic3VwcG9ydGVkRXZlbnRzIiwiT3BlcmF0aW9uS2V5cyIsIkNSRUFURSIsIlVQREFURSIsIkRFTEVURSIsIkJ1bGtDcnVkT3BlcmF0aW9uS2V5cyIsIkNSRUFURV9BTEwiLCJVUERBVEVfQUxMIiwiREVMRVRFX0FMTCIsInVwZGF0ZU9ic2VydmVycyIsImNsYXp6IiwiaWQiLCJhcmdzIiwibG9nIiwiY3R4IiwiQWRhcHRlciIsImxvZ0N0eCIsInBheWxvYWQiLCJpbmRleE9mIiwiZGVidWciLCJldmVudE5hbWUiLCJzZXRFdmVudCIsIkJ1ZmZlciIsImZyb20iLCJKU09OIiwic3RyaW5naWZ5IiwiRmFicmljQ29udHJhY3RSZXBvc2l0b3J5IiwiUmVwb3NpdG9yeSIsImFkYXB0ZXIiLCJ0cmFja2VkRXZlbnRzIiwiRmFicmljU3RhdGVtZW50IiwiQ291Y2hEQlN0YXRlbWVudCIsInJhdyIsInJhd0lucHV0IiwicmVzdWx0cyIsInBrQXR0ciIsIk1vZGVsIiwicGsiLCJmcm9tU2VsZWN0b3IiLCJ0eXBlIiwiTWV0YWRhdGEiLCJrZXkiLCJEQktleXMiLCJJRCIsInNlbGVjdFNlbGVjdG9yIiwibWFwIiwiciIsInByb2Nlc3NSZWNvcmQiLCJidWlsZCIsInNlbGVjdG9ycyIsIkNvdWNoREJLZXlzIiwiVEFCTEUiLCJ0YWJsZU5hbWUiLCJxdWVyeSIsInNlbGVjdG9yIiwiZmllbGRzIiwid2hlcmVDb25kaXRpb24iLCJjb25kaXRpb24iLCJwYXJzZUNvbmRpdGlvbiIsIkNvbmRpdGlvbiIsImFuZCIsImF0dHJpYnV0ZSIsImVxIiwic2VsZWN0b3JLZXlzIiwiT2JqZWN0Iiwia2V5cyIsInZhbHVlcyIsIkNvdWNoREJHcm91cE9wZXJhdG9yIiwiQU5EIiwicmVkdWNlIiwiYWNjdW0iLCJ2YWwiLCJFcnJvciIsImsiLCJPUiIsInMiLCJlbnRyaWVzIiwicmVzdWx0IiwiZm9yRWFjaCIsImNvbnNvbGUiLCJ3YXJuIiwib3JkZXJCeVNlbGVjdG9yIiwic29ydCIsInZhbHVlIiwicmVjIiwiQ291Y2hEQk9wZXJhdG9yIiwiQklHR0VSIiwibGltaXRTZWxlY3RvciIsImxpbWl0Iiwib2Zmc2V0U2VsZWN0b3IiLCJza2lwIiwiRmFicmljTW9kZWxLZXlzIiwiSWRlbnRpdHlUeXBlIiwiRmFicmljRmxhdm91ciIsIlNpbXBsZURldGVybWluaXN0aWNTZXJpYWxpemVyIiwiSlNPTlNlcmlhbGl6ZXIiLCJkZXNlcmlhbGl6ZSIsInN0ciIsImRlc2VyaWFsaXphdGlvbiIsInBhcnNlIiwic2VyaWFsaXplIiwibW9kZWwiLCJyZXF1aXJlIiwic29ydEtleXNSZWN1cnNpdmUiLCJwcmVTZXJpYWxpemUiLCJ0b1NlcmlhbGl6ZSIsImFzc2lnbiIsImFzeW5jIiwib25lVG9PbmVPbkNyZWF0ZSIsImNvbnRleHQiLCJkYXRhIiwicHJvcGVydHlWYWx1ZSIsImlubmVyUmVwbyIsInJlcG9zaXRvcnlGcm9tVHlwZU1ldGFkYXRhIiwiYWxpYXMiLCJyZWFkIiwiY2FjaGVNb2RlbEZvclBvcHVsYXRlIiwiY2xhc3MiLCJJbnRlcm5hbEVycm9yIiwicmVwbyIsImZvck1vZGVsIiwiY3JlYXRlZCIsImNyZWF0ZSIsIm9uZVRvT25lT25VcGRhdGUiLCJjYXNjYWRlIiwidXBkYXRlIiwiQ2FzY2FkZSIsIkNBU0NBREUiLCJ1cGRhdGVkIiwiY3JlYXRlT3JVcGRhdGUiLCJvbmVUb09uZU9uRGVsZXRlIiwiZGVsZXRlZCIsImRlbGV0ZSIsIm9uZVRvTWFueU9uQ3JlYXRlIiwicHJvcGVydHlWYWx1ZXMiLCJhcnJheVR5cGUiLCJldmVyeSIsIml0ZW0iLCJ1bmlxdWVWYWx1ZXMiLCJTZXQiLCJwa05hbWUiLCJtIiwicmVjb3JkIiwiYWRkIiwib25lVG9NYW55T25EZWxldGUiLCJhcmVBbGxTYW1lVHlwZSIsImlzSW5zdGFudGlhdGVkIiwidiIsInBvcHVsYXRlIiwibmVzdGVkIiwiaXNBcnIiLCJBcnJheSIsImlzQXJyYXkiLCJmZXRjaFBvcHVsYXRlVmFsdWVzIiwiYyIsInByb3BOYW1lIiwicHJvcEtleVZhbHVlcyIsImNhY2hlS2V5IiwicHJvS2V5VmFsdWUiLCJnZXRQb3B1bGF0ZUtleSIsImUiLCJyZXMiLCJDb250cmFjdExvZ2dlciIsIk1pbmlMb2dnZXIiLCJjb25mIiwibG9nZ2VyIiwibG9nZ2luZyIsImdldExvZ2dlciIsImxldmVsIiwibXNnIiwic3RhY2siLCJOdW1lcmljTG9nTGV2ZWxzIiwiY29uZmlnIiwibWV0aG9kIiwiTG9nTGV2ZWwiLCJpbmZvIiwidmVyYm9zZSIsImVycm9yIiwic2lsbHkiLCJjYWxsIiwiY3JlYXRlTG9nIiwiZmFjdG9yeSIsIm9iamVjdCIsIkxvZ2dpbmciLCJzZXRGYWN0b3J5IiwiY3JlYXRlZEJ5T25GYWJyaWNDcmVhdGVVcGRhdGUiLCJ1c2VyIiwiZ2V0SUQiLCJVbnN1cHBvcnRlZEVycm9yIiwicGtGYWJyaWNPbkNyZWF0ZSIsInNldFByaW1hcnlLZXlWYWx1ZSIsInRhcmdldCIsInByb3BlcnR5S2V5IiwiZGVmaW5lUHJvcGVydHkiLCJlbnVtZXJhYmxlIiwid3JpdGFibGUiLCJjb25maWd1cmFibGUiLCJzZXF1ZW5jZU5hbWUiLCJzZXF1ZW5jZSIsIlNlcXVlbmNlIiwibmV4dCIsIkZhYnJpY0NvbnRyYWN0QWRhcHRlciIsIkNvdWNoREJBZGFwdGVyIiwiZ2V0Q2xpZW50IiwidGV4dERlY29kZXIiLCJUZXh0RGVjb2RlciIsInNlcmlhbGl6ZXIiLCJyZXBvc2l0b3J5Iiwic2NvcGUiLCJmb3IiLCJjb21wb3NlZEtleSIsImNyZWF0ZUNvbXBvc2l0ZUtleSIsIlN0cmluZyIsInB1dFN0YXRlIiwicGFyc2VFcnJvciIsInJlYWRTdGF0ZSIsImN0eEFyZ3MiLCJkZWxldGVTdGF0ZSIsImZvclByaXZhdGUiLCJjb2xsZWN0aW9uIiwidG9PdmVycmlkZSIsInF1ZXJ5UmVzdWx0IiwicXVlcnlSZXN1bHRQYWdpbmF0ZWQiLCJmbiIsIlByb3h5IiwicHJvcCIsInJlY2VpdmVyIiwiaW5jbHVkZXMiLCJSZWZsZWN0IiwiYXBwbHkiLCJ0aGlzQXJnIiwiYXJnc0xpc3QiLCJwdXRQcml2YXRlRGF0YSIsImRlbGV0ZVByaXZhdGVEYXRhIiwiZ2V0UHJpdmF0ZURhdGEiLCJnZXRQcml2YXRlRGF0YVF1ZXJ5UmVzdWx0IiwiaXRlcmF0b3IiLCJjb3VudCIsInJlYWNoZWRCb29rbWFyayIsImxhc3RLZXkiLCJyZWNvcmRLZXkiLCJyZWNvcmRWYWx1ZSIsIktleSIsIlJlY29yZCIsImNsb3NlIiwibWV0YWRhdGEiLCJmZXRjaGVkUmVjb3Jkc0NvdW50IiwiYm9va21hcmsiLCJkb25lIiwiU2VyaWFsaXphdGlvbkVycm9yIiwiZ2V0U3RhdGUiLCJOb3RGb3VuZEVycm9yIiwiZ2V0UXVlcnlSZXN1bHQiLCJfaWQiLCIkZ3QiLCIkZ3RlIiwiaXQiLCJnZXRRdWVyeVJlc3VsdFdpdGhQYWdpbmF0aW9uIiwibWVyZ2VNb2RlbHMiLCJleHRyYWN0IiwiZmluYWxNb2RlbCIsInBvcCIsImRlY29kZSIsImJ1ZmZlciIsImZsYWdzIiwib3BlcmF0aW9uIiwiYmFzZUZsYWdzIiwic2VncmVnYXRlZCIsImNvcnJlbGF0aW9uSWQiLCJnZXRUeElEIiwiY2xpZW50SWRlbnRpdHkiLCJpbmRleCIsIm1vZGVscyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVzdWx0SXRlcmF0b3IiLCJpc0hpc3RvcnkiLCJhbGxSZXN1bHRzIiwianNvblJlcyIsIlR4SWQiLCJ0eElkIiwiVGltZXN0YW1wIiwiVmFsdWUiLCJlcnIiLCJkb2NzT25seSIsInJlc3BvbnNlIiwiU3RhdGVtZW50IiwiY3JlYXRlQWxsIiwidGFibGVMYWJlbCIsImFsbCIsImkiLCJ1cGRhdGVBbGwiLCJwcmVwYXJlIiwic2VncmVnYXRlIiwibWFwcGVkUHJvcCIsImNvbHVtbk5hbWUiLCJpc1Jlc2VydmVkIiwidHJhbnNpZW50IiwicmV2ZXJ0Iiwib2JqIiwib2IiLCJjcmVhdGVQcmVmaXgiLCJ1cGRhdGVQcmVmaXgiLCJjcmVhdGVBbGxQcmVmaXgiLCJpZHMiLCJyZWNvcmRzIiwidXBkYXRlQWxsUHJlZml4IiwicmVhc29uIiwiZmlsdGVyIiwiYSIsImNsZWFyIiwibWVzc2FnZSIsIkNvbmZsaWN0RXJyb3IiLCJCYWRSZXF1ZXN0RXJyb3IiLCJRdWVyeUVycm9yIiwiUGFnaW5nRXJyb3IiLCJNaWdyYXRpb25FcnJvciIsIk9ic2VydmVyRXJyb3IiLCJBdXRob3JpemF0aW9uRXJyb3IiLCJGb3JiaWRkZW5FcnJvciIsIkNvbm5lY3Rpb25FcnJvciIsImRlY29yYXRpb24iLCJEZWNvcmF0aW9uIiwiZmxhdm91cmVkQXMiLCJQZXJzaXN0ZW5jZUtleXMiLCJDUkVBVEVEX0JZIiwiZGVmaW5lIiwib25DcmVhdGUiLCJwcm9wTWV0YWRhdGEiLCJVUERBVEVEX0JZIiwib25DcmVhdGVVcGRhdGUiLCJkZWNvcmF0b3IiLCJwa0RlYyIsIm9wdGlvbnMiLCJncm91cHNvcnQiLCJhdHRyIiwicmVxdWlyZWQiLCJyZWFkb25seSIsIkNPTFVNTiIsImV4dGVuZCIsIkZhYnJpY1Byb3BlcnR5IiwiUHJvcGVydHkiLCJGYWJyaWNPYmplY3QiLCJvbmVUb09uZURlYyIsImpvaW5Db2x1bW5PcHRzIiwiZmsiLCJtZXRhIiwiam9pblRhYmxlIiwicmVsYXRpb24iLCJPTkVfVE9fT05FIiwiTnVtYmVyIiwiQmlnSW50Iiwib25VcGRhdGUiLCJvbkRlbGV0ZSIsImFmdGVyQW55Iiwib25lVG9NYW55RGVjIiwiam9pblRhYmxlT3B0cyIsIk9ORV9UT19NQU5ZIiwibGlzdCIsIm9uZVRvTWFueU9uVXBkYXRlIiwic2V0Q3VycmVudCIsIkRldGVybWluaXN0aWNTZXJpYWxpemVyIiwiRmFicmljQ3J1ZENvbnRyYWN0IiwiQ29udHJhY3QiLCJpbml0aWFsaXplZCIsImxpc3RCeSIsIm9yZGVyIiwicGFnaW5hdGVCeSIsInNpemUiLCJmaW5kT25lQnkiLCJzdGF0ZW1lbnQiLCJnZXRUcmFuc2llbnREYXRhIiwibWVyZ2UiLCJ0cmFuc2llbnRNYXAiLCJnZXRUcmFuc2llbnQiLCJoYXMiLCJkZWxldGVBbGwiLCJyZWFkQWxsIiwib3JkZXJCeSIsIk9yZGVyRGlyZWN0aW9uIiwiQVNDIiwiaW5pdCIsImdldE5hbWUiLCJoZWFsdGhjaGVjayIsImJpbmQiLCJDdHgiLCJnZXRPcCIsIlJFQUQiLCJSRUFEX0FMTCIsIm92ZXJyaWRlcyIsIlNlcmlhbGl6ZWRDcnVkQ29udHJhY3QiLCJwYXJzZWRLZXlzIiwibW9kZWxMaXN0IiwiY29uZCIsInBhcnNlZElucHV0IiwiX19kZWNvcmF0ZSIsIlRyYW5zYWN0aW9uIiwicHJvdG90eXBlIiwiT3ZlcmZsb3dFcnJvciIsIkJhbGFuY2VFcnJvciIsIkFsbG93YW5jZUVycm9yIiwiUmVnaXN0cmF0aW9uRXJyb3IiLCJNaXNzaW5nQ29udGV4dEVycm9yIiwiVW5hdXRob3JpemVkUHJpdmF0ZURhdGFBY2Nlc3MiLCJCYXNlRXJyb3IiLCJOb3RJbml0aWFsaXplZEVycm9yIiwiTWlzc2luZ1BLQ1NTMTFMaWIiLCJFbmRvcnNlbWVudEVycm9yIiwiYiIsInN1YiIsInNhZmVQYXJzZUludCIsInN0cmluZyIsImRpZ2l0UmVnZXgiLCJ0ZXN0IiwiVmFsaWRhdGlvbkVycm9yIiwic3RyaW5nRm9ybWF0IiwicGFyc2VkaW50IiwicGFyc2VJbnQiLCJpc05hTiIsIkVSQzIwVG9rZW4iLCJCYXNlTW9kZWwiLCJjb2x1bW4iLCJFUkMyMFdhbGxldCIsIkFsbG93YW5jZSIsIk93bmVyIiwiZGVzY3JpcHRvciIsIm9yaWdpbmFsTWV0aG9kIiwiYWNvdW50SWQiLCJzZWxlY3QiLCJ0b2tlbnMiLCJleGVjdXRlIiwib3duZWRCeU9uQ3JlYXRlIiwiY3JlYXRvciIsImdldENyZWF0b3IiLCJtc3BpZCIsInNldE93bmVkQnlLZXlWYWx1ZSIsIk93bmVkQnkiLCJnZXRGYWJyaWNNb2RlbEtleSIsIk9XTkVEQlkiLCJvd25lZEJ5IiwiRkFCUklDIiwiSW1wbGljaXRQcml2YXRlQ29sbGVjdGlvbiIsInNlZ3JlZ2F0ZWREYXRhT25DcmVhdGUiLCJjb2xsZWN0aW9uUmVzb2x2ZXIiLCJjb2xsZWN0aW9ucyIsInJlYnVpbHQiLCJhY2MiLCJ0b0NyZWF0ZSIsIm92ZXJyaWRlIiwic2VncmVnYXRlZERhdGFPblJlYWQiLCJzZWdyZWdhdGVkRGF0YU9uVXBkYXRlIiwib2xkTW9kZWwiLCJzZWdyZWdhdGVkRGF0YU9uRGVsZXRlIiwiaW5uZXJTZWdyZWdhdGVkIiwic2VncmVnYXRlZERlYyIsInByb3BzIiwicHJvcGVydGllcyIsImNvbnN0ciIsInNldCIsImRlY3MiLCJwIiwicHJpb3JpdHkiLCJncm91cCIsIm9uUmVhZCIsInByaXZhdGVEYXRhIiwiUFJJVkFURSIsInNoYXJlZERhdGEiLCJTSEFSRUQiLCJFUkMyMEV2ZW50cyIsIkZhYnJpY0VSQzIwQ29udHJhY3QiLCJ3YWxsZXRSZXBvc2l0b3J5IiwidG9rZW5SZXBvc2l0b3J5IiwiYWxsb3dhbmNlUmVwb3NpdG9yeSIsIlRva2VuTmFtZSIsIkNoZWNrSW5pdGlhbGl6ZWQiLCJ0b2tlbiIsIlN5bWJvbCIsInN5bWJvbCIsIkRlY2ltYWxzIiwiZGVjaW1hbHMiLCJUb3RhbFN1cHBseSIsIndhbGxldHMiLCJ0b3RhbCIsIndhbGxldCIsImJhbGFuY2UiLCJCYWxhbmNlT2YiLCJUcmFuc2ZlciIsInRvIiwidHJhbnNmZXJSZXNwIiwiX3RyYW5zZmVyIiwiVHJhbnNmZXJGcm9tIiwiQnVybkZyb20iLCJzcGVuZGVyIiwiYWxsb3dhbmNlIiwiX2dldEFsbG93YW5jZSIsImN1cnJlbnRBbGxvd2FuY2UiLCJ1cGRhdGVkQWxsb3dhbmNlIiwibmV3QWxsb3dhbmNlIiwiZnJvbVdhbGxldCIsImZyb21CYWxhbmNlIiwidG9XYWxsZXQiLCJuZXdUb1dhbGxldCIsImNvZGUiLCJ0b0JhbGFuY2UiLCJmcm9tVXBkYXRlZEJhbGFuY2UiLCJ0b1VwZGF0ZWRCYWxhbmNlIiwidXBkYXRlZEZyb21XYWxsZXQiLCJ1cGRhdGVkVG9XYWxsZXQiLCJ0cmFuc2ZlckV2ZW50IiwicmVmcmVzaCIsIlRSQU5TRkVSIiwiY2F0Y2giLCJBcHByb3ZlIiwib3duZXJXYWxsZXQiLCJhcHByb3ZhbEV2ZW50IiwiQVBQUk9WQUwiLCJhbGxvd2FuY2VDb25kaXRpb24iLCJ3aGVyZSIsIkluaXRpYWxpemUiLCJNaW50IiwiYW1vdW50IiwibWludGVyIiwibWludGVyV2FsbGV0IiwiY3VycmVudEJhbGFuY2UiLCJ1cGRhdGVkQmFsYW5jZSIsInVwZGF0ZWRtaW50ZXIiLCJuZXdXYWxsZXQiLCJldmVudEhhbmRsZXIiLCJCdXJuIiwiYWNjb3VudCIsImFjY291bnRXYWxsZXQiLCJ1cGRhdGVkYWNjb3VudCIsIkNsaWVudEFjY291bnRCYWxhbmNlIiwiY2xpZW50QWNjb3VudElEIiwiY2xpZW50V2FsbGV0IiwiQ2xpZW50QWNjb3VudElEIiwiX19tZXRhZGF0YSIsImNvbnRyYWN0cyIsIlZFUlNJT04iLCJQQUNLQUdFX05BTUUiLCJyZWdpc3RlckxpYnJhcnkiXSwibWFwcGluZ3MiOiI7Ozs7O0lBa0NNLE1BQU9BLDhCQUE4QkMsS0FBQUE7UUFLekMsV0FBQUM7WUFDRUM7QUFDRDtRQU9ELFFBQUlDO1lBQ0YsT0FBT0MsS0FBS0MsSUFBSTtBQUNqQjtRQU9ELGFBQWFDO1lBQ1gsT0FBT0YsS0FBS0QsS0FBS0k7QUFDbEI7UUFPRCxZQUFJQztZQUNGLE9BQU9KLEtBQUtDLElBQUk7QUFDakI7UUFFUSxRQUFBSTtZQUNQLE9BQU8sYUFBYUwsS0FBS0QsT0FBTyxlQUFlO0FBQ2hEOzthQzVEYU8sd0JBQ2RDLE9BQ0FDLE9BQ0FDO1FBRUEsTUFBTUMsU0FBUyxFQUFDSCxPQUFPQztRQUN2QixJQUFJQyxPQUFPQyxPQUFPQyxLQUFLRjtRQUN2QixPQUFPQyxPQUFPRSxLQUFLO0FBQ3JCO0lB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