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