@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.
- package/dist/for-fabric.cjs +1726 -2
- package/dist/for-fabric.js +1831 -2
- package/lib/bin/build-contract.cjs +2 -1
- package/lib/bin/build-contracts.cjs +2 -1
- package/lib/bin/build-contracts2.cjs +2 -1
- package/lib/bin/compile-indexes.cjs +2 -1
- package/lib/cli-module.cjs +1 -1
- package/lib/client/FabricClientAdapter.cjs +8 -1
- package/lib/client/FabricClientDispatch.cjs +1 -1
- package/lib/client/FabricClientPaginator.cjs +1 -1
- package/lib/client/FabricClientRepository.cjs +2 -2
- package/lib/client/FabricClientStatement.cjs +1 -1
- package/lib/client/erc20/FabricERC20ClientRepository.cjs +1 -1
- package/lib/client/erc20/index.cjs +1 -1
- package/lib/client/fabric-fs.cjs +1 -1
- package/lib/client/fabric-fs.d.ts +1 -1
- package/lib/client/fabric-hsm.cjs +1 -1
- package/lib/client/index.cjs +1 -1
- package/lib/client/indexes/generation.cjs +1 -1
- package/lib/client/indexes/index.cjs +1 -1
- package/lib/client/logging.cjs +1 -1
- package/lib/client/services/FabricEnrollmentService.cjs +1 -1
- package/lib/client/services/constants.cjs +1 -1
- package/lib/client/services/index.cjs +1 -1
- package/lib/contract/Product.cjs +1 -1
- package/lib/contract/ProductContract.cjs +1 -1
- package/lib/contract/User.cjs +1 -1
- package/lib/contract/UserContract.cjs +1 -1
- package/lib/contract/index.cjs +1 -1
- package/lib/contracts/ContractAdapter.cjs +1 -1
- package/lib/contracts/ContractContext.cjs +1 -1
- package/lib/contracts/ContractPrivateDataAdapter.cjs +1 -1
- package/lib/contracts/FabricConstruction.cjs +1 -1
- package/lib/contracts/FabricContractRepository.cjs +1 -1
- package/lib/contracts/FabricContractRepositoryObservableHandler.cjs +1 -1
- package/lib/contracts/FabricContractStatement.cjs +1 -1
- package/lib/contracts/PrivateSequence.cjs +1 -1
- package/lib/contracts/crud/crud-contract.cjs +1 -1
- package/lib/contracts/crud/index.cjs +1 -1
- package/lib/contracts/crud/serialized-crud-contract.cjs +1 -1
- package/lib/contracts/erc20/erc20contract.cjs +1 -1
- package/lib/contracts/erc20/index.cjs +1 -1
- package/lib/contracts/erc20/models.cjs +1 -1
- package/lib/contracts/index.cjs +1 -1
- package/lib/contracts/logging.cjs +1 -1
- package/lib/contracts/private-data.cjs +1 -1
- package/lib/contracts/types.cjs +1 -1
- package/lib/esm/bin/build-contract.js +1 -1
- package/lib/esm/bin/build-contracts.js +1 -1
- package/lib/esm/bin/build-contracts2.js +1 -1
- package/lib/esm/bin/compile-indexes.js +1 -1
- package/lib/esm/cli-module.js +1 -1
- package/lib/esm/client/FabricClientAdapter.js +8 -1
- package/lib/esm/client/FabricClientDispatch.js +1 -1
- package/lib/esm/client/FabricClientPaginator.js +1 -1
- package/lib/esm/client/FabricClientRepository.js +2 -2
- package/lib/esm/client/FabricClientStatement.js +1 -1
- package/lib/esm/client/erc20/FabricERC20ClientRepository.js +1 -1
- package/lib/esm/client/erc20/index.js +1 -1
- package/lib/esm/client/fabric-fs.d.ts +1 -1
- package/lib/esm/client/fabric-fs.js +1 -1
- package/lib/esm/client/fabric-hsm.js +1 -1
- package/lib/esm/client/index.js +1 -1
- package/lib/esm/client/indexes/generation.js +1 -1
- package/lib/esm/client/indexes/index.js +1 -1
- package/lib/esm/client/logging.js +1 -1
- package/lib/esm/client/services/FabricEnrollmentService.js +1 -1
- package/lib/esm/client/services/constants.js +1 -1
- package/lib/esm/client/services/index.js +1 -1
- package/lib/esm/contract/Product.js +1 -1
- package/lib/esm/contract/ProductContract.js +1 -1
- package/lib/esm/contract/User.js +1 -1
- package/lib/esm/contract/UserContract.js +1 -1
- package/lib/esm/contract/index.js +1 -1
- package/lib/esm/contracts/ContractAdapter.js +1 -1
- package/lib/esm/contracts/ContractContext.js +1 -1
- package/lib/esm/contracts/ContractPrivateDataAdapter.js +1 -1
- package/lib/esm/contracts/FabricConstruction.js +1 -1
- package/lib/esm/contracts/FabricContractRepository.js +1 -1
- package/lib/esm/contracts/FabricContractRepositoryObservableHandler.js +1 -1
- package/lib/esm/contracts/FabricContractStatement.js +1 -1
- package/lib/esm/contracts/PrivateSequence.js +1 -1
- package/lib/esm/contracts/crud/crud-contract.js +1 -1
- package/lib/esm/contracts/crud/index.js +1 -1
- package/lib/esm/contracts/crud/serialized-crud-contract.js +1 -1
- package/lib/esm/contracts/erc20/erc20contract.js +1 -1
- package/lib/esm/contracts/erc20/index.js +1 -1
- package/lib/esm/contracts/erc20/models.js +1 -1
- package/lib/esm/contracts/index.js +1 -1
- package/lib/esm/contracts/logging.js +1 -1
- package/lib/esm/contracts/private-data.js +1 -1
- package/lib/esm/contracts/types.js +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/shared/ClientSerializer.js +1 -1
- package/lib/esm/shared/DeterministicSerializer.js +1 -1
- package/lib/esm/shared/SimpleDeterministicSerializer.js +1 -1
- package/lib/esm/shared/constants.js +1 -1
- package/lib/esm/shared/crypto.js +1 -1
- package/lib/esm/shared/decorators.js +1 -1
- package/lib/esm/shared/erc20/erc20-constants.js +1 -1
- package/lib/esm/shared/errors.d.ts +3 -0
- package/lib/esm/shared/errors.js +6 -1
- package/lib/esm/shared/events.js +1 -1
- package/lib/esm/shared/fabric-types.js +1 -1
- package/lib/esm/shared/index.js +1 -1
- package/lib/esm/shared/interfaces/Checkable.js +1 -1
- package/lib/esm/shared/math.js +1 -1
- package/lib/esm/shared/model/FabricBaseModel.js +1 -1
- package/lib/esm/shared/model/FabricIdentifiedBaseModel.js +1 -1
- package/lib/esm/shared/model/Identity.js +1 -1
- package/lib/esm/shared/model/IdentityCredentials.js +1 -1
- package/lib/esm/shared/model/index.js +1 -1
- package/lib/esm/shared/overrides/Model.js +1 -1
- package/lib/esm/shared/overrides/index.js +1 -1
- package/lib/esm/shared/overrides/overrides.js +1 -1
- package/lib/esm/shared/types.js +1 -1
- package/lib/esm/shared/utils.d.ts +1 -1
- package/lib/esm/shared/utils.js +1 -1
- package/lib/esm/version.d.ts +1 -1
- package/lib/esm/version.js +2 -2
- package/lib/index.cjs +1 -1
- package/lib/shared/ClientSerializer.cjs +1 -1
- package/lib/shared/DeterministicSerializer.cjs +1 -1
- package/lib/shared/SimpleDeterministicSerializer.cjs +1 -1
- package/lib/shared/constants.cjs +1 -1
- package/lib/shared/crypto.cjs +1 -1
- package/lib/shared/decorators.cjs +1 -1
- package/lib/shared/erc20/erc20-constants.cjs +1 -1
- package/lib/shared/errors.cjs +8 -2
- package/lib/shared/errors.d.ts +3 -0
- package/lib/shared/events.cjs +1 -1
- package/lib/shared/fabric-types.cjs +1 -1
- package/lib/shared/index.cjs +1 -1
- package/lib/shared/interfaces/Checkable.cjs +1 -1
- package/lib/shared/math.cjs +1 -1
- package/lib/shared/model/FabricBaseModel.cjs +1 -1
- package/lib/shared/model/FabricIdentifiedBaseModel.cjs +1 -1
- package/lib/shared/model/Identity.cjs +1 -1
- package/lib/shared/model/IdentityCredentials.cjs +1 -1
- package/lib/shared/model/index.cjs +1 -1
- package/lib/shared/overrides/Model.cjs +1 -1
- package/lib/shared/overrides/index.cjs +1 -1
- package/lib/shared/overrides/overrides.cjs +1 -1
- package/lib/shared/types.cjs +1 -1
- package/lib/shared/utils.cjs +1 -1
- package/lib/shared/utils.d.ts +1 -1
- package/lib/version.cjs +2 -2
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/for-fabric.cjs.map +0 -1
- package/dist/for-fabric.js.map +0 -1
- package/lib/bin/build-contract.js.map +0 -1
- package/lib/bin/build-contracts.js.map +0 -1
- package/lib/bin/build-contracts2.js.map +0 -1
- package/lib/bin/compile-indexes.js.map +0 -1
- package/lib/cli-module.js.map +0 -1
- package/lib/client/FabricClientAdapter.js.map +0 -1
- package/lib/client/FabricClientDispatch.js.map +0 -1
- package/lib/client/FabricClientPaginator.js.map +0 -1
- package/lib/client/FabricClientRepository.js.map +0 -1
- package/lib/client/FabricClientStatement.js.map +0 -1
- package/lib/client/erc20/FabricERC20ClientRepository.js.map +0 -1
- package/lib/client/erc20/index.js.map +0 -1
- package/lib/client/fabric-fs.js.map +0 -1
- package/lib/client/fabric-hsm.js.map +0 -1
- package/lib/client/index.js.map +0 -1
- package/lib/client/indexes/generation.js.map +0 -1
- package/lib/client/indexes/index.js.map +0 -1
- package/lib/client/logging.js.map +0 -1
- package/lib/client/services/FabricEnrollmentService.js.map +0 -1
- package/lib/client/services/constants.js.map +0 -1
- package/lib/client/services/index.js.map +0 -1
- package/lib/contract/Product.js.map +0 -1
- package/lib/contract/ProductContract.js.map +0 -1
- package/lib/contract/User.js.map +0 -1
- package/lib/contract/UserContract.js.map +0 -1
- package/lib/contract/index.js.map +0 -1
- package/lib/contracts/ContractAdapter.js.map +0 -1
- package/lib/contracts/ContractContext.js.map +0 -1
- package/lib/contracts/ContractPrivateDataAdapter.js.map +0 -1
- package/lib/contracts/FabricConstruction.js.map +0 -1
- package/lib/contracts/FabricContractRepository.js.map +0 -1
- package/lib/contracts/FabricContractRepositoryObservableHandler.js.map +0 -1
- package/lib/contracts/FabricContractStatement.js.map +0 -1
- package/lib/contracts/PrivateSequence.js.map +0 -1
- package/lib/contracts/crud/crud-contract.js.map +0 -1
- package/lib/contracts/crud/index.js.map +0 -1
- package/lib/contracts/crud/serialized-crud-contract.js.map +0 -1
- package/lib/contracts/erc20/erc20contract.js.map +0 -1
- package/lib/contracts/erc20/index.js.map +0 -1
- package/lib/contracts/erc20/models.js.map +0 -1
- package/lib/contracts/index.js.map +0 -1
- package/lib/contracts/logging.js.map +0 -1
- package/lib/contracts/private-data.js.map +0 -1
- package/lib/contracts/types.js.map +0 -1
- package/lib/esm/bin/build-contract.js.map +0 -1
- package/lib/esm/bin/build-contracts.js.map +0 -1
- package/lib/esm/bin/build-contracts2.js.map +0 -1
- package/lib/esm/bin/compile-indexes.js.map +0 -1
- package/lib/esm/cli-module.js.map +0 -1
- package/lib/esm/client/FabricClientAdapter.js.map +0 -1
- package/lib/esm/client/FabricClientDispatch.js.map +0 -1
- package/lib/esm/client/FabricClientPaginator.js.map +0 -1
- package/lib/esm/client/FabricClientRepository.js.map +0 -1
- package/lib/esm/client/FabricClientStatement.js.map +0 -1
- package/lib/esm/client/erc20/FabricERC20ClientRepository.js.map +0 -1
- package/lib/esm/client/erc20/index.js.map +0 -1
- package/lib/esm/client/fabric-fs.js.map +0 -1
- package/lib/esm/client/fabric-hsm.js.map +0 -1
- package/lib/esm/client/index.js.map +0 -1
- package/lib/esm/client/indexes/generation.js.map +0 -1
- package/lib/esm/client/indexes/index.js.map +0 -1
- package/lib/esm/client/logging.js.map +0 -1
- package/lib/esm/client/services/FabricEnrollmentService.js.map +0 -1
- package/lib/esm/client/services/constants.js.map +0 -1
- package/lib/esm/client/services/index.js.map +0 -1
- package/lib/esm/contract/Product.js.map +0 -1
- package/lib/esm/contract/ProductContract.js.map +0 -1
- package/lib/esm/contract/User.js.map +0 -1
- package/lib/esm/contract/UserContract.js.map +0 -1
- package/lib/esm/contract/index.js.map +0 -1
- package/lib/esm/contracts/ContractAdapter.js.map +0 -1
- package/lib/esm/contracts/ContractContext.js.map +0 -1
- package/lib/esm/contracts/ContractPrivateDataAdapter.js.map +0 -1
- package/lib/esm/contracts/FabricConstruction.js.map +0 -1
- package/lib/esm/contracts/FabricContractRepository.js.map +0 -1
- package/lib/esm/contracts/FabricContractRepositoryObservableHandler.js.map +0 -1
- package/lib/esm/contracts/FabricContractStatement.js.map +0 -1
- package/lib/esm/contracts/PrivateSequence.js.map +0 -1
- package/lib/esm/contracts/crud/crud-contract.js.map +0 -1
- package/lib/esm/contracts/crud/index.js.map +0 -1
- package/lib/esm/contracts/crud/serialized-crud-contract.js.map +0 -1
- package/lib/esm/contracts/erc20/erc20contract.js.map +0 -1
- package/lib/esm/contracts/erc20/index.js.map +0 -1
- package/lib/esm/contracts/erc20/models.js.map +0 -1
- package/lib/esm/contracts/index.js.map +0 -1
- package/lib/esm/contracts/logging.js.map +0 -1
- package/lib/esm/contracts/private-data.js.map +0 -1
- package/lib/esm/contracts/types.js.map +0 -1
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/shared/ClientSerializer.js.map +0 -1
- package/lib/esm/shared/DeterministicSerializer.js.map +0 -1
- package/lib/esm/shared/SimpleDeterministicSerializer.js.map +0 -1
- package/lib/esm/shared/constants.js.map +0 -1
- package/lib/esm/shared/crypto.js.map +0 -1
- package/lib/esm/shared/decorators.js.map +0 -1
- package/lib/esm/shared/erc20/erc20-constants.js.map +0 -1
- package/lib/esm/shared/errors.js.map +0 -1
- package/lib/esm/shared/events.js.map +0 -1
- package/lib/esm/shared/fabric-types.js.map +0 -1
- package/lib/esm/shared/index.js.map +0 -1
- package/lib/esm/shared/interfaces/Checkable.js.map +0 -1
- package/lib/esm/shared/math.js.map +0 -1
- package/lib/esm/shared/model/FabricBaseModel.js.map +0 -1
- package/lib/esm/shared/model/FabricIdentifiedBaseModel.js.map +0 -1
- package/lib/esm/shared/model/Identity.js.map +0 -1
- package/lib/esm/shared/model/IdentityCredentials.js.map +0 -1
- package/lib/esm/shared/model/index.js.map +0 -1
- package/lib/esm/shared/overrides/Model.js.map +0 -1
- package/lib/esm/shared/overrides/index.js.map +0 -1
- package/lib/esm/shared/overrides/overrides.js.map +0 -1
- package/lib/esm/shared/types.js.map +0 -1
- package/lib/esm/shared/utils.js.map +0 -1
- package/lib/esm/version.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/shared/ClientSerializer.js.map +0 -1
- package/lib/shared/DeterministicSerializer.js.map +0 -1
- package/lib/shared/SimpleDeterministicSerializer.js.map +0 -1
- package/lib/shared/constants.js.map +0 -1
- package/lib/shared/crypto.js.map +0 -1
- package/lib/shared/decorators.js.map +0 -1
- package/lib/shared/erc20/erc20-constants.js.map +0 -1
- package/lib/shared/errors.js.map +0 -1
- package/lib/shared/events.js.map +0 -1
- package/lib/shared/fabric-types.js.map +0 -1
- package/lib/shared/index.js.map +0 -1
- package/lib/shared/interfaces/Checkable.js.map +0 -1
- package/lib/shared/math.js.map +0 -1
- package/lib/shared/model/FabricBaseModel.js.map +0 -1
- package/lib/shared/model/FabricIdentifiedBaseModel.js.map +0 -1
- package/lib/shared/model/Identity.js.map +0 -1
- package/lib/shared/model/IdentityCredentials.js.map +0 -1
- package/lib/shared/model/index.js.map +0 -1
- package/lib/shared/overrides/Model.js.map +0 -1
- package/lib/shared/overrides/index.js.map +0 -1
- package/lib/shared/overrides/overrides.js.map +0 -1
- package/lib/shared/types.js.map +0 -1
- package/lib/shared/utils.js.map +0 -1
- package/lib/version.js.map +0 -1
package/dist/for-fabric.cjs
CHANGED
|
@@ -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
|
-
|
|
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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
|