@decaf-ts/for-fabric 0.1.45 → 0.1.46
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 +1896 -2
- package/dist/for-fabric.js +2002 -2
- package/lib/bin/cli.cjs +2 -1
- package/lib/cli-module.cjs +4 -4
- package/lib/cli-utils.cjs +1 -1
- package/lib/client/FabricClientAdapter.cjs +1 -1
- package/lib/client/FabricClientDispatch.cjs +1 -1
- package/lib/client/FabricClientPaginator.cjs +1 -1
- package/lib/client/FabricClientRepository.cjs +1 -1
- package/lib/client/FabricClientStatement.cjs +1 -1
- package/lib/client/collections/generation.cjs +1 -1
- package/lib/client/collections/index.cjs +1 -1
- package/lib/client/constants.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-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/FabricIdentityService.cjs +1 -1
- package/lib/client/services/RegistrationRequestBuilder.cjs +1 -1
- package/lib/client/services/constants.cjs +1 -1
- package/lib/client/services/index.cjs +1 -1
- package/lib/client/types.cjs +1 -1
- package/lib/contract/Address.cjs +1 -1
- package/lib/contract/AddressContract.cjs +1 -1
- package/lib/contract/BatchContract.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/contract/models/Audit.cjs +1 -1
- package/lib/contract/models/BaseIdentifiedModel.cjs +1 -1
- package/lib/contract/models/BaseModel.cjs +1 -1
- package/lib/contract/models/Batch.cjs +1 -1
- package/lib/contract/models/Leaflet.cjs +1 -1
- package/lib/contract/models/LeafletFile.cjs +1 -1
- package/lib/contract/models/Market.cjs +1 -1
- package/lib/contract/models/Product.cjs +1 -1
- package/lib/contract/models/ProductStrength.cjs +1 -1
- package/lib/contract/models/constants.cjs +1 -1
- package/lib/contract/models/decorators.cjs +1 -1
- package/lib/contract/models/gtin.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/FabricContractPaginator.cjs +1 -1
- package/lib/contracts/FabricContractRepository.cjs +1 -1
- package/lib/contracts/FabricContractRepositoryObservableHandler.cjs +1 -1
- package/lib/contracts/FabricContractSequence.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/cli.js +1 -1
- package/lib/esm/cli-module.js +4 -4
- package/lib/esm/cli-utils.js +1 -1
- package/lib/esm/client/FabricClientAdapter.js +1 -1
- package/lib/esm/client/FabricClientDispatch.js +1 -1
- package/lib/esm/client/FabricClientPaginator.js +1 -1
- package/lib/esm/client/FabricClientRepository.js +1 -1
- package/lib/esm/client/FabricClientStatement.js +1 -1
- package/lib/esm/client/collections/generation.js +1 -1
- package/lib/esm/client/collections/index.js +1 -1
- package/lib/esm/client/constants.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.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/FabricIdentityService.js +1 -1
- package/lib/esm/client/services/RegistrationRequestBuilder.js +1 -1
- package/lib/esm/client/services/constants.js +1 -1
- package/lib/esm/client/services/index.js +1 -1
- package/lib/esm/client/types.js +1 -1
- package/lib/esm/contract/Address.js +1 -1
- package/lib/esm/contract/AddressContract.js +1 -1
- package/lib/esm/contract/BatchContract.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/contract/models/Audit.js +1 -1
- package/lib/esm/contract/models/BaseIdentifiedModel.js +1 -1
- package/lib/esm/contract/models/BaseModel.js +1 -1
- package/lib/esm/contract/models/Batch.js +1 -1
- package/lib/esm/contract/models/Leaflet.js +1 -1
- package/lib/esm/contract/models/LeafletFile.js +1 -1
- package/lib/esm/contract/models/Market.js +1 -1
- package/lib/esm/contract/models/Product.js +1 -1
- package/lib/esm/contract/models/ProductStrength.js +1 -1
- package/lib/esm/contract/models/constants.js +1 -1
- package/lib/esm/contract/models/decorators.js +1 -1
- package/lib/esm/contract/models/gtin.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/FabricContractPaginator.js +1 -1
- package/lib/esm/contracts/FabricContractRepository.js +1 -1
- package/lib/esm/contracts/FabricContractRepositoryObservableHandler.js +1 -1
- package/lib/esm/contracts/FabricContractSequence.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/erc20/index.js +1 -1
- package/lib/esm/shared/errors.js +1 -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/interfaces/index.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.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/erc20/index.cjs +1 -1
- package/lib/shared/errors.cjs +1 -1
- 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/interfaces/index.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/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/cli.js.map +0 -1
- package/lib/cli-module.js.map +0 -1
- package/lib/cli-utils.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/collections/generation.js.map +0 -1
- package/lib/client/collections/index.js.map +0 -1
- package/lib/client/constants.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/FabricIdentityService.js.map +0 -1
- package/lib/client/services/RegistrationRequestBuilder.js.map +0 -1
- package/lib/client/services/constants.js.map +0 -1
- package/lib/client/services/index.js.map +0 -1
- package/lib/client/types.js.map +0 -1
- package/lib/contract/Address.js.map +0 -1
- package/lib/contract/AddressContract.js.map +0 -1
- package/lib/contract/BatchContract.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/contract/models/Audit.js.map +0 -1
- package/lib/contract/models/BaseIdentifiedModel.js.map +0 -1
- package/lib/contract/models/BaseModel.js.map +0 -1
- package/lib/contract/models/Batch.js.map +0 -1
- package/lib/contract/models/Leaflet.js.map +0 -1
- package/lib/contract/models/LeafletFile.js.map +0 -1
- package/lib/contract/models/Market.js.map +0 -1
- package/lib/contract/models/Product.js.map +0 -1
- package/lib/contract/models/ProductStrength.js.map +0 -1
- package/lib/contract/models/constants.js.map +0 -1
- package/lib/contract/models/decorators.js.map +0 -1
- package/lib/contract/models/gtin.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/FabricContractPaginator.js.map +0 -1
- package/lib/contracts/FabricContractRepository.js.map +0 -1
- package/lib/contracts/FabricContractRepositoryObservableHandler.js.map +0 -1
- package/lib/contracts/FabricContractSequence.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/cli.js.map +0 -1
- package/lib/esm/cli-module.js.map +0 -1
- package/lib/esm/cli-utils.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/collections/generation.js.map +0 -1
- package/lib/esm/client/collections/index.js.map +0 -1
- package/lib/esm/client/constants.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/FabricIdentityService.js.map +0 -1
- package/lib/esm/client/services/RegistrationRequestBuilder.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/client/types.js.map +0 -1
- package/lib/esm/contract/Address.js.map +0 -1
- package/lib/esm/contract/AddressContract.js.map +0 -1
- package/lib/esm/contract/BatchContract.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/contract/models/Audit.js.map +0 -1
- package/lib/esm/contract/models/BaseIdentifiedModel.js.map +0 -1
- package/lib/esm/contract/models/BaseModel.js.map +0 -1
- package/lib/esm/contract/models/Batch.js.map +0 -1
- package/lib/esm/contract/models/Leaflet.js.map +0 -1
- package/lib/esm/contract/models/LeafletFile.js.map +0 -1
- package/lib/esm/contract/models/Market.js.map +0 -1
- package/lib/esm/contract/models/Product.js.map +0 -1
- package/lib/esm/contract/models/ProductStrength.js.map +0 -1
- package/lib/esm/contract/models/constants.js.map +0 -1
- package/lib/esm/contract/models/decorators.js.map +0 -1
- package/lib/esm/contract/models/gtin.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/FabricContractPaginator.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/FabricContractSequence.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/erc20/index.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/interfaces/index.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/erc20/index.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/interfaces/index.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,1896 @@
|
|
|
1
|
-
var t,e;t=this,e=function(t,e,r,a,n,i,o,s,c){"use strict";class l extends a.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 a.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,r,...n){const{log:i,ctx:o}=a.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,r)=>{const a=[t,e];return r&&a.push(r),a.join("_")})(d,e,c);s.setEvent(t,Buffer.from(JSON.stringify({id:r})))}else s.setEvent(e,Buffer.from(JSON.stringify(l)))}}class u extends a.Repository{constructor(t,e,r){super(t,e),this.trackedEvents=r,this._overrides=Object.assign({},super._overrides,{ignoreValidation:!1,ignoreHandlers:!1,allowRawStatements:!0,forcePrepareSimpleQueries:!1,forcePrepareComplexQueries:!1})}async paginateBy(t,e,n={offset:1,limit:10},...i){let{offset:o,bookmark:s,limit:c}=n;if(!o&&!s)throw new a.QueryError("PaginateBy needs a page or a bookmark");const l=await a.Context.args(a.PreparedStatementKeys.PAGE_BY,this.class,i,this.adapter,this._overrides||{}),{log:d,ctxArgs:u}=this.logCtx(l.args,this.paginateBy);let g;if(d.verbose(`paginating ${r.Model.tableName(this.class)} with page size ${c}`),s)g=await this.override({forcePrepareComplexQueries:!1,forcePrepareSimpleQueries:!1}).select().where(this.attr(r.Model.pk(this.class)).gt(s)).orderBy([t,e]).paginate(c,...u),o=1;else{if(!o)throw new a.QueryError("PaginateBy needs a page or a bookmark");g=await this.override({forcePrepareComplexQueries:!1,forcePrepareSimpleQueries:!1}).select().orderBy([t,e]).paginate(c,...u)}const p=await g.page(o,...u);return g.serialize(p)}async statement(t,...e){if(!a.Repository.statements(this,t))throw new a.QueryError("Invalid prepared statement requested "+t);const r=await a.Context.args(a.PersistenceKeys.STATEMENT,this.class,e,this.adapter,this._overrides||{});r.context.logger&&r.context.logger.info(`Repo statement: ${t} + ${e}`);const{log:i,ctxArgs:o}=this.logCtx(r.args,this.statement);let s;i.verbose(`Executing prepared statement ${t} with args ${o}`);try{s=await this[t](...o)}catch(e){if(e instanceof n.BaseError)throw e;throw new n.InternalError(`Failed to execute prepared statement ${t} with args ${o}: ${e}`)}return s}ObserverHandler(){return new d}async updateObservers(t,e,r,...a){if(!this.trackedEvents||-1!==this.trackedEvents.indexOf(e))return await super.updateObservers(t,e,r,...a)}}class g extends e.CouchDBStatement{constructor(t){super(t)}async raw(t,...e){const{ctx:a}=this.logCtx(e,this.raw),i=await this.adapter.raw(t,!0,a),s=r.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,a))}build(){const t={};t[e.CouchDBKeys.TABLE]={},t[e.CouchDBKeys.TABLE]=r.Model.tableName(this.fromSelector);const n={selector:t};if(this.selectSelector&&(n.fields=this.selectSelector),this.whereCondition){const t=this.parseCondition(a.Condition.and(this.whereCondition,a.Condition.attribute(e.CouchDBKeys.TABLE).eq(n.selector[e.CouchDBKeys.TABLE]))).selector,r=Object.keys(t);if(1===r.length&&-1!==Object.values(e.CouchDBGroupOperator).indexOf(r[0]))switch(r[0]){case e.CouchDBGroupOperator.AND:t[e.CouchDBGroupOperator.AND]=[...Object.values(t[e.CouchDBGroupOperator.AND]).reduce((t,r)=>{const a=Object.keys(r);if(1!==a.length)throw Error("Too many keys in query selector. should be one");const n=a[0];return n===e.CouchDBGroupOperator.AND?t.push(...r[n]):t.push(r),t},[])],n.selector=t;break;case e.CouchDBGroupOperator.OR:{const r={};r[e.CouchDBGroupOperator.AND]=[t,...Object.entries(n.selector).map(([t,e])=>{const r={};return r[t]=e,r})],n.selector=r;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,r]=this.orderBySelector,a={};a[t]=r,n.sort.push(a),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}}class p extends a.Sequence{constructor(t,e){super(t,e)}async current(...t){const e=(await a.Context.args(n.OperationKeys.READ,a.SequenceModel,t,this.adapter)).context,{name:r,startWith:i}=this.options;try{const t=await this.repo.read(r,e);return this.parse(t.current)}catch(t){const a=e.logger.for(this.current);if(t instanceof n.NotFoundError){let t;try{a.debug(`Trying to resolve current sequence ${r} value from context`),t=e.get(r),a.debug(`Retrieved cached current value for sequence ${r}: ${t}`)}catch(e){a.info(`No cached value for sequence ${r} in context`),t=i}try{return this.parse(t)}catch(t){throw new n.InternalError(`Failed to parse initial value for sequence ${i}: ${t}`)}}throw new n.InternalError(`Failed to retrieve current value for sequence ${r}: ${t}`)}}async increment(t,e){const r=e.logger.for(this.increment),{type:i,incrementBy:o,name:s}=this.options;if(!s)throw new n.InternalError("Sequence name is required");return r.info("Obtaining sequence lock for sequence "+s),p.lock.execute(async()=>{const c=t||o;if(c%o!==0)throw new n.InternalError("Value to increment does not consider the incrementBy setting: "+o);const l="function"==typeof i&&i?.name?i.name:i,d=await this.current(e);async function u(t){return t instanceof Promise&&(t=await t),e.logger.for(u).info(`Storing new ${s} seq value in cache: ${t.current}`),e.cache.put(s,t.current),t}const g=async t=>{try{return await u(this.repo.update(new a.SequenceModel({id:s,current:t}),e))}catch(i){if(i instanceof n.NotFoundError)return r.debug(`Sequence create ${s} current=${d} next=${t}`),u(this.repo.create(new a.SequenceModel({id:s,current:t}),e));throw i}};if("uuid"===l)for(;;){const t=a.UUID.instance.generate(d);try{const e=await g(t);return r.debug(`Sequence uuid increment ${s} current=${d} next=${t}`),e.current}catch(t){if(t instanceof n.ConflictError)continue;throw t}}const p=(t=>{switch(l){case Number.name:return this.parse(t)+c;case BigInt.name:return this.parse(t)+BigInt(c);case String.name:return this.parse(t);case"serial":return a.Serial.instance.generate(t);default:throw new n.InternalError("Should never happen")}})(d),h=await g(p);return r.debug(`Sequence.increment ${s} current=${d} next=${p}`),h.current},s)}}var h,y;(t=>{t.PRIVATE="private",t.SHARED="shared",t.FABRIC="fabric.",t.OWNEDBY="owned-by",t.TRANSACTION_ID="transaction-id"})(h||(h={})),(t=>{t.X509="X.509"})(y||(y={}));const m="hlf-fabric";class w extends r.JSONSerializer{constructor(){super()}deserialize(t,e){return JSON.parse(t)}serialize(t,e=!0){return require("json-stringify-deterministic")(require("sort-keys-recursive")(this.preSerialize(t,e)))}preSerialize(t,e=!0){const a=Object.assign({},t);let n;try{n=o.Metadata.modelName(t.constructor)}catch(t){n=void 0}function i(t){return"object"!=typeof t?t:Array.isArray(t)?t.map(i):this.preSerialize(t)}return e&&(a[r.ModelKeys.ANCHOR]=n||t.constructor.name),r.Model.relations(t).forEach(t=>{a[t]=i.call(this,a[t])}),a}}class f extends s.MiniLogger{constructor(t,e,r){super(t,e),this.logger=r?r.logging.getLogger(t):new s.MiniLogger(t,e)}log(t,e,r){if(s.NumericLogLevels[this.config("level")]<s.NumericLogLevels[t])return;let a;switch(t){case s.LogLevel.info:a=this.logger.info;break;case s.LogLevel.verbose:a=this.logger.verbose;break;case s.LogLevel.debug:a=this.logger.debug;break;case s.LogLevel.error:a=this.logger.error;break;case s.LogLevel.warn:a=this.logger.warn;break;case s.LogLevel.silly:a=this.logger.silly;break;default:throw new n.InternalError("Invalid log level")}a.call(this.logger,this.createLog(t,e,r))}}s.Logging.setFactory((t,e,r)=>new f(t||f.name,e||{},r));class _ extends e.CouchDBPaginator{constructor(t,e,r,a){super(t,e,r,a)}prepare(t){const e=Object.assign({},t);return e.limit&&(this.limit=e.limit),e.limit=this.size,e}async page(t=1,...e){const{ctxArgs:i,ctx:s}=this.adapter.logCtx(e,this.page);if(this.isPreparedStatement())return this.pagePrepared(t,...i);const c=Object.assign({},this.statement);if(!this._recordCount||!this._totalPages){this._totalPages=this._recordCount=0;const t=await this.adapter.raw({...c,limit:void 0},!0,s)||[];if(this._recordCount=t.length,this._recordCount>0){const t=c?.limit||this.size;this._totalPages=Math.ceil(this._recordCount/t)}}if(this.validatePage(t),1!==t){if(!this._bookmark)throw new a.PagingError("No bookmark. Did you start in the first page?");c.bookmark=this._bookmark}const l=await this.adapter.raw(c,!1,s);if(!this.clazz)throw new a.PagingError("No statement target defined");const d=r.Model.pk(this.clazz),u=o.Metadata.get(this.clazz,o.Metadata.key(n.DBKeys.ID,d))?.type,g=c.fields&&c.fields.length?l:l.map(t=>this.adapter.revert(t,this.clazz,a.Sequence.parseValue(u,t[d]),void 0,s)),p=c.sort?.[0]||a.OrderDirection.DSC;return this._bookmark=g[p===a.OrderDirection.ASC?g.length-1:0][d],this._currentPage=t,g}}class x extends n.InternalError{constructor(t){super(t,x.name)}}class b extends n.InternalError{constructor(t){super(t,b.name)}}class C extends n.InternalError{constructor(t){super(t,C.name)}}class S extends n.InternalError{constructor(t){super(t,S.name,500)}}class v extends n.BaseError{constructor(t){super(v.name,t,409)}}async function E(t,e,r,n){try{const e=t.get("identity");n[r]=e.getID()}catch(t){throw new a.UnsupportedError("No User found in context. Please provide a user in the context")}}class A extends e.CouchDBAdapter{getClient(){throw new a.UnsupportedError("Client is not supported in Fabric contracts")}static{this.textDecoder=new TextDecoder("utf8")}static{this.serializer=new w}repository(){return u}Paginator(t,e,r){return new _(this,t,e,r)}async Sequence(t){return new p(t,this)}constructor(t,e){super(t,m,e),this.Context=l}for(t,...e){return super.for(t,...e)}async create(t,e,a,...n){const{ctx:i,log:o}=this.logCtx(n,this.create);o.info("in ADAPTER create with args "+n);const s=r.Model.tableName(t);try{o.info(`adding entry to ${s} table with pk ${e}`);const t=i.stub.createCompositeKey(s,[e+""]);a=await this.putState(t,a,i)}catch(t){throw this.parseError(t)}return a}async read(t,e,...a){const{ctx:n,log:i}=this.logCtx(a,this.read);i.info("in ADAPTER read with args "+a);const o=r.Model.tableName(t);let s;try{const t=n.stub.createCompositeKey(o,[e+""]);s=await this.readState(t,n)}catch(t){throw this.parseError(t)}return s}async update(t,e,a,...n){const{ctx:i,log:o}=this.logCtx(n,this.update),s=r.Model.tableName(t);try{o.verbose(`updating entry to ${s} table with pk ${e}`);const t=i.stub.createCompositeKey(s,[e+""]);a=await this.putState(t,a,i)}catch(t){throw this.parseError(t)}return a}async delete(t,e,...a){const{ctx:n,log:i,ctxArgs:o}=this.logCtx(a,this.delete),s=r.Model.tableName(t);let c;try{const r=n.stub.createCompositeKey(s,[e+""]);c=await this.read(t,e,...o),i.verbose(`deleting entry with pk ${e} from ${s} table`),await this.deleteState(r,n)}catch(t){throw this.parseError(t)}return c}async deleteState(t,e){const{ctx:r}=this.logCtx([e],this.deleteState);await r.stub.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:(r,a,i)=>e.includes(a)?new Proxy(r[a],{async apply(e,r,i){switch(a){case"putState":{const[e,r,a]=i;return await e.putPrivateData(t,r.toString(),a),a}case"deleteState":{const[e,r]=i;return e.deletePrivateData(t,r)}case"readState":{const[e,r]=i;return e.getPrivateData(t,r)}case"queryResult":{const[e,r]=i;return e.getPrivateDataQueryResult(t,r)}case"queryResultPaginated":{const[e,r,a,n]=i,o=await e.getPrivateDataQueryResult(t,r),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,r=t.value.value.toString("utf8");if(!l){e===n?.toString()&&(l=!0);continue}if(s.push({Key:e,Record:JSON.parse(r)}),d=e,c++,c>=a)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 "+a)}}}):Reflect.get(r,a,i)})}async putState(t,e,r){let a;const{log:i}=this.logCtx([r],this.putState);try{a=Buffer.from(A.serializer.serialize(e,!1))}catch(e){throw new n.SerializationError(`Failed to serialize record with id ${t}: ${e}`)}const o=r.get("segregated");return o?await r.stub.putPrivateData(o,t.toString(),a):await r.stub.putState(t.toString(),a),i.silly(`state stored${o?` in ${o} collection`:""} under id ${t}`),e}async readState(t,e){let r;const{log:a}=this.logCtx([e],this.readState);let i;const o=e.get("segregated");if(i=o?(await e.stub.getPrivateData(o,t.toString())).toString():(await e.stub.getState(t.toString())).toString(),!i)throw new n.NotFoundError(`Record with id ${t}${o?` in ${o} collection`:""} not found`);a.silly(`state retrieved from${o?` ${o} collection`:""} under id ${t}`);try{r=A.serializer.deserialize(i.toString())}catch(t){throw new n.SerializationError("Failed to parse record: "+t)}return r}async queryResult(t,e,...r){const{ctx:a}=this.logCtx(r,this.readState);let n;const i=a.get("segregated");return n=i?await a.stub.getPrivateDataQueryResult(i,JSON.stringify(e)):await t.getQueryResult(JSON.stringify(e)),n}async queryResultPaginated(t,e,r=250,a,...n){const{ctx:i}=this.logCtx(n,this.readState);let o;const s=i.get("segregated");return s?(e.selector={...e.selector,_id:a?{$gt:a.toString()}:{$gte:""}},o={iterator:await t.getPrivateDataQueryResult(s,JSON.stringify(e)),metadata:{fetchedRecordsCount:r,bookmark:""}}):o=await t.getQueryResultWithPagination(JSON.stringify(e),r,a?.toString()),o}mergeModels(t){const e=t=>Object.entries(t).reduce((t,[e,r])=>(void 0!==r&&(t[e]=r),t),{});let r=t.pop();for(const a of t)r=Object.assign({},e(r),e(a));return r}decode(t){return A.textDecoder.decode(t)}async flags(t,e,r,a,...n){const i={stub:a.stub,segregated:!1};return Object.assign(i,a instanceof l?{logger:a.logger,identity:a.identity,correlationId:a.stub.getTxID()}:{identity:a.clientIdentity,logger:new f(this,void 0,a),correlationId:a.stub.getTxID()}),await super.flags(t,e,i,...n)}index(t){return Promise.resolve(void 0)}async resultIterator(t,e,r=!1){const a=[];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")),r){e.TxId=n.value.txId,e.Timestamp=n.value.timestamp;try{e.Value=JSON.parse(n.value.value.toString("utf8"))}catch(r){t.error(r),e.Value=n.value.value.toString("utf8")}}else try{e=JSON.parse(n.value.value.toString("utf8"))}catch(r){t.error(r),e=n.value.value.toString("utf8")}a.push(e)}n=await e.next()}return t.debug(`Closing iterator after ${a.length} results`),e.close(),a}async raw(t,e=!0,...r){const{log:a,stub:n,ctx:i}=this.logCtx(r,this.raw),{skip:o,limit:s}=t;let c;s||o?(delete t.limit,delete t.skip,a.debug(`Retrieving paginated iterator: limit: ${s}/ skip: ${o}`),c=(await this.queryResultPaginated(n,t,s||250,o?.toString(),i)).iterator):(a.debug("Retrieving iterator"),c=await this.queryResult(n,t,i)),a.debug("Iterator acquired");const l=await this.resultIterator(a,c);return a.debug(`returning ${Array.isArray(l)?l.length:1} results`),l}Statement(){return new g(this)}async createAll(t,e,a,...i){if(e.length!==a.length)throw new n.InternalError("Ids and models must have the same length");const{log:o,ctxArgs:s}=this.logCtx(i,this.createAll),c=r.Model.tableName(t);return o.debug(`Creating ${e.length} entries ${c} table`),Promise.all(e.map((e,r)=>this.create(t,e,a[r],...s)))}async updateAll(t,e,a,...i){if(e.length!==a.length)throw new n.InternalError("Ids and models must have the same length");const{log:o,ctxArgs:s}=this.logCtx(i,this.updateAll),c=r.Model.tableName(t);return o.debug(`Updating ${e.length} entries ${c} table`),Promise.all(e.map((e,r)=>this.update(t,e,a[r],...s)))}prepare(t,...e){const{log:a}=this.logCtx(e,this.prepare),i=r.Model.tableName(t.constructor),o=r.Model.pk(t.constructor),s=r.Model.segregate(t),c=Object.entries(s.model).reduce((e,[a,i])=>{if(void 0===i)return e;const o=r.Model.columnName(t,a);if(this.isReserved(o))throw new n.InternalError(`Property name ${o} is reserved`);return e[o]=i,e},{});return a.silly(`Preparing record for ${i} table with pk ${t[o]}`),{record:c,id:t[o],transient:s.transient}}revert(t,e,a,i,...o){const{log:s}=this.logCtx(o,this.revert),c={};c[r.Model.pk(e)]=a;const l="string"==typeof e?r.Model.build(c,e):new e(c);s.silly(`Rebuilding model ${l.constructor.name} id ${a}`);const d=Object.keys(l).reduce((e,a)=>(e[a]=t[r.Model.columnName(e,a)],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,a,n,...i){const{ctxArgs:o}=this.logCtx(i,this.createPrefix),s={};return s[e.CouchDBKeys.TABLE]=r.Model.tableName(t),Object.assign(s,n),[t,a,s,...o]}updatePrefix(t,a,n,...i){const{ctxArgs:o}=this.logCtx(i,this.updatePrefix),s={};return s[e.CouchDBKeys.TABLE]=r.Model.tableName(t),Object.assign(s,n),[t,a,s,...o]}createAllPrefix(t,a,i,...o){if(a.length!==i.length)throw new n.InternalError("Ids and models must have the same length");const s=o.pop(),c=a.map((a,n)=>{const o={};return o[e.CouchDBKeys.TABLE]=r.Model.tableName(t),Object.assign(o,i[n]),o});return[t,a,c,s]}updateAllPrefix(t,a,i,...o){if(a.length!==i.length)throw new n.InternalError("Ids and models must have the same length");const s=o.pop(),c=a.map((a,n)=>{const o={};return o[e.CouchDBKeys.TABLE]=r.Model.tableName(t),Object.assign(o,i[n]),o});return[t,a,c,s]}parseError(t,e){return A.parseError(e||t)}logCtx(t,e){return A.logCtx.call(this,t,e)}static logCtx(t,e){if(1>t.length)throw new n.InternalError("No context provided");const r=t.pop();if(!(r instanceof a.Context))throw new n.InternalError("No context provided");if(t.filter(t=>t instanceof a.Context).length>1)throw Error("here");const i=this?r.logger.for(this).for(e):r.logger.clear().for(this).for(e);return{ctx:r,log:e?i.for(e):i,stub:r.stub,identity:r.identity,ctxArgs:[...t,r]}}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(a.QueryError.name)?new a.QueryError(t):e.includes(a.PagingError.name)?new a.PagingError(t):e.includes(a.UnsupportedError.name)?new a.UnsupportedError(t):e.includes(a.MigrationError.name)?new a.MigrationError(t):e.includes(a.ObserverError.name)?new a.ObserverError(t):e.includes(a.AuthorizationError.name)?new a.AuthorizationError(t):e.includes(a.ForbiddenError.name)?new a.ForbiddenError(t):e.includes(a.ConnectionError.name)?new a.ConnectionError(t):e.includes(n.SerializationError.name)?new n.SerializationError(t):e.includes("no ledger context")?new S("No context found. this can be caused by debugging: "+e):new n.InternalError(t)}static decoration(){super.decoration(),o.Decoration.flavouredAs(m).for(a.PersistenceKeys.CREATED_BY).define(n.onCreate(E),o.propMetadata(a.PersistenceKeys.CREATED_BY,{})).apply(),o.Decoration.flavouredAs(m).for(a.PersistenceKeys.UPDATED_BY).define(n.onCreateUpdate(E),o.propMetadata(a.PersistenceKeys.UPDATED_BY,{})).apply(),o.Decoration.flavouredAs(m).for(a.PersistenceKeys.COLUMN).extend(i.Property()).apply(),o.Decoration.flavouredAs(m).for(r.ValidationKeys.DATE).extend(()=>(t,e)=>{i.Property(e,"string:date")(t,e)}),o.Decoration.flavouredAs(m).for(a.PersistenceKeys.TABLE).extend(t=>{const e=[];let r="function"==typeof t?o.Metadata.constr(t):o.Metadata.constr(t.constructor);for(;r&&r!==Object&&r.prototype;)e.push(r),r=Object.getPrototypeOf(r);for(;e.length>0;){const t=e.pop();i.Object()(t)}return i.Object()(t)}).apply()}}A.decoration(),a.Adapter.setCurrent(m);class O extends r.JSONSerializer{constructor(){super()}preSerialize(t){const e=Object.assign({},t);let a;try{a=o.Metadata.modelName(t.constructor)}catch(t){a=void 0}e[r.ModelKeys.ANCHOR]=a||t.constructor.name;const n=function t(e){const r=this;return"object"!=typeof e?e:Array.isArray(e)?e.map(e=>t.call(r,e)):this.preSerialize.call(this,e)}.bind(this);return r.Model.relations(t).forEach(t=>{e[t]=n(e[t])}),e}deserialize(t){const e=JSON.parse(t),a=e[r.ModelKeys.ANCHOR];if(!a)throw Error("Could not find class reference in serialized model");return r.Model.build(e,a)}serialize(t){return require("json-stringify-deterministic")(require("sort-keys-recursive")(this.preSerialize(t)))}}i.Object()(Date);class k extends i.Contract{static{this.adapter=new A}static{this.serializer=new O}constructor(t,e){super(t),this.clazz=e,this.initialized=!1,this.repo=a.Repository.forModel(e)}async listBy(t,e,r,...a){const{ctxArgs:n,log:i}=await this.logCtx([...a,t],this.listBy);return i.info(`Running listBy key ${e}, order ${r} and args ${n}`),this.repo.listBy(e,r,...n)}async paginateBy(t,e,r,a={offset:1,limit:10},...n){const{ctxArgs:i,log:o}=await this.logCtx([...n,t],this.paginateBy);return o.info(`Running paginateBy key ${e}, order ${r} with size ${a.limit} and args ${i}`),this.repo.paginateBy(e,r,a,...i)}async findOneBy(t,e,r,...a){const{ctxArgs:n,log:i}=await this.logCtx([...a,t],this.findOneBy);return i.info(`Running findOneBy key ${e}, value: ${r} with args ${n}`),this.repo.findOneBy(e,r,...n)}async statement(t,e,...r){const{ctxArgs:a,log:n}=await this.logCtx([...r,t],this.statement);return n.info(`Running statement ${e} with args ${a}`),this.repo.statement(e,...a)}async create(t,e,...a){const{log:n,ctxArgs:i}=await this.logCtx([...a,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=r.Model.merge(e,o,this.clazz),this.repo.create(e,...i)}async read(t,e,...r){const{log:a,ctxArgs:n}=await this.logCtx([...r,t],this.read);return a.info(`reading entry with pk ${e} `),this.repo.read(e,...n)}getTransientData(t){const e=t.stub.getTransient();let r={};return e.has(this.repo.tableName)&&(r=JSON.parse(e.get(this.repo.tableName)?.toString("utf8"))),r}async update(t,e,...a){const{log:n,ctxArgs:i}=await this.logCtx([...a,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=r.Model.merge(e,o,this.clazz),this.repo.update(e,...i)}async delete(t,e,...r){const{log:a,ctxArgs:n}=await this.logCtx([...r,t],this.delete);return a.info(`deleting entry with pk ${e} `),this.repo.delete(e+"",...n)}async deleteAll(t,e,...r){const{ctxArgs:a}=await this.logCtx([...r,t],this.readAll);return"string"==typeof e&&(e=JSON.parse(e)),this.repo.deleteAll(e,...a)}async readAll(t,e,...r){const{ctxArgs:a}=await this.logCtx([...r,t],this.readAll);return"string"==typeof e&&(e=JSON.parse(e)),this.repo.readAll(e,...a)}async updateAll(t,e,...r){const{log:a,ctxArgs:n}=await this.logCtx([...r,t],this.updateAll);return"string"==typeof e&&(e=JSON.parse(e).map(t=>this.deserialize(t)).map(t=>new this.clazz(t))),a.info(`updating ${e.length} entries to the table`),this.repo.updateAll(e,...n)}async query(t,e,r,n=a.OrderDirection.ASC,i,o,...s){const{ctxArgs:c}=await this.logCtx([...s,t],this.query);return this.repo.query(e,r,n,i,o,...c)}async raw(t,e,r,...a){const{ctxArgs:n}=await this.logCtx([...a,t],this.raw);return k.adapter.raw(e,r,...n)}serialize(t){return k.serializer.serialize(t)}deserialize(t){return k.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,...r){const{log:a,ctxArgs:n}=await this.logCtx([...r,t],this.createAll);return"string"==typeof e&&(e=JSON.parse(e).map(t=>this.deserialize(t)).map(t=>new this.clazz(t))),a.info(`adding ${e.length} entries to the table`),this.repo.createAll(e,...n)}async logCtx(t,e){return k.logCtx.bind(this)(t,e)}static async logCtx(t,e){if(1>t.length)throw new n.InternalError("No context provided");const r=t.pop();if(r instanceof l)return{ctx:r,log:r.logger.clear().for(this).for(e),ctxArgs:[...t,r],stub:r.stub,identity:r.identity};if(!(r instanceof i.Context))throw new n.InternalError("No valid context provided");const a={correlationId:r.stub.getTxID()},o=await k.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})(),a,this.clazz,r),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 k{constructor(t,e){super(t,e)}async create(t,e){const{log:r,ctx:a}=await this.logCtx([t],this.create);r.info("Creating model: "+e);const n=this.deserialize(e);r.info("Model deserialized: "+JSON.stringify(n));const i=await super.create(a,n),o=this.serialize(i);return r.info("RESULT: "+JSON.stringify(i)),r.info("Retuning: "+o),o}async read(t,e){const{log:r,ctx:a}=await this.logCtx([t],this.read);return r.info("Reading id: "+e),this.serialize(await super.read(a,e))}async update(t,e){const{log:r,ctx:a}=await this.logCtx([t],this.update);return r.info("Updating model: "+e),this.serialize(await super.update(a,e))}async delete(t,e){const{log:r,ctx:a}=await this.logCtx([t],this.delete);return r.info("Deleting id: "+e),this.serialize(await super.delete(a,e))}async deleteAll(t,e){const r=JSON.parse(e),{log:a,ctx:n}=await this.logCtx([t],this.deleteAll);return a.info(`deleting ${r.length} entries from the table`),JSON.stringify((await super.deleteAll(n,r)).map(t=>this.serialize(t)))}async readAll(t,e){const r=JSON.parse(e),{log:a,ctx:n}=await this.logCtx([t],this.readAll);return a.info(`reading ${r.length} entries from the table`),JSON.stringify((await super.readAll(n,r)).map(t=>this.serialize(t)))}async updateAll(t,e){const{log:r,ctx:a}=await this.logCtx([t],this.updateAll),n=JSON.parse(e).map(t=>this.deserialize(t)).map(t=>new this.clazz(t));return r.info(`Updating ${n.length} entries to the table`),JSON.stringify((await super.updateAll(a,n)).map(t=>this.serialize(t)))}async statement(t,e,r){const{ctx:a,log:i}=await this.logCtx([t],this.statement);try{r=JSON.parse(r)}catch(t){throw new n.SerializationError("Invalid args: "+t)}if(!Array.isArray(r))throw new n.SerializationError(`Invalid args: ${JSON.stringify(r)}. must be an array`);return i.info("calling prepared statement "+e),i.info("with args "+r),JSON.stringify(await super.statement(a,e,...r))}async listBy(t,e,r){const{ctx:a,log:n}=await this.logCtx([t],this.listBy);return n.info(`Executing listBy with key ${e} and order ${r}`),JSON.stringify(await super.listBy(a,e,r))}async paginateBy(t,e,r,a,...i){const{ctx:o,log:s}=await this.logCtx([...i,t],this.paginateBy);try{a=JSON.parse(a)}catch(t){throw new n.SerializationError("Failed to deserialize paginateBy reference: "+t)}return s.info(`Executing paginateBy with key ${e} and order ${r}`),JSON.stringify(await super.paginateBy(o,e,r,a,...i))}async findOneBy(t,e,r,...a){const{ctx:n,log:i}=await this.logCtx([...a,t],this.findOneBy);return i.info(`Executing findOneBy with key ${e} and value ${r}`),JSON.stringify(await super.findOneBy(n,e,r,...a))}async query(t,e,r,i,o,s){const{ctx:c,log:l}=await this.logCtx([t],this.query);let d;l.info(`Executing query orderedBy ${r} and order ${i}`);try{d=a.Condition.from(JSON.parse(e))}catch(t){throw new n.SerializationError("Invalid condition: "+t)}return l.info("Condition: "+JSON.stringify(d)),JSON.stringify(await super.query(c,d,r,i,o,s))}async init(t){await super.init(t)}async healthcheck(t){const{log:e,ctx:r}=await this.logCtx([t],this.updateAll);return e.debug(`Running Healthcheck: ${this.initialized}...`),JSON.stringify(await super.healthcheck(r))}async createAll(t,e){const{log:r}=await this.logCtx([t],this.createAll),a=JSON.parse(e).map(t=>this.deserialize(t)).map(t=>new this.clazz(t));r.info(`Adding ${a.length} entries to the table`);const n=await super.createAll(t,a);return JSON.stringify(n.map(t=>this.serialize(t)))}}function T(t,e){const r=t+e;if(t!==r-e||e!==r-t)throw new x(`Addition overflow: ${t} + ${e}`);return r}function z(t,e){const r=t-e;if(t!==r+e||e!==t-r)throw new x(`Subtraction overflow: ${t} - ${e}`);return r}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]),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,String,l]),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);let $=class extends a.BaseModel{constructor(t){super(t)}};c.__decorate([a.pk({type:"String"}),c.__metadata("design:type",String)],$.prototype,"name",void 0),c.__decorate([a.column(),r.required(),c.__metadata("design:type",String)],$.prototype,"owner",void 0),c.__decorate([a.column(),r.required(),c.__metadata("design:type",String)],$.prototype,"symbol",void 0),c.__decorate([a.column(),r.required(),c.__metadata("design:type",Number)],$.prototype,"decimals",void 0),$=c.__decorate([a.table("erc20_tokens"),r.model(),c.__metadata("design:paramtypes",[Object])],$);let R=class extends a.BaseModel{constructor(t){super(t)}};c.__decorate([a.pk({type:"String"}),c.__metadata("design:type",String)],R.prototype,"id",void 0),c.__decorate([a.column(),r.required(),c.__metadata("design:type",String)],R.prototype,"token",void 0),c.__decorate([a.column(),r.required(),c.__metadata("design:type",Number)],R.prototype,"balance",void 0),c.__decorate([a.column(),c.__metadata("design:type",String)],R.prototype,"captive",void 0),R=c.__decorate([a.table("erc20_wallets"),r.model(),c.__metadata("design:paramtypes",[Object])],R);let B=class extends a.BaseModel{constructor(t){super(t)}};function P(){return function(t,e,r){const i=r.value;return r.value=async function(...t){const r=t[0],o=r.clientIdentity.getID(),s=await this.tokenRepository.select(),c=await s.execute(r);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 a.AuthorizationError(`User not authorized to run ${e} on the token`);return await i.apply(this,t)},r}}var D;c.__decorate([a.pk({type:"String"}),a.column(),r.required(),c.__metadata("design:type",String)],B.prototype,"owner",void 0),c.__decorate([a.column(),r.required(),c.__metadata("design:type",String)],B.prototype,"spender",void 0),c.__decorate([a.column(),r.required(),c.__metadata("design:type",Number)],B.prototype,"value",void 0),B=c.__decorate([a.table("erc20_allowances"),r.model(),c.__metadata("design:paramtypes",[Object])],B),(t=>{t.TRANSFER="Transfer",t.APPROVAL="Approval"})(D||(D={}));class I extends k{constructor(t){super(t,R),I.adapter=I.adapter||new A,this.walletRepository=u.forModel(R,I.adapter.alias),this.tokenRepository=u.forModel($,I.adapter.alias),this.allowanceRepository=u.forModel(B,I.adapter.alias)}async TokenName(t){const{ctx:e}=await this.logCtx([t],this.TokenName);await this.CheckInitialized(e);const r=this.tokenRepository.select();return(await r.execute(e))[0].name}async Symbol(t){const{ctx:e}=await this.logCtx([t],this.TokenName);await this.CheckInitialized(e);const r=this.tokenRepository.select();return(await r.execute(e))[0].symbol}async Decimals(t){const{ctx:e}=await this.logCtx([t],this.TokenName);await this.CheckInitialized(e);const r=this.tokenRepository.select();return(await r.execute(e))[0].decimals}async TotalSupply(t){const{ctx:e}=await this.logCtx([t],this.TokenName);await this.CheckInitialized(e);const r=this.walletRepository.select(),a=await r.execute(e);if(0==a.length)throw new n.NotFoundError(`The token ${this.getName()} does not exist`);let i=0;return a.forEach(t=>{i+=t.balance}),i}async BalanceOf(t,e){const{ctx:r}=await this.logCtx([t],this.TokenName);return await this.CheckInitialized(r),(await this.walletRepository.read(e,r)).balance}async Transfer(t,e,r){const{ctx:a}=await this.logCtx([t],this.Transfer);await this.CheckInitialized(a);const i=a.identity.getID();if(!await this._transfer(i,e,r,a))throw new n.InternalError("Failed to transfer");return!0}async TransferFrom(t,e,r,a){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 C(`spender ${o} has no allowance from ${e}`);const c=s.value;if(a>c)throw new b("The spender does not have enough allowance to spend.");const l=z(c,a),d=Object.assign({},s,{value:l});if(await this.allowanceRepository.update(d,i),!await this._transfer(e,r,a,i))throw new n.InternalError("Failed to transfer");return!0}async _transfer(t,e,r,i){const o=i.logger;if(t===e)throw new a.AuthorizationError("cannot transfer to and from same client account");if(0>r)throw new b("transfer amount cannot be negative");const s=await this.walletRepository.read(t,i),c=s.balance;if(r>c)throw new b(`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 R({id:e,balance:0,token:await this.TokenName(i)}),d=!0}const u=l.balance,g=z(c,r),p=T(u,r),h=Object.assign({},s,{balance:g});await this.walletRepository.update(h,i);const y=Object.assign({},l,{balance:p});d?await this.walletRepository.create(y,i):await this.walletRepository.update(y,i);const m={from:t,to:e,value:r};return this.repo.refresh($,D.TRANSFER,"",m,i).catch(t=>o.error("Failed to notify transfer: "+t)),!0}async Approve(t,e,r){const{ctx:a,ctxArgs:n}=await this.logCtx([t],this.Approve);await this.CheckInitialized(a);const i=a.identity.getID();let o=await this._getAllowance(i,e,a);if((await this.walletRepository.read(i,...n)).balance<r)throw new b(`client account ${i} has insufficient funds.`);o?(o.value=r,await this.allowanceRepository.update(o,...n)):(o=new B({owner:i,spender:e,value:r}),await this.allowanceRepository.create(o,...n));const s={owner:i,spender:e,value:r};return this.repo.refresh($,D.APPROVAL,"",s,a),!0}async Allowance(t,e,r){const{ctx:a}=await this.logCtx([t],this.Allowance);await this.CheckInitialized(a);const n=await this._getAllowance(e,r,a);if(!n)throw new C(`spender ${r} has no allowance from ${e}`);return n.value}async _getAllowance(t,e,r){const n=a.Condition.and(a.Condition.attribute("owner").eq(t),a.Condition.attribute("spender").eq(e)),i=await this.allowanceRepository.select().where(n).execute(r);return i?.[0]}async Initialize(t,e){const{ctx:r}=await this.logCtx([t],this.Initialize);if((await this.tokenRepository.select().execute(r)).length>0)throw new a.AuthorizationError("contract options are already set, client is not authorized to change them");return e.owner=r.identity.getID(),await this.tokenRepository.create(e,r),!0}async CheckInitialized(t){const{ctx:e}=await this.logCtx([t],this.CheckInitialized);if(0==(await this.tokenRepository.select().execute(e)).length)throw new v("contract options need to be set before calling any function, call Initialize() to initialize contract")}async Mint(t,e){const{ctx:r}=await this.logCtx([t],this.Mint);await this.CheckInitialized(r);const a=r.identity.getID();if(0>=e)throw new n.ValidationError("mint amount must be a positive integer");let i;try{i=await this.walletRepository.read(a,r);const t=T(i.balance,e),n=Object.assign({},i,{balance:t});await this.walletRepository.update(n,r)}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 R({id:a,balance:e,token:await this.TokenName(t)});await this.walletRepository.create(n,r)}}const o={from:"0x0",to:a,value:e};this.repo.ObserverHandler().updateObservers($,D.TRANSFER,"",o,r)}async Burn(t,e){const{log:r,ctx:a}=await this.logCtx([t],this.Burn);await this.CheckInitialized(a);const n=a.identity.getID(),i=await this.walletRepository.read(n,a),o=i.balance;if(e>o)throw new b("Minter has insufficient funds.");const s=z(o,e),c=Object.assign({},i,{balance:s});await this.walletRepository.update(c,a),r.info(e+" tokens were burned");const l={from:n,to:"0x0",value:e};this.repo.ObserverHandler().updateObservers($,D.TRANSFER,"",l,a)}async BurnFrom(t,e,r){const{log:a,ctx:n}=await this.logCtx([t],this.BurnFrom);await this.CheckInitialized(n);const i=await this.walletRepository.read(e,n),o=i.balance;if(r>o)throw new b(e+" has insufficient funds.");const s=z(o,r),c=Object.assign({},i,{balance:s});await this.walletRepository.update(c,n),a.info(`${r} tokens were burned from ${e}`);const l={from:e,to:"0x0",value:r};this.repo.ObserverHandler().updateObservers($,D.TRANSFER,"",l,n)}async ClientAccountBalance(t){const{ctx:e}=await this.logCtx([t],this.TokenName);await this.CheckInitialized(e);const r=e.identity.getID(),a=await this.walletRepository.read(r,e);if(!a)throw new b(`The account ${r} does not exist`);return a.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)],I.prototype,"TokenName",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],I.prototype,"Symbol",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],I.prototype,"Decimals",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],I.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)],I.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)],I.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)],I.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)],I.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)],I.prototype,"Allowance",null),c.__decorate([i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,$]),c.__metadata("design:returntype",Promise)],I.prototype,"Initialize",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],I.prototype,"CheckInitialized",null),c.__decorate([P(),i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,Number]),c.__metadata("design:returntype",Promise)],I.prototype,"Mint",null),c.__decorate([P(),i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,Number]),c.__metadata("design:returntype",Promise)],I.prototype,"Burn",null),c.__decorate([P(),i.Transaction(),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context,String,Number]),c.__metadata("design:returntype",Promise)],I.prototype,"BurnFrom",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],I.prototype,"ClientAccountBalance",null),c.__decorate([i.Transaction(!1),c.__metadata("design:type",Function),c.__metadata("design:paramtypes",[i.Context]),c.__metadata("design:returntype",Promise)],I.prototype,"ClientAccountID",null);const F=[I],M="##VERSION##",q="##PACKAGE##";o.Metadata.registerLibrary(q,M),t.ContractLogger=f,t.FabricContractAdapter=A,t.FabricContractContext=l,t.FabricContractPaginator=_,t.FabricContractRepository=u,t.FabricContractRepositoryObservableHandler=d,t.FabricCrudContract=k,t.FabricStatement=g,t.PACKAGE_NAME=q,t.SerializedCrudContract=N,t.VERSION=M,t.contracts=F,t.createdByOnFabricCreateUpdate=E,t.pkFabricOnCreate=async function(t,e,a,i){if(!e.type||i[a])return;let o;e.name||(e.name=r.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,a,{enumerable:!0,writable:!1,configurable:!0,value:s})}},"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
|
+
this._overrides = Object.assign({}, super["_overrides"], {
|
|
67
|
+
ignoreValidation: false,
|
|
68
|
+
ignoreHandlers: false,
|
|
69
|
+
allowRawStatements: true,
|
|
70
|
+
forcePrepareSimpleQueries: false,
|
|
71
|
+
forcePrepareComplexQueries: false
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async paginateBy(key, order, ref = {
|
|
75
|
+
offset: 1,
|
|
76
|
+
limit: 10
|
|
77
|
+
}, ...args) {
|
|
78
|
+
let {offset: offset, bookmark: bookmark, limit: limit} = ref;
|
|
79
|
+
if (!offset && !bookmark) throw new core.QueryError(`PaginateBy needs a page or a bookmark`);
|
|
80
|
+
const contextArgs = await core.Context.args(core.PreparedStatementKeys.PAGE_BY, this.class, args, this.adapter, this._overrides || {});
|
|
81
|
+
const {log: log, ctxArgs: ctxArgs} = this.logCtx(contextArgs.args, this.paginateBy);
|
|
82
|
+
log.verbose(`paginating ${decoratorValidation.Model.tableName(this.class)} with page size ${limit}`);
|
|
83
|
+
let paginator;
|
|
84
|
+
if (bookmark) {
|
|
85
|
+
paginator = await this.override({
|
|
86
|
+
forcePrepareComplexQueries: false,
|
|
87
|
+
forcePrepareSimpleQueries: false
|
|
88
|
+
}).select().where(this.attr(decoratorValidation.Model.pk(this.class)).gt(bookmark)).orderBy([ key, order ]).paginate(limit, ...ctxArgs);
|
|
89
|
+
offset = 1;
|
|
90
|
+
} else if (offset) {
|
|
91
|
+
paginator = await this.override({
|
|
92
|
+
forcePrepareComplexQueries: false,
|
|
93
|
+
forcePrepareSimpleQueries: false
|
|
94
|
+
}).select().orderBy([ key, order ]).paginate(limit, ...ctxArgs);
|
|
95
|
+
} else {
|
|
96
|
+
throw new core.QueryError(`PaginateBy needs a page or a bookmark`);
|
|
97
|
+
}
|
|
98
|
+
const paged = await paginator.page(offset, ...ctxArgs);
|
|
99
|
+
return paginator.serialize(paged);
|
|
100
|
+
}
|
|
101
|
+
async statement(name, ...args) {
|
|
102
|
+
if (!core.Repository.statements(this, name)) throw new core.QueryError(`Invalid prepared statement requested ${name}`);
|
|
103
|
+
const contextArgs = await core.Context.args(core.PersistenceKeys.STATEMENT, this.class, args, this.adapter, this._overrides || {});
|
|
104
|
+
if (contextArgs.context.logger) {
|
|
105
|
+
contextArgs.context.logger.info(`Repo statement: ${name} + ${args}`);
|
|
106
|
+
}
|
|
107
|
+
const {log: log, ctxArgs: ctxArgs} = this.logCtx(contextArgs.args, this.statement);
|
|
108
|
+
log.verbose(`Executing prepared statement ${name} with args ${ctxArgs}`);
|
|
109
|
+
let result;
|
|
110
|
+
try {
|
|
111
|
+
result = await this[name](...ctxArgs);
|
|
112
|
+
} catch (e) {
|
|
113
|
+
if (e instanceof dbDecorators.BaseError) throw e;
|
|
114
|
+
throw new dbDecorators.InternalError(`Failed to execute prepared statement ${name} with args ${ctxArgs}: ${e}`);
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
ObserverHandler() {
|
|
119
|
+
return new FabricContractRepositoryObservableHandler;
|
|
120
|
+
}
|
|
121
|
+
async updateObservers(table, event, id, ...args) {
|
|
122
|
+
if (!this.trackedEvents || this.trackedEvents.indexOf(event) !== -1) return await super.updateObservers(table, event, id, ...args);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
class FabricStatement extends forCouchdb.CouchDBStatement {
|
|
126
|
+
constructor(adapter) {
|
|
127
|
+
super(adapter);
|
|
128
|
+
}
|
|
129
|
+
async raw(rawInput, ...args) {
|
|
130
|
+
const {ctx: ctx} = this.logCtx(args, this.raw);
|
|
131
|
+
const results = await this.adapter.raw(rawInput, true, ctx);
|
|
132
|
+
const pkAttr = decoratorValidation.Model.pk(this.fromSelector);
|
|
133
|
+
const type = decoration.Metadata.get(this.fromSelector, decoration.Metadata.key(dbDecorators.DBKeys.ID, pkAttr))?.type;
|
|
134
|
+
if (!this.selectSelector) return results.map(r => this.processRecord(r, pkAttr, type, ctx));
|
|
135
|
+
return results;
|
|
136
|
+
}
|
|
137
|
+
build() {
|
|
138
|
+
const selectors = {};
|
|
139
|
+
selectors[forCouchdb.CouchDBKeys.TABLE] = {};
|
|
140
|
+
selectors[forCouchdb.CouchDBKeys.TABLE] = decoratorValidation.Model.tableName(this.fromSelector);
|
|
141
|
+
const query = {
|
|
142
|
+
selector: selectors
|
|
143
|
+
};
|
|
144
|
+
if (this.selectSelector) query.fields = this.selectSelector;
|
|
145
|
+
if (this.whereCondition) {
|
|
146
|
+
const condition = this.parseCondition(core.Condition.and(this.whereCondition, core.Condition.attribute(forCouchdb.CouchDBKeys.TABLE).eq(query.selector[forCouchdb.CouchDBKeys.TABLE]))).selector;
|
|
147
|
+
const selectorKeys = Object.keys(condition);
|
|
148
|
+
if (selectorKeys.length === 1 && Object.values(forCouchdb.CouchDBGroupOperator).indexOf(selectorKeys[0]) !== -1) switch (selectorKeys[0]) {
|
|
149
|
+
case forCouchdb.CouchDBGroupOperator.AND:
|
|
150
|
+
condition[forCouchdb.CouchDBGroupOperator.AND] = [ ...Object.values(condition[forCouchdb.CouchDBGroupOperator.AND]).reduce((accum, val) => {
|
|
151
|
+
const keys = Object.keys(val);
|
|
152
|
+
if (keys.length !== 1) throw new Error("Too many keys in query selector. should be one");
|
|
153
|
+
const k = keys[0];
|
|
154
|
+
if (k === forCouchdb.CouchDBGroupOperator.AND) accum.push(...val[k]); else accum.push(val);
|
|
155
|
+
return accum;
|
|
156
|
+
}, []) ];
|
|
157
|
+
query.selector = condition;
|
|
158
|
+
break;
|
|
159
|
+
|
|
160
|
+
case forCouchdb.CouchDBGroupOperator.OR:
|
|
161
|
+
{
|
|
162
|
+
const s = {};
|
|
163
|
+
s[forCouchdb.CouchDBGroupOperator.AND] = [ condition, ...Object.entries(query.selector).map(([key, val]) => {
|
|
164
|
+
const result = {};
|
|
165
|
+
result[key] = val;
|
|
166
|
+
return result;
|
|
167
|
+
}) ];
|
|
168
|
+
query.selector = s;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
default:
|
|
173
|
+
throw new Error("This should be impossible");
|
|
174
|
+
} else {
|
|
175
|
+
Object.entries(condition).forEach(([key, val]) => {
|
|
176
|
+
if (query.selector[key]) console.warn(`A ${key} query param is about to be overridden: ${query.selector[key]} by ${val}`);
|
|
177
|
+
query.selector[key] = val;
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (this.orderBySelector) {
|
|
182
|
+
query.sort = query.sort || [];
|
|
183
|
+
query.selector = query.selector || {};
|
|
184
|
+
const [selector, value] = this.orderBySelector;
|
|
185
|
+
const rec = {};
|
|
186
|
+
rec[selector] = value;
|
|
187
|
+
query.sort.push(rec);
|
|
188
|
+
if (!query.selector[selector]) {
|
|
189
|
+
query.selector[selector] = {};
|
|
190
|
+
query.selector[selector][forCouchdb.CouchDBOperator.BIGGER] = null;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (this.limitSelector) query.limit = this.limitSelector;
|
|
194
|
+
if (this.offsetSelector) query.skip = this.offsetSelector;
|
|
195
|
+
return query;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
class FabricContractSequence extends core.Sequence {
|
|
199
|
+
constructor(options, adapter) {
|
|
200
|
+
super(options, adapter);
|
|
201
|
+
}
|
|
202
|
+
async current(...args) {
|
|
203
|
+
const contextArgs = await core.Context.args(dbDecorators.OperationKeys.READ, core.SequenceModel, args, this.adapter);
|
|
204
|
+
const ctx = contextArgs.context;
|
|
205
|
+
const {name: name, startWith: startWith} = this.options;
|
|
206
|
+
try {
|
|
207
|
+
const sequence = await this.repo.read(name, ctx);
|
|
208
|
+
return this.parse(sequence.current);
|
|
209
|
+
} catch (e) {
|
|
210
|
+
const log = ctx.logger.for(this.current);
|
|
211
|
+
if (e instanceof dbDecorators.NotFoundError) {
|
|
212
|
+
let cachedCurrent;
|
|
213
|
+
try {
|
|
214
|
+
log.debug(`Trying to resolve current sequence ${name} value from context`);
|
|
215
|
+
cachedCurrent = ctx.get(name);
|
|
216
|
+
log.debug(`Retrieved cached current value for sequence ${name}: ${cachedCurrent}`);
|
|
217
|
+
} catch (e) {
|
|
218
|
+
log.info(`No cached value for sequence ${name} in context`);
|
|
219
|
+
cachedCurrent = startWith;
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
return this.parse(cachedCurrent);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
throw new dbDecorators.InternalError(`Failed to parse initial value for sequence ${startWith}: ${e}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
throw new dbDecorators.InternalError(`Failed to retrieve current value for sequence ${name}: ${e}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
async increment(count, ctx) {
|
|
231
|
+
const log = ctx.logger.for(this.increment);
|
|
232
|
+
const {type: type, incrementBy: incrementBy, name: name} = this.options;
|
|
233
|
+
if (!name) throw new dbDecorators.InternalError("Sequence name is required");
|
|
234
|
+
log.info(`Obtaining sequence lock for sequence ${name}`);
|
|
235
|
+
return FabricContractSequence.lock.execute(async () => {
|
|
236
|
+
const toIncrementBy = count || incrementBy;
|
|
237
|
+
if (toIncrementBy % incrementBy !== 0) throw new dbDecorators.InternalError(`Value to increment does not consider the incrementBy setting: ${incrementBy}`);
|
|
238
|
+
const typeName = typeof type === "function" && type?.name ? type.name : type;
|
|
239
|
+
const currentValue = await this.current(ctx);
|
|
240
|
+
async function returnAndCache(res) {
|
|
241
|
+
if (res instanceof Promise) res = await res;
|
|
242
|
+
ctx.logger.for(returnAndCache).info(`Storing new ${name} seq value in cache: ${res.current}`);
|
|
243
|
+
ctx.cache.put(name, res.current);
|
|
244
|
+
return res;
|
|
245
|
+
}
|
|
246
|
+
const performUpsert = async next => {
|
|
247
|
+
try {
|
|
248
|
+
return await returnAndCache(this.repo.update(new core.SequenceModel({
|
|
249
|
+
id: name,
|
|
250
|
+
current: next
|
|
251
|
+
}), ctx));
|
|
252
|
+
} catch (e) {
|
|
253
|
+
if (e instanceof dbDecorators.NotFoundError) {
|
|
254
|
+
log.debug(`Sequence create ${name} current=${currentValue} next=${next}`);
|
|
255
|
+
return returnAndCache(this.repo.create(new core.SequenceModel({
|
|
256
|
+
id: name,
|
|
257
|
+
current: next
|
|
258
|
+
}), ctx));
|
|
259
|
+
}
|
|
260
|
+
throw e;
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
const incrementSerial = base => {
|
|
264
|
+
switch (typeName) {
|
|
265
|
+
case Number.name:
|
|
266
|
+
return this.parse(base) + toIncrementBy;
|
|
267
|
+
|
|
268
|
+
case BigInt.name:
|
|
269
|
+
return this.parse(base) + BigInt(toIncrementBy);
|
|
270
|
+
|
|
271
|
+
case String.name:
|
|
272
|
+
return this.parse(base);
|
|
273
|
+
|
|
274
|
+
case "serial":
|
|
275
|
+
return core.Serial.instance.generate(base);
|
|
276
|
+
|
|
277
|
+
default:
|
|
278
|
+
throw new dbDecorators.InternalError("Should never happen");
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
if (typeName === "uuid") {
|
|
282
|
+
while (true) {
|
|
283
|
+
const next = core.UUID.instance.generate(currentValue);
|
|
284
|
+
try {
|
|
285
|
+
const result = await performUpsert(next);
|
|
286
|
+
log.debug(`Sequence uuid increment ${name} current=${currentValue} next=${next}`);
|
|
287
|
+
return result.current;
|
|
288
|
+
} catch (e) {
|
|
289
|
+
if (e instanceof dbDecorators.ConflictError) continue;
|
|
290
|
+
throw e;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const next = incrementSerial(currentValue);
|
|
295
|
+
const seq = await performUpsert(next);
|
|
296
|
+
log.debug(`Sequence.increment ${name} current=${currentValue} next=${next}`);
|
|
297
|
+
return seq.current;
|
|
298
|
+
}, name);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
var FabricModelKeys;
|
|
302
|
+
(function(FabricModelKeys) {
|
|
303
|
+
FabricModelKeys["PRIVATE"] = "private";
|
|
304
|
+
FabricModelKeys["SHARED"] = "shared";
|
|
305
|
+
FabricModelKeys["FABRIC"] = "fabric.";
|
|
306
|
+
FabricModelKeys["OWNEDBY"] = "owned-by";
|
|
307
|
+
FabricModelKeys["TRANSACTION_ID"] = "transaction-id";
|
|
308
|
+
})(FabricModelKeys || (FabricModelKeys = {}));
|
|
309
|
+
var IdentityType;
|
|
310
|
+
(function(IdentityType) {
|
|
311
|
+
IdentityType["X509"] = "X.509";
|
|
312
|
+
})(IdentityType || (IdentityType = {}));
|
|
313
|
+
const FabricFlavour = "hlf-fabric";
|
|
314
|
+
class SimpleDeterministicSerializer extends decoratorValidation.JSONSerializer {
|
|
315
|
+
constructor() {
|
|
316
|
+
super();
|
|
317
|
+
}
|
|
318
|
+
deserialize(str, tableName) {
|
|
319
|
+
const deserialization = JSON.parse(str);
|
|
320
|
+
return deserialization;
|
|
321
|
+
}
|
|
322
|
+
serialize(model, putAnchor = true) {
|
|
323
|
+
const stringify = require("json-stringify-deterministic");
|
|
324
|
+
const sortKeysRecursive = require("sort-keys-recursive");
|
|
325
|
+
const preSerialization = this.preSerialize(model, putAnchor);
|
|
326
|
+
return stringify(sortKeysRecursive(preSerialization));
|
|
327
|
+
}
|
|
328
|
+
preSerialize(model, putAnchor = true) {
|
|
329
|
+
const toSerialize = Object.assign({}, model);
|
|
330
|
+
let metadata;
|
|
331
|
+
try {
|
|
332
|
+
metadata = decoration.Metadata.modelName(model.constructor);
|
|
333
|
+
} catch (error) {
|
|
334
|
+
metadata = undefined;
|
|
335
|
+
}
|
|
336
|
+
if (putAnchor) toSerialize[decoratorValidation.ModelKeys.ANCHOR] = metadata || model.constructor.name;
|
|
337
|
+
function preSerialize(obj) {
|
|
338
|
+
if (typeof obj !== "object") return obj;
|
|
339
|
+
if (Array.isArray(obj)) return obj.map(preSerialize);
|
|
340
|
+
return this.preSerialize(obj);
|
|
341
|
+
}
|
|
342
|
+
decoratorValidation.Model.relations(model).forEach(r => {
|
|
343
|
+
toSerialize[r] = preSerialize.call(this, toSerialize[r]);
|
|
344
|
+
});
|
|
345
|
+
return toSerialize;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
class ContractLogger extends logging.MiniLogger {
|
|
349
|
+
constructor(context, conf, ctx) {
|
|
350
|
+
super(context, conf);
|
|
351
|
+
if (!ctx) {
|
|
352
|
+
this.logger = new logging.MiniLogger(context, conf);
|
|
353
|
+
} else {
|
|
354
|
+
this.logger = ctx.logging.getLogger(context);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
log(level, msg, stack) {
|
|
358
|
+
if (logging.NumericLogLevels[this.config("level")] < logging.NumericLogLevels[level]) return;
|
|
359
|
+
let method;
|
|
360
|
+
switch (level) {
|
|
361
|
+
case logging.LogLevel.info:
|
|
362
|
+
method = this.logger.info;
|
|
363
|
+
break;
|
|
364
|
+
|
|
365
|
+
case logging.LogLevel.verbose:
|
|
366
|
+
method = this.logger.verbose;
|
|
367
|
+
break;
|
|
368
|
+
|
|
369
|
+
case logging.LogLevel.debug:
|
|
370
|
+
method = this.logger.debug;
|
|
371
|
+
break;
|
|
372
|
+
|
|
373
|
+
case logging.LogLevel.error:
|
|
374
|
+
method = this.logger.error;
|
|
375
|
+
break;
|
|
376
|
+
|
|
377
|
+
case logging.LogLevel.warn:
|
|
378
|
+
method = this.logger.warn;
|
|
379
|
+
break;
|
|
380
|
+
|
|
381
|
+
case logging.LogLevel.silly:
|
|
382
|
+
method = this.logger.silly;
|
|
383
|
+
break;
|
|
384
|
+
|
|
385
|
+
default:
|
|
386
|
+
throw new dbDecorators.InternalError("Invalid log level");
|
|
387
|
+
}
|
|
388
|
+
method.call(this.logger, this.createLog(level, msg, stack));
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
const factory = (object, config, ctx) => new ContractLogger(object || ContractLogger.name, config || {}, ctx);
|
|
392
|
+
logging.Logging.setFactory(factory);
|
|
393
|
+
class FabricContractPaginator extends forCouchdb.CouchDBPaginator {
|
|
394
|
+
constructor(adapter, query, size, clazz) {
|
|
395
|
+
super(adapter, query, size, clazz);
|
|
396
|
+
}
|
|
397
|
+
prepare(rawStatement) {
|
|
398
|
+
const query = Object.assign({}, rawStatement);
|
|
399
|
+
if (query.limit) this.limit = query.limit;
|
|
400
|
+
query.limit = this.size;
|
|
401
|
+
return query;
|
|
402
|
+
}
|
|
403
|
+
async page(page = 1, ...args) {
|
|
404
|
+
const {ctxArgs: ctxArgs, ctx: ctx} = this.adapter["logCtx"](args, this.page);
|
|
405
|
+
if (this.isPreparedStatement()) return this.pagePrepared(page, ...ctxArgs);
|
|
406
|
+
const statement = Object.assign({}, this.statement);
|
|
407
|
+
if (!this._recordCount || !this._totalPages) {
|
|
408
|
+
this._totalPages = this._recordCount = 0;
|
|
409
|
+
const results = await this.adapter.raw({
|
|
410
|
+
...statement,
|
|
411
|
+
limit: undefined
|
|
412
|
+
}, true, ctx) || [];
|
|
413
|
+
this._recordCount = results.length;
|
|
414
|
+
if (this._recordCount > 0) {
|
|
415
|
+
const size = statement?.limit || this.size;
|
|
416
|
+
this._totalPages = Math.ceil(this._recordCount / size);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
this.validatePage(page);
|
|
420
|
+
if (page !== 1) {
|
|
421
|
+
if (!this._bookmark) throw new core.PagingError("No bookmark. Did you start in the first page?");
|
|
422
|
+
statement["bookmark"] = this._bookmark;
|
|
423
|
+
}
|
|
424
|
+
const docs = await this.adapter.raw(statement, false, ctx);
|
|
425
|
+
if (!this.clazz) throw new core.PagingError("No statement target defined");
|
|
426
|
+
const id = decoratorValidation.Model.pk(this.clazz);
|
|
427
|
+
const type = decoration.Metadata.get(this.clazz, decoration.Metadata.key(dbDecorators.DBKeys.ID, id))?.type;
|
|
428
|
+
const results = statement.fields && statement.fields.length ? docs : docs.map(d => this.adapter.revert(d, this.clazz, core.Sequence.parseValue(type, d[id]), undefined, ctx));
|
|
429
|
+
const direction = statement.sort?.[0] || core.OrderDirection.DSC;
|
|
430
|
+
this._bookmark = results[direction === core.OrderDirection.ASC ? results.length - 1 : 0][id];
|
|
431
|
+
this._currentPage = page;
|
|
432
|
+
return results;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
class OverflowError extends dbDecorators.InternalError {
|
|
436
|
+
constructor(msg) {
|
|
437
|
+
super(msg, OverflowError.name);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
class BalanceError extends dbDecorators.InternalError {
|
|
441
|
+
constructor(msg) {
|
|
442
|
+
super(msg, BalanceError.name);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
class AllowanceError extends dbDecorators.InternalError {
|
|
446
|
+
constructor(msg) {
|
|
447
|
+
super(msg, AllowanceError.name);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
class RegistrationError extends core.AuthorizationError {
|
|
451
|
+
constructor(msg) {
|
|
452
|
+
super(msg, RegistrationError.name);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
class MissingContextError extends dbDecorators.InternalError {
|
|
456
|
+
constructor(msg) {
|
|
457
|
+
super(msg, MissingContextError.name, 500);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
class UnauthorizedPrivateDataAccess extends dbDecorators.BaseError {
|
|
461
|
+
constructor(msg = "MISSING_PRIVATE_DATA_ERROR_MESSAGE") {
|
|
462
|
+
super(UnauthorizedPrivateDataAccess.name, msg, 403);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
class NotInitializedError extends dbDecorators.BaseError {
|
|
466
|
+
constructor(msg) {
|
|
467
|
+
super(NotInitializedError.name, msg, 409);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
class MissingPKCSS11Lib extends dbDecorators.InternalError {
|
|
471
|
+
constructor(msg) {
|
|
472
|
+
super(msg, MissingPKCSS11Lib.name, 500);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
class EndorsementError extends dbDecorators.InternalError {
|
|
476
|
+
constructor(message) {
|
|
477
|
+
super(message, EndorsementError.name, 500);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
class MvccReadConflictError extends dbDecorators.InternalError {
|
|
481
|
+
constructor(message) {
|
|
482
|
+
super(message, MvccReadConflictError.name, 500);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
class PhantomReadConflictError extends dbDecorators.InternalError {
|
|
486
|
+
constructor(message) {
|
|
487
|
+
super(message, PhantomReadConflictError.name, 500);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
class EndorsementPolicyError extends dbDecorators.InternalError {
|
|
491
|
+
constructor(message) {
|
|
492
|
+
super(message, EndorsementPolicyError.name, 500);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
async function createdByOnFabricCreateUpdate(context, data, key, model) {
|
|
496
|
+
try {
|
|
497
|
+
const user = context.get("identity");
|
|
498
|
+
model[key] = user.getID();
|
|
499
|
+
} catch (e) {
|
|
500
|
+
throw new core.UnsupportedError("No User found in context. Please provide a user in the context");
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
async function pkFabricOnCreate(context, data, key, model) {
|
|
504
|
+
if (!data.type || model[key]) {
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
const setPrimaryKeyValue = function(target, propertyKey, value) {
|
|
508
|
+
Object.defineProperty(target, propertyKey, {
|
|
509
|
+
enumerable: true,
|
|
510
|
+
writable: false,
|
|
511
|
+
configurable: true,
|
|
512
|
+
value: value
|
|
513
|
+
});
|
|
514
|
+
};
|
|
515
|
+
if (!data.name) data.name = decoratorValidation.Model.sequenceName(model, "pk");
|
|
516
|
+
let sequence;
|
|
517
|
+
try {
|
|
518
|
+
sequence = await this.adapter.Sequence(data);
|
|
519
|
+
} catch (e) {
|
|
520
|
+
throw new dbDecorators.InternalError(`Failed to instantiate Sequence ${data.name}: ${e}`);
|
|
521
|
+
}
|
|
522
|
+
const next = await sequence.next(context);
|
|
523
|
+
setPrimaryKeyValue(model, key, next);
|
|
524
|
+
}
|
|
525
|
+
class FabricContractAdapter extends forCouchdb.CouchDBAdapter {
|
|
526
|
+
getClient() {
|
|
527
|
+
throw new core.UnsupportedError("Client is not supported in Fabric contracts");
|
|
528
|
+
}
|
|
529
|
+
static {
|
|
530
|
+
this.textDecoder = new TextDecoder("utf8");
|
|
531
|
+
}
|
|
532
|
+
static {
|
|
533
|
+
this.serializer = new SimpleDeterministicSerializer;
|
|
534
|
+
}
|
|
535
|
+
repository() {
|
|
536
|
+
return FabricContractRepository;
|
|
537
|
+
}
|
|
538
|
+
Paginator(query, size, clazz) {
|
|
539
|
+
return new FabricContractPaginator(this, query, size, clazz);
|
|
540
|
+
}
|
|
541
|
+
async Sequence(options) {
|
|
542
|
+
return new FabricContractSequence(options, this);
|
|
543
|
+
}
|
|
544
|
+
constructor(scope, alias) {
|
|
545
|
+
super(scope, FabricFlavour, alias);
|
|
546
|
+
this.Context = FabricContractContext;
|
|
547
|
+
}
|
|
548
|
+
for(config, ...args) {
|
|
549
|
+
return super.for(config, ...args);
|
|
550
|
+
}
|
|
551
|
+
async create(clazz, id, model, ...args) {
|
|
552
|
+
const {ctx: ctx, log: log} = this.logCtx(args, this.create);
|
|
553
|
+
log.info(`in ADAPTER create with args ${args}`);
|
|
554
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
555
|
+
try {
|
|
556
|
+
log.info(`adding entry to ${tableName} table with pk ${id}`);
|
|
557
|
+
const composedKey = ctx.stub.createCompositeKey(tableName, [ String(id) ]);
|
|
558
|
+
model = await this.putState(composedKey, model, ctx);
|
|
559
|
+
} catch (e) {
|
|
560
|
+
throw this.parseError(e);
|
|
561
|
+
}
|
|
562
|
+
return model;
|
|
563
|
+
}
|
|
564
|
+
async read(clazz, id, ...args) {
|
|
565
|
+
const {ctx: ctx, log: log} = this.logCtx(args, this.read);
|
|
566
|
+
log.info(`in ADAPTER read with args ${args}`);
|
|
567
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
568
|
+
let model;
|
|
569
|
+
try {
|
|
570
|
+
const composedKey = ctx.stub.createCompositeKey(tableName, [ String(id) ]);
|
|
571
|
+
model = await this.readState(composedKey, ctx);
|
|
572
|
+
} catch (e) {
|
|
573
|
+
throw this.parseError(e);
|
|
574
|
+
}
|
|
575
|
+
return model;
|
|
576
|
+
}
|
|
577
|
+
async update(clazz, id, model, ...args) {
|
|
578
|
+
const {ctx: ctx, log: log} = this.logCtx(args, this.update);
|
|
579
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
580
|
+
try {
|
|
581
|
+
log.verbose(`updating entry to ${tableName} table with pk ${id}`);
|
|
582
|
+
const composedKey = ctx.stub.createCompositeKey(tableName, [ String(id) ]);
|
|
583
|
+
model = await this.putState(composedKey, model, ctx);
|
|
584
|
+
} catch (e) {
|
|
585
|
+
throw this.parseError(e);
|
|
586
|
+
}
|
|
587
|
+
return model;
|
|
588
|
+
}
|
|
589
|
+
async delete(clazz, id, ...args) {
|
|
590
|
+
const {ctx: ctx, log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.delete);
|
|
591
|
+
const tableName = decoratorValidation.Model.tableName(clazz);
|
|
592
|
+
let model;
|
|
593
|
+
try {
|
|
594
|
+
const composedKey = ctx.stub.createCompositeKey(tableName, [ String(id) ]);
|
|
595
|
+
model = await this.read(clazz, id, ...ctxArgs);
|
|
596
|
+
log.verbose(`deleting entry with pk ${id} from ${tableName} table`);
|
|
597
|
+
await this.deleteState(composedKey, ctx);
|
|
598
|
+
} catch (e) {
|
|
599
|
+
throw this.parseError(e);
|
|
600
|
+
}
|
|
601
|
+
return model;
|
|
602
|
+
}
|
|
603
|
+
async deleteState(id, context) {
|
|
604
|
+
const {ctx: ctx} = this.logCtx([ context ], this.deleteState);
|
|
605
|
+
await ctx.stub.deleteState(id);
|
|
606
|
+
}
|
|
607
|
+
forPrivate(collection) {
|
|
608
|
+
const toOverride = [ this.putState, this.readState, this.deleteState, this.queryResult, this.queryResultPaginated ].map(fn => fn.name);
|
|
609
|
+
return new Proxy(this, {
|
|
610
|
+
get(target, prop, receiver) {
|
|
611
|
+
if (!toOverride.includes(prop)) return Reflect.get(target, prop, receiver);
|
|
612
|
+
return new Proxy(target[prop], {
|
|
613
|
+
async apply(fn, thisArg, argsList) {
|
|
614
|
+
switch (prop) {
|
|
615
|
+
case "putState":
|
|
616
|
+
{
|
|
617
|
+
const [stub, id, model] = argsList;
|
|
618
|
+
await stub.putPrivateData(collection, id.toString(), model);
|
|
619
|
+
return model;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
case "deleteState":
|
|
623
|
+
{
|
|
624
|
+
const [stub, id] = argsList;
|
|
625
|
+
return stub.deletePrivateData(collection, id);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
case "readState":
|
|
629
|
+
{
|
|
630
|
+
const [stub, id] = argsList;
|
|
631
|
+
return stub.getPrivateData(collection, id);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
case "queryResult":
|
|
635
|
+
{
|
|
636
|
+
const [stub, rawInput] = argsList;
|
|
637
|
+
return stub.getPrivateDataQueryResult(collection, rawInput);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
case "queryResultPaginated":
|
|
641
|
+
{
|
|
642
|
+
const [stub, rawInput, limit, skip] = argsList;
|
|
643
|
+
const iterator = await stub.getPrivateDataQueryResult(collection, rawInput);
|
|
644
|
+
const results = [];
|
|
645
|
+
let count = 0;
|
|
646
|
+
let reachedBookmark = skip ? false : true;
|
|
647
|
+
let lastKey = null;
|
|
648
|
+
while (true) {
|
|
649
|
+
const res = await iterator.next();
|
|
650
|
+
if (res.value && res.value.value.toString()) {
|
|
651
|
+
const recordKey = res.value.key;
|
|
652
|
+
const recordValue = res.value.value.toString("utf8");
|
|
653
|
+
if (!reachedBookmark) {
|
|
654
|
+
if (recordKey === skip?.toString()) {
|
|
655
|
+
reachedBookmark = true;
|
|
656
|
+
}
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
results.push({
|
|
660
|
+
Key: recordKey,
|
|
661
|
+
Record: JSON.parse(recordValue)
|
|
662
|
+
});
|
|
663
|
+
lastKey = recordKey;
|
|
664
|
+
count++;
|
|
665
|
+
if (count >= limit) {
|
|
666
|
+
await iterator.close();
|
|
667
|
+
return {
|
|
668
|
+
iterator: results,
|
|
669
|
+
metadata: {
|
|
670
|
+
fetchedRecordsCount: results.length,
|
|
671
|
+
bookmark: lastKey
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (res.done) {
|
|
677
|
+
await iterator.close();
|
|
678
|
+
return {
|
|
679
|
+
iterator: results,
|
|
680
|
+
metadata: {
|
|
681
|
+
fetchedRecordsCount: results.length,
|
|
682
|
+
bookmark: ""
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
default:
|
|
690
|
+
throw new dbDecorators.InternalError(`Unsupported method override ${String(prop)}`);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
async putState(id, model, ctx) {
|
|
698
|
+
let data;
|
|
699
|
+
const {log: log} = this.logCtx([ ctx ], this.putState);
|
|
700
|
+
try {
|
|
701
|
+
data = Buffer.from(FabricContractAdapter.serializer.serialize(model, false));
|
|
702
|
+
} catch (e) {
|
|
703
|
+
throw new dbDecorators.SerializationError(`Failed to serialize record with id ${id}: ${e}`);
|
|
704
|
+
}
|
|
705
|
+
const collection = ctx.get("segregated");
|
|
706
|
+
if (collection) await ctx.stub.putPrivateData(collection, id.toString(), data); else await ctx.stub.putState(id.toString(), data);
|
|
707
|
+
log.silly(`state stored${collection ? ` in ${collection} collection` : ""} under id ${id}`);
|
|
708
|
+
return model;
|
|
709
|
+
}
|
|
710
|
+
async readState(id, ctx) {
|
|
711
|
+
let result;
|
|
712
|
+
const {log: log} = this.logCtx([ ctx ], this.readState);
|
|
713
|
+
let res;
|
|
714
|
+
const collection = ctx.get("segregated");
|
|
715
|
+
if (collection) res = (await ctx.stub.getPrivateData(collection, id.toString())).toString(); else res = (await ctx.stub.getState(id.toString())).toString();
|
|
716
|
+
if (!res) throw new dbDecorators.NotFoundError(`Record with id ${id}${collection ? ` in ${collection} collection` : ""} not found`);
|
|
717
|
+
log.silly(`state retrieved from${collection ? ` ${collection} collection` : ""} under id ${id}`);
|
|
718
|
+
try {
|
|
719
|
+
result = FabricContractAdapter.serializer.deserialize(res.toString());
|
|
720
|
+
} catch (e) {
|
|
721
|
+
throw new dbDecorators.SerializationError(`Failed to parse record: ${e}`);
|
|
722
|
+
}
|
|
723
|
+
return result;
|
|
724
|
+
}
|
|
725
|
+
async queryResult(stub, rawInput, ...args) {
|
|
726
|
+
const {ctx: ctx} = this.logCtx(args, this.readState);
|
|
727
|
+
let res;
|
|
728
|
+
const collection = ctx.get("segregated");
|
|
729
|
+
if (collection) res = await ctx.stub.getPrivateDataQueryResult(collection, JSON.stringify(rawInput)); else res = await stub.getQueryResult(JSON.stringify(rawInput));
|
|
730
|
+
return res;
|
|
731
|
+
}
|
|
732
|
+
async queryResultPaginated(stub, rawInput, limit = 250, skip, ...args) {
|
|
733
|
+
const {ctx: ctx} = this.logCtx(args, this.readState);
|
|
734
|
+
let res;
|
|
735
|
+
const collection = ctx.get("segregated");
|
|
736
|
+
if (collection) {
|
|
737
|
+
rawInput.selector = {
|
|
738
|
+
...rawInput.selector,
|
|
739
|
+
_id: skip ? {
|
|
740
|
+
$gt: skip.toString()
|
|
741
|
+
} : {
|
|
742
|
+
$gte: ""
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
const it = await stub.getPrivateDataQueryResult(collection, JSON.stringify(rawInput));
|
|
746
|
+
res = {
|
|
747
|
+
iterator: it,
|
|
748
|
+
metadata: {
|
|
749
|
+
fetchedRecordsCount: limit,
|
|
750
|
+
bookmark: ""
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
} else res = await stub.getQueryResultWithPagination(JSON.stringify(rawInput), limit, skip?.toString());
|
|
754
|
+
return res;
|
|
755
|
+
}
|
|
756
|
+
mergeModels(results) {
|
|
757
|
+
const extract = model => Object.entries(model).reduce((accum, [key, val]) => {
|
|
758
|
+
if (typeof val !== "undefined") accum[key] = val;
|
|
759
|
+
return accum;
|
|
760
|
+
}, {});
|
|
761
|
+
let finalModel = results.pop();
|
|
762
|
+
for (const res of results) {
|
|
763
|
+
finalModel = Object.assign({}, extract(finalModel), extract(res));
|
|
764
|
+
}
|
|
765
|
+
return finalModel;
|
|
766
|
+
}
|
|
767
|
+
decode(buffer) {
|
|
768
|
+
return FabricContractAdapter.textDecoder.decode(buffer);
|
|
769
|
+
}
|
|
770
|
+
async flags(operation, model, flags, ctx, ...args) {
|
|
771
|
+
const baseFlags = {
|
|
772
|
+
stub: ctx.stub,
|
|
773
|
+
segregated: false
|
|
774
|
+
};
|
|
775
|
+
if (ctx instanceof FabricContractContext) {
|
|
776
|
+
Object.assign(baseFlags, {
|
|
777
|
+
logger: ctx.logger,
|
|
778
|
+
identity: ctx.identity,
|
|
779
|
+
correlationId: ctx.stub.getTxID()
|
|
780
|
+
});
|
|
781
|
+
} else {
|
|
782
|
+
Object.assign(baseFlags, {
|
|
783
|
+
identity: ctx.clientIdentity,
|
|
784
|
+
logger: new ContractLogger(this, undefined, ctx),
|
|
785
|
+
correlationId: ctx.stub.getTxID()
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
flags = await super.flags(operation, model, baseFlags, ...args);
|
|
789
|
+
return flags;
|
|
790
|
+
}
|
|
791
|
+
index(models) {
|
|
792
|
+
return Promise.resolve(undefined);
|
|
793
|
+
}
|
|
794
|
+
async resultIterator(log, iterator, isHistory = false) {
|
|
795
|
+
const allResults = [];
|
|
796
|
+
let res = await iterator.next();
|
|
797
|
+
while (!res.done) {
|
|
798
|
+
if (res.value && res.value.value.toString()) {
|
|
799
|
+
let jsonRes = {};
|
|
800
|
+
log.debug(res.value.value.toString("utf8"));
|
|
801
|
+
if (isHistory) {
|
|
802
|
+
jsonRes.TxId = res.value.txId;
|
|
803
|
+
jsonRes.Timestamp = res.value.timestamp;
|
|
804
|
+
try {
|
|
805
|
+
jsonRes.Value = JSON.parse(res.value.value.toString("utf8"));
|
|
806
|
+
} catch (err) {
|
|
807
|
+
log.error(err);
|
|
808
|
+
jsonRes.Value = res.value.value.toString("utf8");
|
|
809
|
+
}
|
|
810
|
+
} else {
|
|
811
|
+
try {
|
|
812
|
+
jsonRes = JSON.parse(res.value.value.toString("utf8"));
|
|
813
|
+
} catch (err) {
|
|
814
|
+
log.error(err);
|
|
815
|
+
jsonRes = res.value.value.toString("utf8");
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
allResults.push(jsonRes);
|
|
819
|
+
}
|
|
820
|
+
res = await iterator.next();
|
|
821
|
+
}
|
|
822
|
+
log.debug(`Closing iterator after ${allResults.length} results`);
|
|
823
|
+
iterator.close();
|
|
824
|
+
return allResults;
|
|
825
|
+
}
|
|
826
|
+
async raw(rawInput, docsOnly = true, ...args) {
|
|
827
|
+
const {log: log, stub: stub, ctx: ctx} = this.logCtx(args, this.raw);
|
|
828
|
+
const {skip: skip, limit: limit} = rawInput;
|
|
829
|
+
let iterator;
|
|
830
|
+
if (limit || skip) {
|
|
831
|
+
delete rawInput["limit"];
|
|
832
|
+
delete rawInput["skip"];
|
|
833
|
+
log.debug(`Retrieving paginated iterator: limit: ${limit}/ skip: ${skip}`);
|
|
834
|
+
const response = await this.queryResultPaginated(stub, rawInput, limit || 250, skip?.toString(), ctx);
|
|
835
|
+
iterator = response.iterator;
|
|
836
|
+
} else {
|
|
837
|
+
log.debug("Retrieving iterator");
|
|
838
|
+
iterator = await this.queryResult(stub, rawInput, ctx);
|
|
839
|
+
}
|
|
840
|
+
log.debug("Iterator acquired");
|
|
841
|
+
const results = await this.resultIterator(log, iterator);
|
|
842
|
+
log.debug(`returning ${Array.isArray(results) ? results.length : 1} results`);
|
|
843
|
+
return results;
|
|
844
|
+
}
|
|
845
|
+
Statement() {
|
|
846
|
+
return new FabricStatement(this);
|
|
847
|
+
}
|
|
848
|
+
async createAll(tableName, id, model, ...args) {
|
|
849
|
+
if (id.length !== model.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
|
|
850
|
+
const {log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.createAll);
|
|
851
|
+
const tableLabel = decoratorValidation.Model.tableName(tableName);
|
|
852
|
+
log.debug(`Creating ${id.length} entries ${tableLabel} table`);
|
|
853
|
+
return Promise.all(id.map((i, count) => this.create(tableName, i, model[count], ...ctxArgs)));
|
|
854
|
+
}
|
|
855
|
+
async updateAll(tableName, id, model, ...args) {
|
|
856
|
+
if (id.length !== model.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
|
|
857
|
+
const {log: log, ctxArgs: ctxArgs} = this.logCtx(args, this.updateAll);
|
|
858
|
+
const tableLabel = decoratorValidation.Model.tableName(tableName);
|
|
859
|
+
log.debug(`Updating ${id.length} entries ${tableLabel} table`);
|
|
860
|
+
return Promise.all(id.map((i, count) => this.update(tableName, i, model[count], ...ctxArgs)));
|
|
861
|
+
}
|
|
862
|
+
prepare(model, ...args) {
|
|
863
|
+
const {log: log} = this.logCtx(args, this.prepare);
|
|
864
|
+
const tableName = decoratorValidation.Model.tableName(model.constructor);
|
|
865
|
+
const pk = decoratorValidation.Model.pk(model.constructor);
|
|
866
|
+
const split = decoratorValidation.Model.segregate(model);
|
|
867
|
+
const result = Object.entries(split.model).reduce((accum, [key, val]) => {
|
|
868
|
+
if (typeof val === "undefined") return accum;
|
|
869
|
+
const mappedProp = decoratorValidation.Model.columnName(model, key);
|
|
870
|
+
if (this.isReserved(mappedProp)) throw new dbDecorators.InternalError(`Property name ${mappedProp} is reserved`);
|
|
871
|
+
accum[mappedProp] = val;
|
|
872
|
+
return accum;
|
|
873
|
+
}, {});
|
|
874
|
+
log.silly(`Preparing record for ${tableName} table with pk ${model[pk]}`);
|
|
875
|
+
return {
|
|
876
|
+
record: result,
|
|
877
|
+
id: model[pk],
|
|
878
|
+
transient: split.transient
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
revert(obj, clazz, id, transient, ...args) {
|
|
882
|
+
const {log: log} = this.logCtx(args, this.revert);
|
|
883
|
+
const ob = {};
|
|
884
|
+
const pk = decoratorValidation.Model.pk(clazz);
|
|
885
|
+
ob[pk] = id;
|
|
886
|
+
const m = typeof clazz === "string" ? decoratorValidation.Model.build(ob, clazz) : new clazz(ob);
|
|
887
|
+
log.silly(`Rebuilding model ${m.constructor.name} id ${id}`);
|
|
888
|
+
const result = Object.keys(m).reduce((accum, key) => {
|
|
889
|
+
accum[key] = obj[decoratorValidation.Model.columnName(accum, key)];
|
|
890
|
+
return accum;
|
|
891
|
+
}, m);
|
|
892
|
+
if (transient) {
|
|
893
|
+
log.debug(`re-adding transient properties: ${Object.keys(transient).join(", ")}`);
|
|
894
|
+
Object.entries(transient).forEach(([key, val]) => {
|
|
895
|
+
if (key in result && result[key] !== undefined) throw new dbDecorators.InternalError(`Transient property ${key} already exists on model ${m.constructor.name}. should be impossible`);
|
|
896
|
+
result[key] = val;
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
return result;
|
|
900
|
+
}
|
|
901
|
+
createPrefix(tableName, id, model, ...args) {
|
|
902
|
+
const {ctxArgs: ctxArgs} = this.logCtx(args, this.createPrefix);
|
|
903
|
+
const record = {};
|
|
904
|
+
record[forCouchdb.CouchDBKeys.TABLE] = decoratorValidation.Model.tableName(tableName);
|
|
905
|
+
Object.assign(record, model);
|
|
906
|
+
return [ tableName, id, record, ...ctxArgs ];
|
|
907
|
+
}
|
|
908
|
+
updatePrefix(tableName, id, model, ...args) {
|
|
909
|
+
const {ctxArgs: ctxArgs} = this.logCtx(args, this.updatePrefix);
|
|
910
|
+
const record = {};
|
|
911
|
+
record[forCouchdb.CouchDBKeys.TABLE] = decoratorValidation.Model.tableName(tableName);
|
|
912
|
+
Object.assign(record, model);
|
|
913
|
+
return [ tableName, id, record, ...ctxArgs ];
|
|
914
|
+
}
|
|
915
|
+
createAllPrefix(tableName, ids, models, ...args) {
|
|
916
|
+
if (ids.length !== models.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
|
|
917
|
+
const ctx = args.pop();
|
|
918
|
+
const records = ids.map((id, count) => {
|
|
919
|
+
const record = {};
|
|
920
|
+
record[forCouchdb.CouchDBKeys.TABLE] = decoratorValidation.Model.tableName(tableName);
|
|
921
|
+
Object.assign(record, models[count]);
|
|
922
|
+
return record;
|
|
923
|
+
});
|
|
924
|
+
return [ tableName, ids, records, ctx ];
|
|
925
|
+
}
|
|
926
|
+
updateAllPrefix(tableName, ids, models, ...args) {
|
|
927
|
+
if (ids.length !== models.length) throw new dbDecorators.InternalError("Ids and models must have the same length");
|
|
928
|
+
const ctx = args.pop();
|
|
929
|
+
const records = ids.map((id, count) => {
|
|
930
|
+
const record = {};
|
|
931
|
+
record[forCouchdb.CouchDBKeys.TABLE] = decoratorValidation.Model.tableName(tableName);
|
|
932
|
+
Object.assign(record, models[count]);
|
|
933
|
+
return record;
|
|
934
|
+
});
|
|
935
|
+
return [ tableName, ids, records, ctx ];
|
|
936
|
+
}
|
|
937
|
+
parseError(err, reason) {
|
|
938
|
+
return FabricContractAdapter.parseError(reason || err);
|
|
939
|
+
}
|
|
940
|
+
logCtx(args, method) {
|
|
941
|
+
return FabricContractAdapter.logCtx.call(this, args, method);
|
|
942
|
+
}
|
|
943
|
+
static logCtx(args, method) {
|
|
944
|
+
if (args.length < 1) throw new dbDecorators.InternalError("No context provided");
|
|
945
|
+
const ctx = args.pop();
|
|
946
|
+
if (!(ctx instanceof core.Context)) throw new dbDecorators.InternalError("No context provided");
|
|
947
|
+
if (args.filter(a => a instanceof core.Context).length > 1) throw new Error("here");
|
|
948
|
+
const log = this ? ctx.logger.for(this).for(method) : ctx.logger.clear().for(this).for(method);
|
|
949
|
+
return {
|
|
950
|
+
ctx: ctx,
|
|
951
|
+
log: method ? log.for(method) : log,
|
|
952
|
+
stub: ctx.stub,
|
|
953
|
+
identity: ctx.identity,
|
|
954
|
+
ctxArgs: [ ...args, ctx ]
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
static parseError(err) {
|
|
958
|
+
const msg = typeof err === "string" ? err : err.message;
|
|
959
|
+
if (msg.includes(dbDecorators.NotFoundError.name)) return new dbDecorators.NotFoundError(err);
|
|
960
|
+
if (msg.includes(dbDecorators.ConflictError.name)) return new dbDecorators.ConflictError(err);
|
|
961
|
+
if (msg.includes(dbDecorators.BadRequestError.name)) return new dbDecorators.BadRequestError(err);
|
|
962
|
+
if (msg.includes(core.QueryError.name)) return new core.QueryError(err);
|
|
963
|
+
if (msg.includes(core.PagingError.name)) return new core.PagingError(err);
|
|
964
|
+
if (msg.includes(core.UnsupportedError.name)) return new core.UnsupportedError(err);
|
|
965
|
+
if (msg.includes(core.MigrationError.name)) return new core.MigrationError(err);
|
|
966
|
+
if (msg.includes(core.ObserverError.name)) return new core.ObserverError(err);
|
|
967
|
+
if (msg.includes(core.AuthorizationError.name)) return new core.AuthorizationError(err);
|
|
968
|
+
if (msg.includes(core.ForbiddenError.name)) return new core.ForbiddenError(err);
|
|
969
|
+
if (msg.includes(core.ConnectionError.name)) return new core.ConnectionError(err);
|
|
970
|
+
if (msg.includes(dbDecorators.SerializationError.name)) return new dbDecorators.SerializationError(err);
|
|
971
|
+
if (msg.includes("no ledger context")) return new MissingContextError(`No context found. this can be caused by debugging: ${msg}`);
|
|
972
|
+
return new dbDecorators.InternalError(err);
|
|
973
|
+
}
|
|
974
|
+
static decoration() {
|
|
975
|
+
super.decoration();
|
|
976
|
+
decoration.Decoration.flavouredAs(FabricFlavour).for(core.PersistenceKeys.CREATED_BY).define(dbDecorators.onCreate(createdByOnFabricCreateUpdate), decoration.propMetadata(core.PersistenceKeys.CREATED_BY, {})).apply();
|
|
977
|
+
decoration.Decoration.flavouredAs(FabricFlavour).for(core.PersistenceKeys.UPDATED_BY).define(dbDecorators.onCreateUpdate(createdByOnFabricCreateUpdate), decoration.propMetadata(core.PersistenceKeys.UPDATED_BY, {})).apply();
|
|
978
|
+
decoration.Decoration.flavouredAs(FabricFlavour).for(core.PersistenceKeys.COLUMN).extend(fabricContractApi.Property()).apply();
|
|
979
|
+
decoration.Decoration.flavouredAs(FabricFlavour).for(decoratorValidation.ValidationKeys.DATE).extend(function fabricProperty() {
|
|
980
|
+
return (target, prop) => {
|
|
981
|
+
fabricContractApi.Property(prop, "string:date")(target, prop);
|
|
982
|
+
};
|
|
983
|
+
});
|
|
984
|
+
decoration.Decoration.flavouredAs(FabricFlavour).for(core.PersistenceKeys.TABLE).extend(function table(obj) {
|
|
985
|
+
const chain = [];
|
|
986
|
+
let current = typeof obj === "function" ? decoration.Metadata.constr(obj) : decoration.Metadata.constr(obj.constructor);
|
|
987
|
+
while (current && current !== Object && current.prototype) {
|
|
988
|
+
chain.push(current);
|
|
989
|
+
current = Object.getPrototypeOf(current);
|
|
990
|
+
}
|
|
991
|
+
console.log(chain.map(c => c.name || c));
|
|
992
|
+
while (chain.length > 0) {
|
|
993
|
+
const constructor = chain.pop();
|
|
994
|
+
console.log(`Calling on ${constructor.name}`);
|
|
995
|
+
fabricContractApi.Object()(constructor);
|
|
996
|
+
}
|
|
997
|
+
return fabricContractApi.Object()(obj);
|
|
998
|
+
}).apply();
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
FabricContractAdapter.decoration();
|
|
1002
|
+
core.Adapter.setCurrent(FabricFlavour);
|
|
1003
|
+
class DeterministicSerializer extends decoratorValidation.JSONSerializer {
|
|
1004
|
+
constructor() {
|
|
1005
|
+
super();
|
|
1006
|
+
}
|
|
1007
|
+
preSerialize(model) {
|
|
1008
|
+
const toSerialize = Object.assign({}, model);
|
|
1009
|
+
let metadata;
|
|
1010
|
+
try {
|
|
1011
|
+
metadata = decoration.Metadata.modelName(model.constructor);
|
|
1012
|
+
} catch (error) {
|
|
1013
|
+
metadata = undefined;
|
|
1014
|
+
}
|
|
1015
|
+
toSerialize[decoratorValidation.ModelKeys.ANCHOR] = metadata || model.constructor.name;
|
|
1016
|
+
const preSerialize = function preSerialize(obj) {
|
|
1017
|
+
const self = this;
|
|
1018
|
+
if (typeof obj !== "object") return obj;
|
|
1019
|
+
if (Array.isArray(obj)) return obj.map(o => preSerialize.call(self, o));
|
|
1020
|
+
return this.preSerialize.call(this, obj);
|
|
1021
|
+
}.bind(this);
|
|
1022
|
+
decoratorValidation.Model.relations(model).forEach(r => {
|
|
1023
|
+
toSerialize[r] = preSerialize(toSerialize[r]);
|
|
1024
|
+
});
|
|
1025
|
+
return toSerialize;
|
|
1026
|
+
}
|
|
1027
|
+
deserialize(str) {
|
|
1028
|
+
const deserialization = JSON.parse(str);
|
|
1029
|
+
const className = deserialization[decoratorValidation.ModelKeys.ANCHOR];
|
|
1030
|
+
if (!className) throw new Error("Could not find class reference in serialized model");
|
|
1031
|
+
const model = decoratorValidation.Model.build(deserialization, className);
|
|
1032
|
+
return model;
|
|
1033
|
+
}
|
|
1034
|
+
serialize(model) {
|
|
1035
|
+
const stringify = require("json-stringify-deterministic");
|
|
1036
|
+
const sortKeysRecursive = require("sort-keys-recursive");
|
|
1037
|
+
return stringify(sortKeysRecursive(this.preSerialize(model)));
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
fabricContractApi.Object()(Date);
|
|
1041
|
+
class FabricCrudContract extends fabricContractApi.Contract {
|
|
1042
|
+
static {
|
|
1043
|
+
this.adapter = new FabricContractAdapter;
|
|
1044
|
+
}
|
|
1045
|
+
static {
|
|
1046
|
+
this.serializer = new DeterministicSerializer;
|
|
1047
|
+
}
|
|
1048
|
+
constructor(name, clazz) {
|
|
1049
|
+
super(name);
|
|
1050
|
+
this.clazz = clazz;
|
|
1051
|
+
this.initialized = false;
|
|
1052
|
+
this.repo = core.Repository.forModel(clazz);
|
|
1053
|
+
}
|
|
1054
|
+
async listBy(ctx, key, order, ...args) {
|
|
1055
|
+
const {ctxArgs: ctxArgs, log: log} = await this.logCtx([ ...args, ctx ], this.listBy);
|
|
1056
|
+
log.info(`Running listBy key ${key}, order ${order} and args ${ctxArgs}`);
|
|
1057
|
+
return this.repo.listBy(key, order, ...ctxArgs);
|
|
1058
|
+
}
|
|
1059
|
+
async paginateBy(ctx, key, order, ref = {
|
|
1060
|
+
offset: 1,
|
|
1061
|
+
limit: 10
|
|
1062
|
+
}, ...args) {
|
|
1063
|
+
const {ctxArgs: ctxArgs, log: log} = await this.logCtx([ ...args, ctx ], this.paginateBy);
|
|
1064
|
+
log.info(`Running paginateBy key ${key}, order ${order} with size ${ref.limit} and args ${ctxArgs}`);
|
|
1065
|
+
return this.repo.paginateBy(key, order, ref, ...ctxArgs);
|
|
1066
|
+
}
|
|
1067
|
+
async findOneBy(ctx, key, value, ...args) {
|
|
1068
|
+
const {ctxArgs: ctxArgs, log: log} = await this.logCtx([ ...args, ctx ], this.findOneBy);
|
|
1069
|
+
log.info(`Running findOneBy key ${key}, value: ${value} with args ${ctxArgs}`);
|
|
1070
|
+
return this.repo.findOneBy(key, value, ...ctxArgs);
|
|
1071
|
+
}
|
|
1072
|
+
async statement(ctx, method, ...args) {
|
|
1073
|
+
const {ctxArgs: ctxArgs, log: log} = await this.logCtx([ ...args, ctx ], this.statement);
|
|
1074
|
+
log.info(`Running statement ${method} with args ${ctxArgs}`);
|
|
1075
|
+
return this.repo.statement(method, ...ctxArgs);
|
|
1076
|
+
}
|
|
1077
|
+
async create(ctx, model, ...args) {
|
|
1078
|
+
const {log: log, ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.create);
|
|
1079
|
+
log.info(`CONTRACT CREATE, ${ctxArgs}`);
|
|
1080
|
+
if (typeof model === "string") model = this.deserialize(model);
|
|
1081
|
+
log.info(`Creating model: ${JSON.stringify(model)}`);
|
|
1082
|
+
const transient = this.getTransientData(ctx);
|
|
1083
|
+
log.info(`Merging transient data...`);
|
|
1084
|
+
model = decoratorValidation.Model.merge(model, transient, this.clazz);
|
|
1085
|
+
return this.repo.create(model, ...ctxArgs);
|
|
1086
|
+
}
|
|
1087
|
+
async read(ctx, key, ...args) {
|
|
1088
|
+
const {log: log, ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.read);
|
|
1089
|
+
log.info(`reading entry with pk ${key} `);
|
|
1090
|
+
return this.repo.read(key, ...ctxArgs);
|
|
1091
|
+
}
|
|
1092
|
+
getTransientData(ctx) {
|
|
1093
|
+
const transientMap = ctx.stub.getTransient();
|
|
1094
|
+
let transient = {};
|
|
1095
|
+
if (transientMap.has(this.repo.tableName)) {
|
|
1096
|
+
transient = JSON.parse(transientMap.get(this.repo.tableName)?.toString("utf8"));
|
|
1097
|
+
}
|
|
1098
|
+
return transient;
|
|
1099
|
+
}
|
|
1100
|
+
async update(ctx, model, ...args) {
|
|
1101
|
+
const {log: log, ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.update);
|
|
1102
|
+
if (typeof model === "string") model = this.deserialize(model);
|
|
1103
|
+
log.info(`Updating model: ${JSON.stringify(model)}`);
|
|
1104
|
+
const transient = this.getTransientData(ctx);
|
|
1105
|
+
log.info(`Merging transient data...`);
|
|
1106
|
+
model = decoratorValidation.Model.merge(model, transient, this.clazz);
|
|
1107
|
+
return this.repo.update(model, ...ctxArgs);
|
|
1108
|
+
}
|
|
1109
|
+
async delete(ctx, key, ...args) {
|
|
1110
|
+
const {log: log, ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.delete);
|
|
1111
|
+
log.info(`deleting entry with pk ${key} `);
|
|
1112
|
+
return this.repo.delete(String(key), ...ctxArgs);
|
|
1113
|
+
}
|
|
1114
|
+
async deleteAll(ctx, keys, ...args) {
|
|
1115
|
+
const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.readAll);
|
|
1116
|
+
if (typeof keys === "string") keys = JSON.parse(keys);
|
|
1117
|
+
return this.repo.deleteAll(keys, ...ctxArgs);
|
|
1118
|
+
}
|
|
1119
|
+
async readAll(ctx, keys, ...args) {
|
|
1120
|
+
const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.readAll);
|
|
1121
|
+
if (typeof keys === "string") keys = JSON.parse(keys);
|
|
1122
|
+
return this.repo.readAll(keys, ...ctxArgs);
|
|
1123
|
+
}
|
|
1124
|
+
async updateAll(ctx, models, ...args) {
|
|
1125
|
+
const {log: log, ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.updateAll);
|
|
1126
|
+
if (typeof models === "string") models = JSON.parse(models).map(m => this.deserialize(m)).map(m => new this.clazz(m));
|
|
1127
|
+
log.info(`updating ${models.length} entries to the table`);
|
|
1128
|
+
return this.repo.updateAll(models, ...ctxArgs);
|
|
1129
|
+
}
|
|
1130
|
+
async query(context, condition, orderBy, order = core.OrderDirection.ASC, limit, skip, ...args) {
|
|
1131
|
+
const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, context ], this.query);
|
|
1132
|
+
return this.repo.query(condition, orderBy, order, limit, skip, ...ctxArgs);
|
|
1133
|
+
}
|
|
1134
|
+
async raw(ctx, rawInput, docsOnly, ...args) {
|
|
1135
|
+
const {ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.raw);
|
|
1136
|
+
return FabricCrudContract.adapter.raw(rawInput, docsOnly, ...ctxArgs);
|
|
1137
|
+
}
|
|
1138
|
+
serialize(model) {
|
|
1139
|
+
return FabricCrudContract.serializer.serialize(model);
|
|
1140
|
+
}
|
|
1141
|
+
deserialize(str) {
|
|
1142
|
+
return FabricCrudContract.serializer.deserialize(str);
|
|
1143
|
+
}
|
|
1144
|
+
async init(ctx) {
|
|
1145
|
+
const {log: log} = await this.logCtx([ ctx ], this.init);
|
|
1146
|
+
log.info(`Running contract ${this.getName()} initialization...`);
|
|
1147
|
+
this.initialized = true;
|
|
1148
|
+
log.info(`Contract initialization completed.`);
|
|
1149
|
+
}
|
|
1150
|
+
async healthcheck(ctx) {
|
|
1151
|
+
const {log: log} = await this.logCtx([ ctx ], this.healthcheck);
|
|
1152
|
+
log.info(`Running Healthcheck: ${this.initialized}...`);
|
|
1153
|
+
return {
|
|
1154
|
+
healthcheck: this.initialized
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
async createAll(ctx, models, ...args) {
|
|
1158
|
+
const {log: log, ctxArgs: ctxArgs} = await this.logCtx([ ...args, ctx ], this.createAll);
|
|
1159
|
+
if (typeof models === "string") models = JSON.parse(models).map(m => this.deserialize(m)).map(m => new this.clazz(m));
|
|
1160
|
+
log.info(`adding ${models.length} entries to the table`);
|
|
1161
|
+
return this.repo.createAll(models, ...ctxArgs);
|
|
1162
|
+
}
|
|
1163
|
+
async logCtx(args, method) {
|
|
1164
|
+
return FabricCrudContract.logCtx.bind(this)(args, method);
|
|
1165
|
+
}
|
|
1166
|
+
static async logCtx(args, method) {
|
|
1167
|
+
if (args.length < 1) throw new dbDecorators.InternalError("No context provided");
|
|
1168
|
+
const ctx = args.pop();
|
|
1169
|
+
if (ctx instanceof FabricContractContext) return {
|
|
1170
|
+
ctx: ctx,
|
|
1171
|
+
log: ctx.logger.clear().for(this).for(method),
|
|
1172
|
+
ctxArgs: [ ...args, ctx ],
|
|
1173
|
+
stub: ctx.stub,
|
|
1174
|
+
identity: ctx.identity
|
|
1175
|
+
};
|
|
1176
|
+
if (!(ctx instanceof fabricContractApi.Context)) throw new dbDecorators.InternalError("No valid context provided");
|
|
1177
|
+
function getOp() {
|
|
1178
|
+
if (typeof method === "string") return method;
|
|
1179
|
+
switch (method.name) {
|
|
1180
|
+
case dbDecorators.OperationKeys.CREATE:
|
|
1181
|
+
case dbDecorators.OperationKeys.READ:
|
|
1182
|
+
case dbDecorators.OperationKeys.UPDATE:
|
|
1183
|
+
case dbDecorators.OperationKeys.DELETE:
|
|
1184
|
+
case dbDecorators.BulkCrudOperationKeys.CREATE_ALL:
|
|
1185
|
+
case dbDecorators.BulkCrudOperationKeys.READ_ALL:
|
|
1186
|
+
case dbDecorators.BulkCrudOperationKeys.UPDATE_ALL:
|
|
1187
|
+
case dbDecorators.BulkCrudOperationKeys.DELETE_ALL:
|
|
1188
|
+
return method.name;
|
|
1189
|
+
|
|
1190
|
+
default:
|
|
1191
|
+
return method.name;
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
const overrides = {
|
|
1195
|
+
correlationId: ctx.stub.getTxID()
|
|
1196
|
+
};
|
|
1197
|
+
const context = await FabricCrudContract.adapter.context(getOp(), overrides, this.clazz, ctx);
|
|
1198
|
+
const log = this ? context.logger.for(this).for(method) : context.logger.clear().for(this).for(method);
|
|
1199
|
+
return {
|
|
1200
|
+
ctx: context,
|
|
1201
|
+
log: log,
|
|
1202
|
+
stub: context.stub,
|
|
1203
|
+
identity: context.identity,
|
|
1204
|
+
ctxArgs: [ ...args, context ]
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
class SerializedCrudContract extends FabricCrudContract {
|
|
1209
|
+
constructor(name, clazz) {
|
|
1210
|
+
super(name, clazz);
|
|
1211
|
+
}
|
|
1212
|
+
async create(context, model) {
|
|
1213
|
+
const {log: log, ctx: ctx} = await this.logCtx([ context ], this.create);
|
|
1214
|
+
log.info(`Creating model: ${model}`);
|
|
1215
|
+
const m = this.deserialize(model);
|
|
1216
|
+
log.info(`Model deserialized: ${JSON.stringify(m)}`);
|
|
1217
|
+
const result = await super.create(ctx, m);
|
|
1218
|
+
const serialized = this.serialize(result);
|
|
1219
|
+
log.info(`RESULT: ${JSON.stringify(result)}`);
|
|
1220
|
+
log.info(`Retuning: ${serialized}`);
|
|
1221
|
+
return serialized;
|
|
1222
|
+
}
|
|
1223
|
+
async read(context, key) {
|
|
1224
|
+
const {log: log, ctx: ctx} = await this.logCtx([ context ], this.read);
|
|
1225
|
+
log.info(`Reading id: ${key}`);
|
|
1226
|
+
return this.serialize(await super.read(ctx, key));
|
|
1227
|
+
}
|
|
1228
|
+
async update(context, model) {
|
|
1229
|
+
const {log: log, ctx: ctx} = await this.logCtx([ context ], this.update);
|
|
1230
|
+
log.info(`Updating model: ${model}`);
|
|
1231
|
+
return this.serialize(await super.update(ctx, model));
|
|
1232
|
+
}
|
|
1233
|
+
async delete(context, key) {
|
|
1234
|
+
const {log: log, ctx: ctx} = await this.logCtx([ context ], this.delete);
|
|
1235
|
+
log.info(`Deleting id: ${key}`);
|
|
1236
|
+
return this.serialize(await super.delete(ctx, key));
|
|
1237
|
+
}
|
|
1238
|
+
async deleteAll(context, keys) {
|
|
1239
|
+
const parsedKeys = JSON.parse(keys);
|
|
1240
|
+
const {log: log, ctx: ctx} = await this.logCtx([ context ], this.deleteAll);
|
|
1241
|
+
log.info(`deleting ${parsedKeys.length} entries from the table`);
|
|
1242
|
+
return JSON.stringify((await super.deleteAll(ctx, parsedKeys)).map(m => this.serialize(m)));
|
|
1243
|
+
}
|
|
1244
|
+
async readAll(context, keys) {
|
|
1245
|
+
const parsedKeys = JSON.parse(keys);
|
|
1246
|
+
const {log: log, ctx: ctx} = await this.logCtx([ context ], this.readAll);
|
|
1247
|
+
log.info(`reading ${parsedKeys.length} entries from the table`);
|
|
1248
|
+
return JSON.stringify((await super.readAll(ctx, parsedKeys)).map(m => this.serialize(m)));
|
|
1249
|
+
}
|
|
1250
|
+
async updateAll(context, models) {
|
|
1251
|
+
const {log: log, ctx: ctx} = await this.logCtx([ context ], this.updateAll);
|
|
1252
|
+
const list = JSON.parse(models);
|
|
1253
|
+
const modelList = list.map(m => this.deserialize(m)).map(m => new this.clazz(m));
|
|
1254
|
+
log.info(`Updating ${modelList.length} entries to the table`);
|
|
1255
|
+
return JSON.stringify((await super.updateAll(ctx, modelList)).map(m => this.serialize(m)));
|
|
1256
|
+
}
|
|
1257
|
+
async statement(context, method, args) {
|
|
1258
|
+
const {ctx: ctx, log: log} = await this.logCtx([ context ], this.statement);
|
|
1259
|
+
try {
|
|
1260
|
+
args = JSON.parse(args);
|
|
1261
|
+
} catch (e) {
|
|
1262
|
+
throw new dbDecorators.SerializationError(`Invalid args: ${e}`);
|
|
1263
|
+
}
|
|
1264
|
+
if (!Array.isArray(args)) throw new dbDecorators.SerializationError(`Invalid args: ${JSON.stringify(args)}. must be an array`);
|
|
1265
|
+
log.info(`calling prepared statement ${method}`);
|
|
1266
|
+
log.info(`with args ${args}`);
|
|
1267
|
+
return JSON.stringify(await super.statement(ctx, method, ...args));
|
|
1268
|
+
}
|
|
1269
|
+
async listBy(context, key, order) {
|
|
1270
|
+
const {ctx: ctx, log: log} = await this.logCtx([ context ], this.listBy);
|
|
1271
|
+
log.info(`Executing listBy with key ${key} and order ${order}`);
|
|
1272
|
+
return JSON.stringify(await super.listBy(ctx, key, order));
|
|
1273
|
+
}
|
|
1274
|
+
async paginateBy(context, key, order, ref, ...args) {
|
|
1275
|
+
const {ctx: ctx, log: log} = await this.logCtx([ ...args, context ], this.paginateBy);
|
|
1276
|
+
try {
|
|
1277
|
+
ref = JSON.parse(ref);
|
|
1278
|
+
} catch (e) {
|
|
1279
|
+
throw new dbDecorators.SerializationError(`Failed to deserialize paginateBy reference: ${e}`);
|
|
1280
|
+
}
|
|
1281
|
+
log.info(`Executing paginateBy with key ${key} and order ${order}`);
|
|
1282
|
+
return JSON.stringify(await super.paginateBy(ctx, key, order, ref, ...args));
|
|
1283
|
+
}
|
|
1284
|
+
async findOneBy(context, key, value, ...args) {
|
|
1285
|
+
const {ctx: ctx, log: log} = await this.logCtx([ ...args, context ], this.findOneBy);
|
|
1286
|
+
log.info(`Executing findOneBy with key ${key} and value ${value}`);
|
|
1287
|
+
return JSON.stringify(await super.findOneBy(ctx, key, value, ...args));
|
|
1288
|
+
}
|
|
1289
|
+
async query(context, condition, orderBy, order, limit, skip) {
|
|
1290
|
+
const {ctx: ctx, log: log} = await this.logCtx([ context ], this.query);
|
|
1291
|
+
log.info(`Executing query orderedBy ${orderBy} and order ${order}`);
|
|
1292
|
+
let cond;
|
|
1293
|
+
try {
|
|
1294
|
+
cond = core.Condition.from(JSON.parse(condition));
|
|
1295
|
+
} catch (e) {
|
|
1296
|
+
throw new dbDecorators.SerializationError(`Invalid condition: ${e}`);
|
|
1297
|
+
}
|
|
1298
|
+
log.info(`Condition: ${JSON.stringify(cond)}`);
|
|
1299
|
+
return JSON.stringify(await super.query(ctx, cond, orderBy, order, limit, skip));
|
|
1300
|
+
}
|
|
1301
|
+
async init(ctx) {
|
|
1302
|
+
await super.init(ctx);
|
|
1303
|
+
}
|
|
1304
|
+
async healthcheck(context) {
|
|
1305
|
+
const {log: log, ctx: ctx} = await this.logCtx([ context ], this.updateAll);
|
|
1306
|
+
log.debug(`Running Healthcheck: ${this.initialized}...`);
|
|
1307
|
+
return JSON.stringify(await super.healthcheck(ctx));
|
|
1308
|
+
}
|
|
1309
|
+
async createAll(context, models) {
|
|
1310
|
+
const {log: log} = await this.logCtx([ context ], this.createAll);
|
|
1311
|
+
const list = JSON.parse(models);
|
|
1312
|
+
const modelList = list.map(m => this.deserialize(m)).map(m => new this.clazz(m));
|
|
1313
|
+
log.info(`Adding ${modelList.length} entries to the table`);
|
|
1314
|
+
const result = await super.createAll(context, modelList);
|
|
1315
|
+
return JSON.stringify(result.map(m => this.serialize(m)));
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
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);
|
|
1319
|
+
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);
|
|
1320
|
+
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);
|
|
1321
|
+
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);
|
|
1322
|
+
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);
|
|
1323
|
+
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);
|
|
1324
|
+
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);
|
|
1325
|
+
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);
|
|
1326
|
+
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, "listBy", null);
|
|
1327
|
+
tslib.__decorate([ fabricContractApi.Transaction(false), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context, String, String, String, FabricContractContext ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "paginateBy", null);
|
|
1328
|
+
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);
|
|
1329
|
+
tslib.__decorate([ fabricContractApi.Transaction(), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ fabricContractApi.Context ]), tslib.__metadata("design:returntype", Promise) ], SerializedCrudContract.prototype, "init", null);
|
|
1330
|
+
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);
|
|
1331
|
+
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);
|
|
1332
|
+
function add(a, b) {
|
|
1333
|
+
const c = a + b;
|
|
1334
|
+
if (a !== c - b || b !== c - a) {
|
|
1335
|
+
throw new OverflowError(`Addition overflow: ${a} + ${b}`);
|
|
1336
|
+
}
|
|
1337
|
+
return c;
|
|
1338
|
+
}
|
|
1339
|
+
function sub(a, b) {
|
|
1340
|
+
const c = a - b;
|
|
1341
|
+
if (a !== c + b || b !== a - c) {
|
|
1342
|
+
throw new OverflowError(`Subtraction overflow: ${a} - ${b}`);
|
|
1343
|
+
}
|
|
1344
|
+
return c;
|
|
1345
|
+
}
|
|
1346
|
+
function safeParseInt(string) {
|
|
1347
|
+
const digitRegex = /^\d+$/;
|
|
1348
|
+
if (!digitRegex.test(string)) {
|
|
1349
|
+
throw new dbDecorators.ValidationError(decoratorValidation.stringFormat("Failed to parse: {0}", "string contains digits"));
|
|
1350
|
+
}
|
|
1351
|
+
const parsedint = parseInt(string);
|
|
1352
|
+
if (isNaN(parsedint)) {
|
|
1353
|
+
throw new dbDecorators.ValidationError(decoratorValidation.stringFormat("Failed to parse: {0}", "string is not a parsable integer"));
|
|
1354
|
+
}
|
|
1355
|
+
return parsedint;
|
|
1356
|
+
}
|
|
1357
|
+
let ERC20Token = class ERC20Token extends core.BaseModel {
|
|
1358
|
+
constructor(m) {
|
|
1359
|
+
super(m);
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
1362
|
+
tslib.__decorate([ core.pk({
|
|
1363
|
+
type: "String"
|
|
1364
|
+
}), tslib.__metadata("design:type", String) ], ERC20Token.prototype, "name", void 0);
|
|
1365
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], ERC20Token.prototype, "owner", void 0);
|
|
1366
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], ERC20Token.prototype, "symbol", void 0);
|
|
1367
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", Number) ], ERC20Token.prototype, "decimals", void 0);
|
|
1368
|
+
ERC20Token = tslib.__decorate([ core.table("erc20_tokens"), decoratorValidation.model(), tslib.__metadata("design:paramtypes", [ Object ]) ], ERC20Token);
|
|
1369
|
+
let ERC20Wallet = class ERC20Wallet extends core.BaseModel {
|
|
1370
|
+
constructor(m) {
|
|
1371
|
+
super(m);
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
tslib.__decorate([ core.pk({
|
|
1375
|
+
type: "String"
|
|
1376
|
+
}), tslib.__metadata("design:type", String) ], ERC20Wallet.prototype, "id", void 0);
|
|
1377
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], ERC20Wallet.prototype, "token", void 0);
|
|
1378
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", Number) ], ERC20Wallet.prototype, "balance", void 0);
|
|
1379
|
+
tslib.__decorate([ core.column(), tslib.__metadata("design:type", String) ], ERC20Wallet.prototype, "captive", void 0);
|
|
1380
|
+
ERC20Wallet = tslib.__decorate([ core.table("erc20_wallets"), decoratorValidation.model(), tslib.__metadata("design:paramtypes", [ Object ]) ], ERC20Wallet);
|
|
1381
|
+
let Allowance = class Allowance extends core.BaseModel {
|
|
1382
|
+
constructor(m) {
|
|
1383
|
+
super(m);
|
|
1384
|
+
}
|
|
1385
|
+
};
|
|
1386
|
+
tslib.__decorate([ core.pk({
|
|
1387
|
+
type: "String"
|
|
1388
|
+
}), core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], Allowance.prototype, "owner", void 0);
|
|
1389
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", String) ], Allowance.prototype, "spender", void 0);
|
|
1390
|
+
tslib.__decorate([ core.column(), decoratorValidation.required(), tslib.__metadata("design:type", Number) ], Allowance.prototype, "value", void 0);
|
|
1391
|
+
Allowance = tslib.__decorate([ core.table("erc20_allowances"), decoratorValidation.model(), tslib.__metadata("design:paramtypes", [ Object ]) ], Allowance);
|
|
1392
|
+
function Owner() {
|
|
1393
|
+
return function(target, propertyKey, descriptor) {
|
|
1394
|
+
const originalMethod = descriptor.value;
|
|
1395
|
+
descriptor.value = async function(...args) {
|
|
1396
|
+
const ctx = args[0];
|
|
1397
|
+
const acountId = ctx.clientIdentity.getID();
|
|
1398
|
+
const select = await this["tokenRepository"].select();
|
|
1399
|
+
const tokens = await select.execute(ctx);
|
|
1400
|
+
if (tokens.length == 0) {
|
|
1401
|
+
throw new dbDecorators.NotFoundError("No tokens avaialble");
|
|
1402
|
+
}
|
|
1403
|
+
if (tokens.length > 1) {
|
|
1404
|
+
throw new dbDecorators.NotFoundError(`To many token available : ${tokens.length}`);
|
|
1405
|
+
}
|
|
1406
|
+
if (tokens[0].owner != acountId) {
|
|
1407
|
+
throw new core.AuthorizationError(`User not authorized to run ${propertyKey} on the token`);
|
|
1408
|
+
}
|
|
1409
|
+
return await originalMethod.apply(this, args);
|
|
1410
|
+
};
|
|
1411
|
+
return descriptor;
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
async function ownedByOnCreate(context, data, key, model) {
|
|
1415
|
+
const {stub: stub} = context;
|
|
1416
|
+
const creator = await stub.getCreator();
|
|
1417
|
+
const owner = creator.mspid;
|
|
1418
|
+
const setOwnedByKeyValue = function(target, propertyKey, value) {
|
|
1419
|
+
Object.defineProperty(target, propertyKey, {
|
|
1420
|
+
enumerable: true,
|
|
1421
|
+
writable: false,
|
|
1422
|
+
configurable: true,
|
|
1423
|
+
value: value
|
|
1424
|
+
});
|
|
1425
|
+
};
|
|
1426
|
+
setOwnedByKeyValue(model, key, owner);
|
|
1427
|
+
}
|
|
1428
|
+
function ownedBy() {
|
|
1429
|
+
const key = getFabricModelKey(FabricModelKeys.OWNEDBY);
|
|
1430
|
+
function ownedBy() {
|
|
1431
|
+
return function(obj, attribute) {
|
|
1432
|
+
return decoration.apply(decoratorValidation.required(), dbDecorators.readonly(), dbDecorators.onCreate(ownedByOnCreate), decoration.propMetadata(getFabricModelKey(FabricModelKeys.OWNEDBY), attribute))(obj, attribute);
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
return decoration.Decoration.for(key).define({
|
|
1436
|
+
decorator: ownedBy,
|
|
1437
|
+
args: []
|
|
1438
|
+
}).apply();
|
|
1439
|
+
}
|
|
1440
|
+
async function transactionIdOnCreate(context, data, key, model) {
|
|
1441
|
+
const {stub: stub} = context;
|
|
1442
|
+
model[key] = stub.getTxID();
|
|
1443
|
+
}
|
|
1444
|
+
function transactionId() {
|
|
1445
|
+
function transactionId() {
|
|
1446
|
+
return function(obj, attribute) {
|
|
1447
|
+
return decoration.apply(decoratorValidation.required(), dbDecorators.readonly(), dbDecorators.onCreate(transactionIdOnCreate), dbDecorators.onUpdate(transactionIdOnCreate), decoration.propMetadata(decoration.Metadata.key(FabricModelKeys.FABRIC, attribute, FabricModelKeys.TRANSACTION_ID), attribute))(obj, attribute);
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
return decoration.Decoration.for(FabricModelKeys.TRANSACTION_ID).define({
|
|
1451
|
+
decorator: transactionId,
|
|
1452
|
+
args: []
|
|
1453
|
+
}).apply();
|
|
1454
|
+
}
|
|
1455
|
+
function getFabricModelKey(key) {
|
|
1456
|
+
return decoration.Metadata.key(FabricModelKeys.FABRIC + key);
|
|
1457
|
+
}
|
|
1458
|
+
const ImplicitPrivateCollection = model => `__${model.constructor.name}PrivateCollection`;
|
|
1459
|
+
async function segregatedDataOnCreate(context, data, keys, model) {
|
|
1460
|
+
if (keys.length !== data.length) throw new dbDecorators.InternalError(`Segregated data keys and metadata length mismatch`);
|
|
1461
|
+
const collectionResolver = data[0].collections;
|
|
1462
|
+
const collection = typeof collectionResolver === "string" ? collectionResolver : collectionResolver(model);
|
|
1463
|
+
const rebuilt = keys.reduce((acc, k, i) => {
|
|
1464
|
+
const c = typeof data[i].collections === "string" ? data[i].collections : data[i].collections(model);
|
|
1465
|
+
if (c !== collection) throw new core.UnsupportedError(`Segregated data collection mismatch: ${c} vs ${collection}`);
|
|
1466
|
+
acc[k] = model[k];
|
|
1467
|
+
return acc;
|
|
1468
|
+
}, {});
|
|
1469
|
+
const toCreate = new this.class(rebuilt);
|
|
1470
|
+
const created = await this.override({
|
|
1471
|
+
segregated: collection
|
|
1472
|
+
}).create(toCreate, context);
|
|
1473
|
+
Object.assign(model, created);
|
|
1474
|
+
}
|
|
1475
|
+
async function segregatedDataOnRead(context, data, keys, model) {
|
|
1476
|
+
if (keys.length !== data.length) throw new dbDecorators.InternalError(`Segregated data keys and metadata length mismatch`);
|
|
1477
|
+
const collectionResolver = data[0].collections;
|
|
1478
|
+
const collection = typeof collectionResolver === "string" ? collectionResolver : collectionResolver(model);
|
|
1479
|
+
const rebuilt = keys.reduce((acc, k, i) => {
|
|
1480
|
+
const c = typeof data[i].collections === "string" ? data[i].collections : data[i].collections(model);
|
|
1481
|
+
if (c !== collection) throw new core.UnsupportedError(`Segregated data collection mismatch: ${c} vs ${collection}`);
|
|
1482
|
+
acc[k] = model[k];
|
|
1483
|
+
return acc;
|
|
1484
|
+
}, {});
|
|
1485
|
+
const toCreate = new this.class(rebuilt);
|
|
1486
|
+
const created = await this.override({
|
|
1487
|
+
segregated: collection
|
|
1488
|
+
}).create(toCreate, context);
|
|
1489
|
+
Object.assign(model, created);
|
|
1490
|
+
}
|
|
1491
|
+
async function segregatedDataOnUpdate(context, data, key, model, oldModel) {}
|
|
1492
|
+
async function segregatedDataOnDelete(context, data, key, model) {}
|
|
1493
|
+
function segregated(collection, type) {
|
|
1494
|
+
return function innerSegregated(target, propertyKey) {
|
|
1495
|
+
function segregatedDec(target, propertyKey) {
|
|
1496
|
+
if (!propertyKey) {
|
|
1497
|
+
const props = decoration.Metadata.properties(target) || [];
|
|
1498
|
+
for (const prop of props) segregated(collection, type)(target, prop);
|
|
1499
|
+
return target;
|
|
1500
|
+
}
|
|
1501
|
+
const key = decoration.Metadata.key(type, propertyKey);
|
|
1502
|
+
const constr = target.constructor;
|
|
1503
|
+
const meta = decoration.Metadata.get(constr, key) || {};
|
|
1504
|
+
const collections = new Set(meta.collections || []);
|
|
1505
|
+
collections.add(collection);
|
|
1506
|
+
meta.collections = [ ...collections ];
|
|
1507
|
+
decoration.Metadata.set(constr, key, meta);
|
|
1508
|
+
}
|
|
1509
|
+
const decs = [];
|
|
1510
|
+
if (!propertyKey) {
|
|
1511
|
+
decoration.Metadata.properties(target)?.forEach(p => segregated(collection, type)(target, p));
|
|
1512
|
+
return decoration.metadata(type, true)(target);
|
|
1513
|
+
} else {
|
|
1514
|
+
decs.push(dbDecorators.transient(), segregatedDec, dbDecorators.onCreate(segregatedDataOnCreate, {
|
|
1515
|
+
collections: collection
|
|
1516
|
+
}, {
|
|
1517
|
+
priority: 95,
|
|
1518
|
+
group: typeof collection === "string" ? collection : collection.toString()
|
|
1519
|
+
}), dbDecorators.onRead(segregatedDataOnRead, {
|
|
1520
|
+
collections: collection
|
|
1521
|
+
}, {
|
|
1522
|
+
priority: 95,
|
|
1523
|
+
group: typeof collection === "string" ? collection : collection.toString()
|
|
1524
|
+
}), dbDecorators.onUpdate(segregatedDataOnUpdate, {
|
|
1525
|
+
collections: collection
|
|
1526
|
+
}, {
|
|
1527
|
+
priority: 95,
|
|
1528
|
+
group: typeof collection === "string" ? collection : collection.toString()
|
|
1529
|
+
}), dbDecorators.onDelete(segregatedDataOnDelete, {
|
|
1530
|
+
collections: collection
|
|
1531
|
+
}, {
|
|
1532
|
+
priority: 95,
|
|
1533
|
+
group: typeof collection === "string" ? collection : collection.toString()
|
|
1534
|
+
}));
|
|
1535
|
+
}
|
|
1536
|
+
return decoration.apply(...decs)(target, propertyKey);
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
function privateData(collection = ImplicitPrivateCollection) {
|
|
1540
|
+
function privateData(collection) {
|
|
1541
|
+
return segregated(collection, FabricModelKeys.PRIVATE);
|
|
1542
|
+
}
|
|
1543
|
+
return decoration.Decoration.for(FabricModelKeys.PRIVATE).define({
|
|
1544
|
+
decorator: privateData,
|
|
1545
|
+
args: [ collection ]
|
|
1546
|
+
}).apply();
|
|
1547
|
+
}
|
|
1548
|
+
function sharedData(collection) {
|
|
1549
|
+
function sharedData(collection) {
|
|
1550
|
+
return segregated(collection, FabricModelKeys.SHARED);
|
|
1551
|
+
}
|
|
1552
|
+
return decoration.Decoration.for(FabricModelKeys.SHARED).define({
|
|
1553
|
+
decorator: sharedData,
|
|
1554
|
+
args: [ collection ]
|
|
1555
|
+
}).apply();
|
|
1556
|
+
}
|
|
1557
|
+
var ERC20Events;
|
|
1558
|
+
(function(ERC20Events) {
|
|
1559
|
+
ERC20Events["TRANSFER"] = "Transfer";
|
|
1560
|
+
ERC20Events["APPROVAL"] = "Approval";
|
|
1561
|
+
})(ERC20Events || (ERC20Events = {}));
|
|
1562
|
+
class FabricERC20Contract extends FabricCrudContract {
|
|
1563
|
+
constructor(name) {
|
|
1564
|
+
super(name, ERC20Wallet);
|
|
1565
|
+
FabricERC20Contract.adapter = FabricERC20Contract.adapter || new FabricContractAdapter;
|
|
1566
|
+
this.walletRepository = FabricContractRepository.forModel(ERC20Wallet, FabricERC20Contract.adapter.alias);
|
|
1567
|
+
this.tokenRepository = FabricContractRepository.forModel(ERC20Token, FabricERC20Contract.adapter.alias);
|
|
1568
|
+
this.allowanceRepository = FabricContractRepository.forModel(Allowance, FabricERC20Contract.adapter.alias);
|
|
1569
|
+
}
|
|
1570
|
+
async TokenName(context) {
|
|
1571
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
|
|
1572
|
+
await this.CheckInitialized(ctx);
|
|
1573
|
+
const select = this.tokenRepository.select();
|
|
1574
|
+
const token = (await select.execute(ctx))[0];
|
|
1575
|
+
return token.name;
|
|
1576
|
+
}
|
|
1577
|
+
async Symbol(context) {
|
|
1578
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
|
|
1579
|
+
await this.CheckInitialized(ctx);
|
|
1580
|
+
const select = this.tokenRepository.select();
|
|
1581
|
+
const token = (await select.execute(ctx))[0];
|
|
1582
|
+
return token.symbol;
|
|
1583
|
+
}
|
|
1584
|
+
async Decimals(context) {
|
|
1585
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
|
|
1586
|
+
await this.CheckInitialized(ctx);
|
|
1587
|
+
const select = this.tokenRepository.select();
|
|
1588
|
+
const token = (await select.execute(ctx))[0];
|
|
1589
|
+
return token.decimals;
|
|
1590
|
+
}
|
|
1591
|
+
async TotalSupply(context) {
|
|
1592
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
|
|
1593
|
+
await this.CheckInitialized(ctx);
|
|
1594
|
+
const select = this.walletRepository.select();
|
|
1595
|
+
const wallets = await select.execute(ctx);
|
|
1596
|
+
if (wallets.length == 0) {
|
|
1597
|
+
throw new dbDecorators.NotFoundError(`The token ${this.getName()} does not exist`);
|
|
1598
|
+
}
|
|
1599
|
+
let total = 0;
|
|
1600
|
+
wallets.forEach(wallet => {
|
|
1601
|
+
total += wallet.balance;
|
|
1602
|
+
});
|
|
1603
|
+
return total;
|
|
1604
|
+
}
|
|
1605
|
+
async BalanceOf(context, owner) {
|
|
1606
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
|
|
1607
|
+
await this.CheckInitialized(ctx);
|
|
1608
|
+
const wallet = await this.walletRepository.read(owner, ctx);
|
|
1609
|
+
return wallet.balance;
|
|
1610
|
+
}
|
|
1611
|
+
async Transfer(context, to, value) {
|
|
1612
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.Transfer);
|
|
1613
|
+
await this.CheckInitialized(ctx);
|
|
1614
|
+
const from = ctx.identity.getID();
|
|
1615
|
+
const transferResp = await this._transfer(from, to, value, ctx);
|
|
1616
|
+
if (!transferResp) {
|
|
1617
|
+
throw new dbDecorators.InternalError("Failed to transfer");
|
|
1618
|
+
}
|
|
1619
|
+
return true;
|
|
1620
|
+
}
|
|
1621
|
+
async TransferFrom(context, from, to, value) {
|
|
1622
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.BurnFrom);
|
|
1623
|
+
await this.CheckInitialized(ctx);
|
|
1624
|
+
const spender = ctx.identity.getID();
|
|
1625
|
+
const allowance = await this._getAllowance(from, spender, ctx);
|
|
1626
|
+
if (!allowance || allowance.value < 0) {
|
|
1627
|
+
throw new AllowanceError(`spender ${spender} has no allowance from ${from}`);
|
|
1628
|
+
}
|
|
1629
|
+
const currentAllowance = allowance.value;
|
|
1630
|
+
if (currentAllowance < value) {
|
|
1631
|
+
throw new BalanceError("The spender does not have enough allowance to spend.");
|
|
1632
|
+
}
|
|
1633
|
+
const updatedAllowance = sub(currentAllowance, value);
|
|
1634
|
+
const newAllowance = Object.assign({}, allowance, {
|
|
1635
|
+
value: updatedAllowance
|
|
1636
|
+
});
|
|
1637
|
+
await this.allowanceRepository.update(newAllowance, ctx);
|
|
1638
|
+
const transferResp = await this._transfer(from, to, value, ctx);
|
|
1639
|
+
if (!transferResp) {
|
|
1640
|
+
throw new dbDecorators.InternalError("Failed to transfer");
|
|
1641
|
+
}
|
|
1642
|
+
return true;
|
|
1643
|
+
}
|
|
1644
|
+
async _transfer(from, to, value, ctx) {
|
|
1645
|
+
const log = ctx.logger;
|
|
1646
|
+
if (from === to) {
|
|
1647
|
+
throw new core.AuthorizationError("cannot transfer to and from same client account");
|
|
1648
|
+
}
|
|
1649
|
+
if (value < 0) {
|
|
1650
|
+
throw new BalanceError("transfer amount cannot be negative");
|
|
1651
|
+
}
|
|
1652
|
+
const fromWallet = await this.walletRepository.read(from, ctx);
|
|
1653
|
+
const fromBalance = fromWallet.balance;
|
|
1654
|
+
if (fromBalance < value) {
|
|
1655
|
+
throw new BalanceError(`client account ${from} has insufficient funds.`);
|
|
1656
|
+
}
|
|
1657
|
+
let toWallet;
|
|
1658
|
+
let newToWallet = false;
|
|
1659
|
+
try {
|
|
1660
|
+
toWallet = await this.walletRepository.read(to, ctx);
|
|
1661
|
+
} catch (e) {
|
|
1662
|
+
if (e instanceof dbDecorators.BaseError) {
|
|
1663
|
+
if (e.code === 404) {
|
|
1664
|
+
toWallet = new ERC20Wallet({
|
|
1665
|
+
id: to,
|
|
1666
|
+
balance: 0,
|
|
1667
|
+
token: await this.TokenName(ctx)
|
|
1668
|
+
});
|
|
1669
|
+
newToWallet = true;
|
|
1670
|
+
} else {
|
|
1671
|
+
throw new dbDecorators.InternalError(e.message);
|
|
1672
|
+
}
|
|
1673
|
+
} else {
|
|
1674
|
+
throw new dbDecorators.InternalError(e);
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
const toBalance = toWallet.balance;
|
|
1678
|
+
const fromUpdatedBalance = sub(fromBalance, value);
|
|
1679
|
+
const toUpdatedBalance = add(toBalance, value);
|
|
1680
|
+
const updatedFromWallet = Object.assign({}, fromWallet, {
|
|
1681
|
+
balance: fromUpdatedBalance
|
|
1682
|
+
});
|
|
1683
|
+
await this.walletRepository.update(updatedFromWallet, ctx);
|
|
1684
|
+
const updatedToWallet = Object.assign({}, toWallet, {
|
|
1685
|
+
balance: toUpdatedBalance
|
|
1686
|
+
});
|
|
1687
|
+
if (newToWallet) {
|
|
1688
|
+
await this.walletRepository.create(updatedToWallet, ctx);
|
|
1689
|
+
} else {
|
|
1690
|
+
await this.walletRepository.update(updatedToWallet, ctx);
|
|
1691
|
+
}
|
|
1692
|
+
const transferEvent = {
|
|
1693
|
+
from: from,
|
|
1694
|
+
to: to,
|
|
1695
|
+
value: value
|
|
1696
|
+
};
|
|
1697
|
+
this.repo.refresh(ERC20Token, ERC20Events.TRANSFER, "", transferEvent, ctx).catch(e => log.error(`Failed to notify transfer: ${e}`));
|
|
1698
|
+
return true;
|
|
1699
|
+
}
|
|
1700
|
+
async Approve(context, spender, value) {
|
|
1701
|
+
const {ctx: ctx, ctxArgs: ctxArgs} = await this.logCtx([ context ], this.Approve);
|
|
1702
|
+
await this.CheckInitialized(ctx);
|
|
1703
|
+
const owner = ctx.identity.getID();
|
|
1704
|
+
let allowance = await this._getAllowance(owner, spender, ctx);
|
|
1705
|
+
const ownerWallet = await this.walletRepository.read(owner, ...ctxArgs);
|
|
1706
|
+
if (ownerWallet.balance < value) {
|
|
1707
|
+
throw new BalanceError(`client account ${owner} has insufficient funds.`);
|
|
1708
|
+
}
|
|
1709
|
+
if (allowance) {
|
|
1710
|
+
allowance.value = value;
|
|
1711
|
+
await this.allowanceRepository.update(allowance, ...ctxArgs);
|
|
1712
|
+
} else {
|
|
1713
|
+
allowance = new Allowance({
|
|
1714
|
+
owner: owner,
|
|
1715
|
+
spender: spender,
|
|
1716
|
+
value: value
|
|
1717
|
+
});
|
|
1718
|
+
await this.allowanceRepository.create(allowance, ...ctxArgs);
|
|
1719
|
+
}
|
|
1720
|
+
const approvalEvent = {
|
|
1721
|
+
owner: owner,
|
|
1722
|
+
spender: spender,
|
|
1723
|
+
value: value
|
|
1724
|
+
};
|
|
1725
|
+
this.repo.refresh(ERC20Token, ERC20Events.APPROVAL, "", approvalEvent, ctx);
|
|
1726
|
+
return true;
|
|
1727
|
+
}
|
|
1728
|
+
async Allowance(context, owner, spender) {
|
|
1729
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.Allowance);
|
|
1730
|
+
await this.CheckInitialized(ctx);
|
|
1731
|
+
const allowance = await this._getAllowance(owner, spender, ctx);
|
|
1732
|
+
if (!allowance) {
|
|
1733
|
+
throw new AllowanceError(`spender ${spender} has no allowance from ${owner}`);
|
|
1734
|
+
}
|
|
1735
|
+
return allowance.value;
|
|
1736
|
+
}
|
|
1737
|
+
async _getAllowance(owner, spender, ctx) {
|
|
1738
|
+
const allowanceCondition = core.Condition.and(core.Condition.attribute("owner").eq(owner), core.Condition.attribute("spender").eq(spender));
|
|
1739
|
+
const allowance = await this.allowanceRepository.select().where(allowanceCondition).execute(ctx);
|
|
1740
|
+
return allowance?.[0];
|
|
1741
|
+
}
|
|
1742
|
+
async Initialize(context, token) {
|
|
1743
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.Initialize);
|
|
1744
|
+
const tokens = await this.tokenRepository.select().execute(ctx);
|
|
1745
|
+
if (tokens.length > 0) {
|
|
1746
|
+
throw new core.AuthorizationError("contract options are already set, client is not authorized to change them");
|
|
1747
|
+
}
|
|
1748
|
+
token.owner = ctx.identity.getID();
|
|
1749
|
+
await this.tokenRepository.create(token, ctx);
|
|
1750
|
+
return true;
|
|
1751
|
+
}
|
|
1752
|
+
async CheckInitialized(context) {
|
|
1753
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.CheckInitialized);
|
|
1754
|
+
const tokens = await this.tokenRepository.select().execute(ctx);
|
|
1755
|
+
if (tokens.length == 0) {
|
|
1756
|
+
throw new NotInitializedError("contract options need to be set before calling any function, call Initialize() to initialize contract");
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
async Mint(context, amount) {
|
|
1760
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.Mint);
|
|
1761
|
+
await this.CheckInitialized(ctx);
|
|
1762
|
+
const minter = ctx.identity.getID();
|
|
1763
|
+
if (amount <= 0) {
|
|
1764
|
+
throw new dbDecorators.ValidationError("mint amount must be a positive integer");
|
|
1765
|
+
}
|
|
1766
|
+
let minterWallet;
|
|
1767
|
+
try {
|
|
1768
|
+
minterWallet = await this.walletRepository.read(minter, ctx);
|
|
1769
|
+
const currentBalance = minterWallet.balance;
|
|
1770
|
+
const updatedBalance = add(currentBalance, amount);
|
|
1771
|
+
const updatedminter = Object.assign({}, minterWallet, {
|
|
1772
|
+
balance: updatedBalance
|
|
1773
|
+
});
|
|
1774
|
+
await this.walletRepository.update(updatedminter, ctx);
|
|
1775
|
+
} catch (e) {
|
|
1776
|
+
if (e instanceof dbDecorators.BaseError) {
|
|
1777
|
+
if (e.code === 404) {
|
|
1778
|
+
const newWallet = new ERC20Wallet({
|
|
1779
|
+
id: minter,
|
|
1780
|
+
balance: amount,
|
|
1781
|
+
token: await this.TokenName(context)
|
|
1782
|
+
});
|
|
1783
|
+
await this.walletRepository.create(newWallet, ctx);
|
|
1784
|
+
} else {
|
|
1785
|
+
throw new dbDecorators.InternalError(e.message);
|
|
1786
|
+
}
|
|
1787
|
+
} else {
|
|
1788
|
+
throw new dbDecorators.InternalError(e);
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
const transferEvent = {
|
|
1792
|
+
from: "0x0",
|
|
1793
|
+
to: minter,
|
|
1794
|
+
value: amount
|
|
1795
|
+
};
|
|
1796
|
+
const eventHandler = this.repo.ObserverHandler();
|
|
1797
|
+
eventHandler.updateObservers(ERC20Token, ERC20Events.TRANSFER, "", transferEvent, ctx);
|
|
1798
|
+
}
|
|
1799
|
+
async Burn(context, amount) {
|
|
1800
|
+
const {log: log, ctx: ctx} = await this.logCtx([ context ], this.Burn);
|
|
1801
|
+
await this.CheckInitialized(ctx);
|
|
1802
|
+
const minter = ctx.identity.getID();
|
|
1803
|
+
const minterWallet = await this.walletRepository.read(minter, ctx);
|
|
1804
|
+
const currentBalance = minterWallet.balance;
|
|
1805
|
+
if (currentBalance < amount) {
|
|
1806
|
+
throw new BalanceError(`Minter has insufficient funds.`);
|
|
1807
|
+
}
|
|
1808
|
+
const updatedBalance = sub(currentBalance, amount);
|
|
1809
|
+
const updatedminter = Object.assign({}, minterWallet, {
|
|
1810
|
+
balance: updatedBalance
|
|
1811
|
+
});
|
|
1812
|
+
await this.walletRepository.update(updatedminter, ctx);
|
|
1813
|
+
log.info(`${amount} tokens were burned`);
|
|
1814
|
+
const transferEvent = {
|
|
1815
|
+
from: minter,
|
|
1816
|
+
to: "0x0",
|
|
1817
|
+
value: amount
|
|
1818
|
+
};
|
|
1819
|
+
const eventHandler = this.repo.ObserverHandler();
|
|
1820
|
+
eventHandler.updateObservers(ERC20Token, ERC20Events.TRANSFER, "", transferEvent, ctx);
|
|
1821
|
+
}
|
|
1822
|
+
async BurnFrom(context, account, amount) {
|
|
1823
|
+
const {log: log, ctx: ctx} = await this.logCtx([ context ], this.BurnFrom);
|
|
1824
|
+
await this.CheckInitialized(ctx);
|
|
1825
|
+
const accountWallet = await this.walletRepository.read(account, ctx);
|
|
1826
|
+
const currentBalance = accountWallet.balance;
|
|
1827
|
+
if (currentBalance < amount) {
|
|
1828
|
+
throw new BalanceError(`${account} has insufficient funds.`);
|
|
1829
|
+
}
|
|
1830
|
+
const updatedBalance = sub(currentBalance, amount);
|
|
1831
|
+
const updatedaccount = Object.assign({}, accountWallet, {
|
|
1832
|
+
balance: updatedBalance
|
|
1833
|
+
});
|
|
1834
|
+
await this.walletRepository.update(updatedaccount, ctx);
|
|
1835
|
+
log.info(`${amount} tokens were burned from ${account}`);
|
|
1836
|
+
const transferEvent = {
|
|
1837
|
+
from: account,
|
|
1838
|
+
to: "0x0",
|
|
1839
|
+
value: amount
|
|
1840
|
+
};
|
|
1841
|
+
const eventHandler = this.repo.ObserverHandler();
|
|
1842
|
+
eventHandler.updateObservers(ERC20Token, ERC20Events.TRANSFER, "", transferEvent, ctx);
|
|
1843
|
+
}
|
|
1844
|
+
async ClientAccountBalance(context) {
|
|
1845
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.TokenName);
|
|
1846
|
+
await this.CheckInitialized(ctx);
|
|
1847
|
+
const clientAccountID = ctx.identity.getID();
|
|
1848
|
+
const clientWallet = await this.walletRepository.read(clientAccountID, ctx);
|
|
1849
|
+
if (!clientWallet) {
|
|
1850
|
+
throw new BalanceError(`The account ${clientAccountID} does not exist`);
|
|
1851
|
+
}
|
|
1852
|
+
return clientWallet.balance;
|
|
1853
|
+
}
|
|
1854
|
+
async ClientAccountID(context) {
|
|
1855
|
+
const {ctx: ctx} = await this.logCtx([ context ], this.ClientAccountID);
|
|
1856
|
+
await this.CheckInitialized(ctx);
|
|
1857
|
+
const clientAccountID = ctx.identity.getID();
|
|
1858
|
+
return clientAccountID;
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
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);
|
|
1862
|
+
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);
|
|
1863
|
+
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);
|
|
1864
|
+
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);
|
|
1865
|
+
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);
|
|
1866
|
+
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);
|
|
1867
|
+
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);
|
|
1868
|
+
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);
|
|
1869
|
+
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);
|
|
1870
|
+
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);
|
|
1871
|
+
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);
|
|
1872
|
+
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);
|
|
1873
|
+
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);
|
|
1874
|
+
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);
|
|
1875
|
+
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);
|
|
1876
|
+
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);
|
|
1877
|
+
const contracts = [ FabricERC20Contract ];
|
|
1878
|
+
const VERSION = "0.1.45";
|
|
1879
|
+
const PACKAGE_NAME = "@decaf-ts/for-fabric";
|
|
1880
|
+
decoration.Metadata.registerLibrary(PACKAGE_NAME, VERSION);
|
|
1881
|
+
exports.ContractLogger = ContractLogger;
|
|
1882
|
+
exports.FabricContractAdapter = FabricContractAdapter;
|
|
1883
|
+
exports.FabricContractContext = FabricContractContext;
|
|
1884
|
+
exports.FabricContractPaginator = FabricContractPaginator;
|
|
1885
|
+
exports.FabricContractRepository = FabricContractRepository;
|
|
1886
|
+
exports.FabricContractRepositoryObservableHandler = FabricContractRepositoryObservableHandler;
|
|
1887
|
+
exports.FabricCrudContract = FabricCrudContract;
|
|
1888
|
+
exports.FabricStatement = FabricStatement;
|
|
1889
|
+
exports.PACKAGE_NAME = PACKAGE_NAME;
|
|
1890
|
+
exports.SerializedCrudContract = SerializedCrudContract;
|
|
1891
|
+
exports.VERSION = VERSION;
|
|
1892
|
+
exports.contracts = contracts;
|
|
1893
|
+
exports.createdByOnFabricCreateUpdate = createdByOnFabricCreateUpdate;
|
|
1894
|
+
exports.pkFabricOnCreate = pkFabricOnCreate;
|
|
1895
|
+
});
|
|
1896
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yLWZhYnJpYy5janMiLCJzb3VyY2VzIjpbIi4uL3NyYy9jb250cmFjdHMvQ29udHJhY3RDb250ZXh0LnRzIiwiLi4vc3JjL3NoYXJlZC9ldmVudHMudHMiLCIuLi9zcmMvY29udHJhY3RzL0ZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyLnRzIiwiLi4vc3JjL2NvbnRyYWN0cy9GYWJyaWNDb250cmFjdFJlcG9zaXRvcnkudHMiLCIuLi9zcmMvY29udHJhY3RzL0ZhYnJpY0NvbnRyYWN0U3RhdGVtZW50LnRzIiwiLi4vc3JjL2NvbnRyYWN0cy9GYWJyaWNDb250cmFjdFNlcXVlbmNlLnRzIiwiLi4vc3JjL3NoYXJlZC9jb25zdGFudHMudHMiLCIuLi9zcmMvc2hhcmVkL1NpbXBsZURldGVybWluaXN0aWNTZXJpYWxpemVyLnRzIiwiLi4vc3JjL2NvbnRyYWN0cy9sb2dnaW5nLnRzIiwiLi4vc3JjL2NvbnRyYWN0cy9GYWJyaWNDb250cmFjdFBhZ2luYXRvci50cyIsIi4uL3NyYy9zaGFyZWQvZXJyb3JzLnRzIiwiLi4vc3JjL2NvbnRyYWN0cy9Db250cmFjdEFkYXB0ZXIudHMiLCIuLi9zcmMvc2hhcmVkL0RldGVybWluaXN0aWNTZXJpYWxpemVyLnRzIiwiLi4vc3JjL2NvbnRyYWN0cy9jcnVkL2NydWQtY29udHJhY3QudHMiLCIuLi9zcmMvY29udHJhY3RzL2NydWQvc2VyaWFsaXplZC1jcnVkLWNvbnRyYWN0LnRzIiwiLi4vc3JjL3NoYXJlZC9tYXRoLnRzIiwiLi4vc3JjL2NvbnRyYWN0cy9lcmMyMC9tb2RlbHMudHMiLCIuLi9zcmMvc2hhcmVkL2RlY29yYXRvcnMudHMiLCIuLi9zcmMvc2hhcmVkL2VyYzIwL2VyYzIwLWNvbnN0YW50cy50cyIsIi4uL3NyYy9jb250cmFjdHMvZXJjMjAvZXJjMjBjb250cmFjdC50cyIsIi4uL3NyYy9jb250cmFjdHMvZXJjMjAvaW5kZXgudHMiLCIuLi9zcmMvdmVyc2lvbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb250ZXh0IH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdEZsYWdzIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IENoYWluY29kZVN0dWIsIENsaWVudElkZW50aXR5IH0gZnJvbSBcImZhYnJpYy1zaGltLWFwaVwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDb250ZXh0IGNsYXNzIGZvciBGYWJyaWMgY2hhaW5jb2RlIG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IFByb3ZpZGVzIGFjY2VzcyB0byBGYWJyaWMtc3BlY2lmaWMgY29udGV4dCBlbGVtZW50cyBsaWtlIHN0dWIsIGlkZW50aXR5LCBhbmQgbG9nZ2VyIHRvIGJlIHVzZWQgYnkgcmVwb3NpdG9yaWVzIGFuZCBhZGFwdGVycyBkdXJpbmcgY29udHJhY3QgZXhlY3V0aW9uLlxuICogQHRlbXBsYXRlIEYgLSBGbGFncyBzcGVjaWZpYyB0byBGYWJyaWMgY29udHJhY3Qgb3BlcmF0aW9uc1xuICogQHBhcmFtIHtvYmplY3R9IFthcmdzXSAtIE9wdGlvbmFsIGluaXRpYWxpemF0aW9uIGFyZ3VtZW50cyBwYXNzZWQgdG8gdGhlIGJhc2UgQ29udGV4dFxuICogQHJldHVybiB7dm9pZH1cbiAqIEBjbGFzcyBGYWJyaWNDb250cmFjdENvbnRleHRcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBJbiBhIEZhYnJpYyBjaGFpbmNvZGUgY29udHJhY3QgbWV0aG9kXG4gKiBjb25zdCBjb250ZXh0ID0gbmV3IEZhYnJpY0NvbnRyYWN0Q29udGV4dCgpO1xuICogLy8gT3B0aW9uYWxseSBzZXQgdmFsdWVzIHZpYSB0aGUgYmFzZSBDb250ZXh0IEFQSVxuICogY29udGV4dC5zZXQoJ3N0dWInLCBjdHguc3R1Yik7XG4gKiBjb250ZXh0LnNldCgnY2xpZW50SWRlbnRpdHknLCBjdHguY2xpZW50SWRlbnRpdHkpO1xuICogY29udGV4dC5zZXQoJ2xvZ2dlcicsIGNvbnRyYWN0TG9nZ2VyKTtcbiAqXG4gKiAvLyBBY2Nlc3MgY29udGV4dCBwcm9wZXJ0aWVzXG4gKiBjb25zdCB0aW1lc3RhbXAgPSBjb250ZXh0LnRpbWVzdGFtcDtcbiAqIGNvbnN0IGNyZWF0b3IgPSBjb250ZXh0LmlkZW50aXR5LmdldElEKCk7XG4gKiBgYGBcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ29udHJhY3RcbiAqICAgcGFydGljaXBhbnQgQ29udGV4dFxuICogICBwYXJ0aWNpcGFudCBMZWRnZXJcbiAqICAgQ29udHJhY3QtPj5Db250ZXh0OiBuZXcgRmFicmljQ29udHJhY3RDb250ZXh0KClcbiAqICAgQ29udHJhY3QtPj5Db250ZXh0OiBzZXQoJ3N0dWInfCdjbGllbnRJZGVudGl0eSd8J2xvZ2dlcicsIC4uLilcbiAqICAgQ29udGV4dC0tPj5Db250cmFjdDogdGltZXN0YW1wLCBpZGVudGl0eSwgbG9nZ2VyXG4gKiAgIENvbnRyYWN0LT4+TGVkZ2VyOiBJbnRlcmFjdCB2aWEgc3R1YlxuICovXG5leHBvcnQgY2xhc3MgRmFicmljQ29udHJhY3RDb250ZXh0IGV4dGVuZHMgQ29udGV4dDxGYWJyaWNDb250cmFjdEZsYWdzPiB7XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIG5ldyBGYWJyaWNDb250cmFjdENvbnRleHQgaW5zdGFuY2VcbiAgICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgdGhlIGNvbnRleHQgd2l0aCBGYWJyaWMtc3BlY2lmaWMgZmxhZ3NcbiAgICovXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEdldHMgdGhlIGNoYWluY29kZSBzdHViXG4gICAqIEBzdW1tYXJ5IFJldHVybnMgdGhlIENoYWluY29kZVN0dWIgaW5zdGFuY2UgZm9yIGludGVyYWN0aW5nIHdpdGggdGhlIGxlZGdlclxuICAgKiBAcmV0dXJuIHtDaGFpbmNvZGVTdHVifSBUaGUgY2hhaW5jb2RlIHN0dWJcbiAgICovXG4gIGdldCBzdHViKCk6IENoYWluY29kZVN0dWIge1xuICAgIHJldHVybiB0aGlzLmdldChcInN0dWJcIik7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEdldHMgdGhlIHRyYW5zYWN0aW9uIHRpbWVzdGFtcFxuICAgKiBAc3VtbWFyeSBPdmVycmlkZXMgdGhlIGJhc2UgdGltZXN0YW1wIGdldHRlciB0byB1c2UgdGhlIHN0dWIncyB0aW1lc3RhbXBcbiAgICogQHJldHVybiB7RGF0ZX0gVGhlIHRyYW5zYWN0aW9uIHRpbWVzdGFtcFxuICAgKi9cbiAgb3ZlcnJpZGUgZ2V0IHRpbWVzdGFtcCgpOiBEYXRlIHtcbiAgICByZXR1cm4gdGhpcy5zdHViLmdldERhdGVUaW1lc3RhbXAoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2V0cyB0aGUgY2xpZW50IGlkZW50aXR5XG4gICAqIEBzdW1tYXJ5IFJldHVybnMgdGhlIENsaWVudElkZW50aXR5IGluc3RhbmNlIGZvciB0aGUgdHJhbnNhY3Rpb24gc3VibWl0dGVyXG4gICAqIEByZXR1cm4ge0NsaWVudElkZW50aXR5fSBUaGUgY2xpZW50IGlkZW50aXR5XG4gICAqL1xuICBnZXQgaWRlbnRpdHkoKTogQ2xpZW50SWRlbnRpdHkge1xuICAgIHJldHVybiB0aGlzLmdldChcImlkZW50aXR5XCIpO1xuICB9XG5cbiAgb3ZlcnJpZGUgdG9TdHJpbmcoKSB7XG4gICAgcmV0dXJuIGBmYWJyaWMgY3R4JHt0aGlzLnN0dWIgPyBcIiB3aXRoIHN0dWJcIiA6IFwid2l0aG91dCBzdHViXCJ9YDtcbiAgfVxufVxuIiwiaW1wb3J0IHsgQnVsa0NydWRPcGVyYXRpb25LZXlzLCBPcGVyYXRpb25LZXlzIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEdlbmVyYXRlcyBhIEZhYnJpYyBldmVudCBuYW1lIGZyb20gY29tcG9uZW50c1xuICogQHN1bW1hcnkgQ3JlYXRlcyBhIHN0YW5kYXJkaXplZCBldmVudCBuYW1lIGJ5IGpvaW5pbmcgdGFibGUsIGV2ZW50LCBhbmQgb3B0aW9uYWwgb3duZXIgd2l0aCB1bmRlcnNjb3Jlc1xuICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlIC0gVGhlIHRhYmxlL2NvbGxlY3Rpb24gbmFtZVxuICogQHBhcmFtIHtPcGVyYXRpb25LZXlzIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzIHwgc3RyaW5nfSBldmVudCAtIFRoZSBldmVudCB0eXBlXG4gKiBAcGFyYW0ge3N0cmluZ30gW293bmVyXSAtIE9wdGlvbmFsIG93bmVyIGlkZW50aWZpZXJcbiAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGdlbmVyYXRlZCBldmVudCBuYW1lIGluIGZvcm1hdCBcInRhYmxlX2V2ZW50XCIgb3IgXCJ0YWJsZV9ldmVudF9vd25lclwiXG4gKiBAZnVuY3Rpb24gZ2VuZXJhdGVGYWJyaWNFdmVudE5hbWVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5zaGFyZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlRmFicmljRXZlbnROYW1lKFxuICB0YWJsZTogc3RyaW5nLFxuICBldmVudDogT3BlcmF0aW9uS2V5cyB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyB8IHN0cmluZyxcbiAgb3duZXI/OiBzdHJpbmdcbikge1xuICBjb25zdCBwYXJhbXMgPSBbdGFibGUsIGV2ZW50XTtcbiAgaWYgKG93bmVyKSBwYXJhbXMucHVzaChvd25lcik7XG4gIHJldHVybiBwYXJhbXMuam9pbihcIl9cIik7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFBhcnNlcyBhIEZhYnJpYyBldmVudCBuYW1lIGludG8gaXRzIGNvbXBvbmVudHNcbiAqIEBzdW1tYXJ5IFNwbGl0cyBhbiBldmVudCBuYW1lIGJ5IHVuZGVyc2NvcmVzIGFuZCBleHRyYWN0cyB0YWJsZSwgZXZlbnQsIGFuZCBvcHRpb25hbCBvd25lclxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgZXZlbnQgbmFtZSB0byBwYXJzZVxuICogQHJldHVybiB7e3RhYmxlOiBzdHJpbmcsIGV2ZW50OiBPcGVyYXRpb25LZXlzIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzIHwgc3RyaW5nLCBvd25lcjogc3RyaW5nfX0gVGhlIHBhcnNlZCBjb21wb25lbnRzIGFzIGEgc3RydWN0dXJlZCBvYmplY3RcbiAqIEB0aHJvd3Mge0ludGVybmFsRXJyb3J9IElmIHRoZSBldmVudCBuYW1lIGZvcm1hdCBpcyBpbnZhbGlkXG4gKiBAZnVuY3Rpb24gcGFyc2VFdmVudE5hbWVcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IFBhcnNlciBhcyBwYXJzZUV2ZW50TmFtZVxuICogICBDYWxsZXItPj5QYXJzZXI6IHBhcnNlRXZlbnROYW1lKG5hbWUpXG4gKiAgIFBhcnNlci0+PlBhcnNlcjogc3BsaXQgbmFtZSBieSBcIl9cIlxuICogICBhbHQgcGFydHMgbGVuZ3RoIGludmFsaWRcbiAqICAgICBQYXJzZXItLT4+Q2FsbGVyOiB0aHJvdyBJbnRlcm5hbEVycm9yXG4gKiAgIGVsc2VcbiAqICAgICBQYXJzZXItLT4+Q2FsbGVyOiB7IHRhYmxlLCBldmVudCwgb3duZXI/IH1cbiAqICAgZW5kXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuc2hhcmVkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYXJzZUV2ZW50TmFtZShuYW1lOiBzdHJpbmcpOiB7XG4gIHRhYmxlPzogc3RyaW5nO1xuICBldmVudDogT3BlcmF0aW9uS2V5cyB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyB8IHN0cmluZztcbiAgb3duZXI/OiBzdHJpbmc7XG59IHtcbiAgY29uc3QgcGFydHMgPSBuYW1lLnNwbGl0KFwiX1wiKTtcbiAgaWYgKHBhcnRzLmxlbmd0aCA8IDIgfHwgcGFydHMubGVuZ3RoID4gMylcbiAgICByZXR1cm4geyB0YWJsZTogdW5kZWZpbmVkLCBldmVudDogbmFtZSwgb3duZXI6IHVuZGVmaW5lZCB9O1xuICByZXR1cm4ge1xuICAgIHRhYmxlOiBwYXJ0c1swXSxcbiAgICBldmVudDogcGFydHNbMV0sXG4gICAgb3duZXI6IHBhcnRzWzJdLFxuICB9IGFzIHtcbiAgICB0YWJsZTogc3RyaW5nO1xuICAgIGV2ZW50OiBPcGVyYXRpb25LZXlzIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzIHwgc3RyaW5nO1xuICAgIG93bmVyPzogc3RyaW5nO1xuICB9O1xufVxuIiwiaW1wb3J0IHsgQnVsa0NydWRPcGVyYXRpb25LZXlzLCBPcGVyYXRpb25LZXlzIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQge1xuICBBZGFwdGVyLFxuICBDb250ZXh0dWFsQXJncyxcbiAgRXZlbnRJZHMsXG4gIE9ic2VydmVySGFuZGxlcixcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBnZW5lcmF0ZUZhYnJpY0V2ZW50TmFtZSB9IGZyb20gXCIuLi9zaGFyZWQvZXZlbnRzXCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdENvbnRleHQgfSBmcm9tIFwiLi9Db250cmFjdENvbnRleHRcIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE9ic2VydmVyIGhhbmRsZXIgZm9yIEZhYnJpYyBjaGFpbmNvZGUgZXZlbnRzXG4gKiBAc3VtbWFyeSBFbWl0cyBldmVudHMgb24gdGhlIEZhYnJpYyBsZWRnZXIgd2hlbiByZXBvc2l0b3J5IG9wZXJhdGlvbnMgb2NjdXJcbiAqIEBjbGFzcyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnlPYnNlcnZhYmxlSGFuZGxlclxuICogQGV4dGVuZHMge09ic2VydmVySGFuZGxlcn1cbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBJbiBhIEZhYnJpYyBjaGFpbmNvZGUgY29udHJhY3RcbiAqIGltcG9ydCB7IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyIH0gZnJvbSAnQGRlY2FmLXRzL2Zvci1mYWJyaWMnO1xuICpcbiAqIC8vIENyZWF0ZSBhIGhhbmRsZXIgd2l0aCBkZWZhdWx0IHN1cHBvcnRlZCBldmVudHNcbiAqIGNvbnN0IGhhbmRsZXIgPSBuZXcgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXIoKTtcbiAqXG4gKiAvLyBFbWl0IGFuIGV2ZW50XG4gKiBhd2FpdCBoYW5kbGVyLnVwZGF0ZU9ic2VydmVycyhcbiAqICAgbG9nZ2VyLFxuICogICAnYXNzZXRzJyxcbiAqICAgT3BlcmF0aW9uS2V5cy5DUkVBVEUsXG4gKiAgICdhc3NldDEnLFxuICogICBjb250ZXh0XG4gKiApO1xuICogYGBgXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IFJlcG9zaXRvcnlcbiAqICAgcGFydGljaXBhbnQgT2JzZXJ2YWJsZUhhbmRsZXJcbiAqICAgcGFydGljaXBhbnQgU3R1YlxuICogICBwYXJ0aWNpcGFudCBMZWRnZXJcbiAqXG4gKiAgIFJlcG9zaXRvcnktPj5PYnNlcnZhYmxlSGFuZGxlcjogdXBkYXRlT2JzZXJ2ZXJzKGxvZywgdGFibGUsIGV2ZW50LCBpZCwgY3R4KVxuICogICBPYnNlcnZhYmxlSGFuZGxlci0+Pk9ic2VydmFibGVIYW5kbGVyOiBDaGVjayBpZiBldmVudCBpcyBzdXBwb3J0ZWRcbiAqICAgT2JzZXJ2YWJsZUhhbmRsZXItPj5PYnNlcnZhYmxlSGFuZGxlcjogZ2VuZXJhdGVGYWJyaWNFdmVudE5hbWUodGFibGUsIGV2ZW50LCBvd25lcilcbiAqICAgT2JzZXJ2YWJsZUhhbmRsZXItPj5TdHViOiBzZXRFdmVudChldmVudE5hbWUsIHBheWxvYWQpXG4gKiAgIFN0dWItPj5MZWRnZXI6IFJlY29yZCBldmVudFxuICovXG5leHBvcnQgY2xhc3MgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXIgZXh0ZW5kcyBPYnNlcnZlckhhbmRsZXIge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXIgaW5zdGFuY2VcbiAgICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgdGhlIGhhbmRsZXIgd2l0aCBhIGxpc3Qgb2Ygc3VwcG9ydGVkIGV2ZW50c1xuICAgKiBAcGFyYW0ge0FycmF5PE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmc+fSBbc3VwcG9ydGVkRXZlbnRzXSAtIEV2ZW50cyB0aGF0IHdpbGwgdHJpZ2dlciBGYWJyaWMgZXZlbnRzXG4gICAqL1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHN1cHBvcnRlZEV2ZW50czogKFxuICAgICAgfCBPcGVyYXRpb25LZXlzXG4gICAgICB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5c1xuICAgICAgfCBzdHJpbmdcbiAgICApW10gPSBbXG4gICAgICBPcGVyYXRpb25LZXlzLkNSRUFURSxcbiAgICAgIE9wZXJhdGlvbktleXMuVVBEQVRFLFxuICAgICAgT3BlcmF0aW9uS2V5cy5ERUxFVEUsXG4gICAgICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuQ1JFQVRFX0FMTCxcbiAgICAgIEJ1bGtDcnVkT3BlcmF0aW9uS2V5cy5VUERBVEVfQUxMLFxuICAgICAgQnVsa0NydWRPcGVyYXRpb25LZXlzLkRFTEVURV9BTEwsXG4gICAgXVxuICApIHtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIG9ic2VydmVycyBieSBlbWl0dGluZyBGYWJyaWMgZXZlbnRzXG4gICAqIEBzdW1tYXJ5IEVtaXRzIGV2ZW50cyBvbiB0aGUgRmFicmljIGxlZGdlciBmb3Igc3VwcG9ydGVkIGV2ZW50IHR5cGVzXG4gICAqIEBwYXJhbSB7TG9nZ2VyfSBsb2cgLSBMb2dnZXIgaW5zdGFuY2UgZm9yIGRlYnVnZ2luZ1xuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGUgLSBUaGUgdGFibGUvY29sbGVjdGlvbiBuYW1lXG4gICAqIEBwYXJhbSB7T3BlcmF0aW9uS2V5cyB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyB8IHN0cmluZ30gZXZlbnQgLSBUaGUgZXZlbnQgdHlwZVxuICAgKiBAcGFyYW0ge0V2ZW50SWRzfSBpZCAtIFRoZSBldmVudCBpZGVudGlmaWVyXG4gICAqIEBwYXJhbSB7RmFicmljQ29udHJhY3RDb250ZXh0fSBjdHggLSBUaGUgRmFicmljIGNvbnRyYWN0IGNvbnRleHRcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtvd25lcl0gLSBPcHRpb25hbCBvd25lciBpZGVudGlmaWVyIGZvciB0aGUgZXZlbnRcbiAgICogQHBhcmFtIHtvYmplY3QgfCBzdHJpbmcgfCB1bmRlZmluZWR9IFtvd25lcl0gLSBPcHRpb25hbCBwYXlsb2FkIGZvciB0aGUgZXZlbnRcbiAgICpcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIGV2ZW50IGlzIGVtaXR0ZWRcbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIHVwZGF0ZU9ic2VydmVycyhcbiAgICBjbGF6ejogc3RyaW5nIHwgQ29uc3RydWN0b3I8YW55PixcbiAgICBldmVudDogT3BlcmF0aW9uS2V5cyB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyB8IHN0cmluZyxcbiAgICBpZDogRXZlbnRJZHMsXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8RmFicmljQ29udHJhY3RDb250ZXh0PlxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSBBZGFwdGVyLmxvZ0N0eDxGYWJyaWNDb250cmFjdENvbnRleHQ+KFxuICAgICAgYXJncyxcbiAgICAgIHRoaXMudXBkYXRlT2JzZXJ2ZXJzXG4gICAgKTtcbiAgICBjb25zdCB7IHN0dWIgfSA9IGN0eDtcbiAgICBjb25zdCBbb3duZXIsIHBheWxvYWRdID0gYXJncztcbiAgICBjb25zdCB0YWJsZSA9IHR5cGVvZiBjbGF6eiA9PT0gXCJzdHJpbmdcIiA/IGNsYXp6IDogY2xhenoubmFtZTtcbiAgICBpZiAodGhpcy5zdXBwb3J0ZWRFdmVudHMuaW5kZXhPZihldmVudCkgIT09IC0xKSB7XG4gICAgICBsb2cuZGVidWcoYEVtaXR0aW5nICR7ZXZlbnR9IGV2ZW50YCk7XG4gICAgICBjb25zdCBldmVudE5hbWUgPSBnZW5lcmF0ZUZhYnJpY0V2ZW50TmFtZSh0YWJsZSwgZXZlbnQsIG93bmVyKTtcbiAgICAgIHN0dWIuc2V0RXZlbnQoZXZlbnROYW1lLCBCdWZmZXIuZnJvbShKU09OLnN0cmluZ2lmeSh7IGlkOiBpZCB9KSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzdHViLnNldEV2ZW50KGV2ZW50LCBCdWZmZXIuZnJvbShKU09OLnN0cmluZ2lmeShwYXlsb2FkKSkpO1xuICAgIH1cbiAgfVxufVxuIiwiaW1wb3J0IHtcbiAgUmVwb3NpdG9yeSxcbiAgT2JzZXJ2ZXJIYW5kbGVyLFxuICBFdmVudElkcyxcbiAgQ29udGV4dHVhbEFyZ3MsXG4gIE1heWJlQ29udGV4dHVhbEFyZyxcbiAgUXVlcnlFcnJvcixcbiAgQ29udGV4dCxcbiAgUGVyc2lzdGVuY2VLZXlzLFxuICBQcmVwYXJlZFN0YXRlbWVudEtleXMsXG4gIE9yZGVyRGlyZWN0aW9uLFxuICBTZXJpYWxpemVkUGFnZSxcbiAgUGFnaW5hdG9yLFxuICBEaXJlY3Rpb25MaW1pdE9mZnNldCxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdENvbnRleHQgfSBmcm9tIFwiLi9Db250cmFjdENvbnRleHRcIjtcbmltcG9ydCB7IE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXIgfSBmcm9tIFwiLi9GYWJyaWNDb250cmFjdFJlcG9zaXRvcnlPYnNlcnZhYmxlSGFuZGxlclwiO1xuaW1wb3J0IHtcbiAgQmFzZUVycm9yLFxuICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMsXG4gIEludGVybmFsRXJyb3IsXG4gIE9wZXJhdGlvbktleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY0NvbnRyYWN0QWRhcHRlciB9IGZyb20gXCIuL0NvbnRyYWN0QWRhcHRlclwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZXBvc2l0b3J5IGZvciBIeXBlcmxlZGdlciBGYWJyaWMgY2hhaW5jb2RlIG1vZGVsc1xuICogQHN1bW1hcnkgUHJvdmlkZXMgQ1JVRCBvcGVyYXRpb25zIGZvciBtb2RlbHMgd2l0aGluIEZhYnJpYyBjaGFpbmNvZGUgY29udHJhY3RzXG4gKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAdGVtcGxhdGUgTWFuZ29RdWVyeSAtIFF1ZXJ5IHR5cGUgZm9yIENvdWNoREItbGlrZSBxdWVyaWVzXG4gKiBAdGVtcGxhdGUgRmFicmljQ29udHJhY3RBZGFwdGVyIC0gQWRhcHRlciB0eXBlIGZvciBGYWJyaWMgY29udHJhY3Qgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIEZhYnJpY0NvbnRyYWN0RmxhZ3MgLSBGbGFncyBzcGVjaWZpYyB0byBGYWJyaWMgY29udHJhY3Qgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIEZhYnJpY0NvbnRyYWN0Q29udGV4dCAtIENvbnRleHQgdHlwZSBmb3IgRmFicmljIGNvbnRyYWN0IG9wZXJhdGlvbnNcbiAqXG4gKiBAcGFyYW0ge0ZhYnJpY0NvbnRyYWN0QWRhcHRlcn0gW2FkYXB0ZXJdIC0gVGhlIGFkYXB0ZXIgZm9yIGludGVyYWN0aW5nIHdpdGggdGhlIHN0YXRlIGRhdGFiYXNlXG4gKiBAcGFyYW0ge0NvbnN0cnVjdG9yPE0+fSBbY2xhenpdIC0gVGhlIG1vZGVsIGNvbnN0cnVjdG9yXG4gKiBAcGFyYW0ge0FycmF5PE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmc+fSBbdHJhY2tlZEV2ZW50c10gLSBFdmVudHMgdG8gdHJhY2sgZm9yIG9ic2VydmVyIG5vdGlmaWNhdGlvbnNcbiAqXG4gKiBAY2xhc3MgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5XG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gSW4gYSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRyYWN0IGNsYXNzXG4gKiBpbXBvcnQgeyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnksIEZhYnJpY0NvbnRyYWN0QWRhcHRlciB9IGZyb20gJ0BkZWNhZi10cy9mb3ItZmFicmljJztcbiAqXG4gKiBAdGFibGUoJ2Fzc2V0cycpXG4gKiBjbGFzcyBBc3NldCBleHRlbmRzIE1vZGVsIHtcbiAqICAgQGlkKClcbiAqICAgaWQ6IHN0cmluZztcbiAqXG4gKiAgIEBwcm9wZXJ0eSgpXG4gKiAgIGRhdGE6IHN0cmluZztcbiAqIH1cbiAqXG4gKiBleHBvcnQgY2xhc3MgTXlDb250cmFjdCBleHRlbmRzIENvbnRyYWN0IHtcbiAqICAgcHJpdmF0ZSBhZGFwdGVyID0gbmV3IEZhYnJpY0NvbnRyYWN0QWRhcHRlcigpO1xuICogICBwcml2YXRlIHJlcG9zaXRvcnk6IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxBc3NldD47XG4gKlxuICogICBjb25zdHJ1Y3RvcigpIHtcbiAqICAgICBzdXBlcignTXlDb250cmFjdCcpO1xuICogICAgIHRoaXMucmVwb3NpdG9yeSA9IG5ldyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnk8QXNzZXQ+KHRoaXMuYWRhcHRlciwgQXNzZXQpO1xuICogICB9XG4gKlxuICogICBAVHJhbnNhY3Rpb24oKVxuICogICBhc3luYyBjcmVhdGVBc3NldChjdHg6IENvbnRleHQsIGlkOiBzdHJpbmcsIGRhdGE6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICogICAgIGNvbnN0IGFzc2V0ID0gbmV3IEFzc2V0KCk7XG4gKiAgICAgYXNzZXQuaWQgPSBpZDtcbiAqICAgICBhc3NldC5kYXRhID0gZGF0YTtcbiAqXG4gKiAgICAgYXdhaXQgdGhpcy5yZXBvc2l0b3J5LmNyZWF0ZShhc3NldCwgeyBzdHViOiBjdHguc3R1YiB9KTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENvbnRyYWN0XG4gKiAgIHBhcnRpY2lwYW50IFJlcG9zaXRvcnlcbiAqICAgcGFydGljaXBhbnQgQWRhcHRlclxuICogICBwYXJ0aWNpcGFudCBTdGF0ZURCXG4gKlxuICogICBDb250cmFjdC0+PlJlcG9zaXRvcnk6IGNyZWF0ZShtb2RlbCwgY3R4KVxuICogICBSZXBvc2l0b3J5LT4+QWRhcHRlcjogcHJlcGFyZShtb2RlbCwgcGspXG4gKiAgIFJlcG9zaXRvcnktPj5BZGFwdGVyOiBjcmVhdGUodGFibGVOYW1lLCBpZCwgcmVjb3JkLCB0cmFuc2llbnQsIGN0eClcbiAqICAgQWRhcHRlci0+PlN0YXRlREI6IHB1dFN0YXRlKGlkLCBzZXJpYWxpemVkRGF0YSlcbiAqICAgU3RhdGVEQi0tPj5BZGFwdGVyOiBTdWNjZXNzXG4gKiAgIEFkYXB0ZXItLT4+UmVwb3NpdG9yeTogcmVjb3JkXG4gKiAgIFJlcG9zaXRvcnktPj5BZGFwdGVyOiByZXZlcnQocmVjb3JkLCBjbGFzcywgcGssIGlkLCB0cmFuc2llbnQpXG4gKiAgIEFkYXB0ZXItLT4+UmVwb3NpdG9yeTogbW9kZWxcbiAqICAgUmVwb3NpdG9yeS0tPj5Db250cmFjdDogbW9kZWxcbiAqL1xuZXhwb3J0IGNsYXNzIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxNIGV4dGVuZHMgTW9kZWw+IGV4dGVuZHMgUmVwb3NpdG9yeTxcbiAgTSxcbiAgRmFicmljQ29udHJhY3RBZGFwdGVyXG4+IHtcbiAgcHJvdGVjdGVkIG92ZXJyaWRlIF9vdmVycmlkZXMgPSBPYmplY3QuYXNzaWduKHt9LCBzdXBlcltcIl9vdmVycmlkZXNcIl0sIHtcbiAgICBpZ25vcmVWYWxpZGF0aW9uOiBmYWxzZSxcbiAgICBpZ25vcmVIYW5kbGVyczogZmFsc2UsXG4gICAgYWxsb3dSYXdTdGF0ZW1lbnRzOiB0cnVlLFxuICAgIGZvcmNlUHJlcGFyZVNpbXBsZVF1ZXJpZXM6IGZhbHNlLFxuICAgIGZvcmNlUHJlcGFyZUNvbXBsZXhRdWVyaWVzOiBmYWxzZSxcbiAgfSk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgYWRhcHRlcj86IEZhYnJpY0NvbnRyYWN0QWRhcHRlcixcbiAgICBjbGF6ej86IENvbnN0cnVjdG9yPE0+LFxuICAgIHByb3RlY3RlZCB0cmFja2VkRXZlbnRzPzogKE9wZXJhdGlvbktleXMgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMgfCBzdHJpbmcpW11cbiAgKSB7XG4gICAgc3VwZXIoYWRhcHRlciwgY2xhenopO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgcGFnaW5hdGVCeShcbiAgICBrZXk6IGtleW9mIE0sXG4gICAgb3JkZXI6IE9yZGVyRGlyZWN0aW9uLFxuICAgIHJlZjogT21pdDxEaXJlY3Rpb25MaW1pdE9mZnNldCwgXCJkaXJlY3Rpb25cIj4gPSB7XG4gICAgICBvZmZzZXQ6IDEsXG4gICAgICBsaW1pdDogMTAsXG4gICAgfSxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8RmFicmljQ29udHJhY3RDb250ZXh0PlxuICApOiBQcm9taXNlPFNlcmlhbGl6ZWRQYWdlPE0+PiB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHByZWZlci1jb25zdFxuICAgIGxldCB7IG9mZnNldCwgYm9va21hcmssIGxpbWl0IH0gPSByZWY7XG4gICAgaWYgKCFvZmZzZXQgJiYgIWJvb2ttYXJrKVxuICAgICAgdGhyb3cgbmV3IFF1ZXJ5RXJyb3IoYFBhZ2luYXRlQnkgbmVlZHMgYSBwYWdlIG9yIGEgYm9va21hcmtgKTtcbiAgICBjb25zdCBjb250ZXh0QXJncyA9IGF3YWl0IENvbnRleHQuYXJncyhcbiAgICAgIFByZXBhcmVkU3RhdGVtZW50S2V5cy5QQUdFX0JZLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIGFyZ3MsXG4gICAgICB0aGlzLmFkYXB0ZXIsXG4gICAgICB0aGlzLl9vdmVycmlkZXMgfHwge31cbiAgICApO1xuICAgIGNvbnN0IHsgbG9nLCBjdHhBcmdzIH0gPSB0aGlzLmxvZ0N0eChjb250ZXh0QXJncy5hcmdzLCB0aGlzLnBhZ2luYXRlQnkpO1xuICAgIGxvZy52ZXJib3NlKFxuICAgICAgYHBhZ2luYXRpbmcgJHtNb2RlbC50YWJsZU5hbWUodGhpcy5jbGFzcyl9IHdpdGggcGFnZSBzaXplICR7bGltaXR9YFxuICAgICk7XG5cbiAgICBsZXQgcGFnaW5hdG9yOiBQYWdpbmF0b3I8TT47XG4gICAgaWYgKGJvb2ttYXJrKSB7XG4gICAgICBwYWdpbmF0b3IgPSBhd2FpdCB0aGlzLm92ZXJyaWRlKHtcbiAgICAgICAgZm9yY2VQcmVwYXJlQ29tcGxleFF1ZXJpZXM6IGZhbHNlLFxuICAgICAgICBmb3JjZVByZXBhcmVTaW1wbGVRdWVyaWVzOiBmYWxzZSxcbiAgICAgIH0gYXMgYW55KVxuICAgICAgICAuc2VsZWN0KClcbiAgICAgICAgLndoZXJlKHRoaXMuYXR0cihNb2RlbC5wayh0aGlzLmNsYXNzKSkuZ3QoYm9va21hcmspKVxuICAgICAgICAub3JkZXJCeShba2V5LCBvcmRlcl0pXG4gICAgICAgIC5wYWdpbmF0ZShsaW1pdCBhcyBudW1iZXIsIC4uLmN0eEFyZ3MpO1xuICAgICAgb2Zmc2V0ID0gMTtcbiAgICB9IGVsc2UgaWYgKG9mZnNldCkge1xuICAgICAgcGFnaW5hdG9yID0gYXdhaXQgdGhpcy5vdmVycmlkZSh7XG4gICAgICAgIGZvcmNlUHJlcGFyZUNvbXBsZXhRdWVyaWVzOiBmYWxzZSxcbiAgICAgICAgZm9yY2VQcmVwYXJlU2ltcGxlUXVlcmllczogZmFsc2UsXG4gICAgICB9IGFzIGFueSlcbiAgICAgICAgLnNlbGVjdCgpXG4gICAgICAgIC5vcmRlckJ5KFtrZXksIG9yZGVyXSlcbiAgICAgICAgLnBhZ2luYXRlKGxpbWl0IGFzIG51bWJlciwgLi4uY3R4QXJncyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBRdWVyeUVycm9yKGBQYWdpbmF0ZUJ5IG5lZWRzIGEgcGFnZSBvciBhIGJvb2ttYXJrYCk7XG4gICAgfVxuICAgIGNvbnN0IHBhZ2VkID0gYXdhaXQgcGFnaW5hdG9yLnBhZ2Uob2Zmc2V0LCAuLi5jdHhBcmdzKTtcbiAgICByZXR1cm4gcGFnaW5hdG9yLnNlcmlhbGl6ZShwYWdlZCkgYXMgU2VyaWFsaXplZFBhZ2U8TT47XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBzdGF0ZW1lbnQoXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxGYWJyaWNDb250cmFjdENvbnRleHQ+XG4gICkge1xuICAgIGlmICghUmVwb3NpdG9yeS5zdGF0ZW1lbnRzKHRoaXMsIG5hbWUgYXMga2V5b2YgdHlwZW9mIHRoaXMpKVxuICAgICAgdGhyb3cgbmV3IFF1ZXJ5RXJyb3IoYEludmFsaWQgcHJlcGFyZWQgc3RhdGVtZW50IHJlcXVlc3RlZCAke25hbWV9YCk7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3MoXG4gICAgICBQZXJzaXN0ZW5jZUtleXMuU1RBVEVNRU5ULFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIGFyZ3MsXG4gICAgICB0aGlzLmFkYXB0ZXIsXG4gICAgICB0aGlzLl9vdmVycmlkZXMgfHwge31cbiAgICApO1xuICAgIGlmIChjb250ZXh0QXJncy5jb250ZXh0LmxvZ2dlcikge1xuICAgICAgY29udGV4dEFyZ3MuY29udGV4dC5sb2dnZXIuaW5mbyhgUmVwbyBzdGF0ZW1lbnQ6ICR7bmFtZX0gKyAke2FyZ3N9YCk7XG4gICAgfVxuICAgIGNvbnN0IHsgbG9nLCBjdHhBcmdzIH0gPSB0aGlzLmxvZ0N0eChjb250ZXh0QXJncy5hcmdzLCB0aGlzLnN0YXRlbWVudCk7XG4gICAgbG9nLnZlcmJvc2UoYEV4ZWN1dGluZyBwcmVwYXJlZCBzdGF0ZW1lbnQgJHtuYW1lfSB3aXRoIGFyZ3MgJHtjdHhBcmdzfWApO1xuXG4gICAgbGV0IHJlc3VsdDogYW55O1xuICAgIHRyeSB7XG4gICAgICByZXN1bHQgPSBhd2FpdCAodGhpcyBhcyBhbnkpW25hbWVdKC4uLmN0eEFyZ3MpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIGlmIChlIGluc3RhbmNlb2YgQmFzZUVycm9yKSB0aHJvdyBlO1xuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBGYWlsZWQgdG8gZXhlY3V0ZSBwcmVwYXJlZCBzdGF0ZW1lbnQgJHtuYW1lfSB3aXRoIGFyZ3MgJHtjdHhBcmdzfTogJHtlfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2V0cyB0aGUgb2JzZXJ2ZXIgaGFuZGxlciBmb3IgdGhpcyByZXBvc2l0b3J5XG4gICAqIEBzdW1tYXJ5IFJldHVybnMgYSBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnlPYnNlcnZhYmxlSGFuZGxlciBpbnN0YW5jZVxuICAgKiBAcmV0dXJuIHtPYnNlcnZlckhhbmRsZXJ9IFRoZSBvYnNlcnZlciBoYW5kbGVyXG4gICAqL1xuICBvdmVycmlkZSBPYnNlcnZlckhhbmRsZXIoKTogT2JzZXJ2ZXJIYW5kbGVyIHtcbiAgICByZXR1cm4gbmV3IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFVwZGF0ZXMgb2JzZXJ2ZXJzIGJhc2VkIG9uIHRyYWNrZWQgZXZlbnRzXG4gICAqIEBzdW1tYXJ5IEZpbHRlcnMgZXZlbnRzIGJhc2VkIG9uIHRyYWNrZWRFdmVudHMgYW5kIGRlbGVnYXRlcyB0byB0aGUgcGFyZW50IG1ldGhvZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGUgLSBUaGUgdGFibGUvY29sbGVjdGlvbiBuYW1lXG4gICAqIEBwYXJhbSB7T3BlcmF0aW9uS2V5cyB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyB8IHN0cmluZ30gZXZlbnQgLSBUaGUgZXZlbnQgdHlwZVxuICAgKiBAcGFyYW0ge0V2ZW50SWRzfSBpZCAtIFRoZSBldmVudCBpZGVudGlmaWVyXG4gICAqIEBwYXJhbSB7RmFicmljQ29udHJhY3RDb250ZXh0fSBjdHggLSBUaGUgRmFicmljIGNvbnRyYWN0IGNvbnRleHRcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIG9ic2VydmVycyBhcmUgdXBkYXRlZFxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgdXBkYXRlT2JzZXJ2ZXJzKFxuICAgIHRhYmxlOiBDb25zdHJ1Y3RvcjxNPiB8IHN0cmluZyxcbiAgICBldmVudDogT3BlcmF0aW9uS2V5cyB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyB8IHN0cmluZyxcbiAgICBpZDogRXZlbnRJZHMsXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8RmFicmljQ29udHJhY3RDb250ZXh0PlxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMudHJhY2tlZEV2ZW50cyB8fCB0aGlzLnRyYWNrZWRFdmVudHMuaW5kZXhPZihldmVudCkgIT09IC0xKVxuICAgICAgcmV0dXJuIGF3YWl0IHN1cGVyLnVwZGF0ZU9ic2VydmVycyh0YWJsZSwgZXZlbnQsIGlkLCAuLi5hcmdzKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQge1xuICBDb3VjaERCQWRhcHRlcixcbiAgQ291Y2hEQkdyb3VwT3BlcmF0b3IsXG4gIENvdWNoREJLZXlzLFxuICBDb3VjaERCT3BlcmF0b3IsXG4gIE1hbmdvT3BlcmF0b3IsXG4gIE1hbmdvUXVlcnksXG4gIE1hbmdvU2VsZWN0b3IsXG59IGZyb20gXCJAZGVjYWYtdHMvZm9yLWNvdWNoZGJcIjtcbmltcG9ydCB7IEZhYnJpY0NvbnRyYWN0Q29udGV4dCB9IGZyb20gXCIuL0NvbnRyYWN0Q29udGV4dFwiO1xuaW1wb3J0IHsgQ291Y2hEQlN0YXRlbWVudCB9IGZyb20gXCJAZGVjYWYtdHMvZm9yLWNvdWNoZGJcIjtcbmltcG9ydCB7IENvbmRpdGlvbiwgT3JkZXJEaXJlY3Rpb24gfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IE1ldGFkYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBEQktleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gU3RhdGVtZW50IHdyYXBwZXIgZm9yIGV4ZWN1dGluZyBNYW5nbyBxdWVyaWVzIHdpdGhpbiBGYWJyaWMgY29udHJhY3RzXG4gKiBAc3VtbWFyeSBCcmlkZ2VzIENvdWNoREItc3R5bGUgcXVlcmllcyB0byBGYWJyaWMgdmlhIHRoZSBGYWJyaWNDb250cmFjdEFkYXB0ZXIsIGhhbmRsaW5nIGlkZW50aXR5IGFuZCBwcmltYXJ5IGtleSBwcm9qZWN0aW9uIHdoZW4gbmVlZGVkLlxuICogQHRlbXBsYXRlIE0gLSBNb2RlbCB0eXBlIHRoaXMgc3RhdGVtZW50IG9wZXJhdGVzIG9uXG4gKiBAdGVtcGxhdGUgUiAtIFJlc3VsdCB0eXBlIHJldHVybmVkIGJ5IHRoZSBzdGF0ZW1lbnRcbiAqIEBwYXJhbSB7RmFicmljQ29udHJhY3RBZGFwdGVyfSBhZGFwdGVyIC0gVGhlIEZhYnJpYyBjb250cmFjdCBhZGFwdGVyIHVzZWQgZm9yIHJhdyBleGVjdXRpb25cbiAqIEBwYXJhbSB7RmFicmljQ29udHJhY3RDb250ZXh0fSBjdHggLSBUaGUgRmFicmljIGNvbnRyYWN0IGNvbnRleHQgY2Fycnlpbmcgc3R1YiBhbmQgaWRlbnRpdHlcbiAqIEByZXR1cm4ge3ZvaWR9XG4gKiBAY2xhc3MgRmFicmljU3RhdGVtZW50XG4gKiBAZXhhbXBsZVxuICogY29uc3Qgc3RtdCA9IG5ldyBGYWJyaWNTdGF0ZW1lbnQ8TXlNb2RlbCwgTXlNb2RlbFtdPihhZGFwdGVyLCBjdHgpO1xuICogY29uc3QgcmVzdWx0ID0gYXdhaXQgc3RtdC5yYXc8TXlNb2RlbFtdPih7IHNlbGVjdG9yOiB7IHR5cGU6ICdNeU1vZGVsJyB9IH0pO1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBBcHBcbiAqICAgcGFydGljaXBhbnQgU3RhdGVtZW50XG4gKiAgIHBhcnRpY2lwYW50IEFkYXB0ZXJcbiAqICAgcGFydGljaXBhbnQgTGVkZ2VyXG4gKiAgIEFwcC0+PlN0YXRlbWVudDogcmF3KHsgc2VsZWN0b3IgfSlcbiAqICAgU3RhdGVtZW50LT4+QWRhcHRlcjogYWRhcHRlci5yYXcobWFuZ28sIHRydWUsIGN0eClcbiAqICAgQWRhcHRlci0+PkxlZGdlcjogRXZhbHVhdGUgcXVlcnlcbiAqICAgQWRhcHRlci0tPj5TdGF0ZW1lbnQ6IHJvd3NcbiAqICAgU3RhdGVtZW50LS0+PkFwcDogbW9kZWxzXG4gKi9cbmV4cG9ydCBjbGFzcyBGYWJyaWNTdGF0ZW1lbnQ8TSBleHRlbmRzIE1vZGVsLCBSPiBleHRlbmRzIENvdWNoREJTdGF0ZW1lbnQ8XG4gIE0sXG4gIENvdWNoREJBZGFwdGVyPGFueSwgdm9pZCwgRmFicmljQ29udHJhY3RDb250ZXh0PixcbiAgUlxuPiB7XG4gIGNvbnN0cnVjdG9yKGFkYXB0ZXI6IENvdWNoREJBZGFwdGVyPGFueSwgdm9pZCwgRmFicmljQ29udHJhY3RDb250ZXh0Pikge1xuICAgIHN1cGVyKGFkYXB0ZXIpO1xuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgcmF3PFI+KHJhd0lucHV0OiBNYW5nb1F1ZXJ5LCAuLi5hcmdzOiBhbnlbXSk6IFByb21pc2U8Uj4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnJhdyk7XG5cbiAgICBjb25zdCByZXN1bHRzOiBhbnlbXSA9IGF3YWl0IHRoaXMuYWRhcHRlci5yYXcocmF3SW5wdXQsIHRydWUsIGN0eCk7XG5cbiAgICBjb25zdCBwa0F0dHIgPSBNb2RlbC5wayh0aGlzLmZyb21TZWxlY3Rvcik7XG4gICAgY29uc3QgdHlwZSA9IE1ldGFkYXRhLmdldChcbiAgICAgIHRoaXMuZnJvbVNlbGVjdG9yLFxuICAgICAgTWV0YWRhdGEua2V5KERCS2V5cy5JRCwgcGtBdHRyIGFzIHN0cmluZylcbiAgICApPy50eXBlO1xuXG4gICAgaWYgKCF0aGlzLnNlbGVjdFNlbGVjdG9yKVxuICAgICAgcmV0dXJuIHJlc3VsdHMubWFwKChyKSA9PiB0aGlzLnByb2Nlc3NSZWNvcmQociwgcGtBdHRyLCB0eXBlLCBjdHgpKSBhcyBSO1xuICAgIHJldHVybiByZXN1bHRzIGFzIFI7XG4gIH1cblxuICBvdmVycmlkZSBidWlsZCgpOiBNYW5nb1F1ZXJ5IHtcbiAgICBjb25zdCBzZWxlY3RvcnM6IE1hbmdvU2VsZWN0b3IgPSB7fTtcbiAgICBzZWxlY3RvcnNbQ291Y2hEQktleXMuVEFCTEVdID0ge307XG4gICAgc2VsZWN0b3JzW0NvdWNoREJLZXlzLlRBQkxFXSA9IE1vZGVsLnRhYmxlTmFtZSh0aGlzLmZyb21TZWxlY3Rvcik7XG4gICAgY29uc3QgcXVlcnk6IE1hbmdvUXVlcnkgPSB7IHNlbGVjdG9yOiBzZWxlY3RvcnMgfTtcbiAgICBpZiAodGhpcy5zZWxlY3RTZWxlY3RvcikgcXVlcnkuZmllbGRzID0gdGhpcy5zZWxlY3RTZWxlY3RvciBhcyBzdHJpbmdbXTtcblxuICAgIGlmICh0aGlzLndoZXJlQ29uZGl0aW9uKSB7XG4gICAgICBjb25zdCBjb25kaXRpb246IE1hbmdvU2VsZWN0b3IgPSB0aGlzLnBhcnNlQ29uZGl0aW9uKFxuICAgICAgICBDb25kaXRpb24uYW5kKFxuICAgICAgICAgIHRoaXMud2hlcmVDb25kaXRpb24sXG4gICAgICAgICAgQ29uZGl0aW9uLmF0dHJpYnV0ZTxNPihDb3VjaERCS2V5cy5UQUJMRSBhcyBrZXlvZiBNKS5lcShcbiAgICAgICAgICAgIHF1ZXJ5LnNlbGVjdG9yW0NvdWNoREJLZXlzLlRBQkxFXVxuICAgICAgICAgIClcbiAgICAgICAgKVxuICAgICAgKS5zZWxlY3RvcjtcbiAgICAgIGNvbnN0IHNlbGVjdG9yS2V5cyA9IE9iamVjdC5rZXlzKGNvbmRpdGlvbikgYXMgTWFuZ29PcGVyYXRvcltdO1xuICAgICAgaWYgKFxuICAgICAgICBzZWxlY3RvcktleXMubGVuZ3RoID09PSAxICYmXG4gICAgICAgIE9iamVjdC52YWx1ZXMoQ291Y2hEQkdyb3VwT3BlcmF0b3IpLmluZGV4T2Yoc2VsZWN0b3JLZXlzWzBdKSAhPT0gLTFcbiAgICAgIClcbiAgICAgICAgc3dpdGNoIChzZWxlY3RvcktleXNbMF0pIHtcbiAgICAgICAgICBjYXNlIENvdWNoREJHcm91cE9wZXJhdG9yLkFORDpcbiAgICAgICAgICAgIGNvbmRpdGlvbltDb3VjaERCR3JvdXBPcGVyYXRvci5BTkRdID0gW1xuICAgICAgICAgICAgICAuLi5PYmplY3QudmFsdWVzKFxuICAgICAgICAgICAgICAgIGNvbmRpdGlvbltDb3VjaERCR3JvdXBPcGVyYXRvci5BTkRdIGFzIE1hbmdvU2VsZWN0b3JcbiAgICAgICAgICAgICAgKS5yZWR1Y2UoKGFjY3VtOiBNYW5nb1NlbGVjdG9yW10sIHZhbDogYW55KSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKHZhbCk7XG4gICAgICAgICAgICAgICAgaWYgKGtleXMubGVuZ3RoICE9PSAxKVxuICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICAgICBcIlRvbyBtYW55IGtleXMgaW4gcXVlcnkgc2VsZWN0b3IuIHNob3VsZCBiZSBvbmVcIlxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBjb25zdCBrID0ga2V5c1swXTtcbiAgICAgICAgICAgICAgICBpZiAoayA9PT0gQ291Y2hEQkdyb3VwT3BlcmF0b3IuQU5EKVxuICAgICAgICAgICAgICAgICAgYWNjdW0ucHVzaCguLi4odmFsW2tdIGFzIGFueVtdKSk7XG4gICAgICAgICAgICAgICAgZWxzZSBhY2N1bS5wdXNoKHZhbCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFjY3VtO1xuICAgICAgICAgICAgICB9LCBbXSksXG4gICAgICAgICAgICBdO1xuICAgICAgICAgICAgcXVlcnkuc2VsZWN0b3IgPSBjb25kaXRpb247XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlIENvdWNoREJHcm91cE9wZXJhdG9yLk9SOiB7XG4gICAgICAgICAgICBjb25zdCBzOiBSZWNvcmQ8YW55LCBhbnk+ID0ge307XG4gICAgICAgICAgICBzW0NvdWNoREJHcm91cE9wZXJhdG9yLkFORF0gPSBbXG4gICAgICAgICAgICAgIGNvbmRpdGlvbixcbiAgICAgICAgICAgICAgLi4uT2JqZWN0LmVudHJpZXMocXVlcnkuc2VsZWN0b3IpLm1hcCgoW2tleSwgdmFsXSkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlc3VsdDogUmVjb3JkPGFueSwgYW55PiA9IHt9O1xuICAgICAgICAgICAgICAgIHJlc3VsdFtrZXldID0gdmFsO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIHF1ZXJ5LnNlbGVjdG9yID0gcztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVGhpcyBzaG91bGQgYmUgaW1wb3NzaWJsZVwiKTtcbiAgICAgICAgfVxuICAgICAgZWxzZSB7XG4gICAgICAgIE9iamVjdC5lbnRyaWVzKGNvbmRpdGlvbikuZm9yRWFjaCgoW2tleSwgdmFsXSkgPT4ge1xuICAgICAgICAgIGlmIChxdWVyeS5zZWxlY3RvcltrZXldKVxuICAgICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgICBgQSAke2tleX0gcXVlcnkgcGFyYW0gaXMgYWJvdXQgdG8gYmUgb3ZlcnJpZGRlbjogJHtxdWVyeS5zZWxlY3RvcltrZXldfSBieSAke3ZhbH1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgIHF1ZXJ5LnNlbGVjdG9yW2tleV0gPSB2YWw7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICh0aGlzLm9yZGVyQnlTZWxlY3Rvcikge1xuICAgICAgcXVlcnkuc29ydCA9IHF1ZXJ5LnNvcnQgfHwgW107XG4gICAgICBxdWVyeS5zZWxlY3RvciA9IHF1ZXJ5LnNlbGVjdG9yIHx8ICh7fSBhcyBNYW5nb1NlbGVjdG9yKTtcbiAgICAgIGNvbnN0IFtzZWxlY3RvciwgdmFsdWVdID0gdGhpcy5vcmRlckJ5U2VsZWN0b3IgYXMgW1xuICAgICAgICBzdHJpbmcsXG4gICAgICAgIE9yZGVyRGlyZWN0aW9uLFxuICAgICAgXTtcbiAgICAgIGNvbnN0IHJlYzogYW55ID0ge307XG4gICAgICByZWNbc2VsZWN0b3JdID0gdmFsdWU7XG4gICAgICAocXVlcnkuc29ydCBhcyBhbnlbXSkucHVzaChyZWMgYXMgYW55KTtcbiAgICAgIGlmICghcXVlcnkuc2VsZWN0b3Jbc2VsZWN0b3JdKSB7XG4gICAgICAgIHF1ZXJ5LnNlbGVjdG9yW3NlbGVjdG9yXSA9IHt9IGFzIE1hbmdvU2VsZWN0b3I7XG4gICAgICAgIChxdWVyeS5zZWxlY3RvcltzZWxlY3Rvcl0gYXMgTWFuZ29TZWxlY3RvcilbQ291Y2hEQk9wZXJhdG9yLkJJR0dFUl0gPVxuICAgICAgICAgIG51bGw7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHRoaXMubGltaXRTZWxlY3RvcikgcXVlcnkubGltaXQgPSB0aGlzLmxpbWl0U2VsZWN0b3I7XG5cbiAgICBpZiAodGhpcy5vZmZzZXRTZWxlY3RvcikgcXVlcnkuc2tpcCA9IHRoaXMub2Zmc2V0U2VsZWN0b3I7XG5cbiAgICByZXR1cm4gcXVlcnk7XG4gIH1cbn1cbiIsImltcG9ydCB7XG4gIENvbmZsaWN0RXJyb3IsXG4gIEludGVybmFsRXJyb3IsXG4gIE5vdEZvdW5kRXJyb3IsXG4gIE9wZXJhdGlvbktleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHtcbiAgQWRhcHRlcixcbiAgQ29udGV4dCxcbiAgTWF5YmVDb250ZXh0dWFsQXJnLFxuICBTZXF1ZW5jZSxcbiAgU2VxdWVuY2VNb2RlbCxcbiAgU2VxdWVuY2VPcHRpb25zLFxuICBTZXJpYWwsXG4gIFVuc3VwcG9ydGVkRXJyb3IsXG4gIFVVSUQsXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgc3R5bGUgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQWJzdHJhY3QgYmFzZSBjbGFzcyBmb3Igc2VxdWVuY2UgZ2VuZXJhdGlvblxuICogQHN1bW1hcnkgUHJvdmlkZXMgYSBmcmFtZXdvcmsgZm9yIGdlbmVyYXRpbmcgc2VxdWVudGlhbCB2YWx1ZXMgKGxpa2UgcHJpbWFyeSBrZXlzKSBpbiB0aGUgcGVyc2lzdGVuY2UgbGF5ZXIuXG4gKiBJbXBsZW1lbnRhdGlvbnMgb2YgdGhpcyBjbGFzcyBoYW5kbGUgdGhlIHNwZWNpZmljcyBvZiBob3cgc2VxdWVuY2VzIGFyZSBzdG9yZWQgYW5kIGluY3JlbWVudGVkIGluIGRpZmZlcmVudFxuICogZGF0YWJhc2Ugc3lzdGVtcy5cbiAqIEBwYXJhbSB7U2VxdWVuY2VPcHRpb25zfSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgc2VxdWVuY2UgZ2VuZXJhdG9yXG4gKiBAY2xhc3MgU2VxdWVuY2VcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBFeGFtcGxlIGltcGxlbWVudGF0aW9uIGZvciBhIHNwZWNpZmljIGRhdGFiYXNlXG4gKiBjbGFzcyBQb3N0Z3Jlc1NlcXVlbmNlIGV4dGVuZHMgU2VxdWVuY2Uge1xuICogICBjb25zdHJ1Y3RvcihvcHRpb25zOiBTZXF1ZW5jZU9wdGlvbnMpIHtcbiAqICAgICBzdXBlcihvcHRpb25zKTtcbiAqICAgfVxuICpcbiAqICAgYXN5bmMgbmV4dCgpOiBQcm9taXNlPG51bWJlcj4ge1xuICogICAgIC8vIEltcGxlbWVudGF0aW9uIHRvIGdldCBuZXh0IHZhbHVlIGZyb20gUG9zdGdyZVNRTCBzZXF1ZW5jZVxuICogICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMub3B0aW9ucy5leGVjdXRvci5yYXcoYFNFTEVDVCBuZXh0dmFsKCcke3RoaXMub3B0aW9ucy5uYW1lfScpYCk7XG4gKiAgICAgcmV0dXJuIHBhcnNlSW50KHJlc3VsdC5yb3dzWzBdLm5leHR2YWwpO1xuICogICB9XG4gKlxuICogICBhc3luYyBjdXJyZW50KCk6IFByb21pc2U8bnVtYmVyPiB7XG4gKiAgICAgLy8gSW1wbGVtZW50YXRpb24gdG8gZ2V0IGN1cnJlbnQgdmFsdWUgZnJvbSBQb3N0Z3JlU1FMIHNlcXVlbmNlXG4gKiAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5vcHRpb25zLmV4ZWN1dG9yLnJhdyhgU0VMRUNUIGN1cnJ2YWwoJyR7dGhpcy5vcHRpb25zLm5hbWV9JylgKTtcbiAqICAgICByZXR1cm4gcGFyc2VJbnQocmVzdWx0LnJvd3NbMF0uY3VycnZhbCk7XG4gKiAgIH1cbiAqXG4gKiAgIGFzeW5jIHJhbmdlKGNvdW50OiBudW1iZXIpOiBQcm9taXNlPG51bWJlcltdPiB7XG4gKiAgICAgLy8gSW1wbGVtZW50YXRpb24gdG8gZ2V0IGEgcmFuZ2Ugb2YgdmFsdWVzXG4gKiAgICAgY29uc3QgdmFsdWVzOiBudW1iZXJbXSA9IFtdO1xuICogICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY291bnQ7IGkrKykge1xuICogICAgICAgdmFsdWVzLnB1c2goYXdhaXQgdGhpcy5uZXh0KCkpO1xuICogICAgIH1cbiAqICAgICByZXR1cm4gdmFsdWVzO1xuICogICB9XG4gKiB9XG4gKlxuICogLy8gVXNhZ2VcbiAqIGNvbnN0IHNlcXVlbmNlID0gbmV3IFBvc3RncmVzU2VxdWVuY2Uoe1xuICogICBuYW1lOiAndXNlcl9pZF9zZXEnLFxuICogICBleGVjdXRvcjogZGJFeGVjdXRvclxuICogfSk7XG4gKlxuICogY29uc3QgbmV4dElkID0gYXdhaXQgc2VxdWVuY2UubmV4dCgpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBGYWJyaWNDb250cmFjdFNlcXVlbmNlIGV4dGVuZHMgU2VxdWVuY2Uge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgc2VxdWVuY2UgaW5zdGFuY2VcbiAgICogQHN1bW1hcnkgUHJvdGVjdGVkIGNvbnN0cnVjdG9yIHRoYXQgaW5pdGlhbGl6ZXMgdGhlIHNlcXVlbmNlIHdpdGggdGhlIHByb3ZpZGVkIG9wdGlvbnNcbiAgICovXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IFNlcXVlbmNlT3B0aW9ucywgYWRhcHRlcjogQWRhcHRlcjxhbnksIGFueSwgYW55Pikge1xuICAgIHN1cGVyKG9wdGlvbnMsIGFkYXB0ZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgdmFsdWUgb2YgdGhlIHNlcXVlbmNlXG4gICAqIEBzdW1tYXJ5IEdldHMgdGhlIGN1cnJlbnQgdmFsdWUgb2YgdGhlIHNlcXVlbmNlIGZyb20gc3RvcmFnZS4gSWYgdGhlIHNlcXVlbmNlXG4gICAqIGRvZXNuJ3QgZXhpc3QgeWV0LCBpdCByZXR1cm5zIHRoZSBjb25maWd1cmVkIHN0YXJ0aW5nIHZhbHVlLlxuICAgKiBAcmV0dXJuIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBjdXJyZW50IHNlcXVlbmNlIHZhbHVlXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyBjdXJyZW50KFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxhbnk+XG4gICk6IFByb21pc2U8c3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50PiB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3M8YW55LCBhbnk+KFxuICAgICAgT3BlcmF0aW9uS2V5cy5SRUFELFxuICAgICAgU2VxdWVuY2VNb2RlbCxcbiAgICAgIGFyZ3MsXG4gICAgICB0aGlzLmFkYXB0ZXJcbiAgICApO1xuICAgIGNvbnN0IGN0eCA9IGNvbnRleHRBcmdzLmNvbnRleHQ7XG4gICAgY29uc3QgeyBuYW1lLCBzdGFydFdpdGggfSA9IHRoaXMub3B0aW9ucztcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc2VxdWVuY2U6IFNlcXVlbmNlTW9kZWwgPSBhd2FpdCB0aGlzLnJlcG8ucmVhZChuYW1lIGFzIHN0cmluZywgY3R4KTtcbiAgICAgIHJldHVybiB0aGlzLnBhcnNlKHNlcXVlbmNlLmN1cnJlbnQgYXMgc3RyaW5nIHwgbnVtYmVyKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIGNvbnN0IGxvZyA9IGN0eC5sb2dnZXIuZm9yKHRoaXMuY3VycmVudCk7XG4gICAgICBpZiAoZSBpbnN0YW5jZW9mIE5vdEZvdW5kRXJyb3IpIHtcbiAgICAgICAgbGV0IGNhY2hlZEN1cnJlbnQ6IGFueTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBsb2cuZGVidWcoXG4gICAgICAgICAgICBgVHJ5aW5nIHRvIHJlc29sdmUgY3VycmVudCBzZXF1ZW5jZSAke25hbWV9IHZhbHVlIGZyb20gY29udGV4dGBcbiAgICAgICAgICApO1xuICAgICAgICAgIGNhY2hlZEN1cnJlbnQgPSBjdHguZ2V0KG5hbWUpO1xuICAgICAgICAgIGxvZy5kZWJ1ZyhcbiAgICAgICAgICAgIGBSZXRyaWV2ZWQgY2FjaGVkIGN1cnJlbnQgdmFsdWUgZm9yIHNlcXVlbmNlICR7bmFtZX06ICR7Y2FjaGVkQ3VycmVudH1gXG4gICAgICAgICAgKTtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgICBsb2cuaW5mbyhgTm8gY2FjaGVkIHZhbHVlIGZvciBzZXF1ZW5jZSAke25hbWV9IGluIGNvbnRleHRgKTtcbiAgICAgICAgICBjYWNoZWRDdXJyZW50ID0gc3RhcnRXaXRoO1xuICAgICAgICB9XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMucGFyc2UoY2FjaGVkQ3VycmVudCk7XG4gICAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgYEZhaWxlZCB0byBwYXJzZSBpbml0aWFsIHZhbHVlIGZvciBzZXF1ZW5jZSAke3N0YXJ0V2l0aH06ICR7ZX1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBGYWlsZWQgdG8gcmV0cmlldmUgY3VycmVudCB2YWx1ZSBmb3Igc2VxdWVuY2UgJHtuYW1lfTogJHtlfWBcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBJbmNyZW1lbnRzIHRoZSBzZXF1ZW5jZSB2YWx1ZVxuICAgKiBAc3VtbWFyeSBJbmNyZWFzZXMgdGhlIGN1cnJlbnQgc2VxdWVuY2UgdmFsdWUgYnkgdGhlIHNwZWNpZmllZCBhbW91bnQgYW5kIHBlcnNpc3RzXG4gICAqIHRoZSBuZXcgdmFsdWUgdG8gc3RvcmFnZS4gVGhpcyBtZXRob2QgaGFuZGxlcyBib3RoIG51bWVyaWMgYW5kIEJpZ0ludCBzZXF1ZW5jZSB0eXBlcy5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudW1iZXIgfCBiaWdpbnR9IGN1cnJlbnQgLSBUaGUgY3VycmVudCB2YWx1ZSBvZiB0aGUgc2VxdWVuY2VcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtjb3VudF0gLSBPcHRpb25hbCBhbW91bnQgdG8gaW5jcmVtZW50IGJ5LCBkZWZhdWx0cyB0byB0aGUgc2VxdWVuY2UncyBpbmNyZW1lbnRCeSB2YWx1ZVxuICAgKiBAcmV0dXJuIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBuZXcgc2VxdWVuY2UgdmFsdWUgYWZ0ZXIgaW5jcmVtZW50aW5nXG4gICAqL1xuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgaW5jcmVtZW50KFxuICAgIGNvdW50OiBudW1iZXIgfCB1bmRlZmluZWQsXG4gICAgY3R4OiBDb250ZXh0PGFueT5cbiAgKTogUHJvbWlzZTxzdHJpbmcgfCBudW1iZXIgfCBiaWdpbnQ+IHtcbiAgICBjb25zdCBsb2cgPSBjdHgubG9nZ2VyLmZvcih0aGlzLmluY3JlbWVudCk7XG4gICAgY29uc3QgeyB0eXBlLCBpbmNyZW1lbnRCeSwgbmFtZSB9ID0gdGhpcy5vcHRpb25zO1xuICAgIGlmICghbmFtZSkgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJTZXF1ZW5jZSBuYW1lIGlzIHJlcXVpcmVkXCIpO1xuICAgIGxvZy5pbmZvKGBPYnRhaW5pbmcgc2VxdWVuY2UgbG9jayBmb3Igc2VxdWVuY2UgJHtuYW1lfWApO1xuICAgIHJldHVybiBGYWJyaWNDb250cmFjdFNlcXVlbmNlLmxvY2suZXhlY3V0ZShhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB0b0luY3JlbWVudEJ5ID0gY291bnQgfHwgaW5jcmVtZW50Qnk7XG4gICAgICBpZiAodG9JbmNyZW1lbnRCeSAlIGluY3JlbWVudEJ5ICE9PSAwKVxuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICBgVmFsdWUgdG8gaW5jcmVtZW50IGRvZXMgbm90IGNvbnNpZGVyIHRoZSBpbmNyZW1lbnRCeSBzZXR0aW5nOiAke2luY3JlbWVudEJ5fWBcbiAgICAgICAgKTtcbiAgICAgIGNvbnN0IHR5cGVOYW1lID1cbiAgICAgICAgdHlwZW9mIHR5cGUgPT09IFwiZnVuY3Rpb25cIiAmJiAodHlwZSBhcyBhbnkpPy5uYW1lXG4gICAgICAgICAgPyAodHlwZSBhcyBhbnkpLm5hbWVcbiAgICAgICAgICA6IHR5cGU7XG4gICAgICBjb25zdCBjdXJyZW50VmFsdWUgPSBhd2FpdCB0aGlzLmN1cnJlbnQoY3R4KTtcblxuICAgICAgYXN5bmMgZnVuY3Rpb24gcmV0dXJuQW5kQ2FjaGUoXG4gICAgICAgIHJlczogU2VxdWVuY2VNb2RlbCB8IFByb21pc2U8U2VxdWVuY2VNb2RlbD5cbiAgICAgICkge1xuICAgICAgICBpZiAocmVzIGluc3RhbmNlb2YgUHJvbWlzZSkgcmVzID0gYXdhaXQgcmVzO1xuICAgICAgICBjdHgubG9nZ2VyXG4gICAgICAgICAgLmZvcihyZXR1cm5BbmRDYWNoZSlcbiAgICAgICAgICAuaW5mbyhgU3RvcmluZyBuZXcgJHtuYW1lfSBzZXEgdmFsdWUgaW4gY2FjaGU6ICR7cmVzLmN1cnJlbnR9YCk7XG4gICAgICAgIGN0eC5jYWNoZS5wdXQobmFtZSBhcyBzdHJpbmcsIHJlcy5jdXJyZW50KTtcbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgIH1cblxuICAgICAgY29uc3QgcGVyZm9ybVVwc2VydCA9IGFzeW5jIChcbiAgICAgICAgbmV4dDogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50XG4gICAgICApOiBQcm9taXNlPFNlcXVlbmNlTW9kZWw+ID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICByZXR1cm4gYXdhaXQgcmV0dXJuQW5kQ2FjaGUoXG4gICAgICAgICAgICB0aGlzLnJlcG8udXBkYXRlKFxuICAgICAgICAgICAgICBuZXcgU2VxdWVuY2VNb2RlbCh7IGlkOiBuYW1lLCBjdXJyZW50OiBuZXh0IH0pLFxuICAgICAgICAgICAgICBjdHhcbiAgICAgICAgICAgIClcbiAgICAgICAgICApO1xuICAgICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgICBpZiAoZSBpbnN0YW5jZW9mIE5vdEZvdW5kRXJyb3IpIHtcbiAgICAgICAgICAgIGxvZy5kZWJ1ZyhcbiAgICAgICAgICAgICAgYFNlcXVlbmNlIGNyZWF0ZSAke25hbWV9IGN1cnJlbnQ9JHtjdXJyZW50VmFsdWUgYXMgYW55fSBuZXh0PSR7bmV4dCBhcyBhbnl9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiByZXR1cm5BbmRDYWNoZShcbiAgICAgICAgICAgICAgdGhpcy5yZXBvLmNyZWF0ZShcbiAgICAgICAgICAgICAgICBuZXcgU2VxdWVuY2VNb2RlbCh7IGlkOiBuYW1lLCBjdXJyZW50OiBuZXh0IH0pLFxuICAgICAgICAgICAgICAgIGN0eFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICBjb25zdCBpbmNyZW1lbnRTZXJpYWwgPSAoXG4gICAgICAgIGJhc2U6IHN0cmluZyB8IG51bWJlciB8IGJpZ2ludFxuICAgICAgKTogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50ID0+IHtcbiAgICAgICAgc3dpdGNoICh0eXBlTmFtZSkge1xuICAgICAgICAgIGNhc2UgTnVtYmVyLm5hbWU6XG4gICAgICAgICAgICByZXR1cm4gKHRoaXMucGFyc2UoYmFzZSkgYXMgbnVtYmVyKSArIHRvSW5jcmVtZW50Qnk7XG4gICAgICAgICAgY2FzZSBCaWdJbnQubmFtZTpcbiAgICAgICAgICAgIHJldHVybiAodGhpcy5wYXJzZShiYXNlKSBhcyBiaWdpbnQpICsgQmlnSW50KHRvSW5jcmVtZW50QnkpO1xuICAgICAgICAgIGNhc2UgU3RyaW5nLm5hbWU6XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wYXJzZShiYXNlKTtcbiAgICAgICAgICBjYXNlIFwic2VyaWFsXCI6XG4gICAgICAgICAgICByZXR1cm4gU2VyaWFsLmluc3RhbmNlLmdlbmVyYXRlKGJhc2UgYXMgc3RyaW5nKTtcbiAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJTaG91bGQgbmV2ZXIgaGFwcGVuXCIpO1xuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICBpZiAodHlwZU5hbWUgPT09IFwidXVpZFwiKSB7XG4gICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgY29uc3QgbmV4dCA9IFVVSUQuaW5zdGFuY2UuZ2VuZXJhdGUoY3VycmVudFZhbHVlIGFzIHN0cmluZyk7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBlcmZvcm1VcHNlcnQobmV4dCk7XG4gICAgICAgICAgICBsb2cuZGVidWcoXG4gICAgICAgICAgICAgIGBTZXF1ZW5jZSB1dWlkIGluY3JlbWVudCAke25hbWV9IGN1cnJlbnQ9JHtjdXJyZW50VmFsdWUgYXMgYW55fSBuZXh0PSR7bmV4dCBhcyBhbnl9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQuY3VycmVudCBhcyBzdHJpbmcgfCBudW1iZXIgfCBiaWdpbnQ7XG4gICAgICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICAgICAgaWYgKGUgaW5zdGFuY2VvZiBDb25mbGljdEVycm9yKSBjb250aW51ZTtcbiAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG5leHQgPSBpbmNyZW1lbnRTZXJpYWwoY3VycmVudFZhbHVlKTtcbiAgICAgIGNvbnN0IHNlcSA9IGF3YWl0IHBlcmZvcm1VcHNlcnQobmV4dCk7XG4gICAgICBsb2cuZGVidWcoXG4gICAgICAgIGBTZXF1ZW5jZS5pbmNyZW1lbnQgJHtuYW1lfSBjdXJyZW50PSR7Y3VycmVudFZhbHVlIGFzIGFueX0gbmV4dD0ke25leHQgYXMgYW55fWBcbiAgICAgICk7XG4gICAgICByZXR1cm4gc2VxLmN1cnJlbnQgYXMgc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50O1xuICAgIH0sIG5hbWUpO1xuICB9XG59XG4iLCIvKipcbiAqIEBkZXNjcmlwdGlvbiBLZXlzIHVzZWQgdG8gbWFyayBGYWJyaWMtc3BlY2lmaWMgbW9kZWwgbWV0YWRhdGFcbiAqIEBzdW1tYXJ5IEVudW1lcmF0aW9uIG9mIHNwZWNpYWwga2V5cyB1c2VkIGJ5IHRoZSBzZXJpYWxpemF0aW9uIGxheWVyIHRvIHBlcnNpc3QgRmFicmljLXJlbGF0ZWQgZmxhZ3Mgb24gbW9kZWxzXG4gKiBAZW51bSB7c3RyaW5nfVxuICogQHJlYWRvbmx5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuc2hhcmVkXG4gKi9cbmV4cG9ydCBlbnVtIEZhYnJpY01vZGVsS2V5cyB7XG4gIC8qKiBQcml2YXRlIGRhdGEgbWFya2VyIHVzZWQgdG8gdGFnIHByb3BlcnRpZXMgb3IgbW9kZWxzIGZvciBGYWJyaWMgcHJpdmF0ZSBjb2xsZWN0aW9ucyAqL1xuICBQUklWQVRFID0gXCJwcml2YXRlXCIsXG4gIFNIQVJFRCA9IFwic2hhcmVkXCIsXG4gIC8qKiBOYW1lc3BhY2UgcHJlZml4IHVzZWQgZm9yIEZhYnJpYy1zcGVjaWZpYyBtZXRhZGF0YSBrZXlzICovXG4gIEZBQlJJQyA9IFwiZmFicmljLlwiLFxuICBPV05FREJZID0gXCJvd25lZC1ieVwiLFxuICBUUkFOU0FDVElPTl9JRCA9IFwidHJhbnNhY3Rpb24taWRcIixcbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIFN1cHBvcnRlZCBpZGVudGl0eSB0eXBlcyBmb3IgRmFicmljIGNyZWRlbnRpYWxzXG4gKiBAc3VtbWFyeSBFbnVtZXJhdGlvbiBvZiBpZGVudGl0eSBmb3JtYXRzIHJlY29nbml6ZWQgYnkgdGhpcyBsaWJyYXJ5XG4gKiBAZW51bSB7c3RyaW5nfVxuICogQHJlYWRvbmx5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1mYWJyaWMuc2hhcmVkXG4gKi9cbmV4cG9ydCBlbnVtIElkZW50aXR5VHlwZSB7XG4gIC8qKiBTdGFuZGFyZCBYLjUwOSBpZGVudGl0eSBmb3JtYXQgdXNlZCBieSBIeXBlcmxlZGdlciBGYWJyaWMgKi9cbiAgWDUwOSA9IFwiWC41MDlcIixcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gU3RyaW5nIGlkZW50aWZpZXIgZm9yIHRoZSBGYWJyaWMgYWRhcHRlciBmbGF2b3VyXG4gKiBAc3VtbWFyeSBVc2VkIHRvIHRhZyBhZGFwdGVycy9yZXBvc2l0b3JpZXMgdGhhdCBvcGVyYXRlIGFnYWluc3QgSHlwZXJsZWRnZXIgRmFicmljXG4gKiBAY29uc3QgRmFicmljRmxhdm91clxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLnNoYXJlZFxuICovXG5leHBvcnQgY29uc3QgRmFicmljRmxhdm91ciA9IFwiaGxmLWZhYnJpY1wiO1xuIiwiaW1wb3J0IHtcbiAgSlNPTlNlcmlhbGl6ZXIsXG4gIE1vZGVsLFxuICBNb2RlbEtleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yLCBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuXG5leHBvcnQgY2xhc3MgU2ltcGxlRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXI8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbj4gZXh0ZW5kcyBKU09OU2VyaWFsaXplcjxNPiB7XG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIG92ZXJyaWRlIGRlc2VyaWFsaXplKHN0cjogc3RyaW5nLCB0YWJsZU5hbWU/OiBzdHJpbmcpOiBNIHtcbiAgICBjb25zdCBkZXNlcmlhbGl6YXRpb24gPSBKU09OLnBhcnNlKHN0cik7XG4gICAgLy8gY29uc3QgY2xhc3NOYW1lID0gdGFibGVOYW1lO1xuICAgIC8vIGlmICghY2xhc3NOYW1lKVxuICAgIC8vICAgdGhyb3cgbmV3IEVycm9yKFwiQ291bGQgbm90IGZpbmQgY2xhc3MgcmVmZXJlbmNlIGluIHNlcmlhbGl6ZWQgbW9kZWxcIik7XG5cbiAgICAvLyAvLyB0aGlzIHdpbGwgcmV0dXJuIHVuZGVmaW5lZCB2YWx1ZXNcbiAgICAvLyBjb25zdCBtb2RlbDogTSA9IE1vZGVsLmJ1aWxkKGRlc2VyaWFsaXphdGlvbiwgY2xhc3NOYW1lKSBhcyB1bmtub3duIGFzIE07XG5cbiAgICAvLyAvLyBQb3B1bGF0ZSBNb2RlbFxuICAgIC8vIGNvbnN0IHByb2Nlc3NlZERlc2VhbGl6YXRpb24gPSBPYmplY3Qua2V5cyhtb2RlbCkucmVkdWNlKFxuICAgIC8vICAgKGFjY3VtOiBNLCBrZXkpID0+IHtcbiAgICAvLyAgICAgKGFjY3VtIGFzIFJlY29yZDxzdHJpbmcsIGFueT4pW2tleV0gPVxuICAgIC8vICAgICAgIGRlc2VyaWFsaXphdGlvbltSZXBvc2l0b3J5LmNvbHVtbihhY2N1bSwga2V5KV07XG4gICAgLy8gICAgIHJldHVybiBhY2N1bTtcbiAgICAvLyAgIH0sXG4gICAgLy8gICBtb2RlbFxuICAgIC8vICk7XG5cbiAgICAvLyBjb25zdCByZXN1bHQgPSBNb2RlbC5idWlsZChcbiAgICAvLyAgIHByb2Nlc3NlZERlc2VhbGl6YXRpb24sXG4gICAgLy8gICBjbGFzc05hbWVcbiAgICAvLyApIGFzIHVua25vd24gYXMgTTtcblxuICAgIC8vIHJldHVybiByZXN1bHQ7XG4gICAgcmV0dXJuIGRlc2VyaWFsaXphdGlvbjtcbiAgfVxuXG4gIG92ZXJyaWRlIHNlcmlhbGl6ZShtb2RlbDogTSwgcHV0QW5jaG9yID0gdHJ1ZSk6IHN0cmluZyB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICBjb25zdCBzdHJpbmdpZnkgPSByZXF1aXJlKFwianNvbi1zdHJpbmdpZnktZGV0ZXJtaW5pc3RpY1wiKTtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuICAgIGNvbnN0IHNvcnRLZXlzUmVjdXJzaXZlID0gcmVxdWlyZShcInNvcnQta2V5cy1yZWN1cnNpdmVcIik7XG4gICAgY29uc3QgcHJlU2VyaWFsaXphdGlvbiA9IHRoaXMucHJlU2VyaWFsaXplKG1vZGVsLCBwdXRBbmNob3IpO1xuICAgIHJldHVybiBzdHJpbmdpZnkoc29ydEtleXNSZWN1cnNpdmUocHJlU2VyaWFsaXphdGlvbikpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIHByZVNlcmlhbGl6ZShtb2RlbDogTSwgcHV0QW5jaG9yOiBib29sZWFuID0gdHJ1ZSkge1xuICAgIC8vIFRPRE86IG5lc3RlZCBwcmVzZXJpYWxpemF0aW9uIChzbyBpbmNyZWFzZSBwZXJmb3JtYW5jZSB3aGVuIGRlc2VyaWFsaXppbmcpXG4gICAgLy8gVE9ETzogVmVyaWZ5IHdoeSB0aGVyZSBpcyBubyBtZXRhZGF0YVxuICAgIGNvbnN0IHRvU2VyaWFsaXplOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0gT2JqZWN0LmFzc2lnbih7fSwgbW9kZWwpO1xuICAgIGxldCBtZXRhZGF0YTtcbiAgICB0cnkge1xuICAgICAgbWV0YWRhdGEgPSBNZXRhZGF0YS5tb2RlbE5hbWUobW9kZWwuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IpO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICBtZXRhZGF0YSA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgaWYgKHB1dEFuY2hvcilcbiAgICAgIHRvU2VyaWFsaXplW01vZGVsS2V5cy5BTkNIT1JdID0gbWV0YWRhdGEgfHwgbW9kZWwuY29uc3RydWN0b3IubmFtZTtcblxuICAgIGZ1bmN0aW9uIHByZVNlcmlhbGl6ZShcbiAgICAgIHRoaXM6IFNpbXBsZURldGVybWluaXN0aWNTZXJpYWxpemVyPGFueT4sXG4gICAgICBvYmo6IGFueVxuICAgICk6IGFueSB7XG4gICAgICBpZiAodHlwZW9mIG9iaiAhPT0gXCJvYmplY3RcIikgcmV0dXJuIG9iajtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KG9iaikpIHJldHVybiBvYmoubWFwKHByZVNlcmlhbGl6ZSk7XG4gICAgICByZXR1cm4gdGhpcy5wcmVTZXJpYWxpemUob2JqKTtcbiAgICB9XG4gICAgTW9kZWwucmVsYXRpb25zKG1vZGVsKS5mb3JFYWNoKChyKSA9PiB7XG4gICAgICB0b1NlcmlhbGl6ZVtyXSA9IHByZVNlcmlhbGl6ZS5jYWxsKHRoaXMsIHRvU2VyaWFsaXplW3JdKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdG9TZXJpYWxpemU7XG4gIH1cbn1cbiIsImltcG9ydCB7XG4gIExvZ2dlckZhY3RvcnksXG4gIExvZ2dpbmcsXG4gIExvZ2dlcixcbiAgTG9nTGV2ZWwsXG4gIE1pbmlMb2dnZXIsXG4gIE51bWVyaWNMb2dMZXZlbHMsXG4gIFN0cmluZ0xpa2UsXG59IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHsgTG9nZ2luZ0NvbmZpZyB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHsgQ29udGV4dCBhcyBDdHggfSBmcm9tIFwiZmFicmljLWNvbnRyYWN0LWFwaVwiO1xuaW1wb3J0IHsgSW50ZXJuYWxFcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBMb2dnZXIgaW1wbGVtZW50YXRpb24gZm9yIEZhYnJpYyBjaGFpbmNvZGUgY29udHJhY3RzXG4gKiBAc3VtbWFyeSBBZGFwdHMgdGhlIHN0YW5kYXJkIGxvZ2dpbmcgaW50ZXJmYWNlIHRvIHdvcmsgd2l0aCBGYWJyaWMncyBjaGFpbmNvZGUgY29udGV4dFxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb250ZXh0IC0gVGhlIGxvZ2dpbmcgY29udGV4dCBuYW1lXG4gKiBAcGFyYW0ge1BhcnRpYWw8TG9nZ2luZ0NvbmZpZz4gfCB1bmRlZmluZWR9IGNvbmYgLSBPcHRpb25hbCBsb2dnaW5nIGNvbmZpZ3VyYXRpb25cbiAqIEBwYXJhbSB7Q3R4fSBjdHggLSBUaGUgRmFicmljIGNoYWluY29kZSBjb250ZXh0XG4gKlxuICogQGNsYXNzIENvbnRyYWN0TG9nZ2VyXG4gKiBAZXh0ZW5kcyB7TWluaUxvZ2dlcn1cbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBJbiBhIEZhYnJpYyBjaGFpbmNvZGUgY29udHJhY3RcbiAqIGltcG9ydCB7IENvbnRyYWN0TG9nZ2VyIH0gZnJvbSAnQGRlY2FmLXRzL2Zvci1mYWJyaWMnO1xuICpcbiAqIGV4cG9ydCBjbGFzcyBNeUNvbnRyYWN0IGV4dGVuZHMgQ29udHJhY3Qge1xuICogICBAVHJhbnNhY3Rpb24oKVxuICogICBhc3luYyBteUZ1bmN0aW9uKGN0eDogQ29udGV4dCk6IFByb21pc2U8dm9pZD4ge1xuICogICAgIGNvbnN0IGxvZ2dlciA9IG5ldyBDb250cmFjdExvZ2dlcignTXlDb250cmFjdCcsIHsgbGV2ZWw6ICdpbmZvJyB9LCBjdHgpO1xuICpcbiAqICAgICBsb2dnZXIuaW5mbygnUHJvY2Vzc2luZyB0cmFuc2FjdGlvbicpO1xuICogICAgIGxvZ2dlci5kZWJ1ZygnVHJhbnNhY3Rpb24gZGV0YWlsczonLCB7IC4uLiB9KTtcbiAqXG4gKiAgICAgLy8gRG8gc29tZXRoaW5nXG4gKlxuICogICAgIGxvZ2dlci5pbmZvKCdUcmFuc2FjdGlvbiBjb21wbGV0ZScpO1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIENvbnRyYWN0TG9nZ2VyIGV4dGVuZHMgTWluaUxvZ2dlciB7XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVGhlIHVuZGVybHlpbmcgRmFicmljIGxvZ2dlciBpbnN0YW5jZVxuICAgKi9cbiAgcHJvdGVjdGVkIGxvZ2dlciE6IExvZ2dlcjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBjb250ZXh0OiBzdHJpbmcsXG4gICAgY29uZjogUGFydGlhbDxMb2dnaW5nQ29uZmlnPiB8IHVuZGVmaW5lZCxcbiAgICBjdHg/OiBDdHhcbiAgKSB7XG4gICAgc3VwZXIoY29udGV4dCwgY29uZik7XG5cbiAgICBpZiAoIWN0eCkge1xuICAgICAgdGhpcy5sb2dnZXIgPSBuZXcgTWluaUxvZ2dlcihjb250ZXh0LCBjb25mKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5sb2dnZXIgPSBjdHgubG9nZ2luZy5nZXRMb2dnZXIoY29udGV4dCkgYXMgdW5rbm93biBhcyBMb2dnZXI7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBMb2dzIGEgbWVzc2FnZSBhdCB0aGUgc3BlY2lmaWVkIGxldmVsXG4gICAqIEBzdW1tYXJ5IE92ZXJyaWRlcyB0aGUgYmFzZSBsb2cgbWV0aG9kIHRvIHVzZSB0aGUgRmFicmljIGNvbnRleHQncyBsb2dnZXJcbiAgICogQHBhcmFtIHtMb2dMZXZlbH0gbGV2ZWwgLSBUaGUgbG9nIGxldmVsXG4gICAqIEBwYXJhbSB7U3RyaW5nTGlrZSB8IEVycm9yfSBtc2cgLSBUaGUgbWVzc2FnZSB0byBsb2dcbiAgICogQHBhcmFtIHtFcnJvcn0gW3N0YWNrXSAtIE9wdGlvbmFsIHN0YWNrIHRyYWNlIGZvciBlcnJvcnNcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICovXG4gIHByb3RlY3RlZCBvdmVycmlkZSBsb2coXG4gICAgbGV2ZWw6IExvZ0xldmVsLFxuICAgIG1zZzogU3RyaW5nTGlrZSB8IEVycm9yLFxuICAgIHN0YWNrPzogRXJyb3JcbiAgKSB7XG4gICAgaWYgKFxuICAgICAgTnVtZXJpY0xvZ0xldmVsc1t0aGlzLmNvbmZpZyhcImxldmVsXCIpIGFzIExvZ0xldmVsXSA8XG4gICAgICBOdW1lcmljTG9nTGV2ZWxzW2xldmVsXVxuICAgIClcbiAgICAgIHJldHVybjtcblxuICAgIGxldCBtZXRob2Q7XG4gICAgc3dpdGNoIChsZXZlbCkge1xuICAgICAgY2FzZSBMb2dMZXZlbC5pbmZvOlxuICAgICAgICBtZXRob2QgPSB0aGlzLmxvZ2dlci5pbmZvO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgTG9nTGV2ZWwudmVyYm9zZTpcbiAgICAgICAgbWV0aG9kID0gdGhpcy5sb2dnZXIudmVyYm9zZTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIExvZ0xldmVsLmRlYnVnOlxuICAgICAgICBtZXRob2QgPSB0aGlzLmxvZ2dlci5kZWJ1ZztcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIExvZ0xldmVsLmVycm9yOlxuICAgICAgICBtZXRob2QgPSB0aGlzLmxvZ2dlci5lcnJvcjtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIExvZ0xldmVsLndhcm46XG4gICAgICAgIG1ldGhvZCA9IHRoaXMubG9nZ2VyLndhcm47XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBMb2dMZXZlbC5zaWxseTpcbiAgICAgICAgbWV0aG9kID0gdGhpcy5sb2dnZXIuc2lsbHk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJJbnZhbGlkIGxvZyBsZXZlbFwiKTtcbiAgICB9XG4gICAgbWV0aG9kLmNhbGwodGhpcy5sb2dnZXIsIHRoaXMuY3JlYXRlTG9nKGxldmVsLCBtc2csIHN0YWNrKSk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRmFjdG9yeSBmdW5jdGlvbiBmb3IgY3JlYXRpbmcgQ29udHJhY3RMb2dnZXIgaW5zdGFuY2VzXG4gKiBAc3VtbWFyeSBDcmVhdGVzIGEgbmV3IENvbnRyYWN0TG9nZ2VyIHdpdGggdGhlIGdpdmVuIGNvbnRleHQsIGNvbmZpZywgYW5kIEZhYnJpYyBjb250ZXh0XG4gKiBAcGFyYW0ge3N0cmluZ30gb2JqZWN0IC0gVGhlIGxvZ2dpbmcgY29udGV4dCBuYW1lXG4gKiBAcGFyYW0ge1BhcnRpYWw8TG9nZ2luZ0NvbmZpZz4gfCB1bmRlZmluZWR9IGNvbmZpZyAtIE9wdGlvbmFsIGxvZ2dpbmcgY29uZmlndXJhdGlvblxuICogQHBhcmFtIHtDdHh9IGN0eCAtIFRoZSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRleHRcbiAqIEByZXR1cm4ge0NvbnRyYWN0TG9nZ2VyfSBBIG5ldyBDb250cmFjdExvZ2dlciBpbnN0YW5jZVxuICogQGZ1bmN0aW9uIGZhY3RvcnlcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZmFicmljLmNvbnRyYWN0c1xuICovXG5jb25zdCBmYWN0b3J5OiBMb2dnZXJGYWN0b3J5ID0gKFxuICBvYmplY3Q/OiBzdHJpbmcsXG4gIGNvbmZpZz86IFBhcnRpYWw8TG9nZ2luZ0NvbmZpZz4sXG4gIGN0eD86IEN0eFxuKSA9PiB7XG4gIHJldHVybiBuZXcgQ29udHJhY3RMb2dnZXIoXG4gICAgb2JqZWN0IHx8IENvbnRyYWN0TG9nZ2VyLm5hbWUsXG4gICAgY29uZmlnIHx8IHt9LFxuICAgIGN0eCBhcyBDdHhcbiAgKTtcbn07XG5cbi8vIFNldCB0aGUgZmFjdG9yeSBhcyB0aGUgZGVmYXVsdCBsb2dnZXIgZmFjdG9yeVxuTG9nZ2luZy5zZXRGYWN0b3J5KGZhY3RvcnkpO1xuIiwiaW1wb3J0IHtcbiAgTWF5YmVDb250ZXh0dWFsQXJnLFxuICBPcmRlckRpcmVjdGlvbixcbiAgUGFnaW5nRXJyb3IsXG4gIFNlcXVlbmNlLFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IERCS2V5cyB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciwgTWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IEZhYnJpY0NvbnRyYWN0QWRhcHRlciB9IGZyb20gXCIuL0NvbnRyYWN0QWRhcHRlclwiO1xuaW1wb3J0IHsgQ291Y2hEQlBhZ2luYXRvciwgTWFuZ29RdWVyeSB9IGZyb20gXCJAZGVjYWYtdHMvZm9yLWNvdWNoZGJcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUGFnaW5hdG9yIGZvciBDb3VjaERCIHF1ZXJ5IHJlc3VsdHNcbiAqIEBzdW1tYXJ5IEltcGxlbWVudHMgcGFnaW5hdGlvbiBmb3IgQ291Y2hEQiBxdWVyaWVzIHVzaW5nIGJvb2ttYXJrcyBmb3IgZWZmaWNpZW50IG5hdmlnYXRpb24gdGhyb3VnaCByZXN1bHQgc2V0c1xuICogQHRlbXBsYXRlIE0gLSBUaGUgbW9kZWwgdHlwZSB0aGF0IGV4dGVuZHMgTW9kZWxcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHJlc3VsdCB0eXBlXG4gKiBAcGFyYW0ge0ZhYnJpY0NvPGFueSwgYW55LCBhbnk+fSBhZGFwdGVyIC0gVGhlIENvdWNoREIgYWRhcHRlclxuICogQHBhcmFtIHtNYW5nb1F1ZXJ5fSBxdWVyeSAtIFRoZSBNYW5nbyBxdWVyeSB0byBwYWdpbmF0ZVxuICogQHBhcmFtIHtudW1iZXJ9IHNpemUgLSBUaGUgcGFnZSBzaXplXG4gKiBAcGFyYW0ge0NvbnN0cnVjdG9yPE0+fSBjbGF6eiAtIFRoZSBtb2RlbCBjb25zdHJ1Y3RvclxuICogQGNsYXNzIENvdWNoREJQYWdpbmF0b3JcbiAqIEBleGFtcGxlXG4gKiAvLyBFeGFtcGxlIG9mIHVzaW5nIENvdWNoREJQYWdpbmF0b3JcbiAqIGNvbnN0IGFkYXB0ZXIgPSBuZXcgTXlDb3VjaERCQWRhcHRlcihzY29wZSk7XG4gKiBjb25zdCBxdWVyeSA9IHsgc2VsZWN0b3I6IHsgdHlwZTogXCJ1c2VyXCIgfSB9O1xuICogY29uc3QgcGFnaW5hdG9yID0gbmV3IENvdWNoREJQYWdpbmF0b3IoYWRhcHRlciwgcXVlcnksIDEwLCBVc2VyKTtcbiAqXG4gKiAvLyBHZXQgdGhlIGZpcnN0IHBhZ2VcbiAqIGNvbnN0IHBhZ2UxID0gYXdhaXQgcGFnaW5hdG9yLnBhZ2UoMSk7XG4gKlxuICogLy8gR2V0IHRoZSBuZXh0IHBhZ2VcbiAqIGNvbnN0IHBhZ2UyID0gYXdhaXQgcGFnaW5hdG9yLnBhZ2UoMik7XG4gKi9cbmV4cG9ydCBjbGFzcyBGYWJyaWNDb250cmFjdFBhZ2luYXRvcjxcbiAgTSBleHRlbmRzIE1vZGVsLFxuICBSLFxuPiBleHRlbmRzIENvdWNoREJQYWdpbmF0b3I8TSwgUj4ge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgQ291Y2hEQlBhZ2luYXRvciBpbnN0YW5jZVxuICAgKiBAc3VtbWFyeSBJbml0aWFsaXplcyBhIHBhZ2luYXRvciBmb3IgQ291Y2hEQiBxdWVyeSByZXN1bHRzXG4gICAqIEBwYXJhbSB7Q291Y2hEQkFkYXB0ZXI8YW55LCBhbnksIGFueSwgYW55Pn0gYWRhcHRlciAtIFRoZSBDb3VjaERCIGFkYXB0ZXJcbiAgICogQHBhcmFtIHtNYW5nb1F1ZXJ5fSBxdWVyeSAtIFRoZSBNYW5nbyBxdWVyeSB0byBwYWdpbmF0ZVxuICAgKiBAcGFyYW0ge251bWJlcn0gc2l6ZSAtIFRoZSBwYWdlIHNpemVcbiAgICogQHBhcmFtIHtDb25zdHJ1Y3RvcjxNPn0gY2xhenogLSBUaGUgbW9kZWwgY29uc3RydWN0b3JcbiAgICovXG4gIGNvbnN0cnVjdG9yKFxuICAgIGFkYXB0ZXI6IEZhYnJpY0NvbnRyYWN0QWRhcHRlcixcbiAgICBxdWVyeTogTWFuZ29RdWVyeSxcbiAgICBzaXplOiBudW1iZXIsXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+XG4gICkge1xuICAgIHN1cGVyKGFkYXB0ZXIsIHF1ZXJ5LCBzaXplLCBjbGF6eik7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByZXBhcmVzIGEgcXVlcnkgZm9yIHBhZ2luYXRpb25cbiAgICogQHN1bW1hcnkgTW9kaWZpZXMgdGhlIHJhdyBxdWVyeSB0byBpbmNsdWRlIHBhZ2luYXRpb24gcGFyYW1ldGVyc1xuICAgKiBAcGFyYW0ge01hbmdvUXVlcnl9IHJhd1N0YXRlbWVudCAtIFRoZSBvcmlnaW5hbCBNYW5nbyBxdWVyeVxuICAgKiBAcmV0dXJuIHtNYW5nb1F1ZXJ5fSBUaGUgcHJlcGFyZWQgcXVlcnkgd2l0aCBwYWdpbmF0aW9uIHBhcmFtZXRlcnNcbiAgICovXG4gIHByb3RlY3RlZCBvdmVycmlkZSBwcmVwYXJlKHJhd1N0YXRlbWVudDogTWFuZ29RdWVyeSk6IE1hbmdvUXVlcnkge1xuICAgIGNvbnN0IHF1ZXJ5OiBNYW5nb1F1ZXJ5ID0gT2JqZWN0LmFzc2lnbih7fSwgcmF3U3RhdGVtZW50KTtcbiAgICBpZiAocXVlcnkubGltaXQpIHRoaXMubGltaXQgPSBxdWVyeS5saW1pdDtcblxuICAgIHF1ZXJ5LmxpbWl0ID0gdGhpcy5zaXplO1xuXG4gICAgcmV0dXJuIHF1ZXJ5O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXRyaWV2ZXMgYSBzcGVjaWZpYyBwYWdlIG9mIHJlc3VsdHNcbiAgICogQHN1bW1hcnkgRXhlY3V0ZXMgdGhlIHF1ZXJ5IHdpdGggcGFnaW5hdGlvbiBhbmQgcHJvY2Vzc2VzIHRoZSByZXN1bHRzXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbcGFnZT0xXSAtIFRoZSBwYWdlIG51bWJlciB0byByZXRyaWV2ZVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJbXT59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIGFycmF5IG9mIHJlc3VsdHNcbiAgICogQHRocm93cyB7UGFnaW5nRXJyb3J9IElmIHRyeWluZyB0byBhY2Nlc3MgYSBwYWdlIG90aGVyIHRoYW4gdGhlIGZpcnN0IHdpdGhvdXQgYSBib29rbWFyaywgb3IgaWYgbm8gY2xhc3MgaXMgZGVmaW5lZFxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBDbGllbnRcbiAgICogICBwYXJ0aWNpcGFudCBDb3VjaERCUGFnaW5hdG9yXG4gICAqICAgcGFydGljaXBhbnQgQWRhcHRlclxuICAgKiAgIHBhcnRpY2lwYW50IENvdWNoREJcbiAgICpcbiAgICogICBDbGllbnQtPj5Db3VjaERCUGFnaW5hdG9yOiBwYWdlKHBhZ2VOdW1iZXIpXG4gICAqICAgTm90ZSBvdmVyIENvdWNoREJQYWdpbmF0b3I6IENsb25lIHN0YXRlbWVudFxuICAgKiAgIENvdWNoREJQYWdpbmF0b3ItPj5Db3VjaERCUGFnaW5hdG9yOiB2YWxpZGF0ZVBhZ2UocGFnZSlcbiAgICpcbiAgICogICBhbHQgcGFnZSAhPT0gMVxuICAgKiAgICAgQ291Y2hEQlBhZ2luYXRvci0+PkNvdWNoREJQYWdpbmF0b3I6IENoZWNrIGJvb2ttYXJrXG4gICAqICAgICBhbHQgTm8gYm9va21hcmtcbiAgICogICAgICAgQ291Y2hEQlBhZ2luYXRvci0tPj5DbGllbnQ6IFRocm93IFBhZ2luZ0Vycm9yXG4gICAqICAgICBlbHNlIEhhcyBib29rbWFya1xuICAgKiAgICAgICBDb3VjaERCUGFnaW5hdG9yLT4+Q291Y2hEQlBhZ2luYXRvcjogQWRkIGJvb2ttYXJrIHRvIHN0YXRlbWVudFxuICAgKiAgICAgZW5kXG4gICAqICAgZW5kXG4gICAqXG4gICAqICAgQ291Y2hEQlBhZ2luYXRvci0+PkFkYXB0ZXI6IHJhdyhzdGF0ZW1lbnQsIGZhbHNlKVxuICAgKiAgIEFkYXB0ZXItPj5Db3VjaERCOiBFeGVjdXRlIHF1ZXJ5XG4gICAqICAgQ291Y2hEQi0tPj5BZGFwdGVyOiBSZXR1cm4gcmVzdWx0c1xuICAgKiAgIEFkYXB0ZXItLT4+Q291Y2hEQlBhZ2luYXRvcjogUmV0dXJuIE1hbmdvUmVzcG9uc2VcbiAgICpcbiAgICogICBOb3RlIG92ZXIgQ291Y2hEQlBhZ2luYXRvcjogUHJvY2VzcyByZXN1bHRzXG4gICAqXG4gICAqICAgYWx0IEhhcyB3YXJuaW5nXG4gICAqICAgICBDb3VjaERCUGFnaW5hdG9yLT4+Q291Y2hEQlBhZ2luYXRvcjogTG9nIHdhcm5pbmdcbiAgICogICBlbmRcbiAgICpcbiAgICogICBDb3VjaERCUGFnaW5hdG9yLT4+Q291Y2hEQlBhZ2luYXRvcjogQ2hlY2sgZm9yIGNsYXp6XG4gICAqXG4gICAqICAgYWx0IE5vIGNsYXp6XG4gICAqICAgICBDb3VjaERCUGFnaW5hdG9yLS0+PkNsaWVudDogVGhyb3cgUGFnaW5nRXJyb3JcbiAgICogICBlbHNlIEhhcyBjbGF6elxuICAgKiAgICAgQ291Y2hEQlBhZ2luYXRvci0+PkNvdWNoREJQYWdpbmF0b3I6IEZpbmQgcHJpbWFyeSBrZXlcbiAgICpcbiAgICogICAgIGFsdCBIYXMgZmllbGRzIGluIHN0YXRlbWVudFxuICAgKiAgICAgICBDb3VjaERCUGFnaW5hdG9yLT4+Q291Y2hEQlBhZ2luYXRvcjogVXNlIGRvY3MgZGlyZWN0bHlcbiAgICogICAgIGVsc2UgTm8gZmllbGRzXG4gICAqICAgICAgIENvdWNoREJQYWdpbmF0b3ItPj5Db3VjaERCUGFnaW5hdG9yOiBQcm9jZXNzIGVhY2ggZG9jdW1lbnRcbiAgICogICAgICAgbG9vcCBGb3IgZWFjaCBkb2N1bWVudFxuICAgKiAgICAgICAgIENvdWNoREJQYWdpbmF0b3ItPj5Db3VjaERCUGFnaW5hdG9yOiBFeHRyYWN0IG9yaWdpbmFsIElEXG4gICAqICAgICAgICAgQ291Y2hEQlBhZ2luYXRvci0+PkFkYXB0ZXI6IHJldmVydChkb2MsIGNsYXp6LCBwa0RlZi5pZCwgcGFyc2VkSWQpXG4gICAqICAgICAgIGVuZFxuICAgKiAgICAgZW5kXG4gICAqXG4gICAqICAgICBDb3VjaERCUGFnaW5hdG9yLT4+Q291Y2hEQlBhZ2luYXRvcjogU3RvcmUgYm9va21hcmtcbiAgICogICAgIENvdWNoREJQYWdpbmF0b3ItPj5Db3VjaERCUGFnaW5hdG9yOiBVcGRhdGUgY3VycmVudFBhZ2VcbiAgICogICAgIENvdWNoREJQYWdpbmF0b3ItLT4+Q2xpZW50OiBSZXR1cm4gcmVzdWx0c1xuICAgKiAgIGVuZFxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgcGFnZShcbiAgICBwYWdlOiBudW1iZXIgPSAxLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxhbnk+XG4gICk6IFByb21pc2U8TVtdPiB7XG4gICAgY29uc3QgeyBjdHhBcmdzLCBjdHggfSA9IHRoaXMuYWRhcHRlcltcImxvZ0N0eFwiXShhcmdzLCB0aGlzLnBhZ2UpO1xuICAgIGlmICh0aGlzLmlzUHJlcGFyZWRTdGF0ZW1lbnQoKSkgcmV0dXJuIHRoaXMucGFnZVByZXBhcmVkKHBhZ2UsIC4uLmN0eEFyZ3MpO1xuICAgIGNvbnN0IHN0YXRlbWVudCA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGVtZW50KTtcblxuICAgIGlmICghdGhpcy5fcmVjb3JkQ291bnQgfHwgIXRoaXMuX3RvdGFsUGFnZXMpIHtcbiAgICAgIHRoaXMuX3RvdGFsUGFnZXMgPSB0aGlzLl9yZWNvcmRDb3VudCA9IDA7XG4gICAgICBjb25zdCByZXN1bHRzOiBSW10gPVxuICAgICAgICAoYXdhaXQgdGhpcy5hZGFwdGVyLnJhdyhcbiAgICAgICAgICB7IC4uLnN0YXRlbWVudCwgbGltaXQ6IHVuZGVmaW5lZCB9LFxuICAgICAgICAgIHRydWUsXG4gICAgICAgICAgY3R4XG4gICAgICAgICkpIHx8IFtdO1xuICAgICAgdGhpcy5fcmVjb3JkQ291bnQgPSByZXN1bHRzLmxlbmd0aDtcbiAgICAgIGlmICh0aGlzLl9yZWNvcmRDb3VudCA+IDApIHtcbiAgICAgICAgY29uc3Qgc2l6ZSA9IHN0YXRlbWVudD8ubGltaXQgfHwgdGhpcy5zaXplO1xuICAgICAgICB0aGlzLl90b3RhbFBhZ2VzID0gTWF0aC5jZWlsKHRoaXMuX3JlY29yZENvdW50IC8gc2l6ZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy52YWxpZGF0ZVBhZ2UocGFnZSk7XG5cbiAgICBpZiAocGFnZSAhPT0gMSkge1xuICAgICAgaWYgKCF0aGlzLl9ib29rbWFyaylcbiAgICAgICAgdGhyb3cgbmV3IFBhZ2luZ0Vycm9yKFwiTm8gYm9va21hcmsuIERpZCB5b3Ugc3RhcnQgaW4gdGhlIGZpcnN0IHBhZ2U/XCIpO1xuICAgICAgc3RhdGVtZW50W1wiYm9va21hcmtcIl0gPSB0aGlzLl9ib29rbWFyayBhcyBzdHJpbmc7XG4gICAgfVxuICAgIGNvbnN0IGRvY3M6IGFueVtdID0gKGF3YWl0IHRoaXMuYWRhcHRlci5yYXcoc3RhdGVtZW50LCBmYWxzZSwgY3R4KSkgYXMgYW55O1xuXG4gICAgaWYgKCF0aGlzLmNsYXp6KSB0aHJvdyBuZXcgUGFnaW5nRXJyb3IoXCJObyBzdGF0ZW1lbnQgdGFyZ2V0IGRlZmluZWRcIik7XG4gICAgY29uc3QgaWQgPSBNb2RlbC5wayh0aGlzLmNsYXp6KTtcbiAgICBjb25zdCB0eXBlID0gTWV0YWRhdGEuZ2V0KFxuICAgICAgdGhpcy5jbGF6eixcbiAgICAgIE1ldGFkYXRhLmtleShEQktleXMuSUQsIGlkIGFzIHN0cmluZylcbiAgICApPy50eXBlO1xuICAgIGNvbnN0IHJlc3VsdHMgPVxuICAgICAgc3RhdGVtZW50LmZpZWxkcyAmJiBzdGF0ZW1lbnQuZmllbGRzLmxlbmd0aFxuICAgICAgICA/IGRvY3MgLy8gaGFzIGZpZWxkcyBtZWFucyBpdHMgbm90IGZ1bGwgbW9kZWxcbiAgICAgICAgOiBkb2NzLm1hcCgoZDogYW55KSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5hZGFwdGVyLnJldmVydChcbiAgICAgICAgICAgICAgZCxcbiAgICAgICAgICAgICAgdGhpcy5jbGF6eixcbiAgICAgICAgICAgICAgU2VxdWVuY2UucGFyc2VWYWx1ZSh0eXBlLCBkW2lkXSksXG4gICAgICAgICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgY3R4XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0pO1xuICAgIGNvbnN0IGRpcmVjdGlvbiA9IHN0YXRlbWVudC5zb3J0Py5bMF0gfHwgT3JkZXJEaXJlY3Rpb24uRFNDO1xuICAgIHRoaXMuX2Jvb2ttYXJrID1cbiAgICAgIHJlc3VsdHNbZGlyZWN0aW9uID09PSBPcmRlckRpcmVjdGlvbi5BU0MgPyByZXN1bHRzLmxlbmd0aCAtIDEgOiAwXVtpZF07XG4gICAgdGhpcy5fY3VycmVudFBhZ2UgPSBwYWdlO1xuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG59XG4iLCJpbXBvcnQgeyBCYXNlRXJyb3IsIEludGVybmFsRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IEF1dGhvcml6YXRpb25FcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuLy8gaW1wb3J0IHsgTUlTU0lOR19QUklWQVRFX0RBVEFfRVJST1JfTUVTU0FHRSB9IGZyb20gXCIuLi9jb250cmFjdHMvcHJpdmF0ZS1kYXRhXCI7XG4vKipcbiAqIEBzdW1tYXJ5IFJlcHJlc2VudHMgYW4gb3ZlcmZsb3cgZXJyb3IgaW4gYXJpdGhtZXRpYyBvcGVyYXRpb25zIGluIFNtYXJ0IENvbnRyYWN0c1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBtc2cgdGhlIGVycm9yIG1lc3NhZ2VcbiAqXG4gKiBAY2xhc3MgT3ZlcmZsb3dFcnJvclxuICogQGV4dGVuZHMgSW50ZXJuYWxFcnJvclxuICpcbiAqIEBjYXRlZ29yeSBFcnJvcnNcbiAqL1xuZXhwb3J0IGNsYXNzIE92ZXJmbG93RXJyb3IgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1zZywgT3ZlcmZsb3dFcnJvci5uYW1lKTtcbiAgfVxufVxuXG4vKipcbiAqIEBzdW1tYXJ5IFJlcHJlc2VudHMgYSBmYWlsdXJlIGluIGJhbGFuY2UgdG8gcGVyZm9ybSBhIHRyYW5zYWN0aW9uIGluIFNtYXJ0IENvbnRyYWN0c1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBtc2cgdGhlIGVycm9yIG1lc3NhZ2VcbiAqXG4gKiBAY2xhc3MgQmFsYW5jZUVycm9yXG4gKiBAZXh0ZW5kcyBJbnRlcm5hbEVycm9yXG4gKlxuICogQGNhdGVnb3J5IEVycm9yc1xuICovXG5leHBvcnQgY2xhc3MgQmFsYW5jZUVycm9yIGV4dGVuZHMgSW50ZXJuYWxFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtc2csIEJhbGFuY2VFcnJvci5uYW1lKTtcbiAgfVxufVxuXG4vKipcbiAqIEBzdW1tYXJ5IFJlcHJlc2VudHMgYSBmYWlsdXJlIGluIGJhbGFuY2UgdG8gcGVyZm9ybSBhIHRyYW5zYWN0aW9uIGluIFNtYXJ0IENvbnRyYWN0c1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBtc2cgdGhlIGVycm9yIG1lc3NhZ2VcbiAqXG4gKiBAY2xhc3MgQmFsYW5jZUVycm9yXG4gKiBAZXh0ZW5kcyBJbnRlcm5hbEVycm9yXG4gKlxuICogQGNhdGVnb3J5IEVycm9yc1xuICovXG5leHBvcnQgY2xhc3MgQWxsb3dhbmNlRXJyb3IgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1zZywgQWxsb3dhbmNlRXJyb3IubmFtZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGEgZmFpbHVyZSByZWdpc3RyYXRpbmcgbmV3IGVudGl0aWVzXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG1zZyB0aGUgZXJyb3IgbWVzc2FnZVxuICpcbiAqIEBjbGFzcyBSZWdpc3RyYXRpb25FcnJvclxuICpcbiAqIEBjYXRlZ29ydCBFcnJvcnNcbiAqL1xuZXhwb3J0IGNsYXNzIFJlZ2lzdHJhdGlvbkVycm9yIGV4dGVuZHMgQXV0aG9yaXphdGlvbkVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1zZywgUmVnaXN0cmF0aW9uRXJyb3IubmFtZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRXJyb3IgdGhyb3duIHdoZW4gYW4gdW5zdXBwb3J0ZWQgb3BlcmF0aW9uIGlzIGF0dGVtcHRlZFxuICogQHN1bW1hcnkgVGhpcyBlcnJvciBpcyB0aHJvd24gd2hlbiBhbiBvcGVyYXRpb24gaXMgcmVxdWVzdGVkIHRoYXQgaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgY3VycmVudFxuICogcGVyc2lzdGVuY2UgYWRhcHRlciBvciBjb25maWd1cmF0aW9uLiBJdCBleHRlbmRzIHRoZSBCYXNlRXJyb3IgY2xhc3MgYW5kIHNldHMgYSA1MDAgc3RhdHVzIGNvZGUuXG4gKiBAcGFyYW0ge3N0cmluZ3xFcnJvcn0gbXNnIC0gVGhlIGVycm9yIG1lc3NhZ2Ugb3IgYW4gRXJyb3Igb2JqZWN0IHRvIHdyYXBcbiAqIEBjbGFzcyBVbnN1cHBvcnRlZEVycm9yXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gVGhyb3dpbmcgYW4gVW5zdXBwb3J0ZWRFcnJvclxuICogaWYgKCFhZGFwdGVyLnN1cHBvcnRzVHJhbnNhY3Rpb25zKCkpIHtcbiAqICAgdGhyb3cgbmV3IFVuc3VwcG9ydGVkRXJyb3IoJ1RyYW5zYWN0aW9ucyBhcmUgbm90IHN1cHBvcnRlZCBieSB0aGlzIGFkYXB0ZXInKTtcbiAqIH1cbiAqXG4gKiAvLyBDYXRjaGluZyBhbiBVbnN1cHBvcnRlZEVycm9yXG4gKiB0cnkge1xuICogICBhd2FpdCBhZGFwdGVyLmJlZ2luVHJhbnNhY3Rpb24oKTtcbiAqIH0gY2F0Y2ggKGVycm9yKSB7XG4gKiAgIGlmIChlcnJvciBpbnN0YW5jZW9mIFVuc3VwcG9ydGVkRXJyb3IpIHtcbiAqICAgICBjb25zb2xlLmVycm9yKCdPcGVyYXRpb24gbm90IHN1cHBvcnRlZDonLCBlcnJvci5tZXNzYWdlKTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKlxuICogQGNhdGVnb3J5IEVycm9yc1xuICovXG5leHBvcnQgY2xhc3MgTWlzc2luZ0NvbnRleHRFcnJvciBleHRlbmRzIEludGVybmFsRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobXNnLCBNaXNzaW5nQ29udGV4dEVycm9yLm5hbWUsIDUwMCk7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIFVuYXV0aG9yaXplZFByaXZhdGVEYXRhQWNjZXNzIGV4dGVuZHMgQmFzZUVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvciA9IFwiTUlTU0lOR19QUklWQVRFX0RBVEFfRVJST1JfTUVTU0FHRVwiKSB7XG4gICAgc3VwZXIoVW5hdXRob3JpemVkUHJpdmF0ZURhdGFBY2Nlc3MubmFtZSwgbXNnLCA0MDMpO1xuICB9XG59XG5cbi8qKlxuICogUmVwcmVzZW50cyBhbiBlcnJvciB0aGF0IG9jY3VycyB3aGVuIGEgcmVxdWlyZWQgaW5pdGlhbGl6YXRpb24gc3RlcCBpcyBub3QgcGVyZm9ybWVkLlxuICpcbiAqIEBjbGFzcyBOb3RJbml0aWFsaXplZEVycm9yXG4gKiBAZXh0ZW5kcyBCYXNlRXJyb3JcbiAqXG4gKiBAY2F0ZWdvcnkgRXJyb3JzXG4gKlxuICogQHBhcmFtIHtzdHJpbmcgfCBFcnJvcn0gbXNnIC0gVGhlIGVycm9yIG1lc3NhZ2Ugb3IgYW4gRXJyb3Igb2JqZWN0IHRvIHdyYXAuXG4gKlxuICogQHRocm93cyB7Tm90SW5pdGlhbGl6ZWRFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3Igd2hlbiBhIHJlcXVpcmVkIGluaXRpYWxpemF0aW9uIHN0ZXAgaXMgbm90IHBlcmZvcm1lZC5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gSW5pdGlhbGl6ZSB0aGUgYXBwbGljYXRpb25cbiAqIGlmICghaXNJbml0aWFsaXplZCkge1xuICogICB0aHJvdyBuZXcgTm90SW5pdGlhbGl6ZWRFcnJvcignQXBwbGljYXRpb24gaXMgbm90IGluaXRpYWxpemVkJyk7XG4gKiB9XG4gKlxuICogLy8gQ2F0Y2hpbmcgYW4gTm90SW5pdGlhbGl6ZWRFcnJvclxuICogdHJ5IHtcbiAqICAgLy8gUGVyZm9ybSBvcGVyYXRpb25zIHRoYXQgcmVxdWlyZSBpbml0aWFsaXphdGlvblxuICogfSBjYXRjaCAoZXJyb3IpIHtcbiAqICAgaWYgKGVycm9yIGluc3RhbmNlb2YgTm90SW5pdGlhbGl6ZWRFcnJvcikge1xuICogICAgIGNvbnNvbGUuZXJyb3IoJ0luaXRpYWxpemF0aW9uIGVycm9yOicsIGVycm9yLm1lc3NhZ2UpO1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIE5vdEluaXRpYWxpemVkRXJyb3IgZXh0ZW5kcyBCYXNlRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIoTm90SW5pdGlhbGl6ZWRFcnJvci5uYW1lLCBtc2csIDQwOSk7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIE1pc3NpbmdQS0NTUzExTGliIGV4dGVuZHMgSW50ZXJuYWxFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtc2csIE1pc3NpbmdQS0NTUzExTGliLm5hbWUsIDUwMCk7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIEVuZG9yc2VtZW50RXJyb3IgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtZXNzYWdlLCBFbmRvcnNlbWVudEVycm9yLm5hbWUsIDUwMCk7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIE12Y2NSZWFkQ29uZmxpY3RFcnJvciBleHRlbmRzIEludGVybmFsRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1lc3NhZ2UsIE12Y2NSZWFkQ29uZmxpY3RFcnJvci5uYW1lLCA1MDApO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBQaGFudG9tUmVhZENvbmZsaWN0RXJyb3IgZXh0ZW5kcyBJbnRlcm5hbEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtZXNzYWdlLCBQaGFudG9tUmVhZENvbmZsaWN0RXJyb3IubmFtZSwgNTAwKTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgRW5kb3JzZW1lbnRQb2xpY3lFcnJvciBleHRlbmRzIEludGVybmFsRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1lc3NhZ2UsIEVuZG9yc2VtZW50UG9saWN5RXJyb3IubmFtZSwgNTAwKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgQ291Y2hEQkFkYXB0ZXIsIENvdWNoREJLZXlzLCBNYW5nb1F1ZXJ5IH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItY291Y2hkYlwiO1xuaW1wb3J0IHsgTW9kZWwsIFZhbGlkYXRpb25LZXlzIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RGbGFncyB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdENvbnRleHQgfSBmcm9tIFwiLi9Db250cmFjdENvbnRleHRcIjtcbmltcG9ydCB7XG4gIEJhZFJlcXVlc3RFcnJvcixcbiAgQmFzZUVycm9yLFxuICBDb25mbGljdEVycm9yLFxuICBJbnRlcm5hbEVycm9yLFxuICBOb3RGb3VuZEVycm9yLFxuICBvbkNyZWF0ZSxcbiAgb25DcmVhdGVVcGRhdGUsXG4gIE9wZXJhdGlvbktleXMsXG4gIFByaW1hcnlLZXlUeXBlLFxuICBTZXJpYWxpemF0aW9uRXJyb3IsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHtcbiAgQ29udGV4dCBhcyBDdHgsXG4gIE9iamVjdCBhcyBGYWJyaWNPYmplY3QsXG4gIFByb3BlcnR5LFxuICBQcm9wZXJ0eSBhcyBGYWJyaWNQcm9wZXJ0eSxcbn0gZnJvbSBcImZhYnJpYy1jb250cmFjdC1hcGlcIjtcbmltcG9ydCB7IExvZ2dlciB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHtcbiAgUGVyc2lzdGVuY2VLZXlzLFxuICBSZWxhdGlvbnNNZXRhZGF0YSxcbiAgU2VxdWVuY2UsXG4gIFNlcXVlbmNlT3B0aW9ucyxcbiAgVW5zdXBwb3J0ZWRFcnJvcixcbiAgQWRhcHRlcixcbiAgUHJlcGFyZWRNb2RlbCxcbiAgUmVwb3NpdG9yeSxcbiAgUXVlcnlFcnJvcixcbiAgUGFnaW5nRXJyb3IsXG4gIE1pZ3JhdGlvbkVycm9yLFxuICBPYnNlcnZlckVycm9yLFxuICBBdXRob3JpemF0aW9uRXJyb3IsXG4gIEZvcmJpZGRlbkVycm9yLFxuICBDb25uZWN0aW9uRXJyb3IsXG4gIENvbnRleHR1YWxpemVkQXJncyxcbiAgTG9nZ2VyT2YsXG4gIENvbnRleHQsXG4gIFJhd1Jlc3VsdCxcbiAgUGFnaW5hdG9yLFxuICBDb250ZXh0dWFsQXJncyxcbiAgTWF5YmVDb250ZXh0dWFsQXJnLFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeSB9IGZyb20gXCIuL0ZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeVwiO1xuaW1wb3J0IHtcbiAgQ2hhaW5jb2RlU3R1YixcbiAgQ2xpZW50SWRlbnRpdHksXG4gIEl0ZXJhdG9ycyxcbiAgU3RhdGVRdWVyeVJlc3BvbnNlLFxufSBmcm9tIFwiZmFicmljLXNoaW0tYXBpXCI7XG5pbXBvcnQgeyBGYWJyaWNTdGF0ZW1lbnQgfSBmcm9tIFwiLi9GYWJyaWNDb250cmFjdFN0YXRlbWVudFwiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RTZXF1ZW5jZSB9IGZyb20gXCIuL0ZhYnJpY0NvbnRyYWN0U2VxdWVuY2VcIjtcbmltcG9ydCB7IEZhYnJpY0ZsYXZvdXIgfSBmcm9tIFwiLi4vc2hhcmVkL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgU2ltcGxlRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXIgfSBmcm9tIFwiLi4vc2hhcmVkL1NpbXBsZURldGVybWluaXN0aWNTZXJpYWxpemVyXCI7XG5pbXBvcnQge1xuICBDb25zdHJ1Y3RvcixcbiAgRGVjb3JhdGlvbixcbiAgTWV0YWRhdGEsXG4gIHByb3BNZXRhZGF0YSxcbn0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBDb250cmFjdExvZ2dlciB9IGZyb20gXCIuL2xvZ2dpbmdcIjtcbmltcG9ydCB7IEZhYnJpY0NvbnRyYWN0UGFnaW5hdG9yIH0gZnJvbSBcIi4vRmFicmljQ29udHJhY3RQYWdpbmF0b3JcIjtcbmltcG9ydCB7IE1pc3NpbmdDb250ZXh0RXJyb3IgfSBmcm9tIFwiLi4vc2hhcmVkL2Vycm9yc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBTZXRzIHRoZSBjcmVhdG9yIG9yIHVwZGF0ZXIgZmllbGQgaW4gYSBtb2RlbCBiYXNlZCBvbiB0aGUgdXNlciBpbiB0aGUgY29udGV4dFxuICogQHN1bW1hcnkgQ2FsbGJhY2sgZnVuY3Rpb24gdXNlZCBpbiBkZWNvcmF0b3JzIHRvIGF1dG9tYXRpY2FsbHkgc2V0IHRoZSBjcmVhdGVkX2J5IG9yIHVwZGF0ZWRfYnkgZmllbGRzXG4gKiB3aXRoIHRoZSB1c2VybmFtZSBmcm9tIHRoZSBjb250ZXh0IHdoZW4gYSBkb2N1bWVudCBpcyBjcmVhdGVkIG9yIHVwZGF0ZWRcbiAqIEB0ZW1wbGF0ZSBNIC0gVHlwZSBleHRlbmRpbmcgTW9kZWxcbiAqIEB0ZW1wbGF0ZSBSIC0gVHlwZSBleHRlbmRpbmcgTmFub1JlcG9zaXRvcnk8TT5cbiAqIEB0ZW1wbGF0ZSBWIC0gVHlwZSBleHRlbmRpbmcgUmVsYXRpb25zTWV0YWRhdGFcbiAqIEBwYXJhbSB7Un0gdGhpcyAtIFRoZSByZXBvc2l0b3J5IGluc3RhbmNlXG4gKiBAcGFyYW0ge0ZhYnJpY0NvbnRyYWN0Q29udGV4dH0gY29udGV4dCAtIFRoZSBvcGVyYXRpb24gY29udGV4dCBjb250YWluaW5nIHVzZXIgaW5mb3JtYXRpb25cbiAqIEBwYXJhbSB7Vn0gZGF0YSAtIFRoZSByZWxhdGlvbiBtZXRhZGF0YVxuICogQHBhcmFtIHtzdHJpbmd9IGtleSAtIFRoZSBwcm9wZXJ0eSBrZXkgdG8gc2V0IHdpdGggdGhlIHVzZXJuYW1lXG4gKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlIGJlaW5nIGNyZWF0ZWQgb3IgdXBkYXRlZFxuICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgb3BlcmF0aW9uIGlzIGNvbXBsZXRlXG4gKiBAZnVuY3Rpb24gY3JlYXRlZEJ5T25GYWJyaWNDcmVhdGVVcGRhdGVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZmFicmljLmNvbnRyYWN0c1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBGIGFzIGNyZWF0ZWRCeU9uTmFub0NyZWF0ZVVwZGF0ZVxuICogICBwYXJ0aWNpcGFudCBDIGFzIENvbnRleHRcbiAqICAgcGFydGljaXBhbnQgTSBhcyBNb2RlbFxuICogICBGLT4+QzogZ2V0KFwidXNlclwiKVxuICogICBDLS0+PkY6IHVzZXIgb2JqZWN0XG4gKiAgIEYtPj5NOiBzZXQga2V5IHRvIHVzZXIubmFtZVxuICogICBOb3RlIG92ZXIgRjogSWYgbm8gdXNlciBpbiBjb250ZXh0XG4gKiAgIEYtLT4+RjogdGhyb3cgVW5zdXBwb3J0ZWRFcnJvclxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlZEJ5T25GYWJyaWNDcmVhdGVVcGRhdGU8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxNPixcbiAgViBleHRlbmRzIFJlbGF0aW9uc01ldGFkYXRhLFxuPihcbiAgdGhpczogUixcbiAgY29udGV4dDogQ29udGV4dDxGYWJyaWNDb250cmFjdEZsYWdzPixcbiAgZGF0YTogVixcbiAga2V5OiBrZXlvZiBNLFxuICBtb2RlbDogTVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgdXNlciA9IGNvbnRleHQuZ2V0KFwiaWRlbnRpdHlcIikgYXMgQ2xpZW50SWRlbnRpdHk7XG4gICAgbW9kZWxba2V5XSA9IHVzZXIuZ2V0SUQoKSBhcyBNW3R5cGVvZiBrZXldO1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgIHRocm93IG5ldyBVbnN1cHBvcnRlZEVycm9yKFxuICAgICAgXCJObyBVc2VyIGZvdW5kIGluIGNvbnRleHQuIFBsZWFzZSBwcm92aWRlIGEgdXNlciBpbiB0aGUgY29udGV4dFwiXG4gICAgKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBQcmltYXJ5IGtleSBhdXRvLWFzc2lnbm1lbnQgY2FsbGJhY2sgZm9yIEZhYnJpYyBtb2RlbHNcbiAqIEBzdW1tYXJ5IEdlbmVyYXRlcyBhbmQgYXNzaWducyBhIHByaW1hcnkga2V5IHZhbHVlIHRvIHRoZSBzcGVjaWZpZWQgbW9kZWwgcHJvcGVydHkgdXNpbmcgYSBGYWJyaWMtYmFja2VkIHNlcXVlbmNlIHdoZW4gdGhlIG1vZGVsIGlzIGNyZWF0ZWQuIElmIHRoZSBzZXF1ZW5jZSBuYW1lIGlzIG5vdCBwcm92aWRlZCBpbiBvcHRpb25zLCBpdCBpcyBkZXJpdmVkIGZyb20gdGhlIG1vZGVsIHZpYSBzZXF1ZW5jZU5hbWVGb3JNb2RlbC4gVGhlIGFzc2lnbmVkIGtleSBpcyBkZWZpbmVkIGFzIG5vbi13cml0YWJsZSBhbmQgZW51bWVyYWJsZS5cbiAqIEB0ZW1wbGF0ZSBNIC0gVHlwZSBleHRlbmRpbmcgTW9kZWwgZm9yIHRoZSB0YXJnZXQgaW5zdGFuY2VcbiAqIEB0ZW1wbGF0ZSBSIC0gVHlwZSBleHRlbmRpbmcgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5IGZvciByZXBvc2l0b3J5IGNvbnRleHRcbiAqIEB0ZW1wbGF0ZSBWIC0gVHlwZSBleHRlbmRpbmcgU2VxdWVuY2VPcHRpb25zIHRvIGNvbmZpZ3VyZSBzZXF1ZW5jZSBiZWhhdmlvclxuICogQHRlbXBsYXRlIEYgLSBUeXBlIGV4dGVuZGluZyBGYWJyaWNDb250cmFjdEZsYWdzIGZvciBjb250ZXh0dWFsIGZsYWdzXG4gKiBAcGFyYW0ge1J9IHRoaXMgLSBUaGUgcmVwb3NpdG9yeSBpbnN0YW5jZSBpbnZva2luZyB0aGUgY2FsbGJhY2tcbiAqIEBwYXJhbSB7RmFicmljQ29udHJhY3RDb250ZXh0fSBjb250ZXh0IC0gRmFicmljIGNvbnRyYWN0IGNvbnRleHQgY29udGFpbmluZyBpbnZvY2F0aW9uIG1ldGFkYXRhXG4gKiBAcGFyYW0ge1Z9IGRhdGEgLSBTZXF1ZW5jZSBvcHRpb25zIHVzZWQgdG8gY29uZmlndXJlIG9yIGxvY2F0ZSB0aGUgc2VxdWVuY2VcbiAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgLSBUaGUgcHJpbWFyeSBrZXkgcHJvcGVydHkgbmFtZSB0byBhc3NpZ24gb24gdGhlIG1vZGVsXG4gKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlIHRvIHJlY2VpdmUgdGhlIGdlbmVyYXRlZCBwcmltYXJ5IGtleVxuICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gUmVzb2x2ZXMgd2hlbiB0aGUga2V5IGlzIGFzc2lnbmVkIG9yIHdoZW4gbm8gYWN0aW9uIGlzIHJlcXVpcmVkXG4gKiBAZnVuY3Rpb24gcGtGYWJyaWNPbkNyZWF0ZVxuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLmNvbnRyYWN0c1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBSIGFzIFJlcG9zaXRvcnlcbiAqICAgcGFydGljaXBhbnQgQyBhcyBDb250ZXh0PEY+XG4gKiAgIHBhcnRpY2lwYW50IFMgYXMgRmFicmljQ29udHJhY3REQlNlcXVlbmNlXG4gKiAgIHBhcnRpY2lwYW50IE0gYXMgTW9kZWxcbiAqICAgUi0+PlI6IGRlcml2ZSBzZXF1ZW5jZSBuYW1lIGlmIG1pc3NpbmdcbiAqICAgUi0+PlM6IGFkYXB0ZXIuU2VxdWVuY2Uob3B0aW9ucylcbiAqICAgUy0tPj5SOiBzZXF1ZW5jZSBpbnN0YW5jZVxuICogICBSLT4+UzogbmV4dChjb250ZXh0KVxuICogICBTLS0+PlI6IG5leHQgdmFsdWVcbiAqICAgUi0+Pk06IGRlZmluZSBub24td3JpdGFibGUgcHJpbWFyeSBrZXlcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBrRmFicmljT25DcmVhdGU8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxNPixcbj4oXG4gIHRoaXM6IFIsXG4gIGNvbnRleHQ6IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgZGF0YTogU2VxdWVuY2VPcHRpb25zLFxuICBrZXk6IGtleW9mIE0sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKCFkYXRhLnR5cGUgfHwgbW9kZWxba2V5XSkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHNldFByaW1hcnlLZXlWYWx1ZSA9IGZ1bmN0aW9uIDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIHRhcmdldDogTSxcbiAgICBwcm9wZXJ0eUtleTogc3RyaW5nLFxuICAgIHZhbHVlOiBzdHJpbmcgfCBudW1iZXIgfCBiaWdpbnRcbiAgKSB7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwgcHJvcGVydHlLZXksIHtcbiAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICB2YWx1ZTogdmFsdWUsXG4gICAgfSk7XG4gIH07XG4gIGlmICghZGF0YS5uYW1lKSBkYXRhLm5hbWUgPSBNb2RlbC5zZXF1ZW5jZU5hbWUobW9kZWwsIFwicGtcIik7XG4gIGxldCBzZXF1ZW5jZTogU2VxdWVuY2U7XG4gIHRyeSB7XG4gICAgc2VxdWVuY2UgPSAoYXdhaXQgdGhpcy5hZGFwdGVyLlNlcXVlbmNlKGRhdGEpKSBhcyBTZXF1ZW5jZTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICBgRmFpbGVkIHRvIGluc3RhbnRpYXRlIFNlcXVlbmNlICR7ZGF0YS5uYW1lfTogJHtlfWBcbiAgICApO1xuICB9XG5cbiAgY29uc3QgbmV4dCA9IGF3YWl0IHNlcXVlbmNlLm5leHQoY29udGV4dCBhcyBGYWJyaWNDb250cmFjdENvbnRleHQpO1xuICBzZXRQcmltYXJ5S2V5VmFsdWUobW9kZWwsIGtleSBhcyBzdHJpbmcsIG5leHQpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBBZGFwdGVyIGZvciBIeXBlcmxlZGdlciBGYWJyaWMgY2hhaW5jb2RlIHN0YXRlIGRhdGFiYXNlIG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IFByb3ZpZGVzIGEgQ291Y2hEQi1saWtlIGludGVyZmFjZSBmb3IgaW50ZXJhY3Rpbmcgd2l0aCB0aGUgRmFicmljIHN0YXRlIGRhdGFiYXNlIGZyb20gd2l0aGluIGEgY2hhaW5jb2RlIGNvbnRyYWN0XG4gKiBAdGVtcGxhdGUgdm9pZCAtIE5vIGNvbmZpZ3VyYXRpb24gbmVlZGVkIGZvciBjb250cmFjdCBhZGFwdGVyXG4gKiBAdGVtcGxhdGUgRmFicmljQ29udHJhY3RGbGFncyAtIEZsYWdzIHNwZWNpZmljIHRvIEZhYnJpYyBjb250cmFjdCBvcGVyYXRpb25zXG4gKiBAdGVtcGxhdGUgRmFicmljQ29udHJhY3RDb250ZXh0IC0gQ29udGV4dCB0eXBlIGZvciBGYWJyaWMgY29udHJhY3Qgb3BlcmF0aW9uc1xuICogQGNsYXNzIEZhYnJpY0NvbnRyYWN0QWRhcHRlclxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIEluIGEgRmFicmljIGNoYWluY29kZSBjb250cmFjdCBjbGFzc1xuICogaW1wb3J0IHsgRmFicmljQ29udHJhY3RBZGFwdGVyIH0gZnJvbSAnQGRlY2FmLXRzL2Zvci1mYWJyaWMnO1xuICpcbiAqIGV4cG9ydCBjbGFzcyBNeUNvbnRyYWN0IGV4dGVuZHMgQ29udHJhY3Qge1xuICogICBwcml2YXRlIGFkYXB0ZXIgPSBuZXcgRmFicmljQ29udHJhY3RBZGFwdGVyKCk7XG4gKlxuICogICBAVHJhbnNhY3Rpb24oKVxuICogICBhc3luYyBjcmVhdGVBc3NldChjdHg6IENvbnRleHQsIGlkOiBzdHJpbmcsIGRhdGE6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICogICAgIGNvbnN0IG1vZGVsID0geyBpZCwgZGF0YSwgdGltZXN0YW1wOiBEYXRlLm5vdygpIH07XG4gKiAgICAgYXdhaXQgdGhpcy5hZGFwdGVyLmNyZWF0ZSgnYXNzZXRzJywgaWQsIG1vZGVsLCB7fSwgeyBzdHViOiBjdHguc3R1YiB9KTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENvbnRyYWN0XG4gKiAgIHBhcnRpY2lwYW50IEZhYnJpY0NvbnRyYWN0QWRhcHRlclxuICogICBwYXJ0aWNpcGFudCBTdHViXG4gKiAgIHBhcnRpY2lwYW50IFN0YXRlREJcbiAqXG4gKiAgIENvbnRyYWN0LT4+RmFicmljQ29udHJhY3RBZGFwdGVyOiBjcmVhdGUodGFibGVOYW1lLCBpZCwgbW9kZWwsIHRyYW5zaWVudCwgY3R4KVxuICogICBGYWJyaWNDb250cmFjdEFkYXB0ZXItPj5GYWJyaWNDb250cmFjdEFkYXB0ZXI6IFNlcmlhbGl6ZSBtb2RlbCB0byBKU09OXG4gKiAgIEZhYnJpY0NvbnRyYWN0QWRhcHRlci0+PlN0dWI6IHB1dFN0YXRlKGlkLCBzZXJpYWxpemVkRGF0YSlcbiAqICAgU3R1Yi0+PlN0YXRlREI6IFdyaXRlIGRhdGFcbiAqICAgU3RhdGVEQi0tPj5TdHViOiBTdWNjZXNzXG4gKiAgIFN0dWItLT4+RmFicmljQ29udHJhY3RBZGFwdGVyOiBTdWNjZXNzXG4gKiAgIEZhYnJpY0NvbnRyYWN0QWRhcHRlci0tPj5Db250cmFjdDogbW9kZWxcbiAqL1xuZXhwb3J0IGNsYXNzIEZhYnJpY0NvbnRyYWN0QWRhcHRlciBleHRlbmRzIENvdWNoREJBZGFwdGVyPFxuICBhbnksXG4gIHZvaWQsXG4gIEZhYnJpY0NvbnRyYWN0Q29udGV4dFxuPiB7XG4gIHByb3RlY3RlZCBvdmVycmlkZSBnZXRDbGllbnQoKTogdm9pZCB7XG4gICAgdGhyb3cgbmV3IFVuc3VwcG9ydGVkRXJyb3IoXCJDbGllbnQgaXMgbm90IHN1cHBvcnRlZCBpbiBGYWJyaWMgY29udHJhY3RzXCIpO1xuICB9XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVGV4dCBkZWNvZGVyIGZvciBjb252ZXJ0aW5nIGJpbmFyeSBkYXRhIHRvIHN0cmluZ3NcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIHRleHREZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKFwidXRmOFwiKTtcblxuICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHNlcmlhbGl6ZXIgPSBuZXcgU2ltcGxlRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXIoKTtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENvbnRleHQgY29uc3RydWN0b3IgZm9yIHRoaXMgYWRhcHRlclxuICAgKiBAc3VtbWFyeSBPdmVycmlkZXMgdGhlIGJhc2UgQ29udGV4dCBjb25zdHJ1Y3RvciB3aXRoIEZhYnJpY0NvbnRyYWN0Q29udGV4dFxuICAgKi9cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIHJlYWRvbmx5IENvbnRleHQ6IENvbnN0cnVjdG9yPEZhYnJpY0NvbnRyYWN0Q29udGV4dD4gPVxuICAgIEZhYnJpY0NvbnRyYWN0Q29udGV4dDtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEdldHMgdGhlIHJlcG9zaXRvcnkgY29uc3RydWN0b3IgZm9yIHRoaXMgYWRhcHRlclxuICAgKiBAc3VtbWFyeSBSZXR1cm5zIHRoZSBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnkgY29uc3RydWN0b3IgZm9yIGNyZWF0aW5nIHJlcG9zaXRvcmllc1xuICAgKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gICAqIEByZXR1cm4ge0NvbnN0cnVjdG9yPFJlcG9zaXRvcnk8TSwgTWFuZ29RdWVyeSwgRmFicmljQ29udHJhY3RBZGFwdGVyLCBGYWJyaWNDb250cmFjdEZsYWdzLCBGYWJyaWNDb250cmFjdENvbnRleHQ+Pn0gVGhlIHJlcG9zaXRvcnkgY29uc3RydWN0b3JcbiAgICovXG4gIG92ZXJyaWRlIHJlcG9zaXRvcnk8XG4gICAgUiBleHRlbmRzIFJlcG9zaXRvcnk8XG4gICAgICBhbnksXG4gICAgICBBZGFwdGVyPGFueSwgdm9pZCwgTWFuZ29RdWVyeSwgQ29udGV4dDxGYWJyaWNDb250cmFjdEZsYWdzPj5cbiAgICA+LFxuICA+KCk6IENvbnN0cnVjdG9yPFI+IHtcbiAgICByZXR1cm4gRmFicmljQ29udHJhY3RSZXBvc2l0b3J5IGFzIHVua25vd24gYXMgQ29uc3RydWN0b3I8Uj47XG4gIH1cblxuICBvdmVycmlkZSBQYWdpbmF0b3I8TSBleHRlbmRzIE1vZGVsPihcbiAgICBxdWVyeTogTWFuZ29RdWVyeSxcbiAgICBzaXplOiBudW1iZXIsXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+XG4gICk6IFBhZ2luYXRvcjxNLCBhbnksIE1hbmdvUXVlcnk+IHtcbiAgICByZXR1cm4gbmV3IEZhYnJpY0NvbnRyYWN0UGFnaW5hdG9yKHRoaXMsIHF1ZXJ5LCBzaXplLCBjbGF6eik7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBTZXF1ZW5jZShvcHRpb25zOiBTZXF1ZW5jZU9wdGlvbnMpOiBQcm9taXNlPFNlcXVlbmNlPiB7XG4gICAgcmV0dXJuIG5ldyBGYWJyaWNDb250cmFjdFNlcXVlbmNlKG9wdGlvbnMsIHRoaXMgYXMgYW55KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIG5ldyBGYWJyaWNDb250cmFjdEFkYXB0ZXIgaW5zdGFuY2VcbiAgICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgYW4gYWRhcHRlciBmb3IgaW50ZXJhY3Rpbmcgd2l0aCB0aGUgRmFicmljIHN0YXRlIGRhdGFiYXNlXG4gICAqIEBwYXJhbSB7dm9pZH0gc2NvcGUgLSBOb3QgdXNlZCBpbiB0aGlzIGFkYXB0ZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IFthbGlhc10gLSBPcHRpb25hbCBhbGlhcyBmb3IgdGhlIGFkYXB0ZXIgaW5zdGFuY2VcbiAgICovXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiB2b2lkLCBhbGlhcz86IHN0cmluZykge1xuICAgIHN1cGVyKHNjb3BlLCBGYWJyaWNGbGF2b3VyLCBhbGlhcyk7XG4gIH1cblxuICBvdmVycmlkZSBmb3IoY29uZmlnOiBQYXJ0aWFsPGFueT4sIC4uLmFyZ3M6IGFueSk6IHR5cGVvZiB0aGlzIHtcbiAgICByZXR1cm4gc3VwZXIuZm9yKGNvbmZpZywgLi4uYXJncyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSByZWNvcmQgaW4gdGhlIHN0YXRlIGRhdGFiYXNlXG4gICAqIEBzdW1tYXJ5IFNlcmlhbGl6ZXMgYSBtb2RlbCBhbmQgc3RvcmVzIGl0IGluIHRoZSBGYWJyaWMgc3RhdGUgZGF0YWJhc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyfSBpZCAtIFRoZSByZWNvcmQgaWRlbnRpZmllclxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIGFueT59IG1vZGVsIC0gVGhlIHJlY29yZCBkYXRhXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gdHJhbnNpZW50IC0gVHJhbnNpZW50IGRhdGEgKG5vdCB1c2VkIGluIHRoaXMgaW1wbGVtZW50YXRpb24pXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cywgaW5jbHVkaW5nIHRoZSBjaGFpbmNvZGUgc3R1YiBhbmQgbG9nZ2VyXG4gICAqIEByZXR1cm4ge1Byb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBjcmVhdGVkIHJlY29yZFxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgY3JlYXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkOiBQcmltYXJ5S2V5VHlwZSxcbiAgICBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxDb250ZXh0PEZhYnJpY0NvbnRyYWN0RmxhZ3M+PlxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+IHtcbiAgICBjb25zdCB7IGN0eCwgbG9nIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLmNyZWF0ZSk7XG4gICAgbG9nLmluZm8oYGluIEFEQVBURVIgY3JlYXRlIHdpdGggYXJncyAke2FyZ3N9YCk7XG4gICAgY29uc3QgdGFibGVOYW1lID0gTW9kZWwudGFibGVOYW1lKGNsYXp6KTtcbiAgICB0cnkge1xuICAgICAgbG9nLmluZm8oYGFkZGluZyBlbnRyeSB0byAke3RhYmxlTmFtZX0gdGFibGUgd2l0aCBwayAke2lkfWApO1xuICAgICAgY29uc3QgY29tcG9zZWRLZXkgPSBjdHguc3R1Yi5jcmVhdGVDb21wb3NpdGVLZXkodGFibGVOYW1lLCBbU3RyaW5nKGlkKV0pO1xuICAgICAgbW9kZWwgPSBhd2FpdCB0aGlzLnB1dFN0YXRlKGNvbXBvc2VkS2V5LCBtb2RlbCwgY3R4KTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuXG4gICAgcmV0dXJuIG1vZGVsO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZWFkcyBhIHJlY29yZCBmcm9tIHRoZSBzdGF0ZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBSZXRyaWV2ZXMgYW5kIGRlc2VyaWFsaXplcyBhIHJlY29yZCBmcm9tIHRoZSBGYWJyaWMgc3RhdGUgZGF0YWJhc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZS9jb2xsZWN0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyfSBpZCAtIFRoZSByZWNvcmQgaWRlbnRpZmllclxuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMsIGluY2x1ZGluZyB0aGUgY2hhaW5jb2RlIHN0dWIgYW5kIGxvZ2dlclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgcmV0cmlldmVkIHJlY29yZFxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgcmVhZDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDb250cmFjdEZsYWdzPj5cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+PiB7XG4gICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5yZWFkKTtcbiAgICBsb2cuaW5mbyhgaW4gQURBUFRFUiByZWFkIHdpdGggYXJncyAke2FyZ3N9YCk7XG4gICAgY29uc3QgdGFibGVOYW1lID0gTW9kZWwudGFibGVOYW1lKGNsYXp6KTtcblxuICAgIGxldCBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PjtcbiAgICB0cnkge1xuICAgICAgY29uc3QgY29tcG9zZWRLZXkgPSBjdHguc3R1Yi5jcmVhdGVDb21wb3NpdGVLZXkodGFibGVOYW1lLCBbU3RyaW5nKGlkKV0pO1xuICAgICAgbW9kZWwgPSBhd2FpdCB0aGlzLnJlYWRTdGF0ZShjb21wb3NlZEtleSwgY3R4KTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuXG4gICAgcmV0dXJuIG1vZGVsO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIGEgcmVjb3JkIGluIHRoZSBzdGF0ZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBTZXJpYWxpemVzIGEgbW9kZWwgYW5kIHVwZGF0ZXMgaXQgaW4gdGhlIEZhYnJpYyBzdGF0ZSBkYXRhYmFzZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlL2NvbGxlY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudW1iZXJ9IGlkIC0gVGhlIHJlY29yZCBpZGVudGlmaWVyXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gbW9kZWwgLSBUaGUgdXBkYXRlZCByZWNvcmQgZGF0YVxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIGFueT59IHRyYW5zaWVudCAtIFRyYW5zaWVudCBkYXRhIChub3QgdXNlZCBpbiB0aGlzIGltcGxlbWVudGF0aW9uKVxuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMsIGluY2x1ZGluZyB0aGUgY2hhaW5jb2RlIHN0dWIgYW5kIGxvZ2dlclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCByZWNvcmRcbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIHVwZGF0ZTxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8Q29udGV4dDxGYWJyaWNDb250cmFjdEZsYWdzPj5cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+PiB7XG4gICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy51cGRhdGUpO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShjbGF6eik7XG5cbiAgICB0cnkge1xuICAgICAgbG9nLnZlcmJvc2UoYHVwZGF0aW5nIGVudHJ5IHRvICR7dGFibGVOYW1lfSB0YWJsZSB3aXRoIHBrICR7aWR9YCk7XG4gICAgICBjb25zdCBjb21wb3NlZEtleSA9IGN0eC5zdHViLmNyZWF0ZUNvbXBvc2l0ZUtleSh0YWJsZU5hbWUsIFtTdHJpbmcoaWQpXSk7XG4gICAgICBtb2RlbCA9IGF3YWl0IHRoaXMucHV0U3RhdGUoY29tcG9zZWRLZXksIG1vZGVsLCBjdHgpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlIGFzIEVycm9yKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbW9kZWw7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIERlbGV0ZXMgYSByZWNvcmQgZnJvbSB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgUmV0cmlldmVzIGEgcmVjb3JkIGFuZCB0aGVuIHJlbW92ZXMgaXQgZnJvbSB0aGUgRmFicmljIHN0YXRlIGRhdGFiYXNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWJsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdGFibGUvY29sbGVjdGlvblxuICAgKiBAcGFyYW0ge3N0cmluZyB8IG51bWJlcn0gaWQgLSBUaGUgcmVjb3JkIGlkZW50aWZpZXIgdG8gZGVsZXRlXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cywgaW5jbHVkaW5nIHRoZSBjaGFpbmNvZGUgc3R1YiBhbmQgbG9nZ2VyXG4gICAqIEByZXR1cm4ge1Byb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBkZWxldGVkIHJlY29yZFxuICAgKi9cbiAgYXN5bmMgZGVsZXRlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkOiBQcmltYXJ5S2V5VHlwZSxcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxDb250ZXh0PEZhYnJpY0NvbnRyYWN0RmxhZ3M+PlxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+IHtcbiAgICBjb25zdCB7IGN0eCwgbG9nLCBjdHhBcmdzIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLmRlbGV0ZSk7XG4gICAgY29uc3QgdGFibGVOYW1lID0gTW9kZWwudGFibGVOYW1lKGNsYXp6KTtcbiAgICBsZXQgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGNvbXBvc2VkS2V5ID0gY3R4LnN0dWIuY3JlYXRlQ29tcG9zaXRlS2V5KHRhYmxlTmFtZSwgW1N0cmluZyhpZCldKTtcbiAgICAgIG1vZGVsID0gYXdhaXQgdGhpcy5yZWFkKGNsYXp6LCBpZCwgLi4uY3R4QXJncyk7XG4gICAgICBsb2cudmVyYm9zZShgZGVsZXRpbmcgZW50cnkgd2l0aCBwayAke2lkfSBmcm9tICR7dGFibGVOYW1lfSB0YWJsZWApO1xuICAgICAgYXdhaXQgdGhpcy5kZWxldGVTdGF0ZShjb21wb3NlZEtleSwgY3R4KTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuXG4gICAgcmV0dXJuIG1vZGVsO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGRlbGV0ZVN0YXRlKGlkOiBzdHJpbmcsIGNvbnRleHQ6IEZhYnJpY0NvbnRyYWN0Q29udGV4dCkge1xuICAgIGNvbnN0IHsgY3R4IH0gPSB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuZGVsZXRlU3RhdGUpO1xuICAgIGF3YWl0IGN0eC5zdHViLmRlbGV0ZVN0YXRlKGlkKTtcbiAgfVxuXG4gIGZvclByaXZhdGUoY29sbGVjdGlvbjogc3RyaW5nKTogRmFicmljQ29udHJhY3RBZGFwdGVyIHtcbiAgICBjb25zdCB0b092ZXJyaWRlID0gW1xuICAgICAgdGhpcy5wdXRTdGF0ZSxcbiAgICAgIHRoaXMucmVhZFN0YXRlLFxuICAgICAgdGhpcy5kZWxldGVTdGF0ZSxcbiAgICAgIHRoaXMucXVlcnlSZXN1bHQsXG4gICAgICB0aGlzLnF1ZXJ5UmVzdWx0UGFnaW5hdGVkLFxuICAgIF0ubWFwKChmbikgPT4gZm4ubmFtZSk7XG4gICAgcmV0dXJuIG5ldyBQcm94eSh0aGlzLCB7XG4gICAgICBnZXQodGFyZ2V0LCBwcm9wLCByZWNlaXZlcikge1xuICAgICAgICBpZiAoIXRvT3ZlcnJpZGUuaW5jbHVkZXMocHJvcCBhcyBzdHJpbmcpKVxuICAgICAgICAgIHJldHVybiBSZWZsZWN0LmdldCh0YXJnZXQsIHByb3AsIHJlY2VpdmVyKTtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm94eSgodGFyZ2V0IGFzIGFueSlbcHJvcF0sIHtcbiAgICAgICAgICBhc3luYyBhcHBseShmbiwgdGhpc0FyZywgYXJnc0xpc3QpIHtcbiAgICAgICAgICAgIHN3aXRjaCAocHJvcCkge1xuICAgICAgICAgICAgICBjYXNlIFwicHV0U3RhdGVcIjoge1xuICAgICAgICAgICAgICAgIGNvbnN0IFtzdHViLCBpZCwgbW9kZWxdID0gYXJnc0xpc3Q7XG4gICAgICAgICAgICAgICAgYXdhaXQgc3R1Yi5wdXRQcml2YXRlRGF0YShjb2xsZWN0aW9uLCBpZC50b1N0cmluZygpLCBtb2RlbCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1vZGVsO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGNhc2UgXCJkZWxldGVTdGF0ZVwiOiB7XG4gICAgICAgICAgICAgICAgY29uc3QgW3N0dWIsIGlkXSA9IGFyZ3NMaXN0O1xuICAgICAgICAgICAgICAgIHJldHVybiAoc3R1YiBhcyBDaGFpbmNvZGVTdHViKS5kZWxldGVQcml2YXRlRGF0YShcbiAgICAgICAgICAgICAgICAgIGNvbGxlY3Rpb24sXG4gICAgICAgICAgICAgICAgICBpZFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgY2FzZSBcInJlYWRTdGF0ZVwiOiB7XG4gICAgICAgICAgICAgICAgY29uc3QgW3N0dWIsIGlkXSA9IGFyZ3NMaXN0O1xuICAgICAgICAgICAgICAgIHJldHVybiBzdHViLmdldFByaXZhdGVEYXRhKGNvbGxlY3Rpb24sIGlkKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBjYXNlIFwicXVlcnlSZXN1bHRcIjoge1xuICAgICAgICAgICAgICAgIGNvbnN0IFtzdHViLCByYXdJbnB1dF0gPSBhcmdzTGlzdDtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3R1Yi5nZXRQcml2YXRlRGF0YVF1ZXJ5UmVzdWx0KGNvbGxlY3Rpb24sIHJhd0lucHV0KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBjYXNlIFwicXVlcnlSZXN1bHRQYWdpbmF0ZWRcIjoge1xuICAgICAgICAgICAgICAgIGNvbnN0IFtzdHViLCByYXdJbnB1dCwgbGltaXQsIHNraXBdID0gYXJnc0xpc3Q7XG4gICAgICAgICAgICAgICAgY29uc3QgaXRlcmF0b3IgPSBhd2FpdCAoXG4gICAgICAgICAgICAgICAgICBzdHViIGFzIENoYWluY29kZVN0dWJcbiAgICAgICAgICAgICAgICApLmdldFByaXZhdGVEYXRhUXVlcnlSZXN1bHQoY29sbGVjdGlvbiwgcmF3SW5wdXQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlc3VsdHM6IGFueVtdID0gW107XG4gICAgICAgICAgICAgICAgbGV0IGNvdW50ID0gMDtcbiAgICAgICAgICAgICAgICBsZXQgcmVhY2hlZEJvb2ttYXJrID0gc2tpcCA/IGZhbHNlIDogdHJ1ZTtcbiAgICAgICAgICAgICAgICBsZXQgbGFzdEtleTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG5cbiAgICAgICAgICAgICAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgaXRlcmF0b3IubmV4dCgpO1xuXG4gICAgICAgICAgICAgICAgICBpZiAocmVzLnZhbHVlICYmIHJlcy52YWx1ZS52YWx1ZS50b1N0cmluZygpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlY29yZEtleSA9IHJlcy52YWx1ZS5rZXk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHJlY29yZFZhbHVlID0gKHJlcy52YWx1ZS52YWx1ZSBhcyBhbnkpLnRvU3RyaW5nKFxuICAgICAgICAgICAgICAgICAgICAgIFwidXRmOFwiXG4gICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgd2UgaGF2ZSBhIHNraXAsIHNraXAgdW50aWwgd2UgcmVhY2ggaXRcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFyZWFjaGVkQm9va21hcmspIHtcbiAgICAgICAgICAgICAgICAgICAgICBpZiAocmVjb3JkS2V5ID09PSBza2lwPy50b1N0cmluZygpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWFjaGVkQm9va21hcmsgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICAgS2V5OiByZWNvcmRLZXksXG4gICAgICAgICAgICAgICAgICAgICAgUmVjb3JkOiBKU09OLnBhcnNlKHJlY29yZFZhbHVlKSxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIGxhc3RLZXkgPSByZWNvcmRLZXk7XG4gICAgICAgICAgICAgICAgICAgIGNvdW50Kys7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvdW50ID49IGxpbWl0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgYXdhaXQgaXRlcmF0b3IuY2xvc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaXRlcmF0b3I6XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgYXMgdW5rbm93biBhcyBJdGVyYXRvcnMuU3RhdGVRdWVyeUl0ZXJhdG9yLFxuICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgZmV0Y2hlZFJlY29yZHNDb3VudDogcmVzdWx0cy5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGJvb2ttYXJrOiBsYXN0S2V5LFxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgIGlmIChyZXMuZG9uZSkge1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCBpdGVyYXRvci5jbG9zZSgpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgIGl0ZXJhdG9yOlxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyBhcyB1bmtub3duIGFzIEl0ZXJhdG9ycy5TdGF0ZVF1ZXJ5SXRlcmF0b3IsXG4gICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZldGNoZWRSZWNvcmRzQ291bnQ6IHJlc3VsdHMubGVuZ3RoLFxuICAgICAgICAgICAgICAgICAgICAgICAgYm9va21hcms6IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICAgICAgICAgIGBVbnN1cHBvcnRlZCBtZXRob2Qgb3ZlcnJpZGUgJHtTdHJpbmcocHJvcCl9YFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICB9LFxuICAgIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIHB1dFN0YXRlKFxuICAgIGlkOiBzdHJpbmcsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgY3R4OiBGYWJyaWNDb250cmFjdENvbnRleHRcbiAgKSB7XG4gICAgbGV0IGRhdGE6IEJ1ZmZlcjtcblxuICAgIGNvbnN0IHsgbG9nIH0gPSB0aGlzLmxvZ0N0eChbY3R4XSwgdGhpcy5wdXRTdGF0ZSk7XG4gICAgdHJ5IHtcbiAgICAgIGRhdGEgPSBCdWZmZXIuZnJvbShcbiAgICAgICAgRmFicmljQ29udHJhY3RBZGFwdGVyLnNlcmlhbGl6ZXIuc2VyaWFsaXplKG1vZGVsIGFzIE1vZGVsLCBmYWxzZSlcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IFNlcmlhbGl6YXRpb25FcnJvcihcbiAgICAgICAgYEZhaWxlZCB0byBzZXJpYWxpemUgcmVjb3JkIHdpdGggaWQgJHtpZH06ICR7ZX1gXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbGxlY3Rpb24gPSBjdHguZ2V0KFwic2VncmVnYXRlZFwiKTtcbiAgICBpZiAoY29sbGVjdGlvbilcbiAgICAgIGF3YWl0IGN0eC5zdHViLnB1dFByaXZhdGVEYXRhKGNvbGxlY3Rpb24sIGlkLnRvU3RyaW5nKCksIGRhdGEpO1xuICAgIGVsc2UgYXdhaXQgY3R4LnN0dWIucHV0U3RhdGUoaWQudG9TdHJpbmcoKSwgZGF0YSk7XG5cbiAgICBsb2cuc2lsbHkoXG4gICAgICBgc3RhdGUgc3RvcmVkJHtjb2xsZWN0aW9uID8gYCBpbiAke2NvbGxlY3Rpb259IGNvbGxlY3Rpb25gIDogXCJcIn0gdW5kZXIgaWQgJHtpZH1gXG4gICAgKTtcbiAgICByZXR1cm4gbW9kZWw7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgcmVhZFN0YXRlKGlkOiBzdHJpbmcsIGN0eDogRmFicmljQ29udHJhY3RDb250ZXh0KSB7XG4gICAgbGV0IHJlc3VsdDogYW55O1xuXG4gICAgY29uc3QgeyBsb2cgfSA9IHRoaXMubG9nQ3R4KFtjdHhdLCB0aGlzLnJlYWRTdGF0ZSk7XG4gICAgbGV0IHJlczogc3RyaW5nO1xuICAgIGNvbnN0IGNvbGxlY3Rpb24gPSBjdHguZ2V0KFwic2VncmVnYXRlZFwiKTtcbiAgICBpZiAoY29sbGVjdGlvbilcbiAgICAgIHJlcyA9IChcbiAgICAgICAgYXdhaXQgY3R4LnN0dWIuZ2V0UHJpdmF0ZURhdGEoY29sbGVjdGlvbiwgaWQudG9TdHJpbmcoKSlcbiAgICAgICkudG9TdHJpbmcoKTtcbiAgICBlbHNlIHJlcyA9IChhd2FpdCBjdHguc3R1Yi5nZXRTdGF0ZShpZC50b1N0cmluZygpKSkudG9TdHJpbmcoKTtcblxuICAgIGlmICghcmVzKVxuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXJyb3IoXG4gICAgICAgIGBSZWNvcmQgd2l0aCBpZCAke2lkfSR7Y29sbGVjdGlvbiA/IGAgaW4gJHtjb2xsZWN0aW9ufSBjb2xsZWN0aW9uYCA6IFwiXCJ9IG5vdCBmb3VuZGBcbiAgICAgICk7XG4gICAgbG9nLnNpbGx5KFxuICAgICAgYHN0YXRlIHJldHJpZXZlZCBmcm9tJHtjb2xsZWN0aW9uID8gYCAke2NvbGxlY3Rpb259IGNvbGxlY3Rpb25gIDogXCJcIn0gdW5kZXIgaWQgJHtpZH1gXG4gICAgKTtcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gRmFicmljQ29udHJhY3RBZGFwdGVyLnNlcmlhbGl6ZXIuZGVzZXJpYWxpemUocmVzLnRvU3RyaW5nKCkpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoYEZhaWxlZCB0byBwYXJzZSByZWNvcmQ6ICR7ZX1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIHF1ZXJ5UmVzdWx0KFxuICAgIHN0dWI6IENoYWluY29kZVN0dWIsXG4gICAgcmF3SW5wdXQ6IGFueSxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPEl0ZXJhdG9ycy5TdGF0ZVF1ZXJ5SXRlcmF0b3I+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5yZWFkU3RhdGUpO1xuICAgIGxldCByZXM6IEl0ZXJhdG9ycy5TdGF0ZVF1ZXJ5SXRlcmF0b3I7XG4gICAgY29uc3QgY29sbGVjdGlvbiA9IGN0eC5nZXQoXCJzZWdyZWdhdGVkXCIpO1xuICAgIGlmIChjb2xsZWN0aW9uKVxuICAgICAgcmVzID0gYXdhaXQgY3R4LnN0dWIuZ2V0UHJpdmF0ZURhdGFRdWVyeVJlc3VsdChcbiAgICAgICAgY29sbGVjdGlvbixcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkocmF3SW5wdXQpXG4gICAgICApO1xuICAgIGVsc2UgcmVzID0gYXdhaXQgc3R1Yi5nZXRRdWVyeVJlc3VsdChKU09OLnN0cmluZ2lmeShyYXdJbnB1dCkpO1xuXG4gICAgcmV0dXJuIHJlcztcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBxdWVyeVJlc3VsdFBhZ2luYXRlZChcbiAgICBzdHViOiBDaGFpbmNvZGVTdHViLFxuICAgIHJhd0lucHV0OiBhbnksXG4gICAgbGltaXQ6IG51bWJlciA9IDI1MCxcbiAgICBza2lwPzogbnVtYmVyLFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8U3RhdGVRdWVyeVJlc3BvbnNlPEl0ZXJhdG9ycy5TdGF0ZVF1ZXJ5SXRlcmF0b3I+PiB7XG4gICAgY29uc3QgeyBjdHggfSA9IHRoaXMubG9nQ3R4KGFyZ3MsIHRoaXMucmVhZFN0YXRlKTtcbiAgICBsZXQgcmVzOiBTdGF0ZVF1ZXJ5UmVzcG9uc2U8SXRlcmF0b3JzLlN0YXRlUXVlcnlJdGVyYXRvcj47XG4gICAgY29uc3QgY29sbGVjdGlvbiA9IGN0eC5nZXQoXCJzZWdyZWdhdGVkXCIpO1xuICAgIGlmIChjb2xsZWN0aW9uKSB7XG4gICAgICByYXdJbnB1dC5zZWxlY3RvciA9IHtcbiAgICAgICAgLi4ucmF3SW5wdXQuc2VsZWN0b3IsXG4gICAgICAgIF9pZDogc2tpcCA/IHsgJGd0OiBza2lwLnRvU3RyaW5nKCkgfSA6IHsgJGd0ZTogXCJcIiB9LFxuICAgICAgfTtcbiAgICAgIGNvbnN0IGl0ID0gYXdhaXQgc3R1Yi5nZXRQcml2YXRlRGF0YVF1ZXJ5UmVzdWx0KFxuICAgICAgICBjb2xsZWN0aW9uLFxuICAgICAgICBKU09OLnN0cmluZ2lmeShyYXdJbnB1dClcbiAgICAgICk7XG4gICAgICByZXMgPSB7XG4gICAgICAgIGl0ZXJhdG9yOiBpdCxcbiAgICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgICBmZXRjaGVkUmVjb3Jkc0NvdW50OiBsaW1pdCxcbiAgICAgICAgICBib29rbWFyazogXCJcIixcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfSBlbHNlXG4gICAgICByZXMgPSBhd2FpdCBzdHViLmdldFF1ZXJ5UmVzdWx0V2l0aFBhZ2luYXRpb24oXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KHJhd0lucHV0KSxcbiAgICAgICAgbGltaXQsXG4gICAgICAgIHNraXA/LnRvU3RyaW5nKClcbiAgICAgICk7XG5cbiAgICByZXR1cm4gcmVzO1xuICB9XG5cbiAgcHJvdGVjdGVkIG1lcmdlTW9kZWxzKHJlc3VsdHM6IFJlY29yZDxzdHJpbmcsIGFueT5bXSk6IFJlY29yZDxzdHJpbmcsIGFueT4ge1xuICAgIGNvbnN0IGV4dHJhY3QgPSAobW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4pID0+XG4gICAgICBPYmplY3QuZW50cmllcyhtb2RlbCkucmVkdWNlKChhY2N1bTogUmVjb3JkPHN0cmluZywgYW55PiwgW2tleSwgdmFsXSkgPT4ge1xuICAgICAgICBpZiAodHlwZW9mIHZhbCAhPT0gXCJ1bmRlZmluZWRcIikgYWNjdW1ba2V5XSA9IHZhbDtcbiAgICAgICAgcmV0dXJuIGFjY3VtO1xuICAgICAgfSwge30pO1xuXG4gICAgbGV0IGZpbmFsTW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4gPSByZXN1bHRzLnBvcCgpIGFzIFJlY29yZDxzdHJpbmcsIGFueT47XG5cbiAgICBmb3IgKGNvbnN0IHJlcyBvZiByZXN1bHRzKSB7XG4gICAgICBmaW5hbE1vZGVsID0gT2JqZWN0LmFzc2lnbih7fSwgZXh0cmFjdChmaW5hbE1vZGVsKSwgZXh0cmFjdChyZXMpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZmluYWxNb2RlbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVjb2RlcyBiaW5hcnkgZGF0YSB0byBzdHJpbmdcbiAgICogQHN1bW1hcnkgQ29udmVydHMgYSBVaW50OEFycmF5IHRvIGEgc3RyaW5nIHVzaW5nIFVURi04IGVuY29kaW5nXG4gICAqIEBwYXJhbSB7VWludDhBcnJheX0gYnVmZmVyIC0gVGhlIGJpbmFyeSBkYXRhIHRvIGRlY29kZVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBkZWNvZGVkIHN0cmluZ1xuICAgKi9cbiAgcHJvdGVjdGVkIGRlY29kZShidWZmZXI6IFVpbnQ4QXJyYXkpIHtcbiAgICByZXR1cm4gRmFicmljQ29udHJhY3RBZGFwdGVyLnRleHREZWNvZGVyLmRlY29kZShidWZmZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIG9wZXJhdGlvbiBmbGFncyBmb3IgRmFicmljIGNvbnRyYWN0IG9wZXJhdGlvbnNcbiAgICogQHN1bW1hcnkgTWVyZ2VzIGRlZmF1bHQgZmxhZ3Mgd2l0aCBGYWJyaWMtc3BlY2lmaWMgY29udGV4dCBpbmZvcm1hdGlvblxuICAgKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gICAqIEBwYXJhbSB7T3BlcmF0aW9uS2V5c30gb3BlcmF0aW9uIC0gVGhlIG9wZXJhdGlvbiBiZWluZyBwZXJmb3JtZWRcbiAgICogQHBhcmFtIHtDb25zdHJ1Y3RvcjxNPn0gbW9kZWwgLSBUaGUgbW9kZWwgY29uc3RydWN0b3JcbiAgICogQHBhcmFtIHtQYXJ0aWFsPEZhYnJpY0NvbnRyYWN0RmxhZ3M+fSBmbGFncyAtIFBhcnRpYWwgZmxhZ3MgdG8gbWVyZ2Ugd2l0aCBkZWZhdWx0c1xuICAgKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICAgKiBAcmV0dXJuIHtGYWJyaWNDb250cmFjdEZsYWdzfSBUaGUgbWVyZ2VkIGZsYWdzXG4gICAqL1xuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgZmxhZ3M8TSBleHRlbmRzIE1vZGVsPihcbiAgICBvcGVyYXRpb246IE9wZXJhdGlvbktleXMsXG4gICAgbW9kZWw6IENvbnN0cnVjdG9yPE0+LFxuICAgIGZsYWdzOiBQYXJ0aWFsPEZhYnJpY0NvbnRyYWN0RmxhZ3M+LFxuICAgIGN0eDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8RmFicmljQ29udHJhY3RGbGFncz4ge1xuICAgIGNvbnN0IGJhc2VGbGFncyA9IHtcbiAgICAgIHN0dWI6IGN0eC5zdHViLFxuICAgICAgc2VncmVnYXRlZDogZmFsc2UsXG4gICAgfTtcbiAgICBpZiAoY3R4IGluc3RhbmNlb2YgRmFicmljQ29udHJhY3RDb250ZXh0KSB7XG4gICAgICBPYmplY3QuYXNzaWduKGJhc2VGbGFncywge1xuICAgICAgICBsb2dnZXI6IGN0eC5sb2dnZXIsXG4gICAgICAgIGlkZW50aXR5OiBjdHguaWRlbnRpdHksXG4gICAgICAgIGNvcnJlbGF0aW9uSWQ6IGN0eC5zdHViLmdldFR4SUQoKSxcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBPYmplY3QuYXNzaWduKGJhc2VGbGFncywge1xuICAgICAgICBpZGVudGl0eTogY3R4LmNsaWVudElkZW50aXR5LFxuICAgICAgICBsb2dnZXI6IG5ldyBDb250cmFjdExvZ2dlcih0aGlzIGFzIGFueSwgdW5kZWZpbmVkLCBjdHgpLFxuICAgICAgICBjb3JyZWxhdGlvbklkOiBjdHguc3R1Yi5nZXRUeElEKCksXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBmbGFncyA9IChhd2FpdCBzdXBlci5mbGFncyhcbiAgICAgIG9wZXJhdGlvbixcbiAgICAgIG1vZGVsLFxuICAgICAgYmFzZUZsYWdzIGFzIGFueSxcbiAgICAgIC4uLmFyZ3NcbiAgICApKSBhcyBGYWJyaWNDb250cmFjdEZsYWdzO1xuXG4gICAgcmV0dXJuIGZsYWdzIGFzIEZhYnJpY0NvbnRyYWN0RmxhZ3M7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYW4gaW5kZXggZm9yIGEgbW9kZWxcbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgaXMgbm90IGltcGxlbWVudGVkIGZvciBGYWJyaWMgY29udHJhY3RzIGFuZCByZXR1cm5zIGEgcmVzb2x2ZWQgcHJvbWlzZVxuICAgKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gICAqIEBwYXJhbSB7Q29uc3RydWN0b3I8TT59IG1vZGVscyAtIFRoZSBtb2RlbCBjb25zdHJ1Y3RvclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgaW1tZWRpYXRlbHlcbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgcHJvdGVjdGVkIGluZGV4PE0+KG1vZGVsczogQ29uc3RydWN0b3I8TT4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHVuZGVmaW5lZCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByb2Nlc3NlcyByZXN1bHRzIGZyb20gYSBzdGF0ZSBxdWVyeSBpdGVyYXRvclxuICAgKiBAc3VtbWFyeSBJdGVyYXRlcyB0aHJvdWdoIHF1ZXJ5IHJlc3VsdHMgYW5kIGNvbnZlcnRzIHRoZW0gdG8gYSBzdHJ1Y3R1cmVkIGZvcm1hdFxuICAgKiBAcGFyYW0ge0xvZ2dlcn0gbG9nIC0gTG9nZ2VyIGluc3RhbmNlIGZvciBkZWJ1Z2dpbmdcbiAgICogQHBhcmFtIHtJdGVyYXRvcnMuU3RhdGVRdWVyeUl0ZXJhdG9yfSBpdGVyYXRvciAtIFRoZSBzdGF0ZSBxdWVyeSBpdGVyYXRvclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtpc0hpc3Rvcnk9ZmFsc2VdIC0gV2hldGhlciB0aGlzIGlzIGEgaGlzdG9yeSBxdWVyeVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPGFueVtdPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gYXJyYXkgb2YgcHJvY2Vzc2VkIHJlc3VsdHNcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gICAqICAgcGFydGljaXBhbnQgUmVzdWx0SXRlcmF0b3JcbiAgICogICBwYXJ0aWNpcGFudCBJdGVyYXRvclxuICAgKlxuICAgKiAgIENhbGxlci0+PlJlc3VsdEl0ZXJhdG9yOiByZXN1bHRJdGVyYXRvcihsb2csIGl0ZXJhdG9yLCBpc0hpc3RvcnkpXG4gICAqICAgbG9vcCBVbnRpbCBkb25lXG4gICAqICAgICBSZXN1bHRJdGVyYXRvci0+Pkl0ZXJhdG9yOiBuZXh0KClcbiAgICogICAgIEl0ZXJhdG9yLS0+PlJlc3VsdEl0ZXJhdG9yOiB7IHZhbHVlLCBkb25lIH1cbiAgICogICAgIGFsdCBIYXMgdmFsdWVcbiAgICogICAgICAgUmVzdWx0SXRlcmF0b3ItPj5SZXN1bHRJdGVyYXRvcjogUHJvY2VzcyB2YWx1ZSBiYXNlZCBvbiBpc0hpc3RvcnlcbiAgICogICAgICAgUmVzdWx0SXRlcmF0b3ItPj5SZXN1bHRJdGVyYXRvcjogQWRkIHRvIHJlc3VsdHMgYXJyYXlcbiAgICogICAgIGVuZFxuICAgKiAgIGVuZFxuICAgKiAgIFJlc3VsdEl0ZXJhdG9yLT4+SXRlcmF0b3I6IGNsb3NlKClcbiAgICogICBSZXN1bHRJdGVyYXRvci0tPj5DYWxsZXI6IGFsbFJlc3VsdHNcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyByZXN1bHRJdGVyYXRvcihcbiAgICBsb2c6IExvZ2dlcixcbiAgICBpdGVyYXRvcjogSXRlcmF0b3JzLlN0YXRlUXVlcnlJdGVyYXRvcixcbiAgICBpc0hpc3RvcnkgPSBmYWxzZVxuICApIHtcbiAgICBjb25zdCBhbGxSZXN1bHRzID0gW107XG4gICAgbGV0IHJlczogeyB2YWx1ZTogYW55OyBkb25lOiBib29sZWFuIH0gPSBhd2FpdCBpdGVyYXRvci5uZXh0KCk7XG4gICAgd2hpbGUgKCFyZXMuZG9uZSkge1xuICAgICAgaWYgKHJlcy52YWx1ZSAmJiByZXMudmFsdWUudmFsdWUudG9TdHJpbmcoKSkge1xuICAgICAgICBsZXQganNvblJlczogYW55ID0ge307XG4gICAgICAgIGxvZy5kZWJ1ZyhyZXMudmFsdWUudmFsdWUudG9TdHJpbmcoXCJ1dGY4XCIpKTtcbiAgICAgICAgaWYgKGlzSGlzdG9yeSAvKiAmJiBpc0hpc3RvcnkgPT09IHRydWUqLykge1xuICAgICAgICAgIGpzb25SZXMuVHhJZCA9IHJlcy52YWx1ZS50eElkO1xuICAgICAgICAgIGpzb25SZXMuVGltZXN0YW1wID0gcmVzLnZhbHVlLnRpbWVzdGFtcDtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAganNvblJlcy5WYWx1ZSA9IEpTT04ucGFyc2UocmVzLnZhbHVlLnZhbHVlLnRvU3RyaW5nKFwidXRmOFwiKSk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgICAgIGxvZy5lcnJvcihlcnIpO1xuICAgICAgICAgICAganNvblJlcy5WYWx1ZSA9IHJlcy52YWx1ZS52YWx1ZS50b1N0cmluZyhcInV0ZjhcIik7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBqc29uUmVzID0gSlNPTi5wYXJzZShyZXMudmFsdWUudmFsdWUudG9TdHJpbmcoXCJ1dGY4XCIpKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgbG9nLmVycm9yKGVycik7XG4gICAgICAgICAgICBqc29uUmVzID0gcmVzLnZhbHVlLnZhbHVlLnRvU3RyaW5nKFwidXRmOFwiKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgYWxsUmVzdWx0cy5wdXNoKGpzb25SZXMpO1xuICAgICAgfVxuICAgICAgcmVzID0gYXdhaXQgaXRlcmF0b3IubmV4dCgpO1xuICAgIH1cbiAgICBsb2cuZGVidWcoYENsb3NpbmcgaXRlcmF0b3IgYWZ0ZXIgJHthbGxSZXN1bHRzLmxlbmd0aH0gcmVzdWx0c2ApO1xuICAgIGl0ZXJhdG9yLmNsb3NlKCk7IC8vIHB1cnBvc2VseSBub3QgYXdhaXQuIGxldCBpdGVyYXRvciBjbG9zZSBvbiBpdHMgb3duXG4gICAgcmV0dXJuIGFsbFJlc3VsdHM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV4ZWN1dGVzIGEgcmF3IHF1ZXJ5IGFnYWluc3QgdGhlIHN0YXRlIGRhdGFiYXNlXG4gICAqIEBzdW1tYXJ5IFBlcmZvcm1zIGEgcmljaCBxdWVyeSB1c2luZyBDb3VjaERCIHN5bnRheCBhZ2FpbnN0IHRoZSBGYWJyaWMgc3RhdGUgZGF0YWJhc2VcbiAgICogQHRlbXBsYXRlIFIgLSBUaGUgcmV0dXJuIHR5cGVcbiAgICogQHBhcmFtIHtNYW5nb1F1ZXJ5fSByYXdJbnB1dCAtIFRoZSBNYW5nbyBRdWVyeSB0byBleGVjdXRlXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gZG9jc09ubHkgLSBXaGV0aGVyIHRvIHJldHVybiBvbmx5IGRvY3VtZW50cyAobm90IHVzZWQgaW4gdGhpcyBpbXBsZW1lbnRhdGlvbilcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzLCBpbmNsdWRpbmcgdGhlIGNoYWluY29kZSBzdHViIGFuZCBsb2dnZXJcbiAgICogQHJldHVybiB7UHJvbWlzZTxSPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHF1ZXJ5IHJlc3VsdHNcbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gICAqICAgcGFydGljaXBhbnQgRmFicmljQ29udHJhY3RBZGFwdGVyXG4gICAqICAgcGFydGljaXBhbnQgU3R1YlxuICAgKiAgIHBhcnRpY2lwYW50IFN0YXRlREJcbiAgICpcbiAgICogICBDYWxsZXItPj5GYWJyaWNDb250cmFjdEFkYXB0ZXI6IHJhdyhyYXdJbnB1dCwgZG9jc09ubHksIGN0eClcbiAgICogICBGYWJyaWNDb250cmFjdEFkYXB0ZXItPj5GYWJyaWNDb250cmFjdEFkYXB0ZXI6IEV4dHJhY3QgbGltaXQgYW5kIHNraXBcbiAgICogICBhbHQgV2l0aCBwYWdpbmF0aW9uXG4gICAqICAgICBGYWJyaWNDb250cmFjdEFkYXB0ZXItPj5TdHViOiBnZXRRdWVyeVJlc3VsdFdpdGhQYWdpbmF0aW9uKHF1ZXJ5LCBsaW1pdCwgc2tpcClcbiAgICogICBlbHNlIFdpdGhvdXQgcGFnaW5hdGlvblxuICAgKiAgICAgRmFicmljQ29udHJhY3RBZGFwdGVyLT4+U3R1YjogZ2V0UXVlcnlSZXN1bHQocXVlcnkpXG4gICAqICAgZW5kXG4gICAqICAgU3R1Yi0+PlN0YXRlREI6IEV4ZWN1dGUgcXVlcnlcbiAgICogICBTdGF0ZURCLS0+PlN0dWI6IEl0ZXJhdG9yXG4gICAqICAgU3R1Yi0tPj5GYWJyaWNDb250cmFjdEFkYXB0ZXI6IEl0ZXJhdG9yXG4gICAqICAgRmFicmljQ29udHJhY3RBZGFwdGVyLT4+RmFicmljQ29udHJhY3RBZGFwdGVyOiByZXN1bHRJdGVyYXRvcihsb2csIGl0ZXJhdG9yKVxuICAgKiAgIEZhYnJpY0NvbnRyYWN0QWRhcHRlci0tPj5DYWxsZXI6IHJlc3VsdHNcbiAgICovXG4gIGFzeW5jIHJhdzxSLCBEIGV4dGVuZHMgYm9vbGVhbj4oXG4gICAgcmF3SW5wdXQ6IE1hbmdvUXVlcnksXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIGRvY3NPbmx5OiBEID0gdHJ1ZSBhcyBELFxuICAgIC4uLmFyZ3M6IENvbnRleHR1YWxBcmdzPEZhYnJpY0NvbnRyYWN0Q29udGV4dD5cbiAgKTogUHJvbWlzZTxSYXdSZXN1bHQ8UiwgRD4+IHtcbiAgICBjb25zdCB7IGxvZywgc3R1YiwgY3R4IH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnJhdyk7XG5cbiAgICBjb25zdCB7IHNraXAsIGxpbWl0IH0gPSByYXdJbnB1dDtcbiAgICBsZXQgaXRlcmF0b3I6IEl0ZXJhdG9ycy5TdGF0ZVF1ZXJ5SXRlcmF0b3I7XG4gICAgaWYgKGxpbWl0IHx8IHNraXApIHtcbiAgICAgIGRlbGV0ZSByYXdJbnB1dFtcImxpbWl0XCJdO1xuICAgICAgZGVsZXRlIHJhd0lucHV0W1wic2tpcFwiXTtcbiAgICAgIGxvZy5kZWJ1ZyhcbiAgICAgICAgYFJldHJpZXZpbmcgcGFnaW5hdGVkIGl0ZXJhdG9yOiBsaW1pdDogJHtsaW1pdH0vIHNraXA6ICR7c2tpcH1gXG4gICAgICApO1xuICAgICAgY29uc3QgcmVzcG9uc2U6IFN0YXRlUXVlcnlSZXNwb25zZTxJdGVyYXRvcnMuU3RhdGVRdWVyeUl0ZXJhdG9yPiA9XG4gICAgICAgIChhd2FpdCB0aGlzLnF1ZXJ5UmVzdWx0UGFnaW5hdGVkKFxuICAgICAgICAgIHN0dWIsXG4gICAgICAgICAgcmF3SW5wdXQsXG4gICAgICAgICAgbGltaXQgfHwgMjUwLFxuICAgICAgICAgIChza2lwIGFzIGFueSk/LnRvU3RyaW5nKCksXG4gICAgICAgICAgY3R4XG4gICAgICAgICkpIGFzIFN0YXRlUXVlcnlSZXNwb25zZTxJdGVyYXRvcnMuU3RhdGVRdWVyeUl0ZXJhdG9yPjtcbiAgICAgIGl0ZXJhdG9yID0gcmVzcG9uc2UuaXRlcmF0b3I7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZy5kZWJ1ZyhcIlJldHJpZXZpbmcgaXRlcmF0b3JcIik7XG4gICAgICBpdGVyYXRvciA9IChhd2FpdCB0aGlzLnF1ZXJ5UmVzdWx0KFxuICAgICAgICBzdHViLFxuICAgICAgICByYXdJbnB1dCxcbiAgICAgICAgY3R4XG4gICAgICApKSBhcyBJdGVyYXRvcnMuU3RhdGVRdWVyeUl0ZXJhdG9yO1xuICAgIH1cbiAgICBsb2cuZGVidWcoXCJJdGVyYXRvciBhY3F1aXJlZFwiKTtcblxuICAgIGNvbnN0IHJlc3VsdHMgPSAoYXdhaXQgdGhpcy5yZXN1bHRJdGVyYXRvcihsb2csIGl0ZXJhdG9yKSkgYXMgUjtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgcmV0dXJuaW5nICR7QXJyYXkuaXNBcnJheShyZXN1bHRzKSA/IHJlc3VsdHMubGVuZ3RoIDogMX0gcmVzdWx0c2BcbiAgICApO1xuICAgIHJldHVybiByZXN1bHRzIGFzIGFueTtcbiAgfVxuXG4gIG92ZXJyaWRlIFN0YXRlbWVudDxNIGV4dGVuZHMgTW9kZWw+KCk6IEZhYnJpY1N0YXRlbWVudDxNLCBhbnk+IHtcbiAgICByZXR1cm4gbmV3IEZhYnJpY1N0YXRlbWVudCh0aGlzIGFzIGFueSk7XG4gIH1cblxuICBvdmVycmlkZSBhc3luYyBjcmVhdGVBbGw8TSBleHRlbmRzIE1vZGVsPihcbiAgICB0YWJsZU5hbWU6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkOiBQcmltYXJ5S2V5VHlwZVtdLFxuICAgIG1vZGVsOiBSZWNvcmQ8c3RyaW5nLCBhbnk+W10sXG4gICAgLi4uYXJnczogQ29udGV4dHVhbEFyZ3M8RmFicmljQ29udHJhY3RDb250ZXh0PlxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT5bXT4ge1xuICAgIGlmIChpZC5sZW5ndGggIT09IG1vZGVsLmxlbmd0aClcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiSWRzIGFuZCBtb2RlbHMgbXVzdCBoYXZlIHRoZSBzYW1lIGxlbmd0aFwiKTtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy5jcmVhdGVBbGwpO1xuICAgIGNvbnN0IHRhYmxlTGFiZWwgPSBNb2RlbC50YWJsZU5hbWUodGFibGVOYW1lKTtcbiAgICBsb2cuZGVidWcoYENyZWF0aW5nICR7aWQubGVuZ3RofSBlbnRyaWVzICR7dGFibGVMYWJlbH0gdGFibGVgKTtcbiAgICByZXR1cm4gUHJvbWlzZS5hbGwoXG4gICAgICBpZC5tYXAoKGksIGNvdW50KSA9PiB0aGlzLmNyZWF0ZSh0YWJsZU5hbWUsIGksIG1vZGVsW2NvdW50XSwgLi4uY3R4QXJncykpXG4gICAgKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIHVwZGF0ZUFsbDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIHRhYmxlTmFtZTogQ29uc3RydWN0b3I8TT4sXG4gICAgaWQ6IFByaW1hcnlLZXlUeXBlW10sXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT5bXSxcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxGYWJyaWNDb250cmFjdENvbnRleHQ+XG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55PltdPiB7XG4gICAgaWYgKGlkLmxlbmd0aCAhPT0gbW9kZWwubGVuZ3RoKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJJZHMgYW5kIG1vZGVscyBtdXN0IGhhdmUgdGhlIHNhbWUgbGVuZ3RoXCIpO1xuICAgIGNvbnN0IHsgbG9nLCBjdHhBcmdzIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnVwZGF0ZUFsbCk7XG4gICAgY29uc3QgdGFibGVMYWJlbCA9IE1vZGVsLnRhYmxlTmFtZSh0YWJsZU5hbWUpO1xuICAgIGxvZy5kZWJ1ZyhgVXBkYXRpbmcgJHtpZC5sZW5ndGh9IGVudHJpZXMgJHt0YWJsZUxhYmVsfSB0YWJsZWApO1xuICAgIHJldHVybiBQcm9taXNlLmFsbChcbiAgICAgIGlkLm1hcCgoaSwgY291bnQpID0+IHRoaXMudXBkYXRlKHRhYmxlTmFtZSwgaSwgbW9kZWxbY291bnRdLCAuLi5jdHhBcmdzKSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqXG4gICAqIEBwYXJhbSBtb2RlbFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGtcbiAgICogQHBhcmFtIGFyZ3NcbiAgICovXG4gIG92ZXJyaWRlIHByZXBhcmU8TSBleHRlbmRzIE1vZGVsPihcbiAgICBtb2RlbDogTSxcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxGYWJyaWNDb250cmFjdENvbnRleHQ+XG4gICk6IFByZXBhcmVkTW9kZWwge1xuICAgIGNvbnN0IHsgbG9nIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnByZXBhcmUpO1xuXG4gICAgY29uc3QgdGFibGVOYW1lID0gTW9kZWwudGFibGVOYW1lKG1vZGVsLmNvbnN0cnVjdG9yIGFzIGFueSk7XG4gICAgY29uc3QgcGsgPSBNb2RlbC5wayhtb2RlbC5jb25zdHJ1Y3RvciBhcyBhbnkpO1xuICAgIGNvbnN0IHNwbGl0ID0gTW9kZWwuc2VncmVnYXRlKG1vZGVsKTtcbiAgICBjb25zdCByZXN1bHQgPSBPYmplY3QuZW50cmllcyhzcGxpdC5tb2RlbCkucmVkdWNlKFxuICAgICAgKGFjY3VtOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBba2V5LCB2YWxdKSA9PiB7XG4gICAgICAgIGlmICh0eXBlb2YgdmFsID09PSBcInVuZGVmaW5lZFwiKSByZXR1cm4gYWNjdW07XG4gICAgICAgIGNvbnN0IG1hcHBlZFByb3AgPSBNb2RlbC5jb2x1bW5OYW1lKG1vZGVsLCBrZXkgYXMgYW55KTtcbiAgICAgICAgaWYgKHRoaXMuaXNSZXNlcnZlZChtYXBwZWRQcm9wKSlcbiAgICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihgUHJvcGVydHkgbmFtZSAke21hcHBlZFByb3B9IGlzIHJlc2VydmVkYCk7XG4gICAgICAgIGFjY3VtW21hcHBlZFByb3BdID0gdmFsO1xuICAgICAgICByZXR1cm4gYWNjdW07XG4gICAgICB9LFxuICAgICAge31cbiAgICApO1xuXG4gICAgbG9nLnNpbGx5KFxuICAgICAgYFByZXBhcmluZyByZWNvcmQgZm9yICR7dGFibGVOYW1lfSB0YWJsZSB3aXRoIHBrICR7KG1vZGVsIGFzIGFueSlbcGtdfWBcbiAgICApO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHJlY29yZDogcmVzdWx0LFxuICAgICAgaWQ6IChtb2RlbCBhcyBhbnkpW3BrXSBhcyBzdHJpbmcsXG4gICAgICB0cmFuc2llbnQ6IHNwbGl0LnRyYW5zaWVudCxcbiAgICB9O1xuICB9XG5cbiAgb3ZlcnJpZGUgcmV2ZXJ0PE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgb2JqOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgdHJhbnNpZW50PzogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICAuLi5hcmdzOiBDb250ZXh0dWFsQXJnczxGYWJyaWNDb250cmFjdENvbnRleHQ+XG4gICk6IE0ge1xuICAgIGNvbnN0IHsgbG9nIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLnJldmVydCk7XG4gICAgY29uc3Qgb2I6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcbiAgICBjb25zdCBwayA9IE1vZGVsLnBrKGNsYXp6KTtcbiAgICBvYltwayBhcyBzdHJpbmddID0gaWQ7XG4gICAgY29uc3QgbSA9IChcbiAgICAgIHR5cGVvZiBjbGF6eiA9PT0gXCJzdHJpbmdcIiA/IE1vZGVsLmJ1aWxkKG9iLCBjbGF6eikgOiBuZXcgY2xhenoob2IpXG4gICAgKSBhcyBNO1xuICAgIGxvZy5zaWxseShgUmVidWlsZGluZyBtb2RlbCAke20uY29uc3RydWN0b3IubmFtZX0gaWQgJHtpZH1gKTtcbiAgICBjb25zdCByZXN1bHQgPSBPYmplY3Qua2V5cyhtKS5yZWR1Y2UoKGFjY3VtOiBNLCBrZXkpID0+IHtcbiAgICAgIChhY2N1bSBhcyBSZWNvcmQ8c3RyaW5nLCBhbnk+KVtrZXldID1cbiAgICAgICAgb2JqW01vZGVsLmNvbHVtbk5hbWUoYWNjdW0sIGtleSBhcyBhbnkpXTtcbiAgICAgIHJldHVybiBhY2N1bTtcbiAgICB9LCBtKTtcblxuICAgIGlmICh0cmFuc2llbnQpIHtcbiAgICAgIGxvZy5kZWJ1ZyhcbiAgICAgICAgYHJlLWFkZGluZyB0cmFuc2llbnQgcHJvcGVydGllczogJHtPYmplY3Qua2V5cyh0cmFuc2llbnQpLmpvaW4oXCIsIFwiKX1gXG4gICAgICApO1xuICAgICAgT2JqZWN0LmVudHJpZXModHJhbnNpZW50KS5mb3JFYWNoKChba2V5LCB2YWxdKSA9PiB7XG4gICAgICAgIGlmIChrZXkgaW4gcmVzdWx0ICYmIChyZXN1bHQgYXMgYW55KVtrZXldICE9PSB1bmRlZmluZWQpXG4gICAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgICAgICBgVHJhbnNpZW50IHByb3BlcnR5ICR7a2V5fSBhbHJlYWR5IGV4aXN0cyBvbiBtb2RlbCAke20uY29uc3RydWN0b3IubmFtZX0uIHNob3VsZCBiZSBpbXBvc3NpYmxlYFxuICAgICAgICAgICk7XG4gICAgICAgIHJlc3VsdFtrZXkgYXMga2V5b2YgTV0gPSB2YWw7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgb3ZlcnJpZGUgY3JlYXRlUHJlZml4PE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgdGFibGVOYW1lOiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPEZhYnJpY0NvbnRyYWN0Q29udGV4dD5cbiAgKSB7XG4gICAgY29uc3QgeyBjdHhBcmdzIH0gPSB0aGlzLmxvZ0N0eChhcmdzLCB0aGlzLmNyZWF0ZVByZWZpeCk7XG4gICAgY29uc3QgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgcmVjb3JkW0NvdWNoREJLZXlzLlRBQkxFXSA9IE1vZGVsLnRhYmxlTmFtZSh0YWJsZU5hbWUpO1xuICAgIE9iamVjdC5hc3NpZ24ocmVjb3JkLCBtb2RlbCk7XG5cbiAgICByZXR1cm4gW3RhYmxlTmFtZSwgaWQsIHJlY29yZCwgLi4uY3R4QXJnc10gYXMgW1xuICAgICAgQ29uc3RydWN0b3I8TT4sXG4gICAgICBQcmltYXJ5S2V5VHlwZSxcbiAgICAgIFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgICAuLi5hbnlbXSxcbiAgICAgIEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgICBdO1xuICB9XG5cbiAgb3ZlcnJpZGUgdXBkYXRlUHJlZml4PE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgdGFibGVOYW1lOiBDb25zdHJ1Y3RvcjxNPixcbiAgICBpZDogUHJpbWFyeUtleVR5cGUsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgLi4uYXJnczogTWF5YmVDb250ZXh0dWFsQXJnPEZhYnJpY0NvbnRyYWN0Q29udGV4dD5cbiAgKTogYW55W10ge1xuICAgIGNvbnN0IHsgY3R4QXJncyB9ID0gdGhpcy5sb2dDdHgoYXJncywgdGhpcy51cGRhdGVQcmVmaXgpO1xuICAgIGNvbnN0IHJlY29yZDogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgIHJlY29yZFtDb3VjaERCS2V5cy5UQUJMRV0gPSBNb2RlbC50YWJsZU5hbWUodGFibGVOYW1lKTtcbiAgICBPYmplY3QuYXNzaWduKHJlY29yZCwgbW9kZWwpO1xuXG4gICAgcmV0dXJuIFt0YWJsZU5hbWUsIGlkLCByZWNvcmQsIC4uLmN0eEFyZ3NdIGFzIFtcbiAgICAgIENvbnN0cnVjdG9yPE0+LFxuICAgICAgUHJpbWFyeUtleVR5cGUsXG4gICAgICBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgICAgLi4uYW55W10sXG4gICAgICBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gICAgXTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvdmVycmlkZSBjcmVhdGVBbGxQcmVmaXg8TSBleHRlbmRzIE1vZGVsPihcbiAgICB0YWJsZU5hbWU6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkczogUHJpbWFyeUtleVR5cGVbXSxcbiAgICBtb2RlbHM6IFJlY29yZDxzdHJpbmcsIGFueT5bXSxcbiAgICAuLi5hcmdzOiBbLi4uYW55LCBGYWJyaWNDb250cmFjdENvbnRleHRdXG4gICk6IChzdHJpbmcgfCBzdHJpbmdbXSB8IG51bWJlcltdIHwgUmVjb3JkPHN0cmluZywgYW55PltdKVtdIHtcbiAgICBpZiAoaWRzLmxlbmd0aCAhPT0gbW9kZWxzLmxlbmd0aClcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiSWRzIGFuZCBtb2RlbHMgbXVzdCBoYXZlIHRoZSBzYW1lIGxlbmd0aFwiKTtcblxuICAgIGNvbnN0IGN0eDogRmFicmljQ29udHJhY3RDb250ZXh0ID0gYXJncy5wb3AoKTtcblxuICAgIGNvbnN0IHJlY29yZHMgPSBpZHMubWFwKChpZCwgY291bnQpID0+IHtcbiAgICAgIGNvbnN0IHJlY29yZDogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgICAgcmVjb3JkW0NvdWNoREJLZXlzLlRBQkxFXSA9IE1vZGVsLnRhYmxlTmFtZSh0YWJsZU5hbWUpO1xuICAgICAgT2JqZWN0LmFzc2lnbihyZWNvcmQsIG1vZGVsc1tjb3VudF0pO1xuICAgICAgcmV0dXJuIHJlY29yZDtcbiAgICB9KTtcbiAgICByZXR1cm4gW3RhYmxlTmFtZSwgaWRzLCByZWNvcmRzLCBjdHggYXMgYW55XTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvdmVycmlkZSB1cGRhdGVBbGxQcmVmaXg8TSBleHRlbmRzIE1vZGVsPihcbiAgICB0YWJsZU5hbWU6IENvbnN0cnVjdG9yPE0+LFxuICAgIGlkczogUHJpbWFyeUtleVR5cGVbXSxcbiAgICBtb2RlbHM6IFJlY29yZDxzdHJpbmcsIGFueT5bXSxcbiAgICAuLi5hcmdzOiBbLi4uYW55LCBGYWJyaWNDb250cmFjdENvbnRleHRdXG4gICkge1xuICAgIGlmIChpZHMubGVuZ3RoICE9PSBtb2RlbHMubGVuZ3RoKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJJZHMgYW5kIG1vZGVscyBtdXN0IGhhdmUgdGhlIHNhbWUgbGVuZ3RoXCIpO1xuXG4gICAgY29uc3QgY3R4OiBGYWJyaWNDb250cmFjdENvbnRleHQgPSBhcmdzLnBvcCgpO1xuXG4gICAgY29uc3QgcmVjb3JkcyA9IGlkcy5tYXAoKGlkLCBjb3VudCkgPT4ge1xuICAgICAgY29uc3QgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgICByZWNvcmRbQ291Y2hEQktleXMuVEFCTEVdID0gTW9kZWwudGFibGVOYW1lKHRhYmxlTmFtZSk7XG4gICAgICBPYmplY3QuYXNzaWduKHJlY29yZCwgbW9kZWxzW2NvdW50XSk7XG4gICAgICByZXR1cm4gcmVjb3JkO1xuICAgIH0pO1xuICAgIHJldHVybiBbdGFibGVOYW1lLCBpZHMsIHJlY29yZHMsIGN0eCBhcyBhbnldO1xuICB9XG5cbiAgb3ZlcnJpZGUgcGFyc2VFcnJvcjxFIGV4dGVuZHMgQmFzZUVycm9yPihcbiAgICBlcnI6IEVycm9yIHwgc3RyaW5nLFxuICAgIHJlYXNvbj86IHN0cmluZ1xuICApOiBFIHtcbiAgICByZXR1cm4gRmFicmljQ29udHJhY3RBZGFwdGVyLnBhcnNlRXJyb3IocmVhc29uIHx8IGVycik7XG4gIH1cblxuICBvdmVycmlkZSBsb2dDdHg8QVJHUyBleHRlbmRzIGFueVtdPihcbiAgICBhcmdzOiBBUkdTLFxuICAgIG1ldGhvZDogKCguLi5hcmdzOiBhbnlbXSkgPT4gYW55KSB8IHN0cmluZ1xuICApOiBDb250ZXh0dWFsaXplZEFyZ3M8RmFicmljQ29udHJhY3RDb250ZXh0LCBBUkdTPiAmIHtcbiAgICBzdHViOiBDaGFpbmNvZGVTdHViO1xuICAgIGlkZW50aXR5OiBDbGllbnRJZGVudGl0eTtcbiAgfSB7XG4gICAgcmV0dXJuIEZhYnJpY0NvbnRyYWN0QWRhcHRlci5sb2dDdHguY2FsbCh0aGlzLCBhcmdzLCBtZXRob2QgYXMgYW55KSBhcyBhbnk7XG4gIH1cblxuICBzdGF0aWMgb3ZlcnJpZGUgbG9nQ3R4PEFSR1MgZXh0ZW5kcyBhbnlbXT4oXG4gICAgdGhpczogYW55LFxuICAgIGFyZ3M6IEFSR1MsXG4gICAgbWV0aG9kOiBzdHJpbmdcbiAgKTogQ29udGV4dHVhbGl6ZWRBcmdzPEZhYnJpY0NvbnRyYWN0Q29udGV4dCwgQVJHUz4gJiB7XG4gICAgc3R1YjogQ2hhaW5jb2RlU3R1YjtcbiAgICBpZGVudGl0eTogQ2xpZW50SWRlbnRpdHk7XG4gIH07XG4gIHN0YXRpYyBvdmVycmlkZSBsb2dDdHg8QVJHUyBleHRlbmRzIGFueVtdPihcbiAgICB0aGlzOiBhbnksXG4gICAgYXJnczogQVJHUyxcbiAgICBtZXRob2Q6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55XG4gICk6IENvbnRleHR1YWxpemVkQXJnczxGYWJyaWNDb250cmFjdENvbnRleHQsIEFSR1M+ICYge1xuICAgIHN0dWI6IENoYWluY29kZVN0dWI7XG4gICAgaWRlbnRpdHk6IENsaWVudElkZW50aXR5O1xuICB9O1xuICBzdGF0aWMgb3ZlcnJpZGUgbG9nQ3R4PEFSR1MgZXh0ZW5kcyBhbnlbXT4oXG4gICAgdGhpczogYW55LFxuICAgIGFyZ3M6IEFSR1MsXG4gICAgbWV0aG9kOiAoKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnkpIHwgc3RyaW5nXG4gICk6IENvbnRleHR1YWxpemVkQXJnczxGYWJyaWNDb250cmFjdENvbnRleHQsIEFSR1M+ICYge1xuICAgIHN0dWI6IENoYWluY29kZVN0dWI7XG4gICAgaWRlbnRpdHk6IENsaWVudElkZW50aXR5O1xuICB9IHtcbiAgICBpZiAoYXJncy5sZW5ndGggPCAxKSB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIk5vIGNvbnRleHQgcHJvdmlkZWRcIik7XG4gICAgY29uc3QgY3R4ID0gYXJncy5wb3AoKSBhcyBGYWJyaWNDb250cmFjdENvbnRleHQ7XG5cbiAgICBpZiAoIShjdHggaW5zdGFuY2VvZiBDb250ZXh0KSlcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiTm8gY29udGV4dCBwcm92aWRlZFwiKTtcbiAgICBpZiAoYXJncy5maWx0ZXIoKGEpID0+IGEgaW5zdGFuY2VvZiBDb250ZXh0KS5sZW5ndGggPiAxKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiaGVyZVwiKTtcbiAgICBjb25zdCBsb2cgPSAoXG4gICAgICB0aGlzXG4gICAgICAgID8gY3R4LmxvZ2dlci5mb3IodGhpcykuZm9yKG1ldGhvZClcbiAgICAgICAgOiBjdHgubG9nZ2VyLmNsZWFyKCkuZm9yKHRoaXMpLmZvcihtZXRob2QpXG4gICAgKSBhcyBMb2dnZXJPZjxGYWJyaWNDb250cmFjdENvbnRleHQ+O1xuICAgIHJldHVybiB7XG4gICAgICBjdHg6IGN0eCxcbiAgICAgIGxvZzogbWV0aG9kID8gKGxvZy5mb3IobWV0aG9kKSBhcyBMb2dnZXJPZjxGYWJyaWNDb250cmFjdENvbnRleHQ+KSA6IGxvZyxcbiAgICAgIHN0dWI6IGN0eC5zdHViLFxuICAgICAgaWRlbnRpdHk6IGN0eC5pZGVudGl0eSxcbiAgICAgIGN0eEFyZ3M6IFsuLi5hcmdzLCBjdHhdLFxuICAgIH07XG4gIH1cblxuICBzdGF0aWMgb3ZlcnJpZGUgcGFyc2VFcnJvcjxFIGV4dGVuZHMgQmFzZUVycm9yPihlcnI6IEVycm9yIHwgc3RyaW5nKTogRSB7XG4gICAgLy8gaWYgKFxuICAgIC8vICAgTUlTU0lOR19QUklWQVRFX0RBVEFfUkVHRVgudGVzdChcbiAgICAvLyAgICAgdHlwZW9mIGVyciA9PT0gXCJzdHJpbmdcIiA/IGVyciA6IGVyci5tZXNzYWdlXG4gICAgLy8gICApXG4gICAgLy8gKVxuICAgIC8vICAgcmV0dXJuIG5ldyBVbmF1dGhvcml6ZWRQcml2YXRlRGF0YUFjY2VzcyhlcnIpIGFzIEU7XG4gICAgY29uc3QgbXNnID0gdHlwZW9mIGVyciA9PT0gXCJzdHJpbmdcIiA/IGVyciA6IGVyci5tZXNzYWdlO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoTm90Rm91bmRFcnJvci5uYW1lKSkgcmV0dXJuIG5ldyBOb3RGb3VuZEVycm9yKGVycikgYXMgRTtcbiAgICBpZiAobXNnLmluY2x1ZGVzKENvbmZsaWN0RXJyb3IubmFtZSkpIHJldHVybiBuZXcgQ29uZmxpY3RFcnJvcihlcnIpIGFzIEU7XG4gICAgaWYgKG1zZy5pbmNsdWRlcyhCYWRSZXF1ZXN0RXJyb3IubmFtZSkpXG4gICAgICByZXR1cm4gbmV3IEJhZFJlcXVlc3RFcnJvcihlcnIpIGFzIEU7XG4gICAgaWYgKG1zZy5pbmNsdWRlcyhRdWVyeUVycm9yLm5hbWUpKSByZXR1cm4gbmV3IFF1ZXJ5RXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoUGFnaW5nRXJyb3IubmFtZSkpIHJldHVybiBuZXcgUGFnaW5nRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoVW5zdXBwb3J0ZWRFcnJvci5uYW1lKSlcbiAgICAgIHJldHVybiBuZXcgVW5zdXBwb3J0ZWRFcnJvcihlcnIpIGFzIEU7XG4gICAgaWYgKG1zZy5pbmNsdWRlcyhNaWdyYXRpb25FcnJvci5uYW1lKSkgcmV0dXJuIG5ldyBNaWdyYXRpb25FcnJvcihlcnIpIGFzIEU7XG4gICAgaWYgKG1zZy5pbmNsdWRlcyhPYnNlcnZlckVycm9yLm5hbWUpKSByZXR1cm4gbmV3IE9ic2VydmVyRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoQXV0aG9yaXphdGlvbkVycm9yLm5hbWUpKVxuICAgICAgcmV0dXJuIG5ldyBBdXRob3JpemF0aW9uRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoRm9yYmlkZGVuRXJyb3IubmFtZSkpIHJldHVybiBuZXcgRm9yYmlkZGVuRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoQ29ubmVjdGlvbkVycm9yLm5hbWUpKVxuICAgICAgcmV0dXJuIG5ldyBDb25uZWN0aW9uRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoU2VyaWFsaXphdGlvbkVycm9yLm5hbWUpKVxuICAgICAgcmV0dXJuIG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoZXJyKSBhcyBFO1xuICAgIGlmIChtc2cuaW5jbHVkZXMoXCJubyBsZWRnZXIgY29udGV4dFwiKSlcbiAgICAgIHJldHVybiBuZXcgTWlzc2luZ0NvbnRleHRFcnJvcihcbiAgICAgICAgYE5vIGNvbnRleHQgZm91bmQuIHRoaXMgY2FuIGJlIGNhdXNlZCBieSBkZWJ1Z2dpbmc6ICR7bXNnfWBcbiAgICAgICkgYXMgRTtcblxuICAgIHJldHVybiBuZXcgSW50ZXJuYWxFcnJvcihlcnIpIGFzIEU7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFN0YXRpYyBtZXRob2QgZm9yIGRlY29yYXRpb24gb3ZlcnJpZGVzXG4gICAqIEBzdW1tYXJ5IE92ZXJyaWRlcy9leHRlbmRzIGRlY2FmIGRlY29yYXRpb24gd2l0aCBGYWJyaWMtc3BlY2lmaWMgZnVuY3Rpb25hbGl0eVxuICAgKiBAc3RhdGljXG4gICAqIEBvdmVycmlkZVxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKi9cbiAgc3RhdGljIG92ZXJyaWRlIGRlY29yYXRpb24oKTogdm9pZCB7XG4gICAgc3VwZXIuZGVjb3JhdGlvbigpO1xuICAgIERlY29yYXRpb24uZmxhdm91cmVkQXMoRmFicmljRmxhdm91cilcbiAgICAgIC5mb3IoUGVyc2lzdGVuY2VLZXlzLkNSRUFURURfQlkpXG4gICAgICAuZGVmaW5lKFxuICAgICAgICBvbkNyZWF0ZShjcmVhdGVkQnlPbkZhYnJpY0NyZWF0ZVVwZGF0ZSksXG4gICAgICAgIHByb3BNZXRhZGF0YShQZXJzaXN0ZW5jZUtleXMuQ1JFQVRFRF9CWSwge30pXG4gICAgICApXG4gICAgICAuYXBwbHkoKTtcblxuICAgIERlY29yYXRpb24uZmxhdm91cmVkQXMoRmFicmljRmxhdm91cilcbiAgICAgIC5mb3IoUGVyc2lzdGVuY2VLZXlzLlVQREFURURfQlkpXG4gICAgICAuZGVmaW5lKFxuICAgICAgICBvbkNyZWF0ZVVwZGF0ZShjcmVhdGVkQnlPbkZhYnJpY0NyZWF0ZVVwZGF0ZSksXG4gICAgICAgIHByb3BNZXRhZGF0YShQZXJzaXN0ZW5jZUtleXMuVVBEQVRFRF9CWSwge30pXG4gICAgICApXG4gICAgICAuYXBwbHkoKTtcblxuICAgIERlY29yYXRpb24uZmxhdm91cmVkQXMoRmFicmljRmxhdm91cilcbiAgICAgIC5mb3IoUGVyc2lzdGVuY2VLZXlzLkNPTFVNTilcbiAgICAgIC5leHRlbmQoRmFicmljUHJvcGVydHkoKSlcbiAgICAgIC5hcHBseSgpO1xuXG4gICAgRGVjb3JhdGlvbi5mbGF2b3VyZWRBcyhGYWJyaWNGbGF2b3VyKVxuICAgICAgLmZvcihWYWxpZGF0aW9uS2V5cy5EQVRFKVxuICAgICAgLmV4dGVuZChmdW5jdGlvbiBmYWJyaWNQcm9wZXJ0eSgpIHtcbiAgICAgICAgcmV0dXJuICh0YXJnZXQ6IGFueSwgcHJvcD86IGFueSkgPT4ge1xuICAgICAgICAgIFByb3BlcnR5KHByb3AsIFwic3RyaW5nOmRhdGVcIikodGFyZ2V0LCBwcm9wKTtcbiAgICAgICAgfTtcbiAgICAgIH0pO1xuXG4gICAgRGVjb3JhdGlvbi5mbGF2b3VyZWRBcyhGYWJyaWNGbGF2b3VyKVxuICAgICAgLmZvcihQZXJzaXN0ZW5jZUtleXMuVEFCTEUpXG4gICAgICAuZXh0ZW5kKGZ1bmN0aW9uIHRhYmxlKG9iajogYW55KSB7XG4gICAgICAgIGNvbnN0IGNoYWluOiBhbnlbXSA9IFtdO1xuICAgICAgICBsZXQgY3VycmVudCA9XG4gICAgICAgICAgdHlwZW9mIG9iaiA9PT0gXCJmdW5jdGlvblwiXG4gICAgICAgICAgICA/IE1ldGFkYXRhLmNvbnN0cihvYmopXG4gICAgICAgICAgICA6IE1ldGFkYXRhLmNvbnN0cihvYmouY29uc3RydWN0b3IpO1xuXG4gICAgICAgIHdoaWxlIChjdXJyZW50ICYmIGN1cnJlbnQgIT09IE9iamVjdCAmJiBjdXJyZW50LnByb3RvdHlwZSkge1xuICAgICAgICAgIGNoYWluLnB1c2goY3VycmVudCk7XG4gICAgICAgICAgY3VycmVudCA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihjdXJyZW50KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnNvbGUubG9nKGNoYWluLm1hcCgoYykgPT4gYy5uYW1lIHx8IGMpKTtcblxuICAgICAgICAvLyBBcHBseSBmcm9tIHRoZSBiYXNlIGNsYXNzIGRvd24gdG8gdGhlIGRlY29yYXRlZCBjbGFzc1xuICAgICAgICB3aGlsZSAoY2hhaW4ubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGNvbnN0IGNvbnN0cnVjdG9yID0gY2hhaW4ucG9wKCk7XG4gICAgICAgICAgY29uc29sZS5sb2coYENhbGxpbmcgb24gJHtjb25zdHJ1Y3Rvci5uYW1lfWApO1xuICAgICAgICAgIEZhYnJpY09iamVjdCgpKGNvbnN0cnVjdG9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBGYWJyaWNPYmplY3QoKShvYmopO1xuICAgICAgfSlcbiAgICAgIC5hcHBseSgpO1xuICB9XG59XG5cbkZhYnJpY0NvbnRyYWN0QWRhcHRlci5kZWNvcmF0aW9uKCk7XG5BZGFwdGVyLnNldEN1cnJlbnQoRmFicmljRmxhdm91cik7XG4iLCIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzICovXG5pbXBvcnQgeyBDb25zdHJ1Y3RvciwgTWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7XG4gIEpTT05TZXJpYWxpemVyLFxuICBNb2RlbCxcbiAgTW9kZWxLZXlzLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERldGVybWluaXN0aWMgSlNPTiBzZXJpYWxpemVyIGZvciBGYWJyaWMgbW9kZWxzXG4gKiBAc3VtbWFyeSBFbnN1cmVzIHN0YWJsZSwgZGV0ZXJtaW5pc3RpYyBKU09OIG91dHB1dCBieSBzb3J0aW5nIG9iamVjdCBrZXlzIHJlY3Vyc2l2ZWx5IGJlZm9yZSBzdHJpbmdpZmljYXRpb24sIHdoaWNoIGlzIGltcG9ydGFudCBmb3IgRmFicmljIGVuZG9yc2VtZW50IGFuZCBoYXNoaW5nLiBFeHRlbmRzIEpTT05TZXJpYWxpemVyIHRvIHBsdWcgaW50byBleGlzdGluZyBEZWNhZiBtb2RlbCBzZXJpYWxpemF0aW9uIGZsb3cuXG4gKiBAdGVtcGxhdGUgTSAtIFRoZSBEZWNhZiBNb2RlbCBzdWJ0eXBlIHNlcmlhbGl6ZWQgYnkgdGhpcyBpbnN0YW5jZVxuICogQHBhcmFtIHt2b2lkfSBbY29uc3RydWN0b3JdIE5vIHB1YmxpYyBjb25zdHJ1Y3RvciBhcmd1bWVudHNcbiAqIEBjbGFzcyBEZXRlcm1pbmlzdGljU2VyaWFsaXplclxuICogQGV4YW1wbGVcbiAqIGNvbnN0IHNlcmlhbGl6ZXIgPSBuZXcgRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXI8TXlNb2RlbD4oKTtcbiAqIGNvbnN0IGpzb24gPSBzZXJpYWxpemVyLnNlcmlhbGl6ZShtb2RlbCk7XG4gKiBjb25zdCByZWJ1aWx0ID0gc2VyaWFsaXplci5kZXNlcmlhbGl6ZShqc29uKTtcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IERTIGFzIERldGVybWluaXN0aWNTZXJpYWxpemVyXG4gKiAgIENhbGxlci0+PkRTOiBzZXJpYWxpemUobW9kZWwpXG4gKiAgIERTLT4+RFM6IHByZVNlcmlhbGl6ZShtb2RlbClcbiAqICAgRFMtPj5EUzogc29ydC1rZXlzLXJlY3Vyc2l2ZVxuICogICBEUy0+PkRTOiBqc29uLXN0cmluZ2lmeS1kZXRlcm1pbmlzdGljXG4gKiAgIERTLS0+PkNhbGxlcjogc3RyaW5nXG4gKiAgIENhbGxlci0+PkRTOiBkZXNlcmlhbGl6ZShzdHJpbmcpXG4gKiAgIERTLS0+PkNhbGxlcjogbW9kZWxcbiAqL1xuZXhwb3J0IGNsYXNzIERldGVybWluaXN0aWNTZXJpYWxpemVyPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4+IGV4dGVuZHMgSlNPTlNlcmlhbGl6ZXI8TT4ge1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcigpO1xuICB9XG4gIHByb3RlY3RlZCBvdmVycmlkZSBwcmVTZXJpYWxpemUobW9kZWw6IE0pIHtcbiAgICAvLyBUT0RPOiBuZXN0ZWQgcHJlc2VyaWFsaXphdGlvbiAoc28gaW5jcmVhc2UgcGVyZm9ybWFuY2Ugd2hlbiBkZXNlcmlhbGl6aW5nKVxuICAgIC8vIFRPRE86IFZlcmlmeSB3aHkgdGhlcmUgaXMgbm8gbWV0YWRhdGFcbiAgICBjb25zdCB0b1NlcmlhbGl6ZTogUmVjb3JkPHN0cmluZywgYW55PiA9IE9iamVjdC5hc3NpZ24oe30sIG1vZGVsKTtcbiAgICBsZXQgbWV0YWRhdGE7XG4gICAgdHJ5IHtcbiAgICAgIG1ldGFkYXRhID0gTWV0YWRhdGEubW9kZWxOYW1lKG1vZGVsLmNvbnN0cnVjdG9yIGFzIENvbnN0cnVjdG9yKTtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICB9IGNhdGNoIChlcnJvcjogdW5rbm93bikge1xuICAgICAgbWV0YWRhdGEgPSB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHRvU2VyaWFsaXplW01vZGVsS2V5cy5BTkNIT1JdID0gbWV0YWRhdGEgfHwgbW9kZWwuY29uc3RydWN0b3IubmFtZTtcblxuICAgIGNvbnN0IHByZVNlcmlhbGl6ZSA9IGZ1bmN0aW9uIHByZVNlcmlhbGl6ZShcbiAgICAgIHRoaXM6IERldGVybWluaXN0aWNTZXJpYWxpemVyPGFueT4sXG4gICAgICBvYmo6IGFueVxuICAgICk6IGFueSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXRoaXMtYWxpYXNcbiAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgaWYgKHR5cGVvZiBvYmogIT09IFwib2JqZWN0XCIpIHJldHVybiBvYmo7XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShvYmopKSByZXR1cm4gb2JqLm1hcCgobykgPT4gcHJlU2VyaWFsaXplLmNhbGwoc2VsZiwgbykpO1xuICAgICAgcmV0dXJuIHRoaXMucHJlU2VyaWFsaXplLmNhbGwodGhpcywgb2JqKTtcbiAgICB9LmJpbmQodGhpcyk7XG5cbiAgICBNb2RlbC5yZWxhdGlvbnMobW9kZWwpLmZvckVhY2goKHIpID0+IHtcbiAgICAgIHRvU2VyaWFsaXplW3JdID0gcHJlU2VyaWFsaXplKHRvU2VyaWFsaXplW3JdKTtcbiAgICB9KTtcbiAgICByZXR1cm4gdG9TZXJpYWxpemU7XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgUmVidWlsZHMgYSBtb2RlbCBmcm9tIGEgc2VyaWFsaXphdGlvblxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyXG4gICAqXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBJZiBpdCBmYWlscyB0byBwYXJzZSB0aGUgc3RyaW5nLCBvciB0byBidWlsZCB0aGUgbW9kZWxcbiAgICovXG4gIG92ZXJyaWRlIGRlc2VyaWFsaXplKHN0cjogc3RyaW5nKTogTSB7XG4gICAgY29uc3QgZGVzZXJpYWxpemF0aW9uID0gSlNPTi5wYXJzZShzdHIpO1xuICAgIGNvbnN0IGNsYXNzTmFtZSA9IGRlc2VyaWFsaXphdGlvbltNb2RlbEtleXMuQU5DSE9SXTtcbiAgICBpZiAoIWNsYXNzTmFtZSlcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkNvdWxkIG5vdCBmaW5kIGNsYXNzIHJlZmVyZW5jZSBpbiBzZXJpYWxpemVkIG1vZGVsXCIpO1xuICAgIGNvbnN0IG1vZGVsOiBNID0gTW9kZWwuYnVpbGQoZGVzZXJpYWxpemF0aW9uLCBjbGFzc05hbWUpIGFzIHVua25vd24gYXMgTTtcbiAgICByZXR1cm4gbW9kZWw7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNlcmlhbGl6ZSBhIG1vZGVsIGludG8gYSBkZXRlcm1pbmlzdGljIEpTT04gc3RyaW5nXG4gICAqIEBzdW1tYXJ5IFByZXBhcmVzIHRoZSBtb2RlbCB3aXRoIHByZVNlcmlhbGl6ZSwgc29ydHMga2V5cyByZWN1cnNpdmVseSwgYW5kIHN0cmluZ2lmaWVzIGRldGVybWluaXN0aWNhbGx5IGZvciBzdGFibGUgb3JkZXJpbmdcbiAgICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZSB0byBzZXJpYWxpemVcbiAgICogQHJldHVybiB7c3RyaW5nfSBEZXRlcm1pbmlzdGljIEpTT04gcmVwcmVzZW50YXRpb24gb2YgdGhlIG1vZGVsXG4gICAqL1xuICBvdmVycmlkZSBzZXJpYWxpemUobW9kZWw6IE0pOiBzdHJpbmcge1xuICAgIGNvbnN0IHN0cmluZ2lmeSA9IHJlcXVpcmUoXCJqc29uLXN0cmluZ2lmeS1kZXRlcm1pbmlzdGljXCIpO1xuICAgIGNvbnN0IHNvcnRLZXlzUmVjdXJzaXZlID0gcmVxdWlyZShcInNvcnQta2V5cy1yZWN1cnNpdmVcIik7XG4gICAgcmV0dXJuIHN0cmluZ2lmeShzb3J0S2V5c1JlY3Vyc2l2ZSh0aGlzLnByZVNlcmlhbGl6ZShtb2RlbCkpKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgRmFicmljQ29udHJhY3RBZGFwdGVyIH0gZnJvbSBcIi4uL0NvbnRyYWN0QWRhcHRlclwiO1xuaW1wb3J0IHsgQ29udHJhY3QsIENvbnRleHQgYXMgQ3R4IH0gZnJvbSBcImZhYnJpYy1jb250cmFjdC1hcGlcIjtcbmltcG9ydCB7IE1vZGVsLCBTZXJpYWxpemVyIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHtcbiAgQ29uZGl0aW9uLFxuICBDb250ZXh0LFxuICBDb250ZXh0dWFsaXplZEFyZ3MsXG4gIERpcmVjdGlvbkxpbWl0T2Zmc2V0LFxuICBMb2dnZXJPZixcbiAgTWF5YmVDb250ZXh0dWFsQXJnLFxuICBPcmRlckRpcmVjdGlvbixcbiAgUmVwb3NpdG9yeSxcbiAgU2VyaWFsaXplZFBhZ2UsXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5IH0gZnJvbSBcIi4uL0ZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeVwiO1xuaW1wb3J0IHsgRGV0ZXJtaW5pc3RpY1NlcmlhbGl6ZXIgfSBmcm9tIFwiLi4vLi4vc2hhcmVkL0RldGVybWluaXN0aWNTZXJpYWxpemVyXCI7XG5pbXBvcnQgeyBNYW5nb1F1ZXJ5IH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItY291Y2hkYlwiO1xuaW1wb3J0IHsgQ2hlY2thYmxlLCBoZWFsdGhjaGVjayB9IGZyb20gXCIuLi8uLi9zaGFyZWQvaW50ZXJmYWNlcy9DaGVja2FibGVcIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdENvbnRleHQgfSBmcm9tIFwiLi4vQ29udHJhY3RDb250ZXh0XCI7XG5pbXBvcnQge1xuICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMsXG4gIEludGVybmFsRXJyb3IsXG4gIE9wZXJhdGlvbktleXMsXG4gIFByaW1hcnlLZXlUeXBlLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IENoYWluY29kZVN0dWIsIENsaWVudElkZW50aXR5IH0gZnJvbSBcImZhYnJpYy1zaGltLWFwaVwiO1xuaW1wb3J0IHsgT2JqZWN0IGFzIEZhYnJpY09iamVjdCB9IGZyb20gXCJmYWJyaWMtY29udHJhY3QtYXBpXCI7XG5cbkZhYnJpY09iamVjdCgpKERhdGUpO1xuLyoqXG4gKiBAZGVzY3JpcHRpb24gQmFzZSBjb250cmFjdCBjbGFzcyBmb3IgQ1JVRCBvcGVyYXRpb25zIGluIEZhYnJpYyBjaGFpbmNvZGVcbiAqIEBzdW1tYXJ5IFByb3ZpZGVzIHN0YW5kYXJkIGNyZWF0ZSwgcmVhZCwgdXBkYXRlLCBhbmQgZGVsZXRlIG9wZXJhdGlvbnMgZm9yIG1vZGVscyBpbiBGYWJyaWMgY2hhaW5jb2RlXG4gKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAY2xhc3MgRmFicmljQ3J1ZENvbnRyYWN0XG4gKiBAZXh0ZW5kcyB7Q29udHJhY3R9XG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gRGVmaW5lIGEgbW9kZWxcbiAqIEB0YWJsZSgnYXNzZXRzJylcbiAqIGNsYXNzIEFzc2V0IGV4dGVuZHMgTW9kZWwge1xuICogICBAaWQoKVxuICogICBpZDogc3RyaW5nO1xuICpcbiAqICAgQHByb3BlcnR5KClcbiAqICAgZGF0YTogc3RyaW5nO1xuICogfVxuICpcbiAqIC8vIENyZWF0ZSBhIGNvbnRyYWN0IHRoYXQgZXh0ZW5kcyBGYWJyaWNDcnVkQ29udHJhY3RcbiAqIGV4cG9ydCBjbGFzcyBBc3NldENvbnRyYWN0IGV4dGVuZHMgRmFicmljQ3J1ZENvbnRyYWN0PEFzc2V0PiB7XG4gKiAgIGNvbnN0cnVjdG9yKCkge1xuICogICAgIHN1cGVyKCdBc3NldENvbnRyYWN0JywgQXNzZXQpO1xuICogICB9XG4gKlxuICogICAvLyBBZGQgY3VzdG9tIG1ldGhvZHMgYXMgbmVlZGVkXG4gKiAgIGFzeW5jIGdldEFzc2V0SGlzdG9yeShjdHg6IENvbnRleHQsIGlkOiBzdHJpbmcpOiBQcm9taXNlPGFueVtdPiB7XG4gKiAgICAgLy8gQ3VzdG9tIGltcGxlbWVudGF0aW9uXG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDbGllbnRcbiAqICAgcGFydGljaXBhbnQgQ29udHJhY3RcbiAqICAgcGFydGljaXBhbnQgUmVwb3NpdG9yeVxuICogICBwYXJ0aWNpcGFudCBBZGFwdGVyXG4gKiAgIHBhcnRpY2lwYW50IFN0YXRlREJcbiAqXG4gKiAgIENsaWVudC0+PkNvbnRyYWN0OiBjcmVhdGUoY3R4LCBtb2RlbClcbiAqICAgQ29udHJhY3QtPj5SZXBvc2l0b3J5OiByZXBvc2l0b3J5KGN0eClcbiAqICAgQ29udHJhY3QtPj5SZXBvc2l0b3J5OiBjcmVhdGUobW9kZWwsIGN0eClcbiAqICAgUmVwb3NpdG9yeS0+PkFkYXB0ZXI6IGNyZWF0ZSh0YWJsZU5hbWUsIGlkLCByZWNvcmQsIHRyYW5zaWVudCwgY3R4KVxuICogICBBZGFwdGVyLT4+U3RhdGVEQjogcHV0U3RhdGUoaWQsIHNlcmlhbGl6ZWREYXRhKVxuICogICBTdGF0ZURCLS0+PkFkYXB0ZXI6IFN1Y2Nlc3NcbiAqICAgQWRhcHRlci0tPj5SZXBvc2l0b3J5OiByZWNvcmRcbiAqICAgUmVwb3NpdG9yeS0tPj5Db250cmFjdDogbW9kZWxcbiAqICAgQ29udHJhY3QtLT4+Q2xpZW50OiBtb2RlbFxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgRmFicmljQ3J1ZENvbnRyYWN0PE0gZXh0ZW5kcyBNb2RlbD5cbiAgZXh0ZW5kcyBDb250cmFjdFxuICBpbXBsZW1lbnRzIENoZWNrYWJsZVxue1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFNoYXJlZCBhZGFwdGVyIGluc3RhbmNlIGZvciBhbGwgY29udHJhY3QgaW5zdGFuY2VzXG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIGFkYXB0ZXI6IEZhYnJpY0NvbnRyYWN0QWRhcHRlciA9IG5ldyBGYWJyaWNDb250cmFjdEFkYXB0ZXIoKTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgcmVwbzogRmFicmljQ29udHJhY3RSZXBvc2l0b3J5PE0+O1xuXG4gIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgc2VyaWFsaXplciA9IG5ldyBEZXRlcm1pbmlzdGljU2VyaWFsaXplcigpO1xuXG4gIHByb3RlY3RlZCBpbml0aWFsaXplZDogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIG5ldyBGYWJyaWNDcnVkQ29udHJhY3QgaW5zdGFuY2VcbiAgICogQHN1bW1hcnkgSW5pdGlhbGl6ZXMgYSBjb250cmFjdCB3aXRoIGEgbmFtZSBhbmQgbW9kZWwgY2xhc3NcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgY29udHJhY3RcbiAgICogQHBhcmFtIHtDb25zdHJ1Y3RvcjxNPn0gY2xhenogLSBUaGUgbW9kZWwgY29uc3RydWN0b3JcbiAgICovXG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihcbiAgICBuYW1lOiBzdHJpbmcsXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGNsYXp6OiBDb25zdHJ1Y3RvcjxNPlxuICApIHtcbiAgICBzdXBlcihuYW1lKTtcbiAgICB0aGlzLnJlcG8gPSBSZXBvc2l0b3J5LmZvck1vZGVsKGNsYXp6KTtcbiAgfVxuXG4gIGFzeW5jIGxpc3RCeShcbiAgICBjdHg6IEN0eCB8IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgICBrZXk6IHN0cmluZyB8IGtleW9mIE0sXG4gICAgb3JkZXI6IHN0cmluZyxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPE1bXSB8IHN0cmluZz4ge1xuICAgIGNvbnN0IHsgY3R4QXJncywgbG9nIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbLi4uYXJncywgY3R4XSwgdGhpcy5saXN0QnkpO1xuICAgIGxvZy5pbmZvKFxuICAgICAgYFJ1bm5pbmcgbGlzdEJ5IGtleSAke2tleSBhcyBzdHJpbmd9LCBvcmRlciAke29yZGVyfSBhbmQgYXJncyAke2N0eEFyZ3N9YFxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMucmVwby5saXN0QnkoXG4gICAgICBrZXkgYXMga2V5b2YgTSxcbiAgICAgIG9yZGVyIGFzIE9yZGVyRGlyZWN0aW9uLFxuICAgICAgLi4uY3R4QXJnc1xuICAgICk7XG4gIH1cblxuICBhc3luYyBwYWdpbmF0ZUJ5KFxuICAgIGN0eDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIGtleTogc3RyaW5nIHwga2V5b2YgTSxcbiAgICBvcmRlcjogc3RyaW5nLFxuICAgIHJlZjogT21pdDxEaXJlY3Rpb25MaW1pdE9mZnNldCwgXCJkaXJlY3Rpb25cIj4gfCBzdHJpbmcgPSB7XG4gICAgICBvZmZzZXQ6IDEsXG4gICAgICBsaW1pdDogMTAsXG4gICAgfSxcbiAgICAuLi5hcmdzOiBNYXliZUNvbnRleHR1YWxBcmc8RmFicmljQ29udHJhY3RDb250ZXh0PlxuICApOiBQcm9taXNlPFNlcmlhbGl6ZWRQYWdlPE0+IHwgc3RyaW5nPiB7XG4gICAgY29uc3QgeyBjdHhBcmdzLCBsb2cgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLnBhZ2luYXRlQnkpO1xuICAgIGxvZy5pbmZvKFxuICAgICAgYFJ1bm5pbmcgcGFnaW5hdGVCeSBrZXkgJHtrZXkgYXMgc3RyaW5nfSwgb3JkZXIgJHtvcmRlcn0gd2l0aCBzaXplICR7KHJlZiBhcyBhbnkpLmxpbWl0fSBhbmQgYXJncyAke2N0eEFyZ3N9YFxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMucmVwby5wYWdpbmF0ZUJ5KFxuICAgICAga2V5IGFzIGtleW9mIE0sXG4gICAgICBvcmRlciBhcyBhbnksXG4gICAgICByZWYgYXMgYW55LFxuICAgICAgLi4uY3R4QXJnc1xuICAgICk7XG4gIH1cblxuICBhc3luYyBmaW5kT25lQnkoXG4gICAgY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gICAga2V5OiBzdHJpbmcgfCBrZXlvZiBNLFxuICAgIHZhbHVlOiBhbnksXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxNIHwgc3RyaW5nPiB7XG4gICAgY29uc3QgeyBjdHhBcmdzLCBsb2cgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLmZpbmRPbmVCeSk7XG4gICAgbG9nLmluZm8oXG4gICAgICBgUnVubmluZyBmaW5kT25lQnkga2V5ICR7a2V5IGFzIHN0cmluZ30sIHZhbHVlOiAke3ZhbHVlfSB3aXRoIGFyZ3MgJHtjdHhBcmdzfWBcbiAgICApO1xuICAgIHJldHVybiB0aGlzLnJlcG8uZmluZE9uZUJ5KGtleSBhcyBrZXlvZiBNLCB2YWx1ZSwgLi4uY3R4QXJncyk7XG4gIH1cblxuICBhc3luYyBzdGF0ZW1lbnQoXG4gICAgY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gICAgbWV0aG9kOiBzdHJpbmcsXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxhbnk+IHtcbiAgICBjb25zdCB7IGN0eEFyZ3MsIGxvZyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoWy4uLmFyZ3MsIGN0eF0sIHRoaXMuc3RhdGVtZW50KTtcbiAgICBsb2cuaW5mbyhgUnVubmluZyBzdGF0ZW1lbnQgJHttZXRob2R9IHdpdGggYXJncyAke2N0eEFyZ3N9YCk7XG4gICAgcmV0dXJuIHRoaXMucmVwby5zdGF0ZW1lbnQobWV0aG9kLCAuLi5jdHhBcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIHNpbmdsZSBtb2RlbCBpbiB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgY3JlYXRlIG1ldGhvZFxuICAgKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICAgKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIHRvIGNyZWF0ZVxuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgICogQHJldHVybiB7UHJvbWlzZTxNPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGNyZWF0ZWQgbW9kZWxcbiAgICovXG4gIGFzeW5jIGNyZWF0ZShcbiAgICBjdHg6IEN0eCB8IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgICBtb2RlbDogc3RyaW5nIHwgTSxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPHN0cmluZyB8IE0+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoWy4uLmFyZ3MsIGN0eF0sIHRoaXMuY3JlYXRlKTtcbiAgICBsb2cuaW5mbyhgQ09OVFJBQ1QgQ1JFQVRFLCAke2N0eEFyZ3N9YCk7XG5cbiAgICBpZiAodHlwZW9mIG1vZGVsID09PSBcInN0cmluZ1wiKSBtb2RlbCA9IHRoaXMuZGVzZXJpYWxpemU8TT4obW9kZWwpIGFzIE07XG5cbiAgICBsb2cuaW5mbyhgQ3JlYXRpbmcgbW9kZWw6ICR7SlNPTi5zdHJpbmdpZnkobW9kZWwpfWApO1xuXG4gICAgY29uc3QgdHJhbnNpZW50ID0gdGhpcy5nZXRUcmFuc2llbnREYXRhKGN0eCk7XG5cbiAgICBsb2cuaW5mbyhgTWVyZ2luZyB0cmFuc2llbnQgZGF0YS4uLmApO1xuICAgIG1vZGVsID0gTW9kZWwubWVyZ2UobW9kZWwsIHRyYW5zaWVudCwgdGhpcy5jbGF6eikgYXMgTTtcblxuICAgIHJldHVybiB0aGlzLnJlcG8uY3JlYXRlKG1vZGVsLCAuLi5jdHhBcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVhZHMgYSBzaW5nbGUgbW9kZWwgZnJvbSB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgcmVhZCBtZXRob2RcbiAgICogQHBhcmFtIHtDdHh9IGN0eCAtIFRoZSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRleHRcbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudW1iZXJ9IGtleSAtIFRoZSBrZXkgb2YgdGhlIG1vZGVsIHRvIHJlYWRcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSByZXRyaWV2ZWQgbW9kZWxcbiAgICovXG4gIGFzeW5jIHJlYWQoXG4gICAgY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gICAga2V5OiBQcmltYXJ5S2V5VHlwZSB8IHN0cmluZyxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPE0gfCBzdHJpbmc+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoWy4uLmFyZ3MsIGN0eF0sIHRoaXMucmVhZCk7XG5cbiAgICBsb2cuaW5mbyhgcmVhZGluZyBlbnRyeSB3aXRoIHBrICR7a2V5fSBgKTtcblxuICAgIHJldHVybiB0aGlzLnJlcG8ucmVhZChrZXksIC4uLmN0eEFyZ3MpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldFRyYW5zaWVudERhdGEoY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQpOiBhbnkge1xuICAgIGNvbnN0IHRyYW5zaWVudE1hcCA9IGN0eC5zdHViLmdldFRyYW5zaWVudCgpO1xuICAgIGxldCB0cmFuc2llbnQ6IGFueSA9IHt9O1xuXG4gICAgaWYgKHRyYW5zaWVudE1hcC5oYXMoKHRoaXMucmVwbyBhcyBhbnkpLnRhYmxlTmFtZSkpIHtcbiAgICAgIHRyYW5zaWVudCA9IEpTT04ucGFyc2UoXG4gICAgICAgICh0cmFuc2llbnRNYXAuZ2V0KCh0aGlzLnJlcG8gYXMgYW55KS50YWJsZU5hbWUpIGFzIEJ1ZmZlcik/LnRvU3RyaW5nKFxuICAgICAgICAgIFwidXRmOFwiXG4gICAgICAgICkgYXMgc3RyaW5nXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiB0cmFuc2llbnQ7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFVwZGF0ZXMgYSBzaW5nbGUgbW9kZWwgaW4gdGhlIHN0YXRlIGRhdGFiYXNlXG4gICAqIEBzdW1tYXJ5IERlbGVnYXRlcyB0byB0aGUgcmVwb3NpdG9yeSdzIHVwZGF0ZSBtZXRob2RcbiAgICogQHBhcmFtIHtDdHh9IGN0eCAtIFRoZSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRleHRcbiAgICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCB0byB1cGRhdGVcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIG1vZGVsXG4gICAqL1xuICBhc3luYyB1cGRhdGUoXG4gICAgY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gICAgbW9kZWw6IHN0cmluZyB8IE0sXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxzdHJpbmcgfCBNPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLnVwZGF0ZSk7XG5cbiAgICBpZiAodHlwZW9mIG1vZGVsID09PSBcInN0cmluZ1wiKSBtb2RlbCA9IHRoaXMuZGVzZXJpYWxpemU8TT4obW9kZWwpIGFzIE07XG5cbiAgICBsb2cuaW5mbyhgVXBkYXRpbmcgbW9kZWw6ICR7SlNPTi5zdHJpbmdpZnkobW9kZWwpfWApO1xuXG4gICAgY29uc3QgdHJhbnNpZW50ID0gdGhpcy5nZXRUcmFuc2llbnREYXRhKGN0eCk7XG5cbiAgICBsb2cuaW5mbyhgTWVyZ2luZyB0cmFuc2llbnQgZGF0YS4uLmApO1xuICAgIG1vZGVsID0gTW9kZWwubWVyZ2UobW9kZWwsIHRyYW5zaWVudCwgdGhpcy5jbGF6eikgYXMgTTtcbiAgICByZXR1cm4gdGhpcy5yZXBvLnVwZGF0ZShtb2RlbCwgLi4uY3R4QXJncyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIERlbGV0ZXMgYSBzaW5nbGUgbW9kZWwgZnJvbSB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgZGVsZXRlIG1ldGhvZFxuICAgKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICAgKiBAcGFyYW0ge3N0cmluZyB8IG51bWJlcn0ga2V5IC0gVGhlIGtleSBvZiB0aGUgbW9kZWwgdG8gZGVsZXRlXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50c1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPE0+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZGVsZXRlZCBtb2RlbFxuICAgKi9cbiAgYXN5bmMgZGVsZXRlKFxuICAgIGN0eDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIGtleTogUHJpbWFyeUtleVR5cGUgfCBzdHJpbmcsXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxNIHwgc3RyaW5nPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLmRlbGV0ZSk7XG4gICAgbG9nLmluZm8oYGRlbGV0aW5nIGVudHJ5IHdpdGggcGsgJHtrZXl9IGApO1xuICAgIHJldHVybiB0aGlzLnJlcG8uZGVsZXRlKFN0cmluZyhrZXkpLCAuLi5jdHhBcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVsZXRlcyBtdWx0aXBsZSBtb2RlbHMgZnJvbSB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgZGVsZXRlQWxsIG1ldGhvZFxuICAgKiBAcGFyYW0ge3N0cmluZ1tdIHwgbnVtYmVyW119IGtleXMgLSBUaGUga2V5cyBvZiB0aGUgbW9kZWxzIHRvIGRlbGV0ZVxuICAgKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgICogQHJldHVybiB7UHJvbWlzZTxNW10+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgZGVsZXRlZCBtb2RlbHNcbiAgICovXG4gIGFzeW5jIGRlbGV0ZUFsbChcbiAgICBjdHg6IEN0eCB8IEZhYnJpY0NvbnRyYWN0Q29udGV4dCxcbiAgICBrZXlzOiBQcmltYXJ5S2V5VHlwZVtdIHwgc3RyaW5nLFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8TVtdIHwgc3RyaW5nPiB7XG4gICAgY29uc3QgeyBjdHhBcmdzIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbLi4uYXJncywgY3R4XSwgdGhpcy5yZWFkQWxsKTtcbiAgICBpZiAodHlwZW9mIGtleXMgPT09IFwic3RyaW5nXCIpIGtleXMgPSBKU09OLnBhcnNlKGtleXMpIGFzIHN0cmluZ1tdO1xuICAgIHJldHVybiB0aGlzLnJlcG8uZGVsZXRlQWxsKGtleXMsIC4uLmN0eEFyZ3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZWFkcyBtdWx0aXBsZSBtb2RlbHMgZnJvbSB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgcmVhZEFsbCBtZXRob2RcbiAgICogQHBhcmFtIHtDdHh9IGN0eCAtIFRoZSBGYWJyaWMgY2hhaW5jb2RlIGNvbnRleHRcbiAgICogQHBhcmFtIHtzdHJpbmdbXSB8IG51bWJlcltdfSBrZXlzIC0gVGhlIGtleXMgb2YgdGhlIG1vZGVscyB0byByZWFkXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50c1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1bXT59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSByZXRyaWV2ZWQgbW9kZWxzXG4gICAqL1xuICBhc3luYyByZWFkQWxsKFxuICAgIGN0eDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIGtleXM6IFByaW1hcnlLZXlUeXBlW10gfCBzdHJpbmcsXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxNW10gfCBzdHJpbmc+IHtcbiAgICBjb25zdCB7IGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjdHhdLCB0aGlzLnJlYWRBbGwpO1xuICAgIGlmICh0eXBlb2Yga2V5cyA9PT0gXCJzdHJpbmdcIikga2V5cyA9IEpTT04ucGFyc2Uoa2V5cykgYXMgc3RyaW5nW107XG4gICAgcmV0dXJuIHRoaXMucmVwby5yZWFkQWxsKGtleXMsIC4uLmN0eEFyZ3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIG11bHRpcGxlIG1vZGVscyBpbiB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgdXBkYXRlQWxsIG1ldGhvZFxuICAgKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICAgKiBAcGFyYW0ge01bXX0gbW9kZWxzIC0gVGhlIG1vZGVscyB0byB1cGRhdGVcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TVtdPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWQgbW9kZWxzXG4gICAqL1xuICBhc3luYyB1cGRhdGVBbGwoXG4gICAgY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gICAgbW9kZWxzOiBzdHJpbmcgfCBNW10sXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxzdHJpbmcgfCBNW10+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoWy4uLmFyZ3MsIGN0eF0sIHRoaXMudXBkYXRlQWxsKTtcbiAgICBpZiAodHlwZW9mIG1vZGVscyA9PT0gXCJzdHJpbmdcIilcbiAgICAgIG1vZGVscyA9IChKU09OLnBhcnNlKG1vZGVscykgYXMgW10pXG4gICAgICAgIC5tYXAoKG0pID0+IHRoaXMuZGVzZXJpYWxpemUobSkpXG4gICAgICAgIC5tYXAoKG0pID0+IG5ldyB0aGlzLmNsYXp6KG0pKSBhcyBhbnk7XG5cbiAgICBsb2cuaW5mbyhgdXBkYXRpbmcgJHttb2RlbHMubGVuZ3RofSBlbnRyaWVzIHRvIHRoZSB0YWJsZWApO1xuICAgIHJldHVybiB0aGlzLnJlcG8udXBkYXRlQWxsKG1vZGVscyBhcyB1bmtub3duIGFzIE1bXSwgLi4uY3R4QXJncyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV4ZWN1dGVzIGEgcXVlcnkgd2l0aCB0aGUgc3BlY2lmaWVkIGNvbmRpdGlvbnMgYW5kIG9wdGlvbnMuXG4gICAqIEBzdW1tYXJ5IFByb3ZpZGVzIGEgc2ltcGxpZmllZCB3YXkgdG8gcXVlcnkgdGhlIGRhdGFiYXNlIHdpdGggY29tbW9uIHF1ZXJ5IHBhcmFtZXRlcnMuXG4gICAqIEBwYXJhbSB7Q29uZGl0aW9uPE0+fSBjb25kaXRpb24gLSBUaGUgY29uZGl0aW9uIHRvIGZpbHRlciByZWNvcmRzLlxuICAgKiBAcGFyYW0gb3JkZXJCeSAtIFRoZSBmaWVsZCB0byBvcmRlciByZXN1bHRzIGJ5LlxuICAgKiBAcGFyYW0ge09yZGVyRGlyZWN0aW9ufSBbb3JkZXI9T3JkZXJEaXJlY3Rpb24uQVNDXSAtIFRoZSBzb3J0IGRpcmVjdGlvbi5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFtsaW1pdF0gLSBPcHRpb25hbCBtYXhpbXVtIG51bWJlciBvZiByZXN1bHRzIHRvIHJldHVybi5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFtza2lwXSAtIE9wdGlvbmFsIG51bWJlciBvZiByZXN1bHRzIHRvIHNraXAuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TVtdPn0gVGhlIHF1ZXJ5IHJlc3VsdHMgYXMgbW9kZWwgaW5zdGFuY2VzLlxuICAgKi9cbiAgYXN5bmMgcXVlcnkoXG4gICAgY29udGV4dDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIGNvbmRpdGlvbjogQ29uZGl0aW9uPE0+IHwgc3RyaW5nLFxuICAgIG9yZGVyQnk6IHN0cmluZyB8IGtleW9mIE0sXG4gICAgb3JkZXI6IE9yZGVyRGlyZWN0aW9uIHwgc3RyaW5nID0gT3JkZXJEaXJlY3Rpb24uQVNDLFxuICAgIGxpbWl0PzogbnVtYmVyLFxuICAgIHNraXA/OiBudW1iZXIsXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxNW10gfCBzdHJpbmc+IHtcbiAgICBjb25zdCB7IGN0eEFyZ3MgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFsuLi5hcmdzLCBjb250ZXh0XSwgdGhpcy5xdWVyeSk7XG4gICAgcmV0dXJuIHRoaXMucmVwby5xdWVyeShcbiAgICAgIGNvbmRpdGlvbiBhcyBDb25kaXRpb248TT4sXG4gICAgICBvcmRlckJ5IGFzIGtleW9mIE0sXG4gICAgICBvcmRlciBhcyBPcmRlckRpcmVjdGlvbixcbiAgICAgIGxpbWl0LFxuICAgICAgc2tpcCxcbiAgICAgIC4uLmN0eEFyZ3NcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFeGVjdXRlcyBhIHJhdyBxdWVyeSBhZ2FpbnN0IHRoZSBzdGF0ZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBEZWxlZ2F0ZXMgdG8gdGhlIHJlcG9zaXRvcnkncyByYXcgbWV0aG9kXG4gICAqIEBwYXJhbSB7Q3R4fSBjdHggLSBUaGUgRmFicmljIGNoYWluY29kZSBjb250ZXh0XG4gICAqIEBwYXJhbSB7YW55fSByYXdJbnB1dCAtIFRoZSBxdWVyeSB0byBleGVjdXRlXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gZG9jc09ubHkgLSBXaGV0aGVyIHRvIHJldHVybiBvbmx5IGRvY3VtZW50c1xuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgICogQHJldHVybiB7UHJvbWlzZTxhbnk+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgcXVlcnkgcmVzdWx0c1xuICAgKi9cbiAgYXN5bmMgcmF3KFxuICAgIGN0eDogQ3R4IHwgRmFicmljQ29udHJhY3RDb250ZXh0LFxuICAgIHJhd0lucHV0OiBNYW5nb1F1ZXJ5LFxuICAgIGRvY3NPbmx5OiBib29sZWFuLFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8YW55PiB7XG4gICAgY29uc3QgeyBjdHhBcmdzIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbLi4uYXJncywgY3R4XSwgdGhpcy5yYXcpO1xuICAgIHJldHVybiBGYWJyaWNDcnVkQ29udHJhY3QuYWRhcHRlci5yYXcocmF3SW5wdXQsIGRvY3NPbmx5LCAuLi5jdHhBcmdzKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBzZXJpYWxpemUobW9kZWw6IE0pOiBzdHJpbmcge1xuICAgIHJldHVybiBGYWJyaWNDcnVkQ29udHJhY3Quc2VyaWFsaXplci5zZXJpYWxpemUobW9kZWwpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGRlc2VyaWFsaXplPE0gZXh0ZW5kcyBNb2RlbD4oc3RyOiBzdHJpbmcpOiBNIHtcbiAgICByZXR1cm4gKFxuICAgICAgRmFicmljQ3J1ZENvbnRyYWN0LnNlcmlhbGl6ZXIgYXMgdW5rbm93biBhcyBTZXJpYWxpemVyPE0+XG4gICAgKS5kZXNlcmlhbGl6ZShzdHIpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGluaXQoY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGxvZyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2N0eF0sIHRoaXMuaW5pdCk7XG4gICAgbG9nLmluZm8oYFJ1bm5pbmcgY29udHJhY3QgJHt0aGlzLmdldE5hbWUoKX0gaW5pdGlhbGl6YXRpb24uLi5gKTtcbiAgICB0aGlzLmluaXRpYWxpemVkID0gdHJ1ZTtcbiAgICBsb2cuaW5mbyhgQ29udHJhY3QgaW5pdGlhbGl6YXRpb24gY29tcGxldGVkLmApO1xuICB9XG5cbiAgYXN5bmMgaGVhbHRoY2hlY2soXG4gICAgY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHRcbiAgKTogUHJvbWlzZTxzdHJpbmcgfCBoZWFsdGhjaGVjaz4ge1xuICAgIGNvbnN0IHsgbG9nIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY3R4XSwgdGhpcy5oZWFsdGhjaGVjayk7XG4gICAgbG9nLmluZm8oYFJ1bm5pbmcgSGVhbHRoY2hlY2s6ICR7dGhpcy5pbml0aWFsaXplZH0uLi5gKTtcbiAgICByZXR1cm4geyBoZWFsdGhjaGVjazogdGhpcy5pbml0aWFsaXplZCB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIG11bHRpcGxlIG1vZGVscyBpbiB0aGUgc3RhdGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgRGVsZWdhdGVzIHRvIHRoZSByZXBvc2l0b3J5J3MgY3JlYXRlQWxsIG1ldGhvZFxuICAgKiBAcGFyYW0ge0N0eH0gY3R4IC0gVGhlIEZhYnJpYyBjaGFpbmNvZGUgY29udGV4dFxuICAgKiBAcGFyYW0ge01bXX0gbW9kZWxzIC0gVGhlIG1vZGVscyB0byBjcmVhdGVcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TVtdPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGNyZWF0ZWQgbW9kZWxzXG4gICAqL1xuICBhc3luYyBjcmVhdGVBbGwoXG4gICAgY3R4OiBDdHggfCBGYWJyaWNDb250cmFjdENvbnRleHQsXG4gICAgbW9kZWxzOiBzdHJpbmcgfCBNW10sXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxzdHJpbmcgfCBNW10+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4QXJncyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoWy4uLmFyZ3MsIGN0eF0sIHRoaXMuY3JlYXRlQWxsKTtcblxuICAgIGlmICh0eXBlb2YgbW9kZWxzID09PSBcInN0cmluZ1wiKVxuICAgICAgbW9kZWxzID0gKEpTT04ucGFyc2UobW9kZWxzKSBhcyBbXSlcbiAgICAgICAgLm1hcCgobSkgPT4gdGhpcy5kZXNlcmlhbGl6ZShtKSlcbiAgICAgICAgLm1hcCgobSkgPT4gbmV3IHRoaXMuY2xhenoobSkpIGFzIGFueTtcblxuICAgIGxvZy5pbmZvKGBhZGRpbmcgJHttb2RlbHMubGVuZ3RofSBlbnRyaWVzIHRvIHRoZSB0YWJsZWApO1xuICAgIHJldHVybiB0aGlzLnJlcG8uY3JlYXRlQWxsKG1vZGVscyBhcyB1bmtub3duIGFzIE1bXSwgLi4uY3R4QXJncyk7XG4gIH1cblxuICBhc3luYyBsb2dDdHg8QVJHUyBleHRlbmRzIGFueVtdPihcbiAgICBhcmdzOiBBUkdTLFxuICAgIG1ldGhvZDogKCguLi5hcmdzOiBhbnlbXSkgPT4gYW55KSB8IHN0cmluZ1xuICApOiBQcm9taXNlPFxuICAgIENvbnRleHR1YWxpemVkQXJnczxGYWJyaWNDb250cmFjdENvbnRleHQsIEFSR1M+ICYge1xuICAgICAgc3R1YjogQ2hhaW5jb2RlU3R1YjtcbiAgICAgIGlkZW50aXR5OiBDbGllbnRJZGVudGl0eTtcbiAgICB9XG4gID4ge1xuICAgIHJldHVybiBGYWJyaWNDcnVkQ29udHJhY3QubG9nQ3R4LmJpbmQodGhpcykoYXJncywgbWV0aG9kIGFzIGFueSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgc3RhdGljIGFzeW5jIGxvZ0N0eDxBUkdTIGV4dGVuZHMgYW55W10+KFxuICAgIHRoaXM6IGFueSxcbiAgICBhcmdzOiBBUkdTLFxuICAgIG1ldGhvZDogc3RyaW5nXG4gICk6IFByb21pc2U8XG4gICAgQ29udGV4dHVhbGl6ZWRBcmdzPEZhYnJpY0NvbnRyYWN0Q29udGV4dCwgQVJHUz4gJiB7XG4gICAgICBzdHViOiBDaGFpbmNvZGVTdHViO1xuICAgICAgaWRlbnRpdHk6IENsaWVudElkZW50aXR5O1xuICAgIH1cbiAgPjtcbiAgcHJvdGVjdGVkIHN0YXRpYyBhc3luYyBsb2dDdHg8QVJHUyBleHRlbmRzIGFueVtdPihcbiAgICB0aGlzOiBhbnksXG4gICAgYXJnczogQVJHUyxcbiAgICBtZXRob2Q6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55XG4gICk6IFByb21pc2U8XG4gICAgQ29udGV4dHVhbGl6ZWRBcmdzPEZhYnJpY0NvbnRyYWN0Q29udGV4dCwgQVJHUz4gJiB7XG4gICAgICBzdHViOiBDaGFpbmNvZGVTdHViO1xuICAgICAgaWRlbnRpdHk6IENsaWVudElkZW50aXR5O1xuICAgIH1cbiAgPjtcbiAgcHJvdGVjdGVkIHN0YXRpYyBhc3luYyBsb2dDdHg8QVJHUyBleHRlbmRzIGFueVtdPihcbiAgICB0aGlzOiBhbnksXG4gICAgYXJnczogQVJHUyxcbiAgICBtZXRob2Q6ICgoLi4uYXJnczogYW55W10pID0+IGFueSkgfCBzdHJpbmdcbiAgKTogUHJvbWlzZTxcbiAgICBDb250ZXh0dWFsaXplZEFyZ3M8RmFicmljQ29udHJhY3RDb250ZXh0LCBBUkdTPiAmIHtcbiAgICAgIHN0dWI6IENoYWluY29kZVN0dWI7XG4gICAgICBpZGVudGl0eTogQ2xpZW50SWRlbnRpdHk7XG4gICAgfVxuICA+IHtcbiAgICBpZiAoYXJncy5sZW5ndGggPCAxKSB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIk5vIGNvbnRleHQgcHJvdmlkZWRcIik7XG4gICAgY29uc3QgY3R4ID0gYXJncy5wb3AoKSBhcyBGYWJyaWNDb250cmFjdENvbnRleHQgfCBDb250ZXh0O1xuICAgIGlmIChjdHggaW5zdGFuY2VvZiBGYWJyaWNDb250cmFjdENvbnRleHQpXG4gICAgICByZXR1cm4ge1xuICAgICAgICBjdHgsXG4gICAgICAgIGxvZzogY3R4LmxvZ2dlci5jbGVhcigpLmZvcih0aGlzKS5mb3IobWV0aG9kKSxcbiAgICAgICAgY3R4QXJnczogWy4uLmFyZ3MsIGN0eF0sXG4gICAgICAgIHN0dWI6IGN0eC5zdHViLFxuICAgICAgICBpZGVudGl0eTogY3R4LmlkZW50aXR5LFxuICAgICAgfTtcblxuICAgIGlmICghKGN0eCBpbnN0YW5jZW9mIEN0eCkpXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIk5vIHZhbGlkIGNvbnRleHQgcHJvdmlkZWRcIik7XG5cbiAgICBmdW5jdGlvbiBnZXRPcCgpIHtcbiAgICAgIGlmICh0eXBlb2YgbWV0aG9kID09PSBcInN0cmluZ1wiKSByZXR1cm4gbWV0aG9kO1xuICAgICAgc3dpdGNoIChtZXRob2QubmFtZSkge1xuICAgICAgICBjYXNlIE9wZXJhdGlvbktleXMuQ1JFQVRFOlxuICAgICAgICBjYXNlIE9wZXJhdGlvbktleXMuUkVBRDpcbiAgICAgICAgY2FzZSBPcGVyYXRpb25LZXlzLlVQREFURTpcbiAgICAgICAgY2FzZSBPcGVyYXRpb25LZXlzLkRFTEVURTpcbiAgICAgICAgY2FzZSBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuQ1JFQVRFX0FMTDpcbiAgICAgICAgY2FzZSBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuUkVBRF9BTEw6XG4gICAgICAgIGNhc2UgQnVsa0NydWRPcGVyYXRpb25LZXlzLlVQREFURV9BTEw6XG4gICAgICAgIGNhc2UgQnVsa0NydWRPcGVyYXRpb25LZXlzLkRFTEVURV9BTEw6XG4gICAgICAgICAgcmV0dXJuIG1ldGhvZC5uYW1lO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHJldHVybiBtZXRob2QubmFtZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBvdmVycmlkZXMgPSB7XG4gICAgICBjb3JyZWxhdGlvbklkOiBjdHguc3R1Yi5nZXRUeElEKCksXG4gICAgfTtcbiAgICBjb25zdCBjb250ZXh0ID0gYXdhaXQgRmFicmljQ3J1ZENvbnRyYWN0LmFkYXB0ZXIuY29udGV4dChcbiAgICAgIGdldE9wKCksXG4gICAgICBvdmVycmlkZXMgYXMgYW55LFxuICAgICAgdGhpcy5jbGF6eixcbiAgICAgIGN0eFxuICAgICk7XG5cbiAgICBjb25zdCBsb2cgPSAoXG4gICAgICB0aGlzXG4gICAgICAgID8gY29udGV4dC5sb2dnZXIuZm9yKHRoaXMpLmZvcihtZXRob2QpXG4gICAgICAgIDogY29udGV4dC5sb2dnZXIuY2xlYXIoKS5mb3IodGhpcykuZm9yKG1ldGhvZClcbiAgICApIGFzIExvZ2dlck9mPEZhYnJpY0NvbnRyYWN0Q29udGV4dD47XG4gICAgcmV0dXJuIHtcbiAgICAgIGN0eDogY29udGV4dCxcbiAgICAgIGxvZzogbG9nLFxuICAgICAgc3R1YjogY29udGV4dC5zdHViLFxuICAgICAgaWRlbnRpdHk6IGNvbnRleHQuaWRlbnRpdHksXG4gICAgICBjdHhBcmdzOiBbLi4uYXJncywgY29udGV4dF0sXG4gICAgfTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgRmFicmljQ3J1ZENvbnRyYWN0IH0gZnJvbSBcIi4vY3J1ZC1jb250cmFjdFwiO1xuaW1wb3J0IHsgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBDb250ZXh0IGFzIEN0eCwgVHJhbnNhY3Rpb24gfSBmcm9tIFwiZmFicmljLWNvbnRyYWN0LWFwaVwiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IENvbmRpdGlvbiwgTWF5YmVDb250ZXh0dWFsQXJnLCBPcmRlckRpcmVjdGlvbiB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgU2VyaWFsaXphdGlvbkVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBGYWJyaWNDb250cmFjdENvbnRleHQgfSBmcm9tIFwiLi4vQ29udHJhY3RDb250ZXh0XCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENSVUQgY29udHJhY3QgdmFyaWFudCB0aGF0IHNlcmlhbGl6ZXMvZGVzZXJpYWxpemVzIHBheWxvYWRzXG4gKiBAc3VtbWFyeSBFeHBvc2VzIHRoZSBzYW1lIENSVUQgb3BlcmF0aW9ucyBhcyBGYWJyaWNDcnVkQ29udHJhY3QgYnV0IHRha2VzIGFuZCByZXR1cm5zIEpTT04gc3RyaW5ncyB0byBmYWNpbGl0YXRlIHNpbXBsZSBjbGllbnQgaW50ZXJhY3Rpb25zLlxuICogQHRlbXBsYXRlIE0gLSBNb2RlbCB0eXBlIGhhbmRsZWQgYnkgdGhpcyBjb250cmFjdFxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgY29udHJhY3QgbmFtZVxuICogQHBhcmFtIHtDb25zdHJ1Y3RvcjxNPn0gY2xhenogLSBUaGUgbW9kZWwgY29uc3RydWN0b3IgdXNlZCB0byBpbnN0YW50aWF0ZSBtb2RlbHMgZnJvbSBKU09OXG4gKiBAcmV0dXJuIHt2b2lkfVxuICogQGNsYXNzIFNlcmlhbGl6ZWRDcnVkQ29udHJhY3RcbiAqIEBleGFtcGxlXG4gKiBjb25zdCBjb250cmFjdCA9IG5ldyBTZXJpYWxpemVkQ3J1ZENvbnRyYWN0PE15TW9kZWw+KCdNeU1vZGVsQ29udHJhY3QnLCBNeU1vZGVsKTtcbiAqIC8vIENsaWVudCBzdWJtaXRzIEpTT04gc3RyaW5nIHBheWxvYWRzIGFuZCByZWNlaXZlcyBKU09OIHN0cmluZyByZXNwb25zZXNcbiAqL1xuZXhwb3J0IGNsYXNzIFNlcmlhbGl6ZWRDcnVkQ29udHJhY3Q8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbj4gZXh0ZW5kcyBGYWJyaWNDcnVkQ29udHJhY3Q8TT4ge1xuICBjb25zdHJ1Y3RvcihuYW1lOiBzdHJpbmcsIGNsYXp6OiBDb25zdHJ1Y3RvcjxNPikge1xuICAgIHN1cGVyKG5hbWUsIGNsYXp6KTtcbiAgfVxuXG4gIEBUcmFuc2FjdGlvbigpXG4gIG92ZXJyaWRlIGFzeW5jIGNyZWF0ZShjb250ZXh0OiBDdHgsIG1vZGVsOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5jcmVhdGUpO1xuICAgIGxvZy5pbmZvKGBDcmVhdGluZyBtb2RlbDogJHttb2RlbH1gKTtcblxuICAgIGNvbnN0IG0gPSB0aGlzLmRlc2VyaWFsaXplPE0+KG1vZGVsKTtcblxuICAgIGxvZy5pbmZvKGBNb2RlbCBkZXNlcmlhbGl6ZWQ6ICR7SlNPTi5zdHJpbmdpZnkobSl9YCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgc3VwZXIuY3JlYXRlKGN0eCBhcyBhbnksIG0pO1xuXG4gICAgY29uc3Qgc2VyaWFsaXplZCA9IHRoaXMuc2VyaWFsaXplKHJlc3VsdCBhcyBNKTtcbiAgICBsb2cuaW5mbyhgUkVTVUxUOiAke0pTT04uc3RyaW5naWZ5KHJlc3VsdCl9YCk7XG4gICAgbG9nLmluZm8oYFJldHVuaW5nOiAke3NlcmlhbGl6ZWR9YCk7XG4gICAgcmV0dXJuIHNlcmlhbGl6ZWQ7XG4gIH1cblxuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIG92ZXJyaWRlIGFzeW5jIHJlYWQoY29udGV4dDogQ3R4LCBrZXk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLnJlYWQpO1xuICAgIGxvZy5pbmZvKGBSZWFkaW5nIGlkOiAke2tleX1gKTtcbiAgICByZXR1cm4gdGhpcy5zZXJpYWxpemUoKGF3YWl0IHN1cGVyLnJlYWQoY3R4IGFzIGFueSwga2V5KSkgYXMgTSk7XG4gIH1cblxuICBAVHJhbnNhY3Rpb24oKVxuICBvdmVycmlkZSBhc3luYyB1cGRhdGUoY29udGV4dDogQ3R4LCBtb2RlbDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMudXBkYXRlKTtcbiAgICBsb2cuaW5mbyhgVXBkYXRpbmcgbW9kZWw6ICR7bW9kZWx9YCk7XG4gICAgcmV0dXJuIHRoaXMuc2VyaWFsaXplKChhd2FpdCBzdXBlci51cGRhdGUoY3R4IGFzIGFueSwgbW9kZWwpKSBhcyBNKTtcbiAgfVxuXG4gIEBUcmFuc2FjdGlvbigpXG4gIG92ZXJyaWRlIGFzeW5jIGRlbGV0ZShjb250ZXh0OiBDdHgsIGtleTogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuZGVsZXRlKTtcbiAgICBsb2cuaW5mbyhgRGVsZXRpbmcgaWQ6ICR7a2V5fWApO1xuICAgIHJldHVybiB0aGlzLnNlcmlhbGl6ZSgoYXdhaXQgc3VwZXIuZGVsZXRlKGN0eCBhcyBhbnksIGtleSkpIGFzIE0pO1xuICB9XG5cbiAgQFRyYW5zYWN0aW9uKClcbiAgb3ZlcnJpZGUgYXN5bmMgZGVsZXRlQWxsKGNvbnRleHQ6IEN0eCwga2V5czogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBwYXJzZWRLZXlzOiBzdHJpbmdbXSA9IEpTT04ucGFyc2Uoa2V5cyk7XG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLmRlbGV0ZUFsbCk7XG5cbiAgICBsb2cuaW5mbyhgZGVsZXRpbmcgJHtwYXJzZWRLZXlzLmxlbmd0aH0gZW50cmllcyBmcm9tIHRoZSB0YWJsZWApO1xuXG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KFxuICAgICAgKChhd2FpdCBzdXBlci5kZWxldGVBbGwoY3R4IGFzIGFueSwgcGFyc2VkS2V5cykpIGFzIE1bXSkubWFwKFxuICAgICAgICAobSkgPT4gdGhpcy5zZXJpYWxpemUobSkgYXMgc3RyaW5nXG4gICAgICApXG4gICAgKTtcbiAgfVxuXG4gIEBUcmFuc2FjdGlvbihmYWxzZSlcbiAgb3ZlcnJpZGUgYXN5bmMgcmVhZEFsbChjb250ZXh0OiBDdHgsIGtleXM6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgcGFyc2VkS2V5czogc3RyaW5nW10gPSBKU09OLnBhcnNlKGtleXMpO1xuXG4gICAgY29uc3QgeyBsb2csIGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLnJlYWRBbGwpO1xuICAgIGxvZy5pbmZvKGByZWFkaW5nICR7cGFyc2VkS2V5cy5sZW5ndGh9IGVudHJpZXMgZnJvbSB0aGUgdGFibGVgKTtcblxuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShcbiAgICAgICgoYXdhaXQgc3VwZXIucmVhZEFsbChjdHggYXMgYW55LCBwYXJzZWRLZXlzKSkgYXMgTVtdKS5tYXAoKG0pID0+XG4gICAgICAgIHRoaXMuc2VyaWFsaXplKG0pXG4gICAgICApXG4gICAgKTtcbiAgfVxuXG4gIEBUcmFuc2FjdGlvbigpXG4gIG92ZXJyaWRlIGFzeW5jIHVwZGF0ZUFsbChjb250ZXh0OiBDdHgsIG1vZGVsczogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB7IGxvZywgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMudXBkYXRlQWxsKTtcbiAgICBjb25zdCBsaXN0OiBzdHJpbmdbXSA9IEpTT04ucGFyc2UobW9kZWxzKTtcbiAgICBjb25zdCBtb2RlbExpc3Q6IE1bXSA9IGxpc3RcbiAgICAgIC5tYXAoKG0pID0+IHRoaXMuZGVzZXJpYWxpemUobSkpXG4gICAgICAubWFwKChtKSA9PiBuZXcgdGhpcy5jbGF6eihtKSk7XG5cbiAgICBsb2cuaW5mbyhgVXBkYXRpbmcgJHttb2RlbExpc3QubGVuZ3RofSBlbnRyaWVzIHRvIHRoZSB0YWJsZWApO1xuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShcbiAgICAgICgoYXdhaXQgc3VwZXIudXBkYXRlQWxsKGN0eCBhcyBhbnksIG1vZGVsTGlzdCkpIGFzIE1bXSkubWFwKFxuICAgICAgICAobSkgPT4gdGhpcy5zZXJpYWxpemUobSkgYXMgc3RyaW5nXG4gICAgICApXG4gICAgKTtcbiAgfVxuXG4gIEBUcmFuc2FjdGlvbihmYWxzZSlcbiAgb3ZlcnJpZGUgYXN5bmMgc3RhdGVtZW50KGNvbnRleHQ6IEN0eCwgbWV0aG9kOiBzdHJpbmcsIGFyZ3M6IHN0cmluZykge1xuICAgIGNvbnN0IHsgY3R4LCBsb2cgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5zdGF0ZW1lbnQpO1xuICAgIHRyeSB7XG4gICAgICBhcmdzID0gSlNPTi5wYXJzZShhcmdzKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyBuZXcgU2VyaWFsaXphdGlvbkVycm9yKGBJbnZhbGlkIGFyZ3M6ICR7ZX1gKTtcbiAgICB9XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KGFyZ3MpKVxuICAgICAgdGhyb3cgbmV3IFNlcmlhbGl6YXRpb25FcnJvcihcbiAgICAgICAgYEludmFsaWQgYXJnczogJHtKU09OLnN0cmluZ2lmeShhcmdzKX0uIG11c3QgYmUgYW4gYXJyYXlgXG4gICAgICApO1xuICAgIGxvZy5pbmZvKGBjYWxsaW5nIHByZXBhcmVkIHN0YXRlbWVudCAke21ldGhvZH1gKTtcbiAgICBsb2cuaW5mbyhgd2l0aCBhcmdzICR7YXJnc31gKTtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoYXdhaXQgc3VwZXIuc3RhdGVtZW50KGN0eCwgbWV0aG9kLCAuLi5hcmdzKSk7XG4gIH1cblxuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIG92ZXJyaWRlIGFzeW5jIGxpc3RCeShjb250ZXh0OiBDdHgsIGtleTogc3RyaW5nLCBvcmRlcjogc3RyaW5nKSB7XG4gICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLmxpc3RCeSk7XG4gICAgbG9nLmluZm8oYEV4ZWN1dGluZyBsaXN0Qnkgd2l0aCBrZXkgJHtrZXl9IGFuZCBvcmRlciAke29yZGVyfWApO1xuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShcbiAgICAgIGF3YWl0IHN1cGVyLmxpc3RCeShjdHgsIGtleSBhcyBrZXlvZiBNLCBvcmRlciBhcyBPcmRlckRpcmVjdGlvbilcbiAgICApO1xuICB9XG5cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBvdmVycmlkZSBhc3luYyBwYWdpbmF0ZUJ5KFxuICAgIGNvbnRleHQ6IEN0eCxcbiAgICBrZXk6IHN0cmluZyxcbiAgICBvcmRlcjogc3RyaW5nLFxuICAgIHJlZjogc3RyaW5nLFxuICAgIC4uLmFyZ3M6IE1heWJlQ29udGV4dHVhbEFyZzxGYWJyaWNDb250cmFjdENvbnRleHQ+XG4gICk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoWy4uLmFyZ3MsIGNvbnRleHRdLCB0aGlzLnBhZ2luYXRlQnkpO1xuICAgIHRyeSB7XG4gICAgICByZWYgPSBKU09OLnBhcnNlKHJlZik7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IFNlcmlhbGl6YXRpb25FcnJvcihcbiAgICAgICAgYEZhaWxlZCB0byBkZXNlcmlhbGl6ZSBwYWdpbmF0ZUJ5IHJlZmVyZW5jZTogJHtlfWBcbiAgICAgICk7XG4gICAgfVxuICAgIGxvZy5pbmZvKGBFeGVjdXRpbmcgcGFnaW5hdGVCeSB3aXRoIGtleSAke2tleX0gYW5kIG9yZGVyICR7b3JkZXJ9YCk7XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KFxuICAgICAgYXdhaXQgc3VwZXIucGFnaW5hdGVCeShjdHgsIGtleSwgb3JkZXIgYXMgYW55LCByZWYgYXMgYW55LCAuLi5hcmdzKVxuICAgICk7XG4gIH1cblxuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIG92ZXJyaWRlIGFzeW5jIGZpbmRPbmVCeShcbiAgICBjb250ZXh0OiBDdHgsXG4gICAga2V5OiBzdHJpbmcsXG4gICAgdmFsdWU6IHN0cmluZyxcbiAgICAuLi5hcmdzOiBzdHJpbmdbXVxuICApIHtcbiAgICBjb25zdCB7IGN0eCwgbG9nIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbLi4uYXJncywgY29udGV4dF0sIHRoaXMuZmluZE9uZUJ5KTtcbiAgICBsb2cuaW5mbyhgRXhlY3V0aW5nIGZpbmRPbmVCeSB3aXRoIGtleSAke2tleX0gYW5kIHZhbHVlICR7dmFsdWV9YCk7XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGF3YWl0IHN1cGVyLmZpbmRPbmVCeShjdHgsIGtleSwgdmFsdWUsIC4uLmFyZ3MpKTtcbiAgfVxuXG4gIC8vIEBUcmFuc2FjdGlvbihmYWxzZSlcbiAgb3ZlcnJpZGUgYXN5bmMgcXVlcnkoXG4gICAgY29udGV4dDogQ3R4LFxuICAgIGNvbmRpdGlvbjogc3RyaW5nLFxuICAgIG9yZGVyQnk6IHN0cmluZyxcbiAgICBvcmRlcjogc3RyaW5nLFxuICAgIGxpbWl0PzogbnVtYmVyLFxuICAgIHNraXA/OiBudW1iZXJcbiAgKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB7IGN0eCwgbG9nIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMucXVlcnkpO1xuXG4gICAgbG9nLmluZm8oYEV4ZWN1dGluZyBxdWVyeSBvcmRlcmVkQnkgJHtvcmRlckJ5fSBhbmQgb3JkZXIgJHtvcmRlcn1gKTtcblxuICAgIGxldCBjb25kOiBDb25kaXRpb248YW55PjtcbiAgICB0cnkge1xuICAgICAgY29uZCA9IENvbmRpdGlvbi5mcm9tKEpTT04ucGFyc2UoY29uZGl0aW9uKSk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IFNlcmlhbGl6YXRpb25FcnJvcihgSW52YWxpZCBjb25kaXRpb246ICR7ZX1gKTtcbiAgICB9XG5cbiAgICBsb2cuaW5mbyhgQ29uZGl0aW9uOiAke0pTT04uc3RyaW5naWZ5KGNvbmQpfWApO1xuXG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KFxuICAgICAgYXdhaXQgc3VwZXIucXVlcnkoY3R4LCBjb25kLCBvcmRlckJ5LCBvcmRlciBhcyBhbnksIGxpbWl0LCBza2lwKVxuICAgICk7XG4gIH1cbiAgLy9cbiAgLy8gLy8gQFRyYW5zYWN0aW9uKGZhbHNlKVxuICAvLyBvdmVycmlkZSBhc3luYyByYXcoXG4gIC8vICAgY29udGV4dDogQ3R4LFxuICAvLyAgIHJhd0lucHV0OiBzdHJpbmcsXG4gIC8vICAgZG9jc09ubHk6IGJvb2xlYW4sXG4gIC8vICAgLi4uYXJnczogc3RyaW5nW11cbiAgLy8gKTogUHJvbWlzZTxhbnk+IHtcbiAgLy8gICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLnJhdyk7XG4gIC8vICAgY29uc3QgcGFyc2VkSW5wdXQ6IE1hbmdvUXVlcnkgPSBKU09OLnBhcnNlKHJhd0lucHV0KTtcbiAgLy8gICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoYXdhaXQgc3VwZXIucmF3KGN0eCwgcGFyc2VkSW5wdXQsIGRvY3NPbmx5LCAuLi5hcmdzKSk7XG4gIC8vIH1cblxuICBAVHJhbnNhY3Rpb24oKVxuICBvdmVycmlkZSBhc3luYyBpbml0KGN0eDogQ3R4KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgc3VwZXIuaW5pdChjdHgpO1xuICB9XG5cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBvdmVycmlkZSBhc3luYyBoZWFsdGhjaGVjayhjb250ZXh0OiBDdHgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy51cGRhdGVBbGwpO1xuICAgIGxvZy5kZWJ1ZyhgUnVubmluZyBIZWFsdGhjaGVjazogJHt0aGlzLmluaXRpYWxpemVkfS4uLmApO1xuICAgIC8vVE9ETzogVFJJTSBOT1QgV09SS0lORyBDSEVDSyBMQVRFUlxuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShhd2FpdCBzdXBlci5oZWFsdGhjaGVjayhjdHggYXMgYW55KSk7XG4gIH1cblxuICBAVHJhbnNhY3Rpb24oKVxuICBvdmVycmlkZSBhc3luYyBjcmVhdGVBbGwoY29udGV4dDogQ3R4LCBtb2RlbHM6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBsb2cgfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5jcmVhdGVBbGwpO1xuICAgIGNvbnN0IGxpc3Q6IHN0cmluZ1tdID0gSlNPTi5wYXJzZShtb2RlbHMpO1xuICAgIGNvbnN0IG1vZGVsTGlzdDogTVtdID0gbGlzdFxuICAgICAgLm1hcCgobSkgPT4gdGhpcy5kZXNlcmlhbGl6ZShtKSlcbiAgICAgIC5tYXAoKG0pID0+IG5ldyB0aGlzLmNsYXp6KG0pKTtcblxuICAgIGxvZy5pbmZvKGBBZGRpbmcgJHttb2RlbExpc3QubGVuZ3RofSBlbnRyaWVzIHRvIHRoZSB0YWJsZWApO1xuXG4gICAgY29uc3QgcmVzdWx0ID0gKGF3YWl0IHN1cGVyLmNyZWF0ZUFsbChjb250ZXh0LCBtb2RlbExpc3QpKSBhcyBNW107XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHJlc3VsdC5tYXAoKG0pID0+IHRoaXMuc2VyaWFsaXplKG0pIGFzIHN0cmluZykpO1xuICB9XG59XG4iLCJpbXBvcnQgeyBzdHJpbmdGb3JtYXQgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBPdmVyZmxvd0Vycm9yIH0gZnJvbSBcIi4vZXJyb3JzXCI7XG5pbXBvcnQgeyBWYWxpZGF0aW9uRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gT3ZlcmZsb3ctc2FmZSBhZGRpdGlvbiBvcGVyYXRpb25cbiAqIEBzdW1tYXJ5IEFkZHMgdHdvIG51bWJlcnMgYW5kIHZlcmlmaWVzIG5vIG92ZXJmbG93IGJ5IHJldmVyc2UtY2hlY2tpbmcgdGhlIG9wZXJhbmRzXG4gKiBAcGFyYW0ge251bWJlcn0gYSAtIEZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7bnVtYmVyfSBiIC0gU2Vjb25kIG9wZXJhbmRcbiAqIEByZXR1cm4ge251bWJlcn0gVGhlIHN1bSBvZiBhIGFuZCBiXG4gKiBAZnVuY3Rpb24gYWRkXG4gKiBAdGhyb3dzIHtPdmVyZmxvd0Vycm9yfSBvbiBhZGRpdGlvbiBvdmVyZmxvd1xuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItZmFicmljLnNoYXJlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gYWRkKGE6IG51bWJlciwgYjogbnVtYmVyKTogbnVtYmVyIHtcbiAgY29uc3QgYyA9IGEgKyBiO1xuICBpZiAoYSAhPT0gYyAtIGIgfHwgYiAhPT0gYyAtIGEpIHtcbiAgICB0aHJvdyBuZXcgT3ZlcmZsb3dFcnJvcihgQWRkaXRpb24gb3ZlcmZsb3c6ICR7YX0gKyAke2J9YCk7XG4gIH1cbiAgcmV0dXJuIGM7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE92ZXJmbG93LXNhZmUgc3VidHJhY3Rpb24gb3BlcmF0aW9uXG4gKiBAc3VtbWFyeSBTdWJ0cmFjdHMgYiBmcm9tIGEgYW5kIHZhbGlkYXRlcyBubyBvdmVyZmxvdyBieSByZXZlcnNlLWNoZWNraW5nIHRoZSBvcGVyYW5kc1xuICogQHBhcmFtIHtudW1iZXJ9IGEgLSBNaW51ZW5kXG4gKiBAcGFyYW0ge251bWJlcn0gYiAtIFN1YnRyYWhlbmRcbiAqIEByZXR1cm4ge251bWJlcn0gVGhlIGRpZmZlcmVuY2UgYSAtIGJcbiAqIEBmdW5jdGlvbiBzdWJcbiAqIEB0aHJvd3Mge092ZXJmbG93RXJyb3J9IG9uIHN1YnRhY3Rpb24gb3ZlcmZsb3dcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5zaGFyZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN1YihhOiBudW1iZXIsIGI6IG51bWJlcik6IG51bWJlciB7XG4gIGNvbnN0IGMgPSBhIC0gYjtcbiAgaWYgKGEgIT09IGMgKyBiIHx8IGIgIT09IGEgLSBjKSB7XG4gICAgdGhyb3cgbmV3IE92ZXJmbG93RXJyb3IoYFN1YnRyYWN0aW9uIG92ZXJmbG93OiAke2F9IC0gJHtifWApO1xuICB9XG4gIHJldHVybiBjO1xufVxuXG4vKipcbiAqIEBzdW1tYXJ5IFNhZmUgSW50ZWdlciBQYXJzZVxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdcbiAqXG4gKiBAZnVuY3Rpb24gc2FmZVBhcnNlSW50XG4gKlxuICogQHRocm93cyB7VmFsaWRhdGlvbkVycm9yfSBpZiBwYXJzZUludCByZXR1cm5zIE5hTlxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLWZhYnJpYy5zaGFyZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNhZmVQYXJzZUludChzdHJpbmc6IHN0cmluZyk6IG51bWJlciB7XG4gIC8vIFJlZ3VsYXIgZXhwcmVzc2lvbiB0byBjaGVjayBpZiBzdHJpbmcgb25seSBoYXZlIGRpZ2l0c1xuICBjb25zdCBkaWdpdFJlZ2V4ID0gL15cXGQrJC87XG4gIGlmICghZGlnaXRSZWdleC50ZXN0KHN0cmluZykpIHtcbiAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKFxuICAgICAgc3RyaW5nRm9ybWF0KFwiRmFpbGVkIHRvIHBhcnNlOiB7MH1cIiwgXCJzdHJpbmcgY29udGFpbnMgZGlnaXRzXCIpXG4gICAgKTtcbiAgfVxuICBjb25zdCBwYXJzZWRpbnQgPSBwYXJzZUludChzdHJpbmcpO1xuICBpZiAoaXNOYU4ocGFyc2VkaW50KSkge1xuICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoXG4gICAgICBzdHJpbmdGb3JtYXQoXCJGYWlsZWQgdG8gcGFyc2U6IHswfVwiLCBcInN0cmluZyBpcyBub3QgYSBwYXJzYWJsZSBpbnRlZ2VyXCIpXG4gICAgKTtcbiAgfVxuICByZXR1cm4gcGFyc2VkaW50O1xufVxuIiwiaW1wb3J0IHsgQmFzZU1vZGVsLCBjb2x1bW4sIHBrLCB0YWJsZSB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgbW9kZWwsIHR5cGUgTW9kZWxBcmcsIHJlcXVpcmVkIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFUkMyMCB0b2tlbiBtZXRhZGF0YSBtb2RlbFxuICogQHN1bW1hcnkgUmVwcmVzZW50cyBhbiBFUkMyMCB0b2tlbiBkZWZpbml0aW9uIHdpdGhpbiB0aGUgRmFicmljIEVSQzIwIHNhbXBsZSwgaW5jbHVkaW5nIG5hbWUsIHN5bWJvbCwgZGVjaW1hbHMsIGFuZCB0aGUgb3duaW5nIGlkZW50aXR5LiBVc2VkIHRvIGRlZmluZSB0aGUgdW5pcXVlIHRva2VuIG1hbmFnZWQgYnkgdGhlIGNvbnRyYWN0LlxuICogQHBhcmFtIHtNb2RlbEFyZzxFUkMyMFRva2VuPn0gW21dIC0gT3B0aW9uYWwgcGFydGlhbCBkYXRhIG9yIGFub3RoZXIgaW5zdGFuY2UgdG8gaW5pdGlhbGl6ZSB0aGUgbW9kZWxcbiAqIEByZXR1cm4ge3ZvaWR9XG4gKiBAY2xhc3MgRVJDMjBUb2tlblxuICogQGV4YW1wbGVcbiAqIGNvbnN0IHRva2VuID0gbmV3IEVSQzIwVG9rZW4oeyBuYW1lOiBcIk15VG9rZW5cIiwgc3ltYm9sOiBcIk1US1wiLCBkZWNpbWFsczogMTgsIG93bmVyOiBcIng1MDk6Oi4uLlwiIH0pO1xuICogLy8gUGVyc2lzdCB0aHJvdWdoIGEgcmVwb3NpdG9yeTogYXdhaXQgcmVwby5jcmVhdGUodG9rZW4sIGN0eClcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQXBwXG4gKiAgIHBhcnRpY2lwYW50IFJlcG9cbiAqICAgcGFydGljaXBhbnQgQWRhcHRlclxuICogICBBcHAtPj5SZXBvOiBjcmVhdGUobmV3IEVSQzIwVG9rZW4oey4uLn0pLCBjdHgpXG4gKiAgIFJlcG8tPj5BZGFwdGVyOiBjcmVhdGUodGFibGUsIGlkPW5hbWUsIHJlY29yZCwgZmxhZ3MpXG4gKiAgIEFkYXB0ZXItLT4+UmVwbzogc3RvcmVkXG4gKiAgIFJlcG8tLT4+QXBwOiBtb2RlbFxuICovXG5AdGFibGUoXCJlcmMyMF90b2tlbnNcIilcbkBtb2RlbCgpXG5leHBvcnQgY2xhc3MgRVJDMjBUb2tlbiBleHRlbmRzIEJhc2VNb2RlbCB7XG4gIEBwayh7IHR5cGU6IFwiU3RyaW5nXCIgfSlcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUb2tlbiB1bmlxdWUgbmFtZVxuICAgKiBAc3VtbWFyeSBTZXJ2ZXMgYXMgdGhlIHByaW1hcnkga2V5IGZvciB0aGUgRVJDMjAgdG9rZW4gZGVmaW5pdGlvbjsgdHlwaWNhbGx5IGEgaHVtYW4tcmVhZGFibGUgaWRlbnRpZmllclxuICAgKi9cbiAgbmFtZSE6IHN0cmluZztcblxuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBPd25pbmcgaWRlbnRpdHkgb2YgdGhlIHRva2VuXG4gICAqIEBzdW1tYXJ5IFguNTA5IHN1YmplY3Qgb3IgTVNQIGlkZW50aXR5IHN0cmluZyB0aGF0IGRlbm90ZXMgd2hvIG93bnMvY29udHJvbHMgdGhlIHRva2VuIGRlZmluaXRpb25cbiAgICovXG4gIG93bmVyITogc3RyaW5nO1xuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUb2tlbiBzeW1ib2xcbiAgICogQHN1bW1hcnkgU2hvcnQgdGlja2VyLWxpa2Ugc3ltYm9sIHVzZWQgdG8gcmVwcmVzZW50IHRoZSB0b2tlbiAoZS5nLiwgTVRLKVxuICAgKi9cbiAgc3ltYm9sITogc3RyaW5nO1xuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBEZWNpbWFsIHByZWNpc2lvbiBmb3IgdG9rZW4gYW1vdW50c1xuICAgKiBAc3VtbWFyeSBOdW1iZXIgb2YgZGlnaXRzIGFmdGVyIHRoZSBkZWNpbWFsIHNlcGFyYXRvciB1c2VkIHdoZW4gZm9ybWF0dGluZyB0b2tlbiBiYWxhbmNlc1xuICAgKi9cbiAgZGVjaW1hbHMhOiBudW1iZXI7XG5cbiAgY29uc3RydWN0b3IobT86IE1vZGVsQXJnPEVSQzIwV2FsbGV0Pikge1xuICAgIHN1cGVyKG0pO1xuICB9XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEVSQzIwIHdhbGxldCBtb2RlbFxuICogQHN1bW1hcnkgUmVwcmVzZW50cyBhIGhvbGRlciBhY2NvdW50IGZvciBhbiBFUkMyMCB0b2tlbiB3aXRoaW4gdGhlIEZhYnJpYyBuZXR3b3JrLCB0cmFja2luZyBiYWxhbmNlIGFuZCB0b2tlbiBhc3NvY2lhdGlvbi5cbiAqIEBwYXJhbSB7TW9kZWxBcmc8RVJDMjBXYWxsZXQ+fSBbbV0gLSBPcHRpb25hbCBwYXJ0aWFsIGRhdGEgb3IgYW5vdGhlciBpbnN0YW5jZSB0byBpbml0aWFsaXplIHRoZSBtb2RlbFxuICogQHJldHVybiB7dm9pZH1cbiAqIEBjbGFzcyBFUkMyMFdhbGxldFxuICogQGV4YW1wbGVcbiAqIGNvbnN0IHdhbGxldCA9IG5ldyBFUkMyMFdhbGxldCh7IGlkOiBcImFjY3QxXCIsIHRva2VuOiBcIk15VG9rZW5cIiwgYmFsYW5jZTogMTAwMCB9KTtcbiAqIC8vIFVwZGF0ZSBiYWxhbmNlIHZpYSByZXBvc2l0b3J5OiBhd2FpdCByZXBvLnVwZGF0ZSh3YWxsZXQsIGN0eClcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQXBwXG4gKiAgIHBhcnRpY2lwYW50IFJlcG9cbiAqICAgQXBwLT4+UmVwbzogcmVhZChcImFjY3QxXCIsIGN0eClcbiAqICAgUmVwby0tPj5BcHA6IEVSQzIwV2FsbGV0XG4gKi9cbkB0YWJsZShcImVyYzIwX3dhbGxldHNcIilcbkBtb2RlbCgpXG5leHBvcnQgY2xhc3MgRVJDMjBXYWxsZXQgZXh0ZW5kcyBCYXNlTW9kZWwge1xuICBAcGsoeyB0eXBlOiBcIlN0cmluZ1wiIH0pXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gV2FsbGV0IHVuaXF1ZSBpZGVudGlmaWVyXG4gICAqIEBzdW1tYXJ5IFByaW1hcnkga2V5IGZvciB0aGUgd2FsbGV0OyBjb21tb25seSByZWZlcmVuY2VzIGFuIGFjY291bnQgb3IgaWRlbnRpdHlcbiAgICovXG4gIGlkITogc3RyaW5nO1xuXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEFzc29jaWF0ZWQgdG9rZW4gbmFtZVxuICAgKiBAc3VtbWFyeSBSZWZlcmVuY2VzIHRoZSBFUkMyMFRva2VuIHRoaXMgd2FsbGV0IGhvbGRzOyBtYWludGFpbmVkIGFzIGEgcmVsYXRpb25zaGlwIGZvciBjYXNjYWRpbmcgdXBkYXRlcy9kZWxldGVzXG4gICAqL1xuICB0b2tlbiE6IHN0cmluZztcblxuICBAY29sdW1uKClcbiAgQHJlcXVpcmVkKClcbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBUb2tlbiBiYWxhbmNlIGZvciB0aGlzIHdhbGxldFxuICAgKiBAc3VtbWFyeSBDdXJyZW50IGFtb3VudCBvZiB0aGUgYXNzb2NpYXRlZCB0b2tlbiBoZWxkIGJ5IHRoaXMgd2FsbGV0XG4gICAqL1xuICBiYWxhbmNlITogbnVtYmVyO1xuXG4gIEBjb2x1bW4oKVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENhcHRpdmUgZmxhZyBvciBpZGVudGlmaWVyXG4gICAqIEBzdW1tYXJ5IE9wdGlvbmFsIGZpZWxkIHVzZWQgYnkgc29tZSBmbG93cyB0byBtYXJrIG5vbi10cmFuc2ZlcmFibGUgZnVuZHMgb3IgbWFuYWdlZCBjdXN0b2R5XG4gICAqL1xuICBjYXB0aXZlITogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKG0/OiBNb2RlbEFyZzxFUkMyMFdhbGxldD4pIHtcbiAgICBzdXBlcihtKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFUkMyMCBhbGxvd2FuY2UgbW9kZWxcbiAqIEBzdW1tYXJ5IENhcHR1cmVzIGFuIGFwcHJvdmFsIHJlbGF0aW9uc2hpcCB3aGVyZSBhbiBvd25lciBhbGxvd3MgYSBzcGVuZGVyIHRvIHRyYW5zZmVyIHVwIHRvIGEgY2VydGFpbiB2YWx1ZSBmcm9tIHRoZSBvd25lcidzIHdhbGxldC5cbiAqIEBwYXJhbSB7TW9kZWxBcmc8QWxsb3dhbmNlPn0gW21dIC0gT3B0aW9uYWwgcGFydGlhbCBkYXRhIG9yIGFub3RoZXIgaW5zdGFuY2UgdG8gaW5pdGlhbGl6ZSB0aGUgbW9kZWxcbiAqIEByZXR1cm4ge3ZvaWR9XG4gKiBAY2xhc3MgQWxsb3dhbmNlXG4gKiBAZXhhbXBsZVxuICogY29uc3QgYWxsb3dhbmNlID0gbmV3IEFsbG93YW5jZSh7IG93bmVyOiBcImFjY3QxXCIsIHNwZW5kZXI6IFwiYWNjdDJcIiwgdmFsdWU6IDUwIH0pO1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBBcHBcbiAqICAgQXBwLT4+QXBwOiBuZXcgQWxsb3dhbmNlKHsgb3duZXIsIHNwZW5kZXIsIHZhbHVlIH0pXG4gKi9cbkB0YWJsZShcImVyYzIwX2FsbG93YW5jZXNcIilcbkBtb2RlbCgpXG5leHBvcnQgY2xhc3MgQWxsb3dhbmNlIGV4dGVuZHMgQmFzZU1vZGVsIHtcbiAgQHBrKHsgdHlwZTogXCJTdHJpbmdcIiB9KVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEFsbG93YW5jZSB1bmlxdWUgaWRlbnRpZmllclxuICAgKiBAc3VtbWFyeSBQcmltYXJ5IGtleSBmb3IgdGhlIGFsbG93YW5jZTsgdHlwaWNhbGx5IGEgdW5pcXVlIGlkZW50aWZpZXIgZm9yIHRoZSBhcHByb3ZhbCByZWxhdGlvbnNoaXBcbiAgICovXG4gIEBjb2x1bW4oKVxuICBAcmVxdWlyZWQoKVxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIE93bmVyIHdhbGxldCBpZGVudGlmaWVyXG4gICAqIEBzdW1tYXJ5IFdhbGxldCB0aGF0IGF1dGhvcml6ZXMgdGhlIGFsbG93YW5jZVxuICAgKi9cbiAgb3duZXIhOiBzdHJpbmc7XG5cbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU3BlbmRlciB3YWxsZXQgaWRlbnRpZmllclxuICAgKiBAc3VtbWFyeSBXYWxsZXQgYWxsb3dlZCB0byBzcGVuZCB1cCB0byB0aGUgYXBwcm92ZWQgdmFsdWUgZnJvbSB0aGUgb3duZXJcbiAgICovXG4gIHNwZW5kZXIhOiBzdHJpbmc7XG5cbiAgQGNvbHVtbigpXG4gIEByZXF1aXJlZCgpXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQXBwcm92ZWQgdmFsdWVcbiAgICogQHN1bW1hcnkgTWF4aW11bSB0b2tlbiBhbW91bnQgdGhlIHNwZW5kZXIgbWF5IHRyYW5zZmVyIG9uIGJlaGFsZiBvZiB0aGUgb3duZXJcbiAgICovXG4gIHZhbHVlITogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKG0/OiBNb2RlbEFyZzxBbGxvd2FuY2U+KSB7XG4gICAgc3VwZXIobSk7XG4gIH1cbn1cbiIsImltcG9ydCB7XG4gIEF1dGhvcml6YXRpb25FcnJvcixcbiAgUmVwbyxcbiAgQ29udGV4dCxcbiAgVW5zdXBwb3J0ZWRFcnJvcixcbiAgUmVwb3NpdG9yeSxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQge1xuICBJbnRlcm5hbEVycm9yLFxuICBOb3RGb3VuZEVycm9yLFxuICBvbkNyZWF0ZSxcbiAgb25EZWxldGUsXG4gIG9uUmVhZCxcbiAgb25VcGRhdGUsXG4gIHJlYWRvbmx5LFxuICB0cmFuc2llbnQsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgTW9kZWwsIHJlcXVpcmVkIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljTW9kZWxLZXlzIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgdHlwZSB7IENvbnRleHQgYXMgSExDb250ZXh0IH0gZnJvbSBcImZhYnJpYy1jb250cmFjdC1hcGlcIjtcbmltcG9ydCB7IEZhYnJpY0VSQzIwQ29udHJhY3QgfSBmcm9tIFwiLi4vY29udHJhY3RzL2VyYzIwL2VyYzIwY29udHJhY3RcIjtcbmltcG9ydCB7XG4gIGFwcGx5LFxuICBDb25zdHJ1Y3RvcixcbiAgRGVjb3JhdGlvbixcbiAgbWV0YWRhdGEsXG4gIE1ldGFkYXRhLFxuICBwcm9wTWV0YWRhdGEsXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgRmFicmljRmxhZ3MgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG4vKipcbiAqIERlY29yYXRvciBmb3IgbWFya2luZyBtZXRob2RzIHRoYXQgcmVxdWlyZSBvd25lcnNoaXAgYXV0aG9yaXphdGlvbi5cbiAqIENoZWNrcyB0aGUgb3duZXIgb2YgdGhlIHRva2VuIGJlZm9yZSBhbGxvd2luZyB0aGUgbWV0aG9kIHRvIGJlIGV4ZWN1dGVkLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjbGFzcyBUb2tlbkNvbnRyYWN0IGV4dGVuZHMgQ29udHJhY3Qge1xuICogICBAT3duZXIoKVxuICogICBhc3luYyBNaW50KGN0eDogQ29udGV4dCwgYW1vdW50OiBudW1iZXIpIHtcbiAqICAgICAvLyBNaW50IHRva2VuIGxvZ2ljXG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICpcbiAqIEByZXR1cm5zIHtNZXRob2REZWNvcmF0b3J9IEEgbWV0aG9kIGRlY29yYXRvciB0aGF0IGNoZWNrcyBvd25lcnNoaXAgYXV0aG9yaXphdGlvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIE93bmVyKCkge1xuICByZXR1cm4gZnVuY3Rpb24gKFxuICAgIHRhcmdldDogYW55LFxuICAgIHByb3BlcnR5S2V5OiBzdHJpbmcsXG4gICAgZGVzY3JpcHRvcjogUHJvcGVydHlEZXNjcmlwdG9yXG4gICkge1xuICAgIGNvbnN0IG9yaWdpbmFsTWV0aG9kID0gZGVzY3JpcHRvci52YWx1ZTtcblxuICAgIGRlc2NyaXB0b3IudmFsdWUgPSBhc3luYyBmdW5jdGlvbiAoXG4gICAgICB0aGlzOiBGYWJyaWNFUkMyMENvbnRyYWN0LFxuICAgICAgLi4uYXJnczogYW55W11cbiAgICApIHtcbiAgICAgIGNvbnN0IGN0eDogSExDb250ZXh0ID0gYXJnc1swXTtcbiAgICAgIGNvbnN0IGFjb3VudElkID0gY3R4LmNsaWVudElkZW50aXR5LmdldElEKCk7XG5cbiAgICAgIGNvbnN0IHNlbGVjdCA9IGF3YWl0ICh0aGlzIGFzIEZhYnJpY0VSQzIwQ29udHJhY3QpW1xuICAgICAgICBcInRva2VuUmVwb3NpdG9yeVwiXG4gICAgICBdLnNlbGVjdCgpO1xuXG4gICAgICBjb25zdCB0b2tlbnMgPSBhd2FpdCBzZWxlY3QuZXhlY3V0ZShjdHgpO1xuXG4gICAgICBpZiAodG9rZW5zLmxlbmd0aCA9PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBOb3RGb3VuZEVycm9yKFwiTm8gdG9rZW5zIGF2YWlhbGJsZVwiKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRva2Vucy5sZW5ndGggPiAxKSB7XG4gICAgICAgIHRocm93IG5ldyBOb3RGb3VuZEVycm9yKGBUbyBtYW55IHRva2VuIGF2YWlsYWJsZSA6ICR7dG9rZW5zLmxlbmd0aH1gKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRva2Vuc1swXS5vd25lciAhPSBhY291bnRJZCkge1xuICAgICAgICB0aHJvdyBuZXcgQXV0aG9yaXphdGlvbkVycm9yKFxuICAgICAgICAgIGBVc2VyIG5vdCBhdXRob3JpemVkIHRvIHJ1biAke3Byb3BlcnR5S2V5fSBvbiB0aGUgdG9rZW5gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBhd2FpdCBvcmlnaW5hbE1ldGhvZC5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIGRlc2NyaXB0b3I7XG4gIH07XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBvd25lZEJ5T25DcmVhdGU8XG4gIE0gZXh0ZW5kcyBNb2RlbDxib29sZWFuPixcbiAgUiBleHRlbmRzIFJlcG88TT4sXG4gIFYsXG4+KFxuICB0aGlzOiBSLFxuICBjb250ZXh0OiBDb250ZXh0PGFueT4sXG4gIGRhdGE6IFYsXG4gIGtleToga2V5b2YgTSxcbiAgbW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB7IHN0dWIgfSA9IGNvbnRleHQgYXMgYW55O1xuXG4gIGNvbnN0IGNyZWF0b3IgPSBhd2FpdCBzdHViLmdldENyZWF0b3IoKTtcbiAgY29uc3Qgb3duZXIgPSBjcmVhdG9yLm1zcGlkO1xuXG4gIGNvbnN0IHNldE93bmVkQnlLZXlWYWx1ZSA9IGZ1bmN0aW9uIDxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIHRhcmdldDogTSxcbiAgICBwcm9wZXJ0eUtleTogc3RyaW5nLFxuICAgIHZhbHVlOiBzdHJpbmcgfCBudW1iZXIgfCBiaWdpbnRcbiAgKSB7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwgcHJvcGVydHlLZXksIHtcbiAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICB2YWx1ZTogdmFsdWUsXG4gICAgfSk7XG4gIH07XG5cbiAgc2V0T3duZWRCeUtleVZhbHVlKG1vZGVsLCBrZXkgYXMgc3RyaW5nLCBvd25lcik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBvd25lZEJ5KCkge1xuICBjb25zdCBrZXkgPSBnZXRGYWJyaWNNb2RlbEtleShGYWJyaWNNb2RlbEtleXMuT1dORURCWSk7XG5cbiAgZnVuY3Rpb24gb3duZWRCeSgpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKG9iajogYW55LCBhdHRyaWJ1dGU/OiBhbnkpIHtcbiAgICAgIHJldHVybiBhcHBseShcbiAgICAgICAgcmVxdWlyZWQoKSxcbiAgICAgICAgcmVhZG9ubHkoKSxcbiAgICAgICAgb25DcmVhdGUob3duZWRCeU9uQ3JlYXRlKSxcbiAgICAgICAgcHJvcE1ldGFkYXRhKGdldEZhYnJpY01vZGVsS2V5KEZhYnJpY01vZGVsS2V5cy5PV05FREJZKSwgYXR0cmlidXRlKVxuICAgICAgKShvYmosIGF0dHJpYnV0ZSk7XG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiBEZWNvcmF0aW9uLmZvcihrZXkpXG4gICAgLmRlZmluZSh7XG4gICAgICBkZWNvcmF0b3I6IG93bmVkQnksXG4gICAgICBhcmdzOiBbXSxcbiAgICB9KVxuICAgIC5hcHBseSgpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdHJhbnNhY3Rpb25JZE9uQ3JlYXRlPFxuICBNIGV4dGVuZHMgTW9kZWw8Ym9vbGVhbj4sXG4gIFIgZXh0ZW5kcyBSZXBvPE0+LFxuICBWLFxuPihcbiAgdGhpczogUixcbiAgY29udGV4dDogQ29udGV4dDxhbnk+LFxuICBkYXRhOiBWLFxuICBrZXk6IGtleW9mIE0sXG4gIG1vZGVsOiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgeyBzdHViIH0gPSBjb250ZXh0IGFzIGFueTtcbiAgbW9kZWxba2V5XSA9IHN0dWIuZ2V0VHhJRCgpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdHJhbnNhY3Rpb25JZCgpIHtcbiAgZnVuY3Rpb24gdHJhbnNhY3Rpb25JZCgpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKG9iajogYW55LCBhdHRyaWJ1dGU/OiBhbnkpIHtcbiAgICAgIHJldHVybiBhcHBseShcbiAgICAgICAgcmVxdWlyZWQoKSxcbiAgICAgICAgcmVhZG9ubHkoKSxcbiAgICAgICAgb25DcmVhdGUodHJhbnNhY3Rpb25JZE9uQ3JlYXRlKSxcbiAgICAgICAgb25VcGRhdGUodHJhbnNhY3Rpb25JZE9uQ3JlYXRlKSxcbiAgICAgICAgcHJvcE1ldGFkYXRhKFxuICAgICAgICAgIE1ldGFkYXRhLmtleShcbiAgICAgICAgICAgIEZhYnJpY01vZGVsS2V5cy5GQUJSSUMsXG4gICAgICAgICAgICBhdHRyaWJ1dGUsXG4gICAgICAgICAgICBGYWJyaWNNb2RlbEtleXMuVFJBTlNBQ1RJT05fSURcbiAgICAgICAgICApLFxuICAgICAgICAgIGF0dHJpYnV0ZVxuICAgICAgICApXG4gICAgICApKG9iaiwgYXR0cmlidXRlKTtcbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIERlY29yYXRpb24uZm9yKEZhYnJpY01vZGVsS2V5cy5UUkFOU0FDVElPTl9JRClcbiAgICAuZGVmaW5lKHtcbiAgICAgIGRlY29yYXRvcjogdHJhbnNhY3Rpb25JZCxcbiAgICAgIGFyZ3M6IFtdLFxuICAgIH0pXG4gICAgLmFwcGx5KCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRGYWJyaWNNb2RlbEtleShrZXk6IHN0cmluZykge1xuICByZXR1cm4gTWV0YWRhdGEua2V5KEZhYnJpY01vZGVsS2V5cy5GQUJSSUMgKyBrZXkpO1xufVxuXG5leHBvcnQgdHlwZSBDb2xsZWN0aW9uUmVzb2x2ZXIgPSA8TSBleHRlbmRzIE1vZGVsPihtb2RlbDogTSkgPT4gc3RyaW5nO1xuXG5leHBvcnQgY29uc3QgSW1wbGljaXRQcml2YXRlQ29sbGVjdGlvbjogQ29sbGVjdGlvblJlc29sdmVyID0gPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNXG4pID0+IHtcbiAgcmV0dXJuIGBfXyR7bW9kZWwuY29uc3RydWN0b3IubmFtZX1Qcml2YXRlQ29sbGVjdGlvbmA7XG59O1xuXG5leHBvcnQgdHlwZSBTZWdyZWdhdGVkRGF0YU1ldGFkYXRhID0ge1xuICBjb2xsZWN0aW9uczogc3RyaW5nIHwgQ29sbGVjdGlvblJlc29sdmVyO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlZ3JlZ2F0ZWREYXRhT25DcmVhdGU8TSBleHRlbmRzIE1vZGVsPihcbiAgdGhpczogUmVwb3NpdG9yeTxNLCBhbnk+LFxuICBjb250ZXh0OiBDb250ZXh0PEZhYnJpY0ZsYWdzPixcbiAgZGF0YTogU2VncmVnYXRlZERhdGFNZXRhZGF0YVtdLFxuICBrZXlzOiAoa2V5b2YgTSlbXSxcbiAgbW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge1xuICBpZiAoa2V5cy5sZW5ndGggIT09IGRhdGEubGVuZ3RoKVxuICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgYFNlZ3JlZ2F0ZWQgZGF0YSBrZXlzIGFuZCBtZXRhZGF0YSBsZW5ndGggbWlzbWF0Y2hgXG4gICAgKTtcblxuICBjb25zdCBjb2xsZWN0aW9uUmVzb2x2ZXIgPSBkYXRhWzBdLmNvbGxlY3Rpb25zO1xuICBjb25zdCBjb2xsZWN0aW9uID1cbiAgICB0eXBlb2YgY29sbGVjdGlvblJlc29sdmVyID09PSBcInN0cmluZ1wiXG4gICAgICA/IGNvbGxlY3Rpb25SZXNvbHZlclxuICAgICAgOiBjb2xsZWN0aW9uUmVzb2x2ZXIobW9kZWwpO1xuXG4gIGNvbnN0IHJlYnVpbHQgPSBrZXlzLnJlZHVjZShcbiAgICAoYWNjOiBSZWNvcmQ8a2V5b2YgTSwgYW55PiwgaywgaSkgPT4ge1xuICAgICAgY29uc3QgYyA9XG4gICAgICAgIHR5cGVvZiBkYXRhW2ldLmNvbGxlY3Rpb25zID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgPyBkYXRhW2ldLmNvbGxlY3Rpb25zXG4gICAgICAgICAgOiBkYXRhW2ldLmNvbGxlY3Rpb25zKG1vZGVsKTtcbiAgICAgIGlmIChjICE9PSBjb2xsZWN0aW9uKVxuICAgICAgICB0aHJvdyBuZXcgVW5zdXBwb3J0ZWRFcnJvcihcbiAgICAgICAgICBgU2VncmVnYXRlZCBkYXRhIGNvbGxlY3Rpb24gbWlzbWF0Y2g6ICR7Y30gdnMgJHtjb2xsZWN0aW9ufWBcbiAgICAgICAgKTtcbiAgICAgIGFjY1trXSA9IG1vZGVsW2tdO1xuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LFxuICAgIHt9IGFzIFJlY29yZDxrZXlvZiBNLCBhbnk+XG4gICk7XG5cbiAgY29uc3QgdG9DcmVhdGUgPSBuZXcgdGhpcy5jbGFzcyhyZWJ1aWx0KTtcblxuICAvLyBjb25zdCBzZWdyZWdhdGVkID0gTW9kZWwuc2VncmVnYXRlKG1vZGVsKTtcblxuICBjb25zdCBjcmVhdGVkID0gYXdhaXQgdGhpcy5vdmVycmlkZSh7IHNlZ3JlZ2F0ZWQ6IGNvbGxlY3Rpb24gfSBhcyBhbnkpLmNyZWF0ZShcbiAgICB0b0NyZWF0ZSxcbiAgICBjb250ZXh0XG4gICk7XG4gIE9iamVjdC5hc3NpZ24obW9kZWwsIGNyZWF0ZWQpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2VncmVnYXRlZERhdGFPblJlYWQ8TSBleHRlbmRzIE1vZGVsPihcbiAgdGhpczogUmVwb3NpdG9yeTxNLCBhbnk+LFxuICBjb250ZXh0OiBDb250ZXh0PEZhYnJpY0ZsYWdzPixcbiAgZGF0YTogU2VncmVnYXRlZERhdGFNZXRhZGF0YVtdLFxuICBrZXlzOiAoa2V5b2YgTSlbXSxcbiAgbW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge1xuICBpZiAoa2V5cy5sZW5ndGggIT09IGRhdGEubGVuZ3RoKVxuICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgYFNlZ3JlZ2F0ZWQgZGF0YSBrZXlzIGFuZCBtZXRhZGF0YSBsZW5ndGggbWlzbWF0Y2hgXG4gICAgKTtcblxuICBjb25zdCBjb2xsZWN0aW9uUmVzb2x2ZXIgPSBkYXRhWzBdLmNvbGxlY3Rpb25zO1xuICBjb25zdCBjb2xsZWN0aW9uID1cbiAgICB0eXBlb2YgY29sbGVjdGlvblJlc29sdmVyID09PSBcInN0cmluZ1wiXG4gICAgICA/IGNvbGxlY3Rpb25SZXNvbHZlclxuICAgICAgOiBjb2xsZWN0aW9uUmVzb2x2ZXIobW9kZWwpO1xuXG4gIGNvbnN0IHJlYnVpbHQgPSBrZXlzLnJlZHVjZShcbiAgICAoYWNjOiBSZWNvcmQ8a2V5b2YgTSwgYW55PiwgaywgaSkgPT4ge1xuICAgICAgY29uc3QgYyA9XG4gICAgICAgIHR5cGVvZiBkYXRhW2ldLmNvbGxlY3Rpb25zID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgPyBkYXRhW2ldLmNvbGxlY3Rpb25zXG4gICAgICAgICAgOiBkYXRhW2ldLmNvbGxlY3Rpb25zKG1vZGVsKTtcbiAgICAgIGlmIChjICE9PSBjb2xsZWN0aW9uKVxuICAgICAgICB0aHJvdyBuZXcgVW5zdXBwb3J0ZWRFcnJvcihcbiAgICAgICAgICBgU2VncmVnYXRlZCBkYXRhIGNvbGxlY3Rpb24gbWlzbWF0Y2g6ICR7Y30gdnMgJHtjb2xsZWN0aW9ufWBcbiAgICAgICAgKTtcbiAgICAgIGFjY1trXSA9IG1vZGVsW2tdO1xuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LFxuICAgIHt9IGFzIFJlY29yZDxrZXlvZiBNLCBhbnk+XG4gICk7XG5cbiAgY29uc3QgdG9DcmVhdGUgPSBuZXcgdGhpcy5jbGFzcyhyZWJ1aWx0KTtcblxuICAvLyBjb25zdCBzZWdyZWdhdGVkID0gTW9kZWwuc2VncmVnYXRlKG1vZGVsKTtcblxuICBjb25zdCBjcmVhdGVkID0gYXdhaXQgdGhpcy5vdmVycmlkZSh7IHNlZ3JlZ2F0ZWQ6IGNvbGxlY3Rpb24gfSBhcyBhbnkpLmNyZWF0ZShcbiAgICB0b0NyZWF0ZSxcbiAgICBjb250ZXh0XG4gICk7XG4gIE9iamVjdC5hc3NpZ24obW9kZWwsIGNyZWF0ZWQpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2VncmVnYXRlZERhdGFPblVwZGF0ZTxNIGV4dGVuZHMgTW9kZWw+KFxuICB0aGlzOiBSZXBvc2l0b3J5PE0sIGFueT4sXG4gIGNvbnRleHQ6IENvbnRleHQ8RmFicmljRmxhZ3M+LFxuICBkYXRhOiBTZWdyZWdhdGVkRGF0YU1ldGFkYXRhW10sXG4gIGtleToga2V5b2YgTVtdLFxuICBtb2RlbDogTSxcbiAgb2xkTW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge31cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlZ3JlZ2F0ZWREYXRhT25EZWxldGU8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIFJlcG9zaXRvcnk8TSwgYW55PixcbiAgViBleHRlbmRzIFNlZ3JlZ2F0ZWREYXRhTWV0YWRhdGEsXG4+KFxuICB0aGlzOiBSLFxuICBjb250ZXh0OiBDb250ZXh0PEZhYnJpY0ZsYWdzPixcbiAgZGF0YTogVltdLFxuICBrZXk6IGtleW9mIE1bXSxcbiAgbW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge31cblxuZnVuY3Rpb24gc2VncmVnYXRlZChcbiAgY29sbGVjdGlvbjogc3RyaW5nIHwgQ29sbGVjdGlvblJlc29sdmVyLFxuICB0eXBlOiBGYWJyaWNNb2RlbEtleXMuUFJJVkFURSB8IEZhYnJpY01vZGVsS2V5cy5TSEFSRURcbikge1xuICByZXR1cm4gZnVuY3Rpb24gaW5uZXJTZWdyZWdhdGVkKHRhcmdldDogb2JqZWN0LCBwcm9wZXJ0eUtleT86IGFueSkge1xuICAgIGZ1bmN0aW9uIHNlZ3JlZ2F0ZWREZWModGFyZ2V0OiBvYmplY3QsIHByb3BlcnR5S2V5PzogYW55KSB7XG4gICAgICBpZiAoIXByb3BlcnR5S2V5KSB7XG4gICAgICAgIGNvbnN0IHByb3BzID0gTWV0YWRhdGEucHJvcGVydGllcyh0YXJnZXQgYXMgQ29uc3RydWN0b3IpIHx8IFtdO1xuICAgICAgICBmb3IgKGNvbnN0IHByb3Agb2YgcHJvcHMpIHNlZ3JlZ2F0ZWQoY29sbGVjdGlvbiwgdHlwZSkodGFyZ2V0LCBwcm9wKTtcbiAgICAgICAgcmV0dXJuIHRhcmdldDtcbiAgICAgIH1cblxuICAgICAgY29uc3Qga2V5ID0gTWV0YWRhdGEua2V5KHR5cGUsIHByb3BlcnR5S2V5KTtcbiAgICAgIGNvbnN0IGNvbnN0cjogQ29uc3RydWN0b3IgPSB0YXJnZXQuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3I7XG5cbiAgICAgIGNvbnN0IG1ldGEgPSBNZXRhZGF0YS5nZXQoY29uc3RyIGFzIENvbnN0cnVjdG9yLCBrZXkpIHx8IHt9O1xuICAgICAgY29uc3QgY29sbGVjdGlvbnMgPSBuZXcgU2V0KG1ldGEuY29sbGVjdGlvbnMgfHwgW10pO1xuICAgICAgY29sbGVjdGlvbnMuYWRkKGNvbGxlY3Rpb24pO1xuICAgICAgbWV0YS5jb2xsZWN0aW9ucyA9IFsuLi5jb2xsZWN0aW9uc107XG4gICAgICBNZXRhZGF0YS5zZXQoY29uc3RyIGFzIENvbnN0cnVjdG9yLCBrZXksIG1ldGEpO1xuICAgIH1cbiAgICBjb25zdCBkZWNzOiBhbnlbXSA9IFtdO1xuICAgIGlmICghcHJvcGVydHlLZXkpIHtcbiAgICAgIC8vIGRlY29yYXRlZCBhdCB0aGUgY2xhc3MgbGV2ZWxcbiAgICAgIE1ldGFkYXRhLnByb3BlcnRpZXModGFyZ2V0IGFzIENvbnN0cnVjdG9yKT8uZm9yRWFjaCgocCkgPT5cbiAgICAgICAgc2VncmVnYXRlZChjb2xsZWN0aW9uLCB0eXBlKSh0YXJnZXQsIHApXG4gICAgICApO1xuICAgICAgcmV0dXJuIG1ldGFkYXRhKHR5cGUsIHRydWUpKHRhcmdldCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRlY3MucHVzaChcbiAgICAgICAgdHJhbnNpZW50KCksXG4gICAgICAgIHNlZ3JlZ2F0ZWREZWMsXG4gICAgICAgIG9uQ3JlYXRlKFxuICAgICAgICAgIHNlZ3JlZ2F0ZWREYXRhT25DcmVhdGUsXG4gICAgICAgICAgeyBjb2xsZWN0aW9uczogY29sbGVjdGlvbiB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHByaW9yaXR5OiA5NSxcbiAgICAgICAgICAgIGdyb3VwOlxuICAgICAgICAgICAgICB0eXBlb2YgY29sbGVjdGlvbiA9PT0gXCJzdHJpbmdcIlxuICAgICAgICAgICAgICAgID8gY29sbGVjdGlvblxuICAgICAgICAgICAgICAgIDogY29sbGVjdGlvbi50b1N0cmluZygpLFxuICAgICAgICAgIH1cbiAgICAgICAgKSxcbiAgICAgICAgb25SZWFkKFxuICAgICAgICAgIHNlZ3JlZ2F0ZWREYXRhT25SZWFkIGFzIGFueSxcbiAgICAgICAgICB7IGNvbGxlY3Rpb25zOiBjb2xsZWN0aW9uIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgcHJpb3JpdHk6IDk1LFxuICAgICAgICAgICAgZ3JvdXA6XG4gICAgICAgICAgICAgIHR5cGVvZiBjb2xsZWN0aW9uID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICAgICAgPyBjb2xsZWN0aW9uXG4gICAgICAgICAgICAgICAgOiBjb2xsZWN0aW9uLnRvU3RyaW5nKCksXG4gICAgICAgICAgfVxuICAgICAgICApLFxuICAgICAgICBvblVwZGF0ZShcbiAgICAgICAgICBzZWdyZWdhdGVkRGF0YU9uVXBkYXRlIGFzIGFueSxcbiAgICAgICAgICB7IGNvbGxlY3Rpb25zOiBjb2xsZWN0aW9uIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgcHJpb3JpdHk6IDk1LFxuICAgICAgICAgICAgZ3JvdXA6XG4gICAgICAgICAgICAgIHR5cGVvZiBjb2xsZWN0aW9uID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICAgICAgPyBjb2xsZWN0aW9uXG4gICAgICAgICAgICAgICAgOiBjb2xsZWN0aW9uLnRvU3RyaW5nKCksXG4gICAgICAgICAgfVxuICAgICAgICApLFxuICAgICAgICBvbkRlbGV0ZShcbiAgICAgICAgICBzZWdyZWdhdGVkRGF0YU9uRGVsZXRlIGFzIGFueSxcbiAgICAgICAgICB7IGNvbGxlY3Rpb25zOiBjb2xsZWN0aW9uIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgcHJpb3JpdHk6IDk1LFxuICAgICAgICAgICAgZ3JvdXA6XG4gICAgICAgICAgICAgIHR5cGVvZiBjb2xsZWN0aW9uID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICAgICAgPyBjb2xsZWN0aW9uXG4gICAgICAgICAgICAgICAgOiBjb2xsZWN0aW9uLnRvU3RyaW5nKCksXG4gICAgICAgICAgfVxuICAgICAgICApXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gYXBwbHkoLi4uZGVjcykodGFyZ2V0LCBwcm9wZXJ0eUtleSk7XG4gICAgLy8gcmV0dXJuIGFwcGx5KCkodGFyZ2V0LCBwcm9wZXJ0eUtleSk7XG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwcml2YXRlRGF0YShcbiAgY29sbGVjdGlvbjogc3RyaW5nIHwgQ29sbGVjdGlvblJlc29sdmVyID0gSW1wbGljaXRQcml2YXRlQ29sbGVjdGlvblxuKSB7XG4gIGZ1bmN0aW9uIHByaXZhdGVEYXRhKGNvbGxlY3Rpb246IHN0cmluZyB8IENvbGxlY3Rpb25SZXNvbHZlcikge1xuICAgIHJldHVybiBzZWdyZWdhdGVkKGNvbGxlY3Rpb24sIEZhYnJpY01vZGVsS2V5cy5QUklWQVRFKTtcbiAgfVxuXG4gIHJldHVybiBEZWNvcmF0aW9uLmZvcihGYWJyaWNNb2RlbEtleXMuUFJJVkFURSlcbiAgICAuZGVmaW5lKHtcbiAgICAgIGRlY29yYXRvcjogcHJpdmF0ZURhdGEsXG4gICAgICBhcmdzOiBbY29sbGVjdGlvbl0sXG4gICAgfSlcbiAgICAuYXBwbHkoKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNoYXJlZERhdGEoY29sbGVjdGlvbjogc3RyaW5nIHwgQ29sbGVjdGlvblJlc29sdmVyKSB7XG4gIGZ1bmN0aW9uIHNoYXJlZERhdGEoY29sbGVjdGlvbjogc3RyaW5nIHwgQ29sbGVjdGlvblJlc29sdmVyKSB7XG4gICAgcmV0dXJuIHNlZ3JlZ2F0ZWQoY29sbGVjdGlvbiwgRmFicmljTW9kZWxLZXlzLlNIQVJFRCk7XG4gIH1cblxuICByZXR1cm4gRGVjb3JhdGlvbi5mb3IoRmFicmljTW9kZWxLZXlzLlNIQVJFRClcbiAgICAuZGVmaW5lKHtcbiAgICAgIGRlY29yYXRvcjogc2hhcmVkRGF0YSxcbiAgICAgIGFyZ3M6IFtjb2xsZWN0aW9uXSxcbiAgICB9KVxuICAgIC5hcHBseSgpO1xufVxuLy9cbi8vIGV4cG9ydCBmdW5jdGlvbiBwcml2YXRlRGF0YShjb2xsZWN0aW9uPzogc3RyaW5nKSB7XG4vLyAgIGlmICghY29sbGVjdGlvbikge1xuLy8gICAgIHRocm93IG5ldyBFcnJvcihcIkNvbGxlY3Rpb24gbmFtZSBpcyByZXF1aXJlZFwiKTtcbi8vICAgfVxuLy9cbi8vICAgY29uc3Qga2V5OiBzdHJpbmcgPSBGYWJyaWNNb2RlbEtleXMuUFJJVkFURTtcbi8vXG4vLyAgIHJldHVybiBmdW5jdGlvbiBwcml2YXRlRGF0YTxNIGV4dGVuZHMgTW9kZWw+KFxuLy8gICAgIG1vZGVsOiBNIHwgQ29uc3RydWN0b3I8TT4sXG4vLyAgICAgYXR0cmlidXRlPzogYW55XG4vLyAgICkge1xuLy8gICAgIGNvbnN0IGNvbnN0ciA9XG4vLyAgICAgICBtb2RlbCBpbnN0YW5jZW9mIE1vZGVsID8gKG1vZGVsLmNvbnN0cnVjdG9yIGFzIENvbnN0cnVjdG9yKSA6IG1vZGVsO1xuLy9cbi8vICAgICBjb25zdCBtZXRhRGF0YTogYW55ID0gTWV0YWRhdGEuZ2V0KGNvbnN0cik7XG4vLyAgICAgY29uc3QgbW9kZWxkYXRhID0gbWV0YURhdGE/LnByaXZhdGU/LmNvbGxlY3Rpb25zIHx8IFtdO1xuLy9cbi8vICAgICBwcm9wTWV0YWRhdGEoa2V5LCB7XG4vLyAgICAgICAuLi4oIWF0dHJpYnV0ZSAmJiB7XG4vLyAgICAgICAgIGNvbGxlY3Rpb25zOiBtb2RlbGRhdGFcbi8vICAgICAgICAgICA/IFsuLi5uZXcgU2V0KFsuLi5tb2RlbGRhdGEsIGNvbGxlY3Rpb25dKV1cbi8vICAgICAgICAgICA6IFtjb2xsZWN0aW9uXSxcbi8vICAgICAgIH0pLFxuLy8gICAgICAgaXNQcml2YXRlOiAhYXR0cmlidXRlLFxuLy8gICAgIH0pKGF0dHJpYnV0ZSA/IGNvbnN0ciA6IG1vZGVsKTtcbi8vXG4vLyAgICAgaWYgKGF0dHJpYnV0ZSkge1xuLy8gICAgICAgY29uc3QgYXR0cmlidXRlRGF0YSA9XG4vLyAgICAgICAgIChtZXRhRGF0YT8ucHJpdmF0ZT8uW2F0dHJpYnV0ZV0gYXMgYW55KT8uY29sbGVjdGlvbnMgfHwgW107XG4vLyAgICAgICBwcm9wTWV0YWRhdGEoTWV0YWRhdGEua2V5KGtleSwgYXR0cmlidXRlKSwge1xuLy8gICAgICAgICBjb2xsZWN0aW9uczogYXR0cmlidXRlRGF0YVxuLy8gICAgICAgICAgID8gWy4uLm5ldyBTZXQoWy4uLmF0dHJpYnV0ZURhdGEsIGNvbGxlY3Rpb25dKV1cbi8vICAgICAgICAgICA6IFtjb2xsZWN0aW9uXSxcbi8vICAgICAgIH0pKG1vZGVsLCBhdHRyaWJ1dGUpO1xuLy8gICAgICAgdHJhbnNpZW50KCkobW9kZWwsIGF0dHJpYnV0ZSk7XG4vLyAgICAgfVxuLy8gICB9O1xuLy8gfVxuIiwiLyoqXG4gKiBFbnVtIHJlcHJlc2VudGluZyB0aGUgZXZlbnRzIGVtaXR0ZWQgYnkgYW4gRVJDMjAgY29udHJhY3QuXG4gKlxuICogQHJlbWFya3NcbiAqIFRoaXMgZW51bSBpcyB1c2VkIHRvIGlkZW50aWZ5IHRoZSBzcGVjaWZpYyBldmVudHMgdGhhdCBjYW4gYmUgZW1pdHRlZCBieSBhbiBFUkMyMCBjb250cmFjdC5cbiAqIFRoZSBldmVudHMgYXJlIG5hbWVkIGFjY29yZGluZyB0byB0aGUgRUlQLTIwIHN0YW5kYXJkLlxuICovXG5leHBvcnQgZW51bSBFUkMyMEV2ZW50cyB7XG4gIC8qKlxuICAgKiBFbWl0dGVkIHdoZW4gYSBgdHJhbnNmZXJgIGZ1bmN0aW9uIGlzIGNhbGxlZCBzdWNjZXNzZnVsbHkuXG4gICAqXG4gICAqIEBwYXJhbSBmcm9tIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIHNlbmRlci5cbiAgICogQHBhcmFtIHRvIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIHJlY2lwaWVudC5cbiAgICogQHBhcmFtIHZhbHVlIC0gVGhlIGFtb3VudCBvZiB0b2tlbnMgdHJhbnNmZXJyZWQuXG4gICAqL1xuICBUUkFOU0ZFUiA9IFwiVHJhbnNmZXJcIixcblxuICAvKipcbiAgICogRW1pdHRlZCB3aGVuIGFuIGBhcHByb3ZlYCBmdW5jdGlvbiBpcyBjYWxsZWQgc3VjY2Vzc2Z1bGx5LlxuICAgKlxuICAgKiBAcGFyYW0gb3duZXIgLSBUaGUgYWRkcmVzcyBvZiB0aGUgdG9rZW4gb3duZXIuXG4gICAqIEBwYXJhbSBzcGVuZGVyIC0gVGhlIGFkZHJlc3Mgb2YgdGhlIGFwcHJvdmVkIHNwZW5kZXIuXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBhbW91bnQgb2YgdG9rZW5zIGFwcHJvdmVkIGZvciB0aGUgc3BlbmRlci5cbiAgICovXG4gIEFQUFJPVkFMID0gXCJBcHByb3ZhbFwiLFxufVxuIiwiaW1wb3J0IHsgQXV0aG9yaXphdGlvbkVycm9yLCBDb25kaXRpb24gfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IENvbnRleHQsIFRyYW5zYWN0aW9uIH0gZnJvbSBcImZhYnJpYy1jb250cmFjdC1hcGlcIjtcbmltcG9ydCB7IGFkZCwgc3ViIH0gZnJvbSBcIi4uLy4uL3NoYXJlZC9tYXRoXCI7XG5pbXBvcnQge1xuICBBbGxvd2FuY2VFcnJvcixcbiAgQmFsYW5jZUVycm9yLFxuICBOb3RJbml0aWFsaXplZEVycm9yLFxufSBmcm9tIFwiLi4vLi4vc2hhcmVkL2Vycm9yc1wiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RBZGFwdGVyIH0gZnJvbSBcIi4uL0NvbnRyYWN0QWRhcHRlclwiO1xuaW1wb3J0IHsgQWxsb3dhbmNlLCBFUkMyMFRva2VuLCBFUkMyMFdhbGxldCB9IGZyb20gXCIuL21vZGVsc1wiO1xuaW1wb3J0IHsgT3duZXIgfSBmcm9tIFwiLi4vLi4vc2hhcmVkL2RlY29yYXRvcnNcIjtcbmltcG9ydCB7IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeSB9IGZyb20gXCIuLi9GYWJyaWNDb250cmFjdFJlcG9zaXRvcnlcIjtcbmltcG9ydCB0eXBlIHsgRmFicmljQ29udHJhY3RDb250ZXh0IH0gZnJvbSBcIi4uL0NvbnRyYWN0Q29udGV4dFwiO1xuaW1wb3J0IHtcbiAgQmFzZUVycm9yLFxuICBJbnRlcm5hbEVycm9yLFxuICBOb3RGb3VuZEVycm9yLFxuICBWYWxpZGF0aW9uRXJyb3IsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgRmFicmljQ3J1ZENvbnRyYWN0IH0gZnJvbSBcIi4uL2NydWQvY3J1ZC1jb250cmFjdFwiO1xuaW1wb3J0IHsgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXIgfSBmcm9tIFwiLi4vRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXJcIjtcbmltcG9ydCB7IEVSQzIwRXZlbnRzIH0gZnJvbSBcIi4uLy4uL3NoYXJlZC9lcmMyMC9lcmMyMC1jb25zdGFudHNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRVJDMjAgdG9rZW4gY29udHJhY3QgYmFzZSBmb3IgSHlwZXJsZWRnZXIgRmFicmljXG4gKiBAc3VtbWFyeSBJbXBsZW1lbnRzIEVSQzIwLWxpa2UgdG9rZW4gbG9naWMgdXNpbmcgcmVwb3NpdG9yaWVzIGFuZCBhZGFwdGVycywgcHJvdmlkaW5nIHN0YW5kYXJkIHRva2VuIG9wZXJhdGlvbnMgc3VjaCBhcyBiYWxhbmNlIHF1ZXJpZXMsIHRyYW5zZmVycywgYXBwcm92YWxzLCBtaW50aW5nIGFuZCBidXJuaW5nLlxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgY29udHJhY3QgbmFtZSB1c2VkIHRvIHNjb3BlIHRva2VuIGlkZW50aXR5XG4gKiBAbm90ZSBodHRwczovL2VpcHMuZXRoZXJldW0ub3JnL0VJUFMvZWlwLTIwXG4gKiBAcmV0dXJuIHt2b2lkfVxuICogQGNsYXNzIEZhYnJpY0VSQzIwQ29udHJhY3RcbiAqIEBleGFtcGxlXG4gKiBjbGFzcyBNeVRva2VuQ29udHJhY3QgZXh0ZW5kcyBGYWJyaWNFUkMyMENvbnRyYWN0IHtcbiAqICAgY29uc3RydWN0b3IoKSB7IHN1cGVyKCdNeVRva2VuJyk7IH1cbiAqIH1cbiAqIC8vIFRoZSBjb250cmFjdCBleHBvc2VzIG1ldGhvZHMgbGlrZSBUcmFuc2ZlciwgQXBwcm92ZSwgTWludCwgQnVybiwgZXRjLlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDbGllbnRcbiAqICAgcGFydGljaXBhbnQgQ29udHJhY3RcbiAqICAgcGFydGljaXBhbnQgV2FsbGV0UmVwb1xuICogICBwYXJ0aWNpcGFudCBUb2tlblJlcG9cbiAqICAgcGFydGljaXBhbnQgTGVkZ2VyXG4gKiAgIENsaWVudC0+PkNvbnRyYWN0OiBUcmFuc2ZlcihjdHgsIHRvLCB2YWx1ZSlcbiAqICAgQ29udHJhY3QtPj5XYWxsZXRSZXBvOiByZWFkKGZyb20pXG4gKiAgIENvbnRyYWN0LT4+V2FsbGV0UmVwbzogcmVhZCh0bylcbiAqICAgQ29udHJhY3QtPj5MZWRnZXI6IHB1dFN0YXRlKHVwZGF0ZWQgYmFsYW5jZXMpXG4gKiAgIENvbnRyYWN0LS0+PkNsaWVudDogc3VjY2Vzc1xuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgRmFicmljRVJDMjBDb250cmFjdCBleHRlbmRzIEZhYnJpY0NydWRDb250cmFjdDxFUkMyMFdhbGxldD4ge1xuICBwcml2YXRlIHdhbGxldFJlcG9zaXRvcnk6IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxFUkMyMFdhbGxldD47XG5cbiAgcHJpdmF0ZSB0b2tlblJlcG9zaXRvcnk6IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxFUkMyMFRva2VuPjtcblxuICBwcml2YXRlIGFsbG93YW5jZVJlcG9zaXRvcnk6IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeTxBbGxvd2FuY2U+O1xuXG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihuYW1lOiBzdHJpbmcpIHtcbiAgICBzdXBlcihuYW1lLCBFUkMyMFdhbGxldCk7XG5cbiAgICBGYWJyaWNFUkMyMENvbnRyYWN0LmFkYXB0ZXIgPVxuICAgICAgRmFicmljRVJDMjBDb250cmFjdC5hZGFwdGVyIHx8IG5ldyBGYWJyaWNDb250cmFjdEFkYXB0ZXIoKTtcblxuICAgIHRoaXMud2FsbGV0UmVwb3NpdG9yeSA9IEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeS5mb3JNb2RlbChcbiAgICAgIEVSQzIwV2FsbGV0LFxuICAgICAgRmFicmljRVJDMjBDb250cmFjdC5hZGFwdGVyLmFsaWFzXG4gICAgKTtcblxuICAgIHRoaXMudG9rZW5SZXBvc2l0b3J5ID0gRmFicmljQ29udHJhY3RSZXBvc2l0b3J5LmZvck1vZGVsKFxuICAgICAgRVJDMjBUb2tlbixcbiAgICAgIEZhYnJpY0VSQzIwQ29udHJhY3QuYWRhcHRlci5hbGlhc1xuICAgICk7XG5cbiAgICB0aGlzLmFsbG93YW5jZVJlcG9zaXRvcnkgPSBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnkuZm9yTW9kZWwoXG4gICAgICBBbGxvd2FuY2UsXG4gICAgICBGYWJyaWNFUkMyMENvbnRyYWN0LmFkYXB0ZXIuYWxpYXNcbiAgICApO1xuICB9XG5cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBUb2tlbk5hbWUoY29udGV4dDogQ29udGV4dCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5Ub2tlbk5hbWUpO1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCBhcyBhbnkpO1xuXG4gICAgY29uc3Qgc2VsZWN0ID0gdGhpcy50b2tlblJlcG9zaXRvcnkuc2VsZWN0KCk7XG4gICAgY29uc3QgdG9rZW4gPSAoYXdhaXQgc2VsZWN0LmV4ZWN1dGUoY3R4KSlbMF07XG5cbiAgICByZXR1cm4gdG9rZW4ubmFtZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIHN5bWJvbCBvZiB0aGUgdG9rZW4uIEUuZy4g4oCcSElY4oCdLlxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGNvbnRleHQgdGhlIHRyYW5zYWN0aW9uIGNvbnRleHRcbiAgICogQHJldHVybnMge1N0cmluZ30gUmV0dXJucyB0aGUgc3ltYm9sIG9mIHRoZSB0b2tlblxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBTeW1ib2woY29udGV4dDogQ29udGV4dCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5Ub2tlbk5hbWUpO1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCBhcyBhbnkpO1xuXG4gICAgY29uc3Qgc2VsZWN0ID0gdGhpcy50b2tlblJlcG9zaXRvcnkuc2VsZWN0KCk7XG4gICAgY29uc3QgdG9rZW4gPSAoYXdhaXQgc2VsZWN0LmV4ZWN1dGUoY3R4KSlbMF07XG5cbiAgICByZXR1cm4gdG9rZW4uc3ltYm9sO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgbnVtYmVyIG9mIGRlY2ltYWxzIHRoZSB0b2tlbiB1c2VzXG4gICAqIGUuZy4gOCwgbWVhbnMgdG8gZGl2aWRlIHRoZSB0b2tlbiBhbW91bnQgYnkgMTAwMDAwMDAwIHRvIGdldCBpdHMgdXNlciByZXByZXNlbnRhdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjb250ZXh0IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgdGhlIG51bWJlciBvZiBkZWNpbWFsc1xuICAgKi9cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBEZWNpbWFscyhjb250ZXh0OiBDb250ZXh0KTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLlRva2VuTmFtZSk7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQgZmlyc3QgdG8gZXhlY3V0ZSB0aGUgZnVuY3Rpb25cbiAgICBhd2FpdCB0aGlzLkNoZWNrSW5pdGlhbGl6ZWQoY3R4IGFzIGFueSk7XG5cbiAgICBjb25zdCBzZWxlY3QgPSB0aGlzLnRva2VuUmVwb3NpdG9yeS5zZWxlY3QoKTtcbiAgICBjb25zdCB0b2tlbiA9IChhd2FpdCBzZWxlY3QuZXhlY3V0ZShjdHgpKVswXTtcblxuICAgIHJldHVybiB0b2tlbi5kZWNpbWFscztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIHRvdGFsIHRva2VuIHN1cHBseS5cbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjb250ZXh0IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEByZXR1cm5zIHtOdW1iZXJ9IFJldHVybnMgdGhlIHRvdGFsIHRva2VuIHN1cHBseVxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBUb3RhbFN1cHBseShjb250ZXh0OiBDb250ZXh0KTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLlRva2VuTmFtZSk7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQgZmlyc3QgdG8gZXhlY3V0ZSB0aGUgZnVuY3Rpb25cbiAgICBhd2FpdCB0aGlzLkNoZWNrSW5pdGlhbGl6ZWQoY3R4IGFzIGFueSk7XG5cbiAgICBjb25zdCBzZWxlY3QgPSB0aGlzLndhbGxldFJlcG9zaXRvcnkuc2VsZWN0KCk7XG4gICAgY29uc3Qgd2FsbGV0cyA9IGF3YWl0IHNlbGVjdC5leGVjdXRlKGN0eCk7XG5cbiAgICBpZiAod2FsbGV0cy5sZW5ndGggPT0gMCkge1xuICAgICAgdGhyb3cgbmV3IE5vdEZvdW5kRXJyb3IoYFRoZSB0b2tlbiAke3RoaXMuZ2V0TmFtZSgpfSBkb2VzIG5vdCBleGlzdGApO1xuICAgIH1cblxuICAgIGxldCB0b3RhbCA9IDA7XG5cbiAgICB3YWxsZXRzLmZvckVhY2goKHdhbGxldCkgPT4ge1xuICAgICAgdG90YWwgKz0gd2FsbGV0LmJhbGFuY2U7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gdG90YWw7XG4gIH1cblxuICAvKipcbiAgICogQmFsYW5jZU9mIHJldHVybnMgdGhlIGJhbGFuY2Ugb2YgdGhlIGdpdmVuIGFjY291bnQuXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY3R4IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBvd25lciBUaGUgb3duZXIgZnJvbSB3aGljaCB0aGUgYmFsYW5jZSB3aWxsIGJlIHJldHJpZXZlZFxuICAgKiBAcmV0dXJucyB7TnVtYmVyfSBSZXR1cm5zIHRoZSBhY2NvdW50IGJhbGFuY2VcbiAgICovXG4gIEBUcmFuc2FjdGlvbihmYWxzZSlcbiAgYXN5bmMgQmFsYW5jZU9mKGNvbnRleHQ6IENvbnRleHQsIG93bmVyOiBzdHJpbmcpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuVG9rZW5OYW1lKTtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHggYXMgYW55KTtcblxuICAgIGNvbnN0IHdhbGxldCA9IGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS5yZWFkKG93bmVyLCBjdHgpO1xuXG4gICAgcmV0dXJuIHdhbGxldC5iYWxhbmNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFRyYW5zZmVyIHRyYW5zZmVycyB0b2tlbnMgZnJvbSBjbGllbnQgYWNjb3VudCB0byByZWNpcGllbnQgYWNjb3VudC5cbiAgICogQGRlc2NyaXB0aW9uIHJlY2lwaWVudCBhY2NvdW50IG11c3QgYmUgYSB2YWxpZCBjbGllbnRJRCBhcyByZXR1cm5lZCBieSB0aGUgQ2xpZW50QWNjb3VudElEKCkgZnVuY3Rpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY29udGV4dCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge1N0cmluZ30gdG8gVGhlIHJlY2lwaWVudFxuICAgKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgVGhlIGFtb3VudCBvZiB0b2tlbiB0byBiZSB0cmFuc2ZlcnJlZFxuICAgKlxuICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gUmV0dXJuIHdoZXRoZXIgdGhlIHRyYW5zZmVyIHdhcyBzdWNjZXNzZnVsIG9yIG5vdFxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKClcbiAgYXN5bmMgVHJhbnNmZXIoXG4gICAgY29udGV4dDogQ29udGV4dCxcbiAgICB0bzogc3RyaW5nLFxuICAgIHZhbHVlOiBudW1iZXJcbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQgZmlyc3QgdG8gZXhlY3V0ZSB0aGUgZnVuY3Rpb25cbiAgICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLlRyYW5zZmVyKTtcbiAgICBhd2FpdCB0aGlzLkNoZWNrSW5pdGlhbGl6ZWQoY3R4IGFzIGFueSk7XG5cbiAgICBjb25zdCBmcm9tID0gY3R4LmlkZW50aXR5LmdldElEKCk7XG5cbiAgICBjb25zdCB0cmFuc2ZlclJlc3AgPSBhd2FpdCB0aGlzLl90cmFuc2Zlcihmcm9tLCB0bywgdmFsdWUsIGN0eCk7XG4gICAgaWYgKCF0cmFuc2ZlclJlc3ApIHtcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiRmFpbGVkIHRvIHRyYW5zZmVyXCIpO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYW5zZmVyIGB2YWx1ZWAgYW1vdW50IG9mIHRva2VucyBmcm9tIGBmcm9tYCB0byBgdG9gLlxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGNvbnRleHQgdGhlIHRyYW5zYWN0aW9uIGNvbnRleHRcbiAgICogQHBhcmFtIHtTdHJpbmd9IGZyb20gVGhlIHNlbmRlclxuICAgKiBAcGFyYW0ge1N0cmluZ30gdG8gVGhlIHJlY2lwaWVudFxuICAgKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgVGhlIGFtb3VudCBvZiB0b2tlbiB0byBiZSB0cmFuc2ZlcnJlZFxuICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gUmV0dXJuIHdoZXRoZXIgdGhlIHRyYW5zZmVyIHdhcyBzdWNjZXNzZnVsIG9yIG5vdFxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKClcbiAgYXN5bmMgVHJhbnNmZXJGcm9tKFxuICAgIGNvbnRleHQ6IENvbnRleHQsXG4gICAgZnJvbTogc3RyaW5nLFxuICAgIHRvOiBzdHJpbmcsXG4gICAgdmFsdWU6IG51bWJlclxuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuQnVybkZyb20pO1xuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHggYXMgYW55KTtcblxuICAgIC8vIFJldHJpZXZlIHRoZSBhbGxvd2FuY2Ugb2YgdGhlIHNwZW5kZXJcblxuICAgIGNvbnN0IHNwZW5kZXIgPSBjdHguaWRlbnRpdHkuZ2V0SUQoKTtcblxuICAgIGNvbnN0IGFsbG93YW5jZSA9IGF3YWl0IHRoaXMuX2dldEFsbG93YW5jZShmcm9tLCBzcGVuZGVyLCBjdHgpO1xuICAgIGlmICghYWxsb3dhbmNlIHx8IGFsbG93YW5jZS52YWx1ZSA8IDApIHtcbiAgICAgIHRocm93IG5ldyBBbGxvd2FuY2VFcnJvcihcbiAgICAgICAgYHNwZW5kZXIgJHtzcGVuZGVyfSBoYXMgbm8gYWxsb3dhbmNlIGZyb20gJHtmcm9tfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgY3VycmVudEFsbG93YW5jZSA9IGFsbG93YW5jZS52YWx1ZTtcblxuICAgIC8vIENoZWNrIGlmIHRoZSB0cmFuc2ZlcnJlZCB2YWx1ZSBpcyBsZXNzIHRoYW4gdGhlIGFsbG93YW5jZVxuICAgIGlmIChjdXJyZW50QWxsb3dhbmNlIDwgdmFsdWUpIHtcbiAgICAgIHRocm93IG5ldyBCYWxhbmNlRXJyb3IoXG4gICAgICAgIFwiVGhlIHNwZW5kZXIgZG9lcyBub3QgaGF2ZSBlbm91Z2ggYWxsb3dhbmNlIHRvIHNwZW5kLlwiXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIERlY3JlYXNlIHRoZSBhbGxvd2FuY2VcbiAgICBjb25zdCB1cGRhdGVkQWxsb3dhbmNlID0gc3ViKGN1cnJlbnRBbGxvd2FuY2UsIHZhbHVlKTtcbiAgICBjb25zdCBuZXdBbGxvd2FuY2UgPSBPYmplY3QuYXNzaWduKHt9LCBhbGxvd2FuY2UsIHtcbiAgICAgIHZhbHVlOiB1cGRhdGVkQWxsb3dhbmNlLFxuICAgIH0pO1xuXG4gICAgYXdhaXQgdGhpcy5hbGxvd2FuY2VSZXBvc2l0b3J5LnVwZGF0ZShuZXdBbGxvd2FuY2UsIGN0eCk7XG5cbiAgICAvL1JlYWxpemUgdGhlIHRyYW5zZmVyXG4gICAgY29uc3QgdHJhbnNmZXJSZXNwID0gYXdhaXQgdGhpcy5fdHJhbnNmZXIoZnJvbSwgdG8sIHZhbHVlLCBjdHgpO1xuICAgIGlmICghdHJhbnNmZXJSZXNwKSB7XG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIkZhaWxlZCB0byB0cmFuc2ZlclwiKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGFzeW5jIF90cmFuc2ZlcihcbiAgICBmcm9tOiBzdHJpbmcsXG4gICAgdG86IHN0cmluZyxcbiAgICB2YWx1ZTogbnVtYmVyLFxuICAgIGN0eDogRmFicmljQ29udHJhY3RDb250ZXh0XG4gICkge1xuICAgIGNvbnN0IGxvZyA9IGN0eC5sb2dnZXI7XG5cbiAgICBpZiAoZnJvbSA9PT0gdG8pIHtcbiAgICAgIHRocm93IG5ldyBBdXRob3JpemF0aW9uRXJyb3IoXG4gICAgICAgIFwiY2Fubm90IHRyYW5zZmVyIHRvIGFuZCBmcm9tIHNhbWUgY2xpZW50IGFjY291bnRcIlxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAodmFsdWUgPCAwKSB7XG4gICAgICAvLyB0cmFuc2ZlciBvZiAwIGlzIGFsbG93ZWQgaW4gRVJDMjAsIHNvIGp1c3QgdmFsaWRhdGUgYWdhaW5zdCBuZWdhdGl2ZSBhbW91bnRzXG4gICAgICB0aHJvdyBuZXcgQmFsYW5jZUVycm9yKFwidHJhbnNmZXIgYW1vdW50IGNhbm5vdCBiZSBuZWdhdGl2ZVwiKTtcbiAgICB9XG5cbiAgICAvLyBSZXRyaWV2ZSB0aGUgY3VycmVudCBiYWxhbmNlIG9mIHRoZSBzZW5kZXJcblxuICAgIGNvbnN0IGZyb21XYWxsZXQgPSBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkucmVhZChmcm9tLCBjdHgpO1xuXG4gICAgY29uc3QgZnJvbUJhbGFuY2UgPSBmcm9tV2FsbGV0LmJhbGFuY2U7XG5cbiAgICAvLyBDaGVjayBpZiB0aGUgc2VuZGVyIGhhcyBlbm91Z2ggdG9rZW5zIHRvIHNwZW5kLlxuICAgIGlmIChmcm9tQmFsYW5jZSA8IHZhbHVlKSB7XG4gICAgICB0aHJvdyBuZXcgQmFsYW5jZUVycm9yKGBjbGllbnQgYWNjb3VudCAke2Zyb219IGhhcyBpbnN1ZmZpY2llbnQgZnVuZHMuYCk7XG4gICAgfVxuXG4gICAgLy8gUmV0cmlldmUgdGhlIGN1cnJlbnQgYmFsYW5jZSBvZiB0aGUgcmVjZXBpZW50XG5cbiAgICBsZXQgdG9XYWxsZXQ6IEVSQzIwV2FsbGV0O1xuICAgIGxldCBuZXdUb1dhbGxldDogYm9vbGVhbiA9IGZhbHNlO1xuICAgIHRyeSB7XG4gICAgICB0b1dhbGxldCA9IGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS5yZWFkKHRvLCBjdHgpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIGlmIChlIGluc3RhbmNlb2YgQmFzZUVycm9yKSB7XG4gICAgICAgIGlmIChlLmNvZGUgPT09IDQwNCkge1xuICAgICAgICAgIC8vIENyZWF0ZSBhIG5ldyB3YWxsZXQgZm9yIHRoZSBtaW50ZXJcbiAgICAgICAgICB0b1dhbGxldCA9IG5ldyBFUkMyMFdhbGxldCh7XG4gICAgICAgICAgICBpZDogdG8sXG4gICAgICAgICAgICBiYWxhbmNlOiAwLFxuICAgICAgICAgICAgdG9rZW46IGF3YWl0IHRoaXMuVG9rZW5OYW1lKGN0eCBhcyBhbnkpLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIG5ld1RvV2FsbGV0ID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihlLm1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihlIGFzIHN0cmluZyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgdG9CYWxhbmNlID0gdG9XYWxsZXQuYmFsYW5jZTtcblxuICAgIC8vIFVwZGF0ZSB0aGUgYmFsYW5jZVxuICAgIGNvbnN0IGZyb21VcGRhdGVkQmFsYW5jZSA9IHN1Yihmcm9tQmFsYW5jZSwgdmFsdWUpO1xuICAgIGNvbnN0IHRvVXBkYXRlZEJhbGFuY2UgPSBhZGQodG9CYWxhbmNlLCB2YWx1ZSk7XG5cbiAgICBjb25zdCB1cGRhdGVkRnJvbVdhbGxldCA9IE9iamVjdC5hc3NpZ24oe30sIGZyb21XYWxsZXQsIHtcbiAgICAgIGJhbGFuY2U6IGZyb21VcGRhdGVkQmFsYW5jZSxcbiAgICB9KTtcblxuICAgIGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS51cGRhdGUodXBkYXRlZEZyb21XYWxsZXQsIGN0eCk7XG5cbiAgICBjb25zdCB1cGRhdGVkVG9XYWxsZXQgPSBPYmplY3QuYXNzaWduKHt9LCB0b1dhbGxldCwge1xuICAgICAgYmFsYW5jZTogdG9VcGRhdGVkQmFsYW5jZSxcbiAgICB9KTtcblxuICAgIGlmIChuZXdUb1dhbGxldCkge1xuICAgICAgYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LmNyZWF0ZSh1cGRhdGVkVG9XYWxsZXQsIGN0eCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS51cGRhdGUodXBkYXRlZFRvV2FsbGV0LCBjdHgpO1xuICAgIH1cblxuICAgIC8vIEVtaXQgdGhlIFRyYW5zZmVyIGV2ZW50XG4gICAgY29uc3QgdHJhbnNmZXJFdmVudCA9IHsgZnJvbSwgdG8sIHZhbHVlOiB2YWx1ZSB9O1xuXG4gICAgdGhpcy5yZXBvXG4gICAgICAucmVmcmVzaChcbiAgICAgICAgRVJDMjBUb2tlbiBhcyBhbnksXG4gICAgICAgIEVSQzIwRXZlbnRzLlRSQU5TRkVSLFxuICAgICAgICBcIlwiLFxuICAgICAgICB0cmFuc2ZlckV2ZW50LFxuICAgICAgICBjdHggYXMgdW5rbm93biBhcyBGYWJyaWNDb250cmFjdENvbnRleHRcbiAgICAgIClcbiAgICAgIC5jYXRjaCgoZSkgPT4gbG9nLmVycm9yKGBGYWlsZWQgdG8gbm90aWZ5IHRyYW5zZmVyOiAke2V9YCkpO1xuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogQWxsb3dzIGBzcGVuZGVyYCB0byBzcGVuZCBgdmFsdWVgIGFtb3VudCBvZiB0b2tlbnMgZnJvbSB0aGUgb3duZXIuIE5ldyBBcHByb3ZlIGNhbGxzIG92ZXJyaWRlIHRoZSBwcmV2aW91cyBhbGxvd2FuY2UuXG4gICAqIEBub3RlIGh0dHBzOi8vZWlwcy5ldGhlcmV1bS5vcmcvRUlQUy9laXAtMjBcbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjdHggdGhlIHRyYW5zYWN0aW9uIGNvbnRleHRcbiAgICogQHBhcmFtIHtTdHJpbmd9IHNwZW5kZXIgVGhlIHNwZW5kZXJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIFRoZSBhbW91bnQgb2YgdG9rZW5zIHRvIGJlIGFwcHJvdmVkIGZvciB0cmFuc2ZlclxuICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gUmV0dXJuIHdoZXRoZXIgdGhlIGFwcHJvdmFsIHdhcyBzdWNjZXNzZnVsIG9yIG5vdFxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKClcbiAgYXN5bmMgQXBwcm92ZShcbiAgICBjb250ZXh0OiBDb250ZXh0LFxuICAgIHNwZW5kZXI6IHN0cmluZyxcbiAgICB2YWx1ZTogbnVtYmVyXG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgY3R4LCBjdHhBcmdzIH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuQXBwcm92ZSk7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQgZmlyc3QgdG8gZXhlY3V0ZSB0aGUgZnVuY3Rpb25cbiAgICBhd2FpdCB0aGlzLkNoZWNrSW5pdGlhbGl6ZWQoY3R4IGFzIGFueSk7XG5cbiAgICBjb25zdCBvd25lciA9IGN0eC5pZGVudGl0eS5nZXRJRCgpO1xuXG4gICAgbGV0IGFsbG93YW5jZSA9IGF3YWl0IHRoaXMuX2dldEFsbG93YW5jZShvd25lciwgc3BlbmRlciwgY3R4KTtcblxuICAgIGNvbnN0IG93bmVyV2FsbGV0ID0gYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnJlYWQob3duZXIsIC4uLmN0eEFyZ3MpO1xuXG4gICAgaWYgKG93bmVyV2FsbGV0LmJhbGFuY2UgPCB2YWx1ZSkge1xuICAgICAgdGhyb3cgbmV3IEJhbGFuY2VFcnJvcihgY2xpZW50IGFjY291bnQgJHtvd25lcn0gaGFzIGluc3VmZmljaWVudCBmdW5kcy5gKTtcbiAgICB9XG5cbiAgICBpZiAoYWxsb3dhbmNlKSB7XG4gICAgICAvLyBPdmVyd3JpdGUgdGhlIGFsbG93YW5jZVxuICAgICAgYWxsb3dhbmNlLnZhbHVlID0gdmFsdWU7XG4gICAgICBhd2FpdCB0aGlzLmFsbG93YW5jZVJlcG9zaXRvcnkudXBkYXRlKGFsbG93YW5jZSwgLi4uY3R4QXJncyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGFsbG93YW5jZSA9IG5ldyBBbGxvd2FuY2Uoe1xuICAgICAgICBvd25lcjogb3duZXIsXG4gICAgICAgIHNwZW5kZXI6IHNwZW5kZXIsXG4gICAgICAgIHZhbHVlOiB2YWx1ZSxcbiAgICAgIH0pO1xuXG4gICAgICBhd2FpdCB0aGlzLmFsbG93YW5jZVJlcG9zaXRvcnkuY3JlYXRlKGFsbG93YW5jZSwgLi4uY3R4QXJncyk7XG4gICAgfVxuXG4gICAgLy8gRW1pdCB0aGUgQXBwcm92YWwgZXZlbnRcbiAgICBjb25zdCBhcHByb3ZhbEV2ZW50ID0geyBvd25lciwgc3BlbmRlciwgdmFsdWU6IHZhbHVlIH07XG4gICAgdGhpcy5yZXBvLnJlZnJlc2goXG4gICAgICBFUkMyMFRva2VuIGFzIGFueSxcbiAgICAgIEVSQzIwRXZlbnRzLkFQUFJPVkFMLFxuICAgICAgXCJcIixcbiAgICAgIGFwcHJvdmFsRXZlbnQsXG4gICAgICBjdHggYXMgdW5rbm93biBhcyBGYWJyaWNDb250cmFjdENvbnRleHRcbiAgICApO1xuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgYW1vdW50IG9mIHRva2VucyB3aGljaCBgIGAgaXMgYWxsb3dlZCB0byB3aXRoZHJhdyBmcm9tIGBvd25lcmAuXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY3R4IHRoZSB0cmFuc2FjdGlvbiBjb250ZXh0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBvd25lciBUaGUgb3duZXIgb2YgdG9rZW5zXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzcGVuZGVyIFRoZSBzcGVuZGVyIHdobyBhcmUgYWJsZSB0byB0cmFuc2ZlciB0aGUgdG9rZW5zXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybiB0aGUgYW1vdW50IG9mIHJlbWFpbmluZyB0b2tlbnMgYWxsb3dlZCB0byBzcGVudFxuICAgKi9cbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBBbGxvd2FuY2UoXG4gICAgY29udGV4dDogQ29udGV4dCxcbiAgICBvd25lcjogc3RyaW5nLFxuICAgIHNwZW5kZXI6IHN0cmluZ1xuICApOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuQWxsb3dhbmNlKTtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHggYXMgYW55KTtcblxuICAgIGNvbnN0IGFsbG93YW5jZSA9IGF3YWl0IHRoaXMuX2dldEFsbG93YW5jZShvd25lciwgc3BlbmRlciwgY3R4KTtcblxuICAgIGlmICghYWxsb3dhbmNlKSB7XG4gICAgICB0aHJvdyBuZXcgQWxsb3dhbmNlRXJyb3IoXG4gICAgICAgIGBzcGVuZGVyICR7c3BlbmRlcn0gaGFzIG5vIGFsbG93YW5jZSBmcm9tICR7b3duZXJ9YFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIGFsbG93YW5jZS52YWx1ZTtcbiAgfVxuXG4gIGFzeW5jIF9nZXRBbGxvd2FuY2UoXG4gICAgb3duZXI6IHN0cmluZyxcbiAgICBzcGVuZGVyOiBzdHJpbmcsXG4gICAgY3R4OiBGYWJyaWNDb250cmFjdENvbnRleHRcbiAgKTogUHJvbWlzZTxBbGxvd2FuY2U+IHtcbiAgICBjb25zdCBhbGxvd2FuY2VDb25kaXRpb24gPSBDb25kaXRpb24uYW5kKFxuICAgICAgQ29uZGl0aW9uLmF0dHJpYnV0ZTxBbGxvd2FuY2U+KFwib3duZXJcIikuZXEob3duZXIpLFxuICAgICAgQ29uZGl0aW9uLmF0dHJpYnV0ZTxBbGxvd2FuY2U+KFwic3BlbmRlclwiKS5lcShzcGVuZGVyKVxuICAgICk7XG5cbiAgICBjb25zdCBhbGxvd2FuY2UgPSBhd2FpdCB0aGlzLmFsbG93YW5jZVJlcG9zaXRvcnlcbiAgICAgIC5zZWxlY3QoKVxuICAgICAgLndoZXJlKGFsbG93YW5jZUNvbmRpdGlvbilcbiAgICAgIC5leGVjdXRlKGN0eCk7XG4gICAgcmV0dXJuIGFsbG93YW5jZT8uWzBdO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09IEV4dGVuZGVkIEZ1bmN0aW9ucyA9PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBTZXQgb3B0aW9uYWwgaW5mb21hdGlvbiBmb3IgYSB0b2tlbi5cbiAgICpcbiAgICogQHBhcmFtIHtDb250ZXh0fSBjdHggdGhlIHRyYW5zYWN0aW9uIGNvbnRleHRcbiAgICogQHBhcmFtIHtTdHJpbmd9IG5hbWUgVGhlIG5hbWUgb2YgdGhlIHRva2VuXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzeW1ib2wgVGhlIHN5bWJvbCBvZiB0aGUgdG9rZW5cbiAgICogQHBhcmFtIHtTdHJpbmd9IGRlY2ltYWxzIFRoZSBkZWNpbWFscyBvZiB0aGUgdG9rZW5cbiAgICogQHBhcmFtIHtTdHJpbmd9IHRvdGFsU3VwcGx5IFRoZSB0b3RhbFN1cHBseSBvZiB0aGUgdG9rZW5cbiAgICovXG4gIEBUcmFuc2FjdGlvbigpXG4gIGFzeW5jIEluaXRpYWxpemUoY29udGV4dDogQ29udGV4dCwgdG9rZW46IEVSQzIwVG9rZW4pIHtcbiAgICBjb25zdCB7IGN0eCB9ID0gYXdhaXQgdGhpcy5sb2dDdHgoW2NvbnRleHRdLCB0aGlzLkluaXRpYWxpemUpO1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIG5vdCBhbHJlYWR5IHNldCwgY2xpZW50IGlzIG5vdCBhdXRob3JpemVkIHRvIGNoYW5nZSB0aGVtIG9uY2UgaW50aXRpYWxpemVkXG4gICAgY29uc3QgdG9rZW5zID0gYXdhaXQgdGhpcy50b2tlblJlcG9zaXRvcnkuc2VsZWN0KCkuZXhlY3V0ZShjdHgpO1xuICAgIGlmICh0b2tlbnMubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IEF1dGhvcml6YXRpb25FcnJvcihcbiAgICAgICAgXCJjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCwgY2xpZW50IGlzIG5vdCBhdXRob3JpemVkIHRvIGNoYW5nZSB0aGVtXCJcbiAgICAgICk7XG4gICAgfVxuXG4gICAgdG9rZW4ub3duZXIgPSBjdHguaWRlbnRpdHkuZ2V0SUQoKTtcblxuICAgIGF3YWl0IHRoaXMudG9rZW5SZXBvc2l0b3J5LmNyZWF0ZSh0b2tlbiwgY3R4KTtcblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLy8gQ2hlY2tzIHRoYXQgY29udHJhY3Qgb3B0aW9ucyBoYXZlIGJlZW4gYWxyZWFkeSBpbml0aWFsaXplZFxuICBAVHJhbnNhY3Rpb24oZmFsc2UpXG4gIGFzeW5jIENoZWNrSW5pdGlhbGl6ZWQoY29udGV4dDogQ29udGV4dCkge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuQ2hlY2tJbml0aWFsaXplZCk7XG4gICAgY29uc3QgdG9rZW5zID0gYXdhaXQgdGhpcy50b2tlblJlcG9zaXRvcnkuc2VsZWN0KCkuZXhlY3V0ZShjdHgpO1xuICAgIGlmICh0b2tlbnMubGVuZ3RoID09IDApIHtcbiAgICAgIHRocm93IG5ldyBOb3RJbml0aWFsaXplZEVycm9yKFxuICAgICAgICBcImNvbnRyYWN0IG9wdGlvbnMgbmVlZCB0byBiZSBzZXQgYmVmb3JlIGNhbGxpbmcgYW55IGZ1bmN0aW9uLCBjYWxsIEluaXRpYWxpemUoKSB0byBpbml0aWFsaXplIGNvbnRyYWN0XCJcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE1pbnQgY3JlYXRlcyBuZXcgdG9rZW5zIGFuZCBhZGRzIHRoZW0gdG8gbWludGVyJ3MgYWNjb3VudCBiYWxhbmNlXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY29udGV4dCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge251bWJlcn0gYW1vdW50IGFtb3VudCBvZiB0b2tlbnMgdG8gYmUgbWludGVkXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBiYWxhbmNlXG4gICAqL1xuICBAT3duZXIoKVxuICBAVHJhbnNhY3Rpb24oKVxuICBhc3luYyBNaW50KGNvbnRleHQ6IENvbnRleHQsIGFtb3VudDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5NaW50KTtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHggYXMgYW55KTtcblxuICAgIC8vIEdldCBJRCBvZiBzdWJtaXR0aW5nIGNsaWVudCBpZGVudGl0eVxuICAgIGNvbnN0IG1pbnRlciA9IGN0eC5pZGVudGl0eS5nZXRJRCgpO1xuXG4gICAgaWYgKGFtb3VudCA8PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKFwibWludCBhbW91bnQgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXJcIik7XG4gICAgfVxuXG4gICAgbGV0IG1pbnRlcldhbGxldDogRVJDMjBXYWxsZXQ7XG4gICAgdHJ5IHtcbiAgICAgIG1pbnRlcldhbGxldCA9IGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS5yZWFkKG1pbnRlciwgY3R4KTtcblxuICAgICAgY29uc3QgY3VycmVudEJhbGFuY2UgPSBtaW50ZXJXYWxsZXQuYmFsYW5jZTtcblxuICAgICAgY29uc3QgdXBkYXRlZEJhbGFuY2UgPSBhZGQoY3VycmVudEJhbGFuY2UsIGFtb3VudCk7XG5cbiAgICAgIGNvbnN0IHVwZGF0ZWRtaW50ZXIgPSBPYmplY3QuYXNzaWduKHt9LCBtaW50ZXJXYWxsZXQsIHtcbiAgICAgICAgYmFsYW5jZTogdXBkYXRlZEJhbGFuY2UsXG4gICAgICB9KTtcblxuICAgICAgYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnVwZGF0ZSh1cGRhdGVkbWludGVyLCBjdHgpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIGlmIChlIGluc3RhbmNlb2YgQmFzZUVycm9yKSB7XG4gICAgICAgIGlmIChlLmNvZGUgPT09IDQwNCkge1xuICAgICAgICAgIC8vIENyZWF0ZSBhIG5ldyB3YWxsZXQgZm9yIHRoZSBtaW50ZXJcbiAgICAgICAgICBjb25zdCBuZXdXYWxsZXQgPSBuZXcgRVJDMjBXYWxsZXQoe1xuICAgICAgICAgICAgaWQ6IG1pbnRlcixcbiAgICAgICAgICAgIGJhbGFuY2U6IGFtb3VudCxcbiAgICAgICAgICAgIHRva2VuOiBhd2FpdCB0aGlzLlRva2VuTmFtZShjb250ZXh0KSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkuY3JlYXRlKG5ld1dhbGxldCwgY3R4KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihlLm1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihlIGFzIHN0cmluZyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gRW1pdCB0aGUgVHJhbnNmZXIgZXZlbnRcbiAgICBjb25zdCB0cmFuc2ZlckV2ZW50ID0geyBmcm9tOiBcIjB4MFwiLCB0bzogbWludGVyLCB2YWx1ZTogYW1vdW50IH07XG4gICAgY29uc3QgZXZlbnRIYW5kbGVyID1cbiAgICAgIHRoaXMucmVwby5PYnNlcnZlckhhbmRsZXIoKSBhcyBGYWJyaWNDb250cmFjdFJlcG9zaXRvcnlPYnNlcnZhYmxlSGFuZGxlcjtcbiAgICBldmVudEhhbmRsZXIudXBkYXRlT2JzZXJ2ZXJzKFxuICAgICAgRVJDMjBUb2tlbixcbiAgICAgIEVSQzIwRXZlbnRzLlRSQU5TRkVSLFxuICAgICAgXCJcIixcbiAgICAgIHRyYW5zZmVyRXZlbnQsXG4gICAgICBjdHggYXMgdW5rbm93biBhcyBGYWJyaWNDb250cmFjdENvbnRleHRcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1cm4gcmVkZWVtIHRva2VucyBmcm9tIG1pbnRlcidzIGFjY291bnQgYmFsYW5jZVxuICAgKlxuICAgKiBAcGFyYW0ge0NvbnRleHR9IGNvbnRleHQgdGhlIHRyYW5zYWN0aW9uIGNvbnRleHRcbiAgICogQHBhcmFtIHtudW1iZXJ9IGFtb3VudCBhbW91bnQgb2YgdG9rZW5zIHRvIGJlIGJ1cm5lZFxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgYmFsYW5jZVxuICAgKi9cbiAgQE93bmVyKClcbiAgQFRyYW5zYWN0aW9uKClcbiAgYXN5bmMgQnVybihjb250ZXh0OiBDb250ZXh0LCBhbW91bnQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5CdXJuKTtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHggYXMgYW55KTtcblxuICAgIGNvbnN0IG1pbnRlciA9IGN0eC5pZGVudGl0eS5nZXRJRCgpO1xuXG4gICAgY29uc3QgbWludGVyV2FsbGV0ID0gYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnJlYWQobWludGVyLCBjdHgpO1xuXG4gICAgY29uc3QgY3VycmVudEJhbGFuY2UgPSBtaW50ZXJXYWxsZXQuYmFsYW5jZTtcblxuICAgIGlmIChjdXJyZW50QmFsYW5jZSA8IGFtb3VudCkge1xuICAgICAgdGhyb3cgbmV3IEJhbGFuY2VFcnJvcihgTWludGVyIGhhcyBpbnN1ZmZpY2llbnQgZnVuZHMuYCk7XG4gICAgfVxuXG4gICAgY29uc3QgdXBkYXRlZEJhbGFuY2UgPSBzdWIoY3VycmVudEJhbGFuY2UsIGFtb3VudCk7XG5cbiAgICBjb25zdCB1cGRhdGVkbWludGVyID0gT2JqZWN0LmFzc2lnbih7fSwgbWludGVyV2FsbGV0LCB7XG4gICAgICBiYWxhbmNlOiB1cGRhdGVkQmFsYW5jZSxcbiAgICB9KTtcblxuICAgIGF3YWl0IHRoaXMud2FsbGV0UmVwb3NpdG9yeS51cGRhdGUodXBkYXRlZG1pbnRlciwgY3R4KTtcblxuICAgIGxvZy5pbmZvKGAke2Ftb3VudH0gdG9rZW5zIHdlcmUgYnVybmVkYCk7XG5cbiAgICAvLyBFbWl0IHRoZSBUcmFuc2ZlciBldmVudFxuICAgIGNvbnN0IHRyYW5zZmVyRXZlbnQgPSB7IGZyb206IG1pbnRlciwgdG86IFwiMHgwXCIsIHZhbHVlOiBhbW91bnQgfTtcbiAgICBjb25zdCBldmVudEhhbmRsZXIgPVxuICAgICAgdGhpcy5yZXBvLk9ic2VydmVySGFuZGxlcigpIGFzIEZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeU9ic2VydmFibGVIYW5kbGVyO1xuICAgIGV2ZW50SGFuZGxlci51cGRhdGVPYnNlcnZlcnMoXG4gICAgICBFUkMyMFRva2VuLFxuICAgICAgRVJDMjBFdmVudHMuVFJBTlNGRVIsXG4gICAgICBcIlwiLFxuICAgICAgdHJhbnNmZXJFdmVudCxcbiAgICAgIGN0eCBhcyB1bmtub3duIGFzIEZhYnJpY0NvbnRyYWN0Q29udGV4dFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQnVybkZyb20gcmVkZWVtIHRva2VucyBmcm9tIGFjY291bnQgYWxsb3dlbmNlIGFuZCBiYWxhbmNlXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY29udGV4dCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcGFyYW0ge251bWJlcn0gYWNjb3VudCBhY2NvdW50IGZyb20gd2hlcmUgdG9rZW5zIHdpbGwgYmUgYnVybmVkXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBhbW91bnQgYW1vdW50IG9mIHRva2VucyB0byBiZSBidXJuZWRcbiAgICogQHJldHVybnMge09iamVjdH0gVGhlIGJhbGFuY2VcbiAgICovXG4gIEBPd25lcigpXG4gIEBUcmFuc2FjdGlvbigpXG4gIGFzeW5jIEJ1cm5Gcm9tKFxuICAgIGNvbnRleHQ6IENvbnRleHQsXG4gICAgYWNjb3VudDogc3RyaW5nLFxuICAgIGFtb3VudDogbnVtYmVyXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgbG9nLCBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5CdXJuRnJvbSk7XG4gICAgLy8gQ2hlY2sgY29udHJhY3Qgb3B0aW9ucyBhcmUgYWxyZWFkeSBzZXQgZmlyc3QgdG8gZXhlY3V0ZSB0aGUgZnVuY3Rpb25cbiAgICBhd2FpdCB0aGlzLkNoZWNrSW5pdGlhbGl6ZWQoY3R4IGFzIGFueSk7XG5cbiAgICBjb25zdCBhY2NvdW50V2FsbGV0ID0gYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnJlYWQoYWNjb3VudCwgY3R4KTtcblxuICAgIGNvbnN0IGN1cnJlbnRCYWxhbmNlID0gYWNjb3VudFdhbGxldC5iYWxhbmNlO1xuXG4gICAgaWYgKGN1cnJlbnRCYWxhbmNlIDwgYW1vdW50KSB7XG4gICAgICB0aHJvdyBuZXcgQmFsYW5jZUVycm9yKGAke2FjY291bnR9IGhhcyBpbnN1ZmZpY2llbnQgZnVuZHMuYCk7XG4gICAgfVxuXG4gICAgY29uc3QgdXBkYXRlZEJhbGFuY2UgPSBzdWIoY3VycmVudEJhbGFuY2UsIGFtb3VudCk7XG5cbiAgICBjb25zdCB1cGRhdGVkYWNjb3VudCA9IE9iamVjdC5hc3NpZ24oe30sIGFjY291bnRXYWxsZXQsIHtcbiAgICAgIGJhbGFuY2U6IHVwZGF0ZWRCYWxhbmNlLFxuICAgIH0pO1xuXG4gICAgYXdhaXQgdGhpcy53YWxsZXRSZXBvc2l0b3J5LnVwZGF0ZSh1cGRhdGVkYWNjb3VudCwgY3R4KTtcblxuICAgIGxvZy5pbmZvKGAke2Ftb3VudH0gdG9rZW5zIHdlcmUgYnVybmVkIGZyb20gJHthY2NvdW50fWApO1xuXG4gICAgLy8gRW1pdCB0aGUgVHJhbnNmZXIgZXZlbnRcbiAgICBjb25zdCB0cmFuc2ZlckV2ZW50ID0geyBmcm9tOiBhY2NvdW50LCB0bzogXCIweDBcIiwgdmFsdWU6IGFtb3VudCB9O1xuICAgIGNvbnN0IGV2ZW50SGFuZGxlciA9XG4gICAgICB0aGlzLnJlcG8uT2JzZXJ2ZXJIYW5kbGVyKCkgYXMgRmFicmljQ29udHJhY3RSZXBvc2l0b3J5T2JzZXJ2YWJsZUhhbmRsZXI7XG4gICAgZXZlbnRIYW5kbGVyLnVwZGF0ZU9ic2VydmVycyhcbiAgICAgIEVSQzIwVG9rZW4sXG4gICAgICBFUkMyMEV2ZW50cy5UUkFOU0ZFUixcbiAgICAgIFwiXCIsXG4gICAgICB0cmFuc2ZlckV2ZW50LFxuICAgICAgY3R4IGFzIHVua25vd24gYXMgRmFicmljQ29udHJhY3RDb250ZXh0XG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbGllbnRBY2NvdW50QmFsYW5jZSByZXR1cm5zIHRoZSBiYWxhbmNlIG9mIHRoZSByZXF1ZXN0aW5nIGNsaWVudCdzIGFjY291bnQuXG4gICAqXG4gICAqIEBwYXJhbSB7Q29udGV4dH0gY29udGV4dCB0aGUgdHJhbnNhY3Rpb24gY29udGV4dFxuICAgKiBAcmV0dXJucyB7TnVtYmVyfSBSZXR1cm5zIHRoZSBhY2NvdW50IGJhbGFuY2VcbiAgICovXG4gIEBUcmFuc2FjdGlvbihmYWxzZSlcbiAgYXN5bmMgQ2xpZW50QWNjb3VudEJhbGFuY2UoY29udGV4dDogQ29udGV4dCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgY29uc3QgeyBjdHggfSA9IGF3YWl0IHRoaXMubG9nQ3R4KFtjb250ZXh0XSwgdGhpcy5Ub2tlbk5hbWUpO1xuICAgIC8vIENoZWNrIGNvbnRyYWN0IG9wdGlvbnMgYXJlIGFscmVhZHkgc2V0IGZpcnN0IHRvIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uXG4gICAgYXdhaXQgdGhpcy5DaGVja0luaXRpYWxpemVkKGN0eCBhcyBhbnkpO1xuXG4gICAgLy8gR2V0IElEIG9mIHN1Ym1pdHRpbmcgY2xpZW50IGlkZW50aXR5XG4gICAgY29uc3QgY2xpZW50QWNjb3VudElEID0gY3R4LmlkZW50aXR5LmdldElEKCk7XG5cbiAgICBjb25zdCBjbGllbnRXYWxsZXQgPSBhd2FpdCB0aGlzLndhbGxldFJlcG9zaXRvcnkucmVhZChjbGllbnRBY2NvdW50SUQsIGN0eCk7XG5cbiAgICBpZiAoIWNsaWVudFdhbGxldCkge1xuICAgICAgdGhyb3cgbmV3IEJhbGFuY2VFcnJvcihgVGhlIGFjY291bnQgJHtjbGllbnRBY2NvdW50SUR9IGRvZXMgbm90IGV4aXN0YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNsaWVudFdhbGxldC5iYWxhbmNlO1xuICB9XG5cbiAgLy8gQ2xpZW50QWNjb3VudElEIHJldHVybnMgdGhlIGlkIG9mIHRoZSByZXF1ZXN0aW5nIGNsaWVudCdzIGFjY291bnQuXG4gIC8vIEluIHRoaXMgaW1wbGVtZW50YXRpb24sIHRoZSBjbGllbnQgYWNjb3VudCBJRCBpcyB0aGUgY2xpZW50SWQgaXRzZWxmLlxuICAvLyBVc2VycyBjYW4gdXNlIHRoaXMgZnVuY3Rpb24gdG8gZ2V0IHRoZWlyIG93biBhY2NvdW50IGlkLCB3aGljaCB0aGV5IGNhbiB0aGVuIGdpdmUgdG8gb3RoZXJzIGFzIHRoZSBwYXltZW50IGFkZHJlc3NcbiAgQFRyYW5zYWN0aW9uKGZhbHNlKVxuICBhc3luYyBDbGllbnRBY2NvdW50SUQoY29udGV4dDogQ29udGV4dCkge1xuICAgIGNvbnN0IHsgY3R4IH0gPSBhd2FpdCB0aGlzLmxvZ0N0eChbY29udGV4dF0sIHRoaXMuQ2xpZW50QWNjb3VudElEKTtcbiAgICAvLyBDaGVjayBjb250cmFjdCBvcHRpb25zIGFyZSBhbHJlYWR5IHNldCBmaXJzdCB0byBleGVjdXRlIHRoZSBmdW5jdGlvblxuICAgIGF3YWl0IHRoaXMuQ2hlY2tJbml0aWFsaXplZChjdHggYXMgYW55KTtcblxuICAgIC8vIEdldCBJRCBvZiBzdWJtaXR0aW5nIGNsaWVudCBpZGVudGl0eVxuICAgIGNvbnN0IGNsaWVudEFjY291bnRJRCA9IGN0eC5pZGVudGl0eS5nZXRJRCgpO1xuICAgIHJldHVybiBjbGllbnRBY2NvdW50SUQ7XG4gIH1cbn1cbiIsImltcG9ydCB7IEZhYnJpY0VSQzIwQ29udHJhY3QgfSBmcm9tIFwiLi9lcmMyMGNvbnRyYWN0XCI7XG5cbmV4cG9ydCAqIGZyb20gXCIuLi9GYWJyaWNDb250cmFjdFN0YXRlbWVudFwiO1xuXG5leHBvcnQgY29uc3QgY29udHJhY3RzOiBhbnlbXSA9IFtGYWJyaWNFUkMyMENvbnRyYWN0XTtcbiIsImltcG9ydCB7IE1ldGFkYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gXCIjI1ZFUlNJT04jI1wiO1xuZXhwb3J0IGNvbnN0IFBBQ0tBR0VfTkFNRSA9IFwiIyNQQUNLQUdFIyNcIjtcblxuTWV0YWRhdGEucmVnaXN0ZXJMaWJyYXJ5KFBBQ0tBR0VfTkFNRSwgVkVSU0lPTik7XG4iXSwibmFtZXMiOlsiRmFicmljQ29udHJhY3RDb250ZXh0IiwiQ29udGV4dCIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJzdHViIiwidGhpcyIsImdldCIsInRpbWVzdGFtcCIsImdldERhdGVUaW1lc3RhbXAiLCJpZGVudGl0eSIsInRvU3RyaW5nIiwiZ2VuZXJhdGVGYWJyaWNFdmVudE5hbWUiLCJ0YWJsZSIsImV2ZW50Iiwib3duZXIiLCJwYXJhbXMiLCJwdXNoIiwiam9pbiIsInBhcnNlRXZlbnROYW1lIiwibmFtZSIsInBhcnRzIiwic3BsaXQiLCJsZW5ndGgiLCJ1bmRlZmluZWQiLCJGYWJyaWNDb250cmFjdFJlcG9zaXRvcnlPYnNlcnZhYmxlSGFuZGxlciIsIk9ic2VydmVySGFuZGxlciIsInN1cHBvcnRlZEV2ZW50cyIsIk9wZXJhdGlvbktleXMiLCJDUkVBVEUiLCJVUERBVEUiLCJERUxFVEUiLCJCdWxrQ3J1ZE9wZXJhdGlvbktleXMiLCJDUkVBVEVfQUxMIiwiVVBEQVRFX0FMTCIsIkRFTEVURV9BTEwiLCJ1cGRhdGVPYnNlcnZlcnMiLCJjbGF6eiIsImlkIiwiYXJncyIsImxvZyIsImN0eCIsIkFkYXB0ZXIiLCJsb2dDdHgiLCJwYXlsb2FkIiwiaW5kZXhPZiIsImRlYnVnIiwiZXZlbnROYW1lIiwic2V0RXZlbnQiLCJCdWZmZXIiLCJmcm9tIiwiSlNPTiIsInN0cmluZ2lmeSIsIkZhYnJpY0NvbnRyYWN0UmVwb3NpdG9yeSIsIlJlcG9zaXRvcnkiLCJhZGFwdGVyIiwidHJhY2tlZEV2ZW50cyIsIl9vdmVycmlkZXMiLCJPYmplY3QiLCJhc3NpZ24iLCJpZ25vcmVWYWxpZGF0aW9uIiwiaWdub3JlSGFuZGxlcnMiLCJhbGxvd1Jhd1N0YXRlbWVudHMiLCJmb3JjZVByZXBhcmVTaW1wbGVRdWVyaWVzIiwiZm9yY2VQcmVwYXJlQ29tcGxleFF1ZXJpZXMiLCJwYWdpbmF0ZUJ5Iiwia2V5Iiwib3JkZXIiLCJyZWYiLCJvZmZzZXQiLCJsaW1pdCIsImJvb2ttYXJrIiwiUXVlcnlFcnJvciIsImNvbnRleHRBcmdzIiwiUHJlcGFyZWRTdGF0ZW1lbnRLZXlzIiwiUEFHRV9CWSIsImNsYXNzIiwiY3R4QXJncyIsInZlcmJvc2UiLCJNb2RlbCIsInRhYmxlTmFtZSIsInBhZ2luYXRvciIsIm92ZXJyaWRlIiwic2VsZWN0Iiwid2hlcmUiLCJhdHRyIiwicGsiLCJndCIsIm9yZGVyQnkiLCJwYWdpbmF0ZSIsInBhZ2VkIiwicGFnZSIsInNlcmlhbGl6ZSIsInN0YXRlbWVudCIsInN0YXRlbWVudHMiLCJQZXJzaXN0ZW5jZUtleXMiLCJTVEFURU1FTlQiLCJjb250ZXh0IiwibG9nZ2VyIiwiaW5mbyIsInJlc3VsdCIsImUiLCJCYXNlRXJyb3IiLCJJbnRlcm5hbEVycm9yIiwiRmFicmljU3RhdGVtZW50IiwiQ291Y2hEQlN0YXRlbWVudCIsInJhdyIsInJhd0lucHV0IiwicmVzdWx0cyIsInBrQXR0ciIsImZyb21TZWxlY3RvciIsInR5cGUiLCJNZXRhZGF0YSIsIkRCS2V5cyIsIklEIiwic2VsZWN0U2VsZWN0b3IiLCJtYXAiLCJyIiwicHJvY2Vzc1JlY29yZCIsImJ1aWxkIiwic2VsZWN0b3JzIiwiQ291Y2hEQktleXMiLCJUQUJMRSIsInF1ZXJ5Iiwic2VsZWN0b3IiLCJmaWVsZHMiLCJ3aGVyZUNvbmRpdGlvbiIsImNvbmRpdGlvbiIsInBhcnNlQ29uZGl0aW9uIiwiQ29uZGl0aW9uIiwiYW5kIiwiYXR0cmlidXRlIiwiZXEiLCJzZWxlY3RvcktleXMiLCJrZXlzIiwidmFsdWVzIiwiQ291Y2hEQkdyb3VwT3BlcmF0b3IiLCJBTkQiLCJyZWR1Y2UiLCJhY2N1bSIsInZhbCIsIkVycm9yIiwiayIsIk9SIiwicyIsImVudHJpZXMiLCJmb3JFYWNoIiwiY29uc29sZSIsIndhcm4iLCJvcmRlckJ5U2VsZWN0b3IiLCJzb3J0IiwidmFsdWUiLCJyZWMiLCJDb3VjaERCT3BlcmF0b3IiLCJCSUdHRVIiLCJsaW1pdFNlbGVjdG9yIiwib2Zmc2V0U2VsZWN0b3IiLCJza2lwIiwiRmFicmljQ29udHJhY3RTZXF1ZW5jZSIsIlNlcXVlbmNlIiwib3B0aW9ucyIsImN1cnJlbnQiLCJSRUFEIiwiU2VxdWVuY2VNb2RlbCIsInN0YXJ0V2l0aCIsInNlcXVlbmNlIiwicmVwbyIsInJlYWQiLCJwYXJzZSIsImZvciIsIk5vdEZvdW5kRXJyb3IiLCJjYWNoZWRDdXJyZW50IiwiaW5jcmVtZW50IiwiY291bnQiLCJpbmNyZW1lbnRCeSIsImxvY2siLCJleGVjdXRlIiwiYXN5bmMiLCJ0b0luY3JlbWVudEJ5IiwidHlwZU5hbWUiLCJjdXJyZW50VmFsdWUiLCJyZXR1cm5BbmRDYWNoZSIsInJlcyIsIlByb21pc2UiLCJjYWNoZSIsInB1dCIsInBlcmZvcm1VcHNlcnQiLCJuZXh0IiwidXBkYXRlIiwiY3JlYXRlIiwiaW5jcmVtZW50U2VyaWFsIiwiYmFzZSIsIk51bWJlciIsIkJpZ0ludCIsIlN0cmluZyIsIlNlcmlhbCIsImluc3RhbmNlIiwiZ2VuZXJhdGUiLCJVVUlEIiwiQ29uZmxpY3RFcnJvciIsInNlcSIsIkZhYnJpY01vZGVsS2V5cyIsIklkZW50aXR5VHlwZSIsIkZhYnJpY0ZsYXZvdXIiLCJTaW1wbGVEZXRlcm1pbmlzdGljU2VyaWFsaXplciIsIkpTT05TZXJpYWxpemVyIiwiZGVzZXJpYWxpemUiLCJzdHIiLCJkZXNlcmlhbGl6YXRpb24iLCJtb2RlbCIsInB1dEFuY2hvciIsInJlcXVpcmUiLCJzb3J0S2V5c1JlY3Vyc2l2ZSIsInByZVNlcmlhbGl6YXRpb24iLCJwcmVTZXJpYWxpemUiLCJ0b1NlcmlhbGl6ZSIsIm1ldGFkYXRhIiwibW9kZWxOYW1lIiwiZXJyb3IiLCJNb2RlbEtleXMiLCJBTkNIT1IiLCJvYmoiLCJBcnJheSIsImlzQXJyYXkiLCJyZWxhdGlvbnMiLCJjYWxsIiwiQ29udHJhY3RMb2dnZXIiLCJNaW5pTG9nZ2VyIiwiY29uZiIsImxvZ2dpbmciLCJnZXRMb2dnZXIiLCJsZXZlbCIsIm1zZyIsInN0YWNrIiwiTnVtZXJpY0xvZ0xldmVscyIsImNvbmZpZyIsIm1ldGhvZCIsIkxvZ0xldmVsIiwic2lsbHkiLCJjcmVhdGVMb2ciLCJmYWN0b3J5Iiwib2JqZWN0IiwiTG9nZ2luZyIsInNldEZhY3RvcnkiLCJGYWJyaWNDb250cmFjdFBhZ2luYXRvciIsIkNvdWNoREJQYWdpbmF0b3IiLCJzaXplIiwicHJlcGFyZSIsInJhd1N0YXRlbWVudCIsImlzUHJlcGFyZWRTdGF0ZW1lbnQiLCJwYWdlUHJlcGFyZWQiLCJfcmVjb3JkQ291bnQiLCJfdG90YWxQYWdlcyIsIk1hdGgiLCJjZWlsIiwidmFsaWRhdGVQYWdlIiwiX2Jvb2ttYXJrIiwiUGFnaW5nRXJyb3IiLCJkb2NzIiwiZCIsInJldmVydCIsInBhcnNlVmFsdWUiLCJkaXJlY3Rpb24iLCJPcmRlckRpcmVjdGlvbiIsIkRTQyIsIkFTQyIsIl9jdXJyZW50UGFnZSIsIk92ZXJmbG93RXJyb3IiLCJCYWxhbmNlRXJyb3IiLCJBbGxvd2FuY2VFcnJvciIsIlJlZ2lzdHJhdGlvbkVycm9yIiwiQXV0aG9yaXphdGlvbkVycm9yIiwiTWlzc2luZ0NvbnRleHRFcnJvciIsIlVuYXV0aG9yaXplZFByaXZhdGVEYXRhQWNjZXNzIiwiTm90SW5pdGlhbGl6ZWRFcnJvciIsIk1pc3NpbmdQS0NTUzExTGliIiwiRW5kb3JzZW1lbnRFcnJvciIsIm1lc3NhZ2UiLCJNdmNjUmVhZENvbmZsaWN0RXJyb3IiLCJQaGFudG9tUmVhZENvbmZsaWN0RXJyb3IiLCJFbmRvcnNlbWVudFBvbGljeUVycm9yIiwiY3JlYXRlZEJ5T25GYWJyaWNDcmVhdGVVcGRhdGUiLCJkYXRhIiwidXNlciIsImdldElEIiwiVW5zdXBwb3J0ZWRFcnJvciIsInBrRmFicmljT25DcmVhdGUiLCJzZXRQcmltYXJ5S2V5VmFsdWUiLCJ0YXJnZXQiLCJwcm9wZXJ0eUtleSIsImRlZmluZVByb3BlcnR5IiwiZW51bWVyYWJsZSIsIndyaXRhYmxlIiwiY29uZmlndXJhYmxlIiwic2VxdWVuY2VOYW1lIiwiRmFicmljQ29udHJhY3RBZGFwdGVyIiwiQ291Y2hEQkFkYXB0ZXIiLCJnZXRDbGllbnQiLCJ0ZXh0RGVjb2RlciIsIlRleHREZWNvZGVyIiwic2VyaWFsaXplciIsInJlcG9zaXRvcnkiLCJQYWdpbmF0b3IiLCJzY29wZSIsImFsaWFzIiwiY29tcG9zZWRLZXkiLCJjcmVhdGVDb21wb3NpdGVLZXkiLCJwdXRTdGF0ZSIsInBhcnNlRXJyb3IiLCJyZWFkU3RhdGUiLCJkZWxldGUiLCJkZWxldGVTdGF0ZSIsImZvclByaXZhdGUiLCJjb2xsZWN0aW9uIiwidG9PdmVycmlkZSIsInF1ZXJ5UmVzdWx0IiwicXVlcnlSZXN1bHRQYWdpbmF0ZWQiLCJmbiIsIlByb3h5IiwicHJvcCIsInJlY2VpdmVyIiwiaW5jbHVkZXMiLCJSZWZsZWN0IiwiYXBwbHkiLCJ0aGlzQXJnIiwiYXJnc0xpc3QiLCJwdXRQcml2YXRlRGF0YSIsImRlbGV0ZVByaXZhdGVEYXRhIiwiZ2V0UHJpdmF0ZURhdGEiLCJnZXRQcml2YXRlRGF0YVF1ZXJ5UmVzdWx0IiwiaXRlcmF0b3IiLCJyZWFjaGVkQm9va21hcmsiLCJsYXN0S2V5IiwicmVjb3JkS2V5IiwicmVjb3JkVmFsdWUiLCJLZXkiLCJSZWNvcmQiLCJjbG9zZSIsImZldGNoZWRSZWNvcmRzQ291bnQiLCJkb25lIiwiU2VyaWFsaXphdGlvbkVycm9yIiwiZ2V0U3RhdGUiLCJnZXRRdWVyeVJlc3VsdCIsIl9pZCIsIiRndCIsIiRndGUiLCJpdCIsImdldFF1ZXJ5UmVzdWx0V2l0aFBhZ2luYXRpb24iLCJtZXJnZU1vZGVscyIsImV4dHJhY3QiLCJmaW5hbE1vZGVsIiwicG9wIiwiZGVjb2RlIiwiYnVmZmVyIiwiZmxhZ3MiLCJvcGVyYXRpb24iLCJiYXNlRmxhZ3MiLCJzZWdyZWdhdGVkIiwiY29ycmVsYXRpb25JZCIsImdldFR4SUQiLCJjbGllbnRJZGVudGl0eSIsImluZGV4IiwibW9kZWxzIiwicmVzb2x2ZSIsInJlc3VsdEl0ZXJhdG9yIiwiaXNIaXN0b3J5IiwiYWxsUmVzdWx0cyIsImpzb25SZXMiLCJUeElkIiwidHhJZCIsIlRpbWVzdGFtcCIsIlZhbHVlIiwiZXJyIiwiZG9jc09ubHkiLCJyZXNwb25zZSIsIlN0YXRlbWVudCIsImNyZWF0ZUFsbCIsInRhYmxlTGFiZWwiLCJhbGwiLCJpIiwidXBkYXRlQWxsIiwic2VncmVnYXRlIiwibWFwcGVkUHJvcCIsImNvbHVtbk5hbWUiLCJpc1Jlc2VydmVkIiwicmVjb3JkIiwidHJhbnNpZW50Iiwib2IiLCJtIiwiY3JlYXRlUHJlZml4IiwidXBkYXRlUHJlZml4IiwiY3JlYXRlQWxsUHJlZml4IiwiaWRzIiwicmVjb3JkcyIsInVwZGF0ZUFsbFByZWZpeCIsInJlYXNvbiIsImZpbHRlciIsImEiLCJjbGVhciIsIkJhZFJlcXVlc3RFcnJvciIsIk1pZ3JhdGlvbkVycm9yIiwiT2JzZXJ2ZXJFcnJvciIsIkZvcmJpZGRlbkVycm9yIiwiQ29ubmVjdGlvbkVycm9yIiwiZGVjb3JhdGlvbiIsIkRlY29yYXRpb24iLCJmbGF2b3VyZWRBcyIsIkNSRUFURURfQlkiLCJkZWZpbmUiLCJvbkNyZWF0ZSIsInByb3BNZXRhZGF0YSIsIlVQREFURURfQlkiLCJvbkNyZWF0ZVVwZGF0ZSIsIkNPTFVNTiIsImV4dGVuZCIsIkZhYnJpY1Byb3BlcnR5IiwiUHJvcGVydHkiLCJWYWxpZGF0aW9uS2V5cyIsIkRBVEUiLCJmYWJyaWNQcm9wZXJ0eSIsImNoYWluIiwiY29uc3RyIiwicHJvdG90eXBlIiwiZ2V0UHJvdG90eXBlT2YiLCJjIiwiRmFicmljT2JqZWN0Iiwic2V0Q3VycmVudCIsIkRldGVybWluaXN0aWNTZXJpYWxpemVyIiwic2VsZiIsIm8iLCJiaW5kIiwiY2xhc3NOYW1lIiwiRGF0ZSIsIkZhYnJpY0NydWRDb250cmFjdCIsIkNvbnRyYWN0IiwiaW5pdGlhbGl6ZWQiLCJmb3JNb2RlbCIsImxpc3RCeSIsImZpbmRPbmVCeSIsImdldFRyYW5zaWVudERhdGEiLCJtZXJnZSIsInRyYW5zaWVudE1hcCIsImdldFRyYW5zaWVudCIsImhhcyIsImRlbGV0ZUFsbCIsInJlYWRBbGwiLCJpbml0IiwiZ2V0TmFtZSIsImhlYWx0aGNoZWNrIiwiQ3R4IiwiZ2V0T3AiLCJSRUFEX0FMTCIsIm92ZXJyaWRlcyIsIlNlcmlhbGl6ZWRDcnVkQ29udHJhY3QiLCJzZXJpYWxpemVkIiwicGFyc2VkS2V5cyIsImxpc3QiLCJtb2RlbExpc3QiLCJjb25kIiwiX19kZWNvcmF0ZSIsIlRyYW5zYWN0aW9uIiwiX19tZXRhZGF0YSIsImFkZCIsImIiLCJzdWIiLCJzYWZlUGFyc2VJbnQiLCJzdHJpbmciLCJkaWdpdFJlZ2V4IiwidGVzdCIsIlZhbGlkYXRpb25FcnJvciIsInN0cmluZ0Zvcm1hdCIsInBhcnNlZGludCIsInBhcnNlSW50IiwiaXNOYU4iLCJFUkMyMFRva2VuIiwiQmFzZU1vZGVsIiwiY29sdW1uIiwicmVxdWlyZWQiLCJFUkMyMFdhbGxldCIsIkFsbG93YW5jZSIsIk93bmVyIiwiZGVzY3JpcHRvciIsIm9yaWdpbmFsTWV0aG9kIiwiYWNvdW50SWQiLCJ0b2tlbnMiLCJvd25lZEJ5T25DcmVhdGUiLCJjcmVhdG9yIiwiZ2V0Q3JlYXRvciIsIm1zcGlkIiwic2V0T3duZWRCeUtleVZhbHVlIiwib3duZWRCeSIsImdldEZhYnJpY01vZGVsS2V5IiwiT1dORURCWSIsInJlYWRvbmx5IiwiZGVjb3JhdG9yIiwidHJhbnNhY3Rpb25JZE9uQ3JlYXRlIiwidHJhbnNhY3Rpb25JZCIsIm9uVXBkYXRlIiwiRkFCUklDIiwiVFJBTlNBQ1RJT05fSUQiLCJJbXBsaWNpdFByaXZhdGVDb2xsZWN0aW9uIiwic2VncmVnYXRlZERhdGFPbkNyZWF0ZSIsImNvbGxlY3Rpb25SZXNvbHZlciIsImNvbGxlY3Rpb25zIiwicmVidWlsdCIsImFjYyIsInRvQ3JlYXRlIiwiY3JlYXRlZCIsInNlZ3JlZ2F0ZWREYXRhT25SZWFkIiwic2VncmVnYXRlZERhdGFPblVwZGF0ZSIsIm9sZE1vZGVsIiwic2VncmVnYXRlZERhdGFPbkRlbGV0ZSIsImlubmVyU2VncmVnYXRlZCIsInNlZ3JlZ2F0ZWREZWMiLCJwcm9wcyIsInByb3BlcnRpZXMiLCJtZXRhIiwiU2V0Iiwic2V0IiwiZGVjcyIsInAiLCJwcmlvcml0eSIsImdyb3VwIiwib25SZWFkIiwib25EZWxldGUiLCJwcml2YXRlRGF0YSIsIlBSSVZBVEUiLCJzaGFyZWREYXRhIiwiU0hBUkVEIiwiRVJDMjBFdmVudHMiLCJGYWJyaWNFUkMyMENvbnRyYWN0Iiwid2FsbGV0UmVwb3NpdG9yeSIsInRva2VuUmVwb3NpdG9yeSIsImFsbG93YW5jZVJlcG9zaXRvcnkiLCJUb2tlbk5hbWUiLCJDaGVja0luaXRpYWxpemVkIiwidG9rZW4iLCJTeW1ib2wiLCJzeW1ib2wiLCJEZWNpbWFscyIsImRlY2ltYWxzIiwiVG90YWxTdXBwbHkiLCJ3YWxsZXRzIiwidG90YWwiLCJ3YWxsZXQiLCJiYWxhbmNlIiwiQmFsYW5jZU9mIiwiVHJhbnNmZXIiLCJ0byIsInRyYW5zZmVyUmVzcCIsIl90cmFuc2ZlciIsIlRyYW5zZmVyRnJvbSIsIkJ1cm5Gcm9tIiwic3BlbmRlciIsImFsbG93YW5jZSIsIl9nZXRBbGxvd2FuY2UiLCJjdXJyZW50QWxsb3dhbmNlIiwidXBkYXRlZEFsbG93YW5jZSIsIm5ld0FsbG93YW5jZSIsImZyb21XYWxsZXQiLCJmcm9tQmFsYW5jZSIsInRvV2FsbGV0IiwibmV3VG9XYWxsZXQiLCJjb2RlIiwidG9CYWxhbmNlIiwiZnJvbVVwZGF0ZWRCYWxhbmNlIiwidG9VcGRhdGVkQmFsYW5jZSIsInVwZGF0ZWRGcm9tV2FsbGV0IiwidXBkYXRlZFRvV2FsbGV0IiwidHJhbnNmZXJFdmVudCIsInJlZnJlc2giLCJUUkFOU0ZFUiIsImNhdGNoIiwiQXBwcm92ZSIsIm93bmVyV2FsbGV0IiwiYXBwcm92YWxFdmVudCIsIkFQUFJPVkFMIiwiYWxsb3dhbmNlQ29uZGl0aW9uIiwiSW5pdGlhbGl6ZSIsIk1pbnQiLCJhbW91bnQiLCJtaW50ZXIiLCJtaW50ZXJXYWxsZXQiLCJjdXJyZW50QmFsYW5jZSIsInVwZGF0ZWRCYWxhbmNlIiwidXBkYXRlZG1pbnRlciIsIm5ld1dhbGxldCIsImV2ZW50SGFuZGxlciIsIkJ1cm4iLCJhY2NvdW50IiwiYWNjb3VudFdhbGxldCIsInVwZGF0ZWRhY2NvdW50IiwiQ2xpZW50QWNjb3VudEJhbGFuY2UiLCJjbGllbnRBY2NvdW50SUQiLCJjbGllbnRXYWxsZXQiLCJDbGllbnRBY2NvdW50SUQiLCJjb250cmFjdHMiLCJWRVJTSU9OIiwiUEFDS0FHRV9OQU1FIiwicmVnaXN0ZXJMaWJyYXJ5Il0sIm1hcHBpbmdzIjoiOzs7OztJQWtDTSxNQUFPQSw4QkFBOEJDLEtBQUFBO1FBS3pDLFdBQUFDO1lBQ0VDO0FBQ0Q7UUFPRCxRQUFJQztZQUNGLE9BQU9DLEtBQUtDLElBQUk7QUFDakI7UUFPRCxhQUFhQztZQUNYLE9BQU9GLEtBQUtELEtBQUtJO0FBQ2xCO1FBT0QsWUFBSUM7WUFDRixPQUFPSixLQUFLQyxJQUFJ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
|